diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..dacc18a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +### This file is used for build example projects. + +# set this will supress some warnings +set(BUILDING_SDK "yes" CACHE INTERNAL "") + +# basic config +if (NOT PROJ) + message(FATAL_ERROR "PROJ must be set. e.g. -DPROJ=hello_world") +endif () +cmake_minimum_required(VERSION 3.0) +include(./cmake/common.cmake) +project(${PROJ}) + +# config self use headers +include(./cmake/macros.internal.cmake) +header_directories(${SDK_ROOT}/lib) +# build library first +add_subdirectory(lib) + +# TODO +#add_subdirectory(third_party) + +# compile project +add_custom_target(build_metis ALL + COMMAND ${CMAKE_MAKE_PROGRAM} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/openmv/src/micropython/ports/k210-standalone + COMMENT "Original metis makefile target") +add_source_files(src/${PROJ}/main/*.c) +include(./cmake/executable.cmake) + diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..f425e58 --- /dev/null +++ b/README.TXT @@ -0,0 +1,5 @@ +Kendryte-standalone-opemv build step: +1. mkdir build +2. cd build +3. cmake .. -DPROJ=openmv -DTOOLCHAIN=/opt/maix-toolchain/bin (risv toolchain path) +4. make diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100755 index 0000000..64f2708 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,44 @@ +### This file is used for build library standalone. + +# set this will supress some warnings +set(BUILDING_SDK "yes" CACHE INTERNAL "") + +# basic config +cmake_minimum_required(VERSION 3.0) +include(./common.cmake) +project(kendryte) + +# config self use headers +include(./macros.internal.cmake) +header_directories(${SDK_ROOT}/lib) + +# include lib make file +include(../lib/CMakeLists.txt) + +# find headers files to INSTALL +file(GLOB_RECURSE LIB_HEADERS + "../lib/*.h" + "../lib/*.hpp" + ) +set_target_properties(kendryte PROPERTIES PUBLIC_HEADER "${LIB_HEADERS}") + +# copy .a file and headers +install(TARGETS kendryte + EXPORT kendryte + ARCHIVE + DESTINATION ${CMAKE_BINARY_DIR}/archive + PUBLIC_HEADER DESTINATION ${CMAKE_BINARY_DIR}/archive/include + ) + +# copy utils files +install(DIRECTORY + ../lds + ../utils + ../cmake + DESTINATION ${CMAKE_BINARY_DIR}/archive + PATTERN "*internal*" EXCLUDE + PATTERN "CMakeLists.txt" EXCLUDE + ) + +# show information +include(./dump-config.cmake) diff --git a/cmake/README.md b/cmake/README.md new file mode 100755 index 0000000..5e5bc8b --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,3 @@ +prepend `common.cmake` before + +append `executable.cmake` after diff --git a/cmake/common.cmake b/cmake/common.cmake new file mode 100755 index 0000000..e9ba31a --- /dev/null +++ b/cmake/common.cmake @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.0) + +include(${CMAKE_CURRENT_LIST_DIR}/macros.cmake) + +global_set(CMAKE_C_COMPILER_WORKS 1) +global_set(CMAKE_CXX_COMPILER_WORKS 1) + +global_set(CMAKE_SYSTEM_NAME "Generic") +if (NOT CMAKE_BUILD_TYPE) + global_set(CMAKE_BUILD_TYPE Debug) +else () + if ((NOT CMAKE_BUILD_TYPE STREQUAL "Debug") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Release")) + message(FATAL_ERROR "CMAKE_BUILD_TYPE must either be Debug or Release instead of ${CMAKE_BUILD_TYPE}") + endif () +endif () + +# - Debug & Release +IF (CMAKE_BUILD_TYPE STREQUAL Debug) + add_definitions(-DDEBUG=1) +ENDIF () + +# definitions in macros +add_definitions(-DCONFIG_LOG_LEVEL=LOG_VERBOSE -DCONFIG_LOG_ENABLE -DCONFIG_LOG_COLORS -DLOG_KERNEL -D__riscv64 -DFPGA_PLL) + +if (NOT SDK_ROOT) + get_filename_component(_SDK_ROOT ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) + global_set(SDK_ROOT ${_SDK_ROOT}) +endif () + +include(${CMAKE_CURRENT_LIST_DIR}/toolchain.cmake) + +include(${CMAKE_CURRENT_LIST_DIR}/compile-flags.cmake) + +include(${CMAKE_CURRENT_LIST_DIR}/fix-9985.cmake) diff --git a/cmake/compile-flags.cmake b/cmake/compile-flags.cmake new file mode 100755 index 0000000..76f1fea --- /dev/null +++ b/cmake/compile-flags.cmake @@ -0,0 +1,54 @@ +add_compile_flags(LD + -nostartfiles + -static + -Wl,--gc-sections + -Wl,-static + -Wl,--start-group + -Wl,--whole-archive + -Wl,--no-whole-archive + -Wl,--end-group + -Wl,-EL + -T ${SDK_ROOT}/lds/kendryte.ld + ) + +# C Flags Settings +add_compile_flags(BOTH + -mcmodel=medany + -fno-common + -ffunction-sections + -fdata-sections + -fstrict-volatile-bitfields + -fno-zero-initialized-in-bss + -Os + -ggdb + ) + +add_compile_flags(C -std=gnu11) +add_compile_flags(CXX -std=gnu++17) + +if (BUILDING_SDK) + add_compile_flags(BOTH + -Wall + -Werror=all + -Wno-error=unused-function + -Wno-error=unused-but-set-variable + -Wno-error=unused-variable + -Wno-error=deprecated-declarations + -Wextra + -Werror=frame-larger-than=65536 + -Wno-unused-parameter + -Wno-sign-compare + -Wno-error=missing-braces + -Wno-error=return-type + -Wno-error=pointer-sign + -Wno-missing-braces + -Wno-pointer-to-int-cast + -Wno-strict-aliasing + -Wno-implicit-fallthrough + ) + + add_compile_flags(C -Wno-old-style-declaration) +else () + add_compile_flags(BOTH -L${SDK_ROOT}/include/) +endif () + diff --git a/cmake/dump-config.cmake b/cmake/dump-config.cmake new file mode 100755 index 0000000..d843858 --- /dev/null +++ b/cmake/dump-config.cmake @@ -0,0 +1,13 @@ +message("") +message("Project: ${PROJECT_NAME}") +message(" TOOLCHAIN=${TOOLCHAIN}") +message(" KENDRYTE IDE=${KENDRYTE_IDE}") +message("") +message(" CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") +message(" CMAKE_C_COMPILER=${CMAKE_C_COMPILER}") +message(" CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") +message(" CMAKE_LINKER=${CMAKE_LINKER}") +message(" CMAKE_OBJCOPY=${CMAKE_OBJCOPY}") +message("Makefile created.") +message("") +message("") diff --git a/cmake/executable.cmake b/cmake/executable.cmake new file mode 100755 index 0000000..6d1ffc4 --- /dev/null +++ b/cmake/executable.cmake @@ -0,0 +1,37 @@ +if (NOT BUILDING_SDK) + add_library(kendryte STATIC IMPORTED) + set_property(TARGET kendryte PROPERTY IMPORTED_LOCATION ${SDK_ROOT}/libmaix.a) + include_directories(${SDK_ROOT}/include/) +endif () + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +# add_dependencies(${PROJECT_NAME} kendryte) # TODO: third_party +# target_link_libraries(${PROJECT_NAME} kendryte) # TODO: third_party +# link_directories(${CMAKE_BINARY_DIR}) +target_link_libraries(${PROJECT_NAME} + ${SDK_ROOT}/src/openmv/src/micropython/ports/k210-standalone/micropython.a + ) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) + +target_link_libraries(${PROJECT_NAME} + -Wl,--start-group + gcc m c kendryte + -Wl,--end-group + ) +IF(SUFFIX) + SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SUFFIX ${SUFFIX}) +ENDIF() + +#message("CMAKE_OBJCOPY=${CMAKE_OBJCOPY}") + +# Build target +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} --output-format=binary ${CMAKE_BINARY_DIR}/${PROJECT_NAME}${SUFFIX} ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin + DEPENDS ${PROJECT_NAME} + COMMENT "Generating .bin file ...") + + +add_custom_target(firmware DEPENDS ${PROJECT_NAME}.firmware.bin) + +# show information +include(${CMAKE_CURRENT_LIST_DIR}/dump-config.cmake) diff --git a/cmake/fix-9985.cmake b/cmake/fix-9985.cmake new file mode 100755 index 0000000..4402bd3 --- /dev/null +++ b/cmake/fix-9985.cmake @@ -0,0 +1,3 @@ +### http://www.cmake.org/Bug/view.php?id=9985 +string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS}") +string(REPLACE "-rdynamic" "" CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS}") diff --git a/cmake/macros.cmake b/cmake/macros.cmake new file mode 100755 index 0000000..9ef8728 --- /dev/null +++ b/cmake/macros.cmake @@ -0,0 +1,65 @@ +macro(global_set Name Value) + # message("set ${Name} to " ${ARGN}) + set(${Name} "${Value}" CACHE STRING "NoDesc" FORCE) +endmacro() + +macro(condition_set Name Value) + if (NOT ${Name}) + global_set(${Name} ${Value}) + else () + # message("exists ${Name} is " ${ARGN}) + endif () +endmacro() + + +set(SOURCE_FILES "" CACHE STRING "Source Files" FORCE) +macro(add_source_files) + # message(" + add_source_files ${ARGN}") + file(GLOB_RECURSE newlist ${ARGN}) + + foreach (filepath ${newlist}) + string(FIND ${filepath} ${CMAKE_BINARY_DIR} found) + if (NOT found EQUAL 0) + set(SOURCE_FILES ${SOURCE_FILES} ${filepath} CACHE STRING "Source Files" FORCE) + endif () + endforeach () +endmacro() + +function(JOIN VALUES GLUE OUTPUT) + string(REGEX REPLACE "([^\\]|^);" "\\1${GLUE}" _TMP_STR "${VALUES}") + string(REGEX REPLACE "[\\](.)" "\\1" _TMP_STR "${_TMP_STR}") #fixes escaping + set(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) +endfunction() + +global_set(LDFLAGS "") +global_set(CMAKE_EXE_LINKER_FLAGS "") +global_set(CMAKE_SHARED_LINKER_FLAGS "") +global_set(CMAKE_MODULE_LINKER_FLAGS "") + +macro(add_compile_flags WHERE) + JOIN("${ARGN}" " " STRING_ARGS) + if (${WHERE} STREQUAL C) + global_set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL CXX) + global_set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL LD) + global_set(LDFLAGS "${LDFLAGS} ${STRING_ARGS}") + global_set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${STRING_ARGS}") + global_set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${STRING_ARGS}") + global_set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${STRING_ARGS}") + + elseif (${WHERE} STREQUAL BOTH) + add_compile_flags(C ${ARGN}) + add_compile_flags(CXX ${ARGN}) + + elseif (${WHERE} STREQUAL ALL) + add_compile_flags(C ${ARGN}) + add_compile_flags(CXX ${ARGN}) + add_compile_flags(LD ${ARGN}) + + else () + message(FATAL_ERROR "add_compile_flags - only support: C, CXX, BOTH, LD, ALL") + endif () +endmacro() diff --git a/cmake/macros.internal.cmake b/cmake/macros.internal.cmake new file mode 100755 index 0000000..a38b56d --- /dev/null +++ b/cmake/macros.internal.cmake @@ -0,0 +1,12 @@ +# Add lib headers +macro(header_directories parent) + file(GLOB_RECURSE newList ${parent}/*.h) + set(dir_list "") + foreach (file_path ${newList}) + get_filename_component(dir_path ${file_path} DIRECTORY) + set(dir_list ${dir_list} ${dir_path}) + endforeach () + list(REMOVE_DUPLICATES dir_list) + + include_directories(${dir_list}) +endmacro() \ No newline at end of file diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake new file mode 100755 index 0000000..163ddac --- /dev/null +++ b/cmake/toolchain.cmake @@ -0,0 +1,22 @@ +if (NOT TOOLCHAIN) + message(FATAL_ERROR "TOOLCHAIN must be set, to absolute path of kendryte-toolchain dist/bin folder.") +endif () + +if (WIN32) + set(EXT ".exe") +else () + set(EXT "") +endif () + +condition_set(CMAKE_C_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-gcc${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/riscv64-unknown-elf-g++${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_LINKER "${TOOLCHAIN}/riscv64-unknown-elf-ld${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_AR "${TOOLCHAIN}/riscv64-unknown-elf-ar${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_CXX_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_C_COMPILER_AR "${CMAKE_AR}${EXT}" CACHE INTERNAL "") +condition_set(CMAKE_OBJCOPY "${TOOLCHAIN}/riscv64-unknown-elf-objcopy${EXT}" CACHE INTERNAL "") + +get_filename_component(_BIN_DIR "${CMAKE_C_COMPILER}" DIRECTORY) +if (NOT "${TOOLCHAIN}" STREQUAL "${_BIN_DIR}") + message(FATAL_ERROR "CMAKE_C_COMPILER is not in kendryte-toolchain dist/bin folder.") +endif () diff --git a/lds/kendryte.ld b/lds/kendryte.ld new file mode 100755 index 0000000..b2fdbe8 --- /dev/null +++ b/lds/kendryte.ld @@ -0,0 +1,250 @@ +/* + * The MEMORY command describes the location and size of blocks of memory + * in the target. You can use it to describe which memory regions may be + * used by the linker, and which memory regions it must avoid. + */ +MEMORY +{ + /* + * Memory with CPU cache. + *6M CPU SRAM + */ + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = (6 * 1024 * 1024) + /* + * Memory without CPU cache + * 6M CPU SRAM + */ + ram_nocache (wxa!ri) : ORIGIN = 0x40000000, LENGTH = (6 * 1024 * 1024) +} + +PROVIDE( _rom_start = ORIGIN(rom) ); +PROVIDE( _rom_end = ORIGIN(rom) + LENGTH(rom) ); +PROVIDE( _ram_start = ORIGIN(ram) ); +PROVIDE( _ram_end = ORIGIN(ram) + LENGTH(ram) ); +PROVIDE( _io_start = 0x40000000 ); +PROVIDE( _io_end = _io_start + LENGTH(ram) ); +PROVIDE( _stack_size = 1 << 17 ); + + +/* + * The OUTPUT_ARCH command specifies the machine architecture where the + * argument is one of the names used in the Kendryte library. + */ +OUTPUT_ARCH( "riscv" ) + +/* + * The ENTRY command specifies the entry point (ie. first instruction to + * execute). The symbol _start is defined in crt0.S + */ +ENTRY(_start) + +/* + * The GROUP command is special since the listed archives will be + * searched repeatedly until there are no new undefined references. We + * need this since -lc depends on -lgloss and -lgloss depends on -lc. I + * thought gcc would automatically include -lgcc when needed, but + * in this file includes it explicitly here and I was seeing link errors + * without it. + */ +/* GROUP( -lc -lgloss -lgcc ) */ + +/* + * The linker only pays attention to the PHDRS command when generating + * an ELF output file. In other cases, the linker will simply ignore PHDRS. + */ +PHDRS +{ + ram_ro PT_LOAD; + ram_init PT_LOAD; + ram PT_NULL; +} + +/* + * This is where we specify how the input sections map to output + * sections. + */ +SECTIONS +{ + /* Program code segment, also known as a text segment */ + .text : + { + PROVIDE( _text = ABSOLUTE(.) ); + /* Initialization code segment */ + KEEP( *(.text.start) ) + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + /* Normal code segment */ + *(.text .text.*) + *(.gnu.linkonce.t.*) + + . = ALIGN(8); + PROVIDE( _etext = ABSOLUTE(.) ); + } >ram AT>ram :ram_ro + + /* Read-only data segment */ + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + /* Init array and fini array */ + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram AT>ram :ram_ro + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram AT>ram :ram_ro + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram AT>ram :ram_ro + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram AT>ram :ram_ro + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram AT>ram :ram_ro + + . = ALIGN(8); + + .lalign : + { + . = ALIGN(8); + PROVIDE( _data_lma = . ); + } >ram AT>ram :ram_ro + + .dalign : + { + . = ALIGN(8); + PROVIDE( _data = . ); + } >ram AT>ram :ram_init + + . = ALIGN(8); + + /* .data, .sdata and .srodata segment */ + .data : + { + /* Writable data segment (.data segment) */ + *(.data .data.*) + *(.gnu.linkonce.d.*) + /* Have _gp point to middle of sdata/sbss to maximize displacement range */ + . = ALIGN(8); + PROVIDE( __global_pointer$ = ABSOLUTE(.) + 0x800); + /* Writable small data segment (.sdata segment) */ + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + /* Read-only small data segment (.srodata segment) */ + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + /* Align _edata to cache line size */ + . = ALIGN(64); + PROVIDE( _edata = ABSOLUTE(.) ); + } >ram AT>ram :ram_init + + /* .bss and .sbss segment */ + .bss : + { + PROVIDE( _bss = ABSOLUTE(.) ); + /* Writable uninitialized small data segment (.sbss segment)*/ + *(.sbss .sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + /* Uninitialized writeable data section (.bss segment)*/ + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + + . = ALIGN(8); + PROVIDE( _ebss = ABSOLUTE(.) ); + } >ram AT>ram :ram + + PROVIDE( _tls_data = ABSOLUTE(.) ); + /* + * Thread Local Storage (TLS) are per-thread global variables. + * Compilers such as GCC provide a __thread keyword to mark global + * variables as per-thread. Support is required in the program loader + * and thread creator. + */ + + /* Thread-local data segment, .tdata (initialized tls). */ + .tdata : + { + KEEP( *(.tdata.begin) ) + *(.tdata .tdata.*) + *(.gnu.linkonce.td.*) + KEEP( *(.tdata.end) ) + } >ram AT>ram :ram + + /* Thread-local bss segment, .tbss (zero-initialized tls). */ + .tbss : + { + *(.tbss .tbss.*) + *(.gnu.linkonce.tb.*) + KEEP( *(.tbss.end) ) + } >ram AT>ram :ram + + /* + * End of uninitalized data segement + * + * Actually the stack needs 16B alignment, and it won't hurt to also slightly + * increase the alignment to 32 or even 64 (cache line size). + * + * Align _heap_start to cache line size + */ + . = ALIGN(64); + PROVIDE( _end = ABSOLUTE(.) ); + /* Leave 2 holes for stack & TLS, the size can set in kconfig */ + PROVIDE( _heap_start = ABSOLUTE(.) + _stack_size * 2 ); + PROVIDE( _tp0 = (_end + 63) & (-64) ); + PROVIDE( _tp1 = _tp0 + _stack_size ); + PROVIDE( _sp0 = _tp0 + _stack_size ); + PROVIDE( _sp1 = _tp1 + _stack_size ); + /* Heap end is at the end of memory, the memory size can set in kconfig */ + PROVIDE( _heap_end = _ram_end ); +} + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100755 index 0000000..c6c2d82 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,33 @@ +#project(maix_drivers) + +# create driver library + +FILE(GLOB_RECURSE LIB_SRC + "${CMAKE_CURRENT_LIST_DIR}/*.h" + "${CMAKE_CURRENT_LIST_DIR}/*.hpp" + "${CMAKE_CURRENT_LIST_DIR}/*.cpp" + "${CMAKE_CURRENT_LIST_DIR}/*.c" + "${CMAKE_CURRENT_LIST_DIR}/*.s" + "${CMAKE_CURRENT_LIST_DIR}/*.S" + ) + +FILE(GLOB_RECURSE ASSEMBLY_FILES + "${CMAKE_CURRENT_LIST_DIR}/*.s" + "${CMAKE_CURRENT_LIST_DIR}/*.S" + ) + +include_directories(${CMAKE_CURRENT_LIST_DIR}/drivers/include ${CMAKE_CURRENT_LIST_DIR}/bsp/include ${CMAKE_CURRENT_LIST_DIR}/firmware/include) +# +#HEADER_DIRECTORIES(LIB_HEADERS) +# +#INCLUDE_DIRECTORIES(${LIB_HEADERS}) + +SET_PROPERTY(SOURCE ${ASSEMBLY_FILES} PROPERTY LANGUAGE C) +SET_SOURCE_FILES_PROPERTIES(${ASSEMBLY_FILES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D __riscv64") + +#MESSAGE("CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") + +ADD_LIBRARY(kendryte + ${LIB_SRC} + ) +SET_TARGET_PROPERTIES(kendryte PROPERTIES LINKER_LANGUAGE C) diff --git a/lib/bsp/crt.S b/lib/bsp/crt.S new file mode 100755 index 0000000..6d4e6a7 --- /dev/null +++ b/lib/bsp/crt.S @@ -0,0 +1,302 @@ +# Copyright 2018 Canaan Inc. +# +# 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. + +#include "encoding.h" + +# define LREG ld +# define SREG sd +# define LFREG fld +# define SFREG fsd +# define REGBYTES 8 +# define STKSHIFT 17 + + +.section .text.start, "ax", @progbits +.globl _start +_start: + j 1f + .word 0xdeadbeef + .align 3 + .global g_wake_up + g_wake_up: + .dword 1 + .dword 0 +1: + csrw mideleg, 0 + csrw medeleg, 0 + csrw mie, 0 + csrw mip, 0 + la t0, trap_entry + csrw mtvec, t0 + + li x1, 0 + li x2, 0 + li x3, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10,0 + li x11,0 + li x12,0 + li x13,0 + li x14,0 + li x15,0 + li x16,0 + li x17,0 + li x18,0 + li x19,0 + li x20,0 + li x21,0 + li x22,0 + li x23,0 + li x24,0 + li x25,0 + li x26,0 + li x27,0 + li x28,0 + li x29,0 + li x30,0 + li x31,0 + + csrr t0, misa + bltz t0, 1f + li a0, 1234 + j sys_exit +1: + + andi t0, t0, 1 << ('f' - 'a') + beqz t0, 1f + li t0, MSTATUS_FS + csrs mstatus, t0 + + fssr x0 + fmv.d.x f0, x0 + fmv.d.x f1, x0 + fmv.d.x f2, x0 + fmv.d.x f3, x0 + fmv.d.x f4, x0 + fmv.d.x f5, x0 + fmv.d.x f6, x0 + fmv.d.x f7, x0 + fmv.d.x f8, x0 + fmv.d.x f9, x0 + fmv.d.x f10,x0 + fmv.d.x f11,x0 + fmv.d.x f12,x0 + fmv.d.x f13,x0 + fmv.d.x f14,x0 + fmv.d.x f15,x0 + fmv.d.x f16,x0 + fmv.d.x f17,x0 + fmv.d.x f18,x0 + fmv.d.x f19,x0 + fmv.d.x f20,x0 + fmv.d.x f21,x0 + fmv.d.x f22,x0 + fmv.d.x f23,x0 + fmv.d.x f24,x0 + fmv.d.x f25,x0 + fmv.d.x f26,x0 + fmv.d.x f27,x0 + fmv.d.x f28,x0 + fmv.d.x f29,x0 + fmv.d.x f30,x0 + fmv.d.x f31,x0 + +1: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la tp, _end + 63 + and tp, tp, -64 + csrr a0, mhartid + li a1, 2 + +1:bgeu a0, a1, 1b + + sll a2, a0, STKSHIFT + add tp, tp, a2 + add sp, a0, 1 + sll sp, sp, STKSHIFT + add sp, sp, tp + + j _init_bsp + + .globl trap_entry + .type trap_entry, @function + .align 2 +trap_entry: + addi sp, sp, -64*REGBYTES + + SREG x1, 1*REGBYTES(sp) + SREG x2, 2*REGBYTES(sp) + SREG x3, 3*REGBYTES(sp) + SREG x4, 4*REGBYTES(sp) + SREG x5, 5*REGBYTES(sp) + SREG x6, 6*REGBYTES(sp) + SREG x7, 7*REGBYTES(sp) + SREG x8, 8*REGBYTES(sp) + SREG x9, 9*REGBYTES(sp) + SREG x10, 10*REGBYTES(sp) + SREG x11, 11*REGBYTES(sp) + SREG x12, 12*REGBYTES(sp) + SREG x13, 13*REGBYTES(sp) + SREG x14, 14*REGBYTES(sp) + SREG x15, 15*REGBYTES(sp) + SREG x16, 16*REGBYTES(sp) + SREG x17, 17*REGBYTES(sp) + SREG x18, 18*REGBYTES(sp) + SREG x19, 19*REGBYTES(sp) + SREG x20, 20*REGBYTES(sp) + SREG x21, 21*REGBYTES(sp) + SREG x22, 22*REGBYTES(sp) + SREG x23, 23*REGBYTES(sp) + SREG x24, 24*REGBYTES(sp) + SREG x25, 25*REGBYTES(sp) + SREG x26, 26*REGBYTES(sp) + SREG x27, 27*REGBYTES(sp) + SREG x28, 28*REGBYTES(sp) + SREG x29, 29*REGBYTES(sp) + SREG x30, 30*REGBYTES(sp) + SREG x31, 31*REGBYTES(sp) + + SFREG f0, ( 0 + 32)*REGBYTES(sp) + SFREG f1, ( 1 + 32)*REGBYTES(sp) + SFREG f2, ( 2 + 32)*REGBYTES(sp) + SFREG f3, ( 3 + 32)*REGBYTES(sp) + SFREG f4, ( 4 + 32)*REGBYTES(sp) + SFREG f5, ( 5 + 32)*REGBYTES(sp) + SFREG f6, ( 6 + 32)*REGBYTES(sp) + SFREG f7, ( 7 + 32)*REGBYTES(sp) + SFREG f8, ( 8 + 32)*REGBYTES(sp) + SFREG f9, ( 9 + 32)*REGBYTES(sp) + SFREG f10,( 10 + 32)*REGBYTES(sp) + SFREG f11,( 11 + 32)*REGBYTES(sp) + SFREG f12,( 12 + 32)*REGBYTES(sp) + SFREG f13,( 13 + 32)*REGBYTES(sp) + SFREG f14,( 14 + 32)*REGBYTES(sp) + SFREG f15,( 15 + 32)*REGBYTES(sp) + SFREG f16,( 16 + 32)*REGBYTES(sp) + SFREG f17,( 17 + 32)*REGBYTES(sp) + SFREG f18,( 18 + 32)*REGBYTES(sp) + SFREG f19,( 19 + 32)*REGBYTES(sp) + SFREG f20,( 20 + 32)*REGBYTES(sp) + SFREG f21,( 21 + 32)*REGBYTES(sp) + SFREG f22,( 22 + 32)*REGBYTES(sp) + SFREG f23,( 23 + 32)*REGBYTES(sp) + SFREG f24,( 24 + 32)*REGBYTES(sp) + SFREG f25,( 25 + 32)*REGBYTES(sp) + SFREG f26,( 26 + 32)*REGBYTES(sp) + SFREG f27,( 27 + 32)*REGBYTES(sp) + SFREG f28,( 28 + 32)*REGBYTES(sp) + SFREG f29,( 29 + 32)*REGBYTES(sp) + SFREG f30,( 30 + 32)*REGBYTES(sp) + SFREG f31,( 31 + 32)*REGBYTES(sp) + + csrr a0, mcause + csrr a1, mepc + mv a2, sp + add a3, sp, 32*REGBYTES + bgez a0, .handle_syscall +.handle_irq: + jal handle_irq + j .restore +.handle_syscall: + jal handle_syscall +.restore: + csrw mepc, a0 + LREG x1, 1*REGBYTES(sp) + LREG x2, 2*REGBYTES(sp) + LREG x3, 3*REGBYTES(sp) + LREG x4, 4*REGBYTES(sp) + LREG x5, 5*REGBYTES(sp) + LREG x6, 6*REGBYTES(sp) + LREG x7, 7*REGBYTES(sp) + LREG x8, 8*REGBYTES(sp) + LREG x9, 9*REGBYTES(sp) + LREG x10, 10*REGBYTES(sp) + LREG x11, 11*REGBYTES(sp) + LREG x12, 12*REGBYTES(sp) + LREG x13, 13*REGBYTES(sp) + LREG x14, 14*REGBYTES(sp) + LREG x15, 15*REGBYTES(sp) + LREG x16, 16*REGBYTES(sp) + LREG x17, 17*REGBYTES(sp) + LREG x18, 18*REGBYTES(sp) + LREG x19, 19*REGBYTES(sp) + LREG x20, 20*REGBYTES(sp) + LREG x21, 21*REGBYTES(sp) + LREG x22, 22*REGBYTES(sp) + LREG x23, 23*REGBYTES(sp) + LREG x24, 24*REGBYTES(sp) + LREG x25, 25*REGBYTES(sp) + LREG x26, 26*REGBYTES(sp) + LREG x27, 27*REGBYTES(sp) + LREG x28, 28*REGBYTES(sp) + LREG x29, 29*REGBYTES(sp) + LREG x30, 30*REGBYTES(sp) + LREG x31, 31*REGBYTES(sp) + + LFREG f0, ( 0 + 32)*REGBYTES(sp) + LFREG f1, ( 1 + 32)*REGBYTES(sp) + LFREG f2, ( 2 + 32)*REGBYTES(sp) + LFREG f3, ( 3 + 32)*REGBYTES(sp) + LFREG f4, ( 4 + 32)*REGBYTES(sp) + LFREG f5, ( 5 + 32)*REGBYTES(sp) + LFREG f6, ( 6 + 32)*REGBYTES(sp) + LFREG f7, ( 7 + 32)*REGBYTES(sp) + LFREG f8, ( 8 + 32)*REGBYTES(sp) + LFREG f9, ( 9 + 32)*REGBYTES(sp) + LFREG f10,( 10 + 32)*REGBYTES(sp) + LFREG f11,( 11 + 32)*REGBYTES(sp) + LFREG f12,( 12 + 32)*REGBYTES(sp) + LFREG f13,( 13 + 32)*REGBYTES(sp) + LFREG f14,( 14 + 32)*REGBYTES(sp) + LFREG f15,( 15 + 32)*REGBYTES(sp) + LFREG f16,( 16 + 32)*REGBYTES(sp) + LFREG f17,( 17 + 32)*REGBYTES(sp) + LFREG f18,( 18 + 32)*REGBYTES(sp) + LFREG f19,( 19 + 32)*REGBYTES(sp) + LFREG f20,( 20 + 32)*REGBYTES(sp) + LFREG f21,( 21 + 32)*REGBYTES(sp) + LFREG f22,( 22 + 32)*REGBYTES(sp) + LFREG f23,( 23 + 32)*REGBYTES(sp) + LFREG f24,( 24 + 32)*REGBYTES(sp) + LFREG f25,( 25 + 32)*REGBYTES(sp) + LFREG f26,( 26 + 32)*REGBYTES(sp) + LFREG f27,( 27 + 32)*REGBYTES(sp) + LFREG f28,( 28 + 32)*REGBYTES(sp) + LFREG f29,( 29 + 32)*REGBYTES(sp) + LFREG f30,( 30 + 32)*REGBYTES(sp) + LFREG f31,( 31 + 32)*REGBYTES(sp) + + addi sp, sp, 64*REGBYTES + mret + +.section ".tdata.begin" +.globl _tdata_begin +_tdata_begin: + +.section ".tdata.end" +.globl _tdata_end +_tdata_end: + +.section ".tbss.end" +.globl _tbss_end +_tbss_end: + diff --git a/lib/bsp/entry.c b/lib/bsp/entry.c new file mode 100755 index 0000000..50385a3 --- /dev/null +++ b/lib/bsp/entry.c @@ -0,0 +1,37 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#include "entry.h" + +/** + * @brief Dummy function for __libc_init_array called + */ +void __attribute__((weak)) _init(void) +{ + /** + * These don't have to do anything since we use init_array/fini_array. + */ +} + +/** + * @brief Dummy function for __libc_fini_array called + */ +void __attribute__((weak)) _fini(void) +{ + /** + * These don't have to do anything since we use init_array/fini_array. + */ +} + diff --git a/lib/bsp/entry_user.c b/lib/bsp/entry_user.c new file mode 100755 index 0000000..0b44fae --- /dev/null +++ b/lib/bsp/entry_user.c @@ -0,0 +1,103 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#include +#include "atomic.h" +#include "clint.h" +#include "dmac.h" +#include "entry.h" +#include "fpioa.h" +#include "platform.h" +#include "plic.h" +#include "sysctl.h" +#include "syslog.h" +#include "uarths.h" + +extern volatile uint64_t g_wake_up[2]; + +core_instance_t core1_instance; + +volatile char * const ram = (volatile char*)RAM_BASE_ADDR; + +extern char _heap_start[]; +extern char _heap_end[]; + +void thread_entry(int core_id) +{ + while (!atomic_read(&g_wake_up[core_id])); +} + +void core_enable(int core_id) +{ + clint_ipi_send(core_id); + atomic_set(&g_wake_up[core_id], 1); +} + +int register_core1(core_function func, void *ctx) +{ + if(func == NULL) + return -1; + core1_instance.callback = func; + core1_instance.ctx = ctx; + core_enable(1); + return 0; +} + +int __attribute__((weak)) os_entry(int core_id, int number_of_cores, int (*user_main)(int, char**)) +{ + /* Call main if there is no OS */ + return user_main(0, 0); +} + +void _init_bsp(int core_id, int number_of_cores) +{ + extern int main(int argc, char* argv[]); + extern void __libc_init_array(void); + extern void __libc_fini_array(void); + /* Initialize thread local data */ + init_tls(); + + if (core_id == 0) + { + /* Initialize bss data to 0 */ + init_bss(); + /* Init UART */ + uarths_init(); + /* Init FPIOA */ + fpioa_init(); + /* Register finalization function */ + atexit(__libc_fini_array); + /* Init libc array for C++ */ + __libc_init_array(); + } + + int ret = 0; + if (core_id == 0) + { + core1_instance.callback = NULL; + core1_instance.ctx = NULL; + ret = os_entry(core_id, number_of_cores, main); + } + else + { + thread_entry(core_id); + if(core1_instance.callback == NULL) + asm volatile ("wfi"); + else + ret = core1_instance.callback(core1_instance.ctx); + } + exit(ret); +} + diff --git a/lib/bsp/include/atomic.h b/lib/bsp/include/atomic.h new file mode 100755 index 0000000..1728b5c --- /dev/null +++ b/lib/bsp/include/atomic.h @@ -0,0 +1,244 @@ + +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _BSP_ATOMIC_H +#define _BSP_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SPINLOCK_INIT \ + { \ + 0 \ + } + +#define CORELOCK_INIT \ + { \ + .lock = SPINLOCK_INIT, \ + .count = 0, \ + .core = -1 \ + } + + +/* Defination of memory barrier macro */ +#define mb() \ + { \ + asm volatile("fence" :: \ + : "memory"); \ + } + +#define atomic_set(ptr, val) (*(volatile typeof(*(ptr))*)(ptr) = val) +#define atomic_read(ptr) (*(volatile typeof(*(ptr))*)(ptr)) + +#ifndef __riscv_atomic +#error "atomic extension is required." +#endif +#define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc) +#define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) +#define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) +#define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp) + +typedef struct _spinlock +{ + int lock; +} spinlock_t; + +typedef struct _semaphore +{ + spinlock_t lock; + int count; + int waiting; +} semaphore_t; + + +typedef struct _corelock +{ + spinlock_t lock; + int count; + int core; +} corelock_t; + + +static inline int spinlock_trylock(spinlock_t *lock) +{ + int res = atomic_swap(&lock->lock, -1); + /* Use memory barrier to keep coherency */ + mb(); + return res; +} + +static inline void spinlock_lock(spinlock_t *lock) +{ + do + { + while (atomic_read(&lock->lock)) + ; + } while (spinlock_trylock(lock)); +} + +static inline void spinlock_unlock(spinlock_t *lock) +{ + /* Use memory barrier to keep coherency */ + mb(); + atomic_set(&lock->lock, 0); +} + +static inline void semaphore_signal(semaphore_t *semaphore, int i) +{ + spinlock_lock(&(semaphore->lock)); + semaphore->count += i; + spinlock_unlock(&(semaphore->lock)); +} + +static inline void semaphore_wait(semaphore_t *semaphore, int i) +{ + atomic_add(&(semaphore->waiting), 1); + while (1) + { + spinlock_lock(&(semaphore->lock)); + if (semaphore->count >= i) + { + semaphore->count -= i; + atomic_add(&(semaphore->waiting), -1); + spinlock_unlock(&(semaphore->lock)); + break; + } + spinlock_unlock(&(semaphore->lock)); + } +} + +static inline int semaphore_count(semaphore_t *semaphore) +{ + int res = 0; + + spinlock_lock(&(semaphore->lock)); + res = semaphore->count; + spinlock_unlock(&(semaphore->lock)); + return res; +} + +static inline int semaphore_waiting(semaphore_t *semaphore) +{ + return atomic_read(&(semaphore->waiting)); +} + +static inline int corelock_trylock(corelock_t *lock) +{ + int res = 0; + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + spinlock_lock(&lock->lock); + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->core = core; + res = 0; + } + else if (lock->core == core) + { + /* Same core get lock */ + lock->count++; + res = 0; + } + else + { + /* Different core get lock */ + res = -1; + } + spinlock_unlock(&lock->lock); + + return res; +} + +static inline void corelock_lock(corelock_t *lock) +{ + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + spinlock_lock(&lock->lock); + + if (lock->count == 0) + { + /* First time get lock */ + lock->count++; + lock->core = core; + } + else if (lock->core == core) + { + /* Same core get lock */ + lock->count++; + } + else + { + /* Different core get lock */ + spinlock_unlock(&lock->lock); + + do + { + while (atomic_read(&lock->count)) + ; + } while (corelock_trylock(lock)); + } + spinlock_unlock(&lock->lock); +} + +static inline void corelock_unlock(corelock_t *lock) +{ + unsigned long core; + + asm volatile("csrr %0, mhartid;" + : "=r"(core)); + spinlock_lock(&lock->lock); + + if (lock->core == core) + { + /* Same core release lock */ + lock->count--; + if (lock->count <= 0) + { + lock->core = -1; + lock->count = 0; + } + } + else + { + /* Different core release lock */ + spinlock_unlock(&lock->lock); + + register unsigned long a7 asm("a7") = 93; + register unsigned long a0 asm("a0") = 0; + register unsigned long a1 asm("a1") = 0; + register unsigned long a2 asm("a2") = 0; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a7)); + } + spinlock_unlock(&lock->lock); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ATOMIC_H */ + diff --git a/lib/bsp/include/bsp.h b/lib/bsp/include/bsp.h new file mode 100755 index 0000000..deecc67 --- /dev/null +++ b/lib/bsp/include/bsp.h @@ -0,0 +1,7 @@ +#ifndef _KENDRYTE_BSP_H +#define _KENDRYTE_BSP_H +#include "atomic.h" +#include "entry.h" +#include "sleep.h" +#include "encoding.h" +#endif \ No newline at end of file diff --git a/lib/bsp/include/dump.h b/lib/bsp/include/dump.h new file mode 100755 index 0000000..da807b1 --- /dev/null +++ b/lib/bsp/include/dump.h @@ -0,0 +1,141 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_DUMP_H +#define _BSP_DUMP_H + +#include +#include +#include "syslog.h" +#include "uarths.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DUMP_PRINTF printk + +static inline void +dump_core(const char *reason, uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + static const char *const reg_usage[][2] = + { + {"zero ", "Hard-wired zero"}, + {"ra ", "Return address"}, + {"sp ", "Stack pointer"}, + {"gp ", "Global pointer"}, + {"tp ", "Thread pointer"}, + {"t0 ", "Temporaries Caller"}, + {"t1 ", "Temporaries Caller"}, + {"t2 ", "Temporaries Caller"}, + {"s0/fp", "Saved register/frame pointer"}, + {"s1 ", "Saved register"}, + {"a0 ", "Function arguments/return values"}, + {"a1 ", "Function arguments/return values"}, + {"a2 ", "Function arguments values"}, + {"a3 ", "Function arguments values"}, + {"a4 ", "Function arguments values"}, + {"a5 ", "Function arguments values"}, + {"a6 ", "Function arguments values"}, + {"a7 ", "Function arguments values"}, + {"s2 ", "Saved registers"}, + {"s3 ", "Saved registers"}, + {"s4 ", "Saved registers"}, + {"s5 ", "Saved registers"}, + {"s6 ", "Saved registers"}, + {"s7 ", "Saved registers"}, + {"s8 ", "Saved registers"}, + {"s9 ", "Saved registers"}, + {"s10 ", "Saved registers"}, + {"s11 ", "Saved registers"}, + {"t3 ", "Temporaries Caller"}, + {"t4 ", "Temporaries Caller"}, + {"t5 ", "Temporaries Caller"}, + {"t6 ", "Temporaries Caller"}, + }; + + static const char *const regf_usage[][2] = + { + {"ft0 ", "FP temporaries"}, + {"ft1 ", "FP temporaries"}, + {"ft2 ", "FP temporaries"}, + {"ft3 ", "FP temporaries"}, + {"ft4 ", "FP temporaries"}, + {"ft5 ", "FP temporaries"}, + {"ft6 ", "FP temporaries"}, + {"ft7 ", "FP temporaries"}, + {"fs0 ", "FP saved registers"}, + {"fs1 ", "FP saved registers"}, + {"fa0 ", "FP arguments/return values"}, + {"fa1 ", "FP arguments/return values"}, + {"fa2 ", "FP arguments values"}, + {"fa3 ", "FP arguments values"}, + {"fa4 ", "FP arguments values"}, + {"fa5 ", "FP arguments values"}, + {"fa6 ", "FP arguments values"}, + {"fa7 ", "FP arguments values"}, + {"fs2 ", "FP Saved registers"}, + {"fs3 ", "FP Saved registers"}, + {"fs4 ", "FP Saved registers"}, + {"fs5 ", "FP Saved registers"}, + {"fs6 ", "FP Saved registers"}, + {"fs7 ", "FP Saved registers"}, + {"fs8 ", "FP Saved registers"}, + {"fs9 ", "FP Saved registers"}, + {"fs10", "FP Saved registers"}, + {"fs11", "FP Saved registers"}, + {"ft8 ", "FP Temporaries Caller"}, + {"ft9 ", "FP Temporaries Caller"}, + {"ft10", "FP Temporaries Caller"}, + {"ft11", "FP Temporaries Caller"}, + }; + + if (CONFIG_LOG_LEVEL >= LOG_ERROR) + { + const char unknown_reason[] = "unknown"; + + if (!reason) + reason = unknown_reason; + + DUMP_PRINTF("core dump: %s\n", reason); + DUMP_PRINTF("Cause 0x%016lx, EPC 0x%016lx\n", cause, epc); + + int i = 0; + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "reg[%02d](%s) = 0x%016lx, reg[%02d](%s) = 0x%016lx\n", + i * 2, reg_usage[i * 2][0], regs[i * 2], + i * 2 + 1, reg_usage[i * 2 + 1][0], regs[i * 2 + 1]); + } + + for (i = 0; i < 32 / 2; i++) + { + DUMP_PRINTF( + "freg[%02d](%s) = 0x%016lx(%f), freg[%02d](%s) = 0x%016lx(%f)\n", + i * 2, regf_usage[i * 2][0], fregs[i * 2], (float)fregs[i * 2], + i * 2 + 1, regf_usage[i * 2 + 1][0], fregs[i * 2 + 1], (float)fregs[i * 2 + 1]); + } + } +} + +#undef DUMP_PRINTF + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_DUMP_H */ + diff --git a/lib/bsp/include/encoding.h b/lib/bsp/include/encoding.h new file mode 100755 index 0000000..06cacea --- /dev/null +++ b/lib/bsp/include/encoding.h @@ -0,0 +1,1326 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001U +#define MSTATUS_SIE 0x00000002U +#define MSTATUS_HIE 0x00000004U +#define MSTATUS_MIE 0x00000008U +#define MSTATUS_UPIE 0x00000010U +#define MSTATUS_SPIE 0x00000020U +#define MSTATUS_HPIE 0x00000040U +#define MSTATUS_MPIE 0x00000080U +#define MSTATUS_SPP 0x00000100U +#define MSTATUS_HPP 0x00000600U +#define MSTATUS_MPP 0x00001800U +#define MSTATUS_FS 0x00006000U +#define MSTATUS_XS 0x00018000U +#define MSTATUS_MPRV 0x00020000U +#define MSTATUS_PUM 0x00040000U +#define MSTATUS_MXR 0x00080000U +#define MSTATUS_VM 0x1F000000U +#define MSTATUS32_SD 0x80000000U +#define MSTATUS64_SD 0x8000000000000000U + +#define SSTATUS_UIE 0x00000001U +#define SSTATUS_SIE 0x00000002U +#define SSTATUS_UPIE 0x00000010U +#define SSTATUS_SPIE 0x00000020U +#define SSTATUS_SPP 0x00000100U +#define SSTATUS_FS 0x00006000U +#define SSTATUS_XS 0x00018000U +#define SSTATUS_PUM 0x00040000U +#define SSTATUS32_SD 0x80000000U +#define SSTATUS64_SD 0x8000000000000000U + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1U<<29) +#define DCSR_FULLRESET (1U<<28) +#define DCSR_EBREAKM (1U<<15) +#define DCSR_EBREAKH (1U<<14) +#define DCSR_EBREAKS (1U<<13) +#define DCSR_EBREAKU (1U<<12) +#define DCSR_STOPCYCLE (1U<<10) +#define DCSR_STOPTIME (1U<<9) +#define DCSR_CAUSE (7U<<6) +#define DCSR_DEBUGINT (1U<<5) +#define DCSR_HALT (1U<<3) +#define DCSR_STEP (1U<<2) +#define DCSR_PRV (3U<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_SELECT (1U<<19) +#define MCONTROL_TIMING (1U<<18) +#define MCONTROL_ACTION (0x3fU<<12) +#define MCONTROL_CHAIN (1U<<11) +#define MCONTROL_MATCH (0xfU<<7) +#define MCONTROL_M (1U<<6) +#define MCONTROL_H (1U<<5) +#define MCONTROL_S (1U<<4) +#define MCONTROL_U (1U<<3) +#define MCONTROL_EXECUTE (1U<<2) +#define MCONTROL_STORE (1U<<1) +#define MCONTROL_LOAD (1U<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define VM_MBARE 0 +#define VM_MBB 1 +#define VM_MBBID 2 +#define VM_SV32 8 +#define VM_SV39 9 +#define VM_SV48 10 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000U +#define DEFAULT_NMIVEC 0x00001004U +#define DEFAULT_MTVEC 0x00001010U +#define CONFIG_STRING_ADDR 0x0000100CU +#define EXT_IO_BASE 0x40000000U +#define DRAM_BASE 0x80000000U + +/* page table entry (PTE) fields */ +#define PTE_V 0x001U /* Valid */ +#define PTE_R 0x002U /* Read */ +#define PTE_W 0x004U /* Write */ +#define PTE_X 0x008U /* Execute */ +#define PTE_U 0x010U /* User */ +#define PTE_G 0x020U /* Global */ +#define PTE_A 0x040U /* Accessed */ +#define PTE_D 0x080U /* Dirty */ +#define PTE_SOFT 0x300U /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#if defined(__riscv) + +#if defined(__riscv64) +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#if defined(__GNUC__) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ + else \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ + else \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define read_time() read_csr(mtime) +#define read_cycle() read_csr(mcycle) +#define current_coreid() read_csr(mhartid) + +#endif + +#endif + +#endif + +#endif + +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63U +#define MASK_BEQ 0x707fU +#define MATCH_BNE 0x1063U +#define MASK_BNE 0x707fU +#define MATCH_BLT 0x4063U +#define MASK_BLT 0x707fU +#define MATCH_BGE 0x5063U +#define MASK_BGE 0x707fU +#define MATCH_BLTU 0x6063U +#define MASK_BLTU 0x707fU +#define MATCH_BGEU 0x7063U +#define MASK_BGEU 0x707fU +#define MATCH_JALR 0x67U +#define MASK_JALR 0x707fU +#define MATCH_JAL 0x6fU +#define MASK_JAL 0x7fU +#define MATCH_LUI 0x37U +#define MASK_LUI 0x7fU +#define MATCH_AUIPC 0x17U +#define MASK_AUIPC 0x7fU +#define MATCH_ADDI 0x13U +#define MASK_ADDI 0x707fU +#define MATCH_SLLI 0x1013U +#define MASK_SLLI 0xfc00707fU +#define MATCH_SLTI 0x2013U +#define MASK_SLTI 0x707fU +#define MATCH_SLTIU 0x3013U +#define MASK_SLTIU 0x707fU +#define MATCH_XORI 0x4013U +#define MASK_XORI 0x707fU +#define MATCH_SRLI 0x5013U +#define MASK_SRLI 0xfc00707fU +#define MATCH_SRAI 0x40005013U +#define MASK_SRAI 0xfc00707fU +#define MATCH_ORI 0x6013U +#define MASK_ORI 0x707fU +#define MATCH_ANDI 0x7013U +#define MASK_ANDI 0x707fU +#define MATCH_ADD 0x33U +#define MASK_ADD 0xfe00707fU +#define MATCH_SUB 0x40000033U +#define MASK_SUB 0xfe00707fU +#define MATCH_SLL 0x1033U +#define MASK_SLL 0xfe00707fU +#define MATCH_SLT 0x2033U +#define MASK_SLT 0xfe00707fU +#define MATCH_SLTU 0x3033U +#define MASK_SLTU 0xfe00707fU +#define MATCH_XOR 0x4033U +#define MASK_XOR 0xfe00707fU +#define MATCH_SRL 0x5033U +#define MASK_SRL 0xfe00707fU +#define MATCH_SRA 0x40005033U +#define MASK_SRA 0xfe00707fU +#define MATCH_OR 0x6033U +#define MASK_OR 0xfe00707fU +#define MATCH_AND 0x7033U +#define MASK_AND 0xfe00707fU +#define MATCH_ADDIW 0x1bU +#define MASK_ADDIW 0x707fU +#define MATCH_SLLIW 0x101bU +#define MASK_SLLIW 0xfe00707fU +#define MATCH_SRLIW 0x501bU +#define MASK_SRLIW 0xfe00707fU +#define MATCH_SRAIW 0x4000501bU +#define MASK_SRAIW 0xfe00707fU +#define MATCH_ADDW 0x3bU +#define MASK_ADDW 0xfe00707fU +#define MATCH_SUBW 0x4000003bU +#define MASK_SUBW 0xfe00707fU +#define MATCH_SLLW 0x103bU +#define MASK_SLLW 0xfe00707fU +#define MATCH_SRLW 0x503bU +#define MASK_SRLW 0xfe00707fU +#define MATCH_SRAW 0x4000503bU +#define MASK_SRAW 0xfe00707fU +#define MATCH_LB 0x3U +#define MASK_LB 0x707fU +#define MATCH_LH 0x1003U +#define MASK_LH 0x707fU +#define MATCH_LW 0x2003U +#define MASK_LW 0x707fU +#define MATCH_LD 0x3003U +#define MASK_LD 0x707fU +#define MATCH_LBU 0x4003U +#define MASK_LBU 0x707fU +#define MATCH_LHU 0x5003U +#define MASK_LHU 0x707fU +#define MATCH_LWU 0x6003U +#define MASK_LWU 0x707fU +#define MATCH_SB 0x23U +#define MASK_SB 0x707fU +#define MATCH_SH 0x1023U +#define MASK_SH 0x707fU +#define MATCH_SW 0x2023U +#define MASK_SW 0x707fU +#define MATCH_SD 0x3023U +#define MASK_SD 0x707fU +#define MATCH_FENCE 0xfU +#define MASK_FENCE 0x707fU +#define MATCH_FENCE_I 0x100fU +#define MASK_FENCE_I 0x707fU +#define MATCH_MUL 0x2000033U +#define MASK_MUL 0xfe00707fU +#define MATCH_MULH 0x2001033U +#define MASK_MULH 0xfe00707fU +#define MATCH_MULHSU 0x2002033U +#define MASK_MULHSU 0xfe00707fU +#define MATCH_MULHU 0x2003033U +#define MASK_MULHU 0xfe00707fU +#define MATCH_DIV 0x2004033U +#define MASK_DIV 0xfe00707fU +#define MATCH_DIVU 0x2005033U +#define MASK_DIVU 0xfe00707fU +#define MATCH_REM 0x2006033U +#define MASK_REM 0xfe00707fU +#define MATCH_REMU 0x2007033U +#define MASK_REMU 0xfe00707fU +#define MATCH_MULW 0x200003bU +#define MASK_MULW 0xfe00707fU +#define MATCH_DIVW 0x200403bU +#define MASK_DIVW 0xfe00707fU +#define MATCH_DIVUW 0x200503bU +#define MASK_DIVUW 0xfe00707fU +#define MATCH_REMW 0x200603bU +#define MASK_REMW 0xfe00707fU +#define MATCH_REMUW 0x200703bU +#define MASK_REMUW 0xfe00707fU +#define MATCH_AMOADD_W 0x202fU +#define MASK_AMOADD_W 0xf800707fU +#define MATCH_AMOXOR_W 0x2000202fU +#define MASK_AMOXOR_W 0xf800707fU +#define MATCH_AMOOR_W 0x4000202fU +#define MASK_AMOOR_W 0xf800707fU +#define MATCH_AMOAND_W 0x6000202fU +#define MASK_AMOAND_W 0xf800707fU +#define MATCH_AMOMIN_W 0x8000202fU +#define MASK_AMOMIN_W 0xf800707fU +#define MATCH_AMOMAX_W 0xa000202fU +#define MASK_AMOMAX_W 0xf800707fU +#define MATCH_AMOMINU_W 0xc000202fU +#define MASK_AMOMINU_W 0xf800707fU +#define MATCH_AMOMAXU_W 0xe000202fU +#define MASK_AMOMAXU_W 0xf800707fU +#define MATCH_AMOSWAP_W 0x800202fU +#define MASK_AMOSWAP_W 0xf800707fU +#define MATCH_LR_W 0x1000202fU +#define MASK_LR_W 0xf9f0707fU +#define MATCH_SC_W 0x1800202fU +#define MASK_SC_W 0xf800707fU +#define MATCH_AMOADD_D 0x302fU +#define MASK_AMOADD_D 0xf800707fU +#define MATCH_AMOXOR_D 0x2000302fU +#define MASK_AMOXOR_D 0xf800707fU +#define MATCH_AMOOR_D 0x4000302fU +#define MASK_AMOOR_D 0xf800707fU +#define MATCH_AMOAND_D 0x6000302fU +#define MASK_AMOAND_D 0xf800707fU +#define MATCH_AMOMIN_D 0x8000302fU +#define MASK_AMOMIN_D 0xf800707fU +#define MATCH_AMOMAX_D 0xa000302fU +#define MASK_AMOMAX_D 0xf800707fU +#define MATCH_AMOMINU_D 0xc000302fU +#define MASK_AMOMINU_D 0xf800707fU +#define MATCH_AMOMAXU_D 0xe000302fU +#define MASK_AMOMAXU_D 0xf800707fU +#define MATCH_AMOSWAP_D 0x800302fU +#define MASK_AMOSWAP_D 0xf800707fU +#define MATCH_LR_D 0x1000302fU +#define MASK_LR_D 0xf9f0707fU +#define MATCH_SC_D 0x1800302fU +#define MASK_SC_D 0xf800707fU +#define MATCH_ECALL 0x73U +#define MASK_ECALL 0xffffffffU +#define MATCH_EBREAK 0x100073U +#define MASK_EBREAK 0xffffffffU +#define MATCH_URET 0x200073U +#define MASK_URET 0xffffffffU +#define MATCH_SRET 0x10200073U +#define MASK_SRET 0xffffffffU +#define MATCH_HRET 0x20200073U +#define MASK_HRET 0xffffffffU +#define MATCH_MRET 0x30200073U +#define MASK_MRET 0xffffffffU +#define MATCH_DRET 0x7b200073U +#define MASK_DRET 0xffffffffU +#define MATCH_SFENCE_VM 0x10400073U +#define MASK_SFENCE_VM 0xfff07fffU +#define MATCH_WFI 0x10500073U +#define MASK_WFI 0xffffffffU +#define MATCH_CSRRW 0x1073U +#define MASK_CSRRW 0x707fU +#define MATCH_CSRRS 0x2073U +#define MASK_CSRRS 0x707fU +#define MATCH_CSRRC 0x3073U +#define MASK_CSRRC 0x707fU +#define MATCH_CSRRWI 0x5073U +#define MASK_CSRRWI 0x707fU +#define MATCH_CSRRSI 0x6073U +#define MASK_CSRRSI 0x707fU +#define MATCH_CSRRCI 0x7073U +#define MASK_CSRRCI 0x707fU +#define MATCH_FADD_S 0x53U +#define MASK_FADD_S 0xfe00007fU +#define MATCH_FSUB_S 0x8000053U +#define MASK_FSUB_S 0xfe00007fU +#define MATCH_FMUL_S 0x10000053U +#define MASK_FMUL_S 0xfe00007fU +#define MATCH_FDIV_S 0x18000053U +#define MASK_FDIV_S 0xfe00007fU +#define MATCH_FSGNJ_S 0x20000053U +#define MASK_FSGNJ_S 0xfe00707fU +#define MATCH_FSGNJN_S 0x20001053U +#define MASK_FSGNJN_S 0xfe00707fU +#define MATCH_FSGNJX_S 0x20002053U +#define MASK_FSGNJX_S 0xfe00707fU +#define MATCH_FMIN_S 0x28000053U +#define MASK_FMIN_S 0xfe00707fU +#define MATCH_FMAX_S 0x28001053U +#define MASK_FMAX_S 0xfe00707fU +#define MATCH_FSQRT_S 0x58000053U +#define MASK_FSQRT_S 0xfff0007fU +#define MATCH_FADD_D 0x2000053U +#define MASK_FADD_D 0xfe00007fU +#define MATCH_FSUB_D 0xa000053U +#define MASK_FSUB_D 0xfe00007fU +#define MATCH_FMUL_D 0x12000053U +#define MASK_FMUL_D 0xfe00007fU +#define MATCH_FDIV_D 0x1a000053U +#define MASK_FDIV_D 0xfe00007fU +#define MATCH_FSGNJ_D 0x22000053U +#define MASK_FSGNJ_D 0xfe00707fU +#define MATCH_FSGNJN_D 0x22001053U +#define MASK_FSGNJN_D 0xfe00707fU +#define MATCH_FSGNJX_D 0x22002053U +#define MASK_FSGNJX_D 0xfe00707fU +#define MATCH_FMIN_D 0x2a000053U +#define MASK_FMIN_D 0xfe00707fU +#define MATCH_FMAX_D 0x2a001053U +#define MASK_FMAX_D 0xfe00707fU +#define MATCH_FCVT_S_D 0x40100053U +#define MASK_FCVT_S_D 0xfff0007fU +#define MATCH_FCVT_D_S 0x42000053U +#define MASK_FCVT_D_S 0xfff0007fU +#define MATCH_FSQRT_D 0x5a000053U +#define MASK_FSQRT_D 0xfff0007fU +#define MATCH_FLE_S 0xa0000053U +#define MASK_FLE_S 0xfe00707fU +#define MATCH_FLT_S 0xa0001053U +#define MASK_FLT_S 0xfe00707fU +#define MATCH_FEQ_S 0xa0002053U +#define MASK_FEQ_S 0xfe00707fU +#define MATCH_FLE_D 0xa2000053U +#define MASK_FLE_D 0xfe00707fU +#define MATCH_FLT_D 0xa2001053U +#define MASK_FLT_D 0xfe00707fU +#define MATCH_FEQ_D 0xa2002053U +#define MASK_FEQ_D 0xfe00707fU +#define MATCH_FCVT_W_S 0xc0000053U +#define MASK_FCVT_W_S 0xfff0007fU +#define MATCH_FCVT_WU_S 0xc0100053U +#define MASK_FCVT_WU_S 0xfff0007fU +#define MATCH_FCVT_L_S 0xc0200053U +#define MASK_FCVT_L_S 0xfff0007fU +#define MATCH_FCVT_LU_S 0xc0300053U +#define MASK_FCVT_LU_S 0xfff0007fU +#define MATCH_FMV_X_S 0xe0000053U +#define MASK_FMV_X_S 0xfff0707fU +#define MATCH_FCLASS_S 0xe0001053U +#define MASK_FCLASS_S 0xfff0707fU +#define MATCH_FCVT_W_D 0xc2000053U +#define MASK_FCVT_W_D 0xfff0007fU +#define MATCH_FCVT_WU_D 0xc2100053U +#define MASK_FCVT_WU_D 0xfff0007fU +#define MATCH_FCVT_L_D 0xc2200053U +#define MASK_FCVT_L_D 0xfff0007fU +#define MATCH_FCVT_LU_D 0xc2300053U +#define MASK_FCVT_LU_D 0xfff0007fU +#define MATCH_FMV_X_D 0xe2000053U +#define MASK_FMV_X_D 0xfff0707fU +#define MATCH_FCLASS_D 0xe2001053U +#define MASK_FCLASS_D 0xfff0707fU +#define MATCH_FCVT_S_W 0xd0000053U +#define MASK_FCVT_S_W 0xfff0007fU +#define MATCH_FCVT_S_WU 0xd0100053U +#define MASK_FCVT_S_WU 0xfff0007fU +#define MATCH_FCVT_S_L 0xd0200053U +#define MASK_FCVT_S_L 0xfff0007fU +#define MATCH_FCVT_S_LU 0xd0300053U +#define MASK_FCVT_S_LU 0xfff0007fU +#define MATCH_FMV_S_X 0xf0000053U +#define MASK_FMV_S_X 0xfff0707fU +#define MATCH_FCVT_D_W 0xd2000053U +#define MASK_FCVT_D_W 0xfff0007fU +#define MATCH_FCVT_D_WU 0xd2100053U +#define MASK_FCVT_D_WU 0xfff0007fU +#define MATCH_FCVT_D_L 0xd2200053U +#define MASK_FCVT_D_L 0xfff0007fU +#define MATCH_FCVT_D_LU 0xd2300053U +#define MASK_FCVT_D_LU 0xfff0007fU +#define MATCH_FMV_D_X 0xf2000053U +#define MASK_FMV_D_X 0xfff0707fU +#define MATCH_FLW 0x2007U +#define MASK_FLW 0x707fU +#define MATCH_FLD 0x3007U +#define MASK_FLD 0x707fU +#define MATCH_FSW 0x2027U +#define MASK_FSW 0x707fU +#define MATCH_FSD 0x3027U +#define MASK_FSD 0x707fU +#define MATCH_FMADD_S 0x43U +#define MASK_FMADD_S 0x600007fU +#define MATCH_FMSUB_S 0x47U +#define MASK_FMSUB_S 0x600007fU +#define MATCH_FNMSUB_S 0x4bU +#define MASK_FNMSUB_S 0x600007fU +#define MATCH_FNMADD_S 0x4fU +#define MASK_FNMADD_S 0x600007fU +#define MATCH_FMADD_D 0x2000043U +#define MASK_FMADD_D 0x600007fU +#define MATCH_FMSUB_D 0x2000047U +#define MASK_FMSUB_D 0x600007fU +#define MATCH_FNMSUB_D 0x200004bU +#define MASK_FNMSUB_D 0x600007fU +#define MATCH_FNMADD_D 0x200004fU +#define MASK_FNMADD_D 0x600007fU +#define MATCH_C_NOP 0x1U +#define MASK_C_NOP 0xffffU +#define MATCH_C_ADDI16SP 0x6101U +#define MASK_C_ADDI16SP 0xef83U +#define MATCH_C_JR 0x8002U +#define MASK_C_JR 0xf07fU +#define MATCH_C_JALR 0x9002U +#define MASK_C_JALR 0xf07fU +#define MATCH_C_EBREAK 0x9002U +#define MASK_C_EBREAK 0xffffU +#define MATCH_C_LD 0x6000U +#define MASK_C_LD 0xe003U +#define MATCH_C_SD 0xe000U +#define MASK_C_SD 0xe003U +#define MATCH_C_ADDIW 0x2001U +#define MASK_C_ADDIW 0xe003U +#define MATCH_C_LDSP 0x6002U +#define MASK_C_LDSP 0xe003U +#define MATCH_C_SDSP 0xe002U +#define MASK_C_SDSP 0xe003U +#define MATCH_C_ADDI4SPN 0x0U +#define MASK_C_ADDI4SPN 0xe003U +#define MATCH_C_FLD 0x2000U +#define MASK_C_FLD 0xe003U +#define MATCH_C_LW 0x4000U +#define MASK_C_LW 0xe003U +#define MATCH_C_FLW 0x6000U +#define MASK_C_FLW 0xe003U +#define MATCH_C_FSD 0xa000U +#define MASK_C_FSD 0xe003U +#define MATCH_C_SW 0xc000U +#define MASK_C_SW 0xe003U +#define MATCH_C_FSW 0xe000U +#define MASK_C_FSW 0xe003U +#define MATCH_C_ADDI 0x1U +#define MASK_C_ADDI 0xe003U +#define MATCH_C_JAL 0x2001U +#define MASK_C_JAL 0xe003U +#define MATCH_C_LI 0x4001U +#define MASK_C_LI 0xe003U +#define MATCH_C_LUI 0x6001U +#define MASK_C_LUI 0xe003U +#define MATCH_C_SRLI 0x8001U +#define MASK_C_SRLI 0xec03U +#define MATCH_C_SRAI 0x8401U +#define MASK_C_SRAI 0xec03U +#define MATCH_C_ANDI 0x8801U +#define MASK_C_ANDI 0xec03U +#define MATCH_C_SUB 0x8c01U +#define MASK_C_SUB 0xfc63U +#define MATCH_C_XOR 0x8c21U +#define MASK_C_XOR 0xfc63U +#define MATCH_C_OR 0x8c41U +#define MASK_C_OR 0xfc63U +#define MATCH_C_AND 0x8c61U +#define MASK_C_AND 0xfc63U +#define MATCH_C_SUBW 0x9c01U +#define MASK_C_SUBW 0xfc63U +#define MATCH_C_ADDW 0x9c21U +#define MASK_C_ADDW 0xfc63U +#define MATCH_C_J 0xa001U +#define MASK_C_J 0xe003U +#define MATCH_C_BEQZ 0xc001U +#define MASK_C_BEQZ 0xe003U +#define MATCH_C_BNEZ 0xe001U +#define MASK_C_BNEZ 0xe003U +#define MATCH_C_SLLI 0x2U +#define MASK_C_SLLI 0xe003U +#define MATCH_C_FLDSP 0x2002U +#define MASK_C_FLDSP 0xe003U +#define MATCH_C_LWSP 0x4002U +#define MASK_C_LWSP 0xe003U +#define MATCH_C_FLWSP 0x6002U +#define MASK_C_FLWSP 0xe003U +#define MATCH_C_MV 0x8002U +#define MASK_C_MV 0xf003U +#define MATCH_C_ADD 0x9002U +#define MASK_C_ADD 0xf003U +#define MATCH_C_FSDSP 0xa002U +#define MASK_C_FSDSP 0xe003U +#define MATCH_C_SWSP 0xc002U +#define MASK_C_SWSP 0xe003U +#define MATCH_C_FSWSP 0xe002U +#define MASK_C_FSWSP 0xe003U +#define MATCH_CUSTOM0 0xbU +#define MASK_CUSTOM0 0x707fU +#define MATCH_CUSTOM0_RS1 0x200bU +#define MASK_CUSTOM0_RS1 0x707fU +#define MATCH_CUSTOM0_RS1_RS2 0x300bU +#define MASK_CUSTOM0_RS1_RS2 0x707fU +#define MATCH_CUSTOM0_RD 0x400bU +#define MASK_CUSTOM0_RD 0x707fU +#define MATCH_CUSTOM0_RD_RS1 0x600bU +#define MASK_CUSTOM0_RD_RS1 0x707fU +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700bU +#define MASK_CUSTOM0_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM1 0x2bU +#define MASK_CUSTOM1 0x707fU +#define MATCH_CUSTOM1_RS1 0x202bU +#define MASK_CUSTOM1_RS1 0x707fU +#define MATCH_CUSTOM1_RS1_RS2 0x302bU +#define MASK_CUSTOM1_RS1_RS2 0x707fU +#define MATCH_CUSTOM1_RD 0x402bU +#define MASK_CUSTOM1_RD 0x707fU +#define MATCH_CUSTOM1_RD_RS1 0x602bU +#define MASK_CUSTOM1_RD_RS1 0x707fU +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702bU +#define MASK_CUSTOM1_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM2 0x5bU +#define MASK_CUSTOM2 0x707fU +#define MATCH_CUSTOM2_RS1 0x205bU +#define MASK_CUSTOM2_RS1 0x707fU +#define MATCH_CUSTOM2_RS1_RS2 0x305bU +#define MASK_CUSTOM2_RS1_RS2 0x707fU +#define MATCH_CUSTOM2_RD 0x405bU +#define MASK_CUSTOM2_RD 0x707fU +#define MATCH_CUSTOM2_RD_RS1 0x605bU +#define MASK_CUSTOM2_RD_RS1 0x707fU +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705bU +#define MASK_CUSTOM2_RD_RS1_RS2 0x707fU +#define MATCH_CUSTOM3 0x7bU +#define MASK_CUSTOM3 0x707fU +#define MATCH_CUSTOM3_RS1 0x207bU +#define MASK_CUSTOM3_RS1 0x707fU +#define MATCH_CUSTOM3_RS1_RS2 0x307bU +#define MASK_CUSTOM3_RS1_RS2 0x707fU +#define MATCH_CUSTOM3_RD 0x407bU +#define MASK_CUSTOM3_RD 0x707fU +#define MATCH_CUSTOM3_RD_RS1 0x607bU +#define MASK_CUSTOM3_RD_RS1 0x707fU +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707bU +#define MASK_CUSTOM3_RD_RS1_RS2 0x707fU +#define CSR_FFLAGS 0x1U +#define CSR_FRM 0x2U +#define CSR_FCSR 0x3U +#define CSR_CYCLE 0xc00U +#define CSR_TIME 0xc01U +#define CSR_INSTRET 0xc02U +#define CSR_HPMCOUNTER3 0xc03U +#define CSR_HPMCOUNTER4 0xc04U +#define CSR_HPMCOUNTER5 0xc05U +#define CSR_HPMCOUNTER6 0xc06U +#define CSR_HPMCOUNTER7 0xc07U +#define CSR_HPMCOUNTER8 0xc08U +#define CSR_HPMCOUNTER9 0xc09U +#define CSR_HPMCOUNTER10 0xc0aU +#define CSR_HPMCOUNTER11 0xc0bU +#define CSR_HPMCOUNTER12 0xc0cU +#define CSR_HPMCOUNTER13 0xc0dU +#define CSR_HPMCOUNTER14 0xc0eU +#define CSR_HPMCOUNTER15 0xc0fU +#define CSR_HPMCOUNTER16 0xc10U +#define CSR_HPMCOUNTER17 0xc11U +#define CSR_HPMCOUNTER18 0xc12U +#define CSR_HPMCOUNTER19 0xc13U +#define CSR_HPMCOUNTER20 0xc14U +#define CSR_HPMCOUNTER21 0xc15U +#define CSR_HPMCOUNTER22 0xc16U +#define CSR_HPMCOUNTER23 0xc17U +#define CSR_HPMCOUNTER24 0xc18U +#define CSR_HPMCOUNTER25 0xc19U +#define CSR_HPMCOUNTER26 0xc1aU +#define CSR_HPMCOUNTER27 0xc1bU +#define CSR_HPMCOUNTER28 0xc1cU +#define CSR_HPMCOUNTER29 0xc1dU +#define CSR_HPMCOUNTER30 0xc1eU +#define CSR_HPMCOUNTER31 0xc1fU +#define CSR_SSTATUS 0x100U +#define CSR_SIE 0x104U +#define CSR_STVEC 0x105U +#define CSR_SSCRATCH 0x140U +#define CSR_SEPC 0x141U +#define CSR_SCAUSE 0x142U +#define CSR_SBADADDR 0x143U +#define CSR_SIP 0x144U +#define CSR_SPTBR 0x180U +#define CSR_MSTATUS 0x300U +#define CSR_MISA 0x301U +#define CSR_MEDELEG 0x302U +#define CSR_MIDELEG 0x303U +#define CSR_MIE 0x304U +#define CSR_MTVEC 0x305U +#define CSR_MSCRATCH 0x340U +#define CSR_MEPC 0x341U +#define CSR_MCAUSE 0x342U +#define CSR_MBADADDR 0x343U +#define CSR_MIP 0x344U +#define CSR_TSELECT 0x7a0U +#define CSR_TDATA1 0x7a1U +#define CSR_TDATA2 0x7a2U +#define CSR_TDATA3 0x7a3U +#define CSR_DCSR 0x7b0U +#define CSR_DPC 0x7b1U +#define CSR_DSCRATCH 0x7b2U +#define CSR_MCYCLE 0xb00U +#define CSR_MINSTRET 0xb02U +#define CSR_MHPMCOUNTER3 0xb03U +#define CSR_MHPMCOUNTER4 0xb04U +#define CSR_MHPMCOUNTER5 0xb05U +#define CSR_MHPMCOUNTER6 0xb06U +#define CSR_MHPMCOUNTER7 0xb07U +#define CSR_MHPMCOUNTER8 0xb08U +#define CSR_MHPMCOUNTER9 0xb09U +#define CSR_MHPMCOUNTER10 0xb0aU +#define CSR_MHPMCOUNTER11 0xb0bU +#define CSR_MHPMCOUNTER12 0xb0cU +#define CSR_MHPMCOUNTER13 0xb0dU +#define CSR_MHPMCOUNTER14 0xb0eU +#define CSR_MHPMCOUNTER15 0xb0fU +#define CSR_MHPMCOUNTER16 0xb10U +#define CSR_MHPMCOUNTER17 0xb11U +#define CSR_MHPMCOUNTER18 0xb12U +#define CSR_MHPMCOUNTER19 0xb13U +#define CSR_MHPMCOUNTER20 0xb14U +#define CSR_MHPMCOUNTER21 0xb15U +#define CSR_MHPMCOUNTER22 0xb16U +#define CSR_MHPMCOUNTER23 0xb17U +#define CSR_MHPMCOUNTER24 0xb18U +#define CSR_MHPMCOUNTER25 0xb19U +#define CSR_MHPMCOUNTER26 0xb1aU +#define CSR_MHPMCOUNTER27 0xb1bU +#define CSR_MHPMCOUNTER28 0xb1cU +#define CSR_MHPMCOUNTER29 0xb1dU +#define CSR_MHPMCOUNTER30 0xb1eU +#define CSR_MHPMCOUNTER31 0xb1fU +#define CSR_MUCOUNTEREN 0x320U +#define CSR_MSCOUNTEREN 0x321U +#define CSR_MHPMEVENT3 0x323U +#define CSR_MHPMEVENT4 0x324U +#define CSR_MHPMEVENT5 0x325U +#define CSR_MHPMEVENT6 0x326U +#define CSR_MHPMEVENT7 0x327U +#define CSR_MHPMEVENT8 0x328U +#define CSR_MHPMEVENT9 0x329U +#define CSR_MHPMEVENT10 0x32aU +#define CSR_MHPMEVENT11 0x32bU +#define CSR_MHPMEVENT12 0x32cU +#define CSR_MHPMEVENT13 0x32dU +#define CSR_MHPMEVENT14 0x32eU +#define CSR_MHPMEVENT15 0x32fU +#define CSR_MHPMEVENT16 0x330U +#define CSR_MHPMEVENT17 0x331U +#define CSR_MHPMEVENT18 0x332U +#define CSR_MHPMEVENT19 0x333U +#define CSR_MHPMEVENT20 0x334U +#define CSR_MHPMEVENT21 0x335U +#define CSR_MHPMEVENT22 0x336U +#define CSR_MHPMEVENT23 0x337U +#define CSR_MHPMEVENT24 0x338U +#define CSR_MHPMEVENT25 0x339U +#define CSR_MHPMEVENT26 0x33aU +#define CSR_MHPMEVENT27 0x33bU +#define CSR_MHPMEVENT28 0x33cU +#define CSR_MHPMEVENT29 0x33dU +#define CSR_MHPMEVENT30 0x33eU +#define CSR_MHPMEVENT31 0x33fU +#define CSR_MVENDORID 0xf11U +#define CSR_MARCHID 0xf12U +#define CSR_MIMPID 0xf13U +#define CSR_MHARTID 0xf14U +#define CSR_CYCLEH 0xc80U +#define CSR_TIMEH 0xc81U +#define CSR_INSTRETH 0xc82U +#define CSR_HPMCOUNTER3H 0xc83U +#define CSR_HPMCOUNTER4H 0xc84U +#define CSR_HPMCOUNTER5H 0xc85U +#define CSR_HPMCOUNTER6H 0xc86U +#define CSR_HPMCOUNTER7H 0xc87U +#define CSR_HPMCOUNTER8H 0xc88U +#define CSR_HPMCOUNTER9H 0xc89U +#define CSR_HPMCOUNTER10H 0xc8aU +#define CSR_HPMCOUNTER11H 0xc8bU +#define CSR_HPMCOUNTER12H 0xc8cU +#define CSR_HPMCOUNTER13H 0xc8dU +#define CSR_HPMCOUNTER14H 0xc8eU +#define CSR_HPMCOUNTER15H 0xc8fU +#define CSR_HPMCOUNTER16H 0xc90U +#define CSR_HPMCOUNTER17H 0xc91U +#define CSR_HPMCOUNTER18H 0xc92U +#define CSR_HPMCOUNTER19H 0xc93U +#define CSR_HPMCOUNTER20H 0xc94U +#define CSR_HPMCOUNTER21H 0xc95U +#define CSR_HPMCOUNTER22H 0xc96U +#define CSR_HPMCOUNTER23H 0xc97U +#define CSR_HPMCOUNTER24H 0xc98U +#define CSR_HPMCOUNTER25H 0xc99U +#define CSR_HPMCOUNTER26H 0xc9aU +#define CSR_HPMCOUNTER27H 0xc9bU +#define CSR_HPMCOUNTER28H 0xc9cU +#define CSR_HPMCOUNTER29H 0xc9dU +#define CSR_HPMCOUNTER30H 0xc9eU +#define CSR_HPMCOUNTER31H 0xc9fU +#define CSR_MCYCLEH 0xb80U +#define CSR_MINSTRETH 0xb82U +#define CSR_MHPMCOUNTER3H 0xb83U +#define CSR_MHPMCOUNTER4H 0xb84U +#define CSR_MHPMCOUNTER5H 0xb85U +#define CSR_MHPMCOUNTER6H 0xb86U +#define CSR_MHPMCOUNTER7H 0xb87U +#define CSR_MHPMCOUNTER8H 0xb88U +#define CSR_MHPMCOUNTER9H 0xb89U +#define CSR_MHPMCOUNTER10H 0xb8aU +#define CSR_MHPMCOUNTER11H 0xb8bU +#define CSR_MHPMCOUNTER12H 0xb8cU +#define CSR_MHPMCOUNTER13H 0xb8dU +#define CSR_MHPMCOUNTER14H 0xb8eU +#define CSR_MHPMCOUNTER15H 0xb8fU +#define CSR_MHPMCOUNTER16H 0xb90U +#define CSR_MHPMCOUNTER17H 0xb91U +#define CSR_MHPMCOUNTER18H 0xb92U +#define CSR_MHPMCOUNTER19H 0xb93U +#define CSR_MHPMCOUNTER20H 0xb94U +#define CSR_MHPMCOUNTER21H 0xb95U +#define CSR_MHPMCOUNTER22H 0xb96U +#define CSR_MHPMCOUNTER23H 0xb97U +#define CSR_MHPMCOUNTER24H 0xb98U +#define CSR_MHPMCOUNTER25H 0xb99U +#define CSR_MHPMCOUNTER26H 0xb9aU +#define CSR_MHPMCOUNTER27H 0xb9bU +#define CSR_MHPMCOUNTER28H 0xb9cU +#define CSR_MHPMCOUNTER29H 0xb9dU +#define CSR_MHPMCOUNTER30H 0xb9eU +#define CSR_MHPMCOUNTER31H 0xb9fU +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#endif +#if defined(DECLARE_INSN) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#if defined(DECLARE_CSR) +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#if defined(DECLARE_CAUSE) +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +#endif + diff --git a/lib/bsp/include/entry.h b/lib/bsp/include/entry.h new file mode 100755 index 0000000..e9ab5b9 --- /dev/null +++ b/lib/bsp/include/entry.h @@ -0,0 +1,81 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_ENTRY_H +#define _BSP_ENTRY_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*core_function)(void *ctx); + +typedef struct _core_instance_t +{ + core_function callback; + void *ctx; +} core_instance_t; + +int register_core1(core_function func, void *ctx); + +static inline void init_lma(void) +{ + extern unsigned int _data_lma; + extern unsigned int _data; + extern unsigned int _edata; + unsigned int *src, *dst; + + src = &_data_lma; + dst = &_data; + while (dst < &_edata) + *dst++ = *src++; +} + +static inline void init_bss(void) +{ + extern unsigned int _bss; + extern unsigned int _ebss; + unsigned int *dst; + + dst = &_bss; + while (dst < &_ebss) + *dst++ = 0; +} + +static inline void init_tls(void) +{ + register void *thread_pointer asm("tp"); + extern char _tls_data; + + extern __thread char _tdata_begin, _tdata_end, _tbss_end; + + size_t tdata_size = &_tdata_end - &_tdata_begin; + + memcpy(thread_pointer, &_tls_data, tdata_size); + + size_t tbss_size = &_tbss_end - &_tdata_end; + + memset(thread_pointer + tdata_size, 0, tbss_size); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_ENTRY_H */ + diff --git a/lib/bsp/include/interrupt.h b/lib/bsp/include/interrupt.h new file mode 100755 index 0000000..160690e --- /dev/null +++ b/lib/bsp/include/interrupt.h @@ -0,0 +1,47 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_INTERRUPT_H +#define _BSP_INTERRUPT_H + +#ifdef __cplusplus +extern "C" { +#endif +/* clang-format off */ +/* Machine interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_MACHINE_IRQ_MASK (0x1ULL << 63) + +/* Machine interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_MACHINE_IRQ_REASON_MASK (CAUSE_MACHINE_IRQ_MASK - 1) + +/* Hypervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_HYPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Hypervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_HYPERVISOR_IRQ_REASON_MASK (CAUSE_HYPERVISOR_IRQ_MASK - 1) + +/* Supervisor interrupt mask for 64 bit system, 0x8000 0000 0000 0000 */ +#define CAUSE_SUPERVISOR_IRQ_MASK (0x1ULL << 63) + +/* Supervisor interrupt reason mask for 64 bit system, 0x7FFF FFFF FFFF FFFF */ +#define CAUSE_SUPERVISOR_IRQ_REASON_MASK (CAUSE_SUPERVISOR_IRQ_MASK - 1) +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_INTERRUPT_H */ + diff --git a/lib/bsp/include/platform.h b/lib/bsp/include/platform.h new file mode 100755 index 0000000..6ce0355 --- /dev/null +++ b/lib/bsp/include/platform.h @@ -0,0 +1,99 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_PLATFORM_H +#define _BSP_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register base address */ + +/* Under Coreplex */ +#define CLINT_BASE_ADDR (0x02000000U) +#define PLIC_BASE_ADDR (0x0C000000U) + +/* Under TileLink */ +#define UARTHS_BASE_ADDR (0x38000000U) +#define GPIOHS_BASE_ADDR (0x38001000U) + +/* Under AXI 64 bit */ +#define RAM_BASE_ADDR (0x80000000U) +#define RAM_SIZE (6 * 1024 * 1024U) + +#define IO_BASE_ADDR (0x40000000U) +#define IO_SIZE (6 * 1024 * 1024U) + +#define AI_RAM_BASE_ADDR (0x80600000U) +#define AI_RAM_SIZE (2 * 1024 * 1024U) + +#define AI_IO_BASE_ADDR (0x40600000U) +#define AI_IO_SIZE (2 * 1024 * 1024U) + +#define AI_BASE_ADDR (0x40800000U) +#define AI_SIZE (12 * 1024 * 1024U) + +#define FFT_BASE_ADDR (0x42000000U) +#define FFT_SIZE (4 * 1024 * 1024U) + +#define ROM_BASE_ADDR (0x88000000U) +#define ROM_SIZE (128 * 1024U) + +/* Under AHB 32 bit */ +#define DMAC_BASE_ADDR (0x50000000U) + +/* Under APB1 32 bit */ +#define GPIO_BASE_ADDR (0x50200000U) +#define UART1_BASE_ADDR (0x50210000U) +#define UART2_BASE_ADDR (0x50220000U) +#define UART3_BASE_ADDR (0x50230000U) +#define SPI_SLAVE_BASE_ADDR (0x50240000U) +#define I2S0_BASE_ADDR (0x50250000U) +#define I2S1_BASE_ADDR (0x50260000U) +#define I2S2_BASE_ADDR (0x50270000U) +#define I2C0_BASE_ADDR (0x50280000U) +#define I2C1_BASE_ADDR (0x50290000U) +#define I2C2_BASE_ADDR (0x502A0000U) +#define FPIOA_BASE_ADDR (0x502B0000U) +#define SHA256_BASE_ADDR (0x502C0000U) +#define TIMER0_BASE_ADDR (0x502D0000U) +#define TIMER1_BASE_ADDR (0x502E0000U) +#define TIMER2_BASE_ADDR (0x502F0000U) + +/* Under APB2 32 bit */ +#define WDT0_BASE_ADDR (0x50400000U) +#define WDT1_BASE_ADDR (0x50410000U) +#define OTP_BASE_ADDR (0x50420000U) +#define DVP_BASE_ADDR (0x50430000U) +#define SYSCTL_BASE_ADDR (0x50440000U) +#define AES_BASE_ADDR (0x50450000U) +#define RTC_BASE_ADDR (0x50460000U) + + +/* Under APB3 32 bit */ +#define SPI0_BASE_ADDR (0x52000000U) +#define SPI1_BASE_ADDR (0x53000000U) +#define SPI3_BASE_ADDR (0x54000000U) + +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PLATFORM_H */ + diff --git a/lib/bsp/include/printf.h b/lib/bsp/include/printf.h new file mode 100755 index 0000000..fa19cd4 --- /dev/null +++ b/lib/bsp/include/printf.h @@ -0,0 +1,209 @@ +/** + * File: printf.h + * + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Kustaa Nyholm or SpareTimeLabs 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 COPYRIGHT HOLDER 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'. + * + * They provide a simple and small (+400 loc) printf functionality to be used + * in embedded systems. + * + * I've found them so useful in debugging that I do not bother with a debugger + * at all. + * + * They are distributed in source form, so to use them, just compile them into + * your project. + * + * Two printf variants are provided: printf and the 'sprintf' family of + * functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf'). + * + * The formats supported by this implementation are: 'c' 'd' 'i' 'o' 'p' 'u' + * 's' 'x' 'X'. + * + * Zero padding, field width, and precision are also supported. + * + * If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then the + * long specifier is also supported. Note that this will pull in some long + * math routines (pun intended!) and thus make your executable noticeably + * longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the long long + * specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t specifier. + * + * The memory footprint of course depends on the target CPU, compiler and + * compiler options, but a rough guesstimate (based on a H8S target) is about + * 1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack + * space. Not too bad. Your mileage may vary. By hacking the source code you + * can get rid of some hundred bytes, I'm sure, but personally I feel the + * balance of functionality and flexibility versus code size is close to + * optimal for many embedded systems. + * + * To use the printf, you need to supply your own character output function, + * something like : + * + * void putc ( void* p, char c) { while (!SERIAL_PORT_EMPTY) ; + * SERIAL_PORT_TX_REGISTER = c; } + * + * Before you can call printf, you need to initialize it to use your character + * output function with something like: + * + * init_printf(NULL,putc); + * + * Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', + * the NULL (or any pointer) you pass into the 'init_printf' will eventually + * be passed to your 'putc' routine. This allows you to pass some storage + * space (or anything really) to the character output function, if necessary. + * This is not often needed but it was implemented like that because it made + * implementing the sprintf function so neat (look at the source code). + * + * The code is re-entrant, except for the 'init_printf' function, so it is + * safe to call it from interrupts too, although this may result in mixed + * output. If you rely on re-entrancy, take care that your 'putc' function is + * re-entrant! + * + * The printf and sprintf functions are actually macros that translate to + * 'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set + * (default). Setting it to 0 makes it possible to use them along with + * 'stdio.h' printf's in a single source file. When 'TINYPRINTF_OVERRIDE_LIBC' + * is set, please note that printf/sprintf are not function-like macros, so if + * you have variables or struct members with these names, things will explode + * in your face. Without variadic macros this is the best we can do to wrap + * these function. If it is a problem, just give up the macros and use the + * functions directly, or rename them. + * + * It is also possible to avoid defining tfp_printf and/or tfp_sprintf by + * clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or + * 'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to export + * only tfp_format, which is at the core of all the other functions. + * + * For further details see source code. + * + * regs Kusti, 23.10.2004 + */ + +#ifndef _BSP_PRINTF_H +#define _BSP_PRINTF_H + +#include +#include + +/* Global configuration */ + +/* Set this to 0 if you do not want to provide tfp_printf */ +#ifndef TINYPRINTF_DEFINE_TFP_PRINTF +#define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#endif + +/** + * Set this to 0 if you do not want to provide + * tfp_sprintf/snprintf/vsprintf/vsnprintf + */ +#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF +#define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#endif + +/** + * Set this to 0 if you do not want tfp_printf and + * tfp_{vsn,sn,vs,s}printf to be also available as + * printf/{vsn,sn,vs,s}printf + */ +#ifndef TINYPRINTF_OVERRIDE_LIBC +#define TINYPRINTF_OVERRIDE_LIBC 0 +#endif + +/* Optional external types dependencies */ + +/* Declarations */ + +#if defined(__GNUC__) +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) \ + __attribute__((format(printf, fmt_idx, arg1_idx))) +#else +#define _TFP_SPECIFY_PRINTF_FMT(fmt_idx, arg1_idx) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*putcf)(void*, char); + +/** + * 'tfp_format' really is the central function for all tinyprintf. For + * each output character after formatting, the 'putf' callback is + * called with 2 args: + * - an arbitrary void* 'putp' param defined by the user and + * passed unmodified from 'tfp_format', + * - the character. + * The 'tfp_printf' and 'tfp_sprintf' functions simply define their own + * callback and pass to it the right 'putp' it is expecting. + */ +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) + _TFP_SPECIFY_PRINTF_FMT(3, 4); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); +#if TINYPRINTF_OVERRIDE_LIBC +#define vsnprintf tfp_vsnprintf +#define snprintf tfp_snprintf +#define vsprintf tfp_vsprintf +#define sprintf tfp_sprintf +#endif +#endif + +#if TINYPRINTF_DEFINE_TFP_PRINTF +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +#if TINYPRINTF_OVERRIDE_LIBC +#define printf tfp_printf + +#ifdef __cplusplus +#include +namespace std +{ + template + auto tfp_printf(Args&&... args) -> decltype(::tfp_printf(std::forward(args)...)) + { + return ::tfp_printf(std::forward(args)...); + } +} +#endif +#endif +#endif + +int printk(const char *format, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_PRINTF_H */ + diff --git a/lib/bsp/include/sleep.h b/lib/bsp/include/sleep.h new file mode 100755 index 0000000..6eb1d24 --- /dev/null +++ b/lib/bsp/include/sleep.h @@ -0,0 +1,36 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_SLEEP_H +#define _BSP_SLEEP_H + +#include "encoding.h" +#include "clint.h" +#include "syscalls.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int usleep(uint64_t usec); +int msleep(uint64_t msec); +unsigned int sleep(unsigned int seconds); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SLEEP_H */ + diff --git a/lib/bsp/include/syscalls.h b/lib/bsp/include/syscalls.h new file mode 100755 index 0000000..12713c3 --- /dev/null +++ b/lib/bsp/include/syscalls.h @@ -0,0 +1,46 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_SYSCALLS_H +#define _BSP_SYSCALLS_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void __attribute__((noreturn)) sys_exit(int code); + +void setStats(int enable); + +#undef putchar +int putchar(int ch); +void printstr(const char *s); + +void printhex(uint64_t x); + +size_t get_free_heap_size(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_SYSCALLS_H */ + diff --git a/lib/bsp/include/util.h b/lib/bsp/include/util.h new file mode 100755 index 0000000..941a37f --- /dev/null +++ b/lib/bsp/include/util.h @@ -0,0 +1,198 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef _BSP_UTIL_H +#define _BSP_UTIL_H + + +#include +#if defined(__riscv) +#include "encoding.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/** + * -------------------------------------------------------------------------- + * Macros + + * Set HOST_DEBUG to 1 if you are going to compile this for a host + * machine (ie Athena/Linux) for debug purposes and set HOST_DEBUG + * to 0 if you are compiling with the smips-gcc toolchain. + */ + +#ifndef HOST_DEBUG +#define HOST_DEBUG 0 +#endif + +/** + * Set PREALLOCATE to 1 if you want to preallocate the benchmark + * function before starting stats. If you have instruction/data + * caches and you don't want to count the overhead of misses, then + * you will need to use preallocation. +*/ + +#ifndef PREALLOCATE +#define PREALLOCATE 0 +#endif + + +#define static_assert(cond) \ + { \ + switch (0) \ + { \ + case 0: \ + case !!(long)(cond):; \ + } \ + } + +#define stringify_1(s) #s +#define stringify(s) stringify_1(s) +#define stats(code, iter) \ + do \ + { \ + unsigned long _c = -read_cycle(), _i = -read_csr(minstret); \ + code; \ + _c += read_cycle(), _i += read_csr(minstret); \ + if (cid == 0) \ + printf("\n%s: %ld cycles, %ld.%ld cycles/iter, %ld.%ld CPI\n", \ + stringify(code), _c, _c / iter, 10 * _c / iter % 10, _c / _i, 10 * _c / _i % 10); \ + } while (0) + + +/** + * Set SET_STATS to 1 if you want to carve out the piece that actually + * does the computation. + */ + +#if HOST_DEBUG +#include +static void setStats(int enable) {} +#else +extern void setStats(int enable); +#endif + + +static void printArray(const char name[], int n, const int arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %3d ", arr[i]); + printf("\n"); +#endif +} + +static void printDoubleArray(const char name[], int n, const double arr[]) +{ +#if HOST_DEBUG + int i; + + printf(" %10s :", name); + for (i = 0; i < n; i++) + printf(" %g ", arr[i]); + printf("\n"); +#endif +} + +static int verify(int n, const volatile int *test, const int *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + int t0 = test[i], t1 = test[i + 1]; + int v0 = verify[i], v1 = verify[i + 1]; + + if (t0 != v0) + return i + 1; + if (t1 != v1) + return i + 2; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static int verifyDouble(int n, const volatile double *test, const double *verify) +{ + int i; + /* Unrolled for faster verification */ + for (i = 0; i < n / 2 * 2; i += 2) + { + double t0 = test[i], t1 = test[i + 1]; + double v0 = verify[i], v1 = verify[i + 1]; + int eq1 = t0 == v0, eq2 = t1 == v1; + + if (!(eq1 & eq2)) + return i + 1 + eq1; + } + if (n % 2 != 0 && test[n - 1] != verify[n - 1]) + return n; + return 0; +} + +static void __attribute__((noinline)) barrier(int ncores) +{ + static volatile int sense = 0; + static volatile int count = 0; + + static __thread int threadsense; + + __sync_synchronize(); + + threadsense = !threadsense; + if (__sync_fetch_and_add(&count, 1) == ncores - 1) + { + count = 0; + sense = threadsense; + } + else + { + while (sense != threadsense) + ; + } + + __sync_synchronize(); +} + +static uint64_t lfsr(uint64_t x) +{ + uint64_t bit = (x ^ (x >> 1)) & 1; + + return (x >> 1) | (bit << 62); +} + + +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Wunused-parameter" +#pragma GCC diagnostic warning "-Wunused-function" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _BSP_UTIL_H */ + diff --git a/lib/bsp/interrupt.c b/lib/bsp/interrupt.c new file mode 100755 index 0000000..4695f99 --- /dev/null +++ b/lib/bsp/interrupt.c @@ -0,0 +1,66 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +/* Enable kernel-mode log API */ + +#include +#include +#include "interrupt.h" +#include "dump.h" +#include "syscalls.h" +#include "syslog.h" + +uintptr_t __attribute__((weak)) +handle_irq_dummy(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("unhandled interrupt", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_irq_dummy"))) +handle_irq_m_ext(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak)) +handle_irq(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Woverride-init" +#endif + /* clang-format off */ + static uintptr_t (* const irq_table[])( + uintptr_t cause, + uintptr_t epc, + uintptr_t regs[32], + uintptr_t fregs[32]) = + { + [0 ... 14] = handle_irq_dummy, + [IRQ_M_SOFT] = handle_irq_m_soft, + [IRQ_M_TIMER] = handle_irq_m_timer, + [IRQ_M_EXT] = handle_irq_m_ext, + }; + /* clang-format on */ +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Woverride-init" +#endif + return irq_table[cause & CAUSE_MACHINE_IRQ_REASON_MASK](cause, epc, regs, fregs); +} + diff --git a/lib/bsp/printf.c b/lib/bsp/printf.c new file mode 100755 index 0000000..5995e93 --- /dev/null +++ b/lib/bsp/printf.c @@ -0,0 +1,668 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +/** + * File: printf.c + * + * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Kustaa Nyholm or SpareTimeLabs 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 COPYRIGHT HOLDER 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 "printf.h" +#include "atomic.h" +#include "uarths.h" + + +/** + * Configuration + */ + +/* Enable long int support */ +#define PRINTF_LONG_SUPPORT + +/* Enable long long int support (implies long int support) */ +#define PRINTF_LONG_LONG_SUPPORT + +/* Enable %z (size_t) support */ +#define PRINTF_SIZE_T_SUPPORT + +/** + * Configuration adjustments + */ +#if defined(PRINTF_LONG_LONG_SUPPORT) +#define PRINTF_LONG_SUPPORT +#endif + +/* __SIZEOF___ defined at least by gcc */ +#if defined(__SIZEOF_POINTER__) +#define SIZEOF_POINTER __SIZEOF_POINTER__ +#endif +#if defined(__SIZEOF_LONG_LONG__) +#define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__ +#endif +#if defined(__SIZEOF_LONG__) +#define SIZEOF_LONG __SIZEOF_LONG__ +#endif +#if defined(__SIZEOF_INT__) +#define SIZEOF_INT __SIZEOF_INT__ +#endif + +#if defined(__GNUC__) +#define _TFP_GCC_NO_INLINE_ __attribute__((noinline)) +#else +#define _TFP_GCC_NO_INLINE_ +#endif + + +#if defined(PRINTF_LONG_SUPPORT) +#define BF_MAX 20 /* long = 64b on some architectures */ +#else +#define BF_MAX 10 /* int = 32b on some architectures */ +#endif + + +#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9') + +/* Clear unused warnings for actually unused variables */ +#define UNUSED(x) (void)(x) + + + +/** + * Implementation + */ +struct param +{ + char lz : 1; /* Leading zeros */ + char alt : 1; /* alternate form */ + char uc : 1; /* Upper case (for base16 only) */ + char align_left : 1; /* 0 == align right (default), 1 == align left */ + int width; /* field width */ + int prec; /* precision */ + char sign; /* The sign to display (if any) */ + unsigned int base; /* number base (e.g.: 8, 10, 16) */ + char *bf; /* Buffer to output */ + size_t bf_len; /* Buffer length */ +}; + +static corelock_t lock = CORELOCK_INIT; + + + +#if defined(PRINTF_LONG_LONG_SUPPORT) +static void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, struct param *p) +{ + unsigned long long int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void lli2a(long long int num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + ulli2a(num, p); +} +#endif + +#if defined(PRINTF_LONG_SUPPORT) +static void uli2a(unsigned long int num, struct param *p) +{ + unsigned long int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void li2a(long num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + uli2a(num, p); +} +#endif + +static void ui2a(unsigned int num, struct param *p) +{ + unsigned int d = 1; + char *bf = p->bf; + if ((p->prec == 0) && (num == 0)) + return; + while (num / d >= p->base) + { + d *= p->base; + } + while (d != 0) + { + int dgt = num / d; + num %= d; + d /= p->base; + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + } + p->bf_len = bf - p->bf; +} + +static void i2a(int num, struct param *p) +{ + if (num < 0) + { + num = -num; + p->sign = '-'; + } + ui2a(num, p); +} + +static int a2d(char ch) +{ + if (IS_DIGIT(ch)) + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static char a2u(char ch, const char **src, int base, unsigned int *nump) +{ + const char *p = *src; + unsigned int num = 0; + int digit; + while ((digit = a2d(ch)) >= 0) + { + if (digit > base) + break; + num = num * base + digit; + ch = *p++; + } + *src = p; + *nump = num; + return ch; +} + +static void putchw(void *putp, putcf putf, struct param *p) +{ + char ch; + int width = p->width; + int prec = p->prec; + char *bf = p->bf; + size_t bf_len = p->bf_len; + + /* Number of filling characters */ + width -= bf_len; + prec -= bf_len; + if (p->sign) + width--; + if (p->alt && p->base == 16) + width -= 2; + else if (p->alt && p->base == 8) + width--; + if (prec > 0) + width -= prec; + + /* Fill with space to align to the right, before alternate or sign */ + if (!p->lz && !p->align_left) + { + while (width-- > 0) + putf(putp, ' '); + } + + /* print sign */ + if (p->sign) + putf(putp, p->sign); + + /* Alternate */ + if (p->alt && p->base == 16) + { + putf(putp, '0'); + putf(putp, (p->uc ? 'X' : 'x')); + } + else if (p->alt && p->base == 8) + { + putf(putp, '0'); + } + + /* Fill with zeros, after alternate or sign */ + while (prec-- > 0) + putf(putp, '0'); + if (p->lz) + { + while (width-- > 0) + putf(putp, '0'); + } + + /* Put actual buffer */ + while ((bf_len-- > 0) && (ch = *bf++)) + putf(putp, ch); + + /* Fill with space to align to the left, after string */ + if (!p->lz && p->align_left) + { + while (width-- > 0) + putf(putp, ' '); + } +} + +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va) +{ + struct param p; + char bf[BF_MAX]; + char ch; + + while ((ch = *(fmt++))) + { + if (ch != '%') + { + putf(putp, ch); + } + else + { +#if defined(PRINTF_LONG_SUPPORT) + char lng = 0; /* 1 for long, 2 for long long */ +#endif + /* Init parameter struct */ + p.lz = 0; + p.alt = 0; + p.uc = 0; + p.align_left = 0; + p.width = 0; + p.prec = -1; + p.sign = 0; + p.bf = bf; + p.bf_len = 0; + + /* Flags */ + while ((ch = *(fmt++))) + { + switch (ch) + { + case '-': + p.align_left = 1; + continue; + case '0': + p.lz = 1; + continue; + case '#': + p.alt = 1; + continue; + default: + break; + } + break; + } + + if (p.align_left) + p.lz = 0; + + /* Width */ + if (ch == '*') + { + ch = *(fmt++); + p.width = va_arg(va, int); + if (p.width < 0) + { + p.align_left = 1; + p.width = -p.width; + } + } + else if (IS_DIGIT(ch)) + { + unsigned int width; + ch = a2u(ch, &fmt, 10, &(width)); + p.width = width; + } + + /* Precision */ + if (ch == '.') + { + ch = *(fmt++); + if (ch == '*') + { + int prec; + ch = *(fmt++); + prec = va_arg(va, int); + if (prec < 0) + /* act as if precision was + * omitted */ + p.prec = -1; + else + p.prec = prec; + } + else if (IS_DIGIT(ch)) + { + unsigned int prec; + ch = a2u(ch, &fmt, 10, &(prec)); + p.prec = prec; + } + else + { + p.prec = 0; + } + } + if (p.prec >= 0) + /* precision causes zero pad to be ignored */ + p.lz = 0; + +#if defined(PRINTF_SIZE_T_SUPPORT) +#if defined(PRINTF_LONG_SUPPORT) + if (ch == 'z') + { + ch = *(fmt++); + if (sizeof(size_t) == sizeof(unsigned long int)) + lng = 1; +#if defined(PRINTF_LONG_LONG_SUPPORT) + else if (sizeof(size_t) == sizeof(unsigned long long int)) + lng = 2; +#endif + } + else +#endif +#endif + +#if defined(PRINTF_LONG_SUPPORT) + if (ch == 'l') + { + ch = *(fmt++); + lng = 1; +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (ch == 'l') + { + ch = *(fmt++); + lng = 2; + } +#endif + } +#endif + switch (ch) + { + case 0: + goto abort; + case 'u': + p.base = 10; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'd': /* No break */ + case 'i': + p.base = 10; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + lli2a(va_arg(va, long long int), &p); + else +#endif + if (1 == lng) + li2a(va_arg(va, long int), &p); + else +#endif + i2a(va_arg(va, int), &p); + putchw(putp, putf, &p); + break; +#if defined(SIZEOF_POINTER) + case 'p': + p.alt = 1; +#if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT + lng = 0; +#elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG + lng = 1; +#elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG + lng = 2; +#endif +#endif + /* No break */ + case 'x': /* No break */ + case 'X': + p.base = 16; + p.uc = (ch == 'X') ? 1 : 0; + if (p.prec < 0) + p.prec = 1; +#if defined(PRINTF_LONG_SUPPORT) +#if defined(PRINTF_LONG_LONG_SUPPORT) + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'o': + p.base = 8; + if (p.prec < 0) + p.prec = 1; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'c': + putf(putp, (char)(va_arg(va, int))); + break; + case 's': + { + unsigned int prec = p.prec; + char *b; + p.bf = va_arg(va, char*); + b = p.bf; + while ((prec-- != 0) && *b++) + { + p.bf_len++; + } + p.prec = -1; + putchw(putp, putf, &p); + } + break; + case '%': + putf(putp, ch); + break; + default: + break; + } + } + } +abort:; +} + +#if defined(TINYPRINTF_DEFINE_TFP_PRINTF) +static putcf stdout_putf; +static void *stdout_putp; + +void init_printf(void *putp, putcf putf) +{ + stdout_putf = putf; + stdout_putp = putp; +} + +void tfp_printf(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + tfp_format(stdout_putp, stdout_putf, fmt, va); + va_end(va); +} +#endif + +#if defined(TINYPRINTF_DEFINE_TFP_SPRINTF) +struct _vsnprintf_putcf_data +{ + size_t dest_capacity; + char *dest; + size_t num_chars; +}; + +static void _vsnprintf_putcf(void *p, char c) +{ + struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p; + if (data->num_chars < data->dest_capacity) + data->dest[data->num_chars] = c; + data->num_chars++; +} + +int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + struct _vsnprintf_putcf_data data; + + if (size < 1) + return 0; + + data.dest = str; + data.dest_capacity = size - 1; + data.num_chars = 0; + tfp_format(&data, _vsnprintf_putcf, format, ap); + + if (data.num_chars < data.dest_capacity) + data.dest[data.num_chars] = '\0'; + else + data.dest[data.dest_capacity] = '\0'; + + return data.num_chars; +} + +int tfp_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsnprintf(str, size, format, ap); + va_end(ap); + return retval; +} + +struct _vsprintf_putcf_data +{ + char *dest; + size_t num_chars; +}; + +static void _vsprintf_putcf(void *p, char c) +{ + struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p; + data->dest[data->num_chars++] = c; +} + +int tfp_vsprintf(char *str, const char *format, va_list ap) +{ + struct _vsprintf_putcf_data data; + data.dest = str; + data.num_chars = 0; + tfp_format(&data, _vsprintf_putcf, format, ap); + data.dest[data.num_chars] = '\0'; + return data.num_chars; +} + +int tfp_sprintf(char *str, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsprintf(str, format, ap); + va_end(ap); + return retval; +} +#endif + +static void uart_putf(void *unused, char c) +{ + UNUSED(unused); + uarths_putchar(c); +} + +int printk(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + /* Begin protected code */ + corelock_lock(&lock); + tfp_format(stdout_putp, uart_putf, format, ap); + /* End protected code */ + corelock_unlock(&lock); + va_end(ap); + + return 0; +} + diff --git a/lib/bsp/sleep.c b/lib/bsp/sleep.c new file mode 100755 index 0000000..ef4c76c --- /dev/null +++ b/lib/bsp/sleep.c @@ -0,0 +1,39 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "sleep.h" +#include "sysctl.h" + +int usleep(uint64_t usec) +{ + uint64_t cycle = read_cycle(); + uint64_t nop_all = usec * sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / 1000000UL; + while (1) + { + if(read_cycle() - cycle >= nop_all) + break; + } + return 0; +} + +int msleep(uint64_t msec) +{ + return (unsigned int)usleep(msec * 1000); +} + +unsigned int sleep(unsigned int seconds) +{ + return (unsigned int)msleep(seconds * 1000); +} + diff --git a/lib/bsp/syscalls.c b/lib/bsp/syscalls.c new file mode 100755 index 0000000..ccd05f2 --- /dev/null +++ b/lib/bsp/syscalls.c @@ -0,0 +1,631 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +/* Enable kernel-mode log API */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syscalls.h" +#include "atomic.h" +#include "clint.h" +#include "fpioa.h" +#include "interrupt.h" +#include "sysctl.h" +#include "uarths.h" +#include "util.h" +#include "syslog.h" +#include "dump.h" + +/** + * @note System call list + * + * See also riscv-newlib/libgloss/riscv/syscalls.c + * + * | System call | Number | + * |------------------|--------| + * | SYS_exit | 93 | + * | SYS_exit_group | 94 | + * | SYS_getpid | 172 | + * | SYS_kill | 129 | + * | SYS_read | 63 | + * | SYS_write | 64 | + * | SYS_open | 1024 | + * | SYS_openat | 56 | + * | SYS_close | 57 | + * | SYS_lseek | 62 | + * | SYS_brk | 214 | + * | SYS_link | 1025 | + * | SYS_unlink | 1026 | + * | SYS_mkdir | 1030 | + * | SYS_chdir | 49 | + * | SYS_getcwd | 17 | + * | SYS_stat | 1038 | + * | SYS_fstat | 80 | + * | SYS_lstat | 1039 | + * | SYS_fstatat | 79 | + * | SYS_access | 1033 | + * | SYS_faccessat | 48 | + * | SYS_pread | 67 | + * | SYS_pwrite | 68 | + * | SYS_uname | 160 | + * | SYS_getuid | 174 | + * | SYS_geteuid | 175 | + * | SYS_getgid | 176 | + * | SYS_getegid | 177 | + * | SYS_mmap | 222 | + * | SYS_munmap | 215 | + * | SYS_mremap | 216 | + * | SYS_time | 1062 | + * | SYS_getmainvars | 2011 | + * | SYS_rt_sigaction | 134 | + * | SYS_writev | 66 | + * | SYS_gettimeofday | 169 | + * | SYS_times | 153 | + * | SYS_fcntl | 25 | + * | SYS_getdents | 61 | + * | SYS_dup | 23 | + * + */ + +#ifndef UNUSED +#define UNUSED(x) (void)(x) +#endif + +static const char *TAG = "SYSCALL"; + +extern char _heap_start[]; +extern char _heap_end[]; +char *_heap_cur = &_heap_start[0]; + + +void __attribute__((noreturn)) sys_exit(int code) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* First print some diagnostic information. */ + LOGW(TAG, "sys_exit called by core %ld with 0x%lx\n", core_id, (uint64_t)code); + while (1) + continue; +} + +static int sys_nosys(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) +{ + UNUSED(a3); + UNUSED(a4); + UNUSED(a5); + + LOGE(TAG, "Unsupported syscall %ld: a0=%lx, a1=%lx, a2=%lx!\n", n, a0, a1, a2); + while (1) + continue; + return -ENOSYS; +} + +static int sys_success(void) +{ + return 0; +} + +static size_t sys_brk(size_t pos) +{ + uintptr_t res = 0; + /** + * brk() sets the end of the data segment to the value + * specified by addr, when that value is reasonable, the system + * has enough memory, and the process does not exceed its + * maximum data size. + * + * sbrk() increments the program's data space by increment + * bytes. Calling sbrk() with an increment of 0 can be used to + * find the current location of the program break. + * + * uintptr_t brk(uintptr_t ptr); + * + * IN : regs[10] = ptr + * OUT: regs[10] = ptr + */ + + /** + * First call: Initialization brk pointer. newlib will pass + * ptr = 0 when it is first called. In this case the address + * _heap_start will be return. + * + * Call again: Adjust brk pointer. The ptr never equal with + * 0. If ptr is below _heap_end, then allocate memory. + * Otherwise throw out of memory error, return -1. + */ + + if (pos) + { + /* Call again */ + if ((uintptr_t)pos > (uintptr_t)&_heap_end[0]) + { + /* Memory out, return -ENOMEM */ + LOGE(TAG, "Out of memory\n"); + res = -ENOMEM; + } + else + { + /* Adjust brk pointer. */ + _heap_cur = (char *)(uintptr_t)pos; + /* Return current address. */ + res = (uintptr_t)_heap_cur; + } + } + else + { + /* First call, return initial address */ + res = (uintptr_t)&_heap_start[0]; + } + return (size_t)res; +} + +static ssize_t sys_write(int file, const void *ptr, size_t len) +{ + ssize_t res = -EBADF; + + /** + * Write to a file. + * + * ssize_t write(int file, const void *ptr, size_t len) + * + * IN : regs[10] = file, regs[11] = ptr, regs[12] = len + * OUT: regs[10] = len + */ + + /* Get size to write */ + register size_t length = len; + /* Get data pointer */ + register char *data = (char *)ptr; + + if (STDOUT_FILENO == file || STDERR_FILENO == file) + { + /* Write data */ + while (length-- > 0 && *data != 0) + uarths_putchar(*(data++)); + + /* Return the actual size written */ + res = len; + } + else + { + /* Not support yet */ + res = -ENOSYS; + } + + return res; +} + +static int sys_fstat(int file, struct stat *st) +{ + int res = -EBADF; + + /** + * Status of an open file. The sys/stat.h header file required + * is + * distributed in the include subdirectory for this C library. + * + * int fstat(int file, struct stat* st) + * + * IN : regs[10] = file, regs[11] = st + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + + UNUSED(file); + + if (st != NULL) + memset(st, 0, sizeof(struct stat)); + /* Return the result */ + res = -ENOSYS; + /** + * Note: This value will return to syscall wrapper, syscall + * wrapper will set errno to ENOSYS and return -1 + */ + + return res; +} + +static int sys_close(int file) +{ + int res = -EBADF; + + /** + * Close a file. + * + * int close(int file) + * + * IN : regs[10] = file + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + + UNUSED(file); + /* Return the result */ + res = 0; + return res; +} + +static int sys_gettimeofday(struct timeval *tp, void *tzp) +{ + /** + * Get the current time. Only relatively correct. + * + * int gettimeofday(struct timeval *tp, void *tzp) + * + * IN : regs[10] = tp + * OUT: regs[10] = Upon successful completion, 0 shall be + * returned. + * Otherwise, -1 shall be returned and errno set to indicate + * the error. + */ + UNUSED(tzp); + + if (tp != NULL) + { + uint64_t clint_usec = clint->mtime / (sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV / 1000000UL); + + tp->tv_sec = clint_usec / 1000000UL; + tp->tv_usec = clint_usec % 1000000UL; + } + /* Return the result */ + return 0; +} + +uintptr_t __attribute__((weak)) +handle_ecall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + UNUSED(cause); + UNUSED(fregs); + enum syscall_id_e + { + SYS_ID_NOSYS, + SYS_ID_SUCCESS, + SYS_ID_EXIT, + SYS_ID_BRK, + SYS_ID_WRITE, + SYS_ID_FSTAT, + SYS_ID_CLOSE, + SYS_ID_GETTIMEOFDAY, + SYS_ID_MAX + }; + + static uintptr_t (* const syscall_table[])(long a0, long a1, long a2, long a3, long a4, long a5, unsigned long n) = + { + [SYS_ID_NOSYS] = (void *)sys_nosys, + [SYS_ID_SUCCESS] = (void *)sys_success, + [SYS_ID_EXIT] = (void *)sys_exit, + [SYS_ID_BRK] = (void *)sys_brk, + [SYS_ID_WRITE] = (void *)sys_write, + [SYS_ID_FSTAT] = (void *)sys_fstat, + [SYS_ID_CLOSE] = (void *)sys_close, + [SYS_ID_GETTIMEOFDAY] = (void *)sys_gettimeofday, + }; + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Woverride-init" +#endif + static const uint8_t syscall_id_table[0x100] = + { + [0x00 ... 0xFF] = SYS_ID_NOSYS, + [0xFF & SYS_exit] = SYS_ID_EXIT, + [0xFF & SYS_exit_group] = SYS_ID_EXIT, + [0xFF & SYS_getpid] = SYS_ID_NOSYS, + [0xFF & SYS_kill] = SYS_ID_NOSYS, + [0xFF & SYS_read] = SYS_ID_NOSYS, + [0xFF & SYS_write] = SYS_ID_WRITE, + [0xFF & SYS_open] = SYS_ID_NOSYS, + [0xFF & SYS_openat] = SYS_ID_NOSYS, + [0xFF & SYS_close] = SYS_ID_CLOSE, + [0xFF & SYS_lseek] = SYS_ID_NOSYS, + [0xFF & SYS_brk] = SYS_ID_BRK, + [0xFF & SYS_link] = SYS_ID_NOSYS, + [0xFF & SYS_unlink] = SYS_ID_NOSYS, + [0xFF & SYS_mkdir] = SYS_ID_NOSYS, + [0xFF & SYS_chdir] = SYS_ID_NOSYS, + [0xFF & SYS_getcwd] = SYS_ID_NOSYS, + [0xFF & SYS_stat] = SYS_ID_NOSYS, + [0xFF & SYS_fstat] = SYS_ID_FSTAT, + [0xFF & SYS_lstat] = SYS_ID_NOSYS, + [0xFF & SYS_fstatat] = SYS_ID_NOSYS, + [0xFF & SYS_access] = SYS_ID_NOSYS, + [0xFF & SYS_faccessat] = SYS_ID_NOSYS, + [0xFF & SYS_pread] = SYS_ID_NOSYS, + [0xFF & SYS_pwrite] = SYS_ID_NOSYS, + [0xFF & SYS_uname] = SYS_ID_NOSYS, + [0xFF & SYS_getuid] = SYS_ID_NOSYS, + [0xFF & SYS_geteuid] = SYS_ID_NOSYS, + [0xFF & SYS_getgid] = SYS_ID_NOSYS, + [0xFF & SYS_getegid] = SYS_ID_NOSYS, + [0xFF & SYS_mmap] = SYS_ID_NOSYS, + [0xFF & SYS_munmap] = SYS_ID_NOSYS, + [0xFF & SYS_mremap] = SYS_ID_NOSYS, + [0xFF & SYS_time] = SYS_ID_NOSYS, + [0xFF & SYS_getmainvars] = SYS_ID_NOSYS, + [0xFF & SYS_rt_sigaction] = SYS_ID_NOSYS, + [0xFF & SYS_writev] = SYS_ID_NOSYS, + [0xFF & SYS_gettimeofday] = SYS_ID_GETTIMEOFDAY, + [0xFF & SYS_times] = SYS_ID_NOSYS, + [0xFF & SYS_fcntl] = SYS_ID_NOSYS, + [0xFF & SYS_getdents] = SYS_ID_NOSYS, + [0xFF & SYS_dup] = SYS_ID_NOSYS, + }; +#if defined(__GNUC__) +#pragma GCC diagnostic warning "-Woverride-init" +#endif + + regs[10] = syscall_table[syscall_id_table[0xFF & regs[17]]] + ( + regs[10], /* a0 */ + regs[11], /* a1 */ + regs[12], /* a2 */ + regs[13], /* a3 */ + regs[14], /* a4 */ + regs[15], /* a5 */ + regs[17] /* n */ + ); + + return epc + ((*(unsigned short *)epc & 3) == 3 ? 4 : 2); +} + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_u(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_h(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_s(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak, alias("handle_ecall"))) +handle_ecall_m(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]); + +uintptr_t __attribute__((weak)) +handle_misaligned_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("misaligned fetch", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_fetch(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault fetch", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_illegal_instruction(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("illegal instruction", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_breakpoint(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("breakpoint", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_misaligned_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + /* notice this function only support 16bit or 32bit instruction */ + + bool compressed = (*(unsigned short *)epc & 3) != 3; + bool fpu = 0; /* load to fpu ? */ + uintptr_t addr = 0; /* src addr */ + uint8_t src = 0; /* src register */ + uint8_t dst = 0; /* dst register */ + uint8_t len = 0; /* data length */ + int offset = 0; /* addr offset to addr in reg */ + bool unsigned_ = 0; /* unsigned */ + uint64_t data_load = 0;/* real data load */ + + if (compressed) + { + /* compressed instruction should not get this fault. */ + goto on_error; + } + else + { + uint32_t instruct = *(uint32_t *)epc; + uint8_t opcode = instruct&0x7F; + + dst = (instruct >> 7)&0x1F; + len = (instruct >> 12)&3; + unsigned_ = (instruct >> 14)&1; + src = (instruct >> 15)&0x1F; + offset = (instruct >> 20); + len = 1 << len; + switch (opcode) + { + case 3:/* load */ + break; + case 7:/* fpu load */ + fpu = 1; + break; + default: + goto on_error; + } + } + + if (offset >> 11) + offset = -((offset & 0x3FF) + 1); + + addr = (uint64_t)((uint64_t)regs[src] + offset); + + for (int i = 0; i < len; ++i) + data_load |= ((uint64_t)*((uint8_t *)addr + i)) << (8 * i); + + + if (!unsigned_ & !fpu) + { + /* adjust sign */ + switch (len) + { + case 1: + data_load = (uint64_t)(int64_t)((int8_t)data_load); + break; + case 2: + data_load = (uint64_t)(int64_t)((int16_t)data_load); + break; + case 4: + data_load = (uint64_t)(int64_t)((int32_t)data_load); + break; + default: + break; + } + } + + if (fpu) + fregs[dst] = data_load; + else + regs[dst] = data_load; + + LOGV(TAG, "misaligned load recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,signed:%1d,float:%1d", (uint64_t)epc, len, (uint64_t)addr, dst, data_load, !unsigned_, fpu); + + return epc + (compressed ? 2 : 4); +on_error: + dump_core("misaligned load", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_load(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault load", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_misaligned_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + /* notice this function only support 16bit or 32bit instruction */ + + bool compressed = (*(unsigned short *)epc & 3) != 3; + bool fpu = 0; /* store to fpu*/ + uintptr_t addr = 0; /* src addr*/ + uint8_t src = 0; /* src register*/ + uint8_t dst = 0; /* dst register*/ + uint8_t len = 0; /* data length*/ + int offset = 0; /* addr offset to addr in reg*/ + uint64_t data_store = 0;/* real data store*/ + + if (compressed) + { + /* compressed instruction should not get this fault. */ + goto on_error; + } + else + { + uint32_t instruct = *(uint32_t *)epc; + uint8_t opcode = instruct&0x7F; + + len = (instruct >> 12)&7; + dst = (instruct >> 15)&0x1F; + src = (instruct >> 20)&0x1F; + offset = ((instruct >> 7)&0x1F) | ((instruct >> 20)&0xFE0); + len = 1 << len; + switch (opcode) + { + case 0x23:/* store */ + break; + case 0x27:/* fpu store */ + fpu = 1; + break; + default: + goto on_error; + } + } + + if (offset >> 11) + offset = -((offset & 0x3FF) + 1); + + addr = (uint64_t)((uint64_t)regs[dst] + offset); + + + if (fpu) + data_store = fregs[src]; + else + data_store = regs[src]; + + for (int i = 0; i < len; ++i) + *((uint8_t *)addr + i) = (data_store >> (i*8)) & 0xFF; + + LOGV(TAG, "misaligned store recovered at %08lx. len:%02d,addr:%08lx,reg:%02d,data:%016lx,float:%1d", (uint64_t)epc, len, (uint64_t)addr, src, data_store, fpu); + + return epc + (compressed ? 2 : 4); +on_error: + dump_core("misaligned store", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t __attribute__((weak)) +handle_fault_store(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + dump_core("fault store", cause, epc, regs, fregs); + sys_exit(1337); + return epc; +} + +uintptr_t handle_syscall(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) +{ + + static uintptr_t (* const cause_table[])(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32]) = + { + [CAUSE_MISALIGNED_FETCH] = handle_misaligned_fetch, + [CAUSE_FAULT_FETCH] = handle_fault_fetch, + [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction, + [CAUSE_BREAKPOINT] = handle_breakpoint, + [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load, + [CAUSE_FAULT_LOAD] = handle_fault_load, + [CAUSE_MISALIGNED_STORE] = handle_misaligned_store, + [CAUSE_FAULT_STORE] = handle_fault_store, + [CAUSE_USER_ECALL] = handle_ecall_u, + [CAUSE_SUPERVISOR_ECALL] = handle_ecall_h, + [CAUSE_HYPERVISOR_ECALL] = handle_ecall_s, + [CAUSE_MACHINE_ECALL] = handle_ecall_m, + }; + + return cause_table[cause](cause, epc, regs, fregs); +} + +size_t get_free_heap_size(void) +{ + return (size_t)(&_heap_end[0] - _heap_cur); +} + diff --git a/lib/drivers/aes.c b/lib/drivers/aes.c new file mode 100755 index 0000000..5fc3696 --- /dev/null +++ b/lib/drivers/aes.c @@ -0,0 +1,421 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "sysctl.h" +#include "aes.h" +#include "utils.h" + +volatile aes_t *const aes = (volatile aes_t *)AES_BASE_ADDR; + +static void aes_clk_init() +{ + sysctl_clock_enable(SYSCTL_CLOCK_AES); + sysctl_reset(SYSCTL_RESET_AES); +} + +static void aes_write_aad(uint32_t aad_data) +{ + aes->aes_aad_data = aad_data; +} + +static void aes_write_text(uint32_t text_data) +{ + aes->aes_text_data = text_data; +} + +static void gcm_write_tag(uint32_t *tag) +{ + aes->gcm_in_tag[0] = tag[3]; + aes->gcm_in_tag[1] = tag[2]; + aes->gcm_in_tag[2] = tag[1]; + aes->gcm_in_tag[3] = tag[0]; +} + +static uint32_t aes_get_data_in_flag(void) +{ + return aes->data_in_flag; +} + +static uint32_t aes_get_data_out_flag(void) +{ + return aes->data_out_flag; +} + +static uint32_t gcm_get_tag_in_flag(void) +{ + return aes->tag_in_flag; +} + +static uint32_t aes_read_out_data(void) +{ + return aes->aes_out_data; +} + +static uint32_t gcm_get_tag_chk(void) +{ + return aes->tag_chk; +} + +static void gcm_clear_chk_tag(void) +{ + aes->tag_clear = 0; +} + +static uint32_t gcm_check_tag(uint32_t *gcm_tag) +{ + while (!gcm_get_tag_in_flag()) + ; + gcm_write_tag(gcm_tag); + while (!gcm_get_tag_chk()) + ; + if (gcm_get_tag_chk() == 0x2) + { + gcm_clear_chk_tag(); + return 1; + } + else + { + gcm_clear_chk_tag(); + return 0; + } +} + +void gcm_get_tag(uint8_t *gcm_tag) +{ + uint32_t uint32_tag; + uint8_t i = 0; + + uint32_tag = aes->gcm_out_tag[3]; + gcm_tag[i++] = (uint8_t)((uint32_tag >> 24) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 16) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 8) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag)&0xff); + + uint32_tag = aes->gcm_out_tag[2]; + gcm_tag[i++] = (uint8_t)((uint32_tag >> 24) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 16) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 8) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag)&0xff); + + uint32_tag = aes->gcm_out_tag[1]; + gcm_tag[i++] = (uint8_t)((uint32_tag >> 24) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 16) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 8) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag)&0xff); + + uint32_tag = aes->gcm_out_tag[0]; + gcm_tag[i++] = (uint8_t)((uint32_tag >> 24) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 16) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag >> 8) & 0xff); + gcm_tag[i++] = (uint8_t)((uint32_tag)&0xff); + + gcm_check_tag((uint32_t *)gcm_tag); +} + + +void aes_init(uint8_t *input_key, size_t input_key_len, uint8_t *iv,size_t iv_len, uint8_t *gcm_aad, + aes_cipher_mode_t cipher_mode, aes_encrypt_sel_t encrypt_sel, size_t gcm_aad_len, size_t input_data_len) +{ + size_t remainder, uint32_num, uint8_num, i; + uint32_t uint32_data; + uint8_t uint8_data[4] = {0}; + size_t padding_len = input_data_len; + aes_clk_init(); + if ((cipher_mode == AES_ECB) || (cipher_mode == AES_CBC)) + padding_len = ((input_data_len + 15) / 16) * 16; + aes->aes_endian |= 1; + uint32_num = input_key_len / 4; + for (i = 0; i < uint32_num; i++) + { + if (i < 4) + aes->aes_key[i] = *((uint32_t *)(&input_key[input_key_len - (4 * i) - 4])); + else + aes->aes_key_ext[i - 4] = *((uint32_t *)(&input_key[input_key_len - (4 * i) - 4])); + } + + uint32_num = iv_len / 4; + for (i = 0; i < uint32_num; i++) + aes->aes_iv[i] = *((uint32_t *)(&iv[iv_len - (4 * i) - 4])); + + aes->mode_ctl.kmode = input_key_len / 8 - 2; /* b'00:AES_128 b'01:AES_192 b'10:AES_256 b'11:RESERVED */ + aes->mode_ctl.cipher_mode = cipher_mode; + aes->encrypt_sel = encrypt_sel; + aes->gb_aad_num = gcm_aad_len - 1; + aes->gb_pc_num = padding_len - 1; + aes->gb_aes_en |= 1; + + if (cipher_mode == AES_GCM) + { + uint32_num = gcm_aad_len / 4; + for (i = 0; i < uint32_num; i++) + { + uint32_data = *((uint32_t *)(&gcm_aad[i * 4])); + while (!aes_get_data_in_flag()) + ; + aes_write_aad(uint32_data); + } + uint8_num = 4 * uint32_num; + remainder = gcm_aad_len % 4; + if (remainder) + { + switch (remainder) + { + case 1: + uint8_data[0] = gcm_aad[uint8_num]; + break; + case 2: + uint8_data[0] = gcm_aad[uint8_num]; + uint8_data[1] = gcm_aad[uint8_num + 1]; + break; + case 3: + uint8_data[0] = gcm_aad[uint8_num]; + uint8_data[1] = gcm_aad[uint8_num + 1]; + uint8_data[2] = gcm_aad[uint8_num + 2]; + break; + default: + break; + } + uint32_data = *((uint32_t *)(&uint8_data[0])); + while (!aes_get_data_in_flag()) + ; + aes_write_aad(uint32_data); + } + } +} + +static void process_less_80_bytes(uint8_t *input_data, uint8_t *output_data, size_t input_data_len, aes_cipher_mode_t cipher_mode) +{ + size_t padding_len, uint32_num, uint8_num, remainder, i; + uint32_t uint32_data; + uint8_t uint8_data[4] = {0}; + + padding_len = ((input_data_len + 15) / 16) * 16; + uint32_num = input_data_len / 4; + for (i = 0; i < uint32_num; i++) + { + uint32_data = *((uint32_t *)(&input_data[i * 4])); + while (!aes_get_data_in_flag()) + ; + aes_write_text(uint32_data); + } + uint8_num = 4 * uint32_num; + remainder = input_data_len % 4; + if (remainder) + { + switch (remainder) + { + case 1: + uint8_data[0] = input_data[uint8_num]; + break; + case 2: + uint8_data[0] = input_data[uint8_num]; + uint8_data[1] = input_data[uint8_num + 1]; + break; + case 3: + uint8_data[0] = input_data[uint8_num]; + uint8_data[1] = input_data[uint8_num + 1]; + uint8_data[2] = input_data[uint8_num + 2]; + break; + default: + break; + } + uint32_data = *((uint32_t *)(&uint8_data[0])); + while (!aes_get_data_in_flag()) + ; + aes_write_text(uint32_data); + } + if ((cipher_mode == AES_ECB) || (cipher_mode == AES_CBC)) + { + uint32_num = (padding_len - input_data_len) / 4; + for (i = 0; i < uint32_num; i++) + { + while (!aes_get_data_in_flag()) + ; + aes_write_text(0); + } + uint32_num = padding_len / 4; + } + for (i = 0; i < uint32_num; i++) + { + while (!aes_get_data_out_flag()) + ; + *((uint32_t *)(&output_data[i * 4])) = aes_read_out_data(); + } + if ((cipher_mode == AES_GCM) && (remainder)) + { + while (!aes_get_data_out_flag()) + ; + *((uint32_t *)(&uint8_data[0])) = aes_read_out_data(); + switch (remainder) + { + case 1: + output_data[uint32_num * 4] = uint8_data[0]; + break; + case 2: + output_data[uint32_num * 4] = uint8_data[0]; + output_data[(i * 4) + 1] = uint8_data[1]; + break; + case 3: + output_data[uint32_num * 4] = uint8_data[0]; + output_data[(i * 4) + 1] = uint8_data[1]; + output_data[(i * 4) + 2] = uint8_data[2]; + break; + default: + break; + } + } +} + +void aes_process(uint8_t *input_data, uint8_t *output_data, size_t input_data_len, aes_cipher_mode_t cipher_mode) +{ + size_t temp_len = 0; + uint32_t i = 0; + + if (input_data_len >= 80) + { + for (i = 0; i < (input_data_len / 80); i++) + process_less_80_bytes(&input_data[i * 80], &output_data[i * 80], 80, cipher_mode); + } + temp_len = input_data_len % 80; + if (temp_len) + process_less_80_bytes(&input_data[i * 80], &output_data[i * 80], temp_len, cipher_mode); +} + +void aes_ecb128_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(input_key, AES_128, NULL, 0L, NULL, AES_ECB, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_ECB); +} + +void aes_ecb128_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(input_key, AES_128, NULL, 0L, NULL, AES_ECB, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_ECB); +} + +void aes_ecb192_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(input_key, AES_192, NULL, 0L, NULL, AES_ECB, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_ECB); +} + +void aes_ecb192_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(input_key, AES_192, NULL, 0L, NULL, AES_ECB, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_ECB); +} + +void aes_ecb256_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(input_key, AES_256, NULL, 0L, NULL, AES_ECB, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_ECB); +} + +void aes_ecb256_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(input_key, AES_256, NULL, 0L, NULL, AES_ECB, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_ECB); +} + +void aes_cbc128_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(context->input_key, AES_128, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_CBC); +} + +void aes_cbc128_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(context->input_key, AES_128, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_CBC); +} + +void aes_cbc192_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(context->input_key, AES_192, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_CBC); +} + +void aes_cbc192_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(context->input_key, AES_192, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_CBC); +} + +void aes_cbc256_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + size_t padding_len = ((input_len + 15) / 16) * 16; + aes_init(context->input_key, AES_256, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_DECRYPTION, 0L, input_len); + aes_process(input_data, output_data, padding_len, AES_CBC); +} + +void aes_cbc256_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data) +{ + aes_init(context->input_key, AES_256, context->iv, IV_LEN_128, NULL, AES_CBC, AES_HARD_ENCRYPTION, 0L, input_len); + aes_process(input_data, output_data, input_len, AES_CBC); +} + +void aes_gcm128_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_128, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_DECRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + +void aes_gcm128_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_128, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_ENCRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + +void aes_gcm192_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_192, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_DECRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + +void aes_gcm192_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_192, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_ENCRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + +void aes_gcm256_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_256, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_DECRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + +void aes_gcm256_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag) +{ + aes_init(context->input_key, AES_256, context->iv, IV_LEN_96, context->gcm_aad, + AES_GCM, AES_HARD_ENCRYPTION, context->gcm_aad_len, input_len); + aes_process(input_data, output_data, input_len, AES_GCM); + gcm_get_tag(gcm_tag); +} + diff --git a/lib/drivers/clint.c b/lib/drivers/clint.c new file mode 100755 index 0000000..4b59a42 --- /dev/null +++ b/lib/drivers/clint.c @@ -0,0 +1,261 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "encoding.h" +#include "clint.h" +#include "sysctl.h" + +volatile clint_t* const clint = (volatile clint_t*)CLINT_BASE_ADDR; +static clint_timer_instance_t clint_timer_instance[CLINT_NUM_CORES]; +static clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_CORES]; + +uint64_t clint_get_time(void) +{ + /* No difference on cores */ + return clint->mtime; +} + +int clint_timer_init(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Clear the Machine-Timer bit in MIE */ + clear_csr(mie, MIP_MTIP); + /* Fill core's instance with original data */ + + /* clang-format off */ + clint_timer_instance[core_id] = (const clint_timer_instance_t) + { + .interval = 0, + .cycles = 0, + .single_shot = 0, + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_timer_stop(void) +{ + /* Clear the Machine-Timer bit in MIE */ + clear_csr(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_freq(void) +{ + /* The clock is divided by CLINT_CLOCK_DIV */ + return sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV; +} + +int clint_timer_start(uint64_t interval, int single_shot) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set timer interval */ + if (clint_timer_set_interval(interval) != 0) + return -1; + /* Set timer single shot */ + if (clint_timer_set_single_shot(single_shot) != 0) + return -1; + /* Check settings to prevent interval is 0 */ + if (clint_timer_instance[core_id].interval == 0) + return -1; + /* Check settings to prevent cycles is 0 */ + if (clint_timer_instance[core_id].cycles == 0) + return -1; + /* Add cycle interval to mtimecmp */ + uint64_t now = clint->mtime; + uint64_t then = now + clint_timer_instance[core_id].cycles; + /* Set mtimecmp by core id */ + clint->mtimecmp[core_id] = then; + /* Enable interrupts in general */ + set_csr(mstatus, MSTATUS_MIE); + /* Enable the Machine-Timer bit in MIE */ + set_csr(mie, MIP_MTIP); + return 0; +} + +uint64_t clint_timer_get_interval(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + return clint_timer_instance[core_id].interval; +} + +int clint_timer_set_interval(uint64_t interval) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Check parameter */ + if (interval == 0) + return -1; + + /* Assign user interval with Millisecond(ms) */ + clint_timer_instance[core_id].interval = interval; + /* Convert interval to cycles */ + clint_timer_instance[core_id].cycles = interval * clint_timer_get_freq() / 1000ULL; + return 0; +} + +int clint_timer_get_single_shot(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Get single shot mode by core id */ + return clint_timer_instance[core_id].single_shot; +} + +int clint_timer_set_single_shot(int single_shot) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set single shot mode by core id */ + clint_timer_instance[core_id].single_shot = single_shot; + return 0; +} + +int clint_timer_register(clint_timer_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + clint_timer_instance[core_id].callback = callback; + /* Assign user context */ + clint_timer_instance[core_id].ctx = ctx; + return 0; +} + +int clint_timer_deregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_timer_register(NULL, NULL); +} + +int clint_ipi_init(void) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Clear the Machine-Software bit in MIE */ + clear_csr(mie, MIP_MSIP); + /* Fill core's instance with original data */ + /* clang-format off */ + clint_ipi_instance[core_id] = (const clint_ipi_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + + return 0; +} + +int clint_ipi_enable(void) +{ + /* Enable interrupts in general */ + set_csr(mstatus, MSTATUS_MIE); + /* Set the Machine-Software bit in MIE */ + set_csr(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_disable(void) +{ + /* Clear the Machine-Software bit in MIE */ + clear_csr(mie, MIP_MSIP); + return 0; +} + +int clint_ipi_send(size_t core_id) +{ + if (core_id >= CLINT_NUM_CORES) + return -1; + clint->msip[core_id].msip = 1; + return 0; +} + +int clint_ipi_clear(size_t core_id) +{ + if (core_id >= CLINT_NUM_CORES) + return -1; + if (clint->msip[core_id].msip) + { + clint->msip[core_id].msip = 0; + return 1; + } + return 0; +} + +int clint_ipi_register(clint_ipi_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + clint_ipi_instance[core_id].callback = callback; + /* Assign user context */ + clint_ipi_instance[core_id].ctx = ctx; + return 0; +} + +int clint_ipi_deregister(void) +{ + /* Just assign NULL to user callback function and context */ + return clint_ipi_register(NULL, NULL); +} + +uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc) +{ + /* Read core id */ + uint64_t core_id = current_coreid(); + uint64_t ie_flag = read_csr(mie); + + clear_csr(mie, MIP_MTIP | MIP_MSIP); + set_csr(mstatus, MSTATUS_MIE); + if (clint_timer_instance[core_id].callback != NULL) + clint_timer_instance[core_id].callback( + clint_timer_instance[core_id].ctx); + clear_csr(mstatus, MSTATUS_MIE); + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + write_csr(mie, ie_flag); + /* If not single shot and cycle interval is not 0, repeat this timer */ + if (!clint_timer_instance[core_id].single_shot && clint_timer_instance[core_id].cycles != 0) + { + /* Set mtimecmp by core id */ + clint->mtimecmp[core_id] += clint_timer_instance[core_id].cycles; + } + else + clear_csr(mie, MIP_MTIP); + return epc; +} + +uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc) +{ + /* Read core id */ + uint64_t core_id = current_coreid(); + /* Clear the Machine-Software bit in MIE to prevent call again */ + clear_csr(mie, MIP_MSIP); + set_csr(mstatus, MSTATUS_MIE); + /* Clear ipi flag */ + clint_ipi_clear(core_id); + if (clint_ipi_instance[core_id].callback != NULL) + clint_ipi_instance[core_id].callback(clint_ipi_instance[core_id].ctx); + clear_csr(mstatus, MSTATUS_MIE); + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + set_csr(mie, MIP_MSIP); + return epc; +} + diff --git a/lib/drivers/common.c b/lib/drivers/common.c new file mode 100755 index 0000000..d21a3b3 --- /dev/null +++ b/lib/drivers/common.c @@ -0,0 +1,44 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "encoding.h" +#include "utils.h" + +void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value) +{ + uint32_t org = (*bits) & ~mask; + *bits = org | (value & mask); +} + +void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value) +{ + set_bit(bits, mask << offset, value << offset); +} + +void set_gpio_bit(volatile uint32_t *bits, size_t offset, uint32_t value) +{ + set_bit_offset(bits, 1, offset, value); +} + +uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset) +{ + return ((*bits) & (mask << offset)) >> offset; +} + +uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset) +{ + return get_bit(bits, 1, offset); +} + diff --git a/lib/drivers/dmac.c b/lib/drivers/dmac.c new file mode 100755 index 0000000..c446049 --- /dev/null +++ b/lib/drivers/dmac.c @@ -0,0 +1,719 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include +#include "dmac.h" +#include "sysctl.h" +#include "fpioa.h" +#include "utils.h" +#include "plic.h" +#include "stdlib.h" + +volatile dmac_t *const dmac = (dmac_t *)DMAC_BASE_ADDR; + +static int is_memory(uintptr_t address) +{ + enum { + mem_len = 6 * 1024 * 1024, + mem_no_cache_len = 8 * 1024 * 1024, + }; + return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_no_cache_len)) || (address == 0x50450040); +} + +uint64_t dmac_read_id(void) +{ + return dmac->id; +} + +uint64_t dmac_read_version(void) +{ + return dmac->compver; +} + +uint64_t dmac_read_channel_id(dmac_channel_number_t channel_num) +{ + return dmac->channel[channel_num].axi_id; +} + +static void dmac_enable(void) +{ + dmac_cfg_u_t dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 1; + dmac_cfg.cfg.int_en = 1; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void dmac_disable(void) +{ + dmac_cfg_u_t dmac_cfg; + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); +} + +void src_transaction_complete_int_enable(dmac_channel_number_t channel_num) +{ + dmac_ch_intstatus_enable_u_t ch_intstat; + + ch_intstat.data = readq(&dmac->channel[channel_num].intstatus_en); + ch_intstat.ch_intstatus_enable.enable_src_transcomp_intstat = 1; + + writeq(ch_intstat.data, &dmac->channel[channel_num].intstatus_en); +} + +static void dmac_channel_enable(dmac_channel_number_t channel_num) +{ + dmac_chen_u_t chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 1; + chen.dmac_chen.ch1_en_we = 1; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 1; + chen.dmac_chen.ch2_en_we = 1; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 1; + chen.dmac_chen.ch3_en_we = 1; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 1; + chen.dmac_chen.ch4_en_we = 1; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 1; + chen.dmac_chen.ch5_en_we = 1; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 1; + chen.dmac_chen.ch6_en_we = 1; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +static void dmac_channel_disable(dmac_channel_number_t channel_num) +{ + dmac_chen_u_t chen; + + chen.data = readq(&dmac->chen); + + switch (channel_num) { + case DMAC_CHANNEL0: + chen.dmac_chen.ch1_en = 0; + chen.dmac_chen.ch1_en_we = 0; + break; + case DMAC_CHANNEL1: + chen.dmac_chen.ch2_en = 0; + chen.dmac_chen.ch2_en_we = 0; + break; + case DMAC_CHANNEL2: + chen.dmac_chen.ch3_en = 0; + chen.dmac_chen.ch3_en_we = 0; + break; + case DMAC_CHANNEL3: + chen.dmac_chen.ch4_en = 0; + chen.dmac_chen.ch4_en_we = 0; + break; + case DMAC_CHANNEL4: + chen.dmac_chen.ch5_en = 0; + chen.dmac_chen.ch5_en_we = 0; + break; + case DMAC_CHANNEL5: + chen.dmac_chen.ch6_en = 0; + chen.dmac_chen.ch6_en_we = 0; + break; + default: + break; + } + + writeq(chen.data, &dmac->chen); +} + +int32_t dmac_check_channel_busy(dmac_channel_number_t channel_num) +{ + int32_t ret = 0; + dmac_chen_u_t chen_u; + + chen_u.data = readq(&dmac->chen); + switch (channel_num) { + case DMAC_CHANNEL0: + if (chen_u.dmac_chen.ch1_en == 1) + ret = 1; + break; + case DMAC_CHANNEL1: + if (chen_u.dmac_chen.ch2_en == 1) + ret = 1; + break; + case DMAC_CHANNEL2: + if (chen_u.dmac_chen.ch3_en == 1) + ret = 1; + break; + case DMAC_CHANNEL3: + if (chen_u.dmac_chen.ch4_en == 1) + ret = 1; + break; + case DMAC_CHANNEL4: + if (chen_u.dmac_chen.ch5_en == 1) + ret = 1; + break; + case DMAC_CHANNEL5: + if (chen_u.dmac_chen.ch6_en == 1) + ret = 1; + break; + default: + break; + } + + writeq(chen_u.data, &dmac->chen); + + return ret; +} + +int32_t dmac_set_list_master_select(dmac_channel_number_t channel_num, + dmac_src_dst_select_t sd_sel, dmac_master_number_t mst_num) +{ + int32_t ret = 0; + uint64_t tmp = 0; + dmac_ch_ctl_u_t ctl; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ret = dmac_check_channel_busy(channel_num); + if (ret == 0) { + if (sd_sel == DMAC_SRC || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.sms = mst_num; + + if (sd_sel == DMAC_DST || sd_sel == DMAC_SRC_DST) + ctl.ch_ctl.dms = mst_num; + tmp |= *(uint64_t *)&dmac->channel[channel_num].ctl; + writeq(ctl.data, &dmac->channel[channel_num].ctl); + } + + return ret; +} + +void dmac_enable_common_interrupt_status(void) +{ + dmac_commonreg_intstatus_enable_u_t intstatus; + + intstatus.data = readq(&dmac->com_intstatus_en); + intstatus.intstatus_enable.enable_slvif_dec_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wr2ro_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_rd2wo_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_wronhold_err_intstat = 1; + intstatus.intstatus_enable.enable_slvif_undefinedreg_dec_err_intstat = 1; + + writeq(intstatus.data, &dmac->com_intstatus_en); +} + +void dmac_enable_common_interrupt_signal(void) +{ + dmac_commonreg_intsignal_enable_u_t intsignal; + + intsignal.data = readq(&dmac->com_intsignal_en); + intsignal.intsignal_enable.enable_slvif_dec_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wr2ro_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_rd2wo_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_wronhold_err_intsignal = 1; + intsignal.intsignal_enable.enable_slvif_undefinedreg_dec_err_intsignal = 1; + + writeq(intsignal.data, &dmac->com_intsignal_en); +} + +static void dmac_enable_channel_interrupt_status(dmac_channel_number_t channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); + writeq(0xffffffff, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_disable_channel_interrupt_status(dmac_channel_number_t channel_num) +{ + writeq(0, &dmac->channel[channel_num].intstatus_en); +} + +void dmac_enable_channel_interrupt_signal(dmac_channel_number_t channel_num, + dmac_common_int_t which_interrupt) +{ + +} + +static void dmac_chanel_interrupt_clear(dmac_channel_number_t channel_num) +{ + writeq(0xffffffff, &dmac->channel[channel_num].intclear); +} + +int dmac_set_channel_config(dmac_channel_number_t channel_num, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg; + dmac_ch_llp_u_t ch_llp; + + if (cfg_param->ctl_sms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_dms > DMAC_MASTER2) + return -1; + if (cfg_param->ctl_src_msize > DMAC_MSIZE_256) + return -1; + if (cfg_param->ctl_drc_msize > DMAC_MSIZE_256) + return -1; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg.data = readq(&dmac->channel[channel_num].cfg); + + cfg.ch_cfg.hs_sel_src = cfg_param->cfg_hs_sel_src; + cfg.ch_cfg.hs_sel_dst = cfg_param->cfg_hs_sel_dst; + cfg.ch_cfg.src_hwhs_pol = cfg_param->cfg_src_hs_pol; + cfg.ch_cfg.dst_hwhs_pol = cfg_param->cfg_dst_hs_pol; + cfg.ch_cfg.src_per = cfg_param->cfg_src_per; + cfg.ch_cfg.dst_per = cfg_param->cfg_dst_per; + cfg.ch_cfg.ch_prior = cfg_param->cfg_ch_prior; + cfg.ch_cfg.tt_fc = cfg_param->ctl_tt_fc; + + cfg.ch_cfg.src_multblk_type = cfg_param->cfg_src_multblk_type; + cfg.ch_cfg.dst_multblk_type = cfg_param->cfg_dst_multblk_type; + + writeq(cfg.data, &dmac->channel[channel_num].cfg); + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + /* master select */ + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + /* transfer width */ + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + /* Burst transaction length */ + ctl.ch_ctl.ioc_blktfr = cfg_param->ctl_ioc_blktfr; + /* interrupt on completion of block transfer */ + /* 0x1 enable BLOCK_TFR_DONE_IntStat field */ + + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + /* the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + + dmac->channel[channel_num].sar = cfg_param->sar; + dmac->channel[channel_num].dar = cfg_param->dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + ch_llp.llp.loc = cfg_param->llp_loc; + ch_llp.llp.lms = cfg_param->llp_lms; + writeq(ch_llp.data, &dmac->channel[channel_num].llp); + writeq(ctl.data, &dmac->channel[channel_num].ctl); + readq(&dmac->channel[channel_num].swhssrc); + + return 0; +} + +static int dmac_set_channel_param(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + uint32_t blockSize) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg_u; + + int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest); + dmac_transfer_flow_t flow_control; + if (mem_type_src == 0 && mem_type_dest == 0) + { + flow_control = DMAC_PRF2PRF_DMA; + }else if (mem_type_src == 1 && mem_type_dest == 0) + flow_control = DMAC_MEM2PRF_DMA; + else if (mem_type_src == 0 && mem_type_dest == 1) + flow_control = DMAC_PRF2MEM_DMA; + else + flow_control = DMAC_MEM2MEM_DMA; + + /** + * cfg register must configure before ts_block and + * sar dar register + */ + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + + cfg_u.ch_cfg.tt_fc = flow_control; + cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE; + cfg_u.ch_cfg.src_per = channel_num; + cfg_u.ch_cfg.dst_per = channel_num; + cfg_u.ch_cfg.src_multblk_type = 0; + cfg_u.ch_cfg.dst_multblk_type = 0; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); + + dmac->channel[channel_num].sar = (uint64_t)src; + dmac->channel[channel_num].dar = (uint64_t)dest; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = DMAC_MASTER1; + ctl.ch_ctl.dms = DMAC_MASTER2; + /* master select */ + ctl.ch_ctl.sinc = src_inc; + ctl.ch_ctl.dinc = dest_inc; + /* address incrememt */ + ctl.ch_ctl.src_tr_width = dmac_trans_width; + ctl.ch_ctl.dst_tr_width = dmac_trans_width; + /* transfer width */ + ctl.ch_ctl.src_msize = dmac_burst_size; + ctl.ch_ctl.dst_msize = dmac_burst_size; + + writeq(ctl.data, &dmac->channel[channel_num].ctl); + + writeq(blockSize - 1, &dmac->channel[channel_num].block_ts); + /*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */ + /* transferred in a dma block transfer */ + return 0; +} + +int dmac_get_channel_config(dmac_channel_number_t channel_num, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_cfg_u_t cfg; + dmac_ch_llp_u_t ch_llp; + + if (cfg_param == 0) + return -1; + if (channel_num < DMAC_CHANNEL0 || + channel_num > DMAC_CHANNEL3) + return -1; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + + cfg_param->ctl_sms = ctl.ch_ctl.sms; + cfg_param->ctl_dms = ctl.ch_ctl.dms; + cfg_param->ctl_sinc = ctl.ch_ctl.sinc; + cfg_param->ctl_dinc = ctl.ch_ctl.dinc; + cfg_param->ctl_src_tr_width = ctl.ch_ctl.src_tr_width; + cfg_param->ctl_dst_tr_width = ctl.ch_ctl.dst_tr_width; + cfg_param->ctl_src_msize = ctl.ch_ctl.src_msize; + cfg_param->ctl_drc_msize = ctl.ch_ctl.dst_msize; + cfg_param->ctl_ioc_blktfr = ctl.ch_ctl.ioc_blktfr; + + cfg.data = readq(&dmac->channel[channel_num].cfg); + cfg_param->cfg_hs_sel_src = cfg.ch_cfg.hs_sel_src; + cfg_param->cfg_hs_sel_dst = cfg.ch_cfg.hs_sel_dst; + cfg_param->cfg_src_hs_pol = cfg.ch_cfg.src_hwhs_pol; + cfg_param->cfg_dst_hs_pol = cfg.ch_cfg.dst_hwhs_pol; + cfg_param->cfg_src_per = cfg.ch_cfg.src_per; + cfg_param->cfg_dst_per = cfg.ch_cfg.dst_per; + cfg_param->cfg_ch_prior = cfg.ch_cfg.ch_prior; + cfg_param->cfg_src_multblk_type = cfg.ch_cfg.src_multblk_type; + cfg_param->cfg_dst_multblk_type = cfg.ch_cfg.dst_multblk_type; + + cfg_param->sar = dmac->channel[channel_num].sar; + cfg_param->dar = dmac->channel[channel_num].dar; + + ch_llp.data = readq(&dmac->channel[channel_num].llp); + cfg_param->llp_loc = ch_llp.llp.loc; + cfg_param->llp_lms = ch_llp.llp.lms; + + cfg_param->ctl_block_ts = readq(&dmac->channel[channel_num].block_ts); + + return 0; +} + +void dmac_set_address(dmac_channel_number_t channel_num, uint64_t src_addr, + uint64_t dst_addr) +{ + writeq(src_addr, &dmac->channel[channel_num].sar); + writeq(dst_addr, &dmac->channel[channel_num].dar); +} + +void dmac_set_block_ts(dmac_channel_number_t channel_num, + uint32_t block_size) +{ + uint32_t block_ts; + + block_ts = block_size & 0x3fffff; + writeq(block_ts, &dmac->channel[channel_num].block_ts); +} + +void dmac_source_control(dmac_channel_number_t channel_num, + dmac_master_number_t master_select, + dmac_address_increment_t address_mode, + dmac_transfer_width_t tr_width, + dmac_burst_trans_length_t burst_length) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.sms = master_select; + ctl_u.ch_ctl.sinc = address_mode; + ctl_u.ch_ctl.src_tr_width = tr_width; + ctl_u.ch_ctl.src_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_master_control(dmac_channel_number_t channel_num, + dmac_master_number_t master_select, + dmac_address_increment_t address_mode, + dmac_transfer_width_t tr_width, + dmac_burst_trans_length_t burst_length) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.dms = master_select; + ctl_u.ch_ctl.dinc = address_mode; + ctl_u.ch_ctl.dst_tr_width = tr_width; + ctl_u.ch_ctl.dst_msize = burst_length; + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_source_transfer_control(dmac_channel_number_t channel_num, + dmac_multiblk_transfer_type_t transfer_type, + dmac_sw_hw_hs_select_t handshak_select) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.src_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_src = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_destination_transfer_control(dmac_channel_number_t channel_num, + dmac_multiblk_transfer_type_t transfer_type, + dmac_sw_hw_hs_select_t handshak_select) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.dst_multblk_type = transfer_type; + cfg_u.ch_cfg.hs_sel_dst = handshak_select; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_flow_control(dmac_channel_number_t channel_num, + dmac_transfer_flow_t flow_control) +{ + dmac_ch_cfg_u_t cfg_u; + + cfg_u.data = readq(&dmac->channel[channel_num].cfg); + cfg_u.ch_cfg.tt_fc = flow_control; + + writeq(cfg_u.data, &dmac->channel[channel_num].cfg); +} + +void dmac_set_linked_list_addr_point(dmac_channel_number_t channel_num, + uint64_t *addr) +{ + dmac_ch_llp_u_t llp_u; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + /* Cast pointer to uint64_t */ + llp_u.llp.loc = (uint64_t)addr; + writeq(llp_u.data, &dmac->channel[channel_num].llp); +} + +void dmac_init(void) +{ + uint64_t tmp; + dmac_commonreg_intclear_u_t intclear; + dmac_cfg_u_t dmac_cfg; + dmac_reset_u_t dmac_reset; + + sysctl_clock_enable(SYSCTL_CLOCK_DMA); + + dmac_reset.data = readq(&dmac->reset); + dmac_reset.reset.rst = 1; + writeq(dmac_reset.data, &dmac->reset); + while (dmac_reset.reset.rst) + dmac_reset.data = readq(&dmac->reset); + + /*reset dmac */ + + intclear.data = readq(&dmac->com_intclear); + intclear.com_intclear.cear_slvif_dec_err_intstat = 1; + intclear.com_intclear.clear_slvif_wr2ro_err_intstat = 1; + intclear.com_intclear.clear_slvif_rd2wo_err_intstat = 1; + intclear.com_intclear.clear_slvif_wronhold_err_intstat = 1; + intclear.com_intclear.clear_slvif_undefinedreg_dec_err_intstat = 1; + writeq(intclear.data, &dmac->com_intclear); + /* clear common register interrupt */ + + dmac_cfg.data = readq(&dmac->cfg); + dmac_cfg.cfg.dmac_en = 0; + dmac_cfg.cfg.int_en = 0; + writeq(dmac_cfg.data, &dmac->cfg); + /* disable dmac and disable interrupt */ + + while (readq(&dmac->cfg)) + ; + tmp = readq(&dmac->chen); + tmp &= ~0xf; + writeq(tmp, &dmac->chen); + /* disable all channel before configure */ +} + +static void list_add(struct list_head_t *new, struct list_head_t *prev, + struct list_head_t *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static void list_add_tail(struct list_head_t *new, struct list_head_t *head) +{ + list_add(new, head->prev, head); +} + +static void INIT_LIST_HEAD(struct list_head_t *list) +{ + list->next = list; + list->prev = list; +} + +void dmac_link_list_item(dmac_channel_number_t channel_num, + uint8_t LLI_row_num, int8_t LLI_last_row, + dmac_lli_item_t *lli_item, + dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl; + dmac_ch_llp_u_t llp_u; + + lli_item[LLI_row_num].sar = cfg_param->sar; + lli_item[LLI_row_num].dar = cfg_param->dar; + + ctl.data = readq(&dmac->channel[channel_num].ctl); + ctl.ch_ctl.sms = cfg_param->ctl_sms; + ctl.ch_ctl.dms = cfg_param->ctl_dms; + ctl.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + + if (LLI_last_row != LAST_ROW) { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl.ch_ctl.shadowreg_or_lli_valid = 1; + ctl.ch_ctl.shadowreg_or_lli_last = 1; + } + + lli_item[LLI_row_num].ctl = ctl.data; + + lli_item[LLI_row_num].ch_block_ts = cfg_param->ctl_block_ts; + lli_item[LLI_row_num].sstat = 0; + lli_item[LLI_row_num].dstat = 0; + + llp_u.data = readq(&dmac->channel[channel_num].llp); + + if (LLI_last_row != LAST_ROW) + llp_u.llp.loc = ((uint64_t)&lli_item[LLI_row_num + 1]) >> 6; + else + llp_u.llp.loc = 0; + + lli_item[LLI_row_num].llp = llp_u.data; +} + +void dmac_update_shandow_register(dmac_channel_number_t channel_num, + int8_t last_block, dmac_channel_config_t *cfg_param) +{ + dmac_ch_ctl_u_t ctl_u; + + do { + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + } while (ctl_u.ch_ctl.shadowreg_or_lli_valid); + + writeq(cfg_param->sar, &dmac->channel[channel_num].sar); + writeq(cfg_param->dar, &dmac->channel[channel_num].dar); + writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts); + + ctl_u.ch_ctl.sms = cfg_param->ctl_sms; + ctl_u.ch_ctl.dms = cfg_param->ctl_dms; + ctl_u.ch_ctl.sinc = cfg_param->ctl_sinc; + ctl_u.ch_ctl.dinc = cfg_param->ctl_dinc; + ctl_u.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width; + ctl_u.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width; + ctl_u.ch_ctl.src_msize = cfg_param->ctl_src_msize; + ctl_u.ch_ctl.dst_msize = cfg_param->ctl_drc_msize; + ctl_u.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en; + ctl_u.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en; + if (last_block != LAST_ROW) + { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + } else { + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 1; + } + + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); + writeq(0, &dmac->channel[channel_num].blk_tfr); +} + +void dmac_set_shadow_invalid_flag(dmac_channel_number_t channel_num) +{ + dmac_ch_ctl_u_t ctl_u; + + ctl_u.data = readq(&dmac->channel[channel_num].ctl); + ctl_u.ch_ctl.shadowreg_or_lli_valid = 1; + ctl_u.ch_ctl.shadowreg_or_lli_last = 0; + writeq(ctl_u.data, &dmac->channel[channel_num].ctl); +} + +void dmac_set_single_mode(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, + dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + size_t block_size) { + dmac_channel_disable(channel_num); + dmac_set_channel_param(channel_num, src, dest, src_inc, dest_inc, + dmac_burst_size, dmac_trans_width, block_size); + dmac_enable(); + dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */ + dmac_enable_channel_interrupt_status(channel_num); + dmac_channel_enable(channel_num); +} + +void dmac_wait_done(dmac_channel_number_t channel_num) +{ + while (!(readq(&dmac->channel[channel_num].intstatus) & 0x2)) + ; + dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */ +} diff --git a/lib/drivers/dvp.c b/lib/drivers/dvp.c new file mode 100755 index 0000000..771643a --- /dev/null +++ b/lib/drivers/dvp.c @@ -0,0 +1,265 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "dvp.h" +#include "utils.h" +#include "fpioa.h" +#include "sysctl.h" + +volatile dvp_t* const dvp = (volatile dvp_t*)DVP_BASE_ADDR; +static uint8_t g_sccb_reg_len = 8; + +static void mdelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25000; i++) + __asm__ __volatile__("nop"); + } +} + +static void dvp_sccb_clk_init(void) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK)); + tmp |= DVP_SCCB_SCL_LCNT(500) | DVP_SCCB_SCL_HCNT(500); + + dvp->sccb_cfg = tmp; +} + +static void dvp_sccb_start_transfer(void) +{ + while (dvp->sts & DVP_STS_SCCB_EN) + ; + dvp->sts = DVP_STS_SCCB_EN | DVP_STS_SCCB_EN_WE; + while (dvp->sts & DVP_STS_SCCB_EN) + ; +} + +void dvp_sccb_send_data(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK); + + (g_sccb_reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_3) : (tmp |= DVP_SCCB_BYTE_NUM_4); + + dvp->sccb_cfg = tmp; + + if (g_sccb_reg_len == 8) + { + dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr) | DVP_SCCB_WDATA_BYTE0(reg_data); + } + else + { + dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff) | DVP_SCCB_WDATA_BYTE1(reg_data); + } + dvp_sccb_start_transfer(); +} + +uint8_t dvp_sccb_receive_data(uint8_t dev_addr, uint16_t reg_addr) +{ + uint32_t tmp; + + tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK); + + if (g_sccb_reg_len == 8) + tmp |= DVP_SCCB_BYTE_NUM_2; + else + tmp |= DVP_SCCB_BYTE_NUM_3; + + dvp->sccb_cfg = tmp; + + if (g_sccb_reg_len == 8) + { + dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr); + } + else + { + dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff); + } + dvp_sccb_start_transfer(); + + dvp->sccb_ctl = DVP_SCCB_DEVICE_ADDRESS(dev_addr); + + dvp_sccb_start_transfer(); + + return (uint8_t) DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg); +} + +void dvp_reset(void) +{ + /* First power down */ + dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN; + mdelay(200); + dvp->cmos_cfg &= ~DVP_CMOS_POWER_DOWN; + mdelay(200); + + /* Second reset */ + dvp->cmos_cfg &= ~DVP_CMOS_RESET; + mdelay(200); + dvp->cmos_cfg |= DVP_CMOS_RESET; + mdelay(200); +} + +void dvp_init(uint8_t reg_len) +{ + g_sccb_reg_len = reg_len; + sysctl_clock_enable(SYSCTL_CLOCK_DVP); + sysctl_reset(SYSCTL_RESET_DVP); + dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK); + dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(0) | DVP_CMOS_CLK_ENABLE; + dvp_sccb_clk_init(); + dvp_reset(); +} + +void dvp_set_image_format(uint32_t format) +{ + uint32_t tmp; + + tmp = dvp->dvp_cfg & (~DVP_CFG_FORMAT_MASK); + dvp->dvp_cfg = tmp | format; +} + +void dvp_enable_burst(void) +{ + dvp->dvp_cfg |= DVP_CFG_BURST_SIZE_4BEATS; + + dvp->axi &= (~DVP_AXI_GM_MLEN_MASK); + dvp->axi |= DVP_AXI_GM_MLEN_4BYTE; +} + +void dvp_disable_burst(void) +{ + dvp->dvp_cfg &= (~DVP_CFG_BURST_SIZE_4BEATS); + + dvp->axi &= (~DVP_AXI_GM_MLEN_MASK); + dvp->axi |= DVP_AXI_GM_MLEN_1BYTE; +} + +void dvp_set_image_size(uint32_t width, uint32_t height) +{ + uint32_t tmp; + + tmp = dvp->dvp_cfg & (~(DVP_CFG_HREF_BURST_NUM_MASK | DVP_CFG_LINE_NUM_MASK)); + + tmp |= DVP_CFG_LINE_NUM(height); + + if (dvp->dvp_cfg & DVP_CFG_BURST_SIZE_4BEATS) + tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 4); + else + tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 1); + + dvp->dvp_cfg = tmp; +} + +void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr) +{ + dvp->r_addr = r_addr; + dvp->g_addr = g_addr; + dvp->b_addr = b_addr; +} + +void dvp_set_display_addr(uint32_t addr) +{ + dvp->rgb_addr = addr; +} + +void dvp_start_frame(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = (DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE); +} + +void dvp_start_convert(void) +{ + dvp->sts = DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE; +} + +void dvp_finish_convert(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_FINISH)) + ; + dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE; +} + +void dvp_get_image(void) +{ + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE; + while (!(dvp->sts & DVP_STS_FRAME_START)) + ; + dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE | DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE | DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE; + while (!(dvp->sts & DVP_STS_FRAME_FINISH)) + ; +} + +void dvp_config_interrupt(uint32_t interrupt, uint8_t enable) +{ + if (enable) + dvp->dvp_cfg |= interrupt; + else + dvp->dvp_cfg &= (~interrupt); +} + +int dvp_get_interrupt(uint32_t interrupt) +{ + if (dvp->sts & interrupt) + return 1; + return 0; +} + +void dvp_clear_interrupt(uint32_t interrupt) +{ + interrupt |= (interrupt << 1); + dvp->sts |= interrupt; +} + +void dvp_enable_auto(void) +{ + dvp->dvp_cfg |= DVP_CFG_AUTO_ENABLE; +} + +void dvp_disable_auto(void) +{ + dvp->dvp_cfg &= (~DVP_CFG_AUTO_ENABLE); +} + +void dvp_set_output_enable(dvp_output_mode_t index, int enable) +{ + configASSERT(index < 2); + + if (index == 0) + { + if (enable) + dvp->dvp_cfg |= DVP_CFG_AI_OUTPUT_ENABLE; + else + dvp->dvp_cfg &= ~DVP_CFG_AI_OUTPUT_ENABLE; + } + else + { + if (enable) + dvp->dvp_cfg |= DVP_CFG_DISPLAY_OUTPUT_ENABLE; + else + dvp->dvp_cfg &= ~DVP_CFG_DISPLAY_OUTPUT_ENABLE; + } +} + diff --git a/lib/drivers/fft.c b/lib/drivers/fft.c new file mode 100755 index 0000000..102dacf --- /dev/null +++ b/lib/drivers/fft.c @@ -0,0 +1,68 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "dmac.h" +#include "utils.h" +#include "sysctl.h" +#include "fft.h" + +static volatile fft_t *const fft = (volatile fft_t *)FFT_BASE_ADDR; + +static void fft_init(uint8_t point, uint8_t mode, uint16_t shift, uint8_t is_dma, uint8_t input_mode, uint8_t data_mode) +{ + fft->fft_ctrl.fft_point = point; + fft->fft_ctrl.fft_mode = mode; + fft->fft_ctrl.fft_shift = shift; + fft->fft_ctrl.dma_send = is_dma; + fft->fft_ctrl.fft_enable = 1; + fft->fft_ctrl.fft_input_mode = input_mode; + fft->fft_ctrl.fft_data_mode = data_mode; +} + +void fft_complex_uint16_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + uint16_t shift, fft_direction_t direction, const uint64_t *input, size_t point_num, uint64_t *output) +{ + fft_point_t point = FFT_512; + switch(point_num) + { + case 512: + point = FFT_512; + break; + case 256: + point = FFT_256; + break; + case 128: + point = FFT_128; + break; + case 64: + point = FFT_64; + break; + default: + configASSERT(!"fft point error"); + break; + } + sysctl_clock_enable(SYSCTL_CLOCK_FFT); + sysctl_reset(SYSCTL_RESET_FFT); + fft_init(point, direction, shift, 1, 0, 0); + sysctl_dma_select(dma_receive_channel_num, SYSCTL_DMA_SELECT_FFT_RX_REQ); + sysctl_dma_select(dma_send_channel_num, SYSCTL_DMA_SELECT_FFT_TX_REQ); + dmac_set_single_mode(dma_receive_channel_num, (void *)(&fft->fft_output_fifo), output, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_64, point_num>>1); + dmac_set_single_mode(dma_send_channel_num, input, (void *)(&fft->fft_input_fifo), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_64, point_num>>1); + dmac_wait_done(dma_receive_channel_num); +} + + diff --git a/lib/drivers/fpioa.c b/lib/drivers/fpioa.c new file mode 100755 index 0000000..29dea63 --- /dev/null +++ b/lib/drivers/fpioa.c @@ -0,0 +1,5398 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "sysctl.h" +#include "fpioa.h" + +volatile fpioa_t *const fpioa = (volatile fpioa_t *)FPIOA_BASE_ADDR; + +/** + * @brief Internal used FPIOA function initialize cell + * + * This is NOT fpioa_io_config_t, can't assign directly + * + */ +typedef struct _fpioa_assign_t +{ + uint32_t ch_sel : 8; + /* Channel select from 256 input. */ + uint32_t ds : 4; + /* Driving selector. */ + uint32_t oe_en : 1; + /* Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /* Invert output enable. */ + uint32_t do_sel : 1; + /* Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /* Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /* Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /* Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /* Reserved bits. */ + uint32_t sl : 1; + /* Slew rate control enable. */ + uint32_t ie_en : 1; + /* Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /* Invert input enable. */ + uint32_t di_inv : 1; + /* Invert Data input. */ + uint32_t st : 1; + /* Schmitt trigger. */ + uint32_t tie_en : 1; + /* Input tie enable, 1 for enable, 0 for disable. */ + uint32_t tie_val : 1; + /* Input tie value, 1 for high, 0 for low. */ + uint32_t resv1 : 5; + /* Reserved bits. */ + uint32_t pad_di : 1; + /* Read current PAD's data input. */ +} __attribute__((packed, aligned(4))) fpioa_assign_t; + +/* Function list */ +static const fpioa_assign_t function_config[FUNC_MAX] = +{ + { + .ch_sel = FUNC_JTAG_TCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TMS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_JTAG_TDO, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UARTHS_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIOHS31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_GPIO7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RX, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_TX, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_D7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SS3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_ARB, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 1, + .tie_val = 1, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 1, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SPI_SLAVE_SCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S0_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S1_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_MCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_SCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_WS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_IN_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2S2_OUT_D3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_RESV5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C0_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C1_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_I2C2_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_XCLK, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_RST, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PWDN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_VSYNC, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_HREF, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_PCLK, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D0, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D1, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D2, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D3, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D4, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D5, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D6, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CMOS_D7, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SCLK, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_SCCB_SDA, + .ds = 0x0, + .oe_en = 1, + .oe_inv = 1, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART1_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART2_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_CTS, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DSR, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DCD, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RI, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_IN, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DTR, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RTS, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_OUT1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_SIR_OUT, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_BAUD, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_DE, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_UART3_RS485_EN, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER0_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER1_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_TIMER2_TOGGLE4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_SPI2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CLK_I2C2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL9, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL10, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL11, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL12, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL13, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 1, + .pd = 0, + .resv1 = 0, + .sl = 1, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL15, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL16, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL17, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_CONSTANT, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_INTERNAL18, + .ds = 0x0, + .oe_en = 0, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 1, + .ie_inv = 0, + .di_inv = 0, + .st = 1, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG0, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG1, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG2, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG3, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG4, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG5, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG6, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG7, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG8, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG9, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG10, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG11, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG12, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG13, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG14, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG15, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG16, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG17, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG18, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG19, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG20, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG21, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG22, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG23, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG24, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG25, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG26, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG27, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG28, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG29, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG30, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, + { + .ch_sel = FUNC_DEBUG31, + .ds = 0xf, + .oe_en = 1, + .oe_inv = 0, + .do_sel = 0, + .do_inv = 0, + .pu = 0, + .pd = 0, + .resv1 = 0, + .sl = 0, + .ie_en = 0, + .ie_inv = 0, + .di_inv = 0, + .st = 0, + .tie_en = 0, + .tie_val = 0, + .resv0 = 0, + .pad_di = 0 + }, +}; + +int fpioa_init(void) +{ + int i = 0; + + /* Enable fpioa clock in system controller */ + sysctl_clock_enable(SYSCTL_CLOCK_FPIOA); + + /* Initialize tie */ + fpioa_tie_t tie = { 0 }; + + /* Set tie enable and tie value */ + for (i = 0; i < FUNC_MAX; i++) + { + tie.en[i / 32] |= (function_config[i].tie_en << (i % 32)); + tie.val[i / 32] |= (function_config[i].tie_val << (i % 32)); + } + + /* Atomic write every 32bit register to fpioa function */ + for (i = 0; i < FUNC_MAX / 32; i++) + { + /* Set value before enable */ + fpioa->tie.val[i] = tie.val[i]; + fpioa->tie.en[i] = tie.en[i]; + } + + return 0; +} + +int fpioa_get_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic read register */ + *cfg = fpioa->io[number]; + return 0; +} + +int fpioa_set_io(int number, fpioa_io_config_t *cfg) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || cfg == NULL) + return -1; + /* Atomic write register */ + fpioa->io[number] = *cfg; + return 0; +} + +int fpioa_set_io_pull(int number, fpioa_pull_t pull) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || pull >= FPIOA_PULL_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + switch (pull) + { + case FPIOA_PULL_NONE: + cfg.pu = 0; + cfg.pd = 0; + break; + case FPIOA_PULL_DOWN: + cfg.pu = 0; + cfg.pd = 1; + break; + case FPIOA_PULL_UP: + cfg.pu = 1; + cfg.pd = 0; + break; + default: + break; + } + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_pull(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + fpioa_pull_t pull; + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + + if (cfg.pu == 0 && cfg.pd == 1) + pull = FPIOA_PULL_DOWN; + else if (cfg.pu == 1 && cfg.pd == 0) + pull = FPIOA_PULL_UP; + else + pull = FPIOA_PULL_NONE; + return pull; +} + +int fpioa_set_io_driving(int number, fpioa_driving_t driving) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || driving >= FPIOA_DRIVING_MAX) + return -1; + + /* Atomic read register */ + fpioa_io_config_t cfg = fpioa->io[number]; + /* Set IO driving */ + cfg.ds = driving; + /* Atomic write register */ + fpioa->io[number] = cfg; + return 0; +} + +int fpioa_get_io_driving(int number) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO) + return -1; + + return fpioa->io[number].ds; +} + +int fpioa_set_function_raw(int number, fpioa_function_t function) +{ + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + /* Atomic write register */ + fpioa->io[number] =(const fpioa_io_config_t) + { + .ch_sel = function_config[function].ch_sel, + .ds = function_config[function].ds, + .oe_en = function_config[function].oe_en, + .oe_inv = function_config[function].oe_inv, + .do_sel = function_config[function].do_sel, + .do_inv = function_config[function].do_inv, + .pu = function_config[function].pu, + .pd = function_config[function].pd, + .sl = function_config[function].sl, + .ie_en = function_config[function].ie_en, + .ie_inv = function_config[function].ie_inv, + .di_inv = function_config[function].di_inv, + .st = function_config[function].st, + /* resv and pad_di do not need initialization */ + }; + return 0; +} + +int fpioa_set_function(int number, fpioa_function_t function) +{ + uint8_t index = 0; + /* Check parameters */ + if (number < 0 || number >= FPIOA_NUM_IO || function < 0 || function >= FUNC_MAX) + return -1; + if (function == FUNC_RESV0) + { + fpioa_set_function_raw(number, FUNC_RESV0); + return 0; + } + /* Compare all IO */ + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if ((fpioa->io[index].ch_sel == function) && (index != number)) + fpioa_set_function_raw(index, FUNC_RESV0); + } + fpioa_set_function_raw(number, function); + return 0; +} + +int fpioa_set_tie_enable(fpioa_function_t function, int enable) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie enable */ + if (enable) + fpioa->tie.en[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.en[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_set_tie_value(fpioa_function_t function, int value) +{ + /* Check parameters */ + if (function < 0 || function >= FUNC_MAX) + return -1; + /* Set tie value */ + if (value) + fpioa->tie.val[function / 32] |= (1UL << (function % 32)); + else + fpioa->tie.val[function / 32] &= (~(1UL << (function % 32))); + return 0; +} + +int fpioa_get_io_by_function(fpioa_function_t function) +{ + int index = 0; + for (index = 0; index < FPIOA_NUM_IO; index++) + { + if (fpioa->io[index].ch_sel == function) + return index; + } + + return -1; +} diff --git a/lib/drivers/gpio.c b/lib/drivers/gpio.c new file mode 100755 index 0000000..ba996d8 --- /dev/null +++ b/lib/drivers/gpio.c @@ -0,0 +1,79 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "gpio.h" +#include "utils.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIO_MAX_PINNO 8 + +volatile gpio_t* const gpio = (volatile gpio_t*)GPIO_BASE_ADDR; + +int gpio_init(void) +{ + return sysctl_clock_enable(SYSCTL_CLOCK_GPIO); +} + +void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode) +{ + configASSERT(pin < GPIO_MAX_PINNO); + int io_number = fpioa_get_io_by_function(FUNC_GPIO0 + pin); + configASSERT(io_number > 0); + + fpioa_pull_t pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_INPUT: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_DOWN: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_UP: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_OUTPUT: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + set_gpio_bit(gpio->direction.u32, pin, dir); +} + +gpio_pin_value_t gpio_get_pin(uint8_t pin) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t *reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + return get_gpio_bit(reg, pin); +} + +void gpio_set_pin(uint8_t pin, gpio_pin_value_t value) +{ + configASSERT(pin < GPIO_MAX_PINNO); + uint32_t dir = get_gpio_bit(gpio->direction.u32, pin); + volatile uint32_t *reg = dir ? gpio->data_output.u32 : gpio->data_input.u32; + configASSERT(dir == 1); + set_gpio_bit(reg, pin, value); +} + diff --git a/lib/drivers/gpiohs.c b/lib/drivers/gpiohs.c new file mode 100755 index 0000000..951bd0b --- /dev/null +++ b/lib/drivers/gpiohs.c @@ -0,0 +1,171 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "gpiohs.h" +#include "utils.h" +#include "fpioa.h" +#include "sysctl.h" +#define GPIOHS_MAX_PINNO 32 + +volatile gpiohs_t* const gpiohs = (volatile gpiohs_t*)GPIOHS_BASE_ADDR; + +typedef struct _gpiohs_pin_context +{ + size_t pin; + gpio_pin_edge_t edge; + void (*callback)(); +} gpiohs_pin_context; + +gpiohs_pin_context pin_context[32]; + +void gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + int io_number = fpioa_get_io_by_function(FUNC_GPIOHS0 + pin); + configASSERT(io_number > 0); + + fpioa_pull_t pull; + uint32_t dir; + + switch (mode) + { + case GPIO_DM_INPUT: + pull = FPIOA_PULL_NONE; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_DOWN: + pull = FPIOA_PULL_DOWN; + dir = 0; + break; + case GPIO_DM_INPUT_PULL_UP: + pull = FPIOA_PULL_UP; + dir = 0; + break; + case GPIO_DM_OUTPUT: + pull = FPIOA_PULL_DOWN; + dir = 1; + break; + default: + configASSERT(!"GPIO drive mode is not supported.") break; + } + + fpioa_set_io_pull(io_number, pull); + volatile uint32_t *reg = dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + volatile uint32_t *reg_d = !dir ? gpiohs->output_en.u32 : gpiohs->input_en.u32; + set_gpio_bit(reg_d, pin, 0); + set_gpio_bit(reg, pin, 1); +} + +gpio_pin_value_t gpiohs_get_pin(uint8_t pin) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + return get_gpio_bit(gpiohs->input_val.u32, pin); +} + +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value) +{ + configASSERT(pin < GPIOHS_MAX_PINNO); + set_gpio_bit(gpiohs->output_val.u32, pin, value); +} + +void gpiohs_set_pin_edge(uint8_t pin, gpio_pin_edge_t edge) +{ + uint32_t rise, fall, irq; + switch (edge) + { + case GPIO_PE_NONE: + rise = fall = irq = 0; + break; + case GPIO_PE_FALLING: + rise = 0; + fall = irq = 1; + break; + case GPIO_PE_RISING: + fall = 0; + rise = irq = 1; + break; + case GPIO_PE_BOTH: + rise = fall = irq = 1; + break; + default: + configASSERT(!"Invalid gpio edge"); + break; + } + + set_gpio_bit(gpiohs->rise_ie.u32, pin, rise); + set_gpio_bit(gpiohs->fall_ie.u32, pin, fall); + pin_context[pin].edge = edge; +} + +int gpiohs_pin_onchange_isr(void *userdata) +{ + gpiohs_pin_context *ctx = (gpiohs_pin_context *)userdata; + size_t pin = ctx->pin; + uint32_t rise, fall; + switch (ctx->edge) + { + case GPIO_PE_NONE: + rise = fall = 0; + break; + case GPIO_PE_FALLING: + rise = 0; + fall = 1; + break; + case GPIO_PE_RISING: + fall = 0; + rise = 1; + break; + case GPIO_PE_BOTH: + rise = fall = 1; + break; + default: + configASSERT(!"Invalid gpio edge"); + break; + } + + if (rise) + { + set_gpio_bit(gpiohs->rise_ie.u32, pin, 0); + set_gpio_bit(gpiohs->rise_ip.u32, pin, 1); + set_gpio_bit(gpiohs->rise_ie.u32, pin, 1); + } + + if (fall) + { + set_gpio_bit(gpiohs->fall_ie.u32, pin, 0); + set_gpio_bit(gpiohs->fall_ip.u32, pin, 1); + set_gpio_bit(gpiohs->fall_ie.u32, pin, 1); + } + + if (ctx->callback) + ctx->callback(); + return 0; +} + +void gpiohs_set_irq(uint8_t pin, uint32_t priority, void (*func)()) +{ + + pin_context[pin].pin = pin; + pin_context[pin].callback = func; + + plic_set_priority(IRQN_GPIOHS0_INTERRUPT + pin, priority); + plic_irq_register(IRQN_GPIOHS0_INTERRUPT + pin, gpiohs_pin_onchange_isr, &(pin_context[pin])); + plic_irq_enable(IRQN_GPIOHS0_INTERRUPT + pin); +} + +void gpiohs_irq_disable(size_t pin) +{ + plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + pin); +} + diff --git a/lib/drivers/i2c.c b/lib/drivers/i2c.c new file mode 100755 index 0000000..857979a --- /dev/null +++ b/lib/drivers/i2c.c @@ -0,0 +1,189 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "i2c.h" +#include "utils.h" +#include "fpioa.h" +#include "platform.h" +#include "stdlib.h" +#include "string.h" +#include "sysctl.h" + +volatile i2c_t* const i2c[3] = +{ + (volatile i2c_t*)I2C0_BASE_ADDR, + (volatile i2c_t*)I2C1_BASE_ADDR, + (volatile i2c_t*)I2C2_BASE_ADDR +}; + +static void i2c_clk_init(i2c_device_number_t i2c_num) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + sysctl_clock_enable(SYSCTL_CLOCK_I2C0 + i2c_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2C0 + i2c_num, 3); +} + +void i2c_init(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + uint32_t i2c_clk) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + configASSERT(address_width == 7 || address_width == 10); + + volatile i2c_t *i2c_adapter = i2c[i2c_num]; + + i2c_clk_init(i2c_num); + + uint32_t v_i2c_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_I2C0 + i2c_num); + uint16_t v_period_clk_cnt = v_i2c_freq / i2c_clk / 2; + + if(v_period_clk_cnt == 0) + v_period_clk_cnt = 1; + + i2c_adapter->enable = 0; + i2c_adapter->con = I2C_CON_MASTER_MODE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN | + (address_width == 10 ? I2C_CON_10BITADDR_SLAVE : 0) | I2C_CON_SPEED(1); + i2c_adapter->ss_scl_hcnt = I2C_SS_SCL_HCNT_COUNT(v_period_clk_cnt); + i2c_adapter->ss_scl_lcnt = I2C_SS_SCL_LCNT_COUNT(v_period_clk_cnt); + + i2c_adapter->tar = I2C_TAR_ADDRESS(slave_address); + i2c_adapter->intr_mask = 0; + i2c_adapter->dma_cr = 0x3; + i2c_adapter->dma_rdlr = 0; + i2c_adapter->dma_tdlr = 4; + i2c_adapter->enable = I2C_ENABLE_ENABLE; +} + +int i2c_send_data(i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + size_t fifo_len, index; + + while (send_buf_len) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = send_buf_len < fifo_len ? send_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*send_buf++); + if (i2c_adapter->tx_abrt_source != 0) + return 1; + send_buf_len -= fifo_len; + } + while (i2c_adapter->status & I2C_STATUS_ACTIVITY) + ; + + return 0; +} + +void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_t i2c_num, const uint8_t *send_buf, + size_t send_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + + uint32_t *buf = malloc(send_buf_len * sizeof(uint32_t)); + int i; + for (i = 0; i < send_buf_len; i++) + { + buf[i] = send_buf[i]; + } + + sysctl_dma_select((sysctl_dma_channel_t)dma_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + dmac_set_single_mode(dma_channel_num, buf, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, send_buf_len); + + dmac_wait_done(dma_channel_num); + free((void *)buf); + + while (i2c_adapter->status & I2C_STATUS_ACTIVITY) + { + if (i2c_adapter->tx_abrt_source != 0) + configASSERT(!"source abort"); + } +} + +int i2c_recv_data(i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len, uint8_t *receive_buf, + size_t receive_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + + size_t fifo_len, index; + size_t rx_len = receive_buf_len; + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + + while (send_buf_len) + { + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = send_buf_len < fifo_len ? send_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_DATA(*send_buf++); + if (i2c_adapter->tx_abrt_source != 0) + return 1; + send_buf_len -= fifo_len; + } + + while (receive_buf_len || rx_len) + { + fifo_len = i2c_adapter->rxflr; + fifo_len = rx_len < fifo_len ? rx_len : fifo_len; + for (index = 0; index < fifo_len; index++) + *receive_buf++ = (uint8_t)i2c_adapter->data_cmd; + rx_len -= fifo_len; + fifo_len = 8 - i2c_adapter->txflr; + fifo_len = receive_buf_len < fifo_len ? receive_buf_len : fifo_len; + for (index = 0; index < fifo_len; index++) + i2c_adapter->data_cmd = I2C_DATA_CMD_CMD; + if (i2c_adapter->tx_abrt_source != 0) + return 1; + receive_buf_len -= fifo_len; + } + return 0; +} + +void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len, + uint8_t *receive_buf, size_t receive_buf_len) +{ + configASSERT(i2c_num < I2C_MAX_NUM); + + volatile i2c_t* i2c_adapter = i2c[i2c_num]; + + uint32_t *write_cmd = malloc(sizeof(uint32_t) * (send_buf_len + receive_buf_len)); + size_t i; + for(i = 0; i < send_buf_len; i++) + write_cmd[i] = *send_buf++; + for (i = 0; i < receive_buf_len; i++) + write_cmd[i + send_buf_len] = I2C_DATA_CMD_CMD; + + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_I2C0_TX_REQ + i2c_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_I2C0_RX_REQ + i2c_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&i2c_adapter->data_cmd), write_cmd, DMAC_ADDR_NOCHANGE, + DMAC_ADDR_INCREMENT,DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, receive_buf_len); + + dmac_set_single_mode(dma_send_channel_num, write_cmd, (void *)(&i2c_adapter->data_cmd), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE,DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, receive_buf_len + send_buf_len); + + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + for (i = 0; i < receive_buf_len; i++) + { + receive_buf[i] = (uint8_t)write_cmd[i]; + } + + free(write_cmd); +} + diff --git a/lib/drivers/i2s.c b/lib/drivers/i2s.c new file mode 100755 index 0000000..ccbe0af --- /dev/null +++ b/lib/drivers/i2s.c @@ -0,0 +1,613 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "i2s.h" +#include "sysctl.h" +#include "stdlib.h" +#include "utils.h" + +volatile i2s_t *const i2s[3] = +{ + (volatile i2s_t *)I2S0_BASE_ADDR, + (volatile i2s_t *)I2S1_BASE_ADDR, + (volatile i2s_t *)I2S2_BASE_ADDR +}; + +static int i2s_recv_channel_enable(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, uint32_t enable) +{ + rer_t u_rer; + + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + u_rer.reg_data = readl(&i2s[device_num]->channel[channel_num].rer); + u_rer.rer.rxchenx = enable; + writel(u_rer.reg_data, &i2s[device_num]->channel[channel_num].rer); + return 0; +} + +static int i2s_transmit_channel_enable(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, uint32_t enable) +{ + ter_t u_ter; + + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + u_ter.reg_data = readl(&i2s[device_num]->channel[channel_num].ter); + u_ter.ter.txchenx = enable; + writel(u_ter.reg_data, &i2s[device_num]->channel[channel_num].ter); + return 0; +} + +static void i2s_receive_enable(i2s_device_number_t device_num, i2s_channel_num_t channel_num) +{ + irer_t u_irer; + + u_irer.reg_data = readl(&i2s[device_num]->irer); + u_irer.irer.rxen = 1; + writel(u_irer.reg_data, &i2s[device_num]->irer); + /* Receiver block enable */ + + i2s_recv_channel_enable(device_num, channel_num, 1); + /* Receive channel enable */ +} + +static void i2s_transimit_enable(i2s_device_number_t device_num, i2s_channel_num_t channel_num) +{ + iter_t u_iter; + + u_iter.reg_data = readl(&i2s[device_num]->iter); + u_iter.iter.txen = 1; + writel(u_iter.reg_data, &i2s[device_num]->iter); + /* Transmitter block enable */ + + i2s_transmit_channel_enable(device_num, channel_num, 1); + /* Transmit channel enable */ +} + +static void i2s_set_enable(i2s_device_number_t device_num, uint32_t enable) +{ + ier_t u_ier; + + u_ier.reg_data = readl(&i2s[device_num]->ier); + u_ier.ier.ien = enable; + writel(u_ier.reg_data, &i2s[device_num]->ier); +} + +static void i2s_disable_block(i2s_device_number_t device_num, i2s_transmit_t rxtx_mode) +{ + irer_t u_irer; + iter_t u_iter; + + if (rxtx_mode == I2S_RECEIVER) + { + u_irer.reg_data = readl(&i2s[device_num]->irer); + u_irer.irer.rxen = 0; + writel(u_irer.reg_data, &i2s[device_num]->irer); + /* Receiver block disable */ + } + else + { + u_iter.reg_data = readl(&i2s[device_num]->iter); + u_iter.iter.txen = 0; + writel(u_iter.reg_data, &i2s[device_num]->iter); + /* Transmitter block disable */ + } +} + +static int i2s_set_rx_word_length(i2s_device_number_t device_num, + i2s_word_length_t word_length, + i2s_channel_num_t channel_num) +{ + rcr_tcr_t u_rcr; + + if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH) + return -1; + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + u_rcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rcr); + u_rcr.rcr_tcr.wlen = word_length; + writel(u_rcr.reg_data, &i2s[device_num]->channel[channel_num].rcr); + return 0; +} + +static int i2s_set_tx_word_length(i2s_device_number_t device_num, + i2s_word_length_t word_length, + i2s_channel_num_t channel_num) +{ + rcr_tcr_t u_tcr; + + if (word_length > RESOLUTION_32_BIT || word_length < IGNORE_WORD_LENGTH) + return -1; + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + u_tcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tcr); + u_tcr.rcr_tcr.wlen = word_length; + writel(u_tcr.reg_data, &i2s[device_num]->channel[channel_num].tcr); + return 0; +} + +static void i2s_master_configure(i2s_device_number_t device_num, + i2s_word_select_cycles_t word_select_size, + i2s_sclk_gating_cycles_t gating_cycles, + i2s_work_mode_t word_mode) +{ + configASSERT(!(word_select_size < SCLK_CYCLES_16 || + word_select_size > SCLK_CYCLES_32)); + configASSERT(!(gating_cycles < NO_CLOCK_GATING || + gating_cycles > CLOCK_CYCLES_24)); + + ccr_t u_ccr; + cer_t u_cer; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.clk_word_size = word_select_size; + u_ccr.ccr.clk_gate = gating_cycles; + u_ccr.ccr.align_mode = word_mode; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + u_cer.reg_data = readl(&i2s[device_num]->cer); + u_cer.cer.clken = 1; + writel(u_cer.reg_data, &i2s[device_num]->cer); + /* Clock generation enable */ + +} + +static int i2s_set_rx_threshold(i2s_device_number_t device_num, + i2s_fifo_threshold_t threshold, + i2s_channel_num_t channel_num) +{ + rfcr_t u_rfcr; + + if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16) + return -1; + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + u_rfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].rfcr); + u_rfcr.rfcr.rxchdt = threshold; + writel(u_rfcr.reg_data, &i2s[device_num]->channel[channel_num].rfcr); + + return 0; +} + +static int i2s_set_tx_threshold(i2s_device_number_t device_num, + i2s_fifo_threshold_t threshold, + i2s_channel_num_t channel_num) +{ + tfcr_t u_tfcr; + + if (threshold < TRIGGER_LEVEL_1 || threshold > TRIGGER_LEVEL_16) + return -1; + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + u_tfcr.reg_data = readl(&i2s[device_num]->channel[channel_num].tfcr); + u_tfcr.tfcr.txchet = threshold; + writel(u_tfcr.reg_data, &i2s[device_num]->channel[channel_num].tfcr); + return 0; +} + +static int i2s_set_mask_interrupt(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, + uint32_t rx_available_int, uint32_t rx_overrun_int, + uint32_t tx_empty_int, uint32_t tx_overrun_int) +{ + imr_t u_imr; + + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + u_imr.reg_data = readl(&i2s[device_num]->channel[channel_num].imr); + + if (rx_available_int == 1) + u_imr.imr.rxdam = 1; + else + u_imr.imr.rxdam = 0; + if (rx_overrun_int == 1) + u_imr.imr.rxfom = 1; + else + u_imr.imr.rxfom = 0; + + if (tx_empty_int == 1) + u_imr.imr.txfem = 1; + else + u_imr.imr.txfem = 0; + if (tx_overrun_int == 1) + u_imr.imr.txfom = 1; + else + u_imr.imr.txfom = 0; + writel(u_imr.reg_data, &i2s[device_num]->channel[channel_num].imr); + return 0; +} + +static int i2s_transmit_dma_enable(i2s_device_number_t device_num, uint32_t enable) +{ + ccr_t u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_tx_en = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +static int i2s_receive_dma_enable(i2s_device_number_t device_num, uint32_t enable) +{ + ccr_t u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_rx_en = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +static int i2s_transmit_dma_divide(i2s_device_number_t device_num, uint32_t enable) +{ + ccr_t u_ccr; + + if (device_num >= I2S_DEVICE_MAX) + return -1; + + u_ccr.reg_data = readl(&i2s[device_num]->ccr); + u_ccr.ccr.dma_divide_16 = enable; + writel(u_ccr.reg_data, &i2s[device_num]->ccr); + + return 0; +} + +int i2s_receive_data(i2s_device_number_t device_num, i2s_channel_num_t channel_num, uint64_t *buf, size_t buf_len) +{ + uint32_t i = 0; + isr_t u_isr; + + readl(&i2s[device_num]->channel[channel_num].ror); + /*clear over run*/ + + for (i = 0; i < buf_len;) + { + u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr); + if (u_isr.isr.rxda == 1) + { + buf[i] = readl(&i2s[device_num]->channel[channel_num].left_rxtx); + buf[i] <<= 32; + buf[i++] |= readl(&i2s[device_num]->channel[channel_num].right_rxtx); + } + } + return 0; +} + +void i2s_receive_data_dma(i2s_device_number_t device_num, uint32_t *buf, + size_t buf_len, dmac_channel_number_t channel_num) +{ + static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0}; + if(dmac_recv_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_recv_flag[channel_num] = 1; + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, (void *)(&i2s[device_num]->rxdma), buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len); +} + +int i2s_rx_to_tx(i2s_device_number_t device_src_num, i2s_device_number_t device_dest_num, + size_t buf_len, dmac_channel_number_t channel_num) +{ + static uint8_t dmac_recv_flag[6] = {0,0,0,0,0,0}; + if(dmac_recv_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_recv_flag[channel_num] = 1; + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_I2S0_RX_REQ + device_src_num * 2); + dmac_set_single_mode(channel_num, (void *)(&i2s[device_src_num]->rxdma), (void *)(&i2s[device_dest_num]->txdma), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len); + return 0; +} + +int i2s_send_data(i2s_device_number_t device_num, i2s_channel_num_t channel_num, const uint8_t *pcm, size_t buf_len, + size_t single_length) +{ + isr_t u_isr; + uint32_t left_buffer = 0; + uint32_t right_buffer = 0; + uint32_t i = 0; + uint32_t j = 0; + if (channel_num < I2S_CHANNEL_0 || channel_num > I2S_CHANNEL_3) + return -1; + + buf_len = buf_len / (single_length / 8) / 2; /* sample num */ + readl(&i2s[device_num]->channel[channel_num].tor); + /* read clear overrun flag */ + + for (j = 0; j < buf_len;) + { + u_isr.reg_data = readl(&i2s[device_num]->channel[channel_num].isr); + if (u_isr.isr.txfe == 1) + { + switch(single_length) + { + case 16: + left_buffer = ((uint16_t *)pcm)[i++]; + right_buffer = ((uint16_t *)pcm)[i++]; + break; + case 24: + left_buffer = 0; + left_buffer |= pcm[i++]; + left_buffer |= pcm[i++] << 8; + left_buffer |= pcm[i++] << 16; + right_buffer = 0; + right_buffer |= pcm[i++]; + right_buffer |= pcm[i++] << 8; + right_buffer |= pcm[i++] << 16; + break; + case 32: + left_buffer = ((uint32_t *)pcm)[i++]; + right_buffer = ((uint32_t *)pcm)[i++]; + break; + default: + left_buffer = pcm[i++]; + right_buffer = pcm[i++]; + break; + } + writel(left_buffer, &i2s[device_num]->channel[channel_num].left_rxtx); + writel(right_buffer, &i2s[device_num]->channel[channel_num].right_rxtx); + j++; + } + } + return 0; +} + +void i2s_send_data_dma(i2s_device_number_t device_num, const void *buf, size_t buf_len, dmac_channel_number_t channel_num) +{ + static uint8_t dmac_init_flag[6] = {0,0,0,0,0,0}; + if(dmac_init_flag[channel_num]) + dmac_wait_done(channel_num); + else + dmac_init_flag[channel_num] = 1; + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_I2S0_TX_REQ + device_num * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&i2s[device_num]->txdma), DMAC_ADDR_INCREMENT, + DMAC_ADDR_NOCHANGE, DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len); +} + +static void i2s_parse_voice(uint32_t *buf, const uint8_t *pcm, size_t length, size_t bits_per_sample, + uint8_t track_num, size_t *send_len) +{ + uint32_t i,j=0; + *send_len = length * 2; + switch(bits_per_sample) + { + case 16: + i2s_transmit_dma_divide(I2S_DEVICE_0, 1); + for(i = 0; i < length; i++) + { + buf[i] = ((uint16_t *)pcm)[i]; + } + *send_len = length; + break; + case 24: + for(i = 0; i < length; i++) + { + buf[2*i] = 0; + buf[2*i] |= pcm[j++]; + buf[2*i] |= pcm[j++] << 8; + buf[2*i] |= pcm[j++] << 16; + buf[2*i+1] = 0; + if(track_num == 2) + { + buf[2*i+1] |= pcm[j++]; + buf[2*i+1] |= pcm[j++] << 8; + buf[2*i+1] |= pcm[j++] << 16; + } + } + break; + case 32: + for(i = 0; i < length; i++) + { + buf[2*i] = ((uint32_t *)pcm)[i]; + buf[2*i+1] = 0; + } + break; + default: + break; + } +} + + +void i2s_play(i2s_device_number_t device_num, dmac_channel_number_t channel_num, + const uint8_t *buf, size_t buf_len, size_t frame, size_t bits_per_sample, uint8_t track_num) +{ + const uint8_t *trans_buf; + uint32_t i; + size_t sample_cnt = buf_len / ( bits_per_sample / 8 ) / track_num; + size_t frame_cnt = sample_cnt / frame; + size_t frame_remain = sample_cnt % frame; + + if (bits_per_sample == 16 && track_num == 2) + { + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num,trans_buf, frame, channel_num); + } + if(frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num, trans_buf, frame_remain, channel_num); + } + } + else if (bits_per_sample == 32 && track_num == 2) + { + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num,trans_buf, frame * 2, channel_num); + } + if(frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + i2s_send_data_dma(device_num, trans_buf, frame_remain * 2, channel_num); + } + } + else + { + uint32_t *buff[2]; + buff[0] = malloc(frame * 2 * sizeof(uint32_t) * 2); + buff[1] = buff[0] + frame * 2; + uint8_t flag = 0; + size_t send_len = 0; + for (i = 0; i < frame_cnt; i++) + { + trans_buf = buf + i * frame * (bits_per_sample / 8) * track_num; + i2s_parse_voice(buff[flag], trans_buf, frame, bits_per_sample, track_num, &send_len); + i2s_send_data_dma(device_num,buff[flag], send_len, channel_num); + flag = !flag; + } + if (frame_remain) + { + trans_buf = buf + frame_cnt * frame * (bits_per_sample / 8) * track_num; + i2s_parse_voice(buff[flag], trans_buf, frame_remain, bits_per_sample, track_num, &send_len); + i2s_send_data_dma(device_num, trans_buf, send_len, channel_num); + } + free(buff[0]); + } +} + +void i2s_rx_channel_config(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, + i2s_word_length_t word_length, + i2s_word_select_cycles_t word_select_size, + i2s_fifo_threshold_t trigger_level, + i2s_work_mode_t word_mode) +{ + i2s_recv_channel_enable(device_num, channel_num, 0); + /* Receive channel disable */ + + writel(0, &i2s[device_num]->channel[channel_num].ter); + /* disable tx */ + + writel(1, &i2s[device_num]->channel[channel_num].rff); + /* flash individual fifo */ + + writel(1, &i2s[device_num]->rxffr); + /* flush tx fifo*/ + + i2s_set_rx_word_length(device_num, word_length, channel_num); + /* Word buf_len is RESOLUTION_32_BIT */ + + i2s_master_configure(device_num, + word_select_size, NO_CLOCK_GATING, word_mode); + /* word select size is 32 bits,no clock gating */ + + i2s_set_rx_threshold(device_num, trigger_level, channel_num); + /* Interrupt trigger when FIFO level is 8 */ + + readl(&i2s[device_num]->channel[channel_num].ror); + readl(&i2s[device_num]->channel[channel_num].tor); + + i2s_recv_channel_enable(device_num, channel_num, 1); +} + +void i2s_tx_channel_config(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, + i2s_word_length_t word_length, + i2s_word_select_cycles_t word_select_size, + i2s_fifo_threshold_t trigger_level, + i2s_work_mode_t word_mode) +{ + writel(0, &i2s[device_num]->channel[channel_num].rer); + /* disable rx */ + + i2s_transmit_channel_enable(device_num, channel_num, 0); + /* Transmit channel disable */ + + writel(1, &i2s[device_num]->txffr); + /* flush tx fifo */ + writel(1, &i2s[device_num]->channel[channel_num].tff); + /* flush individual fifo */ + + if (word_length == RESOLUTION_16_BIT) + { + i2s_transmit_dma_divide(I2S_DEVICE_0, 1); + } + i2s_set_tx_word_length(device_num, word_length, channel_num); + /* Word buf_len is RESOLUTION_16_BIT */ + + i2s_master_configure(device_num, word_select_size, NO_CLOCK_GATING, word_mode); + /* word select size is 16 bits,gating after 16 bit */ + + i2s_set_tx_threshold(device_num, trigger_level, channel_num); + /* Interrupt trigger when FIFO level is 8 */ + + i2s_transmit_channel_enable(device_num, channel_num, 1); +} + + +void i2s_init(i2s_device_number_t device_num, i2s_transmit_t rxtx_mode, uint32_t channel_mask) +{ + sysctl_clock_enable(SYSCTL_CLOCK_I2S0 + device_num); + sysctl_reset(SYSCTL_RESET_I2S0 + device_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0 + device_num, 7); + /*96k:5,44k:12,24k:23,22k:25 16k:35 sampling*/ + /*sample rate*32bit*2 =75MHz/((N+1)*2) */ + i2s_set_enable(device_num, 1); + i2s_disable_block(device_num, I2S_TRANSMITTER); + i2s_disable_block(device_num, I2S_RECEIVER); + + if (rxtx_mode == I2S_TRANSMITTER) + { + for (int i=0; i<4; i++) + { + if ((channel_mask & 0x3) == 0x3) + { + i2s_set_mask_interrupt(device_num, I2S_CHANNEL_0 + i, 1, 1, 1, 1); + i2s_transimit_enable(device_num, I2S_CHANNEL_0 + i); + } + else + { + i2s_transmit_channel_enable(device_num, I2S_CHANNEL_0 + i, 0); + } + channel_mask >>= 2; + } + i2s_transmit_dma_enable(device_num, 1); + } + else + { + for (int i=0; i<4; i++) + { + if ((channel_mask & 0x3) == 0x3) + { + i2s_set_mask_interrupt(device_num, I2S_CHANNEL_0 + i, 1, 1, 1, 1); + i2s_receive_enable(device_num, I2S_CHANNEL_0 + i); + } + else + { + i2s_recv_channel_enable(device_num, I2S_CHANNEL_0 + i, 0); + } + channel_mask >>= 2; + } + i2s_receive_dma_enable(device_num, 1); + } +} + diff --git a/lib/drivers/include/aes.h b/lib/drivers/include/aes.h new file mode 100755 index 0000000..0cbac8e --- /dev/null +++ b/lib/drivers/include/aes.h @@ -0,0 +1,411 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_AES_H +#define _DRIVER_AES_H +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _aes_cipher_mode +{ + AES_ECB = 0, + AES_CBC = 1, + AES_GCM = 2, + AES_CIPHER_MAX, +} aes_cipher_mode_t; + +typedef enum _aes_kmode +{ + AES_128 = 16, + AES_192 = 24, + AES_256 = 32, +} aes_kmode_t; + +typedef enum _aes_iv_len +{ + IV_LEN_96 = 12, + IV_LEN_128 = 16, +} aes_iv_len_t; + +typedef enum _aes_encrypt_sel +{ + AES_HARD_ENCRYPTION = 0, + AES_HARD_DECRYPTION = 1, +} aes_encrypt_sel_t; + +typedef struct _aes_mode_ctl +{ + /* [2:0]:000:ecb; 001:cbc,010:gcm */ + uint32_t cipher_mode : 3; + /* [4:3]:00:aes-128; 01:aes-192; 10:aes-256;11:reserved*/ + uint32_t kmode : 2; + /* [6:5]:input key order 1:little endian; 0: big endian */ + uint32_t key_order : 2; + /* [8:7]:input data order 1:little endian; 0: big endian */ + uint32_t input_order : 2; + /* [10:9]:output data order 1:little endian; 0: big endian */ + uint32_t output_order : 2; + uint32_t reserved : 21; +} __attribute__((packed, aligned(4))) aes_mode_ctl_t; + +/** + * @brief AES + */ +typedef struct _aes +{ + /* (0x00) customer key.1st~4th byte key */ + uint32_t aes_key[4]; + /* (0x10) 0: encryption; 1: decryption */ + uint32_t encrypt_sel; + /* (0x14) aes mode reg */ + aes_mode_ctl_t mode_ctl; + /* (0x18) Initialisation Vector. GCM support 96bit. CBC support 128bit */ + uint32_t aes_iv[4]; + /* (0x28) input data endian;1:little endian; 0:big endian */ + uint32_t aes_endian; + /* (0x2c) calculate status. 1:finish; 0:not finish */ + uint32_t aes_finish; + /* (0x30) aes out data to dma 0:cpu 1:dma */ + uint32_t dma_sel; + /* (0x34) gcm Additional authenticated data number */ + uint32_t gb_aad_num; + uint32_t reserved; + /* (0x3c) aes plantext/ciphter text input data number */ + uint32_t gb_pc_num; + /* (0x40) aes plantext/ciphter text input data */ + uint32_t aes_text_data; + /* (0x44) Additional authenticated data */ + uint32_t aes_aad_data; + /** + * (0x48) [1:0],b'00:check not finish; b'01:check fail; b'10:check success; + * b'11:reversed + */ + uint32_t tag_chk; + /* (0x4c) data can input flag. 1: data can input; 0 : data cannot input */ + uint32_t data_in_flag; + /* (0x50) gcm input tag for compare with the calculate tag */ + uint32_t gcm_in_tag[4]; + /* (0x60) aes plantext/ciphter text output data */ + uint32_t aes_out_data; + /* (0x64) aes module enable */ + uint32_t gb_aes_en; + /* (0x68) data can output flag 1: data ready 0: data not ready */ + uint32_t data_out_flag; + /* (0x6c) allow tag input when use gcm */ + uint32_t tag_in_flag; + /* (0x70) clear tag_chk */ + uint32_t tag_clear; + uint32_t gcm_out_tag[4]; + /* (0x84) customer key for aes-192 aes-256.5th~8th byte key */ + uint32_t aes_key_ext[4]; +} __attribute__((packed, aligned(4))) aes_t; + +typedef struct _gcm_context +{ + /* The buffer holding the encryption or decryption key. */ + uint8_t *input_key; + /* The initialization vector. must be 96 bit */ + uint8_t *iv; + /* The buffer holding the Additional authenticated data. or NULL */ + uint8_t *gcm_aad; + /* The length of the Additional authenticated data. or 0L */ + size_t gcm_aad_len; +} gcm_context_t; + +typedef struct _cbc_context +{ + /* The buffer holding the encryption or decryption key. */ + uint8_t *input_key; + /* The initialization vector. must be 128 bit */ + uint8_t *iv; +} cbc_context_t; + +/** + * @brief AES-ECB-128 decryption + * + * @param[in] input_key The decryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb128_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-ECB-128 encryption + * + * @param[in] input_key The encryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb128_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-ECB-192 decryption + * + * @param[in] input_key The decryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb192_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-ECB-192 encryption + * + * @param[in] input_key The encryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb192_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-ECB-256 decryption + * + * @param[in] input_key The decryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb256_hard_decrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-ECB-256 encryption + * + * @param[in] input_key The encryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_ecb256_hard_encrypt(uint8_t *input_key, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-128 decryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc128_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-128 encryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc128_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-192 decryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc192_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-192 encryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc192_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-256 decryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc256_hard_decrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-CBC-256 encryption + * + * @param[in] context The cbc context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + */ +void aes_cbc256_hard_encrypt(cbc_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data); + +/** + * @brief AES-GCM-128 decryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm128_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief AES-GCM-128 encryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 16bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm128_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief AES-GCM-192 decryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm192_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief AES-GCM-192 encryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 24bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm192_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief AES-GCM-256 decryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The decryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm256_hard_decrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief AES-GCM-256 encryption + * + * @param[in] context The gcm context to use for encryption or decryption. + * @param[in] input_key The encryption key. must be 32bytes. + * @param[in] input_data The buffer holding the input data. + * @param[in] input_len The length of a data unit in bytes. + * This can be any length between 16 bytes and 2^31 bytes inclusive + * (between 1 and 2^27 block cipher blocks). + * @param[out] output_data The buffer holding the output data. + * @param[out] gcm_tag The buffer for holding the tag.The length of the tag must be 4 bytes. + */ +void aes_gcm256_hard_encrypt(gcm_context_t *context, uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag); + +/** + * @brief This function initializes the AES hard module. + * + * @param[in] input_key The buffer holding the encryption or decryption key. + * @param[in] input_key_len The length of the input_key.must be 16bytes || 24bytes || 32bytes. + * @param[in] iv The initialization vector. + * @param[in] iv_len The length of the iv.GCM must be 12bytes. CBC must be 16bytes. ECB set 0L. + * @param[in] gcm_aad The buffer holding the Additional authenticated data. or NULL + * @param[in] cipher_mode Cipher Modes.must be AES_CBC || AES_ECB || AES_GCM. + * Other cipher modes, please look forward to the next generation of kendryte. + * @param[in] encrypt_sel The operation to perform:encryption or decryption. + * @param[in] gcm_aad_len The length of the gcm_aad. + * @param[in] input_data_len The length of the input_data. + */ +void aes_init(uint8_t *input_key, size_t input_key_len, uint8_t *iv,size_t iv_len, uint8_t *gcm_aad, + aes_cipher_mode_t cipher_mode, aes_encrypt_sel_t encrypt_sel, size_t gcm_aad_len, size_t input_data_len); + +/** + * @brief This function feeds an input buffer into an encryption or decryption operation. + * + * @param[in] input_data The buffer holding the input data. + * @param[out] output_data The buffer holding the output data. + * @param[in] input_data_len The length of the input_data. + * @param[in] cipher_mode Cipher Modes.must be AES_CBC || AES_ECB || AES_GCM. + * Other cipher modes, please look forward to the next generation of kendryte. + */ +void aes_process(uint8_t *input_data, uint8_t *output_data, size_t input_data_len, aes_cipher_mode_t cipher_mode); + +/** + * @brief This function get the gcm tag to verify. + * + * @param[out] gcm_tag The buffer holding the gcm tag.The length of the tag must be 16bytes. + */ +void gcm_get_tag(uint8_t *gcm_tag); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_AES_H */ diff --git a/lib/drivers/include/clint.h b/lib/drivers/include/clint.h new file mode 100755 index 0000000..3e8b1b1 --- /dev/null +++ b/lib/drivers/include/clint.h @@ -0,0 +1,338 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +/** + * @file + * @brief The CLINT block holds memory-mapped control and status registers + * associated with local interrupts for a Coreplex. + * + * @note CLINT RAM Layout + * + * | Address -| Description | + * |------------|---------------------------------| + * | 0x02000000 | msip for core 0 | + * | 0x02000004 | msip for core 1 | + * | ... | ... | + * | 0x02003FF8 | msip for core 4094 | + * | | | + * | 0x02004000 | mtimecmp for core 0 | + * | 0x02004008 | mtimecmp for core 1 | + * | ... | ... | + * | 0x0200BFF0 | mtimecmp For core 4094 | + * | 0x0200BFF8 | mtime | + * | | | + * | 0x0200C000 | Reserved | + * | ... | ... | + * | 0x0200EFFC | Reserved | + */ + +#ifndef _DRIVER_CLINT_H +#define _DRIVER_CLINT_H + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define CLINT_MSIP (0x0000) +#define CLINT_MSIP_SIZE (0x4) +#define CLINT_MTIMECMP (0x4000) +#define CLINT_MTIMECMP_SIZE (0x8) +#define CLINT_MTIME (0xBFF8) +#define CLINT_MTIME_SIZE (0x8) +/* Max number of cores */ +#define CLINT_MAX_CORES (4095) +/* Real number of cores */ +#define CLINT_NUM_CORES (2) +/* Clock frequency division factor */ +#define CLINT_CLOCK_DIV (50) +/* clang-format on */ + +/** + * @brief MSIP Registers + * + * Machine-mode software interrupts are generated by writing to a + * per-core memory-mapped control register. The msip registers are + * 32-bit wide WARL registers, where the LSB is reflected in the + * msip bit of the associated core’s mip register. Other bits in + * the msip registers are hardwired to zero. The mapping supports + * up to 4095 machine-mode cores. + */ +typedef struct _clint_msip +{ + uint32_t msip : 1; /*!< Bit 0 is msip */ + uint32_t zero : 31; /*!< Bits [32:1] is 0 */ +} __attribute__((packed, aligned(4))) clint_msip_t; + +/** + * @brief Timer compare Registers Machine-mode timer interrupts are + * generated by a real-time counter and a per-core comparator. The + * mtime register is a 64-bit read-only register that contains the + * current value of the real-time counter. Each mtimecmp register + * holds its core’s time comparator. A timer interrupt is pending + * whenever mtime is greater than or equal to the value in a + * core’s mtimecmp register. The timer interrupt is reflected in + * the mtip bit of the associated core’s mip register. + */ +typedef uint64_t clint_mtimecmp_t; + +/** + * @brief Timer Registers + * + * The mtime register has a 64-bit precision on all RV32, RV64, + * and RV128 systems. Platforms provide a 64-bit memory-mapped + * machine-mode timer compare register (mtimecmp), which causes a + * timer interrupt to be posted when the mtime register contains a + * value greater than or equal to the value in the mtimecmp + * register. The interrupt remains posted until it is cleared by + * writing the mtimecmp register. The interrupt will only be taken + * if interrupts are enabled and the MTIE bit is set in the mie + * register. + */ +typedef uint64_t clint_mtime_t; + +/** + * @brief CLINT object + * + * Coreplex-Local INTerrupts, which includes software interrupts, + * local timer interrupts, and other interrupts routed directly to + * a core. + */ +typedef struct _clint +{ + /* 0x0000 to 0x3FF8, MSIP Registers */ + clint_msip_t msip[CLINT_MAX_CORES]; + /* Resverd space, do not use */ + uint32_t resv0; + /* 0x4000 to 0xBFF0, Timer Compare Registers */ + clint_mtimecmp_t mtimecmp[CLINT_MAX_CORES]; + /* 0xBFF8, Time Register */ + clint_mtime_t mtime; +} __attribute__((packed, aligned(4))) clint_t; + +/** + * @brief Clint object instanse + */ +extern volatile clint_t* const clint; + +/** + * @brief Definitions for the timer callbacks + */ +typedef int (*clint_timer_callback_t)(void *ctx); + +/** + * @brief Definitions for local interprocessor interrupt callbacks + */ +typedef int (*clint_ipi_callback_t)(void *ctx); + +typedef struct _clint_timer_instance +{ + uint64_t interval; + uint64_t cycles; + uint64_t single_shot; + clint_timer_callback_t callback; + void *ctx; +} clint_timer_instance_t; + +typedef struct _clint_ipi_instance +{ + clint_ipi_callback_t callback; + void *ctx; +} clint_ipi_instance_t; + +/** + * @brief Get the time form CLINT timer register + * + * @note The CLINT must init to get right time + * + * @return 64bit Time + */ +uint64_t clint_get_time(void); + +/** + * @brief Init the CLINT timer + * + * @note MIP_MTIP will be clear after init. The MSTATUS_MIE must set by + * user. + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_init(void); + +/** + * @brief Stop the CLINT timer + * + * @note MIP_MTIP will be clear after stop + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_stop(void); + +/** + * @brief Start the CLINT timer + * + * @param[in] interval The interval with Millisecond(ms) + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_start(uint64_t interval, int single_shot); + +/** + * @brief Get the interval of timer + * + * @return The interval with Millisecond(ms) + */ +uint64_t clint_timer_get_interval(void); + +/** + * @brief Set the interval with Millisecond(ms) + * + * @param[in] interval The interval with Millisecond(ms) + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_interval(uint64_t interval); + +/** + * @brief Get whether the timer is a single shot timer + * + * @return result + * - 0 It is a repeat timer + * - 1 It is a single shot timer + */ +int clint_timer_get_single_shot(void); + +/** + * @brief Set the timer working as a single shot timer or repeat timer + * + * @param[in] single_shot Single shot or repeat + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_set_single_shot(int single_shot); + +/** + * @brief Set user callback function when timer is timeout + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_register(clint_timer_callback_t callback, void *ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_timer_deregister(void); + +/** + * @brief Initialize local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_init(void); + +/** + * @brief Enable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_enable(void); + +/** + * @brief Disable local interprocessor interrupt + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_disable(void); + +/** + * @brief Send local interprocessor interrupt to core by core id + * + * @param[in] core_id The core identifier + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_send(size_t core_id); + +/** + * @brief Clear local interprocessor interrupt + * + * @param[in] core_id The core identifier + * + * @return result + * - 1 An IPI was pending + * - 0 Non IPI was pending + * - -1 Fail + */ +int clint_ipi_clear(size_t core_id); + +/** + * @brief Set user callback function when interprocessor interrupt + * + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_register(clint_ipi_callback_t callback, void *ctx); + +/** + * @brief Deregister user callback function + * + * @return result + * - 0 Success + * - Other Fail + */ +int clint_ipi_deregister(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_CLINT_H */ + diff --git a/lib/drivers/include/dmac.h b/lib/drivers/include/dmac.h new file mode 100755 index 0000000..e54171c --- /dev/null +++ b/lib/drivers/include/dmac.h @@ -0,0 +1,1439 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_DMAC_H +#define _DRIVER_DMAC_H + +#include +#include "io.h" +#include "platform.h" +#include "stdbool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* DMAC */ +#define DMAC_CHANNEL_COUNT (DMAC_CHANNEL_MAX) +#define LAST_ROW (-1) + +typedef enum _dmac_channel_number +{ + DMAC_CHANNEL0 = 0, + DMAC_CHANNEL1 = 1, + DMAC_CHANNEL2 = 2, + DMAC_CHANNEL3 = 3, + DMAC_CHANNEL4 = 4, + DMAC_CHANNEL5 = 5, + DMAC_CHANNEL_MAX +} dmac_channel_number_t; + +typedef enum _dmac_src_dst_select +{ + DMAC_SRC = 0x1, + DMAC_DST = 0x2, + DMAC_SRC_DST = 0x3 +} dmac_src_dst_select_t; + +typedef enum _state_value +{ + clear = 0, + set = 1 +} state_value_t; + +typedef enum _dmac_lock_bus_ch +{ + DMAC_LOCK_BUS = 0x1, + DMAC_LOCK_CHANNEL = 0x2, + DMAC_LOCK_BUS_CH = 0x3 +} dmac_lock_bus_ch_t; + +typedef enum _dmac_sw_hw_hs_select +{ + DMAC_HS_HARDWARE = 0x0, + DMAC_HS_SOFTWARE = 0x1 +} dmac_sw_hw_hs_select_t; + +typedef enum _dmac_scatter_gather_param +{ + DMAC_SG_COUNT = 0x0, + DMAC_SG_INTERVAL = 0x1 +} dmac_scatter_gather_param_t; + +typedef enum _dmac_irq +{ + /* no interrupts */ + DMAC_IRQ_NONE = 0x00, + /* transfer complete */ + DMAC_IRQ_TFR = 0x01, + /* block transfer complete */ + DMAC_IRQ_BLOCK = 0x02, + /* source transaction complete */ + DMAC_IRQ_SRCTRAN = 0x04, + /* destination transaction complete */ + DMAC_IRQ_DSTTRAN = 0x08, + /* error */ + DMAC_IRQ_ERR = 0x10, + /* all interrupts */ + DMAC_IRQ_ALL = 0x1f +} dmac_irq_t; + +typedef enum _dmac_software_req +{ + /* ReqSrcReq/ReqDstReq */ + DMAC_REQUEST = 0x1, + /* SglReqSrcReq/SglReqDstReq */ + DMAC_SINGLE_REQUEST = 0x2, + /* LstReqSrcReq/LstReqDstReq */ + DMAC_LAST_REQUEST = 0x4 +} dmac_software_req_t; + +typedef enum _dmac_master_number +{ + DMAC_MASTER1 = 0x0, + DMAC_MASTER2 = 0x1 +} dmac_master_number_t; + +typedef enum _dmac_transfer_flow +{ + /* mem to mem - DMAC flow ctlr */ + DMAC_MEM2MEM_DMA = 0x0, + /* mem to prf - DMAC flow ctlr */ + DMAC_MEM2PRF_DMA = 0x1, + /* prf to mem - DMAC flow ctlr */ + DMAC_PRF2MEM_DMA = 0x2, + /* prf to prf - DMAC flow ctlr */ + DMAC_PRF2PRF_DMA = 0x3, + /* prf to mem - periph flow ctlr */ + DMAC_PRF2MEM_PRF = 0x4, + /* prf to prf - source flow ctlr */ + DMAC_PRF2PRF_SRCPRF = 0x5, + /* mem to prf - periph flow ctlr */ + DMAC_MEM2PRF_PRF = 0x6, + /* prf to prf - dest flow ctlr */ + DMAC_PRF2PRF_DSTPRF = 0x7 +} dmac_transfer_flow_t; + +typedef enum _dmac_burst_trans_length +{ + DMAC_MSIZE_1 = 0x0, + DMAC_MSIZE_4 = 0x1, + DMAC_MSIZE_8 = 0x2, + DMAC_MSIZE_16 = 0x3, + DMAC_MSIZE_32 = 0x4, + DMAC_MSIZE_64 = 0x5, + DMAC_MSIZE_128 = 0x6, + DMAC_MSIZE_256 = 0x7 +} dmac_burst_trans_length_t; + +typedef enum _dmac_address_increment +{ + DMAC_ADDR_INCREMENT = 0x0, + DMAC_ADDR_NOCHANGE = 0x1 +} dmac_address_increment_t; + +typedef enum _dmac_transfer_width +{ + DMAC_TRANS_WIDTH_8 = 0x0, + DMAC_TRANS_WIDTH_16 = 0x1, + DMAC_TRANS_WIDTH_32 = 0x2, + DMAC_TRANS_WIDTH_64 = 0x3, + DMAC_TRANS_WIDTH_128 = 0x4, + DMAC_TRANS_WIDTH_256 = 0x5 +} dmac_transfer_width_t; + +typedef enum _dmac_hs_interface +{ + DMAC_HS_IF0 = 0x0, + DMAC_HS_IF1 = 0x1, + DMAC_HS_IF2 = 0x2, + DMAC_HS_IF3 = 0x3, + DMAC_HS_IF4 = 0x4, + DMAC_HS_IF5 = 0x5, + DMAC_HS_IF6 = 0x6, + DMAC_HS_IF7 = 0x7, + DMAC_HS_IF8 = 0x8, + DMAC_HS_IF9 = 0x9, + DMAC_HS_IF10 = 0xa, + DMAC_HS_IF11 = 0xb, + DMAC_HS_IF12 = 0xc, + DMAC_HS_IF13 = 0xd, + DMAC_HS_IF14 = 0xe, + DMAC_HS_IF15 = 0xf +} dmac_hs_interface_t; + +typedef enum _dmac_multiblk_transfer_type +{ + CONTIGUOUS = 0, + RELOAD = 1, + SHADOWREGISTER = 2, + LINKEDLIST = 3 +} dmac_multiblk_transfer_type_t; + +typedef enum _dmac_multiblk_type +{ + DMAC_SRC_DST_CONTINUE = 0, + DMAC_SRC_CONTINUE_DST_RELAOD = 2, + DMAC_SRC_CONTINUE_DST_LINKEDLIST = 3, + DMAC_SRC_RELOAD_DST_CONTINUE = 4, + DMAC_SRC_RELOAD_DST_RELOAD = 5, + DMAC_SRC_RELOAD_DST_LINKEDLIST = 6, + DMAC_SRC_LINKEDLIST_DST_CONTINUE = 7, + DMAC_SRC_LINKEDLIST_DST_RELOAD = 8, + DMAC_SRC_LINKEDLIST_DST_LINKEDLIST = 9, + DMAC_SRC_SHADOWREG_DST_CONTINUE = 10 +} dmac_multiblk_type_t; + +typedef enum _dmac_transfer_type +{ + DMAC_TRANSFER_ROW1 = 0x1, + DMAC_TRANSFER_ROW2 = 0x2, + DMAC_TRANSFER_ROW3 = 0x3, + DMAC_TRANSFER_ROW4 = 0x4, + DMAC_TRANSFER_ROW5 = 0x5, + DMAC_TRANSFER_ROW6 = 0x6, + DMAC_TRANSFER_ROW7 = 0x7, + DMAC_TRANSFER_ROW8 = 0x8, + DMAC_TRANSFER_ROW9 = 0x9, + DMAC_TRANSFER_ROW10 = 0xa +} dmac_transfer_type_t; + +typedef enum _dmac_prot_level +{ + /* default prot level */ + DMAC_NONCACHE_NONBUFF_NONPRIV_OPCODE = 0x0, + DMAC_NONCACHE_NONBUFF_NONPRIV_DATA = 0x1, + DMAC_NONCACHE_NONBUFF_PRIV_OPCODE = 0x2, + DMAC_NONCACHE_NONBUFF_PRIV_DATA = 0x3, + DMAC_NONCACHE_BUFF_NONPRIV_OPCODE = 0x4, + DMAC_NONCACHE_BUFF_NONPRIV_DATA = 0x5, + DMAC_NONCACHE_BUFF_PRIV_OPCODE = 0x6, + DMAC_NONCACHE_BUFF_PRIV_DATA = 0x7, + DMAC_CACHE_NONBUFF_NONPRIV_OPCODE = 0x8, + DMAC_CACHE_NONBUFF_NONPRIV_DATA = 0x9, + DMAC_CACHE_NONBUFF_PRIV_OPCODE = 0xa, + DMAC_CACHE_NONBUFF_PRIV_DATA = 0xb, + DMAC_CACHE_BUFF_NONPRIV_OPCODE = 0xc, + DMAC_CACHE_BUFF_NONPRIV_DATA = 0xd, + DMAC_CACHE_BUFF_PRIV_OPCODE = 0xe, + DMAC_CACHE_BUFF_PRIV_DATA = 0xf +} dmac_prot_level_t; + +typedef enum _dmac_fifo_mode +{ + DMAC_FIFO_MODE_SINGLE = 0x0, + DMAC_FIFO_MODE_HALF = 0x1 +} dmac_fifo_mode_t; + +typedef enum _dw_dmac_flow_ctl_mode +{ + DMAC_DATA_PREFETCH_ENABLED = 0x0, + DMAC_DATA_PREFETCH_DISABLED = 0x1 +} dw_dmac_flow_ctl_mode_t; + +typedef enum _dmac_polarity_level +{ + DMAC_ACTIVE_HIGH = 0x0, + DMAC_ACTIVE_LOW = 0x1 +} dmac_polarity_level_t; + +typedef enum _dmac_lock_level +{ + DMAC_LOCK_LEVEL_DMA_TRANSFER = 0x0, + DMAC_LOCK_LEVEL_BLOCK_TRANSFER = 0x1, + DMAC_LOCK_LEVEL_TRANSACTION = 0x2 +} dmac_lock_level_t; + +typedef enum _dmac_channel_priority +{ + DMAC_PRIORITY_0 = 0x0, + DMAC_PRIORITY_1 = 0x1, + DMAC_PRIORITY_2 = 0x2, + DMAC_PRIORITY_3 = 0x3, + DMAC_PRIORITY_4 = 0x4, + DMAC_PRIORITY_5 = 0x5, + DMAC_PRIORITY_6 = 0x6, + DMAC_PRIORITY_7 = 0x7 +} dmac_channel_priority_t; + +typedef enum _dmac_state +{ + ZERO, + ONE +} dmac_state_t; + +typedef enum _dmac_common_int +{ + SLVIF_COMMON_DEC_ERR = 0, + SLVIF_COMMON_WR2RO_ERR = 1, + SLVIF_COMMON_RD2WO_ERR = 2, + SLVIF_COMMON__WRONHOLD_ERR = 3, + SLVIF_UNDEFINED_DEC_ERR = 4, + SLVIF_ALL_INT = 5 +} dmac_common_int_t; + +typedef struct _dmac_cfg +{ + /** + * Bit 0 is used to enable dmac + * 0x1 for enable, 0x0 for disable + */ + uint64_t dmac_en : 1; + /** + * Bit 1 is used to glabally enable interrupt generation + * 0x1 for enable interrupt, 0x0 for disable interrupt + */ + uint64_t int_en : 1; + /* Bits [63:2] is reserved */ + uint64_t rsvd : 62; +} __attribute__((packed, aligned(8))) dmac_cfg_t; + +typedef union _dmac_cfg_u +{ + dmac_cfg_t cfg; + uint64_t data; +} dmac_cfg_u_t; + +typedef struct _damc_chen +{ + /** + * Bit 0 is used to enable channel 1 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en : 1; + /** + * Bit 1 is used to enable channel 2 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en : 1; + /** + * Bit 2 is used to enable channel 3 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en : 1; + /** + * Bit 3 is used to enable channel 4 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en : 1; + /** + * Bit 4 is used to enable channel 5 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en : 1; + /** + * Bit 5 is used to enable channel 6 + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en : 1; + /* Bits [7:6] is reserved */ + uint64_t rsvd1 : 2; + /** + * Bit 8 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch1_en_we : 1; + /** + * Bit 9 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch2_en_we : 1; + /** + * Bit 10 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch3_en_we : 1; + /** + * Bit 11 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch4_en_we : 1; + /** + * Bit 12 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch5_en_we : 1; + /** + * Bit 13 is write enable bit + * 0x1 for enable, 0x0 for disable + */ + uint64_t ch6_en_we : 1; + /* Bits [15:14] is reserved */ + uint64_t rsvd2 : 2; + /** + * Bit 16 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch1_susp : 1; + /** + * Bit 17 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch2_susp : 1; + /* Bit 18 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch3_susp : 1; + /** + * Bit 19 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch4_susp : 1; + /** + * Bit 20 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch5_susp : 1; + /** + * Bit 21 is susped reuest + * 0x1 for request channel suspend + * 0x0 for no channel suspend request + */ + uint64_t ch6_susp : 1; + /* Bits [23:22] is reserved */ + uint64_t rsvd3 : 2; + /** + * Bit 24 is write enable to the channel suspend bit + * 0x1 for enable write to CH1_SUSP bit + * 0x0 for disable write to CH1_SUSP bit + */ + uint64_t ch1_susp_we : 1; + /** + * Bit 25 is write enable to the channel suspend bit + * 0x1 for enable write to CH2_SUSP bit + * 0x0 for disable write to CH2_SUSP bit + */ + uint64_t ch2_susp_we : 1; + /** + * Bit 26 is write enable to the channel suspend bit + * 0x1 for enable write to CH3_SUSP bit + * 0x0 for disable write to CH3_SUSP bit + */ + uint64_t ch3_susp_we : 1; + /** + * Bit 27 is write enable to the channel suspend bit + * 0x1 for enable write to CH4_SUSP bit + * 0x0 for disable write to CH4_SUSP bit + */ + uint64_t ch4_susp_we : 1; + /** + * Bit 28 is write enable to the channel suspend bit + * 0x1 for enable write to CH5_SUSP bit + * 0x0 for disable write to CH5_SUSP bit + */ + uint64_t ch5_susp_we : 1; + /** + * Bit 29 is write enable to the channel suspend bit + * 0x1 for enable write to CH6_SUSP bit + * 0x0 for disable write to CH6_SUSP bit + */ + uint64_t ch6_susp_we : 1; + /* Bits [31:30] is reserved */ + uint64_t rsvd4 : 2; + /** + * Bit 32 is channel-1 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch1_abort : 1; + /** + * Bit 33 is channel-2 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch2_abort : 1; + /** + * Bit 34 is channel-3 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch3_abort : 1; + /** + * Bit 35 is channel-4 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch4_abort : 1; + /** + * Bit 36 is channel-5 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch5_abort : 1; + /** + * Bit 37 is channel-6 abort requst bit + * 0x1 for request for channnel abort + * 0x0 for no channel abort request + */ + uint64_t ch6_abort : 1; + /* Bits [39:38] is reserved */ + uint64_t rsvd5 : 2; + /** + * Bit 40 is ued to write enable channel-1 abort bit + * 0x1 for enable write to CH1_ABORT bit + * 0x0 for disable write to CH1_ABORT bit + */ + uint64_t ch1_abort_we : 1; + /** + * Bit 41 is ued to write enable channel-2 abort bit + * 0x1 for enable write to CH2_ABORT bit + * 0x0 for disable write to CH2_ABORT bit + */ + uint64_t ch2_abort_we : 1; + /** + * Bit 42 is ued to write enable channel-3 abort bit + * 0x1 for enable write to CH3_ABORT bit + * 0x0 for disable write to CH3_ABORT bit + */ + uint64_t ch3_abort_we : 1; + /** + * Bit 43 is ued to write enable channel-4 abort bit + * 0x1 for enable write to CH4_ABORT bit + * 0x0 for disable write to CH4_ABORT bit + */ + uint64_t ch4_abort_we : 1; + /** + * Bit 44 is ued to write enable channel-5 abort bit + * 0x1 for enable write to CH5_ABORT bit + * 0x0 for disable write to CH5_ABORT bit + */ + uint64_t ch5_abort_we : 1; + /** + * Bit 45 is ued to write enable channel-6 abort bit + * 0x1 for enable write to CH6_ABORT bit + * 0x0 for disable write to CH6_ABORT bit + */ + uint64_t ch6_abort_we : 1; + /* Bits [47:46] is reserved */ + uint64_t rsvd6 : 2; + /* Bits [63:48] is reserved */ + uint64_t rsvd7 : 16; +} __attribute__((packed, aligned(8))) damc_chen_t; + +typedef union _dmac_chen_u +{ + damc_chen_t dmac_chen; + uint64_t data; +} dmac_chen_u_t; + +typedef struct _dmac_intstatus +{ + /** + * Bit 0 is channel 1 interrupt bit + * 0x1 for channel 1 interrupt active + * 0x0 for channel 1 interrupt inactive + */ + uint64_t ch1_intstat : 1; + /** + * Bit 1 is channel 1 interrupt bit + * 0x1 for channel 2 interrupt active + * 0x0 for channel 2 interrupt inactive + */ + uint64_t ch2_intstat : 1; + /** + * Bit 2 is channel 3 interrupt bit + * 0x1 for channel 3 interrupt active + * 0x0 for channel 3 interrupt inactive + */ + uint64_t ch3_intstat : 1; + /** + * Bit 3 is channel 4 interrupt bit + * 0x1 for channel 4 interrupt active + * 0x0 for channel 4 interrupt inactive + */ + uint64_t ch4_intstat : 1; + /** + * Bit 4 is channel 5 interrupt bit + * 0x1 for channel 5 interrupt active + * 0x0 for channel 5 interrupt inactive + */ + uint64_t ch5_intstat : 1; + /** + * Bit 5 is channel 6 interrupt bit + * 0x1 for channel 6 interrupt active + * 0x0 for channel 6 interrupt inactive + */ + uint64_t ch6_intstat : 1; + /* Bits [15:6] is reserved */ + uint64_t rsvd1 : 10; + /** + * Bit 16 is commom register status bit + * 0x1 for common register interrupt is active + * 0x0 for common register interrupt inactive + */ + uint64_t commonreg_intstat : 1; + /* Bits [63:17] is reserved */ + uint64_t rsvd2 : 47; +} __attribute__((packed, aligned(8))) dmac_intstatus_t; + +typedef union _dmac_intstatus_u +{ + dmac_intstatus_t intstatus; + uint64_t data; +} dmac_intstatus_u_t; + +typedef struct _dmac_commonreg_intclear +{ + /** + * Bit 0 is slave nterface Common Register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_DEC_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t cear_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write + * to Read only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_WR2RO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt clear Bit + * x01 for clear SLVIF_CommonReg_RD2WO_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write + * On Hold Error Interrupt clear Bit + * x01 for clear SSLVIF_CommonReg_WrOnHold_ERR interrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register + * Decode Error Interrupt clear Bit + * x01 for clear SLVIF_UndefinedReg_DEC_ERRinterrupt + * in DMAC_COMMONREG_INTSTATUSREG + * 0x0 for inactive signal + */ + uint64_t clear_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intclear_t; + +typedef union _dmac_commonreg_intclear_u +{ + dmac_commonreg_intclear_t com_intclear; + uint64_t data; +} dmac_commonreg_intclear_u_t; + +typedef struct _dmac_commonreg_intstatus_enable +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat bit disable + */ + uint64_t enable_slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wr2ro_err_intstat : 1; + /*!< + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold + * Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat bit disable + */ + uint64_t enable_slvif_wronhold_err_intstat : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Status enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat bit enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_enable_t; + +typedef union _dmac_commonreg_intstatus_enable_u +{ + dmac_commonreg_intstatus_enable_t intstatus_enable; + uint64_t data; +} dmac_commonreg_intstatus_enable_u_t; + +typedef struct _dmac_commonreg_intsignal_enable +{ + /** + * Bit 0 is Slave Interface Common Register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_dec_err_intsignal : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read only + * Error Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WR2RO_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wr2ro_err_intsignal : 1; + /** + * Bit 2 is Slave Interface Common Register Read to + * Write only Error Interrupt Status Enable Bit + * 0x1 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit enable + * 0x0 for SLVIF_CommonReg_RD2WO_ERR_IntStat bit disable + */ + uint64_t enable_slvif_rd2wo_err_intsignal : 1; + /** + * Bit 3 is Slave Interface Common Register Write On Hold Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal enable + * 0x0 for SLVIF_CommonReg_WrOnHold_ERR_IntStat signal disable + */ + uint64_t enable_slvif_wronhold_err_intsignal : 1; + /* Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode Error + * Interrupt Signal Enable Bit + * 0x1 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal enable + * 0x0 for SLVIF_UndefinedReg_DEC_ERR_IntStat signal disable + */ + uint64_t enable_slvif_undefinedreg_dec_err_intsignal : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intsignal_enable_t; + +typedef union _dmac_commonreg_intsignal_enable_u +{ + dmac_commonreg_intsignal_enable_t intsignal_enable; + uint64_t data; +} dmac_commonreg_intsignal_enable_u_t; + +typedef struct _dmac_commonreg_intstatus +{ + /** + * Bit 0 is Slave Interface Common Register Decode + * Error Interrupt Status Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_dec_err_intstat : 1; + /** + * Bit 1 is Slave Interface Common Register Write to Read Only + * Error Interrupt Status bit + * 0x1 for Slave Interface Write to Read Only Error detected + * 0x0 No Slave Interface Write to Read Only Errors + */ + uint64_t slvif_wr2ro_err_intstat : 1; + /** + * Bit 2 is Slave Interface Common Register Read to Write + * only Error Interrupt Status bit + * 0x1 for Slave Interface Read to Write Only Error detected + * 0x0 for No Slave Interface Read to Write Only Errors + */ + uint64_t slvif_rd2wo_err_intstat : 1; + /** + * Bit 3 is Slave Interface Common Register Write On + * Hold Error Interrupt Status Bit + * 0x1 for Slave Interface Common Register Write On Hold Error detected + * 0x0 for No Slave Interface Common Register Write On Hold Errors + */ + uint64_t slvif_wronhold_err_intstat : 1; + /*!< Bits [7:4] is reserved */ + uint64_t rsvd1 : 4; + /** + * Bit 8 is Slave Interface Undefined register Decode + * Error Interrupt Signal Enable Bit + * 0x1 for Slave Interface Decode Error detected + * 0x0 for No Slave Interface Decode Errors + */ + uint64_t slvif_undefinedreg_dec_err_intstat : 1; + /* Bits [63:9] is reserved */ + uint64_t rsvd2 : 55; +} __attribute__((packed, aligned(8))) dmac_commonreg_intstatus_t; + +typedef union _dmac_commonreg_intstatus_u +{ + dmac_commonreg_intstatus_t commonreg_intstatus; + uint64_t data; +} dmac_commonreg_intstatus_u_t; + +typedef struct _dmac_reset +{ + /* Bit 0 is DMAC reset request bit */ + uint64_t rst : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))) dmac_reset_t; + +typedef union _dmac_reset_u +{ + dmac_reset_t reset; + uint64_t data; +} dmac_reset_u_t; + +typedef struct _dmac_ch_block_ts +{ + uint64_t block_ts : 22; + /*!< Bit [21:0] is block transfer size*/ + uint64_t rsvd : 42; + /*!< Bits [63:22] is reserved */ +} __attribute__((packed, aligned(8))) dmac_ch_block_ts_t; + +typedef union _dmac_ch_block_ts_u +{ + dmac_ch_block_ts_t block_ts; + uint64_t data; +} dmac_ch_block_ts_u_t; + +typedef struct _dmac_ch_ctl +{ + /** + * Bit 0 is source master select + * 1 for AXI master 2, 0 for AXI master 1 + */ + uint64_t sms : 1; + /* Bit 1 is reserved */ + uint64_t rsvd1 : 1; + /** + * Bit 2 is destination master select + * 0x1 for AXI master 2,0x0 for AXI master 1 + */ + uint64_t dms : 1; + /* Bit 3 is reserved */ + uint64_t rsvd2 : 1; + /** + * Bit 4 is source address increment + * 0x1 for no change, 0x0 for incremnet + */ + uint64_t sinc : 1; + /** + * Bit 5 is reserved + */ + uint64_t rsvd3 : 1; + /** + * Bit 6 is destination address incremnet + * 0x1 for no change, 0x0 for increment + */ + uint64_t dinc : 1; + /* Bit 7 is reserved*/ + uint64_t rsvd4 : 1; + /** + * Bits [10:8] is source transfer width + * 0x0 for source transfer width is 8 bits + * 0x1 for source transfer width is 16 bits + * 0x2 for source transfer width is 32 bits + * 0x3 for source transfer width is 64 bits + * 0x4 for source transfer width is 128 bits + * 0x5 for source transfer width is 256 bits + * 0x6 for source transfer width is 512 bits + */ + uint64_t src_tr_width : 3; + /** + * Bits [13:11] is detination transfer width + * 0x0 for detination transfer width is 8 bits + * 0x1 for detination transfer width is 16 bits + * 0x2 for detination transfer width is 32 bits + * 0x3 for detination transfer width is 64 bits + * 0x4 for detination transfer width is 128 bits + * 0x5 for detination transfer width is 256 bits + * 0x6 for detination transfer width is 512 bits + */ + uint64_t dst_tr_width : 3; + /** + * Bits [17:14] is source burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t src_msize : 4; + /** + * Bits [17:14] is sdestination burst transaction length + * 0x0 for 1 data item read from rource in the burst transaction + * 0x1 for 4 data item read from rource in the burst transaction + * 0x2 for 8 data item read from rource in the burst transaction + * 0x3 for 16 data item read from rource in the burst transaction + * 0x4 for 32 data item read from rource in the burst transaction + * 0x5 for 64 data item read from rource in the burst transaction + * 0x6 for 128 data item read from rource in the burst transaction + * 0x7 for 256 data item read from rource in the burst transaction + * 0x8 for 512 data item read from rource in the burst transaction + * 0x9 for 1024 data item read from rource in the burst transaction + */ + uint64_t dst_msize : 4; + /** + * Bits [25:22] is reserved + */ + uint64_t rsvd5 : 4; + /*!< Bits [29:26] is reserved */ + uint64_t rsvd6 : 4; + /** + * Bit 30 is Non Posted Last Write Enable + * 0x1 for posted writes may be used till the end of the block + * 0x 0 for posted writes may be used throughout the block transfer + */ + uint64_t nonposted_lastwrite_en : 1; + /* Bit 31 is resrved */ + uint64_t rsvd7 : 1; + /* Bits [34:32] is reserved*/ + uint64_t rsvd8 : 3; + /* Bits [37:35] is reserved*/ + uint64_t rsvd9 : 3; + /** + * Bit 38 is source burst length enable + * 1 for enable, 0 for disable + */ + uint64_t arlen_en : 1; + /* Bits [46:39] is source burst length*/ + uint64_t arlen : 8; + /** + * Bit 47 is destination burst length enable + * 1 for enable, 0 for disable + */ + uint64_t awlen_en : 1; + /* Bits [55:48] is destination burst length */ + uint64_t awlen : 8; + /** + * Bit 56 is source status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t src_stat_en : 1; + /** + * Bit 57 is destination status enable + * 0x1 for enable, 0x0 for disable + */ + uint64_t dst_stat_en : 1; + /** + * Bit 58 is interrupt completion of block transfer + * 0x1 for enable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + * 0x0 for dsiable CHx_IntStatusReg.BLOCK_TFR_DONE_IntStat field + */ + uint64_t ioc_blktfr : 1; + /** + * Bits [61:59] is reserved + */ + uint64_t rsvd10 : 3; + /** + * Bit 62 is last shadow linked list item + * 0x1 for indicate shadowreg/LLI content is the last one + * 0x0 for indicate shadowreg/LLI content not the last one + */ + uint64_t shadowreg_or_lli_last : 1; + /** + * Bit 63 is last shadow linked list item valid + * 0x1 for indicate shadowreg/LLI content is valid + * 0x0 for indicate shadowreg/LLI content is invalid + */ + uint64_t shadowreg_or_lli_valid : 1; +} __attribute__((packed, aligned(8))) dmac_ch_ctl_t; + +typedef union _dmac_ch_ctl_u +{ + dmac_ch_ctl_t ch_ctl; + uint64_t data; +} dmac_ch_ctl_u_t; + +typedef struct _dmac_ch_cfg +{ + /** + * Bit[1:0] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t src_multblk_type : 2; + /** + * Bit[3:2] is source multi block transfer type + * 0x0 for continuous multiblock type + * 0x1 for reload multiblock type + * 0x2 for shadow register based multiblock type + * 0x3 for linked lisr bases multiblock type + */ + uint64_t dst_multblk_type : 2; + /* Bits [31:4] is reserved*/ + uint64_t rsvd1 : 28; + /** + * Bits [34:32] is transfer type and flow control + * 0x0 transfer memory to memory and flow controler is dmac + * 0x1 transfer memory to peripheral and flow controler is dmac + * 0x2 transfer peripheral to memory and flow controler is dmac + * 0x3 transfer peripheral to peripheral and flow controler is dmac + * 0x4 transfer peripheral to memory and flow controler is + * source peripheral + * 0x5 transfer peripheral to peripheral and flow controler + * is source peripheral + * 0x6 transfer memory to peripheral and flow controler is + * destination peripheral + * 0x7 transfer peripheral to peripheral and flow controler + * is destination peripheral + */ + uint64_t tt_fc : 3; + /** + * Bit 35 is source software or hardware handshaking select + * 0x1 for software handshaking is used + * 0x0 for hardware handshaking is used + */ + uint64_t hs_sel_src : 1; + /** + * Bit 36 is destination software or hardware handshaking select + *0x1 for software handshaking is used + *0x0 for hardware handshaking is used + */ + uint64_t hs_sel_dst : 1; + /** + * Bit 37 is sorce hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t src_hwhs_pol : 1; + /** + * Bit 38 is destination hardware handshaking interface polarity + * 0x1 active low, 0x0 active high + */ + uint64_t dst_hwhs_pol : 1; + /** + * Bits [41:39] is assign a hardware handshaking interface + * to source of channel x + */ + uint64_t src_per : 4; + /* Bit 43 is reserved*/ + uint64_t rsvd3 : 1; + /** + * Bits [46:44] is assign a hardware handshaking interface + * to destination of channel x + */ + uint64_t dst_per : 4; + /* Bit 48 is reserved*/ + uint64_t rsvd5 : 1; + /* Bits [51:49] is channel priority,7 is highest, 0 is lowest*/ + uint64_t ch_prior : 3; + /** + * Bit 52 is channel lock bit + * 0x0 for channel is not locked, 0x1 for channel is locked + */ + uint64_t lock_ch : 1; + /** + * Bits [54:53] is chnannel lock level + * 0x0 for duration of channel is locked for entire DMA transfer + * 0x1 for duration of channel is locked for current block transfer + */ + uint64_t lock_ch_l : 2; + uint64_t src_osr_lmt : 4; + /* Bits [58:55] is source outstanding request limit */ + uint64_t dst_osr_lmt : 4; + /* Bits [62:59] is destination outstanding request limit */ +} __attribute__((packed, aligned(8))) dmac_ch_cfg_t; + +typedef union _dmac_ch_cfg_u +{ + dmac_ch_cfg_t ch_cfg; + uint64_t data; +} dmac_ch_cfg_u_t; + +typedef struct _dmac_ch_llp +{ + /** + * Bit 0 is LLI master select + * 0x0 for next linked list item resides on AXI madster1 interface + * 0x1 for next linked list item resides on AXI madster2 interface + */ + uint64_t lms : 1; + /* Bits [5:1] is reserved */ + uint64_t rsvd1 : 5; + /* Bits [63:6] is starting address memeory of LLI block */ + uint64_t loc : 58; +} __attribute__((packed, aligned(8))) dmac_ch_llp_t; + +typedef union _dmac_ch_llp_u +{ + dmac_ch_llp_t llp; + uint64_t data; +} dmac_ch_llp_u_t; + +typedef struct _dmac_ch_status +{ + /* Bits [21:0] is completed block transfer size */ + uint64_t cmpltd_blk_size : 22; + /* Bits [46:32] is reserved */ + uint64_t rsvd1 : 15; + /* Bits [63:47] is reserved */ + uint64_t rsvd2 : 17; +} __attribute__((packed, aligned(8))) dmac_ch_status_t; + +typedef union _dmac_ch_status_u +{ + dmac_ch_status_t status; + uint64_t data; +} dmac_ch_status_u_t; + +typedef struct _dmac_ch_swhssrc +{ + /** + * Bit 0 is software handshake request for channel source + * 0x1 source periphraral request for a dma transfer + * 0x0 source peripheral is not request for a burst transfer + */ + uint64_t swhs_req_src : 1; + /** + * Bit 1 is write enable bit for software handshake request + *0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_src_we : 1; + /** + * Bit 2 is software handshake single request for channel source + * 0x1 for source peripheral requesr for a single dma transfer + * 0x0 for source peripheral is not requesting for a single transfer + */ + uint64_t swhs_sglreq_src : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle source + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_src_we : 1; + /** + * Bit 4 software handshake last request for channel source + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_src : 1; + /** + * Bit 5 is write enable bit for software + * handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_src_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))) dmac_ch_swhssrc_t; + +typedef union _dmac_ch_swhssrc_u +{ + dmac_ch_swhssrc_t swhssrc; + uint64_t data; +} dmac_ch_swhssrc_u_t; + +typedef struct _dmac_ch_swhsdst +{ + /** + * Bit 0 is software handshake request for channel destination + * 0x1 destination periphraral request for a dma transfer + * 0x0 destination peripheral is not request for a burst transfer + */ + uint64_t swhs_req_dst : 1; + /** + * Bit 1 is write enable bit for software handshake request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_req_dst_we : 1; + /** + * Bit 2 is software handshake single request for channel destination + * 0x1 for destination peripheral requesr for a single dma transfer + * 0x0 for destination peripheral is not requesting + * for a single transfer + */ + uint64_t swhs_sglreq_dst : 1; + /** + * Bit 3 is write enable bit for software handshake + * single request for channle destination + * 0x1 for enable write, 0x0 for disable write + */ + uint64_t swhs_sglreq_dst_we : 1; + /** + * Bit 4 software handshake last request for channel dstination + * 0x1 for current transfer is last transfer + * 0x0 for current transfer is not the last transfer + */ + uint64_t swhs_lst_dst : 1; + /** + * Bit 5 is write enable bit for software handshake last request + * 0x1 for enable, 0x0 for disable + */ + uint64_t swhs_lst_dst_we : 1; + /* Bits [63:6] is reserved */ + uint64_t rsvd : 58; +} __attribute__((packed, aligned(8))) dmac_ch_swhsdst_t; + +typedef union _dmac_ch_swhsdst_u +{ + dmac_ch_swhsdst_t swhsdst; + uint64_t data; +} dmac_ch_swhsdst_u_t; + +typedef struct _dmac_ch_blk_tfr_resumereq +{ + /** + * Bit 0 is block transfer resume request bit + * 0x1 for request for resuming + * 0x0 for no request to resume + */ + uint64_t blk_tfr_resumereq : 1; + /* Bits [63:1] is reserved */ + uint64_t rsvd : 63; +} __attribute__((packed, aligned(8))) dmac_ch_blk_tfr_resumereq_t; + +typedef union _dmac_ch_blk_tfr_resumereq_u +{ + dmac_ch_blk_tfr_resumereq_t blk_tfr_resumereq; + uint64_t data; +} dmac_ch_blk_tfr_resumereq_u_t; + +typedef struct _dmac_ch_intstatus_enable +{ + /* Bit 0 is block transfer done interrupt status enable */ + uint64_t enable_block_tfr_done_intstatus : 1; + /* DMA transfer done interrupt status enable */ + uint64_t enable_dma_tfr_done_intstat : 1; + /* Bit 2 reserved */ + uint64_t rsvd1 : 1; + /* Bit 3 source transaction complete status enable */ + uint64_t enable_src_transcomp_intstat : 1; + /* Bit 4 destination transaction complete */ + uint64_t enable_dst_transcomp_intstat : 1; + /* Bit 5 Source Decode Error Status Enable */ + uint64_t enable_src_dec_err_intstat : 1; + /* Bit 6 Destination Decode Error Status Enable */ + uint64_t enable_dst_dec_err_intstat : 1; + /* Bit 7 Source Slave Error Status Enable */ + uint64_t enable_src_slv_err_intstat : 1; + /* Bit 8 Destination Slave Error Status Enable */ + uint64_t enable_dst_slv_err_intstat : 1; + /* Bit 9 LLI Read Decode Error Status Enable */ + uint64_t enable_lli_rd_dec_err_intstat : 1; + /* Bit 10 LLI WRITE Decode Error Status Enable */ + uint64_t enable_lli_wr_dec_err_intstat : 1; + /* Bit 11 LLI Read Slave Error Status Enable */ + uint64_t enable_lli_rd_slv_err_intstat : 1; + /* Bit 12 LLI WRITE Slave Error Status Enable */ + uint64_t enable_lli_wr_slv_err_intstat : 1; + uint64_t rsvd2 : 51; +} dmac_ch_intstatus_enable_t; + +typedef union _dmac_ch_intstatus_enable_u +{ + dmac_ch_intstatus_enable_t ch_intstatus_enable; + uint64_t data; +} dmac_ch_intstatus_enable_u_t; + +typedef struct _dmac_ch_intclear +{ + /* Bit 0 block transfer done interrupt clear bit.*/ + uint64_t blk_tfr_done_intstat : 1; + /* Bit 1 DMA transfer done interrupt clear bit */ + uint64_t dma_tfr_done_intstat : 1; + /* Bit 2 is reserved */ + uint64_t resv1 : 1; + uint64_t resv2 : 61; +} __attribute__((packed, aligned(8))) dmac_ch_intclear_t; + +typedef union _dmac_ch_intclear_u +{ + uint64_t data; + dmac_ch_intclear_t intclear; +} dmac_ch_intclear_u_t; + +typedef struct _dmac_channel +{ + /* (0x100) SAR Address Register */ + uint64_t sar; + /* (0x108) DAR Address Register */ + uint64_t dar; + /* (0x110) Block Transfer Size Register */ + uint64_t block_ts; + /* (0x118) Control Register */ + uint64_t ctl; + /* (0x120) Configure Register */ + uint64_t cfg; + /* (0x128) Linked List Pointer register */ + uint64_t llp; + /* (0x130) Channelx Status Register */ + uint64_t status; + /* (0x138) Channelx Software handshake Source Register */ + uint64_t swhssrc; + /* (0x140) Channelx Software handshake Destination Register */ + uint64_t swhsdst; + /* (0x148) Channelx Block Transfer Resume Request Register */ + uint64_t blk_tfr; + /* (0x150) Channelx AXI ID Register */ + uint64_t axi_id; + /* (0x158) Channelx AXI QOS Register */ + uint64_t axi_qos; + /* Reserved address */ + uint64_t reserved1[4]; + /* (0x180) Interrupt Status Enable Register */ + uint64_t intstatus_en; + /* (0x188) Channelx Interrupt Status Register */ + uint64_t intstatus; + /* (0x190) Interrupt Siganl Enable Register */ + uint64_t intsignal_en; + /* (0x198) Interrupt Clear Register */ + uint64_t intclear; + uint64_t reserved2[12]; +} __attribute__((packed, aligned(8))) dmac_channel_t; + +typedef struct _dmac +{ + /* (0x00) DMAC ID Rgister */ + uint64_t id; + /* (0x08) DMAC COMPVER Register */ + uint64_t compver; + /* (0x10) DMAC Configure Register */ + uint64_t cfg; + /* (0x18) Channel Enable Register */ + uint64_t chen; + uint64_t reserved1[2]; + /* (0x30) DMAC Interrupt Status Register */ + uint64_t intstatus; + /* (0x38) DMAC Common register Interrupt Status Register */ + uint64_t com_intclear; + /* (0x40) DMAC Common Interrupt Enable Register */ + uint64_t com_intstatus_en; + /* (0x48) DMAC Common Interrupt Signal Enable Register */ + uint64_t com_intsignal_en; + /* (0x50) DMAC Common Interrupt Status */ + uint64_t com_intstatus; + /* (0x58) DMAC Reset register */ + uint64_t reset; + uint64_t reserved2[20]; + dmac_channel_t channel[DMAC_CHANNEL_COUNT]; +} __attribute__((packed, aligned(8))) dmac_t; + +typedef struct _dmac_channel_config +{ + uint64_t sar; + uint64_t dar; + uint8_t ctl_sms; + uint8_t ctl_dms; + uint8_t ctl_src_msize; + uint8_t ctl_drc_msize; + uint8_t ctl_sinc; + uint8_t ctl_dinc; + uint8_t ctl_src_tr_width; + uint8_t ctl_dst_tr_width; + uint8_t ctl_ioc_blktfr; + uint8_t ctl_src_stat_en; + uint8_t ctl_dst_stat_en; + uint8_t cfg_dst_per; + uint8_t cfg_src_per; + uint8_t cfg_src_hs_pol; + uint8_t cfg_dst_hs_pol; + uint8_t cfg_hs_sel_src; + uint8_t cfg_hs_sel_dst; + uint64_t cfg_src_multblk_type; + uint64_t cfg_dst_multblk_type; + uint64_t llp_loc; + uint8_t llp_lms; + uint64_t ctl_block_ts; + uint8_t ctl_tt_fc; + uint8_t cfg_protctl; + uint8_t cfg_fifo_mode; + uint8_t cfg_fcmode; + uint8_t cfg_lock_ch_l; + uint8_t cfg_ch_prior; +} dmac_channel_config_t; + +#define LIST_ENTRY(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + +struct list_head_t +{ + struct list_head_t *next, *prev; +}; + +/** + * @brief Dmac.data/dw_dmac_lli_item + * + * @desc This structure is used when creating Linked List Items. + * + * @see dw_dmac_addLliItem() + */ +typedef struct _dmac_lli_item +{ + uint64_t sar; + uint64_t dar; + uint64_t ch_block_ts; + uint64_t llp; + uint64_t ctl; + uint64_t sstat; + uint64_t dstat; + uint64_t resv; +} __attribute__((packed, aligned(64))) dmac_lli_item_t; + +extern volatile dmac_t *const dmac; + +/** + * @brief Dmac initialize + */ +void dmac_init(void); + +/** + * @brief Set dmac param + * + * @param[in] channel_num Dmac channel + * @param[in] src Dmac source + * @param[in] dest Dmac dest + * @param[in] src_inc Source address increase or not + * @param[in] dest_inc Dest address increase or not + * @param[in] dmac_burst_size Dmac burst length + * @param[in] dmac_trans_width Dmac transfer data width + * @param[in] block_size Dmac transfer length + * + */ +void dmac_set_single_mode(dmac_channel_number_t channel_num, + const void *src, void *dest, dmac_address_increment_t src_inc, + dmac_address_increment_t dest_inc, + dmac_burst_trans_length_t dmac_burst_size, + dmac_transfer_width_t dmac_trans_width, + size_t block_size); + +/** + * @brief Wait for dmac work done + * + * @param[in] channel_num Dmac channel + * + */ +void dmac_wait_done(dmac_channel_number_t channel_num); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_DMAC_H */ diff --git a/lib/drivers/include/dvp.h b/lib/drivers/include/dvp.h new file mode 100755 index 0000000..42334a7 --- /dev/null +++ b/lib/drivers/include/dvp.h @@ -0,0 +1,253 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_DVP_H +#define _DRIVER_DVP_H +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/** + * @brief DVP object + */ +typedef struct _dvp +{ + uint32_t dvp_cfg; + uint32_t r_addr; + uint32_t g_addr; + uint32_t b_addr; + uint32_t cmos_cfg; + uint32_t sccb_cfg; + uint32_t sccb_ctl; + uint32_t axi; + uint32_t sts; + uint32_t reverse; + uint32_t rgb_addr; +} __attribute__((packed, aligned(4))) dvp_t; + +/* DVP Config Register */ +#define DVP_CFG_START_INT_ENABLE 0x00000001U +#define DVP_CFG_FINISH_INT_ENABLE 0x00000002U +#define DVP_CFG_AI_OUTPUT_ENABLE 0x00000004U +#define DVP_CFG_DISPLAY_OUTPUT_ENABLE 0x00000008U +#define DVP_CFG_AUTO_ENABLE 0x00000010U +#define DVP_CFG_BURST_SIZE_4BEATS 0x00000100U +#define DVP_CFG_FORMAT_MASK 0x00000600U +#define DVP_CFG_RGB_FORMAT 0x00000000U +#define DVP_CFG_YUV_FORMAT 0x00000200U +#define DVP_CFG_Y_FORMAT 0x00000600U +#define DVP_CFG_HREF_BURST_NUM_MASK 0x000FF000U +#define DVP_CFG_HREF_BURST_NUM(x) ((x) << 12) +#define DVP_CFG_LINE_NUM_MASK 0x3FF00000U +#define DVP_CFG_LINE_NUM(x) ((x) << 20) + +/* DVP CMOS Config Register */ +#define DVP_CMOS_CLK_DIV_MASK 0x000000FFU +#define DVP_CMOS_CLK_DIV(x) ((x) << 0) +#define DVP_CMOS_CLK_ENABLE 0x00000100U +#define DVP_CMOS_RESET 0x00010000U +#define DVP_CMOS_POWER_DOWN 0x01000000U + +/* DVP SCCB Config Register */ +#define DVP_SCCB_BYTE_NUM_MASK 0x00000003U +#define DVP_SCCB_BYTE_NUM_2 0x00000001U +#define DVP_SCCB_BYTE_NUM_3 0x00000002U +#define DVP_SCCB_BYTE_NUM_4 0x00000003U +#define DVP_SCCB_SCL_LCNT_MASK 0x0000FF00U +#define DVP_SCCB_SCL_LCNT(x) ((x) << 8) +#define DVP_SCCB_SCL_HCNT_MASK 0x00FF0000U +#define DVP_SCCB_SCL_HCNT(x) ((x) << 16) +#define DVP_SCCB_RDATA_BYTE(x) ((x) >> 24) + +/* DVP SCCB Control Register */ +#define DVP_SCCB_WRITE_DATA_ENABLE 0x00000001U +#define DVP_SCCB_DEVICE_ADDRESS(x) ((x) << 0) +#define DVP_SCCB_REG_ADDRESS(x) ((x) << 8) +#define DVP_SCCB_WDATA_BYTE0(x) ((x) << 16) +#define DVP_SCCB_WDATA_BYTE1(x) ((x) << 24) + +/* DVP AXI Register */ +#define DVP_AXI_GM_MLEN_MASK 0x000000FFU +#define DVP_AXI_GM_MLEN_1BYTE 0x00000000U +#define DVP_AXI_GM_MLEN_4BYTE 0x00000003U + +/* DVP STS Register */ +#define DVP_STS_FRAME_START 0x00000001U +#define DVP_STS_FRAME_START_WE 0x00000002U +#define DVP_STS_FRAME_FINISH 0x00000100U +#define DVP_STS_FRAME_FINISH_WE 0x00000200U +#define DVP_STS_DVP_EN 0x00010000U +#define DVP_STS_DVP_EN_WE 0x00020000U +#define DVP_STS_SCCB_EN 0x01000000U +#define DVP_STS_SCCB_EN_WE 0x02000000U +/* clang-format on */ + +typedef enum _dvp_output_mode +{ + DVP_OUTPUT_AI, + DVP_OUTPUT_DISPLAY, +} dvp_output_mode_t; + +/** + * @brief DVP object instance + */ +extern volatile dvp_t* const dvp; + +/** + * @brief Initialize DVP + */ +void dvp_init(uint8_t reg_len); + +/** + * @brief Set image format + * + * @param[in] format The image format + */ +void dvp_set_image_format(uint32_t format); + +/** + * @brief Set image size + * + * @param[in] width The width of image + * @param[in] height The height of image + */ +void dvp_set_image_size(uint32_t width, uint32_t height); + +/** + * @brief Set the address of RGB for AI + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + */ +void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr); + +/** + * @brief Set the address of RGB for display + * + * @param[in] r_addr The R address of RGB + * @param[in] g_addr The G address of RGB + * @param[in] b_addr The B address of RGB + */ +void dvp_set_display_addr(uint32_t addr); + +/** + * @brief The frame start transfer + */ +void dvp_start_frame(void); + +/** + * @brief The DVP convert start + */ +void dvp_start_convert(void); + +/** + * @brief The DVP convert finish + */ +void dvp_finish_convert(void); + +/** + * @brief Get the image data + * + * @note The image data stored in the address of RGB + */ +void dvp_get_image(void); + +/** + * @brief Use SCCB write register + * + * @param[in] dev_addr The device address + * @param[in] reg_addr The register address + * @param[in] reg_data The register data + */ +void dvp_sccb_send_data(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data); + +/** + * @brief Use SCCB read register + * + * @param[in] dev_addr The device address + * @param[in] reg_addr The register address + * + * @return The register value + */ +uint8_t dvp_sccb_receive_data(uint8_t dev_addr, uint16_t reg_addr); + +/** + * @brief Enable dvp burst + */ +void dvp_enable_burst(void); + +/** + * @brief Disable dvp burst + */ +void dvp_disable_burst(void); + +/** + * @brief Enable or disable dvp interrupt + * + * @param[in] interrupt Dvp interrupt + * @param[in] status 0:disable 1:enable + * + */ +void dvp_config_interrupt(uint32_t interrupt, uint8_t enable); + +/** + * @brief Get dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + * + * @return Interrupt status + * - 0 false + * - 1 true + */ +int dvp_get_interrupt(uint32_t interrupt); + +/** + * @brief Clear dvp interrupt status + * + * @param[in] interrupt Dvp interrupt + * + */ +void dvp_clear_interrupt(uint32_t interrupt); + +/** + * @brief Enable dvp auto mode + */ +void dvp_enable_auto(void); + +/** + * @brief Disable dvp auto mode + */ +void dvp_disable_auto(void); + +/** + * @brief Dvp ouput data enable or not + * + * @param[in] index 0:AI, 1:display + * @param[in] enable 0:disable, 1:enable + * + */ +void dvp_set_output_enable(dvp_output_mode_t index, int enable); + +void dvp_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_DVP_H */ diff --git a/lib/drivers/include/fft.h b/lib/drivers/include/fft.h new file mode 100755 index 0000000..fcef54f --- /dev/null +++ b/lib/drivers/include/fft.h @@ -0,0 +1,232 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_FFT_H +#define _DRIVER_FFT_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _complex_hard +{ + int16_t real; + int16_t imag; +} complex_hard_t; + +typedef struct _fft_data +{ + int16_t I1; + int16_t R1; + int16_t I2; + int16_t R2; +} fft_data_t; + +typedef enum _fft_point +{ + FFT_512, + FFT_256, + FFT_128, + FFT_64, +} fft_point_t; + +typedef enum _fft_direction +{ + FFT_DIR_BACKWARD, + FFT_DIR_FORWARD, + FFT_DIR_MAX, +} fft_direction_t; + +/** + * @brief FFT algorithm accelerator register + * + * @note FFT algorithm accelerator register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | fft_input_fifo | input data fifo | + * | 0x08 | fft_ctrl | fft ctrl reg | + * | 0x10 | fifo_ctrl | fifo ctrl | + * | 0x18 | intr_mask | interrupt mask | + * | 0x20 | intr_clear | interrupt clear | + * | 0x28 | fft_status | fft status reg | + * | 0x30 | fft_status_raw | fft_status_raw | + * | 0x38 | fft_output_fifo| fft_output_fifo | + * + */ + +/** + * @brief The calculation data is input through this register + * + * No. 0 Register (0x00) + */ +typedef struct _fft_input_fifo +{ + uint64_t fft_input_fifo : 64; +} __attribute__((packed, aligned(8))) fft_input_fifo_t; + +/** + * @brief fft ctrl reg + * + * No. 1 Register (0x08) + */ +typedef struct _fft_fft_ctrl +{ + /** + *FFT calculation data length: + *b'000:512 point; b'001:256 point; b'010:128 point; b'011:64 point; + */ + uint64_t fft_point : 3; + /* FFT mode: b'0:FFT b'1:IFFT */ + uint64_t fft_mode : 1; + /* Corresponding to the nine layer butterfly shift operation, 0x0: does not shift; 0x1: shift 1st layer. ...*/ + uint64_t fft_shift : 9; + /* FFT enable: b'0:disable b'1:enable */ + uint64_t fft_enable : 1; + /* FFT DMA enable: b'0:disable b'1:enable */ + uint64_t dma_send : 1; + /** + *Input data arrangement: b'00:RIRI; b'01:only real part exist, RRRR; + *b'10:First input the real part and then input the imaginary part. + */ + uint64_t fft_input_mode : 2; + /* Effective width of input data. b'0:64bit effective; b'1:32bit effective */ + uint64_t fft_data_mode : 1; + uint64_t reserved : 46; +} __attribute__((packed, aligned(8))) fft_fft_ctrl_t; + +/** + * @brief fifo ctrl + * + * No. 2 Register (0x10) + */ +typedef struct _fft_fifo_ctrl +{ + /* Response memory initialization flag.b'1:initialization */ + uint64_t resp_fifo_flush_n : 1; + /* Command memory initialization flag.b'1:initialization */ + uint64_t cmd_fifo_flush_n : 1; + /* Output interface memory initialization flag.b'1:initialization */ + uint64_t gs_fifo_flush_n : 1; + uint64_t reserved : 61; +} __attribute__((packed, aligned(8))) fft_fifo_ctrl_t; + +/** + * @brief interrupt mask + * + * No. 3 Register (0x18) + */ +typedef struct _fft_intr_mask +{ + /** + *FFT return status set. + *b'0:FFT returns to the state after completion. + *b'1:FFT does not return to the state after completion + */ + uint64_t fft_done_mask : 1; + uint64_t reserved : 63; +} __attribute__((packed, aligned(8))) fft_intr_mask_t; + +/** + * @brief interrupt clear + * + * No. 4 Register (0x20) + */ +typedef struct _fft_intr_clear +{ + /* The interrupt state clears. b'1:clear current interrupt request */ + uint64_t fft_done_clear : 1; + uint64_t reserved1 : 63; +} __attribute__((packed, aligned(8))) fft_intr_clear_t; + +/** + * @brief fft status reg + * + * No. 5 Register (0x28) + */ +typedef struct _fft_status +{ + /* FFT calculation state.b'0:not completed; b'1:completed */ + uint64_t fft_done_status : 1; + uint64_t reserved1 : 63; +} __attribute__((packed, aligned(8))) fft_status_t; + +/** + * @brief fft status raw + * + * No. 6 Register (0x30) + */ +typedef struct _fft_status_raw +{ + /* FFT calculation state. b'1:done */ + uint64_t fft_done_status_raw : 1; + /* FFT calculation state. b'1:working */ + uint64_t fft_work_status_raw : 1; + uint64_t reserved : 62; +} __attribute__((packed, aligned(8))) fft_status_raw_t; + +/** + * @brief Output of FFT calculation data through this register + * + * No. 7 Register (0x38) + */ +typedef struct _fft_output_fifo +{ + uint64_t fft_output_fifo : 64; +} __attribute__((packed, aligned(8))) fft_output_fifo_t; + +/** + * @brief Fast Fourier transform (FFT) algorithm accelerator object + * + * A fast Fourier transform (FFT) algorithm computes the discrete + * Fourier transform (DFT) of a sequence, or its inverse (IFFT). + * Fourier analysis converts a signal from its original domain + * (often time or space) to a representation in the frequency + * domain and vice versa. An FFT rapidly computes such + * transformations by factorizing the DFT matrix into a product of + * sparse (mostly zero) factors. + */ +typedef struct _fft +{ + /* No. 0 (0x00): input data fifo */ + fft_input_fifo_t fft_input_fifo; + /* No. 1 (0x08): fft ctrl reg */ + fft_fft_ctrl_t fft_ctrl; + /* No. 2 (0x10): fifo ctrl */ + fft_fifo_ctrl_t fifo_ctrl; + /* No. 3 (0x18): interrupt mask */ + fft_intr_mask_t intr_mask; + /* No. 4 (0x20): interrupt clear */ + fft_intr_clear_t intr_clear; + /* No. 5 (0x28): fft status reg */ + fft_status_t fft_status; + /* No. 6 (0x30): fft_status_raw */ + fft_status_raw_t fft_status_raw; + /* No. 7 (0x38): fft_output_fifo */ + fft_output_fifo_t fft_output_fifo; +} __attribute__((packed, aligned(8))) fft_t; + + +void fft_complex_uint16_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + uint16_t shift, fft_direction_t direction, const uint64_t *input, size_t point_num, uint64_t *output); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_FFT_H */ + diff --git a/lib/drivers/include/fpioa.h b/lib/drivers/include/fpioa.h new file mode 100755 index 0000000..b077f4e --- /dev/null +++ b/lib/drivers/include/fpioa.h @@ -0,0 +1,1001 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +/** + * @file + * @brief Field Programmable GPIO Array (FPIOA) + * + * The FPIOA peripheral supports the following features: + * + * - 48 IO with 256 functions + * + * - Schmitt trigger + * + * - Invert input and output + * + * - Pull up and pull down + * + * - Driving selector + * + * - Static input and output + * + */ + +#ifndef _DRIVER_FPIOA_H +#define _DRIVER_FPIOA_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Pad number settings */ +#define FPIOA_NUM_IO (48) +/* clang-format on */ + +/** + * @brief FPIOA IO functions + * + * @note FPIOA pin function table + * + * | Function | Name | Description | + * |-----------|------------------|-----------------------------------| + * | 0 | JTAG_TCLK | JTAG Test Clock | + * | 1 | JTAG_TDI | JTAG Test Data In | + * | 2 | JTAG_TMS | JTAG Test Mode Select | + * | 3 | JTAG_TDO | JTAG Test Data Out | + * | 4 | SPI0_D0 | SPI0 Data 0 | + * | 5 | SPI0_D1 | SPI0 Data 1 | + * | 6 | SPI0_D2 | SPI0 Data 2 | + * | 7 | SPI0_D3 | SPI0 Data 3 | + * | 8 | SPI0_D4 | SPI0 Data 4 | + * | 9 | SPI0_D5 | SPI0 Data 5 | + * | 10 | SPI0_D6 | SPI0 Data 6 | + * | 11 | SPI0_D7 | SPI0 Data 7 | + * | 12 | SPI0_SS0 | SPI0 Chip Select 0 | + * | 13 | SPI0_SS1 | SPI0 Chip Select 1 | + * | 14 | SPI0_SS2 | SPI0 Chip Select 2 | + * | 15 | SPI0_SS3 | SPI0 Chip Select 3 | + * | 16 | SPI0_ARB | SPI0 Arbitration | + * | 17 | SPI0_SCLK | SPI0 Serial Clock | + * | 18 | UARTHS_RX | UART High speed Receiver | + * | 19 | UARTHS_TX | UART High speed Transmitter | + * | 20 | RESV6 | Reserved function | + * | 21 | RESV7 | Reserved function | + * | 22 | CLK_SPI1 | Clock SPI1 | + * | 23 | CLK_I2C1 | Clock I2C1 | + * | 24 | GPIOHS0 | GPIO High speed 0 | + * | 25 | GPIOHS1 | GPIO High speed 1 | + * | 26 | GPIOHS2 | GPIO High speed 2 | + * | 27 | GPIOHS3 | GPIO High speed 3 | + * | 28 | GPIOHS4 | GPIO High speed 4 | + * | 29 | GPIOHS5 | GPIO High speed 5 | + * | 30 | GPIOHS6 | GPIO High speed 6 | + * | 31 | GPIOHS7 | GPIO High speed 7 | + * | 32 | GPIOHS8 | GPIO High speed 8 | + * | 33 | GPIOHS9 | GPIO High speed 9 | + * | 34 | GPIOHS10 | GPIO High speed 10 | + * | 35 | GPIOHS11 | GPIO High speed 11 | + * | 36 | GPIOHS12 | GPIO High speed 12 | + * | 37 | GPIOHS13 | GPIO High speed 13 | + * | 38 | GPIOHS14 | GPIO High speed 14 | + * | 39 | GPIOHS15 | GPIO High speed 15 | + * | 40 | GPIOHS16 | GPIO High speed 16 | + * | 41 | GPIOHS17 | GPIO High speed 17 | + * | 42 | GPIOHS18 | GPIO High speed 18 | + * | 43 | GPIOHS19 | GPIO High speed 19 | + * | 44 | GPIOHS20 | GPIO High speed 20 | + * | 45 | GPIOHS21 | GPIO High speed 21 | + * | 46 | GPIOHS22 | GPIO High speed 22 | + * | 47 | GPIOHS23 | GPIO High speed 23 | + * | 48 | GPIOHS24 | GPIO High speed 24 | + * | 49 | GPIOHS25 | GPIO High speed 25 | + * | 50 | GPIOHS26 | GPIO High speed 26 | + * | 51 | GPIOHS27 | GPIO High speed 27 | + * | 52 | GPIOHS28 | GPIO High speed 28 | + * | 53 | GPIOHS29 | GPIO High speed 29 | + * | 54 | GPIOHS30 | GPIO High speed 30 | + * | 55 | GPIOHS31 | GPIO High speed 31 | + * | 56 | GPIO0 | GPIO pin 0 | + * | 57 | GPIO1 | GPIO pin 1 | + * | 58 | GPIO2 | GPIO pin 2 | + * | 59 | GPIO3 | GPIO pin 3 | + * | 60 | GPIO4 | GPIO pin 4 | + * | 61 | GPIO5 | GPIO pin 5 | + * | 62 | GPIO6 | GPIO pin 6 | + * | 63 | GPIO7 | GPIO pin 7 | + * | 64 | UART1_RX | UART1 Receiver | + * | 65 | UART1_TX | UART1 Transmitter | + * | 66 | UART2_RX | UART2 Receiver | + * | 67 | UART2_TX | UART2 Transmitter | + * | 68 | UART3_RX | UART3 Receiver | + * | 69 | UART3_TX | UART3 Transmitter | + * | 70 | SPI1_D0 | SPI1 Data 0 | + * | 71 | SPI1_D1 | SPI1 Data 1 | + * | 72 | SPI1_D2 | SPI1 Data 2 | + * | 73 | SPI1_D3 | SPI1 Data 3 | + * | 74 | SPI1_D4 | SPI1 Data 4 | + * | 75 | SPI1_D5 | SPI1 Data 5 | + * | 76 | SPI1_D6 | SPI1 Data 6 | + * | 77 | SPI1_D7 | SPI1 Data 7 | + * | 78 | SPI1_SS0 | SPI1 Chip Select 0 | + * | 79 | SPI1_SS1 | SPI1 Chip Select 1 | + * | 80 | SPI1_SS2 | SPI1 Chip Select 2 | + * | 81 | SPI1_SS3 | SPI1 Chip Select 3 | + * | 82 | SPI1_ARB | SPI1 Arbitration | + * | 83 | SPI1_SCLK | SPI1 Serial Clock | + * | 84 | SPI_SLAVE_D0 | SPI Slave Data 0 | + * | 85 | SPI_SLAVE_SS | SPI Slave Select | + * | 86 | SPI_SLAVE_SCLK | SPI Slave Serial Clock | + * | 87 | I2S0_MCLK | I2S0 Master Clock | + * | 88 | I2S0_SCLK | I2S0 Serial Clock(BCLK) | + * | 89 | I2S0_WS | I2S0 Word Select(LRCLK) | + * | 90 | I2S0_IN_D0 | I2S0 Serial Data Input 0 | + * | 91 | I2S0_IN_D1 | I2S0 Serial Data Input 1 | + * | 92 | I2S0_IN_D2 | I2S0 Serial Data Input 2 | + * | 93 | I2S0_IN_D3 | I2S0 Serial Data Input 3 | + * | 94 | I2S0_OUT_D0 | I2S0 Serial Data Output 0 | + * | 95 | I2S0_OUT_D1 | I2S0 Serial Data Output 1 | + * | 96 | I2S0_OUT_D2 | I2S0 Serial Data Output 2 | + * | 97 | I2S0_OUT_D3 | I2S0 Serial Data Output 3 | + * | 98 | I2S1_MCLK | I2S1 Master Clock | + * | 99 | I2S1_SCLK | I2S1 Serial Clock(BCLK) | + * | 100 | I2S1_WS | I2S1 Word Select(LRCLK) | + * | 101 | I2S1_IN_D0 | I2S1 Serial Data Input 0 | + * | 102 | I2S1_IN_D1 | I2S1 Serial Data Input 1 | + * | 103 | I2S1_IN_D2 | I2S1 Serial Data Input 2 | + * | 104 | I2S1_IN_D3 | I2S1 Serial Data Input 3 | + * | 105 | I2S1_OUT_D0 | I2S1 Serial Data Output 0 | + * | 106 | I2S1_OUT_D1 | I2S1 Serial Data Output 1 | + * | 107 | I2S1_OUT_D2 | I2S1 Serial Data Output 2 | + * | 108 | I2S1_OUT_D3 | I2S1 Serial Data Output 3 | + * | 109 | I2S2_MCLK | I2S2 Master Clock | + * | 110 | I2S2_SCLK | I2S2 Serial Clock(BCLK) | + * | 111 | I2S2_WS | I2S2 Word Select(LRCLK) | + * | 112 | I2S2_IN_D0 | I2S2 Serial Data Input 0 | + * | 113 | I2S2_IN_D1 | I2S2 Serial Data Input 1 | + * | 114 | I2S2_IN_D2 | I2S2 Serial Data Input 2 | + * | 115 | I2S2_IN_D3 | I2S2 Serial Data Input 3 | + * | 116 | I2S2_OUT_D0 | I2S2 Serial Data Output 0 | + * | 117 | I2S2_OUT_D1 | I2S2 Serial Data Output 1 | + * | 118 | I2S2_OUT_D2 | I2S2 Serial Data Output 2 | + * | 119 | I2S2_OUT_D3 | I2S2 Serial Data Output 3 | + * | 120 | RESV0 | Reserved function | + * | 121 | RESV1 | Reserved function | + * | 122 | RESV2 | Reserved function | + * | 123 | RESV3 | Reserved function | + * | 124 | RESV4 | Reserved function | + * | 125 | RESV5 | Reserved function | + * | 126 | I2C0_SCLK | I2C0 Serial Clock | + * | 127 | I2C0_SDA | I2C0 Serial Data | + * | 128 | I2C1_SCLK | I2C1 Serial Clock | + * | 129 | I2C1_SDA | I2C1 Serial Data | + * | 130 | I2C2_SCLK | I2C2 Serial Clock | + * | 131 | I2C2_SDA | I2C2 Serial Data | + * | 132 | CMOS_XCLK | DVP System Clock | + * | 133 | CMOS_RST | DVP System Reset | + * | 134 | CMOS_PWDN | DVP Power Down Mode | + * | 135 | CMOS_VSYNC | DVP Vertical Sync | + * | 136 | CMOS_HREF | DVP Horizontal Reference output | + * | 137 | CMOS_PCLK | Pixel Clock | + * | 138 | CMOS_D0 | Data Bit 0 | + * | 139 | CMOS_D1 | Data Bit 1 | + * | 140 | CMOS_D2 | Data Bit 2 | + * | 141 | CMOS_D3 | Data Bit 3 | + * | 142 | CMOS_D4 | Data Bit 4 | + * | 143 | CMOS_D5 | Data Bit 5 | + * | 144 | CMOS_D6 | Data Bit 6 | + * | 145 | CMOS_D7 | Data Bit 7 | + * | 146 | SCCB_SCLK | SCCB Serial Clock | + * | 147 | SCCB_SDA | SCCB Serial Data | + * | 148 | UART1_CTS | UART1 Clear To Send | + * | 149 | UART1_DSR | UART1 Data Set Ready | + * | 150 | UART1_DCD | UART1 Data Carrier Detect | + * | 151 | UART1_RI | UART1 Ring Indicator | + * | 152 | UART1_SIR_IN | UART1 Serial Infrared Input | + * | 153 | UART1_DTR | UART1 Data Terminal Ready | + * | 154 | UART1_RTS | UART1 Request To Send | + * | 155 | UART1_OUT2 | UART1 User-designated Output 2 | + * | 156 | UART1_OUT1 | UART1 User-designated Output 1 | + * | 157 | UART1_SIR_OUT | UART1 Serial Infrared Output | + * | 158 | UART1_BAUD | UART1 Transmit Clock Output | + * | 159 | UART1_RE | UART1 Receiver Output Enable | + * | 160 | UART1_DE | UART1 Driver Output Enable | + * | 161 | UART1_RS485_EN | UART1 RS485 Enable | + * | 162 | UART2_CTS | UART2 Clear To Send | + * | 163 | UART2_DSR | UART2 Data Set Ready | + * | 164 | UART2_DCD | UART2 Data Carrier Detect | + * | 165 | UART2_RI | UART2 Ring Indicator | + * | 166 | UART2_SIR_IN | UART2 Serial Infrared Input | + * | 167 | UART2_DTR | UART2 Data Terminal Ready | + * | 168 | UART2_RTS | UART2 Request To Send | + * | 169 | UART2_OUT2 | UART2 User-designated Output 2 | + * | 170 | UART2_OUT1 | UART2 User-designated Output 1 | + * | 171 | UART2_SIR_OUT | UART2 Serial Infrared Output | + * | 172 | UART2_BAUD | UART2 Transmit Clock Output | + * | 173 | UART2_RE | UART2 Receiver Output Enable | + * | 174 | UART2_DE | UART2 Driver Output Enable | + * | 175 | UART2_RS485_EN | UART2 RS485 Enable | + * | 176 | UART3_CTS | UART3 Clear To Send | + * | 177 | UART3_DSR | UART3 Data Set Ready | + * | 178 | UART3_DCD | UART3 Data Carrier Detect | + * | 179 | UART3_RI | UART3 Ring Indicator | + * | 180 | UART3_SIR_IN | UART3 Serial Infrared Input | + * | 181 | UART3_DTR | UART3 Data Terminal Ready | + * | 182 | UART3_RTS | UART3 Request To Send | + * | 183 | UART3_OUT2 | UART3 User-designated Output 2 | + * | 184 | UART3_OUT1 | UART3 User-designated Output 1 | + * | 185 | UART3_SIR_OUT | UART3 Serial Infrared Output | + * | 186 | UART3_BAUD | UART3 Transmit Clock Output | + * | 187 | UART3_RE | UART3 Receiver Output Enable | + * | 188 | UART3_DE | UART3 Driver Output Enable | + * | 189 | UART3_RS485_EN | UART3 RS485 Enable | + * | 190 | TIMER0_TOGGLE1 | TIMER0 Toggle Output 1 | + * | 191 | TIMER0_TOGGLE2 | TIMER0 Toggle Output 2 | + * | 192 | TIMER0_TOGGLE3 | TIMER0 Toggle Output 3 | + * | 193 | TIMER0_TOGGLE4 | TIMER0 Toggle Output 4 | + * | 194 | TIMER1_TOGGLE1 | TIMER1 Toggle Output 1 | + * | 195 | TIMER1_TOGGLE2 | TIMER1 Toggle Output 2 | + * | 196 | TIMER1_TOGGLE3 | TIMER1 Toggle Output 3 | + * | 197 | TIMER1_TOGGLE4 | TIMER1 Toggle Output 4 | + * | 198 | TIMER2_TOGGLE1 | TIMER2 Toggle Output 1 | + * | 199 | TIMER2_TOGGLE2 | TIMER2 Toggle Output 2 | + * | 200 | TIMER2_TOGGLE3 | TIMER2 Toggle Output 3 | + * | 201 | TIMER2_TOGGLE4 | TIMER2 Toggle Output 4 | + * | 202 | CLK_SPI2 | Clock SPI2 | + * | 203 | CLK_I2C2 | Clock I2C2 | + * | 204 | INTERNAL0 | Internal function signal 0 | + * | 205 | INTERNAL1 | Internal function signal 1 | + * | 206 | INTERNAL2 | Internal function signal 2 | + * | 207 | INTERNAL3 | Internal function signal 3 | + * | 208 | INTERNAL4 | Internal function signal 4 | + * | 209 | INTERNAL5 | Internal function signal 5 | + * | 210 | INTERNAL6 | Internal function signal 6 | + * | 211 | INTERNAL7 | Internal function signal 7 | + * | 212 | INTERNAL8 | Internal function signal 8 | + * | 213 | INTERNAL9 | Internal function signal 9 | + * | 214 | INTERNAL10 | Internal function signal 10 | + * | 215 | INTERNAL11 | Internal function signal 11 | + * | 216 | INTERNAL12 | Internal function signal 12 | + * | 217 | INTERNAL13 | Internal function signal 13 | + * | 218 | INTERNAL14 | Internal function signal 14 | + * | 219 | INTERNAL15 | Internal function signal 15 | + * | 220 | INTERNAL16 | Internal function signal 16 | + * | 221 | INTERNAL17 | Internal function signal 17 | + * | 222 | CONSTANT | Constant function | + * | 223 | INTERNAL18 | Internal function signal 18 | + * | 224 | DEBUG0 | Debug function 0 | + * | 225 | DEBUG1 | Debug function 1 | + * | 226 | DEBUG2 | Debug function 2 | + * | 227 | DEBUG3 | Debug function 3 | + * | 228 | DEBUG4 | Debug function 4 | + * | 229 | DEBUG5 | Debug function 5 | + * | 230 | DEBUG6 | Debug function 6 | + * | 231 | DEBUG7 | Debug function 7 | + * | 232 | DEBUG8 | Debug function 8 | + * | 233 | DEBUG9 | Debug function 9 | + * | 234 | DEBUG10 | Debug function 10 | + * | 235 | DEBUG11 | Debug function 11 | + * | 236 | DEBUG12 | Debug function 12 | + * | 237 | DEBUG13 | Debug function 13 | + * | 238 | DEBUG14 | Debug function 14 | + * | 239 | DEBUG15 | Debug function 15 | + * | 240 | DEBUG16 | Debug function 16 | + * | 241 | DEBUG17 | Debug function 17 | + * | 242 | DEBUG18 | Debug function 18 | + * | 243 | DEBUG19 | Debug function 19 | + * | 244 | DEBUG20 | Debug function 20 | + * | 245 | DEBUG21 | Debug function 21 | + * | 246 | DEBUG22 | Debug function 22 | + * | 247 | DEBUG23 | Debug function 23 | + * | 248 | DEBUG24 | Debug function 24 | + * | 249 | DEBUG25 | Debug function 25 | + * | 250 | DEBUG26 | Debug function 26 | + * | 251 | DEBUG27 | Debug function 27 | + * | 252 | DEBUG28 | Debug function 28 | + * | 253 | DEBUG29 | Debug function 29 | + * | 254 | DEBUG30 | Debug function 30 | + * | 255 | DEBUG31 | Debug function 31 | + * + * Any IO of FPIOA have 256 functions, it is a IO-function matrix. + * All IO have default reset function, after reset, re-configure + * IO function is required. + */ + +/* clang-format off */ +typedef enum _fpioa_function +{ + FUNC_JTAG_TCLK = 0, /*!< JTAG Test Clock */ + FUNC_JTAG_TDI = 1, /*!< JTAG Test Data In */ + FUNC_JTAG_TMS = 2, /*!< JTAG Test Mode Select */ + FUNC_JTAG_TDO = 3, /*!< JTAG Test Data Out */ + FUNC_SPI0_D0 = 4, /*!< SPI0 Data 0 */ + FUNC_SPI0_D1 = 5, /*!< SPI0 Data 1 */ + FUNC_SPI0_D2 = 6, /*!< SPI0 Data 2 */ + FUNC_SPI0_D3 = 7, /*!< SPI0 Data 3 */ + FUNC_SPI0_D4 = 8, /*!< SPI0 Data 4 */ + FUNC_SPI0_D5 = 9, /*!< SPI0 Data 5 */ + FUNC_SPI0_D6 = 10, /*!< SPI0 Data 6 */ + FUNC_SPI0_D7 = 11, /*!< SPI0 Data 7 */ + FUNC_SPI0_SS0 = 12, /*!< SPI0 Chip Select 0 */ + FUNC_SPI0_SS1 = 13, /*!< SPI0 Chip Select 1 */ + FUNC_SPI0_SS2 = 14, /*!< SPI0 Chip Select 2 */ + FUNC_SPI0_SS3 = 15, /*!< SPI0 Chip Select 3 */ + FUNC_SPI0_ARB = 16, /*!< SPI0 Arbitration */ + FUNC_SPI0_SCLK = 17, /*!< SPI0 Serial Clock */ + FUNC_UARTHS_RX = 18, /*!< UART High speed Receiver */ + FUNC_UARTHS_TX = 19, /*!< UART High speed Transmitter */ + FUNC_RESV6 = 20, /*!< Reserved function */ + FUNC_RESV7 = 21, /*!< Reserved function */ + FUNC_CLK_SPI1 = 22, /*!< Clock SPI1 */ + FUNC_CLK_I2C1 = 23, /*!< Clock I2C1 */ + FUNC_GPIOHS0 = 24, /*!< GPIO High speed 0 */ + FUNC_GPIOHS1 = 25, /*!< GPIO High speed 1 */ + FUNC_GPIOHS2 = 26, /*!< GPIO High speed 2 */ + FUNC_GPIOHS3 = 27, /*!< GPIO High speed 3 */ + FUNC_GPIOHS4 = 28, /*!< GPIO High speed 4 */ + FUNC_GPIOHS5 = 29, /*!< GPIO High speed 5 */ + FUNC_GPIOHS6 = 30, /*!< GPIO High speed 6 */ + FUNC_GPIOHS7 = 31, /*!< GPIO High speed 7 */ + FUNC_GPIOHS8 = 32, /*!< GPIO High speed 8 */ + FUNC_GPIOHS9 = 33, /*!< GPIO High speed 9 */ + FUNC_GPIOHS10 = 34, /*!< GPIO High speed 10 */ + FUNC_GPIOHS11 = 35, /*!< GPIO High speed 11 */ + FUNC_GPIOHS12 = 36, /*!< GPIO High speed 12 */ + FUNC_GPIOHS13 = 37, /*!< GPIO High speed 13 */ + FUNC_GPIOHS14 = 38, /*!< GPIO High speed 14 */ + FUNC_GPIOHS15 = 39, /*!< GPIO High speed 15 */ + FUNC_GPIOHS16 = 40, /*!< GPIO High speed 16 */ + FUNC_GPIOHS17 = 41, /*!< GPIO High speed 17 */ + FUNC_GPIOHS18 = 42, /*!< GPIO High speed 18 */ + FUNC_GPIOHS19 = 43, /*!< GPIO High speed 19 */ + FUNC_GPIOHS20 = 44, /*!< GPIO High speed 20 */ + FUNC_GPIOHS21 = 45, /*!< GPIO High speed 21 */ + FUNC_GPIOHS22 = 46, /*!< GPIO High speed 22 */ + FUNC_GPIOHS23 = 47, /*!< GPIO High speed 23 */ + FUNC_GPIOHS24 = 48, /*!< GPIO High speed 24 */ + FUNC_GPIOHS25 = 49, /*!< GPIO High speed 25 */ + FUNC_GPIOHS26 = 50, /*!< GPIO High speed 26 */ + FUNC_GPIOHS27 = 51, /*!< GPIO High speed 27 */ + FUNC_GPIOHS28 = 52, /*!< GPIO High speed 28 */ + FUNC_GPIOHS29 = 53, /*!< GPIO High speed 29 */ + FUNC_GPIOHS30 = 54, /*!< GPIO High speed 30 */ + FUNC_GPIOHS31 = 55, /*!< GPIO High speed 31 */ + FUNC_GPIO0 = 56, /*!< GPIO pin 0 */ + FUNC_GPIO1 = 57, /*!< GPIO pin 1 */ + FUNC_GPIO2 = 58, /*!< GPIO pin 2 */ + FUNC_GPIO3 = 59, /*!< GPIO pin 3 */ + FUNC_GPIO4 = 60, /*!< GPIO pin 4 */ + FUNC_GPIO5 = 61, /*!< GPIO pin 5 */ + FUNC_GPIO6 = 62, /*!< GPIO pin 6 */ + FUNC_GPIO7 = 63, /*!< GPIO pin 7 */ + FUNC_UART1_RX = 64, /*!< UART1 Receiver */ + FUNC_UART1_TX = 65, /*!< UART1 Transmitter */ + FUNC_UART2_RX = 66, /*!< UART2 Receiver */ + FUNC_UART2_TX = 67, /*!< UART2 Transmitter */ + FUNC_UART3_RX = 68, /*!< UART3 Receiver */ + FUNC_UART3_TX = 69, /*!< UART3 Transmitter */ + FUNC_SPI1_D0 = 70, /*!< SPI1 Data 0 */ + FUNC_SPI1_D1 = 71, /*!< SPI1 Data 1 */ + FUNC_SPI1_D2 = 72, /*!< SPI1 Data 2 */ + FUNC_SPI1_D3 = 73, /*!< SPI1 Data 3 */ + FUNC_SPI1_D4 = 74, /*!< SPI1 Data 4 */ + FUNC_SPI1_D5 = 75, /*!< SPI1 Data 5 */ + FUNC_SPI1_D6 = 76, /*!< SPI1 Data 6 */ + FUNC_SPI1_D7 = 77, /*!< SPI1 Data 7 */ + FUNC_SPI1_SS0 = 78, /*!< SPI1 Chip Select 0 */ + FUNC_SPI1_SS1 = 79, /*!< SPI1 Chip Select 1 */ + FUNC_SPI1_SS2 = 80, /*!< SPI1 Chip Select 2 */ + FUNC_SPI1_SS3 = 81, /*!< SPI1 Chip Select 3 */ + FUNC_SPI1_ARB = 82, /*!< SPI1 Arbitration */ + FUNC_SPI1_SCLK = 83, /*!< SPI1 Serial Clock */ + FUNC_SPI_SLAVE_D0 = 84, /*!< SPI Slave Data 0 */ + FUNC_SPI_SLAVE_SS = 85, /*!< SPI Slave Select */ + FUNC_SPI_SLAVE_SCLK = 86, /*!< SPI Slave Serial Clock */ + FUNC_I2S0_MCLK = 87, /*!< I2S0 Master Clock */ + FUNC_I2S0_SCLK = 88, /*!< I2S0 Serial Clock(BCLK) */ + FUNC_I2S0_WS = 89, /*!< I2S0 Word Select(LRCLK) */ + FUNC_I2S0_IN_D0 = 90, /*!< I2S0 Serial Data Input 0 */ + FUNC_I2S0_IN_D1 = 91, /*!< I2S0 Serial Data Input 1 */ + FUNC_I2S0_IN_D2 = 92, /*!< I2S0 Serial Data Input 2 */ + FUNC_I2S0_IN_D3 = 93, /*!< I2S0 Serial Data Input 3 */ + FUNC_I2S0_OUT_D0 = 94, /*!< I2S0 Serial Data Output 0 */ + FUNC_I2S0_OUT_D1 = 95, /*!< I2S0 Serial Data Output 1 */ + FUNC_I2S0_OUT_D2 = 96, /*!< I2S0 Serial Data Output 2 */ + FUNC_I2S0_OUT_D3 = 97, /*!< I2S0 Serial Data Output 3 */ + FUNC_I2S1_MCLK = 98, /*!< I2S1 Master Clock */ + FUNC_I2S1_SCLK = 99, /*!< I2S1 Serial Clock(BCLK) */ + FUNC_I2S1_WS = 100, /*!< I2S1 Word Select(LRCLK) */ + FUNC_I2S1_IN_D0 = 101, /*!< I2S1 Serial Data Input 0 */ + FUNC_I2S1_IN_D1 = 102, /*!< I2S1 Serial Data Input 1 */ + FUNC_I2S1_IN_D2 = 103, /*!< I2S1 Serial Data Input 2 */ + FUNC_I2S1_IN_D3 = 104, /*!< I2S1 Serial Data Input 3 */ + FUNC_I2S1_OUT_D0 = 105, /*!< I2S1 Serial Data Output 0 */ + FUNC_I2S1_OUT_D1 = 106, /*!< I2S1 Serial Data Output 1 */ + FUNC_I2S1_OUT_D2 = 107, /*!< I2S1 Serial Data Output 2 */ + FUNC_I2S1_OUT_D3 = 108, /*!< I2S1 Serial Data Output 3 */ + FUNC_I2S2_MCLK = 109, /*!< I2S2 Master Clock */ + FUNC_I2S2_SCLK = 110, /*!< I2S2 Serial Clock(BCLK) */ + FUNC_I2S2_WS = 111, /*!< I2S2 Word Select(LRCLK) */ + FUNC_I2S2_IN_D0 = 112, /*!< I2S2 Serial Data Input 0 */ + FUNC_I2S2_IN_D1 = 113, /*!< I2S2 Serial Data Input 1 */ + FUNC_I2S2_IN_D2 = 114, /*!< I2S2 Serial Data Input 2 */ + FUNC_I2S2_IN_D3 = 115, /*!< I2S2 Serial Data Input 3 */ + FUNC_I2S2_OUT_D0 = 116, /*!< I2S2 Serial Data Output 0 */ + FUNC_I2S2_OUT_D1 = 117, /*!< I2S2 Serial Data Output 1 */ + FUNC_I2S2_OUT_D2 = 118, /*!< I2S2 Serial Data Output 2 */ + FUNC_I2S2_OUT_D3 = 119, /*!< I2S2 Serial Data Output 3 */ + FUNC_RESV0 = 120, /*!< Reserved function */ + FUNC_RESV1 = 121, /*!< Reserved function */ + FUNC_RESV2 = 122, /*!< Reserved function */ + FUNC_RESV3 = 123, /*!< Reserved function */ + FUNC_RESV4 = 124, /*!< Reserved function */ + FUNC_RESV5 = 125, /*!< Reserved function */ + FUNC_I2C0_SCLK = 126, /*!< I2C0 Serial Clock */ + FUNC_I2C0_SDA = 127, /*!< I2C0 Serial Data */ + FUNC_I2C1_SCLK = 128, /*!< I2C1 Serial Clock */ + FUNC_I2C1_SDA = 129, /*!< I2C1 Serial Data */ + FUNC_I2C2_SCLK = 130, /*!< I2C2 Serial Clock */ + FUNC_I2C2_SDA = 131, /*!< I2C2 Serial Data */ + FUNC_CMOS_XCLK = 132, /*!< DVP System Clock */ + FUNC_CMOS_RST = 133, /*!< DVP System Reset */ + FUNC_CMOS_PWDN = 134, /*!< DVP Power Down Mode */ + FUNC_CMOS_VSYNC = 135, /*!< DVP Vertical Sync */ + FUNC_CMOS_HREF = 136, /*!< DVP Horizontal Reference output */ + FUNC_CMOS_PCLK = 137, /*!< Pixel Clock */ + FUNC_CMOS_D0 = 138, /*!< Data Bit 0 */ + FUNC_CMOS_D1 = 139, /*!< Data Bit 1 */ + FUNC_CMOS_D2 = 140, /*!< Data Bit 2 */ + FUNC_CMOS_D3 = 141, /*!< Data Bit 3 */ + FUNC_CMOS_D4 = 142, /*!< Data Bit 4 */ + FUNC_CMOS_D5 = 143, /*!< Data Bit 5 */ + FUNC_CMOS_D6 = 144, /*!< Data Bit 6 */ + FUNC_CMOS_D7 = 145, /*!< Data Bit 7 */ + FUNC_SCCB_SCLK = 146, /*!< SCCB Serial Clock */ + FUNC_SCCB_SDA = 147, /*!< SCCB Serial Data */ + FUNC_UART1_CTS = 148, /*!< UART1 Clear To Send */ + FUNC_UART1_DSR = 149, /*!< UART1 Data Set Ready */ + FUNC_UART1_DCD = 150, /*!< UART1 Data Carrier Detect */ + FUNC_UART1_RI = 151, /*!< UART1 Ring Indicator */ + FUNC_UART1_SIR_IN = 152, /*!< UART1 Serial Infrared Input */ + FUNC_UART1_DTR = 153, /*!< UART1 Data Terminal Ready */ + FUNC_UART1_RTS = 154, /*!< UART1 Request To Send */ + FUNC_UART1_OUT2 = 155, /*!< UART1 User-designated Output 2 */ + FUNC_UART1_OUT1 = 156, /*!< UART1 User-designated Output 1 */ + FUNC_UART1_SIR_OUT = 157, /*!< UART1 Serial Infrared Output */ + FUNC_UART1_BAUD = 158, /*!< UART1 Transmit Clock Output */ + FUNC_UART1_RE = 159, /*!< UART1 Receiver Output Enable */ + FUNC_UART1_DE = 160, /*!< UART1 Driver Output Enable */ + FUNC_UART1_RS485_EN = 161, /*!< UART1 RS485 Enable */ + FUNC_UART2_CTS = 162, /*!< UART2 Clear To Send */ + FUNC_UART2_DSR = 163, /*!< UART2 Data Set Ready */ + FUNC_UART2_DCD = 164, /*!< UART2 Data Carrier Detect */ + FUNC_UART2_RI = 165, /*!< UART2 Ring Indicator */ + FUNC_UART2_SIR_IN = 166, /*!< UART2 Serial Infrared Input */ + FUNC_UART2_DTR = 167, /*!< UART2 Data Terminal Ready */ + FUNC_UART2_RTS = 168, /*!< UART2 Request To Send */ + FUNC_UART2_OUT2 = 169, /*!< UART2 User-designated Output 2 */ + FUNC_UART2_OUT1 = 170, /*!< UART2 User-designated Output 1 */ + FUNC_UART2_SIR_OUT = 171, /*!< UART2 Serial Infrared Output */ + FUNC_UART2_BAUD = 172, /*!< UART2 Transmit Clock Output */ + FUNC_UART2_RE = 173, /*!< UART2 Receiver Output Enable */ + FUNC_UART2_DE = 174, /*!< UART2 Driver Output Enable */ + FUNC_UART2_RS485_EN = 175, /*!< UART2 RS485 Enable */ + FUNC_UART3_CTS = 176, /*!< UART3 Clear To Send */ + FUNC_UART3_DSR = 177, /*!< UART3 Data Set Ready */ + FUNC_UART3_DCD = 178, /*!< UART3 Data Carrier Detect */ + FUNC_UART3_RI = 179, /*!< UART3 Ring Indicator */ + FUNC_UART3_SIR_IN = 180, /*!< UART3 Serial Infrared Input */ + FUNC_UART3_DTR = 181, /*!< UART3 Data Terminal Ready */ + FUNC_UART3_RTS = 182, /*!< UART3 Request To Send */ + FUNC_UART3_OUT2 = 183, /*!< UART3 User-designated Output 2 */ + FUNC_UART3_OUT1 = 184, /*!< UART3 User-designated Output 1 */ + FUNC_UART3_SIR_OUT = 185, /*!< UART3 Serial Infrared Output */ + FUNC_UART3_BAUD = 186, /*!< UART3 Transmit Clock Output */ + FUNC_UART3_RE = 187, /*!< UART3 Receiver Output Enable */ + FUNC_UART3_DE = 188, /*!< UART3 Driver Output Enable */ + FUNC_UART3_RS485_EN = 189, /*!< UART3 RS485 Enable */ + FUNC_TIMER0_TOGGLE1 = 190, /*!< TIMER0 Toggle Output 1 */ + FUNC_TIMER0_TOGGLE2 = 191, /*!< TIMER0 Toggle Output 2 */ + FUNC_TIMER0_TOGGLE3 = 192, /*!< TIMER0 Toggle Output 3 */ + FUNC_TIMER0_TOGGLE4 = 193, /*!< TIMER0 Toggle Output 4 */ + FUNC_TIMER1_TOGGLE1 = 194, /*!< TIMER1 Toggle Output 1 */ + FUNC_TIMER1_TOGGLE2 = 195, /*!< TIMER1 Toggle Output 2 */ + FUNC_TIMER1_TOGGLE3 = 196, /*!< TIMER1 Toggle Output 3 */ + FUNC_TIMER1_TOGGLE4 = 197, /*!< TIMER1 Toggle Output 4 */ + FUNC_TIMER2_TOGGLE1 = 198, /*!< TIMER2 Toggle Output 1 */ + FUNC_TIMER2_TOGGLE2 = 199, /*!< TIMER2 Toggle Output 2 */ + FUNC_TIMER2_TOGGLE3 = 200, /*!< TIMER2 Toggle Output 3 */ + FUNC_TIMER2_TOGGLE4 = 201, /*!< TIMER2 Toggle Output 4 */ + FUNC_CLK_SPI2 = 202, /*!< Clock SPI2 */ + FUNC_CLK_I2C2 = 203, /*!< Clock I2C2 */ + FUNC_INTERNAL0 = 204, /*!< Internal function signal 0 */ + FUNC_INTERNAL1 = 205, /*!< Internal function signal 1 */ + FUNC_INTERNAL2 = 206, /*!< Internal function signal 2 */ + FUNC_INTERNAL3 = 207, /*!< Internal function signal 3 */ + FUNC_INTERNAL4 = 208, /*!< Internal function signal 4 */ + FUNC_INTERNAL5 = 209, /*!< Internal function signal 5 */ + FUNC_INTERNAL6 = 210, /*!< Internal function signal 6 */ + FUNC_INTERNAL7 = 211, /*!< Internal function signal 7 */ + FUNC_INTERNAL8 = 212, /*!< Internal function signal 8 */ + FUNC_INTERNAL9 = 213, /*!< Internal function signal 9 */ + FUNC_INTERNAL10 = 214, /*!< Internal function signal 10 */ + FUNC_INTERNAL11 = 215, /*!< Internal function signal 11 */ + FUNC_INTERNAL12 = 216, /*!< Internal function signal 12 */ + FUNC_INTERNAL13 = 217, /*!< Internal function signal 13 */ + FUNC_INTERNAL14 = 218, /*!< Internal function signal 14 */ + FUNC_INTERNAL15 = 219, /*!< Internal function signal 15 */ + FUNC_INTERNAL16 = 220, /*!< Internal function signal 16 */ + FUNC_INTERNAL17 = 221, /*!< Internal function signal 17 */ + FUNC_CONSTANT = 222, /*!< Constant function */ + FUNC_INTERNAL18 = 223, /*!< Internal function signal 18 */ + FUNC_DEBUG0 = 224, /*!< Debug function 0 */ + FUNC_DEBUG1 = 225, /*!< Debug function 1 */ + FUNC_DEBUG2 = 226, /*!< Debug function 2 */ + FUNC_DEBUG3 = 227, /*!< Debug function 3 */ + FUNC_DEBUG4 = 228, /*!< Debug function 4 */ + FUNC_DEBUG5 = 229, /*!< Debug function 5 */ + FUNC_DEBUG6 = 230, /*!< Debug function 6 */ + FUNC_DEBUG7 = 231, /*!< Debug function 7 */ + FUNC_DEBUG8 = 232, /*!< Debug function 8 */ + FUNC_DEBUG9 = 233, /*!< Debug function 9 */ + FUNC_DEBUG10 = 234, /*!< Debug function 10 */ + FUNC_DEBUG11 = 235, /*!< Debug function 11 */ + FUNC_DEBUG12 = 236, /*!< Debug function 12 */ + FUNC_DEBUG13 = 237, /*!< Debug function 13 */ + FUNC_DEBUG14 = 238, /*!< Debug function 14 */ + FUNC_DEBUG15 = 239, /*!< Debug function 15 */ + FUNC_DEBUG16 = 240, /*!< Debug function 16 */ + FUNC_DEBUG17 = 241, /*!< Debug function 17 */ + FUNC_DEBUG18 = 242, /*!< Debug function 18 */ + FUNC_DEBUG19 = 243, /*!< Debug function 19 */ + FUNC_DEBUG20 = 244, /*!< Debug function 20 */ + FUNC_DEBUG21 = 245, /*!< Debug function 21 */ + FUNC_DEBUG22 = 246, /*!< Debug function 22 */ + FUNC_DEBUG23 = 247, /*!< Debug function 23 */ + FUNC_DEBUG24 = 248, /*!< Debug function 24 */ + FUNC_DEBUG25 = 249, /*!< Debug function 25 */ + FUNC_DEBUG26 = 250, /*!< Debug function 26 */ + FUNC_DEBUG27 = 251, /*!< Debug function 27 */ + FUNC_DEBUG28 = 252, /*!< Debug function 28 */ + FUNC_DEBUG29 = 253, /*!< Debug function 29 */ + FUNC_DEBUG30 = 254, /*!< Debug function 30 */ + FUNC_DEBUG31 = 255, /*!< Debug function 31 */ + FUNC_MAX = 256, /*!< Function numbers */ +} fpioa_function_t; +/* clang-format on */ + +/** + * @brief FPIOA pull settings + * + * @note FPIOA pull settings description + * + * | PU | PD | Description | + * |-----|-----|-----------------------------------| + * | 0 | 0 | No Pull | + * | 0 | 1 | Pull Down | + * | 1 | 0 | Pull Up | + * | 1 | 1 | Undefined | + * + */ + +/* clang-format off */ +typedef enum _fpioa_pull +{ + FPIOA_PULL_NONE, /*!< No Pull */ + FPIOA_PULL_DOWN, /*!< Pull Down */ + FPIOA_PULL_UP, /*!< Pull Up */ + FPIOA_PULL_MAX /*!< Count of pull settings */ +} fpioa_pull_t; +/* clang-format on */ + +/** + * @brief FPIOA driving settings + * + * @note FPIOA driving settings description + * There are 16 kinds of driving settings + * + * @note Low Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |3.2 |5.4 |8.3 | + * |0001 |4.7 |8.0 |12.3 | + * |0010 |6.3 |10.7 |16.4 | + * |0011 |7.8 |13.2 |20.2 | + * |0100 |9.4 |15.9 |24.2 | + * |0101 |10.9 |18.4 |28.1 | + * |0110 |12.4 |20.9 |31.8 | + * |0111 |13.9 |23.4 |35.5 | + * + * @note High Level Output Current + * + * |DS[3:0] |Min(mA)|Typ(mA)|Max(mA)| + * |--------|-------|-------|-------| + * |0000 |5.0 |7.6 |11.2 | + * |0001 |7.5 |11.4 |16.8 | + * |0010 |10.0 |15.2 |22.3 | + * |0011 |12.4 |18.9 |27.8 | + * |0100 |14.9 |22.6 |33.3 | + * |0101 |17.4 |26.3 |38.7 | + * |0110 |19.8 |30.0 |44.1 | + * |0111 |22.3 |33.7 |49.5 | + * + */ + +/* clang-format off */ +typedef enum _fpioa_driving +{ + FPIOA_DRIVING_0, /*!< 0000 */ + FPIOA_DRIVING_1, /*!< 0001 */ + FPIOA_DRIVING_2, /*!< 0010 */ + FPIOA_DRIVING_3, /*!< 0011 */ + FPIOA_DRIVING_4, /*!< 0100 */ + FPIOA_DRIVING_5, /*!< 0101 */ + FPIOA_DRIVING_6, /*!< 0110 */ + FPIOA_DRIVING_7, /*!< 0111 */ + FPIOA_DRIVING_8, /*!< 1000 */ + FPIOA_DRIVING_9, /*!< 1001 */ + FPIOA_DRIVING_10, /*!< 1010 */ + FPIOA_DRIVING_11, /*!< 1011 */ + FPIOA_DRIVING_12, /*!< 1100 */ + FPIOA_DRIVING_13, /*!< 1101 */ + FPIOA_DRIVING_14, /*!< 1110 */ + FPIOA_DRIVING_15, /*!< 1111 */ + FPIOA_DRIVING_MAX /*!< Count of driving settings */ +} fpioa_driving_t; +/* clang-format on */ + +/** + * @brief FPIOA IO + * + * FPIOA IO is the specific pin of the chip package. Every IO + * has a 32bit width register that can independently implement + * schmitt trigger, invert input, invert output, strong pull + * up, driving selector, static input and static output. And more, + * it can implement any pin of any peripheral devices. + * + * @note FPIOA IO's register bits Layout + * + * | Bits | Name |Description | + * |-----------|----------|---------------------------------------------------| + * | 31 | PAD_DI | Read current IO's data input. | + * | 30:24 | NA | Reserved bits. | + * | 23 | ST | Schmitt trigger. | + * | 22 | DI_INV | Invert Data input. | + * | 21 | IE_INV | Invert the input enable signal. | + * | 20 | IE_EN | Input enable. It can disable or enable IO input. | + * | 19 | SL | Slew rate control enable. | + * | 18 | SPU | Strong pull up. | + * | 17 | PD | Pull select: 0 for pull down, 1 for pull up. | + * | 16 | PU | Pull enable. | + * | 15 | DO_INV | Invert the result of data output select (DO_SEL). | + * | 14 | DO_SEL | Data output select: 0 for DO, 1 for OE. | + * | 13 | OE_INV | Invert the output enable signal. | + * | 12 | OE_EN | Output enable.It can disable or enable IO output. | + * | 11:8 | DS | Driving selector. | + * | 7:0 | CH_SEL | Channel select from 256 input. | + * + */ +typedef struct _fpioa_io_config +{ + uint32_t ch_sel : 8; + /*!< Channel select from 256 input. */ + uint32_t ds : 4; + /*!< Driving selector. */ + uint32_t oe_en : 1; + /*!< Static output enable, will AND with OE_INV. */ + uint32_t oe_inv : 1; + /*!< Invert output enable. */ + uint32_t do_sel : 1; + /*!< Data output select: 0 for DO, 1 for OE. */ + uint32_t do_inv : 1; + /*!< Invert the result of data output select (DO_SEL). */ + uint32_t pu : 1; + /*!< Pull up enable. 0 for nothing, 1 for pull up. */ + uint32_t pd : 1; + /*!< Pull down enable. 0 for nothing, 1 for pull down. */ + uint32_t resv0 : 1; + /*!< Reserved bits. */ + uint32_t sl : 1; + /*!< Slew rate control enable. */ + uint32_t ie_en : 1; + /*!< Static input enable, will AND with IE_INV. */ + uint32_t ie_inv : 1; + /*!< Invert input enable. */ + uint32_t di_inv : 1; + /*!< Invert Data input. */ + uint32_t st : 1; + /*!< Schmitt trigger. */ + uint32_t resv1 : 7; + /*!< Reserved bits. */ + uint32_t pad_di : 1; + /*!< Read current IO's data input. */ +} __attribute__((packed, aligned(4))) fpioa_io_config_t; + +/** + * @brief FPIOA tie setting + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA function tie bits RAM Layout + * + * | Address | Name |Description | + * |-----------|------------------|----------------------------------| + * | 0x000 | TIE_EN[31:0] | Input tie enable bits [31:0] | + * | 0x004 | TIE_EN[63:32] | Input tie enable bits [63:32] | + * | 0x008 | TIE_EN[95:64] | Input tie enable bits [95:64] | + * | 0x00C | TIE_EN[127:96] | Input tie enable bits [127:96] | + * | 0x010 | TIE_EN[159:128] | Input tie enable bits [159:128] | + * | 0x014 | TIE_EN[191:160] | Input tie enable bits [191:160] | + * | 0x018 | TIE_EN[223:192] | Input tie enable bits [223:192] | + * | 0x01C | TIE_EN[255:224] | Input tie enable bits [255:224] | + * | 0x020 | TIE_VAL[31:0] | Input tie value bits [31:0] | + * | 0x024 | TIE_VAL[63:32] | Input tie value bits [63:32] | + * | 0x028 | TIE_VAL[95:64] | Input tie value bits [95:64] | + * | 0x02C | TIE_VAL[127:96] | Input tie value bits [127:96] | + * | 0x030 | TIE_VAL[159:128] | Input tie value bits [159:128] | + * | 0x034 | TIE_VAL[191:160] | Input tie value bits [191:160] | + * | 0x038 | TIE_VAL[223:192] | Input tie value bits [223:192] | + * | 0x03C | TIE_VAL[255:224] | Input tie value bits [255:224] | + * + * @note Function which input tie high by default + * + * | Name |Description | + * |---------------|---------------------------------------| + * | SPI0_ARB | Arbitration function of SPI master 0 | + * | SPI1_ARB | Arbitration function of SPI master 1 | + * + * Tie high means the SPI Arbitration input is 1 + * + */ +typedef struct _fpioa_tie +{ + uint32_t en[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie enable array */ + uint32_t val[FUNC_MAX / 32]; + /*!< FPIOA GPIO multiplexer tie value array */ +} __attribute__((packed, aligned(4))) fpioa_tie_t; + +/** + * @brief FPIOA Object + * + * FPIOA Object have 48 IO pin object and 256 bit input tie bits. + * All SPI arbitration signal will tie high by default. + * + * @note FPIOA IO Pin RAM Layout + * + * | Address | Name |Description | + * |-----------|----------|--------------------------------| + * | 0x000 | PAD0 | FPIOA GPIO multiplexer io 0 | + * | 0x004 | PAD1 | FPIOA GPIO multiplexer io 1 | + * | 0x008 | PAD2 | FPIOA GPIO multiplexer io 2 | + * | 0x00C | PAD3 | FPIOA GPIO multiplexer io 3 | + * | 0x010 | PAD4 | FPIOA GPIO multiplexer io 4 | + * | 0x014 | PAD5 | FPIOA GPIO multiplexer io 5 | + * | 0x018 | PAD6 | FPIOA GPIO multiplexer io 6 | + * | 0x01C | PAD7 | FPIOA GPIO multiplexer io 7 | + * | 0x020 | PAD8 | FPIOA GPIO multiplexer io 8 | + * | 0x024 | PAD9 | FPIOA GPIO multiplexer io 9 | + * | 0x028 | PAD10 | FPIOA GPIO multiplexer io 10 | + * | 0x02C | PAD11 | FPIOA GPIO multiplexer io 11 | + * | 0x030 | PAD12 | FPIOA GPIO multiplexer io 12 | + * | 0x034 | PAD13 | FPIOA GPIO multiplexer io 13 | + * | 0x038 | PAD14 | FPIOA GPIO multiplexer io 14 | + * | 0x03C | PAD15 | FPIOA GPIO multiplexer io 15 | + * | 0x040 | PAD16 | FPIOA GPIO multiplexer io 16 | + * | 0x044 | PAD17 | FPIOA GPIO multiplexer io 17 | + * | 0x048 | PAD18 | FPIOA GPIO multiplexer io 18 | + * | 0x04C | PAD19 | FPIOA GPIO multiplexer io 19 | + * | 0x050 | PAD20 | FPIOA GPIO multiplexer io 20 | + * | 0x054 | PAD21 | FPIOA GPIO multiplexer io 21 | + * | 0x058 | PAD22 | FPIOA GPIO multiplexer io 22 | + * | 0x05C | PAD23 | FPIOA GPIO multiplexer io 23 | + * | 0x060 | PAD24 | FPIOA GPIO multiplexer io 24 | + * | 0x064 | PAD25 | FPIOA GPIO multiplexer io 25 | + * | 0x068 | PAD26 | FPIOA GPIO multiplexer io 26 | + * | 0x06C | PAD27 | FPIOA GPIO multiplexer io 27 | + * | 0x070 | PAD28 | FPIOA GPIO multiplexer io 28 | + * | 0x074 | PAD29 | FPIOA GPIO multiplexer io 29 | + * | 0x078 | PAD30 | FPIOA GPIO multiplexer io 30 | + * | 0x07C | PAD31 | FPIOA GPIO multiplexer io 31 | + * | 0x080 | PAD32 | FPIOA GPIO multiplexer io 32 | + * | 0x084 | PAD33 | FPIOA GPIO multiplexer io 33 | + * | 0x088 | PAD34 | FPIOA GPIO multiplexer io 34 | + * | 0x08C | PAD35 | FPIOA GPIO multiplexer io 35 | + * | 0x090 | PAD36 | FPIOA GPIO multiplexer io 36 | + * | 0x094 | PAD37 | FPIOA GPIO multiplexer io 37 | + * | 0x098 | PAD38 | FPIOA GPIO multiplexer io 38 | + * | 0x09C | PAD39 | FPIOA GPIO multiplexer io 39 | + * | 0x0A0 | PAD40 | FPIOA GPIO multiplexer io 40 | + * | 0x0A4 | PAD41 | FPIOA GPIO multiplexer io 41 | + * | 0x0A8 | PAD42 | FPIOA GPIO multiplexer io 42 | + * | 0x0AC | PAD43 | FPIOA GPIO multiplexer io 43 | + * | 0x0B0 | PAD44 | FPIOA GPIO multiplexer io 44 | + * | 0x0B4 | PAD45 | FPIOA GPIO multiplexer io 45 | + * | 0x0B8 | PAD46 | FPIOA GPIO multiplexer io 46 | + * | 0x0BC | PAD47 | FPIOA GPIO multiplexer io 47 | + * + */ +typedef struct _fpioa +{ + fpioa_io_config_t io[FPIOA_NUM_IO]; + /*!< FPIOA GPIO multiplexer io array */ + fpioa_tie_t tie; + /*!< FPIOA GPIO multiplexer tie */ +} __attribute__((packed, aligned(4))) fpioa_t; + +/** + * @brief FPIOA object instanse + */ +extern volatile fpioa_t *const fpioa; + +/** + * @brief Initialize FPIOA user custom default settings + * + * @note This function will set all FPIOA pad registers to user-defined + * values from kconfig + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_init(void); + +/** + * @brief Get IO configuration + * + * @param[in] number The IO number + * @param cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_get_io(int number, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration + * + * @param[in] number The IO number + * @param[in] cfg Pointer to struct of IO configuration for specified IO + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io(int number, fpioa_io_config_t *cfg); + +/** + * @brief Set IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function_raw(int number, fpioa_function_t function); + +/** + * @brief Set only IO configuration with function number + * + * @note The default IO configuration which bind to function number will + * set automatically + * + * @param[in] number The IO number + * @param[in] function The function enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_function(int number, fpioa_function_t function); + +/** + * @brief Set tie enable to function + * + * @param[in] function The function enum number + * @param[in] enable Tie enable to set, 1 is enable, 0 is disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_enable(fpioa_function_t function, int enable); + +/** + * @brief Set tie value to function + * + * @param[in] function The function enum number + * @param[in] value Tie value to set, 1 is HIGH, 0 is LOW + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_tie_value(fpioa_function_t function, int value); + +/** + * @brief Set IO pull function + * + * @param[in] number The IO number + * @param[in] pull The pull enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_pull(int number, fpioa_pull_t pull); + +/** + * @brief Get IO pull function + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The pull enum number + */ +int fpioa_get_io_pull(int number); + +/** + * @brief Set IO driving + * + * @param[in] number The IO number + * @param[in] driving The driving enum number + * + * @return result + * - 0 Success + * - Other Fail + */ +int fpioa_set_io_driving(int number, fpioa_driving_t driving); + +/** + * @brief Get IO driving + * + * @param[in] number The IO number + * + * @return result + * - -1 Fail + * - Other The driving enum number + */ +int fpioa_get_io_driving(int number); + +/** + * @brief Get IO by function + * + * @param[in] function The function enum number + * + * @return result + * - -1 Fail + * - Other The IO number + */ +int fpioa_get_io_by_function(fpioa_function_t function); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_FPIOA_H */ + diff --git a/lib/drivers/include/gpio.h b/lib/drivers/include/gpio.h new file mode 100755 index 0000000..9d96e17 --- /dev/null +++ b/lib/drivers/include/gpio.h @@ -0,0 +1,168 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_GPIO_H +#define _DRIVER_GPIO_H + +#include "platform.h" +#include +#include +#include "gpio_common.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Structure for accessing GPIO registers by individual bit + */ +typedef struct _gpio_bits +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpio_bits_t; + +/** + * @brief Structure of templates for accessing GPIO registers + */ +typedef union _gpio_access_tp +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpio_bits_t bits; +} __attribute__((packed, aligned(4))) gpio_access_tp_t; + +/** + * @brief The GPIO address map + */ +typedef struct _gpio +{ + /* Offset 0x00: Data (output) registers */ + gpio_access_tp_t data_output; + /* Offset 0x04: Data direction registers */ + gpio_access_tp_t direction; + /* Offset 0x08: Data source registers */ + gpio_access_tp_t source; + /* Offset 0x10 - 0x2f: Unused registers, 9x4 bytes */ + uint32_t unused_0[9]; + /* Offset 0x30: Interrupt enable/disable registers */ + gpio_access_tp_t interrupt_enable; + /* Offset 0x34: Interrupt mask registers */ + gpio_access_tp_t interrupt_mask; + /* Offset 0x38: Interrupt level registers */ + gpio_access_tp_t interrupt_level; + /* Offset 0x3c: Interrupt polarity registers */ + gpio_access_tp_t interrupt_polarity; + /* Offset 0x40: Interrupt status registers */ + gpio_access_tp_t interrupt_status; + /* Offset 0x44: Raw interrupt status registers */ + gpio_access_tp_t interrupt_status_raw; + /* Offset 0x48: Interrupt debounce registers */ + gpio_access_tp_t interrupt_debounce; + /* Offset 0x4c: Registers for clearing interrupts */ + gpio_access_tp_t interrupt_clear; + /* Offset 0x50: External port (data input) registers */ + gpio_access_tp_t data_input; + /* Offset 0x54 - 0x5f: Unused registers, 3x4 bytes */ + uint32_t unused_1[3]; + /* Offset 0x60: Sync level registers */ + gpio_access_tp_t sync_level; + /* Offset 0x64: ID code */ + gpio_access_tp_t id_code; + /* Offset 0x68: Interrupt both edge type */ + gpio_access_tp_t interrupt_bothedge; + +} __attribute__((packed, aligned(4))) gpio_t; + +/** + * @brief Bus GPIO object instance + */ +extern volatile gpio_t *const gpio; + +/** + * @brief Gpio initialize + * + * @return Result + * - 0 Success + * - Other Fail + */ +int gpio_init(void); + +/** + * @brief Set Gpio drive mode + * + * @param[in] pin Gpio pin + * @param[in] mode Gpio pin drive mode + */ +void gpio_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode); + +/** + * @brief Get Gpio pin value + * + * @param[in] pin Gpio pin + * @return Pin value + * + * - GPIO_PV_Low Gpio pin low + * - GPIO_PV_High Gpio pin high + */ +gpio_pin_value_t gpio_get_pin(uint8_t pin); + +/** + * @brief Set Gpio pin value + * + * @param[in] pin Gpio pin + * @param[in] value Gpio pin value + */ +void gpio_set_pin(uint8_t pin, gpio_pin_value_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_GPIO_H */ + diff --git a/lib/drivers/include/gpio_common.h b/lib/drivers/include/gpio_common.h new file mode 100755 index 0000000..af402f0 --- /dev/null +++ b/lib/drivers/include/gpio_common.h @@ -0,0 +1,49 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _GPIO_COMMON_H +#define _GPIO_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _gpio_drive_mode +{ + GPIO_DM_INPUT, + GPIO_DM_INPUT_PULL_DOWN, + GPIO_DM_INPUT_PULL_UP, + GPIO_DM_OUTPUT, +} gpio_drive_mode_t; + +typedef enum _gpio_pin_edge +{ + GPIO_PE_NONE, + GPIO_PE_FALLING, + GPIO_PE_RISING, + GPIO_PE_BOTH +} gpio_pin_edge_t; + +typedef enum _gpio_pin_value +{ + GPIO_PV_LOW, + GPIO_PV_HIGH +} gpio_pin_value_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _GPIO_COMMON_H */ + diff --git a/lib/drivers/include/gpiohs.h b/lib/drivers/include/gpiohs.h new file mode 100755 index 0000000..48a1c10 --- /dev/null +++ b/lib/drivers/include/gpiohs.h @@ -0,0 +1,250 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_GPIOHS_H +#define _DRIVER_GPIOHS_H + +#include +#include "platform.h" +#include +#include "gpio_common.h" +#include "plic.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define GPIOHS_INPUT_VAL (0x00) +#define GPIOHS_INPUT_EN (0x04) +#define GPIOHS_OUTPUT_EN (0x08) +#define GPIOHS_OUTPUT_VAL (0x0C) +#define GPIOHS_PULLUP_EN (0x10) +#define GPIOHS_DRIVE (0x14) +#define GPIOHS_RISE_IE (0x18) +#define GPIOHS_RISE_IP (0x1C) +#define GPIOHS_FALL_IE (0x20) +#define GPIOHS_FALL_IP (0x24) +#define GPIOHS_HIGH_IE (0x28) +#define GPIOHS_HIGH_IP (0x2C) +#define GPIOHS_LOW_IE (0x30) +#define GPIOHS_LOW_IP (0x34) +#define GPIOHS_IOF_EN (0x38) +#define GPIOHS_IOF_SEL (0x3C) +#define GPIOHS_OUTPUT_XOR (0x40) +/* clang-format on */ + +/** + * @brief GPIO bits raw object + */ +typedef struct _gpiohs_raw +{ + /* Address offset 0x00 */ + uint32_t input_val; + /* Address offset 0x04 */ + uint32_t input_en; + /* Address offset 0x08 */ + uint32_t output_en; + /* Address offset 0x0c */ + uint32_t output_val; + /* Address offset 0x10 */ + uint32_t pullup_en; + /* Address offset 0x14 */ + uint32_t drive; + /* Address offset 0x18 */ + uint32_t rise_ie; + /* Address offset 0x1c */ + uint32_t rise_ip; + /* Address offset 0x20 */ + uint32_t fall_ie; + /* Address offset 0x24 */ + uint32_t fall_ip; + /* Address offset 0x28 */ + uint32_t high_ie; + /* Address offset 0x2c */ + uint32_t high_ip; + /* Address offset 0x30 */ + uint32_t low_ie; + /* Address offset 0x34 */ + uint32_t low_ip; + /* Address offset 0x38 */ + uint32_t iof_en; + /* Address offset 0x3c */ + uint32_t iof_sel; + /* Address offset 0x40 */ + uint32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_raw_t; + +/** + * @brief GPIO bits object + */ +typedef struct _gpiohs_bits +{ + uint32_t b0 : 1; + uint32_t b1 : 1; + uint32_t b2 : 1; + uint32_t b3 : 1; + uint32_t b4 : 1; + uint32_t b5 : 1; + uint32_t b6 : 1; + uint32_t b7 : 1; + uint32_t b8 : 1; + uint32_t b9 : 1; + uint32_t b10 : 1; + uint32_t b11 : 1; + uint32_t b12 : 1; + uint32_t b13 : 1; + uint32_t b14 : 1; + uint32_t b15 : 1; + uint32_t b16 : 1; + uint32_t b17 : 1; + uint32_t b18 : 1; + uint32_t b19 : 1; + uint32_t b20 : 1; + uint32_t b21 : 1; + uint32_t b22 : 1; + uint32_t b23 : 1; + uint32_t b24 : 1; + uint32_t b25 : 1; + uint32_t b26 : 1; + uint32_t b27 : 1; + uint32_t b28 : 1; + uint32_t b29 : 1; + uint32_t b30 : 1; + uint32_t b31 : 1; +} __attribute__((packed, aligned(4))) gpiohs_bits_t; + +/** + * @brief GPIO bits multi access union + */ +typedef union _gpiohs_u32 +{ + /* 32x1 bit mode */ + uint32_t u32[1]; + /* 16x2 bit mode */ + uint16_t u16[2]; + /* 8x4 bit mode */ + uint8_t u8[4]; + /* 1 bit mode */ + gpiohs_bits_t bits; +} __attribute__((packed, aligned(4))) gpiohs_u32_t; + +/** + * @brief GPIO object + * + * The GPIO controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of the actual + * GPIO pads on the device (direction, pull up-enable, and drive + * value), as well as selecting between various sources of the + * controls for these signals. The GPIO controller allows seperate + * configuration of each of N GPIO bits. + * + * Once the interrupt is pending, it will remain set until a 1 is + * written to the *_ip register at that bit. + */ + +typedef struct _gpiohs +{ + /* Address offset 0x00, Input Values */ + gpiohs_u32_t input_val; + /* Address offset 0x04, Input enable */ + gpiohs_u32_t input_en; + /* Address offset 0x08, Output enable */ + gpiohs_u32_t output_en; + /* Address offset 0x0c, Onput Values */ + gpiohs_u32_t output_val; + /* Address offset 0x10, Internal Pull-Ups enable */ + gpiohs_u32_t pullup_en; + /* Address offset 0x14, Drive Strength */ + gpiohs_u32_t drive; + /* Address offset 0x18, Rise interrupt enable */ + gpiohs_u32_t rise_ie; + /* Address offset 0x1c, Rise interrupt pending */ + gpiohs_u32_t rise_ip; + /* Address offset 0x20, Fall interrupt enable */ + gpiohs_u32_t fall_ie; + /* Address offset 0x24, Fall interrupt pending */ + gpiohs_u32_t fall_ip; + /* Address offset 0x28, High interrupt enable */ + gpiohs_u32_t high_ie; + /* Address offset 0x2c, High interrupt pending */ + gpiohs_u32_t high_ip; + /* Address offset 0x30, Low interrupt enable */ + gpiohs_u32_t low_ie; + /* Address offset 0x34, Low interrupt pending */ + gpiohs_u32_t low_ip; + /* Address offset 0x38, HW I/O Function enable */ + gpiohs_u32_t iof_en; + /* Address offset 0x3c, HW I/O Function select */ + gpiohs_u32_t iof_sel; + /* Address offset 0x40, Output XOR (invert) */ + gpiohs_u32_t output_xor; +} __attribute__((packed, aligned(4))) gpiohs_t; + +/** + * @brief GPIO High-speed object instanse + */ +extern volatile gpiohs_t *const gpiohs; + +/** + * @brief Set Gpiohs drive mode + * + * @param[in] pin Gpiohs pin + * @param[in] mode Gpiohs pin drive mode + */ +void gpiohs_set_drive_mode(uint8_t pin, gpio_drive_mode_t mode); + +/** + * @brief Get Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @return Pin value + * + * - GPIO_PV_Low Gpiohs pin low + * - GPIO_PV_High Gpiohs pin high + */ +gpio_pin_value_t gpiohs_get_pin(uint8_t pin); + +/** + * @brief Set Gpiohs pin value + * + * @param[in] pin Gpiohs pin + * @param[in] value Gpiohs pin value + */ +void gpiohs_set_pin(uint8_t pin, gpio_pin_value_t value); + +/** + * @brief Set Gpiohs pin edge for interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] edge Gpiohs pin edge type + */ +void gpiohs_set_pin_edge(uint8_t pin, gpio_pin_edge_t edge); + +/** + * @brief Set Gpiohs pin interrupt + * + * @param[in] pin Gpiohs pin + * @param[in] priority Gpiohs pin interrupt priority + * @param[in] func Gpiohs pin interrupt service routine + */ +void gpiohs_set_irq(uint8_t pin, uint32_t priority, void(*func)()); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_GPIOHS_H */ + diff --git a/lib/drivers/include/i2c.h b/lib/drivers/include/i2c.h new file mode 100755 index 0000000..a6a2e44 --- /dev/null +++ b/lib/drivers/include/i2c.h @@ -0,0 +1,421 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_I2C_H +#define _DRIVER_I2C_H + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_MAX_NUM 3 + +/* clang-format off */ +typedef struct _i2c +{ + /* I2C Control Register (0x00) */ + volatile uint32_t con; + /* I2C Target Address Register (0x04) */ + volatile uint32_t tar; + /* I2C Slave Address Register (0x08) */ + volatile uint32_t sar; + /* reserved (0x0c) */ + volatile uint32_t resv1; + /* I2C Data Buffer and Command Register (0x10) */ + volatile uint32_t data_cmd; + /* I2C Standard Speed Clock SCL High Count Register (0x14) */ + volatile uint32_t ss_scl_hcnt; + /* I2C Standard Speed Clock SCL Low Count Register (0x18) */ + volatile uint32_t ss_scl_lcnt; + /* reserverd (0x1c-0x28) */ + volatile uint32_t resv2[4]; + /* I2C Interrupt Status Register (0x2c) */ + volatile uint32_t intr_stat; + /* I2C Interrupt Mask Register (0x30) */ + volatile uint32_t intr_mask; + /* I2C Raw Interrupt Status Register (0x34) */ + volatile uint32_t raw_intr_stat; + /* I2C Receive FIFO Threshold Register (0x38) */ + volatile uint32_t rx_tl; + /* I2C Transmit FIFO Threshold Register (0x3c) */ + volatile uint32_t tx_tl; + /* I2C Clear Combined and Individual Interrupt Register (0x40) */ + volatile uint32_t clr_intr; + /* I2C Clear RX_UNDER Interrupt Register (0x44) */ + volatile uint32_t clr_rx_under; + /* I2C Clear RX_OVER Interrupt Register (0x48) */ + volatile uint32_t clr_rx_over; + /* I2C Clear TX_OVER Interrupt Register (0x4c) */ + volatile uint32_t clr_tx_over; + /* I2C Clear RD_REQ Interrupt Register (0x50) */ + volatile uint32_t clr_rd_req; + /* I2C Clear TX_ABRT Interrupt Register (0x54) */ + volatile uint32_t clr_tx_abrt; + /* I2C Clear RX_DONE Interrupt Register (0x58) */ + volatile uint32_t clr_rx_done; + /* I2C Clear ACTIVITY Interrupt Register (0x5c) */ + volatile uint32_t clr_activity; + /* I2C Clear STOP_DET Interrupt Register (0x60) */ + volatile uint32_t clr_stop_det; + /* I2C Clear START_DET Interrupt Register (0x64) */ + volatile uint32_t clr_start_det; + /* I2C Clear GEN_CALL Interrupt Register (0x68) */ + volatile uint32_t clr_gen_call; + /* I2C Enable Register (0x6c) */ + volatile uint32_t enable; + /* I2C Status Register (0x70) */ + volatile uint32_t status; + /* I2C Transmit FIFO Level Register (0x74) */ + volatile uint32_t txflr; + /* I2C Receive FIFO Level Register (0x78) */ + volatile uint32_t rxflr; + /* I2C SDA Hold Time Length Register (0x7c) */ + volatile uint32_t sda_hold; + /* I2C Transmit Abort Source Register (0x80) */ + volatile uint32_t tx_abrt_source; + /* reserved (0x84) */ + volatile uint32_t resv3; + /* I2C DMA Control Register (0x88) */ + volatile uint32_t dma_cr; + /* I2C DMA Transmit Data Level Register (0x8c) */ + volatile uint32_t dma_tdlr; + /* I2C DMA Receive Data Level Register (0x90) */ + volatile uint32_t dma_rdlr; + /* I2C SDA Setup Register (0x94) */ + volatile uint32_t sda_setup; + /* I2C ACK General Call Register (0x98) */ + volatile uint32_t general_call; + /* I2C Enable Status Register (0x9c) */ + volatile uint32_t enable_status; + /* I2C SS, FS or FM+ spike suppression limit (0xa0) */ + volatile uint32_t fs_spklen; + /* reserved (0xa4-0xf0) */ + volatile uint32_t resv4[20]; + /* I2C Component Parameter Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* I2C Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* I2C Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))) i2c_t; + +/* I2C Control Register*/ +#define I2C_CON_MASTER_MODE 0x00000001U +#define I2C_CON_SPEED_MASK 0x00000006U +#define I2C_CON_SPEED(x) ((x) << 1) +#define I2C_CON_10BITADDR_SLAVE 0x00000008U +#define I2C_CON_RESTART_EN 0x00000020U +#define I2C_CON_SLAVE_DISABLE 0x00000040U +#define I2C_CON_STOP_DET_IFADDRESSED 0x00000080U +#define I2C_CON_TX_EMPTY_CTRL 0x00000100U + +/* I2C Target Address Register*/ +#define I2C_TAR_ADDRESS_MASK 0x000003FFU +#define I2C_TAR_ADDRESS(x) ((x) << 0) +#define I2C_TAR_GC_OR_START 0x00000400U +#define I2C_TAR_SPECIAL 0x00000800U +#define I2C_TAR_10BITADDR_MASTER 0x00001000U + +/* I2C Slave Address Register*/ +#define I2C_SAR_ADDRESS_MASK 0x000003FFU +#define I2C_SAR_ADDRESS(x) ((x) << 0) + +/* I2C Rx/Tx Data Buffer and Command Register*/ +#define I2C_DATA_CMD_CMD 0x00000100U +#define I2C_DATA_CMD_DATA_MASK 0x000000FFU +#define I2C_DATA_CMD_DATA(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL High Count Register*/ +#define I2C_SS_SCL_HCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_HCNT_COUNT(x) ((x) << 0) + +/* Standard Speed I2C Clock SCL Low Count Register*/ +#define I2C_SS_SCL_LCNT_COUNT_MASK 0x0000FFFFU +#define I2C_SS_SCL_LCNT_COUNT(x) ((x) << 0) + +/* I2C Interrupt Status Register*/ +#define I2C_INTR_STAT_RX_UNDER 0x00000001U +#define I2C_INTR_STAT_RX_OVER 0x00000002U +#define I2C_INTR_STAT_RX_FULL 0x00000004U +#define I2C_INTR_STAT_TX_OVER 0x00000008U +#define I2C_INTR_STAT_TX_EMPTY 0x00000010U +#define I2C_INTR_STAT_RD_REQ 0x00000020U +#define I2C_INTR_STAT_TX_ABRT 0x00000040U +#define I2C_INTR_STAT_RX_DONE 0x00000080U +#define I2C_INTR_STAT_ACTIVITY 0x00000100U +#define I2C_INTR_STAT_STOP_DET 0x00000200U +#define I2C_INTR_STAT_START_DET 0x00000400U +#define I2C_INTR_STAT_GEN_CALL 0x00000800U + +/* I2C Interrupt Mask Register*/ +#define I2C_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_INTR_MASK_RX_OVER 0x00000002U +#define I2C_INTR_MASK_RX_FULL 0x00000004U +#define I2C_INTR_MASK_TX_OVER 0x00000008U +#define I2C_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_INTR_MASK_RD_REQ 0x00000020U +#define I2C_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_INTR_MASK_RX_DONE 0x00000080U +#define I2C_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_INTR_MASK_STOP_DET 0x00000200U +#define I2C_INTR_MASK_START_DET 0x00000400U +#define I2C_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Raw Interrupt Status Register*/ +#define I2C_RAW_INTR_MASK_RX_UNDER 0x00000001U +#define I2C_RAW_INTR_MASK_RX_OVER 0x00000002U +#define I2C_RAW_INTR_MASK_RX_FULL 0x00000004U +#define I2C_RAW_INTR_MASK_TX_OVER 0x00000008U +#define I2C_RAW_INTR_MASK_TX_EMPTY 0x00000010U +#define I2C_RAW_INTR_MASK_RD_REQ 0x00000020U +#define I2C_RAW_INTR_MASK_TX_ABRT 0x00000040U +#define I2C_RAW_INTR_MASK_RX_DONE 0x00000080U +#define I2C_RAW_INTR_MASK_ACTIVITY 0x00000100U +#define I2C_RAW_INTR_MASK_STOP_DET 0x00000200U +#define I2C_RAW_INTR_MASK_START_DET 0x00000400U +#define I2C_RAW_INTR_MASK_GEN_CALL 0x00000800U + +/* I2C Receive FIFO Threshold Register*/ +#define I2C_RX_TL_VALUE_MASK 0x00000007U +#define I2C_RX_TL_VALUE(x) ((x) << 0) + +/* I2C Transmit FIFO Threshold Register*/ +#define I2C_TX_TL_VALUE_MASK 0x00000007U +#define I2C_TX_TL_VALUE(x) ((x) << 0) + +/* Clear Combined and Individual Interrupt Register*/ +#define I2C_CLR_INTR_CLR 0x00000001U + +/* Clear RX_UNDER Interrupt Register*/ +#define I2C_CLR_RX_UNDER_CLR 0x00000001U + +/* Clear RX_OVER Interrupt Register*/ +#define I2C_CLR_RX_OVER_CLR 0x00000001U + +/* Clear TX_OVER Interrupt Register*/ +#define I2C_CLR_TX_OVER_CLR 0x00000001U + +/* Clear RD_REQ Interrupt Register*/ +#define I2C_CLR_RD_REQ_CLR 0x00000001U + +/* Clear TX_ABRT Interrupt Register*/ +#define I2C_CLR_TX_ABRT_CLR 0x00000001U + +/* Clear RX_DONE Interrupt Register*/ +#define I2C_CLR_RX_DONE_CLR 0x00000001U + +/* Clear ACTIVITY Interrupt Register*/ +#define I2C_CLR_ACTIVITY_CLR 0x00000001U + +/* Clear STOP_DET Interrupt Register*/ +#define I2C_CLR_STOP_DET_CLR 0x00000001U + +/* Clear START_DET Interrupt Register*/ +#define I2C_CLR_START_DET_CLR 0x00000001U + +/* Clear GEN_CALL Interrupt Register*/ +#define I2C_CLR_GEN_CALL_CLR 0x00000001U + +/* I2C Enable Register*/ +#define I2C_ENABLE_ENABLE 0x00000001U +#define I2C_ENABLE_ABORT 0x00000002U +#define I2C_ENABLE_TX_CMD_BLOCK 0x00000004U + +/* I2C Status Register*/ +#define I2C_STATUS_ACTIVITY 0x00000001U +#define I2C_STATUS_TFNF 0x00000002U +#define I2C_STATUS_TFE 0x00000004U +#define I2C_STATUS_RFNE 0x00000008U +#define I2C_STATUS_RFF 0x00000010U +#define I2C_STATUS_MST_ACTIVITY 0x00000020U +#define I2C_STATUS_SLV_ACTIVITY 0x00000040U + +/* I2C Transmit FIFO Level Register*/ +#define I2C_TXFLR_VALUE_MASK 0x00000007U +#define I2C_TXFLR_VALUE(x) ((x) << 0) + +/* I2C Receive FIFO Level Register*/ +#define I2C_RXFLR_VALUE_MASK 0x00000007U +#define I2C_RXFLR_VALUE(x) ((x) << 0) + +/* I2C SDA Hold Time Length Register*/ +#define I2C_SDA_HOLD_TX_MASK 0x0000FFFFU +#define I2C_SDA_HOLD_TX(x) ((x) << 0) +#define I2C_SDA_HOLD_RX_MASK 0x00FF0000U +#define I2C_SDA_HOLD_RX(x) ((x) << 16) + +/* I2C Transmit Abort Source Register*/ +#define I2C_TX_ABRT_SOURCE_7B_ADDR_NOACK 0x00000001U +#define I2C_TX_ABRT_SOURCE_10B_ADDR1_NOACK 0x00000002U +#define I2C_TX_ABRT_SOURCE_10B_ADDR2_NOACK 0x00000004U +#define I2C_TX_ABRT_SOURCE_TXDATA_NOACK 0x00000008U +#define I2C_TX_ABRT_SOURCE_GCALL_NOACK 0x00000010U +#define I2C_TX_ABRT_SOURCE_GCALL_READ 0x00000020U +#define I2C_TX_ABRT_SOURCE_HS_ACKDET 0x00000040U +#define I2C_TX_ABRT_SOURCE_SBYTE_ACKDET 0x00000080U +#define I2C_TX_ABRT_SOURCE_HS_NORSTRT 0x00000100U +#define I2C_TX_ABRT_SOURCE_SBYTE_NORSTRT 0x00000200U +#define I2C_TX_ABRT_SOURCE_10B_RD_NORSTRT 0x00000400U +#define I2C_TX_ABRT_SOURCE_MASTER_DIS 0x00000800U +#define I2C_TX_ABRT_SOURCE_MST_ARBLOST 0x00001000U +#define I2C_TX_ABRT_SOURCE_SLVFLUSH_TXFIFO 0x00002000U +#define I2C_TX_ABRT_SOURCE_SLV_ARBLOST 0x00004000U +#define I2C_TX_ABRT_SOURCE_SLVRD_INTX 0x00008000U +#define I2C_TX_ABRT_SOURCE_USER_ABRT 0x00010000U + +/* DMA Control Register*/ +#define I2C_DMA_CR_RDMAE 0x00000001U +#define I2C_DMA_CR_TDMAE 0x00000002U + +/* DMA Transmit Data Level Register*/ +#define I2C_DMA_TDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_TDLR_VALUE(x) ((x) << 0) + +/* DMA Receive Data Level Register*/ +#define I2C_DMA_RDLR_VALUE_MASK 0x00000007U +#define I2C_DMA_RDLR_VALUE(x) ((x) << 0) + +/* I2C SDA Setup Register*/ +#define I2C_SDA_SETUP_VALUE_MASK 0x000000FFU +#define I2C_SDA_SETUP_VALUE(x) ((x) << 0) + +/* I2C ACK General Call Register*/ +#define I2C_ACK_GENERAL_CALL_ENABLE 0x00000001U + +/* I2C Enable Status Register*/ +#define I2C_ENABLE_STATUS_IC_ENABLE 0x00000001U +#define I2C_ENABLE_STATUS_SLV_DIS_BUSY 0x00000002U +#define I2C_ENABLE_STATUS_SLV_RX_DATA_LOST 0x00000004U + +/* I2C SS, FS or FM+ spike suppression limit*/ +#define I2C_FS_SPKLEN_VALUE_MASK 0x000000FFU +#define I2C_FS_SPKLEN_VALUE(x) ((x) << 0) + +/* Component Parameter Register 1*/ +#define I2C_COMP_PARAM1_APB_DATA_WIDTH 0x00000003U +#define I2C_COMP_PARAM1_MAX_SPEED_MODE 0x0000000CU +#define I2C_COMP_PARAM1_HC_COUNT_VALUES 0x00000010U +#define I2C_COMP_PARAM1_INTR_IO 0x00000020U +#define I2C_COMP_PARAM1_HAS_DMA 0x00000040U +#define I2C_COMP_PARAM1_ENCODED_PARAMS 0x00000080U +#define I2C_COMP_PARAM1_RX_BUFFER_DEPTH 0x0000FF00U +#define I2C_COMP_PARAM1_TX_BUFFER_DEPTH 0x00FF0000U + +/* I2C Component Version Register*/ +#define I2C_COMP_VERSION_VALUE 0xFFFFFFFFU + +/* I2C Component Type Register*/ +#define I2C_COMP_TYPE_VALUE 0xFFFFFFFFU +/* clang-format on */ + +extern volatile i2c_t *const i2c[3]; + +typedef enum _i2c_device_number +{ + I2C_DEVICE_0, + I2C_DEVICE_1, + I2C_DEVICE_2, + I2C_DEVICE_MAX, +} i2c_device_number_t; + +typedef enum _i2c_bus_speed_mode +{ + I2C_BS_STANDARD, + I2C_BS_FAST, + I2C_BS_HIGHSPEED +} i2c_bus_speed_mode_t; + +/** + * @brief Set i2c params + * + * @param[in] i2c_num i2c number + * @param[in] slave_address i2c slave device address + * @param[in] address_width address width 7bit or 10bit + * @param[in] i2c_clk i2c clk rate + */ +void i2c_init(i2c_device_number_t i2c_num, uint32_t slave_address, uint32_t address_width, + uint32_t i2c_clk); + +/** + * @brief I2c send data + * + * @param[in] i2c_num i2c number + * @param[in] send_buf send data + * @param[in] send_buf_len send data length + * + * @return result + * - 0 Success + * - Other Fail + */ +int i2c_send_data(i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len); + +/** + * @brief I2c send data by dma + * + * @param[in] dma_channel_num dma channel + * @param[in] i2c_num i2c number + * @param[in] send_buf send data + * @param[in] send_buf_len send data length + * + * @return result + * - 0 Success + * - Other Fail + */ +void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_t i2c_num, const uint8_t *send_buf, + size_t send_buf_len); + +/** + * @brief I2c receive data + * + * @param[in] i2c_num i2c number + * @param[in] send_buf send data address + * @param[in] send_buf_len length of send buf + * @param[in] receive_buf receive buf address + * @param[in] receive_buf_len length of receive buf + * + * @return result + * - 0 Success + * - Other Fail +*/ +int i2c_recv_data(i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len, uint8_t *receive_buf, + size_t receive_buf_len); + +/** + * @brief I2c receive data by dma + * + * @param[in] dma_send_channel_num send dma channel + * @param[in] dma_receive_channel_num receive dma channel + * @param[in] i2c_num i2c number + * @param[in] send_buf send data address + * @param[in] send_buf_len length of send buf + * @param[in] receive_buf receive buf address + * @param[in] receive_buf_len length of receive buf + * + * @return result + * - 0 Success + * - Other Fail +*/ +void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_number_t dma_receive_channel_num, + i2c_device_number_t i2c_num, const uint8_t *send_buf, size_t send_buf_len, + uint8_t *receive_buf, size_t receive_buf_len); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_I2C_H */ diff --git a/lib/drivers/include/i2s.h b/lib/drivers/include/i2s.h new file mode 100755 index 0000000..c64b2d7 --- /dev/null +++ b/lib/drivers/include/i2s.h @@ -0,0 +1,719 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_I2S_H +#define _DRIVER_I2S_H + +#include +#include +#include "platform.h" +#include "io.h" +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define I2S0_IN_D0 90 +#define I2S0_SCLK 88 +#define I2S0_WS 89 + +typedef enum _i2s_device_number +{ + I2S_DEVICE_0 = 0, + I2S_DEVICE_1 = 1, + I2S_DEVICE_2 = 2, + I2S_DEVICE_MAX +} i2s_device_number_t; + +typedef enum _i2s_channel_num +{ + I2S_CHANNEL_0 = 0, + I2S_CHANNEL_1 = 1, + I2S_CHANNEL_2 = 2, + I2S_CHANNEL_3 = 3 +} i2s_channel_num_t; + +typedef enum _i2s_transmit +{ + I2S_TRANSMITTER = 0, + I2S_RECEIVER = 1 +} i2s_transmit_t; + +typedef enum _i2s_work_mode +{ + STANDARD_MODE = 1, + RIGHT_JUSTIFYING_MODE = 2, + LEFT_JUSTIFYING_MODE = 4 +} i2s_work_mode_t; + +typedef enum _sclk_gating_cycles +{ + /* Clock gating is diable */ + NO_CLOCK_GATING = 0x0, + /* Gating after 12 sclk cycles */ + CLOCK_CYCLES_12 = 0x1, + /* Gating after 16 sclk cycles */ + CLOCK_CYCLES_16 = 0x2, + /* Gating after 20 sclk cycles */ + CLOCK_CYCLES_20 = 0x3, + /* Gating after 24 sclk cycles */ + CLOCK_CYCLES_24 = 0x4 +} i2s_sclk_gating_cycles_t; + +typedef enum _word_select_cycles +{ + /* 16 sclk cycles */ + SCLK_CYCLES_16 = 0x0, + /* 24 sclk cycles */ + SCLK_CYCLES_24 = 0x1, + /* 32 sclk cycles */ + SCLK_CYCLES_32 = 0x2 +} i2s_word_select_cycles_t; + +typedef enum _word_length +{ + /* Ignore the word length */ + IGNORE_WORD_LENGTH = 0x0, + /* 12-bit data resolution of the receiver */ + RESOLUTION_12_BIT = 0x1, + /* 16-bit data resolution of the receiver */ + RESOLUTION_16_BIT = 0x2, + /* 20-bit data resolution of the receiver */ + RESOLUTION_20_BIT = 0x3, + /* 24-bit data resolution of the receiver */ + RESOLUTION_24_BIT = 0x4, + /* 32-bit data resolution of the receiver */ + RESOLUTION_32_BIT = 0x5 +} i2s_word_length_t; + +typedef enum _fifo_threshold +{ + /* Interrupt trigger when FIFO level is 1 */ + TRIGGER_LEVEL_1 = 0x0, + /* Interrupt trigger when FIFO level is 2 */ + TRIGGER_LEVEL_2 = 0x1, + /* Interrupt trigger when FIFO level is 3 */ + TRIGGER_LEVEL_3 = 0x2, + /* Interrupt trigger when FIFO level is 4 */ + TRIGGER_LEVEL_4 = 0x3, + /* Interrupt trigger when FIFO level is 5 */ + TRIGGER_LEVEL_5 = 0x4, + /* Interrupt trigger when FIFO level is 6 */ + TRIGGER_LEVEL_6 = 0x5, + /* Interrupt trigger when FIFO level is 7 */ + TRIGGER_LEVEL_7 = 0x6, + /* Interrupt trigger when FIFO level is 8 */ + TRIGGER_LEVEL_8 = 0x7, + /* Interrupt trigger when FIFO level is 9 */ + TRIGGER_LEVEL_9 = 0x8, + /* Interrupt trigger when FIFO level is 10 */ + TRIGGER_LEVEL_10 = 0x9, + /* Interrupt trigger when FIFO level is 11 */ + TRIGGER_LEVEL_11 = 0xa, + /* Interrupt trigger when FIFO level is 12 */ + TRIGGER_LEVEL_12 = 0xb, + /* Interrupt trigger when FIFO level is 13 */ + TRIGGER_LEVEL_13 = 0xc, + /* Interrupt trigger when FIFO level is 14 */ + TRIGGER_LEVEL_14 = 0xd, + /* Interrupt trigger when FIFO level is 15 */ + TRIGGER_LEVEL_15 = 0xe, + /* Interrupt trigger when FIFO level is 16 */ + TRIGGER_LEVEL_16 = 0xf +} i2s_fifo_threshold_t; + + +typedef struct _i2s_ier +{ + /* Bit 0 is ien, 0 for disable i2s and 1 for enable i2s */ + uint32_t ien : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_ier_t; + +typedef union _ier_u +{ + i2s_ier_t ier; + uint32_t reg_data; +} ier_t; + +typedef struct _i2s_irer +{ + /* Bit 0 is receiver block enable, + * 0 for receiver disable + * 1 for receiver enable + */ + uint32_t rxen : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_irer_t; + +typedef union _irer_u +{ + i2s_irer_t irer; + uint32_t reg_data; +} irer_t; + +typedef struct _i2s_iter +{ + uint32_t txen : 1; + /* Bit 0 is transmitter block enable, + * 0 for transmitter disable + * 1 for transmitter enable + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))) i2s_iter_t; + +typedef union _iter_u +{ + i2s_iter_t iter; + uint32_t reg_data; +} iter_t; + +typedef struct _i2s_cer +{ + uint32_t clken : 1; + /* Bit 0 is clock generation enable/disable, + * 0 for clock generation disable, + * 1 for clock generation enable + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))) i2s_cer_t; + +typedef union _cer_u +{ + i2s_cer_t cer; + uint32_t reg_data; +} cer_t; + +typedef struct _i2s_ccr +{ + /* Bits [2:0] is used to program the gating of sclk, + * 0x0 for clock gating is diable, + * 0x1 for gating after 12 sclk cycles + * 0x2 for gating after 16 sclk cycles + * 0x3 for gating after 20 sclk cycles + * 0x4 for gating after 24 sclk cycles + */ + uint32_t clk_gate : 3; + /* Bits [4:3] used program the number of sclk cycles for which the + * word select line stayd in the left aligned or right aligned mode. + * 0x0 for 16sclk cycles, 0x1 for 24 sclk cycles 0x2 for 32 sclk + * cycles + */ + uint32_t clk_word_size : 2; + /* Bit[5:7] is alignment mode setting. + * 0x1 for standard i2s format + * 0x2 for right aligned format + * 0x4 for left aligned format + */ + uint32_t align_mode : 3; + /* Bit[8] is DMA transmit enable control */ + uint32_t dma_tx_en : 1; + /* Bit[9] is DMA receive enable control */ + uint32_t dma_rx_en : 1; + uint32_t dma_divide_16 : 1; + /* Bit[10] split 32bit data to two 16 bit data and filled in left + * and right channel. Used with dma_tx_en or dma_rx_en + */ + uint32_t sign_expand_en : 1; + uint32_t resv : 20; + /* Bits [31:11] is reseved */ +} __attribute__((packed, aligned(4))) i2s_ccr_t; + +typedef union _ccr_u +{ + i2s_ccr_t ccr; + uint32_t reg_data; +} ccr_t; + +typedef struct _i2s_rxffr +{ + uint32_t rxffr : 1; + /* Bit 0 is receiver FIFO reset, + * 0 for does not flush RX FIFO, 1 for flush RX FIFO + */ + uint32_t resv : 31; + /* Bits [31:1] is reserved */ +} __attribute__((packed, aligned(4))) i2s_rxffr_t; + +typedef union _rxffr_u +{ + i2s_rxffr_t rxffr; + uint32_t reg_data; +} rxffr_t; + +typedef struct _i2s_lrbrthr +{ + uint32_t fifo : 16; + /* Bits [15:0] if used data receive or transmit */ + uint32_t resv : 16; +} i2s_lrbrthr_t; + +typedef union _lrbthr_u +{ + i2s_lrbrthr_t buffer; + uint32_t reg_data; +} lrbthr_t; + +typedef struct _i2s_rthr +{ + /* Bits [15:0] is right stereo data transmitted serially + * from transmit channel input + */ + uint32_t rthrx : 16; + /* Bits [31:16] is reserved */ + uint32_t resv : 16; +} __attribute__((packed, aligned(4))) i2s_rthr_t; + +typedef union _rthr_u +{ + i2s_rthr_t rthr; + uint32_t reg_data; +} rthr_t; + +typedef struct _i2s_rer +{ + /* Bit 0 is receive channel enable/disable, 0 for receive channel disable, + *1 for receive channel enable + */ + uint32_t rxchenx : 1; + /* Bits [31:1] is reseved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_rer_t; + +typedef union _rer_u +{ + i2s_rer_t rer; + uint32_t reg_data; +} rer_t; + +typedef struct _i2s_ter +{ + /* Bit 0 is transmit channel enable/disable, 0 for transmit channel disable, + * 1 for transmit channel enable + */ + uint32_t txchenx : 1; + /* Bits [31:1] is reseved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_ter_t; + +typedef union _ter_u +{ + i2s_ter_t ter; + uint32_t reg_data; +} ter_t; + +typedef struct _i2s_rcr_tcr +{ + /* Bits [2:0] is used to program desired data resolution of + * receiver/transmitter, + * 0x0 for ignore the word length + * 0x1 for 12-bit data resolution of the receiver/transmitter, + * 0x2 for 16-bit data resolution of the receiver/transmitter, + * 0x3 for 20-bit data resolution of the receiver/transmitter, + * 0x4 for 24-bit data resolution of the receiver/transmitter, + * 0x5 for 32-bit data resolution of the receiver/transmitter + */ + uint32_t wlen : 3; + /* Bits [31:3] is reseved */ + uint32_t resv : 29; +} __attribute__((packed, aligned(4))) i2s_rcr_tcr_t; + +typedef union _rcr_tcr_u { + i2s_rcr_tcr_t rcr_tcr; + uint32_t reg_data; +} rcr_tcr_t; + +typedef struct _i2s_isr +{ + /* Bit 0 is status of receiver data avaliable interrupt + * 0x0 for RX FIFO trigger level not reached + * 0x1 for RX FIFO trigger level is reached + */ + uint32_t rxda : 1; + /* Bit 1 is status of data overrun interrupt for rx channel + * 0x0 for RX FIFO write valid + * 0x1 for RX FIFO write overrun + */ + uint32_t rxfo : 1; + /* Bits [3:2] is reserved */ + uint32_t resv1 : 2; + /* Bit 4 is status of transmit empty triger interrupt + * 0x0 for TX FIFO triiger level is reach + * 0x1 for TX FIFO trigger level is not reached + */ + uint32_t txfe : 1; + /* BIt 5 is status of data overrun interrupt for the TX channel + * 0x0 for TX FIFO write valid + * 0x1 for TX FIFO write overrun + */ + uint32_t txfo : 1; + /* BIts [31:6] is reserved */ + uint32_t resv2 : 26; +} __attribute__((packed, aligned(4))) i2s_isr_t; + +typedef union _isr_u +{ + i2s_isr_t isr; + uint32_t reg_data; +} isr_t; + +typedef struct _i2s_imr +{ + /* Bit 0 is mask RX FIFO data available interrupt + * 0x0 for unmask RX FIFO data available interrupt + * 0x1 for mask RX FIFO data available interrupt + */ + uint32_t rxdam : 1; + /* Bit 1 is mask RX FIFO overrun interrupt + * 0x0 for unmask RX FIFO overrun interrupt + * 0x1 for mask RX FIFO overrun interrupt + */ + uint32_t rxfom : 1; + /* Bits [3:2] is reserved */ + uint32_t resv1 : 2; + /* Bit 4 is mask TX FIFO empty interrupt, + * 0x0 for unmask TX FIFO empty interrupt, + * 0x1 for mask TX FIFO empty interrupt + */ + uint32_t txfem : 1; + /* BIt 5 is mask TX FIFO overrun interrupt + * 0x0 for mask TX FIFO overrun interrupt + * 0x1 for unmash TX FIFO overrun interrupt + */ + uint32_t txfom : 1; + /* Bits [31:6] is reserved */ + uint32_t resv2 : 26; +} __attribute__((packed, aligned(4))) i2s_imr_t; + +typedef union _imr_u +{ + i2s_imr_t imr; + uint32_t reg_data; +} imr_t; + +typedef struct _i2s_ror +{ + /* Bit 0 is read this bit to clear RX FIFO data overrun interrupt + * 0x0 for RX FIFO write valid, + *0x1 for RX FIFO write overrun + */ + uint32_t rxcho : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_ror_t; + +typedef union _ror_u +{ + i2s_ror_t ror; + uint32_t reg_data; +} ror_t; + +typedef struct _i2s_tor +{ + /* Bit 0 is read this bit to clear TX FIFO data overrun interrupt + * 0x0 for TX FIFO write valid, + *0x1 for TX FIFO write overrun + */ + uint32_t txcho : 1; + /* Bits [31:1] is reserved */ + uint32_t resv : 31; +} __attribute__((packed, aligned(4))) i2s_tor_t; + +typedef union _tor_u +{ + i2s_tor_t tor; + uint32_t reg_data; +} tor_t; + +typedef struct _i2s_rfcr +{ + /* Bits [3:0] is used program the trigger level in the RX FIFO at + * which the receiver data available interrupt generate, + * 0x0 for interrupt trigger when FIFO level is 1, + * 0x2 for interrupt trigger when FIFO level is 2, + * 0x3 for interrupt trigger when FIFO level is 4, + * 0x4 for interrupt trigger when FIFO level is 5, + * 0x5 for interrupt trigger when FIFO level is 6, + * 0x6 for interrupt trigger when FIFO level is 7, + * 0x7 for interrupt trigger when FIFO level is 8, + * 0x8 for interrupt trigger when FIFO level is 9, + * 0x9 for interrupt trigger when FIFO level is 10, + * 0xa for interrupt trigger when FIFO level is 11, + * 0xb for interrupt trigger when FIFO level is 12, + * 0xc for interrupt trigger when FIFO level is 13, + * 0xd for interrupt trigger when FIFO level is 14, + * 0xe for interrupt trigger when FIFO level is 15, + * 0xf for interrupt trigger when FIFO level is 16 + */ + uint32_t rxchdt : 4; + /* Bits [31:4] is reserved */ + uint32_t rsvd_rfcrx : 28; +} __attribute__((packed, aligned(4))) i2s_rfcr_t; + +typedef union _rfcr_u +{ + i2s_rfcr_t rfcr; + uint32_t reg_data; +} rfcr_t; + +typedef struct _i2s_tfcr +{ + /* Bits [3:0] is used program the trigger level in the TX FIFO at + * which the receiver data available interrupt generate, + * 0x0 for interrupt trigger when FIFO level is 1, + * 0x2 for interrupt trigger when FIFO level is 2, + * 0x3 for interrupt trigger when FIFO level is 4, + * 0x4 for interrupt trigger when FIFO level is 5, + * 0x5 for interrupt trigger when FIFO level is 6, + * 0x6 for interrupt trigger when FIFO level is 7, + * 0x7 for interrupt trigger when FIFO level is 8, + * 0x8 for interrupt trigger when FIFO level is 9, + * 0x9 for interrupt trigger when FIFO level is 10, + * 0xa for interrupt trigger when FIFO level is 11, + * 0xb for interrupt trigger when FIFO level is 12, + * 0xc for interrupt trigger when FIFO level is 13, + * 0xd for interrupt trigger when FIFO level is 14, + * 0xe for interrupt trigger when FIFO level is 15, + * 0xf for interrupt trigger when FIFO level is 16 + */ + uint32_t txchet : 4; + /* Bits [31:4] is reserved */ + uint32_t rsvd_tfcrx : 28; +} __attribute__((packed, aligned(4))) i2s_tfcr_t; + +typedef union _tfcr_u +{ + i2s_tfcr_t tfcr; + uint32_t reg_data; +} tfcr_t; + +typedef struct _i2s_rff +{ + /* Bit 0 is receiver channel FIFO reset, + * 0x0 for does not flush an individual RX FIFO, + * 0x1 for flush an indiviadual RX FIFO + */ + uint32_t rxchfr : 1; + /*< Bits [31:1] is reserved ,write only */ + uint32_t rsvd_rffx : 31; +} __attribute__((packed, aligned(4))) i2s_rff_t; + +typedef union _rff_u +{ + i2s_rff_t rff; + uint32_t reg_data; +} rff_t; + +typedef struct _i2s_tff +{ + /* Bit 0 is transmit channel FIFO reset, + * 0x0 for does not flush an individual TX FIFO, + * 0x1 for flush an indiviadual TX FIFO + */ + uint32_t rtxchfr : 1; + /*< Bits [31:1] is reserved ,write only */ + uint32_t rsvd_rffx : 31; +} __attribute__((packed, aligned(4))) i2s_tff_t; + +typedef union tff_u +{ + i2s_tff_t tff; + uint32_t reg_data; +} tff_t; + +typedef struct _i2s_channel +{ + /* Left Receive or Left Transmit Register (0x20) */ + volatile uint32_t left_rxtx; + /* Right Receive or Right Transmit Register (0x24) */ + volatile uint32_t right_rxtx; + /* Receive Enable Register (0x28) */ + volatile uint32_t rer; + /* Transmit Enable Register (0x2c) */ + volatile uint32_t ter; + /* Receive Configuration Register (0x30) */ + volatile uint32_t rcr; + /* Transmit Configuration Register (0x34) */ + volatile uint32_t tcr; + /* Interrupt Status Register (0x38) */ + volatile uint32_t isr; + /* Interrupt Mask Register (0x3c) */ + volatile uint32_t imr; + /* Receive Overrun Register (0x40) */ + volatile uint32_t ror; + /* Transmit Overrun Register (0x44) */ + volatile uint32_t tor; + /* Receive FIFO Configuration Register (0x48) */ + volatile uint32_t rfcr; + /* Transmit FIFO Configuration Register (0x4c) */ + volatile uint32_t tfcr; + /* Receive FIFO Flush Register (0x50) */ + volatile uint32_t rff; + /* Transmit FIFO Flush Register (0x54) */ + volatile uint32_t tff; + /* reserved (0x58-0x5c) */ + volatile uint32_t reserved1[2]; +} __attribute__((packed, aligned(4))) i2s_channel_t; + +/****is* i2s.api/dw_i2s_portmap + * NAME + * i2s_t + * DESCRIPTION + * This is the structure used for accessing the i2s register + * portmap. + * EXAMPLE + * struct i2s_t *portmap; + * portmap = (struct dw_i2s_portmap *) DW_APB_I2S_BASE; + * SOURCE + */ +typedef struct _i2s +{ + /* I2S Enable Register (0x00) */ + volatile uint32_t ier; + /* I2S Receiver Block Enable Register (0x04) */ + volatile uint32_t irer; + /* I2S Transmitter Block Enable Register (0x08) */ + volatile uint32_t iter; + /* Clock Enable Register (0x0c) */ + volatile uint32_t cer; + /* Clock Configuration Register (0x10) */ + volatile uint32_t ccr; + /* Receiver Block FIFO Reset Register (0x04) */ + volatile uint32_t rxffr; + /* Transmitter Block FIFO Reset Register (0x18) */ + volatile uint32_t txffr; + /* reserved (0x1c) */ + volatile uint32_t reserved1; + volatile i2s_channel_t channel[4]; + /* reserved (0x118-0x1bc) */ + volatile uint32_t reserved2[40]; + /* Receiver Block DMA Register (0x1c0) */ + volatile uint32_t rxdma; + /* Reset Receiver Block DMA Register (0x1c4) */ + volatile uint32_t rrxdma; + /* Transmitter Block DMA Register (0x1c8) */ + volatile uint32_t txdma; + /* Reset Transmitter Block DMA Register (0x1cc) */ + volatile uint32_t rtxdma; + /* reserved (0x1d0-0x1ec) */ + volatile uint32_t reserved3[8]; + /* Component Parameter Register 2 (0x1f0) */ + volatile uint32_t i2s_comp_param_2; + /* Component Parameter Register 1 (0x1f4) */ + volatile uint32_t i2s_comp_param_1; + /* I2S Component Version Register (0x1f8) */ + volatile uint32_t i2s_comp_version_1; + /* I2S Component Type Register (0x1fc) */ + volatile uint32_t i2s_comp_type; +} __attribute__((packed, aligned(4))) i2s_t; + +/** + * @brief I2S object instance + */ +extern volatile i2s_t *const i2s[3]; + +/** +* @brief I2s init +* +* @param[in] device_num The device number +* @param[in] rxtx_mode I2s work mode +* @param[in] channel_mask Channel mask to which channel work +* +*/ +void i2s_init(i2s_device_number_t device_num, i2s_transmit_t rxtx_mode, uint32_t channel_mask); + +/** + * @brief Read pcm data from dma + * + * @param[in] device_num which of device + * @param[in] buf save read data + * @param[in] buf_len the length to read form i2s + * @param[in] channel_num The dma channel number + * + * @return result + * - 0 Success + * - Other Fail + */ +void i2s_receive_data_dma(i2s_device_number_t device_num, uint32_t *buf, size_t buf_len, + dmac_channel_number_t channel_num); + +/** + * @brief Write pcm data to channel_num channel by dma, first wait dmac done + * + * @param[in] device_num which of device + * @param[in] pcm Send data + * @param[in] buf_len Send data length + * @param[in] channel_num dmac channel + * + */ +void i2s_send_data_dma(i2s_device_number_t device_num, const void *buf, size_t buf_len, dmac_channel_number_t channel_num); + +/** + * @brief I2S receive channel configure + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + * @param[in] word_length The word length + * @param[in] word_select_size The word select size + * @param[in] trigger_level The trigger level + */ +void i2s_rx_channel_config(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, + i2s_word_length_t word_length, + i2s_word_select_cycles_t word_select_size, + i2s_fifo_threshold_t trigger_level, + i2s_work_mode_t word_mode); + +/** + * @brief I2S transmit channel enable + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + * @param[in] word_length The word length + * @param[in] word_select_size The word select size + * @param[in] trigger_level The trigger level + */ +void i2s_tx_channel_config(i2s_device_number_t device_num, + i2s_channel_num_t channel_num, + i2s_word_length_t word_length, + i2s_word_select_cycles_t word_select_size, + i2s_fifo_threshold_t trigger_level, + i2s_work_mode_t word_mode); + + +/** + * @brief Play PCM format audio + * + * @param[in] device_num The device number + * @param[in] channel_num The channel number + * @param[in] buf PCM data + * @param[in] buf_len PCM data length + * @param[in] frame Transmit amount once + * @param[in] bits_per_sample Sample bit length + * @param[in] track_num Track amount + */ +void i2s_play(i2s_device_number_t device_num, dmac_channel_number_t channel_num, + const uint8_t *buf, size_t buf_len, size_t frame, size_t bits_per_sample, uint8_t track_num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/drivers/include/io.h b/lib/drivers/include/io.h new file mode 100755 index 0000000..190263f --- /dev/null +++ b/lib/drivers/include/io.h @@ -0,0 +1,50 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_IO_H +#define _DRIVER_IO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define readb(addr) (*(volatile uint8_t *)(addr)) +#define readw(addr) (*(volatile uint16_t *)(addr)) +#define readl(addr) (*(volatile uint32_t *)(addr)) +#define readq(addr) (*(volatile uint64_t *)(addr)) + +#define writeb(v, addr) \ + { \ + (*(volatile uint8_t *)(addr)) = (v); \ + } +#define writew(v, addr) \ + { \ + (*(volatile uint16_t *)(addr)) = (v); \ + } +#define writel(v, addr) \ + { \ + (*(volatile uint32_t *)(addr)) = (v); \ + } +#define writeq(v, addr) \ + { \ + (*(volatile uint64_t *)(addr)) = (v); \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_IO_H */ diff --git a/lib/drivers/include/plic.h b/lib/drivers/include/plic.h new file mode 100755 index 0000000..1215c68 --- /dev/null +++ b/lib/drivers/include/plic.h @@ -0,0 +1,463 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +/** + * @file + * @brief The PLIC complies with the RISC-V Privileged Architecture + * specification, and can support a maximum of 1023 external + * interrupt sources targeting up to 15,872 core contexts. + * + * @note PLIC RAM Layout + * + * | Address | Description | + * |-----------|---------------------------------| + * |0x0C000000 | Reserved | + * |0x0C000004 | source 1 priority | + * |0x0C000008 | source 2 priority | + * |... | ... | + * |0x0C000FFC | source 1023 priority | + * | | | + * |0x0C001000 | Start of pending array | + * |... | (read-only) | + * |0x0C00107C | End of pending array | + * |0x0C001080 | Reserved | + * |... | ... | + * |0x0C001FFF | Reserved | + * | | | + * |0x0C002000 | target 0 enables | + * |0x0C002080 | target 1 enables | + * |... | ... | + * |0x0C1F1F80 | target 15871 enables | + * |0x0C1F2000 | Reserved | + * |... | ... | + * |0x0C1FFFFC | Reserved | + * | | | + * |0x0C200000 | target 0 priority threshold | + * |0x0C200004 | target 0 claim/complete | + * |... | ... | + * |0x0C201000 | target 1 priority threshold | + * |0x0C201004 | target 1 claim/complete | + * |... | ... | + * |0x0FFFF000 | target 15871 priority threshold | + * |0x0FFFF004 | target 15871 claim/complete | + * + */ + +#ifndef _DRIVER_PLIC_H +#define _DRIVER_PLIC_H + +#include +#include "encoding.h" +#include "platform.h" + +/* For c++ compatibility */ +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* IRQ number settings */ +#define PLIC_NUM_SOURCES (IRQN_MAX - 1) +#define PLIC_NUM_PRIORITIES (7) + +/* Real number of cores */ +#define PLIC_NUM_CORES (2) +/* clang-format on */ + +/** + * @brief PLIC External Interrupt Numbers + * + * @note PLIC interrupt sources + * + * | Source | Name | Description | + * |--------|--------------------------|------------------------------------| + * | 0 | IRQN_NO_INTERRUPT | The non-existent interrupt | + * | 1 | IRQN_SPI0_INTERRUPT | SPI0 interrupt | + * | 2 | IRQN_SPI1_INTERRUPT | SPI1 interrupt | + * | 3 | IRQN_SPI_SLAVE_INTERRUPT | SPI_SLAVE interrupt | + * | 4 | IRQN_SPI3_INTERRUPT | SPI3 interrupt | + * | 5 | IRQN_I2S0_INTERRUPT | I2S0 interrupt | + * | 6 | IRQN_I2S1_INTERRUPT | I2S1 interrupt | + * | 7 | IRQN_I2S2_INTERRUPT | I2S2 interrupt | + * | 8 | IRQN_I2C0_INTERRUPT | I2C0 interrupt | + * | 9 | IRQN_I2C1_INTERRUPT | I2C1 interrupt | + * | 10 | IRQN_I2C2_INTERRUPT | I2C2 interrupt | + * | 11 | IRQN_UART1_INTERRUPT | UART1 interrupt | + * | 12 | IRQN_UART2_INTERRUPT | UART2 interrupt | + * | 13 | IRQN_UART3_INTERRUPT | UART3 interrupt | + * | 14 | IRQN_TIMER0A_INTERRUPT | TIMER0 channel 0 or 1 interrupt | + * | 15 | IRQN_TIMER0B_INTERRUPT | TIMER0 channel 2 or 3 interrupt | + * | 16 | IRQN_TIMER1A_INTERRUPT | TIMER1 channel 0 or 1 interrupt | + * | 17 | IRQN_TIMER1B_INTERRUPT | TIMER1 channel 2 or 3 interrupt | + * | 18 | IRQN_TIMER2A_INTERRUPT | TIMER2 channel 0 or 1 interrupt | + * | 19 | IRQN_TIMER2B_INTERRUPT | TIMER2 channel 2 or 3 interrupt | + * | 20 | IRQN_RTC_INTERRUPT | RTC tick and alarm interrupt | + * | 21 | IRQN_WDT0_INTERRUPT | Watching dog timer0 interrupt | + * | 22 | IRQN_WDT1_INTERRUPT | Watching dog timer1 interrupt | + * | 23 | IRQN_APB_GPIO_INTERRUPT | APB GPIO interrupt | + * | 24 | IRQN_DVP_INTERRUPT | Digital video port interrupt | + * | 25 | IRQN_AI_INTERRUPT | AI accelerator interrupt | + * | 26 | IRQN_FFT_INTERRUPT | FFT accelerator interrupt | + * | 27 | IRQN_DMA0_INTERRUPT | DMA channel0 interrupt | + * | 28 | IRQN_DMA1_INTERRUPT | DMA channel1 interrupt | + * | 29 | IRQN_DMA2_INTERRUPT | DMA channel2 interrupt | + * | 30 | IRQN_DMA3_INTERRUPT | DMA channel3 interrupt | + * | 31 | IRQN_DMA4_INTERRUPT | DMA channel4 interrupt | + * | 32 | IRQN_DMA5_INTERRUPT | DMA channel5 interrupt | + * | 33 | IRQN_UARTHS_INTERRUPT | Hi-speed UART0 interrupt | + * | 34 | IRQN_GPIOHS0_INTERRUPT | Hi-speed GPIO0 interrupt | + * | 35 | IRQN_GPIOHS1_INTERRUPT | Hi-speed GPIO1 interrupt | + * | 36 | IRQN_GPIOHS2_INTERRUPT | Hi-speed GPIO2 interrupt | + * | 37 | IRQN_GPIOHS3_INTERRUPT | Hi-speed GPIO3 interrupt | + * | 38 | IRQN_GPIOHS4_INTERRUPT | Hi-speed GPIO4 interrupt | + * | 39 | IRQN_GPIOHS5_INTERRUPT | Hi-speed GPIO5 interrupt | + * | 40 | IRQN_GPIOHS6_INTERRUPT | Hi-speed GPIO6 interrupt | + * | 41 | IRQN_GPIOHS7_INTERRUPT | Hi-speed GPIO7 interrupt | + * | 42 | IRQN_GPIOHS8_INTERRUPT | Hi-speed GPIO8 interrupt | + * | 43 | IRQN_GPIOHS9_INTERRUPT | Hi-speed GPIO9 interrupt | + * | 44 | IRQN_GPIOHS10_INTERRUPT | Hi-speed GPIO10 interrupt | + * | 45 | IRQN_GPIOHS11_INTERRUPT | Hi-speed GPIO11 interrupt | + * | 46 | IRQN_GPIOHS12_INTERRUPT | Hi-speed GPIO12 interrupt | + * | 47 | IRQN_GPIOHS13_INTERRUPT | Hi-speed GPIO13 interrupt | + * | 48 | IRQN_GPIOHS14_INTERRUPT | Hi-speed GPIO14 interrupt | + * | 49 | IRQN_GPIOHS15_INTERRUPT | Hi-speed GPIO15 interrupt | + * | 50 | IRQN_GPIOHS16_INTERRUPT | Hi-speed GPIO16 interrupt | + * | 51 | IRQN_GPIOHS17_INTERRUPT | Hi-speed GPIO17 interrupt | + * | 52 | IRQN_GPIOHS18_INTERRUPT | Hi-speed GPIO18 interrupt | + * | 53 | IRQN_GPIOHS19_INTERRUPT | Hi-speed GPIO19 interrupt | + * | 54 | IRQN_GPIOHS20_INTERRUPT | Hi-speed GPIO20 interrupt | + * | 55 | IRQN_GPIOHS21_INTERRUPT | Hi-speed GPIO21 interrupt | + * | 56 | IRQN_GPIOHS22_INTERRUPT | Hi-speed GPIO22 interrupt | + * | 57 | IRQN_GPIOHS23_INTERRUPT | Hi-speed GPIO23 interrupt | + * | 58 | IRQN_GPIOHS24_INTERRUPT | Hi-speed GPIO24 interrupt | + * | 59 | IRQN_GPIOHS25_INTERRUPT | Hi-speed GPIO25 interrupt | + * | 60 | IRQN_GPIOHS26_INTERRUPT | Hi-speed GPIO26 interrupt | + * | 61 | IRQN_GPIOHS27_INTERRUPT | Hi-speed GPIO27 interrupt | + * | 62 | IRQN_GPIOHS28_INTERRUPT | Hi-speed GPIO28 interrupt | + * | 63 | IRQN_GPIOHS29_INTERRUPT | Hi-speed GPIO29 interrupt | + * | 64 | IRQN_GPIOHS30_INTERRUPT | Hi-speed GPIO30 interrupt | + * | 65 | IRQN_GPIOHS31_INTERRUPT | Hi-speed GPIO31 interrupt | + * + */ +/* clang-format off */ +typedef enum _plic_irq +{ + IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */ + IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */ + IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */ + IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */ + IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */ + IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */ + IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */ + IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */ + IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */ + IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */ + IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */ + IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */ + IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */ + IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */ + IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */ + IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */ + IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */ + IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */ + IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */ + IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */ + IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */ + IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */ + IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */ + IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */ + IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */ + IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */ + IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */ + IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */ + IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */ + IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */ + IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */ + IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */ + IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */ + IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */ + IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */ + IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */ + IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */ + IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */ + IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */ + IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */ + IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */ + IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */ + IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */ + IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */ + IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */ + IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */ + IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */ + IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */ + IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */ + IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */ + IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */ + IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */ + IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */ + IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */ + IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */ + IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */ + IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */ + IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */ + IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */ + IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */ + IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */ + IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */ + IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */ + IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */ + IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */ + IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */ + IRQN_MAX +} plic_irq_t; +/* clang-format on */ + +/** + * @brief Interrupt Source Priorities + * + * Each external interrupt source can be assigned a priority by + * writing to its 32-bit memory-mapped priority register. The + * number and value of supported priority levels can vary by + * implementa- tion, with the simplest implementations having all + * devices hardwired at priority 1, in which case, interrupts with + * the lowest ID have the highest effective priority. The priority + * registers are all WARL. + */ +typedef struct _plic_source_priorities +{ + /* 0x0C000000: Reserved, 0x0C000004-0x0C000FFC: 1-1023 priorities */ + uint32_t priority[1024]; +} __attribute__((packed, aligned(4))) plic_source_priorities_t; + +/** + * @brief Interrupt Pending Bits + * + * The current status of the interrupt source pending bits in the + * PLIC core can be read from the pending array, organized as 32 + * words of 32 bits. The pending bit for interrupt ID N is stored + * in bit (N mod 32) of word (N/32). Bit 0 of word 0, which + * represents the non-existent interrupt source 0, is always + * hardwired to zero. The pending bits are read-only. A pending + * bit in the PLIC core can be cleared by setting enable bits to + * only enable the desired interrupt, then performing a claim. A + * pending bit can be set by instructing the associated gateway to + * send an interrupt service request. + */ +typedef struct _plic_pending_bits +{ + /* 0x0C001000-0x0C00107C: Bit 0 is zero, Bits 1-1023 is pending bits */ + uint32_t u32[32]; + /* 0x0C001080-0x0C001FFF: Reserved */ + uint8_t resv[0xF80]; +} __attribute__((packed, aligned(4))) plic_pending_bits_t; + +/** + * @brief Target Interrupt Enables + * + * For each interrupt target, each device’s interrupt can be + * enabled by setting the corresponding bit in that target’s + * enables registers. The enables for a target are accessed as a + * contiguous array of 32×32-bit words, packed the same way as the + * pending bits. For each target, bit 0 of enable word 0 + * represents the non-existent interrupt ID 0 and is hardwired to + * 0. Unused interrupt IDs are also hardwired to zero. The enables + * arrays for different targets are packed contiguously in the + * address space. Only 32-bit word accesses are supported by the + * enables array in RV32 systems. Implementations can trap on + * accesses to enables for non-existent targets, but must allow + * access to the full enables array for any extant target, + * treating all non-existent interrupt source’s enables as + * hardwired to zero. + */ +typedef struct _plic_target_enables +{ + /* 0x0C002000-0x0C1F1F80: target 0-15871 enables */ + struct + { + uint32_t enable[32];/* Offset 0x00-0x7C: Bit 0 is zero, Bits 1-1023 is bits*/ + } target[15872]; + + /* 0x0C1F2000-0x0C1FFFFC: Reserved, size 0xE000 */ + uint8_t resv[0xE000]; +} __attribute__((packed, aligned(4))) plic_target_enables_t; + +/** + * @brief PLIC Targets + * + * Target Priority Thresholds The threshold for a pending + * interrupt priority that can interrupt each target can be set in + * the target’s threshold register. The threshold is a WARL field, + * where different implementations can support different numbers + * of thresholds. The simplest implementation has a threshold + * hardwired to zero. + * + * Target Claim Each target can perform a claim by reading the + * claim/complete register, which returns the ID of the highest + * priority pending interrupt or zero if there is no pending + * interrupt for the target. A successful claim will also + * atomically clear the corresponding pending bit on the interrupt + * source. A target can perform a claim at any time, even if the + * EIP is not set. The claim operation is not affected by the + * setting of the target’s priority threshold register. + * + * Target Completion A target signals it has completed running a + * handler by writing the interrupt ID it received from the claim + * to the claim/complete register. This is routed to the + * corresponding interrupt gateway, which can now send another + * interrupt request to the PLIC. The PLIC does not check whether + * the completion ID is the same as the last claim ID for that + * target. If the completion ID does not match an interrupt source + * that is currently enabled for the target, the completion is + * silently ignored. + */ +typedef struct _plic_target +{ + /* 0x0C200000-0x0FFFF004: target 0-15871 */ + struct { + uint32_t priority_threshold;/* Offset 0x000 */ + uint32_t claim_complete; /* Offset 0x004 */ + uint8_t resv[0xFF8]; /* Offset 0x008, Size 0xFF8 */ + } target[15872]; +} __attribute__((packed, aligned(4))) plic_target_t; + +/** + * @brief Platform-Level Interrupt Controller + * + * PLIC is Platform-Level Interrupt Controller. The PLIC complies + * with the RISC-V Privileged Architecture specification, and can + * support a maximum of 1023 external interrupt sources targeting + * up to 15,872 core contexts. + */ +typedef struct _plic +{ + /* 0x0C000000-0x0C000FFC */ + plic_source_priorities_t source_priorities; + /* 0x0C001000-0x0C001FFF */ + const plic_pending_bits_t pending_bits; + /* 0x0C002000-0x0C1FFFFC */ + plic_target_enables_t target_enables; + /* 0x0C200000-0x0FFFF004 */ + plic_target_t targets; +} __attribute__((packed, aligned(4))) plic_t; + +extern volatile plic_t *const plic; + +/** + * @brief Definitions for the interrupt callbacks + */ +typedef int (*plic_irq_callback_t)(void *ctx); + +/** + * @brief Initialize PLIC external interrupt + * + * @note This function will set MIP_MEIP. The MSTATUS_MIE must set by user. + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_init(void); + +/** + * @brief Enable PLIC external interrupt + * + * @param[in] irq_number external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ + +int plic_irq_enable(plic_irq_t irq_number); + +/** + * @brief Disable PLIC external interrupt + * + * @param[in] irq_number The external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_disable(plic_irq_t irq_number); + +/** + * @brief Set IRQ priority + * + * @param[in] irq_number The external interrupt number + * @param[in] priority The priority of external interrupt number + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_set_priority(plic_irq_t irq_number, uint32_t priority); + +/** + * @brief Get IRQ priority + * + * @param[in] irq_number The external interrupt number + * + * @return The priority of external interrupt number + */ +uint32_t plic_get_priority(plic_irq_t irq_number); + +/** + * @brief Claim an IRQ + * + * @return The current IRQ number + */ +uint32_t plic_irq_claim(void); + +/** + * @brief Complete an IRQ + * + * @param[in] source The source IRQ number to complete + * + * @return result + * - 0 Success + * - Other Fail + */ +int plic_irq_complete(uint32_t source); + +/** + * @brief Register user callback function by IRQ number + * + * @param[in] irq The irq + * @param[in] callback The callback + * @param ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx); + +/** + * @brief Deegister user callback function by IRQ number + * + * @param[in] irq The irq + * + * @return result + * - 0 Success + * - Other Fail + */ +void plic_irq_deregister(plic_irq_t irq); + +/* For c++ compatibility */ +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_PLIC_H */ diff --git a/lib/drivers/include/pwm.h b/lib/drivers/include/pwm.h new file mode 100755 index 0000000..45af61d --- /dev/null +++ b/lib/drivers/include/pwm.h @@ -0,0 +1,74 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_PWM_H +#define _DRIVER_PWM_H + +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _pwm_device_number +{ + PWM_DEVICE_0, + PWM_DEVICE_1, + PWM_DEVICE_2, + PWM_DEVICE_MAX, +} pwm_device_number_t; + +typedef enum _pwm_channel_number +{ + PWM_CHANNEL_0, + PWM_CHANNEL_1, + PWM_CHANNEL_2, + PWM_CHANNEL_3, + PWM_CHANNEL_MAX, +} pwm_channel_number_t; + +/** + * @brief Init pwm timer + * + * @param[in] timer timer + */ +void pwm_init(pwm_device_number_t pwm_number); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void pwm_set_enable(pwm_device_number_t pwm_number, pwm_channel_number_t channel, int enable); + +/** + * @brief Set pwm duty + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] frequency pwm frequency + * @param[in] duty duty + * + */ +double pwm_set_frequency(pwm_device_number_t pwm_number, pwm_channel_number_t channel, double frequency, double duty); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_PWM_H */ diff --git a/lib/drivers/include/rtc.h b/lib/drivers/include/rtc.h new file mode 100755 index 0000000..91fde34 --- /dev/null +++ b/lib/drivers/include/rtc.h @@ -0,0 +1,398 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +/** + * @file + * @brief A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ + +#ifndef _DRIVER_RTC_H +#define _DRIVER_RTC_H + +#include +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RTC timer mode + * + * Timer mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Timer pause | + * | 1 | Timer time running | + * | 2 | Timer time setting | + */ +typedef enum _rtc_timer_mode_e +{ + /* 0: Timer pause */ + RTC_TIMER_PAUSE, + /* 1: Timer time running */ + RTC_TIMER_RUNNING, + /* 2: Timer time setting */ + RTC_TIMER_SETTING, + /* Max count of this enum*/ + RTC_TIMER_MAX +} rtc_timer_mode_t; + +/* + * @brief RTC tick interrupt mode + * + * Tick interrupt mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Interrupt every second | + * | 1 | Interrupt every minute | + * | 2 | Interrupt every hour | + * | 3 | Interrupt every day | + */ +typedef enum _rtc_tick_interrupt_mode_e +{ + /* 0: Interrupt every second */ + RTC_INT_SECOND, + /* 1: Interrupt every minute */ + RTC_INT_MINUTE, + /* 2: Interrupt every hour */ + RTC_INT_HOUR, + /* 3: Interrupt every day */ + RTC_INT_DAY, + /* Max count of this enum*/ + RTC_INT_MAX +} rtc_tick_interrupt_mode_t; + +/** + * @brief RTC mask structure + * + * RTC mask structure for common use + */ +typedef struct _rtc_mask +{ + /* Reserved */ + uint32_t resv : 1; + /* Second mask */ + uint32_t second : 1; + /* Minute mask */ + uint32_t minute : 1; + /* Hour mask */ + uint32_t hour : 1; + /* Week mask */ + uint32_t week : 1; + /* Day mask */ + uint32_t day : 1; + /* Month mask */ + uint32_t month : 1; + /* Year mask */ + uint32_t year : 1; +} __attribute__((packed, aligned(1))) rtc_mask_t; + +/** + * @brief RTC register + * + * @note RTC register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | date | Timer date information | + * | 0x04 | time | Timer time information | + * | 0x08 | alarm_date | Alarm date information | + * | 0x0c | alarm_time | Alarm time information | + * | 0x10 | initial_count | Timer counter initial value | + * | 0x14 | current_count | Timer counter current value | + * | 0x18 | interrupt_ctrl | RTC interrupt settings | + * | 0x1c | register_ctrl | RTC register settings | + * | 0x20 | reserved0 | Reserved | + * | 0x24 | reserved1 | Reserved | + * | 0x28 | extended | Timer extended information | + * + */ + + +/** + * @brief Timer date information + * + * No. 0 Register (0x00) + */ +typedef struct _rtc_date +{ + /* Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Month. Range [1,12] */ + uint32_t month : 4; + /* Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_date_t; + +/** + * @brief Timer time information + * + * No. 1 Register (0x04) + */ +typedef struct _rtc_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Second. Range [0,59] */ + uint32_t second : 6; + /* Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_time_t; + +/** + * @brief Alarm date information + * + * No. 2 Register (0x08) + */ +typedef struct _rtc_alarm_date +{ + /* Alarm Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Alarm Month. Range [1,12] */ + uint32_t month : 4; + /* Alarm Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_alarm_date_t; + +/** + * @brief Alarm time information + * + * No. 3 Register (0x0c) + */ +typedef struct _rtc_alarm_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Alarm Second. Range [0,59] */ + uint32_t second : 6; + /* Alarm Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Alarm Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_alarm_time_t; + +/** + * @brief Timer counter initial value + * + * No. 4 Register (0x10) + */ +typedef struct _rtc_initial_count +{ + /* RTC counter initial value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_initial_count_t; + +/** + * @brief Timer counter current value + * + * No. 5 Register (0x14) + */ +typedef struct _rtc_current_count +{ + /* RTC counter current value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_current_count_t; + +/** + * @brief RTC interrupt settings + * + * No. 6 Register (0x18) + */ +typedef struct _rtc_interrupt_ctrl +{ + /* Reserved */ + uint32_t tick_enable : 1; + /* Alarm interrupt enable */ + uint32_t alarm_enable : 1; + /* Tick interrupt enable */ + uint32_t tick_int_mode : 2; + /* Reserved */ + uint32_t resv : 20; + /* Alarm compare mask for interrupt */ + uint32_t alarm_compare_mask : 8; +} __attribute__((packed, aligned(4))) rtc_interrupt_ctrl_t; + +/** + * @brief RTC register settings + * + * No. 7 Register (0x1c) + */ +typedef struct _rtc_register_ctrl +{ + /* RTC timer read enable */ + uint32_t read_enable : 1; + /* RTC timer write enable */ + uint32_t write_enable : 1; + /* Reserved */ + uint32_t resv0 : 11; + /* RTC timer mask */ + uint32_t timer_mask : 8; + /* RTC alarm mask */ + uint32_t alarm_mask : 8; + /* RTC counter initial count value mask */ + uint32_t initial_count_mask : 1; + /* RTC interrupt register mask */ + uint32_t interrupt_register_mask : 1; + /* Reserved */ + uint32_t resv1 : 1; +} __attribute__((packed, aligned(4))) rtc_register_ctrl_t; + +/** + * @brief Reserved + * + * No. 8 Register (0x20) + */ +typedef struct _rtc_reserved0 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved0_t; + +/** + * @brief Reserved + * + * No. 9 Register (0x24) + */ +typedef struct _rtc_reserved1 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved1_t; + +/** + * @brief Timer extended information + * + * No. 10 Register (0x28) + */ +typedef struct _rtc_extended +{ + /* Century. Range [0,31] */ + uint32_t century : 5; + /* Is leap year. 1 is leap year, 0 is not leap year */ + uint32_t leap_year : 1; + /* Reserved */ + uint32_t resv : 26; +} __attribute__((packed, aligned(4))) rtc_extended_t; + + +/** + * @brief Real-time clock struct + * + * A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ +typedef struct _rtc +{ + /* No. 0 (0x00): Timer date information */ + rtc_date_t date; + /* No. 1 (0x04): Timer time information */ + rtc_time_t time; + /* No. 2 (0x08): Alarm date information */ + rtc_alarm_date_t alarm_date; + /* No. 3 (0x0c): Alarm time information */ + rtc_alarm_time_t alarm_time; + /* No. 4 (0x10): Timer counter initial value */ + rtc_initial_count_t initial_count; + /* No. 5 (0x14): Timer counter current value */ + rtc_current_count_t current_count; + /* No. 6 (0x18): RTC interrupt settings */ + rtc_interrupt_ctrl_t interrupt_ctrl; + /* No. 7 (0x1c): RTC register settings */ + rtc_register_ctrl_t register_ctrl; + /* No. 8 (0x20): Reserved */ + rtc_reserved0_t reserved0; + /* No. 9 (0x24): Reserved */ + rtc_reserved1_t reserved1; + /* No. 10 (0x28): Timer extended information */ + rtc_extended_t extended; +} __attribute__((packed, aligned(4))) rtc_t; + + +/** + * @brief Real-time clock object + */ +extern volatile rtc_t *const rtc; +extern volatile uint32_t *const rtc_base; + +/** + * @brief Set date time to RTC + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * @param[in] hour The hour + * @param[in] minute The minute + * @param[in] second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second); + +/** + * @brief Get date time from RTC + * + * @param year The year + * @param month The month + * @param day The day + * @param hour The hour + * @param minute The minute + * @param second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second); + +/** + * @brief Initialize RTC + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_RTC_H */ diff --git a/lib/drivers/include/sha256.h b/lib/drivers/include/sha256.h new file mode 100755 index 0000000..b23c165 --- /dev/null +++ b/lib/drivers/include/sha256.h @@ -0,0 +1,128 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _SHA256_H +#define _SHA256_H +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ENABLE_SHA (0x1) +#define SHA256_BIG_ENDIAN (0x1) + +#define SHA256_HASH_LEN 32 +#define SHA256_HASH_WORDS 8 +#define SHA256_BLOCK_LEN 64L + +typedef struct _sha_num_reg +{ + /* The total amount of data calculated by SHA256 is set by this register, and the smallest unit is 512bit. */ + uint32_t sha_data_cnt : 16; + /* currently calculated block number. 512bit=1block*/ + uint32_t sha_data_num : 16; +} __attribute__((packed, aligned(4))) sha_num_reg_t; + +typedef struct _sha_function_reg_0 +{ + /* write:SHA256 enable register. read:Calculation completed flag */ + uint32_t sha_en : 1; + uint32_t reserved00 : 7; + /* SHA256 calculation overflow flag */ + uint32_t sha_overflow : 1; + uint32_t reserved01 : 7; + /* Endian setting; b'0:little endian b'1:big endian */ + uint32_t sha_endian : 1; + uint32_t reserved02 : 15; +} __attribute__((packed, aligned(4))) sha_function_reg_0_t; + +typedef struct _sha_function_reg_1 +{ + /* Sha and DMA handshake signals enable.b'1:enable;b'0:disable */ + uint32_t dma_en : 1; + uint32_t reserved10 : 7; + /* b'1:sha256 fifo is full; b'0:not full */ + uint32_t fifo_in_full : 1; + uint32_t reserved11 : 23; +} __attribute__((packed, aligned(4))) sha_function_reg_1_t; + +typedef struct _sha256 +{ + /* Calculated sha256 return value. */ + uint32_t sha_result[8]; + /* SHA256 input data from this register. */ + uint32_t sha_data_in1; + uint32_t reselved0; + sha_num_reg_t sha_num_reg; + sha_function_reg_0_t sha_function_reg_0; + uint32_t reserved1; + sha_function_reg_1_t sha_function_reg_1; +} __attribute__((packed, aligned(4))) sha256_t; + +typedef struct _sha256_context +{ + size_t total_len; + size_t buffer_len; + union + { + uint32_t words[16]; + uint8_t bytes[64]; + } buffer; +} sha256_context_t; + +/** + * @brief Init SHA256 calculation context + * + * @param[in] context SHA256 context object + * + */ +void sha256_init(sha256_context_t *context, size_t input_len); + +/** + * @brief Called repeatedly with chunks of the message to be hashed + * + * @param[in] context SHA256 context object + * @param[in] data_buf data chunk to be hashed + * @param[in] buf_len length of data chunk + * + */ +void sha256_update(sha256_context_t *context, const void *input, size_t input_len); + +/** + * @brief Finish SHA256 hash process, output the result. + * + * @param[in] context SHA256 context object + * @param[out] output The buffer where SHA256 hash will be output + * + */ +void sha256_final(sha256_context_t *context, uint8_t *output); + +/** + * @brief Simple SHA256 hash once. + * + * @param[in] data Data will be hashed + * @param[in] data_len Data length + * @param[out] output Output buffer + * + */ +void sha256_hard_calculate(const uint8_t *input, size_t input_len, uint8_t *output); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib/drivers/include/spi.h b/lib/drivers/include/spi.h new file mode 100755 index 0000000..d55b3a9 --- /dev/null +++ b/lib/drivers/include/spi.h @@ -0,0 +1,388 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_SPI_H +#define _DRIVER_SPI_H + +#include +#include +#include "dmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _spi +{ + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))) spi_t; +/* clang-format on */ + +typedef enum _spi_device_num +{ + SPI_DEVICE_0, + SPI_DEVICE_1, + SPI_DEVICE_2, + SPI_DEVICE_3, + SPI_DEVICE_MAX, +} spi_device_num_t; + +typedef enum _spi_work_mode +{ + SPI_WORK_MODE_0, + SPI_WORK_MODE_1, + SPI_WORK_MODE_2, + SPI_WORK_MODE_3, +} spi_work_mode_t; + +typedef enum _spi_frame_format +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format_t; + +typedef enum _spi_instruction_address_trans_mode +{ + SPI_AITM_STANDARD, + SPI_AITM_ADDR_STANDARD, + SPI_AITM_AS_FRAME_FORMAT +} spi_instruction_address_trans_mode_t; + +typedef enum _spi_transfer_mode +{ + SPI_TMOD_TRANS_RECV, + SPI_TMOD_TRANS, + SPI_TMOD_RECV, + SPI_TMOD_EEROM +} spi_transfer_mode_t; + + +typedef enum _spi_transfer_width +{ + SPI_TRANS_CHAR = 0x1, + SPI_TRANS_SHORT = 0x2, + SPI_TRANS_INT = 0x4, +} spi_transfer_width_t; + +typedef enum _spi_chip_select +{ + SPI_CHIP_SELECT_0, + SPI_CHIP_SELECT_1, + SPI_CHIP_SELECT_2, + SPI_CHIP_SELECT_3, + SPI_CHIP_SELECT_MAX, +} spi_chip_select_t; + + +extern volatile spi_t *const spi[4]; + +/** + * @brief Set spi configuration + * + * @param[in] spi_num Spi bus number + * @param[in] mode Spi mode + * @param[in] frame_format Spi frame format + * @param[in] data_bit_length Spi data bit length + * @param[in] endian 0:little-endian 1:big-endian + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian); + +/** + * @brief Set multiline configuration + * + * @param[in] spi_num Spi bus number + * @param[in] instruction_length Instruction length + * @param[in] address_length Address length + * @param[in] wait_cycles Wait cycles + * @param[in] instruction_address_trans_mode Spi transfer mode + * + */ +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode); + +/** + * @brief Spi send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *cmd_buff, size_t cmd_len, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data by dma + * + * @param[in] w_channel_num Dmac write channel number + * @param[in] r_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *cmd_buff, size_t cmd_len, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi special receive data by dma + * + * @param[in] dma_send_channel_num Dmac write channel number + * @param[in] dma_receive_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] cmd_buff Spi command buffer point + * @param[in] cmd_len Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi fill dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi command buffer point + * @param[in] tx_len Spi command length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len); + +/** + * @brief Spi normal send by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * @param[in] stw Spi transfer width + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width); + +/** + * @brief Spi normal send by dma + * + * @param[in] spi_num Spi bus number + * @param[in] spi_clk Spi clock rate + * + * @return The real spi clock rate + */ +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SPI_H */ diff --git a/lib/drivers/include/sysctl.h b/lib/drivers/include/sysctl.h new file mode 100755 index 0000000..be394d0 --- /dev/null +++ b/lib/drivers/include/sysctl.h @@ -0,0 +1,1042 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_SYSCTL_H +#define _DRIVER_SYSCTL_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief System controller register + * + * @note System controller register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | git_id | Git short commit id | + * | 0x04 | clk_freq | System clock base frequency | + * | 0x08 | pll0 | PLL0 controller | + * | 0x0c | pll1 | PLL1 controller | + * | 0x10 | pll2 | PLL2 controller | + * | 0x14 | resv5 | Reserved | + * | 0x18 | pll_lock | PLL lock tester | + * | 0x1c | rom_error | AXI ROM detector | + * | 0x20 | clk_sel0 | Clock select controller0 | + * | 0x24 | clk_sel1 | Clock select controller1 | + * | 0x28 | clk_en_cent | Central clock enable | + * | 0x2c | clk_en_peri | Peripheral clock enable | + * | 0x30 | soft_reset | Soft reset ctrl | + * | 0x34 | peri_reset | Peripheral reset controller | + * | 0x38 | clk_th0 | Clock threshold controller 0 | + * | 0x3c | clk_th1 | Clock threshold controller 1 | + * | 0x40 | clk_th2 | Clock threshold controller 2 | + * | 0x44 | clk_th3 | Clock threshold controller 3 | + * | 0x48 | clk_th4 | Clock threshold controller 4 | + * | 0x4c | clk_th5 | Clock threshold controller 5 | + * | 0x50 | clk_th6 | Clock threshold controller 6 | + * | 0x54 | misc | Miscellaneous controller | + * | 0x58 | peri | Peripheral controller | + * | 0x5c | spi_sleep | SPI sleep controller | + * | 0x60 | reset_status | Reset source status | + * | 0x64 | dma_sel0 | DMA handshake selector | + * | 0x68 | dma_sel1 | DMA handshake selector | + * | 0x6c | power_sel | IO Power Mode Select controller | + * | 0x70 | resv28 | Reserved | + * | 0x74 | resv29 | Reserved | + * | 0x78 | resv30 | Reserved | + * | 0x7c | resv31 | Reserved | + * + */ + +typedef enum _sysctl_pll_t +{ + SYSCTL_PLL0, + SYSCTL_PLL1, + SYSCTL_PLL2, + SYSCTL_PLL_MAX +} sysctl_pll_t; + +typedef enum _sysctl_clock_source_t +{ + SYSCTL_SOURCE_IN0, + SYSCTL_SOURCE_PLL0, + SYSCTL_SOURCE_PLL1, + SYSCTL_SOURCE_PLL2, + SYSCTL_SOURCE_ACLK, + SYSCTL_SOURCE_MAX +} sysctl_clock_source_t; + +typedef enum _sysctl_dma_channel_t +{ + SYSCTL_DMA_CHANNEL_0, + SYSCTL_DMA_CHANNEL_1, + SYSCTL_DMA_CHANNEL_2, + SYSCTL_DMA_CHANNEL_3, + SYSCTL_DMA_CHANNEL_4, + SYSCTL_DMA_CHANNEL_5, + SYSCTL_DMA_CHANNEL_MAX +} sysctl_dma_channel_t; + +typedef enum _sysctl_dma_select_t +{ + SYSCTL_DMA_SELECT_SSI0_RX_REQ, + SYSCTL_DMA_SELECT_SSI0_TX_REQ, + SYSCTL_DMA_SELECT_SSI1_RX_REQ, + SYSCTL_DMA_SELECT_SSI1_TX_REQ, + SYSCTL_DMA_SELECT_SSI2_RX_REQ, + SYSCTL_DMA_SELECT_SSI2_TX_REQ, + SYSCTL_DMA_SELECT_SSI3_RX_REQ, + SYSCTL_DMA_SELECT_SSI3_TX_REQ, + SYSCTL_DMA_SELECT_I2C0_RX_REQ, + SYSCTL_DMA_SELECT_I2C0_TX_REQ, + SYSCTL_DMA_SELECT_I2C1_RX_REQ, + SYSCTL_DMA_SELECT_I2C1_TX_REQ, + SYSCTL_DMA_SELECT_I2C2_RX_REQ, + SYSCTL_DMA_SELECT_I2C2_TX_REQ, + SYSCTL_DMA_SELECT_UART1_RX_REQ, + SYSCTL_DMA_SELECT_UART1_TX_REQ, + SYSCTL_DMA_SELECT_UART2_RX_REQ, + SYSCTL_DMA_SELECT_UART2_TX_REQ, + SYSCTL_DMA_SELECT_UART3_RX_REQ, + SYSCTL_DMA_SELECT_UART3_TX_REQ, + SYSCTL_DMA_SELECT_AES_REQ, + SYSCTL_DMA_SELECT_SHA_RX_REQ, + SYSCTL_DMA_SELECT_AI_RX_REQ, + SYSCTL_DMA_SELECT_FFT_RX_REQ, + SYSCTL_DMA_SELECT_FFT_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_TX_REQ, + SYSCTL_DMA_SELECT_I2S0_RX_REQ, + SYSCTL_DMA_SELECT_I2S1_TX_REQ, + SYSCTL_DMA_SELECT_I2S1_RX_REQ, + SYSCTL_DMA_SELECT_I2S2_TX_REQ, + SYSCTL_DMA_SELECT_I2S2_RX_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ, + SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ, + SYSCTL_DMA_SELECT_MAX +} sysctl_dma_select_t; + +/** + * @brief System controller clock id + */ +typedef enum _sysctl_clock_t +{ + SYSCTL_CLOCK_PLL0, + SYSCTL_CLOCK_PLL1, + SYSCTL_CLOCK_PLL2, + SYSCTL_CLOCK_CPU, + SYSCTL_CLOCK_SRAM0, + SYSCTL_CLOCK_SRAM1, + SYSCTL_CLOCK_APB0, + SYSCTL_CLOCK_APB1, + SYSCTL_CLOCK_APB2, + SYSCTL_CLOCK_ROM, + SYSCTL_CLOCK_DMA, + SYSCTL_CLOCK_AI, + SYSCTL_CLOCK_DVP, + SYSCTL_CLOCK_FFT, + SYSCTL_CLOCK_GPIO, + SYSCTL_CLOCK_SPI0, + SYSCTL_CLOCK_SPI1, + SYSCTL_CLOCK_SPI2, + SYSCTL_CLOCK_SPI3, + SYSCTL_CLOCK_I2S0, + SYSCTL_CLOCK_I2S1, + SYSCTL_CLOCK_I2S2, + SYSCTL_CLOCK_I2C0, + SYSCTL_CLOCK_I2C1, + SYSCTL_CLOCK_I2C2, + SYSCTL_CLOCK_UART1, + SYSCTL_CLOCK_UART2, + SYSCTL_CLOCK_UART3, + SYSCTL_CLOCK_AES, + SYSCTL_CLOCK_FPIOA, + SYSCTL_CLOCK_TIMER0, + SYSCTL_CLOCK_TIMER1, + SYSCTL_CLOCK_TIMER2, + SYSCTL_CLOCK_WDT0, + SYSCTL_CLOCK_WDT1, + SYSCTL_CLOCK_SHA, + SYSCTL_CLOCK_OTP, + SYSCTL_CLOCK_RTC, + SYSCTL_CLOCK_ACLK = 40, + SYSCTL_CLOCK_HCLK, + SYSCTL_CLOCK_IN0, + SYSCTL_CLOCK_MAX +} sysctl_clock_t; + +/** + * @brief System controller clock select id + */ +typedef enum _sysctl_clock_select_t +{ + SYSCTL_CLOCK_SELECT_PLL0_BYPASS, + SYSCTL_CLOCK_SELECT_PLL1_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2_BYPASS, + SYSCTL_CLOCK_SELECT_PLL2, + SYSCTL_CLOCK_SELECT_ACLK, + SYSCTL_CLOCK_SELECT_SPI3, + SYSCTL_CLOCK_SELECT_TIMER0, + SYSCTL_CLOCK_SELECT_TIMER1, + SYSCTL_CLOCK_SELECT_TIMER2, + SYSCTL_CLOCK_SELECT_SPI3_SAMPLE, + SYSCTL_CLOCK_SELECT_MAX = 11 +} sysctl_clock_select_t; + +/** + * @brief System controller clock threshold id + */ +typedef enum _sysctl_threshold_t +{ + SYSCTL_THRESHOLD_ACLK, + SYSCTL_THRESHOLD_APB0, + SYSCTL_THRESHOLD_APB1, + SYSCTL_THRESHOLD_APB2, + SYSCTL_THRESHOLD_SRAM0, + SYSCTL_THRESHOLD_SRAM1, + SYSCTL_THRESHOLD_AI, + SYSCTL_THRESHOLD_DVP, + SYSCTL_THRESHOLD_ROM, + SYSCTL_THRESHOLD_SPI0, + SYSCTL_THRESHOLD_SPI1, + SYSCTL_THRESHOLD_SPI2, + SYSCTL_THRESHOLD_SPI3, + SYSCTL_THRESHOLD_TIMER0, + SYSCTL_THRESHOLD_TIMER1, + SYSCTL_THRESHOLD_TIMER2, + SYSCTL_THRESHOLD_I2S0, + SYSCTL_THRESHOLD_I2S1, + SYSCTL_THRESHOLD_I2S2, + SYSCTL_THRESHOLD_I2S0_M, + SYSCTL_THRESHOLD_I2S1_M, + SYSCTL_THRESHOLD_I2S2_M, + SYSCTL_THRESHOLD_I2C0, + SYSCTL_THRESHOLD_I2C1, + SYSCTL_THRESHOLD_I2C2, + SYSCTL_THRESHOLD_WDT0, + SYSCTL_THRESHOLD_WDT1, + SYSCTL_THRESHOLD_MAX = 28 +} sysctl_threshold_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_reset_t +{ + SYSCTL_RESET_SOC, + SYSCTL_RESET_ROM, + SYSCTL_RESET_DMA, + SYSCTL_RESET_AI, + SYSCTL_RESET_DVP, + SYSCTL_RESET_FFT, + SYSCTL_RESET_GPIO, + SYSCTL_RESET_SPI0, + SYSCTL_RESET_SPI1, + SYSCTL_RESET_SPI2, + SYSCTL_RESET_SPI3, + SYSCTL_RESET_I2S0, + SYSCTL_RESET_I2S1, + SYSCTL_RESET_I2S2, + SYSCTL_RESET_I2C0, + SYSCTL_RESET_I2C1, + SYSCTL_RESET_I2C2, + SYSCTL_RESET_UART1, + SYSCTL_RESET_UART2, + SYSCTL_RESET_UART3, + SYSCTL_RESET_AES, + SYSCTL_RESET_FPIOA, + SYSCTL_RESET_TIMER0, + SYSCTL_RESET_TIMER1, + SYSCTL_RESET_TIMER2, + SYSCTL_RESET_WDT0, + SYSCTL_RESET_WDT1, + SYSCTL_RESET_SHA, + SYSCTL_RESET_RTC, + SYSCTL_RESET_MAX = 31 +} sysctl_reset_t; + +typedef enum _sysctl_power_bank +{ + SYSCTL_POWER_BANK0, + SYSCTL_POWER_BANK1, + SYSCTL_POWER_BANK2, + SYSCTL_POWER_BANK3, + SYSCTL_POWER_BANK4, + SYSCTL_POWER_BANK5, + SYSCTL_POWER_BANK6, + SYSCTL_POWER_BANK7, + SYSCTL_POWER_BANK_MAX, +} sysctl_power_bank_t; + +/** + * @brief System controller reset control id + */ +typedef enum _sysctl_io_power_mode +{ + SYSCTL_POWER_V33, + SYSCTL_POWER_V18 +} sysctl_io_power_mode_t; + +/** + * @brief Git short commit id + * + * No. 0 Register (0x00) + */ +typedef struct _sysctl_git_id +{ + uint32_t git_id : 32; +} __attribute__((packed, aligned(4))) sysctl_git_id_t; + +/** + * @brief System clock base frequency + * + * No. 1 Register (0x04) + */ +typedef struct _sysctl_clk_freq +{ + uint32_t clk_freq : 32; +} __attribute__((packed, aligned(4))) sysctl_clk_freq_t; + +/** + * @brief PLL0 controller + * + * No. 2 Register (0x08) + */ +typedef struct _sysctl_pll0 +{ + uint32_t clkr0 : 4; + uint32_t clkf0 : 6; + uint32_t clkod0 : 4; + uint32_t bwadj0 : 6; + uint32_t pll_reset0 : 1; + uint32_t pll_pwrd0 : 1; + uint32_t pll_intfb0 : 1; + uint32_t pll_bypass0 : 1; + uint32_t pll_test0 : 1; + uint32_t pll_out_en0 : 1; + uint32_t pll_test_en : 1; + uint32_t reserved : 5; +} __attribute__((packed, aligned(4))) sysctl_pll0_t; + +/** + * @brief PLL1 controller + * + * No. 3 Register (0x0c) + */ +typedef struct _sysctl_pll1 +{ + uint32_t clkr1 : 4; + uint32_t clkf1 : 6; + uint32_t clkod1 : 4; + uint32_t bwadj1 : 6; + uint32_t pll_reset1 : 1; + uint32_t pll_pwrd1 : 1; + uint32_t pll_intfb1 : 1; + uint32_t pll_bypass1 : 1; + uint32_t pll_test1 : 1; + uint32_t pll_out_en1 : 1; + uint32_t reserved : 6; +} __attribute__((packed, aligned(4))) sysctl_pll1_t; + +/** + * @brief PLL2 controller + * + * No. 4 Register (0x10) + */ +typedef struct _sysctl_pll2 +{ + uint32_t clkr2 : 4; + uint32_t clkf2 : 6; + uint32_t clkod2 : 4; + uint32_t bwadj2 : 6; + uint32_t pll_reset2 : 1; + uint32_t pll_pwrd2 : 1; + uint32_t pll_intfb2 : 1; + uint32_t pll_bypass2 : 1; + uint32_t pll_test2 : 1; + uint32_t pll_out_en2 : 1; + uint32_t pll_ckin_sel2 : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_pll2_t; + +/** + * @brief PLL lock tester + * + * No. 6 Register (0x18) + */ +typedef struct _sysctl_pll_lock +{ + uint32_t pll_lock0 : 2; + uint32_t pll_slip_clear0 : 1; + uint32_t test_clk_out0 : 1; + uint32_t reserved0 : 4; + uint32_t pll_lock1 : 2; + uint32_t pll_slip_clear1 : 1; + uint32_t test_clk_out1 : 1; + uint32_t reserved1 : 4; + uint32_t pll_lock2 : 2; + uint32_t pll_slip_clear2 : 1; + uint32_t test_clk_out2 : 1; + uint32_t reserved2 : 12; +} __attribute__((packed, aligned(4))) sysctl_pll_lock_t; + +/** + * @brief AXI ROM detector + * + * No. 7 Register (0x1c) + */ +typedef struct _sysctl_rom_error +{ + uint32_t rom_mul_error : 1; + uint32_t rom_one_error : 1; + uint32_t reserved : 30; +} __attribute__((packed, aligned(4))) sysctl_rom_error_t; + +/** + * @brief Clock select controller0 + * + * No. 8 Register (0x20) + */ +typedef struct _sysctl_clk_sel0 +{ + uint32_t aclk_sel : 1; + uint32_t aclk_divider_sel : 2; + uint32_t apb0_clk_sel : 3; + uint32_t apb1_clk_sel : 3; + uint32_t apb2_clk_sel : 3; + uint32_t spi3_clk_sel : 1; + uint32_t timer0_clk_sel : 1; + uint32_t timer1_clk_sel : 1; + uint32_t timer2_clk_sel : 1; + uint32_t reserved : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t; + +/** + * @brief Clock select controller1 + * + * No. 9 Register (0x24) + */ +typedef struct _sysctl_clk_sel1 +{ + uint32_t spi3_sample_clk_sel : 1; + uint32_t reserved0 : 30; + uint32_t reserved1 : 1; +} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t; + +/** + * @brief Central clock enable + * + * No. 10 Register (0x28) + */ +typedef struct _sysctl_clk_en_cent +{ + uint32_t cpu_clk_en : 1; + uint32_t sram0_clk_en : 1; + uint32_t sram1_clk_en : 1; + uint32_t apb0_clk_en : 1; + uint32_t apb1_clk_en : 1; + uint32_t apb2_clk_en : 1; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t; + +/** + * @brief Peripheral clock enable + * + * No. 11 Register (0x2c) + */ +typedef struct _sysctl_clk_en_peri +{ + uint32_t rom_clk_en : 1; + uint32_t dma_clk_en : 1; + uint32_t ai_clk_en : 1; + uint32_t dvp_clk_en : 1; + uint32_t fft_clk_en : 1; + uint32_t gpio_clk_en : 1; + uint32_t spi0_clk_en : 1; + uint32_t spi1_clk_en : 1; + uint32_t spi2_clk_en : 1; + uint32_t spi3_clk_en : 1; + uint32_t i2s0_clk_en : 1; + uint32_t i2s1_clk_en : 1; + uint32_t i2s2_clk_en : 1; + uint32_t i2c0_clk_en : 1; + uint32_t i2c1_clk_en : 1; + uint32_t i2c2_clk_en : 1; + uint32_t uart1_clk_en : 1; + uint32_t uart2_clk_en : 1; + uint32_t uart3_clk_en : 1; + uint32_t aes_clk_en : 1; + uint32_t fpioa_clk_en : 1; + uint32_t timer0_clk_en : 1; + uint32_t timer1_clk_en : 1; + uint32_t timer2_clk_en : 1; + uint32_t wdt0_clk_en : 1; + uint32_t wdt1_clk_en : 1; + uint32_t sha_clk_en : 1; + uint32_t otp_clk_en : 1; + uint32_t reserved : 1; + uint32_t rtc_clk_en : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t; + +/** + * @brief Soft reset ctrl + * + * No. 12 Register (0x30) + */ +typedef struct _sysctl_soft_reset +{ + uint32_t soft_reset : 1; + uint32_t reserved : 31; +} __attribute__((packed, aligned(4))) sysctl_soft_reset_t; + +/** + * @brief Peripheral reset controller + * + * No. 13 Register (0x34) + */ +typedef struct _sysctl_peri_reset +{ + uint32_t rom_reset : 1; + uint32_t dma_reset : 1; + uint32_t ai_reset : 1; + uint32_t dvp_reset : 1; + uint32_t fft_reset : 1; + uint32_t gpio_reset : 1; + uint32_t spi0_reset : 1; + uint32_t spi1_reset : 1; + uint32_t spi2_reset : 1; + uint32_t spi3_reset : 1; + uint32_t i2s0_reset : 1; + uint32_t i2s1_reset : 1; + uint32_t i2s2_reset : 1; + uint32_t i2c0_reset : 1; + uint32_t i2c1_reset : 1; + uint32_t i2c2_reset : 1; + uint32_t uart1_reset : 1; + uint32_t uart2_reset : 1; + uint32_t uart3_reset : 1; + uint32_t aes_reset : 1; + uint32_t fpioa_reset : 1; + uint32_t timer0_reset : 1; + uint32_t timer1_reset : 1; + uint32_t timer2_reset : 1; + uint32_t wdt0_reset : 1; + uint32_t wdt1_reset : 1; + uint32_t sha_reset : 1; + uint32_t reserved : 2; + uint32_t rtc_reset : 1; + uint32_t reserved0 : 2; +} __attribute__((packed, aligned(4))) sysctl_peri_reset_t; + +/** + * @brief Clock threshold controller 0 + * + * No. 14 Register (0x38) + */ +typedef struct _sysctl_clk_th0 +{ + uint32_t sram0_gclk_threshold : 4; + uint32_t sram1_gclk_threshold : 4; + uint32_t ai_gclk_threshold : 4; + uint32_t dvp_gclk_threshold : 4; + uint32_t rom_gclk_threshold : 4; + uint32_t reserved : 12; +} __attribute__((packed, aligned(4))) sysctl_clk_th0_t; + +/** + * @brief Clock threshold controller 1 + * + * No. 15 Register (0x3c) + */ +typedef struct _sysctl_clk_th1 +{ + uint32_t spi0_clk_threshold : 8; + uint32_t spi1_clk_threshold : 8; + uint32_t spi2_clk_threshold : 8; + uint32_t spi3_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th1_t; + +/** + * @brief Clock threshold controller 2 + * + * No. 16 Register (0x40) + */ +typedef struct _sysctl_clk_th2 +{ + uint32_t timer0_clk_threshold : 8; + uint32_t timer1_clk_threshold : 8; + uint32_t timer2_clk_threshold : 8; + uint32_t reserved : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th2_t; + +/** + * @brief Clock threshold controller 3 + * + * No. 17 Register (0x44) + */ +typedef struct _sysctl_clk_th3 +{ + uint32_t i2s0_clk_threshold : 16; + uint32_t i2s1_clk_threshold : 16; +} __attribute__((packed, aligned(4))) sysctl_clk_th3_t; + +/** + * @brief Clock threshold controller 4 + * + * No. 18 Register (0x48) + */ +typedef struct _sysctl_clk_th4 +{ + uint32_t i2s2_clk_threshold : 16; + uint32_t i2s0_mclk_threshold : 8; + uint32_t i2s1_mclk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th4_t; + +/** + * @brief Clock threshold controller 5 + * + * No. 19 Register (0x4c) + */ +typedef struct _sysctl_clk_th5 +{ + uint32_t i2s2_mclk_threshold : 8; + uint32_t i2c0_clk_threshold : 8; + uint32_t i2c1_clk_threshold : 8; + uint32_t i2c2_clk_threshold : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th5_t; + +/** + * @brief Clock threshold controller 6 + * + * No. 20 Register (0x50) + */ +typedef struct _sysctl_clk_th6 +{ + uint32_t wdt0_clk_threshold : 8; + uint32_t wdt1_clk_threshold : 8; + uint32_t reserved0 : 8; + uint32_t reserved1 : 8; +} __attribute__((packed, aligned(4))) sysctl_clk_th6_t; + +/** + * @brief Miscellaneous controller + * + * No. 21 Register (0x54) + */ +typedef struct _sysctl_misc +{ + uint32_t debug_sel : 6; + uint32_t reserved0 : 4; + uint32_t spi_dvp_data_enable: 1; + uint32_t reserved1 : 21; +} __attribute__((packed, aligned(4))) sysctl_misc_t; + +/** + * @brief Peripheral controller + * + * No. 22 Register (0x58) + */ +typedef struct _sysctl_peri +{ + uint32_t timer0_pause : 1; + uint32_t timer1_pause : 1; + uint32_t timer2_pause : 1; + uint32_t timer3_pause : 1; + uint32_t timer4_pause : 1; + uint32_t timer5_pause : 1; + uint32_t timer6_pause : 1; + uint32_t timer7_pause : 1; + uint32_t timer8_pause : 1; + uint32_t timer9_pause : 1; + uint32_t timer10_pause : 1; + uint32_t timer11_pause : 1; + uint32_t spi0_xip_en : 1; + uint32_t spi1_xip_en : 1; + uint32_t spi2_xip_en : 1; + uint32_t spi3_xip_en : 1; + uint32_t spi0_clk_bypass : 1; + uint32_t spi1_clk_bypass : 1; + uint32_t spi2_clk_bypass : 1; + uint32_t i2s0_clk_bypass : 1; + uint32_t i2s1_clk_bypass : 1; + uint32_t i2s2_clk_bypass : 1; + uint32_t jtag_clk_bypass : 1; + uint32_t dvp_clk_bypass : 1; + uint32_t debug_clk_bypass : 1; + uint32_t reserved0 : 1; + uint32_t reserved1 : 6; +} __attribute__((packed, aligned(4))) sysctl_peri_t; + +/** + * @brief SPI sleep controller + * + * No. 23 Register (0x5c) + */ +typedef struct _sysctl_spi_sleep +{ + uint32_t ssi0_sleep : 1; + uint32_t ssi1_sleep : 1; + uint32_t ssi2_sleep : 1; + uint32_t ssi3_sleep : 1; + uint32_t reserved : 28; +} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t; + +/** + * @brief Reset source status + * + * No. 24 Register (0x60) + */ +typedef struct _sysctl_reset_status +{ + uint32_t reset_sts_clr : 1; + uint32_t pin_reset_sts : 1; + uint32_t wdt0_reset_sts : 1; + uint32_t wdt1_reset_sts : 1; + uint32_t soft_reset_sts : 1; + uint32_t reserved : 27; +} __attribute__((packed, aligned(4))) sysctl_reset_status_t; + +/** + * @brief DMA handshake selector + * + * No. 25 Register (0x64) + */ +typedef struct _sysctl_dma_sel0 +{ + uint32_t dma_sel0 : 6; + uint32_t dma_sel1 : 6; + uint32_t dma_sel2 : 6; + uint32_t dma_sel3 : 6; + uint32_t dma_sel4 : 6; + uint32_t reserved : 2; +} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t; + +/** + * @brief DMA handshake selector + * + * No. 26 Register (0x68) + */ +typedef struct _sysctl_dma_sel1 +{ + uint32_t dma_sel5 : 6; + uint32_t reserved : 26; +} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t; + +/** + * @brief IO Power Mode Select controller + * + * No. 27 Register (0x6c) + */ +typedef struct _sysctl_power_sel +{ + uint32_t power_mode_sel0 : 1; + uint32_t power_mode_sel1 : 1; + uint32_t power_mode_sel2 : 1; + uint32_t power_mode_sel3 : 1; + uint32_t power_mode_sel4 : 1; + uint32_t power_mode_sel5 : 1; + uint32_t power_mode_sel6 : 1; + uint32_t power_mode_sel7 : 1; + uint32_t reserved : 24; +} __attribute__((packed, aligned(4))) sysctl_power_sel_t; + +/** + * @brief System controller object + * + * The System controller is a peripheral device mapped in the + * internal memory map, discoverable in the Configuration String. + * It is responsible for low-level configuration of all system + * related peripheral device. It contain PLL controller, clock + * controller, reset controller, DMA handshake controller, SPI + * controller, timer controller, WDT controller and sleep + * controller. + */ +typedef struct _sysctl +{ + /* No. 0 (0x00): Git short commit id */ + sysctl_git_id_t git_id; + /* No. 1 (0x04): System clock base frequency */ + sysctl_clk_freq_t clk_freq; + /* No. 2 (0x08): PLL0 controller */ + sysctl_pll0_t pll0; + /* No. 3 (0x0c): PLL1 controller */ + sysctl_pll1_t pll1; + /* No. 4 (0x10): PLL2 controller */ + sysctl_pll2_t pll2; + /* No. 5 (0x14): Reserved */ + uint32_t resv5; + /* No. 6 (0x18): PLL lock tester */ + sysctl_pll_lock_t pll_lock; + /* No. 7 (0x1c): AXI ROM detector */ + sysctl_rom_error_t rom_error; + /* No. 8 (0x20): Clock select controller0 */ + sysctl_clk_sel0_t clk_sel0; + /* No. 9 (0x24): Clock select controller1 */ + sysctl_clk_sel1_t clk_sel1; + /* No. 10 (0x28): Central clock enable */ + sysctl_clk_en_cent_t clk_en_cent; + /* No. 11 (0x2c): Peripheral clock enable */ + sysctl_clk_en_peri_t clk_en_peri; + /* No. 12 (0x30): Soft reset ctrl */ + sysctl_soft_reset_t soft_reset; + /* No. 13 (0x34): Peripheral reset controller */ + sysctl_peri_reset_t peri_reset; + /* No. 14 (0x38): Clock threshold controller 0 */ + sysctl_clk_th0_t clk_th0; + /* No. 15 (0x3c): Clock threshold controller 1 */ + sysctl_clk_th1_t clk_th1; + /* No. 16 (0x40): Clock threshold controller 2 */ + sysctl_clk_th2_t clk_th2; + /* No. 17 (0x44): Clock threshold controller 3 */ + sysctl_clk_th3_t clk_th3; + /* No. 18 (0x48): Clock threshold controller 4 */ + sysctl_clk_th4_t clk_th4; + /* No. 19 (0x4c): Clock threshold controller 5 */ + sysctl_clk_th5_t clk_th5; + /* No. 20 (0x50): Clock threshold controller 6 */ + sysctl_clk_th6_t clk_th6; + /* No. 21 (0x54): Miscellaneous controller */ + sysctl_misc_t misc; + /* No. 22 (0x58): Peripheral controller */ + sysctl_peri_t peri; + /* No. 23 (0x5c): SPI sleep controller */ + sysctl_spi_sleep_t spi_sleep; + /* No. 24 (0x60): Reset source status */ + sysctl_reset_status_t reset_status; + /* No. 25 (0x64): DMA handshake selector */ + sysctl_dma_sel0_t dma_sel0; + /* No. 26 (0x68): DMA handshake selector */ + sysctl_dma_sel1_t dma_sel1; + /* No. 27 (0x6c): IO Power Mode Select controller */ + sysctl_power_sel_t power_sel; + /* No. 28 (0x70): Reserved */ + uint32_t resv28; + /* No. 29 (0x74): Reserved */ + uint32_t resv29; + /* No. 30 (0x78): Reserved */ + uint32_t resv30; + /* No. 31 (0x7c): Reserved */ + uint32_t resv31; +} __attribute__((packed, aligned(4))) sysctl_t; + +/** + * @brief Abstruct PLL struct + */ +typedef struct _sysctl_general_pll +{ + uint32_t clkr : 4; + uint32_t clkf : 6; + uint32_t clkod : 4; + uint32_t bwadj : 6; + uint32_t pll_reset : 1; + uint32_t pll_pwrd : 1; + uint32_t pll_intfb : 1; + uint32_t pll_bypass : 1; + uint32_t pll_test : 1; + uint32_t pll_out_en : 1; + uint32_t pll_ckin_sel : 2; + uint32_t reserved : 4; +} __attribute__((packed, aligned(4))) sysctl_general_pll_t; + +/** + * @brief System controller object instanse + */ +extern volatile sysctl_t *const sysctl; + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be enable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_enable(sysctl_clock_t clock); + +/** + * @brief Enable clock for peripheral + * + * @param[in] clock The clock to be disable + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_disable(sysctl_clock_t clock); + +/** + * @brief Sysctl clock set threshold + * + * @param[in] which Which threshold to set + * @param[in] threshold The threshold value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_threshold(sysctl_threshold_t which, int threshold); + +/** + * @brief Sysctl clock get threshold + * + * @param[in] which Which threshold to get + * + * @return The threshold value + * - Other Value of threshold + * - -1 Fail + */ +int sysctl_clock_get_threshold(sysctl_threshold_t which); + +/** + * @brief Sysctl clock set clock select + * + * @param[in] which Which clock select to set + * @param[in] select The clock select value + * + * @return result + * - 0 Success + * - Other Fail + */ +int sysctl_clock_set_clock_select(sysctl_clock_select_t which, int select); + +/** + * @brief Sysctl clock get clock select + * + * @param[in] which Which clock select to get + * + * @return The clock select value + * - Other Value of clock select + * - -1 Fail + */ +int sysctl_clock_get_clock_select(sysctl_clock_select_t which); + +/** + * @brief Get PLL frequency + * + * @param[in] pll The PLL id + * + * @return The frequency of PLL + */ +uint32_t sysctl_pll_get_freq(sysctl_pll_t pll); + +/** + * @brief Get base clock frequency by clock id + * + * @param[in] clock The clock id + * + * @return The clock frequency + */ +uint32_t sysctl_clock_get_freq(sysctl_clock_t clock); + +/** + * @brief Reset device by reset controller + * + * @param[in] reset The reset signal + */ +void sysctl_reset(sysctl_reset_t reset); + +/** + * @brief Enable the PLL and power on with reset + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_enable(sysctl_pll_t pll); + +/** + * @brief Disable the PLL and power off + * + * @param[in] pll The pll id + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_pll_disable(sysctl_pll_t pll); + +/** + * @brief Select DMA channel handshake peripheral signal + * + * @param[in] channel The DMA channel + * @param[in] select The peripheral select + * + * @return Result + * - 0 Success + * - Other Fail + */ +int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select); + +/** + * @brief Set SPI0_D0-D7 DVP_D0-D7 as spi and dvp data pin + * + * @param[in] en Enable or not + * + * @return Result + * - 0 Success + * - Other Fail + */ +uint32_t sysctl_set_spi0_dvp_data(uint8_t en); + +/** + * @brief Set io power mode + * + * @param[in] power_bank IO power bank + * @param[in] io_power_mode Set power mode 3.3v or 1.8 + * + * @return Result + * - 0 Success + * - Other Fail + */ +void sysctl_set_power_mode(sysctl_power_bank_t power_bank, sysctl_io_power_mode_t io_power_mode); + +/** + * @brief Set frequency of CPU + * @param[in] freq The desired frequency in Hz + * + * @return The actual frequency of CPU after set + */ +uint32_t sysctl_cpu_set_freq(uint32_t freq); + +/** + * @brief Init PLL freqency + * @param[in] pll The PLL id + * @param[in] pll_freq The desired frequency in Hz + + */ +uint32_t sysctl_pll_set_freq(sysctl_pll_t pll, uint32_t pll_freq); + +/** + * @brief Enable interrupt + */ +void sysctl_enable_irq(void); + +/** + * @brief Disable interrupt + */ +void sysctl_disable_irq(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_SYSCTL_H */ diff --git a/lib/drivers/include/timer.h b/lib/drivers/include/timer.h new file mode 100755 index 0000000..b9ae89b --- /dev/null +++ b/lib/drivers/include/timer.h @@ -0,0 +1,140 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_TIMER_H +#define _DRIVER_TIMER_H + +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _timer_channel +{ + /* TIMER_N Load Count Register (0x00+(N-1)*0x14) */ + volatile uint32_t load_count; + /* TIMER_N Current Value Register (0x04+(N-1)*0x14) */ + volatile uint32_t current_value; + /* TIMER_N Control Register (0x08+(N-1)*0x14) */ + volatile uint32_t control; + /* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */ + volatile uint32_t eoi; + /* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */ + volatile uint32_t intr_stat; +} __attribute__((packed, aligned(4))) timer_channel_t; + +typedef struct _kendryte_timer +{ + /* TIMER_N Register (0x00-0x4c) */ + volatile timer_channel_t channel[4]; + /* reserverd (0x50-0x9c) */ + volatile uint32_t resv1[20]; + /* TIMER Interrupt Status Register (0xa0) */ + volatile uint32_t intr_stat; + /* TIMER Interrupt Clear Register (0xa4) */ + volatile uint32_t eoi; + /* TIMER Raw Interrupt Status Register (0xa8) */ + volatile uint32_t raw_intr_stat; + /* TIMER Component Version Register (0xac) */ + volatile uint32_t comp_version; + /* TIMER_N Load Count2 Register (0xb0-0xbc) */ + volatile uint32_t load_count2[4]; +} __attribute__((packed, aligned(4))) kendryte_timer_t; + +typedef enum _timer_deivce_number +{ + TIMER_DEVICE_0, + TIMER_DEVICE_1, + TIMER_DEVICE_2, + TIMER_DEVICE_MAX, +} timer_device_number_t; + +typedef enum _timer_channel_number +{ + TIMER_CHANNEL_0, + TIMER_CHANNEL_1, + TIMER_CHANNEL_2, + TIMER_CHANNEL_3, + TIMER_CHANNEL_MAX, +} timer_channel_number_t; + +/* TIMER Control Register */ +#define TIMER_CR_ENABLE 0x00000001 +#define TIMER_CR_MODE_MASK 0x00000002 +#define TIMER_CR_FREE_MODE 0x00000000 +#define TIMER_CR_USER_MODE 0x00000002 +#define TIMER_CR_INTERRUPT_MASK 0x00000004 +#define TIMER_CR_PWM_ENABLE 0x00000008 +/* clang-format on */ + +extern volatile kendryte_timer_t *const timer[3]; + + +/** + * @brief Set timer timeout + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] nanoseconds timeout + * + * @return the real timeout + */ +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds); + +/** + * @brief Init timer + * + * @param[in] timer timer + */ +void timer_init(timer_device_number_t timer_number); + +/** + * @brief Set timer timeout function + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] func timeout function + * @param[in] priority interrupt priority + * + */ +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable); + +uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel); + +uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel); + +void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count); + +void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel); +void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div); +void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel); +void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_TIMER_H */ diff --git a/lib/drivers/include/uart.h b/lib/drivers/include/uart.h new file mode 100755 index 0000000..0532d3a --- /dev/null +++ b/lib/drivers/include/uart.h @@ -0,0 +1,195 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +/** + * @file + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * + */ + +#ifndef _DRIVER_APBUART_H +#define _DRIVER_APBUART_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _uart_dev +{ + UART_DEV1 = 0, + UART_DEV2, + UART_DEV3, +} uart_dev_t; + +typedef struct _uart +{ + union + { + volatile uint32_t RBR; + volatile uint32_t DLL; + volatile uint32_t THR; + }; + + union + { + volatile uint32_t DLH; + volatile uint32_t IER; + }; + + union + { + volatile uint32_t FCR; + volatile uint32_t IIR; + }; + + volatile uint32_t LCR; + volatile uint32_t MCR; + volatile uint32_t LSR; + volatile uint32_t MSR; + volatile uint32_t SCR; + volatile uint32_t LPDLL; + volatile uint32_t LPDLH; + volatile uint32_t reserve[18]; + volatile uint32_t FAR; + volatile uint32_t TFR; + volatile uint32_t RFW; + volatile uint32_t USR; + volatile uint32_t TFL; + volatile uint32_t RFL; + volatile uint32_t SRR; + volatile uint32_t SRTS; + volatile uint32_t SBCR; + volatile uint32_t SDMAM; + volatile uint32_t SFE; + volatile uint32_t SRT; + volatile uint32_t STET; + volatile uint32_t HTX; + volatile uint32_t DMASA; + volatile uint32_t TCR; + volatile uint32_t DE_EN; + volatile uint32_t RE_EN; + volatile uint32_t DET; + volatile uint32_t TAT; + volatile uint32_t DLF; + volatile uint32_t RAR; + volatile uint32_t TAR; + volatile uint32_t LCR_EXT; + volatile uint32_t R[5]; + volatile uint32_t CPR; + volatile uint32_t UCV; + volatile uint32_t CTR; +} uart_t; + +typedef enum _uart_device_number +{ + UART_DEVICE_1, + UART_DEVICE_2, + UART_DEVICE_3, + UART_DEVICE_MAX, +} uart_device_number_t; + +typedef enum _uart_bitwidth +{ + UART_BITWIDTH_5BIT = 0, + UART_BITWIDTH_6BIT, + UART_BITWIDTH_7BIT, + UART_BITWIDTH_8BIT, +} uart_bitwidth_t; + +typedef enum _uart_stopbit +{ + UART_STOP_1, + UART_STOP_1_5, + UART_STOP_2 +} uart_stopbit_t; + +typedef enum _uart_rede_sel +{ + DISABLE = 0, + ENABLE, +} uart_rede_sel_t; + +typedef enum _uart_parity +{ + UART_PARITY_NONE, + UART_PARITY_ODD, + UART_PARITY_EVEN +} uart_parity_t; + +/** + * @brief Send data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The data be transfer + * @param[in] len The data length + * + * @return Transfer length + */ +int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len); + +/** + * @brief Read data from uart + * + * @param[in] channel Uart index + * @param[in] buffer The Data received + * @param[in] len Receive length + * + * @return Receive length + */ +int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len); + +/** + * @brief Init uart + * + * @param[in] channel Uart index + * + */ +void uart_init(uart_device_number_t channel); + +/** + * @brief Set uart param + * + * @param[in] channel Uart index + * @param[in] baud_rate Baudrate + * @param[in] data_width Data width + * @param[in] stopbit Stop bit + * @param[in] parity Odd Even parity + * + */ +void uart_config(uart_device_number_t channel, uint32_t baud_rate, uart_bitwidth_t data_width, uart_stopbit_t stopbit, uart_parity_t parity); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_APBUART_H */ diff --git a/lib/drivers/include/uarths.h b/lib/drivers/include/uarths.h new file mode 100755 index 0000000..4cf17de --- /dev/null +++ b/lib/drivers/include/uarths.h @@ -0,0 +1,223 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +/** + * @file + * @brief Universal Asynchronous Receiver/Transmitter (UART) + * + * The UART peripheral supports the following features: + * + * - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start + * bit, 1 or 2 stop bits + * + * - 8-entry transmit and receive FIFO buffers with programmable + * watermark interrupts + * + * - 16× Rx oversampling with 2/3 majority voting per bit + * + * The UART peripheral does not support hardware flow control or + * other modem control signals, or synchronous serial data + * tranfesrs. + * + * @note UART RAM Layout + * + * | Address | Name | Description | + * |-----------|----------|---------------------------------| + * | 0x000 | txdata | Transmit data register | + * | 0x004 | rxdata | Receive data register | + * | 0x008 | txctrl | Transmit control register | + * | 0x00C | rxctrl | Receive control register | + * | 0x010 | ie | UART interrupt enable | + * | 0x014 | ip | UART Interrupt pending | + * | 0x018 | div | Baud rate divisor | + * + */ + +#ifndef _DRIVER_UARTHS_H +#define _DRIVER_UARTHS_H + +#include +#include "platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +/* Register address offsets */ +#define UARTHS_REG_TXFIFO (0x00) +#define UARTHS_REG_RXFIFO (0x04) +#define UARTHS_REG_TXCTRL (0x08) +#define UARTHS_REG_RXCTRL (0x0c) +#define UARTHS_REG_IE (0x10) +#define UARTHS_REG_IP (0x14) +#define UARTHS_REG_DIV (0x18) + +/* TXCTRL register */ +#define UARTHS_TXEN (0x01) +#define UARTHS_TXWM(x) (((x) & 0xffff) << 16) + +/* RXCTRL register */ +#define UARTHS_RXEN (0x01) +#define UARTHS_RXWM(x) (((x) & 0xffff) << 16) + +/* IP register */ +#define UARTHS_IP_TXWM (0x01) +#define UARTHS_IP_RXWM (0x02) +/* clang-format on */ + +typedef struct _uarths_txdata +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is full status */ + uint32_t full : 1; +} __attribute__((packed, aligned(4))) uarths_txdata_t; + +typedef struct _uarths_rxdata +{ + /* Bits [7:0] is data */ + uint32_t data : 8; + /* Bits [30:8] is 0 */ + uint32_t zero : 23; + /* Bit 31 is empty status */ + uint32_t empty : 1; +} __attribute__((packed, aligned(4))) uarths_rxdata_t; + +typedef struct _uarths_txctrl +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t txen : 1; + /* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */ + uint32_t nstop : 1; + /* Bits [15:2] is reserved */ + uint32_t resv0 : 14; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t txcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))) uarths_txctrl_t; + +typedef struct _uarths_rxctrl +{ + /* Bit 0 is txen, controls whether the Tx channel is active. */ + uint32_t rxen : 1; + /* Bits [15:1] is reserved */ + uint32_t resv0 : 15; + /* Bits [18:16] is threshold of interrupt triggers */ + uint32_t rxcnt : 3; + /* Bits [31:19] is reserved */ + uint32_t resv1 : 13; +} __attribute__((packed, aligned(4))) uarths_rxctrl_t; + +typedef struct _uarths_ip +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))) uarths_ip_t; + +typedef struct _uarths_ie +{ + /* Bit 0 is txwm, raised less than txcnt */ + uint32_t txwm : 1; + /* Bit 1 is txwm, raised greater than rxcnt */ + uint32_t rxwm : 1; + /* Bits [31:2] is 0 */ + uint32_t zero : 30; +} __attribute__((packed, aligned(4))) uarths_ie_t; + +typedef struct _uarths_div +{ + /* Bits [31:2] is baud rate divisor register */ + uint32_t div : 16; + /* Bits [31:16] is 0 */ + uint32_t zero : 16; +} __attribute__((packed, aligned(4))) uarths_div_t; + +typedef struct _uarths +{ + /* Address offset 0x00 */ + uarths_txdata_t txdata; + /* Address offset 0x04 */ + uarths_rxdata_t rxdata; + /* Address offset 0x08 */ + uarths_txctrl_t txctrl; + /* Address offset 0x0c */ + uarths_rxctrl_t rxctrl; + /* Address offset 0x10 */ + uarths_ie_t ie; + /* Address offset 0x14 */ + uarths_ip_t ip; + /* Address offset 0x18 */ + uarths_div_t div; +} __attribute__((packed, aligned(4))) uarths_t; + +extern volatile uarths_t *const uarths; + +/** + * @brief Initialization Core UART + * + * @return result + * - 0 Success + * - Other Fail + */ +void uarths_init(void); + +/** + * @brief Put a char to UART + * + * @param[in] c The char to put + * + * @note If c is '\n', a '\r' will be appended automatically + * + * @return result + * - 0 Success + * - Other Fail + */ +int uarths_putchar(char c); + +/** + * @brief Send a string to UART + * + * @param[in] s The string to send + * + * @note The string must ending with '\0' + * + * @return result + * - 0 Success + * - Other Fail + */ +int uarths_puts(const char *s); + + +/** + * @brief Get a byte from UART + * + * @return byte as int type from UART + */ +int uarths_getc(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_UARTHS_H */ diff --git a/lib/drivers/include/utils.h b/lib/drivers/include/utils.h new file mode 100755 index 0000000..4782d2f --- /dev/null +++ b/lib/drivers/include/utils.h @@ -0,0 +1,347 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_UTILS_H +#define _DRIVER_UTILS_H + +#ifdef __cplusplus +#include +#include +#include +#else /* __cplusplus */ +#include +#include +#include +#include +#endif /* __cplusplus */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifdef __ASSEMBLY__ +#define KENDRYTE_CAST(type, ptr) ptr +#else /* __ASSEMBLY__ */ +/** + * @brief Cast the pointer to specified pointer type. + * + * @param[in] type The pointer type to cast to + * @param[in] ptr The pointer to apply the type cast to + */ +#define KENDRYTE_CAST(type, ptr) ((type)(ptr)) +#endif /* __ASSEMBLY__ */ + +/** + * @addtogroup UTIL_RW_FUNC Memory Read/Write Utilities + * + * This section implements read and write functionality for various + * memory untis. The memory unit terms used for these functions are + * consistent with those used in the ARM Architecture Reference Manual + * ARMv7-A and ARMv7-R edition manual. The terms used for units of memory are: + * + * Unit of Memory | Abbreviation | Size in Bits + * :---------------|:-------------|:------------: + * Byte | byte | 8 + * Half Word | hword | 16 + * Word | word | 32 + * Double Word | dword | 64 + * + */ + +/** + * @brief Write the 8 bit byte to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 8 bit data byte to write to memory + */ +#define kendryte_write_byte(dest, src) \ + (*KENDRYTE_CAST(volatile uint8_t*, (dest)) = (src)) + +/** + * @brief Read and return the 8 bit byte from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 8 bit data byte value + */ +#define kendryte_read_byte(src) (*KENDRYTE_CAST(volatile uint8_t*, (src))) + +/** + * @brief Write the 16 bit half word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 16 bit data half word to write to memory + */ +#define kendryte_write_hword(dest, src) \ + (*KENDRYTE_CAST(volatile uint16_t*, (dest)) = (src)) + +/** + * @brief Read and return the 16 bit half word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 16 bit data half word value + */ +#define kendryte_read_hword(src) (*KENDRYTE_CAST(volatile uint16_t*, (src))) + +/** + * @brief Write the 32 bit word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 32 bit data word to write to memory + */ +#define kendryte_write_word(dest, src) \ + (*KENDRYTE_CAST(volatile uint32_t*, (dest)) = (src)) + +/** + * @brief Read and return the 32 bit word from the source address in device memory. + * + * @param[in] src Read source pointer address + * + * @return 32 bit data half word value + */ +#define kendryte_read_word(src) (*KENDRYTE_CAST(volatile uint32_t*, (src))) + +/** + * @brief Write the 64 bit double word to the destination address in device memory. + * + * @param[in] dest Write destination pointer address + * @param[in] src 64 bit data word to write to memory + */ +#define kendryte_write_dword(dest, src) \ + (*KENDRYTE_CAST(volatile uint64_t*, (dest)) = (src)) + +/** + * @brief Read and return the 64 bit double word from the source address in device + * + * @param[in] src Read source pointer address + * + * @return 64 bit data half word value + */ +#define kendryte_read_dword(src) (*KENDRYTE_CAST(volatile uint64_t*, (src))) + +/** + * @brief Set selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination byte + */ +#define kendryte_setbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) | (bits))) + +/** + * @brief Clear selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination byte + */ +#define kendryte_clrbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 8 bit byte at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination byte + */ +#define kendryte_xorbits_byte(dest, bits) \ + (kendryte_write_byte(dest, kendryte_read_byte(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 8 bit byte at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination byte + */ +#define kendryte_replbits_byte(dest, msk, src) \ + (kendryte_write_byte(dest, (kendryte_read_byte(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination halfword + */ +#define kendryte_setbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination halfword + */ +#define kendryte_clrbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 16 bit halfword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination halfword + */ +#define kendryte_xorbits_hword(dest, bits) \ + (kendryte_write_hword(dest, kendryte_read_hword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 16 bit halfword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination byte + * @param[in] src Source bits to write to cleared bits in destination halfword + */ +#define kendryte_replbits_hword(dest, msk, src) \ + (kendryte_write_hword(dest, (kendryte_read_hword(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination word + */ +#define kendryte_setbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) | (bits))) + +/** + * @brief Clear selected bits in the 32 bit word at the destination address in device + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination word + */ +#define kendryte_clrbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 32 bit word at the destination address + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination word + */ +#define kendryte_xorbits_word(dest, bits) \ + (kendryte_write_word(dest, kendryte_read_word(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 32 bit word at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk Bits to replace in destination word + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_word(dest, msk, src) \ + (kendryte_write_word(dest, (kendryte_read_word(dest) & ~(msk)) | ((src) & (msk)))) + +/** + * @brief Set selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to set in destination doubleword + */ +#define kendryte_setbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) | (bits))) + +/** + * @brief Clear selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to clear in destination doubleword + */ +#define kendryte_clrbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) & ~(bits))) + +/** + * @brief Change or toggle selected bits in the 64 bit doubleword at the destination + * + * @param[in] dest Destination pointer address + * @param[in] bits Bits to change in destination doubleword + */ +#define kendryte_xorbits_dword(dest, bits) \ + (kendryte_write_dword(dest, kendryte_read_dword(dest) ^ (bits))) + +/** + * @brief Replace selected bits in the 64 bit doubleword at the destination address in + * + * @param[in] dest Destination pointer address + * @param[in] msk its to replace in destination doubleword + * @param[in] src Source bits to write to cleared bits in destination word + */ +#define kendryte_replbits_dword(dest, msk, src) \ + (kendryte_write_dword(dest, (kendryte_read_dword(dest) & ~(msk)) | ((src) & (msk)))) + +#define configASSERT(x) \ + if ((x) == 0) \ + { \ + printf("(%s:%d) %s", __FILE__, __LINE__, #x); \ + for (;;) \ + ; \ + } + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask mask value + * @param[in] value The value to set + */ +void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value); + +/** + * @brief Set value by mask + * + * @param[in] bits The one be set + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * @param[in] value The value to set + */ +void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value); + +/** + * @brief Set bit for gpio, only set one bit + * + * @param[in] bits The one be set + * @param[in] idx Offset value + * @param[in] value The value to set + */ +void set_gpio_bit(volatile uint32_t *bits, size_t idx, uint32_t value); + +/** + * @brief Get bits value of mask + * + * @param[in] bits The source data + * @param[in] mask Mask value + * @param[in] offset Mask's offset + * + * @return The bits value of mask + */ +uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset); + +/** + * @brief Get a bit value by offset + * + * @param[in] bits The source data + * @param[in] offset Bit's offset + * + * + * @return The bit value + */ +uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _DRIVER_COMMON_H */ + diff --git a/lib/drivers/include/wdt.h b/lib/drivers/include/wdt.h new file mode 100755 index 0000000..70a102d --- /dev/null +++ b/lib/drivers/include/wdt.h @@ -0,0 +1,156 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _DRIVER_WDT_H +#define _DRIVER_WDT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _wdt +{ + /* WDT Control Register (0x00) */ + volatile uint32_t cr; + /* WDT Timeout Range Register (0x04) */ + volatile uint32_t torr; + /* WDT Current Counter Value Register (0x08) */ + volatile uint32_t ccvr; + /* WDT Counter Restart Register (0x0c) */ + volatile uint32_t crr; + /* WDT Interrupt Status Register (0x10) */ + volatile uint32_t stat; + /* WDT Interrupt Clear Register (0x14) */ + volatile uint32_t eoi; + /* reserverd (0x18) */ + volatile uint32_t resv1; + /* WDT Protection level Register (0x1c) */ + volatile uint32_t prot_level; + /* reserved (0x20-0xe0) */ + volatile uint32_t resv4[49]; + /* WDT Component Parameters Register 5 (0xe4) */ + volatile uint32_t comp_param_5; + /* WDT Component Parameters Register 4 (0xe8) */ + volatile uint32_t comp_param_4; + /* WDT Component Parameters Register 3 (0xec) */ + volatile uint32_t comp_param_3; + /* WDT Component Parameters Register 2 (0xf0) */ + volatile uint32_t comp_param_2; + /* WDT Component Parameters Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* WDT Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* WDT Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))) wdt_t; + +typedef enum _wdt_device_number +{ + WDT_DEVICE_0, + WDT_DEVICE_1, + WDT_DEVICE_MAX, +} wdt_device_number_t; + + +#define WDT_RESET_ALL 0x00000000U +#define WDT_RESET_CPU 0x00000001U + +/* WDT Control Register */ +#define WDT_CR_ENABLE 0x00000001U +#define WDT_CR_RMOD_MASK 0x00000002U +#define WDT_CR_RMOD_RESET 0x00000000U +#define WDT_CR_RMOD_INTERRUPT 0x00000002U +#define WDT_CR_RPL_MASK 0x0000001CU +#define WDT_CR_RPL(x) ((x) << 2) +/* WDT Timeout Range Register */ +#define WDT_TORR_TOP_MASK 0x000000FFU +#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0) +/* WDT Current Counter Value Register */ +#define WDT_CCVR_MASK 0xFFFFFFFFU +/* WDT Counter Restart Register */ +#define WDT_CRR_MASK 0x00000076U +/* WDT Interrupt Status Register */ +#define WDT_STAT_MASK 0x00000001U +/* WDT Interrupt Clear Register */ +#define WDT_EOI_MASK 0x00000001U +/* WDT Protection level Register */ +#define WDT_PROT_LEVEL_MASK 0x00000007U +/* WDT Component Parameter Register 5 */ +#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 4 */ +#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 3 */ +#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 2 */ +#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 1 */ +#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U +#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U +#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U +#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U +#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U +#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U +#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U +#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U +#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U +#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U +#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U +/* WDT Component Version Register */ +#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU +/* WDT Component Type Register */ +#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU +/* clang-format on */ + +/** + * @brief Feed wdt + */ +void wdt_feed(wdt_device_number_t id); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] time_out_ms Wdt trigger time + * + */ +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq); + +/** + * @brief Stop wdt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_stop(wdt_device_number_t id); + +/** + * @brief Clear wdt interrupt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_clear_interrupt(wdt_device_number_t id); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_WDT_H */ diff --git a/lib/drivers/plic.c b/lib/drivers/plic.c new file mode 100755 index 0000000..72bed79 --- /dev/null +++ b/lib/drivers/plic.c @@ -0,0 +1,202 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "encoding.h" +#include "plic.h" +#include "syscalls.h" +#include "syslog.h" + +volatile plic_t* const plic = (volatile plic_t*)PLIC_BASE_ADDR; + +typedef struct _plic_instance_t +{ + plic_irq_callback_t callback; + void *ctx; +} plic_instance_t; + +static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX]; + +void plic_init(void) +{ + int i = 0; + + /* Get current core id */ + unsigned long core_id = current_coreid(); + + /* Disable all interrupts for the current core. */ + for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++) + plic->target_enables.target[core_id].enable[i] = 0; + + /* Set priorities to zero. */ + for (i = 0; i < PLIC_NUM_SOURCES; i++) + plic->source_priorities.priority[i] = 0; + + /* Set the threshold to zero. */ + plic->targets.target[core_id].priority_threshold = 0; + + /* Clear PLIC instance for every cores */ + for (i = 0; i < IRQN_MAX; i++) + { + /* clang-format off */ + plic_instance[core_id][i] = (const plic_instance_t){ + .callback = NULL, + .ctx = NULL, + }; + /* clang-format on */ + } + + /* + * A successful claim will also atomically clear the corresponding + * pending bit on the interrupt source. A target can perform a claim + * at any time, even if the EIP is not set. + */ + i = 0; + while (plic->targets.target[core_id].claim_complete > 0 && i < 100) + { + /* This loop will clear pending bit on the interrupt source */ + i++; + } + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +int plic_irq_enable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long core_id = current_coreid(); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; + /* Set enable bit in enable bit array */ + current |= (uint32_t)1 << (irq_number % 32); + /* Write back the enable bit array */ + plic->target_enables.target[core_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_irq_disable(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + unsigned long core_id = current_coreid(); + /* Get current enable bit array by IRQ number */ + uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; + /* Clear enable bit in enable bit array */ + current &= ~((uint32_t)1 << (irq_number % 32)); + /* Write back the enable bit array */ + plic->target_enables.target[core_id].enable[irq_number / 32] = current; + return 0; +} + +int plic_set_priority(plic_irq_t irq_number, uint32_t priority) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return -1; + /* Set interrupt priority by IRQ number */ + plic->source_priorities.priority[irq_number] = priority; + return 0; +} + +uint32_t plic_get_priority(plic_irq_t irq_number) +{ + /* Check parameters */ + if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) + return 0; + /* Get interrupt priority by IRQ number */ + return plic->source_priorities.priority[irq_number]; +} + +uint32_t plic_irq_claim(void) +{ + unsigned long core_id = current_coreid(); + /* Perform IRQ claim */ + return plic->targets.target[core_id].claim_complete; +} + +int plic_irq_complete(uint32_t source) +{ + unsigned long core_id = current_coreid(); + /* Perform IRQ complete */ + plic->targets.target[core_id].claim_complete = source; + return 0; +} + +void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx) +{ + /* Read core id */ + unsigned long core_id = current_coreid(); + /* Set user callback function */ + plic_instance[core_id][irq].callback = callback; + /* Assign user context */ + plic_instance[core_id][irq].ctx = ctx; +} + +void plic_irq_deregister(plic_irq_t irq) +{ + /* Just assign NULL to user callback function and context */ + plic_irq_register(irq, NULL, NULL); +} + +/*Entry Point for PLIC Interrupt Handler*/ +uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc) +{ + /* + * After the highest-priority pending interrupt is claimed by a target + * and the corresponding IP bit is cleared, other lower-priority + * pending interrupts might then become visible to the target, and so + * the PLIC EIP bit might not be cleared after a claim. The interrupt + * handler can check the local meip/heip/seip/ueip bits before exiting + * the handler, to allow more efficient service of other interrupts + * without first restoring the interrupted context and taking another + * interrupt trap. + */ + if (read_csr(mip) & MIP_MEIP) + { + /* Get current core id */ + uint64_t core_id = current_coreid(); + /* Get primitive interrupt enable flag */ + uint64_t ie_flag = read_csr(mie); + /* Get current IRQ num */ + uint32_t int_num = plic->targets.target[core_id].claim_complete; + /* Get primitive IRQ threshold */ + uint32_t int_threshold = plic->targets.target[core_id].priority_threshold; + /* Set new IRQ threshold = current IRQ threshold */ + plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num]; + /* Disable software interrupt and timer interrupt */ + clear_csr(mie, MIP_MTIP | MIP_MSIP); + /* Enable global interrupt */ + set_csr(mstatus, MSTATUS_MIE); + if (plic_instance[core_id][int_num].callback) + plic_instance[core_id][int_num].callback( + plic_instance[core_id][int_num].ctx); + /* Perform IRQ complete */ + plic->targets.target[core_id].claim_complete = int_num; + /* Disable global interrupt */ + clear_csr(mstatus, MSTATUS_MIE); + /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */ + set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); + /* Restore primitive interrupt enable flag */ + write_csr(mie, ie_flag); + /* Restore primitive IRQ threshold */ + plic->targets.target[core_id].priority_threshold = int_threshold; + } + + return epc; +} diff --git a/lib/drivers/pwm.c b/lib/drivers/pwm.c new file mode 100755 index 0000000..9d1ed11 --- /dev/null +++ b/lib/drivers/pwm.c @@ -0,0 +1,50 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "timer.h" +#include "pwm.h" +#include "sysctl.h" +#include +#include "utils.h" +#include "plic.h" +#include "io.h" + +void pwm_init(pwm_device_number_t pwm_number) +{ + sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + pwm_number); +} + +void pwm_set_enable(pwm_device_number_t pwm_number, pwm_channel_number_t channel, int enable) +{ + if (enable) + timer[pwm_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK | TIMER_CR_PWM_ENABLE | TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[pwm_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +double pwm_set_frequency(pwm_device_number_t pwm_number, pwm_channel_number_t channel, double frequency, double duty) +{ + uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + pwm_number); + + int32_t periods = (int32_t)(clk_freq / frequency); + configASSERT(periods > 0 && periods <= INT32_MAX); + frequency = clk_freq / (double)periods; + + uint32_t percent = (uint32_t)(duty * periods); + timer[pwm_number]->channel[channel].load_count = periods - percent; + timer[pwm_number]->load_count2[channel] = percent; + + return frequency; +} + diff --git a/lib/drivers/rtc.c b/lib/drivers/rtc.c new file mode 100755 index 0000000..c16d5a1 --- /dev/null +++ b/lib/drivers/rtc.c @@ -0,0 +1,587 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include +#include "encoding.h" +#include "sysctl.h" +#include "rtc.h" + +volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR; + +struct tm rtc_date_time; + +void rtc_timer_set_mode(rtc_timer_mode_t timer_mode) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + switch (timer_mode) + { + case RTC_TIMER_PAUSE: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_RUNNING: + register_ctrl.read_enable = 1; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_SETTING: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 1; + break; + default: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + } + rtc->register_ctrl = register_ctrl; +} + +rtc_timer_mode_t rtc_timer_get_mode(void) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE; + + if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_PAUSE */ + timer_mode = RTC_TIMER_PAUSE; + } + else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_RUNNING */ + timer_mode = RTC_TIMER_RUNNING; + } + else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) { + /* RTC_TIMER_SETTING */ + timer_mode = RTC_TIMER_RUNNING; + } + else + { + /* Something is error, reset timer mode */ + rtc_timer_set_mode(timer_mode); + } + + return timer_mode; +} + +static inline int rtc_in_range(int value, int min, int max) +{ + return ((value >= min) && (value <= max)); +} + +int rtc_timer_set_tm(const struct tm *tm) +{ + rtc_date_t timer_date; + rtc_time_t timer_time; + rtc_extended_t timer_extended; + + if (tm) + { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + timer_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + timer_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + timer_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + timer_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + timer_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + timer_date.year = rtc_year; + timer_extended.century = rtc_century; + } + else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + timer_date.week = tm->tm_wday; + else + return -1; + + /* Set RTC mode to timer setting mode */ + rtc_timer_set_mode(RTC_TIMER_SETTING); + /* Write value to RTC */ + rtc->date = timer_date; + rtc->time = timer_time; + rtc->extended = timer_extended; + /* Get CPU current freq */ + unsigned long freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + /* Set threshold to 1/26000000 s */ + freq = freq / 26000000; + /* Get current CPU cycle */ + unsigned long start_cycle = read_cycle(); + /* Wait for 1/26000000 s to sync data */ + while (read_cycle() - start_cycle < freq) + continue; + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + } + + return 0; +} + +int rtc_timer_set_alarm_tm(const struct tm *tm) +{ + rtc_alarm_date_t alarm_date; + rtc_alarm_time_t alarm_time; + + if (tm) { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + alarm_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + alarm_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + alarm_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + alarm_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + alarm_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + alarm_date.year = rtc_year; + } else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + alarm_date.week = tm->tm_wday; + else + return -1; + + /* Write value to RTC */ + rtc->alarm_date = alarm_date; + rtc->alarm_time = alarm_time; + } + + return 0; +} + +static int rtc_year_is_leap(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static int rtc_get_yday(int year, int month, int day) +{ + static const int days[2][13] = + { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + int leap = rtc_year_is_leap(year); + + return days[leap][month] + day; +} + +static int rtc_get_wday(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +struct tm *rtc_timer_get_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_date_t timer_date = rtc->date; + rtc_time_t timer_time = rtc->time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = timer_time.second % 60; + tm->tm_min = timer_time.minute % 60; + tm->tm_hour = timer_time.hour % 24; + tm->tm_mday = timer_date.day % 31; + tm->tm_mon = (timer_date.month % 12) - 1; + tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = timer_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +struct tm *rtc_timer_get_alarm_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_alarm_date_t alarm_date = rtc->alarm_date; + rtc_alarm_time_t alarm_time = rtc->alarm_time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = alarm_time.second % 60; + tm->tm_min = alarm_time.minute % 60; + tm->tm_hour = alarm_time.hour % 24; + tm->tm_mday = alarm_date.day % 31; + tm->tm_mon = (alarm_date.month % 12) - 1; + /* Alarm and Timer use same timer_extended.century */ + tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = alarm_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = + { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + return rtc_timer_set_tm(&date_time); +} + +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_tm(); + + if (tm) + { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + + return rtc_timer_set_alarm_tm(&date_time); +} + +int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_alarm_tm(); + + if (tm) { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_clock_frequency(unsigned int frequency) +{ + + rtc_initial_count_t initial_count; + + initial_count.count = frequency; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->initial_count = initial_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_frequency(void) +{ + return rtc->initial_count.count; +} + +int rtc_timer_set_clock_count_value(unsigned int count) +{ + + rtc_current_count_t current_count; + + current_count.count = count; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->current_count = current_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_count_value(void) +{ + return rtc->current_count.count; +} + +int rtc_tick_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + interrupt_ctrl.tick_enable = enable; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_tick_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_enable; +} + +int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_t mode) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.tick_int_mode = mode; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +rtc_tick_interrupt_mode_t rtc_tick_interrupt_mode_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_int_mode; +} + +int rtc_alarm_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_enable = enable; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +int rtc_alarm_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.alarm_enable; +} + +int rtc_alarm_interrupt_mask_set(rtc_mask_t mask) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +rtc_mask_t rtc_alarm_interrupt_mask_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask; + + return *(rtc_mask_t *)&compare_mask; +} + +int rtc_protect_set(int enable) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + rtc_mask_t mask = + { + .second = 1, + /* Second mask */ + .minute = 1, + /* Minute mask */ + .hour = 1, + /* Hour mask */ + .week = 1, + /* Week mask */ + .day = 1, + /* Day mask */ + .month = 1, + /* Month mask */ + .year = 1, + }; + + rtc_mask_t unmask = + { + .second = 0, + /* Second mask */ + .minute = 0, + /* Minute mask */ + .hour = 0, + /* Hour mask */ + .week = 0, + /* Week mask */ + .day = 0, + /* Day mask */ + .month = 0, + /* Month mask */ + .year = 0, + }; + + if (enable) + { + /* Turn RTC in protect mode, no one can write time */ + register_ctrl.timer_mask = *(uint8_t *)&unmask; + register_ctrl.alarm_mask = *(uint8_t *)&unmask; + register_ctrl.initial_count_mask = 0; + register_ctrl.interrupt_register_mask = 0; + } + else + { + /* Turn RTC in unprotect mode, everyone can write time */ + register_ctrl.timer_mask = *(uint8_t *)&mask; + register_ctrl.alarm_mask = *(uint8_t *)&mask; + register_ctrl.initial_count_mask = 1; + register_ctrl.interrupt_register_mask = 1; + } + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->register_ctrl = register_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_init(void) +{ + /* Reset RTC */ + sysctl_reset(SYSCTL_RESET_RTC); + /* Enable RTC */ + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + /* Unprotect RTC */ + rtc_protect_set(0); + /* Set RTC clock frequency */ + rtc_timer_set_clock_frequency( + sysctl_clock_get_freq(SYSCTL_CLOCK_IN0) + ); + rtc_timer_set_clock_count_value(1); + + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} diff --git a/lib/drivers/sha256.c b/lib/drivers/sha256.c new file mode 100755 index 0000000..2200911 --- /dev/null +++ b/lib/drivers/sha256.c @@ -0,0 +1,120 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "sysctl.h" +#include "sha256.h" +#include "utils.h" + +#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define BYTESWAP(x) ((ROTR((x), 8) & 0xff00ff00L) | (ROTL((x), 8) & 0x00ff00ffL)) +#define BYTESWAP64(x) byteswap64(x) + +volatile sha256_t* const sha256 = (volatile sha256_t*)SHA256_BASE_ADDR; +static const uint8_t padding[64] = +{ + 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 +}; + +static inline uint64_t byteswap64(uint64_t x) +{ + uint32_t a = (uint32_t)(x >> 32); + uint32_t b = (uint32_t)x; + return ((uint64_t)BYTESWAP(b) << 32) | (uint64_t)BYTESWAP(a); +} + +void sha256_init(sha256_context_t *context, size_t input_len) +{ + sysctl_clock_enable(SYSCTL_CLOCK_SHA); + sysctl_reset(SYSCTL_RESET_SHA); + + sha256->sha_num_reg.sha_data_cnt = (uint32_t)((input_len + SHA256_BLOCK_LEN + 8) / SHA256_BLOCK_LEN); + sha256->sha_function_reg_1.dma_en = 0x0; + sha256->sha_function_reg_0.sha_endian = SHA256_BIG_ENDIAN; + sha256->sha_function_reg_0.sha_en = ENABLE_SHA; + context->total_len = 0L; + context->buffer_len = 0L; +} + +void sha256_update(sha256_context_t *context, const void *input, size_t input_len) +{ + const uint8_t *data = input; + size_t buffer_bytes_left; + size_t bytes_to_copy; + uint32_t i; + + while (input_len) + { + buffer_bytes_left = SHA256_BLOCK_LEN - context->buffer_len; + bytes_to_copy = buffer_bytes_left; + if (bytes_to_copy > input_len) + bytes_to_copy = input_len; + memcpy(&context->buffer.bytes[context->buffer_len], data, bytes_to_copy); + context->total_len += bytes_to_copy * 8L; + context->buffer_len += bytes_to_copy; + data += bytes_to_copy; + input_len -= bytes_to_copy; + if (context->buffer_len == SHA256_BLOCK_LEN) + { + for (i = 0; i < 16; i++) + { + while (sha256->sha_function_reg_1.fifo_in_full) + ; + sha256->sha_data_in1 = context->buffer.words[i]; + } + context->buffer_len = 0L; + } + } +} + +void sha256_final(sha256_context_t *context, uint8_t *output) +{ + size_t bytes_to_pad; + size_t length_pad; + uint32_t i; + + bytes_to_pad = 120L - context->buffer_len; + if (bytes_to_pad > 64L) + bytes_to_pad -= 64L; + length_pad = BYTESWAP64(context->total_len); + sha256_update(context, padding, bytes_to_pad); + sha256_update(context, &length_pad, 8L); + while (!(sha256->sha_function_reg_0.sha_en)) + ; + if (output) + { + for (i = 0; i < SHA256_HASH_WORDS; i++) + { + *((uint32_t *)output) = sha256->sha_result[SHA256_HASH_WORDS - i - 1]; + output += 4; + } + } +} + +void sha256_hard_calculate(const uint8_t *input, size_t input_len, uint8_t *output) +{ + sha256_context_t sha; + sha256_init(&sha, input_len); + sha256_update(&sha, input, input_len); + sha256_final(&sha, output); +} + diff --git a/lib/drivers/spi.c b/lib/drivers/spi.c new file mode 100755 index 0000000..e679c9a --- /dev/null +++ b/lib/drivers/spi.c @@ -0,0 +1,828 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "platform.h" +#include "spi.h" +#include "fpioa.h" +#include "utils.h" +#include "sysctl.h" +#include +#include + +volatile spi_t *const spi[4] = +{ + (volatile spi_t *)SPI0_BASE_ADDR, + (volatile spi_t *)SPI1_BASE_ADDR, + (volatile spi_t *)SPI_SLAVE_BASE_ADDR, + (volatile spi_t *)SPI3_BASE_ADDR +}; + +static spi_transfer_width_t get_frame_size(size_t data_bit_length) +{ + if (data_bit_length < 8) + return SPI_TRANS_CHAR; + else if (data_bit_length < 16) + return SPI_TRANS_SHORT; + return SPI_TRANS_INT; +} + +static int spi_clk_init(uint8_t spi_num) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + if(spi_num == 3) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1); + sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0 + spi_num, 0); + return 0; +} + +static void spi_set_tmod(uint8_t spi_num, uint32_t tmod) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + uint8_t tmod_offset = 0; + switch(spi_num) + { + case 0: + case 1: + tmod_offset = 8; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + tmod_offset = 10; + break; + } + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian) +{ + configASSERT(data_bit_length >= 4 && data_bit_length <= 32); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_clk_init(spi_num); + + uint8_t dfs_offset, frf_offset, work_mode_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + frf_offset = 21; + work_mode_offset = 6; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + frf_offset = 22; + work_mode_offset = 8; + break; + } + + switch (frame_format) + { + case SPI_FF_DUAL: + configASSERT(data_bit_length % 2 == 0); + break; + case SPI_FF_QUAD: + configASSERT(data_bit_length % 4 == 0); + break; + case SPI_FF_OCTAL: + configASSERT(data_bit_length % 8 == 0); + break; + default: + break; + } + volatile spi_t *spi_adapter = spi[spi_num]; + spi_adapter->baudr = 0x14; + spi_adapter->imr = 0x00; + spi_adapter->dmacr = 0x00; + spi_adapter->dmatdlr = 0x10; + spi_adapter->dmardlr = 0x00; + spi_adapter->ser = 0x00; + spi_adapter->ssienr = 0x00; + spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset); + spi_adapter->spi_ctrlr0 = 0; + spi_adapter->endian = endian; +} + +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode) +{ + configASSERT(wait_cycles < (1 << 5)); + configASSERT(instruction_address_trans_mode < 3); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t inst_l = 0; + switch (instruction_length) + { + case 0: + inst_l = 0; + break; + case 4: + inst_l = 1; + break; + case 8: + inst_l = 2; + break; + case 16: + inst_l = 3; + break; + default: + configASSERT(!"Invalid instruction length"); + break; + } + + configASSERT(address_length % 4 == 0 && address_length <= 60); + uint32_t addr_l = address_length / 4; + + spi_handle->spi_ctrlr0 = (wait_cycles << 11) | (inst_l << 8) | (addr_l << 2) | instruction_address_trans_mode; +} + +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk) +{ + uint32_t spi_baudr = sysctl_clock_get_freq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_clk; + if(spi_baudr < 2 ) + { + spi_baudr = 2; + } + else if(spi_baudr > 65534) + { + spi_baudr = 65534; + } + volatile spi_t *spi_adapter = spi[spi_num]; + spi_adapter->baudr = spi_baudr; + return sysctl_clock_get_freq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_baudr; +} + +void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + uint32_t i = 0; + while (tx_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = ((uint32_t *)tx_buff)[i++]; + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + for (index = 0; index < fifo_len / 2; index++) + spi_handle->dr[0] = ((uint16_t *)tx_buff)[i++]; + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = tx_buff[i++]; + break; + } + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + uint8_t *v_buf = malloc(cmd_len + tx_len); + size_t i; + for(i = 0; i < cmd_len; i++) + v_buf[i] = cmd_buff[i]; + for(i = 0; i < tx_len; i++) + v_buf[cmd_len + i] = tx_buff[i]; + + spi_send_data_normal(spi_num, chip_select, v_buf, cmd_len + tx_len); + free((void *)v_buf); +} + +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *cmd_buff, size_t cmd_len, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(cmd_len + tx_len); + for(i = 0; i < cmd_len / 4; i++) + buf[i] = ((uint32_t *)cmd_buff)[i]; + for(i = 0; i < tx_len / 4; i++) + buf[cmd_len / 4 + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = (cmd_len + tx_len) / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc((cmd_len + tx_len) / 2 * sizeof(uint32_t)); + for(i = 0; i < cmd_len / 2; i++) + buf[i] = ((uint16_t *)cmd_buff)[i]; + for(i = 0; i < tx_len / 2; i++) + buf[cmd_len / 2 + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = (cmd_len + tx_len) / 2; + break; + default: + buf = malloc((cmd_len + tx_len) * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + buf[i] = cmd_buff[i]; + for(i = 0; i < tx_len; i++) + buf[cmd_len + i] = tx_buff[i]; + v_send_len = cmd_len + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t *buf; + int i; + switch(spi_transfer_width) + { + case SPI_TRANS_SHORT: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint16_t *)tx_buff)[i]; + break; + case SPI_TRANS_INT: + buf = (uint32_t *)tx_buff; + break; + case SPI_TRANS_CHAR: + default: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint8_t *)tx_buff)[i]; + break; + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t) channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + if(spi_transfer_width != SPI_TRANS_INT) + free((void *)buf); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + uint32_t v_rx_len = 0; + uint32_t i = 0; + + v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < cmd_len ? fifo_len : cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = ((uint32_t *)cmd_buff)[i++]; + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + for (index = 0; index < fifo_len / 2; index++) + spi_handle->dr[0] = ((uint16_t *)cmd_buff)[i++]; + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = cmd_buff[i++]; + break; + } + spi_handle->ser = 1U << chip_select; + cmd_len -= fifo_len; + } + + i = 0; + while (rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + for (index = 0; index < fifo_len / 2; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_receive_data_normal_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const void *cmd_buff, + size_t cmd_len, void *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + if(cmd_len == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + + volatile spi_t *spi_handle = spi[spi_num]; + + spi_handle->ctrlr1 = (uint32_t)(rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + if(cmd_len) + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len); + if(cmd_len) + dmac_set_single_mode(dma_send_channel_num, cmd_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, cmd_len); + + spi_handle->ser = 1U << chip_select; + if(cmd_len) + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + + +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd; + uint32_t *read_buf; + size_t v_recv_len; + size_t v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + write_cmd = malloc(cmd_len + rx_len); + for(i = 0; i < cmd_len / 4; i++) + write_cmd[i] = ((uint32_t *)cmd_buff)[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len / 4; + v_cmd_len = cmd_len / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc((cmd_len + rx_len) /2 * sizeof(uint32_t)); + for(i = 0; i < cmd_len / 2; i++) + write_cmd[i] = ((uint16_t *)cmd_buff)[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len / 2; + v_cmd_len = cmd_len / 2; + break; + default: + write_cmd = malloc((cmd_len + rx_len) * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len; + v_cmd_len = cmd_len; + break; + } + + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, v_cmd_len, read_buf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_recv_len; i++) + ((uint32_t *)rx_buff)[i] = read_buf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = read_buf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = read_buf[i]; + break; + } + + free(write_cmd); +} + + +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + uint32_t v_cmd_len = cmd_len * 4; + uint32_t i = 0; + + uint32_t v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = *cmd_buff++; + + spi_handle->ser = 1U << chip_select; + v_cmd_len -= fifo_len; + } + + while (rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + for (index = 0; index < fifo_len / 2; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + spi_set_tmod(spi_num, SPI_TMOD_RECV); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd; + uint32_t *read_buf; + size_t v_recv_len; + size_t v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + write_cmd = malloc(cmd_len + rx_len); + for(i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len / 4; + v_cmd_len = cmd_len / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc(cmd_len + rx_len /2 * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len / 2; + v_cmd_len = cmd_len / 2; + break; + default: + write_cmd = malloc(cmd_len + rx_len * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + write_cmd[i] = cmd_buff[i]; + read_buf = &write_cmd[i]; + v_recv_len = rx_len; + v_cmd_len = cmd_len; + break; + } + + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, v_cmd_len, read_buf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_recv_len; i++) + ((uint32_t *)rx_buff)[i] = read_buf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = read_buf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = read_buf[i]; + break; + } + + free(write_cmd); +} + + +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff, + size_t cmd_len, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + + size_t v_cmd_len = cmd_len * 4; + while(v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = *cmd_buff++; + v_cmd_len -= fifo_len; + } + spi_send_data_normal(spi_num, chip_select, tx_buff, tx_len); +} + +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *cmd_buff, size_t cmd_len, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num){ + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(cmd_len * sizeof(uint32_t) + tx_len); + for(i = 0; i < cmd_len; i++) + buf[i] = cmd_buff[i]; + for(i = 0; i < tx_len / 4; i++) + buf[cmd_len + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = cmd_len + tx_len / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc(cmd_len * sizeof(uint32_t) + tx_len / 2 * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + buf[i] = cmd_buff[i]; + for(i = 0; i < tx_len / 2; i++) + buf[cmd_len + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = cmd_len + tx_len / 2; + break; + default: + buf = malloc((cmd_len + tx_len) * sizeof(uint32_t)); + for(i = 0; i < cmd_len; i++) + buf[i] = cmd_buff[i]; + for(i = 0; i < tx_len; i++) + buf[cmd_len + i] = tx_buff[i]; + v_send_len = cmd_len + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, tx_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + diff --git a/lib/drivers/sysclock.c b/lib/drivers/sysclock.c new file mode 100755 index 0000000..583c9b2 --- /dev/null +++ b/lib/drivers/sysclock.c @@ -0,0 +1,18 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "stdio.h" +#include "sysctl.h" +#include "uarths.h" + diff --git a/lib/drivers/sysctl.c b/lib/drivers/sysctl.c new file mode 100755 index 0000000..d085058 --- /dev/null +++ b/lib/drivers/sysctl.c @@ -0,0 +1,1823 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include +#include +#include "sysctl.h" +#include "string.h" +#include "encoding.h" + +#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL) + +const uint8_t get_select_pll2[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, + [SYSCTL_SOURCE_PLL1] = 2, +}; + +const uint8_t get_source_pll2[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, + [2] = SYSCTL_SOURCE_PLL1, +}; + +const uint8_t get_select_aclk[] = +{ + [SYSCTL_SOURCE_IN0] = 0, + [SYSCTL_SOURCE_PLL0] = 1, +}; + +const uint8_t get_source_aclk[] = +{ + [0] = SYSCTL_SOURCE_IN0, + [1] = SYSCTL_SOURCE_PLL0, +}; + +volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR; + +uint32_t sysctl_get_git_id(void) +{ + return sysctl->git_id.git_id; +} + +uint32_t sysctl_get_freq(void) +{ + return sysctl->clk_freq.clk_freq; +} + +static void sysctl_reset_ctl(sysctl_reset_t reset, uint8_t rst_value) +{ + switch (reset) + { + case SYSCTL_RESET_SOC: + sysctl->soft_reset.soft_reset = rst_value; + break; + case SYSCTL_RESET_ROM: + sysctl->peri_reset.rom_reset = rst_value; + break; + case SYSCTL_RESET_DMA: + sysctl->peri_reset.dma_reset = rst_value; + break; + case SYSCTL_RESET_AI: + sysctl->peri_reset.ai_reset = rst_value; + break; + case SYSCTL_RESET_DVP: + sysctl->peri_reset.dvp_reset = rst_value; + break; + case SYSCTL_RESET_FFT: + sysctl->peri_reset.fft_reset = rst_value; + break; + case SYSCTL_RESET_GPIO: + sysctl->peri_reset.gpio_reset = rst_value; + break; + case SYSCTL_RESET_SPI0: + sysctl->peri_reset.spi0_reset = rst_value; + break; + case SYSCTL_RESET_SPI1: + sysctl->peri_reset.spi1_reset = rst_value; + break; + case SYSCTL_RESET_SPI2: + sysctl->peri_reset.spi2_reset = rst_value; + break; + case SYSCTL_RESET_SPI3: + sysctl->peri_reset.spi3_reset = rst_value; + break; + case SYSCTL_RESET_I2S0: + sysctl->peri_reset.i2s0_reset = rst_value; + break; + case SYSCTL_RESET_I2S1: + sysctl->peri_reset.i2s1_reset = rst_value; + break; + case SYSCTL_RESET_I2S2: + sysctl->peri_reset.i2s2_reset = rst_value; + break; + case SYSCTL_RESET_I2C0: + sysctl->peri_reset.i2c0_reset = rst_value; + break; + case SYSCTL_RESET_I2C1: + sysctl->peri_reset.i2c1_reset = rst_value; + break; + case SYSCTL_RESET_I2C2: + sysctl->peri_reset.i2c2_reset = rst_value; + break; + case SYSCTL_RESET_UART1: + sysctl->peri_reset.uart1_reset = rst_value; + break; + case SYSCTL_RESET_UART2: + sysctl->peri_reset.uart2_reset = rst_value; + break; + case SYSCTL_RESET_UART3: + sysctl->peri_reset.uart3_reset = rst_value; + break; + case SYSCTL_RESET_AES: + sysctl->peri_reset.aes_reset = rst_value; + break; + case SYSCTL_RESET_FPIOA: + sysctl->peri_reset.fpioa_reset = rst_value; + break; + case SYSCTL_RESET_TIMER0: + sysctl->peri_reset.timer0_reset = rst_value; + break; + case SYSCTL_RESET_TIMER1: + sysctl->peri_reset.timer1_reset = rst_value; + break; + case SYSCTL_RESET_TIMER2: + sysctl->peri_reset.timer2_reset = rst_value; + break; + case SYSCTL_RESET_WDT0: + sysctl->peri_reset.wdt0_reset = rst_value; + break; + case SYSCTL_RESET_WDT1: + sysctl->peri_reset.wdt1_reset = rst_value; + break; + case SYSCTL_RESET_SHA: + sysctl->peri_reset.sha_reset = rst_value; + break; + case SYSCTL_RESET_RTC: + sysctl->peri_reset.rtc_reset = rst_value; + break; + + default: + break; + } +} + +void sysctl_reset(sysctl_reset_t reset) +{ + sysctl_reset_ctl(reset, 1); + sysctl_reset_ctl(reset, 0); +} + +static int sysctl_clock_bus_en(sysctl_clock_t clock, uint8_t en) +{ + /* + * The timer is under APB0, to prevent apb0_clk_en1 and apb0_clk_en0 + * on same register, we split it to peripheral and central two + * registers, to protect CPU close apb0 clock accidentally. + * + * The apb0_clk_en0 and apb0_clk_en1 have same function, + * one of them set, the APB0 clock enable. + */ + + /* The APB clock should carefully disable */ + if (en) + { + switch (clock) + { + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + case SYSCTL_CLOCK_SPI2: + case SYSCTL_CLOCK_I2S0: + case SYSCTL_CLOCK_I2S1: + case SYSCTL_CLOCK_I2S2: + case SYSCTL_CLOCK_I2C0: + case SYSCTL_CLOCK_I2C1: + case SYSCTL_CLOCK_I2C2: + case SYSCTL_CLOCK_UART1: + case SYSCTL_CLOCK_UART2: + case SYSCTL_CLOCK_UART3: + case SYSCTL_CLOCK_FPIOA: + case SYSCTL_CLOCK_TIMER0: + case SYSCTL_CLOCK_TIMER1: + case SYSCTL_CLOCK_TIMER2: + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + case SYSCTL_CLOCK_WDT0: + case SYSCTL_CLOCK_WDT1: + case SYSCTL_CLOCK_OTP: + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + + default: + break; + } + } + + return 0; +} + +static int sysctl_clock_device_en(sysctl_clock_t clock, uint8_t en) +{ + switch (clock) + { + /* + * These devices are PLL + */ + case SYSCTL_CLOCK_PLL0: + sysctl->pll0.pll_out_en0 = en; + break; + case SYSCTL_CLOCK_PLL1: + sysctl->pll1.pll_out_en1 = en; + break; + case SYSCTL_CLOCK_PLL2: + sysctl->pll2.pll_out_en2 = en; + break; + + /* + * These devices are CPU, SRAM, APB bus, ROM, DMA, AI + */ + case SYSCTL_CLOCK_CPU: + sysctl->clk_en_cent.cpu_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM0: + sysctl->clk_en_cent.sram0_clk_en = en; + break; + case SYSCTL_CLOCK_SRAM1: + sysctl->clk_en_cent.sram1_clk_en = en; + break; + case SYSCTL_CLOCK_APB0: + sysctl->clk_en_cent.apb0_clk_en = en; + break; + case SYSCTL_CLOCK_APB1: + sysctl->clk_en_cent.apb1_clk_en = en; + break; + case SYSCTL_CLOCK_APB2: + sysctl->clk_en_cent.apb2_clk_en = en; + break; + case SYSCTL_CLOCK_ROM: + sysctl->clk_en_peri.rom_clk_en = en; + break; + case SYSCTL_CLOCK_DMA: + sysctl->clk_en_peri.dma_clk_en = en; + break; + case SYSCTL_CLOCK_AI: + sysctl->clk_en_peri.ai_clk_en = en; + break; + case SYSCTL_CLOCK_DVP: + sysctl->clk_en_peri.dvp_clk_en = en; + break; + case SYSCTL_CLOCK_FFT: + sysctl->clk_en_peri.fft_clk_en = en; + break; + case SYSCTL_CLOCK_SPI3: + sysctl->clk_en_peri.spi3_clk_en = en; + break; + + /* + * These peripheral devices are under APB0 + * GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1, + * I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0, + * TIMER1, TIMER2 + */ + case SYSCTL_CLOCK_GPIO: + sysctl->clk_en_peri.gpio_clk_en = en; + break; + case SYSCTL_CLOCK_SPI2: + sysctl->clk_en_peri.spi2_clk_en = en; + break; + case SYSCTL_CLOCK_I2S0: + sysctl->clk_en_peri.i2s0_clk_en = en; + break; + case SYSCTL_CLOCK_I2S1: + sysctl->clk_en_peri.i2s1_clk_en = en; + break; + case SYSCTL_CLOCK_I2S2: + sysctl->clk_en_peri.i2s2_clk_en = en; + break; + case SYSCTL_CLOCK_I2C0: + sysctl->clk_en_peri.i2c0_clk_en = en; + break; + case SYSCTL_CLOCK_I2C1: + sysctl->clk_en_peri.i2c1_clk_en = en; + break; + case SYSCTL_CLOCK_I2C2: + sysctl->clk_en_peri.i2c2_clk_en = en; + break; + case SYSCTL_CLOCK_UART1: + sysctl->clk_en_peri.uart1_clk_en = en; + break; + case SYSCTL_CLOCK_UART2: + sysctl->clk_en_peri.uart2_clk_en = en; + break; + case SYSCTL_CLOCK_UART3: + sysctl->clk_en_peri.uart3_clk_en = en; + break; + case SYSCTL_CLOCK_FPIOA: + sysctl->clk_en_peri.fpioa_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER0: + sysctl->clk_en_peri.timer0_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER1: + sysctl->clk_en_peri.timer1_clk_en = en; + break; + case SYSCTL_CLOCK_TIMER2: + sysctl->clk_en_peri.timer2_clk_en = en; + break; + case SYSCTL_CLOCK_SHA: + sysctl->clk_en_peri.sha_clk_en = en; + break; + + /* + * These peripheral devices are under APB1 + * WDT, AES, OTP, DVP, SYSCTL + */ + case SYSCTL_CLOCK_AES: + sysctl->clk_en_peri.aes_clk_en = en; + break; + case SYSCTL_CLOCK_WDT0: + sysctl->clk_en_peri.wdt0_clk_en = en; + break; + case SYSCTL_CLOCK_WDT1: + sysctl->clk_en_peri.wdt1_clk_en = en; + break; + case SYSCTL_CLOCK_OTP: + sysctl->clk_en_peri.otp_clk_en = en; + break; + case SYSCTL_CLOCK_RTC: + sysctl->clk_en_peri.rtc_clk_en = en; + break; + + /* + * These peripheral devices are under APB2 + * SPI0, SPI1 + */ + case SYSCTL_CLOCK_SPI0: + sysctl->clk_en_peri.spi0_clk_en = en; + break; + case SYSCTL_CLOCK_SPI1: + sysctl->clk_en_peri.spi1_clk_en = en; + break; + + default: + break; + } + + return 0; +} + +int sysctl_clock_enable(sysctl_clock_t clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + sysctl_clock_bus_en(clock, 1); + sysctl_clock_device_en(clock, 1); + return 0; +} + +int sysctl_clock_disable(sysctl_clock_t clock) +{ + if (clock >= SYSCTL_CLOCK_MAX) + return -1; + sysctl_clock_bus_en(clock, 0); + sysctl_clock_device_en(clock, 0); + return 0; +} + +int sysctl_clock_set_threshold(sysctl_threshold_t which, int threshold) +{ + int result = 0; + switch (which) + { + /* + * These threshold is 2 bit width + */ + case SYSCTL_THRESHOLD_ACLK: + sysctl->clk_sel0.aclk_divider_sel = (uint8_t)threshold & 0x03; + break; + + /* + * These threshold is 3 bit width + */ + case SYSCTL_THRESHOLD_APB0: + sysctl->clk_sel0.apb0_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB1: + sysctl->clk_sel0.apb1_clk_sel = (uint8_t)threshold & 0x07; + break; + case SYSCTL_THRESHOLD_APB2: + sysctl->clk_sel0.apb2_clk_sel = (uint8_t)threshold & 0x07; + break; + + /* + * These threshold is 4 bit width + */ + case SYSCTL_THRESHOLD_SRAM0: + sysctl->clk_th0.sram0_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_SRAM1: + sysctl->clk_th0.sram1_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_AI: + sysctl->clk_th0.ai_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_DVP: + sysctl->clk_th0.dvp_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + case SYSCTL_THRESHOLD_ROM: + sysctl->clk_th0.rom_gclk_threshold = (uint8_t)threshold & 0x0F; + break; + + /* + * These threshold is 8 bit width + */ + case SYSCTL_THRESHOLD_SPI0: + sysctl->clk_th1.spi0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + sysctl->clk_th1.spi1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + sysctl->clk_th1.spi2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + sysctl->clk_th1.spi3_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + sysctl->clk_th2.timer0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + sysctl->clk_th2.timer1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + sysctl->clk_th2.timer2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + sysctl->clk_th4.i2s0_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + sysctl->clk_th4.i2s1_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + sysctl->clk_th5.i2s2_mclk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + sysctl->clk_th5.i2c0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + sysctl->clk_th5.i2c1_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + sysctl->clk_th5.i2c2_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + sysctl->clk_th6.wdt0_clk_threshold = (uint8_t)threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + sysctl->clk_th6.wdt1_clk_threshold = (uint8_t)threshold; + break; + + /* + * These threshold is 16 bit width + */ + case SYSCTL_THRESHOLD_I2S0: + sysctl->clk_th3.i2s0_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + sysctl->clk_th3.i2s1_clk_threshold = (uint16_t)threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + sysctl->clk_th4.i2s2_clk_threshold = (uint16_t)threshold; + break; + + default: + result = -1; + break; + } + return result; +} + +int sysctl_clock_get_threshold(sysctl_threshold_t which) +{ + int threshold = 0; + + switch (which) + { + /* + * Select and get threshold value + */ + case SYSCTL_THRESHOLD_ACLK: + threshold = (int)sysctl->clk_sel0.aclk_divider_sel; + break; + case SYSCTL_THRESHOLD_APB0: + threshold = (int)sysctl->clk_sel0.apb0_clk_sel; + break; + case SYSCTL_THRESHOLD_APB1: + threshold = (int)sysctl->clk_sel0.apb1_clk_sel; + break; + case SYSCTL_THRESHOLD_APB2: + threshold = (int)sysctl->clk_sel0.apb2_clk_sel; + break; + case SYSCTL_THRESHOLD_SRAM0: + threshold = (int)sysctl->clk_th0.sram0_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SRAM1: + threshold = (int)sysctl->clk_th0.sram1_gclk_threshold; + break; + case SYSCTL_THRESHOLD_AI: + threshold = (int)sysctl->clk_th0.ai_gclk_threshold; + break; + case SYSCTL_THRESHOLD_DVP: + threshold = (int)sysctl->clk_th0.dvp_gclk_threshold; + break; + case SYSCTL_THRESHOLD_ROM: + threshold = (int)sysctl->clk_th0.rom_gclk_threshold; + break; + case SYSCTL_THRESHOLD_SPI0: + threshold = (int)sysctl->clk_th1.spi0_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI1: + threshold = (int)sysctl->clk_th1.spi1_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI2: + threshold = (int)sysctl->clk_th1.spi2_clk_threshold; + break; + case SYSCTL_THRESHOLD_SPI3: + threshold = (int)sysctl->clk_th1.spi3_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER0: + threshold = (int)sysctl->clk_th2.timer0_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER1: + threshold = (int)sysctl->clk_th2.timer1_clk_threshold; + break; + case SYSCTL_THRESHOLD_TIMER2: + threshold = (int)sysctl->clk_th2.timer2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0: + threshold = (int)sysctl->clk_th3.i2s0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1: + threshold = (int)sysctl->clk_th3.i2s1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2: + threshold = (int)sysctl->clk_th4.i2s2_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2S0_M: + threshold = (int)sysctl->clk_th4.i2s0_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S1_M: + threshold = (int)sysctl->clk_th4.i2s1_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2S2_M: + threshold = (int)sysctl->clk_th5.i2s2_mclk_threshold; + break; + case SYSCTL_THRESHOLD_I2C0: + threshold = (int)sysctl->clk_th5.i2c0_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C1: + threshold = (int)sysctl->clk_th5.i2c1_clk_threshold; + break; + case SYSCTL_THRESHOLD_I2C2: + threshold = (int)sysctl->clk_th5.i2c2_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT0: + threshold = (int)sysctl->clk_th6.wdt0_clk_threshold; + break; + case SYSCTL_THRESHOLD_WDT1: + threshold = (int)sysctl->clk_th6.wdt1_clk_threshold; + break; + + default: + break; + } + + return threshold; +} + +int sysctl_clock_set_clock_select(sysctl_clock_select_t which, int select) +{ + int result = 0; + switch (which) + { + /* + * These clock select is 1 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + sysctl->pll0.pll_bypass0 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + sysctl->pll1.pll_bypass1 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_PLL2_BYPASS: + sysctl->pll2.pll_bypass2 = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + sysctl->clk_sel0.aclk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + sysctl->clk_sel0.spi3_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + sysctl->clk_sel0.timer0_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + sysctl->clk_sel0.timer1_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + sysctl->clk_sel0.timer2_clk_sel = select & 0x01; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + sysctl->clk_sel1.spi3_sample_clk_sel = select & 0x01; + break; + + /* + * These clock select is 2 bit width + */ + case SYSCTL_CLOCK_SELECT_PLL2: + sysctl->pll2.pll_ckin_sel2 = select & 0x03; + break; + + default: + result = -1; + break; + } + + return result; +} + +int sysctl_clock_get_clock_select(sysctl_clock_select_t which) +{ + int clock_select = 0; + + switch (which) + { + /* + * Select and get clock select value + */ + case SYSCTL_CLOCK_SELECT_PLL0_BYPASS: + clock_select = (int)sysctl->pll0.pll_bypass0; + break; + case SYSCTL_CLOCK_SELECT_PLL1_BYPASS: + clock_select = (int)sysctl->pll1.pll_bypass1; + break; + case SYSCTL_CLOCK_SELECT_PLL2_BYPASS: + clock_select = (int)sysctl->pll2.pll_bypass2; + break; + case SYSCTL_CLOCK_SELECT_PLL2: + clock_select = (int)sysctl->pll2.pll_ckin_sel2; + break; + case SYSCTL_CLOCK_SELECT_ACLK: + clock_select = (int)sysctl->clk_sel0.aclk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3: + clock_select = (int)sysctl->clk_sel0.spi3_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER0: + clock_select = (int)sysctl->clk_sel0.timer0_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER1: + clock_select = (int)sysctl->clk_sel0.timer1_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_TIMER2: + clock_select = (int)sysctl->clk_sel0.timer2_clk_sel; + break; + case SYSCTL_CLOCK_SELECT_SPI3_SAMPLE: + clock_select = (int)sysctl->clk_sel1.spi3_sample_clk_sel; + break; + + default: + break; + } + + return clock_select; +} + +uint32_t sysctl_clock_source_get_freq(sysctl_clock_source_t input) +{ + uint32_t result; + + switch (input) + { + case SYSCTL_SOURCE_IN0: + result = SYSCTRL_CLOCK_FREQ_IN0; + break; + case SYSCTL_SOURCE_PLL0: + result = sysctl_pll_get_freq(SYSCTL_PLL0); + break; + case SYSCTL_SOURCE_PLL1: + result = sysctl_pll_get_freq(SYSCTL_PLL1); + break; + case SYSCTL_SOURCE_PLL2: + result = sysctl_pll_get_freq(SYSCTL_PLL2); + break; + case SYSCTL_SOURCE_ACLK: + result = sysctl_clock_get_freq(SYSCTL_CLOCK_ACLK); + break; + default: + result = 0; + break; + } + return result; +} + +static int sysctl_pll_is_lock(sysctl_pll_t pll) +{ + /* + * All bit enable means PLL lock + * + * struct pll_lock_t + * { + * uint8_t overflow : 1; + * uint8_t rfslip : 1; + * uint8_t fbslip : 1; + * }; + * + */ + + uint8_t lock = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + lock = sysctl->pll_lock.pll_lock0; + break; + + case SYSCTL_PLL1: + lock = sysctl->pll_lock.pll_lock1; + break; + + case SYSCTL_PLL2: + lock = sysctl->pll_lock.pll_lock2; + break; + + default: + break; + } + + if (lock == 3) + return 1; + + return 0; +} + +static int sysctl_pll_clear_slip(sysctl_pll_t pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + sysctl->pll_lock.pll_slip_clear0 = 1; + break; + + case SYSCTL_PLL1: + sysctl->pll_lock.pll_slip_clear1 = 1; + break; + + case SYSCTL_PLL2: + sysctl->pll_lock.pll_slip_clear2 = 1; + break; + + default: + break; + } + + return sysctl_pll_is_lock(pll) ? 0 : -1; +} + +int sysctl_pll_enable(sysctl_pll_t pll) +{ + /* + * ---+ + * PWRDN | + * +------------------------------------------------------------- + * ^ + * | + * | + * t1 + * +------------------+ + * RESET | | + * ----------+ +----------------------------------- + * ^ ^ ^ + * |<----- t_rst ---->|<---------- t_lock ---------->| + * | | | + * t2 t3 t4 + */ + + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Do not bypass PLL */ + sysctl->pll0.pll_bypass0 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll0.pll_reset0 = 0; + sysctl->pll0.pll_reset0 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll0.pll_reset0 = 0; + break; + + case SYSCTL_PLL1: + /* Do not bypass PLL */ + sysctl->pll1.pll_bypass1 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll1.pll_reset1 = 0; + sysctl->pll1.pll_reset1 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll1.pll_reset1 = 0; + break; + + case SYSCTL_PLL2: + /* Do not bypass PLL */ + sysctl->pll2.pll_bypass2 = 0; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 1; + /* + * Reset trigger of the PLL, connected RESET + * 0 is free + * 1 is reset + */ + sysctl->pll2.pll_reset2 = 0; + sysctl->pll2.pll_reset2 = 1; + asm volatile ("nop"); + asm volatile ("nop"); + sysctl->pll2.pll_reset2 = 0; + break; + + default: + break; + } + + return 0; +} + +int sysctl_pll_disable(sysctl_pll_t pll) +{ + if (pll >= SYSCTL_PLL_MAX) + return -1; + + switch (pll) + { + case SYSCTL_PLL0: + /* Bypass PLL */ + sysctl->pll0.pll_bypass0 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll0.pll_pwrd0 = 0; + break; + + case SYSCTL_PLL1: + /* Bypass PLL */ + sysctl->pll1.pll_bypass1 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll1.pll_pwrd1 = 0; + break; + + case SYSCTL_PLL2: + /* Bypass PLL */ + sysctl->pll2.pll_bypass2 = 1; + /* + * Power on the PLL, negtive from PWRDN + * 0 is power off + * 1 is power on + */ + sysctl->pll2.pll_pwrd2 = 0; + break; + + default: + break; + } + + return 0; +} + +uint32_t sysctl_pll_get_freq(sysctl_pll_t pll) +{ + uint32_t freq_in = 0, freq_out = 0; + uint32_t nr = 0, nf = 0, od = 0; + uint8_t select = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll0.clkr0 + 1; + nf = sysctl->pll0.clkf0 + 1; + od = sysctl->pll0.clkod0 + 1; + break; + + case SYSCTL_PLL1: + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + nr = sysctl->pll1.clkr1 + 1; + nf = sysctl->pll1.clkf1 + 1; + od = sysctl->pll1.clkod1 + 1; + break; + + case SYSCTL_PLL2: + /* + * Get input freq accroding select register + */ + select = sysctl->pll2.pll_ckin_sel2; + if (select < sizeof(get_source_pll2)) + freq_in = sysctl_clock_source_get_freq(get_source_pll2[select]); + else + return 0; + + nr = sysctl->pll2.clkr2 + 1; + nf = sysctl->pll2.clkf2 + 1; + od = sysctl->pll2.clkod2 + 1; + break; + + default: + break; + } + + /* + * Get final PLL output freq + * FOUT = FIN / NR * NF / OD + */ + freq_out = (double)freq_in / (double)nr * (double)nf / (double)od; + return freq_out; +} + +static uint32_t sysctl_pll_source_set_freq(sysctl_pll_t pll, sysctl_clock_source_t source, uint32_t freq) +{ + uint32_t freq_in = 0; + + if (pll >= SYSCTL_PLL_MAX) + return 0; + + if (source >= SYSCTL_SOURCE_MAX) + return 0; + + switch (pll) + { + case SYSCTL_PLL0: + case SYSCTL_PLL1: + /* + * Check input clock source + */ + if (source != SYSCTL_SOURCE_IN0) + return 0; + freq_in = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + /* + * Check input clock freq + */ + if (freq_in == 0) + return 0; + break; + + case SYSCTL_PLL2: + /* + * Check input clock source + */ + if (source < sizeof(get_select_pll2)) + freq_in = sysctl_clock_source_get_freq(source); + /* + * Check input clock freq + */ + if (freq_in == 0) + return 0; + break; + + default: + return 0; + } + + /* + * Begin calculate PLL registers' value + */ + + /* constants */ + const double vco_min = 3.5e+08; + const double vco_max = 1.75e+09; + const double ref_min = 1.36719e+07; + const double ref_max = 1.75e+09; + const int nr_min = 1; + const int nr_max = 16; + const int nf_min = 1; + const int nf_max = 64; + const int no_min = 1; + const int no_max = 16; + const int nb_min = 1; + const int nb_max = 64; + const int max_vco = 1; + const int ref_rng = 1; + + /* variables */ + int nr = 0; + int nrx = 0; + int nf = 0; + int nfi = 0; + int no = 0; + int noe = 0; + int not = 0; + int nor = 0; + int nore = 0; + int nb = 0; + int first = 0; + int firstx = 0; + int found = 0; + + long long nfx = 0; + double fin = 0, fout = 0, fvco = 0; + double val = 0, nval = 0, err = 0, merr = 0, terr = 0; + int x_nrx = 0, x_no = 0, x_nb = 0; + long long x_nfx = 0; + double x_fvco = 0, x_err = 0; + + fin = freq_in; + fout = freq; + val = fout / fin; + terr = 0.5 / ((double)(nf_max / 2)); + first = firstx = 1; + if (terr != -2) + { + first = 0; + if (terr == 0) + terr = 1e-16; + merr = fabs(terr); + } + found = 0; + for (nfi = val; nfi < nf_max; ++nfi) + { + nr = rint(((double)nfi) / val); + if (nr == 0) + continue; + if ((ref_rng) && (nr < nr_min)) + continue; + if (fin / ((double)nr) > ref_max) + continue; + nrx = nr; + nf = nfx = nfi; + nval = ((double)nfx) / ((double)nr); + if (nf == 0) + nf = 1; + err = 1 - nval / val; + + if ((first) || (fabs(err) < merr * (1 + 1e-6)) || (fabs(err) < 1e-16)) + { + not = floor(vco_max / fout); + for (no = (not > no_max) ? no_max : not; no > no_min; --no) + { + if ((ref_rng) && ((nr / no) < nr_min)) + continue; + if ((nr % no) == 0) + break; + } + if ((nr % no) != 0) + continue; + nor = ((not > no_max) ? no_max : not) / no; + nore = nf_max / nf; + if (nor > nore) + nor = nore; + noe = ceil(vco_min / fout); + if (!max_vco) + { + nore = (noe - 1) / no + 1; + nor = nore; + not = 0; /* force next if to fail */ + } + if ((((no * nor) < (not >> 1)) || ((no * nor) < noe)) && ((no * nor) < (nf_max / nf))) + { + no = nf_max / nf; + if (no > no_max) + no = no_max; + if (no > not) + no = not; + nfx *= no; + nf *= no; + if ((no > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + else + { + nrx /= no; + nfx *= nor; + nf *= nor; + no *= nor; + if (no > no_max) + continue; + if ((nor > 1) && (!firstx)) + continue; + /* wait for larger nf in later iterations */ + } + + nb = nfx; + if (nb < nb_min) + nb = nb_min; + if (nb > nb_max) + continue; + + fvco = fin / ((double)nrx) * ((double)nfx); + if (fvco < vco_min) + continue; + if (fvco > vco_max) + continue; + if (nf < nf_min) + continue; + if ((ref_rng) && (fin / ((double)nrx) < ref_min)) + continue; + if ((ref_rng) && (nrx > nr_max)) + continue; + if (!(((firstx) && (terr < 0)) || (fabs(err) < merr * (1 - 1e-6)) || ((max_vco) && (no > x_no)))) + continue; + if ((!firstx) && (terr >= 0) && (nrx > x_nrx)) + continue; + + found = 1; + x_no = no; + x_nrx = nrx; + x_nfx = nfx; + x_nb = nb; + x_fvco = fvco; + x_err = err; + first = firstx = 0; + merr = fabs(err); + if (terr != -1) + continue; + } + } + if (!found) + { + return 0; + } + + nrx = x_nrx; + nfx = x_nfx; + no = x_no; + nb = x_nb; + fvco = x_fvco; + err = x_err; + if ((terr != -2) && (fabs(err) >= terr * (1 - 1e-6))) + { + return 0; + } + + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + sysctl_pll0_t pll0; + sysctl_pll1_t pll1; + sysctl_pll2_t pll2; + + switch (pll) + { + case SYSCTL_PLL0: + /* Read register from bus */ + pll0 = sysctl->pll0; + /* Set register temporary value */ + pll0.clkr0 = nrx - 1; + pll0.clkf0 = nfx - 1; + pll0.clkod0 = no - 1; + pll0.bwadj0 = nb - 1; + /* Write register back to bus */ + sysctl->pll0 = pll0; + break; + + case SYSCTL_PLL1: + /* Read register from bus */ + pll1 = sysctl->pll1; + /* Set register temporary value */ + pll1.clkr1 = nrx - 1; + pll1.clkf1 = nfx - 1; + pll1.clkod1 = no - 1; + pll1.bwadj1 = nb - 1; + /* Write register back to bus */ + sysctl->pll1 = pll1; + break; + + case SYSCTL_PLL2: + /* Read register from bus */ + pll2 = sysctl->pll2; + /* Set register temporary value */ + if (source < sizeof(get_select_pll2)) + pll2.pll_ckin_sel2 = get_select_pll2[source]; + + pll2.clkr2 = nrx - 1; + pll2.clkf2 = nfx - 1; + pll2.clkod2 = no - 1; + pll2.bwadj2 = nb - 1; + /* Write register back to bus */ + sysctl->pll2 = pll2; + break; + + default: + return 0; + } + + return sysctl_pll_get_freq(pll); +} + +uint32_t sysctl_clock_get_freq(sysctl_clock_t clock) +{ + uint32_t source = 0; + uint32_t result = 0; + + switch (clock) + { + /* + * The clock IN0 + */ + case SYSCTL_CLOCK_IN0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source; + break; + + /* + * These clock directly under PLL clock domain + * They are using gated divider. + */ + case SYSCTL_CLOCK_PLL0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source; + break; + case SYSCTL_CLOCK_PLL1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source; + break; + case SYSCTL_CLOCK_PLL2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source; + break; + + /* + * These clock directly under ACLK clock domain + */ + case SYSCTL_CLOCK_CPU: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_DMA: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_FFT: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_ACLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + case SYSCTL_CLOCK_HCLK: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_ACLK)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0) / + (2ULL << sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ACLK)); + break; + default: + break; + } + result = source; + break; + + /* + * These clock under ACLK clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_SRAM0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM0) + 1); + break; + case SYSCTL_CLOCK_SRAM1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SRAM1) + 1); + break; + case SYSCTL_CLOCK_ROM: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_ROM) + 1); + break; + case SYSCTL_CLOCK_DVP: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_DVP) + 1); + break; + + /* + * These clock under ACLK clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_APB0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB0) + 1); + break; + case SYSCTL_CLOCK_APB1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB1) + 1); + break; + case SYSCTL_CLOCK_APB2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_ACLK); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_APB2) + 1); + break; + + /* + * These clock under AI clock domain. + * They are using gated divider. + */ + case SYSCTL_CLOCK_AI: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL1); + result = source / (sysctl_clock_get_threshold(SYSCTL_THRESHOLD_AI) + 1); + break; + + /* + * These clock under I2S clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_I2S0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2S2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL2); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2S2) + 1) * 2); + break; + + /* + * These clock under WDT clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_WDT0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT0) + 1) * 2); + break; + case SYSCTL_CLOCK_WDT1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_WDT1) + 1) * 2); + break; + + /* + * These clock under PLL0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI0) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI1) + 1) * 2); + break; + case SYSCTL_CLOCK_SPI2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI2) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C0) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C1) + 1) * 2); + break; + case SYSCTL_CLOCK_I2C2: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_I2C2) + 1) * 2); + break; + + /* + * These clock under PLL0_SEL clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_SPI3: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_SPI3)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_SPI3) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER0: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER0)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER0) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER1: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER1)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER1) + 1) * 2); + break; + case SYSCTL_CLOCK_TIMER2: + switch (sysctl_clock_get_clock_select(SYSCTL_CLOCK_SELECT_TIMER2)) + { + case 0: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + break; + case 1: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_PLL0); + break; + default: + break; + } + + result = source / ((sysctl_clock_get_threshold(SYSCTL_THRESHOLD_TIMER2) + 1) * 2); + break; + + /* + * These clock under MISC clock domain. + * They are using even divider. + */ + + /* + * These clock under APB0 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_GPIO: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART1: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART2: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_UART3: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_FPIOA: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + case SYSCTL_CLOCK_SHA: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + result = source; + break; + + /* + * These clock under APB1 clock domain. + * They are using even divider. + */ + case SYSCTL_CLOCK_AES: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_OTP: + source = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1); + result = source; + break; + case SYSCTL_CLOCK_RTC: + source = sysctl_clock_source_get_freq(SYSCTL_SOURCE_IN0); + result = source; + break; + + /* + * These clock under APB2 clock domain. + * They are using even divider. + */ + /* + * Do nothing. + */ + default: + break; + } + return result; +} + +int sysctl_dma_select(sysctl_dma_channel_t channel, sysctl_dma_select_t select) +{ + sysctl_dma_sel0_t dma_sel0; + sysctl_dma_sel1_t dma_sel1; + + /* Read register from bus */ + dma_sel0 = sysctl->dma_sel0; + dma_sel1 = sysctl->dma_sel1; + switch (channel) + { + case SYSCTL_DMA_CHANNEL_0: + dma_sel0.dma_sel0 = select; + break; + + case SYSCTL_DMA_CHANNEL_1: + dma_sel0.dma_sel1 = select; + break; + + case SYSCTL_DMA_CHANNEL_2: + dma_sel0.dma_sel2 = select; + break; + + case SYSCTL_DMA_CHANNEL_3: + dma_sel0.dma_sel3 = select; + break; + + case SYSCTL_DMA_CHANNEL_4: + dma_sel0.dma_sel4 = select; + break; + + case SYSCTL_DMA_CHANNEL_5: + dma_sel1.dma_sel5 = select; + break; + + default: + return -1; + } + + /* Write register back to bus */ + sysctl->dma_sel0 = dma_sel0; + sysctl->dma_sel1 = dma_sel1; + + return 0; +} + +uint32_t sysctl_pll_fast_enable_pll(void) +{ + /* + * Begin write PLL registers' value, + * Using atomic write method. + */ + sysctl_pll0_t pll0; + sysctl_pll1_t pll1; + sysctl_pll2_t pll2; + + /* Read register from bus */ + pll0 = sysctl->pll0; + pll1 = sysctl->pll1; + pll2 = sysctl->pll2; + + /* PLL VCO MAX freq: 1.8GHz */ + + /* PLL0: 26M reference clk get 793M output clock */ + pll0.clkr0 = 0; + pll0.clkf0 = 60; + pll0.clkod0 = 1; + pll0.bwadj0 = 60; + + /* PLL1: 26M reference clk get 390M output clock */ + pll1.clkr1 = 0; + pll1.clkf1 = 59; + pll1.clkod1 = 3; + pll1.bwadj1 = 59; + + /* PLL2: 26M reference clk get 390M output clock */ + pll2.clkr2 = 0; + pll2.clkf2 = 59; + pll2.clkod2 = 3; + pll2.bwadj2 = 59; + + /* Write register to bus */ + sysctl->pll0 = pll0; + sysctl->pll1 = pll1; + sysctl->pll2 = pll2; + + sysctl_pll_enable(SYSCTL_PLL0); + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_enable(SYSCTL_PLL2); + + while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL0); + while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL1); + while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0) + sysctl_pll_clear_slip(SYSCTL_PLL2); + + sysctl_clock_enable(SYSCTL_CLOCK_PLL0); + sysctl_clock_enable(SYSCTL_CLOCK_PLL1); + sysctl_clock_enable(SYSCTL_CLOCK_PLL2); + + /* Set ACLK to PLL0 */ + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + return 0; +} + +uint32_t sysctl_set_spi0_dvp_data(uint8_t en) +{ + sysctl->misc.spi_dvp_data_enable = en; + return 0; +} + +void sysctl_set_power_mode(sysctl_power_bank_t power_bank, sysctl_io_power_mode_t io_power_mode) +{ + if(io_power_mode) + *((uint32_t *)(&sysctl->power_sel)) |= (1 << power_bank); + else + *((uint32_t *)(&sysctl->power_sel)) &= ~(1 << power_bank); +} + +uint32_t sysctl_pll_set_freq(sysctl_pll_t pll, uint32_t pll_freq) +{ + if(pll_freq == 0) + return 0; + + volatile sysctl_general_pll_t *v_pll_t; + switch(pll) + { + case SYSCTL_PLL0: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll0); + break; + case SYSCTL_PLL1: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll1); + break; + case SYSCTL_PLL2: + v_pll_t = (sysctl_general_pll_t *)(&sysctl->pll2); + break; + default: + return 0; + break; + } + + /* 1. Change CPU CLK to XTAL */ + if(pll == SYSCTL_PLL0) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0); + + /* 2. Disable PLL output */ + v_pll_t->pll_out_en = 0; + + /* 3. Turn off PLL */ + v_pll_t->pll_pwrd = 0; + + /* 4. Set PLL new value */ + uint32_t result; + if(pll == SYSCTL_PLL2) + result = sysctl_pll_source_set_freq(pll, v_pll_t->pll_ckin_sel, pll_freq); + else + result = sysctl_pll_source_set_freq(pll, SYSCTL_SOURCE_IN0, pll_freq); + + /* 5. Power on PLL */ + v_pll_t->pll_pwrd = 1; + + /* 6. Reset PLL then Release Reset*/ + v_pll_t->pll_reset = 0; + v_pll_t->pll_reset = 1; + /* wait 100ns */ + asm volatile ("nop"); + asm volatile ("nop"); + v_pll_t->pll_reset = 0; + + /* 7. Get lock status, wait PLL stable */ + while (sysctl_pll_is_lock(pll) == 0) + sysctl_pll_clear_slip(pll); + + /* 8. Enable PLL output */ + v_pll_t->pll_out_en = 1; + + /* 9. Change CPU CLK to PLL */ + if(pll == SYSCTL_PLL0) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + + return result; +} + +uint32_t sysctl_cpu_set_freq(uint32_t freq) +{ + if(freq == 0) + return 0; + + return sysctl_pll_set_freq(SYSCTL_PLL0, (sysctl->clk_sel0.aclk_divider_sel + 1) * 2 * freq); +} + +void sysctl_enable_irq(void) +{ + set_csr(mie, MIP_MEIP); + set_csr(mstatus, MSTATUS_MIE); +} + +void sysctl_disable_irq(void) +{ + clear_csr(mie, MIP_MEIP); + clear_csr(mstatus, MSTATUS_MIE); +} + diff --git a/lib/drivers/timer.c b/lib/drivers/timer.c new file mode 100755 index 0000000..3566446 --- /dev/null +++ b/lib/drivers/timer.c @@ -0,0 +1,192 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "timer.h" +#include "sysctl.h" +#include "stddef.h" +#include "utils.h" +#include "plic.h" +#include "io.h" + +volatile kendryte_timer_t *const timer[3] = +{ + (volatile kendryte_timer_t *)TIMER0_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER1_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER2_BASE_ADDR +}; + +void timer_init(timer_device_number_t timer_number) +{ + sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number); +} + +void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div) +{ + sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 : + timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 : + SYSCTL_THRESHOLD_TIMER2, div); +} + +void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE; +} + +void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE); +} + +void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE; +} + +void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE); +} + +void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK); +} + +void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK; +} + +void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK); + timer[timer_number]->channel[channel].control |= mode; +} + +void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->channel[channel].load_count = count; +} + +void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->load_count2[channel] = count; +} + +uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].current_value; +} + +uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].load_count; +} + +uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->load_count2[channel]; +} + +uint32_t timer_get_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->intr_stat; +} + +uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->raw_intr_stat; +} + +uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].intr_stat; +} + +void timer_clear_interrupt(timer_device_number_t timer_number) +{ + timer[timer_number]->eoi = timer[timer_number]->eoi; +} + +void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi; +} + +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable) +{ + if (enable) + timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds) +{ + uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + timer_number); + + double min_step = 1e9 / clk_freq; + size_t value = (size_t)(nanoseconds / min_step); + configASSERT(value > 0 && value < UINT32_MAX); + timer[timer_number]->channel[channel].load_count = (uint32_t)value; + return (size_t)(min_step * value); +} + +typedef void(*timer_ontick)(); +timer_ontick time_irq[3][4] = { NULL }; + +static int timer_isr(void *parm) +{ + uint32_t timer_number; + for (timer_number = 0; timer_number < 3; timer_number++) + { + if (parm == timer[timer_number]) + break; + } + + uint32_t channel = timer[timer_number]->intr_stat; + size_t i = 0; + for (i = 0; i < 4; i++) + { + if (channel & 1) + { + if (time_irq[timer_number][i]) + (time_irq[timer_number][i])(); + break; + } + + channel >>= 1; + } + + readl(&timer[timer_number]->eoi); + return 0; +} + +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority) +{ + time_irq[timer_number][channel] = func; + if (channel < 2) + { + plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]); + plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2); + } + else + { + plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, NULL); + plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2); + } +} + diff --git a/lib/drivers/uart.c b/lib/drivers/uart.c new file mode 100755 index 0000000..bf0fb96 --- /dev/null +++ b/lib/drivers/uart.c @@ -0,0 +1,187 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include +#include "plic.h" +#include "sysctl.h" +#include "uart.h" +#include "utils.h" +#include "atomic.h" + +#define __UART_BRATE_CONST 16 + +volatile uart_t* const uart[3] = +{ + (volatile uart_t*)UART1_BASE_ADDR, + (volatile uart_t*)UART2_BASE_ADDR, + (volatile uart_t*)UART3_BASE_ADDR +}; + +#define RING_BUFF_LEN 64U + +typedef struct _ring_buff_t +{ + size_t head; + size_t tail; + size_t length; + char ring_buff[RING_BUFF_LEN]; +} ring_buff_t; + +ring_buff_t *ring_recv[3] = {NULL, NULL, NULL}; + +static int write_ringbuff(uint8_t channel, uint8_t rdata) +{ + ring_buff_t *rb = ring_recv[channel]; + + if (rb->length >= RING_BUFF_LEN) + { + return -1; + } + rb->ring_buff[rb->tail] = rdata; + rb->tail = (rb->tail + 1) % RING_BUFF_LEN; + atomic_add(&rb->length, 1); + return 0; +} + +static int read_ringbuff(uart_device_number_t channel, char *rdata, size_t len) +{ + ring_buff_t *rb = ring_recv[channel]; + size_t cnt = 0; + while ((len--) && rb->length) + { + *(rdata++) = rb->ring_buff[rb->head]; + rb->head = (rb->head + 1) % RING_BUFF_LEN; + atomic_add(&rb->length, -1); + cnt++; + } + return cnt; +} + +static int on_irq_apbuart_recv(void *param) +{ + int i = 0; + for (i = 0; i < 3; i++) + { + if (param == uart[i]) + break; + } + + while (uart[i]->LSR & 1) + { + write_ringbuff(i, ((uint8_t)(uart[i]->RBR & 0xff))); + } + return 0; +} + +static int uartapb_putc(uart_device_number_t channel, char c) +{ + while (!(uart[channel]->LSR & (1u << 6))) + continue; + uart[channel]->THR = c; + return 0; +} + +int uartapb_getc(uart_device_number_t channel) +{ + while (!(uart[channel]->LSR & 1)) + continue; + + return (char)(uart[channel]->RBR & 0xff); +} + + +int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len) +{ + return read_ringbuff(channel, buffer, buf_len); +} + +int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len) +{ + int write = 0; + while (write < buf_len) + { + uartapb_putc(channel, *buffer++); + write++; + } + + return write; +} + +void uart_config(uart_device_number_t channel, uint32_t baud_rate, uart_bitwidth_t data_width, uart_stopbit_t stopbit, uart_parity_t parity) +{ + + configASSERT(data_width >= 5 && data_width <= 8); + if (data_width == 5) + { + configASSERT(stopbit != UART_STOP_2); + } + else + { + configASSERT(stopbit != UART_STOP_1_5); + } + + uint32_t stopbit_val = stopbit == UART_STOP_1 ? 0 : 1; + uint32_t parity_val; + switch (parity) + { + case UART_PARITY_NONE: + parity_val = 0; + break; + case UART_PARITY_ODD: + parity_val = 1; + break; + case UART_PARITY_EVEN: + parity_val = 3; + break; + default: + configASSERT(!"Invalid parity"); + break; + } + + uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_APB0); + uint32_t u16Divider = (freq + __UART_BRATE_CONST * baud_rate / 2) / + (__UART_BRATE_CONST * baud_rate); + + /* Set UART registers */ + uart[channel]->TCR &= ~(1u); + uart[channel]->TCR &= ~(1u << 3); + uart[channel]->TCR &= ~(1u << 4); + uart[channel]->TCR |= (1u << 2); + uart[channel]->TCR &= ~(1u << 1); + uart[channel]->DE_EN &= ~(1u); + + uart[channel]->LCR |= 1u << 7; + uart[channel]->DLL = u16Divider & 0xFF; + uart[channel]->DLH = u16Divider >> 8; + uart[channel]->LCR = 0; + uart[channel]->LCR = (data_width - 5) | (stopbit_val << 2) | (parity_val << 3); + uart[channel]->LCR &= ~(1u << 7); + uart[channel]->MCR &= ~3; + uart[channel]->IER = 1; /*RX INT enable*/ +} + +void uart_init(uart_device_number_t channel) +{ + sysctl_clock_enable(SYSCTL_CLOCK_UART1 + channel); + + ring_buff_t *rb = malloc(sizeof(ring_buff_t)); + rb->head = 0; + rb->tail = 0; + rb->length = 0; + ring_recv[channel] = rb; + plic_irq_register(IRQN_UART1_INTERRUPT + channel, on_irq_apbuart_recv, (void *)uart[channel]); + plic_set_priority(IRQN_UART1_INTERRUPT + channel, 1); + plic_irq_enable(IRQN_UART1_INTERRUPT); +} diff --git a/lib/drivers/uarths.c b/lib/drivers/uarths.c new file mode 100755 index 0000000..c935119 --- /dev/null +++ b/lib/drivers/uarths.c @@ -0,0 +1,72 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#include +#include +#include "uarths.h" +#include "sysctl.h" +#include "encoding.h" + +volatile uarths_t *const uarths = (volatile uarths_t *)UARTHS_BASE_ADDR; + +static inline int uarths_putc(char c) +{ + while (uarths->txdata.full) + continue; + uarths->txdata.data = (uint8_t)c; + + return 0; +} + +int uarths_getc(void) +{ + /* while not empty */ + uarths_rxdata_t recv = uarths->rxdata; + + if (recv.empty) + return EOF; + else + return recv.data; +} + +int uarths_putchar(char c) +{ + return uarths_putc(c); +} + +int uarths_puts(const char *s) +{ + while (*s) + if (uarths_putc(*s++) != 0) + return -1; + return 0; +} + +void uarths_init(void) +{ + uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + uint16_t div = freq / 115200 - 1; + + /* Set UART registers */ + uarths->div.div = div; + uarths->txctrl.txen = 1; + uarths->rxctrl.rxen = 1; + uarths->txctrl.txcnt = 0; + uarths->rxctrl.rxcnt = 0; + uarths->ip.txwm = 1; + uarths->ip.rxwm = 1; + uarths->ie.txwm = 0; + uarths->ie.rxwm = 1; +} diff --git a/lib/drivers/utils.c b/lib/drivers/utils.c new file mode 100755 index 0000000..d21a3b3 --- /dev/null +++ b/lib/drivers/utils.c @@ -0,0 +1,44 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "encoding.h" +#include "utils.h" + +void set_bit(volatile uint32_t *bits, uint32_t mask, uint32_t value) +{ + uint32_t org = (*bits) & ~mask; + *bits = org | (value & mask); +} + +void set_bit_offset(volatile uint32_t *bits, uint32_t mask, size_t offset, uint32_t value) +{ + set_bit(bits, mask << offset, value << offset); +} + +void set_gpio_bit(volatile uint32_t *bits, size_t offset, uint32_t value) +{ + set_bit_offset(bits, 1, offset, value); +} + +uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset) +{ + return ((*bits) & (mask << offset)) >> offset; +} + +uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset) +{ + return get_bit(bits, 1, offset); +} + diff --git a/lib/drivers/wdt.c b/lib/drivers/wdt.c new file mode 100755 index 0000000..b99edd3 --- /dev/null +++ b/lib/drivers/wdt.c @@ -0,0 +1,99 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include "wdt.h" +#include "platform.h" +#include "stddef.h" +#include "utils.h" +#include "sysctl.h" +#include "plic.h" +#include "math.h" + +volatile wdt_t *const wdt[2] = +{ + (volatile wdt_t *)WDT0_BASE_ADDR, + (volatile wdt_t *)WDT1_BASE_ADDR +}; + +static void wdt_enable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr |= WDT_CR_ENABLE; +} + +static void wdt_disable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr &= (~WDT_CR_ENABLE); +} + +static void wdt_set_timeout(wdt_device_number_t id, uint8_t timeout) +{ + wdt[id]->torr = WDT_TORR_TOP(timeout); +} + +static void wdt_response_mode(wdt_device_number_t id, uint8_t mode) +{ + wdt[id]->cr &= (~WDT_CR_RMOD_MASK); + wdt[id]->cr |= mode; +} + +static uint64_t wdt_get_pclk(wdt_device_number_t id) +{ + return id ? sysctl_clock_get_freq(SYSCTL_CLOCK_WDT1) : sysctl_clock_get_freq(SYSCTL_CLOCK_WDT0); +} + +static uint8_t wdt_get_top(wdt_device_number_t id, uint64_t timeout_ms) +{ + uint64_t wdt_clk = wdt_get_pclk(id); + uint64_t ret = (timeout_ms * wdt_clk / 1000) >> 16; + if (ret) + ret = (uint32_t)log2(ret); + if (ret > 0xf) + ret = 0xf; + return (uint8_t)ret; +} + +void wdt_feed(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; +} + +void wdt_clear_interrupt(wdt_device_number_t id) +{ + wdt[id]->eoi = wdt[id]->eoi; +} + +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq) +{ + wdt_disable(id); + wdt_clear_interrupt(id); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, NULL); + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, time_out_ms); + wdt_set_timeout(id, m_top); + wdt_enable(id); +} + +void wdt_stop(wdt_device_number_t id) +{ + wdt_disable(id); +} + diff --git a/lib/math/fastexp.c b/lib/math/fastexp.c new file mode 100755 index 0000000..9745391 --- /dev/null +++ b/lib/math/fastexp.c @@ -0,0 +1,71 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#include "fastexp.h" +#include + +static inline float _fast_exp2f(float in) +{ + static const float p1 = 0.0f; + static const float p2 = 0.0f; + static const float p3 = 0.0f; + static const float p4 = 0.0f; + static const float p5 = 0.0f; + + float x1 = in; + float x2 = x1 * in; + float x3 = x2 * in; + float x4 = x3 * in; + + return x4 * p1 + x3 * p2 + x2 * p3 + x1 * p4 + p5; +} + + +float fast_exp2f(float x) +{ + union _float { + float f; + struct { + uint32_t frac : 23; + uint32_t expo : 8; + uint32_t sign : 1; + } data; + }; + + if (x < 0) + return 1.0f / fast_exp2f(-x); + + union _float f = {.f = 1.0f}; + + f.data.expo = (int)x + 127; + + return _fast_exp2f(x - (int)x) * f.f; +} + + +float fast_expf(float x) +{ + extern float __ieee754_expf(float x); + + return __ieee754_expf(x); +} + + +float fast_powf(float base, float expo) +{ + extern float __ieee754_powf(float base, float expo); + + return __ieee754_powf(base, expo); +} diff --git a/lib/math/fastexp.h b/lib/math/fastexp.h new file mode 100755 index 0000000..6db48e6 --- /dev/null +++ b/lib/math/fastexp.h @@ -0,0 +1,116 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ + +#ifndef KENDRYTE_FAST_EXP +#define KENDRYTE_FAST_EXP + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * calc exp2f(x) + **/ +float fast_exp2f(float x); + +/** + * calc expf(x) + **/ +float fast_expf(float x); + +/** + * calc powf(base,expo) + **/ +float fast_powf(float base, float expo); + +/** + * calc exp2(x) + **/ +static inline double fast_exp2(double x) +{ + return fast_exp2f((float)x); +} + +/** + * calc exp(x) + **/ +static inline double fast_exp(double x) +{ + return fast_expf((float)x); +} + +/** + * calc pow(base,expo) + **/ +static inline double fast_pow(double base, double expo) +{ + return fast_powf((float)base, (float)expo); +} + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +#include +namespace std{ + template < typename... Args > + auto fast_pow(Args && ... args)->decltype(::fast_pow(std::forward < Args > (args)...)) { + return ::fast_pow(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_powf(Args && ... args)->decltype(::fast_powf(std::forward < Args > (args)...)) { + return ::fast_powf(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp(Args && ... args)->decltype(::fast_exp(std::forward < Args > (args)...)) { + return ::fast_exp(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_expf(Args && ... args)->decltype(::fast_expf(std::forward < Args > (args)...)) { + return ::fast_expf(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp2(Args && ... args)->decltype(fast_exp2(std::forward < Args > (args)...)) { + return ::fast_exp2(std::forward < Args > (args)...); + } + + template < typename... Args > + auto fast_exp2f(Args && ... args)->decltype(::fast_exp2f(std::forward < Args > (args)...)) { + return ::fast_exp2f(std::forward < Args > (args)...); + } +} +#endif + + + +#ifdef CONFIG_FAST_EXP_OVERRIDE +#define pow fast_pow +#define powf fast_powf +#define exp fast_exp +#define expf fast_expf +#define exp2 fast_exp2 +#define exp2f fast_exp2f + + +#endif + +#endif diff --git a/lib/utils/include/syslog.h b/lib/utils/include/syslog.h new file mode 100755 index 0000000..cc10b4f --- /dev/null +++ b/lib/utils/include/syslog.h @@ -0,0 +1,141 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include +#include +#include "printf.h" +#include "encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Logging library + * + * Log library has two ways of managing log verbosity: compile time, set via + * menuconfig + * + * At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via + * menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL + * will be removed by the preprocessor. + * + * + * How to use this library: + * + * In each C file which uses logging functionality, define TAG variable like this: + * + * static const char *TAG = "MODULE_NAME"; + * + * then use one of logging macros to produce output, e.g: + * + * LOGW(TAG, "Interrupt error %d", error); + * + * Several macros are available for different verbosity levels: + * + * LOGE - error + * LOGW - warning + * LOGI - info + * LOGD - debug + * LOGV - verbose + * + * To override default verbosity level at file or component scope, define LOG_LEVEL macro. + * At file scope, define it before including esp_log.h, e.g.: + * + * #define LOG_LEVEL LOG_VERBOSE + * #include "dxx_log.h" + * + * At component scope, define it in component makefile: + * + * CFLAGS += -D LOG_LEVEL=LOG_DEBUG + * + * + */ + +/* clang-format off */ +typedef enum _kendryte_log_level +{ + LOG_NONE, /*!< No log output */ + LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + LOG_INFO, /*!< Information messages which describe normal flow of events */ + LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ +} kendryte_log_level_t ; +/* clang-format on */ + +/* clang-format off */ +#if CONFIG_LOG_COLORS +#define LOG_COLOR_BLACK "30" +#define LOG_COLOR_RED "31" +#define LOG_COLOR_GREEN "32" +#define LOG_COLOR_BROWN "33" +#define LOG_COLOR_BLUE "34" +#define LOG_COLOR_PURPLE "35" +#define LOG_COLOR_CYAN "36" +#define LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define LOG_RESET_COLOR "\033[0m" +#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED) +#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN) +#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN) +#define LOG_COLOR_D +#define LOG_COLOR_V +#else /* CONFIG_LOG_COLORS */ +#define LOG_COLOR_E +#define LOG_COLOR_W +#define LOG_COLOR_I +#define LOG_COLOR_D +#define LOG_COLOR_V +#define LOG_RESET_COLOR +#endif /* CONFIG_LOG_COLORS */ +/* clang-format on */ + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%lu) %s: " format LOG_RESET_COLOR "\n" + +#ifdef LOG_LEVEL +#undef CONFIG_LOG_LEVEL +#define CONFIG_LOG_LEVEL LOG_LEVEL +#endif + +#ifdef LOG_KERNEL +#define LOG_PRINTF printk +#else +#define LOG_PRINTF printf +#endif + +#ifdef CONFIG_LOG_ENABLE +#define LOGE(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_ERROR) LOG_PRINTF(LOG_FORMAT(E, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGW(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_WARN) LOG_PRINTF(LOG_FORMAT(W, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGI(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_INFO) LOG_PRINTF(LOG_FORMAT(I, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGD(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_DEBUG) LOG_PRINTF(LOG_FORMAT(D, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#define LOGV(tag, format, ...) do {if (CONFIG_LOG_LEVEL >= LOG_VERBOSE) LOG_PRINTF(LOG_FORMAT(V, format), read_cycle(), tag, ##__VA_ARGS__); } while (0) +#else +#define LOGE(tag, format, ...) +#define LOGW(tag, format, ...) +#define LOGI(tag, format, ...) +#define LOGD(tag, format, ...) +#define LOGV(tag, format, ...) +#endif /* LOG_ENABLE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _SYSLOG_H */ + diff --git a/src/openmv/main/main.c b/src/openmv/main/main.c new file mode 100755 index 0000000..686817b --- /dev/null +++ b/src/openmv/main/main.c @@ -0,0 +1,24 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +#include +#include "bsp.h" +extern void mpy_main(void); +int main() +{ + uint64_t core = current_coreid(); + printf("Core %ld Hello world\n", core); + mpy_main(); + while(1); +} diff --git a/src/openmv/src/micropython/ACKNOWLEDGEMENTS b/src/openmv/src/micropython/ACKNOWLEDGEMENTS new file mode 100755 index 0000000..65f731b --- /dev/null +++ b/src/openmv/src/micropython/ACKNOWLEDGEMENTS @@ -0,0 +1,1765 @@ +The MicroPython project was proudly and successfully crowdfunded +via a Kickstarter campaign which ended on 13th December 2013. The +project was supported by 1923 very generous backers, who pledged +for a total of 2320 pyboards. + +Damien George, the project creator, is grateful to the people +listed below (and others who asked not to be named), whose support +of the project help make the code in this repository what it is +today. The names appear in order of pledging. + + 3 Cliff Senkbeil + 4 MacDefender (http://www.macdefender.org) + 11 Shaun Walker - http://theshaun.com + 12 Robert Joscelyne + 17 Peter Simon, Germany + 18 theNetImp + 21 Eamonn Maguire + 22 Rob Knegjens + 27 Greg, https://www.logre.eu + 28 Rick S + 30 Norman Jaffe (OpenDragon) + 34 UltraBob was here. + 35 Geoffrey R. Thompson + 36 MrAtoni + 40 Proud to be a backer of Micro Python, Phil C. United Kingdom. + 42 www.babybadger.co.uk + 45 Mert + 46 Miles Cederman-Haysom + 47 unixarmy.com + 52 Proud to be here! Tonton Pommes + 54 Espen Sae-Tang Ottersen + 56 howang.hk + 58 Innovatology + 59 Marzsman + 63 Tristan A. Hearn + 64 Patrick Clarke + 65 Bryan Lyon + 70 Craig Burkhead + 72 Dr Igor Vizir + 73 Steve Iltis, @steven_iltis + 79 www.giacomo.inches.ch + 80 Alexander Gordeyev + 81 Steve Conklin www.ai4qr.com + 83 n1c0la5 + 84 Matthew R. Johnson + 86 Jeppe Rishede + 87 Kirill Zakharenko - Russian Federation + 88 beltwaybureau.com + 93 felix svoboda + 95 Smart + 96 Stephen Goudge + 97 Dr Richard Whitaker, www.drrich.co.uk, UK + 99 Tim Robertson + 101 Rudy De Volder, www.devolder.be, Belgium + 104 August H., Wien + 107 Jason Hsu + 109 dstensnes + 110 Joe Reynolds (professorlamp) + 112 Michael Davies (AU) - @butterparty @spaceduststudio + 113 Jim Kirk, Westborough, MA, USA + 114 yfnt + 117 Even when it looks like someone is reaching for blue sky. Some days you just have to blindly support that dreamer. + 118 G. Todd Vaules - todd.vaules.net + 122 Gunnar Wehrhahn + 124 Eric Masser + 126 Vaibhav Sagar + 128 Eric Wallstedt + 129 Richard G Wiater + 130 Toby Nance + 132 Michael Fogleman + 133 Snepo Research www.snepo.com Gary says Hi! + 137 nic gihl + 138 Felix Yuan + 139 mmhanif + 141 James Snyder + 144 roddyr2 + 146 Richard Jones + 147 Jon-Eric Simmons + 148 Craig "The Coder" Dunn + 150 Jesse S (USA) + 151 Matt I. - github.com/pengii23 + 153 Seth Borders - sethborders.com + 155 David Zemon (http://david.zemon.name) + 156 Garry DuBose + 157 Apeiron Systems + 158 BAR + 160 Jakob Hedman + 163 Bryan Moffatt + 165 Moises Lorenzo, Tenerife Isl. + 166 Erik H. + 170 Peter George + 171 Nikolas Akerblom + 174 Chris (@chassing) + 176 Wei-Ning Huang + 178 Edd Barrett, UK + 179 Alec Langford + 180 Shunya Sato + 181 Serge GUILLAUME + 183 Dr. Ross A Lumley + 184 Dorian Pula + 189 Tendayi Mawushe + 190 SDanziger + 191 Sean O'Donnell + 192 Kevin McLaughlin + 193 Tommy Allen + 194 Beedlebub + 195 Brad Howes + 196 Mike B + 200 AleÅ¡ Bublík + 202 David Dever + 206 Danilo Bargen, https://dbrgn.ch/ + 209 Brendan Curran-Johnson + 210 Piotr MaliÅ„ski http://www.rkblog.rk.edu.pl + 211 SEE Co. - Science, Engineering and Education Co. - www.seeco.us + 215 Richard Lancaster + 218 Bilbo Baggins from Middle Zealand + 219 Ollie Guy + 221 Shlomo Zippel + 222 Andy Kenny + 223 Double-O-ren + 226 For the pleasure of @tinproject + 229 mfr + 230 Eric Floehr + 232 Matt from Adp.EU.Com + 234 Joanna Tustanowska & Wojciech Bederski + 235 Eric LeBlanc + 236 Siggy , Belgium + 238 Mauro De Giorgi + 239 Belug http://belug.ca/ + 241 Arik Baratz - @arikb + 242 Zvika Palkovich + 243 Yves Dorfsman - yves at zioup dot com + 244 Asad Ansari, Canada + 245 Brandon Bennett + 246 Christoph Bluoss + 248 Konstantin Renner + 249 Abtin Afshar + 250 A. Soltani + 251 Jon Mills + 256 NoisyGecko + 258 Lothilius + 262 Jay Deiman + 263 flo at twigs dot de + 265 _Mark_ eichin at thok dot org + 267 Adrian Astley + 268 aknerats[::-1] + 271 @robberwick + 272 Daniele Lacamera + 273 Thanks to M. Derome + 275 Paul Paradigm, Australia + 276 lyuden + 277 www.SamuelJohn.de + 279 John Pinner, funthyme at gmail dot com + 280 Michael and Vicky Twomey-Lee + 281 Kenneth Ljungqvist + 292 Karin Beitins, Australia + 295 Nick Johnson + 297 Chris Cole U.K. + 298 The planet Andete is famous for its killer edible poets. + 302 Patrick B (aged 11) + 304 Chris Mason, Australia + 306 Steven Foster + 308 Pat Fleury, Andrew Hodgson + 311 @moneywithwings + 313 Neil Stephen + 314 Cory A. Johannsen + 315 Massimo Di Stefano - geofemengineering.it - Italy + 317 James Luscher, Madison, Wisconsin, USA + 319 Lindsay Watt + 320 Nils Fischbeck + 324 Peter J. Farrell - Maestro Publishing, LLC - Minneapolis, MN, USA + 325 Alex Willmer (@moreati) + 328 T.R. Renicker + 329 William B. Phelps + 330 David Goodger + 331 Viktoriya Skoryk + 334 JR Rickerson + 336 Keven Webb + 338 www.hcfengineering.com + 341 Larry Lab Rat, Shalford. + 342 Rob Hetland + 343 Brush Technology (NZ) + 346 Jason Fehr + 347 Olivier Vigneresse + 348 Nano Gennari, me at nngn dot net, Brasilia, Brazil + 352 Petr Viktorin (http://encukou.cz) + 355 Karijn Wessing (IN2TECH) + 356 Arsham Hatambeiki + 358 Alvaro Rivera-Rei + 360 Nolan & Theo Baldwin + 362 Tyler Baker, USA + 363 Russell Warren (Canada) + 365 Aaron Peterson + 366 Al Billings + 367 Jeremy Herbert + 372 Dimitrios Bogiatzoules, www.bogiatzoules.de, Germany + 375 Paul Nicholls + 376 Robert F. Brost + 378 Aideen (Cambridge, UK) - Very happy backer and follower of this great project + 379 Caelan Borowiec + 380 Caroline, Canada - carolinesimpson.ca + 382 Rikard Anglerud + 383 Scott Will + 384 Jussi Ylanen + 385 @joshbapiste + 387 spongefile + 389 Keith Baston + 392 Holger Steinlechner + 394 sent by State mail service + 398 N.Pearce, Wells UK - @t #ashtag UK + 399 Paid up & stood back;; + 401 Mike M. Tempe, AZ, USA + 406 Brandon Jasper + 407 Dan Mahoney + 411 George Bushnell, for use in CPSS + 412 Per Konradsson + 413 Supported by afinzel + 417 Tom Igoe + 418 Jonathan Saggau + 419 Chris Allick http://chrisallick.com + 420 joshuaalbers.com + 423 B. Adryan + 432 Tim Fuchs + 433 steven antalics + 434 BezouwenR + 435 Andrew Addison + 436 Hubert de L'arrêtdubus - France + 437 Salim Fadhley + 438 Ben Hockley + 439 Geoffrey Webb + 441 Vladimir Mikulik + 442 7 Elements & Troy Benjegerdes - hozer at hozed dot org + 443 Pashakun + 444 Craig Barnes, UK + 445 Andres Ayala + 446 Stonly Baptiste (urban.us) + 448 Brian Conner + 452 Jeremy Blum (jeremyblum.com) + 454 Pebble Technology + 455 Andrew + 456 Jeffrey Allen Randorf, PE PhD + 457 J.A.Zaratiegui a.k.a. Zara + 459 simon.vc and hack.rs + 462 La vida es para vivirla y ser feliz, de esa forma damos gracias por tan gran regalo! + 463 Alistair Walsh + 469 fun, Ireland + 474 martijnthe.nl + 479 Andreas Kobara + 486 Armanda + 487 Richard Myhill + 488 Ash Gibbons + 489 Glenn Franxman HackerMojo.com + 492 Russell Durrett + 494 Pieter Ennes + 495 Tom Gross, Washington D.C. + 496 Mark Schafer + 497 Sandro Dutra, Brazil + 500 Can Bulbul + 501 Chih-Chun Chen, http://abmcet.net/Chih-Chun_Chen/home.html + 502 Lost Property Bureau Ltd + 503 skakz + 504 Chad Cooper + 505 Makhan Virdi, mlvirdi.com, InfinityXLabs.com, USA + 506 Glenn Ruben Bakke, Norway + 507 Alasdair Allan + 509 dlbrandon + 511 Dr J Garcia, Sweden + 513 Tiago Vieira + 518 Team ME + 519 OBD Solutions (http://www.obdsol.com) + 520 @pors + 521 Joo Chew Ang + 523 garbas + 526 http://epoz.org/ + 527 J. Sabater + 530 José-María Súnico + 537 Erfundnix + 538 Tontonisback Belgium + 539 Greg Benson, Professor, University of San Francisco + 542 Thomas Sarlandie aka @sarfata + 545 JanTheMan kickstarter at embedded-systems dot craftx dot biz + 546 Chuhan Frank Qin + 549 Peb R Aryan, Indonesia + 553 Johan Deimert, http://www.ldchome.org + 555 Conny Sjöblom / Finland + 558 AndyboyH, UK + 559 Anthony Lupinetti + 561 Travis Travelstead + 566 Siegfried Boyd Isidro-Cloudas + 567 G. Schroeer + 568 mmths, http://randomaccessmemory.at/ + 570 Andy Miller - NZ.. + 571 Rodolfo Lara from México + 572 Gary Patton Wolfe + 574 Vend-lab Russia + 578 Super Job! FXF + 579 Oliver Heggelbacher, www.kickdrive.de + 581 James Husum + 585 David Lodge + 587 Tess + 592 PR Taylor + 593 6306665119 + 598 Jorg Bliesener, Brazil - www.bliesener.com + 602 Rodrigo, Germany + 605 Tanja Kaiser, www.mrsminirobot.de, Germany + 606 Franco Ponticelli - www.weblob.net + 608 Piet Hoffman + 609 Paul Cunnane + 610 Balazs Kinszler + 611 Nathan Ramella (synthesizerpatel) + 612 Tyler Jones (squirly) + 613 James Saffery + 614 Christoffer Sjowall + 615 Iman Shames + 616 Thomas Dejanovic, Australia. + 618 Tom Alker + 619 Matt Davis, UK + 621 Design for the real world! @UXnightingale + 622 Budd Van Lines + 624 __Gio__ + 628 Chew Kok Hoor + 630 Santiago Alarcon, Thanks Damien for Micro Python + 632 hardtoneselector + 633 supported by Chris Bunker + 634 Sebus - France + 635 Mechanical Men Sweden + 638 A Fellow Electronics Enthusiast + 639 Stan Seibert + 642 Dave Curtis + 652 Sebastian Ross - www.ross.sx + 653 Julien Goodwin + 654 Reinoud de Lange, the Netherlands + 655 carl beck + 659 John Gaidimas + 660 Tyler Eckwright + 661 Keith Rome (Wintellect - http://www.wintellect.com/blogs/krome) + 662 Kashev Dalmia - kashevdalmia.com + 666 Alberto Martín de la Torre + 667 Niels Kjøller Hansen + 668 pmst - Italy + 671 Sergio Conde Gómez (skgsergio) + 672 Micromint, www.micromint.com + 673 Xie Yanbo, China + 675 Thank you + 677 Kacem Ben Dhiab + 679 CornishSteve + 680 Daniel Wood, Warrington, UK. + 682 Greg "GothAck" Miell + 688 Matt Williams & Sam Carter + 691 Frédéric Lasnier + 694 Tim K + 697 Joshua Clarke, Guernsey! + 700 daynewaterlow.com + 703 Scott Winder + 704 @DepletionMode + 707 Maria Yablonina + 710 Roger Hausermann + 713 Crazy_Owl + 714 mike hardin usa + 717 C. Towne Springer + 719 ursm gruesst euch + 720 madnis + 727 http://itay.bazoo.org + 729 @0atman + 730 Jerry Gagnon + 732 Emmanuel Boyer + 738 suspenders + 739 Roland Frédéric - http://www.creativeconvergence.be/ + 742 @herchu + 745 Riley Lundquist + 746 Go LOBOS + 749 João Alves, http://jpralves.net, Portugal + 751 Nick Porcino + 753 Jack E. Wilkinson, Texas, USA + 754 @rcarmo on Twitter/Github + 758 Matt Manuel, www.mattmanuel.com + 759 Padraic D. Hallinan + 760 Rob Fairbairn + 763 Zac Luzader + 768 Sam Shams + 773 terje nagel, dk + 775 Luc LEGER + 782 Luis M. Morales S. + 785 Charles Edward Pax + 786 Daryl Cumbo + 787 Zephyris13 + 788 Wonderful project. + 792 Sylvain Maziere + 794 Milen + 795 Robert Mai, Germany, hsapps.com + 797 Angelo Compagnucci angelo.compagnucci at gmail dot com + 801 Long Live Micro Python, airtripper.com + 804 António M P Mendes + 805 Marc Z. + 809 Anoyomouse + 810 in memory of Dan J. Schlacks III + 817 Peter Froehlich - http://werk-schau.blogspot.com + 818 Ahmad Albaqsami + 821 Peter Lavelle (http://solderintheveins.co.uk) + 822 Manuel Sagra de Diego http://manuelsagra.com/ + 823 Sam Wilson + 824 Khalis + 825 c't Hacks + 828 Georg Bremer + 830 Ward en Sanne (WenS) + 832 javacasm http://www.elcacharreo.com Spain + 833 mctouch + 835 Bruce Schreiner @ www.stevenscollege.edu/electronics + 836 Jonas + 839 Nick Ludlam + 840 Patrick_Law, UK + 843 Alex Crouzen, UK + 848 Ben Banfield-Zanin + 850 Wouter Slegers, Your Creative Solutions + 851 Fred Zyda + 853 Gianfranco Risaliti + 854 Ron Hochsprung + 858 Vianney Tran + 862 Aaron Mahler - http://halfpress.com + 868 Stephan Schulte, Germany + 869 Kenneth Henderick + 872 DaveP (www.davepeake.com) + 873 Markus Schuss, Austria + 876 Kyle Gordon, http://lodge.glasgownet.com + 877 Joseph Gerard Campbell + 881 Thanks for the board. Good luck to you. --Jason Doege + 883 Garet McKinley + 884 www.magtouchelectronics.co.za + 889 Ben Johnson + 896 Ruairi Newman + 897 Gemma Hentsch + 902 Alexander Steppke + 906 Stephen Paulger + 907 Martin Buhr, http://lonelycode.com, UK + 912 Dale Drummond + 913 Go Utah State + 918 Jarturomartinez, Mexico + 921 Barry Bourne Micro Python Supporter + 923 Andreas Bolka + 927 Thanks Susan, Tom, Paul, and Mark! + 935 http://wall-y.fr + 937 Eero af Heurlin, Finland, https://github.com/rambo/ + 938 Guillaume DAVY + 941 Alexander Steffen + 942 Janne "Lietu" Enberg + 945 Luca 'loop' de Marinis - https://github.com/loop23 + 946 Andras Veres-Szentkiralyi http://techblog.vsza.hu/ + 948 Florian flowolf Klien (http://blog.flo.cx) + 949 nickyb + 951 Mark Walland, England + 952 Ian Barfield + 953 Andrew Murray, UK - eat my code - http://links.bloater.org/micropython + 955 Kyle Howells + 956 Chris Cadonic + 957 LCS, USA: scripting___/||\===/||\___embedded + 958 Sven Wegener + 963 Kean Electronics http://www.kean.com.au/ + 964 Beandob + 965 Don't feed the troll. + 966 Alexis Polti (http://rose.eu.org) + 969 Scottyler + 971 The Dead's Own Jones + 974 Evseev Alexey + 976 Arnaud + 978 Jannis Rosenbaum + 980 paul at fontenworks dot com + 981 John Griessen ecosensory.com USA + 982 Tobias Ammann + 983 Simon V. + 984 JaWi + 987 Ergun Kucukkose + 989 Jonathan Piat France + 990 Steve Pemberton + 993 Aaron Robson + 994 Antoine Authier + 995 Thomas Winkler, Austria + 997 Jannes mit dem dicken Pannes + 1001 Joe Baker + 1002 Jon Hylands, Canada (blog.huv.com) + 1004 Mike Asker (aka mpymike) + 1007 Charles V Bock - Charles at CharlesBock dot com + 1010 Remember June 4th, 1989 + 1012 Stuart Marsden + 1013 Herbert Graef, Stuttgart + 1014 Arthur P, USA + 1015 John Hall & Jeremy Armijo + 1017 Luciano Ramalho, Python.pro.br + 1018 Quentin Stafford-Fraser + 1019 Marcin Walendzik Ratingpedia.eu + 1020 Wincent Balin + 1022 rbp + 1024 Frank Carver ( www.frankcarver.me ) + 1026 Peter Farmer, http://geekytronics.com/ + 1029 Rubens Altimari + 1033 Sebastian + 1035 Gerli, Estonia + 1036 Maurin, Switzerland + 1037 Kevin Houlihan (http://crimsoncookie.com) + 1039 Jon Green of Adeptium Consulting (www.adeptium.com) + 1040 Eirik S. Mikkelsen + 1042 Jogy Sam + 1043 GGG + 1045 Sean E Palmer, epimetheon.com + 1049 Greg O'Drobinak, USA + 1050 RaptorBird Robotics Inc + 1051 Desmond Larsen-Rosner + 1056 Crusty + 1057 ArthurGuy.co.uk + 1059 Melissa-Ivan, 14/04/2013 + 1064 Enrico Spinielli, https://github.com/espinielli + 1066 Dave Snowdon + 1067 Martin P. Hellwig + 1070 Carl Clement + 1074 Paul Taylor + 1076 Pandemon + 1082 Thrilled to support Damien's effort to put this together: there will no doubt be many applications for this effort and many enhancements and ports.. + 1083 Oddvar Lovaas + 1090 BenScarb + 1093 Www.qualnetics.com + 1094 Manny Muro - Now Python can RULE from below as it does from above! PYTHON RULES!!! :) + 1095 Michael Grazebrook + 1098 Mark Shuttleworth, UK + 1106 wyzzar + 1110 Luca Zanetti + 1112 Carl A Fagg + 1115 Adam Klotblixt + 1118 Breawn + 1122 pippyisatruck + 1124 Andrew "ClothBot" Plumb + 1126 Realise the projects your heart beats for! Sven Wiebus (http://wiebus.tumblr.com) + 1128 Citius Systems + 1130 Benjamin & Reuben Fuller + 1131 aglimme + 1133 John Becker + 1135 Mark Drummond + 1138 JHProuty + 1141 Lars Olsson Sweden + 1144 daisuke, http://dkpyn.com + 1145 Chris Pawley - http://www.pawley.co.uk/honey/ + 1147 Daniel from EzSBC.com + 1149 New York Mortgage Exchange NYME.COM + 1150 Herb Winters,USA,www.ecs87.com + 1151 renttu + 1159 Joe Rickerby + 1160 john guthrie + 1161 PUBLIC + 1163 dobra-dobra + 1164 Neil Reynolds, Staffordshire + 1165 GEHoward + 1166 Frank Delporte + 1167 Bauer Brauner Enterprise + 1168 Francisco Mardones + 1169 Ryan Kirkpatrick, @rkirkpatnet, http://rkirkpat.net/ + 1170 Krister Svanlund + 1174 Derek Patton Pearcy + 1177 Roger Olsson, Sweden + 1179 Jan-Niklas Braak + 1180 Pete boy + 1181 MilenX + 1182 Ubbe Larsson + 1183 Simon Freethy + 1184 Daniel Andersson + 1187 Daniele Procida + 1190 Adrian Duke + 1191 Pauline Middelink + 1193 Ted Gueniche + 1197 Craig Knott, University of Queensland, Australia + 1198 Jamie Mackenzie - Australia + 1199 ravenoak + 1200 LucaP Luni Italy + 1203 jacanterbury + 1205 Bleachin, www.rhyspowell.com + 1207 Supported by Andrew Maier via Kickstarter + 1208 Rob, http://robjstanley.me.uk + 1210 George Gingell + 1213 Chris Elleman + 1215 Jack Barham - @jackbarham - http://jackbarham.com + 1221 Kyle Dausin + 1222 Ben Lucker + 1225 Gareth cheesewhisk Evans + 1226 Jacob Forsyth + 1227 Olof S - Germany + 1231 Brasil + 1233 glaslos + 1234 Will Cooke - http://www.whizzy.org + 1236 Andrew Wright - Canada + 1239 Resourceful Robin + 1240 Jay O'Neill @jayoneilluk + 1241 Dennis G Daniels + 1244 J. Peterson (www.saccade.com) + 1245 Chipaca + 1246 Nicko van Someren + 1247 C. Cumbaa, Canada + 1248 Gyro Gearloose was here + 1249 Magnus Ericmats, Sweden + 1253 Steve Wilson + 1256 Adrian Bullock + 1258 Sarevian & Longwall + 1261 Skipp Savage + 1265 Eric Nahon + 1267 Stuart Dallas / 3ft9 Ltd + 1270 USA + 1271 Oliver + 1277 jeffmcneill.com + 1278 alnjxn + 1283 Marc Liyanage + 1285 Christian Lange + 1286 Bryant Paul Umali from the Philippines + 1290 W.B.Hill, Norwich, UK + 1292 Michael Karliner + 1293 Oli Larkin + 1303 A. Pockberger + 1304 dc - bagel + 1305 Thadeus Arnel + 1308 technoweenie + 1309 Liam Welsh + 1313 Per Thorell, Sweden + 1314 peterlee + 1316 Dustin Mierau + 1317 tech-zen.tv + 1320 Cheers from IDF :) + 1322 www.a-d-k.de + 1323 rixx + 1324 @jlev + 1325 e2e4 + 1328 Thomas J. Quinlan, London UK + 1329 Don Bone + 1331 Narayanamurthi + 1333 PGS_Astra-ProjeX_Wilts + 1337 Mark Schulz & Phillip Long, CEIT, The University of Queensland + 1340 Tiegeng (Tim) Ren + 1344 EMR_1344, DE + 1348 Matt Ward, Nottingham + 1351 Rupert + 1352 Cory Li - http://cory.li + 1354 Jim Davies, Brighton, UK + 1355 Jon Watkins, UK + 1356 Thomas, www.bitmix.de + 1359 Markus Gritsch + 1362 Carl H. Blomqvist + 1371 Brian Green + 1374 Ben Merryman + 1375 O'Dea + 1376 Josh Trujillo + 1378 Daniel Halloran + 1379 another_martin + 1383 Thanks for innovating! + 1385 CoderDojo Malahide + 1397 Jacob Z + 1398 Staffan Hillberg + 1399 http://kim.ht + 1402 Can't wait to plug it in! + 1403 Márton Szinovszki + 1405 sellorm says 'Hi!' + 1406 Thomas Provoost + 1411 Clive Freeman + 1412 Norman Thomas + 1415 Javier Llopis + 1417 Ho Man Fai + 1418 Anders Helland + 1421 Richard lavanture + 1425 Alan Churley, UK + 1426 Robert'); DROP TABLE Students;--unicode is fun! + 1427 Go Illini! + 1430 MicroPy FTW + 1431 Bryan Morrissey, www.browninnovations.com + 1436 Krzysztof Chomski, Poland + 1437 WellAware (USA) + 1441 Tomas Hau + 1443 Paul Way + 1444 Benjamin Anderson + 1445 Andrew Bates + 1446 Davide Di Blasi + 1451 Mathias Fischer + 1453 Drexore, NL + 1454 Marek Mroz + 1455 Mark Easley Jr. - USA + 1457 Joshua Warren + 1459 Rohan Menon + 1460 Paul Sokolovsky + 1461 Chris Foresman, @foresmac + 1475 USI + 1478 Chris Emerson + 1479 Ph. Truillet, France, http://www.irit.fr/~Philippe.Truillet + 1480 WAB3 + 1481 Lucidologia.pl + 1482 Ed Hardebeck | www.hardebeck.us + 1484 Ludovic Léau-Mercier, www.coriolys.org, France + 1487 BLUEBOBO + 1488 Berno Kneer, Germany + 1491 Julian Eccli + 1494 Batman + 1495 Manuel Núñez Sánchez + 1496 Millie and Sadie Smith + 1499 Ronald Eddy + 1500 SynShop Las Vegas + 1503 This is really cool. - Jack Conway + 1505 Victor Suarez, Argentina + 1507 Renesas Electronics America + 1509 Team + 1513 A. Lamborn KD0ZFY + 1514 olifink + 1520 mike at sustainable-opportunities dot com + 1521 luis almeida, Teresina - Brazil + 1523 Muhammad Jamaludin + 1524 Sdlion + 1525 Charles Rogers + 1526 Diego M. Aires, Brazil + 1529 muwatt.com + 1532 Proud supporter of microPython + 1535 Jesus J. de Felipe + 1536 slminneman.com -- Wow, an acknowledgement? ...really? + 1538 Mike (Meski) Smith + 1541 Piero Steinger + 1545 Alex Rembish (https://rembish.org) + 1551 Sergey [BuG2BuG] Sobko, Russia + 1553 Serge Krier + 1556 Luuk Derksen + 1561 Jimmy Caille (CH) + 1562 Jesús Leganés Combarro "piranna" + 1564 Viacheslav Olegovich Savitskiy + 1565 Jamie Whitehorn + 1567 Bagge Carlson + 1568 Milan Cermak + 1569 Matthias Lemp + 1570 BOFG + 1571 Johan Elmerfjord, Sweden + 1573 Matt Finch • fnch.io + 1574 Jean-Francois Paris + 1575 Florian Franzen, Germany + 1576 doganowscy.com + 1579 Stan Yamane + 1580 William Cirillo + 1583 David Dibben + 1584 Nicolás, Amelia, Luli y alecu + 1586 Alex W + 1591 Livia Maria Dias Tavares + 1593 d freymann chicago il & his australian shepherd jaldi + 1594 Barnstorm Studio, LLC + 1595 Sashi Penta + 1597 tflhyl + 1598 clacktronics + 1599 j3hyde + 1600 Rik Williams + 1602 Valeriy Van, Ukraine, w7software.com + 1603 Louis Taylor - https://github.com/kragniz + 1606 What's the derivative of (6.022 x 10^23)x? That's A(n)mol + 1611 Bailey & Brayden Yoong Policarpio + 1613 William Bettridge-Radford + 1617 Urbane Jackson + 1618 Henius + 1622 Alister Galpin, New Zealand + 1623 Marco Bertoldi + 1627 Julian Pistorius + 1628 www.neotral.com + 1632 ChrisB + 1633 Norbini + 1634 Eric Rand at Brownhatsecurity.com + 1636 Benjamin Eberle + 1637 MG Projects bvba, Geert Maertens, Belgium + 1640 Robson dos Santos França (Brasil) + 1642 Udine + 1643 Simon Critchley + 1644 Sven Haiges, Germany + 1645 Yi Qing Sim + 1646 "silicium" ("silicium_one", if "silicium" is busy) + 1648 Andy O'Malia, @andyomalia + 1650 RedCamelApps.com + 1652 Christoph Heer + 1653 AlisonW + 1654 Yannick Allard (Belgium) supported this project. + 1655 Andy Pointon, UK + 1660 Diego Cantalapiedra + 1664 Pepillou + 1670 Sonny Cannon + 1671 Rick W + 1672 David Chan, USA + 1674 Philip Rowlands + 1675 dieresys + 1676 T.R. Fullhart + 1683 Oleg Sidorkin + 1686 Tatsuro Yasukawa + 1687 Brad Smith, Somerville MA, USA + 1688 kristoffervikhansen.com + 1690 Nice Project de W6AKB Alan Biocca + 1691 Hiss Hisss Hissss Hiss Hiss Hissssssss + 1692 Alan Kennedy + 1698 ElChessu + 1701 Flower Craswell + 1702 David Fontenot + 1707 To innovation & creativity. Tony J Winter + 1708 Joakim Hentula + 1711 Michael Schaefer + 1713 Brody Radford ~ www.brodyradford.com + 1714 Charles Durrant + 1715 Rodrigo S. + 1718 Dima Shylo + 1719 Jiahao James Jian + 1722 Helen Wilson, Christ's Hospital + 1726 Martin Aule, http://hackest.org/ + 1727 Ä°smail Etem Tezcan, Rasteda + 1728 Charlie "Blackfrog" Sizer + 1729 Matloob Qureshi + 1730 Travis Saul http://travissaul.com + 1731 Michael Cavins + 1733 Peter Köllensperger, Norway + 1734 Anne Harrison + 1736 Peter Bradeen + 1739 Fredrik Luthander + 1740 Nick LaRosa + 1744 Aladuino + 1745 dgrebb + 1746 Truls Unstad + 1748 Jesus Saves + 1750 Andy Stannard (@rockmonkey) + 1751 Daniel Atkinson + 1755 John Potter + 1758 Ian V + 1760 David Leinbach + 1761 nemec-automation.com + 1765 Supported by JoW with Hardwired TCP/IP from www.WIZnet.eu + 1767 misskniss, Boise Idaho. It is our responsibility to code the freedom we want to see in the world. + 1768 Jeff Vahue - Knowlogic Software Corp. + 1769 Pat Molloy + 1770 Greg Maxwell gregmaxwell-at-mac-dot-com + 1771 Rich Robinson + 1773 Ken Corey @ flippinbits.com + 1782 Acknowledged + 1785 Optimized Tomfoolery + 1791 Nontakan Nuntachit, Thailand + 1794 Rasit Eskicioglu - Canada + 1795 Simon Elliston Ball + 1796 pfh + 1798 John W. C. McNabb + 1799 Frank Sanborn + 1803 Morgan Hough + 1804 Sorcha Bowler + 1805 http://www.WayneKeenan.info + 1806 HBEE, hbee.eu + 1807 Deadlight + 1809 www.danenet.org + 1811 Sergey Nebolsin + 1813 Threv + 1817 dynsne + 1818 David Wright + 1819 John Warren + 1821 I wanted Erlang! (╯°□°)╯︵ â”»â”â”» + 1825 Howard R Hansen + 1828 Kevin Schumacher + 1833 Matthias Erll, Sweden + 1836 Matt Graham + 1837 thedawn + 1838 Ruby Feinstein + 1839 Gustavo Muñoz (timbergus) + 1840 Ian Paczek + 1841 Köteles Károly, Hungary + 1843 Tobias Sette Ferreira + 1846 x4FF3 <3 microPython + 1847 Enrico Faulhaber (Germany) + 1850 jolan00 + 1854 Red Harbinger Inc + 1855 Noman + 1858 @DerLinkshaender + 1863 Jon Woodcock + 1864 Elmo, hakkerikartano.fi + 1865 Imaginals + 1866 Sam Hathaway and Rachel Stevens + 1874 Remo Sanges, SZN, Italy + 1875 Devraj Mukherjee + 1876 an Embedded fan + 1877 Peter Huisers + 1878 Kin-Wai Lee (Malaysia) + 1879 Samuel Hawksby-Robinson + 1881 R. Stock + 1886 Randy of Capistrano street backed Damien's MicroPython! + 1887 Rogério Bulha Siqueira - www.esd-talk.com - Brazil + 1889 NickE is happy to support such a worthy project! + 1892 John Boudreaux + 1894 Riverfreeloader + 1895 Jose Marcelino http://metavurt.net + 1896 T Britto-Borges + 1899 DannyWhitsonUSA + 1904 José Iván Ferrer Ruiz. + 1905 Tom Loredo + 1906 Gregory Perry USA + 1908 josephoberholtzer.com + 1910 Michael Klos, USA + 1912 Adam Mildenberger + 1913 R Anderson + 1914 Nikesh, USA + 1915 Bogdan Chivoiu, Romania + 1916 Scott C. Lemon, USA + 1918 Konstantin Ufimtsev (@KestL) + 1919 Benny Khoo + 1922 Nicci Tofts + 1925 Joshua Coxwell + 1926 Franklin Hamilton + 1928 Peter Korcz + 1929 Leroy Douglas + 1930 A ナル㨠fan from Nigeria who likes smileys, here's one for good measure :) + 1931 Kimmo Lahtinen, Finland + 1932 http://staybles.co.uk + 1937 The Olivetti's: Emanuele Laura Nausicaa Sibilla Ettore + 1940 Pascal Hirsch + 1942 cbernander, Sweden + 1944 Enrico M. + 1947 Dinis Cruz + 1949 Jonathan Greig, http://embroidermodder.github.io + 1950 Andy Bower + 1952 Gerard Hickey + 1953 Fabrice BARRAL was here ... + 1955 Pieter Röhling + 1957 uomorando, Italy + 1959 Acacio Cruz + +The MicroPython project raised further funds through a second +Kickstarter campaign that was primarily targeted at porting the +code to the ESP8266 WiFi chip. The campaign ended on 2nd March +2016 and gained the support of 1384 fantastic backers who believed +in the project and the principles of Open Source code. Those +backers who asked to be named are listed below, with an asterisk +indicating that they also supported the first campaign. + +* 1 Gabriel, Seattle +* 2 @robberwick +* 6 Dave Hylands + 7 Les, UK + 8 Ryanteck LTD., UK + 10 karlsruhe, HU +* 11 Turbinenreiter + 13 Ben Nuttall, UK +* 14 Bryan Morrissey, MA, USA +* 15 Jogy, Qatar +* 16 BOB63,IT + 19 ReaBoyd +* 20 Andrew, MK +* 21 chrisq, NO + 22 Pascal RENOU, France + 23 Javier G, ES + 25 Forrest, US + 26 Filip Korling, Sweden + 27 roberthh - Rhineland +* 28 Herbert Graef, Stuttgart, thanking the MicroPython Team for this great project +* 29 johnsonfamily38, UK + 30 CympleCy + 31 OJ, PK + 32 Daniel, SVK + 33 Shabaz Mohammad +* 35 Kenneth Henderick, BE +* 37 Daniel Mouritzen, DK + 39 Torntrousers, UK +* 44 Scanner + 45 Radomir Dopieralski + 46 Nick, UK +* 47 Jon Hylands, Canada +* 48 Ben Barwise Clacktronics + 50 Rob Kent, UK + 52 Carlos Pereira Atencio + 54 Andy, UK +* 55 WMinarik, Canada + 57 Hauffe, Germany + 58 HyperTaz, IT +* 61 Michael Kovacs, AT + 62 Erick Navarro, PE + 69 Karan,US +* 71 Nick B, UK +* 72 Anthony Lister, NZ +* 73 Bryan Lyon + 76 Miguel Angel Ajo, ES +* 78 Sebastian, Regensburg (GER) +* 80 iv3unm + 81 Thierry BÉNET, FR + 84 Jannis, Germany + 86 Nathan Jeffrey + 88 Cory Benfield, UK + 90 Carlo, IT +* 91 Wojciech Bederski (@wuub) + 92 Steve Holden, UK + 93 Tristan Roddis, UK + 94 Balder, Sweden +* 95 Rhys, UK + 96 Rowan, UK +* 97 Gary Martin, Edinburgh +* 100 Mikael Eiman +* 101 torwag +* 102 Craig Barnes, UK + 103 Andrea Grandi, UK + 105 Piers, UK +* 109 Wayne Keenan + 110 makuk66 + 111 Hamine,DZ + 112 Arahavica,JP +* 113 Bill Eubanks, USA + 114 Jonathan, UK + 115 ghickman +* 117 Christian Lange, Germany + 119 Jonty Wareing + 121 TheHetman + 123 Víctor R. Ruiz, Spain +* 124 Laurynas Paukste, Norway +* 125 Taki + 126 André Milette, Canada +* 127 Ron Cromberge,NL + 128 IJ, Thailand +* 130 IGOR VIZIR + 132 Bill Saturno + 134 scibi + 136 Timbo, AU + 137 Raphael Vogel, DE +* 139 jasonkirk, US + 141 Linköping, Sweden +* 142 Dugres + 144 DarioS, UK + 146 NelisW +* 148 _Mark_ +* 149 Folke Berglund, Sweden + 150 Deniz Dag/Belgium + 152 Jacques Thomas + 153 Dag Henrik, Norway +* 154 Alexander Steppke + 158 stavros.io +* 161 Seong-Woo Kim, KR + 162 Aaron H, Seattle + 164 Iwan, CZ + 165 Jenning, DE + 167 Oliver Z, Germany +* 168 Chris Mason, Australia + 169 Fabio P. Italy + 171 Jonathan, Ireland + 173 Philipp B., DE + 174 Mancho, IT + 175 Mikkel Sørensen, DK + 176 Raphael Lullis +* 177 Tim, China + 179 JasperS, NL + 180 Scott, AU + 181 Roland Kay, UK + 182 Adam Baxter + 184 Hugo Herter + 185 Simon AM, Malta + 186 Leif Denby + 190 Maxious +* 192 Guido, GER +* 193 Pierre Rousseau, Canada + 195 Pete Hinch +* 198 KoalaBear,USA. TRUMPED 2016! +* 200 Pimoroni, UK + 201 jpwsutton, UK + 203 Felix, Sweden + 204 Dmitri Don, Tallinn Estonia + 205 PeteDemiSwede, UK +* 207 Serge GUILLAUME + 208 Gurtubay, ES + 209 Geir-Olav, NO + 210 RayDeo, Germany + 215 DIYAbility + 216 Josef Dunbar, USA +* 217 Enrico, BE/IT + 219 Damian Moore, UK + 220 Wayne and Layne, LLC + 221 The Old Crow, USA + 224 Hackscribble, UK +* 225 Alex March, UK + 226 @rdslw + 227 Mike, Canada +* 228 Adrian Smith + 229 Dinu Gherman, Germany + 230 Tinamous.com +* 231 Nikesh, US +* 232 chrisallick.com + 234 Daniel Von Fange +* 235 Michal Muhlpachr, CZ +* 236 Petr Viktorin + 237 Ryan Aldredge + 238 Patrik Wallström, SE +* 239 MobiusNexus + 240 Stray, US +* 241 BOFG, no + 244 Issac Kelly +* 247 David Prime + 249 James Marsh, UK +* 250 BezouwenR + 252 Avinash Magdum, India + 253 Greg Abbas, Menlo Park CA + 254 Jorge, ES + 256 JohanP, swe +* 258 Ben Doan + 259 Jan van Haarst, NL +* 263 JoshT, Los Angeles + 264 cstuder, Switzerland + 266 Jon Armani +* 270 Liam Welsh + 271 Jason Peacock + 272 Alejandro Lopez + 275 Dan O'Donovan, UK + 276 N1TWC + 277 Roland Tanglao, Vancouver + 278 Twpsyn + 280 Robert, ME-US +* 282 Thomas, UK + 283 Jeff Schroeder, USA + 284 Paulus Schoutsen +* 287 Neon22, NZ + 290 kbmeister + 291 Gary Hahn + 292 Dave Matsumoto, USA + 296 Sam Lee, SG + 304 Poul Borg, Denmark + 307 MightyPork + 308 Dale +* 312 Anton Kraft, Germany + 315 Kism3t, UK + 317 NateM +* 318 N&T, Calvijn Meerpaal, NL + 322 Andreas Monitzer + 323 Rikard, SE + 328 Olaf, DE +* 329 John Boudreaux + 330 DOCE, Germany + 331 feilipu + 332 Stefan Schwetschke + 333 Wayneji, NZ + 337 Alain de Lamirande, Canada + 338 Hori, TW + 340 Azmodie, UK + 341 Lygon, UK +* 342 JRM in STL, USA + 344 R Colistete-Jr., BR +* 345 ChristianG, DE + 347 Nis Sarup, DK. + 350 Nickedynick + 351 Dazza, Oz + 352 lispmeister, NL + 355 Tomas Lubkowitz, SE + 357 Mark, UK +* 358 Team ME + 363 Papahabla + 364 Greg Chevalley + 365 Maic Striepe, Germany + 369 Ian McMahon + 371 A. DARGA, Fr + 372 Ernesto Maranesi, BR + 373 Steve Lyon + 374 James Cloos + 375 Bas Zeppenfeldt, The Netherlands + 378 Pycom Ltd + 380 Wade Christensen, USA + 382 Justin Wing Chung Hui, UK + 383 C Paulson + 384 Ian Tickle + 386 Danny, Seattle + 388 Erik Moe, Chicago, IL +* 389 Eric B. Wertz, USA + 390 Michael. CH + 391 Christopher Baughman + 392 James Churchill + 393 Rob, DC + 395 Whee Min, Singapore +* 396 Jason Doege, TX + 401 MrFish + 403 Thejesh GN + 404 Markus, Sweden + 405 AMR, Spain + 407 Svet, ES +* 408 Thoralt, Germany + 409 Emil, Sweden + 410 David Moloney, ireland + 411 Marco S, DE + 415 Peter W., Austria + 417 emendo A/S +* 419 Kalestis, Switzerland + 421 Ondra, CZ + 422 Elheffe + 423 thinkl33t, UK + 424 TonyF + 425 Herr Robert Linder, PA, USA +* 426 Anders Astrom S(E|G) +* 428 Jussi Ylanen, CT, USA + 431 Neil H., USA + 434 Rod Perez, MX + 435 Carol, US + 436 Gina Haeussge, DE + 438 Weilinger, GER +* 439 Ron Ward, Australia + 441 Rex, UT, USA +* 444 Slush, CZ + 445 Bruce, Florida +* 448 Patrick Di Justo + 449 ScubaBearLA + 450 Mike Causer, Sydney AU + 451 Joel Fries, USA +* 452 Andrew Bernstein, US + 454 EAS, Seattle, WA, USA +* 456 Christopher J. Morrone, USA +* 457 Anthony Gilley, Sweden + 458 Andre Breiler, DE +* 460 Fuffkin, UK +* 461 adent, CZ + 462 Samuel Pickard + 463 Mirko, Germany +* 464 Ramin/US + 465 Mike, Grenoble + 466 Rolf, DE +* 467 Dave Haynes +* 469 Mac Ha, Vietnam +* 470 Enno, DE +* 473 Smudo, DE +* 474 Duncan, Scotland + 475 Chris, UK + 476 Peter Groen, NL + 478 Gertjan Geerling, Nijmegen +* 479 Benjamin Eberle +* 480 Mechanical Men Sweden +* 482 Rémi de Chazelles, FR + 483 mager, Bremen + 484 jurekh, NL +* 485 Craig Burkhead + 487 JohanHartman, SouthAfrica +* 489 Viktor, NL + 491 Jean-Denis Carre + 492 Jesse, Canada + 493 Alex C. MacDonald, USA +* 494 GustavoV, MX + 495 Sebastian, Berlin + 497 Bernard, Feluy +* 500 Ron H, USA + 501 Gregg "Cabe" Bond, UK + 502 Colin, NI + 504 Robin, USA +* 507 pkropf +* 510 6LhasaCo Canada + 511 Tom Sepe, USA + 513 Andrew McKenna + 515 tom46037 + 516 G2, USA +* 517 Pauline Middelink, NL +* 518 Brush Technology, Ltd + 520 Pierre Meyitang, USA + 521 Stephanie Maks, Canada + 526 John McClain +* 527 Sigadore, US + 528 Richard Hudspeth, US + 530 Martin, Austria + 531 Stephen Eaton, Australia +* 533 RJCE, UK + 535 Teiste, Finland + 536 Pio, UK + 537 DirtyHarry, DE +* 540 Dom G. UK +* 541 Nial, UK + 543 Andreas, AUT + 545 WisdomWolf +* 549 MrMx,ES + 552 Daniel Soto, Landscape. + 554 Claus Fischer, DK + 557 Aleksi Määttä + 560 Justin Wilcott, USA + 562 LoneTone, UK + 567 Cameron, US + 568 Dirck, Germany + 569 Michael Keirnan + 571 Harry, CN +* 572 Ward Wouts + 573 Dan Anaya, USA + 574 Ben Bennett + 575 nirvana2165, US + 576 PDG, BZH +* 581 Visit, Thailand + 582 John Carr, UK +* 583 Klankschap + 587 jacky,FR + 588 JD Marsters + 591 Ryan Jarvis, US + 595 Claudio Hediger, CH +* 597 Bambam, Sweden + 598 Timothé, FR +* 599 Luís Manuel, Portugal + 601 Eric, DE + 602 Olaf, Cambridge, UK +* 603 Tim, Dubai + 604 Tyndell, US + 606 Ciellt AB, SE + 607 Ömer Boratav + 609 Guy Molinari, US + 614 Freek Dijkstra + 615 Carlos Camargo CO + 616 Michael Nemecky, Norway + 618 Ovidiu G. + 619 arobg, USA +* 621 Geoff Shilling, US + 623 EliotB, NZ + 624 slos UK + 625 Montreal, CA +* 626 Peter Korcz + 627 Kodi + 628 Jim, Valdosta, USA + 629 Sander Boele, NL + 630 Max Lupo + 631 Daniel.B, Newcastle Australia + 632 Andrés Suárez García, Vigo (Spain) + 633 Rens, NL + 634 Max Petrich, DE + 635 Fabian Affolter, CH + 636 Cadair +* 637 Mike Karliner + 638 Daniel T, UK + 639 Mark Campbell, UK + 640 James S, Australia + 641 PBTX! +* 642 amaza,SP + 644 se4mus +* 645 Alexander Steffen +* 647 Jim Richards Maine, USA + 649 Doug D, US + 650 Keaton Walker +* 651 Scott Winder, USA + 653 Jeff Fischer, USA + 654 Andrej Mosat + 655 Mohd Faizal Mansor, Malaysia + 657 Mike "Cutter" Shievitz, US +* 658 Daniel Andersson, SE + 659 Alexander, NL + 660 François, CH +* 661 AndrewS, UK + 662 Denisae, PT + 663 KC8KZN + 664 Angelo, Wales + 665 BlueberryE, Germany + 667 fvlmurat + 668 Adam Wilson + 675 Ulrich Norbisrath (http://ulno.net) + 676 Daniel, Portland OR +* 677 Andreas Lindquist, SE + 680 Jason, NL + 682 lapawa, GER + 683 John Batty, UK + 685 Addy, Netherlands + 686 Marc, CA + 690 APapantonatos + 691 gmorell, US +* 692 Jamie Mackenzie, Adelaide, SA +* 693 Dave Dean, US + 697 woojay, US + 698 Webabot, NY +* 699 Jason Fehr, Canada + 700 Hadi (AU) +* 701 Abraham Arce +* 703 Must Be Art + 712 Thanks for the great work!/datax-holding/Stuttgart +* 714 Thomas Pr., BE + 715 Black Country Atelier BCA + 718 Don W, Arlington VA + 721 Xavier C. (EU) + 722 Chad P. Lung, U.S.A + 726 Alexander Lash (@lexlash) + 727 Sven, MX + 728 Terence, PL +* 730 Mauro De Giorgi, USA + 735 Jay Ward, Canada + 736 Fabian Topfstedt, AT + 739 sjoerdDOTcom + 740 David, Australia + 743 Michael Niewiera, Germany + 745 cbenhagen + 746 berserck, CH + 748 Lars Hansson, Sweden + 750 Landrash + 751 Richard B., CT USA + 752 Neil Chandler, UK +* 753 John Griessen US +* 755 Caminiti, Mexico + 757 Mikael Trieb, Sweden + 760 S1GM9, MX + 761 Dave C, US +* 763 Su Zhou, China + 765 Caitlyn - USA + 769 Will, NZ + 770 CJB,UK + 771 Victor Claessen, NL + 772 Antal, CH + 773 Tokyo, Japan +* 774 Join Business & Technology AB, Sweden + 777 Overspeed Innovation +* 778 Bruce, Chanute KS + 779 TOPALIS, RO + 780 klaas2 + 781 Matthias Schmitz, Berlin + 783 Jan Studený wishes "Python everywhere" + 788 Ian, USA + 789 Mark K, UK + 791 DerFlob, Germany + 792 Staffan Johansson, Sweden + 793 Stefan W., DE + 795 Mark S. Harris, Small Dog Electronics + 796 Kittikun, TH +* 798 aerialist, Japan + 799 Sweta +* 800 Mark Shuttleworth + 802 Kim Thostrup + 803 Andy Fundinger + 810 Matt Vallevand, Detroit MI + 813 Jim McDonald + 816 Rob Dobson + 817 RafaÅ‚ ZieliÅ„ski, PL +* 818 Shaun Walker, AUS + 819 Timothy R, Belgium + 820 clem + 825 JuanB, ES + 826 Randall Gaz, Colorado USA + 827 Dick van Ginkel, The Netherlands + 829 Jan-Pieter Van Impe + 831 David Kirkpatrick, AU + 832 Ravi Teja, India + 833 AkosLukacs, HU + 834 Dave Desson, CAN + 837 LWQ.CZ, CZ + 838 Robert W., Issaquah, WA + 839 Daniel Hrynczenko + 840 Martin Filtenborg, DK + 841 InnHuchen, Ger + 845 Raju Pillai,India + 847 cfus/DE +* 851 Juli H. + 853 David Monterroso Cabello , SP + 857 24x8, LLC, US + 860 Sebastian, DE + 861 pajusmar + 864 Ronnie, UK +* 867 Travis Travelstead, USA +* 870 Woodat, US/UK + 872 Gary Bake, UK + 873 Ernesto Martinez +* 874 Scottt, USA + 876 Ronnie Kizzle, LA + 880 Harish, Singapore + 882 Wacht, Pittsburgh + 883 PatrickF, US + 886 Paolo, IT + 888 Defragster + 889 Rachel Rayns, UK +* 890 Peak Data LLC + 891 Mindwarp, AU + 892 Vincent Smedley, UK +* 894 Bailey & Brayden + 898 Jacek Artymiak, UK + 900 John Hudson, USA +* 901 ReneS, NL +* 902 B Stevens + 903 Cptnslick, US + 904 janlj@me.com + 905 Fabricio Biazzotto + 906 Lenz Hirsch + 907 SerSher, RU + 908 Florian, DE + 909 Mathias Svendsen, DK +* 910 Jeremiah Dey-Oh + 911 Allan Joseph Medwick + 913 Matt, Australia + 914 Christian Pedersen +* 915 SPIN + 916 Denis M., Russia + 917 Ahmed Alboori, Saudi Arabia + 918 Luciano, Italy + 919 Ragdehl +* 921 Artur, HU + 922 Greg, NC - USA + 924 Gurzixo +* 927 Gregg, Oregon + 928 cwschroeder, BY + 929 W. Bush - NY, USA. + 932 ddparker + 933 Enkion +* 934 Eric G. Barron + 936 thomasDOTwtf + 940 mifous, cucurbitae.eu + 942 VFL68, FR + 943 Casey, Hong Kong +* 945 Kean Electronics + 946 Nima, UK + 947 Klosinski, USA + 948 PieWiE, NL +* 949 Rui Carmo, PT +* 950 basbrun.com + 951 Aashu, UK +* 952 vk2nq - Brian + 954 gojimmypi + 955 Jack, USA +* 957 @SteveBattle +* 958 Beshr, Sweden + 962 PeterR, UK + 964 Russell Calbert + 965 LAurent_B, Fr + 967 Qazi, USA + 971 Jonas, FR + 973 PK Shiu +* 974 sea_kev + 976 Radhika, USA + 977 Chris Gibson, US +* 978 Mike, AU +* 979 Geeky Pete + 981 Timmy the wonderdog + 983 An Ostler it IT + 984 Frank Ray Robles + 985 Kurtsik + 987 Johan, SE + 988 NJBerland, Norway + 992 Leon Noel - @leonnoel + 994 Kjell, SE + 995 boriskourt + 997 Bartek B., CANADA + 999 Thomas Wiradikusuma, Indonesia + 1000 Trey, NOLA + 1002 Jori, FI + 1005 nmmarkin + 1006 Mattias Fornander + 1007 Panayot Daskalov, Bulgaria +*1009 AndyP, UK + 1011 TSD + 1013 Chris, Berlin + 1017 Gareth Edwards, UK + 1018 Trixam,DE + 1019 César from Makespace Madrid, Spain + 1020 Prajwal, Australia +*1024 Fred Dart - FTDI + 1025 bsx +*1026 Regis, FR + 1027 Adrian Hill + 1029 Alice, UK + 1030 Erkan Shakir, BG + 1031 Alexander, EE + 1033 Patric, Luxembourg + 1034 For my beloved mother, Colleen Clancy. + 1035 NigelB + 1037 François, Aus/Fr +*1039 Thanura Siribaddana, Australia + 1041 Harald, USA + 1042 Jeremy Utting, NZ + 1043 bejuryu, KR +*1044 Daniel Wood, UK + 1046 C. J. Blocker +*1047 Rodrigo Benenson, Germany + 1048 HÃ¥vard Gulldahl + 1049 SeB, Belgium + 1054 Ryan Miller, Austin TX + 1055 Gianluca Cancelmi + 1057 Francesco, IT + 1058 RockTractor! + 1060 Bill G., Atlanta GA USA + 1061 joenotjoe + 1064 ATrivedi, USA + 1067 Jim Chandler, UK + 1068 Aria Sabeti + 1069 Noah Rosamilia, USA + 1070 GAKgDavid, CA + 1072 Markus, Austria +*1073 Tarwin, MUC +*1077 Balazs Kinszler, HU +*1080 pfh +*1082 Ovidiu Hossu, SG +*1083 mmhanif, NJ +*1084 Wincent Balin, DE +*1086 Anatoly Verkhovsky +*1087 Greg, Plano +*1089 Angelo Compagnucci + 1090 Ryan Shaw (ryannathans), AU + 1092 Dries007, BE +*1093 Dave Snowdon, UK +*1094 halfpress +*1096 DeuxVis, FR +*1097 Your Creative Solutions + 1099 Emanuele Goldoni, IT +*1100 Tendayi Mawushe + 1101 Rob, Tikitere +*1102 SolidStateSoul +*1103 Michael, GER +*1106 Paul, San Francisco +*1107 Oddvar Lovaas +*1108 Doc Savage, Man of Bronze + 1109 Stijn Debrouwere + 1111 Ark Nieckarz, USA +*1112 ECS87.com, USA +*1114 Gary P. Wolfe, USA + 1117 Tom Hodson +*1118 @arikb (twitter) + 1123 Piotr Gryko UK +*1125 Cantalaweb, Spain + 1126 Edward of Clovis + 1127 Jim G +*1128 billbr, Loveland, CO, USA + 1129 dalanmiller +*1130 StephenH, UK +*1132 Thomas Sarlandie - @sarfata + 1133 Doug Rohm, US +*1134 Eric Floehr, Ohio, USA +*1135 Sven Haiges + 1136 relix42 +*1137 Ralf Nyren +*1138 nickgb + 1139 zwack, DE + 1140 Michal B., PL + 1141 Matt, Australia + 1143 slv, Mi2 + 1144 Pawel, CH +*1145 James Saffery +*1147 nekomatic +*1149 @nt1, Earth +*1150 Alister Galpin, NZ + 1151 Jayemel, UK + 1152 Koalabs + 1153 James Myatt, UK +*1154 DanS, Norway + 1155 Sandeep, US +*1156 Anil Kavipurapu +*1158 Frederik Werner, DE + 1160 Erik J, Canada + 1164 bluezebra, Ireland + 1168 Birk, DE + 1169 Gabi, FR +*1173 mliberty, USA + 1174 Jamie Smith, Scotland + 1175 Sebastian, Germany +*1176 John Cooper, UK + 1177 Moritz, DE + 1178 Kevin, DE +*1179 Ming Leung, Canada + 1180 Laird Popkin + 1181 tasmaniac, GA +*1183 RichardW, UK +*1187 Thomas Quinlan, London, UK + 1188 LGnap, BE +*1189 bloater, Edinburgh UK + 1192 pakt, SE + 1194 Sandsmark, NO +*1195 Gert Menke + 1197 Emsi88, SK + 1199 GTtronics HK Ltd. + 1200 Jo, Bergen +*1202 MarkS, Australia + 1203 Igor, HR + 1204 Lord Nightmare + 1205 Great Uncle Bulgaria, UK +*1206 salomonderossi + 1208 Master_Ipse, DE + 1209 Luis G.F, ES + 1211 Harald, FO +*1212 Kimmo, Finland +*1213 P. Perreijn, Netherlands + 1214 jcea, Spain + 1215 simon holmes à court + 1217 Bill M, Newcastle +*1218 snowball +*1221 Georges, CDN + 1222 JPLa + 1225 Erik Gullberg, Sweden + 1226 Matthias Fuchs, IN, Germany + 1229 Majed, CA + 1230 Michiel, Reeuwijk + 1231 Clive, Essex UK + 1232 Jan Kalina, CZ + 1234 MBBest, Australia +*1235 Reinoud de Lange, NL + 1237 Jeffrey Park, South Korea + 1238 David Olson + 1239 Nathan Battan + 1240 Marcus, TW + 1241 randyrrt, USA + 1242 Holger, Germany + 1243 Dmitri Chapkine, FRANCE + 1244 Ceyhun Kapucu, TR + 1245 Hong Kong +*1246 gPozo, US + 1247 Peter M, Sweden +*1249 Duncan, Cambridge +*1251 Schaeferling, DE + 1252 Christian Prior, DE +*1256 ovig + 1257 Kerry Channing, UK + 1258 Exception42, GER +*1259 nchalikias + 1261 Kittie, US + 1263 Alex, Norway + 1264 wats0n, TW +*1265 Henner +*1266 Mike M, AZ, USA + 1268 Bobby Ly, USA +*1269 Espen STO, Norway + 1270 arduware.cc + 1274 Christopher Flynn, NH USA +*1275 Bruce Boyes, USA + 1276 DCH + 1278 McGinkel, Netherlands + 1279 Dieter, Wien + 1280 R. Tummers, NL + 1283 Pranav Maddula, USA + 1286 Dusan, SLovakia + 1290 Stephen Youndt +*1291 Lertsenem, FR + 1292 NuclearTide, London + 1293 Ben Gift, USA + 1294 rmg + 1295 jmaybe, USA + 1296 Allan G, Georgia + 1297 Duncan Brassington, UK + 1300 Hans, NL + 1301 Valerio "valdez" Paolini, IT + 1303 Neotreat, DE + 1306 tomtoump + 1307 Edward B Cox, England + 1310 Oliver Steele + 1311 merps, AUS + 1313 n8henrie, USA +*1314 YGA-KSD n7/ULB, FR-BE + 1317 Adrian, Romania +*1318 Luca "Loop", ITA +*1319 Michael Twomey, Ireland + 1321 Trey Aughenbaugh + 1322 Marcel Hecko, SK + 1323 Hugo Neira, CL + 1326 JH, US +*1330 Luthander, SE + 1331 Rickard Dahlstrand, Sweden + 1333 Olivier M., France + 1334 DWVL, UK + 1335 MRZANE, Sweden + 1336 Benedikt, DE +*1338 Tiegeng, US +*1339 arthoo Eindhoven Nederland + 1340 Magnus Gustavsson, Sweden + 1341 Jan Bednařík + 1344 Mike McGary: US + 1346 mp3tobi +*1350 Cyberhippy + 1351 Sandro, PT + 1355 Kwabena W. Agyeman + 1357 Ryan Young +*1358 Chiang Mai, Thailand + 1359 AKLitman, USA + 1360 JASK Enterprises, Ltd-John +*1361 Tom Gidden, UK + 1362 AdamT, USA + 1363 Jose de la Campa, BOL + 1365 Steve Laguna, U.S.A +*1368 Walrusklasse, NL + 1370 Timofei Korostelev, Belarus + 1374 Janos,HU +*1375 Paul Cunnane + 1377 IanE, UK + 1378 Hans, NL + 1379 Jose Angel Jimenez Vadillo, Spain +*1380 PaulT, Lancs + 1383 Lutz; DE + 1385 AnRkey + 1387 Fredrik, FIN + 1388 Matt W (funkyHat) + 1389 Zeev Rotshtein, Israel + 1391 joostd, NL + 1392 Lukasz Blaszczyk, USA +*1397 Wei-Ning Huang, TW + 1398 myu +*1399 Thorsten, Germany + 1401 sm0ihr + 1403 Xiaotian, Seattle US +*1406 -gt-, Czech Republic + 1407 Mike Y. Diallo, US + 1409 ubii, US diff --git a/src/openmv/src/micropython/CODECONVENTIONS.md b/src/openmv/src/micropython/CODECONVENTIONS.md new file mode 100755 index 0000000..982b958 --- /dev/null +++ b/src/openmv/src/micropython/CODECONVENTIONS.md @@ -0,0 +1,210 @@ +Git commit conventions +====================== + +Each commit message should start with a directory or full file path +prefix, so it was clear which part of codebase a commit affects. If +a change affects one file, it's better to use path to a file. If it +affects few files in a subdirectory, using subdirectory as a prefix +is ok. For longish paths, it's acceptable to drop intermediate +components, which still should provide good context of a change. +It's also ok to drop file extensions. + +Besides prefix, first line of a commit message should describe a +change clearly and to the point, and be a grammatical sentence with +final full stop. First line should fit within 78 characters. Examples +of good first line of commit messages: + + py/objstr: Add splitlines() method. + py: Rename FOO to BAR. + docs/machine: Fix typo in reset() description. + ports: Switch to use lib/foo instead of duplicated code. + +After the first line, add an empty line and in following lines describe +a change in a detail, if needed. Any change beyond 5 lines would likely +require such detailed description. + +To get good practical examples of good commits and their messages, browse +the `git log` of the project. + +MicroPython doesn't require explicit sign-off for patches ("Signed-off-by" +lines and similar). Instead, the commit message, and your name and email +address on it construes your sign-off of the following: + +* That you wrote the change yourself, or took it from a project with + a compatible license (in the latter case the commit message, and possibly + source code should provide reference where the implementation was taken + from and give credit to the original author, as required by the license). +* That you are allowed to release these changes to an open-source project + (for example, changes done during paid work for a third party may require + explicit approval from that third party). +* That you (or your employer) agree to release the changes under + MicroPython's license, which is the MIT license. Note that you retain + copyright for your changes (for smaller changes, the commit message + conveys your copyright; if you make significant changes to a particular + source module, you're welcome to add your name to the file header). +* Your signature for all of the above, which is the 'Author' line in + the commit message, and which should include your full real name and + a valid and active email address by which you can be contacted in the + foreseeable future. + +Python code conventions +======================= + +Python code follows [PEP 8](http://legacy.python.org/dev/peps/pep-0008/). + +Naming conventions: +- Module names are short and all lowercase; eg pyb, stm. +- Class names are CamelCase, with abreviations all uppercase; eg I2C, not + I2c. +- Function and method names are all lowercase with words separated by + a single underscore as necessary to improve readability; eg mem_read. +- Constants are all uppercase with words separated by a single underscore; + eg GPIO_IDR. + +C code conventions +================== + +When writing new C code, please adhere to the following conventions. + +White space: +- Expand tabs to 4 spaces. +- Don't leave trailing whitespace at the end of a line. +- For control blocks (if, for, while), put 1 space between the + keyword and the opening parenthesis. +- Put 1 space after a comma, and 1 space around operators. + +Braces: +- Use braces for all blocks, even no-line and single-line pieces of + code. +- Put opening braces on the end of the line it belongs to, not on + a new line. +- For else-statements, put the else on the same line as the previous + closing brace. + +Header files: +- Header files should be protected from multiple inclusion with #if + directives. See an existing header for naming convention. + +Names: +- Use underscore_case, not camelCase for all names. +- Use CAPS_WITH_UNDERSCORE for enums and macros. +- When defining a type use underscore_case and put '_t' after it. + +Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's +important to use the correctly-sized (and signed) integer types. The +general guidelines are: +- For most cases use mp_int_t for signed and mp_uint_t for unsigned + integer values. These are guaranteed to be machine-word sized and + therefore big enough to hold the value from a MicroPython small-int + object. +- Use size_t for things that count bytes / sizes of objects. +- You can use int/uint, but remember that they may be 16-bits wide. +- If in doubt, use mp_int_t/mp_uint_t. + +Comments: +- Be concise and only write comments for things that are not obvious. +- Use `// ` prefix, NOT `/* ... */`. No extra fluff. + +Memory allocation: +- Use m_new, m_renew, m_del (and friends) to allocate and free heap memory. + These macros are defined in py/misc.h. + +Examples +-------- + +Braces, spaces, names and comments: + + #define TO_ADD (123) + + // This function will always recurse indefinitely and is only used to show + // coding style + int foo_function(int x, int some_value) { + if (x < some_value) { + foo(some_value, x); + } else { + foo(x + TO_ADD, some_value - 1); + } + + for (int my_counter = 0; my_counter < x; my_counter++) { + } + } + +Type declarations: + + typedef struct _my_struct_t { + int member; + void *data; + } my_struct_t; + +Documentation conventions +========================= + +MicroPython generally follows CPython in documentation process and +conventions. reStructuredText syntax is used for the documention. + +Specific conventions/suggestions: + +* Use `*` markup to refer to arguments of a function, e.g.: + +``` +.. method:: poll.unregister(obj) + + Unregister *obj* from polling. +``` + +* Use following syntax for cross-references/cross-links: + +``` +:func:`foo` - function foo in current module +:func:`module1.foo` - function foo in module "module1" + (similarly for other referent types) +:class:`Foo` - class Foo +:meth:`Class.method1` - method1 in Class +:meth:`~Class.method1` - method1 in Class, but rendered just as "method1()", + not "Class.method1()" +:meth:`title ` - reference method1, but render as "title" (use only + if really needed) +:mod:`module1` - module module1 + +`symbol` - generic xref syntax which can replace any of the above in case + the xref is unambiguous. If there's ambiguity, there will be a warning + during docs generation, which need to be fixed using one of the syntaxes + above +``` + +* Cross-referencing arbitrary locations +~~~ +.. _xref_target: + +Normal non-indented text. + +This is :ref:`reference `. + +(If xref target is followed by section title, can be just +:ref:`xref_target`). +~~~ + +* Linking to external URL: +``` +`link text `_ +``` + +* Referencing builtin singleton objects: +``` +``None``, ``True``, ``False`` +``` + +* Use following syntax to create common description for more than one element: +~~~ +.. function:: foo(x) + bar(y) + + Description common to foo() and bar(). +~~~ + + +More detailed guides and quickrefs: + +* http://www.sphinx-doc.org/en/stable/rest.html +* http://www.sphinx-doc.org/en/stable/markup/inline.html +* http://docutils.sourceforge.net/docs/user/rst/quickref.html diff --git a/src/openmv/src/micropython/CONTRIBUTING.md b/src/openmv/src/micropython/CONTRIBUTING.md new file mode 100755 index 0000000..06f9706 --- /dev/null +++ b/src/openmv/src/micropython/CONTRIBUTING.md @@ -0,0 +1,8 @@ +When reporting an issue and especially submitting a pull request, please +make sure that you are acquainted with Contributor Guidelines: + +https://github.com/micropython/micropython/wiki/ContributorGuidelines + +and Code Conventions: + +https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md diff --git a/src/openmv/src/micropython/LICENSE b/src/openmv/src/micropython/LICENSE new file mode 100755 index 0000000..e3474e3 --- /dev/null +++ b/src/openmv/src/micropython/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013, 2014 Damien P. George + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/openmv/src/micropython/README.md b/src/openmv/src/micropython/README.md new file mode 100755 index 0000000..a4ddacf --- /dev/null +++ b/src/openmv/src/micropython/README.md @@ -0,0 +1,76 @@ +Micropython based on the Sipeed Maix one platform +=============================================== + +

+ Sipeed Maix one +

+ +This micropython based on the Sipeed Maix one platform + +This version of micropython is Python 3.4, based on the K210-standalone-sdk. + +The main structure of the micropython directory is as follows: + +- py/ -- a core Python implementation that includes the compiler, runtime, and core libraries. +- mpy-cross/ -- the MicroPython cross-compiler which is used to turn scripts into precompiled bytecode. +- ports/k210-standalone/ -- micropython porting code based on k210 platform sdk +- tests/ -- test framework and test scripts +- docs/ -- user documentation in Sphinx reStructuredText format. Rendered HTML documentation is available at http://docs.micropython.org (be sure to select needed board/port at the bottom left corner). + +Platform porting code directory architecture: + +- board-drivers/ store the onboard module driver code +- buildin-py/ firmware built-in microPython script +- mpy-mod/ micropython module code +- spiffs/ spiffs file system source code +- spiffs-port/ spiffs porting configuration code +- kendryte-standalone-sdk/ k210 sdk generated after using the build script + +Sipeed Maix one-micropython build and compile +-------------------------------------------- + +Build code: + +$ git clone xxxx Download sdk +$ cd port/k210-standalon/ Enter the platform code directory +$ make build build platform code in case of first use + +Compile the code: + +$ make CROSS_COMPILE=/your_compiler_path + + +`your_compiler_path` is the compiler path, about the compiler , you can see http://dan.lichee.pro/ + +After compiling, the micropython.bin file will be generated in this directory, and you can burne it to the Sipeed Maix One suite. The burning method can be found at http://dan.lichee.pro/ + +contribution +------------ + +MicroPython is an open-source project and welcomes contributions. To be productive, please be sure to follow the [Contributors' Guidelines](https://github.com/micropython/micropython/wiki/ContributorGuidelines) and the [Code Conventions] https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md). Note that MicroPython is licenced under the MIT license, and all contributions should follow this license. + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/README_CN.md b/src/openmv/src/micropython/README_CN.md new file mode 100755 index 0000000..7cfed43 --- /dev/null +++ b/src/openmv/src/micropython/README_CN.md @@ -0,0 +1,50 @@ +基于Sipeed Maix oneå¹³å°çš„micropython +====================================== +

+ Sipeed Maix one +

+ +基于Sipeed Maix oneå¹³å°çš„micropython + +该版本的micropython为 Python 3.4,基于K210裸机sdk编写. + +micropython的目录主è¦æž¶æž„如下: + +- py/ -- 核心Python实现,包括编译器,è¿è¡Œæ—¶å’Œæ ¸å¿ƒåº“。 +- mpy-cross/ -- MicroPython交å‰ç¼–译器,用于将脚本转æ¢ä¸ºé¢„编译的字节ç ã€‚ +- ports/k210-standalone/ -- 基于k210å¹³å°sdkçš„micropython移æ¤ä»£ç  +- tests/ -- 测试框架åŠæµ‹è¯•è„šæœ¬ +- docs/ -- 基于rstæ ¼å¼çš„micropython用户文档,HTML文档的链接 http://docs.micropython.org + +å¹³å°ç§»æ¤ä»£ç ç›®å½•æž¶æž„: + +- board-drivers/ 存放æ¿è½½æ¨¡å—é©±åŠ¨ä»£ç  +- buildin-py/ 固件内置microPython脚本 +- mpy-mod/ micropython模å—ä»£ç  +- spiffs/ spiffs文件系统æºç  +- spiffs-port/ spiffs移æ¤é…ç½®ä»£ç  +- kendryte-standalone-sdk/ 在使用构建脚本åŽç”Ÿæˆçš„k210 sdk + +Sipeed Maix one-micropython构建åŠç¼–译 +-------------------------------------------- + +构建代ç : + + $ git clone xxxx 下载sdk + $ cd port/k210-standalon/ 进入平å°ä»£ç ç›®å½• + $ make build 在第一次使用的情况下,构建平å°ä»£ç  + +编译代ç : + + $ make CROSS_COMPILE=/your_compiler_path + + +`your_compiler_path`为编译器路径,编译器å¯ä»¥æŸ¥çœ‹http://dan.lichee.pro/ 了解 + +编译完æˆå°†åœ¨è¯¥ç›®å½•ä¸‹ç”Ÿæˆmicropython.bin文件,将该文件烧录到Sipeed Maix One套件å³å¯,烧录方法å¯ä»¥æŸ¥çœ‹http://dan.lichee.pro/ 了解 + + +贡献 +------------ + +MicroPython是一个开æºé¡¹ç›®ï¼Œæ¬¢è¿Žè´¡çŒ®ï¼ŒMicroPython是根æ®MIT许å¯è¯èŽ·å¾—许å¯çš„,所有贡献都应éµå¾ªæ­¤è®¸å¯è¯ã€‚ \ No newline at end of file diff --git a/src/openmv/src/micropython/docs/Makefile b/src/openmv/src/micropython/docs/Makefile new file mode 100755 index 0000000..e9c128e --- /dev/null +++ b/src/openmv/src/micropython/docs/Makefile @@ -0,0 +1,191 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +PYTHON = python3 +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build/$(MICROPY_PORT) +CPYDIFFDIR = ../tools +CPYDIFF = gen-cpydiff.py +GENRSTDIR = genrst +# Run "make FORCE= ..." to avoid rebuilding from scratch (and risk +# producing incorrect docs). +FORCE = -E + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " cpydiff to generate the MicroPython differences from CPython" + +clean: + rm -rf $(BUILDDIR)/* + rm -f $(GENRSTDIR)/* + +cpydiff: + @echo "Generating MicroPython Differences." + rm -f $(GENRSTDIR)/* + cd $(CPYDIFFDIR) && $(PYTHON) $(CPYDIFF) + +html: cpydiff + $(SPHINXBUILD) $(FORCE) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/MicroPython.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/MicroPython.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/MicroPython" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/MicroPython" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: cpydiff + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: cpydiff + $(SPHINXBUILD) $(FORCE) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: cpydiff + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/src/openmv/src/micropython/docs/README.md b/src/openmv/src/micropython/docs/README.md new file mode 100755 index 0000000..faf3867 --- /dev/null +++ b/src/openmv/src/micropython/docs/README.md @@ -0,0 +1,40 @@ +MicroPython Documentation +========================= + +The MicroPython documentation can be found at: +http://docs.micropython.org/en/latest/ + +The documentation you see there is generated from the files in the docs tree: +https://github.com/micropython/micropython/tree/master/docs + +Building the documentation locally +---------------------------------- + +If you're making changes to the documentation, you may want to build the +documentation locally so that you can preview your changes. + +Install Sphinx, and optionally (for the RTD-styling), sphinx_rtd_theme, +preferably in a virtualenv: + + pip install sphinx + pip install sphinx_rtd_theme + +In `micropython/docs`, build the docs: + + make MICROPY_PORT= html + +Where `` can be `unix`, `pyboard`, `wipy` or `esp8266`. + +You'll find the index page at `micropython/docs/build//html/index.html`. + +PDF manual generation +--------------------- + +This can be achieved with: + + make MICROPY_PORT= latexpdf + +but require rather complete install of LaTeX with various extensions. On +Debian/Ubuntu, try (500MB+ download): + + apt-get install texlive-latex-recommended texlive-latex-extra diff --git a/src/openmv/src/micropython/docs/conf.py b/src/openmv/src/micropython/docs/conf.py new file mode 100755 index 0000000..cd1f065 --- /dev/null +++ b/src/openmv/src/micropython/docs/conf.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# MicroPython documentation build configuration file, created by +# sphinx-quickstart on Sun Sep 21 11:42:03 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('.')) + +# The members of the html_context dict are available inside topindex.html +micropy_version = os.getenv('MICROPY_VERSION') or 'latest' +micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',') +url_pattern = '%s/en/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',) +html_context = { + 'cur_version':micropy_version, + 'all_versions':[ + (ver, url_pattern % ver) for ver in micropy_all_versions + ], + 'downloads':[ + ('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'), + ], +} + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'MicroPython' +copyright = '2014-2018, Damien P. George, Paul Sokolovsky, and contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" +# breakdown, so use the same version identifier for both to avoid confusion. +version = release = '1.9.4' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['build', '.venv'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = 'any' + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# Global include files. Sphinx docs suggest using rst_epilog in preference +# of rst_prolog, so we follow. Absolute paths below mean "from the base +# of the doctree". +rst_epilog = """ +.. include:: /templates/replace.inc +""" + +# -- Options for HTML output ---------------------------------------------- + +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + except: + html_theme = 'default' + html_theme_path = ['.'] +else: + html_theme_path = ['.'] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = ['.'] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = '../../logo/trans-logo.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = 'favicon.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%d %b %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = {"index": "topindex.html"} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'MicroPythondoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +# Include 3 levels of headers in PDF ToC +'preamble': '\setcounter{tocdepth}{2}', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'MicroPython.tex', 'MicroPython Documentation', + 'Damien P. George, Paul Sokolovsky, and contributors', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'micropython', 'MicroPython Documentation', + ['Damien P. George, Paul Sokolovsky, and contributors'], 1), +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'MicroPython', 'MicroPython Documentation', + 'Damien P. George, Paul Sokolovsky, and contributors', 'MicroPython', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None)} diff --git a/src/openmv/src/micropython/docs/differences/index_template.txt b/src/openmv/src/micropython/docs/differences/index_template.txt new file mode 100755 index 0000000..eb8b3ba --- /dev/null +++ b/src/openmv/src/micropython/docs/differences/index_template.txt @@ -0,0 +1,10 @@ +.. _cpython_diffs: + +MicroPython differences from CPython +==================================== + +The operations listed in this section produce conflicting results in MicroPython when compared to standard Python. + +.. toctree:: + :maxdepth: 2 + diff --git a/src/openmv/src/micropython/docs/esp8266/general.rst b/src/openmv/src/micropython/docs/esp8266/general.rst new file mode 100755 index 0000000..020e21d --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/general.rst @@ -0,0 +1,197 @@ +.. _esp8266_general: + +General information about the ESP8266 port +========================================== + +ESP8266 is a popular WiFi-enabled System-on-Chip (SoC) by Espressif Systems. + +Multitude of boards +------------------- + +There is a multitude of modules and boards from different sources which carry +the ESP8266 chip. MicroPython tries to provide a generic port which would run on +as many boards/modules as possible, but there may be limitations. Adafruit +Feather HUZZAH board is taken as a reference board for the port (for example, +testing is performed on it). If you have another board, please make sure you +have a datasheet, schematics and other reference materials for your board +handy to look up various aspects of your board functioning. + +To make a generic ESP8266 port and support as many boards as possible, +the following design and implementation decision were made: + +* GPIO pin numbering is based on ESP8266 chip numbering, not some "logical" + numbering of a particular board. Please have the manual/pin diagram of your board + at hand to find correspondence between your board pins and actual ESP8266 pins. + We also encourage users of various boards to share this mapping via MicroPython + forum, with the idea to collect community-maintained reference materials + eventually. +* All pins which make sense to support, are supported by MicroPython + (for example, pins which are used to connect SPI flash + are not exposed, as they're unlikely useful for anything else, and + operating on them will lead to board lock-up). However, any particular + board may expose only subset of pins. Consult your board reference manual. +* Some boards may lack external pins/internal connectivity to support + ESP8266 deepsleep mode. + + +Technical specifications and SoC datasheets +------------------------------------------- + +The datasheets and other reference material for ESP8266 chip are available +from the vendor site: http://bbs.espressif.com/viewtopic.php?f=67&t=225 . +They are the primary reference for the chip technical specifications, capabilities, +operating modes, internal functioning, etc. + +For your convenience, some of technical specifications are provided below: + +* Architecture: Xtensa lx106 +* CPU frequency: 80MHz overclockable to 160MHz +* Total RAM available: 96KB (part of it reserved for system) +* BootROM: 64KB +* Internal FlashROM: None +* External FlashROM: code and data, via SPI Flash. Normal sizes 512KB-4MB. +* GPIO: 16 + 1 (GPIOs are multiplexed with other functions, including + external FlashROM, UART, deep sleep wake-up, etc.) +* UART: One RX/TX UART (no hardware handshaking), one TX-only UART. +* SPI: 2 SPI interfaces (one used for FlashROM). +* I2C: No native external I2C (bitbang implementation available on any pins). +* I2S: 1. +* Programming: using BootROM bootloader from UART. Due to external FlashROM + and always-available BootROM bootloader, ESP8266 is not brickable. + + +Scarcity of runtime resources +----------------------------- + +ESP8266 has very modest resources (first of all, RAM memory). So, please +avoid allocating too big container objects (lists, dictionaries) and +buffers. There is also no full-fledged OS to keep track of resources +and automatically clean them up, so that's the task of a user/user +application: please be sure to close open files, sockets, etc. as soon +as possible after use. + + +Boot process +------------ + +On boot, MicroPython EPS8266 port executes ``_boot.py`` script from internal +frozen modules. It mounts filesystem in FlashROM, or if it's not available, +performs first-time setup of the module and creates the filesystem. This +part of the boot process is considered fixed, and not available for customization +for end users (even if you build from source, please refrain from changes to +it; customization of early boot process is available only to advanced users +and developers, who can diagnose themselves any issues arising from +modifying the standard process). + +Once the filesystem is mounted, ``boot.py`` is executed from it. The standard +version of this file is created during first-time module set up and has +commands to start a WebREPL daemon (disabled by default, configurable +with ``webrepl_setup`` module), etc. This +file is customizable by end users (for example, you may want to set some +parameters or add other services which should be run on +a module start-up). But keep in mind that incorrect modifications to boot.py +may still lead to boot loops or lock ups, requiring to reflash a module +from scratch. (In particular, it's recommended that you use either +``webrepl_setup`` module or manual editing to configure WebREPL, but not +both). + +As a final step of boot procedure, ``main.py`` is executed from filesystem, +if exists. This file is a hook to start up a user application each time +on boot (instead of going to REPL). For small test applications, you may +name them directly as ``main.py``, and upload to module, but instead it's +recommended to keep your application(s) in separate files, and have just +the following in ``main.py``:: + + import my_app + my_app.main() + +This will allow to keep the structure of your application clear, as well as +allow to install multiple applications on a board, and switch among them. + + +Known Issues +------------ + +Real-time clock +~~~~~~~~~~~~~~~ + +RTC in ESP8266 has very bad accuracy, drift may be seconds per minute. As +a workaround, to measure short enough intervals you can use +``utime.time()``, etc. functions, and for wall clock time, synchronize from +the net using included ``ntptime.py`` module. + +Due to limitations of the ESP8266 chip the internal real-time clock (RTC) +will overflow every 7:45h. If a long-term working RTC time is required then +``time()`` or ``localtime()`` must be called at least once within 7 hours. +MicroPython will then handle the overflow. + +Sockets and WiFi buffers overflow +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Socket instances remain active until they are explicitly closed. This has two +consequences. Firstly they occupy RAM, so an application which opens sockets +without closing them may eventually run out of memory. Secondly not properly +closed socket can cause the low-level part of the vendor WiFi stack to emit +``Lmac`` errors. This occurs if data comes in for a socket and is not +processed in a timely manner. This can overflow the WiFi stack input queue +and lead to a deadlock. The only recovery is by a hard reset. + +The above may also happen after an application terminates and quits to the REPL +for any reason including an exception. Subsequent arrival of data provokes the +failure with the above error message repeatedly issued. So, sockets should be +closed in any case, regardless whether an application terminates successfully +or by an exeption, for example using try/finally:: + + sock = socket(...) + try: + # Use sock + finally: + sock.close() + + +SSL/TLS limitations +~~~~~~~~~~~~~~~~~~~ + +ESP8266 uses `axTLS `_ library, which is one +of the smallest TLS libraries with the compatible licensing. However, it +also has some known issues/limitations: + +1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve + cryptography (ECC). This means it can't work with sites which force + the use of these features (it works ok with classic RSA certificates). +2. Half-duplex communication nature. axTLS uses a single buffer for both + sending and receiving, which leads to considerable memory saving and + works well with protocols like HTTP. But there may be problems with + protocols which don't follow classic request-response model. + +Besides axTLS own limitations, the configuration used for MicroPython is +highly optimized for code size, which leads to additional limitations +(these may be lifted in the future): + +3. Optimized RSA algorithms are not enabled, which may lead to slow + SSL handshakes. +4. Stored sessions are not supported (may allow faster repeated connections + to the same site in some circumstances). + +Besides axTLS specific limitations described above, there's another generic +limitation with usage of TLS on the low-memory devices: + +5. The TLS standard specifies the maximum length of the TLS record (unit + of TLS communication, the entire record must be buffered before it can + be processed) as 16KB. That's almost half of the available ESP8266 memory, + and inside a more or less advanced application would be hard to allocate + due to memory fragmentation issues. As a compromise, a smaller buffer is + used, with the idea that the most interesting usage for SSL would be + accessing various REST APIs, which usually require much smaller messages. + The buffers size is on the order of 5KB, and is adjusted from time to + time, taking as a reference being able to access https://google.com . + The smaller buffer hower means that some sites can't be accessed using + it, and it's not possible to stream large amounts of data. + +There are also some not implemented features specifically in MicroPython's +``ussl`` module based on axTLS: + +6. Certificates are not validated (this may make connections susceptible + to man-in-the-middle attacks). +7. There is no support for client certificates (scheduled to be fixed in + 1.9.4 release). diff --git a/src/openmv/src/micropython/docs/esp8266/img/adafruit_products_pinoutstop.jpg b/src/openmv/src/micropython/docs/esp8266/img/adafruit_products_pinoutstop.jpg new file mode 100755 index 0000000..655e27a Binary files /dev/null and b/src/openmv/src/micropython/docs/esp8266/img/adafruit_products_pinoutstop.jpg differ diff --git a/src/openmv/src/micropython/docs/esp8266/quickref.rst b/src/openmv/src/micropython/docs/esp8266/quickref.rst new file mode 100755 index 0000000..95ae55b --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/quickref.rst @@ -0,0 +1,384 @@ +.. _esp8266_quickref: + +Quick reference for the ESP8266 +=============================== + +.. image:: img/adafruit_products_pinoutstop.jpg + :alt: Adafruit Feather HUZZAH board + :width: 640px + +The Adafruit Feather HUZZAH board (image attribution: Adafruit). + +Below is a quick reference for ESP8266-based boards. If it is your first time +working with this board please consider reading the following sections first: + +.. toctree:: + :maxdepth: 1 + + general.rst + tutorial/index.rst + +Installing MicroPython +---------------------- + +See the corresponding section of tutorial: :ref:`intro`. It also includes +a troubleshooting subsection. + +General board control +--------------------- + +The MicroPython REPL is on UART0 (GPIO1=TX, GPIO3=RX) at baudrate 115200. +Tab-completion is useful to find out what methods an object has. +Paste mode (ctrl-E) is useful to paste a large slab of Python code into +the REPL. + +The :mod:`machine` module:: + + import machine + + machine.freq() # get the current frequency of the CPU + machine.freq(160000000) # set the CPU frequency to 160 MHz + +The :mod:`esp` module:: + + import esp + + esp.osdebug(None) # turn off vendor O/S debugging messages + esp.osdebug(0) # redirect vendor O/S debugging messages to UART(0) + +Networking +---------- + +The :mod:`network` module:: + + import network + + wlan = network.WLAN(network.STA_IF) # create station interface + wlan.active(True) # activate the interface + wlan.scan() # scan for access points + wlan.isconnected() # check if the station is connected to an AP + wlan.connect('essid', 'password') # connect to an AP + wlan.config('mac') # get the interface's MAC adddress + wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + + ap = network.WLAN(network.AP_IF) # create access-point interface + ap.active(True) # activate the interface + ap.config(essid='ESP-AP') # set the ESSID of the access point + +A useful function for connecting to your local WiFi network is:: + + def do_connect(): + import network + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + if not wlan.isconnected(): + print('connecting to network...') + wlan.connect('essid', 'password') + while not wlan.isconnected(): + pass + print('network config:', wlan.ifconfig()) + +Once the network is established the :mod:`socket ` module can be used +to create and use TCP/UDP sockets as usual. + +Delay and timing +---------------- + +Use the :mod:`time ` module:: + + import time + + time.sleep(1) # sleep for 1 second + time.sleep_ms(500) # sleep for 500 milliseconds + time.sleep_us(10) # sleep for 10 microseconds + start = time.ticks_ms() # get millisecond counter + delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference + +Timers +------ + +Virtual (RTOS-based) timers are supported. Use the :ref:`machine.Timer ` class +with timer ID of -1:: + + from machine import Timer + + tim = Timer(-1) + tim.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1)) + tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2)) + +The period is in milliseconds. + +Pins and GPIO +------------- + +Use the :ref:`machine.Pin ` class:: + + from machine import Pin + + p0 = Pin(0, Pin.OUT) # create output pin on GPIO0 + p0.on() # set pin to "on" (high) level + p0.off() # set pin to "off" (low) level + p0.value(1) # set pin to on/high + + p2 = Pin(2, Pin.IN) # create input pin on GPIO2 + print(p2.value()) # get value, 0 or 1 + + p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor + p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation + +Available pins are: 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, which correspond +to the actual GPIO pin numbers of ESP8266 chip. Note that many end-user +boards use their own adhoc pin numbering (marked e.g. D0, D1, ...). As +MicroPython supports different boards and modules, physical pin numbering +was chosen as the lowest common denominator. For mapping between board +logical pins and physical chip pins, consult your board documentation. + +Note that Pin(1) and Pin(3) are REPL UART TX and RX respectively. +Also note that Pin(16) is a special pin (used for wakeup from deepsleep +mode) and may be not available for use with higher-level classes like +``Neopixel``. + +PWM (pulse width modulation) +---------------------------- + +PWM can be enabled on all pins except Pin(16). There is a single frequency +for all channels, with range between 1 and 1000 (measured in Hz). The duty +cycle is between 0 and 1023 inclusive. + +Use the ``machine.PWM`` class:: + + from machine import Pin, PWM + + pwm0 = PWM(Pin(0)) # create PWM object from a pin + pwm0.freq() # get current frequency + pwm0.freq(1000) # set frequency + pwm0.duty() # get current duty cycle + pwm0.duty(200) # set duty cycle + pwm0.deinit() # turn off PWM on the pin + + pwm2 = PWM(Pin(2), freq=500, duty=512) # create and configure in one go + +ADC (analog to digital conversion) +---------------------------------- + +ADC is available on a dedicated pin. +Note that input voltages on the ADC pin must be between 0v and 1.0v. + +Use the :ref:`machine.ADC ` class:: + + from machine import ADC + + adc = ADC(0) # create ADC object on ADC pin + adc.read() # read value, 0-1024 + +Software SPI bus +---------------- + +There are two SPI drivers. One is implemented in software (bit-banging) +and works on all pins, and is accessed via the :ref:`machine.SPI ` +class:: + + from machine import Pin, SPI + + # construct an SPI bus on the given pins + # polarity is the idle state of SCK + # phase=0 means sample on the first edge of SCK, phase=1 means the second + spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) + + spi.init(baudrate=200000) # set the baudrate + + spi.read(10) # read 10 bytes on MISO + spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI + + buf = bytearray(50) # create a buffer + spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case) + spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI + + spi.write(b'12345') # write 5 bytes on MOSI + + buf = bytearray(4) # create a buffer + spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer + spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf + + +Hardware SPI bus +---------------- + +The hardware SPI is faster (up to 80Mhz), but only works on following pins: +``MISO`` is GPIO12, ``MOSI`` is GPIO13, and ``SCK`` is GPIO14. It has the same +methods as the bitbanging SPI class above, except for the pin parameters for the +constructor and init (as those are fixed):: + + from machine import Pin, SPI + + hspi = SPI(1, baudrate=80000000, polarity=0, phase=0) + +(``SPI(0)`` is used for FlashROM and not available to users.) + +I2C bus +------- + +The I2C driver is implemented in software and works on all pins, +and is accessed via the :ref:`machine.I2C ` class:: + + from machine import Pin, I2C + + # construct an I2C bus + i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000) + + i2c.readfrom(0x3a, 4) # read 4 bytes from slave device with address 0x3a + i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a + + buf = bytearray(10) # create a buffer with 10 bytes + i2c.writeto(0x3a, buf) # write the given buffer to the slave + +Real time clock (RTC) +--------------------- + +See :ref:`machine.RTC ` :: + + from machine import RTC + + rtc = RTC() + rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime() # get date and time + +Deep-sleep mode +--------------- + +Connect GPIO16 to the reset pin (RST on HUZZAH). Then the following code +can be used to sleep, wake and check the reset cause:: + + import machine + + # configure RTC.ALARM0 to be able to wake the device + rtc = machine.RTC() + rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) + + # check if the device woke from a deep sleep + if machine.reset_cause() == machine.DEEPSLEEP_RESET: + print('woke from a deep sleep') + + # set RTC.ALARM0 to fire after 10 seconds (waking the device) + rtc.alarm(rtc.ALARM0, 10000) + + # put the device to sleep + machine.deepsleep() + +OneWire driver +-------------- + +The OneWire driver is implemented in software and works on all pins:: + + from machine import Pin + import onewire + + ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12 + ow.scan() # return a list of devices on the bus + ow.reset() # reset the bus + ow.readbyte() # read a byte + ow.writebyte(0x12) # write a byte on the bus + ow.write('123') # write bytes on the bus + ow.select_rom(b'12345678') # select a specific device by its ROM code + +There is a specific driver for DS18S20 and DS18B20 devices:: + + import time, ds18x20 + ds = ds18x20.DS18X20(ow) + roms = ds.scan() + ds.convert_temp() + time.sleep_ms(750) + for rom in roms: + print(ds.read_temp(rom)) + +Be sure to put a 4.7k pull-up resistor on the data line. Note that +the ``convert_temp()`` method must be called each time you want to +sample the temperature. + +NeoPixel driver +--------------- + +Use the ``neopixel`` module:: + + from machine import Pin + from neopixel import NeoPixel + + pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels + np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels + np[0] = (255, 255, 255) # set the first pixel to white + np.write() # write data to all pixels + r, g, b = np[0] # get first pixel colour + +For low-level driving of a NeoPixel:: + + import esp + esp.neopixel_write(pin, grb_buf, is800khz) + +APA102 driver +------------- + +Use the ``apa102`` module:: + + from machine import Pin + from apa102 import APA102 + + clock = Pin(14, Pin.OUT) # set GPIO14 to output to drive the clock + data = Pin(13, Pin.OUT) # set GPIO13 to output to drive the data + apa = APA102(clock, data, 8) # create APA102 driver on the clock and the data pin for 8 pixels + apa[0] = (255, 255, 255, 31) # set the first pixel to white with a maximum brightness of 31 + apa.write() # write data to all pixels + r, g, b, brightness = apa[0] # get first pixel colour + +For low-level driving of an APA102:: + + import esp + esp.apa102_write(clock_pin, data_pin, rgbi_buf) + +DHT driver +---------- + +The DHT driver is implemented in software and works on all pins:: + + import dht + import machine + + d = dht.DHT11(machine.Pin(4)) + d.measure() + d.temperature() # eg. 23 (°C) + d.humidity() # eg. 41 (% RH) + + d = dht.DHT22(machine.Pin(4)) + d.measure() + d.temperature() # eg. 23.6 (°C) + d.humidity() # eg. 41.3 (% RH) + +WebREPL (web browser interactive prompt) +---------------------------------------- + +WebREPL (REPL over WebSockets, accessible via a web browser) is an +experimental feature available in ESP8266 port. Download web client +from https://github.com/micropython/webrepl (hosted version available +at http://micropython.org/webrepl), and configure it by executing:: + + import webrepl_setup + +and following on-screen instructions. After reboot, it will be available +for connection. If you disabled automatic start-up on boot, you may +run configured daemon on demand using:: + + import webrepl + webrepl.start() + +The supported way to use WebREPL is by connecting to ESP8266 access point, +but the daemon is also started on STA interface if it is active, so if your +router is set up and works correctly, you may also use WebREPL while connected +to your normal Internet access point (use the ESP8266 AP connection method +if you face any issues). + +Besides terminal/command prompt access, WebREPL also has provision for file +transfer (both upload and download). Web client has buttons for the +corresponding functions, or you can use command-line client ``webrepl_cli.py`` +from the repository above. + +See the MicroPython forum for other community-supported alternatives +to transfer files to ESP8266. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/adc.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/adc.rst new file mode 100755 index 0000000..fa6fdab --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/adc.rst @@ -0,0 +1,19 @@ +Analog to Digital Conversion +============================ + +The ESP8266 has a single pin (separate to the GPIO pins) which can be used to +read analog voltages and convert them to a digital value. You can construct +such an ADC pin object using:: + + >>> import machine + >>> adc = machine.ADC(0) + +Then read its value with:: + + >>> adc.read() + 58 + +The values returned from the ``read()`` function are between 0 (for 0.0 volts) +and 1024 (for 1.0 volts). Please note that this input can only tolerate a +maximum of 1.0 volts and you must use a voltage divider circuit to measure +larger voltages. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/dht.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/dht.rst new file mode 100755 index 0000000..1602e8a --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/dht.rst @@ -0,0 +1,65 @@ +Temperature and Humidity +======================== + +DHT (Digital Humidity & Temperature) sensors are low cost digital sensors with +capacitive humidity sensors and thermistors to measure the surrounding air. +They feature a chip that handles analog to digital conversion and provide a +1-wire interface. Newer sensors additionally provide an I2C interface. + +The DHT11 (blue) and DHT22 (white) sensors provide the same 1-wire interface, +however, the DHT22 requires a separate object as it has more complex +calculation. DHT22 have 1 decimal place resolution for both humidity and +temperature readings. DHT11 have whole number for both. + +A custom 1-wire protocol, which is different to Dallas 1-wire, is used to get +the measurements from the sensor. The payload consists of a humidity value, +a temperature value and a checksum. + +To use the 1-wire interface, construct the objects referring to their data pin:: + + >>> import dht + >>> import machine + >>> d = dht.DHT11(machine.Pin(4)) + + >>> import dht + >>> import machine + >>> d = dht.DHT22(machine.Pin(4)) + +Then measure and read their values with:: + + >>> d.measure() + >>> d.temperature() + >>> d.humidity() + +Values returned from ``temperature()`` are in degrees Celsius and values +returned from ``humidity()`` are a percentage of relative humidity. + +The DHT11 can be called no more than once per second and the DHT22 once every +two seconds for most accurate results. Sensor accuracy will degrade over time. +Each sensor supports a different operating range. Refer to the product +datasheets for specifics. + +In 1-wire mode, only three of the four pins are used and in I2C mode, all four +pins are used. Older sensors may still have 4 pins even though they do not +support I2C. The 3rd pin is simply not connected. + +Pin configurations: + +Sensor without I2C in 1-wire mode (eg. DHT11, DHT22, AM2301, AM2302): + + 1=VDD, 2=Data, 3=NC, 4=GND + +Sensor with I2C in 1-wire mode (eg. DHT12, AM2320, AM2321, AM2322): + + 1=VDD, 2=Data, 3=GND, 4=GND + +Sensor with I2C in I2C mode (eg. DHT12, AM2320, AM2321, AM2322): + + 1=VDD, 2=SDA, 3=GND, 4=SCL + +You should use pull-up resistors for the Data, SDA and SCL pins. + +To make newer I2C sensors work in backwards compatible 1-wire mode, you must +connect both pins 3 and 4 to GND. This disables the I2C interface. + +DHT22 sensors are now sold under the name AM2302 and are otherwise identical. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/filesystem.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/filesystem.rst new file mode 100755 index 0000000..27b0d26 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/filesystem.rst @@ -0,0 +1,69 @@ +The internal filesystem +======================= + +If your devices has 1Mbyte or more of storage then it will be set up (upon first +boot) to contain a filesystem. This filesystem uses the FAT format and is +stored in the flash after the MicroPython firmware. + +Creating and reading files +-------------------------- + +MicroPython on the ESP8266 supports the standard way of accessing files in +Python, using the built-in ``open()`` function. + +To create a file try:: + + >>> f = open('data.txt', 'w') + >>> f.write('some data') + 9 + >>> f.close() + +The "9" is the number of bytes that were written with the ``write()`` method. +Then you can read back the contents of this new file using:: + + >>> f = open('data.txt') + >>> f.read() + 'some data' + >>> f.close() + +Note that the default mode when opening a file is to open it in read-only mode, +and as a text file. Specify ``'wb'`` as the second argument to ``open()`` to +open for writing in binary mode, and ``'rb'`` to open for reading in binary +mode. + +Listing file and more +--------------------- + +The os module can be used for further control over the filesystem. First +import the module:: + + >>> import os + +Then try listing the contents of the filesystem:: + + >>> os.listdir() + ['boot.py', 'port_config.py', 'data.txt'] + +You can make directories:: + + >>> os.mkdir('dir') + +And remove entries:: + + >>> os.remove('data.txt') + +Start up scripts +---------------- + +There are two files that are treated specially by the ESP8266 when it starts up: +boot.py and main.py. The boot.py script is executed first (if it exists) and +then once it completes the main.py script is executed. You can create these +files yourself and populate them with the code that you want to run when the +device starts up. + +Accessing the filesystem via WebREPL +------------------------------------ + +You can access the filesystem over WebREPL using the web client in a browser +or via the command-line tool. Please refer to Quick Reference and Tutorial +sections for more information about WebREPL. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/index.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/index.rst new file mode 100755 index 0000000..0a4b5f2 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/index.rst @@ -0,0 +1,33 @@ +.. _esp8266_tutorial: + +MicroPython tutorial for ESP8266 +================================ + +This tutorial is intended to get you started using MicroPython on the ESP8266 +system-on-a-chip. If it is your first time it is recommended to follow the +tutorial through in the order below. Otherwise the sections are mostly self +contained, so feel free to skip to those that interest you. + +The tutorial does not assume that you know Python, but it also does not attempt +to explain any of the details of the Python language. Instead it provides you +with commands that are ready to run, and hopes that you will gain a bit of +Python knowledge along the way. To learn more about Python itself please refer +to ``__. + +.. toctree:: + :maxdepth: 1 + :numbered: + + intro.rst + repl.rst + filesystem.rst + network_basics.rst + network_tcp.rst + pins.rst + pwm.rst + adc.rst + powerctrl.rst + onewire.rst + neopixel.rst + dht.rst + nextsteps.rst diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/intro.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/intro.rst new file mode 100755 index 0000000..711db3f --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/intro.rst @@ -0,0 +1,202 @@ +.. _intro: + +Getting started with MicroPython on the ESP8266 +=============================================== + +Using MicroPython is a great way to get the most of your ESP8266 board. And +vice versa, the ESP8266 chip is a great platform for using MicroPython. This +tutorial will guide you through setting up MicroPython, getting a prompt, using +WebREPL, connecting to the network and communicating with the Internet, using +the hardware peripherals, and controlling some external components. + +Let's get started! + +Requirements +------------ + +The first thing you need is a board with an ESP8266 chip. The MicroPython +software supports the ESP8266 chip itself and any board should work. The main +characteristic of a board is how much flash it has, how the GPIO pins are +connected to the outside world, and whether it includes a built-in USB-serial +convertor to make the UART available to your PC. + +The minimum requirement for flash size is 1Mbyte. There is also a special +build for boards with 512KB, but it is highly limited comparing to the +normal build: there is no support for filesystem, and thus features which +depend on it won't work (WebREPL, upip, etc.). As such, 512KB build will +be more interesting for users who build from source and fine-tune parameters +for their particular application. + +Names of pins will be given in this tutorial using the chip names (eg GPIO0) +and it should be straightforward to find which pin this corresponds to on your +particular board. + +Powering the board +------------------ + +If your board has a USB connector on it then most likely it is powered through +this when connected to your PC. Otherwise you will need to power it directly. +Please refer to the documentation for your board for further details. + +Getting the firmware +-------------------- + +The first thing you need to do is download the most recent MicroPython firmware +.bin file to load onto your ESP8266 device. You can download it from the +`MicroPython downloads page `_. +From here, you have 3 main choices + +* Stable firmware builds for 1024kb modules and above. +* Daily firmware builds for 1024kb modules and above. +* Daily firmware builds for 512kb modules. + +If you are just starting with MicroPython, the best bet is to go for the Stable +firmware builds. If you are an advanced, experienced MicroPython ESP8266 user +who would like to follow development closely and help with testing new +features, there are daily builds (note: you actually may need some +development experience, e.g. being ready to follow git history to know +what new changes and features were introduced). + +Support for 512kb modules is provided on a feature preview basis. For end +users, it's recommended to use modules with flash of 1024kb or more. As +such, only daily builds for 512kb modules are provided. + +Deploying the firmware +---------------------- + +Once you have the MicroPython firmware (compiled code), you need to load it onto +your ESP8266 device. There are two main steps to do this: first you +need to put your device in boot-loader mode, and second you need to copy across +the firmware. The exact procedure for these steps is highly dependent on the +particular board and you will need to refer to its documentation for details. + +If you have a board that has a USB connector, a USB-serial convertor, and has +the DTR and RTS pins wired in a special way then deploying the firmware should +be easy as all steps can be done automatically. Boards that have such features +include the Adafruit Feather HUZZAH and NodeMCU boards. + +For best results it is recommended to first erase the entire flash of your +device before putting on new MicroPython firmware. + +Currently we only support esptool.py to copy across the firmware. You can find +this tool here: ``__, or install it +using pip:: + + pip install esptool + +Versions starting with 1.3 support both Python 2.7 and Python 3.4 (or newer). +An older version (at least 1.2.1 is needed) works fine but will require Python +2.7. + +Any other flashing program should work, so feel free to try them out or refer +to the documentation for your board to see its recommendations. + +Using esptool.py you can erase the flash with the command:: + + esptool.py --port /dev/ttyUSB0 erase_flash + +And then deploy the new firmware using:: + + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin + +You might need to change the "port" setting to something else relevant for your +PC. You may also need to reduce the baudrate if you get errors when flashing +(eg down to 115200). The filename of the firmware should also match the file +that you have. + +For some boards with a particular FlashROM configuration (e.g. some variants of +a NodeMCU board) you may need to use the following command to deploy +the firmware (note the ``-fm dio`` option):: + + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin + +If the above commands run without error then MicroPython should be installed on +your board! + +Serial prompt +------------- + +Once you have the firmware on the device you can access the REPL (Python prompt) +over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial +convertor, depending on your board. The baudrate is 115200. The next part of +the tutorial will discuss the prompt in more detail. + +WiFi +---- + +After a fresh install and boot the device configures itself as a WiFi access +point (AP) that you can connect to. The ESSID is of the form MicroPython-xxxxxx +where the x's are replaced with part of the MAC address of your device (so will +be the same everytime, and most likely different for all ESP8266 chips). The +password for the WiFi is micropythoN (note the upper-case N). Its IP address +will be 192.168.4.1 once you connect to its network. WiFi configuration will +be discussed in more detail later in the tutorial. + +Troubleshooting installation problems +------------------------------------- + +If you experience problems during flashing or with running firmware immediately +after it, here are troubleshooting recommendations: + +* Be aware of and try to exclude hardware problems. There are 2 common problems: + bad power source quality and worn-out/defective FlashROM. Speaking of power + source, not just raw amperage is important, but also low ripple and noise/EMI + in general. If you experience issues with self-made or wall-wart style power + supply, try USB power from a computer. Unearthed power supplies are also known + to cause problems as they source of increased EMI (electromagnetic interference) + - at the very least, and may lead to electrical devices breakdown. So, you are + advised to avoid using unearthed power connections when working with ESP8266 + and other boards. In regard to FlashROM hardware problems, there are independent + (not related to MicroPython in any way) reports + `(e.g.) `_ + that on some ESP8266 modules, FlashROM can be programmed as little as 20 times + before programming errors occur. This is *much* less than 100,000 programming + cycles cited for FlashROM chips of a type used with ESP8266 by reputable + vendors, which points to either production rejects, or second-hand worn-out + flash chips to be used on some (apparently cheap) modules/boards. You may want + to use your best judgement about source, price, documentation, warranty, + post-sales support for the modules/boards you purchase. + +* The flashing instructions above use flashing speed of 460800 baud, which is + good compromise between speed and stability. However, depending on your + module/board, USB-UART convertor, cables, host OS, etc., the above baud + rate may be too high and lead to errors. Try a more common 115200 baud + rate instead in such cases. + +* If lower baud rate didn't help, you may want to try older version of + esptool.py, which had a different programming algorithm:: + + pip install esptool==1.0.1 + + This version doesn't support ``--flash_size=detect`` option, so you will + need to specify FlashROM size explicitly (in megabits). It also requires + Python 2.7, so you may need to use ``pip2`` instead of ``pip`` in the + command above. + +* The ``--flash_size`` option in the commands above is mandatory. Omitting + it will lead to a corrupted firmware. + +* To catch incorrect flash content (e.g. from a defective sector on a chip), + add ``--verify`` switch to the commands above. + +* Additionally, you can check the firmware integrity from a MicroPython REPL + prompt (assuming you were able to flash it and ``--verify`` option doesn't + report errors):: + + import esp + esp.check_fw() + + If the last output value is True, the firmware is OK. Otherwise, it's + corrupted and need to be reflashed correctly. + +* If you experience any issues with another flashing application (not + esptool.py), try esptool.py, it is a generally accepted flashing + application in the ESP8266 community. + +* If you still experience problems with even flashing the firmware, please + refer to esptool.py project page, https://github.com/espressif/esptool + for additional documentation and bug tracker where you can report problems. + +* If you are able to flash firmware, but ``--verify`` option or + ``esp.check_fw()`` return errors even after multiple retries, you + may have a defective FlashROM chip, as explained above. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/neopixel.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/neopixel.rst new file mode 100755 index 0000000..a153752 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/neopixel.rst @@ -0,0 +1,84 @@ +Controlling NeoPixels +===================== + +NeoPixels, also known as WS2812 LEDs, are full-colour LEDs that are connected in +serial, are individually addressable, and can have their red, green and blue +components set between 0 and 255. They require precise timing to control them +and there is a special neopixel module to do just this. + +To create a NeoPixel object do the following:: + + >>> import machine, neopixel + >>> np = neopixel.NeoPixel(machine.Pin(4), 8) + +This configures a NeoPixel strip on GPIO4 with 8 pixels. You can adjust the +"4" (pin number) and the "8" (number of pixel) to suit your set up. + +To set the colour of pixels use:: + + >>> np[0] = (255, 0, 0) # set to red, full brightness + >>> np[1] = (0, 128, 0) # set to green, half brightness + >>> np[2] = (0, 0, 64) # set to blue, quarter brightness + +For LEDs with more than 3 colours, such as RGBW pixels or RGBY pixels, the +NeoPixel class takes a ``bpp`` parameter. To setup a NeoPixel object for an +RGBW Pixel, do the following:: + + >>> import machine, neopixel + >>> np = neopixel.NeoPixel(machine.Pin(4), 8, bpp=4) + +In a 4-bpp mode, remember to use 4-tuples instead of 3-tuples to set the colour. +For example to set the first three pixels use:: + + >>> np[0] = (255, 0, 0, 128) # Orange in an RGBY Setup + >>> np[1] = (0, 255, 0, 128) # Yellow-green in an RGBY Setup + >>> np[2] = (0, 0, 255, 128) # Green-blue in an RGBY Setup + +Then use the ``write()`` method to output the colours to the LEDs:: + + >>> np.write() + +The following demo function makes a fancy show on the LEDs:: + + import time + + def demo(np): + n = np.n + + # cycle + for i in range(4 * n): + for j in range(n): + np[j] = (0, 0, 0) + np[i % n] = (255, 255, 255) + np.write() + time.sleep_ms(25) + + # bounce + for i in range(4 * n): + for j in range(n): + np[j] = (0, 0, 128) + if (i // n) % 2 == 0: + np[i % n] = (0, 0, 0) + else: + np[n - 1 - (i % n)] = (0, 0, 0) + np.write() + time.sleep_ms(60) + + # fade in/out + for i in range(0, 4 * 256, 8): + for j in range(n): + if (i // 256) % 2 == 0: + val = i & 0xff + else: + val = 255 - (i & 0xff) + np[j] = (val, 0, 0) + np.write() + + # clear + for i in range(n): + np[i] = (0, 0, 0) + np.write() + +Execute it using:: + + >>> demo(np) diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/network_basics.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/network_basics.rst new file mode 100755 index 0000000..95d8cba --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/network_basics.rst @@ -0,0 +1,81 @@ +Network basics +============== + +The network module is used to configure the WiFi connection. There are two WiFi +interfaces, one for the station (when the ESP8266 connects to a router) and one +for the access point (for other devices to connect to the ESP8266). Create +instances of these objects using:: + + >>> import network + >>> sta_if = network.WLAN(network.STA_IF) + >>> ap_if = network.WLAN(network.AP_IF) + +You can check if the interfaces are active by:: + + >>> sta_if.active() + False + >>> ap_if.active() + True + +You can also check the network settings of the interface by:: + + >>> ap_if.ifconfig() + ('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8') + +The returned values are: IP address, netmask, gateway, DNS. + +Configuration of the WiFi +------------------------- + +Upon a fresh install the ESP8266 is configured in access point mode, so the +AP_IF interface is active and the STA_IF interface is inactive. You can +configure the module to connect to your own network using the STA_IF interface. + +First activate the station interface:: + + >>> sta_if.active(True) + +Then connect to your WiFi network:: + + >>> sta_if.connect('', '') + +To check if the connection is established use:: + + >>> sta_if.isconnected() + +Once established you can check the IP address:: + + >>> sta_if.ifconfig() + ('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8') + +You can then disable the access-point interface if you no longer need it:: + + >>> ap_if.active(False) + +Here is a function you can run (or put in your boot.py file) to automatically +connect to your WiFi network:: + + def do_connect(): + import network + sta_if = network.WLAN(network.STA_IF) + if not sta_if.isconnected(): + print('connecting to network...') + sta_if.active(True) + sta_if.connect('', '') + while not sta_if.isconnected(): + pass + print('network config:', sta_if.ifconfig()) + +Sockets +------- + +Once the WiFi is set up the way to access the network is by using sockets. +A socket represents an endpoint on a network device, and when two sockets are +connected together communication can proceed. +Internet protocols are built on top of sockets, such as email (SMTP), the web +(HTTP), telnet, ssh, among many others. Each of these protocols is assigned +a specific port, which is just an integer. Given an IP address and a port +number you can connect to a remote device and start talking with it. + +The next part of the tutorial discusses how to use sockets to do some common +and useful network tasks. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/network_tcp.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/network_tcp.rst new file mode 100755 index 0000000..26a2f46 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/network_tcp.rst @@ -0,0 +1,122 @@ +Network - TCP sockets +===================== + +The building block of most of the internet is the TCP socket. These sockets +provide a reliable stream of bytes between the connected network devices. +This part of the tutorial will show how to use TCP sockets in a few different +cases. + +Star Wars Asciimation +--------------------- + +The simplest thing to do is to download data from the internet. In this case +we will use the Star Wars Asciimation service provided by the blinkenlights.nl +website. It uses the telnet protocol on port 23 to stream data to anyone that +connects. It's very simple to use because it doesn't require you to +authenticate (give a username or password), you can just start downloading data +straight away. + +The first thing to do is make sure we have the socket module available:: + + >>> import socket + +Then get the IP address of the server:: + + >>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23) + +The ``getaddrinfo`` function actually returns a list of addresses, and each +address has more information than we need. We want to get just the first valid +address, and then just the IP address and port of the server. To do this use:: + + >>> addr = addr_info[0][-1] + +If you type ``addr_info`` and ``addr`` at the prompt you will see exactly what +information they hold. + +Using the IP address we can make a socket and connect to the server:: + + >>> s = socket.socket() + >>> s.connect(addr) + +Now that we are connected we can download and display the data:: + + >>> while True: + ... data = s.recv(500) + ... print(str(data, 'utf8'), end='') + ... + +When this loop executes it should start showing the animation (use ctrl-C to +interrupt it). + +You should also be able to run this same code on your PC using normal Python if +you want to try it out there. + +HTTP GET request +---------------- + +The next example shows how to download a webpage. HTTP uses port 80 and you +first need to send a "GET" request before you can download anything. As part +of the request you need to specify the page to retrieve. + +Let's define a function that can download and print a URL:: + + def http_get(url): + _, _, host, path = url.split('/', 3) + addr = socket.getaddrinfo(host, 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8')) + while True: + data = s.recv(100) + if data: + print(str(data, 'utf8'), end='') + else: + break + s.close() + +Make sure that you import the socket module before running this function. Then +you can try:: + + >>> http_get('http://micropython.org/ks/test.html') + +This should retrieve the webpage and print the HTML to the console. + +Simple HTTP server +------------------ + +The following code creates an simple HTTP server which serves a single webpage +that contains a table with the state of all the GPIO pins:: + + import machine + pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)] + + html = """ + + ESP8266 Pins +

ESP8266 Pins

+ %s
PinValue
+ + + """ + + import socket + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + + s = socket.socket() + s.bind(addr) + s.listen(1) + + print('listening on', addr) + + while True: + cl, addr = s.accept() + print('client connected from', addr) + cl_file = cl.makefile('rwb', 0) + while True: + line = cl_file.readline() + if not line or line == b'\r\n': + break + rows = ['%s%d' % (str(p), p.value()) for p in pins] + response = html % '\n'.join(rows) + cl.send(response) + cl.close() diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/nextsteps.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/nextsteps.rst new file mode 100755 index 0000000..318bd7d --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/nextsteps.rst @@ -0,0 +1,12 @@ +Next steps +========== + +That brings us to the end of the tutorial! Hopefully by now you have a good +feel for the capabilities of MicroPython on the ESP8266 and understand how to +control both the WiFi and IO aspects of the chip. + +There are many features that were not covered in this tutorial. The best way +to learn about them is to read the full documentation of the modules, and to +experiment! + +Good luck creating your Internet of Things devices! diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/onewire.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/onewire.rst new file mode 100755 index 0000000..c2cede9 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/onewire.rst @@ -0,0 +1,37 @@ +Controlling 1-wire devices +========================== + +The 1-wire bus is a serial bus that uses just a single wire for communication +(in addition to wires for ground and power). The DS18B20 temperature sensor +is a very popular 1-wire device, and here we show how to use the onewire module +to read from such a device. + +For the following code to work you need to have at least one DS18S20 or DS18B20 temperature +sensor with its data line connected to GPIO12. You must also power the sensors +and connect a 4.7k Ohm resistor between the data pin and the power pin. :: + + import time + import machine + import onewire, ds18x20 + + # the device is on GPIO12 + dat = machine.Pin(12) + + # create the onewire object + ds = ds18x20.DS18X20(onewire.OneWire(dat)) + + # scan for devices on the bus + roms = ds.scan() + print('found devices:', roms) + + # loop 10 times and print all temperatures + for i in range(10): + print('temperatures:', end=' ') + ds.convert_temp() + time.sleep_ms(750) + for rom in roms: + print(ds.read_temp(rom), end=' ') + print() + +Note that you must execute the ``convert_temp()`` function to initiate a +temperature reading, then wait at least 750ms before reading the value. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/pins.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/pins.rst new file mode 100755 index 0000000..d304cd5 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/pins.rst @@ -0,0 +1,76 @@ +GPIO Pins +========= + +The way to connect your board to the external world, and control other +components, is through the GPIO pins. Not all pins are available to use, +in most cases only pins 0, 2, 4, 5, 12, 13, 14, 15, and 16 can be used. + +The pins are available in the machine module, so make sure you import that +first. Then you can create a pin using:: + + >>> pin = machine.Pin(0) + +Here, the "0" is the pin that you want to access. Usually you want to +configure the pin to be input or output, and you do this when constructing +it. To make an input pin use:: + + >>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) + +You can either use PULL_UP or None for the input pull-mode. If it's +not specified then it defaults to None, which is no pull resistor. GPIO16 +has no pull-up mode. +You can read the value on the pin using:: + + >>> pin.value() + 0 + +The pin on your board may return 0 or 1 here, depending on what it's connected +to. To make an output pin use:: + + >>> pin = machine.Pin(0, machine.Pin.OUT) + +Then set its value using:: + + >>> pin.value(0) + >>> pin.value(1) + +Or:: + + >>> pin.off() + >>> pin.on() + +External interrupts +------------------- + +All pins except number 16 can be configured to trigger a hard interrupt if their +input changes. You can set code (a callback function) to be executed on the +trigger. + +Let's first define a callback function, which must take a single argument, +being the pin that triggered the function. We will make the function just print +the pin:: + + >>> def callback(p): + ... print('pin change', p) + +Next we will create two pins and configure them as inputs:: + + >>> from machine import Pin + >>> p0 = Pin(0, Pin.IN) + >>> p2 = Pin(2, Pin.IN) + +An finally we need to tell the pins when to trigger, and the function to call +when they detect an event:: + + >>> p0.irq(trigger=Pin.IRQ_FALLING, handler=callback) + >>> p2.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=callback) + +We set pin 0 to trigger only on a falling edge of the input (when it goes from +high to low), and set pin 2 to trigger on both a rising and falling edge. After +entering this code you can apply high and low voltages to pins 0 and 2 to see +the interrupt being executed. + +A hard interrupt will trigger as soon as the event occurs and will interrupt any +running code, including Python code. As such your callback functions are +limited in what they can do (they cannot allocate memory, for example) and +should be as short and simple as possible. diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/powerctrl.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/powerctrl.rst new file mode 100755 index 0000000..289b4c4 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/powerctrl.rst @@ -0,0 +1,61 @@ +Power control +============= + +The ESP8266 provides the ability to change the CPU frequency on the fly, and +enter a deep-sleep state. Both can be used to manage power consumption. + +Changing the CPU frequency +-------------------------- + +The machine module has a function to get and set the CPU frequency. To get the +current frequency use:: + + >>> import machine + >>> machine.freq() + 80000000 + +By default the CPU runs at 80MHz. It can be changed to 160MHz if you need more +processing power, at the expense of current consumption:: + + >>> machine.freq(160000000) + >>> machine.freq() + 160000000 + +You can change to the higher frequency just while your code does the heavy +processing and then change back when it's finished. + +Deep-sleep mode +--------------- + +The deep-sleep mode will shut down the ESP8266 and all its peripherals, +including the WiFi (but not including the real-time-clock, which is used to wake +the chip). This drastically reduces current consumption and is a good way to +make devices that can run for a while on a battery. + +To be able to use the deep-sleep feature you must connect GPIO16 to the reset +pin (RST on the Adafruit Feather HUZZAH board). Then the following code can be +used to sleep and wake the device:: + + import machine + + # configure RTC.ALARM0 to be able to wake the device + rtc = machine.RTC() + rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) + + # set RTC.ALARM0 to fire after 10 seconds (waking the device) + rtc.alarm(rtc.ALARM0, 10000) + + # put the device to sleep + machine.deepsleep() + +Note that when the chip wakes from a deep-sleep it is completely reset, +including all of the memory. The boot scripts will run as usual and you can +put code in them to check the reset cause to perhaps do something different if +the device just woke from a deep-sleep. For example, to print the reset cause +you can use:: + + if machine.reset_cause() == machine.DEEPSLEEP_RESET: + print('woke from a deep sleep') + else: + print('power on or hard reset') + diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/pwm.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/pwm.rst new file mode 100755 index 0000000..61eb190 --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/pwm.rst @@ -0,0 +1,87 @@ +Pulse Width Modulation +====================== + +Pulse width modulation (PWM) is a way to get an artificial analog output on a +digital pin. It achieves this by rapidly toggling the pin from low to high. +There are two parameters associated with this: the frequency of the toggling, +and the duty cycle. The duty cycle is defined to be how long the pin is high +compared with the length of a single period (low plus high time). Maximum +duty cycle is when the pin is high all of the time, and minimum is when it is +low all of the time. + +On the ESP8266 the pins 0, 2, 4, 5, 12, 13, 14 and 15 all support PWM. The +limitation is that they must all be at the same frequency, and the frequency +must be between 1Hz and 1kHz. + +To use PWM on a pin you must first create the pin object, for example:: + + >>> import machine + >>> p12 = machine.Pin(12) + +Then create the PWM object using:: + + >>> pwm12 = machine.PWM(p12) + +You can set the frequency and duty cycle using:: + + >>> pwm12.freq(500) + >>> pwm12.duty(512) + +Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512 +being a 50% duty. Values beyond this min/max will be clipped. If you +print the PWM object then it will tell you its current configuration:: + + >>> pwm12 + PWM(12, freq=500, duty=512) + +You can also call the ``freq()`` and ``duty()`` methods with no arguments to +get their current values. + +The pin will continue to be in PWM mode until you deinitialise it using:: + + >>> pwm12.deinit() + +Fading an LED +------------- + +Let's use the PWM feature to fade an LED. Assuming your board has an LED +connected to pin 2 (ESP-12 modules do) we can create an LED-PWM object using:: + + >>> led = machine.PWM(machine.Pin(2), freq=1000) + +Notice that we can set the frequency in the PWM constructor. + +For the next part we will use timing and some math, so import these modules:: + + >>> import time, math + +Then create a function to pulse the LED:: + + >>> def pulse(l, t): + ... for i in range(20): + ... l.duty(int(math.sin(i / 10 * math.pi) * 500 + 500)) + ... time.sleep_ms(t) + +You can try this function out using:: + + >>> pulse(led, 50) + +For a nice effect you can pulse many times in a row:: + + >>> for i in range(10): + ... pulse(led, 20) + +Remember you can use ctrl-C to interrupt the code. + +Control a hobby servo +--------------------- + +Hobby servo motors can be controlled using PWM. They require a frequency of +50Hz and then a duty between about 40 and 115, with 77 being the centre value. +If you connect a servo to the power and ground pins, and then the signal line +to pin 12 (other pins will work just as well), you can control the motor using:: + + >>> servo = machine.PWM(machine.Pin(12), freq=50) + >>> servo.duty(40) + >>> servo.duty(115) + >>> servo.duty(77) diff --git a/src/openmv/src/micropython/docs/esp8266/tutorial/repl.rst b/src/openmv/src/micropython/docs/esp8266/tutorial/repl.rst new file mode 100755 index 0000000..ba64fcc --- /dev/null +++ b/src/openmv/src/micropython/docs/esp8266/tutorial/repl.rst @@ -0,0 +1,212 @@ +Getting a MicroPython REPL prompt +================================= + +REPL stands for Read Evaluate Print Loop, and is the name given to the +interactive MicroPython prompt that you can access on the ESP8266. Using the +REPL is by far the easiest way to test out your code and run commands. + +There are two ways to access the REPL: either via a wired connection through the +UART serial port, or via WiFi. + +REPL over the serial port +------------------------- + +The REPL is always available on the UART0 serial peripheral, which is connected +to the pins GPIO1 for TX and GPIO3 for RX. The baudrate of the REPL is 115200. +If your board has a USB-serial convertor on it then you should be able to access +the REPL directly from your PC. Otherwise you will need to have a way of +communicating with the UART. + +To access the prompt over USB-serial you need to use a terminal emulator program. +On Windows TeraTerm is a good choice, on Mac you can use the built-in screen +program, and Linux has picocom and minicom. Of course, there are many other +terminal programs that will work, so pick your favourite! + +For example, on Linux you can try running:: + + picocom /dev/ttyUSB0 -b115200 + +Once you have made the connection over the serial port you can test if it is +working by hitting enter a few times. You should see the Python REPL prompt, +indicated by ``>>>``. + +WebREPL - a prompt over WiFi +---------------------------- + +WebREPL allows you to use the Python prompt over WiFi, connecting through a +browser. The latest versions of Firefox and Chrome are supported. + +For your convenience, WebREPL client is hosted at +``__ . Alternatively, you can install it +locally from the the GitHub repository +``__ . + +Before connecting to WebREPL, you should set a password and enable it via +a normal serial connection. Initial versions of MicroPython for ESP8266 +came with WebREPL automatically enabled on the boot and with the +ability to set a password via WiFi on the first connection, but as WebREPL +was becoming more widely known and popular, the initial setup has switched +to a wired connection for improved security:: + + import webrepl_setup + +Follow the on-screen instructions and prompts. To make any changes active, +you will need to reboot your device. + +To use WebREPL connect your computer to the ESP8266's access point +(MicroPython-xxxxxx, see the previous section about this). If you have +already reconfigured your ESP8266 to connect to a router then you can +skip this part. + +Once you are on the same network as the ESP8266 you click the "Connect" button +(if you are connecting via a router then you may need to change the IP address, +by default the IP address is correct when connected to the ESP8266's access +point). If the connection succeeds then you should see a password prompt. + +Once you type the password configured at the setup step above, press Enter once +more and you should get a prompt looking like ``>>>``. You can now start +typing Python commands! + +Using the REPL +-------------- + +Once you have a prompt you can start experimenting! Anything you type at the +prompt will be executed after you press the Enter key. MicroPython will run +the code that you enter and print the result (if there is one). If there is an +error with the text that you enter then an error message is printed. + +Try typing the following at the prompt:: + + >>> print('hello esp8266!') + hello esp8266! + +Note that you shouldn't type the ``>>>`` arrows, they are there to indicate that +you should type the text after it at the prompt. And then the line following is +what the device should respond with. In the end, once you have entered the text +``print("hello esp8266!")`` and pressed the Enter key, the output on your screen +should look exactly like it does above. + +If you already know some python you can now try some basic commands here. For +example:: + + >>> 1 + 2 + 3 + >>> 1 / 2 + 0.5 + >>> 12**34 + 4922235242952026704037113243122008064 + +If your board has an LED attached to GPIO2 (the ESP-12 modules do) then you can +turn it on and off using the following code:: + + >>> import machine + >>> pin = machine.Pin(2, machine.Pin.OUT) + >>> pin.on() + >>> pin.off() + +Note that ``on`` method of a Pin might turn the LED off and ``off`` might +turn it on (or vice versa), depending on how the LED is wired on your board. +To resolve this, machine.Signal class is provided. + +Line editing +~~~~~~~~~~~~ + +You can edit the current line that you are entering using the left and right +arrow keys to move the cursor, as well as the delete and backspace keys. Also, +pressing Home or ctrl-A moves the cursor to the start of the line, and pressing +End or ctrl-E moves to the end of the line. + +Input history +~~~~~~~~~~~~~ + +The REPL remembers a certain number of previous lines of text that you entered +(up to 8 on the ESP8266). To recall previous lines use the up and down arrow +keys. + +Tab completion +~~~~~~~~~~~~~~ + +Pressing the Tab key will do an auto-completion of the current word that you are +entering. This can be very useful to find out functions and methods that a +module or object has. Try it out by typing "ma" and then pressing Tab. It +should complete to "machine" (assuming you imported machine in the above +example). Then type "." and press Tab again to see a list of all the functions +that the machine module has. + +Line continuation and auto-indent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Certain things that you type will need "continuing", that is, will need more +lines of text to make a proper Python statement. In this case the prompt will +change to ``...`` and the cursor will auto-indent the correct amount so you can +start typing the next line straight away. Try this by defining the following +function:: + + >>> def toggle(p): + ... p.value(not p.value()) + ... + ... + ... + >>> + +In the above, you needed to press the Enter key three times in a row to finish +the compound statement (that's the three lines with just dots on them). The +other way to finish a compound statement is to press backspace to get to the +start of the line, then press the Enter key. (If you did something wrong and +want to escape the continuation mode then press ctrl-C; all lines will be +ignored.) + +The function you just defined allows you to toggle a pin. The pin object you +created earlier should still exist (recreate it if it doesn't) and you can +toggle the LED using:: + + >>> toggle(pin) + +Let's now toggle the LED in a loop (if you don't have an LED then you can just +print some text instead of calling toggle, to see the effect):: + + >>> import time + >>> while True: + ... toggle(pin) + ... time.sleep_ms(500) + ... + ... + ... + >>> + +This will toggle the LED at 1Hz (half a second on, half a second off). To stop +the toggling press ctrl-C, which will raise a KeyboardInterrupt exception and +break out of the loop. + +The time module provides some useful functions for making delays and doing +timing. Use tab completion to find out what they are and play around with them! + +Paste mode +~~~~~~~~~~ + +Pressing ctrl-E will enter a special paste mode. This allows you to copy and +paste a chunk of text into the REPL. If you press ctrl-E you will see the +paste-mode prompt:: + + paste mode; Ctrl-C to cancel, Ctrl-D to finish + === + +You can then paste (or type) your text in. Note that none of the special keys +or commands work in paste mode (eg Tab or backspace), they are just accepted +as-is. Press ctrl-D to finish entering the text and execute it. + +Other control commands +~~~~~~~~~~~~~~~~~~~~~~ + +There are four other control commands: + +* Ctrl-A on a blank line will enter raw REPL mode. This is like a permanent + paste mode, except that characters are not echoed back. + +* Ctrl-B on a blank like goes to normal REPL mode. + +* Ctrl-C cancels any input, or interrupts the currently running code. + +* Ctrl-D on a blank line will do a soft reset. + +Note that ctrl-A and ctrl-D do not work with WebREPL. diff --git a/src/openmv/src/micropython/docs/index.rst b/src/openmv/src/micropython/docs/index.rst new file mode 100755 index 0000000..af5ffb8 --- /dev/null +++ b/src/openmv/src/micropython/docs/index.rst @@ -0,0 +1,12 @@ +MicroPython documentation and references +======================================== + +.. toctree:: + + library/index.rst + reference/index.rst + genrst/index.rst + license.rst + pyboard/quickref.rst + esp8266/quickref.rst + wipy/quickref.rst diff --git a/src/openmv/src/micropython/docs/library/_thread.rst b/src/openmv/src/micropython/docs/library/_thread.rst new file mode 100755 index 0000000..47c1c23 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/_thread.rst @@ -0,0 +1,12 @@ +:mod:`_thread` -- multithreading support +======================================== + +.. module:: _thread + :synopsis: multithreading support + +|see_cpython_module| :mod:`python:_thread`. + +This module implements multithreading support. + +This module is highly experimental and its API is not yet fully settled +and not yet described in this documentation. diff --git a/src/openmv/src/micropython/docs/library/array.rst b/src/openmv/src/micropython/docs/library/array.rst new file mode 100755 index 0000000..f837b03 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/array.rst @@ -0,0 +1,29 @@ +:mod:`array` -- arrays of numeric data +====================================== + +.. module:: array + :synopsis: efficient arrays of numeric data + +|see_cpython_module| :mod:`python:array`. + +Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``, +``L``, ``q``, ``Q``, ``f``, ``d`` (the latter 2 depending on the +floating-point support). + +Classes +------- + +.. class:: array.array(typecode, [iterable]) + + Create array with elements of given type. Initial contents of the + array are given by *iterable*. If it is not provided, an empty + array is created. + + .. method:: append(val) + + Append new element *val* to the end of array, growing it. + + .. method:: extend(iterable) + + Append new elements as contained in *iterable* to the end of + array, growing it. diff --git a/src/openmv/src/micropython/docs/library/btree.rst b/src/openmv/src/micropython/docs/library/btree.rst new file mode 100755 index 0000000..3578acd --- /dev/null +++ b/src/openmv/src/micropython/docs/library/btree.rst @@ -0,0 +1,159 @@ +:mod:`btree` -- simple BTree database +===================================== + +.. module:: btree + :synopsis: simple BTree database + +The ``btree`` module implements a simple key-value database using external +storage (disk files, or in general case, a random-access `stream`). Keys are +stored sorted in the database, and besides efficient retrieval by a key +value, a database also supports efficient ordered range scans (retrieval +of values with the keys in a given range). On the application interface +side, BTree database work as close a possible to a way standard `dict` +type works, one notable difference is that both keys and values must +be `bytes` objects (so, if you want to store objects of other types, you +need to serialize them to `bytes` first). + +The module is based on the well-known BerkelyDB library, version 1.xx. + +Example:: + + import btree + + # First, we need to open a stream which holds a database + # This is usually a file, but can be in-memory database + # using uio.BytesIO, a raw flash partition, etc. + # Oftentimes, you want to create a database file if it doesn't + # exist and open if it exists. Idiom below takes care of this. + # DO NOT open database with "a+b" access mode. + try: + f = open("mydb", "r+b") + except OSError: + f = open("mydb", "w+b") + + # Now open a database itself + db = btree.open(f) + + # The keys you add will be sorted internally in the database + db[b"3"] = b"three" + db[b"1"] = b"one" + db[b"2"] = b"two" + + # Assume that any changes are cached in memory unless + # explicitly flushed (or database closed). Flush database + # at the end of each "transaction". + db.flush() + + # Prints b'two' + print(db[b"2"]) + + # Iterate over sorted keys in the database, starting from b"2" + # until the end of the database, returning only values. + # Mind that arguments passed to values() method are *key* values. + # Prints: + # b'two' + # b'three' + for word in db.values(b"2"): + print(word) + + del db[b"2"] + + # No longer true, prints False + print(b"2" in db) + + # Prints: + # b"1" + # b"3" + for key in db: + print(key) + + db.close() + + # Don't forget to close the underlying stream! + f.close() + + +Functions +--------- + +.. function:: open(stream, \*, flags=0, pagesize=0, cachesize=0, minkeypage=0) + + Open a database from a random-access `stream` (like an open file). All + other parameters are optional and keyword-only, and allow to tweak advanced + parameters of the database operation (most users will not need them): + + * *flags* - Currently unused. + * *pagesize* - Page size used for the nodes in BTree. Acceptable range + is 512-65536. If 0, a port-specific default will be used, optimized for + port's memory usage and/or performance. + * *cachesize* - Suggested memory cache size in bytes. For a + board with enough memory using larger values may improve performance. + Cache policy is as follows: entire cache is not allocated at once; + instead, accessing a new page in database will allocate a memory buffer + for it, until value specified by *cachesize* is reached. Then, these + buffers will be managed using LRU (least recently used) policy. More + buffers may still be allocated if needed (e.g., if a database contains + big keys and/or values). Allocated cache buffers aren't reclaimed. + * *minkeypage* - Minimum number of keys to store per page. Default value + of 0 equivalent to 2. + + Returns a BTree object, which implements a dictionary protocol (set + of methods), and some additional methods described below. + +Methods +------- + +.. method:: btree.close() + + Close the database. It's mandatory to close the database at the end of + processing, as some unwritten data may be still in the cache. Note that + this does not close underlying stream with which the database was opened, + it should be closed separately (which is also mandatory to make sure that + data flushed from buffer to the underlying storage). + +.. method:: btree.flush() + + Flush any data in cache to the underlying stream. + +.. method:: btree.__getitem__(key) + btree.get(key, default=None) + btree.__setitem__(key, val) + btree.__detitem__(key) + btree.__contains__(key) + + Standard dictionary methods. + +.. method:: btree.__iter__() + + A BTree object can be iterated over directly (similar to a dictionary) + to get access to all keys in order. + +.. method:: btree.keys([start_key, [end_key, [flags]]]) + btree.values([start_key, [end_key, [flags]]]) + btree.items([start_key, [end_key, [flags]]]) + + These methods are similar to standard dictionary methods, but also can + take optional parameters to iterate over a key sub-range, instead of + the entire database. Note that for all 3 methods, *start_key* and + *end_key* arguments represent key values. For example, `values()` + method will iterate over values corresponding to they key range + given. None values for *start_key* means "from the first key", no + *end_key* or its value of None means "until the end of database". + By default, range is inclusive of *start_key* and exclusive of + *end_key*, you can include *end_key* in iteration by passing *flags* + of `btree.INCL`. You can iterate in descending key direction + by passing *flags* of `btree.DESC`. The flags values can be ORed + together. + +Constants +--------- + +.. data:: INCL + + A flag for `keys()`, `values()`, `items()` methods to specify that + scanning should be inclusive of the end key. + +.. data:: DESC + + A flag for `keys()`, `values()`, `items()` methods to specify that + scanning should be in descending direction of keys. diff --git a/src/openmv/src/micropython/docs/library/builtins.rst b/src/openmv/src/micropython/docs/library/builtins.rst new file mode 100755 index 0000000..365248d --- /dev/null +++ b/src/openmv/src/micropython/docs/library/builtins.rst @@ -0,0 +1,199 @@ +Builtin functions and exceptions +================================ + +All builtin functions and exceptions are described here. They are also +available via ``builtins`` module. + +Functions and types +------------------- + +.. function:: abs() + +.. function:: all() + +.. function:: any() + +.. function:: bin() + +.. class:: bool() + +.. class:: bytearray() + +.. class:: bytes() + + |see_cpython| `python:bytes`. + +.. function:: callable() + +.. function:: chr() + +.. function:: classmethod() + +.. function:: compile() + +.. class:: complex() + +.. function:: delattr(obj, name) + + The argument *name* should be a string, and this function deletes the named + attribute from the object given by *obj*. + +.. class:: dict() + +.. function:: dir() + +.. function:: divmod() + +.. function:: enumerate() + +.. function:: eval() + +.. function:: exec() + +.. function:: filter() + +.. class:: float() + +.. class:: frozenset() + +.. function:: getattr() + +.. function:: globals() + +.. function:: hasattr() + +.. function:: hash() + +.. function:: hex() + +.. function:: id() + +.. function:: input() + +.. class:: int() + + .. classmethod:: from_bytes(bytes, byteorder) + + In MicroPython, `byteorder` parameter must be positional (this is + compatible with CPython). + + .. method:: to_bytes(size, byteorder) + + In MicroPython, `byteorder` parameter must be positional (this is + compatible with CPython). + +.. function:: isinstance() + +.. function:: issubclass() + +.. function:: iter() + +.. function:: len() + +.. class:: list() + +.. function:: locals() + +.. function:: map() + +.. function:: max() + +.. class:: memoryview() + +.. function:: min() + +.. function:: next() + +.. class:: object() + +.. function:: oct() + +.. function:: open() + +.. function:: ord() + +.. function:: pow() + +.. function:: print() + +.. function:: property() + +.. function:: range() + +.. function:: repr() + +.. function:: reversed() + +.. function:: round() + +.. class:: set() + +.. function:: setattr() + +.. class:: slice() + + The *slice* builtin is the type that slice objects have. + +.. function:: sorted() + +.. function:: staticmethod() + +.. class:: str() + +.. function:: sum() + +.. function:: super() + +.. class:: tuple() + +.. function:: type() + +.. function:: zip() + + +Exceptions +---------- + +.. exception:: AssertionError + +.. exception:: AttributeError + +.. exception:: Exception + +.. exception:: ImportError + +.. exception:: IndexError + +.. exception:: KeyboardInterrupt + +.. exception:: KeyError + +.. exception:: MemoryError + +.. exception:: NameError + +.. exception:: NotImplementedError + +.. exception:: OSError + + |see_cpython| `python:OSError`. MicroPython doesn't implement ``errno`` + attribute, instead use the standard way to access exception arguments: + ``exc.args[0]``. + +.. exception:: RuntimeError + +.. exception:: StopIteration + +.. exception:: SyntaxError + +.. exception:: SystemExit + + |see_cpython| `python:SystemExit`. + +.. exception:: TypeError + + |see_cpython| `python:TypeError`. + +.. exception:: ValueError + +.. exception:: ZeroDivisionError diff --git a/src/openmv/src/micropython/docs/library/cmath.rst b/src/openmv/src/micropython/docs/library/cmath.rst new file mode 100755 index 0000000..59e4ec1 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/cmath.rst @@ -0,0 +1,63 @@ +:mod:`cmath` -- mathematical functions for complex numbers +========================================================== + +.. module:: cmath + :synopsis: mathematical functions for complex numbers + +|see_cpython_module| :mod:`python:cmath`. + +The ``cmath`` module provides some basic mathematical functions for +working with complex numbers. + +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + +Functions +--------- + +.. function:: cos(z) + + Return the cosine of ``z``. + +.. function:: exp(z) + + Return the exponential of ``z``. + +.. function:: log(z) + + Return the natural logarithm of ``z``. The branch cut is along the negative real axis. + +.. function:: log10(z) + + Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis. + +.. function:: phase(z) + + Returns the phase of the number ``z``, in the range (-pi, +pi]. + +.. function:: polar(z) + + Returns, as a tuple, the polar form of ``z``. + +.. function:: rect(r, phi) + + Returns the complex number with modulus ``r`` and phase ``phi``. + +.. function:: sin(z) + + Return the sine of ``z``. + +.. function:: sqrt(z) + + Return the square-root of ``z``. + +Constants +--------- + +.. data:: e + + base of the natural logarithm + +.. data:: pi + + the ratio of a circle's circumference to its diameter diff --git a/src/openmv/src/micropython/docs/library/esp.rst b/src/openmv/src/micropython/docs/library/esp.rst new file mode 100755 index 0000000..121a80d --- /dev/null +++ b/src/openmv/src/micropython/docs/library/esp.rst @@ -0,0 +1,83 @@ +:mod:`esp` --- functions related to the ESP8266 +=============================================== + +.. module:: esp + :synopsis: functions related to the ESP8266 + +The ``esp`` module contains specific functions related to the ESP8266 module. + + +Functions +--------- + +.. function:: sleep_type([sleep_type]) + + Get or set the sleep type. + + If the *sleep_type* parameter is provided, sets the sleep type to its + value. If the function is called without parameters, returns the current + sleep type. + + The possible sleep types are defined as constants: + + * ``SLEEP_NONE`` -- all functions enabled, + * ``SLEEP_MODEM`` -- modem sleep, shuts down the WiFi Modem circuit. + * ``SLEEP_LIGHT`` -- light sleep, shuts down the WiFi Modem circuit + and suspends the processor periodically. + + The system enters the set sleep mode automatically when possible. + +.. function:: deepsleep(time=0) + + Enter deep sleep. + + The whole module powers down, except for the RTC clock circuit, which can + be used to restart the module after the specified time if the pin 16 is + connected to the reset pin. Otherwise the module will sleep until manually + reset. + +.. function:: flash_id() + + Read the device ID of the flash memory. + +.. function:: flash_read(byte_offset, length_or_buffer) + +.. function:: flash_write(byte_offset, bytes) + +.. function:: flash_erase(sector_no) + +.. function:: set_native_code_location(start, length) + + Set the location that native code will be placed for execution after it is + compiled. Native code is emitted when the ``@micropython.native``, + ``@micropython.viper`` and ``@micropython.asm_xtensa`` decorators are applied + to a function. The ESP8266 must execute code from either iRAM or the lower + 1MByte of flash (which is memory mapped), and this function controls the + location. + + If *start* and *length* are both ``None`` then the native code location is + set to the unused portion of memory at the end of the iRAM1 region. The + size of this unused portion depends on the firmware and is typically quite + small (around 500 bytes), and is enough to store a few very small + functions. The advantage of using this iRAM1 region is that it does not + get worn out by writing to it. + + If neither *start* nor *length* are ``None`` then they should be integers. + *start* should specify the byte offset from the beginning of the flash at + which native code should be stored. *length* specifies how many bytes of + flash from *start* can be used to store native code. *start* and *length* + should be multiples of the sector size (being 4096 bytes). The flash will + be automatically erased before writing to it so be sure to use a region of + flash that is not otherwise used, for example by the firmware or the + filesystem. + + When using the flash to store native code *start+length* must be less + than or equal to 1MByte. Note that the flash can be worn out if repeated + erasures (and writes) are made so use this feature sparingly. + In particular, native code needs to be recompiled and rewritten to flash + on each boot (including wake from deepsleep). + + In both cases above, using iRAM1 or flash, if there is no more room left + in the specified region then the use of a native decorator on a function + will lead to `MemoryError` exception being raised during compilation of + that function. diff --git a/src/openmv/src/micropython/docs/library/framebuf.rst b/src/openmv/src/micropython/docs/library/framebuf.rst new file mode 100755 index 0000000..ed4b78a --- /dev/null +++ b/src/openmv/src/micropython/docs/library/framebuf.rst @@ -0,0 +1,161 @@ +:mod:`framebuf` --- Frame buffer manipulation +============================================= + +.. module:: framebuf + :synopsis: Frame buffer manipulation + +This module provides a general frame buffer which can be used to create +bitmap images, which can then be sent to a display. + +class FrameBuffer +----------------- + +The FrameBuffer class provides a pixel buffer which can be drawn upon with +pixels, lines, rectangles, text and even other FrameBuffer's. It is useful +when generating output for displays. + +For example:: + + import framebuf + + # FrameBuffer needs 2 bytes for every RGB565 pixel + fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) + + fbuf.fill(0) + fbuf.text('MicroPython!', 0, 0, 0xffff) + fbuf.hline(0, 10, 96, 0xffff) + +Constructors +------------ + +.. class:: FrameBuffer(buffer, width, height, format, stride=width) + + Construct a FrameBuffer object. The parameters are: + + - *buffer* is an object with a buffer protocol which must be large + enough to contain every pixel defined by the width, height and + format of the FrameBuffer. + - *width* is the width of the FrameBuffer in pixels + - *height* is the height of the FrameBuffer in pixels + - *format* specifies the type of pixel used in the FrameBuffer; + permissible values are listed under Constants below. These set the + number of bits used to encode a color value and the layout of these + bits in *buffer*. + Where a color value c is passed to a method, c is a small integer + with an encoding that is dependent on the format of the FrameBuffer. + - *stride* is the number of pixels between each horizontal line + of pixels in the FrameBuffer. This defaults to *width* but may + need adjustments when implementing a FrameBuffer within another + larger FrameBuffer or screen. The *buffer* size must accommodate + an increased step size. + + One must specify valid *buffer*, *width*, *height*, *format* and + optionally *stride*. Invalid *buffer* size or dimensions may lead to + unexpected errors. + +Drawing primitive shapes +------------------------ + +The following methods draw shapes onto the FrameBuffer. + +.. method:: FrameBuffer.fill(c) + + Fill the entire FrameBuffer with the specified color. + +.. method:: FrameBuffer.pixel(x, y[, c]) + + If *c* is not given, get the color value of the specified pixel. + If *c* is given, set the specified pixel to the given color. + +.. method:: FrameBuffer.hline(x, y, w, c) +.. method:: FrameBuffer.vline(x, y, h, c) +.. method:: FrameBuffer.line(x1, y1, x2, y2, c) + + Draw a line from a set of coordinates using the given color and + a thickness of 1 pixel. The `line` method draws the line up to + a second set of coordinates whereas the `hline` and `vline` + methods draw horizontal and vertical lines respectively up to + a given length. + +.. method:: FrameBuffer.rect(x, y, w, h, c) +.. method:: FrameBuffer.fill_rect(x, y, w, h, c) + + Draw a rectangle at the given location, size and color. The `rect` + method draws only a 1 pixel outline whereas the `fill_rect` method + draws both the outline and interior. + +Drawing text +------------ + +.. method:: FrameBuffer.text(s, x, y[, c]) + + Write text to the FrameBuffer using the the coordinates as the upper-left + corner of the text. The color of the text can be defined by the optional + argument but is otherwise a default value of 1. All characters have + dimensions of 8x8 pixels and there is currently no way to change the font. + + +Other methods +------------- + +.. method:: FrameBuffer.scroll(xstep, ystep) + + Shift the contents of the FrameBuffer by the given vector. This may + leave a footprint of the previous colors in the FrameBuffer. + +.. method:: FrameBuffer.blit(fbuf, x, y[, key]) + + Draw another FrameBuffer on top of the current one at the given coordinates. + If *key* is specified then it should be a color integer and the + corresponding color will be considered transparent: all pixels with that + color value will not be drawn. + + This method works between FrameBuffer instances utilising different formats, + but the resulting colors may be unexpected due to the mismatch in color + formats. + +Constants +--------- + +.. data:: framebuf.MONO_VLSB + + Monochrome (1-bit) color format + This defines a mapping where the bits in a byte are vertically mapped with + bit 0 being nearest the top of the screen. Consequently each byte occupies + 8 vertical pixels. Subsequent bytes appear at successive horizontal + locations until the rightmost edge is reached. Further bytes are rendered + at locations starting at the leftmost edge, 8 pixels lower. + +.. data:: framebuf.MONO_HLSB + + Monochrome (1-bit) color format + This defines a mapping where the bits in a byte are horizontally mapped. + Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. + Subsequent bytes appear at successive horizontal locations until the + rightmost edge is reached. Further bytes are rendered on the next row, one + pixel lower. + +.. data:: framebuf.MONO_HMSB + + Monochrome (1-bit) color format + This defines a mapping where the bits in a byte are horizontally mapped. + Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. + Subsequent bytes appear at successive horizontal locations until the + rightmost edge is reached. Further bytes are rendered on the next row, one + pixel lower. + +.. data:: framebuf.RGB565 + + Red Green Blue (16-bit, 5+6+5) color format + +.. data:: framebuf.GS2_HMSB + + Grayscale (2-bit) color format + +.. data:: framebuf.GS4_HMSB + + Grayscale (4-bit) color format + +.. data:: framebuf.GS8 + + Grayscale (8-bit) color format diff --git a/src/openmv/src/micropython/docs/library/gc.rst b/src/openmv/src/micropython/docs/library/gc.rst new file mode 100755 index 0000000..c823aed --- /dev/null +++ b/src/openmv/src/micropython/docs/library/gc.rst @@ -0,0 +1,66 @@ +:mod:`gc` -- control the garbage collector +========================================== + +.. module:: gc + :synopsis: control the garbage collector + +|see_cpython_module| :mod:`python:gc`. + +Functions +--------- + +.. function:: enable() + + Enable automatic garbage collection. + +.. function:: disable() + + Disable automatic garbage collection. Heap memory can still be allocated, + and garbage collection can still be initiated manually using :meth:`gc.collect`. + +.. function:: collect() + + Run a garbage collection. + +.. function:: mem_alloc() + + Return the number of bytes of heap RAM that are allocated. + + .. admonition:: Difference to CPython + :class: attention + + This function is MicroPython extension. + +.. function:: mem_free() + + Return the number of bytes of available heap RAM, or -1 if this amount + is not known. + + .. admonition:: Difference to CPython + :class: attention + + This function is MicroPython extension. + +.. function:: threshold([amount]) + + Set or query the additional GC allocation threshold. Normally, a collection + is triggered only when a new allocation cannot be satisfied, i.e. on an + out-of-memory (OOM) condition. If this function is called, in addition to + OOM, a collection will be triggered each time after *amount* bytes have been + allocated (in total, since the previous time such an amount of bytes + have been allocated). *amount* is usually specified as less than the + full heap size, with the intention to trigger a collection earlier than when the + heap becomes exhausted, and in the hope that an early collection will prevent + excessive memory fragmentation. This is a heuristic measure, the effect + of which will vary from application to application, as well as + the optimal value of the *amount* parameter. + + Calling the function without argument will return the current value of + the threshold. A value of -1 means a disabled allocation threshold. + + .. admonition:: Difference to CPython + :class: attention + + This function is a MicroPython extension. CPython has a similar + function - ``set_threshold()``, but due to different GC + implementations, its signature and semantics are different. diff --git a/src/openmv/src/micropython/docs/library/index.rst b/src/openmv/src/micropython/docs/library/index.rst new file mode 100755 index 0000000..e37f1d6 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/index.rst @@ -0,0 +1,150 @@ +.. _micropython_lib: + +MicroPython libraries +===================== + +.. warning:: + + Important summary of this section + + * MicroPython implements a subset of Python functionality for each module. + * To ease extensibility, MicroPython versions of standard Python modules + usually have ``u`` ("micro") prefix. + * Any particular MicroPython variant or port may miss any feature/function + described in this general documentation (due to resource constraints or + other limitations). + + +This chapter describes modules (function and class libraries) which are built +into MicroPython. There are a few categories of such modules: + +* Modules which implement a subset of standard Python functionality and are not + intended to be extended by the user. +* Modules which implement a subset of Python functionality, with a provision + for extension by the user (via Python code). +* Modules which implement MicroPython extensions to the Python standard libraries. +* Modules specific to a particular `MicroPython port` and thus not portable. + +Note about the availability of the modules and their contents: This documentation +in general aspires to describe all modules and functions/classes which are +implemented in MicroPython project. However, MicroPython is highly configurable, and +each port to a particular board/embedded system makes available only a subset +of MicroPython libraries. For officially supported ports, there is an effort +to either filter out non-applicable items, or mark individual descriptions +with "Availability:" clauses describing which ports provide a given feature. + +With that in mind, please still be warned that some functions/classes +in a module (or even the entire module) described in this documentation **may be +unavailable** in a particular build of MicroPython on a particular system. The +best place to find general information of the availability/non-availability +of a particular feature is the "General Information" section which contains +information pertaining to a specific `MicroPython port`. + +On some ports you are able to discover the available, built-in libraries that +can be imported by entering the following at the REPL:: + + help('modules') + +Beyond the built-in libraries described in this documentation, many more +modules from the Python standard library, as well as further MicroPython +extensions to it, can be found in `micropython-lib`. + +Python standard libraries and micro-libraries +--------------------------------------------- + +The following standard Python libraries have been "micro-ified" to fit in with +the philosophy of MicroPython. They provide the core functionality of that +module and are intended to be a drop-in replacement for the standard Python +library. Some modules below use a standard Python name, but prefixed with "u", +e.g. ``ujson`` instead of ``json``. This is to signify that such a module is +micro-library, i.e. implements only a subset of CPython module functionality. +By naming them differently, a user has a choice to write a Python-level module +to extend functionality for better compatibility with CPython (indeed, this is +what done by the `micropython-lib` project mentioned above). + +On some embedded platforms, where it may be cumbersome to add Python-level +wrapper modules to achieve naming compatibility with CPython, micro-modules +are available both by their u-name, and also by their non-u-name. The +non-u-name can be overridden by a file of that name in your library path (``sys.path``). +For example, ``import json`` will first search for a file ``json.py`` (or package +directory ``json``) and load that module if it is found. If nothing is found, +it will fallback to loading the built-in ``ujson`` module. + +.. toctree:: + :maxdepth: 1 + + builtins.rst + array.rst + cmath.rst + gc.rst + math.rst + sys.rst + ubinascii.rst + ucollections.rst + uerrno.rst + uhashlib.rst + uheapq.rst + uio.rst + ujson.rst + uos.rst + ure.rst + uselect.rst + usocket.rst + ussl.rst + ustruct.rst + utime.rst + uzlib.rst + _thread.rst + + +MicroPython-specific libraries +------------------------------ + +Functionality specific to the MicroPython implementation is available in +the following libraries. + +.. toctree:: + :maxdepth: 1 + + btree.rst + framebuf.rst + machine.rst + micropython.rst + network.rst + ucryptolib.rst + uctypes.rst + + +Libraries specific to the pyboard +--------------------------------- + +The following libraries are specific to the pyboard. + +.. toctree:: + :maxdepth: 2 + + pyb.rst + lcd160cr.rst + + +Libraries specific to the WiPy +------------------------------ + +The following libraries and classes are specific to the WiPy. + +.. toctree:: + :maxdepth: 2 + + wipy.rst + machine.TimerWiPy.rst + + +Libraries specific to the ESP8266 +--------------------------------- + +The following libraries are specific to the ESP8266. + +.. toctree:: + :maxdepth: 2 + + esp.rst diff --git a/src/openmv/src/micropython/docs/library/lcd160cr.rst b/src/openmv/src/micropython/docs/library/lcd160cr.rst new file mode 100755 index 0000000..bb8e6da --- /dev/null +++ b/src/openmv/src/micropython/docs/library/lcd160cr.rst @@ -0,0 +1,394 @@ +:mod:`lcd160cr` --- control of LCD160CR display +=============================================== + +.. module:: lcd160cr + :synopsis: control of LCD160CR display + +This module provides control of the MicroPython LCD160CR display. + +.. image:: http://micropython.org/resources/LCD160CRv10-persp.jpg + :alt: LCD160CRv1.0 picture + :width: 640px + +Further resources are available via the following links: + +* `LCD160CRv1.0 reference manual `_ (100KiB PDF) +* `LCD160CRv1.0 schematics `_ (1.6MiB PDF) + +class LCD160CR +-------------- + +The LCD160CR class provides an interface to the display. Create an +instance of this class and use its methods to draw to the LCD and get +the status of the touch panel. + +For example:: + + import lcd160cr + + lcd = lcd160cr.LCD160CR('X') + lcd.set_orient(lcd160cr.PORTRAIT) + lcd.set_pos(0, 0) + lcd.set_text_color(lcd.rgb(255, 0, 0), lcd.rgb(0, 0, 0)) + lcd.set_font(1) + lcd.write('Hello MicroPython!') + print('touch:', lcd.get_touch()) + +Constructors +------------ + +.. class:: LCD160CR(connect=None, \*, pwr=None, i2c=None, spi=None, i2c_addr=98) + + Construct an LCD160CR object. The parameters are: + + - *connect* is a string specifying the physical connection of the LCD + display to the board; valid values are "X", "Y", "XY", "YX". + Use "X" when the display is connected to a pyboard in the X-skin + position, and "Y" when connected in the Y-skin position. "XY" + and "YX" are used when the display is connected to the right or + left side of the pyboard, respectively. + - *pwr* is a Pin object connected to the LCD's power/enabled pin. + - *i2c* is an I2C object connected to the LCD's I2C interface. + - *spi* is an SPI object connected to the LCD's SPI interface. + - *i2c_addr* is the I2C address of the display. + + One must specify either a valid *connect* or all of *pwr*, *i2c* and *spi*. + If a valid *connect* is given then any of *pwr*, *i2c* or *spi* which are + not passed as parameters (i.e. they are ``None``) will be created based on the + value of *connect*. This allows to override the default interface to the + display if needed. + + The default values are: + + - "X" is for the X-skin and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")`` + - "Y" is for the Y-skin and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")`` + - "XY" is for the right-side and uses: + ``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")`` + - "YX" is for the left-side and uses: + ``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")`` + + See `this image `_ + for how the display can be connected to the pyboard. + +Static methods +-------------- + +.. staticmethod:: LCD160CR.rgb(r, g, b) + + Return a 16-bit integer representing the given rgb color values. The + 16-bit value can be used to set the font color (see + :meth:`LCD160CR.set_text_color`) pen color (see :meth:`LCD160CR.set_pen`) + and draw individual pixels. + +.. staticmethod:: LCD160CR.clip_line(data, w, h): + + Clip the given line data. This is for internal use. + +Instance members +---------------- + +The following instance members are publicly accessible. + +.. data:: LCD160CR.w +.. data:: LCD160CR.h + + The width and height of the display, respectively, in pixels. These + members are updated when calling :meth:`LCD160CR.set_orient` and should + be considered read-only. + +Setup commands +-------------- + +.. method:: LCD160CR.set_power(on) + + Turn the display on or off, depending on the given value of *on*: 0 or ``False`` + will turn the display off, and 1 or ``True`` will turn it on. + +.. method:: LCD160CR.set_orient(orient) + + Set the orientation of the display. The *orient* parameter can be one + of `PORTRAIT`, `LANDSCAPE`, `PORTRAIT_UPSIDEDOWN`, `LANDSCAPE_UPSIDEDOWN`. + +.. method:: LCD160CR.set_brightness(value) + + Set the brightness of the display, between 0 and 31. + +.. method:: LCD160CR.set_i2c_addr(addr) + + Set the I2C address of the display. The *addr* value must have the + lower 2 bits cleared. + +.. method:: LCD160CR.set_uart_baudrate(baudrate) + + Set the baudrate of the UART interface. + +.. method:: LCD160CR.set_startup_deco(value) + + Set the start-up decoration of the display. The *value* parameter can be a + logical or of `STARTUP_DECO_NONE`, `STARTUP_DECO_MLOGO`, `STARTUP_DECO_INFO`. + +.. method:: LCD160CR.save_to_flash() + + Save the following parameters to flash so they persist on restart and power up: + initial decoration, orientation, brightness, UART baud rate, I2C address. + +Pixel access methods +-------------------- + +The following methods manipulate individual pixels on the display. + +.. method:: LCD160CR.set_pixel(x, y, c) + + Set the specified pixel to the given color. The color should be a 16-bit + integer and can be created by :meth:`LCD160CR.rgb`. + +.. method:: LCD160CR.get_pixel(x, y) + + Get the 16-bit value of the specified pixel. + +.. method:: LCD160CR.get_line(x, y, buf) + + Low-level method to get a line of pixels into the given buffer. + To read *n* pixels *buf* should be *2*n+1* bytes in length. The first byte + is a dummy byte and should be ignored, and subsequent bytes represent the + pixels in the line starting at coordinate *(x, y)*. + +.. method:: LCD160CR.screen_dump(buf, x=0, y=0, w=None, h=None) + + Dump the contents of the screen to the given buffer. The parameters *x* and *y* + specify the starting coordinate, and *w* and *h* the size of the region. If *w* + or *h* are ``None`` then they will take on their maximum values, set by the size + of the screen minus the given *x* and *y* values. *buf* should be large enough + to hold ``2*w*h`` bytes. If it's smaller then only the initial horizontal lines + will be stored. + +.. method:: LCD160CR.screen_load(buf) + + Load the entire screen from the given buffer. + +Drawing text +------------ + +To draw text one sets the position, color and font, and then uses +`LCD160CR.write` to draw the text. + +.. method:: LCD160CR.set_pos(x, y) + + Set the position for text output using :meth:`LCD160CR.write`. The position + is the upper-left corner of the text. + +.. method:: LCD160CR.set_text_color(fg, bg) + + Set the foreground and background color of the text. + +.. method:: LCD160CR.set_font(font, scale=0, bold=0, trans=0, scroll=0) + + Set the font for the text. Subsequent calls to `write` will use the newly + configured font. The parameters are: + + - *font* is the font family to use, valid values are 0, 1, 2, 3. + - *scale* is a scaling value for each character pixel, where the pixels + are drawn as a square with side length equal to *scale + 1*. The value + can be between 0 and 63. + - *bold* controls the number of pixels to overdraw each character pixel, + making a bold effect. The lower 2 bits of *bold* are the number of + pixels to overdraw in the horizontal direction, and the next 2 bits are + for the vertical direction. For example, a *bold* value of 5 will + overdraw 1 pixel in both the horizontal and vertical directions. + - *trans* can be either 0 or 1 and if set to 1 the characters will be + drawn with a transparent background. + - *scroll* can be either 0 or 1 and if set to 1 the display will do a + soft scroll if the text moves to the next line. + +.. method:: LCD160CR.write(s) + + Write text to the display, using the current position, color and font. + As text is written the position is automatically incremented. The + display supports basic VT100 control codes such as newline and backspace. + +Drawing primitive shapes +------------------------ + +Primitive drawing commands use a foreground and background color set by the +`set_pen` method. + +.. method:: LCD160CR.set_pen(line, fill) + + Set the line and fill color for primitive shapes. + +.. method:: LCD160CR.erase() + + Erase the entire display to the pen fill color. + +.. method:: LCD160CR.dot(x, y) + + Draw a single pixel at the given location using the pen line color. + +.. method:: LCD160CR.rect(x, y, w, h) +.. method:: LCD160CR.rect_outline(x, y, w, h) +.. method:: LCD160CR.rect_interior(x, y, w, h) + + Draw a rectangle at the given location and size using the pen line + color for the outline, and the pen fill color for the interior. + The `rect` method draws the outline and interior, while the other methods + just draw one or the other. + +.. method:: LCD160CR.line(x1, y1, x2, y2) + + Draw a line between the given coordinates using the pen line color. + +.. method:: LCD160CR.dot_no_clip(x, y) +.. method:: LCD160CR.rect_no_clip(x, y, w, h) +.. method:: LCD160CR.rect_outline_no_clip(x, y, w, h) +.. method:: LCD160CR.rect_interior_no_clip(x, y, w, h) +.. method:: LCD160CR.line_no_clip(x1, y1, x2, y2) + + These methods are as above but don't do any clipping on the input + coordinates. They are faster than the clipping versions and can be + used when you know that the coordinates are within the display. + +.. method:: LCD160CR.poly_dot(data) + + Draw a sequence of dots using the pen line color. + The *data* should be a buffer of bytes, with each successive pair of + bytes corresponding to coordinate pairs (x, y). + +.. method:: LCD160CR.poly_line(data) + + Similar to :meth:`LCD160CR.poly_dot` but draws lines between the dots. + +Touch screen methods +-------------------- + +.. method:: LCD160CR.touch_config(calib=False, save=False, irq=None) + + Configure the touch panel: + + - If *calib* is ``True`` then the call will trigger a touch calibration of + the resistive touch sensor. This requires the user to touch various + parts of the screen. + - If *save* is ``True`` then the touch parameters will be saved to NVRAM + to persist across reset/power up. + - If *irq* is ``True`` then the display will be configured to pull the IRQ + line low when a touch force is detected. If *irq* is ``False`` then this + feature is disabled. If *irq* is ``None`` (the default value) then no + change is made to this setting. + +.. method:: LCD160CR.is_touched() + + Returns a boolean: ``True`` if there is currently a touch force on the screen, + ``False`` otherwise. + +.. method:: LCD160CR.get_touch() + + Returns a 3-tuple of: *(active, x, y)*. If there is currently a touch force + on the screen then *active* is 1, otherwise it is 0. The *x* and *y* values + indicate the position of the current or most recent touch. + +Advanced commands +----------------- + +.. method:: LCD160CR.set_spi_win(x, y, w, h) + + Set the window that SPI data is written to. + +.. method:: LCD160CR.fast_spi(flush=True) + + Ready the display to accept RGB pixel data on the SPI bus, resetting the location + of the first byte to go to the top-left corner of the window set by + :meth:`LCD160CR.set_spi_win`. + The method returns an SPI object which can be used to write the pixel data. + + Pixels should be sent as 16-bit RGB values in the 5-6-5 format. The destination + counter will increase as data is sent, and data can be sent in arbitrary sized + chunks. Once the destination counter reaches the end of the window specified by + :meth:`LCD160CR.set_spi_win` it will wrap around to the top-left corner of that window. + +.. method:: LCD160CR.show_framebuf(buf) + + Show the given buffer on the display. *buf* should be an array of bytes containing + the 16-bit RGB values for the pixels, and they will be written to the area + specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner. + + The `framebuf `_ module can be used to construct frame buffers + and provides drawing primitives. Using a frame buffer will improve + performance of animations when compared to drawing directly to the screen. + +.. method:: LCD160CR.set_scroll(on) + + Turn scrolling on or off. This controls globally whether any window regions will + scroll. + +.. method:: LCD160CR.set_scroll_win(win, x=-1, y=0, w=0, h=0, vec=0, pat=0, fill=0x07e0, color=0) + + Configure a window region for scrolling: + + - *win* is the window id to configure. There are 0..7 standard windows for + general purpose use. Window 8 is the text scroll window (the ticker). + - *x*, *y*, *w*, *h* specify the location of the window in the display. + - *vec* specifies the direction and speed of scroll: it is a 16-bit value + of the form ``0bF.ddSSSSSSSSSSSS``. *dd* is 0, 1, 2, 3 for +x, +y, -x, + -y scrolling. *F* sets the speed format, with 0 meaning that the window + is shifted *S % 256* pixel every frame, and 1 meaning that the window + is shifted 1 pixel every *S* frames. + - *pat* is a 16-bit pattern mask for the background. + - *fill* is the fill color. + - *color* is the extra color, either of the text or pattern foreground. + +.. method:: LCD160CR.set_scroll_win_param(win, param, value) + + Set a single parameter of a scrolling window region: + + - *win* is the window id, 0..8. + - *param* is the parameter number to configure, 0..7, and corresponds + to the parameters in the `set_scroll_win` method. + - *value* is the value to set. + +.. method:: LCD160CR.set_scroll_buf(s) + + Set the string for scrolling in window 8. The parameter *s* must be a string + with length 32 or less. + +.. method:: LCD160CR.jpeg(buf) + + Display a JPEG. *buf* should contain the entire JPEG data. JPEG data should + not include EXIF information. The following encodings are supported: Baseline + DCT, Huffman coding, 8 bits per sample, 3 color components, YCbCr4:2:2. + The origin of the JPEG is set by :meth:`LCD160CR.set_pos`. + +.. method:: LCD160CR.jpeg_start(total_len) +.. method:: LCD160CR.jpeg_data(buf) + + Display a JPEG with the data split across multiple buffers. There must be + a single call to `jpeg_start` to begin with, specifying the total number of + bytes in the JPEG. Then this number of bytes must be transferred to the + display using one or more calls to the `jpeg_data` command. + +.. method:: LCD160CR.feed_wdt() + + The first call to this method will start the display's internal watchdog + timer. Subsequent calls will feed the watchdog. The timeout is roughly 30 + seconds. + +.. method:: LCD160CR.reset() + + Reset the display. + +Constants +--------- + +.. data:: lcd160cr.PORTRAIT + lcd160cr.LANDSCAPE + lcd160cr.PORTRAIT_UPSIDEDOWN + lcd160cr.LANDSCAPE_UPSIDEDOWN + + Orientations of the display, used by :meth:`LCD160CR.set_orient`. + +.. data:: lcd160cr.STARTUP_DECO_NONE + lcd160cr.STARTUP_DECO_MLOGO + lcd160cr.STARTUP_DECO_INFO + + Types of start-up decoration, can be OR'ed together, used by + :meth:`LCD160CR.set_startup_deco`. diff --git a/src/openmv/src/micropython/docs/library/machine.ADC.rst b/src/openmv/src/micropython/docs/library/machine.ADC.rst new file mode 100755 index 0000000..4c7a04d --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.ADC.rst @@ -0,0 +1,74 @@ +.. currentmodule:: machine +.. _machine.ADC: + +class ADC -- analog to digital conversion +========================================= + +Usage:: + + import machine + + adc = machine.ADC() # create an ADC object + apin = adc.channel(pin='GP3') # create an analog pin on GP3 + val = apin() # read an analog value + +Constructors +------------ + +.. class:: ADC(id=0, \*, bits=12) + + Create an ADC object associated with the given pin. + This allows you to then read analog values on that pin. + For more info check the `pinout and alternate functions + table. `_ + + .. warning:: + + ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it + can withstand). When GP2, GP3, GP4 or GP5 are remapped to the + ADC block, 1.8 V is the maximum. If these pins are used in digital mode, + then the maximum allowed input is 3.6V. + +Methods +------- + +.. method:: ADC.channel(id, \*, pin) + + Create an analog pin. If only channel ID is given, the correct pin will + be selected. Alternatively, only the pin can be passed and the correct + channel will be selected. Examples:: + + # all of these are equivalent and enable ADC channel 1 on GP3 + apin = adc.channel(1) + apin = adc.channel(pin='GP3') + apin = adc.channel(id=1, pin='GP3') + +.. method:: ADC.init() + + Enable the ADC block. + +.. method:: ADC.deinit() + + Disable the ADC block. + +class ADCChannel --- read analog values from internal or external sources +========================================================================= + +ADC channels can be connected to internal points of the MCU or to GPIO pins. +ADC channels are created using the ADC.channel method. + +.. method:: adcchannel() + + Fast method to read the channel value. + +.. method:: adcchannel.value() + + Read the channel value. + +.. method:: adcchannel.init() + + Re-init (and effectively enable) the ADC channel. + +.. method:: adcchannel.deinit() + + Disable the ADC channel. diff --git a/src/openmv/src/micropython/docs/library/machine.I2C.rst b/src/openmv/src/micropython/docs/library/machine.I2C.rst new file mode 100755 index 0000000..71ca9b0 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.I2C.rst @@ -0,0 +1,166 @@ +.. currentmodule:: machine +.. _machine.I2C: + +class I2C -- a two-wire serial protocol +======================================= + +I2C is a two-wire protocol for communicating between devices. At the physical +level it consists of 2 wires: SCL and SDA, the clock and data lines respectively. + +I2C objects are created attached to a specific bus. They can be initialised +when created, or initialised later on. + +Printing the I2C object gives you information about its configuration. + +Example usage:: + + from machine import I2C + + i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz + # depending on the port, extra parameters may be required + # to select the peripheral and/or pins to use + + i2c.scan() # scan for slaves, returning a list of 7-bit addresses + + i2c.writeto(42, b'123') # write 3 bytes to slave with 7-bit address 42 + i2c.readfrom(42, 4) # read 4 bytes from slave with 7-bit address 42 + + i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of slave 42, + # starting at memory-address 8 in the slave + i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of slave 42 + # starting at address 2 in the slave + +Constructors +------------ + +.. class:: I2C(id=-1, \*, scl, sda, freq=400000) + + Construct and return a new I2C object using the following parameters: + + - *id* identifies a particular I2C peripheral. The default + value of -1 selects a software implementation of I2C which can + work (in most cases) with arbitrary pins for SCL and SDA. + If *id* is -1 then *scl* and *sda* must be specified. Other + allowed values for *id* depend on the particular port/board, + and specifying *scl* and *sda* may or may not be required or + allowed in this case. + - *scl* should be a pin object specifying the pin to use for SCL. + - *sda* should be a pin object specifying the pin to use for SDA. + - *freq* should be an integer which sets the maximum frequency + for SCL. + +General Methods +--------------- + +.. method:: I2C.init(scl, sda, \*, freq=400000) + + Initialise the I2C bus with the given arguments: + + - *scl* is a pin object for the SCL line + - *sda* is a pin object for the SDA line + - *freq* is the SCL clock rate + +.. method:: I2C.deinit() + + Turn off the I2C bus. + + Availability: WiPy. + +.. method:: I2C.scan() + + Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of + those that respond. A device responds if it pulls the SDA line low after + its address (including a write bit) is sent on the bus. + +Primitive I2C operations +------------------------ + +The following methods implement the primitive I2C master bus operations and can +be combined to make any I2C transaction. They are provided if you need more +control over the bus, otherwise the standard methods (see below) can be used. + +These methods are available on software I2C only. + +.. method:: I2C.start() + + Generate a START condition on the bus (SDA transitions to low while SCL is high). + +.. method:: I2C.stop() + + Generate a STOP condition on the bus (SDA transitions to high while SCL is high). + +.. method:: I2C.readinto(buf, nack=True) + + Reads bytes from the bus and stores them into *buf*. The number of bytes + read is the length of *buf*. An ACK will be sent on the bus after + receiving all but the last byte. After the last byte is received, if *nack* + is true then a NACK will be sent, otherwise an ACK will be sent (and in this + case the slave assumes more bytes are going to be read in a later call). + +.. method:: I2C.write(buf) + + Write the bytes from *buf* to the bus. Checks that an ACK is received + after each byte and stops transmitting the remaining bytes if a NACK is + received. The function returns the number of ACKs that were received. + +Standard bus operations +----------------------- + +The following methods implement the standard I2C master read and write +operations that target a given slave device. + +.. method:: I2C.readfrom(addr, nbytes, stop=True) + + Read *nbytes* from the slave specified by *addr*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + Returns a `bytes` object with the data read. + +.. method:: I2C.readfrom_into(addr, buf, stop=True) + + Read into *buf* from the slave specified by *addr*. + The number of bytes read will be the length of *buf*. + If *stop* is true then a STOP condition is generated at the end of the transfer. + + The method returns ``None``. + +.. method:: I2C.writeto(addr, buf, stop=True) + + Write the bytes from *buf* to the slave specified by *addr*. If a + NACK is received following the write of a byte from *buf* then the + remaining bytes are not sent. If *stop* is true then a STOP condition is + generated at the end of the transfer, even if a NACK is received. + The function returns the number of ACKs that were received. + +Memory operations +----------------- + +Some I2C devices act as a memory device (or set of registers) that can be read +from and written to. In this case there are two addresses associated with an +I2C transaction: the slave address and the memory address. The following +methods are convenience functions to communicate with such devices. + +.. method:: I2C.readfrom_mem(addr, memaddr, nbytes, \*, addrsize=8) + + Read *nbytes* from the slave specified by *addr* starting from the memory + address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits. + Returns a `bytes` object with the data read. + +.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8) + + Read into *buf* from the slave specified by *addr* starting from the + memory address specified by *memaddr*. The number of bytes read is the + length of *buf*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. + +.. method:: I2C.writeto_mem(addr, memaddr, buf, \*, addrsize=8) + + Write *buf* to the slave specified by *addr* starting from the + memory address specified by *memaddr*. + The argument *addrsize* specifies the address size in bits (on ESP8266 + this argument is not recognised and the address size is always 8 bits). + + The method returns ``None``. diff --git a/src/openmv/src/micropython/docs/library/machine.Pin.rst b/src/openmv/src/micropython/docs/library/machine.Pin.rst new file mode 100755 index 0000000..a355a6f --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.Pin.rst @@ -0,0 +1,253 @@ +.. currentmodule:: machine +.. _machine.Pin: + +class Pin -- control I/O pins +============================= + +A pin object is used to control I/O pins (also known as GPIO - general-purpose +input/output). Pin objects are commonly associated with a physical pin that can +drive an output voltage and read input voltages. The pin class has methods to set the mode of +the pin (IN, OUT, etc) and methods to get and set the digital logic level. +For analog control of a pin, see the :class:`ADC` class. + +A pin object is constructed by using an identifier which unambiguously +specifies a certain I/O pin. The allowed forms of the identifier and the +physical pin that the identifier maps to are port-specific. Possibilities +for the identifier are an integer, a string or a tuple with port and pin +number. + +Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode + p0.mode(p0.IN) + + # configure an irq callback + p0.irq(lambda p:print(p)) + +Constructors +------------ + +.. class:: Pin(id, mode=-1, pull=-1, \*, value, drive, alt) + + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. + +Methods +------- + +.. method:: Pin.init(mode=-1, pull=-1, \*, value, drive, alt) + + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. + + Returns ``None``. + +.. method:: Pin.value([x]) + + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. + + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: + + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. + + When setting the value this method returns ``None``. + +.. method:: Pin.__call__([x]) + + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. + +.. method:: Pin.on() + + Set pin to "1" output level. + +.. method:: Pin.off() + + Set pin to "0" output level. + +.. method:: Pin.mode([mode]) + + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. + +.. method:: Pin.pull([pull]) + + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. + +.. method:: Pin.drive([drive]) + + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. + + Not all ports implement this method. + + Availability: WiPy. + +.. method:: Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), \*, priority=1, wake=None, hard=False) + + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. The handler must take exactly one argument which is the + ``Pin`` instance. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + - ``hard`` if true a hardware interrupt is used. This reduces the delay + between the pin change and the handler being called. Hard interrupt + handlers may not allocate memory; see :ref:`isr_rules`. + + This method returns a callback object. + +Constants +--------- + +The following constants are used to configure the pin objects. Note that +not all constants are available on all ports. + +.. data:: Pin.IN + Pin.OUT + Pin.OPEN_DRAIN + Pin.ALT + Pin.ALT_OPEN_DRAIN + + Selects the pin mode. + +.. data:: Pin.PULL_UP + Pin.PULL_DOWN + + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. + +.. data:: Pin.LOW_POWER + Pin.MED_POWER + Pin.HIGH_POWER + + Selects the pin drive strength. + +.. data:: Pin.IRQ_FALLING + Pin.IRQ_RISING + Pin.IRQ_LOW_LEVEL + Pin.IRQ_HIGH_LEVEL + + Selects the IRQ trigger type. diff --git a/src/openmv/src/micropython/docs/library/machine.RTC.rst b/src/openmv/src/micropython/docs/library/machine.RTC.rst new file mode 100755 index 0000000..95fa2b4 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.RTC.rst @@ -0,0 +1,69 @@ +.. currentmodule:: machine +.. _machine.RTC: + +class RTC -- real time clock +============================ + +The RTC is and independent clock that keeps track of the date +and time. + +Example usage:: + + rtc = machine.RTC() + rtc.init((2014, 5, 1, 4, 13, 0, 0, 0)) + print(rtc.now()) + + +Constructors +------------ + +.. class:: RTC(id=0, ...) + + Create an RTC object. See init for parameters of initialization. + +Methods +------- + +.. method:: RTC.init(datetime) + + Initialise the RTC. Datetime is a tuple of the form: + + ``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])`` + +.. method:: RTC.now() + + Get get the current datetime tuple. + +.. method:: RTC.deinit() + + Resets the RTC to the time of January 1, 2015 and starts running it again. + +.. method:: RTC.alarm(id, time, \*, repeat=False) + + Set the RTC alarm. Time might be either a millisecond value to program the alarm to + current time + time_in_ms in the future, or a datetimetuple. If the time passed is in + milliseconds, repeat can be set to ``True`` to make the alarm periodic. + +.. method:: RTC.alarm_left(alarm_id=0) + + Get the number of milliseconds left before the alarm expires. + +.. method:: RTC.cancel(alarm_id=0) + + Cancel a running alarm. + +.. method:: RTC.irq(\*, trigger, handler=None, wake=machine.IDLE) + + Create an irq object triggered by a real time clock alarm. + + - ``trigger`` must be ``RTC.ALARM0`` + - ``handler`` is the function to be called when the callback is triggered. + - ``wake`` specifies the sleep mode from where this interrupt can wake + up the system. + +Constants +--------- + +.. data:: RTC.ALARM0 + + irq trigger source diff --git a/src/openmv/src/micropython/docs/library/machine.SD.rst b/src/openmv/src/micropython/docs/library/machine.SD.rst new file mode 100755 index 0000000..9c58e73 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.SD.rst @@ -0,0 +1,47 @@ +.. currentmodule:: machine +.. _machine.SD: + +class SD -- secure digital memory card +====================================== + +.. warning:: + + This is a non-standard class and is only available on the cc3200 port. + + +The SD card class allows to configure and enable the memory card +module of the WiPy and automatically mount it as ``/sd`` as part +of the file system. There are several pin combinations that can be +used to wire the SD card socket to the WiPy and the pins used can +be specified in the constructor. Please check the `pinout and alternate functions +table. `_ for +more info regarding the pins which can be remapped to be used with a SD card. + +Example usage:: + + from machine import SD + import os + # clk cmd and dat0 pins must be passed along with + # their respective alternate functions + sd = machine.SD(pins=('GP10', 'GP11', 'GP15')) + os.mount(sd, '/sd') + # do normal file operations + +Constructors +------------ + +.. class:: SD(id,... ) + + Create a SD card object. See ``init()`` for parameters if initialization. + +Methods +------- + +.. method:: SD.init(id=0, pins=('GP10', 'GP11', 'GP15')) + + Enable the SD card. In order to initialize the card, give it a 3-tuple: + ``(clk_pin, cmd_pin, dat0_pin)``. + +.. method:: SD.deinit() + + Disable the SD card. diff --git a/src/openmv/src/micropython/docs/library/machine.SPI.rst b/src/openmv/src/micropython/docs/library/machine.SPI.rst new file mode 100755 index 0000000..a9fcc71 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.SPI.rst @@ -0,0 +1,101 @@ +.. currentmodule:: machine +.. _machine.SPI: + +class SPI -- a Serial Peripheral Interface bus protocol (master side) +===================================================================== + +SPI is a synchronous serial protocol that is driven by a master. At the +physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices +can share the same bus. Each device should have a separate, 4th signal, +SS (Slave Select), to select a particular device on a bus with which +communication takes place. Management of an SS signal should happen in +user code (via machine.Pin class). + +Constructors +------------ + +.. class:: SPI(id, ...) + + Construct an SPI object on the given bus, ``id``. Values of ``id`` depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. Value -1 can be used for + bitbanging (software) implementation of SPI (if supported by a port). + + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + +Methods +------- + +.. method:: SPI.init(baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None, pins=(SCK, MOSI, MISO)) + + Initialise the SPI bus with the given parameters: + + - ``baudrate`` is the SCK clock rate. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` parameter. + + In the case of hardware SPI the actual clock frequency may be lower than the + requested baudrate. This is dependant on the platform hardware. The actual + rate may be determined by printing the SPI object. + +.. method:: SPI.deinit() + + Turn off the SPI bus. + +.. method:: SPI.read(nbytes, write=0x00) + + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + +.. method:: SPI.readinto(buf, write=0x00) + + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + +.. method:: SPI.write(buf) + + Write the bytes contained in ``buf``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + +.. method:: SPI.write_readinto(write_buf, read_buf) + + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the + same length. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. + +Constants +--------- + +.. data:: SPI.MASTER + + for initialising the SPI bus to master; this is only used for the WiPy + +.. data:: SPI.MSB + + set the first bit to be the most significant bit + +.. data:: SPI.LSB + + set the first bit to be the least significant bit diff --git a/src/openmv/src/micropython/docs/library/machine.Signal.rst b/src/openmv/src/micropython/docs/library/machine.Signal.rst new file mode 100755 index 0000000..a1a2916 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.Signal.rst @@ -0,0 +1,123 @@ +.. currentmodule:: machine +.. _machine.Signal: + +class Signal -- control and sense external I/O devices +====================================================== + +The Signal class is a simple extension of the `Pin` class. Unlike Pin, which +can be only in "absolute" 0 and 1 states, a Signal can be in "asserted" +(on) or "deasserted" (off) states, while being inverted (active-low) or +not. In other words, it adds logical inversion support to Pin functionality. +While this may seem a simple addition, it is exactly what is needed to +support wide array of simple digital devices in a way portable across +different boards, which is one of the major MicroPython goals. Regardless +of whether different users have an active-high or active-low LED, a normally +open or normally closed relay - you can develop a single, nicely looking +application which works with each of them, and capture hardware +configuration differences in few lines in the config file of your app. + +Example:: + + from machine import Pin, Signal + + # Suppose you have an active-high LED on pin 0 + led1_pin = Pin(0, Pin.OUT) + # ... and active-low LED on pin 1 + led2_pin = Pin(1, Pin.OUT) + + # Now to light up both of them using Pin class, you'll need to set + # them to different values + led1_pin.value(1) + led2_pin.value(0) + + # Signal class allows to abstract away active-high/active-low + # difference + led1 = Signal(led1_pin, invert=False) + led2 = Signal(led2_pin, invert=True) + + # Now lighting up them looks the same + led1.value(1) + led2.value(1) + + # Even better: + led1.on() + led2.on() + +Following is the guide when Signal vs Pin should be used: + +* Use Signal: If you want to control a simple on/off (including software + PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or + read simple binary sensors, like normally open or normally closed buttons, + pulled high or low, Reed switches, moisture/flame detectors, etc. etc. + Summing up, if you have a real physical device/sensor requiring GPIO + access, you likely should use a Signal. + +* Use Pin: If you implement a higher-level protocol or bus to communicate + with more complex devices. + +The split between Pin and Signal come from the usecases above and the +architecture of MicroPython: Pin offers the lowest overhead, which may +be important when bit-banging protocols. But Signal adds additional +flexibility on top of Pin, at the cost of minor overhead (much smaller +than if you implemented active-high vs active-low device differences in +Python manually!). Also, Pin is a low-level object which needs to be +implemented for each support board, while Signal is a high-level object +which comes for free once Pin is implemented. + +If in doubt, give the Signal a try! Once again, it is offered to save +developers from the need to handle unexciting differences like active-low +vs active-high signals, and allow other users to share and enjoy your +application, instead of being frustrated by the fact that it doesn't +work for them simply because their LEDs or relays are wired in a slightly +different way. + +Constructors +------------ + +.. class:: Signal(pin_obj, invert=False) + Signal(pin_arguments..., \*, invert=False) + + Create a Signal object. There're two ways to create it: + + * By wrapping existing Pin object - universal method which works for + any board. + * By passing required Pin parameters directly to Signal constructor, + skipping the need to create intermediate Pin object. Available on + many, but not all boards. + + The arguments are: + + - ``pin_obj`` is existing Pin object. + + - ``pin_arguments`` are the same arguments as can be passed to Pin constructor. + + - ``invert`` - if True, the signal will be inverted (active low). + +Methods +------- + +.. method:: Signal.value([x]) + + This method allows to set and get the value of the signal, depending on whether + the argument ``x`` is supplied or not. + + If the argument is omitted then this method gets the signal level, 1 meaning + signal is asserted (active) and 0 - signal inactive. + + If the argument is supplied then this method sets the signal level. The + argument ``x`` can be anything that converts to a boolean. If it converts + to ``True``, the signal is active, otherwise it is inactive. + + Correspondence between signal being active and actual logic level on the + underlying pin depends on whether signal is inverted (active-low) or not. + For non-inverted signal, active status corresponds to logical 1, inactive - + to logical 0. For inverted/active-low signal, active status corresponds + to logical 0, while inactive - to logical 1. + +.. method:: Signal.on() + + Activate signal. + +.. method:: Signal.off() + + Deactivate signal. diff --git a/src/openmv/src/micropython/docs/library/machine.Timer.rst b/src/openmv/src/micropython/docs/library/machine.Timer.rst new file mode 100755 index 0000000..b16ad52 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.Timer.rst @@ -0,0 +1,64 @@ +.. currentmodule:: machine +.. _machine.Timer: + +class Timer -- control hardware timers +====================================== + +Hardware timers deal with timing of periods and events. Timers are perhaps +the most flexible and heterogeneous kind of hardware in MCUs and SoCs, +differently greatly from a model to a model. MicroPython's Timer class +defines a baseline operation of executing a callback with a given period +(or once after some delay), and allow specific boards to define more +non-standard behavior (which thus won't be portable to other boards). + +See discussion of :ref:`important constraints ` on +Timer callbacks. + +.. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + +If you are using a WiPy board please refer to :ref:`machine.TimerWiPy ` +instead of this class. + +Constructors +------------ + +.. class:: Timer(id, ...) + + Construct a new timer object of the given id. Id of -1 constructs a + virtual timer (if supported by a board). + +Methods +------- + +.. method:: Timer.init(\*, mode=Timer.PERIODIC, period=-1, callback=None) + + Initialise the timer. Example:: + + tim.init(period=100) # periodic with 100ms period + tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``Timer.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + +.. method:: Timer.deinit() + + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + +Constants +--------- + +.. data:: Timer.ONE_SHOT + Timer.PERIODIC + + Timer operating mode. diff --git a/src/openmv/src/micropython/docs/library/machine.TimerWiPy.rst b/src/openmv/src/micropython/docs/library/machine.TimerWiPy.rst new file mode 100755 index 0000000..abbcc28 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.TimerWiPy.rst @@ -0,0 +1,159 @@ +.. currentmodule:: machine +.. _machine.TimerWiPy: + +class TimerWiPy -- control hardware timers +========================================== + +.. note:: + + This class is a non-standard Timer implementation for the WiPy. + It is available simply as ``machine.Timer`` on the WiPy but is named in the + documentation below as ``machine.TimerWiPy`` to distinguish it from the + more general :ref:`machine.Timer ` class. + +Hardware timers deal with timing of periods and events. Timers are perhaps +the most flexible and heterogeneous kind of hardware in MCUs and SoCs, +differently greatly from a model to a model. MicroPython's Timer class +defines a baseline operation of executing a callback with a given period +(or once after some delay), and allow specific boards to define more +non-standard behavior (which thus won't be portable to other boards). + +See discussion of :ref:`important constraints ` on +Timer callbacks. + +.. note:: + + Memory can't be allocated inside irq handlers (an interrupt) and so + exceptions raised within a handler don't give much information. See + :func:`micropython.alloc_emergency_exception_buf` for how to get around this + limitation. + +Constructors +------------ + +.. class:: TimerWiPy(id, ...) + + Construct a new timer object of the given id. Id of -1 constructs a + virtual timer (if supported by a board). + +Methods +------- + +.. method:: TimerWiPy.init(mode, \*, width=16) + + Initialise the timer. Example:: + + tim.init(Timer.PERIODIC) # periodic 16-bit timer + tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer + + Keyword arguments: + + - ``mode`` can be one of: + + - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured + period of the channel expires. + - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured + frequency of the channel. + - ``TimerWiPy.PWM`` - Output a PWM signal on a pin. + + - ``width`` must be either 16 or 32 (bits). For really low frequencies < 5Hz + (or large periods), 32-bit timers should be used. 32-bit mode is only available + for ``ONE_SHOT`` AND ``PERIODIC`` modes. + +.. method:: TimerWiPy.deinit() + + Deinitialises the timer. Stops the timer, and disables the timer peripheral. + +.. method:: TimerWiPy.channel(channel, \**, freq, period, polarity=TimerWiPy.POSITIVE, duty_cycle=0) + + If only a channel identifier passed, then a previously initialized channel + object is returned (or ``None`` if there is no previous channel). + + Otherwise, a TimerChannel object is initialized and returned. + + The operating mode is is the one configured to the Timer object that was used to + create the channel. + + - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``. + If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``. + + Keyword only arguments: + + - ``freq`` sets the frequency in Hz. + - ``period`` sets the period in microseconds. + + .. note:: + + Either ``freq`` or ``period`` must be given, never both. + + - ``polarity`` this is applicable for ``PWM``, and defines the polarity of the duty cycle + - ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0.00-100.00). Since the WiPy + doesn't support floating point numbers the duty cycle must be specified in the range 0-10000, + where 10000 would represent 100.00, 5050 represents 50.50, and so on. + + .. note:: + + When the channel is in PWM mode, the corresponding pin is assigned automatically, therefore + there's no need to assign the alternate function of the pin via the ``Pin`` class. The pins which + support PWM functionality are the following: + + - ``GP24`` on Timer 0 channel A. + - ``GP25`` on Timer 1 channel A. + - ``GP9`` on Timer 2 channel B. + - ``GP10`` on Timer 3 channel A. + - ``GP11`` on Timer 3 channel B. + +class TimerChannel --- setup a channel for a timer +================================================== + +Timer channels are used to generate/capture a signal using a timer. + +TimerChannel objects are created using the Timer.channel() method. + +Methods +------- + +.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None) + + The behavior of this callback is heavily dependent on the operating + mode of the timer channel: + + - If mode is ``TimerWiPy.PERIODIC`` the callback is executed periodically + with the configured frequency or period. + - If mode is ``TimerWiPy.ONE_SHOT`` the callback is executed once when + the configured timer expires. + - If mode is ``TimerWiPy.PWM`` the callback is executed when reaching the duty + cycle value. + + The accepted params are: + + - ``priority`` level of the interrupt. Can take values in the range 1-7. + Higher values represent higher priorities. + - ``handler`` is an optional function to be called when the interrupt is triggered. + - ``trigger`` must be ``TimerWiPy.TIMEOUT`` when the operating mode is either ``TimerWiPy.PERIODIC`` or + ``TimerWiPy.ONE_SHOT``. In the case that mode is ``TimerWiPy.PWM`` then trigger must be equal to + ``TimerWiPy.MATCH``. + + Returns a callback object. + +.. method:: timerchannel.freq([value]) + + Get or set the timer channel frequency (in Hz). + +.. method:: timerchannel.period([value]) + + Get or set the timer channel period (in microseconds). + +.. method:: timerchannel.duty_cycle([value]) + + Get or set the duty cycle of the PWM signal. It's a percentage (0.00-100.00). Since the WiPy + doesn't support floating point numbers the duty cycle must be specified in the range 0-10000, + where 10000 would represent 100.00, 5050 represents 50.50, and so on. + +Constants +--------- + +.. data:: TimerWiPy.ONE_SHOT +.. data:: TimerWiPy.PERIODIC + + Timer operating mode. diff --git a/src/openmv/src/micropython/docs/library/machine.UART.rst b/src/openmv/src/micropython/docs/library/machine.UART.rst new file mode 100755 index 0000000..5fcdc27 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.UART.rst @@ -0,0 +1,152 @@ +.. currentmodule:: machine +.. _machine.UART: + +class UART -- duplex serial communication bus +============================================= + +UART implements the standard UART/USART duplex serial communications protocol. At +the physical level it consists of 2 lines: RX and TX. The unit of communication +is a character (not to be confused with a string character) which can be 8 or 9 +bits wide. + +UART objects can be created and initialised using:: + + from machine import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + +Supported parameters differ on a board: + +Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*, +only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits +are supported. + +WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. + +A UART object acts like a `stream` object and reading and writing is done +using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + +Constructors +------------ + +.. class:: UART(id, ...) + + Construct a UART object of the given id. + +Methods +------- + +.. method:: UART.init(baudrate=9600, bits=8, parity=None, stop=1, \*, ...) + + Initialise the UART bus with the given parameters: + + - *baudrate* is the clock rate. + - *bits* is the number of bits per character, 7, 8 or 9. + - *parity* is the parity, ``None``, 0 (even) or 1 (odd). + - *stop* is the number of stop bits, 1 or 2. + + Additional keyword-only parameters that may be supported by a port are: + + - *tx* specifies the TX pin to use. + - *rx* specifies the RX pin to use. + - *txbuf* specifies the length in characters of the TX buffer. + - *rxbuf* specifies the length in characters of the RX buffer. + + On the WiPy only the following keyword-only parameter is supported: + + - *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). + Any of the pins can be None if one wants the UART to operate with limited functionality. + If the RTS pin is given the the RX pin must be given as well. The same applies to CTS. + When no pins are given, then the default set of TX and RX pins is taken, and hardware + flow control will be disabled. If *pins* is ``None``, no pin assignment will be made. + +.. method:: UART.deinit() + + Turn off the UART bus. + +.. method:: UART.any() + + Returns an integer counting the number of characters that can be read without + blocking. It will return 0 if there are no characters available and a positive + number if there are characters. The method may return 1 even if there is more + than one character available for reading. + + For more sophisticated querying of available characters use select.poll:: + + poll = select.poll() + poll.register(uart, select.POLLIN) + poll.poll(timeout) + +.. method:: UART.read([nbytes]) + + Read characters. If ``nbytes`` is specified then read at most that many bytes, + otherwise read as much data as possible. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + +.. method:: UART.readinto(buf[, nbytes]) + + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + +.. method:: UART.readline() + + Read a line, ending in a newline character. + + Return value: the line read or ``None`` on timeout. + +.. method:: UART.write(buf) + + Write the buffer of bytes to the bus. + + Return value: number of bytes written or ``None`` on timeout. + +.. method:: UART.sendbreak() + + Send a break condition on the bus. This drives the bus low for a duration + longer than required for a normal transmission of a character. + +.. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE) + + Create a callback to be triggered when data is received on the UART. + + - *trigger* can only be ``UART.RX_ANY`` + - *priority* level of the interrupt. Can take values in the range 1-7. + Higher values represent higher priorities. + - *handler* an optional function to be called when new characters arrive. + - *wake* can only be ``machine.IDLE``. + + .. note:: + + The handler will be called whenever any of the following two conditions are met: + + - 8 new characters have been received. + - At least 1 new character is waiting in the Rx buffer and the Rx line has been + silent for the duration of 1 complete frame. + + This means that when the handler function is called there will be between 1 to 8 + characters waiting. + + Returns an irq object. + + Availability: WiPy. + +Constants +--------- + +.. data:: UART.RX_ANY + + IRQ trigger sources + + Availability: WiPy. diff --git a/src/openmv/src/micropython/docs/library/machine.WDT.rst b/src/openmv/src/micropython/docs/library/machine.WDT.rst new file mode 100755 index 0000000..5ca6dce --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.WDT.rst @@ -0,0 +1,36 @@ +.. currentmodule:: machine +.. _machine.WDT: + +class WDT -- watchdog timer +=========================== + +The WDT is used to restart the system when the application crashes and ends +up into a non recoverable state. Once started it cannot be stopped or +reconfigured in any way. After enabling, the application must "feed" the +watchdog periodically to prevent it from expiring and resetting the system. + +Example usage:: + + from machine import WDT + wdt = WDT(timeout=2000) # enable it with a timeout of 2s + wdt.feed() + +Availability of this class: pyboard, WiPy. + +Constructors +------------ + +.. class:: WDT(id=0, timeout=5000) + + Create a WDT object and start it. The timeout must be given in seconds and + the minimum value that is accepted is 1 second. Once it is running the timeout + cannot be changed and the WDT cannot be stopped either. + +Methods +------- + +.. method:: wdt.feed() + + Feed the WDT to prevent it from resetting the system. The application + should place this call in a sensible place ensuring that the WDT is + only fed after verifying that everything is functioning correctly. diff --git a/src/openmv/src/micropython/docs/library/machine.rst b/src/openmv/src/micropython/docs/library/machine.rst new file mode 100755 index 0000000..f734ccc --- /dev/null +++ b/src/openmv/src/micropython/docs/library/machine.rst @@ -0,0 +1,155 @@ +:mod:`machine` --- functions related to the hardware +==================================================== + +.. module:: machine + :synopsis: functions related to the hardware + +The ``machine`` module contains specific functions related to the hardware +on a particular board. Most functions in this module allow to achieve direct +and unrestricted access to and control of hardware blocks on a system +(like CPU, timers, buses, etc.). Used incorrectly, this can lead to +malfunction, lockups, crashes of your board, and in extreme cases, hardware +damage. + +.. _machine_callbacks: + +A note of callbacks used by functions and class methods of :mod:`machine` module: +all these callbacks should be considered as executing in an interrupt context. +This is true for both physical devices with IDs >= 0 and "virtual" devices +with negative IDs like -1 (these "virtual" devices are still thin shims on +top of real hardware and real hardware interrupts). See :ref:`isr_rules`. + +Reset related functions +----------------------- + +.. function:: reset() + + Resets the device in a manner similar to pushing the external RESET + button. + +.. function:: reset_cause() + + Get the reset cause. See :ref:`constants ` for the possible return values. + +Interrupt related functions +--------------------------- + +.. function:: disable_irq() + + Disable interrupt requests. + Returns the previous IRQ state which should be considered an opaque value. + This return value should be passed to the `enable_irq()` function to restore + interrupts to their original state, before `disable_irq()` was called. + +.. function:: enable_irq(state) + + Re-enable interrupt requests. + The *state* parameter should be the value that was returned from the most + recent call to the `disable_irq()` function. + +Power related functions +----------------------- + +.. function:: freq() + + Returns CPU frequency in hertz. + +.. function:: idle() + + Gates the clock to the CPU, useful to reduce power consumption at any time during + short or long periods. Peripherals continue working and execution resumes as soon + as any interrupt is triggered (on many ports this includes system timer + interrupt occurring at regular intervals on the order of millisecond). + +.. function:: sleep() + + Stops the CPU and disables all peripherals except for WLAN. Execution is resumed from + the point where the sleep was requested. For wake up to actually happen, wake sources + should be configured first. + +.. function:: deepsleep() + + Stops the CPU and all peripherals (including networking interfaces, if any). Execution + is resumed from the main script, just as with a reset. The reset cause can be checked + to know that we are coming from `machine.DEEPSLEEP`. For wake up to actually happen, + wake sources should be configured first, like `Pin` change or `RTC` timeout. + +.. function:: wake_reason() + + Get the wake reason. See :ref:`constants ` for the possible return values. + + Availability: ESP32, WiPy. + +Miscellaneous functions +----------------------- + +.. function:: unique_id() + + Returns a byte string with a unique identifier of a board/SoC. It will vary + from a board/SoC instance to another, if underlying hardware allows. Length + varies by hardware (so use substring of a full value if you expect a short + ID). In some MicroPython ports, ID corresponds to the network MAC address. + +.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000) + + Time a pulse on the given *pin*, and return the duration of the pulse in + microseconds. The *pulse_level* argument should be 0 to time a low pulse + or 1 to time a high pulse. + + If the current input value of the pin is different to *pulse_level*, + the function first (*) waits until the pin input becomes equal to *pulse_level*, + then (**) times the duration that the pin is equal to *pulse_level*. + If the pin is already equal to *pulse_level* then timing starts straight away. + + The function will return -2 if there was timeout waiting for condition marked + (*) above, and -1 if there was timeout during the main measurement, marked (**) + above. The timeout is the same for both cases and given by *timeout_us* (which + is in microseconds). + +.. function:: rng() + + Return a 24-bit software generated random number. + + Availability: WiPy. + +.. _machine_constants: + +Constants +--------- + +.. data:: machine.IDLE + machine.SLEEP + machine.DEEPSLEEP + + IRQ wake values. + +.. data:: machine.PWRON_RESET + machine.HARD_RESET + machine.WDT_RESET + machine.DEEPSLEEP_RESET + machine.SOFT_RESET + + Reset causes. + +.. data:: machine.WLAN_WAKE + machine.PIN_WAKE + machine.RTC_WAKE + + Wake-up reasons. + +Classes +------- + +.. toctree:: + :maxdepth: 1 + + machine.Pin.rst + machine.Signal.rst + machine.ADC.rst + machine.UART.rst + machine.SPI.rst + machine.I2C.rst + machine.RTC.rst + machine.Timer.rst + machine.WDT.rst + machine.SD.rst diff --git a/src/openmv/src/micropython/docs/library/math.rst b/src/openmv/src/micropython/docs/library/math.rst new file mode 100755 index 0000000..a6f13d4 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/math.rst @@ -0,0 +1,185 @@ +:mod:`math` -- mathematical functions +===================================== + +.. module:: math + :synopsis: mathematical functions + +|see_cpython_module| :mod:`python:math`. + +The ``math`` module provides some basic mathematical functions for +working with floating-point numbers. + +*Note:* On the pyboard, floating-point numbers have 32-bit precision. + +Availability: not available on WiPy. Floating point support required +for this module. + +Functions +--------- + +.. function:: acos(x) + + Return the inverse cosine of ``x``. + +.. function:: acosh(x) + + Return the inverse hyperbolic cosine of ``x``. + +.. function:: asin(x) + + Return the inverse sine of ``x``. + +.. function:: asinh(x) + + Return the inverse hyperbolic sine of ``x``. + +.. function:: atan(x) + + Return the inverse tangent of ``x``. + +.. function:: atan2(y, x) + + Return the principal value of the inverse tangent of ``y/x``. + +.. function:: atanh(x) + + Return the inverse hyperbolic tangent of ``x``. + +.. function:: ceil(x) + + Return an integer, being ``x`` rounded towards positive infinity. + +.. function:: copysign(x, y) + + Return ``x`` with the sign of ``y``. + +.. function:: cos(x) + + Return the cosine of ``x``. + +.. function:: cosh(x) + + Return the hyperbolic cosine of ``x``. + +.. function:: degrees(x) + + Return radians ``x`` converted to degrees. + +.. function:: erf(x) + + Return the error function of ``x``. + +.. function:: erfc(x) + + Return the complementary error function of ``x``. + +.. function:: exp(x) + + Return the exponential of ``x``. + +.. function:: expm1(x) + + Return ``exp(x) - 1``. + +.. function:: fabs(x) + + Return the absolute value of ``x``. + +.. function:: floor(x) + + Return an integer, being ``x`` rounded towards negative infinity. + +.. function:: fmod(x, y) + + Return the remainder of ``x/y``. + +.. function:: frexp(x) + + Decomposes a floating-point number into its mantissa and exponent. + The returned value is the tuple ``(m, e)`` such that ``x == m * 2**e`` + exactly. If ``x == 0`` then the function returns ``(0.0, 0)``, otherwise + the relation ``0.5 <= abs(m) < 1`` holds. + +.. function:: gamma(x) + + Return the gamma function of ``x``. + +.. function:: isfinite(x) + + Return ``True`` if ``x`` is finite. + +.. function:: isinf(x) + + Return ``True`` if ``x`` is infinite. + +.. function:: isnan(x) + + Return ``True`` if ``x`` is not-a-number + +.. function:: ldexp(x, exp) + + Return ``x * (2**exp)``. + +.. function:: lgamma(x) + + Return the natural logarithm of the gamma function of ``x``. + +.. function:: log(x) + + Return the natural logarithm of ``x``. + +.. function:: log10(x) + + Return the base-10 logarithm of ``x``. + +.. function:: log2(x) + + Return the base-2 logarithm of ``x``. + +.. function:: modf(x) + + Return a tuple of two floats, being the fractional and integral parts of + ``x``. Both return values have the same sign as ``x``. + +.. function:: pow(x, y) + + Returns ``x`` to the power of ``y``. + +.. function:: radians(x) + + Return degrees ``x`` converted to radians. + +.. function:: sin(x) + + Return the sine of ``x``. + +.. function:: sinh(x) + + Return the hyperbolic sine of ``x``. + +.. function:: sqrt(x) + + Return the square root of ``x``. + +.. function:: tan(x) + + Return the tangent of ``x``. + +.. function:: tanh(x) + + Return the hyperbolic tangent of ``x``. + +.. function:: trunc(x) + + Return an integer, being ``x`` rounded towards 0. + +Constants +--------- + +.. data:: e + + base of the natural logarithm + +.. data:: pi + + the ratio of a circle's circumference to its diameter diff --git a/src/openmv/src/micropython/docs/library/micropython.rst b/src/openmv/src/micropython/docs/library/micropython.rst new file mode 100755 index 0000000..d9f913b --- /dev/null +++ b/src/openmv/src/micropython/docs/library/micropython.rst @@ -0,0 +1,140 @@ +:mod:`micropython` -- access and control MicroPython internals +============================================================== + +.. module:: micropython + :synopsis: access and control MicroPython internals + +Functions +--------- + +.. function:: const(expr) + + Used to declare that the expression is a constant so that the compile can + optimise it. The use of this function should be as follows:: + + from micropython import const + + CONST_X = const(123) + CONST_Y = const(2 * CONST_X + 1) + + Constants declared this way are still accessible as global variables from + outside the module they are declared in. On the other hand, if a constant + begins with an underscore then it is hidden, it is not available as a global + variable, and does not take up any memory during execution. + + This `const` function is recognised directly by the MicroPython parser and is + provided as part of the :mod:`micropython` module mainly so that scripts can be + written which run under both CPython and MicroPython, by following the above + pattern. + +.. function:: opt_level([level]) + + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + +.. function:: alloc_emergency_exception_buf(size) + + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + +.. function:: mem_info([verbose]) + + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + +.. function:: qstr_info([verbose]) + + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + +.. function:: stack_use() + + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + +.. function:: heap_lock() +.. function:: heap_unlock() + + Lock or unlock the heap. When locked no memory allocation can occur and a + `MemoryError` will be raised if any heap allocation is attempted. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + +.. function:: kbd_intr(chr) + + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + +.. function:: schedule(func, arg) + + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite stack to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the stack is full. diff --git a/src/openmv/src/micropython/docs/library/network.CC3K.rst b/src/openmv/src/micropython/docs/library/network.CC3K.rst new file mode 100755 index 0000000..212a1e3 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/network.CC3K.rst @@ -0,0 +1,89 @@ +.. currentmodule:: network +.. _network.CC3K: + +class CC3K -- control CC3000 WiFi modules +========================================= + +This class provides a driver for CC3000 WiFi modules. Example usage:: + + import network + nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3) + nic.connect('your-ssid', 'your-password') + while not nic.isconnected(): + pyb.delay(50) + print(nic.ifconfig()) + + # now use socket as usual + ... + +For this example to work the CC3000 module must have the following connections: + + - MOSI connected to Y8 + - MISO connected to Y7 + - CLK connected to Y6 + - CS connected to Y5 + - VBEN connected to Y4 + - IRQ connected to Y3 + +It is possible to use other SPI busses and other pins for CS, VBEN and IRQ. + +Constructors +------------ + +.. class:: CC3K(spi, pin_cs, pin_en, pin_irq) + + Create a CC3K driver object, initialise the CC3000 module using the given SPI bus + and pins, and return the CC3K object. + + Arguments are: + + - *spi* is an :ref:`SPI object ` which is the SPI bus that the CC3000 is + connected to (the MOSI, MISO and CLK pins). + - *pin_cs* is a :ref:`Pin object ` which is connected to the CC3000 CS pin. + - *pin_en* is a :ref:`Pin object ` which is connected to the CC3000 VBEN pin. + - *pin_irq* is a :ref:`Pin object ` which is connected to the CC3000 IRQ pin. + + All of these objects will be initialised by the driver, so there is no need to + initialise them yourself. For example, you can use:: + + nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3) + +Methods +------- + +.. method:: CC3K.connect(ssid, key=None, \*, security=WPA2, bssid=None) + + Connect to a WiFi access point using the given SSID, and other security + parameters. + +.. method:: CC3K.disconnect() + + Disconnect from the WiFi access point. + +.. method:: CC3K.isconnected() + + Returns True if connected to a WiFi access point and has a valid IP address, + False otherwise. + +.. method:: CC3K.ifconfig() + + Returns a 7-tuple with (ip, subnet mask, gateway, DNS server, DHCP server, + MAC address, SSID). + +.. method:: CC3K.patch_version() + + Return the version of the patch program (firmware) on the CC3000. + +.. method:: CC3K.patch_program('pgm') + + Upload the current firmware to the CC3000. You must pass 'pgm' as the first + argument in order for the upload to proceed. + +Constants +--------- + +.. data:: CC3K.WEP +.. data:: CC3K.WPA +.. data:: CC3K.WPA2 + + security type to use diff --git a/src/openmv/src/micropython/docs/library/network.WIZNET5K.rst b/src/openmv/src/micropython/docs/library/network.WIZNET5K.rst new file mode 100755 index 0000000..e21e3a4 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/network.WIZNET5K.rst @@ -0,0 +1,71 @@ +.. currentmodule:: network +.. _network.WIZNET5K: + +class WIZNET5K -- control WIZnet5x00 Ethernet modules +===================================================== + +This class allows you to control WIZnet5x00 Ethernet adaptors based on +the W5200 and W5500 chipsets. The particular chipset that is supported +by the firmware is selected at compile-time via the MICROPY_PY_WIZNET5K +option. + +Example usage:: + + import network + nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4) + print(nic.ifconfig()) + + # now use socket as usual + ... + +For this example to work the WIZnet5x00 module must have the following connections: + + - MOSI connected to X8 + - MISO connected to X7 + - SCLK connected to X6 + - nSS connected to X5 + - nRESET connected to X4 + +It is possible to use other SPI busses and other pins for nSS and nRESET. + +Constructors +------------ + +.. class:: WIZNET5K(spi, pin_cs, pin_rst) + + Create a WIZNET5K driver object, initialise the WIZnet5x00 module using the given + SPI bus and pins, and return the WIZNET5K object. + + Arguments are: + + - *spi* is an :ref:`SPI object ` which is the SPI bus that the WIZnet5x00 is + connected to (the MOSI, MISO and SCLK pins). + - *pin_cs* is a :ref:`Pin object ` which is connected to the WIZnet5x00 nSS pin. + - *pin_rst* is a :ref:`Pin object ` which is connected to the WIZnet5x00 nRESET pin. + + All of these objects will be initialised by the driver, so there is no need to + initialise them yourself. For example, you can use:: + + nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4) + +Methods +------- + +.. method:: WIZNET5K.isconnected() + + Returns ``True`` if the physical Ethernet link is connected and up. + Returns ``False`` otherwise. + +.. method:: WIZNET5K.ifconfig([(ip, subnet, gateway, dns)]) + + Get/set IP address, subnet mask, gateway and DNS. + + When called with no arguments, this method returns a 4-tuple with the above information. + + To set the above values, pass a 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + +.. method:: WIZNET5K.regs() + + Dump the WIZnet5x00 registers. Useful for debugging. diff --git a/src/openmv/src/micropython/docs/library/network.WLAN.rst b/src/openmv/src/micropython/docs/library/network.WLAN.rst new file mode 100755 index 0000000..46a27a8 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/network.WLAN.rst @@ -0,0 +1,132 @@ +.. currentmodule:: network +.. _network.WLAN: + +class WLAN -- control built-in WiFi interfaces +============================================== + +This class provides a driver for WiFi network processors. Example usage:: + + import network + # enable station interface and connect to WiFi access point + nic = network.WLAN(network.STA_IF) + nic.active(True) + nic.connect('your-ssid', 'your-password') + # now use sockets as usual + +Constructors +------------ +.. class:: WLAN(interface_id) + +Create a WLAN network interface object. Supported interfaces are +``network.STA_IF`` (station aka client, connects to upstream WiFi access +points) and ``network.AP_IF`` (access point, allows other WiFi clients to +connect). Availability of the methods below depends on interface type. +For example, only STA interface may `WLAN.connect()` to an access point. + +Methods +------- + +.. method:: WLAN.active([is_active]) + + Activate ("up") or deactivate ("down") network interface, if boolean + argument is passed. Otherwise, query current state if no argument is + provided. Most other methods require active interface. + +.. method:: WLAN.connect(ssid=None, password=None, \*, bssid=None) + + Connect to the specified wireless network, using the specified password. + If *bssid* is given then the connection will be restricted to the + access-point with that MAC address (the *ssid* must also be specified + in this case). + +.. method:: WLAN.disconnect() + + Disconnect from the currently connected wireless network. + +.. method:: WLAN.scan() + + Scan for the available wireless networks. + + Scanning is only possible on STA interface. Returns list of tuples with + the information about WiFi access points: + + (ssid, bssid, channel, RSSI, authmode, hidden) + + *bssid* is hardware address of an access point, in binary form, returned as + bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form. + + There are five values for authmode: + + * 0 -- open + * 1 -- WEP + * 2 -- WPA-PSK + * 3 -- WPA2-PSK + * 4 -- WPA/WPA2-PSK + + and two for hidden: + + * 0 -- visible + * 1 -- hidden + +.. method:: WLAN.status([param]) + + Return the current status of the wireless connection. + + When called with no argument the return value describes the network link status. + The possible statuses are defined as constants: + + * ``STAT_IDLE`` -- no connection and no activity, + * ``STAT_CONNECTING`` -- connecting in progress, + * ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password, + * ``STAT_NO_AP_FOUND`` -- failed because no access point replied, + * ``STAT_CONNECT_FAIL`` -- failed due to other problems, + * ``STAT_GOT_IP`` -- connection successful. + + When called with one argument *param* should be a string naming the status + parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``. + +.. method:: WLAN.isconnected() + + In case of STA mode, returns ``True`` if connected to a WiFi access + point and has a valid IP address. In AP mode returns ``True`` when a + station is connected. Returns ``False`` otherwise. + +.. method:: WLAN.ifconfig([(ip, subnet, gateway, dns)]) + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + +.. method:: WLAN.config('param') +.. method:: WLAN.config(param=value, ...) + + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `WLAN.ifconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, keyword argument syntax should be used, + multiple parameters can be set at once. For querying, parameters name should + be quoted as a string, and only one parameter can be queries at time:: + + # Set WiFi access point name (formally known as ESSID) and WiFi channel + ap.config(essid='My AP', channel=11) + # Query params one by one + print(ap.config('essid')) + print(ap.config('channel')) + + Following are commonly supported parameters (availability of a specific parameter + depends on network technology type, driver, and `MicroPython port`). + + ============= =========== + Parameter Description + ============= =========== + mac MAC address (bytes) + essid WiFi access point name (string) + channel WiFi channel (integer) + hidden Whether ESSID is hidden (boolean) + authmode Authentication mode supported (enumeration, see module constants) + password Access password (string) + dhcp_hostname The DHCP hostname to use + ============= =========== diff --git a/src/openmv/src/micropython/docs/library/network.WLANWiPy.rst b/src/openmv/src/micropython/docs/library/network.WLANWiPy.rst new file mode 100755 index 0000000..b6e3279 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/network.WLANWiPy.rst @@ -0,0 +1,161 @@ +.. currentmodule:: network +.. _network.WLANWiPy: + +class WLANWiPy -- WiPy specific WiFi control +============================================ + +.. note:: + + This class is a non-standard WLAN implementation for the WiPy. + It is available simply as ``network.WLAN`` on the WiPy but is named in the + documentation below as ``network.WLANWiPy`` to distinguish it from the + more general :ref:`network.WLAN ` class. + +This class provides a driver for the WiFi network processor in the WiPy. Example usage:: + + import network + import time + # setup as a station + wlan = network.WLAN(mode=WLAN.STA) + wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key')) + while not wlan.isconnected(): + time.sleep_ms(50) + print(wlan.ifconfig()) + + # now use socket as usual + ... + +Constructors +------------ + +.. class:: WLANWiPy(id=0, ...) + + Create a WLAN object, and optionally configure it. See `init()` for params of configuration. + +.. note:: + + The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given, + it will return the already existing ``WLAN`` instance without re-configuring it. This is + because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not + initialized it will do the same as the other constructors an will initialize it with default + values. + +Methods +------- + +.. method:: WLANWiPy.init(mode, \*, ssid, auth, channel, antenna) + + Set or get the WiFi network processor configuration. + + Arguments are: + + - *mode* can be either ``WLAN.STA`` or ``WLAN.AP``. + - *ssid* is a string with the ssid name. Only needed when mode is ``WLAN.AP``. + - *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``, + ``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password. + If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal + values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``. + - *channel* a number in the range 1-11. Only needed when mode is ``WLAN.AP``. + - *antenna* selects between the internal and the external antenna. Can be either + ``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``. + + For example, you can do:: + + # create and configure as an access point + wlan.init(mode=WLAN.AP, ssid='wipy-wlan', auth=(WLAN.WPA2,'www.wipy.io'), channel=7, antenna=WLAN.INT_ANT) + + or:: + + # configure as an station + wlan.init(mode=WLAN.STA) + +.. method:: WLANWiPy.connect(ssid, \*, auth=None, bssid=None, timeout=None) + + Connect to a WiFi access point using the given SSID, and other security + parameters. + + - *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``, + ``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password. + If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal + values (e.g. 'ABC1DE45BF'). + - *bssid* is the MAC address of the AP to connect to. Useful when there are several + APs with the same ssid. + - *timeout* is the maximum time in milliseconds to wait for the connection to succeed. + +.. method:: WLANWiPy.scan() + + Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi). + Note that channel is always ``None`` since this info is not provided by the WiPy. + +.. method:: WLANWiPy.disconnect() + + Disconnect from the WiFi access point. + +.. method:: WLANWiPy.isconnected() + + In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address. + In AP mode returns ``True`` when a station is connected, ``False`` otherwise. + +.. method:: WLANWiPy.ifconfig(if_id=0, config=['dhcp' or configtuple]) + + With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*. + + if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params + are negotiated with the AP. + + If the 4-tuple config is given then a static IP is configured. For instance:: + + wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + +.. method:: WLANWiPy.mode([mode]) + + Get or set the WLAN mode. + +.. method:: WLANWiPy.ssid([ssid]) + + Get or set the SSID when in AP mode. + +.. method:: WLANWiPy.auth([auth]) + + Get or set the authentication type when in AP mode. + +.. method:: WLANWiPy.channel([channel]) + + Get or set the channel (only applicable in AP mode). + +.. method:: WLANWiPy.antenna([antenna]) + + Get or set the antenna type (external or internal). + +.. method:: WLANWiPy.mac([mac_addr]) + + Get or set a 6-byte long bytes object with the MAC address. + +.. method:: WLANWiPy.irq(\*, handler, wake) + + Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP`` + mode. Events are triggered by socket activity or by WLAN connection/disconnection. + + - *handler* is the function that gets called when the IRQ is triggered. + - *wake* must be ``machine.SLEEP``. + + Returns an IRQ object. + +Constants +--------- + +.. data:: WLANWiPy.STA +.. data:: WLANWiPy.AP + + selects the WLAN mode + +.. data:: WLANWiPy.WEP +.. data:: WLANWiPy.WPA +.. data:: WLANWiPy.WPA2 + + selects the network security + +.. data:: WLANWiPy.INT_ANT +.. data:: WLANWiPy.EXT_ANT + + selects the antenna type diff --git a/src/openmv/src/micropython/docs/library/network.rst b/src/openmv/src/micropython/docs/library/network.rst new file mode 100755 index 0000000..0c56592 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/network.rst @@ -0,0 +1,173 @@ +**************************************** +:mod:`network` --- network configuration +**************************************** + +.. module:: network + :synopsis: network configuration + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`usocket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import utime + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + utime.sleep(1) + print(nic.ifconfig()) + + # now use usocket as usual + import usocket as socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n') + data = s.recv(1000) + s.close() + +Common network adapter interface +================================ + +This section describes an (implied) abstract base class for all network +interface classes implemented by `MicroPython ports ` +for different hardware. This means that MicroPython does not actually +provide ``AbstractNIC`` class, but any actual NIC class, as described +in the following sections, implements methods as described here. + +.. class:: AbstractNIC(id=None, ...) + +Instantiate a network interface object. Parameters are network interface +dependent. If there are more than one interface of the same type, the first +parameter should be `id`. + +.. method:: AbstractNIC.active([is_active]) + + Activate ("up") or deactivate ("down") the network interface, if + a boolean argument is passed. Otherwise, query current state if + no argument is provided. Most other methods require an active + interface (behavior of calling them on inactive interface is + undefined). + +.. method:: AbstractNIC.connect([service_id, key=None, \*, ...]) + + Connect the interface to a network. This method is optional, and + available only for interfaces which are not "always connected". + If no parameters are given, connect to the default (or the only) + service. If a single parameter is given, it is the primary identifier + of a service to connect to. It may be accompanied by a key + (password) required to access said service. There can be further + arbitrary keyword-only parameters, depending on the networking medium + type and/or particular device. Parameters can be used to: a) + specify alternative service identifer types; b) provide additional + connection parameters. For various medium types, there are different + sets of predefined/recommended parameters, among them: + + * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address) + +.. method:: AbstractNIC.disconnect() + + Disconnect from network. + +.. method:: AbstractNIC.isconnected() + + Returns ``True`` if connected to network, otherwise returns ``False``. + +.. method:: AbstractNIC.scan(\*, ...) + + Scan for the available network services/connections. Returns a + list of tuples with discovered service parameters. For various + network media, there are different variants of predefined/ + recommended tuple formats, among them: + + * WiFi: (ssid, bssid, channel, RSSI, authmode, hidden). There + may be further fields, specific to a particular device. + + The function may accept additional keyword arguments to filter scan + results (e.g. scan for a particular service, on a particular channel, + for services of a particular set, etc.), and to affect scan + duration and other parameters. Where possible, parameter names + should match those in connect(). + +.. method:: AbstractNIC.status([param]) + + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). + +.. method:: AbstractNIC.ifconfig([(ip, subnet, gateway, dns)]) + + Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. When called with no arguments, this method returns + a 4-tuple with the above information. To set the above values, pass a + 4-tuple with the required information. For example:: + + nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + +.. method:: AbstractNIC.config('param') + AbstractNIC.config(param=value, ...) + + Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `ifconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, the keyword argument + syntax should be used, and multiple parameters can be set at once. For + querying, a parameter name should be quoted as a string, and only one + parameter can be queried at a time:: + + # Set WiFi access point name (formally known as ESSID) and WiFi channel + ap.config(essid='My AP', channel=11) + # Query params one by one + print(ap.config('essid')) + print(ap.config('channel')) + +Specific network class implementations +====================================== + +The following concrete classes implement the AbstractNIC interface and +provide a way to control networking interfaces of various kinds. + +.. toctree:: + :maxdepth: 1 + + network.WLAN.rst + network.WLANWiPy.rst + network.CC3K.rst + network.WIZNET5K.rst + +Network functions +================= + +The following are functions available in the network module. + +.. function:: phy_mode([mode]) + + Get or set the PHY mode. + + If the *mode* parameter is provided, sets the mode to its value. If + the function is called without parameters, returns the current mode. + + The possible modes are defined as constants: + * ``MODE_11B`` -- IEEE 802.11b, + * ``MODE_11G`` -- IEEE 802.11g, + * ``MODE_11N`` -- IEEE 802.11n. + + Availability: ESP8266. diff --git a/src/openmv/src/micropython/docs/library/pyb.ADC.rst b/src/openmv/src/micropython/docs/library/pyb.ADC.rst new file mode 100755 index 0000000..a95f2d5 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.ADC.rst @@ -0,0 +1,167 @@ +.. currentmodule:: pyb +.. _pyb.ADC: + +class ADC -- analog to digital conversion +========================================= + +Usage:: + + import pyb + + adc = pyb.ADC(pin) # create an analog object from a pin + val = adc.read() # read an analog value + + adc = pyb.ADCAll(resolution) # create an ADCAll object + adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels + val = adc.read_channel(channel) # read the given channel + val = adc.read_core_temp() # read MCU temperature + val = adc.read_core_vbat() # read MCU VBAT + val = adc.read_core_vref() # read MCU VREF + val = adc.read_vref() # read MCU supply voltage + + +Constructors +------------ + +.. class:: pyb.ADC(pin) + + Create an ADC object associated with the given pin. + This allows you to then read analog values on that pin. + +Methods +------- + +.. method:: ADC.read() + + Read the value on the analog pin and return it. The returned value + will be between 0 and 4095. + +.. method:: ADC.read_timed(buf, timer) + + Read analog values into ``buf`` at a rate set by the ``timer`` object. + + ``buf`` can be bytearray or array.array for example. The ADC values have + 12-bit resolution and are stored directly into ``buf`` if its element size is + 16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then + the sample resolution will be reduced to 8 bits. + + ``timer`` should be a Timer object, and a sample is read each time the timer + triggers. The timer must already be initialised and running at the desired + sampling frequency. + + To support previous behaviour of this function, ``timer`` can also be an + integer which specifies the frequency (in Hz) to sample at. In this case + Timer(6) will be automatically configured to run at the given frequency. + + Example using a Timer object (preferred way):: + + adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 + tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz + buf = bytearray(100) # creat a buffer to store the samples + adc.read_timed(buf, tim) # sample 100 values, taking 10s + + Example using an integer for the frequency:: + + adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 + buf = bytearray(100) # create a buffer of 100 bytes + adc.read_timed(buf, 10) # read analog values into buf at 10Hz + # this will take 10 seconds to finish + for val in buf: # loop over all values + print(val) # print the value out + + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffer is full. + +.. method:: ADC.read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) + + This is a static method. It can be used to extract relative timing or + phase data from multiple ADC's. + + It reads analog values from multiple ADC's into buffers at a rate set by + the *timer* object. Each time the timer triggers a sample is rapidly + read from each ADC in turn. + + ADC and buffer instances are passed in tuples with each ADC having an + associated buffer. All buffers must be of the same type and length and + the number of buffers must equal the number of ADC's. + + Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values + have 12-bit resolution and are stored directly into the buffer if its element + size is 16 bits or greater. If buffers have only 8-bit elements (eg a + ``bytearray``) then the sample resolution will be reduced to 8 bits. + + *timer* must be a Timer object. The timer must already be initialised + and running at the desired sampling frequency. + + Example reading 3 ADC's:: + + adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's + adc1 = pyb.ADC(pyb.Pin.board.X2) + adc2 = pyb.ADC(pyb.Pin.board.X3) + tim = pyb.Timer(8, freq=100) # Create timer + rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of + rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words + rx2 = array.array('H', (0 for i in range(100))) + # read analog values into buffers at 100Hz (takes one second) + pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim) + for n in range(len(rx0)): + print(rx0[n], rx1[n], rx2[n]) + + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffers are full. + + The function returns ``True`` if all samples were acquired with correct + timing. At high sample rates the time taken to acquire a set of samples + can exceed the timer period. In this case the function returns ``False``, + indicating a loss of precision in the sample interval. In extreme cases + samples may be missed. + + The maximum rate depends on factors including the data width and the + number of ADC's being read. In testing two ADC's were sampled at a timer + rate of 210kHz without overrun. Samples were missed at 215kHz. For three + ADC's the limit is around 140kHz, and for four it is around 110kHz. + At high sample rates disabling interrupts for the duration can reduce the + risk of sporadic data loss. + +The ADCAll Object +----------------- + +Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature, +VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively. +Appropriate scaling is handled according to reference voltage used (usually 3.3V). +The temperature sensor on the chip is factory calibrated and allows to read the die temperature +to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal +temperature is measured. Depending on processing loads and I/O subsystems active the die temperature +may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a +long standby period will show correct ambient temperature within limits mentioned above. + +The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read +the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the +actual supply as a reference. All results are floating point numbers giving direct voltage values. + +``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according +to the actual supply voltage. To avoid analog input overload the battery voltage is measured +via a voltage divider and scaled according to the divider value. To prevent excessive loads +to the backup battery, the voltage divider is only active during ADC conversion. + +``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using +factory calibration value of the internal voltage reference. In most cases the reading would be close +to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V. +The pyboard will still operate fine as long as the operating conditions are met. With proper settings +of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to +2 V and still get useful ADC conversion. + +It is very important to make sure analog input voltages never exceed actual supply voltage. + +Other analog input channels (0..15) will return unscaled integer values according to the selected +precision. + +To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified. +This parameter is a binary pattern where each requested analog input has the corresponding bit set. +The default value is 0xffffffff which means all analog inputs are active. If just the internal +channels (16..18) are required, the mask value should be 0x70000. + +Example:: + + adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels + temp = adcall.read_core_temp() diff --git a/src/openmv/src/micropython/docs/library/pyb.Accel.rst b/src/openmv/src/micropython/docs/library/pyb.Accel.rst new file mode 100755 index 0000000..9ade5c5 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.Accel.rst @@ -0,0 +1,57 @@ +.. currentmodule:: pyb +.. _pyb.Accel: + +class Accel -- accelerometer control +==================================== + +Accel is an object that controls the accelerometer. Example usage:: + + accel = pyb.Accel() + for i in range(10): + print(accel.x(), accel.y(), accel.z()) + +Raw values are between -32 and 31. + + +Constructors +------------ + +.. class:: pyb.Accel() + + Create and return an accelerometer object. + +Methods +------- + +.. method:: Accel.filtered_xyz() + + Get a 3-tuple of filtered x, y and z values. + + Implementation note: this method is currently implemented as taking the + sum of 4 samples, sampled from the 3 previous calls to this function along + with the sample from the current call. Returned values are therefore 4 + times the size of what they would be from the raw x(), y() and z() calls. + +.. method:: Accel.tilt() + + Get the tilt register. + +.. method:: Accel.x() + + Get the x-axis value. + +.. method:: Accel.y() + + Get the y-axis value. + +.. method:: Accel.z() + + Get the z-axis value. + +Hardware Note +------------- + +The accelerometer uses I2C bus 1 to communicate with the processor. Consequently +when readings are being taken pins X9 and X10 should be unused (other than for +I2C). Other devices using those pins, and which therefore cannot be used +concurrently, are UART 1 and Timer 4 channels 1 and 2. diff --git a/src/openmv/src/micropython/docs/library/pyb.CAN.rst b/src/openmv/src/micropython/docs/library/pyb.CAN.rst new file mode 100755 index 0000000..09b97a1 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.CAN.rst @@ -0,0 +1,300 @@ +.. currentmodule:: pyb +.. _pyb.CAN: + +class CAN -- controller area network communication bus +====================================================== + +CAN implements the standard CAN communications protocol. At +the physical level it consists of 2 lines: RX and TX. Note that +to connect the pyboard to a CAN bus you must use a CAN transceiver +to convert the CAN logic signals from the pyboard to the correct +voltage levels on the bus. + +Example usage (works without anything connected):: + + from pyb import CAN + can = CAN(1, CAN.LOOPBACK) + can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126)) # set a filter to receive messages with id=123, 124, 125 and 126 + can.send('message!', 123) # send a message with id 123 + can.recv(0) # receive message on FIFO 0 + + +Constructors +------------ + +.. class:: pyb.CAN(bus, ...) + + Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``. + With no additional parameters, the CAN object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See :meth:`CAN.init` for parameters of initialisation. + + The physical pins of the CAN busses are: + + - ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)`` + - ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)`` + +Class Methods +------------- +.. classmethod:: CAN.initfilterbanks(nr) + + Reset and disable all filter banks and assign how many banks should be available for CAN(1). + + STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers. + This function configures how many filter banks should be assigned to each. *nr* is the number of banks + that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). + At boot, 14 banks are assigned to each controller. + +Methods +------- + +.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False) + + Initialise the CAN bus with the given parameters: + + - *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK + - if *extframe* is True then the bus uses extended identifiers in the frames + (29 bits); otherwise it uses standard 11 bit identifiers + - *prescaler* is used to set the duration of 1 time quanta; the time quanta + will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler + - *sjw* is the resynchronisation jump width in units of the time quanta; + it can be 1, 2, 3, 4 + - *bs1* defines the location of the sample point in units of the time quanta; + it can be between 1 and 1024 inclusive + - *bs2* defines the location of the transmit point in units of the time quanta; + it can be between 1 and 16 inclusive + - *auto_restart* sets whether the controller will automatically try and restart + communications after entering the bus-off state; if this is disabled then + :meth:`~CAN.restart()` can be used to leave the bus-off state + + The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN + prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); + see :meth:`pyb.freq()` to determine PCLK1. + + A single bit is made up of the synchronisation segment, which is always 1 tq. + Then follows bit segment 1, then bit segment 2. The sample point is after bit + segment 1 finishes. The transmit point is after bit segment 2 finishes. + The baud rate will be 1/bittime, where the bittime is 1 + BS1 + BS2 multiplied + by the time quanta tq. + + For example, with PCLK1=42MHz, prescaler=100, sjw=1, bs1=6, bs2=8, the value of + tq is 2.38 microseconds. The bittime is 35.7 microseconds, and the baudrate + is 28kHz. + + See page 680 of the STM32F405 datasheet for more details. + +.. method:: CAN.deinit() + + Turn off the CAN bus. + +.. method:: CAN.restart() + + Force a software restart of the CAN controller without resetting its + configuration. + + If the controller enters the bus-off state then it will no longer participate + in bus activity. If the controller is not configured to automatically restart + (see :meth:`~CAN.init()`) then this method can be used to trigger a restart, + and the controller will follow the CAN protocol to leave the bus-off state and + go into the error active state. + +.. method:: CAN.state() + + Return the state of the controller. The return value can be one of: + + - ``CAN.STOPPED`` -- the controller is completely off and reset; + - ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state + (both TEC and REC are less than 96); + - ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state + (at least one of TEC or REC is 96 or greater); + - ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state + (at least one of TEC or REC is 128 or greater); + - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity + (TEC overflowed beyond 255). + +.. method:: CAN.info([list]) + + Get information about the controller's error states and TX and RX buffers. + If *list* is provided then it should be a list object with at least 8 entries, + which will be filled in with the information. Otherwise a new list will be + created and filled in. In both cases the return value of the method is the + populated list. + + The values in the list are: + + - TEC value + - REC value + - number of times the controller enterted the Error Warning state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Error Passive state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Bus Off state (wrapped + around to 0 after 65535) + - number of pending TX messages + - number of pending RX messages on fifo 0 + - number of pending RX messages on fifo 1 + +.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) + + Configure a filter bank: + + - *bank* is the filter bank that is to be configured. + - *mode* is the mode the filter should operate in. + - *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. + - *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument. + + +-----------+---------------------------------------------------------+ + |*mode* |contents of *params* array | + +===========+=========================================================+ + |CAN.LIST16 |Four 16 bit ids that will be accepted | + +-----------+---------------------------------------------------------+ + |CAN.LIST32 |Two 32 bit ids that will be accepted | + +-----------+---------------------------------------------------------+ + |CAN.MASK16 |Two 16 bit id/mask pairs. E.g. (1, 3, 4, 4) | + | | | The first pair, 1 and 3 will accept all ids | + | | | that have bit 0 = 1 and bit 1 = 0. | + | | | The second pair, 4 and 4, will accept all ids | + | | | that have bit 2 = 1. | + +-----------+---------------------------------------------------------+ + |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| + +-----------+---------------------------------------------------------+ + + - *rtr* is an array of booleans that states if a filter should accept a + remote transmission request message. If this argument is not given + then it defaults to ``False`` for all entries. The length of the array + depends on the *mode* argument. + + +-----------+----------------------+ + |*mode* |length of *rtr* array | + +===========+======================+ + |CAN.LIST16 |4 | + +-----------+----------------------+ + |CAN.LIST32 |2 | + +-----------+----------------------+ + |CAN.MASK16 |2 | + +-----------+----------------------+ + |CAN.MASK32 |1 | + +-----------+----------------------+ + +.. method:: CAN.clearfilter(bank) + + Clear and disables a filter bank: + + - *bank* is the filter bank that is to be cleared. + +.. method:: CAN.any(fifo) + + Return ``True`` if any message waiting on the FIFO, else ``False``. + +.. method:: CAN.recv(fifo, list=None, \*, timeout=5000) + + Receive data on the bus: + + - *fifo* is an integer, which is the FIFO to receive on + - *list* is an optional list object to be used as the return value + - *timeout* is the timeout in milliseconds to wait for the receive. + + Return value: A tuple containing four values. + + - The id of the message. + - A boolean that indicates if the message is an RTR message. + - The FMI (Filter Match Index) value. + - An array containing the data. + + If *list* is ``None`` then a new tuple will be allocated, as well as a new + bytes object to contain the data (as the fourth element in the tuple). + + If *list* is not ``None`` then it should be a list object with a least four + elements. The fourth element should be a memoryview object which is created + from either a bytearray or an array of type 'B' or 'b', and this array must + have enough room for at least 8 bytes. The list object will then be + populated with the first three return values above, and the memoryview object + will be resized inplace to the size of the data and filled in with that data. + The same list and memoryview objects can be reused in subsequent calls to + this method, providing a way of receiving data without using the heap. + For example:: + + buf = bytearray(8) + lst = [0, 0, 0, memoryview(buf)] + # No heap memory is allocated in the following call + can.recv(0, lst) + +.. method:: CAN.send(data, id, \*, timeout=0, rtr=False) + + Send a message on the bus: + + - *data* is the data to send (an integer to send, or a buffer object). + - *id* is the id of the message to be sent. + - *timeout* is the timeout in milliseconds to wait for the send. + - *rtr* is a boolean that specifies if the message shall be sent as + a remote transmission request. If *rtr* is True then only the length + of *data* is used to fill in the DLC slot of the frame; the actual + bytes in *data* are unused. + + If timeout is 0 the message is placed in a buffer in one of three hardware + buffers and the method returns immediately. If all three buffers are in use + an exception is thrown. If timeout is not 0, the method waits until the + message is transmitted. If the message can't be transmitted within the + specified time an exception is thrown. + + Return value: ``None``. + +.. method:: CAN.rxcallback(fifo, fun) + + Register a function to be called when a message is accepted into a empty fifo: + + - *fifo* is the receiving fifo. + - *fun* is the function to be called when the fifo becomes non empty. + + The callback function takes two arguments the first is the can object it self the second is + a integer that indicates the reason for the callback. + + +--------+------------------------------------------------+ + | Reason | | + +========+================================================+ + | 0 | A message has been accepted into a empty FIFO. | + +--------+------------------------------------------------+ + | 1 | The FIFO is full | + +--------+------------------------------------------------+ + | 2 | A message has been lost due to a full FIFO | + +--------+------------------------------------------------+ + + Example use of rxcallback:: + + def cb0(bus, reason): + print('cb0') + if reason == 0: + print('pending') + if reason == 1: + print('full') + if reason == 2: + print('overflow') + + can = CAN(1, CAN.LOOPBACK) + can.rxcallback(0, cb0) + +Constants +--------- + +.. data:: CAN.NORMAL + CAN.LOOPBACK + CAN.SILENT + CAN.SILENT_LOOPBACK + + The mode of the CAN bus used in :meth:`~CAN.init()`. + +.. data:: CAN.STOPPED + CAN.ERROR_ACTIVE + CAN.ERROR_WARNING + CAN.ERROR_PASSIVE + CAN.BUS_OFF + + Possible states of the CAN controller returned from :meth:`~CAN.state()`. + +.. data:: CAN.LIST16 + CAN.MASK16 + CAN.LIST32 + CAN.MASK32 + + The operation mode of a filter used in :meth:`~CAN.setfilter()`. diff --git a/src/openmv/src/micropython/docs/library/pyb.DAC.rst b/src/openmv/src/micropython/docs/library/pyb.DAC.rst new file mode 100755 index 0000000..c67603a --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.DAC.rst @@ -0,0 +1,124 @@ +.. currentmodule:: pyb +.. _pyb.DAC: + +class DAC -- digital to analog conversion +========================================= + +The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6. +The voltage will be between 0 and 3.3V. + +*This module will undergo changes to the API.* + +Example usage:: + + from pyb import DAC + + dac = DAC(1) # create DAC 1 on pin X5 + dac.write(128) # write a value to the DAC (makes X5 1.65V) + + dac = DAC(1, bits=12) # use 12 bit resolution + dac.write(4095) # output maximum value, 3.3V + +To output a continuous sine-wave:: + + import math + from pyb import DAC + + # create a buffer containing a sine-wave + buf = bytearray(100) + for i in range(len(buf)): + buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf))) + + # output the sine-wave at 400Hz + dac = DAC(1) + dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) + +To output a continuous sine-wave at 12-bit resolution:: + + import math + from array import array + from pyb import DAC + + # create a buffer containing a sine-wave, using half-word samples + buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128)) + + # output the sine-wave at 400Hz + dac = DAC(1, bits=12) + dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) + +Constructors +------------ + +.. class:: pyb.DAC(port, bits=8, \*, buffering=None) + + Construct a new DAC object. + + ``port`` can be a pin object, or an integer (1 or 2). + DAC(1) is on pin X5 and DAC(2) is on pin X6. + + ``bits`` is an integer specifying the resolution, and can be 8 or 12. + The maximum value for the write and write_timed methods will be + 2\*\*``bits``-1. + + The *buffering* parameter selects the behaviour of the DAC op-amp output + buffer, whose purpose is to reduce the output impedance. It can be + ``None`` to select the default (buffering enabled for :meth:`DAC.noise`, + :meth:`DAC.triangle` and :meth:`DAC.write_timed`, and disabled for + :meth:`DAC.write`), ``False`` to disable buffering completely, or ``True`` + to enable output buffering. + + When buffering is enabled the DAC pin can drive loads down to 5KΩ. + Otherwise it has an output impedance of 15KΩ maximum: consequently + to achieve a 1% accuracy without buffering requires the applied load + to be less than 1.5MΩ. Using the buffer incurs a penalty in accuracy, + especially near the extremes of range. + +Methods +------- + +.. method:: DAC.init(bits=8, \*, buffering=None) + + Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be + ``None``, ``False`` or ``True``; see above constructor for the meaning + of this parameter. + +.. method:: DAC.deinit() + + De-initialise the DAC making its pin available for other uses. + +.. method:: DAC.noise(freq) + + Generate a pseudo-random noise signal. A new random sample is written + to the DAC output at the given frequency. + +.. method:: DAC.triangle(freq) + + Generate a triangle wave. The value on the DAC output changes at + the given frequency, and the frequency of the repeating triangle wave + itself is 2048 times smaller. + +.. method:: DAC.write(value) + + Direct access to the DAC output. The minimum value is 0. The maximum + value is 2\*\*``bits``-1, where ``bits`` is set when creating the DAC + object or by using the ``init`` method. + +.. method:: DAC.write_timed(data, freq, \*, mode=DAC.NORMAL) + + Initiates a burst of RAM to DAC using a DMA transfer. + The input data is treated as an array of bytes in 8-bit mode, and + an array of unsigned half-words (array typecode 'H') in 12-bit mode. + + ``freq`` can be an integer specifying the frequency to write the DAC + samples at, using Timer(6). Or it can be an already-initialised + Timer object which is used to trigger the DAC sample. Valid timers + are 2, 4, 5, 6, 7 and 8. + + ``mode`` can be ``DAC.NORMAL`` or ``DAC.CIRCULAR``. + + Example using both DACs at the same time:: + + dac1 = DAC(1) + dac2 = DAC(2) + dac1.write_timed(buf1, pyb.Timer(6, freq=100), mode=DAC.CIRCULAR) + dac2.write_timed(buf2, pyb.Timer(7, freq=200), mode=DAC.CIRCULAR) diff --git a/src/openmv/src/micropython/docs/library/pyb.ExtInt.rst b/src/openmv/src/micropython/docs/library/pyb.ExtInt.rst new file mode 100755 index 0000000..814217c --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.ExtInt.rst @@ -0,0 +1,114 @@ +.. currentmodule:: pyb +.. _pyb.ExtInt: + +class ExtInt -- configure I/O pins to interrupt on external events +================================================================== + +There are a total of 22 interrupt lines. 16 of these can come from GPIO pins +and the remaining 6 are from internal sources. + +For lines 0 through 15, a given line can map to the corresponding line from an +arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and +line 1 can map to Px1 where x is A, B, C, ... :: + + def callback(line): + print("line =", line) + +Note: ExtInt will automatically configure the gpio line as an input. :: + + extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback) + +Now every time a falling edge is seen on the X1 pin, the callback will be +called. Caution: mechanical pushbuttons have "bounce" and pushing or +releasing a switch will often generate multiple edges. +See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed +explanation, along with various techniques for debouncing. + +Trying to register 2 callbacks onto the same pin will throw an exception. + +If pin is passed as an integer, then it is assumed to map to one of the +internal interrupt sources, and must be in the range 16 through 22. + +All other pin objects go through the pin mapper to come up with one of the +gpio pins. :: + + extint = pyb.ExtInt(pin, mode, pull, callback) + +Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING, +pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING, +pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING. + +Only the IRQ_xxx modes have been tested. The EVT_xxx modes have +something to do with sleep mode and the WFE instruction. + +Valid pull values are pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN, pyb.Pin.PULL_NONE. + +There is also a C API, so that drivers which require EXTI interrupt lines +can also use this code. See extint.h for the available functions and +usrsw.h for an example of using this. + + +Constructors +------------ + +.. class:: pyb.ExtInt(pin, mode, pull, callback) + + Create an ExtInt object: + + - ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name). + - ``mode`` can be one of: + - ``ExtInt.IRQ_RISING`` - trigger on a rising edge; + - ``ExtInt.IRQ_FALLING`` - trigger on a falling edge; + - ``ExtInt.IRQ_RISING_FALLING`` - trigger on a rising or falling edge. + - ``pull`` can be one of: + - ``pyb.Pin.PULL_NONE`` - no pull up or down resistors; + - ``pyb.Pin.PULL_UP`` - enable the pull-up resistor; + - ``pyb.Pin.PULL_DOWN`` - enable the pull-down resistor. + - ``callback`` is the function to call when the interrupt triggers. The + callback function must accept exactly 1 argument, which is the line that + triggered the interrupt. + + +Class methods +------------- + +.. classmethod:: ExtInt.regs() + + Dump the values of the EXTI registers. + + +Methods +------- + +.. method:: ExtInt.disable() + + Disable the interrupt associated with the ExtInt object. + This could be useful for debouncing. + +.. method:: ExtInt.enable() + + Enable a disabled interrupt. + +.. method:: ExtInt.line() + + Return the line number that the pin is mapped to. + +.. method:: ExtInt.swint() + + Trigger the callback from software. + + +Constants +--------- + +.. data:: ExtInt.IRQ_FALLING + + interrupt on a falling edge + +.. data:: ExtInt.IRQ_RISING + + interrupt on a rising edge + +.. data:: ExtInt.IRQ_RISING_FALLING + + interrupt on a rising or falling edge diff --git a/src/openmv/src/micropython/docs/library/pyb.I2C.rst b/src/openmv/src/micropython/docs/library/pyb.I2C.rst new file mode 100755 index 0000000..d549c1a --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.I2C.rst @@ -0,0 +1,165 @@ +.. currentmodule:: pyb +.. _pyb.I2C: + +class I2C -- a two-wire serial protocol +======================================= + +I2C is a two-wire protocol for communicating between devices. At the physical +level it consists of 2 wires: SCL and SDA, the clock and data lines respectively. + +I2C objects are created attached to a specific bus. They can be initialised +when created, or initialised later on. + +Example:: + + from pyb import I2C + + i2c = I2C(1) # create on bus 1 + i2c = I2C(1, I2C.MASTER) # create and init as a master + i2c.init(I2C.MASTER, baudrate=20000) # init as a master + i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address + i2c.deinit() # turn off the peripheral + +Printing the i2c object gives you information about its configuration. + +The basic methods are send and recv:: + + i2c.send('abc') # send 3 bytes + i2c.send(0x42) # send a single byte, given by the number + data = i2c.recv(3) # receive 3 bytes + +To receive inplace, first create a bytearray:: + + data = bytearray(3) # create a buffer + i2c.recv(data) # receive 3 bytes, writing them into data + +You can specify a timeout (in ms):: + + i2c.send(b'123', timeout=2000) # timeout after 2 seconds + +A master must specify the recipient's address:: + + i2c.init(I2C.MASTER) + i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42 + i2c.send(b'456', addr=0x42) # keyword for address + +Master also has other methods:: + + i2c.is_ready(0x42) # check if slave 0x42 is ready + i2c.scan() # scan for slaves on the bus, returning + # a list of valid addresses + i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42, + # starting at address 2 in the slave + i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of slave 0x42 + # starting at address 2 in the slave, timeout after 1 second + +Constructors +------------ + +.. class:: pyb.I2C(bus, ...) + + Construct an I2C object on the given bus. ``bus`` can be 1 or 2, 'X' or + 'Y'. With no additional parameters, the I2C object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + + The physical pins of the I2C busses on Pyboards V1.0 and V1.1 are: + + - ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)`` + - ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)`` + + On the Pyboard Lite: + + - ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)`` + - ``I2C(3)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PA8, PB8)`` + + Calling the constructor with 'X' or 'Y' enables portability between Pyboard + types. + +Methods +------- + +.. method:: I2C.deinit() + + Turn off the I2C bus. + +.. method:: I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False, dma=False) + + Initialise the I2C bus with the given parameters: + + - ``mode`` must be either ``I2C.MASTER`` or ``I2C.SLAVE`` + - ``addr`` is the 7-bit address (only sensible for a slave) + - ``baudrate`` is the SCL clock rate (only sensible for a master) + - ``gencall`` is whether to support general call mode + - ``dma`` is whether to allow the use of DMA for the I2C transfers (note + that DMA transfers have more precise timing but currently do not handle bus + errors properly) + +.. method:: I2C.is_ready(addr) + + Check if an I2C device responds to the given address. Only valid when in master mode. + +.. method:: I2C.mem_read(data, addr, memaddr, \*, timeout=5000, addr_size=8) + + Read from the memory of an I2C device: + + - ``data`` can be an integer (number of bytes to read) or a buffer to read into + - ``addr`` is the I2C device address + - ``memaddr`` is the memory location within the I2C device + - ``timeout`` is the timeout in milliseconds to wait for the read + - ``addr_size`` selects width of memaddr: 8 or 16 bits + + Returns the read data. + This is only valid in master mode. + +.. method:: I2C.mem_write(data, addr, memaddr, \*, timeout=5000, addr_size=8) + + Write to the memory of an I2C device: + + - ``data`` can be an integer or a buffer to write from + - ``addr`` is the I2C device address + - ``memaddr`` is the memory location within the I2C device + - ``timeout`` is the timeout in milliseconds to wait for the write + - ``addr_size`` selects width of memaddr: 8 or 16 bits + + Returns ``None``. + This is only valid in master mode. + +.. method:: I2C.recv(recv, addr=0x00, \*, timeout=5000) + + Receive data on the bus: + + - ``recv`` can be an integer, which is the number of bytes to receive, + or a mutable buffer, which will be filled with received bytes + - ``addr`` is the address to receive from (only required in master mode) + - ``timeout`` is the timeout in milliseconds to wait for the receive + + Return value: if ``recv`` is an integer then a new buffer of the bytes received, + otherwise the same buffer that was passed in to ``recv``. + +.. method:: I2C.send(send, addr=0x00, \*, timeout=5000) + + Send data on the bus: + + - ``send`` is the data to send (an integer to send, or a buffer object) + - ``addr`` is the address to send to (only required in master mode) + - ``timeout`` is the timeout in milliseconds to wait for the send + + Return value: ``None``. + +.. method:: I2C.scan() + + Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond. + Only valid when in master mode. + +Constants +--------- + +.. data:: I2C.MASTER + + for initialising the bus to master mode + +.. data:: I2C.SLAVE + + for initialising the bus to slave mode diff --git a/src/openmv/src/micropython/docs/library/pyb.LCD.rst b/src/openmv/src/micropython/docs/library/pyb.LCD.rst new file mode 100755 index 0000000..5ab127e --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.LCD.rst @@ -0,0 +1,97 @@ +.. currentmodule:: pyb +.. _pyb.LCD: + +class LCD -- LCD control for the LCD touch-sensor pyskin +======================================================== + +The LCD class is used to control the LCD on the LCD touch-sensor pyskin, +LCD32MKv1.0. The LCD is a 128x32 pixel monochrome screen, part NHD-C12832A1Z. + +The pyskin must be connected in either the X or Y positions, and then +an LCD object is made using:: + + lcd = pyb.LCD('X') # if pyskin is in the X position + lcd = pyb.LCD('Y') # if pyskin is in the Y position + +Then you can use:: + + lcd.light(True) # turn the backlight on + lcd.write('Hello world!\n') # print text to the screen + +This driver implements a double buffer for setting/getting pixels. +For example, to make a bouncing dot, try:: + + x = y = 0 + dx = dy = 1 + while True: + # update the dot's position + x += dx + y += dy + + # make the dot bounce of the edges of the screen + if x <= 0 or x >= 127: dx = -dx + if y <= 0 or y >= 31: dy = -dy + + lcd.fill(0) # clear the buffer + lcd.pixel(x, y, 1) # draw the dot + lcd.show() # show the buffer + pyb.delay(50) # pause for 50ms + + +Constructors +------------ + +.. class:: pyb.LCD(skin_position) + + Construct an LCD object in the given skin position. ``skin_position`` can be 'X' or 'Y', and + should match the position where the LCD pyskin is plugged in. + + +Methods +------- + +.. method:: LCD.command(instr_data, buf) + + Send an arbitrary command to the LCD. Pass 0 for ``instr_data`` to send an + instruction, otherwise pass 1 to send data. ``buf`` is a buffer with the + instructions/data to send. + +.. method:: LCD.contrast(value) + + Set the contrast of the LCD. Valid values are between 0 and 47. + +.. method:: LCD.fill(colour) + + Fill the screen with the given colour (0 or 1 for white or black). + + This method writes to the hidden buffer. Use ``show()`` to show the buffer. + +.. method:: LCD.get(x, y) + + Get the pixel at the position ``(x, y)``. Returns 0 or 1. + + This method reads from the visible buffer. + +.. method:: LCD.light(value) + + Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off. + +.. method:: LCD.pixel(x, y, colour) + + Set the pixel at ``(x, y)`` to the given colour (0 or 1). + + This method writes to the hidden buffer. Use ``show()`` to show the buffer. + +.. method:: LCD.show() + + Show the hidden buffer on the screen. + +.. method:: LCD.text(str, x, y, colour) + + Draw the given text to the position ``(x, y)`` using the given colour (0 or 1). + + This method writes to the hidden buffer. Use ``show()`` to show the buffer. + +.. method:: LCD.write(str) + + Write the string ``str`` to the screen. It will appear immediately. diff --git a/src/openmv/src/micropython/docs/library/pyb.LED.rst b/src/openmv/src/micropython/docs/library/pyb.LED.rst new file mode 100755 index 0000000..1ab73a6 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.LED.rst @@ -0,0 +1,46 @@ +.. currentmodule:: pyb +.. _pyb.LED: + +class LED -- LED object +======================= + +The LED object controls an individual LED (Light Emitting Diode). + + +Constructors +------------ + +.. class:: pyb.LED(id) + + Create an LED object associated with the given LED: + + - ``id`` is the LED number, 1-4. + + +Methods +------- + +.. method:: LED.intensity([value]) + + Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on). + If no argument is given, return the LED intensity. + If an argument is given, set the LED intensity and return ``None``. + + *Note:* Only LED(3) and LED(4) can have a smoothly varying intensity, and + they use timer PWM to implement it. LED(3) uses Timer(2) and LED(4) uses + Timer(3). These timers are only configured for PWM if the intensity of the + relevant LED is set to a value between 1 and 254. Otherwise the timers are + free for general purpose use. + +.. method:: LED.off() + + Turn the LED off. + +.. method:: LED.on() + + Turn the LED on, to maximum intensity. + +.. method:: LED.toggle() + + Toggle the LED between on (maximum intensity) and off. If the LED is at + non-zero intensity then it is considered "on" and toggle will turn it off. diff --git a/src/openmv/src/micropython/docs/library/pyb.Pin.rst b/src/openmv/src/micropython/docs/library/pyb.Pin.rst new file mode 100755 index 0000000..3d019cd --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.Pin.rst @@ -0,0 +1,268 @@ +.. currentmodule:: pyb +.. _pyb.Pin: + +class Pin -- control I/O pins +============================= + +A pin is the basic object to control I/O pins. It has methods to set +the mode of the pin (input, output, etc) and methods to get and set the +digital logic level. For analog control of a pin, see the ADC class. + +Usage Model: + +All Board Pins are predefined as pyb.Pin.board.Name:: + + x1_pin = pyb.Pin.board.X1 + + g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN) + +CPU pins which correspond to the board pins are available +as ``pyb.Pin.cpu.Name``. For the CPU pins, the names are the port letter +followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and +``pyb.Pin.cpu.A0`` are the same pin. + +You can also use strings:: + + g = pyb.Pin('X1', pyb.Pin.OUT_PP) + +Users can add their own names:: + + MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 } + pyb.Pin.dict(MyMapperDict) + g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD) + +and can query mappings:: + + pin = pyb.Pin("LeftMotorDir") + +Users can also add their own mapping function:: + + def MyMapper(pin_name): + if pin_name == "LeftMotorDir": + return pyb.Pin.cpu.A0 + + pyb.Pin.mapper(MyMapper) + +So, if you were to call: ``pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)`` +then ``"LeftMotorDir"`` is passed directly to the mapper function. + +To summarise, the following order determines how things get mapped into +an ordinal pin number: + +1. Directly specify a pin object +2. User supplied mapping function +3. User supplied mapping (object must be usable as a dictionary key) +4. Supply a string which matches a board pin +5. Supply a string which matches a CPU port/pin + +You can set ``pyb.Pin.debug(True)`` to get some debug information about +how a particular object gets mapped to a pin. + +When a pin has the ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` pull-mode enabled, +that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND +respectively (except pin Y5 which has 11k Ohm resistors). + +Now every time a falling edge is seen on the gpio pin, the callback will be +executed. Caution: mechanical push buttons have "bounce" and pushing or +releasing a switch will often generate multiple edges. +See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed +explanation, along with various techniques for debouncing. + +All pin objects go through the pin mapper to come up with one of the +gpio pins. + +Constructors +------------ + +.. class:: pyb.Pin(id, ...) + + Create a new Pin object associated with the id. If additional arguments are given, + they are used to initialise the pin. See :meth:`pin.init`. + +Class methods +------------- + +.. classmethod:: Pin.debug([state]) + + Get or set the debugging state (``True`` or ``False`` for on or off). + +.. classmethod:: Pin.dict([dict]) + + Get or set the pin mapper dictionary. + +.. classmethod:: Pin.mapper([fun]) + + Get or set the pin mapper function. + + +Methods +------- + +.. method:: Pin.init(mode, pull=Pin.PULL_NONE, af=-1) + + Initialise the pin: + + - ``mode`` can be one of: + + - ``Pin.IN`` - configure the pin for input; + - ``Pin.OUT_PP`` - configure the pin for output, with push-pull control; + - ``Pin.OUT_OD`` - configure the pin for output, with open-drain control; + - ``Pin.AF_PP`` - configure the pin for alternate function, pull-pull; + - ``Pin.AF_OD`` - configure the pin for alternate function, open-drain; + - ``Pin.ANALOG`` - configure the pin for analog. + + - ``pull`` can be one of: + + - ``Pin.PULL_NONE`` - no pull up or down resistors; + - ``Pin.PULL_UP`` - enable the pull-up resistor; + - ``Pin.PULL_DOWN`` - enable the pull-down resistor. + + - when mode is ``Pin.AF_PP`` or ``Pin.AF_OD``, then af can be the index or name + of one of the alternate functions associated with a pin. + + Returns: ``None``. + +.. method:: Pin.value([value]) + + Get or set the digital logic level of the pin: + + - With no argument, return 0 or 1 depending on the logic level of the pin. + - With ``value`` given, set the logic level of the pin. ``value`` can be + anything that converts to a boolean. If it converts to ``True``, the pin + is set high, otherwise it is set low. + +.. method:: Pin.__str__() + + Return a string describing the pin object. + +.. method:: Pin.af() + + Returns the currently configured alternate-function of the pin. The + integer returned will match one of the allowed constants for the af + argument to the init function. + +.. method:: Pin.af_list() + + Returns an array of alternate functions available for this pin. + +.. method:: Pin.gpio() + + Returns the base address of the GPIO block associated with this pin. + +.. method:: Pin.mode() + + Returns the currently configured mode of the pin. The integer returned + will match one of the allowed constants for the mode argument to the init + function. + +.. method:: Pin.name() + + Get the pin name. + +.. method:: Pin.names() + + Returns the cpu and board names for this pin. + +.. method:: Pin.pin() + + Get the pin number. + +.. method:: Pin.port() + + Get the pin port. + +.. method:: Pin.pull() + + Returns the currently configured pull of the pin. The integer returned + will match one of the allowed constants for the pull argument to the init + function. + +Constants +--------- + +.. data:: Pin.AF_OD + + initialise the pin to alternate-function mode with an open-drain drive + +.. data:: Pin.AF_PP + + initialise the pin to alternate-function mode with a push-pull drive + +.. data:: Pin.ANALOG + + initialise the pin to analog mode + +.. data:: Pin.IN + + initialise the pin to input mode + +.. data:: Pin.OUT_OD + + initialise the pin to output mode with an open-drain drive + +.. data:: Pin.OUT_PP + + initialise the pin to output mode with a push-pull drive + +.. data:: Pin.PULL_DOWN + + enable the pull-down resistor on the pin + +.. data:: Pin.PULL_NONE + + don't enable any pull up or down resistors on the pin + +.. data:: Pin.PULL_UP + + enable the pull-up resistor on the pin + +class PinAF -- Pin Alternate Functions +====================================== + +A Pin represents a physical pin on the microprocessor. Each pin +can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF +object represents a particular function for a pin. + +Usage Model:: + + x3 = pyb.Pin.board.X3 + x3_af = x3.af_list() + +x3_af will now contain an array of PinAF objects which are available on +pin X3. + +For the pyboard, x3_af would contain: + [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2] + +Normally, each peripheral would configure the af automatically, but sometimes +the same function is available on multiple pins, and having more control +is desired. + +To configure X3 to expose TIM2_CH3, you could use:: + + pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2) + +or:: + + pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1) + +Methods +------- + +.. method:: pinaf.__str__() + + Return a string describing the alternate function. + +.. method:: pinaf.index() + + Return the alternate function index. + +.. method:: pinaf.name() + + Return the name of the alternate function. + +.. method:: pinaf.reg() + + Return the base register associated with the peripheral assigned to this + alternate function. For example, if the alternate function were TIM2_CH3 + this would return stm.TIM2 diff --git a/src/openmv/src/micropython/docs/library/pyb.RTC.rst b/src/openmv/src/micropython/docs/library/pyb.RTC.rst new file mode 100755 index 0000000..2862686 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.RTC.rst @@ -0,0 +1,78 @@ +.. currentmodule:: pyb +.. _pyb.RTC: + +class RTC -- real time clock +============================ + +The RTC is and independent clock that keeps track of the date +and time. + +Example usage:: + + rtc = pyb.RTC() + rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0)) + print(rtc.datetime()) + + +Constructors +------------ + +.. class:: pyb.RTC() + + Create an RTC object. + + +Methods +------- + +.. method:: RTC.datetime([datetimetuple]) + + Get or set the date and time of the RTC. + + With no arguments, this method returns an 8-tuple with the current + date and time. With 1 argument (being an 8-tuple) it sets the date + and time (and ``subseconds`` is reset to 255). + + The 8-tuple has the following format: + + (year, month, day, weekday, hours, minutes, seconds, subseconds) + + ``weekday`` is 1-7 for Monday through Sunday. + + ``subseconds`` counts down from 255 to 0 + +.. method:: RTC.wakeup(timeout, callback=None) + + Set the RTC wakeup timer to trigger repeatedly at every ``timeout`` + milliseconds. This trigger can wake the pyboard from both the sleep + states: :meth:`pyb.stop` and :meth:`pyb.standby`. + + If ``timeout`` is ``None`` then the wakeup timer is disabled. + + If ``callback`` is given then it is executed at every trigger of the + wakeup timer. ``callback`` must take exactly one argument. + +.. method:: RTC.info() + + Get information about the startup time and reset source. + + - The lower 0xffff are the number of milliseconds the RTC took to + start up. + - Bit 0x10000 is set if a power-on reset occurred. + - Bit 0x20000 is set if an external reset occurred + +.. method:: RTC.calibration(cal) + + Get or set RTC calibration. + + With no arguments, ``calibration()`` returns the current calibration + value, which is an integer in the range [-511 : 512]. With one + argument it sets the RTC calibration. + + The RTC Smooth Calibration mechanism adjusts the RTC clock rate by + adding or subtracting the given number of ticks from the 32768 Hz + clock over a 32 second period (corresponding to 2^20 clock ticks.) + Each tick added will speed up the clock by 1 part in 2^20, or 0.954 + ppm; likewise the RTC clock it slowed by negative values. The + usable calibration range is: + (-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm diff --git a/src/openmv/src/micropython/docs/library/pyb.SPI.rst b/src/openmv/src/micropython/docs/library/pyb.SPI.rst new file mode 100755 index 0000000..a1910be --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.SPI.rst @@ -0,0 +1,122 @@ +.. currentmodule:: pyb +.. _pyb.SPI: + +class SPI -- a master-driven serial protocol +============================================ + +SPI is a serial protocol that is driven by a master. At the physical level +there are 3 lines: SCK, MOSI, MISO. + +See usage model of I2C; SPI is very similar. Main difference is +parameters to init the SPI bus:: + + from pyb import SPI + spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) + +Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be +0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1 +to sample data on the first or second clock edge respectively. Crc can be +None for no CRC, or a polynomial specifier. + +Additional methods for SPI:: + + data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes + buf = bytearray(4) + spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf + spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf + +Constructors +------------ + +.. class:: pyb.SPI(bus, ...) + + Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or + 'X' or 'Y'. With no additional parameters, the SPI object is created but + not initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + + The physical pins of the SPI busses are: + + - ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)`` + - ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)`` + + At the moment, the NSS pin is not used by the SPI driver and is free + for other use. + +Methods +------- + +.. method:: SPI.deinit() + + Turn off the SPI bus. + +.. method:: SPI.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) + + Initialise the SPI bus with the given parameters: + + - ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``. + - ``baudrate`` is the SCK clock rate (only sensible for a master). + - ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency; + use of ``prescaler`` overrides ``baudrate``. + - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. + - ``phase`` can be 0 or 1 to sample data on the first or second clock edge + respectively. + - ``bits`` can be 8 or 16, and is the number of bits in each transferred word. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``crc`` can be None for no CRC, or a polynomial specifier. + + Note that the SPI clock frequency will not always be the requested baudrate. + The hardware only supports baudrates that are the APB bus frequency + (see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32, + 64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise + control over the SPI clock frequency, specify ``prescaler`` instead of + ``baudrate``. + + Printing the SPI object will show you the computed baudrate and the chosen + prescaler. + +.. method:: SPI.recv(recv, \*, timeout=5000) + + Receive data on the bus: + + - ``recv`` can be an integer, which is the number of bytes to receive, + or a mutable buffer, which will be filled with received bytes. + - ``timeout`` is the timeout in milliseconds to wait for the receive. + + Return value: if ``recv`` is an integer then a new buffer of the bytes received, + otherwise the same buffer that was passed in to ``recv``. + +.. method:: SPI.send(send, \*, timeout=5000) + + Send data on the bus: + + - ``send`` is the data to send (an integer to send, or a buffer object). + - ``timeout`` is the timeout in milliseconds to wait for the send. + + Return value: ``None``. + +.. method:: SPI.send_recv(send, recv=None, \*, timeout=5000) + + Send and receive data on the bus at the same time: + + - ``send`` is the data to send (an integer to send, or a buffer object). + - ``recv`` is a mutable buffer which will be filled with received bytes. + It can be the same as ``send``, or omitted. If omitted, a new buffer will + be created. + - ``timeout`` is the timeout in milliseconds to wait for the receive. + + Return value: the buffer with the received bytes. + +Constants +--------- + +.. data:: SPI.MASTER +.. data:: SPI.SLAVE + + for initialising the SPI bus to master or slave mode + +.. data:: SPI.LSB +.. data:: SPI.MSB + + set the first bit to be the least or most significant bit diff --git a/src/openmv/src/micropython/docs/library/pyb.Servo.rst b/src/openmv/src/micropython/docs/library/pyb.Servo.rst new file mode 100755 index 0000000..b3ce71d --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.Servo.rst @@ -0,0 +1,80 @@ +.. currentmodule:: pyb +.. _pyb.Servo: + +class Servo -- 3-wire hobby servo driver +======================================== + +Servo objects control standard hobby servo motors with 3-wires (ground, power, +signal). There are 4 positions on the pyboard where these motors can be plugged +in: pins X1 through X4 are the signal pins, and next to them are 4 sets of power +and ground pins. + +Example usage:: + + import pyb + + s1 = pyb.Servo(1) # create a servo object on position X1 + s2 = pyb.Servo(2) # create a servo object on position X2 + + s1.angle(45) # move servo 1 to 45 degrees + s2.angle(0) # move servo 2 to 0 degrees + + # move servo1 and servo2 synchronously, taking 1500ms + s1.angle(-60, 1500) + s2.angle(30, 1500) + +.. note:: The Servo objects use Timer(5) to produce the PWM output. You can + use Timer(5) for Servo control, or your own purposes, but not both at the + same time. + +Constructors +------------ + +.. class:: pyb.Servo(id) + + Create a servo object. ``id`` is 1-4, and corresponds to pins X1 through X4. + + +Methods +------- + +.. method:: Servo.angle([angle, time=0]) + + If no arguments are given, this function returns the current angle. + + If arguments are given, this function sets the angle of the servo: + + - ``angle`` is the angle to move to in degrees. + - ``time`` is the number of milliseconds to take to get to the specified + angle. If omitted, then the servo moves as quickly as possible to its + new position. + +.. method:: Servo.speed([speed, time=0]) + + If no arguments are given, this function returns the current speed. + + If arguments are given, this function sets the speed of the servo: + + - ``speed`` is the speed to change to, between -100 and 100. + - ``time`` is the number of milliseconds to take to get to the specified + speed. If omitted, then the servo accelerates as quickly as possible. + +.. method:: Servo.pulse_width([value]) + + If no arguments are given, this function returns the current raw pulse-width + value. + + If an argument is given, this function sets the raw pulse-width value. + +.. method:: Servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]]) + + If no arguments are given, this function returns the current calibration + data, as a 5-tuple. + + If arguments are given, this function sets the timing calibration: + + - ``pulse_min`` is the minimum allowed pulse width. + - ``pulse_max`` is the maximum allowed pulse width. + - ``pulse_centre`` is the pulse width corresponding to the centre/zero position. + - ``pulse_angle_90`` is the pulse width corresponding to 90 degrees. + - ``pulse_speed_100`` is the pulse width corresponding to a speed of 100. diff --git a/src/openmv/src/micropython/docs/library/pyb.Switch.rst b/src/openmv/src/micropython/docs/library/pyb.Switch.rst new file mode 100755 index 0000000..1edcbf8 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.Switch.rst @@ -0,0 +1,46 @@ +.. currentmodule:: pyb +.. _pyb.Switch: + +class Switch -- switch object +============================= + +A Switch object is used to control a push-button switch. + +Usage:: + + sw = pyb.Switch() # create a switch object + sw.value() # get state (True if pressed, False otherwise) + sw() # shorthand notation to get the switch state + sw.callback(f) # register a callback to be called when the + # switch is pressed down + sw.callback(None) # remove the callback + +Example:: + + pyb.Switch().callback(lambda: pyb.LED(1).toggle()) + + +Constructors +------------ + +.. class:: pyb.Switch() + + Create and return a switch object. + + +Methods +------- + +.. method:: Switch.__call__() + + Call switch object directly to get its state: ``True`` if pressed down, + ``False`` otherwise. + +.. method:: Switch.value() + + Get the switch state. Returns ``True`` if pressed down, otherwise ``False``. + +.. method:: Switch.callback(fun) + + Register the given function to be called when the switch is pressed down. + If ``fun`` is ``None``, then it disables the callback. diff --git a/src/openmv/src/micropython/docs/library/pyb.Timer.rst b/src/openmv/src/micropython/docs/library/pyb.Timer.rst new file mode 100755 index 0000000..977ba88 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.Timer.rst @@ -0,0 +1,264 @@ +.. currentmodule:: pyb +.. _pyb.Timer: + +class Timer -- control internal timers +====================================== + +Timers can be used for a great variety of tasks. At the moment, only +the simplest case is implemented: that of calling a function periodically. + +Each timer consists of a counter that counts up at a certain rate. The rate +at which it counts is the peripheral clock frequency (in Hz) divided by the +timer prescaler. When the counter reaches the timer period it triggers an +event, and the counter resets back to zero. By using the callback method, +the timer event can call a Python function. + +Example usage to toggle an LED at a fixed frequency:: + + tim = pyb.Timer(4) # create a timer object using timer 4 + tim.init(freq=2) # trigger at 2Hz + tim.callback(lambda t:pyb.LED(1).toggle()) + +Example using named function for the callback:: + + def tick(timer): # we will receive the timer object when being called + print(timer.counter()) # show current timer's counter value + tim = pyb.Timer(4, freq=1) # create a timer object using timer 4 - trigger at 1Hz + tim.callback(tick) # set the callback to our tick function + +Further examples:: + + tim = pyb.Timer(4, freq=100) # freq in Hz + tim = pyb.Timer(4, prescaler=0, period=99) + tim.counter() # get counter (can also set) + tim.prescaler(2) # set prescaler (can also get) + tim.period(199) # set period (can also get) + tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance) + tim.callback(None) # clear callback + +*Note:* Timer(2) and Timer(3) are used for PWM to set the intensity of LED(3) +and LED(4) respectively. But these timers are only configured for PWM if +the intensity of the relevant LED is set to a value between 1 and 254. If +the intensity feature of the LEDs is not used then these timers are free for +general purpose use. Similarly, Timer(5) controls the servo driver, and +Timer(6) is used for timed ADC/DAC reading/writing. It is recommended to +use the other timers in your programs. + +*Note:* Memory can't be allocated during a callback (an interrupt) and so +exceptions raised within a callback don't give much information. See +:func:`micropython.alloc_emergency_exception_buf` for how to get around this +limitation. + + +Constructors +------------ + +.. class:: pyb.Timer(id, ...) + + Construct a new timer object of the given id. If additional + arguments are given, then the timer is initialised by ``init(...)``. + ``id`` can be 1 to 14. + +Methods +------- + +.. method:: Timer.init(\*, freq, prescaler, period) + + Initialise the timer. Initialisation must be either by frequency (in Hz) + or by prescaler and period:: + + tim.init(freq=100) # set the timer to trigger at 100Hz + tim.init(prescaler=83, period=999) # set the prescaler and period directly + + Keyword arguments: + + - ``freq`` --- specifies the periodic frequency of the timer. You might also + view this as the frequency with which the timer goes through one complete cycle. + + - ``prescaler`` [0-0xffff] - specifies the value to be loaded into the + timer's Prescaler Register (PSC). The timer clock source is divided by + (``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14 + have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11 + have a clock source of 168 MHz (pyb.freq()[3] \* 2). + + - ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5. + Specifies the value to be loaded into the timer's AutoReload + Register (ARR). This determines the period of the timer (i.e. when the + counter cycles). The timer counter will roll-over after ``period + 1`` + timer clock cycles. + + - ``mode`` can be one of: + + - ``Timer.UP`` - configures the timer to count from 0 to ARR (default) + - ``Timer.DOWN`` - configures the timer to count from ARR down to 0. + - ``Timer.CENTER`` - configures the timer to count from 0 to ARR and + then back down to 0. + + - ``div`` can be one of 1, 2, or 4. Divides the timer clock to determine + the sampling clock used by the digital filters. + + - ``callback`` - as per Timer.callback() + + - ``deadtime`` - specifies the amount of "dead" or inactive time between + transitions on complimentary channels (both channels will be inactive) + for this time). ``deadtime`` may be an integer between 0 and 1008, with + the following restrictions: 0-128 in steps of 1. 128-256 in steps of + 2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadtime`` + measures ticks of ``source_freq`` divided by ``div`` clock ticks. + ``deadtime`` is only available on timers 1 and 8. + + You must either specify freq or both of period and prescaler. + +.. method:: Timer.deinit() + + Deinitialises the timer. + + Disables the callback (and the associated irq). + + Disables any channel callbacks (and the associated irq). + Stops the timer, and disables the timer peripheral. + +.. method:: Timer.callback(fun) + + Set the function to be called when the timer triggers. + ``fun`` is passed 1 argument, the timer object. + If ``fun`` is ``None`` then the callback will be disabled. + +.. method:: Timer.channel(channel, mode, ...) + + If only a channel number is passed, then a previously initialized channel + object is returned (or ``None`` if there is no previous channel). + + Otherwise, a TimerChannel object is initialized and returned. + + Each channel can be configured to perform pwm, output compare, or + input capture. All channels share the same underlying timer, which means + that they share the same timer clock. + + Keyword arguments: + + - ``mode`` can be one of: + + - ``Timer.PWM`` --- configure the timer in PWM mode (active high). + - ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low). + - ``Timer.OC_TIMING`` --- indicates that no pin is driven. + - ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity) + - ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs. + - ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs. + - ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored). + - ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored). + - ``Timer.IC`` --- configure the timer in Input Capture mode. + - ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes. + - ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes. + - ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes. + + - ``callback`` - as per TimerChannel.callback() + + - ``pin`` None (the default) or a Pin object. If specified (and not None) + this will cause the alternate function of the the indicated pin + to be configured for this timer channel. An error will be raised if + the pin doesn't support any alternate functions for this timer channel. + + Keyword arguments for Timer.PWM modes: + + - ``pulse_width`` - determines the initial pulse width value to use. + - ``pulse_width_percent`` - determines the initial pulse width percentage to use. + + Keyword arguments for Timer.OC modes: + + - ``compare`` - determines the initial value of the compare register. + + - ``polarity`` can be one of: + + - ``Timer.HIGH`` - output is active high + - ``Timer.LOW`` - output is active low + + Optional keyword arguments for Timer.IC modes: + + - ``polarity`` can be one of: + + - ``Timer.RISING`` - captures on rising edge. + - ``Timer.FALLING`` - captures on falling edge. + - ``Timer.BOTH`` - captures on both edges. + + Note that capture only works on the primary channel, and not on the + complimentary channels. + + Notes for Timer.ENC modes: + + - Requires 2 pins, so one or both pins will need to be configured to use + the appropriate timer AF using the Pin API. + - Read the encoder value using the timer.counter() method. + - Only works on CH1 and CH2 (and not on CH1N or CH2N) + - The channel number is ignored when setting the encoder mode. + + PWM Example:: + + timer = pyb.Timer(2, freq=1000) + ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000) + ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000) + +.. method:: Timer.counter([value]) + + Get or set the timer counter. + +.. method:: Timer.freq([value]) + + Get or set the frequency for the timer (changes prescaler and period if set). + +.. method:: Timer.period([value]) + + Get or set the period of the timer. + +.. method:: Timer.prescaler([value]) + + Get or set the prescaler for the timer. + +.. method:: Timer.source_freq() + + Get the frequency of the source of the timer. + +class TimerChannel --- setup a channel for a timer +================================================== + +Timer channels are used to generate/capture a signal using a timer. + +TimerChannel objects are created using the Timer.channel() method. + +Methods +------- + +.. method:: timerchannel.callback(fun) + + Set the function to be called when the timer channel triggers. + ``fun`` is passed 1 argument, the timer object. + If ``fun`` is ``None`` then the callback will be disabled. + +.. method:: timerchannel.capture([value]) + + Get or set the capture value associated with a channel. + capture, compare, and pulse_width are all aliases for the same function. + capture is the logical name to use when the channel is in input capture mode. + +.. method:: timerchannel.compare([value]) + + Get or set the compare value associated with a channel. + capture, compare, and pulse_width are all aliases for the same function. + compare is the logical name to use when the channel is in output compare mode. + +.. method:: timerchannel.pulse_width([value]) + + Get or set the pulse width value associated with a channel. + capture, compare, and pulse_width are all aliases for the same function. + pulse_width is the logical name to use when the channel is in PWM mode. + + In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100% + In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100% + +.. method:: timerchannel.pulse_width_percent([value]) + + Get or set the pulse width percentage associated with a channel. The value + is a number between 0 and 100 and sets the percentage of the timer period + for which the pulse is active. The value can be an integer or + floating-point number for more accuracy. For example, a value of 25 gives + a duty cycle of 25%. diff --git a/src/openmv/src/micropython/docs/library/pyb.UART.rst b/src/openmv/src/micropython/docs/library/pyb.UART.rst new file mode 100755 index 0000000..4359f1d --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.UART.rst @@ -0,0 +1,225 @@ +.. currentmodule:: pyb +.. _pyb.UART: + +class UART -- duplex serial communication bus +============================================= + +UART implements the standard UART/USART duplex serial communications protocol. At +the physical level it consists of 2 lines: RX and TX. The unit of communication +is a character (not to be confused with a string character) which can be 8 or 9 +bits wide. + +UART objects can be created and initialised using:: + + from pyb import UART + + uart = UART(1, 9600) # init with given baudrate + uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters + +Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2. + +*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, +only 7 and 8 bits are supported. + +A UART object acts like a `stream` object and reading and writing is done +using the standard stream methods:: + + uart.read(10) # read 10 characters, returns a bytes object + uart.read() # read all available characters + uart.readline() # read a line + uart.readinto(buf) # read and store into the given buffer + uart.write('abc') # write the 3 characters + +Individual characters can be read/written using:: + + uart.readchar() # read 1 character and returns it as an integer + uart.writechar(42) # write 1 character + +To check if there is anything to be read, use:: + + uart.any() # returns the number of characters waiting + + +*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4. +Earlier versions use ``uart.send`` and ``uart.recv``. + +Constructors +------------ + +.. class:: pyb.UART(bus, ...) + + Construct a UART object on the given bus. ``bus`` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'. + With no additional parameters, the UART object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. + + The physical pins of the UART busses are: + + - ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)`` + - ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)`` + - ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)`` + - ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)`` + - ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)`` + + The Pyboard Lite supports UART(1), UART(2) and UART(6) only. Pins are as above except: + + - ``UART(2)`` is on: ``(TX, RX) = (X1, X2) = (PA2, PA3)`` + +Methods +------- + +.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64) + + Initialise the UART bus with the given parameters: + + - ``baudrate`` is the clock rate. + - ``bits`` is the number of bits per character, 7, 8 or 9. + - ``parity`` is the parity, ``None``, 0 (even) or 1 (odd). + - ``stop`` is the number of stop bits, 1 or 2. + - ``flow`` sets the flow control type. Can be 0, ``UART.RTS``, ``UART.CTS`` + or ``UART.RTS | UART.CTS``. + - ``timeout`` is the timeout in milliseconds to wait for writing/reading the first character. + - ``timeout_char`` is the timeout in milliseconds to wait between characters while writing or reading. + - ``read_buf_len`` is the character length of the read buffer (0 to disable). + + This method will raise an exception if the baudrate could not be set within + 5% of the desired value. The minimum baudrate is dictated by the frequency + of the bus that the UART is on; UART(1) and UART(6) are APB2, the rest are on + APB1. The default bus frequencies give a minimum baudrate of 1300 for + UART(1) and UART(6) and 650 for the others. Use :func:`pyb.freq ` + to reduce the bus frequencies to get lower baudrates. + + *Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, + only 7 and 8 bits are supported. + +.. method:: UART.deinit() + + Turn off the UART bus. + +.. method:: UART.any() + + Returns the number of bytes waiting (may be 0). + +.. method:: UART.read([nbytes]) + + Read characters. If ``nbytes`` is specified then read at most that many bytes. + If ``nbytes`` are available in the buffer, returns immediately, otherwise returns + when sufficient characters arrive or the timeout elapses. + + If ``nbytes`` is not given then the method reads as much data as possible. It + returns after the timeout has elapsed. + + *Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must + be even, and the number of characters is ``nbytes/2``. + + Return value: a bytes object containing the bytes read in. Returns ``None`` + on timeout. + +.. method:: UART.readchar() + + Receive a single character on the bus. + + Return value: The character read, as an integer. Returns -1 on timeout. + +.. method:: UART.readinto(buf[, nbytes]) + + Read bytes into the ``buf``. If ``nbytes`` is specified then read at most + that many bytes. Otherwise, read at most ``len(buf)`` bytes. + + Return value: number of bytes read and stored into ``buf`` or ``None`` on + timeout. + +.. method:: UART.readline() + + Read a line, ending in a newline character. If such a line exists, return is + immediate. If the timeout elapses, all available data is returned regardless + of whether a newline exists. + + Return value: the line read or ``None`` on timeout if no data is available. + +.. method:: UART.write(buf) + + Write the buffer of bytes to the bus. If characters are 7 or 8 bits wide + then each byte is one character. If characters are 9 bits wide then two + bytes are used for each character (little endian), and ``buf`` must contain + an even number of bytes. + + Return value: number of bytes written. If a timeout occurs and no bytes + were written returns ``None``. + +.. method:: UART.writechar(char) + + Write a single character on the bus. ``char`` is an integer to write. + Return value: ``None``. See note below if CTS flow control is used. + +.. method:: UART.sendbreak() + + Send a break condition on the bus. This drives the bus low for a duration + of 13 bits. + Return value: ``None``. + +Constants +--------- + +.. data:: UART.RTS + UART.CTS + + to select the flow control type. + +Flow Control +------------ + +On Pyboards V1 and V1.1 ``UART(2)`` and ``UART(3)`` support RTS/CTS hardware flow control +using the following pins: + + - ``UART(2)`` is on: ``(TX, RX, nRTS, nCTS) = (X3, X4, X2, X1) = (PA2, PA3, PA1, PA0)`` + - ``UART(3)`` is on :``(TX, RX, nRTS, nCTS) = (Y9, Y10, Y7, Y6) = (PB10, PB11, PB14, PB13)`` + +On the Pyboard Lite only ``UART(2)`` supports flow control on these pins: + + ``(TX, RX, nRTS, nCTS) = (X1, X2, X4, X3) = (PA2, PA3, PA1, PA0)`` + +In the following paragraphs the term "target" refers to the device connected to +the UART. + +When the UART's ``init()`` method is called with ``flow`` set to one or both of +``UART.RTS`` and ``UART.CTS`` the relevant flow control pins are configured. +``nRTS`` is an active low output, ``nCTS`` is an active low input with pullup +enabled. To achieve flow control the Pyboard's ``nCTS`` signal should be connected +to the target's ``nRTS`` and the Pyboard's ``nRTS`` to the target's ``nCTS``. + +CTS: target controls Pyboard transmitter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If CTS flow control is enabled the write behaviour is as follows: + +If the Pyboard's ``UART.write(buf)`` method is called, transmission will stall for +any periods when ``nCTS`` is ``False``. This will result in a timeout if the entire +buffer was not transmitted in the timeout period. The method returns the number of +bytes written, enabling the user to write the remainder of the data if required. In +the event of a timeout, a character will remain in the UART pending ``nCTS``. The +number of bytes composing this character will be included in the return value. + +If ``UART.writechar()`` is called when ``nCTS`` is ``False`` the method will time +out unless the target asserts ``nCTS`` in time. If it times out ``OSError 116`` +will be raised. The character will be transmitted as soon as the target asserts ``nCTS``. + +RTS: Pyboard controls target's transmitter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If RTS flow control is enabled, behaviour is as follows: + +If buffered input is used (``read_buf_len`` > 0), incoming characters are buffered. +If the buffer becomes full, the next character to arrive will cause ``nRTS`` to go +``False``: the target should cease transmission. ``nRTS`` will go ``True`` when +characters are read from the buffer. + +Note that the ``any()`` method returns the number of bytes in the buffer. Assume a +buffer length of ``N`` bytes. If the buffer becomes full, and another character arrives, +``nRTS`` will be set False, and ``any()`` will return the count ``N``. When +characters are read the additional character will be placed in the buffer and will +be included in the result of a subsequent ``any()`` call. + +If buffered input is not used (``read_buf_len`` == 0) the arrival of a character will +cause ``nRTS`` to go ``False`` until the character is read. diff --git a/src/openmv/src/micropython/docs/library/pyb.USB_HID.rst b/src/openmv/src/micropython/docs/library/pyb.USB_HID.rst new file mode 100755 index 0000000..7027044 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.USB_HID.rst @@ -0,0 +1,40 @@ +.. currentmodule:: pyb +.. _pyb.USB_HID: + +class USB_HID -- USB Human Interface Device (HID) +================================================= + +The USB_HID class allows creation of an object representing the USB +Human Interface Device (HID) interface. It can be used to emulate +a peripheral such as a mouse or keyboard. + +Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface. + +Constructors +------------ + +.. class:: pyb.USB_HID() + + Create a new USB_HID object. + + +Methods +------- + +.. method:: USB_HID.recv(data, \*, timeout=5000) + + Receive data on the bus: + + - ``data`` can be an integer, which is the number of bytes to receive, + or a mutable buffer, which will be filled with received bytes. + - ``timeout`` is the timeout in milliseconds to wait for the receive. + + Return value: if ``data`` is an integer then a new buffer of the bytes received, + otherwise the number of bytes read into ``data`` is returned. + +.. method:: USB_HID.send(data) + + Send data over the USB HID interface: + + - ``data`` is the data to send (a tuple/list of integers, or a + bytearray). diff --git a/src/openmv/src/micropython/docs/library/pyb.USB_VCP.rst b/src/openmv/src/micropython/docs/library/pyb.USB_VCP.rst new file mode 100755 index 0000000..3bc6c74 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.USB_VCP.rst @@ -0,0 +1,103 @@ +.. currentmodule:: pyb +.. _pyb.USB_VCP: + +class USB_VCP -- USB virtual comm port +====================================== + +The USB_VCP class allows creation of a `stream`-like object representing the USB +virtual comm port. It can be used to read and write data over USB to +the connected host. + + +Constructors +------------ + +.. class:: pyb.USB_VCP() + + Create a new USB_VCP object. + + +Methods +------- + +.. method:: USB_VCP.setinterrupt(chr) + + Set the character which interrupts running Python code. This is set + to 3 (CTRL-C) by default, and when a CTRL-C character is received over + the USB VCP port, a KeyboardInterrupt exception is raised. + + Set to -1 to disable this interrupt feature. This is useful when you + want to send raw bytes over the USB VCP port. + +.. method:: USB_VCP.isconnected() + + Return ``True`` if USB is connected as a serial device, else ``False``. + +.. method:: USB_VCP.any() + + Return ``True`` if any characters waiting, else ``False``. + +.. method:: USB_VCP.close() + + This method does nothing. It exists so the USB_VCP object can act as + a file. + +.. method:: USB_VCP.read([nbytes]) + + Read at most ``nbytes`` from the serial device and return them as a + bytes object. If ``nbytes`` is not specified then the method reads + all available bytes from the serial device. + USB_VCP `stream` implicitly works in non-blocking mode, + so if no pending data available, this method will return immediately + with ``None`` value. + +.. method:: USB_VCP.readinto(buf, [maxlen]) + + Read bytes from the serial device and store them into ``buf``, which + should be a buffer-like object. At most ``len(buf)`` bytes are read. + If ``maxlen`` is given and then at most ``min(maxlen, len(buf))`` bytes + are read. + + Returns the number of bytes read and stored into ``buf`` or ``None`` + if no pending data available. + +.. method:: USB_VCP.readline() + + Read a whole line from the serial device. + + Returns a bytes object containing the data, including the trailing + newline character or ``None`` if no pending data available. + +.. method:: USB_VCP.readlines() + + Read as much data as possible from the serial device, breaking it into + lines. + + Returns a list of bytes objects, each object being one of the lines. + Each line will include the newline character. + +.. method:: USB_VCP.write(buf) + + Write the bytes from ``buf`` to the serial device. + + Returns the number of bytes written. + +.. method:: USB_VCP.recv(data, \*, timeout=5000) + + Receive data on the bus: + + - ``data`` can be an integer, which is the number of bytes to receive, + or a mutable buffer, which will be filled with received bytes. + - ``timeout`` is the timeout in milliseconds to wait for the receive. + + Return value: if ``data`` is an integer then a new buffer of the bytes received, + otherwise the number of bytes read into ``data`` is returned. + +.. method:: USB_VCP.send(data, \*, timeout=5000) + + Send data over the USB VCP: + + - ``data`` is the data to send (an integer to send, or a buffer object). + - ``timeout`` is the timeout in milliseconds to wait for the send. + + Return value: number of bytes sent. diff --git a/src/openmv/src/micropython/docs/library/pyb.rst b/src/openmv/src/micropython/docs/library/pyb.rst new file mode 100755 index 0000000..1e1e9ff --- /dev/null +++ b/src/openmv/src/micropython/docs/library/pyb.rst @@ -0,0 +1,312 @@ +:mod:`pyb` --- functions related to the board +============================================= + +.. module:: pyb + :synopsis: functions related to the board + +The ``pyb`` module contains specific functions related to the board. + +Time related functions +---------------------- + +.. function:: delay(ms) + + Delay for the given number of milliseconds. + +.. function:: udelay(us) + + Delay for the given number of microseconds. + +.. function:: millis() + + Returns the number of milliseconds since the board was last reset. + + The result is always a MicroPython smallint (31-bit signed number), so + after 2^30 milliseconds (about 12.4 days) this will start to return + negative numbers. + + Note that if :meth:`pyb.stop()` is issued the hardware counter supporting this + function will pause for the duration of the "sleeping" state. This + will affect the outcome of :meth:`pyb.elapsed_millis()`. + +.. function:: micros() + + Returns the number of microseconds since the board was last reset. + + The result is always a MicroPython smallint (31-bit signed number), so + after 2^30 microseconds (about 17.8 minutes) this will start to return + negative numbers. + + Note that if :meth:`pyb.stop()` is issued the hardware counter supporting this + function will pause for the duration of the "sleeping" state. This + will affect the outcome of :meth:`pyb.elapsed_micros()`. + +.. function:: elapsed_millis(start) + + Returns the number of milliseconds which have elapsed since ``start``. + + This function takes care of counter wrap, and always returns a positive + number. This means it can be used to measure periods up to about 12.4 days. + + Example:: + + start = pyb.millis() + while pyb.elapsed_millis(start) < 1000: + # Perform some operation + +.. function:: elapsed_micros(start) + + Returns the number of microseconds which have elapsed since ``start``. + + This function takes care of counter wrap, and always returns a positive + number. This means it can be used to measure periods up to about 17.8 minutes. + + Example:: + + start = pyb.micros() + while pyb.elapsed_micros(start) < 1000: + # Perform some operation + pass + +Reset related functions +----------------------- + +.. function:: hard_reset() + + Resets the pyboard in a manner similar to pushing the external RESET + button. + +.. function:: bootloader() + + Activate the bootloader without BOOT\* pins. + +.. function:: fault_debug(value) + + Enable or disable hard-fault debugging. A hard-fault is when there is a fatal + error in the underlying system, like an invalid memory access. + + If the *value* argument is ``False`` then the board will automatically reset if + there is a hard fault. + + If *value* is ``True`` then, when the board has a hard fault, it will print the + registers and the stack trace, and then cycle the LEDs indefinitely. + + The default value is disabled, i.e. to automatically reset. + +Interrupt related functions +--------------------------- + +.. function:: disable_irq() + + Disable interrupt requests. + Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs + respectively. This return value can be passed to enable_irq to restore + the IRQ to its original state. + +.. function:: enable_irq(state=True) + + Enable interrupt requests. + If ``state`` is ``True`` (the default value) then IRQs are enabled. + If ``state`` is ``False`` then IRQs are disabled. The most common use of + this function is to pass it the value returned by ``disable_irq`` to + exit a critical section. + +Power related functions +----------------------- + +.. function:: freq([sysclk[, hclk[, pclk1[, pclk2]]]]) + + If given no arguments, returns a tuple of clock frequencies: + (sysclk, hclk, pclk1, pclk2). + These correspond to: + + - sysclk: frequency of the CPU + - hclk: frequency of the AHB bus, core memory and DMA + - pclk1: frequency of the APB1 bus + - pclk2: frequency of the APB2 bus + + If given any arguments then the function sets the frequency of the CPU, + and the busses if additional arguments are given. Frequencies are given in + Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that + not all values are supported and the largest supported frequency not greater + than the given value will be selected. + + Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48, + 54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168. + + The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is + 84MHz. Be sure not to set frequencies above these values. + + The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency + using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8, + 16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2, + 4, 8. A prescaler will be chosen to best match the requested frequency. + + A sysclk frequency of + 8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI + (internal oscillator) directly. The higher frequencies use the HSE to + drive the PLL (phase locked loop), and then use the output of the PLL. + + Note that if you change the frequency while the USB is enabled then + the USB may become unreliable. It is best to change the frequency + in boot.py, before the USB peripheral is started. Also note that sysclk + frequencies below 36MHz do not allow the USB to function correctly. + +.. function:: wfi() + + Wait for an internal or external interrupt. + + This executes a ``wfi`` instruction which reduces power consumption + of the MCU until any interrupt occurs (be it internal or external), + at which point execution continues. Note that the system-tick interrupt + occurs once every millisecond (1000Hz) so this function will block for + at most 1ms. + +.. function:: stop() + + Put the pyboard in a "sleeping" state. + + This reduces power consumption to less than 500 uA. To wake from this + sleep state requires an external interrupt or a real-time-clock event. + Upon waking execution continues where it left off. + + See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event. + +.. function:: standby() + + Put the pyboard into a "deep sleep" state. + + This reduces power consumption to less than 50 uA. To wake from this + sleep state requires a real-time-clock event, or an external interrupt + on X1 (PA0=WKUP) or X18 (PC13=TAMP1). + Upon waking the system undergoes a hard reset. + + See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event. + +Miscellaneous functions +----------------------- + +.. function:: have_cdc() + + Return True if USB is connected as a serial device, False otherwise. + + .. note:: This function is deprecated. Use pyb.USB_VCP().isconnected() instead. + +.. function:: hid((buttons, x, y, z)) + + Takes a 4-tuple (or list) and sends it to the USB host (the PC) to + signal a HID mouse-motion event. + + .. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead. + +.. function:: info([dump_alloc_table]) + + Print out lots of information about the board. + +.. function:: main(filename) + + Set the filename of the main script to run after boot.py is finished. If + this function is not called then the default file main.py will be executed. + + It only makes sense to call this function from within boot.py. + +.. function:: mount(device, mountpoint, \*, readonly=False, mkfs=False) + + .. note:: This function is deprecated. Mounting and unmounting devices should + be performed by :meth:`uos.mount` and :meth:`uos.umount` instead. + + Mount a block device and make it available as part of the filesystem. + ``device`` must be an object that provides the block protocol. (The + following is also deprecated. See :class:`uos.AbstractBlockDev` for the + correct way to create a block device.) + + - ``readblocks(self, blocknum, buf)`` + - ``writeblocks(self, blocknum, buf)`` (optional) + - ``count(self)`` + - ``sync(self)`` (optional) + + ``readblocks`` and ``writeblocks`` should copy data between ``buf`` and + the block device, starting from block number ``blocknum`` on the device. + ``buf`` will be a bytearray with length a multiple of 512. If + ``writeblocks`` is not defined then the device is mounted read-only. + The return value of these two functions is ignored. + + ``count`` should return the number of blocks available on the device. + ``sync``, if implemented, should sync the data on the device. + + The parameter ``mountpoint`` is the location in the root of the filesystem + to mount the device. It must begin with a forward-slash. + + If ``readonly`` is ``True``, then the device is mounted read-only, + otherwise it is mounted read-write. + + If ``mkfs`` is ``True``, then a new filesystem is created if one does not + already exist. + +.. function:: repl_uart(uart) + + Get or set the UART object where the REPL is repeated on. + +.. function:: rng() + + Return a 30-bit hardware generated random number. + +.. function:: sync() + + Sync all file systems. + +.. function:: unique_id() + + Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU. + +.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse) + + If called with no arguments, return the current USB mode as a string. + + If called with ``modestr`` provided, attempts to set USB mode. + This can only be done when called from ``boot.py`` before + :meth:`pyb.main()` has been called. The following values of + ``modestr`` are understood: + + - ``None``: disables USB + - ``'VCP'``: enable with VCP (Virtual COM Port) interface + - ``'MSC'``: enable with MSC (mass storage device class) interface + - ``'VCP+MSC'``: enable with VCP and MSC + - ``'VCP+HID'``: enable with VCP and HID (human interface device) + + For backwards compatibility, ``'CDC'`` is understood to mean + ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). + + The ``vid`` and ``pid`` parameters allow you to specify the VID + (vendor id) and PID (product id). + + If enabling HID mode, you may also specify the HID details by + passing the ``hid`` keyword parameter. It takes a tuple of + (subclass, protocol, max packet length, polling interval, report + descriptor). By default it will set appropriate values for a USB + mouse. There is also a ``pyb.hid_keyboard`` constant, which is an + appropriate tuple for a USB keyboard. + +Classes +------- + +.. toctree:: + :maxdepth: 1 + + pyb.Accel.rst + pyb.ADC.rst + pyb.CAN.rst + pyb.DAC.rst + pyb.ExtInt.rst + pyb.I2C.rst + pyb.LCD.rst + pyb.LED.rst + pyb.Pin.rst + pyb.RTC.rst + pyb.Servo.rst + pyb.SPI.rst + pyb.Switch.rst + pyb.Timer.rst + pyb.UART.rst + pyb.USB_HID.rst + pyb.USB_VCP.rst diff --git a/src/openmv/src/micropython/docs/library/sys.rst b/src/openmv/src/micropython/docs/library/sys.rst new file mode 100755 index 0000000..f2d96cb --- /dev/null +++ b/src/openmv/src/micropython/docs/library/sys.rst @@ -0,0 +1,123 @@ +:mod:`sys` -- system specific functions +======================================= + +.. module:: sys + :synopsis: system specific functions + +|see_cpython_module| :mod:`python:sys`. + +Functions +--------- + +.. function:: exit(retval=0) + + Terminate current program with a given exit code. Underlyingly, this + function raise as `SystemExit` exception. If an argument is given, its + value given as an argument to `SystemExit`. + +.. function:: print_exception(exc, file=sys.stdout) + + Print exception with a traceback to a file-like object *file* (or + `sys.stdout` by default). + + .. admonition:: Difference to CPython + :class: attention + + This is simplified version of a function which appears in the + ``traceback`` module in CPython. Unlike ``traceback.print_exception()``, + this function takes just exception value instead of exception type, + exception value, and traceback object; *file* argument should be + positional; further arguments are not supported. CPython-compatible + ``traceback`` module can be found in `micropython-lib`. + +Constants +--------- + +.. data:: argv + + A mutable list of arguments the current program was started with. + +.. data:: byteorder + + The byte order of the system (``"little"`` or ``"big"``). + +.. data:: implementation + + Object with information about the current Python implementation. For + MicroPython, it has following attributes: + + * *name* - string "micropython" + * *version* - tuple (major, minor, micro), e.g. (1, 7, 0) + + This object is the recommended way to distinguish MicroPython from other + Python implementations (note that it still may not exist in the very + minimal ports). + + .. admonition:: Difference to CPython + :class: attention + + CPython mandates more attributes for this object, but the actual useful + bare minimum is implemented in MicroPython. + +.. data:: maxsize + + Maximum value which a native integer type can hold on the current platform, + or maximum value representable by MicroPython integer type, if it's smaller + than platform max value (that is the case for MicroPython ports without + long int support). + + This attribute is useful for detecting "bitness" of a platform (32-bit vs + 64-bit, etc.). It's recommended to not compare this attribute to some + value directly, but instead count number of bits in it:: + + bits = 0 + v = sys.maxsize + while v: + bits += 1 + v >>= 1 + if bits > 32: + # 64-bit (or more) platform + ... + else: + # 32-bit (or less) platform + # Note that on 32-bit platform, value of bits may be less than 32 + # (e.g. 31) due to peculiarities described above, so use "> 16", + # "> 32", "> 64" style of comparisons. + +.. data:: modules + + Dictionary of loaded modules. On some ports, it may not include builtin + modules. + +.. data:: path + + A mutable list of directories to search for imported modules. + +.. data:: platform + + The platform that MicroPython is running on. For OS/RTOS ports, this is + usually an identifier of the OS, e.g. ``"linux"``. For baremetal ports it + is an identifier of a board, e.g. ``"pyboard"`` for the original MicroPython + reference board. It thus can be used to distinguish one board from another. + If you need to check whether your program runs on MicroPython (vs other + Python implementation), use `sys.implementation` instead. + +.. data:: stderr + + Standard error `stream`. + +.. data:: stdin + + Standard input `stream`. + +.. data:: stdout + + Standard output `stream`. + +.. data:: version + + Python language version that this implementation conforms to, as a string. + +.. data:: version_info + + Python language version that this implementation conforms to, as a tuple of ints. diff --git a/src/openmv/src/micropython/docs/library/ubinascii.rst b/src/openmv/src/micropython/docs/library/ubinascii.rst new file mode 100755 index 0000000..192d345 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ubinascii.rst @@ -0,0 +1,40 @@ +:mod:`ubinascii` -- binary/ASCII conversions +============================================ + +.. module:: ubinascii + :synopsis: binary/ASCII conversions + +|see_cpython_module| :mod:`python:binascii`. + +This module implements conversions between binary data and various +encodings of it in ASCII form (in both directions). + +Functions +--------- + +.. function:: hexlify(data, [sep]) + + Convert binary data to hexadecimal representation. Returns bytes string. + + .. admonition:: Difference to CPython + :class: attention + + If additional argument, *sep* is supplied, it is used as a separator + between hexadecimal values. + +.. function:: unhexlify(data) + + Convert hexadecimal data to binary representation. Returns bytes string. + (i.e. inverse of hexlify) + +.. function:: a2b_base64(data) + + Decode base64-encoded data, ignoring invalid characters in the input. + Conforms to `RFC 2045 s.6.8 `_. + Returns a bytes object. + +.. function:: b2a_base64(data) + + Encode binary data in base64 format, as in `RFC 3548 + `_. Returns the encoded data + followed by a newline character, as a bytes object. diff --git a/src/openmv/src/micropython/docs/library/ucollections.rst b/src/openmv/src/micropython/docs/library/ucollections.rst new file mode 100755 index 0000000..b833842 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ucollections.rst @@ -0,0 +1,82 @@ +:mod:`ucollections` -- collection and container types +===================================================== + +.. module:: ucollections + :synopsis: collection and container types + +|see_cpython_module| :mod:`python:collections`. + +This module implements advanced collection and container types to +hold/accumulate various objects. + +Classes +------- + +.. function:: deque(iterable, maxlen[, flags]) + + Deques (double-ended queues) are a list-like container that support O(1) + appends and pops from either side of the deque. New deques are created + using the following arguments: + + - *iterable* must be the empty tuple, and the new deque is created empty. + + - *maxlen* must be specified and the deque will be bounded to this + maximum length. Once the deque is full, any new items added will + discard items from the opposite end. + + - The optional *flags* can be 1 to check for overflow when adding items. + + As well as supporting `bool` and `len`, deque objects have the following + methods: + + .. method:: deque.append(x) + + Add *x* to the right side of the deque. + Raises IndexError if overflow checking is enabled and there is no more room left. + + .. method:: deque.popleft() + + Remove and return an item from the left side of the deque. + Raises IndexError if no items are present. + +.. function:: namedtuple(name, fields) + + This is factory function to create a new namedtuple type with a specific + name and set of fields. A namedtuple is a subclass of tuple which allows + to access its fields not just by numeric index, but also with an attribute + access syntax using symbolic field names. Fields is a sequence of strings + specifying field names. For compatibility with CPython it can also be a + a string with space-separated field named (but this is less efficient). + Example of use:: + + from ucollections import namedtuple + + MyTuple = namedtuple("MyTuple", ("id", "name")) + t1 = MyTuple(1, "foo") + t2 = MyTuple(2, "bar") + print(t1.name) + assert t2.name == t2[1] + +.. function:: OrderedDict(...) + + ``dict`` type subclass which remembers and preserves the order of keys + added. When ordered dict is iterated over, keys/items are returned in + the order they were added:: + + from ucollections import OrderedDict + + # To make benefit of ordered keys, OrderedDict should be initialized + # from sequence of (key, value) pairs. + d = OrderedDict([("z", 1), ("a", 2)]) + # More items can be added as usual + d["w"] = 5 + d["b"] = 3 + for k, v in d.items(): + print(k, v) + + Output:: + + z 1 + a 2 + w 5 + b 3 diff --git a/src/openmv/src/micropython/docs/library/ucryptolib.rst b/src/openmv/src/micropython/docs/library/ucryptolib.rst new file mode 100755 index 0000000..c9e0bb7 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ucryptolib.rst @@ -0,0 +1,38 @@ +:mod:`ucryptolib` -- cryptographic ciphers +========================================== + +.. module:: ucryptolib + :synopsis: cryptographic ciphers + +Classes +------- + +.. class:: aes + + .. classmethod:: __init__(key, mode, [IV]) + + Initialize cipher object, suitable for encryption/decryption. Note: + after initialization, cipher object can be use only either for + encryption or decryption. Running decrypt() operation after encrypt() + or vice versa is not supported. + + Parameters are: + + * *key* is an encryption/decryption key (bytes-like). + * *mode* is: + + * ``1`` (or ``ucryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB). + * ``2`` (or ``ucryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC) + + * *IV* is an initialization vector for CBC mode. + + .. method:: encrypt(in_buf, [out_buf]) + + Encrypt *in_buf*. If no *out_buf* is given result is returned as a + newly allocated `bytes` object. Otherwise, result is written into + mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer + to the same mutable buffer, in which case data is encrypted in-place. + + .. method:: decrypt(in_buf, [out_buf]) + + Like `encrypt()`, but for decryption. diff --git a/src/openmv/src/micropython/docs/library/uctypes.rst b/src/openmv/src/micropython/docs/library/uctypes.rst new file mode 100755 index 0000000..dce8cae --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uctypes.rst @@ -0,0 +1,325 @@ +:mod:`uctypes` -- access binary data in a structured way +======================================================== + +.. module:: uctypes + :synopsis: access binary data in a structured way + +This module implements "foreign data interface" for MicroPython. The idea +behind it is similar to CPython's ``ctypes`` modules, but the actual API is +different, streamlined and optimized for small size. The basic idea of the +module is to define data structure layout with about the same power as the +C language allows, and then access it using familiar dot-syntax to reference +sub-fields. + +.. warning:: + + ``uctypes`` module allows access to arbitrary memory addresses of the + machine (including I/O and control registers). Uncareful usage of it + may lead to crashes, data loss, and even hardware malfunction. + +.. seealso:: + + Module :mod:`ustruct` + Standard Python way to access binary data structures (doesn't scale + well to large and complex structures). + +Usage examples:: + + import uctypes + + # Example 1: Subset of ELF file header + # https://wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + ELF_HEADER = { + "EI_MAG": (0x0 | uctypes.ARRAY, 4 | uctypes.UINT8), + "EI_DATA": 0x5 | uctypes.UINT8, + "e_machine": 0x12 | uctypes.UINT16, + } + + # "f" is an ELF file opened in binary mode + buf = f.read(uctypes.sizeof(ELF_HEADER, uctypes.LITTLE_ENDIAN)) + header = uctypes.struct(uctypes.addressof(buf), ELF_HEADER, uctypes.LITTLE_ENDIAN) + assert header.EI_MAG == b"\x7fELF" + assert header.EI_DATA == 1, "Oops, wrong endianness. Could retry with uctypes.BIG_ENDIAN." + print("machine:", hex(header.e_machine)) + + + # Example 2: In-memory data structure, with pointers + COORD = { + "x": 0 | uctypes.FLOAT32, + "y": 4 | uctypes.FLOAT32, + } + + STRUCT1 = { + "data1": 0 | uctypes.UINT8, + "data2": 4 | uctypes.UINT32, + "ptr": (8 | uctypes.PTR, COORD), + } + + # Suppose you have address of a structure of type STRUCT1 in "addr" + # uctypes.NATIVE is optional (used by default) + struct1 = uctypes.struct(addr, STRUCT1, uctypes.NATIVE) + print("x:", struct1.ptr[0].x) + + + # Example 3: Access to CPU registers. Subset of STM32F4xx WWDG block + WWDG_LAYOUT = { + "WWDG_CR": (0, { + # BFUINT32 here means size of the WWDG_CR register + "WDGA": 7 << uctypes.BF_POS | 1 << uctypes.BF_LEN | uctypes.BFUINT32, + "T": 0 << uctypes.BF_POS | 7 << uctypes.BF_LEN | uctypes.BFUINT32, + }), + "WWDG_CFR": (4, { + "EWI": 9 << uctypes.BF_POS | 1 << uctypes.BF_LEN | uctypes.BFUINT32, + "WDGTB": 7 << uctypes.BF_POS | 2 << uctypes.BF_LEN | uctypes.BFUINT32, + "W": 0 << uctypes.BF_POS | 7 << uctypes.BF_LEN | uctypes.BFUINT32, + }), + } + + WWDG = uctypes.struct(0x40002c00, WWDG_LAYOUT) + + WWDG.WWDG_CFR.WDGTB = 0b10 + WWDG.WWDG_CR.WDGA = 1 + print("Current counter:", WWDG.WWDG_CR.T) + +Defining structure layout +------------------------- + +Structure layout is defined by a "descriptor" - a Python dictionary which +encodes field names as keys and other properties required to access them as +associated values:: + + { + "field1": , + "field2": , + ... + } + +Currently, ``uctypes`` requires explicit specification of offsets for each +field. Offset are given in bytes from the structure start. + +Following are encoding examples for various field types: + +* Scalar types:: + + "field_name": offset | uctypes.UINT32 + + in other words, the value is a scalar type identifier ORed with a field offset + (in bytes) from the start of the structure. + +* Recursive structures:: + + "sub": (offset, { + "b0": 0 | uctypes.UINT8, + "b1": 1 | uctypes.UINT8, + }) + + i.e. value is a 2-tuple, first element of which is an offset, and second is + a structure descriptor dictionary (note: offsets in recursive descriptors + are relative to the structure it defines). Of course, recursive structures + can be specified not just by a literal dictionary, but by referring to a + structure descriptor dictionary (defined earlier) by name. + +* Arrays of primitive types:: + + "arr": (offset | uctypes.ARRAY, size | uctypes.UINT8), + + i.e. value is a 2-tuple, first element of which is ARRAY flag ORed + with offset, and second is scalar element type ORed number of elements + in the array. + +* Arrays of aggregate types:: + + "arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}), + + i.e. value is a 3-tuple, first element of which is ARRAY flag ORed + with offset, second is a number of elements in the array, and third is + a descriptor of element type. + +* Pointer to a primitive type:: + + "ptr": (offset | uctypes.PTR, uctypes.UINT8), + + i.e. value is a 2-tuple, first element of which is PTR flag ORed + with offset, and second is a scalar element type. + +* Pointer to an aggregate type:: + + "ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}), + + i.e. value is a 2-tuple, first element of which is PTR flag ORed + with offset, second is a descriptor of type pointed to. + +* Bitfields:: + + "bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN, + + i.e. value is a type of scalar value containing given bitfield (typenames are + similar to scalar types, but prefixes with ``BF``), ORed with offset for + scalar value containing the bitfield, and further ORed with values for + bit position and bit length of the bitfield within the scalar value, shifted by + BF_POS and BF_LEN bits, respectively. A bitfield position is counted + from the least significant bit of the scalar (having position of 0), and + is the number of right-most bit of a field (in other words, it's a number + of bits a scalar needs to be shifted right to extract the bitfield). + + In the example above, first a UINT16 value will be extracted at offset 0 + (this detail may be important when accessing hardware registers, where + particular access size and alignment are required), and then bitfield + whose rightmost bit is *lsbit* bit of this UINT16, and length + is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and + *bitsize* is 8, then effectively it will access least-significant byte + of UINT16. + + Note that bitfield operations are independent of target byte endianness, + in particular, example above will access least-significant byte of UINT16 + in both little- and big-endian structures. But it depends on the least + significant bit being numbered 0. Some targets may use different + numbering in their native ABI, but ``uctypes`` always uses the normalized + numbering described above. + +Module contents +--------------- + +.. class:: struct(addr, descriptor, layout_type=NATIVE) + + Instantiate a "foreign data structure" object based on structure address in + memory, descriptor (encoded as a dictionary), and layout type (see below). + +.. data:: LITTLE_ENDIAN + + Layout type for a little-endian packed structure. (Packed means that every + field occupies exactly as many bytes as defined in the descriptor, i.e. + the alignment is 1). + +.. data:: BIG_ENDIAN + + Layout type for a big-endian packed structure. + +.. data:: NATIVE + + Layout type for a native structure - with data endianness and alignment + conforming to the ABI of the system on which MicroPython runs. + +.. function:: sizeof(struct, layout_type=NATIVE) + + Return size of data structure in bytes. The *struct* argument can be + either a structure class or a specific instantiated structure object + (or its aggregate field). + +.. function:: addressof(obj) + + Return address of an object. Argument should be bytes, bytearray or + other object supporting buffer protocol (and address of this buffer + is what actually returned). + +.. function:: bytes_at(addr, size) + + Capture memory at the given address and size as bytes object. As bytes + object is immutable, memory is actually duplicated and copied into + bytes object, so if memory contents change later, created object + retains original value. + +.. function:: bytearray_at(addr, size) + + Capture memory at the given address and size as bytearray object. + Unlike bytes_at() function above, memory is captured by reference, + so it can be both written too, and you will access current value + at the given memory address. + +.. data:: UINT8 + INT8 + UINT16 + INT16 + UINT32 + INT32 + UINT64 + INT64 + + Integer types for structure descriptors. Constants for 8, 16, 32, + and 64 bit types are provided, both signed and unsigned. + +.. data:: FLOAT32 + FLOAT64 + + Floating-point types for structure descriptors. + +.. data:: VOID + + ``VOID`` is an alias for ``UINT8``, and is provided to conviniently define + C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. + +.. data:: PTR + ARRAY + + Type constants for pointers and arrays. Note that there is no explicit + constant for structures, it's implicit: an aggregate type without ``PTR`` + or ``ARRAY`` flags is a structure. + +Structure descriptors and instantiating structure objects +--------------------------------------------------------- + +Given a structure descriptor dictionary and its layout type, you can +instantiate a specific structure instance at a given memory address +using :class:`uctypes.struct()` constructor. Memory address usually comes from +following sources: + +* Predefined address, when accessing hardware registers on a baremetal + system. Lookup these addresses in datasheet for a particular MCU/SoC. +* As a return value from a call to some FFI (Foreign Function Interface) + function. +* From `uctypes.addressof()`, when you want to pass arguments to an FFI + function, or alternatively, to access some data for I/O (for example, + data read from a file or network socket). + +Structure objects +----------------- + +Structure objects allow accessing individual fields using standard dot +notation: ``my_struct.substruct1.field1``. If a field is of scalar type, +getting it will produce a primitive value (Python integer or float) +corresponding to the value contained in a field. A scalar field can also +be assigned to. + +If a field is an array, its individual elements can be accessed with +the standard subscript operator ``[]`` - both read and assigned to. + +If a field is a pointer, it can be dereferenced using ``[0]`` syntax +(corresponding to C ``*`` operator, though ``[0]`` works in C too). +Subscripting a pointer with other integer values but 0 are also supported, +with the same semantics as in C. + +Summing up, accessing structure fields generally follows the C syntax, +except for pointer dereference, when you need to use ``[0]`` operator +instead of ``*``. + +Limitations +----------- + +1. Accessing non-scalar fields leads to allocation of intermediate objects +to represent them. This means that special care should be taken to +layout a structure which needs to be accessed when memory allocation +is disabled (e.g. from an interrupt). The recommendations are: + +* Avoid accessing nested structures. For example, instead of + ``mcu_registers.peripheral_a.register1``, define separate layout + descriptors for each peripheral, to be accessed as + ``peripheral_a.register1``. Or just cache a particular peripheral: + ``peripheral_a = mcu_registers.peripheral_a``. If a register + consists of multiple bitfields, you would need to cache references + to a particular register: ``reg_a = mcu_registers.peripheral_a.reg_a``. +* Avoid other non-scalar data, like arrays. For example, instead of + ``peripheral_a.register[0]`` use ``peripheral_a.register0``. Again, + an alternative is to cache intermediate values, e.g. + ``register0 = peripheral_a.register[0]``. + +2. Range of offsets supported by the ``uctypes`` module is limited. +The exact range supported is considered an implementation detail, +and the general suggestion is to split structure definitions to +cover from a few kilobytes to a few dozen of kilobytes maximum. +In most cases, this is a natural situation anyway, e.g. it doesn't make +sense to define all registers of an MCU (spread over 32-bit address +space) in one structure, but rather a peripheral block by peripheral +block. In some extreme cases, you may need to split a structure in +several parts artificially (e.g. if accessing native data structure +with multi-megabyte array in the middle, though that would be a very +synthetic case). diff --git a/src/openmv/src/micropython/docs/library/uerrno.rst b/src/openmv/src/micropython/docs/library/uerrno.rst new file mode 100755 index 0000000..e336eb5 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uerrno.rst @@ -0,0 +1,34 @@ +:mod:`uerrno` -- system error codes +=================================== + +.. module:: uerrno + :synopsis: system error codes + +|see_cpython_module| :mod:`python:errno`. + +This module provides access to symbolic error codes for `OSError` exception. +A particular inventory of codes depends on `MicroPython port`. + +Constants +--------- + +.. data:: EEXIST, EAGAIN, etc. + + Error codes, based on ANSI C/POSIX standard. All error codes start with + "E". As mentioned above, inventory of the codes depends on + `MicroPython port`. Errors are usually accessible as ``exc.args[0]`` + where ``exc`` is an instance of `OSError`. Usage example:: + + try: + uos.mkdir("my_dir") + except OSError as exc: + if exc.args[0] == uerrno.EEXIST: + print("Directory already exists") + +.. data:: errorcode + + Dictionary mapping numeric error codes to strings with symbolic error + code (see above):: + + >>> print(uerrno.errorcode[uerrno.EEXIST]) + EEXIST diff --git a/src/openmv/src/micropython/docs/library/uhashlib.rst b/src/openmv/src/micropython/docs/library/uhashlib.rst new file mode 100755 index 0000000..50ed658 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uhashlib.rst @@ -0,0 +1,57 @@ +:mod:`uhashlib` -- hashing algorithms +===================================== + +.. module:: uhashlib + :synopsis: hashing algorithms + +|see_cpython_module| :mod:`python:hashlib`. + +This module implements binary data hashing algorithms. The exact inventory +of available algorithms depends on a board. Among the algorithms which may +be implemented: + +* SHA256 - The current generation, modern hashing algorithm (of SHA2 series). + It is suitable for cryptographically-secure purposes. Included in the + MicroPython core and any board is recommended to provide this, unless + it has particular code size constraints. + +* SHA1 - A previous generation algorithm. Not recommended for new usages, + but SHA1 is a part of number of Internet standards and existing + applications, so boards targeting network connectivity and + interoperatiability will try to provide this. + +* MD5 - A legacy algorithm, not considered cryptographically secure. Only + selected boards, targeting interoperatibility with legacy applications, + will offer this. + +Constructors +------------ + +.. class:: uhashlib.sha256([data]) + + Create an SHA256 hasher object and optionally feed ``data`` into it. + +.. class:: uhashlib.sha1([data]) + + Create an SHA1 hasher object and optionally feed ``data`` into it. + +.. class:: uhashlib.md5([data]) + + Create an MD5 hasher object and optionally feed ``data`` into it. + +Methods +------- + +.. method:: hash.update(data) + + Feed more binary data into hash. + +.. method:: hash.digest() + + Return hash for all data passed through hash, as a bytes object. After this + method is called, more data cannot be fed into the hash any longer. + +.. method:: hash.hexdigest() + + This method is NOT implemented. Use ``ubinascii.hexlify(hash.digest())`` + to achieve a similar effect. diff --git a/src/openmv/src/micropython/docs/library/uheapq.rst b/src/openmv/src/micropython/docs/library/uheapq.rst new file mode 100755 index 0000000..f822f1e --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uheapq.rst @@ -0,0 +1,27 @@ +:mod:`uheapq` -- heap queue algorithm +===================================== + +.. module:: uheapq + :synopsis: heap queue algorithm + +|see_cpython_module| :mod:`python:heapq`. + +This module implements the heap queue algorithm. + +A heap queue is simply a list that has its elements stored in a certain way. + +Functions +--------- + +.. function:: heappush(heap, item) + + Push the ``item`` onto the ``heap``. + +.. function:: heappop(heap) + + Pop the first item from the ``heap``, and return it. Raises IndexError if + heap is empty. + +.. function:: heapify(x) + + Convert the list ``x`` into a heap. This is an in-place operation. diff --git a/src/openmv/src/micropython/docs/library/uio.rst b/src/openmv/src/micropython/docs/library/uio.rst new file mode 100755 index 0000000..1a64b36 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uio.rst @@ -0,0 +1,129 @@ +:mod:`uio` -- input/output streams +================================== + +.. module:: uio + :synopsis: input/output streams + +|see_cpython_module| :mod:`python:io`. + +This module contains additional types of `stream` (file-like) objects +and helper functions. + +Conceptual hierarchy +-------------------- + +.. admonition:: Difference to CPython + :class: attention + + Conceptual hierarchy of stream base classes is simplified in MicroPython, + as described in this section. + +(Abstract) base stream classes, which serve as a foundation for behavior +of all the concrete classes, adhere to few dichotomies (pair-wise +classifications) in CPython. In MicroPython, they are somewhat simplified +and made implicit to achieve higher efficiencies and save resources. + +An important dichotomy in CPython is unbuffered vs buffered streams. In +MicroPython, all streams are currently unbuffered. This is because all +modern OSes, and even many RTOSes and filesystem drivers already perform +buffering on their side. Adding another layer of buffering is counter- +productive (an issue known as "bufferbloat") and takes precious memory. +Note that there still cases where buffering may be useful, so we may +introduce optional buffering support at a later time. + +But in CPython, another important dichotomy is tied with "bufferedness" - +it's whether a stream may incur short read/writes or not. A short read +is when a user asks e.g. 10 bytes from a stream, but gets less, similarly +for writes. In CPython, unbuffered streams are automatically short +operation susceptible, while buffered are guarantee against them. The +no short read/writes is an important trait, as it allows to develop +more concise and efficient programs - something which is highly desirable +for MicroPython. So, while MicroPython doesn't support buffered streams, +it still provides for no-short-operations streams. Whether there will +be short operations or not depends on each particular class' needs, but +developers are strongly advised to favor no-short-operations behavior +for the reasons stated above. For example, MicroPython sockets are +guaranteed to avoid short read/writes. Actually, at this time, there is +no example of a short-operations stream class in the core, and one would +be a port-specific class, where such a need is governed by hardware +peculiarities. + +The no-short-operations behavior gets tricky in case of non-blocking +streams, blocking vs non-blocking behavior being another CPython dichotomy, +fully supported by MicroPython. Non-blocking streams never wait for +data either to arrive or be written - they read/write whatever possible, +or signal lack of data (or ability to write data). Clearly, this conflicts +with "no-short-operations" policy, and indeed, a case of non-blocking +buffered (and this no-short-ops) streams is convoluted in CPython - in +some places, such combination is prohibited, in some it's undefined or +just not documented, in some cases it raises verbose exceptions. The +matter is much simpler in MicroPython: non-blocking stream are important +for efficient asynchronous operations, so this property prevails on +the "no-short-ops" one. So, while blocking streams will avoid short +reads/writes whenever possible (the only case to get a short read is +if end of file is reached, or in case of error (but errors don't +return short data, but raise exceptions)), non-blocking streams may +produce short data to avoid blocking the operation. + +The final dichotomy is binary vs text streams. MicroPython of course +supports these, but while in CPython text streams are inherently +buffered, they aren't in MicroPython. (Indeed, that's one of the cases +for which we may introduce buffering support.) + +Note that for efficiency, MicroPython doesn't provide abstract base +classes corresponding to the hierarchy above, and it's not possible +to implement, or subclass, a stream class in pure Python. + +Functions +--------- + +.. function:: open(name, mode='r', **kwargs) + + Open a file. Builtin ``open()`` function is aliased to this function. + All ports (which provide access to file system) are required to support + *mode* parameter, but support for other arguments vary by port. + +Classes +------- + +.. class:: FileIO(...) + + This is type of a file open in binary mode, e.g. using ``open(name, "rb")``. + You should not instantiate this class directly. + +.. class:: TextIOWrapper(...) + + This is type of a file open in text mode, e.g. using ``open(name, "rt")``. + You should not instantiate this class directly. + +.. class:: StringIO([string]) +.. class:: BytesIO([string]) + + In-memory file-like objects for input/output. `StringIO` is used for + text-mode I/O (similar to a normal file opened with "t" modifier). + `BytesIO` is used for binary-mode I/O (similar to a normal file + opened with "b" modifier). Initial contents of file-like objects + can be specified with *string* parameter (should be normal string + for `StringIO` or bytes object for `BytesIO`). All the usual file + methods like ``read()``, ``write()``, ``seek()``, ``flush()``, + ``close()`` are available on these objects, and additionally, a + following method: + + .. method:: getvalue() + + Get the current contents of the underlying buffer which holds data. + +.. class:: StringIO(alloc_size) +.. class:: BytesIO(alloc_size) + + Create an empty `StringIO`/`BytesIO` object, preallocated to hold up + to *alloc_size* number of bytes. That means that writing that amount + of bytes won't lead to reallocation of the buffer, and thus won't hit + out-of-memory situation or lead to memory fragmentation. These constructors + are a MicroPython extension and are recommended for usage only in special + cases and in system-level libraries, not for end-user applications. + + .. admonition:: Difference to CPython + :class: attention + + These constructors are a MicroPython extension. diff --git a/src/openmv/src/micropython/docs/library/ujson.rst b/src/openmv/src/micropython/docs/library/ujson.rst new file mode 100755 index 0000000..5668eb2 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ujson.rst @@ -0,0 +1,35 @@ +:mod:`ujson` -- JSON encoding and decoding +========================================== + +.. module:: ujson + :synopsis: JSON encoding and decoding + +|see_cpython_module| :mod:`python:json`. + +This modules allows to convert between Python objects and the JSON +data format. + +Functions +--------- + +.. function:: dump(obj, stream) + + Serialise *obj* to a JSON string, writing it to the given *stream*. + +.. function:: dumps(obj) + + Return *obj* represented as a JSON string. + +.. function:: load(stream) + + Parse the given *stream*, interpreting it as a JSON string and + deserialising the data to a Python object. The resulting object is + returned. + + Parsing continues until end-of-file is encountered. + A :exc:`ValueError` is raised if the data in *stream* is not correctly formed. + +.. function:: loads(str) + + Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the + string is not correctly formed. diff --git a/src/openmv/src/micropython/docs/library/uos.rst b/src/openmv/src/micropython/docs/library/uos.rst new file mode 100755 index 0000000..c073f07 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uos.rst @@ -0,0 +1,251 @@ +:mod:`uos` -- basic "operating system" services +=============================================== + +.. module:: uos + :synopsis: basic "operating system" services + +|see_cpython_module| :mod:`python:os`. + +The ``uos`` module contains functions for filesystem access and mounting, +terminal redirection and duplication, and the ``uname`` and ``urandom`` +functions. + +General functions +----------------- + +.. function:: uname() + + Return a tuple (possibly a named tuple) containing information about the + underlying machine and/or its operating system. The tuple has five fields + in the following order, each of them being a string: + + * ``sysname`` -- the name of the underlying system + * ``nodename`` -- the network name (can be the same as ``sysname``) + * ``release`` -- the version of the underlying system + * ``version`` -- the MicroPython version and build date + * ``machine`` -- an identifier for the underlying hardware (eg board, CPU) + +.. function:: urandom(n) + + Return a bytes object with *n* random bytes. Whenever possible, it is + generated by the hardware random number generator. + +Filesystem access +----------------- + +.. function:: chdir(path) + + Change current directory. + +.. function:: getcwd() + + Get the current directory. + +.. function:: ilistdir([dir]) + + This function returns an iterator which then yields tuples corresponding to + the entries in the directory that it is listing. With no argument it lists the + current directory, otherwise it lists the directory given by *dir*. + + The tuples have the form *(name, type, inode[, size])*: + + - *name* is a string (or bytes if *dir* is a bytes object) and is the name of + the entry; + - *type* is an integer that specifies the type of the entry, with 0x4000 for + directories and 0x8000 for regular files; + - *inode* is an integer corresponding to the inode of the file, and may be 0 + for filesystems that don't have such a notion. + - Some platforms may return a 4-tuple that includes the entry's *size*. For + file entries, *size* is an integer representing the size of the file + or -1 if unknown. Its meaning is currently undefined for directory + entries. + +.. function:: listdir([dir]) + + With no argument, list the current directory. Otherwise list the given directory. + +.. function:: mkdir(path) + + Create a new directory. + +.. function:: remove(path) + + Remove a file. + +.. function:: rmdir(path) + + Remove a directory. + +.. function:: rename(old_path, new_path) + + Rename a file. + +.. function:: stat(path) + + Get the status of a file or directory. + +.. function:: statvfs(path) + + Get the status of a fileystem. + + Returns a tuple with the filesystem information in the following order: + + * ``f_bsize`` -- file system block size + * ``f_frsize`` -- fragment size + * ``f_blocks`` -- size of fs in f_frsize units + * ``f_bfree`` -- number of free blocks + * ``f_bavail`` -- number of free blocks for unpriviliged users + * ``f_files`` -- number of inodes + * ``f_ffree`` -- number of free inodes + * ``f_favail`` -- number of free inodes for unpriviliged users + * ``f_flag`` -- mount flags + * ``f_namemax`` -- maximum filename length + + Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail`` + and the ``f_flags`` parameter may return ``0`` as they can be unavailable + in a port-specific implementation. + +.. function:: sync() + + Sync all filesystems. + +Terminal redirection and duplication +------------------------------------ + +.. function:: dupterm(stream_object, index=0) + + Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like + object. The *stream_object* argument must implement the ``readinto()`` and + ``write()`` methods. The stream should be in non-blocking mode and + ``readinto()`` should return ``None`` if there is no data available for reading. + + After calling this function all terminal output is repeated on this stream, + and any input that is available on the stream is passed on to the terminal input. + + The *index* parameter should be a non-negative integer and specifies which + duplication slot is set. A given port may implement more than one slot (slot 0 + will always be available) and in that case terminal input and output is + duplicated on all the slots that are set. + + If ``None`` is passed as the *stream_object* then duplication is cancelled on + the slot given by *index*. + + The function returns the previous stream-like object in the given slot. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +.. function:: mount(fsobj, mount_point, \*, readonly) + + Mount the filesystem object *fsobj* at the location in the VFS given by the + *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` + method, or a block device. If it's a block device then the filesystem type + is automatically detected (an exception is raised if no filesystem was + recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, + or ``'/'`` to mount it at a subdirectory under the root. + + If *readonly* is ``True`` then the filesystem is mounted read-only. + + During the mount process the method ``mount()`` is called on the filesystem + object. + + Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + +.. function:: umount(mount_point) + + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + +.. class:: VfsFat(block_dev) + + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + + .. staticmethod:: mkfs(block_dev) + + Build a FAT filesystem on *block_dev*. + +Block devices +------------- + +A block device is an object which implements the block protocol, which is a set +of methods described below by the :class:`AbstractBlockDev` class. A concrete +implementation of this class will usually allow access to the memory-like +functionality a piece of hardware (like flash memory). A block device can be +used by a particular filesystem driver to store the data for its filesystem. + +.. class:: AbstractBlockDev(...) + + Construct a block device object. The parameters to the constructor are + dependent on the specific block device. + + .. method:: readblocks(block_num, buf) + + Starting at the block given by the index *block_num*, read blocks from + the device into *buf* (an array of bytes). + The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: writeblocks(block_num, buf) + + Starting at the block given by the index *block_num*, write blocks from + *buf* (an array of bytes) to the device. + The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: ioctl(op, arg) + + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + +By way of example, the following class will implement a block device that stores +its data in RAM using a ``bytearray``:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf): + for i in range(len(buf)): + buf[i] = self.data[block_num * self.block_size + i] + + def writeblocks(self, block_num, buf): + for i in range(len(buf)): + self.data[block_num * self.block_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return len(self.data) // self.block_size + if op == 5: # get block size + return self.block_size + +It can be used as follows:: + + import uos + + bdev = RAMBlockDev(512, 50) + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/ramdisk') diff --git a/src/openmv/src/micropython/docs/library/ure.rst b/src/openmv/src/micropython/docs/library/ure.rst new file mode 100755 index 0000000..6f90940 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ure.rst @@ -0,0 +1,148 @@ +:mod:`ure` -- simple regular expressions +======================================== + +.. module:: ure + :synopsis: regular expressions + +|see_cpython_module| :mod:`python:re`. + +This module implements regular expression operations. Regular expression +syntax supported is a subset of CPython ``re`` module (and actually is +a subset of POSIX extended regular expressions). + +Supported operators are: + +``'.'`` + Match any character. + +``'[...]'`` + Match set of characters. Individual characters and ranges are supported, + including negated sets (e.g. ``[^a-c]``). + +``'^'`` + Match the start of the string. + +``'$'`` + Match the end of the string. + +``'?'`` + Match zero or one of the previous entity. + +``'*'`` + Match zero or more of the previous entity. + +``'+'`` + Match one or more of the previous entity. + +``'??'`` + +``'*?'`` + +``'+?'`` + +``'|'`` + Match either the LHS or the RHS of this operator. + +``'(...)'`` + Grouping. Each group is capturing (a substring it captures can be accessed + with `match.group()` method). + +**NOT SUPPORTED**: Counted repetitions (``{m,n}``), more advanced assertions +(``\b``, ``\B``), named groups (``(?P...)``), non-capturing groups +(``(?:...)``), etc. + + +Functions +--------- + +.. function:: compile(regex_str, [flags]) + + Compile regular expression, return `regex ` object. + +.. function:: match(regex_str, string) + + Compile *regex_str* and match against *string*. Match always happens + from starting position in a string. + +.. function:: search(regex_str, string) + + Compile *regex_str* and search it in a *string*. Unlike `match`, this will search + string for first position which matches regex (which still may be + 0 if regex is anchored). + +.. function:: sub(regex_str, replace, string, count=0, flags=0) + + Compile *regex_str* and search for it in *string*, replacing all matches + with *replace*, and returning the new string. + + *replace* can be a string or a function. If it is a string then escape + sequences of the form ``\`` and ``\g`` can be used to + expand to the corresponding group (or an empty string for unmatched groups). + If *replace* is a function then it must take a single argument (the match) + and should return a replacement string. + + If *count* is specified and non-zero then substitution will stop after + this many substitutions are made. The *flags* argument is ignored. + + Note: availability of this function depends on `MicroPython port`. + +.. data:: DEBUG + + Flag value, display debug information about compiled expression. + (Availability depends on `MicroPython port`.) + + +.. _regex: + +Regex objects +------------- + +Compiled regular expression. Instances of this class are created using +`ure.compile()`. + +.. method:: regex.match(string) + regex.search(string) + regex.sub(replace, string, count=0, flags=0) + + Similar to the module-level functions :meth:`match`, :meth:`search` + and :meth:`sub`. + Using methods is (much) more efficient if the same regex is applied to + multiple strings. + +.. method:: regex.split(string, max_split=-1) + + Split a *string* using regex. If *max_split* is given, it specifies + maximum number of splits to perform. Returns list of strings (there + may be up to *max_split+1* elements if it's specified). + +Match objects +------------- + +Match objects as returned by `match()` and `search()` methods, and passed +to the replacement function in `sub()`. + +.. method:: match.group([index]) + + Return matching (sub)string. *index* is 0 for entire match, + 1 and above for each capturing group. Only numeric groups are supported. + +.. method:: match.groups() + + Return a tuple containing all the substrings of the groups of the match. + + Note: availability of this method depends on `MicroPython port`. + +.. method:: match.start([index]) + match.end([index]) + + Return the index in the original string of the start or end of the + substring group that was matched. *index* defaults to the entire + group, otherwise it will select a group. + + Note: availability of these methods depends on `MicroPython port`. + +.. method:: match.span([index]) + + Returns the 2-tuple ``(match.start(index), match.end(index))``. + + Note: availability of this method depends on `MicroPython port`. diff --git a/src/openmv/src/micropython/docs/library/uselect.rst b/src/openmv/src/micropython/docs/library/uselect.rst new file mode 100755 index 0000000..e1becc6 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uselect.rst @@ -0,0 +1,99 @@ +:mod:`uselect` -- wait for events on a set of streams +======================================================================== + +.. module:: uselect + :synopsis: wait for events on a set of streams + +|see_cpython_module| :mod:`python:select`. + +This module provides functions to efficiently wait for events on multiple +`streams ` (select streams which are ready for operations). + +Functions +--------- + +.. function:: poll() + + Create an instance of the Poll class. + +.. function:: select(rlist, wlist, xlist[, timeout]) + + Wait for activity on a set of objects. + + This function is provided by some MicroPython ports for compatibility + and is not efficient. Usage of :class:`Poll` is recommended instead. + +.. _class: Poll + +class ``Poll`` +-------------- + +Methods +~~~~~~~ + +.. method:: poll.register(obj[, eventmask]) + + Register `stream` *obj* for polling. *eventmask* is logical OR of: + + * ``uselect.POLLIN`` - data available for reading + * ``uselect.POLLOUT`` - more data can be written + + Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``uselect.POLLIN | uselect.POLLOUT``. + + It is OK to call this function multiple times for the same *obj*. + Successive calls will update *obj*'s eventmask to the value of + *eventmask* (i.e. will behave as `modify()`). + +.. method:: poll.unregister(obj) + + Unregister *obj* from polling. + +.. method:: poll.modify(obj, eventmask) + + Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` + is raised with error of ENOENT. + +.. method:: poll.poll(timeout=-1) + + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``uselect.POLL*`` constants described above. Note that + flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. + + .. admonition:: Difference to CPython + :class: attention + + Tuples returned may contain more than 2 elements as described above. + +.. method:: poll.ipoll(timeout=-1, flags=0) + + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free + way to poll on streams. + + If *flags* is 1, one-shot behavior for events is employed: streams for + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behavior is useful for asynchronous I/O schedulers. + + .. admonition:: Difference to CPython + :class: attention + + This function is a MicroPython extension. diff --git a/src/openmv/src/micropython/docs/library/usocket.rst b/src/openmv/src/micropython/docs/library/usocket.rst new file mode 100755 index 0000000..461e37b --- /dev/null +++ b/src/openmv/src/micropython/docs/library/usocket.rst @@ -0,0 +1,353 @@ +******************************* +:mod:`usocket` -- socket module +******************************* + +.. module:: usocket + :synopsis: socket module + +|see_cpython_module| :mod:`python:socket`. + +This module provides access to the BSD socket interface. + +.. admonition:: Difference to CPython + :class: attention + + For efficiency and consistency, socket objects in MicroPython implement a `stream` + (file-like) interface directly. In CPython, you need to convert a socket to + a file-like object using `makefile()` method. This method is still supported + by MicroPython (but is a no-op), so where compatibility with CPython matters, + be sure to use it. + +Socket address format(s) +------------------------ + +The native socket address format of the ``usocket`` module is an opaque data type +returned by `getaddrinfo` function, which must be used to resolve textual address +(including numeric addresses):: + + sockaddr = usocket.getaddrinfo('www.micropython.org', 80)[0][-1] + # You must use getaddrinfo() even for numeric addresses + sockaddr = usocket.getaddrinfo('127.0.0.1', 80)[0][-1] + # Now you can use that address + sock.connect(addr) + +Using `getaddrinfo` is the most efficient (both in terms of memory and processing +power) and portable way to work with addresses. + +However, ``socket`` module (note the difference with native MicroPython +``usocket`` module described here) provides CPython-compatible way to specify +addresses using tuples, as described below. Note that depending on a +`MicroPython port`, ``socket`` module can be builtin or need to be +installed from `micropython-lib` (as in the case of `MicroPython Unix port`), +and some ports still accept only numeric addresses in the tuple format, +and require to use `getaddrinfo` function to resolve domain names. + +Summing up: + +* Always use `getaddrinfo` when writing portable applications. +* Tuple addresses described below can be used as a shortcut for + quick hacks and interactive use, if your port supports them. + +Tuple address format for ``socket`` module: + +* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with + dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and + integer port number in the range 1-65535. Note the domain names are not + accepted as *ipv4_address*, they should be resolved first using + `usocket.getaddrinfo()`. +* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address* + is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``, + and *port* is an integer port number in the range 1-65535. *flowinfo* + must be 0. *scopeid* is the interface scope identifier for link-local + addresses. Note the domain names are not accepted as *ipv6_address*, + they should be resolved first using `usocket.getaddrinfo()`. Availability + of IPv6 support depends on a `MicroPython port`. + +Functions +--------- + +.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP) + + Create a new socket using the given address family, socket type and + protocol number. Note that specifying *proto* in most cases is not + required (and not recommended, as some MicroPython ports may omit + ``IPPROTO_*`` constants). Instead, *type* argument will select needed + protocol automatically:: + + # Create STREAM TCP socket + socket(AF_INET, SOCK_STREAM) + # Create DGRAM UDP socket + socket(AF_INET, SOCK_DGRAM) + +.. function:: getaddrinfo(host, port, af=0, type=0, proto=0, flags=0) + + Translate the host/port argument into a sequence of 5-tuples that contain all the + necessary arguments for creating a socket connected to that service. Arguments + *af*, *type*, and *proto* (which have the same meaning as for the `socket()` function) + can be used to filter which kind of addresses are returned. If a parameter is not + specified or zero, all combinations of addresses can be returned (requiring + filtering on the user side). + + The resulting list of 5-tuples has the following structure:: + + (family, type, proto, canonname, sockaddr) + + The following example shows how to connect to a given url:: + + s = usocket.socket() + # This assumes that if "type" is not specified, an address for + # SOCK_STREAM will be returned, which may be not true + s.connect(usocket.getaddrinfo('www.micropython.org', 80)[0][-1]) + + Recommended use of filtering params:: + + s = usocket.socket() + # Guaranteed to return an address which can be connect'ed to for + # stream operation. + s.connect(usocket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1]) + + .. admonition:: Difference to CPython + :class: attention + + CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case + of error in this function. MicroPython doesn't have ``socket.gaierror`` + and raises OSError directly. Note that error numbers of `getaddrinfo()` + form a separate namespace and may not match error numbers from + the :mod:`uerrno` module. To distinguish `getaddrinfo()` errors, they are + represented by negative numbers, whereas standard system errors are + positive numbers (error numbers are accessible using ``e.args[0]`` property + from an exception object). The use of negative values is a provisional + detail which may change in the future. + +.. function:: inet_ntop(af, bin_addr) + + Convert a binary network address *bin_addr* of the given address family *af* + to a textual representation:: + + >>> usocket.inet_ntop(usocket.AF_INET, b"\x7f\0\0\1") + '127.0.0.1' + +.. function:: inet_pton(af, txt_addr) + + Convert a textual network address *txt_addr* of the given address family *af* + to a binary representation:: + + >>> usocket.inet_pton(usocket.AF_INET, "1.2.3.4") + b'\x01\x02\x03\x04' + +Constants +--------- + +.. data:: AF_INET + AF_INET6 + + Address family types. Availability depends on a particular `MicroPython port`. + +.. data:: SOCK_STREAM + SOCK_DGRAM + + Socket types. + +.. data:: IPPROTO_UDP + IPPROTO_TCP + + IP protocol numbers. Availability depends on a particular `MicroPython port`. + Note that you don't need to specify these in a call to `usocket.socket()`, + because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and + `SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants + is as an argument to `setsockopt()`. + +.. data:: usocket.SOL_* + + Socket option levels (an argument to `setsockopt()`). The exact + inventory depends on a `MicroPython port`. + +.. data:: usocket.SO_* + + Socket options (an argument to `setsockopt()`). The exact + inventory depends on a `MicroPython port`. + +Constants specific to WiPy: + +.. data:: IPPROTO_SEC + + Special protocol value to create SSL-compatible socket. + +class socket +============ + +Methods +------- + +.. method:: socket.close() + + Mark the socket closed and release all resources. Once that happens, all future operations + on the socket object will fail. The remote end will receive EOF indication if + supported by protocol. + + Sockets are automatically closed when they are garbage-collected, but it is recommended + to `close()` them explicitly as soon you finished working with them. + +.. method:: socket.bind(address) + + Bind the socket to *address*. The socket must not already be bound. + +.. method:: socket.listen([backlog]) + + Enable a server to accept connections. If *backlog* is specified, it must be at least 0 + (if it's lower, it will be set to 0); and specifies the number of unaccepted connections + that the system will allow before refusing new connections. If not specified, a default + reasonable value is chosen. + +.. method:: socket.accept() + + Accept a connection. The socket must be bound to an address and listening for connections. + The return value is a pair (conn, address) where conn is a new socket object usable to send + and receive data on the connection, and address is the address bound to the socket on the + other end of the connection. + +.. method:: socket.connect(address) + + Connect to a remote socket at *address*. + +.. method:: socket.send(bytes) + + Send data to the socket. The socket must be connected to a remote socket. + Returns number of bytes sent, which may be smaller than the length of data + ("short write"). + +.. method:: socket.sendall(bytes) + + Send all data to the socket. The socket must be connected to a remote socket. + Unlike `send()`, this method will try to send all of data, by sending data + chunk by chunk consecutively. + + The behavior of this method on non-blocking sockets is undefined. Due to this, + on MicroPython, it's recommended to use `write()` method instead, which + has the same "no short writes" policy for blocking sockets, and will return + number of bytes sent on non-blocking sockets. + +.. method:: socket.recv(bufsize) + + Receive data from the socket. The return value is a bytes object representing the data + received. The maximum amount of data to be received at once is specified by bufsize. + +.. method:: socket.sendto(bytes, address) + + Send data to the socket. The socket should not be connected to a remote socket, since the + destination socket is specified by *address*. + +.. method:: socket.recvfrom(bufsize) + + Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a + bytes object representing the data received and *address* is the address of the socket sending + the data. + +.. method:: socket.setsockopt(level, optname, value) + + Set the value of the given socket option. The needed symbolic constants are defined in the + socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing + a buffer. + +.. method:: socket.settimeout(value) + + **Note**: Not every port supports this method, see below. + + Set a timeout on blocking socket operations. The value argument can be a nonnegative floating + point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations + will raise an `OSError` exception if the timeout period value has elapsed before the operation has + completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket + is put in blocking mode. + + Not every `MicroPython port` supports this method. A more portable and + generic solution is to use `uselect.poll` object. This allows to wait on + multiple objects at the same time (and not just on sockets, but on generic + `stream` objects which support polling). Example:: + + # Instead of: + s.settimeout(1.0) # time in seconds + s.read(10) # may timeout + + # Use: + poller = uselect.poll() + poller.register(s, uselect.POLLIN) + res = poller.poll(1000) # time in milliseconds + if not res: + # s is still not ready for input, i.e. operation timed out + + .. admonition:: Difference to CPython + :class: attention + + CPython raises a ``socket.timeout`` exception in case of timeout, + which is an `OSError` subclass. MicroPython raises an OSError directly + instead. If you use ``except OSError:`` to catch the exception, + your code will work both in MicroPython and CPython. + +.. method:: socket.setblocking(flag) + + Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking, + else to blocking mode. + + This method is a shorthand for certain `settimeout()` calls: + + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)`` + +.. method:: socket.makefile(mode='rb', buffering=0) + + Return a file object associated with the socket. The exact returned type depends on the arguments + given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb'). + CPython's arguments: *encoding*, *errors* and *newline* are not supported. + + .. admonition:: Difference to CPython + :class: attention + + As MicroPython doesn't support buffered streams, values of *buffering* + parameter is ignored and treated as if it was 0 (unbuffered). + + .. admonition:: Difference to CPython + :class: attention + + Closing the file object returned by makefile() WILL close the + original socket as well. + +.. method:: socket.read([size]) + + Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it + reads all data available from the socket until EOF; as such the method will not return until + the socket is closed. This function tries to read as much data as + requested (no "short reads"). This may be not possible with + non-blocking socket though, and then less data will be returned. + +.. method:: socket.readinto(buf[, nbytes]) + + Read bytes into the *buf*. If *nbytes* is specified then read at most + that many bytes. Otherwise, read at most *len(buf)* bytes. Just as + `read()`, this method follows "no short reads" policy. + + Return value: number of bytes read and stored into *buf*. + +.. method:: socket.readline() + + Read a line, ending in a newline character. + + Return value: the line read. + +.. method:: socket.write(buf) + + Write the buffer of bytes to the socket. This function will try to + write all data to a socket (no "short writes"). This may be not possible + with a non-blocking socket though, and returned value will be less than + the length of *buf*. + + Return value: number of bytes written. + +.. exception:: usocket.error + + MicroPython does NOT have this exception. + + .. admonition:: Difference to CPython + :class: attention + + CPython used to have a ``socket.error`` exception which is now deprecated, + and is an alias of `OSError`. In MicroPython, use `OSError` directly. diff --git a/src/openmv/src/micropython/docs/library/ussl.rst b/src/openmv/src/micropython/docs/library/ussl.rst new file mode 100755 index 0000000..be84dc0 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ussl.rst @@ -0,0 +1,48 @@ +:mod:`ussl` -- SSL/TLS module +============================= + +.. module:: ussl + :synopsis: TLS/SSL wrapper for socket objects + +|see_cpython_module| :mod:`python:ssl`. + +This module provides access to Transport Layer Security (previously and +widely known as “Secure Sockets Layerâ€) encryption and peer authentication +facilities for network sockets, both client-side and server-side. + +Functions +--------- + +.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None) + + Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), + and returns an instance of ssl.SSLSocket, which wraps the underlying stream in + an SSL context. Returned object has the usual `stream` interface methods like + ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose + socket interface and methods like ``recv()``, ``send()``. In particular, a + server-side SSL socket should be created from a normal socket returned from + :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. + + Depending on the underlying module implementation in a particular + `MicroPython port`, some or all keyword arguments above may be not supported. + +.. warning:: + + Some implementations of ``ussl`` module do NOT validate server certificates, + which makes an SSL connection established prone to man-in-the-middle attacks. + +Exceptions +---------- + +.. data:: ssl.SSLError + + This exception does NOT exist. Instead its base class, OSError, is used. + +Constants +--------- + +.. data:: ussl.CERT_NONE + ussl.CERT_OPTIONAL + ussl.CERT_REQUIRED + + Supported values for *cert_reqs* parameter. diff --git a/src/openmv/src/micropython/docs/library/ustruct.rst b/src/openmv/src/micropython/docs/library/ustruct.rst new file mode 100755 index 0000000..81915d0 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/ustruct.rst @@ -0,0 +1,42 @@ +:mod:`ustruct` -- pack and unpack primitive data types +====================================================== + +.. module:: ustruct + :synopsis: pack and unpack primitive data types + +|see_cpython_module| :mod:`python:struct`. + +Supported size/byte order prefixes: ``@``, ``<``, ``>``, ``!``. + +Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``, +``L``, ``q``, ``Q``, ``s``, ``P``, ``f``, ``d`` (the latter 2 depending +on the floating-point support). + +Functions +--------- + +.. function:: calcsize(fmt) + + Return the number of bytes needed to store the given *fmt*. + +.. function:: pack(fmt, v1, v2, ...) + + Pack the values *v1*, *v2*, ... according to the format string *fmt*. + The return value is a bytes object encoding the values. + +.. function:: pack_into(fmt, buffer, offset, v1, v2, ...) + + Pack the values *v1*, *v2*, ... according to the format string *fmt* + into a *buffer* starting at *offset*. *offset* may be negative to count + from the end of *buffer*. + +.. function:: unpack(fmt, data) + + Unpack from the *data* according to the format string *fmt*. + The return value is a tuple of the unpacked values. + +.. function:: unpack_from(fmt, data, offset=0) + + Unpack from the *data* starting at *offset* according to the format string + *fmt*. *offset* may be negative to count from the end of *buffer*. The return + value is a tuple of the unpacked values. diff --git a/src/openmv/src/micropython/docs/library/utime.rst b/src/openmv/src/micropython/docs/library/utime.rst new file mode 100755 index 0000000..7fe83f5 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/utime.rst @@ -0,0 +1,229 @@ +:mod:`utime` -- time related functions +====================================== + +.. module:: utime + :synopsis: time related functions + +|see_cpython_module| :mod:`python:time`. + +The ``utime`` module provides functions for getting the current time and date, +measuring time intervals, and for delays. + +**Time Epoch**: Unix port uses standard for POSIX systems epoch of +1970-01-01 00:00:00 UTC. However, embedded ports use epoch of +2000-01-01 00:00:00 UTC. + +**Maintaining actual calendar date/time**: This requires a +Real Time Clock (RTC). On systems with underlying OS (including some +RTOS), an RTC may be implicit. Setting and maintaining actual calendar +time is responsibility of OS/RTOS and is done outside of MicroPython, +it just uses OS API to query date/time. On baremetal ports however +system time depends on ``machine.RTC()`` object. The current calendar time +may be set using ``machine.RTC().datetime(tuple)`` function, and maintained +by following means: + +* By a backup battery (which may be an additional, optional component for + a particular board). +* Using networked time protocol (requires setup by a port/user). +* Set manually by a user on each power-up (many boards then maintain + RTC time across hard resets, though some may require setting it again + in such case). + +If actual calendar time is not maintained with a system/MicroPython RTC, +functions below which require reference to current absolute time may +behave not as expected. + +Functions +--------- + +.. function:: localtime([secs]) + + Convert a time expressed in seconds since the Epoch (see above) into an 8-tuple which + contains: (year, month, mday, hour, minute, second, weekday, yearday) + If secs is not provided or None, then the current time from the RTC is used. + + * year includes the century (for example 2014). + * month is 1-12 + * mday is 1-31 + * hour is 0-23 + * minute is 0-59 + * second is 0-59 + * weekday is 0-6 for Mon-Sun + * yearday is 1-366 + +.. function:: mktime() + + This is inverse function of localtime. It's argument is a full 8-tuple + which expresses a time as per localtime. It returns an integer which is + the number of seconds since Jan 1, 2000. + +.. function:: sleep(seconds) + + Sleep for the given number of seconds. Some boards may accept *seconds* as a + floating-point number to sleep for a fractional number of seconds. Note that + other boards may not accept a floating-point argument, for compatibility with + them use `sleep_ms()` and `sleep_us()` functions. + +.. function:: sleep_ms(ms) + + Delay for given number of milliseconds, should be positive or 0. + +.. function:: sleep_us(us) + + Delay for given number of microseconds, should be positive or 0. + +.. function:: ticks_ms() + + Returns an increasing millisecond counter with an arbitrary reference point, that + wraps around after some value. + + The wrap-around value is not explicitly exposed, but we will + refer to it as *TICKS_MAX* to simplify discussion. Period of the values is + *TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of + two, but otherwise may differ from port to port. The same period value is used + for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for + simplicity). Thus, these functions will return a value in range [*0* .. + *TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only + non-negative values are used. For the most part, you should treat values returned + by these functions as opaque. The only operations available for them are + `ticks_diff()` and `ticks_add()` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to `ticks_diff()` or `ticks_add()` will also lead to + invalid results from the latter functions. + +.. function:: ticks_us() + + Just like `ticks_ms()` above, but in microseconds. + +.. function:: ticks_cpu() + + Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to be a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``utime`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. + + Availability: Not every port implements this function. + + +.. function:: ticks_add(ticks, delta) + + Offset ticks value by a given number, which can be either positive or negative. + Given a *ticks* value, this function allows to calculate ticks value *delta* + ticks before or after it, following modular-arithmetic definition of tick values + (see `ticks_ms()` above). *ticks* parameter must be a direct result of call + to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous + call to `ticks_add()`). However, *delta* can be an arbitrary integer number + or numeric expression. `ticks_add()` is useful for calculating deadlines for + events/tasks. (Note: you must use `ticks_diff()` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(ticks_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = ticks_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(ticks_add(0, -1)) + + +.. function:: ticks_diff(ticks1, ticks2) + + Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`, + or `ticks_cpu()` functions, as a signed value which may wrap around. + + The argument order is the same as for subtraction + operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. + However, values returned by `ticks_ms()`, etc. functions may wrap around, so + directly using subtraction on them will produce incorrect result. That is why + `ticks_diff()` is needed, it implements modular (or more specifically, ring) + arithmetics to produce correct result even for wrap-around values (as long as they not + too distant inbetween, see below). The function returns **signed** value in the range + [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for + two's-complement signed binary integers). If the result is negative, it means that + *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that + *ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2* + are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does + not hold, incorrect result will be returned. Specifically, if two tick values are + apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function. + However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the + function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around + to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behavior: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping inbetween. + + `ticks_diff()` is designed to accommodate various usage patterns, among them: + + * Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of `ticks_diff()`:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + * Scheduling events. In this case, `ticks_diff()` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(scheduled_time, now) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(scheduled_time, now)) + task.run() + elif ticks_diff(scheduled_time, now) == 0: + print("Right at time!") + task.run() + elif ticks_diff(scheduled_time, now) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass `time()` values to `ticks_diff()`, you should use + normal mathematical operations on them. But note that `time()` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . + + +.. function:: time() + + Returns the number of seconds, as an integer, since the Epoch, assuming that + underlying RTC is set and maintained as described above. If an RTC is not set, this + function returns number of seconds since a port-specific reference point in time (for + embedded boards without a battery-backed RTC, usually since power up or reset). If you + want to develop portable MicroPython application, you should not rely on this function + to provide higher than second precision. If you need higher precision, use + `ticks_ms()` and `ticks_us()` functions, if you need calendar time, + `localtime()` without an argument is a better choice. + + .. admonition:: Difference to CPython + :class: attention + + In CPython, this function returns number of + seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point, + usually having microsecond precision. With MicroPython, only Unix port + uses the same Epoch, and if floating-point precision allows, + returns sub-second precision. Embedded hardware usually doesn't have + floating-point precision to represent both long time ranges and subsecond + precision, so they use integer value with second precision. Some embedded + hardware also lacks battery-powered RTC, so returns number of seconds + since last power-up or from other relative, hardware-specific point + (e.g. reset). diff --git a/src/openmv/src/micropython/docs/library/uzlib.rst b/src/openmv/src/micropython/docs/library/uzlib.rst new file mode 100755 index 0000000..0b399f2 --- /dev/null +++ b/src/openmv/src/micropython/docs/library/uzlib.rst @@ -0,0 +1,38 @@ +:mod:`uzlib` -- zlib decompression +================================== + +.. module:: uzlib + :synopsis: zlib decompression + +|see_cpython_module| :mod:`python:zlib`. + +This module allows to decompress binary data compressed with +`DEFLATE algorithm `_ +(commonly used in zlib library and gzip archiver). Compression +is not yet implemented. + +Functions +--------- + +.. function:: decompress(data, wbits=0, bufsize=0) + + Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window + size used during compression (8-15, the dictionary size is power of 2 of + that value). Additionally, if value is positive, *data* is assumed to be + zlib stream (with zlib header). Otherwise, if it's negative, it's assumed + to be raw DEFLATE stream. *bufsize* parameter is for compatibility with + CPython and is ignored. + +.. class:: DecompIO(stream, wbits=0) + + Create a `stream` wrapper which allows transparent decompression of + compressed data in another *stream*. This allows to process compressed + streams with data larger than available heap size. In addition to + values described in :func:`decompress`, *wbits* may take values + 24..31 (16 + 8..15), meaning that input stream has gzip header. + + .. admonition:: Difference to CPython + :class: attention + + This class is MicroPython extension. It's included on provisional + basis and may be changed considerably or removed in later versions. diff --git a/src/openmv/src/micropython/docs/library/wipy.rst b/src/openmv/src/micropython/docs/library/wipy.rst new file mode 100755 index 0000000..cdece7b --- /dev/null +++ b/src/openmv/src/micropython/docs/library/wipy.rst @@ -0,0 +1,17 @@ +************************************* +:mod:`wipy` -- WiPy specific features +************************************* + +.. module:: wipy + :synopsis: WiPy specific features + +The ``wipy`` module contains functions to control specific features of the +WiPy, such as the heartbeat LED. + +Functions +--------- + +.. function:: heartbeat([enable]) + + Get or set the state (enabled or disabled) of the heartbeat LED. Accepts and + returns boolean values (``True`` or ``False``). diff --git a/src/openmv/src/micropython/docs/license.rst b/src/openmv/src/micropython/docs/license.rst new file mode 100755 index 0000000..73caa90 --- /dev/null +++ b/src/openmv/src/micropython/docs/license.rst @@ -0,0 +1,24 @@ +MicroPython license information +=============================== + +The MIT License (MIT) + +Copyright (c) 2013-2017 Damien P. George, and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/openmv/src/micropython/docs/make.bat b/src/openmv/src/micropython/docs/make.bat new file mode 100755 index 0000000..1d046ed --- /dev/null +++ b/src/openmv/src/micropython/docs/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\MicroPython.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\MicroPython.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/src/openmv/src/micropython/docs/pyboard/general.rst b/src/openmv/src/micropython/docs/pyboard/general.rst new file mode 100755 index 0000000..0fc7332 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/general.rst @@ -0,0 +1,84 @@ +.. _pyboard_general: + +General information about the pyboard +===================================== + +.. contents:: + +Local filesystem and SD card +---------------------------- + +There is a small internal filesystem (a drive) on the pyboard, called ``/flash``, +which is stored within the microcontroller's flash memory. If a micro SD card +is inserted into the slot, it is available as ``/sd``. + +When the pyboard boots up, it needs to choose a filesystem to boot from. If +there is no SD card, then it uses the internal filesystem ``/flash`` as the boot +filesystem, otherwise, it uses the SD card ``/sd``. After the boot, the current +directory is set to one of the directories above. + +If needed, you can prevent the use of the SD card by creating an empty file +called ``/flash/SKIPSD``. If this file exists when the pyboard boots +up then the SD card will be skipped and the pyboard will always boot from the +internal filesystem (in this case the SD card won't be mounted but you can still +mount and use it later in your program using ``os.mount``). + +(Note that on older versions of the board, ``/flash`` is called ``0:/`` and ``/sd`` +is called ``1:/``). + +The boot filesystem is used for 2 things: it is the filesystem from which +the ``boot.py`` and ``main.py`` files are searched for, and it is the filesystem +which is made available on your PC over the USB cable. + +The filesystem will be available as a USB flash drive on your PC. You can +save files to the drive, and edit ``boot.py`` and ``main.py``. + +*Remember to eject (on Linux, unmount) the USB drive before you reset your +pyboard.* + +Boot modes +---------- + +If you power up normally, or press the reset button, the pyboard will boot +into standard mode: the ``boot.py`` file will be executed first, then the +USB will be configured, then ``main.py`` will run. + +You can override this boot sequence by holding down the user switch as +the board is booting up. Hold down user switch and press reset, and then +as you continue to hold the user switch, the LEDs will count in binary. +When the LEDs have reached the mode you want, let go of the user switch, +the LEDs for the selected mode will flash quickly, and the board will boot. + +The modes are: + +1. Green LED only, *standard boot*: run ``boot.py`` then ``main.py``. +2. Orange LED only, *safe boot*: don't run any scripts on boot-up. +3. Green and orange LED together, *filesystem reset*: resets the flash + filesystem to its factory state, then boots in safe mode. + +If your filesystem becomes corrupt, boot into mode 3 to fix it. +If resetting the filesystem while plugged into your compute doesn't work, +you can try doing the same procedure while the board is plugged into a USB +charger, or other USB power supply without data connection. + +Errors: flashing LEDs +--------------------- + +There are currently 2 kinds of errors that you might see: + +1. If the red and green LEDs flash alternatively, then a Python script + (eg ``main.py``) has an error. Use the REPL to debug it. +2. If all 4 LEDs cycle on and off slowly, then there was a hard fault. + This cannot be recovered from and you need to do a hard reset. + +Guide for using the pyboard with Windows +---------------------------------------- + +The following PDF guide gives information about using the pyboard with Windows, +including setting up the serial prompt and downloading new firmware using +DFU programming: +`PDF guide `__. + +.. _hardware_index: + +.. include:: hardware/index.rst diff --git a/src/openmv/src/micropython/docs/pyboard/hardware/index.rst b/src/openmv/src/micropython/docs/pyboard/hardware/index.rst new file mode 100755 index 0000000..d6a14b2 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/hardware/index.rst @@ -0,0 +1,28 @@ +The pyboard hardware +-------------------- + +For the pyboard: + +* `PYBv1.0 schematics and layout `_ (2.4MiB PDF) +* `PYBv1.0 metric dimensions `_ (360KiB PDF) +* `PYBv1.0 imperial dimensions `_ (360KiB PDF) + +For the official skin modules: + +* `LCD32MKv1.0 schematics `_ (194KiB PDF) +* `AMPv1.0 schematics `_ (209KiB PDF) +* LCD160CRv1.0: see :mod:`lcd160cr` + +Datasheets for the components on the pyboard +-------------------------------------------- + +* The microcontroller: `STM32F405RGT6 `_ (link to manufacturer's site) +* The accelerometer: `Freescale MMA7660 `_ (800kiB PDF) +* The LDO voltage regulator: `Microchip MCP1802 `_ (400kiB PDF) + +Datasheets for other components +------------------------------- + +* The LCD display on the LCD touch-sensor skin: `Newhaven Display NHD-C12832A1Z-FSW-FBW-3V3 `_ (460KiB PDF) +* The touch sensor chip on the LCD touch-sensor skin: `Freescale MPR121 `_ (280KiB PDF) +* The digital potentiometer on the audio skin: `Microchip MCP4541 `_ (2.7MiB PDF) diff --git a/src/openmv/src/micropython/docs/pyboard/quickref.rst b/src/openmv/src/micropython/docs/pyboard/quickref.rst new file mode 100755 index 0000000..ec789f2 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/quickref.rst @@ -0,0 +1,233 @@ +.. _pyboard_quickref: + +Quick reference for the pyboard +=============================== + +The below pinout is for PYBv1.0. You can also view pinouts for +other versions of the pyboard: +`PYBv1.1 `__ +or `PYBLITEv1.0-AC `__ +or `PYBLITEv1.0 `__. + +.. only:: not latex + + .. image:: http://micropython.org/resources/pybv10-pinout.jpg + :alt: PYBv1.0 pinout + :width: 700px + +.. only:: latex + + .. image:: http://micropython.org/resources/pybv10-pinout-800px.jpg + :alt: PYBv1.0 pinout + +Below is a quick reference for the pyboard. If it is your first time working with +this board please consider reading the following sections first: + +.. toctree:: + :maxdepth: 1 + + general.rst + tutorial/index.rst + +General board control +--------------------- + +See :mod:`pyb`. :: + + import pyb + + pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1) + pyb.wfi() # pause CPU, waiting for interrupt + pyb.freq() # get CPU and bus frequencies + pyb.freq(60000000) # set CPU freq to 60MHz + pyb.stop() # stop CPU, waiting for external interrupt + +Delay and timing +---------------- + +Use the :mod:`time ` module:: + + import time + + time.sleep(1) # sleep for 1 second + time.sleep_ms(500) # sleep for 500 milliseconds + time.sleep_us(10) # sleep for 10 microseconds + start = time.ticks_ms() # get value of millisecond counter + delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference + +Internal LEDs +------------- + +See :ref:`pyb.LED `. :: + + from pyb import LED + + led = LED(1) # 1=red, 2=green, 3=yellow, 4=blue + led.toggle() + led.on() + led.off() + + # LEDs 3 and 4 support PWM intensity (0-255) + LED(4).intensity() # get intensity + LED(4).intensity(128) # set intensity to half + +Internal switch +--------------- + +See :ref:`pyb.Switch `. :: + + from pyb import Switch + + sw = Switch() + sw.value() # returns True or False + sw.callback(lambda: pyb.LED(1).toggle()) + +Pins and GPIO +------------- + +See :ref:`pyb.Pin `. :: + + from pyb import Pin + + p_out = Pin('X1', Pin.OUT_PP) + p_out.high() + p_out.low() + + p_in = Pin('X2', Pin.IN, Pin.PULL_UP) + p_in.value() # get value, 0 or 1 + +Servo control +------------- + +See :ref:`pyb.Servo `. :: + + from pyb import Servo + + s1 = Servo(1) # servo on position 1 (X1, VIN, GND) + s1.angle(45) # move to 45 degrees + s1.angle(-60, 1500) # move to -60 degrees in 1500ms + s1.speed(50) # for continuous rotation servos + +External interrupts +------------------- + +See :ref:`pyb.ExtInt `. :: + + from pyb import Pin, ExtInt + + callback = lambda e: print("intr") + ext = ExtInt(Pin('Y1'), ExtInt.IRQ_RISING, Pin.PULL_NONE, callback) + +Timers +------ + +See :ref:`pyb.Timer `. :: + + from pyb import Timer + + tim = Timer(1, freq=1000) + tim.counter() # get counter value + tim.freq(0.5) # 0.5 Hz + tim.callback(lambda t: pyb.LED(1).toggle()) + +RTC (real time clock) +--------------------- + +See :ref:`pyb.RTC ` :: + + from pyb import RTC + + rtc = RTC() + rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time + rtc.datetime() # get date and time + +PWM (pulse width modulation) +---------------------------- + +See :ref:`pyb.Pin ` and :ref:`pyb.Timer `. :: + + from pyb import Pin, Timer + + p = Pin('X1') # X1 has TIM2, CH1 + tim = Timer(2, freq=1000) + ch = tim.channel(1, Timer.PWM, pin=p) + ch.pulse_width_percent(50) + +ADC (analog to digital conversion) +---------------------------------- + +See :ref:`pyb.Pin ` and :ref:`pyb.ADC `. :: + + from pyb import Pin, ADC + + adc = ADC(Pin('X19')) + adc.read() # read value, 0-4095 + +DAC (digital to analog conversion) +---------------------------------- + +See :ref:`pyb.Pin ` and :ref:`pyb.DAC `. :: + + from pyb import Pin, DAC + + dac = DAC(Pin('X5')) + dac.write(120) # output between 0 and 255 + +UART (serial bus) +----------------- + +See :ref:`pyb.UART `. :: + + from pyb import UART + + uart = UART(1, 9600) + uart.write('hello') + uart.read(5) # read up to 5 bytes + +SPI bus +------- + +See :ref:`pyb.SPI `. :: + + from pyb import SPI + + spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0) + spi.send('hello') + spi.recv(5) # receive 5 bytes on the bus + spi.send_recv('hello') # send and receive 5 bytes + +I2C bus +------- + +See :ref:`pyb.I2C `. :: + + from pyb import I2C + + i2c = I2C(1, I2C.MASTER, baudrate=100000) + i2c.scan() # returns list of slave addresses + i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42 + i2c.recv(5, 0x42) # receive 5 bytes from slave + i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10 + i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10 + +CAN bus (controller area network) +--------------------------------- + +See :ref:`pyb.CAN `. :: + + from pyb import CAN + + can = CAN(1, CAN.LOOPBACK) + can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126)) + can.send('message!', 123) # send a message with id 123 + can.recv(0) # receive message on FIFO 0 + +Internal accelerometer +---------------------- + +See :ref:`pyb.Accel `. :: + + from pyb import Accel + + accel = Accel() + print(accel.x(), accel.y(), accel.z(), accel.tilt()) diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/accel.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/accel.rst new file mode 100755 index 0000000..58170e7 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/accel.rst @@ -0,0 +1,92 @@ +The accelerometer +================= + +Here you will learn how to read the accelerometer and signal using LEDs states like tilt left and tilt right. + +Using the accelerometer +----------------------- + +The pyboard has an accelerometer (a tiny mass on a tiny spring) that can be used +to detect the angle of the board and motion. There is a different sensor for +each of the x, y, z directions. To get the value of the accelerometer, create a +pyb.Accel() object and then call the x() method. :: + + >>> accel = pyb.Accel() + >>> accel.x() + 7 + +This returns a signed integer with a value between around -30 and 30. Note that +the measurement is very noisy, this means that even if you keep the board +perfectly still there will be some variation in the number that you measure. +Because of this, you shouldn't use the exact value of the x() method but see if +it is in a certain range. + +We will start by using the accelerometer to turn on a light if it is not flat. :: + + accel = pyb.Accel() + light = pyb.LED(3) + SENSITIVITY = 3 + + while True: + x = accel.x() + if abs(x) > SENSITIVITY: + light.on() + else: + light.off() + + pyb.delay(100) + +We create Accel and LED objects, then get the value of the x direction of the +accelerometer. If the magnitude of x is bigger than a certain value ``SENSITIVITY``, +then the LED turns on, otherwise it turns off. The loop has a small ``pyb.delay()`` +otherwise the LED flashes annoyingly when the value of x is close to +``SENSITIVITY``. Try running this on the pyboard and tilt the board left and right +to make the LED turn on and off. + +**Exercise: Change the above script so that the blue LED gets brighter the more +you tilt the pyboard. HINT: You will need to rescale the values, intensity goes +from 0-255.** + +Making a spirit level +--------------------- + +The example above is only sensitive to the angle in the x direction but if we +use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level. :: + + xlights = (pyb.LED(2), pyb.LED(3)) + ylights = (pyb.LED(1), pyb.LED(4)) + + accel = pyb.Accel() + SENSITIVITY = 3 + + while True: + x = accel.x() + if x > SENSITIVITY: + xlights[0].on() + xlights[1].off() + elif x < -SENSITIVITY: + xlights[1].on() + xlights[0].off() + else: + xlights[0].off() + xlights[1].off() + + y = accel.y() + if y > SENSITIVITY: + ylights[0].on() + ylights[1].off() + elif y < -SENSITIVITY: + ylights[1].on() + ylights[0].off() + else: + ylights[0].off() + ylights[1].off() + + pyb.delay(100) + +We start by creating a tuple of LED objects for the x and y directions. Tuples +are immutable objects in python which means they can't be modified once they are +created. We then proceed as before but turn on a different LED for positive and +negative x values. We then do the same for the y direction. This isn't +particularly sophisticated but it does the job. Run this on your pyboard and you +should see different LEDs turning on depending on how you tilt the board. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/amp_skin.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/amp_skin.rst new file mode 100755 index 0000000..697637f --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/amp_skin.rst @@ -0,0 +1,98 @@ +The AMP audio skin +================== + +Soldering and using the AMP audio skin. + +.. image:: img/skin_amp_1.jpg + :alt: AMP skin + :width: 250px + +.. image:: img/skin_amp_2.jpg + :alt: AMP skin + :width: 250px + +The following video shows how to solder the headers, microphone and speaker onto the AMP skin. + +.. raw:: html + + + +For circuit schematics and datasheets for the components on the skin see :ref:`hardware_index`. + +Example code +------------ + +The AMP skin has a speaker which is connected to ``DAC(1)`` via a small +power amplifier. The volume of the amplifier is controlled by a digital +potentiometer, which is an I2C device with address 46 on the ``IC2(1)`` bus. + +To set the volume, define the following function:: + + import pyb + def volume(val): + pyb.I2C(1, pyb.I2C.MASTER).mem_write(val, 46, 0) + +Then you can do:: + + >>> volume(0) # minimum volume + >>> volume(127) # maximum volume + +To play a sound, use the ``write_timed`` method of the ``DAC`` object. +For example:: + + import math + from pyb import DAC + + # create a buffer containing a sine-wave + buf = bytearray(100) + for i in range(len(buf)): + buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf))) + + # output the sine-wave at 400Hz + dac = DAC(1) + dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) + +You can also play WAV files using the Python ``wave`` module. You can get +the wave module `here `__ and you will also need +the chunk module available `here `__. Put these +on your pyboard (either on the flash or the SD card in the top-level directory). You will need an +8-bit WAV file to play, such as `this one `_, +or to convert any file you have with the command:: + + avconv -i original.wav -ar 22050 -codec pcm_u8 test.wav + +Then you can do:: + + >>> import wave + >>> from pyb import DAC + >>> dac = DAC(1) + >>> f = wave.open('test.wav') + >>> dac.write_timed(f.readframes(f.getnframes()), f.getframerate()) + +This should play the WAV file. Note that this will read the whole file into RAM +so it has to be small enough to fit in it. + +To play larger wave files you will have to use the micro-SD card to store it. +Also the file must be read and sent to the DAC in small chunks that will fit +the RAM limit of the microcontroller. Here is an example function that can +play 8-bit wave files with up to 16kHz sampling:: + + import wave + from pyb import DAC + from pyb import delay + dac = DAC(1) + + def play(filename): + f = wave.open(filename, 'r') + total_frames = f.getnframes() + framerate = f.getframerate() + + for position in range(0, total_frames, framerate): + f.setpos(position) + dac.write_timed(f.readframes(framerate), framerate) + delay(1000) + +This function reads one second worth of data and sends it to DAC. It then waits +one second and moves the file cursor to the new position to read the next second +of data in the next iteration of the for-loop. It plays one second of audio at +a time every one second. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/assembler.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/assembler.rst new file mode 100755 index 0000000..1fe2bc4 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/assembler.rst @@ -0,0 +1,131 @@ +.. _pyboard_tutorial_assembler: + +Inline assembler +================ + +Here you will learn how to write inline assembler in MicroPython. + +**Note**: this is an advanced tutorial, intended for those who already +know a bit about microcontrollers and assembly language. + +MicroPython includes an inline assembler. It allows you to write +assembly routines as a Python function, and you can call them as you would +a normal Python function. + +Returning a value +----------------- + +Inline assembler functions are denoted by a special function decorator. +Let's start with the simplest example:: + + @micropython.asm_thumb + def fun(): + movw(r0, 42) + +You can enter this in a script or at the REPL. This function takes no +arguments and returns the number 42. ``r0`` is a register, and the value +in this register when the function returns is the value that is returned. +MicroPython always interprets the ``r0`` as an integer, and converts it to an +integer object for the caller. + +If you run ``print(fun())`` you will see it print out 42. + +Accessing peripherals +--------------------- + +For something a bit more complicated, let's turn on an LED:: + + @micropython.asm_thumb + def led_on(): + movwt(r0, stm.GPIOA) + movw(r1, 1 << 13) + strh(r1, [r0, stm.GPIO_BSRRL]) + +This code uses a few new concepts: + + - ``stm`` is a module which provides a set of constants for easy + access to the registers of the pyboard's microcontroller. Try + running ``import stm`` and then ``help(stm)`` at the REPL. It will + give you a list of all the available constants. + + - ``stm.GPIOA`` is the address in memory of the GPIOA peripheral. + On the pyboard, the red LED is on port A, pin PA13. + + - ``movwt`` moves a 32-bit number into a register. It is a convenience + function that turns into 2 thumb instructions: ``movw`` followed by ``movt``. + The ``movt`` also shifts the immediate value right by 16 bits. + + - ``strh`` stores a half-word (16 bits). The instruction above stores + the lower 16-bits of ``r1`` into the memory location ``r0 + stm.GPIO_BSRRL``. + This has the effect of setting high all those pins on port A for which + the corresponding bit in ``r0`` is set. In our example above, the 13th + bit in ``r0`` is set, so PA13 is pulled high. This turns on the red LED. + +Accepting arguments +------------------- + +Inline assembler functions can accept up to 4 arguments. If they are +used, they must be named ``r0``, ``r1``, ``r2`` and ``r3`` to reflect the registers +and the calling conventions. + +Here is a function that adds its arguments:: + + @micropython.asm_thumb + def asm_add(r0, r1): + add(r0, r0, r1) + +This performs the computation ``r0 = r0 + r1``. Since the result is put +in ``r0``, that is what is returned. Try ``asm_add(1, 2)``, it should return +3. + +Loops +----- + +We can assign labels with ``label(my_label)``, and branch to them using +``b(my_label)``, or a conditional branch like ``bgt(my_label)``. + +The following example flashes the green LED. It flashes it ``r0`` times. :: + + @micropython.asm_thumb + def flash_led(r0): + # get the GPIOA address in r1 + movwt(r1, stm.GPIOA) + + # get the bit mask for PA14 (the pin LED #2 is on) + movw(r2, 1 << 14) + + b(loop_entry) + + label(loop1) + + # turn LED on + strh(r2, [r1, stm.GPIO_BSRRL]) + + # delay for a bit + movwt(r4, 5599900) + label(delay_on) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_on) + + # turn LED off + strh(r2, [r1, stm.GPIO_BSRRH]) + + # delay for a bit + movwt(r4, 5599900) + label(delay_off) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_off) + + # loop r0 times + sub(r0, r0, 1) + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + +Further reading +--------------- + +For further information about supported instructions of the inline assembler, +see the :ref:`reference documentation `. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/debounce.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/debounce.rst new file mode 100755 index 0000000..f730e1d --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/debounce.rst @@ -0,0 +1,37 @@ +Debouncing a pin input +====================== + +A pin used as input from a switch or other mechanical device can have a lot +of noise on it, rapidly changing from low to high when the switch is first +pressed or released. This noise can be eliminated using a capacitor (a +debouncing circuit). It can also be eliminated using a simple function that +makes sure the value on the pin is stable. + +The following function does just this. It gets the current value of the given +pin, and then waits for the value to change. The new pin value must be stable +for a continuous 20ms for it to register the change. You can adjust this time +(to say 50ms) if you still have noise. :: + + import pyb + + def wait_pin_change(pin): + # wait for pin to change value + # it needs to be stable for a continuous 20ms + cur_value = pin.value() + active = 0 + while active < 20: + if pin.value() != cur_value: + active += 1 + else: + active = 0 + pyb.delay(1) + + +Use it something like this:: + + import pyb + + pin_x1 = pyb.Pin('X1', pyb.Pin.IN, pyb.Pin.PULL_DOWN) + while True: + wait_pin_change(pin_x1) + pyb.LED(4).toggle() diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/fading_led.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/fading_led.rst new file mode 100755 index 0000000..8303c96 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/fading_led.rst @@ -0,0 +1,91 @@ +Fading LEDs +=========== + +In addition to turning LEDs on and off, it is also possible to control the brightness of an LED using `Pulse-Width Modulation (PWM) `_, a common technique for obtaining variable output from a digital pin. This allows us to fade an LED: + +.. only:: not latex + + .. image:: http://upload.wikimedia.org/wikipedia/commons/a/a9/Fade.gif + +Components +---------- + +You will need: + +- Standard 5 or 3 mm LED +- 100 Ohm resistor +- Wires +- `Breadboard `_ (optional, but makes things easier) + +Connecting Things Up +-------------------- + +For this tutorial, we will use the ``X1`` pin. Connect one end of the resistor to ``X1``, and the other end to the **anode** of the LED, which is the longer leg. Connect the **cathode** of the LED to ground. + +.. image:: img/fading_leds_breadboard_fritzing.png + +Code +---- +By examining the :ref:`pyboard_quickref`, we see that ``X1`` is connected to channel 1 of timer 5 (``TIM5 CH1``). Therefore we will first create a ``Timer`` object for timer 5, then create a ``TimerChannel`` object for channel 1:: + + from pyb import Timer + from time import sleep + + # timer 5 will be created with a frequency of 100 Hz + tim = pyb.Timer(5, freq=100) + tchannel = tim.channel(1, Timer.PWM, pin=pyb.Pin.board.X1, pulse_width=0) + +Brightness of the LED in PWM is controlled by controlling the pulse-width, that is the amount of time the LED is on every cycle. With a timer frequency of 100 Hz, each cycle takes 0.01 second, or 10 ms. + +To achieve the fading effect shown at the beginning of this tutorial, we want to set the pulse-width to a small value, then slowly increase the pulse-width to brighten the LED, and start over when we reach some maximum brightness:: + + # maximum and minimum pulse-width, which corresponds to maximum + # and minimum brightness + max_width = 200000 + min_width = 20000 + + # how much to change the pulse-width by each step + wstep = 1500 + cur_width = min_width + + while True: + tchannel.pulse_width(cur_width) + + # this determines how often we change the pulse-width. It is + # analogous to frames-per-second + sleep(0.01) + + cur_width += wstep + + if cur_width > max_width: + cur_width = min_width + +Breathing Effect +---------------- + +If we want to have a breathing effect, where the LED fades from dim to bright then bright to dim, then we simply need to reverse the sign of ``wstep`` when we reach maximum brightness, and reverse it again at minimum brightness. To do this we modify the ``while`` loop to be:: + + while True: + tchannel.pulse_width(cur_width) + + sleep(0.01) + + cur_width += wstep + + if cur_width > max_width: + cur_width = max_width + wstep *= -1 + elif cur_width < min_width: + cur_width = min_width + wstep *= -1 + +Advanced Exercise +----------------- + +You may have noticed that the LED brightness seems to fade slowly, but increases quickly. This is because our eyes interprets brightness logarithmically (`Weber's Law `_ +), while the LED's brightness changes linearly, that is by the same amount each time. How do you solve this problem? (Hint: what is the opposite of the logarithmic function?) + +Addendum +-------- + +We could have also used the digital-to-analog converter (DAC) to achieve the same effect. The PWM method has the advantage that it drives the LED with the same current each time, but for different lengths of time. This allows better control over the brightness, because LEDs do not necessarily exhibit a linear relationship between the driving current and brightness. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/fading_leds_breadboard_fritzing.png b/src/openmv/src/micropython/docs/pyboard/tutorial/img/fading_leds_breadboard_fritzing.png new file mode 100755 index 0000000..a8eec4e Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/fading_leds_breadboard_fritzing.png differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_servo.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_servo.jpg new file mode 100755 index 0000000..0d64e46 Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_servo.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_usb_micro.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_usb_micro.jpg new file mode 100755 index 0000000..bc1c2b8 Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/pyboard_usb_micro.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_1.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_1.jpg new file mode 100755 index 0000000..df44460 Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_1.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_2.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_2.jpg new file mode 100755 index 0000000..7631b3b Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_amp_2.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_1.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_1.jpg new file mode 100755 index 0000000..1dda73f Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_1.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_2.jpg b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_2.jpg new file mode 100755 index 0000000..6e3e103 Binary files /dev/null and b/src/openmv/src/micropython/docs/pyboard/tutorial/img/skin_lcd_2.jpg differ diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/index.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/index.rst new file mode 100755 index 0000000..666c2de --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/index.rst @@ -0,0 +1,48 @@ +.. _pyboard_tutorial: + +MicroPython tutorial for the pyboard +==================================== + +This tutorial is intended to get you started with your pyboard. +All you need is a pyboard and a micro-USB cable to connect it to +your PC. If it is your first time, it is recommended to follow +the tutorial through in the order below. + +.. toctree:: + :maxdepth: 1 + :numbered: + + intro.rst + script.rst + repl.rst + leds.rst + switch.rst + accel.rst + reset.rst + usb_mouse.rst + timer.rst + assembler.rst + power_ctrl.rst + +Tutorials requiring extra components +------------------------------------ + +.. toctree:: + :maxdepth: 1 + :numbered: + + servo.rst + fading_led.rst + lcd_skin.rst + amp_skin.rst + lcd160cr_skin.rst + +Tips, tricks and useful things to know +-------------------------------------- + +.. toctree:: + :maxdepth: 1 + :numbered: + + debounce.rst + pass_through.rst diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/intro.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/intro.rst new file mode 100755 index 0000000..78343db --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/intro.rst @@ -0,0 +1,54 @@ +Introduction to the pyboard +=========================== + +To get the most out of your pyboard, there are a few basic things to +understand about how it works. + +Caring for your pyboard +----------------------- + +Because the pyboard does not have a housing it needs a bit of care: + + - Be gentle when plugging/unplugging the USB cable. Whilst the USB connector + is soldered through the board and is relatively strong, if it breaks off + it can be very difficult to fix. + + - Static electricity can shock the components on the pyboard and destroy them. + If you experience a lot of static electricity in your area (eg dry and cold + climates), take extra care not to shock the pyboard. If your pyboard came + in a black plastic box, then this box is the best way to store and carry the + pyboard as it is an anti-static box (it is made of a conductive plastic, with + conductive foam inside). + +As long as you take care of the hardware, you should be okay. It's almost +impossible to break the software on the pyboard, so feel free to play around +with writing code as much as you like. If the filesystem gets corrupt, see +below on how to reset it. In the worst case you might need to reflash the +MicroPython software, but that can be done over USB. + +Layout of the pyboard +--------------------- + +The micro USB connector is on the top right, the micro SD card slot on +the top left of the board. There are 4 LEDs between the SD slot and +USB connector. The colours are: red on the bottom, then green, orange, +and blue on the top. There are 2 switches: the right one is the reset +switch, the left is the user switch. + +Plugging in and powering on +--------------------------- + +The pyboard can be powered via USB. Connect it to your PC via a micro USB +cable. There is only one way that the cable will fit. Once connected, +the green LED on the board should flash quickly. + +Powering by an external power source +------------------------------------ + +The pyboard can be powered by a battery or other external power source. + +**Be sure to connect the positive lead of the power supply to VIN, and +ground to GND. There is no polarity protection on the pyboard so you +must be careful when connecting anything to VIN.** + +**The input voltage must be between 3.6V and 10V.** diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/lcd160cr_skin.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/lcd160cr_skin.rst new file mode 100755 index 0000000..fc9d635 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/lcd160cr_skin.rst @@ -0,0 +1,134 @@ +The LCD160CR skin +================= + +This tutorial shows how to get started using the LCD160CR skin. + +.. image:: http://micropython.org/resources/LCD160CRv10-positions.jpg + :alt: LCD160CRv1.0 picture + :width: 800px + +For detailed documentation of the driver for the display see the +:mod:`lcd160cr` module. + +Plugging in the display +----------------------- + +The display can be plugged directly into a pyboard (all pyboard versions +are supported). You plug the display onto the top of the pyboard either +in the X or Y positions. The display should cover half of the pyboard. +See the picture above for how to achieve this; the left half of the picture +shows the X position, and the right half shows the Y position. + +Getting the driver +------------------ + +You can control the display directly using a power/enable pin and an I2C +bus, but it is much more convenient to use the driver provided by the +:mod:`lcd160cr` module. This driver is included in recent version of the +pyboard firmware (see `here `__). You +can also find the driver in the GitHub repository +`here `__, and to use this version you will need to copy the file to your +board, into a directory that is searched by import (usually the lib/ +directory). + +Once you have the driver installed you need to import it to use it:: + + import lcd160cr + +Testing the display +------------------- + +There is a test program which you can use to test the features of the display, +and which also serves as a basis to start creating your own code that uses the +LCD. This test program is included in recent versions of the pyboard firmware +and is also available on GitHub +`here `__. + +To run the test from the MicroPython prompt do:: + + >>> import lcd160cr_test + +It will then print some brief instructions. You will need to know which +position your display is connected to (X or Y) and then you can run (assuming +you have the display on position X):: + + >>> test_all('X') + +Drawing some graphics +--------------------- + +You must first create an LCD160CR object which will control the display. Do this +using:: + + >>> import lcd160cr + >>> lcd = lcd160cr.LCD160CR('X') + +This assumes your display is connected in the X position. If it's in the Y +position then use ``lcd = lcd160cr.LCD160CR('Y')`` instead. + +To erase the screen and draw a line, try:: + + >>> lcd.set_pen(lcd.rgb(255, 0, 0), lcd.rgb(64, 64, 128)) + >>> lcd.erase() + >>> lcd.line(10, 10, 50, 80) + +The next example draws random rectangles on the screen. You can copy-and-paste it +into the MicroPython prompt by first pressing "Ctrl-E" at the prompt, then "Ctrl-D" +once you have pasted the text. :: + + from random import randint + for i in range(1000): + fg = lcd.rgb(randint(128, 255), randint(128, 255), randint(128, 255)) + bg = lcd.rgb(randint(0, 128), randint(0, 128), randint(0, 128)) + lcd.set_pen(fg, bg) + lcd.rect(randint(0, lcd.w), randint(0, lcd.h), randint(10, 40), randint(10, 40)) + +Using the touch sensor +---------------------- + +The display includes a resistive touch sensor that can report the position (in +pixels) of a single force-based touch on the screen. To see if there is a touch +on the screen use:: + + >>> lcd.is_touched() + +This will return either ``False`` or ``True``. Run the above command while touching +the screen to see the result. + +To get the location of the touch you can use the method:: + + >>> lcd.get_touch() + +This will return a 3-tuple, with the first entry being 0 or 1 depending on whether +there is currently anything touching the screen (1 if there is), and the second and +third entries in the tuple being the x and y coordinates of the current (or most +recent) touch. + +Directing the MicroPython output to the display +----------------------------------------------- + +The display supports input from a UART and implements basic VT100 commands, which +means it can be used as a simple, general purpose terminal. Let's set up the +pyboard to redirect its output to the display. + +First you need to create a UART object:: + + >>> import pyb + >>> uart = pyb.UART('XA', 115200) + +This assumes your display is connected to position X. If it's on position Y then +use ``uart = pyb.UART('YA', 115200)`` instead. + +Now, connect the REPL output to this UART:: + + >>> pyb.repl_uart(uart) + +From now on anything you type at the MicroPython prompt, and any output you +receive, will appear on the display. + +No set-up commands are required for this mode to work and you can use the display +to monitor the output of any UART, not just from the pyboard. All that is needed +is for the display to have power, ground and the power/enable pin driven high. +Then any characters on the display's UART input will be printed to the screen. +You can adjust the UART baudrate from the default of 115200 using the +`set_uart_baudrate` method. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/lcd_skin.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/lcd_skin.rst new file mode 100755 index 0000000..288ac1b --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/lcd_skin.rst @@ -0,0 +1,86 @@ +The LCD and touch-sensor skin +============================= + +Soldering and using the LCD and touch-sensor skin. + +.. image:: img/skin_lcd_1.jpg + :alt: pyboard with LCD skin + :width: 250px + +.. image:: img/skin_lcd_2.jpg + :alt: pyboard with LCD skin + :width: 250px + +The following video shows how to solder the headers onto the LCD skin. +At the end of the video, it shows you how to correctly connect the LCD skin to the pyboard. + +.. raw:: html + + + +For circuit schematics and datasheets for the components on the skin see :ref:`hardware_index`. + +Using the LCD +------------- + +To get started using the LCD, try the following at the MicroPython prompt. +Make sure the LCD skin is attached to the pyboard as pictured at the top of this page. :: + + >>> import pyb + >>> lcd = pyb.LCD('X') + >>> lcd.light(True) + >>> lcd.write('Hello uPy!\n') + +You can make a simple animation using the code:: + + import pyb + lcd = pyb.LCD('X') + lcd.light(True) + for x in range(-80, 128): + lcd.fill(0) + lcd.text('Hello uPy!', x, 10, 1) + lcd.show() + pyb.delay(25) + +Using the touch sensor +---------------------- + +To read the touch-sensor data you need to use the I2C bus. The +MPR121 capacitive touch sensor has address 90. + +To get started, try:: + + >>> import pyb + >>> i2c = pyb.I2C(1, pyb.I2C.MASTER) + >>> i2c.mem_write(4, 90, 0x5e) + >>> touch = i2c.mem_read(1, 90, 0)[0] + +The first line above makes an I2C object, and the second line +enables the 4 touch sensors. The third line reads the touch +status and the ``touch`` variable holds the state of the 4 touch +buttons (A, B, X, Y). + +There is a simple driver `here `__ +which allows you to set the threshold and debounce parameters, and +easily read the touch status and electrode voltage levels. Copy +this script to your pyboard (either flash or SD card, in the top +directory or ``lib/`` directory) and then try:: + + >>> import pyb + >>> import mpr121 + >>> m = mpr121.MPR121(pyb.I2C(1, pyb.I2C.MASTER)) + >>> for i in range(100): + ... print(m.touch_status()) + ... pyb.delay(100) + ... + +This will continuously print out the touch status of all electrodes. +Try touching each one in turn. + +Note that if you put the LCD skin in the Y-position, then you need to +initialise the I2C bus using:: + + >>> m = mpr121.MPR121(pyb.I2C(2, pyb.I2C.MASTER)) + +There is also a demo which uses the LCD and the touch sensors together, +and can be found `here `__. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/leds.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/leds.rst new file mode 100755 index 0000000..6b05f5d --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/leds.rst @@ -0,0 +1,75 @@ +Turning on LEDs and basic Python concepts +========================================= + +The easiest thing to do on the pyboard is to turn on the LEDs attached to the board. Connect the board, and log in as described in tutorial 1. We will start by turning and LED on in the interpreter, type the following :: + + >>> myled = pyb.LED(1) + >>> myled.on() + >>> myled.off() + +These commands turn the LED on and off. + +This is all very well but we would like this process to be automated. Open the file MAIN.PY on the pyboard in your favourite text editor. Write or paste the following lines into the file. If you are new to python, then make sure you get the indentation correct since this matters! :: + + led = pyb.LED(2) + while True: + led.toggle() + pyb.delay(1000) + +When you save, the red light on the pyboard should turn on for about a second. To run the script, do a soft reset (CTRL-D). The pyboard will then restart and you should see a green light continuously flashing on and off. Success, the first step on your path to building an army of evil robots! When you are bored of the annoying flashing light then press CTRL-C at your terminal to stop it running. + +So what does this code do? First we need some terminology. Python is an object-oriented language, almost everything in python is a *class* and when you create an instance of a class you get an *object*. Classes have *methods* associated to them. A method (also called a member function) is used to interact with or control the object. + +The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in miliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second. + +**Exercise: Try changing the time between toggling the led and turning on a different LED.** + +**Exercise: Connect to the pyboard directly, create a pyb.LED object and turn it on using the on() method.** + +A Disco on your pyboard +----------------------- + +So far we have only used a single LED but the pyboard has 4 available. Let's start by creating an object for each LED so we can control each of them. We do that by creating a list of LEDS with a list comprehension. :: + + leds = [pyb.LED(i) for i in range(1,5)] + +If you call pyb.LED() with a number that isn't 1,2,3,4 you will get an error message. +Next we will set up an infinite loop that cycles through each of the LEDs turning them on and off. :: + + n = 0 + while True: + n = (n + 1) % 4 + leds[n].toggle() + pyb.delay(50) + +Here, n keeps track of the current LED and every time the loop is executed we cycle to the next n (the % sign is a modulus operator that keeps n between 0 and 3.) Then we access the nth LED and toggle it. If you run this you should see each of the LEDs turning on then all turning off again in sequence. + +One problem you might find is that if you stop the script and then start it again that the LEDs are stuck on from the previous run, ruining our carefully choreographed disco. We can fix this by turning all the LEDs off when we initialise the script and then using a try/finally block. When you press CTRL-C, MicroPython generates a VCPInterrupt exception. Exceptions normally mean something has gone wrong and you can use a try: command to "catch" an exception. In this case it is just the user interrupting the script, so we don't need to catch the error but just tell MicroPython what to do when we exit. The finally block does this, and we use it to make sure all the LEDs are off. The full code is:: + + leds = [pyb.LED(i) for i in range(1,5)] + for l in leds: + l.off() + + n = 0 + try: + while True: + n = (n + 1) % 4 + leds[n].toggle() + pyb.delay(50) + finally: + for l in leds: + l.off() + +The Special LEDs +---------------- + +The yellow and blue LEDs are special. As well as turning them on and off, you can control their intensity using the intensity() method. This takes a number between 0 and 255 that determines how bright it is. The following script makes the blue LED gradually brighter then turns it off again. :: + + led = pyb.LED(4) + intensity = 0 + while True: + intensity = (intensity + 1) % 255 + led.intensity(intensity) + pyb.delay(20) + +You can call intensity() on LEDs 1 and 2 but they can only be off or on. 0 sets them off and any other number up to 255 turns them on. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/pass_through.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/pass_through.rst new file mode 100755 index 0000000..012a907 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/pass_through.rst @@ -0,0 +1,18 @@ +Making a UART - USB pass through +================================ + +It's as simple as:: + + import pyb + import select + + def pass_through(usb, uart): + usb.setinterrupt(-1) + while True: + select.select([usb, uart], [], []) + if usb.any(): + uart.write(usb.read(256)) + if uart.any(): + usb.write(uart.read(256)) + + pass_through(pyb.USB_VCP(), pyb.UART(1, 9600, timeout=0)) diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/power_ctrl.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/power_ctrl.rst new file mode 100755 index 0000000..877b7cd --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/power_ctrl.rst @@ -0,0 +1,13 @@ +Power control +============= + +:meth:`pyb.wfi` is used to reduce power consumption while waiting for an +event such as an interrupt. You would use it in the following situation:: + + while True: + do_some_processing() + pyb.wfi() + +Control the frequency using :meth:`pyb.freq`:: + + pyb.freq(30000000) # set CPU frequency to 30MHz diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/repl.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/repl.rst new file mode 100755 index 0000000..646ecbc --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/repl.rst @@ -0,0 +1,110 @@ +Getting a MicroPython REPL prompt +================================= + +REPL stands for Read Evaluate Print Loop, and is the name given to the +interactive MicroPython prompt that you can access on the pyboard. Using +the REPL is by far the easiest way to test out your code and run commands. +You can use the REPL in addition to writing scripts in ``main.py``. + +To use the REPL, you must connect to the serial USB device on the pyboard. +How you do this depends on your operating system. + +Windows +------- + +You need to install the pyboard driver to use the serial USB device. +The driver is on the pyboard's USB flash drive, and is called ``pybcdc.inf``. + +To install this driver you need to go to Device Manager +for your computer, find the pyboard in the list of devices (it should have +a warning sign next to it because it's not working yet), right click on +the pyboard device, select Properties, then Install Driver. You need to +then select the option to find the driver manually (don't use Windows auto update), +navigate to the pyboard's USB drive, and select that. It should then install. +After installing, go back to the Device Manager to find the installed pyboard, +and see which COM port it is (eg COM4). +More comprehensive instructions can be found in the +`Guide for pyboard on Windows (PDF) `_. +Please consult this guide if you are having problems installing the driver. + +You now need to run your terminal program. You can use HyperTerminal if you +have it installed, or download the free program PuTTY: +`putty.exe `_. +Using your serial program you must connect to the COM port that you found in the +previous step. With PuTTY, click on "Session" in the left-hand panel, then click +the "Serial" radio button on the right, then enter you COM port (eg COM4) in the +"Serial Line" box. Finally, click the "Open" button. + +Mac OS X +-------- + +Open a terminal and run:: + + screen /dev/tty.usbmodem* + +When you are finished and want to exit screen, type CTRL-A CTRL-\\. + +Linux +----- + +Open a terminal and run:: + + screen /dev/ttyACM0 + +You can also try ``picocom`` or ``minicom`` instead of screen. You may have to +use ``/dev/ttyACM1`` or a higher number for ``ttyACM``. And, you may need to give +yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``, +or use sudo). + +Using the REPL prompt +--------------------- + +Now let's try running some MicroPython code directly on the pyboard. + +With your serial program open (PuTTY, screen, picocom, etc) you may see a blank +screen with a flashing cursor. Press Enter and you should be presented with a +MicroPython prompt, i.e. ``>>>``. Let's make sure it is working with the obligatory test:: + + >>> print("hello pyboard!") + hello pyboard! + +In the above, you should not type in the ``>>>`` characters. They are there to +indicate that you should type the text after it at the prompt. In the end, once +you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output +on your screen should look like it does above. + +If you already know some python you can now try some basic commands here. + +If any of this is not working you can try either a hard reset or a soft reset; +see below. + +Go ahead and try typing in some other commands. For example:: + + >>> pyb.LED(1).on() + >>> pyb.LED(2).on() + >>> 1 + 2 + 3 + >>> 1 / 2 + 0.5 + >>> 20 * 'py' + 'pypypypypypypypypypypypypypypypypypypypy' + +Resetting the board +------------------- + +If something goes wrong, you can reset the board in two ways. The first is to press CTRL-D +at the MicroPython prompt, which performs a soft reset. You will see a message something like :: + + >>> + PYB: sync filesystems + PYB: soft reboot + Micro Python v1.0 on 2014-05-03; PYBv1.0 with STM32F405RG + Type "help()" for more information. + >>> + +If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the RST +switch (the small black button closest to the micro-USB socket on the board). This will end your +session, disconnecting whatever program (PuTTY, screen, etc) that you used to connect to the pyboard. + +If you are going to do a hard-reset, it's recommended to first close your serial program and eject/unmount +the pyboard drive. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/reset.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/reset.rst new file mode 100755 index 0000000..0cd5ac2 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/reset.rst @@ -0,0 +1,60 @@ +Safe mode and factory reset +=========================== + +If something goes wrong with your pyboard, don't panic! It is almost +impossible for you to break the pyboard by programming the wrong thing. + +The first thing to try is to enter safe mode: this temporarily skips +execution of ``boot.py`` and ``main.py`` and gives default USB settings. + +If you have problems with the filesystem you can do a factory reset, +which restores the filesystem to its original state. + +Safe mode +--------- + +To enter safe mode, do the following steps: + +1. Connect the pyboard to USB so it powers up. +2. Hold down the USR switch. +3. While still holding down USR, press and release the RST switch. +4. The LEDs will then cycle green to orange to green+orange and back again. +5. Keep holding down USR until *only the orange LED is lit*, and then let + go of the USR switch. +6. The orange LED should flash quickly 4 times, and then turn off. +7. You are now in safe mode. + +In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so +the pyboard boots up with default settings. This means you now have access +to the filesystem (the USB drive should appear), and you can edit ``boot.py`` +and ``main.py`` to fix any problems. + +Entering safe mode is temporary, and does not make any changes to the +files on the pyboard. + +Factory reset the filesystem +---------------------------- + +If you pyboard's filesystem gets corrupted (for example, you forgot to +eject/unmount it), or you have some code in ``boot.py`` or ``main.py`` which +you can't escape from, then you can reset the filesystem. + +Resetting the filesystem deletes all files on the internal pyboard storage +(not the SD card), and restores the files ``boot.py``, ``main.py``, ``README.txt`` +and ``pybcdc.inf`` back to their original state. + +To do a factory reset of the filesystem you follow a similar procedure as +you did to enter safe mode, but release USR on green+orange: + +1. Connect the pyboard to USB so it powers up. +2. Hold down the USR switch. +3. While still holding down USR, press and release the RST switch. +4. The LEDs will then cycle green to orange to green+orange and back again. +5. Keep holding down USR until *both the green and orange LEDs are lit*, and + then let go of the USR switch. +6. The green and orange LEDs should flash quickly 4 times. +7. The red LED will turn on (so red, green and orange are now on). +8. The pyboard is now resetting the filesystem (this takes a few seconds). +9. The LEDs all turn off. +10. You now have a reset filesystem, and are in safe mode. +11. Press and release the RST switch to boot normally. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/script.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/script.rst new file mode 100755 index 0000000..75dd324 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/script.rst @@ -0,0 +1,105 @@ +Running your first script +========================= + +Let's jump right in and get a Python script running on the pyboard. After +all, that's what it's all about! + +Connecting your pyboard +----------------------- + +Connect your pyboard to your PC (Windows, Mac or Linux) with a micro USB cable. +There is only one way that the cable will connect, so you can't get it wrong. + +.. image:: img/pyboard_usb_micro.jpg + +When the pyboard is connected to your PC it will power on and enter the start up +process (the boot process). The green LED should light up for half a second or +less, and when it turns off it means the boot process has completed. + +Opening the pyboard USB drive +----------------------------- + +Your PC should now recognise the pyboard. It depends on the type of PC you +have as to what happens next: + + - **Windows**: Your pyboard will appear as a removable USB flash drive. + Windows may automatically pop-up a window, or you may need to go there + using Explorer. + + Windows will also see that the pyboard has a serial device, and it will + try to automatically configure this device. If it does, cancel the process. + We will get the serial device working in the next tutorial. + + - **Mac**: Your pyboard will appear on the desktop as a removable disc. + It will probably be called "NONAME". Click on it to open the pyboard folder. + + - **Linux**: Your pyboard will appear as a removable medium. On Ubuntu + it will mount automatically and pop-up a window with the pyboard folder. + On other Linux distributions, the pyboard may be mounted automatically, + or you may need to do it manually. At a terminal command line, type ``lsblk`` + to see a list of connected drives, and then ``mount /dev/sdb1`` (replace ``sdb1`` + with the appropriate device). You may need to be root to do this. + +Okay, so you should now have the pyboard connected as a USB flash drive, and +a window (or command line) should be showing the files on the pyboard drive. + +The drive you are looking at is known as ``/flash`` by the pyboard, and should contain +the following 4 files: + +* `boot.py `_ -- this script is executed when the pyboard boots up. It sets + up various configuration options for the pyboard. + +* `main.py `_ -- this is the main script that will contain your Python program. + It is executed after ``boot.py``. + +* `README.txt `_ -- this contains some very basic information about getting + started with the pyboard. + +* `pybcdc.inf `_ -- this is a Windows driver file to configure the serial USB + device. More about this in the next tutorial. + +Editing ``main.py`` +------------------- + +Now we are going to write our Python program, so open the ``main.py`` +file in a text editor. On Windows you can use notepad, or any other editor. +On Mac and Linux, use your favourite text editor. With the file open you will +see it contains 1 line:: + + # main.py -- put your code here! + +This line starts with a # character, which means that it is a *comment*. Such +lines will not do anything, and are there for you to write notes about your +program. + +Let's add 2 lines to this ``main.py`` file, to make it look like this:: + + # main.py -- put your code here! + import pyb + pyb.LED(4).on() + +The first line we wrote says that we want to use the ``pyb`` module. +This module contains all the functions and classes to control the features +of the pyboard. + +The second line that we wrote turns the blue LED on: it first gets the ``LED`` +class from the ``pyb`` module, creates LED number 4 (the blue LED), and then +turns it on. + +Resetting the pyboard +--------------------- + +To run this little script, you need to first save and close the ``main.py`` file, +and then eject (or unmount) the pyboard USB drive. Do this like you would a +normal USB flash drive. + +When the drive is safely ejected/unmounted you can get to the fun part: +press the RST switch on the pyboard to reset and run your script. The RST +switch is the small black button just below the USB connector on the board, +on the right edge. + +When you press RST the green LED will flash quickly, and then the blue +LED should turn on and stay on. + +Congratulations! You have written and run your very first MicroPython +program! diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/servo.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/servo.rst new file mode 100755 index 0000000..783d2b9 --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/servo.rst @@ -0,0 +1,146 @@ +Controlling hobby servo motors +============================== + +There are 4 dedicated connection points on the pyboard for connecting up +hobby servo motors (see eg +`Wikipedia `__). +These motors have 3 wires: ground, power and signal. On the pyboard you +can connect them in the bottom right corner, with the signal pin on the +far right. Pins X1, X2, X3 and X4 are the 4 dedicated servo signal pins. + +.. image:: img/pyboard_servo.jpg + +In this picture there are male-male double adaptors to connect the servos +to the header pins on the pyboard. + +The ground wire on a servo is usually the darkest coloured one, either +black or dark brown. The power wire will most likely be red. + +The power pin for the servos (labelled VIN) is connected directly to the +input power source of the pyboard. When powered via USB, VIN is powered +through a diode by the 5V USB power line. Connect to USB, the pyboard can +power at least 4 small to medium sized servo motors. + +If using a battery to power the pyboard and run servo motors, make sure it +is not greater than 6V, since this is the maximum voltage most servo motors +can take. (Some motors take only up to 4.8V, so check what type you are +using.) + +Creating a Servo object +----------------------- + +Plug in a servo to position 1 (the one with pin X1) and create a servo object +using:: + + >>> servo1 = pyb.Servo(1) + +To change the angle of the servo use the ``angle`` method:: + + >>> servo1.angle(45) + >>> servo1.angle(-60) + +The angle here is measured in degrees, and ranges from about -90 to +90, +depending on the motor. Calling ``angle`` without parameters will return +the current angle:: + + >>> servo1.angle() + -60 + +Note that for some angles, the returned angle is not exactly the same as +the angle you set, due to rounding errors in setting the pulse width. + +You can pass a second parameter to the ``angle`` method, which specifies how +long to take (in milliseconds) to reach the desired angle. For example, to +take 1 second (1000 milliseconds) to go from the current position to 50 degrees, +use :: + + >>> servo1.angle(50, 1000) + +This command will return straight away and the servo will continue to move +to the desired angle, and stop when it gets there. You can use this feature +as a speed control, or to synchronise 2 or more servo motors. If we have +another servo motor (``servo2 = pyb.Servo(2)``) then we can do :: + + >>> servo1.angle(-45, 2000); servo2.angle(60, 2000) + +This will move the servos together, making them both take 2 seconds to +reach their final angles. + +Note: the semicolon between the 2 expressions above is used so that they +are executed one after the other when you press enter at the REPL prompt. +In a script you don't need to do this, you can just write them one line +after the other. + +Continuous rotation servos +-------------------------- + +So far we have been using standard servos that move to a specific angle +and stay at that angle. These servo motors are useful to create joints +of a robot, or things like pan-tilt mechanisms. Internally, the motor +has a variable resistor (potentiometer) which measures the current angle +and applies power to the motor proportional to how far it is from the +desired angle. The desired angle is set by the width of a high-pulse on +the servo signal wire. A pulse width of 1500 microsecond corresponds +to the centre position (0 degrees). The pulses are sent at 50 Hz, ie +50 pulses per second. + +You can also get **continuous rotation** servo motors which turn +continuously clockwise or counterclockwise. The direction and speed of +rotation is set by the pulse width on the signal wire. A pulse width +of 1500 microseconds corresponds to a stopped motor. A pulse width +smaller or larger than this means rotate one way or the other, at a +given speed. + +On the pyboard, the servo object for a continuous rotation motor is +the same as before. In fact, using ``angle`` you can set the speed. But +to make it easier to understand what is intended, there is another method +called ``speed`` which sets the speed:: + + >>> servo1.speed(30) + +``speed`` has the same functionality as ``angle``: you can get the speed, +set it, and set it with a time to reach the final speed. :: + + >>> servo1.speed() + 30 + >>> servo1.speed(-20) + >>> servo1.speed(0, 2000) + +The final command above will set the motor to stop, but take 2 seconds +to do it. This is essentially a control over the acceleration of the +continuous servo. + +A servo speed of 100 (or -100) is considered maximum speed, but actually +you can go a bit faster than that, depending on the particular motor. + +The only difference between the ``angle`` and ``speed`` methods (apart from +the name) is the way the input numbers (angle or speed) are converted to +a pulse width. + +Calibration +----------- + +The conversion from angle or speed to pulse width is done by the servo +object using its calibration values. To get the current calibration, +use :: + + >>> servo1.calibration() + (640, 2420, 1500, 2470, 2200) + +There are 5 numbers here, which have meaning: + +1. Minimum pulse width; the smallest pulse width that the servo accepts. +2. Maximum pulse width; the largest pulse width that the servo accepts. +3. Centre pulse width; the pulse width that puts the servo at 0 degrees + or 0 speed. +4. The pulse width corresponding to 90 degrees. This sets the conversion + in the method ``angle`` of angle to pulse width. +5. The pulse width corresponding to a speed of 100. This sets the conversion + in the method ``speed`` of speed to pulse width. + +You can recalibrate the servo (change its default values) by using:: + + >>> servo1.calibration(700, 2400, 1510, 2500, 2000) + +Of course, you would change the above values to suit your particular +servo motor. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/switch.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/switch.rst new file mode 100755 index 0000000..e2a5eae --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/switch.rst @@ -0,0 +1,115 @@ +.. _pyboard_tutorial_switch: + +The Switch, callbacks and interrupts +==================================== + +The pyboard has 2 small switches, labelled USR and RST. The RST switch +is a hard-reset switch, and if you press it then it restarts the pyboard +from scratch, equivalent to turning the power off then back on. + +The USR switch is for general use, and is controlled via a Switch object. +To make a switch object do:: + + >>> sw = pyb.Switch() + +Remember that you may need to type ``import pyb`` if you get an error that +the name ``pyb`` does not exist. + +With the switch object you can get its status:: + + >>> sw.value() + False + +This will print ``False`` if the switch is not held, or ``True`` if it is held. +Try holding the USR switch down while running the above command. + +There is also a shorthand notation to get the switch status, by "calling" the +switch object:: + + >>> sw() + False + +Switch callbacks +---------------- + +The switch is a very simple object, but it does have one advanced feature: +the ``sw.callback()`` function. The callback function sets up something to +run when the switch is pressed, and uses an interrupt. It's probably best +to start with an example before understanding how interrupts work. Try +running the following at the prompt:: + + >>> sw.callback(lambda:print('press!')) + +This tells the switch to print ``press!`` each time the switch is pressed +down. Go ahead and try it: press the USR switch and watch the output on +your PC. Note that this print will interrupt anything you are typing, and +is an example of an interrupt routine running asynchronously. + +As another example try:: + + >>> sw.callback(lambda:pyb.LED(1).toggle()) + +This will toggle the red LED each time the switch is pressed. And it will +even work while other code is running. + +To disable the switch callback, pass ``None`` to the callback function:: + + >>> sw.callback(None) + +You can pass any function (that takes zero arguments) to the switch callback. +Above we used the ``lambda`` feature of Python to create an anonymous function +on the fly. But we could equally do:: + + >>> def f(): + ... pyb.LED(1).toggle() + ... + >>> sw.callback(f) + +This creates a function called ``f`` and assigns it to the switch callback. +You can do things this way when your function is more complicated than a +``lambda`` will allow. + +Note that your callback functions must not allocate any memory (for example +they cannot create a tuple or list). Callback functions should be relatively +simple. If you need to make a list, make it beforehand and store it in a +global variable (or make it local and close over it). If you need to do +a long, complicated calculation, then use the callback to set a flag which +some other code then responds to. + +Technical details of interrupts +------------------------------- + +Let's step through the details of what is happening with the switch +callback. When you register a function with ``sw.callback()``, the switch +sets up an external interrupt trigger (falling edge) on the pin that the +switch is connected to. This means that the microcontroller will listen +on the pin for any changes, and the following will occur: + +1. When the switch is pressed a change occurs on the pin (the pin goes + from low to high), and the microcontroller registers this change. +2. The microcontroller finishes executing the current machine instruction, + stops execution, and saves its current state (pushes the registers on + the stack). This has the effect of pausing any code, for example your + running Python script. +3. The microcontroller starts executing the special interrupt handler + associated with the switch's external trigger. This interrupt handler + get the function that you registered with ``sw.callback()`` and executes + it. +4. Your callback function is executed until it finishes, returning control + to the switch interrupt handler. +5. The switch interrupt handler returns, and the microcontroller is + notified that the interrupt has been dealt with. +6. The microcontroller restores the state that it saved in step 2. +7. Execution continues of the code that was running at the beginning. Apart + from the pause, this code does not notice that it was interrupted. + +The above sequence of events gets a bit more complicated when multiple +interrupts occur at the same time. In that case, the interrupt with the +highest priority goes first, then the others in order of their priority. +The switch interrupt is set at the lowest priority. + +Further reading +--------------- + +For further information about using hardware interrupts see +:ref:`writing interrupt handlers `. diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/timer.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/timer.rst new file mode 100755 index 0000000..1cca18d --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/timer.rst @@ -0,0 +1,114 @@ +The Timers +========== + +The pyboard has 14 timers which each consist of an independent counter +running at a user-defined frequency. They can be set up to run a function +at specific intervals. +The 14 timers are numbered 1 through 14, but 3 is reserved +for internal use, and 5 and 6 are used for servo and ADC/DAC control. +Avoid using these timers if possible. + +Let's create a timer object:: + + >>> tim = pyb.Timer(4) + +Now let's see what we just created:: + + >>> tim + Timer(4) + +The pyboard is telling us that ``tim`` is attached to timer number 4, but +it's not yet initialised. So let's initialise it to trigger at 10 Hz +(that's 10 times per second):: + + >>> tim.init(freq=10) + +Now that it's initialised, we can see some information about the timer:: + + >>> tim + Timer(4, prescaler=624, period=13439, mode=UP, div=1) + +The information means that this timer is set to run at the peripheral +clock speed divided by 624+1, and it will count from 0 up to 13439, at which +point it triggers an interrupt, and then starts counting again from 0. These +numbers are set to make the timer trigger at 10 Hz: the source frequency +of the timer is 84MHz (found by running ``tim.source_freq()``) so we +get 84MHz / 625 / 13440 = 10Hz. + +Timer counter +------------- + +So what can we do with our timer? The most basic thing is to get the +current value of its counter:: + + >>> tim.counter() + 21504 + +This counter will continuously change, and counts up. + +Timer callbacks +--------------- + +The next thing we can do is register a callback function for the timer to +execute when it triggers (see the :ref:`switch tutorial ` +for an introduction to callback functions):: + + >>> tim.callback(lambda t:pyb.LED(1).toggle()) + +This should start the red LED flashing right away. It will be flashing +at 5 Hz (2 toggle's are needed for 1 flash, so toggling at 10 Hz makes +it flash at 5 Hz). You can change the frequency by re-initialising the +timer:: + + >>> tim.init(freq=20) + +You can disable the callback by passing it the value ``None``:: + + >>> tim.callback(None) + +The function that you pass to callback must take 1 argument, which is +the timer object that triggered. This allows you to control the timer +from within the callback function. + +We can create 2 timers and run them independently:: + + >>> tim4 = pyb.Timer(4, freq=10) + >>> tim7 = pyb.Timer(7, freq=20) + >>> tim4.callback(lambda t: pyb.LED(1).toggle()) + >>> tim7.callback(lambda t: pyb.LED(2).toggle()) + +Because the callbacks are proper hardware interrupts, we can continue +to use the pyboard for other things while these timers are running. + +Making a microsecond counter +---------------------------- + +You can use a timer to create a microsecond counter, which might be +useful when you are doing something which requires accurate timing. +We will use timer 2 for this, since timer 2 has a 32-bit counter (so +does timer 5, but if you use timer 5 then you can't use the Servo +driver at the same time). + +We set up timer 2 as follows:: + + >>> micros = pyb.Timer(2, prescaler=83, period=0x3fffffff) + +The prescaler is set at 83, which makes this timer count at 1 MHz. +This is because the CPU clock, running at 168 MHz, is divided by +2 and then by prescaler+1, giving a frequency of 168 MHz/2/(83+1)=1 MHz +for timer 2. The period is set to a large number so that the timer +can count up to a large number before wrapping back around to zero. +In this case it will take about 17 minutes before it cycles back to +zero. + +To use this timer, it's best to first reset it to 0:: + + >>> micros.counter(0) + +and then perform your timing:: + + >>> start_micros = micros.counter() + + ... do some stuff ... + + >>> end_micros = micros.counter() diff --git a/src/openmv/src/micropython/docs/pyboard/tutorial/usb_mouse.rst b/src/openmv/src/micropython/docs/pyboard/tutorial/usb_mouse.rst new file mode 100755 index 0000000..6f8831e --- /dev/null +++ b/src/openmv/src/micropython/docs/pyboard/tutorial/usb_mouse.rst @@ -0,0 +1,131 @@ +Making the pyboard act as a USB mouse +===================================== + +The pyboard is a USB device, and can configured to act as a mouse instead +of the default USB flash drive. + +To do this we must first edit the ``boot.py`` file to change the USB +configuration. If you have not yet touched your ``boot.py`` file then it +will look something like this:: + + # boot.py -- run on boot-up + # can run arbitrary Python, but best to keep it minimal + + import pyb + #pyb.main('main.py') # main script to run after this one + #pyb.usb_mode('VCP+MSC') # act as a serial and a storage device + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse + +To enable the mouse mode, uncomment the last line of the file, to +make it look like:: + + pyb.usb_mode('VCP+HID') # act as a serial device and a mouse + +If you already changed your ``boot.py`` file, then the minimum code it +needs to work is:: + + import pyb + pyb.usb_mode('VCP+HID') + +This tells the pyboard to configure itself as a VCP (Virtual COM Port, +ie serial port) and HID (human interface device, in our case a mouse) +USB device when it boots up. + +Eject/unmount the pyboard drive and reset it using the RST switch. +Your PC should now detect the pyboard as a mouse! + +Sending mouse events by hand +---------------------------- + +To get the py-mouse to do anything we need to send mouse events to the PC. +We will first do this manually using the REPL prompt. Connect to your +pyboard using your serial program and type the following:: + + >>> hid = pyb.USB_HID() + >>> hid.send((0, 10, 0, 0)) + +Your mouse should move 10 pixels to the right! In the command above you +are sending 4 pieces of information: button status, x, y and scroll. The +number 10 is telling the PC that the mouse moved 10 pixels in the x direction. + +Let's make the mouse oscillate left and right:: + + >>> import math + >>> def osc(n, d): + ... for i in range(n): + ... hid.send((0, int(20 * math.sin(i / 10)), 0, 0)) + ... pyb.delay(d) + ... + >>> osc(100, 50) + +The first argument to the function ``osc`` is the number of mouse events to send, +and the second argument is the delay (in milliseconds) between events. Try +playing around with different numbers. + +**Exercise: make the mouse go around in a circle.** + +Making a mouse with the accelerometer +------------------------------------- + +Now lets make the mouse move based on the angle of the pyboard, using the +accelerometer. The following code can be typed directly at the REPL prompt, +or put in the ``main.py`` file. Here, we'll put in in ``main.py`` because to do +that we will learn how to go into safe mode. + +At the moment the pyboard is acting as a serial USB device and an HID (a mouse). +So you cannot access the filesystem to edit your ``main.py`` file. + +You also can't edit your ``boot.py`` to get out of HID-mode and back to normal +mode with a USB drive... + +To get around this we need to go into *safe mode*. This was described in +the [safe mode tutorial](tut-reset), but we repeat the instructions here: + +1. Hold down the USR switch. +2. While still holding down USR, press and release the RST switch. +3. The LEDs will then cycle green to orange to green+orange and back again. +4. Keep holding down USR until *only the orange LED is lit*, and then let + go of the USR switch. +5. The orange LED should flash quickly 4 times, and then turn off. +6. You are now in safe mode. + +In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so +the pyboard boots up with default settings. This means you now have access +to the filesystem (the USB drive should appear), and you can edit ``main.py``. +(Leave ``boot.py`` as-is, because we still want to go back to HID-mode after +we finish editing ``main.py``.) + +In ``main.py`` put the following code:: + + import pyb + + switch = pyb.Switch() + accel = pyb.Accel() + hid = pyb.USB_HID() + + while not switch(): + hid.send((0, accel.x(), accel.y(), 0)) + pyb.delay(20) + +Save your file, eject/unmount your pyboard drive, and reset it using the RST +switch. It should now act as a mouse, and the angle of the board will move +the mouse around. Try it out, and see if you can make the mouse stand still! + +Press the USR switch to stop the mouse motion. + +You'll note that the y-axis is inverted. That's easy to fix: just put a +minus sign in front of the y-coordinate in the ``hid.send()`` line above. + +Restoring your pyboard to normal +-------------------------------- + +If you leave your pyboard as-is, it'll behave as a mouse everytime you plug +it in. You probably want to change it back to normal. To do this you need +to first enter safe mode (see above), and then edit the ``boot.py`` file. +In the ``boot.py`` file, comment out (put a # in front of) the line with the +``VCP+HID`` setting, so it looks like:: + + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse + +Save your file, eject/unmount the drive, and reset the pyboard. It is now +back to normal operating mode. diff --git a/src/openmv/src/micropython/docs/readthedocs/settings/local_settings.py b/src/openmv/src/micropython/docs/readthedocs/settings/local_settings.py new file mode 100755 index 0000000..8d2bac7 --- /dev/null +++ b/src/openmv/src/micropython/docs/readthedocs/settings/local_settings.py @@ -0,0 +1,9 @@ +import os + +# Directory that the project lives in, aka ../.. +SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2]) + +TEMPLATE_DIRS = ( + "%s/templates/" % SITE_ROOT, # Your custom template directory, before the RTD one to override it. + "%s/readthedocs/templates/" % SITE_ROOT, # Default RTD template dir +) diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_arith.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_arith.rst new file mode 100755 index 0000000..da4a688 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_arith.rst @@ -0,0 +1,50 @@ +Arithmetic instructions +======================= + +Document conventions +-------------------- + +Notation: ``Rd, Rm, Rn`` denote ARM registers R0-R7. ``immN`` denotes an immediate +value having a width of N bits e.g. ``imm8``, ``imm3``. ``carry`` denotes +the carry condition flag, ``not(carry)`` denotes its complement. In the case of instructions +with more than one register argument, it is permissible for some to be identical. For example +the following will add the contents of R0 to itself, placing the result in R0: + +* add(r0, r0, r0) + +Arithmetic instructions affect the condition flags except where stated. + +Addition +-------- + +* add(Rdn, imm8) ``Rdn = Rdn + imm8`` +* add(Rd, Rn, imm3) ``Rd = Rn + imm3`` +* add(Rd, Rn, Rm) ``Rd = Rn +Rm`` +* adc(Rd, Rn) ``Rd = Rd + Rn + carry`` + +Subtraction +----------- + +* sub(Rdn, imm8) ``Rdn = Rdn - imm8`` +* sub(Rd, Rn, imm3) ``Rd = Rn - imm3`` +* sub(Rd, Rn, Rm) ``Rd = Rn - Rm`` +* sbc(Rd, Rn) ``Rd = Rd - Rn - not(carry)`` + +Negation +-------- + +* neg(Rd, Rn) ``Rd = -Rn`` + +Multiplication and division +--------------------------- + +* mul(Rd, Rn) ``Rd = Rd * Rn`` + +This produces a 32 bit result with overflow lost. The result may be treated as +signed or unsigned according to the definition of the operands. + +* sdiv(Rd, Rn, Rm) ``Rd = Rn / Rm`` +* udiv(Rd, Rn, Rm) ``Rd = Rn / Rm`` + +These functions perform signed and unsigned division respectively. Condition flags +are not affected. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_compare.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_compare.rst new file mode 100755 index 0000000..521af69 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_compare.rst @@ -0,0 +1,90 @@ +Comparison instructions +======================= + +These perform an arithmetic or logical instruction on two arguments, discarding the result +but setting the condition flags. Typically these are used to test data values without changing +them prior to executing a conditional branch. + +Document conventions +-------------------- + +Notation: ``Rd, Rm, Rn`` denote ARM registers R0-R7. ``imm8`` denotes an immediate +value having a width of 8 bits. + +The Application Program Status Register (APSR) +---------------------------------------------- + +This contains four bits which are tested by the conditional branch instructions. Typically a +conditional branch will test multiple bits, for example ``bge(LABEL)``. The meaning of +condition codes can depend on whether the operands of an arithmetic instruction are viewed as +signed or unsigned integers. Thus ``bhi(LABEL)`` assumes unsigned numbers were processed while +``bgt(LABEL)`` assumes signed operands. + +APSR Bits +--------- + +* Z (zero) + +This is set if the result of an operation is zero or the operands of a comparison are equal. + +* N (negative) + +Set if the result is negative. + +* C (carry) + +An addition sets the carry flag when the result overflows out of the MSB, for example adding +0x80000000 and 0x80000000. By the nature of two's complement arithmetic this behaviour is reversed +on subtraction, with a borrow indicated by the carry bit being clear. Thus 0x10 - 0x01 is executed +as 0x10 + 0xffffffff which will set the carry bit. + +* V (overflow) + +The overflow flag is set if the result, viewed as a two's compliment number, has the "wrong" sign +in relation to the operands. For example adding 1 to 0x7fffffff will set the overflow bit because +the result (0x8000000), viewed as a two's complement integer, is negative. Note that in this instance +the carry bit is not set. + +Comparison instructions +----------------------- + +These set the APSR (Application Program Status Register) N (negative), Z (zero), C (carry) and V +(overflow) flags. + +* cmp(Rn, imm8) ``Rn - imm8`` +* cmp(Rn, Rm) ``Rn - Rm`` +* cmn(Rn, Rm) ``Rn + Rm`` +* tst(Rn, Rm) ``Rn & Rm`` + +Conditional execution +--------------------- + +The ``it`` and ``ite`` instructions provide a means of conditionally executing from one to four subsequent +instructions without the need for a label. + +* it() If then + +Execute the next instruction if is true: + +:: + + cmp(r0, r1) + it(eq) + mov(r0, 100) # runs if r0 == r1 + # execution continues here + +* ite() If then else + +If is true, execute the next instruction, otherwise execute the +subsequent one. Thus: + +:: + + cmp(r0, r1) + ite(eq) + mov(r0, 100) # runs if r0 == r1 + mov(r0, 200) # runs if r0 != r1 + # execution continues here + +This may be extended to control the execution of upto four subsequent instructions: it[x[y[z]]] +where x,y,z=t/e; e.g. itt, itee, itete, ittte, itttt, iteee, etc. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_directives.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_directives.rst new file mode 100755 index 0000000..95acd77 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_directives.rst @@ -0,0 +1,36 @@ +Assembler Directives +==================== + +Labels +------ + +* label(INNER1) + +This defines a label for use in a branch instruction. Thus elsewhere in the code a ``b(INNER1)`` +will cause execution to continue with the instruction after the label directive. + +Defining inline data +-------------------- + +The following assembler directives facilitate embedding data in an assembler code block. + +* data(size, d0, d1 .. dn) + +The data directive creates n array of data values in memory. The first argument specifies the +size in bytes of the subsequent arguments. Hence the first statement below will cause the +assembler to put three bytes (with values 2, 3 and 4) into consecutive memory locations +while the second will cause it to emit two four byte words. + +:: + + data(1, 2, 3, 4) + data(4, 2, 100000) + +Data values longer than a single byte are stored in memory in little-endian format. + +* align(nBytes) + +Align the following instruction to an nBytes value. ARM Thumb-2 instructions must be two +byte aligned, hence it's advisable to issue ``align(2)`` after ``data`` directives and +prior to any subsequent code. This ensures that the code will run irrespective of the +size of the data array. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_float.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_float.rst new file mode 100755 index 0000000..4acb734 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_float.rst @@ -0,0 +1,77 @@ +Floating Point instructions +============================== + +These instructions support the use of the ARM floating point coprocessor +(on platforms such as the Pyboard which are equipped with one). The FPU +has 32 registers known as ``s0-s31`` each of which can hold a single +precision float. Data can be passed between the FPU registers and the +ARM core registers with the ``vmov`` instruction. + +Note that MicroPython doesn't support passing floats to +assembler functions, nor can you put a float into ``r0`` and expect a +reasonable result. There are two ways to overcome this. The first is to +use arrays, and the second is to pass and/or return integers and convert +to and from floats in code. + +Document conventions +-------------------- + +Notation: ``Sd, Sm, Sn`` denote FPU registers, ``Rd, Rm, Rn`` denote ARM core +registers. The latter can be any ARM core register although registers +``R13-R15`` are unlikely to be appropriate in this context. + +Arithmetic +---------- + +* vadd(Sd, Sn, Sm) ``Sd = Sn + Sm`` +* vsub(Sd, Sn, Sm) ``Sd = Sn - Sm`` +* vneg(Sd, Sm) ``Sd = -Sm`` +* vmul(Sd, Sn, Sm) ``Sd = Sn * Sm`` +* vdiv(Sd, Sn, Sm) ``Sd = Sn / Sm`` +* vsqrt(Sd, Sm) ``Sd = sqrt(Sm)`` + +Registers may be identical: ``vmul(S0, S0, S0)`` will execute ``S0 = S0*S0`` + +Move between ARM core and FPU registers +--------------------------------------- + +* vmov(Sd, Rm) ``Sd = Rm`` +* vmov(Rd, Sm) ``Rd = Sm`` + +The FPU has a register known as FPSCR, similar to the ARM core's APSR, which stores condition +codes plus other data. The following instructions provide access to this. + +* vmrs(APSR\_nzcv, FPSCR) + +Move the floating-point N, Z, C, and V flags to the APSR N, Z, C, and V flags. + +This is done after an instruction such as an FPU +comparison to enable the condition codes to be tested by the assembler +code. The following is a more general form of the instruction. + +* vmrs(Rd, FPSCR) ``Rd = FPSCR`` + +Move between FPU register and memory +------------------------------------ + +* vldr(Sd, [Rn, offset]) ``Sd = [Rn + offset]`` +* vstr(Sd, [Rn, offset]) ``[Rn + offset] = Sd`` + +Where ``[Rn + offset]`` denotes the memory address obtained by adding Rn to the offset. This +is specified in bytes. Since each float value occupies a 32 bit word, when accessing arrays of +floats the offset must always be a multiple of four bytes. + +Data Comparison +--------------- + +* vcmp(Sd, Sm) + +Compare the values in Sd and Sm and set the FPU N, Z, +C, and V flags. This would normally be followed by ``vmrs(APSR_nzcv, FPSCR)`` +to enable the results to be tested. + +Convert between integer and float +--------------------------------- + +* vcvt\_f32\_s32(Sd, Sm) ``Sd = float(Sm)`` +* vcvt\_s32\_f32(Sd, Sm) ``Sd = int(Sm)`` diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_hints_tips.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_hints_tips.rst new file mode 100755 index 0000000..062a3c8 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_hints_tips.rst @@ -0,0 +1,244 @@ +Hints and tips +============== + +The following are some examples of the use of the inline assembler and some +information on how to work around its limitations. In this document the term +"assembler function" refers to a function declared in Python with the +``@micropython.asm_thumb`` decorator, whereas "subroutine" refers to assembler +code called from within an assembler function. + +Code branches and subroutines +----------------------------- + +It is important to appreciate that labels are local to an assembler function. +There is currently no way for a subroutine defined in one function to be called +from another. + +To call a subroutine the instruction ``bl(LABEL)`` is issued. This transfers +control to the instruction following the ``label(LABEL)`` directive and stores +the return address in the link register (``lr`` or ``r14``). To return the +instruction ``bx(lr)`` is issued which causes execution to continue with +the instruction following the subroutine call. This mechanism implies that, if +a subroutine is to call another, it must save the link register prior to +the call and restore it before terminating. + +The following rather contrived example illustrates a function call. Note that +it's necessary at the start to branch around all subroutine calls: subroutines +end execution with ``bx(lr)`` while the outer function simply "drops off the end" +in the style of Python functions. + +:: + + @micropython.asm_thumb + def quad(r0): + b(START) + label(DOUBLE) + add(r0, r0, r0) + bx(lr) + label(START) + bl(DOUBLE) + bl(DOUBLE) + + print(quad(10)) + +The following code example demonstrates a nested (recursive) call: the classic +Fibonacci sequence. Here, prior to a recursive call, the link register is saved +along with other registers which the program logic requires to be preserved. + +:: + + @micropython.asm_thumb + def fib(r0): + b(START) + label(DOFIB) + push({r1, r2, lr}) + cmp(r0, 1) + ble(FIBDONE) + sub(r0, 1) + mov(r2, r0) # r2 = n -1 + bl(DOFIB) + mov(r1, r0) # r1 = fib(n -1) + sub(r0, r2, 1) + bl(DOFIB) # r0 = fib(n -2) + add(r0, r0, r1) + label(FIBDONE) + pop({r1, r2, lr}) + bx(lr) + label(START) + bl(DOFIB) + + for n in range(10): + print(fib(n)) + +Argument passing and return +--------------------------- + +The tutorial details the fact that assembler functions can support from zero to +three arguments, which must (if used) be named ``r0``, ``r1`` and ``r2``. When +the code executes the registers will be initialised to those values. + +The data types which can be passed in this way are integers and memory +addresses. With current firmware all possible 32 bit values may be passed and +returned. If the return value may have the most significant bit set a Python +type hint should be employed to enable MicroPython to determine whether the +value should be interpreted as a signed or unsigned integer: types are +``int`` or ``uint``. + +:: + + @micropython.asm_thumb + def uadd(r0, r1) -> uint: + add(r0, r0, r1) + +``hex(uadd(0x40000000,0x40000000))`` will return 0x80000000, demonstrating the +passing and return of integers where bits 30 and 31 differ. + +The limitations on the number of arguments and return values can be overcome by means +of the ``array`` module which enables any number of values of any type to be accessed. + +Multiple arguments +~~~~~~~~~~~~~~~~~~ + +If a Python array of integers is passed as an argument to an assembler +function, the function will receive the address of a contiguous set of integers. +Thus multiple arguments can be passed as elements of a single array. Similarly a +function can return multiple values by assigning them to array elements. +Assembler functions have no means of determining the length of an array: +this will need to be passed to the function. + +This use of arrays can be extended to enable more than three arrays to be used. +This is done using indirection: the ``uctypes`` module supports ``addressof()`` +which will return the address of an array passed as its argument. Thus you can +populate an integer array with the addresses of other arrays: + +:: + + from uctypes import addressof + @micropython.asm_thumb + def getindirect(r0): + ldr(r0, [r0, 0]) # Address of array loaded from passed array + ldr(r0, [r0, 4]) # Return element 1 of indirect array (24) + + def testindirect(): + a = array.array('i',[23, 24]) + b = array.array('i',[0,0]) + b[0] = addressof(a) + print(getindirect(b)) + +Non-integer data types +~~~~~~~~~~~~~~~~~~~~~~ + +These may be handled by means of arrays of the appropriate data type. For +example, single precision floating point data may be processed as follows. +This code example takes an array of floats and replaces its contents with +their squares. + +:: + + from array import array + + @micropython.asm_thumb + def square(r0, r1): + label(LOOP) + vldr(s0, [r0, 0]) + vmul(s0, s0, s0) + vstr(s0, [r0, 0]) + add(r0, 4) + sub(r1, 1) + bgt(LOOP) + + a = array('f', (x for x in range(10))) + square(a, len(a)) + print(a) + +The uctypes module supports the use of data structures beyond simple +arrays. It enables a Python data structure to be mapped onto a bytearray +instance which may then be passed to the assembler function. + +Named constants +--------------- + +Assembler code may be made more readable and maintainable by using named +constants rather than littering code with numbers. This may be achieved +thus: + +:: + + MYDATA = const(33) + + @micropython.asm_thumb + def foo(): + mov(r0, MYDATA) + +The const() construct causes MicroPython to replace the variable name +with its value at compile time. If constants are declared in an outer +Python scope they can be shared between multiple assembler functions and +with Python code. + +Assembler code as class methods +------------------------------- + +MicroPython passes the address of the object instance as the first argument +to class methods. This is normally of little use to an assembler function. +It can be avoided by declaring the function as a static method thus: + +:: + + class foo: + @staticmethod + @micropython.asm_thumb + def bar(r0): + add(r0, r0, r0) + +Use of unsupported instructions +------------------------------- + +These can be coded using the data statement as shown below. While +``push()`` and ``pop()`` are supported the example below illustrates the +principle. The necessary machine code may be found in the ARM v7-M +Architecture Reference Manual. Note that the first argument of data +calls such as + +:: + + data(2, 0xe92d, 0x0f00) # push r8,r9,r10,r11 + +indicates that each subsequent argument is a two byte quantity. + +Overcoming MicroPython's integer restriction +-------------------------------------------- + +The Pyboard chip includes a CRC generator. Its use presents a problem in +MicroPython because the returned values cover the full gamut of 32 bit +quantities whereas small integers in MicroPython cannot have differing values +in bits 30 and 31. This limitation is overcome with the following code, which +uses assembler to put the result into an array and Python code to +coerce the result into an arbitrary precision unsigned integer. + +:: + + from array import array + import stm + + def enable_crc(): + stm.mem32[stm.RCC + stm.RCC_AHB1ENR] |= 0x1000 + + def reset_crc(): + stm.mem32[stm.CRC+stm.CRC_CR] = 1 + + @micropython.asm_thumb + def getval(r0, r1): + movwt(r3, stm.CRC + stm.CRC_DR) + str(r1, [r3, 0]) + ldr(r2, [r3, 0]) + str(r2, [r0, 0]) + + def getcrc(value): + a = array('i', [0]) + getval(a, value) + return a[0] & 0xffffffff # coerce to arbitrary precision + + enable_crc() + reset_crc() + for x in range(20): + print(hex(getcrc(0))) diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_index.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_index.rst new file mode 100755 index 0000000..f066e6a --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_index.rst @@ -0,0 +1,73 @@ +.. _asm_thumb2_index: + +Inline Assembler for Thumb2 architectures +========================================= + +This document assumes some familiarity with assembly language programming and should be read after studying +the :ref:`tutorial `. For a detailed description of the instruction set consult the +Architecture Reference Manual detailed below. +The inline assembler supports a subset of the ARM Thumb-2 instruction set described here. The syntax tries +to be as close as possible to that defined in the above ARM manual, converted to Python function calls. + +Instructions operate on 32 bit signed integer data except where stated otherwise. Most supported instructions +operate on registers ``R0-R7`` only: where ``R8-R15`` are supported this is stated. Registers ``R8-R12`` must be +restored to their initial value before return from a function. Registers ``R13-R15`` constitute the Link Register, +Stack Pointer and Program Counter respectively. + +Document conventions +-------------------- + +Where possible the behaviour of each instruction is described in Python, for example + +* add(Rd, Rn, Rm) ``Rd = Rn + Rm`` + +This enables the effect of instructions to be demonstrated in Python. In certain case this is impossible +because Python doesn't support concepts such as indirection. The pseudocode employed in such cases is +described on the relevant page. + +Instruction Categories +---------------------- + +The following sections details the subset of the ARM Thumb-2 instruction set supported by MicroPython. + +.. toctree:: + :maxdepth: 1 + :numbered: + + asm_thumb2_mov.rst + asm_thumb2_ldr.rst + asm_thumb2_str.rst + asm_thumb2_logical_bit.rst + asm_thumb2_arith.rst + asm_thumb2_compare.rst + asm_thumb2_label_branch.rst + asm_thumb2_stack.rst + asm_thumb2_misc.rst + asm_thumb2_float.rst + asm_thumb2_directives.rst + +Usage examples +-------------- + +These sections provide further code examples and hints on the use of the assembler. + +.. toctree:: + :maxdepth: 1 + :numbered: + + asm_thumb2_hints_tips.rst + +References +---------- + +- :ref:`Assembler Tutorial ` +- `Wiki hints and tips + `__ +- `uPy Inline Assembler source-code, + emitinlinethumb.c `__ +- `ARM Thumb2 Instruction Set Quick Reference + Card `__ +- `RM0090 Reference + Manual `__ +- ARM v7-M Architecture Reference Manual (Available on the + ARM site after a simple registration procedure. Also available on academic sites but beware of out of date versions.) diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_label_branch.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_label_branch.rst new file mode 100755 index 0000000..8c85e55 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_label_branch.rst @@ -0,0 +1,85 @@ +Branch instructions +=================== + +These cause execution to jump to a target location usually specified by a label (see the ``label`` +assembler directive). Conditional branches and the ``it`` and ``ite`` instructions test +the Application Program Status Register (APSR) N (negative), Z (zero), C (carry) and V +(overflow) flags to determine whether the branch should be executed. + +Most of the exposed assembler instructions (including move operations) set the flags but +there are explicit comparison instructions to enable values to be tested. + +Further detail on the meaning of the condition flags is provided in the section +describing comparison functions. + +Document conventions +-------------------- + +Notation: ``Rm`` denotes ARM registers R0-R15. ``LABEL`` denotes a label defined with the +``label()`` assembler directive. ```` indicates one of the following condition +specifiers: + +* eq Equal to (result was zero) +* ne Not equal +* cs Carry set +* cc Carry clear +* mi Minus (negative) +* pl Plus (positive) +* vs Overflow set +* vc Overflow clear +* hi > (unsigned comparison) +* ls <= (unsigned comparison) +* ge >= (signed comparison) +* lt < (signed comparison) +* gt > (signed comparison) +* le <= (signed comparison) + +Branch to label +--------------- + +* b(LABEL) Unconditional branch +* beq(LABEL) branch if equal +* bne(LABEL) branch if not equal +* bge(LABEL) branch if greater than or equal +* bgt(LABEL) branch if greater than +* blt(LABEL) branch if less than (<) (signed) +* ble(LABEL) branch if less than or equal to (<=) (signed) +* bcs(LABEL) branch if carry flag is set +* bcc(LABEL) branch if carry flag is clear +* bmi(LABEL) branch if negative +* bpl(LABEL) branch if positive +* bvs(LABEL) branch if overflow flag set +* bvc(LABEL) branch if overflow flag is clear +* bhi(LABEL) branch if higher (unsigned) +* bls(LABEL) branch if lower or equal (unsigned) + +Long branches +------------- + +The code produced by the branch instructions listed above uses a fixed bit width to specify the +branch destination, which is PC relative. Consequently in long programs where the +branch instruction is remote from its destination the assembler will produce a "branch not in +range" error. This can be overcome with the "wide" variants such as + +* beq\_w(LABEL) long branch if equal + +Wide branches use 4 bytes to encode the instruction (compared with 2 bytes for standard branch instructions). + +Subroutines (functions) +----------------------- + +When entering a subroutine the processor stores the return address in register r14, also +known as the link register (lr). Return to the instruction after the subroutine call is +performed by updating the program counter (r15 or pc) from the link register, This +process is handled by the following instructions. + +* bl(LABEL) + +Transfer execution to the instruction after ``LABEL`` storing the return address in +the link register (r14). + +* bx(Rm) Branch to address specified by Rm. + +Typically ``bx(lr)`` is issued to return from a subroutine. For nested subroutines the +link register of outer scopes must be saved (usually on the stack) before performing +inner subroutine calls. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_ldr.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_ldr.rst new file mode 100755 index 0000000..16b7729 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_ldr.rst @@ -0,0 +1,23 @@ +Load register from memory +========================= + +Document conventions +-------------------- + +Notation: ``Rt, Rn`` denote ARM registers R0-R7 except where stated. ``immN`` represents an immediate +value having a width of N bits hence ``imm5`` is constrained to the range 0-31. ``[Rn + immN]`` is the contents +of the memory address obtained by adding Rn and the offset ``immN``. Offsets are measured in +bytes. These instructions affect the condition flags. + +Register Load +------------- + +* ldr(Rt, [Rn, imm7]) ``Rt = [Rn + imm7]`` Load a 32 bit word +* ldrb(Rt, [Rn, imm5]) ``Rt = [Rn + imm5]`` Load a byte +* ldrh(Rt, [Rn, imm6]) ``Rt = [Rn + imm6]`` Load a 16 bit half word + +Where a byte or half word is loaded, it is zero-extended to 32 bits. + +The specified immediate offsets are measured in bytes. Hence in the case of ``ldr`` the 7 bit value +enables 32 bit word aligned values to be accessed with a maximum offset of 31 words. In the case of ``ldrh`` the +6 bit value enables 16 bit half-word aligned values to be accessed with a maximum offset of 31 half-words. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_logical_bit.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_logical_bit.rst new file mode 100755 index 0000000..8c51fea --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_logical_bit.rst @@ -0,0 +1,53 @@ +Logical & Bitwise instructions +============================== + +Document conventions +-------------------- + +Notation: ``Rd, Rn`` denote ARM registers R0-R7 except in the case of the +special instructions where R0-R15 may be used. ``Rn`` denotes an ARM register +whose contents must lie in range ``a <= contents <= b``. In the case of instructions +with two register arguments, it is permissible for them to be identical. For example +the following will zero R0 (Python ``R0 ^= R0``) regardless of its initial contents. + +* eor(r0, r0) + +These instructions affect the condition flags except where stated. + +Logical instructions +-------------------- + +* and\_(Rd, Rn) ``Rd &= Rn`` +* orr(Rd, Rn) ``Rd |= Rn`` +* eor(Rd, Rn) ``Rd ^= Rn`` +* mvn(Rd, Rn) ``Rd = Rn ^ 0xffffffff`` i.e. Rd = 1's complement of Rn +* bic(Rd, Rn) ``Rd &= ~Rn`` bit clear Rd using mask in Rn + +Note the use of "and\_" instead of "and", because "and" is a reserved keyword in Python. + +Shift and rotation instructions +------------------------------- + +* lsl(Rd, Rn<0-31>) ``Rd <<= Rn`` +* lsr(Rd, Rn<1-32>) ``Rd = (Rd & 0xffffffff) >> Rn`` Logical shift right +* asr(Rd, Rn<1-32>) ``Rd >>= Rn`` arithmetic shift right +* ror(Rd, Rn<1-31>) ``Rd = rotate_right(Rd, Rn)`` Rd is rotated right Rn bits. + +A rotation by (for example) three bits works as follows. If Rd initially +contains bits ``b31 b30..b0`` after rotation it will contain ``b2 b1 b0 b31 b30..b3`` + +Special instructions +-------------------- + +Condition codes are unaffected by these instructions. + +* clz(Rd, Rn) ``Rd = count_leading_zeros(Rn)`` + +count_leading_zeros(Rn) returns the number of binary zero bits before the first binary one bit in Rn. + +* rbit(Rd, Rn) ``Rd = bit_reverse(Rn)`` + +bit_reverse(Rn) returns the bit-reversed contents of Rn. If Rn contains bits ``b31 b30..b0`` Rd will be set +to ``b0 b1 b2..b31`` + +Trailing zeros may be counted by performing a bit reverse prior to executing clz. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_misc.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_misc.rst new file mode 100755 index 0000000..ca3f878 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_misc.rst @@ -0,0 +1,13 @@ +Miscellaneous instructions +========================== + +* nop() ``pass`` no operation. +* wfi() Suspend execution in a low power state until an interrupt occurs. +* cpsid(flags) set the Priority Mask Register - disable interrupts. +* cpsie(flags) clear the Priority Mask Register - enable interrupts. +* mrs(Rd, special_reg) ``Rd = special_reg`` copy a special register to a general register. The special register + may be IPSR (Interrupt Status Register) or BASEPRI (Base Priority Register). The IPSR provides a means of determining + the exception number of an interrupt being processed. It contains zero if no interrupt is being processed. + +Currently the ``cpsie()`` and ``cpsid()`` functions are partially implemented. +They require but ignore the flags argument and serve as a means of enabling and disabling interrupts. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_mov.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_mov.rst new file mode 100755 index 0000000..900bf95 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_mov.rst @@ -0,0 +1,27 @@ +Register move instructions +========================== + +Document conventions +-------------------- + +Notation: ``Rd, Rn`` denote ARM registers R0-R15. ``immN`` denotes an immediate +value having a width of N bits. These instructions affect the condition flags. + +Register moves +-------------- + +Where immediate values are used, these are zero-extended to 32 bits. Thus +``mov(R0, 0xff)`` will set R0 to 255. + +* mov(Rd, imm8) ``Rd = imm8`` +* mov(Rd, Rn) ``Rd = Rn`` +* movw(Rd, imm16) ``Rd = imm16`` +* movt(Rd, imm16) ``Rd = (Rd & 0xffff) | (imm16 << 16)`` + +movt writes an immediate value to the top halfword of the destination register. +It does not affect the contents of the bottom halfword. + +* movwt(Rd, imm32) ``Rd = imm32`` + +movwt is a pseudo-instruction: the MicroPython assembler emits a ``movw`` followed +by a ``movt`` to move a 32-bit value into Rd. diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_stack.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_stack.rst new file mode 100755 index 0000000..bffbab2 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_stack.rst @@ -0,0 +1,20 @@ +Stack push and pop +================== + +Document conventions +-------------------- + +The ``push()`` and ``pop()`` instructions accept as their argument a register set containing +a subset, or possibly all, of the general-purpose registers R0-R12 and the link register (lr or R14). +As with any Python set the order in which the registers are specified is immaterial. Thus the +in the following example the pop() instruction would restore R1, R7 and R8 to their contents prior +to the push(): + +* push({r1, r8, r7}) Save three registers on the stack. +* pop({r7, r1, r8}) Restore them + +Stack operations +---------------- + +* push({regset}) Push a set of registers onto the stack +* pop({regset}) Restore a set of registers from the stack diff --git a/src/openmv/src/micropython/docs/reference/asm_thumb2_str.rst b/src/openmv/src/micropython/docs/reference/asm_thumb2_str.rst new file mode 100755 index 0000000..5a88b09 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/asm_thumb2_str.rst @@ -0,0 +1,21 @@ +Store register to memory +======================== + +Document conventions +-------------------- + +Notation: ``Rt, Rn`` denote ARM registers R0-R7 except where stated. ``immN`` represents an immediate +value having a width of N bits hence ``imm5`` is constrained to the range 0-31. ``[Rn + imm5]`` is the +contents of the memory address obtained by adding Rn and the offset ``imm5``. Offsets are measured in +bytes. These instructions do not affect the condition flags. + +Register Store +-------------- + +* str(Rt, [Rn, imm7]) ``[Rn + imm7] = Rt`` Store a 32 bit word +* strb(Rt, [Rn, imm5]) ``[Rn + imm5] = Rt`` Store a byte (b0-b7) +* strh(Rt, [Rn, imm6]) ``[Rn + imm6] = Rt`` Store a 16 bit half word (b0-b15) + +The specified immediate offsets are measured in bytes. Hence in the case of ``str`` the 7 bit value +enables 32 bit word aligned values to be accessed with a maximum offset of 31 words. In the case of ``strh`` the +6 bit value enables 16 bit half-word aligned values to be accessed with a maximum offset of 31 half-words. diff --git a/src/openmv/src/micropython/docs/reference/constrained.rst b/src/openmv/src/micropython/docs/reference/constrained.rst new file mode 100755 index 0000000..edac0ae --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/constrained.rst @@ -0,0 +1,456 @@ +.. _constrained: + +MicroPython on Microcontrollers +=============================== + +MicroPython is designed to be capable of running on microcontrollers. These +have hardware limitations which may be unfamiliar to programmers more familiar +with conventional computers. In particular the amount of RAM and nonvolatile +"disk" (flash memory) storage is limited. This tutorial offers ways to make +the most of the limited resources. Because MicroPython runs on controllers +based on a variety of architectures, the methods presented are generic: in some +cases it will be necessary to obtain detailed information from platform specific +documentation. + +Flash Memory +------------ + +On the Pyboard the simple way to address the limited capacity is to fit a micro +SD card. In some cases this is impractical, either because the device does not +have an SD card slot or for reasons of cost or power consumption; hence the +on-chip flash must be used. The firmware including the MicroPython subsystem is +stored in the onboard flash. The remaining capacity is available for use. For +reasons connected with the physical architecture of the flash memory part of +this capacity may be inaccessible as a filesystem. In such cases this space may +be employed by incorporating user modules into a firmware build which is then +flashed to the device. + +There are two ways to achieve this: frozen modules and frozen bytecode. Frozen +modules store the Python source with the firmware. Frozen bytecode uses the +cross compiler to convert the source to bytecode which is then stored with the +firmware. In either case the module may be accessed with an import statement: + +.. code:: + + import mymodule + +The procedure for producing frozen modules and bytecode is platform dependent; +instructions for building the firmware can be found in the README files in the +relevant part of the source tree. + +In general terms the steps are as follows: + +* Clone the MicroPython `repository `_. +* Acquire the (platform specific) toolchain to build the firmware. +* Build the cross compiler. +* Place the modules to be frozen in a specified directory (dependent on whether + the module is to be frozen as source or as bytecode). +* Build the firmware. A specific command may be required to build frozen + code of either type - see the platform documentation. +* Flash the firmware to the device. + +RAM +--- + +When reducing RAM usage there are two phases to consider: compilation and +execution. In addition to memory consumption, there is also an issue known as +heap fragmentation. In general terms it is best to minimise the repeated +creation and destruction of objects. The reason for this is covered in the +section covering the `heap`_. + +Compilation Phase +~~~~~~~~~~~~~~~~~ + +When a module is imported, MicroPython compiles the code to bytecode which is +then executed by the MicroPython virtual machine (VM). The bytecode is stored +in RAM. The compiler itself requires RAM, but this becomes available for use +when the compilation has completed. + +If a number of modules have already been imported the situation can arise where +there is insufficient RAM to run the compiler. In this case the import +statement will produce a memory exception. + +If a module instantiates global objects on import it will consume RAM at the +time of import, which is then unavailable for the compiler to use on subsequent +imports. In general it is best to avoid code which runs on import; a better +approach is to have initialisation code which is run by the application after +all modules have been imported. This maximises the RAM available to the +compiler. + +If RAM is still insufficient to compile all modules one solution is to +precompile modules. MicroPython has a cross compiler capable of compiling Python +modules to bytecode (see the README in the mpy-cross directory). The resulting +bytecode file has a .mpy extension; it may be copied to the filesystem and +imported in the usual way. Alternatively some or all modules may be implemented +as frozen bytecode: on most platforms this saves even more RAM as the bytecode +is run directly from flash rather than being stored in RAM. + +Execution Phase +~~~~~~~~~~~~~~~ + +There are a number of coding techniques for reducing RAM usage. + +**Constants** + +MicroPython provides a ``const`` keyword which may be used as follows: + +.. code:: + + from micropython import const + ROWS = const(33) + _COLS = const(0x10) + a = ROWS + b = _COLS + +In both instances where the constant is assigned to a variable the compiler +will avoid coding a lookup to the name of the constant by substituting its +literal value. This saves bytecode and hence RAM. However the ``ROWS`` value +will occupy at least two machine words, one each for the key and value in the +globals dictionary. The presence in the dictionary is necessary because another +module might import or use it. This RAM can be saved by prepending the name +with an underscore as in ``_COLS``: this symbol is not visible outside the +module so will not occupy RAM. + +The argument to ``const()`` may be anything which, at compile time, evaluates +to an integer e.g. ``0x100`` or ``1 << 8``. It can even include other const +symbols that have already been defined, e.g. ``1 << BIT``. + +**Constant data structures** + +Where there is a substantial volume of constant data and the platform supports +execution from Flash, RAM may be saved as follows. The data should be located in +Python modules and frozen as bytecode. The data must be defined as `bytes` +objects. The compiler 'knows' that `bytes` objects are immutable and ensures +that the objects remain in flash memory rather than being copied to RAM. The +`ustruct` module can assist in converting between `bytes` types and other +Python built-in types. + +When considering the implications of frozen bytecode, note that in Python +strings, floats, bytes, integers and complex numbers are immutable. Accordingly +these will be frozen into flash. Thus, in the line + +.. code:: + + mystring = "The quick brown fox" + +the actual string "The quick brown fox" will reside in flash. At runtime a +reference to the string is assigned to the *variable* ``mystring``. The reference +occupies a single machine word. In principle a long integer could be used to +store constant data: + +.. code:: + + bar = 0xDEADBEEF0000DEADBEEF + +As in the string example, at runtime a reference to the arbitrarily large +integer is assigned to the variable ``bar``. That reference occupies a +single machine word. + +It might be expected that tuples of integers could be employed for the purpose +of storing constant data with minimal RAM use. With the current compiler this +is ineffective (the code works, but RAM is not saved). + +.. code:: + + foo = (1, 2, 3, 4, 5, 6, 100000) + +At runtime the tuple will be located in RAM. This may be subject to future +improvement. + +**Needless object creation** + +There are a number of situations where objects may unwittingly be created and +destroyed. This can reduce the usability of RAM through fragmentation. The +following sections discuss instances of this. + +**String concatenation** + +Consider the following code fragments which aim to produce constant strings: + +.. code:: + + var = "foo" + "bar" + var1 = "foo" "bar" + var2 = """\ + foo\ + bar""" + +Each produces the same outcome, however the first needlessly creates two string +objects at runtime, allocates more RAM for concatenation before producing the +third. The others perform the concatenation at compile time which is more +efficient, reducing fragmentation. + +Where strings must be dynamically created before being fed to a stream such as +a file it will save RAM if this is done in a piecemeal fashion. Rather than +creating a large string object, create a substring and feed it to the stream +before dealing with the next. + +The best way to create dynamic strings is by means of the string ``format()`` +method: + +.. code:: + + var = "Temperature {:5.2f} Pressure {:06d}\n".format(temp, press) + +**Buffers** + +When accessing devices such as instances of UART, I2C and SPI interfaces, using +pre-allocated buffers avoids the creation of needless objects. Consider these +two loops: + +.. code:: + + while True: + var = spi.read(100) + # process data + + buf = bytearray(100) + while True: + spi.readinto(buf) + # process data in buf + +The first creates a buffer on each pass whereas the second re-uses a pre-allocated +buffer; this is both faster and more efficient in terms of memory fragmentation. + +**Bytes are smaller than ints** + +On most platforms an integer consumes four bytes. Consider the two calls to the +function ``foo()``: + +.. code:: + + def foo(bar): + for x in bar: + print(x) + foo((1, 2, 0xff)) + foo(b'\1\2\xff') + +In the first call a tuple of integers is created in RAM. The second efficiently +creates a `bytes` object consuming the minimum amount of RAM. If the module +were frozen as bytecode, the `bytes` object would reside in flash. + +**Strings Versus Bytes** + +Python3 introduced Unicode support. This introduced a distinction between a +string and an array of bytes. MicroPython ensures that Unicode strings take no +additional space so long as all characters in the string are ASCII (i.e. have +a value < 126). If values in the full 8-bit range are required `bytes` and +`bytearray` objects can be used to ensure that no additional space will be +required. Note that most string methods (e.g. :meth:`str.strip()`) apply also to `bytes` +instances so the process of eliminating Unicode can be painless. + +.. code:: + + s = 'the quick brown fox' # A string instance + b = b'the quick brown fox' # A bytes instance + +Where it is necessary to convert between strings and bytes the :meth:`str.encode` +and the :meth:`bytes.decode` methods can be used. Note that both strings and bytes +are immutable. Any operation which takes as input such an object and produces +another implies at least one RAM allocation to produce the result. In the +second line below a new bytes object is allocated. This would also occur if ``foo`` +were a string. + +.. code:: + + foo = b' empty whitespace' + foo = foo.lstrip() + +**Runtime compiler execution** + +The Python funcitons `eval` and `exec` invoke the compiler at runtime, which +requires significant amounts of RAM. Note that the ``pickle`` library from +`micropython-lib` employs `exec`. It may be more RAM efficient to use the +`ujson` library for object serialisation. + +**Storing strings in flash** + +Python strings are immutable hence have the potential to be stored in read only +memory. The compiler can place in flash strings defined in Python code. As with +frozen modules it is necessary to have a copy of the source tree on the PC and +the toolchain to build the firmware. The procedure will work even if the +modules have not been fully debugged, so long as they can be imported and run. + +After importing the modules, execute: + +.. code:: + + micropython.qstr_info(1) + +Then copy and paste all the Q(xxx) lines into a text editor. Check for and +remove lines which are obviously invalid. Open the file qstrdefsport.h which +will be found in ports/stm32 (or the equivalent directory for the architecture in +use). Copy and paste the corrected lines at the end of the file. Save the file, +rebuild and flash the firmware. The outcome can be checked by importing the +modules and again issuing: + +.. code:: + + micropython.qstr_info(1) + +The Q(xxx) lines should be gone. + +.. _heap: + +The Heap +-------- + +When a running program instantiates an object the necessary RAM is allocated +from a fixed size pool known as the heap. When the object goes out of scope (in +other words becomes inaccessible to code) the redundant object is known as +"garbage". A process known as "garbage collection" (GC) reclaims that memory, +returning it to the free heap. This process runs automatically, however it can +be invoked directly by issuing `gc.collect()`. + +The discourse on this is somewhat involved. For a 'quick fix' issue the +following periodically: + +.. code:: + + gc.collect() + gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) + +Fragmentation +~~~~~~~~~~~~~ + +Say a program creates an object ``foo``, then an object ``bar``. Subsequently +``foo`` goes out of scope but ``bar`` remains. The RAM used by ``foo`` will be +reclaimed by GC. However if ``bar`` was allocated to a higher address, the +RAM reclaimed from ``foo`` will only be of use for objects no bigger than +``foo``. In a complex or long running program the heap can become fragmented: +despite there being a substantial amount of RAM available, there is insufficient +contiguous space to allocate a particular object, and the program fails with a +memory error. + +The techniques outlined above aim to minimise this. Where large permanent buffers +or other objects are required it is best to instantiate these early in the +process of program execution before fragmentation can occur. Further improvements +may be made by monitoring the state of the heap and by controlling GC; these are +outlined below. + +Reporting +~~~~~~~~~ + +A number of library functions are available to report on memory allocation and +to control GC. These are to be found in the `gc` and `micropython` modules. +The following example may be pasted at the REPL (``ctrl e`` to enter paste mode, +``ctrl d`` to run it). + +.. code:: + + import gc + import micropython + gc.collect() + micropython.mem_info() + print('-----------------------------') + print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + def func(): + a = bytearray(10000) + gc.collect() + print('Func definition: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + func() + print('Func run free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + gc.collect() + print('Garbage collect free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + print('-----------------------------') + micropython.mem_info(1) + +Methods employed above: + +* `gc.collect()` Force a garbage collection. See footnote. +* `micropython.mem_info()` Print a summary of RAM utilisation. +* `gc.mem_free()` Return the free heap size in bytes. +* `gc.mem_alloc()` Return the number of bytes currently allocated. +* ``micropython.mem_info(1)`` Print a table of heap utilisation (detailed below). + +The numbers produced are dependent on the platform, but it can be seen that +declaring the function uses a small amount of RAM in the form of bytecode +emitted by the compiler (the RAM used by the compiler has been reclaimed). +Running the function uses over 10KiB, but on return ``a`` is garbage because it +is out of scope and cannot be referenced. The final `gc.collect()` recovers +that memory. + +The final output produced by ``micropython.mem_info(1)`` will vary in detail but +may be interpreted as follows: + +====== ================= +Symbol Meaning +====== ================= + . free block + h head block + = tail block + m marked head block + T tuple + L list + D dict + F float + B byte code + M module +====== ================= + +Each letter represents a single block of memory, a block being 16 bytes. So each +line of the heap dump represents 0x400 bytes or 1KiB of RAM. + +Control of Garbage Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A GC can be demanded at any time by issuing `gc.collect()`. It is advantageous +to do this at intervals, firstly to pre-empt fragmentation and secondly for +performance. A GC can take several milliseconds but is quicker when there is +little work to do (about 1ms on the Pyboard). An explicit call can minimise that +delay while ensuring it occurs at points in the program when it is acceptable. + +Automatic GC is provoked under the following circumstances. When an attempt at +allocation fails, a GC is performed and the allocation re-tried. Only if this +fails is an exception raised. Secondly an automatic GC will be triggered if the +amount of free RAM falls below a threshold. This threshold can be adapted as +execution progresses: + +.. code:: + + gc.collect() + gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) + +This will provoke a GC when more than 25% of the currently free heap becomes +occupied. + +In general modules should instantiate data objects at runtime using constructors +or other initialisation functions. The reason is that if this occurs on +initialisation the compiler may be starved of RAM when subsequent modules are +imported. If modules do instantiate data on import then `gc.collect()` issued +after the import will ameliorate the problem. + +String Operations +----------------- + +MicroPython handles strings in an efficient manner and understanding this can +help in designing applications to run on microcontrollers. When a module +is compiled, strings which occur multiple times are stored once only, a process +known as string interning. In MicroPython an interned string is known as a ``qstr``. +In a module imported normally that single instance will be located in RAM, but +as described above, in modules frozen as bytecode it will be located in flash. + +String comparisons are also performed efficiently using hashing rather than +character by character. The penalty for using strings rather than integers may +hence be small both in terms of performance and RAM usage - a fact which may +come as a surprise to C programmers. + +Postscript +---------- + +MicroPython passes, returns and (by default) copies objects by reference. A +reference occupies a single machine word so these processes are efficient in +RAM usage and speed. + +Where variables are required whose size is neither a byte nor a machine word +there are standard libraries which can assist in storing these efficiently and +in performing conversions. See the `array`, `ustruct` and `uctypes` +modules. + +Footnote: gc.collect() return value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Unix and Windows platforms the `gc.collect()` method returns an integer +which signifies the number of distinct memory regions that were reclaimed in the +collection (more precisely, the number of heads that were turned into frees). For +efficiency reasons bare metal ports do not return this value. diff --git a/src/openmv/src/micropython/docs/reference/glossary.rst b/src/openmv/src/micropython/docs/reference/glossary.rst new file mode 100755 index 0000000..a6abc8b --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/glossary.rst @@ -0,0 +1,155 @@ +Glossary +======== + +.. glossary:: + + baremetal + A system without a (full-fledged) OS, for example an + :term:`MCU`-based system. When running on a baremetal system, + MicroPython effectively becomes its user-facing OS with a command + interpreter (REPL). + + board + A PCB board. Oftentimes, the term is used to denote a particular + model of an :term:`MCU` system. Sometimes, it is used to actually + refer to :term:`MicroPython port` to a particular board (and then + may also refer to "boardless" ports like + :term:`Unix port `). + + callee-owned tuple + A tuple returned by some builtin function/method, containing data + which is valid for a limited time, usually until next call to the + same function (or a group of related functions). After next call, + data in the tuple may be changed. This leads to the following + restriction on the usage of callee-owned tuples - references to + them cannot be stored. The only valid operation is extracting + values from them (including making a copy). Callee-owned tuples + is a MicroPython-specific construct (not available in the general + Python language), introduced for memory allocation optimization. + The idea is that callee-owned tuple is allocated once and stored + on the callee side. Subsequent calls don't require allocation, + allowing to return multiple values when allocation is not possible + (e.g. in interrupt context) or not desirable (because allocation + inherently leads to memory fragmentation). Note that callee-owned + tuples are effectively mutable tuples, making an exception to + Python's rule that tuples are immutable. (It may be interesting + why tuples were used for such a purpose then, instead of mutable + lists - the reason for that is that lists are mutable from user + application side too, so a user could do things to a callee-owned + list which the callee doesn't expect and could lead to problems; + a tuple is protected from this.) + + CPython + CPython is the reference implementation of Python programming + language, and the most well-known one, which most of the people + run. It is however one of many implementations (among which + Jython, IronPython, PyPy, and many more, including MicroPython). + As there is no formal specification of the Python language, only + CPython documentation, it is not always easy to draw a line + between Python the language and CPython its particular + implementation. This however leaves more freedom for other + implementations. For example, MicroPython does a lot of things + differently than CPython, while still aspiring to be a Python + language implementation. + + GPIO + General-purpose input/output. The simplest means to control + electrical signals. With GPIO, user can configure hardware + signal pin to be either input or output, and set or get + its digital signal value (logical "0" or "1"). MicroPython + abstracts GPIO access using :class:`machine.Pin` and :class:`machine.Signal` + classes. + + GPIO port + A group of :term:`GPIO` pins, usually based on hardware + properties of these pins (e.g. controllable by the same + register). + + interned string + A string referenced by its (unique) identity rather than its + address. Interned strings are thus can be quickly compared just + by their identifiers, instead of comparing by content. The + drawbacks of interned strings are that interning operation takes + time (proportional to the number of existing interned strings, + i.e. becoming slower and slower over time) and that the space + used for interned strings is not reclaimable. String interning + is done automatically by MicroPython compiler and runtimer when + it's either required by the implementation (e.g. function keyword + arguments are represented by interned string id's) or deemed + beneficial (e.g. for short enough strings, which have a chance + to be repeated, and thus interning them would save memory on + copies). Most of string and I/O operations don't produce interned + strings due to drawbacks described above. + + MCU + Microcontroller. Microcontrollers usually have much less resources + than a full-fledged computing system, but smaller, cheaper and + require much less power. MicroPython is designed to be small and + optimized enough to run on an average modern microcontroller. + + micropython-lib + MicroPython is (usually) distributed as a single executable/binary + file with just few builtin modules. There is no extensive standard + library comparable with :term:`CPython`. Instead, there is a related, but + separate project + `micropython-lib `_ + which provides implementations for many modules from CPython's + standard library. However, large subset of these modules require + POSIX-like environment (Linux, FreeBSD, MacOS, etc.; Windows may be + partially supported), and thus would work or make sense only with + `MicroPython Unix port`. Some subset of modules is however usable + for `baremetal` ports too. + + Unlike monolithic :term:`CPython` stdlib, micropython-lib modules + are intended to be installed individually - either using manual + copying or using :term:`upip`. + + MicroPython port + MicroPython supports different :term:`boards `, RTOSes, + and OSes, and can be relatively easily adapted to new systems. + MicroPython with support for a particular system is called a + "port" to that system. Different ports may have widely different + functionality. This documentation is intended to be a reference + of the generic APIs available across different ports ("MicroPython + core"). Note that some ports may still omit some APIs described + here (e.g. due to resource constraints). Any such differences, + and port-specific extensions beyond MicroPython core functionality, + would be described in the separate port-specific documentation. + + MicroPython Unix port + Unix port is one of the major :term:`MicroPython ports `. + It is intended to run on POSIX-compatible operating systems, like + Linux, MacOS, FreeBSD, Solaris, etc. It also serves as the basis + of Windows port. The importance of Unix port lies in the fact + that while there are many different :term:`boards `, so + two random users unlikely have the same board, almost all modern + OSes have some level of POSIX compatibility, so Unix port serves + as a kind of "common ground" to which any user can have access. + So, Unix port is used for initial prototyping, different kinds + of testing, development of machine-independent features, etc. + All users of MicroPython, even those which are interested only + in running MicroPython on :term:`MCU` systems, are recommended + to be familiar with Unix (or Windows) port, as it is important + productivity helper and a part of normal MicroPython workflow. + + port + Either :term:`MicroPython port` or :term:`GPIO port`. If not clear + from context, it's recommended to use full specification like one + of the above. + + stream + Also known as a "file-like object". An object which provides sequential + read-write access to the underlying data. A stream object implements + a corresponding interface, which consists of methods like ``read()``, + ``write()``, ``readinto()``, ``seek()``, ``flush()``, ``close()``, etc. + A stream is an important concept in MicroPython, many I/O objects + implement the stream interface, and thus can be used consistently and + interchangeably in different contexts. For more information on + streams in MicroPython, see `uio` module. + + upip + (Literally, "micro pip"). A package manage for MicroPython, inspired + by :term:`CPython`'s pip, but much smaller and with reduced functionality. + upip runs both on :term:`Unix port ` and on + :term:`baremetal` ports (those which offer filesystem and networking + support). diff --git a/src/openmv/src/micropython/docs/reference/index.rst b/src/openmv/src/micropython/docs/reference/index.rst new file mode 100755 index 0000000..d0c7f69 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/index.rst @@ -0,0 +1,28 @@ +The MicroPython language +======================== + +MicroPython aims to implement the Python 3.4 standard (with selected +features from later versions) with respect to language syntax, and most +of the features of MicroPython are identical to those described by the +"Language Reference" documentation at +`docs.python.org `_. + +The MicroPython standard library is described in the +:ref:`corresponding chapter `. The :ref:`cpython_diffs` +chapter describes differences between MicroPython and CPython (which +mostly concern standard library and types, but also some language-level +features). + +This chapter describes features and peculiarities of MicroPython +implementation and the best practices to use them. + +.. toctree:: + :maxdepth: 1 + + glossary.rst + repl.rst + isr_rules.rst + speed_python.rst + constrained.rst + packages.rst + asm_thumb2_index.rst diff --git a/src/openmv/src/micropython/docs/reference/isr_rules.rst b/src/openmv/src/micropython/docs/reference/isr_rules.rst new file mode 100755 index 0000000..dfdee04 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/isr_rules.rst @@ -0,0 +1,382 @@ +.. _isr_rules: + +Writing interrupt handlers +========================== + +On suitable hardware MicroPython offers the ability to write interrupt handlers in Python. Interrupt handlers +- also known as interrupt service routines (ISR's) - are defined as callback functions. These are executed +in response to an event such as a timer trigger or a voltage change on a pin. Such events can occur at any point +in the execution of the program code. This carries significant consequences, some specific to the MicroPython +language. Others are common to all systems capable of responding to real time events. This document covers +the language specific issues first, followed by a brief introduction to real time programming for those new to it. + +This introduction uses vague terms like "slow" or "as fast as possible". This is deliberate, as speeds are +application dependent. Acceptable durations for an ISR are dependent on the rate at which interrupts occur, +the nature of the main program, and the presence of other concurrent events. + +Tips and recommended practices +------------------------------ + +This summarises the points detailed below and lists the principal recommendations for interrupt handler code. + +* Keep the code as short and simple as possible. +* Avoid memory allocation: no appending to lists or insertion into dictionaries, no floating point. +* Consider using ``micropython.schedule`` to work around the above constraint. +* Where an ISR returns multiple bytes use a pre-allocated ``bytearray``. If multiple integers are to be + shared between an ISR and the main program consider an array (``array.array``). +* Where data is shared between the main program and an ISR, consider disabling interrupts prior to accessing + the data in the main program and re-enabling them immediately afterwards (see Critical Sections). +* Allocate an emergency exception buffer (see below). + + +MicroPython Issues +------------------ + +The emergency exception buffer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If an error occurs in an ISR, MicroPython is unable to produce an error report unless a special buffer is created +for the purpose. Debugging is simplified if the following code is included in any program using interrupts. + +.. code:: python + + import micropython + micropython.alloc_emergency_exception_buf(100) + +Simplicity +~~~~~~~~~~ + +For a variety of reasons it is important to keep ISR code as short and simple as possible. It should do only what +has to be done immediately after the event which caused it: operations which can be deferred should be delegated +to the main program loop. Typically an ISR will deal with the hardware device which caused the interrupt, making +it ready for the next interrupt to occur. It will communicate with the main loop by updating shared data to indicate +that the interrupt has occurred, and it will return. An ISR should return control to the main loop as quickly +as possible. This is not a specific MicroPython issue so is covered in more detail :ref:`below `. + +Communication between an ISR and the main program +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Normally an ISR needs to communicate with the main program. The simplest means of doing this is via one or more +shared data objects, either declared as global or shared via a class (see below). There are various restrictions +and hazards around doing this, which are covered in more detail below. Integers, ``bytes`` and ``bytearray`` objects +are commonly used for this purpose along with arrays (from the array module) which can store various data types. + +The use of object methods as callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MicroPython supports this powerful technique which enables an ISR to share instance variables with the underlying +code. It also enables a class implementing a device driver to support multiple device instances. The following +example causes two LED's to flash at different rates. + +.. code:: python + + import pyb, micropython + micropython.alloc_emergency_exception_buf(100) + class Foo(object): + def __init__(self, timer, led): + self.led = led + timer.callback(self.cb) + def cb(self, tim): + self.led.toggle() + + red = Foo(pyb.Timer(4, freq=1), pyb.LED(1)) + green = Foo(pyb.Timer(2, freq=0.8), pyb.LED(2)) + +In this example the ``red`` instance associates timer 4 with LED 1: when a timer 4 interrupt occurs ``red.cb()`` +is called causing LED 1 to change state. The ``green`` instance operates similarly: a timer 2 interrupt +results in the execution of ``green.cb()`` and toggles LED 2. The use of instance methods confers two +benefits. Firstly a single class enables code to be shared between multiple hardware instances. Secondly, as +a bound method the callback function's first argument is ``self``. This enables the callback to access instance +data and to save state between successive calls. For example, if the class above had a variable ``self.count`` +set to zero in the constructor, ``cb()`` could increment the counter. The ``red`` and ``green`` instances would +then maintain independent counts of the number of times each LED had changed state. + +Creation of Python objects +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ISR's cannot create instances of Python objects. This is because MicroPython needs to allocate memory for the +object from a store of free memory block called the heap. This is not permitted in an interrupt handler because +heap allocation is not re-entrant. In other words the interrupt might occur when the main program is part way +through performing an allocation - to maintain the integrity of the heap the interpreter disallows memory +allocations in ISR code. + +A consequence of this is that ISR's can't use floating point arithmetic; this is because floats are Python objects. Similarly +an ISR can't append an item to a list. In practice it can be hard to determine exactly which code constructs will +attempt to perform memory allocation and provoke an error message: another reason for keeping ISR code short and simple. + +One way to avoid this issue is for the ISR to use pre-allocated buffers. For example a class constructor +creates a ``bytearray`` instance and a boolean flag. The ISR method assigns data to locations in the buffer and sets +the flag. The memory allocation occurs in the main program code when the object is instantiated rather than in the ISR. + +The MicroPython library I/O methods usually provide an option to use a pre-allocated buffer. For +example ``pyb.i2c.recv()`` can accept a mutable buffer as its first argument: this enables its use in an ISR. + +A means of creating an object without employing a class or globals is as follows: + +.. code:: python + + def set_volume(t, buf=bytearray(3)): + buf[0] = 0xa5 + buf[1] = t >> 4 + buf[2] = 0x5a + return buf + +The compiler instantiates the default ``buf`` argument when the function is +loaded for the first time (usually when the module it's in is imported). + +An instance of object creation occurs when a reference to a bound method is +created. This means that an ISR cannot pass a bound method to a function. One +solution is to create a reference to the bound method in the class constructor +and to pass that reference in the ISR. For example: + +.. code:: python + + class Foo(): + def __init__(self): + self.bar_ref = self.bar # Allocation occurs here + self.x = 0.1 + tim = pyb.Timer(4) + tim.init(freq=2) + tim.callback(self.cb) + + def bar(self, _): + self.x *= 1.2 + print(self.x) + + def cb(self, t): + # Passing self.bar would cause allocation. + micropython.schedule(self.bar_ref, 0) + +Other techniques are to define and instantiate the method in the constructor +or to pass :meth:`Foo.bar` with the argument *self*. + +Use of Python objects +~~~~~~~~~~~~~~~~~~~~~ + +A further restriction on objects arises because of the way Python works. When an ``import`` statement is executed the +Python code is compiled to bytecode, with one line of code typically mapping to multiple bytecodes. When the code +runs the interpreter reads each bytecode and executes it as a series of machine code instructions. Given that an +interrupt can occur at any time between machine code instructions, the original line of Python code may be only +partially executed. Consequently a Python object such as a set, list or dictionary modified in the main loop +may lack internal consistency at the moment the interrupt occurs. + +A typical outcome is as follows. On rare occasions the ISR will run at the precise moment in time when the object +is partially updated. When the ISR tries to read the object, a crash results. Because such problems typically occur +on rare, random occasions they can be hard to diagnose. There are ways to circumvent this issue, described in +:ref:`Critical Sections ` below. + +It is important to be clear about what constitutes the modification of an object. An alteration to a built-in type +such as a dictionary is problematic. Altering the contents of an array or bytearray is not. This is because bytes +or words are written as a single machine code instruction which is not interruptible: in the parlance of real time +programming the write is atomic. A user defined object might instantiate an integer, array or bytearray. It is valid +for both the main loop and the ISR to alter the contents of these. + +MicroPython supports integers of arbitrary precision. Values between 2**30 -1 and -2**30 will be stored in +a single machine word. Larger values are stored as Python objects. Consequently changes to long integers cannot +be considered atomic. The use of long integers in ISR's is unsafe because memory allocation may be +attempted as the variable's value changes. + +Overcoming the float limitation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In general it is best to avoid using floats in ISR code: hardware devices normally handle integers and conversion +to floats is normally done in the main loop. However there are a few DSP algorithms which require floating point. +On platforms with hardware floating point (such as the Pyboard) the inline ARM Thumb assembler can be used to work +round this limitation. This is because the processor stores float values in a machine word; values can be shared +between the ISR and main program code via an array of floats. + +Using micropython.schedule +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This function enables an ISR to schedule a callback for execution "very soon". The callback is queued for +execution which will take place at a time when the heap is not locked. Hence it can create Python objects +and use floats. The callback is also guaranteed to run at a time when the main program has completed any +update of Python objects, so the callback will not encounter partially updated objects. + +Typical usage is to handle sensor hardware. The ISR acquires data from the hardware and enables it to +issue a further interrupt. It then schedules a callback to process the data. + +Scheduled callbacks should comply with the principles of interrupt handler design outlined below. This is to +avoid problems resulting from I/O activity and the modification of shared data which can arise in any code +which pre-empts the main program loop. + +Execution time needs to be considered in relation to the frequency with which interrupts can occur. If an +interrupt occurs while the previous callback is executing, a further instance of the callback will be queued +for execution; this will run after the current instance has completed. A sustained high interrupt repetition +rate therefore carries a risk of unconstrained queue growth and eventual failure with a ``RuntimeError``. + +If the callback to be passed to `schedule()` is a bound method, consider the +note in "Creation of Python objects". + +Exceptions +---------- + +If an ISR raises an exception it will not propagate to the main loop. The interrupt will be disabled unless the +exception is handled by the ISR code. + +General Issues +-------------- + +This is merely a brief introduction to the subject of real time programming. Beginners should note +that design errors in real time programs can lead to faults which are particularly hard to diagnose. This is because +they can occur rarely and at intervals which are essentially random. It is crucial to get the initial design right and +to anticipate issues before they arise. Both interrupt handlers and the main program need to be designed +with an appreciation of the following issues. + +.. _ISR: + +Interrupt Handler Design +~~~~~~~~~~~~~~~~~~~~~~~~ + +As mentioned above, ISR's should be designed to be as simple as possible. They should always return in a short, +predictable period of time. This is important because when the ISR is running, the main loop is not: inevitably +the main loop experiences pauses in its execution at random points in the code. Such pauses can be a source of hard +to diagnose bugs particularly if their duration is long or variable. In order to understand the implications of +ISR run time, a basic grasp of interrupt priorities is required. + +Interrupts are organised according to a priority scheme. ISR code may itself be interrupted by a higher priority +interrupt. This has implications if the two interrupts share data (see Critical Sections below). If such an interrupt +occurs it interposes a delay into the ISR code. If a lower priority interrupt occurs while the ISR is running, it +will be delayed until the ISR is complete: if the delay is too long, the lower priority interrupt may fail. A +further issue with slow ISR's is the case where a second interrupt of the same type occurs during its execution. +The second interrupt will be handled on termination of the first. However if the rate of incoming interrupts +consistently exceeds the capacity of the ISR to service them the outcome will not be a happy one. + +Consequently looping constructs should be avoided or minimised. I/O to devices other than to the interrupting device +should normally be avoided: I/O such as disk access, ``print`` statements and UART access is relatively slow, and +its duration may vary. A further issue here is that filesystem functions are not reentrant: using filesystem I/O +in an ISR and the main program would be hazardous. Crucially ISR code should not wait on an event. I/O is acceptable +if the code can be guaranteed to return in a predictable period, for example toggling a pin or LED. Accessing the +interrupting device via I2C or SPI may be necessary but the time taken for such accesses should be calculated or +measured and its impact on the application assessed. + +There is usually a need to share data between the ISR and the main loop. This may be done either through global +variables or via class or instance variables. Variables are typically integer or boolean types, or integer or byte +arrays (a pre-allocated integer array offers faster access than a list). Where multiple values are modified by +the ISR it is necessary to consider the case where the interrupt occurs at a time when the main program has +accessed some, but not all, of the values. This can lead to inconsistencies. + +Consider the following design. An ISR stores incoming data in a bytearray, then adds the number of bytes +received to an integer representing total bytes ready for processing. The main program reads the number of bytes, +processes the bytes, then clears down the number of bytes ready. This will work until an interrupt occurs just +after the main program has read the number of bytes. The ISR puts the added data into the buffer and updates +the number received, but the main program has already read the number, so processes the data originally received. +The newly arrived bytes are lost. + +There are various ways of avoiding this hazard, the simplest being to use a circular buffer. If it is not possible +to use a structure with inherent thread safety other ways are described below. + +Reentrancy +~~~~~~~~~~ + +A potential hazard may occur if a function or method is shared between the main program and one or more ISR's or +between multiple ISR's. The issue here is that the function may itself be interrupted and a further instance of +that function run. If this is to occur, the function must be designed to be reentrant. How this is done is an +advanced topic beyond the scope of this tutorial. + +.. _Critical: + +Critical Sections +~~~~~~~~~~~~~~~~~ + +An example of a critical section of code is one which accesses more than one variable which can be affected by an ISR. If +the interrupt happens to occur between accesses to the individual variables, their values will be inconsistent. This is +an instance of a hazard known as a race condition: the ISR and the main program loop race to alter the variables. To +avoid inconsistency a means must be employed to ensure that the ISR does not alter the values for the duration of +the critical section. One way to achieve this is to issue ``pyb.disable_irq()`` before the start of the section, and +``pyb.enable_irq()`` at the end. Here is an example of this approach: + +.. code:: python + + import pyb, micropython, array + micropython.alloc_emergency_exception_buf(100) + + class BoundsException(Exception): + pass + + ARRAYSIZE = const(20) + index = 0 + data = array.array('i', 0 for x in range(ARRAYSIZE)) + + def callback1(t): + global data, index + for x in range(5): + data[index] = pyb.rng() # simulate input + index += 1 + if index >= ARRAYSIZE: + raise BoundsException('Array bounds exceeded') + + tim4 = pyb.Timer(4, freq=100, callback=callback1) + + for loop in range(1000): + if index > 0: + irq_state = pyb.disable_irq() # Start of critical section + for x in range(index): + print(data[x]) + index = 0 + pyb.enable_irq(irq_state) # End of critical section + print('loop {}'.format(loop)) + pyb.delay(1) + + tim4.callback(None) + +A critical section can comprise a single line of code and a single variable. Consider the following code fragment. + +.. code:: python + + count = 0 + def cb(): # An interrupt callback + count +=1 + def main(): + # Code to set up the interrupt callback omitted + while True: + count += 1 + +This example illustrates a subtle source of bugs. The line ``count += 1`` in the main loop carries a specific race +condition hazard known as a read-modify-write. This is a classic cause of bugs in real time systems. In the main loop +MicroPython reads the value of ``t.counter``, adds 1 to it, and writes it back. On rare occasions the interrupt occurs +after the read and before the write. The interrupt modifies ``t.counter`` but its change is overwritten by the main +loop when the ISR returns. In a real system this could lead to rare, unpredictable failures. + +As mentioned above, care should be taken if an instance of a Python built in type is modified in the main code and +that instance is accessed in an ISR. The code performing the modification should be regarded as a critical +section to ensure that the instance is in a valid state when the ISR runs. + +Particular care needs to be taken if a dataset is shared between different ISR's. The hazard here is that the higher +priority interrupt may occur when the lower priority one has partially updated the shared data. Dealing with this +situation is an advanced topic beyond the scope of this introduction other than to note that mutex objects described +below can sometimes be used. + +Disabling interrupts for the duration of a critical section is the usual and simplest way to proceed, but it disables +all interrupts rather than merely the one with the potential to cause problems. It is generally undesirable to disable +an interrupt for long. In the case of timer interrupts it introduces variability to the time when a callback occurs. +In the case of device interrupts, it can lead to the device being serviced too late with possible loss of data or +overrun errors in the device hardware. Like ISR's, a critical section in the main code should have a short, predictable +duration. + +An approach to dealing with critical sections which radically reduces the time for which interrupts are disabled is to +use an object termed a mutex (name derived from the notion of mutual exclusion). The main program locks the mutex +before running the critical section and unlocks it at the end. The ISR tests whether the mutex is locked. If it is, +it avoids the critical section and returns. The design challenge is defining what the ISR should do in the event +that access to the critical variables is denied. A simple example of a mutex may be found +`here `_. Note that the mutex code does disable interrupts, +but only for the duration of eight machine instructions: the benefit of this approach is that other interrupts are +virtually unaffected. + +Interrupts and the REPL +~~~~~~~~~~~~~~~~~~~~~~~ + +Interrupt handlers, such as those associated with timers, can continue to run +after a program terminates. This may produce unexpected results where you might +have expected the object raising the callback to have gone out of scope. For +example on the Pyboard: + +.. code:: python + + def bar(): + foo = pyb.Timer(2, freq=4, callback=lambda t: print('.', end='')) + + bar() + +This continues to run until the timer is explicitly disabled or the board is +reset with ``ctrl D``. diff --git a/src/openmv/src/micropython/docs/reference/packages.rst b/src/openmv/src/micropython/docs/reference/packages.rst new file mode 100755 index 0000000..8be2461 --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/packages.rst @@ -0,0 +1,312 @@ +Distribution packages, package management, and deploying applications +===================================================================== + +Just as the "big" Python, MicroPython supports creation of "third party" +packages, distributing them, and easily installing them in each user's +environment. This chapter discusses how these actions are achieved. +Some familiarity with Python packaging is recommended. + +Overview +-------- + +Steps below represent a high-level workflow when creating and consuming +packages: + +1. Python modules and packages are turned into distribution package + archives, and published at the Python Package Index (PyPI). +2. `upip` package manager can be used to install a distribution package + on a `MicroPython port` with networking capabilities (for example, + on the Unix port). +3. For ports without networking capabilities, an "installation image" + can be prepared on the Unix port, and transferred to a device by + suitable means. +4. For low-memory ports, the installation image can be frozen as the + bytecode into MicroPython executable, thus minimizing the memory + storage overheads. + +The sections below describe this process in details. + +Distribution packages +--------------------- + +Python modules and packages can be packaged into archives suitable for +transfer between systems, storing at the well-known location (PyPI), +and downloading on demand for deployment. These archives are known as +*distribution packages* (to differentiate them from Python packages +(means to organize Python source code)). + +The MicroPython distribution package format is a well-known tar.gz +format, with some adaptations however. The Gzip compressor, used as +an external wrapper for TAR archives, by default uses 32KB dictionary +size, which means that to uncompress a compressed stream, 32KB of +contguous memory needs to be allocated. This requirement may be not +satisfiable on low-memory devices, which may have total memory available +less than that amount, and even if not, a contiguous block like that +may be hard to allocate due to memory fragmentation. To accommodate +these constraints, MicroPython distribution packages use Gzip compression +with the dictionary size of 4K, which should be a suitable compromise +with still achieving some compression while being able to uncompressed +even by the smallest devices. + +Besides the small compression dictionary size, MicroPython distribution +packages also have other optimizations, like removing any files from +the archive which aren't used by the installation process. In particular, +`upip` package manager doesn't execute ``setup.py`` during installation +(see below), and thus that file is not included in the archive. + +At the same time, these optimizations make MicroPython distribution +packages not compatible with `CPython`'s package manager, ``pip``. +This isn't considered a big problem, because: + +1. Packages can be installed with `upip`, and then can be used with + CPython (if they are compatible with it). +2. In the other direction, majority of CPython packages would be + incompatible with MicroPython by various reasons, first of all, + the reliance on features not implemented by MicroPython. + +Summing up, the MicroPython distribution package archives are highly +optimized for MicroPython's target environments, which are highly +resource constrained devices. + + +``upip`` package manager +------------------------ + +MicroPython distribution packages are intended to be installed using +the `upip` package manager. `upip` is a Python application which is +usually distributed (as frozen bytecode) with network-enabled +`MicroPython ports `. At the very least, +`upip` is available in the `MicroPython Unix port`. + +On any `MicroPython port` providing `upip`, it can be accessed as +following:: + + import upip + upip.help() + upip.install(package_or_package_list, [path]) + +Where *package_or_package_list* is the name of a distribution +package to install, or a list of such names to install multiple +packages. Optional *path* parameter specifies filesystem +location to install under and defaults to the standard library +location (see below). + +An example of installing a specific package and then using it:: + + >>> import upip + >>> upip.install("micropython-pystone_lowmem") + [...] + >>> import pystone_lowmem + >>> pystone_lowmem.main() + +Note that the name of Python package and the name of distribution +package for it in general don't have to match, and oftentimes they +don't. This is because PyPI provides a central package repository +for all different Python implementations and versions, and thus +distribution package names may need to be namespaced for a particular +implementation. For example, all packages from `micropython-lib` +follow this naming convention: for a Python module or package named +``foo``, the distribution package name is ``micropython-foo``. + +For the ports which run MicroPython executable from the OS command +prompts (like the Unix port), `upip` can be (and indeed, usually is) +run from the command line instead of MicroPython's own REPL. The +commands which corresponds to the example above are:: + + micropython -m upip -h + micropython -m upip install [-p ] ... + micropython -m upip install micropython-pystone_lowmem + +[TODO: Describe installation path.] + + +Cross-installing packages +------------------------- + +For `MicroPython ports ` without native networking +capabilities, the recommend process is "cross-installing" them into a +"directory image" using the `MicroPython Unix port`, and then +transferring this image to a device by suitable means. + +Installing to a directory image involves using ``-p`` switch to `upip`:: + + micropython -m upip install -p install_dir micropython-pystone_lowmem + +After this command, the package content (and contents of every depenency +packages) will be available in the ``install_dir/`` subdirectory. You +would need to transfer contents of this directory (without the +``install_dir/`` prefix) to the device, at the suitable location, where +it can be found by the Python ``import`` statement (see discussion of +the `upip` installation path above). + + +Cross-installing packages with freezing +--------------------------------------- + +For the low-memory `MicroPython ports `, the process +described in the previous section does not provide the most efficient +resource usage,because the packages are installed in the source form, +so need to be compiled to the bytecome on each import. This compilation +requires RAM, and the resulting bytecode is also stored in RAM, reducing +its amount available for storing application data. Moreover, the process +above requires presence of the filesystem on a device, and the most +resource-constrained devices may not even have it. + +The bytecode freezing is a process which resolves all the issues +mentioned above: + +* The source code is pre-compiled into bytecode and store as such. +* The bytecode is stored in ROM, not RAM. +* Filesystem is not required for frozen packages. + +Using frozen bytecode requires building the executable (firmware) +for a given `MicroPython port` from the C source code. Consequently, +the process is: + +1. Follow the instructions for a particular port on setting up a + toolchain and building the port. For example, for ESP8266 port, + study instructions in ``ports/esp8266/README.md`` and follow them. + Make sure you can build the port and deploy the resulting + executable/firmware successfully before proceeding to the next steps. +2. Build `MicroPython Unix port` and make sure it is in your PATH and + you can execute ``micropython``. +3. Change to port's directory (e.g. ``ports/esp8266/`` for ESP8266). +4. Run ``make clean-frozen``. This step cleans up any previous + modules which were installed for freezing (consequently, you need + to skip this step to add additional modules, instead of starting + from scratch). +5. Run ``micropython -m upip install -p modules ...`` to + install packages you want to freeze. +6. Run ``make clean``. +7. Run ``make``. + +After this, you should have the executable/firmware with modules as +the bytecode inside, which you can deploy the usual way. + +Few notes: + +1. Step 5 in the sequence above assumes that the distribution package + is available from PyPI. If that is not the case, you would need + to copy Python source files manually to ``modules/`` subdirectory + of the port port directory. (Note that upip does not support + installing from e.g. version control repositories). +2. The firmware for baremetal devices usually has size restrictions, + so adding too many frozen modules may overflow it. Usually, you + would get a linking error if this happens. However, in some cases, + an image may be produced, which is not runnable on a device. Such + cases are in general bugs, and should be reported and further + investigated. If you face such a situation, as an initial step, + you may want to decrease the amount of frozen modules included. + + +Creating distribution packages +------------------------------ + +Distribution packages for MicroPython are created in the same manner +as for CPython or any other Python implementation, see references at +the end of chapter. Setuptools (instead of distutils) should be used, +because distutils do not support dependencies and other features. "Source +distribution" (``sdist``) format is used for packaging. The post-processing +discussed above, (and pre-processing discussed in the following section) +is achieved by using custom ``sdist`` command for setuptools. Thus, packaging +steps remain the same as for the standard setuptools, the user just +needs to override ``sdist`` command implementation by passing the +appropriate argument to ``setup()`` call:: + + from setuptools import setup + import sdist_upip + + setup( + ..., + cmdclass={'sdist': sdist_upip.sdist} + ) + +The sdist_upip.py module as referenced above can be found in +`micropython-lib`: +https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py + + +Application resources +--------------------- + +A complete application, besides the source code, oftentimes also consists +of data files, e.g. web page templates, game images, etc. It's clear how +to deal with those when application is installed manually - you just put +those data files in the filesystem at some location and use the normal +file access functions. + +The situation is different when deploying applications from packages - this +is more advanced, streamlined and flexible way, but also requires more +advanced approach to accessing data files. This approach is treating +the data files as "resources", and abstracting away access to them. + +Python supports resource access using its "setuptools" library, using +``pkg_resources`` module. MicroPython, following its usual approach, +implements subset of the functionality of that module, specifically +``pkg_resources.resource_stream(package, resource)`` function. +The idea is that an application calls this function, passing a +resource identifier, which is a relative path to data file within +the specified package (usually top-level application package). It +returns a stream object which can be used to access resource contents. +Thus, the ``resource_stream()`` emulates interface of the standard +`open()` function. + +Implementation-wise, ``resource_stream()`` uses file operations +underlyingly, if distribution package is install in the filesystem. +However, it also supports functioning without the underlying filesystem, +e.g. if the package is frozen as the bytecode. This however requires +an extra intermediate step when packaging application - creation of +"Python resource module". + +The idea of this module is to convert binary data to a Python bytes +object, and put it into the dictionary, indexed by the resource name. +This conversion is done automatically using overridden ``sdist`` command +described in the previous section. + +Let's trace the complete process using the following example. Suppose +your application has the following structure:: + + my_app/ + __main__.py + utils.py + data/ + page.html + image.png + +``__main__.py`` and ``utils.py`` should access resources using the +following calls:: + + import pkg_resources + + pkg_resources.resource_stream(__name__, "data/page.html") + pkg_resources.resource_stream(__name__, "data/image.png") + +You can develop and debug using the `MicroPython Unix port` as usual. +When time comes to make a distribution package out of it, just use +overridden "sdist" command from sdist_upip.py module as described in +the previous section. + +This will create a Python resource module named ``R.py``, based on the +files declared in ``MANIFEST`` or ``MANIFEST.in`` files (any non-``.py`` +file will be considered a resource and added to ``R.py``) - before +proceeding with the normal packaging steps. + +Prepared like this, your application will work both when deployed to +filesystem and as frozen bytecode. + +If you would like to debug ``R.py`` creation, you can run:: + + python3 setup.py sdist --manifest-only + +Alternatively, you can use tools/mpy_bin2res.py script from the +MicroPython distribution, in which can you will need to pass paths +to all resource files:: + + mpy_bin2res.py data/page.html data/image.png + +References +---------- + +* Python Packaging User Guide: https://packaging.python.org/ +* Setuptools documentation: https://setuptools.readthedocs.io/ +* Distutils documentation: https://docs.python.org/3/library/distutils.html diff --git a/src/openmv/src/micropython/docs/reference/repl.rst b/src/openmv/src/micropython/docs/reference/repl.rst new file mode 100755 index 0000000..1eccb9a --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/repl.rst @@ -0,0 +1,212 @@ +The MicroPython Interactive Interpreter Mode (aka REPL) +======================================================= + +This section covers some characteristics of the MicroPython Interactive +Interpreter Mode. A commonly used term for this is REPL (read-eval-print-loop) +which will be used to refer to this interactive prompt. + +Auto-indent +----------- + +When typing python statements which end in a colon (for example if, for, while) +then the prompt will change to three dots (...) and the cursor will be indented +by 4 spaces. When you press return, the next line will continue at the same +level of indentation for regular statements or an additional level of indentation +where appropriate. If you press the backspace key then it will undo one +level of indentation. + +If your cursor is all the way back at the beginning, pressing RETURN will then +execute the code that you've entered. The following shows what you'd see +after entering a for statement (the underscore shows where the cursor winds up): + + >>> for i in range(30): + ... _ + +If you then enter an if statement, an additional level of indentation will be +provided: + + >>> for i in range(30): + ... if i > 3: + ... _ + +Now enter ``break`` followed by RETURN and press BACKSPACE: + + >>> for i in range(30): + ... if i > 3: + ... break + ... _ + +Finally type ``print(i)``, press RETURN, press BACKSPACE and press RETURN again: + + >>> for i in range(30): + ... if i > 3: + ... break + ... print(i) + ... + 0 + 1 + 2 + 3 + >>> + +Auto-indent won't be applied if the previous two lines were all spaces. This +means that you can finish entering a compound statement by pressing RETURN +twice, and then a third press will finish and execute. + +Auto-completion +--------------- + +While typing a command at the REPL, if the line typed so far corresponds to +the beginning of the name of something, then pressing TAB will show +possible things that could be entered. For example, first import the machine +module by entering ``import machine`` and pressing RETURN. +Then type ``m`` and press TAB and it should expand to ``machine``. +Enter a dot ``.`` and press TAB again. You should see something like: + + >>> machine. + __name__ info unique_id reset + bootloader freq rng idle + sleep deepsleep disable_irq enable_irq + Pin + +The word will be expanded as much as possible until multiple possibilities exist. +For example, type ``machine.Pin.AF3`` and press TAB and it will expand to +``machine.Pin.AF3_TIM``. Pressing TAB a second time will show the possible +expansions: + + >>> machine.Pin.AF3_TIM + AF3_TIM10 AF3_TIM11 AF3_TIM8 AF3_TIM9 + >>> machine.Pin.AF3_TIM + +Interrupting a running program +------------------------------ + +You can interrupt a running program by pressing Ctrl-C. This will raise a KeyboardInterrupt +which will bring you back to the REPL, providing your program doesn't intercept the +KeyboardInterrupt exception. + +For example: + + >>> for i in range(1000000): + ... print(i) + ... + 0 + 1 + 2 + 3 + ... + 6466 + 6467 + 6468 + Traceback (most recent call last): + File "", line 2, in + KeyboardInterrupt: + >>> + +Paste Mode +---------- + +If you want to paste some code into your terminal window, the auto-indent feature +will mess things up. For example, if you had the following python code: :: + + def foo(): + print('This is a test to show paste mode') + print('Here is a second line') + foo() + +and you try to paste this into the normal REPL, then you will see something like +this: + + >>> def foo(): + ... print('This is a test to show paste mode') + ... print('Here is a second line') + ... foo() + ... + Traceback (most recent call last): + File "", line 3 + IndentationError: unexpected indent + +If you press Ctrl-E, then you will enter paste mode, which essentially turns off +the auto-indent feature, and changes the prompt from ``>>>`` to ``===``. For example: + + >>> + paste mode; Ctrl-C to cancel, Ctrl-D to finish + === def foo(): + === print('This is a test to show paste mode') + === print('Here is a second line') + === foo() + === + This is a test to show paste mode + Here is a second line + >>> + +Paste Mode allows blank lines to be pasted. The pasted text is compiled as if +it were a file. Pressing Ctrl-D exits paste mode and initiates the compilation. + +Soft Reset +---------- + +A soft reset will reset the python interpreter, but tries not to reset the +method by which you're connected to the MicroPython board (USB-serial, or Wifi). + +You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python +code by executing: :: + + machine.soft_reset() + +For example, if you reset your MicroPython board, and you execute a dir() +command, you'd see something like this: + + >>> dir() + ['__name__', 'pyb'] + +Now create some variables and repeat the dir() command: + + >>> i = 1 + >>> j = 23 + >>> x = 'abc' + >>> dir() + ['j', 'x', '__name__', 'pyb', 'i'] + >>> + +Now if you enter Ctrl-D, and repeat the dir() command, you'll see that your +variables no longer exist: + +.. code-block:: python + + PYB: sync filesystems + PYB: soft reboot + MicroPython v1.5-51-g6f70283-dirty on 2015-10-30; PYBv1.0 with STM32F405RG + Type "help()" for more information. + >>> dir() + ['__name__', 'pyb'] + >>> + +The special variable _ (underscore) +----------------------------------- + +When you use the REPL, you may perform computations and see the results. +MicroPython stores the results of the previous statement in the variable _ (underscore). +So you can use the underscore to save the result in a variable. For example: + + >>> 1 + 2 + 3 + 4 + 5 + 15 + >>> x = _ + >>> x + 15 + >>> + +Raw Mode +-------- + +Raw mode is not something that a person would normally use. It is intended for +programmatic use. It essentially behaves like paste mode with echo turned off. + +Raw mode is entered using Ctrl-A. You then send your python code, followed by +a Ctrl-D. The Ctrl-D will be acknowledged by 'OK' and then the python code will +be compiled and executed. Any output (or errors) will be sent back. Entering +Ctrl-B will leave raw mode and return the the regular (aka friendly) REPL. + +The ``tools/pyboard.py`` program uses the raw REPL to execute python files on the +MicroPython board. + diff --git a/src/openmv/src/micropython/docs/reference/speed_python.rst b/src/openmv/src/micropython/docs/reference/speed_python.rst new file mode 100755 index 0000000..4db60ec --- /dev/null +++ b/src/openmv/src/micropython/docs/reference/speed_python.rst @@ -0,0 +1,342 @@ +Maximising MicroPython Speed +============================ + +.. contents:: + +This tutorial describes ways of improving the performance of MicroPython code. +Optimisations involving other languages are covered elsewhere, namely the use +of modules written in C and the MicroPython inline assembler. + +The process of developing high performance code comprises the following stages +which should be performed in the order listed. + +* Design for speed. +* Code and debug. + +Optimisation steps: + +* Identify the slowest section of code. +* Improve the efficiency of the Python code. +* Use the native code emitter. +* Use the viper code emitter. +* Use hardware-specific optimisations. + +Designing for speed +------------------- + +Performance issues should be considered at the outset. This involves taking a view +on the sections of code which are most performance critical and devoting particular +attention to their design. The process of optimisation begins when the code has +been tested: if the design is correct at the outset optimisation will be +straightforward and may actually be unnecessary. + +Algorithms +~~~~~~~~~~ + +The most important aspect of designing any routine for performance is ensuring that +the best algorithm is employed. This is a topic for textbooks rather than for a +MicroPython guide but spectacular performance gains can sometimes be achieved +by adopting algorithms known for their efficiency. + +RAM Allocation +~~~~~~~~~~~~~~ + +To design efficient MicroPython code it is necessary to have an understanding of the +way the interpreter allocates RAM. When an object is created or grows in size +(for example where an item is appended to a list) the necessary RAM is allocated +from a block known as the heap. This takes a significant amount of time; +further it will on occasion trigger a process known as garbage collection which +can take several milliseconds. + +Consequently the performance of a function or method can be improved if an object is created +once only and not permitted to grow in size. This implies that the object persists +for the duration of its use: typically it will be instantiated in a class constructor +and used in various methods. + +This is covered in further detail :ref:`Controlling garbage collection ` below. + +Buffers +~~~~~~~ + +An example of the above is the common case where a buffer is required, such as one +used for communication with a device. A typical driver will create the buffer in the +constructor and use it in its I/O methods which will be called repeatedly. + +The MicroPython libraries typically provide support for pre-allocated buffers. For +example, objects which support stream interface (e.g., file or UART) provide ``read()`` +method which allocates new buffer for read data, but also a ``readinto()`` method +to read data into an existing buffer. + +Floating Point +~~~~~~~~~~~~~~ + +Some MicroPython ports allocate floating point numbers on heap. Some other ports +may lack dedicated floating-point coprocessor, and perform arithmetic operations +on them in "software" at considerably lower speed than on integers. Where +performance is important, use integer operations and restrict the use of floating +point to sections of the code where performance is not paramount. For example, +capture ADC readings as integers values to an array in one quick go, and only then +convert them to floating-point numbers for signal processing. + +Arrays +~~~~~~ + +Consider the use of the various types of array classes as an alternative to lists. +The `array` module supports various element types with 8-bit elements supported +by Python's built in `bytes` and `bytearray` classes. These data structures all store +elements in contiguous memory locations. Once again to avoid memory allocation in critical +code these should be pre-allocated and passed as arguments or as bound objects. + +When passing slices of objects such as `bytearray` instances, Python creates +a copy which involves allocation of the size proportional to the size of slice. +This can be alleviated using a `memoryview` object. `memoryview` itself +is allocated on heap, but is a small, fixed-size object, regardless of the size +of slice it points too. + +.. code:: python + + ba = bytearray(10000) # big array + func(ba[30:2000]) # a copy is passed, ~2K new allocation + mv = memoryview(ba) # small object is allocated + func(mv[30:2000]) # a pointer to memory is passed + +A `memoryview` can only be applied to objects supporting the buffer protocol - this +includes arrays but not lists. Small caveat is that while memoryview object is live, +it also keeps alive the original buffer object. So, a memoryview isn't a universal +panacea. For instance, in the example above, if you are done with 10K buffer and +just need those bytes 30:2000 from it, it may be better to make a slice, and let +the 10K buffer go (be ready for garbage collection), instead of making a +long-living memoryview and keeping 10K blocked for GC. + +Nonetheless, `memoryview` is indispensable for advanced preallocated buffer +management. ``readinto()`` method discussed above puts data at the beginning +of buffer and fills in entire buffer. What if you need to put data in the +middle of existing buffer? Just create a memoryview into the needed section +of buffer and pass it to ``readinto()``. + +Identifying the slowest section of code +--------------------------------------- + +This is a process known as profiling and is covered in textbooks and +(for standard Python) supported by various software tools. For the type of +smaller embedded application likely to be running on MicroPython platforms +the slowest function or method can usually be established by judicious use +of the timing ``ticks`` group of functions documented in `utime`. +Code execution time can be measured in ms, us, or CPU cycles. + +The following enables any function or method to be timed by adding an +``@timed_function`` decorator: + +.. code:: python + + def timed_function(f, *args, **kwargs): + myname = str(f).split(' ')[1] + def new_func(*args, **kwargs): + t = utime.ticks_us() + result = f(*args, **kwargs) + delta = utime.ticks_diff(utime.ticks_us(), t) + print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000)) + return result + return new_func + +MicroPython code improvements +----------------------------- + +The const() declaration +~~~~~~~~~~~~~~~~~~~~~~~ + +MicroPython provides a ``const()`` declaration. This works in a similar way +to ``#define`` in C in that when the code is compiled to bytecode the compiler +substitutes the numeric value for the identifier. This avoids a dictionary +lookup at runtime. The argument to ``const()`` may be anything which, at +compile time, evaluates to an integer e.g. ``0x100`` or ``1 << 8``. + +.. _Caching: + +Caching object references +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Where a function or method repeatedly accesses objects performance is improved +by caching the object in a local variable: + +.. code:: python + + class foo(object): + def __init__(self): + ba = bytearray(100) + def bar(self, obj_display): + ba_ref = self.ba + fb = obj_display.framebuffer + # iterative code using these two objects + +This avoids the need repeatedly to look up ``self.ba`` and ``obj_display.framebuffer`` +in the body of the method ``bar()``. + +.. _controlling_gc: + +Controlling garbage collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When memory allocation is required, MicroPython attempts to locate an adequately +sized block on the heap. This may fail, usually because the heap is cluttered +with objects which are no longer referenced by code. If a failure occurs, the +process known as garbage collection reclaims the memory used by these redundant +objects and the allocation is then tried again - a process which can take several +milliseconds. + +There may be benefits in pre-empting this by periodically issuing `gc.collect()`. +Firstly doing a collection before it is actually required is quicker - typically on the +order of 1ms if done frequently. Secondly you can determine the point in code +where this time is used rather than have a longer delay occur at random points, +possibly in a speed critical section. Finally performing collections regularly +can reduce fragmentation in the heap. Severe fragmentation can lead to +non-recoverable allocation failures. + +The Native code emitter +----------------------- + +This causes the MicroPython compiler to emit native CPU opcodes rather than +bytecode. It covers the bulk of the MicroPython functionality, so most functions will require +no adaptation (but see below). It is invoked by means of a function decorator: + +.. code:: python + + @micropython.native + def foo(self, arg): + buf = self.linebuf # Cached object + # code + +There are certain limitations in the current implementation of the native code emitter. + +* Context managers are not supported (the ``with`` statement). +* Generators are not supported. +* If ``raise`` is used an argument must be supplied. + +The trade-off for the improved performance (roughly twices as fast as bytecode) is an +increase in compiled code size. + +The Viper code emitter +---------------------- + +The optimisations discussed above involve standards-compliant Python code. The +Viper code emitter is not fully compliant. It supports special Viper native data types +in pursuit of performance. Integer processing is non-compliant because it uses machine +words: arithmetic on 32 bit hardware is performed modulo 2**32. + +Like the Native emitter Viper produces machine instructions but further optimisations +are performed, substantially increasing performance especially for integer arithmetic and +bit manipulations. It is invoked using a decorator: + +.. code:: python + + @micropython.viper + def foo(self, arg: int) -> int: + # code + +As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser. +Type hints provide information on the data types of arguments and of the return value; these +are a standard Python language feature formally defined here `PEP0484 `_. +Viper supports its own set of types namely ``int``, ``uint`` (unsigned integer), ``ptr``, ``ptr8``, +``ptr16`` and ``ptr32``. The ``ptrX`` types are discussed below. Currently the ``uint`` type serves +a single purpose: as a type hint for a function return value. If such a function returns ``0xffffffff`` +Python will interpret the result as 2**32 -1 rather than as -1. + +In addition to the restrictions imposed by the native emitter the following constraints apply: + +* Functions may have up to four arguments. +* Default argument values are not permitted. +* Floating point may be used but is not optimised. + +Viper provides pointer types to assist the optimiser. These comprise + +* ``ptr`` Pointer to an object. +* ``ptr8`` Points to a byte. +* ``ptr16`` Points to a 16 bit half-word. +* ``ptr32`` Points to a 32 bit machine word. + +The concept of a pointer may be unfamiliar to Python programmers. It has similarities +to a Python `memoryview` object in that it provides direct access to data stored in memory. +Items are accessed using subscript notation, but slices are not supported: a pointer can return +a single item only. Its purpose is to provide fast random access to data stored in contiguous +memory locations - such as data stored in objects which support the buffer protocol, and +memory-mapped peripheral registers in a microcontroller. It should be noted that programming +using pointers is hazardous: bounds checking is not performed and the compiler does nothing to +prevent buffer overrun errors. + +Typical usage is to cache variables: + +.. code:: python + + @micropython.viper + def foo(self, arg: int) -> int: + buf = ptr8(self.linebuf) # self.linebuf is a bytearray or bytes object + for x in range(20, 30): + bar = buf[x] # Access a data item through the pointer + # code omitted + +In this instance the compiler "knows" that ``buf`` is the address of an array of bytes; +it can emit code to rapidly compute the address of ``buf[x]`` at runtime. Where casts are +used to convert objects to Viper native types these should be performed at the start of +the function rather than in critical timing loops as the cast operation can take several +microseconds. The rules for casting are as follows: + +* Casting operators are currently: ``int``, ``bool``, ``uint``, ``ptr``, ``ptr8``, ``ptr16`` and ``ptr32``. +* The result of a cast will be a native Viper variable. +* Arguments to a cast can be a Python object or a native Viper variable. +* If argument is a native Viper variable, then cast is a no-op (i.e. costs nothing at runtime) + that just changes the type (e.g. from ``uint`` to ``ptr8``) so that you can then store/load + using this pointer. +* If the argument is a Python object and the cast is ``int`` or ``uint``, then the Python object + must be of integral type and the value of that integral object is returned. +* The argument to a bool cast must be integral type (boolean or integer); when used as a return + type the viper function will return True or False objects. +* If the argument is a Python object and the cast is ``ptr``, ``ptr``, ``ptr16`` or ``ptr32``, + then the Python object must either have the buffer protocol with read-write capabilities + (in which case a pointer to the start of the buffer is returned) or it must be of integral + type (in which case the value of that integral object is returned). + +The following example illustrates the use of a ``ptr16`` cast to toggle pin X1 ``n`` times: + +.. code:: python + + BIT0 = const(1) + @micropython.viper + def toggle_n(n: int): + odr = ptr16(stm.GPIOA + stm.GPIO_ODR) + for _ in range(n): + odr[0] ^= BIT0 + +A detailed technical description of the three code emitters may be found +on Kickstarter here `Note 1 `_ +and here `Note 2 `_ + +Accessing hardware directly +--------------------------- + +.. note:: + + Code examples in this section are given for the Pyboard. The techniques + described however may be applied to other MicroPython ports too. + +This comes into the category of more advanced programming and involves some knowledge +of the target MCU. Consider the example of toggling an output pin on the Pyboard. The +standard approach would be to write + +.. code:: python + + mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin + +This involves the overhead of two calls to the :class:`~machine.Pin` instance's :meth:`~machine.Pin.value()` +method. This overhead can be eliminated by performing a read/write to the relevant bit +of the chip's GPIO port output data register (odr). To facilitate this the ``stm`` +module provides a set of constants providing the addresses of the relevant registers. +A fast toggle of pin ``P4`` (CPU pin ``A14``) - corresponding to the green LED - +can be performed as follows: + +.. code:: python + + import machine + import stm + + BIT14 = const(1 << 14) + machine.mem16[stm.GPIOA + stm.GPIO_ODR] ^= BIT14 diff --git a/src/openmv/src/micropython/docs/static/customstyle.css b/src/openmv/src/micropython/docs/static/customstyle.css new file mode 100755 index 0000000..74eff4e --- /dev/null +++ b/src/openmv/src/micropython/docs/static/customstyle.css @@ -0,0 +1,10 @@ +/* custom CSS for MicroPython docs + */ + +.admonition-difference-to-cpython { + border: 1px solid black; +} + +.admonition-difference-to-cpython .admonition-title { + margin: 4px; +} diff --git a/src/openmv/src/micropython/docs/static/favicon.ico b/src/openmv/src/micropython/docs/static/favicon.ico new file mode 100755 index 0000000..49c6154 Binary files /dev/null and b/src/openmv/src/micropython/docs/static/favicon.ico differ diff --git a/src/openmv/src/micropython/docs/templates/layout.html b/src/openmv/src/micropython/docs/templates/layout.html new file mode 100755 index 0000000..a6caa0b --- /dev/null +++ b/src/openmv/src/micropython/docs/templates/layout.html @@ -0,0 +1,6 @@ +{% extends "!layout.html" %} +{% set css_files = css_files + ["_static/customstyle.css"] %} + +{# we change the master_doc variable so that links to the index + page are to index.html instead of _index.html #} +{% set master_doc = "index" %} diff --git a/src/openmv/src/micropython/docs/templates/replace.inc b/src/openmv/src/micropython/docs/templates/replace.inc new file mode 100755 index 0000000..319c537 --- /dev/null +++ b/src/openmv/src/micropython/docs/templates/replace.inc @@ -0,0 +1,9 @@ +.. comment: This file is intended for global "replace" definitions. + +.. |see_cpython| replace:: See CPython documentation: + +.. |see_cpython_module| replace:: + + *This module implements a subset of the corresponding* `CPython` *module, + as described below. For more information, refer to the original + CPython documentation:* diff --git a/src/openmv/src/micropython/docs/templates/topindex.html b/src/openmv/src/micropython/docs/templates/topindex.html new file mode 100755 index 0000000..675fae2 --- /dev/null +++ b/src/openmv/src/micropython/docs/templates/topindex.html @@ -0,0 +1,109 @@ +{% extends "defindex.html" %} +{% block body %} + +

MicroPython documentation

+ +

+ {{ _('Welcome! This is the documentation for MicroPython') }} + v{{ release|e }}{% if last_updated %}, {{ _('last updated') }} {{ last_updated|e }}{% endif %}. +

+ +

+ MicroPython runs on a variety of systems and hardware platforms. Here you can read + the general documentation which applies to all systems, as well as specific information + about the various platforms - + also known as ports + - that MicroPython runs on. +

+ +

General documentation for MicroPython:

+ + + + +
+ + + + + +
+ +

References and tutorials for specific platforms:

+ + + +
+ + + +
+ +

Indices and tables:

+ + + + +
+ + + + + +
+ +

External links:

+ + + + +
+ + + + +
+ +{% endblock %} diff --git a/src/openmv/src/micropython/docs/templates/versions.html b/src/openmv/src/micropython/docs/templates/versions.html new file mode 100755 index 0000000..80b9b0f --- /dev/null +++ b/src/openmv/src/micropython/docs/templates/versions.html @@ -0,0 +1,31 @@ +
+ + Versions and Downloads + {{ cur_version }} + + +
+
+
Versions
+ {% for slug, url in all_versions %} +
{{ slug }}
+ {% endfor %} +
+
+
Downloads
+ {% for type, url in downloads %} +
{{ type }}
+ {% endfor %} +
+
+
+
External links
+
+ micropython.org +
+
+ GitHub +
+
+
+
diff --git a/src/openmv/src/micropython/docs/wipy/general.rst b/src/openmv/src/micropython/docs/wipy/general.rst new file mode 100755 index 0000000..4dfab9c --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/general.rst @@ -0,0 +1,387 @@ +.. _wipy_general: + +General information about the WiPy +================================== + +No floating point support +------------------------- + +Due to space reasons, there's no floating point support, and no math module. This +means that floating point numbers cannot be used anywhere in the code, and that +all divisions must be performed using '//' instead of '/'. Example:: + + >>> r = 4 // 2 # this will work + >>> r = 4 / 2 # this WON'T + +Before applying power +--------------------- + +.. warning:: + + The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higher + than 3.6V will cause irreparable damage to the board. ADC pins, when configured + in analog mode cannot withstand voltages above 1.8V. Keep these considerations in + mind when wiring your electronics. + +WLAN default behaviour +---------------------- + +When the WiPy boots with the default factory configuration starts in Access Point +mode with ``ssid`` that starts with: ``wipy-wlan`` and ``key: www.wipy.io``. +Connect to this network and the WiPy will be reachable at ``192.168.1.1``. In order +to gain access to the interactive prompt, open a telnet session to that IP address on +the default port (23). You will be asked for credentials: +``login: micro`` and ``password: python`` + +.. _wipy_telnet: + +Telnet REPL +----------- + +Linux stock telnet works like a charm (also on OSX), but other tools like putty +work quite well too. The default credentials are: **user:** ``micro``, **password:** ``python``. +See :class:`network.Server` for info on how to change the defaults. +For instance, on a linux shell (when connected to the WiPy in AP mode):: + + $ telnet 192.168.1.1 + +.. _wipy_filesystem: + +Local file system and FTP access +-------------------------------- + +There is a small internal file system (a drive) on the WiPy, called ``/flash``, +which is stored within the external serial flash memory. If a micro SD card +is hooked-up and mounted, it will be available as well. + +When the WiPy starts up, it always boots from the ``boot.py`` located in the +``/flash`` file system. On boot up, the current directory is ``/flash``. + +The file system is accessible via the native FTP server running in the WiPy. +Open your FTP client of choice and connect to: + +**url:** ``ftp://192.168.1.1``, **user:** ``micro``, **password:** ``python`` + +See :class:`network.Server` for info on how to change the defaults. +The recommended clients are: Linux stock FTP (also in OSX), Filezilla and FireFTP. +For example, on a linux shell:: + + $ ftp 192.168.1.1 + +The FTP server on the WiPy doesn't support active mode, only passive, therefore, +if using the native unix ftp client, just after logging in do:: + + ftp> passive + +Besides that, the FTP server only supports one data connection at a time. Check out +the Filezilla settings section below for more info. + +FileZilla settings +------------------ +Do not use the quick connect button, instead, open the site manager and create a new +configuration. In the ``General`` tab make sure that encryption is set to: ``Only use +plain FTP (insecure)``. In the Transfer Settings tab limit the max number of connections +to one, otherwise FileZilla will try to open a second command connection when retrieving +and saving files, and for simplicity and to reduce code size, only one command and one +data connections are possible. Other FTP clients might behave in a similar way. + +.. _wipy_firmware_upgrade: + +Upgrading the firmware Over The Air +----------------------------------- + +OTA software updates can be performed through the FTP server. Upload the ``mcuimg.bin`` file +to: ``/flash/sys/mcuimg.bin`` it will take around 6s. You won't see the file being stored +inside ``/flash/sys/`` because it's actually saved bypassing the user file system, so it +ends up inside the internal **hidden** file system, but rest assured that it was successfully +transferred, and it has been signed with a MD5 checksum to verify its integrity. Now, reset +the WiPy by pressing the switch on the board, or by typing:: + + >>> import machine + >>> machine.reset() + +Software updates can be found in: https://github.com/wipy/wipy/releases (**Binaries.zip**). +It's always recommended to update to the latest software, but make sure to +read the **release notes** before. + +.. note:: + + The ``bootloader.bin`` found inside ``Binaries.zip`` is there only for reference, it's not + needed for the Over The Air update. + +In order to check your software version, do:: + + >>> import os + >>> os.uname().release + +If the version number is lower than the latest release found in +`the releases `_, go ahead and update your WiPy! + + +.. _wipy_boot_modes: + +Boot modes and safe boot +------------------------ + +If you power up normally, or press the reset button, the WiPy will boot +into standard mode; the ``boot.py`` file will be executed first, then +``main.py`` will run. + +You can override this boot sequence by pulling ``GP28`` **up** (connect +it to the 3v3 output pin) during reset. This procedure also allows going +back in time to old firmware versions. The WiPy can hold up to 3 different +firmware versions, which are: the factory firmware plus 2 user updates. + +After reset, if ``GP28`` is held high, the heartbeat LED will start flashing +slowly, if after 3 seconds the pin is still being held high, the LED will start +blinking a bit faster and the WiPy will select the previous user update to boot. +If the previous user update is the desired firmware image, ``GP28`` must be +released before 3 more seconds elapse. If 3 seconds later the pin is still high, +the factory firmware will be selected, the LED will flash quickly for 1.5 seconds +and the WiPy will proceed to boot. The firmware selection mechanism is as follows: + + +**Safe Boot Pin** ``GP28`` **released during:** + ++-------------------------+-------------------------+----------------------------+ +| 1st 3 secs window | 2nd 3 secs window | Final 1.5 secs window | ++=========================+=========================+============================+ +| | Safe boot, *latest* | | Safe boot, *previous* | | Safe boot, the *factory* | +| | firmware is selected | | user update selected | | firmware is selected | ++-------------------------+-------------------------+----------------------------+ + +On all of the above 3 scenarios, safe boot mode is entered, meaning that +the execution of both ``boot.py`` and ``main.py`` is skipped. This is +useful to recover from crash situations caused by the user scripts. The selection +made during safe boot is not persistent, therefore after the next normal reset +the latest firmware will run again. + +The heartbeat LED +------------------ + +By default the heartbeat LED flashes once every 4s to signal that the system is +alive. This can be overridden through the :mod:`wipy` module:: + + >>> import wipy + >>> wipy.heartbeat(False) + +There are currently 2 kinds of errors that you might see: + +1. If the heartbeat LED flashes quickly, then a Python script (eg ``main.py``) + has an error. Use the REPL to debug it. +2. If the heartbeat LED stays on, then there was a hard fault, you cannot + recover from this, the only way out is to press the reset switch. + +Details on sleep modes +---------------------- + +* ``machine.idle()``: Power consumption: ~12mA (in WLAN STA mode). Wake sources: + any hardware interrupt (including systick with period of 1ms), no special + configuration required. +* ``machine.sleep()``: 950uA (in WLAN STA mode). Wake sources are ``Pin``, ``RTC`` + and ``WLAN`` +* ``machine.deepsleep()``: ~350uA. Wake sources are ``Pin`` and ``RTC``. + +Additional details for machine.Pin +---------------------------------- + +On the WiPy board the pins are identified by their string id:: + + from machine import Pin + g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1) + +You can also configure the Pin to generate interrupts. For instance:: + + from machine import Pin + + def pincb(pin): + print(pin.id()) + + pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN) + pin_int.irq(trigger=Pin.IRQ_RISING, handler=pincb) + # the callback can be triggered manually + pin_int.irq()() + # to disable the callback + pin_int.irq().disable() + +Now every time a falling edge is seen on the gpio pin, the callback will be +executed. Caution: mechanical push buttons have "bounce" and pushing or +releasing a switch will often generate multiple edges. +See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed +explanation, along with various techniques for debouncing. + +All pin objects go through the pin mapper to come up with one of the +gpio pins. + +For the ``drive`` parameter the strengths are: + + - ``Pin.LOW_POWER`` - 2mA drive capability. + - ``Pin.MED_POWER`` - 4mA drive capability. + - ``Pin.HIGH_POWER`` - 6mA drive capability. + +For the ``alt`` parameter please refer to the pinout and alternate functions +table at `_ +for the specific alternate functions that each pin supports. + +For interrupts, the ``priority`` can take values in the range 1-7. And the +``wake`` parameter has the following properties: + + - If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board. + - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, + ``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1 + of this pins can be enabled as a wake source at the same time, so, only + the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect. + - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, + ``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the + 6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time. + +Additional Pin methods: + +.. method:: machine.Pin.alt_list() + + Returns a list of the alternate functions supported by the pin. List items are + a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)`` + +Additional details for machine.I2C +---------------------------------- + +On the WiPy there is a single hardware I2C peripheral, identified by "0". By +default this is the peripheral that is used when constructing an I2C instance. +The default pins are GP23 for SCL and GP13 for SDA, and one can create the +default I2C peripheral simply by doing:: + + i2c = machine.I2C() + +The pins and frequency can be specified as:: + + i2c = machine.I2C(freq=400000, scl='GP23', sda='GP13') + +Only certain pins can be used as SCL/SDA. Please refer to the pinout for further +information. + +Known issues +------------ + +Incompatible way to create SSL sockets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +SSL sockets need to be created the following way before wrapping them with. +``ssl.wrap_socket``:: + + import socket + import ssl + s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) + ss = ssl.wrap_socket(s) + +Certificates must be used in order to validate the other side of the connection, and also to +authenticate ourselves with the other end. Such certificates must be stored as files using the +FTP server, and they must be placed in specific paths with specific names. + +- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'** +- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'** +- The key for our own certificate goes in: **'/flash/cert/private.key'** + +.. note:: + + When these files are stored, they are placed inside the internal **hidden** file system + (just like firmware updates), and therefore they are never visible. + +For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located +in the `blynk examples folder `_. +and put it in '/flash/cert/'. Then do:: + + import socket + import ssl + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) + ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem') + ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1]) + +Incompatibilities in uhashlib module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Due to hardware implementation details of the WiPy, data must be buffered before being +digested, which would make it impossible to calculate the hash of big blocks of data that +do not fit in RAM. In this case, since most likely the total size of the data is known +in advance, the size can be passed to the constructor and hence the HASH hardware engine +of the WiPy can be properly initialized without needing buffering. If ``block_size`` is +to be given, an initial chunk of ``data`` must be passed as well. **When using this extension, +care must be taken to make sure that the length of all intermediate chunks (including the +initial one) is a multiple of 4 bytes.** The last chunk may be of any length. + +Example:: + + hash = uhashlib.sha1('abcd1234', 1001) # length of the initial piece is multiple of 4 bytes + hash.update('1234') # also multiple of 4 bytes + ... + hash.update('12345') # last chunk may be of any length + hash.digest() + +Unrelated function in machine module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. function:: main(filename) + + Set the filename of the main script to run after boot.py is finished. If + this function is not called then the default file main.py will be executed. + + It only makes sense to call this function from within boot.py. + +Adhoc way to control telnet/FTP server via network module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Server`` class controls the behaviour and the configuration of the FTP and telnet +services running on the WiPy. Any changes performed using this class' methods will +affect both. + +Example:: + + import network + server = network.Server() + server.deinit() # disable the server + # enable the server again with new settings + server.init(login=('user', 'password'), timeout=600) + +.. class:: network.Server(id, ...) + + Create a server instance, see ``init`` for parameters of initialization. + +.. method:: server.init(\*, login=('micro', 'python'), timeout=300) + + Init (and effectively start the server). Optionally a new ``user``, ``password`` + and ``timeout`` (in seconds) can be passed. + +.. method:: server.deinit() + + Stop the server + +.. method:: server.timeout([timeout_in_seconds]) + + Get or set the server timeout. + +.. method:: server.isrunning() + + Returns ``True`` if the server is running, ``False`` otherwise. + +Adhoc VFS-like support +~~~~~~~~~~~~~~~~~~~~~~ + +WiPy doesn't implement full MicroPython VFS support, instead following +functions are defined in ``uos`` module: + +.. function:: mount(block_device, mount_point, \*, readonly=False) + + Mounts a block device (like an ``SD`` object) in the specified mount + point. Example:: + + os.mount(sd, '/sd') + +.. function:: unmount(path) + + Unmounts a previously mounted block device from the given path. + +.. function:: mkfs(block_device or path) + + Formats the specified path, must be either ``/flash`` or ``/sd``. + A block device can also be passed like an ``SD`` object before + being mounted. + diff --git a/src/openmv/src/micropython/docs/wipy/quickref.rst b/src/openmv/src/micropython/docs/wipy/quickref.rst new file mode 100755 index 0000000..1f34bda --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/quickref.rst @@ -0,0 +1,227 @@ +.. _wipy_quickref: + +Quick reference for the WiPy +============================ + +.. image:: https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png + :alt: WiPy pinout and alternate functions table + :width: 800px + +Below is a quick reference for CC3200/WiPy. If it is your first time +working with this board please consider reading the following sections first: + +.. toctree:: + :maxdepth: 1 + + general.rst + tutorial/index.rst + +General board control (including sleep modes) +--------------------------------------------- + +See the :mod:`machine` module:: + + import machine + + help(machine) # display all members from the machine module + machine.freq() # get the CPU frequency + machine.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address) + + machine.idle() # average current decreases to (~12mA), any interrupts wake it up + machine.sleep() # everything except for WLAN is powered down (~950uA avg. current) + # wakes from Pin, RTC or WLAN + machine.deepsleep() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC. + +Pins and GPIO +------------- + +See :ref:`machine.Pin `. :: + + from machine import Pin + + # initialize GP2 in gpio mode (alt=0) and make it an output + p_out = Pin('GP2', mode=Pin.OUT) + p_out.value(1) + p_out.value(0) + p_out.toggle() + p_out(True) + + # make GP1 an input with the pull-up enabled + p_in = Pin('GP1', mode=Pin.IN, pull=Pin.PULL_UP) + p_in() # get value, 0 or 1 + +Timers +------ + +See :ref:`machine.TimerWiPy ` and :ref:`machine.Pin `. +Timer ``id``'s take values from 0 to 3.:: + + from machine import Timer + from machine import Pin + + tim = Timer(0, mode=Timer.PERIODIC) + tim_a = tim.channel(Timer.A, freq=1000) + tim_a.freq(5) # 5 Hz + + p_out = Pin('GP2', mode=Pin.OUT) + tim_a.irq(trigger=Timer.TIMEOUT, handler=lambda t: p_out.toggle()) + +PWM (pulse width modulation) +---------------------------- + +See :ref:`machine.Pin ` and :ref:`machine.Timer `. :: + + from machine import Timer + + # timer 1 in PWM mode and width must be 16 buts + tim = Timer(1, mode=Timer.PWM, width=16) + + # enable channel A @1KHz with a 50.55% duty cycle + tim_a = tim.channel(Timer.A, freq=1000, duty_cycle=5055) + +ADC (analog to digital conversion) +---------------------------------- + +See :ref:`machine.ADC `. :: + + from machine import ADC + + adc = ADC() + apin = adc.channel(pin='GP3') + apin() # read value, 0-4095 + +UART (serial bus) +----------------- + +See :ref:`machine.UART `. :: + + from machine import UART + uart = UART(0, baudrate=9600) + uart.write('hello') + uart.read(5) # read up to 5 bytes + +SPI bus +------- + +See :ref:`machine.SPI `. :: + + from machine import SPI + + # configure the SPI master @ 2MHz + spi = SPI(0, SPI.MASTER, baudrate=200000, polarity=0, phase=0) + spi.write('hello') + spi.read(5) # receive 5 bytes on the bus + rbuf = bytearray(5) + spi.write_readinto('hello', rbuf) # send and receive 5 bytes + +I2C bus +------- + +See :ref:`machine.I2C `. :: + + from machine import I2C + # configure the I2C bus + i2c = I2C(baudrate=100000) + i2c.scan() # returns list of slave addresses + i2c.writeto(0x42, 'hello') # send 5 bytes to slave with address 0x42 + i2c.readfrom(0x42, 5) # receive 5 bytes from slave + i2c.readfrom_mem(0x42, 0x10, 2) # read 2 bytes from slave 0x42, slave memory 0x10 + i2c.writeto_mem(0x42, 0x10, 'xy') # write 2 bytes to slave 0x42, slave memory 0x10 + +Watchdog timer (WDT) +-------------------- + +See :ref:`machine.WDT `. :: + + from machine import WDT + + # enable the WDT with a timeout of 5s (1s is the minimum) + wdt = WDT(timeout=5000) + wdt.feed() + +Real time clock (RTC) +--------------------- + +See :ref:`machine.RTC ` :: + + from machine import RTC + + rtc = RTC() # init with default time and date + rtc = RTC(datetime=(2015, 8, 29, 9, 0, 0, 0, None)) # init with a specific time and date + print(rtc.now()) + + def alarm_handler (rtc_o): + pass + # do some non blocking operations + # warning printing on an irq via telnet is not + # possible, only via UART + + # create a RTC alarm that expires after 5 seconds + rtc.alarm(time=5000, repeat=False) + + # enable RTC interrupts + rtc_i = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP) + + # go into suspended mode waiting for the RTC alarm to expire and wake us up + machine.sleep() + +SD card +------- + +See :ref:`machine.SD `. :: + + from machine import SD + import os + + # clock pin, cmd pin, data0 pin + sd = SD(pins=('GP10', 'GP11', 'GP15')) + # or use default ones for the expansion board + sd = SD() + os.mount(sd, '/sd') + +WLAN (WiFi) +----------- + +See :ref:`network.WLAN ` and :mod:`machine`. :: + + import machine + from network import WLAN + + # configure the WLAN subsystem in station mode (the default is AP) + wlan = WLAN(mode=WLAN.STA) + # go for fixed IP settings + wlan.ifconfig(config=('192.168.0.107', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + wlan.scan() # scan for available networks + wlan.connect(ssid='mynetwork', auth=(WLAN.WPA2, 'mynetworkkey')) + while not wlan.isconnected(): + pass + print(wlan.ifconfig()) + # enable wake on WLAN + wlan.irq(trigger=WLAN.ANY_EVENT, wake=machine.SLEEP) + # go to sleep + machine.sleep() + # now, connect to the FTP or the Telnet server and the WiPy will wake-up + +Telnet and FTP server +--------------------- + +See :class:`network.Server` :: + + from network import Server + + # init with new user, password and seconds timeout + server = Server(login=('user', 'password'), timeout=60) + server.timeout(300) # change the timeout + server.timeout() # get the timeout + server.isrunning() # check whether the server is running or not + +Heart beat LED +-------------- + +See :mod:`wipy`. :: + + import wipy + + wipy.heartbeat(False) # disable the heartbeat LED + wipy.heartbeat(True) # enable the heartbeat LED + wipy.heartbeat() # get the heartbeat state diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/blynk.rst b/src/openmv/src/micropython/docs/wipy/tutorial/blynk.rst new file mode 100755 index 0000000..b5a2f24 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/blynk.rst @@ -0,0 +1,19 @@ +Getting started with Blynk and the WiPy +--------------------------------------- + +Blynk is a platform with iOS and Android apps to control +Arduino, Raspberry Pi and the likes over the Internet. +You can easily build graphic interfaces for all your +projects by simply dragging and dropping widgets. + +There are several examples available that work out-of-the-box with +the WiPy. Before anything else, make sure that your WiPy is running +the latest software, check :ref:`OTA How-To ` for instructions. + +1. Get the `Blynk library `_ and put it in ``/flash/lib/`` via FTP. +2. Get the `Blynk examples `_, edit the network settings, and afterwards + upload them to ``/flash/lib/`` via FTP as well. +3. Follow the instructions on each example to setup the Blynk dashboard on your smartphone or tablet. +4. Give it a try, for instance:: + + >>> execfile('01_simple.py') diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/index.rst b/src/openmv/src/micropython/docs/wipy/tutorial/index.rst new file mode 100755 index 0000000..e548879 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/index.rst @@ -0,0 +1,18 @@ +.. _wipy_tutorial: + +WiPy tutorials and examples +=========================== + +Before starting, make sure that you are running the latest firmware, +for instructions see :ref:`OTA How-To `. + +.. toctree:: + :maxdepth: 1 + :numbered: + + intro.rst + repl.rst + blynk.rst + wlan.rst + timer.rst + reset.rst diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/intro.rst b/src/openmv/src/micropython/docs/wipy/tutorial/intro.rst new file mode 100755 index 0000000..1b90495 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/intro.rst @@ -0,0 +1,64 @@ +Introduction to the WiPy +======================== + +To get the most out of your WiPy, there are a few basic things to +understand about how it works. + +Caring for your WiPy and expansion board +---------------------------------------- + +Because the WiPy/expansion board does not have a housing it needs a bit of care: + + - Be gentle when plugging/unplugging the USB cable. Whilst the USB connector + is well soldered and is relatively strong, if it breaks off it can be very + difficult to fix. + + - Static electricity can shock the components on the WiPy and destroy them. + If you experience a lot of static electricity in your area (eg dry and cold + climates), take extra care not to shock the WiPy. If your WiPy came + in a ESD bag, then this bag is the best way to store and carry the + WiPy as it will protect it against static discharges. + +As long as you take care of the hardware, you should be okay. It's almost +impossible to break the software on the WiPy, so feel free to play around +with writing code as much as you like. If the filesystem gets corrupt, see +below on how to reset it. In the worst case you might need to do a safe boot, +which is explained in detail in :ref:`wipy_boot_modes`. + +Plugging into the expansion board and powering on +------------------------------------------------- + +The expansion board can power the WiPy via USB. The WiPy comes with a sticker +on top of the RF shield that labels all pins, and this should match the label +numbers on the expansion board headers. When plugging it in, the WiPy antenna +will end up on top of the SD card connector of the expansion board. A video +showing how to do this can be found `here on YouTube `_. + +Expansion board hardware guide +------------------------------ + +The document explaining the hardware details of the expansion board can be found +`in this PDF `_. + +Powering by an external power source +------------------------------------ + +The WiPy can be powered by a battery or other external power source. + +**Be sure to connect the positive lead of the power supply to VIN, and +ground to GND. There is no polarity protection on the WiPy so you +must be careful when connecting anything to VIN.** + +- When powering via ``VIN``: + + **The input voltage must be between 3.6V and 5.5V.** + +- When powering via ``3V3``: + + **The input voltage must be exactly 3V3, ripple free and from a supply capable + of sourcing at least 300mA of current** + +Performing firmware upgrades +---------------------------- + +For detailed instructions see :ref:`OTA How-To `. diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/repl.rst b/src/openmv/src/micropython/docs/wipy/tutorial/repl.rst new file mode 100755 index 0000000..e25e047 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/repl.rst @@ -0,0 +1,130 @@ +Getting a MicroPython REPL prompt +================================= + +REPL stands for Read Evaluate Print Loop, and is the name given to the +interactive MicroPython prompt that you can access on the WiPy. Using +the REPL is by far the easiest way to test out your code and run commands. +You can use the REPL in addition to writing scripts in ``main.py``. + +.. _wipy_uart: + +To use the REPL, you must connect to the WiPy either via :ref:`telnet `, +or with a USB to serial converter wired to one of the two UARTs on the +WiPy. To enable REPL duplication on UART0 (the one accessible via the expansion board) +do:: + + >>> from machine import UART + >>> import os + >>> uart = UART(0, 115200) + >>> os.dupterm(uart) + +Place this piece of code inside your ``boot.py`` so that it's done automatically after +reset. + +Windows +------- + +First you need to install the FTDI drivers for the expansion board's USB to serial +converter. Then you need a terminal software. The best option is to download the +free program PuTTY: `putty.exe `_. + +**In order to get to the telnet REPL:** + +Using putty, select ``Telnet`` as connection type, leave the default port (23) +and enter the IP address of your WiPy (192.168.1.1 when in ``WLAN.AP`` mode), +then click open. + +**In order to get to the REPL UART:** + +Using your serial program you must connect to the COM port that you found in the +previous step. With PuTTY, click on "Session" in the left-hand panel, then click +the "Serial" radio button on the right, then enter you COM port (eg COM4) in the +"Serial Line" box. Finally, click the "Open" button. + +Mac OS X +-------- + +Open a terminal and run:: + + $ telnet 192.168.1.1 + +or:: + + $ screen /dev/tty.usbmodem* 115200 + +When you are finished and want to exit ``screen``, type CTRL-A CTRL-\\. If your keyboard does not have a \\-key (i.e. you need an obscure combination for \\ like ALT-SHIFT-7) you can remap the ``quit`` command: + +- create ``~/.screenrc`` +- add ``bind q quit`` + +This will allow you to quit ``screen`` by hitting CTRL-A Q. + +Linux +----- + +Open a terminal and run:: + + $ telnet 192.168.1.1 + +or:: + + $ screen /dev/ttyUSB0 115200 + +You can also try ``picocom`` or ``minicom`` instead of screen. You may have to +use ``/dev/ttyUSB01`` or a higher number for ``ttyUSB``. And, you may need to give +yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``, +or use sudo). + +Using the REPL prompt +--------------------- + +Now let's try running some MicroPython code directly on the WiPy. + +With your serial program open (PuTTY, screen, picocom, etc) you may see a blank +screen with a flashing cursor. Press Enter and you should be presented with a +MicroPython prompt, i.e. ``>>>``. Let's make sure it is working with the obligatory test:: + + >>> print("hello WiPy!") + hello WiPy! + +In the above, you should not type in the ``>>>`` characters. They are there to +indicate that you should type the text after it at the prompt. In the end, once +you have entered the text ``print("hello WiPy!")`` and pressed Enter, the output +on your screen should look like it does above. + +If you already know some Python you can now try some basic commands here. + +If any of this is not working you can try either a hard reset or a soft reset; +see below. + +Go ahead and try typing in some other commands. For example:: + + >>> from machine import Pin + >>> import wipy + >>> wipy.heartbeat(False) # disable the heartbeat + >>> led = Pin('GP25', mode=Pin.OUT) + >>> led(1) + >>> led(0) + >>> led.toggle() + >>> 1 + 2 + 3 + >>> 4 // 2 + 2 + >>> 20 * 'py' + 'pypypypypypypypypypypypypypypypypypypypy' + +Resetting the board +------------------- + +If something goes wrong, you can reset the board in two ways. The first is to press CTRL-D +at the MicroPython prompt, which performs a soft reset. You will see a message something like:: + + >>> + PYB: soft reboot + MicroPython v1.4.6-146-g1d8b5e5 on 2015-10-21; WiPy with CC3200 + Type "help()" for more information. + >>> + +If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the +RST switch (the small black button next to the heartbeat LED). During telnet, this will end +your session, disconnecting whatever program that you used to connect to the WiPy. diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/reset.rst b/src/openmv/src/micropython/docs/wipy/tutorial/reset.rst new file mode 100755 index 0000000..ece2849 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/reset.rst @@ -0,0 +1,54 @@ +Reset and boot modes +==================== + +There are soft resets and hard resets. + + - A soft reset simply clears the state of the MicroPython virtual machine, + but leaves hardware peripherals unaffected. To do a soft reset, simply press + **Ctrl+D** on the REPL, or within a script do:: + + import sys + sys.exit() + + - A hard reset is the same as performing a power cycle to the board. In order to + hard reset the WiPy, press the switch on the board or:: + + import machine + machine.reset() + +Safe boot +--------- + +If something goes wrong with your WiPy, don't panic! It is almost +impossible for you to break the WiPy by programming the wrong thing. + +The first thing to try is to boot in safe mode: this temporarily skips +execution of ``boot.py`` and ``main.py`` and gives default WLAN settings. + +If you have problems with the filesystem you can :ref:`format the internal flash +drive `. + +To boot in safe mode, follow the detailed instructions described :ref:`here `. + +In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so +the WiPy boots up with default settings. This means you now have access +to the filesystem, and you can edit ``boot.py`` and ``main.py`` to fix any problems. + +Entering safe mode is temporary, and does not make any changes to the +files on the WiPy. + +.. _wipy_factory_reset: + +Factory reset the filesystem +---------------------------- + +If you WiPy's filesystem gets corrupted (very unlikely, but possible), you +can format it very easily by doing:: + + >>> import os + >>> os.mkfs('/flash') + +Resetting the filesystem deletes all files on the internal WiPy storage +(not the SD card), and restores the files ``boot.py`` and ``main.py`` back +to their original state after the next reset. + diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/timer.rst b/src/openmv/src/micropython/docs/wipy/tutorial/timer.rst new file mode 100755 index 0000000..c87ac44 --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/timer.rst @@ -0,0 +1,70 @@ +Hardware timers +=============== + +Timers can be used for a great variety of tasks, calling a function periodically, +counting events, and generating a PWM signal are among the most common use cases. +Each timer consists of two 16-bit channels and this channels can be tied together to +form one 32-bit timer. The operating mode needs to be configured per timer, but then +the period (or the frequency) can be independently configured on each channel. +By using the callback method, the timer event can call a Python function. + +Example usage to toggle an LED at a fixed frequency:: + + from machine import Timer + from machine import Pin + led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED + tim = Timer(3) # create a timer object using timer 3 + tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode + tim_ch = tim.channel(Timer.A, freq=5) # configure channel A at a frequency of 5Hz + tim_ch.irq(handler=lambda t:led.toggle(), trigger=Timer.TIMEOUT) # toggle a LED on every cycle of the timer + +Example using named function for the callback:: + + from machine import Timer + from machine import Pin + tim = Timer(1, mode=Timer.PERIODIC, width=32) + tim_a = tim.channel(Timer.A | Timer.B, freq=1) # 1 Hz frequency requires a 32 bit timer + + led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED + + def tick(timer): # we will receive the timer object when being called + global led + led.toggle() # toggle the LED + + tim_a.irq(handler=tick, trigger=Timer.TIMEOUT) # create the interrupt + +Further examples:: + + from machine import Timer + tim1 = Timer(1, mode=Timer.ONE_SHOT) # initialize it in one shot mode + tim2 = Timer(2, mode=Timer.PWM) # initialize it in PWM mode + tim1_ch = tim1.channel(Timer.A, freq=10, polarity=Timer.POSITIVE) # start the event counter with a frequency of 10Hz and triggered by positive edges + tim2_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=5000) # start the PWM on channel B with a 50% duty cycle + tim2_ch.freq(20) # set the frequency (can also get) + tim2_ch.duty_cycle(3010) # set the duty cycle to 30.1% (can also get) + tim2_ch.duty_cycle(3020, Timer.NEGATIVE) # set the duty cycle to 30.2% and change the polarity to negative + tim2_ch.period(2000000) # change the period to 2 seconds + + +Additional constants for Timer class +------------------------------------ + +.. data:: Timer.PWM + + PWM timer operating mode. + +.. data:: Timer.A +.. data:: Timer.B + + Selects the timer channel. Must be ORed (``Timer.A`` | ``Timer.B``) when + using a 32-bit timer. + +.. data:: Timer.POSITIVE +.. data:: Timer.NEGATIVE + + Timer channel polarity selection (only relevant in PWM mode). + +.. data:: Timer.TIMEOUT +.. data:: Timer.MATCH + + Timer channel IRQ triggers. diff --git a/src/openmv/src/micropython/docs/wipy/tutorial/wlan.rst b/src/openmv/src/micropython/docs/wipy/tutorial/wlan.rst new file mode 100755 index 0000000..434367c --- /dev/null +++ b/src/openmv/src/micropython/docs/wipy/tutorial/wlan.rst @@ -0,0 +1,71 @@ +WLAN step by step +================= + +The WLAN is a system feature of the WiPy, therefore it is always enabled +(even while in ``machine.SLEEP``), except when deepsleep mode is entered. + +In order to retrieve the current WLAN instance, do:: + + >>> from network import WLAN + >>> wlan = WLAN() # we call the constructor without params + +You can check the current mode (which is always ``WLAN.AP`` after power up):: + + >>> wlan.mode() + +.. warning:: + When you change the WLAN mode following the instructions below, your WLAN + connection to the WiPy will be broken. This means you will not be able + to run these commands interactively over the WLAN. + + There are two ways around this:: + 1. put this setup code into your :ref:`boot.py file` so that it gets executed automatically after reset. + 2. :ref:`duplicate the REPL on UART `, so that you can run commands via USB. + +Connecting to your home router +------------------------------ + +The WLAN network card always boots in ``WLAN.AP`` mode, so we must first configure +it as a station:: + + from network import WLAN + wlan = WLAN(mode=WLAN.STA) + + +Now you can proceed to scan for networks:: + + nets = wlan.scan() + for net in nets: + if net.ssid == 'mywifi': + print('Network found!') + wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000) + while not wlan.isconnected(): + machine.idle() # save power while waiting + print('WLAN connection succeeded!') + break + +Assigning a static IP address when booting +------------------------------------------ + +If you want your WiPy to connect to your home router after boot-up, and with a fixed +IP address so that you can access it via telnet or FTP, use the following script as /flash/boot.py:: + + import machine + from network import WLAN + wlan = WLAN() # get current object, without changing the mode + + if machine.reset_cause() != machine.SOFT_RESET: + wlan.init(WLAN.STA) + # configuration below MUST match your home router settings!! + wlan.ifconfig(config=('192.168.178.107', '255.255.255.0', '192.168.178.1', '8.8.8.8')) + + if not wlan.isconnected(): + # change the line below to match your network ssid, security and password + wlan.connect('mywifi', auth=(WLAN.WPA2, 'mywifikey'), timeout=5000) + while not wlan.isconnected(): + machine.idle() # save power while waiting + +.. note:: + + Notice how we check for the reset cause and the connection status, this is crucial in order + to be able to soft reset the WiPy during a telnet session without breaking the connection. diff --git a/src/openmv/src/micropython/drivers/README.md b/src/openmv/src/micropython/drivers/README.md new file mode 100755 index 0000000..854acc5 --- /dev/null +++ b/src/openmv/src/micropython/drivers/README.md @@ -0,0 +1,2 @@ +This directory contains drivers for specific hardware. The drivers are +intended to work across multiple ports. diff --git a/src/openmv/src/micropython/drivers/bus/qspi.h b/src/openmv/src/micropython/drivers/bus/qspi.h new file mode 100755 index 0000000..31c9d14 --- /dev/null +++ b/src/openmv/src/micropython/drivers/bus/qspi.h @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H + +#include "py/mphal.h" + +enum { + MP_QSPI_IOCTL_INIT, + MP_QSPI_IOCTL_DEINIT, + MP_QSPI_IOCTL_BUS_ACQUIRE, + MP_QSPI_IOCTL_BUS_RELEASE, +}; + +typedef struct _mp_qspi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data); + void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src); + uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len); + void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest); +} mp_qspi_proto_t; + +typedef struct _mp_soft_qspi_obj_t { + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t clk; + mp_hal_pin_obj_t io0; + mp_hal_pin_obj_t io1; + mp_hal_pin_obj_t io2; + mp_hal_pin_obj_t io3; +} mp_soft_qspi_obj_t; + +extern const mp_qspi_proto_t mp_soft_qspi_proto; + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/src/openmv/src/micropython/drivers/bus/softqspi.c b/src/openmv/src/micropython/drivers/bus/softqspi.c new file mode 100755 index 0000000..10c5992 --- /dev/null +++ b/src/openmv/src/micropython/drivers/bus/softqspi.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/qspi.h" + +#define CS_LOW(self) mp_hal_pin_write(self->cs, 0) +#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1) + +#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW + +// Use externally provided functions for SCK control and IO reading +#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self) +#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self) +#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self) + +#else + +// Use generic pin functions for SCK control and IO reading +#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0) +#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1) +#define NIBBLE_READ(self) ( \ + mp_hal_pin_read(self->io0) \ + | (mp_hal_pin_read(self->io1) << 1) \ + | (mp_hal_pin_read(self->io2) << 2) \ + | (mp_hal_pin_read(self->io3) << 3)) + +#endif + +STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) { + mp_hal_pin_write(self->io0, v & 1); + mp_hal_pin_write(self->io1, (v >> 1) & 1); + mp_hal_pin_write(self->io2, (v >> 2) & 1); + mp_hal_pin_write(self->io3, (v >> 3) & 1); +} + +STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + mp_hal_pin_high(self->cs); + mp_hal_pin_output(self->cs); + + // Configure pins + mp_hal_pin_write(self->clk, 0); + mp_hal_pin_output(self->clk); + //mp_hal_pin_write(self->clk, 1); + mp_hal_pin_output(self->io0); + mp_hal_pin_input(self->io1); + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + break; + } + + return 0; // success +} + +STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) { + // Will run as fast as possible, limited only by CPU speed and GPIO time + mp_hal_pin_input(self->io1); + mp_hal_pin_output(self->io0); + if (self->io3) { + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + } + if (src) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->io0, (data_out >> 7) & 1); + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } else { + for (size_t i = 0; i < len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j) { + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } +} + +STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) { + // Make all IO lines input + mp_hal_pin_input(self->io2); + mp_hal_pin_input(self->io3); + mp_hal_pin_input(self->io0); + mp_hal_pin_input(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + while (len--) { + SCK_HIGH(self); + uint8_t data_in = NIBBLE_READ(self); + SCK_LOW(self); + SCK_HIGH(self); + *buf++ = (data_in << 4) | NIBBLE_READ(self); + SCK_LOW(self); + } +} + +STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) { + // Make all IO lines output + mp_hal_pin_output(self->io2); + mp_hal_pin_output(self->io3); + mp_hal_pin_output(self->io0); + mp_hal_pin_output(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + for (size_t i = 0; i < len; ++i) { + nibble_write(self, buf[i] >> 4); + SCK_HIGH(self); + SCK_LOW(self); + + nibble_write(self, buf[i]); + SCK_HIGH(self); + SCK_LOW(self); + } + + //mp_hal_pin_input(self->io1); +} + +STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd | data << 8; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL); + CS_HIGH(self); +} + +STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, len, src, NULL); + CS_HIGH(self); +} + +STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf); + CS_HIGH(self); + return cmd_buf >> 8; +} + +STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1, cmd_buf, NULL); + mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) + mp_soft_qspi_qread(self, len, dest); + CS_HIGH(self); +} + +const mp_qspi_proto_t mp_soft_qspi_proto = { + .ioctl = mp_soft_qspi_ioctl, + .write_cmd_data = mp_soft_qspi_write_cmd_data, + .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data, + .read_cmd = mp_soft_qspi_read_cmd, + .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata, +}; diff --git a/src/openmv/src/micropython/drivers/bus/softspi.c b/src/openmv/src/micropython/drivers/bus/softspi.c new file mode 100755 index 0000000..bc12d89 --- /dev/null +++ b/src/openmv/src/micropython/drivers/bus/softspi.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/spi.h" + +int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + + switch (cmd) { + case MP_SPI_IOCTL_INIT: + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_pin_output(self->sck); + mp_hal_pin_output(self->mosi); + mp_hal_pin_input(self->miso); + break; + + case MP_SPI_IOCTL_DEINIT: + break; + } + + return 0; +} + +void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + uint32_t delay_half = self->delay_half; + + // only MSB transfer is implemented + + // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + mp_hal_pin_write(self->sck, 1 - self->polarity); + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + mp_hal_pin_write(self->sck, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + return; + } + #endif + + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, 1 - self->polarity); + } else { + mp_hal_pin_write(self->sck, 1 - self->polarity); + mp_hal_delay_us_fast(delay_half); + } + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, self->polarity); + } else { + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_delay_us_fast(delay_half); + } + } + if (dest != NULL) { + dest[i] = data_in; + } + } +} + +const mp_spi_proto_t mp_soft_spi_proto = { + .ioctl = mp_soft_spi_ioctl, + .transfer = mp_soft_spi_transfer, +}; diff --git a/src/openmv/src/micropython/drivers/bus/spi.h b/src/openmv/src/micropython/drivers/bus/spi.h new file mode 100755 index 0000000..6d1b9c2 --- /dev/null +++ b/src/openmv/src/micropython/drivers/bus/spi.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H + +#include "py/mphal.h" + +enum { + MP_SPI_IOCTL_INIT, + MP_SPI_IOCTL_DEINIT, +}; + +typedef struct _mp_spi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest); +} mp_spi_proto_t; + +typedef struct _mp_soft_spi_obj_t { + uint32_t delay_half; // microsecond delay for half SCK period + uint8_t polarity; + uint8_t phase; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t mosi; + mp_hal_pin_obj_t miso; +} mp_soft_spi_obj_t; + +extern const mp_spi_proto_t mp_soft_spi_proto; + +int mp_soft_spi_ioctl(void *self, uint32_t cmd); +void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest); + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/cc3000_common.h b/src/openmv/src/micropython/drivers/cc3000/inc/cc3000_common.h new file mode 100755 index 0000000..d0c4b1d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/cc3000_common.h @@ -0,0 +1,365 @@ +/***************************************************************************** +* +* cc3000_common.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_COMMON_H__ +#define __CC3000_COMMON_H__ + +#include "data_types.h" + +//****************************************************************************** +// Include files +//****************************************************************************** +#include +#include + +//***************************************************************************** +// Prefix exported names to avoid name clash +//***************************************************************************** +#define CC3000_EXPORT(name) cc3000_ ## name + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +extern int CC3000_EXPORT(errno); + +//***************************************************************************** +// ERROR CODES +//***************************************************************************** +#define ESUCCESS 0 +#define EFAIL -1 +#define EERROR EFAIL + +//***************************************************************************** +// COMMON DEFINES +//***************************************************************************** +#define ERROR_SOCKET_INACTIVE -57 + +#define WLAN_ENABLE (1) +#define WLAN_DISABLE (0) + +#define MAC_ADDR_LEN (6) + +#define SP_PORTION_SIZE (32) + +/*Defines for minimal and maximal RX buffer size. This size includes the spi + header and hci header. + The maximal buffer size derives from: + MTU + HCI header + SPI header + sendto() agrs size + The minimum buffer size derives from: + HCI header + SPI header + max args size + + This buffer is used for receiving events and data. + The packet can not be longer than MTU size and CC3000 does not support + fragmentation. Note that the same buffer is used for reception of the data + and events from CC3000. That is why the minimum is defined. + The calculation for the actual size of buffer for reception is: + Given the maximal data size MAX_DATA that is expected to be received by + application, the required buffer is: + Using recv() or recvfrom(): + + max(CC3000_MINIMAL_RX_SIZE, MAX_DATA + HEADERS_SIZE_DATA + fromlen + + ucArgsize + 1) + + Using gethostbyname() with minimal buffer size will limit the host name + returned to 99 bytes only. + The 1 is used for the overrun detection + + Buffer size increased to 130 following the add_profile() with WEP security + which requires TX buffer size of 130 bytes: + HEADERS_SIZE_EVNT + WLAN_ADD_PROFILE_WEP_PARAM_LEN + MAX SSID LEN + 4 * MAX KEY LEN = 130 + MAX SSID LEN = 32 + MAX SSID LEN = 13 (with add_profile only ascii key setting is supported, + therfore maximum key size is 13) +*/ + +#define CC3000_MINIMAL_RX_SIZE (130 + 1) +#define CC3000_MAXIMAL_RX_SIZE (1519 + 1) + +/*Defines for minimal and maximal TX buffer size. + This buffer is used for sending events and data. + The packet can not be longer than MTU size and CC3000 does not support + fragmentation. Note that the same buffer is used for transmission of the data + and commands. That is why the minimum is defined. + The calculation for the actual size of buffer for transmission is: + Given the maximal data size MAX_DATA, the required buffer is: + Using Sendto(): + + max(CC3000_MINIMAL_TX_SIZE, MAX_DATA + SPI_HEADER_SIZE + + SOCKET_SENDTO_PARAMS_LEN + SIMPLE_LINK_HCI_DATA_HEADER_SIZE + 1) + + Using Send(): + + max(CC3000_MINIMAL_TX_SIZE, MAX_DATA + SPI_HEADER_SIZE + + HCI_CMND_SEND_ARG_LENGTH + SIMPLE_LINK_HCI_DATA_HEADER_SIZE + 1) + + The 1 is used for the overrun detection */ + +#define CC3000_MINIMAL_TX_SIZE (130 + 1) +#define CC3000_MAXIMAL_TX_SIZE (1519 + 1) + +//TX and RX buffer sizes, allow to receive and transmit maximum data at length 8. +#ifdef CC3000_TINY_DRIVER +#define TINY_CC3000_MAXIMAL_RX_SIZE 44 +#define TINY_CC3000_MAXIMAL_TX_SIZE 59 +#endif + +/*In order to determine your preferred buffer size, + change CC3000_MAXIMAL_RX_SIZE and CC3000_MAXIMAL_TX_SIZE to a value between + the minimal and maximal specified above. + Note that the buffers are allocated by SPI. + In case you change the size of those buffers, you might need also to change + the linker file, since for example on MSP430 FRAM devices the buffers are + allocated in the FRAM section that is allocated manually and not by IDE. +*/ + +#ifndef CC3000_TINY_DRIVER + + #define CC3000_RX_BUFFER_SIZE (CC3000_MAXIMAL_RX_SIZE) + #define CC3000_TX_BUFFER_SIZE (CC3000_MAXIMAL_TX_SIZE) + +//if defined TINY DRIVER we use smaller RX and TX buffer in order to minimize RAM consumption +#else + #define CC3000_RX_BUFFER_SIZE (TINY_CC3000_MAXIMAL_RX_SIZE) + #define CC3000_TX_BUFFER_SIZE (TINY_CC3000_MAXIMAL_TX_SIZE) + +#endif + +//***************************************************************************** +// Compound Types +//***************************************************************************** +typedef INT32 cc3000_time_t; +typedef UINT32 clock_t; +typedef INT32 suseconds_t; + +typedef struct cc3000_timeval cc3000_timeval; + +struct cc3000_timeval +{ + cc3000_time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ +}; + +typedef CHAR *(*tFWPatches)(UINT32 *usLength); + +typedef CHAR *(*tDriverPatches)(UINT32 *usLength); + +typedef CHAR *(*tBootLoaderPatches)(UINT32 *usLength); + +typedef void (*tWlanCB)(INT32 event_type, CHAR * data, UINT8 length ); + +typedef INT32 (*tWlanReadInteruptPin)(void); + +typedef void (*tWlanInterruptEnable)(void); + +typedef void (*tWlanInterruptDisable)(void); + +typedef void (*tWriteWlanPin)(UINT8 val); + +typedef struct +{ + UINT16 usRxEventOpcode; + UINT16 usEventOrDataReceived; + UINT8 *pucReceivedData; + UINT8 *pucTxCommandBuffer; + + tFWPatches sFWPatches; + tDriverPatches sDriverPatches; + tBootLoaderPatches sBootLoaderPatches; + tWlanCB sWlanCB; + tWlanReadInteruptPin ReadWlanInterruptPin; + tWlanInterruptEnable WlanInterruptEnable; + tWlanInterruptDisable WlanInterruptDisable; + tWriteWlanPin WriteWlanPin; + + INT32 slTransmitDataError; + UINT16 usNumberOfFreeBuffers; + UINT16 usSlBufferLength; + UINT16 usBufferSize; + UINT16 usRxDataPending; + + UINT32 NumberOfSentPackets; + UINT32 NumberOfReleasedPackets; + + UINT8 InformHostOnTxComplete; +}sSimplLinkInformation; + +extern volatile sSimplLinkInformation tSLInformation; + + +//***************************************************************************** +// Prototypes for the APIs. +//***************************************************************************** + + + +//***************************************************************************** +// +//! SimpleLinkWaitEvent +//! +//! @param usOpcode command operation code +//! @param pRetParams command return parameters +//! +//! @return none +//! +//! @brief Wait for event, pass it to the hci_event_handler and +//! update the event opcode in a global variable. +// +//***************************************************************************** + +extern void SimpleLinkWaitEvent(UINT16 usOpcode, void *pRetParams); + +//***************************************************************************** +// +//! SimpleLinkWaitData +//! +//! @param pBuf data buffer +//! @param from from information +//! @param fromlen from information length +//! +//! @return none +//! +//! @brief Wait for data, pass it to the hci_event_handler +//! and update in a global variable that there is +//! data to read. +// +//***************************************************************************** + +extern void SimpleLinkWaitData(UINT8 *pBuf, UINT8 *from, UINT8 *fromlen); + +//***************************************************************************** +// +//! UINT32_TO_STREAM_f +//! +//! \param p pointer to the new stream +//! \param u32 pointer to the 32 bit +//! +//! \return pointer to the new stream +//! +//! \brief This function is used for copying 32 bit to stream +//! while converting to little endian format. +// +//***************************************************************************** + +extern UINT8* UINT32_TO_STREAM_f (UINT8 *p, UINT32 u32); + +//***************************************************************************** +// +//! UINT16_TO_STREAM_f +//! +//! \param p pointer to the new stream +//! \param u32 pointer to the 16 bit +//! +//! \return pointer to the new stream +//! +//! \brief This function is used for copying 16 bit to stream +//! while converting to little endian format. +// +//***************************************************************************** + +extern UINT8* UINT16_TO_STREAM_f (UINT8 *p, UINT16 u16); + +//***************************************************************************** +// +//! STREAM_TO_UINT16_f +//! +//! \param p pointer to the stream +//! \param offset offset in the stream +//! +//! \return pointer to the new 16 bit +//! +//! \brief This function is used for copying received stream to +//! 16 bit in little endian format. +// +//***************************************************************************** + +extern UINT16 STREAM_TO_UINT16_f(CHAR* p, UINT16 offset); + +//***************************************************************************** +// +//! STREAM_TO_UINT32_f +//! +//! \param p pointer to the stream +//! \param offset offset in the stream +//! +//! \return pointer to the new 32 bit +//! +//! \brief This function is used for copying received stream to +//! 32 bit in little endian format. +// +//***************************************************************************** + +extern UINT32 STREAM_TO_UINT32_f(CHAR* p, UINT16 offset); + + +//***************************************************************************** +// COMMON MACROs +//***************************************************************************** + + +//This macro is used for copying 8 bit to stream while converting to little endian format. +#define UINT8_TO_STREAM(_p, _val) {*(_p)++ = (_val);} +//This macro is used for copying 16 bit to stream while converting to little endian format. +#define UINT16_TO_STREAM(_p, _u16) (UINT16_TO_STREAM_f(_p, _u16)) +//This macro is used for copying 32 bit to stream while converting to little endian format. +#define UINT32_TO_STREAM(_p, _u32) (UINT32_TO_STREAM_f(_p, _u32)) +//This macro is used for copying a specified value length bits (l) to stream while converting to little endian format. +#define ARRAY_TO_STREAM(p, a, l) {register INT16 _i; for (_i = 0; _i < l; _i++) *(p)++ = ((UINT8 *) a)[_i];} +//This macro is used for copying received stream to 8 bit in little endian format. +#define STREAM_TO_UINT8(_p, _offset, _u8) {_u8 = (UINT8)(*(_p + _offset));} +//This macro is used for copying received stream to 16 bit in little endian format. +#define STREAM_TO_UINT16(_p, _offset, _u16) {_u16 = STREAM_TO_UINT16_f(_p, _offset);} +//This macro is used for copying received stream to 32 bit in little endian format. +#define STREAM_TO_UINT32(_p, _offset, _u32) {_u32 = STREAM_TO_UINT32_f(_p, _offset);} +#define STREAM_TO_STREAM(p, a, l) {register INT16 _i; for (_i = 0; _i < l; _i++) *(a)++= ((UINT8 *) p)[_i];} + + + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_COMMON_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/ccspi.h b/src/openmv/src/micropython/drivers/cc3000/inc/ccspi.h new file mode 100755 index 0000000..8fa3ecd --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/ccspi.h @@ -0,0 +1,84 @@ +/***************************************************************************** +* +* spi.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_SPI_H__ +#define __CC3000_SPI_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*gcSpiHandleRx)(void *p); +typedef void (*gcSpiHandleTx)(void); +extern unsigned char wlan_tx_buffer[]; + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** + +// the arguments must be of type pin_obj_t* and SPI_HandleTypeDef* +extern void SpiInit(void *spi, const void *pin_cs, const void *pin_en, const void *pin_irq); + +extern void SpiOpen(gcSpiHandleRx pfRxHandler); +extern void SpiClose(void); +extern void SpiPauseSpi(void); +extern void SpiResumeSpi(void); +extern long SpiWrite(unsigned char *pUserBuffer, unsigned short usLength); +extern void SpiConfigureHwMapping(void); +extern void SpiCleanGPIOISR(void); +extern void SSIConfigure(unsigned long ulSSIFreq, unsigned long bForceGpioConfiguration, unsigned long uiReconfigureSysClock); +extern int init_spi(void); +extern long ReadWlanInterruptPin(void); +extern void WriteWlanPin(unsigned char val); +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif + diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/data_types.h b/src/openmv/src/micropython/drivers/cc3000/inc/data_types.h new file mode 100755 index 0000000..0520a92 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/data_types.h @@ -0,0 +1,107 @@ +/***************************************************************************** +* +* data_types.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_DATA_TYPES__ +#define __CC3000_DATA_TYPES__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef NULL +#define NULL (0) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifndef OK +#define OK (0) +#endif + +#ifndef _INT8 +#define _INT8 +typedef signed char INT8; +#endif + +#ifndef _UINT8 +#define _UINT8 +typedef unsigned char UINT8; +#endif + +#ifndef _INT16 +#define _INT16 +typedef signed short INT16; +#endif + +#ifndef _UINT16 +#define _UINT16 +typedef unsigned short UINT16; +#endif + +#ifndef _BOOLEAN +#define _BOOLEAN +typedef unsigned char BOOLEAN; +#endif + +#ifndef _INT32 +#define _INT32 +typedef signed long INT32; +#endif + +#ifndef _UINT32 +#define _UINT32 +typedef unsigned long UINT32; +#endif + +typedef int INT; +typedef char CHAR; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __CC3000_DATA_TYPES__ */ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/evnt_handler.h b/src/openmv/src/micropython/drivers/cc3000/inc/evnt_handler.h new file mode 100755 index 0000000..d05a442 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/evnt_handler.h @@ -0,0 +1,166 @@ +/***************************************************************************** +* +* evnt_handler.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_EVENT_HANDLER_H__ +#define __CC3000_EVENT_HANDLER_H__ +#include "hci.h" +#include "socket.h" + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** + +//***************************************************************************** +// +//! hci_event_handler +//! +//! @param pRetParams incoming data buffer +//! @param from from information (in case of data received) +//! @param fromlen from information length (in case of data received) +//! +//! @return none +//! +//! @brief Parse the incoming events packets and issues corresponding +//! event handler from global array of handlers pointers +// +//***************************************************************************** +extern UINT8 *hci_event_handler(void *pRetParams, UINT8 *from, UINT8 *fromlen); + +//***************************************************************************** +// +//! hci_unsol_event_handler +//! +//! @param event_hdr event header +//! +//! @return 1 if event supported and handled +//! 0 if event is not supported +//! +//! @brief Handle unsolicited events +// +//***************************************************************************** +extern INT32 hci_unsol_event_handler(CHAR *event_hdr); + +//***************************************************************************** +// +//! hci_unsolicited_event_handler +//! +//! @param None +//! +//! @return ESUCCESS if successful, EFAIL if an error occurred +//! +//! @brief Parse the incoming unsolicited event packets and issues +//! corresponding event handler. +// +//***************************************************************************** +extern INT32 hci_unsolicited_event_handler(void); + +#define M_BSD_RESP_PARAMS_OFFSET(hci_event_hdr)((CHAR *)(hci_event_hdr) + HCI_EVENT_HEADER_SIZE) + +#define SOCKET_STATUS_ACTIVE 0 +#define SOCKET_STATUS_INACTIVE 1 +/* Init socket_active_status = 'all ones': init all sockets with SOCKET_STATUS_INACTIVE. + Will be changed by 'set_socket_active_status' upon 'connect' and 'accept' calls */ +#define SOCKET_STATUS_INIT_VAL 0xFFFF +#define M_IS_VALID_SD(sd) ((0 <= (sd)) && ((sd) <= 7)) +#define M_IS_VALID_STATUS(status) (((status) == SOCKET_STATUS_ACTIVE)||((status) == SOCKET_STATUS_INACTIVE)) + +extern UINT32 socket_active_status; + +extern void set_socket_active_status(INT32 Sd, INT32 Status); +extern INT32 get_socket_active_status(INT32 Sd); + +typedef struct _bsd_accept_return_t +{ + INT32 iSocketDescriptor; + INT32 iStatus; + sockaddr tSocketAddress; + +} tBsdReturnParams; + + +typedef struct _bsd_read_return_t +{ + INT32 iSocketDescriptor; + INT32 iNumberOfBytes; + UINT32 uiFlags; +} tBsdReadReturnParams; + +#define BSD_RECV_FROM_FROMLEN_OFFSET (4) +#define BSD_RECV_FROM_FROM_OFFSET (16) + + +typedef struct _bsd_select_return_t +{ + INT32 iStatus; + UINT32 uiRdfd; + UINT32 uiWrfd; + UINT32 uiExfd; +} tBsdSelectRecvParams; + + +typedef struct _bsd_getsockopt_return_t +{ + UINT8 ucOptValue[4]; + CHAR iStatus; +} tBsdGetSockOptReturnParams; + +typedef struct _bsd_gethostbyname_return_t +{ + INT32 retVal; + INT32 outputAddress; +} tBsdGethostbynameParams; + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_EVENT_HANDLER_H__ + diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/hci.h b/src/openmv/src/micropython/drivers/cc3000/inc/hci.h new file mode 100755 index 0000000..f12b00e --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/hci.h @@ -0,0 +1,330 @@ +/***************************************************************************** +* +* hci.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_HCI_H__ +#define __CC3000_HCI_H__ + +#include "cc3000_common.h" + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + + +#define SPI_HEADER_SIZE (5) +#define SIMPLE_LINK_HCI_CMND_HEADER_SIZE (4) +#define HEADERS_SIZE_CMD (SPI_HEADER_SIZE + SIMPLE_LINK_HCI_CMND_HEADER_SIZE) +#define SIMPLE_LINK_HCI_DATA_CMND_HEADER_SIZE (5) +#define SIMPLE_LINK_HCI_DATA_HEADER_SIZE (5) +#define SIMPLE_LINK_HCI_PATCH_HEADER_SIZE (2) + + +//***************************************************************************** +// +// Values that can be used as HCI Commands and HCI Packet header defines +// +//***************************************************************************** +#define HCI_TYPE_CMND 0x1 +#define HCI_TYPE_DATA 0x2 +#define HCI_TYPE_PATCH 0x3 +#define HCI_TYPE_EVNT 0x4 + + +#define HCI_EVENT_PATCHES_DRV_REQ (1) +#define HCI_EVENT_PATCHES_FW_REQ (2) +#define HCI_EVENT_PATCHES_BOOTLOAD_REQ (3) + + +#define HCI_CMND_WLAN_BASE (0x0000) +#define HCI_CMND_WLAN_CONNECT 0x0001 +#define HCI_CMND_WLAN_DISCONNECT 0x0002 +#define HCI_CMND_WLAN_IOCTL_SET_SCANPARAM 0x0003 +#define HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY 0x0004 +#define HCI_CMND_WLAN_IOCTL_ADD_PROFILE 0x0005 +#define HCI_CMND_WLAN_IOCTL_DEL_PROFILE 0x0006 +#define HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS 0x0007 +#define HCI_CMND_EVENT_MASK 0x0008 +#define HCI_CMND_WLAN_IOCTL_STATUSGET 0x0009 +#define HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START 0x000A +#define HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP 0x000B +#define HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX 0x000C +#define HCI_CMND_WLAN_CONFIGURE_PATCH 0x000D + + +#define HCI_CMND_SOCKET_BASE 0x1000 +#define HCI_CMND_SOCKET 0x1001 +#define HCI_CMND_BIND 0x1002 +#define HCI_CMND_RECV 0x1004 +#define HCI_CMND_ACCEPT 0x1005 +#define HCI_CMND_LISTEN 0x1006 +#define HCI_CMND_CONNECT 0x1007 +#define HCI_CMND_BSD_SELECT 0x1008 +#define HCI_CMND_SETSOCKOPT 0x1009 +#define HCI_CMND_GETSOCKOPT 0x100A +#define HCI_CMND_CLOSE_SOCKET 0x100B +#define HCI_CMND_RECVFROM 0x100D +#define HCI_CMND_GETHOSTNAME 0x1010 +#define HCI_CMND_MDNS_ADVERTISE 0x1011 +#define HCI_CMND_GETMSSVALUE 0x1012 + + +#define HCI_DATA_BASE 0x80 + +#define HCI_CMND_SEND (0x01 + HCI_DATA_BASE) +#define HCI_CMND_SENDTO (0x03 + HCI_DATA_BASE) +#define HCI_DATA_BSD_RECVFROM (0x04 + HCI_DATA_BASE) +#define HCI_DATA_BSD_RECV (0x05 + HCI_DATA_BASE) + + +#define HCI_CMND_NVMEM_CBASE (0x0200) + + +#define HCI_CMND_NVMEM_CREATE_ENTRY (0x0203) +#define HCI_CMND_NVMEM_SWAP_ENTRY (0x0205) +#define HCI_CMND_NVMEM_READ (0x0201) +#define HCI_CMND_NVMEM_WRITE (0x0090) +#define HCI_CMND_NVMEM_WRITE_PATCH (0x0204) +#define HCI_CMND_READ_SP_VERSION (0x0207) + +#define HCI_CMND_READ_BUFFER_SIZE 0x400B +#define HCI_CMND_SIMPLE_LINK_START 0x4000 + +#define HCI_CMND_NETAPP_BASE 0x2000 + +#define HCI_NETAPP_DHCP (0x0001 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_PING_SEND (0x0002 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_PING_REPORT (0x0003 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_PING_STOP (0x0004 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_IPCONFIG (0x0005 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_ARP_FLUSH (0x0006 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_SET_DEBUG_LEVEL (0x0008 + HCI_CMND_NETAPP_BASE) +#define HCI_NETAPP_SET_TIMERS (0x0009 + HCI_CMND_NETAPP_BASE) + + + + + + +//***************************************************************************** +// +// Values that can be used as HCI Events defines +// +//***************************************************************************** +#define HCI_EVNT_WLAN_BASE 0x0000 +#define HCI_EVNT_WLAN_CONNECT 0x0001 +#define HCI_EVNT_WLAN_DISCONNECT \ + 0x0002 +#define HCI_EVNT_WLAN_IOCTL_ADD_PROFILE \ + 0x0005 + + +#define HCI_EVNT_SOCKET HCI_CMND_SOCKET +#define HCI_EVNT_BIND HCI_CMND_BIND +#define HCI_EVNT_RECV HCI_CMND_RECV +#define HCI_EVNT_ACCEPT HCI_CMND_ACCEPT +#define HCI_EVNT_LISTEN HCI_CMND_LISTEN +#define HCI_EVNT_CONNECT HCI_CMND_CONNECT +#define HCI_EVNT_SELECT HCI_CMND_BSD_SELECT +#define HCI_EVNT_CLOSE_SOCKET HCI_CMND_CLOSE_SOCKET +#define HCI_EVNT_RECVFROM HCI_CMND_RECVFROM +#define HCI_EVNT_SETSOCKOPT HCI_CMND_SETSOCKOPT +#define HCI_EVNT_GETSOCKOPT HCI_CMND_GETSOCKOPT +#define HCI_EVNT_BSD_GETHOSTBYNAME HCI_CMND_GETHOSTNAME +#define HCI_EVNT_MDNS_ADVERTISE HCI_CMND_MDNS_ADVERTISE +#define HCI_EVNT_GETMSSVALUE HCI_CMND_GETMSSVALUE + +#define HCI_EVNT_SEND 0x1003 +#define HCI_EVNT_WRITE 0x100E +#define HCI_EVNT_SENDTO 0x100F + +#define HCI_EVNT_PATCHES_REQ 0x1000 + +#define HCI_EVNT_UNSOL_BASE 0x4000 + +#define HCI_EVNT_WLAN_UNSOL_BASE (0x8000) + +#define HCI_EVNT_WLAN_UNSOL_CONNECT (0x0001 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_UNSOL_DISCONNECT (0x0002 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_UNSOL_INIT (0x0004 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_TX_COMPLETE (0x0008 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_UNSOL_DHCP (0x0010 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_ASYNC_PING_REPORT (0x0040 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE (0x0080 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_WLAN_KEEPALIVE (0x0200 + HCI_EVNT_WLAN_UNSOL_BASE) +#define HCI_EVNT_BSD_TCP_CLOSE_WAIT (0x0800 + HCI_EVNT_WLAN_UNSOL_BASE) + +#define HCI_EVNT_DATA_UNSOL_FREE_BUFF \ + 0x4100 + +#define HCI_EVNT_NVMEM_CREATE_ENTRY \ + HCI_CMND_NVMEM_CREATE_ENTRY +#define HCI_EVNT_NVMEM_SWAP_ENTRY HCI_CMND_NVMEM_SWAP_ENTRY + +#define HCI_EVNT_NVMEM_READ HCI_CMND_NVMEM_READ +#define HCI_EVNT_NVMEM_WRITE (0x0202) + +#define HCI_EVNT_READ_SP_VERSION \ + HCI_CMND_READ_SP_VERSION + +#define HCI_EVNT_INPROGRESS 0xFFFF + + +#define HCI_DATA_RECVFROM 0x84 +#define HCI_DATA_RECV 0x85 +#define HCI_DATA_NVMEM 0x91 + +#define HCI_EVENT_CC3000_CAN_SHUT_DOWN 0x99 + +//***************************************************************************** +// +// Prototypes for the structures for APIs. +// +//***************************************************************************** + +#define HCI_DATA_HEADER_SIZE (5) +#define HCI_EVENT_HEADER_SIZE (5) +#define HCI_DATA_CMD_HEADER_SIZE (5) +#define HCI_PATCH_HEADER_SIZE (6) + +#define HCI_PACKET_TYPE_OFFSET (0) +#define HCI_PACKET_ARGSIZE_OFFSET (2) +#define HCI_PACKET_LENGTH_OFFSET (3) + + +#define HCI_EVENT_OPCODE_OFFSET (1) +#define HCI_EVENT_LENGTH_OFFSET (3) +#define HCI_EVENT_STATUS_OFFSET (4) +#define HCI_DATA_LENGTH_OFFSET (3) + + + + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** + +//***************************************************************************** +// +//! hci_command_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the command's arguments buffer +//! @param ucArgsLength length of the arguments +//! +//! @return none +//! +//! @brief Initiate an HCI command. +// +//***************************************************************************** +extern UINT16 hci_command_send(UINT16 usOpcode, + UINT8 *ucArgs, + UINT8 ucArgsLength); + + +//***************************************************************************** +// +//! hci_data_send +//! +//! @param usOpcode command operation code +//! @param ucArgs pointer to the command's arguments buffer +//! @param usArgsLength length of the arguments +//! @param ucTail pointer to the data buffer +//! @param usTailLength buffer length +//! +//! @return none +//! +//! @brief Initiate an HCI data write operation +// +//***************************************************************************** +extern INT32 hci_data_send(UINT8 ucOpcode, + UINT8 *ucArgs, + UINT16 usArgsLength, + UINT16 usDataLength, + const UINT8 *ucTail, + UINT16 usTailLength); + + +//***************************************************************************** +// +//! hci_data_command_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the data buffer +//! @param ucArgsLength arguments length +//! @param ucDataLength data length +//! +//! @return none +//! +//! @brief Prepare HCI header and initiate an HCI data write operation +// +//***************************************************************************** +extern void hci_data_command_send(UINT16 usOpcode, UINT8 *pucBuff, + UINT8 ucArgsLength, UINT16 ucDataLength); + +//***************************************************************************** +// +//! hci_patch_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the command's arguments buffer +//! @param patch pointer to patch content buffer +//! @param usDataLength data length +//! +//! @return none +//! +//! @brief Prepare HCI header and initiate an HCI patch write operation +// +//***************************************************************************** +extern void hci_patch_send(UINT8 ucOpcode, UINT8 *pucBuff, CHAR *patch, UINT16 usDataLength); + + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_HCI_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/host_driver_version.h b/src/openmv/src/micropython/drivers/cc3000/inc/host_driver_version.h new file mode 100755 index 0000000..a28d21f --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/host_driver_version.h @@ -0,0 +1,40 @@ +/***************************************************************************** +* +* host_driver_version.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_HOST_DRIVER_VERSION_H__ +#define __CC3000_HOST_DRIVER_VERSION_H__ + +#define DRIVER_VERSION_NUMBER 15 + +#endif // __CC3000_HOST_DRIVER_VERSION_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/inet_ntop.h b/src/openmv/src/micropython/drivers/cc3000/inc/inet_ntop.h new file mode 100755 index 0000000..fa70806 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/inet_ntop.h @@ -0,0 +1,4 @@ +#ifndef __INET_NTOP_H +#define __INET_NTOP_H +char *inet_ntop(int af, const void *addr, char *buf, size_t size); +#endif /* __INET_NTOP_H */ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/inet_pton.h b/src/openmv/src/micropython/drivers/cc3000/inc/inet_pton.h new file mode 100755 index 0000000..0896d5d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/inet_pton.h @@ -0,0 +1,4 @@ +#ifndef __INET_PTON_H +#define __INET_PTON_H +int inet_pton(int, const char *, void *); +#endif /* __INET_PTON_H */ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/netapp.h b/src/openmv/src/micropython/drivers/cc3000/inc/netapp.h new file mode 100755 index 0000000..1e4f265 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/netapp.h @@ -0,0 +1,343 @@ +/***************************************************************************** +* +* netapp.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_NETAPP_H__ +#define __CC3000_NETAPP_H__ + +#include "data_types.h" + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +//***************************************************************************** +// +//! \addtogroup netapp_api +//! @{ +// +//***************************************************************************** + +typedef struct _netapp_dhcp_ret_args_t +{ + UINT8 aucIP[4]; + UINT8 aucSubnetMask[4]; + UINT8 aucDefaultGateway[4]; + UINT8 aucDHCPServer[4]; + UINT8 aucDNSServer[4]; +}tNetappDhcpParams; + +typedef struct _netapp_ipconfig_ret_args_t +{ + UINT8 aucIP[4]; + UINT8 aucSubnetMask[4]; + UINT8 aucDefaultGateway[4]; + UINT8 aucDHCPServer[4]; + UINT8 aucDNSServer[4]; + UINT8 uaMacAddr[6]; + UINT8 uaSSID[32]; +}tNetappIpconfigRetArgs; + + +/*Ping send report parameters*/ +typedef struct _netapp_pingreport_args +{ + UINT32 packets_sent; + UINT32 packets_received; + UINT32 min_round_time; + UINT32 max_round_time; + UINT32 avg_round_time; +} netapp_pingreport_args_t; + + +//***************************************************************************** +// +//! netapp_config_mac_adrress +//! +//! @param mac device mac address, 6 bytes. Saved: yes +//! +//! @return return on success 0, otherwise error. +//! +//! @brief Configure device MAC address and store it in NVMEM. +//! The value of the MAC address configured through the API will +//! be stored in CC3000 non volatile memory, thus preserved +//! over resets. +// +//***************************************************************************** +extern INT32 netapp_config_mac_adrress( UINT8 *mac ); + +//***************************************************************************** +// +//! netapp_dhcp +//! +//! @param aucIP device mac address, 6 bytes. Saved: yes +//! @param aucSubnetMask device mac address, 6 bytes. Saved: yes +//! @param aucDefaultGateway device mac address, 6 bytes. Saved: yes +//! @param aucDNSServer device mac address, 6 bytes. Saved: yes +//! +//! @return return on success 0, otherwise error. +//! +//! @brief netapp_dhcp is used to configure the network interface, +//! static or dynamic (DHCP).\n In order to activate DHCP mode, +//! aucIP, aucSubnetMask, aucDefaultGateway must be 0. +//! The default mode of CC3000 is DHCP mode. +//! Note that the configuration is saved in non volatile memory +//! and thus preserved over resets. +//! +//! @note If the mode is altered a reset of CC3000 device is required +//! in order to apply changes.\nAlso note that asynchronous event +//! of DHCP_EVENT, which is generated when an IP address is +//! allocated either by the DHCP server or due to static +//! allocation is generated only upon a connection to the +//! AP was established. +//! +//***************************************************************************** +extern INT32 netapp_dhcp(UINT32 *aucIP, UINT32 *aucSubnetMask,UINT32 *aucDefaultGateway, UINT32 *aucDNSServer); + + + +//***************************************************************************** +// +//! netapp_timeout_values +//! +//! @param aucDHCP DHCP lease time request, also impact +//! the DHCP renew timeout. Range: [0-0xffffffff] seconds, +//! 0 or 0xffffffff == infinity lease timeout. +//! Resolution:10 seconds. Influence: only after +//! reconnecting to the AP. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 seconds. +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 14400 seconds. +//! +//! @param aucARP ARP refresh timeout, if ARP entry is not updated by +//! incoming packet, the ARP entry will be deleted by +//! the end of the timeout. +//! Range: [0-0xffffffff] seconds, 0 == infinity ARP timeout +//! Resolution: 10 seconds. Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 seconds +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 3600 seconds. +//! +//! @param aucKeepalive Keepalive event sent by the end of keepalive timeout +//! Range: [0-0xffffffff] seconds, 0 == infinity timeout +//! Resolution: 10 seconds. +//! Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 sec +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 10 seconds. +//! +//! @param aucInactivity Socket inactivity timeout, socket timeout is +//! refreshed by incoming or outgoing packet, by the +//! end of the socket timeout the socket will be closed +//! Range: [0-0xffffffff] sec, 0 == infinity timeout. +//! Resolution: 10 seconds. Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 sec +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 60 seconds. +//! +//! @return return on success 0, otherwise error. +//! +//! @brief Set new timeout values. Function set new timeout values for: +//! DHCP lease timeout, ARP refresh timeout, keepalive event +//! timeout and socket inactivity timeout +//! +//! @note If a parameter set to non zero value which is less than 10s, +//! it will be set automatically to 10s. +//! +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern INT32 netapp_timeout_values(UINT32 *aucDHCP, UINT32 *aucARP, UINT32 *aucKeepalive, UINT32 *aucInactivity); +#endif + +//***************************************************************************** +// +//! netapp_ping_send +//! +//! @param ip destination IP address +//! @param pingAttempts number of echo requests to send +//! @param pingSize send buffer size which may be up to 1400 bytes +//! @param pingTimeout Time to wait for a response,in milliseconds. +//! +//! @return return on success 0, otherwise error. +//! +//! @brief send ICMP ECHO_REQUEST to network hosts +//! +//! @note If an operation finished successfully asynchronous ping report +//! event will be generated. The report structure is as defined +//! by structure netapp_pingreport_args_t. +//! +//! @warning Calling this function while a previous Ping Requests are in +//! progress will stop the previous ping request. +//***************************************************************************** + + #ifndef CC3000_TINY_DRIVER +extern INT32 netapp_ping_send(UINT32 *ip, UINT32 ulPingAttempts, UINT32 ulPingSize, UINT32 ulPingTimeout); +#endif + +//***************************************************************************** +// +//! netapp_ping_stop +//! +//! @param none +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief Stop any ping request. +//! +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +extern INT32 netapp_ping_stop(); +#endif +//***************************************************************************** +// +//! netapp_ping_report +//! +//! @param none +//! +//! @return none +//! +//! @brief Request for ping status. This API triggers the CC3000 to send +//! asynchronous events: HCI_EVNT_WLAN_ASYNC_PING_REPORT. +//! This event will carry the report structure: +//! netapp_pingreport_args_t. This structure is filled in with ping +//! results up till point of triggering API. +//! netapp_pingreport_args_t:\n packets_sent - echo sent, +//! packets_received - echo reply, min_round_time - minimum +//! round time, max_round_time - max round time, +//! avg_round_time - average round time +//! +//! @note When a ping operation is not active, the returned structure +//! fields are 0. +//! +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern void netapp_ping_report(); +#endif + + +//***************************************************************************** +// +//! netapp_ipconfig +//! +//! @param[out] ipconfig This argument is a pointer to a +//! tNetappIpconfigRetArgs structure. This structure is +//! filled in with the network interface configuration. +//! tNetappIpconfigRetArgs:\n aucIP - ip address, +//! aucSubnetMask - mask, aucDefaultGateway - default +//! gateway address, aucDHCPServer - dhcp server address +//! aucDNSServer - dns server address, uaMacAddr - mac +//! address, uaSSID - connected AP ssid +//! +//! @return none +//! +//! @brief Obtain the CC3000 Network interface information. +//! Note that the information is available only after the WLAN +//! connection was established. Calling this function before +//! associated, will cause non-defined values to be returned. +//! +//! @note The function is useful for figuring out the IP Configuration of +//! the device when DHCP is used and for figuring out the SSID of +//! the Wireless network the device is associated with. +//! +//***************************************************************************** + +extern void netapp_ipconfig( tNetappIpconfigRetArgs * ipconfig ); + + +//***************************************************************************** +// +//! netapp_arp_flush +//! +//! @param none +//! +//! @return none +//! +//! @brief Flushes ARP table +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +extern INT32 netapp_arp_flush(); +#endif + + +//***************************************************************************** +// +//! netapp_set_debug_level +//! +//! @param[in] level debug level. Bitwise [0-8], +//! 0(disable)or 1(enable).\n Bitwise map: 0 - Critical +//! message, 1 information message, 2 - core messages, 3 - +//! HCI messages, 4 - Network stack messages, 5 - wlan +//! messages, 6 - wlan driver messages, 7 - epprom messages, +//! 8 - general messages. Default: 0x13f. Saved: no +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Debug messages sent via the UART debug channel, this function +//! enable/disable the debug level +//! +//***************************************************************************** + + +#ifndef CC3000_TINY_DRIVER +INT32 netapp_set_debug_level(UINT32 ulLevel); +#endif +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_NETAPP_H__ + diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/nvmem.h b/src/openmv/src/micropython/drivers/cc3000/inc/nvmem.h new file mode 100755 index 0000000..b99a2e7 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/nvmem.h @@ -0,0 +1,248 @@ +/***************************************************************************** +* +* nvmem.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_NVRAM_H__ +#define __CC3000_NVRAM_H__ + +#include "cc3000_common.h" + + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + + +//***************************************************************************** +// +//! \addtogroup nvmem_api +//! @{ +// +//***************************************************************************** + +/**************************************************************************** +** +** Definitions for File IDs +** +****************************************************************************/ +/* NVMEM file ID - system files*/ +#define NVMEM_NVS_FILEID (0) +#define NVMEM_NVS_SHADOW_FILEID (1) +#define NVMEM_WLAN_CONFIG_FILEID (2) +#define NVMEM_WLAN_CONFIG_SHADOW_FILEID (3) +#define NVMEM_WLAN_DRIVER_SP_FILEID (4) +#define NVMEM_WLAN_FW_SP_FILEID (5) +#define NVMEM_MAC_FILEID (6) +#define NVMEM_FRONTEND_VARS_FILEID (7) +#define NVMEM_IP_CONFIG_FILEID (8) +#define NVMEM_IP_CONFIG_SHADOW_FILEID (9) +#define NVMEM_BOOTLOADER_SP_FILEID (10) +#define NVMEM_RM_FILEID (11) + +/* NVMEM file ID - user files*/ +#define NVMEM_AES128_KEY_FILEID (12) +#define NVMEM_SHARED_MEM_FILEID (13) + +/* max entry in order to invalid nvmem */ +#define NVMEM_MAX_ENTRY (16) + + +//***************************************************************************** +// +//! nvmem_read +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_NVS_FILEID, NVMEM_NVS_SHADOW_FILEID, +//! NVMEM_WLAN_CONFIG_FILEID, NVMEM_WLAN_CONFIG_SHADOW_FILEID, +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! NVMEM_MAC_FILEID, NVMEM_FRONTEND_VARS_FILEID, +//! NVMEM_IP_CONFIG_FILEID, NVMEM_IP_CONFIG_SHADOW_FILEID, +//! NVMEM_BOOTLOADER_SP_FILEID, NVMEM_RM_FILEID, +//! and user files 12-15. +//! @param ulLength number of bytes to read +//! @param ulOffset ulOffset in file from where to read +//! @param buff output buffer pointer +//! +//! @return on success 0, error otherwise. +//! +//! @brief Reads data from the file referred by the ulFileId parameter. +//! Reads data from file ulOffset till length. Err if the file can't +//! be used, is invalid, or if the read is out of bounds. +//! +//***************************************************************************** + +extern INT32 nvmem_read(UINT32 file_id, UINT32 length, UINT32 offset, UINT8 *buff); + +//***************************************************************************** +// +//! nvmem_write +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! NVMEM_MAC_FILEID, NVMEM_BOOTLOADER_SP_FILEID, +//! and user files 12-15. +//! @param ulLength number of bytes to write +//! @param ulEntryOffset offset in file to start write operation from +//! @param buff data to write +//! +//! @return on success 0, error otherwise. +//! +//! @brief Write data to nvmem. +//! writes data to file referred by the ulFileId parameter. +//! Writes data to file ulOffset till ulLength.The file id will be +//! marked invalid till the write is done. The file entry doesn't +//! need to be valid - only allocated. +//! +//***************************************************************************** + +extern INT32 nvmem_write(UINT32 ulFileId, UINT32 ulLength, UINT32 ulEntryOffset, UINT8 *buff); + + +//***************************************************************************** +// +//! nvmem_set_mac_address +//! +//! @param mac mac address to be set +//! +//! @return on success 0, error otherwise. +//! +//! @brief Write MAC address to EEPROM. +//! mac address as appears over the air (OUI first) +//! +//***************************************************************************** +extern UINT8 nvmem_set_mac_address(UINT8 *mac); + + +//***************************************************************************** +// +//! nvmem_get_mac_address +//! +//! @param[out] mac mac address +//! +//! @return on success 0, error otherwise. +//! +//! @brief Read MAC address from EEPROM. +//! mac address as appears over the air (OUI first) +//! +//***************************************************************************** +extern UINT8 nvmem_get_mac_address(UINT8 *mac); + + +//***************************************************************************** +// +//! nvmem_write_patch +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! @param spLength number of bytes to write +//! @param spData SP data to write +//! +//! @return on success 0, error otherwise. +//! +//! @brief program a patch to a specific file ID. +//! The SP data is assumed to be organized in 2-dimensional. +//! Each line is SP_PORTION_SIZE bytes long. Actual programming is +//! applied in SP_PORTION_SIZE bytes portions. +//! +//***************************************************************************** +extern UINT8 nvmem_write_patch(UINT32 ulFileId, UINT32 spLength, const UINT8 *spData); + + +//***************************************************************************** +// +//! nvmem_read_sp_version +//! +//! @param[out] patchVer first number indicates package ID and the second +//! number indicates package build number +//! +//! @return on success 0, error otherwise. +//! +//! @brief Read patch version. read package version (WiFi FW patch, +//! driver-supplicant-NS patch, bootloader patch) +//! +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern UINT8 nvmem_read_sp_version(UINT8* patchVer); +#endif + +//***************************************************************************** +// +//! nvmem_create_entry +//! +//! @param ulFileId nvmem file Id:\n +//! * NVMEM_AES128_KEY_FILEID: 12 +//! * NVMEM_SHARED_MEM_FILEID: 13 +//! * and fileIDs 14 and 15 +//! @param ulNewLen entry ulLength +//! +//! @return on success 0, error otherwise. +//! +//! @brief Create new file entry and allocate space on the NVMEM. +//! Applies only to user files. +//! Modify the size of file. +//! If the entry is unallocated - allocate it to size +//! ulNewLen (marked invalid). +//! If it is allocated then deallocate it first. +//! To just mark the file as invalid without resizing - +//! set ulNewLen=0. +//! +//***************************************************************************** +extern INT32 nvmem_create_entry(UINT32 file_id, UINT32 newlen); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** + + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_NVRAM_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/patch_prog.h b/src/openmv/src/micropython/drivers/cc3000/inc/patch_prog.h new file mode 100755 index 0000000..0a141a0 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/patch_prog.h @@ -0,0 +1,11 @@ +#ifndef __CC3000_PATCH_PROG_H__ +#define __CC3000_PATCH_PROG_H__ +extern unsigned short fw_length; +extern const unsigned char fw_patch[]; + +extern unsigned short drv_length; +extern const unsigned char wlan_drv_patch[]; +extern const unsigned char cRMdefaultParams[128]; + +void patch_prog_start(); +#endif //__CC3000_PATCH_PROG_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/security.h b/src/openmv/src/micropython/drivers/cc3000/inc/security.h new file mode 100755 index 0000000..cd1baf5 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/security.h @@ -0,0 +1,130 @@ +/***************************************************************************** +* +* security.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_SECURITY__ +#define __CC3000_SECURITY__ + +#include "nvmem.h" + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + + +#define AES128_KEY_SIZE 16 + +#ifndef CC3000_UNENCRYPTED_SMART_CONFIG + + +//***************************************************************************** +// +//! aes_encrypt +//! +//! @param[in] key AES128 key of size 16 bytes +//! @param[in\out] state 16 bytes of plain text and cipher text +//! +//! @return none +//! +//! @brief AES128 encryption: +//! Given AES128 key and 16 bytes plain text, cipher text of 16 bytes +//! is computed. The AES implementation is in mode ECB (Electronic +//! Code Book). +//! +//! +//***************************************************************************** +extern void aes_encrypt(UINT8 *state, UINT8 *key); + +//***************************************************************************** +// +//! aes_decrypt +//! +//! @param[in] key AES128 key of size 16 bytes +//! @param[in\out] state 16 bytes of cipher text and plain text +//! +//! @return none +//! +//! @brief AES128 decryption: +//! Given AES128 key and 16 bytes cipher text, plain text of 16 bytes +//! is computed The AES implementation is in mode ECB +//! (Electronic Code Book). +//! +//! +//***************************************************************************** +extern void aes_decrypt(UINT8 *state, UINT8 *key); + + +//***************************************************************************** +// +//! aes_read_key +//! +//! @param[out] key AES128 key of size 16 bytes +//! +//! @return on success 0, error otherwise. +//! +//! @brief Reads AES128 key from EEPROM +//! Reads the AES128 key from fileID #12 in EEPROM +//! returns an error if the key does not exist. +//! +//! +//***************************************************************************** +extern INT32 aes_read_key(UINT8 *key); + +//***************************************************************************** +// +//! aes_write_key +//! +//! @param[out] key AES128 key of size 16 bytes +//! +//! @return on success 0, error otherwise. +//! +//! @brief writes AES128 key from EEPROM +//! Writes the AES128 key to fileID #12 in EEPROM +//! +//! +//***************************************************************************** +extern INT32 aes_write_key(UINT8 *key); + +#endif //CC3000_UNENCRYPTED_SMART_CONFIG + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/socket.h b/src/openmv/src/micropython/drivers/cc3000/inc/socket.h new file mode 100755 index 0000000..96c814b --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/socket.h @@ -0,0 +1,676 @@ +/***************************************************************************** +* +* socket.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_SOCKET_H__ +#define __CC3000_SOCKET_H__ + +#include "cc3000_common.h" + +//***************************************************************************** +// +//! \addtogroup socket_api +//! @{ +// +//***************************************************************************** + + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +#define HOSTNAME_MAX_LENGTH (230) // 230 bytes + header shouldn't exceed 8 bit value + +//--------- Address Families -------- + +#define AF_INET 2 +#define AF_INET6 23 + +//------------ Socket Types ------------ + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 // Raw sockets allow new IPv4 protocols to be implemented in user space. A raw socket receives or sends the raw datagram not including link level headers +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 + +//----------- Socket Protocol ---------- + +#define IPPROTO_IP 0 // dummy for IP +#define IPPROTO_ICMP 1 // control message protocol +#define IPPROTO_IPV4 IPPROTO_IP // IP inside IP +#define IPPROTO_TCP 6 // tcp +#define IPPROTO_UDP 17 // user datagram protocol +#define IPPROTO_IPV6 41 // IPv6 in IPv6 +#define IPPROTO_NONE 59 // No next header +#define IPPROTO_RAW 255 // raw IP packet +#define IPPROTO_MAX 256 + +//----------- Socket retunr codes ----------- + +#define SOC_ERROR (-1) // error +#define SOC_IN_PROGRESS (-2) // socket in progress + +//----------- Socket Options ----------- +#define SOL_SOCKET 0xffff // socket level +#define SOCKOPT_RECV_NONBLOCK 0 // recv non block mode, set SOCK_ON or SOCK_OFF (default block mode) +#define SOCKOPT_RECV_TIMEOUT 1 // optname to configure recv and recvfromtimeout +#define SOCKOPT_ACCEPT_NONBLOCK 2 // accept non block mode, set SOCK_ON or SOCK_OFF (default block mode) +#define SOCK_ON 0 // socket non-blocking mode is enabled +#define SOCK_OFF 1 // socket blocking mode is enabled + +#define MAX_PACKET_SIZE 1500 +#define MAX_LISTEN_QUEUE 4 + +#define IOCTL_SOCKET_EVENTMASK + +#define ENOBUFS 55 // No buffer space available + +#define __FD_SETSIZE 32 + +#define ASIC_ADDR_LEN 8 + +#define NO_QUERY_RECIVED -3 + + +typedef struct _in_addr_t +{ + UINT32 s_addr; // load with inet_aton() +} in_addr; + +typedef struct _sockaddr_t +{ + UINT16 sa_family; + UINT8 sa_data[14]; +} sockaddr; + +typedef struct _sockaddr_in_t +{ + INT16 sin_family; // e.g. AF_INET + UINT16 sin_port; // e.g. htons(3490) + in_addr sin_addr; // see struct in_addr, below + CHAR sin_zero[8]; // zero this if you want to +} sockaddr_in; + +typedef UINT32 socklen_t; + +// The fd_set member is required to be an array of INT32s. +typedef INT32 __fd_mask; + +// It's easier to assume 8-bit bytes than to get CHAR_BIT. +#define __NFDBITS (8 * sizeof (__fd_mask)) +#define __FDELT(d) ((d) / __NFDBITS) +#define __FDMASK(d) ((__fd_mask) 1 << ((d) % __NFDBITS)) + +// fd_set for select and pselect. +typedef struct +{ + __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; +#define __FDS_BITS(set) ((set)->fds_bits) +} fd_set; + +// We don't use `memset' because this would require a prototype and +// the array isn't too big. +#define __FD_ZERO(set) \ + do { \ + UINT16 __i; \ + fd_set *__arr = (set); \ + for (__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) \ + __FDS_BITS (__arr)[__i] = 0; \ + } while (0) +#define __FD_SET(d, set) (__FDS_BITS (set)[__FDELT (d)] |= __FDMASK (d)) +#define __FD_CLR(d, set) (__FDS_BITS (set)[__FDELT (d)] &= ~__FDMASK (d)) +#define __FD_ISSET(d, set) (__FDS_BITS (set)[__FDELT (d)] & __FDMASK (d)) + +// Access macros for 'fd_set'. +#define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp) +#define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp) +#define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp) +#define FD_ZERO(fdsetp) __FD_ZERO (fdsetp) + +//Use in case of Big Endian only + +#define htonl(A) ((((UINT32)(A) & 0xff000000) >> 24) | \ + (((UINT32)(A) & 0x00ff0000) >> 8) | \ + (((UINT32)(A) & 0x0000ff00) << 8) | \ + (((UINT32)(A) & 0x000000ff) << 24)) + +#define ntohl htonl + +//Use in case of Big Endian only +#define htons(A) ((((UINT32)(A) & 0xff00) >> 8) | \ + (((UINT32)(A) & 0x00ff) << 8)) + + +#define ntohs htons + +// mDNS port - 5353 mDNS multicast address - 224.0.0.251 +#define SET_mDNS_ADD(sockaddr) sockaddr.sa_data[0] = 0x14; \ + sockaddr.sa_data[1] = 0xe9; \ + sockaddr.sa_data[2] = 0xe0; \ + sockaddr.sa_data[3] = 0x0; \ + sockaddr.sa_data[4] = 0x0; \ + sockaddr.sa_data[5] = 0xfb; + + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** + +//***************************************************************************** +// +//! socket +//! +//! @param domain selects the protocol family which will be used for +//! communication. On this version only AF_INET is supported +//! @param type specifies the communication semantics. On this version +//! only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW are supported +//! @param protocol specifies a particular protocol to be used with the +//! socket IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW are +//! supported. +//! +//! @return On success, socket handle that is used for consequent socket +//! operations. On error, -1 is returned. +//! +//! @brief create an endpoint for communication +//! The socket function creates a socket that is bound to a specific +//! transport service provider. This function is called by the +//! application layer to obtain a socket handle. +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(socket)(INT32 domain, INT32 type, INT32 protocol); + +//***************************************************************************** +// +//! closesocket +//! +//! @param sd socket handle. +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief The socket function closes a created socket. +// +//***************************************************************************** +extern INT32 CC3000_EXPORT(closesocket)(INT32 sd); + +//***************************************************************************** +// +//! accept +//! +//! @param[in] sd socket descriptor (handle) +//! @param[out] addr the argument addr is a pointer to a sockaddr structure +//! This structure is filled in with the address of the +//! peer socket, as known to the communications layer. +//! determined. The exact format of the address returned +//! addr is by the socket's address sockaddr. +//! On this version only AF_INET is supported. +//! This argument returns in network order. +//! @param[out] addrlen the addrlen argument is a value-result argument: +//! it should initially contain the size of the structure +//! pointed to by addr. +//! +//! @return For socket in blocking mode: +//! On success, socket handle. on failure negative +//! For socket in non-blocking mode: +//! - On connection establishment, socket handle +//! - On connection pending, SOC_IN_PROGRESS (-2) +//! - On failure, SOC_ERROR (-1) +//! +//! @brief accept a connection on a socket: +//! This function is used with connection-based socket types +//! (SOCK_STREAM). It extracts the first connection request on the +//! queue of pending connections, creates a new connected socket, and +//! returns a new file descriptor referring to that socket. +//! The newly created socket is not in the listening state. +//! The original socket sd is unaffected by this call. +//! The argument sd is a socket that has been created with socket(), +//! bound to a local address with bind(), and is listening for +//! connections after a listen(). The argument addr is a pointer +//! to a sockaddr structure. This structure is filled in with the +//! address of the peer socket, as known to the communications layer. +//! The exact format of the address returned addr is determined by the +//! socket's address family. The addrlen argument is a value-result +//! argument: it should initially contain the size of the structure +//! pointed to by addr, on return it will contain the actual +//! length (in bytes) of the address returned. +//! +//! @sa socket ; bind ; listen +// +//***************************************************************************** +extern INT32 CC3000_EXPORT(accept)(INT32 sd, sockaddr *addr, socklen_t *addrlen); + +//***************************************************************************** +// +//! bind +//! +//! @param[in] sd socket descriptor (handle) +//! @param[out] addr specifies the destination address. On this version +//! only AF_INET is supported. +//! @param[out] addrlen contains the size of the structure pointed to by addr. +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief assign a name to a socket +//! This function gives the socket the local address addr. +//! addr is addrlen bytes long. Traditionally, this is called when a +//! socket is created with socket, it exists in a name space (address +//! family) but has no name assigned. +//! It is necessary to assign a local address before a SOCK_STREAM +//! socket may receive connections. +//! +//! @sa socket ; accept ; listen +// +//***************************************************************************** +extern INT32 CC3000_EXPORT(bind)(INT32 sd, const sockaddr *addr, INT32 addrlen); + +//***************************************************************************** +// +//! listen +//! +//! @param[in] sd socket descriptor (handle) +//! @param[in] backlog specifies the listen queue depth. On this version +//! backlog is not supported. +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief listen for connections on a socket +//! The willingness to accept incoming connections and a queue +//! limit for incoming connections are specified with listen(), +//! and then the connections are accepted with accept. +//! The listen() call applies only to sockets of type SOCK_STREAM +//! The backlog parameter defines the maximum length the queue of +//! pending connections may grow to. +//! +//! @sa socket ; accept ; bind +//! +//! @note On this version, backlog is not supported +// +//***************************************************************************** +extern INT32 CC3000_EXPORT(listen)(INT32 sd, INT32 backlog); + +//***************************************************************************** +// +//! gethostbyname +//! +//! @param[in] hostname host name +//! @param[in] usNameLen name length +//! @param[out] out_ip_addr This parameter is filled in with host IP address. +//! In case that host name is not resolved, +//! out_ip_addr is zero. +//! @return On success, positive is returned. On error, negative is returned +//! +//! @brief Get host IP by name. Obtain the IP Address of machine on network, +//! by its name. +//! +//! @note On this version, only blocking mode is supported. Also note that +//! the function requires DNS server to be configured prior to its usage. +// +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern INT16 CC3000_EXPORT(gethostbyname)(CHAR * hostname, UINT16 usNameLen, UINT32* out_ip_addr); +#endif + + +//***************************************************************************** +// +//! connect +//! +//! @param[in] sd socket descriptor (handle) +//! @param[in] addr specifies the destination addr. On this version +//! only AF_INET is supported. +//! @param[out] addrlen contains the size of the structure pointed to by addr +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief initiate a connection on a socket +//! Function connects the socket referred to by the socket descriptor +//! sd, to the address specified by addr. The addrlen argument +//! specifies the size of addr. The format of the address in addr is +//! determined by the address space of the socket. If it is of type +//! SOCK_DGRAM, this call specifies the peer with which the socket is +//! to be associated; this address is that to which datagrams are to be +//! sent, and the only address from which datagrams are to be received. +//! If the socket is of type SOCK_STREAM, this call attempts to make a +//! connection to another socket. The other socket is specified by +//! address, which is an address in the communications space of the +//! socket. Note that the function implements only blocking behavior +//! thus the caller will be waiting either for the connection +//! establishment or for the connection establishment failure. +//! +//! @sa socket +// +//***************************************************************************** +extern INT32 CC3000_EXPORT(connect)(INT32 sd, const sockaddr *addr, INT32 addrlen); + +//***************************************************************************** +// +//! select +//! +//! @param[in] nfds the highest-numbered file descriptor in any of the +//! three sets, plus 1. +//! @param[out] writesds socket descriptors list for write monitoring +//! @param[out] readsds socket descriptors list for read monitoring +//! @param[out] exceptsds socket descriptors list for exception monitoring +//! @param[in] timeout is an upper bound on the amount of time elapsed +//! before select() returns. Null means infinity +//! timeout. The minimum timeout is 5 milliseconds, +//! less than 5 milliseconds will be set +//! automatically to 5 milliseconds. +//! @return On success, select() returns the number of file descriptors +//! contained in the three returned descriptor sets (that is, the +//! total number of bits that are set in readfds, writefds, +//! exceptfds) which may be zero if the timeout expires before +//! anything interesting happens. +//! On error, -1 is returned. +//! *readsds - return the sockets on which Read request will +//! return without delay with valid data. +//! *writesds - return the sockets on which Write request +//! will return without delay. +//! *exceptsds - return the sockets which closed recently. +//! +//! @brief Monitor socket activity +//! Select allow a program to monitor multiple file descriptors, +//! waiting until one or more of the file descriptors become +//! "ready" for some class of I/O operation +//! +//! @Note If the timeout value set to less than 5ms it will automatically set +//! to 5ms to prevent overload of the system +//! +//! @sa socket +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(select)(INT32 nfds, fd_set *readsds, fd_set *writesds, + fd_set *exceptsds, struct cc3000_timeval *timeout); + +//***************************************************************************** +// +//! setsockopt +//! +//! @param[in] sd socket handle +//! @param[in] level defines the protocol level for this option +//! @param[in] optname defines the option name to Interrogate +//! @param[in] optval specifies a value for the option +//! @param[in] optlen specifies the length of the option value +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief set socket options +//! This function manipulate the options associated with a socket. +//! Options may exist at multiple protocol levels; they are always +//! present at the uppermost socket level. +//! When manipulating socket options the level at which the option +//! resides and the name of the option must be specified. +//! To manipulate options at the socket level, level is specified as +//! SOL_SOCKET. To manipulate options at any other level the protocol +//! number of the appropriate protocol controlling the option is +//! supplied. For example, to indicate that an option is to be +//! interpreted by the TCP protocol, level should be set to the +//! protocol number of TCP; +//! The parameters optval and optlen are used to access optval - +//! use for setsockopt(). For getsockopt() they identify a buffer +//! in which the value for the requested option(s) are to +//! be returned. For getsockopt(), optlen is a value-result +//! parameter, initially containing the size of the buffer +//! pointed to by option_value, and modified on return to +//! indicate the actual size of the value returned. If no option +//! value is to be supplied or returned, option_value may be NULL. +//! +//! @Note On this version the following two socket options are enabled: +//! The only protocol level supported in this version +//! is SOL_SOCKET (level). +//! 1. SOCKOPT_RECV_TIMEOUT (optname) +//! SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout +//! in milliseconds. +//! In that case optval should be pointer to UINT32. +//! 2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on +//! or off. +//! In that case optval should be SOCK_ON or SOCK_OFF (optval). +//! +//! @sa getsockopt +// +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern INT16 CC3000_EXPORT(setsockopt)(INT32 sd, INT32 level, INT32 optname, const void *optval, + socklen_t optlen); +#endif +//***************************************************************************** +// +//! getsockopt +//! +//! @param[in] sd socket handle +//! @param[in] level defines the protocol level for this option +//! @param[in] optname defines the option name to Interrogate +//! @param[out] optval specifies a value for the option +//! @param[out] optlen specifies the length of the option value +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief set socket options +//! This function manipulate the options associated with a socket. +//! Options may exist at multiple protocol levels; they are always +//! present at the uppermost socket level. +//! When manipulating socket options the level at which the option +//! resides and the name of the option must be specified. +//! To manipulate options at the socket level, level is specified as +//! SOL_SOCKET. To manipulate options at any other level the protocol +//! number of the appropriate protocol controlling the option is +//! supplied. For example, to indicate that an option is to be +//! interpreted by the TCP protocol, level should be set to the +//! protocol number of TCP; +//! The parameters optval and optlen are used to access optval - +//! use for setsockopt(). For getsockopt() they identify a buffer +//! in which the value for the requested option(s) are to +//! be returned. For getsockopt(), optlen is a value-result +//! parameter, initially containing the size of the buffer +//! pointed to by option_value, and modified on return to +//! indicate the actual size of the value returned. If no option +//! value is to be supplied or returned, option_value may be NULL. +//! +//! @Note On this version the following two socket options are enabled: +//! The only protocol level supported in this version +//! is SOL_SOCKET (level). +//! 1. SOCKOPT_RECV_TIMEOUT (optname) +//! SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout +//! in milliseconds. +//! In that case optval should be pointer to UINT32. +//! 2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on +//! or off. +//! In that case optval should be SOCK_ON or SOCK_OFF (optval). +//! +//! @sa setsockopt +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(getsockopt)(INT32 sd, INT32 level, INT32 optname, void *optval, + socklen_t *optlen); + +//***************************************************************************** +// +//! recv +//! +//! @param[in] sd socket handle +//! @param[out] buf Points to the buffer where the message should be stored +//! @param[in] len Specifies the length in bytes of the buffer pointed to +//! by the buffer argument. +//! @param[in] flags Specifies the type of message reception. +//! On this version, this parameter is not supported. +//! +//! @return Return the number of bytes received, or -1 if an error +//! occurred +//! +//! @brief function receives a message from a connection-mode socket +//! +//! @sa recvfrom +//! +//! @Note On this version, only blocking mode is supported. +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(recv)(INT32 sd, void *buf, INT32 len, INT32 flags); + +//***************************************************************************** +// +//! recvfrom +//! +//! @param[in] sd socket handle +//! @param[out] buf Points to the buffer where the message should be stored +//! @param[in] len Specifies the length in bytes of the buffer pointed to +//! by the buffer argument. +//! @param[in] flags Specifies the type of message reception. +//! On this version, this parameter is not supported. +//! @param[in] from pointer to an address structure indicating the source +//! address: sockaddr. On this version only AF_INET is +//! supported. +//! @param[in] fromlen source address structure size +//! +//! @return Return the number of bytes received, or -1 if an error +//! occurred +//! +//! @brief read data from socket +//! function receives a message from a connection-mode or +//! connectionless-mode socket. Note that raw sockets are not +//! supported. +//! +//! @sa recv +//! +//! @Note On this version, only blocking mode is supported. +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(recvfrom)(INT32 sd, void *buf, INT32 len, INT32 flags, sockaddr *from, + socklen_t *fromlen); + +//***************************************************************************** +// +//! send +//! +//! @param sd socket handle +//! @param buf Points to a buffer containing the message to be sent +//! @param len message size in bytes +//! @param flags On this version, this parameter is not supported +//! +//! @return Return the number of bytes transmitted, or -1 if an +//! error occurred +//! +//! @brief Write data to TCP socket +//! This function is used to transmit a message to another +//! socket. +//! +//! @Note On this version, only blocking mode is supported. +//! +//! @sa sendto +// +//***************************************************************************** + +extern INT16 CC3000_EXPORT(send)(INT32 sd, const void *buf, INT32 len, INT32 flags); + +//***************************************************************************** +// +//! sendto +//! +//! @param sd socket handle +//! @param buf Points to a buffer containing the message to be sent +//! @param len message size in bytes +//! @param flags On this version, this parameter is not supported +//! @param to pointer to an address structure indicating the destination +//! address: sockaddr. On this version only AF_INET is +//! supported. +//! @param tolen destination address structure size +//! +//! @return Return the number of bytes transmitted, or -1 if an +//! error occurred +//! +//! @brief Write data to TCP socket +//! This function is used to transmit a message to another +//! socket. +//! +//! @Note On this version, only blocking mode is supported. +//! +//! @sa send +// +//***************************************************************************** + +extern INT16 CC3000_EXPORT(sendto)(INT32 sd, const void *buf, INT32 len, INT32 flags, + const sockaddr *to, socklen_t tolen); + +//***************************************************************************** +// +//! mdnsAdvertiser +//! +//! @param[in] mdnsEnabled flag to enable/disable the mDNS feature +//! @param[in] deviceServiceName Service name as part of the published +//! canonical domain name +//! @param[in] deviceServiceNameLength Length of the service name - up to 32 chars +//! +//! +//! @return On success, zero is returned, return SOC_ERROR if socket was not +//! opened successfully, or if an error occurred. +//! +//! @brief Set CC3000 in mDNS advertiser mode in order to advertise itself. +// +//***************************************************************************** +extern INT16 CC3000_EXPORT(mdnsAdvertiser)(UINT16 mdnsEnabled, CHAR * deviceServiceName, UINT16 deviceServiceNameLength); + + +//***************************************************************************** +// +//! getmssvalue +//! +//! @param[in] sd socket descriptor +//! +//! @return On success, returns the MSS value of a TCP connection +//! +//! @brief Returns the MSS value of a TCP connection according to the socket descriptor +// +//***************************************************************************** +extern UINT16 CC3000_EXPORT(getmssvalue) (INT32 sd); + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __SOCKET_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/inc/wlan.h b/src/openmv/src/micropython/drivers/cc3000/inc/wlan.h new file mode 100755 index 0000000..48d195b --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/inc/wlan.h @@ -0,0 +1,518 @@ +/***************************************************************************** +* +* wlan.h - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 __CC3000_WLAN_H__ +#define __CC3000_WLAN_H__ + +#include "cc3000_common.h" + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" { +#endif + +#define WLAN_SEC_UNSEC (0) +#define WLAN_SEC_WEP (1) +#define WLAN_SEC_WPA (2) +#define WLAN_SEC_WPA2 (3) +//***************************************************************************** +// +//! \addtogroup wlan_api +//! @{ +// +//***************************************************************************** + + +//***************************************************************************** +// +//! wlan_init +//! +//! @param sWlanCB Asynchronous events callback. +//! 0 no event call back. +//! -call back parameters: +//! 1) event_type: HCI_EVNT_WLAN_UNSOL_CONNECT connect event, +//! HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event, +//! HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE config done, +//! HCI_EVNT_WLAN_UNSOL_DHCP dhcp report, +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report OR +//! HCI_EVNT_WLAN_KEEPALIVE keepalive. +//! 2) data: pointer to extra data that received by the event +//! (NULL no data). +//! 3) length: data length. +//! -Events with extra data: +//! HCI_EVNT_WLAN_UNSOL_DHCP: 4 bytes IP, 4 bytes Mask, +//! 4 bytes default gateway, 4 bytes DHCP server and 4 bytes +//! for DNS server. +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT: 4 bytes Packets sent, +//! 4 bytes Packets received, 4 bytes Min round time, +//! 4 bytes Max round time and 4 bytes for Avg round time. +//! +//! @param sFWPatches 0 no patch or pointer to FW patches +//! @param sDriverPatches 0 no patch or pointer to driver patches +//! @param sBootLoaderPatches 0 no patch or pointer to bootloader patches +//! @param sReadWlanInterruptPin init callback. the callback read wlan +//! interrupt status. +//! @param sWlanInterruptEnable init callback. the callback enable wlan +//! interrupt. +//! @param sWlanInterruptDisable init callback. the callback disable wlan +//! interrupt. +//! @param sWriteWlanPin init callback. the callback write value +//! to device pin. +//! +//! @return none +//! +//! @sa wlan_set_event_mask , wlan_start , wlan_stop +//! +//! @brief Initialize wlan driver +//! +//! @warning This function must be called before ANY other wlan driver function +// +//***************************************************************************** +extern void wlan_init( tWlanCB sWlanCB, + tFWPatches sFWPatches, + tDriverPatches sDriverPatches, + tBootLoaderPatches sBootLoaderPatches, + tWlanReadInteruptPin sReadWlanInterruptPin, + tWlanInterruptEnable sWlanInterruptEnable, + tWlanInterruptDisable sWlanInterruptDisable, + tWriteWlanPin sWriteWlanPin); + + + +//***************************************************************************** +// +//! wlan_start +//! +//! @param usPatchesAvailableAtHost - flag to indicate if patches available +//! from host or from EEPROM. Due to the +//! fact the patches are burn to the EEPROM +//! using the patch programmer utility, the +//! patches will be available from the EEPROM +//! and not from the host. +//! +//! @return none +//! +//! @brief Start WLAN device. This function asserts the enable pin of +//! the device (WLAN_EN), starting the HW initialization process. +//! The function blocked until device Initialization is completed. +//! Function also configure patches (FW, driver or bootloader) +//! and calls appropriate device callbacks. +//! +//! @Note Prior calling the function wlan_init shall be called. +//! @Warning This function must be called after wlan_init and before any +//! other wlan API +//! @sa wlan_init , wlan_stop +//! +// +//***************************************************************************** +extern int wlan_start(UINT16 usPatchesAvailableAtHost); + +//***************************************************************************** +// +//! wlan_stop +//! +//! @param none +//! +//! @return none +//! +//! @brief Stop WLAN device by putting it into reset state. +//! +//! @sa wlan_start +// +//***************************************************************************** +extern void wlan_stop(void); + +//***************************************************************************** +// +//! wlan_connect +//! +//! @param sec_type security options: +//! WLAN_SEC_UNSEC, +//! WLAN_SEC_WEP (ASCII support only), +//! WLAN_SEC_WPA or WLAN_SEC_WPA2 +//! @param ssid up to 32 bytes and is ASCII SSID of the AP +//! @param ssid_len length of the SSID +//! @param bssid 6 bytes specified the AP bssid +//! @param key up to 32 bytes specified the AP security key +//! @param key_len key length +//! +//! @return On success, zero is returned. On error, negative is returned. +//! Note that even though a zero is returned on success to trigger +//! connection operation, it does not mean that CCC3000 is already +//! connected. An asynchronous "Connected" event is generated when +//! actual association process finishes and CC3000 is connected to +//! the AP. If DHCP is set, An asynchronous "DHCP" event is +//! generated when DHCP process is finish. +//! +//! +//! @brief Connect to AP +//! @warning Please Note that when connection to AP configured with security +//! type WEP, please confirm that the key is set as ASCII and not +//! as HEX. +//! @sa wlan_disconnect +// +//***************************************************************************** +#ifndef CC3000_TINY_DRIVER +extern INT32 wlan_connect(UINT32 ulSecType, CHAR *ssid, INT32 ssid_len, + UINT8 *bssid, UINT8 *key, INT32 key_len); +#else +extern INT32 wlan_connect(CHAR *ssid, INT32 ssid_len); + +#endif + +//***************************************************************************** +// +//! wlan_disconnect +//! +//! @return 0 disconnected done, other CC3000 already disconnected +//! +//! @brief Disconnect connection from AP. +//! +//! @sa wlan_connect +// +//***************************************************************************** + +extern INT32 wlan_disconnect(void); + +//***************************************************************************** +// +//! wlan_add_profile +//! +//! @param ulSecType WLAN_SEC_UNSEC,WLAN_SEC_WEP,WLAN_SEC_WPA,WLAN_SEC_WPA2 +//! @param ucSsid ssid SSID up to 32 bytes +//! @param ulSsidLen ssid length +//! @param ucBssid bssid 6 bytes +//! @param ulPriority ulPriority profile priority. Lowest priority:0. +//! @param ulPairwiseCipher_Or_TxKeyLen key length for WEP security +//! @param ulGroupCipher_TxKeyIndex key index +//! @param ulKeyMgmt KEY management +//! @param ucPf_OrKey security key +//! @param ulPassPhraseLen security key length for WPA\WPA2 +//! +//! @return On success, index (1-7) of the stored profile is returned. +//! On error, -1 is returned. +//! +//! @brief When auto start is enabled, the device connects to +//! station from the profiles table. Up to 7 profiles are supported. +//! If several profiles configured the device choose the highest +//! priority profile, within each priority group, device will choose +//! profile based on security policy, signal strength, etc +//! parameters. All the profiles are stored in CC3000 NVMEM. +//! +//! @sa wlan_ioctl_del_profile +// +//***************************************************************************** + +extern INT32 wlan_add_profile(UINT32 ulSecType, UINT8* ucSsid, + UINT32 ulSsidLen, + UINT8 *ucBssid, + UINT32 ulPriority, + UINT32 ulPairwiseCipher_Or_Key, + UINT32 ulGroupCipher_TxKeyLen, + UINT32 ulKeyMgmt, + UINT8* ucPf_OrKey, + UINT32 ulPassPhraseLen); + + + +//***************************************************************************** +// +//! wlan_ioctl_del_profile +//! +//! @param index number of profile to delete +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Delete WLAN profile +//! +//! @Note In order to delete all stored profile, set index to 255. +//! +//! @sa wlan_add_profile +// +//***************************************************************************** +extern INT32 wlan_ioctl_del_profile(UINT32 ulIndex); + +//***************************************************************************** +// +//! wlan_set_event_mask +//! +//! @param mask mask option: +//! HCI_EVNT_WLAN_UNSOL_CONNECT connect event +//! HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event +//! HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE smart config done +//! HCI_EVNT_WLAN_UNSOL_INIT init done +//! HCI_EVNT_WLAN_UNSOL_DHCP dhcp event report +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report +//! HCI_EVNT_WLAN_KEEPALIVE keepalive +//! HCI_EVNT_WLAN_TX_COMPLETE - disable information on end of transmission +//! Saved: no. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Mask event according to bit mask. In case that event is +//! masked (1), the device will not send the masked event to host. +// +//***************************************************************************** +extern INT32 wlan_set_event_mask(UINT32 ulMask); + +//***************************************************************************** +// +//! wlan_ioctl_statusget +//! +//! @param none +//! +//! @return WLAN_STATUS_DISCONNECTED, WLAN_STATUS_SCANING, +//! STATUS_CONNECTING or WLAN_STATUS_CONNECTED +//! +//! @brief get wlan status: disconnected, scanning, connecting or connected +// +//***************************************************************************** +extern INT32 wlan_ioctl_statusget(void); + + +//***************************************************************************** +// +//! wlan_ioctl_set_connection_policy +//! +//! @param should_connect_to_open_ap enable(1), disable(0) connect to any +//! available AP. This parameter corresponds to the configuration of +//! item # 3 in the brief description. +//! @param should_use_fast_connect enable(1), disable(0). if enabled, tries +//! to connect to the last connected AP. This parameter corresponds +//! to the configuration of item # 1 in the brief description. +//! @param auto_start enable(1), disable(0) auto connect +//! after reset and periodically reconnect if needed. This +//! configuration configures option 2 in the above description. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief When auto is enabled, the device tries to connect according +//! the following policy: +//! 1) If fast connect is enabled and last connection is valid, +//! the device will try to connect to it without the scanning +//! procedure (fast). The last connection will be marked as +//! invalid, due to adding/removing profile. +//! 2) If profile exists, the device will try to connect it +//! (Up to seven profiles). +//! 3) If fast and profiles are not found, and open mode is +//! enabled, the device will try to connect to any AP. +//! * Note that the policy settings are stored in the CC3000 NVMEM. +//! +//! @sa wlan_add_profile , wlan_ioctl_del_profile +// +//***************************************************************************** +extern INT32 wlan_ioctl_set_connection_policy( + UINT32 should_connect_to_open_ap, + UINT32 should_use_fast_connect, + UINT32 ulUseProfiles); + +//***************************************************************************** +// +//! wlan_ioctl_get_scan_results +//! +//! @param[in] scan_timeout parameter not supported +//! @param[out] ucResults scan result (_wlan_full_scan_results_args_t) +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Gets entry from scan result table. +//! The scan results are returned one by one, and each entry +//! represents a single AP found in the area. The following is a +//! format of the scan result: +//! - 4 Bytes: number of networks found +//! - 4 Bytes: The status of the scan: 0 - aged results, +//! 1 - results valid, 2 - no results +//! - 42 bytes: Result entry, where the bytes are arranged as follows: +//! +//! - 1 bit isValid - is result valid or not +//! - 7 bits rssi - RSSI value; +//! - 2 bits: securityMode - security mode of the AP: +//! 0 - Open, 1 - WEP, 2 WPA, 3 WPA2 +//! - 6 bits: SSID name length +//! - 2 bytes: the time at which the entry has entered into +//! scans result table +//! - 32 bytes: SSID name +//! - 6 bytes: BSSID +//! +//! @Note scan_timeout, is not supported on this version. +//! +//! @sa wlan_ioctl_set_scan_params +// +//***************************************************************************** + + +extern INT32 wlan_ioctl_get_scan_results(UINT32 ulScanTimeout, + UINT8 *ucResults); + +//***************************************************************************** +// +//! wlan_ioctl_set_scan_params +//! +//! @param uiEnable - start/stop application scan: +//! 1 = start scan with default interval value of 10 min. +//! in order to set a different scan interval value apply the value +//! in milliseconds. minimum 1 second. 0=stop). Wlan reset +//! (wlan_stop() wlan_start()) is needed when changing scan interval +//! value. Saved: No +//! @param uiMinDwellTime minimum dwell time value to be used for each +//! channel, in milliseconds. Saved: yes +//! Recommended Value: 100 (Default: 20) +//! @param uiMaxDwellTime maximum dwell time value to be used for each +//! channel, in milliseconds. Saved: yes +//! Recommended Value: 100 (Default: 30) +//! @param uiNumOfProbeRequests max probe request between dwell time. +//! Saved: yes. Recommended Value: 5 (Default:2) +//! @param uiChannelMask bitwise, up to 13 channels (0x1fff). +//! Saved: yes. Default: 0x7ff +//! @param uiRSSIThreshold RSSI threshold. Saved: yes (Default: -80) +//! @param uiSNRThreshold NSR threshold. Saved: yes (Default: 0) +//! @param uiDefaultTxPower probe Tx power. Saved: yes (Default: 205) +//! @param aiIntervalList pointer to array with 16 entries (16 channels) +//! each entry (UINT32) holds timeout between periodic scan +//! (connection scan) - in milliseconds. Saved: yes. Default 2000ms. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief start and stop scan procedure. Set scan parameters. +//! +//! @Note uiDefaultTxPower, is not supported on this version. +//! +//! @sa wlan_ioctl_get_scan_results +// +//***************************************************************************** +extern INT32 wlan_ioctl_set_scan_params(UINT32 uiEnable, UINT32 + uiMinDwellTime,UINT32 uiMaxDwellTime, + UINT32 uiNumOfProbeRequests, + UINT32 uiChannelMask, + INT32 iRSSIThreshold,UINT32 uiSNRThreshold, + UINT32 uiDefaultTxPower, + UINT32 *aiIntervalList); + + +//***************************************************************************** +// +//! wlan_smart_config_start +//! +//! @param algoEncryptedFlag indicates whether the information is encrypted +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Start to acquire device profile. The device acquire its own +//! profile, if profile message is found. The acquired AP information +//! is stored in CC3000 EEPROM only in case AES128 encryption is used. +//! In case AES128 encryption is not used, a profile is created by +//! CC3000 internally. +//! +//! @Note An asynchronous event - Smart Config Done will be generated as soon +//! as the process finishes successfully. +//! +//! @sa wlan_smart_config_set_prefix , wlan_smart_config_stop +// +//***************************************************************************** +extern INT32 wlan_smart_config_start(UINT32 algoEncryptedFlag); + + +//***************************************************************************** +// +//! wlan_smart_config_stop +//! +//! @param algoEncryptedFlag indicates whether the information is encrypted +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Stop the acquire profile procedure +//! +//! @sa wlan_smart_config_start , wlan_smart_config_set_prefix +// +//***************************************************************************** +extern INT32 wlan_smart_config_stop(void); + +//***************************************************************************** +// +//! wlan_smart_config_set_prefix +//! +//! @param newPrefix 3 bytes identify the SSID prefix for the Smart Config. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Configure station ssid prefix. The prefix is used internally +//! in CC3000. It should always be TTT. +//! +//! @Note The prefix is stored in CC3000 NVMEM +//! +//! @sa wlan_smart_config_start , wlan_smart_config_stop +// +//***************************************************************************** +extern INT32 wlan_smart_config_set_prefix(CHAR* cNewPrefix); + +//***************************************************************************** +// +//! wlan_smart_config_process +//! +//! @param none +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief process the acquired data and store it as a profile. The acquired +//! AP information is stored in CC3000 EEPROM encrypted. +//! The encrypted data is decrypted and stored as a profile. +//! behavior is as defined by connection policy. +// +//***************************************************************************** +extern INT32 wlan_smart_config_process(void); + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __CC3000_WLAN_H__ diff --git a/src/openmv/src/micropython/drivers/cc3000/src/cc3000_common.c b/src/openmv/src/micropython/drivers/cc3000/src/cc3000_common.c new file mode 100755 index 0000000..b4c8784 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/cc3000_common.c @@ -0,0 +1,164 @@ +/***************************************************************************** +* +* cc3000_common.c.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ +//***************************************************************************** +// +//! \addtogroup common_api +//! @{ +// +//***************************************************************************** +/****************************************************************************** +* +* Include files +* +*****************************************************************************/ + +#include "cc3000_common.h" +#include "socket.h" +#include "wlan.h" +#include "evnt_handler.h" + +//***************************************************************************** +// +//! __error__ +//! +//! @param pcFilename - file name, where error occurred +//! @param ulLine - line number, where error occurred +//! +//! @return none +//! +//! @brief stub function for ASSERT macro +// +//***************************************************************************** +void __error__(CHAR *pcFilename, UINT32 ulLine) +{ + //TODO full up function +} + + + +//***************************************************************************** +// +//! UINT32_TO_STREAM_f +//! +//! @param p pointer to the new stream +//! @param u32 pointer to the 32 bit +//! +//! @return pointer to the new stream +//! +//! @brief This function is used for copying 32 bit to stream +//! while converting to little endian format. +// +//***************************************************************************** + +UINT8* UINT32_TO_STREAM_f (UINT8 *p, UINT32 u32) +{ + *(p)++ = (UINT8)(u32); + *(p)++ = (UINT8)((u32) >> 8); + *(p)++ = (UINT8)((u32) >> 16); + *(p)++ = (UINT8)((u32) >> 24); + return p; +} + +//***************************************************************************** +// +//! UINT16_TO_STREAM_f +//! +//! @param p pointer to the new stream +//! @param u32 pointer to the 16 bit +//! +//! @return pointer to the new stream +//! +//! @brief This function is used for copying 16 bit to stream +//! while converting to little endian format. +// +//***************************************************************************** + +UINT8* UINT16_TO_STREAM_f (UINT8 *p, UINT16 u16) +{ + *(p)++ = (UINT8)(u16); + *(p)++ = (UINT8)((u16) >> 8); + return p; +} + +//***************************************************************************** +// +//! STREAM_TO_UINT16_f +//! +//! @param p pointer to the stream +//! @param offset offset in the stream +//! +//! @return pointer to the new 16 bit +//! +//! @brief This function is used for copying received stream to +//! 16 bit in little endian format. +// +//***************************************************************************** + +UINT16 STREAM_TO_UINT16_f(CHAR* p, UINT16 offset) +{ + return (UINT16)((UINT16)((UINT16) + (*(p + offset + 1)) << 8) + (UINT16)(*(p + offset))); +} + +//***************************************************************************** +// +//! STREAM_TO_UINT32_f +//! +//! @param p pointer to the stream +//! @param offset offset in the stream +//! +//! @return pointer to the new 32 bit +//! +//! @brief This function is used for copying received stream to +//! 32 bit in little endian format. +// +//***************************************************************************** + +UINT32 STREAM_TO_UINT32_f(CHAR* p, UINT16 offset) +{ + return (UINT32)((UINT32)((UINT32) + (*(p + offset + 3)) << 24) + (UINT32)((UINT32) + (*(p + offset + 2)) << 16) + (UINT32)((UINT32) + (*(p + offset + 1)) << 8) + (UINT32)(*(p + offset))); +} + + + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3000/src/ccspi.c b/src/openmv/src/micropython/drivers/cc3000/src/ccspi.c new file mode 100755 index 0000000..1dcd618 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/ccspi.c @@ -0,0 +1,455 @@ +/***************************************************************************** + * + * spi.c - CC3000 Host Driver Implementation. + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 "py/runtime.h" +#include "pin.h" +#include "led.h" +#include "extint.h" +#include "spi.h" +#include "ccspi.h" +#include "evnt_handler.h" + +#if 0 // print debugging info +#include +#define DEBUG_printf(args...) printf(args) +#else // don't print debugging info +#define DEBUG_printf(args...) (void)0 +#endif + +// these need to be set to valid values before anything in this file will work +STATIC const spi_t *SPI_HANDLE = NULL; +STATIC const pin_obj_t *PIN_CS = NULL; +STATIC const pin_obj_t *PIN_EN = NULL; +STATIC const pin_obj_t *PIN_IRQ = NULL; + +#define CS_LOW() HAL_GPIO_WritePin(PIN_CS->gpio, PIN_CS->pin_mask, GPIO_PIN_RESET) +#define CS_HIGH() HAL_GPIO_WritePin(PIN_CS->gpio, PIN_CS->pin_mask, GPIO_PIN_SET) + +#define READ 3 +#define WRITE 1 + +#define HI(value) (((value) & 0xFF00) >> 8) +#define LO(value) ((value) & 0x00FF) + +#define SPI_TIMEOUT (1000) +#define HEADERS_SIZE_EVNT (SPI_HEADER_SIZE + 5) + +/* SPI bus states */ +#define eSPI_STATE_POWERUP (0) +#define eSPI_STATE_INITIALIZED (1) +#define eSPI_STATE_IDLE (2) +#define eSPI_STATE_WRITE_IRQ (3) +#define eSPI_STATE_WRITE_FIRST_PORTION (4) +#define eSPI_STATE_WRITE_EOT (5) +#define eSPI_STATE_READ_IRQ (6) +#define eSPI_STATE_READ_FIRST_PORTION (7) +#define eSPI_STATE_READ_EOT (8) + +// The magic number that resides at the end of the TX/RX buffer (1 byte after the allocated size) +// for the purpose of detection of the overrun. The location of the memory where the magic number +// resides shall never be written. In case it is written - the overrun occured and either recevie function +// or send function will stuck forever. +#define CC3000_BUFFER_MAGIC_NUMBER (0xDE) + +typedef struct { + gcSpiHandleRx SPIRxHandler; + unsigned short usTxPacketLength; + unsigned short usRxPacketLength; + unsigned long ulSpiState; + unsigned char *pTxPacket; + unsigned char *pRxPacket; +} tSpiInformation; +STATIC tSpiInformation sSpiInformation; + +STATIC char spi_buffer[CC3000_RX_BUFFER_SIZE]; +unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; + +STATIC const mp_obj_fun_builtin_fixed_t irq_callback_obj; + +// set the pins to use to communicate with the CC3000 +// the arguments must be of type pin_obj_t* and SPI_HandleTypeDef* +void SpiInit(void *spi, const void *pin_cs, const void *pin_en, const void *pin_irq) { + SPI_HANDLE = spi; + PIN_CS = pin_cs; + PIN_EN = pin_en; + PIN_IRQ = pin_irq; +} + +void SpiClose(void) +{ + if (sSpiInformation.pRxPacket) { + sSpiInformation.pRxPacket = 0; + } + + tSLInformation.WlanInterruptDisable(); + + //HAL_SPI_DeInit(SPI_HANDLE); +} + +void SpiOpen(gcSpiHandleRx pfRxHandler) +{ + DEBUG_printf("SpiOpen\n"); + + /* initialize SPI state */ + sSpiInformation.ulSpiState = eSPI_STATE_POWERUP; + sSpiInformation.SPIRxHandler = pfRxHandler; + sSpiInformation.usTxPacketLength = 0; + sSpiInformation.pTxPacket = NULL; + sSpiInformation.pRxPacket = (unsigned char *)spi_buffer; + sSpiInformation.usRxPacketLength = 0; + spi_buffer[CC3000_RX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; + wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; + + /* SPI configuration */ + SPI_InitTypeDef *init = &SPI_HANDLE->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; + init->CLKPhase = SPI_PHASE_2EDGE; + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; + spi_init(SPI_HANDLE, false); + + // configure wlan CS and EN pins + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Speed = GPIO_SPEED_FAST; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = 0; + + GPIO_InitStructure.Pin = PIN_CS->pin_mask; + HAL_GPIO_Init(PIN_CS->gpio, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = PIN_EN->pin_mask; + HAL_GPIO_Init(PIN_EN->gpio, &GPIO_InitStructure); + + HAL_GPIO_WritePin(PIN_CS->gpio, PIN_CS->pin_mask, GPIO_PIN_SET); + HAL_GPIO_WritePin(PIN_EN->gpio, PIN_EN->pin_mask, GPIO_PIN_RESET); + + /* do a dummy read, this ensures SCLK is low before + actual communications start, it might be required */ + CS_LOW(); + uint8_t buf[1]; + HAL_SPI_Receive(SPI_HANDLE->spi, buf, sizeof(buf), SPI_TIMEOUT); + CS_HIGH(); + + // register EXTI + extint_register((mp_obj_t)PIN_IRQ, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t)&irq_callback_obj, true); + extint_enable(PIN_IRQ->pin); + + DEBUG_printf("SpiOpen finished; IRQ.pin=%d IRQ_LINE=%d\n", PIN_IRQ->pin, PIN_IRQ->pin); +} + +long ReadWlanInterruptPin(void) +{ + return HAL_GPIO_ReadPin(PIN_IRQ->gpio, PIN_IRQ->pin_mask); +} + +void WriteWlanPin(unsigned char val) +{ + HAL_GPIO_WritePin(PIN_EN->gpio, PIN_EN->pin_mask, + (WLAN_ENABLE)? GPIO_PIN_SET:GPIO_PIN_RESET); +} + +STATIC void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) +{ + DEBUG_printf("SpiWriteDataSynchronous(data=%p [%x %x %x %x], size=%u)\n", data, data[0], data[1], data[2], data[3], size); + __disable_irq(); + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { + //BREAK(); + } + __enable_irq(); + DEBUG_printf(" - rx data = [%x %x %x %x]\n", data[0], data[1], data[2], data[3]); +} + +STATIC void SpiReadDataSynchronous(unsigned char *data, unsigned short size) +{ + memset(data, READ, size); + __disable_irq(); + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { + //BREAK(); + } + __enable_irq(); +} + +STATIC void __delay_cycles(volatile int x) +{ + x *= 6; // for 168 MHz CPU + while (x--); +} + +STATIC long SpiFirstWrite(unsigned char *ucBuf, unsigned short usLength) +{ + DEBUG_printf("SpiFirstWrite %lu\n", sSpiInformation.ulSpiState); + + CS_LOW(); + + // Assuming we are running on 24 MHz ~50 micro delay is 1200 cycles; + __delay_cycles(1200); + + // SPI writes first 4 bytes of data + SpiWriteDataSynchronous(ucBuf, 4); + + __delay_cycles(1200); + + SpiWriteDataSynchronous(ucBuf + 4, usLength - 4); + + // From this point on - operate in a regular way + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + + CS_HIGH(); + + return(0); +} + +long SpiWrite(unsigned char *pUserBuffer, unsigned short usLength) +{ + DEBUG_printf("SpiWrite %lu\n", sSpiInformation.ulSpiState); + + unsigned char ucPad = 0; + + // Figure out the total length of the packet in order to figure out if there + // is padding or not + if(!(usLength & 0x0001)) { + ucPad++; + } + + pUserBuffer[0] = WRITE; + pUserBuffer[1] = HI(usLength + ucPad); + pUserBuffer[2] = LO(usLength + ucPad); + pUserBuffer[3] = 0; + pUserBuffer[4] = 0; + + usLength += (SPI_HEADER_SIZE + ucPad); + + // The magic number that resides at the end of the TX/RX buffer (1 byte after the allocated size) + // for the purpose of detection of the overrun. If the magic number is overriten - buffer overrun + // occurred - and we will stuck here forever! + if (wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) { + while (1); + } + + if (sSpiInformation.ulSpiState == eSPI_STATE_POWERUP) { + while (sSpiInformation.ulSpiState != eSPI_STATE_INITIALIZED); + } + + if (sSpiInformation.ulSpiState == eSPI_STATE_INITIALIZED) { + // This is time for first TX/RX transactions over SPI: + // the IRQ is down - so need to send read buffer size command + SpiFirstWrite(pUserBuffer, usLength); + } else { + // + // We need to prevent here race that can occur in case 2 back to back packets are sent to the + // device, so the state will move to IDLE and once again to not IDLE due to IRQ + // + tSLInformation.WlanInterruptDisable(); + + while (sSpiInformation.ulSpiState != eSPI_STATE_IDLE); + + sSpiInformation.ulSpiState = eSPI_STATE_WRITE_IRQ; + sSpiInformation.pTxPacket = pUserBuffer; + sSpiInformation.usTxPacketLength = usLength; + + // Assert the CS line and wait till SSI IRQ line is active and then initialize write operation + CS_LOW(); + + // Re-enable IRQ - if it was not disabled - this is not a problem... + tSLInformation.WlanInterruptEnable(); + + // check for a missing interrupt between the CS assertion and enabling back the interrupts + if (tSLInformation.ReadWlanInterruptPin() == 0) { + SpiWriteDataSynchronous(sSpiInformation.pTxPacket, sSpiInformation.usTxPacketLength); + + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + + CS_HIGH(); + } + } + + // Due to the fact that we are currently implementing a blocking situation + // here we will wait till end of transaction + while (eSPI_STATE_IDLE != sSpiInformation.ulSpiState); + + return(0); +} + +#if 0 +unused +STATIC void SpiReadPacket(void) +{ + int length; + + /* read SPI header */ + SpiReadDataSynchronous(sSpiInformation.pRxPacket, SPI_HEADER_SIZE); + + /* parse data length */ + STREAM_TO_UINT8(sSpiInformation.pRxPacket, SPI_HEADER_SIZE-1, length); + + /* read the remainder of the packet */ + SpiReadDataSynchronous(sSpiInformation.pRxPacket + SPI_HEADER_SIZE, length); + + sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; +} +#endif + +STATIC void SpiReadHeader(void) +{ + SpiReadDataSynchronous(sSpiInformation.pRxPacket, 10); +} + +STATIC void SpiTriggerRxProcessing(void) +{ + SpiPauseSpi(); + CS_HIGH(); + + // The magic number that resides at the end of the TX/RX buffer (1 byte after the allocated size) + // for the purpose of detection of the overrun. If the magic number is overriten - buffer overrun + // occurred - and we will stuck here forever! + if (sSpiInformation.pRxPacket[CC3000_RX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) { + while (1); + } + + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + sSpiInformation.SPIRxHandler(sSpiInformation.pRxPacket + SPI_HEADER_SIZE); +} + + +STATIC long SpiReadDataCont(void) +{ + long data_to_recv=0; + unsigned char *evnt_buff, type; + + //determine what type of packet we have + evnt_buff = sSpiInformation.pRxPacket; + STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_PACKET_TYPE_OFFSET, type); + + switch (type) { + case HCI_TYPE_DATA:{ + // We need to read the rest of data.. + STREAM_TO_UINT16((char *)(evnt_buff + SPI_HEADER_SIZE), + HCI_DATA_LENGTH_OFFSET, data_to_recv); + if (!((HEADERS_SIZE_EVNT + data_to_recv) & 1)) { + data_to_recv++; + } + + if (data_to_recv) { + SpiReadDataSynchronous(evnt_buff + 10, data_to_recv); + } + break; + } + case HCI_TYPE_EVNT: { + // Calculate the rest length of the data + STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), + HCI_EVENT_LENGTH_OFFSET, data_to_recv); + data_to_recv -= 1; + + // Add padding byte if needed + if ((HEADERS_SIZE_EVNT + data_to_recv) & 1) { + data_to_recv++; + } + + if (data_to_recv) { + SpiReadDataSynchronous(evnt_buff + 10, data_to_recv); + } + + sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; + break; + } + } + + return 0; +} + +STATIC void SSIContReadOperation(void) +{ + // The header was read - continue with the payload read + if (!SpiReadDataCont()) { + /* All the data was read - finalize handling by switching + to the task and calling from task Event Handler */ + SpiTriggerRxProcessing(); + } +} + +STATIC mp_obj_t irq_callback(mp_obj_t line) { + DEBUG_printf("<< IRQ; state=%lu >>\n", sSpiInformation.ulSpiState); + switch (sSpiInformation.ulSpiState) { + case eSPI_STATE_POWERUP: + /* This means IRQ line was low call a callback of HCI Layer to inform on event */ + DEBUG_printf(" - POWERUP\n"); + sSpiInformation.ulSpiState = eSPI_STATE_INITIALIZED; + break; + case eSPI_STATE_IDLE: + DEBUG_printf(" - IDLE\n"); + sSpiInformation.ulSpiState = eSPI_STATE_READ_IRQ; + + /* IRQ line goes down - we are start reception */ + CS_LOW(); + + // Wait for TX/RX Compete which will come as DMA interrupt + SpiReadHeader(); + + sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; + + SSIContReadOperation(); + break; + case eSPI_STATE_WRITE_IRQ: + DEBUG_printf(" - WRITE IRQ\n"); + SpiWriteDataSynchronous(sSpiInformation.pTxPacket, sSpiInformation.usTxPacketLength); + + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + + CS_HIGH(); + break; + } + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(irq_callback_obj, irq_callback); + +void SpiPauseSpi(void) { + DEBUG_printf("SpiPauseSpi\n"); + extint_disable(PIN_IRQ->pin); +} + +void SpiResumeSpi(void) { + DEBUG_printf("SpiResumeSpi\n"); + extint_enable(PIN_IRQ->pin); +} diff --git a/src/openmv/src/micropython/drivers/cc3000/src/evnt_handler.c b/src/openmv/src/micropython/drivers/cc3000/src/evnt_handler.c new file mode 100755 index 0000000..80f34e4 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/evnt_handler.c @@ -0,0 +1,849 @@ +/***************************************************************************** +* +* evnt_handler.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ +//***************************************************************************** +// +//! \addtogroup evnt_handler_api +//! @{ +// +//****************************************************************************** + +//****************************************************************************** +// INCLUDE FILES +//****************************************************************************** + +#include "cc3000_common.h" +#include "string.h" +#include "hci.h" +#include "evnt_handler.h" +#include "wlan.h" +#include "socket.h" +#include "netapp.h" +#include "ccspi.h" + + + +//***************************************************************************** +// COMMON DEFINES +//***************************************************************************** + +#define FLOW_CONTROL_EVENT_HANDLE_OFFSET (0) +#define FLOW_CONTROL_EVENT_BLOCK_MODE_OFFSET (1) +#define FLOW_CONTROL_EVENT_FREE_BUFFS_OFFSET (2) +#define FLOW_CONTROL_EVENT_SIZE (4) + +#define BSD_RSP_PARAMS_SOCKET_OFFSET (0) +#define BSD_RSP_PARAMS_STATUS_OFFSET (4) + +#define GET_HOST_BY_NAME_RETVAL_OFFSET (0) +#define GET_HOST_BY_NAME_ADDR_OFFSET (4) + +#define ACCEPT_SD_OFFSET (0) +#define ACCEPT_RETURN_STATUS_OFFSET (4) +#define ACCEPT_ADDRESS__OFFSET (8) + +#define SL_RECEIVE_SD_OFFSET (0) +#define SL_RECEIVE_NUM_BYTES_OFFSET (4) +#define SL_RECEIVE__FLAGS__OFFSET (8) + + +#define SELECT_STATUS_OFFSET (0) +#define SELECT_READFD_OFFSET (4) +#define SELECT_WRITEFD_OFFSET (8) +#define SELECT_EXFD_OFFSET (12) + + +#define NETAPP_IPCONFIG_IP_OFFSET (0) +#define NETAPP_IPCONFIG_SUBNET_OFFSET (4) +#define NETAPP_IPCONFIG_GW_OFFSET (8) +#define NETAPP_IPCONFIG_DHCP_OFFSET (12) +#define NETAPP_IPCONFIG_DNS_OFFSET (16) +#define NETAPP_IPCONFIG_MAC_OFFSET (20) +#define NETAPP_IPCONFIG_SSID_OFFSET (26) + +#define NETAPP_IPCONFIG_IP_LENGTH (4) +#define NETAPP_IPCONFIG_MAC_LENGTH (6) +#define NETAPP_IPCONFIG_SSID_LENGTH (32) + + +#define NETAPP_PING_PACKETS_SENT_OFFSET (0) +#define NETAPP_PING_PACKETS_RCVD_OFFSET (4) +#define NETAPP_PING_MIN_RTT_OFFSET (8) +#define NETAPP_PING_MAX_RTT_OFFSET (12) +#define NETAPP_PING_AVG_RTT_OFFSET (16) + +#define GET_SCAN_RESULTS_TABlE_COUNT_OFFSET (0) +#define GET_SCAN_RESULTS_SCANRESULT_STATUS_OFFSET (4) +#define GET_SCAN_RESULTS_ISVALID_TO_SSIDLEN_OFFSET (8) +#define GET_SCAN_RESULTS_FRAME_TIME_OFFSET (10) +#define GET_SCAN_RESULTS_SSID_MAC_LENGTH (38) + +#define GET_MSS_VAL_RETVAL_OFFSET (0) + +//***************************************************************************** +// GLOBAL VARAIABLES +//***************************************************************************** + +UINT32 socket_active_status = SOCKET_STATUS_INIT_VAL; + + +//***************************************************************************** +// Prototypes for the static functions +//***************************************************************************** + +static INT32 hci_event_unsol_flowcontrol_handler(CHAR *pEvent); + +static void update_socket_active_status(CHAR *resp_params); + + +//***************************************************************************** +// +//! hci_unsol_handle_patch_request +//! +//! @param event_hdr event header +//! +//! @return none +//! +//! @brief Handle unsolicited event from type patch request +// +//***************************************************************************** +void hci_unsol_handle_patch_request(CHAR *event_hdr) +{ + CHAR *params = (CHAR *)(event_hdr) + HCI_EVENT_HEADER_SIZE; + UINT32 ucLength = 0; + CHAR *patch; + + switch (*params) + { + case HCI_EVENT_PATCHES_DRV_REQ: + + if (tSLInformation.sDriverPatches) + { + patch = tSLInformation.sDriverPatches(&ucLength); + + if (patch) + { + hci_patch_send(HCI_EVENT_PATCHES_DRV_REQ, + tSLInformation.pucTxCommandBuffer, patch, ucLength); + return; + } + } + + // Send 0 length Patches response event + hci_patch_send(HCI_EVENT_PATCHES_DRV_REQ, + tSLInformation.pucTxCommandBuffer, 0, 0); + break; + + case HCI_EVENT_PATCHES_FW_REQ: + + if (tSLInformation.sFWPatches) + { + patch = tSLInformation.sFWPatches(&ucLength); + + // Build and send a patch + if (patch) + { + hci_patch_send(HCI_EVENT_PATCHES_FW_REQ, + tSLInformation.pucTxCommandBuffer, patch, ucLength); + return; + } + } + + // Send 0 length Patches response event + hci_patch_send(HCI_EVENT_PATCHES_FW_REQ, + tSLInformation.pucTxCommandBuffer, 0, 0); + break; + + case HCI_EVENT_PATCHES_BOOTLOAD_REQ: + + if (tSLInformation.sBootLoaderPatches) + { + patch = tSLInformation.sBootLoaderPatches(&ucLength); + + if (patch) + { + hci_patch_send(HCI_EVENT_PATCHES_BOOTLOAD_REQ, + tSLInformation.pucTxCommandBuffer, patch, ucLength); + return; + } + } + + // Send 0 length Patches response event + hci_patch_send(HCI_EVENT_PATCHES_BOOTLOAD_REQ, + tSLInformation.pucTxCommandBuffer, 0, 0); + break; + } +} + + + +//***************************************************************************** +// +//! hci_event_handler +//! +//! @param pRetParams incoming data buffer +//! @param from from information (in case of data received) +//! @param fromlen from information length (in case of data received) +//! +//! @return none +//! +//! @brief Parse the incoming events packets and issues corresponding +//! event handler from global array of handlers pointers +// +//***************************************************************************** + + +UINT8 * hci_event_handler(void *pRetParams, UINT8 *from, UINT8 *fromlen) +{ + UINT8 *pucReceivedData, ucArgsize; + UINT16 usLength; + UINT8 *pucReceivedParams; + UINT16 usReceivedEventOpcode = 0; + UINT32 retValue32; + UINT8 * RecvParams; + UINT8 *RetParams; + + + while (1) + { + if (tSLInformation.usEventOrDataReceived != 0) + { + pucReceivedData = (tSLInformation.pucReceivedData); + + if (*pucReceivedData == HCI_TYPE_EVNT) + { + // Event Received + STREAM_TO_UINT16((CHAR *)pucReceivedData, HCI_EVENT_OPCODE_OFFSET, + usReceivedEventOpcode); + pucReceivedParams = pucReceivedData + HCI_EVENT_HEADER_SIZE; + RecvParams = pucReceivedParams; + RetParams = pRetParams; + + // In case unsolicited event received - here the handling finished + if (hci_unsol_event_handler((CHAR *)pucReceivedData) == 0) + { + STREAM_TO_UINT8(pucReceivedData, HCI_DATA_LENGTH_OFFSET, usLength); + + switch(usReceivedEventOpcode) + { + case HCI_CMND_READ_BUFFER_SIZE: + { + STREAM_TO_UINT8((CHAR *)pucReceivedParams, 0, + tSLInformation.usNumberOfFreeBuffers); + STREAM_TO_UINT16((CHAR *)pucReceivedParams, 1, + tSLInformation.usSlBufferLength); + } + break; + + case HCI_CMND_WLAN_CONFIGURE_PATCH: + case HCI_NETAPP_DHCP: + case HCI_NETAPP_PING_SEND: + case HCI_NETAPP_PING_STOP: + case HCI_NETAPP_ARP_FLUSH: + case HCI_NETAPP_SET_DEBUG_LEVEL: + case HCI_NETAPP_SET_TIMERS: + case HCI_EVNT_NVMEM_READ: + case HCI_EVNT_NVMEM_CREATE_ENTRY: + case HCI_CMND_NVMEM_WRITE_PATCH: + case HCI_NETAPP_PING_REPORT: + case HCI_EVNT_MDNS_ADVERTISE: + + STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET + ,*(UINT8 *)pRetParams); + break; + + case HCI_CMND_SETSOCKOPT: + case HCI_CMND_WLAN_CONNECT: + case HCI_CMND_WLAN_IOCTL_STATUSGET: + case HCI_EVNT_WLAN_IOCTL_ADD_PROFILE: + case HCI_CMND_WLAN_IOCTL_DEL_PROFILE: + case HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY: + case HCI_CMND_WLAN_IOCTL_SET_SCANPARAM: + case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START: + case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP: + case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX: + case HCI_CMND_EVENT_MASK: + case HCI_EVNT_WLAN_DISCONNECT: + case HCI_EVNT_SOCKET: + case HCI_EVNT_BIND: + case HCI_CMND_LISTEN: + case HCI_EVNT_CLOSE_SOCKET: + case HCI_EVNT_CONNECT: + case HCI_EVNT_NVMEM_WRITE: + + STREAM_TO_UINT32((CHAR *)pucReceivedParams,0 + ,*(UINT32 *)pRetParams); + break; + + case HCI_EVNT_READ_SP_VERSION: + + STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET + ,*(UINT8 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 1; + STREAM_TO_UINT32((CHAR *)pucReceivedParams, 0, retValue32); + UINT32_TO_STREAM((UINT8 *)pRetParams, retValue32); + break; + + case HCI_EVNT_BSD_GETHOSTBYNAME: + + STREAM_TO_UINT32((CHAR *)pucReceivedParams + ,GET_HOST_BY_NAME_RETVAL_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams + ,GET_HOST_BY_NAME_ADDR_OFFSET,*(UINT32 *)pRetParams); + break; + + case HCI_EVNT_GETMSSVALUE: + + STREAM_TO_UINT16((CHAR *)pucReceivedParams + ,GET_MSS_VAL_RETVAL_OFFSET,*(UINT16 *)pRetParams); + + break; + + case HCI_EVNT_ACCEPT: + { + STREAM_TO_UINT32((CHAR *)pucReceivedParams,ACCEPT_SD_OFFSET + ,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams + ,ACCEPT_RETURN_STATUS_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + + //This argument returns in network order + memcpy((UINT8 *)pRetParams, + pucReceivedParams + ACCEPT_ADDRESS__OFFSET, sizeof(sockaddr)); + break; + } + + case HCI_EVNT_RECV: + case HCI_EVNT_RECVFROM: + { + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SL_RECEIVE_SD_OFFSET ,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SL_RECEIVE_NUM_BYTES_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SL_RECEIVE__FLAGS__OFFSET,*(UINT32 *)pRetParams); + + if(((tBsdReadReturnParams *)pRetParams)->iNumberOfBytes == ERROR_SOCKET_INACTIVE) + { + set_socket_active_status(((tBsdReadReturnParams *)pRetParams)->iSocketDescriptor,SOCKET_STATUS_INACTIVE); + } + break; + } + + case HCI_EVNT_SEND: + case HCI_EVNT_SENDTO: + { + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SL_RECEIVE_SD_OFFSET ,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SL_RECEIVE_NUM_BYTES_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + + break; + } + + case HCI_EVNT_SELECT: + { + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SELECT_STATUS_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SELECT_READFD_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SELECT_WRITEFD_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,SELECT_EXFD_OFFSET,*(UINT32 *)pRetParams); + break; + } + + case HCI_CMND_GETSOCKOPT: + + STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET,((tBsdGetSockOptReturnParams *)pRetParams)->iStatus); + //This argument returns in network order + memcpy((UINT8 *)pRetParams, pucReceivedParams, 4); + break; + + case HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS: + + STREAM_TO_UINT32((CHAR *)pucReceivedParams,GET_SCAN_RESULTS_TABlE_COUNT_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT32((CHAR *)pucReceivedParams,GET_SCAN_RESULTS_SCANRESULT_STATUS_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 4; + STREAM_TO_UINT16((CHAR *)pucReceivedParams,GET_SCAN_RESULTS_ISVALID_TO_SSIDLEN_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 2; + STREAM_TO_UINT16((CHAR *)pucReceivedParams,GET_SCAN_RESULTS_FRAME_TIME_OFFSET,*(UINT32 *)pRetParams); + pRetParams = ((CHAR *)pRetParams) + 2; + memcpy((UINT8 *)pRetParams, (CHAR *)(pucReceivedParams + GET_SCAN_RESULTS_FRAME_TIME_OFFSET + 2), GET_SCAN_RESULTS_SSID_MAC_LENGTH); + break; + + case HCI_CMND_SIMPLE_LINK_START: + break; + + case HCI_NETAPP_IPCONFIG: + + //Read IP address + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH); + RecvParams += 4; + + //Read subnet + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH); + RecvParams += 4; + + //Read default GW + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH); + RecvParams += 4; + + //Read DHCP server + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH); + RecvParams += 4; + + //Read DNS server + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH); + RecvParams += 4; + + //Read Mac address + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_MAC_LENGTH); + RecvParams += 6; + + //Read SSID + STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_SSID_LENGTH); + + } + } + + if (usReceivedEventOpcode == tSLInformation.usRxEventOpcode) + { + tSLInformation.usRxEventOpcode = 0; + } + } + else + { + pucReceivedParams = pucReceivedData; + STREAM_TO_UINT8((CHAR *)pucReceivedData, HCI_PACKET_ARGSIZE_OFFSET, ucArgsize); + + STREAM_TO_UINT16((CHAR *)pucReceivedData, HCI_PACKET_LENGTH_OFFSET, usLength); + + // Data received: note that the only case where from and from length + // are not null is in recv from, so fill the args accordingly + if (from) + { + STREAM_TO_UINT32((CHAR *)(pucReceivedData + HCI_DATA_HEADER_SIZE), BSD_RECV_FROM_FROMLEN_OFFSET, *(UINT32 *)fromlen); + memcpy(from, (pucReceivedData + HCI_DATA_HEADER_SIZE + BSD_RECV_FROM_FROM_OFFSET) ,*fromlen); + } + + memcpy(pRetParams, pucReceivedParams + HCI_DATA_HEADER_SIZE + ucArgsize, + usLength - ucArgsize); + + tSLInformation.usRxDataPending = 0; + } + + tSLInformation.usEventOrDataReceived = 0; + + SpiResumeSpi(); + + // Since we are going to TX - we need to handle this event after the + // ResumeSPi since we need interrupts + if ((*pucReceivedData == HCI_TYPE_EVNT) && + (usReceivedEventOpcode == HCI_EVNT_PATCHES_REQ)) + { + hci_unsol_handle_patch_request((CHAR *)pucReceivedData); + } + + if ((tSLInformation.usRxEventOpcode == 0) && (tSLInformation.usRxDataPending == 0)) + { + return NULL; + } + } + } + +} + +//***************************************************************************** +// +//! hci_unsol_event_handler +//! +//! @param event_hdr event header +//! +//! @return 1 if event supported and handled +//! 0 if event is not supported +//! +//! @brief Handle unsolicited events +// +//***************************************************************************** +INT32 hci_unsol_event_handler(CHAR *event_hdr) +{ + CHAR * data = NULL; + INT32 event_type; + UINT32 NumberOfReleasedPackets; + UINT32 NumberOfSentPackets; + + STREAM_TO_UINT16(event_hdr, HCI_EVENT_OPCODE_OFFSET,event_type); + + if (event_type & HCI_EVNT_UNSOL_BASE) + { + switch(event_type) + { + + case HCI_EVNT_DATA_UNSOL_FREE_BUFF: + { + hci_event_unsol_flowcontrol_handler(event_hdr); + + NumberOfReleasedPackets = tSLInformation.NumberOfReleasedPackets; + NumberOfSentPackets = tSLInformation.NumberOfSentPackets; + + if (NumberOfReleasedPackets == NumberOfSentPackets) + { + if (tSLInformation.InformHostOnTxComplete) + { + tSLInformation.sWlanCB(HCI_EVENT_CC3000_CAN_SHUT_DOWN, NULL, 0); + } + } + return 1; + + } + } + } + + if(event_type & HCI_EVNT_WLAN_UNSOL_BASE) + { + switch(event_type) + { + case HCI_EVNT_WLAN_KEEPALIVE: + case HCI_EVNT_WLAN_UNSOL_CONNECT: + case HCI_EVNT_WLAN_UNSOL_DISCONNECT: + case HCI_EVNT_WLAN_UNSOL_INIT: + case HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE: + + if( tSLInformation.sWlanCB ) + { + tSLInformation.sWlanCB(event_type, 0, 0); + } + break; + + case HCI_EVNT_WLAN_UNSOL_DHCP: + { + UINT8 params[NETAPP_IPCONFIG_MAC_OFFSET + 1]; // extra byte is for the status + UINT8 *recParams = params; + + data = (CHAR*)(event_hdr) + HCI_EVENT_HEADER_SIZE; + + //Read IP address + STREAM_TO_STREAM(data,recParams,NETAPP_IPCONFIG_IP_LENGTH); + data += 4; + //Read subnet + STREAM_TO_STREAM(data,recParams,NETAPP_IPCONFIG_IP_LENGTH); + data += 4; + //Read default GW + STREAM_TO_STREAM(data,recParams,NETAPP_IPCONFIG_IP_LENGTH); + data += 4; + //Read DHCP server + STREAM_TO_STREAM(data,recParams,NETAPP_IPCONFIG_IP_LENGTH); + data += 4; + //Read DNS server + STREAM_TO_STREAM(data,recParams,NETAPP_IPCONFIG_IP_LENGTH); + // read the status + STREAM_TO_UINT8(event_hdr, HCI_EVENT_STATUS_OFFSET, *recParams); + + + if( tSLInformation.sWlanCB ) + { + tSLInformation.sWlanCB(event_type, (CHAR *)params, sizeof(params)); + } + } + break; + + case HCI_EVNT_WLAN_ASYNC_PING_REPORT: + { + netapp_pingreport_args_t params; + data = (CHAR*)(event_hdr) + HCI_EVENT_HEADER_SIZE; + STREAM_TO_UINT32(data, NETAPP_PING_PACKETS_SENT_OFFSET, params.packets_sent); + STREAM_TO_UINT32(data, NETAPP_PING_PACKETS_RCVD_OFFSET, params.packets_received); + STREAM_TO_UINT32(data, NETAPP_PING_MIN_RTT_OFFSET, params.min_round_time); + STREAM_TO_UINT32(data, NETAPP_PING_MAX_RTT_OFFSET, params.max_round_time); + STREAM_TO_UINT32(data, NETAPP_PING_AVG_RTT_OFFSET, params.avg_round_time); + + if( tSLInformation.sWlanCB ) + { + tSLInformation.sWlanCB(event_type, (CHAR *)¶ms, sizeof(params)); + } + } + break; + case HCI_EVNT_BSD_TCP_CLOSE_WAIT: + { + data = (CHAR *)(event_hdr) + HCI_EVENT_HEADER_SIZE; + if( tSLInformation.sWlanCB ) + { + //data[0] represents the socket id, for which FIN was received by remote. + //Upon receiving this event, the user can close the socket, or else the + //socket will be closded after inacvitity timeout (by default 60 seconds) + tSLInformation.sWlanCB(event_type, data, 1); + } + } + break; + + //'default' case which means "event not supported" + default: + return (0); + } + return(1); + } + + if ((event_type == HCI_EVNT_SEND) || (event_type == HCI_EVNT_SENDTO) + || (event_type == HCI_EVNT_WRITE)) + { + CHAR *pArg; + INT32 status; + + pArg = M_BSD_RESP_PARAMS_OFFSET(event_hdr); + STREAM_TO_UINT32(pArg, BSD_RSP_PARAMS_STATUS_OFFSET,status); + + if (ERROR_SOCKET_INACTIVE == status) + { + // The only synchronous event that can come from SL device in form of + // command complete is "Command Complete" on data sent, in case SL device + // was unable to transmit + STREAM_TO_UINT8(event_hdr, HCI_EVENT_STATUS_OFFSET, tSLInformation.slTransmitDataError); + update_socket_active_status(M_BSD_RESP_PARAMS_OFFSET(event_hdr)); + + return (1); + } + else + return (0); + } + + //handle a case where unsolicited event arrived, but was not handled by any of the cases above + if ((event_type != tSLInformation.usRxEventOpcode) && (event_type != HCI_EVNT_PATCHES_REQ)) + { + return(1); + } + + return(0); +} + +//***************************************************************************** +// +//! hci_unsolicited_event_handler +//! +//! @param None +//! +//! @return ESUCCESS if successful, EFAIL if an error occurred +//! +//! @brief Parse the incoming unsolicited event packets and issues +//! corresponding event handler. +// +//***************************************************************************** +INT32 hci_unsolicited_event_handler(void) +{ + UINT32 res = 0; + UINT8 *pucReceivedData; + + if (tSLInformation.usEventOrDataReceived != 0) + { + pucReceivedData = (tSLInformation.pucReceivedData); + + if (*pucReceivedData == HCI_TYPE_EVNT) + { + + // In case unsolicited event received - here the handling finished + if (hci_unsol_event_handler((CHAR *)pucReceivedData) == 1) + { + + // There was an unsolicited event received - we can release the buffer + // and clean the event received + tSLInformation.usEventOrDataReceived = 0; + + res = 1; + SpiResumeSpi(); + } + } + } + + return res; +} + +//***************************************************************************** +// +//! set_socket_active_status +//! +//! @param Sd +//! @param Status +//! @return none +//! +//! @brief Check if the socket ID and status are valid and set +//! accordingly the global socket status +// +//***************************************************************************** +void set_socket_active_status(INT32 Sd, INT32 Status) +{ + if(M_IS_VALID_SD(Sd) && M_IS_VALID_STATUS(Status)) + { + socket_active_status &= ~(1 << Sd); /* clean socket's mask */ + socket_active_status |= (Status << Sd); /* set new socket's mask */ + } +} + + +//***************************************************************************** +// +//! hci_event_unsol_flowcontrol_handler +//! +//! @param pEvent pointer to the string contains parameters for IPERF +//! @return ESUCCESS if successful, EFAIL if an error occurred +//! +//! @brief Called in case unsolicited event from type +//! HCI_EVNT_DATA_UNSOL_FREE_BUFF has received. +//! Keep track on the number of packets transmitted and update the +//! number of free buffer in the SL device. +// +//***************************************************************************** +INT32 hci_event_unsol_flowcontrol_handler(CHAR *pEvent) +{ + + INT32 temp, value; + UINT16 i; + UINT16 pusNumberOfHandles=0; + CHAR *pReadPayload; + + STREAM_TO_UINT16((CHAR *)pEvent,HCI_EVENT_HEADER_SIZE,pusNumberOfHandles); + pReadPayload = ((CHAR *)pEvent + + HCI_EVENT_HEADER_SIZE + sizeof(pusNumberOfHandles)); + temp = 0; + + for(i = 0; i < pusNumberOfHandles ; i++) + { + STREAM_TO_UINT16(pReadPayload, FLOW_CONTROL_EVENT_FREE_BUFFS_OFFSET, value); + temp += value; + pReadPayload += FLOW_CONTROL_EVENT_SIZE; + } + + tSLInformation.usNumberOfFreeBuffers += temp; + tSLInformation.NumberOfReleasedPackets += temp; + + return(ESUCCESS); +} + +//***************************************************************************** +// +//! get_socket_active_status +//! +//! @param Sd Socket IS +//! @return Current status of the socket. +//! +//! @brief Retrieve socket status +// +//***************************************************************************** + +INT32 get_socket_active_status(INT32 Sd) +{ + if(M_IS_VALID_SD(Sd)) + { + return (socket_active_status & (1 << Sd)) ? SOCKET_STATUS_INACTIVE : SOCKET_STATUS_ACTIVE; + } + return SOCKET_STATUS_INACTIVE; +} + +//***************************************************************************** +// +//! update_socket_active_status +//! +//! @param resp_params Socket IS +//! @return Current status of the socket. +//! +//! @brief Retrieve socket status +// +//***************************************************************************** +void update_socket_active_status(CHAR *resp_params) +{ + INT32 status, sd; + + STREAM_TO_UINT32(resp_params, BSD_RSP_PARAMS_SOCKET_OFFSET,sd); + STREAM_TO_UINT32(resp_params, BSD_RSP_PARAMS_STATUS_OFFSET,status); + + if(ERROR_SOCKET_INACTIVE == status) + { + set_socket_active_status(sd, SOCKET_STATUS_INACTIVE); + } +} + + +//***************************************************************************** +// +//! SimpleLinkWaitEvent +//! +//! @param usOpcode command operation code +//! @param pRetParams command return parameters +//! +//! @return none +//! +//! @brief Wait for event, pass it to the hci_event_handler and +//! update the event opcode in a global variable. +// +//***************************************************************************** + +void SimpleLinkWaitEvent(UINT16 usOpcode, void *pRetParams) +{ + // In the blocking implementation the control to caller will be returned only + // after the end of current transaction + tSLInformation.usRxEventOpcode = usOpcode; + hci_event_handler(pRetParams, 0, 0); +} + +//***************************************************************************** +// +//! SimpleLinkWaitData +//! +//! @param pBuf data buffer +//! @param from from information +//! @param fromlen from information length +//! +//! @return none +//! +//! @brief Wait for data, pass it to the hci_event_handler +//! and update in a global variable that there is +//! data to read. +// +//***************************************************************************** + +void SimpleLinkWaitData(UINT8 *pBuf, UINT8 *from, UINT8 *fromlen) +{ + // In the blocking implementation the control to caller will be returned only + // after the end of current transaction, i.e. only after data will be received + tSLInformation.usRxDataPending = 1; + hci_event_handler(pBuf, from, fromlen); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3000/src/hci.c b/src/openmv/src/micropython/drivers/cc3000/src/hci.c new file mode 100755 index 0000000..4391692 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/hci.c @@ -0,0 +1,225 @@ +/***************************************************************************** +* +* hci.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ + +//***************************************************************************** +// +//! \addtogroup hci_app +//! @{ +// +//***************************************************************************** + +#include +#include "cc3000_common.h" +#include "hci.h" +#include "ccspi.h" +#include "evnt_handler.h" +#include "wlan.h" + +#define SL_PATCH_PORTION_SIZE (1000) + + +//***************************************************************************** +// +//! hci_command_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the command's arguments buffer +//! @param ucArgsLength length of the arguments +//! +//! @return none +//! +//! @brief Initiate an HCI command. +// +//***************************************************************************** +UINT16 hci_command_send(UINT16 usOpcode, UINT8 *pucBuff, UINT8 ucArgsLength) +{ + UINT8 *stream; + + stream = (pucBuff + SPI_HEADER_SIZE); + + UINT8_TO_STREAM(stream, HCI_TYPE_CMND); + stream = UINT16_TO_STREAM(stream, usOpcode); + UINT8_TO_STREAM(stream, ucArgsLength); + + //Update the opcode of the event we will be waiting for + SpiWrite(pucBuff, ucArgsLength + SIMPLE_LINK_HCI_CMND_HEADER_SIZE); + + return(0); +} + +//***************************************************************************** +// +//! hci_data_send +//! +//! @param usOpcode command operation code +//! @param ucArgs pointer to the command's arguments buffer +//! @param usArgsLength length of the arguments +//! @param ucTail pointer to the data buffer +//! @param usTailLength buffer length +//! +//! @return none +//! +//! @brief Initiate an HCI data write operation +// +//***************************************************************************** +INT32 hci_data_send(UINT8 ucOpcode, + UINT8 *ucArgs, + UINT16 usArgsLength, + UINT16 usDataLength, + const UINT8 *ucTail, + UINT16 usTailLength) +{ + UINT8 *stream; + + stream = ((ucArgs) + SPI_HEADER_SIZE); + + UINT8_TO_STREAM(stream, HCI_TYPE_DATA); + UINT8_TO_STREAM(stream, ucOpcode); + UINT8_TO_STREAM(stream, usArgsLength); + stream = UINT16_TO_STREAM(stream, usArgsLength + usDataLength + usTailLength); + + // Send the packet over the SPI + SpiWrite(ucArgs, SIMPLE_LINK_HCI_DATA_HEADER_SIZE + usArgsLength + usDataLength + usTailLength); + + return(ESUCCESS); +} + + +//***************************************************************************** +// +//! hci_data_command_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the data buffer +//! @param ucArgsLength arguments length +//! @param ucDataLength data length +//! +//! @return none +//! +//! @brief Prepeare HCI header and initiate an HCI data write operation +// +//***************************************************************************** +void hci_data_command_send(UINT16 usOpcode, UINT8 *pucBuff, UINT8 ucArgsLength,UINT16 ucDataLength) +{ + UINT8 *stream = (pucBuff + SPI_HEADER_SIZE); + + UINT8_TO_STREAM(stream, HCI_TYPE_DATA); + UINT8_TO_STREAM(stream, usOpcode); + UINT8_TO_STREAM(stream, ucArgsLength); + stream = UINT16_TO_STREAM(stream, ucArgsLength + ucDataLength); + + // Send the command over SPI on data channel + SpiWrite(pucBuff, ucArgsLength + ucDataLength + SIMPLE_LINK_HCI_DATA_CMND_HEADER_SIZE); + + return; +} + +//***************************************************************************** +// +//! hci_patch_send +//! +//! @param usOpcode command operation code +//! @param pucBuff pointer to the command's arguments buffer +//! @param patch pointer to patch content buffer +//! @param usDataLength data length +//! +//! @return none +//! +//! @brief Prepeare HCI header and initiate an HCI patch write operation +// +//***************************************************************************** +void hci_patch_send(UINT8 ucOpcode, UINT8 *pucBuff, CHAR *patch, UINT16 usDataLength) +{ + UINT8 *data_ptr = (pucBuff + SPI_HEADER_SIZE); + UINT16 usTransLength; + UINT8 *stream = (pucBuff + SPI_HEADER_SIZE); + + UINT8_TO_STREAM(stream, HCI_TYPE_PATCH); + UINT8_TO_STREAM(stream, ucOpcode); + stream = UINT16_TO_STREAM(stream, usDataLength + SIMPLE_LINK_HCI_PATCH_HEADER_SIZE); + + if (usDataLength <= SL_PATCH_PORTION_SIZE) + { + UINT16_TO_STREAM(stream, usDataLength); + stream = UINT16_TO_STREAM(stream, usDataLength); + memcpy((pucBuff + SPI_HEADER_SIZE) + HCI_PATCH_HEADER_SIZE, patch, usDataLength); + + // Update the opcode of the event we will be waiting for + SpiWrite(pucBuff, usDataLength + HCI_PATCH_HEADER_SIZE); + } + else + { + + usTransLength = (usDataLength/SL_PATCH_PORTION_SIZE); + UINT16_TO_STREAM(stream, usDataLength + SIMPLE_LINK_HCI_PATCH_HEADER_SIZE + usTransLength*SIMPLE_LINK_HCI_PATCH_HEADER_SIZE); + stream = UINT16_TO_STREAM(stream, SL_PATCH_PORTION_SIZE); + memcpy(pucBuff + SPI_HEADER_SIZE + HCI_PATCH_HEADER_SIZE, patch, SL_PATCH_PORTION_SIZE); + usDataLength -= SL_PATCH_PORTION_SIZE; + patch += SL_PATCH_PORTION_SIZE; + + // Update the opcode of the event we will be waiting for + SpiWrite(pucBuff, SL_PATCH_PORTION_SIZE + HCI_PATCH_HEADER_SIZE); + + while (usDataLength) + { + if (usDataLength <= SL_PATCH_PORTION_SIZE) + { + usTransLength = usDataLength; + usDataLength = 0; + + } + else + { + usTransLength = SL_PATCH_PORTION_SIZE; + usDataLength -= usTransLength; + } + + *(UINT16 *)data_ptr = usTransLength; + memcpy(data_ptr + SIMPLE_LINK_HCI_PATCH_HEADER_SIZE, patch, usTransLength); + patch += usTransLength; + + // Update the opcode of the event we will be waiting for + SpiWrite((UINT8 *)data_ptr, usTransLength + sizeof(usTransLength)); + } + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3000/src/inet_ntop.c b/src/openmv/src/micropython/drivers/cc3000/src/inet_ntop.c new file mode 100755 index 0000000..83242ef --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/inet_ntop.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "cc3000_common.h" +#include "socket.h" +#include "inet_ntop.h" + +// We can't include stdio.h because it defines _types_fd_set, but we +// need to use the CC3000 version of this type. So we must provide +// our own declaration of snprintf. Grrr. +int snprintf(char *str, size_t size, const char *fmt, ...); + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +#define ENOSPC (28) +#define EAFNOSUPPORT (106) +#define SET_ERRNO(err) (CC3000_EXPORT(errno)=-err) + +/* + * Format an IPv4 address, more or less like inet_ntoa(). + * + * Returns `dst' (as a const) + * Note: + * - uses no statics + * - takes a unsigned char* not an in_addr as input + */ +static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) +{ + size_t len; + char tmp[sizeof "255.255.255.255"]; + + tmp[0] = '\0'; + (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", + ((int)((unsigned char)src[3])) & 0xff, + ((int)((unsigned char)src[2])) & 0xff, + ((int)((unsigned char)src[1])) & 0xff, + ((int)((unsigned char)src[0])) & 0xff); + + len = strlen(tmp); + if(len == 0 || len >= size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + strcpy(dst, tmp); + return dst; +} + +#ifdef ENABLE_IPV6 +/* + * Convert IPv6 binary address into presentation (printable) format. + */ +static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + char *tp; + struct { + long base; + long len; + } best, cur; + unsigned long words[IN6ADDRSZ / INT16SZ]; + int i; + + /* Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for (i = 0; i < IN6ADDRSZ; i++) + words[i/2] |= (src[i] << ((1 - (i % 2)) << 3)); + + best.base = -1; + cur.base = -1; + best.len = 0; + cur.len = 0; + + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + if(words[i] == 0) + { + if(cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else if(cur.base != -1) + { + if(best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + if((cur.base != -1) && (best.base == -1 || cur.len > best.len)) + best = cur; + if(best.base != -1 && best.len < 2) + best.base = -1; + + /* Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? + */ + if(best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + if(i == best.base) + *tp++ = ':'; + continue; + } + + /* Are we following an initial run of 0x00s or any real hex? + */ + if(i != 0) + *tp++ = ':'; + + /* Is this address an encapsulated IPv4? + */ + if(i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) + { + if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + tp += strlen(tp); + break; + } + tp += snprintf(tp, 5, "%lx", words[i]); + } + + /* Was it a trailing run of 0x00's? + */ + if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* Check for overflow, copy, and we're done. + */ + if((size_t)(tp - tmp) > size) + { + SET_ERRNO(ENOSPC); + return (NULL); + } + strcpy(dst, tmp); + return dst; +} +#endif /* ENABLE_IPV6 */ + +/* + * Convert a network format address to presentation format. + * + * Returns pointer to presentation format address (`buf'). + * Returns NULL on error and errno set with the specific + * error, EAFNOSUPPORT or ENOSPC. + * + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid loosing the + * actual last winsock error. So use macro ERRNO to fetch the + * errno this funtion sets when returning NULL, not SOCKERRNO. + */ +char *inet_ntop(int af, const void *src, char *buf, size_t size) +{ + switch (af) { + case AF_INET: + return inet_ntop4((const unsigned char*)src, buf, size); +#ifdef ENABLE_IPV6 + case AF_INET6: + return inet_ntop6((const unsigned char*)src, buf, size); +#endif + default: + SET_ERRNO(EAFNOSUPPORT); + return NULL; + } +} diff --git a/src/openmv/src/micropython/drivers/cc3000/src/inet_pton.c b/src/openmv/src/micropython/drivers/cc3000/src/inet_pton.c new file mode 100755 index 0000000..5f5ae5f --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/inet_pton.c @@ -0,0 +1,216 @@ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include +#include "cc3000_common.h" +#include "socket.h" +#include "inet_pton.h" + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +static int inet_pton4(const char *src, unsigned char *dst); +#ifdef ENABLE_IPV6 +static int inet_pton6(const char *src, unsigned char *dst); +#endif + +#define EAFNOSUPPORT (106) +#define SET_ERRNO(err) (CC3000_EXPORT(errno)=-err) + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * notice: + * On Windows we store the error in the thread errno, not + * in the winsock error code. This is to avoid loosing the + * actual last winsock error. So use macro ERRNO to fetch the + * errno this funtion sets when returning (-1), not SOCKERRNO. + * author: + * Paul Vixie, 1996. + */ +int inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, (unsigned char *)dst)); +#ifdef ENABLE_IPV6 + case AF_INET6: + return (inet_pton6(src, (unsigned char *)dst)); +#endif + default: + SET_ERRNO(EAFNOSUPPORT); + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + tp = tmp; + *tp = 0; + while((ch = *src++) != '\0') { + const char *pch; + + if((pch = strchr(digits, ch)) != NULL) { + unsigned int val = *tp * 10 + (unsigned int)(pch - digits); + + if(saw_digit && *tp == 0) + return (0); + if(val > 255) + return (0); + *tp = (unsigned char)val; + if(! saw_digit) { + if(++octets > 4) + return (0); + saw_digit = 1; + } + } + else if(ch == '.' && saw_digit) { + if(octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } + else + return (0); + } + if(octets < 4) + return (0); + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +#ifdef ENABLE_IPV6 +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if(*src == ':') + if(*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while((ch = *src++) != '\0') { + const char *pch; + + if((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if(pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if(++saw_xdigit > 4) + return (0); + continue; + } + if(ch == ':') { + curtok = src; + if(!saw_xdigit) { + if(colonp) + return (0); + colonp = tp; + continue; + } + if(tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if(ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if(saw_xdigit) { + if(tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if(colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const long n = tp - colonp; + long i; + + if(tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if(tp != endp) + return (0); + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} +#endif /* ENABLE_IPV6 */ diff --git a/src/openmv/src/micropython/drivers/cc3000/src/netapp.c b/src/openmv/src/micropython/drivers/cc3000/src/netapp.c new file mode 100755 index 0000000..a6f60fe --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/netapp.c @@ -0,0 +1,459 @@ +/***************************************************************************** +* +* netapp.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 "netapp.h" +#include "hci.h" +#include "socket.h" +#include "evnt_handler.h" +#include "nvmem.h" + +#define MIN_TIMER_VAL_SECONDS 10 +#define MIN_TIMER_SET(t) if ((0 != t) && (t < MIN_TIMER_VAL_SECONDS)) \ + { \ + t = MIN_TIMER_VAL_SECONDS; \ + } + + +#define NETAPP_DHCP_PARAMS_LEN (20) +#define NETAPP_SET_TIMER_PARAMS_LEN (20) +#define NETAPP_SET_DEBUG_LEVEL_PARAMS_LEN (4) +#define NETAPP_PING_SEND_PARAMS_LEN (16) + + +//***************************************************************************** +// +//! netapp_config_mac_adrress +//! +//! @param mac device mac address, 6 bytes. Saved: yes +//! +//! @return return on success 0, otherwise error. +//! +//! @brief Configure device MAC address and store it in NVMEM. +//! The value of the MAC address configured through the API will +//! be stored in CC3000 non volatile memory, thus preserved +//! over resets. +// +//***************************************************************************** +INT32 netapp_config_mac_adrress(UINT8 * mac) +{ + return nvmem_set_mac_address(mac); +} + +//***************************************************************************** +// +//! netapp_dhcp +//! +//! @param aucIP device mac address, 6 bytes. Saved: yes +//! @param aucSubnetMask device mac address, 6 bytes. Saved: yes +//! @param aucDefaultGateway device mac address, 6 bytes. Saved: yes +//! @param aucDNSServer device mac address, 6 bytes. Saved: yes +//! +//! @return return on success 0, otherwise error. +//! +//! @brief netapp_dhcp is used to configure the network interface, +//! static or dynamic (DHCP).\n In order to activate DHCP mode, +//! aucIP, aucSubnetMask, aucDefaultGateway must be 0. +//! The default mode of CC3000 is DHCP mode. +//! Note that the configuration is saved in non volatile memory +//! and thus preserved over resets. +//! +//! @note If the mode is altered a reset of CC3000 device is required +//! in order to apply changes.\nAlso note that asynchronous event +//! of DHCP_EVENT, which is generated when an IP address is +//! allocated either by the DHCP server or due to static +//! allocation is generated only upon a connection to the +//! AP was established. +//! +//***************************************************************************** +INT32 netapp_dhcp(UINT32 *aucIP, UINT32 *aucSubnetMask,UINT32 *aucDefaultGateway, UINT32 *aucDNSServer) +{ + INT8 scRet; + UINT8 *ptr; + UINT8 *args; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + ARRAY_TO_STREAM(args,aucIP,4); + ARRAY_TO_STREAM(args,aucSubnetMask,4); + ARRAY_TO_STREAM(args,aucDefaultGateway,4); + args = UINT32_TO_STREAM(args, 0); + ARRAY_TO_STREAM(args,aucDNSServer,4); + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_DHCP, ptr, NETAPP_DHCP_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_DHCP, &scRet); + + return(scRet); +} + + +//***************************************************************************** +// +//! netapp_timeout_values +//! +//! @param aucDHCP DHCP lease time request, also impact +//! the DHCP renew timeout. Range: [0-0xffffffff] seconds, +//! 0 or 0xffffffff == infinity lease timeout. +//! Resolution:10 seconds. Influence: only after +//! reconnecting to the AP. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 seconds. +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 14400 seconds. +//! +//! @param aucARP ARP refresh timeout, if ARP entry is not updated by +//! incoming packet, the ARP entry will be deleted by +//! the end of the timeout. +//! Range: [0-0xffffffff] seconds, 0 == infinity ARP timeout +//! Resolution: 10 seconds. Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 seconds +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 3600 seconds. +//! +//! @param aucKeepalive Keepalive event sent by the end of keepalive timeout +//! Range: [0-0xffffffff] seconds, 0 == infinity timeout +//! Resolution: 10 seconds. +//! Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 sec +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 10 seconds. +//! +//! @param aucInactivity Socket inactivity timeout, socket timeout is +//! refreshed by incoming or outgoing packet, by the +//! end of the socket timeout the socket will be closed +//! Range: [0-0xffffffff] sec, 0 == infinity timeout. +//! Resolution: 10 seconds. Influence: on runtime. +//! Minimal bound value: MIN_TIMER_VAL_SECONDS - 10 sec +//! The parameter is saved into the CC3000 NVMEM. +//! The default value on CC3000 is 60 seconds. +//! +//! @return return on success 0, otherwise error. +//! +//! @brief Set new timeout values. Function set new timeout values for: +//! DHCP lease timeout, ARP refresh timeout, keepalive event +//! timeout and socket inactivity timeout +//! +//! @note If a parameter set to non zero value which is less than 10s, +//! it will be set automatically to 10s. +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 netapp_timeout_values(UINT32 *aucDHCP, UINT32 *aucARP,UINT32 *aucKeepalive, UINT32 *aucInactivity) +{ + INT8 scRet; + UINT8 *ptr; + UINT8 *args; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Set minimal values of timers + MIN_TIMER_SET(*aucDHCP) + MIN_TIMER_SET(*aucARP) + MIN_TIMER_SET(*aucKeepalive) + MIN_TIMER_SET(*aucInactivity) + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, *aucDHCP); + args = UINT32_TO_STREAM(args, *aucARP); + args = UINT32_TO_STREAM(args, *aucKeepalive); + args = UINT32_TO_STREAM(args, *aucInactivity); + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_SET_TIMERS, ptr, NETAPP_SET_TIMER_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_SET_TIMERS, &scRet); + + return(scRet); +} +#endif + + +//***************************************************************************** +// +//! netapp_ping_send +//! +//! @param ip destination IP address +//! @param pingAttempts number of echo requests to send +//! @param pingSize send buffer size which may be up to 1400 bytes +//! @param pingTimeout Time to wait for a response,in milliseconds. +//! +//! @return return on success 0, otherwise error. +//! +//! @brief send ICMP ECHO_REQUEST to network hosts +//! +//! @note If an operation finished successfully asynchronous ping report +//! event will be generated. The report structure is as defined +//! by structure netapp_pingreport_args_t. +//! +//! @warning Calling this function while a previous Ping Requests are in +//! progress will stop the previous ping request. +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 + netapp_ping_send(UINT32 *ip, UINT32 ulPingAttempts, UINT32 ulPingSize, UINT32 ulPingTimeout) +{ + INT8 scRet; + UINT8 *ptr, *args; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, *ip); + args = UINT32_TO_STREAM(args, ulPingAttempts); + args = UINT32_TO_STREAM(args, ulPingSize); + args = UINT32_TO_STREAM(args, ulPingTimeout); + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_PING_SEND, ptr, NETAPP_PING_SEND_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_PING_SEND, &scRet); + + return(scRet); +} +#endif + +//***************************************************************************** +// +//! netapp_ping_report +//! +//! @param none +//! +//! @return none +//! +//! @brief Request for ping status. This API triggers the CC3000 to send +//! asynchronous events: HCI_EVNT_WLAN_ASYNC_PING_REPORT. +//! This event will carry the report structure: +//! netapp_pingreport_args_t. This structure is filled in with ping +//! results up till point of triggering API. +//! netapp_pingreport_args_t:\n packets_sent - echo sent, +//! packets_received - echo reply, min_round_time - minimum +//! round time, max_round_time - max round time, +//! avg_round_time - average round time +//! +//! @note When a ping operation is not active, the returned structure +//! fields are 0. +//! +//***************************************************************************** + + +#ifndef CC3000_TINY_DRIVER +void netapp_ping_report() +{ + UINT8 *ptr; + ptr = tSLInformation.pucTxCommandBuffer; + INT8 scRet; + + scRet = EFAIL; + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_PING_REPORT, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_PING_REPORT, &scRet); +} +#endif + +//***************************************************************************** +// +//! netapp_ping_stop +//! +//! @param none +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief Stop any ping request. +//! +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 netapp_ping_stop() +{ + INT8 scRet; + UINT8 *ptr; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_PING_STOP, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_PING_STOP, &scRet); + + return(scRet); +} +#endif + +//***************************************************************************** +// +//! netapp_ipconfig +//! +//! @param[out] ipconfig This argument is a pointer to a +//! tNetappIpconfigRetArgs structure. This structure is +//! filled in with the network interface configuration. +//! tNetappIpconfigRetArgs:\n aucIP - ip address, +//! aucSubnetMask - mask, aucDefaultGateway - default +//! gateway address, aucDHCPServer - dhcp server address +//! aucDNSServer - dns server address, uaMacAddr - mac +//! address, uaSSID - connected AP ssid +//! +//! @return none +//! +//! @brief Obtain the CC3000 Network interface information. +//! Note that the information is available only after the WLAN +//! connection was established. Calling this function before +//! associated, will cause non-defined values to be returned. +//! +//! @note The function is useful for figuring out the IP Configuration of +//! the device when DHCP is used and for figuring out the SSID of +//! the Wireless network the device is associated with. +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +void netapp_ipconfig( tNetappIpconfigRetArgs * ipconfig ) +{ + UINT8 *ptr; + + ptr = tSLInformation.pucTxCommandBuffer; + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_IPCONFIG, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_IPCONFIG, ipconfig ); + +} +#else +void netapp_ipconfig( tNetappIpconfigRetArgs * ipconfig ) +{ + +} +#endif + +//***************************************************************************** +// +//! netapp_arp_flush +//! +//! @param none +//! +//! @return none +//! +//! @brief Flushes ARP table +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 netapp_arp_flush(void) +{ + INT8 scRet; + UINT8 *ptr; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + + // Initiate a HCI command + hci_command_send(HCI_NETAPP_ARP_FLUSH, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_NETAPP_ARP_FLUSH, &scRet); + + return(scRet); +} +#endif + +//***************************************************************************** +// +//! netapp_set_debug_level +//! +//! @param[in] level debug level. Bitwise [0-8], +//! 0(disable)or 1(enable).\n Bitwise map: 0 - Critical +//! message, 1 information message, 2 - core messages, 3 - +//! HCI messages, 4 - Network stack messages, 5 - wlan +//! messages, 6 - wlan driver messages, 7 - epprom messages, +//! 8 - general messages. Default: 0x13f. Saved: no +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Debug messages sent via the UART debug channel, this function +//! enable/disable the debug level +//! +//***************************************************************************** + + +#ifndef CC3000_TINY_DRIVER +INT32 netapp_set_debug_level(UINT32 ulLevel) +{ + INT8 scRet; + UINT8 *ptr, *args; + + scRet = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // + // Fill in temporary command buffer + // + args = UINT32_TO_STREAM(args, ulLevel); + + + // + // Initiate a HCI command + // + hci_command_send(HCI_NETAPP_SET_DEBUG_LEVEL, ptr, NETAPP_SET_DEBUG_LEVEL_PARAMS_LEN); + + // + // Wait for command complete event + // + SimpleLinkWaitEvent(HCI_NETAPP_SET_DEBUG_LEVEL, &scRet); + + return(scRet); + +} +#endif diff --git a/src/openmv/src/micropython/drivers/cc3000/src/nvmem.c b/src/openmv/src/micropython/drivers/cc3000/src/nvmem.c new file mode 100755 index 0000000..c6e170a --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/nvmem.c @@ -0,0 +1,334 @@ +/***************************************************************************** +* +* nvmem.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ + +//***************************************************************************** +// +//! \addtogroup nvmem_api +//! @{ +// +//***************************************************************************** + +#include +#include "nvmem.h" +#include "hci.h" +#include "socket.h" +#include "evnt_handler.h" + +//***************************************************************************** +// +// Prototypes for the structures for APIs. +// +//***************************************************************************** + +#define NVMEM_READ_PARAMS_LEN (12) +#define NVMEM_CREATE_PARAMS_LEN (8) +#define NVMEM_WRITE_PARAMS_LEN (16) + +//***************************************************************************** +// +//! nvmem_read +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_NVS_FILEID, NVMEM_NVS_SHADOW_FILEID, +//! NVMEM_WLAN_CONFIG_FILEID, NVMEM_WLAN_CONFIG_SHADOW_FILEID, +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! NVMEM_MAC_FILEID, NVMEM_FRONTEND_VARS_FILEID, +//! NVMEM_IP_CONFIG_FILEID, NVMEM_IP_CONFIG_SHADOW_FILEID, +//! NVMEM_BOOTLOADER_SP_FILEID, NVMEM_RM_FILEID, +//! and user files 12-15. +//! @param ulLength number of bytes to read +//! @param ulOffset ulOffset in file from where to read +//! @param buff output buffer pointer +//! +//! @return on success 0, error otherwise. +//! +//! @brief Reads data from the file referred by the ulFileId parameter. +//! Reads data from file ulOffset till length. Err if the file can't +//! be used, is invalid, or if the read is out of bounds. +//! +//***************************************************************************** + +INT32 nvmem_read(UINT32 ulFileId, UINT32 ulLength, UINT32 ulOffset, UINT8 *buff) +{ + UINT8 ucStatus = 0xFF; + UINT8 *ptr; + UINT8 *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, ulFileId); + args = UINT32_TO_STREAM(args, ulLength); + args = UINT32_TO_STREAM(args, ulOffset); + + // Initiate a HCI command + hci_command_send(HCI_CMND_NVMEM_READ, ptr, NVMEM_READ_PARAMS_LEN); + SimpleLinkWaitEvent(HCI_CMND_NVMEM_READ, &ucStatus); + + // In case there is data - read it - even if an error code is returned + // Note: It is the user responsibility to ignore the data in case of an error code + + // Wait for the data in a synchronous way. Here we assume that the buffer is + // big enough to store also parameters of nvmem + + SimpleLinkWaitData(buff, 0, 0); + + return(ucStatus); +} + +//***************************************************************************** +// +//! nvmem_write +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! NVMEM_MAC_FILEID, NVMEM_BOOTLOADER_SP_FILEID, +//! and user files 12-15. +//! @param ulLength number of bytes to write +//! @param ulEntryOffset offset in file to start write operation from +//! @param buff data to write +//! +//! @return on success 0, error otherwise. +//! +//! @brief Write data to nvmem. +//! writes data to file referred by the ulFileId parameter. +//! Writes data to file ulOffset till ulLength.The file id will be +//! marked invalid till the write is done. The file entry doesn't +//! need to be valid - only allocated. +//! +//***************************************************************************** + +INT32 nvmem_write(UINT32 ulFileId, UINT32 ulLength, UINT32 ulEntryOffset, UINT8 *buff) +{ + INT32 iRes; + UINT8 *ptr; + UINT8 *args; + + iRes = EFAIL; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + SPI_HEADER_SIZE + HCI_DATA_CMD_HEADER_SIZE); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, ulFileId); + args = UINT32_TO_STREAM(args, 12); + args = UINT32_TO_STREAM(args, ulLength); + args = UINT32_TO_STREAM(args, ulEntryOffset); + + memcpy((ptr + SPI_HEADER_SIZE + HCI_DATA_CMD_HEADER_SIZE + + NVMEM_WRITE_PARAMS_LEN),buff,ulLength); + + // Initiate a HCI command but it will come on data channel + hci_data_command_send(HCI_CMND_NVMEM_WRITE, ptr, NVMEM_WRITE_PARAMS_LEN, + ulLength); + + SimpleLinkWaitEvent(HCI_EVNT_NVMEM_WRITE, &iRes); + + return(iRes); +} + + +//***************************************************************************** +// +//! nvmem_set_mac_address +//! +//! @param mac mac address to be set +//! +//! @return on success 0, error otherwise. +//! +//! @brief Write MAC address to EEPROM. +//! mac address as appears over the air (OUI first) +//! +//***************************************************************************** + +UINT8 nvmem_set_mac_address(UINT8 *mac) +{ + return nvmem_write(NVMEM_MAC_FILEID, MAC_ADDR_LEN, 0, mac); +} + +//***************************************************************************** +// +//! nvmem_get_mac_address +//! +//! @param[out] mac mac address +//! +//! @return on success 0, error otherwise. +//! +//! @brief Read MAC address from EEPROM. +//! mac address as appears over the air (OUI first) +//! +//***************************************************************************** + +UINT8 nvmem_get_mac_address(UINT8 *mac) +{ + return nvmem_read(NVMEM_MAC_FILEID, MAC_ADDR_LEN, 0, mac); +} + +//***************************************************************************** +// +//! nvmem_write_patch +//! +//! @param ulFileId nvmem file id:\n +//! NVMEM_WLAN_DRIVER_SP_FILEID, NVMEM_WLAN_FW_SP_FILEID, +//! @param spLength number of bytes to write +//! @param spData SP data to write +//! +//! @return on success 0, error otherwise. +//! +//! @brief program a patch to a specific file ID. +//! The SP data is assumed to be organized in 2-dimensional. +//! Each line is SP_PORTION_SIZE bytes long. Actual programming is +//! applied in SP_PORTION_SIZE bytes portions. +//! +//***************************************************************************** + +UINT8 nvmem_write_patch(UINT32 ulFileId, UINT32 spLength, const UINT8 *spData) +{ + UINT8 status = 0; + UINT16 offset = 0; + UINT8* spDataPtr = (UINT8*)spData; + + while ((status == 0) && (spLength >= SP_PORTION_SIZE)) + { + status = nvmem_write(ulFileId, SP_PORTION_SIZE, offset, spDataPtr); + offset += SP_PORTION_SIZE; + spLength -= SP_PORTION_SIZE; + spDataPtr += SP_PORTION_SIZE; + } + + if (status !=0) + { + // NVMEM error occurred + return status; + } + + if (spLength != 0) + { + // if reached here, a reminder is left + status = nvmem_write(ulFileId, spLength, offset, spDataPtr); + } + + return status; +} + +//***************************************************************************** +// +//! nvmem_read_sp_version +//! +//! @param[out] patchVer first number indicates package ID and the second +//! number indicates package build number +//! +//! @return on success 0, error otherwise. +//! +//! @brief Read patch version. read package version (WiFi FW patch, +//! driver-supplicant-NS patch, bootloader patch) +//! +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +UINT8 nvmem_read_sp_version(UINT8* patchVer) +{ + UINT8 *ptr; + // 1st byte is the status and the rest is the SP version + UINT8 retBuf[5]; + + ptr = tSLInformation.pucTxCommandBuffer; + + // Initiate a HCI command, no args are required + hci_command_send(HCI_CMND_READ_SP_VERSION, ptr, 0); + SimpleLinkWaitEvent(HCI_CMND_READ_SP_VERSION, retBuf); + + // package ID + *patchVer = retBuf[3]; + // package build number + *(patchVer+1) = retBuf[4]; + + return(retBuf[0]); +} +#endif + +//***************************************************************************** +// +//! nvmem_create_entry +//! +//! @param ulFileId nvmem file Id:\n +//! * NVMEM_AES128_KEY_FILEID: 12 +//! * NVMEM_SHARED_MEM_FILEID: 13 +//! * and fileIDs 14 and 15 +//! @param ulNewLen entry ulLength +//! +//! @return on success 0, error otherwise. +//! +//! @brief Create new file entry and allocate space on the NVMEM. +//! Applies only to user files. +//! Modify the size of file. +//! If the entry is unallocated - allocate it to size +//! ulNewLen (marked invalid). +//! If it is allocated then deallocate it first. +//! To just mark the file as invalid without resizing - +//! set ulNewLen=0. +//! +//***************************************************************************** + +INT32 nvmem_create_entry(UINT32 ulFileId, UINT32 ulNewLen) +{ + UINT8 *ptr; + UINT8 *args; + UINT8 retval; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, ulFileId); + args = UINT32_TO_STREAM(args, ulNewLen); + + // Initiate a HCI command + hci_command_send(HCI_CMND_NVMEM_CREATE_ENTRY,ptr, NVMEM_CREATE_PARAMS_LEN); + + SimpleLinkWaitEvent(HCI_CMND_NVMEM_CREATE_ENTRY, &retval); + + return(retval); +} + + + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3000/src/patch.c b/src/openmv/src/micropython/drivers/cc3000/src/patch.c new file mode 100755 index 0000000..227be3c --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/patch.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * + * {PatchProgrammer_DR_Patch.c} + * + * Burn Patches to EEPROM + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * ALL RIGHTS RESERVED + * + *****************************************************************************/ +// +// Service Pack version P1.13.7.15.28 - Driver patches +// This file contains the CC3K driver and firmware patches +// From CC3000-FRAM-PATCH V:1.13.7 15-MAY-2014 + +unsigned short fw_length = 5700; +unsigned short drv_length = 8024; + +const unsigned char wlan_drv_patch[8024] = { 0x00, 0x01, 0x00, 0x00, 0x50, 0x1F, 0x00, 0x00, 0xF0, 0x03, 0x18, 0x00, 0xE4, 0x62, 0x08, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xFF, 0x7A, 0x63, 0x08, 0x00, 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, 0x00, 0x00, 0x00 , +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xFF, 0x10, 0x64, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x0C, 0x49, 0x08, 0x60, 0x0C, 0x48, 0x19, 0x30, 0xF7, 0x46, 0x30, 0xB5, 0x05, 0x1C, 0xAC, 0x69, 0x68, 0x68, 0x5F, 0x30, 0x09, 0xD1, 0x60, 0x6B, 0x0C, 0x38, 0x01, 0x21, 0x8E, 0x46, 0x06, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x00, 0x20, 0x60, 0x63, 0xAC, 0x69, 0x6C, 0x60, 0x04, 0x48, 0x5B, 0x30, 0x30, 0xBD, 0x40, 0x3B, 0x08, 0x00, 0x49, 0xD0, 0x01, 0x00, 0x09, 0xEA, 0x02, 0x00, 0x91, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xFF, 0xA6, 0x64, 0x08, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xFF, 0x3C, 0x65, 0x08, 0x00, 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, 0xF0, 0xB5, 0x85, 0xB0, 0x05, 0x1C, 0xA8, 0x88, 0x00, 0x90, 0x28, 0x89, 0x01, 0x90, 0xE9, 0x68, 0x02, 0x91, 0x28, 0x7C, 0x03, 0x90, 0x2A, 0x6A, 0x00, 0x20, 0x17, 0x56, 0x68, 0x60, 0x00, 0x29, 0x4C, 0xD0, 0x00, 0x2F, 0x4A, 0xDC , +0xCA, 0x49, 0x0C, 0x1C, 0x08, 0x26, 0x04, 0x90, 0x21, 0x88, 0x00, 0x98, 0x81, 0x42, 0x0C, 0xD1, 0x62, 0x88, 0x01, 0x98, 0x82, 0x42, 0x08, 0xD1, 0x46, 0x20, 0x02, 0x5D, 0x03, 0x98, 0x82, 0x42, 0x03, 0xD1, 0x0E, 0x20, 0x00, 0x57, 0xB8, 0x42, 0x0A, 0xD0, 0x46, 0x20, 0x00, 0x5D, 0x11, 0x28, 0x22, 0xD1, 0x00, 0x98, 0x81, 0x42, 0x1F, 0xD1, 0x0E, 0x20, 0x00, 0x57, 0xFF, 0xFF, 0xD2, 0x65, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xB8, 0x42, 0x1B, 0xD1, 0x04, 0x20, 0x02, 0x1C, 0x02, 0x98, 0xB9, 0x49, 0x01, 0x23, 0x9E, 0x46, 0xEC, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x17, 0xD0, 0x20, 0x1D, 0x02, 0x99, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0xE7, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x0D, 0xD0, 0x46, 0x20, 0x00, 0x5D, 0x11, 0x28, 0x09, 0xD0, 0xA0, 0x6D, 0x00, 0x28, 0x06, 0xD0, 0xAC, 0x34, 0x04, 0x98, 0x01, 0x30, 0x04, 0x90, 0x01, 0x3E, 0xC1, 0xD1, 0x07, 0xE0, 0x04, 0x98, 0x00, 0x06, 0x00, 0x0E , +0xAC, 0x21, 0x41, 0x43, 0xA6, 0x48, 0x40, 0x18, 0x68, 0x60, 0xA6, 0x48, 0xAD, 0x30, 0x05, 0xB0, 0xF0, 0xBD, 0x00, 0xB5, 0xC2, 0x68, 0x90, 0x69, 0x02, 0x21, 0x01, 0x23, 0x9E, 0x46, 0xA2, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xA2, 0x48, 0x61, 0x30, 0x00, 0xBD, 0x01, 0x79, 0x0B, 0x29, 0x03, 0xD0, 0x89, 0x00, 0x9F, 0x4A, 0x51, 0x5A, 0x01, 0xE0, 0x01, 0x21, 0x49, 0x02, 0x41, 0x60, 0x9D, 0x48, 0x0D, 0x30, 0xF7, 0x46, 0x01, 0x1C, 0xFF, 0xFF, 0x68, 0x66, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x9C, 0x48, 0x02, 0x68, 0x9C, 0x48, 0x01, 0x2A, 0x01, 0xD1, 0x25, 0x30, 0xF7, 0x46, 0x9B, 0x4A, 0x12, 0x68, 0x4A, 0x60, 0x19, 0x30, 0xF7, 0x46, 0x00, 0x21, 0x41, 0x60, 0x99, 0x48, 0x98, 0x49, 0x08, 0x18, 0xF7, 0x46, 0x00, 0x21, 0x41, 0x60, 0x97, 0x48, 0xE7, 0x49, 0x08, 0x18, 0xF7, 0x46, 0xFF, 0xB5, 0x46, 0x69, 0x40, 0x68, 0x01, 0x90, 0x94, 0x49, 0x0A, 0x7C, 0x9A, 0x4F, 0x01, 0x2A, 0x63, 0xD0, 0x09, 0x7C, 0x03, 0x29 , +0x60, 0xD0, 0x91, 0x4A, 0x92, 0x4B, 0x00, 0x21, 0x02, 0x91, 0x59, 0x56, 0x24, 0x23, 0x59, 0x43, 0x53, 0x18, 0x03, 0x93, 0x01, 0x28, 0x17, 0xD1, 0x8A, 0x18, 0x04, 0x23, 0x6C, 0x46, 0x8C, 0x49, 0x15, 0x79, 0x08, 0x78, 0xC0, 0x43, 0x28, 0x43, 0x20, 0x70, 0x01, 0x32, 0x01, 0x31, 0x01, 0x34, 0x01, 0x3B, 0xF5, 0xD1, 0x31, 0x1D, 0x68, 0x46, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0xA9, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x40, 0xD0, 0x35, 0x1D, 0x82, 0x48, 0x00, 0x78, 0xFF, 0x28, 0xFF, 0xFF, 0xFE, 0x66, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x11, 0xD0, 0x00, 0x28, 0x0F, 0xD0, 0x03, 0x98, 0x01, 0x1D, 0x28, 0x1C, 0x01, 0x24, 0xA6, 0x46, 0x7E, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x00, 0x28, 0x05, 0xD1, 0x7A, 0x48, 0xA6, 0x46, 0x7B, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x05, 0xE0, 0x28, 0x1C, 0x01, 0x21, 0x8E, 0x46, 0x78, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x01, 0x99, 0x01, 0x29, 0x01, 0xD1, 0x00, 0x28, 0x1E, 0xD1 , +0x01, 0x99, 0x5F, 0x31, 0x01, 0xD0, 0x00, 0x28, 0x0F, 0xD1, 0xA8, 0x20, 0x81, 0x5D, 0x00, 0x29, 0x08, 0xD0, 0x49, 0x1E, 0x81, 0x55, 0x80, 0x5D, 0x00, 0x28, 0x09, 0xD1, 0x38, 0x1C, 0xFF, 0x30, 0x08, 0x30, 0x11, 0xE0, 0x03, 0x21, 0x02, 0x91, 0x00, 0xE0, 0xA8, 0x20, 0x02, 0x99, 0x81, 0x55, 0x38, 0x1C, 0xFF, 0x30, 0x16, 0x30, 0x07, 0xE0, 0x01, 0x98, 0x01, 0x28, 0x02, 0xD1, 0x38, 0x1C, 0xA3, 0x30, 0x01, 0xE0, 0x38, 0x1C, 0x9F, 0x30, 0x00, 0x90, 0xFF, 0xBD, 0x00, 0xB5, 0x02, 0x1C, 0x10, 0x6A, 0xD1, 0x69, 0x52, 0x69, 0xC3, 0x69, 0x5A, 0x60, 0xFF, 0xFF, 0x94, 0x67, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x01, 0x22, 0x96, 0x46, 0x5E, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x5E, 0x48, 0xFF, 0x30, 0x6E, 0x30, 0x00, 0xBD, 0x10, 0xB5, 0x0A, 0x1C, 0x41, 0x69, 0x00, 0x6A, 0x93, 0x69, 0xDB, 0x69, 0x58, 0x60, 0x90, 0x69, 0x01, 0x24, 0xA6, 0x46, 0x56, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0xA6, 0x46, 0x56, 0x48, 0xFE, 0x44 , +0x00, 0x47, 0x55, 0x48, 0xFF, 0x30, 0xB6, 0x30, 0x10, 0xBD, 0x70, 0xB5, 0x05, 0x1C, 0x6E, 0x69, 0x53, 0x48, 0x02, 0x68, 0x5C, 0x21, 0x88, 0x5D, 0x04, 0x28, 0x15, 0xD1, 0x07, 0x20, 0x88, 0x55, 0x10, 0x0B, 0x11, 0xD2, 0x01, 0x24, 0xA6, 0x46, 0x4E, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x00, 0x28, 0x0A, 0xD0, 0x47, 0x21, 0x89, 0x57, 0xC1, 0x60, 0x11, 0x21, 0xC9, 0x02, 0x00, 0x22, 0x04, 0x23, 0xA6, 0x46, 0xE8, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x01, 0x20, 0x68, 0x60, 0x43, 0x48, 0xED, 0x49, 0x08, 0x18, 0x70, 0xBD, 0x70, 0xB5, 0x05, 0x1C, 0xAE, 0x69, 0x9C, 0x20, 0x80, 0x19, 0x4B, 0x21, 0x89, 0x00, 0x01, 0x24, 0xFF, 0xFF, 0x2A, 0x68, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xA6, 0x46, 0xE8, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x5C, 0x21, 0x88, 0x5D, 0x07, 0x28, 0x01, 0xD1, 0x09, 0x20, 0x00, 0xE0, 0x05, 0x20, 0xAA, 0x69, 0x88, 0x54, 0x30, 0x1C, 0xA6, 0x46, 0xE9, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x68, 0x60, 0xE8, 0x48 , +0x4D, 0x30, 0x70, 0xBD, 0xF0, 0xB5, 0x41, 0x68, 0x82, 0x68, 0x88, 0x23, 0x5E, 0x18, 0x37, 0x88, 0x0B, 0x6F, 0x00, 0x2B, 0x01, 0xD1, 0x00, 0x2F, 0x10, 0xD1, 0x06, 0x2F, 0x02, 0xDD, 0x00, 0x21, 0xC9, 0x43, 0x07, 0xE0, 0x33, 0x88, 0x9B, 0x00, 0xC9, 0x18, 0x0A, 0x67, 0x31, 0x88, 0x01, 0x31, 0x31, 0x80, 0x01, 0x21, 0x81, 0x60, 0xE1, 0x48, 0x1D, 0x30, 0xF0, 0xBD, 0x0B, 0x1C, 0x01, 0x24, 0x5D, 0x6F, 0x1D, 0x67, 0x04, 0x33, 0x01, 0x34, 0x06, 0x2C, 0xE1, 0xDA, 0xF8, 0xE7, 0x00, 0xB5, 0x00, 0x21, 0xC1, 0x60, 0xE9, 0x48, 0x01, 0x68, 0x10, 0x31, 0xE6, 0x48, 0x20, 0x22, 0x01, 0x23, 0x9E, 0x46, 0xE7, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xE5, 0x48, 0xFB, 0x30, 0x00, 0xBD, 0xFF, 0xFF, 0xC0, 0x68, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x14, 0x0D, 0x1B, 0x00, 0x54, 0x19, 0x1B, 0x00, 0x91, 0x1A, 0x01, 0x00, 0x4B, 0xAD, 0x03, 0x00, 0x61, 0x4E, 0x01, 0x00, 0x06, 0x32, 0x08, 0x00, 0x1F, 0x0B, 0x02, 0x00, 0x54, 0x3F , +0x08, 0x00, 0x45, 0xC1, 0x00, 0x00, 0x84, 0x3C, 0x08, 0x00, 0x1B, 0x02, 0x00, 0x00, 0xED, 0x17, 0x00, 0x00, 0xF3, 0xC1, 0x01, 0x00, 0x34, 0x19, 0x1B, 0x00, 0x08, 0x19, 0x1B, 0x00, 0xA6, 0x44, 0x08, 0x00, 0x1C, 0x17, 0x1B, 0x00, 0x18, 0x17, 0x1B, 0x00, 0xCB, 0x67, 0x03, 0x00, 0x0D, 0x47, 0x02, 0x00, 0x39, 0x42, 0x03, 0x00, 0xBD, 0xE7, 0x02, 0x00, 0xB1, 0x40, 0x03, 0x00, 0xB9, 0xEA, 0x01, 0x00, 0x45, 0xDA, 0x00, 0x00, 0x24, 0x41, 0x08, 0x00, 0x71, 0xC0, 0x02, 0x00, 0xF0, 0xB5, 0x88, 0xB0, 0x06, 0x91, 0x07, 0x90, 0x86, 0x69, 0xF0, 0x1C, 0xD9, 0xA1, 0x04, 0x22, 0x01, 0x24, 0xA6, 0x46, 0x14, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x32, 0xD1, 0xF2, 0x79, 0xD7, 0x48, 0x02, 0x70, 0x35, 0x7A, 0x77, 0x7A, 0x78, 0x1B, 0xFF, 0xFF, 0x56, 0x69, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x43, 0x1C, 0x93, 0x42, 0x1D, 0xD0, 0x16, 0x2A, 0x0C, 0xDB, 0x00, 0x2D, 0x0A, 0xD1, 0xD6, 0x48, 0x04, 0x70, 0x0A, 0x20 , +0x81, 0x19, 0xD0, 0x48, 0x1A, 0x1C, 0xA6, 0x46, 0xB8, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x74, 0xE0, 0xD2, 0x48, 0x04, 0x70, 0xCC, 0x48, 0x40, 0x19, 0x0A, 0x21, 0x89, 0x19, 0x7A, 0x1B, 0x52, 0x1C, 0xA6, 0x46, 0xB1, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x67, 0xE0, 0x8F, 0xC6, 0x03, 0x00, 0xC9, 0x48, 0x04, 0x70, 0xC9, 0x48, 0x04, 0x70, 0x0A, 0x20, 0x81, 0x19, 0xC2, 0x48, 0xA6, 0x46, 0xAA, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x59, 0xE0, 0xF0, 0x1C, 0x03, 0x21, 0x0A, 0x1C, 0xBC, 0xA1, 0xA6, 0x46, 0xC6, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x4F, 0xD1, 0xF1, 0x79, 0xBB, 0x48, 0x01, 0x70, 0xBB, 0x4D, 0xB2, 0x79, 0x2A, 0x70, 0x03, 0x20, 0x17, 0x49, 0xF4, 0x31, 0xA6, 0x46, 0xB8, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x28, 0x78, 0x00, 0x28, 0x0B, 0xD1, 0xFF, 0xE7, 0xB8, 0x49, 0x0C, 0x70, 0xB8, 0x49, 0xFF, 0xFF, 0xEC, 0x69, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0C, 0x70, 0x03, 0x20, 0x0F, 0x49, 0xF5, 0x31, 0xA6, 0x46 , +0xB6, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x20, 0x1C, 0xF2, 0x79, 0x35, 0x7A, 0x77, 0x7A, 0x79, 0x1B, 0x4B, 0x1C, 0x93, 0x42, 0x20, 0xD0, 0xA9, 0x49, 0x09, 0x78, 0x16, 0x29, 0x0F, 0xDB, 0x00, 0x2D, 0x0D, 0xD1, 0xAB, 0x49, 0x08, 0x70, 0x0A, 0x20, 0x81, 0x19, 0xE9, 0x48, 0x1A, 0x1C, 0xA6, 0x46, 0x8B, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x1A, 0xE0, 0xC0, 0x46, 0xC7, 0x04, 0x00, 0x00, 0xA5, 0x49, 0x08, 0x70, 0xE3, 0x48, 0x40, 0x19, 0x0A, 0x21, 0x89, 0x19, 0x7A, 0x1B, 0x52, 0x1C, 0xA6, 0x46, 0x83, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x0A, 0xE0, 0x9E, 0x49, 0x08, 0x70, 0x9E, 0x49, 0x08, 0x70, 0x0A, 0x20, 0x81, 0x19, 0xDB, 0x48, 0xA6, 0x46, 0x7D, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x96, 0x48, 0x00, 0x78, 0x00, 0x28, 0x0A, 0xD0, 0x95, 0x48, 0x00, 0x78, 0x00, 0x28, 0x06, 0xD0, 0x94, 0x48, 0x00, 0x78, 0x00, 0x28, 0x02, 0xD0, 0x93, 0x48, 0x00, 0x78, 0x00, 0x28, 0xFF, 0xFF, 0x82, 0x6A, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00 , +0x00, 0xD1, 0x8C, 0xE0, 0x03, 0x20, 0x17, 0x21, 0x89, 0x01, 0xA6, 0x46, 0x90, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x87, 0x48, 0x01, 0x78, 0x87, 0x48, 0x07, 0x78, 0x84, 0x4E, 0x83, 0x4D, 0xE0, 0x48, 0x00, 0x68, 0x00, 0x28, 0x2E, 0xD1, 0x07, 0x98, 0x41, 0x61, 0x06, 0x62, 0xC6, 0x48, 0x06, 0x9A, 0x10, 0x64, 0x02, 0x2F, 0x01, 0xD0, 0x03, 0x2F, 0x01, 0xD1, 0x03, 0x22, 0x00, 0xE0, 0x3A, 0x1C, 0x06, 0x9B, 0xDA, 0x63, 0x2A, 0x78, 0x9A, 0x63, 0x01, 0x2F, 0x03, 0xD1, 0x05, 0x29, 0x04, 0xD0, 0x0D, 0x29, 0x02, 0xD0, 0xEC, 0x48, 0xDB, 0x30, 0x64, 0xE0, 0x00, 0x25, 0x00, 0x95, 0x01, 0x91, 0x02, 0x96, 0x03, 0x95, 0x04, 0x90, 0x2B, 0x1C, 0x20, 0x1C, 0x01, 0x1C, 0x8E, 0x46, 0xE6, 0x4E, 0xFE, 0x44, 0x30, 0x47, 0xE6, 0x48, 0x04, 0x60, 0x28, 0x1C, 0xA6, 0x46, 0xE5, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x4C, 0xE0, 0x0D, 0x27, 0x00, 0x20, 0x39, 0x1C, 0x05, 0xAA, 0xA6, 0x46, 0xE3, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x68, 0x46 , +0xFF, 0xFF, 0x18, 0x6B, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x80, 0x8A, 0x40, 0x08, 0x05, 0xD2, 0x38, 0x1C, 0x50, 0x21, 0xA6, 0x46, 0xDC, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x38, 0x1C, 0x21, 0x1C, 0x0B, 0x1C, 0x29, 0x1C, 0x00, 0x22, 0xA6, 0x46, 0xD9, 0x4F, 0xFE, 0x44, 0x38, 0x47, 0x2B, 0x78, 0x0D, 0x20, 0x31, 0x1C, 0x22, 0x1C, 0xA6, 0x46, 0xD5, 0x4E, 0xFE, 0x44, 0x30, 0x47, 0x28, 0x78, 0x01, 0x30, 0x02, 0x1C, 0x0D, 0x20, 0x57, 0x49, 0x23, 0x1C, 0xA6, 0x46, 0xD0, 0x4E, 0xFE, 0x44, 0x30, 0x47, 0x55, 0x4E, 0x28, 0x78, 0x02, 0x30, 0x02, 0x1C, 0x0D, 0x20, 0x31, 0x1C, 0x23, 0x1C, 0xA6, 0x46, 0xCA, 0x4F, 0xFE, 0x44, 0x38, 0x47, 0x30, 0x78, 0x00, 0x28, 0x0A, 0xD0, 0x28, 0x78, 0x03, 0x30, 0x02, 0x1C, 0x4C, 0x48, 0x03, 0x78, 0x0D, 0x20, 0x8F, 0x49, 0xA6, 0x46, 0xC3, 0x4D, 0xFE, 0x44, 0x28, 0x47, 0xBF, 0x48, 0x04, 0x60, 0x00, 0x20, 0xA6, 0x46, 0xBE, 0x49, 0xFE, 0x44, 0x08, 0x47, 0xB9, 0x48, 0xEC, 0x49 , +0x08, 0x18, 0x08, 0xB0, 0xF0, 0xBD, 0xC0, 0x46, 0x7B, 0xC0, 0xFF, 0xFF, 0xAE, 0x6B, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x1C, 0xE9, 0x48, 0x02, 0x68, 0xE9, 0x48, 0x00, 0x2A, 0x04, 0xD0, 0x00, 0x22, 0x0A, 0x62, 0x8A, 0x61, 0x1D, 0x30, 0xF7, 0x46, 0xD7, 0x30, 0xF7, 0x46, 0xC0, 0x46, 0x9F, 0x03, 0x00, 0x00, 0x7D, 0xB8, 0x03, 0x00, 0x01, 0x1C, 0xE2, 0x48, 0x02, 0x68, 0xE2, 0x48, 0x00, 0x2A, 0x02, 0xD0, 0xFF, 0x30, 0xB4, 0x30, 0xF7, 0x46, 0x00, 0x22, 0xCA, 0x61, 0x8A, 0x61, 0x4F, 0x30, 0xF7, 0x46, 0xC9, 0x21, 0x01, 0x00, 0x91, 0xE1, 0x00, 0x00, 0xDB, 0x48, 0x01, 0x68, 0x8A, 0x69, 0x01, 0x20, 0xC0, 0x03, 0x10, 0x43, 0x88, 0x61, 0x00, 0x20, 0x08, 0x61, 0xD8, 0x48, 0x23, 0x30, 0xF7, 0x46, 0x89, 0x17, 0x02, 0x00, 0x70, 0xB5, 0x05, 0x1C, 0xD5, 0x4E, 0x29, 0x6A, 0xEA, 0x69, 0x30, 0x1C, 0x01, 0x24, 0xA6, 0x46, 0x0B, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x68, 0x69, 0xA6, 0x46, 0xD1, 0x49 , +0xFE, 0x44, 0x08, 0x47, 0xA8, 0x69, 0x06, 0x30, 0xA8, 0x60, 0xCF, 0x48, 0x00, 0x68, 0x68, 0x60, 0xEE, 0x60, 0xCE, 0x48, 0xFF, 0xFF, 0x44, 0x6C, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x6D, 0x30, 0x70, 0xBD, 0x46, 0x17, 0x1B, 0x00, 0x30, 0x3F, 0x08, 0x00, 0x41, 0xEB, 0x00, 0x00, 0x09, 0xB4, 0x03, 0x00, 0x30, 0xB5, 0xEE, 0x48, 0x01, 0x6D, 0x80, 0x6C, 0x08, 0x43, 0x18, 0xD0, 0xEC, 0x49, 0x08, 0x1C, 0x07, 0x22, 0xFF, 0x23, 0x09, 0x33, 0x1B, 0x58, 0x00, 0x2B, 0x04, 0xD0, 0xFF, 0x30, 0x1D, 0x30, 0x01, 0x3A, 0xF6, 0xD1, 0x0B, 0xE0, 0x02, 0x20, 0xF0, 0x4A, 0xF1, 0x4B, 0x01, 0x24, 0xA6, 0x46, 0xF0, 0x4D, 0xFE, 0x44, 0x28, 0x47, 0xA6, 0x46, 0xEF, 0x48, 0xFE, 0x44, 0x00, 0x47, 0xEF, 0x48, 0xFF, 0x30, 0x5C, 0x30, 0x30, 0xBD, 0xC0, 0x46, 0x53, 0x53, 0x49, 0x44, 0x00, 0xC0, 0x46, 0xC0, 0x4B, 0x45, 0x59, 0x00, 0xEE, 0x62, 0x08, 0x00, 0xF0, 0x62, 0x08, 0x00, 0xEC, 0x62, 0x08, 0x00, 0xED, 0x62, 0x08, 0x00 , +0xE7, 0x7E, 0x03, 0x00, 0xE8, 0x62, 0x08, 0x00, 0xE9, 0x62, 0x08, 0x00, 0xEA, 0x62, 0x08, 0x00, 0xEB, 0x62, 0x08, 0x00, 0xDD, 0x7E, 0x03, 0x00, 0x8F, 0xC6, 0x03, 0x00, 0xF0, 0xB5, 0xFF, 0xFF, 0xDA, 0x6C, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x87, 0xB0, 0x00, 0x91, 0x01, 0x90, 0x6B, 0x48, 0x01, 0x68, 0xCC, 0x4A, 0x14, 0x1C, 0x02, 0x94, 0x07, 0x26, 0x00, 0x25, 0x03, 0x95, 0x04, 0x94, 0x05, 0x95, 0xDF, 0x48, 0x00, 0x68, 0x08, 0x43, 0x27, 0xD0, 0xE0, 0x68, 0x03, 0x99, 0x88, 0x42, 0x0A, 0xDD, 0x03, 0x90, 0x40, 0x1C, 0x00, 0x99, 0x88, 0x60, 0xC2, 0x49, 0xFF, 0x20, 0x1D, 0x30, 0x68, 0x43, 0x0C, 0x18, 0xE0, 0x68, 0x04, 0x91, 0x02, 0x99, 0xC9, 0x68, 0x88, 0x42, 0x10, 0xDB, 0x88, 0x42, 0x10, 0xD1, 0x02, 0x98, 0x01, 0x27, 0xBE, 0x46, 0xCE, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x06, 0x90, 0x20, 0x1C, 0xBE, 0x46, 0xCB, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x06, 0x99, 0x88, 0x42, 0x01, 0xDA, 0x05, 0x95, 0x02, 0x94 , +0x51, 0x48, 0x01, 0x68, 0xFF, 0x27, 0x09, 0x37, 0x38, 0x59, 0x00, 0x28, 0x06, 0xD0, 0xC7, 0x48, 0x00, 0x68, 0x07, 0x2E, 0x00, 0xD1, 0x2E, 0x1C, 0x08, 0x43, 0x04, 0xD0, 0xFF, 0x34, 0x1D, 0x34, 0x01, 0x35, 0x07, 0x2D, 0xC2, 0xDB, 0x07, 0x2E, 0xFF, 0xFF, 0x70, 0x6D, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0A, 0xD1, 0xC0, 0x48, 0x00, 0x68, 0x08, 0x43, 0x06, 0xD0, 0x05, 0x9E, 0x30, 0x1C, 0x01, 0x21, 0x8E, 0x46, 0xBA, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x01, 0x98, 0x47, 0x61, 0x00, 0x21, 0x81, 0x61, 0xFF, 0x22, 0x1D, 0x32, 0x72, 0x43, 0x04, 0x99, 0x89, 0x18, 0xC1, 0x61, 0x06, 0x62, 0xB4, 0x48, 0x39, 0x30, 0x07, 0xB0, 0xF0, 0xBD, 0x10, 0xB5, 0x04, 0x1C, 0x00, 0x20, 0x01, 0x21, 0x8E, 0x46, 0xB1, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x40, 0x1E, 0x00, 0xD5, 0x00, 0x20, 0x60, 0x60, 0xE0, 0x61, 0xAE, 0x48, 0x21, 0x30, 0x10, 0xBD, 0xC0, 0x46, 0x10, 0x63, 0x08, 0x00, 0x70, 0xB5, 0x04, 0x1C, 0xE5, 0x69, 0x66, 0x69 , +0x00, 0x20, 0x01, 0x21, 0x8E, 0x46, 0xA7, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x60, 0x60, 0xAB, 0x19, 0xA6, 0x4A, 0xA5, 0x49, 0x93, 0x42, 0x02, 0xD3, 0x9A, 0x1A, 0x82, 0x42, 0x02, 0xD9, 0x08, 0x1C, 0x99, 0x30, 0x70, 0xBD, 0x08, 0x1C, 0xAB, 0x30, 0x70, 0xBD, 0x08, 0x6B, 0x41, 0x7D, 0x02, 0x88, 0x92, 0x00, 0xFF, 0xFF, 0x06, 0x6E, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x51, 0x1A, 0x3C, 0x39, 0xFF, 0x22, 0x5F, 0x32, 0x91, 0x42, 0x03, 0xD9, 0x65, 0x21, 0x01, 0x80, 0x02, 0x21, 0x81, 0x73, 0x9B, 0x48, 0x99, 0x49, 0x08, 0x18, 0xF7, 0x46, 0xC0, 0x46, 0x30, 0x63, 0x08, 0x00, 0xF8, 0xB5, 0x40, 0x68, 0x24, 0x21, 0x41, 0x43, 0x97, 0x48, 0x45, 0x18, 0x28, 0x1D, 0x0C, 0x21, 0x49, 0x19, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0x94, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x91, 0x4C, 0x00, 0x28, 0x1B, 0xD0, 0x2B, 0x1C, 0x04, 0x22, 0x6E, 0x46, 0x91, 0x49, 0x1F, 0x7B, 0x08, 0x78, 0xC0, 0x43, 0x38, 0x43, 0x30, 0x70, 0x01, 0x33 , +0x01, 0x31, 0x01, 0x36, 0x01, 0x3A, 0xF5, 0xD1, 0x0C, 0x20, 0x41, 0x19, 0x68, 0x46, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0x87, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x02, 0xD0, 0x20, 0x1C, 0x4A, 0x30, 0xF8, 0xBD, 0x20, 0x1C, 0xF8, 0xBD, 0xB1, 0xBD, 0x00, 0x00, 0x15, 0x95, 0x00, 0x00, 0x58, 0x3F, 0x08, 0x00, 0xF3, 0xF8, 0x00, 0x00, 0xE9, 0x09, 0x02, 0x00, 0xFF, 0xFF, 0x9C, 0x6E, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x2B, 0x09, 0x02, 0x00, 0xDD, 0x0A, 0x02, 0x00, 0xF8, 0xB5, 0x05, 0x1C, 0xAA, 0x69, 0x7D, 0x49, 0x00, 0x20, 0x08, 0x56, 0x24, 0x21, 0x41, 0x43, 0x76, 0x48, 0x43, 0x18, 0x04, 0x24, 0x6E, 0x46, 0x76, 0x49, 0x1F, 0x79, 0x08, 0x78, 0xC0, 0x43, 0x38, 0x43, 0x30, 0x70, 0x01, 0x33, 0x01, 0x31, 0x01, 0x36, 0x01, 0x3C, 0xF5, 0xD1, 0x11, 0x1D, 0x68, 0x46, 0x04, 0x22, 0x01, 0x24, 0xA6, 0x46, 0x6D, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x01, 0x1C, 0x6D, 0x48, 0x04, 0xD0, 0x6E, 0x49, 0x09, 0x78 , +0x69, 0x60, 0x45, 0x30, 0xF8, 0xBD, 0xEC, 0x61, 0xAF, 0x30, 0xF8, 0xBD, 0x70, 0xB5, 0xC5, 0x68, 0x81, 0x68, 0x0A, 0x89, 0x6D, 0x4E, 0x00, 0x2A, 0x22, 0xD0, 0x01, 0x24, 0xC2, 0x6D, 0xA2, 0x18, 0xC2, 0x65, 0x08, 0x89, 0x0D, 0x28, 0x1B, 0xD1, 0x68, 0x6B, 0x21, 0x1C, 0xA6, 0x46, 0x63, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x22, 0x1C, 0x28, 0x1C, 0x00, 0x21, 0xA6, 0x46, 0x60, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x2C, 0x60, 0xE9, 0x6B, 0xFF, 0xFF, 0x32, 0x6F, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x28, 0x1C, 0xA6, 0x46, 0x5E, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x28, 0x1C, 0xA6, 0x46, 0x5C, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x30, 0x1C, 0x3D, 0x30, 0x70, 0xBD, 0x30, 0x1C, 0x23, 0x30, 0x70, 0xBD, 0xC0, 0x46, 0xB1, 0x02, 0x00, 0x00, 0x74, 0x3F, 0x08, 0x00, 0x19, 0xC6, 0x00, 0x00, 0x5C, 0x3F, 0x08, 0x00, 0x1D, 0xC2, 0x00, 0x00, 0x68, 0x44, 0x08, 0x00, 0x43, 0x12, 0x03, 0x00, 0x34, 0x63, 0x08, 0x00, 0x2F, 0x7A, 0x02, 0x00 , +0xB4, 0x36, 0x08, 0x00, 0x8F, 0xF4, 0x01, 0x00, 0xF0, 0xB5, 0x05, 0x1C, 0xAB, 0x69, 0xEC, 0x69, 0x60, 0x68, 0x00, 0x68, 0x2A, 0x30, 0x01, 0x78, 0x0A, 0x06, 0x41, 0x78, 0x09, 0x04, 0x8A, 0x18, 0x81, 0x78, 0x09, 0x02, 0x8A, 0x18, 0xC1, 0x78, 0x8A, 0x18, 0x8E, 0x26, 0xF1, 0x5A, 0x09, 0x0A, 0x01, 0x70, 0xF0, 0x5C, 0x61, 0x68, 0x09, 0x68, 0x2B, 0x26, 0x70, 0x54, 0x8C, 0x20, 0xC0, 0x18, 0x61, 0x68, 0x0E, 0x68, 0x01, 0x88, 0x09, 0x0A, 0x2C, 0x27, 0xB9, 0x55, 0x61, 0x68, 0x09, 0x68, 0xFF, 0xFF, 0xC8, 0x6F, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x2D, 0x26, 0x00, 0x78, 0x70, 0x54, 0x60, 0x68, 0x01, 0x68, 0x32, 0x31, 0x08, 0x78, 0x00, 0x02, 0x49, 0x78, 0x08, 0x18, 0x00, 0x04, 0x00, 0x0C, 0x8C, 0x21, 0xCB, 0x58, 0x35, 0x49, 0x41, 0x40, 0x08, 0x04, 0x00, 0x0C, 0xC0, 0x18, 0x80, 0x1A, 0x01, 0x21, 0x8E, 0x46, 0x32, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x61, 0x68, 0x0A, 0x68, 0x32, 0x23, 0x01, 0x0A, 0x99, 0x54 , +0x61, 0x68, 0x09, 0x68, 0x33, 0x22, 0x50, 0x54, 0x60, 0x68, 0x68, 0x60, 0x2C, 0x48, 0xF0, 0xBD, 0x00, 0x00, 0x1B, 0x00, 0x34, 0x04, 0x1B, 0x00, 0x02, 0x6A, 0x8B, 0x69, 0xDB, 0x69, 0x1B, 0x68, 0x83, 0x60, 0x88, 0x69, 0xC0, 0x69, 0x41, 0x68, 0x8A, 0x42, 0x00, 0xDA, 0x42, 0x60, 0x25, 0x48, 0x79, 0x30, 0xF7, 0x46, 0x24, 0x48, 0x57, 0x30, 0xF7, 0x46, 0x24, 0x48, 0x91, 0x30, 0xF7, 0x46, 0x32, 0x04, 0x00, 0x00, 0xC4, 0x07, 0x00, 0x00, 0x15, 0x09, 0x02, 0x00, 0xC5, 0x93, 0x00, 0x00, 0x0D, 0x91, 0x00, 0x00, 0x40, 0x1E, 0x80, 0x00, 0x1E, 0x4B, 0xFF, 0xFF, 0x5E, 0x70, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x19, 0x50, 0x1C, 0x49, 0x0A, 0x50, 0xF7, 0x46, 0xC0, 0x46, 0xBD, 0xB5, 0x00, 0x00, 0x95, 0x92, 0x00, 0x00, 0xFD, 0x93, 0x00, 0x00, 0x54, 0x3F, 0x08, 0x00, 0x29, 0x4F, 0x03, 0x00, 0xDF, 0xE8, 0x02, 0x00, 0x36, 0x89, 0x41, 0x00, 0x81, 0x06, 0x00, 0x00, 0xB1, 0x78, 0x00, 0x00, 0x94, 0xEC, 0x01, 0x00 , +0x08, 0x19, 0x1B, 0x00, 0x8F, 0xC6, 0x03, 0x00, 0x1C, 0x17, 0x1B, 0x00, 0x67, 0x66, 0x03, 0x00, 0xA6, 0x44, 0x08, 0x00, 0x18, 0x17, 0x1B, 0x00, 0xA7, 0x2F, 0x02, 0x00, 0x91, 0x44, 0x03, 0x00, 0x91, 0x63, 0x03, 0x00, 0x5B, 0x44, 0x03, 0x00, 0xE7, 0x44, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x61, 0xA2, 0x03, 0x00, 0x6A, 0x1E, 0x01, 0x00, 0x45, 0xDA, 0x00, 0x00, 0xD7, 0xE8, 0x01, 0x00, 0xE9, 0x78, 0x02, 0x00, 0x04, 0xF3, 0x1A, 0x00, 0x80, 0x7B, 0x08, 0x00, 0xFC, 0xB5, 0x04, 0x1C, 0xA5, 0x69, 0x60, 0x6A, 0x01, 0x90, 0x20, 0x69, 0x00, 0x28, 0x35, 0xD4, 0x08, 0x28, 0x33, 0xDA, 0xE1, 0x69, 0x09, 0x68, 0xFF, 0xFF, 0xF4, 0x70, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x10, 0x29, 0x2F, 0xD1, 0xAC, 0x21, 0x41, 0x43, 0x9E, 0x4A, 0x51, 0x5C, 0x49, 0x08, 0x27, 0xD3, 0x00, 0x06, 0x00, 0x16, 0xA2, 0x68, 0x69, 0x46, 0x01, 0x23, 0x9E, 0x46, 0x9A, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x06, 0x1C, 0x39, 0x30, 0x1F, 0xD0 , +0x00, 0x2E, 0x1D, 0xD0, 0x00, 0x98, 0x07, 0x68, 0x00, 0x99, 0x0C, 0x39, 0x01, 0x98, 0x01, 0x60, 0x28, 0x1D, 0x10, 0x21, 0x79, 0x1A, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0x91, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x02, 0x22, 0x2A, 0x80, 0xA8, 0x1C, 0x08, 0x21, 0x79, 0x1A, 0x01, 0x23, 0x9E, 0x46, 0x8C, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x03, 0xE0, 0x38, 0x20, 0x00, 0xE0, 0x00, 0x20, 0xC6, 0x43, 0x26, 0x60, 0x89, 0x48, 0x7C, 0x30, 0x20, 0x62, 0xFC, 0xBD, 0x30, 0xB5, 0x05, 0x1C, 0x28, 0x69, 0xA9, 0x69, 0x90, 0x29, 0x1D, 0xD1, 0x69, 0x69, 0x09, 0x78, 0x04, 0x29, 0x19, 0xD0, 0x05, 0x29, 0x17, 0xD0, 0x0A, 0x29, 0x15, 0xD0, 0x06, 0x29, 0x13, 0xD0, 0x0C, 0x29, 0x01, 0xDB, 0xFF, 0xFF, 0x8A, 0x71, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x10, 0x29, 0x0F, 0xD1, 0x01, 0x24, 0xA6, 0x46, 0x7D, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x7C, 0x48, 0x7D, 0x49, 0x00, 0x22, 0xA6, 0x46, 0x7C, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x7C, 0x48 , +0xFF, 0x30, 0x5F, 0x30, 0x28, 0x62, 0x30, 0xBD, 0xF0, 0xB5, 0x89, 0xB0, 0x05, 0x90, 0x41, 0x69, 0x02, 0x69, 0x75, 0x48, 0x79, 0x4E, 0x82, 0x42, 0x3A, 0xD0, 0x04, 0x30, 0x82, 0x42, 0x25, 0xD0, 0x74, 0x4D, 0xAA, 0x42, 0x00, 0xD0, 0xCC, 0xE0, 0x08, 0x68, 0x06, 0x1C, 0x0C, 0x22, 0x8F, 0x1A, 0x4A, 0x68, 0x89, 0x18, 0x09, 0x1D, 0x10, 0x22, 0x01, 0x24, 0xA6, 0x46, 0x6E, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x01, 0x1C, 0x09, 0xD1, 0xAC, 0x22, 0x72, 0x43, 0xCB, 0x48, 0x80, 0x18, 0x46, 0x22, 0x12, 0x5C, 0x11, 0x2A, 0x01, 0xD1, 0x44, 0x22, 0x14, 0x54, 0x28, 0x1C, 0x3A, 0x1C, 0xA6, 0x46, 0x62, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x69, 0x48, 0xEC, 0x30, 0xAB, 0xE0, 0x08, 0x68, 0xC0, 0x00, 0x30, 0x18, 0x8A, 0x68, 0x02, 0x2A, 0x02, 0xD0, 0xFF, 0xFF, 0x20, 0x72, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xE7, 0x20, 0x80, 0x00, 0xA2, 0xE0, 0xCA, 0x68, 0x89, 0x18, 0x09, 0x7B, 0x41, 0x60, 0x80, 0x21, 0x01, 0x60, 0x3B, 0x20 , +0x00, 0x01, 0x99, 0xE0, 0x08, 0x68, 0x06, 0x90, 0xC0, 0x00, 0x34, 0x58, 0x10, 0x20, 0x04, 0x90, 0x01, 0x25, 0xAE, 0x46, 0x57, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x07, 0x90, 0x00, 0x28, 0x00, 0xD1, 0x89, 0xE0, 0x0C, 0x21, 0x07, 0x98, 0x0F, 0x18, 0xB0, 0x49, 0xAC, 0x20, 0x06, 0x9A, 0x50, 0x43, 0x08, 0x18, 0x48, 0x22, 0x13, 0x5C, 0x5B, 0x06, 0x5B, 0x0E, 0x13, 0x54, 0x06, 0x9A, 0xD2, 0x00, 0xB6, 0x18, 0x71, 0x68, 0x00, 0x29, 0x47, 0xD1, 0x00, 0x2C, 0x01, 0xDD, 0x08, 0x2C, 0x21, 0xDB, 0x00, 0x22, 0x69, 0x46, 0x0A, 0x70, 0x01, 0x92, 0x0A, 0x81, 0x8A, 0x72, 0xCD, 0x72, 0x0D, 0x73, 0x4D, 0x73, 0x01, 0x88, 0x44, 0x48, 0x06, 0x23, 0xAE, 0x46, 0x44, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x04, 0x1C, 0x02, 0xDC, 0x00, 0x20, 0xC0, 0x43, 0x36, 0xE0, 0x34, 0x60, 0xAC, 0x20, 0x60, 0x43, 0x9A, 0x49, 0xFF, 0xFF, 0xB6, 0x72, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x09, 0x18, 0x5C, 0x22, 0x28, 0x1C, 0x50, 0x54, 0x48, 0x20 , +0x42, 0x5C, 0x52, 0x06, 0x52, 0x0E, 0x42, 0x54, 0xAC, 0x20, 0x60, 0x43, 0x94, 0x49, 0x08, 0x18, 0x5C, 0x21, 0x09, 0x5C, 0x49, 0x1E, 0x02, 0x29, 0x16, 0xD9, 0x03, 0x39, 0x08, 0xD0, 0x00, 0x20, 0x30, 0x56, 0xAE, 0x46, 0xEA, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x80, 0x20, 0x30, 0x60, 0xDB, 0xE7, 0x08, 0x94, 0x80, 0x21, 0x31, 0x60, 0x48, 0x22, 0x13, 0x5C, 0x19, 0x43, 0x11, 0x54, 0xAE, 0x46, 0xE4, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x0A, 0xE0, 0x01, 0x20, 0xCE, 0xE7, 0x06, 0x98, 0x39, 0x1C, 0x04, 0xAA, 0xAE, 0x46, 0xE0, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x04, 0x1C, 0x08, 0x90, 0x06, 0x98, 0x38, 0x60, 0x08, 0x98, 0x78, 0x60, 0x00, 0x28, 0x15, 0xD0, 0xAC, 0x20, 0x60, 0x43, 0x7C, 0x49, 0x09, 0x18, 0x48, 0x88, 0x02, 0x04, 0x02, 0x20, 0x10, 0x43, 0xB8, 0x60, 0x48, 0x68, 0x02, 0x0E, 0x01, 0x02, 0x09, 0x0E, 0x09, 0x02, 0x11, 0x43, 0x02, 0x04, 0x12, 0x0E, 0xFF, 0xFF, 0x4C, 0x73, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00 , +0x12, 0x04, 0x0A, 0x43, 0x00, 0x06, 0x10, 0x43, 0xF8, 0x60, 0x07, 0x98, 0x0D, 0x49, 0x00, 0x22, 0x10, 0x23, 0xAE, 0x46, 0xCE, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x13, 0x48, 0x00, 0xE0, 0x16, 0x20, 0xCC, 0x49, 0x09, 0x18, 0x05, 0x98, 0x01, 0x62, 0x09, 0xB0, 0xF0, 0xBD, 0x5D, 0x0D, 0x1B, 0x00, 0x81, 0xE7, 0x02, 0x00, 0x09, 0xB4, 0x03, 0x00, 0x27, 0x1A, 0x02, 0x00, 0x2F, 0x7A, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0xCF, 0xF6, 0x00, 0x00, 0xD5, 0xF4, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x91, 0x19, 0x02, 0x00, 0x50, 0x65, 0x08, 0x00, 0x71, 0xC0, 0x02, 0x00, 0x50, 0x19, 0x1B, 0x00, 0x29, 0x16, 0x01, 0x00, 0x2A, 0x03, 0x00, 0x00, 0xF0, 0xB5, 0x8B, 0xB0, 0x07, 0x90, 0x05, 0x69, 0x47, 0x69, 0x0C, 0x20, 0x38, 0x1A, 0x08, 0x90, 0xB6, 0x49, 0x8D, 0x42, 0x16, 0xD1, 0x78, 0x68, 0x0F, 0x30, 0x00, 0x11, 0x00, 0x01, 0x78, 0x60, 0x38, 0x68, 0x0B, 0x28, 0x0E, 0xD8, 0x00, 0x23, 0x68, 0x46 , +0xFF, 0xFF, 0xE2, 0x73, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x03, 0x70, 0x08, 0x98, 0x05, 0x22, 0x01, 0x24, 0xA6, 0x46, 0xAE, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0xAE, 0x48, 0xFF, 0x30, 0x95, 0x30, 0x07, 0x99, 0x08, 0x62, 0xAC, 0x48, 0x85, 0x42, 0x23, 0xD1, 0xAC, 0x48, 0x02, 0x78, 0x6C, 0x46, 0x22, 0x72, 0x43, 0x78, 0x63, 0x72, 0x81, 0x78, 0xA1, 0x72, 0xC0, 0x78, 0xE0, 0x72, 0x00, 0x91, 0x01, 0x90, 0x03, 0x20, 0xA6, 0x49, 0x01, 0x39, 0x01, 0x26, 0xB6, 0x46, 0xF3, 0x4E, 0xFE, 0x44, 0x30, 0x47, 0x04, 0x20, 0x20, 0x70, 0x08, 0x98, 0x9F, 0x49, 0x00, 0x22, 0x02, 0xAB, 0x01, 0x24, 0xA6, 0x46, 0x9B, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x9A, 0x48, 0xFF, 0x30, 0x95, 0x30, 0x07, 0x99, 0x08, 0x62, 0xEB, 0x49, 0x8D, 0x42, 0x14, 0xD1, 0x02, 0x22, 0x68, 0x46, 0x02, 0x70, 0x3A, 0x68, 0xAC, 0x20, 0x42, 0x43, 0x30, 0x48, 0x68, 0x30, 0x83, 0x18, 0x08, 0x98, 0x00, 0x22, 0x01, 0x24, 0xA6, 0x46, 0x8F, 0x4C, 0xFE, 0x44 , +0x20, 0x47, 0x8E, 0x48, 0xFF, 0x30, 0x95, 0x30, 0x07, 0x99, 0xFF, 0xFF, 0x78, 0x74, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x08, 0x62, 0xEF, 0x48, 0x85, 0x42, 0x00, 0xD0, 0x04, 0xE1, 0x03, 0x20, 0x8C, 0x49, 0x01, 0x22, 0x96, 0x46, 0xEC, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x86, 0x48, 0xFF, 0x30, 0x95, 0x30, 0x09, 0x90, 0x38, 0x68, 0xEA, 0x4D, 0x00, 0x28, 0x00, 0xD1, 0xE2, 0xE0, 0x01, 0x24, 0xA6, 0x46, 0xE6, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x00, 0x28, 0x00, 0xD1, 0xD6, 0xE0, 0xE4, 0x48, 0x02, 0x68, 0x03, 0x20, 0x7F, 0x49, 0x01, 0x31, 0xA6, 0x46, 0xE2, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xDF, 0x48, 0x00, 0x68, 0x00, 0x28, 0x5A, 0xD1, 0xDF, 0x4D, 0x2E, 0x20, 0x41, 0x19, 0xB8, 0x68, 0x03, 0x30, 0x08, 0x70, 0x38, 0x7A, 0x48, 0x70, 0x2E, 0x1C, 0x30, 0x36, 0xB8, 0x68, 0x28, 0x18, 0x30, 0x30, 0xDA, 0x49, 0x0A, 0x68, 0x30, 0x3A, 0x31, 0x1C, 0xA6, 0x46, 0xD8, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x78, 0x68, 0x38, 0x18 , +0x01, 0x1D, 0xBA, 0x68, 0x30, 0x1C, 0xA6, 0x46, 0xD9, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xB8, 0x68, 0x41, 0x19, 0x97, 0x22, 0xFF, 0xFF, 0x0E, 0x75, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x09, 0x30, 0x50, 0x54, 0xB8, 0x68, 0x46, 0x19, 0x9E, 0x36, 0x30, 0x70, 0x01, 0x36, 0xB8, 0x68, 0x01, 0xE0, 0x14, 0x0D, 0x1B, 0x00, 0x30, 0x18, 0xCA, 0x49, 0x0A, 0x68, 0x9E, 0x3A, 0x31, 0x1C, 0xA6, 0x46, 0xC8, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x78, 0x68, 0x38, 0x18, 0x01, 0x1D, 0xBA, 0x68, 0x30, 0x1C, 0xA6, 0x46, 0xC9, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xB8, 0x68, 0x40, 0x00, 0xC0, 0x49, 0x09, 0x68, 0x08, 0x18, 0x28, 0x18, 0xC0, 0x49, 0x0A, 0x79, 0x02, 0x70, 0x4A, 0x79, 0x42, 0x70, 0x8A, 0x79, 0x82, 0x70, 0xC9, 0x79, 0xC1, 0x70, 0x04, 0x30, 0x0F, 0x21, 0x41, 0x1A, 0x0A, 0x78, 0xBB, 0x68, 0x9A, 0x18, 0x0A, 0x70, 0x40, 0x1B, 0x00, 0x04, 0x00, 0x0C, 0xB5, 0x49, 0x08, 0x60, 0xB1, 0x48, 0x04, 0x60, 0x02, 0x20, 0x01, 0x1C , +0x11, 0x22, 0xA6, 0x46, 0xB4, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x06, 0x1C, 0x63, 0xD4, 0x03, 0x20, 0xA6, 0x46, 0xB1, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x0A, 0x90, 0x00, 0x25, 0x01, 0x1C, 0xFF, 0xFF, 0xA4, 0x75, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x8D, 0x42, 0x50, 0xD0, 0x29, 0x1C, 0x2B, 0x22, 0xA6, 0x46, 0xAD, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x0C, 0x20, 0x0A, 0x99, 0x40, 0x18, 0xAC, 0x22, 0x72, 0x43, 0xAB, 0x49, 0x8F, 0x18, 0x78, 0x63, 0x29, 0x1C, 0x18, 0x22, 0xA6, 0x46, 0xA6, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x9F, 0x48, 0x02, 0x68, 0x79, 0x6B, 0x4A, 0x60, 0x0A, 0x98, 0xAC, 0x30, 0x08, 0x60, 0x08, 0x68, 0x9A, 0x49, 0xA6, 0x46, 0xA0, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x29, 0x1C, 0x03, 0xA8, 0x10, 0x22, 0xA6, 0x46, 0x9C, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xE0, 0x21, 0x68, 0x46, 0x01, 0x74, 0x45, 0x74, 0x85, 0x74, 0xFB, 0x21, 0xC1, 0x74, 0xEE, 0x49, 0xC1, 0x81, 0x02, 0x21, 0x81, 0x81, 0x79, 0x6B, 0xCA, 0x68 , +0x01, 0x20, 0xC0, 0x03, 0x10, 0x43, 0xC8, 0x60, 0x48, 0x68, 0x00, 0x90, 0x2A, 0x1C, 0x30, 0x1C, 0x0A, 0x9D, 0x29, 0x1C, 0x03, 0xAB, 0xA6, 0x46, 0xE6, 0x4F, 0xFE, 0x44, 0x38, 0x47, 0x07, 0x1C, 0x30, 0x06, 0x00, 0x16, 0xA6, 0x46, 0xEF, 0x49, 0xFF, 0xFF, 0x3A, 0x76, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xFE, 0x44, 0x08, 0x47, 0x28, 0x1C, 0xA6, 0x46, 0xEE, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x11, 0xE0, 0x30, 0x06, 0x00, 0x16, 0xA6, 0x46, 0xE9, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x01, 0x20, 0xC7, 0x43, 0x08, 0xE0, 0x07, 0x1C, 0x06, 0xE0, 0x00, 0x20, 0x00, 0x21, 0xCF, 0x43, 0x01, 0xE0, 0x00, 0x20, 0x07, 0x1C, 0x28, 0x60, 0x00, 0x23, 0x68, 0x46, 0x03, 0x70, 0x3A, 0x06, 0x12, 0x0E, 0x08, 0x98, 0x6F, 0x49, 0x01, 0x24, 0xA6, 0x46, 0x09, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x07, 0x98, 0x09, 0x99, 0x01, 0x62, 0x0B, 0xB0, 0xF0, 0xBD, 0xC1, 0x18, 0x01, 0x00, 0xF1, 0x1B, 0x01, 0x00, 0xF3, 0x1C, 0x02, 0x00, 0x7B, 0xC0 , +0x02, 0x00, 0x91, 0xF0, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0xA3, 0xC0, 0x02, 0x00, 0xA9, 0xE9, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0xE4, 0x62, 0x08, 0x00, 0xAC, 0x05, 0x00, 0x00, 0xFE, 0xB5, 0x07, 0x1C, 0x7D, 0x69, 0xBE, 0x69, 0x0C, 0x20, 0x30, 0x1A, 0x01, 0x90, 0xDF, 0x4C, 0x0A, 0x2D, 0x13, 0xD1, 0xFF, 0xFF, 0xD0, 0x76, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x30, 0x68, 0xDB, 0x49, 0x08, 0x60, 0x01, 0x20, 0x86, 0x46, 0xDA, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x0A, 0x20, 0x00, 0x21, 0x01, 0x9A, 0x01, 0x23, 0x9E, 0x46, 0xE6, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xF5, 0x20, 0x80, 0x00, 0x00, 0x19, 0x38, 0x62, 0x03, 0x2D, 0x79, 0xD1, 0xF5, 0x20, 0x80, 0x00, 0x00, 0x19, 0x02, 0x90, 0x70, 0x68, 0x00, 0x28, 0x0C, 0xD1, 0x00, 0x21, 0xCF, 0x48, 0x01, 0x60, 0xCF, 0x48, 0x00, 0x68, 0x00, 0x28, 0x61, 0xD0, 0x01, 0x21, 0x8E, 0x46, 0xCD, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x5B, 0xE0, 0xCC, 0x48, 0xB1, 0x68, 0x01, 0x60 , +0xF1, 0x68, 0x41, 0x60, 0x31, 0x69, 0x81, 0x60, 0x71, 0x69, 0xC1, 0x60, 0xB1, 0x69, 0xC1, 0x63, 0xF1, 0x69, 0x01, 0x64, 0x31, 0x6A, 0xC1, 0x64, 0x01, 0x24, 0xA6, 0x46, 0xC5, 0x48, 0xFE, 0x44, 0x00, 0x47, 0xA6, 0x46, 0xC4, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x70, 0x68, 0x7D, 0x25, 0xED, 0x00, 0xA8, 0x42, 0x21, 0xD8, 0x01, 0x28, 0x18, 0xD0, 0x02, 0x28, 0x05, 0xD0, 0xFF, 0xFF, 0x66, 0x77, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x28, 0x1C, 0xA6, 0x46, 0xBE, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x1C, 0xE0, 0xB9, 0x48, 0x00, 0x23, 0x19, 0x1C, 0x59, 0x43, 0x3E, 0x22, 0x4A, 0x43, 0x82, 0x83, 0x02, 0x30, 0x01, 0x33, 0x10, 0x2B, 0xF6, 0xDB, 0xA6, 0x46, 0xB4, 0x48, 0xFE, 0x44, 0x00, 0x47, 0xB5, 0x48, 0x0D, 0xE0, 0xB5, 0x4D, 0x28, 0x1C, 0xA6, 0x46, 0xB2, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x04, 0xE0, 0xA6, 0x46, 0xAF, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x75, 0x68, 0xAE, 0x48, 0x05, 0x60, 0x05, 0x1C, 0xA7, 0x4E, 0x30, 0x68 , +0x00, 0x28, 0x06, 0xD1, 0xAD, 0x48, 0x00, 0x68, 0xA6, 0x46, 0xAC, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x30, 0x60, 0x00, 0x94, 0x2B, 0x68, 0xAA, 0x49, 0xAB, 0x4A, 0xA6, 0x46, 0xAB, 0x4D, 0xFE, 0x44, 0x28, 0x47, 0x9C, 0x48, 0x04, 0x60, 0x03, 0x20, 0x00, 0x21, 0x01, 0x9A, 0x01, 0x23, 0x9E, 0x46, 0xA7, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x02, 0x98, 0x38, 0x62, 0xFE, 0xBD, 0xC0, 0x46, 0x13, 0x7F, 0x03, 0x00, 0x12, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x77, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x30, 0xB5, 0x05, 0x1C, 0x00, 0x20, 0x01, 0x24, 0xA6, 0x46, 0xA0, 0x49, 0xFE, 0x44, 0x08, 0x47, 0xA6, 0x46, 0x9F, 0x49, 0xFE, 0x44, 0x08, 0x47, 0xA6, 0x46, 0x9E, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x7D, 0x21, 0xC9, 0x00, 0xA6, 0x46, 0x9E, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0x9B, 0x49, 0x08, 0x18, 0x99, 0x49, 0x08, 0x80, 0x9B, 0x48, 0x0A, 0x30, 0x28, 0x62, 0x30, 0xBD, 0x11, 0x10, 0x00, 0x00, 0xDD, 0x7E, 0x03, 0x00, 0xB9, 0x90 , +0x00, 0x00, 0x6C, 0x64, 0x08, 0x00, 0xE7, 0x7E, 0x03, 0x00, 0x74, 0x64, 0x08, 0x00, 0x70, 0x64, 0x08, 0x00, 0x6D, 0xC6, 0x03, 0x00, 0x08, 0x19, 0x1B, 0x00, 0x11, 0x18, 0x02, 0x00, 0xD1, 0x78, 0x02, 0x00, 0xC9, 0xBA, 0x03, 0x00, 0x09, 0xB4, 0x03, 0x00, 0x14, 0x0D, 0x1B, 0x00, 0xFE, 0xB5, 0x02, 0x90, 0x45, 0x69, 0x68, 0x46, 0x01, 0x21, 0x8E, 0x46, 0x89, 0x49, 0xFE, 0x44, 0x08, 0x47, 0x89, 0x48, 0x04, 0x1C, 0x68, 0x68, 0x01, 0x69, 0x4A, 0x78, 0x00, 0x27, 0x3E, 0x1C, 0x20, 0x88, 0xFF, 0xFF, 0x92, 0x78, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x40, 0x08, 0x22, 0xD3, 0x20, 0x1D, 0x89, 0x1C, 0x01, 0x23, 0x9E, 0x46, 0x83, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x00, 0x28, 0x07, 0xD1, 0x68, 0x68, 0x00, 0x69, 0x40, 0x78, 0x21, 0x88, 0x09, 0x04, 0x89, 0x16, 0x81, 0x42, 0x3D, 0xD0, 0x02, 0x20, 0x00, 0x5F, 0x00, 0x99, 0x08, 0x1A, 0x00, 0x04, 0x00, 0x14, 0x3C, 0x28, 0x03, 0xDD, 0x20, 0x88, 0x40, 0x10, 0x40, 0x00 , +0x20, 0x80, 0x78, 0x1C, 0x07, 0x06, 0x3F, 0x0E, 0x68, 0x68, 0x01, 0x69, 0x4A, 0x78, 0x2A, 0x34, 0x01, 0x36, 0x14, 0x2E, 0xD5, 0xDB, 0x00, 0x2A, 0x02, 0xD1, 0xAB, 0x20, 0x40, 0x00, 0x50, 0xE0, 0x00, 0x9B, 0x6D, 0x48, 0x14, 0x21, 0x00, 0x22, 0x04, 0x88, 0x64, 0x08, 0x03, 0xD3, 0x2A, 0x30, 0x01, 0x32, 0x01, 0x39, 0xF8, 0xD1, 0x12, 0x06, 0x12, 0x0E, 0x14, 0x2F, 0x16, 0xD1, 0x66, 0x48, 0x00, 0x88, 0x00, 0x06, 0x44, 0x16, 0x64, 0x49, 0x00, 0x22, 0x01, 0x20, 0x4E, 0x8D, 0x36, 0x06, 0x76, 0x16, 0xA6, 0x42, 0x02, 0xDD, 0x34, 0x1C, 0x02, 0x06, 0xFF, 0xFF, 0x28, 0x79, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0x12, 0x0E, 0x2A, 0x31, 0x01, 0x30, 0x14, 0x28, 0xF3, 0xDB, 0x02, 0xE0, 0x32, 0x06, 0x12, 0x0E, 0x00, 0x9B, 0x2A, 0x20, 0x42, 0x43, 0x5A, 0x48, 0x11, 0x18, 0x0C, 0x88, 0x01, 0x20, 0x20, 0x43, 0x00, 0x04, 0x00, 0x0C, 0x08, 0x80, 0xFE, 0x24, 0xA0, 0x43, 0x14, 0x24, 0x64, 0x57, 0x64, 0x06, 0x24, 0x0E , +0x04, 0x43, 0x52, 0x48, 0x14, 0x52, 0x14, 0x18, 0x63, 0x80, 0x08, 0x88, 0x80, 0x05, 0x82, 0x0D, 0x68, 0x68, 0x00, 0x69, 0x40, 0x78, 0x80, 0x02, 0x10, 0x43, 0x08, 0x80, 0x68, 0x68, 0x02, 0x69, 0x20, 0x1D, 0x91, 0x1C, 0x52, 0x78, 0x01, 0x23, 0x9E, 0x46, 0x4B, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x02, 0x98, 0x04, 0x61, 0xFE, 0x20, 0x47, 0x49, 0x09, 0x18, 0x02, 0x98, 0x01, 0x62, 0xFE, 0xBD, 0x82, 0x69, 0x41, 0x69, 0x03, 0x69, 0x02, 0x2B, 0x0A, 0xD1, 0x01, 0x2A, 0x01, 0xD1, 0x00, 0x29, 0x05, 0xD0, 0x02, 0x2A, 0x04, 0xD1, 0x00, 0x29, 0x02, 0xD1, 0x11, 0x21, 0x00, 0xE0, 0x06, 0x21, 0x41, 0x61, 0xF7, 0x46, 0xFF, 0xFF, 0xBE, 0x79, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xC0, 0x46, 0x14, 0xE9, 0x00, 0x00, 0xC9, 0x18, 0x02, 0x00, 0x30, 0xB5, 0x05, 0x1C, 0x3A, 0x48, 0x00, 0x78, 0x00, 0x28, 0x04, 0xD0, 0x01, 0x20, 0x86, 0x46, 0x38, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x01, 0x24, 0xA6, 0x46, 0x37, 0x48, 0xFE, 0x44 , +0x00, 0x47, 0xA6, 0x46, 0x36, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x35, 0x48, 0x0E, 0x30, 0x28, 0x62, 0x30, 0xBD, 0x49, 0x19, 0x01, 0x00, 0x2F, 0x7A, 0x02, 0x00, 0x18, 0xB5, 0x43, 0x69, 0x81, 0x69, 0x31, 0x48, 0x81, 0x29, 0x00, 0xD1, 0x0B, 0x38, 0x00, 0x21, 0x00, 0x91, 0x1A, 0x68, 0x9B, 0x68, 0x01, 0x24, 0xA6, 0x46, 0x2D, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x18, 0xBD, 0x18, 0xB5, 0x40, 0x69, 0x00, 0x21, 0x00, 0x91, 0x02, 0x68, 0x83, 0x68, 0x27, 0x48, 0x01, 0x30, 0x01, 0x24, 0xA6, 0x46, 0x26, 0x4C, 0xFE, 0x44, 0x20, 0x47, 0x18, 0xBD, 0xC0, 0x46, 0x30, 0x63, 0x08, 0x00, 0x19, 0x9E, 0x00, 0x00, 0xB9, 0xEC, 0x00, 0x00, 0x74, 0x3F, 0x08, 0x00, 0x80, 0x3F, 0x08, 0x00, 0xFF, 0xFF, 0x54, 0x7A, 0x08, 0x00, 0x96, 0x00, 0x00, 0x00, 0xB7, 0x5D, 0x03, 0x00, 0x00, 0x00, 0x1B, 0x00, 0xD3, 0x8E, 0x00, 0x00, 0xF7, 0xC6, 0x00, 0x00, 0xE5, 0x90, 0x00, 0x00, 0x68, 0x64, 0x08, 0x00, 0xC0, 0x27, 0x09, 0x00, 0xA0, 0x3B , +0x08, 0x00, 0x3D, 0x5D, 0x03, 0x00, 0x19, 0xC6, 0x00, 0x00, 0xE8, 0x3A, 0x08, 0x00, 0x81, 0x5D, 0x03, 0x00, 0xCF, 0xF6, 0x00, 0x00, 0x4B, 0x4F, 0x03, 0x00, 0x6B, 0xC0, 0x03, 0x00, 0x95, 0x1E, 0x01, 0x00, 0xDA, 0x40, 0x08, 0x00, 0xDC, 0x05, 0x00, 0x00, 0x55, 0xAA, 0x03, 0x00, 0x0D, 0x91, 0x00, 0x00, 0xD7, 0x56, 0x03, 0x00, 0x08, 0x51, 0x08, 0x00, 0x8F, 0xC6, 0x03, 0x00, 0x65, 0xB8, 0x00, 0x00, 0x09, 0xB4, 0x03, 0x00, 0x84, 0x17, 0x1B, 0x00, 0xB5, 0x86, 0x01, 0x00, 0x3D, 0x47, 0x02, 0x00, 0x73, 0x49, 0x02, 0x00, 0x5F, 0x90, 0x00, 0x00, 0x0E, 0x10, 0x00, 0x00, 0xF7, 0xF6, 0x00, 0x00, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x76, 0xFF, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x5A, 0xFF, 0xFF, 0xBD, 0xFF, 0xB5, 0xFF, 0xFF, 0xEA, 0x7A, 0x08, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x46, 0xFF, 0xF7, 0x99, 0xFF, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x83, 0xFF, 0xFF, 0xBD, 0xFF, 0xB5 , +0x68, 0x46, 0xFF, 0xF7, 0xB6, 0xFE, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x55, 0xFC, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x27, 0xFB, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0xDD, 0xFA, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x68, 0xFE, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0x3D, 0xFB, 0xFF, 0xBD, 0xFF, 0xB5, 0x68, 0x46, 0xFF, 0xF7, 0xBE, 0xFD, 0xFF, 0xBD, 0x78, 0x7B, 0x08, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xF8, 0xF0, 0x43, 0xFA, 0x00, 0xBD, 0x35, 0x66, 0x08, 0x00, 0x67, 0x66, 0x08, 0x00, 0x71, 0x65, 0x08, 0x00, 0x4D, 0x66, 0x08, 0x00, 0x25, 0x64, 0x08, 0x00, 0x81, 0x66, 0x08, 0x00, 0x8D, 0x66, 0x08, 0x00, 0x99, 0x66, 0x08, 0x00, 0x87, 0x67, 0x08, 0x00, 0xA7, 0x67, 0x08, 0x00, 0xD1, 0x67, 0x08, 0x00, 0x1B, 0x68, 0x08, 0x00, 0x57, 0x68, 0x08, 0x00, 0x2D, 0x69, 0x08, 0x00, 0xB1, 0x6B, 0x08, 0x00, 0xD5, 0x6B, 0x08, 0x00, 0xF9, 0x6B , +0x08, 0x00, 0x15, 0x6C, 0x08, 0x00, 0xA1, 0x68, 0x08, 0x00, 0x59, 0x6C, 0x08, 0x00, 0xA7, 0x6D, 0x08, 0x00, 0xFF, 0x6D, 0x08, 0x00, 0x29, 0x6E, 0x08, 0x00, 0xF9, 0x6E, 0x08, 0x00, 0xD9, 0x6C, 0x08, 0x00, 0xA5, 0x6E, 0x08, 0x00, 0xCD, 0x6D, 0x08, 0x00, 0x81, 0x6F, 0x08, 0x00, 0x1D, 0x70, 0x08, 0x00, 0x31, 0x64, 0x08, 0x00, 0x39, 0x70, 0x08, 0x00, 0x3F, 0x70, 0x08, 0x00, 0x04, 0xF3, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x00, 0xB2, 0x4E, 0x01, 0x00, 0x5A, 0xC1, 0x00, 0x00, 0x96, 0x1A, 0x01, 0x00, 0x22, 0x0B, 0x02, 0x00, 0x60, 0xD0, 0x01, 0x00, 0x06, 0x1A, 0x00, 0x00, 0xB8, 0xC6, 0x01, 0x00, 0xD8, 0x42, 0x03, 0x00, 0x16, 0x42, 0x03, 0x00, 0xEE, 0xDB, 0x00, 0x00, 0x62, 0xDC, 0x00, 0x00, 0xC8, 0xE1, 0x00, 0x00, 0x8A, 0x17, 0x02, 0x00, 0x38, 0xBE, 0x00, 0x00, 0x26, 0xC6, 0x00, 0x00, 0x56, 0xC2, 0x00, 0x00, 0x62, 0x12, 0x03, 0x00, 0xE4, 0xF4, 0x01, 0x00, 0x3A, 0xEC, 0x00, 0x00, 0x5E, 0x92, 0x00, 0x00 , +0xFE, 0xE8, 0x02, 0x00, 0x18, 0x7F, 0x00, 0x00, 0x64, 0xEC, 0x01, 0x00, 0xFE, 0x44, 0x03, 0x00, 0x1C, 0x94, 0x00, 0x00, 0xA8, 0x66, 0x03, 0x00, 0x74, 0xE9, 0x02, 0x00, 0x68, 0x1E, 0x01, 0x00, 0xBC, 0xDA, 0x00, 0x00, 0xEA, 0xE1, 0x00, 0x00, 0x24, 0xE9, 0x01, 0x00, 0x70, 0x79, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x1C, 0xF0, 0xB5, 0x88, 0xB0, 0xCA, 0x4C, 0x03, 0x20, 0x22, 0x78, 0x63, 0x78, 0xCA, 0x4E, 0x31, 0x1C, 0x01, 0x39, 0x01, 0x25, 0xAE, 0x46, 0xC7, 0x4F, 0xFE, 0x44, 0x38, 0x47, 0xA2, 0x78, 0xE3, 0x78, 0x03, 0x20, 0x31, 0x1C, 0xAE, 0x46, 0xC3, 0x4F, 0xFE, 0x44, 0x38, 0x47, 0x03, 0x20, 0x31, 0x1C, 0x01, 0x31, 0xAE, 0x46, 0xC1, 0x4A, 0xFE, 0x44, 0x10, 0x47, 0xC1, 0x48, 0x21, 0x78, 0x01, 0x70, 0x61, 0x78, 0x41, 0x70, 0xE1, 0x78, 0xC1, 0x70, 0xA1, 0x78, 0x81, 0x70, 0xBF, 0x48, 0x04, 0x1C, 0x33, 0x3C, 0x20, 0x1C, 0x00, 0x21, 0xDC, 0x22, 0xAE, 0x46 , +0xBA, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x84, 0x20, 0xA0, 0x70, 0x05, 0x27, 0xE7, 0x71, 0x0C, 0x26, 0x26, 0x73, 0x0D, 0x20, 0x00, 0x19, 0x98, 0xA1, 0x32, 0x1C, 0xAE, 0x46, 0xB4, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x04, 0x20, 0x60, 0x76, 0x1A, 0x20, 0x00, 0x19, 0x97, 0xA1, 0x06, 0x91, 0x04, 0x22, 0xAE, 0x46, 0xAE, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xFF, 0xFF, 0x96, 0x00, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0xA7, 0x77, 0x1F, 0x34, 0x95, 0xA1, 0x07, 0x91, 0x20, 0x1C, 0x3A, 0x1C, 0xAE, 0x46, 0xA9, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xE6, 0x71, 0x28, 0x1C, 0x60, 0x72, 0x11, 0x20, 0x20, 0x73, 0x94, 0x20, 0x60, 0x73, 0xC0, 0x25, 0x65, 0x74, 0xA6, 0x74, 0x09, 0x22, 0xE2, 0x74, 0xA3, 0x4C, 0x20, 0x1C, 0x8C, 0xA1, 0x01, 0x23, 0x9E, 0x46, 0x9F, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x07, 0x22, 0x62, 0x72, 0x9E, 0x4C, 0x0A, 0x34, 0x20, 0x1C, 0x89, 0xA1, 0x01, 0x23, 0x9E, 0x46, 0x9A, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x04, 0x20 , +0xE0, 0x71, 0x98, 0x4C, 0x12, 0x34, 0x20, 0x1C, 0x06, 0x99, 0x04, 0x22, 0x01, 0x23, 0x9E, 0x46, 0x94, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x27, 0x71, 0x93, 0x4C, 0x17, 0x34, 0x20, 0x1C, 0x07, 0x99, 0x3A, 0x1C, 0x01, 0x23, 0x9E, 0x46, 0x8E, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0xE6, 0x71, 0x01, 0x20, 0x60, 0x72, 0x11, 0x20, 0x20, 0x73, 0x94, 0x20, 0x60, 0x73, 0x02, 0x20, 0xE0, 0x73, 0x25, 0x74, 0x66, 0x74, 0xFF, 0xFF, 0x2C, 0x01, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0xA5, 0x74, 0x2F, 0x27, 0xE7, 0x74, 0x10, 0x20, 0x60, 0x75, 0x80, 0x26, 0xA6, 0x75, 0x01, 0x20, 0xE0, 0x75, 0x11, 0x20, 0xA0, 0x76, 0x94, 0x20, 0xE0, 0x76, 0x24, 0x20, 0x60, 0x77, 0x0A, 0x22, 0xA2, 0x77, 0x80, 0x4C, 0x36, 0x34, 0x20, 0x1C, 0x6D, 0xA1, 0x01, 0x23, 0x9E, 0x46, 0x7C, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x18, 0x22, 0xA2, 0x72, 0x7A, 0x4C, 0x41, 0x34, 0x20, 0x1C, 0x6B, 0xA1, 0x01, 0x23, 0x9E, 0x46, 0x76, 0x4B, 0xFE, 0x44, 0x18, 0x47 , +0x25, 0x76, 0x67, 0x76, 0x21, 0x20, 0xE0, 0x76, 0x26, 0x77, 0x01, 0x20, 0x60, 0x77, 0x72, 0x48, 0x61, 0x30, 0x11, 0x21, 0x01, 0x70, 0x94, 0x21, 0x41, 0x70, 0x04, 0x21, 0x01, 0x72, 0xD2, 0x21, 0x41, 0x72, 0xC5, 0x72, 0x1E, 0x21, 0x01, 0x73, 0x45, 0x73, 0x9E, 0x21, 0x81, 0x73, 0x01, 0x21, 0x01, 0x74, 0x46, 0x74, 0x81, 0x74, 0x11, 0x21, 0x41, 0x75, 0x94, 0x21, 0x81, 0x75, 0x04, 0x21, 0x01, 0x76, 0xAD, 0x20, 0x66, 0x49, 0x08, 0x60, 0x00, 0x24, 0x0F, 0x25, 0xFF, 0xFF, 0xC2, 0x01, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0x29, 0x06, 0x09, 0x0E, 0x00, 0x20, 0x6A, 0x46, 0x01, 0x23, 0x9E, 0x46, 0x62, 0x4B, 0xFE, 0x44, 0x18, 0x47, 0x6B, 0x46, 0x18, 0x88, 0x40, 0x08, 0x0E, 0xD3, 0xA0, 0x00, 0x0F, 0x21, 0xCA, 0x43, 0x69, 0x46, 0x0E, 0x88, 0x16, 0x40, 0x01, 0xAF, 0x3E, 0x52, 0x49, 0x88, 0x11, 0x40, 0x68, 0x44, 0xC1, 0x80, 0x60, 0x1C, 0x04, 0x04, 0x24, 0x0C, 0x01, 0x3D, 0x0B, 0x2D, 0xE0, 0xDA, 0x60, 0x1E , +0x00, 0x04, 0x00, 0x0C, 0x1D, 0xD0, 0x86, 0x46, 0x01, 0x1C, 0x01, 0xAD, 0x01, 0x22, 0xAE, 0x88, 0x90, 0x00, 0xC7, 0x5A, 0xB7, 0x42, 0x0A, 0xDA, 0xBC, 0x46, 0x07, 0x1C, 0x6F, 0x44, 0x7F, 0x88, 0x68, 0x44, 0x06, 0x80, 0xEE, 0x88, 0x46, 0x80, 0x60, 0x46, 0xA8, 0x80, 0xEF, 0x80, 0x04, 0x35, 0x50, 0x1C, 0x02, 0x04, 0x12, 0x0C, 0x01, 0x39, 0xE9, 0xD1, 0x70, 0x46, 0x01, 0x38, 0x86, 0x46, 0xE2, 0xD1, 0x99, 0x88, 0x68, 0x46, 0xC0, 0x88, 0x40, 0x18, 0x00, 0x04, 0x00, 0x0C, 0x42, 0x4B, 0x18, 0x80, 0x42, 0x49, 0x08, 0x1A, 0xFF, 0xFF, 0x58, 0x02, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0x58, 0x80, 0x02, 0x2C, 0x1E, 0xDB, 0x65, 0x1E, 0x01, 0xAA, 0x01, 0x20, 0x01, 0x1C, 0x8C, 0x00, 0x6B, 0x46, 0xE6, 0x5A, 0x93, 0x88, 0xD4, 0x88, 0xE7, 0x18, 0xB7, 0x42, 0x0C, 0xDA, 0x06, 0x24, 0x44, 0x43, 0x38, 0x4B, 0x1B, 0x19, 0x1F, 0x80, 0x1C, 0x88, 0x34, 0x1B, 0x5C, 0x80, 0x01, 0x24, 0x1C, 0x71, 0x40, 0x1C, 0x00, 0x04 , +0x00, 0x0C, 0x04, 0x32, 0x49, 0x1C, 0x09, 0x06, 0x09, 0x0E, 0x01, 0x3D, 0xE4, 0xD1, 0x00, 0x24, 0x31, 0x48, 0x04, 0x70, 0x31, 0x48, 0x04, 0x70, 0x31, 0x48, 0x04, 0x70, 0x31, 0x48, 0x04, 0x70, 0x01, 0x20, 0x86, 0x46, 0x30, 0x48, 0xFE, 0x44, 0x00, 0x47, 0x2F, 0x49, 0x22, 0x1C, 0x08, 0x68, 0x00, 0x28, 0x02, 0xD0, 0x01, 0x20, 0x90, 0x40, 0x04, 0x43, 0x04, 0x31, 0x01, 0x32, 0x20, 0x2A, 0xF5, 0xD3, 0x2A, 0x48, 0x04, 0x60, 0x08, 0xB0, 0xF0, 0xBD, 0x5F, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2D, 0x69, 0x6E, 0x66, 0x6F, 0x00, 0xC0, 0x46, 0xC0, 0x5F, 0x75, 0x64, 0x70, 0x00, 0xC0, 0xFF, 0xFF, 0xEE, 0x02, 0x18, 0x00, 0x96, 0x00, 0x00, 0x00, 0x46, 0xC0, 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x00, 0xC0, 0x46, 0x5F, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x00, 0xC0, 0x46, 0x5F, 0x64, 0x6E, 0x73, 0x2D, 0x73, 0x64, 0x00, 0x64, 0x65, 0x76, 0x3D, 0x43, 0x43, 0x33, 0x30, 0x30, 0x30, 0x00, 0xC0, 0x76, 0x65 , +0x6E, 0x64, 0x6F, 0x72, 0x3D, 0x54, 0x65, 0x78, 0x61, 0x73, 0x2D, 0x49, 0x6E, 0x73, 0x74, 0x72, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x00, 0xC0, 0x46, 0xC0, 0x00, 0x00, 0x18, 0x00, 0xF3, 0x7E, 0x03, 0x00, 0xC6, 0x05, 0x00, 0x00, 0xDD, 0x7E, 0x03, 0x00, 0xE4, 0x62, 0x08, 0x00, 0xC9, 0xBA, 0x03, 0x00, 0x09, 0xB4, 0x03, 0x00, 0xA7, 0x64, 0x08, 0x00, 0x70, 0x64, 0x08, 0x00, 0xDD, 0x0A, 0x02, 0x00, 0x48, 0x32, 0x08, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xE8, 0x62, 0x08, 0x00, 0xE9, 0x62, 0x08, 0x00, 0xEA, 0x62, 0x08, 0x00, 0xEB, 0x62, 0x08, 0x00, 0x81, 0x03, 0x18, 0x00, 0x80, 0x7B, 0x08, 0x00, 0x84, 0xF3, 0x1A, 0x00, 0x0D, 0x49, 0x0E, 0x48, 0xFF, 0xFF, 0x84, 0x03, 0x18, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x88, 0x67, 0x0E, 0x48, 0x88, 0x64, 0x0E, 0x48, 0x48, 0x64, 0x0E, 0x48, 0xC8, 0x64, 0x0E, 0x48, 0x08, 0x65, 0x11, 0x48, 0x02, 0x1C, 0x04, 0x32, 0x0C, 0x4B, 0x13, 0x60, 0x0C, 0x4B, 0x93, 0x62, 0x0C, 0x4A , +0x8A, 0x66, 0x0D, 0x49, 0x01, 0x60, 0x0D, 0x48, 0x0E, 0x49, 0x01, 0x60, 0x0E, 0x49, 0x41, 0x60, 0xF7, 0x46, 0x1C, 0x21, 0x08, 0x00, 0x1B, 0x7B, 0x08, 0x00, 0x11, 0x7B, 0x08, 0x00, 0x07, 0x7B, 0x08, 0x00, 0x39, 0x7B, 0x08, 0x00, 0x2F, 0x7B, 0x08, 0x00, 0x25, 0x7B, 0x08, 0x00, 0xFD, 0x7A, 0x08, 0x00, 0xDF, 0x7A, 0x08, 0x00, 0x50, 0x23, 0x08, 0x00, 0xD5, 0x7A, 0x08, 0x00, 0x58, 0x26, 0x08, 0x00, 0xF3, 0x7A, 0x08, 0x00, 0xE9, 0x7A, 0x08, 0x00 }; + + +const unsigned char cRMdefaultParams[128] = { 0x03, 0x00, 0x01, 0x01, 0x14, 0x14, 0x00, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x23, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x23, 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x01, 0x77, 0x80, 0x1D, 0x1F, 0x22, 0x26, 0x28, 0x29, 0x1A, 0x1F, 0x22, 0x24, 0x26, 0x28, 0x16, 0x1D, 0x1E, 0x20, 0x24, 0x25, 0x1E, 0x2D, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00, 0x15, 0x15, 0x15, 0x11, 0x15, 0x15, 0x0E, 0x00}; + +// +//Service Pack version P1.13.7.15.15 - FW patches +// +const unsigned char fw_patch[5700] = { 0x00, 0x01, 0x00, 0x00, 0x3C, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x14, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x68, 0x46, 0x25, 0xF0, 0x95, 0xFB, 0xE0, 0x6B, 0xD0, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x38, 0xFB, 0x2C, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x0A, 0xFB, 0x04, 0x15, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB8, 0xF1, 0x90, 0x0F, 0xA4, 0x16, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x66, 0xE0, 0x04, 0xA8, 0x35, 0x1D, 0x21, 0xF0, 0x99, 0xFC, 0x68, 0x46, 0x23, 0xF0, 0x28, 0xFB, 0x9A, 0xF8, 0x00, 0x00, 0x01, 0x28, 0x07, 0xD1, 0x28, 0x46, 0x05, 0xF0, 0xC3, 0xFE, 0x01, 0x46, 0x01, 0xAA, 0x00, 0x20, 0x21, 0xF0, 0x50, 0xF9, 0x28, 0x46, 0x05, 0xF0, 0xBB, 0xFE, 0x01, 0xA9, 0x21, 0xF0, 0x2A, 0xFA, 0xE9, 0x79, 0x4F, 0xEA, 0xE0, 0x00, 0x40, 0xB2, 0x11, 0xB1, 0x00, 0xF1, 0x06, 0x00, 0x40, 0xB2, 0xA8, 0x71, 0x1F, 0x38, 0x40, 0x00, 0xE8, 0x71, 0x30, 0x46 , +0x01, 0xF0, 0x0D, 0xFF, 0x10, 0xF1, 0x00, 0x09, 0x4F, 0xF0, 0x00, 0x01, 0x09, 0xD0, 0x28, 0x68, 0x40, 0x0C, 0x09, 0xD3, 0xE8, 0x68, 0xC0, 0x0B, 0x03, 0xD2, 0x48, 0x46, 0xFF, 0xF7, 0xDD, 0xFE, 0x01, 0x21, 0x28, 0x68, 0x40, 0x0C, 0x0A, 0xD2, 0x38, 0x68, 0x40, 0x1C, 0x38, 0x60, 0x20, 0x68, 0x6F, 0xF3, 0x0F, 0x00, 0x20, 0x60, 0x22, 0x68, 0x38, 0x68, 0x10, 0x43, 0x20, 0x60, 0xE8, 0x68, 0xC0, 0x0B, 0x0F, 0xD3, 0xD8, 0xF8, 0x00, 0x00, 0x00, 0xF1, 0x01, 0x00, 0xC8, 0xF8, 0x00, 0x00, 0x20, 0x68, 0x6F, 0xF3, 0x1F, 0x40, 0x20, 0x60, 0xD8, 0xF8, 0x00, 0x20, 0x20, 0x68, 0x40, 0xEA, 0x02, 0x40, 0x20, 0x60, 0x49, 0xB9, 0xB9, 0xF1, 0x00, 0x0F, 0x03, 0xD1, 0x30, 0x46, 0x07, 0xF0, 0xBE, 0xF9, 0x02, 0xE0, 0x48, 0x46, 0x07, 0xF0, 0x06, 0xFA, 0x6C, 0x17, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x68, 0x46, 0x0E, 0xF0, 0x85, 0xFB, 0x00, 0x9E, 0x00, 0x2E, 0x96, 0xD1, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0xC0, 0x46 , +0x9C, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x23, 0xF0, 0x2A, 0xFE, 0x74, 0x47, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x21, 0x21, 0xF0, 0x41, 0xFA, 0x20, 0x68, 0x18, 0x4B, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0xF0, 0x1C, 0xF9, 0x0A, 0xE0, 0x20, 0x68, 0x00, 0x68, 0x0C, 0x21, 0x40, 0xF0, 0x20, 0x00, 0x21, 0xF0, 0x14, 0xF9, 0x10, 0x57, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0xA8, 0x20, 0xF0, 0x97, 0xF9, 0x01, 0x98, 0x5C, 0x57, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x20, 0xF0, 0x71, 0xF9, 0x03, 0x98, 0x00, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0xF0, 0x20, 0xF9, 0x1C, 0x58, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0xF0, 0x12, 0xF9, 0x54, 0x58, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0xA8, 0x20, 0xF0, 0xF5, 0xF8, 0x04, 0xAB, 0x04, 0x62, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x79, 0x1F, 0xF0, 0x1B, 0xFD, 0x69, 0xE0, 0x60, 0x93, 0x00, 0x00, 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, 0x48, 0xA6, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1B, 0xF0, 0x39, 0xFB, 0x28, 0x46, 0x90, 0xA8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1B, 0xF0, 0x69, 0xF9, 0x1E, 0x48, 0x34, 0xAD, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x68, 0xFF, 0x29, 0x98, 0xAD, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0xD4, 0x21, 0xD4, 0xB2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0xD0, 0x1A, 0xF0, 0x47, 0xFC, 0x20, 0x98, 0xAC, 0xC5, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0xF0 , +0xDB, 0xFA, 0x09, 0x49, 0x28, 0xC6, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0xF0, 0x9E, 0xFA, 0xDC, 0xD3, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xB5, 0x18, 0xF0, 0xAB, 0xFC, 0x00, 0xF0, 0x03, 0xF8, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xDF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x17, 0xF0, 0xA8, 0xFD, 0xCC, 0xEB, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x38, 0x78, 0x17, 0xF0, 0x77, 0xF8, 0x38, 0x78, 0x16, 0xF0, 0xF0, 0xFF, 0xA8, 0xF7, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0E, 0x49, 0x09, 0x68, 0x23, 0x22, 0x41, 0x61, 0xC8, 0xF7, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x31, 0x2E, 0x31, 0x39, 0x2E, 0x33, 0x31, 0x34, 0x5F, 0x4E, 0x65, 0x77, 0x5F, 0x43, 0x43, 0x41, 0x5F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x69, 0x74, 0x68, 0x6D, 0x00, 0xC0, 0x74, 0x56, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0xF9, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x16, 0xF0, 0x79, 0xF8 , +0x12, 0xE0, 0x38, 0xFA, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0xA8, 0x16, 0xF0, 0x03, 0xF8, 0x32, 0x20, 0x94, 0xFB, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0C, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x14, 0xF0, 0x05, 0xFF, 0x01, 0xF0, 0x10, 0x1B, 0x01, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1E, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0xF0, 0x46, 0xBF, 0x18, 0x30, 0x01, 0x00, 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, 0x90, 0x30, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0xF0, 0xD8, 0xFC, 0x9C, 0x31, 0x01, 0x00, 0x08, 0x00 , +0x00, 0x00, 0x68, 0x46, 0x12, 0xF0, 0x51, 0xFC, 0xFE, 0xF7, 0xF0, 0x35, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x68, 0x46, 0x12, 0xF0, 0x27, 0xFA, 0xFE, 0xF7, 0xF0, 0x3D, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0xA9, 0x11, 0xF0, 0x27, 0xFE, 0x20, 0x6F, 0xD0, 0x62, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0xB8, 0xFB, 0x80, 0x7E, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xDF, 0xF8, 0x58, 0x82, 0xE0, 0x7E, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0D, 0xF0, 0x6A, 0xFE, 0x0B, 0xF0, 0x9A, 0xF9, 0x03, 0x20, 0xA8, 0xF5, 0x88, 0x71, 0x08, 0x60, 0xF2, 0xF7, 0x16, 0xF9, 0x7A, 0x48, 0x6B, 0x49, 0x9C, 0x7F, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x70, 0x51, 0x4D, 0xC4, 0x7F, 0x01, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x40, 0x49, 0x00, 0xF1, 0x52, 0x00, 0x3A, 0x4A, 0xA8, 0x81, 0x28, 0x83, 0xE8, 0x83, 0xE8, 0x84, 0xA8, 0x85, 0x2A, 0x60, 0x39, 0x48, 0x41, 0xF2, 0x11, 0x12, 0x2A, 0x85, 0x18, 0x90, 0x19, 0x91 , +0x39, 0x49, 0x1A, 0x91, 0x39, 0x49, 0x1B, 0x91, 0x39, 0x49, 0x20, 0x46, 0xDF, 0xF8, 0xC4, 0x90, 0x1C, 0x91, 0x38, 0x49, 0xDF, 0xF8, 0xC0, 0xB0, 0x31, 0x4E, 0x1D, 0x91, 0x48, 0x80, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0xF0, 0x7C, 0xFA, 0xB4, 0x80, 0x01, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x12, 0x66, 0x09, 0x84, 0x6B, 0x00, 0x20, 0x94, 0x70, 0x00, 0x20, 0xB4, 0x70, 0x00, 0x20, 0xC4, 0x78, 0x00, 0x20, 0x50, 0x7A, 0x00, 0x20, 0xFE, 0xFF, 0x03, 0x00, 0xA4, 0x70, 0x00, 0x20, 0xB0, 0x70, 0x00, 0x20, 0xB8, 0x70, 0x00, 0x20, 0x60, 0x55, 0x30, 0x80, 0x3C, 0x5C, 0x00, 0x20, 0x04, 0x74, 0x00, 0x20, 0xB8, 0xE4, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x20, 0x78, 0x07, 0xF0, 0x01, 0xFC, 0x20, 0x78, 0x07, 0xF0, 0x7A, 0xFB, 0x04, 0x4D, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xAD, 0xF1, 0x8C, 0x0D, 0x04, 0x68, 0x0F, 0x30, 0x03, 0x94, 0xFE, 0xF7, 0xDB, 0xFA, 0x04, 0xF1, 0x14, 0x00 , +0x04, 0x90, 0x21, 0x7D, 0x00, 0x20, 0x21, 0xF0, 0x73, 0x01, 0x88, 0x29, 0x08, 0xBF, 0x01, 0x20, 0x05, 0x90, 0x03, 0x98, 0x00, 0x1D, 0x06, 0x90, 0x5D, 0x48, 0x00, 0x68, 0x01, 0x28, 0x40, 0xF0, 0xFA, 0x83, 0x5B, 0x4D, 0x5C, 0x48, 0xDF, 0xF8, 0x70, 0x91, 0x29, 0x68, 0xDF, 0xF8, 0x70, 0x81, 0xDF, 0xF8, 0x74, 0xA1, 0x88, 0x42, 0x21, 0xD1, 0x10, 0x22, 0x00, 0x21, 0x48, 0x46, 0x4F, 0x46, 0xFB, 0xF7, 0xB7, 0xFE, 0x10, 0x22, 0x00, 0x21, 0x40, 0x46, 0xFB, 0xF7, 0xB2, 0xFE, 0x54, 0x49, 0x08, 0x68, 0x40, 0xF4, 0x80, 0x10, 0x08, 0x60, 0x01, 0x20, 0x51, 0x46, 0x08, 0x60, 0x00, 0x21, 0x29, 0x60, 0x39, 0x78, 0x46, 0x46, 0x00, 0x91, 0x31, 0x78, 0x41, 0xF2, 0x11, 0x13, 0x04, 0x22, 0x01, 0x91, 0x07, 0x21, 0x02, 0x90, 0x03, 0x20, 0xF3, 0xF7, 0x41, 0xFC, 0x51, 0x46, 0x07, 0x91, 0x08, 0x68, 0x56, 0x49, 0xDF, 0xF8, 0x5C, 0xB1, 0x01, 0x28, 0x08, 0x91, 0x56, 0x49, 0xDF, 0xF8, 0x48, 0xA1, 0x09, 0x91, 0x55, 0x49 , +0x0A, 0x91, 0x44, 0x49, 0x0B, 0x91, 0x44, 0x49, 0x0C, 0x91, 0x44, 0x49, 0x0D, 0x91, 0x44, 0x49, 0x0E, 0x91, 0x44, 0x49, 0x0F, 0x91, 0x44, 0x49, 0x10, 0x91, 0x44, 0x49, 0xCC, 0x4D, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x11, 0x91, 0x44, 0x49, 0x12, 0x91, 0x44, 0x49, 0x13, 0x91, 0x44, 0x49, 0x14, 0x91, 0x44, 0x49, 0x15, 0x91, 0x44, 0x49, 0x16, 0x91, 0x9F, 0x49, 0x17, 0x91, 0x9F, 0x49, 0x18, 0x91, 0x9F, 0x49, 0x19, 0x91, 0x9F, 0x49, 0x1A, 0x91, 0x9F, 0x49, 0x1B, 0x91, 0x9F, 0x49, 0x1C, 0x91, 0x9F, 0x49, 0x1D, 0x91, 0x9F, 0x49, 0x1E, 0x91, 0x9F, 0x49, 0x1F, 0x91, 0x40, 0xF0, 0x00, 0x81, 0x04, 0x98, 0x40, 0x78, 0x00, 0xF0, 0x03, 0x01, 0x01, 0x29, 0x40, 0xF0, 0xF9, 0x80, 0x04, 0x99, 0x09, 0x78, 0x01, 0xF0, 0x0C, 0x01, 0x08, 0x29, 0x40, 0xF0, 0xF2, 0x80, 0x06, 0x99, 0x09, 0x88, 0xA1, 0xF1, 0x3C, 0x01, 0x0E, 0xB2, 0x05, 0x99, 0x11, 0xB1, 0xA6, 0xF1, 0x02, 0x06, 0x36, 0xB2, 0xC0, 0x09, 0x4F, 0xF0 , +0x00, 0x07, 0x15, 0xD3, 0x08, 0x3E, 0x36, 0xB2, 0x03, 0x2E, 0x10, 0xD0, 0x17, 0x2E, 0x0E, 0xD0, 0x08, 0x3E, 0x36, 0xB2, 0x03, 0x2E, 0x08, 0xD0, 0x17, 0x2E, 0x06, 0xD0, 0x36, 0x1F, 0x36, 0xB2, 0x03, 0x2E, 0x14, 0xBF, 0x17, 0x2E, 0x02, 0x27, 0x02, 0xE0, 0x03, 0x27, 0x00, 0xE0, 0x01, 0x27, 0x03, 0x2E, 0x18, 0xBF, 0x17, 0x2E, 0x04, 0x9A, 0x40, 0xF0, 0xC8, 0x80, 0x0A, 0x32, 0x12, 0xF8, 0x01, 0x1B, 0x05, 0x24, 0x12, 0xF8, 0x01, 0x3B, 0x4B, 0x40, 0x64, 0x1E, 0xD9, 0xB2, 0xF9, 0xD1, 0x81, 0xEA, 0x21, 0x11, 0x03, 0x2E, 0x94, 0x4E, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x0F, 0x01, 0x48, 0x46, 0x35, 0xD0, 0x43, 0x46, 0xCA, 0x5C, 0x52, 0x1C, 0xCA, 0x54, 0x0C, 0x18, 0x33, 0xE0, 0x50, 0x57, 0x02, 0x00, 0x04, 0x74, 0x00, 0x20, 0x34, 0x12, 0x66, 0x09, 0x60, 0x57, 0x02, 0x00, 0x70, 0x57, 0x02, 0x00, 0xC8, 0x48, 0x30, 0x80, 0x4C, 0x57, 0x02, 0x00, 0x88, 0x57, 0x02, 0x00, 0x80, 0x57, 0x02, 0x00 , +0x18, 0x58, 0x02, 0x00, 0x20, 0x58, 0x02, 0x00, 0x28, 0x58, 0x02, 0x00, 0x30, 0x58, 0x02, 0x00, 0x38, 0x58, 0x02, 0x00, 0x40, 0x58, 0x02, 0x00, 0xE4, 0x58, 0x02, 0x00, 0xE2, 0x58, 0x02, 0x00, 0x14, 0x58, 0x02, 0x00, 0xEF, 0x58, 0x02, 0x00, 0xE0, 0x58, 0x02, 0x00, 0xEE, 0x58, 0x02, 0x00, 0x5C, 0x57, 0x02, 0x00, 0xE6, 0x58, 0x02, 0x00, 0xE8, 0x58, 0x02, 0x00, 0x0C, 0x18, 0x20, 0x78, 0x40, 0x1C, 0x20, 0x70, 0x20, 0x78, 0x43, 0x46, 0x03, 0xEB, 0x01, 0x08, 0x0A, 0x28, 0x76, 0xDB, 0x98, 0xF8, 0x00, 0x00, 0x0A, 0x28, 0x72, 0xDB, 0x94, 0x48, 0x00, 0x25, 0x01, 0x60, 0x04, 0x98, 0x00, 0xF1, 0x0A, 0x09, 0x40, 0x78, 0x41, 0x08, 0x24, 0xBF, 0x04, 0x99, 0x09, 0x1D, 0x04, 0xD2, 0x80, 0x08, 0x2E, 0xBF, 0x49, 0x46, 0x04, 0x99, 0x10, 0x31, 0x0B, 0x98, 0x06, 0x22, 0xFA, 0xF7, 0xB9, 0xFC, 0x0C, 0x98, 0x06, 0x22, 0x49, 0x46, 0xFA, 0xF7, 0xB4, 0xFC, 0x9B, 0x48, 0x9A, 0x49, 0x5C, 0x4F, 0x02, 0x00, 0xC8, 0x00 , +0x00, 0x00, 0x00, 0x78, 0x08, 0x22, 0x08, 0x60, 0x58, 0x46, 0x07, 0x60, 0x0D, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0xAF, 0xFD, 0x08, 0x22, 0x0E, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0xAA, 0xFD, 0x08, 0x22, 0x0F, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0xA5, 0xFD, 0x08, 0x22, 0x10, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0xA0, 0xFD, 0x08, 0x22, 0x11, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0x9B, 0xFD, 0x08, 0x22, 0x12, 0x98, 0x29, 0x46, 0xFB, 0xF7, 0x96, 0xFD, 0x07, 0x99, 0x02, 0x20, 0x08, 0x60, 0x13, 0x99, 0x28, 0x46, 0x08, 0x80, 0x08, 0x99, 0x08, 0x70, 0x14, 0x99, 0x08, 0x70, 0x15, 0x99, 0x08, 0x60, 0x16, 0x99, 0x08, 0x70, 0x17, 0x99, 0x08, 0x60, 0x18, 0x99, 0x08, 0x60, 0x19, 0x99, 0x08, 0x60, 0x09, 0x99, 0x08, 0x80, 0x0A, 0x99, 0x08, 0x80, 0x1A, 0x99, 0x08, 0x80, 0x7D, 0x49, 0x0D, 0x60, 0x1B, 0x99, 0x08, 0x70, 0x1C, 0x99, 0x08, 0x70, 0x1D, 0x99, 0x08, 0x70, 0x1E, 0x99, 0x08, 0x80, 0x1F, 0x99, 0x08, 0x80, 0x51, 0x46, 0x08, 0x80 , +0x20, 0x78, 0x00, 0x96, 0x04, 0x22, 0x01, 0x90, 0x98, 0xF8, 0x00, 0x00, 0x41, 0xF2, 0x14, 0x13, 0x07, 0x21, 0x02, 0x90, 0x03, 0x20, 0xF3, 0xF7, 0x07, 0xFB, 0x07, 0x98, 0xA2, 0x49, 0x00, 0x68, 0x20, 0x91, 0xA2, 0x49, 0x05, 0x28, 0x21, 0x91, 0x9E, 0x49, 0x22, 0x91, 0x40, 0xF0, 0x37, 0x82, 0x04, 0x98, 0x40, 0x78, 0x24, 0x50, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x41, 0x08, 0x24, 0xBF, 0x04, 0x99, 0x09, 0x1D, 0x05, 0xD2, 0x80, 0x08, 0x27, 0xBF, 0x04, 0x99, 0x0A, 0x31, 0x04, 0x99, 0x10, 0x31, 0x0B, 0x98, 0xF8, 0xF7, 0x2D, 0xFC, 0x01, 0x28, 0x04, 0x98, 0x40, 0xF0, 0x23, 0x82, 0x40, 0x78, 0x00, 0xF0, 0x03, 0x00, 0x03, 0x28, 0x18, 0xD0, 0x02, 0x28, 0x07, 0xBF, 0x04, 0x99, 0x10, 0x31, 0x04, 0x99, 0x0A, 0x31, 0x13, 0xE0, 0x48, 0x58, 0x02, 0x00, 0x4C, 0x58, 0x02, 0x00, 0x50, 0x58, 0x02, 0x00, 0xF0, 0x58, 0x02, 0x00, 0xF2, 0x58, 0x02, 0x00, 0xF3, 0x58, 0x02, 0x00, 0xF4, 0x58, 0x02, 0x00, 0xEA, 0x58 , +0x02, 0x00, 0xEC, 0x58, 0x02, 0x00, 0x04, 0x99, 0x18, 0x31, 0x0C, 0x98, 0xF8, 0xF7, 0x06, 0xFC, 0x04, 0x99, 0x01, 0x28, 0x40, 0xF0, 0xFC, 0x81, 0x49, 0x78, 0x01, 0xF0, 0x03, 0x01, 0x01, 0x29, 0x40, 0xF0, 0xF6, 0x81, 0x59, 0x46, 0x09, 0x68, 0x04, 0x9A, 0x8E, 0x46, 0x51, 0x46, 0xD2, 0x8A, 0x0B, 0x88, 0x12, 0x11, 0x93, 0x42, 0x00, 0xF0, 0x37, 0x82, 0x0A, 0x80, 0x06, 0x99, 0x09, 0x88, 0x3C, 0x39, 0x0B, 0xB2, 0x71, 0x46, 0x49, 0x1E, 0x09, 0xD0, 0x49, 0x1E, 0x04, 0xD0, 0x49, 0x1E, 0x08, 0xD1, 0xA3, 0xF1, 0x10, 0x03, 0x04, 0xE0, 0xA3, 0xF1, 0x14, 0x03, 0x01, 0xE0, 0xA3, 0xF1, 0x08, 0x03, 0x1B, 0xB2, 0x05, 0x98, 0x10, 0xB1, 0xA3, 0xF1, 0x02, 0x03, 0x1B, 0xB2, 0xEC, 0x50, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0xF1, 0xCE, 0x81, 0x16, 0x98, 0x40, 0xF2, 0x77, 0x51, 0x99, 0x42, 0x0B, 0x90, 0x14, 0x98, 0x05, 0x90, 0x00, 0xF0, 0xA3, 0x81, 0x08, 0x46, 0x00, 0xF1, 0x3C, 0x00, 0x98, 0x42 , +0x05, 0x9A, 0x00, 0xF0, 0x9A, 0x81, 0xDF, 0xF8, 0x48, 0x82, 0x14, 0x78, 0x0B, 0x9A, 0xBB, 0x2C, 0x12, 0x78, 0x0C, 0x92, 0x63, 0xD1, 0xDD, 0xF8, 0x68, 0xC0, 0xBC, 0xF9, 0x00, 0x20, 0x91, 0x42, 0x18, 0xBF, 0x90, 0x42, 0x5B, 0xD1, 0x1C, 0x2B, 0x4F, 0xF0, 0x00, 0x00, 0xC0, 0xF2, 0x82, 0x81, 0x3D, 0x2B, 0x13, 0x9D, 0x80, 0xF2, 0x7E, 0x81, 0xA3, 0xF1, 0x1C, 0x01, 0x09, 0xB2, 0x29, 0x80, 0x1E, 0x9A, 0xDD, 0xF8, 0x30, 0x90, 0xB2, 0xF9, 0x00, 0x60, 0xB9, 0xF1, 0x01, 0x0F, 0x15, 0xD1, 0xDD, 0xF8, 0x24, 0x90, 0x03, 0x2E, 0x0D, 0xDA, 0xB9, 0xF9, 0x00, 0x70, 0xB9, 0x42, 0x07, 0xD0, 0x01, 0x26, 0x16, 0x80, 0x4A, 0x46, 0x0E, 0x46, 0x03, 0xE0, 0xC0, 0x46, 0x90, 0x57, 0x02, 0x00, 0x76, 0x1C, 0x16, 0x80, 0x1B, 0x9A, 0x16, 0x78, 0x1D, 0x9A, 0x16, 0x70, 0x0C, 0x9A, 0x1F, 0x9E, 0x02, 0x2A, 0x28, 0xD1, 0xB6, 0xF9, 0x00, 0x20, 0xBE, 0xF1, 0x00, 0x0F, 0x1A, 0xD0, 0x03, 0x2A, 0x35, 0x46, 0x0B, 0xDA, 0x0A, 0x9E , +0xB6, 0xF9, 0x00, 0x70, 0xB9, 0x42, 0x04, 0xD0, 0x01, 0x22, 0x2A, 0x80, 0x0A, 0x46, 0x35, 0x46, 0x00, 0xE0, 0xB4, 0x51, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x52, 0x1C, 0x2A, 0x80, 0x1C, 0x99, 0x0A, 0x78, 0x1D, 0x99, 0x0A, 0x70, 0x0F, 0xE0, 0xC0, 0x46, 0x58, 0x57, 0x02, 0x00, 0xA6, 0x64, 0x00, 0x20, 0x54, 0x57, 0x02, 0x00, 0x28, 0x80, 0x05, 0x99, 0x08, 0x70, 0x08, 0x9A, 0x11, 0x78, 0x41, 0xF0, 0x04, 0x01, 0x11, 0x70, 0x04, 0x46, 0x45, 0x46, 0xAC, 0xF8, 0x00, 0x00, 0x28, 0x70, 0xCC, 0x2C, 0x09, 0x9A, 0x40, 0xF0, 0x00, 0x81, 0xDD, 0xF8, 0x7C, 0xC0, 0x0A, 0x99, 0x1E, 0x9F, 0x45, 0x46, 0xB1, 0xF9, 0x00, 0x60, 0xB2, 0xF9, 0x00, 0x90, 0x28, 0x78, 0xCD, 0xF8, 0x50, 0xC0, 0x16, 0x91, 0x0A, 0x97, 0x13, 0x92, 0x09, 0x95, 0x0C, 0x99, 0x01, 0x29, 0x05, 0xD1, 0x05, 0x9A, 0xB0, 0xEB, 0x49, 0x0F, 0x01, 0xD1, 0x00, 0x21, 0x11, 0x70, 0x0C, 0x99, 0x02, 0x29, 0x05, 0xD1, 0x05, 0x9A, 0xB0, 0xEB, 0x46, 0x0F , +0x01, 0xD1, 0x00, 0x21, 0x11, 0x70, 0xB3, 0xF5, 0x14, 0x7F, 0x40, 0xF3, 0xBA, 0x80, 0x40, 0xF2, 0x51, 0x31, 0x99, 0x42, 0x08, 0x99, 0x40, 0xF3, 0xB4, 0x80, 0x09, 0x78, 0x06, 0x29, 0x00, 0xF0, 0xB0, 0x80, 0xA3, 0xF2, 0x51, 0x21, 0x0B, 0xB2, 0x4F, 0xEA, 0xE3, 0x01, 0x03, 0xEB, 0x11, 0x71, 0x4F, 0xEA, 0x21, 0x11, 0xCA, 0xB2, 0x4F, 0xEA, 0xE3, 0x01, 0x03, 0xEB, 0x11, 0x71, 0x15, 0x9D, 0x21, 0xF0, 0x0F, 0x01, 0xA3, 0xEB, 0x01, 0x03, 0x1D, 0x99, 0x2E, 0x68, 0x7C, 0x52, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x91, 0xF8, 0x00, 0xE0, 0x5F, 0xFA, 0x83, 0xF8, 0x60, 0xB1, 0x31, 0x18, 0x11, 0xF8, 0x01, 0x1C, 0x51, 0x40, 0xCB, 0xB2, 0x07, 0xE0, 0xC0, 0x46, 0x58, 0x58, 0x02, 0x00, 0x54, 0x58, 0x02, 0x00, 0xDC, 0x58, 0x02, 0x00, 0x13, 0x46, 0x19, 0x99, 0xDD, 0xF8, 0x6C, 0xA0, 0xDD, 0xF8, 0x70, 0xB0, 0xD1, 0xF8, 0x00, 0xC0, 0x00, 0xF0, 0x0F, 0x01, 0x99, 0x42, 0x22, 0xD0, 0x0A, 0x9B, 0x86, 0x45, 0x9A, 0xF8 , +0x00, 0x10, 0xB3, 0xF9, 0x00, 0x30, 0x9B, 0xF8, 0x00, 0x50, 0x15, 0xDD, 0x37, 0x5C, 0x44, 0x1C, 0x82, 0xEA, 0x07, 0x0C, 0x04, 0xF0, 0x0F, 0x07, 0x67, 0x45, 0x0B, 0xD0, 0xA6, 0x45, 0x06, 0x44, 0x0A, 0xDD, 0x76, 0x78, 0x72, 0x40, 0x86, 0x1C, 0x06, 0xF0, 0x0F, 0x06, 0x96, 0x42, 0x03, 0xD1, 0xC0, 0x1C, 0x4D, 0xE0, 0x80, 0x1C, 0x4B, 0xE0, 0x05, 0x9E, 0x00, 0x22, 0x32, 0x70, 0x4A, 0xE0, 0x00, 0xF0, 0x1F, 0x01, 0x01, 0x22, 0x8A, 0x40, 0x17, 0x99, 0xC4, 0x10, 0x0B, 0x68, 0x24, 0xF0, 0x03, 0x01, 0x5C, 0xF8, 0x01, 0x70, 0x3A, 0x42, 0x32, 0xD1, 0x5F, 0x58, 0x3A, 0x42, 0x06, 0x44, 0x1F, 0xD0, 0x18, 0x9B, 0x37, 0x78, 0x1B, 0x68, 0xB8, 0x45, 0x04, 0xD1, 0x58, 0x58, 0x02, 0x42, 0x19, 0xD0, 0x63, 0x46, 0x15, 0xE0, 0xA1, 0x10, 0x8C, 0x00, 0x19, 0x59, 0x91, 0x43, 0x19, 0x51, 0x00, 0x90, 0x30, 0x78, 0x01, 0x90, 0x44, 0x53, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x03, 0x20, 0x06, 0x21, 0x02, 0x46, 0x4D, 0xF6 , +0x80, 0x53, 0xF3, 0xF7, 0x63, 0xF9, 0x09, 0x99, 0x28, 0x68, 0x0E, 0x78, 0x36, 0x18, 0x06, 0xE0, 0xE3, 0x58, 0x02, 0x00, 0xA0, 0x10, 0x81, 0x00, 0x58, 0x58, 0x02, 0x43, 0x5A, 0x50, 0x86, 0xF8, 0x00, 0x80, 0x0B, 0x98, 0x00, 0x78, 0x0C, 0x90, 0x13, 0x98, 0xB0, 0xF9, 0x00, 0x90, 0x09, 0x98, 0x00, 0x78, 0x0A, 0x9A, 0x40, 0x1C, 0x9B, 0xF8, 0x00, 0x50, 0x9A, 0xF8, 0x00, 0x10, 0xB2, 0xF9, 0x00, 0x30, 0x09, 0x9A, 0xC0, 0xB2, 0x10, 0x70, 0x0C, 0x9A, 0x01, 0x2A, 0x03, 0xD1, 0x88, 0x42, 0xC8, 0xBF, 0x8A, 0xF8, 0x00, 0x00, 0x0C, 0x99, 0x02, 0x29, 0x07, 0xD1, 0xA8, 0x42, 0xC8, 0xBF, 0x8B, 0xF8, 0x00, 0x00, 0x02, 0xE0, 0x0A, 0x98, 0xB0, 0xF9, 0x00, 0x30, 0xB9, 0xF1, 0x00, 0x0F, 0x06, 0xDD, 0x03, 0x2B, 0x04, 0xD1, 0x11, 0x98, 0x01, 0x22, 0x49, 0x46, 0x00, 0xF0, 0x72, 0xFB, 0x16, 0x98, 0xB0, 0xF9, 0x00, 0x10, 0x14, 0x98, 0x00, 0x29, 0xB0, 0xF9, 0x00, 0x00, 0x05, 0xDD, 0x03, 0x28, 0x03, 0xD1, 0x12, 0x98 , +0x02, 0x22, 0x00, 0xF0, 0x64, 0xFB, 0x05, 0x98, 0x04, 0x78, 0x0B, 0x98, 0x00, 0x78, 0x0C, 0x90, 0x08, 0x98, 0xBB, 0x2C, 0x01, 0x78, 0x02, 0xD0, 0xAA, 0x2C, 0x2F, 0xD0, 0x31, 0xE0, 0x0C, 0x98, 0x01, 0x28, 0x0B, 0xD1, 0x0D, 0x98, 0x17, 0x9A, 0x10, 0x60, 0x0C, 0x54, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x0F, 0x98, 0x18, 0x9A, 0x10, 0x60, 0x19, 0x9A, 0x11, 0x98, 0x10, 0x60, 0x47, 0x4A, 0x15, 0x98, 0x02, 0x60, 0x0C, 0x98, 0x02, 0x28, 0x0B, 0xD1, 0x0E, 0x98, 0x17, 0x9A, 0x10, 0x60, 0x10, 0x98, 0x18, 0x9A, 0x10, 0x60, 0x19, 0x9A, 0x12, 0x98, 0x10, 0x60, 0x41, 0x4A, 0x15, 0x98, 0x02, 0x60, 0xCC, 0x20, 0x0F, 0xE0, 0x08, 0x99, 0x09, 0x78, 0x0C, 0xE0, 0x02, 0x20, 0x00, 0xE0, 0x01, 0x20, 0x0B, 0x99, 0x08, 0x70, 0x1A, 0x99, 0x0B, 0x80, 0x13, 0x99, 0x00, 0x20, 0x08, 0x80, 0x08, 0x98, 0x01, 0x78, 0xBB, 0x20, 0x05, 0x9A, 0x10, 0x70, 0x06, 0x29, 0x07, 0x99, 0x11, 0xD1, 0x06, 0x20, 0x08, 0x60, 0x20, 0x98 , +0x00, 0x25, 0x05, 0x70, 0x21, 0x98, 0x29, 0x46, 0x04, 0x22, 0xFB, 0xF7, 0x27, 0xFB, 0x01, 0x20, 0x00, 0xF0, 0x3A, 0xFA, 0x02, 0x20, 0x00, 0xF0, 0x37, 0xFA, 0x22, 0x98, 0x05, 0x60, 0x07, 0x98, 0x04, 0x99, 0x00, 0x68, 0x07, 0x28, 0x44, 0xD1, 0x09, 0x78, 0x03, 0x9C, 0x80, 0x29, 0x40, 0xD1, 0x38, 0x34, 0x21, 0x78, 0x64, 0x1C, 0x22, 0x46, 0x00, 0x29, 0x3A, 0xD1, 0x20, 0x98, 0x90, 0xF8, 0x00, 0xA0, 0x22, 0x98, 0x05, 0x90, 0xD0, 0xF8, 0x00, 0x90, 0x51, 0x46, 0x48, 0x46, 0xFD, 0xF7, 0x79, 0xF9, 0x5F, 0xFA, 0x80, 0xF8, 0x21, 0x9F, 0x15, 0x78, 0x51, 0x46, 0x48, 0x46, 0x17, 0xF8, 0x08, 0x30, 0xFD, 0xF7, 0xD4, 0x54, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x6F, 0xF9, 0x1E, 0x46, 0x1B, 0x1D, 0xC0, 0xB2, 0x38, 0x5C, 0x00, 0x1D, 0xA8, 0x42, 0x28, 0x46, 0x07, 0xDD, 0x80, 0x18, 0x82, 0x1C, 0x10, 0x78, 0x2D, 0x18, 0xAD, 0x1C, 0xAD, 0xB2, 0xAB, 0x42, 0xF7, 0xDC, 0x04, 0xF8, 0x01, 0x6B, 0x11, 0x49, 0x32, 0x46 , +0x20, 0x46, 0x01, 0xEB, 0x48, 0x11, 0xFA, 0xF7, 0xDC, 0xF9, 0xAD, 0x1B, 0xFF, 0x20, 0x34, 0x19, 0xAD, 0x1E, 0x04, 0xF8, 0x01, 0x0B, 0x25, 0x70, 0x05, 0x98, 0x01, 0x68, 0x49, 0x1C, 0x01, 0x60, 0x07, 0x98, 0x00, 0x68, 0x07, 0x28, 0x04, 0xD0, 0x06, 0x99, 0x08, 0x68, 0x20, 0xF4, 0x80, 0x30, 0x08, 0x60, 0x23, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xC0, 0x46, 0x94, 0x57, 0x02, 0x00, 0xD4, 0x57, 0x02, 0x00, 0x5C, 0x58, 0x02, 0x00, 0x6E, 0x48, 0x2D, 0xE9, 0xF0, 0x47, 0x6E, 0x4D, 0x82, 0x89, 0x4A, 0xF6, 0x55, 0x21, 0xAD, 0xF5, 0xFE, 0x7D, 0x91, 0x42, 0x4F, 0xF0, 0x00, 0x01, 0xAD, 0xF1, 0x38, 0x0D, 0x12, 0xD1, 0x29, 0x60, 0x68, 0x4A, 0x11, 0x70, 0x41, 0xF2, 0x10, 0x41, 0x81, 0x81, 0x4F, 0xF6, 0xFF, 0x70, 0x66, 0x49, 0x08, 0x60, 0x28, 0x68, 0x00, 0x90, 0x02, 0x22, 0x05, 0x21, 0x03, 0x20, 0x41, 0xF2, 0x34, 0x23, 0xF3, 0xF7, 0x48, 0xF8, 0x29, 0x68, 0x61, 0x4C, 0x01, 0x29, 0x20, 0x68, 0x40, 0xF0, 0xAF, 0x80 , +0x5F, 0x4D, 0x02, 0x28, 0x29, 0x68, 0x23, 0xD1, 0x9C, 0x55, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x5E, 0x48, 0x00, 0x68, 0x5F, 0x4A, 0x12, 0x5C, 0x00, 0x92, 0x01, 0x91, 0x5E, 0x49, 0x09, 0x68, 0x02, 0x91, 0x5B, 0x49, 0x0B, 0x5C, 0x03, 0x20, 0x07, 0x21, 0x04, 0x22, 0xF3, 0xF7, 0x2E, 0xF8, 0x5B, 0x49, 0x4A, 0x79, 0x59, 0x48, 0x00, 0x92, 0x02, 0x79, 0x01, 0x92, 0x40, 0x79, 0x04, 0x22, 0x02, 0x90, 0x03, 0x20, 0x0B, 0x79, 0x07, 0x21, 0xF3, 0xF7, 0x20, 0xF8, 0x03, 0x20, 0x20, 0x60, 0xEC, 0xF7, 0x1A, 0xFF, 0x20, 0x68, 0x29, 0x68, 0x04, 0x28, 0x15, 0xD1, 0x0D, 0x20, 0x8D, 0xF8, 0x10, 0x00, 0x00, 0x25, 0x8D, 0xF8, 0x14, 0x50, 0x8D, 0xF8, 0x15, 0x10, 0x28, 0x46, 0x63, 0x21, 0x00, 0xF0, 0xAA, 0xFB, 0x63, 0x21, 0x28, 0x46, 0x00, 0xF0, 0xFA, 0xFA, 0x03, 0xA9, 0x04, 0xA8, 0xE0, 0xF7, 0xCA, 0xFC, 0x05, 0x20, 0x20, 0x60, 0x46, 0x4D, 0x05, 0x28, 0x29, 0x68, 0x01, 0xF1, 0x01, 0x01, 0x29, 0x60, 0x1D, 0xD1 , +0x44, 0x4A, 0x8A, 0x42, 0x1A, 0xD1, 0x43, 0x48, 0x01, 0x68, 0x00, 0x91, 0x40, 0x68, 0x01, 0x90, 0x03, 0x20, 0x02, 0x46, 0x06, 0x21, 0x41, 0x4E, 0x33, 0x46, 0x22, 0x3B, 0xF2, 0xF7, 0xEB, 0xFF, 0x3E, 0x48, 0x01, 0x68, 0x00, 0x91, 0x40, 0x68, 0x33, 0x46, 0x06, 0x21, 0x01, 0x90, 0x03, 0x20, 0x02, 0x46, 0xF2, 0xF7, 0xE0, 0xFF, 0x00, 0x20, 0x28, 0x60, 0x20, 0x68, 0x06, 0x28, 0x47, 0xD1, 0x4F, 0xF0, 0x64, 0x56, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x07, 0x0A, 0xC4, 0xF8, 0x00, 0xA0, 0x03, 0x20, 0x48, 0xF2, 0x70, 0x53, 0x01, 0x22, 0x04, 0x21, 0xF2, 0xF7, 0xD0, 0xFF, 0xDF, 0xF8, 0xCC, 0x80, 0x31, 0x4F, 0x48, 0xF2, 0x70, 0x59, 0x01, 0x25, 0x49, 0xEA, 0x05, 0x03, 0x01, 0x22, 0x04, 0x21, 0x03, 0x20, 0xF2, 0xF7, 0xC3, 0xFF, 0x00, 0x24, 0x17, 0xF8, 0x02, 0x0F, 0x20, 0xE0, 0x69, 0x01, 0x04, 0xEB, 0x08, 0x02, 0x88, 0x18, 0xC6, 0x1C, 0x43, 0x78, 0x00, 0x93, 0x80, 0x78, 0x01, 0x90, 0x30, 0x78, 0x02, 0x90 , +0x53, 0x5C, 0x51, 0x46, 0x04, 0x22, 0x03, 0x20, 0xF2, 0xF7, 0xAE, 0xFF, 0x38, 0x78, 0x01, 0x1B, 0xB1, 0xF1, 0xFF, 0x3F, 0x08, 0xD1, 0xF0, 0x78, 0x00, 0x90, 0xB3, 0x78, 0x03, 0x20, 0x02, 0x22, 0x05, 0x21, 0xF2, 0xF7, 0xA1, 0xFF, 0x38, 0x78, 0x24, 0x1D, 0xE4, 0xB2, 0xA0, 0x42, 0xDC, 0xDC, 0xAD, 0x1C, 0xED, 0xB2, 0x04, 0x2D, 0xCD, 0xDB, 0x63, 0x21, 0x4F, 0xF4, 0x05, 0x70, 0xF1, 0xF7, 0xA3, 0xFC, 0xE1, 0xF7, 0x85, 0xFD, 0x7F, 0xB0, 0x0E, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0xC0, 0x46, 0x04, 0x74, 0x00, 0x20, 0x50, 0x57, 0x02, 0x00, 0x6C, 0x5D, 0x02, 0x00, 0x40, 0x00, 0x3D, 0x80, 0x4C, 0x57, 0x02, 0x00, 0x58, 0x57, 0x02, 0x00, 0x90, 0x57, 0x02, 0x00, 0x60, 0x57, 0x02, 0x00, 0x70, 0x57, 0x02, 0x00, 0x5C, 0x57, 0x02, 0x00, 0x80, 0x57, 0x02, 0x00, 0x2C, 0x57, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x88, 0x57, 0x02, 0x00, 0x54, 0x57, 0x02, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x38, 0x58, 0x02, 0x00, 0x40, 0x58 , +0x02, 0x00, 0x66, 0x55, 0xDD, 0xEE, 0xDB, 0x58, 0x02, 0x00, 0x5C, 0x58, 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, 0xF4, 0x57, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x58, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xE9, 0xFE, 0x4F, 0x4A, 0x4A, 0x49, 0x4D, 0x00, 0x90, 0xB2, 0xF9, 0x00, 0x20, 0x43, 0xA3, 0x29, 0x78, 0x01, 0x93, 0x43, 0xA3, 0x01, 0x28, 0x02, 0x93, 0x47, 0x4E, 0xDF, 0xF8, 0x1C, 0x81, 0xDF, 0xF8, 0x1C, 0x91, 0x1E, 0xD0, 0x43, 0x48, 0x04, 0x78, 0x48, 0x01, 0x87, 0x19, 0x30, 0x18, 0x01, 0x99, 0x06, 0x22, 0xF9, 0xF7, 0xC8, 0xFF, 0x40, 0x46, 0x01, 0x78, 0x00, 0x68, 0x07, 0xF1, 0x06, 0x07, 0x07, 0xF8, 0x01, 0x1B, 0x07, 0xF8, 0x01, 0x4B, 0x4F, 0xF0, 0x00, 0x01, 0x07, 0xF8, 0x01, 0x1B, 0x20, 0xB9, 0x39, 0x70, 0x28, 0x78, 0x4E, 0x46, 0x0A, 0x21, 0x58, 0xE0, 0xDF, 0xF8, 0xE4, 0xB0, 0x0F, 0xE0, 0xD4, 0xB2, 0x48, 0x01, 0x87, 0x19, 0x30, 0x18, 0x02, 0x99, 0x07, 0x22, 0xF9, 0xF7, 0xAA, 0xFF, 0xFF, 0x1D, 0x00, 0x20, 0xDF, 0xF8, 0xCC, 0xB0, 0x07, 0xF8, 0x01, 0x4B, 0x07, 0xF8, 0x01, 0x0B, 0x16, 0x2C, 0xB2, 0x46, 0xAE, 0xBF, 0x14, 0x20, 0x84, 0x59 , +0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x60, 0x1E, 0xC0, 0xB2, 0x38, 0x70, 0x4E, 0x46, 0x7F, 0x1C, 0x40, 0x1C, 0xC2, 0xB2, 0x28, 0x78, 0x5B, 0x46, 0x00, 0x21, 0x32, 0x54, 0x38, 0x46, 0x00, 0xF0, 0xBC, 0xF9, 0x28, 0x78, 0x16, 0x2C, 0x31, 0x5C, 0x01, 0xF1, 0x0A, 0x01, 0x31, 0x54, 0x00, 0xF1, 0x01, 0x00, 0xC0, 0xB2, 0x28, 0x70, 0x2B, 0xDB, 0x00, 0x99, 0x0A, 0xEB, 0x40, 0x10, 0x07, 0x46, 0x01, 0x29, 0xA4, 0xF1, 0x01, 0x09, 0x09, 0xD0, 0x01, 0x99, 0x06, 0x22, 0xF9, 0xF7, 0x79, 0xFF, 0x40, 0x46, 0x00, 0x78, 0xBF, 0x1D, 0x07, 0xF8, 0x01, 0x0B, 0x04, 0xE0, 0x02, 0x99, 0x07, 0x22, 0xF9, 0xF7, 0x6F, 0xFF, 0xFF, 0x1D, 0x07, 0xF8, 0x01, 0x4B, 0x15, 0x3C, 0x15, 0x21, 0x28, 0x78, 0xE2, 0xB2, 0x5B, 0x46, 0x07, 0xF8, 0x01, 0x1B, 0x32, 0x54, 0x07, 0xF8, 0x01, 0x9B, 0x38, 0x46, 0x00, 0xF0, 0x8B, 0xF9, 0x28, 0x78, 0x31, 0x5C, 0x0A, 0x31, 0x31, 0x54, 0x40, 0x1C, 0x28, 0x70, 0xBD, 0xE8, 0xFE, 0x8F, 0xC0, 0x46 , +0x54, 0x54, 0x54, 0x4B, 0x45, 0x59, 0x00, 0xC0, 0x54, 0x54, 0x54, 0x53, 0x53, 0x49, 0x44, 0x00, 0x54, 0x58, 0x02, 0x00, 0xE6, 0x58, 0x02, 0x00, 0xE8, 0x58, 0x02, 0x00, 0x5C, 0x58, 0x02, 0x00, 0x5C, 0x57, 0x02, 0x00, 0xDC, 0x58, 0x02, 0x00, 0xD4, 0x57, 0x02, 0x00, 0x94, 0x57, 0x02, 0x00, 0xFF, 0xB5, 0x0C, 0x46, 0x06, 0x46, 0xF7, 0xF7, 0x4C, 0x5A, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xE3, 0xFE, 0x15, 0x49, 0x15, 0x4A, 0x0D, 0x68, 0x01, 0xA9, 0x92, 0xE8, 0x8C, 0x00, 0x81, 0xE8, 0x8C, 0x00, 0xF7, 0xF7, 0xFD, 0xFE, 0x01, 0x98, 0x11, 0x49, 0x28, 0x1A, 0x03, 0x9D, 0x25, 0x60, 0x02, 0x9A, 0x80, 0x18, 0x82, 0x42, 0x30, 0x60, 0x0E, 0xD8, 0x08, 0x46, 0x00, 0x68, 0x22, 0x68, 0x82, 0x42, 0x0E, 0xD2, 0x68, 0x46, 0xE8, 0xF7, 0xB9, 0xFF, 0x9D, 0xF8, 0x00, 0x00, 0x05, 0xF1, 0x01, 0x05, 0x30, 0xB9, 0x03, 0x95, 0x03, 0xE0, 0x25, 0x68, 0x6D, 0x1C, 0x25, 0x60, 0x0C, 0x46, 0x25, 0x60, 0x00, 0x20, 0x00, 0x90 , +0xFF, 0xBD, 0x60, 0x55, 0x30, 0x80, 0x24, 0x5D, 0x00, 0x20, 0x6C, 0x5D, 0x02, 0x00, 0x70, 0xB5, 0x4D, 0x00, 0x20, 0x2D, 0x4F, 0xF0, 0x00, 0x01, 0x0C, 0x46, 0x4F, 0xEA, 0x55, 0x13, 0x09, 0xD3, 0x50, 0xF8, 0x21, 0x60, 0xB6, 0xF1, 0xFF, 0x3F, 0x04, 0xD1, 0x49, 0x1C, 0xC9, 0xB2, 0x20, 0x3D, 0x5B, 0x1E, 0xF5, 0xD1, 0x4D, 0xB1, 0x20, 0x2D, 0x09, 0xD2, 0x01, 0x23, 0xAB, 0x40, 0x5B, 0x1E, 0x50, 0xF8, 0x21, 0x00, 0x18, 0x40, 0x83, 0x42, 0x01, 0xD1, 0x4F, 0xF0, 0x01, 0x04, 0x07, 0x48, 0x03, 0x78, 0x2C, 0xB9, 0x01, 0x21, 0x91, 0x40, 0xC9, 0x43, 0xC9, 0xB2, 0x0B, 0x40, 0x03, 0xE0, 0x01, 0x21, 0x91, 0x40, 0xC9, 0xB2, 0x0B, 0x43, 0x03, 0x70, 0x70, 0xBD, 0xC0, 0x46, 0xEE, 0x58, 0x02, 0x00, 0x14, 0x5B, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x7E, 0xB5, 0x05, 0x46, 0x95, 0xF8, 0x36, 0x20, 0x0E, 0x46, 0x0F, 0x49, 0x07, 0x2A, 0x12, 0xBF, 0x08, 0x68, 0x01, 0x20, 0x08, 0x60, 0x0D, 0x4C, 0x00, 0x92, 0x21, 0x68 , +0x41, 0xF2, 0x12, 0x13, 0x04, 0x22, 0x01, 0x91, 0x07, 0x21, 0x02, 0x90, 0x03, 0x20, 0xF2, 0xF7, 0x6B, 0xFD, 0x31, 0x46, 0x28, 0x46, 0xE7, 0xF7, 0x21, 0xFC, 0x21, 0x68, 0x00, 0x22, 0x05, 0x29, 0x02, 0xD1, 0x04, 0x49, 0x08, 0x31, 0x0A, 0x60, 0x7E, 0xBD, 0xC0, 0x46, 0x50, 0x57, 0x02, 0x00, 0x4C, 0x57, 0x02, 0x00, 0x00, 0x7C, 0x00, 0x20, 0x0E, 0x49, 0x09, 0x68, 0x49, 0x08, 0x15, 0xD2, 0x0D, 0x49, 0x09, 0x78, 0x91, 0xB1, 0x44, 0xF2, 0xE9, 0x21, 0x68, 0xB9, 0x0B, 0x48, 0x01, 0x78, 0x07, 0x48, 0x01, 0x29, 0x03, 0xD1, 0x0A, 0x49, 0x09, 0x78, 0x0E, 0x29, 0x02, 0xD0, 0x44, 0xF2, 0xDE, 0x21, 0x41, 0x60, 0x01, 0x21, 0x00, 0xE0, 0x06, 0x48, 0x01, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x97, 0x3C, 0x80, 0x10, 0x0C, 0x30, 0x80, 0xDD, 0x6A, 0x00, 0x20, 0xE0, 0x7C, 0x00, 0x20, 0xA6, 0x64, 0x00, 0x20, 0x04, 0x97, 0x3C, 0x80, 0x00, 0xB5, 0xAD, 0xF1, 0x18, 0x0D, 0x4F, 0xF0, 0x09, 0x00, 0x00, 0x90, 0x4F, 0xF4 , +0x0C, 0x60, 0x03, 0x90, 0x4F, 0xF0, 0x00, 0x00, 0x01, 0x90, 0x02, 0x90, 0x08, 0x48, 0x08, 0x49, 0x05, 0x90, 0x08, 0x68, 0x20, 0xB9, 0xDC, 0x5B, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x68, 0x46, 0x03, 0x22, 0xED, 0xF7, 0x3A, 0xFA, 0x03, 0xE0, 0x68, 0x46, 0x03, 0x22, 0xED, 0xF7, 0xC1, 0xFC, 0x06, 0xB0, 0x00, 0xBD, 0xC0, 0x46, 0x81, 0x5C, 0x02, 0x00, 0xDC, 0x7C, 0x00, 0x20, 0x1C, 0xB5, 0x0F, 0x4C, 0x22, 0x68, 0x01, 0x2A, 0x15, 0xD1, 0x0C, 0x48, 0x00, 0x68, 0x07, 0x28, 0x14, 0xBF, 0x40, 0x20, 0x4F, 0xF4, 0x05, 0x70, 0x63, 0x21, 0xF1, 0xF7, 0x0F, 0xFA, 0x20, 0x68, 0x00, 0x90, 0x43, 0xF2, 0x33, 0x33, 0x06, 0x21, 0x40, 0x20, 0x01, 0x90, 0x03, 0x20, 0x02, 0x46, 0xF2, 0xF7, 0xF4, 0xFC, 0x1C, 0xBD, 0xF1, 0xF7, 0x01, 0xFA, 0x1C, 0xBD, 0x4C, 0x57, 0x02, 0x00, 0x50, 0x57, 0x02, 0x00, 0x1E, 0xB5, 0x04, 0x46, 0x0A, 0x49, 0x00, 0x20, 0x0A, 0x4A, 0x08, 0x60, 0x0A, 0x49, 0x00, 0x90, 0x01, 0x90, 0x11, 0x60 , +0x09, 0x4A, 0x45, 0xF2, 0x55, 0x53, 0x02, 0x91, 0x10, 0x60, 0x07, 0x21, 0x04, 0x22, 0x03, 0x20, 0xF2, 0xF7, 0xD8, 0xFC, 0x20, 0x46, 0xE7, 0xF7, 0x59, 0xFD, 0x1E, 0xBD, 0x50, 0x57, 0x02, 0x00, 0x04, 0x74, 0x00, 0x20, 0x34, 0x12, 0x66, 0x09, 0x4C, 0x57, 0x02, 0x00, 0x00, 0xB5, 0x0B, 0x49, 0x00, 0x20, 0x08, 0x60, 0xE0, 0x20, 0xF7, 0xF7, 0xAA, 0xFD, 0x09, 0x49, 0x09, 0x78, 0x49, 0xB1, 0x08, 0x49, 0x0A, 0x78, 0x08, 0x49, 0x00, 0x2A, 0x06, 0xBF, 0x01, 0x22, 0x09, 0x1F, 0x44, 0xF2, 0xA4, 0x5C, 0x02, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xE9, 0x22, 0x0A, 0x60, 0xF7, 0xF7, 0xA1, 0xFD, 0x00, 0xBD, 0xC0, 0x46, 0xDC, 0x7C, 0x00, 0x20, 0xDD, 0x6A, 0x00, 0x20, 0xA7, 0x64, 0x00, 0x20, 0x04, 0x97, 0x3C, 0x80, 0x50, 0xB9, 0x09, 0x48, 0x00, 0x78, 0x01, 0x28, 0x06, 0xD1, 0x08, 0x48, 0x00, 0x78, 0x0E, 0x28, 0x08, 0xBF, 0x44, 0xF2, 0xCB, 0x20, 0x01, 0xD0, 0x44, 0xF2, 0xDE, 0x20, 0x04, 0x49, 0x08, 0x60, 0x01, 0x20 , +0x41, 0xF8, 0x04, 0x0C, 0x70, 0x47, 0xE0, 0x7C, 0x00, 0x20, 0xA6, 0x64, 0x00, 0x20, 0x04, 0x97, 0x3C, 0x80, 0x30, 0xB5, 0x0D, 0x46, 0x84, 0x69, 0xDC, 0xF7, 0x97, 0xFB, 0x24, 0x1D, 0x01, 0x28, 0x04, 0xEB, 0x45, 0x01, 0x06, 0xD1, 0x89, 0x8E, 0x04, 0xEB, 0x85, 0x04, 0x11, 0xB9, 0x21, 0x69, 0x01, 0xB9, 0x00, 0x20, 0x30, 0xBD, 0x30, 0xB5, 0x05, 0x46, 0x5A, 0xB1, 0x03, 0xEB, 0x41, 0x03, 0x1C, 0x78, 0x59, 0x78, 0x41, 0xEA, 0x04, 0x11, 0x52, 0x1E, 0x03, 0xF1, 0x02, 0x03, 0x05, 0xF8, 0x01, 0x1B, 0xF5, 0xD1, 0x30, 0xBD, 0x00, 0xB5, 0x00, 0x20, 0xE7, 0xF7, 0xD6, 0xFE, 0x03, 0x48, 0x01, 0x68, 0x03, 0x29, 0x04, 0xBF, 0x04, 0x21, 0x01, 0x60, 0x00, 0xBD, 0xC0, 0x46, 0x4C, 0x57, 0x02, 0x00, 0x03, 0x4A, 0x12, 0x68, 0x01, 0x2A, 0x04, 0xBF, 0x02, 0x48, 0x63, 0x21, 0xF1, 0xF7, 0x76, 0xB9, 0x50, 0x57, 0x02, 0x00, 0x02, 0x20, 0x01, 0x00, 0x6C, 0x5D, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/src/openmv/src/micropython/drivers/cc3000/src/patch_prog.c b/src/openmv/src/micropython/drivers/cc3000/src/patch_prog.c new file mode 100755 index 0000000..fd12892 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/patch_prog.c @@ -0,0 +1,414 @@ +#include +#include +#include "cc3000_common.h" +#include "nvmem.h" +#include "ccspi.h" +#include "hci.h" +#include "wlan.h" +#include "patch_prog.h" +#define BIT0 0x1 +#define BIT1 0x2 +#define BIT2 0x4 +#define BIT3 0x8 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 + +static unsigned char ucStatus_Dr; +static unsigned char ucStatus_FW; +static unsigned char return_status = 0xFF; + +static signed char mac_status = -1; +static unsigned char counter = 0; + +// Array to store RM parameters from EEPROM. +static unsigned char cRMParamsFromEeprom[128]; +// Array to store MAC address from EEPROM. +static unsigned char cMacFromEeprom[MAC_ADDR_LEN]; +// Smart Config Prefix +static const char aucCC3000_prefix[] = {'T', 'T', 'T'}; + +static void systick_sleep(unsigned long ms) { + extern void HAL_Delay(volatile uint32_t Delay); + HAL_Delay(ms); +} + +// 2 dim array to store address and length of new FAT +static const unsigned short aFATEntries[2][NVMEM_RM_FILEID + 1] = +/* address */ {{0x50, 0x1f0, 0x390, 0x1390, 0x2390, 0x4390, 0x6390, 0x63a0, 0x63b0, 0x63f0, 0x6430, 0x6830}, +/* length */ {0x1a0, 0x1a0, 0x1000, 0x1000, 0x2000, 0x2000, 0x10, 0x10, 0x40, 0x40, 0x400, 0x200}}; +/* 0. NVS */ +/* 1. NVS Shadow */ +/* 2. Wireless Conf */ +/* 3. Wireless Conf Shadow */ +/* 4. BT (WLAN driver) Patches */ +/* 5. WiLink (Firmware) Patches */ +/* 6. MAC addr */ +/* 7. Frontend Vars */ +/* 8. IP config */ +/* 9. IP config Shadow */ +/* 10. Bootloader Patches */ +/* 11. Radio Module params */ +/* 12. AES128 for smart config */ +/* 13. user file */ +/* 14. user file */ +/* 15. user file */ + +//***************************************************************************** +// +//! sendDriverPatch +//! +//! \param pointer to the length +//! +//! \return none +//! +//! \brief The function returns a pointer to the driver patch: +//! since there is no patch yet - it returns 0 +// +//***************************************************************************** + +static char *sendDriverPatch(unsigned long *Length) +{ + *Length = 0; + return NULL; +} + + +//***************************************************************************** +// +//! sendBootLoaderPatch +//! +//! \param pointer to the length +//! +//! \return none +//! +//! \brief The function returns a pointer to the boot loader patch: +//! since there is no patch yet - it returns 0 +// +//***************************************************************************** + +static char *sendBootLoaderPatch(unsigned long *Length) +{ + *Length = 0; + return NULL; +} + +//***************************************************************************** +// +//! sendWLFWPatch +//! +//! \param pointer to the length +//! +//! \return none +//! +//! \brief The function returns a pointer to the FW patch: +//! since there is no patch yet - it returns 0 +// +//***************************************************************************** + +static char *sendWLFWPatch(unsigned long *Length) +{ + *Length = 0; + return NULL; +} + +//***************************************************************************** +// +//! CC3000_UsynchCallback +//! +//! \param Event type +//! +//! \return none +//! +//! \brief The function handles asynchronous events that come from CC3000 +//! device and operates a LED4 to have an on-board indication +// +//***************************************************************************** + +static void CC3000_UsynchCallback(long lEventType, char * data, unsigned char length) +{ + +} + +//***************************************************************************** +// +//! initDriver +//! +//! \param[in] cRequestPatch 0 to load with EEPROM patches +//! and 1 to load with no patches +//! +//! \return none +//! +//! \brief The function initializes a CC3000 device +//! and triggers it to start operation +// +//***************************************************************************** +static int initDriver(unsigned short cRequestPatch) +{ + // WLAN On API Implementation + wlan_init(CC3000_UsynchCallback, sendWLFWPatch, sendDriverPatch, sendBootLoaderPatch, + ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin); + + // Trigger a WLAN device + wlan_start(cRequestPatch); + wlan_smart_config_set_prefix((char*)aucCC3000_prefix); + wlan_ioctl_set_connection_policy(0, 0, 0); + wlan_ioctl_del_profile(255); + + // Mask out all non-required events from CC3000 + wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE| + HCI_EVNT_WLAN_UNSOL_INIT| + HCI_EVNT_WLAN_ASYNC_PING_REPORT); + + //unsolicicted_events_timer_init(); + systick_sleep(100); + return(0); +} + + +//***************************************************************************** +// +//! fat_read_content +//! +//! \param[out] is_allocated array of is_allocated in FAT table:\n +//! an allocated entry implies the address and length of the +//! file are valid. +//! 0: not allocated; 1: allocated. +//! \param[out] is_valid array of is_valid in FAT table:\n +//! a valid entry implies the content of the file is relevant. +//! 0: not valid; 1: valid. +//! \param[out] write_protected array of write_protected in FAT table:\n +//! a write protected entry implies it is not possible to write +//! into this entry. +//! 0: not protected; 1: protected. +//! \param[out] file_address array of file address in FAT table:\n +//! this is the absolute address of the file in the EEPROM. +//! \param[out] file_length array of file length in FAT table:\n +//! this is the upper limit of the file size in the EEPROM. +//! +//! \return on succes 0, error otherwise +//! +//! \brief parse the FAT table from eeprom +// +//***************************************************************************** +static unsigned char __attribute__ ((unused)) +fat_read_content(unsigned char *is_allocated, unsigned char *is_valid, + unsigned char *write_protected, unsigned short *file_address, unsigned short *file_length) +{ + unsigned short index; + unsigned char ucStatus; + unsigned char fatTable[48]; + unsigned char* fatTablePtr = fatTable; + + // + // Read in 6 parts to work with tiny driver + // + for (index = 0; index < 6; index++) + { + ucStatus = nvmem_read(16, 8, 4 + 8*index, fatTablePtr); + fatTablePtr += 8; + } + + fatTablePtr = fatTable; + + for (index = 0; index <= NVMEM_RM_FILEID; index++) + { + *is_allocated++ = (*fatTablePtr) & BIT0; + *is_valid++ = ((*fatTablePtr) & BIT1) >> 1; + *write_protected++ = ((*fatTablePtr) & BIT2) >> 2; + *file_address++ = ((*(fatTablePtr+1)<<8) | (*fatTablePtr)) & (BIT4|BIT5|BIT6|BIT7); + *file_length++ = ((*(fatTablePtr+3)<<8) | (*(fatTablePtr+2))) & (BIT4|BIT5|BIT6|BIT7); + + // + // Move to next file ID + // + fatTablePtr += 4; + } + + return ucStatus; +} + +//***************************************************************************** +// +//! fat_write_content +//! +//! \param[in] file_address array of file address in FAT table:\n +//! this is the absolute address of the file in the EEPROM. +//! \param[in] file_length array of file length in FAT table:\n +//! this is the upper limit of the file size in the EEPROM. +//! +//! \return on succes 0, error otherwise +//! +//! \brief parse the FAT table from eeprom +// +//***************************************************************************** +static unsigned char fat_write_content(unsigned short const *file_address, + unsigned short const *file_length) +{ + unsigned short index = 0; + unsigned char ucStatus; + unsigned char fatTable[48]; + unsigned char* fatTablePtr = fatTable; + + // + // First, write the magic number. + // + ucStatus = nvmem_write(16, 2, 0, (unsigned char*)"LS"); + + for (; index <= NVMEM_RM_FILEID; index++) + { + // + // Write address low char and mark as allocated. + // + *fatTablePtr++ = (unsigned char)(file_address[index] & 0xff) | BIT0; + + // + // Write address high char. + // + *fatTablePtr++ = (unsigned char)((file_address[index]>>8) & 0xff); + + // + // Write length low char. + // + *fatTablePtr++ = (unsigned char)(file_length[index] & 0xff); + + // + // Write length high char. + // + *fatTablePtr++ = (unsigned char)((file_length[index]>>8) & 0xff); + } + + // + // Second, write the FAT. + // Write in two parts to work with tiny driver. + // + ucStatus = nvmem_write(16, 24, 4, fatTable); + ucStatus = nvmem_write(16, 24, 24+4, &fatTable[24]); + + // + // Third, we want to erase any user files. + // + memset(fatTable, 0, sizeof(fatTable)); + ucStatus = nvmem_write(16, 16, 52, fatTable); + + return ucStatus; +} + +void patch_prog_start() +{ + unsigned short index; + unsigned char *pRMParams; + + printf("Initializing module...\n"); + + // Init module and request to load with no patches. + // This is in order to overwrite restrictions to + // write to specific places in EEPROM. + initDriver(1); + + // Read MAC address. + mac_status = nvmem_get_mac_address(cMacFromEeprom); + + return_status = 1; + + printf("Reading RM parameters...\n"); + while ((return_status) && (counter < 3)) { + // Read RM parameters. + // Read in 16 parts to work with tiny driver. + return_status = 0; + pRMParams = cRMParamsFromEeprom; + for (index = 0; index < 16; index++) { + return_status |= nvmem_read(NVMEM_RM_FILEID, 8, 8*index, pRMParams); + pRMParams += 8; + } + counter++; + } + + // If RM file is not valid, load the default one. + if (counter == 3) { + printf("RM is not valid, loading default one...\n"); + pRMParams = (unsigned char *)cRMdefaultParams; + } else { + printf("RM is valid.\n"); + pRMParams = cRMParamsFromEeprom; + } + + return_status = 1; + + printf("Writing new FAT\n"); + while (return_status) { + // Write new FAT. + return_status = fat_write_content(aFATEntries[0], aFATEntries[1]); + } + + return_status = 1; + + printf("Writing RM parameters...\n"); + while (return_status) { + // Write RM parameters. + // Write in 4 parts to work with tiny driver. + return_status = 0; + + for (index = 0; index < 4; index++) { + return_status |= nvmem_write(NVMEM_RM_FILEID, + 32, + 32*index, + (pRMParams + 32*index)); + } + } + + return_status = 1; + + // Write back the MAC address, only if exists. + if (mac_status == 0) { + // Zero out MCAST bit if set. + cMacFromEeprom[0] &= 0xfe; + printf("Writing back MAC address..\n"); + while (return_status) { + return_status = nvmem_set_mac_address(cMacFromEeprom); + } + } + + // Update driver + ucStatus_Dr = 1; + printf("Updating driver patch...\n"); + while (ucStatus_Dr) { + // Writing driver patch to EEPRROM - PROTABLE CODE + // Note that the array itself is changing between the + // different Service Packs. + ucStatus_Dr = nvmem_write_patch(NVMEM_WLAN_DRIVER_SP_FILEID, + drv_length, + wlan_drv_patch); + } + + // Update firmware + ucStatus_FW = 1; + printf("Updating firmware patch...\n"); + while (ucStatus_FW) { + // Writing FW patch to EEPRROM - PROTABLE CODE + // Note that the array itself is changing between the + // different Service Packs. + ucStatus_FW = nvmem_write_patch(NVMEM_WLAN_FW_SP_FILEID, + fw_length, + fw_patch); + } + + printf("Update complete, resetting module\n"\ + "If this doesn't work, reset manually...\n"); + + wlan_stop(); + systick_sleep(500); + + // Re-Init module and request to load with patches. + initDriver(0); + + // If MAC does not exist, it is recommended + // that the user will write a valid mac address. + if (mac_status != 0) { + printf("MAC address is not valid, please write a new one\n"); + } + + // Patch update done + printf("All done, call wlan.patch_version()\n"); +} diff --git a/src/openmv/src/micropython/drivers/cc3000/src/security.c b/src/openmv/src/micropython/drivers/cc3000/src/security.c new file mode 100755 index 0000000..62b4f88 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/security.c @@ -0,0 +1,530 @@ +/***************************************************************************** +* +* security.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ + +//***************************************************************************** +// +//! \addtogroup security_api +//! @{ +// +//***************************************************************************** + +#include "security.h" + +#ifndef CC3000_UNENCRYPTED_SMART_CONFIG +// foreward sbox +const UINT8 sbox[256] = { +//0 1 2 3 4 5 6 7 8 9 A B C D E F +0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0 +0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1 +0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2 +0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3 +0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4 +0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5 +0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6 +0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7 +0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8 +0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9 +0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A +0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B +0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C +0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D +0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E +0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F +// inverse sbox +const UINT8 rsbox[256] = +{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb +, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb +, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e +, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 +, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 +, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 +, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 +, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b +, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 +, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e +, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b +, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 +, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f +, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef +, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 +, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; +// round constant +const UINT8 Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; + + +UINT8 expandedKey[176]; + +//***************************************************************************** +// +//! expandKey +//! +//! @param key AES128 key - 16 bytes +//! @param expandedKey expanded AES128 key +//! +//! @return none +//! +//! @brief expend a 16 bytes key for AES128 implementation +//! +//***************************************************************************** + +void expandKey(UINT8 *expandedKey, UINT8 *key) +{ + UINT16 ii, buf1; + for (ii=0;ii<16;ii++) + expandedKey[ii] = key[ii]; + for (ii=1;ii<11;ii++){ + buf1 = expandedKey[ii*16 - 4]; + expandedKey[ii*16 + 0] = sbox[expandedKey[ii*16 - 3]]^expandedKey[(ii-1)*16 + 0]^Rcon[ii]; + expandedKey[ii*16 + 1] = sbox[expandedKey[ii*16 - 2]]^expandedKey[(ii-1)*16 + 1]; + expandedKey[ii*16 + 2] = sbox[expandedKey[ii*16 - 1]]^expandedKey[(ii-1)*16 + 2]; + expandedKey[ii*16 + 3] = sbox[buf1 ]^expandedKey[(ii-1)*16 + 3]; + expandedKey[ii*16 + 4] = expandedKey[(ii-1)*16 + 4]^expandedKey[ii*16 + 0]; + expandedKey[ii*16 + 5] = expandedKey[(ii-1)*16 + 5]^expandedKey[ii*16 + 1]; + expandedKey[ii*16 + 6] = expandedKey[(ii-1)*16 + 6]^expandedKey[ii*16 + 2]; + expandedKey[ii*16 + 7] = expandedKey[(ii-1)*16 + 7]^expandedKey[ii*16 + 3]; + expandedKey[ii*16 + 8] = expandedKey[(ii-1)*16 + 8]^expandedKey[ii*16 + 4]; + expandedKey[ii*16 + 9] = expandedKey[(ii-1)*16 + 9]^expandedKey[ii*16 + 5]; + expandedKey[ii*16 +10] = expandedKey[(ii-1)*16 +10]^expandedKey[ii*16 + 6]; + expandedKey[ii*16 +11] = expandedKey[(ii-1)*16 +11]^expandedKey[ii*16 + 7]; + expandedKey[ii*16 +12] = expandedKey[(ii-1)*16 +12]^expandedKey[ii*16 + 8]; + expandedKey[ii*16 +13] = expandedKey[(ii-1)*16 +13]^expandedKey[ii*16 + 9]; + expandedKey[ii*16 +14] = expandedKey[(ii-1)*16 +14]^expandedKey[ii*16 +10]; + expandedKey[ii*16 +15] = expandedKey[(ii-1)*16 +15]^expandedKey[ii*16 +11]; + } + +} + +//***************************************************************************** +// +//! galois_mul2 +//! +//! @param value argument to multiply +//! +//! @return multiplied argument +//! +//! @brief multiply by 2 in the galois field +//! +//***************************************************************************** + +UINT8 galois_mul2(UINT8 value) +{ + if (value>>7) + { + value = value << 1; + return (value^0x1b); + } else + return value<<1; +} + +//***************************************************************************** +// +//! aes_encr +//! +//! @param[in] expandedKey expanded AES128 key +//! @param[in/out] state 16 bytes of plain text and cipher text +//! +//! @return none +//! +//! @brief internal implementation of AES128 encryption. +//! straight forward aes encryption implementation +//! first the group of operations +//! - addRoundKey +//! - subbytes +//! - shiftrows +//! - mixcolums +//! is executed 9 times, after this addroundkey to finish the 9th +//! round, after that the 10th round without mixcolums +//! no further subfunctions to save cycles for function calls +//! no structuring with "for (....)" to save cycles. +//! +//! +//***************************************************************************** + +void aes_encr(UINT8 *state, UINT8 *expandedKey) +{ + UINT8 buf1, buf2, buf3, round; + + for (round = 0; round < 9; round ++){ + // addroundkey, sbox and shiftrows + // row 0 + state[ 0] = sbox[(state[ 0] ^ expandedKey[(round*16) ])]; + state[ 4] = sbox[(state[ 4] ^ expandedKey[(round*16) + 4])]; + state[ 8] = sbox[(state[ 8] ^ expandedKey[(round*16) + 8])]; + state[12] = sbox[(state[12] ^ expandedKey[(round*16) + 12])]; + // row 1 + buf1 = state[1] ^ expandedKey[(round*16) + 1]; + state[ 1] = sbox[(state[ 5] ^ expandedKey[(round*16) + 5])]; + state[ 5] = sbox[(state[ 9] ^ expandedKey[(round*16) + 9])]; + state[ 9] = sbox[(state[13] ^ expandedKey[(round*16) + 13])]; + state[13] = sbox[buf1]; + // row 2 + buf1 = state[2] ^ expandedKey[(round*16) + 2]; + buf2 = state[6] ^ expandedKey[(round*16) + 6]; + state[ 2] = sbox[(state[10] ^ expandedKey[(round*16) + 10])]; + state[ 6] = sbox[(state[14] ^ expandedKey[(round*16) + 14])]; + state[10] = sbox[buf1]; + state[14] = sbox[buf2]; + // row 3 + buf1 = state[15] ^ expandedKey[(round*16) + 15]; + state[15] = sbox[(state[11] ^ expandedKey[(round*16) + 11])]; + state[11] = sbox[(state[ 7] ^ expandedKey[(round*16) + 7])]; + state[ 7] = sbox[(state[ 3] ^ expandedKey[(round*16) + 3])]; + state[ 3] = sbox[buf1]; + + // mixcolums ////////// + // col1 + buf1 = state[0] ^ state[1] ^ state[2] ^ state[3]; + buf2 = state[0]; + buf3 = state[0]^state[1]; buf3=galois_mul2(buf3); state[0] = state[0] ^ buf3 ^ buf1; + buf3 = state[1]^state[2]; buf3=galois_mul2(buf3); state[1] = state[1] ^ buf3 ^ buf1; + buf3 = state[2]^state[3]; buf3=galois_mul2(buf3); state[2] = state[2] ^ buf3 ^ buf1; + buf3 = state[3]^buf2; buf3=galois_mul2(buf3); state[3] = state[3] ^ buf3 ^ buf1; + // col2 + buf1 = state[4] ^ state[5] ^ state[6] ^ state[7]; + buf2 = state[4]; + buf3 = state[4]^state[5]; buf3=galois_mul2(buf3); state[4] = state[4] ^ buf3 ^ buf1; + buf3 = state[5]^state[6]; buf3=galois_mul2(buf3); state[5] = state[5] ^ buf3 ^ buf1; + buf3 = state[6]^state[7]; buf3=galois_mul2(buf3); state[6] = state[6] ^ buf3 ^ buf1; + buf3 = state[7]^buf2; buf3=galois_mul2(buf3); state[7] = state[7] ^ buf3 ^ buf1; + // col3 + buf1 = state[8] ^ state[9] ^ state[10] ^ state[11]; + buf2 = state[8]; + buf3 = state[8]^state[9]; buf3=galois_mul2(buf3); state[8] = state[8] ^ buf3 ^ buf1; + buf3 = state[9]^state[10]; buf3=galois_mul2(buf3); state[9] = state[9] ^ buf3 ^ buf1; + buf3 = state[10]^state[11]; buf3=galois_mul2(buf3); state[10] = state[10] ^ buf3 ^ buf1; + buf3 = state[11]^buf2; buf3=galois_mul2(buf3); state[11] = state[11] ^ buf3 ^ buf1; + // col4 + buf1 = state[12] ^ state[13] ^ state[14] ^ state[15]; + buf2 = state[12]; + buf3 = state[12]^state[13]; buf3=galois_mul2(buf3); state[12] = state[12] ^ buf3 ^ buf1; + buf3 = state[13]^state[14]; buf3=galois_mul2(buf3); state[13] = state[13] ^ buf3 ^ buf1; + buf3 = state[14]^state[15]; buf3=galois_mul2(buf3); state[14] = state[14] ^ buf3 ^ buf1; + buf3 = state[15]^buf2; buf3=galois_mul2(buf3); state[15] = state[15] ^ buf3 ^ buf1; + + } + // 10th round without mixcols + state[ 0] = sbox[(state[ 0] ^ expandedKey[(round*16) ])]; + state[ 4] = sbox[(state[ 4] ^ expandedKey[(round*16) + 4])]; + state[ 8] = sbox[(state[ 8] ^ expandedKey[(round*16) + 8])]; + state[12] = sbox[(state[12] ^ expandedKey[(round*16) + 12])]; + // row 1 + buf1 = state[1] ^ expandedKey[(round*16) + 1]; + state[ 1] = sbox[(state[ 5] ^ expandedKey[(round*16) + 5])]; + state[ 5] = sbox[(state[ 9] ^ expandedKey[(round*16) + 9])]; + state[ 9] = sbox[(state[13] ^ expandedKey[(round*16) + 13])]; + state[13] = sbox[buf1]; + // row 2 + buf1 = state[2] ^ expandedKey[(round*16) + 2]; + buf2 = state[6] ^ expandedKey[(round*16) + 6]; + state[ 2] = sbox[(state[10] ^ expandedKey[(round*16) + 10])]; + state[ 6] = sbox[(state[14] ^ expandedKey[(round*16) + 14])]; + state[10] = sbox[buf1]; + state[14] = sbox[buf2]; + // row 3 + buf1 = state[15] ^ expandedKey[(round*16) + 15]; + state[15] = sbox[(state[11] ^ expandedKey[(round*16) + 11])]; + state[11] = sbox[(state[ 7] ^ expandedKey[(round*16) + 7])]; + state[ 7] = sbox[(state[ 3] ^ expandedKey[(round*16) + 3])]; + state[ 3] = sbox[buf1]; + // last addroundkey + state[ 0]^=expandedKey[160]; + state[ 1]^=expandedKey[161]; + state[ 2]^=expandedKey[162]; + state[ 3]^=expandedKey[163]; + state[ 4]^=expandedKey[164]; + state[ 5]^=expandedKey[165]; + state[ 6]^=expandedKey[166]; + state[ 7]^=expandedKey[167]; + state[ 8]^=expandedKey[168]; + state[ 9]^=expandedKey[169]; + state[10]^=expandedKey[170]; + state[11]^=expandedKey[171]; + state[12]^=expandedKey[172]; + state[13]^=expandedKey[173]; + state[14]^=expandedKey[174]; + state[15]^=expandedKey[175]; +} + +//***************************************************************************** +// +//! aes_decr +//! +//! @param[in] expandedKey expanded AES128 key +//! @param[in\out] state 16 bytes of cipher text and plain text +//! +//! @return none +//! +//! @brief internal implementation of AES128 decryption. +//! straight forward aes decryption implementation +//! the order of substeps is the exact reverse of decryption +//! inverse functions: +//! - addRoundKey is its own inverse +//! - rsbox is inverse of sbox +//! - rightshift instead of leftshift +//! - invMixColumns = barreto + mixColumns +//! no further subfunctions to save cycles for function calls +//! no structuring with "for (....)" to save cycles +//! +//***************************************************************************** + +void aes_decr(UINT8 *state, UINT8 *expandedKey) +{ + UINT8 buf1, buf2, buf3; + INT8 round; + round = 9; + + // initial addroundkey + state[ 0]^=expandedKey[160]; + state[ 1]^=expandedKey[161]; + state[ 2]^=expandedKey[162]; + state[ 3]^=expandedKey[163]; + state[ 4]^=expandedKey[164]; + state[ 5]^=expandedKey[165]; + state[ 6]^=expandedKey[166]; + state[ 7]^=expandedKey[167]; + state[ 8]^=expandedKey[168]; + state[ 9]^=expandedKey[169]; + state[10]^=expandedKey[170]; + state[11]^=expandedKey[171]; + state[12]^=expandedKey[172]; + state[13]^=expandedKey[173]; + state[14]^=expandedKey[174]; + state[15]^=expandedKey[175]; + + // 10th round without mixcols + state[ 0] = rsbox[state[ 0]] ^ expandedKey[(round*16) ]; + state[ 4] = rsbox[state[ 4]] ^ expandedKey[(round*16) + 4]; + state[ 8] = rsbox[state[ 8]] ^ expandedKey[(round*16) + 8]; + state[12] = rsbox[state[12]] ^ expandedKey[(round*16) + 12]; + // row 1 + buf1 = rsbox[state[13]] ^ expandedKey[(round*16) + 1]; + state[13] = rsbox[state[ 9]] ^ expandedKey[(round*16) + 13]; + state[ 9] = rsbox[state[ 5]] ^ expandedKey[(round*16) + 9]; + state[ 5] = rsbox[state[ 1]] ^ expandedKey[(round*16) + 5]; + state[ 1] = buf1; + // row 2 + buf1 = rsbox[state[ 2]] ^ expandedKey[(round*16) + 10]; + buf2 = rsbox[state[ 6]] ^ expandedKey[(round*16) + 14]; + state[ 2] = rsbox[state[10]] ^ expandedKey[(round*16) + 2]; + state[ 6] = rsbox[state[14]] ^ expandedKey[(round*16) + 6]; + state[10] = buf1; + state[14] = buf2; + // row 3 + buf1 = rsbox[state[ 3]] ^ expandedKey[(round*16) + 15]; + state[ 3] = rsbox[state[ 7]] ^ expandedKey[(round*16) + 3]; + state[ 7] = rsbox[state[11]] ^ expandedKey[(round*16) + 7]; + state[11] = rsbox[state[15]] ^ expandedKey[(round*16) + 11]; + state[15] = buf1; + + for (round = 8; round >= 0; round--){ + // barreto + //col1 + buf1 = galois_mul2(galois_mul2(state[0]^state[2])); + buf2 = galois_mul2(galois_mul2(state[1]^state[3])); + state[0] ^= buf1; state[1] ^= buf2; state[2] ^= buf1; state[3] ^= buf2; + //col2 + buf1 = galois_mul2(galois_mul2(state[4]^state[6])); + buf2 = galois_mul2(galois_mul2(state[5]^state[7])); + state[4] ^= buf1; state[5] ^= buf2; state[6] ^= buf1; state[7] ^= buf2; + //col3 + buf1 = galois_mul2(galois_mul2(state[8]^state[10])); + buf2 = galois_mul2(galois_mul2(state[9]^state[11])); + state[8] ^= buf1; state[9] ^= buf2; state[10] ^= buf1; state[11] ^= buf2; + //col4 + buf1 = galois_mul2(galois_mul2(state[12]^state[14])); + buf2 = galois_mul2(galois_mul2(state[13]^state[15])); + state[12] ^= buf1; state[13] ^= buf2; state[14] ^= buf1; state[15] ^= buf2; + // mixcolums ////////// + // col1 + buf1 = state[0] ^ state[1] ^ state[2] ^ state[3]; + buf2 = state[0]; + buf3 = state[0]^state[1]; buf3=galois_mul2(buf3); state[0] = state[0] ^ buf3 ^ buf1; + buf3 = state[1]^state[2]; buf3=galois_mul2(buf3); state[1] = state[1] ^ buf3 ^ buf1; + buf3 = state[2]^state[3]; buf3=galois_mul2(buf3); state[2] = state[2] ^ buf3 ^ buf1; + buf3 = state[3]^buf2; buf3=galois_mul2(buf3); state[3] = state[3] ^ buf3 ^ buf1; + // col2 + buf1 = state[4] ^ state[5] ^ state[6] ^ state[7]; + buf2 = state[4]; + buf3 = state[4]^state[5]; buf3=galois_mul2(buf3); state[4] = state[4] ^ buf3 ^ buf1; + buf3 = state[5]^state[6]; buf3=galois_mul2(buf3); state[5] = state[5] ^ buf3 ^ buf1; + buf3 = state[6]^state[7]; buf3=galois_mul2(buf3); state[6] = state[6] ^ buf3 ^ buf1; + buf3 = state[7]^buf2; buf3=galois_mul2(buf3); state[7] = state[7] ^ buf3 ^ buf1; + // col3 + buf1 = state[8] ^ state[9] ^ state[10] ^ state[11]; + buf2 = state[8]; + buf3 = state[8]^state[9]; buf3=galois_mul2(buf3); state[8] = state[8] ^ buf3 ^ buf1; + buf3 = state[9]^state[10]; buf3=galois_mul2(buf3); state[9] = state[9] ^ buf3 ^ buf1; + buf3 = state[10]^state[11]; buf3=galois_mul2(buf3); state[10] = state[10] ^ buf3 ^ buf1; + buf3 = state[11]^buf2; buf3=galois_mul2(buf3); state[11] = state[11] ^ buf3 ^ buf1; + // col4 + buf1 = state[12] ^ state[13] ^ state[14] ^ state[15]; + buf2 = state[12]; + buf3 = state[12]^state[13]; buf3=galois_mul2(buf3); state[12] = state[12] ^ buf3 ^ buf1; + buf3 = state[13]^state[14]; buf3=galois_mul2(buf3); state[13] = state[13] ^ buf3 ^ buf1; + buf3 = state[14]^state[15]; buf3=galois_mul2(buf3); state[14] = state[14] ^ buf3 ^ buf1; + buf3 = state[15]^buf2; buf3=galois_mul2(buf3); state[15] = state[15] ^ buf3 ^ buf1; + + // addroundkey, rsbox and shiftrows + // row 0 + state[ 0] = rsbox[state[ 0]] ^ expandedKey[(round*16) ]; + state[ 4] = rsbox[state[ 4]] ^ expandedKey[(round*16) + 4]; + state[ 8] = rsbox[state[ 8]] ^ expandedKey[(round*16) + 8]; + state[12] = rsbox[state[12]] ^ expandedKey[(round*16) + 12]; + // row 1 + buf1 = rsbox[state[13]] ^ expandedKey[(round*16) + 1]; + state[13] = rsbox[state[ 9]] ^ expandedKey[(round*16) + 13]; + state[ 9] = rsbox[state[ 5]] ^ expandedKey[(round*16) + 9]; + state[ 5] = rsbox[state[ 1]] ^ expandedKey[(round*16) + 5]; + state[ 1] = buf1; + // row 2 + buf1 = rsbox[state[ 2]] ^ expandedKey[(round*16) + 10]; + buf2 = rsbox[state[ 6]] ^ expandedKey[(round*16) + 14]; + state[ 2] = rsbox[state[10]] ^ expandedKey[(round*16) + 2]; + state[ 6] = rsbox[state[14]] ^ expandedKey[(round*16) + 6]; + state[10] = buf1; + state[14] = buf2; + // row 3 + buf1 = rsbox[state[ 3]] ^ expandedKey[(round*16) + 15]; + state[ 3] = rsbox[state[ 7]] ^ expandedKey[(round*16) + 3]; + state[ 7] = rsbox[state[11]] ^ expandedKey[(round*16) + 7]; + state[11] = rsbox[state[15]] ^ expandedKey[(round*16) + 11]; + state[15] = buf1; + } + +} + +//***************************************************************************** +// +//! aes_encrypt +//! +//! @param[in] key AES128 key of size 16 bytes +//! @param[in\out] state 16 bytes of plain text and cipher text +//! +//! @return none +//! +//! @brief AES128 encryption: +//! Given AES128 key and 16 bytes plain text, cipher text of 16 bytes +//! is computed. The AES implementation is in mode ECB (Electronic +//! Code Book). +//! +//! +//***************************************************************************** + +void aes_encrypt(UINT8 *state, UINT8 *key) +{ + // expand the key into 176 bytes + expandKey(expandedKey, key); + aes_encr(state, expandedKey); +} + +//***************************************************************************** +// +//! aes_decrypt +//! +//! @param[in] key AES128 key of size 16 bytes +//! @param[in\out] state 16 bytes of cipher text and plain text +//! +//! @return none +//! +//! @brief AES128 decryption: +//! Given AES128 key and 16 bytes cipher text, plain text of 16 bytes +//! is computed The AES implementation is in mode ECB +//! (Electronic Code Book). +//! +//! +//***************************************************************************** + +void aes_decrypt(UINT8 *state, UINT8 *key) +{ + expandKey(expandedKey, key); // expand the key into 176 bytes + aes_decr(state, expandedKey); +} + +//***************************************************************************** +// +//! aes_read_key +//! +//! @param[out] key AES128 key of size 16 bytes +//! +//! @return on success 0, error otherwise. +//! +//! @brief Reads AES128 key from EEPROM +//! Reads the AES128 key from fileID #12 in EEPROM +//! returns an error if the key does not exist. +//! +//! +//***************************************************************************** + +INT32 aes_read_key(UINT8 *key) +{ + INT32 returnValue; + + returnValue = nvmem_read(NVMEM_AES128_KEY_FILEID, AES128_KEY_SIZE, 0, key); + + return returnValue; +} + +//***************************************************************************** +// +//! aes_write_key +//! +//! @param[out] key AES128 key of size 16 bytes +//! +//! @return on success 0, error otherwise. +//! +//! @brief writes AES128 key from EEPROM +//! Writes the AES128 key to fileID #12 in EEPROM +//! +//! +//***************************************************************************** + +INT32 aes_write_key(UINT8 *key) +{ + INT32 returnValue; + + returnValue = nvmem_write(NVMEM_AES128_KEY_FILEID, AES128_KEY_SIZE, 0, key); + + return returnValue; +} + +#endif //CC3000_UNENCRYPTED_SMART_CONFIG + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3000/src/socket.c b/src/openmv/src/micropython/drivers/cc3000/src/socket.c new file mode 100755 index 0000000..ddd7e56 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/socket.c @@ -0,0 +1,1182 @@ +/***************************************************************************** +* +* socket.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ + +//***************************************************************************** +// +//! \addtogroup socket_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "hci.h" +#include "socket.h" +#include "evnt_handler.h" +#include "netapp.h" + + + +//Enable this flag if and only if you must comply with BSD socket +//close() function +#ifdef _API_USE_BSD_CLOSE +#define close(sd) closesocket(sd) +#endif + +//Enable this flag if and only if you must comply with BSD socket read() and +//write() functions +#ifdef _API_USE_BSD_READ_WRITE +#define read(sd, buf, len, flags) recv(sd, buf, len, flags) +#define write(sd, buf, len, flags) send(sd, buf, len, flags) +#endif + +#define SOCKET_OPEN_PARAMS_LEN (12) +#define SOCKET_CLOSE_PARAMS_LEN (4) +#define SOCKET_ACCEPT_PARAMS_LEN (4) +#define SOCKET_BIND_PARAMS_LEN (20) +#define SOCKET_LISTEN_PARAMS_LEN (8) +#define SOCKET_GET_HOST_BY_NAME_PARAMS_LEN (9) +#define SOCKET_CONNECT_PARAMS_LEN (20) +#define SOCKET_SELECT_PARAMS_LEN (44) +#define SOCKET_SET_SOCK_OPT_PARAMS_LEN (20) +#define SOCKET_GET_SOCK_OPT_PARAMS_LEN (12) +#define SOCKET_RECV_FROM_PARAMS_LEN (12) +#define SOCKET_SENDTO_PARAMS_LEN (24) +#define SOCKET_MDNS_ADVERTISE_PARAMS_LEN (12) +#define SOCKET_GET_MSS_VALUE_PARAMS_LEN (4) + +// The legnth of arguments for the SEND command: sd + buff_offset + len + flags, +// while size of each parameter is 32 bit - so the total length is 16 bytes; + +#define HCI_CMND_SEND_ARG_LENGTH (16) + + +#define SELECT_TIMEOUT_MIN_MICRO_SECONDS 5000 + +#define HEADERS_SIZE_DATA (SPI_HEADER_SIZE + 5) + +#define SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE (SPI_HEADER_SIZE + SIMPLE_LINK_HCI_CMND_HEADER_SIZE) + +#define MDNS_DEVICE_SERVICE_MAX_LENGTH (32) + + +//***************************************************************************** +// +//! HostFlowControlConsumeBuff +//! +//! @param sd socket descriptor +//! +//! @return 0 in case there are buffers available, +//! -1 in case of bad socket +//! -2 if there are no free buffers present (only when +//! SEND_NON_BLOCKING is enabled) +//! +//! @brief if SEND_NON_BLOCKING not define - block until have free buffer +//! becomes available, else return immediately with correct status +//! regarding the buffers available. +// +//***************************************************************************** +static INT16 HostFlowControlConsumeBuff(INT16 sd) +{ +#ifndef SEND_NON_BLOCKING + /* wait in busy loop */ + do + { + // In case last transmission failed then we will return the last failure + // reason here. + // Note that the buffer will not be allocated in this case + if (tSLInformation.slTransmitDataError != 0) + { + CC3000_EXPORT(errno) = tSLInformation.slTransmitDataError; + tSLInformation.slTransmitDataError = 0; + return CC3000_EXPORT(errno); + } + + if(SOCKET_STATUS_ACTIVE != get_socket_active_status(sd)) + return -1; + } while(0 == tSLInformation.usNumberOfFreeBuffers); + + tSLInformation.usNumberOfFreeBuffers--; + + return 0; +#else + + // In case last transmission failed then we will return the last failure + // reason here. + // Note that the buffer will not be allocated in this case + if (tSLInformation.slTransmitDataError != 0) + { + CC3000_EXPORT(errno) = tSLInformation.slTransmitDataError; + tSLInformation.slTransmitDataError = 0; + return CC3000_EXPORT(errno); + } + if(SOCKET_STATUS_ACTIVE != get_socket_active_status(sd)) + return -1; + + //If there are no available buffers, return -2. It is recommended to use + // select or receive to see if there is any buffer occupied with received data + // If so, call receive() to release the buffer. + if(0 == tSLInformation.usNumberOfFreeBuffers) + { + return -2; + } + else + { + tSLInformation.usNumberOfFreeBuffers--; + return 0; + } +#endif +} + +//***************************************************************************** +// +//! socket +//! +//! @param domain selects the protocol family which will be used for +//! communication. On this version only AF_INET is supported +//! @param type specifies the communication semantics. On this version +//! only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW are supported +//! @param protocol specifies a particular protocol to be used with the +//! socket IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW are +//! supported. +//! +//! @return On success, socket handle that is used for consequent socket +//! operations. On error, -1 is returned. +//! +//! @brief create an endpoint for communication +//! The socket function creates a socket that is bound to a specific +//! transport service provider. This function is called by the +//! application layer to obtain a socket handle. +// +//***************************************************************************** + +INT16 CC3000_EXPORT(socket)(INT32 domain, INT32 type, INT32 protocol) +{ + INT32 ret; + UINT8 *ptr, *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, domain); + args = UINT32_TO_STREAM(args, type); + args = UINT32_TO_STREAM(args, protocol); + + // Initiate a HCI command + hci_command_send(HCI_CMND_SOCKET, ptr, SOCKET_OPEN_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_SOCKET, &ret); + + // Process the event + CC3000_EXPORT(errno) = ret; + + set_socket_active_status(ret, SOCKET_STATUS_ACTIVE); + + return(ret); +} + +//***************************************************************************** +// +//! closesocket +//! +//! @param sd socket handle. +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief The socket function closes a created socket. +// +//***************************************************************************** + +INT32 CC3000_EXPORT(closesocket)(INT32 sd) +{ + INT32 ret; + UINT8 *ptr, *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, sd); + + // Initiate a HCI command + hci_command_send(HCI_CMND_CLOSE_SOCKET, + ptr, SOCKET_CLOSE_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_CLOSE_SOCKET, &ret); + CC3000_EXPORT(errno) = ret; + + // since 'close' call may result in either OK (and then it closed) or error + // mark this socket as invalid + set_socket_active_status(sd, SOCKET_STATUS_INACTIVE); + + return(ret); +} + +//***************************************************************************** +// +//! accept +//! +//! @param[in] sd socket descriptor (handle) +//! @param[out] addr the argument addr is a pointer to a sockaddr structure +//! This structure is filled in with the address of the +//! peer socket, as known to the communications layer. +//! determined. The exact format of the address returned +//! addr is by the socket's address sockaddr. +//! On this version only AF_INET is supported. +//! This argument returns in network order. +//! @param[out] addrlen the addrlen argument is a value-result argument: +//! it should initially contain the size of the structure +//! pointed to by addr. +//! +//! @return For socket in blocking mode: +//! On success, socket handle. on failure negative +//! For socket in non-blocking mode: +//! - On connection establishment, socket handle +//! - On connection pending, SOC_IN_PROGRESS (-2) +//! - On failure, SOC_ERROR (-1) +//! +//! @brief accept a connection on a socket: +//! This function is used with connection-based socket types +//! (SOCK_STREAM). It extracts the first connection request on the +//! queue of pending connections, creates a new connected socket, and +//! returns a new file descriptor referring to that socket. +//! The newly created socket is not in the listening state. +//! The original socket sd is unaffected by this call. +//! The argument sd is a socket that has been created with socket(), +//! bound to a local address with bind(), and is listening for +//! connections after a listen(). The argument addr is a pointer +//! to a sockaddr structure. This structure is filled in with the +//! address of the peer socket, as known to the communications layer. +//! The exact format of the address returned addr is determined by the +//! socket's address family. The addrlen argument is a value-result +//! argument: it should initially contain the size of the structure +//! pointed to by addr, on return it will contain the actual +//! length (in bytes) of the address returned. +//! +//! @sa socket ; bind ; listen +// +//***************************************************************************** + +INT32 CC3000_EXPORT(accept)(INT32 sd, sockaddr *addr, socklen_t *addrlen) +{ + INT32 ret; + UINT8 *ptr, *args; + tBsdReturnParams tAcceptReturnArguments; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + + // Initiate a HCI command + hci_command_send(HCI_CMND_ACCEPT, + ptr, SOCKET_ACCEPT_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_ACCEPT, &tAcceptReturnArguments); + + + // need specify return parameters!!! + memcpy(addr, &tAcceptReturnArguments.tSocketAddress, ASIC_ADDR_LEN); + *addrlen = ASIC_ADDR_LEN; + CC3000_EXPORT(errno) = tAcceptReturnArguments.iStatus; + ret = CC3000_EXPORT(errno); + + // if succeeded, iStatus = new socket descriptor. otherwise - error number + if(M_IS_VALID_SD(ret)) + { + set_socket_active_status(ret, SOCKET_STATUS_ACTIVE); + } + else + { + set_socket_active_status(sd, SOCKET_STATUS_INACTIVE); + } + + return(ret); +} + +//***************************************************************************** +// +//! bind +//! +//! @param[in] sd socket descriptor (handle) +//! @param[out] addr specifies the destination address. On this version +//! only AF_INET is supported. +//! @param[out] addrlen contains the size of the structure pointed to by addr. +//! +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief assign a name to a socket +//! This function gives the socket the local address addr. +//! addr is addrlen bytes long. Traditionally, this is called when a +//! socket is created with socket, it exists in a name space (address +//! family) but has no name assigned. +//! It is necessary to assign a local address before a SOCK_STREAM +//! socket may receive connections. +//! +//! @sa socket ; accept ; listen +// +//***************************************************************************** + +INT32 CC3000_EXPORT(bind)(INT32 sd, const sockaddr *addr, INT32 addrlen) +{ + INT32 ret; + UINT8 *ptr, *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + addrlen = ASIC_ADDR_LEN; + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, 0x00000008); + args = UINT32_TO_STREAM(args, addrlen); + ARRAY_TO_STREAM(args, ((UINT8 *)addr), addrlen); + + // Initiate a HCI command + hci_command_send(HCI_CMND_BIND, + ptr, SOCKET_BIND_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_BIND, &ret); + + CC3000_EXPORT(errno) = ret; + + return(ret); +} + +//***************************************************************************** +// +//! listen +//! +//! @param[in] sd socket descriptor (handle) +//! @param[in] backlog specifies the listen queue depth. On this version +//! backlog is not supported. +//! @return On success, zero is returned. On error, -1 is returned. +//! +//! @brief listen for connections on a socket +//! The willingness to accept incoming connections and a queue +//! limit for incoming connections are specified with listen(), +//! and then the connections are accepted with accept. +//! The listen() call applies only to sockets of type SOCK_STREAM +//! The backlog parameter defines the maximum length the queue of +//! pending connections may grow to. +//! +//! @sa socket ; accept ; bind +//! +//! @note On this version, backlog is not supported +// +//***************************************************************************** + +INT32 CC3000_EXPORT(listen)(INT32 sd, INT32 backlog) +{ + INT32 ret; + UINT8 *ptr, *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, backlog); + + // Initiate a HCI command + hci_command_send(HCI_CMND_LISTEN, + ptr, SOCKET_LISTEN_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_LISTEN, &ret); + CC3000_EXPORT(errno) = ret; + + return(ret); +} + +//***************************************************************************** +// +//! gethostbyname +//! +//! @param[in] hostname host name +//! @param[in] usNameLen name length +//! @param[out] out_ip_addr This parameter is filled in with host IP address. +//! In case that host name is not resolved, +//! out_ip_addr is zero. +//! @return On success, positive is returned. On error, negative is returned +//! +//! @brief Get host IP by name. Obtain the IP Address of machine on network, +//! by its name. +//! +//! @note On this version, only blocking mode is supported. Also note that +//! the function requires DNS server to be configured prior to its usage. +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT16 CC3000_EXPORT(gethostbyname)(CHAR * hostname, UINT16 usNameLen, + UINT32* out_ip_addr) +{ + tBsdGethostbynameParams ret; + UINT8 *ptr, *args; + + CC3000_EXPORT(errno) = EFAIL; + + if (usNameLen > HOSTNAME_MAX_LENGTH) + { + return CC3000_EXPORT(errno); + } + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, 8); + args = UINT32_TO_STREAM(args, usNameLen); + ARRAY_TO_STREAM(args, hostname, usNameLen); + + // Initiate a HCI command + hci_command_send(HCI_CMND_GETHOSTNAME, ptr, SOCKET_GET_HOST_BY_NAME_PARAMS_LEN + + usNameLen - 1); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_EVNT_BSD_GETHOSTBYNAME, &ret); + + CC3000_EXPORT(errno) = ret.retVal; + + (*((INT32*)out_ip_addr)) = ret.outputAddress; + + return CC3000_EXPORT(errno); + +} +#endif + +//***************************************************************************** +// +//! connect +//! +//! @param[in] sd socket descriptor (handle) +//! @param[in] addr specifies the destination addr. On this version +//! only AF_INET is supported. +//! @param[out] addrlen contains the size of the structure pointed to by addr +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief initiate a connection on a socket +//! Function connects the socket referred to by the socket descriptor +//! sd, to the address specified by addr. The addrlen argument +//! specifies the size of addr. The format of the address in addr is +//! determined by the address space of the socket. If it is of type +//! SOCK_DGRAM, this call specifies the peer with which the socket is +//! to be associated; this address is that to which datagrams are to be +//! sent, and the only address from which datagrams are to be received. +//! If the socket is of type SOCK_STREAM, this call attempts to make a +//! connection to another socket. The other socket is specified by +//! address, which is an address in the communications space of the +//! socket. Note that the function implements only blocking behavior +//! thus the caller will be waiting either for the connection +//! establishment or for the connection establishment failure. +//! +//! @sa socket +// +//***************************************************************************** + +INT32 CC3000_EXPORT(connect)(INT32 sd, const sockaddr *addr, INT32 addrlen) +{ + INT32 ret; + UINT8 *ptr, *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE); + addrlen = 8; + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, 0x00000008); + args = UINT32_TO_STREAM(args, addrlen); + ARRAY_TO_STREAM(args, ((UINT8 *)addr), addrlen); + + // Initiate a HCI command + hci_command_send(HCI_CMND_CONNECT, + ptr, SOCKET_CONNECT_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_CONNECT, &ret); + + CC3000_EXPORT(errno) = ret; + + return((INT32)ret); +} + + +//***************************************************************************** +// +//! select +//! +//! @param[in] nfds the highest-numbered file descriptor in any of the +//! three sets, plus 1. +//! @param[out] writesds socket descriptors list for write monitoring +//! @param[out] readsds socket descriptors list for read monitoring +//! @param[out] exceptsds socket descriptors list for exception monitoring +//! @param[in] timeout is an upper bound on the amount of time elapsed +//! before select() returns. Null means infinity +//! timeout. The minimum timeout is 5 milliseconds, +//! less than 5 milliseconds will be set +//! automatically to 5 milliseconds. +//! @return On success, select() returns the number of file descriptors +//! contained in the three returned descriptor sets (that is, the +//! total number of bits that are set in readfds, writefds, +//! exceptfds) which may be zero if the timeout expires before +//! anything interesting happens. +//! On error, -1 is returned. +//! *readsds - return the sockets on which Read request will +//! return without delay with valid data. +//! *writesds - return the sockets on which Write request +//! will return without delay. +//! *exceptsds - return the sockets which closed recently. +//! +//! @brief Monitor socket activity +//! Select allow a program to monitor multiple file descriptors, +//! waiting until one or more of the file descriptors become +//! "ready" for some class of I/O operation +//! +//! @Note If the timeout value set to less than 5ms it will automatically set +//! to 5ms to prevent overload of the system +//! +//! @sa socket +// +//***************************************************************************** + +INT16 CC3000_EXPORT(select)(INT32 nfds, fd_set *readsds, fd_set *writesds, fd_set *exceptsds, +struct cc3000_timeval *timeout) +{ + UINT8 *ptr, *args; + tBsdSelectRecvParams tParams; + UINT32 is_blocking; + + if( timeout == NULL) + { + is_blocking = 1; /* blocking , infinity timeout */ + } + else + { + is_blocking = 0; /* no blocking, timeout */ + } + + // Fill in HCI packet structure + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, nfds); + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, is_blocking); + args = UINT32_TO_STREAM(args, ((readsds) ? *(UINT32*)readsds : 0)); + args = UINT32_TO_STREAM(args, ((writesds) ? *(UINT32*)writesds : 0)); + args = UINT32_TO_STREAM(args, ((exceptsds) ? *(UINT32*)exceptsds : 0)); + + if (timeout) + { + if ( 0 == timeout->tv_sec && timeout->tv_usec < + SELECT_TIMEOUT_MIN_MICRO_SECONDS) + { + timeout->tv_usec = SELECT_TIMEOUT_MIN_MICRO_SECONDS; + } + args = UINT32_TO_STREAM(args, timeout->tv_sec); + args = UINT32_TO_STREAM(args, timeout->tv_usec); + } + + // Initiate a HCI command + hci_command_send(HCI_CMND_BSD_SELECT, ptr, SOCKET_SELECT_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_EVNT_SELECT, &tParams); + + // Update actually read FD + if (tParams.iStatus >= 0) + { + if (readsds) + { + memcpy(readsds, &tParams.uiRdfd, sizeof(tParams.uiRdfd)); + } + + if (writesds) + { + memcpy(writesds, &tParams.uiWrfd, sizeof(tParams.uiWrfd)); + } + + if (exceptsds) + { + memcpy(exceptsds, &tParams.uiExfd, sizeof(tParams.uiExfd)); + } + + return(tParams.iStatus); + + } + else + { + CC3000_EXPORT(errno) = tParams.iStatus; + return(-1); + } +} + +//***************************************************************************** +// +//! setsockopt +//! +//! @param[in] sd socket handle +//! @param[in] level defines the protocol level for this option +//! @param[in] optname defines the option name to Interrogate +//! @param[in] optval specifies a value for the option +//! @param[in] optlen specifies the length of the option value +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief set socket options +//! This function manipulate the options associated with a socket. +//! Options may exist at multiple protocol levels; they are always +//! present at the uppermost socket level. +//! When manipulating socket options the level at which the option +//! resides and the name of the option must be specified. +//! To manipulate options at the socket level, level is specified as +//! SOL_SOCKET. To manipulate options at any other level the protocol +//! number of the appropriate protocol controlling the option is +//! supplied. For example, to indicate that an option is to be +//! interpreted by the TCP protocol, level should be set to the +//! protocol number of TCP; +//! The parameters optval and optlen are used to access optval - +//! use for setsockopt(). For getsockopt() they identify a buffer +//! in which the value for the requested option(s) are to +//! be returned. For getsockopt(), optlen is a value-result +//! parameter, initially containing the size of the buffer +//! pointed to by option_value, and modified on return to +//! indicate the actual size of the value returned. If no option +//! value is to be supplied or returned, option_value may be NULL. +//! +//! @Note On this version the following two socket options are enabled: +//! The only protocol level supported in this version +//! is SOL_SOCKET (level). +//! 1. SOCKOPT_RECV_TIMEOUT (optname) +//! SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout +//! in milliseconds. +//! In that case optval should be pointer to UINT32. +//! 2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on +//! or off. +//! In that case optval should be SOCK_ON or SOCK_OFF (optval). +//! +//! @sa getsockopt +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT16 CC3000_EXPORT(setsockopt)(INT32 sd, INT32 level, INT32 optname, const void *optval, + socklen_t optlen) +{ + INT32 ret; + UINT8 *ptr, *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, level); + args = UINT32_TO_STREAM(args, optname); + args = UINT32_TO_STREAM(args, 0x00000008); + args = UINT32_TO_STREAM(args, optlen); + ARRAY_TO_STREAM(args, ((UINT8 *)optval), optlen); + + // Initiate a HCI command + hci_command_send(HCI_CMND_SETSOCKOPT, + ptr, SOCKET_SET_SOCK_OPT_PARAMS_LEN + optlen); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_SETSOCKOPT, &ret); + + if (ret >= 0) + { + return (0); + } + else + { + CC3000_EXPORT(errno) = ret; + return ret; + } +} +#endif + +//***************************************************************************** +// +//! getsockopt +//! +//! @param[in] sd socket handle +//! @param[in] level defines the protocol level for this option +//! @param[in] optname defines the option name to Interrogate +//! @param[out] optval specifies a value for the option +//! @param[out] optlen specifies the length of the option value +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief set socket options +//! This function manipulate the options associated with a socket. +//! Options may exist at multiple protocol levels; they are always +//! present at the uppermost socket level. +//! When manipulating socket options the level at which the option +//! resides and the name of the option must be specified. +//! To manipulate options at the socket level, level is specified as +//! SOL_SOCKET. To manipulate options at any other level the protocol +//! number of the appropriate protocol controlling the option is +//! supplied. For example, to indicate that an option is to be +//! interpreted by the TCP protocol, level should be set to the +//! protocol number of TCP; +//! The parameters optval and optlen are used to access optval - +//! use for setsockopt(). For getsockopt() they identify a buffer +//! in which the value for the requested option(s) are to +//! be returned. For getsockopt(), optlen is a value-result +//! parameter, initially containing the size of the buffer +//! pointed to by option_value, and modified on return to +//! indicate the actual size of the value returned. If no option +//! value is to be supplied or returned, option_value may be NULL. +//! +//! @Note On this version the following two socket options are enabled: +//! The only protocol level supported in this version +//! is SOL_SOCKET (level). +//! 1. SOCKOPT_RECV_TIMEOUT (optname) +//! SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout +//! in milliseconds. +//! In that case optval should be pointer to UINT32. +//! 2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on +//! or off. +//! In that case optval should be SOCK_ON or SOCK_OFF (optval). +//! +//! @sa setsockopt +// +//***************************************************************************** + +INT16 CC3000_EXPORT(getsockopt) (INT32 sd, INT32 level, INT32 optname, void *optval, socklen_t *optlen) +{ + UINT8 *ptr, *args; + tBsdGetSockOptReturnParams tRetParams; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, level); + args = UINT32_TO_STREAM(args, optname); + + // Initiate a HCI command + hci_command_send(HCI_CMND_GETSOCKOPT, + ptr, SOCKET_GET_SOCK_OPT_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_CMND_GETSOCKOPT, &tRetParams); + + if (((INT8)tRetParams.iStatus) >= 0) + { + *optlen = 4; + memcpy(optval, tRetParams.ucOptValue, 4); + return (0); + } + else + { + CC3000_EXPORT(errno) = tRetParams.iStatus; + return CC3000_EXPORT(errno); + } +} + +//***************************************************************************** +// +//! simple_link_recv +//! +//! @param sd socket handle +//! @param buf read buffer +//! @param len buffer length +//! @param flags indicates blocking or non-blocking operation +//! @param from pointer to an address structure indicating source address +//! @param fromlen source address structure size +//! +//! @return Return the number of bytes received, or -1 if an error +//! occurred +//! +//! @brief Read data from socket +//! Return the length of the message on successful completion. +//! If a message is too long to fit in the supplied buffer, +//! excess bytes may be discarded depending on the type of +//! socket the message is received from +// +//***************************************************************************** +static INT16 simple_link_recv(INT32 sd, void *buf, INT32 len, INT32 flags, sockaddr *from, + socklen_t *fromlen, INT32 opcode) +{ + UINT8 *ptr, *args; + tBsdReadReturnParams tSocketReadEvent; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, len); + args = UINT32_TO_STREAM(args, flags); + + // Generate the read command, and wait for the + hci_command_send(opcode, ptr, SOCKET_RECV_FROM_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(opcode, &tSocketReadEvent); + + // In case the number of bytes is more then zero - read data + if (tSocketReadEvent.iNumberOfBytes > 0) + { + // Wait for the data in a synchronous way. Here we assume that the bug is + // big enough to store also parameters of receive from too.... + SimpleLinkWaitData(buf, (UINT8 *)from, (UINT8 *)fromlen); + } + + CC3000_EXPORT(errno) = tSocketReadEvent.iNumberOfBytes; + + return(tSocketReadEvent.iNumberOfBytes); +} + +//***************************************************************************** +// +//! recv +//! +//! @param[in] sd socket handle +//! @param[out] buf Points to the buffer where the message should be stored +//! @param[in] len Specifies the length in bytes of the buffer pointed to +//! by the buffer argument. +//! @param[in] flags Specifies the type of message reception. +//! On this version, this parameter is not supported. +//! +//! @return Return the number of bytes received, or -1 if an error +//! occurred +//! +//! @brief function receives a message from a connection-mode socket +//! +//! @sa recvfrom +//! +//! @Note On this version, only blocking mode is supported. +// +//***************************************************************************** + +INT16 CC3000_EXPORT(recv)(INT32 sd, void *buf, INT32 len, INT32 flags) +{ + return(simple_link_recv(sd, buf, len, flags, NULL, NULL, HCI_CMND_RECV)); +} + +//***************************************************************************** +// +//! recvfrom +//! +//! @param[in] sd socket handle +//! @param[out] buf Points to the buffer where the message should be stored +//! @param[in] len Specifies the length in bytes of the buffer pointed to +//! by the buffer argument. +//! @param[in] flags Specifies the type of message reception. +//! On this version, this parameter is not supported. +//! @param[in] from pointer to an address structure indicating the source +//! address: sockaddr. On this version only AF_INET is +//! supported. +//! @param[in] fromlen source address tructure size +//! +//! @return Return the number of bytes received, or -1 if an error +//! occurred +//! +//! @brief read data from socket +//! function receives a message from a connection-mode or +//! connectionless-mode socket. Note that raw sockets are not +//! supported. +//! +//! @sa recv +//! +//! @Note On this version, only blocking mode is supported. +// +//***************************************************************************** +INT16 CC3000_EXPORT(recvfrom)(INT32 sd, void *buf, INT32 len, INT32 flags, sockaddr *from, + socklen_t *fromlen) +{ + return(simple_link_recv(sd, buf, len, flags, from, fromlen, + HCI_CMND_RECVFROM)); +} + +//***************************************************************************** +// +//! simple_link_send +//! +//! @param sd socket handle +//! @param buf write buffer +//! @param len buffer length +//! @param flags On this version, this parameter is not supported +//! @param to pointer to an address structure indicating destination +//! address +//! @param tolen destination address structure size +//! +//! @return Return the number of bytes transmitted, or -1 if an error +//! occurred, or -2 in case there are no free buffers available +//! (only when SEND_NON_BLOCKING is enabled) +//! +//! @brief This function is used to transmit a message to another +//! socket +// +//***************************************************************************** +static INT16 simple_link_send(INT32 sd, const void *buf, INT32 len, INT32 flags, + const sockaddr *to, INT32 tolen, INT32 opcode) +{ + UINT8 uArgSize=0, addrlen; + UINT8 *ptr, *pDataPtr=0, *args; + UINT32 addr_offset=0; + INT16 res; + tBsdReadReturnParams tSocketSendEvent; + + // Check the bsd_arguments + if (0 != (res = HostFlowControlConsumeBuff(sd))) + { + return res; + } + + //Update the number of sent packets + tSLInformation.NumberOfSentPackets++; + + // Allocate a buffer and construct a packet and send it over spi + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_DATA); + + // Update the offset of data and parameters according to the command + switch(opcode) + { + case HCI_CMND_SENDTO: + { + addr_offset = len + sizeof(len) + sizeof(len); + addrlen = 8; + uArgSize = SOCKET_SENDTO_PARAMS_LEN; + pDataPtr = ptr + HEADERS_SIZE_DATA + SOCKET_SENDTO_PARAMS_LEN; + break; + } + + case HCI_CMND_SEND: + { + tolen = 0; + to = NULL; + uArgSize = HCI_CMND_SEND_ARG_LENGTH; + pDataPtr = ptr + HEADERS_SIZE_DATA + HCI_CMND_SEND_ARG_LENGTH; + break; + } + + default: + { + break; + } + } + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + args = UINT32_TO_STREAM(args, uArgSize - sizeof(sd)); + args = UINT32_TO_STREAM(args, len); + args = UINT32_TO_STREAM(args, flags); + + if (opcode == HCI_CMND_SENDTO) + { + args = UINT32_TO_STREAM(args, addr_offset); + args = UINT32_TO_STREAM(args, addrlen); + } + + // Copy the data received from user into the TX Buffer + ARRAY_TO_STREAM(pDataPtr, ((UINT8 *)buf), len); + + // In case we are using SendTo, copy the to parameters + if (opcode == HCI_CMND_SENDTO) + { + ARRAY_TO_STREAM(pDataPtr, ((UINT8 *)to), tolen); + } + + // Initiate a HCI command + hci_data_send(opcode, ptr, uArgSize, len,(UINT8*)to, tolen); + + if (opcode == HCI_CMND_SENDTO) + SimpleLinkWaitEvent(HCI_EVNT_SENDTO, &tSocketSendEvent); + else + SimpleLinkWaitEvent(HCI_EVNT_SEND, &tSocketSendEvent); + + return (len); +} + + +//***************************************************************************** +// +//! send +//! +//! @param sd socket handle +//! @param buf Points to a buffer containing the message to be sent +//! @param len message size in bytes +//! @param flags On this version, this parameter is not supported +//! +//! @return Return the number of bytes transmitted, or -1 if an +//! error occurred +//! +//! @brief Write data to TCP socket +//! This function is used to transmit a message to another +//! socket. +//! +//! @Note On this version, only blocking mode is supported. +//! +//! @sa sendto +// +//***************************************************************************** + +INT16 CC3000_EXPORT(send)(INT32 sd, const void *buf, INT32 len, INT32 flags) +{ + return(simple_link_send(sd, buf, len, flags, NULL, 0, HCI_CMND_SEND)); +} + +//***************************************************************************** +// +//! sendto +//! +//! @param sd socket handle +//! @param buf Points to a buffer containing the message to be sent +//! @param len message size in bytes +//! @param flags On this version, this parameter is not supported +//! @param to pointer to an address structure indicating the destination +//! address: sockaddr. On this version only AF_INET is +//! supported. +//! @param tolen destination address structure size +//! +//! @return Return the number of bytes transmitted, or -1 if an +//! error occurred +//! +//! @brief Write data to TCP socket +//! This function is used to transmit a message to another +//! socket. +//! +//! @Note On this version, only blocking mode is supported. +//! +//! @sa send +// +//***************************************************************************** + +INT16 CC3000_EXPORT(sendto)(INT32 sd, const void *buf, INT32 len, INT32 flags, const sockaddr *to, + socklen_t tolen) +{ + return(simple_link_send(sd, buf, len, flags, to, tolen, HCI_CMND_SENDTO)); +} + +//***************************************************************************** +// +//! mdnsAdvertiser +//! +//! @param[in] mdnsEnabled flag to enable/disable the mDNS feature +//! @param[in] deviceServiceName Service name as part of the published +//! canonical domain name +//! @param[in] deviceServiceNameLength Length of the service name - up to 32 chars +//! +//! +//! @return On success, zero is returned, return SOC_ERROR if socket was not +//! opened successfully, or if an error occurred. +//! +//! @brief Set CC3000 in mDNS advertiser mode in order to advertise itself. +// +//***************************************************************************** + +INT16 CC3000_EXPORT(mdnsAdvertiser)(UINT16 mdnsEnabled, CHAR * deviceServiceName, UINT16 deviceServiceNameLength) +{ + INT8 ret; + UINT8 *pTxBuffer, *pArgs; + + if (deviceServiceNameLength > MDNS_DEVICE_SERVICE_MAX_LENGTH) + { + return EFAIL; + } + + pTxBuffer = tSLInformation.pucTxCommandBuffer; + pArgs = (pTxBuffer + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE); + + // Fill in HCI packet structure + pArgs = UINT32_TO_STREAM(pArgs, mdnsEnabled); + pArgs = UINT32_TO_STREAM(pArgs, 8); + pArgs = UINT32_TO_STREAM(pArgs, deviceServiceNameLength); + ARRAY_TO_STREAM(pArgs, deviceServiceName, deviceServiceNameLength); + + // Initiate a HCI command + hci_command_send(HCI_CMND_MDNS_ADVERTISE, pTxBuffer, SOCKET_MDNS_ADVERTISE_PARAMS_LEN + deviceServiceNameLength); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_EVNT_MDNS_ADVERTISE, &ret); + + return ret; + +} + + +//***************************************************************************** +// +//! getmssvalue +//! +//! @param[in] sd socket descriptor +//! +//! @return On success, returns the MSS value of a TCP connection +//! +//! @brief Returns the MSS value of a TCP connection according to the socket descriptor +// +//***************************************************************************** +UINT16 CC3000_EXPORT(getmssvalue) (INT32 sd) +{ + UINT8 *ptr, *args; + UINT16 ret; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, sd); + + // Initiate a HCI command + hci_command_send(HCI_CMND_GETMSSVALUE, ptr, SOCKET_GET_MSS_VALUE_PARAMS_LEN); + + // Since we are in blocking state - wait for event complete + SimpleLinkWaitEvent(HCI_EVNT_GETMSSVALUE, &ret); + + return ret; +} diff --git a/src/openmv/src/micropython/drivers/cc3000/src/wlan.c b/src/openmv/src/micropython/drivers/cc3000/src/wlan.c new file mode 100755 index 0000000..6385937 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3000/src/wlan.c @@ -0,0 +1,1252 @@ +/***************************************************************************** +* +* wlan.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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. +* +*****************************************************************************/ + +//***************************************************************************** +// +//! \addtogroup wlan_api +//! @{ +// +//***************************************************************************** + +#include +#include "wlan.h" +#include "hci.h" +#include "ccspi.h" +#include "socket.h" +#include "nvmem.h" +#include "security.h" +#include "evnt_handler.h" + + +volatile sSimplLinkInformation tSLInformation; + +#define SMART_CONFIG_PROFILE_SIZE 67 // 67 = 32 (max ssid) + 32 (max key) + 1 (SSID length) + 1 (security type) + 1 (key length) + +#ifndef CC3000_UNENCRYPTED_SMART_CONFIG +UINT8 key[AES128_KEY_SIZE]; +UINT8 profileArray[SMART_CONFIG_PROFILE_SIZE]; +#endif //CC3000_UNENCRYPTED_SMART_CONFIG + +/* patches type */ +#define PATCHES_HOST_TYPE_WLAN_DRIVER 0x01 +#define PATCHES_HOST_TYPE_WLAN_FW 0x02 +#define PATCHES_HOST_TYPE_BOOTLOADER 0x03 + +#define SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE (16) +#define SL_SIMPLE_CONFIG_PREFIX_LENGTH (3) +#define ETH_ALEN (6) +#define MAXIMAL_SSID_LENGTH (32) + +#define SL_PATCHES_REQUEST_DEFAULT (0) +#define SL_PATCHES_REQUEST_FORCE_HOST (1) +#define SL_PATCHES_REQUEST_FORCE_NONE (2) + + +#define WLAN_SEC_UNSEC (0) +#define WLAN_SEC_WEP (1) +#define WLAN_SEC_WPA (2) +#define WLAN_SEC_WPA2 (3) + + +#define WLAN_SL_INIT_START_PARAMS_LEN (1) +#define WLAN_PATCH_PARAMS_LENGTH (8) +#define WLAN_SET_CONNECTION_POLICY_PARAMS_LEN (12) +#define WLAN_DEL_PROFILE_PARAMS_LEN (4) +#define WLAN_SET_MASK_PARAMS_LEN (4) +#define WLAN_SET_SCAN_PARAMS_LEN (100) +#define WLAN_GET_SCAN_RESULTS_PARAMS_LEN (4) +#define WLAN_ADD_PROFILE_NOSEC_PARAM_LEN (24) +#define WLAN_ADD_PROFILE_WEP_PARAM_LEN (36) +#define WLAN_ADD_PROFILE_WPA_PARAM_LEN (44) +#define WLAN_CONNECT_PARAM_LEN (29) +#define WLAN_SMART_CONFIG_START_PARAMS_LEN (4) + + + + +//***************************************************************************** +// +//! SimpleLink_Init_Start +//! +//! @param usPatchesAvailableAtHost flag to indicate if patches available +//! from host or from EEPROM. Due to the +//! fact the patches are burn to the EEPROM +//! using the patch programmer utility, the +//! patches will be available from the EEPROM +//! and not from the host. +//! +//! @return none +//! +//! @brief Send HCI_CMND_SIMPLE_LINK_START to CC3000 +// +//***************************************************************************** +static void SimpleLink_Init_Start(UINT16 usPatchesAvailableAtHost) +{ + UINT8 *ptr; + UINT8 *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (UINT8 *)(ptr + HEADERS_SIZE_CMD); + + UINT8_TO_STREAM(args, ((usPatchesAvailableAtHost) ? SL_PATCHES_REQUEST_FORCE_NONE : SL_PATCHES_REQUEST_DEFAULT)); + + // IRQ Line asserted - send HCI_CMND_SIMPLE_LINK_START to CC3000 + hci_command_send(HCI_CMND_SIMPLE_LINK_START, ptr, WLAN_SL_INIT_START_PARAMS_LEN); + + SimpleLinkWaitEvent(HCI_CMND_SIMPLE_LINK_START, 0); +} + + + +//***************************************************************************** +// +//! wlan_init +//! +//! @param sWlanCB Asynchronous events callback. +//! 0 no event call back. +//! -call back parameters: +//! 1) event_type: HCI_EVNT_WLAN_UNSOL_CONNECT connect event, +//! HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event, +//! HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE config done, +//! HCI_EVNT_WLAN_UNSOL_DHCP dhcp report, +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report OR +//! HCI_EVNT_WLAN_KEEPALIVE keepalive. +//! 2) data: pointer to extra data that received by the event +//! (NULL no data). +//! 3) length: data length. +//! -Events with extra data: +//! HCI_EVNT_WLAN_UNSOL_DHCP: 4 bytes IP, 4 bytes Mask, +//! 4 bytes default gateway, 4 bytes DHCP server and 4 bytes +//! for DNS server. +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT: 4 bytes Packets sent, +//! 4 bytes Packets received, 4 bytes Min round time, +//! 4 bytes Max round time and 4 bytes for Avg round time. +//! +//! @param sFWPatches 0 no patch or pointer to FW patches +//! @param sDriverPatches 0 no patch or pointer to driver patches +//! @param sBootLoaderPatches 0 no patch or pointer to bootloader patches +//! @param sReadWlanInterruptPin init callback. the callback read wlan +//! interrupt status. +//! @param sWlanInterruptEnable init callback. the callback enable wlan +//! interrupt. +//! @param sWlanInterruptDisable init callback. the callback disable wlan +//! interrupt. +//! @param sWriteWlanPin init callback. the callback write value +//! to device pin. +//! +//! @return none +//! +//! @sa wlan_set_event_mask , wlan_start , wlan_stop +//! +//! @brief Initialize wlan driver +//! +//! @warning This function must be called before ANY other wlan driver function +// +//***************************************************************************** + +void wlan_init( tWlanCB sWlanCB, + tFWPatches sFWPatches, + tDriverPatches sDriverPatches, + tBootLoaderPatches sBootLoaderPatches, + tWlanReadInteruptPin sReadWlanInterruptPin, + tWlanInterruptEnable sWlanInterruptEnable, + tWlanInterruptDisable sWlanInterruptDisable, + tWriteWlanPin sWriteWlanPin) +{ + + tSLInformation.sFWPatches = sFWPatches; + tSLInformation.sDriverPatches = sDriverPatches; + tSLInformation.sBootLoaderPatches = sBootLoaderPatches; + + // init io callback + tSLInformation.ReadWlanInterruptPin = sReadWlanInterruptPin; + tSLInformation.WlanInterruptEnable = sWlanInterruptEnable; + tSLInformation.WlanInterruptDisable = sWlanInterruptDisable; + tSLInformation.WriteWlanPin = sWriteWlanPin; + + //init asynchronous events callback + tSLInformation.sWlanCB= sWlanCB; + + // By default TX Complete events are routed to host too + tSLInformation.InformHostOnTxComplete = 1; +} + +//***************************************************************************** +// +//! SpiReceiveHandler +//! +//! @param pvBuffer - pointer to the received data buffer +//! The function triggers Received event/data processing +//! +//! @param Pointer to the received data +//! @return none +//! +//! @brief The function triggers Received event/data processing. It is +//! called from the SPI library to receive the data +// +//***************************************************************************** +void SpiReceiveHandler(void *pvBuffer) +{ + tSLInformation.usEventOrDataReceived = 1; + tSLInformation.pucReceivedData = (UINT8 *)pvBuffer; + + hci_unsolicited_event_handler(); +} + + +//***************************************************************************** +// +//! wlan_start +//! +//! @param usPatchesAvailableAtHost - flag to indicate if patches available +//! from host or from EEPROM. Due to the +//! fact the patches are burn to the EEPROM +//! using the patch programmer utility, the +//! patches will be available from the EEPROM +//! and not from the host. +//! +//! @return none +//! +//! @brief Start WLAN device. This function asserts the enable pin of +//! the device (WLAN_EN), starting the HW initialization process. +//! The function blocked until device Initialization is completed. +//! Function also configure patches (FW, driver or bootloader) +//! and calls appropriate device callbacks. +//! +//! @Note Prior calling the function wlan_init shall be called. +//! @Warning This function must be called after wlan_init and before any +//! other wlan API +//! @sa wlan_init , wlan_stop +//! +// +//***************************************************************************** +#define TIMEOUT (500000) + +int wlan_start(UINT16 usPatchesAvailableAtHost) +{ + + UINT32 ulSpiIRQState; + UINT32 wlan_timeout; + + tSLInformation.NumberOfSentPackets = 0; + tSLInformation.NumberOfReleasedPackets = 0; + tSLInformation.usRxEventOpcode = 0; + tSLInformation.usNumberOfFreeBuffers = 0; + tSLInformation.usSlBufferLength = 0; + tSLInformation.usBufferSize = 0; + tSLInformation.usRxDataPending = 0; + tSLInformation.slTransmitDataError = 0; + tSLInformation.usEventOrDataReceived = 0; + tSLInformation.pucReceivedData = 0; + + // Allocate the memory for the RX/TX data transactions + tSLInformation.pucTxCommandBuffer = (UINT8 *)wlan_tx_buffer; + + // init spi + SpiOpen(SpiReceiveHandler); + + // Check the IRQ line + ulSpiIRQState = tSLInformation.ReadWlanInterruptPin(); + + // Chip enable: toggle WLAN EN line + tSLInformation.WriteWlanPin( WLAN_ENABLE ); + + wlan_timeout = TIMEOUT; + if (ulSpiIRQState) { + // wait till the IRQ line goes low + while(tSLInformation.ReadWlanInterruptPin() != 0 && --wlan_timeout) + { + } + } + else + { + // wait till the IRQ line goes high and than low + while(tSLInformation.ReadWlanInterruptPin() == 0 && --wlan_timeout) + { + } + + if (wlan_timeout == 0) { + return -1; + } + + wlan_timeout = TIMEOUT; + while(tSLInformation.ReadWlanInterruptPin() != 0 && --wlan_timeout) + { + } + } + + if (wlan_timeout ==0) { + return -1; + } + + SimpleLink_Init_Start(usPatchesAvailableAtHost); + + // Read Buffer's size and finish + hci_command_send(HCI_CMND_READ_BUFFER_SIZE, tSLInformation.pucTxCommandBuffer, 0); + SimpleLinkWaitEvent(HCI_CMND_READ_BUFFER_SIZE, 0); + + return 0; +} + + +//***************************************************************************** +// +//! wlan_stop +//! +//! @param none +//! +//! @return none +//! +//! @brief Stop WLAN device by putting it into reset state. +//! +//! @sa wlan_start +// +//***************************************************************************** + +void wlan_stop(void) +{ + // Chip disable + tSLInformation.WriteWlanPin( WLAN_DISABLE ); + + // Wait till IRQ line goes high... + while(tSLInformation.ReadWlanInterruptPin() == 0) + { + } + + // Free the used by WLAN Driver memory + if (tSLInformation.pucTxCommandBuffer) + { + tSLInformation.pucTxCommandBuffer = 0; + } + + SpiClose(); +} + + +//***************************************************************************** +// +//! wlan_connect +//! +//! @param sec_type security options: +//! WLAN_SEC_UNSEC, +//! WLAN_SEC_WEP (ASCII support only), +//! WLAN_SEC_WPA or WLAN_SEC_WPA2 +//! @param ssid up to 32 bytes and is ASCII SSID of the AP +//! @param ssid_len length of the SSID +//! @param bssid 6 bytes specified the AP bssid +//! @param key up to 32 bytes specified the AP security key +//! @param key_len key length +//! +//! @return On success, zero is returned. On error, negative is returned. +//! Note that even though a zero is returned on success to trigger +//! connection operation, it does not mean that CCC3000 is already +//! connected. An asynchronous "Connected" event is generated when +//! actual association process finishes and CC3000 is connected to +//! the AP. If DHCP is set, An asynchronous "DHCP" event is +//! generated when DHCP process is finish. +//! +//! +//! @brief Connect to AP +//! @warning Please Note that when connection to AP configured with security +//! type WEP, please confirm that the key is set as ASCII and not +//! as HEX. +//! @sa wlan_disconnect +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 wlan_connect(UINT32 ulSecType, CHAR *ssid, INT32 ssid_len, + UINT8 *bssid, UINT8 *key, INT32 key_len) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in command buffer + args = UINT32_TO_STREAM(args, 0x0000001c); + args = UINT32_TO_STREAM(args, ssid_len); + args = UINT32_TO_STREAM(args, ulSecType); + args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); + args = UINT32_TO_STREAM(args, key_len); + args = UINT16_TO_STREAM(args, 0); + + // padding shall be zeroed + if(bssid) + { + ARRAY_TO_STREAM(args, bssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + + ARRAY_TO_STREAM(args, ssid, ssid_len); + + if(key_len && key) + { + ARRAY_TO_STREAM(args, key, key_len); + } + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + + ssid_len + key_len - 1); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret); + CC3000_EXPORT(errno) = ret; + + return(ret); +} +#else +INT32 wlan_connect(CHAR *ssid, INT32 ssid_len) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in command buffer + args = UINT32_TO_STREAM(args, 0x0000001c); + args = UINT32_TO_STREAM(args, ssid_len); + args = UINT32_TO_STREAM(args, 0); + args = UINT32_TO_STREAM(args, 0x00000010 + ssid_len); + args = UINT32_TO_STREAM(args, 0); + args = UINT16_TO_STREAM(args, 0); + + // padding shall be zeroed + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + ARRAY_TO_STREAM(args, ssid, ssid_len); + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_CONNECT, ptr, WLAN_CONNECT_PARAM_LEN + + ssid_len - 1); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_CONNECT, &ret); + CC3000_EXPORT(errno) = ret; + + return(ret); +} +#endif + +//***************************************************************************** +// +//! wlan_disconnect +//! +//! @return 0 disconnected done, other CC3000 already disconnected +//! +//! @brief Disconnect connection from AP. +//! +//! @sa wlan_connect +// +//***************************************************************************** + +INT32 wlan_disconnect() +{ + INT32 ret; + UINT8 *ptr; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + + hci_command_send(HCI_CMND_WLAN_DISCONNECT, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_DISCONNECT, &ret); + CC3000_EXPORT(errno) = ret; + + return(ret); +} + +//***************************************************************************** +// +//! wlan_ioctl_set_connection_policy +//! +//! @param should_connect_to_open_ap enable(1), disable(0) connect to any +//! available AP. This parameter corresponds to the configuration of +//! item # 3 in the brief description. +//! @param should_use_fast_connect enable(1), disable(0). if enabled, tries +//! to connect to the last connected AP. This parameter corresponds +//! to the configuration of item # 1 in the brief description. +//! @param auto_start enable(1), disable(0) auto connect +//! after reset and periodically reconnect if needed. This +//! configuration configures option 2 in the above description. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief When auto is enabled, the device tries to connect according +//! the following policy: +//! 1) If fast connect is enabled and last connection is valid, +//! the device will try to connect to it without the scanning +//! procedure (fast). The last connection will be marked as +//! invalid, due to adding/removing profile. +//! 2) If profile exists, the device will try to connect it +//! (Up to seven profiles). +//! 3) If fast and profiles are not found, and open mode is +//! enabled, the device will try to connect to any AP. +//! * Note that the policy settings are stored in the CC3000 NVMEM. +//! +//! @sa wlan_add_profile , wlan_ioctl_del_profile +// +//***************************************************************************** + +INT32 wlan_ioctl_set_connection_policy(UINT32 should_connect_to_open_ap, + UINT32 ulShouldUseFastConnect, + UINT32 ulUseProfiles) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (UINT8 *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, should_connect_to_open_ap); + args = UINT32_TO_STREAM(args, ulShouldUseFastConnect); + args = UINT32_TO_STREAM(args, ulUseProfiles); + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, + ptr, WLAN_SET_CONNECTION_POLICY_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_add_profile +//! +//! @param ulSecType WLAN_SEC_UNSEC,WLAN_SEC_WEP,WLAN_SEC_WPA,WLAN_SEC_WPA2 +//! @param ucSsid ssid SSID up to 32 bytes +//! @param ulSsidLen ssid length +//! @param ucBssid bssid 6 bytes +//! @param ulPriority ulPriority profile priority. Lowest priority:0. +//! Important Note: Smartconfig process (in unencrypted mode) +//! stores the profile internally with priority 1, so changing +//! priorities when adding new profiles should be done with extra care +//! @param ulPairwiseCipher_Or_TxKeyLen key length for WEP security +//! @param ulGroupCipher_TxKeyIndex key index +//! @param ulKeyMgmt KEY management +//! @param ucPf_OrKey security key +//! @param ulPassPhraseLen security key length for WPA\WPA2 +//! +//! @return On success, index (1-7) of the stored profile is returned. +//! On error, -1 is returned. +//! +//! @brief When auto start is enabled, the device connects to +//! station from the profiles table. Up to 7 profiles are supported. +//! If several profiles configured the device choose the highest +//! priority profile, within each priority group, device will choose +//! profile based on security policy, signal strength, etc +//! parameters. All the profiles are stored in CC3000 NVMEM. +//! +//! @sa wlan_ioctl_del_profile +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 wlan_add_profile(UINT32 ulSecType, + UINT8* ucSsid, + UINT32 ulSsidLen, + UINT8 *ucBssid, + UINT32 ulPriority, + UINT32 ulPairwiseCipher_Or_TxKeyLen, + UINT32 ulGroupCipher_TxKeyIndex, + UINT32 ulKeyMgmt, + UINT8* ucPf_OrKey, + UINT32 ulPassPhraseLen) +{ + UINT16 arg_len=0; + INT32 ret; + UINT8 *ptr; + INT32 i = 0; + UINT8 *args; + UINT8 bssid_zero[] = {0, 0, 0, 0, 0, 0}; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + args = UINT32_TO_STREAM(args, ulSecType); + + // Setup arguments in accordance with the security type + switch (ulSecType) + { + //OPEN + case WLAN_SEC_UNSEC: + { + args = UINT32_TO_STREAM(args, 0x00000014); + args = UINT32_TO_STREAM(args, ulSsidLen); + args = UINT16_TO_STREAM(args, 0); + if(ucBssid) + { + ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, ulPriority); + ARRAY_TO_STREAM(args, ucSsid, ulSsidLen); + + arg_len = WLAN_ADD_PROFILE_NOSEC_PARAM_LEN + ulSsidLen; + } + break; + + //WEP + case WLAN_SEC_WEP: + { + args = UINT32_TO_STREAM(args, 0x00000020); + args = UINT32_TO_STREAM(args, ulSsidLen); + args = UINT16_TO_STREAM(args, 0); + if(ucBssid) + { + ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, ulPriority); + args = UINT32_TO_STREAM(args, 0x0000000C + ulSsidLen); + args = UINT32_TO_STREAM(args, ulPairwiseCipher_Or_TxKeyLen); + args = UINT32_TO_STREAM(args, ulGroupCipher_TxKeyIndex); + ARRAY_TO_STREAM(args, ucSsid, ulSsidLen); + + for(i = 0; i < 4; i++) + { + UINT8 *p = &ucPf_OrKey[i * ulPairwiseCipher_Or_TxKeyLen]; + + ARRAY_TO_STREAM(args, p, ulPairwiseCipher_Or_TxKeyLen); + } + + arg_len = WLAN_ADD_PROFILE_WEP_PARAM_LEN + ulSsidLen + + ulPairwiseCipher_Or_TxKeyLen * 4; + + } + break; + + //WPA + //WPA2 + case WLAN_SEC_WPA: + case WLAN_SEC_WPA2: + { + args = UINT32_TO_STREAM(args, 0x00000028); + args = UINT32_TO_STREAM(args, ulSsidLen); + args = UINT16_TO_STREAM(args, 0); + if(ucBssid) + { + ARRAY_TO_STREAM(args, ucBssid, ETH_ALEN); + } + else + { + ARRAY_TO_STREAM(args, bssid_zero, ETH_ALEN); + } + args = UINT32_TO_STREAM(args, ulPriority); + args = UINT32_TO_STREAM(args, ulPairwiseCipher_Or_TxKeyLen); + args = UINT32_TO_STREAM(args, ulGroupCipher_TxKeyIndex); + args = UINT32_TO_STREAM(args, ulKeyMgmt); + args = UINT32_TO_STREAM(args, 0x00000008 + ulSsidLen); + args = UINT32_TO_STREAM(args, ulPassPhraseLen); + ARRAY_TO_STREAM(args, ucSsid, ulSsidLen); + ARRAY_TO_STREAM(args, ucPf_OrKey, ulPassPhraseLen); + + arg_len = WLAN_ADD_PROFILE_WPA_PARAM_LEN + ulSsidLen + ulPassPhraseLen; + } + + break; + } + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, + ptr, arg_len); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_ADD_PROFILE, &ret); + + return(ret); +} +#else +INT32 wlan_add_profile(UINT32 ulSecType, + UINT8* ucSsid, + UINT32 ulSsidLen, + UINT8 *ucBssid, + UINT32 ulPriority, + UINT32 ulPairwiseCipher_Or_TxKeyLen, + UINT32 ulGroupCipher_TxKeyIndex, + UINT32 ulKeyMgmt, + UINT8* ucPf_OrKey, + UINT32 ulPassPhraseLen) +{ + return -1; +} +#endif + +//***************************************************************************** +// +//! wlan_ioctl_del_profile +//! +//! @param index number of profile to delete +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Delete WLAN profile +//! +//! @Note In order to delete all stored profile, set index to 255. +//! +//! @sa wlan_add_profile +// +//***************************************************************************** + +INT32 wlan_ioctl_del_profile(UINT32 ulIndex) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (UINT8 *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, ulIndex); + ret = EFAIL; + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, + ptr, WLAN_DEL_PROFILE_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_DEL_PROFILE, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_ioctl_get_scan_results +//! +//! @param[in] scan_timeout parameter not supported +//! @param[out] ucResults scan results (_wlan_full_scan_results_args_t) +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Gets entry from scan result table. +//! The scan results are returned one by one, and each entry +//! represents a single AP found in the area. The following is a +//! format of the scan result: +//! - 4 Bytes: number of networks found +//! - 4 Bytes: The status of the scan: 0 - aged results, +//! 1 - results valid, 2 - no results +//! - 42 bytes: Result entry, where the bytes are arranged as follows: +//! +//! - 1 bit isValid - is result valid or not +//! - 7 bits rssi - RSSI value; +//! - 2 bits: securityMode - security mode of the AP: +//! 0 - Open, 1 - WEP, 2 WPA, 3 WPA2 +//! - 6 bits: SSID name length +//! - 2 bytes: the time at which the entry has entered into +//! scans result table +//! - 32 bytes: SSID name +//! - 6 bytes: BSSID +//! +//! @Note scan_timeout, is not supported on this version. +//! +//! @sa wlan_ioctl_set_scan_params +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 wlan_ioctl_get_scan_results(UINT32 ulScanTimeout, + UINT8 *ucResults) +{ + UINT8 *ptr; + UINT8 *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, ulScanTimeout); + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, + ptr, WLAN_GET_SCAN_RESULTS_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS, ucResults); + + return(0); +} +#endif + +//***************************************************************************** +// +//! wlan_ioctl_set_scan_params +//! +//! @param uiEnable - start/stop application scan: +//! 1 = start scan with default interval value of 10 min. +//! in order to set a different scan interval value apply the value +//! in milliseconds. minimum 1 second. 0=stop). Wlan reset +//! (wlan_stop() wlan_start()) is needed when changing scan interval +//! value. Saved: No +//! @param uiMinDwellTime minimum dwell time value to be used for each +//! channel, in milliseconds. Saved: yes +//! Recommended Value: 100 (Default: 20) +//! @param uiMaxDwellTime maximum dwell time value to be used for each +//! channel, in milliseconds. Saved: yes +//! Recommended Value: 100 (Default: 30) +//! @param uiNumOfProbeRequests max probe request between dwell time. +//! Saved: yes. Recommended Value: 5 (Default:2) +//! @param uiChannelMask bitwise, up to 13 channels (0x1fff). +//! Saved: yes. Default: 0x7ff +//! @param uiRSSIThreshold RSSI threshold. Saved: yes (Default: -80) +//! @param uiSNRThreshold NSR threshold. Saved: yes (Default: 0) +//! @param uiDefaultTxPower probe Tx power. Saved: yes (Default: 205) +//! @param aiIntervalList pointer to array with 16 entries (16 channels) +//! each entry (UINT32) holds timeout between periodic scan +//! (connection scan) - in millisecond. Saved: yes. Default 2000ms. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief start and stop scan procedure. Set scan parameters. +//! +//! @Note uiDefaultTxPower, is not supported on this version. +//! +//! @sa wlan_ioctl_get_scan_results +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 wlan_ioctl_set_scan_params(UINT32 uiEnable, UINT32 uiMinDwellTime, + UINT32 uiMaxDwellTime, + UINT32 uiNumOfProbeRequests, + UINT32 uiChannelMask,INT32 iRSSIThreshold, + UINT32 uiSNRThreshold, + UINT32 uiDefaultTxPower, + UINT32 *aiIntervalList) +{ + UINT32 uiRes; + UINT8 *ptr; + UINT8 *args; + + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + // Fill in temporary command buffer + args = UINT32_TO_STREAM(args, 36); + args = UINT32_TO_STREAM(args, uiEnable); + args = UINT32_TO_STREAM(args, uiMinDwellTime); + args = UINT32_TO_STREAM(args, uiMaxDwellTime); + args = UINT32_TO_STREAM(args, uiNumOfProbeRequests); + args = UINT32_TO_STREAM(args, uiChannelMask); + args = UINT32_TO_STREAM(args, iRSSIThreshold); + args = UINT32_TO_STREAM(args, uiSNRThreshold); + args = UINT32_TO_STREAM(args, uiDefaultTxPower); + ARRAY_TO_STREAM(args, aiIntervalList, sizeof(UINT32) * + SL_SET_SCAN_PARAMS_INTERVAL_LIST_SIZE); + + // Initiate a HCI command + hci_command_send(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, + ptr, WLAN_SET_SCAN_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SET_SCANPARAM, &uiRes); + + return(uiRes); +} +#endif + +//***************************************************************************** +// +//! wlan_set_event_mask +//! +//! @param mask mask option: +//! HCI_EVNT_WLAN_UNSOL_CONNECT connect event +//! HCI_EVNT_WLAN_UNSOL_DISCONNECT disconnect event +//! HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE smart config done +//! HCI_EVNT_WLAN_UNSOL_INIT init done +//! HCI_EVNT_WLAN_UNSOL_DHCP dhcp event report +//! HCI_EVNT_WLAN_ASYNC_PING_REPORT ping report +//! HCI_EVNT_WLAN_KEEPALIVE keepalive +//! HCI_EVNT_WLAN_TX_COMPLETE - disable information on end of transmission +//! Saved: no. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Mask event according to bit mask. In case that event is +//! masked (1), the device will not send the masked event to host. +// +//***************************************************************************** + +INT32 wlan_set_event_mask(UINT32 ulMask) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + + + if ((ulMask & HCI_EVNT_WLAN_TX_COMPLETE) == HCI_EVNT_WLAN_TX_COMPLETE) + { + tSLInformation.InformHostOnTxComplete = 0; + + // Since an event is a virtual event - i.e. it is not coming from CC3000 + // there is no need to send anything to the device if it was an only event + if (ulMask == HCI_EVNT_WLAN_TX_COMPLETE) + { + return 0; + } + + ulMask &= ~HCI_EVNT_WLAN_TX_COMPLETE; + ulMask |= HCI_EVNT_WLAN_UNSOL_BASE; + } + else + { + tSLInformation.InformHostOnTxComplete = 1; + } + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (UINT8 *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, ulMask); + + // Initiate a HCI command + hci_command_send(HCI_CMND_EVENT_MASK, + ptr, WLAN_SET_MASK_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_EVENT_MASK, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_ioctl_statusget +//! +//! @param none +//! +//! @return WLAN_STATUS_DISCONNECTED, WLAN_STATUS_SCANING, +//! STATUS_CONNECTING or WLAN_STATUS_CONNECTED +//! +//! @brief get wlan status: disconnected, scanning, connecting or connected +// +//***************************************************************************** + +#ifndef CC3000_TINY_DRIVER +INT32 wlan_ioctl_statusget(void) +{ + INT32 ret; + UINT8 *ptr; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + + hci_command_send(HCI_CMND_WLAN_IOCTL_STATUSGET, + ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_STATUSGET, &ret); + + return(ret); +} +#endif + +//***************************************************************************** +// +//! wlan_smart_config_start +//! +//! @param algoEncryptedFlag indicates whether the information is encrypted +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Start to acquire device profile. The device acquire its own +//! profile, if profile message is found. The acquired AP information +//! is stored in CC3000 EEPROM only in case AES128 encryption is used. +//! In case AES128 encryption is not used, a profile is created by +//! CC3000 internally. +//! +//! @Note An asynchronous event - Smart Config Done will be generated as soon +//! as the process finishes successfully. +//! +//! @sa wlan_smart_config_set_prefix , wlan_smart_config_stop +// +//***************************************************************************** + +INT32 wlan_smart_config_start(UINT32 algoEncryptedFlag) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (UINT8 *)(ptr + HEADERS_SIZE_CMD); + + // Fill in HCI packet structure + args = UINT32_TO_STREAM(args, algoEncryptedFlag); + ret = EFAIL; + + hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, ptr, + WLAN_SMART_CONFIG_START_PARAMS_LEN); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_smart_config_stop +//! +//! @param algoEncryptedFlag indicates whether the information is encrypted +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Stop the acquire profile procedure +//! +//! @sa wlan_smart_config_start , wlan_smart_config_set_prefix +// +//***************************************************************************** + +INT32 wlan_smart_config_stop(void) +{ + INT32 ret; + UINT8 *ptr; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + + hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, ptr, 0); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_smart_config_set_prefix +//! +//! @param newPrefix 3 bytes identify the SSID prefix for the Smart Config. +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief Configure station ssid prefix. The prefix is used internally +//! in CC3000. It should always be TTT. +//! +//! @Note The prefix is stored in CC3000 NVMEM +//! +//! @sa wlan_smart_config_start , wlan_smart_config_stop +// +//***************************************************************************** + +INT32 wlan_smart_config_set_prefix(CHAR* cNewPrefix) +{ + INT32 ret; + UINT8 *ptr; + UINT8 *args; + + ret = EFAIL; + ptr = tSLInformation.pucTxCommandBuffer; + args = (ptr + HEADERS_SIZE_CMD); + + if (cNewPrefix == NULL) + return ret; + else // with the new Smart Config, prefix must be TTT + { + *cNewPrefix = 'T'; + *(cNewPrefix + 1) = 'T'; + *(cNewPrefix + 2) = 'T'; + } + + ARRAY_TO_STREAM(args, cNewPrefix, SL_SIMPLE_CONFIG_PREFIX_LENGTH); + + hci_command_send(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, ptr, + SL_SIMPLE_CONFIG_PREFIX_LENGTH); + + // Wait for command complete event + SimpleLinkWaitEvent(HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX, &ret); + + return(ret); +} + +//***************************************************************************** +// +//! wlan_smart_config_process +//! +//! @param none +//! +//! @return On success, zero is returned. On error, -1 is returned +//! +//! @brief process the acquired data and store it as a profile. The acquired +//! AP information is stored in CC3000 EEPROM encrypted. +//! The encrypted data is decrypted and stored as a profile. +//! behavior is as defined by connection policy. +// +//***************************************************************************** + + +#ifndef CC3000_UNENCRYPTED_SMART_CONFIG +INT32 wlan_smart_config_process() +{ + INT32 returnValue; + UINT32 ssidLen, keyLen; + UINT8 *decKeyPtr; + UINT8 *ssidPtr; + + // read the key from EEPROM - fileID 12 + returnValue = aes_read_key(key); + + if (returnValue != 0) + return returnValue; + + // read the received data from fileID #13 and parse it according to the followings: + // 1) SSID LEN - not encrypted + // 2) SSID - not encrypted + // 3) KEY LEN - not encrypted. always 32 bytes long + // 4) Security type - not encrypted + // 5) KEY - encrypted together with true key length as the first byte in KEY + // to elaborate, there are two corner cases: + // 1) the KEY is 32 bytes long. In this case, the first byte does not represent KEY length + // 2) the KEY is 31 bytes long. In this case, the first byte represent KEY length and equals 31 + returnValue = nvmem_read(NVMEM_SHARED_MEM_FILEID, SMART_CONFIG_PROFILE_SIZE, 0, profileArray); + + if (returnValue != 0) + return returnValue; + + ssidPtr = &profileArray[1]; + + ssidLen = profileArray[0]; + + decKeyPtr = &profileArray[profileArray[0] + 3]; + + aes_decrypt(decKeyPtr, key); + if (profileArray[profileArray[0] + 1] > 16) + aes_decrypt((UINT8 *)(decKeyPtr + 16), key); + + if (*(UINT8 *)(decKeyPtr +31) != 0) + { + if (*decKeyPtr == 31) + { + keyLen = 31; + decKeyPtr++; + } + else + { + keyLen = 32; + } + } + else + { + keyLen = *decKeyPtr; + decKeyPtr++; + } + + // add a profile + switch (profileArray[profileArray[0] + 2]) + { + case WLAN_SEC_UNSEC://None + { + returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type + ssidPtr, // SSID + ssidLen, // SSID length + NULL, // BSSID + 1, // Priority + 0, 0, 0, 0, 0); + + break; + } + + case WLAN_SEC_WEP://WEP + { + returnValue = wlan_add_profile(profileArray[profileArray[0] + 2], // security type + ssidPtr, // SSID + ssidLen, // SSID length + NULL, // BSSID + 1, // Priority + keyLen, // KEY length + 0, // KEY index + 0, + decKeyPtr, // KEY + 0); + + break; + } + + case WLAN_SEC_WPA://WPA + case WLAN_SEC_WPA2://WPA2 + { + returnValue = wlan_add_profile(WLAN_SEC_WPA2, // security type + ssidPtr, + ssidLen, + NULL, // BSSID + 1, // Priority + 0x18, // PairwiseCipher + 0x1e, // GroupCipher + 2, // KEY management + decKeyPtr, // KEY + keyLen); // KEY length + + break; + } + } + + return returnValue; +} +#endif //CC3000_UNENCRYPTED_SMART_CONFIG + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/device.h b/src/openmv/src/micropython/drivers/cc3100/inc/device.h new file mode 100755 index 0000000..169736d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/device.h @@ -0,0 +1,656 @@ +/* + * device.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + + + +#ifdef __cplusplus +extern "C" { +#endif + + + +/*! + + \addtogroup device + @{ + +*/ + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + + +/* SL internal Error codes */ + +/* Receive this error in case there are no resources to issue the command + If possible, increase the number of MAX_CUNCURENT_ACTIONS (result in memory increase) + If not, try again later */ +#define SL_POOL_IS_EMPTY (-2000) + +/* Receive this error in case a given length for RX buffer was too small. + Receive payload was bigger than the given buffer size. Therefore, payload is cut according to receive size + Recommend to increase buffer size */ +#define SL_ESMALLBUF (-2001) + +/* Receive this error in case zero length is supplied to a "get" API + Recommend to supply length according to requested information (view options defines for help) */ +#define SL_EZEROLEN (-2002) + +/* User supplied invalid parameter */ +#define SL_INVALPARAM (-2003) + + +/* Failed to open interface */ +#define SL_BAD_INTERFACE (-2004) + +/* End of SL internal Error codes */ + + + +/*****************************************************************************/ +/* Errors returned from the general error async event */ +/*****************************************************************************/ + +/* Send types */ +typedef enum +{ + SL_ERR_SENDER_HEALTH_MON, + SL_ERR_SENDER_CLI_UART, + SL_ERR_SENDER_SUPPLICANT, + SL_ERR_SENDER_NETWORK_STACK, + SL_ERR_SENDER_WLAN_DRV_IF, + SL_ERR_SENDER_WILINK, + SL_ERR_SENDER_INIT_APP, + SL_ERR_SENDER_NETX, + SL_ERR_SENDER_HOST_APD, + SL_ERR_SENDER_MDNS, + SL_ERR_SENDER_HTTP_SERVER, + SL_ERR_SENDER_DHCP_SERVER, + SL_ERR_SENDER_DHCP_CLIENT, + SL_ERR_DISPATCHER, + SL_ERR_NUM_SENDER_LAST=0xFF +}SlErrorSender_e; + + +/* Error codes */ +#define SL_ERROR_STATIC_ADDR_SUBNET_ERROR (-60) /* network stack error*/ +#define SL_ERROR_ILLEGAL_CHANNEL (-61) /* supplicant error */ +#define SL_ERROR_SUPPLICANT_ERROR (-72) /* init error code */ +#define SL_ERROR_HOSTAPD_INIT_FAIL (-73) /* init error code */ +#define SL_ERROR_HOSTAPD_INIT_IF_FAIL (-74) /* init error code */ +#define SL_ERROR_WLAN_DRV_INIT_FAIL (-75) /* init error code */ +#define SL_ERROR_WLAN_DRV_START_FAIL (-76) /* wlan start error */ +#define SL_ERROR_FS_FILE_TABLE_LOAD_FAILED (-77) /* init file system failed */ +#define SL_ERROR_PREFERRED_NETWORKS_FILE_LOAD_FAILED (-78) /* init file system failed */ +#define SL_ERROR_HOSTAPD_BSSID_VALIDATION_ERROR (-79) /* Ap configurations BSSID error */ +#define SL_ERROR_HOSTAPD_FAILED_TO_SETUP_INTERFACE (-80) /* Ap configurations interface error */ +#define SL_ERROR_MDNS_ENABLE_FAIL (-81) /* mDNS enable failed */ +#define SL_ERROR_HTTP_SERVER_ENABLE_FAILED (-82) /* HTTP server enable failed */ +#define SL_ERROR_DHCP_SERVER_ENABLE_FAILED (-83) /* DHCP server enable failed */ +#define SL_ERROR_PREFERRED_NETWORK_LIST_FULL (-93) /* supplicant error */ +#define SL_ERROR_PREFERRED_NETWORKS_FILE_WRITE_FAILED (-94) /* supplicant error */ +#define SL_ERROR_DHCP_CLIENT_RENEW_FAILED (-100) /* DHCP client error */ +/* WLAN Connection management status */ +#define SL_ERROR_CON_MGMT_STATUS_UNSPECIFIED (-102) +#define SL_ERROR_CON_MGMT_STATUS_AUTH_REJECT (-103) +#define SL_ERROR_CON_MGMT_STATUS_ASSOC_REJECT (-104) +#define SL_ERROR_CON_MGMT_STATUS_SECURITY_FAILURE (-105) +#define SL_ERROR_CON_MGMT_STATUS_AP_DEAUTHENTICATE (-106) +#define SL_ERROR_CON_MGMT_STATUS_AP_DISASSOCIATE (-107) +#define SL_ERROR_CON_MGMT_STATUS_ROAMING_TRIGGER (-108) +#define SL_ERROR_CON_MGMT_STATUS_DISCONNECT_DURING_CONNECT (-109) +#define SL_ERROR_CON_MGMT_STATUS_SG_RESELECT (-110) +#define SL_ERROR_CON_MGMT_STATUS_ROC_FAILURE (-111) +#define SL_ERROR_CON_MGMT_STATUS_MIC_FAILURE (-112) +/* end of WLAN connection management error statuses */ +#define SL_ERROR_WAKELOCK_ERROR_PREFIX (-115) /* Wake lock expired */ +#define SL_ERROR_LENGTH_ERROR_PREFIX (-116) /* Uart header length error */ +#define SL_ERROR_MDNS_CREATE_FAIL (-121) /* mDNS create failed */ +#define SL_ERROR_GENERAL_ERROR (-127) + + + +#define SL_DEVICE_GENERAL_CONFIGURATION (1) +#define SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME (11) +#define SL_DEVICE_GENERAL_VERSION (12) +#define SL_DEVICE_STATUS (2) + +/* + Declare the different event group classifications + The SimpleLink device send asynchronous events. Each event has a group + classification according to its nature. +*/ +/* SL_EVENT_CLASS_WLAN connection user events */ +#define SL_WLAN_CONNECT_EVENT (1) +#define SL_WLAN_DISCONNECT_EVENT (2) +/* WLAN Smart Config user events */ +#define SL_WLAN_SMART_CONFIG_COMPLETE_EVENT (3) +#define SL_WLAN_SMART_CONFIG_STOP_EVENT (4) +/* WLAN AP user events */ +#define SL_WLAN_STA_CONNECTED_EVENT (5) +#define SL_WLAN_STA_DISCONNECTED_EVENT (6) +/* WLAN P2P user events */ +#define SL_WLAN_P2P_DEV_FOUND_EVENT (7) +#define SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT (8) +#define SL_WLAN_CONNECTION_FAILED_EVENT (9) +/* SL_EVENT_CLASS_DEVICE user events */ +#define SL_DEVICE_FATAL_ERROR_EVENT (1) +#define SL_DEVICE_ABORT_ERROR_EVENT (2) + +/* SL_EVENT_CLASS_BSD user events */ +#define SL_SOCKET_TX_FAILED_EVENT (1) +#define SL_SOCKET_ASYNC_EVENT (2) +/* SL_EVENT_CLASS_NETAPP user events */ +#define SL_NETAPP_IPV4_IPACQUIRED_EVENT (1) +#define SL_NETAPP_IPV6_IPACQUIRED_EVENT (2) +#define SL_NETAPP_IP_LEASED_EVENT (3) +#define SL_NETAPP_IP_RELEASED_EVENT (4) + +/* Server Events */ +#define SL_NETAPP_HTTPGETTOKENVALUE_EVENT (1) +#define SL_NETAPP_HTTPPOSTTOKENVALUE_EVENT (2) + + +/* + Declare the different event group classifications for sl_DevGet + for getting status indications + */ + +/* Events list to mask/unmask*/ +#define SL_EVENT_CLASS_GLOBAL (0) +#define SL_EVENT_CLASS_DEVICE (1) +#define SL_EVENT_CLASS_WLAN (2) +#define SL_EVENT_CLASS_BSD (3) +#define SL_EVENT_CLASS_NETAPP (4) +#define SL_EVENT_CLASS_NETCFG (5) +#define SL_EVENT_CLASS_FS (6) + + +/****************** DEVICE CLASS status ****************/ +#define EVENT_DROPPED_DEVICE_ASYNC_GENERAL_ERROR (0x00000001L) +#define STATUS_DEVICE_SMART_CONFIG_ACTIVE (0x80000000L) + +/****************** WLAN CLASS status ****************/ +#define EVENT_DROPPED_WLAN_WLANASYNCONNECTEDRESPONSE (0x00000001L) +#define EVENT_DROPPED_WLAN_WLANASYNCDISCONNECTEDRESPONSE (0x00000002L) +#define EVENT_DROPPED_WLAN_STA_CONNECTED (0x00000004L) +#define EVENT_DROPPED_WLAN_STA_DISCONNECTED (0x00000008L) +#define STATUS_WLAN_STA_CONNECTED (0x80000000L) + +/****************** NETAPP CLASS status ****************/ +#define EVENT_DROPPED_NETAPP_IPACQUIRED (0x00000001L) +#define EVENT_DROPPED_NETAPP_IPACQUIRED_V6 (0x00000002L) +#define EVENT_DROPPED_NETAPP_IP_LEASED (0x00000004L) +#define EVENT_DROPPED_NETAPP_IP_RELEASED (0x00000008L) + +/****************** BSD CLASS status ****************/ +#define EVENT_DROPPED_SOCKET_TXFAILEDASYNCRESPONSE (0x00000001L) + +/****************** FS CLASS ****************/ + + + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ + +#define ROLE_UNKNOWN_ERR (-1) + +#ifdef SL_IF_TYPE_UART +typedef struct +{ + _u32 BaudRate; + _u8 FlowControlEnable; + _u8 CommPort; +} SlUartIfParams_t; +#endif + +typedef struct +{ + _u32 ChipId; + _u32 FwVersion[4]; + _u8 PhyVersion[4]; +}_SlPartialVersion; + +typedef struct +{ + _SlPartialVersion ChipFwAndPhyVersion; + _u32 NwpVersion[4]; + _u16 RomVersion; + _u16 Padding; +}SlVersionFull; + + +typedef struct +{ + _u32 AbortType; + _u32 AbortData; +}sl_DeviceReportAbort; + + +typedef struct +{ + _i8 status; + SlErrorSender_e sender; +}sl_DeviceReport; + +typedef union +{ + sl_DeviceReport deviceEvent; + sl_DeviceReportAbort deviceReport; +} _SlDeviceEventData_u; + +typedef struct +{ + _u32 Event; + _SlDeviceEventData_u EventData; +} SlDeviceEvent_t; + +typedef struct +{ + /* time */ + _u32 sl_tm_sec; + _u32 sl_tm_min; + _u32 sl_tm_hour; + /* date */ + _u32 sl_tm_day; /* 1-31 */ + _u32 sl_tm_mon; /* 1-12 */ + _u32 sl_tm_year; /* YYYY 4 digits */ + _u32 sl_tm_week_day; /* not required */ + _u32 sl_tm_year_day; /* not required */ + _u32 reserved[3]; +}SlDateTime_t; + + +/******************************************************************************/ +/* Type declarations */ +/******************************************************************************/ +typedef void (*P_INIT_CALLBACK)(_u32 Status); + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + +/*! + \brief Start the SimpleLink device + + This function initialize the communication interface, set the enable pin + of the device, and call to the init complete callback. + + \param[in] pIfHdl Opened Interface Object. In case the interface + must be opened outside the SimpleLink Driver, the + user might give the handler to be used in \n + any access of the communication interface with the + device (UART/SPI). \n + The SimpleLink driver will open an interface port + only if this parameter is null! \n + \param[in] pDevName The name of the device to open. Could be used when + the pIfHdl is null, to transfer information to the + open interface function \n + This pointer could be used to pass additional information to + sl_IfOpen in case it is required (e.g. UART com port name) + \param[in] pInitCallBack Pointer to function that would be called + on completion of the initialization process.\n + If this parameter is NULL the function is + blocked until the device initialization + is completed, otherwise the function returns + immediately. + + \return Returns the current active role (STA/AP/P2P) or an error code: + - ROLE_STA, ROLE_AP, ROLE_P2P in case of success, + otherwise in failure one of the following is return: + - ROLE_STA_ERR (Failure to load MAC/PHY in STA role) + - ROLE_AP_ERR (Failure to load MAC/PHY in AP role) + - ROLE_P2P_ERR (Failure to load MAC/PHY in P2P role) + + + \sa sl_Stop + + \note belongs to \ref basic_api + + \warning This function must be called before any other SimpleLink API is used, or after sl_Stop is called for reinit the device + \par Example: + \code + An example for open interface without callback routine. The interface name and handler are + handled by the sl_IfOpen routine: + + if( sl_Start(NULL, NULL, NULL) < 0 ) + { + LOG("Error opening interface to device\n"); + } + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_Start) +_i16 sl_Start(const void* pIfHdl, _i8* pDevName, const P_INIT_CALLBACK pInitCallBack); +#endif + +/*! + \brief Stop the SimpleLink device + + This function clears the enable pin of the device, closes the communication \n + interface and invokes the stop complete callback + + \param[in] timeout Stop timeout in msec. Should be used to give the device time to finish \n + any transmission/reception that is not completed when the function was called. \n + Additional options: + - 0 Enter to hibernate immediately \n + - 0xFFFF Host waits for device's response before \n + hibernating, without timeout protection \n + - 0 < Timeout[msec] < 0xFFFF Host waits for device's response before \n + hibernating, with a defined timeout protection \n + This timeout defines the max time to wait. The NWP \n + response can be sent earlier than this timeout. + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_Start + + \note This API will shutdown the device and invoke the "i/f close" function regardless \n + if it was opened implicitly or explicitly. \n + It is up to the platform interface library to properly handle interface close \n + routine \n + belongs to \ref basic_api \n + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Stop) +_i16 sl_Stop(const _u16 timeout); +#endif + + +/*! + \brief Internal function for setting device configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] DeviceSetId configuration id + \param[in] Option configurations option + \param[in] ConfigLen configurations len + \param[in] pValues configurations values + + \sa + \note + \warning + \par Examples: + \code + Setting device time and date example: + + SlDateTime_t dateTime= {0}; + dateTime.sl_tm_day = (_u32)23; // Day of month (DD format) range 1-31 + dateTime.sl_tm_mon = (_u32)6; // Month (MM format) in the range of 1-12 + dateTime.sl_tm_year = (_u32)2014; // Year (YYYY format) + dateTime.sl_tm_hour = (_u32)17; // Hours in the range of 0-23 + dateTime.sl_tm_min = (_u32)55; // Minutes in the range of 0-59 + dateTime.sl_tm_sec = (_u32)22; // Seconds in the range of 0-59 + sl_DevSet(SL_DEVICE_GENERAL_CONFIGURATION, + SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME, + sizeof(SlDateTime_t), + (_u8 *)(&dateTime)); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_DevSet) +_i32 sl_DevSet(const _u8 DeviceSetId ,const _u8 Option,const _u8 ConfigLen,const _u8 *pValues); +#endif + +/*! + \brief Internal function for getting device configurations + \return On success, zero is returned. On error, -1 is + returned + \param[in] DeviceGetId configuration id - example SL_DEVICE_STATUS + \param[out] pOption Get configurations option, example for get status options + - SL_EVENT_CLASS_GLOBAL + - SL_EVENT_CLASS_DEVICE + - SL_EVENT_CLASS_WLAN + - SL_EVENT_CLASS_BSD + - SL_EVENT_CLASS_NETAPP + - SL_EVENT_CLASS_NETCFG + - SL_EVENT_CLASS_FS + \param[out] pConfigLen The length of the allocated memory as input, when the + function complete, the value of this parameter would be + the len that actually read from the device.\n + If the device return length that is longer from the input + value, the function will cut the end of the returned structure + and will return SL_ESMALLBUF + \param[out] pValues Get configurations values + \sa + \note + \warning + \par Examples: + \code + Example for getting WLAN class status: + _u32 statusWlan; + _u8 pConfigOpt; + _u8 pConfigLen; + pConfigOpt = SL_EVENT_CLASS_WLAN; + pConfigLen = sizeof(_u32); + sl_DevGet(SL_DEVICE_STATUS,&pConfigOpt,&pConfigLen,(_u8 *)(&statusWlan)); + Example for getting version: + SlVersionFull ver; + pConfigLen = sizeof(ver); + pConfigOpt = SL_DEVICE_GENERAL_VERSION; + sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION,&pConfigOpt,&pConfigLen,(_u8 *)(&ver)); + printf("CHIP %d\nMAC 31.%d.%d.%d.%d\nPHY %d.%d.%d.%d\nNWP %d.%d.%d.%d\nROM %d\nHOST %d.%d.%d.%d\n", + ver.ChipFwAndPhyVersion.ChipId, + ver.ChipFwAndPhyVersion.FwVersion[0],ver.ChipFwAndPhyVersion.FwVersion[1], + ver.ChipFwAndPhyVersion.FwVersion[2],ver.ChipFwAndPhyVersion.FwVersion[3], + ver.ChipFwAndPhyVersion.PhyVersion[0],ver.ChipFwAndPhyVersion.PhyVersion[1], + ver.ChipFwAndPhyVersion.PhyVersion[2],ver.ChipFwAndPhyVersion.PhyVersion[3], + ver.NwpVersion[0],ver.NwpVersion[1],ver.NwpVersion[2],ver.NwpVersion[3], + ver.RomVersion, + SL_MAJOR_VERSION_NUM,SL_MINOR_VERSION_NUM,SL_VERSION_NUM,SL_SUB_VERSION_NUM); + + \endcode + \code + Getting Device time and date example: + + SlDateTime_t dateTime = {0}; + _i8 configLen = sizeof(SlDateTime_t); + _i8 configOpt = SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME; + sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION,&configOpt, &configLen,(_u8 *)(&dateTime)); + + printf("Day %d,Mon %d,Year %d,Hour %,Min %d,Sec %d\n",dateTime.sl_tm_day,dateTime.sl_tm_mon,dateTime.sl_tm_year + dateTime.sl_tm_hour,dateTime.sl_tm_min,dateTime.sl_tm_sec); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_DevGet) +_i32 sl_DevGet(const _u8 DeviceGetId,_u8 *pOption,_u8 *pConfigLen, _u8 *pValues); +#endif + + +/*! + \brief Set asynchronous event mask + + Mask asynchronous events from the device. Masked events do not + generate asynchronous messages from the device. + By default - all events are active + + \param[in] EventClass The classification groups that the + mask is referred to. Need to be one of + the following: + - SL_EVENT_CLASS_GLOBAL + - SL_EVENT_CLASS_DEVICE + - SL_EVENT_CLASS_WLAN + - SL_EVENT_CLASS_BSD + - SL_EVENT_CLASS_NETAPP + - SL_EVENT_CLASS_NETCFG + - SL_EVENT_CLASS_FS + + + \param[in] Mask Event Mask bitmap. Valid mask are (per group): + - SL_EVENT_CLASS_WLAN user events + - SL_WLAN_CONNECT_EVENT + - SL_WLAN_DISCONNECT_EVENT + - SL_EVENT_CLASS_DEVICE user events + - SL_DEVICE_FATAL_ERROR_EVENT + - SL_EVENT_CLASS_BSD user events + - SL_SOCKET_TX_FAILED_EVENT + - SL_SOCKET_ASYNC_EVENT + - SL_EVENT_CLASS_NETAPP user events + - SL_NETAPP_IPV4_IPACQUIRED_EVENT + - SL_NETAPP_IPV6_IPACQUIRED_EVENT + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_EventMaskGet + + \note belongs to \ref ext_api + + \warning + \par Example: + \code + + An example of masking connection/disconnection async events from WLAN class: + sl_EventMaskSet(SL_EVENT_CLASS_WLAN, (SL_WLAN_CONNECT_EVENT | SL_WLAN_DISCONNECT_EVENT) ); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_EventMaskSet) +_i16 sl_EventMaskSet(const _u8 EventClass ,const _u32 Mask); +#endif + +/*! + \brief Get current event mask of the device + + return the events bit mask from the device. In case that event is + masked, the device is not sending this event. + + \param[in] EventClass The classification groups that the + mask is referred to. Need to be one of + the following: + - SL_EVENT_CLASS_GLOBAL + - SL_EVENT_CLASS_DEVICE + - SL_EVENT_CLASS_WLAN + - SL_EVENT_CLASS_BSD + - SL_EVENT_CLASS_NETAPP + - SL_EVENT_CLASS_NETCFG + - SL_EVENT_CLASS_FS + + \param[out] pMask Pointer to Mask bitmap where the + value should be stored. Bitmasks are the same as in \ref sl_EventMaskSet + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_EventMaskSet + + \note belongs to \ref ext_api + + \warning + \par Example: + \code + + An example of getting an event mask for WLAN class + _u32 maskWlan; + sl_StatusGet(SL_EVENT_CLASS_WLAN,&maskWlan); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_EventMaskGet) +_i16 sl_EventMaskGet(const _u8 EventClass,_u32 *pMask); +#endif + + +/*! + \brief the simple link task entry + + \Param + This function must be called from the main loop or from dedicated thread in + the following cases: + - Non-Os Platform - should be called from the mail loop + - Multi Threaded Platform when the user does not implement the external spawn functions - + should be called from dedicated thread allocated to the simplelink driver. + In this mode the function never return. + + \return None + + \sa sl_Stop + + \note belongs to \ref basic_api + + \warning This function must be called from a thread that is start running before + any call to other simple link API +*/ +#if _SL_INCLUDE_FUNC(sl_Task) +void sl_Task(void); +#endif + + +/*! + \brief Setting the internal uart mode + + \param[in] pUartParams Pointer to the uart configuration parameter set: + baudrate - up to 711 Kbps + flow control - enable/disable + comm port - the comm port number + + \return On success zero is returned, otherwise - Failed. + + \sa sl_Stop + + \note belongs to \ref basic_api + + \warning This function must consider the host uart capability +*/ +#ifdef SL_IF_TYPE_UART +#if _SL_INCLUDE_FUNC(sl_UartSetMode) +_i16 sl_UartSetMode(const SlUartIfParams_t* pUartParams); +#endif +#endif + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DEVICE_H__ */ + + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/driver.h b/src/openmv/src/micropython/drivers/cc3100/inc/driver.h new file mode 100755 index 0000000..4ef484d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/driver.h @@ -0,0 +1,247 @@ +/* + * driver.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __DRIVER_INT_H__ +#define __DRIVER_INT_H__ + + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +#ifndef CPU_FREQ_IN_MHZ + #define CPU_FREQ_IN_MHZ (200) +#endif +#define USEC_DELAY (50) + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ + +typedef struct +{ + _SlOpcode_t Opcode; + _SlArgSize_t TxDescLen; + _SlArgSize_t RxDescLen; +}_SlCmdCtrl_t; + +typedef struct +{ + _u16 TxPayloadLen; + _i16 RxPayloadLen; + _i16 ActualRxPayloadLen; + _u8 *pTxPayload; + _u8 *pRxPayload; +}_SlCmdExt_t; + + +typedef struct _SlArgsData_t +{ + _u8 *pArgs; + _u8 *pData; +} _SlArgsData_t; + + +typedef struct _SlPoolObj_t +{ + _SlSyncObj_t SyncObj; + _u8 *pRespArgs; + _u8 ActionID; + _u8 AdditionalData; /* use for socketID and one bit which indicate supprt IPV6 or not (1=support, 0 otherwise) */ + _u8 NextIndex; + +} _SlPoolObj_t; + + +typedef enum +{ + SOCKET_0, + SOCKET_1, + SOCKET_2, + SOCKET_3, + SOCKET_4, + SOCKET_5, + SOCKET_6, + SOCKET_7, + MAX_SOCKET_ENUM_IDX, +#ifndef SL_TINY_EXT + ACCEPT_ID = MAX_SOCKET_ENUM_IDX, + CONNECT_ID, +#else + CONNECT_ID = MAX_SOCKET_ENUM_IDX, +#endif +#ifndef SL_TINY_EXT + SELECT_ID, +#endif + GETHOSYBYNAME_ID, +#ifndef SL_TINY_EXT + GETHOSYBYSERVICE_ID, + PING_ID, +#endif + START_STOP_ID, + RECV_ID +}_SlActionID_e; + +typedef struct _SlActionLookup_t +{ + _u8 ActionID; + _u16 ActionAsyncOpcode; + _SlSpawnEntryFunc_t AsyncEventHandler; + +} _SlActionLookup_t; + + +typedef struct +{ + _u8 TxPoolCnt; + _SlLockObj_t TxLockObj; + _SlSyncObj_t TxSyncObj; +}_SlFlowContCB_t; + +typedef enum +{ + RECV_RESP_CLASS, + CMD_RESP_CLASS, + ASYNC_EVT_CLASS, + DUMMY_MSG_CLASS +}_SlRxMsgClass_e; + +typedef struct +{ + _u8 *pAsyncBuf; /* place to write pointer to buffer with CmdResp's Header + Arguments */ + _u8 ActionIndex; + _SlSpawnEntryFunc_t AsyncEvtHandler; /* place to write pointer to AsyncEvent handler (calc-ed by Opcode) */ + _SlRxMsgClass_e RxMsgClass; /* type of Rx message */ +} AsyncExt_t; + +typedef _u8 _SlSd_t; + +typedef struct +{ + _SlCmdCtrl_t *pCmdCtrl; + _u8 *pTxRxDescBuff; + _SlCmdExt_t *pCmdExt; + AsyncExt_t AsyncExt; +}_SlFunctionParams_t; + + +typedef struct +{ + _SlFd_t FD; + _SlLockObj_t GlobalLockObj; + _SlCommandHeader_t TempProtocolHeader; + P_INIT_CALLBACK pInitCallback; + + _SlPoolObj_t ObjPool[MAX_CONCURRENT_ACTIONS]; + _u8 FreePoolIdx; + _u8 PendingPoolIdx; + _u8 ActivePoolIdx; + _u32 ActiveActionsBitmap; + _SlLockObj_t ProtectionLockObj; + + _SlSyncObj_t CmdSyncObj; + _u8 IsCmdRespWaited; + _SlFlowContCB_t FlowContCB; + _u8 TxSeqNum; + _u8 RxDoneCnt; + _u8 SocketNonBlocking; + _u8 SocketTXFailure; + /* for stack reduction the parameters are globals */ + _SlFunctionParams_t FunctionParams; + + _u8 ActionIndex; +}_SlDriverCb_t; + +extern _volatile _u8 RxIrqCnt; + +extern _SlDriverCb_t* g_pCB; +extern P_SL_DEV_PING_CALLBACK pPingCallBackFunc; + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ +extern void _SlDrvDriverCBInit(void); +extern void _SlDrvDriverCBDeinit(void); +extern void _SlDrvRxIrqHandler(void *pValue); +extern _SlReturnVal_t _SlDrvCmdOp(_SlCmdCtrl_t *pCmdCtrl , void* pTxRxDescBuff , _SlCmdExt_t* pCmdExt); +extern _SlReturnVal_t _SlDrvCmdSend(_SlCmdCtrl_t *pCmdCtrl , void* pTxRxDescBuff , _SlCmdExt_t* pCmdExt); +extern _SlReturnVal_t _SlDrvDataReadOp(_SlSd_t Sd, _SlCmdCtrl_t *pCmdCtrl , void* pTxRxDescBuff , _SlCmdExt_t* pCmdExt); +extern _SlReturnVal_t _SlDrvDataWriteOp(_SlSd_t Sd, _SlCmdCtrl_t *pCmdCtrl , void* pTxRxDescBuff , _SlCmdExt_t* pCmdExt); +extern void _sl_HandleAsync_InitComplete(void *pVoidBuf); +extern void _sl_HandleAsync_Connect(void *pVoidBuf); + + +#ifndef SL_TINY_EXT +extern _i16 _SlDrvBasicCmd(_SlOpcode_t Opcode); +extern void _sl_HandleAsync_Accept(void *pVoidBuf); +extern void _sl_HandleAsync_DnsGetHostByService(void *pVoidBuf); +extern void _sl_HandleAsync_Select(void *pVoidBuf); +#endif + + +extern void _sl_HandleAsync_DnsGetHostByName(void *pVoidBuf); +extern void _sl_HandleAsync_DnsGetHostByAddr(void *pVoidBuf); +extern void _sl_HandleAsync_PingResponse(void *pVoidBuf); +extern void _SlDrvNetAppEventHandler(void* pArgs); +extern void _SlDrvDeviceEventHandler(void* pArgs); +extern void _sl_HandleAsync_Stop(void *pVoidBuf); +extern _u8 _SlDrvWaitForPoolObj(_u8 ActionID, _u8 SocketID); +extern void _SlDrvReleasePoolObj(_u8 pObj); +extern _u16 _SlDrvAlignSize(_u16 msgLen); +extern _u8 _SlDrvProtectAsyncRespSetting(_u8 *pAsyncRsp, _u8 ActionID, _u8 SocketID); + + +extern void _SlDrvSyncObjWaitForever(_SlSyncObj_t *pSyncObj); +extern void _SlDrvSyncObjSignal(_SlSyncObj_t *pSyncObj); +extern void _SlDrvObjLock(_SlLockObj_t *pLockObj, _SlTime_t Timeout); +extern void _SlDrvObjLockWaitForever(_SlLockObj_t *pLockObj); +extern void _SlDrvProtectionObjLockWaitForever(); +extern void _SlDrvObjUnLock(_SlLockObj_t *pLockObj); +extern void _SlDrvProtectionObjUnLock(); + +extern void _SlDrvMemZero(void* Addr, _u16 size); +extern void _SlDrvResetCmdExt(_SlCmdExt_t* pCmdExt); + + + +#define _SL_PROTOCOL_ALIGN_SIZE(msgLen) (((msgLen)+3) & (~3)) +#define _SL_IS_PROTOCOL_ALIGNED_SIZE(msgLen) (!((msgLen) & 3)) + + +#define _SL_PROTOCOL_CALC_LEN(pCmdCtrl,pCmdExt) ((pCmdExt) ? \ + (_SL_PROTOCOL_ALIGN_SIZE(pCmdCtrl->TxDescLen) + _SL_PROTOCOL_ALIGN_SIZE(pCmdExt->TxPayloadLen)) : \ + (_SL_PROTOCOL_ALIGN_SIZE(pCmdCtrl->TxDescLen))) +#endif /* __DRIVER_INT_H__ */ diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/flowcont.h b/src/openmv/src/micropython/drivers/cc3100/inc/flowcont.h new file mode 100755 index 0000000..3dcc130 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/flowcont.h @@ -0,0 +1,61 @@ +/* + * flowcont.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __FLOWCONT_H__ +#define __FLOWCONT_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ +#define FLOW_CONT_MIN 1 + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ +extern void _SlDrvFlowContInit(void); +extern void _SlDrvFlowContDeinit(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FLOWCONT_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/fs.h b/src/openmv/src/micropython/drivers/cc3100/inc/fs.h new file mode 100755 index 0000000..078feaf --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/fs.h @@ -0,0 +1,382 @@ +/* + * fs.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ + +#include "simplelink.h" + +#ifndef __FS_H__ +#define __FS_H__ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + + \addtogroup FileSystem + @{ + +*/ + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +/* FS error codes */ +#define SL_FS_OK (0) +#define SL_FS_ERR_EMPTY_SFLASH (-67) +#define SL_FS_ERR_FILE_IS_NOT_SECURE_AND_SIGN (-66) +#define SL_FS_ERASING_FLASH (-65) +#define SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY (-64) +#define SL_FS_WRONG_SIGNATURE (-63) +#define SL_FS_WRONG_SIGNATURE_OR_CERTIFIC_NAME_LENGTH (-62) +#define SL_FS_NOT_16_ALIGNED (-61) +#define SL_FS_CERT_CHAIN_ERROR (-60) +#define SL_FS_FILE_NAME_EXIST (-59) +#define SL_FS_SECURITY_BUF_ALREADY_ALLOC (-58) +#define SL_FS_SECURE_FILE_MUST_BE_COMMIT (-57) +#define SL_FS_ERR_INCORRECT_OFFSET_ALIGNMENT (-56) +#define SL_FS_ERR_FAILED_READ_NVMEM_HEADER (-55) +#define SL_FS_WRONG_FILE_NAME (-54) +#define SL_FS_FILE_SYSTEM_IS_LOCKED (-53) +#define SL_FS_SECURITY_ALLERT (-52) +#define SL_FS_FILE_UNVALID_FILE_SIZE (-51) +#define SL_FS_ERR_TOKEN_IS_NOT_VALID (-50) +#define SL_FS_NO_DEVICE_IS_LOADED (-49) +#define SL_FS_DATA_ADDRESS_SHOUD_BE_IN_DATA_RAM (-48) +#define SL_FS_DATA_IS_NOT_ALIGNED (-47) +#define SL_FS_ERR_OVERLAP_DETECTION_THRESHHOLD (-46) +#define SL_FS_FILE_HAS_RESERVED_NV_INDEX (-45) +#define SL_FS_ERR_MAX_FS_FILES_IS_LARGER (-44) +#define SL_FS_ERR_MAX_FS_FILES_IS_SMALLER (-43) +#define SL_FS_FILE_MAX_SIZE_EXCEEDED (-42) +#define SL_FS_INVALID_BUFFER_FOR_READ (-41) +#define SL_FS_INVALID_BUFFER_FOR_WRITE (-40) +#define SL_FS_ERR_FILE_IMAGE_IS_CORRUPTED (-39) +#define SL_FS_ERR_SIZE_OF_FILE_EXT_EXCEEDED (-38) +#define SL_FS_WARNING_FILE_NAME_NOT_KEPT (-37) +#define SL_FS_ERR_DEVICE_IS_NOT_FORMATTED (-36) +#define SL_FS_ERR_FAILED_WRITE_NVMEM_HEADER (-35) +#define SL_FS_ERR_NO_AVAILABLE_NV_INDEX (-34) +#define SL_FS_ERR_FAILED_TO_ALLOCATE_MEM (-33) +#define SL_FS_ERR_FAILED_TO_READ_INTEGRITY_HEADER_2 (-32) +#define SL_FS_ERR_FAILED_TO_READ_INTEGRITY_HEADER_1 (-31) +#define SL_FS_ERR_NO_AVAILABLE_BLOCKS (-30) +#define SL_FS_ERR_FILE_MAX_SIZE_BIGGER_THAN_EXISTING_FILE (-29) +#define SL_FS_ERR_FILE_EXISTS_ON_DIFFERENT_DEVICE_ID (-28) +#define SL_FS_ERR_INVALID_ACCESS_TYPE (-27) +#define SL_FS_ERR_FILE_ALREADY_EXISTS (-26) +#define SL_FS_ERR_PROGRAM (-25) +#define SL_FS_ERR_NO_ENTRIES_AVAILABLE (-24) +#define SL_FS_ERR_FILE_ACCESS_IS_DIFFERENT (-23) +#define SL_FS_ERR_BAD_FILE_MODE (-22) +#define SL_FS_ERR_FAILED_READ_NVFILE (-21) +#define SL_FS_ERR_FAILED_INIT_STORAGE (-20) +#define SL_FS_ERR_CONTINUE_WRITE_MUST_BE_MOD_4 (-19) +#define SL_FS_ERR_FAILED_LOAD_FILE (-18) +#define SL_FS_ERR_INVALID_HANDLE (-17) +#define SL_FS_ERR_FAILED_TO_WRITE (-16) +#define SL_FS_ERR_OFFSET_OUT_OF_RANGE (-15) +#define SL_FS_ERR_ALLOC (-14) +#define SL_FS_ERR_READ_DATA_LENGTH (-13) +#define SL_FS_ERR_INVALID_FILE_ID (-12) +#define SL_FS_ERR_FILE_NOT_EXISTS (-11) +#define SL_FS_ERR_EMPTY_ERROR (-10) +#define SL_FS_ERR_INVALID_ARGS (-9) +#define SL_FS_ERR_FAILED_TO_CREATE_FILE (-8) +#define SL_FS_ERR_FS_ALREADY_LOADED (-7) +#define SL_FS_ERR_UNKNOWN (-6) +#define SL_FS_ERR_FAILED_TO_CREATE_LOCK_OBJ (-5) +#define SL_FS_ERR_DEVICE_NOT_LOADED (-4) +#define SL_FS_ERR_INVALID_MAGIC_NUM (-3) +#define SL_FS_ERR_FAILED_TO_READ (-2) +#define SL_FS_ERR_NOT_SUPPORTED (-1) +/* end of error codes */ + +#define _FS_MODE_ACCESS_RESERVED_OFFSET (24) +#define _FS_MODE_ACCESS_RESERVED_MASK (0xFF) +#define _FS_MODE_ACCESS_FLAGS_OFFSET (16) +#define _FS_MODE_ACCESS_FLAGS_MASK (0xFF) +#define _FS_MODE_ACCESS_OFFSET (12) +#define _FS_MODE_ACCESS_MASK (0xF) +#define _FS_MODE_OPEN_SIZE_GRAN_OFFSET (8) +#define _FS_MODE_OPEN_SIZE_GRAN_MASK (0xF) +#define _FS_MODE_OPEN_SIZE_OFFSET (0) +#define _FS_MODE_OPEN_SIZE_MASK (0xFF) +#define MAX_MODE_SIZE (0xFF) +#define _FS_MODE(Access, SizeGran, Size,Flags) (_u32)(((_u32)((Access) & _FS_MODE_ACCESS_MASK)<<_FS_MODE_ACCESS_OFFSET) | \ + ((_u32)((SizeGran) & _FS_MODE_OPEN_SIZE_GRAN_MASK)<<_FS_MODE_OPEN_SIZE_GRAN_OFFSET) | \ + ((_u32)((Size) & _FS_MODE_OPEN_SIZE_MASK)<<_FS_MODE_OPEN_SIZE_OFFSET) | \ + ((_u32)((Flags) & _FS_MODE_ACCESS_FLAGS_MASK)<<_FS_MODE_ACCESS_FLAGS_OFFSET)) + + +/* sl_FsOpen options */ +/* Open for Read */ +#define FS_MODE_OPEN_READ _FS_MODE(_FS_MODE_OPEN_READ,0,0,0) +/* Open for Write (in case file exist) */ +#define FS_MODE_OPEN_WRITE _FS_MODE(_FS_MODE_OPEN_WRITE,0,0,0) +/* Open for Creating a new file */ +#define FS_MODE_OPEN_CREATE(maxSizeInBytes,accessModeFlags) _sl_GetCreateFsMode(maxSizeInBytes,accessModeFlags) + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ +typedef struct +{ + _u16 flags; + _u32 FileLen; + _u32 AllocatedLen; + _u32 Token[4]; +}SlFsFileInfo_t; + +typedef enum +{ + _FS_MODE_OPEN_READ = 0, + _FS_MODE_OPEN_WRITE, + _FS_MODE_OPEN_CREATE, + _FS_MODE_OPEN_WRITE_CREATE_IF_NOT_EXIST +}SlFsFileOpenAccessType_e; + +typedef enum +{ + _FS_FILE_OPEN_FLAG_COMMIT = 0x1, /* MIRROR - for fail safe */ + _FS_FILE_OPEN_FLAG_SECURE = 0x2, /* SECURE */ + _FS_FILE_OPEN_FLAG_NO_SIGNATURE_TEST = 0x4, /* Relevant to secure file only */ + _FS_FILE_OPEN_FLAG_STATIC = 0x8, /* Relevant to secure file only */ + _FS_FILE_OPEN_FLAG_VENDOR = 0x10, /* Relevant to secure file only */ + _FS_FILE_PUBLIC_WRITE= 0x20, /* Relevant to secure file only, the file can be opened for write without Token */ + _FS_FILE_PUBLIC_READ = 0x40 /* Relevant to secure file only, the file can be opened for read without Token */ +}SlFileOpenFlags_e; + +typedef enum +{ + _FS_MODE_SIZE_GRAN_256B = 0, /* MAX_SIZE = 64K */ + _FS_MODE_SIZE_GRAN_1KB, /* MAX_SIZE = 256K */ + _FS_MODE_SIZE_GRAN_4KB, /* MAX_SZIE = 1M */ + _FS_MODE_SIZE_GRAN_16KB, /* MAX_SIZE = 4M */ + _FS_MODE_SIZE_GRAN_64KB, /* MAX_SIZE = 16M */ + _FS_MAX_MODE_SIZE_GRAN +}_SlFsFileOpenMaxSizeGran_e; + +/*****************************************************************************/ +/* Internal Function prototypes */ +/*****************************************************************************/ +_u32 _sl_GetCreateFsMode(_u32 maxSizeInBytes,_u32 accessFlags); + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + +/*! + \brief open file for read or write from/to storage device + + \param[in] pFileName File Name buffer pointer + \param[in] AccessModeAndMaxSize Options: As described below + \param[in] pToken Reserved for future use. Use NULL for this field + \param[out] pFileHandle Pointing on the file and used for read and write commands to the file + + AccessModeAndMaxSize possible input \n + FS_MODE_OPEN_READ - Read a file \n + FS_MODE_OPEN_WRITE - Open for write for an existing file \n + FS_MODE_OPEN_CREATE(maxSizeInBytes,accessModeFlags) - Open for creating a new file. Max file size is defined in bytes. \n + For optimal FS size, use max size in 4K-512 bytes steps (e.g. 3584,7680,117760) \n + Several access modes bits can be combined together from SlFileOpenFlags_e enum + + \return On success, zero is returned. On error, an error code is returned + + \sa sl_FsRead sl_FsWrite sl_FsClose + \note belongs to \ref basic_api + \warning + \par Example: + \code + char* DeviceFileName = "MyFile.txt"; + unsigned long MaxSize = 63 * 1024; //62.5K is max file size + long DeviceFileHandle = -1; + long RetVal; //negative retval is an error + unsigned long Offset = 0; + unsigned char InputBuffer[100]; + + // Create a file and write data. The file in this example is secured, without signature and with a fail safe commit + RetVal = sl_FsOpen((unsigned char *)DeviceFileName, + FS_MODE_OPEN_CREATE(MaxSize , _FS_FILE_OPEN_FLAG_NO_SIGNATURE_TEST | _FS_FILE_OPEN_FLAG_COMMIT ), + NULL, &DeviceFileHandle); + + Offset = 0; + //Preferred in secure file that the Offset and the length will be aligned to 16 bytes. + RetVal = sl_FsWrite( DeviceFileHandle, Offset, (unsigned char *)"HelloWorld", strlen("HelloWorld")); + + RetVal = sl_FsClose(DeviceFileHandle, NULL, NULL , 0); + + // open the same file for read, using the Token we got from the creation procedure above + RetVal = sl_FsOpen((unsigned char *)DeviceFileName, + FS_MODE_OPEN_READ, + NULL, &DeviceFileHandle); + + Offset = 0; + RetVal = sl_FsRead( DeviceFileHandle, Offset, (unsigned char *)InputBuffer, strlen("HelloWorld")); + + RetVal = sl_FsClose(DeviceFileHandle, NULL, NULL , 0); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsOpen) +_i32 sl_FsOpen(const _u8 *pFileName,const _u32 AccessModeAndMaxSize,_u32 *pToken,_i32 *pFileHandle); +#endif + +/*! + \brief close file in storage device + + \param[in] FileHdl Pointer to the file (assigned from sl_FsOpen) + \param[in] pCeritificateFileName Reserved for future use. Use NULL. + \param[in] pSignature Reserved for future use. Use NULL. + \param[in] SignatureLen Reserved for future use. Use 0. + + + \return On success, zero is returned. On error, an error code is returned + + \sa sl_FsRead sl_FsWrite sl_FsOpen + \note Call the fs_Close with signature = 'A' signature len = 1 for activating an abort action + \warning + \par Example: + \code + sl_FsClose(FileHandle,0,0,0); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsClose) +_i16 sl_FsClose(const _i32 FileHdl,const _u8* pCeritificateFileName,const _u8* pSignature,const _u32 SignatureLen); +#endif + +/*! + \brief Read block of data from a file in storage device + + \param[in] FileHdl Pointer to the file (assigned from sl_FsOpen) + \param[in] Offset Offset to specific read block + \param[out] pData Pointer for the received data + \param[in] Len Length of the received data + + \return On success, returns the number of read bytes. On error, negative number is returned + + \sa sl_FsClose sl_FsWrite sl_FsOpen + \note belongs to \ref basic_api + \warning + \par Example: + \code + Status = sl_FsRead(FileHandle, 0, &readBuff[0], readSize); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsRead) +_i32 sl_FsRead(const _i32 FileHdl,_u32 Offset ,_u8* pData,_u32 Len); +#endif + +/*! + \brief write block of data to a file in storage device + + \param[in] FileHdl Pointer to the file (assigned from sl_FsOpen) + \param[in] Offset Offset to specific block to be written + \param[in] pData Pointer the transmitted data to the storage device + \param[in] Len Length of the transmitted data + + \return On success, returns the number of written bytes. On error, an error code is returned + + \sa + \note belongs to \ref basic_api + \warning + \par Example: + \code + Status = sl_FsWrite(FileHandle, 0, &buff[0], readSize); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsWrite) +_i32 sl_FsWrite(const _i32 FileHdl,_u32 Offset,_u8* pData,_u32 Len); +#endif + +/*! + \brief get info on a file + + \param[in] pFileName File name + \param[in] Token Reserved for future use. Use 0 + \param[out] pFsFileInfo Returns the File's Information: flags,file size, allocated size and Tokens + + \return On success, zero is returned. On error, an error code is returned + + \sa sl_FsOpen + \note belongs to \ref basic_api + \warning + \par Example: + \code + Status = sl_FsGetInfo("FileName.html",0,&FsFileInfo); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsGetInfo) +_i16 sl_FsGetInfo(const _u8 *pFileName,const _u32 Token,SlFsFileInfo_t* pFsFileInfo); +#endif + +/*! + \brief Delete specific file from a storage or all files from a storage (format) + + \param[in] pFileName File Name + \param[in] Token Reserved for future use. Use 0 + \return On success, zero is returned. On error, an error code is returned + + \sa + \note belongs to \ref basic_api + \warning + \par Example: + \code + Status = sl_FsDel("FileName.html",0); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_FsDel) +_i16 sl_FsDel(const _u8 *pFileName,const _u32 Token); +#endif +/*! + + Close the Doxygen group. + @} + + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FS_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/netapp.h b/src/openmv/src/micropython/drivers/cc3100/inc/netapp.h new file mode 100755 index 0000000..a968e7d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/netapp.h @@ -0,0 +1,884 @@ +/* + * netapp.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ + +#include "simplelink.h" + +#ifndef __NETAPP_H__ +#define __NETAPP_H__ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + + \addtogroup netapp + @{ + +*/ + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +/*ERROR code*/ +#define SL_ERROR_NETAPP_RX_BUFFER_LENGTH_ERROR (-230) + +/* Http Server interface */ +#define MAX_INPUT_STRING (64) /* because of WPA */ + +#define MAX_AUTH_NAME_LEN (20) +#define MAX_AUTH_PASSWORD_LEN (20) +#define MAX_AUTH_REALM_LEN (20) + +#define MAX_DEVICE_URN_LEN (15+1) +#define MAX_DOMAIN_NAME_LEN (24+1) + +#define MAX_ACTION_LEN (30) +/* Important: in case the max len is changed, make sure the struct sl_NetAppHttpServerSendToken_t in protocol.h is padded correctly! */ +#define MAX_TOKEN_NAME_LEN (20) +#define MAX_TOKEN_VALUE_LEN MAX_INPUT_STRING + +#define NETAPP_MAX_SERVICE_TEXT_SIZE (256) +#define NETAPP_MAX_SERVICE_NAME_SIZE (60) +#define NETAPP_MAX_SERVICE_HOST_NAME_SIZE (64) + + +/* Server Responses */ +#define SL_NETAPP_RESPONSE_NONE (0) +#define SL_NETAPP_HTTPSETTOKENVALUE (1) + +#define SL_NETAPP_FAMILY_MASK (0x80) + +/* mDNS types */ +#define SL_NET_APP_MASK_IPP_TYPE_OF_SERVICE (0x00000001) +#define SL_NET_APP_MASK_DEVICE_INFO_TYPE_OF_SERVICE (0x00000002) +#define SL_NET_APP_MASK_HTTP_TYPE_OF_SERVICE (0x00000004) +#define SL_NET_APP_MASK_HTTPS_TYPE_OF_SERVICE (0x00000008) +#define SL_NET_APP_MASK_WORKSATION_TYPE_OF_SERVICE (0x00000010) +#define SL_NET_APP_MASK_GUID_TYPE_OF_SERVICE (0x00000020) +#define SL_NET_APP_MASK_H323_TYPE_OF_SERVICE (0x00000040) +#define SL_NET_APP_MASK_NTP_TYPE_OF_SERVICE (0x00000080) +#define SL_NET_APP_MASK_OBJECITVE_TYPE_OF_SERVICE (0x00000100) +#define SL_NET_APP_MASK_RDP_TYPE_OF_SERVICE (0x00000200) +#define SL_NET_APP_MASK_REMOTE_TYPE_OF_SERVICE (0x00000400) +#define SL_NET_APP_MASK_RTSP_TYPE_OF_SERVICE (0x00000800) +#define SL_NET_APP_MASK_SIP_TYPE_OF_SERVICE (0x00001000) +#define SL_NET_APP_MASK_SMB_TYPE_OF_SERVICE (0x00002000) +#define SL_NET_APP_MASK_SOAP_TYPE_OF_SERVICE (0x00004000) +#define SL_NET_APP_MASK_SSH_TYPE_OF_SERVICE (0x00008000) +#define SL_NET_APP_MASK_TELNET_TYPE_OF_SERVICE (0x00010000) +#define SL_NET_APP_MASK_TFTP_TYPE_OF_SERVICE (0x00020000) +#define SL_NET_APP_MASK_XMPP_CLIENT_TYPE_OF_SERVICE (0x00040000) +#define SL_NET_APP_MASK_RAOP_TYPE_OF_SERVICE (0x00080000) +#define SL_NET_APP_MASK_ALL_TYPE_OF_SERVICE (0xFFFFFFFF) + +/********************************************************************************************************/ +/* sl_NetAppDnsGetHostByName error codes */ + +#define SL_NET_APP_DNS_QUERY_NO_RESPONSE (-159) /* DNS query failed, no response */ +#define SL_NET_APP_DNS_NO_SERVER (-161) /* No DNS server was specified */ +#define SL_NET_APP_DNS_PARAM_ERROR (-162) /* mDNS parameters error */ +#define SL_NET_APP_DNS_QUERY_FAILED (-163) /* DNS query failed; no DNS server sent an 'answer' */ +#define SL_NET_APP_DNS_INTERNAL_1 (-164) +#define SL_NET_APP_DNS_INTERNAL_2 (-165) +#define SL_NET_APP_DNS_MALFORMED_PACKET (-166) /* Improperly formed or corrupted DNS packet received */ +#define SL_NET_APP_DNS_INTERNAL_3 (-167) +#define SL_NET_APP_DNS_INTERNAL_4 (-168) +#define SL_NET_APP_DNS_INTERNAL_5 (-169) +#define SL_NET_APP_DNS_INTERNAL_6 (-170) +#define SL_NET_APP_DNS_INTERNAL_7 (-171) +#define SL_NET_APP_DNS_INTERNAL_8 (-172) +#define SL_NET_APP_DNS_INTERNAL_9 (-173) +#define SL_NET_APP_DNS_MISMATCHED_RESPONSE (-174) /* Server response type does not match the query request*/ +#define SL_NET_APP_DNS_INTERNAL_10 (-175) +#define SL_NET_APP_DNS_INTERNAL_11 (-176) +#define SL_NET_APP_DNS_NO_ANSWER (-177) /* No response for one-shot query */ +#define SL_NET_APP_DNS_NO_KNOWN_ANSWER (-178) /* No known answer for query */ +#define SL_NET_APP_DNS_NAME_MISMATCH (-179) /* Illegal service name according to the RFC */ +#define SL_NET_APP_DNS_NOT_STARTED (-180) /* mDNS is not running */ +#define SL_NET_APP_DNS_HOST_NAME_ERROR (-181) /* Host name error. Host name format is not allowed according to RFC 1033,1034,1035, 6763 */ +#define SL_NET_APP_DNS_NO_MORE_ENTRIES (-182) /* No more entries be found. */ + +#define SL_NET_APP_DNS_MAX_SERVICES_ERROR (-200) /* Maximum advertise services are already configured */ +#define SL_NET_APP_DNS_IDENTICAL_SERVICES_ERROR (-201) /* Trying to register a service that is already exists */ +#define SL_NET_APP_DNS_NOT_EXISTED_SERVICE_ERROR (-203) /* Trying to delete service that does not existed */ +#define SL_NET_APP_DNS_ERROR_SERVICE_NAME_ERROR (-204) /* Illegal service name according to the RFC */ +#define SL_NET_APP_DNS_RX_PACKET_ALLOCATION_ERROR (-205) /* Retry request */ +#define SL_NET_APP_DNS_BUFFER_SIZE_ERROR (-206) /* List size buffer is bigger than internally allowed in the NWP */ +#define SL_NET_APP_DNS_NET_APP_SET_ERROR (-207) /* Illegal length of one of the mDNS Set functions */ +#define SL_NET_APP_DNS_GET_SERVICE_LIST_FLAG_ERROR (-208) +#define SL_NET_APP_DNS_NO_CONFIGURATION_ERROR (-209) + +/* Set Dev name error codes (NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN) */ +#define SL_ERROR_DEVICE_NAME_LEN_ERR (-117) +#define SL_ERROR_DEVICE_NAME_INVALID (-118) +/* Set domain name error codes (NETAPP_SET_GET_DEV_CONF_OPT_DOMAIN_NAME) */ +#define SL_ERROR_DOMAIN_NAME_LEN_ERR (-119) +#define SL_ERROR_DOMAIN_NAME_INVALID (-120) + +/********************************************************************************************************/ + +/* NetApp application IDs */ +#define SL_NET_APP_HTTP_SERVER_ID (1) +#define SL_NET_APP_DHCP_SERVER_ID (2) +#define SL_NET_APP_MDNS_ID (4) +#define SL_NET_APP_DNS_SERVER_ID (8) +#define SL_NET_APP_DEVICE_CONFIG_ID (16) +/* NetApp application set/get options */ +#define NETAPP_SET_DHCP_SRV_BASIC_OPT (0) +/* HTTP server set/get options */ +#define NETAPP_SET_GET_HTTP_OPT_PORT_NUMBER (0) +#define NETAPP_SET_GET_HTTP_OPT_AUTH_CHECK (1) +#define NETAPP_SET_GET_HTTP_OPT_AUTH_NAME (2) +#define NETAPP_SET_GET_HTTP_OPT_AUTH_PASSWORD (3) +#define NETAPP_SET_GET_HTTP_OPT_AUTH_REALM (4) +#define NETAPP_SET_GET_HTTP_OPT_ROM_PAGES_ACCESS (5) + +#define NETAPP_SET_GET_MDNS_CONT_QUERY_OPT (1) +#define NETAPP_SET_GET_MDNS_QEVETN_MASK_OPT (2) +#define NETAPP_SET_GET_MDNS_TIMING_PARAMS_OPT (3) + +/* DNS server set/get options */ +#define NETAPP_SET_GET_DNS_OPT_DOMAIN_NAME (0) + +/* Device Config set/get options */ +#define NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN (0) +#define NETAPP_SET_GET_DEV_CONF_OPT_DOMAIN_NAME (1) + + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ + +typedef struct +{ + _u32 PacketsSent; + _u32 PacketsReceived; + _u16 MinRoundTime; + _u16 MaxRoundTime; + _u16 AvgRoundTime; + _u32 TestTime; +}SlPingReport_t; + +typedef struct +{ + _u32 PingIntervalTime; /* delay between pings, in milliseconds */ + _u16 PingSize; /* ping packet size in bytes */ + _u16 PingRequestTimeout; /* timeout time for every ping in milliseconds */ + _u32 TotalNumberOfAttempts; /* max number of ping requests. 0 - forever */ + _u32 Flags; /* flag - 0 report only when finished, 1 - return response for every ping, 2 - stop after 1 successful ping. */ + _u32 Ip; /* IPv4 address or IPv6 first 4 bytes */ + _u32 Ip1OrPaadding; + _u32 Ip2OrPaadding; + _u32 Ip3OrPaadding; +}SlPingStartCommand_t; + +typedef struct _slHttpServerString_t +{ + _u8 len; + _u8 *data; +} slHttpServerString_t; + +typedef struct _slHttpServerData_t +{ + _u8 value_len; + _u8 name_len; + _u8 *token_value; + _u8 *token_name; +} slHttpServerData_t; + +typedef struct _slHttpServerPostData_t +{ + slHttpServerString_t action; + slHttpServerString_t token_name; + slHttpServerString_t token_value; +}slHttpServerPostData_t; + +typedef union +{ + slHttpServerString_t httpTokenName; /* SL_NETAPP_HTTPGETTOKENVALUE */ + slHttpServerPostData_t httpPostData; /* SL_NETAPP_HTTPPOSTTOKENVALUE */ +} SlHttpServerEventData_u; + +typedef union +{ + slHttpServerString_t token_value; +} SlHttpServerResponsedata_u; + +typedef struct +{ + _u32 Event; + SlHttpServerEventData_u EventData; +}SlHttpServerEvent_t; + +typedef struct +{ + _u32 Response; + SlHttpServerResponsedata_u ResponseData; +}SlHttpServerResponse_t; + + +typedef struct +{ + _u32 lease_time; + _u32 ipv4_addr_start; + _u32 ipv4_addr_last; +}SlNetAppDhcpServerBasicOpt_t; + +/*mDNS parameters*/ +typedef enum +{ + SL_NET_APP_FULL_SERVICE_WITH_TEXT_IPV4_TYPE = 1, + SL_NET_APP_FULL_SERVICE_IPV4_TYPE, + SL_NET_APP_SHORT_SERVICE_IPV4_TYPE + +} SlNetAppGetServiceListType_e; + +typedef struct +{ + _u32 service_ipv4; + _u16 service_port; + _u16 Reserved; +}SlNetAppGetShortServiceIpv4List_t; + +typedef struct +{ + _u32 service_ipv4; + _u16 service_port; + _u16 Reserved; + _u8 service_name[NETAPP_MAX_SERVICE_NAME_SIZE]; + _u8 service_host[NETAPP_MAX_SERVICE_HOST_NAME_SIZE]; +}SlNetAppGetFullServiceIpv4List_t; + +typedef struct +{ + _u32 service_ipv4; + _u16 service_port; + _u16 Reserved; + _u8 service_name[NETAPP_MAX_SERVICE_NAME_SIZE]; + _u8 service_host[NETAPP_MAX_SERVICE_HOST_NAME_SIZE]; + _u8 service_text[NETAPP_MAX_SERVICE_TEXT_SIZE]; +}SlNetAppGetFullServiceWithTextIpv4List_t; + +typedef struct +{ + /*The below parameters are used to configure the advertise times and interval + For example: + If: + Period is set to T + Repetitions are set to P + Telescopic factor is K=2 + The transmission shall be: + advertise P times + wait T + advertise P times + wait 4 * T + advertise P time + wait 16 * T ... (till max time reached / configuration changed / query issued) + */ + _u32 t; /* Number of ticks for the initial period. Default is 100 ticks for 1 second. */ + _u32 p; /* Number of repetitions. Default value is 1 */ + _u32 k; /* Telescopic factor. Default value is 2. */ + _u32 RetransInterval;/* Announcing retransmission interval */ + _u32 Maxinterval; /* Announcing max period interval */ + _u32 max_time; /* Announcing max time */ +}SlNetAppServiceAdvertiseTimingParameters_t; + +/*****************************************************************************/ +/* Types declarations */ +/*****************************************************************************/ +typedef void (*P_SL_DEV_PING_CALLBACK)(SlPingReport_t*); + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + + +/*! + \brief Starts a network application + + Gets and starts network application for the current WLAN mode + + \param[in] AppBitMap application bitmap, could be one or combination of the following: \n + - SL_NET_APP_HTTP_SERVER_ID + - SL_NET_APP_DHCP_SERVER_ID + - SL_NET_APP_MDNS_ID + + \return On error, negative number is returned + + \sa Stop one or more the above started applications using sl_NetAppStop + \note This command activates the application for the current WLAN mode (AP or STA) + \warning + \par Example: + \code + For example: Starting internal HTTP server + DHCP server: + sl_NetAppStart(SL_NET_APP_HTTP_SERVER_ID | SL_NET_APP_DHCP_SERVER_ID) + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppStart) +_i16 sl_NetAppStart(const _u32 AppBitMap); +#endif +/*! + \brief Stops a network application + + Gets and stops network application for the current WLAN mode + + \param[in] AppBitMap application id, could be one of the following: \n + - SL_NET_APP_HTTP_SERVER_ID + - SL_NET_APP_DHCP_SERVER_ID + - SL_NET_APP_MDNS_ID + + \return On error, negative number is returned + + \sa + \note This command disables the application for the current active WLAN mode (AP or STA) + \warning + \par Example: + \code + + For example: Stopping internal HTTP server: + sl_NetAppStop(SL_NET_APP_HTTP_SERVER_ID); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppStop) +_i16 sl_NetAppStop(const _u32 AppBitMap); +#endif + +/*! + \brief Get host IP by name + + Obtain the IP Address of machine on network, by machine name. + + \param[in] hostname host name + \param[in] usNameLen name length + \param[out] out_ip_addr This parameter is filled in with + host IP address. In case that host name is not + resolved, out_ip_addr is zero. + \param[in] family protocol family + + \return On success, 0 is returned. + On error, negative is returned + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + Possible DNS error codes: + - SL_NET_APP_DNS_QUERY_NO_RESPONSE + - SL_NET_APP_DNS_NO_SERVER + - SL_NET_APP_DNS_QUERY_FAILED + - SL_NET_APP_DNS_MALFORMED_PACKET + - SL_NET_APP_DNS_MISMATCHED_RESPONSE + + \sa + \note Only one sl_NetAppDnsGetHostByName can be handled at a time. + Calling this API while the same command is called from another thread, may result + in one of the two scenarios: + 1. The command will wait (internal) until the previous command finish, and then be executed. + 2. There are not enough resources and POOL_IS_EMPTY error will return. + In this case, MAX_CONCURRENT_ACTIONS can be increased (result in memory increase) or try + again later to issue the command. + \warning + In case an IP address in a string format is set as input, without any prefix (e.g. "1.2.3.4") the device will not + try to access the DNS and it will return the input address on the 'out_ip_addr' field + \par Example: + \code + _u32 DestinationIP; + sl_NetAppDnsGetHostByName("www.google.com", strlen("www.google.com"), &DestinationIP,SL_AF_INET); + + Addr.sin_family = SL_AF_INET; + Addr.sin_port = sl_Htons(80); + Addr.sin_addr.s_addr = sl_Htonl(DestinationIP); + AddrSize = sizeof(SlSockAddrIn_t); + SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppDnsGetHostByName) +_i16 sl_NetAppDnsGetHostByName(_i8 * hostname,const _u16 usNameLen, _u32* out_ip_addr,const _u8 family ); +#endif + +/*! + \brief Return service attributes like IP address, port and text according to service name + \par + The user sets a service name Full/Part (see example below), and should get: + - IP of service + - The port of service + - The text of service + + Hence it can make a connection to the specific service and use it. + It is similar to get host by name method. + It is done by a single shot query with PTR type on the service name. + The command that is sent is from constant parameters and variables parameters. + + \param[in] pService Service name can be full or partial. \n + Example for full service name: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local \n + . + Example for partial service name: + 1. _ipp._tcp.local + 2. _ftp._tcp.local + + \param[in] ServiceLen The length of the service name (in_pService). + \param[in] Family IPv4 or IPv6 (SL_AF_INET , SL_AF_INET6). + \param[out] pAddr Contains the IP address of the service. + \param[out] pPort Contains the port of the service. + \param[out] pTextLen Has 2 options. One as Input field and the other one as output: + - Input: \n + Contains the max length of the text that the user wants to get.\n + It means that if the text len of service is bigger that its value than + the text is cut to inout_TextLen value. + - Output: \n + Contain the length of the text that is returned. Can be full text or part of the text (see above). + + \param[out] pOut_pText Contains the text of the service full or partial + + \return On success, zero is returned + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + In case No service is found error SL_NET_APP_DNS_NO_ANSWER will be returned + + \note The returns attributes belongs to the first service found. + There may be other services with the same service name that will response to the query. + The results of these responses are saved in the peer cache of the Device and should be read by another API. + + Only one sl_NetAppDnsGetHostByService can be handled at a time. + Calling this API while the same command is called from another thread, may result + in one of the two scenarios: + 1. The command will wait (internal) until the previous command finish, and then be executed. + 2. There are not enough resources and SL_POOL_IS_EMPTY error will return. + In this case, MAX_CONCURRENT_ACTIONS can be increased (result in memory increase) or try + again later to issue the command. + + \warning Text length can be 120 bytes only +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppDnsGetHostByService) +_i32 sl_NetAppDnsGetHostByService(_i8 *pServiceName, /* string containing all (or only part): name + subtype + service */ + const _u8 ServiceLen, + const _u8 Family, /* 4-IPv4 , 16-IPv6 */ + _u32 pAddr[], + _u32 *pPort, + _u16 *pTextLen, /* in: max len , out: actual len */ + _i8 *pText + ); + +#endif + +/*! + \brief Get service List + Insert into out pBuffer a list of peer's services that are the NWP. + The list is in a form of service struct. The user should chose the type + of the service struct like: + - Full service parameters with text. + - Full service parameters. + - Short service parameters (port and IP only) especially for tiny hosts. + + The different types of struct are made to give the + Possibility to save memory in the host + + + The user also chose how many max services to get and start point index + NWP peer cache. + For example: + 1. Get max of 3 full services from index 0.Up to 3 full services + from index 0 are inserted into pBuffer (services that are in indexes 0,1,2). + 2. Get max of 4 full services from index 3.Up to 4 full services + from index 3 are inserted into pBuffer (services that are in indexes 3,4,5,6). + 3. Get max of 2 int services from index 6.Up to 2 int services + from index 6 are inserted into pBuffer (services that are in indexes 6,7). + + See below - command parameters. + + \param[in] indexOffset - The start index in the peer cache that from it the first service is returned. + \param[in] MaxServiceCount - The Max services that can be returned if existed or if not exceed the max index + in the peer cache + \param[in] Flags - an ENUM number that means which service struct to use (means which types of service to fill) + - use SlNetAppGetFullServiceWithTextIpv4List_t + - use SlNetAppGetFullServiceIpv4List_t + - use SlNetAppGetShortServiceIpv4List_t + + \param[out] Buffer - The Services are inserted into this buffer. In the struct form according to the bit that is set in the Flags + input parameter. + + \return ServiceFoundCount - The number of the services that were inserted into the buffer. zero means no service is found + negative number means an error + \sa sl_NetAppMDNSRegisterService + \note + \warning + if the out pBuffer size is bigger than an RX packet(1480), than + an error is returned because there + is no place in the RX packet. + The size is a multiply of MaxServiceCount and size of service struct(that is set + according to flag value). +*/ + +#if _SL_INCLUDE_FUNC(sl_NetAppGetServiceList) +_i16 sl_NetAppGetServiceList(const _u8 IndexOffest, + const _u8 MaxServiceCount, + const _u8 Flags, + _i8 *pBuffer, + const _u32 RxBufferLength + ); + +#endif + +/*! + \brief Unregister mDNS service + This function deletes the mDNS service from the mDNS package and the database. + + The mDNS service that is to be unregistered is a service that the application no longer wishes to provide. \n + The service name should be the full service name according to RFC + of the DNS-SD - meaning the value in name field in the SRV answer. + + Examples for service names: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + + \param[in] pServiceName Full service name. \n + Example for service name: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + \param[in] ServiceLen The length of the service. + \return On success, zero is returned + \sa sl_NetAppMDNSRegisterService + \note + \warning + The size of the service length should be smaller than 255. +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppMDNSUnRegisterService) +_i16 sl_NetAppMDNSUnRegisterService(const _i8 *pServiceName,const _u8 ServiceNameLen); +#endif + +/*! + \brief Register a new mDNS service + \par + This function registers a new mDNS service to the mDNS package and the DB. + + This registered service is a service offered by the application. + The service name should be full service name according to RFC + of the DNS-SD - meaning the value in name field in the SRV answer. + Example for service name: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + + If the option is_unique is set, mDNS probes the service name to make sure + it is unique before starting to announce the service on the network. + Instance is the instance portion of the service name. + + \param[in] ServiceLen The length of the service. + \param[in] TextLen The length of the service should be smaller than 64. + \param[in] port The port on this target host port. + \param[in] TTL The TTL of the service + \param[in] Options bitwise parameters: \n + - bit 0 - service is unique (means that the service needs to be unique) + - bit 31 - for internal use if the service should be added or deleted (set means ADD). + - bit 1-30 for future. + + \param[in] pServiceName The service name. + Example for service name: \n + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + + \param[in] pText The description of the service. + should be as mentioned in the RFC + (according to type of the service IPP,FTP...) + + \return On success, zero is returned + Possible error codes: + - Maximum advertise services are already configured. + Delete another existed service that is registered and then register again the new service + - Trying to register a service that is already exists + - Trying to delete service that does not existed + - Illegal service name according to the RFC + - Retry request + - Illegal length of one of the mDNS Set functions + - mDNS is not operational as the device has no IP.Connect the device to an AP to get an IP address. + - mDNS parameters error + - mDNS internal cache error + - mDNS internal error + - Adding a service is not allowed as it is already exist (duplicate service) + - mDNS is not running + - Host name error. Host name format is not allowed according to RFC 1033,1034,1035, 6763 + - List size buffer is bigger than internally allowed in the NWP (API get service list), + change the APIs’ parameters to decrease the size of the list + + + \sa sl_NetAppMDNSUnRegisterService + + \warning 1) Temporary - there is an allocation on stack of internal buffer. + Its size is NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. \n + It means that the sum of the text length and service name length cannot be bigger than + NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH.\n + If it is - An error is returned. \n + 2) According to now from certain constraints the variables parameters are set in the + attribute part (contain constant parameters) +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppMDNSRegisterService) +_i16 sl_NetAppMDNSRegisterService( const _i8* pServiceName, + const _u8 ServiceNameLen, + const _i8* pText, + const _u8 TextLen, + const _u16 Port, + const _u32 TTL, + _u32 Options); +#endif + +/*! + \brief send ICMP ECHO_REQUEST to network hosts + + Ping uses the ICMP protocol's mandatory ECHO_REQUEST + + \param[in] pPingParams Pointer to the ping request structure: \n + - if flags parameter is set to 0, ping will report back once all requested pings are done (as defined by TotalNumberOfAttempts). \n + - if flags parameter is set to 1, ping will report back after every ping, for TotalNumberOfAttempts. + - if flags parameter is set to 2, ping will stop after the first successful ping, and report back for the successful ping, as well as any preceding failed ones. + For stopping an ongoing ping activity, set parameters IP address to 0 + + \param[in] family SL_AF_INET or SL_AF_INET6 + \param[out] pReport Ping pReport + \param[out] pCallback Callback function upon completion. + If callback is NULL, the API is blocked until data arrives + + + \return On success, zero is returned. On error, -1 is returned + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_NetAppPingReport + \note Only one sl_NetAppPingStart can be handled at a time. + Calling this API while the same command is called from another thread, may result + in one of the two scenarios: + 1. The command will wait (internal) until the previous command finish, and then be executed. + 2. There are not enough resources and SL_POOL_IS_EMPTY error will return. + In this case, MAX_CONCURRENT_ACTIONS can be increased (result in memory increase) or try + again later to issue the command. + \warning + \par Example: + \code + + An example of sending 20 ping requests and reporting results to a callback routine when + all requests are sent: + + // callback routine + void pingRes(SlPingReport_t* pReport) + { + // handle ping results + } + + // ping activation + void PingTest() + { + SlPingReport_t report; + SlPingStartCommand_t pingCommand; + + pingCommand.Ip = SL_IPV4_VAL(10,1,1,200); // destination IP address is 10.1.1.200 + pingCommand.PingSize = 150; // size of ping, in bytes + pingCommand.PingIntervalTime = 100; // delay between pings, in milliseconds + pingCommand.PingRequestTimeout = 1000; // timeout for every ping in milliseconds + pingCommand.TotalNumberOfAttempts = 20; // max number of ping requests. 0 - forever + pingCommand.Flags = 0; // report only when finished + + sl_NetAppPingStart( &pingCommand, SL_AF_INET, &report, pingRes ) ; + } + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppPingStart) +_i16 sl_NetAppPingStart(const SlPingStartCommand_t* pPingParams,const _u8 family,SlPingReport_t *pReport,const P_SL_DEV_PING_CALLBACK pPingCallback); +#endif + +/*! + \brief Internal function for setting network application configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] AppId Application id, could be one of the following: \n + - SL_NET_APP_HTTP_SERVER_ID + - SL_NET_APP_DHCP_SERVER_ID + - SL_NET_APP_MDNS_ID + - SL_NET_APP_DEVICE_CONFIG_ID + + \param[in] SetOptions set option, could be one of the following: \n + - SL_NET_APP_DHCP_SERVER_ID + - NETAPP_SET_DHCP_SRV_BASIC_OPT + - SL_NET_APP_HTTP_SERVER_ID + - NETAPP_SET_GET_HTTP_OPT_PORT_NUMBER + - NETAPP_SET_GET_HTTP_OPT_AUTH_CHECK + - NETAPP_SET_GET_HTTP_OPT_AUTH_NAME + - NETAPP_SET_GET_HTTP_OPT_AUTH_PASSWORD + - NETAPP_SET_GET_HTTP_OPT_AUTH_REALM + - NETAPP_SET_GET_HTTP_OPT_ROM_PAGES_ACCESS + - SL_NET_APP_MDNS_ID + - NETAPP_SET_GET_MDNS_CONT_QUERY_OPT + - NETAPP_SET_GET_MDNS_QEVETN_MASK_OPT + - NETAPP_SET_GET_MDNS_TIMING_PARAMS_OPT + - SL_NET_APP_DEVICE_CONFIG_ID + - NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN + - NETAPP_SET_GET_DEV_CONF_OPT_DOMAIN_NAME + + + \param[in] OptionLen option structure length + + \param[in] pOptionValues pointer to the option structure + \sa + \note + \warning + \par + \code + Set DHCP Server (AP mode) parameters example: + + SlNetAppDhcpServerBasicOpt_t dhcpParams; + _u8 outLen = sizeof(SlNetAppDhcpServerBasicOpt_t); + dhcpParams.lease_time = 4096; // lease time (in seconds) of the IP Address + dhcpParams.ipv4_addr_start = SL_IPV4_VAL(192,168,1,10); // first IP Address for allocation. IP Address should be set as Hex number - i.e. 0A0B0C01 for (10.11.12.1) + dhcpParams.ipv4_addr_last = SL_IPV4_VAL(192,168,1,16); // last IP Address for allocation. IP Address should be set as Hex number - i.e. 0A0B0C01 for (10.11.12.1) + sl_NetAppStop(SL_NET_APP_DHCP_SERVER_ID); // Stop DHCP server before settings + sl_NetAppSet(SL_NET_APP_DHCP_SERVER_ID, NETAPP_SET_DHCP_SRV_BASIC_OPT, outLen, (_u8* )&dhcpParams); // set parameters + sl_NetAppStart(SL_NET_APP_DHCP_SERVER_ID); // Start DHCP server with new settings + \endcode + \code + Set Device URN name example: + + Device name, maximum length of 33 characters + Device name affects URN name, own SSID name in AP mode, and WPS file "device name" in WPS I.E (STA-WPS / P2P) + In case no device URN name set, the default name is "mysimplelink" + Allowed characters in device name are: 'a - z' , 'A - Z' , '0-9' and '-' + + _u8 *my_device = "MY-SIMPLELINK-DEV"; + sl_NetAppSet (SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, strlen(my_device), (_u8 *) my_device); + \endcode + +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppSet) +_i32 sl_NetAppSet(const _u8 AppId ,const _u8 Option,const _u8 OptionLen,const _u8 *pOptionValue); +#endif + +/*! + \brief Internal function for getting network applications configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] AppId Application id, could be one of the following: \n + - SL_NET_APP_HTTP_SERVER_ID + - SL_NET_APP_DHCP_SERVER_ID + - SL_NET_APP_MDNS_ID + - SL_NET_APP_DEVICE_CONFIG_ID + + \param[in] SetOptions set option, could be one of the following: \n + - SL_NET_APP_DHCP_SERVER_ID + - NETAPP_SET_DHCP_SRV_BASIC_OPT + - SL_NET_APP_HTTP_SERVER_ID + - NETAPP_SET_GET_HTTP_OPT_PORT_NUMBER + - NETAPP_SET_GET_HTTP_OPT_AUTH_CHECK + - NETAPP_SET_GET_HTTP_OPT_AUTH_NAME + - NETAPP_SET_GET_HTTP_OPT_AUTH_PASSWORD + - NETAPP_SET_GET_HTTP_OPT_AUTH_REALM + - NETAPP_SET_GET_HTTP_OPT_ROM_PAGES_ACCESS + - SL_NET_APP_MDNS_ID + - NETAPP_SET_GET_MDNS_CONT_QUERY_OPT + - NETAPP_SET_GET_MDNS_QEVETN_MASK_OPT + - NETAPP_SET_GET_MDNS_TIMING_PARAMS_OPT + - SL_NET_APP_DEVICE_CONFIG_ID + - NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN + - NETAPP_SET_GET_DEV_CONF_OPT_DOMAIN_NAME + + + \param[in] OptionLen The length of the allocated memory as input, when the + function complete, the value of this parameter would be + the len that actually read from the device. + If the device return length that is longer from the input + value, the function will cut the end of the returned structure + and will return ESMALLBUF + + \param[out] pValues pointer to the option structure which will be filled with the response from the device + + \sa + \note + \warning + \par + \code + Get DHCP Server parameters example: + + SlNetAppDhcpServerBasicOpt_t dhcpParams; + _u8 outLen = sizeof(SlNetAppDhcpServerBasicOpt_t); + sl_NetAppGet(SL_NET_APP_DHCP_SERVER_ID, NETAPP_SET_DHCP_SRV_BASIC_OPT, &outLen, (_u8* )&dhcpParams); + + printf("DHCP Start IP %d.%d.%d.%d End IP %d.%d.%d.%d Lease time seconds %d\n", + SL_IPV4_BYTE(dhcpParams.ipv4_addr_start,3),SL_IPV4_BYTE(dhcpParams.ipv4_addr_start,2), + SL_IPV4_BYTE(dhcpParams.ipv4_addr_start,1),SL_IPV4_BYTE(dhcpParams.ipv4_addr_start,0), + SL_IPV4_BYTE(dhcpParams.ipv4_addr_last,3),SL_IPV4_BYTE(dhcpParams.ipv4_addr_last,2), + SL_IPV4_BYTE(dhcpParams.ipv4_addr_last,1),SL_IPV4_BYTE(dhcpParams.ipv4_addr_last,0), + dhcpParams.lease_time); + \endcode + \code + Get Device URN name example: + Maximum length of 33 characters of device name. + Device name affects URN name, own SSID name in AP mode, and WPS file "device name" in WPS I.E (STA-WPS / P2P) + in case no device URN name set, the default name is "mysimplelink" + + _u8 my_device_name[35]; + sl_NetAppGet (SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, strlen(my_device_name), (_u8 *)my_device_name); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_NetAppGet) +_i32 sl_NetAppGet(const _u8 AppId,const _u8 Option,_u8 *pOptionLen, _u8 *pOptionValue); +#endif + + + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __NETAPP_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/netcfg.h b/src/openmv/src/micropython/drivers/cc3100/inc/netcfg.h new file mode 100755 index 0000000..cc8cfbc --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/netcfg.h @@ -0,0 +1,283 @@ +/* + * netcfg.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + + +#ifndef __NETCFG_H__ +#define __NETCFG_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +/*! + + \addtogroup netcfg + @{ + +*/ + + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +#define SL_MAC_ADDR_LEN (6) +#define SL_IPV4_VAL(add_3,add_2,add_1,add_0) ((((_u32)add_3 << 24) & 0xFF000000) | (((_u32)add_2 << 16) & 0xFF0000) | (((_u32)add_1 << 8) & 0xFF00) | ((_u32)add_0 & 0xFF) ) +#define SL_IPV4_BYTE(val,index) ( (val >> (index*8)) & 0xFF ) + +#define IPCONFIG_MODE_DISABLE_IPV4 (0) +#define IPCONFIG_MODE_ENABLE_IPV4 (1) + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ +typedef enum +{ + SL_MAC_ADDRESS_SET = 1, + SL_MAC_ADDRESS_GET = 2, + SL_IPV4_STA_P2P_CL_GET_INFO = 3, + SL_IPV4_STA_P2P_CL_DHCP_ENABLE = 4, + SL_IPV4_STA_P2P_CL_STATIC_ENABLE = 5, + SL_IPV4_AP_P2P_GO_GET_INFO = 6, + SL_IPV4_AP_P2P_GO_STATIC_ENABLE = 7, + SL_SET_HOST_RX_AGGR = 8, + MAX_SETTINGS = 0xFF +}Sl_NetCfg_e; + + +typedef struct +{ + _u32 ipV4; + _u32 ipV4Mask; + _u32 ipV4Gateway; + _u32 ipV4DnsServer; +}SlNetCfgIpV4Args_t; + + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + +/*! + \brief Internal function for setting network configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] ConfigId configuration id + \param[in] ConfigOpt configurations option + \param[in] ConfigLen configurations len + \param[in] pValues configurations values + + \sa + \note + \warning + + \par Examples: + \code + SL_MAC_ADDRESS_SET: + + Setting MAC address to the Device. + The new MAC address will override the default MAC address and it be saved in the FileSystem. + Requires restarting the device for updating this setting. + + _u8 MAC_Address[6]; + MAC_Address[0] = 0x8; + MAC_Address[1] = 0x0; + MAC_Address[2] = 0x28; + MAC_Address[3] = 0x22; + MAC_Address[4] = 0x69; + MAC_Address[5] = 0x31; + sl_NetCfgSet(SL_MAC_ADDRESS_SET,1,SL_MAC_ADDR_LEN,(_u8 *)newMacAddress); + sl_Stop(0); + sl_Start(NULL,NULL,NULL); + \endcode + + \code + SL_IPV4_STA_P2P_CL_STATIC_ENABLE: + + Setting a static IP address to the device working in STA mode or P2P client. + The IP address will be stored in the FileSystem. + In order to disable the static IP and get the address assigned from DHCP one should use SL_STA_P2P_CL_IPV4_DHCP_SET + + SlNetCfgIpV4Args_t ipV4; + ipV4.ipV4 = (_u32)SL_IPV4_VAL(10,1,1,201); // _u32 IP address + ipV4.ipV4Mask = (_u32)SL_IPV4_VAL(255,255,255,0); // _u32 Subnet mask for this STA/P2P + ipV4.ipV4Gateway = (_u32)SL_IPV4_VAL(10,1,1,1); // _u32 Default gateway address + ipV4.ipV4DnsServer = (_u32)SL_IPV4_VAL(8,16,32,64); // _u32 DNS server address + + sl_NetCfgSet(SL_IPV4_STA_P2P_CL_STATIC_ENABLE,IPCONFIG_MODE_ENABLE_IPV4,sizeof(SlNetCfgIpV4Args_t),(_u8 *)&ipV4); + sl_Stop(0); + sl_Start(NULL,NULL,NULL); + \endcode + + \code + SL_IPV4_STA_P2P_CL_DHCP_ENABLE: + + Setting IP address by DHCP to FileSystem using WLAN sta mode or P2P client. + This should be done once if using Serial Flash. + This is the system's default mode for acquiring an IP address after WLAN connection. + _u8 val = 1; + sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE,IPCONFIG_MODE_ENABLE_IPV4,1,&val); + sl_Stop(0); + sl_Start(NULL,NULL,NULL); + \endcode + + \code + SL_IPV4_AP_P2P_GO_STATIC_ENABLE: + + Setting a static IP address to the device working in AP mode or P2P go. + The IP address will be stored in the FileSystem. Requires restart. + + SlNetCfgIpV4Args_t ipV4; + ipV4.ipV4 = (_u32)SL_IPV4_VAL(10,1,1,201); // _u32 IP address + ipV4.ipV4Mask = (_u32)SL_IPV4_VAL(255,255,255,0); // _u32 Subnet mask for this AP/P2P + ipV4.ipV4Gateway = (_u32)SL_IPV4_VAL(10,1,1,1); // _u32 Default gateway address + ipV4.ipV4DnsServer = (_u32)SL_IPV4_VAL(8,16,32,64); // _u32 DNS server address + + sl_NetCfgSet(SL_IPV4_AP_P2P_GO_STATIC_ENABLE,IPCONFIG_MODE_ENABLE_IPV4,sizeof(SlNetCfgIpV4Args_t),(_u8 *)&ipV4); + sl_Stop(0); + sl_Start(NULL,NULL,NULL); + \endcode + + +*/ +#if _SL_INCLUDE_FUNC(sl_NetCfgSet) +_i32 sl_NetCfgSet(const _u8 ConfigId,const _u8 ConfigOpt,const _u8 ConfigLen,const _u8 *pValues); +#endif + + +/*! + \brief Internal function for getting network configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] ConfigId configuration id + + \param[out] pConfigOpt Get configurations option + + \param[out] pConfigLen The length of the allocated memory as input, when the + function complete, the value of this parameter would be + the len that actually read from the device.\n + If the device return length that is longer from the input + value, the function will cut the end of the returned structure + and will return ESMALLBUF + + \param[out] pValues - get configurations values + + \sa + \note + \warning + \par Examples: + \code + SL_MAC_ADDRESS_GET: + + Get the device MAC address. + The returned MAC address is taken from FileSystem first. If the MAC address was not set by SL_MAC_ADDRESS_SET, the default MAC address + is retrieved from HW. + + _u8 macAddressVal[SL_MAC_ADDR_LEN]; + _u8 macAddressLen = SL_MAC_ADDR_LEN; + sl_NetCfgGet(SL_MAC_ADDRESS_GET,NULL,&macAddressLen,(_u8 *)macAddressVal); + + \endcode + + \code + SL_IPV4_STA_P2P_CL_GET_INFO: + + Get IP address from WLAN station or P2P client. A DHCP flag is returned to indicate if the IP address is static or from DHCP. + + _u8 len = sizeof(SlNetCfgIpV4Args_t); + _u8 dhcpIsOn = 0; + SlNetCfgIpV4Args_t ipV4 = {0}; + sl_NetCfgGet(SL_IPV4_STA_P2P_CL_GET_INFO,&dhcpIsOn,&len,(_u8 *)&ipV4); + + printf("DHCP is %s IP %d.%d.%d.%d MASK %d.%d.%d.%d GW %d.%d.%d.%d DNS %d.%d.%d.%d\n", + (dhcpIsOn > 0) ? "ON" : "OFF", + SL_IPV4_BYTE(ipV4.ipV4,3),SL_IPV4_BYTE(ipV4.ipV4,2),SL_IPV4_BYTE(ipV4.ipV4,1),SL_IPV4_BYTE(ipV4.ipV4,0), + SL_IPV4_BYTE(ipV4.ipV4Mask,3),SL_IPV4_BYTE(ipV4.ipV4Mask,2),SL_IPV4_BYTE(ipV4.ipV4Mask,1),SL_IPV4_BYTE(ipV4.ipV4Mask,0), + SL_IPV4_BYTE(ipV4.ipV4Gateway,3),SL_IPV4_BYTE(ipV4.ipV4Gateway,2),SL_IPV4_BYTE(ipV4.ipV4Gateway,1),SL_IPV4_BYTE(ipV4.ipV4Gateway,0), + SL_IPV4_BYTE(ipV4.ipV4DnsServer,3),SL_IPV4_BYTE(ipV4.ipV4DnsServer,2),SL_IPV4_BYTE(ipV4.ipV4DnsServer,1),SL_IPV4_BYTE(ipV4.ipV4DnsServer,0)); + + \endcode + + \code + SL_IPV4_AP_P2P_GO_GET_INFO: + + Get static IP address for AP or P2P go. + + _u8 len = sizeof(SlNetCfgIpV4Args_t); + _u8 dhcpIsOn = 0; // this flag is meaningless on AP/P2P go. + SlNetCfgIpV4Args_t ipV4 = {0}; + sl_NetCfgGet(SL_IPV4_AP_P2P_GO_GET_INFO,&dhcpIsOn,&len,(_u8 *)&ipV4); + + printf("IP %d.%d.%d.%d MASK %d.%d.%d.%d GW %d.%d.%d.%d DNS %d.%d.%d.%d\n", + SL_IPV4_BYTE(ipV4.ipV4,3),SL_IPV4_BYTE(ipV4.ipV4,2),SL_IPV4_BYTE(ipV4.ipV4,1),SL_IPV4_BYTE(ipV4.ipV4,0), + SL_IPV4_BYTE(ipV4.ipV4Mask,3),SL_IPV4_BYTE(ipV4.ipV4Mask,2),SL_IPV4_BYTE(ipV4.ipV4Mask,1),SL_IPV4_BYTE(ipV4.ipV4Mask,0), + SL_IPV4_BYTE(ipV4.ipV4Gateway,3),SL_IPV4_BYTE(ipV4.ipV4Gateway,2),SL_IPV4_BYTE(ipV4.ipV4Gateway,1),SL_IPV4_BYTE(ipV4.ipV4Gateway,0), + SL_IPV4_BYTE(ipV4.ipV4DnsServer,3),SL_IPV4_BYTE(ipV4.ipV4DnsServer,2),SL_IPV4_BYTE(ipV4.ipV4DnsServer,1),SL_IPV4_BYTE(ipV4.ipV4DnsServer,0)); + + \endcode + + +*/ +#if _SL_INCLUDE_FUNC(sl_NetCfgGet) +_i32 sl_NetCfgGet(const _u8 ConfigId ,_u8 *pConfigOpt, _u8 *pConfigLen, _u8 *pValues); +#endif + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __NETCFG_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/nonos.h b/src/openmv/src/micropython/drivers/cc3100/inc/nonos.h new file mode 100755 index 0000000..568c0ff --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/nonos.h @@ -0,0 +1,325 @@ +/* + * nonos.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __NONOS_H__ +#define __NONOS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef SL_PLATFORM_MULTI_THREADED + +/* This function call the user defined function, if defined, from the sync wait loop */ +/* The use case of this function is to allow nonos system to call a user function to put the device into sleep */ +/* The wake up should be activated after getting an interrupt from the device to Host */ +/* The user function must return without blocking to prevent a delay on the event handling */ +/* +#define _SlSyncWaitLoopCallback UserSleepFunction +*/ + + + +#define NONOS_WAIT_FOREVER 0xFF +#define NONOS_NO_WAIT 0x00 + +#define NONOS_RET_OK (0) +#define NONOS_RET_ERR (0xFF) +#define OSI_OK NONOS_RET_OK + +#define __NON_OS_SYNC_OBJ_CLEAR_VALUE 0x11 +#define __NON_OS_SYNC_OBJ_SIGNAL_VALUE 0x22 +#define __NON_OS_LOCK_OBJ_UNLOCK_VALUE 0x33 +#define __NON_OS_LOCK_OBJ_LOCK_VALUE 0x44 + +/*! + \brief type definition for the return values of this adaptation layer +*/ +typedef _i8 _SlNonOsRetVal_t; + +/*! + \brief type definition for a time value +*/ +typedef _u8 _SlNonOsTime_t; + +/*! + \brief type definition for a sync object container + + Sync object is object used to synchronize between two threads or thread and interrupt handler. + One thread is waiting on the object and the other thread send a signal, which then + release the waiting thread. + The signal must be able to be sent from interrupt context. + This object is generally implemented by binary semaphore or events. +*/ +typedef _u8 _SlNonOsSemObj_t; + + +#define _SlTime_t _SlNonOsTime_t + +#define _SlSyncObj_t _SlNonOsSemObj_t + +#define _SlLockObj_t _SlNonOsSemObj_t + +#define SL_OS_WAIT_FOREVER NONOS_WAIT_FOREVER + +#define SL_OS_RET_CODE_OK NONOS_RET_OK + +#define SL_OS_NO_WAIT NONOS_NO_WAIT + + + + + +/*! + \brief This function creates a sync object + + The sync object is used for synchronization between different thread or ISR and + a thread. + + \param pSyncObj - pointer to the sync object control block + + \return upon successful creation the function return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsSyncObjCreate(pSyncObj) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_CLEAR_VALUE) + +/*! + \brief This function deletes a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsSyncObjDelete(pSyncObj) _SlNonOsSemSet(pSyncObj,0) + +/*! + \brief This function generates a sync signal for the object. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +#define _SlNonOsSyncObjSignal(pSyncObj) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_SIGNAL_VALUE) + +/*! + \brief This function waits for a sync signal of the specific sync object + + \param pSyncObj - pointer to the sync object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the sync signal + Currently, the simple link driver uses only two values: + - NONOS_WAIT_FOREVER + - NONOS_NO_WAIT + + \return upon successful reception of the signal within the timeout window return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsSyncObjWait(pSyncObj , Timeout) _SlNonOsSemGet(pSyncObj,__NON_OS_SYNC_OBJ_SIGNAL_VALUE,__NON_OS_SYNC_OBJ_CLEAR_VALUE,Timeout) + +/*! + \brief This function clears a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful clearing the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsSyncObjClear(pSyncObj) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_CLEAR_VALUE) + +/*! + \brief This function creates a locking object. + + The locking object is used for protecting a shared resources between different + threads. + + \param pLockObj - pointer to the locking object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsLockObjCreate(pLockObj) _SlNonOsSemSet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE) + +/*! + \brief This function deletes a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsLockObjDelete(pLockObj) _SlNonOsSemSet(pLockObj,0) + +/*! + \brief This function locks a locking object. + + All other threads that call this function before this thread calls + the _SlNonOsLockObjUnlock would be suspended + + \param pLockObj - pointer to the locking object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the locking object + Currently, the simple link driver uses only two values: + - NONOS_WAIT_FOREVER + - NONOS_NO_WAIT + + + \return upon successful reception of the locking object the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsLockObjLock(pLockObj , Timeout) _SlNonOsSemGet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE,__NON_OS_LOCK_OBJ_LOCK_VALUE,Timeout) + +/*! + \brief This function unlock a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define _SlNonOsLockObjUnlock(pLockObj) _SlNonOsSemSet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE) + + +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +_SlNonOsRetVal_t _SlNonOsSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , _u32 flags); + + +/*! + \brief This function must be called from the main loop in non-os paltforms + + \param None + + \return 0 - No more activities + 1 - Activity still in progress + \note + \warning +*/ +_SlNonOsRetVal_t _SlNonOsMainLoopTask(void); + +extern _SlNonOsRetVal_t _SlNonOsSemGet(_SlNonOsSemObj_t* pSyncObj, _SlNonOsSemObj_t WaitValue, _SlNonOsSemObj_t SetValue, _SlNonOsTime_t Timeout); +extern _SlNonOsRetVal_t _SlNonOsSemSet(_SlNonOsSemObj_t* pSemObj , _SlNonOsSemObj_t Value); +extern _SlNonOsRetVal_t _SlNonOsSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , _u32 flags); + +#if (defined(_SlSyncWaitLoopCallback)) +extern void _SlSyncWaitLoopCallback(void); +#endif + + +/***************************************************************************** + + Overwrite SimpleLink driver OS adaptation functions + + + *****************************************************************************/ + +#undef sl_SyncObjCreate +#define sl_SyncObjCreate(pSyncObj,pName) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_CLEAR_VALUE) + +#undef sl_SyncObjDelete +#define sl_SyncObjDelete(pSyncObj) _SlNonOsSemSet(pSyncObj,0) + +#undef sl_SyncObjSignal +#define sl_SyncObjSignal(pSyncObj) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_SIGNAL_VALUE) + +#undef sl_SyncObjSignalFromIRQ +#define sl_SyncObjSignalFromIRQ(pSyncObj) _SlNonOsSemSet(pSyncObj,__NON_OS_SYNC_OBJ_SIGNAL_VALUE) + +#undef sl_SyncObjWait +#define sl_SyncObjWait(pSyncObj,Timeout) _SlNonOsSemGet(pSyncObj,__NON_OS_SYNC_OBJ_SIGNAL_VALUE,__NON_OS_SYNC_OBJ_CLEAR_VALUE,Timeout) + +#undef sl_LockObjCreate +#define sl_LockObjCreate(pLockObj,pName) _SlNonOsSemSet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE) + +#undef sl_LockObjDelete +#define sl_LockObjDelete(pLockObj) _SlNonOsSemSet(pLockObj,0) + +#undef sl_LockObjLock +#define sl_LockObjLock(pLockObj,Timeout) _SlNonOsSemGet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE,__NON_OS_LOCK_OBJ_LOCK_VALUE,Timeout) + +#undef sl_LockObjUnlock +#define sl_LockObjUnlock(pLockObj) _SlNonOsSemSet(pLockObj,__NON_OS_LOCK_OBJ_UNLOCK_VALUE) + +#undef sl_Spawn +#define sl_Spawn(pEntry,pValue,flags) _SlNonOsSpawn(pEntry,pValue,flags) + +#undef _SlTaskEntry +#define _SlTaskEntry _SlNonOsMainLoopTask + +#endif /* !SL_PLATFORM_MULTI_THREADED */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/objInclusion.h b/src/openmv/src/micropython/drivers/cc3100/inc/objInclusion.h new file mode 100755 index 0000000..cfe875e --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/objInclusion.h @@ -0,0 +1,322 @@ +/* + * objInclusion.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 + +#ifndef OBJINCLUSION_H_ +#define OBJINCLUSION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + + For future use + +*******************************************************************************/ + +#define __inln /* if inline functions requiered: #define __inln inline */ + +#define SL_DEVICE /* Device silo is currently always mandatory */ + + + +/****************************************************************************** + + Qualifiers for package customizations + +*******************************************************************************/ + +#if defined (SL_DEVICE) +#define __dev 1 +#else +#define __dev 0 +#endif + +#if defined (SL_DEVICE) && defined (SL_INC_EXT_API) +#define __dev__ext 1 +#else +#define __dev__ext 0 +#endif + + +#if (!defined (SL_PLATFORM_MULTI_THREADED)) || (!defined (SL_PLATFORM_EXTERNAL_SPAWN)) +#define __int__spwn 1 +#else +#define __int__spwn 0 +#endif + +#if defined (SL_INC_NET_APP_PKG) +#define __nap 1 +#else +#define __nap 0 +#endif + +#if defined (SL_INC_NET_APP_PKG) && defined (SL_INC_SOCK_CLIENT_SIDE_API) +#define __nap__clt 1 +#else +#define __nap__clt 0 +#endif + +#if defined (SL_INC_NET_APP_PKG) && defined (SL_INC_EXT_API) +#define __nap__ext 1 +#else +#define __nap__ext 0 +#endif + +#if defined (SL_INC_NET_CFG_PKG) +#define __ncg 1 +#else +#define __ncg 0 +#endif + +#if defined (SL_INC_NET_CFG_PKG) && defined (SL_INC_EXT_API) +#define __ncg__ext 1 +#else +#define __ncg__ext 0 +#endif + +#if defined (SL_INC_NVMEM_PKG) +#define __nvm 1 +#else +#define __nvm 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) +#define __sck 1 +#else +#define __sck 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) && defined (SL_INC_EXT_API) +#define __sck__ext 1 +#else +#define __sck__ext 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) && defined (SL_INC_SOCK_SERVER_SIDE_API) +#define __sck__srv 1 +#else +#define __sck__srv 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) && defined (SL_INC_SOCK_CLIENT_SIDE_API) +#define __sck__clt 1 +#else +#define __sck__clt 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) && defined (SL_INC_SOCK_RECV_API) +#define __sck__rcv 1 +#else +#define __sck__rcv 0 +#endif + +#if defined (SL_INC_SOCKET_PKG) && defined (SL_INC_SOCK_SEND_API) +#define __sck__snd 1 +#else +#define __sck__snd 0 +#endif + +#if defined (SL_INC_WLAN_PKG) +#define __wln 1 +#else +#define __wln 0 +#endif + +#if defined (SL_INC_WLAN_PKG) && defined (SL_INC_EXT_API) +#define __wln__ext 1 +#else +#define __wln__ext 0 +#endif + +/* The return 1 is the function need to be included in the output */ +#define _SL_INCLUDE_FUNC(Name) (_SL_INC_##Name) + +/* Driver */ +#define _SL_INC_sl_NetAppStart __nap__ext +#define _SL_INC_sl_NetAppStop __nap__ext + +#define _SL_INC_sl_NetAppDnsGetHostByName __nap__clt + + +#define _SL_INC_sl_NetAppDnsGetHostByService __nap__ext +#define _SL_INC_sl_NetAppMDNSRegisterService __nap__ext +#define _SL_INC_sl_NetAppMDNSUnRegisterService __nap__ext +#define _SL_INC_sl_NetAppMDNSRegisterUnregisterService __nap__ext +#define _SL_INC_sl_NetAppGetServiceList __nap__ext + + +#define _SL_INC_sl_DnsGetHostByAddr __nap__ext +#define _SL_INC_sl_NetAppPingStart __nap__ext +#define _SL_INC_sl_NetAppPingReport __nap__ext +#define _SL_INC_sl_NetAppSet __nap__ext +#define _SL_INC_sl_NetAppGet __nap__ext + + +/* FS */ +#define _SL_INC_sl_FsOpen __nvm + +#define _SL_INC_sl_FsClose __nvm + +#define _SL_INC_sl_FsRead __nvm + +#define _SL_INC_sl_FsWrite __nvm + +#define _SL_INC_sl_FsGetInfo __nvm + +#define _SL_INC_sl_FsDel __nvm + +/* netcfg */ +#define _SL_INC_sl_MacAdrrSet __ncg + +#define _SL_INC_sl_MacAdrrGet __ncg + +#define _SL_INC_sl_NetCfgGet __ncg + +#define _SL_INC_sl_NetCfgSet __ncg + + +/* socket */ +#define _SL_INC_sl_Socket __sck + +#define _SL_INC_sl_Close __sck + +#define _SL_INC_sl_Accept __sck__srv + +#define _SL_INC_sl_Bind __sck + +#define _SL_INC_sl_Listen __sck__srv + +#define _SL_INC_sl_Connect __sck__clt + +#define _SL_INC_sl_Select __sck + +#define _SL_INC_sl_SetSockOpt __sck + +#define _SL_INC_sl_GetSockOpt __sck__ext + +#define _SL_INC_sl_Recv __sck__rcv + +#define _SL_INC_sl_RecvFrom __sck__rcv + +#define _SL_INC_sl_Write __sck__snd + +#define _SL_INC_sl_Send __sck__snd + +#define _SL_INC_sl_SendTo __sck__snd + +#define _SL_INC_sl_Htonl __sck + +#define _SL_INC_sl_Htons __sck + +/* wlan */ +#define _SL_INC_sl_WlanConnect __wln__ext + +#define _SL_INC_sl_WlanDisconnect __wln__ext + +#define _SL_INC_sl_WlanProfileAdd __wln__ext + +#define _SL_INC_sl_WlanProfileGet __wln__ext + +#define _SL_INC_sl_WlanProfileDel __wln__ext + +#define _SL_INC_sl_WlanPolicySet __wln__ext + +#define _SL_INC_sl_WlanPolicyGet __wln__ext + +#define _SL_INC_sl_WlanGetNetworkList __wln__ext + +#define _SL_INC_sl_WlanRxFilterAdd __wln__ext + +#define _SL_INC_sl_WlanRxFilterSet __wln__ext + +#define _SL_INC_sl_WlanRxFilterGet __wln__ext + +#define _SL_INC_sl_SmartConfigStart __wln + +#define _SL_INC_sl_SmartConfigOptSet __wln__ext + + +#define _SL_INC_sl_WlanSmartConfigStart __wln + +#define _SL_INC_sl_WlanSmartConfigStop __wln + +#define _SL_INC_sl_WlanSetMode __wln + +#define _SL_INC_sl_WlanSet __wln + +#define _SL_INC_sl_WlanGet __wln + +#define _SL_INC_sl_SmartConfigOptSet __wln__ext + +#define _SL_INC_sl_SmartConfigOptGet __wln__ext + +#define _SL_INC_sl_WlanRxStatStart __wln__ext + +#define _SL_INC_sl_WlanRxStatStop __wln__ext + +#define _SL_INC_sl_WlanRxStatGet __wln__ext + + +/* device */ +#define _SL_INC_sl_Task __int__spwn + +#define _SL_INC_sl_Start __dev + +#define _SL_INC_sl_Stop __dev + +#define _SL_INC_sl_StatusGet __dev + +#ifdef SL_IF_TYPE_UART +#define _SL_INC_sl_UartSetMode __dev__ext +#endif + +#define _SL_INC_sl_EventMaskGet __dev__ext + +#define _SL_INC_sl_EventMaskSet __dev__ext + +#define _SL_INC_sl_DevGet __dev__ext + +#define _SL_INC_sl_DevSet __dev__ext + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /*OBJINCLUSION_H_ */ diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/protocol.h b/src/openmv/src/micropython/drivers/cc3100/inc/protocol.h new file mode 100755 index 0000000..8a1299a --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/protocol.h @@ -0,0 +1,1182 @@ +/* + * protocol.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 NAME: protocol.h +* +* DESCRIPTION: Constant and data structure definitions and function +* prototypes for the SL protocol module, which implements +* processing of SimpleLink Commands. +* +* AUTHOR: +* +\*******************************************************************************/ + +#ifndef _SL_PROTOCOL_TYPES_H_ +#define _SL_PROTOCOL_TYPES_H_ + +/**************************************************************************** +** +** User I/F pools definitions +** +****************************************************************************/ + +/**************************************************************************** +** +** Definitions for SimpleLink Commands +** +****************************************************************************/ + + +/* pattern for LE 8/16/32 or BE*/ +#define H2N_SYNC_PATTERN {0xBBDDEEFF,0x4321,0x34,0x12} +#define H2N_CNYS_PATTERN {0xBBDDEEFF,0x8765,0x78,0x56} + +#define H2N_DUMMY_PATTERN (_u32)0xFFFFFFFF +#define N2H_SYNC_PATTERN (_u32)0xABCDDCBA +#define SYNC_PATTERN_LEN (_u32)sizeof(_u32) +#define UART_SET_MODE_MAGIC_CODE (_u32)0xAA55AA55 +#define SPI_16BITS_BUG(pattern) (_u32)((_u32)pattern & (_u32)0xFFFF7FFF) +#define SPI_8BITS_BUG(pattern) (_u32)((_u32)pattern & (_u32)0xFFFFFF7F) + + + +typedef struct +{ + _u16 Opcode; + _u16 Len; +}_SlGenericHeader_t; + + +typedef struct +{ + _u32 Long; + _u16 Short; + _u8 Byte1; + _u8 Byte2; +}_SlSyncPattern_t; + +typedef _SlGenericHeader_t _SlCommandHeader_t; + +typedef struct +{ + _SlGenericHeader_t GenHeader; + _u8 TxPoolCnt; + _u8 DevStatus; + _u8 SocketTXFailure; + _u8 SocketNonBlocking; +}_SlResponseHeader_t; + +#define _SL_RESP_SPEC_HDR_SIZE (sizeof(_SlResponseHeader_t) - sizeof(_SlGenericHeader_t)) +#define _SL_RESP_HDR_SIZE sizeof(_SlResponseHeader_t) +#define _SL_CMD_HDR_SIZE sizeof(_SlCommandHeader_t) + +#define _SL_RESP_ARGS_START(_pMsg) (((_SlResponseHeader_t *)(_pMsg)) + 1) + +/* Used only in NWP! */ +typedef struct +{ + _SlCommandHeader_t sl_hdr; + _u8 func_args_start; +} T_SCMD; + + +#define WLAN_CONN_STATUS_BIT 0x01 +#define EVENTS_Q_STATUS_BIT 0x02 +#define PENDING_RCV_CMD_BIT 0x04 +#define FW_BUSY_PACKETS_BIT 0x08 + +#define INIT_STA_OK 0x11111111 +#define INIT_STA_ERR 0x22222222 +#define INIT_AP_OK 0x33333333 +#define INIT_AP_ERR 0x44444444 +#define INIT_P2P_OK 0x55555555 +#define INIT_P2P_ERR 0x66666666 + +/**************************************************************************** +** OPCODES +****************************************************************************/ +#define SL_IPV4_IPV6_OFFSET ( 9 ) +#define SL_OPCODE_IPV4 ( 0x0 << SL_IPV4_IPV6_OFFSET ) +#define SL_OPCODE_IPV6 ( 0x1 << SL_IPV4_IPV6_OFFSET ) + +#define SL_SYNC_ASYNC_OFFSET ( 10 ) +#define SL_OPCODE_SYNC (0x1 << SL_SYNC_ASYNC_OFFSET ) +#define SL_OPCODE_SILO_OFFSET ( 11 ) +#define SL_OPCODE_SILO_MASK ( 0xF << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_DEVICE ( 0x0 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_WLAN ( 0x1 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_SOCKET ( 0x2 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NETAPP ( 0x3 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NVMEM ( 0x4 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NETCFG ( 0x5 << SL_OPCODE_SILO_OFFSET ) + +#define SL_FAMILY_SHIFT (0x4) +#define SL_FLAGS_MASK (0xF) + +#define SL_OPCODE_DEVICE_INITCOMPLETE 0x0008 +#define SL_OPCODE_DEVICE_ABORT 0x000C +#define SL_OPCODE_DEVICE_STOP_COMMAND 0x8473 +#define SL_OPCODE_DEVICE_STOP_RESPONSE 0x0473 +#define SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE 0x0073 +#define SL_OPCODE_DEVICE_DEVICEASYNCDUMMY 0x0063 + +#define SL_OPCODE_DEVICE_VERSIONREADCOMMAND 0x8470 +#define SL_OPCODE_DEVICE_VERSIONREADRESPONSE 0x0470 +#define SL_OPCODE_DEVICE_DEVICEASYNCFATALERROR 0x0078 +#define SL_OPCODE_WLAN_WLANCONNECTCOMMAND 0x8C80 +#define SL_OPCODE_WLAN_WLANCONNECTRESPONSE 0x0C80 +#define SL_OPCODE_WLAN_WLANASYNCCONNECTEDRESPONSE 0x0880 +#define SL_OPCODE_WLAN_P2P_DEV_FOUND 0x0830 +#define SL_OPCODE_WLAN_CONNECTION_FAILED 0x0831 +#define SL_OPCODE_WLAN_P2P_NEG_REQ_RECEIVED 0x0832 + +#define SL_OPCODE_WLAN_WLANDISCONNECTCOMMAND 0x8C81 +#define SL_OPCODE_WLAN_WLANDISCONNECTRESPONSE 0x0C81 +#define SL_OPCODE_WLAN_WLANASYNCDISCONNECTEDRESPONSE 0x0881 +#define SL_OPCODE_WLAN_WLANCONNECTEAPCOMMAND 0x8C82 +#define SL_OPCODE_WLAN_WLANCONNECTEAPCRESPONSE 0x0C82 +#define SL_OPCODE_WLAN_PROFILEADDCOMMAND 0x8C83 +#define SL_OPCODE_WLAN_PROFILEADDRESPONSE 0x0C83 +#define SL_OPCODE_WLAN_PROFILEGETCOMMAND 0x8C84 +#define SL_OPCODE_WLAN_PROFILEGETRESPONSE 0x0C84 +#define SL_OPCODE_WLAN_PROFILEDELCOMMAND 0x8C85 +#define SL_OPCODE_WLAN_PROFILEDELRESPONSE 0x0C85 +#define SL_OPCODE_WLAN_POLICYSETCOMMAND 0x8C86 +#define SL_OPCODE_WLAN_POLICYSETRESPONSE 0x0C86 +#define SL_OPCODE_WLAN_POLICYGETCOMMAND 0x8C87 +#define SL_OPCODE_WLAN_POLICYGETRESPONSE 0x0C87 +#define SL_OPCODE_WLAN_FILTERADD 0x8C88 +#define SL_OPCODE_WLAN_FILTERADDRESPONSE 0x0C88 +#define SL_OPCODE_WLAN_FILTERGET 0x8C89 +#define SL_OPCODE_WLAN_FILTERGETRESPONSE 0x0C89 +#define SL_OPCODE_WLAN_FILTERDELETE 0x8C8A +#define SL_OPCODE_WLAN_FILTERDELETERESPOSNE 0x0C8A +#define SL_OPCODE_WLAN_WLANGETSTATUSCOMMAND 0x8C8F +#define SL_OPCODE_WLAN_WLANGETSTATUSRESPONSE 0x0C8F +#define SL_OPCODE_WLAN_STARTTXCONTINUESCOMMAND 0x8CAA +#define SL_OPCODE_WLAN_STARTTXCONTINUESRESPONSE 0x0CAA +#define SL_OPCODE_WLAN_STOPTXCONTINUESCOMMAND 0x8CAB +#define SL_OPCODE_WLAN_STOPTXCONTINUESRESPONSE 0x0CAB +#define SL_OPCODE_WLAN_STARTRXSTATCOMMAND 0x8CAC +#define SL_OPCODE_WLAN_STARTRXSTATRESPONSE 0x0CAC +#define SL_OPCODE_WLAN_STOPRXSTATCOMMAND 0x8CAD +#define SL_OPCODE_WLAN_STOPRXSTATRESPONSE 0x0CAD +#define SL_OPCODE_WLAN_GETRXSTATCOMMAND 0x8CAF +#define SL_OPCODE_WLAN_GETRXSTATRESPONSE 0x0CAF +#define SL_OPCODE_WLAN_POLICYSETCOMMANDNEW 0x8CB0 +#define SL_OPCODE_WLAN_POLICYSETRESPONSENEW 0x0CB0 +#define SL_OPCODE_WLAN_POLICYGETCOMMANDNEW 0x8CB1 +#define SL_OPCODE_WLAN_POLICYGETRESPONSENEW 0x0CB1 + +#define SL_OPCODE_WLAN_SMART_CONFIG_START_COMMAND 0x8CB2 +#define SL_OPCODE_WLAN_SMART_CONFIG_START_RESPONSE 0x0CB2 +#define SL_OPCODE_WLAN_SMART_CONFIG_START_ASYNC_RESPONSE 0x08B2 +#define SL_OPCODE_WLAN_SMART_CONFIG_STOP_COMMAND 0x8CB3 +#define SL_OPCODE_WLAN_SMART_CONFIG_STOP_RESPONSE 0x0CB3 +#define SL_OPCODE_WLAN_SMART_CONFIG_STOP_ASYNC_RESPONSE 0x08B3 +#define SL_OPCODE_WLAN_SET_MODE 0x8CB4 +#define SL_OPCODE_WLAN_SET_MODE_RESPONSE 0x0CB4 +#define SL_OPCODE_WLAN_CFG_SET 0x8CB5 +#define SL_OPCODE_WLAN_CFG_SET_RESPONSE 0x0CB5 +#define SL_OPCODE_WLAN_CFG_GET 0x8CB6 +#define SL_OPCODE_WLAN_CFG_GET_RESPONSE 0x0CB6 +#define SL_OPCODE_WLAN_STA_CONNECTED 0x082E +#define SL_OPCODE_WLAN_STA_DISCONNECTED 0x082F +#define SL_OPCODE_WLAN_EAP_PROFILEADDCOMMAND 0x8C67 +#define SL_OPCODE_WLAN_EAP_PROFILEADDCOMMAND_RESPONSE 0x0C67 + +#define SL_OPCODE_SOCKET_SOCKET 0x9401 +#define SL_OPCODE_SOCKET_SOCKETRESPONSE 0x1401 +#define SL_OPCODE_SOCKET_CLOSE 0x9402 +#define SL_OPCODE_SOCKET_CLOSERESPONSE 0x1402 +#define SL_OPCODE_SOCKET_ACCEPT 0x9403 +#define SL_OPCODE_SOCKET_ACCEPTRESPONSE 0x1403 +#define SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE 0x1003 +#define SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE_V6 0x1203 +#define SL_OPCODE_SOCKET_BIND 0x9404 +#define SL_OPCODE_SOCKET_BIND_V6 0x9604 +#define SL_OPCODE_SOCKET_BINDRESPONSE 0x1404 +#define SL_OPCODE_SOCKET_LISTEN 0x9405 +#define SL_OPCODE_SOCKET_LISTENRESPONSE 0x1405 +#define SL_OPCODE_SOCKET_CONNECT 0x9406 +#define SL_OPCODE_SOCKET_CONNECT_V6 0x9606 +#define SL_OPCODE_SOCKET_CONNECTRESPONSE 0x1406 +#define SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE 0x1006 +#define SL_OPCODE_SOCKET_SELECT 0x9407 +#define SL_OPCODE_SOCKET_SELECTRESPONSE 0x1407 +#define SL_OPCODE_SOCKET_SELECTASYNCRESPONSE 0x1007 +#define SL_OPCODE_SOCKET_SETSOCKOPT 0x9408 +#define SL_OPCODE_SOCKET_SETSOCKOPTRESPONSE 0x1408 +#define SL_OPCODE_SOCKET_GETSOCKOPT 0x9409 +#define SL_OPCODE_SOCKET_GETSOCKOPTRESPONSE 0x1409 +#define SL_OPCODE_SOCKET_RECV 0x940A +#define SL_OPCODE_SOCKET_RECVASYNCRESPONSE 0x100A +#define SL_OPCODE_SOCKET_RECVFROM 0x940B +#define SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE 0x100B +#define SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6 0x120B +#define SL_OPCODE_SOCKET_SEND 0x940C +#define SL_OPCODE_SOCKET_SENDTO 0x940D +#define SL_OPCODE_SOCKET_SENDTO_V6 0x960D +#define SL_OPCODE_SOCKET_TXFAILEDASYNCRESPONSE 0x100E +#define SL_OPCODE_SOCKET_SOCKETASYNCEVENT 0x100F +#define SL_OPCODE_NETAPP_START_COMMAND 0x9C0A +#define SL_OPCODE_NETAPP_START_RESPONSE 0x1C0A +#define SL_OPCODE_NETAPP_NETAPPSTARTRESPONSE 0x1C0A +#define SL_OPCODE_NETAPP_STOP_COMMAND 0x9C61 +#define SL_OPCODE_NETAPP_STOP_RESPONSE 0x1C61 +#define SL_OPCODE_NETAPP_NETAPPSET 0x9C0B +#define SL_OPCODE_NETAPP_NETAPPSETRESPONSE 0x1C0B +#define SL_OPCODE_NETAPP_NETAPPGET 0x9C27 +#define SL_OPCODE_NETAPP_NETAPPGETRESPONSE 0x1C27 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYNAME 0x9C20 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYNAMERESPONSE 0x1C20 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE 0x1820 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE_V6 0x1A20 +#define SL_OPCODE_NETAPP_NETAPP_MDNS_LOOKUP_SERVICE 0x9C71 +#define SL_OPCODE_NETAPP_NETAPP_MDNS_LOOKUP_SERVICE_RESPONSE 0x1C72 +#define SL_OPCODE_NETAPP_MDNSREGISTERSERVICE 0x9C34 +#define SL_OPCODE_NETAPP_MDNSREGISTERSERVICERESPONSE 0x1C34 +#define SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICE 0x9C35 +#define SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICERESPONSE 0x1C35 +#define SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE 0x1835 +#define SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE_V6 0x1A35 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYADDR 0x9C26 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYADDR_V6 0x9E26 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYADDRRESPONSE 0x1C26 +#define SL_OPCODE_NETAPP_DNSGETHOSTBYADDRASYNCRESPONSE 0x1826 +#define SL_OPCODE_NETAPP_PINGSTART 0x9C21 +#define SL_OPCODE_NETAPP_PINGSTART_V6 0x9E21 +#define SL_OPCODE_NETAPP_PINGSTARTRESPONSE 0x1C21 +#define SL_OPCODE_NETAPP_PINGREPORTREQUEST 0x9C22 +#define SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE 0x1822 +#define SL_OPCODE_NETAPP_PINGSTOP 0x9C23 +#define SL_OPCODE_NETAPP_PINGSTOPRESPONSE 0x1C23 +#define SL_OPCODE_NETAPP_ARPFLUSH 0x9C24 +#define SL_OPCODE_NETAPP_ARPFLUSHRESPONSE 0x1C24 +#define SL_OPCODE_NETAPP_IPACQUIRED 0x1825 +#define SL_OPCODE_NETAPP_IPV4_LOST 0x1832 +#define SL_OPCODE_NETAPP_DHCP_IPV4_ACQUIRE_TIMEOUT 0x1833 +#define SL_OPCODE_NETAPP_IPACQUIRED_V6 0x1A25 +#define SL_OPCODE_NETAPP_IPERFSTARTCOMMAND 0x9C28 +#define SL_OPCODE_NETAPP_IPERFSTARTRESPONSE 0x1C28 +#define SL_OPCODE_NETAPP_IPERFSTOPCOMMAND 0x9C29 +#define SL_OPCODE_NETAPP_IPERFSTOPRESPONSE 0x1C29 +#define SL_OPCODE_NETAPP_CTESTSTARTCOMMAND 0x9C2A +#define SL_OPCODE_NETAPP_CTESTSTARTRESPONSE 0x1C2A +#define SL_OPCODE_NETAPP_CTESTASYNCRESPONSE 0x182A +#define SL_OPCODE_NETAPP_CTESTSTOPCOMMAND 0x9C2B +#define SL_OPCODE_NETAPP_CTESTSTOPRESPONSE 0x1C2B +#define SL_OPCODE_NETAPP_IP_LEASED 0x182C +#define SL_OPCODE_NETAPP_IP_RELEASED 0x182D +#define SL_OPCODE_NETAPP_HTTPGETTOKENVALUE 0x182E +#define SL_OPCODE_NETAPP_HTTPSENDTOKENVALUE 0x9C2F +#define SL_OPCODE_NETAPP_HTTPPOSTTOKENVALUE 0x1830 +#define SL_OPCODE_NVMEM_FILEOPEN 0xA43C +#define SL_OPCODE_NVMEM_FILEOPENRESPONSE 0x243C +#define SL_OPCODE_NVMEM_FILECLOSE 0xA43D +#define SL_OPCODE_NVMEM_FILECLOSERESPONSE 0x243D +#define SL_OPCODE_NVMEM_FILEREADCOMMAND 0xA440 +#define SL_OPCODE_NVMEM_FILEREADRESPONSE 0x2440 +#define SL_OPCODE_NVMEM_FILEWRITECOMMAND 0xA441 +#define SL_OPCODE_NVMEM_FILEWRITERESPONSE 0x2441 +#define SL_OPCODE_NVMEM_FILEGETINFOCOMMAND 0xA442 +#define SL_OPCODE_NVMEM_FILEGETINFORESPONSE 0x2442 +#define SL_OPCODE_NVMEM_FILEDELCOMMAND 0xA443 +#define SL_OPCODE_NVMEM_FILEDELRESPONSE 0x2443 +#define SL_OPCODE_NVMEM_NVMEMFORMATCOMMAND 0xA444 +#define SL_OPCODE_NVMEM_NVMEMFORMATRESPONSE 0x2444 + +#define SL_OPCODE_DEVICE_SETDEBUGLEVELCOMMAND 0x846A +#define SL_OPCODE_DEVICE_SETDEBUGLEVELRESPONSE 0x046A + +#define SL_OPCODE_DEVICE_NETCFG_SET_COMMAND 0x8432 +#define SL_OPCODE_DEVICE_NETCFG_SET_RESPONSE 0x0432 +#define SL_OPCODE_DEVICE_NETCFG_GET_COMMAND 0x8433 +#define SL_OPCODE_DEVICE_NETCFG_GET_RESPONSE 0x0433 +/* */ +#define SL_OPCODE_DEVICE_SETUARTMODECOMMAND 0x846B +#define SL_OPCODE_DEVICE_SETUARTMODERESPONSE 0x046B +#define SL_OPCODE_DEVICE_SSISIZESETCOMMAND 0x846B +#define SL_OPCODE_DEVICE_SSISIZESETRESPONSE 0x046B + +/* */ +#define SL_OPCODE_DEVICE_EVENTMASKSET 0x8464 +#define SL_OPCODE_DEVICE_EVENTMASKSETRESPONSE 0x0464 +#define SL_OPCODE_DEVICE_EVENTMASKGET 0x8465 +#define SL_OPCODE_DEVICE_EVENTMASKGETRESPONSE 0x0465 + +#define SL_OPCODE_DEVICE_DEVICEGET 0x8466 +#define SL_OPCODE_DEVICE_DEVICEGETRESPONSE 0x0466 +#define SL_OPCODE_DEVICE_DEVICESET 0x84B7 +#define SL_OPCODE_DEVICE_DEVICESETRESPONSE 0x04B7 + +#define SL_OPCODE_WLAN_SCANRESULTSGETCOMMAND 0x8C8C +#define SL_OPCODE_WLAN_SCANRESULTSGETRESPONSE 0x0C8C +#define SL_OPCODE_WLAN_SMARTCONFIGOPTSET 0x8C8D +#define SL_OPCODE_WLAN_SMARTCONFIGOPTSETRESPONSE 0x0C8D +#define SL_OPCODE_WLAN_SMARTCONFIGOPTGET 0x8C8E +#define SL_OPCODE_WLAN_SMARTCONFIGOPTGETRESPONSE 0x0C8E + + +/* Rx Filters opcodes */ +#define SL_OPCODE_WLAN_WLANRXFILTERADDCOMMAND 0x8C6C +#define SL_OPCODE_WLAN_WLANRXFILTERADDRESPONSE 0x0C6C +#define SL_OPCODE_WLAN_WLANRXFILTERSETCOMMAND 0x8C6D +#define SL_OPCODE_WLAN_WLANRXFILTERSETRESPONSE 0x0C6D +#define SL_OPCODE_WLAN_WLANRXFILTERGETSTATISTICSINFOCOMMAND 0x8C6E +#define SL_OPCODE_WLAN_WLANRXFILTERGETSTATISTICSINFORESPONSE 0x0C6E +#define SL_OPCODE_WLAN_WLANRXFILTERGETCOMMAND 0x8C6F +#define SL_OPCODE_WLAN_WLANRXFILTERGETRESPONSE 0x0C6F +#define SL_OPCODE_WLAN_WLANRXFILTERGETINFO 0x8C70 +#define SL_OPCODE_WLAN_WLANRXFILTERGETINFORESPONSE 0x0C70 + + +/******************************************************************************************/ +/* Device structs */ +/******************************************************************************************/ +typedef _u32 InitStatus_t; + + +typedef struct +{ + _i32 Status; +}InitComplete_t; + +typedef struct +{ + _i16 status; + _u16 padding; + +}_BasicResponse_t; + +typedef struct +{ + _u16 Timeout; + _u16 padding; +}_DevStopCommand_t; + +typedef struct +{ + _u32 group; + _u32 mask; +}_DevMaskEventSetCommand_t; + +typedef _BasicResponse_t _DevMaskEventSetResponse_t; + + +typedef struct +{ + _u32 group; +}_DevMaskEventGetCommand_t; + + +typedef struct +{ + _u32 group; + _u32 mask; +}_DevMaskEventGetResponse_t; + + +typedef struct +{ + _u32 group; +}_DevStatusGetCommand_t; + + +typedef struct +{ + _u32 group; + _u32 status; +}_DevStatusGetResponse_t; + +typedef struct +{ + _u32 ChipId; + _u32 FwVersion[4]; + _u8 PhyVersion[4]; +}_Device_VersionReadResponsePart_t; + +typedef struct +{ + _Device_VersionReadResponsePart_t part; + _u32 NwpVersion[4]; + _u16 RomVersion; + _u16 Padding; +}_Device_VersionReadResponseFull_t; + + +typedef struct +{ + _u32 BaudRate; + _u8 FlowControlEnable; +}_DevUartSetModeCommand_t; + +typedef _BasicResponse_t _DevUartSetModeResponse_t; + +/******************************************************/ + +typedef struct +{ + _u8 SsiSizeInBytes; + _u8 Padding[3]; +}_StellarisSsiSizeSet_t; + +/*****************************************************************************************/ +/* WLAN structs */ +/*****************************************************************************************/ +#define MAXIMAL_PASSWORD_LENGTH (64) + +typedef struct{ + _u8 SecType; + _u8 SsidLen; + _u8 Bssid[6]; + _u8 PasswordLen; +}_WlanConnectCommon_t; + +#define SSID_STRING(pCmd) (_i8 *)((_WlanConnectCommon_t *)(pCmd) + 1) +#define PASSWORD_STRING(pCmd) (SSID_STRING(pCmd) + ((_WlanConnectCommon_t *)(pCmd))->SsidLen) + +typedef struct{ + _WlanConnectCommon_t Common; + _u8 UserLen; + _u8 AnonUserLen; + _u8 CertIndex; + _u32 EapBitmask; +}_WlanConnectEapCommand_t; + +#define EAP_SSID_STRING(pCmd) (_i8 *)((_WlanConnectEapCommand_t *)(pCmd) + 1) +#define EAP_PASSWORD_STRING(pCmd) (EAP_SSID_STRING(pCmd) + ((_WlanConnectEapCommand_t *)(pCmd))->Common.SsidLen) +#define EAP_USER_STRING(pCmd) (EAP_PASSWORD_STRING(pCmd) + ((_WlanConnectEapCommand_t *)(pCmd))->Common.PasswordLen) +#define EAP_ANON_USER_STRING(pCmd) (EAP_USER_STRING(pCmd) + ((_WlanConnectEapCommand_t *)(pCmd))->UserLen) + + +typedef struct +{ + _u8 PolicyType; + _u8 Padding; + _u8 PolicyOption; + _u8 PolicyOptionLen; +}_WlanPoliciySetGet_t; + + +typedef struct{ + _u32 minDwellTime; + _u32 maxDwellTime; + _u32 numProbeResponse; + _u32 G_Channels_mask; + _i32 rssiThershold; + _i32 snrThershold; + _i32 defaultTXPower; + _u16 intervalList[16]; +}_WlanScanParamSetCommand_t; + + +typedef struct{ + _i8 SecType; + _u8 SsidLen; + _u8 Priority; + _u8 Bssid[6]; + _u8 PasswordLen; + _u8 WepKeyId; +}_WlanAddGetProfile_t; + + +typedef struct{ + _WlanAddGetProfile_t Common; + _u8 UserLen; + _u8 AnonUserLen; + _u8 CertIndex; + _u16 padding; + _u32 EapBitmask; +}_WlanAddGetEapProfile_t; + + + + +#define PROFILE_SSID_STRING(pCmd) ((_i8 *)((_WlanAddGetProfile_t *)(pCmd) + 1)) +#define PROFILE_PASSWORD_STRING(pCmd) (PROFILE_SSID_STRING(pCmd) + ((_WlanAddGetProfile_t *)(pCmd))->SsidLen) + +#define EAP_PROFILE_SSID_STRING(pCmd) (_i8 *)((_WlanAddGetEapProfile_t *)(pCmd) + 1) +#define EAP_PROFILE_PASSWORD_STRING(pCmd) (EAP_PROFILE_SSID_STRING(pCmd) + ((_WlanAddGetEapProfile_t *)(pCmd))->Common.SsidLen) +#define EAP_PROFILE_USER_STRING(pCmd) (EAP_PROFILE_PASSWORD_STRING(pCmd) + ((_WlanAddGetEapProfile_t *)(pCmd))->Common.PasswordLen) +#define EAP_PROFILE_ANON_USER_STRING(pCmd) (EAP_PROFILE_USER_STRING(pCmd) + ((_WlanAddGetEapProfile_t *)(pCmd))->UserLen) + + + +typedef struct +{ + _u8 index; + _u8 padding[3]; +}_WlanProfileDelGetCommand_t; + +typedef _BasicResponse_t _WlanGetNetworkListResponse_t; + +typedef struct +{ + _u8 index; + _u8 count; + _i8 padding[2]; +}_WlanGetNetworkListCommand_t; + + + + +typedef struct +{ + _u32 groupIdBitmask; + _u8 cipher; + _u8 publicKeyLen; + _u8 group1KeyLen; + _u8 group2KeyLen; +}_WlanSmartConfigStartCommand_t; + +#define SMART_CONFIG_START_PUBLIC_KEY_STRING(pCmd) ((_i8 *)((_WlanSmartConfigStartCommand_t *)(pCmd) + 1)) +#define SMART_CONFIG_START_GROUP1_KEY_STRING(pCmd) ((_i8 *) (SMART_CONFIG_START_PUBLIC_KEY_STRING(pCmd) + ((_WlanSmartConfigStartCommand_t *)(pCmd))->publicKeyLen)) +#define SMART_CONFIG_START_GROUP2_KEY_STRING(pCmd) ((_i8 *) (SMART_CONFIG_START_GROUP1_KEY_STRING(pCmd) + ((_WlanSmartConfigStartCommand_t *)(pCmd))->group1KeyLen)) + + + +typedef struct +{ + _u8 mode; + _u8 padding[3]; +}_WlanSetMode_t; + + + + +typedef struct +{ + _u16 Status; + _u16 ConfigId; + _u16 ConfigOpt; + _u16 ConfigLen; +}_WlanCfgSetGet_t; + + +/* ******************************************************************************/ +/* RX filters - Start */ +/* ******************************************************************************/ +/* -- 80 bytes */ +typedef struct _WlanRxFilterAddCommand_t +{ + /* -- 1 byte */ + SlrxFilterRuleType_t RuleType; + /* -- 1 byte */ + SlrxFilterFlags_t FilterFlags; + /* -- 1 byte */ + SlrxFilterID_t FilterId; + /* -- 1 byte */ + _u8 Padding; + /* -- 56 byte */ + SlrxFilterRule_t Rule; + /* -- 12 byte ( 3 padding ) */ + SlrxFilterTrigger_t Trigger; + /* -- 8 byte */ + SlrxFilterAction_t Action; +}_WlanRxFilterAddCommand_t; + + + +/* -- 4 bytes */ +typedef struct l_WlanRxFilterAddCommandReponse_t +{ + /* -- 1 byte */ + SlrxFilterID_t FilterId; + /* -- 1 Byte */ + _u8 Status; + /* -- 2 byte */ + _u8 Padding[2]; + +}_WlanRxFilterAddCommandReponse_t; + + + +/* + * \struct _WlanRxFilterSetCommand_t + */ +typedef struct _WlanRxFilterSetCommand_t +{ + _u16 InputBufferLength; + /* 1 byte */ + SLrxFilterOperation_t RxFilterOperation; + _u8 Padding[1]; +}_WlanRxFilterSetCommand_t; + +/** + * \struct _WlanRxFilterSetCommandReponse_t + */ +typedef struct _WlanRxFilterSetCommandReponse_t +{ + /* 1 byte */ + _u8 Status; + /* 3 bytes */ + _u8 Padding[3]; + +}_WlanRxFilterSetCommandReponse_t; + +/** + * \struct _WlanRxFilterGetCommand_t + */ +typedef struct _WlanRxFilterGetCommand_t +{ + _u16 OutputBufferLength; + /* 1 byte */ + SLrxFilterOperation_t RxFilterOperation; + _u8 Padding[1]; +}_WlanRxFilterGetCommand_t; + +/** + * \struct _WlanRxFilterGetCommandReponse_t + */ +typedef struct _WlanRxFilterGetCommandReponse_t +{ + /* 1 byte */ + _u8 Status; + /* 1 bytes */ + _u8 Padding; + /* 2 byte */ + _u16 OutputBufferLength; + +}_WlanRxFilterGetCommandReponse_t; + + + +/* ******************************************************************************/ +/* RX filters -- End */ +/* ******************************************************************************/ + +typedef struct +{ + _u16 status; + _u8 WlanRole; /* 0 = station, 2 = AP */ + _u8 Ipv6Enabled; + _u8 Ipv6DhcpEnabled; + + _u32 ipV6Global[4]; + _u32 ipV6Local[4]; + _u32 ipV6DnsServer[4]; + _u8 Ipv6DhcpState; + +}_NetappIpV6configRetArgs_t; + + +typedef struct +{ + _u8 ipV4[4]; + _u8 ipV4Mask[4]; + _u8 ipV4Gateway[4]; + _u8 ipV4DnsServer[4]; + _u8 ipV4Start[4]; + _u8 ipV4End[4]; +}_NetCfgIpV4AP_Args_t; + + + +typedef struct +{ + _u16 status; + _u8 MacAddr[6]; +} _MAC_Address_SetGet_t; + + +typedef struct +{ + _u16 Status; + _u16 ConfigId; + _u16 ConfigOpt; + _u16 ConfigLen; +}_NetCfgSetGet_t; + +typedef struct +{ + _u16 Status; + _u16 DeviceSetId; + _u16 Option; + _u16 ConfigLen; +}_DeviceSetGet_t; + + + + +/******************************************************************************************/ +/* Socket structs */ +/******************************************************************************************/ + +typedef struct +{ + _u8 Domain; + _u8 Type; + _u8 Protocol; + _u8 Padding; +}_SocketCommand_t; + + +typedef struct +{ + _i16 statusOrLen; + _u8 sd; + _u8 padding; +}_SocketResponse_t; + +typedef struct +{ + _u8 sd; + _u8 family; + _u8 padding1; + _u8 padding2; +}_AcceptCommand_t; + + +typedef struct +{ + _i16 statusOrLen; + _u8 sd; + _u8 family; + _u16 port; + _u16 paddingOrAddr; + _u32 address; +}_SocketAddrAsyncIPv4Response_t; + +typedef struct +{ + _i16 statusOrLen; + _u8 sd; + _u8 family; + _u16 port; + _u8 address[6]; +}_SocketAddrAsyncIPv6EUI48Response_t; +typedef struct +{ + _i16 statusOrLen; + _u8 sd; + _u8 family; + _u16 port; + _u16 paddingOrAddr; + _u32 address[4]; +}_SocketAddrAsyncIPv6Response_t; + + +typedef struct +{ + _i16 lenOrPadding; + _u8 sd; + _u8 FamilyAndFlags; + _u16 port; + _u16 paddingOrAddr; + _u32 address; +}_SocketAddrIPv4Command_t; + +typedef struct +{ + _i16 lenOrPadding; + _u8 sd; + _u8 FamilyAndFlags; + _u16 port; + _u8 address[6]; +}_SocketAddrIPv6EUI48Command_t; +typedef struct +{ + _i16 lenOrPadding; + _u8 sd; + _u8 FamilyAndFlags; + _u16 port; + _u16 paddingOrAddr; + _u32 address[4]; +}_SocketAddrIPv6Command_t; + +typedef union { + _SocketAddrIPv4Command_t IpV4; + _SocketAddrIPv6EUI48Command_t IpV6EUI48; +#ifdef SL_SUPPORT_IPV6 + _SocketAddrIPv6Command_t IpV6; +#endif +} _SocketAddrCommand_u; + +typedef union { + _SocketAddrAsyncIPv4Response_t IpV4; + _SocketAddrAsyncIPv6EUI48Response_t IpV6EUI48; +#ifdef SL_SUPPORT_IPV6 + _SocketAddrAsyncIPv6Response_t IpV6; +#endif +} _SocketAddrResponse_u; + +typedef struct +{ + _u8 sd; + _u8 backlog; + _u8 padding1; + _u8 padding2; +}_ListenCommand_t; + +typedef struct +{ + _u8 sd; + _u8 padding0; + _u8 padding1; + _u8 padding2; +}_CloseCommand_t; + + +typedef struct +{ + _u8 nfds; + _u8 readFdsCount; + _u8 writeFdsCount; + _u8 padding; + _u16 readFds; + _u16 writeFds; + _u16 tv_usec; + _u16 tv_sec; +}_SelectCommand_t; + + +typedef struct +{ + _u16 status; + _u8 readFdsCount; + _u8 writeFdsCount; + _u16 readFds; + _u16 writeFds; +}_SelectAsyncResponse_t; + +typedef struct +{ + _u8 sd; + _u8 level; + _u8 optionName; + _u8 optionLen; +}_setSockOptCommand_t; + +typedef struct +{ + _u8 sd; + _u8 level; + _u8 optionName; + _u8 optionLen; +}_getSockOptCommand_t; + +typedef struct +{ + _i16 status; + _u8 sd; + _u8 optionLen; +}_getSockOptResponse_t; + + +typedef struct +{ + _u16 StatusOrLen; + _u8 sd; + _u8 FamilyAndFlags; +}_sendRecvCommand_t; + +/***************************************************************************************** +* NETAPP structs +******************************************************************************************/ + + +typedef _BasicResponse_t _NetAppStartStopResponse_t; + +typedef struct +{ + _u32 appId; +}_NetAppStartStopCommand_t; + +typedef struct +{ + _u16 Status; + _u16 AppId; + _u16 ConfigOpt; + _u16 ConfigLen; +}_NetAppSetGet_t; +typedef struct +{ + _u16 port_number; +} _NetAppHttpServerGetSet_port_num_t; + +typedef struct +{ + _u8 auth_enable; +}_NetAppHttpServerGetSet_auth_enable_t; + +typedef struct _sl_NetAppHttpServerGetToken_t +{ + _u8 token_name_len; + _u8 padd1; + _u16 padd2; +}sl_NetAppHttpServerGetToken_t; + +typedef struct _sl_NetAppHttpServerSendToken_t +{ + _u8 token_value_len; + _u8 token_name_len; + _u8 token_name[MAX_TOKEN_NAME_LEN]; + _u16 padd; +}sl_NetAppHttpServerSendToken_t; + +typedef struct _sl_NetAppHttpServerPostToken_t +{ + _u8 post_action_len; + _u8 token_name_len; + _u8 token_value_len; + _u8 padding; +}sl_NetAppHttpServerPostToken_t; + + +typedef struct +{ + _u16 Len; + _u8 family; + _u8 padding; +}_GetHostByNameCommand_t; + +typedef struct +{ + _u16 status; + _u16 padding; + _u32 ip0; + _u32 ip1; + _u32 ip2; + _u32 ip3; +}_GetHostByNameIPv6AsyncResponse_t; + +typedef struct +{ + _u16 status; + _u8 padding1; + _u8 padding2; + _u32 ip0; +}_GetHostByNameIPv4AsyncResponse_t; + + + + +typedef enum +{ + CTST_BSD_UDP_TX, + CTST_BSD_UDP_RX, + CTST_BSD_TCP_TX, + CTST_BSD_TCP_RX, + CTST_BSD_TCP_SERVER_BI_DIR, + CTST_BSD_TCP_CLIENT_BI_DIR, + CTST_BSD_UDP_BI_DIR, + CTST_BSD_RAW_TX, + CTST_BSD_RAW_RX, + CTST_BSD_RAW_BI_DIR, + CTST_BSD_SECURED_TCP_TX, + CTST_BSD_SECURED_TCP_RX, + CTST_BSD_SECURED_TCP_SERVER_BI_DIR, + CTST_BSD_SECURED_TCP_CLIENT_BI_DIR + }CommTest_e; + +typedef struct _sl_protocol_CtestStartCommand_t +{ + _u32 Test; + _u16 DestPort; + _u16 SrcPort; + _u32 DestAddr[4]; + _u32 PayloadSize; + _u32 timeout; + _u32 csEnabled; + _u32 secure; + _u32 rawProtocol; + _u8 reserved1[4]; +}_CtestStartCommand_t; + +typedef struct +{ + _u8 test; + _u8 socket; + _i16 status; + _u32 startTime; + _u32 endTime; + _u16 txKbitsSec; + _u16 rxKbitsSec; + _u32 outOfOrderPackets; + _u32 missedPackets; + _i16 token; +}_CtestAsyncResponse_t; + +typedef struct +{ + _u32 pingIntervalTime; + _u16 PingSize; + _u16 pingRequestTimeout; + _u32 totalNumberOfAttempts; + _u32 flags; + _u32 ip0; + _u32 ip1OrPaadding; + _u32 ip2OrPaadding; + _u32 ip3OrPaadding; +}_PingStartCommand_t; + +typedef struct +{ + _u16 status; + _u16 rttMin; + _u16 rttMax; + _u16 rttAvg; + _u32 numSuccsessPings; + _u32 numSendsPings; + _u32 testTime; +}_PingReportResponse_t; + + +typedef struct +{ + _u32 ip; + _u32 gateway; + _u32 dns; +}_IpV4AcquiredAsync_t; + + +typedef enum +{ + ACQUIRED_IPV6_LOCAL = 1, + ACQUIRED_IPV6_GLOBAL +}IpV6AcquiredType_e; + + +typedef struct +{ + _u32 type; + _u32 ip[4]; + _u32 gateway[4]; + _u32 dns[4]; +}_IpV6AcquiredAsync_t; + + +typedef union +{ + _SocketCommand_t EventMask; + _sendRecvCommand_t DeviceInit; +}_device_commands_t; + +/***************************************************************************************** +* FS structs +******************************************************************************************/ + +typedef struct +{ + _u32 FileHandle; + _u32 Offset; + _u16 Len; + _u16 Padding; +}_FsReadCommand_t; + +typedef struct +{ + _u32 Mode; + _u32 Token; +}_FsOpenCommand_t; + +typedef struct +{ + _u32 FileHandle; + _u32 Token; +}_FsOpenResponse_t; + + +typedef struct +{ + _u32 FileHandle; + _u32 CertificFileNameLength; + _u32 SignatureLen; +}_FsCloseCommand_t; + + +typedef _BasicResponse_t _FsReadResponse_t; +typedef _BasicResponse_t _FsDeleteResponse_t; +typedef _BasicResponse_t _FsCloseResponse_t; + +typedef struct +{ + _u16 Status; + _u16 flags; + _u32 FileLen; + _u32 AllocatedLen; + _u32 Token[4]; +}_FsGetInfoResponse_t; + +typedef struct +{ + _u8 DeviceID; + _u8 Padding[3]; +}_FsFormatCommand_t; + +typedef _BasicResponse_t _FsFormatResponse_t; + +typedef struct +{ + _u32 Token; +}_FsDeleteCommand_t; + +typedef _FsDeleteCommand_t _FsGetInfoCommand_t; + +typedef struct +{ + _u32 FileHandle; + _u32 Offset; + _u16 Len; + _u16 Padding; +}_FsWriteCommand_t; + +typedef _BasicResponse_t _FsWriteResponse_t; + + + +/* TODO: Set MAx Async Payload length depending on flavor (Tiny, Small, etc.) */ + + +#ifdef SL_TINY_EXT +#define SL_ASYNC_MAX_PAYLOAD_LEN 120 /* size must be aligned to 4 */ +#else +#define SL_ASYNC_MAX_PAYLOAD_LEN 160 /* size must be aligned to 4 */ +#endif + +#define SL_ASYNC_MAX_MSG_LEN (_SL_RESP_HDR_SIZE + SL_ASYNC_MAX_PAYLOAD_LEN) + +#define RECV_ARGS_SIZE (sizeof(_SocketResponse_t)) +#define RECVFROM_IPV4_ARGS_SIZE (sizeof(_SocketAddrAsyncIPv4Response_t)) +#define RECVFROM_IPV6_ARGS_SIZE (sizeof(_SocketAddrAsyncIPv6Response_t)) + +#define SL_IPV4_ADDRESS_SIZE (sizeof(_u32)) +#define SL_IPV6_ADDRESS_SIZE (4 * sizeof(_u32)) + +#endif /* _SL_PROTOCOL_TYPES_H_ */ diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/simplelink.h b/src/openmv/src/micropython/drivers/cc3100/inc/simplelink.h new file mode 100755 index 0000000..19ca17f --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/simplelink.h @@ -0,0 +1,948 @@ +/* + * simplelink.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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. + * +*/ + + +/*! + \mainpage SimpleLink Driver + + \section intro_sec Introduction + + The SimpleLink CC31xx/CC2xx family allows to add Wi-Fi and networking capabilities + to low-cost embedded products without having prior Wi-Fi, RF or networking expertise. + The CC31xx/CC32xx is an ideal solution for microcontroller-based sensor and control + applications such as home appliances, home automation and smart metering. + The CC31xx/CC32xx has integrated a comprehensive TCP/IP network stack, Wi-Fi driver and + security supplicant leading to easier portability to microcontrollers, to an + ultra-low memory footprint, all without compromising the capabilities and robustness + of the final application. + + + + \section modules_sec Module Names + To make it simple, TI's SimpleLink CC31xx/CC32xx platform capabilities were divided into modules by topic (Silo). + These capabilities range from basic device management through wireless + network configuration, standard BSD socket and much more. + Listed below are the various modules in the SimpleLink CC31xx/CC32xx driver: + -# \ref device - controls the behaviour of the CC31xx/CC32xx device (start/stop, events masking and obtaining specific device status) + -# \ref wlan - controls the use of the WiFi WLAN module including: + - Connection features, such as: profiles, policies, SmartConfig� + - Advanced WLAN features, such as: scans, rx filters and rx statistics collection + -# \ref socket - controls standard client/server sockets programming options and capabilities + -# \ref netapp - activates networking applications, such as: HTTP Server, DHCP Server, Ping, DNS and mDNS. + -# \ref netcfg - controls the configuration of the device addresses (i.e. IP and MAC addresses) + -# \ref FileSystem - provides file system capabilities to TI's CC31XX that can be used by both the CC31XX device and the user. + + + \section proting_sec Porting Guide + + The porting of the SimpleLink driver to any new platform is based on few simple steps. + This guide takes you through this process step by step. Please follow the instructions + carefully to avoid any problems during this process and to enable efficient and proper + work with the device. + Please notice that all modifications and porting adjustments of the driver should be + made in the user.h header file only. + Keep making any of the changes only in this file will ensure smoothly transaction to + new versions of the driver at the future! + + + \subsection porting_step1 Step 1 - Create your own user.h file + + The first step is to create a user.h file that will include your configurations and + adjustments. You can use the empty template provided as part of this driver or + you can choose to base your file on file from one of the wide range of examples + applications provided by Texas Instruments + + + \subsection porting_step2 Step 2 - Select the capabilities set required for your application + + Texas Instruments made a lot of efforts to build set of predefined capability sets that would + fit most of the target application. + It is recommended to try and choose one of this predefined capabilities set before going to + build your own customized set. If you find compatible set you can skip the rest of this step. + + The available sets are: + -# SL_TINY - Compatible to be used on platforms with very limited resources. Provides + the best in class foot print in terms of Code and Data consumption. + -# SL_SMALL - Compatible to most common networking applications. Provide the most + common APIs with decent balance between code size, data size, functionality + and performances + -# SL_FULL - Provide access to all SimpleLink functionalities + + + \subsection porting_step3 Step 3 - Bind the device enable/disable output line + + The enable/disable line (nHib) provide mechanism to enter the device into the least current + consumption mode. This mode could be used when no traffic is required (tx/rx). + when this line is not connected to any IO of the host this define should be left empty. + Not connecting this line results in ability to start the driver only once. + + + \subsection porting_step4 Step 4 - Writing your interface communication driver + + The SimpleLink device support several standard communication protocol among SPI and + UART. Depending on your needs and your hardware design, you should choose the + communication channel type. + The interface for this communication channel should include 4 simple access functions: + -# open + -# close + -# read + -# write + + The way this driver would be implemented is directly effecting the efficiency and + the performances of the SimpleLink device on this platform. + If your system has DMA you should consider to use it in order to increase the utilization + of the communication channel + If you have enough memory resources you should consider using a buffer to increase the + efficiency of the write operations. + + + \subsection porting_step5 Step 5 - Choose your memory management model + + The SimpleLink driver support two memory models: + -# Static (default) + -# Dynamic + + If you choose to work in dynamic model you will have to provide alloc and free functions + to be used by the Simple Link driver otherwise nothing need to be done. + + + \subsection porting_step6 Step 6 - OS adaptation + + The SimpleLink driver could run on two kind of platforms: + -# Non-Os / Single Threaded (default) + -# Multi-Threaded + + If you choose to work in multi-threaded environment under operating system you will have to + provide some basic adaptation routines to allow the driver to protect access to resources + for different threads (locking object) and to allow synchronization between threads (sync objects). + In additional the driver support running without dedicated thread allocated solely to the simple + link driver. If you choose to work in this mode, you should also supply a spawn method that + will enable to run function on a temporary context. + + + \subsection porting_step7 Step 7 - Set your asynchronous event handlers routines + + The SimpleLink device generate asynchronous events in several situations. + These asynchronous events could be masked. + In order to catch these events you have to provide handler routines. + Please notice that if you not provide a handler routine and the event is received, + the driver will drop this event without any indication of this drop. + + + \subsection porting_step8 Step 8 - Run diagnostic tools to validate the correctness of your porting + + The driver is delivered with some porting diagnostic tools to simplify the porting validation process + and to reduce issues latter. It is very important to follow carefully this process. + + The diagnostic process include: + -# Validating Interface Communication Driver + -# Validating OS adaptation layer + -# Validating HW integrity + -# Validating basic work with the device + + + \section sw_license License + + * + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __SIMPLELINK_H__ +#define __SIMPLELINK_H__ + +#include "user.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/*! \attention Async event activation notes + Function prototypes for event callback handlers + Event handler function names should be defined in the user.h file + e.g. + "#define sl_WlanEvtHdlr SLWlanEventHandler" + Indicates all WLAN events are handled by User func "SLWlanEventHandler" + Important notes: + 1. Event handlers cannot activate another SimpleLink API from the event's context + 2. Event's data is valid during event's context. Any application data + which is required for the user application should be copied or marked + into user's variables + 3. It is not recommended to delay the execution of the event callback handler + +*/ + +/*! + + \addtogroup UserEvents + @{ + +*/ + + +/*****************************************************************************/ +/* Macro declarations for Host Driver version */ +/*****************************************************************************/ +#define SL_DRIVER_VERSION "1.0.0.10" +#define SL_MAJOR_VERSION_NUM 1L +#define SL_MINOR_VERSION_NUM 0L +#define SL_VERSION_NUM 0L +#define SL_SUB_VERSION_NUM 10L + + +/*****************************************************************************/ +/* Macro declarations for predefined configurations */ +/*****************************************************************************/ + +#ifdef SL_TINY +#undef SL_INC_ARG_CHECK +#undef SL_INC_EXT_API +#undef SL_INC_SOCK_SERVER_SIDE_API +#undef SL_INC_WLAN_PKG +#undef SL_INC_NET_CFG_PKG +#undef SL_INC_FS_PKG +#undef SL_INC_SET_UART_MODE +#undef SL_INC_STD_BSD_API_NAMING +#undef SL_INC_SOCK_CLIENT_SIDE_API +#undef SL_INC_NET_APP_PKG +#undef SL_INC_SOCK_RECV_API +#undef SL_INC_SOCK_SEND_API +#undef SL_INC_SOCKET_PKG +#endif + +#ifdef SL_SMALL +#undef SL_INC_EXT_API +#undef SL_INC_NET_APP_PKG +#undef SL_INC_NET_CFG_PKG +#undef SL_INC_FS_PKG +#define SL_INC_ARG_CHECK +#define SL_INC_WLAN_PKG +#define SL_INC_SOCKET_PKG +#define SL_INC_SOCK_CLIENT_SIDE_API +#define SL_INC_SOCK_SERVER_SIDE_API +#define SL_INC_SOCK_RECV_API +#define SL_INC_SOCK_SEND_API +#define SL_INC_SET_UART_MODE +#endif + +#ifdef SL_FULL +#define SL_INC_EXT_API +#define SL_INC_NET_APP_PKG +#define SL_INC_NET_CFG_PKG +#define SL_INC_FS_PKG +#define SL_INC_ARG_CHECK +#define SL_INC_WLAN_PKG +#define SL_INC_SOCKET_PKG +#define SL_INC_SOCK_CLIENT_SIDE_API +#define SL_INC_SOCK_SERVER_SIDE_API +#define SL_INC_SOCK_RECV_API +#define SL_INC_SOCK_SEND_API +#define SL_INC_SET_UART_MODE +#endif + +#define SL_RET_CODE_OK (0) +#define SL_RET_CODE_INVALID_INPUT (-2) +#define SL_RET_CODE_SELF_ERROR (-3) +#define SL_RET_CODE_NWP_IF_ERROR (-4) +#define SL_RET_CODE_MALLOC_ERROR (-5) + +#define sl_Memcpy memcpy +#define sl_Memset memset + +#define sl_SyncObjClear(pObj) sl_SyncObjWait(pObj,SL_OS_NO_WAIT) + +#ifndef SL_TINY_EXT +#define SL_MAX_SOCKETS (8) +#else +#define SL_MAX_SOCKETS (2) +#endif + + +/*****************************************************************************/ +/* Types definitions */ +/*****************************************************************************/ +typedef void (*_SlSpawnEntryFunc_t)(void* pValue); + +#ifndef NULL +#define NULL (0) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifndef OK +#define OK (0) +#endif + +#ifndef _SL_USER_TYPES + typedef unsigned char _u8; + typedef signed char _i8; + + typedef unsigned short _u16; + typedef signed short _i16; + + typedef unsigned long _u32; + typedef signed long _i32; + #define _volatile volatile + #define _const const +#endif + +typedef _u16 _SlOpcode_t; +typedef _u8 _SlArgSize_t; +typedef _i16 _SlDataSize_t; +typedef _i16 _SlReturnVal_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + + +/* + * This event status used to block or continue the event propagation + * through all the registered external libs/user application + * + */ + + typedef enum { + EVENT_PROPAGATION_BLOCK = 0, + EVENT_PROPAGATION_CONTINUE + + } _SlEventPropogationStatus_e; + + + + + + +/*****************************************************************************/ +/* Include files */ +/*****************************************************************************/ + +#ifdef SL_PLATFORM_MULTI_THREADED + #include "spawn.h" +#else + #include "nonos.h" +#endif + + +/* + objInclusion.h and user.h must be included before all api header files + objInclusion.h must be the last arrangement just before including the API header files + since it based on the other configurations to decide which object should be included +*/ +#include "objInclusion.h" +#include "trace.h" +#include "fs.h" +#include "socket.h" +#include "netapp.h" +#include "wlan.h" +#include "device.h" +#include "netcfg.h" +#include "wlan_rx_filters.h" + + + /* The general events dispatcher which is + * initialized to the user handler */ +#ifdef sl_GeneralEvtHdlr +#define _SlDrvHandleGeneralEvents sl_GeneralEvtHdlr +#endif + + /* The wlan events dispatcher which is + * initialized to the user handler */ +#ifdef sl_WlanEvtHdlr +#define _SlDrvHandleWlanEvents sl_WlanEvtHdlr +#endif + + /* The NetApp events dispatcher which is + * initialized to the user handler */ +#ifdef sl_NetAppEvtHdlr +#define _SlDrvHandleNetAppEvents sl_NetAppEvtHdlr +#endif + + /* The http server events dispatcher which is + * initialized to the user handler if exists */ +#ifdef sl_HttpServerCallback +#define _SlDrvHandleHttpServerEvents sl_HttpServerCallback +#endif + + /* The socket events dispatcher which is + * initialized to the user handler */ +#ifdef sl_SockEvtHdlr +#define _SlDrvHandleSockEvents sl_SockEvtHdlr +#endif + + +#ifndef __CONCAT +#define __CONCAT(x,y) x ## y +#endif +#define __CONCAT2(x,y) __CONCAT(x,y) + + +/* + * The section below handles the external lib event registration + * according to the desired events it specified in its API header file. + * The external lib should be first installed by the user (see user.h) + */ +#ifdef SL_EXT_LIB_1 + + /* General Event Registration */ + #if __CONCAT2(SL_EXT_LIB_1, _NOTIFY_GENERAL_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_1, _GeneralEventHdl) (SlDeviceEvent_t *); + #define SlExtLib1GeneralEventHandler __CONCAT2(SL_EXT_LIB_1, _GeneralEventHdl) + + #undef EXT_LIB_REGISTERED_GENERAL_EVENTS + #define EXT_LIB_REGISTERED_GENERAL_EVENTS + #endif + + /* Wlan Event Registration */ + #if __CONCAT2(SL_EXT_LIB_1, _NOTIFY_WLAN_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_1, _WlanEventHdl) (SlWlanEvent_t *); + #define SlExtLib1WlanEventHandler __CONCAT2(SL_EXT_LIB_1, _WlanEventHdl) + + #undef EXT_LIB_REGISTERED_WLAN_EVENTS + #define EXT_LIB_REGISTERED_WLAN_EVENTS + #endif + + /* NetApp Event Registration */ + #if __CONCAT2(SL_EXT_LIB_1, _NOTIFY_NETAPP_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_1, _NetAppEventHdl) (SlNetAppEvent_t *); + #define SlExtLib1NetAppEventHandler __CONCAT2(SL_EXT_LIB_1, _NetAppEventHdl) + + #undef EXT_LIB_REGISTERED_NETAPP_EVENTS + #define EXT_LIB_REGISTERED_NETAPP_EVENTS + #endif + + /* Http Server Event Registration */ + #if __CONCAT2(SL_EXT_LIB_1, _NOTIFY_HTTP_SERVER_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_1, _HttpServerEventHdl) (SlHttpServerEvent_t* , SlHttpServerResponse_t*); + #define SlExtLib1HttpServerEventHandler __CONCAT2(SL_EXT_LIB_1, _HttpServerEventHdl) + + #undef EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #define EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #endif + + /* Socket Event Registration */ + #if __CONCAT2(SL_EXT_LIB_1, _NOTIFY_SOCK_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_1, _SockEventHdl) (SlSockEvent_t *); + #define SlExtLib1SockEventHandler __CONCAT2(SL_EXT_LIB_1, _SockEventHdl) + + #undef EXT_LIB_REGISTERED_SOCK_EVENTS + #define EXT_LIB_REGISTERED_SOCK_EVENTS + #endif + +#endif + + +#ifdef SL_EXT_LIB_2 + + /* General Event Registration */ + #if __CONCAT2(SL_EXT_LIB_2, _NOTIFY_GENERAL_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_2, _GeneralEventHdl) (SlDeviceEvent_t *); + #define SlExtLib2GeneralEventHandler __CONCAT2(SL_EXT_LIB_2, _GeneralEventHdl) + + #undef EXT_LIB_REGISTERED_GENERAL_EVENTS + #define EXT_LIB_REGISTERED_GENERAL_EVENTS + #endif + + /* Wlan Event Registration */ + #if __CONCAT2(SL_EXT_LIB_2, _NOTIFY_WLAN_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_2, _WlanEventHdl) (SlWlanEvent_t *); + #define SlExtLib2WlanEventHandler __CONCAT2(SL_EXT_LIB_2, _WlanEventHdl) + + #undef EXT_LIB_REGISTERED_WLAN_EVENTS + #define EXT_LIB_REGISTERED_WLAN_EVENTS + #endif + + /* NetApp Event Registration */ + #if __CONCAT2(SL_EXT_LIB_2, _NOTIFY_NETAPP_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_2, _NetAppEventHdl) (SlNetAppEvent_t *); + #define SlExtLib2NetAppEventHandler __CONCAT2(SL_EXT_LIB_2, _NetAppEventHdl) + + #undef EXT_LIB_REGISTERED_NETAPP_EVENTS + #define EXT_LIB_REGISTERED_NETAPP_EVENTS + #endif + + /* Http Server Event Registration */ + #if __CONCAT2(SL_EXT_LIB_2, _NOTIFY_HTTP_SERVER_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_2, _HttpServerEventHdl) (SlHttpServerEvent_t* , SlHttpServerResponse_t*); + #define SlExtLib2HttpServerEventHandler __CONCAT2(SL_EXT_LIB_2, _HttpServerEventHdl) + + #undef EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #define EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #endif + + /* Socket Event Registration */ + #if __CONCAT2(SL_EXT_LIB_2, _NOTIFY_SOCK_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_2, _SockEventHdl) (SlSockEvent_t *); + #define SlExtLib2SockEventHandler __CONCAT2(SL_EXT_LIB_2, _SockEventHdl) + + #undef EXT_LIB_REGISTERED_SOCK_EVENTS + #define EXT_LIB_REGISTERED_SOCK_EVENTS + #endif + +#endif + + +#ifdef SL_EXT_LIB_3 + + /* General Event Registration */ + #if __CONCAT2(SL_EXT_LIB_3, _NOTIFY_GENERAL_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_3, _GeneralEventHdl) (SlDeviceEvent_t *); + #define SlExtLib3GeneralEventHandler __CONCAT2(SL_EXT_LIB_3, _GeneralEventHdl) + + #undef EXT_LIB_REGISTERED_GENERAL_EVENTS + #define EXT_LIB_REGISTERED_GENERAL_EVENTS + #endif + + /* Wlan Event Registration */ + #if __CONCAT2(SL_EXT_LIB_3, _NOTIFY_WLAN_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_3, _WlanEventHdl) (SlWlanEvent_t *); + #define SlExtLib3WlanEventHandler __CONCAT2(SL_EXT_LIB_3, _WlanEventHdl) + + #undef EXT_LIB_REGISTERED_WLAN_EVENTS + #define EXT_LIB_REGISTERED_WLAN_EVENTS + #endif + + /* NetApp Event Registration */ + #if __CONCAT2(SL_EXT_LIB_3, _NOTIFY_NETAPP_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_3, _NetAppEventHdl) (SlNetAppEvent_t *); + #define SlExtLib3NetAppEventHandler __CONCAT2(SL_EXT_LIB_3, _NetAppEventHdl) + + #undef EXT_LIB_REGISTERED_NETAPP_EVENTS + #define EXT_LIB_REGISTERED_NETAPP_EVENTS + #endif + + /* Http Server Event Registration */ + #if __CONCAT2(SL_EXT_LIB_3, _NOTIFY_HTTP_SERVER_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_3, _HttpServerEventHdl) (SlHttpServerEvent_t* , SlHttpServerResponse_t*); + #define SlExtLib3HttpServerEventHandler __CONCAT2(SL_EXT_LIB_3, _HttpServerEventHdl) + + #undef EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #define EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #endif + + /* Socket Event Registration */ + #if __CONCAT2(SL_EXT_LIB_3, _NOTIFY_SOCK_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_3, _SockEventHdl) (SlSockEvent_t *); + #define SlExtLib3SockEventHandler __CONCAT2(SL_EXT_LIB_3, _SockEventHdl) + + #undef EXT_LIB_REGISTERED_SOCK_EVENTS + #define EXT_LIB_REGISTERED_SOCK_EVENTS + #endif + +#endif + + +#ifdef SL_EXT_LIB_4 + + /* General Event Registration */ + #if __CONCAT2(SL_EXT_LIB_4, _NOTIFY_GENERAL_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_4, _GeneralEventHdl) (SlDeviceEvent_t *); + #define SlExtLib4GeneralEventHandler __CONCAT2(SL_EXT_LIB_4, _GeneralEventHdl) + + #undef EXT_LIB_REGISTERED_GENERAL_EVENTS + #define EXT_LIB_REGISTERED_GENERAL_EVENTS + #endif + + /* Wlan Event Registration */ + #if __CONCAT2(SL_EXT_LIB_4, _NOTIFY_WLAN_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_4, _WlanEventHdl) (SlWlanEvent_t *); + #define SlExtLib4WlanEventHandler __CONCAT2(SL_EXT_LIB_4, _WlanEventHdl) + + #undef EXT_LIB_REGISTERED_WLAN_EVENTS + #define EXT_LIB_REGISTERED_WLAN_EVENTS + #endif + + /* NetApp Event Registration */ + #if __CONCAT2(SL_EXT_LIB_4, _NOTIFY_NETAPP_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_4, _NetAppEventHdl) (SlNetAppEvent_t *); + #define SlExtLib4NetAppEventHandler __CONCAT2(SL_EXT_LIB_4, _NetAppEventHdl) + + #undef EXT_LIB_REGISTERED_NETAPP_EVENTS + #define EXT_LIB_REGISTERED_NETAPP_EVENTS + #endif + + /* Http Server Event Registration */ + #if __CONCAT2(SL_EXT_LIB_4, _NOTIFY_HTTP_SERVER_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_4, _HttpServerEventHdl) (SlHttpServerEvent_t* , SlHttpServerResponse_t*); + #define SlExtLib4HttpServerEventHandler __CONCAT2(SL_EXT_LIB_4, _HttpServerEventHdl) + + #undef EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #define EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #endif + + /* Socket Event Registration */ + #if __CONCAT2(SL_EXT_LIB_4, _NOTIFY_SOCK_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_4, _SockEventHdl) (SlSockEvent_t *); + #define SlExtLib4SockEventHandler __CONCAT2(SL_EXT_LIB_4, _SockEventHdl) + + #undef EXT_LIB_REGISTERED_SOCK_EVENTS + #define EXT_LIB_REGISTERED_SOCK_EVENTS + #endif + +#endif + + +#ifdef SL_EXT_LIB_5 + + /* General Event Registration */ + #if __CONCAT2(SL_EXT_LIB_5, _NOTIFY_GENERAL_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_5, _GeneralEventHdl) (SlDeviceEvent_t *); + #define SlExtLib5GeneralEventHandler __CONCAT2(SL_EXT_LIB_5, _GeneralEventHdl) + + #undef EXT_LIB_REGISTERED_GENERAL_EVENTS + #define EXT_LIB_REGISTERED_GENERAL_EVENTS + #endif + + /* Wlan Event Registration */ + #if __CONCAT2(SL_EXT_LIB_5, _NOTIFY_WLAN_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_5, _WlanEventHdl) (SlWlanEvent_t *); + #define SlExtLib5WlanEventHandler __CONCAT2(SL_EXT_LIB_5, _WlanEventHdl) + + #undef EXT_LIB_REGISTERED_WLAN_EVENTS + #define EXT_LIB_REGISTERED_WLAN_EVENTS + #endif + + /* NetApp Event Registration */ + #if __CONCAT2(SL_EXT_LIB_5, _NOTIFY_NETAPP_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_5, _NetAppEventHdl) (SlNetAppEvent_t *); + #define SlExtLib5NetAppEventHandler __CONCAT2(SL_EXT_LIB_5, _NetAppEventHdl) + + #undef EXT_LIB_REGISTERED_NETAPP_EVENTS + #define EXT_LIB_REGISTERED_NETAPP_EVENTS + #endif + + /* Http Server Event Registration */ + #if __CONCAT2(SL_EXT_LIB_5, _NOTIFY_HTTP_SERVER_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_5, _HttpServerEventHdl) (SlHttpServerEvent_t* , SlHttpServerResponse_t*); + #define SlExtLib5HttpServerEventHandler __CONCAT2(SL_EXT_LIB_5, _HttpServerEventHdl) + + #undef EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #define EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS + #endif + + /* Socket Event Registration */ + #if __CONCAT2(SL_EXT_LIB_5, _NOTIFY_SOCK_EVENT) + extern _SlEventPropogationStatus_e __CONCAT2(SL_EXT_LIB_5, _SockEventHdl) (SlSockEvent_t *); + #define SlExtLib5SockEventHandler __CONCAT2(SL_EXT_LIB_5, _SockEventHdl) + + #undef EXT_LIB_REGISTERED_SOCK_EVENTS + #define EXT_LIB_REGISTERED_SOCK_EVENTS + #endif + +#endif + + + +#if defined(EXT_LIB_REGISTERED_GENERAL_EVENTS) +extern void _SlDrvHandleGeneralEvents(SlDeviceEvent_t *slGeneralEvent); +#endif + +#if defined(EXT_LIB_REGISTERED_WLAN_EVENTS) +extern void _SlDrvHandleWlanEvents(SlWlanEvent_t *slWlanEvent); +#endif + +#if defined (EXT_LIB_REGISTERED_NETAPP_EVENTS) +extern void _SlDrvHandleNetAppEvents(SlNetAppEvent_t *slNetAppEvent); +#endif + +#if defined(EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) +extern void _SlDrvHandleHttpServerEvents(SlHttpServerEvent_t *slHttpServerEvent, SlHttpServerResponse_t *slHttpServerResponse); +#endif + + +#if defined(EXT_LIB_REGISTERED_SOCK_EVENTS) +extern void _SlDrvHandleSockEvents(SlSockEvent_t *slSockEvent); +#endif + + +typedef void (*_SlSpawnEntryFunc_t)(void* pValue); + + +/* Async functions description*/ + +/*! + \brief General async event for inspecting general events + + \param[out] pSlDeviceEvent pointer to SlDeviceEvent_t + + \par + Parameters: \n + - pSlDeviceEvent->Event = SL_DEVICE_FATAL_ERROR_EVENT + - pSlDeviceEvent->EventData.deviceEvent fields: + - status: An error code indication from the device + - sender: The sender originator which is based on SlErrorSender_e enum + + - pSlDeviceEvent->Event = SL_DEVICE_ABORT_ERROR_EVENT + Indicates a severe error occured and the device stopped + - pSlDeviceEvent->EventData.deviceReport fields: + - AbortType: An idication of the event type + - AbortData: Additional info about the data error + + + \par Example for fatal error: + \code + printf(General Event Handler - ID=%d Sender=%d\n\n", + pSlDeviceEvent->EventData.deviceEvent.status, // status of the general event + pSlDeviceEvent->EventData.deviceEvent.sender); // sender type + \endcode + \par Example for abort request: + \code + printf(Abort type =%d Abort Data=%d\n\n", + pSlDeviceEvent->EventData.deviceReport.AbortType, + pSlDeviceEvent->EventData.deviceReport.AbortData); + + \endcode +*/ +#if (defined(sl_GeneralEvtHdlr)) +extern void sl_GeneralEvtHdlr(SlDeviceEvent_t *pSlDeviceEvent); +#endif + + +/*! + \brief WLAN Async event handler + + \param[out] pSlWlanEvent pointer to SlWlanEvent_t data + + \par + Parameters: + + - pSlWlanEvent->Event = SL_WLAN_CONNECT_EVENT , STA or P2P client connection indication event + - pSlWlanEvent->EventData.STAandP2PModeWlanConnected main fields: + - ssid_name + - ssid_len + - bssid + - go_peer_device_name + - go_peer_device_name_len + + - pSlWlanEvent->Event = SL_WLAN_DISCONNECT_EVENT , STA or P2P client disconnection event + - pSlWlanEvent->EventData.STAandP2PModeDisconnected main fields: + - ssid_name + - ssid_len + - reason_code + + - pSlWlanEvent->Event = SL_WLAN_STA_CONNECTED_EVENT , AP/P2P(Go) connected STA/P2P(Client) + - pSlWlanEvent->EventData.APModeStaConnected fields: + - go_peer_device_name + - mac + - go_peer_device_name_len + - wps_dev_password_id + - own_ssid: relevant for event sta-connected only + - own_ssid_len: relevant for event sta-connected only + + - pSlWlanEvent->Event = SL_WLAN_STA_DISCONNECTED_EVENT , AP/P2P(Go) disconnected STA/P2P(Client) + - pSlWlanEvent->EventData.APModestaDisconnected fields: + - go_peer_device_name + - mac + - go_peer_device_name_len + - wps_dev_password_id + - own_ssid: relevant for event sta-connected only + - own_ssid_len: relevant for event sta-connected only + + - pSlWlanEvent->Event = SL_WLAN_SMART_CONFIG_COMPLETE_EVENT + - pSlWlanEvent->EventData.smartConfigStartResponse fields: + - status + - ssid_len + - ssid + - private_token_len + - private_token + + - pSlWlanEvent->Event = SL_WLAN_SMART_CONFIG_STOP_EVENT + - pSlWlanEvent->EventData.smartConfigStopResponse fields: + - status + + - pSlWlanEvent->Event = SL_WLAN_P2P_DEV_FOUND_EVENT + - pSlWlanEvent->EventData.P2PModeDevFound fields: + - go_peer_device_name + - mac + - go_peer_device_name_len + - wps_dev_password_id + - own_ssid: relevant for event sta-connected only + - own_ssid_len: relevant for event sta-connected only + + - pSlWlanEvent->Event = SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT + - pSlWlanEvent->EventData.P2PModeNegReqReceived fields + - go_peer_device_name + - mac + - go_peer_device_name_len + - wps_dev_password_id + - own_ssid: relevant for event sta-connected only + + - pSlWlanEvent->Event = SL_WLAN_CONNECTION_FAILED_EVENT , P2P only + - pSlWlanEvent->EventData.P2PModewlanConnectionFailure fields: + - status +*/ +#if (defined(sl_WlanEvtHdlr)) +extern void sl_WlanEvtHdlr(SlWlanEvent_t* pSlWlanEvent); +#endif + + +/*! + \brief NETAPP Async event handler + + \param[out] pSlNetApp pointer to SlNetAppEvent_t data + + \par + Parameters: + - pSlNetApp->Event = SL_NETAPP_IPV4_IPACQUIRED_EVENT, IPV4 acquired event + - pSlNetApp->EventData.ipAcquiredV4 fields: + - ip + - gateway + - dns + + - pSlNetApp->Event = SL_NETAPP_IP_LEASED_EVENT, AP or P2P go dhcp lease event + - pSlNetApp->EventData.ipLeased fields: + - ip_address + - lease_time + - mac + + - pSlNetApp->Event = SL_NETAPP_IP_RELEASED_EVENT, AP or P2P go dhcp ip release event + - pSlNetApp->EventData.ipReleased fields + - ip_address + - mac + - reason + +*/ +#if (defined(sl_NetAppEvtHdlr)) +extern void sl_NetAppEvtHdlr(SlNetAppEvent_t* pSlNetApp); +#endif + +/*! + \brief Socket Async event handler + + \param[out] pSlSockEvent pointer to SlSockEvent_t data + + \par + Parameters:\n + - pSlSockEvent->Event = SL_SOCKET_TX_FAILED_EVENT + - pSlSockEvent->SockTxFailData fields: + - sd + - status + - pSlSockEvent->Event = SL_SOCKET_ASYNC_EVENT + - pSlSockEvent->SockAsyncData fields: + - sd + - type: SSL_ACCEPT or RX_FRAGMENTATION_TOO_BIG or OTHER_SIDE_CLOSE_SSL_DATA_NOT_ENCRYPTED + - val + +*/ +#if (defined(sl_SockEvtHdlr)) +extern void sl_SockEvtHdlr(SlSockEvent_t* pSlSockEvent); +#endif + +/*! + \brief HTTP server async event + + \param[out] pSlHttpServerEvent pointer to SlHttpServerEvent_t + \param[in] pSlHttpServerResponse pointer to SlHttpServerResponse_t + + \par + Parameters: \n + + - pSlHttpServerEvent->Event = SL_NETAPP_HTTPGETTOKENVALUE_EVENT + - pSlHttpServerEvent->EventData fields: + - httpTokenName + - data + - len + - pSlHttpServerResponse->ResponseData fields: + - data + - len + + - pSlHttpServerEvent->Event = SL_NETAPP_HTTPPOSTTOKENVALUE_EVENT + - pSlHttpServerEvent->EventData.httpPostData fields: + - action + - token_name + - token_value + - pSlHttpServerResponse->ResponseData fields: + - data + - len + +*/ +#if (defined(sl_HttpServerCallback)) +extern void sl_HttpServerCallback(SlHttpServerEvent_t *pSlHttpServerEvent, SlHttpServerResponse_t *pSlHttpServerResponse); +#endif +/*! + + Close the Doxygen group. + @} + + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SIMPLELINK_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/socket.h b/src/openmv/src/micropython/drivers/cc3100/inc/socket.h new file mode 100755 index 0000000..81554d4 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/socket.h @@ -0,0 +1,1573 @@ +/* + * socket.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + +#ifndef __SL_SOCKET_H__ +#define __SL_SOCKET_H__ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + + \addtogroup socket + @{ + +*/ + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +#define SL_FD_SETSIZE SL_MAX_SOCKETS /* Number of sockets to select on - same is max sockets! */ +#define BSD_SOCKET_ID_MASK (0x0F) /* Index using the LBS 4 bits for socket id 0-7 */ +/* Define some BSD protocol constants. */ +#define SL_SOCK_STREAM (1) /* TCP Socket */ +#define SL_SOCK_DGRAM (2) /* UDP Socket */ +#define SL_SOCK_RAW (3) /* Raw socket */ +#define SL_IPPROTO_TCP (6) /* TCP Raw Socket */ +#define SL_IPPROTO_UDP (17) /* UDP Raw Socket */ +#define SL_IPPROTO_RAW (255) /* Raw Socket */ +#define SL_SEC_SOCKET (100) /* Secured Socket Layer (SSL,TLS) */ + +/* Address families. */ +#define SL_AF_INET (2) /* IPv4 socket (UDP, TCP, etc) */ +#define SL_AF_INET6 (3) /* IPv6 socket (UDP, TCP, etc) */ +#define SL_AF_INET6_EUI_48 (9) +#define SL_AF_RF (6) /* data include RF parameter, All layer by user (Wifi could be disconnected) */ +#define SL_AF_PACKET (17) +/* Protocol families, same as address families. */ +#define SL_PF_INET AF_INET +#define SL_PF_INET6 AF_INET6 +#define SL_INADDR_ANY (0) /* bind any address */ + +/* error codes */ +#define SL_SOC_ERROR (-1) /* Failure. */ +#define SL_SOC_OK ( 0) /* Success. */ +#define SL_INEXE (-8) /* socket command in execution */ +#define SL_EBADF (-9) /* Bad file number */ +#define SL_ENSOCK (-10) /* The system limit on the total number of open socket, has been reached */ +#define SL_EAGAIN (-11) /* Try again */ +#define SL_EWOULDBLOCK SL_EAGAIN +#define SL_ENOMEM (-12) /* Out of memory */ +#define SL_EACCES (-13) /* Permission denied */ +#define SL_EFAULT (-14) /* Bad address */ +#define SL_ECLOSE (-15) /* close socket operation failed to transmit all queued packets */ +#define SL_EALREADY_ENABLED (-21) /* Transceiver - Transceiver already ON. there could be only one */ +#define SL_EINVAL (-22) /* Invalid argument */ +#define SL_EAUTO_CONNECT_OR_CONNECTING (-69) /* Transceiver - During connection, connected or auto mode started */ +#define SL_CONNECTION_PENDING (-72) /* Transceiver - Device is connected, disconnect first to open transceiver */ +#define SL_EUNSUPPORTED_ROLE (-86) /* Transceiver - Trying to start when WLAN role is AP or P2P GO */ +#define SL_EDESTADDRREQ (-89) /* Destination address required */ +#define SL_EPROTOTYPE (-91) /* Protocol wrong type for socket */ +#define SL_ENOPROTOOPT (-92) /* Protocol not available */ +#define SL_EPROTONOSUPPORT (-93) /* Protocol not supported */ +#define SL_ESOCKTNOSUPPORT (-94) /* Socket type not supported */ +#define SL_EOPNOTSUPP (-95) /* Operation not supported on transport endpoint */ +#define SL_EAFNOSUPPORT (-97) /* Address family not supported by protocol */ +#define SL_EADDRINUSE (-98) /* Address already in use */ +#define SL_EADDRNOTAVAIL (-99) /* Cannot assign requested address */ +#define SL_ENETUNREACH (-101) /* Network is unreachable */ +#define SL_ENOBUFS (-105) /* No buffer space available */ +#define SL_EOBUFF SL_ENOBUFS +#define SL_EISCONN (-106) /* Transport endpoint is already connected */ +#define SL_ENOTCONN (-107) /* Transport endpoint is not connected */ +#define SL_ETIMEDOUT (-110) /* Connection timed out */ +#define SL_ECONNREFUSED (-111) /* Connection refused */ +#define SL_EALREADY (-114) /* Non blocking connect in progress, try again */ + +#define SL_ESEC_RSA_WRONG_TYPE_E (-130) /* RSA wrong block type for RSA function */ +#define SL_ESEC_RSA_BUFFER_E (-131) /* RSA buffer error, output too small or */ +#define SL_ESEC_BUFFER_E (-132) /* output buffer too small or input too large */ +#define SL_ESEC_ALGO_ID_E (-133) /* setting algo id error */ +#define SL_ESEC_PUBLIC_KEY_E (-134) /* setting public key error */ +#define SL_ESEC_DATE_E (-135) /* setting date validity error */ +#define SL_ESEC_SUBJECT_E (-136) /* setting subject name error */ +#define SL_ESEC_ISSUER_E (-137) /* setting issuer name error */ +#define SL_ESEC_CA_TRUE_E (-138) /* setting CA basic constraint true error */ +#define SL_ESEC_EXTENSIONS_E (-139) /* setting extensions error */ +#define SL_ESEC_ASN_PARSE_E (-140) /* ASN parsing error, invalid input */ +#define SL_ESEC_ASN_VERSION_E (-141) /* ASN version error, invalid number */ +#define SL_ESEC_ASN_GETINT_E (-142) /* ASN get big _i16 error, invalid data */ +#define SL_ESEC_ASN_RSA_KEY_E (-143) /* ASN key init error, invalid input */ +#define SL_ESEC_ASN_OBJECT_ID_E (-144) /* ASN object id error, invalid id */ +#define SL_ESEC_ASN_TAG_NULL_E (-145) /* ASN tag error, not null */ +#define SL_ESEC_ASN_EXPECT_0_E (-146) /* ASN expect error, not zero */ +#define SL_ESEC_ASN_BITSTR_E (-147) /* ASN bit string error, wrong id */ +#define SL_ESEC_ASN_UNKNOWN_OID_E (-148) /* ASN oid error, unknown sum id */ +#define SL_ESEC_ASN_DATE_SZ_E (-149) /* ASN date error, bad size */ +#define SL_ESEC_ASN_BEFORE_DATE_E (-150) /* ASN date error, current date before */ +#define SL_ESEC_ASN_AFTER_DATE_E (-151) /* ASN date error, current date after */ +#define SL_ESEC_ASN_SIG_OID_E (-152) /* ASN signature error, mismatched oid */ +#define SL_ESEC_ASN_TIME_E (-153) /* ASN time error, unknown time type */ +#define SL_ESEC_ASN_INPUT_E (-154) /* ASN input error, not enough data */ +#define SL_ESEC_ASN_SIG_CONFIRM_E (-155) /* ASN sig error, confirm failure */ +#define SL_ESEC_ASN_SIG_HASH_E (-156) /* ASN sig error, unsupported hash type */ +#define SL_ESEC_ASN_SIG_KEY_E (-157) /* ASN sig error, unsupported key type */ +#define SL_ESEC_ASN_DH_KEY_E (-158) /* ASN key init error, invalid input */ +#define SL_ESEC_ASN_NTRU_KEY_E (-159) /* ASN ntru key decode error, invalid input */ +#define SL_ESEC_ECC_BAD_ARG_E (-170) /* ECC input argument of wrong type */ +#define SL_ESEC_ASN_ECC_KEY_E (-171) /* ASN ECC bad input */ +#define SL_ESEC_ECC_CURVE_OID_E (-172) /* Unsupported ECC OID curve type */ +#define SL_ESEC_BAD_FUNC_ARG (-173) /* Bad function argument provided */ +#define SL_ESEC_NOT_COMPILED_IN (-174) /* Feature not compiled in */ +#define SL_ESEC_UNICODE_SIZE_E (-175) /* Unicode password too big */ +#define SL_ESEC_NO_PASSWORD (-176) /* no password provided by user */ +#define SL_ESEC_ALT_NAME_E (-177) /* alt name size problem, too big */ +#define SL_ESEC_AES_GCM_AUTH_E (-180) /* AES-GCM Authentication check failure */ +#define SL_ESEC_AES_CCM_AUTH_E (-181) /* AES-CCM Authentication check failure */ +#define SL_SOCKET_ERROR_E (-208) /* Error state on socket */ + +#define SL_ESEC_MEMORY_ERROR (-203) /* out of memory */ +#define SL_ESEC_VERIFY_FINISHED_ERROR (-204) /* verify problem on finished */ +#define SL_ESEC_VERIFY_MAC_ERROR (-205) /* verify mac problem */ +#define SL_ESEC_UNKNOWN_HANDSHAKE_TYPE (-207) /* weird handshake type */ +#define SL_ESEC_SOCKET_ERROR_E (-208) /* error state on socket */ +#define SL_ESEC_SOCKET_NODATA (-209) /* expected data, not there */ +#define SL_ESEC_INCOMPLETE_DATA (-210) /* don't have enough data to complete task */ +#define SL_ESEC_UNKNOWN_RECORD_TYPE (-211) /* unknown type in record hdr */ +#define SL_ESEC_FATAL_ERROR (-213) /* recvd alert fatal error */ +#define SL_ESEC_ENCRYPT_ERROR (-214) /* error during encryption */ +#define SL_ESEC_NO_PEER_KEY (-216) /* need peer's key */ +#define SL_ESEC_NO_PRIVATE_KEY (-217) /* need the private key */ +#define SL_ESEC_RSA_PRIVATE_ERROR (-218) /* error during rsa priv op */ +#define SL_ESEC_NO_DH_PARAMS (-219) /* server missing DH params */ +#define SL_ESEC_BUILD_MSG_ERROR (-220) /* build message failure */ +#define SL_ESEC_BAD_HELLO (-221) /* client hello malformed */ +#define SL_ESEC_DOMAIN_NAME_MISMATCH (-222) /* peer subject name mismatch */ +#define SL_ESEC_WANT_READ (-223) /* want read, call again */ +#define SL_ESEC_NOT_READY_ERROR (-224) /* handshake layer not ready */ +#define SL_ESEC_PMS_VERSION_ERROR (-225) /* pre m secret version error */ +#define SL_ESEC_VERSION_ERROR (-226) /* record layer version error */ +#define SL_ESEC_WANT_WRITE (-227) /* want write, call again */ +#define SL_ESEC_BUFFER_ERROR (-228) /* malformed buffer input */ +#define SL_ESEC_VERIFY_CERT_ERROR (-229) /* verify cert error */ +#define SL_ESEC_VERIFY_SIGN_ERROR (-230) /* verify sign error */ + +#define SL_ESEC_LENGTH_ERROR (-241) /* record layer length error */ +#define SL_ESEC_PEER_KEY_ERROR (-242) /* can't decode peer key */ +#define SL_ESEC_ZERO_RETURN (-243) /* peer sent close notify */ +#define SL_ESEC_SIDE_ERROR (-244) /* wrong client/server type */ +#define SL_ESEC_NO_PEER_CERT (-245) /* peer didn't send key */ +#define SL_ESEC_ECC_CURVETYPE_ERROR (-250) /* Bad ECC Curve Type */ +#define SL_ESEC_ECC_CURVE_ERROR (-251) /* Bad ECC Curve */ +#define SL_ESEC_ECC_PEERKEY_ERROR (-252) /* Bad Peer ECC Key */ +#define SL_ESEC_ECC_MAKEKEY_ERROR (-253) /* Bad Make ECC Key */ +#define SL_ESEC_ECC_EXPORT_ERROR (-254) /* Bad ECC Export Key */ +#define SL_ESEC_ECC_SHARED_ERROR (-255) /* Bad ECC Shared Secret */ +#define SL_ESEC_NOT_CA_ERROR (-257) /* Not a CA cert error */ +#define SL_ESEC_BAD_PATH_ERROR (-258) /* Bad path for opendir */ +#define SL_ESEC_BAD_CERT_MANAGER_ERROR (-259) /* Bad Cert Manager */ +#define SL_ESEC_MAX_CHAIN_ERROR (-268) /* max chain depth exceeded */ +#define SL_ESEC_SUITES_ERROR (-271) /* suites pointer error */ +#define SL_ESEC_SSL_NO_PEM_HEADER (-272) /* no PEM header found */ +#define SL_ESEC_OUT_OF_ORDER_E (-273) /* out of order message */ +#define SL_ESEC_SANITY_CIPHER_E (-275) /* sanity check on cipher error */ +#define SL_ESEC_GEN_COOKIE_E (-277) /* Generate Cookie Error */ +#define SL_ESEC_NO_PEER_VERIFY (-278) /* Need peer cert verify Error */ +#define SL_ESEC_UNKNOWN_SNI_HOST_NAME_E (-281) /* Unrecognized host name Error */ +/* begin negotiation parameter errors */ +#define SL_ESEC_UNSUPPORTED_SUITE (-290) /* unsupported cipher suite */ +#define SL_ESEC_MATCH_SUITE_ERROR (-291 ) /* can't match cipher suite */ + +/* ssl tls security start with -300 offset */ +#define SL_ESEC_CLOSE_NOTIFY (-300) /* ssl/tls alerts */ +#define SL_ESEC_UNEXPECTED_MESSAGE (-310) /* ssl/tls alerts */ +#define SL_ESEC_BAD_RECORD_MAC (-320) /* ssl/tls alerts */ +#define SL_ESEC_DECRYPTION_FAILED (-321) /* ssl/tls alerts */ +#define SL_ESEC_RECORD_OVERFLOW (-322) /* ssl/tls alerts */ +#define SL_ESEC_DECOMPRESSION_FAILURE (-330) /* ssl/tls alerts */ +#define SL_ESEC_HANDSHAKE_FAILURE (-340) /* ssl/tls alerts */ +#define SL_ESEC_NO_CERTIFICATE (-341) /* ssl/tls alerts */ +#define SL_ESEC_BAD_CERTIFICATE (-342) /* ssl/tls alerts */ +#define SL_ESEC_UNSUPPORTED_CERTIFICATE (-343) /* ssl/tls alerts */ +#define SL_ESEC_CERTIFICATE_REVOKED (-344) /* ssl/tls alerts */ +#define SL_ESEC_CERTIFICATE_EXPIRED (-345) /* ssl/tls alerts */ +#define SL_ESEC_CERTIFICATE_UNKNOWN (-346) /* ssl/tls alerts */ +#define SL_ESEC_ILLEGAL_PARAMETER (-347) /* ssl/tls alerts */ +#define SL_ESEC_UNKNOWN_CA (-348) /* ssl/tls alerts */ +#define SL_ESEC_ACCESS_DENIED (-349) /* ssl/tls alerts */ +#define SL_ESEC_DECODE_ERROR (-350) /* ssl/tls alerts */ +#define SL_ESEC_DECRYPT_ERROR (-351) /* ssl/tls alerts */ +#define SL_ESEC_EXPORT_RESTRICTION (-360) /* ssl/tls alerts */ +#define SL_ESEC_PROTOCOL_VERSION (-370) /* ssl/tls alerts */ +#define SL_ESEC_INSUFFICIENT_SECURITY (-371) /* ssl/tls alerts */ +#define SL_ESEC_INTERNAL_ERROR (-380) /* ssl/tls alerts */ +#define SL_ESEC_USER_CANCELLED (-390) /* ssl/tls alerts */ +#define SL_ESEC_NO_RENEGOTIATION (-400) /* ssl/tls alerts */ +#define SL_ESEC_UNSUPPORTED_EXTENSION (-410) /* ssl/tls alerts */ +#define SL_ESEC_CERTIFICATE_UNOBTAINABLE (-411) /* ssl/tls alerts */ +#define SL_ESEC_UNRECOGNIZED_NAME (-412) /* ssl/tls alerts */ +#define SL_ESEC_BAD_CERTIFICATE_STATUS_RESPONSE (-413) /* ssl/tls alerts */ +#define SL_ESEC_BAD_CERTIFICATE_HASH_VALUE (-414) /* ssl/tls alerts */ +/* propierty secure */ +#define SL_ESECGENERAL (-450) /* error secure level general error */ +#define SL_ESECDECRYPT (-451) /* error secure level, decrypt recv packet fail */ +#define SL_ESECCLOSED (-452) /* secure layrer is closed by other size , tcp is still connected */ +#define SL_ESECSNOVERIFY (-453) /* Connected without server verification */ +#define SL_ESECNOCAFILE (-454) /* error secure level CA file not found*/ +#define SL_ESECMEMORY (-455) /* error secure level No memory space available */ +#define SL_ESECBADCAFILE (-456) /* error secure level bad CA file */ +#define SL_ESECBADCERTFILE (-457) /* error secure level bad Certificate file */ +#define SL_ESECBADPRIVATEFILE (-458) /* error secure level bad private file */ +#define SL_ESECBADDHFILE (-459) /* error secure level bad DH file */ +#define SL_ESECT00MANYSSLOPENED (-460) /* MAX SSL Sockets are opened */ +#define SL_ESECDATEERROR (-461) /* connected with certificate date verification error */ +#define SL_ESECHANDSHAKETIMEDOUT (-462) /* connection timed out due to handshake time */ + +/* end error codes */ + +/* Max payload size by protocol */ +#define SL_SOCKET_PAYLOAD_TYPE_MASK (0xF0) /*4 bits type, 4 bits sockets id */ +#define SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4 (0x00) /* 1472 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4 (0x10) /* 1460 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6 (0x20) /* 1452 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6 (0x30) /* 1440 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4_SECURE (0x40) /* */ +#define SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4_SECURE (0x50) /* */ +#define SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6_SECURE (0x60) /* */ +#define SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6_SECURE (0x70) /* */ +#define SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER (0x80) /* 1536 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_RAW_PACKET (0x90) /* 1536 bytes */ +#define SL_SOCKET_PAYLOAD_TYPE_RAW_IP4 (0xa0) +#define SL_SOCKET_PAYLOAD_TYPE_RAW_IP6 (SL_SOCKET_PAYLOAD_TYPE_RAW_IP4 ) + + + +#define SL_SOL_SOCKET (1) /* Define the socket option category. */ +#define SL_IPPROTO_IP (2) /* Define the IP option category. */ +#define SL_SOL_PHY_OPT (3) /* Define the PHY option category. */ + +#define SL_SO_RCVBUF (8) /* Setting TCP receive buffer size */ +#define SL_SO_KEEPALIVE (9) /* Connections are kept alive with periodic messages */ +#define SL_SO_RCVTIMEO (20) /* Enable receive timeout */ +#define SL_SO_NONBLOCKING (24) /* Enable . disable nonblocking mode */ +#define SL_SO_SECMETHOD (25) /* security metohd */ +#define SL_SO_SECURE_MASK (26) /* security mask */ +#define SL_SO_SECURE_FILES (27) /* security files */ +#define SL_SO_CHANGE_CHANNEL (28) /* This option is available only when transceiver started */ +#define SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME (30) /* This option used to configue secure file */ +#define SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME (31) /* This option used to configue secure file */ +#define SL_SO_SECURE_FILES_CA_FILE_NAME (32) /* This option used to configue secure file */ +#define SL_SO_SECURE_FILES_DH_KEY_FILE_NAME (33) /* This option used to configue secure file */ + +#define SL_IP_MULTICAST_IF (60) /* Specify outgoing multicast interface */ +#define SL_IP_MULTICAST_TTL (61) /* Specify the TTL value to use for outgoing multicast packet. */ +#define SL_IP_ADD_MEMBERSHIP (65) /* Join IPv4 multicast membership */ +#define SL_IP_DROP_MEMBERSHIP (66) /* Leave IPv4 multicast membership */ +#define SL_IP_HDRINCL (67) /* Raw socket IPv4 header included. */ +#define SL_IP_RAW_RX_NO_HEADER (68) /* Proprietary socket option that does not includeIPv4/IPv6 header (and extension headers) on received raw sockets*/ +#define SL_IP_RAW_IPV6_HDRINCL (69) /* Transmitted buffer over IPv6 socket contains IPv6 header. */ + +#define SL_SO_PHY_RATE (100) /* WLAN Transmit rate */ +#define SL_SO_PHY_TX_POWER (101) /* TX Power level */ +#define SL_SO_PHY_NUM_FRAMES_TO_TX (102) /* Number of frames to transmit */ +#define SL_SO_PHY_PREAMBLE (103) /* Preamble for transmission */ + +#define SL_SO_SEC_METHOD_SSLV3 (0) /* security metohd SSL v3*/ +#define SL_SO_SEC_METHOD_TLSV1 (1) /* security metohd TLS v1*/ +#define SL_SO_SEC_METHOD_TLSV1_1 (2) /* security metohd TLS v1_1*/ +#define SL_SO_SEC_METHOD_TLSV1_2 (3) /* security metohd TLS v1_2*/ +#define SL_SO_SEC_METHOD_SSLv3_TLSV1_2 (4) /* use highest possible version from SSLv3 - TLS 1.2*/ +#define SL_SO_SEC_METHOD_DLSV1 (5) /* security metohd DTL v1 */ + +#define SL_SEC_MASK_SSL_RSA_WITH_RC4_128_SHA (1 << 0) +#define SL_SEC_MASK_SSL_RSA_WITH_RC4_128_MD5 (1 << 1) +#define SL_SEC_MASK_TLS_RSA_WITH_AES_256_CBC_SHA (1 << 2) +#define SL_SEC_MASK_TLS_DHE_RSA_WITH_AES_256_CBC_SHA (1 << 3) +#define SL_SEC_MASK_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (1 << 4) +#define SL_SEC_MASK_TLS_ECDHE_RSA_WITH_RC4_128_SHA (1 << 5) +#define SL_SEC_MASK_TLS_RSA_WITH_AES_128_CBC_SHA256 (1 << 6) +#define SL_SEC_MASK_TLS_RSA_WITH_AES_256_CBC_SHA256 (1 << 7) +#define SL_SEC_MASK_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (1 << 8) +#define SL_SEC_MASK_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (1 << 9) + + +#define SL_SEC_MASK_SECURE_DEFAULT ((SL_SEC_MASK_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 << 1) - 1) + +#define SL_MSG_DONTWAIT (0x00000008) /* Nonblocking IO */ + +/* AP DHCP Server - IP Release reason code */ +#define SL_IP_LEASE_PEER_RELEASE (0) +#define SL_IP_LEASE_PEER_DECLINE (1) +#define SL_IP_LEASE_EXPIRED (2) + +/* possible types when receiving SL_SOCKET_ASYNC_EVENT*/ +#define SSL_ACCEPT (1) /* accept failed due to ssl issue ( tcp pass) */ +#define RX_FRAGMENTATION_TOO_BIG (2) /* connection less mode, rx packet fragmentation > 16K, packet is being released */ +#define OTHER_SIDE_CLOSE_SSL_DATA_NOT_ENCRYPTED (3) /* remote side down from secure to unsecure */ + + + +#ifdef SL_INC_STD_BSD_API_NAMING + +#define FD_SETSIZE SL_FD_SETSIZE + +#define SOCK_STREAM SL_SOCK_STREAM +#define SOCK_DGRAM SL_SOCK_DGRAM +#define SOCK_RAW SL_SOCK_RAW +#define IPPROTO_TCP SL_IPPROTO_TCP +#define IPPROTO_UDP SL_IPPROTO_UDP +#define IPPROTO_RAW SL_IPPROTO_RAW + +#define AF_INET SL_AF_INET +#define AF_INET6 SL_AF_INET6 +#define AF_INET6_EUI_48 SL_AF_INET6_EUI_48 +#define AF_RF SL_AF_RF +#define AF_PACKET SL_AF_PACKET + +#define PF_INET SL_PF_INET +#define PF_INET6 SL_PF_INET6 + +#define INADDR_ANY SL_INADDR_ANY +#define ERROR SL_SOC_ERROR +#define INEXE SL_INEXE +#define EBADF SL_EBADF +#define ENSOCK SL_ENSOCK +#define EAGAIN SL_EAGAIN +#define EWOULDBLOCK SL_EWOULDBLOCK +#define ENOMEM SL_ENOMEM +#define EACCES SL_EACCES +#define EFAULT SL_EFAULT +#define EINVAL SL_EINVAL +#define EDESTADDRREQ SL_EDESTADDRREQ +#define EPROTOTYPE SL_EPROTOTYPE +#define ENOPROTOOPT SL_ENOPROTOOPT +#define EPROTONOSUPPORT SL_EPROTONOSUPPORT +#define ESOCKTNOSUPPORT SL_ESOCKTNOSUPPORT +#define EOPNOTSUPP SL_EOPNOTSUPP +#define EAFNOSUPPORT SL_EAFNOSUPPORT +#define EADDRINUSE SL_EADDRINUSE +#define EADDRNOTAVAIL SL_EADDRNOTAVAIL +#define ENETUNREACH SL_ENETUNREACH +#define ENOBUFS SL_ENOBUFS +#define EOBUFF SL_EOBUFF +#define EISCONN SL_EISCONN +#define ENOTCONN SL_ENOTCONN +#define ETIMEDOUT SL_ETIMEDOUT +#define ECONNREFUSED SL_ECONNREFUSED + +#define SOL_SOCKET SL_SOL_SOCKET +#define IPPROTO_IP SL_IPPROTO_IP +#define SO_KEEPALIVE SL_SO_KEEPALIVE + +#define SO_RCVTIMEO SL_SO_RCVTIMEO +#define SO_NONBLOCKING SL_SO_NONBLOCKING + +#define IP_MULTICAST_IF SL_IP_MULTICAST_IF +#define IP_MULTICAST_TTL SL_IP_MULTICAST_TTL +#define IP_ADD_MEMBERSHIP SL_IP_ADD_MEMBERSHIP +#define IP_DROP_MEMBERSHIP SL_IP_DROP_MEMBERSHIP + +#define socklen_t SlSocklen_t +#define timeval SlTimeval_t +#define sockaddr SlSockAddr_t +#define in6_addr SlIn6Addr_t +#define sockaddr_in6 SlSockAddrIn6_t +#define in_addr SlInAddr_t +#define sockaddr_in SlSockAddrIn_t + +#define MSG_DONTWAIT SL_MSG_DONTWAIT + +#define FD_SET SL_FD_SET +#define FD_CLR SL_FD_CLR +#define FD_ISSET SL_FD_ISSET +#define FD_ZERO SL_FD_ZERO +#define fd_set SlFdSet_t + +#define socket sl_Socket +#define close sl_Close +#define accept sl_Accept +#define bind sl_Bind +#define listen sl_Listen +#define connect sl_Connect +#define select sl_Select +#define setsockopt sl_SetSockOpt +#define getsockopt sl_GetSockOpt +#define recv sl_Recv +#define recvfrom sl_RecvFrom +#define write sl_Write +#define send sl_Send +#define sendto sl_SendTo +#define gethostbyname sl_NetAppDnsGetHostByName +#define htonl sl_Htonl +#define ntohl sl_Ntohl +#define htons sl_Htons +#define ntohs sl_Ntohs +#endif + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ + +/* Internet address */ +typedef struct SlInAddr_t +{ +#ifndef s_addr + _u32 s_addr; /* Internet address 32 bits */ +#else + union S_un { + struct { _u8 s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { _u8 s_w1,s_w2; } S_un_w; + _u32 S_addr; + } S_un; +#endif +}SlInAddr_t; + + +/* sockopt */ +typedef struct +{ + _u32 KeepaliveEnabled; /* 0 = disabled;1 = enabled; default = 1*/ +}SlSockKeepalive_t; + +typedef struct +{ + _u32 ReuseaddrEnabled; /* 0 = disabled; 1 = enabled; default = 1*/ +}SlSockReuseaddr_t; + +typedef struct +{ + _u32 Winsize; /* receive window size for tcp sockets */ +}SlSockWinsize_t; + +typedef struct +{ + _u32 NonblockingEnabled;/* 0 = disabled;1 = enabled;default = 1*/ +}SlSockNonblocking_t; + + +typedef struct +{ + _u8 sd; + _u8 type; + _i16 val; + _u8* pExtraInfo; +} SlSocketAsyncEvent_t; + +typedef struct +{ + _i16 status; + _u8 sd; + _u8 padding; +} SlSockTxFailEventData_t; + + +typedef union +{ + SlSockTxFailEventData_t SockTxFailData; + SlSocketAsyncEvent_t SockAsyncData; +} SlSockEventData_u; + + +typedef struct +{ + _u32 Event; + SlSockEventData_u socketAsyncEvent; +} SlSockEvent_t; + + + + + + +typedef struct +{ + _u32 secureMask; +} SlSockSecureMask; + +typedef struct +{ + _u8 secureMethod; +} SlSockSecureMethod; + +typedef enum +{ + SL_BSD_SECURED_PRIVATE_KEY_IDX = 0, + SL_BSD_SECURED_CERTIFICATE_IDX, + SL_BSD_SECURED_CA_IDX, + SL_BSD_SECURED_DH_IDX +}slBsd_secureSocketFilesIndex_e; + +typedef struct +{ + SlInAddr_t imr_multiaddr; /* The IPv4 multicast address to join */ + SlInAddr_t imr_interface; /* The interface to use for this group */ +} SlSockIpMreq; + + +/* sockopt */ +typedef _u32 SlTime_t; +typedef _u32 SlSuseconds_t; + +typedef struct SlTimeval_t +{ + SlTime_t tv_sec; /* Seconds */ + SlSuseconds_t tv_usec; /* Microseconds */ +}SlTimeval_t; + +typedef _u16 SlSocklen_t; + +/* IpV4 socket address */ +typedef struct SlSockAddr_t +{ + _u16 sa_family; /* Address family (e.g. , AF_INET) */ + _u8 sa_data[14]; /* Protocol- specific address information*/ +}SlSockAddr_t; + + +/* IpV6 or Ipv6 EUI64 */ +typedef struct SlIn6Addr_t +{ + union + { + _u8 _S6_u8[16]; + _u32 _S6_u32[4]; + } _S6_un; +}SlIn6Addr_t; + +typedef struct SlSockAddrIn6_t +{ + _u16 sin6_family; /* AF_INET6 || AF_INET6_EUI_48*/ + _u16 sin6_port; /* Transport layer port. */ + _u32 sin6_flowinfo; /* IPv6 flow information. */ + SlIn6Addr_t sin6_addr; /* IPv6 address. */ + _u32 sin6_scope_id; /* set of interfaces for a scope. */ +}SlSockAddrIn6_t; + +/* Socket address, Internet style. */ + +typedef struct SlSockAddrIn_t +{ + _u16 sin_family; /* Internet Protocol (AF_INET). */ + _u16 sin_port; /* Address port (16 bits). */ + SlInAddr_t sin_addr; /* Internet address (32 bits). */ + _i8 sin_zero[8]; /* Not used. */ +}SlSockAddrIn_t; + +typedef struct +{ + _u32 ip; + _u32 gateway; + _u32 dns; +}SlIpV4AcquiredAsync_t; + +typedef struct +{ + _u32 type; + _u32 ip[4]; + _u32 gateway[4]; + _u32 dns[4]; +}SlIpV6AcquiredAsync_t; + +typedef struct +{ + _u32 ip_address; + _u32 lease_time; + _u8 mac[6]; + _u16 padding; +}SlIpLeasedAsync_t; + +typedef struct +{ + _u32 ip_address; + _u8 mac[6]; + _u16 reason; +}SlIpReleasedAsync_t; + + +typedef union +{ + SlIpV4AcquiredAsync_t ipAcquiredV4; /*SL_NETAPP_IPV4_IPACQUIRED_EVENT*/ + SlIpV6AcquiredAsync_t ipAcquiredV6; /*SL_NETAPP_IPV6_IPACQUIRED_EVENT*/ + _u32 sd; /*SL_SOCKET_TX_FAILED_EVENT*/ + SlIpLeasedAsync_t ipLeased; /* SL_NETAPP_IP_LEASED_EVENT */ + SlIpReleasedAsync_t ipReleased; /* SL_NETAPP_IP_RELEASED_EVENT */ +} SlNetAppEventData_u; + +typedef struct +{ + _u32 Event; + SlNetAppEventData_u EventData; +}SlNetAppEvent_t; + + +typedef struct sock_secureFiles +{ + _u8 secureFiles[4]; +}SlSockSecureFiles_t; + + +typedef struct SlFdSet_t /* The select socket array manager */ +{ + _u32 fd_array[(SL_FD_SETSIZE + 31)/32]; /* Bit map of SOCKET Descriptors */ +} SlFdSet_t; + +typedef struct +{ + _u8 rate; /* Recevied Rate */ + _u8 channel; /* The received channel*/ + _i8 rssi; /* The computed RSSI value in db of current frame */ + _u8 padding; /* pad to align to 32 bits */ + _u32 timestamp; /* Timestamp in microseconds, */ +}SlTransceiverRxOverHead_t; + + + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + +/*! + + \brief create an endpoint for communication + + The socket function creates a new socket of a certain socket type, identified + by an integer number, and allocates system resources to it. + This function is called by the application layer to obtain a socket handle. + + \param[in] domain specifies the protocol family of the created socket. + For example: + AF_INET for network protocol IPv4 + AF_RF for starting transceiver mode. Notes: + - sending and receiving any packet overriding 802.11 header + - for optimized power consumption the socket will be started in TX + only mode until receive command is activated + AF_INET6 for IPv6 + + + \param[in] type specifies the communication semantic, one of: + SOCK_STREAM (reliable stream-oriented service or Stream Sockets) + SOCK_DGRAM (datagram service or Datagram Sockets) + SOCK_RAW (raw protocols atop the network layer) + when used with AF_RF: + SOCK_DGRAM - L2 socket + SOCK_RAW - L1 socket - bypass WLAN CCA (Clear Channel Assessment) + + \param[in] protocol specifies a particular transport to be used with + the socket. + The most common are IPPROTO_TCP, IPPROTO_SCTP, IPPROTO_UDP, + IPPROTO_DCCP. + The value 0 may be used to select a default + protocol from the selected domain and type + + + \return On success, socket handle that is used for consequent socket operations. + A successful return code should be a positive number (int16) + On error, a negative (int16) value will be returned specifying the error code. + SL_EAFNOSUPPORT - illegal domain parameter + SL_EPROTOTYPE - illegal type parameter + SL_EACCES - permission denied + SL_ENSOCK - exceeded maximal number of socket + SL_ENOMEM - memory allocation error + SL_EINVAL - error in socket configuration + SL_EPROTONOSUPPORT - illegal protocol parameter + SL_EOPNOTSUPP - illegal combination of protocol and type parameters + + + \sa sl_Close + \note belongs to \ref basic_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Socket) +_i16 sl_Socket(_i16 Domain, _i16 Type, _i16 Protocol); +#endif + +/*! + \brief gracefully close socket + + This function causes the system to release resources allocated to a socket. \n + In case of TCP, the connection is terminated. + + \param[in] sd socket handle (received in sl_Socket) + + \return On success, zero is returned. + On error, a negative number is returned. + + \sa sl_Socket + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Close) +_i16 sl_Close(_i16 sd); +#endif + +/*! + \brief Accept a connection on a socket + + This function is used with connection-based socket types (SOCK_STREAM). + It extracts the first connection request on the queue of pending + connections, creates a new connected socket, and returns a new file + descriptor referring to that socket. + The newly created socket is not in the listening state. The + original socket sd is unaffected by this call. + The argument sd is a socket that has been created with + sl_Socket(), bound to a local address with sl_Bind(), and is + listening for connections after a sl_Listen(). The argument \b + \e addr is a pointer to a sockaddr structure. This structure + is filled in with the address of the peer socket, as known to + the communications layer. The exact format of the address + returned addr is determined by the socket's address family. + The \b \e addrlen argument is a value-result argument: it + should initially contain the size of the structure pointed to + by addr, on return it will contain the actual length (in + bytes) of the address returned. + + \param[in] sd socket descriptor (handle) + \param[out] addr the argument addr is a pointer + to a sockaddr structure. This + structure is filled in with the + address of the peer socket, as + known to the communications + layer. The exact format of the + address returned addr is + determined by the socket's + address\n + sockaddr:\n - code for the + address format. On this version + only AF_INET is supported.\n - + socket address, the length + depends on the code format + \param[out] addrlen the addrlen argument is a value-result + argument: it should initially contain the + size of the structure pointed to by addr + + \return On success, a socket handle. + On a non-blocking accept a possible negative value is SL_EAGAIN. + On failure, negative value. + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_Socket sl_Bind sl_Listen + \note belongs to \ref server_side + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Accept) +_i16 sl_Accept(_i16 sd, SlSockAddr_t *addr, SlSocklen_t *addrlen); +#endif + +/*! + \brief assign a name to a socket + + This function gives the socket the local address addr. + addr is addrlen bytes long. Traditionally, this is called + When a socket is created with socket, it exists in a name + space (address family) but has no name assigned. + It is necessary to assign a local address before a SOCK_STREAM + socket may receive connections. + + \param[in] sd socket descriptor (handle) + \param[in] addr specifies the destination + addrs\n sockaddr:\n - code for + the address format. On this + version only AF_INET is + supported.\n - socket address, + the length depends on the code + format + \param[in] addrlen contains the size of the structure pointed to by addr + + \return On success, zero is returned. On error, a negative error code is returned. + + \sa sl_Socket sl_Accept sl_Listen + \note belongs to \ref basic_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Bind) +_i16 sl_Bind(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen); +#endif + +/*! + \brief listen for connections on a socket + + The willingness to accept incoming connections and a queue + limit for incoming connections are specified with listen(), + and then the connections are accepted with accept. + The listen() call applies only to sockets of type SOCK_STREAM + The backlog parameter defines the maximum length the queue of + pending connections may grow to. + + \param[in] sd socket descriptor (handle) + \param[in] backlog specifies the listen queue depth. + + + \return On success, zero is returned. On error, a negative error code is returned. + + \sa sl_Socket sl_Accept sl_Bind + \note belongs to \ref server_side + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Listen) +_i16 sl_Listen(_i16 sd, _i16 backlog); +#endif + +/*! + \brief Initiate a connection on a socket + + Function connects the socket referred to by the socket + descriptor sd, to the address specified by addr. The addrlen + argument specifies the size of addr. The format of the + address in addr is determined by the address space of the + socket. If it is of type SOCK_DGRAM, this call specifies the + peer with which the socket is to be associated; this address + is that to which datagrams are to be sent, and the only + address from which datagrams are to be received. If the + socket is of type SOCK_STREAM, this call attempts to make a + connection to another socket. The other socket is specified + by address, which is an address in the communications space + of the socket. + + + \param[in] sd socket descriptor (handle) + \param[in] addr specifies the destination addr\n + sockaddr:\n - code for the + address format. On this version + only AF_INET is supported.\n - + socket address, the length + depends on the code format + + \param[in] addrlen contains the size of the structure pointed + to by addr + + \return On success, a socket handle. + On a non-blocking connect a possible negative value is SL_EALREADY. + On failure, negative value. + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_Socket + \note belongs to \ref client_side + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Connect) +_i16 sl_Connect(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen); +#endif + +/*! + \brief Monitor socket activity + + Select allow a program to monitor multiple file descriptors, + waiting until one or more of the file descriptors become + "ready" for some class of I/O operation + + + \param[in] nfds the highest-numbered file descriptor in any of the + three sets, plus 1. + \param[out] readsds socket descriptors list for read monitoring and accept monitoring + \param[out] writesds socket descriptors list for connect monitoring only, write monitoring is not supported, non blocking connect is supported + \param[out] exceptsds socket descriptors list for exception monitoring, not supported. + \param[in] timeout is an upper bound on the amount of time elapsed + before select() returns. Null or above 0xffff seconds means + infinity timeout. The minimum timeout is 10 milliseconds, + less than 10 milliseconds will be set automatically to 10 milliseconds. + Max microseconds supported is 0xfffc00. + + \return On success, select() returns the number of + file descriptors contained in the three returned + descriptor sets (that is, the total number of bits that + are set in readfds, writefds, exceptfds) which may be + zero if the timeout expires before anything interesting + happens. On error, a negative value is returned. + readsds - return the sockets on which Read request will + return without delay with valid data. + writesds - return the sockets on which Write request + will return without delay. + exceptsds - return the sockets closed recently. + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_Socket + \note If the timeout value set to less than 5ms it will automatically set + to 5ms to prevent overload of the system + belongs to \ref basic_api + + Only one sl_Select can be handled at a time. + Calling this API while the same command is called from another thread, may result + in one of the two scenarios: + 1. The command will wait (internal) until the previous command finish, and then be executed. + 2. There are not enough resources and SL_POOL_IS_EMPTY error will return. + In this case, MAX_CONCURRENT_ACTIONS can be increased (result in memory increase) or try + again later to issue the command. + + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Select) +_i16 sl_Select(_i16 nfds, SlFdSet_t *readsds, SlFdSet_t *writesds, SlFdSet_t *exceptsds, struct SlTimeval_t *timeout); + + +/*! + \brief Select's SlFdSet_t SET function + + Sets current socket descriptor on SlFdSet_t container +*/ +void SL_FD_SET(_i16 fd, SlFdSet_t *fdset); + +/*! + \brief Select's SlFdSet_t CLR function + + Clears current socket descriptor on SlFdSet_t container +*/ +void SL_FD_CLR(_i16 fd, SlFdSet_t *fdset); + + +/*! + \brief Select's SlFdSet_t ISSET function + + Checks if current socket descriptor is set (TRUE/FALSE) + + \return Returns TRUE if set, FALSE if unset + +*/ +_i16 SL_FD_ISSET(_i16 fd, SlFdSet_t *fdset); + +/*! + \brief Select's SlFdSet_t ZERO function + + Clears all socket descriptors from SlFdSet_t +*/ +void SL_FD_ZERO(SlFdSet_t *fdset); + + + +#endif + +/*! + \brief set socket options + + This function manipulate the options associated with a socket. + Options may exist at multiple protocol levels; they are always + present at the uppermost socket level. + + When manipulating socket options the level at which the option resides + and the name of the option must be specified. To manipulate options at + the socket level, level is specified as SOL_SOCKET. To manipulate + options at any other level the protocol number of the appropriate proto- + col controlling the option is supplied. For example, to indicate that an + option is to be interpreted by the TCP protocol, level should be set to + the protocol number of TCP; + + The parameters optval and optlen are used to access optval - + ues for setsockopt(). For getsockopt() they identify a + buffer in which the value for the requested option(s) are to + be returned. For getsockopt(), optlen is a value-result + parameter, initially containing the size of the buffer + pointed to by option_value, and modified on return to + indicate the actual size of the value returned. If no option + value is to be supplied or returned, option_value may be + NULL. + + \param[in] sd socket handle + \param[in] level defines the protocol level for this option + - SL_SOL_SOCKET Socket level configurations (L4, transport layer) + - SL_IPPROTO_IP IP level configurations (L3, network layer) + - SL_SOL_PHY_OPT Link level configurations (L2, link layer) + \param[in] optname defines the option name to interrogate + - SL_SOL_SOCKET + - SL_SO_KEEPALIVE \n + Enable/Disable periodic keep alive. + Keeps TCP connections active by enabling the periodic transmission of messages \n + Timeout is 5 minutes.\n + Default: Enabled \n + This options takes SlSockKeepalive_t struct as parameter + - SL_SO_RCVTIMEO \n + Sets the timeout value that specifies the maximum amount of time an input function waits until it completes. \n + Default: No timeout \n + This options takes SlTimeval_t struct as parameter + - SL_SO_RCVBUF \n + Sets tcp max recv window size. \n + This options takes SlSockWinsize_t struct as parameter + - SL_SO_NONBLOCKING \n + Sets socket to non-blocking operation Impacts: connect, accept, send, sendto, recv and recvfrom. \n + Default: Blocking. + This options takes SlSockNonblocking_t struct as parameter + - SL_SO_SECMETHOD \n + Sets method to tcp secured socket (SL_SEC_SOCKET) \n + Default: SL_SO_SEC_METHOD_SSLv3_TLSV1_2 \n + This options takes SlSockSecureMethod struct as parameter + - SL_SO_SEC_MASK \n + Sets specific cipher to tcp secured socket (SL_SEC_SOCKET) \n + Default: "Best" cipher suitable to method \n + This options takes SlSockSecureMask struct as parameter + - SL_SO_SECURE_FILES_CA_FILE_NAME \n + Map secured socket to CA file by name \n + This options takes _u8 buffer as parameter + - SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME \n + Map secured socket to private key by name \n + This options takes _u8 buffer as parameter + - SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME \n + Map secured socket to certificate file by name \n + This options takes _u8 buffer as parameter + - SL_SO_SECURE_FILES_DH_KEY_FILE_NAME \n + Map secured socket to Diffie Hellman file by name \n + This options takes _u8 buffer as parameter + - SL_SO_CHANGE_CHANNEL \n + Sets channel in transceiver mode. + This options takes _u32 as channel number parameter + - SL_IPPROTO_IP + - SL_IP_MULTICAST_TTL \n + Set the time-to-live value of outgoing multicast packets for this socket. \n + This options takes _u8 as parameter + - SL_IP_ADD_MEMBERSHIP \n + UDP socket, Join a multicast group. \n + This options takes SlSockIpMreq struct as parameter + - SL_IP_DROP_MEMBERSHIP \n + UDP socket, Leave a multicast group \n + This options takes SlSockIpMreq struct as parameter + - SL_IP_RAW_RX_NO_HEADER \n + Raw socket remove IP header from received data. \n + Default: data includes ip header \n + This options takes _u32 as parameter + - SL_IP_HDRINCL \n + RAW socket only, the IPv4 layer generates an IP header when sending a packet unless \n + the IP_HDRINCL socket option is enabled on the socket. \n + When it is enabled, the packet must contain an IP header. \n + Default: disabled, IPv4 header generated by Network Stack \n + This options takes _u32 as parameter + - SL_IP_RAW_IPV6_HDRINCL (inactive) \n + RAW socket only, the IPv6 layer generates an IP header when sending a packet unless \n + the IP_HDRINCL socket option is enabled on the socket. When it is enabled, the packet must contain an IP header \n + Default: disabled, IPv4 header generated by Network Stack \n + This options takes _u32 as parameter + - SL_SOL_PHY_OPT + - SL_SO_PHY_RATE \n + RAW socket, set WLAN PHY transmit rate \n + The values are based on RateIndex_e \n + This options takes _u32 as parameter + - SL_SO_PHY_TX_POWER \n + RAW socket, set WLAN PHY TX power \n + Valid rage is 1-15 \n + This options takes _u32 as parameter + - SL_SO_PHY_NUM_FRAMES_TO_TX \n + RAW socket, set number of frames to transmit in transceiver mode. + Default: 1 packet + This options takes _u32 as parameter + - SL_SO_PHY_PREAMBLE \n + RAW socket, set WLAN PHY preamble for Long/Short\n + This options takes _u32 as parameter + + \param[in] optval specifies a value for the option + \param[in] optlen specifies the length of the + option value + + \return On success, zero is returned. + On error, a negative value is returned. + \sa sl_getsockopt + \note belongs to \ref basic_api + \warning + \par Examples: + \par + SL_SO_KEEPALIVE: (disable Keepalive) + \code + SlSockKeepalive_t enableOption; + enableOption.KeepaliveEnabled = 0; + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_KEEPALIVE, (_u8 *)&enableOption,sizeof(enableOption)); + \endcode + \par + SL_SO_RCVTIMEO: + \code + struct SlTimeval_t timeVal; + timeVal.tv_sec = 1; // Seconds + timeVal.tv_usec = 0; // Microseconds. 10000 microseconds resolution + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_RCVTIMEO, (_u8 *)&timeVal, sizeof(timeVal)); // Enable receive timeout + \endcode + \par + SL_SO_RCVBUF: + \code + SlSockWinsize_t size; + size.Winsize = 3000; // bytes + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_RCVBUF, (_u8 *)&size, sizeof(size)); + \endcode + \par + SL_SO_NONBLOCKING: + \code + SlSockNonblocking_t enableOption; + enableOption.NonblockingEnabled = 1; + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_NONBLOCKING, (_u8 *)&enableOption,sizeof(enableOption)); // Enable/disable nonblocking mode + \endcode + \par + SL_SO_SECMETHOD: + \code + SlSockSecureMethod method; + method.secureMethod = SL_SO_SEC_METHOD_SSLV3; // security method we want to use + SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, SL_SEC_SOCKET); + sl_SetSockOpt(SockID, SL_SOL_SOCKET, SL_SO_SECMETHOD, (_u8 *)&method, sizeof(method)); + \endcode + \par + SL_SO_SECURE_MASK: + \code + SlSockSecureMask cipher; + cipher.secureMask = SL_SEC_MASK_SSL_RSA_WITH_RC4_128_SHA; // cipher type + SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, SL_SEC_SOCKET); + sl_SetSockOpt(SockID, SL_SOL_SOCKET, SL_SO_SEC_MASK,(_u8 *)&cipher, sizeof(cipher)); + \endcode + \par + SL_SO_SECURE_FILES_CA_FILE_NAME: + \code + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_SECURE_FILES_CA_FILE_NAME,"exuifaxCaCert.der",strlen("exuifaxCaCert.der")); + \endcode + + \par + SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME: + \code + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME,"myPrivateKey.der",strlen("myPrivateKey.der")); + \endcode + + \par + SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME: + \code + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME,"myCertificate.der",strlen("myCertificate.der")); + \endcode + + \par + SL_SO_SECURE_FILES_DH_KEY_FILE_NAME: + \code + sl_SetSockOpt(SockID,SL_SOL_SOCKET,SL_SO_SECURE_FILES_DH_KEY_FILE_NAME,"myDHinServerMode.der",strlen("myDHinServerMode.der")); + \endcode + + \par + SL_IP_MULTICAST_TTL: + \code + _u8 ttl = 20; + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + \endcode + + \par + SL_IP_ADD_MEMBERSHIP: + \code + SlSockIpMreq mreq; + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + \endcode + + \par + SL_IP_DROP_MEMBERSHIP: + \code + SlSockIpMreq mreq; + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); + \endcode + + \par + SL_SO_CHANGE_CHANNEL: + \code + _u32 newChannel = 6; // range is 1-13 + sl_SetSockOpt(SockID, SL_SOL_SOCKET, SL_SO_CHANGE_CHANNEL, &newChannel, sizeof(newChannel)); + \endcode + + \par + SL_IP_RAW_RX_NO_HEADER: + \code + _u32 header = 1; // remove ip header + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_RAW_RX_NO_HEADER, &header, sizeof(header)); + \endcode + + \par + SL_IP_HDRINCL: + \code + _u32 header = 1; + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_HDRINCL, &header, sizeof(header)); + \endcode + \par + SL_IP_RAW_IPV6_HDRINCL: + \code + _u32 header = 1; + sl_SetSockOpt(SockID, SL_IPPROTO_IP, SL_IP_RAW_IPV6_HDRINCL, &header, sizeof(header)); + \endcode + + \par + SL_SO_PHY_RATE: + \code + _u32 rate = 6; // see wlan.h RateIndex_e for values + sl_SetSockOpt(SockID, SL_SOL_PHY_OPT, SL_SO_PHY_RATE, &rate, sizeof(rate)); + \endcode + + \par + SL_SO_PHY_TX_POWER: + \code + _u32 txpower = 1; // valid range is 1-15 + sl_SetSockOpt(SockID, SL_SOL_PHY_OPT, SL_SO_PHY_TX_POWER, &txpower, sizeof(txpower)); + \endcode + + \par + SL_SO_PHY_NUM_FRAMES_TO_TX: + \code + _u32 numframes = 1; + sl_SetSockOpt(SockID, SL_SOL_PHY_OPT, SL_SO_PHY_NUM_FRAMES_TO_TX, &numframes, sizeof(numframes)); + \endcode + + \par + SL_SO_PHY_PREAMBLE: + \code + _u32 preamble = 1; + sl_SetSockOpt(SockID, SL_SOL_PHY_OPT, SL_SO_PHY_PREAMBLE, &preamble, sizeof(preamble)); + \endcode + +*/ +#if _SL_INCLUDE_FUNC(sl_SetSockOpt) +_i16 sl_SetSockOpt(_i16 sd, _i16 level, _i16 optname, const void *optval, SlSocklen_t optlen); +#endif + +/*! + \brief Get socket options + + This function manipulate the options associated with a socket. + Options may exist at multiple protocol levels; they are always + present at the uppermost socket level. + + When manipulating socket options the level at which the option resides + and the name of the option must be specified. To manipulate options at + the socket level, level is specified as SOL_SOCKET. To manipulate + options at any other level the protocol number of the appropriate proto- + col controlling the option is supplied. For example, to indicate that an + option is to be interpreted by the TCP protocol, level should be set to + the protocol number of TCP; + + The parameters optval and optlen are used to access optval - + ues for setsockopt(). For getsockopt() they identify a + buffer in which the value for the requested option(s) are to + be returned. For getsockopt(), optlen is a value-result + parameter, initially containing the size of the buffer + pointed to by option_value, and modified on return to + indicate the actual size of the value returned. If no option + value is to be supplied or returned, option_value may be + NULL. + + + \param[in] sd socket handle + \param[in] level defines the protocol level for this option + \param[in] optname defines the option name to interrogate + \param[out] optval specifies a value for the option + \param[out] optlen specifies the length of the + option value + + \return On success, zero is returned. + On error, a negative value is returned. + \sa sl_SetSockOpt + \note See sl_SetSockOpt + belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_GetSockOpt) +_i16 sl_GetSockOpt(_i16 sd, _i16 level, _i16 optname, void *optval, SlSocklen_t *optlen); +#endif + +/*! + \brief read data from TCP socket + + function receives a message from a connection-mode socket + + \param[in] sd socket handle + \param[out] buf Points to the buffer where the + message should be stored. + \param[in] Len Specifies the length in bytes of + the buffer pointed to by the buffer argument. + Range: 1-16000 bytes + \param[in] flags Specifies the type of message + reception. On this version, this parameter is not + supported. + + \return return the number of bytes received, + or a negative value if an error occurred. + using a non-blocking recv a possible negative value is SL_EAGAIN. + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_RecvFrom + \note belongs to \ref recv_api + \warning + \par Examples: + \code An example of receiving data using TCP socket: + + SlSockAddrIn_t Addr; + SlSockAddrIn_t LocalAddr; + _i16 AddrSize = sizeof(SlSockAddrIn_t); + _i16 SockID, newSockID; + _i16 Status; + _i8 Buf[RECV_BUF_LEN]; + + LocalAddr.sin_family = SL_AF_INET; + LocalAddr.sin_port = sl_Htons(5001); + LocalAddr.sin_addr.s_addr = 0; + + Addr.sin_family = SL_AF_INET; + Addr.sin_port = sl_Htons(5001); + Addr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(10,1,1,200)); + + SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0); + Status = sl_Bind(SockID, (SlSockAddr_t *)&LocalAddr, AddrSize); + Status = sl_Listen(SockID, 0); + newSockID = sl_Accept(SockID, (SlSockAddr_t*)&Addr, (SlSocklen_t*) &AddrSize); + Status = sl_Recv(newSockID, Buf, 1460, 0); + \endcode + \code Example code for Rx transceiver mode using a raw socket + _i8 buffer[1536]; + _i16 sd; + _u16 size; + SlTransceiverRxOverHead_t *transHeader; + sd = sl_Socket(SL_AF_RF,SL_SOCK_RAW,11); // channel 11 + while(1) + { + size = sl_Recv(sd,buffer,1536,0); + transHeader = (SlTransceiverRxOverHead_t *)buffer; + printf("RSSI is %d frame type is 0x%x size %d\n",transHeader->rssi,buffer[sizeof(SlTransceiverRxOverHead_t)],size); + } + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_Recv) +_i16 sl_Recv(_i16 sd, void *buf, _i16 Len, _i16 flags); +#endif + +/*! + \brief read data from socket + + function receives a message from a connection-mode or + connectionless-mode socket + + \param[in] sd socket handle + \param[out] buf Points to the buffer where the message should be stored. + \param[in] Len Specifies the length in bytes of the buffer pointed to by the buffer argument. + Range: 1-16000 bytes + \param[in] flags Specifies the type of message + reception. On this version, this parameter is not + supported. + \param[in] from pointer to an address structure + indicating the source + address.\n sockaddr:\n - code + for the address format. On this + version only AF_INET is + supported.\n - socket address, + the length depends on the code + format + \param[in] fromlen source address structure + size. This parameter MUST be set to the size of the structure pointed to by addr. + + + \return return the number of bytes received, + or a negative value if an error occurred. + using a non-blocking recv a possible negative value is SL_EAGAIN. + SL_RET_CODE_INVALID_INPUT (-2) will be returned if fromlen has incorrect length. + SL_POOL_IS_EMPTY may be return in case there are no resources in the system + In this case try again later or increase MAX_CONCURRENT_ACTIONS + + \sa sl_Recv + \note belongs to \ref recv_api + \warning + \par Example: + \code An example of receiving data: + + SlSockAddrIn_t Addr; + SlSockAddrIn_t LocalAddr; + _i16 AddrSize = sizeof(SlSockAddrIn_t); + _i16 SockID; + _i16 Status; + _i8 Buf[RECV_BUF_LEN]; + + LocalAddr.sin_family = SL_AF_INET; + LocalAddr.sin_port = sl_Htons(5001); + LocalAddr.sin_addr.s_addr = 0; + + SockID = sl_Socket(SL_AF_INET,SL_SOCK_DGRAM, 0); + Status = sl_Bind(SockID, (SlSockAddr_t *)&LocalAddr, AddrSize); + Status = sl_RecvFrom(SockID, Buf, 1472, 0, (SlSockAddr_t *)&Addr, (SlSocklen_t*)&AddrSize); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_RecvFrom) +_i16 sl_RecvFrom(_i16 sd, void *buf, _i16 Len, _i16 flags, SlSockAddr_t *from, SlSocklen_t *fromlen); +#endif + +/*! + \brief write data to TCP socket + + This function is used to transmit a message to another socket. + Returns immediately after sending data to device. + In case of TCP failure an async event SL_SOCKET_TX_FAILED_EVENT is going to + be received. + In case of a RAW socket (transceiver mode), extra 4 bytes should be reserved at the end of the + frame data buffer for WLAN FCS + + \param[in] sd socket handle + \param[in] buf Points to a buffer containing + the message to be sent + \param[in] Len message size in bytes. Range: 1-1460 bytes + \param[in] flags Specifies the type of message + transmission. On this version, this parameter is not + supported for TCP. + For transceiver mode, the SL_RAW_RF_TX_PARAMS macro can be used to determine + transmission parameters (channel,rate,tx_power,preamble) + + + \return Return the number of bytes transmitted, + or -1 if an error occurred + + \sa sl_SendTo + \note belongs to \ref send_api + \warning + \par Example: + \code An example of sending data: + + SlSockAddrIn_t Addr; + _i16 AddrSize = sizeof(SlSockAddrIn_t); + _i16 SockID; + _i16 Status; + _i8 Buf[SEND_BUF_LEN]; + + Addr.sin_family = SL_AF_INET; + Addr.sin_port = sl_Htons(5001); + Addr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(10,1,1,200)); + + SockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0); + Status = sl_Connect(SockID, (SlSockAddr_t *)&Addr, AddrSize); + Status = sl_Send(SockID, Buf, 1460, 0 ); + + \endcode + */ +#if _SL_INCLUDE_FUNC(sl_Send ) +_i16 sl_Send(_i16 sd, const void *buf, _i16 Len, _i16 flags); +#endif + +/*! + \brief write data to socket + + This function is used to transmit a message to another socket + (connection less socket SOCK_DGRAM, SOCK_RAW). + Returns immediately after sending data to device. + In case of transmission failure an async event SL_SOCKET_TX_FAILED_EVENT is going to + be received. + + \param[in] sd socket handle + \param[in] buf Points to a buffer containing + the message to be sent + \param[in] Len message size in bytes. Range: 1-1460 bytes + \param[in] flags Specifies the type of message + transmission. On this version, this parameter is not + supported + \param[in] to pointer to an address structure + indicating the destination + address.\n sockaddr:\n - code + for the address format. On this + version only AF_INET is + supported.\n - socket address, + the length depends on the code + format + \param[in] tolen destination address structure size + + \return Return the number of transmitted bytes, + or -1 if an error occurred + + \sa sl_Send + \note belongs to \ref send_api + \warning + \par Example: + \code An example of sending data: + + SlSockAddrIn_t Addr; + _i16 AddrSize = sizeof(SlSockAddrIn_t); + _i16 SockID; + _i16 Status; + _i8 Buf[SEND_BUF_LEN]; + + Addr.sin_family = SL_AF_INET; + Addr.sin_port = sl_Htons(5001); + Addr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(10,1,1,200)); + + SockID = sl_Socket(SL_AF_INET,SL_SOCK_DGRAM, 0); + Status = sl_SendTo(SockID, Buf, 1472, 0, (SlSockAddr_t *)&Addr, AddrSize); + + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_SendTo) +_i16 sl_SendTo(_i16 sd, const void *buf, _i16 Len, _i16 flags, const SlSockAddr_t *to, SlSocklen_t tolen); +#endif + +/*! + \brief Reorder the bytes of a 32-bit unsigned value + + This function is used to Reorder the bytes of a 32-bit unsigned value from processor order to network order. + + \param[in] var variable to reorder + + \return Return the reorder variable, + + \sa sl_SendTo sl_Bind sl_Connect sl_RecvFrom sl_Accept + \note belongs to \ref send_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Htonl ) +_u32 sl_Htonl( _u32 val ); + +#define sl_Ntohl sl_Htonl /* Reorder the bytes of a 16-bit unsigned value from network order to processor orde. */ +#endif + +/*! + \brief Reorder the bytes of a 16-bit unsigned value + + This function is used to Reorder the bytes of a 16-bit unsigned value from processor order to network order. + + \param[in] var variable to reorder + + \return Return the reorder variable, + + \sa sl_SendTo sl_Bind sl_Connect sl_RecvFrom sl_Accept + \note belongs to \ref send_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_Htons ) +_u16 sl_Htons( _u16 val ); + +#define sl_Ntohs sl_Htons /* Reorder the bytes of a 16-bit unsigned value from network order to processor orde. */ +#endif + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SOCKET_H__ */ + + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/spawn.h b/src/openmv/src/micropython/drivers/cc3100/inc/spawn.h new file mode 100755 index 0000000..82c112d --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/spawn.h @@ -0,0 +1,63 @@ +/* + * spawn.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __NONOS_H__ +#define __NONOS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if (defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN)) + +extern void _SlInternalSpawnTaskEntry(); +extern _i16 _SlInternalSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , _u32 flags); + +#undef sl_Spawn +#define sl_Spawn(pEntry,pValue,flags) _SlInternalSpawn(pEntry,pValue,flags) + +#undef _SlTaskEntry +#define _SlTaskEntry _SlInternalSpawnTaskEntry + + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/trace.h b/src/openmv/src/micropython/drivers/cc3100/inc/trace.h new file mode 100755 index 0000000..4ca42c7 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/trace.h @@ -0,0 +1,173 @@ +/* + * trace.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 "simplelink.h" + +#ifndef __SIMPLELINK_TRACE_H__ +#define __SIMPLELINK_TRACE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +#define SL_SYNC_SCAN_THRESHOLD (( _u32 )2000) + +#define _SL_ASSERT(expr) { ASSERT(expr); } +#define _SL_ERROR(expr, error) { if(!(expr)){return (error); } } + +#define SL_HANDLING_ASSERT 2 +#define SL_HANDLING_ERROR 1 +#define SL_HANDLING_NONE 0 + +#define SL_SELF_COND_HANDLING SL_HANDLING_NONE +#define SL_PROTOCOL_HANDLING SL_HANDLING_NONE +#define SL_DRV_RET_CODE_HANDLING SL_HANDLING_NONE +#define SL_NWP_IF_HANDLING SL_HANDLING_NONE +#define SL_OSI_RET_OK_HANDLING SL_HANDLING_NONE +#define SL_MALLOC_OK_HANDLING SL_HANDLING_NONE +#define SL_USER_ARGS_HANDLING SL_HANDLING_NONE + +#if (SL_DRV_RET_CODE_HANDLING == SL_HANDLING_ASSERT) +#define VERIFY_RET_OK(Func) {_SlReturnVal_t _RetVal = (Func); _SL_ASSERT((_SlReturnVal_t)SL_OS_RET_CODE_OK == _RetVal)} +#elif (SL_DRV_RET_CODE_HANDLING == SL_HANDLING_ERROR) +#define VERIFY_RET_OK(Func) {_SlReturnVal_t _RetVal = (Func); if (SL_OS_RET_CODE_OK != _RetVal) return _RetVal;} +#else +#define VERIFY_RET_OK(Func) (Func); +#endif + +#if (SL_PROTOCOL_HANDLING == SL_HANDLING_ASSERT) +#define VERIFY_PROTOCOL(expr) _SL_ASSERT(expr) +#elif (SL_PROTOCOL_HANDLING == SL_HANDLING_ERROR) +#define VERIFY_PROTOCOL(expr) _SL_ERROR(expr, SL_RET_CODE_PROTOCOL_ERROR) +#else +#define VERIFY_PROTOCOL(expr) +#endif + +#if (defined(PROTECT_SOCKET_ASYNC_RESP) && (SL_SELF_COND_HANDLING == SL_HANDLING_ASSERT)) +#define VERIFY_SOCKET_CB(expr) _SL_ASSERT(expr) +#elif (defined(PROTECT_SOCKET_ASYNC_RESP) && (SL_SELF_COND_HANDLING == SL_HANDLING_ERROR)) +#define VERIFY_SOCKET_CB(expr) _SL_ERROR(expr, SL_RET_CODE_SELF_ERROR) +#else +#define VERIFY_SOCKET_CB(expr) +#endif + +#if (SL_NWP_IF_HANDLING == SL_HANDLING_ASSERT) +#define NWP_IF_WRITE_CHECK(fd,pBuff,len) { _i16 RetSize, ExpSize = (len); RetSize = sl_IfWrite((fd),(pBuff),ExpSize); _SL_ASSERT(ExpSize == RetSize)} +#define NWP_IF_READ_CHECK(fd,pBuff,len) { _i16 RetSize, ExpSize = (len); RetSize = sl_IfRead((fd),(pBuff),ExpSize); _SL_ASSERT(ExpSize == RetSize)} +#elif (SL_NWP_IF_HANDLING == SL_HANDLING_ERROR) +#define NWP_IF_WRITE_CHECK(fd,pBuff,len) { _SL_ERROR((len == sl_IfWrite((fd),(pBuff),(len))), SL_RET_CODE_NWP_IF_ERROR);} +#define NWP_IF_READ_CHECK(fd,pBuff,len) { _SL_ERROR((len == sl_IfRead((fd),(pBuff),(len))), SL_RET_CODE_NWP_IF_ERROR);} +#else +#define NWP_IF_WRITE_CHECK(fd,pBuff,len) { sl_IfWrite((fd),(pBuff),(len));} +#define NWP_IF_READ_CHECK(fd,pBuff,len) { sl_IfRead((fd),(pBuff),(len));} +#endif + +#if (SL_OSI_RET_OK_HANDLING == SL_HANDLING_ASSERT) +#define OSI_RET_OK_CHECK(Func) {_SlReturnVal_t _RetVal = (Func); _SL_ASSERT((_SlReturnVal_t)SL_OS_RET_CODE_OK == _RetVal)} +#elif (SL_OSI_RET_OK_HANDLING == SL_HANDLING_ERROR) +#define OSI_RET_OK_CHECK(Func) {_SlReturnVal_t _RetVal = (Func); if (SL_OS_RET_CODE_OK != _RetVal) return _RetVal;} +#else +#define OSI_RET_OK_CHECK(Func) (Func); +#endif + +#if (SL_MALLOC_OK_HANDLING == SL_HANDLING_ASSERT) +#define MALLOC_OK_CHECK(Ptr) _SL_ASSERT(NULL != Ptr) +#elif (SL_MALLOC_OK_HANDLING == SL_HANDLING_ERROR) +#define MALLOC_OK_CHECK(Ptr) _SL_ERROR((NULL != Ptr), SL_RET_CODE_MALLOC_ERROR) +#else +#define MALLOC_OK_CHECK(Ptr) +#endif + +#ifdef SL_INC_ARG_CHECK + +#if (SL_USER_ARGS_HANDLING == SL_HANDLING_ASSERT) +#define ARG_CHECK_PTR(Ptr) _SL_ASSERT(NULL != Ptr) +#elif (SL_USER_ARGS_HANDLING == SL_HANDLING_ERROR) +#define ARG_CHECK_PTR(Ptr) _SL_ERROR((NULL != Ptr), SL_RET_CODE_INVALID_INPUT) +#else +#define ARG_CHECK_PTR(Ptr) +#endif + +#else +#define ARG_CHECK_PTR(Ptr) +#endif + +#define SL_TRACE0(level,msg_id,str) +#define SL_TRACE1(level,msg_id,str,p1) +#define SL_TRACE2(level,msg_id,str,p1,p2) +#define SL_TRACE3(level,msg_id,str,p1,p2,p3) +#define SL_TRACE4(level,msg_id,str,p1,p2,p3,p4) +#define SL_ERROR_TRACE(msg_id,str) +#define SL_ERROR_TRACE1(msg_id,str,p1) +#define SL_ERROR_TRACE2(msg_id,str,p1,p2) +#define SL_ERROR_TRACE3(msg_id,str,p1,p2,p3) +#define SL_ERROR_TRACE4(msg_id,str,p1,p2,p3,p4) +#define SL_TRACE_FLUSH() + +/* #define SL_DBG_CNT_ENABLE */ +#ifdef SL_DBG_CNT_ENABLE +#define _SL_DBG_CNT_INC(Cnt) g_DbgCnt. ## Cnt++ +#define _SL_DBG_SYNC_LOG(index,value) {if(index < SL_DBG_SYNC_LOG_SIZE){*(_u32 *)&g_DbgCnt.SyncLog[index] = *(_u32 *)(value);}} + +#else +#define _SL_DBG_CNT_INC(Cnt) +#define _SL_DBG_SYNC_LOG(index,value) +#endif + +#define SL_DBG_LEVEL_1 1 +#define SL_DBG_LEVEL_2 2 +#define SL_DBG_LEVEL_3 4 +#define SL_DBG_LEVEL_MASK (SL_DBG_LEVEL_2|SL_DBG_LEVEL_3) + +#define SL_INCLUDE_DBG_FUNC(Name) ((Name ## _DBG_LEVEL) & SL_DBG_LEVEL_MASK) + +#define _SlDrvPrintStat_DBG_LEVEL SL_DBG_LEVEL_3 +#define _SlDrvOtherFunc_DBG_LEVEL SL_DBG_LEVEL_1 + +#ifdef __cplusplus +} +#endif + + +#endif /*__SIMPLELINK_TRACE_H__*/ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/wlan.h b/src/openmv/src/micropython/drivers/cc3100/inc/wlan.h new file mode 100755 index 0000000..156b94e --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/wlan.h @@ -0,0 +1,1308 @@ +/* + * wlan.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + +#ifndef __WLAN_H__ +#define __WLAN_H__ + + + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +/*! + + \addtogroup wlan + @{ + +*/ + +#define SL_BSSID_LENGTH (6) +#define MAXIMAL_SSID_LENGTH (32) + +#define NUM_OF_RATE_INDEXES (20) +#define SIZE_OF_RSSI_HISTOGRAM (6) + +/* WLAN Disconnect Reason Codes */ +#define SL_DISCONNECT_RESERVED_0 (0) +#define SL_DISCONNECT_UNSPECIFIED_REASON (1) +#define SL_PREVIOUS_AUTHENTICATION_NO_LONGER_VALID (2) +#define SL_DEAUTHENTICATED_BECAUSE_SENDING_STATION_IS_LEAVING (3) +#define SL_DISASSOCIATED_DUE_TO_INACTIVITY (4) +#define SL_DISASSOCIATED_BECAUSE_AP_IS_UNABLE_TO_HANDLE_ALL_CURRENTLY_ASSOCIATED_STATIONS (5) +#define SL_CLASS_2_FRAME_RECEIVED_FROM_NONAUTHENTICATED_STATION (6) +#define SL_CLASS_3_FRAME_RECEIVED_FROM_NONASSOCIATED_STATION (7) +#define SL_DISASSOCIATED_BECAUSE_SENDING_STATION_IS_LEAVING_BSS (8) +#define SL_STATION_REQUESTING_ASSOCIATION_IS_NOT_AUTHENTICATED_WITH_RESPONDING_STATION (9) +#define SL_DISASSOCIATED_BECAUSE_THE_INFORMATION_IN_THE_POWER_CAPABILITY_ELEMENT_IS_UNACCEPTABLE (10) +#define SL_DISASSOCIATED_BECAUSE_THE_INFORMATION_IN_THE_SUPPORTED_CHANNELS_ELEMENT_IS_UNACCEPTABLE (11) +#define SL_DISCONNECT_RESERVED_1 (12) +#define SL_INVALID_INFORMATION_ELEMENT (13) +#define SL_MESSAGE_INTEGRITY_CODE_MIC_FAILURE (14) +#define SL_FOUR_WAY_HANDSHAKE_TIMEOUT (15) +#define SL_GROUP_KEY_HANDSHAKE_TIMEOUT (16) +#define SL_RE_ASSOCIATION_REQUEST_PROBE_RESPONSE_BEACON_FRAME (17) +#define SL_INVALID_GROUP_CIPHER (18) +#define SL_INVALID_PAIRWISE_CIPHER (19) +#define SL_INVALID_AKMP (20) +#define SL_UNSUPPORTED_RSN_INFORMATION_ELEMENT_VERSION (21) +#define SL_INVALID_RSN_INFORMATION_ELEMENT_CAPABILITIES (22) +#define SL_IEEE_802_1X_AUTHENTICATION_FAILED (23) +#define SL_CIPHER_SUITE_REJECTED_BECAUSE_OF_THE_SECURITY_POLICY (24) +#define SL_DISCONNECT_RESERVED_2 (25) +#define SL_DISCONNECT_RESERVED_3 (26) +#define SL_DISCONNECT_RESERVED_4 (27) +#define SL_DISCONNECT_RESERVED_5 (28) +#define SL_DISCONNECT_RESERVED_6 (29) +#define SL_DISCONNECT_RESERVED_7 (30) +#define SL_DISCONNECT_RESERVED_8 (31) +#define SL_USER_INITIATED_DISCONNECTION (200) + +/* Wlan error codes */ +#define SL_ERROR_KEY_ERROR (-3) +#define SL_ERROR_INVALID_ROLE (-71) +#define SL_ERROR_INVALID_SECURITY_TYPE (-84) +#define SL_ERROR_PASSPHRASE_TOO_LONG (-85) +#define SL_ERROR_WPS_NO_PIN_OR_WRONG_PIN_LEN (-87) +#define SL_ERROR_EAP_WRONG_METHOD (-88) +#define SL_ERROR_PASSWORD_ERROR (-89) +#define SL_ERROR_EAP_ANONYMOUS_LEN_ERROR (-90) +#define SL_ERROR_SSID_LEN_ERROR (-91) +#define SL_ERROR_USER_ID_LEN_ERROR (-92) +#define SL_ERROR_ILLEGAL_WEP_KEY_INDEX (-95) +#define SL_ERROR_INVALID_DWELL_TIME_VALUES (-96) +#define SL_ERROR_INVALID_POLICY_TYPE (-97) +#define SL_ERROR_PM_POLICY_INVALID_OPTION (-98) +#define SL_ERROR_PM_POLICY_INVALID_PARAMS (-99) +#define SL_ERROR_WIFI_ALREADY_DISCONNECTED (-129) +#define SL_ERROR_WIFI_NOT_CONNECTED (-59) + + + +#define SL_SEC_TYPE_OPEN (0) +#define SL_SEC_TYPE_WEP (1) +#define SL_SEC_TYPE_WPA (2) /* deprecated */ +#define SL_SEC_TYPE_WPA_WPA2 (2) +#define SL_SEC_TYPE_WPS_PBC (3) +#define SL_SEC_TYPE_WPS_PIN (4) +#define SL_SEC_TYPE_WPA_ENT (5) +#define SL_SEC_TYPE_P2P_PBC (6) +#define SL_SEC_TYPE_P2P_PIN_KEYPAD (7) +#define SL_SEC_TYPE_P2P_PIN_DISPLAY (8) +#define SL_SEC_TYPE_P2P_PIN_AUTO (9) /* NOT Supported yet */ + + + +#define SL_SCAN_SEC_TYPE_OPEN (0) +#define SL_SCAN_SEC_TYPE_WEP (1) +#define SL_SCAN_SEC_TYPE_WPA (2) +#define SL_SCAN_SEC_TYPE_WPA2 (3) + + + +#define TLS (0x1) +#define MSCHAP (0x0) +#define PSK (0x2) +#define TTLS (0x10) +#define PEAP0 (0x20) +#define PEAP1 (0x40) +#define FAST (0x80) + +#define FAST_AUTH_PROVISIONING (0x02) +#define FAST_UNAUTH_PROVISIONING (0x01) +#define FAST_NO_PROVISIONING (0x00) + +#define EAPMETHOD_PHASE2_SHIFT (8) +#define EAPMETHOD_PAIRWISE_CIPHER_SHIFT (19) +#define EAPMETHOD_GROUP_CIPHER_SHIFT (27) + +#define WPA_CIPHER_CCMP (0x1) +#define WPA_CIPHER_TKIP (0x2) +#define CC31XX_DEFAULT_CIPHER (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP) + +#define EAPMETHOD(phase1,phase2,pairwise_cipher,group_cipher) \ +((phase1) | \ + ((phase2) << EAPMETHOD_PHASE2_SHIFT ) |\ + ((_u32)(pairwise_cipher) << EAPMETHOD_PAIRWISE_CIPHER_SHIFT ) |\ + ((_u32)(group_cipher) << EAPMETHOD_GROUP_CIPHER_SHIFT )) + +/* phase1 phase2 pairwise_cipher group_cipher */ +#define SL_ENT_EAP_METHOD_TLS EAPMETHOD(TLS , 0 , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_TTLS_TLS EAPMETHOD(TTLS , TLS , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_TTLS_MSCHAPv2 EAPMETHOD(TTLS , MSCHAP , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_TTLS_PSK EAPMETHOD(TTLS , PSK , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP0_TLS EAPMETHOD(PEAP0 , TLS , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP0_MSCHAPv2 EAPMETHOD(PEAP0 , MSCHAP , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP0_PSK EAPMETHOD(PEAP0 , PSK , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP1_TLS EAPMETHOD(PEAP1 , TLS , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP1_MSCHAPv2 EAPMETHOD(PEAP1 , MSCHAP , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_PEAP1_PSK EAPMETHOD(PEAP1 , PSK , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_FAST_AUTH_PROVISIONING EAPMETHOD(FAST , FAST_AUTH_PROVISIONING , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_FAST_UNAUTH_PROVISIONING EAPMETHOD(FAST , FAST_UNAUTH_PROVISIONING , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) +#define SL_ENT_EAP_METHOD_FAST_NO_PROVISIONING EAPMETHOD(FAST , FAST_NO_PROVISIONING , CC31XX_DEFAULT_CIPHER , CC31XX_DEFAULT_CIPHER) + +#define SL_LONG_PREAMBLE (0) +#define SL_SHORT_PREAMBLE (1) + +#define SL_RAW_RF_TX_PARAMS_CHANNEL_SHIFT (0) +#define SL_RAW_RF_TX_PARAMS_RATE_SHIFT (6) +#define SL_RAW_RF_TX_PARAMS_POWER_SHIFT (11) +#define SL_RAW_RF_TX_PARAMS_PREAMBLE_SHIFT (15) + +#define SL_RAW_RF_TX_PARAMS(chan,rate,power,preamble) \ + ((chan << SL_RAW_RF_TX_PARAMS_CHANNEL_SHIFT) | \ + (rate << SL_RAW_RF_TX_PARAMS_RATE_SHIFT) | \ + (power << SL_RAW_RF_TX_PARAMS_POWER_SHIFT) | \ + (preamble << SL_RAW_RF_TX_PARAMS_PREAMBLE_SHIFT)) + + +/* wlan config application IDs */ +#define SL_WLAN_CFG_AP_ID (0) +#define SL_WLAN_CFG_GENERAL_PARAM_ID (1) +#define SL_WLAN_CFG_P2P_PARAM_ID (2) + +/* wlan AP Config set/get options */ +#define WLAN_AP_OPT_SSID (0) +#define WLAN_AP_OPT_CHANNEL (3) +#define WLAN_AP_OPT_HIDDEN_SSID (4) +#define WLAN_AP_OPT_SECURITY_TYPE (6) +#define WLAN_AP_OPT_PASSWORD (7) +#define WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE (9) +#define WLAN_GENERAL_PARAM_OPT_STA_TX_POWER (10) +#define WLAN_GENERAL_PARAM_OPT_AP_TX_POWER (11) + +#define WLAN_P2P_OPT_DEV_NAME (12) +#define WLAN_P2P_OPT_DEV_TYPE (13) +#define WLAN_P2P_OPT_CHANNEL_N_REGS (14) +#define WLAN_GENERAL_PARAM_OPT_INFO_ELEMENT (16) +#define WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS (18) /* change the scan channels and RSSI threshold using this configuration option */ + +/* SmartConfig CIPHER options */ +#define SMART_CONFIG_CIPHER_SFLASH (0) /* password is not delivered by the application. The Simple Manager should */ + /* check if the keys are stored in the Flash. */ +#define SMART_CONFIG_CIPHER_AES (1) /* AES (other types are not supported) */ +#define SMART_CONFIG_CIPHER_NONE (0xFF) /* do not check in the flash */ + + +#define SL_POLICY_CONNECTION (0x10) +#define SL_POLICY_SCAN (0x20) +#define SL_POLICY_PM (0x30) +#define SL_POLICY_P2P (0x40) + +#define VAL_2_MASK(position,value) ((1 & (value))<<(position)) +#define MASK_2_VAL(position,mask) (((1 << position) & (mask)) >> (position)) + +#define SL_CONNECTION_POLICY(Auto,Fast,Open,anyP2P,autoSmartConfig) (VAL_2_MASK(0,Auto) | VAL_2_MASK(1,Fast) | VAL_2_MASK(2,Open) | VAL_2_MASK(3,anyP2P) | VAL_2_MASK(4,autoSmartConfig)) +#define SL_SCAN_POLICY_EN(policy) (MASK_2_VAL(0,policy)) +#define SL_SCAN_POLICY(Enable) (VAL_2_MASK(0,Enable)) + + +#define SL_NORMAL_POLICY (0) +#define SL_LOW_LATENCY_POLICY (1) +#define SL_LOW_POWER_POLICY (2) +#define SL_ALWAYS_ON_POLICY (3) +#define SL_LONG_SLEEP_INTERVAL_POLICY (4) + +#define SL_P2P_ROLE_NEGOTIATE (3) +#define SL_P2P_ROLE_GROUP_OWNER (15) +#define SL_P2P_ROLE_CLIENT (0) + +#define SL_P2P_NEG_INITIATOR_ACTIVE (0) +#define SL_P2P_NEG_INITIATOR_PASSIVE (1) +#define SL_P2P_NEG_INITIATOR_RAND_BACKOFF (2) + +#define POLICY_VAL_2_OPTIONS(position,mask,policy) ((mask & policy) << position ) + +#define SL_P2P_POLICY(p2pNegType,p2pNegInitiator) (POLICY_VAL_2_OPTIONS(0,0xF,(p2pNegType > SL_P2P_ROLE_GROUP_OWNER ? SL_P2P_ROLE_GROUP_OWNER : p2pNegType)) | \ + POLICY_VAL_2_OPTIONS(4,0x1,(p2pNegType > SL_P2P_ROLE_GROUP_OWNER ? 1:0)) | \ + POLICY_VAL_2_OPTIONS(5,0x3, p2pNegInitiator)) + + +/* Info elements */ + +#define INFO_ELEMENT_DEFAULT_ID (0) /* 221 will be used */ + +/* info element size is up to 252 bytes (+ 3 bytes of OUI). */ +#define INFO_ELEMENT_MAX_SIZE (252) + +/* For AP - the total length of all info elements is 300 bytes (for example - 4 info elements of 75 bytes each) */ +#define INFO_ELEMENT_MAX_TOTAL_LENGTH_AP (300) +/* For P2P - the total length of all info elements is 150 bytes (for example - 4 info elements of 40 bytes each) */ +#define INFO_ELEMENT_MAX_TOTAL_LENGTH_P2P_GO (160) + +#define INFO_ELEMENT_AP_ROLE (0) +#define INFO_ELEMENT_P2P_GO_ROLE (1) + +/* we support up to 4 info elements per Role. */ +#define MAX_PRIVATE_INFO_ELEMENTS_SUPPROTED (4) + +#define INFO_ELEMENT_DEFAULT_OUI_0 (0x08) +#define INFO_ELEMENT_DEFAULT_OUI_1 (0x00) +#define INFO_ELEMENT_DEFAULT_OUI_2 (0x28) + +#define INFO_ELEMENT_DEFAULT_OUI (0x000000) /* 08, 00, 28 will be used */ + +/*****************************************************************************/ +/* Structure/Enum declarations */ +/*****************************************************************************/ + +typedef enum +{ + RATE_1M = 1, + RATE_2M = 2, + RATE_5_5M = 3, + RATE_11M = 4, + RATE_6M = 6, + RATE_9M = 7, + RATE_12M = 8, + RATE_18M = 9, + RATE_24M = 10, + RATE_36M = 11, + RATE_48M = 12, + RATE_54M = 13, + RATE_MCS_0 = 14, + RATE_MCS_1 = 15, + RATE_MCS_2 = 16, + RATE_MCS_3 = 17, + RATE_MCS_4 = 18, + RATE_MCS_5 = 19, + RATE_MCS_6 = 20, + RATE_MCS_7 = 21, + MAX_NUM_RATES = 0xFF +}SlRateIndex_e; + +typedef enum { + DEV_PW_DEFAULT=0, + DEV_PW_PIN_KEYPAD=1, + DEV_PW_PUSH_BUTTON=4, + DEV_PW_PIN_DISPLAY=5 +} sl_p2p_dev_password_method; + + +typedef struct +{ + _u32 status; + _u32 ssid_len; + _u8 ssid[32]; + _u32 private_token_len; + _u8 private_token[32]; +}slSmartConfigStartAsyncResponse_t; + +typedef struct +{ + _u16 status; + _u16 padding; +}slSmartConfigStopAsyncResponse_t; + +typedef struct +{ + _u16 status; + _u16 padding; +}slWlanConnFailureAsyncResponse_t; + +typedef struct +{ + _u8 connection_type;/* 0-STA,3-P2P_CL */ + _u8 ssid_len; + _u8 ssid_name[32]; + _u8 go_peer_device_name_len; + _u8 go_peer_device_name[32]; + _u8 bssid[6]; + _u8 reason_code; + _u8 padding[2]; +} slWlanConnectAsyncResponse_t; + +typedef struct +{ + _u8 go_peer_device_name[32]; + _u8 mac[6]; + _u8 go_peer_device_name_len; + _u8 wps_dev_password_id; + _u8 own_ssid[32];/* relevant for event sta-connected only */ + _u8 own_ssid_len;/* relevant for event sta-connected only */ + _u8 padding[3]; +}slPeerInfoAsyncResponse_t; + + +typedef union +{ + slSmartConfigStartAsyncResponse_t smartConfigStartResponse; /*SL_WLAN_SMART_CONFIG_COMPLETE_EVENT*/ + slSmartConfigStopAsyncResponse_t smartConfigStopResponse; /*SL_WLAN_SMART_CONFIG_STOP_EVENT */ + slPeerInfoAsyncResponse_t APModeStaConnected; /* SL_WLAN_STA_CONNECTED_EVENT - relevant only in AP mode - holds information regarding a new STA connection */ + slPeerInfoAsyncResponse_t APModestaDisconnected; /* SL_WLAN_STA_DISCONNECTED_EVENT - relevant only in AP mode - holds information regarding a STA disconnection */ + slWlanConnectAsyncResponse_t STAandP2PModeWlanConnected; /* SL_WLAN_CONNECT_EVENT - relevant only in STA and P2P mode - holds information regarding a new connection */ + slWlanConnectAsyncResponse_t STAandP2PModeDisconnected; /* SL_WLAN_DISCONNECT_EVENT - relevant only in STA and P2P mode - holds information regarding a disconnection */ + slPeerInfoAsyncResponse_t P2PModeDevFound; /* SL_WLAN_P2P_DEV_FOUND_EVENT - relevant only in P2P mode */ + slPeerInfoAsyncResponse_t P2PModeNegReqReceived; /* SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT - relevant only in P2P mode */ + slWlanConnFailureAsyncResponse_t P2PModewlanConnectionFailure; /* SL_WLAN_CONNECTION_FAILED_EVENT - relevant only in P2P mode */ + +} SlWlanEventData_u; + +typedef struct +{ + _u32 Event; + SlWlanEventData_u EventData; +} SlWlanEvent_t; + + +typedef struct +{ + _u32 ReceivedValidPacketsNumber; /* sum of the packets that been received OK (include filtered) */ + _u32 ReceivedFcsErrorPacketsNumber; /* sum of the packets that been dropped due to FCS error */ + _u32 ReceivedAddressMismatchPacketsNumber; /* sum of the packets that been received but filtered out by one of the HW filters */ + _i16 AvarageDataCtrlRssi; /* average RSSI for all valid data packets received */ + _i16 AvarageMgMntRssi; /* average RSSI for all valid management packets received */ + _u16 RateHistogram[NUM_OF_RATE_INDEXES]; /* rate histogram for all valid packets received */ + _u16 RssiHistogram[SIZE_OF_RSSI_HISTOGRAM]; /* RSSI histogram from -40 until -87 (all below and above\n RSSI will appear in the first and last cells */ + _u32 StartTimeStamp; /* the time stamp started collecting the statistics in uSec */ + _u32 GetTimeStamp; /* the time stamp called the get statistics command */ +}SlGetRxStatResponse_t; + + +typedef struct +{ + _u8 ssid[MAXIMAL_SSID_LENGTH]; + _u8 ssid_len; + _u8 sec_type; + _u8 bssid[SL_BSSID_LENGTH]; + _i8 rssi; + _i8 reserved[3]; +}Sl_WlanNetworkEntry_t; + + +typedef struct +{ + _u8 Type; + _i8* Key; + _u8 KeyLen; +}SlSecParams_t; + +typedef struct +{ + _i8* User; + _u8 UserLen; + _i8* AnonUser; + _u8 AnonUserLen; + _u8 CertIndex; /* not supported */ + _u32 EapMethod; +}SlSecParamsExt_t; + +typedef struct +{ + _i8 User[32]; + _u8 UserLen; + _i8 AnonUser[32]; + _u8 AnonUserLen; + _u8 CertIndex; /* not supported */ + _u32 EapMethod; +}SlGetSecParamsExt_t; + +typedef enum +{ + ROLE_STA = 0, + ROLE_AP = 2, + ROLE_P2P = 3, + ROLE_STA_ERR = -1, /* Failure to load MAC/PHY in STA role */ + ROLE_AP_ERR = -ROLE_AP, /* Failure to load MAC/PHY in AP role */ + ROLE_P2P_ERR = -ROLE_P2P /* Failure to load MAC/PHY in P2P role */ +}SlWlanMode_t; + +typedef struct +{ + _u32 G_Channels_mask; + _i32 rssiThershold; +}slWlanScanParamCommand_t; + + +typedef struct +{ + _u8 id; + _u8 oui[3]; + _u16 length; + _u8 data[252]; +} sl_protocol_InfoElement_t; + +typedef struct +{ + _u8 index; /* 0 - MAX_PRIVATE_INFO_ELEMENTS_SUPPROTED */ + _u8 role; /* bit0: AP = 0, GO = 1 */ + sl_protocol_InfoElement_t ie; +} sl_protocol_WlanSetInfoElement_t; + + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ + + +/*! + \brief Connect to wlan network as a station + + \param[in] pName up to 32 bytes in case of STA the name is the SSID of the Access Point + \param[in] NameLen name length + \param[in] pMacAddr 6 bytes for MAC address + \param[in] pSecParams Security parameters (use NULL key for SL_SEC_TYPE_OPEN) + Security types options: \n + - SL_SEC_TYPE_OPEN + - SL_SEC_TYPE_WEP + - SL_SEC_TYPE_WPA_WPA2 + - SL_SEC_TYPE_WPA_ENT + - SL_SEC_TYPE_WPS_PBC + - SL_SEC_TYPE_WPS_PIN + + \param[in] pSecExtParams Enterprise parameters (set NULL in case Enterprise parameters is not in use) + + \return On success, zero is returned. On error, negative is returned + In case error number (-71) is returned, it indicates a connection was activated while the device it running in AP role + + \sa sl_WlanDisconnect + \note belongs to \ref ext_api + \warning In this version only single enterprise mode could be used + SL_SEC_TYPE_WPA is a deprecated definition, the new definition is SL_SEC_TYPE_WPA_WPA2 +*/ +#if _SL_INCLUDE_FUNC(sl_WlanConnect) +_i16 sl_WlanConnect(const _i8* pName,const _i16 NameLen,const _u8 *pMacAddr,const SlSecParams_t* pSecParams ,const SlSecParamsExt_t* pSecExtParams); +#endif + +/*! + \brief wlan disconnect + + Disconnect connection + + \return 0 disconnected done, other already disconnected + + \sa sl_WlanConnect + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_WlanDisconnect) +_i16 sl_WlanDisconnect(void); +#endif + +/*! + \brief add profile + + When auto start is enabled, the device connects to a + station from the profiles table. Up to 7 profiles are + supported. If several profiles configured the device chose + the highest priority profile, within each priority group, + device will chose profile based on security policy, signal + strength, etc parameters. + + + \param[in] pName up to 32 bytes in case of STA the name is the + SSID of the Access Point + in case of P2P the name is the remote device name + \param[in] NameLen name length + \param[in] pMacAddr 6 bytes for MAC address + \param[in] pSecParams Security parameters - security type + (SL_SEC_TYPE_OPEN,SL_SEC_TYPE_WEP,SL_SEC_TYPE_WPA_WPA2, + SL_SEC_TYPE_P2P_PBC,SL_SEC_TYPE_P2P_PIN_KEYPAD,SL_SEC_TYPE_P2P_PIN_DISPLAY, SL_SEC_TYPE_WPA_ENT), key, and key length + in case of p2p security type pin the key refers to pin code + \param[in] pSecExtParams Enterprise parameters - identity, identity length, + Anonymous, Anonymous length, CertIndex (not supported, + certificates need to be placed in a specific file ID), + EapMethod.Use NULL in case Enterprise parameters is not in use + + \param[in] Priority profile priority. Lowest priority: 0 + \param[in] Options Not supported + + \return On success, profile stored index is returned. On error, negative value is returned + + \sa sl_WlanProfileGet , sl_WlanProfileDel + \note belongs to \ref ext_api + \warning Only one Enterprise profile is supported. + Please Note that in case of adding an existing profile (compared by pName,pMACAddr and security type) + the old profile will be deleted and the same index will be returned. + SL_SEC_TYPE_WPA is a deprecated definition, the new definition is SL_SEC_TYPE_WPA_WPA2 + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanProfileAdd) +_i16 sl_WlanProfileAdd(const _i8* pName,const _i16 NameLen,const _u8 *pMacAddr,const SlSecParams_t* pSecParams ,const SlSecParamsExt_t* pSecExtParams,const _u32 Priority,const _u32 Options); +#endif + +/*! + \brief get profile + + read profile from the device + + \param[in] Index profile stored index, if index does not exists + error is return + \param[out] pName up to 32 bytes, in case of sta mode the name of the Access Point + in case of p2p mode the name of the Remote Device + \param[out] pNameLen name length + \param[out] pMacAddr 6 bytes for MAC address + \param[out] pSecParams security parameters - security type + (SL_SEC_TYPE_OPEN, SL_SEC_TYPE_WEP, SL_SEC_TYPE_WPA_WPA2 or + SL_SEC_TYPE_WPS_PBC, SL_SEC_TYPE_WPS_PIN, SL_SEC_TYPE_WPA_ENT,SL_SEC_TYPE_P2P_PBC,SL_SEC_TYPE_P2P_PIN_KEYPAD or SL_SEC_TYPE_P2P_PIN_DISPLAY), key and key length are not + in case of p2p security type pin the key refers to pin code + return due to security reasons. + \param[out] pSecExtParams enterprise parameters - identity, identity + length, Anonymous, Anonymous length + CertIndex (not supported), EapMethod. + \param[out] Priority profile priority + + \return On success, Profile security type is returned (0 or positive number). On error, -1 is + returned + + \sa sl_WlanProfileAdd , sl_WlanProfileDel + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_WlanProfileGet) +_i16 sl_WlanProfileGet(const _i16 Index,_i8* pName, _i16 *pNameLen, _u8 *pMacAddr, SlSecParams_t* pSecParams, SlGetSecParamsExt_t* pSecExtParams, _u32 *pPriority); +#endif + +/*! + \brief Delete WLAN profile + + Delete WLAN profile + + \param[in] index number of profile to delete.Possible values are 0 to 6. + Index value 255 will delete all saved profiles + + \return On success, zero is returned. On error, -1 is + returned + + \sa sl_WlanProfileAdd , sl_WlanProfileGet + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_WlanProfileDel) +_i16 sl_WlanProfileDel(const _i16 Index); +#endif + +/*! + \brief Set policy values + + \param[in] Type Type of policy to be modified. The Options are:\n + - SL_POLICY_CONNECTION + - SL_POLICY_SCAN + - SL_POLICY_PM + - SL_POLICY_P2P + \param[in] Policy The option value which depends on action type + \param[in] pVal An optional value pointer + \param[in] ValLen An optional value length, in bytes + \return On success, zero is returned. On error, -1 is + returned + \sa sl_WlanPolicyGet + \note belongs to \ref ext_api + \warning + \par + SL_POLICY_CONNECTION type defines three options available to connect the CC31xx device to the AP: \n + + - If Auto Connect is set, the CC31xx device tries to automatically reconnect to one of its stored profiles, each time the connection fails or the device is rebooted.\n + To set this option, use: \n + sl_WlanPolicySet(SL_POLICY_CONNECTION,SL_CONNECTION_POLICY(1,0,0,0,0),NULL,0) + - If Fast Connect is set, the CC31xx device tries to establish a fast connection to AP. \n + To set this option, use: \n + sl_WlanPolicySet(SL_POLICY_CONNECTION,SL_CONNECTION_POLICY(0,1,0,0,0),NULL,0) + - (relevant for P2P mode only) - If Any P2P is set, CC31xx/CC32xx device tries to automatically connect to the first P2P device available, \n + supporting push button only. To set this option, use: \n + sl_WlanPolicySet(SL_POLICY_CONNECTION,SL_CONNECTION_POLICY(0,0,0,1,0),NULL,0) + - For auto smart config upon restart (any command from Host will end this state) use: \n + sl_WlanPolicySet(SL_POLICY_CONNECTION,SL_CONNECTION_POLICY(0,0,0,0,1),NULL,0) \n + The options above could be combined to a single action, if more than one action is required. \n + \par + SL_POLICY_SCAN defines system scan time interval.Default interval is 10 minutes. \n + After settings scan interval, an immediate scan is activated. The next scan will be based on the interval settings. \n + - For example, setting scan interval to 1 minute interval use: \n + _u32 intervalInSeconds = 60; \n + #define SL_SCAN_ENABLE 1 \n + sl_WlanPolicySet(SL_POLICY_SCAN,SL_SCAN_ENABLE, (_u8 *)&intervalInSeconds,sizeof(intervalInSeconds)); \n + + - For example, disable scan: \n + #define SL_SCAN_DISABLE 0 \n + sl_WlanPolicySet(SL_POLICY_SCAN,SL_SCAN_DISABLE,0,0); \n + \par + SL_POLICY_PM defines a power management policy for Station mode only: + - For setting normal power management (default) policy use: sl_WlanPolicySet(SL_POLICY_PM , SL_NORMAL_POLICY, NULL,0) + - For setting low latency power management policy use: sl_WlanPolicySet(SL_POLICY_PM , SL_LOW_LATENCY_POLICY, NULL,0) + - For setting low power management policy use: sl_WlanPolicySet(SL_POLICY_PM , SL_LOW_POWER_POLICY, NULL,0) + - For setting always on power management policy use: sl_WlanPolicySet(SL_POLICY_PM , SL_ALWAYS_ON_POLICY, NULL,0) + - For setting Long Sleep Interval policy use: \n + _u16 PolicyBuff[4] = {0,0,800,0}; // PolicyBuff[2] is max sleep time in mSec \n + sl_WlanPolicySet(SL_POLICY_PM , SL_LONG_SLEEP_INTERVAL_POLICY, (_u8*)PolicyBuff,sizeof(PolicyBuff)); \n + + SL_POLICY_P2P defines p2p negotiation policy parameters for P2P role: + - To set intent negotiation value, set on of the following: + SL_P2P_ROLE_NEGOTIATE - intent 3 + SL_P2P_ROLE_GROUP_OWNER - intent 15 + SL_P2P_ROLE_CLIENT - intent 0 + - To set negotiation initiator value (initiator policy of first negotiation action frame), set on of the following: + SL_P2P_NEG_INITIATOR_ACTIVE + SL_P2P_NEG_INITIATOR_PASSIVE + SL_P2P_NEG_INITIATOR_RAND_BACKOFF + For example: \n + sl_WlanPolicySet(SL_POLICY_P2P, SL_P2P_POLICY(SL_P2P_ROLE_NEGOTIATE,SL_P2P_NEG_INITIATOR_RAND_BACKOFF),NULL,0) + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanPolicySet) +_i16 sl_WlanPolicySet(const _u8 Type , const _u8 Policy, _u8 *pVal,const _u8 ValLen); +#endif +/*! + \brief get policy values + + \param[in] Type SL_POLICY_CONNECTION, SL_POLICY_SCAN, SL_POLICY_PM,SL_POLICY_P2P \n + + \param[in] Policy argument may be set to any value \n + + \param[out] The returned values, depends on each policy type, will be stored in the allocated buffer pointed by pVal + with a maximum buffer length set by the calling function and pointed to by argument *pValLen + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_WlanPolicySet + + \note belongs to \ref ext_api + + \warning The value pointed by the argument *pValLen should be set to a value different from 0 and + greater than the buffer length returned from the SL device. Otherwise, an error will be returned. + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanPolicyGet) +_i16 sl_WlanPolicyGet(const _u8 Type , _u8 Policy,_u8 *pVal,_u8 *pValLen); +#endif +/*! + \brief Gets the WLAN scan operation results + + Gets scan results , gets entry from scan result table + + \param[in] Index - Starting index identifier (range 0-19) for getting scan results + \param[in] Count - How many entries to fetch. Max is (20-"Index"). + \param[out] pEntries - pointer to an allocated Sl_WlanNetworkEntry_t. + the number of array items should match "Count" + sec_type: SL_SCAN_SEC_TYPE_OPEN, SL_SCAN_SEC_TYPE_WEP, SL_SCAN_SEC_TYPE_WPA or SL_SCAN_SEC_TYPE_WPA2 + + + \return Number of valid networks list items + + \sa + \note belongs to \ref ext_api + \warning This command do not initiate any active scanning action + \par Example: + \code An example of fetching max 10 results: + + Sl_WlanNetworkEntry_t netEntries[10]; + _i16 resultsCount = sl_WlanGetNetworkList(0,10,&netEntries[0]); + for(i=0; i< resultsCount; i++) + { + printf("%s\n",netEntries[i].ssid); + } + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_WlanGetNetworkList) +_i16 sl_WlanGetNetworkList(const _u8 Index,const _u8 Count, Sl_WlanNetworkEntry_t *pEntries); +#endif + +/*! + \brief Start collecting wlan RX statistics, for unlimited time. + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_WlanRxStatStop sl_WlanRxStatGet + \note belongs to \ref ext_api + \warning + \par Example: + \code Getting wlan RX statistics: + + void RxStatCollectTwice() + { + SlGetRxStatResponse_t rxStat; + _i16 rawSocket; + _i8 DataFrame[200]; + struct SlTimeval_t timeval; + timeval.tv_sec = 0; // Seconds + timeval.tv_usec = 20000; // Microseconds. 10000 microseconds resolution + + sl_WlanRxStatStart(); // set statistics mode + + rawSocket = sl_Socket(SL_AF_RF, SL_SOCK_RAW, eChannel); + // set timeout - in case we have no activity for the specified channel + sl_SetSockOpt(rawSocket,SL_SOL_SOCKET,SL_SO_RCVTIMEO, &timeval, sizeof(timeval)); // Enable receive timeout + status = sl_Recv(rawSocket, DataFrame, sizeof(DataFrame), 0); + + Sleep(1000); // sleep for 1 sec + sl_WlanRxStatGet(&rxStat,0); // statistics has been cleared upon read + Sleep(1000); // sleep for 1 sec + sl_WlanRxStatGet(&rxStat,0); + + } + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_WlanRxStatStart) +_i16 sl_WlanRxStatStart(void); +#endif + + +/*! + \brief Stop collecting wlan RX statistic, (if previous called sl_WlanRxStatStart) + + \return On success, zero is returned. On error, -1 is returned + + \sa sl_WlanRxStatStart sl_WlanRxStatGet + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_WlanRxStatStop) +_i16 sl_WlanRxStatStop(void); +#endif + + +/*! + \brief Get wlan RX statistics. upon calling this command, the statistics counters will be cleared. + + \param[in] Flags should be 0 ( not applicable right now, will be added the future ) + \param[in] pRxStat a pointer to SlGetRxStatResponse_t filled with Rx statistics results + \return On success, zero is returned. On error, -1 is returned + + \sa sl_WlanRxStatStart sl_WlanRxStatStop + \note belongs to \ref ext_api + \warning +*/ +#if _SL_INCLUDE_FUNC(sl_WlanRxStatGet) +_i16 sl_WlanRxStatGet(SlGetRxStatResponse_t *pRxStat,const _u32 Flags); +#endif + + +/*! + \brief Stop Smart Config procedure. Once Smart Config will be stopped, + Asynchronous event will be received - SL_OPCODE_WLAN_SMART_CONFIG_STOP_ASYNC_RESPONSE. + + \param[in] none + \param[out] none + + \return 0 - if Stop Smart Config is about to be executed without errors. + + \sa sl_WlanSmartConfigStart + \note belongs to \ref ext_api + \warning + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanSmartConfigStop) +_i16 sl_WlanSmartConfigStop(void); +#endif + +/*! + \brief Start Smart Config procedure + \par + The target of the procedure is to let the \n + device to gain the network parameters: SSID and Password (if network is secured) \n + and to connect to it once located in the network range. \n + An external application should be used on a device connected to any mobile network. \n + The external application will transmit over the air the network parameters in secured manner.\n + The Password may be decrypted using a Key. \n + The decryption method may be decided in the command or embedded in the Flash. \n + The procedure can be activated for 1-3 group ID in the range of BIT_0 - BIT_15 where the default group ID id 0 (BIT_0) \n + Once Smart Config has ended successfully, Asynchronous event will be received - \n + SL_OPCODE_WLAN_SMART_CONFIG_START_ASYNC_RESPONSE. \n + The Event will hold the SSID and an extra field that might have been delivered as well (i.e. - device name) + + \param[in] groupIdBitmask - each bit represent a group ID that should be searched. + The Default group ID id BIT_0. 2 more group can be searched + in addition. The range is BIT_0 - BIT_15. + \param[in] chiper - 0: check in flash, 1 - AES, 0xFF - do not check in flash + \param[in] publicKeyLen - public key len (used for the default group ID - BIT_0) + \param[in] group1KeyLen - group ID1 length + \param[in] group2KeyLen - group ID2 length + \param[in] publicKey - public key (used for the default group ID - BIT_0) + \param[in] group1Key - group ID1 key + \param[in] group2Key - group ID2 key + + \param[out] none + + \return 0 - if Smart Config started successfully. + + \sa sl_WlanSmartConfigStop + \note belongs to \ref ext_api + \warning + \par + \code An example of starting smart Config on group ID's 0 + 1 + 2 + + sl_WlanSmartConfigStart(7, //group ID's (BIT_0 | BIT_1 | BIT_2) + 1, //decrypt key by AES method + 16, //decryption key length for group ID0 + 16, //decryption key length for group ID1 + 16, //decryption key length for group ID2 + "Key0Key0Key0Key0", //decryption key for group ID0 + "Key1Key1Key1Key1", //decryption key for group ID1 + "Key2Key2Key2Key2" //decryption key for group ID2 + ); + \endcode +*/ +#if _SL_INCLUDE_FUNC(sl_WlanSmartConfigStart) +_i16 sl_WlanSmartConfigStart(const _u32 groupIdBitmask, + const _u8 cipher, + const _u8 publicKeyLen, + const _u8 group1KeyLen, + const _u8 group2KeyLen, + const _u8* publicKey, + const _u8* group1Key, + const _u8* group2Key); +#endif + + +/*! + \brief Wlan set mode + + Setting WLAN mode + + \param[in] mode - WLAN mode to start the CC31xx device. Possible options are: + - ROLE_STA - for WLAN station mode + - ROLE_AP - for WLAN AP mode + - ROLE_P2P -for WLAN P2P mode + \return 0 - if mode was set correctly + \sa sl_Start sl_Stop + \note belongs to \ref ext_api + \warning After setting the mode the system must be restarted for activating the new mode + \par Example: + \code + //Switch from any role to STA: + sl_WlanSetMode(ROLE_STA); + sl_Stop(0); + sl_Start(NULL,NULL,NULL); + \endcode + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanSetMode) +_i16 sl_WlanSetMode(const _u8 mode); +#endif + + +/*! + \brief Internal function for setting WLAN configurations + + \return On success, zero is returned. On error one of the following error codes returned: + - CONF_ERROR (-1) + - CONF_NVMEM_ACCESS_FAILED (-2) + - CONF_OLD_FILE_VERSION (-3) + - CONF_ERROR_NO_SUCH_COUNTRY_CODE (-4) + + + \param[in] ConfigId - configuration id + - SL_WLAN_CFG_AP_ID + - SL_WLAN_CFG_GENERAL_PARAM_ID + - SL_WLAN_CFG_P2P_PARAM_ID + + \param[in] ConfigOpt - configurations option + - SL_WLAN_CFG_AP_ID + - WLAN_AP_OPT_SSID \n + Set SSID for AP mode. \n + This options takes _u8 buffer as parameter + - WLAN_AP_OPT_CHANNEL \n + Set channel for AP mode. \n + The channel is dependant on the country code which is set. i.e. for "US" the channel should be in the range of [1-11] \n + This option takes _u8 as a parameter + - WLAN_AP_OPT_HIDDEN_SSID \n + Set Hidden SSID Mode for AP mode.Hidden options: \n + 0: disabled \n + 1: Send empty (length=0) SSID in beacon and ignore probe request for broadcast SSID \n + 2: Clear SSID (ASCII 0), but keep the original length (this may be required with some \n + clients that do not support empty SSID) and ignore probe requests for broadcast SSID \n + This option takes _u8 as a parameter + - WLAN_AP_OPT_SECURITY_TYPE \n + Set Security type for AP mode. Security options are: + - Open security: SL_SEC_TYPE_OPEN + - WEP security: SL_SEC_TYPE_WEP + - WPA security: SL_SEC_TYPE_WPA_WPA2 \n + This option takes _u8 pointer as a parameter + - WLAN_AP_OPT_PASSWORD \n + Set Password for for AP mode (for WEP or for WPA): \n + Password - for WPA: 8 - 63 characters \n + for WEP: 5 / 13 characters (ascii) \n + This options takes _u8 buffer as parameter + - SL_WLAN_CFG_GENERAL_PARAM_ID + - WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS \n + Set scan parameters. + This option uses slWlanScanParamCommand_t as parameter + - WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE \n + Set Country Code for AP mode \n + This options takes _u8 2 bytes buffer as parameter + - WLAN_GENERAL_PARAM_OPT_STA_TX_POWER \n + Set STA mode Tx power level \n + Number between 0-15, as dB offset from max power (0 will set MAX power) \n + This options takes _u8 as parameter + - WLAN_GENERAL_PARAM_OPT_AP_TX_POWER + Set AP mode Tx power level \n + Number between 0-15, as dB offset from max power (0 will set MAX power) \n + This options takes _u8 as parameter + - WLAN_GENERAL_PARAM_OPT_INFO_ELEMENT + Set Info Element for AP mode. \n + The Application can set up to MAX_PRIVATE_INFO_ELEMENTS_SUPPROTED info elements per Role (AP / P2P GO). \n + To delete an info element use the relevant index and length = 0. \n + The Application can set up to MAX_PRIVATE_INFO_ELEMENTS_SUPPROTED to the same role. \n + However, for AP - no more than INFO_ELEMENT_MAX_TOTAL_LENGTH_AP bytes can be stored for all info elements. \n + For P2P GO - no more than INFO_ELEMENT_MAX_TOTAL_LENGTH_P2P_GO bytes can be stored for all info elements. \n + This option takes sl_protocol_WlanSetInfoElement_t as parameter + - SL_WLAN_CFG_P2P_PARAM_ID + - WLAN_P2P_OPT_DEV_TYPE \n + Set P2P Device type.Maximum length of 17 characters. Device type is published under P2P I.E, \n + allows to make devices easier to recognize. \n + In case no device type is set, the default type is "1-0050F204-1" \n + This options takes _u8 buffer as parameter + - WLAN_P2P_OPT_CHANNEL_N_REGS \n + Set P2P Channels. \n + listen channel (either 1/6/11 for 2.4GHz) \n + listen regulatory class (81 for 2.4GHz) \n + oper channel (either 1/6/11 for 2.4GHz) \n + oper regulatory class (81 for 2.4GHz) \n + listen channel and regulatory class will determine the device listen channel during p2p find listen phase \n + oper channel and regulatory class will determine the operating channel preferred by this device (in case it is group owner this will be the operating channel) \n + channels should be one of the social channels (1/6/11). In case no listen/oper channel selected, a random 1/6/11 will be selected. + This option takes pointer to _u8[4] as parameter + + \param[in] ConfigLen - configurations len + + \param[in] pValues - configurations values + + \sa + \note + \warning + \par Examples: + \par + WLAN_AP_OPT_SSID: + \code + _u8 str[33]; + memset(str, 0, 33); + memcpy(str, ssid, len); // ssid string of 32 characters + sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SSID, strlen(ssid), str); + \endcode + \par + WLAN_AP_OPT_CHANNEL: + \code + _u8 val = channel; + sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_CHANNEL, 1, (_u8 *)&val); + \endcode + \par + WLAN_AP_OPT_HIDDEN_SSID: + \code + _u8 val = hidden; + sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_HIDDEN_SSID, 1, (_u8 *)&val); + \endcode + \par + WLAN_AP_OPT_SECURITY_TYPE: + \code + _u8 val = SL_SEC_TYPE_WPA_WPA2; + sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SECURITY_TYPE, 1, (_u8 *)&val); + \endcode + \par + WLAN_AP_OPT_PASSWORD: + \code + _u8 str[65]; + _u16 len = strlen(password); + memset(str, 0, 65); + memcpy(str, password, len); + sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_PASSWORD, len, (_u8 *)str); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_STA_TX_POWER: + \code + _u8 stapower=(_u8)power; + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER,1,(_u8 *)&stapower); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS: + \code + slWlanScanParamCommand_t ScanParamConfig; + ScanParamConfig.G_Channels_mask = 0x01; // bit mask for channels:1 means channel 1 is enabled, 3 means channels 1 + 2 are enabled + ScanParamConfig.rssiThershold = -70; // only for RSSI level which is higher than -70 + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID ,WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS,sizeof(slWlanScanParamCommand_t),(_u8*)&ScanParamConfig); + \endcode + + \par + WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE: + \code + _u8* str = (_u8 *) country; // string of 2 characters. i.e. - "US" + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE, 2, str); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_AP_TX_POWER: + \code + _u8 appower=(_u8)power; + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_AP_TX_POWER,1,(_u8 *)&appower); + \endcode + \par + WLAN_P2P_OPT_DEV_TYPE: + \code + _u8 str[17]; + _u16 len = strlen(device_type); + memset(str, 0, 17); + memcpy(str, device_type, len); + sl_WlanSet(SL_WLAN_CFG_P2P_PARAM_ID, WLAN_P2P_OPT_DEV_TYPE, len, str); + \endcode + \par + WLAN_P2P_OPT_CHANNEL_N_REGS: + \code + _u8 str[4]; + str[0] = (_u8)11; // listen channel + str[1] = (_u8)81; // listen regulatory class + str[2] = (_u8)6; // oper channel + str[3] = (_u8)81; // oper regulatory class + sl_WlanSet(SL_WLAN_CFG_P2P_PARAM_ID, WLAN_P2P_OPT_CHANNEL_N_REGS, 4, str); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_INFO_ELEMENT: + \code + sl_protocol_WlanSetInfoElement_t infoele; + infoele.index = Index; // Index of the info element. range: 0 - MAX_PRIVATE_INFO_ELEMENTS_SUPPROTED + infoele.role = Role; // INFO_ELEMENT_AP_ROLE (0) or INFO_ELEMENT_P2P_GO_ROLE (1) + infoele.ie.id = Id; // Info element ID. if INFO_ELEMENT_DEFAULT_ID (0) is set, ID will be set to 221. + // Organization unique ID. If all 3 bytes are zero - it will be replaced with 08,00,28. + infoele.ie.oui[0] = Oui0; // Organization unique ID first Byte + infoele.ie.oui[1] = Oui1; // Organization unique ID second Byte + infoele.ie.oui[2] = Oui2; // Organization unique ID third Byte + infoele.ie.length = Len; // Length of the info element. must be smaller than 253 bytes + memset(infoele.ie.data, 0, INFO_ELEMENT_MAX_SIZE); + if ( Len <= INFO_ELEMENT_MAX_SIZE ) + { + memcpy(infoele.ie.data, IE, Len); // Info element. length of the info element is [0-252] + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID,WLAN_GENERAL_PARAM_OPT_INFO_ELEMENT,sizeof(sl_protocol_WlanSetInfoElement_t),(_u8* ) &infoele); + } + sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID,WLAN_GENERAL_PARAM_OPT_INFO_ELEMENT,sizeof(sl_protocol_WlanSetInfoElement_t),(_u8* ) &infoele); + \endcode + +*/ +#if _SL_INCLUDE_FUNC(sl_WlanSet) +_i16 sl_WlanSet(const _u16 ConfigId ,const _u16 ConfigOpt,const _u16 ConfigLen,const _u8 *pValues); +#endif + +/*! + \brief Internal function for getting WLAN configurations + + \return On success, zero is returned. On error, -1 is + returned + + \param[in] ConfigId - configuration id + - SL_WLAN_CFG_AP_ID + - SL_WLAN_CFG_GENERAL_PARAM_ID + - SL_WLAN_CFG_P2P_PARAM_ID + + \param[out] pConfigOpt - get configurations option + - SL_WLAN_CFG_AP_ID + - WLAN_AP_OPT_SSID \n + Get SSID for AP mode. \n + Get up to 32 characters of SSID \n + This options takes _u8 as parameter + - WLAN_AP_OPT_CHANNEL \n + Get channel for AP mode. \n + This option takes _u8 as a parameter + - WLAN_AP_OPT_HIDDEN_SSID \n + Get Hidden SSID Mode for AP mode.Hidden options: \n + 0: disabled \n + 1: Send empty (length=0) SSID in beacon and ignore probe request for broadcast SSID \n + 2: Clear SSID (ASCII 0), but keep the original length (this may be required with some \n + clients that do not support empty SSID) and ignore probe requests for broadcast SSID \n + This option takes _u8 as a parameter + - WLAN_AP_OPT_SECURITY_TYPE \n + Get Security type for AP mode. Security options are: + - Open security: SL_SEC_TYPE_OPEN + - WEP security: SL_SEC_TYPE_WEP + - WPA security: SL_SEC_TYPE_WPA_WPA2 \n + This option takes _u8 as a parameter + - WLAN_AP_OPT_PASSWORD \n + Get Password for for AP mode (for WEP or for WPA): \n + Returns password - string, fills up to 64 characters. \n + This options takes _u8 buffer as parameter + - SL_WLAN_CFG_GENERAL_PARAM_ID + - WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS \n + Get scan parameters. + This option uses slWlanScanParamCommand_t as parameter + - WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE \n + Get Country Code for AP mode \n + This options takes _u8 buffer as parameter + - WLAN_GENERAL_PARAM_OPT_STA_TX_POWER \n + Get STA mode Tx power level \n + Number between 0-15, as dB offset from max power (0 indicates MAX power) \n + This options takes _u8 as parameter + - WLAN_GENERAL_PARAM_OPT_AP_TX_POWER + Get AP mode Tx power level \n + Number between 0-15, as dB offset from max power (0 indicates MAX power) \n + This options takes _u8 as parameter + - SL_WLAN_CFG_P2P_PARAM_ID + - WLAN_P2P_OPT_CHANNEL_N_REGS \n + Get P2P Channels. \n + listen channel (either 1/6/11 for 2.4GHz) \n + listen regulatory class (81 for 2.4GHz) \n + oper channel (either 1/6/11 for 2.4GHz) \n + oper regulatory class (81 for 2.4GHz) \n + listen channel and regulatory class will determine the device listen channel during p2p find listen phase \n + oper channel and regulatory class will determine the operating channel preferred by this device (in case it is group owner this will be the operating channel) \n + channels should be one of the social channels (1/6/11). In case no listen/oper channel selected, a random 1/6/11 will be selected. \n + This option takes pointer to _u8[4] as parameter + + \param[out] pConfigLen - The length of the allocated memory as input, when the + function complete, the value of this parameter would be + the len that actually read from the device. + If the device return length that is longer from the input + value, the function will cut the end of the returned structure + and will return SL_ESMALLBUF. + + + \param[out] pValues - get configurations values + + \sa sl_WlanSet + + \note + + \warning + + \par Examples: + \par + WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS: + \code + slWlanScanParamCommand_t ScanParamConfig; + _u16 Option = WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS; + _u16 OptionLen = sizeof(slWlanScanParamCommand_t); + sl_WlanGet(SL_WLAN_CFG_GENERAL_PARAM_ID ,&Option,&OptionLen,(_u8 *)&ScanParamConfig); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_AP_TX_POWER: + \code + _i8 TXPower = 0; + _u16 Option = WLAN_GENERAL_PARAM_OPT_AP_TX_POWER; + _u16 OptionLen = sizeof(_i8); + sl_WlanGet(SL_WLAN_CFG_GENERAL_PARAM_ID ,&Option,&OptionLen,(_u8 *)&TXPower); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_STA_TX_POWER: + \code + _i8 TXPower = 0; + _u16 Option = WLAN_GENERAL_PARAM_OPT_STA_TX_POWER; + _u16 OptionLen = sizeof(_i8); + + sl_WlanGet(SL_WLAN_CFG_GENERAL_PARAM_ID ,&Option,&OptionLen,(_u8 *)&TXPower); + \endcode + \par + WLAN_P2P_OPT_DEV_TYPE: + \code + _i8 device_type[18]; + _u16 len = 18; + _u16 config_opt = WLAN_P2P_OPT_DEV_TYPE; + sl_WlanGet(SL_WLAN_CFG_P2P_PARAM_ID, &config_opt , &len, (_u8* )device_type); + \endcode + \par + WLAN_AP_OPT_SSID: + \code + _i8 ssid[32]; + _u16 len = 32; + _u16 config_opt = WLAN_AP_OPT_SSID; + sl_WlanGet(SL_WLAN_CFG_AP_ID, &config_opt , &len, (_u8* )ssid); + \endcode + \par + WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE: + \code + _i8 country[3]; + _u16 len = 3; + _u16 config_opt = WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE; + sl_WlanGet(SL_WLAN_CFG_GENERAL_PARAM_ID, &config_opt, &len, (_u8* )country); + \endcode + \par + WLAN_AP_OPT_CHANNEL: + \code + _i8 channel; + _u16 len = 1; + _u16 config_opt = WLAN_AP_OPT_CHANNEL; + sl_WlanGet(SL_WLAN_CFG_AP_ID, &config_opt, &len, (_u8* )&channel); + \endcode + \par + WLAN_AP_OPT_HIDDEN_SSID: + \code + _u8 hidden; + _u16 len = 1; + _u16 config_opt = WLAN_AP_OPT_HIDDEN_SSID; + sl_WlanGet(SL_WLAN_CFG_AP_ID, &config_opt, &len, (_u8* )&hidden); + \endcode + \par + WLAN_AP_OPT_SECURITY_TYPE: + \code + _u8 sec_type; + _u16 len = 1; + _u16 config_opt = WLAN_AP_OPT_SECURITY_TYPE; + sl_WlanGet(SL_WLAN_CFG_AP_ID, &config_opt, &len, (_u8* )&sec_type); + \endcode + \par + WLAN_AP_OPT_PASSWORD: + \code + _u8 password[64]; + _u16 len = 64; + memset(password,0,64); + _u16 config_opt = WLAN_AP_OPT_PASSWORD; + sl_WlanGet(SL_WLAN_CFG_AP_ID, &config_opt, &len, (_u8* )password); + + \endcode + \par + WLAN_P2P_OPT_CHANNEL_N_REGS: + \code + _u16 listen_channel,listen_reg,oper_channel,oper_reg; + _u16 len = 4; + _u16 config_opt = WLAN_P2P_OPT_CHANNEL_N_REGS; + _u8 channel_n_regs[4]; + sl_WlanGet(SL_WLAN_CFG_P2P_PARAM_ID, &config_opt, &len, (_u8* )channel_n_regs); + listen_channel = channel_n_regs[0]; + listen_reg = channel_n_regs[1]; + oper_channel = channel_n_regs[2]; + oper_reg = channel_n_regs[3]; + \endcode +*/ + +#if _SL_INCLUDE_FUNC(sl_WlanGet) +_i16 sl_WlanGet(const _u16 ConfigId, _u16 *pConfigOpt,_u16 *pConfigLen, _u8 *pValues); +#endif +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __WLAN_H__ */ + diff --git a/src/openmv/src/micropython/drivers/cc3100/inc/wlan_rx_filters.h b/src/openmv/src/micropython/drivers/cc3100/inc/wlan_rx_filters.h new file mode 100755 index 0000000..8bd712f --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/inc/wlan_rx_filters.h @@ -0,0 +1,932 @@ +/* + * wlan_rx_filters.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + +#ifndef RX_FILTERS_PREPROCESSOR_CLI_IF_H_ +#define RX_FILTERS_PREPROCESSOR_CLI_IF_H_ + + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +/*! + * \def SL_RX_FILTER_MAX_FILTERS + * The Max number of filters for 64 filters + */ +#define SL_RX_FILTER_MAX_FILTERS 64 + +/*! + * \def SL_RX_FILTER_MAX_PRE_PREPARED_FILTERS_SETS + * The Max number of software filters + */ +#define SL_RX_FILTER_MAX_PRE_PREPARED_FILTERS_SETS (32) +/*! + * \def SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * + */ +#define SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS (2) +/*! + * \def SL_RX_FILTER_NUM_OF_FILTER_PAYLOAD_ARGS + * + */ +#define SL_RX_FILTER_NUM_OF_FILTER_PAYLOAD_ARGS (2) +/*! + * \def SL_RX_FILTER_NUM_OF_FILTER_PAYLOAD_ARGS + * + */ +#define SL_RX_FILTER_NUM_OF_COMBINATION_TYPE_ARGS (2) +/*! + * \def SL_RX_FILTER_LENGTH_OF_REGX_PATTERN_LENGTH + * + */ +#define SL_RX_FILTER_LENGTH_OF_REGX_PATTERN_LENGTH (32) + + +/* List of possible error numbers */ +#define RXFL_OK (0) /* O.K */ +#define RXFL_OUTPUT_OR_INPUT_BUFFER_LENGTH_TOO_SMALL (76) /* ! The output buffer length is smaller than required for that operation */ +#define RXFL_DEPENDENT_FILTER_SOFTWARE_FILTER_NOT_FIT (75) /* Node filter can't be child of software filter and vice_versa */ +#define RXFL_DEPENDENCY_IS_NOT_PERSISTENT (74) /* Dependency filter is not persistent */ +#define RXFL_SYSTEM_STATE_NOT_SUPPORTED_FOR_THIS_FILTER (72) /* System state is not supported */ +#define RXFL_TRIGGER_USE_REG5_TO_REG8 (71) /* Only counters 5 - 8 are allowed, for Tigger */ +#define RXFL_TRIGGER_USE_REG1_TO_REG4 (70) /* Only counters 1 - 4 are allowed, for trigger */ +#define RXFL_ACTION_USE_REG5_TO_REG8 (69) /* Only counters 5 - 8 are allowed, for action */ +#define RXFL_ACTION_USE_REG1_TO_REG4 (68) /* Only counters 1 - 4 are allowed, for action */ +#define RXFL_FIELD_SUPPORT_ONLY_EQUAL_AND_NOTEQUAL (67) /* Rule compare function Id is out of range */ +#define RXFL_WRONG_MULTICAST_BROADCAST_ADDRESS (66) /* The address should be of type mutlicast or broadcast */ +#define RXFL_THE_FILTER_IS_NOT_OF_HEADER_TYPE (65) /* The filter should be of header type */ +#define RXFL_WRONG_COMPARE_FUNC_FOR_BROADCAST_ADDRESS (64) /* The compare funcion is not suitable for broadcast address */ +#define RXFL_WRONG_MULTICAST_ADDRESS (63) /* The address should be of muticast type */ +#define RXFL_DEPENDENT_FILTER_IS_NOT_PERSISTENT (62) /* The dependency filter is not persistent */ +#define RXFL_DEPENDENT_FILTER_IS_NOT_ENABLED (61) /* The dependency filter is not enabled */ +#define RXFL_FILTER_HAS_CHILDS (60) /* The filter has childs and can't be removed */ +#define RXFL_CHILD_IS_ENABLED (59) /* Can't disable filter while the child is enabled */ +#define RXFL_DEPENDENCY_IS_DISABLED (58) /* Can't enable filetr in case its depndency filter is disabled */ +#define RXFL_NUMBER_OF_CONNECTION_POINTS_EXCEEDED (52) /* Number of connection points exceeded */ +#define RXFL_DEPENDENT_FILTER_DEPENDENCY_ACTION_IS_DROP (51) /* The dependent filter has Drop action, thus the filter can't be created */ +#define RXFL_FILTER_DO_NOT_EXISTS (50) /* The filter doesn't exists */ +#define RXFL_DEPEDENCY_NOT_ON_THE_SAME_LAYER (49) /* The filter and its dependency must be on the same layer */ +#define RXFL_NUMBER_OF_ARGS_EXCEEDED (48) /* Number of arguments excceded */ +#define RXFL_ACTION_NO_REG_NUMBER (47) /* Action require counter number */ +#define RXFL_DEPENDENT_FILTER_LAYER_DO_NOT_FIT (46) /* the filter and its dependency should be from the same layer */ +#define RXFL_DEPENDENT_FILTER_SYSTEM_STATE_DO_NOT_FIT (45) /* The filter and its dependency system state don't fit */ +#define RXFL_DEPENDENT_FILTER_DO_NOT_EXIST_2 (44) /* The parent filter don't exist */ +#define RXFL_DEPENDENT_FILTER_DO_NOT_EXIST_1 (43) /* The parent filter is null */ +#define RXFL_RULE_HEADER_ACTION_TYPE_NOT_SUPPORTED (42) /* The action type is not supported */ +#define RXFL_RULE_HEADER_TRIGGER_COMPARE_FUNC_OUT_OF_RANGE (41) /* The Trigger comparision function is out of range */ +#define RXFL_RULE_HEADER_TRIGGER_OUT_OF_RANGE (40) /* The Trigger is out of range */ +#define RXFL_RULE_HEADER_COMPARE_FUNC_OUT_OF_RANGE (39) /* The rule compare function is out of range */ +#define RXFL_FRAME_TYPE_NOT_SUPPORTED (38) /* ASCII frame type string is illegal */ +#define RXFL_RULE_FIELD_ID_NOT_SUPPORTED (37) /* Rule field ID is out of range */ +#define RXFL_RULE_HEADER_FIELD_ID_ASCII_NOT_SUPPORTED (36) /* This ASCII field ID is not supported */ +#define RXFL_RULE_HEADER_NOT_SUPPORTED (35) /* The header rule is not supported on current release */ +#define RXFL_RULE_HEADER_OUT_OF_RANGE (34) /* The header rule is out of range */ +#define RXFL_RULE_HEADER_COMBINATION_OPERATOR_OUT_OF_RANGE (33) /* Combination function Id is out of ramge */ +#define RXFL_RULE_HEADER_FIELD_ID_OUT_OF_RANGE (32) /* rule field Id is out of range */ +#define RXFL_UPDATE_NOT_SUPPORTED (31) /* Update not supported */ +#define RXFL_NO_FILTERS_ARE_DEFINED (24) /* No filters are defined in the system */ +#define RXFL_NUMBER_OF_FILTER_EXCEEDED (23) /* Number of max filters excceded */ + + +/******************************************************************************/ +/* Type declarations */ +/******************************************************************************/ + +/*! + + + * \typedef SlrxFilterID_t + * Unique filter ID which is allocated by the system , negative number means error + */ +typedef _i8 SlrxFilterID_t; + + +/*! + * \typedef SlrxFilterCompareMask_t + * The mask is used for the rule comparison function + */ +typedef _u8 SlrxFilterCompareMask_t; + +/*! + * \typedef SlrxFilterIdMask_t + * Representation of filters Id as a bit field + * The bit field is used to declare which filters are involved + * in operation. Number of filter can be up to 128 filters. i.e. 128 bits are needed. + * On the current release, up to 64 filters can be defined. + */ +typedef _u8 SlrxFilterIdMask_t[128/8]; + +/*! + * \typedef SlrxFilterPrePreparedFilters_t + * Describes the supported software filter sets, + */ +typedef _u8 SlrxFilterPrePreparedFilters_t; +#define SL_ARP_AUTO_REPLY_PRE_PREPARED_FILTERS (0) +#define SL_MULTICASTSIPV4_DROP_PREPREPARED_FILTERS (1) +#define SL_MULTICASTSIPV6_DROP_PREPREPARED_FILTERS (2) +#define SL_MULTICASTSWIFI_DROP_PREPREPARED_FILTERS (3) + + + +/*! + * \typedef SlrxFilterPrePreparedFiltersMask_t + * Describes the supported software filter sets, + * each bit represents different software filter set + * The filter sets are defined at SlrxFilterPrePreparedFilters_t + */ +typedef _u8 SlrxFilterPrePreparedFiltersMask_t[SL_RX_FILTER_MAX_PRE_PREPARED_FILTERS_SETS/8]; + + +/*! \typedef SlrxFilterRegxPattern_t + * The struct contains the regular expression pattern which is used in case of payload rule. + * Not supported in the current release + */ +typedef struct SlrxFilterRegxPattern_t +{ + _u8 x[SL_RX_FILTER_LENGTH_OF_REGX_PATTERN_LENGTH]; +}SlrxFilterRegxPattern_t; + + +/*! \typedef SlrxFilterAsciiArg_t + * The buffer is used to provide container for ASCII argument, which may be used in case of HEADER rule. + * example for ASCII argument can be : IP = 256.0.67.1 + */ +typedef _u8 SlrxFilterAsciiArg_t; + + +/*! \typedef SlrxFilterBinaryArg_t + * The buffer provides container for binary argument, which may be used in case of HEADER rule + */ +typedef _u8 SlrxFilterBinaryArg_t ; + + +/*! \typedef SlrxFilterActionArg_t + * Provides container for the filter action argument. + * for example: in case action is to send automatic response , the argument is the template to be used for the automatic response. + * + * + */ +typedef _u8 SlrxFilterActionArg_t ; + + + +/*! \typedef SlrxFilterOffset_t + * The offset relative to the packet payload start location. + * Not supported on current release + */ +typedef _u32 SlrxFilterOffset_t; + + + +/*! \typedef SlrxFilterRuleType_t + * Enumerates the different filter types. + * On the current release only HEADER and COMBINATION are supported. + */ +typedef _u8 SlrxFilterRuleType_t; +/* possible values for SlrxFilterRuleType_t */ +#define HEADER (0) +#define COMBINATION (1) +#define EXACT_PATTERN (2) +#define LIKELIHOOD_PATTERN (3) +#define ALWAYS_TRUE (4) +#define NUM_OF_FILTER_TYPES (5) + + +/*! \typedef SlrxFilterFlags_t + * Bit field which sets the behaviour of the RX filter + * + */ + +#define RX_FILTER_BINARY (0x1) +#define RX_FILTER_PERSISTENT (0x8) +#define RX_FILTER_ENABLE (0x10) + +typedef union SlrxFilterFlags_t +{ + + /* struct + { */ + /*! + * The filter argument can be set as binary argument or ASCII arguments. + * When the bit is on the argument are binary. + */ + /* _u8 Binary: 1; */ + /*! + * + */ + /* _u8 AutoSort : 1; */ + /*! + * + */ + /* _u8 AutoFaultDetect : 1; */ + /*! + * When the bit is on it means the the node is enabled . + */ + /* _u8 Enabled : 1; */ + /* _u8 padding : 3; */ + /* + };*/ + + _u8 IntRepresentation; + +}SlrxFilterFlags_t; + +/*! \typedef SlrxFilterCompareFunction_t + * Used as comparison function for the header type arguments + * + */ +typedef _u8 SlrxFilterCompareFunction_t; +/* Possible values for SlrxFilterCompareFunction_t */ +#define COMPARE_FUNC_IN_BETWEEN (0) +#define COMPARE_FUNC_EQUAL (1) +#define COMPARE_FUNC_NOT_EQUAL_TO (2) +#define COMPARE_FUNC_NOT_IN_BETWEEN (3) +#define COMPARE_FUNC_NUM_OF_FILTER_COMPARE_FUNC (4) + +/*! \typedef SlrxFilterCompareFunction_t + * Used as comparison function for the header type arguments + * + */ +typedef _u8 SlrxTriggerCompareFunction_t; +/* Possible values for SlrxTriggerCompareFunction_t */ +#define TRIGGER_COMPARE_FUNC_EQUAL (0) +/* arg1 == protocolVal ,not supported in current release */ +#define TRIGGER_COMPARE_FUNC_NOT_EQUAL_TO (1) +/* arg1 == protocolVal */ +#define TRIGGER_COMPARE_FUNC_SMALLER_THAN (2) +/* arg1 == protocolVal */ +#define TRIGGER_COMPARE_FUNC_BIGGER_THAN (3) +/* definition */ +#define TRIGGER_COMPARE_FUNC_NUM_OF_FILTER_COMPARE_FUNC (4) + + +/*! \typedef SlrxFilterHdrField_t + * Provides list of possible header types which may be defined as part of the rule + * + */ +typedef _u8 SlrxFilterHdrField_t; +/* Possible values for SlrxFilterHdrField_t */ +#define NULL_FIELD_ID_TYPE (0) +/* 802.11 control\data\management */ +#define FRAME_TYPE_FIELD (1) +/* 802.11 beacon\probe\.. */ +#define FRAME_SUBTYPE_FIELD (2) + /* 802.11 bssid type */ +#define BSSID_FIELD (3) + /* */ +#define MAC_SRC_ADDRESS_FIELD (4) + /* */ +#define MAC_DST_ADDRESS_FIELD (5) +/* */ +#define FRAME_LENGTH_FIELD (6) +/* */ +#define PROTOCOL_TYPE_FIELD (7) + /* */ +#define IP_VERSION_FIELD (8) + /* TCP / UDP */ +#define IP_PROTOCOL_FIELD (9) + /* */ +#define IPV4_SRC_ADRRESS_FIELD (10) +/* */ +#define IPV4_DST_ADDRESS_FIELD (11) +/* */ +#define IPV6_SRC_ADRRESS_FIELD (12) +/* */ +#define IPV6_DST_ADDRESS_FIELD (13) + /* */ +#define SRC_PORT_FIELD (14) + /* */ +#define DST_PORT_FIELD (15) + /* Definition */ +#define NUM_OF_FIELD_NAME_FIELD (16) + +/*! \union SlrxFilterHeaderArg_t + * The structure holds the header ARGS which are used in case of HDR rule. + */ +/* -- 36 bytes */ +typedef union SlrxFilterHeaderArg_t +{ + /*----------------------------- Large size ---------------------------------*/ + /*! buffer for binary arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * example : IPV6 16 bytes, 39 characters + * ipv6 Ascii address: 2001:0db8:3c4d:0015:0000:0000:abcd:ef12 + */ + + SlrxFilterBinaryArg_t RxFilterDB16BytesRuleArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][16 ]; /* Binary Values for comparition */ + /*! buffer for ASCII arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * example : IPV6 16 bytes, 39 characters + * ipv6 Ascii address: 2001:0db8:3c4d:0015:0000:0000:abcd:ef12 + * Ascii format for ipV6 is not supported + */ + /*----------------------------- Medium size ---------------------------------*/ + /*! buffer for binary arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * MAC address: 6 bytes, 17 chars + */ + SlrxFilterBinaryArg_t RxFilterDB6BytesRuleArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][6]; /* Binary Values for comparition */ + /*! + * ! buffer for ASCII arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * IP address: 4 bytes, 15 chars + * 2 bytes are added for padding + */ + SlrxFilterAsciiArg_t RxFilterDB18BytesAsciiRuleArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][18]; /* Ascii Values for comparison */ + /*----------------------------- Small size ---------------------------------*/ + /*! buffer for binary arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * IP address: 4 bytes, 15 chars + * Port: 2 bytes, chars: 5 chars + */ + SlrxFilterBinaryArg_t RxFilterDB4BytesRuleArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][4]; /* Binary Values for comparison */ + /*! buffer for ASCII arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + * Port: 2 bytes, chars: 5 chars + */ + SlrxFilterAsciiArg_t RxFilterDB5BytesRuleAsciiArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][5]; /* Ascii Values for comparison */ + /*----------------------------- 1 byte size ---------------------------------*/ + /*! buffer for binary arguments, number of argument may be up to SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS + */ + SlrxFilterBinaryArg_t RxFilterDB1BytesRuleArgs[SL_RX_FILTER_NUM_OF_FILTER_HEADER_ARGS][1]; /* Binary Values for comparison */ +}SlrxFilterHeaderArg_t; + + + +/*! \typedef SlrxFilterRuleHeaderArgsAndMask_t + * Structure which defines the Header Args and mask + */ +/* -- 52 bytes */ +typedef struct SlrxFilterRuleHeaderArgsAndMask_t +{ + /*! Argument for the comparison function */ + /* -- 36 byte */ + SlrxFilterHeaderArg_t RuleHeaderArgs; + + /*! the mask is used in order to enable partial comparison, + * Use the 0xFFFFFFFF in case you don't want to use mask + */ + /* -- 16 bytes */ + SlrxFilterCompareMask_t RuleHeaderArgsMask[16]; + +}SlrxFilterRuleHeaderArgsAndMask_t; + +/*! \typedef SlrxFilterHeaderType_t + * Structure which defines the Header rule + * The header rule defines compare function on the protocol header + * For example destMacAddre is between ( 12:6::78:77, 12:6::78:90 ) + * + */ +/* -- 56 byte */ +typedef struct SlrxFilterHeaderType_t +{ + /*! see :: SlrxFilterRuleHeaderArgsAndMask_t */ + /* -- 52 bytes */ + SlrxFilterRuleHeaderArgsAndMask_t RuleHeaderArgsAndMask; + + /*! Packet HDR field which will be compared to the argument */ + /* -- 1 byte */ + SlrxFilterHdrField_t RuleHeaderfield; + + /* -- 1 byte */ + /*! type of the comparison function + * see :: SlrxFilterCompareFunction_t + */ + SlrxFilterCompareFunction_t RuleCompareFunc; + + /*! padding */ + /* -- 2 bytes */ + _u8 RulePadding[2]; + +}SlrxFilterHeaderType_t; + +/*! \typedef SlrxFilterPayloadType_t + * Structure which defines payload rule. + * Not supported on current release. + */ +/* -- 40 byte */ +typedef struct SlrxFilterPayloadType_t +{ + /*! Not supported on current release */ + /* -- 32 byte */ + SlrxFilterRegxPattern_t RegxPattern; + /*! Not supported on current release */ + /* -- 4 byte */ + SlrxFilterOffset_t LowerOffset; + /*! Not supported on current release */ + /* -- 4 byte */ + SlrxFilterOffset_t UpperOffset; +}SlrxFilterPayloadType_t; + +/*! \typedef SlrxFilterCombinationTypeOperator_t + * Enumerate the optional operators for the combination type + * filterID1 is located in the first arg , filterId2 is the second arg,see ::SlrxFilterCombinationType_t.CombinationFilterId + */ +typedef _u8 SlrxFilterCombinationTypeOperator_t; +/* Possible values for SlrxFilterCombinationTypeOperator_t */ +/*! !filterID1 */ +#define COMBINED_FUNC_NOT (0) +/*! filterID1 && filterID2 */ +#define COMBINED_FUNC_AND (1) +/*! filterID1 && filterID2 */ +#define COMBINED_FUNC_OR (2) + +/*! \typedef SlrxFilterCombinationType_t + * Defines the structure which define the combination type filter + * The combined filter enable to make operation on one or two filter, + * for example !filterId1 or and(filterId2,filterId3). + * + */ +/* -- 4 byte */ +typedef struct SlrxFilterCombinationType_t +{ + /* ! combination operator */ + /* -- 1 byte */ + SlrxFilterCombinationTypeOperator_t CombinationTypeOperator; + /* ! filterID, may be one or two depends on the combination operator type */ + /* -- 2 byte */ + SlrxFilterID_t CombinationFilterId[SL_RX_FILTER_NUM_OF_COMBINATION_TYPE_ARGS]; + /* ! Padding */ + /* -- 1 byte */ + _u8 Padding; +}SlrxFilterCombinationType_t; + + +/*! \typedef SlrxFilterRule_t + * Rule structure composed of behavioral flags and the filter rule definitions + * + */ +/* -- 56 byte */ +typedef union SlrxFilterRule_t +{ + /* ! Header type rule , see explanation on the ::SlrxFilterHeaderType_t structure */ + /* -- 56 byte */ + SlrxFilterHeaderType_t HeaderType; + /* ! Payload rule, not supported in current release */ + /* -- 40 byte */ + SlrxFilterPayloadType_t PayLoadHeaderType; /* future for exact pattern or like hood pattern */ + /* ! Combined type rule , see explanation in ::SlrxFilterCombinationType_t structure */ + /* -- 4 byte */ + SlrxFilterCombinationType_t CombinationType; +}SlrxFilterRule_t; + +/*! \typedef SlrxFilterTriggerRoles_t + * Bit field which represents the roleId possible values + * In the current release only Station/AP roles are supported. + */ +#define RX_FILTER_ROLE_AP (1) +#define RX_FILTER_ROLE_STA (2) +#define RX_FILTER_ROLE_PROMISCUOUS (4) +#define RX_FILTER_ROLE_NULL (0) + +typedef union SlrxFilterTriggerRoles_t +{ +/* struct */ +/* { */ +/* _u8 RoleAP :1; */ +/* _u8 RoleStation :1; */ + /* The filter is activated only in Promiscuous mode */ +/* _u8 PromiscuousMode :1; */ +/* _u8 RoleReserved :5; */ +/* }; */ + /* ! Bit fiels of the Filter role */ + _u8 IntRepresentation; + +}SlrxFilterTriggerRoles_t; + +/*! \typedef SlrxFilterTriggerConnectionStates_t + * Bit field representing the possible values of the When section of the rule + * + */ +#define RX_FILTER_CONNECTION_STATE_STA_CONNECTED (1) +#define RX_FILTER_CONNECTION_STATE_STA_NOT_CONNECTED (2) +#define RX_FILTER_CONNECTION_STATE_STA_HAS_IP (4) +#define RX_FILTER_CONNECTION_STATE_STA_HAS_NO_IP (8) + +typedef union SlrxFilterTriggerConnectionStates_t +{ +/* struct */ +/* { */ +/* _u8 RoleStationWiFiConnected :1; */ +/* _u8 RoleStationWiFiDisconneted:1; */ +/* _u8 RoleStationWiFiHasIp:1; */ +/* _u8 RoleStationWiFiHasNoIp:1; */ +/* _u8 RoleStationWiFiSocketOpened:1; */ +/* _u8 RoleStationWiFiSocketclosed:1; */ +/* }; */ +/* */ + /* ! */ + _u8 IntRepresentation; + +}SlrxFilterTriggerConnectionStates_t; + +/*! \typedef SlrxFilterDBTriggerArg_t + * Provides container for entering the filter 'when' argument. + * The current release support 'When rules' which has no arguments. + * For example : + * When connect to specific AP -- the AP bssid is the argument. + * + */ +typedef _u32 SlrxFilterDBTriggerArg_t; + + + +/*! \typedef SlrxFilterCounterId_t + * the counter ID we have 4 counters + */ +typedef _u8 SlrxFilterCounterId_t; +/* Possible values for SlrxFilterCounterId_t */ +#define NO_TRIGGER (0) +#define RX_FILTER_COUNTER1 (1) +#define RX_FILTER_COUNTER2 (2) +#define RX_FILTER_COUNTER3 (3) +#define RX_FILTER_COUNTER4 (4) +#define RX_FILTER_COUNTER5 (5) +#define RX_FILTER_COUNTER6 (6) +#define RX_FILTER_COUNTER7 (7) +#define RX_FILTER_COUNTER8 (8) +#define MAX_RX_FILTER_COUNTER (9) + + + +/*! \typedef SlrxFilterActionArgs_t + * Possible value for filter action args + * + */ + +typedef _u8 SlrxFilterActionArgs_t; +/* Possible values for SlrxFilterActionArgs_t */ +#define ACTION_ARG_REG_1_4 (0) + /* ! Can be use as counter */ +#define ACTION_ARG_TEMPLATE (1) + /* ! Can be use as counter */ +#define ACTION_ARG_EVENT (2) + +/* ! GPIO number */ +#define ACTION_ARG_GPIO (4) +/*! + * \def SL_RX_FILTER_NUM_OF_BYTES_FOR_ACTIONS_ARGS + * + */ +#define SL_RX_FILTER_NUM_OF_BYTES_FOR_ACTIONS_ARGS (5) + + + + +/*! \typedef SlrxFilterTrigger_t + * The filter trigger, determine when the filter is triggered, + * The filter is triggered in the following condition :\n + * 1. The filter parent is triggered\n + * 2. The requested connection type exists, i.e. wlan_connect\n + * 3. The filter role is the same as the system role\n + * + */ +/* -- 12 byte */ +typedef struct SlrxFilterTrigger_t +{ + /*! The parent filter ID, this is the way to build filter tree. */ + /* NULL value means tree root. + */ + /* -- 1 byte */ + SlrxFilterID_t ParentFilterID; + /* ! See ::SlrxFilterCounterId_t explanation */ + /* -- 1 byte */ + SlrxFilterCounterId_t Trigger; + /* ! See :: SlrxFilterTriggerConnectionStates_t */ + /* -- 1 byte */ + SlrxFilterTriggerConnectionStates_t TriggerArgConnectionState; + /* ! See ::SlrxFilterTriggerRoles_t */ + /* -- 1 byte */ + SlrxFilterTriggerRoles_t TriggerArgRoleStatus; + /* ! The Trigger arguments are in the same order as the Trigger bit field order. */ + /* -- 4 byte */ + SlrxFilterDBTriggerArg_t TriggerArg; + /** The compare function which will be operate for each bit that is turned on in the ::SlrxFilterTrigger_t.Trigger field, + * for example , in case the second bit in the Trigger function is on the second function in the list will be executed. + * + */ + /* -- 1 byte */ + SlrxTriggerCompareFunction_t TriggerCompareFunction; + + /* ! padding */ + /* -- 3 byte */ + _u8 Padding[3]; +} SlrxFilterTrigger_t; + +/*! \typedef SlrxFilterActionType_t + * The actions are executed only if the filter is matched,\n + * In case of false match the packet is transfered to the HOST. \n + * The action is composed of bit field structure, + * up to 2 actions can be defined per filter. + * + */ +#define RX_FILTER_ACTION_NULL (0x0) +#define RX_FILTER_ACTION_DROP (0x1) +#define RX_FILTER_ACTION_GPIO (0x2) +#define RX_FILTER_ACTION_ON_REG_INCREASE (0x4) +#define RX_FILTER_ACTION_ON_REG_DECREASE (0x8) +#define RX_FILTER_ACTION_ON_REG_RESET (0x10) +#define RX_FILTER_ACTION_SEND_TEMPLATE (0x20) /* unsupported */ +#define RX_FILTER_ACTION_EVENT_TO_HOST (0x40) /* unsupported */ + +typedef union SlrxFilterActionType_t +{ +/* struct */ +/* { */ + /* ! No action to execute the packet is dropped,drop is always on leaf. */ + /* ! If not dropped ,The packet is passed to the next filter or in case it is the last filter to the host */ +/* _u8 ActionDrop : 1; */ + /* ! Not Supported in the current release */ +/* _u8 ActionGpio : 1; */ + /*! action can increase counter registers. + * 1 = Increase + * 2 = decrease + * 3 = reset + */ +/* _u8 ActionOnREGIncrease : 1; */ +/* _u8 ActionOnREGDecrease : 1; */ +/* _u8 ActionOnREGReset : 1; */ + + /* ! Not Supported in the current release */ +/* _u8 ActionSendTemplate : 1; */ + /* ! Not Supported in the current release */ +/* _u8 ActionEventToHost: 1; */ +/* _u8 padding: 1; */ +/* }; */ + + _u8 IntRepresentation; + +}SlrxFilterActionType_t; + +/*! \typedef SlrxFilterAction_t + * Several actions can be defined,\n + * The action is executed in case the filter rule is matched. + */ +/* -- 8 byte */ +typedef struct SlrxFilterAction_t +{ + /* -- 1 byte */ + /* ! Determine which actions are supported */ + SlrxFilterActionType_t ActionType; + /* ! Buffer for the action arguments */ + /** + * location 0 - The counter to increase + * In case the action is of type "increase" the arg will contain the counter number, + * The counter number values are as in ::SlrxFilterCounterId_t.\n + * location 1 - The template arg.\n + * location 2 - The event arg.\n + * + */ + /* -- 5 byte */ + SlrxFilterActionArg_t ActionArg[SL_RX_FILTER_NUM_OF_BYTES_FOR_ACTIONS_ARGS]; + + /* ! Padding */ + /* - 2 Bytes */ + _u8 Padding[2]; + +} SlrxFilterAction_t; + + +/*! \struct _WlanRxFilterOperationCommandBuff_t + * The structure is used for the interface HOST NWP.\n + * The supported operation : \n + * ::ENABLE_DISABLE_RX_FILTER,\n + * ::REMOVE_RX_FILTER,\n + * + */ +/* 20 bytes */ +typedef struct _WlanRxFilterOperationCommandBuff_t +{ + /* -- 16 bytes */ + SlrxFilterIdMask_t FilterIdMask; + /* 4 bytes */ + _u8 Padding[4]; +}_WlanRxFilterOperationCommandBuff_t; + + + +/* -- 56 bytes */ +typedef struct _WlanRxFilterUpdateArgsCommandBuff_t +{ + /* -- 1 bytes */ + _u8 FilterId; + + /* -- 1 bytes */ + /* ! the args representation */ + _u8 BinaryRepresentation; + + /* -- 52 byte */ + SlrxFilterRuleHeaderArgsAndMask_t FilterRuleHeaderArgsAndMask; + + /* -- 2 bytes */ + _u8 Padding[2]; +}_WlanRxFilterUpdateArgsCommandBuff_t; + + +/*! \typedef _WlanRxFilterRetrieveEnableStatusCommandResponseBuff_t + * The structure is used for the interface HOST NWP.\n + * + */ +/* -- 16 bytes */ +typedef struct _WlanRxFilterRetrieveEnableStatusCommandResponseBuff_t +{ + + /* ! the filter set bit map */ + /* -- 16 bytes */ + SlrxFilterIdMask_t FilterIdMask; + +}_WlanRxFilterRetrieveEnableStatusCommandResponseBuff_t; + + +/*! \struct _WlanRxFilterPrePreparedFiltersCommandBuff_t + * The function enables to perform operations on pre-prepared filters + * + */ +typedef struct _WlanRxFilterPrePreparedFiltersCommandBuff_t +{ + /* ! the filter set bit map */ + /* -- 4 bytes */ + SlrxFilterPrePreparedFiltersMask_t FilterPrePreparedFiltersMask; + +}_WlanRxFilterPrePreparedFiltersCommandBuff_t; + + +/*! \typedef sl_protocol_WlanRxFilterPrePreparedFiltersCommandResponseBuff_t + * + */ +/*-- 4 bytes */ +typedef struct _WlanRxFilterPrePreparedFiltersCommandResponseBuff_t +{ + /* -- 4 bytes */ + /* ! the filter set bit map */ + SlrxFilterPrePreparedFiltersMask_t FilterPrePreparedFiltersMask; + +}_WlanRxFilterPrePreparedFiltersCommandResponseBuff_t; + + + +typedef _u8 SLrxFilterOperation_t; +#define SL_ENABLE_DISABLE_RX_FILTER (0) +#define SL_REMOVE_RX_FILTER (1) +#define SL_STORE_RX_FILTERS (2) +#define SL_UPDATE_RX_FILTER_ARGS (3) +#define SL_FILTER_RETRIEVE_ENABLE_STATE (4) +#define SL_FILTER_PRE_PREPARED_RETRIEVE_CREATE_REMOVE_STATE (5) +#define SL_FILTER_PRE_PREPARED_SET_CREATE_REMOVE_STATE (6) + + +/* Bit manipulation for 8 bit */ +#define ISBITSET8(x,i) ((x[i>>3] & (0x80>>(i&7)))!=0) /* < Is bit set, 8 bit unsigned numbers = x , location = i */ +#define SETBIT8(x,i) x[i>>3]|=(0x80>>(i&7)); /* < Set bit,8 bit unsigned numbers = x , location = i */ +#define CLEARBIT8(x,i) x[i>>3]&=(0x80>>(i&7))^0xFF; /* < Clear bit,8 bit unsigned numbers = x , location = i */ + + +/*********************************************************************************************/ +/* Function prototypes */ +/*********************************************************************************************/ + +/*! + + \addtogroup wlan + @{ + +*/ + + +/*! + \brief Adds new filter rule to the system + + \param[in] RuleType The rule type + \param[in] FilterFlags Flags which set the type of header rule Args and sets the persistent flag + \param[in] pRule Determine the filter rule logic + \param[in] pTrigger Determine when the rule is triggered also sets rule parent. + \param[in] pAction Sets the action to be executed in case the match functions pass + \param[out] pFilterId The filterId which was created + + \return On success, zero is returned. Otherwise error code is returned + */ +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterAdd) +SlrxFilterID_t sl_WlanRxFilterAdd( SlrxFilterRuleType_t RuleType, + SlrxFilterFlags_t FilterFlags, + const SlrxFilterRule_t* const Rule, + const SlrxFilterTrigger_t* const Trigger, + const SlrxFilterAction_t* const Action, + SlrxFilterID_t* pFilterId); + +#endif + + + + + +/*! + \brief Sets parameters to Rx filters + + \param[in] RxFilterOperation + possible operations : + - SL_ENABLE_DISABLE_RX_FILTER - Enables\disables filter in a filter list + - SL_REMOVE_RX_FILTER - Removes filter from memory ( to remove from flash call SL_STORE_RX_FILTERS after this command) + - SL_STORE_RX_FILTERS - Save the filters for persistent + - SL_UPDATE_RX_FILTER_ARGS - Update the arguments of existing filter + - SL_FILTER_PRE_PREPARED_SET_CREATE_REMOVE_STATE - Change the default creation of the pre-prepared filters + + \param[in] pInputBuffer options: + The buffer input is _WlanRxFilterOperationCommandBuff_t: + - SL_ENABLE_DISABLE_RX_FILTER + - SL_REMOVE_RX_FILTER + - SL_STORE_RX_FILTERS + The buffer input is _WlanRxFilterUpdateArgsCommandBuff_t: + - SL_UPDATE_RX_FILTER_ARGS + The buffer input is _WlanRxFilterPrePreparedFiltersCommandBuff_t: + - SL_FILTER_PRE_PREPARED_SET_CREATE_REMOVE_STATE + + \param[in] InputbufferLength The length in byte of the input buffer + + \return On success, zero is returned. Otherwise error code is returned + */ + +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterSet) +_i16 sl_WlanRxFilterSet( const SLrxFilterOperation_t RxFilterOperation, + const _u8* const pInputBuffer, + _u16 InputbufferLength); +#endif + +/*! + \brief Gets parameters of Rx filters + + \param[in] RxFilterOperation + possible operations : + - SL_FILTER_RETRIEVE_ENABLE_STATE - Retrieves the enable disable status + - SL_FILTER_PRE_PREPARED_RETRIEVE_CREATE_REMOVE_STATE - Retrieves the pre-prepared filters creation status + + \param[in] pOutputBuffer + The buffer input is _WlanRxFilterRetrieveEnableStatusCommandResponseBuff_t: + - SL_FILTER_RETRIEVE_ENABLE_STATE + The buffer input is _WlanRxFilterPrePreparedFiltersCommandResponseBuff_t: + - SL_FILTER_PRE_PREPARED_RETRIEVE_CREATE_REMOVE_STATE + + \param[in] OutputbufferLength The length in byte of the output buffer + + \return On success, zero is returned. Otherwise error code is returned +*/ + +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterGet) +_i16 sl_WlanRxFilterGet(const SLrxFilterOperation_t RxFilterOperation, + _u8* pOutputBuffer, + _u16 OutputbufferLength); +#endif + + +/*! + + Close the Doxygen group. + @} + + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RX_FILTERS_PREPROCESSOR_CLI_IF_H_ */ + + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/device.c b/src/openmv/src/micropython/drivers/cc3100/src/device.c new file mode 100755 index 0000000..3d4028f --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/device.c @@ -0,0 +1,557 @@ +/* +* device.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "flowcont.h" +#include "driver.h" + + +/*****************************************************************************/ +/* Internal functions */ +/*****************************************************************************/ + +const _i8 StartResponseLUT[8] = +{ + ROLE_UNKNOWN_ERR, + ROLE_STA, + ROLE_STA_ERR, + ROLE_AP, + ROLE_AP_ERR, + ROLE_P2P, + ROLE_P2P_ERR, + ROLE_UNKNOWN_ERR +}; + + + +_i16 _sl_GetStartResponseConvert(_u32 Status) +{ + return (_i16)StartResponseLUT[Status & 0x7]; +} + +/*****************************************************************************/ +/* API Functions */ +/*****************************************************************************/ + + + +/*****************************************************************************/ +/* sl_Task */ +/*****************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_Task) +void sl_Task(void) +{ +#ifdef _SlTaskEntry + _SlTaskEntry(); +#endif +} +#endif + +/*****************************************************************************/ +/* sl_Start */ +/*****************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_Start) +_i16 sl_Start(const void* pIfHdl, _i8* pDevName, const P_INIT_CALLBACK pInitCallBack) +{ + _i16 ObjIdx = MAX_CONCURRENT_ACTIONS; + InitComplete_t AsyncRsp; + + /* Perform any preprocessing before enable networking services */ + sl_DeviceEnablePreamble(); + + /* ControlBlock init */ + _SlDrvDriverCBInit(); + + /* open the interface: usually SPI or UART */ + if (NULL == pIfHdl) + { + g_pCB->FD = sl_IfOpen((void *)pDevName, 0); + } + else + { + g_pCB->FD = (_SlFd_t)pIfHdl; + } + + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8 *)&AsyncRsp, START_STOP_ID, SL_MAX_SOCKETS); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + if( g_pCB->FD >= (_SlFd_t)0) + { + sl_DeviceDisable(); + + sl_IfRegIntHdlr((SL_P_EVENT_HANDLER)_SlDrvRxIrqHandler, NULL); + + g_pCB->pInitCallback = pInitCallBack; + sl_DeviceEnable(); + + if (NULL == pInitCallBack) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + /* release Pool Object */ + _SlDrvReleasePoolObj(g_pCB->FunctionParams.AsyncExt.ActionIndex); + return _sl_GetStartResponseConvert(AsyncRsp.Status); + } + else + { + return SL_RET_CODE_OK; + } + } + return SL_BAD_INTERFACE; +} +#endif + +/*************************************************************************** +_sl_HandleAsync_InitComplete - handles init complete signalling to +a waiting object +****************************************************************************/ +void _sl_HandleAsync_InitComplete(void *pVoidBuf) +{ + InitComplete_t *pMsgArgs = (InitComplete_t *)_SL_RESP_ARGS_START(pVoidBuf); + + _SlDrvProtectionObjLockWaitForever(); + + if(g_pCB->pInitCallback) + { + g_pCB->pInitCallback(_sl_GetStartResponseConvert(pMsgArgs->Status)); + } + else + { + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(InitComplete_t)); + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + } + + _SlDrvProtectionObjUnLock(); + + if(g_pCB->pInitCallback) + { + _SlDrvReleasePoolObj(g_pCB->FunctionParams.AsyncExt.ActionIndex); + } + +} + +/*************************************************************************** +_sl_HandleAsync_Stop - handles stop signalling to +a waiting object +****************************************************************************/ +void _sl_HandleAsync_Stop(void *pVoidBuf) +{ + _BasicResponse_t *pMsgArgs = (_BasicResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + + VERIFY_SOCKET_CB(NULL != g_pCB->StopCB.pAsyncRsp); + + _SlDrvProtectionObjLockWaitForever(); + + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_BasicResponse_t)); + + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + _SlDrvProtectionObjUnLock(); + + return; +} + + +/***************************************************************************** +sl_stop +******************************************************************************/ +typedef union +{ + _DevStopCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlStopMsg_u; + +const _SlCmdCtrl_t _SlStopCmdCtrl = +{ + SL_OPCODE_DEVICE_STOP_COMMAND, + sizeof(_DevStopCommand_t), + sizeof(_BasicResponse_t) +}; + +#if _SL_INCLUDE_FUNC(sl_Stop) +_i16 sl_Stop(const _u16 timeout) +{ + _i16 RetVal=0; + _SlStopMsg_u Msg; + _BasicResponse_t AsyncRsp; + _i8 ObjIdx = MAX_CONCURRENT_ACTIONS; + /* if timeout is 0 the shutdown is forced immediately */ + if( 0 == timeout ) + { + sl_IfRegIntHdlr(NULL, NULL); + sl_DeviceDisable(); + RetVal = sl_IfClose(g_pCB->FD); + + } + else + { + /* let the device make the shutdown using the defined timeout */ + Msg.Cmd.Timeout = timeout; + + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8 *)&AsyncRsp, START_STOP_ID, SL_MAX_SOCKETS); + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlStopCmdCtrl, &Msg, NULL)); + + if(SL_OS_RET_CODE_OK == (_i16)Msg.Rsp.status) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + Msg.Rsp.status = AsyncRsp.status; + RetVal = Msg.Rsp.status; + } + + _SlDrvReleasePoolObj(ObjIdx); + sl_IfRegIntHdlr(NULL, NULL); + sl_DeviceDisable(); + sl_IfClose(g_pCB->FD); + } + _SlDrvDriverCBDeinit(); + + return RetVal; +} +#endif + + +/***************************************************************************** +sl_EventMaskSet +*****************************************************************************/ +typedef union +{ + _DevMaskEventSetCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlEventMaskSetMsg_u; + + + + +#if _SL_INCLUDE_FUNC(sl_EventMaskSet) + +const _SlCmdCtrl_t _SlEventMaskSetCmdCtrl = +{ + SL_OPCODE_DEVICE_EVENTMASKSET, + sizeof(_DevMaskEventSetCommand_t), + sizeof(_BasicResponse_t) +}; + + +_i16 sl_EventMaskSet(const _u8 EventClass ,const _u32 Mask) +{ + _SlEventMaskSetMsg_u Msg; + + Msg.Cmd.group = EventClass; + Msg.Cmd.mask = Mask; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlEventMaskSetCmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif + +/****************************************************************************** +sl_EventMaskGet +******************************************************************************/ +typedef union +{ + _DevMaskEventGetCommand_t Cmd; + _DevMaskEventGetResponse_t Rsp; +}_SlEventMaskGetMsg_u; + + + +#if _SL_INCLUDE_FUNC(sl_EventMaskGet) + +const _SlCmdCtrl_t _SlEventMaskGetCmdCtrl = +{ + SL_OPCODE_DEVICE_EVENTMASKGET, + sizeof(_DevMaskEventGetCommand_t), + sizeof(_DevMaskEventGetResponse_t) +}; + + +_i16 sl_EventMaskGet(const _u8 EventClass,_u32 *pMask) +{ + _SlEventMaskGetMsg_u Msg; + + Msg.Cmd.group = EventClass; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlEventMaskGetCmdCtrl, &Msg, NULL)); + + *pMask = Msg.Rsp.mask; + return SL_RET_CODE_OK; +} +#endif + + + +/****************************************************************************** +sl_DevGet +******************************************************************************/ + +typedef union +{ + _DeviceSetGet_t Cmd; + _DeviceSetGet_t Rsp; +}_SlDeviceMsgGet_u; + + + +#if _SL_INCLUDE_FUNC(sl_DevGet) + +const _SlCmdCtrl_t _SlDeviceGetCmdCtrl = +{ + SL_OPCODE_DEVICE_DEVICEGET, + sizeof(_DeviceSetGet_t), + sizeof(_DeviceSetGet_t) +}; + +_i32 sl_DevGet(const _u8 DeviceGetId,_u8 *pOption,_u8 *pConfigLen, _u8 *pValues) +{ + _SlDeviceMsgGet_u Msg; + _SlCmdExt_t CmdExt; + + if (*pConfigLen == 0) + { + return SL_EZEROLEN; + } + + if( pOption ) + { + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pConfigLen; + CmdExt.pRxPayload = (_u8 *)pValues; + + Msg.Cmd.DeviceSetId = DeviceGetId; + + Msg.Cmd.Option = (_u16)*pOption; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlDeviceGetCmdCtrl, &Msg, &CmdExt)); + + if( pOption ) + { + *pOption = (_u8)Msg.Rsp.Option; + } + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *pConfigLen = (_u8)CmdExt.RxPayloadLen; + return SL_ESMALLBUF; + } + else + { + *pConfigLen = (_u8)CmdExt.ActualRxPayloadLen; + } + + return (_i16)Msg.Rsp.Status; + } + else + { + return -1; + } +} +#endif + +/****************************************************************************** +sl_DevSet +******************************************************************************/ +typedef union +{ + _DeviceSetGet_t Cmd; + _BasicResponse_t Rsp; +}_SlDeviceMsgSet_u; + + + +#if _SL_INCLUDE_FUNC(sl_DevSet) + +const _SlCmdCtrl_t _SlDeviceSetCmdCtrl = +{ + SL_OPCODE_DEVICE_DEVICESET, + sizeof(_DeviceSetGet_t), + sizeof(_BasicResponse_t) +}; + +_i32 sl_DevSet(const _u8 DeviceSetId ,const _u8 Option,const _u8 ConfigLen,const _u8 *pValues) +{ + _SlDeviceMsgSet_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + + CmdExt.TxPayloadLen = (ConfigLen+3) & (~3); + CmdExt.pTxPayload = (_u8 *)pValues; + + Msg.Cmd.DeviceSetId = DeviceSetId; + Msg.Cmd.ConfigLen = ConfigLen; + Msg.Cmd.Option = Option; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlDeviceSetCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; +} +#endif + + +/****************************************************************************** +_SlDrvDeviceEventHandler - handles internally device async events +******************************************************************************/ +void _SlDrvDeviceEventHandler(void* pArgs) +{ + _SlResponseHeader_t *pHdr = (_SlResponseHeader_t *)pArgs; + + switch(pHdr->GenHeader.Opcode) + { + case SL_OPCODE_DEVICE_INITCOMPLETE: + _sl_HandleAsync_InitComplete(pHdr); + break; + case SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE: + _sl_HandleAsync_Stop(pHdr); + break; + + + case SL_OPCODE_DEVICE_ABORT: + { +#if defined (sl_GeneralEvtHdlr) || defined(EXT_LIB_REGISTERED_GENERAL_EVENTS) + SlDeviceEvent_t devHandler; + devHandler.Event = SL_DEVICE_ABORT_ERROR_EVENT; + devHandler.EventData.deviceReport.AbortType = *((_u32*)pArgs + 2); + devHandler.EventData.deviceReport.AbortData = *((_u32*)pArgs + 3); + _SlDrvHandleGeneralEvents(&devHandler); +#endif + } + break; + + case SL_OPCODE_DEVICE_DEVICEASYNCFATALERROR: +#if defined (sl_GeneralEvtHdlr) || defined(EXT_LIB_REGISTERED_GENERAL_EVENTS) + { + _BasicResponse_t *pMsgArgs = (_BasicResponse_t *)_SL_RESP_ARGS_START(pHdr); + SlDeviceEvent_t devHandler; + devHandler.Event = SL_DEVICE_FATAL_ERROR_EVENT; + devHandler.EventData.deviceEvent.status = pMsgArgs->status & 0xFF; + devHandler.EventData.deviceEvent.sender = (SlErrorSender_e)((pMsgArgs->status >> 8) & 0xFF); + _SlDrvHandleGeneralEvents(&devHandler); + } +#endif + break; + default: + SL_ERROR_TRACE2(MSG_306, "ASSERT: _SlDrvDeviceEventHandler : invalid opcode = 0x%x = %1", pHdr->GenHeader.Opcode, pHdr->GenHeader.Opcode); + } +} + + +/****************************************************************************** +sl_UartSetMode +******************************************************************************/ +#ifdef SL_IF_TYPE_UART +typedef union +{ + _DevUartSetModeCommand_t Cmd; + _DevUartSetModeResponse_t Rsp; +}_SlUartSetModeMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_UartSetMode) + + +const _SlCmdCtrl_t _SlUartSetModeCmdCtrl = +{ + SL_OPCODE_DEVICE_SETUARTMODECOMMAND, + sizeof(_DevUartSetModeCommand_t), + sizeof(_DevUartSetModeResponse_t) +}; + +_i16 sl_UartSetMode(const SlUartIfParams_t* pUartParams) +{ + _SlUartSetModeMsg_u Msg; + _u32 magicCode = 0xFFFFFFFF; + + Msg.Cmd.BaudRate = pUartParams->BaudRate; + Msg.Cmd.FlowControlEnable = pUartParams->FlowControlEnable; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlUartSetModeCmdCtrl, &Msg, NULL)); + + /* cmd response OK, we can continue with the handshake */ + if (SL_RET_CODE_OK == Msg.Rsp.status) + { + sl_IfMaskIntHdlr(); + + /* Close the comm port */ + sl_IfClose(g_pCB->FD); + + /* Re-open the comm port */ + sl_IfOpen((void * )pUartParams, UART_IF_OPEN_FLAG_RE_OPEN); + + sl_IfUnMaskIntHdlr(); + + /* send the magic code and wait for the response */ + sl_IfWrite(g_pCB->FD, (_u8* )&magicCode, 4); + + magicCode = UART_SET_MODE_MAGIC_CODE; + sl_IfWrite(g_pCB->FD, (_u8* )&magicCode, 4); + + /* clear magic code */ + magicCode = 0; + + /* wait (blocking) till the magic code to be returned from device */ + sl_IfRead(g_pCB->FD, (_u8* )&magicCode, 4); + + /* check for the received magic code matching */ + if (UART_SET_MODE_MAGIC_CODE != magicCode) + { + _SL_ASSERT(0); + } + } + + return (_i16)Msg.Rsp.status; +} +#endif +#endif + + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/driver.c b/src/openmv/src/micropython/drivers/cc3100/src/driver.c new file mode 100755 index 0000000..817ff0e --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/driver.c @@ -0,0 +1,1843 @@ +/* +* driver.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" +#include "flowcont.h" + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ + +#define _SL_PENDING_RX_MSG(pDriverCB) (RxIrqCnt != (pDriverCB)->RxDoneCnt) + +/* 2 LSB of the N2H_SYNC_PATTERN are for sequence number +only in SPI interface +support backward sync pattern */ +#define N2H_SYNC_PATTERN_SEQ_NUM_BITS ((_u32)0x00000003) /* Bits 0..1 - use the 2 LBS for seq num */ +#define N2H_SYNC_PATTERN_SEQ_NUM_EXISTS ((_u32)0x00000004) /* Bit 2 - sign that sequence number exists in the sync pattern */ +#define N2H_SYNC_PATTERN_MASK ((_u32)0xFFFFFFF8) /* Bits 3..31 - constant SYNC PATTERN */ +#define N2H_SYNC_SPI_BUGS_MASK ((_u32)0x7FFF7F7F) /* Bits 7,15,31 - ignore the SPI (8,16,32 bites bus) error bits */ +#define BUF_SYNC_SPIM(pBuf) ((*(_u32 *)(pBuf)) & N2H_SYNC_SPI_BUGS_MASK) + +_u8 _SlDrvProtectAsyncRespSetting(_u8 *pAsyncRsp, _u8 ActionID, _u8 SocketID); +#define N2H_SYNC_SPIM (N2H_SYNC_PATTERN & N2H_SYNC_SPI_BUGS_MASK) +#define N2H_SYNC_SPIM_WITH_SEQ(TxSeqNum) ((N2H_SYNC_SPIM & N2H_SYNC_PATTERN_MASK) | N2H_SYNC_PATTERN_SEQ_NUM_EXISTS | ((TxSeqNum) & (N2H_SYNC_PATTERN_SEQ_NUM_BITS))) +#define MATCH_WOUT_SEQ_NUM(pBuf) ( BUF_SYNC_SPIM(pBuf) == N2H_SYNC_SPIM ) +#define MATCH_WITH_SEQ_NUM(pBuf, TxSeqNum) ( BUF_SYNC_SPIM(pBuf) == (N2H_SYNC_SPIM_WITH_SEQ(TxSeqNum)) ) +#define N2H_SYNC_PATTERN_MATCH(pBuf, TxSeqNum) \ + ( \ + ( (*((_u32 *)pBuf) & N2H_SYNC_PATTERN_SEQ_NUM_EXISTS) && ( MATCH_WITH_SEQ_NUM(pBuf, TxSeqNum) ) ) || \ + ( !(*((_u32 *)pBuf) & N2H_SYNC_PATTERN_SEQ_NUM_EXISTS) && ( MATCH_WOUT_SEQ_NUM(pBuf ) ) ) \ + ) + +#define OPCODE(_ptr) (((_SlResponseHeader_t *)(_ptr))->GenHeader.Opcode) +#define RSP_PAYLOAD_LEN(_ptr) (((_SlResponseHeader_t *)(_ptr))->GenHeader.Len - _SL_RESP_SPEC_HDR_SIZE) +#define SD(_ptr) (((_SocketAddrResponse_u *)(_ptr))->IpV4.sd) +/* Actual size of Recv/Recvfrom response data */ +#define ACT_DATA_SIZE(_ptr) (((_SocketAddrResponse_u *)(_ptr))->IpV4.statusOrLen) + + + + +/* General Events handling*/ +#if defined (EXT_LIB_REGISTERED_GENERAL_EVENTS) + +typedef _SlEventPropogationStatus_e (*general_callback) (SlDeviceEvent_t *); + +static const general_callback general_callbacks[] = +{ +#ifdef SlExtLib1GeneralEventHandler + SlExtLib1GeneralEventHandler, +#endif + +#ifdef SlExtLib2GeneralEventHandler + SlExtLib2GeneralEventHandler, +#endif + +#ifdef SlExtLib3GeneralEventHandler + SlExtLib3GeneralEventHandler, +#endif + +#ifdef SlExtLib4GeneralEventHandler + SlExtLib4GeneralEventHandler, +#endif + +#ifdef SlExtLib5GeneralEventHandler + SlExtLib5GeneralEventHandler, +#endif +}; + +#undef _SlDrvHandleGeneralEvents + +/******************************************************************** + _SlDrvHandleGeneralEvents + Iterates through all the general(device) event handlers which are + registered by the external libs/user application. +*********************************************************************/ +void _SlDrvHandleGeneralEvents(SlDeviceEvent_t *slGeneralEvent) +{ + _u8 i; + + /* Iterate over all the extenal libs handlers */ + for ( i = 0 ; i < sizeof(general_callbacks)/sizeof(general_callbacks[0]) ; i++ ) + { + if (EVENT_PROPAGATION_BLOCK == general_callbacks[i](slGeneralEvent) ) + { + /* exit immediately and do not call the user specific handler as well */ + return; + } + } + +/* At last call the Application specific handler if registered */ +#ifdef sl_GeneralEvtHdlr + sl_GeneralEvtHdlr(slGeneralEvent); +#endif + +} +#endif + + + +/* WLAN Events handling*/ + +#if defined (EXT_LIB_REGISTERED_WLAN_EVENTS) + +typedef _SlEventPropogationStatus_e (*wlan_callback) (SlWlanEvent_t *); + +static wlan_callback wlan_callbacks[] = +{ +#ifdef SlExtLib1WlanEventHandler + SlExtLib1WlanEventHandler, +#endif + +#ifdef SlExtLib2WlanEventHandler + SlExtLib2WlanEventHandler, +#endif + +#ifdef SlExtLib3WlanEventHandler + SlExtLib3WlanEventHandler, +#endif + +#ifdef SlExtLib4WlanEventHandler + SlExtLib4WlanEventHandler, +#endif + +#ifdef SlExtLib5WlanEventHandler + SlExtLib5WlanEventHandler, +#endif +}; + +#undef _SlDrvHandleWlanEvents + +/*********************************************************** + _SlDrvHandleWlanEvents + Iterates through all the wlan event handlers which are + registered by the external libs/user application. +************************************************************/ +void _SlDrvHandleWlanEvents(SlWlanEvent_t *slWlanEvent) +{ + _u8 i; + + /* Iterate over all the extenal libs handlers */ + for ( i = 0 ; i < sizeof(wlan_callbacks)/sizeof(wlan_callbacks[0]) ; i++ ) + { + if ( EVENT_PROPAGATION_BLOCK == wlan_callbacks[i](slWlanEvent) ) + { + /* exit immediately and do not call the user specific handler as well */ + return; + } + } + +/* At last call the Application specific handler if registered */ +#ifdef sl_WlanEvtHdlr + sl_WlanEvtHdlr(slWlanEvent); +#endif + +} +#endif + + +/* NetApp Events handling */ +#if defined (EXT_LIB_REGISTERED_NETAPP_EVENTS) + +typedef _SlEventPropogationStatus_e (*netApp_callback) (SlNetAppEvent_t *); + +static const netApp_callback netApp_callbacks[] = +{ +#ifdef SlExtLib1NetAppEventHandler + SlExtLib1NetAppEventHandler, +#endif + +#ifdef SlExtLib2NetAppEventHandler + SlExtLib2NetAppEventHandler, +#endif + +#ifdef SlExtLib3NetAppEventHandler + SlExtLib3NetAppEventHandler, +#endif + +#ifdef SlExtLib4NetAppEventHandler + SlExtLib4NetAppEventHandler, +#endif + +#ifdef SlExtLib5NetAppEventHandler + SlExtLib5NetAppEventHandler, +#endif +}; + +#undef _SlDrvHandleNetAppEvents + +/************************************************************ + _SlDrvHandleNetAppEvents + Iterates through all the net app event handlers which are + registered by the external libs/user application. +************************************************************/ +void _SlDrvHandleNetAppEvents(SlNetAppEvent_t *slNetAppEvent) +{ + _u8 i; + + /* Iterate over all the extenal libs handlers */ + for ( i = 0 ; i < sizeof(netApp_callbacks)/sizeof(netApp_callbacks[0]) ; i++ ) + { + if (EVENT_PROPAGATION_BLOCK == netApp_callbacks[i](slNetAppEvent) ) + { + /* exit immediately and do not call the user specific handler as well */ + return; + } + } + +/* At last call the Application specific handler if registered */ +#ifdef sl_NetAppEvtHdlr + sl_NetAppEvtHdlr(slNetAppEvent); +#endif + +} +#endif + + +/* Http Server Events handling */ +#if defined (EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) + +typedef _SlEventPropogationStatus_e (*httpServer_callback) (SlHttpServerEvent_t*, SlHttpServerResponse_t*); + +static const httpServer_callback httpServer_callbacks[] = +{ +#ifdef SlExtLib1HttpServerEventHandler + SlExtLib1HttpServerEventHandler, +#endif + +#ifdef SlExtLib2HttpServerEventHandler + SlExtLib2HttpServerEventHandler, +#endif + +#ifdef SlExtLib3HttpServerEventHandler + SlExtLib3HttpServerEventHandler, +#endif + +#ifdef SlExtLib4HttpServerEventHandler + SlExtLib4HttpServerEventHandler, +#endif + +#ifdef SlExtLib5HttpServerEventHandler + SlExtLib5HttpServerEventHandler, +#endif +}; + +#undef _SlDrvHandleHttpServerEvents + +/******************************************************************* + _SlDrvHandleHttpServerEvents + Iterates through all the http server event handlers which are + registered by the external libs/user application. +********************************************************************/ +void _SlDrvHandleHttpServerEvents(SlHttpServerEvent_t *slHttpServerEvent, SlHttpServerResponse_t *slHttpServerResponse) +{ + _u8 i; + + /* Iterate over all the external libs handlers */ + for ( i = 0 ; i < sizeof(httpServer_callbacks)/sizeof(httpServer_callbacks[0]) ; i++ ) + { + if ( EVENT_PROPAGATION_BLOCK == httpServer_callbacks[i](slHttpServerEvent, slHttpServerResponse) ) + { + /* exit immediately and do not call the user specific handler as well */ + return; + } + } + +/* At last call the Application specific handler if registered */ +#ifdef sl_HttpServerCallback + sl_HttpServerCallback(slHttpServerEvent, slHttpServerResponse); +#endif + +} +#endif + + +/* Socket Events */ +#if defined (EXT_LIB_REGISTERED_SOCK_EVENTS) + +typedef _SlEventPropogationStatus_e (*sock_callback) (SlSockEvent_t *); + +static const sock_callback sock_callbacks[] = +{ +#ifdef SlExtLib1SockEventHandler + SlExtLib1SockEventHandler, +#endif + +#ifdef SlExtLib2SockEventHandler + SlExtLib2SockEventHandler, +#endif + +#ifdef SlExtLib3SockEventHandler + SlExtLib3SockEventHandler, +#endif + +#ifdef SlExtLib4SockEventHandler + SlExtLib4SockEventHandler, +#endif + +#ifdef SlExtLib5SockEventHandler + SlExtLib5SockEventHandler, +#endif +}; + +/************************************************************* + _SlDrvHandleSockEvents + Iterates through all the socket event handlers which are + registered by the external libs/user application. +**************************************************************/ +void _SlDrvHandleSockEvents(SlSockEvent_t *slSockEvent) +{ + _u8 i; + + /* Iterate over all the external libs handlers */ + for ( i = 0 ; i < sizeof(sock_callbacks)/sizeof(sock_callbacks[0]) ; i++ ) + { + if ( EVENT_PROPAGATION_BLOCK == sock_callbacks[i](slSockEvent) ) + { + /* exit immediately and do not call the user specific handler as well */ + return; + } + } + +/* At last call the Application specific handler if registered */ +#ifdef sl_SockEvtHdlr + sl_SockEvtHdlr(slSockEvent); +#endif + +} + +#endif + + +#if (SL_MEMORY_MGMT != SL_MEMORY_MGMT_DYNAMIC) +typedef struct +{ + _u32 Align; + _SlDriverCb_t DriverCB; + _u8 AsyncRespBuf[SL_ASYNC_MAX_MSG_LEN]; +}_SlStatMem_t; + +_SlStatMem_t g_StatMem; +#endif + +_u8 _SlDrvProtectAsyncRespSetting(_u8 *pAsyncRsp, _u8 ActionID, _u8 SocketID) +{ + _u8 ObjIdx; + + + /* Use Obj to issue the command, if not available try later */ + ObjIdx = _SlDrvWaitForPoolObj(ActionID, SocketID); + + if (MAX_CONCURRENT_ACTIONS != ObjIdx) + { + _SlDrvProtectionObjLockWaitForever(); + g_pCB->ObjPool[ObjIdx].pRespArgs = pAsyncRsp; + _SlDrvProtectionObjUnLock(); + } + + return ObjIdx; +} + + +/*****************************************************************************/ +/* Variables */ +/*****************************************************************************/ +const _SlSyncPattern_t g_H2NSyncPattern = H2N_SYNC_PATTERN; +const _SlSyncPattern_t g_H2NCnysPattern = H2N_CNYS_PATTERN; +_volatile _u8 RxIrqCnt; + +#ifndef SL_TINY_EXT +const _SlActionLookup_t _SlActionLookupTable[] = +{ + {ACCEPT_ID, SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE, (_SlSpawnEntryFunc_t)_sl_HandleAsync_Accept}, + {CONNECT_ID, SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Connect}, + {SELECT_ID, SL_OPCODE_SOCKET_SELECTASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Select}, + {GETHOSYBYNAME_ID, SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_DnsGetHostByName}, + {GETHOSYBYSERVICE_ID, SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_DnsGetHostByService}, + {PING_ID, SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE, (_SlSpawnEntryFunc_t)_sl_HandleAsync_PingResponse}, + {START_STOP_ID, SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Stop} +}; +#else +const _SlActionLookup_t _SlActionLookupTable[] = +{ + {CONNECT_ID, SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Connect}, + {GETHOSYBYNAME_ID, SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_DnsGetHostByName}, + {START_STOP_ID, SL_OPCODE_DEVICE_STOP_ASYNC_RESPONSE,(_SlSpawnEntryFunc_t)_sl_HandleAsync_Stop} +}; +#endif + + + +typedef struct +{ + _u16 opcode; + _u8 event; +} OpcodeKeyVal_t; + +/* The table translates opcode to user's event type */ +const OpcodeKeyVal_t OpcodeTranslateTable[] = +{ +{SL_OPCODE_WLAN_SMART_CONFIG_START_ASYNC_RESPONSE, SL_WLAN_SMART_CONFIG_COMPLETE_EVENT}, +{SL_OPCODE_WLAN_SMART_CONFIG_STOP_ASYNC_RESPONSE,SL_WLAN_SMART_CONFIG_STOP_EVENT}, +{SL_OPCODE_WLAN_STA_CONNECTED, SL_WLAN_STA_CONNECTED_EVENT}, +{SL_OPCODE_WLAN_STA_DISCONNECTED,SL_WLAN_STA_DISCONNECTED_EVENT}, +{SL_OPCODE_WLAN_P2P_DEV_FOUND,SL_WLAN_P2P_DEV_FOUND_EVENT}, +{SL_OPCODE_WLAN_P2P_NEG_REQ_RECEIVED, SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT}, +{SL_OPCODE_WLAN_CONNECTION_FAILED, SL_WLAN_CONNECTION_FAILED_EVENT}, +{SL_OPCODE_WLAN_WLANASYNCCONNECTEDRESPONSE, SL_WLAN_CONNECT_EVENT}, +{SL_OPCODE_WLAN_WLANASYNCDISCONNECTEDRESPONSE, SL_WLAN_DISCONNECT_EVENT}, +{SL_OPCODE_NETAPP_IPACQUIRED, SL_NETAPP_IPV4_IPACQUIRED_EVENT}, +{SL_OPCODE_NETAPP_IPACQUIRED_V6, SL_NETAPP_IPV6_IPACQUIRED_EVENT}, +{SL_OPCODE_NETAPP_IP_LEASED, SL_NETAPP_IP_LEASED_EVENT}, +{SL_OPCODE_NETAPP_IP_RELEASED, SL_NETAPP_IP_RELEASED_EVENT}, +{SL_OPCODE_SOCKET_TXFAILEDASYNCRESPONSE, SL_SOCKET_TX_FAILED_EVENT}, +{SL_OPCODE_SOCKET_SOCKETASYNCEVENT, SL_SOCKET_ASYNC_EVENT} +}; + + + +_SlDriverCb_t* g_pCB = NULL; +P_SL_DEV_PING_CALLBACK pPingCallBackFunc = NULL; +_u8 gFirstCmdMode = 0; + +/*****************************************************************************/ +/* Function prototypes */ +/*****************************************************************************/ +_SlReturnVal_t _SlDrvMsgRead(void); +_SlReturnVal_t _SlDrvMsgWrite(_SlCmdCtrl_t *pCmdCtrl,_SlCmdExt_t *pCmdExt, _u8 *pTxRxDescBuff); +_SlReturnVal_t _SlDrvMsgReadCmdCtx(void); +_SlReturnVal_t _SlDrvMsgReadSpawnCtx(void *pValue); +void _SlDrvClassifyRxMsg(_SlOpcode_t Opcode ); +_SlReturnVal_t _SlDrvRxHdrRead(_u8 *pBuf, _u8 *pAlignSize); +void _SlDrvShiftDWord(_u8 *pBuf); +void _SlDrvDriverCBInit(void); +void _SlAsyncEventGenericHandler(void); +_u8 _SlDrvWaitForPoolObj(_u8 ActionID, _u8 SocketID); +void _SlDrvReleasePoolObj(_u8 pObj); +void _SlRemoveFromList(_u8* ListIndex, _u8 ItemIndex); +_SlReturnVal_t _SlFindAndSetActiveObj(_SlOpcode_t Opcode, _u8 Sd); + + +/*****************************************************************************/ +/* Internal functions */ +/*****************************************************************************/ + + +/***************************************************************************** +_SlDrvDriverCBInit - init Driver Control Block +*****************************************************************************/ + +void _SlDrvDriverCBInit(void) +{ + _u8 Idx =0; + +#if (SL_MEMORY_MGMT == SL_MEMORY_MGMT_DYNAMIC) + g_pCB = sl_Malloc(sizeof(_SlDriverCb_t)); +#else + g_pCB = &(g_StatMem.DriverCB); +#endif + MALLOC_OK_CHECK(g_pCB); + + + _SlDrvMemZero(g_pCB, sizeof(_SlDriverCb_t)); + RxIrqCnt = 0; + OSI_RET_OK_CHECK( sl_SyncObjCreate(&g_pCB->CmdSyncObj, "CmdSyncObj") ); + sl_SyncObjClear(&g_pCB->CmdSyncObj); + + OSI_RET_OK_CHECK( sl_LockObjCreate(&g_pCB->GlobalLockObj, "GlobalLockObj") ); + OSI_RET_OK_CHECK( sl_LockObjCreate(&g_pCB->ProtectionLockObj, "ProtectionLockObj") ); + + /* Init Drv object */ + _SlDrvMemZero(&g_pCB->ObjPool[0], MAX_CONCURRENT_ACTIONS*sizeof(_SlPoolObj_t)); + + /* place all Obj in the free list*/ + g_pCB->FreePoolIdx = 0; + + for (Idx = 0 ; Idx < MAX_CONCURRENT_ACTIONS ; Idx++) + { + g_pCB->ObjPool[Idx].NextIndex = Idx + 1; + g_pCB->ObjPool[Idx].AdditionalData = SL_MAX_SOCKETS; + + OSI_RET_OK_CHECK( sl_SyncObjCreate(&g_pCB->ObjPool[Idx].SyncObj, "SyncObj")); + sl_SyncObjClear(&g_pCB->ObjPool[Idx].SyncObj); + } + + g_pCB->ActivePoolIdx = MAX_CONCURRENT_ACTIONS; + g_pCB->PendingPoolIdx = MAX_CONCURRENT_ACTIONS; + + /* Flow control init */ + g_pCB->FlowContCB.TxPoolCnt = FLOW_CONT_MIN; + OSI_RET_OK_CHECK(sl_LockObjCreate(&g_pCB->FlowContCB.TxLockObj, "TxLockObj")); + OSI_RET_OK_CHECK(sl_SyncObjCreate(&g_pCB->FlowContCB.TxSyncObj, "TxSyncObj")); + + gFirstCmdMode = 0; + +} + +/***************************************************************************** +_SlDrvDriverCBDeinit - De init Driver Control Block +*****************************************************************************/ +void _SlDrvDriverCBDeinit() +{ + _u8 Idx =0; + + /* Flow control de-init */ + g_pCB->FlowContCB.TxPoolCnt = 0; + OSI_RET_OK_CHECK(sl_LockObjDelete(&g_pCB->FlowContCB.TxLockObj)); + OSI_RET_OK_CHECK(sl_SyncObjDelete(&g_pCB->FlowContCB.TxSyncObj)); + + OSI_RET_OK_CHECK( sl_SyncObjDelete(&g_pCB->CmdSyncObj) ); + OSI_RET_OK_CHECK( sl_LockObjDelete(&g_pCB->GlobalLockObj) ); + OSI_RET_OK_CHECK( sl_LockObjDelete(&g_pCB->ProtectionLockObj) ); + + #ifndef SL_TINY_EXT + for (Idx = 0; Idx < MAX_CONCURRENT_ACTIONS; Idx++) + #endif + { + OSI_RET_OK_CHECK( sl_SyncObjDelete(&g_pCB->ObjPool[Idx].SyncObj) ); + } + + g_pCB->FreePoolIdx = 0; + g_pCB->PendingPoolIdx = MAX_CONCURRENT_ACTIONS; + g_pCB->ActivePoolIdx = MAX_CONCURRENT_ACTIONS; + +#if (SL_MEMORY_MGMT == SL_MEMORY_MGMT_DYNAMIC) + sl_Free(g_pCB); +#else + g_pCB = NULL; +#endif + + + g_pCB = NULL; +} + +/***************************************************************************** +_SlDrvRxIrqHandler - Interrupt handler +*****************************************************************************/ +void _SlDrvRxIrqHandler(void *pValue) +{ + sl_IfMaskIntHdlr(); + + RxIrqCnt++; + + if (TRUE == g_pCB->IsCmdRespWaited) + { + OSI_RET_OK_CHECK( sl_SyncObjSignalFromIRQ(&g_pCB->CmdSyncObj) ); + } + else + { + sl_Spawn((_SlSpawnEntryFunc_t)_SlDrvMsgReadSpawnCtx, NULL, 0); + } +} + +/***************************************************************************** +_SlDrvCmdOp +*****************************************************************************/ +_SlReturnVal_t _SlDrvCmdOp( + _SlCmdCtrl_t *pCmdCtrl , + void *pTxRxDescBuff , + _SlCmdExt_t *pCmdExt) +{ + _SlReturnVal_t RetVal; + + + _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj); + + g_pCB->IsCmdRespWaited = TRUE; + + SL_TRACE0(DBG_MSG, MSG_312, "_SlDrvCmdOp: call _SlDrvMsgWrite"); + + + /* send the message */ + RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, pTxRxDescBuff); + + if(SL_OS_RET_CODE_OK == RetVal) + { + +#ifndef SL_IF_TYPE_UART + /* Waiting for SPI to stabilize after first command */ + if( 0 == gFirstCmdMode ) + { + volatile _u32 CountVal = 0; + gFirstCmdMode = 1; + CountVal = CPU_FREQ_IN_MHZ*USEC_DELAY; + while( CountVal-- ); + } +#endif + /* wait for respond */ + RetVal = _SlDrvMsgReadCmdCtx(); /* will free global lock */ + SL_TRACE0(DBG_MSG, MSG_314, "_SlDrvCmdOp: exited _SlDrvMsgReadCmdCtx"); + } + else + { + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + } + + return RetVal; +} + + + +/***************************************************************************** +_SlDrvDataReadOp +*****************************************************************************/ +_SlReturnVal_t _SlDrvDataReadOp( + _SlSd_t Sd, + _SlCmdCtrl_t *pCmdCtrl , + void *pTxRxDescBuff , + _SlCmdExt_t *pCmdExt) +{ + _SlReturnVal_t RetVal; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + _SlArgsData_t pArgsData; + + /* Validate input arguments */ + VERIFY_PROTOCOL(NULL != pCmdExt->pRxPayload); + + /* If zero bytes is requested, return error. */ + /* This allows us not to fill remote socket's IP address in return arguments */ + VERIFY_PROTOCOL(0 != pCmdExt->RxPayloadLen); + + /* Validate socket */ + if((Sd & BSD_SOCKET_ID_MASK) >= SL_MAX_SOCKETS) + { + return SL_EBADF; + } + + /*Use Obj to issue the command, if not available try later*/ + ObjIdx = (_u8)_SlDrvWaitForPoolObj(RECV_ID, Sd & BSD_SOCKET_ID_MASK); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + _SlDrvProtectionObjLockWaitForever(); + + pArgsData.pData = pCmdExt->pRxPayload; + pArgsData.pArgs = (_u8 *)pTxRxDescBuff; + g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&pArgsData; + + _SlDrvProtectionObjUnLock(); + + + /* Do Flow Control check/update for DataWrite operation */ + _SlDrvObjLockWaitForever(&g_pCB->FlowContCB.TxLockObj); + + + /* Clear SyncObj for the case it was signalled before TxPoolCnt */ + /* dropped below '1' (last Data buffer was taken) */ + /* OSI_RET_OK_CHECK( sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj) ); */ + sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj); + + if(g_pCB->FlowContCB.TxPoolCnt <= FLOW_CONT_MIN) + { + + /* If TxPoolCnt was increased by other thread at this moment, + TxSyncObj won't wait here */ + _SlDrvSyncObjWaitForever(&g_pCB->FlowContCB.TxSyncObj); + + } + + _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj); + + + VERIFY_PROTOCOL(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN); + g_pCB->FlowContCB.TxPoolCnt--; + + _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj); + + /* send the message */ + RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, (_u8 *)pTxRxDescBuff); + + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + + + if(SL_OS_RET_CODE_OK == RetVal) + { + /* Wait for response message. Will be signaled by _SlDrvMsgRead. */ + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + } + + _SlDrvReleasePoolObj(ObjIdx); + return RetVal; +} + +/* ******************************************************************************/ +/* _SlDrvDataWriteOp */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvDataWriteOp( + _SlSd_t Sd, + _SlCmdCtrl_t *pCmdCtrl , + void *pTxRxDescBuff , + _SlCmdExt_t *pCmdExt) +{ + _SlReturnVal_t RetVal = SL_EAGAIN; /* initiated as SL_EAGAIN for the non blocking mode */ + while( 1 ) + { + /* Do Flow Control check/update for DataWrite operation */ + _SlDrvObjLockWaitForever(&g_pCB->FlowContCB.TxLockObj); + + /* Clear SyncObj for the case it was signalled before TxPoolCnt */ + /* dropped below '1' (last Data buffer was taken) */ + /* OSI_RET_OK_CHECK( sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj) ); */ + sl_SyncObjClear(&g_pCB->FlowContCB.TxSyncObj); + + /* we have indication that the last send has failed - socket is no longer valid for operations */ + if(g_pCB->SocketTXFailure & (1<<(Sd & BSD_SOCKET_ID_MASK))) + { + _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj); + return SL_SOC_ERROR; + } + if(g_pCB->FlowContCB.TxPoolCnt <= FLOW_CONT_MIN + 1) + { + /* we have indication that this socket is set as blocking and we try to */ + /* unblock it - return an error */ + if( g_pCB->SocketNonBlocking & (1<< (Sd & BSD_SOCKET_ID_MASK))) + { + _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj); + return RetVal; + } + /* If TxPoolCnt was increased by other thread at this moment, */ + /* TxSyncObj won't wait here */ + _SlDrvSyncObjWaitForever(&g_pCB->FlowContCB.TxSyncObj); + } + if(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN + 1 ) + { + break; + } + else + { + _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj); + } + } + + _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj); + + + VERIFY_PROTOCOL(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN + 1 ); + g_pCB->FlowContCB.TxPoolCnt--; + + _SlDrvObjUnLock(&g_pCB->FlowContCB.TxLockObj); + + /* send the message */ + RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, pTxRxDescBuff); + + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + + return RetVal; +} + +/* ******************************************************************************/ +/* _SlDrvMsgWrite */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvMsgWrite(_SlCmdCtrl_t *pCmdCtrl,_SlCmdExt_t *pCmdExt, _u8 *pTxRxDescBuff) +{ + _u8 sendRxPayload = FALSE; + VERIFY_PROTOCOL(NULL != pCmdCtrl); + + g_pCB->FunctionParams.pCmdCtrl = pCmdCtrl; + g_pCB->FunctionParams.pTxRxDescBuff = pTxRxDescBuff; + g_pCB->FunctionParams.pCmdExt = pCmdExt; + + g_pCB->TempProtocolHeader.Opcode = pCmdCtrl->Opcode; + g_pCB->TempProtocolHeader.Len = _SL_PROTOCOL_CALC_LEN(pCmdCtrl, pCmdExt); + + if (pCmdExt && pCmdExt->RxPayloadLen < 0 && pCmdExt->TxPayloadLen) + { + pCmdExt->RxPayloadLen = pCmdExt->RxPayloadLen * (-1); /* change sign */ + sendRxPayload = TRUE; + g_pCB->TempProtocolHeader.Len = g_pCB->TempProtocolHeader.Len + pCmdExt->RxPayloadLen; + } + +#ifdef SL_START_WRITE_STAT + sl_IfStartWriteSequence(g_pCB->FD); +#endif + +#ifdef SL_IF_TYPE_UART + /* Write long sync pattern */ + NWP_IF_WRITE_CHECK(g_pCB->FD, (_u8 *)&g_H2NSyncPattern.Long, 2*SYNC_PATTERN_LEN); +#else + /* Write short sync pattern */ + NWP_IF_WRITE_CHECK(g_pCB->FD, (_u8 *)&g_H2NSyncPattern.Short, SYNC_PATTERN_LEN); +#endif + + /* Header */ + NWP_IF_WRITE_CHECK(g_pCB->FD, (_u8 *)&g_pCB->TempProtocolHeader, _SL_CMD_HDR_SIZE); + + /* Descriptors */ + if (pTxRxDescBuff && pCmdCtrl->TxDescLen > 0) + { + NWP_IF_WRITE_CHECK(g_pCB->FD, pTxRxDescBuff, + _SL_PROTOCOL_ALIGN_SIZE(pCmdCtrl->TxDescLen)); + } + + /* A special mode where Rx payload and Rx length are used as Tx as well */ + /* This mode requires no Rx payload on the response and currently used by fs_Close and sl_Send on */ + /* transceiver mode */ + if (sendRxPayload == TRUE ) + { + NWP_IF_WRITE_CHECK(g_pCB->FD, pCmdExt->pRxPayload, + _SL_PROTOCOL_ALIGN_SIZE(pCmdExt->RxPayloadLen)); + } + + /* Payload */ + if (pCmdExt && pCmdExt->TxPayloadLen > 0) + { + /* If the message has payload, it is mandatory that the message's arguments are protocol aligned. */ + /* Otherwise the aligning of arguments will create a gap between arguments and payload. */ + VERIFY_PROTOCOL(_SL_IS_PROTOCOL_ALIGNED_SIZE(pCmdCtrl->TxDescLen)); + + NWP_IF_WRITE_CHECK(g_pCB->FD, pCmdExt->pTxPayload, + _SL_PROTOCOL_ALIGN_SIZE(pCmdExt->TxPayloadLen)); + } + + + _SL_DBG_CNT_INC(MsgCnt.Write); + +#ifdef SL_START_WRITE_STAT + sl_IfEndWriteSequence(g_pCB->FD); +#endif + + return SL_OS_RET_CODE_OK; +} + +/* ******************************************************************************/ +/* _SlDrvMsgRead */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvMsgRead(void) +{ + /* alignment for small memory models */ + union + { + _u8 TempBuf[_SL_RESP_HDR_SIZE]; + _u32 DummyBuf[2]; + } uBuf; + _u8 TailBuffer[4]; + _u16 LengthToCopy; + _u16 AlignedLengthRecv; + _u8 AlignSize; + _u8 *pAsyncBuf = NULL; + _u16 OpCode; + _u16 RespPayloadLen; + _u8 sd = SL_MAX_SOCKETS; + _SlRxMsgClass_e RxMsgClass; + + + /* save params in global CB */ + g_pCB->FunctionParams.AsyncExt.pAsyncBuf = NULL; + g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler= NULL; + + + VERIFY_RET_OK(_SlDrvRxHdrRead((_u8*)(uBuf.TempBuf), &AlignSize)); + + OpCode = OPCODE(uBuf.TempBuf); + RespPayloadLen = RSP_PAYLOAD_LEN(uBuf.TempBuf); + + + /* 'Init Compelete' message bears no valid FlowControl info */ + if(SL_OPCODE_DEVICE_INITCOMPLETE != OpCode) + { + g_pCB->FlowContCB.TxPoolCnt = ((_SlResponseHeader_t *)uBuf.TempBuf)->TxPoolCnt; + g_pCB->SocketNonBlocking = ((_SlResponseHeader_t *)uBuf.TempBuf)->SocketNonBlocking; + g_pCB->SocketTXFailure = ((_SlResponseHeader_t *)uBuf.TempBuf)->SocketTXFailure; + + if(g_pCB->FlowContCB.TxPoolCnt > FLOW_CONT_MIN) + { + _SlDrvSyncObjSignal(&g_pCB->FlowContCB.TxSyncObj); + } + } + + /* Find the RX messaage class and set its async event handler */ + _SlDrvClassifyRxMsg(OpCode); + + RxMsgClass = g_pCB->FunctionParams.AsyncExt.RxMsgClass; + + + switch(RxMsgClass) + { + case ASYNC_EVT_CLASS: + + VERIFY_PROTOCOL(NULL == pAsyncBuf); + +#if (SL_MEMORY_MGMT == SL_MEMORY_MGMT_DYNAMIC) + g_pCB->FunctionParams.AsyncExt.pAsyncBuf = sl_Malloc(SL_ASYNC_MAX_MSG_LEN); +#else + g_pCB->FunctionParams.AsyncExt.pAsyncBuf = g_StatMem.AsyncRespBuf; +#endif + /* set the local pointer to the allocated one */ + pAsyncBuf = g_pCB->FunctionParams.AsyncExt.pAsyncBuf; + + /* clear the async buffer */ + _SlDrvMemZero(pAsyncBuf, SL_ASYNC_MAX_MSG_LEN); + + MALLOC_OK_CHECK(pAsyncBuf); + + sl_Memcpy(pAsyncBuf, uBuf.TempBuf, _SL_RESP_HDR_SIZE); + if (_SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) <= SL_ASYNC_MAX_PAYLOAD_LEN) + { + AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen); + } + else + { + AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(SL_ASYNC_MAX_PAYLOAD_LEN); + } + if (RespPayloadLen > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD, + pAsyncBuf + _SL_RESP_HDR_SIZE, + AlignedLengthRecv); + } + /* In case ASYNC RX buffer length is smaller then the received data length, dump the rest */ + if ((_SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) > SL_ASYNC_MAX_PAYLOAD_LEN)) + { + AlignedLengthRecv = _SL_PROTOCOL_ALIGN_SIZE(RespPayloadLen) - SL_ASYNC_MAX_PAYLOAD_LEN; + while (AlignedLengthRecv > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4); + AlignedLengthRecv = AlignedLengthRecv - 4; + } + } + + _SlDrvProtectionObjLockWaitForever(); + + if ( +#ifndef SL_TINY_EXT + (SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE == OpCode) || + (SL_OPCODE_SOCKET_ACCEPTASYNCRESPONSE_V6 == OpCode) || +#endif + (SL_OPCODE_SOCKET_CONNECTASYNCRESPONSE == OpCode) + ) + { + /* go over the active list if exist to find obj waiting for this Async event */ + sd = ((((_SocketResponse_t *)(pAsyncBuf + _SL_RESP_HDR_SIZE))->sd) & BSD_SOCKET_ID_MASK); + } + _SlFindAndSetActiveObj(OpCode, sd); + + _SlDrvProtectionObjUnLock(); + + break; + case RECV_RESP_CLASS: + { + _u8 ExpArgSize; /* Expected size of Recv/Recvfrom arguments */ + + switch(OpCode) + { + case SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE: + ExpArgSize = RECVFROM_IPV4_ARGS_SIZE; + break; +#ifndef SL_TINY_EXT + case SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6: + ExpArgSize = RECVFROM_IPV6_ARGS_SIZE; + break; +#endif + default: + /* SL_OPCODE_SOCKET_RECVASYNCRESPONSE: */ + ExpArgSize = RECV_ARGS_SIZE; + } + + /* Read first 4 bytes of Recv/Recvfrom response to get SocketId and actual */ + /* response data length */ + NWP_IF_READ_CHECK(g_pCB->FD, &uBuf.TempBuf[4], RECV_ARGS_SIZE); + + /* Validate Socket ID and Received Length value. */ + VERIFY_PROTOCOL((SD(&uBuf.TempBuf[4])& BSD_SOCKET_ID_MASK) < SL_MAX_SOCKETS); + + _SlDrvProtectionObjLockWaitForever(); + + /* go over the active list if exist to find obj waiting for this Async event */ + VERIFY_RET_OK(_SlFindAndSetActiveObj(OpCode,SD(&uBuf.TempBuf[4]) & BSD_SOCKET_ID_MASK)); + + /* Verify data is waited on this socket. The pArgs should have been set by _SlDrvDataReadOp(). */ + VERIFY_SOCKET_CB(NULL != ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pData))->pArgs); + + sl_Memcpy( ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pArgs, &uBuf.TempBuf[4], RECV_ARGS_SIZE); + + if(ExpArgSize > RECV_ARGS_SIZE) + { + NWP_IF_READ_CHECK(g_pCB->FD, + ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pArgs + RECV_ARGS_SIZE, + ExpArgSize - RECV_ARGS_SIZE); + } + + /* Here g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pData contains requested(expected) Recv/Recvfrom DataSize. */ + /* Overwrite requested DataSize with actual one. */ + /* If error is received, this information will be read from arguments. */ + if(ACT_DATA_SIZE(&uBuf.TempBuf[4]) > 0) + { + VERIFY_SOCKET_CB(NULL != ((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData); + + /* Read 4 bytes aligned from interface */ + /* therefore check the requested length and read only */ + /* 4 bytes aligned data. The rest unaligned (if any) will be read */ + /* and copied to a TailBuffer */ + LengthToCopy = ACT_DATA_SIZE(&uBuf.TempBuf[4]) & (3); + AlignedLengthRecv = ACT_DATA_SIZE(&uBuf.TempBuf[4]) & (~3); + if( AlignedLengthRecv >= 4) + { + NWP_IF_READ_CHECK(g_pCB->FD,((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData,AlignedLengthRecv ); + } + /* copy the unaligned part, if any */ + if( LengthToCopy > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4); + /* copy TailBuffer unaligned part (1/2/3 bytes) */ + sl_Memcpy(((_SlArgsData_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->pData + AlignedLengthRecv,TailBuffer,LengthToCopy); + } + } + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + _SlDrvProtectionObjUnLock(); + } + break; + + case CMD_RESP_CLASS: + + /* Some commands pass a maximum arguments size. */ + /* In this case Driver will send extra dummy patterns to NWP if */ + /* the response message is smaller than maximum. */ + /* When RxDescLen is not exact, using RxPayloadLen is forbidden! */ + /* If such case cannot be avoided - parse message here to detect */ + /* arguments/payload border. */ + NWP_IF_READ_CHECK(g_pCB->FD, + g_pCB->FunctionParams.pTxRxDescBuff, + _SL_PROTOCOL_ALIGN_SIZE(g_pCB->FunctionParams.pCmdCtrl->RxDescLen)); + + if((NULL != g_pCB->FunctionParams.pCmdExt) && (0 != g_pCB->FunctionParams.pCmdExt->RxPayloadLen)) + { + /* Actual size of command's response payload: - */ + _i16 ActDataSize = RSP_PAYLOAD_LEN(uBuf.TempBuf) - g_pCB->FunctionParams.pCmdCtrl->RxDescLen; + + g_pCB->FunctionParams.pCmdExt->ActualRxPayloadLen = ActDataSize; + + /* Check that the space prepared by user for the response data is sufficient. */ + if(ActDataSize <= 0) + { + g_pCB->FunctionParams.pCmdExt->RxPayloadLen = 0; + } + else + { + /* In case the user supplied Rx buffer length which is smaller then the received data length, copy according to user length */ + if (ActDataSize > g_pCB->FunctionParams.pCmdExt->RxPayloadLen) + { + LengthToCopy = g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (3); + AlignedLengthRecv = g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (~3); + } + else + { + LengthToCopy = ActDataSize & (3); + AlignedLengthRecv = ActDataSize & (~3); + } + /* Read 4 bytes aligned from interface */ + /* therefore check the requested length and read only */ + /* 4 bytes aligned data. The rest unaligned (if any) will be read */ + /* and copied to a TailBuffer */ + + if( AlignedLengthRecv >= 4) + { + NWP_IF_READ_CHECK(g_pCB->FD, + g_pCB->FunctionParams.pCmdExt->pRxPayload, + AlignedLengthRecv ); + + } + /* copy the unaligned part, if any */ + if( LengthToCopy > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer,4); + /* copy TailBuffer unaligned part (1/2/3 bytes) */ + sl_Memcpy(g_pCB->FunctionParams.pCmdExt->pRxPayload + AlignedLengthRecv, + TailBuffer, + LengthToCopy); + ActDataSize = ActDataSize-4; + } + /* In case the user supplied Rx buffer length which is smaller then the received data length, dump the rest */ + if (ActDataSize > g_pCB->FunctionParams.pCmdExt->RxPayloadLen) + { + /* calculate the rest of the data size to dump */ + AlignedLengthRecv = ActDataSize - (g_pCB->FunctionParams.pCmdExt->RxPayloadLen & (~3)); + while( AlignedLengthRecv > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD,TailBuffer, 4 ); + AlignedLengthRecv = AlignedLengthRecv - 4; + } + } + } + } + break; + + default: + /* DUMMY_MSG_CLASS: Flow control message has no payload. */ + break; + } + + if(AlignSize > 0) + { + NWP_IF_READ_CHECK(g_pCB->FD, uBuf.TempBuf, AlignSize); + } + + _SL_DBG_CNT_INC(MsgCnt.Read); + + /* Unmask Interrupt call */ + sl_IfUnMaskIntHdlr(); + + return SL_OS_RET_CODE_OK; +} + + +/* ******************************************************************************/ +/* _SlAsyncEventGenericHandler */ +/* ******************************************************************************/ +void _SlAsyncEventGenericHandler(void) +{ + _u32 SlAsyncEvent = 0; + _u8 OpcodeFound = FALSE; + _u8 i; + + _u32* pEventLocation = NULL; /* This pointer will override the async buffer with the translated event type */ + _SlResponseHeader_t *pHdr = (_SlResponseHeader_t *)g_pCB->FunctionParams.AsyncExt.pAsyncBuf; + + + /* if no async event registered nothing to do..*/ + if (g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler == NULL) + return; + + /* Iterate through all the opcode in the table */ + for (i=0; i< (sizeof(OpcodeTranslateTable) / sizeof(OpcodeKeyVal_t)); i++) + { + if (OpcodeTranslateTable[i].opcode == pHdr->GenHeader.Opcode) + { + SlAsyncEvent = OpcodeTranslateTable[i].event; + OpcodeFound = TRUE; + break; + } + } + + /* No Async event found in the table */ + if (OpcodeFound == FALSE) + { + /* This case handles all the async events handlers of the DEVICE & SOCK Silos which are handled internally. + For these cases we send the async even buffer as is */ + g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler(g_pCB->FunctionParams.AsyncExt.pAsyncBuf); + } + else + { + /* calculate the event type location to be filled in the async buffer */ + pEventLocation = (_u32*)(g_pCB->FunctionParams.AsyncExt.pAsyncBuf + sizeof (_SlResponseHeader_t) - sizeof(SlAsyncEvent) ); + + /* Override the async buffer (before the data starts ) with our event type */ + *pEventLocation = SlAsyncEvent; + + /* call the event handler registered by the user with our async buffer which now holds + the User's event type and its related data */ + g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler(pEventLocation); + } + + +} + + +/* ******************************************************************************/ +/* _SlDrvMsgReadCmdCtx */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvMsgReadCmdCtx(void) +{ + + /* after command response is received and isCmdRespWaited */ + /* flag is set FALSE, it is necessary to read out all */ + /* Async messages in Commands context, because ssiDma_IsrHandleSignalFromSlave */ + /* could have dispatched some Async messages to g_NwpIf.CmdSyncObj */ + /* after command response but before this response has been processed */ + /* by spi_singleRead and isCmdRespWaited was set FALSE. */ + while (TRUE == g_pCB->IsCmdRespWaited) + { + if(_SL_PENDING_RX_MSG(g_pCB)) + { + VERIFY_RET_OK(_SlDrvMsgRead()); + g_pCB->RxDoneCnt++; + + if (CMD_RESP_CLASS == g_pCB->FunctionParams.AsyncExt.RxMsgClass) + { + g_pCB->IsCmdRespWaited = FALSE; + + /* In case CmdResp has been read without waiting on CmdSyncObj - that */ + /* Sync object. That to prevent old signal to be processed. */ + sl_SyncObjClear(&g_pCB->CmdSyncObj); + } + else if (ASYNC_EVT_CLASS == g_pCB->FunctionParams.AsyncExt.RxMsgClass) + { + /* If Async event has been read in CmdResp context, check whether */ + /* there is a handler for this event. If there is, spawn specific */ + /* handler. Otherwise free the event's buffer. */ + /* This way there will be no "dry shots" from CmdResp context to */ + /* temporary context, i.e less waste of CPU and faster buffer */ + /* release. */ + _SlAsyncEventGenericHandler(); + + +#if (SL_MEMORY_MGMT == SL_MEMORY_MGMT_DYNAMIC) + sl_Free(g_pCB->FunctionParams.AsyncExt.pAsyncBuf); +#else + g_pCB->FunctionParams.AsyncExt.pAsyncBuf = NULL; +#endif + } + } + else + { + /* CmdSyncObj will be signaled by IRQ */ + _SlDrvSyncObjWaitForever(&g_pCB->CmdSyncObj); + } + } + + /* If there are more pending Rx Msgs after CmdResp is received, */ + /* that means that these are Async, Dummy or Read Data Msgs. */ + /* Spawn _SlDrvMsgReadSpawnCtx to trigger reading these messages from */ + /* Temporary context. */ + /* sl_Spawn is activated, using a different context */ + + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + + if(_SL_PENDING_RX_MSG(g_pCB)) + { + sl_Spawn((_SlSpawnEntryFunc_t)_SlDrvMsgReadSpawnCtx, NULL, 0); + } + + return SL_OS_RET_CODE_OK; +} + +/* ******************************************************************************/ +/* _SlDrvMsgReadSpawnCtx */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvMsgReadSpawnCtx(void *pValue) +{ +#ifdef SL_POLLING_MODE_USED + _i16 retCode = OSI_OK; + /* for polling based systems */ + do + { + retCode = sl_LockObjLock(&g_pCB->GlobalLockObj, 0); + if ( OSI_OK != retCode ) + { + if (TRUE == g_pCB->IsCmdRespWaited) + { + _SlDrvSyncObjSignal(&g_pCB->CmdSyncObj); + return SL_RET_CODE_OK; + } + } + + } + while (OSI_OK != retCode); + +#else + _SlDrvObjLockWaitForever(&g_pCB->GlobalLockObj); +#endif + + + /* Messages might have been read by CmdResp context. Therefore after */ + /* getting LockObj, check again where the Pending Rx Msg is still present. */ + if(FALSE == (_SL_PENDING_RX_MSG(g_pCB))) + { + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + + return SL_RET_CODE_OK; + } + + VERIFY_RET_OK(_SlDrvMsgRead()); + + g_pCB->RxDoneCnt++; + + switch(g_pCB->FunctionParams.AsyncExt.RxMsgClass) + { + case ASYNC_EVT_CLASS: + /* If got here and protected by LockObj a message is waiting */ + /* to be read */ + VERIFY_PROTOCOL(NULL != g_pCB->FunctionParams.AsyncExt.pAsyncBuf); + + _SlAsyncEventGenericHandler(); + +#if (SL_MEMORY_MGMT == SL_MEMORY_MGMT_DYNAMIC) + sl_Free(g_pCB->FunctionParams.AsyncExt.pAsyncBuf); +#else + g_pCB->FunctionParams.AsyncExt.pAsyncBuf = NULL; +#endif + break; + case DUMMY_MSG_CLASS: + case RECV_RESP_CLASS: + /* These types are legal in this context. Do nothing */ + break; + case CMD_RESP_CLASS: + /* Command response is illegal in this context. */ + /* No 'break' here: Assert! */ + default: + VERIFY_PROTOCOL(0); + } + + _SlDrvObjUnLock(&g_pCB->GlobalLockObj); + + return(SL_RET_CODE_OK); +} + + + +/* + +#define SL_OPCODE_SILO_DEVICE ( 0x0 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_WLAN ( 0x1 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_SOCKET ( 0x2 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NETAPP ( 0x3 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NVMEM ( 0x4 << SL_OPCODE_SILO_OFFSET ) +#define SL_OPCODE_SILO_NETCFG ( 0x5 << SL_OPCODE_SILO_OFFSET ) + + +*/ + +/* The Lookup table below holds the event handlers to be called according to the incoming + RX message SILO type */ +const _SlSpawnEntryFunc_t RxMsgClassLUT[] = { + (_SlSpawnEntryFunc_t)_SlDrvDeviceEventHandler, /* SL_OPCODE_SILO_DEVICE */ +#if defined(sl_WlanEvtHdlr) || defined(EXT_LIB_REGISTERED_WLAN_EVENTS) + (_SlSpawnEntryFunc_t)_SlDrvHandleWlanEvents, /* SL_OPCODE_SILO_WLAN */ +#else + NULL, +#endif +#if defined (sl_SockEvtHdlr) || defined(EXT_LIB_REGISTERED_SOCK_EVENTS) + (_SlSpawnEntryFunc_t)_SlDrvHandleSockEvents, /* SL_OPCODE_SILO_SOCKET */ +#else + NULL, +#endif + +#if defined(sl_NetAppEvtHdlr) || defined(EXT_LIB_REGISTERED_NETAPP_EVENTS) + (_SlSpawnEntryFunc_t)_SlDrvHandleNetAppEvents, /* SL_OPCODE_SILO_NETAPP */ +#else + NULL, +#endif + NULL, /* SL_OPCODE_SILO_NVMEM */ + NULL, /* SL_OPCODE_SILO_NETCFG */ + NULL, + NULL +}; + + +/* ******************************************************************************/ +/* _SlDrvClassifyRxMsg */ +/* ******************************************************************************/ +void _SlDrvClassifyRxMsg( + _SlOpcode_t Opcode) +{ + _SlSpawnEntryFunc_t AsyncEvtHandler = NULL; + _SlRxMsgClass_e RxMsgClass = CMD_RESP_CLASS; + _u8 Silo; + + + if (0 == (SL_OPCODE_SYNC & Opcode)) + { /* Async event has received */ + + if (SL_OPCODE_DEVICE_DEVICEASYNCDUMMY == Opcode) + { + RxMsgClass = DUMMY_MSG_CLASS; + } + else if ( (SL_OPCODE_SOCKET_RECVASYNCRESPONSE == Opcode) || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE == Opcode) +#ifndef SL_TINY_EXT + || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6 == Opcode) +#endif + ) + { + RxMsgClass = RECV_RESP_CLASS; + } + else + { + /* This is Async Event class message */ + RxMsgClass = ASYNC_EVT_CLASS; + + /* Despite the fact that 4 bits are allocated in the SILO field, we actually have only 6 SILOs + So we can use the 8 options of SILO in look up table */ + Silo = ((Opcode >> SL_OPCODE_SILO_OFFSET) & 0x7); + + VERIFY_PROTOCOL(Silo < (sizeof(RxMsgClassLUT)/sizeof(_SlSpawnEntryFunc_t))); + + /* Set the async event hander according to the LUT */ + AsyncEvtHandler = RxMsgClassLUT[Silo]; + + if ((SL_OPCODE_NETAPP_HTTPGETTOKENVALUE == Opcode) || (SL_OPCODE_NETAPP_HTTPPOSTTOKENVALUE == Opcode)) + { + AsyncEvtHandler = _SlDrvNetAppEventHandler; + } +#ifndef SL_TINY_EXT + else if (SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE == Opcode) + { + AsyncEvtHandler = (_SlSpawnEntryFunc_t)_sl_HandleAsync_PingResponse; + } +#endif + } + } + + g_pCB->FunctionParams.AsyncExt.RxMsgClass = RxMsgClass; + g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler = AsyncEvtHandler; + +} + + +/* ******************************************************************************/ +/* _SlDrvRxHdrRead */ +/* ******************************************************************************/ +_SlReturnVal_t _SlDrvRxHdrRead(_u8 *pBuf, _u8 *pAlignSize) +{ + _u32 SyncCnt = 0; + _u8 ShiftIdx; + +#ifndef SL_IF_TYPE_UART + /* 1. Write CNYS pattern to NWP when working in SPI mode only */ + NWP_IF_WRITE_CHECK(g_pCB->FD, (_u8 *)&g_H2NCnysPattern.Short, SYNC_PATTERN_LEN); +#endif + + /* 2. Read 4 bytes (protocol aligned) */ + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], 4); + _SL_DBG_SYNC_LOG(SyncCnt,pBuf); + + /* Wait for SYNC_PATTERN_LEN from the device */ + while ( ! N2H_SYNC_PATTERN_MATCH(pBuf, g_pCB->TxSeqNum) ) + { + /* 3. Debug limit of scan */ + VERIFY_PROTOCOL(SyncCnt < SL_SYNC_SCAN_THRESHOLD); + + /* 4. Read next 4 bytes to Low 4 bytes of buffer */ + if(0 == (SyncCnt % (_u32)SYNC_PATTERN_LEN)) + { + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[4], 4); + _SL_DBG_SYNC_LOG(SyncCnt,pBuf); + } + + /* 5. Shift Buffer Up for checking if the sync is shifted */ + for(ShiftIdx = 0; ShiftIdx< 7; ShiftIdx++) + { + pBuf[ShiftIdx] = pBuf[ShiftIdx+1]; + } + pBuf[7] = 0; + + SyncCnt++; + } + + /* 5. Sync pattern found. If needed, complete number of read bytes to multiple of 4 (protocol align) */ + SyncCnt %= SYNC_PATTERN_LEN; + + if(SyncCnt > 0) + { + *(_u32 *)&pBuf[0] = *(_u32 *)&pBuf[4]; + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[SYNC_PATTERN_LEN - SyncCnt], (_u16)SyncCnt); + } + else + { + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], 4); + } + + /* 6. Scan for Double pattern. */ + while ( N2H_SYNC_PATTERN_MATCH(pBuf, g_pCB->TxSeqNum) ) + { + _SL_DBG_CNT_INC(Work.DoubleSyncPattern); + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[0], SYNC_PATTERN_LEN); + } + g_pCB->TxSeqNum++; + + /* 7. Here we've read Generic Header (4 bytes). Read the Resp Specific header (4 more bytes). */ + NWP_IF_READ_CHECK(g_pCB->FD, &pBuf[SYNC_PATTERN_LEN], _SL_RESP_SPEC_HDR_SIZE); + + /* 8. Here we've read the entire Resp Header. */ + /* Return number bytes needed to be sent after read for NWP Rx 4-byte alignment (protocol alignment) */ + *pAlignSize = (_u8)((SyncCnt > 0) ? (SYNC_PATTERN_LEN - SyncCnt) : 0); + + return SL_RET_CODE_OK; +} + +/* ***************************************************************************** */ +/* _SlDrvBasicCmd */ +/* ***************************************************************************** */ +typedef union +{ + _BasicResponse_t Rsp; +}_SlBasicCmdMsg_u; + + +#ifndef SL_TINY_EXT +_i16 _SlDrvBasicCmd(_SlOpcode_t Opcode) +{ + _SlBasicCmdMsg_u Msg = {{0, 0}}; + _SlCmdCtrl_t CmdCtrl; + + CmdCtrl.Opcode = Opcode; + CmdCtrl.TxDescLen = 0; + CmdCtrl.RxDescLen = sizeof(_BasicResponse_t); + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} + +/***************************************************************************** + _SlDrvCmdSend + Send SL command without waiting for command response + This function is unprotected and the caller should make + sure global lock is active +*****************************************************************************/ +_SlReturnVal_t _SlDrvCmdSend( + _SlCmdCtrl_t *pCmdCtrl , + void *pTxRxDescBuff , + _SlCmdExt_t *pCmdExt) +{ + _SlReturnVal_t RetVal; + _u8 IsCmdRespWaitedOriginalVal; + + _SlFunctionParams_t originalFuncParms; + + /* save the current RespWait flag before clearing it */ + IsCmdRespWaitedOriginalVal = g_pCB->IsCmdRespWaited; + + /* save the current command parameters */ + sl_Memcpy(&originalFuncParms, &g_pCB->FunctionParams, sizeof(_SlFunctionParams_t)); + + g_pCB->IsCmdRespWaited = FALSE; + + SL_TRACE0(DBG_MSG, MSG_312, "_SlDrvCmdSend: call _SlDrvMsgWrite"); + + /* send the message */ + RetVal = _SlDrvMsgWrite(pCmdCtrl, pCmdExt, pTxRxDescBuff); + + /* restore the original RespWait flag */ + g_pCB->IsCmdRespWaited = IsCmdRespWaitedOriginalVal; + + /* restore the original command parameters */ + sl_Memcpy(&g_pCB->FunctionParams, &originalFuncParms, sizeof(_SlFunctionParams_t)); + + return RetVal; + + +} +#endif + +/* ***************************************************************************** */ +/* _SlDrvWaitForPoolObj */ +/* ***************************************************************************** */ +_u8 _SlDrvWaitForPoolObj(_u8 ActionID, _u8 SocketID) +{ + _u8 CurrObjIndex = MAX_CONCURRENT_ACTIONS; + + /* Get free object */ + _SlDrvProtectionObjLockWaitForever(); + if (MAX_CONCURRENT_ACTIONS > g_pCB->FreePoolIdx) + { + /* save the current obj index */ + CurrObjIndex = g_pCB->FreePoolIdx; + /* set the new free index */ +#ifndef SL_TINY_EXT + if (MAX_CONCURRENT_ACTIONS > g_pCB->ObjPool[CurrObjIndex].NextIndex) + { + g_pCB->FreePoolIdx = g_pCB->ObjPool[CurrObjIndex].NextIndex; + } + else +#endif + { + /* No further free actions available */ + g_pCB->FreePoolIdx = MAX_CONCURRENT_ACTIONS; + } + } + else + { + _SlDrvProtectionObjUnLock(); + return CurrObjIndex; + } + g_pCB->ObjPool[CurrObjIndex].ActionID = (_u8)ActionID; + if (SL_MAX_SOCKETS > SocketID) + { + g_pCB->ObjPool[CurrObjIndex].AdditionalData = SocketID; + } +#ifndef SL_TINY_EXT + /*In case this action is socket related, SocketID bit will be on + In case SocketID is set to SL_MAX_SOCKETS, the socket is not relevant to the action. In that case ActionID bit will be on */ + while ( ( (SL_MAX_SOCKETS > SocketID) && (g_pCB->ActiveActionsBitmap & (1<ActiveActionsBitmap & (1<ObjPool[CurrObjIndex].NextIndex = g_pCB->PendingPoolIdx; + g_pCB->PendingPoolIdx = CurrObjIndex; + _SlDrvProtectionObjUnLock(); + + /* wait for action to be free */ + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[CurrObjIndex].SyncObj); + + /* set params and move to active (remove from pending list at _SlDrvReleasePoolObj) */ + _SlDrvProtectionObjLockWaitForever(); + } +#endif + /* mark as active. Set socket as active if action is on socket, otherwise mark action as active */ + if (SL_MAX_SOCKETS > SocketID) + { + g_pCB->ActiveActionsBitmap |= (1<ActiveActionsBitmap |= (1<ObjPool[CurrObjIndex].NextIndex = g_pCB->ActivePoolIdx; + g_pCB->ActivePoolIdx = CurrObjIndex; + /* unlock */ + _SlDrvProtectionObjUnLock(); + return CurrObjIndex; +} + +/* ******************************************************************************/ +/* _SlDrvReleasePoolObj */ +/* ******************************************************************************/ +void _SlDrvReleasePoolObj(_u8 ObjIdx) +{ +#ifndef SL_TINY_EXT + _u8 PendingIndex; +#endif + + _SlDrvProtectionObjLockWaitForever(); + + /* In Tiny mode, there is only one object pool so no pending actions are available */ +#ifndef SL_TINY_EXT + /* go over the pending list and release other pending action if needed */ + PendingIndex = g_pCB->PendingPoolIdx; + + while(MAX_CONCURRENT_ACTIONS > PendingIndex) + { + /* In case this action is socket related, SocketID is in use, otherwise will be set to SL_MAX_SOCKETS */ + if ( (g_pCB->ObjPool[PendingIndex].ActionID == g_pCB->ObjPool[ObjIdx].ActionID) && + ( (SL_MAX_SOCKETS == (g_pCB->ObjPool[PendingIndex].AdditionalData & BSD_SOCKET_ID_MASK)) || + ((SL_MAX_SOCKETS > (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK)) && ( (g_pCB->ObjPool[PendingIndex].AdditionalData & BSD_SOCKET_ID_MASK) == (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK) ))) ) + { + /* remove from pending list */ + _SlRemoveFromList(&g_pCB->PendingPoolIdx, PendingIndex); + _SlDrvSyncObjSignal(&g_pCB->ObjPool[PendingIndex].SyncObj); + break; + } + PendingIndex = g_pCB->ObjPool[PendingIndex].NextIndex; + } +#endif + + if (SL_MAX_SOCKETS > (g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK)) + { + /* unset socketID */ + g_pCB->ActiveActionsBitmap &= ~(1<<(g_pCB->ObjPool[ObjIdx].AdditionalData & BSD_SOCKET_ID_MASK)); + } + else + { + /* unset actionID */ + g_pCB->ActiveActionsBitmap &= ~(1<ObjPool[ObjIdx].ActionID); + } + + /* delete old data */ + g_pCB->ObjPool[ObjIdx].pRespArgs = NULL; + g_pCB->ObjPool[ObjIdx].ActionID = 0; + g_pCB->ObjPool[ObjIdx].AdditionalData = SL_MAX_SOCKETS; + + /* remove from active list */ + _SlRemoveFromList(&g_pCB->ActivePoolIdx, ObjIdx); + /* move to free list */ + g_pCB->ObjPool[ObjIdx].NextIndex = g_pCB->FreePoolIdx; + g_pCB->FreePoolIdx = ObjIdx; + _SlDrvProtectionObjUnLock(); +} + + +/* ******************************************************************************/ +/* _SlRemoveFromList */ +/* ******************************************************************************/ +void _SlRemoveFromList(_u8 *ListIndex, _u8 ItemIndex) +{ +#ifndef SL_TINY_EXT + _u8 Idx; +#endif + + if (MAX_CONCURRENT_ACTIONS == g_pCB->ObjPool[*ListIndex].NextIndex) + { + *ListIndex = MAX_CONCURRENT_ACTIONS; + } + /* As MAX_CONCURRENT_ACTIONS is equal to 1 in Tiny mode */ +#ifndef SL_TINY_EXT + /* need to remove the first item in the list and therefore update the global which holds this index */ + else if (*ListIndex == ItemIndex) + { + *ListIndex = g_pCB->ObjPool[ItemIndex].NextIndex; + } + else + { + Idx = *ListIndex; + + while(MAX_CONCURRENT_ACTIONS > Idx) + { + /* remove from list */ + if (g_pCB->ObjPool[Idx].NextIndex == ItemIndex) + { + g_pCB->ObjPool[Idx].NextIndex = g_pCB->ObjPool[ItemIndex].NextIndex; + break; + } + + Idx = g_pCB->ObjPool[Idx].NextIndex; + } + } +#endif +} + + +/* ******************************************************************************/ +/* _SlFindAndSetActiveObj */ +/* ******************************************************************************/ +_SlReturnVal_t _SlFindAndSetActiveObj(_SlOpcode_t Opcode, _u8 Sd) +{ + _u8 ActiveIndex; + + ActiveIndex = g_pCB->ActivePoolIdx; + /* go over the active list if exist to find obj waiting for this Async event */ +#ifndef SL_TINY_EXT + while (MAX_CONCURRENT_ACTIONS > ActiveIndex) +#else + /* Only one Active action is availabe in tiny mode, so we can replace the loop with if condition */ + if (MAX_CONCURRENT_ACTIONS > ActiveIndex) +#endif + { + /* unset the Ipv4\IPv6 bit in the opcode if family bit was set */ + if (g_pCB->ObjPool[ActiveIndex].AdditionalData & SL_NETAPP_FAMILY_MASK) + { + Opcode &= ~SL_OPCODE_IPV6; + } + + if ((g_pCB->ObjPool[ActiveIndex].ActionID == RECV_ID) && (Sd == g_pCB->ObjPool[ActiveIndex].AdditionalData) && + ( (SL_OPCODE_SOCKET_RECVASYNCRESPONSE == Opcode) || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE == Opcode) +#ifndef SL_TINY_EXT + || (SL_OPCODE_SOCKET_RECVFROMASYNCRESPONSE_V6 == Opcode) +#endif + ) + + ) + { + g_pCB->FunctionParams.AsyncExt.ActionIndex = ActiveIndex; + return SL_RET_CODE_OK; + } + /* In case this action is socket related, SocketID is in use, otherwise will be set to SL_MAX_SOCKETS */ + if ( (_SlActionLookupTable[ g_pCB->ObjPool[ActiveIndex].ActionID - MAX_SOCKET_ENUM_IDX].ActionAsyncOpcode == Opcode) && + ( ((Sd == (g_pCB->ObjPool[ActiveIndex].AdditionalData & BSD_SOCKET_ID_MASK) ) && (SL_MAX_SOCKETS > Sd)) || (SL_MAX_SOCKETS == (g_pCB->ObjPool[ActiveIndex].AdditionalData & BSD_SOCKET_ID_MASK)) ) ) + { + /* set handler */ + g_pCB->FunctionParams.AsyncExt.AsyncEvtHandler = _SlActionLookupTable[ g_pCB->ObjPool[ActiveIndex].ActionID - MAX_SOCKET_ENUM_IDX].AsyncEventHandler; + g_pCB->FunctionParams.AsyncExt.ActionIndex = ActiveIndex; + return SL_RET_CODE_OK; + } + ActiveIndex = g_pCB->ObjPool[ActiveIndex].NextIndex; + } + + return SL_RET_CODE_SELF_ERROR; + + + +} + + +/* Wrappers for the object functions */ + +void _SlDrvSyncObjWaitForever(_SlSyncObj_t *pSyncObj) +{ + OSI_RET_OK_CHECK(sl_SyncObjWait(pSyncObj, SL_OS_WAIT_FOREVER)); +} + +void _SlDrvSyncObjSignal(_SlSyncObj_t *pSyncObj) +{ + OSI_RET_OK_CHECK(sl_SyncObjSignal(pSyncObj)); +} + +void _SlDrvObjLockWaitForever(_SlLockObj_t *pLockObj) +{ + OSI_RET_OK_CHECK(sl_LockObjLock(pLockObj, SL_OS_WAIT_FOREVER)); +} + +void _SlDrvProtectionObjLockWaitForever() +{ + OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER)); + +} + +void _SlDrvObjUnLock(_SlLockObj_t *pLockObj) +{ + OSI_RET_OK_CHECK(sl_LockObjUnlock(pLockObj)); + +} + +void _SlDrvProtectionObjUnLock() +{ + OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj)); +} + + +void _SlDrvMemZero(void* Addr, _u16 size) +{ + sl_Memset(Addr, 0, size); +} + + +void _SlDrvResetCmdExt(_SlCmdExt_t* pCmdExt) +{ + _SlDrvMemZero(pCmdExt, sizeof (_SlCmdExt_t)); +} + + + + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/flowcont.c b/src/openmv/src/micropython/drivers/cc3100/src/flowcont.c new file mode 100755 index 0000000..889241e --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/flowcont.c @@ -0,0 +1,71 @@ +/* + * flowcont.c - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" +#include "flowcont.h" + + +/*****************************************************************************/ +/* _SlDrvFlowContInit */ +/*****************************************************************************/ +void _SlDrvFlowContInit(void) +{ + g_pCB->FlowContCB.TxPoolCnt = FLOW_CONT_MIN; + + OSI_RET_OK_CHECK(sl_LockObjCreate(&g_pCB->FlowContCB.TxLockObj, "TxLockObj")); + + OSI_RET_OK_CHECK(sl_SyncObjCreate(&g_pCB->FlowContCB.TxSyncObj, "TxSyncObj")); +} + +/*****************************************************************************/ +/* _SlDrvFlowContDeinit */ +/*****************************************************************************/ +void _SlDrvFlowContDeinit(void) +{ + g_pCB->FlowContCB.TxPoolCnt = 0; + + OSI_RET_OK_CHECK(sl_LockObjDelete(&g_pCB->FlowContCB.TxLockObj)); + + OSI_RET_OK_CHECK(sl_SyncObjDelete(&g_pCB->FlowContCB.TxSyncObj)); +} + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/fs.c b/src/openmv/src/micropython/drivers/cc3100/src/fs.c new file mode 100755 index 0000000..cc2e998 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/fs.c @@ -0,0 +1,424 @@ +/* + * fs.c - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ +#define sl_min(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX_NVMEM_CHUNK_SIZE 1460 + +/*****************************************************************************/ +/* Internal functions */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* _sl_Strlen */ +/*****************************************************************************/ +_u16 _sl_Strlen(const _u8 *buffer) +{ + _u16 len = 0; + if( buffer != NULL ) + { + while(*buffer++) len++; + } + return len; +} + +/*****************************************************************************/ +/* _sl_GetCreateFsMode */ +/*****************************************************************************/ +_u32 _sl_GetCreateFsMode(_u32 maxSizeInBytes,_u32 accessFlags) +{ + _u32 granIdx = 0; + _u32 granNum = 0; + _u32 granTable[_FS_MAX_MODE_SIZE_GRAN] = {256,1024,4096,16384,65536}; + for(granIdx= _FS_MODE_SIZE_GRAN_256B ;granIdx< _FS_MAX_MODE_SIZE_GRAN;granIdx++) + { + if( granTable[granIdx]*255 >= maxSizeInBytes ) + break; + } + granNum = maxSizeInBytes/granTable[granIdx]; + if( maxSizeInBytes % granTable[granIdx] != 0 ) + granNum++; + + return _FS_MODE(_FS_MODE_OPEN_WRITE_CREATE_IF_NOT_EXIST, granIdx, granNum, accessFlags); +} + +/*****************************************************************************/ +/* API functions */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* sl_FsOpen */ +/*****************************************************************************/ +typedef union +{ + _FsOpenCommand_t Cmd; + _FsOpenResponse_t Rsp; +}_SlFsOpenMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_FsOpen) + +const _SlCmdCtrl_t _SlFsOpenCmdCtrl = +{ + SL_OPCODE_NVMEM_FILEOPEN, + sizeof(_FsOpenCommand_t), + sizeof(_FsOpenResponse_t) +}; + +_i32 sl_FsOpen(const _u8 *pFileName,const _u32 AccessModeAndMaxSize, _u32 *pToken,_i32 *pFileHandle) +{ + _SlReturnVal_t RetVal; + _SlFsOpenMsg_u Msg; + _SlCmdExt_t CmdExt; + + CmdExt.TxPayloadLen = (_sl_Strlen(pFileName)+4) & (~3); /* add 4: 1 for NULL and the 3 for align */ + CmdExt.RxPayloadLen = 0; + CmdExt.pTxPayload = (_u8*)pFileName; + CmdExt.pRxPayload = NULL; + + Msg.Cmd.Mode = AccessModeAndMaxSize; + + if(pToken != NULL) + { + Msg.Cmd.Token = *pToken; + } + else + { + Msg.Cmd.Token = 0; + } + + RetVal = _SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsOpenCmdCtrl, &Msg, &CmdExt); + *pFileHandle = Msg.Rsp.FileHandle; + if (pToken != NULL) + { + *pToken = Msg.Rsp.Token; + } + + /* in case of an error, return the erros file handler as an error code */ + if( *pFileHandle < 0 ) + { + return *pFileHandle; + } + return (_i32)RetVal; +} +#endif + +/*****************************************************************************/ +/* sl_FsClose */ +/*****************************************************************************/ +typedef union +{ + _FsCloseCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlFsCloseMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_FsClose) + +const _SlCmdCtrl_t _SlFsCloseCmdCtrl = +{ + SL_OPCODE_NVMEM_FILECLOSE, + sizeof(_FsCloseCommand_t), + sizeof(_FsCloseResponse_t) +}; + +_i16 sl_FsClose(const _i32 FileHdl, const _u8* pCeritificateFileName,const _u8* pSignature ,const _u32 SignatureLen) +{ + _SlFsCloseMsg_u Msg = {{0, 0}}; + _SlCmdExt_t ExtCtrl; + + Msg.Cmd.FileHandle = FileHdl; + if( pCeritificateFileName != NULL ) + { + Msg.Cmd.CertificFileNameLength = (_sl_Strlen(pCeritificateFileName)+4) & (~3); /* add 4: 1 for NULL and the 3 for align */ + } + Msg.Cmd.SignatureLen = SignatureLen; + + ExtCtrl.TxPayloadLen = ((SignatureLen+3) & (~3)); /* align */ + ExtCtrl.pTxPayload = (_u8*)pSignature; + ExtCtrl.RxPayloadLen = (_i16)Msg.Cmd.CertificFileNameLength; + ExtCtrl.pRxPayload = (_u8*)pCeritificateFileName; /* Add signature */ + + if(ExtCtrl.pRxPayload != NULL && ExtCtrl.RxPayloadLen != 0) + { + ExtCtrl.RxPayloadLen = ExtCtrl.RxPayloadLen * (-1); + } + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsCloseCmdCtrl, &Msg, &ExtCtrl)); + + return (_i16)((_i16)Msg.Rsp.status); +} +#endif + + +/*****************************************************************************/ +/* sl_FsRead */ +/*****************************************************************************/ +typedef union +{ + _FsReadCommand_t Cmd; + _FsReadResponse_t Rsp; +}_SlFsReadMsg_u; + +#if _SL_INCLUDE_FUNC(sl_FsRead) + + +const _SlCmdCtrl_t _SlFsReadCmdCtrl = +{ + SL_OPCODE_NVMEM_FILEREADCOMMAND, + sizeof(_FsReadCommand_t), + sizeof(_FsReadResponse_t) +}; + +_i32 sl_FsRead(const _i32 FileHdl,_u32 Offset, _u8* pData,_u32 Len) +{ + _SlFsReadMsg_u Msg; + _SlCmdExt_t ExtCtrl; + _u16 ChunkLen; + _SlReturnVal_t RetVal =0; + _i32 RetCount = 0; + + ExtCtrl.TxPayloadLen = 0; + ExtCtrl.pTxPayload = NULL; + + ChunkLen = (_u16)sl_min(MAX_NVMEM_CHUNK_SIZE,Len); + ExtCtrl.RxPayloadLen = ChunkLen; + ExtCtrl.pRxPayload = (_u8 *)(pData); + Msg.Cmd.Offset = Offset; + Msg.Cmd.Len = ChunkLen; + Msg.Cmd.FileHandle = FileHdl; + do + { + RetVal = _SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsReadCmdCtrl, &Msg, &ExtCtrl); + if(SL_OS_RET_CODE_OK == RetVal) + { + if( Msg.Rsp.status < 0) + { + if( RetCount > 0) + { + return RetCount; + } + else + { + return Msg.Rsp.status; + } + } + RetCount += (_i32)Msg.Rsp.status; + Len -= ChunkLen; + Offset += ChunkLen; + Msg.Cmd.Offset = Offset; + ExtCtrl.pRxPayload += ChunkLen; + ChunkLen = (_u16)sl_min(MAX_NVMEM_CHUNK_SIZE,Len); + ExtCtrl.RxPayloadLen = ChunkLen; + Msg.Cmd.Len = ChunkLen; + Msg.Cmd.FileHandle = FileHdl; + } + else + { + return RetVal; + } + }while(ChunkLen > 0); + + return (_i32)RetCount; +} +#endif + +/*****************************************************************************/ +/* sl_FsWrite */ +/*****************************************************************************/ +typedef union +{ + _FsWriteCommand_t Cmd; + _FsWriteResponse_t Rsp; +}_SlFsWriteMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_FsWrite) + +const _SlCmdCtrl_t _SlFsWriteCmdCtrl = +{ + SL_OPCODE_NVMEM_FILEWRITECOMMAND, + sizeof(_FsWriteCommand_t), + sizeof(_FsWriteResponse_t) +}; + +_i32 sl_FsWrite(const _i32 FileHdl,_u32 Offset, _u8* pData,_u32 Len) +{ + _SlFsWriteMsg_u Msg; + _SlCmdExt_t ExtCtrl; + _u16 ChunkLen; + _SlReturnVal_t RetVal; + _i32 RetCount = 0; + + ExtCtrl.RxPayloadLen = 0; + ExtCtrl.pRxPayload = NULL; + + ChunkLen = (_u16)sl_min(MAX_NVMEM_CHUNK_SIZE,Len); + ExtCtrl.TxPayloadLen = ChunkLen; + ExtCtrl.pTxPayload = (_u8 *)(pData); + Msg.Cmd.Offset = Offset; + Msg.Cmd.Len = ChunkLen; + Msg.Cmd.FileHandle = FileHdl; + + do + { + + RetVal = _SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsWriteCmdCtrl, &Msg, &ExtCtrl); + if(SL_OS_RET_CODE_OK == RetVal) + { + if( Msg.Rsp.status < 0) + { + if( RetCount > 0) + { + return RetCount; + } + else + { + return Msg.Rsp.status; + } + } + + RetCount += (_i32)Msg.Rsp.status; + Len -= ChunkLen; + Offset += ChunkLen; + Msg.Cmd.Offset = Offset; + ExtCtrl.pTxPayload += ChunkLen; + ChunkLen = (_u16)sl_min(MAX_NVMEM_CHUNK_SIZE,Len); + ExtCtrl.TxPayloadLen = ChunkLen; + Msg.Cmd.Len = ChunkLen; + Msg.Cmd.FileHandle = FileHdl; + } + else + { + return RetVal; + } + }while(ChunkLen > 0); + + return (_i32)RetCount; +} +#endif + +/*****************************************************************************/ +/* sl_FsGetInfo */ +/*****************************************************************************/ +typedef union +{ + _FsGetInfoCommand_t Cmd; + _FsGetInfoResponse_t Rsp; +}_SlFsGetInfoMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_FsGetInfo) + + +const _SlCmdCtrl_t _SlFsGetInfoCmdCtrl = +{ + SL_OPCODE_NVMEM_FILEGETINFOCOMMAND, + sizeof(_FsGetInfoCommand_t), + sizeof(_FsGetInfoResponse_t) +}; + +_i16 sl_FsGetInfo(const _u8 *pFileName,const _u32 Token,SlFsFileInfo_t* pFsFileInfo) +{ + _SlFsGetInfoMsg_u Msg; + _SlCmdExt_t CmdExt; + + CmdExt.TxPayloadLen = (_sl_Strlen(pFileName)+4) & (~3); /* add 4: 1 for NULL and the 3 for align */ + CmdExt.RxPayloadLen = 0; + CmdExt.pTxPayload = (_u8*)pFileName; + CmdExt.pRxPayload = NULL; + Msg.Cmd.Token = Token; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsGetInfoCmdCtrl, &Msg, &CmdExt)); + + pFsFileInfo->flags = Msg.Rsp.flags; + pFsFileInfo->FileLen = Msg.Rsp.FileLen; + pFsFileInfo->AllocatedLen = Msg.Rsp.AllocatedLen; + pFsFileInfo->Token[0] = Msg.Rsp.Token[0]; + pFsFileInfo->Token[1] = Msg.Rsp.Token[1]; + pFsFileInfo->Token[2] = Msg.Rsp.Token[2]; + pFsFileInfo->Token[3] = Msg.Rsp.Token[3]; + return (_i16)((_i16)Msg.Rsp.Status); +} +#endif + +/*****************************************************************************/ +/* sl_FsDel */ +/*****************************************************************************/ +typedef union +{ + _FsDeleteCommand_t Cmd; + _FsDeleteResponse_t Rsp; +}_SlFsDeleteMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_FsDel) + +const _SlCmdCtrl_t _SlFsDeleteCmdCtrl = +{ + SL_OPCODE_NVMEM_FILEDELCOMMAND, + sizeof(_FsDeleteCommand_t), + sizeof(_FsDeleteResponse_t) +}; + +_i16 sl_FsDel(const _u8 *pFileName,const _u32 Token) +{ + _SlFsDeleteMsg_u Msg; + _SlCmdExt_t CmdExt; + + CmdExt.TxPayloadLen = (_sl_Strlen(pFileName)+4) & (~3); /* add 4: 1 for NULL and the 3 for align */ + CmdExt.RxPayloadLen = 0; + CmdExt.pTxPayload = (_u8*)pFileName; + CmdExt.pRxPayload = NULL; + Msg.Cmd.Token = Token; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlFsDeleteCmdCtrl, &Msg, &CmdExt)); + + return (_i16)((_i16)Msg.Rsp.status); +} +#endif diff --git a/src/openmv/src/micropython/drivers/cc3100/src/netapp.c b/src/openmv/src/micropython/drivers/cc3100/src/netapp.c new file mode 100755 index 0000000..11bcdef --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/netapp.c @@ -0,0 +1,1304 @@ +/* + * netapp.c - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ +#define NETAPP_MDNS_OPTIONS_ADD_SERVICE_BIT ((_u32)0x1 << 31) + +#ifdef SL_TINY +#define NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH 63 +#else +#define NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH 255 +#endif + + +/*****************************************************************************/ +/* Functions prototypes */ +/*****************************************************************************/ +void _sl_HandleAsync_DnsGetHostByName(void *pVoidBuf); + +#ifndef SL_TINY_EXT +void _sl_HandleAsync_DnsGetHostByService(void *pVoidBuf); +void _sl_HandleAsync_PingResponse(void *pVoidBuf); +#endif + +void CopyPingResultsToReport(_PingReportResponse_t *pResults,SlPingReport_t *pReport); +_i16 sl_NetAppMDNSRegisterUnregisterService(const _i8* pServiceName, + const _u8 ServiceNameLen, + const _i8* pText, + const _u8 TextLen, + const _u16 Port, + const _u32 TTL, + const _u32 Options); + +#if defined(sl_HttpServerCallback) || defined(EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) +_u16 _sl_NetAppSendTokenValue(slHttpServerData_t * Token); +#endif +typedef union +{ + _NetAppStartStopCommand_t Cmd; + _NetAppStartStopResponse_t Rsp; +}_SlNetAppStartStopMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppStart) + +const _SlCmdCtrl_t _SlNetAppStartCtrl = +{ + SL_OPCODE_NETAPP_START_COMMAND, + sizeof(_NetAppStartStopCommand_t), + sizeof(_NetAppStartStopResponse_t) +}; + +_i16 sl_NetAppStart(const _u32 AppBitMap) +{ + _SlNetAppStartStopMsg_u Msg; + Msg.Cmd.appId = AppBitMap; + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetAppStartCtrl, &Msg, NULL)); + + return Msg.Rsp.status; +} +#endif + +/***************************************************************************** + sl_NetAppStop +*****************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_NetAppStop) + + +const _SlCmdCtrl_t _SlNetAppStopCtrl = +{ + SL_OPCODE_NETAPP_STOP_COMMAND, + sizeof(_NetAppStartStopCommand_t), + sizeof(_NetAppStartStopResponse_t) +}; + + + +_i16 sl_NetAppStop(const _u32 AppBitMap) +{ + _SlNetAppStartStopMsg_u Msg; + Msg.Cmd.appId = AppBitMap; + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetAppStopCtrl, &Msg, NULL)); + + return Msg.Rsp.status; +} +#endif + + +/******************************************************************************/ +/* sl_NetAppGetServiceList */ +/******************************************************************************/ +typedef struct +{ + _u8 IndexOffest; + _u8 MaxServiceCount; + _u8 Flags; + _i8 Padding; +}NetappGetServiceListCMD_t; + +typedef union +{ + NetappGetServiceListCMD_t Cmd; + _BasicResponse_t Rsp; +}_SlNetappGetServiceListMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppGetServiceList) + +const _SlCmdCtrl_t _SlGetServiceListeCtrl = +{ + SL_OPCODE_NETAPP_NETAPP_MDNS_LOOKUP_SERVICE, + sizeof(NetappGetServiceListCMD_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_NetAppGetServiceList(const _u8 IndexOffest, + const _u8 MaxServiceCount, + const _u8 Flags, + _i8 *pBuffer, + const _u32 RxBufferLength + ) +{ + + _i32 retVal= 0; + _SlNetappGetServiceListMsg_u Msg; + _SlCmdExt_t CmdExt; + _u16 ServiceSize = 0; + _u16 BufferSize = 0; + + /* + Calculate RX pBuffer size + WARNING: + if this size is BufferSize than 1480 error should be returned because there + is no place in the RX packet. + */ + switch(Flags) + { + case SL_NET_APP_FULL_SERVICE_WITH_TEXT_IPV4_TYPE: + ServiceSize = sizeof(SlNetAppGetFullServiceWithTextIpv4List_t); + break; + + case SL_NET_APP_FULL_SERVICE_IPV4_TYPE: + ServiceSize = sizeof(SlNetAppGetFullServiceIpv4List_t); + break; + + case SL_NET_APP_SHORT_SERVICE_IPV4_TYPE: + ServiceSize = sizeof(SlNetAppGetShortServiceIpv4List_t); + break; + + default: + ServiceSize = sizeof(_BasicResponse_t); + break; + } + + + + BufferSize = MaxServiceCount * ServiceSize; + + /*Check the size of the requested services is smaller than size of the user buffer. + If not an error is returned in order to avoid overwriting memory. */ + if(RxBufferLength <= BufferSize) + { + return SL_ERROR_NETAPP_RX_BUFFER_LENGTH_ERROR; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = BufferSize; + CmdExt.pRxPayload = (_u8 *)pBuffer; + + Msg.Cmd.IndexOffest = IndexOffest; + Msg.Cmd.MaxServiceCount = MaxServiceCount; + Msg.Cmd.Flags = Flags; + Msg.Cmd.Padding = 0; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetServiceListeCtrl, &Msg, &CmdExt)); + retVal = Msg.Rsp.status; + + return (_i16)retVal; +} + +#endif + +/*****************************************************************************/ +/* sl_mDNSRegisterService */ +/*****************************************************************************/ +/* + * The below struct depicts the constant parameters of the command/API RegisterService. + * + 1. ServiceLen - The length of the service should be smaller than NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + 2. TextLen - The length of the text should be smaller than NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + 3. port - The port on this target host. + 4. TTL - The TTL of the service + 5. Options - bitwise parameters: + bit 0 - is unique (means if the service needs to be unique) + bit 31 - for internal use if the service should be added or deleted (set means ADD). + bit 1-30 for future. + + NOTE: + + 1. There are another variable parameter is this API which is the service name and the text. + 2. According to now there is no warning and Async event to user on if the service is a unique. +* + */ + + +typedef struct +{ + _u8 ServiceNameLen; + _u8 TextLen; + _u16 Port; + _u32 TTL; + _u32 Options; +}NetappMdnsSetService_t; + +typedef union +{ + NetappMdnsSetService_t Cmd; + _BasicResponse_t Rsp; +}_SlNetappMdnsRegisterServiceMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppMDNSRegisterUnregisterService) + +const _SlCmdCtrl_t _SlRegisterServiceCtrl = +{ + SL_OPCODE_NETAPP_MDNSREGISTERSERVICE, + sizeof(NetappMdnsSetService_t), + sizeof(_BasicResponse_t) +}; + +/****************************************************************************** + + sl_NetAppMDNSRegisterService + + CALLER user from its host + + + DESCRIPTION: + Add/delete service + The function manipulates the command that register the service and call + to the NWP in order to add/delete the service to/from the mDNS package and to/from the DB. + + This register service is a service offered by the application. + This unregister service is a service offered by the application before. + + The service name should be full service name according to RFC + of the DNS-SD - means the value in name field in SRV answer. + + Example for service name: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + + If the option is_unique is set, mDNS probes the service name to make sure + it is unique before starting to announce the service on the network. + Instance is the instance portion of the service name. + + + + + PARAMETERS: + + The command is from constant parameters and variables parameters. + + Constant parameters are: + + ServiceLen - The length of the service. + TextLen - The length of the service should be smaller than 64. + port - The port on this target host. + TTL - The TTL of the service + Options - bitwise parameters: + bit 0 - is unique (means if the service needs to be unique) + bit 31 - for internal use if the service should be added or deleted (set means ADD). + bit 1-30 for future. + + The variables parameters are: + + Service name(full service name) - The service name. + Example for service name: + 1. PC1._ipp._tcp.local + 2. PC2_server._ftp._tcp.local + + Text - The description of the service. + should be as mentioned in the RFC + (according to type of the service IPP,FTP...) + + NOTE - pay attention + + 1. Temporary - there is an allocation on stack of internal buffer. + Its size is NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + It means that the sum of the text length and service name length cannot be bigger than + NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + If it is - An error is returned. + + 2. According to now from certain constraints the variables parameters are set in the + attribute part (contain constant parameters) + + + + RETURNS: Status - the immediate response of the command status. + 0 means success. + + + +******************************************************************************/ +_i16 sl_NetAppMDNSRegisterUnregisterService( const _i8* pServiceName, + const _u8 ServiceNameLen, + const _i8* pText, + const _u8 TextLen, + const _u16 Port, + const _u32 TTL, + const _u32 Options) + +{ + _SlNetappMdnsRegisterServiceMsg_u Msg; + _SlCmdExt_t CmdExt ; + _i8 ServiceNameAndTextBuffer[NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH]; + _i8 *TextPtr; + + /* + + NOTE - pay attention + + 1. Temporary - there is an allocation on stack of internal buffer. + Its size is NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + It means that the sum of the text length and service name length cannot be bigger than + NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + If it is - An error is returned. + + 2. According to now from certain constraints the variables parameters are set in the + attribute part (contain constant parameters) + + + */ + + /*build the attribute part of the command. + It contains the constant parameters of the command*/ + + Msg.Cmd.ServiceNameLen = ServiceNameLen; + Msg.Cmd.Options = Options; + Msg.Cmd.Port = Port; + Msg.Cmd.TextLen = TextLen; + Msg.Cmd.TTL = TTL; + + /*Build the payload part of the command + Copy the service name and text to one buffer. + NOTE - pay attention + The size of the service length + the text length should be smaller than 255, + Until the simplelink drive supports to variable length through SPI command. */ + if(TextLen + ServiceNameLen > (NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH - 1 )) /*-1 is for giving a place to set null termination at the end of the text*/ + { + return -1; + } + + _SlDrvMemZero(ServiceNameAndTextBuffer, NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH); + + + /*Copy the service name*/ + sl_Memcpy(ServiceNameAndTextBuffer, + pServiceName, + ServiceNameLen); + + if(TextLen > 0 ) + { + + TextPtr = &ServiceNameAndTextBuffer[ServiceNameLen]; + /*Copy the text just after the service name*/ + sl_Memcpy(TextPtr, + pText, + TextLen); + + + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (TextLen + ServiceNameLen); + CmdExt.pTxPayload = (_u8 *)ServiceNameAndTextBuffer; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlRegisterServiceCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; + + +} +#endif + +/**********************************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_NetAppMDNSRegisterService) + +_i16 sl_NetAppMDNSRegisterService( const _i8* pServiceName, + const _u8 ServiceNameLen, + const _i8* pText, + const _u8 TextLen, + const _u16 Port, + const _u32 TTL, + _u32 Options) + +{ + + /* + + NOTE - pay attention + + 1. Temporary - there is an allocation on stack of internal buffer. + Its size is NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + It means that the sum of the text length and service name length cannot be bigger than + NETAPP_MDNS_MAX_SERVICE_NAME_AND_TEXT_LENGTH. + If it is - An error is returned. + + 2. According to now from certain constraints the variables parameters are set in the + attribute part (contain constant parameters) + + */ + + /*Set the add service bit in the options parameter. + In order not use different opcodes for the register service and unregister service + bit 31 in option is taken for this purpose. if it is set it means in NWP that the service should be added + if it is cleared it means that the service should be deleted and there is only meaning to pServiceName + and ServiceNameLen values. */ + Options |= NETAPP_MDNS_OPTIONS_ADD_SERVICE_BIT; + + return sl_NetAppMDNSRegisterUnregisterService( pServiceName, + ServiceNameLen, + pText, + TextLen, + Port, + TTL, + Options); + + +} +#endif +/**********************************************************************************************/ + + + +/**********************************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_NetAppMDNSUnRegisterService) + +_i16 sl_NetAppMDNSUnRegisterService( const _i8* pServiceName, + const _u8 ServiceNameLen) + + +{ + _u32 Options = 0; + + /* + + NOTE - pay attention + + The size of the service length should be smaller than 255, + Until the simplelink drive supports to variable length through SPI command. + + + */ + + /*Clear the add service bit in the options parameter. + In order not use different opcodes for the register service and unregister service + bit 31 in option is taken for this purpose. if it is set it means in NWP that the service should be added + if it is cleared it means that the service should be deleted and there is only meaning to pServiceName + and ServiceNameLen values.*/ + + Options &= (~NETAPP_MDNS_OPTIONS_ADD_SERVICE_BIT); + + return sl_NetAppMDNSRegisterUnregisterService( pServiceName, + ServiceNameLen, + NULL, + 0, + 0, + 0, + Options); + + +} +#endif +/**********************************************************************************************/ + + + +/*****************************************************************************/ +/* sl_DnsGetHostByService */ +/*****************************************************************************/ +/* + * The below struct depicts the constant parameters of the command/API sl_DnsGetHostByService. + * + 1. ServiceLen - The length of the service should be smaller than 255. + 2. AddrLen - TIPv4 or IPv6 (SL_AF_INET , SL_AF_INET6). +* + */ + +typedef struct +{ + _u8 ServiceLen; + _u8 AddrLen; + _u16 Padding; +}_GetHostByServiceCommand_t; + + + +/* + * The below structure depict the constant parameters that are returned in the Async event answer + * according to command/API sl_DnsGetHostByService for IPv4 and IPv6. + * + 1Status - The status of the response. + 2.Address - Contains the IP address of the service. + 3.Port - Contains the port of the service. + 4.TextLen - Contains the max length of the text that the user wants to get. + it means that if the test of service is bigger that its value than + the text is cut to inout_TextLen value. + Output: Contain the length of the text that is returned. Can be full text or part + of the text (see above). + +* + */ +typedef struct +{ + _u16 Status; + _u16 TextLen; + _u32 Port; + _u32 Address; +}_GetHostByServiceIPv4AsyncResponse_t; + + +typedef struct +{ + _u16 Status; + _u16 TextLen; + _u32 Port; + _u32 Address[4]; +}_GetHostByServiceIPv6AsyncResponse_t; + + +typedef union +{ + _GetHostByServiceIPv4AsyncResponse_t IpV4; + _GetHostByServiceIPv6AsyncResponse_t IpV6; +}_GetHostByServiceAsyncResponseAttribute_u; + +/* + * The below struct contains pointers to the output parameters that the user gives + * + */ +typedef struct +{ + _i16 Status; + _u32 *out_pAddr; + _u32 *out_pPort; + _u16 *inout_TextLen; /* in: max len , out: actual len */ + _i8 *out_pText; +}_GetHostByServiceAsyncResponse_t; + + +typedef union +{ + _GetHostByServiceCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlGetHostByServiceMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppDnsGetHostByService) + +const _SlCmdCtrl_t _SlGetHostByServiceCtrl = +{ + SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICE, + sizeof(_GetHostByServiceCommand_t), + sizeof(_BasicResponse_t) +}; + +/******************************************************************************/ + +_i32 sl_NetAppDnsGetHostByService(_i8 *pServiceName, /* string containing all (or only part): name + subtype + service */ + const _u8 ServiceLen, + const _u8 Family, /* 4-IPv4 , 16-IPv6 */ + _u32 pAddr[], + _u32 *pPort, + _u16 *pTextLen, /* in: max len , out: actual len */ + _i8 *pText + ) +{ + _SlGetHostByServiceMsg_u Msg; + _SlCmdExt_t CmdExt ; + _GetHostByServiceAsyncResponse_t AsyncRsp; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + +/* + Note: + 1. The return's attributes are belonged to first service that is found. + It can be other services with the same service name will response to + the query. The results of these responses are saved in the peer cache of the NWP, and + should be read by another API. + + 2. Text length can be 120 bytes only - not more + It is because of constraints in the NWP on the buffer that is allocated for the Async event. + + 3.The API waits to Async event by blocking. It means that the API is finished only after an Async event + is sent by the NWP. + + 4.No rolling option!!! - only PTR type is sent. + + +*/ + /*build the attribute part of the command. + It contains the constant parameters of the command */ + + Msg.Cmd.ServiceLen = ServiceLen; + Msg.Cmd.AddrLen = Family; + + /*Build the payload part of the command + Copy the service name and text to one buffer.*/ + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = ServiceLen; + CmdExt.pTxPayload = (_u8 *)pServiceName; + + /*set pointers to the output parameters (the returned parameters). + This pointers are belonged to local struct that is set to global Async response parameter. + It is done in order not to run more than one sl_DnsGetHostByService at the same time. + The API should be run only if global parameter is pointed to NULL. */ + AsyncRsp.out_pText = pText; + AsyncRsp.inout_TextLen = (_u16* )pTextLen; + AsyncRsp.out_pPort = pPort; + AsyncRsp.out_pAddr = (_u32 *)pAddr; + + + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, GETHOSYBYSERVICE_ID, SL_MAX_SOCKETS); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + + if (SL_AF_INET6 == Family) + { + g_pCB->ObjPool[ObjIdx].AdditionalData |= SL_NETAPP_FAMILY_MASK; + } + /* Send the command */ + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetHostByServiceCtrl, &Msg, &CmdExt)); + + + + /* If the immediate reponse is O.K. than wait for aSYNC event response. */ + if(SL_RET_CODE_OK == Msg.Rsp.status) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + /* If we are - it means that Async event was sent. + The results are copied in the Async handle return functions */ + + Msg.Rsp.status = AsyncRsp.Status; + } + + _SlDrvReleasePoolObj(ObjIdx); + return Msg.Rsp.status; +} +#endif + +/******************************************************************************/ + +/****************************************************************************** + _sl_HandleAsync_DnsGetHostByService + + CALLER NWP - Async event on sl_DnsGetHostByService with IPv4 Family + + + DESCRIPTION: + + Async event on sl_DnsGetHostByService command with IPv4 Family. + Return service attributes like IP address, port and text according to service name. + The user sets a service name Full/Part (see example below), and should get the: + 1. IP of the service + 2. The port of service. + 3. The text of service. + + Hence it can make a connection to the specific service and use it. + It is similar to get host by name method. + + It is done by a single shot query with PTR type on the service name. + + + + Note: + 1. The return's attributes are belonged to first service that is found. + It can be other services with the same service name will response to + the query. The results of these responses are saved in the peer cache of the NWP, and + should be read by another API. + + + PARAMETERS: + + pVoidBuf - is point to opcode of the event. + it contains the outputs that are given to the user + + outputs description: + + 1.out_pAddr[] - output: Contain the IP address of the service. + 2.out_pPort - output: Contain the port of the service. + 3.inout_TextLen - Input: Contain the max length of the text that the user wants to get. + it means that if the test of service is bigger that its value than + the text is cut to inout_TextLen value. + Output: Contain the length of the text that is returned. Can be full text or part + of the text (see above). + + 4.out_pText - Contain the text of the service (full or part see above- inout_TextLen description). + + * + + + RETURNS: success or fail. + + + + + +******************************************************************************/ +#ifndef SL_TINY_EXT +void _sl_HandleAsync_DnsGetHostByService(void *pVoidBuf) +{ + + _GetHostByServiceAsyncResponse_t* Res; + _u16 TextLen; + _u16 UserTextLen; + + + /*pVoidBuf - is point to opcode of the event.*/ + + /*set pMsgArgs to point to the attribute of the event.*/ + _GetHostByServiceIPv4AsyncResponse_t *pMsgArgs = (_GetHostByServiceIPv4AsyncResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + + VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs); + + /*IPv6*/ + if(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].AdditionalData & SL_NETAPP_FAMILY_MASK) + { + return; + } + /*IPv4*/ + else + { + /************************************************************************************************* + + 1. Copy the attribute part of the evnt to the attribute part of the response + sl_Memcpy(g_pCB->GetHostByServiceCB.pAsyncRsp, pMsgArgs, sizeof(_GetHostByServiceIPv4AsyncResponse_t)); + + set to TextLen the text length of the service.*/ + TextLen = pMsgArgs->TextLen; + + /*Res pointed to mDNS global object struct */ + Res = (_GetHostByServiceAsyncResponse_t*)g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs; + + + + /*It is 4 bytes so we avoid from memcpy*/ + Res->out_pAddr[0] = pMsgArgs->Address; + Res->out_pPort[0] = pMsgArgs->Port; + Res->Status = pMsgArgs->Status; + + /*set to TextLen the text length of the user (input fromthe user).*/ + UserTextLen = Res->inout_TextLen[0]; + + /*Cut the service text if the user requested for smaller text.*/ + UserTextLen = (TextLen <= UserTextLen) ? TextLen : UserTextLen; + Res->inout_TextLen[0] = UserTextLen ; + + /************************************************************************************************** + + 2. Copy the payload part of the evnt (the text) to the payload part of the response + the lenght of the copy is according to the text length in the attribute part. */ + + + sl_Memcpy(Res->out_pText , + (_i8 *)(& pMsgArgs[1]) , /* & pMsgArgs[1] -> 1st byte after the fixed header = 1st byte of variable text.*/ + UserTextLen ); + + + /**************************************************************************************************/ + + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + return; + } +} + +/*****************************************************************************/ +/* _sl_HandleAsync_DnsGetHostByAddr */ +/*****************************************************************************/ +void _sl_HandleAsync_DnsGetHostByAddr(void *pVoidBuf) +{ + SL_TRACE0(DBG_MSG, MSG_303, "STUB: _sl_HandleAsync_DnsGetHostByAddr not implemented yet!"); + return; +} +#endif + +/*****************************************************************************/ +/* sl_DnsGetHostByName */ +/*****************************************************************************/ +typedef union +{ + _GetHostByNameIPv4AsyncResponse_t IpV4; + _GetHostByNameIPv6AsyncResponse_t IpV6; +}_GetHostByNameAsyncResponse_u; + +typedef union +{ + _GetHostByNameCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlGetHostByNameMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppDnsGetHostByName) +const _SlCmdCtrl_t _SlGetHostByNameCtrl = +{ + SL_OPCODE_NETAPP_DNSGETHOSTBYNAME, + sizeof(_GetHostByNameCommand_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_NetAppDnsGetHostByName(_i8 * hostname,const _u16 usNameLen, _u32* out_ip_addr,const _u8 family) +{ + _SlGetHostByNameMsg_u Msg; + _SlCmdExt_t ExtCtrl; + _GetHostByNameAsyncResponse_u AsyncRsp; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + + + _SlDrvResetCmdExt(&ExtCtrl); + ExtCtrl.TxPayloadLen = usNameLen; + ExtCtrl.pTxPayload = (_u8 *)hostname; + + Msg.Cmd.Len = usNameLen; + Msg.Cmd.family = family; + + /*Use Obj to issue the command, if not available try later */ + ObjIdx = (_u8)_SlDrvWaitForPoolObj(GETHOSYBYNAME_ID,SL_MAX_SOCKETS); + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + _SlDrvProtectionObjLockWaitForever(); + + g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&AsyncRsp; + /*set bit to indicate IPv6 address is expected */ + if (SL_AF_INET6 == family) + { + g_pCB->ObjPool[ObjIdx].AdditionalData |= SL_NETAPP_FAMILY_MASK; + } + + _SlDrvProtectionObjUnLock(); + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetHostByNameCtrl, &Msg, &ExtCtrl)); + + if(SL_RET_CODE_OK == Msg.Rsp.status) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + Msg.Rsp.status = AsyncRsp.IpV4.status; + + if(SL_OS_RET_CODE_OK == (_i16)Msg.Rsp.status) + { + sl_Memcpy((_i8 *)out_ip_addr, + (_i8 *)&AsyncRsp.IpV4.ip0, + (SL_AF_INET == family) ? SL_IPV4_ADDRESS_SIZE : SL_IPV6_ADDRESS_SIZE); + } + } + _SlDrvReleasePoolObj(ObjIdx); + return Msg.Rsp.status; +} +#endif + + +/******************************************************************************/ +/* _sl_HandleAsync_DnsGetHostByName */ +/******************************************************************************/ +void _sl_HandleAsync_DnsGetHostByName(void *pVoidBuf) +{ + _GetHostByNameIPv4AsyncResponse_t *pMsgArgs = (_GetHostByNameIPv4AsyncResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + + _SlDrvProtectionObjLockWaitForever(); + + VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs); + + /*IPv6 */ + if(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].AdditionalData & SL_NETAPP_FAMILY_MASK) + { + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_GetHostByNameIPv6AsyncResponse_t)); + } + /*IPv4 */ + else + { + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_GetHostByNameIPv4AsyncResponse_t)); + } + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + _SlDrvProtectionObjUnLock(); + return; +} + + +#ifndef SL_TINY_EXT +void CopyPingResultsToReport(_PingReportResponse_t *pResults,SlPingReport_t *pReport) +{ + pReport->PacketsSent = pResults->numSendsPings; + pReport->PacketsReceived = pResults->numSuccsessPings; + pReport->MinRoundTime = pResults->rttMin; + pReport->MaxRoundTime = pResults->rttMax; + pReport->AvgRoundTime = pResults->rttAvg; + pReport->TestTime = pResults->testTime; +} + +/*****************************************************************************/ +/* _sl_HandleAsync_PingResponse */ +/*****************************************************************************/ +void _sl_HandleAsync_PingResponse(void *pVoidBuf) +{ + _PingReportResponse_t *pMsgArgs = (_PingReportResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + SlPingReport_t pingReport; + + if(pPingCallBackFunc) + { + CopyPingResultsToReport(pMsgArgs,&pingReport); + pPingCallBackFunc(&pingReport); + } + else + { + + _SlDrvProtectionObjLockWaitForever(); + + VERIFY_SOCKET_CB(NULL != g_pCB->PingCB.PingAsync.pAsyncRsp); + + if (NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs) + { + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_PingReportResponse_t)); + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + } + _SlDrvProtectionObjUnLock(); + } + return; +} +#endif + +/*****************************************************************************/ +/* sl_PingStart */ +/*****************************************************************************/ +typedef union +{ + _PingStartCommand_t Cmd; + _PingReportResponse_t Rsp; +}_SlPingStartMsg_u; + + +typedef enum +{ + CMD_PING_TEST_RUNNING = 0, + CMD_PING_TEST_STOPPED +}_SlPingStatus_e; + + +#if _SL_INCLUDE_FUNC(sl_NetAppPingStart) +_i16 sl_NetAppPingStart(const SlPingStartCommand_t* pPingParams,const _u8 family,SlPingReport_t *pReport,const P_SL_DEV_PING_CALLBACK pPingCallback) +{ + _SlCmdCtrl_t CmdCtrl = {0, sizeof(_PingStartCommand_t), sizeof(_BasicResponse_t)}; + _SlPingStartMsg_u Msg; + _PingReportResponse_t PingRsp; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + + if( 0 == pPingParams->Ip ) + {/* stop any ongoing ping */ + return _SlDrvBasicCmd(SL_OPCODE_NETAPP_PINGSTOP); + } + + if(SL_AF_INET == family) + { + CmdCtrl.Opcode = SL_OPCODE_NETAPP_PINGSTART; + sl_Memcpy(&Msg.Cmd.ip0, &pPingParams->Ip, SL_IPV4_ADDRESS_SIZE); + } + else + { + CmdCtrl.Opcode = SL_OPCODE_NETAPP_PINGSTART_V6; + sl_Memcpy(&Msg.Cmd.ip0, &pPingParams->Ip, SL_IPV6_ADDRESS_SIZE); + } + + Msg.Cmd.pingIntervalTime = pPingParams->PingIntervalTime; + Msg.Cmd.PingSize = pPingParams->PingSize; + Msg.Cmd.pingRequestTimeout = pPingParams->PingRequestTimeout; + Msg.Cmd.totalNumberOfAttempts = pPingParams->TotalNumberOfAttempts; + Msg.Cmd.flags = pPingParams->Flags; + + + if( pPingCallback ) + { + pPingCallBackFunc = pPingCallback; + } + else + { + /*Use Obj to issue the command, if not available try later */ + ObjIdx = (_u8)_SlDrvWaitForPoolObj(PING_ID,SL_MAX_SOCKETS); + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + OSI_RET_OK_CHECK(sl_LockObjLock(&g_pCB->ProtectionLockObj, SL_OS_WAIT_FOREVER)); + /* async response handler for non callback mode */ + g_pCB->ObjPool[ObjIdx].pRespArgs = (_u8 *)&PingRsp; + pPingCallBackFunc = NULL; + OSI_RET_OK_CHECK(sl_LockObjUnlock(&g_pCB->ProtectionLockObj)); + } + + + VERIFY_RET_OK(_SlDrvCmdOp(&CmdCtrl, &Msg, NULL)); + /*send the command*/ + if(CMD_PING_TEST_RUNNING == (_i16)Msg.Rsp.status || CMD_PING_TEST_STOPPED == (_i16)Msg.Rsp.status ) + { + /* block waiting for results if no callback function is used */ + if( NULL == pPingCallback ) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + if( SL_OS_RET_CODE_OK == (_i16)PingRsp.status ) + { + CopyPingResultsToReport(&PingRsp,pReport); + } + _SlDrvReleasePoolObj(ObjIdx); + } + } + else + { /* ping failure, no async response */ + if( NULL == pPingCallback ) + { + _SlDrvReleasePoolObj(ObjIdx); + } + } + + return Msg.Rsp.status; +} +#endif + +/*****************************************************************************/ +/* sl_NetAppSet */ +/*****************************************************************************/ +typedef union +{ + _NetAppSetGet_t Cmd; + _BasicResponse_t Rsp; +}_SlNetAppMsgSet_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppSet) + +const _SlCmdCtrl_t _SlNetAppSetCmdCtrl = +{ + SL_OPCODE_NETAPP_NETAPPSET, + sizeof(_NetAppSetGet_t), + sizeof(_BasicResponse_t) +}; + +_i32 sl_NetAppSet(const _u8 AppId ,const _u8 Option,const _u8 OptionLen,const _u8 *pOptionValue) +{ + _SlNetAppMsgSet_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (OptionLen+3) & (~3); + CmdExt.pTxPayload = (_u8 *)pOptionValue; + + + Msg.Cmd.AppId = AppId; + Msg.Cmd.ConfigLen = OptionLen; + Msg.Cmd.ConfigOpt = Option; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetAppSetCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; +} +#endif + +/*****************************************************************************/ +/* sl_NetAppSendTokenValue */ +/*****************************************************************************/ +typedef union +{ + sl_NetAppHttpServerSendToken_t Cmd; + _BasicResponse_t Rsp; +}_SlNetAppMsgSendTokenValue_u; + + + +#if defined(sl_HttpServerCallback) || defined(EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) +const _SlCmdCtrl_t _SlNetAppSendTokenValueCmdCtrl = +{ + SL_OPCODE_NETAPP_HTTPSENDTOKENVALUE, + sizeof(sl_NetAppHttpServerSendToken_t), + sizeof(_BasicResponse_t) +}; + +_u16 _sl_NetAppSendTokenValue(slHttpServerData_t * Token_value) +{ + _SlNetAppMsgSendTokenValue_u Msg; + _SlCmdExt_t CmdExt; + + CmdExt.TxPayloadLen = (Token_value->value_len+3) & (~3); + CmdExt.RxPayloadLen = 0; + CmdExt.pTxPayload = (_u8 *) Token_value->token_value; + CmdExt.pRxPayload = NULL; + + Msg.Cmd.token_value_len = Token_value->value_len; + Msg.Cmd.token_name_len = Token_value->name_len; + sl_Memcpy(&Msg.Cmd.token_name[0], Token_value->token_name, Token_value->name_len); + + + VERIFY_RET_OK(_SlDrvCmdSend((_SlCmdCtrl_t *)&_SlNetAppSendTokenValueCmdCtrl, &Msg, &CmdExt)); + + return Msg.Rsp.status; +} +#endif + + +/*****************************************************************************/ +/* sl_NetAppGet */ +/*****************************************************************************/ +typedef union +{ + _NetAppSetGet_t Cmd; + _NetAppSetGet_t Rsp; +}_SlNetAppMsgGet_u; + + +#if _SL_INCLUDE_FUNC(sl_NetAppGet) +const _SlCmdCtrl_t _SlNetAppGetCmdCtrl = +{ + SL_OPCODE_NETAPP_NETAPPGET, + sizeof(_NetAppSetGet_t), + sizeof(_NetAppSetGet_t) +}; + +_i32 sl_NetAppGet(const _u8 AppId,const _u8 Option,_u8 *pOptionLen, _u8 *pOptionValue) +{ + _SlNetAppMsgGet_u Msg; + _SlCmdExt_t CmdExt; + + if (*pOptionLen == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pOptionLen; + CmdExt.pRxPayload = (_u8 *)pOptionValue; + + Msg.Cmd.AppId = AppId; + Msg.Cmd.ConfigOpt = Option; + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetAppGetCmdCtrl, &Msg, &CmdExt)); + + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *pOptionLen = (_u8)CmdExt.RxPayloadLen; + return SL_ESMALLBUF; + } + else + { + *pOptionLen = (_u8)CmdExt.ActualRxPayloadLen; + } + + return (_i16)Msg.Rsp.Status; +} +#endif + + +/*****************************************************************************/ +/* _SlDrvNetAppEventHandler */ +/*****************************************************************************/ +void _SlDrvNetAppEventHandler(void* pArgs) +{ + _SlResponseHeader_t *pHdr = (_SlResponseHeader_t *)pArgs; +#if defined(sl_HttpServerCallback) || defined(EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) + SlHttpServerEvent_t httpServerEvent; + SlHttpServerResponse_t httpServerResponse; +#endif + + switch(pHdr->GenHeader.Opcode) + { + case SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE: + case SL_OPCODE_NETAPP_DNSGETHOSTBYNAMEASYNCRESPONSE_V6: + _sl_HandleAsync_DnsGetHostByName(pArgs); + break; +#ifndef SL_TINY_EXT + case SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE: + case SL_OPCODE_NETAPP_MDNSGETHOSTBYSERVICEASYNCRESPONSE_V6: + _sl_HandleAsync_DnsGetHostByService(pArgs); + break; + case SL_OPCODE_NETAPP_PINGREPORTREQUESTRESPONSE: + _sl_HandleAsync_PingResponse(pArgs); + break; +#endif + +#if defined(sl_HttpServerCallback) || defined(EXT_LIB_REGISTERED_HTTP_SERVER_EVENTS) + case SL_OPCODE_NETAPP_HTTPGETTOKENVALUE: + { + _u8 *pTokenName; + slHttpServerData_t Token_value; + sl_NetAppHttpServerGetToken_t *httpGetToken = (sl_NetAppHttpServerGetToken_t *)_SL_RESP_ARGS_START(pHdr); + pTokenName = (_u8 *)((sl_NetAppHttpServerGetToken_t *)httpGetToken + 1); + + httpServerResponse.Response = SL_NETAPP_HTTPSETTOKENVALUE; + httpServerResponse.ResponseData.token_value.len = MAX_TOKEN_VALUE_LEN; + + /* Reuse the async buffer for getting the token value response from the user */ + httpServerResponse.ResponseData.token_value.data = (_u8 *)_SL_RESP_ARGS_START(pHdr) + MAX_TOKEN_NAME_LEN; + + httpServerEvent.Event = SL_NETAPP_HTTPGETTOKENVALUE_EVENT; + httpServerEvent.EventData.httpTokenName.len = httpGetToken->token_name_len; + httpServerEvent.EventData.httpTokenName.data = pTokenName; + + Token_value.token_name = pTokenName; + + _SlDrvHandleHttpServerEvents (&httpServerEvent, &httpServerResponse); + + Token_value.value_len = httpServerResponse.ResponseData.token_value.len; + Token_value.name_len = httpServerEvent.EventData.httpTokenName.len; + Token_value.token_value = httpServerResponse.ResponseData.token_value.data; + + + _sl_NetAppSendTokenValue(&Token_value); + } + break; + + case SL_OPCODE_NETAPP_HTTPPOSTTOKENVALUE: + { + _u8 *pPostParams; + + sl_NetAppHttpServerPostToken_t *httpPostTokenArgs = (sl_NetAppHttpServerPostToken_t *)_SL_RESP_ARGS_START(pHdr); + pPostParams = (_u8 *)((sl_NetAppHttpServerPostToken_t *)httpPostTokenArgs + 1); + + httpServerEvent.Event = SL_NETAPP_HTTPPOSTTOKENVALUE_EVENT; + + httpServerEvent.EventData.httpPostData.action.len = httpPostTokenArgs->post_action_len; + httpServerEvent.EventData.httpPostData.action.data = pPostParams; + pPostParams+=httpPostTokenArgs->post_action_len; + + httpServerEvent.EventData.httpPostData.token_name.len = httpPostTokenArgs->token_name_len; + httpServerEvent.EventData.httpPostData.token_name.data = pPostParams; + pPostParams+=httpPostTokenArgs->token_name_len; + + httpServerEvent.EventData.httpPostData.token_value.len = httpPostTokenArgs->token_value_len; + httpServerEvent.EventData.httpPostData.token_value.data = pPostParams; + + httpServerResponse.Response = SL_NETAPP_RESPONSE_NONE; + + _SlDrvHandleHttpServerEvents (&httpServerEvent, &httpServerResponse); + + } + break; +#endif + + + default: + SL_ERROR_TRACE2(MSG_305, "ASSERT: _SlDrvNetAppEventHandler : invalid opcode = 0x%x = %1", pHdr->GenHeader.Opcode, pHdr->GenHeader.Opcode); + VERIFY_PROTOCOL(0); + } +} + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/netcfg.c b/src/openmv/src/micropython/drivers/cc3100/src/netcfg.c new file mode 100755 index 0000000..3674e07 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/netcfg.c @@ -0,0 +1,150 @@ +/* +* netcfg.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + +/*****************************************************************************/ +/* sl_NetCfgSet */ +/*****************************************************************************/ +typedef union +{ + _NetCfgSetGet_t Cmd; + _BasicResponse_t Rsp; +}_SlNetCfgMsgSet_u; + +#if _SL_INCLUDE_FUNC(sl_NetCfgSet) + +const _SlCmdCtrl_t _SlNetCfgSetCmdCtrl = +{ + SL_OPCODE_DEVICE_NETCFG_SET_COMMAND, + sizeof(_NetCfgSetGet_t), + sizeof(_BasicResponse_t) +}; + +_i32 sl_NetCfgSet(const _u8 ConfigId ,const _u8 ConfigOpt,const _u8 ConfigLen,const _u8 *pValues) +{ + _SlNetCfgMsgSet_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (ConfigLen+3) & (~3); + CmdExt.pTxPayload = (_u8 *)pValues; + + + Msg.Cmd.ConfigId = ConfigId; + Msg.Cmd.ConfigLen = ConfigLen; + Msg.Cmd.ConfigOpt = ConfigOpt; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetCfgSetCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; +} +#endif + + +/*****************************************************************************/ +/* sl_NetCfgGet */ +/*****************************************************************************/ +typedef union +{ + _NetCfgSetGet_t Cmd; + _NetCfgSetGet_t Rsp; +}_SlNetCfgMsgGet_u; + +#if _SL_INCLUDE_FUNC(sl_NetCfgGet) + +const _SlCmdCtrl_t _SlNetCfgGetCmdCtrl = +{ + SL_OPCODE_DEVICE_NETCFG_GET_COMMAND, + sizeof(_NetCfgSetGet_t), + sizeof(_NetCfgSetGet_t) +}; + +_i32 sl_NetCfgGet(const _u8 ConfigId, _u8 *pConfigOpt,_u8 *pConfigLen, _u8 *pValues) +{ + _SlNetCfgMsgGet_u Msg; + _SlCmdExt_t CmdExt; + + if (*pConfigLen == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pConfigLen; + CmdExt.pRxPayload = (_u8 *)pValues; + Msg.Cmd.ConfigLen = *pConfigLen; + Msg.Cmd.ConfigId = ConfigId; + + if( pConfigOpt ) + { + Msg.Cmd.ConfigOpt = (_u16)*pConfigOpt; + } + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlNetCfgGetCmdCtrl, &Msg, &CmdExt)); + + if( pConfigOpt ) + { + *pConfigOpt = (_u8)Msg.Rsp.ConfigOpt; + } + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *pConfigLen = (_u8)CmdExt.RxPayloadLen; + if( SL_MAC_ADDRESS_GET == ConfigId ) + { + return SL_RET_CODE_OK; /* sp fix */ + } + else + { + return SL_ESMALLBUF; + } + } + else + { + *pConfigLen = (_u8)CmdExt.ActualRxPayloadLen; + } + + return (_i16)Msg.Rsp.Status; +} +#endif + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/nonos.c b/src/openmv/src/micropython/drivers/cc3100/src/nonos.c new file mode 100755 index 0000000..a20e895 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/nonos.c @@ -0,0 +1,171 @@ +/* +* nonos.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + +#ifndef SL_PLATFORM_MULTI_THREADED + +#include "nonos.h" + +#ifndef SL_TINY_EXT +#define NONOS_MAX_SPAWN_ENTRIES 5 +#else +#define NONOS_MAX_SPAWN_ENTRIES 1 +#endif + + +typedef struct +{ + _SlSpawnEntryFunc_t pEntry; + void* pValue; +}_SlNonOsSpawnEntry_t; + +typedef struct +{ + _SlNonOsSpawnEntry_t SpawnEntries[NONOS_MAX_SPAWN_ENTRIES]; +}_SlNonOsCB_t; + +_SlNonOsCB_t g__SlNonOsCB; + + +_SlNonOsRetVal_t _SlNonOsSemSet(_SlNonOsSemObj_t* pSemObj , _SlNonOsSemObj_t Value) +{ + *pSemObj = Value; + return NONOS_RET_OK; +} + +_SlNonOsRetVal_t _SlNonOsSemGet(_SlNonOsSemObj_t* pSyncObj, _SlNonOsSemObj_t WaitValue, _SlNonOsSemObj_t SetValue, _SlNonOsTime_t Timeout) +{ +#ifdef _SlSyncWaitLoopCallback + _SlNonOsTime_t timeOutRequest = Timeout; +#endif + while (Timeout>0) + { + if (WaitValue == *pSyncObj) + { + *pSyncObj = SetValue; + break; + } + if (Timeout != NONOS_WAIT_FOREVER) + { + Timeout--; + } + _SlNonOsMainLoopTask(); +#ifdef _SlSyncWaitLoopCallback + if( (__NON_OS_SYNC_OBJ_SIGNAL_VALUE == WaitValue) && (timeOutRequest != NONOS_NO_WAIT) ) + { + if (WaitValue == *pSyncObj) + { + *pSyncObj = SetValue; + break; + } + _SlSyncWaitLoopCallback(); + } +#endif + } + + if (0 == Timeout) + { + return NONOS_RET_ERR; + } + else + { + return NONOS_RET_OK; + } +} + + +_SlNonOsRetVal_t _SlNonOsSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , _u32 flags) +{ + _i8 i = 0; + +#ifndef SL_TINY_EXT + for (i=0 ; ipEntry) + { + pE->pValue = pValue; + pE->pEntry = pEntry; +#ifndef SL_TINY_EXT + break; +#endif + } + } + + + return NONOS_RET_OK; +} + + +_SlNonOsRetVal_t _SlNonOsMainLoopTask(void) +{ + _i8 i=0; + + +#ifndef SL_TINY_EXT + for (i=0 ; ipEntry; + + if (NULL != pF) + { + if(RxIrqCnt != (g_pCB)->RxDoneCnt) + { + pF(0); /* (pValue) */ + } + + pE->pEntry = NULL; + pE->pValue = NULL; + } + } + + return NONOS_RET_OK; +} + + +#endif /*(SL_PLATFORM != SL_PLATFORM_NON_OS)*/ diff --git a/src/openmv/src/micropython/drivers/cc3100/src/socket.c b/src/openmv/src/micropython/drivers/cc3100/src/socket.c new file mode 100755 index 0000000..8ef9e09 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/socket.c @@ -0,0 +1,1150 @@ +/* + * socket.c - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + + +void _sl_BuildAddress(const SlSockAddr_t *addr, _SocketAddrCommand_u *pCmd); +void _sl_HandleAsync_Connect(void *pVoidBuf); + +#ifndef SL_TINY_EXT +void _sl_ParseAddress(_SocketAddrResponse_u *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen); +void _sl_HandleAsync_Accept(void *pVoidBuf); +void _sl_HandleAsync_Select(void *pVoidBuf); +#endif +_u16 _sl_TruncatePayloadByProtocol(const _i16 pSd, const _u16 length); + +/*******************************************************************************/ +/* Functions */ +/*******************************************************************************/ + + + /* Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */ + /* is possible as _i32 as these parameters are in the same offset and size for these */ + /* three families. */ +#define SL_SOCKET_PAYLOAD_BASE (1350) + +const _u8 _SlPayloadByProtocolLUT[16] = +{ + (1472 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4 */ + (1460 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4 */ + (1452 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6 */ + (1440 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6 */ + (1386 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV4_SECURE */ + (1386 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV4_SECURE */ + (1396 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_UDP_IPV6_SECURE */ + (1396 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_TCP_IPV6_SECURE */ + (1476 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER */ + (1514 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_PACKET */ + (1480 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_IP4 */ + (1480 - SL_SOCKET_PAYLOAD_BASE), /* SL_SOCKET_PAYLOAD_TYPE_RAW_IP6 */ + (1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */ + (1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */ + (1440 - SL_SOCKET_PAYLOAD_BASE), /* Default */ + (1440 - SL_SOCKET_PAYLOAD_BASE) /* Default */ +}; + + + +/* ******************************************************************************/ +/* _sl_BuildAddress */ +/* ******************************************************************************/ +void _sl_BuildAddress(const SlSockAddr_t *addr, _SocketAddrCommand_u *pCmd) +{ + + /* Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 + is possible as long as these parameters are in the same offset and size for these + three families. */ + pCmd->IpV4.FamilyAndFlags = (addr->sa_family << 4) & 0xF0; + pCmd->IpV4.port = ((SlSockAddrIn_t *)addr)->sin_port; + + if(SL_AF_INET == addr->sa_family) + { + pCmd->IpV4.address = ((SlSockAddrIn_t *)addr)->sin_addr.s_addr; + } + else if (SL_AF_INET6_EUI_48 == addr->sa_family ) + { + sl_Memcpy( pCmd->IpV6EUI48.address,((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, 6); + } +#ifdef SL_SUPPORT_IPV6 + else + { + sl_Memcpy(pCmd->IpV6.address, ((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, 16 ); + } +#endif +} + + +/***************************************************************************** + _sl_TruncatePayloadByProtocol +*****************************************************************************/ +_u16 _sl_TruncatePayloadByProtocol(const _i16 sd, const _u16 length) +{ + unsigned int maxLength; + + + maxLength = SL_SOCKET_PAYLOAD_BASE + _SlPayloadByProtocolLUT[((sd & SL_SOCKET_PAYLOAD_TYPE_MASK) >> 4)]; + + + + if( length > maxLength ) + { + return maxLength; + } + else + { + return length; + } +} + +/*******************************************************************************/ +/* _sl_ParseAddress */ +/*******************************************************************************/ + +#ifndef SL_TINY_EXT +void _sl_ParseAddress(_SocketAddrResponse_u *pRsp, SlSockAddr_t *addr, SlSocklen_t *addrlen) +{ + /* Note: parsing of family and port in the generic way for all IPV4, IPV6 and EUI48 */ + /* is possible as long as these parameters are in the same offset and size for these */ + /* three families. */ + addr->sa_family = pRsp->IpV4.family; + ((SlSockAddrIn_t *)addr)->sin_port = pRsp->IpV4.port; + + *addrlen = (SL_AF_INET == addr->sa_family) ? sizeof(SlSockAddrIn_t) : sizeof(SlSockAddrIn6_t); + + if(SL_AF_INET == addr->sa_family) + { + ((SlSockAddrIn_t *)addr)->sin_addr.s_addr = pRsp->IpV4.address; + } + else if (SL_AF_INET6_EUI_48 == addr->sa_family ) + { + sl_Memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, pRsp->IpV6EUI48.address, 6); + } +#ifdef SL_SUPPORT_IPV6 + else + { + sl_Memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, pRsp->IpV6.address, 16); + } +#endif +} + +#endif + +/*******************************************************************************/ +/* sl_Socket */ +/*******************************************************************************/ +typedef union +{ + _u32 Dummy; + _SocketCommand_t Cmd; + _SocketResponse_t Rsp; +}_SlSockSocketMsg_u; + + + +#if _SL_INCLUDE_FUNC(sl_Socket) + +const _SlCmdCtrl_t _SlSockSocketCmdCtrl = +{ + SL_OPCODE_SOCKET_SOCKET, + sizeof(_SocketCommand_t), + sizeof(_SocketResponse_t) +}; + +_i16 sl_Socket(_i16 Domain, _i16 Type, _i16 Protocol) +{ + _SlSockSocketMsg_u Msg; + + Msg.Cmd.Domain = (_u8)Domain; + Msg.Cmd.Type = (_u8)Type; + Msg.Cmd.Protocol = (_u8)Protocol; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockSocketCmdCtrl, &Msg, NULL)); + + if( Msg.Rsp.statusOrLen < 0 ) + { + return( Msg.Rsp.statusOrLen ); + } + else + { + return (_i16)((_u8)Msg.Rsp.sd); +} +} +#endif + +/*******************************************************************************/ +/* sl_Close */ +/*******************************************************************************/ +typedef union +{ + _CloseCommand_t Cmd; + _SocketResponse_t Rsp; +}_SlSockCloseMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_Close) + +const _SlCmdCtrl_t _SlSockCloseCmdCtrl = +{ + SL_OPCODE_SOCKET_CLOSE, + sizeof(_CloseCommand_t), + sizeof(_SocketResponse_t) +}; + +_i16 sl_Close(_i16 sd) +{ + _SlSockCloseMsg_u Msg; + + Msg.Cmd.sd = (_u8)sd; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSockCloseCmdCtrl, &Msg, NULL)); + + return Msg.Rsp.statusOrLen; +} +#endif + +/*******************************************************************************/ +/* sl_Bind */ +/*******************************************************************************/ +typedef union +{ + _SocketAddrCommand_u Cmd; + _SocketResponse_t Rsp; +}_SlSockBindMsg_u; + +#if _SL_INCLUDE_FUNC(sl_Bind) +_i16 sl_Bind(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen) +{ + _SlSockBindMsg_u Msg; + _SlCmdCtrl_t CmdCtrl = {0, 0, sizeof(_SocketResponse_t)}; + + switch(addr->sa_family) + { + case SL_AF_INET : + CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t); + break; +#ifndef SL_TINY_EXT + case SL_AF_INET6_EUI_48: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t); + break; + +#ifdef SL_SUPPORT_IPV6 + case AF_INET6: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t); + break; +#endif +#endif + + + case SL_AF_RF : + default: + return SL_RET_CODE_INVALID_INPUT; + } + + Msg.Cmd.IpV4.lenOrPadding = 0; + Msg.Cmd.IpV4.sd = (_u8)sd; + + _sl_BuildAddress(addr, &Msg.Cmd); + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL)); + + return Msg.Rsp.statusOrLen; +} +#endif + +/*******************************************************************************/ +/* sl_Sendto */ +/*******************************************************************************/ +typedef union +{ + _SocketAddrCommand_u Cmd; + /* no response for 'sendto' commands*/ +}_SlSendtoMsg_u; + +#if _SL_INCLUDE_FUNC(sl_SendTo) +_i16 sl_SendTo(_i16 sd, const void *pBuf, _i16 Len, _i16 flags, const SlSockAddr_t *to, SlSocklen_t tolen) +{ + _SlSendtoMsg_u Msg; + _SlCmdCtrl_t CmdCtrl = {0, 0, 0}; + _SlCmdExt_t CmdExt; + _u16 ChunkLen; + _i16 RetVal; + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (_u16)Len; + CmdExt.pTxPayload = (_u8 *)pBuf; + + switch(to->sa_family) + { + case SL_AF_INET: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t); + break; +#ifndef SL_TINY_EXT + case SL_AF_INET6_EUI_48: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_BIND_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t); + break; +#ifdef SL_SUPPORT_IPV6 + case AF_INET6: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_SENDTO_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t); + break; +#endif +#endif + case SL_AF_RF: + default: + return SL_RET_CODE_INVALID_INPUT; + } + + ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len); + Msg.Cmd.IpV4.lenOrPadding = ChunkLen; + CmdExt.TxPayloadLen = ChunkLen; + + Msg.Cmd.IpV4.sd = (_u8)sd; + + _sl_BuildAddress(to, &Msg.Cmd); + + Msg.Cmd.IpV4.FamilyAndFlags |= flags & 0x0F; + + do + { + RetVal = _SlDrvDataWriteOp((_SlSd_t)sd, &CmdCtrl, &Msg, &CmdExt); + + if(SL_OS_RET_CODE_OK == RetVal) + { + CmdExt.pTxPayload += ChunkLen; + ChunkLen = (_u16)((_u8 *)pBuf + Len - CmdExt.pTxPayload); + ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen); + CmdExt.TxPayloadLen = ChunkLen; + Msg.Cmd.IpV4.lenOrPadding = ChunkLen; + } + else + { + return RetVal; + } + }while(ChunkLen > 0); + + return (_i16)Len; +} +#endif + +/*******************************************************************************/ +/* sl_Recvfrom */ +/*******************************************************************************/ +typedef union +{ + _sendRecvCommand_t Cmd; + _SocketAddrResponse_u Rsp; +}_SlRecvfromMsg_u; + +const _SlCmdCtrl_t _SlRecvfomCmdCtrl = +{ + SL_OPCODE_SOCKET_RECVFROM, + sizeof(_sendRecvCommand_t), + sizeof(_SocketAddrResponse_u) +}; + + + +#if _SL_INCLUDE_FUNC(sl_RecvFrom) +_i16 sl_RecvFrom(_i16 sd, void *buf, _i16 Len, _i16 flags, SlSockAddr_t *from, SlSocklen_t *fromlen) +{ + _SlRecvfromMsg_u Msg; + _SlCmdExt_t CmdExt; + _i16 RetVal; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = Len; + CmdExt.pRxPayload = (_u8 *)buf; + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.StatusOrLen = Len; + /* no size truncation in recv path */ + CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen; + + + Msg.Cmd.FamilyAndFlags = flags & 0x0F; + + + if(sizeof(SlSockAddrIn_t) == *fromlen) + { + Msg.Cmd.FamilyAndFlags |= (SL_AF_INET << 4); + } + else if (sizeof(SlSockAddrIn6_t) == *fromlen) + { + Msg.Cmd.FamilyAndFlags |= (SL_AF_INET6 << 4); + } + else + { + return SL_RET_CODE_INVALID_INPUT; + } + + RetVal = _SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvfomCmdCtrl, &Msg, &CmdExt); + if( RetVal != SL_OS_RET_CODE_OK ) + { + return RetVal; + } + + RetVal = Msg.Rsp.IpV4.statusOrLen; + + if(RetVal >= 0) + { + VERIFY_PROTOCOL(sd == Msg.Rsp.IpV4.sd); +#if 0 + _sl_ParseAddress(&Msg.Rsp, from, fromlen); +#else + from->sa_family = Msg.Rsp.IpV4.family; + if(SL_AF_INET == from->sa_family) + { + ((SlSockAddrIn_t *)from)->sin_port = Msg.Rsp.IpV4.port; + ((SlSockAddrIn_t *)from)->sin_addr.s_addr = Msg.Rsp.IpV4.address; + *fromlen = sizeof(SlSockAddrIn_t); + } + else if (SL_AF_INET6_EUI_48 == from->sa_family ) + { + ((SlSockAddrIn6_t *)from)->sin6_port = Msg.Rsp.IpV6EUI48.port; + sl_Memcpy(((SlSockAddrIn6_t *)from)->sin6_addr._S6_un._S6_u8, Msg.Rsp.IpV6EUI48.address, 6); + } +#ifdef SL_SUPPORT_IPV6 + else if(AF_INET6 == from->sa_family) + { + VERIFY_PROTOCOL(*fromlen >= sizeof(sockaddr_in6)); + + ((sockaddr_in6 *)from)->sin6_port = Msg.Rsp.IpV6.port; + sl_Memcpy(((sockaddr_in6 *)from)->sin6_addr._S6_un._S6_u32, Msg.Rsp.IpV6.address, 16); + *fromlen = sizeof(sockaddr_in6); + } +#endif +#endif + } + + return (_i16)RetVal; +} +#endif + +/*******************************************************************************/ +/* sl_Connect */ +/*******************************************************************************/ +typedef union +{ + _SocketAddrCommand_u Cmd; + _SocketResponse_t Rsp; +}_SlSockConnectMsg_u; + +#if _SL_INCLUDE_FUNC(sl_Connect) +_i16 sl_Connect(_i16 sd, const SlSockAddr_t *addr, _i16 addrlen) +{ + _SlSockConnectMsg_u Msg; + _SlReturnVal_t RetVal; + _SlCmdCtrl_t CmdCtrl = {0, 0, sizeof(_SocketResponse_t)}; + _SocketResponse_t AsyncRsp; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + + + switch(addr->sa_family) + { + case SL_AF_INET : + CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv4Command_t); + /* Do nothing - cmd already initialized to this type */ + break; + case SL_AF_INET6_EUI_48: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6EUI48Command_t); + break; +#ifdef SL_SUPPORT_IPV6 + case AF_INET6: + CmdCtrl.Opcode = SL_OPCODE_SOCKET_CONNECT_V6; + CmdCtrl.TxDescLen = sizeof(_SocketAddrIPv6Command_t); + break; +#endif + case SL_AF_RF: + default: + return SL_RET_CODE_INVALID_INPUT; + } + + Msg.Cmd.IpV4.lenOrPadding = 0; + Msg.Cmd.IpV4.sd = (_u8)sd; + + _sl_BuildAddress(addr, &Msg.Cmd); + + + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, CONNECT_ID, sd & BSD_SOCKET_ID_MASK); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + /* send the command */ + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, &Msg, NULL)); + VERIFY_PROTOCOL(Msg.Rsp.sd == sd) + + RetVal = Msg.Rsp.statusOrLen; + + if(SL_RET_CODE_OK == RetVal) + { + /* wait for async and get Data Read parameters */ + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + VERIFY_PROTOCOL(AsyncRsp.sd == sd); + + RetVal = AsyncRsp.statusOrLen; + } + + + + _SlDrvReleasePoolObj(ObjIdx); + return RetVal; +} + +#endif + + +/*******************************************************************************/ +/* _sl_HandleAsync_Connect */ +/*******************************************************************************/ +void _sl_HandleAsync_Connect(void *pVoidBuf) +{ + _SocketResponse_t *pMsgArgs = (_SocketResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + + _SlDrvProtectionObjLockWaitForever(); + + VERIFY_PROTOCOL((pMsgArgs->sd & BSD_SOCKET_ID_MASK) <= SL_MAX_SOCKETS); + VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs); + + + ((_SocketResponse_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->sd = pMsgArgs->sd; + ((_SocketResponse_t *)(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs))->statusOrLen = pMsgArgs->statusOrLen; + + + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + _SlDrvProtectionObjUnLock(); + return; +} + +/*******************************************************************************/ +/* sl_Send */ +/*******************************************************************************/ +typedef union +{ + _sendRecvCommand_t Cmd; + /* no response for 'sendto' commands*/ +}_SlSendMsg_u; + +const _SlCmdCtrl_t _SlSendCmdCtrl = +{ + SL_OPCODE_SOCKET_SEND, + sizeof(_sendRecvCommand_t), + 0 +}; + +#if _SL_INCLUDE_FUNC(sl_Send) +_i16 sl_Send(_i16 sd, const void *pBuf, _i16 Len, _i16 flags) +{ + _SlSendMsg_u Msg; + _SlCmdExt_t CmdExt; + _u16 ChunkLen; + _i16 RetVal; + _u32 tempVal; + _u8 runSingleChunk = FALSE; + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = Len; + CmdExt.pTxPayload = (_u8 *)pBuf; + + /* Only for RAW transceiver type socket, relay the flags parameter in the 2 bytes (4 byte aligned) before the actual payload */ + if ((sd & SL_SOCKET_PAYLOAD_TYPE_MASK) == SL_SOCKET_PAYLOAD_TYPE_RAW_TRANCEIVER) + { + tempVal = flags; + CmdExt.pRxPayload = (_u8 *)&tempVal; + CmdExt.RxPayloadLen = -4; /* mark as Rx data to send */ + runSingleChunk = TRUE; + } + else + { + CmdExt.pRxPayload = NULL; + } + + ChunkLen = _sl_TruncatePayloadByProtocol(sd,Len); + CmdExt.TxPayloadLen = ChunkLen; + Msg.Cmd.StatusOrLen = ChunkLen; + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.FamilyAndFlags |= flags & 0x0F; + + do + { + RetVal = _SlDrvDataWriteOp((_u8)sd, (_SlCmdCtrl_t *)&_SlSendCmdCtrl, &Msg, &CmdExt); + if(SL_OS_RET_CODE_OK == RetVal) + { + CmdExt.pTxPayload += ChunkLen; + ChunkLen = (_u8 *)pBuf + Len - CmdExt.pTxPayload; + ChunkLen = _sl_TruncatePayloadByProtocol(sd,ChunkLen); + CmdExt.TxPayloadLen = ChunkLen; + Msg.Cmd.StatusOrLen = ChunkLen; + } + else + { + return RetVal; + } + }while((ChunkLen > 0) && (runSingleChunk==FALSE)); + + return (_i16)Len; +} +#endif + +/*******************************************************************************/ +/* sl_Listen */ +/*******************************************************************************/ +typedef union +{ + _ListenCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlListenMsg_u; + + + +#if _SL_INCLUDE_FUNC(sl_Listen) + +const _SlCmdCtrl_t _SlListenCmdCtrl = +{ + SL_OPCODE_SOCKET_LISTEN, + sizeof(_ListenCommand_t), + sizeof(_BasicResponse_t), +}; + +_i16 sl_Listen(_i16 sd, _i16 backlog) +{ + _SlListenMsg_u Msg; + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.backlog = (_u8)backlog; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlListenCmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif + +/*******************************************************************************/ +/* sl_Accept */ +/*******************************************************************************/ +typedef union +{ + _AcceptCommand_t Cmd; + _SocketResponse_t Rsp; +}_SlSockAcceptMsg_u; + + + +#if _SL_INCLUDE_FUNC(sl_Accept) + +const _SlCmdCtrl_t _SlAcceptCmdCtrl = +{ + SL_OPCODE_SOCKET_ACCEPT, + sizeof(_AcceptCommand_t), + sizeof(_BasicResponse_t), +}; + +_i16 sl_Accept(_i16 sd, SlSockAddr_t *addr, SlSocklen_t *addrlen) +{ + _SlSockAcceptMsg_u Msg; + _SlReturnVal_t RetVal; + _SocketAddrResponse_u AsyncRsp; + + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.family = (sizeof(SlSockAddrIn_t) == *addrlen) ? SL_AF_INET : SL_AF_INET6; + + + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, ACCEPT_ID, sd & BSD_SOCKET_ID_MASK ); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + /* send the command */ + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlAcceptCmdCtrl, &Msg, NULL)); + VERIFY_PROTOCOL(Msg.Rsp.sd == sd); + + RetVal = Msg.Rsp.statusOrLen; + + if(SL_OS_RET_CODE_OK == RetVal) + { + /* wait for async and get Data Read parameters */ + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + VERIFY_PROTOCOL(AsyncRsp.IpV4.sd == sd); + + RetVal = AsyncRsp.IpV4.statusOrLen; + if( (NULL != addr) && (NULL != addrlen) ) + { +#if 0 /* Kept for backup */ + _sl_ParseAddress(&AsyncRsp, addr, addrlen); +#else + addr->sa_family = AsyncRsp.IpV4.family; + + if(SL_AF_INET == addr->sa_family) + { + if( *addrlen == sizeof( SlSockAddrIn_t ) ) + { + ((SlSockAddrIn_t *)addr)->sin_port = AsyncRsp.IpV4.port; + ((SlSockAddrIn_t *)addr)->sin_addr.s_addr = AsyncRsp.IpV4.address; + } + else + { + *addrlen = 0; + } + } + else if (SL_AF_INET6_EUI_48 == addr->sa_family ) + { + if( *addrlen == sizeof( SlSockAddrIn6_t ) ) + { + ((SlSockAddrIn6_t *)addr)->sin6_port = AsyncRsp.IpV6EUI48.port ; + /* will be called from here and from _sl_BuildAddress*/ + sl_Memcpy(((SlSockAddrIn6_t *)addr)->sin6_addr._S6_un._S6_u8, AsyncRsp.IpV6EUI48.address, 6); + } + else + { + *addrlen = 0; + } + } +#ifdef SL_SUPPORT_IPV6 + else + { + if( *addrlen == sizeof( sockaddr_in6 ) ) + { + ((sockaddr_in6 *)addr)->sin6_port = AsyncRsp.IpV6.port ; + sl_Memcpy(((sockaddr_in6 *)addr)->sin6_addr._S6_un._S6_u32, AsyncRsp.IpV6.address, 16); + } + else + { + *addrlen = 0; + } + } +#endif +#endif + } + } + + _SlDrvReleasePoolObj(ObjIdx); + return (_i16)RetVal; +} +#endif + + +/*******************************************************************************/ +/* sl_Htonl */ +/*******************************************************************************/ +_u32 sl_Htonl( _u32 val ) +{ + _u32 i = 1; + _i8 *p = (_i8 *)&i; + if (p[0] == 1) /* little endian */ + { + p[0] = ((_i8* )&val)[3]; + p[1] = ((_i8* )&val)[2]; + p[2] = ((_i8* )&val)[1]; + p[3] = ((_i8* )&val)[0]; + return i; + } + else /* big endian */ + { + return val; + } +} + +/*******************************************************************************/ +/* sl_Htonl */ +/*******************************************************************************/ +_u16 sl_Htons( _u16 val ) +{ + _i16 i = 1; + _i8 *p = (_i8 *)&i; + if (p[0] == 1) /* little endian */ + { + p[0] = ((_i8* )&val)[1]; + p[1] = ((_i8* )&val)[0]; + return i; + } + else /* big endian */ + { + return val; + } +} + +/*******************************************************************************/ +/* _sl_HandleAsync_Accept */ +/*******************************************************************************/ +#ifndef SL_TINY_EXT +void _sl_HandleAsync_Accept(void *pVoidBuf) +{ + _SocketAddrResponse_u *pMsgArgs = (_SocketAddrResponse_u *)_SL_RESP_ARGS_START(pVoidBuf); + + _SlDrvProtectionObjLockWaitForever(); + + VERIFY_PROTOCOL(( pMsgArgs->IpV4.sd & BSD_SOCKET_ID_MASK) <= SL_MAX_SOCKETS); + VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs); + + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs,sizeof(_SocketAddrResponse_u)); + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + + _SlDrvProtectionObjUnLock(); + return; +} + +/*******************************************************************************/ +/* _sl_HandleAsync_Select */ +/*******************************************************************************/ +void _sl_HandleAsync_Select(void *pVoidBuf) +{ + _SelectAsyncResponse_t *pMsgArgs = (_SelectAsyncResponse_t *)_SL_RESP_ARGS_START(pVoidBuf); + + _SlDrvProtectionObjLockWaitForever(); + + VERIFY_SOCKET_CB(NULL != g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs); + + sl_Memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(_SelectAsyncResponse_t)); + + _SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + _SlDrvProtectionObjUnLock(); + + return; +} + +#endif + +/*******************************************************************************/ +/* sl_Recv */ +/*******************************************************************************/ +typedef union +{ + _sendRecvCommand_t Cmd; + _SocketResponse_t Rsp; +}_SlRecvMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_Recv) + +const _SlCmdCtrl_t _SlRecvCmdCtrl = +{ + SL_OPCODE_SOCKET_RECV, + sizeof(_sendRecvCommand_t), + sizeof(_SocketResponse_t) +}; + + +_i16 sl_Recv(_i16 sd, void *pBuf, _i16 Len, _i16 flags) +{ + _SlRecvMsg_u Msg; + _SlCmdExt_t CmdExt; + _SlReturnVal_t status; + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = Len; + CmdExt.pRxPayload = (_u8 *)pBuf; + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.StatusOrLen = Len; + + /* no size truncation in recv path */ + CmdExt.RxPayloadLen = Msg.Cmd.StatusOrLen; + + Msg.Cmd.FamilyAndFlags = flags & 0x0F; + + status = _SlDrvDataReadOp((_SlSd_t)sd, (_SlCmdCtrl_t *)&_SlRecvCmdCtrl, &Msg, &CmdExt); + if( status != SL_OS_RET_CODE_OK ) + { + return status; + } + + /* if the Device side sends less than expected it is not the Driver's role */ + /* the returned value could be smaller than the requested size */ + return (_i16)Msg.Rsp.statusOrLen; +} +#endif + +/*******************************************************************************/ +/* sl_SetSockOpt */ +/*******************************************************************************/ +typedef union +{ + _setSockOptCommand_t Cmd; + _SocketResponse_t Rsp; +}_SlSetSockOptMsg_u; + +const _SlCmdCtrl_t _SlSetSockOptCmdCtrl = +{ + SL_OPCODE_SOCKET_SETSOCKOPT, + sizeof(_setSockOptCommand_t), + sizeof(_SocketResponse_t) +}; + +#if _SL_INCLUDE_FUNC(sl_SetSockOpt) +_i16 sl_SetSockOpt(_i16 sd, _i16 level, _i16 optname, const void *optval, SlSocklen_t optlen) +{ + _SlSetSockOptMsg_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = optlen; + CmdExt.pTxPayload = (_u8 *)optval; + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.level = (_u8)level; + Msg.Cmd.optionLen = (_u8)optlen; + Msg.Cmd.optionName = (_u8)optname; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSetSockOptCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.statusOrLen; +} +#endif + +/*******************************************************************************/ +/* sl_GetSockOpt */ +/*******************************************************************************/ +typedef union +{ + _getSockOptCommand_t Cmd; + _getSockOptResponse_t Rsp; +}_SlGetSockOptMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_GetSockOpt) + +const _SlCmdCtrl_t _SlGetSockOptCmdCtrl = +{ + SL_OPCODE_SOCKET_GETSOCKOPT, + sizeof(_getSockOptCommand_t), + sizeof(_getSockOptResponse_t) +}; + +_i16 sl_GetSockOpt(_i16 sd, _i16 level, _i16 optname, void *optval, SlSocklen_t *optlen) +{ + _SlGetSockOptMsg_u Msg; + _SlCmdExt_t CmdExt; + + if (*optlen == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *optlen; + CmdExt.pRxPayload = optval; + + Msg.Cmd.sd = (_u8)sd; + Msg.Cmd.level = (_u8)level; + Msg.Cmd.optionLen = (_u8)(*optlen); + Msg.Cmd.optionName = (_u8)optname; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlGetSockOptCmdCtrl, &Msg, &CmdExt)); + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *optlen = Msg.Rsp.optionLen; + return SL_ESMALLBUF; + } + else + { + *optlen = (_u8)CmdExt.ActualRxPayloadLen; + } + return (_i16)Msg.Rsp.status; +} +#endif + +/*******************************************************************************/ +/* sl_Select */ +/* ******************************************************************************/ +typedef union +{ + _SelectCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlSelectMsg_u; + + + +#ifndef SL_TINY_EXT +#if _SL_INCLUDE_FUNC(sl_Select) + +const _SlCmdCtrl_t _SlSelectCmdCtrl = +{ + SL_OPCODE_SOCKET_SELECT, + sizeof(_SelectCommand_t), + sizeof(_BasicResponse_t) +}; + + +_i16 sl_Select(_i16 nfds, SlFdSet_t *readsds, SlFdSet_t *writesds, SlFdSet_t *exceptsds, struct SlTimeval_t *timeout) +{ + _SlSelectMsg_u Msg; + _SelectAsyncResponse_t AsyncRsp; + _u8 ObjIdx = MAX_CONCURRENT_ACTIONS; + + Msg.Cmd.nfds = (_u8)nfds; + Msg.Cmd.readFdsCount = 0; + Msg.Cmd.writeFdsCount = 0; + + Msg.Cmd.readFds = 0; + Msg.Cmd.writeFds = 0; + + + if( readsds ) + { + Msg.Cmd.readFds = (_u16)readsds->fd_array[0]; + } + if( writesds ) + { + Msg.Cmd.writeFds = (_u16)writesds->fd_array[0]; + } + if( NULL == timeout ) + { + Msg.Cmd.tv_sec = 0xffff; + Msg.Cmd.tv_usec = 0xffff; + } + else + { + if( 0xffff <= timeout->tv_sec ) + { + Msg.Cmd.tv_sec = 0xffff; + } + else + { + Msg.Cmd.tv_sec = (_u16)timeout->tv_sec; + } + timeout->tv_usec = timeout->tv_usec >> 10; /* convert to milliseconds */ + if( 0xffff <= timeout->tv_usec ) + { + Msg.Cmd.tv_usec = 0xffff; + } + else + { + Msg.Cmd.tv_usec = (_u16)timeout->tv_usec; + } + } + + /* Use Obj to issue the command, if not available try later */ + ObjIdx = _SlDrvProtectAsyncRespSetting((_u8*)&AsyncRsp, SELECT_ID, SL_MAX_SOCKETS); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + + /* send the command */ + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSelectCmdCtrl, &Msg, NULL)); + + if(SL_OS_RET_CODE_OK == (_i16)Msg.Rsp.status) + { + _SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + Msg.Rsp.status = AsyncRsp.status; + + if( ((_i16)Msg.Rsp.status) >= 0 ) + { + if( readsds ) + { + readsds->fd_array[0] = AsyncRsp.readFds; + } + if( writesds ) + { + writesds->fd_array[0] = AsyncRsp.writeFds; + } + } + } + + _SlDrvReleasePoolObj(ObjIdx); + return (_i16)Msg.Rsp.status; +} + +/* Select helper functions */ +/*******************************************************************************/ +/* SL_FD_SET */ +/* ******************************************************************************/ +void SL_FD_SET(_i16 fd, SlFdSet_t *fdset) +{ + fdset->fd_array[0] |= (1<< (fd & BSD_SOCKET_ID_MASK)); +} +/*******************************************************************************/ +/* SL_FD_CLR */ +/*******************************************************************************/ +void SL_FD_CLR(_i16 fd, SlFdSet_t *fdset) +{ + fdset->fd_array[0] &= ~(1<< (fd & BSD_SOCKET_ID_MASK)); +} +/*******************************************************************************/ +/* SL_FD_ISSET */ +/*******************************************************************************/ +_i16 SL_FD_ISSET(_i16 fd, SlFdSet_t *fdset) +{ + if( fdset->fd_array[0] & (1<< (fd & BSD_SOCKET_ID_MASK)) ) + { + return 1; + } + return 0; +} +/*******************************************************************************/ +/* SL_FD_ZERO */ +/*******************************************************************************/ +void SL_FD_ZERO(SlFdSet_t *fdset) +{ + fdset->fd_array[0] = 0; +} + +#endif +#endif + + + diff --git a/src/openmv/src/micropython/drivers/cc3100/src/spawn.c b/src/openmv/src/micropython/drivers/cc3100/src/spawn.c new file mode 100755 index 0000000..bb55758 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/spawn.c @@ -0,0 +1,197 @@ +/* + * spawn.c - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" + + +#if (defined (SL_PLATFORM_MULTI_THREADED)) && (!defined (SL_PLATFORM_EXTERNAL_SPAWN)) + +#define _SL_MAX_INTERNAL_SPAWN_ENTRIES 10 + +typedef struct _SlInternalSpawnEntry_t +{ + _SlSpawnEntryFunc_t pEntry; + void* pValue; + struct _SlInternalSpawnEntry_t* pNext; +}_SlInternalSpawnEntry_t; + +typedef struct +{ + _SlInternalSpawnEntry_t SpawnEntries[_SL_MAX_INTERNAL_SPAWN_ENTRIES]; + _SlInternalSpawnEntry_t* pFree; + _SlInternalSpawnEntry_t* pWaitForExe; + _SlInternalSpawnEntry_t* pLastInWaitList; + _SlSyncObj_t SyncObj; + _SlLockObj_t LockObj; +}_SlInternalSpawnCB_t; + +_SlInternalSpawnCB_t g_SlInternalSpawnCB; + + +void _SlInternalSpawnTaskEntry() +{ + _i16 i; + _SlInternalSpawnEntry_t* pEntry; + _u8 LastEntry; + + /* create and lock the locking object. lock in order to avoid race condition + on the first creation */ + sl_LockObjCreate(&g_SlInternalSpawnCB.LockObj,"SlSpawnProtect"); + sl_LockObjLock(&g_SlInternalSpawnCB.LockObj,SL_OS_NO_WAIT); + + /* create and clear the sync object */ + sl_SyncObjCreate(&g_SlInternalSpawnCB.SyncObj,"SlSpawnSync"); + sl_SyncObjWait(&g_SlInternalSpawnCB.SyncObj,SL_OS_NO_WAIT); + + g_SlInternalSpawnCB.pFree = &g_SlInternalSpawnCB.SpawnEntries[0]; + g_SlInternalSpawnCB.pWaitForExe = NULL; + g_SlInternalSpawnCB.pLastInWaitList = NULL; + + /* create the link list between the entries */ + for (i=0 ; i<_SL_MAX_INTERNAL_SPAWN_ENTRIES - 1 ; i++) + { + g_SlInternalSpawnCB.SpawnEntries[i].pNext = &g_SlInternalSpawnCB.SpawnEntries[i+1]; + g_SlInternalSpawnCB.SpawnEntries[i].pEntry = NULL; + } + g_SlInternalSpawnCB.SpawnEntries[i].pNext = NULL; + + _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj); + + /* here we ready to execute entries */ + + while (TRUE) + { + sl_SyncObjWait(&g_SlInternalSpawnCB.SyncObj,SL_OS_WAIT_FOREVER); + /* go over all entries that already waiting for execution */ + LastEntry = FALSE; + do + { + /* get entry to execute */ + _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj); + + pEntry = g_SlInternalSpawnCB.pWaitForExe; + if ( NULL == pEntry ) + { + _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj); + break; + } + g_SlInternalSpawnCB.pWaitForExe = pEntry->pNext; + if (pEntry == g_SlInternalSpawnCB.pLastInWaitList) + { + g_SlInternalSpawnCB.pLastInWaitList = NULL; + LastEntry = TRUE; + } + + _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj); + + /* pEntry could be null in case that the sync was already set by some + of the entries during execution of earlier entry */ + if (NULL != pEntry) + { + pEntry->pEntry(pEntry->pValue); + /* free the entry */ + + _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj); + + pEntry->pNext = g_SlInternalSpawnCB.pFree; + g_SlInternalSpawnCB.pFree = pEntry; + + + if (NULL != g_SlInternalSpawnCB.pWaitForExe) + { + /* new entry received meanwhile */ + LastEntry = FALSE; + } + + _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj); + + } + + }while (!LastEntry); + } +} + + +_i16 _SlInternalSpawn(_SlSpawnEntryFunc_t pEntry , void* pValue , _u32 flags) +{ + _i16 Res = 0; + _SlInternalSpawnEntry_t* pSpawnEntry; + + if (NULL == pEntry) + { + Res = -1; + } + else + { + _SlDrvObjLockWaitForever(&g_SlInternalSpawnCB.LockObj); + + pSpawnEntry = g_SlInternalSpawnCB.pFree; + g_SlInternalSpawnCB.pFree = pSpawnEntry->pNext; + + pSpawnEntry->pEntry = pEntry; + pSpawnEntry->pValue = pValue; + pSpawnEntry->pNext = NULL; + + if (NULL == g_SlInternalSpawnCB.pWaitForExe) + { + g_SlInternalSpawnCB.pWaitForExe = pSpawnEntry; + g_SlInternalSpawnCB.pLastInWaitList = pSpawnEntry; + } + else + { + g_SlInternalSpawnCB.pLastInWaitList->pNext = pSpawnEntry; + g_SlInternalSpawnCB.pLastInWaitList = pSpawnEntry; + } + + _SlDrvObjUnLock(&g_SlInternalSpawnCB.LockObj); + + /* this sync is called after releasing the lock object to avoid unnecessary context switches */ + _SlDrvSyncObjSignal(&g_SlInternalSpawnCB.SyncObj); + } + + return Res; +} + + + + + +#endif diff --git a/src/openmv/src/micropython/drivers/cc3100/src/wlan.c b/src/openmv/src/micropython/drivers/cc3100/src/wlan.c new file mode 100755 index 0000000..59adf02 --- /dev/null +++ b/src/openmv/src/micropython/drivers/cc3100/src/wlan.c @@ -0,0 +1,1006 @@ +/* +* wlan.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of Texas Instruments Incorporated 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 +* OWNER 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 files */ +/*****************************************************************************/ +#include "simplelink.h" +#include "protocol.h" +#include "driver.h" + +/*****************************************************************************/ +/* Macro declarations */ +/*****************************************************************************/ +#define MAX_SSID_LEN (32) +#define MAX_KEY_LEN (63) +#define MAX_USER_LEN (32) +#define MAX_ANON_USER_LEN (32) +#define MAX_SMART_CONFIG_KEY (16) + + +/***************************************************************************** +sl_WlanConnect +*****************************************************************************/ +typedef struct +{ + _WlanConnectEapCommand_t Args; + _i8 Strings[MAX_SSID_LEN + MAX_KEY_LEN + MAX_USER_LEN + MAX_ANON_USER_LEN]; +}_WlanConnectCmd_t; + +typedef union +{ + _WlanConnectCmd_t Cmd; + _BasicResponse_t Rsp; +}_SlWlanConnectMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_WlanConnect) +_i16 sl_WlanConnect(const _i8* pName,const _i16 NameLen,const _u8 *pMacAddr,const SlSecParams_t* pSecParams ,const SlSecParamsExt_t* pSecExtParams) +{ + _SlWlanConnectMsg_u Msg; + _SlCmdCtrl_t CmdCtrl; + + sl_Memset (&Msg, 0, sizeof(Msg)); + + CmdCtrl.TxDescLen = 0;/* init */ + CmdCtrl.RxDescLen = sizeof(_BasicResponse_t); + + /* verify SSID length */ + VERIFY_PROTOCOL(NameLen <= MAX_SSID_LEN); + /* verify SSID is not NULL */ + if( NULL == pName ) + { + return SL_INVALPARAM; + } + /* update SSID length */ + Msg.Cmd.Args.Common.SsidLen = (_u8)NameLen; + + /* Profile with no security */ + /* Enterprise security profile */ + if (NULL != pSecExtParams) + { + /* Update command opcode */ + CmdCtrl.Opcode = SL_OPCODE_WLAN_WLANCONNECTEAPCOMMAND; + CmdCtrl.TxDescLen += sizeof(_WlanConnectEapCommand_t); + /* copy SSID */ + sl_Memcpy(EAP_SSID_STRING(&Msg), pName, NameLen); + CmdCtrl.TxDescLen += NameLen; + /* Copy password if supplied */ + if ((NULL != pSecParams) && (pSecParams->KeyLen > 0)) + { + /* update security type */ + Msg.Cmd.Args.Common.SecType = pSecParams->Type; + /* verify key length */ + if (pSecParams->KeyLen > MAX_KEY_LEN) + { + return SL_INVALPARAM; + } + /* update key length */ + Msg.Cmd.Args.Common.PasswordLen = pSecParams->KeyLen; + ARG_CHECK_PTR(pSecParams->Key); + /* copy key */ + sl_Memcpy(EAP_PASSWORD_STRING(&Msg), pSecParams->Key, pSecParams->KeyLen); + CmdCtrl.TxDescLen += pSecParams->KeyLen; + } + else + { + Msg.Cmd.Args.Common.PasswordLen = 0; + } + + ARG_CHECK_PTR(pSecExtParams); + /* Update Eap bitmask */ + Msg.Cmd.Args.EapBitmask = pSecExtParams->EapMethod; + /* Update Certificate file ID index - currently not supported */ + Msg.Cmd.Args.CertIndex = pSecExtParams->CertIndex; + /* verify user length */ + if (pSecExtParams->UserLen > MAX_USER_LEN) + { + return SL_INVALPARAM; + } + Msg.Cmd.Args.UserLen = pSecExtParams->UserLen; + /* copy user name (identity) */ + if(pSecExtParams->UserLen > 0) + { + sl_Memcpy(EAP_USER_STRING(&Msg), pSecExtParams->User, pSecExtParams->UserLen); + CmdCtrl.TxDescLen += pSecExtParams->UserLen; + } + /* verify Anonymous user length */ + if (pSecExtParams->AnonUserLen > MAX_ANON_USER_LEN) + { + return SL_INVALPARAM; + } + Msg.Cmd.Args.AnonUserLen = pSecExtParams->AnonUserLen; + /* copy Anonymous user */ + if(pSecExtParams->AnonUserLen > 0) + { + sl_Memcpy(EAP_ANON_USER_STRING(&Msg), pSecExtParams->AnonUser, pSecExtParams->AnonUserLen); + CmdCtrl.TxDescLen += pSecExtParams->AnonUserLen; + } + + } + + /* Regular or open security profile */ + else + { + /* Update command opcode */ + CmdCtrl.Opcode = SL_OPCODE_WLAN_WLANCONNECTCOMMAND; + CmdCtrl.TxDescLen += sizeof(_WlanConnectCommon_t); + /* copy SSID */ + sl_Memcpy(SSID_STRING(&Msg), pName, NameLen); + CmdCtrl.TxDescLen += NameLen; + /* Copy password if supplied */ + if( NULL != pSecParams ) + { + /* update security type */ + Msg.Cmd.Args.Common.SecType = pSecParams->Type; + /* verify key length is valid */ + if (pSecParams->KeyLen > MAX_KEY_LEN) + { + return SL_INVALPARAM; + } + /* update key length */ + Msg.Cmd.Args.Common.PasswordLen = pSecParams->KeyLen; + CmdCtrl.TxDescLen += pSecParams->KeyLen; + /* copy key (could be no key in case of WPS pin) */ + if( NULL != pSecParams->Key ) + { + sl_Memcpy(PASSWORD_STRING(&Msg), pSecParams->Key, pSecParams->KeyLen); + } + } + /* Profile with no security */ + else + { + Msg.Cmd.Args.Common.PasswordLen = 0; + Msg.Cmd.Args.Common.SecType = SL_SEC_TYPE_OPEN; + } + } + /* If BSSID is not null, copy to buffer, otherwise set to 0 */ + if(NULL != pMacAddr) + { + sl_Memcpy(Msg.Cmd.Args.Common.Bssid, pMacAddr, sizeof(Msg.Cmd.Args.Common.Bssid)); + } + else + { + _SlDrvMemZero(Msg.Cmd.Args.Common.Bssid, sizeof(Msg.Cmd.Args.Common.Bssid)); + } + + + VERIFY_RET_OK ( _SlDrvCmdOp(&CmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif + +/*******************************************************************************/ +/* sl_Disconnect */ +/* ******************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_WlanDisconnect) +_i16 sl_WlanDisconnect(void) +{ + return _SlDrvBasicCmd(SL_OPCODE_WLAN_WLANDISCONNECTCOMMAND); +} +#endif + +/******************************************************************************/ +/* sl_PolicySet */ +/******************************************************************************/ +typedef union +{ + _WlanPoliciySetGet_t Cmd; + _BasicResponse_t Rsp; +}_SlPolicyMsg_u; + +#if _SL_INCLUDE_FUNC(sl_WlanPolicySet) + +const _SlCmdCtrl_t _SlPolicySetCmdCtrl = +{ + SL_OPCODE_WLAN_POLICYSETCOMMAND, + sizeof(_WlanPoliciySetGet_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_WlanPolicySet(const _u8 Type , const _u8 Policy, _u8 *pVal,const _u8 ValLen) +{ + _SlPolicyMsg_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = ValLen; + CmdExt.pTxPayload = (_u8 *)pVal; + + + Msg.Cmd.PolicyType = Type; + Msg.Cmd.PolicyOption = Policy; + Msg.Cmd.PolicyOptionLen = ValLen; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlPolicySetCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; +} +#endif + + +/******************************************************************************/ +/* sl_PolicyGet */ +/******************************************************************************/ +typedef union +{ + _WlanPoliciySetGet_t Cmd; + _WlanPoliciySetGet_t Rsp; +}_SlPolicyGetMsg_u; + +#if _SL_INCLUDE_FUNC(sl_WlanPolicyGet) + +const _SlCmdCtrl_t _SlPolicyGetCmdCtrl = +{ + SL_OPCODE_WLAN_POLICYGETCOMMAND, + sizeof(_WlanPoliciySetGet_t), + sizeof(_WlanPoliciySetGet_t) +}; + +_i16 sl_WlanPolicyGet(const _u8 Type ,_u8 Policy,_u8 *pVal,_u8 *pValLen) +{ + _SlPolicyGetMsg_u Msg; + _SlCmdExt_t CmdExt; + + if (*pValLen == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pValLen; + CmdExt.pRxPayload = pVal; + + Msg.Cmd.PolicyType = Type; + Msg.Cmd.PolicyOption = Policy; + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlPolicyGetCmdCtrl, &Msg, &CmdExt)); + + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *pValLen = Msg.Rsp.PolicyOptionLen; + return SL_ESMALLBUF; + } + else + { + /* no pointer valus, fill the results into _i8 */ + *pValLen = (_u8)CmdExt.ActualRxPayloadLen; + if( 0 == CmdExt.ActualRxPayloadLen ) + { + *pValLen = 1; + pVal[0] = Msg.Rsp.PolicyOption; + } + } + return (_i16)SL_OS_RET_CODE_OK; +} +#endif + + +/*******************************************************************************/ +/* sl_ProfileAdd */ +/*******************************************************************************/ +typedef struct +{ + _WlanAddGetEapProfile_t Args; + _i8 Strings[MAX_SSID_LEN + MAX_KEY_LEN + MAX_USER_LEN + MAX_ANON_USER_LEN]; +}_SlProfileParams_t; + +typedef union +{ + _SlProfileParams_t Cmd; + _BasicResponse_t Rsp; +}_SlProfileAddMsg_u; + + + +#if _SL_INCLUDE_FUNC(sl_WlanProfileAdd) +_i16 sl_WlanProfileAdd(const _i8* pName,const _i16 NameLen,const _u8 *pMacAddr,const SlSecParams_t* pSecParams ,const SlSecParamsExt_t* pSecExtParams,const _u32 Priority,const _u32 Options) +{ + _SlProfileAddMsg_u Msg; + _SlCmdCtrl_t CmdCtrl = {0}; + CmdCtrl.TxDescLen = 0;/* init */ + CmdCtrl.RxDescLen = sizeof(_BasicResponse_t); + + /* update priority */ + Msg.Cmd.Args.Common.Priority = (_u8)Priority; + /* verify SSID is not NULL */ + if( NULL == pName ) + { + return SL_INVALPARAM; + } + /* verify SSID length */ + VERIFY_PROTOCOL(NameLen <= MAX_SSID_LEN); + /* update SSID length */ + Msg.Cmd.Args.Common.SsidLen = (_u8)NameLen; + + + /* Enterprise security profile */ + if (NULL != pSecExtParams) + { + /* Update command opcode */ + CmdCtrl.Opcode = SL_OPCODE_WLAN_EAP_PROFILEADDCOMMAND; + CmdCtrl.TxDescLen += sizeof(_WlanAddGetEapProfile_t); + + /* copy SSID */ + sl_Memcpy(EAP_PROFILE_SSID_STRING(&Msg), pName, NameLen); + CmdCtrl.TxDescLen += NameLen; + + /* Copy password if supplied */ + if ((NULL != pSecParams) && (pSecParams->KeyLen > 0)) + { + /* update security type */ + Msg.Cmd.Args.Common.SecType = pSecParams->Type; + + if( SL_SEC_TYPE_WEP == Msg.Cmd.Args.Common.SecType ) + { + Msg.Cmd.Args.Common.WepKeyId = 0; + } + + /* verify key length */ + if (pSecParams->KeyLen > MAX_KEY_LEN) + { + return SL_INVALPARAM; + } + VERIFY_PROTOCOL(pSecParams->KeyLen <= MAX_KEY_LEN); + /* update key length */ + Msg.Cmd.Args.Common.PasswordLen = pSecParams->KeyLen; + CmdCtrl.TxDescLen += pSecParams->KeyLen; + ARG_CHECK_PTR(pSecParams->Key); + /* copy key */ + sl_Memcpy(EAP_PROFILE_PASSWORD_STRING(&Msg), pSecParams->Key, pSecParams->KeyLen); + } + else + { + Msg.Cmd.Args.Common.PasswordLen = 0; + } + + ARG_CHECK_PTR(pSecExtParams); + /* Update Eap bitmask */ + Msg.Cmd.Args.EapBitmask = pSecExtParams->EapMethod; + /* Update Certificate file ID index - currently not supported */ + Msg.Cmd.Args.CertIndex = pSecExtParams->CertIndex; + /* verify user length */ + if (pSecExtParams->UserLen > MAX_USER_LEN) + { + return SL_INVALPARAM; + } + Msg.Cmd.Args.UserLen = pSecExtParams->UserLen; + /* copy user name (identity) */ + if(pSecExtParams->UserLen > 0) + { + sl_Memcpy(EAP_PROFILE_USER_STRING(&Msg), pSecExtParams->User, pSecExtParams->UserLen); + CmdCtrl.TxDescLen += pSecExtParams->UserLen; + } + + /* verify Anonymous user length (for tunneled) */ + if (pSecExtParams->AnonUserLen > MAX_ANON_USER_LEN) + { + return SL_INVALPARAM; + } + Msg.Cmd.Args.AnonUserLen = pSecExtParams->AnonUserLen; + + /* copy Anonymous user */ + if(pSecExtParams->AnonUserLen > 0) + { + sl_Memcpy(EAP_PROFILE_ANON_USER_STRING(&Msg), pSecExtParams->AnonUser, pSecExtParams->AnonUserLen); + CmdCtrl.TxDescLen += pSecExtParams->AnonUserLen; + } + + } + /* Regular or open security profile */ + else + { + /* Update command opcode */ + CmdCtrl.Opcode = SL_OPCODE_WLAN_PROFILEADDCOMMAND; + /* update commnad length */ + CmdCtrl.TxDescLen += sizeof(_WlanAddGetProfile_t); + + if (NULL != pName) + { + /* copy SSID */ + sl_Memcpy(PROFILE_SSID_STRING(&Msg), pName, NameLen); + CmdCtrl.TxDescLen += NameLen; + } + + /* Copy password if supplied */ + if( NULL != pSecParams ) + { + /* update security type */ + Msg.Cmd.Args.Common.SecType = pSecParams->Type; + + if( SL_SEC_TYPE_WEP == Msg.Cmd.Args.Common.SecType ) + { + Msg.Cmd.Args.Common.WepKeyId = 0; + } + + /* verify key length */ + if (pSecParams->KeyLen > MAX_KEY_LEN) + { + return SL_INVALPARAM; + } + /* update key length */ + Msg.Cmd.Args.Common.PasswordLen = pSecParams->KeyLen; + CmdCtrl.TxDescLen += pSecParams->KeyLen; + /* copy key (could be no key in case of WPS pin) */ + if( NULL != pSecParams->Key ) + { + sl_Memcpy(PROFILE_PASSWORD_STRING(&Msg), pSecParams->Key, pSecParams->KeyLen); + } + } + else + { + Msg.Cmd.Args.Common.SecType = SL_SEC_TYPE_OPEN; + Msg.Cmd.Args.Common.PasswordLen = 0; + } + + } + + + /* If BSSID is not null, copy to buffer, otherwise set to 0 */ + if(NULL != pMacAddr) + { + sl_Memcpy(Msg.Cmd.Args.Common.Bssid, pMacAddr, sizeof(Msg.Cmd.Args.Common.Bssid)); + } + else + { + _SlDrvMemZero(Msg.Cmd.Args.Common.Bssid, sizeof(Msg.Cmd.Args.Common.Bssid)); + } + + VERIFY_RET_OK(_SlDrvCmdOp(&CmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif +/*******************************************************************************/ +/* sl_ProfileGet */ +/*******************************************************************************/ +typedef union +{ + _WlanProfileDelGetCommand_t Cmd; + _SlProfileParams_t Rsp; +}_SlProfileGetMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_WlanProfileGet) + +const _SlCmdCtrl_t _SlProfileGetCmdCtrl = +{ + SL_OPCODE_WLAN_PROFILEGETCOMMAND, + sizeof(_WlanProfileDelGetCommand_t), + sizeof(_SlProfileParams_t) +}; + +_i16 sl_WlanProfileGet(const _i16 Index,_i8* pName, _i16 *pNameLen, _u8 *pMacAddr, SlSecParams_t* pSecParams, SlGetSecParamsExt_t* pEntParams, _u32 *pPriority) +{ + _SlProfileGetMsg_u Msg; + Msg.Cmd.index = (_u8)Index; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlProfileGetCmdCtrl, &Msg, NULL)); + + pSecParams->Type = Msg.Rsp.Args.Common.SecType; + /* since password is not transferred in getprofile, password length should always be zero */ + pSecParams->KeyLen = Msg.Rsp.Args.Common.PasswordLen; + if (NULL != pEntParams) + { + pEntParams->UserLen = Msg.Rsp.Args.UserLen; + /* copy user name */ + if (pEntParams->UserLen > 0) + { + sl_Memcpy(pEntParams->User, EAP_PROFILE_USER_STRING(&Msg), pEntParams->UserLen); + } + pEntParams->AnonUserLen = Msg.Rsp.Args.AnonUserLen; + /* copy anonymous user name */ + if (pEntParams->AnonUserLen > 0) + { + sl_Memcpy(pEntParams->AnonUser, EAP_PROFILE_ANON_USER_STRING(&Msg), pEntParams->AnonUserLen); + } + } + + *pNameLen = Msg.Rsp.Args.Common.SsidLen; + *pPriority = Msg.Rsp.Args.Common.Priority; + + if (NULL != Msg.Rsp.Args.Common.Bssid) + { + sl_Memcpy(pMacAddr, Msg.Rsp.Args.Common.Bssid, sizeof(Msg.Rsp.Args.Common.Bssid)); + } + + sl_Memcpy(pName, EAP_PROFILE_SSID_STRING(&Msg), *pNameLen); + + return (_i16)Msg.Rsp.Args.Common.SecType; + +} +#endif +/*******************************************************************************/ +/* sl_ProfileDel */ +/*******************************************************************************/ +typedef union +{ + _WlanProfileDelGetCommand_t Cmd; + _BasicResponse_t Rsp; +}_SlProfileDelMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_WlanProfileDel) + +const _SlCmdCtrl_t _SlProfileDelCmdCtrl = +{ + SL_OPCODE_WLAN_PROFILEDELCOMMAND, + sizeof(_WlanProfileDelGetCommand_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_WlanProfileDel(const _i16 Index) +{ + _SlProfileDelMsg_u Msg; + + Msg.Cmd.index = (_u8)Index; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlProfileDelCmdCtrl, &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif + + +/******************************************************************************/ +/* sl_WlanGetNetworkList */ +/******************************************************************************/ +typedef union +{ + _WlanGetNetworkListCommand_t Cmd; + _WlanGetNetworkListResponse_t Rsp; +}_SlWlanGetNetworkListMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_WlanGetNetworkList) + +const _SlCmdCtrl_t _SlWlanGetNetworkListCtrl = +{ + SL_OPCODE_WLAN_SCANRESULTSGETCOMMAND, + sizeof(_WlanGetNetworkListCommand_t), + sizeof(_WlanGetNetworkListResponse_t) +}; + +_i16 sl_WlanGetNetworkList(const _u8 Index,const _u8 Count, Sl_WlanNetworkEntry_t *pEntries) +{ + _i16 retVal = 0; + _SlWlanGetNetworkListMsg_u Msg; + _SlCmdExt_t CmdExt; + + if (Count == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = sizeof(Sl_WlanNetworkEntry_t)*(Count); + CmdExt.pRxPayload = (_u8 *)pEntries; + + Msg.Cmd.index = Index; + Msg.Cmd.count = Count; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlWlanGetNetworkListCtrl, &Msg, &CmdExt)); + retVal = Msg.Rsp.status; + + return (_i16)retVal; +} +#endif + + + + + +/******************************************************************************/ +/* RX filters message command response structures */ +/******************************************************************************/ + +/* Set command */ +typedef union +{ + _WlanRxFilterAddCommand_t Cmd; + _WlanRxFilterAddCommandReponse_t Rsp; +}_SlrxFilterAddMsg_u; + + +/* Set command */ +typedef union _SlRxFilterSetMsg_u +{ + _WlanRxFilterSetCommand_t Cmd; + _WlanRxFilterSetCommandReponse_t Rsp; +}_SlRxFilterSetMsg_u; + + +/* Get command */ +typedef union _SlRxFilterGetMsg_u +{ + _WlanRxFilterGetCommand_t Cmd; + _WlanRxFilterGetCommandReponse_t Rsp; +}_SlRxFilterGetMsg_u; + +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterAdd) + +const _SlCmdCtrl_t _SlRxFilterAddtCmdCtrl = +{ + SL_OPCODE_WLAN_WLANRXFILTERADDCOMMAND, + sizeof(_WlanRxFilterAddCommand_t), + sizeof(_WlanRxFilterAddCommandReponse_t) +}; + + +/***************************************************************************** + RX filters +*****************************************************************************/ +SlrxFilterID_t sl_WlanRxFilterAdd( SlrxFilterRuleType_t RuleType, + SlrxFilterFlags_t FilterFlags, + const SlrxFilterRule_t* const Rule, + const SlrxFilterTrigger_t* const Trigger, + const SlrxFilterAction_t* const Action, + SlrxFilterID_t* pFilterId) +{ + + + _SlrxFilterAddMsg_u Msg; + Msg.Cmd.RuleType = RuleType; + /* filterId is zero */ + Msg.Cmd.FilterId = 0; + Msg.Cmd.FilterFlags = FilterFlags; + sl_Memcpy( &(Msg.Cmd.Rule), Rule, sizeof(SlrxFilterRule_t) ); + sl_Memcpy( &(Msg.Cmd.Trigger), Trigger, sizeof(SlrxFilterTrigger_t) ); + sl_Memcpy( &(Msg.Cmd.Action), Action, sizeof(SlrxFilterAction_t) ); + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlRxFilterAddtCmdCtrl, &Msg, NULL) ); + *pFilterId = Msg.Rsp.FilterId; + return (_i16)Msg.Rsp.Status; + +} +#endif + + + +/*******************************************************************************/ +/* RX filters */ +/*******************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterSet) + +const _SlCmdCtrl_t _SlRxFilterSetCmdCtrl = +{ + SL_OPCODE_WLAN_WLANRXFILTERSETCOMMAND, + sizeof(_WlanRxFilterSetCommand_t), + sizeof(_WlanRxFilterSetCommandReponse_t) +}; + +_i16 sl_WlanRxFilterSet(const SLrxFilterOperation_t RxFilterOperation, + const _u8* const pInputBuffer, + _u16 InputbufferLength) +{ + _SlRxFilterSetMsg_u Msg; + _SlCmdExt_t CmdExt; + + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = InputbufferLength; + CmdExt.pTxPayload = (_u8 *)pInputBuffer; + + Msg.Cmd.RxFilterOperation = RxFilterOperation; + Msg.Cmd.InputBufferLength = InputbufferLength; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlRxFilterSetCmdCtrl, &Msg, &CmdExt) ); + + + return (_i16)Msg.Rsp.Status; +} +#endif + +/******************************************************************************/ +/* RX filters */ +/******************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_WlanRxFilterGet) + +const _SlCmdCtrl_t _SlRxFilterGetCmdCtrl = +{ + SL_OPCODE_WLAN_WLANRXFILTERGETCOMMAND, + sizeof(_WlanRxFilterGetCommand_t), + sizeof(_WlanRxFilterGetCommandReponse_t) +}; + + +_i16 sl_WlanRxFilterGet(const SLrxFilterOperation_t RxFilterOperation, + _u8* pOutputBuffer, + _u16 OutputbufferLength) +{ + _SlRxFilterGetMsg_u Msg; + _SlCmdExt_t CmdExt; + + if (OutputbufferLength == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = OutputbufferLength; + CmdExt.pRxPayload = (_u8 *)pOutputBuffer; + + Msg.Cmd.RxFilterOperation = RxFilterOperation; + Msg.Cmd.OutputBufferLength = OutputbufferLength; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlRxFilterGetCmdCtrl, &Msg, &CmdExt) ); + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + return SL_ESMALLBUF; + } + + return (_i16)Msg.Rsp.Status; +} +#endif + +/*******************************************************************************/ +/* sl_WlanRxStatStart */ +/*******************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_WlanRxStatStart) +_i16 sl_WlanRxStatStart(void) +{ + return _SlDrvBasicCmd(SL_OPCODE_WLAN_STARTRXSTATCOMMAND); +} +#endif + +#if _SL_INCLUDE_FUNC(sl_WlanRxStatStop) +_i16 sl_WlanRxStatStop(void) +{ + return _SlDrvBasicCmd(SL_OPCODE_WLAN_STOPRXSTATCOMMAND); +} +#endif + +#if _SL_INCLUDE_FUNC(sl_WlanRxStatGet) +_i16 sl_WlanRxStatGet(SlGetRxStatResponse_t *pRxStat,const _u32 Flags) +{ + _SlCmdCtrl_t CmdCtrl = {SL_OPCODE_WLAN_GETRXSTATCOMMAND, 0, sizeof(SlGetRxStatResponse_t)}; + + _SlDrvMemZero(pRxStat, sizeof(SlGetRxStatResponse_t)); + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&CmdCtrl, pRxStat, NULL)); + + return 0; +} +#endif + + + +/******************************************************************************/ +/* sl_WlanSmartConfigStop */ +/******************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_WlanSmartConfigStop) +_i16 sl_WlanSmartConfigStop(void) +{ + return _SlDrvBasicCmd(SL_OPCODE_WLAN_SMART_CONFIG_STOP_COMMAND); +} +#endif + + +/******************************************************************************/ +/* sl_WlanSmartConfigStart */ +/******************************************************************************/ + + +typedef struct +{ + _WlanSmartConfigStartCommand_t Args; + _i8 Strings[3 * MAX_SMART_CONFIG_KEY]; /* public key + groupId1 key + groupId2 key */ +}_SlSmartConfigStart_t; + +typedef union +{ + _SlSmartConfigStart_t Cmd; + _BasicResponse_t Rsp; +}_SlSmartConfigStartMsg_u; + +#if _SL_INCLUDE_FUNC(sl_WlanSmartConfigStart) + +const _SlCmdCtrl_t _SlSmartConfigStartCmdCtrl = +{ + SL_OPCODE_WLAN_SMART_CONFIG_START_COMMAND, + sizeof(_SlSmartConfigStart_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_WlanSmartConfigStart( const _u32 groupIdBitmask, + const _u8 cipher, + const _u8 publicKeyLen, + const _u8 group1KeyLen, + const _u8 group2KeyLen, + const _u8* pPublicKey, + const _u8* pGroup1Key, + const _u8* pGroup2Key) +{ + _SlSmartConfigStartMsg_u Msg; + + Msg.Cmd.Args.groupIdBitmask = (_u8)groupIdBitmask; + Msg.Cmd.Args.cipher = (_u8)cipher; + Msg.Cmd.Args.publicKeyLen = (_u8)publicKeyLen; + Msg.Cmd.Args.group1KeyLen = (_u8)group1KeyLen; + Msg.Cmd.Args.group2KeyLen = (_u8)group2KeyLen; + + /* copy keys (if exist) after command (one after another) */ + sl_Memcpy(SMART_CONFIG_START_PUBLIC_KEY_STRING(&Msg), pPublicKey, publicKeyLen); + sl_Memcpy(SMART_CONFIG_START_GROUP1_KEY_STRING(&Msg), pGroup1Key, group1KeyLen); + sl_Memcpy(SMART_CONFIG_START_GROUP2_KEY_STRING(&Msg), pGroup2Key, group2KeyLen); + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlSmartConfigStartCmdCtrl , &Msg, NULL)); + + return (_i16)Msg.Rsp.status; + + +} +#endif + + +/*******************************************************************************/ +/* sl_WlanSetMode */ +/*******************************************************************************/ +typedef union +{ + _WlanSetMode_t Cmd; + _BasicResponse_t Rsp; +}_SlwlanSetModeMsg_u; + +#if _SL_INCLUDE_FUNC(sl_WlanSetMode) + +const _SlCmdCtrl_t _SlWlanSetModeCmdCtrl = +{ + SL_OPCODE_WLAN_SET_MODE, + sizeof(_WlanSetMode_t), + sizeof(_BasicResponse_t) +}; + +/* possible values are: +WLAN_SET_STA_MODE = 1 +WLAN_SET_AP_MODE = 2 +WLAN_SET_P2P_MODE = 3 */ +_i16 sl_WlanSetMode(const _u8 mode) +{ + _SlwlanSetModeMsg_u Msg; + + Msg.Cmd.mode = mode; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlWlanSetModeCmdCtrl , &Msg, NULL)); + + return (_i16)Msg.Rsp.status; +} +#endif + + + + +/*******************************************************************************/ +/* sl_WlanSet */ +/* ******************************************************************************/ +typedef union +{ + _WlanCfgSetGet_t Cmd; + _BasicResponse_t Rsp; +}_SlWlanCfgSetMsg_u; + + +#if _SL_INCLUDE_FUNC(sl_WlanSet) + +const _SlCmdCtrl_t _SlWlanCfgSetCmdCtrl = +{ + SL_OPCODE_WLAN_CFG_SET, + sizeof(_WlanCfgSetGet_t), + sizeof(_BasicResponse_t) +}; + +_i16 sl_WlanSet(const _u16 ConfigId ,const _u16 ConfigOpt,const _u16 ConfigLen,const _u8 *pValues) +{ + _SlWlanCfgSetMsg_u Msg; + _SlCmdExt_t CmdExt; + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (ConfigLen+3) & (~3); + CmdExt.pTxPayload = (_u8 *)pValues; + + Msg.Cmd.ConfigId = ConfigId; + Msg.Cmd.ConfigLen = ConfigLen; + Msg.Cmd.ConfigOpt = ConfigOpt; + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlWlanCfgSetCmdCtrl, &Msg, &CmdExt)); + + return (_i16)Msg.Rsp.status; +} +#endif + + +/******************************************************************************/ +/* sl_WlanGet */ +/******************************************************************************/ +typedef union +{ + _WlanCfgSetGet_t Cmd; + _WlanCfgSetGet_t Rsp; +}_SlWlanCfgMsgGet_u; + +#if _SL_INCLUDE_FUNC(sl_WlanGet) + +const _SlCmdCtrl_t _SlWlanCfgGetCmdCtrl = +{ + SL_OPCODE_WLAN_CFG_GET, + sizeof(_WlanCfgSetGet_t), + sizeof(_WlanCfgSetGet_t) +}; + +_i16 sl_WlanGet(const _u16 ConfigId, _u16 *pConfigOpt,_u16 *pConfigLen, _u8 *pValues) +{ + _SlWlanCfgMsgGet_u Msg; + _SlCmdExt_t CmdExt; + + if (*pConfigLen == 0) + { + return SL_EZEROLEN; + } + + _SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pConfigLen; + CmdExt.pRxPayload = (_u8 *)pValues; + + Msg.Cmd.ConfigId = ConfigId; + if( pConfigOpt ) + { + Msg.Cmd.ConfigOpt = (_u16)*pConfigOpt; + } + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlWlanCfgGetCmdCtrl, &Msg, &CmdExt)); + + if( pConfigOpt ) + { + *pConfigOpt = (_u8)Msg.Rsp.ConfigOpt; + } + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) + { + *pConfigLen = (_u8)CmdExt.RxPayloadLen; + return SL_ESMALLBUF; + } + else + { + *pConfigLen = (_u8)CmdExt.ActualRxPayloadLen; + } + + + return (_i16)Msg.Rsp.Status; +} +#endif diff --git a/src/openmv/src/micropython/drivers/dht/dht.c b/src/openmv/src/micropython/drivers/dht/dht.c new file mode 100755 index 0000000..5d92ae3 --- /dev/null +++ b/src/openmv/src/micropython/drivers/dht/dht.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/machine_pulse.h" +#include "drivers/dht/dht.h" + +STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in); + mp_hal_pin_open_drain(pin); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + + if (bufinfo.len < 5) { + mp_raise_ValueError("buffer too small"); + } + + // issue start command + mp_hal_pin_od_high(pin); + mp_hal_delay_ms(250); + mp_hal_pin_od_low(pin); + mp_hal_delay_ms(18); + + mp_uint_t irq_state = mp_hal_quiet_timing_enter(); + + // release the line so the device can respond + mp_hal_pin_od_high(pin); + mp_hal_delay_us_fast(10); + + // wait for device to respond + mp_uint_t ticks = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) != 0) { + if ((mp_uint_t)(mp_hal_ticks_us() - ticks) > 100) { + goto timeout; + } + } + + // time pulse, should be 80us + ticks = machine_time_pulse_us(pin, 1, 150); + if ((mp_int_t)ticks < 0) { + goto timeout; + } + + // time 40 pulses for data (either 26us or 70us) + uint8_t *buf = bufinfo.buf; + for (int i = 0; i < 40; ++i) { + ticks = machine_time_pulse_us(pin, 1, 100); + if ((mp_int_t)ticks < 0) { + goto timeout; + } + buf[i / 8] = (buf[i / 8] << 1) | (ticks > 48); + } + + mp_hal_quiet_timing_exit(irq_state); + return mp_const_none; + +timeout: + mp_hal_quiet_timing_exit(irq_state); + mp_raise_OSError(MP_ETIMEDOUT); +} +MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto); diff --git a/src/openmv/src/micropython/drivers/dht/dht.h b/src/openmv/src/micropython/drivers/dht/dht.h new file mode 100755 index 0000000..883e077 --- /dev/null +++ b/src/openmv/src/micropython/drivers/dht/dht.h @@ -0,0 +1,8 @@ +#ifndef MICROPY_INCLUDED_DRIVERS_DHT_DHT_H +#define MICROPY_INCLUDED_DRIVERS_DHT_DHT_H + +#include "py/obj.h" + +MP_DECLARE_CONST_FUN_OBJ_2(dht_readinto_obj); + +#endif // MICROPY_INCLUDED_DRIVERS_DHT_DHT_H diff --git a/src/openmv/src/micropython/drivers/dht/dht.py b/src/openmv/src/micropython/drivers/dht/dht.py new file mode 100755 index 0000000..eed61df --- /dev/null +++ b/src/openmv/src/micropython/drivers/dht/dht.py @@ -0,0 +1,35 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +try: + from esp import dht_readinto +except: + from pyb import dht_readinto + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: + raise Exception("checksum error") + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/src/openmv/src/micropython/drivers/display/lcd160cr.py b/src/openmv/src/micropython/drivers/display/lcd160cr.py new file mode 100755 index 0000000..cf562a4 --- /dev/null +++ b/src/openmv/src/micropython/drivers/display/lcd160cr.py @@ -0,0 +1,474 @@ +# Driver for official MicroPython LCD160CR display +# MIT license; Copyright (c) 2017 Damien P. George + +from micropython import const +from utime import sleep_ms +from ustruct import calcsize, pack_into +import uerrno, machine + +# for set_orient +PORTRAIT = const(0) +LANDSCAPE = const(1) +PORTRAIT_UPSIDEDOWN = const(2) +LANDSCAPE_UPSIDEDOWN = const(3) + +# for set_startup_deco; can be or'd +STARTUP_DECO_NONE = const(0) +STARTUP_DECO_MLOGO = const(1) +STARTUP_DECO_INFO = const(2) + +_uart_baud_table = { + 2400: 0, + 4800: 1, + 9600: 2, + 19200: 3, + 38400: 4, + 57600: 5, + 115200: 6, + 230400: 7, + 460800: 8, +} + +class LCD160CR: + def __init__(self, connect=None, *, pwr=None, i2c=None, spi=None, i2c_addr=98): + if connect in ('X', 'Y', 'XY', 'YX'): + i = connect[-1] + j = connect[0] + y = j + '4' + elif connect == 'C': + i = 2 + j = 2 + y = 'A7' + else: + if pwr is None or i2c is None or spi is None: + raise ValueError('must specify valid "connect" or all of "pwr", "i2c" and "spi"') + + if pwr is None: + pwr = machine.Pin(y, machine.Pin.OUT) + if i2c is None: + i2c = machine.I2C(i, freq=1000000) + if spi is None: + spi = machine.SPI(j, baudrate=13500000, polarity=0, phase=0) + + if not pwr.value(): + pwr(1) + sleep_ms(10) + # else: + # alread have power + # lets be optimistic... + + # set connections + self.pwr = pwr + self.i2c = i2c + self.spi = spi + self.i2c_addr = i2c_addr + + # create temp buffers and memoryviews + self.buf16 = bytearray(16) + self.buf19 = bytearray(19) + self.buf = [None] * 10 + for i in range(1, 10): + self.buf[i] = memoryview(self.buf16)[0:i] + self.buf1 = self.buf[1] + self.array4 = [0, 0, 0, 0] + + # set default orientation and window + self.set_orient(PORTRAIT) + self._fcmd2b('= n: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(uerrno.ETIMEDOUT) + + def oflush(self, n=255): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr + 1, self.buf1) + r = self.buf1[0] + if r >= n: + return + t -= 1 + machine.idle() + raise OSError(uerrno.ETIMEDOUT) + + def iflush(self): + t = 5000 + while t: + self.i2c.readfrom_into(self.i2c_addr, self.buf16) + if self.buf16[0] == 0: + return + t -= 1 + sleep_ms(1) + raise OSError(uerrno.ETIMEDOUT) + + #### MISC METHODS #### + + @staticmethod + def rgb(r, g, b): + return ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | (r >> 3) + + @staticmethod + def clip_line(c, w, h): + while True: + ca = ce = 0 + if c[1] < 0: + ca |= 8 + elif c[1] > h: + ca |= 4 + if c[0] < 0: + ca |= 1 + elif c[0] > w: + ca |= 2 + if c[3] < 0: + ce |= 8 + elif c[3] > h: + ce |= 4 + if c[2] < 0: + ce |= 1 + elif c[2] > w: + ce |= 2 + if ca & ce: + return False + elif ca | ce: + ca |= ce + if ca & 1: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[1] += ((-c[0]) * (c[3] - c[1])) // (c[2] - c[0]) + c[0] = 0 + elif ca & 2: + if c[2] < c[0]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[3] += ((w - 1 - c[2]) * (c[3] - c[1])) // (c[2] - c[0]) + c[2] = w - 1 + elif ca & 4: + if c[0] == c[2]: + if c[1] >= h: + c[1] = h - 1 + if c[3] >= h: + c[3] = h - 1 + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[2] += ((h - 1 - c[3]) * (c[2] - c[0])) // (c[3] - c[1]) + c[3] = h - 1 + else: + if c[0] == c[2]: + if c[1] < 0: + c[1] = 0 + if c[3] < 0: + c[3] = 0 + else: + if c[3] < c[1]: + c[0], c[2] = c[2], c[0] + c[1], c[3] = c[3], c[1] + c[0] += ((-c[1]) * (c[2] - c[0])) // (c[3] - c[1]) + c[1] = 0 + else: + return True + + #### SETUP COMMANDS #### + + def set_power(self, on): + self.pwr(on) + sleep_ms(15) + + def set_orient(self, orient): + self._fcmd2('= 2: + self.i2c.readfrom_into(self.i2c_addr, self.buf[3]) + return self.buf[3][1] | self.buf[3][2] << 8 + t -= 1 + sleep_ms(1) + raise OSError(uerrno.ETIMEDOUT) + + def get_line(self, x, y, buf): + l = len(buf) // 2 + self._fcmd2b('= l: + self.i2c.readfrom_into(self.i2c_addr, buf) + return + t -= 1 + sleep_ms(1) + raise OSError(uerrno.ETIMEDOUT) + + def screen_dump(self, buf, x=0, y=0, w=None, h=None): + if w is None: + w = self.w - x + if h is None: + h = self.h - y + if w <= 127: + line = bytearray(2 * w + 1) + line2 = None + else: + # split line if more than 254 bytes needed + buflen = (w + 1) // 2 + line = bytearray(2 * buflen + 1) + line2 = memoryview(line)[:2 * (w - buflen) + 1] + for i in range(min(len(buf) // (2 * w), h)): + ix = i * w * 2 + self.get_line(x, y + i, line) + buf[ix:ix + len(line) - 1] = memoryview(line)[1:] + ix += len(line) - 1 + if line2: + self.get_line(x + buflen, y + i, line2) + buf[ix:ix + len(line2) - 1] = memoryview(line2)[1:] + ix += len(line2) - 1 + + def screen_load(self, buf): + l = self.w * self.h * 2+2 + self._fcmd2b('= 0x200: + self._send(ar[n:n + 0x200]) + n += 0x200 + else: + self._send(ar[n:]) + while n < self.w * self.h * 2: + self._send(b'\x00') + n += 1 + + #### TEXT COMMANDS #### + + def set_pos(self, x, y): + self._fcmd2('= self.w or y >= self.h: + return + elif x < 0 or y < 0: + left = top = True + if x < 0: + left = False + w += x + x = 0 + if y < 0: + top = False + h += y + y = 0 + if cmd == 0x51 or cmd == 0x72: + # draw interior + self._fcmd2b('> 7 != 0 + + def get_touch(self): + self._send(b'\x02T') # implicit LCD output flush + b = self.buf[4] + self._waitfor(3, b) + return b[1] >> 7, b[2], b[3] + + #### ADVANCED COMMANDS #### + + def set_spi_win(self, x, y, w, h): + pack_into(' 32: + raise ValueError('length must be 32 or less') + self._fcmd2(' 0xffff: + raise ValueError('length must be 65535 or less') + self.oflush() + self._fcmd2(' 0: + s = '%6.3fV' % data[i] + else: + s = '%5.1f°C' % data[i] + if lcd.h == 160: + lcd.set_font(1, bold=0, scale=1) + else: + lcd.set_font(1, bold=0, scale=1, trans=1) + lcd.set_pos(45, lcd.h-60 + i * 16) + lcd.write(s) + +def test_features(lcd, orient=lcd160cr.PORTRAIT): + # if we run on pyboard then use ADC and RTC features + try: + import pyb + adc = pyb.ADCAll(12, 0xf0000) + rtc = pyb.RTC() + except: + adc = None + rtc = None + + # set orientation and clear screen + lcd = get_lcd(lcd) + lcd.set_orient(orient) + lcd.set_pen(0, 0) + lcd.erase() + + # create M-logo + mlogo = framebuf.FrameBuffer(bytearray(17 * 17 * 2), 17, 17, framebuf.RGB565) + mlogo.fill(0) + mlogo.fill_rect(1, 1, 15, 15, 0xffffff) + mlogo.vline(4, 4, 12, 0) + mlogo.vline(8, 1, 12, 0) + mlogo.vline(12, 4, 12, 0) + mlogo.vline(14, 13, 2, 0) + + # create inline framebuf + offx = 14 + offy = 19 + w = 100 + h = 75 + fbuf = framebuf.FrameBuffer(bytearray(w * h * 2), w, h, framebuf.RGB565) + lcd.set_spi_win(offx, offy, w, h) + + # initialise loop parameters + tx = ty = 0 + t0 = time.ticks_us() + + for i in range(300): + # update position of cross-hair + t, tx2, ty2 = lcd.get_touch() + if t: + tx2 -= offx + ty2 -= offy + if tx2 >= 0 and ty2 >= 0 and tx2 < w and ty2 < h: + tx, ty = tx2, ty2 + else: + tx = (tx + 1) % w + ty = (ty + 1) % h + + # create and show the inline framebuf + fbuf.fill(lcd.rgb(128 + int(64 * math.cos(0.1 * i)), 128, 192)) + fbuf.line(w // 2, h // 2, + w // 2 + int(40 * math.cos(0.2 * i)), + h // 2 + int(40 * math.sin(0.2 * i)), + lcd.rgb(128, 255, 64)) + fbuf.hline(0, ty, w, lcd.rgb(64, 64, 64)) + fbuf.vline(tx, 0, h, lcd.rgb(64, 64, 64)) + fbuf.rect(tx - 3, ty - 3, 7, 7, lcd.rgb(64, 64, 64)) + for phase in (-0.2, 0, 0.2): + x = w // 2 - 8 + int(50 * math.cos(0.05 * i + phase)) + y = h // 2 - 8 + int(32 * math.sin(0.05 * i + phase)) + fbuf.blit(mlogo, x, y) + for j in range(-3, 3): + fbuf.text('MicroPython', + 5, h // 2 + 9 * j + int(20 * math.sin(0.1 * (i + j))), + lcd.rgb(128 + 10 * j, 0, 128 - 10 * j)) + lcd.show_framebuf(fbuf) + + # show results from the ADC + if adc: + show_adc(lcd, adc) + + # show the time + if rtc: + lcd.set_pos(2, 0) + lcd.set_font(1) + t = rtc.datetime() + lcd.write('%4d-%02d-%02d %2d:%02d:%02d.%01d' % (t[0], t[1], t[2], t[4], t[5], t[6], t[7] // 100000)) + + # compute the frame rate + t1 = time.ticks_us() + dt = time.ticks_diff(t1, t0) + t0 = t1 + + # show the frame rate + lcd.set_pos(2, 9) + lcd.write('%.2f fps' % (1000000 / dt)) + +def test_mandel(lcd, orient=lcd160cr.PORTRAIT): + # set orientation and clear screen + lcd = get_lcd(lcd) + lcd.set_orient(orient) + lcd.set_pen(0, 0xffff) + lcd.erase() + + # function to compute Mandelbrot pixels + def in_set(c): + z = 0 + for i in range(32): + z = z * z + c + if abs(z) > 100: + return i + return 0 + + # cache width and height of LCD + w = lcd.w + h = lcd.h + + # create the buffer for each line and set SPI parameters + line = bytearray(w * 2) + lcd.set_spi_win(0, 0, w, h) + spi = lcd.fast_spi() + + # draw the Mandelbrot set line-by-line + hh = ((h - 1) / 3.2) + ww = ((w - 1) / 2.4) + for v in range(h): + for u in range(w): + c = in_set((v / hh - 2.3) + (u / ww - 1.2) * 1j) + if c < 16: + rgb = c << 12 | c << 6 + else: + rgb = 0xf800 | c << 6 + line[2 * u] = rgb + line[2 * u + 1] = rgb >> 8 + spi.write(line) + +def test_all(lcd, orient=lcd160cr.PORTRAIT): + lcd = get_lcd(lcd) + test_features(lcd, orient) + test_mandel(lcd, orient) + +print('To run all tests: test_all()') +print('Individual tests are: test_features, test_mandel') +print(' argument should be a connection, eg "X", or an LCD160CR object') diff --git a/src/openmv/src/micropython/drivers/display/ssd1306.py b/src/openmv/src/micropython/drivers/display/ssd1306.py new file mode 100755 index 0000000..178b491 --- /dev/null +++ b/src/openmv/src/micropython/drivers/display/ssd1306.py @@ -0,0 +1,147 @@ +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces + +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xa4) +SET_NORM_INV = const(0xa6) +SET_DISP = const(0xae) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xa0) +SET_MUX_RATIO = const(0xa8) +SET_COM_OUT_DIR = const(0xc0) +SET_DISP_OFFSET = const(0xd3) +SET_COM_PIN_CFG = const(0xda) +SET_DISP_CLK_DIV = const(0xd5) +SET_PRECHARGE = const(0xd9) +SET_VCOM_DESEL = const(0xdb) +SET_CHARGE_PUMP = const(0x8d) + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP | 0x00, # off + # address setting + SET_MEM_ADDR, 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE | 0x00, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, 0x00, + SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, 0x80, + SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1, + SET_VCOM_DESEL, 0x30, # 0.83*Vcc + # display + SET_CONTRAST, 0xff, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + # charge pump + SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP | 0x00) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.temp[0] = self.addr << 1 + self.temp[1] = 0x40 # Co=0, D/C#=1 + self.i2c.start() + self.i2c.write(self.temp) + self.i2c.write(buf) + self.i2c.stop() + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) diff --git a/src/openmv/src/micropython/drivers/memory/spiflash.c b/src/openmv/src/micropython/drivers/memory/spiflash.c new file mode 100755 index 0000000..c0b5559 --- /dev/null +++ b/src/openmv/src/micropython/drivers/memory/spiflash.c @@ -0,0 +1,489 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "drivers/memory/spiflash.h" + +#define QSPI_QE_MASK (0x02) +#define USE_WR_DELAY (1) + +#define CMD_WRSR (0x01) +#define CMD_WRITE (0x02) +#define CMD_READ (0x03) +#define CMD_RDSR (0x05) +#define CMD_WREN (0x06) +#define CMD_SEC_ERASE (0x20) +#define CMD_RDCR (0x35) +#define CMD_RD_DEVID (0x9f) +#define CMD_CHIP_ERASE (0xc7) +#define CMD_C4READ (0xeb) + +#define WAIT_SR_TIMEOUT (1000000) + +#define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer +#define SECTOR_SIZE MP_SPIFLASH_ERASE_BLOCK_SIZE + +STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE); + } +} + +STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE); + } +} + +STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + // Note: len/data are unused for standard SPI + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data); + } +} + +STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + if (len) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } +} + +STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint32_t buf; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + return buf; + } else { + return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len); + } +} + +STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + } +} + +STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { + mp_spiflash_write_cmd_data(self, cmd, 0, 0); +} + +STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) { + mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL); +} + +STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { + uint8_t sr; + for (; timeout; --timeout) { + sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1); + if ((sr & mask) == val) { + break; + } + } + if ((sr & mask) == val) { + return 0; // success + } else if (timeout == 0) { + return -MP_ETIMEDOUT; + } else { + return -MP_EIO; + } +} + +STATIC int mp_spiflash_wait_wel1(mp_spiflash_t *self) { + return mp_spiflash_wait_sr(self, 2, 2, WAIT_SR_TIMEOUT); +} + +STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) { + return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT); +} + +void mp_spiflash_init(mp_spiflash_t *self) { + self->flags = 0; + + if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { + mp_hal_pin_write(self->config->bus.u_spi.cs, 1); + mp_hal_pin_output(self->config->bus.u_spi.cs); + self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT); + } else { + self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); + } + + mp_spiflash_acquire_bus(self); + + #if defined(CHECK_DEVID) + // Validate device id + uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3); + if (devid != CHECK_DEVID) { + return 0; + } + #endif + + if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) { + // Set QE bit + uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) + | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; + if (!(data & (QSPI_QE_MASK << 8))) { + data |= QSPI_QE_MASK << 8; + mp_spiflash_write_cmd(self, CMD_WREN); + mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); + mp_spiflash_wait_wip0(self); + } + } + + mp_spiflash_release_bus(self); +} + +STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) { + // enable writes + mp_spiflash_write_cmd(self, CMD_WREN); + + // wait WEL=1 + int ret = mp_spiflash_wait_wel1(self); + if (ret != 0) { + return ret; + } + + // erase the sector + mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); + + // wait WIP=0 + return mp_spiflash_wait_wip0(self); +} + +STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + // enable writes + mp_spiflash_write_cmd(self, CMD_WREN); + + // wait WEL=1 + int ret = mp_spiflash_wait_wel1(self); + if (ret != 0) { + return ret; + } + + // write the page + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, len, src); + + // wait WIP=0 + return mp_spiflash_wait_wip0(self); +} + +/******************************************************************************/ +// Interface functions that go direct to the SPI flash device + +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr) { + mp_spiflash_acquire_bus(self); + int ret = mp_spiflash_erase_block_internal(self, addr); + mp_spiflash_release_bus(self); + return ret; +} + +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } + mp_spiflash_acquire_bus(self); + mp_spiflash_read_data(self, addr, len, dest); + mp_spiflash_release_bus(self); +} + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + mp_spiflash_acquire_bus(self); + int ret = 0; + uint32_t offset = addr & (PAGE_SIZE - 1); + while (len) { + size_t rest = PAGE_SIZE - offset; + if (rest > len) { + rest = len; + } + ret = mp_spiflash_write_page(self, addr, rest, src); + if (ret != 0) { + break; + } + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + mp_spiflash_release_bus(self); + return ret; +} + +/******************************************************************************/ +// Interface functions that use the cache + +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } + mp_spiflash_acquire_bus(self); + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && cache->block != 0xffffffff) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + if (bis <= cache->block && cache->block <= bie) { + // Read straddles current buffer + size_t rest = 0; + if (bis < cache->block) { + // Read direct from flash for first part + rest = cache->block * SECTOR_SIZE - addr; + mp_spiflash_read_data(self, addr, rest, dest); + len -= rest; + dest += rest; + addr += rest; + } + uint32_t offset = addr & (SECTOR_SIZE - 1); + rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + memcpy(dest, &cache->buf[offset], rest); + len -= rest; + if (len == 0) { + mp_spiflash_release_bus(self); + return; + } + dest += rest; + addr += rest; + } + } + // Read rest direct from flash + mp_spiflash_read_data(self, addr, len, dest); + mp_spiflash_release_bus(self); +} + +STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) { + #if USE_WR_DELAY + if (!(self->flags & 1)) { + return; + } + + self->flags &= ~1; + + mp_spiflash_cache_t *cache = self->config->cache; + + // Erase sector + int ret = mp_spiflash_erase_block_internal(self, cache->block * SECTOR_SIZE); + if (ret != 0) { + return; + } + + // Write + for (int i = 0; i < 16; i += 1) { + uint32_t addr = cache->block * SECTOR_SIZE + i * PAGE_SIZE; + int ret = mp_spiflash_write_page(self, addr, PAGE_SIZE, cache->buf + i * PAGE_SIZE); + if (ret != 0) { + return; + } + } + #endif +} + +void mp_spiflash_cache_flush(mp_spiflash_t *self) { + mp_spiflash_acquire_bus(self); + mp_spiflash_cache_flush_internal(self); + mp_spiflash_release_bus(self); +} + +STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + // Align to 4096 sector + uint32_t offset = addr & 0xfff; + uint32_t sec = addr >> 12; + addr = sec << 12; + + // Restriction for now, so we don't need to erase multiple pages + if (offset + len > SECTOR_SIZE) { + printf("mp_spiflash_cached_write_part: len is too large\n"); + return -MP_EIO; + } + + mp_spiflash_cache_t *cache = self->config->cache; + + // Acquire the sector buffer + if (cache->user != self) { + if (cache->user != NULL) { + mp_spiflash_cache_flush(cache->user); + } + cache->user = self; + cache->block = 0xffffffff; + } + + if (cache->block != sec) { + // Read sector + #if USE_WR_DELAY + if (cache->block != 0xffffffff) { + mp_spiflash_cache_flush_internal(self); + } + #endif + mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf); + } + + #if USE_WR_DELAY + + cache->block = sec; + // Just copy to buffer + memcpy(cache->buf + offset, src, len); + // And mark dirty + self->flags |= 1; + + #else + + uint32_t dirty = 0; + for (size_t i = 0; i < len; ++i) { + if (cache->buf[offset + i] != src[i]) { + if (cache->buf[offset + i] != 0xff) { + // Erase sector + int ret = mp_spiflash_erase_block_internal(self, addr); + if (ret != 0) { + return ret; + } + dirty = 0xffff; + break; + } else { + dirty |= (1 << ((offset + i) >> 8)); + } + } + } + + cache->block = sec; + // Copy new block into buffer + memcpy(cache->buf + offset, src, len); + + // Write sector in pages of 256 bytes + for (size_t i = 0; i < 16; ++i) { + if (dirty & (1 << i)) { + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, PAGE_SIZE, cache->buf + i * PAGE_SIZE); + if (ret != 0) { + return ret; + } + } + } + + #endif + + return 0; // success +} + +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + + mp_spiflash_acquire_bus(self); + + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && bis <= cache->block && bie >= cache->block) { + // Write straddles current buffer + uint32_t pre; + uint32_t offset; + if (cache->block * SECTOR_SIZE >= addr) { + pre = cache->block * SECTOR_SIZE - addr; + offset = 0; + } else { + pre = 0; + offset = addr - cache->block * SECTOR_SIZE; + } + + // Write buffered part first + uint32_t len_in_buf = len - pre; + len = 0; + if (len_in_buf > SECTOR_SIZE - offset) { + len = len_in_buf - (SECTOR_SIZE - offset); + len_in_buf = SECTOR_SIZE - offset; + } + memcpy(&cache->buf[offset], &src[pre], len_in_buf); + self->flags |= 1; // Mark dirty + + // Write part before buffer sector + while (pre) { + int rest = pre & (SECTOR_SIZE - 1); + if (rest == 0) { + rest = SECTOR_SIZE; + } + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + src += rest; + addr += rest; + pre -= rest; + } + src += len_in_buf; + addr += len_in_buf; + + // Fall through to write remaining part + } + + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + + mp_spiflash_release_bus(self); + return 0; +} diff --git a/src/openmv/src/micropython/drivers/memory/spiflash.h b/src/openmv/src/micropython/drivers/memory/spiflash.h new file mode 100755 index 0000000..a5b8a1d --- /dev/null +++ b/src/openmv/src/micropython/drivers/memory/spiflash.h @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H +#define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H + +#include "drivers/bus/spi.h" +#include "drivers/bus/qspi.h" + +#define MP_SPIFLASH_ERASE_BLOCK_SIZE (4096) // must be a power of 2 + +enum { + MP_SPIFLASH_BUS_SPI, + MP_SPIFLASH_BUS_QSPI, +}; + +struct _mp_spiflash_t; + +// A cache must be provided by the user in the config struct. The same cache +// struct can be shared by multiple SPI flash instances. +typedef struct _mp_spiflash_cache_t { + uint8_t buf[MP_SPIFLASH_ERASE_BLOCK_SIZE] __attribute__((aligned(4))); + struct _mp_spiflash_t *user; // current user of buf, for shared use + uint32_t block; // current block stored in buf; 0xffffffff if invalid +} mp_spiflash_cache_t; + +typedef struct _mp_spiflash_config_t { + uint32_t bus_kind; + union { + struct { + mp_hal_pin_obj_t cs; + void *data; + const mp_spi_proto_t *proto; + } u_spi; + struct { + void *data; + const mp_qspi_proto_t *proto; + } u_qspi; + } bus; + mp_spiflash_cache_t *cache; // can be NULL if cache functions not used +} mp_spiflash_config_t; + +typedef struct _mp_spiflash_t { + const mp_spiflash_config_t *config; + volatile uint32_t flags; +} mp_spiflash_t; + +void mp_spiflash_init(mp_spiflash_t *self); + +// These functions go direct to the SPI flash device +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr); +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + +// These functions use the cache (which must already be configured) +void mp_spiflash_cache_flush(mp_spiflash_t *self); +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + +#endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H diff --git a/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01.py b/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01.py new file mode 100755 index 0000000..a95d2b5 --- /dev/null +++ b/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01.py @@ -0,0 +1,251 @@ +"""NRF24L01 driver for MicroPython +""" + +from micropython import const +import utime + +# nRF24L01+ registers +CONFIG = const(0x00) +EN_RXADDR = const(0x02) +SETUP_AW = const(0x03) +SETUP_RETR = const(0x04) +RF_CH = const(0x05) +RF_SETUP = const(0x06) +STATUS = const(0x07) +RX_ADDR_P0 = const(0x0a) +TX_ADDR = const(0x10) +RX_PW_P0 = const(0x11) +FIFO_STATUS = const(0x17) +DYNPD = const(0x1c) + +# CONFIG register +EN_CRC = const(0x08) # enable CRC +CRCO = const(0x04) # CRC encoding scheme; 0=1 byte, 1=2 bytes +PWR_UP = const(0x02) # 1=power up, 0=power down +PRIM_RX = const(0x01) # RX/TX control; 0=PTX, 1=PRX + +# RF_SETUP register +POWER_0 = const(0x00) # -18 dBm +POWER_1 = const(0x02) # -12 dBm +POWER_2 = const(0x04) # -6 dBm +POWER_3 = const(0x06) # 0 dBm +SPEED_1M = const(0x00) +SPEED_2M = const(0x08) +SPEED_250K = const(0x20) + +# STATUS register +RX_DR = const(0x40) # RX data ready; write 1 to clear +TX_DS = const(0x20) # TX data sent; write 1 to clear +MAX_RT = const(0x10) # max retransmits reached; write 1 to clear + +# FIFO_STATUS register +RX_EMPTY = const(0x01) # 1 if RX FIFO is empty + +# constants for instructions +R_RX_PL_WID = const(0x60) # read RX payload width +R_RX_PAYLOAD = const(0x61) # read RX payload +W_TX_PAYLOAD = const(0xa0) # write TX payload +FLUSH_TX = const(0xe1) # flush TX FIFO +FLUSH_RX = const(0xe2) # flush RX FIFO +NOP = const(0xff) # use to read STATUS register + +class NRF24L01: + def __init__(self, spi, cs, ce, channel=46, payload_size=16): + assert payload_size <= 32 + + self.buf = bytearray(1) + + # store the pins + self.spi = spi + self.cs = cs + self.ce = ce + + # init the SPI bus and pins + self.init_spi(4000000) + + # reset everything + ce.init(ce.OUT, value=0) + cs.init(cs.OUT, value=1) + + self.payload_size = payload_size + self.pipe0_read_addr = None + utime.sleep_ms(5) + + # set address width to 5 bytes and check for device present + self.reg_write(SETUP_AW, 0b11) + if self.reg_read(SETUP_AW) != 0b11: + raise OSError("nRF24L01+ Hardware not responding") + + # disable dynamic payloads + self.reg_write(DYNPD, 0) + + # auto retransmit delay: 1750us + # auto retransmit count: 8 + self.reg_write(SETUP_RETR, (6 << 4) | 8) + + # set rf power and speed + self.set_power_speed(POWER_3, SPEED_250K) # Best for point to point links + + # init CRC + self.set_crc(2) + + # clear status flags + self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT) + + # set channel + self.set_channel(channel) + + # flush buffers + self.flush_rx() + self.flush_tx() + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + self.spi.init(baudrate=baudrate, polarity=0, phase=0) + else: + self.spi.init(master, baudrate=baudrate, polarity=0, phase=0) + + def reg_read(self, reg): + self.cs(0) + self.spi.readinto(self.buf, reg) + self.spi.readinto(self.buf) + self.cs(1) + return self.buf[0] + + def reg_write_bytes(self, reg, buf): + self.cs(0) + self.spi.readinto(self.buf, 0x20 | reg) + self.spi.write(buf) + self.cs(1) + return self.buf[0] + + def reg_write(self, reg, value): + self.cs(0) + self.spi.readinto(self.buf, 0x20 | reg) + ret = self.buf[0] + self.spi.readinto(self.buf, value) + self.cs(1) + return ret + + def flush_rx(self): + self.cs(0) + self.spi.readinto(self.buf, FLUSH_RX) + self.cs(1) + + def flush_tx(self): + self.cs(0) + self.spi.readinto(self.buf, FLUSH_TX) + self.cs(1) + + # power is one of POWER_x defines; speed is one of SPEED_x defines + def set_power_speed(self, power, speed): + setup = self.reg_read(RF_SETUP) & 0b11010001 + self.reg_write(RF_SETUP, setup | power | speed) + + # length in bytes: 0, 1 or 2 + def set_crc(self, length): + config = self.reg_read(CONFIG) & ~(CRCO | EN_CRC) + if length == 0: + pass + elif length == 1: + config |= EN_CRC + else: + config |= EN_CRC | CRCO + self.reg_write(CONFIG, config) + + def set_channel(self, channel): + self.reg_write(RF_CH, min(channel, 125)) + + # address should be a bytes object 5 bytes long + def open_tx_pipe(self, address): + assert len(address) == 5 + self.reg_write_bytes(RX_ADDR_P0, address) + self.reg_write_bytes(TX_ADDR, address) + self.reg_write(RX_PW_P0, self.payload_size) + + # address should be a bytes object 5 bytes long + # pipe 0 and 1 have 5 byte address + # pipes 2-5 use same 4 most-significant bytes as pipe 1, plus 1 extra byte + def open_rx_pipe(self, pipe_id, address): + assert len(address) == 5 + assert 0 <= pipe_id <= 5 + if pipe_id == 0: + self.pipe0_read_addr = address + if pipe_id < 2: + self.reg_write_bytes(RX_ADDR_P0 + pipe_id, address) + else: + self.reg_write(RX_ADDR_P0 + pipe_id, address[0]) + self.reg_write(RX_PW_P0 + pipe_id, self.payload_size) + self.reg_write(EN_RXADDR, self.reg_read(EN_RXADDR) | (1 << pipe_id)) + + def start_listening(self): + self.reg_write(CONFIG, self.reg_read(CONFIG) | PWR_UP | PRIM_RX) + self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT) + + if self.pipe0_read_addr is not None: + self.reg_write_bytes(RX_ADDR_P0, self.pipe0_read_addr) + + self.flush_rx() + self.flush_tx() + self.ce(1) + utime.sleep_us(130) + + def stop_listening(self): + self.ce(0) + self.flush_tx() + self.flush_rx() + + # returns True if any data available to recv + def any(self): + return not bool(self.reg_read(FIFO_STATUS) & RX_EMPTY) + + def recv(self): + # get the data + self.cs(0) + self.spi.readinto(self.buf, R_RX_PAYLOAD) + buf = self.spi.read(self.payload_size) + self.cs(1) + # clear RX ready flag + self.reg_write(STATUS, RX_DR) + + return buf + + # blocking wait for tx complete + def send(self, buf, timeout=500): + self.send_start(buf) + start = utime.ticks_ms() + result = None + while result is None and utime.ticks_diff(utime.ticks_ms(), start) < timeout: + result = self.send_done() # 1 == success, 2 == fail + if result == 2: + raise OSError("send failed") + + # non-blocking tx + def send_start(self, buf): + # power up + self.reg_write(CONFIG, (self.reg_read(CONFIG) | PWR_UP) & ~PRIM_RX) + utime.sleep_us(150) + # send the data + self.cs(0) + self.spi.readinto(self.buf, W_TX_PAYLOAD) + self.spi.write(buf) + if len(buf) < self.payload_size: + self.spi.write(b'\x00' * (self.payload_size - len(buf))) # pad out data + self.cs(1) + + # enable the chip so it can send the data + self.ce(1) + utime.sleep_us(15) # needs to be >10us + self.ce(0) + + # returns None if send still in progress, 1 for success, 2 for fail + def send_done(self): + if not (self.reg_read(STATUS) & (TX_DS | MAX_RT)): + return None # tx not finished + + # either finished or failed: get and clear status flags, power down + status = self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT) + self.reg_write(CONFIG, self.reg_read(CONFIG) & ~PWR_UP) + return 1 if status & TX_DS else 2 diff --git a/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01test.py b/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01test.py new file mode 100755 index 0000000..876b2bb --- /dev/null +++ b/src/openmv/src/micropython/drivers/nrf24l01/nrf24l01test.py @@ -0,0 +1,138 @@ +"""Test for nrf24l01 module. Portable between MicroPython targets.""" + +import sys +import ustruct as struct +import utime +from machine import Pin, SPI +from nrf24l01 import NRF24L01 +from micropython import const + +# Slave pause between receiving data and checking for further packets. +_RX_POLL_DELAY = const(15) +# Slave pauses an additional _SLAVE_SEND_DELAY ms after receiving data and before +# transmitting to allow the (remote) master time to get into receive mode. The +# master may be a slow device. Value tested with Pyboard, ESP32 and ESP8266. +_SLAVE_SEND_DELAY = const(10) + +if sys.platform == 'pyboard': + cfg = {'spi': 2, 'miso': 'Y7', 'mosi': 'Y8', 'sck': 'Y6', 'csn': 'Y5', 'ce': 'Y4'} +elif sys.platform == 'esp8266': # Hardware SPI + cfg = {'spi': 1, 'miso': 12, 'mosi': 13, 'sck': 14, 'csn': 4, 'ce': 5} +elif sys.platform == 'esp32': # Software SPI + cfg = {'spi': -1, 'miso': 32, 'mosi': 33, 'sck': 25, 'csn': 26, 'ce': 27} +else: + raise ValueError('Unsupported platform {}'.format(sys.platform)) + +pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2') + +def master(): + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) + + nrf.open_tx_pipe(pipes[0]) + nrf.open_rx_pipe(1, pipes[1]) + nrf.start_listening() + + num_needed = 16 + num_successes = 0 + num_failures = 0 + led_state = 0 + + print('NRF24L01 master mode, sending %d packets...' % num_needed) + + while num_successes < num_needed and num_failures < num_needed: + # stop listening and send packet + nrf.stop_listening() + millis = utime.ticks_ms() + led_state = max(1, (led_state << 1) & 0x0f) + print('sending:', millis, led_state) + try: + nrf.send(struct.pack('ii', millis, led_state)) + except OSError: + pass + + # start listening again + nrf.start_listening() + + # wait for response, with 250ms timeout + start_time = utime.ticks_ms() + timeout = False + while not nrf.any() and not timeout: + if utime.ticks_diff(utime.ticks_ms(), start_time) > 250: + timeout = True + + if timeout: + print('failed, response timed out') + num_failures += 1 + + else: + # recv packet + got_millis, = struct.unpack('i', nrf.recv()) + + # print response and round-trip delay + print('got response:', got_millis, '(delay', utime.ticks_diff(utime.ticks_ms(), got_millis), 'ms)') + num_successes += 1 + + # delay then loop + utime.sleep_ms(250) + + print('master finished sending; successes=%d, failures=%d' % (num_successes, num_failures)) + +def slave(): + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) + + nrf.open_tx_pipe(pipes[1]) + nrf.open_rx_pipe(1, pipes[0]) + nrf.start_listening() + + print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)') + + while True: + if nrf.any(): + while nrf.any(): + buf = nrf.recv() + millis, led_state = struct.unpack('ii', buf) + print('received:', millis, led_state) + for led in leds: + if led_state & 1: + led.on() + else: + led.off() + led_state >>= 1 + utime.sleep_ms(_RX_POLL_DELAY) + + # Give master time to get into receive mode. + utime.sleep_ms(_SLAVE_SEND_DELAY) + nrf.stop_listening() + try: + nrf.send(struct.pack('i', millis)) + except OSError: + pass + print('sent response') + nrf.start_listening() + +try: + import pyb + leds = [pyb.LED(i + 1) for i in range(4)] +except: + leds = [] + +print('NRF24L01 test module loaded') +print('NRF24L01 pinout for test:') +print(' CE on', cfg['ce']) +print(' CSN on', cfg['csn']) +print(' SCK on', cfg['sck']) +print(' MISO on', cfg['miso']) +print(' MOSI on', cfg['mosi']) +print('run nrf24l01test.slave() on slave, then nrf24l01test.master() on master') diff --git a/src/openmv/src/micropython/drivers/onewire/ds18x20.py b/src/openmv/src/micropython/drivers/onewire/ds18x20.py new file mode 100755 index 0000000..bf06094 --- /dev/null +++ b/src/openmv/src/micropython/drivers/onewire/ds18x20.py @@ -0,0 +1,51 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const + +_CONVERT = const(0x44) +_RD_SCRATCH = const(0xbe) +_WR_SCRATCH = const(0x4e) + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + self.buf = bytearray(9) + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): + raise Exception('CRC error') + return self.buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xff) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xffff) + 1) + return t / 16 diff --git a/src/openmv/src/micropython/drivers/onewire/onewire.py b/src/openmv/src/micropython/drivers/onewire/onewire.py new file mode 100755 index 0000000..3309ba0 --- /dev/null +++ b/src/openmv/src/micropython/drivers/onewire/onewire.py @@ -0,0 +1,91 @@ +# 1-Wire driver for MicroPython +# MIT license; Copyright (c) 2016 Damien P. George + +from micropython import const +import _onewire as _ow + +class OneWireError(Exception): + pass + +class OneWire: + SEARCH_ROM = const(0xf0) + MATCH_ROM = const(0x55) + SKIP_ROM = const(0xcc) + + def __init__(self, pin): + self.pin = pin + self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) + + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset + + def readbit(self): + return _ow.readbit(self.pin) + + def readbyte(self): + return _ow.readbyte(self.pin) + + def readinto(self, buf): + for i in range(len(buf)): + buf[i] = _ow.readbyte(self.pin) + + def writebit(self, value): + return _ow.writebit(self.pin, value) + + def writebyte(self, value): + return _ow.writebyte(self.pin, value) + + def write(self, buf): + for b in buf: + _ow.writebyte(self.pin, b) + + def select_rom(self, rom): + self.reset() + self.writebyte(MATCH_ROM) + self.write(rom) + + def scan(self): + devices = [] + diff = 65 + rom = False + for i in range(0xff): + rom, diff = self._search_rom(rom, diff) + if rom: + devices += [rom] + if diff == 0: + break + return devices + + def _search_rom(self, l_rom, diff): + if not self.reset(): + return None, 0 + self.writebyte(SEARCH_ROM) + if not l_rom: + l_rom = bytearray(8) + rom = bytearray(8) + next_diff = 0 + i = 64 + for byte in range(8): + r_b = 0 + for bit in range(8): + b = self.readbit() + if self.readbit(): + if b: # there are no devices or there is an error on the bus + return None, 0 + else: + if not b: # collision, two devices with different bit meaning + if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i): + b = 1 + next_diff = i + self.writebit(b) + if b: + r_b |= 1 << bit + i -= 1 + rom[byte] = r_b + return rom, next_diff + + def crc8(self, data): + return _ow.crc8(data) diff --git a/src/openmv/src/micropython/drivers/sdcard/sdcard.py b/src/openmv/src/micropython/drivers/sdcard/sdcard.py new file mode 100755 index 0000000..ffc551d --- /dev/null +++ b/src/openmv/src/micropython/drivers/sdcard/sdcard.py @@ -0,0 +1,278 @@ +""" +MicroPython driver for SD cards using SPI bus. + +Requires an SPI bus and a CS pin. Provides readblocks and writeblocks +methods so the device can be mounted as a filesystem. + +Example usage on pyboard: + + import pyb, sdcard, os + sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) + pyb.mount(sd, '/sd2') + os.listdir('/') + +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') + +""" + +from micropython import const +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +#R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +#R1_COM_CRC_ERROR = const(1 << 3) +#R1_ERASE_SEQUENCE_ERROR = const(1 << 4) +#R1_ADDRESS_ERROR = const(1 << 5) +#R1_PARAMETER_ERROR = const(1 << 6) +_TOKEN_CMD25 = const(0xfc) +_TOKEN_STOP_TRAN = const(0xfd) +_TOKEN_DATA = const(0xfe) + + +class SDCard: + def __init__(self, spi, cs): + self.spi = spi + self.cs = cs + + self.cmdbuf = bytearray(6) + self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) + for i in range(512): + self.dummybuf[i] = 0xff + self.dummybuf_memoryview = memoryview(self.dummybuf) + + # initialise the card + self.init_card() + + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + + def init_card(self): + # init CS pin + self.cs.init(self.cs.OUT, value=1) + + # init SPI bus; use low data rate for initialisation + self.init_spi(100000) + + # clock card at least 100 cycles with cs high + for i in range(16): + self.spi.write(b'\xff') + + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) + for _ in range(5): + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: + break + else: + raise OSError("no SD card") + + # CMD8: determine card version + r = self.cmd(8, 0x01aa, 0x87, 4) + if r == _R1_IDLE_STATE: + self.init_card_v2() + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): + self.init_card_v1() + else: + raise OSError("couldn't determine SD card version") + + # get the number of sectors + # CMD9: response R2 (R1 byte + 16-byte block read) + if self.cmd(9, 0, 0, 0, False) != 0: + raise OSError("no response from SD card") + csd = bytearray(16) + self.readinto(csd) + if csd[0] & 0xc0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 + elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 + c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 + self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) + else: + raise OSError("SD card CSD format not supported") + #print('sectors', self.sectors) + + # CMD16: set block length to 512 bytes + if self.cmd(16, 512, 0) != 0: + raise OSError("can't set 512 block size") + + # set to high data rate now that it's initialised + self.init_spi(1320000) + + def init_card_v1(self): + for i in range(_CMD_TIMEOUT): + self.cmd(55, 0, 0) + if self.cmd(41, 0, 0) == 0: + self.cdv = 512 + #print("[SDCard] v1 card") + return + raise OSError("timeout waiting for v1 card") + + def init_card_v2(self): + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) + self.cmd(58, 0, 0, 4) + self.cmd(55, 0, 0) + if self.cmd(41, 0x40000000, 0) == 0: + self.cmd(58, 0, 0, 4) + self.cdv = 1 + #print("[SDCard] v2 card") + return + raise OSError("timeout waiting for v2 card") + + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): + self.cs(0) + + # create and send the command + buf = self.cmdbuf + buf[0] = 0x40 | cmd + buf[1] = arg >> 24 + buf[2] = arg >> 16 + buf[3] = arg >> 8 + buf[4] = arg + buf[5] = crc + self.spi.write(buf) + + if skip1: + self.spi.readinto(self.tokenbuf, 0xff) + + # wait for the response (response[7] == 0) + for i in range(_CMD_TIMEOUT): + self.spi.readinto(self.tokenbuf, 0xff) + response = self.tokenbuf[0] + if not (response & 0x80): + # this could be a big-endian integer that we are getting here + for j in range(final): + self.spi.write(b'\xff') + if release: + self.cs(1) + self.spi.write(b'\xff') + return response + + # timeout + self.cs(1) + self.spi.write(b'\xff') + return -1 + + def readinto(self, buf): + self.cs(0) + + # read until start byte (0xff) + while True: + self.spi.readinto(self.tokenbuf, 0xff) + if self.tokenbuf[0] == _TOKEN_DATA: + break + + # read data + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[:len(buf)] + self.spi.write_readinto(mv, buf) + + # read checksum + self.spi.write(b'\xff') + self.spi.write(b'\xff') + + self.cs(1) + self.spi.write(b'\xff') + + def write(self, token, buf): + self.cs(0) + + # send: start of block, data, checksum + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b'\xff') + self.spi.write(b'\xff') + + # check the response + if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05: + self.cs(1) + self.spi.write(b'\xff') + return + + # wait for write to finish + while self.spi.read(1, 0xff)[0] == 0: + pass + + self.cs(1) + self.spi.write(b'\xff') + + def write_token(self, token): + self.cs(0) + self.spi.read(1, token) + self.spi.write(b'\xff') + # wait for write to finish + while self.spi.read(1, 0xff)[0] == 0x00: + pass + + self.cs(1) + self.spi.write(b'\xff') + + def readblocks(self, block_num, buf): + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, 'Buffer length is invalid' + if nblocks == 1: + # CMD17: set read address for single block + if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + # receive the data and release card + self.readinto(buf) + else: + # CMD18: set read address for multiple blocks + if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: + # release the card + self.cs(1) + raise OSError(5) # EIO + offset = 0 + mv = memoryview(buf) + while nblocks: + # receive the data and release card + self.readinto(mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + if self.cmd(12, 0, 0xff, skip1=True): + raise OSError(5) # EIO + + def writeblocks(self, block_num, buf): + nblocks, err = divmod(len(buf), 512) + assert nblocks and not err, 'Buffer length is invalid' + if nblocks == 1: + # CMD24: set write address for single block + if self.cmd(24, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + + # send the data + self.write(_TOKEN_DATA, buf) + else: + # CMD25: set write address for first block + if self.cmd(25, block_num * self.cdv, 0) != 0: + raise OSError(5) # EIO + # send the data + offset = 0 + mv = memoryview(buf) + while nblocks: + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) + offset += 512 + nblocks -= 1 + self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return self.sectors diff --git a/src/openmv/src/micropython/drivers/sdcard/sdtest.py b/src/openmv/src/micropython/drivers/sdcard/sdtest.py new file mode 100755 index 0000000..01fe65a --- /dev/null +++ b/src/openmv/src/micropython/drivers/sdcard/sdtest.py @@ -0,0 +1,60 @@ +# Test for sdcard block protocol +# Peter hinch 30th Jan 2016 +import os, sdcard, machine + +def sdtest(): + spi = machine.SPI(1) + spi.init() # Ensure right baudrate + sd = sdcard.SDCard(spi, machine.Pin.board.X21) # Compatible with PCB + vfs = os.VfsFat(sd) + os.mount(vfs, '/fc') + print('Filesystem check') + print(os.listdir('/fc')) + + line = 'abcdefghijklmnopqrstuvwxyz\n' + lines = line * 200 # 5400 chars + short = '1234567890\n' + + fn = '/fc/rats.txt' + print() + print('Multiple block read/write') + with open(fn,'w') as f: + n = f.write(lines) + print(n, 'bytes written') + n = f.write(short) + print(n, 'bytes written') + n = f.write(lines) + print(n, 'bytes written') + + with open(fn,'r') as f: + result1 = f.read() + print(len(result1), 'bytes read') + + fn = '/fc/rats1.txt' + print() + print('Single block read/write') + with open(fn,'w') as f: + n = f.write(short) # one block + print(n, 'bytes written') + + with open(fn,'r') as f: + result2 = f.read() + print(len(result2), 'bytes read') + + os.umount('/fc') + + print() + print('Verifying data read back') + success = True + if result1 == ''.join((lines, short, lines)): + print('Large file Pass') + else: + print('Large file Fail') + success = False + if result2 == short: + print('Small file Pass') + else: + print('Small file Fail') + success = False + print() + print('Tests', 'passed' if success else 'failed') diff --git a/src/openmv/src/micropython/drivers/wiznet5k/README.md b/src/openmv/src/micropython/drivers/wiznet5k/README.md new file mode 100755 index 0000000..88f25a2 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/README.md @@ -0,0 +1,6 @@ +This is the driver for the WIZnet5x00 series of Ethernet controllers. + +Adapted for MicroPython. + +Original source: https://github.com/Wiznet/W5500_EVB/tree/master/ioLibrary +Taken on: 30 August 2014 diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.c b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.c new file mode 100755 index 0000000..3ffda3a --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.c @@ -0,0 +1,725 @@ +//***************************************************************************** +// +//! \file socket.c +//! \brief SOCKET APIs Implements file. +//! \details SOCKET APIs like as Berkeley Socket APIs. +//! \version 1.0.3 +//! \date 2013/10/21 +//! \par Revision history +//! <2014/05/01> V1.0.3. Refer to M20140501 +//! 1. Implicit type casting -> Explicit type casting. +//! 2. replace 0x01 with PACK_REMAINED in recvfrom() +//! 3. Validation a destination ip in connect() & sendto(): +//! It occurs a fatal error on converting unint32 address if uint8* addr parameter is not aligned by 4byte address. +//! Copy 4 byte addr value into temporary uint32 variable and then compares it. +//! <2013/12/20> V1.0.2 Refer to M20131220 +//! Remove Warning. +//! <2013/11/04> V1.0.1 2nd Release. Refer to "20131104". +//! In sendto(), Add to clear timeout interrupt status (Sn_IR_TIMEOUT) +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 "py/mpthread.h" +#include "socket.h" + +#define SOCK_ANY_PORT_NUM 0xC000; + +static uint16_t sock_any_port = SOCK_ANY_PORT_NUM; +static uint16_t sock_io_mode = 0; +static uint16_t sock_is_sending = 0; +static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = {0,0,}; +static uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,}; + +#if _WIZCHIP_ == 5200 + static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] ={0,}; +#endif + +#define CHECK_SOCKNUM() \ + do{ \ + if(sn > _WIZCHIP_SOCK_NUM_) return SOCKERR_SOCKNUM; \ + }while(0); \ + +#define CHECK_SOCKMODE(mode) \ + do{ \ + if((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE; \ + }while(0); \ + +#define CHECK_SOCKINIT() \ + do{ \ + if((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \ + }while(0); \ + +#define CHECK_SOCKDATA() \ + do{ \ + if(len == 0) return SOCKERR_DATALEN; \ + }while(0); \ + +void WIZCHIP_EXPORT(socket_reset)(void) { + sock_any_port = SOCK_ANY_PORT_NUM; + sock_io_mode = 0; + sock_is_sending = 0; + /* + memset(sock_remained_size, 0, _WIZCHIP_SOCK_NUM_ * sizeof(uint16_t)); + memset(sock_pack_info, 0, _WIZCHIP_SOCK_NUM_ * sizeof(uint8_t)); + */ + +#if _WIZCHIP_ == 5200 + memset(sock_next_rd, 0, _WIZCHIP_SOCK_NUM_ * sizeof(uint16_t)); +#endif +} + +int8_t WIZCHIP_EXPORT(socket)(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag) +{ + CHECK_SOCKNUM(); + switch(protocol) + { + case Sn_MR_TCP : + case Sn_MR_UDP : + case Sn_MR_MACRAW : + break; + #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW : + case Sn_MR_PPPoE : + break; + #endif + default : + return SOCKERR_SOCKMODE; + } + if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG; +#if _WIZCHIP_ == 5200 + if(flag & 0x10) return SOCKERR_SOCKFLAG; +#endif + + if(flag != 0) + { + switch(protocol) + { + case Sn_MR_TCP: + if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK))==0) return SOCKERR_SOCKFLAG; + break; + case Sn_MR_UDP: + if(flag & SF_IGMP_VER2) + { + if((flag & SF_MULTI_ENABLE)==0) return SOCKERR_SOCKFLAG; + } + #if _WIZCHIP_ == 5500 + if(flag & SF_UNI_BLOCK) + { + if((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG; + } + #endif + break; + default: + break; + } + } + WIZCHIP_EXPORT(close)(sn); + setSn_MR(sn, (protocol | (flag & 0xF0))); + if(!port) + { + port = sock_any_port++; + if(sock_any_port == 0xFFF0) sock_any_port = SOCK_ANY_PORT_NUM; + } + setSn_PORT(sn,port); + setSn_CR(sn,Sn_CR_OPEN); + while(getSn_CR(sn)); + sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn); + sock_is_sending &= ~(1< freesize) len = freesize; // check size not to exceed MAX size. + while(1) + { + freesize = getSn_TX_FSR(sn); + tmp = getSn_SR(sn); + if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT)) + { + WIZCHIP_EXPORT(close)(sn); + return SOCKERR_SOCKSTATUS; + } + if( (sock_io_mode & (1< freesize) ) return SOCK_BUSY; + if(len <= freesize) break; + MICROPY_THREAD_YIELD(); + } + wiz_send_data(sn, buf, len); + #if _WIZCHIP_ == 5200 + sock_next_rd[sn] = getSn_TX_RD(sn) + len; + #endif + setSn_CR(sn,Sn_CR_SEND); + /* wait to process the command... */ + while(getSn_CR(sn)); + sock_is_sending |= (1 << sn); + return len; +} + + +int32_t WIZCHIP_EXPORT(recv)(uint8_t sn, uint8_t * buf, uint16_t len) +{ + uint8_t tmp = 0; + uint16_t recvsize = 0; + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKDATA(); + + recvsize = getSn_RxMAX(sn); + if(recvsize < len) len = recvsize; + while(1) + { + recvsize = getSn_RX_RSR(sn); + tmp = getSn_SR(sn); + if (tmp != SOCK_ESTABLISHED) + { + if(tmp == SOCK_CLOSE_WAIT) + { + if(recvsize != 0) break; + else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn)) + { + // dpgeorge: Getting here seems to be an orderly shutdown of the + // socket, and trying to get POSIX behaviour we return 0 because: + // "If no messages are available to be received and the peer has per†+ // formed an orderly shutdown, recv() shall return 0". + // TODO this return value clashes with SOCK_BUSY in non-blocking mode. + WIZCHIP_EXPORT(close)(sn); + return 0; + } + } + else + { + WIZCHIP_EXPORT(close)(sn); + return SOCKERR_SOCKSTATUS; + } + } + if((sock_io_mode & (1< freesize) len = freesize; // check size not to exceed MAX size. + while(1) + { + freesize = getSn_TX_FSR(sn); + if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if( (sock_io_mode & (1< freesize) ) return SOCK_BUSY; + if(len <= freesize) break; + MICROPY_THREAD_YIELD(); + }; + wiz_send_data(sn, buf, len); + + #if _WIZCHIP_ == 5200 // for W5200 ARP errata + setSUBR(wizchip_getsubn()); + #endif + + setSn_CR(sn,Sn_CR_SEND); + /* wait to process the command... */ + while(getSn_CR(sn)); + while(1) + { + tmp = getSn_IR(sn); + if(tmp & Sn_IR_SENDOK) + { + setSn_IR(sn, Sn_IR_SENDOK); + break; + } + //M:20131104 + //else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT; + else if(tmp & Sn_IR_TIMEOUT) + { + setSn_IR(sn, Sn_IR_TIMEOUT); + #if _WIZCHIP_ == 5200 // for W5200 ARP errata + setSUBR((uint8_t*)"\x00\x00\x00\x00"); + #endif + return SOCKERR_TIMEOUT; + } + //////////// + MICROPY_THREAD_YIELD(); + } + #if _WIZCHIP_ == 5200 // for W5200 ARP errata + setSUBR((uint8_t*)"\x00\x00\x00\x00"); + #endif + return len; +} + + + +int32_t WIZCHIP_EXPORT(recvfrom)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port) +{ + uint8_t mr; + uint8_t head[8]; + uint16_t pack_len=0; + + CHECK_SOCKNUM(); + //CHECK_SOCKMODE(Sn_MR_UDP); + switch((mr=getSn_MR(sn)) & 0x0F) + { + case Sn_MR_UDP: + case Sn_MR_MACRAW: + break; + #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + case Sn_MR_PPPoE: + break; + #endif + default: + return SOCKERR_SOCKMODE; + } + CHECK_SOCKDATA(); + if(sock_remained_size[sn] == 0) + { + while(1) + { + pack_len = getSn_RX_RSR(sn); + if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if( (sock_io_mode & (1< 1514) + { + WIZCHIP_EXPORT(close)(sn); + return SOCKFATAL_PACKLEN; + } + sock_pack_info[sn] = PACK_FIRST; + } + if(len < sock_remained_size[sn]) pack_len = len; + else pack_len = sock_remained_size[sn]; + wiz_recv_data(sn,buf,pack_len); + break; + #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + if(sock_remained_size[sn] == 0) + { + wiz_recv_data(sn, head, 6); + setSn_CR(sn,Sn_CR_RECV); + while(getSn_CR(sn)); + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + sock_remained_size[sn] = head[4]; + sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5]; + sock_pack_info[sn] = PACK_FIRST; + } + // + // Need to packet length check + // + if(len < sock_remained_size[sn]) pack_len = len; + else pack_len = sock_remained_size[sn]; + wiz_recv_data(sn, buf, pack_len); // data copy. + break; + #endif + default: + wiz_recv_ignore(sn, pack_len); // data copy. + sock_remained_size[sn] = pack_len; + break; + } + setSn_CR(sn,Sn_CR_RECV); + /* wait to process the command... */ + while(getSn_CR(sn)) ; + sock_remained_size[sn] -= pack_len; + //M20140501 : replace 0x01 with PACK_REMAINED + //if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01; + if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= PACK_REMAINED; + // + return pack_len; +} + + +int8_t WIZCHIP_EXPORT(ctlsocket)(uint8_t sn, ctlsock_type cstype, void* arg) +{ + uint8_t tmp = 0; + CHECK_SOCKNUM(); + switch(cstype) + { + case CS_SET_IOMODE: + tmp = *((uint8_t*)arg); + if(tmp == SOCK_IO_NONBLOCK) sock_io_mode |= (1< explict type casting + //*((uint8_t*)arg) = (sock_io_mode >> sn) & 0x0001; + *((uint8_t*)arg) = (uint8_t)((sock_io_mode >> sn) & 0x0001); + // + break; + case CS_GET_MAXTXBUF: + *((uint16_t*)arg) = getSn_TxMAX(sn); + break; + case CS_GET_MAXRXBUF: + *((uint16_t*)arg) = getSn_RxMAX(sn); + break; + case CS_CLR_INTERRUPT: + if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IR(sn,*(uint8_t*)arg); + break; + case CS_GET_INTERRUPT: + *((uint8_t*)arg) = getSn_IR(sn); + break; + case CS_SET_INTMASK: + if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IMR(sn,*(uint8_t*)arg); + break; + case CS_GET_INTMASK: + *((uint8_t*)arg) = getSn_IMR(sn); + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t WIZCHIP_EXPORT(setsockopt)(uint8_t sn, sockopt_type sotype, void* arg) +{ + // M20131220 : Remove warning + //uint8_t tmp; + CHECK_SOCKNUM(); + switch(sotype) + { + case SO_TTL: + setSn_TTL(sn,*(uint8_t*)arg); + break; + case SO_TOS: + setSn_TOS(sn,*(uint8_t*)arg); + break; + case SO_MSS: + setSn_MSSR(sn,*(uint16_t*)arg); + break; + case SO_DESTIP: + setSn_DIPR(sn, (uint8_t*)arg); + break; + case SO_DESTPORT: + setSn_DPORT(sn, *(uint16_t*)arg); + break; +#if _WIZCHIP_ != 5100 + case SO_KEEPALIVESEND: + CHECK_SOCKMODE(Sn_MR_TCP); + #if _WIZCHIP_ > 5200 + if(getSn_KPALVTR(sn) != 0) return SOCKERR_SOCKOPT; + #endif + setSn_CR(sn,Sn_CR_SEND_KEEP); + while(getSn_CR(sn) != 0) + { + // M20131220 + //if ((tmp = getSn_IR(sn)) & Sn_IR_TIMEOUT) + if (getSn_IR(sn) & Sn_IR_TIMEOUT) + { + setSn_IR(sn, Sn_IR_TIMEOUT); + return SOCKERR_TIMEOUT; + } + } + break; + #if _WIZCHIP_ > 5200 + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + setSn_KPALVTR(sn,*(uint8_t*)arg); + break; + #endif +#endif + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t WIZCHIP_EXPORT(getsockopt)(uint8_t sn, sockopt_type sotype, void* arg) +{ + CHECK_SOCKNUM(); + switch(sotype) + { + case SO_FLAG: + *(uint8_t*)arg = getSn_MR(sn) & 0xF0; + break; + case SO_TTL: + *(uint8_t*) arg = getSn_TTL(sn); + break; + case SO_TOS: + *(uint8_t*) arg = getSn_TOS(sn); + break; + case SO_MSS: + *(uint8_t*) arg = getSn_MSSR(sn); + case SO_DESTIP: + getSn_DIPR(sn, (uint8_t*)arg); + break; + case SO_DESTPORT: + *(uint16_t*) arg = getSn_DPORT(sn); + break; + #if _WIZCHIP_ > 5200 + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + *(uint16_t*) arg = getSn_KPALVTR(sn); + break; + #endif + case SO_SENDBUF: + *(uint16_t*) arg = getSn_TX_FSR(sn); + case SO_RECVBUF: + *(uint16_t*) arg = getSn_RX_RSR(sn); + case SO_STATUS: + *(uint8_t*) arg = getSn_SR(sn); + break; + case SO_REMAINSIZE: + if(getSn_MR(sn) == Sn_MR_TCP) + *(uint16_t*)arg = getSn_RX_RSR(sn); + else + *(uint16_t*)arg = sock_remained_size[sn]; + break; + case SO_PACKINFO: + CHECK_SOCKMODE(Sn_MR_TCP); + *(uint8_t*)arg = sock_pack_info[sn]; + break; + default: + return SOCKERR_SOCKOPT; + } + return SOCK_OK; +} diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.h b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.h new file mode 100755 index 0000000..2f03a34 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/socket.h @@ -0,0 +1,472 @@ +//***************************************************************************** +// +//! \file socket.h +//! \brief SOCKET APIs Header file. +//! \details SOCKET APIs like as berkeley socket api. +//! \version 1.0.2 +//! \date 2013/10/21 +//! \par Revision history +//! <2014/05/01> V1.0.2. Refer to M20140501 +//! 1. Modify the comment : SO_REMAINED -> PACK_REMAINED +//! 2. Add the comment as zero byte udp data reception in getsockopt(). +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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. +// +//***************************************************************************** +/** + * @defgroup WIZnet_socket_APIs 1. WIZnet socket APIs + * @brief WIZnet socket APIs are based on Berkeley socket APIs, thus it has much similar name and interface. + * But there is a little bit of difference. + * @details + * Comparison between WIZnet and Berkeley SOCKET APIs + * + * + * + * + * + * + * + * + * + * + * + * + *
API WIZnet Berkeley
socket() O O
bind() X O
listen() O O
connect() O O
accept() X O
recv() O O
send() O O
recvfrom() O O
sendto() O O
closesocket() O
close() & disconnect()
O
+ * There are @b bind() and @b accept() functions in @b Berkeley SOCKET API but, + * not in @b WIZnet SOCKET API. Because socket() of WIZnet is not only creating a SOCKET but also binding a local port number, + * and listen() of WIZnet is not only listening to connection request from client but also accepting the connection request. \n + * When you program "TCP SERVER" with Berkeley SOCKET API, you can use only one listen port. + * When the listen SOCKET accepts a connection request from a client, it keeps listening. + * After accepting the connection request, a new SOCKET is created and the new SOCKET is used in communication with the client. \n + * Following figure shows network flow diagram by Berkeley SOCKET API. + * @image html Berkeley_SOCKET.jpg "" + * But, When you program "TCP SERVER" with WIZnet SOCKET API, you can use as many as 8 listen SOCKET with same port number. \n + * Because there's no accept() in WIZnet SOCKET APIs, when the listen SOCKET accepts a connection request from a client, + * it is changed in order to communicate with the client. + * And the changed SOCKET is not listening any more and is dedicated for communicating with the client. \n + * If there're many listen SOCKET with same listen port number and a client requests a connection, + * the SOCKET which has the smallest SOCKET number accepts the request and is changed as communication SOCKET. \n + * Following figure shows network flow diagram by WIZnet SOCKET API. + * @image html WIZnet_SOCKET.jpg "" + */ +#ifndef _WIZCHIP_SOCKET_H_ +#define _WIZCHIP_SOCKET_H_ + +// use this macro for exported names to avoid name clashes +#define WIZCHIP_EXPORT(name) wizchip_ ## name + +#include "wizchip_conf.h" + +#define SOCKET uint8_t ///< SOCKET type define for legacy driver + +#define SOCK_OK 1 ///< Result is OK about socket process. +#define SOCK_BUSY 0 ///< Socket is busy on processing the operation. Valid only Non-block IO Mode. +#define SOCK_FATAL -1000 ///< Result is fatal error about socket process. + +#define SOCK_ERROR 0 +#define SOCKERR_SOCKNUM (SOCK_ERROR - 1) ///< Invalid socket number +#define SOCKERR_SOCKOPT (SOCK_ERROR - 2) ///< Invalid socket option +#define SOCKERR_SOCKINIT (SOCK_ERROR - 3) ///< Socket is not initialized +#define SOCKERR_SOCKCLOSED (SOCK_ERROR - 4) ///< Socket unexpectedly closed. +#define SOCKERR_SOCKMODE (SOCK_ERROR - 5) ///< Invalid socket mode for socket operation. +#define SOCKERR_SOCKFLAG (SOCK_ERROR - 6) ///< Invalid socket flag +#define SOCKERR_SOCKSTATUS (SOCK_ERROR - 7) ///< Invalid socket status for socket operation. +#define SOCKERR_ARG (SOCK_ERROR - 10) ///< Invalid argument. +#define SOCKERR_PORTZERO (SOCK_ERROR - 11) ///< Port number is zero +#define SOCKERR_IPINVALID (SOCK_ERROR - 12) ///< Invalid IP address +#define SOCKERR_TIMEOUT (SOCK_ERROR - 13) ///< Timeout occurred +#define SOCKERR_DATALEN (SOCK_ERROR - 14) ///< Data length is zero or greater than buffer max size. +#define SOCKERR_BUFFER (SOCK_ERROR - 15) ///< Socket buffer is not enough for data communication. + +#define SOCKFATAL_PACKLEN (SOCK_FATAL - 1) ///< Invalid packet length. Fatal Error. + +/* + * SOCKET FLAG + */ +#define SF_ETHER_OWN (Sn_MR_MFEN) ///< In \ref Sn_MR_MACRAW, Receive only the packet as broadcast, multicast and own packet +#define SF_IGMP_VER2 (Sn_MR_MC) ///< In \ref Sn_MR_UDP with \ref SF_MULTI_ENABLE, Select IGMP version 2. +#define SF_TCP_NODELAY (Sn_MR_ND) ///< In \ref Sn_MR_TCP, Use to nodelayed ack. +#define SF_MULTI_ENABLE (Sn_MR_MULTI) ///< In \ref Sn_MR_UDP, Enable multicast mode. + +#if _WIZCHIP_ == 5500 + #define SF_BROAD_BLOCK (Sn_MR_BCASTB) ///< In \ref Sn_MR_UDP or \ref Sn_MR_MACRAW, Block broadcast packet. Valid only in W5500 + #define SF_MULTI_BLOCK (Sn_MR_MMB) ///< In \ref Sn_MR_MACRAW, Block multicast packet. Valid only in W5500 + #define SF_IPv6_BLOCK (Sn_MR_MIP6B) ///< In \ref Sn_MR_MACRAW, Block IPv6 packet. Valid only in W5500 + #define SF_UNI_BLOCK (Sn_MR_UCASTB) ///< In \ref Sn_MR_UDP with \ref SF_MULTI_ENABLE. Valid only in W5500 +#endif + +#define SF_IO_NONBLOCK 0x01 ///< Socket nonblock io mode. It used parameter in \ref socket(). + +/* + * UDP & MACRAW Packet Infomation + */ +#define PACK_FIRST 0x80 ///< In Non-TCP packet, It indicates to start receiving a packet. +#define PACK_REMAINED 0x01 ///< In Non-TCP packet, It indicates to remain a packet to be received. +#define PACK_COMPLETED 0x00 ///< In Non-TCP packet, It indicates to complete to receive a packet. + +// resets all global state associated with the socket interface +void WIZCHIP_EXPORT(socket_reset)(void); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Open a socket. + * @details Initializes the socket with 'sn' passed as parameter and open. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param protocol Protocol type to operate such as TCP, UDP and MACRAW. + * @param port Port number to be bined. + * @param flag Socket flags as \ref SF_ETHER_OWN, \ref SF_IGMP_VER2, \ref SF_TCP_NODELAY, \ref SF_MULTI_ENABLE, \ref SF_IO_NONBLOCK and so on.\n + * Valid flags only in W5500 : @ref SF_BROAD_BLOCK, @ref SF_MULTI_BLOCK, @ref SF_IPv6_BLOCK, and @ref SF_UNI_BLOCK. + * @sa Sn_MR + * + * @return @b Success : The socket number @b 'sn' passed as parameter\n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Not support socket mode as TCP, UDP, and so on. \n + * @ref SOCKERR_SOCKFLAG - Invaild socket flag. + */ +int8_t WIZCHIP_EXPORT(socket)(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Close a socket. + * @details It closes the socket with @b'sn' passed as parameter. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail : @ref SOCKERR_SOCKNUM - Invalid socket number + */ +int8_t WIZCHIP_EXPORT(close)(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Listen to a connection request from a client. + * @details It is listening to a connection request from a client. + * If connection request is accepted successfully, the connection is established. Socket sn is used in passive(server) mode. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKINIT - Socket is not initialized \n + * @ref SOCKERR_SOCKCLOSED - Socket closed unexpectedly. + */ +int8_t WIZCHIP_EXPORT(listen)(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to connect a server. + * @details It requests connection to the server with destination IP address and port number passed as parameter.\n + * @note It is valid only in TCP client mode. + * In block io mode, it does not return until connection is completed. + * In Non-block io mode, it return @ref SOCK_BUSY immediately. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Invalid socket mode\n + * @ref SOCKERR_SOCKINIT - Socket is not initialized\n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_TIMEOUT - Timeout occurred during request connection\n + * @ref SOCK_BUSY - In non-block io mode, it returned immediately\n + */ +int8_t WIZCHIP_EXPORT(connect)(uint8_t sn, uint8_t * addr, uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to disconnect a connection socket. + * @details It sends request message to disconnect the TCP socket 'sn' passed as parameter to the server or client. + * @note It is valid only in TCP server or client mode. \n + * In block io mode, it does not return until disconnection is completed. \n + * In Non-block io mode, it return @ref SOCK_BUSY immediately. \n + + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int8_t WIZCHIP_EXPORT(disconnect)(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Send data to the connected peer in TCP socket. + * @details It is used to send outgoing data to the connected socket. + * @note It is valid only in TCP server or client mode. It can't send data greater than socket buffer size. \n + * In block io mode, It doesn't return until data send is completed - socket buffer size is greater than data. \n + * In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. \n + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer containing data to be sent. + * @param len The byte length of data in buf. + * @return @b Success : The sent data size \n + * @b Fail : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t WIZCHIP_EXPORT(send)(uint8_t sn, uint8_t * buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive data from the connected peer. + * @details It is used to read incoming data from the connected socket.\n + * It waits for data as much as the application wants to receive. + * @note It is valid only in TCP server or client mode. It can't receive data greater than socket buffer size. \n + * In block io mode, it doesn't return until data reception is completed - data is filled as len in socket buffer. \n + * In non-block io mode, it return @ref SOCK_BUSY immediately when len is greater than data size in socket buffer. \n + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * @return @b Success : The real received data size \n + * @b Fail :\n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t WIZCHIP_EXPORT(recv)(uint8_t sn, uint8_t * buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Sends datagram to the peer with destination IP address and port number passed as parameter. + * @details It sends datagram of UDP or MACRAW to the peer with destination IP address and port number passed as parameter.\n + * Even if the connectionless socket has been previously connected to a specific address, + * the address and port number parameters override the destination address for that particular datagram only. + * @note In block io mode, It doesn't return until data send is completed - socket buffer size is greater than len. + * In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to send outgoing data. + * @param len The byte length of data in buf. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : The sent data size \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_SOCKCLOSED - Socket unexpectedly closed \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t WIZCHIP_EXPORT(sendto)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive datagram of UDP or MACRAW + * @details This function is an application I/F function which is used to receive the data in other then TCP mode. \n + * This function is used to receive UDP and MAC_RAW mode, and handle the header as well. + * This function can divide to received the packet data. + * On the MACRAW SOCKET, the addr and port parameters are ignored. + * @note In block io mode, it doesn't return until data reception is completed - data is filled as len in socket buffer + * In non-block io mode, it return @ref SOCK_BUSY immediately when len is greater than data size in socket buffer. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * When the received packet size <= len, receives data as packet sized. + * When others, receives data as len. + * @param addr Pointer variable of destination IP address. It should be allocated 4 bytes. + * It is valid only when the first call recvfrom for receiving the packet. + * When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * @param port Pointer variable of destination port number. + * It is valid only when the first call recvform for receiving the packet. +* When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * + * @return @b Success : This function return real received data size for success.\n + * @b Fail : @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKBUSY - Socket is busy. + */ +int32_t WIZCHIP_EXPORT(recvfrom)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); + + +///////////////////////////// +// SOCKET CONTROL & OPTION // +///////////////////////////// +#define SOCK_IO_BLOCK 0 ///< Socket Block IO Mode in @ref setsockopt(). +#define SOCK_IO_NONBLOCK 1 ///< Socket Non-block IO Mode in @ref setsockopt(). + +/** + * @defgroup DATA_TYPE DATA TYPE + */ + +/** + * @ingroup DATA_TYPE + * @brief The kind of Socket Interrupt. + * @sa Sn_IR, Sn_IMR, setSn_IR(), getSn_IR(), setSn_IMR(), getSn_IMR() + */ +typedef enum +{ + SIK_CONNECTED = (1 << 0), ///< connected + SIK_DISCONNECTED = (1 << 1), ///< disconnected + SIK_RECEIVED = (1 << 2), ///< data received + SIK_TIMEOUT = (1 << 3), ///< timeout occurred + SIK_SENT = (1 << 4), ///< send ok + SIK_ALL = 0x1F, ///< all interrupt +}sockint_kind; + +/** + * @ingroup DATA_TYPE + * @brief The type of @ref ctlsocket(). + */ +typedef enum +{ + CS_SET_IOMODE, ///< set socket IO mode with @ref SOCK_IO_BLOCK or @ref SOCK_IO_NONBLOCK + CS_GET_IOMODE, ///< get socket IO mode + CS_GET_MAXTXBUF, ///< get the size of socket buffer allocated in TX memory + CS_GET_MAXRXBUF, ///< get the size of socket buffer allocated in RX memory + CS_CLR_INTERRUPT, ///< clear the interrupt of socket with @ref sockint_kind + CS_GET_INTERRUPT, ///< get the socket interrupt. refer to @ref sockint_kind + CS_SET_INTMASK, ///< set the interrupt mask of socket with @ref sockint_kind + CS_GET_INTMASK ///< get the masked interrupt of socket. refer to @ref sockint_kind +}ctlsock_type; + + +/** + * @ingroup DATA_TYPE + * @brief The type of socket option in @ref setsockopt() or @ref getsockopt() + */ +typedef enum +{ + SO_FLAG, ///< Valid only in getsockopt(), For set flag of socket refer to flag in @ref socket(). + SO_TTL, ///< Set/Get TTL. @ref Sn_TTL ( @ref setSn_TTL(), @ref getSn_TTL() ) + SO_TOS, ///< Set/Get TOS. @ref Sn_TOS ( @ref setSn_TOS(), @ref getSn_TOS() ) + SO_MSS, ///< Set/Get MSS. @ref Sn_MSSR ( @ref setSn_MSSR(), @ref getSn_MSSR() ) + SO_DESTIP, ///< Set/Get the destination IP address. @ref Sn_DIPR ( @ref setSn_DIPR(), @ref getSn_DIPR() ) + SO_DESTPORT, ///< Set/Get the destination Port number. @ref Sn_DPORT ( @ref setSn_DPORT(), @ref getSn_DPORT() ) +#if _WIZCHIP_ != 5100 + SO_KEEPALIVESEND, ///< Valid only in setsockopt. Manually send keep-alive packet in TCP mode + #if _WIZCHIP_ > 5200 + SO_KEEPALIVEAUTO, ///< Set/Get keep-alive auto transmission timer in TCP mode + #endif +#endif + SO_SENDBUF, ///< Valid only in getsockopt. Get the free data size of Socekt TX buffer. @ref Sn_TX_FSR, @ref getSn_TX_FSR() + SO_RECVBUF, ///< Valid only in getsockopt. Get the received data size in socket RX buffer. @ref Sn_RX_RSR, @ref getSn_RX_RSR() + SO_STATUS, ///< Valid only in getsockopt. Get the socket status. @ref Sn_SR, @ref getSn_SR() + SO_REMAINSIZE, ///< Valid only in getsockopt. Get the remained packet size in other then TCP mode. + SO_PACKINFO ///< Valid only in getsockopt. Get the packet information as @ref PACK_FIRST, @ref PACK_REMAINED, and @ref PACK_COMPLETED in other then TCP mode. +}sockopt_type; + +/** + * @ingroup WIZnet_socket_APIs + * @brief Control socket. + * @details Control IO mode, Interrupt & Mask of socket and get the socket buffer information. + * Refer to @ref ctlsock_type. + * @param sn socket number + * @param cstype type of control socket. refer to @ref ctlsock_type. + * @param arg Data type and value is determined according to @ref ctlsock_type. \n + * + * + * + * + * + *
@b cstype @b data type@b value
@ref CS_SET_IOMODE \n @ref CS_GET_IOMODE uint8_t @ref SOCK_IO_BLOCK @ref SOCK_IO_NONBLOCK
@ref CS_GET_MAXTXBUF \n @ref CS_GET_MAXRXBUF uint16_t 0 ~ 16K
@ref CS_CLR_INTERRUPT \n @ref CS_GET_INTERRUPT \n @ref CS_SET_INTMASK \n @ref CS_GET_INTMASK @ref sockint_kind @ref SIK_CONNECTED, etc.
+ * @return @b Success @ref SOCK_OK \n + * @b fail @ref SOCKERR_ARG - Invalid argument\n + */ +int8_t WIZCHIP_EXPORT(ctlsocket)(uint8_t sn, ctlsock_type cstype, void* arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief set socket options + * @details Set socket option like as TTL, MSS, TOS, and so on. Refer to @ref sockopt_type. + * + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + * + * + * + * + * + * + * + *
@b sotype @b data type@b value
@ref SO_TTL uint8_t 0 ~ 255
@ref SO_TOS uint8_t 0 ~ 255
@ref SO_MSS uint16_t 0 ~ 65535
@ref SO_DESTIP uint8_t[4]
@ref SO_DESTPORT uint16_t 0 ~ 65535
@ref SO_KEEPALIVESEND null null
@ref SO_KEEPALIVEAUTO uint8_t 0 ~ 255
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_TIMEOUT - Timeout occurred when sending keep-alive packet \n + */ +int8_t WIZCHIP_EXPORT(setsockopt)(uint8_t sn, sockopt_type sotype, void* arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief get socket options + * @details Get socket option like as FLAG, TTL, MSS, and so on. Refer to @ref sockopt_type + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + * + * + * + * + * + * + * + * + * + * + * + *
@b sotype @b data type@b value
@ref SO_FLAG uint8_t @ref SF_ETHER_OWN, etc...
@ref SO_TOS uint8_t 0 ~ 255
@ref SO_MSS uint16_t 0 ~ 65535
@ref SO_DESTIP uint8_t[4]
@ref SO_DESTPORT uint16_t
@ref SO_KEEPALIVEAUTO uint8_t 0 ~ 255
@ref SO_SENDBUF uint16_t 0 ~ 65535
@ref SO_RECVBUF uint16_t 0 ~ 65535
@ref SO_STATUS uint8_t @ref SOCK_ESTABLISHED, etc..
@ref SO_REMAINSIZE uint16_t 0~ 65535
@ref SO_PACKINFO uint8_t @ref PACK_FIRST, etc...
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * @note + * The option as PACK_REMAINED and SO_PACKINFO is valid only in NON-TCP mode and after call @ref recvfrom(). \n + * When SO_PACKINFO value is PACK_FIRST and the return value of recvfrom() is zero, + * This means the zero byte UDP data(UDP Header only) received. + */ +int8_t WIZCHIP_EXPORT(getsockopt)(uint8_t sn, sockopt_type sotype, void* arg); + +#endif // _WIZCHIP_SOCKET_H_ diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.c b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.c new file mode 100755 index 0000000..8c37807 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.c @@ -0,0 +1,206 @@ +// dpgeorge: this file taken from w5500/w5500.c and adapted to W5200 + +//***************************************************************************** +// +//! \file w5500.c +//! \brief W5500 HAL Interface. +//! \version 1.0.1 +//! \date 2013/10/21 +//! \par Revision history +//! <2014/05/01> V1.0.2 +//! 1. Implicit type casting -> Explicit type casting. Refer to M20140501 +//! Fixed the problem on porting into under 32bit MCU +//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh +//! Thank for your interesting and serious advices. +//! <2013/10/21> 1st Release +//! <2013/12/20> V1.0.1 +//! 1. Remove warning +//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_ +//! for loop optimized(removed). refer to M20131220 +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 "w5200.h" + +#define SMASK (0x7ff) /* tx buffer mask */ +#define RMASK (0x7ff) /* rx buffer mask */ +#define SSIZE (2048) /* max tx buffer size */ +#define RSIZE (2048) /* max rx buffer size */ + +#define TXBUF_BASE (0x8000) +#define RXBUF_BASE (0xc000) +#define SBASE(sn) (TXBUF_BASE + SSIZE * (sn)) /* tx buffer base for socket sn */ +#define RBASE(sn) (RXBUF_BASE + RSIZE * (sn)) /* rx buffer base for socket sn */ + +uint8_t WIZCHIP_READ(uint32_t AddrSel) { + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + uint8_t spi_data[4] = { + AddrSel >> 8, + AddrSel, + 0x00, + 0x01, + }; + WIZCHIP.IF.SPI._write_bytes(spi_data, 4); + uint8_t ret; + WIZCHIP.IF.SPI._read_bytes(&ret, 1); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); + + return ret; +} + +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb) { + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + uint8_t spi_data[5] = { + AddrSel >> 8, + AddrSel, + 0x80, + 0x01, + wb, + }; + WIZCHIP.IF.SPI._write_bytes(spi_data, 5); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) { + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + uint8_t spi_data[4] = { + AddrSel >> 8, + AddrSel, + 0x00 | ((len >> 8) & 0x7f), + len & 0xff, + }; + WIZCHIP.IF.SPI._write_bytes(spi_data, 4); + WIZCHIP.IF.SPI._read_bytes(pBuf, len); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) { + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + uint8_t spi_data[4] = { + AddrSel >> 8, + AddrSel, + 0x80 | ((len >> 8) & 0x7f), + len & 0xff, + }; + WIZCHIP.IF.SPI._write_bytes(spi_data, 4); + WIZCHIP.IF.SPI._write_bytes(pBuf, len); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +uint16_t getSn_TX_FSR(uint8_t sn) { + uint16_t val = 0, val1 = 0; + do { + val1 = (WIZCHIP_READ(Sn_TX_FSR(sn)) << 8) | WIZCHIP_READ(Sn_TX_FSR(sn) + 1); + if (val1 != 0) { + val = (WIZCHIP_READ(Sn_TX_FSR(sn)) << 8) | WIZCHIP_READ(Sn_TX_FSR(sn) + 1); + } + } while (val != val1); + return val; +} + +uint16_t getSn_RX_RSR(uint8_t sn) { + uint16_t val = 0, val1 = 0; + do { + val1 = (WIZCHIP_READ(Sn_RX_RSR(sn)) << 8) | WIZCHIP_READ(Sn_RX_RSR(sn) + 1); + if (val1 != 0) { + val = (WIZCHIP_READ(Sn_RX_RSR(sn)) << 8) | WIZCHIP_READ(Sn_RX_RSR(sn) + 1); + } + } while (val != val1); + return val; +} + +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len) { + if (len == 0) { + return; + } + + uint16_t ptr = getSn_TX_WR(sn); + uint16_t offset = ptr & SMASK; + uint32_t addr = offset + SBASE(sn); + + if (offset + len > SSIZE) { + // implement wrap-around circular buffer + uint16_t size = SSIZE - offset; + WIZCHIP_WRITE_BUF(addr, wizdata, size); + WIZCHIP_WRITE_BUF(SBASE(sn), wizdata + size, len - size); + } else { + WIZCHIP_WRITE_BUF(addr, wizdata, len); + } + + ptr += len; + setSn_TX_WR(sn, ptr); +} + +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len) { + if (len == 0) { + return; + } + + uint16_t ptr = getSn_RX_RD(sn); + uint16_t offset = ptr & RMASK; + uint16_t addr = RBASE(sn) + offset; + + if (offset + len > RSIZE) { + // implement wrap-around circular buffer + uint16_t size = RSIZE - offset; + WIZCHIP_READ_BUF(addr, wizdata, size); + WIZCHIP_READ_BUF(RBASE(sn), wizdata + size, len - size); + } else { + WIZCHIP_READ_BUF(addr, wizdata, len); + } + + ptr += len; + setSn_RX_RD(sn, ptr); +} + +void wiz_recv_ignore(uint8_t sn, uint16_t len) { + uint16_t ptr = getSn_RX_RD(sn); + ptr += len; + setSn_RX_RD(sn, ptr); +} diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.h b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.h new file mode 100755 index 0000000..6356194 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5200/w5200.h @@ -0,0 +1,2092 @@ +// dpgeorge: this file taken from w5500/w5500.h and adapted to W5200 + +//***************************************************************************** +// +//! \file w5500.h +//! \brief W5500 HAL Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 _W5200_H_ +#define _W5200_H_ + +#include +#include "../wizchip_conf.h" +//#include "board.h" + +#define _W5200_IO_BASE_ 0x00000000 + +#define WIZCHIP_CREG_ADDR(addr) (_W5200_IO_BASE_ + (addr)) + +#define WIZCHIP_CH_BASE (0x4000) +#define WIZCHIP_CH_SIZE (0x100) +#define WIZCHIP_SREG_ADDR(sn, addr) (_W5200_IO_BASE_ + WIZCHIP_CH_BASE + (sn) * WIZCHIP_CH_SIZE + (addr)) + +////////////////////////////// +//-------------------------- defgroup --------------------------------- +/** + * @defgroup W5500 W5500 + * + * @brief WHIZCHIP register defines and I/O functions of @b W5500. + * + * - @ref WIZCHIP_register : @ref Common_register_group and @ref Socket_register_group + * - @ref WIZCHIP_IO_Functions : @ref Basic_IO_function, @ref Common_register_access_function and @ref Socket_register_access_function + */ + + +/** + * @defgroup WIZCHIP_register WIZCHIP register + * @ingroup W5500 + * + * @brief WHIZCHIP register defines register group of @b W5500. + * + * - @ref Common_register_group : Common register group + * - @ref Socket_register_group : \c SOCKET n register group + */ + + +/** + * @defgroup WIZCHIP_IO_Functions WIZCHIP I/O functions + * @ingroup W5500 + * + * @brief This supports the basic I/O functions for @ref WIZCHIP_register. + * + * - Basic I/O function \n + * WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() \n\n + * + * - @ref Common_register_group access functions \n + * -# @b Mode \n + * getMR(), setMR() + * -# @b Interrupt \n + * getIR(), setIR(), getIMR(), setIMR(), getSIR(), setSIR(), getSIMR(), setSIMR(), getINTLEVEL(), setINTLEVEL() + * -# Network Information \n + * getSHAR(), setSHAR(), getGAR(), setGAR(), getSUBR(), setSUBR(), getSIPR(), setSIPR() + * -# @b Retransmission \n + * getRCR(), setRCR(), getRTR(), setRTR() + * -# @b PPPoE \n + * getPTIMER(), setPTIMER(), getPMAGIC(), getPMAGIC(), getPSID(), setPSID(), getPHAR(), setPHAR(), getPMRU(), setPMRU() + * -# ICMP packet \n + * getUIPR(), getUPORTR() + * -# @b etc. \n + * getPHYCFGR(), setPHYCFGR(), getVERSIONR() \n\n + * + * - \ref Socket_register_group access functions \n + * -# SOCKET control \n + * getSn_MR(), setSn_MR(), getSn_CR(), setSn_CR(), getSn_IMR(), setSn_IMR(), getSn_IR(), setSn_IR() + * -# SOCKET information \n + * getSn_SR(), getSn_DHAR(), setSn_DHAR(), getSn_PORT(), setSn_PORT(), getSn_DIPR(), setSn_DIPR(), getSn_DPORT(), setSn_DPORT() + * getSn_MSSR(), setSn_MSSR() + * -# SOCKET communication \n + * getSn_RXBUF_SIZE(), setSn_RXBUF_SIZE(), getSn_TXBUF_SIZE(), setSn_TXBUF_SIZE() \n + * getSn_TX_RD(), getSn_TX_WR(), setSn_TX_WR() \n + * getSn_RX_RD(), setSn_RX_RD(), getSn_RX_WR() \n + * getSn_TX_FSR(), getSn_RX_RSR(), getSn_KPALVTR(), setSn_KPALVTR() + * -# IP header field \n + * getSn_FRAG(), setSn_FRAG(), getSn_TOS(), setSn_TOS() \n + * getSn_TTL(), setSn_TTL() + */ + + + +/** + * @defgroup Common_register_group Common register + * @ingroup WIZCHIP_register + * + * @brief Common register group\n + * It set the basic for the networking\n + * It set the configuration such as interrupt, network information, ICMP, etc. + * @details + * @sa MR : Mode register. + * @sa GAR, SUBR, SHAR, SIPR + * @sa INTLEVEL, IR, IMR, SIR, SIMR : Interrupt. + * @sa RTR, RCR : Data retransmission. + * @sa PTIMER, PMAGIC, PHAR, PSID, PMRU : PPPoE. + * @sa UIPR, UPORTR : ICMP message. + * @sa PHYCFGR, VERSIONR : etc. + */ + + + +/** + * @defgroup Socket_register_group Socket register + * @ingroup WIZCHIP_register + * + * @brief Socket register group.\n + * Socket register configures and control SOCKETn which is necessary to data communication. + * @details + * @sa Sn_MR, Sn_CR, Sn_IR, Sn_IMR : SOCKETn Control + * @sa Sn_SR, Sn_PORT, Sn_DHAR, Sn_DIPR, Sn_DPORT : SOCKETn Information + * @sa Sn_MSSR, Sn_TOS, Sn_TTL, Sn_KPALVTR, Sn_FRAG : Internet protocol. + * @sa Sn_RXBUF_SIZE, Sn_TXBUF_SIZE, Sn_TX_FSR, Sn_TX_RD, Sn_TX_WR, Sn_RX_RSR, Sn_RX_RD, Sn_RX_WR : Data communication + */ + + + + /** + * @defgroup Basic_IO_function Basic I/O function + * @ingroup WIZCHIP_IO_Functions + * @brief These are basic input/output functions to read values from register or write values to register. + */ + +/** + * @defgroup Common_register_access_function Common register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access common registers. + */ + +/** + * @defgroup Socket_register_access_function Socket register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access socket registers. + */ + +//------------------------------- defgroup end -------------------------------------------- +//----------------------------- W5500 Common Registers IOMAP ----------------------------- +/** + * @ingroup Common_register_group + * @brief Mode Register address(R/W)\n + * @ref MR is used for S/W reset, ping block mode, PPPoE mode and etc. + * @details Each bit of @ref MR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
RST Reserved WOL PB PPPoE Reserved FARP Reserved
+ * - \ref MR_RST : Reset + * - \ref MR_WOL : Wake on LAN + * - \ref MR_PB : Ping block + * - \ref MR_PPPOE : PPPoE mode + * - \ref MR_FARP : Force ARP mode + */ +#define MR WIZCHIP_CREG_ADDR(0x0000) + +/** + * @ingroup Common_register_group + * @brief Gateway IP Register address(R/W) + * @details @ref GAR configures the default gateway address. + */ +#define GAR WIZCHIP_CREG_ADDR(0x0001) + +/** + * @ingroup Common_register_group + * @brief Subnet mask Register address(R/W) + * @details @ref SUBR configures the subnet mask address. + */ +#define SUBR WIZCHIP_CREG_ADDR(0x0005) + +/** + * @ingroup Common_register_group + * @brief Source MAC Register address(R/W) + * @details @ref SHAR configures the source hardware address. + */ +#define SHAR WIZCHIP_CREG_ADDR(0x0009) + +/** + * @ingroup Common_register_group + * @brief Source IP Register address(R/W) + * @details @ref SIPR configures the source IP address. + */ +#define SIPR WIZCHIP_CREG_ADDR(0x000f) + +/** + * @ingroup Common_register_group + * @brief Set Interrupt low level timer register address(R/W) + * @details @ref INTLEVEL configures the Interrupt Assert Time. + */ +//#define INTLEVEL (_W5500_IO_BASE_ + (0x0013 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt Register(R/W) + * @details @ref IR indicates the interrupt status. Each bit of @ref IR will be still until the bit will be written to by the host. + * If @ref IR is not equal to x00 INTn PIN is asserted to low until it is x00\n\n + * Each bit of @ref IR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
CONFLICT UNREACH PPPoE MP Reserved Reserved Reserved Reserved
+ * - \ref IR_CONFLICT : IP conflict + * - \ref IR_UNREACH : Destination unreachable + * - \ref IR_PPPoE : PPPoE connection close + * - \ref IR_MP : Magic packet + */ +#define IR WIZCHIP_CREG_ADDR(0x0015) + +/** + * @ingroup Common_register_group + * @brief Interrupt mask register(R/W) + * @details @ref IMR is used to mask interrupts. Each bit of @ref IMR corresponds to each bit of @ref IR. + * When a bit of @ref IMR is and the corresponding bit of @ref IR is an interrupt will be issued. In other words, + * if a bit of @ref IMR is an interrupt will not be issued even if the corresponding bit of @ref IR is \n\n + * Each bit of @ref IMR defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
IM_IR7 IM_IR6 IM_IR5 IM_IR4 Reserved Reserved Reserved Reserved
+ * - \ref IM_IR7 : IP Conflict Interrupt Mask + * - \ref IM_IR6 : Destination unreachable Interrupt Mask + * - \ref IM_IR5 : PPPoE Close Interrupt Mask + * - \ref IM_IR4 : Magic Packet Interrupt Mask + */ +#define IMR WIZCHIP_CREG_ADDR(0x0016) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Register(R/W) + * @details @ref SIR indicates the interrupt status of Socket.\n + * Each bit of @ref SIR be still until @ref Sn_IR is cleared by the host.\n + * If @ref Sn_IR is not equal to x00 the n-th bit of @ref SIR is and INTn PIN is asserted until @ref SIR is x00 */ +//#define SIR (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Mask Register(R/W) + * @details Each bit of @ref SIMR corresponds to each bit of @ref SIR. + * When a bit of @ref SIMR is and the corresponding bit of @ref SIR is Interrupt will be issued. + * In other words, if a bit of @ref SIMR is an interrupt will be not issued even if the corresponding bit of @ref SIR is + */ +//#define SIMR (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Timeout register address( 1 is 100us )(R/W) + * @details @ref RTR configures the retransmission timeout period. The unit of timeout period is 100us and the default of @ref RTR is x07D0or 000 + * And so the default timeout period is 200ms(100us X 2000). During the time configured by @ref RTR, W5500 waits for the peer response + * to the packet that is transmitted by \ref Sn_CR (CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP command). + * If the peer does not respond within the @ref RTR time, W5500 retransmits the packet or issues timeout. + */ +#define RTR WIZCHIP_CREG_ADDR(0x0017) + +/** + * @ingroup Common_register_group + * @brief Retry count register(R/W) + * @details @ref RCR configures the number of time of retransmission. + * When retransmission occurs as many as ref RCR+1 Timeout interrupt is issued (@ref Sn_IR[TIMEOUT] = . + */ +#define RCR WIZCHIP_CREG_ADDR(0x0019) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Request Timer register in PPPoE mode(R/W) + * @details @ref PTIMER configures the time for sending LCP echo request. The unit of time is 25ms. + */ +#define PTIMER WIZCHIP_CREG_ADDR(0x0028) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Magic number register in PPPoE mode(R/W) + * @details @ref PMAGIC configures the 4bytes magic number to be used in LCP negotiation. + */ +#define PMAGIC WIZCHIP_CREG_ADDR(0x0029) + +/** + * @ingroup Common_register_group + * @brief PPP Destination MAC Register address(R/W) + * @details @ref PHAR configures the PPPoE server hardware address that is acquired during PPPoE connection process. + */ +//#define PHAR (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Session Identification Register(R/W) + * @details @ref PSID configures the PPPoE sever session ID acquired during PPPoE connection process. + */ +//#define PSID (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Maximum Segment Size(MSS) register(R/W) + * @details @ref PMRU configures the maximum receive unit of PPPoE. + */ +//#define PMRU (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable IP register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates + * the destination IP address & port number respectively. + */ +//#define UIPR (_W5500_IO_BASE_ + (0x002a << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable Port register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR + * indicates the destination IP address & port number respectively. + */ +//#define UPORTR (_W5500_IO_BASE_ + (0x002e << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PHY Status Register(R/W) + * @details @ref PHYCFGR configures PHY operation mode and resets PHY. In addition, @ref PHYCFGR indicates the status of PHY such as duplex, Speed, Link. + */ +//#define PHYCFGR (_W5500_IO_BASE_ + (0x002E << 8) + (WIZCHIP_CREG_BLOCK << 3)) +#define PHYSTATUS WIZCHIP_CREG_ADDR(0x0035) + +// Reserved (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0031 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0032 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0033 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0034 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0035 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0036 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0037 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0038 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief chip version register address(R) + * @details @ref VERSIONR always indicates the W5500 version as @b 0x04. + */ +//#define VERSIONR (_W5200_IO_BASE_ + (0x0039 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + + +//----------------------------- W5500 Socket Registers IOMAP ----------------------------- +/** + * @ingroup Socket_register_group + * @brief socket Mode register(R/W) + * @details @ref Sn_MR configures the option or protocol type of Socket n.\n\n + * Each bit of @ref Sn_MR defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
MULTI/MFEN BCASTB ND/MC/MMB UCASTB/MIP6B Protocol[3] Protocol[2] Protocol[1] Protocol[0]
+ * - @ref Sn_MR_MULTI : Support UDP Multicasting + * - @ref Sn_MR_BCASTB : Broadcast block in UDP Multicasting + * - @ref Sn_MR_ND : No Delayed Ack(TCP) flag + * - @ref Sn_MR_MC : IGMP version used in UDP mulitcasting + * - @ref Sn_MR_MMB : Multicast Blocking in @ref Sn_MR_MACRAW mode + * - @ref Sn_MR_UCASTB : Unicast Block in UDP Multicating + * - @ref Sn_MR_MIP6B : IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * - Protocol + * + * + * + * + * + * + *
Protocol[3] Protocol[2] Protocol[1] Protocol[0] @b Meaning
0 0 0 0 Closed
0 0 0 1 TCP
0 0 1 0 UDP
0 1 0 0 MACRAW
+ * - @ref Sn_MR_MACRAW : MAC LAYER RAW SOCK \n + * - @ref Sn_MR_UDP : UDP + * - @ref Sn_MR_TCP : TCP + * - @ref Sn_MR_CLOSE : Unused socket + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR(N) WIZCHIP_SREG_ADDR(N, 0x0000) + +/** + * @ingroup Socket_register_group + * @brief Socket command register(R/W) + * @details This is used to set the command for Socket n such as OPEN, CLOSE, CONNECT, LISTEN, SEND, and RECEIVE.\n + * After W5500 accepts the command, the @ref Sn_CR register is automatically cleared to 0x00. + * Even though @ref Sn_CR is cleared to 0x00, the command is still being processed.\n + * To check whether the command is completed or not, please check the @ref Sn_IR or @ref Sn_SR. + * - @ref Sn_CR_OPEN : Initialize or open socket. + * - @ref Sn_CR_LISTEN : Wait connection request in TCP mode(Server mode) + * - @ref Sn_CR_CONNECT : Send connection request in TCP mode(Client mode) + * - @ref Sn_CR_DISCON : Send closing request in TCP mode. + * - @ref Sn_CR_CLOSE : Close socket. + * - @ref Sn_CR_SEND : Update TX buffer pointer and send data. + * - @ref Sn_CR_SEND_MAC : Send data with MAC address, so without ARP process. + * - @ref Sn_CR_SEND_KEEP : Send keep alive message. + * - @ref Sn_CR_RECV : Update RX buffer pointer and receive data. + */ +#define Sn_CR(N) WIZCHIP_SREG_ADDR(N, 0x0001) + +/** + * @ingroup Socket_register_group + * @brief Socket interrupt register(R) + * @details @ref Sn_IR indicates the status of Socket Interrupt such as establishment, termination, receiving data, timeout).\n + * When an interrupt occurs and the corresponding bit of @ref Sn_IMR is the corresponding bit of @ref Sn_IR becomes \n + * In order to clear the @ref Sn_IR bit, the host should write the bit to \n + * + * + * + *
7 6 5 4 3 2 1 0
Reserved Reserved Reserved SEND_OK TIMEOUT RECV DISCON CON
+ * - \ref Sn_IR_SENDOK : SEND_OK Interrupt + * - \ref Sn_IR_TIMEOUT : TIMEOUT Interrupt + * - \ref Sn_IR_RECV : RECV Interrupt + * - \ref Sn_IR_DISCON : DISCON Interrupt + * - \ref Sn_IR_CON : CON Interrupt + */ +#define Sn_IR(N) WIZCHIP_SREG_ADDR(N, 0x0002) + +/** + * @ingroup Socket_register_group + * @brief Socket status register(R) + * @details @ref Sn_SR indicates the status of Socket n.\n + * The status of Socket n is changed by @ref Sn_CR or some special control packet as SYN, FIN packet in TCP. + * @par Normal status + * - @ref SOCK_CLOSED : Closed + * - @ref SOCK_INIT : Initiate state + * - @ref SOCK_LISTEN : Listen state + * - @ref SOCK_ESTABLISHED : Success to connect + * - @ref SOCK_CLOSE_WAIT : Closing state + * - @ref SOCK_UDP : UDP socket + * - @ref SOCK_MACRAW : MAC raw mode socket + *@par Temporary status during changing the status of Socket n. + * - @ref SOCK_SYNSENT : This indicates Socket n sent the connect-request packet (SYN packet) to a peer. + * - @ref SOCK_SYNRECV : It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer. + * - @ref SOCK_FIN_WAIT : Connection state + * - @ref SOCK_CLOSING : Closing state + * - @ref SOCK_TIME_WAIT : Closing state + * - @ref SOCK_LAST_ACK : Closing state + */ +#define Sn_SR(N) WIZCHIP_SREG_ADDR(N, 0x0003) + +/** + * @ingroup Socket_register_group + * @brief source port register(R/W) + * @details @ref Sn_PORT configures the source port number of Socket n. + * It is valid when Socket n is used in TCP/UPD mode. It should be set before OPEN command is ordered. + */ +#define Sn_PORT(N) WIZCHIP_SREG_ADDR(N, 0x0004) + +/** + * @ingroup Socket_register_group + * @brief Peer MAC register address(R/W) + * @details @ref Sn_DHAR configures the destination hardware address of Socket n when using SEND_MAC command in UDP mode or + * it indicates that it is acquired in ARP-process by CONNECT/SEND command. + */ +#define Sn_DHAR(N) WIZCHIP_SREG_ADDR(N, 0x0006) + +/** + * @ingroup Socket_register_group + * @brief Peer IP register address(R/W) + * @details @ref Sn_DIPR configures or indicates the destination IP address of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In TCP client mode, it configures an IP address of �TCP serverbefore CONNECT command. + * In TCP server mode, it indicates an IP address of �TCP clientafter successfully establishing connection. + * In UDP mode, it configures an IP address of peer to be received the UDP packet by SEND or SEND_MAC command. + */ +#define Sn_DIPR(N) WIZCHIP_SREG_ADDR(N, 0x000c) + +/** + * @ingroup Socket_register_group + * @brief Peer port register address(R/W) + * @details @ref Sn_DPORT configures or indicates the destination port number of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In �TCP clientmode, it configures the listen port number of �TCP serverbefore CONNECT command. + * In �TCP Servermode, it indicates the port number of TCP client after successfully establishing connection. + * In UDP mode, it configures the port number of peer to be transmitted the UDP packet by SEND/SEND_MAC command. + */ +#define Sn_DPORT(N) WIZCHIP_SREG_ADDR(N, 0x0010) + +/** + * @ingroup Socket_register_group + * @brief Maximum Segment Size(Sn_MSSR0) register address(R/W) + * @details @ref Sn_MSSR configures or indicates the MTU(Maximum Transfer Unit) of Socket n. + */ +#define Sn_MSSR(N) WIZCHIP_SREG_ADDR(N, 0x0012) + +// Reserved (_W5500_IO_BASE_ + (0x0014 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief IP Type of Service(TOS) Register(R/W) + * @details @ref Sn_TOS configures the TOS(Type Of Service field in IP Header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TOS(N) WIZCHIP_SREG_ADDR(N, 0x0015) +/** + * @ingroup Socket_register_group + * @brief IP Time to live(TTL) Register(R/W) + * @details @ref Sn_TTL configures the TTL(Time To Live field in IP header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TTL(N) WIZCHIP_SREG_ADDR(N, 0x0016) +// Reserved (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Receive memory size register(R/W) + * @details @ref Sn_RXBUF_SIZE configures the RX buffer block size of Socket n. + * Socket n RX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data cannot be normally received from a peer. + * Although Socket n RX Buffer Block size is initially configured to 2Kbytes, + * user can re-configure its size using @ref Sn_RXBUF_SIZE. The total sum of @ref Sn_RXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data reception error is occurred. + */ +#define Sn_RXBUF_SIZE(N) WIZCHIP_SREG_ADDR(N, 0x001e) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory size register(R/W) + * @details @ref Sn_TXBUF_SIZE configures the TX buffer block size of Socket n. Socket n TX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data can�t be normally transmitted to a peer. + * Although Socket n TX Buffer Block size is initially configured to 2Kbytes, + * user can be re-configure its size using @ref Sn_TXBUF_SIZE. The total sum of @ref Sn_TXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data transmission error is occurred. + */ +#define Sn_TXBUF_SIZE(N) WIZCHIP_SREG_ADDR(N, 0x001f) + +/** + * @ingroup Socket_register_group + * @brief Transmit free memory size register(R) + * @details @ref Sn_TX_FSR indicates the free size of Socket n TX Buffer Block. It is initialized to the configured size by @ref Sn_TXBUF_SIZE. + * Data bigger than @ref Sn_TX_FSR should not be saved in the Socket n TX Buffer because the bigger data overwrites the previous saved data not yet sent. + * Therefore, check before saving the data to the Socket n TX Buffer, and if data is equal or smaller than its checked size, + * transmit the data with SEND/SEND_MAC command after saving the data in Socket n TX buffer. But, if data is bigger than its checked size, + * transmit the data after dividing into the checked size and saving in the Socket n TX buffer. + */ +#define Sn_TX_FSR(N) WIZCHIP_SREG_ADDR(N, 0x0020) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory read pointer register address(R) + * @details @ref Sn_TX_RD is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP. + * After its initialization, it is auto-increased by SEND command. + * SEND command transmits the saved data from the current @ref Sn_TX_RD to the @ref Sn_TX_WR in the Socket n TX Buffer. + * After transmitting the saved data, the SEND command increases the @ref Sn_TX_RD as same as the @ref Sn_TX_WR. + * If its increment value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_TX_RD(N) WIZCHIP_SREG_ADDR(N, 0x0022) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory write pointer register address(R/W) + * @details @ref Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP.\n + * It should be read or be updated like as follows.\n + * 1. Read the starting address for saving the transmitting data.\n + * 2. Save the transmitting data from the starting address of Socket n TX buffer.\n + * 3. After saving the transmitting data, update @ref Sn_TX_WR to the increased value as many as transmitting data size. + * If the increment value exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value.\n + * 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND command + */ +#define Sn_TX_WR(N) WIZCHIP_SREG_ADDR(N, 0x0024) + +/** + * @ingroup Socket_register_group + * @brief Received data size register(R) + * @details @ref Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer. + * @ref Sn_RX_RSR does not exceed the @ref Sn_RXBUF_SIZE and is calculated as the difference between + * �Socket n RX Write Pointer (@ref Sn_RX_WR)and �Socket n RX Read Pointer (@ref Sn_RX_RD) + */ +#define Sn_RX_RSR(N) WIZCHIP_SREG_ADDR(N, 0x0026) + +/** + * @ingroup Socket_register_group + * @brief Read point of Receive memory(R/W) + * @details @ref Sn_RX_RD is initialized by OPEN command. Make sure to be read or updated as follows.\n + * 1. Read the starting save address of the received data.\n + * 2. Read data from the starting address of Socket n RX Buffer.\n + * 3. After reading the received data, Update @ref Sn_RX_RD to the increased value as many as the reading size. + * If the increment value exceeds the maximum value 0xFFFF, that is, is greater than 0x10000 and the carry bit occurs, + * update with the lower 16bits value ignored the carry bit.\n + * 4. Order RECV command is for notifying the updated @ref Sn_RX_RD to W5500. + */ +#define Sn_RX_RD(N) WIZCHIP_SREG_ADDR(N, 0x0028) + +/** + * @ingroup Socket_register_group + * @brief Write point of Receive memory(R) + * @details @ref Sn_RX_WR is initialized by OPEN command and it is auto-increased by the data reception. + * If the increased value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_RX_WR(N) WIZCHIP_SREG_ADDR(N, 0x002a) + +/** + * @ingroup Socket_register_group + * @brief socket interrupt mask register(R) + * @details @ref Sn_IMR masks the interrupt of Socket n. + * Each bit corresponds to each bit of @ref Sn_IR. When a Socket n Interrupt is occurred and the corresponding bit of @ref Sn_IMR is + * the corresponding bit of @ref Sn_IR becomes When both the corresponding bit of @ref Sn_IMR and @ref Sn_IR are and the n-th bit of @ref IR is + * Host is interrupted by asserted INTn PIN to low. + */ +//#define Sn_IMR(N) (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Fragment field value in IP header register(R/W) + * @details @ref Sn_FRAG configures the FRAG(Fragment field in IP header). + */ +//#define Sn_FRAG(N) (_W5500_IO_BASE_ + (0x002D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Keep Alive Timer register(R/W) + * @details @ref Sn_KPALVTR configures the transmitting timer of �KEEP ALIVE(KA)packet of SOCKETn. It is valid only in TCP mode, + * and ignored in other modes. The time unit is 5s. + * KA packet is transmittable after @ref Sn_SR is changed to SOCK_ESTABLISHED and after the data is transmitted or received to/from a peer at least once. + * In case of '@ref Sn_KPALVTR > 0', W5500 automatically transmits KA packet after time-period for checking the TCP connection (Auto-keepalive-process). + * In case of '@ref Sn_KPALVTR = 0', Auto-keep-alive-process will not operate, + * and KA packet can be transmitted by SEND_KEEP command by the host (Manual-keep-alive-process). + * Manual-keep-alive-process is ignored in case of '@ref Sn_KPALVTR > 0'. + */ +//#define Sn_KPALVTR(N) (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +//#define Sn_TSR(N) (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + + +//----------------------------- W5500 Register values ----------------------------- + +/* MODE register values */ +/** + * @brief Reset + * @details If this bit is All internal registers will be initialized. It will be automatically cleared as after S/W reset. + */ +#define MR_RST 0x80 + +/** + * @brief Wake on LAN + * @details 0 : Disable WOL mode\n + * 1 : Enable WOL mode\n + * If WOL mode is enabled and the received magic packet over UDP has been normally processed, the Interrupt PIN (INTn) asserts to low. + * When using WOL mode, the UDP Socket should be opened with any source port number. (Refer to Socket n Mode Register (@ref Sn_MR) for opening Socket.) + * @note The magic packet over UDP supported by W5500 consists of 6 bytes synchronization stream (xFFFFFFFFFFFF and + * 16 times Target MAC address stream in UDP payload. The options such like password are ignored. You can use any UDP source port number for WOL mode. + */ +#define MR_WOL 0x20 + +/** + * @brief Ping block + * @details 0 : Disable Ping block\n + * 1 : Enable Ping block\n + * If the bit is it blocks the response to a ping request. + */ +#define MR_PB 0x10 + +/** + * @brief Enable PPPoE + * @details 0 : DisablePPPoE mode\n + * 1 : EnablePPPoE mode\n + * If you use ADSL, this bit should be + */ +#define MR_PPPOE 0x08 + +/** + * @brief Enable UDP_FORCE_ARP CHECHK + * @details 0 : Disable Force ARP mode\n + * 1 : Enable Force ARP mode\n + * In Force ARP mode, It forces on sending ARP Request whenever data is sent. + */ +#define MR_FARP 0x02 + +/* IR register values */ +/** + * @brief Check IP conflict. + * @details Bit is set as when own source IP address is same with the sender IP address in the received ARP request. + */ +#define IR_CONFLICT 0x80 + +/** + * @brief Get the destination unreachable message in UDP sending. + * @details When receiving the ICMP (Destination port unreachable) packet, this bit is set as + * When this bit is Destination Information such as IP address and Port number may be checked with the corresponding @ref UIPR & @ref UPORTR. + */ +#define IR_UNREACH 0x40 + +/** + * @brief Get the PPPoE close message. + * @details When PPPoE is disconnected during PPPoE mode, this bit is set. + */ +#define IR_PPPoE 0x20 + +/** + * @brief Get the magic packet interrupt. + * @details When WOL mode is enabled and receives the magic packet over UDP, this bit is set. + */ +#define IR_MP 0x10 + + +/* PHYCFGR register value */ +#define PHYCFGR_RST ~(1<<7) //< For PHY reset, must operate AND mask. +#define PHYCFGR_OPMD (1<<6) // Configre PHY with OPMDC value +#define PHYCFGR_OPMDC_ALLA (7<<3) +#define PHYCFGR_OPMDC_PDOWN (6<<3) +#define PHYCFGR_OPMDC_NA (5<<3) +#define PHYCFGR_OPMDC_100FA (4<<3) +#define PHYCFGR_OPMDC_100F (3<<3) +#define PHYCFGR_OPMDC_100H (2<<3) +#define PHYCFGR_OPMDC_10F (1<<3) +#define PHYCFGR_OPMDC_10H (0<<3) +#define PHYCFGR_DPX_FULL (1<<2) +#define PHYCFGR_DPX_HALF (0<<2) +#define PHYCFGR_SPD_100 (1<<1) +#define PHYCFGR_SPD_10 (0<<1) +#define PHYCFGR_LNK_ON (1<<0) +#define PHYCFGR_LNK_OFF (0<<0) + +// PHYSTATUS register +#define PHYSTATUS_POWERDOWN (0x08) +#define PHYSTATUS_LINK (0x20) + +/* IMR register values */ +/** + * @brief IP Conflict Interrupt Mask. + * @details 0: Disable IP Conflict Interrupt\n + * 1: Enable IP Conflict Interrupt + */ +#define IM_IR7 0x80 + +/** + * @brief Destination unreachable Interrupt Mask. + * @details 0: Disable Destination unreachable Interrupt\n + * 1: Enable Destination unreachable Interrupt + */ +#define IM_IR6 0x40 + +/** + * @brief PPPoE Close Interrupt Mask. + * @details 0: Disable PPPoE Close Interrupt\n + * 1: Enable PPPoE Close Interrupt + */ +#define IM_IR5 0x20 + +/** + * @brief Magic Packet Interrupt Mask. + * @details 0: Disable Magic Packet Interrupt\n + * 1: Enable Magic Packet Interrupt + */ +#define IM_IR4 0x10 + +/* Sn_MR Default values */ +/** + * @brief Support UDP Multicasting + * @details 0 : disable Multicasting\n + * 1 : enable Multicasting\n + * This bit is applied only during UDP mode(P[3:0] = 010.\n + * To use multicasting, @ref Sn_DIPR & @ref Sn_DPORT should be respectively configured with the multicast group IP address & port number + * before Socket n is opened by OPEN command of @ref Sn_CR. + */ +#define Sn_MR_MULTI 0x80 + +/** + * @brief Broadcast block in UDP Multicasting. + * @details 0 : disable Broadcast Blocking\n + * 1 : enable Broadcast Blocking\n + * This bit blocks to receive broadcasting packet during UDP mode(P[3:0] = 010.\m + * In addition, This bit does when MACRAW mode(P[3:0] = 100 + */ +//#define Sn_MR_BCASTB 0x40 + +/** + * @brief No Delayed Ack(TCP), Multicast flag + * @details 0 : Disable No Delayed ACK option\n + * 1 : Enable No Delayed ACK option\n + * This bit is applied only during TCP mode (P[3:0] = 001.\n + * When this bit is It sends the ACK packet without delay as soon as a Data packet is received from a peer.\n + * When this bit is It sends the ACK packet after waiting for the timeout time configured by @ref RTR. + */ +#define Sn_MR_ND 0x20 + +/** + * @brief Unicast Block in UDP Multicasting + * @details 0 : disable Unicast Blocking\n + * 1 : enable Unicast Blocking\n + * This bit blocks receiving the unicast packet during UDP mode(P[3:0] = 010 and MULTI = + */ +//#define Sn_MR_UCASTB 0x10 + +/** + * @brief MAC LAYER RAW SOCK + * @details This configures the protocol mode of Socket n. + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR_MACRAW 0x04 + +#define Sn_MR_IPRAW 0x03 /**< IP LAYER RAW SOCK */ + +/** + * @brief UDP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_UDP 0x02 + +/** + * @brief TCP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_TCP 0x01 + +/** + * @brief Unused socket + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_CLOSE 0x00 + +/* Sn_MR values used with Sn_MR_MACRAW */ +/** + * @brief MAC filter enable in @ref Sn_MR_MACRAW mode + * @details 0 : disable MAC Filtering\n + * 1 : enable MAC Filtering\n + * This bit is applied only during MACRAW mode(P[3:0] = 100.\n + * When set as W5500 can only receive broadcasting packet or packet sent to itself. + * When this bit is W5500 can receive all packets on Ethernet. + * If user wants to implement Hybrid TCP/IP stack, + * it is recommended that this bit is set as for reducing host overhead to process the all received packets. + */ +#define Sn_MR_MFEN Sn_MR_MULTI + +/** + * @brief Multicast Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : using IGMP version 2\n + * 1 : using IGMP version 1\n + * This bit is applied only during UDP mode(P[3:0] = 010 and MULTI = + * It configures the version for IGMP messages (Join/Leave/Report). + */ +#define Sn_MR_MMB Sn_MR_ND + +/** + * @brief IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : disable IPv6 Blocking\n + * 1 : enable IPv6 Blocking\n + * This bit is applied only during MACRAW mode (P[3:0] = 100. It blocks to receiving the IPv6 packet. + */ +#define Sn_MR_MIP6B Sn_MR_UCASTB + +/* Sn_MR value used with Sn_MR_UDP & Sn_MR_MULTI */ +/** + * @brief IGMP version used in UDP mulitcasting + * @details 0 : disable Multicast Blocking\n + * 1 : enable Multicast Blocking\n + * This bit is applied only when MACRAW mode(P[3:0] = 100. It blocks to receive the packet with multicast MAC address. + */ +#define Sn_MR_MC Sn_MR_ND + +/* Sn_MR alternate values */ +/** + * @brief For Berkeley Socket API + */ +#define SOCK_STREAM Sn_MR_TCP + +/** + * @brief For Berkeley Socket API + */ +#define SOCK_DGRAM Sn_MR_UDP + + +/* Sn_CR values */ +/** + * @brief Initialize or open socket + * @details Socket n is initialized and opened according to the protocol selected in Sn_MR(P3:P0). + * The table below shows the value of @ref Sn_SR corresponding to @ref Sn_MR.\n + * + * + * + * + * + * + *
\b Sn_MR (P[3:0]) \b Sn_SR
Sn_MR_CLOSE (000
Sn_MR_TCP (001 SOCK_INIT (0x13)
Sn_MR_UDP (010 SOCK_UDP (0x22)
S0_MR_MACRAW (100 SOCK_MACRAW (0x02)
+ */ +#define Sn_CR_OPEN 0x01 + +/** + * @brief Wait connection request in TCP mode(Server mode) + * @details This is valid only in TCP mode (Sn_MR(P3:P0) = Sn_MR_TCP). + * In this mode, Socket n operates as a �TCP serverand waits for connection-request (SYN packet) from any �TCP client + * The @ref Sn_SR changes the state from SOCK_INIT to SOCKET_LISTEN. + * When a �TCP clientconnection request is successfully established, + * the @ref Sn_SR changes from SOCK_LISTEN to SOCK_ESTABLISHED and the Sn_IR(0) becomes + * But when a �TCP clientconnection request is failed, Sn_IR(3) becomes and the status of @ref Sn_SR changes to SOCK_CLOSED. + */ +#define Sn_CR_LISTEN 0x02 + +/** + * @brief Send connection request in TCP mode(Client mode) + * @details To connect, a connect-request (SYN packet) is sent to b>TCP serverconfigured by @ref Sn_DIPR & Sn_DPORT(destination address & port). + * If the connect-request is successful, the @ref Sn_SR is changed to @ref SOCK_ESTABLISHED and the Sn_IR(0) becomes \n\n + * The connect-request fails in the following three cases.\n + * 1. When a @b ARPTO occurs (@ref Sn_IR[3] = ) because destination hardware address is not acquired through the ARP-process.\n + * 2. When a @b SYN/ACK packet is not received and @b TCPTO (Sn_IR(3) = )\n + * 3. When a @b RST packet is received instead of a @b SYN/ACK packet. In these cases, @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note This is valid only in TCP mode and operates when Socket n acts as b>TCP client + */ +#define Sn_CR_CONNECT 0x04 + +/** + * @brief Send closing request in TCP mode + * @details Regardless of b>TCP serveror b>TCP client the DISCON command processes the disconnect-process (b>Active closeor b>Passive close.\n + * @par Active close + * it transmits disconnect-request(FIN packet) to the connected peer\n + * @par Passive close + * When FIN packet is received from peer, a FIN packet is replied back to the peer.\n + * @details When the disconnect-process is successful (that is, FIN/ACK packet is received successfully), @ref Sn_SR is changed to @ref SOCK_CLOSED.\n + * Otherwise, TCPTO occurs (Sn_IR(3)=)= and then @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note Valid only in TCP mode. + */ +#define Sn_CR_DISCON 0x08 + +/** + * @brief Close socket + * @details Sn_SR is changed to @ref SOCK_CLOSED. + */ +#define Sn_CR_CLOSE 0x10 + +/** + * @brief Update TX buffer pointer and send data + * @details SEND transmits all the data in the Socket n TX buffer.\n + * For more details, please refer to Socket n TX Free Size Register (@ref Sn_TX_FSR), Socket n, + * TX Write Pointer Register(@ref Sn_TX_WR), and Socket n TX Read Pointer Register(@ref Sn_TX_RD). + */ +#define Sn_CR_SEND 0x20 + +/** + * @brief Send data with MAC address, so without ARP process + * @details The basic operation is same as SEND.\n + * Normally SEND transmits data after destination hardware address is acquired by the automatic ARP-process(Address Resolution Protocol).\n + * But SEND_MAC transmits data without the automatic ARP-process.\n + * In this case, the destination hardware address is acquired from @ref Sn_DHAR configured by host, instead of APR-process. + * @note Valid only in UDP mode. + */ +#define Sn_CR_SEND_MAC 0x21 + +/** + * @brief Send keep alive message + * @details It checks the connection status by sending 1byte keep-alive packet.\n + * If the peer can not respond to the keep-alive packet during timeout time, the connection is terminated and the timeout interrupt will occur. + * @note Valid only in TCP mode. + */ +#define Sn_CR_SEND_KEEP 0x22 + +/** + * @brief Update RX buffer pointer and receive data + * @details RECV completes the processing of the received data in Socket n RX Buffer by using a RX read pointer register (@ref Sn_RX_RD).\n + * For more details, refer to Socket n RX Received Size Register (@ref Sn_RX_RSR), Socket n RX Write Pointer Register (@ref Sn_RX_WR), + * and Socket n RX Read Pointer Register (@ref Sn_RX_RD). + */ +#define Sn_CR_RECV 0x40 + +/* Sn_IR values */ +/** + * @brief SEND_OK Interrupt + * @details This is issued when SEND command is completed. + */ +#define Sn_IR_SENDOK 0x10 + +/** + * @brief TIMEOUT Interrupt + * @details This is issued when ARPTO or TCPTO occurs. + */ +#define Sn_IR_TIMEOUT 0x08 + +/** + * @brief RECV Interrupt + * @details This is issued whenever data is received from a peer. + */ +#define Sn_IR_RECV 0x04 + +/** + * @brief DISCON Interrupt + * @details This is issued when FIN or FIN/ACK packet is received from a peer. + */ +#define Sn_IR_DISCON 0x02 + +/** + * @brief CON Interrupt + * @details This is issued one time when the connection with peer is successful and then @ref Sn_SR is changed to @ref SOCK_ESTABLISHED. + */ +#define Sn_IR_CON 0x01 + +/* Sn_SR values */ +/** + * @brief Closed + * @details This indicates that Socket n is released.\N + * When DICON, CLOSE command is ordered, or when a timeout occurs, it is changed to @ref SOCK_CLOSED regardless of previous status. + */ +#define SOCK_CLOSED 0x00 + +/** + * @brief Initiate state + * @details This indicates Socket n is opened with TCP mode.\N + * It is changed to @ref SOCK_INIT when Sn_MR(P[3:0]) = 001and OPEN command is ordered.\N + * After @ref SOCK_INIT, user can use LISTEN /CONNECT command. + */ +#define SOCK_INIT 0x13 + +/** + * @brief Listen state + * @details This indicates Socket n is operating as b>TCP servermode and waiting for connection-request (SYN packet) from a peer (b>TCP client.\n + * It will change to @ref SOCK_ESTALBLISHED when the connection-request is successfully accepted.\n + * Otherwise it will change to @ref SOCK_CLOSED after TCPTO occurred (Sn_IR(TIMEOUT) = . + */ +#define SOCK_LISTEN 0x14 + +/** + * @brief Connection state + * @details This indicates Socket n sent the connect-request packet (SYN packet) to a peer.\n + * It is temporarily shown when @ref Sn_SR is changed from @ref SOCK_INIT to @ref SOCK_ESTABLISHED by CONNECT command.\n + * If connect-accept(SYN/ACK packet) is received from the peer at SOCK_SYNSENT, it changes to @ref SOCK_ESTABLISHED.\n + * Otherwise, it changes to @ref SOCK_CLOSED after TCPTO (@ref Sn_IR[TIMEOUT] = is occurred. + */ +#define SOCK_SYNSENT 0x15 + +/** + * @brief Connection state + * @details It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer.\n + * If socket n sends the response (SYN/ACK packet) to the peer successfully, it changes to @ref SOCK_ESTABLISHED. \n + * If not, it changes to @ref SOCK_CLOSED after timeout occurs (@ref Sn_IR[TIMEOUT] = . + */ +#define SOCK_SYNRECV 0x16 + +/** + * @brief Success to connect + * @details This indicates the status of the connection of Socket n.\n + * It changes to @ref SOCK_ESTABLISHED when the b>TCP SERVERprocessed the SYN packet from the b>TCP CLIENTduring @ref SOCK_LISTEN, or + * when the CONNECT command is successful.\n + * During @ref SOCK_ESTABLISHED, DATA packet can be transferred using SEND or RECV command. + */ +#define SOCK_ESTABLISHED 0x17 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_FIN_WAIT 0x18 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_CLOSING 0x1A + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_TIME_WAIT 0x1B + +/** + * @brief Closing state + * @details This indicates Socket n received the disconnect-request (FIN packet) from the connected peer.\n + * This is half-closing status, and data can be transferred.\n + * For full-closing, DISCON command is used. But For just-closing, CLOSE command is used. + */ +#define SOCK_CLOSE_WAIT 0x1C + +/** + * @brief Closing state + * @details This indicates Socket n is waiting for the response (FIN/ACK packet) to the disconnect-request (FIN packet) by passive-close.\n + * It changes to @ref SOCK_CLOSED when Socket n received the response successfully, or when timeout occurs (@ref Sn_IR[TIMEOUT] = . + */ +#define SOCK_LAST_ACK 0x1D + +/** + * @brief UDP socket + * @details This indicates Socket n is opened in UDP mode(Sn_MR(P[3:0]) = 010.\n + * It changes to SOCK_UPD when Sn_MR(P[3:0]) = 010 and OPEN command is ordered.\n + * Unlike TCP mode, data can be transfered without the connection-process. + */ +#define SOCK_UDP 0x22 + +//#define SOCK_IPRAW 0x32 /**< IP raw mode socket */ + +/** + * @brief MAC raw mode socket + * @details This indicates Socket 0 is opened in MACRAW mode (S0_MR(P[3:0]) = 100and is valid only in Socket 0.\n + * It changes to SOCK_MACRAW when S0_MR(P[3:0] = 100and OPEN command is ordered.\n + * Like UDP mode socket, MACRAW mode Socket 0 can transfer a MAC packet (Ethernet frame) without the connection-process. + */ +#define SOCK_MACRAW 0x42 + +//#define SOCK_PPPOE 0x5F + +/* IP PROTOCOL */ +#define IPPROTO_IP 0 //< Dummy for IP +#define IPPROTO_ICMP 1 //< Control message protocol +#define IPPROTO_IGMP 2 //< Internet group management protocol +#define IPPROTO_GGP 3 //< Gateway^2 (deprecated) +#define IPPROTO_TCP 6 //< TCP +#define IPPROTO_PUP 12 //< PUP +#define IPPROTO_UDP 17 //< UDP +#define IPPROTO_IDP 22 //< XNS idp +#define IPPROTO_ND 77 //< UNOFFICIAL net disk protocol +#define IPPROTO_RAW 255 //< Raw IP packet + + +/** + * @brief Enter a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n \n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt.\n + * In OS environment, You can replace it to critical section api supported by OS. + * + * \sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * \sa WIZCHIP_CRITICAL_EXIT() + */ +#define WIZCHIP_CRITICAL_ENTER() WIZCHIP.CRIS._enter() + +/** + * @brief Exit a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n\n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt. \n + * In OS environment, You can replace it to critical section api supported by OS. + * + * @sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * @sa WIZCHIP_CRITICAL_ENTER() + */ +#ifdef _exit +#undef _exit +#endif +#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit() + + + +//////////////////////// +// Basic I/O Function // +//////////////////////// + +/** + * @ingroup Basic_IO_function + * @brief It reads 1 byte value from a register. + * @param AddrSel Register address + * @return The value of register + */ +uint8_t WIZCHIP_READ (uint32_t AddrSel); + +/** + * @ingroup Basic_IO_function + * @brief It writes 1 byte value to a register. + * @param AddrSel Register address + * @param wb Write data + * @return void + */ +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb ); + +/** + * @ingroup Basic_IO_function + * @brief It reads sequence data from registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to read data + * @param len Data length + */ +void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It writes sequence data to registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to write data + * @param len Data length + */ +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +///////////////////////////////// +// Common Register I/O function // +///////////////////////////////// +/** + * @ingroup Common_register_access_function + * @brief Set Mode Register + * @param (uint8_t)mr The value to be set. + * @sa getMR() + */ +#define setMR(mr) \ + WIZCHIP_WRITE(MR,mr) + + +/** + * @ingroup Common_register_access_function + * @brief Get Mode Register + * @return uint8_t. The value of Mode register. + * @sa setMR() + */ +#define getMR() \ + WIZCHIP_READ(MR) + +/** + * @ingroup Common_register_access_function + * @brief Set gateway IP address + * @param (uint8_t*)gar Pointer variable to set gateway IP address. It should be allocated 4 bytes. + * @sa getGAR() + */ +#define setGAR(gar) \ + WIZCHIP_WRITE_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Get gateway IP address + * @param (uint8_t*)gar Pointer variable to get gateway IP address. It should be allocated 4 bytes. + * @sa setGAR() + */ +#define getGAR(gar) \ + WIZCHIP_READ_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Set subnet mask address + * @param (uint8_t*)subr Pointer variable to set subnet mask address. It should be allocated 4 bytes. + * @sa getSUBR() + */ +#define setSUBR(subr) \ + WIZCHIP_WRITE_BUF(SUBR, subr,4) + + +/** + * @ingroup Common_register_access_function + * @brief Get subnet mask address + * @param (uint8_t*)subr Pointer variable to get subnet mask address. It should be allocated 4 bytes. + * @sa setSUBR() + */ +#define getSUBR(subr) \ + WIZCHIP_READ_BUF(SUBR, subr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set local MAC address + * @param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes. + * @sa getSHAR() + */ +#define setSHAR(shar) \ + WIZCHIP_WRITE_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local MAC address + * @param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes. + * @sa setSHAR() + */ +#define getSHAR(shar) \ + WIZCHIP_READ_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set local IP address + * @param (uint8_t*)sipr Pointer variable to set local IP address. It should be allocated 4 bytes. + * @sa getSIPR() + */ +#define setSIPR(sipr) \ + WIZCHIP_WRITE_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)sipr Pointer variable to get local IP address. It should be allocated 4 bytes. + * @sa setSIPR() + */ +#define getSIPR(sipr) \ + WIZCHIP_READ_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set INTLEVEL register + * @param (uint16_t)intlevel Value to set @ref INTLEVEL register. + * @sa getINTLEVEL() + */ +// dpgeorge: not yet implemented +#define setINTLEVEL(intlevel) (void)intlevel +#if 0 +#define setINTLEVEL(intlevel) {\ + WIZCHIP_WRITE(INTLEVEL, (uint8_t)(intlevel >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(INTLEVEL,1), (uint8_t) intlevel); \ + } +#endif + + +/** + * @ingroup Common_register_access_function + * @brief Get INTLEVEL register + * @return uint16_t. Value of @ref INTLEVEL register. + * @sa setINTLEVEL() + */ +// dpgeorge: not yet implemented +#define getINTLEVEL() (0) +#if 0 +#define getINTLEVEL() \ + ((WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1))) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Set @ref IR register + * @param (uint8_t)ir Value to set @ref IR register. + * @sa getIR() + */ +#define setIR(ir) \ + WIZCHIP_WRITE(IR, (ir & 0xF0)) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IR register + * @return uint8_t. Value of @ref IR register. + * @sa setIR() + */ +#define getIR() \ + (WIZCHIP_READ(IR) & 0xF0) +/** + * @ingroup Common_register_access_function + * @brief Set @ref IMR register + * @param (uint8_t)imr Value to set @ref IMR register. + * @sa getIMR() + */ +#define setIMR(imr) \ + WIZCHIP_WRITE(IMR, imr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IMR register + * @return uint8_t. Value of @ref IMR register. + * @sa setIMR() + */ +#define getIMR() \ + WIZCHIP_READ(IMR) + + +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIR register + * @param (uint8_t)sir Value to set @ref SIR register. + * @sa getSIR() + */ +// dpgeorge: not yet implemented +#define setSIR(sir) ((void)sir) +#if 0 +#define setSIR(sir) \ + WIZCHIP_WRITE(SIR, sir) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIR register + * @return uint8_t. Value of @ref SIR register. + * @sa setSIR() + */ +// dpgeorge: not yet implemented +#define getSIR() (0) +#if 0 +#define getSIR() \ + WIZCHIP_READ(SIR) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIMR register + * @param (uint8_t)simr Value to set @ref SIMR register. + * @sa getSIMR() + */ +// dpgeorge: not yet implemented +#define setSIMR(simr) ((void)simr) +#if 0 +#define setSIMR(simr) \ + WIZCHIP_WRITE(SIMR, simr) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIMR register + * @return uint8_t. Value of @ref SIMR register. + * @sa setSIMR() + */ +// dpgeorge: not yet implemented +#define getSIMR() (0) +#if 0 +#define getSIMR() \ + WIZCHIP_READ(SIMR) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Set @ref RTR register + * @param (uint16_t)rtr Value to set @ref RTR register. + * @sa getRTR() + */ +#define setRTR(rtr) {\ + WIZCHIP_WRITE(RTR, (uint8_t)(rtr >> 8)); \ + WIZCHIP_WRITE(RTR + 1, (uint8_t) rtr); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref RTR register + * @return uint16_t. Value of @ref RTR register. + * @sa setRTR() + */ +#define getRTR() \ + ((WIZCHIP_READ(RTR) << 8) + WIZCHIP_READ(RTR + 1)) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref RCR register + * @param (uint8_t)rcr Value to set @ref RCR register. + * @sa getRCR() + */ +#define setRCR(rcr) \ + WIZCHIP_WRITE(RCR, rcr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref RCR register + * @return uint8_t. Value of @ref RCR register. + * @sa setRCR() + */ +#define getRCR() \ + WIZCHIP_READ(RCR) + +//================================================== test done =========================================================== + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PTIMER register + * @param (uint8_t)ptimer Value to set @ref PTIMER register. + * @sa getPTIMER() + */ +#define setPTIMER(ptimer) \ + WIZCHIP_WRITE(PTIMER, ptimer) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PTIMER register + * @return uint8_t. Value of @ref PTIMER register. + * @sa setPTIMER() + */ +#define getPTIMER() \ + WIZCHIP_READ(PTIMER) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMAGIC register + * @param (uint8_t)pmagic Value to set @ref PMAGIC register. + * @sa getPMAGIC() + */ +#define setPMAGIC(pmagic) \ + WIZCHIP_WRITE(PMAGIC, pmagic) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMAGIC register + * @return uint8_t. Value of @ref PMAGIC register. + * @sa setPMAGIC() + */ +#define getPMAGIC() \ + WIZCHIP_READ(PMAGIC) + +/** + * @ingroup Common_register_access_function + * @brief Set PHAR address + * @param (uint8_t*)phar Pointer variable to set PPP destination MAC register address. It should be allocated 6 bytes. + * @sa getPHAR() + */ +#if 0 +#define setPHAR(phar) \ + WIZCHIP_WRITE_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)phar Pointer variable to PPP destination MAC register address. It should be allocated 6 bytes. + * @sa setPHAR() + */ +#define getPHAR(phar) \ + WIZCHIP_READ_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PSID register + * @param (uint16_t)psid Value to set @ref PSID register. + * @sa getPSID() + */ +#define setPSID(psid) {\ + WIZCHIP_WRITE(PSID, (uint8_t)(psid >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PSID,1), (uint8_t) psid); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PSID register + * @return uint16_t. Value of @ref PSID register. + * @sa setPSID() + */ +//uint16_t getPSID(void); +#define getPSID() \ + ((WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMRU register + * @param (uint16_t)pmru Value to set @ref PMRU register. + * @sa getPMRU() + */ +#define setPMRU(pmru) { \ + WIZCHIP_WRITE(PMRU, (uint8_t)(pmru>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PMRU,1), (uint8_t) pmru); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMRU register + * @return uint16_t. Value of @ref PMRU register. + * @sa setPMRU() + */ +#define getPMRU() \ + ((WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1))) + +/** + * @ingroup Common_register_access_function + * @brief Get unreachable IP address + * @param (uint8_t*)uipr Pointer variable to get unreachable IP address. It should be allocated 4 bytes. + */ +#define getUIPR(uipr) \ + WIZCHIP_READ_BUF(UIPR,uipr,6) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref UPORTR register + * @return uint16_t. Value of @ref UPORTR register. + */ +#define getUPORTR() \ + ((WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHYCFGR register + * @param (uint8_t)phycfgr Value to set @ref PHYCFGR register. + * @sa getPHYCFGR() + */ +#define setPHYCFGR(phycfgr) \ + WIZCHIP_WRITE(PHYCFGR, phycfgr) +#endif + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHYCFGR register + * @return uint8_t. Value of @ref PHYCFGR register. + * @sa setPHYCFGR() + */ +#define getPHYSTATUS() \ + WIZCHIP_READ(PHYSTATUS) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref VERSIONR register + * @return uint8_t. Value of @ref VERSIONR register. + */ +/* +#define getVERSIONR() \ + WIZCHIP_READ(VERSIONR) + */ +///////////////////////////////////// + +/////////////////////////////////// +// Socket N register I/O function // +/////////////////////////////////// +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)mr Value to set @ref Sn_MR + * @sa getSn_MR() + */ +#define setSn_MR(sn, mr) \ + WIZCHIP_WRITE(Sn_MR(sn),mr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_MR. + * @sa setSn_MR() + */ +#define getSn_MR(sn) \ + WIZCHIP_READ(Sn_MR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)cr Value to set @ref Sn_CR + * @sa getSn_CR() + */ +#define setSn_CR(sn, cr) \ + WIZCHIP_WRITE(Sn_CR(sn), cr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_CR. + * @sa setSn_CR() + */ +#define getSn_CR(sn) \ + WIZCHIP_READ(Sn_CR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ir Value to set @ref Sn_IR + * @sa getSn_IR() + */ +#define setSn_IR(sn, ir) \ + WIZCHIP_WRITE(Sn_IR(sn), (ir & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IR. + * @sa setSn_IR() + */ +#define getSn_IR(sn) \ + (WIZCHIP_READ(Sn_IR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)imr Value to set @ref Sn_IMR + * @sa getSn_IMR() + */ +// dpgeorge: not yet implemented +#define setSn_IMR(sn, imr) (void)sn; (void)imr +#if 0 +#define setSn_IMR(sn, imr) \ + WIZCHIP_WRITE(Sn_IMR(sn), (imr & 0x1F)) +#endif + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IMR. + * @sa setSn_IMR() + */ +// dpgeorge: not yet implemented +#define getSn_IMR(sn) (0) +#if 0 +#define getSn_IMR(sn) \ + (WIZCHIP_READ(Sn_IMR(sn)) & 0x1F) +#endif + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_SR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_SR. + */ +#define getSn_SR(sn) \ + WIZCHIP_READ(Sn_SR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)port Value to set @ref Sn_PORT. + * @sa getSn_PORT() + */ +#define setSn_PORT(sn, port) { \ + WIZCHIP_WRITE(Sn_PORT(sn), (uint8_t)(port >> 8)); \ + WIZCHIP_WRITE(Sn_PORT(sn) + 1, (uint8_t) port); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_PORT. + * @sa setSn_PORT() + */ +#define getSn_PORT(sn) \ + ((WIZCHIP_READ(Sn_PORT(sn)) << 8) | WIZCHIP_READ(Sn_PORT(sn) + 1)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DHAR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to set socket n destination hardware address. It should be allocated 6 bytes. + * @sa getSn_DHAR() + */ +#define setSn_DHAR(sn, dhar) \ + WIZCHIP_WRITE_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to get socket n destination hardware address. It should be allocated 6 bytes. + * @sa setSn_DHAR() + */ +#define getSn_DHAR(sn, dhar) \ + WIZCHIP_READ_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to set socket n destination IP address. It should be allocated 4 bytes. + * @sa getSn_DIPR() + */ +#define setSn_DIPR(sn, dipr) \ + WIZCHIP_WRITE_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to get socket n destination IP address. It should be allocated 4 bytes. + * @sa SetSn_DIPR() + */ +#define getSn_DIPR(sn, dipr) \ + WIZCHIP_READ_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)dport Value to set @ref Sn_DPORT + * @sa getSn_DPORT() + */ +#define setSn_DPORT(sn, dport) { \ + WIZCHIP_WRITE(Sn_DPORT(sn), (uint8_t) (dport>>8)); \ + WIZCHIP_WRITE(Sn_DPORT(sn) + 1, (uint8_t) dport); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_DPORT. + * @sa setSn_DPORT() + */ +#define getSn_DPORT(sn) \ + ((WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ((Sn_DPORT(sn)+1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)mss Value to set @ref Sn_MSSR + * @sa setSn_MSSR() + */ +#define setSn_MSSR(sn, mss) { \ + WIZCHIP_WRITE(Sn_MSSR(sn), (uint8_t)(mss>>8)); \ + WIZCHIP_WRITE((Sn_MSSR(sn)+1), (uint8_t) mss); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_MSSR. + * @sa setSn_MSSR() + */ +#define getSn_MSSR(sn) \ + ((WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ((Sn_MSSR(sn)+1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)tos Value to set @ref Sn_TOS + * @sa getSn_TOS() + */ +#define setSn_TOS(sn, tos) \ + WIZCHIP_WRITE(Sn_TOS(sn), tos) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of Sn_TOS. + * @sa setSn_TOS() + */ +#define getSn_TOS(sn) \ + WIZCHIP_READ(Sn_TOS(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ttl Value to set @ref Sn_TTL + * @sa getSn_TTL() + */ +#define setSn_TTL(sn, ttl) \ + WIZCHIP_WRITE(Sn_TTL(sn), ttl) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TTL. + * @sa setSn_TTL() + */ +#define getSn_TTL(sn) \ + WIZCHIP_READ(Sn_TTL(sn)) + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE + * @sa getSn_RXBUF_SIZE() + */ +#define setSn_RXBUF_SIZE(sn, rxbufsize) \ + WIZCHIP_WRITE(Sn_RXBUF_SIZE(sn),rxbufsize) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_RXBUF_SIZE. + * @sa setSn_RXBUF_SIZE() + */ +#define getSn_RXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_RXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE + * @sa getSn_TXBUF_SIZE() + */ +#define setSn_TXBUF_SIZE(sn, txbufsize) \ + WIZCHIP_WRITE(Sn_TXBUF_SIZE(sn), txbufsize) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TXBUF_SIZE. + * @sa setSn_TXBUF_SIZE() + */ +#define getSn_TXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_TXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_FSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_FSR. + */ +uint16_t getSn_TX_FSR(uint8_t sn); + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_RD. + */ +#define getSn_TX_RD(sn) \ + ((WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ((Sn_TX_RD(sn)+1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)txwr Value to set @ref Sn_TX_WR + * @sa GetSn_TX_WR() + */ +#define setSn_TX_WR(sn, txwr) { \ + WIZCHIP_WRITE(Sn_TX_WR(sn), (uint8_t)(txwr>>8)); \ + WIZCHIP_WRITE((Sn_TX_WR(sn)+1), (uint8_t) txwr); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_WR. + * @sa setSn_TX_WR() + */ +#define getSn_TX_WR(sn) \ + ((WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ((Sn_TX_WR(sn)+1))) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RSR. + */ +uint16_t getSn_RX_RSR(uint8_t sn); + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)rxrd Value to set @ref Sn_RX_RD + * @sa getSn_RX_RD() + */ +#define setSn_RX_RD(sn, rxrd) { \ + WIZCHIP_WRITE(Sn_RX_RD(sn), (uint8_t)(rxrd>>8)); \ + WIZCHIP_WRITE((Sn_RX_RD(sn)+1), (uint8_t) rxrd); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @regurn uint16_t. Value of @ref Sn_RX_RD. + * @sa setSn_RX_RD() + */ +#define getSn_RX_RD(sn) \ + ((WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ((Sn_RX_RD(sn)+1))) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_WR. + */ +#define getSn_RX_WR(sn) \ + ((WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ((Sn_RX_WR(sn)+1))) + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)frag Value to set @ref Sn_FRAG + * @sa getSn_FRAD() + */ +#if 0 // dpgeorge +#define setSn_FRAG(sn, frag) { \ + WIZCHIP_WRITE(Sn_FRAG(sn), (uint8_t)(frag >>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1), (uint8_t) frag); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_FRAG. + * @sa setSn_FRAG() + */ +#define getSn_FRAG(sn) \ + ((WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)kpalvt Value to set @ref Sn_KPALVTR + * @sa getSn_KPALVTR() + */ +#define setSn_KPALVTR(sn, kpalvt) \ + WIZCHIP_WRITE(Sn_KPALVTR(sn), kpalvt) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_KPALVTR. + * @sa setSn_KPALVTR() + */ +#define getSn_KPALVTR(sn) \ + WIZCHIP_READ(Sn_KPALVTR(sn)) + +////////////////////////////////////// +#endif + +///////////////////////////////////// +// Sn_TXBUF & Sn_RXBUF IO function // +///////////////////////////////////// +/** + * @brief Gets the max buffer size of socket sn passed as parameter. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n RX max buffer size. + */ +#define getSn_RxMAX(sn) \ + (getSn_RXBUF_SIZE(sn) << 10) + +/** + * @brief Gets the max buffer size of socket sn passed as parameters. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n TX max buffer size. + */ +//uint16_t getSn_TxMAX(uint8_t sn); +#define getSn_TxMAX(sn) \ + (getSn_TXBUF_SIZE(sn) << 10) + +void wiz_init(void); + +/** + * @ingroup Basic_IO_function + * @brief It copies data to internal TX memory + * + * @details This function reads the Tx write pointer register and after that, + * it copies the wizdata(pointer buffer) of the length of len(variable) bytes to internal TX memory + * and updates the Tx write pointer register. + * This function is being called by send() and sendto() function also. + * + * @note User should read upper byte first and lower byte later to get proper value. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to write data + * @param len Data length + * @sa wiz_recv_data() + */ +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It copies data to your buffer from internal RX memory + * + * @details This function read the Rx read pointer register and after that, + * it copies the received data from internal RX memory + * to wizdata(pointer variable) of the length of len(variable) bytes. + * This function is being called by recv() also. + * + * @note User should read upper byte first and lower byte later to get proper value. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to read data + * @param len Data length + * @sa wiz_send_data() + */ +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It discard the received data in RX memory. + * @details It discards the data of the length of len(variable) bytes in internal RX memory. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param len Data length + */ +void wiz_recv_ignore(uint8_t sn, uint16_t len); + +#endif // _W5500_H_ diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.c b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.c new file mode 100755 index 0000000..3107b1b --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.c @@ -0,0 +1,247 @@ +//***************************************************************************** +// +//! \file w5500.c +//! \brief W5500 HAL Interface. +//! \version 1.0.1 +//! \date 2013/10/21 +//! \par Revision history +//! <2014/05/01> V1.0.2 +//! 1. Implicit type casting -> Explicit type casting. Refer to M20140501 +//! Fixed the problem on porting into under 32bit MCU +//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh +//! Thank for your interesting and serious advices. +//! <2013/10/21> 1st Release +//! <2013/12/20> V1.0.1 +//! 1. Remove warning +//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_ +//! for loop optimized(removed). refer to M20131220 +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 "w5500.h" + +#define _W5500_SPI_VDM_OP_ 0x00 +#define _W5500_SPI_FDM_OP_LEN1_ 0x01 +#define _W5500_SPI_FDM_OP_LEN2_ 0x02 +#define _W5500_SPI_FDM_OP_LEN4_ 0x03 + +//////////////////////////////////////////////////// + +#define LPC_SSP0 (0) + +static void Chip_SSP_ReadFrames_Blocking(int dummy, uint8_t *buf, uint32_t len) { + WIZCHIP.IF.SPI._read_bytes(buf, len); +} + +static void Chip_SSP_WriteFrames_Blocking(int dummy, const uint8_t *buf, uint32_t len) { + WIZCHIP.IF.SPI._write_bytes(buf, len); +} + +uint8_t WIZCHIP_READ(uint32_t AddrSel) +{ + uint8_t ret; + uint8_t spi_data[3]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + //ret = WIZCHIP.IF.SPI._read_byte(); + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3); + Chip_SSP_ReadFrames_Blocking(LPC_SSP0, &ret, 1); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); + return ret; +} + +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb ) +{ + uint8_t spi_data[4]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + //WIZCHIP.IF.SPI._write_byte(wb); + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + spi_data[3] = wb; + Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 4); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len) +{ + uint8_t spi_data[3]; + //uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + //for(i = 0; i < len; i++) + // pBuf[i] = WIZCHIP.IF.SPI._read_byte(); + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3); + Chip_SSP_ReadFrames_Blocking(LPC_SSP0, pBuf, len); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) +{ + uint8_t spi_data[3]; + //uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + //WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + //for(i = 0; i < len; i++) + // WIZCHIP.IF.SPI._write_byte(pBuf[i]); + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3); + Chip_SSP_WriteFrames_Blocking(LPC_SSP0, pBuf, len); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + + +uint16_t getSn_TX_FSR(uint8_t sn) +{ + uint16_t val=0,val1=0; + + do + { + val1 = WIZCHIP_READ(Sn_TX_FSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1)); + if (val1 != 0) + { + val = WIZCHIP_READ(Sn_TX_FSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1)); + } + }while (val != val1); + return val; +} + + +uint16_t getSn_RX_RSR(uint8_t sn) +{ + uint16_t val=0,val1=0; + + do + { + val1 = WIZCHIP_READ(Sn_RX_RSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1)); + if (val1 != 0) + { + val = WIZCHIP_READ(Sn_RX_RSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1)); + } + }while (val != val1); + return val; +} + +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len) +{ + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if(len == 0) return; + ptr = getSn_TX_WR(sn); + //M20140501 : implict type casting -> explict type casting + //addrsel = (ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + // + WIZCHIP_WRITE_BUF(addrsel,wizdata, len); + + ptr += len; + setSn_TX_WR(sn,ptr); +} + +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len) +{ + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if(len == 0) return; + ptr = getSn_RX_RD(sn); + //M20140501 : implict type casting -> explict type casting + //addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + // + WIZCHIP_READ_BUF(addrsel, wizdata, len); + ptr += len; + + setSn_RX_RD(sn,ptr); +} + + +void wiz_recv_ignore(uint8_t sn, uint16_t len) +{ + uint16_t ptr = 0; + + ptr = getSn_RX_RD(sn); + ptr += len; + setSn_RX_RD(sn,ptr); +} + diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.h b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.h new file mode 100755 index 0000000..c2afb18 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/w5500/w5500.h @@ -0,0 +1,2057 @@ +//***************************************************************************** +// +//! \file w5500.h +//! \brief W5500 HAL Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 _W5500_H_ +#define _W5500_H_ + +#include +#include "../wizchip_conf.h" + +#define _W5500_IO_BASE_ 0x00000000 + +#define _W5500_SPI_READ_ (0x00 << 2) //< SPI interface Read operation in Control Phase +#define _W5500_SPI_WRITE_ (0x01 << 2) //< SPI interface Write operation in Control Phase + +#define WIZCHIP_CREG_BLOCK 0x00 //< Common register block +#define WIZCHIP_SREG_BLOCK(N) (1+4*N) //< Socket N register block +#define WIZCHIP_TXBUF_BLOCK(N) (2+4*N) //< Socket N Tx buffer address block +#define WIZCHIP_RXBUF_BLOCK(N) (3+4*N) //< Socket N Rx buffer address block + +#define WIZCHIP_OFFSET_INC(ADDR, N) (ADDR + (N<<8)) //< Increase offset address + + +/////////////////////////////////////// +// Definition For Legacy Chip Driver // +/////////////////////////////////////// +#define IINCHIP_READ(ADDR) WIZCHIP_READ(ADDR) ///< The defined for legacy chip driver +#define IINCHIP_WRITE(ADDR,VAL) WIZCHIP_WRITE(ADDR,VAL) ///< The defined for legacy chip driver +#define IINCHIP_READ_BUF(ADDR,BUF,LEN) WIZCHIP_READ_BUF(ADDR,BUF,LEN) ///< The defined for legacy chip driver +#define IINCHIP_WRITE_BUF(ADDR,BUF,LEN) WIZCHIP_WRITE(ADDR,BUF,LEN) ///< The defined for legacy chip driver + +////////////////////////////// +//-------------------------- defgroup --------------------------------- +/** + * @defgroup W5500 W5500 + * + * @brief WHIZCHIP register defines and I/O functions of @b W5500. + * + * - @ref WIZCHIP_register : @ref Common_register_group and @ref Socket_register_group + * - @ref WIZCHIP_IO_Functions : @ref Basic_IO_function, @ref Common_register_access_function and @ref Socket_register_access_function + */ + + +/** + * @defgroup WIZCHIP_register WIZCHIP register + * @ingroup W5500 + * + * @brief WHIZCHIP register defines register group of @b W5500. + * + * - @ref Common_register_group : Common register group + * - @ref Socket_register_group : \c SOCKET n register group + */ + + +/** + * @defgroup WIZCHIP_IO_Functions WIZCHIP I/O functions + * @ingroup W5500 + * + * @brief This supports the basic I/O functions for @ref WIZCHIP_register. + * + * - Basic I/O function \n + * WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() \n\n + * + * - @ref Common_register_group access functions \n + * -# @b Mode \n + * getMR(), setMR() + * -# @b Interrupt \n + * getIR(), setIR(), getIMR(), setIMR(), getSIR(), setSIR(), getSIMR(), setSIMR(), getINTLEVEL(), setINTLEVEL() + * -# Network Information \n + * getSHAR(), setSHAR(), getGAR(), setGAR(), getSUBR(), setSUBR(), getSIPR(), setSIPR() + * -# @b Retransmission \n + * getRCR(), setRCR(), getRTR(), setRTR() + * -# @b PPPoE \n + * getPTIMER(), setPTIMER(), getPMAGIC(), getPMAGIC(), getPSID(), setPSID(), getPHAR(), setPHAR(), getPMRU(), setPMRU() + * -# ICMP packet \n + * getUIPR(), getUPORTR() + * -# @b etc. \n + * getPHYCFGR(), setPHYCFGR(), getVERSIONR() \n\n + * + * - \ref Socket_register_group access functions \n + * -# SOCKET control \n + * getSn_MR(), setSn_MR(), getSn_CR(), setSn_CR(), getSn_IMR(), setSn_IMR(), getSn_IR(), setSn_IR() + * -# SOCKET information \n + * getSn_SR(), getSn_DHAR(), setSn_DHAR(), getSn_PORT(), setSn_PORT(), getSn_DIPR(), setSn_DIPR(), getSn_DPORT(), setSn_DPORT() + * getSn_MSSR(), setSn_MSSR() + * -# SOCKET communication \n + * getSn_RXBUF_SIZE(), setSn_RXBUF_SIZE(), getSn_TXBUF_SIZE(), setSn_TXBUF_SIZE() \n + * getSn_TX_RD(), getSn_TX_WR(), setSn_TX_WR() \n + * getSn_RX_RD(), setSn_RX_RD(), getSn_RX_WR() \n + * getSn_TX_FSR(), getSn_RX_RSR(), getSn_KPALVTR(), setSn_KPALVTR() + * -# IP header field \n + * getSn_FRAG(), setSn_FRAG(), getSn_TOS(), setSn_TOS() \n + * getSn_TTL(), setSn_TTL() + */ + + + +/** + * @defgroup Common_register_group Common register + * @ingroup WIZCHIP_register + * + * @brief Common register group\n + * It set the basic for the networking\n + * It set the configuration such as interrupt, network information, ICMP, etc. + * @details + * @sa MR : Mode register. + * @sa GAR, SUBR, SHAR, SIPR + * @sa INTLEVEL, IR, IMR, SIR, SIMR : Interrupt. + * @sa RTR, RCR : Data retransmission. + * @sa PTIMER, PMAGIC, PHAR, PSID, PMRU : PPPoE. + * @sa UIPR, UPORTR : ICMP message. + * @sa PHYCFGR, VERSIONR : etc. + */ + + + +/** + * @defgroup Socket_register_group Socket register + * @ingroup WIZCHIP_register + * + * @brief Socket register group.\n + * Socket register configures and control SOCKETn which is necessary to data communication. + * @details + * @sa Sn_MR, Sn_CR, Sn_IR, Sn_IMR : SOCKETn Control + * @sa Sn_SR, Sn_PORT, Sn_DHAR, Sn_DIPR, Sn_DPORT : SOCKETn Information + * @sa Sn_MSSR, Sn_TOS, Sn_TTL, Sn_KPALVTR, Sn_FRAG : Internet protocol. + * @sa Sn_RXBUF_SIZE, Sn_TXBUF_SIZE, Sn_TX_FSR, Sn_TX_RD, Sn_TX_WR, Sn_RX_RSR, Sn_RX_RD, Sn_RX_WR : Data communication + */ + + + + /** + * @defgroup Basic_IO_function Basic I/O function + * @ingroup WIZCHIP_IO_Functions + * @brief These are basic input/output functions to read values from register or write values to register. + */ + +/** + * @defgroup Common_register_access_function Common register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access common registers. + */ + +/** + * @defgroup Socket_register_access_function Socket register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access socket registers. + */ + +//------------------------------- defgroup end -------------------------------------------- +//----------------------------- W5500 Common Registers IOMAP ----------------------------- +/** + * @ingroup Common_register_group + * @brief Mode Register address(R/W)\n + * @ref MR is used for S/W reset, ping block mode, PPPoE mode and etc. + * @details Each bit of @ref MR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
RST Reserved WOL PB PPPoE Reserved FARP Reserved
+ * - \ref MR_RST : Reset + * - \ref MR_WOL : Wake on LAN + * - \ref MR_PB : Ping block + * - \ref MR_PPPOE : PPPoE mode + * - \ref MR_FARP : Force ARP mode + */ +#define MR (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Gateway IP Register address(R/W) + * @details @ref GAR configures the default gateway address. + */ +#define GAR (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Subnet mask Register address(R/W) + * @details @ref SUBR configures the subnet mask address. + */ +#define SUBR (_W5500_IO_BASE_ + (0x0005 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source MAC Register address(R/W) + * @details @ref SHAR configures the source hardware address. + */ +#define SHAR (_W5500_IO_BASE_ + (0x0009 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source IP Register address(R/W) + * @details @ref SIPR configures the source IP address. + */ +#define SIPR (_W5500_IO_BASE_ + (0x000F << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Set Interrupt low level timer register address(R/W) + * @details @ref INTLEVEL configures the Interrupt Assert Time. + */ +#define INTLEVEL (_W5500_IO_BASE_ + (0x0013 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt Register(R/W) + * @details @ref IR indicates the interrupt status. Each bit of @ref IR will be still until the bit will be written to by the host. + * If @ref IR is not equal to x00 INTn PIN is asserted to low until it is x00\n\n + * Each bit of @ref IR defined as follows. + * + * + * + *
7 6 5 4 3 2 1 0
CONFLICT UNREACH PPPoE MP Reserved Reserved Reserved Reserved
+ * - \ref IR_CONFLICT : IP conflict + * - \ref IR_UNREACH : Destination unreachable + * - \ref IR_PPPoE : PPPoE connection close + * - \ref IR_MP : Magic packet + */ +#define IR (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt mask register(R/W) + * @details @ref IMR is used to mask interrupts. Each bit of @ref IMR corresponds to each bit of @ref IR. + * When a bit of @ref IMR is and the corresponding bit of @ref IR is an interrupt will be issued. In other words, + * if a bit of @ref IMR is an interrupt will not be issued even if the corresponding bit of @ref IR is \n\n + * Each bit of @ref IMR defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
IM_IR7 IM_IR6 IM_IR5 IM_IR4 Reserved Reserved Reserved Reserved
+ * - \ref IM_IR7 : IP Conflict Interrupt Mask + * - \ref IM_IR6 : Destination unreachable Interrupt Mask + * - \ref IM_IR5 : PPPoE Close Interrupt Mask + * - \ref IM_IR4 : Magic Packet Interrupt Mask + */ +#define IMR (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Register(R/W) + * @details @ref SIR indicates the interrupt status of Socket.\n + * Each bit of @ref SIR be still until @ref Sn_IR is cleared by the host.\n + * If @ref Sn_IR is not equal to x00 the n-th bit of @ref SIR is and INTn PIN is asserted until @ref SIR is x00 */ +#define SIR (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Mask Register(R/W) + * @details Each bit of @ref SIMR corresponds to each bit of @ref SIR. + * When a bit of @ref SIMR is and the corresponding bit of @ref SIR is Interrupt will be issued. + * In other words, if a bit of @ref SIMR is an interrupt will be not issued even if the corresponding bit of @ref SIR is + */ +#define SIMR (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Timeout register address( 1 is 100us )(R/W) + * @details @ref RTR configures the retransmission timeout period. The unit of timeout period is 100us and the default of @ref RTR is x07D0or 000 + * And so the default timeout period is 200ms(100us X 2000). During the time configured by @ref RTR, W5500 waits for the peer response + * to the packet that is transmitted by \ref Sn_CR (CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP command). + * If the peer does not respond within the @ref RTR time, W5500 retransmits the packet or issues timeout. + */ +#define RTR (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Retry count register(R/W) + * @details @ref RCR configures the number of time of retransmission. + * When retransmission occurs as many as ref RCR+1 Timeout interrupt is issued (@ref Sn_IR[TIMEOUT] = . + */ +#define RCR (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Request Timer register in PPPoE mode(R/W) + * @details @ref PTIMER configures the time for sending LCP echo request. The unit of time is 25ms. + */ +#define PTIMER (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Magic number register in PPPoE mode(R/W) + * @details @ref PMAGIC configures the 4bytes magic number to be used in LCP negotiation. + */ +#define PMAGIC (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Destination MAC Register address(R/W) + * @details @ref PHAR configures the PPPoE server hardware address that is acquired during PPPoE connection process. + */ +#define PHAR (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Session Identification Register(R/W) + * @details @ref PSID configures the PPPoE sever session ID acquired during PPPoE connection process. + */ +#define PSID (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Maximum Segment Size(MSS) register(R/W) + * @details @ref PMRU configures the maximum receive unit of PPPoE. + */ +#define PMRU (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable IP register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates + * the destination IP address & port number respectively. + */ +#define UIPR (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable Port register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when data is sent to a port number + * which socket is not open and @ref UNREACH bit of @ref IR becomes and @ref UIPR & @ref UPORTR + * indicates the destination IP address & port number respectively. + */ +#define UPORTR (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PHY Status Register(R/W) + * @details @ref PHYCFGR configures PHY operation mode and resets PHY. In addition, @ref PHYCFGR indicates the status of PHY such as duplex, Speed, Link. + */ +#define PHYCFGR (_W5500_IO_BASE_ + (0x002E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0031 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0032 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0033 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0034 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0035 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0036 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0037 << 8) + (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0038 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief chip version register address(R) + * @details @ref VERSIONR always indicates the W5500 version as @b 0x04. + */ +#define VERSIONR (_W5500_IO_BASE_ + (0x0039 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + + +//----------------------------- W5500 Socket Registers IOMAP ----------------------------- +/** + * @ingroup Socket_register_group + * @brief socket Mode register(R/W) + * @details @ref Sn_MR configures the option or protocol type of Socket n.\n\n + * Each bit of @ref Sn_MR defined as the following. + * + * + * + *
7 6 5 4 3 2 1 0
MULTI/MFEN BCASTB ND/MC/MMB UCASTB/MIP6B Protocol[3] Protocol[2] Protocol[1] Protocol[0]
+ * - @ref Sn_MR_MULTI : Support UDP Multicasting + * - @ref Sn_MR_BCASTB : Broadcast block in UDP Multicasting + * - @ref Sn_MR_ND : No Delayed Ack(TCP) flag + * - @ref Sn_MR_MC : IGMP version used in UDP mulitcasting + * - @ref Sn_MR_MMB : Multicast Blocking in @ref Sn_MR_MACRAW mode + * - @ref Sn_MR_UCASTB : Unicast Block in UDP Multicating + * - @ref Sn_MR_MIP6B : IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * - Protocol + * + * + * + * + * + * + *
Protocol[3] Protocol[2] Protocol[1] Protocol[0] @b Meaning
0 0 0 0 Closed
0 0 0 1 TCP
0 0 1 0 UDP
0 1 0 0 MACRAW
+ * - @ref Sn_MR_MACRAW : MAC LAYER RAW SOCK \n + * - @ref Sn_MR_UDP : UDP + * - @ref Sn_MR_TCP : TCP + * - @ref Sn_MR_CLOSE : Unused socket + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR(N) (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket command register(R/W) + * @details This is used to set the command for Socket n such as OPEN, CLOSE, CONNECT, LISTEN, SEND, and RECEIVE.\n + * After W5500 accepts the command, the @ref Sn_CR register is automatically cleared to 0x00. + * Even though @ref Sn_CR is cleared to 0x00, the command is still being processed.\n + * To check whether the command is completed or not, please check the @ref Sn_IR or @ref Sn_SR. + * - @ref Sn_CR_OPEN : Initialize or open socket. + * - @ref Sn_CR_LISTEN : Wait connection request in TCP mode(Server mode) + * - @ref Sn_CR_CONNECT : Send connection request in TCP mode(Client mode) + * - @ref Sn_CR_DISCON : Send closing request in TCP mode. + * - @ref Sn_CR_CLOSE : Close socket. + * - @ref Sn_CR_SEND : Update TX buffer pointer and send data. + * - @ref Sn_CR_SEND_MAC : Send data with MAC address, so without ARP process. + * - @ref Sn_CR_SEND_KEEP : Send keep alive message. + * - @ref Sn_CR_RECV : Update RX buffer pointer and receive data. + */ +#define Sn_CR(N) (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket interrupt register(R) + * @details @ref Sn_IR indicates the status of Socket Interrupt such as establishment, termination, receiving data, timeout).\n + * When an interrupt occurs and the corresponding bit of @ref Sn_IMR is the corresponding bit of @ref Sn_IR becomes \n + * In order to clear the @ref Sn_IR bit, the host should write the bit to \n + * + * + * + *
7 6 5 4 3 2 1 0
Reserved Reserved Reserved SEND_OK TIMEOUT RECV DISCON CON
+ * - \ref Sn_IR_SENDOK : SEND_OK Interrupt + * - \ref Sn_IR_TIMEOUT : TIMEOUT Interrupt + * - \ref Sn_IR_RECV : RECV Interrupt + * - \ref Sn_IR_DISCON : DISCON Interrupt + * - \ref Sn_IR_CON : CON Interrupt + */ +#define Sn_IR(N) (_W5500_IO_BASE_ + (0x0002 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket status register(R) + * @details @ref Sn_SR indicates the status of Socket n.\n + * The status of Socket n is changed by @ref Sn_CR or some special control packet as SYN, FIN packet in TCP. + * @par Normal status + * - @ref SOCK_CLOSED : Closed + * - @ref SOCK_INIT : Initiate state + * - @ref SOCK_LISTEN : Listen state + * - @ref SOCK_ESTABLISHED : Success to connect + * - @ref SOCK_CLOSE_WAIT : Closing state + * - @ref SOCK_UDP : UDP socket + * - @ref SOCK_MACRAW : MAC raw mode socket + *@par Temporary status during changing the status of Socket n. + * - @ref SOCK_SYNSENT : This indicates Socket n sent the connect-request packet (SYN packet) to a peer. + * - @ref SOCK_SYNRECV : It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer. + * - @ref SOCK_FIN_WAIT : Connection state + * - @ref SOCK_CLOSING : Closing state + * - @ref SOCK_TIME_WAIT : Closing state + * - @ref SOCK_LAST_ACK : Closing state + */ +#define Sn_SR(N) (_W5500_IO_BASE_ + (0x0003 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief source port register(R/W) + * @details @ref Sn_PORT configures the source port number of Socket n. + * It is valid when Socket n is used in TCP/UPD mode. It should be set before OPEN command is ordered. + */ +#define Sn_PORT(N) (_W5500_IO_BASE_ + (0x0004 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer MAC register address(R/W) + * @details @ref Sn_DHAR configures the destination hardware address of Socket n when using SEND_MAC command in UDP mode or + * it indicates that it is acquired in ARP-process by CONNECT/SEND command. + */ +#define Sn_DHAR(N) (_W5500_IO_BASE_ + (0x0006 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer IP register address(R/W) + * @details @ref Sn_DIPR configures or indicates the destination IP address of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In TCP client mode, it configures an IP address of �TCP serverbefore CONNECT command. + * In TCP server mode, it indicates an IP address of �TCP clientafter successfully establishing connection. + * In UDP mode, it configures an IP address of peer to be received the UDP packet by SEND or SEND_MAC command. + */ +#define Sn_DIPR(N) (_W5500_IO_BASE_ + (0x000C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer port register address(R/W) + * @details @ref Sn_DPORT configures or indicates the destination port number of Socket n. It is valid when Socket n is used in TCP/UDP mode. + * In �TCP clientmode, it configures the listen port number of �TCP serverbefore CONNECT command. + * In �TCP Servermode, it indicates the port number of TCP client after successfully establishing connection. + * In UDP mode, it configures the port number of peer to be transmitted the UDP packet by SEND/SEND_MAC command. + */ +#define Sn_DPORT(N) (_W5500_IO_BASE_ + (0x0010 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Maximum Segment Size(Sn_MSSR0) register address(R/W) + * @details @ref Sn_MSSR configures or indicates the MTU(Maximum Transfer Unit) of Socket n. + */ +#define Sn_MSSR(N) (_W5500_IO_BASE_ + (0x0012 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x0014 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief IP Type of Service(TOS) Register(R/W) + * @details @ref Sn_TOS configures the TOS(Type Of Service field in IP Header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TOS(N) (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +/** + * @ingroup Socket_register_group + * @brief IP Time to live(TTL) Register(R/W) + * @details @ref Sn_TTL configures the TTL(Time To Live field in IP header) of Socket n. + * It is set before OPEN command. + */ +#define Sn_TTL(N) (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Receive memory size register(R/W) + * @details @ref Sn_RXBUF_SIZE configures the RX buffer block size of Socket n. + * Socket n RX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data cannot be normally received from a peer. + * Although Socket n RX Buffer Block size is initially configured to 2Kbytes, + * user can re-configure its size using @ref Sn_RXBUF_SIZE. The total sum of @ref Sn_RXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data reception error is occurred. + */ +#define Sn_RXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory size register(R/W) + * @details @ref Sn_TXBUF_SIZE configures the TX buffer block size of Socket n. Socket n TX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data can�t be normally transmitted to a peer. + * Although Socket n TX Buffer Block size is initially configured to 2Kbytes, + * user can be re-configure its size using @ref Sn_TXBUF_SIZE. The total sum of @ref Sn_TXBUF_SIZE can not be exceed 16Kbytes. + * When exceeded, the data transmission error is occurred. + */ +#define Sn_TXBUF_SIZE(N) (_W5500_IO_BASE_ + (0x001F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit free memory size register(R) + * @details @ref Sn_TX_FSR indicates the free size of Socket n TX Buffer Block. It is initialized to the configured size by @ref Sn_TXBUF_SIZE. + * Data bigger than @ref Sn_TX_FSR should not be saved in the Socket n TX Buffer because the bigger data overwrites the previous saved data not yet sent. + * Therefore, check before saving the data to the Socket n TX Buffer, and if data is equal or smaller than its checked size, + * transmit the data with SEND/SEND_MAC command after saving the data in Socket n TX buffer. But, if data is bigger than its checked size, + * transmit the data after dividing into the checked size and saving in the Socket n TX buffer. + */ +#define Sn_TX_FSR(N) (_W5500_IO_BASE_ + (0x0020 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory read pointer register address(R) + * @details @ref Sn_TX_RD is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP. + * After its initialization, it is auto-increased by SEND command. + * SEND command transmits the saved data from the current @ref Sn_TX_RD to the @ref Sn_TX_WR in the Socket n TX Buffer. + * After transmitting the saved data, the SEND command increases the @ref Sn_TX_RD as same as the @ref Sn_TX_WR. + * If its increment value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_TX_RD(N) (_W5500_IO_BASE_ + (0x0022 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory write pointer register address(R/W) + * @details @ref Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with TCP.\n + * It should be read or be updated like as follows.\n + * 1. Read the starting address for saving the transmitting data.\n + * 2. Save the transmitting data from the starting address of Socket n TX buffer.\n + * 3. After saving the transmitting data, update @ref Sn_TX_WR to the increased value as many as transmitting data size. + * If the increment value exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value.\n + * 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND command + */ +#define Sn_TX_WR(N) (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Received data size register(R) + * @details @ref Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer. + * @ref Sn_RX_RSR does not exceed the @ref Sn_RXBUF_SIZE and is calculated as the difference between + * �Socket n RX Write Pointer (@ref Sn_RX_WR)and �Socket n RX Read Pointer (@ref Sn_RX_RD) + */ +#define Sn_RX_RSR(N) (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Read point of Receive memory(R/W) + * @details @ref Sn_RX_RD is initialized by OPEN command. Make sure to be read or updated as follows.\n + * 1. Read the starting save address of the received data.\n + * 2. Read data from the starting address of Socket n RX Buffer.\n + * 3. After reading the received data, Update @ref Sn_RX_RD to the increased value as many as the reading size. + * If the increment value exceeds the maximum value 0xFFFF, that is, is greater than 0x10000 and the carry bit occurs, + * update with the lower 16bits value ignored the carry bit.\n + * 4. Order RECV command is for notifying the updated @ref Sn_RX_RD to W5500. + */ +#define Sn_RX_RD(N) (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Write point of Receive memory(R) + * @details @ref Sn_RX_WR is initialized by OPEN command and it is auto-increased by the data reception. + * If the increased value exceeds the maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), + * then the carry bit is ignored and will automatically update with the lower 16bits value. + */ +#define Sn_RX_WR(N) (_W5500_IO_BASE_ + (0x002A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief socket interrupt mask register(R) + * @details @ref Sn_IMR masks the interrupt of Socket n. + * Each bit corresponds to each bit of @ref Sn_IR. When a Socket n Interrupt is occurred and the corresponding bit of @ref Sn_IMR is + * the corresponding bit of @ref Sn_IR becomes When both the corresponding bit of @ref Sn_IMR and @ref Sn_IR are and the n-th bit of @ref IR is + * Host is interrupted by asserted INTn PIN to low. + */ +#define Sn_IMR(N) (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Fragment field value in IP header register(R/W) + * @details @ref Sn_FRAG configures the FRAG(Fragment field in IP header). + */ +#define Sn_FRAG(N) (_W5500_IO_BASE_ + (0x002D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Keep Alive Timer register(R/W) + * @details @ref Sn_KPALVTR configures the transmitting timer of �KEEP ALIVE(KA)packet of SOCKETn. It is valid only in TCP mode, + * and ignored in other modes. The time unit is 5s. + * KA packet is transmittable after @ref Sn_SR is changed to SOCK_ESTABLISHED and after the data is transmitted or received to/from a peer at least once. + * In case of '@ref Sn_KPALVTR > 0', W5500 automatically transmits KA packet after time-period for checking the TCP connection (Auto-keepalive-process). + * In case of '@ref Sn_KPALVTR = 0', Auto-keep-alive-process will not operate, + * and KA packet can be transmitted by SEND_KEEP command by the host (Manual-keep-alive-process). + * Manual-keep-alive-process is ignored in case of '@ref Sn_KPALVTR > 0'. + */ +#define Sn_KPALVTR(N) (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +//#define Sn_TSR(N) (_W5500_IO_BASE_ + (0x0030 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + + +//----------------------------- W5500 Register values ----------------------------- + +/* MODE register values */ +/** + * @brief Reset + * @details If this bit is All internal registers will be initialized. It will be automatically cleared as after S/W reset. + */ +#define MR_RST 0x80 + +/** + * @brief Wake on LAN + * @details 0 : Disable WOL mode\n + * 1 : Enable WOL mode\n + * If WOL mode is enabled and the received magic packet over UDP has been normally processed, the Interrupt PIN (INTn) asserts to low. + * When using WOL mode, the UDP Socket should be opened with any source port number. (Refer to Socket n Mode Register (@ref Sn_MR) for opening Socket.) + * @note The magic packet over UDP supported by W5500 consists of 6 bytes synchronization stream (xFFFFFFFFFFFF and + * 16 times Target MAC address stream in UDP payload. The options such like password are ignored. You can use any UDP source port number for WOL mode. + */ +#define MR_WOL 0x20 + +/** + * @brief Ping block + * @details 0 : Disable Ping block\n + * 1 : Enable Ping block\n + * If the bit is it blocks the response to a ping request. + */ +#define MR_PB 0x10 + +/** + * @brief Enable PPPoE + * @details 0 : DisablePPPoE mode\n + * 1 : EnablePPPoE mode\n + * If you use ADSL, this bit should be + */ +#define MR_PPPOE 0x08 + +/** + * @brief Enable UDP_FORCE_ARP CHECHK + * @details 0 : Disable Force ARP mode\n + * 1 : Enable Force ARP mode\n + * In Force ARP mode, It forces on sending ARP Request whenever data is sent. + */ +#define MR_FARP 0x02 + +/* IR register values */ +/** + * @brief Check IP conflict. + * @details Bit is set as when own source IP address is same with the sender IP address in the received ARP request. + */ +#define IR_CONFLICT 0x80 + +/** + * @brief Get the destination unreachable message in UDP sending. + * @details When receiving the ICMP (Destination port unreachable) packet, this bit is set as + * When this bit is Destination Information such as IP address and Port number may be checked with the corresponding @ref UIPR & @ref UPORTR. + */ +#define IR_UNREACH 0x40 + +/** + * @brief Get the PPPoE close message. + * @details When PPPoE is disconnected during PPPoE mode, this bit is set. + */ +#define IR_PPPoE 0x20 + +/** + * @brief Get the magic packet interrupt. + * @details When WOL mode is enabled and receives the magic packet over UDP, this bit is set. + */ +#define IR_MP 0x10 + + +/* PHYCFGR register value */ +#define PHYCFGR_RST ~(1<<7) //< For PHY reset, must operate AND mask. +#define PHYCFGR_OPMD (1<<6) // Configre PHY with OPMDC value +#define PHYCFGR_OPMDC_ALLA (7<<3) +#define PHYCFGR_OPMDC_PDOWN (6<<3) +#define PHYCFGR_OPMDC_NA (5<<3) +#define PHYCFGR_OPMDC_100FA (4<<3) +#define PHYCFGR_OPMDC_100F (3<<3) +#define PHYCFGR_OPMDC_100H (2<<3) +#define PHYCFGR_OPMDC_10F (1<<3) +#define PHYCFGR_OPMDC_10H (0<<3) +#define PHYCFGR_DPX_FULL (1<<2) +#define PHYCFGR_DPX_HALF (0<<2) +#define PHYCFGR_SPD_100 (1<<1) +#define PHYCFGR_SPD_10 (0<<1) +#define PHYCFGR_LNK_ON (1<<0) +#define PHYCFGR_LNK_OFF (0<<0) + +/* IMR register values */ +/** + * @brief IP Conflict Interrupt Mask. + * @details 0: Disable IP Conflict Interrupt\n + * 1: Enable IP Conflict Interrupt + */ +#define IM_IR7 0x80 + +/** + * @brief Destination unreachable Interrupt Mask. + * @details 0: Disable Destination unreachable Interrupt\n + * 1: Enable Destination unreachable Interrupt + */ +#define IM_IR6 0x40 + +/** + * @brief PPPoE Close Interrupt Mask. + * @details 0: Disable PPPoE Close Interrupt\n + * 1: Enable PPPoE Close Interrupt + */ +#define IM_IR5 0x20 + +/** + * @brief Magic Packet Interrupt Mask. + * @details 0: Disable Magic Packet Interrupt\n + * 1: Enable Magic Packet Interrupt + */ +#define IM_IR4 0x10 + +/* Sn_MR Default values */ +/** + * @brief Support UDP Multicasting + * @details 0 : disable Multicasting\n + * 1 : enable Multicasting\n + * This bit is applied only during UDP mode(P[3:0] = 010.\n + * To use multicasting, @ref Sn_DIPR & @ref Sn_DPORT should be respectively configured with the multicast group IP address & port number + * before Socket n is opened by OPEN command of @ref Sn_CR. + */ +#define Sn_MR_MULTI 0x80 + +/** + * @brief Broadcast block in UDP Multicasting. + * @details 0 : disable Broadcast Blocking\n + * 1 : enable Broadcast Blocking\n + * This bit blocks to receive broadcasting packet during UDP mode(P[3:0] = 010.\m + * In addition, This bit does when MACRAW mode(P[3:0] = 100 + */ +#define Sn_MR_BCASTB 0x40 + +/** + * @brief No Delayed Ack(TCP), Multicast flag + * @details 0 : Disable No Delayed ACK option\n + * 1 : Enable No Delayed ACK option\n + * This bit is applied only during TCP mode (P[3:0] = 001.\n + * When this bit is It sends the ACK packet without delay as soon as a Data packet is received from a peer.\n + * When this bit is It sends the ACK packet after waiting for the timeout time configured by @ref RTR. + */ +#define Sn_MR_ND 0x20 + +/** + * @brief Unicast Block in UDP Multicasting + * @details 0 : disable Unicast Blocking\n + * 1 : enable Unicast Blocking\n + * This bit blocks receiving the unicast packet during UDP mode(P[3:0] = 010 and MULTI = + */ +#define Sn_MR_UCASTB 0x10 + +/** + * @brief MAC LAYER RAW SOCK + * @details This configures the protocol mode of Socket n. + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR_MACRAW 0x04 + +//#define Sn_MR_IPRAW 0x03 /**< IP LAYER RAW SOCK */ + +/** + * @brief UDP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_UDP 0x02 + +/** + * @brief TCP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_TCP 0x01 + +/** + * @brief Unused socket + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_CLOSE 0x00 + +/* Sn_MR values used with Sn_MR_MACRAW */ +/** + * @brief MAC filter enable in @ref Sn_MR_MACRAW mode + * @details 0 : disable MAC Filtering\n + * 1 : enable MAC Filtering\n + * This bit is applied only during MACRAW mode(P[3:0] = 100.\n + * When set as W5500 can only receive broadcasting packet or packet sent to itself. + * When this bit is W5500 can receive all packets on Ethernet. + * If user wants to implement Hybrid TCP/IP stack, + * it is recommended that this bit is set as for reducing host overhead to process the all received packets. + */ +#define Sn_MR_MFEN Sn_MR_MULTI + +/** + * @brief Multicast Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : using IGMP version 2\n + * 1 : using IGMP version 1\n + * This bit is applied only during UDP mode(P[3:0] = 010 and MULTI = + * It configures the version for IGMP messages (Join/Leave/Report). + */ +#define Sn_MR_MMB Sn_MR_ND + +/** + * @brief IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : disable IPv6 Blocking\n + * 1 : enable IPv6 Blocking\n + * This bit is applied only during MACRAW mode (P[3:0] = 100. It blocks to receiving the IPv6 packet. + */ +#define Sn_MR_MIP6B Sn_MR_UCASTB + +/* Sn_MR value used with Sn_MR_UDP & Sn_MR_MULTI */ +/** + * @brief IGMP version used in UDP mulitcasting + * @details 0 : disable Multicast Blocking\n + * 1 : enable Multicast Blocking\n + * This bit is applied only when MACRAW mode(P[3:0] = 100. It blocks to receive the packet with multicast MAC address. + */ +#define Sn_MR_MC Sn_MR_ND + +/* Sn_MR alternate values */ +/** + * @brief For Berkeley Socket API + */ +#define SOCK_STREAM Sn_MR_TCP + +/** + * @brief For Berkeley Socket API + */ +#define SOCK_DGRAM Sn_MR_UDP + + +/* Sn_CR values */ +/** + * @brief Initialize or open socket + * @details Socket n is initialized and opened according to the protocol selected in Sn_MR(P3:P0). + * The table below shows the value of @ref Sn_SR corresponding to @ref Sn_MR.\n + * + * + * + * + * + * + *
\b Sn_MR (P[3:0]) \b Sn_SR
Sn_MR_CLOSE (000
Sn_MR_TCP (001 SOCK_INIT (0x13)
Sn_MR_UDP (010 SOCK_UDP (0x22)
S0_MR_MACRAW (100 SOCK_MACRAW (0x02)
+ */ +#define Sn_CR_OPEN 0x01 + +/** + * @brief Wait connection request in TCP mode(Server mode) + * @details This is valid only in TCP mode (Sn_MR(P3:P0) = Sn_MR_TCP). + * In this mode, Socket n operates as a �TCP serverand waits for connection-request (SYN packet) from any �TCP client + * The @ref Sn_SR changes the state from SOCK_INIT to SOCKET_LISTEN. + * When a �TCP clientconnection request is successfully established, + * the @ref Sn_SR changes from SOCK_LISTEN to SOCK_ESTABLISHED and the Sn_IR(0) becomes + * But when a �TCP clientconnection request is failed, Sn_IR(3) becomes and the status of @ref Sn_SR changes to SOCK_CLOSED. + */ +#define Sn_CR_LISTEN 0x02 + +/** + * @brief Send connection request in TCP mode(Client mode) + * @details To connect, a connect-request (SYN packet) is sent to b>TCP serverconfigured by @ref Sn_DIPR & Sn_DPORT(destination address & port). + * If the connect-request is successful, the @ref Sn_SR is changed to @ref SOCK_ESTABLISHED and the Sn_IR(0) becomes \n\n + * The connect-request fails in the following three cases.\n + * 1. When a @b ARPTO occurs (@ref Sn_IR[3] = ) because destination hardware address is not acquired through the ARP-process.\n + * 2. When a @b SYN/ACK packet is not received and @b TCPTO (Sn_IR(3) = )\n + * 3. When a @b RST packet is received instead of a @b SYN/ACK packet. In these cases, @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note This is valid only in TCP mode and operates when Socket n acts as b>TCP client + */ +#define Sn_CR_CONNECT 0x04 + +/** + * @brief Send closing request in TCP mode + * @details Regardless of b>TCP serveror b>TCP client the DISCON command processes the disconnect-process (b>Active closeor b>Passive close.\n + * @par Active close + * it transmits disconnect-request(FIN packet) to the connected peer\n + * @par Passive close + * When FIN packet is received from peer, a FIN packet is replied back to the peer.\n + * @details When the disconnect-process is successful (that is, FIN/ACK packet is received successfully), @ref Sn_SR is changed to @ref SOCK_CLOSED.\n + * Otherwise, TCPTO occurs (Sn_IR(3)=)= and then @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note Valid only in TCP mode. + */ +#define Sn_CR_DISCON 0x08 + +/** + * @brief Close socket + * @details Sn_SR is changed to @ref SOCK_CLOSED. + */ +#define Sn_CR_CLOSE 0x10 + +/** + * @brief Update TX buffer pointer and send data + * @details SEND transmits all the data in the Socket n TX buffer.\n + * For more details, please refer to Socket n TX Free Size Register (@ref Sn_TX_FSR), Socket n, + * TX Write Pointer Register(@ref Sn_TX_WR), and Socket n TX Read Pointer Register(@ref Sn_TX_RD). + */ +#define Sn_CR_SEND 0x20 + +/** + * @brief Send data with MAC address, so without ARP process + * @details The basic operation is same as SEND.\n + * Normally SEND transmits data after destination hardware address is acquired by the automatic ARP-process(Address Resolution Protocol).\n + * But SEND_MAC transmits data without the automatic ARP-process.\n + * In this case, the destination hardware address is acquired from @ref Sn_DHAR configured by host, instead of APR-process. + * @note Valid only in UDP mode. + */ +#define Sn_CR_SEND_MAC 0x21 + +/** + * @brief Send keep alive message + * @details It checks the connection status by sending 1byte keep-alive packet.\n + * If the peer can not respond to the keep-alive packet during timeout time, the connection is terminated and the timeout interrupt will occur. + * @note Valid only in TCP mode. + */ +#define Sn_CR_SEND_KEEP 0x22 + +/** + * @brief Update RX buffer pointer and receive data + * @details RECV completes the processing of the received data in Socket n RX Buffer by using a RX read pointer register (@ref Sn_RX_RD).\n + * For more details, refer to Socket n RX Received Size Register (@ref Sn_RX_RSR), Socket n RX Write Pointer Register (@ref Sn_RX_WR), + * and Socket n RX Read Pointer Register (@ref Sn_RX_RD). + */ +#define Sn_CR_RECV 0x40 + +/* Sn_IR values */ +/** + * @brief SEND_OK Interrupt + * @details This is issued when SEND command is completed. + */ +#define Sn_IR_SENDOK 0x10 + +/** + * @brief TIMEOUT Interrupt + * @details This is issued when ARPTO or TCPTO occurs. + */ +#define Sn_IR_TIMEOUT 0x08 + +/** + * @brief RECV Interrupt + * @details This is issued whenever data is received from a peer. + */ +#define Sn_IR_RECV 0x04 + +/** + * @brief DISCON Interrupt + * @details This is issued when FIN or FIN/ACK packet is received from a peer. + */ +#define Sn_IR_DISCON 0x02 + +/** + * @brief CON Interrupt + * @details This is issued one time when the connection with peer is successful and then @ref Sn_SR is changed to @ref SOCK_ESTABLISHED. + */ +#define Sn_IR_CON 0x01 + +/* Sn_SR values */ +/** + * @brief Closed + * @details This indicates that Socket n is released.\N + * When DICON, CLOSE command is ordered, or when a timeout occurs, it is changed to @ref SOCK_CLOSED regardless of previous status. + */ +#define SOCK_CLOSED 0x00 + +/** + * @brief Initiate state + * @details This indicates Socket n is opened with TCP mode.\N + * It is changed to @ref SOCK_INIT when Sn_MR(P[3:0]) = 001and OPEN command is ordered.\N + * After @ref SOCK_INIT, user can use LISTEN /CONNECT command. + */ +#define SOCK_INIT 0x13 + +/** + * @brief Listen state + * @details This indicates Socket n is operating as b>TCP servermode and waiting for connection-request (SYN packet) from a peer (b>TCP client.\n + * It will change to @ref SOCK_ESTALBLISHED when the connection-request is successfully accepted.\n + * Otherwise it will change to @ref SOCK_CLOSED after TCPTO occurred (Sn_IR(TIMEOUT) = . + */ +#define SOCK_LISTEN 0x14 + +/** + * @brief Connection state + * @details This indicates Socket n sent the connect-request packet (SYN packet) to a peer.\n + * It is temporarily shown when @ref Sn_SR is changed from @ref SOCK_INIT to @ref SOCK_ESTABLISHED by CONNECT command.\n + * If connect-accept(SYN/ACK packet) is received from the peer at SOCK_SYNSENT, it changes to @ref SOCK_ESTABLISHED.\n + * Otherwise, it changes to @ref SOCK_CLOSED after TCPTO (@ref Sn_IR[TIMEOUT] = is occurred. + */ +#define SOCK_SYNSENT 0x15 + +/** + * @brief Connection state + * @details It indicates Socket n successfully received the connect-request packet (SYN packet) from a peer.\n + * If socket n sends the response (SYN/ACK packet) to the peer successfully, it changes to @ref SOCK_ESTABLISHED. \n + * If not, it changes to @ref SOCK_CLOSED after timeout occurs (@ref Sn_IR[TIMEOUT] = . + */ +#define SOCK_SYNRECV 0x16 + +/** + * @brief Success to connect + * @details This indicates the status of the connection of Socket n.\n + * It changes to @ref SOCK_ESTABLISHED when the b>TCP SERVERprocessed the SYN packet from the b>TCP CLIENTduring @ref SOCK_LISTEN, or + * when the CONNECT command is successful.\n + * During @ref SOCK_ESTABLISHED, DATA packet can be transferred using SEND or RECV command. + */ +#define SOCK_ESTABLISHED 0x17 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_FIN_WAIT 0x18 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_CLOSING 0x1A + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and passive-close.\n + * When Disconnect-process is successfully completed, or when timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_TIME_WAIT 0x1B + +/** + * @brief Closing state + * @details This indicates Socket n received the disconnect-request (FIN packet) from the connected peer.\n + * This is half-closing status, and data can be transferred.\n + * For full-closing, DISCON command is used. But For just-closing, CLOSE command is used. + */ +#define SOCK_CLOSE_WAIT 0x1C + +/** + * @brief Closing state + * @details This indicates Socket n is waiting for the response (FIN/ACK packet) to the disconnect-request (FIN packet) by passive-close.\n + * It changes to @ref SOCK_CLOSED when Socket n received the response successfully, or when timeout occurs (@ref Sn_IR[TIMEOUT] = . + */ +#define SOCK_LAST_ACK 0x1D + +/** + * @brief UDP socket + * @details This indicates Socket n is opened in UDP mode(Sn_MR(P[3:0]) = 010.\n + * It changes to SOCK_UPD when Sn_MR(P[3:0]) = 010 and OPEN command is ordered.\n + * Unlike TCP mode, data can be transfered without the connection-process. + */ +#define SOCK_UDP 0x22 + +//#define SOCK_IPRAW 0x32 /**< IP raw mode socket */ + +/** + * @brief MAC raw mode socket + * @details This indicates Socket 0 is opened in MACRAW mode (S0_MR(P[3:0]) = 100and is valid only in Socket 0.\n + * It changes to SOCK_MACRAW when S0_MR(P[3:0] = 100and OPEN command is ordered.\n + * Like UDP mode socket, MACRAW mode Socket 0 can transfer a MAC packet (Ethernet frame) without the connection-process. + */ +#define SOCK_MACRAW 0x42 + +//#define SOCK_PPPOE 0x5F + +/* IP PROTOCOL */ +#define IPPROTO_IP 0 //< Dummy for IP +#define IPPROTO_ICMP 1 //< Control message protocol +#define IPPROTO_IGMP 2 //< Internet group management protocol +#define IPPROTO_GGP 3 //< Gateway^2 (deprecated) +#define IPPROTO_TCP 6 //< TCP +#define IPPROTO_PUP 12 //< PUP +#define IPPROTO_UDP 17 //< UDP +#define IPPROTO_IDP 22 //< XNS idp +#define IPPROTO_ND 77 //< UNOFFICIAL net disk protocol +#define IPPROTO_RAW 255 //< Raw IP packet + + +/** + * @brief Enter a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n \n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt.\n + * In OS environment, You can replace it to critical section api supported by OS. + * + * \sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * \sa WIZCHIP_CRITICAL_EXIT() + */ +#define WIZCHIP_CRITICAL_ENTER() WIZCHIP.CRIS._enter() + +/** + * @brief Exit a critical section + * + * @details It is provided to protect your shared code which are executed without distribution. \n\n + * + * In non-OS environment, It can be just implemented by disabling whole interrupt. \n + * In OS environment, You can replace it to critical section api supported by OS. + * + * @sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * @sa WIZCHIP_CRITICAL_ENTER() + */ +#ifdef _exit +#undef _exit +#endif +#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit() + + + +//////////////////////// +// Basic I/O Function // +//////////////////////// + +/** + * @ingroup Basic_IO_function + * @brief It reads 1 byte value from a register. + * @param AddrSel Register address + * @return The value of register + */ +uint8_t WIZCHIP_READ (uint32_t AddrSel); + +/** + * @ingroup Basic_IO_function + * @brief It writes 1 byte value to a register. + * @param AddrSel Register address + * @param wb Write data + * @return void + */ +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb ); + +/** + * @ingroup Basic_IO_function + * @brief It reads sequence data from registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to read data + * @param len Data length + */ +void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It writes sequence data to registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to write data + * @param len Data length + */ +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len); + +///////////////////////////////// +// Common Register I/O function // +///////////////////////////////// +/** + * @ingroup Common_register_access_function + * @brief Set Mode Register + * @param (uint8_t)mr The value to be set. + * @sa getMR() + */ +#define setMR(mr) \ + WIZCHIP_WRITE(MR,mr) + + +/** + * @ingroup Common_register_access_function + * @brief Get Mode Register + * @return uint8_t. The value of Mode register. + * @sa setMR() + */ +#define getMR() \ + WIZCHIP_READ(MR) + +/** + * @ingroup Common_register_access_function + * @brief Set gateway IP address + * @param (uint8_t*)gar Pointer variable to set gateway IP address. It should be allocated 4 bytes. + * @sa getGAR() + */ +#define setGAR(gar) \ + WIZCHIP_WRITE_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Get gateway IP address + * @param (uint8_t*)gar Pointer variable to get gateway IP address. It should be allocated 4 bytes. + * @sa setGAR() + */ +#define getGAR(gar) \ + WIZCHIP_READ_BUF(GAR,gar,4) + +/** + * @ingroup Common_register_access_function + * @brief Set subnet mask address + * @param (uint8_t*)subr Pointer variable to set subnet mask address. It should be allocated 4 bytes. + * @sa getSUBR() + */ +#define setSUBR(subr) \ + WIZCHIP_WRITE_BUF(SUBR, subr,4) + + +/** + * @ingroup Common_register_access_function + * @brief Get subnet mask address + * @param (uint8_t*)subr Pointer variable to get subnet mask address. It should be allocated 4 bytes. + * @sa setSUBR() + */ +#define getSUBR(subr) \ + WIZCHIP_READ_BUF(SUBR, subr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set local MAC address + * @param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6 bytes. + * @sa getSHAR() + */ +#define setSHAR(shar) \ + WIZCHIP_WRITE_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local MAC address + * @param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6 bytes. + * @sa setSHAR() + */ +#define getSHAR(shar) \ + WIZCHIP_READ_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set local IP address + * @param (uint8_t*)sipr Pointer variable to set local IP address. It should be allocated 4 bytes. + * @sa getSIPR() + */ +#define setSIPR(sipr) \ + WIZCHIP_WRITE_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)sipr Pointer variable to get local IP address. It should be allocated 4 bytes. + * @sa setSIPR() + */ +#define getSIPR(sipr) \ + WIZCHIP_READ_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set INTLEVEL register + * @param (uint16_t)intlevel Value to set @ref INTLEVEL register. + * @sa getINTLEVEL() + */ +#define setINTLEVEL(intlevel) {\ + WIZCHIP_WRITE(INTLEVEL, (uint8_t)(intlevel >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(INTLEVEL,1), (uint8_t) intlevel); \ + } + + +/** + * @ingroup Common_register_access_function + * @brief Get INTLEVEL register + * @return uint16_t. Value of @ref INTLEVEL register. + * @sa setINTLEVEL() + */ +#define getINTLEVEL() \ + ((WIZCHIP_READ(INTLEVEL) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref IR register + * @param (uint8_t)ir Value to set @ref IR register. + * @sa getIR() + */ +#define setIR(ir) \ + WIZCHIP_WRITE(IR, (ir & 0xF0)) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IR register + * @return uint8_t. Value of @ref IR register. + * @sa setIR() + */ +#define getIR() \ + (WIZCHIP_READ(IR) & 0xF0) +/** + * @ingroup Common_register_access_function + * @brief Set @ref IMR register + * @param (uint8_t)imr Value to set @ref IMR register. + * @sa getIMR() + */ +#define setIMR(imr) \ + WIZCHIP_WRITE(IMR, imr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IMR register + * @return uint8_t. Value of @ref IMR register. + * @sa setIMR() + */ +#define getIMR() \ + WIZCHIP_READ(IMR) + + +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIR register + * @param (uint8_t)sir Value to set @ref SIR register. + * @sa getSIR() + */ +#define setSIR(sir) \ + WIZCHIP_WRITE(SIR, sir) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIR register + * @return uint8_t. Value of @ref SIR register. + * @sa setSIR() + */ +#define getSIR() \ + WIZCHIP_READ(SIR) +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIMR register + * @param (uint8_t)simr Value to set @ref SIMR register. + * @sa getSIMR() + */ +#define setSIMR(simr) \ + WIZCHIP_WRITE(SIMR, simr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIMR register + * @return uint8_t. Value of @ref SIMR register. + * @sa setSIMR() + */ +#define getSIMR() \ + WIZCHIP_READ(SIMR) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref RTR register + * @param (uint16_t)rtr Value to set @ref RTR register. + * @sa getRTR() + */ +#define setRTR(rtr) {\ + WIZCHIP_WRITE(RTR, (uint8_t)(rtr >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(RTR,1), (uint8_t) rtr); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref RTR register + * @return uint16_t. Value of @ref RTR register. + * @sa setRTR() + */ +#define getRTR() \ + ((WIZCHIP_READ(RTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(RTR,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref RCR register + * @param (uint8_t)rcr Value to set @ref RCR register. + * @sa getRCR() + */ +#define setRCR(rcr) \ + WIZCHIP_WRITE(RCR, rcr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref RCR register + * @return uint8_t. Value of @ref RCR register. + * @sa setRCR() + */ +#define getRCR() \ + WIZCHIP_READ(RCR) + +//================================================== test done =========================================================== + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PTIMER register + * @param (uint8_t)ptimer Value to set @ref PTIMER register. + * @sa getPTIMER() + */ +#define setPTIMER(ptimer) \ + WIZCHIP_WRITE(PTIMER, ptimer) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PTIMER register + * @return uint8_t. Value of @ref PTIMER register. + * @sa setPTIMER() + */ +#define getPTIMER() \ + WIZCHIP_READ(PTIMER) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMAGIC register + * @param (uint8_t)pmagic Value to set @ref PMAGIC register. + * @sa getPMAGIC() + */ +#define setPMAGIC(pmagic) \ + WIZCHIP_WRITE(PMAGIC, pmagic) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMAGIC register + * @return uint8_t. Value of @ref PMAGIC register. + * @sa setPMAGIC() + */ +#define getPMAGIC() \ + WIZCHIP_READ(PMAGIC) + +/** + * @ingroup Common_register_access_function + * @brief Set PHAR address + * @param (uint8_t*)phar Pointer variable to set PPP destination MAC register address. It should be allocated 6 bytes. + * @sa getPHAR() + */ +#define setPHAR(phar) \ + WIZCHIP_WRITE_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)phar Pointer variable to PPP destination MAC register address. It should be allocated 6 bytes. + * @sa setPHAR() + */ +#define getPHAR(phar) \ + WIZCHIP_READ_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PSID register + * @param (uint16_t)psid Value to set @ref PSID register. + * @sa getPSID() + */ +#define setPSID(psid) {\ + WIZCHIP_WRITE(PSID, (uint8_t)(psid >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PSID,1), (uint8_t) psid); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PSID register + * @return uint16_t. Value of @ref PSID register. + * @sa setPSID() + */ +//uint16_t getPSID(void); +#define getPSID() \ + ((WIZCHIP_READ(PSID) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMRU register + * @param (uint16_t)pmru Value to set @ref PMRU register. + * @sa getPMRU() + */ +#define setPMRU(pmru) { \ + WIZCHIP_WRITE(PMRU, (uint8_t)(pmru>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PMRU,1), (uint8_t) pmru); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMRU register + * @return uint16_t. Value of @ref PMRU register. + * @sa setPMRU() + */ +#define getPMRU() \ + ((WIZCHIP_READ(PMRU) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1))) + +/** + * @ingroup Common_register_access_function + * @brief Get unreachable IP address + * @param (uint8_t*)uipr Pointer variable to get unreachable IP address. It should be allocated 4 bytes. + */ +#define getUIPR(uipr) \ + WIZCHIP_READ_BUF(UIPR,uipr,6) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref UPORTR register + * @return uint16_t. Value of @ref UPORTR register. + */ +#define getUPORTR() \ + ((WIZCHIP_READ(UPORTR) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHYCFGR register + * @param (uint8_t)phycfgr Value to set @ref PHYCFGR register. + * @sa getPHYCFGR() + */ +#define setPHYCFGR(phycfgr) \ + WIZCHIP_WRITE(PHYCFGR, phycfgr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHYCFGR register + * @return uint8_t. Value of @ref PHYCFGR register. + * @sa setPHYCFGR() + */ +#define getPHYCFGR() \ + WIZCHIP_READ(PHYCFGR) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref VERSIONR register + * @return uint8_t. Value of @ref VERSIONR register. + */ +#define getVERSIONR() \ + WIZCHIP_READ(VERSIONR) + +///////////////////////////////////// + +/////////////////////////////////// +// Socket N register I/O function // +/////////////////////////////////// +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)mr Value to set @ref Sn_MR + * @sa getSn_MR() + */ +#define setSn_MR(sn, mr) \ + WIZCHIP_WRITE(Sn_MR(sn),mr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_MR. + * @sa setSn_MR() + */ +#define getSn_MR(sn) \ + WIZCHIP_READ(Sn_MR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)cr Value to set @ref Sn_CR + * @sa getSn_CR() + */ +#define setSn_CR(sn, cr) \ + WIZCHIP_WRITE(Sn_CR(sn), cr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_CR. + * @sa setSn_CR() + */ +#define getSn_CR(sn) \ + WIZCHIP_READ(Sn_CR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ir Value to set @ref Sn_IR + * @sa getSn_IR() + */ +#define setSn_IR(sn, ir) \ + WIZCHIP_WRITE(Sn_IR(sn), (ir & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IR. + * @sa setSn_IR() + */ +#define getSn_IR(sn) \ + (WIZCHIP_READ(Sn_IR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)imr Value to set @ref Sn_IMR + * @sa getSn_IMR() + */ +#define setSn_IMR(sn, imr) \ + WIZCHIP_WRITE(Sn_IMR(sn), (imr & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IMR. + * @sa setSn_IMR() + */ +#define getSn_IMR(sn) \ + (WIZCHIP_READ(Sn_IMR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_SR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_SR. + */ +#define getSn_SR(sn) \ + WIZCHIP_READ(Sn_SR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)port Value to set @ref Sn_PORT. + * @sa getSn_PORT() + */ +#define setSn_PORT(sn, port) { \ + WIZCHIP_WRITE(Sn_PORT(sn), (uint8_t)(port >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1), (uint8_t) port); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_PORT. + * @sa setSn_PORT() + */ +#define getSn_PORT(sn) \ + ((WIZCHIP_READ(Sn_PORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DHAR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to set socket n destination hardware address. It should be allocated 6 bytes. + * @sa getSn_DHAR() + */ +#define setSn_DHAR(sn, dhar) \ + WIZCHIP_WRITE_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to get socket n destination hardware address. It should be allocated 6 bytes. + * @sa setSn_DHAR() + */ +#define getSn_DHAR(sn, dhar) \ + WIZCHIP_READ_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to set socket n destination IP address. It should be allocated 4 bytes. + * @sa getSn_DIPR() + */ +#define setSn_DIPR(sn, dipr) \ + WIZCHIP_WRITE_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to get socket n destination IP address. It should be allocated 4 bytes. + * @sa SetSn_DIPR() + */ +#define getSn_DIPR(sn, dipr) \ + WIZCHIP_READ_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)dport Value to set @ref Sn_DPORT + * @sa getSn_DPORT() + */ +#define setSn_DPORT(sn, dport) { \ + WIZCHIP_WRITE(Sn_DPORT(sn), (uint8_t) (dport>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1), (uint8_t) dport); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_DPORT. + * @sa setSn_DPORT() + */ +#define getSn_DPORT(sn) \ + ((WIZCHIP_READ(Sn_DPORT(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)mss Value to set @ref Sn_MSSR + * @sa setSn_MSSR() + */ +#define setSn_MSSR(sn, mss) { \ + WIZCHIP_WRITE(Sn_MSSR(sn), (uint8_t)(mss>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1), (uint8_t) mss); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_MSSR. + * @sa setSn_MSSR() + */ +#define getSn_MSSR(sn) \ + ((WIZCHIP_READ(Sn_MSSR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)tos Value to set @ref Sn_TOS + * @sa getSn_TOS() + */ +#define setSn_TOS(sn, tos) \ + WIZCHIP_WRITE(Sn_TOS(sn), tos) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of Sn_TOS. + * @sa setSn_TOS() + */ +#define getSn_TOS(sn) \ + WIZCHIP_READ(Sn_TOS(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ttl Value to set @ref Sn_TTL + * @sa getSn_TTL() + */ +#define setSn_TTL(sn, ttl) \ + WIZCHIP_WRITE(Sn_TTL(sn), ttl) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TTL. + * @sa setSn_TTL() + */ +#define getSn_TTL(sn) \ + WIZCHIP_READ(Sn_TTL(sn)) + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE + * @sa getSn_RXBUF_SIZE() + */ +#define setSn_RXBUF_SIZE(sn, rxbufsize) \ + WIZCHIP_WRITE(Sn_RXBUF_SIZE(sn),rxbufsize) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_RXBUF_SIZE. + * @sa setSn_RXBUF_SIZE() + */ +#define getSn_RXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_RXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE + * @sa getSn_TXBUF_SIZE() + */ +#define setSn_TXBUF_SIZE(sn, txbufsize) \ + WIZCHIP_WRITE(Sn_TXBUF_SIZE(sn), txbufsize) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TXBUF_SIZE. + * @sa setSn_TXBUF_SIZE() + */ +#define getSn_TXBUF_SIZE(sn) \ + WIZCHIP_READ(Sn_TXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_FSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_FSR. + */ +uint16_t getSn_TX_FSR(uint8_t sn); + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_RD. + */ +#define getSn_TX_RD(sn) \ + ((WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)txwr Value to set @ref Sn_TX_WR + * @sa GetSn_TX_WR() + */ +#define setSn_TX_WR(sn, txwr) { \ + WIZCHIP_WRITE(Sn_TX_WR(sn), (uint8_t)(txwr>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1), (uint8_t) txwr); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_WR. + * @sa setSn_TX_WR() + */ +#define getSn_TX_WR(sn) \ + ((WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1))) + + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RSR. + */ +uint16_t getSn_RX_RSR(uint8_t sn); + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)rxrd Value to set @ref Sn_RX_RD + * @sa getSn_RX_RD() + */ +#define setSn_RX_RD(sn, rxrd) { \ + WIZCHIP_WRITE(Sn_RX_RD(sn), (uint8_t)(rxrd>>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1), (uint8_t) rxrd); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @regurn uint16_t. Value of @ref Sn_RX_RD. + * @sa setSn_RX_RD() + */ +#define getSn_RX_RD(sn) \ + ((WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_WR. + */ +#define getSn_RX_WR(sn) \ + ((WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn),1))) + + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)frag Value to set @ref Sn_FRAG + * @sa getSn_FRAD() + */ +#define setSn_FRAG(sn, frag) { \ + WIZCHIP_WRITE(Sn_FRAG(sn), (uint8_t)(frag >>8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1), (uint8_t) frag); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_FRAG. + * @sa setSn_FRAG() + */ +#define getSn_FRAG(sn) \ + ((WIZCHIP_READ(Sn_FRAG(sn)) << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)kpalvt Value to set @ref Sn_KPALVTR + * @sa getSn_KPALVTR() + */ +#define setSn_KPALVTR(sn, kpalvt) \ + WIZCHIP_WRITE(Sn_KPALVTR(sn), kpalvt) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_KPALVTR. + * @sa setSn_KPALVTR() + */ +#define getSn_KPALVTR(sn) \ + WIZCHIP_READ(Sn_KPALVTR(sn)) + +////////////////////////////////////// + +///////////////////////////////////// +// Sn_TXBUF & Sn_RXBUF IO function // +///////////////////////////////////// +/** + * @brief Gets the max buffer size of socket sn passed as parameter. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n RX max buffer size. + */ +#define getSn_RxMAX(sn) \ + (getSn_RXBUF_SIZE(sn) << 10) + +/** + * @brief Gets the max buffer size of socket sn passed as parameters. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n TX max buffer size. + */ +//uint16_t getSn_TxMAX(uint8_t sn); +#define getSn_TxMAX(sn) \ + (getSn_TXBUF_SIZE(sn) << 10) + +/** + * @ingroup Basic_IO_function + * @brief It copies data to internal TX memory + * + * @details This function reads the Tx write pointer register and after that, + * it copies the wizdata(pointer buffer) of the length of len(variable) bytes to internal TX memory + * and updates the Tx write pointer register. + * This function is being called by send() and sendto() function also. + * + * @note User should read upper byte first and lower byte later to get proper value. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to write data + * @param len Data length + * @sa wiz_recv_data() + */ +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It copies data to your buffer from internal RX memory + * + * @details This function read the Rx read pointer register and after that, + * it copies the received data from internal RX memory + * to wizdata(pointer variable) of the length of len(variable) bytes. + * This function is being called by recv() also. + * + * @note User should read upper byte first and lower byte later to get proper value. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to read data + * @param len Data length + * @sa wiz_send_data() + */ +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It discard the received data in RX memory. + * @details It discards the data of the length of len(variable) bytes in internal RX memory. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param len Data length + */ +void wiz_recv_ignore(uint8_t sn, uint16_t len); + +#endif // _W5500_H_ diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.c b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.c new file mode 100755 index 0000000..3e54d2c --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.c @@ -0,0 +1,662 @@ +//****************************************************************************/ +//! +//! \file wizchip_conf.c +//! \brief WIZCHIP Config Header File. +//! \version 1.0.1 +//! \date 2013/10/21 +//! \par Revision history +//! <2014/05/01> V1.0.1 Refer to M20140501 +//! 1. Explicit type casting in wizchip_bus_readbyte() & wizchip_bus_writebyte() +// Issued by Mathias ClauBen. +//! uint32_t type converts into ptrdiff_t first. And then recoverting it into uint8_t* +//! For remove the warning when pointer type size is not 32bit. +//! If ptrdiff_t doesn't support in your complier, You should must replace ptrdiff_t into your suitable pointer type. +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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. +// +//*****************************************************************************/ +//A20140501 : for use the type - ptrdiff_t +#include +// + +#include "wizchip_conf.h" +#include "socket.h" + +/** + * @brief Default function to enable interrupt. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_cris_enter(void) {}; +/** + * @brief Default function to disable interrupt. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_cris_exit(void) {}; +/** + * @brief Default function to select chip. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_cs_select(void) {}; +/** + * @brief Default function to deselect chip. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_cs_deselect(void) {}; +/** + * @brief Default function to read in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ + //M20140501 : Explict pointer type casting +//uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *) AddrSel); }; +uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *)((ptrdiff_t) AddrSel)); }; +/** + * @brief Default function to write in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ + +//M20140501 : Explict pointer type casting +//void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile uint8_t*) AddrSel) = wb; }; +void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile uint8_t*)((ptrdiff_t)AddrSel)) = wb; }; + +/** + * @brief Default function to read in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_spi_readbytes(uint8_t *buf, uint32_t len) {} +/** + * @brief Default function to write in SPI interface. + * @note This function help not to access wrong address. If you do not describe this function or register any functions, + * null function is called. + */ +void wizchip_spi_writebytes(const uint8_t *buf, uint32_t len) {} + +/** + * @\ref _WIZCHIP instance + */ +_WIZCHIP WIZCHIP = + { + .id = _WIZCHIP_ID_, + .if_mode = _WIZCHIP_IO_MODE_, + .CRIS._enter = wizchip_cris_enter, + .CRIS._exit = wizchip_cris_exit, + .CS._select = wizchip_cs_select, + .CS._deselect = wizchip_cs_deselect, + .IF.BUS._read_byte = wizchip_bus_readbyte, + .IF.BUS._write_byte = wizchip_bus_writebyte +// .IF.SPI._read_byte = wizchip_spi_readbyte, +// .IF.SPI._write_byte = wizchip_spi_writebyte + }; + +#if _WIZCHIP_ == 5200 // for W5200 ARP errata +static uint8_t _SUBN_[4]; // subnet +#endif +static uint8_t _DNS_[4]; // DNS server ip address +static dhcp_mode _DHCP_; // DHCP mode + +void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void)) +{ + if(!cris_en || !cris_ex) + { + WIZCHIP.CRIS._enter = wizchip_cris_enter; + WIZCHIP.CRIS._exit = wizchip_cris_exit; + } + else + { + WIZCHIP.CRIS._enter = cris_en; + WIZCHIP.CRIS._exit = cris_ex; + } +} + +void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void)) +{ + if(!cs_sel || !cs_desel) + { + WIZCHIP.CS._select = wizchip_cs_select; + WIZCHIP.CS._deselect = wizchip_cs_deselect; + } + else + { + WIZCHIP.CS._select = cs_sel; + WIZCHIP.CS._deselect = cs_desel; + } +} + +void reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb)) +{ + while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_BUS_)); + + if(!bus_rb || !bus_wb) + { + WIZCHIP.IF.BUS._read_byte = wizchip_bus_readbyte; + WIZCHIP.IF.BUS._write_byte = wizchip_bus_writebyte; + } + else + { + WIZCHIP.IF.BUS._read_byte = bus_rb; + WIZCHIP.IF.BUS._write_byte = bus_wb; + } +} + +void reg_wizchip_spi_cbfunc(void (*spi_rb)(uint8_t *, uint32_t), void (*spi_wb)(const uint8_t *, uint32_t)) +{ + while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_)); + + if(!spi_rb || !spi_wb) + { + WIZCHIP.IF.SPI._read_bytes = wizchip_spi_readbytes; + WIZCHIP.IF.SPI._write_bytes = wizchip_spi_writebytes; + } + else + { + WIZCHIP.IF.SPI._read_bytes = spi_rb; + WIZCHIP.IF.SPI._write_bytes = spi_wb; + } +} + +int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg) +{ + uint8_t tmp = 0; + uint8_t* ptmp[2] = {0,0}; + switch(cwtype) + { + case CW_RESET_WIZCHIP: + wizchip_sw_reset(); + break; + case CW_INIT_WIZCHIP: + if(arg != 0) + { + ptmp[0] = (uint8_t*)arg; + ptmp[1] = ptmp[0] + _WIZCHIP_SOCK_NUM_; + } + return wizchip_init(ptmp[0], ptmp[1]); + case CW_CLR_INTERRUPT: + wizchip_clrinterrupt(*((intr_kind*)arg)); + break; + case CW_GET_INTERRUPT: + *((intr_kind*)arg) = wizchip_getinterrupt(); + break; + case CW_SET_INTRMASK: + wizchip_setinterruptmask(*((intr_kind*)arg)); + break; + case CW_GET_INTRMASK: + *((intr_kind*)arg) = wizchip_getinterruptmask(); + break; + #if _WIZCHIP_ > 5100 + case CW_SET_INTRTIME: + setINTLEVEL(*(uint16_t*)arg); + break; + case CW_GET_INTRTIME: + *(uint16_t*)arg = getINTLEVEL(); + break; + #endif + case CW_GET_ID: + ((uint8_t*)arg)[0] = WIZCHIP.id[0]; + ((uint8_t*)arg)[1] = WIZCHIP.id[1]; + ((uint8_t*)arg)[2] = WIZCHIP.id[2]; + ((uint8_t*)arg)[3] = WIZCHIP.id[3]; + ((uint8_t*)arg)[4] = WIZCHIP.id[4]; + ((uint8_t*)arg)[5] = 0; + break; + #if _WIZCHIP_ == 5500 + case CW_RESET_PHY: + wizphy_reset(); + break; + case CW_SET_PHYCONF: + wizphy_setphyconf((wiz_PhyConf*)arg); + break; + case CW_GET_PHYCONF: + wizphy_getphyconf((wiz_PhyConf*)arg); + break; + case CW_GET_PHYSTATUS: + break; + case CW_SET_PHYPOWMODE: + return wizphy_setphypmode(*(uint8_t*)arg); + #endif + case CW_GET_PHYPOWMODE: + tmp = wizphy_getphypmode(); + if((int8_t)tmp == -1) return -1; + *(uint8_t*)arg = tmp; + break; + case CW_GET_PHYLINK: + tmp = wizphy_getphylink(); + if((int8_t)tmp == -1) return -1; + *(uint8_t*)arg = tmp; + break; + default: + return -1; + } + return 0; +} + + +int8_t ctlnetwork(ctlnetwork_type cntype, void* arg) +{ + + switch(cntype) + { + case CN_SET_NETINFO: + wizchip_setnetinfo((wiz_NetInfo*)arg); + break; + case CN_GET_NETINFO: + wizchip_getnetinfo((wiz_NetInfo*)arg); + break; + case CN_SET_NETMODE: + return wizchip_setnetmode(*(netmode_type*)arg); + case CN_GET_NETMODE: + *(netmode_type*)arg = wizchip_getnetmode(); + break; + case CN_SET_TIMEOUT: + wizchip_settimeout((wiz_NetTimeout*)arg); + break; + case CN_GET_TIMEOUT: + wizchip_gettimeout((wiz_NetTimeout*)arg); + break; + default: + return -1; + } + return 0; +} + +void wizchip_sw_reset(void) +{ + uint8_t gw[4], sn[4], sip[4]; + uint8_t mac[6]; + getSHAR(mac); + getGAR(gw); getSUBR(sn); getSIPR(sip); + setMR(MR_RST); + getMR(); // for delay + setSHAR(mac); + setGAR(gw); + setSUBR(sn); + setSIPR(sip); +} + +int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize) +{ + int8_t i; + int8_t tmp = 0; + wizchip_sw_reset(); + if(txsize) + { + tmp = 0; + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + tmp += txsize[i]; + if(tmp > 16) return -1; + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + setSn_TXBUF_SIZE(i, txsize[i]); + } + if(rxsize) + { + tmp = 0; + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + tmp += rxsize[i]; + if(tmp > 16) return -1; + for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++) + setSn_RXBUF_SIZE(i, rxsize[i]); + } + + WIZCHIP_EXPORT(socket_reset)(); + + return 0; +} + +void wizchip_clrinterrupt(intr_kind intr) +{ + uint8_t ir = (uint8_t)intr; + uint8_t sir = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < 5500 + ir |= (1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == 5200 + ir |= (1 << 6); +#endif + +#if _WIZCHIP_ < 5200 + sir &= 0x0F; +#endif + +#if _WIZCHIP_ == 5100 + ir |= sir; + setIR(ir); +#else + setIR(ir); + setSIR(sir); +#endif +} + +intr_kind wizchip_getinterrupt(void) +{ + uint8_t ir = 0; + uint8_t sir = 0; + uint16_t ret = 0; +#if _WIZCHIP_ == 5100 + ir = getIR(); + sir = ir 0x0F; +#else + ir = getIR(); + sir = getSIR(); +#endif + +#if _WIZCHIP_ < 5500 + ir &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == 5200 + ir &= ~(1 << 6); +#endif + ret = sir; + ret = (ret << 8) + ir; + return (intr_kind)ret; +} + +void wizchip_setinterruptmask(intr_kind intr) +{ + uint8_t imr = (uint8_t)intr; + uint8_t simr = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < 5500 + imr &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == 5200 + imr &= ~(1 << 6); +#endif + +#if _WIZCHIP_ < 5200 + simr &= 0x0F; +#endif + +#if _WIZCHIP_ == 5100 + imr |= simr; + setIMR(imr); +#else + setIMR(imr); + setSIMR(simr); +#endif +} + +intr_kind wizchip_getinterruptmask(void) +{ + uint8_t imr = 0; + uint8_t simr = 0; + uint16_t ret = 0; +#if _WIZCHIP_ == 5100 + imr = getIMR(); + simr = imr 0x0F; +#else + imr = getIMR(); + simr = getSIMR(); +#endif + +#if _WIZCHIP_ < 5500 + imr &= ~(1<<4); // IK_WOL +#endif +#if _WIZCHIP_ == 5200 + imr &= ~(1 << 6); // IK_DEST_UNREACH +#endif + ret = simr; + ret = (ret << 8) + imr; + return (intr_kind)ret; +} + +int8_t wizphy_getphylink(void) +{ + int8_t tmp; +#if _WIZCHIP_ == 5200 + if(getPHYSTATUS() & PHYSTATUS_LINK) + tmp = PHY_LINK_ON; + else + tmp = PHY_LINK_OFF; +#elif _WIZCHIP_ == 5500 + if(getPHYCFGR() & PHYCFGR_LNK_ON) + tmp = PHY_LINK_ON; + else + tmp = PHY_LINK_OFF; +#else + tmp = -1; +#endif + return tmp; +} + +#if _WIZCHIP_ > 5100 + +int8_t wizphy_getphypmode(void) +{ + int8_t tmp = 0; + #if _WIZCHIP_ == 5200 + if(getPHYSTATUS() & PHYSTATUS_POWERDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; + #elif _WIZCHIP_ == 5500 + if(getPHYCFGR() & PHYCFGR_OPMDC_PDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; + #else + tmp = -1; + #endif + return tmp; +} +#endif + +#if _WIZCHIP_ == 5500 +void wizphy_reset(void) +{ + uint8_t tmp = getPHYCFGR(); + tmp &= PHYCFGR_RST; + setPHYCFGR(tmp); + tmp = getPHYCFGR(); + tmp |= ~PHYCFGR_RST; + setPHYCFGR(tmp); +} + +void wizphy_setphyconf(wiz_PhyConf* phyconf) +{ + uint8_t tmp = 0; + if(phyconf->by == PHY_CONFBY_SW) + tmp |= PHYCFGR_OPMD; + else + tmp &= ~PHYCFGR_OPMD; + if(phyconf->mode == PHY_MODE_AUTONEGO) + tmp |= PHYCFGR_OPMDC_ALLA; + else + { + if(phyconf->duplex == PHY_DUPLEX_FULL) + { + if(phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100F; + else + tmp |= PHYCFGR_OPMDC_10F; + } + else + { + if(phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100H; + else + tmp |= PHYCFGR_OPMDC_10H; + } + } + setPHYCFGR(tmp); + wizphy_reset(); +} + +void wizphy_getphyconf(wiz_PhyConf* phyconf) +{ + uint8_t tmp = 0; + tmp = getPHYCFGR(); + phyconf->by = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW; + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_ALLA: + case PHYCFGR_OPMDC_100FA: + phyconf->mode = PHY_MODE_AUTONEGO; + break; + default: + phyconf->mode = PHY_MODE_MANUAL; + break; + } + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_100H: + phyconf->speed = PHY_SPEED_100; + break; + default: + phyconf->speed = PHY_SPEED_10; + break; + } + switch(tmp & PHYCFGR_OPMDC_ALLA) + { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_10F: + phyconf->duplex = PHY_DUPLEX_FULL; + break; + default: + phyconf->duplex = PHY_DUPLEX_HALF; + break; + } +} + +void wizphy_getphystat(wiz_PhyConf* phyconf) +{ + uint8_t tmp = getPHYCFGR(); + phyconf->duplex = (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF; + phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10; +} + +int8_t wizphy_setphypmode(uint8_t pmode) +{ + uint8_t tmp = 0; + tmp = getPHYCFGR(); + if((tmp & PHYCFGR_OPMD)== 0) return -1; + tmp &= ~PHYCFGR_OPMDC_ALLA; + if( pmode == PHY_POWER_DOWN) + tmp |= PHYCFGR_OPMDC_PDOWN; + else + tmp |= PHYCFGR_OPMDC_ALLA; + setPHYCFGR(tmp); + wizphy_reset(); + tmp = getPHYCFGR(); + if( pmode == PHY_POWER_DOWN) + { + if(tmp & PHYCFGR_OPMDC_PDOWN) return 0; + } + else + { + if(tmp & PHYCFGR_OPMDC_ALLA) return 0; + } + return -1; +} +#endif + + +void wizchip_setnetinfo(wiz_NetInfo* pnetinfo) +{ + setSHAR(pnetinfo->mac); + setGAR(pnetinfo->gw); + setSUBR(pnetinfo->sn); + setSIPR(pnetinfo->ip); +#if _WIZCHIP_ == 5200 // for W5200 ARP errata + _SUBN_[0] = pnetinfo->sn[0]; + _SUBN_[1] = pnetinfo->sn[1]; + _SUBN_[2] = pnetinfo->sn[2]; + _SUBN_[3] = pnetinfo->sn[3]; +#endif + _DNS_[0] = pnetinfo->dns[0]; + _DNS_[1] = pnetinfo->dns[1]; + _DNS_[2] = pnetinfo->dns[2]; + _DNS_[3] = pnetinfo->dns[3]; + _DHCP_ = pnetinfo->dhcp; +} + +void wizchip_getnetinfo(wiz_NetInfo* pnetinfo) +{ + getSHAR(pnetinfo->mac); + getGAR(pnetinfo->gw); + getSUBR(pnetinfo->sn); + getSIPR(pnetinfo->ip); +#if _WIZCHIP_ == 5200 // for W5200 ARP errata + pnetinfo->sn[0] = _SUBN_[0]; + pnetinfo->sn[1] = _SUBN_[1]; + pnetinfo->sn[2] = _SUBN_[2]; + pnetinfo->sn[3] = _SUBN_[3]; +#endif + pnetinfo->dns[0]= _DNS_[0]; + pnetinfo->dns[1]= _DNS_[1]; + pnetinfo->dns[2]= _DNS_[2]; + pnetinfo->dns[3]= _DNS_[3]; + pnetinfo->dhcp = _DHCP_; +} + +#if _WIZCHIP_ == 5200 // for W5200 ARP errata +uint8_t *wizchip_getsubn(void) { + return _SUBN_; +} +#endif + +int8_t wizchip_setnetmode(netmode_type netmode) +{ + uint8_t tmp = 0; +#if _WIZCHIP_ != 5500 + if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK)) return -1; +#else + if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK | NM_FORCEARP)) return -1; +#endif + tmp = getMR(); + tmp |= (uint8_t)netmode; + setMR(tmp); + return 0; +} + +netmode_type wizchip_getnetmode(void) +{ + return (netmode_type) getMR(); +} + +void wizchip_settimeout(wiz_NetTimeout* nettime) +{ + setRCR(nettime->retry_cnt); + setRTR(nettime->time_100us); +} + +void wizchip_gettimeout(wiz_NetTimeout* nettime) +{ + nettime->retry_cnt = getRCR(); + nettime->time_100us = getRTR(); +} diff --git a/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.h b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.h new file mode 100755 index 0000000..4a7a7bd --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/ethernet/wizchip_conf.h @@ -0,0 +1,554 @@ +//***************************************************************************** +// +//! \file wizchip_conf.h +//! \brief WIZCHIP Config Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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. +// +//***************************************************************************** + +/** + * @defgroup extra_functions 2. WIZnet Extra Functions + * + * @brief These functions is optional function. It could be replaced at WIZCHIP I/O function because they were made by WIZCHIP I/O functions. + * @details There are functions of configuring WIZCHIP, network, interrupt, phy, network information and timer. \n + * + */ + +#ifndef _WIZCHIP_CONF_H_ +#define _WIZCHIP_CONF_H_ + +#include +/** + * @brief Select WIZCHIP. + * @todo You should select one, \b 5100, \b 5200 ,\b 5500 or etc. \n\n + * ex> #define \_WIZCHIP_ 5500 + */ +#ifndef _WIZCHIP_ +#define _WIZCHIP_ 5200 // 5100, 5200, 5500 +#endif + +#define _WIZCHIP_IO_MODE_NONE_ 0x0000 +#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */ +#define _WIZCHIP_IO_MODE_SPI_ 0x0200 /**< SPI interface mode */ +//#define _WIZCHIP_IO_MODE_IIC_ 0x0400 +//#define _WIZCHIP_IO_MODE_SDIO_ 0x0800 +// Add to +// + +#define _WIZCHIP_IO_MODE_BUS_DIR_ (_WIZCHIP_IO_MODE_BUS_ + 1) /**< BUS interface mode for direct */ +#define _WIZCHIP_IO_MODE_BUS_INDIR_ (_WIZCHIP_IO_MODE_BUS_ + 2) /**< BUS interface mode for indirect */ + +#define _WIZCHIP_IO_MODE_SPI_VDM_ (_WIZCHIP_IO_MODE_SPI_ + 1) /**< SPI interface mode for variable length data*/ +#define _WIZCHIP_IO_MODE_SPI_FDM_ (_WIZCHIP_IO_MODE_SPI_ + 2) /**< SPI interface mode for fixed length data mode*/ + + +#if (_WIZCHIP_ == 5100) + #define _WIZCHIP_ID_ "W5100\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ + +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + +#elif (_WIZCHIP_ == 5200) + #define _WIZCHIP_ID_ "W5200\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + #include "w5200/w5200.h" +#elif (_WIZCHIP_ == 5500) + #define _WIZCHIP_ID_ "W5500\0" + +/** + * @brief Define interface mode. \n + * @todo Should select interface mode as chip. + * - @ref \_WIZCHIP_IO_MODE_SPI_ \n + * -@ref \_WIZCHIP_IO_MODE_SPI_VDM_ : Valid only in @ref \_WIZCHIP_ == 5500 \n + * -@ref \_WIZCHIP_IO_MODE_SPI_FDM_ : Valid only in @ref \_WIZCHIP_ == 5500 \n + * - @ref \_WIZCHIP_IO_MODE_BUS_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_DIR_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ \n + * - Others will be defined in future. \n\n + * ex> #define \_WIZCHIP_IO_MODE_ \_WIZCHIP_IO_MODE_SPI_VDM_ + * + */ + //#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_FDM_ + #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_ + #include "w5500/w5500.h" +#else + #error "Unknown defined _WIZCHIP_. You should define one of 5100, 5200, and 5500 !!!" +#endif + +#ifndef _WIZCHIP_IO_MODE_ + #error "Undefined _WIZCHIP_IO_MODE_. You should define it !!!" +#endif + +/** + * @brief Define I/O base address when BUS IF mode. + * @todo Should re-define it to fit your system when BUS IF Mode (@ref \_WIZCHIP_IO_MODE_BUS_, + * @ref \_WIZCHIP_IO_MODE_BUS_DIR_, @ref \_WIZCHIP_IO_MODE_BUS_INDIR_). \n\n + * ex> #define \_WIZCHIP_IO_BASE_ 0x00008000 + */ +#define _WIZCHIP_IO_BASE_ 0x00000000 // + +#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS + #ifndef _WIZCHIP_IO_BASE_ + #error "You should be define _WIZCHIP_IO_BASE to fit your system memory map." + #endif +#endif + +#if _WIZCHIP_ > 5100 + #define _WIZCHIP_SOCK_NUM_ 8 ///< The count of independant socket of @b WIZCHIP +#else + #define _WIZCHIP_SOCK_NUM_ 4 ///< The count of independant socket of @b WIZCHIP +#endif + + +/******************************************************** +* WIZCHIP BASIC IF functions for SPI, SDIO, I2C , ETC. +*********************************************************/ +/** + * @ingroup DATA_TYPE + * @brief The set of callback functions for W5500:@ref WIZCHIP_IO_Functions W5200:@ref WIZCHIP_IO_Functions_W5200 + */ +typedef struct __WIZCHIP +{ + uint16_t if_mode; ///< host interface mode + uint8_t id[6]; ///< @b WIZCHIP ID such as @b 5100, @b 5200, @b 5500, and so on. + /** + * The set of critical section callback func. + */ + struct _CRIS + { + void (*_enter) (void); ///< crtical section enter + void (*_exit) (void); ///< critial section exit + }CRIS; + /** + * The set of @ref\_WIZCHIP_ select control callback func. + */ + struct _CS + { + void (*_select) (void); ///< @ref \_WIZCHIP_ selected + void (*_deselect)(void); ///< @ref \_WIZCHIP_ deselected + }CS; + /** + * The set of interface IO callback func. + */ + union _IF + { + /** + * For BUS interface IO + */ + struct + { + uint8_t (*_read_byte) (uint32_t AddrSel); + void (*_write_byte) (uint32_t AddrSel, uint8_t wb); + }BUS; + /** + * For SPI interface IO + */ + struct + { + void (*_read_bytes) (uint8_t *buf, uint32_t len); + void (*_write_bytes) (const uint8_t *buf, uint32_t len); + }SPI; + // To be added + // + }IF; +}_WIZCHIP; + +extern _WIZCHIP WIZCHIP; + +/** + * @ingroup DATA_TYPE + * WIZCHIP control type enumration used in @ref ctlwizchip(). + */ +typedef enum +{ + CW_RESET_WIZCHIP, ///< Resets WIZCHIP by softly + CW_INIT_WIZCHIP, ///< Inializes to WIZCHIP with SOCKET buffer size 2 or 1 dimension array typed uint8_t. + CW_GET_INTERRUPT, ///< Get Interrupt status of WIZCHIP + CW_CLR_INTERRUPT, ///< Clears interrupt + CW_SET_INTRMASK, ///< Masks interrupt + CW_GET_INTRMASK, ///< Get interrupt mask + CW_SET_INTRTIME, ///< Set interval time between the current and next interrupt. + CW_GET_INTRTIME, ///< Set interval time between the current and next interrupt. + CW_GET_ID, ///< Gets WIZCHIP name. + +#if _WIZCHIP_ == 5500 + CW_RESET_PHY, ///< Resets internal PHY. Valid Only W5000 + CW_SET_PHYCONF, ///< When PHY configured by interal register, PHY operation mode (Manual/Auto, 10/100, Half/Full). Valid Only W5000 + CW_GET_PHYCONF, ///< Get PHY operation mode in interal register. Valid Only W5000 + CW_GET_PHYSTATUS, ///< Get real PHY status on operating. Valid Only W5000 + CW_SET_PHYPOWMODE, ///< Set PHY power mode as noraml and down when PHYSTATUS.OPMD == 1. Valid Only W5000 +#endif + CW_GET_PHYPOWMODE, ///< Get PHY Power mode as down or normal + CW_GET_PHYLINK ///< Get PHY Link status +}ctlwizchip_type; + +/** + * @ingroup DATA_TYPE + * Network control type enumration used in @ref ctlnetwork(). + */ +typedef enum +{ + CN_SET_NETINFO, ///< Set Network with @ref wiz_NetInfo + CN_GET_NETINFO, ///< Get Network with @ref wiz_NetInfo + CN_SET_NETMODE, ///< Set network mode as WOL, PPPoE, Ping Block, and Force ARP mode + CN_GET_NETMODE, ///< Get network mode as WOL, PPPoE, Ping Block, and Force ARP mode + CN_SET_TIMEOUT, ///< Set network timeout as retry count and time. + CN_GET_TIMEOUT, ///< Get network timeout as retry count and time. +}ctlnetwork_type; + +/** + * @ingroup DATA_TYPE + * Interrupt kind when CW_SET_INTRRUPT, CW_GET_INTERRUPT, CW_SET_INTRMASK + * and CW_GET_INTRMASK is used in @ref ctlnetwork(). + * It can be used with OR operation. + */ +typedef enum +{ +#if _WIZCHIP_ > 5200 + IK_WOL = (1 << 4), ///< Wake On Lan by receiving the magic packet. Valid in W500. +#endif + + IK_PPPOE_TERMINATED = (1 << 5), ///< PPPoE Disconnected + +#if _WIZCHIP_ != 5200 + IK_DEST_UNREACH = (1 << 6), ///< Destination IP & Port Unreable, No use in W5200 +#endif + + IK_IP_CONFLICT = (1 << 7), ///< IP conflict occurred + + IK_SOCK_0 = (1 << 8), ///< Socket 0 interrupt + IK_SOCK_1 = (1 << 9), ///< Socket 1 interrupt + IK_SOCK_2 = (1 << 10), ///< Socket 2 interrupt + IK_SOCK_3 = (1 << 11), ///< Socket 3 interrupt +#if _WIZCHIP_ > 5100 + IK_SOCK_4 = (1 << 12), ///< Socket 4 interrupt, No use in 5100 + IK_SOCK_5 = (1 << 13), ///< Socket 5 interrupt, No use in 5100 + IK_SOCK_6 = (1 << 14), ///< Socket 6 interrupt, No use in 5100 + IK_SOCK_7 = (1 << 15), ///< Socket 7 interrupt, No use in 5100 +#endif + +#if _WIZCHIP_ > 5100 + IK_SOCK_ALL = (0xFF << 8) ///< All Socket interrpt +#else + IK_SOCK_ALL = (0x0F << 8) ///< All Socket interrpt +#endif +}intr_kind; + +#define PHY_CONFBY_HW 0 ///< Configured PHY operation mode by HW pin +#define PHY_CONFBY_SW 1 ///< Configured PHY operation mode by SW register +#define PHY_MODE_MANUAL 0 ///< Configured PHY operation mode with user setting. +#define PHY_MODE_AUTONEGO 1 ///< Configured PHY operation mode with auto-negotiation +#define PHY_SPEED_10 0 ///< Link Speed 10 +#define PHY_SPEED_100 1 ///< Link Speed 100 +#define PHY_DUPLEX_HALF 0 ///< Link Half-Duplex +#define PHY_DUPLEX_FULL 1 ///< Link Full-Duplex +#define PHY_LINK_OFF 0 ///< Link Off +#define PHY_LINK_ON 1 ///< Link On +#define PHY_POWER_NORM 0 ///< PHY power normal mode +#define PHY_POWER_DOWN 1 ///< PHY power down mode + + +#if _WIZCHIP_ == 5500 +/** + * @ingroup DATA_TYPE + * It configures PHY configuration when CW_SET PHYCONF or CW_GET_PHYCONF in W5500, + * and it indicates the real PHY status configured by HW or SW in all WIZCHIP. \n + * Valid only in W5500. + */ +typedef struct wiz_PhyConf_t +{ + uint8_t by; ///< set by @ref PHY_CONFBY_HW or @ref PHY_CONFBY_SW + uint8_t mode; ///< set by @ref PHY_MODE_MANUAL or @ref PHY_MODE_AUTONEGO + uint8_t speed; ///< set by @ref PHY_SPEED_10 or @ref PHY_SPEED_100 + uint8_t duplex; ///< set by @ref PHY_DUPLEX_HALF @ref PHY_DUPLEX_FULL + //uint8_t power; ///< set by @ref PHY_POWER_NORM or @ref PHY_POWER_DOWN + //uint8_t link; ///< Valid only in CW_GET_PHYSTATUS. set by @ref PHY_LINK_ON or PHY_DUPLEX_OFF + }wiz_PhyConf; +#endif + +/** + * @ingroup DATA_TYPE + * It used in setting dhcp_mode of @ref wiz_NetInfo. + */ +typedef enum +{ + NETINFO_STATIC = 1, ///< Static IP configuration by manually. + NETINFO_DHCP ///< Dynamic IP configruation from a DHCP sever +}dhcp_mode; + +/** + * @ingroup DATA_TYPE + * Network Information for WIZCHIP + */ +typedef struct wiz_NetInfo_t +{ + uint8_t mac[6]; ///< Source Mac Address + uint8_t ip[4]; ///< Source IP Address + uint8_t sn[4]; ///< Subnet Mask + uint8_t gw[4]; ///< Gateway IP Address + uint8_t dns[4]; ///< DNS server IP Address + dhcp_mode dhcp; ///< 1 - Static, 2 - DHCP +}wiz_NetInfo; + +/** + * @ingroup DATA_TYPE + * Network mode + */ +typedef enum +{ +#if _WIZCHIP_ == 5500 + NM_FORCEARP = (1<<1), ///< Force to APP send whenever udp data is sent. Valid only in W5500 +#endif + NM_WAKEONLAN = (1<<5), ///< Wake On Lan + NM_PINGBLOCK = (1<<4), ///< Block ping-request + NM_PPPOE = (1<<3), ///< PPPoE mode +}netmode_type; + +/** + * @ingroup DATA_TYPE + * Used in CN_SET_TIMEOUT or CN_GET_TIMEOUT of @ref ctlwizchip() for timeout configruation. + */ +typedef struct wiz_NetTimeout_t +{ + uint8_t retry_cnt; ///< retry count + uint16_t time_100us; ///< time unit 100us +}wiz_NetTimeout; + +/** + *@brief Registers call back function for critical section of I/O functions such as + *\ref WIZCHIP_READ, @ref WIZCHIP_WRITE, @ref WIZCHIP_READ_BUF and @ref WIZCHIP_WRITE_BUF. + *@param cris_en : callback function for critical section enter. + *@param cris_ex : callback function for critical section exit. + *@todo Describe @ref WIZCHIP_CRITICAL_ENTER and @ref WIZCHIP_CRITICAL_EXIT marco or register your functions. + *@note If you do not describe or register, default functions(@ref wizchip_cris_enter & @ref wizchip_cris_exit) is called. + */ +void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void)); + + +/** + *@brief Registers call back function for WIZCHIP select & deselect. + *@param cs_sel : callback function for WIZCHIP select + *@param cs_desel : callback fucntion for WIZCHIP deselect + *@todo Describe @ref wizchip_cs_select and @ref wizchip_cs_deselect function or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void)); + +/** + *@brief Registers call back function for bus interface. + *@param bus_rb : callback function to read byte data using system bus + *@param bus_wb : callback function to write byte data using system bus + *@todo Describe @ref wizchip_bus_readbyte and @ref wizchip_bus_writebyte function + *or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_bus_cbfunc(uint8_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb)); + +/** + *@brief Registers call back function for SPI interface. + *@param spi_rb : callback function to read byte usig SPI + *@param spi_wb : callback function to write byte usig SPI + *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function + *or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_spi_cbfunc(void (*spi_rb)(uint8_t *, uint32_t), void (*spi_wb)(const uint8_t *, uint32_t)); + +/** + * @ingroup extra_functions + * @brief Controls to the WIZCHIP. + * @details Resets WIZCHIP & internal PHY, Configures PHY mode, Monitor PHY(Link,Speed,Half/Full/Auto), + * controls interrupt & mask and so on. + * @param cwtype : Decides to the control type + * @param arg : arg type is dependent on cwtype. + * @return 0 : Success \n + * -1 : Fail because of invalid \ref ctlwizchip_type or unsupported \ref ctlwizchip_type in WIZCHIP + */ +int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg); + +/** + * @ingroup extra_functions + * @brief Controls to network. + * @details Controls to network environment, mode, timeout and so on. + * @param cntype : Input. Decides to the control type + * @param arg : Inout. arg type is dependent on cntype. + * @return -1 : Fail because of invalid \ref ctlnetwork_type or unsupported \ref ctlnetwork_type in WIZCHIP \n + * 0 : Success + */ +int8_t ctlnetwork(ctlnetwork_type cntype, void* arg); + + +/* + * The following functions are implemented for internal use. + * but You can call these functions for code size reduction instead of ctlwizchip() and ctlnetwork(). + */ + +/** + * @ingroup extra_functions + * @brief Reset WIZCHIP by softly. + */ +void wizchip_sw_reset(void); + +/** + * @ingroup extra_functions + * @brief Initializes WIZCHIP with socket buffer size + * @param txsize Socket tx buffer sizes. If null, initialized the default size 2KB. + * @param rxsize Socket rx buffer sizes. If null, initialized the default size 2KB. + * @return 0 : succcess \n + * -1 : fail. Invalid buffer size + */ +int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize); + +/** + * @ingroup extra_functions + * @brief Clear Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_clrinterrupt(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt of WIZCHIP. + * @return @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +intr_kind wizchip_getinterrupt(void); + +/** + * @ingroup extra_functions + * @brief Mask or Unmask Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_setinterruptmask(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt mask of WIZCHIP. + * @return : The operated OR vaule of @ref intr_kind. It can type-cast to uint16_t. + */ +intr_kind wizchip_getinterruptmask(void); + +#if _WIZCHIP_ > 5100 + int8_t wizphy_getphylink(void); ///< get the link status of phy in WIZCHIP. No use in W5100 + int8_t wizphy_getphypmode(void); ///< get the power mode of PHY in WIZCHIP. No use in W5100 +#endif + +#if _WIZCHIP_ == 5500 + void wizphy_reset(void); ///< Reset phy. Vailid only in W5500 +/** + * @ingroup extra_functions + * @brief Set the phy information for WIZCHIP without power mode + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_setphyconf(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief Get phy configuration information. + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_getphyconf(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief Get phy status. + * @param phyconf : @ref wiz_PhyConf + */ + void wizphy_getphystat(wiz_PhyConf* phyconf); + /** + * @ingroup extra_functions + * @brief set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in W5200 + * @param pmode Settig value of power down mode. + */ + int8_t wizphy_setphypmode(uint8_t pmode); +#endif + +/** +* @ingroup extra_functions + * @brief Set the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_setnetinfo(wiz_NetInfo* pnetinfo); + +/** + * @ingroup extra_functions + * @brief Get the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_getnetinfo(wiz_NetInfo* pnetinfo); + +#if _WIZCHIP_ == 5200 // for W5200 ARP errata +uint8_t *wizchip_getsubn(void); +#endif + +/** + * @ingroup extra_functions + * @brief Set the network mode such WOL, PPPoE, Ping Block, and etc. + * @param pnetinfo Value of network mode. Refer to @ref netmode_type. + */ +int8_t wizchip_setnetmode(netmode_type netmode); + +/** + * @ingroup extra_functions + * @brief Get the network mode such WOL, PPPoE, Ping Block, and etc. + * @return Value of network mode. Refer to @ref netmode_type. + */ +netmode_type wizchip_getnetmode(void); + +/** + * @ingroup extra_functions + * @brief Set retry time value(@ref RTR) and retry count(@ref RCR). + * @details @ref RTR configures the retransmission timeout period and @ref RCR configures the number of time of retransmission. + * @param nettime @ref RTR value and @ref RCR value. Refer to @ref wiz_NetTimeout. + */ +void wizchip_settimeout(wiz_NetTimeout* nettime); + +/** + * @ingroup extra_functions + * @brief Get retry time value(@ref RTR) and retry count(@ref RCR). + * @details @ref RTR configures the retransmission timeout period and @ref RCR configures the number of time of retransmission. + * @param nettime @ref RTR value and @ref RCR value. Refer to @ref wiz_NetTimeout. + */ +void wizchip_gettimeout(wiz_NetTimeout* nettime); + +#endif // _WIZCHIP_CONF_H_ diff --git a/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.c b/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.c new file mode 100755 index 0000000..5747582 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.c @@ -0,0 +1,978 @@ +//***************************************************************************** +// +//! \file dhcp.c +//! \brief DHCP APIs implement file. +//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE. +//! \version 1.1.0 +//! \date 2013/11/18 +//! \par Revision history +//! <2013/11/18> 1st Release +//! <2012/12/20> V1.1.0 +//! 1. Optimize code +//! 2. Add reg_dhcp_cbfunc() +//! 3. Add DHCP_stop() +//! 4. Integrate check_DHCP_state() & DHCP_run() to DHCP_run() +//! 5. Don't care system endian +//! 6. Add comments +//! <2012/12/26> V1.1.1 +//! 1. Modify variable declaration: dhcp_tick_1s is declared volatile for code optimization +//! \author Eric Jung & MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 "Ethernet/socket.h" +//#include "Internet/DHCP/dhcp.h" +#include "../../Ethernet/socket.h" +#include "dhcp.h" + +/* If you want to display debug & processing message, Define _DHCP_DEBUG_ in dhcp.h */ + +#ifdef _DHCP_DEBUG_ + #include +#endif + +/* DHCP state machine. */ +#define STATE_DHCP_INIT 0 ///< Initialize +#define STATE_DHCP_DISCOVER 1 ///< send DISCOVER and wait OFFER +#define STATE_DHCP_REQUEST 2 ///< send REQEUST and wait ACK or NACK +#define STATE_DHCP_LEASED 3 ///< ReceiveD ACK and IP leased +#define STATE_DHCP_REREQUEST 4 ///< send REQUEST for maintaining leased IP +#define STATE_DHCP_RELEASE 5 ///< No use +#define STATE_DHCP_STOP 6 ///< Stop processing DHCP + +#define DHCP_FLAGSBROADCAST 0x8000 ///< The broadcast value of flags in @ref RIP_MSG +#define DHCP_FLAGSUNICAST 0x0000 ///< The unicast value of flags in @ref RIP_MSG + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 ///< Request Message used in op of @ref RIP_MSG +#define DHCP_BOOTREPLY 2 ///< Reply Message used i op of @ref RIP_MSG + +/* DHCP message type */ +#define DHCP_DISCOVER 1 ///< DISCOVER message in OPT of @ref RIP_MSG +#define DHCP_OFFER 2 ///< OFFER message in OPT of @ref RIP_MSG +#define DHCP_REQUEST 3 ///< REQUEST message in OPT of @ref RIP_MSG +#define DHCP_DECLINE 4 ///< DECLINE message in OPT of @ref RIP_MSG +#define DHCP_ACK 5 ///< ACK message in OPT of @ref RIP_MSG +#define DHCP_NAK 6 ///< NACK message in OPT of @ref RIP_MSG +#define DHCP_RELEASE 7 ///< RELEASE message in OPT of @ref RIP_MSG. No use +#define DHCP_INFORM 8 ///< INFORM message in OPT of @ref RIP_MSG. No use + +#define DHCP_HTYPE10MB 1 ///< Used in type of @ref RIP_MSG +#define DHCP_HTYPE100MB 2 ///< Used in type of @ref RIP_MSG + +#define DHCP_HLENETHERNET 6 ///< Used in hlen of @ref RIP_MSG +#define DHCP_HOPS 0 ///< Used in hops of @ref RIP_MSG +#define DHCP_SECS 0 ///< Used in secs of @ref RIP_MSG + +#define INFINITE_LEASETIME 0xffffffff ///< Infinite lease time + +#define OPT_SIZE 312 /// Max OPT size of @ref RIP_MSG +#define RIP_MSG_SIZE (236+OPT_SIZE) /// Max size of @ref RIP_MSG + +/* + * @brief DHCP option and value (cf. RFC1533) + */ +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + timeServer = 4, + nameServer = 5, + dns = 6, + logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11, + hostName = 12, + bootFileSize = 13, + meritDumpFile = 14, + domainName = 15, + swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49, + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + dhcpOptionOverload = 52, + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + dhcpMsg = 56, + dhcpMaxMsgSize = 57, + dhcpT1value = 58, + dhcpT2value = 59, + dhcpClassIdentifier = 60, + dhcpClientIdentifier = 61, + endOption = 255 +}; + +/* + * @brief DHCP message format + */ +typedef struct { + uint8_t op; ///< @ref DHCP_BOOTREQUEST or @ref DHCP_BOOTREPLY + uint8_t htype; ///< @ref DHCP_HTYPE10MB or @ref DHCP_HTYPE100MB + uint8_t hlen; ///< @ref DHCP_HLENETHERNET + uint8_t hops; ///< @ref DHCP_HOPS + uint32_t xid; ///< @ref DHCP_XID This increase one every DHCP transaction. + uint16_t secs; ///< @ref DHCP_SECS + uint16_t flags; ///< @ref DHCP_FLAGSBROADCAST or @ref DHCP_FLAGSUNICAST + uint8_t ciaddr[4]; ///< @ref Request IP to DHCP sever + uint8_t yiaddr[4]; ///< @ref Offered IP from DHCP server + uint8_t siaddr[4]; ///< No use + uint8_t giaddr[4]; ///< No use + uint8_t chaddr[16]; ///< DHCP client 6bytes MAC address. Others is filled to zero + uint8_t sname[64]; ///< No use + uint8_t file[128]; ///< No use + uint8_t OPT[OPT_SIZE]; ///< Option +} RIP_MSG; + + + +uint8_t DHCP_SOCKET; // Socket number for DHCP + +uint8_t DHCP_SIP[4]; // DHCP Server IP address + +// Network information from DHCP Server +uint8_t OLD_allocated_ip[4] = {0, }; // Previous IP address +uint8_t DHCP_allocated_ip[4] = {0, }; // IP address from DHCP +uint8_t DHCP_allocated_gw[4] = {0, }; // Gateway address from DHCP +uint8_t DHCP_allocated_sn[4] = {0, }; // Subnet mask from DHCP +uint8_t DHCP_allocated_dns[4] = {0, }; // DNS address from DHCP + + +int8_t dhcp_state = STATE_DHCP_INIT; // DHCP state +int8_t dhcp_retry_count = 0; + +uint32_t dhcp_lease_time = INFINITE_LEASETIME; +volatile uint32_t dhcp_tick_1s = 0; // unit 1 second +uint32_t dhcp_tick_next = DHCP_WAIT_TIME ; + +uint32_t DHCP_XID; // Any number + +RIP_MSG* pDHCPMSG; // Buffer pointer for DHCP processing + +uint8_t HOST_NAME[] = DCHP_HOST_NAME; + +uint8_t DHCP_CHADDR[6]; // DHCP Client MAC address. + +/* The default callback function */ +void default_ip_assign(void); +void default_ip_update(void); +void default_ip_conflict(void); + +/* Callback handler */ +void (*dhcp_ip_assign)(void) = default_ip_assign; /* handler to be called when the IP address from DHCP server is first assigned */ +void (*dhcp_ip_update)(void) = default_ip_update; /* handler to be called when the IP address from DHCP server is updated */ +void (*dhcp_ip_conflict)(void) = default_ip_conflict; /* handler to be called when the IP address from DHCP server is conflict */ + +void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void)); + + +/* send DISCOVER message to DHCP server */ +void send_DHCP_DISCOVER(void); + +/* send REQEUST message to DHCP server */ +void send_DHCP_REQUEST(void); + +/* send DECLINE message to DHCP server */ +void send_DHCP_DECLINE(void); + +/* IP conflict check by sending ARP-request to leased IP and wait ARP-response. */ +int8_t check_DHCP_leasedIP(void); + +/* check the timeout in DHCP process */ +uint8_t check_DHCP_timeout(void); + +/* Intialize to timeout process. */ +void reset_DHCP_timeout(void); + +/* Parse message as OFFER and ACK and NACK from DHCP server.*/ +int8_t parseDHCPCMSG(void); + +/* The default handler of ip assign first */ +void default_ip_assign(void) +{ + setSIPR(DHCP_allocated_ip); + setSUBR(DHCP_allocated_sn); + setGAR (DHCP_allocated_gw); +} + +/* The default handler of ip changed */ +void default_ip_update(void) +{ + /* WIZchip Software Reset */ + setMR(MR_RST); + getMR(); // for delay + default_ip_assign(); + setSHAR(DHCP_CHADDR); +} + +/* The default handler of ip changed */ +void default_ip_conflict(void) +{ + // WIZchip Software Reset + setMR(MR_RST); + getMR(); // for delay + setSHAR(DHCP_CHADDR); +} + +/* register the call back func. */ +void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void)) +{ + dhcp_ip_assign = default_ip_assign; + dhcp_ip_update = default_ip_update; + dhcp_ip_conflict = default_ip_conflict; + if(ip_assign) dhcp_ip_assign = ip_assign; + if(ip_update) dhcp_ip_update = ip_update; + if(ip_conflict) dhcp_ip_conflict = ip_conflict; +} + +/* make the common DHCP message */ +void makeDHCPMSG(void) +{ + uint8_t bk_mac[6]; + uint8_t* ptmp; + uint8_t i; + getSHAR(bk_mac); + pDHCPMSG->op = DHCP_BOOTREQUEST; + pDHCPMSG->htype = DHCP_HTYPE10MB; + pDHCPMSG->hlen = DHCP_HLENETHERNET; + pDHCPMSG->hops = DHCP_HOPS; + ptmp = (uint8_t*)(&pDHCPMSG->xid); + *(ptmp+0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24); + *(ptmp+1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16); + *(ptmp+2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8); + *(ptmp+3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0); + pDHCPMSG->secs = DHCP_SECS; + ptmp = (uint8_t*)(&pDHCPMSG->flags); + *(ptmp+0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8); + *(ptmp+1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0); + + pDHCPMSG->ciaddr[0] = 0; + pDHCPMSG->ciaddr[1] = 0; + pDHCPMSG->ciaddr[2] = 0; + pDHCPMSG->ciaddr[3] = 0; + + pDHCPMSG->yiaddr[0] = 0; + pDHCPMSG->yiaddr[1] = 0; + pDHCPMSG->yiaddr[2] = 0; + pDHCPMSG->yiaddr[3] = 0; + + pDHCPMSG->siaddr[0] = 0; + pDHCPMSG->siaddr[1] = 0; + pDHCPMSG->siaddr[2] = 0; + pDHCPMSG->siaddr[3] = 0; + + pDHCPMSG->giaddr[0] = 0; + pDHCPMSG->giaddr[1] = 0; + pDHCPMSG->giaddr[2] = 0; + pDHCPMSG->giaddr[3] = 0; + + pDHCPMSG->chaddr[0] = DHCP_CHADDR[0]; + pDHCPMSG->chaddr[1] = DHCP_CHADDR[1]; + pDHCPMSG->chaddr[2] = DHCP_CHADDR[2]; + pDHCPMSG->chaddr[3] = DHCP_CHADDR[3]; + pDHCPMSG->chaddr[4] = DHCP_CHADDR[4]; + pDHCPMSG->chaddr[5] = DHCP_CHADDR[5]; + + for (i = 6; i < 16; i++) pDHCPMSG->chaddr[i] = 0; + for (i = 0; i < 64; i++) pDHCPMSG->sname[i] = 0; + for (i = 0; i < 128; i++) pDHCPMSG->file[i] = 0; + + // MAGIC_COOKIE + pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24); + pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16); + pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8); + pDHCPMSG->OPT[3] = (uint8_t) (MAGIC_COOKIE & 0x000000FF) >> 0; +} + +/* SEND DHCP DISCOVER */ +void send_DHCP_DISCOVER(void) +{ + uint16_t i; + uint8_t ip[4]; + uint16_t k = 0; + + makeDHCPMSG(); + + k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG() + + // Option Request Param + pDHCPMSG->OPT[k++] = dhcpMessageType; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_DISCOVER; + + // Client identifier + pDHCPMSG->OPT[k++] = dhcpClientIdentifier; + pDHCPMSG->OPT[k++] = 0x07; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[0]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[1]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[2]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[3]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[4]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[5]; + + // host name + pDHCPMSG->OPT[k++] = hostName; + pDHCPMSG->OPT[k++] = 0; // fill zero length of hostname + for(i = 0 ; HOST_NAME[i] != 0; i++) + pDHCPMSG->OPT[k++] = HOST_NAME[i]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[3]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[4]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[5]; + pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname + + pDHCPMSG->OPT[k++] = dhcpParamRequest; + pDHCPMSG->OPT[k++] = 0x06; // length of request + pDHCPMSG->OPT[k++] = subnetMask; + pDHCPMSG->OPT[k++] = routersOnSubnet; + pDHCPMSG->OPT[k++] = dns; + pDHCPMSG->OPT[k++] = domainName; + pDHCPMSG->OPT[k++] = dhcpT1value; + pDHCPMSG->OPT[k++] = dhcpT2value; + pDHCPMSG->OPT[k++] = endOption; + + for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0; + + // send broadcasting packet + ip[0] = 255; + ip[1] = 255; + ip[2] = 255; + ip[3] = 255; + +#ifdef _DHCP_DEBUG_ + printf("> Send DHCP_DISCOVER\r\n"); +#endif + + sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT); +} + +/* SEND DHCP REQUEST */ +void send_DHCP_REQUEST(void) +{ + int i; + uint8_t ip[4]; + uint16_t k = 0; + + makeDHCPMSG(); + + if(dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST) + { + *((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8); + *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF); + pDHCPMSG->ciaddr[0] = DHCP_allocated_ip[0]; + pDHCPMSG->ciaddr[1] = DHCP_allocated_ip[1]; + pDHCPMSG->ciaddr[2] = DHCP_allocated_ip[2]; + pDHCPMSG->ciaddr[3] = DHCP_allocated_ip[3]; + ip[0] = DHCP_SIP[0]; + ip[1] = DHCP_SIP[1]; + ip[2] = DHCP_SIP[2]; + ip[3] = DHCP_SIP[3]; + } + else + { + ip[0] = 255; + ip[1] = 255; + ip[2] = 255; + ip[3] = 255; + } + + k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG() + + // Option Request Param. + pDHCPMSG->OPT[k++] = dhcpMessageType; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_REQUEST; + + pDHCPMSG->OPT[k++] = dhcpClientIdentifier; + pDHCPMSG->OPT[k++] = 0x07; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[0]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[1]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[2]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[3]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[4]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[5]; + + if(ip[3] == 255) // if(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE) + { + pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr; + pDHCPMSG->OPT[k++] = 0x04; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3]; + + pDHCPMSG->OPT[k++] = dhcpServerIdentifier; + pDHCPMSG->OPT[k++] = 0x04; + pDHCPMSG->OPT[k++] = DHCP_SIP[0]; + pDHCPMSG->OPT[k++] = DHCP_SIP[1]; + pDHCPMSG->OPT[k++] = DHCP_SIP[2]; + pDHCPMSG->OPT[k++] = DHCP_SIP[3]; + } + + // host name + pDHCPMSG->OPT[k++] = hostName; + pDHCPMSG->OPT[k++] = 0; // length of hostname + for(i = 0 ; HOST_NAME[i] != 0; i++) + pDHCPMSG->OPT[k++] = HOST_NAME[i]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[3]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[4]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[5]; + pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname + + pDHCPMSG->OPT[k++] = dhcpParamRequest; + pDHCPMSG->OPT[k++] = 0x08; + pDHCPMSG->OPT[k++] = subnetMask; + pDHCPMSG->OPT[k++] = routersOnSubnet; + pDHCPMSG->OPT[k++] = dns; + pDHCPMSG->OPT[k++] = domainName; + pDHCPMSG->OPT[k++] = dhcpT1value; + pDHCPMSG->OPT[k++] = dhcpT2value; + pDHCPMSG->OPT[k++] = performRouterDiscovery; + pDHCPMSG->OPT[k++] = staticRoute; + pDHCPMSG->OPT[k++] = endOption; + + for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0; + +#ifdef _DHCP_DEBUG_ + printf("> Send DHCP_REQUEST\r\n"); +#endif + + sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT); + +} + +/* SEND DHCP DHCPDECLINE */ +void send_DHCP_DECLINE(void) +{ + int i; + uint8_t ip[4]; + uint16_t k = 0; + + makeDHCPMSG(); + + k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG() + + *((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8); + *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF); + + // Option Request Param. + pDHCPMSG->OPT[k++] = dhcpMessageType; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_DECLINE; + + pDHCPMSG->OPT[k++] = dhcpClientIdentifier; + pDHCPMSG->OPT[k++] = 0x07; + pDHCPMSG->OPT[k++] = 0x01; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[0]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[1]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[2]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[3]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[4]; + pDHCPMSG->OPT[k++] = DHCP_CHADDR[5]; + + pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr; + pDHCPMSG->OPT[k++] = 0x04; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2]; + pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3]; + + pDHCPMSG->OPT[k++] = dhcpServerIdentifier; + pDHCPMSG->OPT[k++] = 0x04; + pDHCPMSG->OPT[k++] = DHCP_SIP[0]; + pDHCPMSG->OPT[k++] = DHCP_SIP[1]; + pDHCPMSG->OPT[k++] = DHCP_SIP[2]; + pDHCPMSG->OPT[k++] = DHCP_SIP[3]; + + pDHCPMSG->OPT[k++] = endOption; + + for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0; + + //send broadcasting packet + ip[0] = 0xFF; + ip[1] = 0xFF; + ip[2] = 0xFF; + ip[3] = 0xFF; + +#ifdef _DHCP_DEBUG_ + printf("\r\n> Send DHCP_DECLINE\r\n"); +#endif + + sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT); +} + +/* PARSE REPLY pDHCPMSG */ +int8_t parseDHCPMSG(void) +{ + uint8_t svr_addr[6]; + uint16_t svr_port; + uint16_t len; + + uint8_t * p; + uint8_t * e; + uint8_t type; + uint8_t opt_len; + + if((len = getSn_RX_RSR(DHCP_SOCKET)) > 0) + { + len = recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port); + #ifdef _DHCP_DEBUG_ + printf("DHCP message : %d.%d.%d.%d(%d) %d received. \r\n",svr_addr[0],svr_addr[1],svr_addr[2], svr_addr[3],svr_port, len); + #endif + } + else return 0; + if (svr_port == DHCP_SERVER_PORT) { + // compare mac address + if ( (pDHCPMSG->chaddr[0] != DHCP_CHADDR[0]) || (pDHCPMSG->chaddr[1] != DHCP_CHADDR[1]) || + (pDHCPMSG->chaddr[2] != DHCP_CHADDR[2]) || (pDHCPMSG->chaddr[3] != DHCP_CHADDR[3]) || + (pDHCPMSG->chaddr[4] != DHCP_CHADDR[4]) || (pDHCPMSG->chaddr[5] != DHCP_CHADDR[5]) ) + return 0; + type = 0; + p = (uint8_t *)(&pDHCPMSG->op); + p = p + 240; // 240 = sizeof(RIP_MSG) + MAGIC_COOKIE size in RIP_MSG.opt - sizeof(RIP_MSG.opt) + e = p + (len - 240); + + while ( p < e ) { + + switch ( *p ) { + + case endOption : + p = e; // for break while(p < e) + break; + case padOption : + p++; + break; + case dhcpMessageType : + p++; + p++; + type = *p++; + break; + case subnetMask : + p++; + p++; + DHCP_allocated_sn[0] = *p++; + DHCP_allocated_sn[1] = *p++; + DHCP_allocated_sn[2] = *p++; + DHCP_allocated_sn[3] = *p++; + break; + case routersOnSubnet : + p++; + opt_len = *p++; + DHCP_allocated_gw[0] = *p++; + DHCP_allocated_gw[1] = *p++; + DHCP_allocated_gw[2] = *p++; + DHCP_allocated_gw[3] = *p++; + p = p + (opt_len - 4); + break; + case dns : + p++; + opt_len = *p++; + DHCP_allocated_dns[0] = *p++; + DHCP_allocated_dns[1] = *p++; + DHCP_allocated_dns[2] = *p++; + DHCP_allocated_dns[3] = *p++; + p = p + (opt_len - 4); + break; + case dhcpIPaddrLeaseTime : + p++; + opt_len = *p++; + dhcp_lease_time = *p++; + dhcp_lease_time = (dhcp_lease_time << 8) + *p++; + dhcp_lease_time = (dhcp_lease_time << 8) + *p++; + dhcp_lease_time = (dhcp_lease_time << 8) + *p++; + #ifdef _DHCP_DEBUG_ + dhcp_lease_time = 10; + #endif + break; + case dhcpServerIdentifier : + p++; + opt_len = *p++; + DHCP_SIP[0] = *p++; + DHCP_SIP[1] = *p++; + DHCP_SIP[2] = *p++; + DHCP_SIP[3] = *p++; + break; + default : + p++; + opt_len = *p++; + p += opt_len; + break; + } // switch + } // while + } // if + return type; +} + +uint8_t DHCP_run(void) +{ + uint8_t type; + uint8_t ret; + + if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED; + + if(getSn_SR(DHCP_SOCKET) != SOCK_UDP) + socket(DHCP_SOCKET, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00); + + ret = DHCP_RUNNING; + type = parseDHCPMSG(); + + switch ( dhcp_state ) { + case STATE_DHCP_INIT : + DHCP_allocated_ip[0] = 0; + DHCP_allocated_ip[1] = 0; + DHCP_allocated_ip[2] = 0; + DHCP_allocated_ip[3] = 0; + send_DHCP_DISCOVER(); + dhcp_state = STATE_DHCP_DISCOVER; + break; + case STATE_DHCP_DISCOVER : + if (type == DHCP_OFFER){ +#ifdef _DHCP_DEBUG_ + printf("> Receive DHCP_OFFER\r\n"); +#endif + DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0]; + DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1]; + DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2]; + DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3]; + + send_DHCP_REQUEST(); + dhcp_state = STATE_DHCP_REQUEST; + } else ret = check_DHCP_timeout(); + break; + + case STATE_DHCP_REQUEST : + if (type == DHCP_ACK) { + +#ifdef _DHCP_DEBUG_ + printf("> Receive DHCP_ACK\r\n"); +#endif + if (check_DHCP_leasedIP()) { + // Network info assignment from DHCP + dhcp_ip_assign(); + reset_DHCP_timeout(); + + dhcp_state = STATE_DHCP_LEASED; + } else { + // IP address conflict occurred + reset_DHCP_timeout(); + dhcp_ip_conflict(); + dhcp_state = STATE_DHCP_INIT; + } + } else if (type == DHCP_NAK) { + +#ifdef _DHCP_DEBUG_ + printf("> Receive DHCP_NACK\r\n"); +#endif + + reset_DHCP_timeout(); + + dhcp_state = STATE_DHCP_DISCOVER; + } else ret = check_DHCP_timeout(); + break; + + case STATE_DHCP_LEASED : + ret = DHCP_IP_LEASED; + if ((dhcp_lease_time != INFINITE_LEASETIME) && ((dhcp_lease_time/2) < dhcp_tick_1s)) { + +#ifdef _DHCP_DEBUG_ + printf("> Maintains the IP address \r\n"); +#endif + + type = 0; + OLD_allocated_ip[0] = DHCP_allocated_ip[0]; + OLD_allocated_ip[1] = DHCP_allocated_ip[1]; + OLD_allocated_ip[2] = DHCP_allocated_ip[2]; + OLD_allocated_ip[3] = DHCP_allocated_ip[3]; + + DHCP_XID++; + + send_DHCP_REQUEST(); + + reset_DHCP_timeout(); + + dhcp_state = STATE_DHCP_REREQUEST; + } + break; + + case STATE_DHCP_REREQUEST : + ret = DHCP_IP_LEASED; + if (type == DHCP_ACK) { + dhcp_retry_count = 0; + if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || + OLD_allocated_ip[1] != DHCP_allocated_ip[1] || + OLD_allocated_ip[2] != DHCP_allocated_ip[2] || + OLD_allocated_ip[3] != DHCP_allocated_ip[3]) + { + ret = DHCP_IP_CHANGED; + dhcp_ip_update(); + #ifdef _DHCP_DEBUG_ + printf(">IP changed.\r\n"); + #endif + + } + #ifdef _DHCP_DEBUG_ + else printf(">IP is continued.\r\n"); + #endif + reset_DHCP_timeout(); + dhcp_state = STATE_DHCP_LEASED; + } else if (type == DHCP_NAK) { + +#ifdef _DHCP_DEBUG_ + printf("> Receive DHCP_NACK, Failed to maintain ip\r\n"); +#endif + + reset_DHCP_timeout(); + + dhcp_state = STATE_DHCP_DISCOVER; + } else ret = check_DHCP_timeout(); + break; + default : + break; + } + + return ret; +} + +void DHCP_stop(void) +{ + close(DHCP_SOCKET); + dhcp_state = STATE_DHCP_STOP; +} + +uint8_t check_DHCP_timeout(void) +{ + uint8_t ret = DHCP_RUNNING; + + if (dhcp_retry_count < MAX_DHCP_RETRY) { + if (dhcp_tick_next < dhcp_tick_1s) { + + switch ( dhcp_state ) { + case STATE_DHCP_DISCOVER : +// printf("<> state : STATE_DHCP_DISCOVER\r\n"); + send_DHCP_DISCOVER(); + break; + + case STATE_DHCP_REQUEST : +// printf("<> state : STATE_DHCP_REQUEST\r\n"); + + send_DHCP_REQUEST(); + break; + + case STATE_DHCP_REREQUEST : +// printf("<> state : STATE_DHCP_REREQUEST\r\n"); + + send_DHCP_REQUEST(); + break; + + default : + break; + } + + dhcp_tick_1s = 0; + dhcp_tick_next = dhcp_tick_1s + DHCP_WAIT_TIME; + dhcp_retry_count++; + } + } else { // timeout occurred + + switch(dhcp_state) { + case STATE_DHCP_DISCOVER: + dhcp_state = STATE_DHCP_INIT; + ret = DHCP_FAILED; + break; + case STATE_DHCP_REQUEST: + case STATE_DHCP_REREQUEST: + send_DHCP_DISCOVER(); + dhcp_state = STATE_DHCP_DISCOVER; + break; + default : + break; + } + reset_DHCP_timeout(); + } + return ret; +} + +int8_t check_DHCP_leasedIP(void) +{ + uint8_t tmp; + int32_t ret; + + //WIZchip RCR value changed for ARP Timeout count control + tmp = getRCR(); + setRCR(0x03); + + // IP conflict detection : ARP request - ARP reply + // Broadcasting ARP Request for check the IP conflict using UDP sendto() function + ret = sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000); + + // RCR value restore + setRCR(tmp); + + if(ret == SOCKERR_TIMEOUT) { + // UDP send Timeout occurred : allocated IP address is unique, DHCP Success + +#ifdef _DHCP_DEBUG_ + printf("\r\n> Check leased IP - OK\r\n"); +#endif + + return 1; + } else { + // Received ARP reply or etc : IP address conflict occur, DHCP Failed + send_DHCP_DECLINE(); + + ret = dhcp_tick_1s; + while((dhcp_tick_1s - ret) < 2) ; // wait for 1s over; wait to complete to send DECLINE message; + + return 0; + } +} + +void DHCP_init(uint8_t s, uint8_t * buf) +{ + uint8_t zeroip[4] = {0,0,0,0}; + getSHAR(DHCP_CHADDR); + if((DHCP_CHADDR[0] | DHCP_CHADDR[1] | DHCP_CHADDR[2] | DHCP_CHADDR[3] | DHCP_CHADDR[4] | DHCP_CHADDR[5]) == 0x00) + { + // assign temporary mac address, you should be set SHAR before call this function. + DHCP_CHADDR[0] = 0x00; + DHCP_CHADDR[1] = 0x08; + DHCP_CHADDR[2] = 0xdc; + DHCP_CHADDR[3] = 0x00; + DHCP_CHADDR[4] = 0x00; + DHCP_CHADDR[5] = 0x00; + setSHAR(DHCP_CHADDR); + } + + DHCP_SOCKET = s; // SOCK_DHCP + pDHCPMSG = (RIP_MSG*)buf; + DHCP_XID = 0x12345678; + + // WIZchip Netinfo Clear + setSIPR(zeroip); + setSIPR(zeroip); + setGAR(zeroip); + + reset_DHCP_timeout(); + dhcp_state = STATE_DHCP_INIT; +} + + +/* Rset the DHCP timeout count and retry count. */ +void reset_DHCP_timeout(void) +{ + dhcp_tick_1s = 0; + dhcp_tick_next = DHCP_WAIT_TIME; + dhcp_retry_count = 0; +} + +void DHCP_time_handler(void) +{ + dhcp_tick_1s++; +} + +void getIPfromDHCP(uint8_t* ip) +{ + ip[0] = DHCP_allocated_ip[0]; + ip[1] = DHCP_allocated_ip[1]; + ip[2] = DHCP_allocated_ip[2]; + ip[3] = DHCP_allocated_ip[3]; +} + +void getGWfromDHCP(uint8_t* ip) +{ + ip[0] =DHCP_allocated_gw[0]; + ip[1] =DHCP_allocated_gw[1]; + ip[2] =DHCP_allocated_gw[2]; + ip[3] =DHCP_allocated_gw[3]; +} + +void getSNfromDHCP(uint8_t* ip) +{ + ip[0] = DHCP_allocated_sn[0]; + ip[1] = DHCP_allocated_sn[1]; + ip[2] = DHCP_allocated_sn[2]; + ip[3] = DHCP_allocated_sn[3]; +} + +void getDNSfromDHCP(uint8_t* ip) +{ + ip[0] = DHCP_allocated_dns[0]; + ip[1] = DHCP_allocated_dns[1]; + ip[2] = DHCP_allocated_dns[2]; + ip[3] = DHCP_allocated_dns[3]; +} + +uint32_t getDHCPLeasetime(void) +{ + return dhcp_lease_time; +} + + + + diff --git a/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.h b/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.h new file mode 100755 index 0000000..ee154d5 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/internet/dhcp/dhcp.h @@ -0,0 +1,150 @@ +//***************************************************************************** +// +//! \file dhcp.h +//! \brief DHCP APIs Header file. +//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE. +//! \version 1.1.0 +//! \date 2013/11/18 +//! \par Revision history +//! <2013/11/18> 1st Release +//! <2012/12/20> V1.1.0 +//! 1. Move unreferenced DEFINE to dhcp.c +//! <2012/12/26> V1.1.1 +//! \author Eric Jung & MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 _DHCP_H_ +#define _DHCP_H_ + +/* + * @brief + * @details If you want to display debug & processing message, Define _DHCP_DEBUG_ + * @note If defined, it depends on + */ + +//#define _DHCP_DEBUG_ + +/* Retry to processing DHCP */ +#define MAX_DHCP_RETRY 2 ///< Maximum retry count +#define DHCP_WAIT_TIME 10 ///< Wait Time 10s + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 ///< DHCP server port number +#define DHCP_CLIENT_PORT 68 ///< DHCP client port number + +#define MAGIC_COOKIE 0x63825363 ///< Any number. You can be modified it any number + +#define DCHP_HOST_NAME "WIZnet\0" + +/* + * @brief return value of @ref DHCP_run() + */ +enum +{ + DHCP_FAILED = 0, ///< Processing Fail + DHCP_RUNNING, ///< Processing DHCP protocol + DHCP_IP_ASSIGN, ///< First Occupy IP from DHPC server (if cbfunc == null, act as default default_ip_assign) + DHCP_IP_CHANGED, ///< Change IP address by new IP address from DHCP (if cbfunc == null, act as default default_ip_update) + DHCP_IP_LEASED, ///< Stand by + DHCP_STOPPED ///< Stop processing DHCP protocol +}; + +/* + * @brief DHCP client initialization (outside of the main loop) + * @param s - socket number + * @param buf - buffer for processing DHCP message + */ +void DHCP_init(uint8_t s, uint8_t * buf); + +/* + * @brief DHCP 1s Tick Timer handler + * @note SHOULD BE register to your system 1s Tick timer handler + */ +void DHCP_time_handler(void); + +/* + * @brief Register call back function + * @param ip_assign - callback func when IP is assigned from DHCP server first + * @param ip_update - callback func when IP is changed + * @prarm ip_conflict - callback func when the assigned IP is conflict with others. + */ +void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void)); + +/* + * @brief DHCP client in the main loop + * @return The value is as the follow \n + * @ref DHCP_FAILED \n + * @ref DHCP_RUNNING \n + * @ref DHCP_IP_ASSIGN \n + * @ref DHCP_IP_CHANGED \n + * @ref DHCP_IP_LEASED \n + * @ref DHCP_STOPPED \n + * + * @note This function is always called by you main task. + */ +uint8_t DHCP_run(void); + +/* + * @brief Stop DHCP processing + * @note If you want to restart. call DHCP_init() and DHCP_run() + */ +void DHCP_stop(void); + +/* Get Network information assigned from DHCP server */ +/* + * @brief Get IP address + * @param ip - IP address to be returned + */ +void getIPfromDHCP(uint8_t* ip); +/* + * @brief Get Gateway address + * @param ip - Gateway address to be returned + */ +void getGWfromDHCP(uint8_t* ip); +/* + * @brief Get Subnet mask value + * @param ip - Subnet mask to be returned + */ +void getSNfromDHCP(uint8_t* ip); +/* + * @brief Get DNS address + * @param ip - DNS address to be returned + */ +void getDNSfromDHCP(uint8_t* ip); + +/* + * @brief Get the leased time by DHCP sever + * @return unit 1s + */ +uint32_t getDHCPLeasetime(void); + +#endif /* _DHCP_H_ */ diff --git a/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.c b/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.c new file mode 100755 index 0000000..c0ad570 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.c @@ -0,0 +1,566 @@ +//***************************************************************************** +// +//! \file dns.c +//! \brief DNS APIs Implement file. +//! \details Send DNS query & Receive DNS reponse. \n +//! It depends on stdlib.h & string.h in ansi-c library +//! \version 1.1.0 +//! \date 2013/11/18 +//! \par Revision history +//! <2013/10/21> 1st Release +//! <2013/12/20> V1.1.0 +//! 1. Remove secondary DNS server in DNS_run +//! If 1st DNS_run failed, call DNS_run with 2nd DNS again +//! 2. DNS_timerHandler -> DNS_time_handler +//! 3. Remove the unused define +//! 4. Integrated dns.h dns.c & dns_parse.h dns_parse.c into dns.h & dns.c +//! <2013/12/20> V1.1.0 +//! +//! \author Eric Jung & MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 "Ethernet/socket.h" +//#include "Internet/DNS/dns.h" +#include "../../ethernet/socket.h" +#include "dns.h" + +#ifdef _DNS_DEBUG_ + #include +#endif + +#define INITRTT 2000L /* Initial smoothed response time */ +#define MAXCNAME (MAX_DOMAIN_NAME + (MAX_DOMAIN_NAME>>1)) /* Maximum amount of cname recursion */ + +#define TYPE_A 1 /* Host address */ +#define TYPE_NS 2 /* Name server */ +#define TYPE_MD 3 /* Mail destination (obsolete) */ +#define TYPE_MF 4 /* Mail forwarder (obsolete) */ +#define TYPE_CNAME 5 /* Canonical name */ +#define TYPE_SOA 6 /* Start of Authority */ +#define TYPE_MB 7 /* Mailbox name (experimental) */ +#define TYPE_MG 8 /* Mail group member (experimental) */ +#define TYPE_MR 9 /* Mail rename name (experimental) */ +#define TYPE_NULL 10 /* Null (experimental) */ +#define TYPE_WKS 11 /* Well-known sockets */ +#define TYPE_PTR 12 /* Pointer record */ +#define TYPE_HINFO 13 /* Host information */ +#define TYPE_MINFO 14 /* Mailbox information (experimental)*/ +#define TYPE_MX 15 /* Mail exchanger */ +#define TYPE_TXT 16 /* Text strings */ +#define TYPE_ANY 255 /* Matches any type */ + +#define CLASS_IN 1 /* The ARPA Internet */ + +/* Round trip timing parameters */ +#define AGAIN 8 /* Average RTT gain = 1/8 */ +#define LAGAIN 3 /* Log2(AGAIN) */ +#define DGAIN 4 /* Mean deviation gain = 1/4 */ +#define LDGAIN 2 /* log2(DGAIN) */ + +/* Header for all domain messages */ +struct dhdr +{ + uint16_t id; /* Identification */ + uint8_t qr; /* Query/Response */ +#define QUERY 0 +#define RESPONSE 1 + uint8_t opcode; +#define IQUERY 1 + uint8_t aa; /* Authoratative answer */ + uint8_t tc; /* Truncation */ + uint8_t rd; /* Recursion desired */ + uint8_t ra; /* Recursion available */ + uint8_t rcode; /* Response code */ +#define NO_ERROR 0 +#define FORMAT_ERROR 1 +#define SERVER_FAIL 2 +#define NAME_ERROR 3 +#define NOT_IMPL 4 +#define REFUSED 5 + uint16_t qdcount; /* Question count */ + uint16_t ancount; /* Answer count */ + uint16_t nscount; /* Authority (name server) count */ + uint16_t arcount; /* Additional record count */ +}; + + +uint8_t* pDNSMSG; // DNS message buffer +uint8_t DNS_SOCKET; // SOCKET number for DNS +uint16_t DNS_MSGID; // DNS message ID + +extern uint32_t HAL_GetTick(void); +uint32_t hal_sys_tick; + +/* converts uint16_t from network buffer to a host byte order integer. */ +uint16_t get16(uint8_t * s) +{ + uint16_t i; + i = *s++ << 8; + i = i + *s; + return i; +} + +/* copies uint16_t to the network buffer with network byte order. */ +uint8_t * put16(uint8_t * s, uint16_t i) +{ + *s++ = i >> 8; + *s++ = i; + return s; +} + + +/* + * CONVERT A DOMAIN NAME TO THE HUMAN-READABLE FORM + * + * Description : This function converts a compressed domain name to the human-readable form + * Arguments : msg - is a pointer to the reply message + * compressed - is a pointer to the domain name in reply message. + * buf - is a pointer to the buffer for the human-readable form name. + * len - is the MAX. size of buffer. + * Returns : the length of compressed message + */ +int parse_name(uint8_t * msg, uint8_t * compressed, char * buf, int16_t len) +{ + uint16_t slen; /* Length of current segment */ + uint8_t * cp; + int clen = 0; /* Total length of compressed name */ + int indirect = 0; /* Set if indirection encountered */ + int nseg = 0; /* Total number of segments in name */ + + cp = compressed; + + for (;;) + { + slen = *cp++; /* Length of this segment */ + + if (!indirect) clen++; + + if ((slen & 0xc0) == 0xc0) + { + if (!indirect) + clen++; + indirect = 1; + /* Follow indirection */ + cp = &msg[((slen & 0x3f)<<8) + *cp]; + slen = *cp++; + } + + if (slen == 0) /* zero length == all done */ + break; + + len -= slen + 1; + + if (len < 0) return -1; + + if (!indirect) clen += slen; + + while (slen-- != 0) *buf++ = (char)*cp++; + *buf++ = '.'; + nseg++; + } + + if (nseg == 0) + { + /* Root name; represent as single dot */ + *buf++ = '.'; + len--; + } + + *buf++ = '\0'; + len--; + + return clen; /* Length of compressed message */ +} + +/* + * PARSE QUESTION SECTION + * + * Description : This function parses the question record of the reply message. + * Arguments : msg - is a pointer to the reply message + * cp - is a pointer to the question record. + * Returns : a pointer the to next record. + */ +uint8_t * dns_question(uint8_t * msg, uint8_t * cp) +{ + int len; + char name[MAXCNAME]; + + len = parse_name(msg, cp, name, MAXCNAME); + + + if (len == -1) return 0; + + cp += len; + cp += 2; /* type */ + cp += 2; /* class */ + + return cp; +} + + +/* + * PARSE ANSER SECTION + * + * Description : This function parses the answer record of the reply message. + * Arguments : msg - is a pointer to the reply message + * cp - is a pointer to the answer record. + * Returns : a pointer the to next record. + */ +uint8_t * dns_answer(uint8_t * msg, uint8_t * cp, uint8_t * ip_from_dns) +{ + int len, type; + char name[MAXCNAME]; + + len = parse_name(msg, cp, name, MAXCNAME); + + if (len == -1) return 0; + + cp += len; + type = get16(cp); + cp += 2; /* type */ + cp += 2; /* class */ + cp += 4; /* ttl */ + cp += 2; /* len */ + + + switch (type) + { + case TYPE_A: + /* Just read the address directly into the structure */ + ip_from_dns[0] = *cp++; + ip_from_dns[1] = *cp++; + ip_from_dns[2] = *cp++; + ip_from_dns[3] = *cp++; + break; + case TYPE_CNAME: + case TYPE_MB: + case TYPE_MG: + case TYPE_MR: + case TYPE_NS: + case TYPE_PTR: + /* These types all consist of a single domain name */ + /* convert it to ASCII format */ + len = parse_name(msg, cp, name, MAXCNAME); + if (len == -1) return 0; + + cp += len; + break; + case TYPE_HINFO: + len = *cp++; + cp += len; + + len = *cp++; + cp += len; + break; + case TYPE_MX: + cp += 2; + /* Get domain name of exchanger */ + len = parse_name(msg, cp, name, MAXCNAME); + if (len == -1) return 0; + + cp += len; + break; + case TYPE_SOA: + /* Get domain name of name server */ + len = parse_name(msg, cp, name, MAXCNAME); + if (len == -1) return 0; + + cp += len; + + /* Get domain name of responsible person */ + len = parse_name(msg, cp, name, MAXCNAME); + if (len == -1) return 0; + + cp += len; + + cp += 4; + cp += 4; + cp += 4; + cp += 4; + cp += 4; + break; + case TYPE_TXT: + /* Just stash */ + break; + default: + /* Ignore */ + break; + } + + return cp; +} + +/* + * PARSE THE DNS REPLY + * + * Description : This function parses the reply message from DNS server. + * Arguments : dhdr - is a pointer to the header for DNS message + * buf - is a pointer to the reply message. + * len - is the size of reply message. + * Returns : -1 - Domain name length is too big + * 0 - Fail (Timeout or parse error) + * 1 - Success, + */ +int8_t parseDNSMSG(struct dhdr * pdhdr, uint8_t * pbuf, uint8_t * ip_from_dns) +{ + uint16_t tmp; + uint16_t i; + uint8_t * msg; + uint8_t * cp; + + msg = pbuf; + memset(pdhdr, 0, sizeof(*pdhdr)); + + pdhdr->id = get16(&msg[0]); + tmp = get16(&msg[2]); + if (tmp & 0x8000) pdhdr->qr = 1; + + pdhdr->opcode = (tmp >> 11) & 0xf; + + if (tmp & 0x0400) pdhdr->aa = 1; + if (tmp & 0x0200) pdhdr->tc = 1; + if (tmp & 0x0100) pdhdr->rd = 1; + if (tmp & 0x0080) pdhdr->ra = 1; + + pdhdr->rcode = tmp & 0xf; + pdhdr->qdcount = get16(&msg[4]); + pdhdr->ancount = get16(&msg[6]); + pdhdr->nscount = get16(&msg[8]); + pdhdr->arcount = get16(&msg[10]); + + + /* Now parse the variable length sections */ + cp = &msg[12]; + + /* Question section */ + for (i = 0; i < pdhdr->qdcount; i++) + { + cp = dns_question(msg, cp); + if(!cp) + { +#ifdef _DNS_DEBUG_ + printf("MAX_DOMAIN_NAME is too small, it should be redefined in dns.h\r\n"); +#endif + return -1; + } + } + + /* Answer section */ + for (i = 0; i < pdhdr->ancount; i++) + { + cp = dns_answer(msg, cp, ip_from_dns); + if(!cp) + { +#ifdef _DNS_DEBUG_ + printf("MAX_DOMAIN_NAME is too small, it should be redefined in dns.h\r\n"); +#endif + return -1; + } + + } + + /* Name server (authority) section */ + for (i = 0; i < pdhdr->nscount; i++) + { + ; + } + + /* Additional section */ + for (i = 0; i < pdhdr->arcount; i++) + { + ; + } + + if(pdhdr->rcode == 0) return 1; // No error + else return 0; +} + + +/* + * MAKE DNS QUERY MESSAGE + * + * Description : This function makes DNS query message. + * Arguments : op - Recursion desired + * name - is a pointer to the domain name. + * buf - is a pointer to the buffer for DNS message. + * len - is the MAX. size of buffer. + * Returns : the pointer to the DNS message. + */ +int16_t dns_makequery(uint16_t op, char * name, uint8_t * buf, uint16_t len) +{ + uint8_t *cp; + char *cp1; + char sname[MAXCNAME]; + char *dname; + uint16_t p; + uint16_t dlen; + + cp = buf; + + DNS_MSGID++; + cp = put16(cp, DNS_MSGID); + p = (op << 11) | 0x0100; /* Recursion desired */ + cp = put16(cp, p); + cp = put16(cp, 1); + cp = put16(cp, 0); + cp = put16(cp, 0); + cp = put16(cp, 0); + + strcpy(sname, name); + dname = sname; + dlen = strlen(dname); + for (;;) + { + /* Look for next dot */ + cp1 = strchr(dname, '.'); + + if (cp1 != NULL) len = cp1 - dname; /* More to come */ + else len = dlen; /* Last component */ + + *cp++ = len; /* Write length of component */ + if (len == 0) break; + + /* Copy component up to (but not including) dot */ + memcpy(cp, dname, len); + cp += len; + if (cp1 == NULL) + { + *cp++ = 0; /* Last one; write null and finish */ + break; + } + dname += len+1; + dlen -= len+1; + } + + cp = put16(cp, 0x0001); /* type */ + cp = put16(cp, 0x0001); /* class */ + + return ((int16_t)((uint32_t)(cp) - (uint32_t)(buf))); +} + +/* + * CHECK DNS TIMEOUT + * + * Description : This function check the DNS timeout + * Arguments : None. + * Returns : -1 - timeout occurred, 0 - timer over, but no timeout, 1 - no timer over, no timeout occur + * Note : timeout : retry count and timer both over. + */ + +int8_t check_DNS_timeout(void) +{ + static uint8_t retry_count; + + uint32_t tick = HAL_GetTick(); + if(tick - hal_sys_tick >= DNS_WAIT_TIME * 1000) + { + hal_sys_tick = tick; + if(retry_count >= MAX_DNS_RETRY) { + retry_count = 0; + return -1; // timeout occurred + } + retry_count++; + return 0; // timer over, but no timeout + } + + return 1; // no timer over, no timeout occur +} + + + +/* DNS CLIENT INIT */ +void DNS_init(uint8_t s, uint8_t * buf) +{ + DNS_SOCKET = s; // SOCK_DNS + pDNSMSG = buf; // User's shared buffer + DNS_MSGID = DNS_MSG_ID; +} + +/* DNS CLIENT RUN */ +int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns) +{ + int8_t ret; + struct dhdr dhp; + uint8_t ip[4]; + uint16_t len, port; + int8_t ret_check_timeout; + + hal_sys_tick = HAL_GetTick(); + + // Socket open + WIZCHIP_EXPORT(socket)(DNS_SOCKET, Sn_MR_UDP, 0, 0); + +#ifdef _DNS_DEBUG_ + printf("> DNS Query to DNS Server : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]); +#endif + + len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE); + WIZCHIP_EXPORT(sendto)(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN); + + while (1) + { + if ((len = getSn_RX_RSR(DNS_SOCKET)) > 0) + { + if (len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE; + len = WIZCHIP_EXPORT(recvfrom)(DNS_SOCKET, pDNSMSG, len, ip, &port); + #ifdef _DNS_DEBUG_ + printf("> Receive DNS message from %d.%d.%d.%d(%d). len = %d\r\n", ip[0], ip[1], ip[2], ip[3],port,len); + #endif + ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns); + break; + } + // Check Timeout + ret_check_timeout = check_DNS_timeout(); + if (ret_check_timeout < 0) { + +#ifdef _DNS_DEBUG_ + printf("> DNS Server is not responding : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]); +#endif + return 0; // timeout occurred + } + else if (ret_check_timeout == 0) { + +#ifdef _DNS_DEBUG_ + printf("> DNS Timeout\r\n"); +#endif + WIZCHIP_EXPORT(sendto)(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN); + } + } + WIZCHIP_EXPORT(close)(DNS_SOCKET); + // Return value + // 0 > : failed / 1 - success + return ret; +} diff --git a/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.h b/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.h new file mode 100755 index 0000000..de00395 --- /dev/null +++ b/src/openmv/src/micropython/drivers/wiznet5k/internet/dns/dns.h @@ -0,0 +1,96 @@ +//***************************************************************************** +// +//! \file dns.h +//! \brief DNS APIs Header file. +//! \details Send DNS query & Receive DNS reponse. +//! \version 1.1.0 +//! \date 2013/11/18 +//! \par Revision history +//! <2013/10/21> 1st Release +//! <2013/12/20> V1.1.0 +//! 1. Remove secondary DNS server in DNS_run +//! If 1st DNS_run failed, call DNS_run with 2nd DNS again +//! 2. DNS_timerHandler -> DNS_time_handler +//! 3. Move the no reference define to dns.c +//! 4. Integrated dns.h dns.c & dns_parse.h dns_parse.c into dns.h & dns.c +//! <2013/12/20> V1.1.0 +//! +//! \author Eric Jung & MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! All rights reserved. +//! +//! Redistribution and use in source and binary forms, with or without +//! modification, are permitted provided that the following conditions +//! are met: +//! +//! * Redistributions of source code must retain the above copyright +//! notice, this list of conditions and the following disclaimer. +//! * 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. +//! * Neither the name of the 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 OWNER 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 _DNS_H_ +#define _DNS_H_ + +#include +/* + * @brief Define it for Debug & Monitor DNS processing. + * @note If defined, it depends on + */ + +//#define _DNS_DEBUG_ + +#define MAX_DNS_BUF_SIZE 256 ///< maximum size of DNS buffer. */ +/* + * @brief Maximum length of your queried Domain name + * @todo SHOULD BE defined it equal as or greater than your Domain name length + null character(1) + * @note SHOULD BE careful to stack overflow because it is allocated 1.5 times as MAX_DOMAIN_NAME in stack. + */ +#define MAX_DOMAIN_NAME 32 // for example "www.google.com" + +#define MAX_DNS_RETRY 2 ///< Requery Count +#define DNS_WAIT_TIME 4 ///< Wait response time. unit 1s. + +#define IPPORT_DOMAIN 53 ///< DNS server port number + +#define DNS_MSG_ID 0x1122 ///< ID for DNS message. You can be modified it any number +/* + * @brief DNS process initialize + * @param s : Socket number for DNS + * @param buf : Buffer for DNS message + */ +void DNS_init(uint8_t s, uint8_t * buf); + +/* + * @brief DNS process + * @details Send DNS query and receive DNS response + * @param dns_ip : DNS server ip address + * @param name : Domain name to be queried + * @param ip_from_dns : IP address from DNS server + * @return -1 : failed. @ref MAX_DOMIN_NAME is too small \n + * 0 : failed (Timeout or Parse error)\n + * 1 : success + * @note This function blocks until success or fail. max time = @ref MAX_DNS_RETRY * @ref DNS_WAIT_TIME + */ +int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns); + +#endif /* _DNS_H_ */ diff --git a/src/openmv/src/micropython/examples/SDdatalogger/README.md b/src/openmv/src/micropython/examples/SDdatalogger/README.md new file mode 100755 index 0000000..24e69c8 --- /dev/null +++ b/src/openmv/src/micropython/examples/SDdatalogger/README.md @@ -0,0 +1,4 @@ +This is a SDdatalogger, to log data from the accelerometer to the SD-card. It also functions as card reader, so you can easily get the data on your PC. + +To run, put the boot.py, cardreader.py and datalogger.py files on either the flash or the SD-card of your pyboard. +Upon reset, the datalogger script is run and logs the data. If you press the user button after reset and hold it until the orange LED goes out, you enter the cardreader mode and the filesystem is mounted to your PC. diff --git a/src/openmv/src/micropython/examples/SDdatalogger/boot.py b/src/openmv/src/micropython/examples/SDdatalogger/boot.py new file mode 100755 index 0000000..4ac94bb --- /dev/null +++ b/src/openmv/src/micropython/examples/SDdatalogger/boot.py @@ -0,0 +1,25 @@ +# boot.py -- runs on boot-up +# Let's you choose which script to run. +# > To run 'datalogger.py': +# * press reset and do nothing else +# > To run 'cardreader.py': +# * press reset +# * press user switch and hold until orange LED goes out + +import pyb + +pyb.LED(3).on() # indicate we are waiting for switch press +pyb.delay(2000) # wait for user to maybe press the switch +switch_value = pyb.Switch()() # sample the switch at end of delay +pyb.LED(3).off() # indicate that we finished waiting for the switch + +pyb.LED(4).on() # indicate that we are selecting the mode + +if switch_value: + pyb.usb_mode('VCP+MSC') + pyb.main('cardreader.py') # if switch was pressed, run this +else: + pyb.usb_mode('VCP+HID') + pyb.main('datalogger.py') # if switch wasn't pressed, run this + +pyb.LED(4).off() # indicate that we finished selecting the mode diff --git a/src/openmv/src/micropython/examples/SDdatalogger/cardreader.py b/src/openmv/src/micropython/examples/SDdatalogger/cardreader.py new file mode 100755 index 0000000..98d7a37 --- /dev/null +++ b/src/openmv/src/micropython/examples/SDdatalogger/cardreader.py @@ -0,0 +1,2 @@ +# cardread.py +# This is called when the user enters cardreader mode. It does nothing. diff --git a/src/openmv/src/micropython/examples/SDdatalogger/datalogger.py b/src/openmv/src/micropython/examples/SDdatalogger/datalogger.py new file mode 100755 index 0000000..0690c20 --- /dev/null +++ b/src/openmv/src/micropython/examples/SDdatalogger/datalogger.py @@ -0,0 +1,33 @@ +# datalogger.py +# Logs the data from the acceleromter to a file on the SD-card + +import pyb + +# creating objects +accel = pyb.Accel() +blue = pyb.LED(4) +switch = pyb.Switch() + +# loop +while True: + + # wait for interrupt + # this reduces power consumption while waiting for switch press + pyb.wfi() + + # start if switch is pressed + if switch(): + pyb.delay(200) # delay avoids detection of multiple presses + blue.on() # blue LED indicates file open + log = open('/sd/log.csv', 'w') # open file on SD (SD: '/sd/', flash: '/flash/) + + # until switch is pressed again + while not switch(): + t = pyb.millis() # get time + x, y, z = accel.filtered_xyz() # get acceleration data + log.write('{},{},{},{}\n'.format(t,x,y,z)) # write data to file + + # end after switch is pressed again + log.close() # close file + blue.off() # blue LED indicates file closed + pyb.delay(200) # delay avoids detection of multiple presses diff --git a/src/openmv/src/micropython/examples/accel_i2c.py b/src/openmv/src/micropython/examples/accel_i2c.py new file mode 100755 index 0000000..d635e3c --- /dev/null +++ b/src/openmv/src/micropython/examples/accel_i2c.py @@ -0,0 +1,34 @@ +# This is an example on how to access accelerometer on +# PyBoard directly using I2C bus. As such, it's more +# intended to be an I2C example, rather than accelerometer +# example. For the latter, using pyb.Accel class is +# much easier. + +from machine import Pin +from machine import I2C +import time + +# Accelerometer needs to be powered on first. Even +# though signal is called "AVDD", and there's separate +# "DVDD", without AVDD, it won't event talk on I2C bus. +accel_pwr = Pin("MMA_AVDD") +accel_pwr.value(1) + +i2c = I2C(1, baudrate=100000) +addrs = i2c.scan() +print("Scanning devices:", [hex(x) for x in addrs]) +if 0x4c not in addrs: + print("Accelerometer is not detected") + +ACCEL_ADDR = 0x4c +ACCEL_AXIS_X_REG = 0 +ACCEL_MODE_REG = 7 + +# Now activate measurements +i2c.mem_write(b"\x01", ACCEL_ADDR, ACCEL_MODE_REG) + +print("Try to move accelerometer and watch the values") +while True: + val = i2c.mem_read(1, ACCEL_ADDR, ACCEL_AXIS_X_REG) + print(val[0]) + time.sleep(1) diff --git a/src/openmv/src/micropython/examples/accellog.py b/src/openmv/src/micropython/examples/accellog.py new file mode 100755 index 0000000..b1f289f --- /dev/null +++ b/src/openmv/src/micropython/examples/accellog.py @@ -0,0 +1,17 @@ +# log the accelerometer values to a .csv-file on the SD-card + +import pyb + +accel = pyb.Accel() # create object of accelerometer +blue = pyb.LED(4) # create object of blue LED + +log = open('/sd/log.csv', 'w') # open file to write data - /sd/ is the SD-card, /flash/ the internal memory +blue.on() # turn on blue LED + +for i in range(100): # do 100 times (if the board is connected via USB, you can't write longer because the PC tries to open the filesystem which messes up your file.) + t = pyb.millis() # get time since reset + x, y, z = accel.filtered_xyz() # get acceleration data + log.write('{},{},{},{}\n'.format(t,x,y,z)) # write data to file + +log.close() # close file +blue.off() # turn off LED diff --git a/src/openmv/src/micropython/examples/asmled.py b/src/openmv/src/micropython/examples/asmled.py new file mode 100755 index 0000000..917d9ba --- /dev/null +++ b/src/openmv/src/micropython/examples/asmled.py @@ -0,0 +1,85 @@ +# flash LED #1 using inline assembler +# this version is overly verbose and uses word stores +@micropython.asm_thumb +def flash_led(r0): + movw(r1, (stm.GPIOA + stm.GPIO_BSRRL) & 0xffff) + movt(r1, ((stm.GPIOA + stm.GPIO_BSRRL) >> 16) & 0x7fff) + movw(r2, 1 << 13) + movt(r2, 0) + movw(r3, 0) + movt(r3, 1 << 13) + + b(loop_entry) + + label(loop1) + + # turn LED on + str(r2, [r1, 0]) + + # delay for a bit + movw(r4, 5599900 & 0xffff) + movt(r4, (5599900 >> 16) & 0xffff) + label(delay_on) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_on) + + # turn LED off + str(r3, [r1, 0]) + + # delay for a bit + movw(r4, 5599900 & 0xffff) + movt(r4, (5599900 >> 16) & 0xffff) + label(delay_off) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_off) + + # loop r0 times + sub(r0, r0, 1) + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + +# flash LED #2 using inline assembler +# this version uses half-word sortes, and the convenience assembler operation 'movwt' +@micropython.asm_thumb +def flash_led_v2(r0): + # get the GPIOA address in r1 + movwt(r1, stm.GPIOA) + + # get the bit mask for PA14 (the pin LED #2 is on) + movw(r2, 1 << 14) + + b(loop_entry) + + label(loop1) + + # turn LED on + strh(r2, [r1, stm.GPIO_BSRRL]) + + # delay for a bit + movwt(r4, 5599900) + label(delay_on) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_on) + + # turn LED off + strh(r2, [r1, stm.GPIO_BSRRH]) + + # delay for a bit + movwt(r4, 5599900) + label(delay_off) + sub(r4, r4, 1) + cmp(r4, 0) + bgt(delay_off) + + # loop r0 times + sub(r0, r0, 1) + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + +flash_led(5) +flash_led_v2(5) diff --git a/src/openmv/src/micropython/examples/asmsum.py b/src/openmv/src/micropython/examples/asmsum.py new file mode 100755 index 0000000..07e71c7 --- /dev/null +++ b/src/openmv/src/micropython/examples/asmsum.py @@ -0,0 +1,57 @@ +@micropython.asm_thumb +def asm_sum_words(r0, r1): + + # r0 = len + # r1 = ptr + # r2 = sum + # r3 = dummy + mov(r2, 0) + + b(loop_entry) + + label(loop1) + ldr(r3, [r1, 0]) + add(r2, r2, r3) + + add(r1, r1, 4) + sub(r0, r0, 1) + + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + + mov(r0, r2) + +@micropython.asm_thumb +def asm_sum_bytes(r0, r1): + + # r0 = len + # r1 = ptr + # r2 = sum + # r3 = dummy + mov(r2, 0) + + b(loop_entry) + + label(loop1) + ldrb(r3, [r1, 0]) + add(r2, r2, r3) + + add(r1, r1, 1) + sub(r0, r0, 1) + + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + + mov(r0, r2) + +import array + +b = array.array('l', (100, 200, 300, 400)) +n = asm_sum_words(len(b), b) +print(b, n) + +b = array.array('b', (10, 20, 30, 40, 50, 60, 70, 80)) +n = asm_sum_bytes(len(b), b) +print(b, n) diff --git a/src/openmv/src/micropython/examples/conwaylife.py b/src/openmv/src/micropython/examples/conwaylife.py new file mode 100755 index 0000000..323f42e --- /dev/null +++ b/src/openmv/src/micropython/examples/conwaylife.py @@ -0,0 +1,46 @@ +#import essential libraries +import pyb + +lcd = pyb.LCD('x') +lcd.light(1) + +# do 1 iteration of Conway's Game of Life +def conway_step(): + for x in range(128): # loop over x coordinates + for y in range(32): # loop over y coordinates + # count number of neighbours + num_neighbours = (lcd.get(x - 1, y - 1) + + lcd.get(x, y - 1) + + lcd.get(x + 1, y - 1) + + lcd.get(x - 1, y) + + lcd.get(x + 1, y) + + lcd.get(x + 1, y + 1) + + lcd.get(x, y + 1) + + lcd.get(x - 1, y + 1)) + + # check if the centre cell is alive or not + self = lcd.get(x, y) + + # apply the rules of life + if self and not (2 <= num_neighbours <= 3): + lcd.pixel(x, y, 0) # not enough, or too many neighbours: cell dies + elif not self and num_neighbours == 3: + lcd.pixel(x, y, 1) # exactly 3 neighbours around an empty cell: cell is born + +# randomise the start +def conway_rand(): + lcd.fill(0) # clear the LCD + for x in range(128): # loop over x coordinates + for y in range(32): # loop over y coordinates + lcd.pixel(x, y, pyb.rng() & 1) # set the pixel randomly + +# loop for a certain number of frames, doing iterations of Conway's Game of Life +def conway_go(num_frames): + for i in range(num_frames): + conway_step() # do 1 iteration + lcd.show() # update the LCD + pyb.delay(50) + +# testing +conway_rand() +conway_go(100) diff --git a/src/openmv/src/micropython/examples/embedding/Makefile b/src/openmv/src/micropython/examples/embedding/Makefile new file mode 100755 index 0000000..99f239a --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/Makefile @@ -0,0 +1,8 @@ +MPTOP = ../.. +CFLAGS = -std=c99 -I. -I$(MPTOP) -DNO_QSTR +LDFLAGS = -L. + +hello-embed: hello-embed.o -lmicropython + +-lmicropython: + $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) diff --git a/src/openmv/src/micropython/examples/embedding/Makefile.upylib b/src/openmv/src/micropython/examples/embedding/Makefile.upylib new file mode 100755 index 0000000..6d63020 --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/Makefile.upylib @@ -0,0 +1,198 @@ +MPTOP = ../.. +-include mpconfigport.mk +include $(MPTOP)/py/mkenv.mk + +all: lib + +# OS name, for simple autoconfig +UNAME_S := $(shell uname -s) + +# include py core make definitions +include $(MPTOP)/py/py.mk + +INC += -I. +INC += -I.. +INC += -I$(MPTOP) +INC += -I$(MPTOP)/ports/unix +INC += -I$(BUILD) + +# compiler settings +CWARN = -Wall -Werror +CWARN += -Wpointer-arith -Wuninitialized +CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) + +# Debugging/Optimization +ifdef DEBUG +CFLAGS += -g +COPT = -O0 +else +COPT = -Os #-DNDEBUG +# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra +# security for detecting buffer overflows. Some distros (Ubuntu at the very least) +# have it enabled by default. +# +# gcc already optimizes some printf calls to call puts and/or putchar. When +# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some +# printf calls will also be optimized to call __printf_chk (in glibc). Any +# printfs which get redirected to __printf_chk are then no longer synchronized +# with printfs that go through mp_printf. +# +# In MicroPython, we don't want to use the runtime library's printf but rather +# go through mp_printf, so that stdout is properly tied into streams, etc. +# This means that we either need to turn off _FORTIFY_SOURCE or provide our +# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE. +# It should also be noted that the use of printf in MicroPython is typically +# quite limited anyways (primarily for debug and some error reporting, etc +# in the unix version). +# +# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could +# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/ +# Original patchset was introduced by +# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html . +# +# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater +CFLAGS += -U _FORTIFY_SOURCE +endif + +# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. +# The unix port of MicroPython on OSX must be compiled with clang, +# while cross-compile ports require gcc, so we test here for OSX and +# if necessary override the value of 'CC' set in py/mkenv.mk +ifeq ($(UNAME_S),Darwin) +CC = clang +# Use clang syntax for map file +LDFLAGS_ARCH = -Wl,-map,$@.map +else +# Use gcc syntax for map file +LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref +endif +LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) + +ifeq ($(MICROPY_FORCE_32BIT),1) +# Note: you may need to install i386 versions of dependency packages, +# starting with linux-libc-dev:i386 +ifeq ($(MICROPY_PY_FFI),1) +ifeq ($(UNAME_S),Linux) +CFLAGS_MOD += -I/usr/include/i686-linux-gnu +endif +endif +endif + +ifeq ($(MICROPY_USE_READLINE),1) +INC += -I$(MPTOP)/lib/mp-readline +CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +LIB_SRC_C_EXTRA += mp-readline/readline.c +endif +ifeq ($(MICROPY_USE_READLINE),2) +CFLAGS_MOD += -DMICROPY_USE_READLINE=2 +LDFLAGS_MOD += -lreadline +# the following is needed for BSD +#LDFLAGS_MOD += -ltermcap +endif +ifeq ($(MICROPY_PY_TIME),1) +CFLAGS_MOD += -DMICROPY_PY_TIME=1 +SRC_MOD += modtime.c +endif +ifeq ($(MICROPY_PY_TERMIOS),1) +CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 +SRC_MOD += modtermios.c +endif +ifeq ($(MICROPY_PY_SOCKET),1) +CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 +SRC_MOD += modsocket.c +endif + +ifeq ($(MICROPY_PY_FFI),1) + +ifeq ($(MICROPY_STANDALONE),1) +LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include) + ifeq ($(MICROPY_FORCE_32BIT),1) + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a + else + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a + endif +else +LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) +LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi) +endif + +ifeq ($(UNAME_S),Linux) +LIBFFI_LDFLAGS_MOD += -ldl +endif + +CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1 +LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD) +SRC_MOD += modffi.c +endif + +MAIN_C = main.c + +# source files +SRC_C = $(addprefix ports/unix/,\ + $(MAIN_C) \ + gccollect.c \ + unix_mphal.c \ + input.c \ + file.c \ + modmachine.c \ + modos.c \ + moduselect.c \ + alloc.c \ + coverage.c \ + fatfs_port.c \ + $(SRC_MOD) \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + $(LIB_SRC_C_EXTRA) \ + utils/printf.c \ + timeutils/timeutils.c \ + ) + +ifeq ($(MICROPY_FATFS),1) +LIB_SRC_C += $(addprefix lib/,\ + fatfs/ff.c \ + fatfs/option/ccsbcs.c \ + ) +endif + +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(LIB_SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +include $(MPTOP)/py/mkrules.mk + +# Value of configure's --host= option (required for cross-compilation). +# Deduce it from CROSS_COMPILE by default, but can be overridden. +ifneq ($(CROSS_COMPILE),) +CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE)) +else +CROSS_COMPILE_HOST = +endif + +deplibs: libffi axtls + +# install-exec-recursive & install-data-am targets are used to avoid building +# docs and depending on makeinfo +libffi: + cd $(MPTOP)/lib/libffi; git clean -d -x -f + cd $(MPTOP)/lib/libffi; ./autogen.sh + mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \ + ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ + make install-exec-recursive; make -C include install-data-am + +axtls: $(MPTOP)/lib/axtls/README + cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config + cd $(MPTOP)/lib/axtls; make oldconfig -B + cd $(MPTOP)/lib/axtls; make clean + cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)" + +$(MPTOP)/lib/axtls/README: + @echo "You cloned without --recursive, fetching submodules for you." + (cd $(MPTOP); git submodule update --init --recursive) diff --git a/src/openmv/src/micropython/examples/embedding/README.md b/src/openmv/src/micropython/examples/embedding/README.md new file mode 100755 index 0000000..0dfc52e --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/README.md @@ -0,0 +1,67 @@ +Example of embedding MicroPython in a standalone C application +============================================================== + +This directory contains a (very simple!) example of how to embed a MicroPython +in an existing C application. + +A C application is represented by the file `hello-embed.c`. It executes a simple +Python statement which prints to the standard output. + + +Building the example +-------------------- + +Building the example is as simple as running: + + make + +It's worth to trace what's happening behind the scenes though: + +1. As a first step, a MicroPython library is built. This is handled by a +separate makefile, `Makefile.upylib`. It is more or less complex, but the +good news is that you won't need to change anything in it, just use it +as is, the main `Makefile` shows how. What may require editing though is +a MicroPython configuration file. MicroPython is highly configurable, so +you would need to build a library suiting your application well, while +not bloating its size. Check the options in the file `mpconfigport.h`. +Included is a copy of the "minimal" Unix port, which should be a good start +for minimal embedding. For the list of all available options, see +`py/mpconfig.h`. + +2. Once the MicroPython library is built, your application is compiled +and linked it. The main Makefile is very simple and shows that the changes +you would need to do to your application's `Makefile` (or other build +configuration) are also simple: + +a) You would need to use C99 standard (you're using this 15+ years old +standard already, not a 25+ years old one, right?). + +b) You need to provide a path to MicroPython's top-level dir, for includes. + +c) You need to include `-DNO_QSTR` compile-time flag. + +d) Otherwise, just link with the MicroPython library produced in step 1. + + +Out of tree build +----------------- + +This example is set up to work out of the box, being part of the MicroPython +tree. Your application of course will be outside of its tree, but the +only thing you need to do is to pass `MPTOP` variable pointing to +MicroPython directory to both Makefiles (in this example, the main Makefile +automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget +to use a suitable value). + +A practical way to embed MicroPython in your application is to include it +as a git submodule. Suppose you included it as `libs/micropython`. Then in +your main Makefile you would have something like: + +~~~ +MPTOP = libs/micropython + +my_app: $(MY_OBJS) -lmicropython + +-lmicropython: + $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP) +~~~ diff --git a/src/openmv/src/micropython/examples/embedding/hello-embed.c b/src/openmv/src/micropython/examples/embedding/hello-embed.c new file mode 100755 index 0000000..9659630 --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/hello-embed.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/stackctrl.h" + +static char heap[16384]; + +mp_obj_t execute_from_str(const char *str) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + qstr src_name = 1/*MP_QSTR_*/; + mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false); + mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&pt, src_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + return 0; + } else { + // uncaught exception + return (mp_obj_t)nlr.ret_val; + } +} + +int main() { + // Initialized stack limit + mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + // Initialize heap + gc_init(heap, heap + sizeof(heap)); + // Initialize interpreter + mp_init(); + + const char str[] = "print('Hello world of easy embedding!')"; + if (execute_from_str(str)) { + printf("Error\n"); + } +} + +uint mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught NLR %p\n", val); + exit(1); +} diff --git a/src/openmv/src/micropython/examples/embedding/mpconfigport.h b/src/openmv/src/micropython/examples/embedding/mpconfigport.h new file mode 100755 index 0000000..142e5d6 --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/mpconfigport.h @@ -0,0 +1 @@ +mpconfigport_minimal.h \ No newline at end of file diff --git a/src/openmv/src/micropython/examples/embedding/mpconfigport_minimal.h b/src/openmv/src/micropython/examples/embedding/mpconfigport_minimal.h new file mode 100755 index 0000000..fa52be4 --- /dev/null +++ b/src/openmv/src/micropython/examples/embedding/mpconfigport_minimal.h @@ -0,0 +1,134 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (0) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_READER_POSIX (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_WARNINGS (0) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#define MICROPY_STREAMS_NON_BLOCK (0) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_CAN_OVERRIDE_BUILTINS (0) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_COMPILE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_GC_COLLECT_RETVAL (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_EXIT (0) +#define MICROPY_PY_SYS_PLATFORM "linux" +#define MICROPY_PY_SYS_MAXSIZE (0) +#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_URE (0) +#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UBINASCII (0) + +extern const struct _mp_obj_module_t mp_module_os; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ + +#define MICROPY_PORT_ROOT_POINTERS \ + +////////////////////////////////////////// +// Do not change anything beyond this line +////////////////////////////////////////// + +// Define to 1 to use undertested inefficient GC helper implementation +// (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP + #ifdef __mips__ + #define MICROPY_GCREGS_SETJMP (1) + #else + #define MICROPY_GCREGS_SETJMP (0) + #endif +#endif + +// type definitions for the specific machine + +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +// We need to provide a declaration/definition of alloca() +#ifdef __FreeBSD__ +#include +#else +#include +#endif diff --git a/src/openmv/src/micropython/examples/hwapi/README.md b/src/openmv/src/micropython/examples/hwapi/README.md new file mode 100755 index 0000000..1992eb6 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/README.md @@ -0,0 +1,126 @@ +This directory shows the best practices for using MicroPython hardware API +(`machine` module). `machine` module strives to provide consistent API +across various boards, with the aim to enable writing portable applications, +which would work from a board to board, from a system to another systems. +This is inherently a hard problem, because hardware is different from one +board type to another, and even from examplar of board to another. For +example, if your app requires an external LED, one user may connect it +to one GPIO pin, while another user may find it much more convinient to +use another pin. This of course applies to relays, buzzers, sensors, etc. + +With complications above in mind, it's still possible to write portable +applications by using "low[est] denominator" subset of hardware API and +following simple rules outlined below. The applications won't be able +to rely on advanced hardware capabilities of a particular board and +will be limited to generic capabilities, but it's still possible to +write many useful applications in such a way, with the obvious benefit of +"write once - run everywhere" approach (only configuration for a particular +board is required). + +The key to this approach is splitting your application into (at least) +2 parts: + +* main application logic +* hardware configuration + +The key point is that hardware configuration should be a separate file +(module in Python terms). A good name would be `hwconfig.py`, and that's +how we'll call it from now on. Another key point is that main application +should never instantiate (construct) hardware objects directly. Instead, +they should be defined in `hwconfig.py`, and main application should +import and reference hardware objects via this module. The simplest +application of this idea would look like: + +`hwconfig.py`: + + from machine import Pin + + LED = Pin("A3", Pin.OUT) + +`app.py`: + + from hwconfig import * + import utime + + while True: + LED.value(1) + utime.sleep_ms(500) + LED.value(0) + utime.sleep_ms(500) + + +To deploy this application to a particular board, a user will need: + +1. Edit `hwconfig.py` to adjust Pin and other hardware peripheral + parameters and locations. +2. Actually deploy `hwconfig.py` and `app.py` to a board (e.g. copy to + board's filesystem, or build new firmware with these modules frozen + into it). + +Note that there's no need to edit the main application code! (Which may +be complex, while `hwconfig.py` should usually remain short enough, and +focused solely on hardware configuration). + +An obvious improvement to this approach is the following. There're few +well-known boards which run MicroPython, and most of them include an +onboard LED. So, to help users of these boards to do configuration +quickly (that's especially important for novice users, for who may +be stumped by the need to reach out to a board reference to find LED +pin assignments), `hwconfig.py` your application ships may include +commented out sections with working configurations for different +boards. The step 1 above then will be: + +1. Look thru `hwconfig.py` to find a section which either exactly + matches your board, or the closest to it. Uncomment, and if any + adjustments required, apply them. + +It's important to keep in mind that adjustments may be always required, +and that there may be users whose configuration doesn't match any of +the available. So, always include a section or instructions for them. +Consider for example that even on a supported board, user may want to +blink not an on-board LED, but the one they connected externally. +MicroPython's Hardware API offers portability not just among "supported" +boards, but to any board at all, so make sure users can enjoy it. + +There's next step of improvement to make. While having one `hwconfig.py` +with many sections would work for smaller projects with few hardware +objects, it may become more cumbersome to maintain both on programmer's +and user's sides for larger projects. Then instead of single +`hwconfig.py` file, you can provide few "template" ones for well-known +boards: + +* `hwconfig_pyboard.py` +* `hwconfig_wipy.py` +* `hwconfig_esp8266.py` +* etc. + +Then step 1 above will be: + +1. Look thru available `hwconfig_*.py` files and find one which matches + your board the best, then rename to `hwconfig.py` and make adjustments, + if any. + +Again, please keep in mind that there may be users whose hardware will be +completely unlike you heard of. Give them some helpful hints too, perhaps +provide `hwconfig_custom.py` with some instructions. + +That's where we stop with improvements to the "separate file for hardware +configuration" idea, as it is already pretty flexible and viable. An +application in this directory shows it in practice, using slightly less +trivial example than just a blinking LED: `soft_pwm.py` implements a +software PWM (pulse width modulation) to produce an LED fade-in/fade-out +effect - without any dependence on hardware PWM availability. + +Note that improvements to board configuration handling may continue further. +For example, one may invent a "configuration manager" helper module which will +try to detect current board (among well-known ones), and load appropriate +`hwconfig_*.py` - this assumes that a user would lazily deploy them all +(or that application will be automatically installed, e.g. using MicroPython's +`upip` package manager). The key point in this case remains the same as +elaborated above - always assume there can, and will be a custom configuration, +and it should be well supported. So, any automatic detection should be +overridable by a user, and instructions how to do so are among the most +important you may provide for your application. + +By following these best practices, you will use MicroPython at its full +potential, and let users enjoy it too. Good luck! diff --git a/src/openmv/src/micropython/examples/hwapi/button_led.py b/src/openmv/src/micropython/examples/hwapi/button_led.py new file mode 100755 index 0000000..bd6fe01 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/button_led.py @@ -0,0 +1,9 @@ +import utime +from hwconfig import LED, BUTTON + +# Light LED when (and while) a BUTTON is pressed + +while 1: + LED.value(BUTTON.value()) + # Don't burn CPU + utime.sleep_ms(10) diff --git a/src/openmv/src/micropython/examples/hwapi/button_reaction.py b/src/openmv/src/micropython/examples/hwapi/button_reaction.py new file mode 100755 index 0000000..b72e813 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/button_reaction.py @@ -0,0 +1,19 @@ +import utime +import machine +from hwconfig import LED, BUTTON + +# machine.time_pulse_us() function demo + +print("""\ +Let's play an interesting game: +You click button as fast as you can, and I tell you how slow you are. +Ready? Cliiiiick! +""") + +while 1: + delay = machine.time_pulse_us(BUTTON, 1, 10*1000*1000) + if delay < 0: + print("Well, you're *really* slow") + else: + print("You are as slow as %d microseconds!" % delay) + utime.sleep_ms(10) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_console.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_console.py new file mode 100755 index 0000000..bbcc0e8 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_console.py @@ -0,0 +1,19 @@ +# This is hwconfig for "emulation" for cases when there's no real hardware. +# It just prints information to console. +class LEDClass: + + def __init__(self, id): + self.id = "LED(%d):" % id + + def value(self, v): + print(self.id, v) + + def on(self): + self.value(1) + + def off(self): + self.value(0) + + +LED = LEDClass(1) +LED2 = LEDClass(12) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_dragonboard410c.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_dragonboard410c.py new file mode 100755 index 0000000..eec3582 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_dragonboard410c.py @@ -0,0 +1,22 @@ +from machine import Pin, Signal + +# 96Boards/Qualcomm DragonBoard 410c +# +# By default, on-board LEDs are controlled by kernel LED driver. +# To make corresponding pins be available as normal GPIO, +# corresponding driver needs to be unbound first (as root): +# echo -n "soc:leds" >/sys/class/leds/apq8016-sbc:green:user1/device/driver/unbind +# Note that application also either should be run as root, or +# /sys/class/gpio ownership needs to be changed. +# Likewise, onboard buttons are controlled by gpio_keys driver. +# To release corresponding GPIOs: +# echo -n "gpio_keys" >/sys/class/input/input1/device/driver/unbind + +# User LED 1 on gpio21 +LED = Signal(Pin(21, Pin.OUT)) + +# User LED 2 on gpio120 +LED2 = Signal(Pin(120, Pin.OUT)) + +# Button S3 on gpio107 +BUTTON = Pin(107, Pin.IN) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_esp8266_esp12.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_esp8266_esp12.py new file mode 100755 index 0000000..2e855ee --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_esp8266_esp12.py @@ -0,0 +1,5 @@ +from machine import Pin, Signal + +# ESP12 module as used by many boards +# Blue LED on pin 2, active low (inverted) +LED = Signal(2, Pin.OUT, invert=True) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_pyboard.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_pyboard.py new file mode 100755 index 0000000..fb26003 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_pyboard.py @@ -0,0 +1,13 @@ +from machine import Pin, Signal + +# Red LED on pin LED_RED also kown as A13 +LED = Signal('LED_RED', Pin.OUT) + +# Green LED on pin LED_GREEN also known as A14 +LED2 = Signal('LED_GREEN', Pin.OUT) + +# Yellow LED on pin LED_YELLOW also known as A15 +LED3 = Signal('LED_YELLOW', Pin.OUT) + +# Blue LED on pin LED_BLUE also known as B4 +LED4 = Signal('LED_BLUE', Pin.OUT) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_z_96b_carbon.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_z_96b_carbon.py new file mode 100755 index 0000000..97fd57a --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_z_96b_carbon.py @@ -0,0 +1,9 @@ +from machine import Signal + +# 96Boards Carbon board +# USR1 - User controlled led, connected to PD2 +# USR2 - User controlled led, connected to PA15 +# BT - Bluetooth indicator, connected to PB5. +# Note - 96b_carbon uses (at the time of writing) non-standard +# for Zephyr port device naming convention. +LED = Signal(("GPIOA", 15), Pin.OUT) diff --git a/src/openmv/src/micropython/examples/hwapi/hwconfig_z_frdm_k64f.py b/src/openmv/src/micropython/examples/hwapi/hwconfig_z_frdm_k64f.py new file mode 100755 index 0000000..377c638 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/hwconfig_z_frdm_k64f.py @@ -0,0 +1,5 @@ +from machine import Pin, Signal + +# Freescale/NXP FRDM-K64F board +# Blue LED on port B, pin 21 +LED = Signal(("GPIO_1", 21), Pin.OUT) diff --git a/src/openmv/src/micropython/examples/hwapi/soft_pwm.py b/src/openmv/src/micropython/examples/hwapi/soft_pwm.py new file mode 100755 index 0000000..72291b0 --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/soft_pwm.py @@ -0,0 +1,38 @@ +import utime +from hwconfig import LED + + +# Using sleep_ms() gives pretty poor PWM resolution and +# brightness control, but we use it in the attempt to +# make this demo portable to even more boards (e.g. to +# those which don't provide sleep_us(), or provide, but +# it's not precise, like would be on non realtime OSes). +# We otherwise use 20ms period, to make frequency not less +# than 50Hz to avoid visible flickering (you may still see +# if you're unlucky). +def pwm_cycle(led, duty, cycles): + duty_off = 20 - duty + for i in range(cycles): + if duty: + led.on() + utime.sleep_ms(duty) + if duty_off: + led.off() + utime.sleep_ms(duty_off) + + +# At the duty setting of 1, an LED is still pretty bright, then +# at duty 0, it's off. This makes rather unsmooth transition, and +# breaks fade effect. So, we avoid value of 0 and oscillate between +# 1 and 20. Actually, highest values like 19 and 20 are also +# barely distinguishible (like, both of them too bright and burn +# your eye). So, improvement to the visible effect would be to use +# more steps (at least 10x), and then higher frequency, and use +# range which includes 1 but excludes values at the top. +while True: + # Fade in + for i in range(1, 21): + pwm_cycle(LED, i, 2) + # Fade out + for i in range(20, 0, -1): + pwm_cycle(LED, i, 2) diff --git a/src/openmv/src/micropython/examples/hwapi/soft_pwm2_uasyncio.py b/src/openmv/src/micropython/examples/hwapi/soft_pwm2_uasyncio.py new file mode 100755 index 0000000..908ef2d --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/soft_pwm2_uasyncio.py @@ -0,0 +1,31 @@ +# Like soft_pwm_uasyncio.py, but fading 2 LEDs with different phase. +# Also see original soft_pwm.py. +import uasyncio +from hwconfig import LED, LED2 + + +async def pwm_cycle(led, duty, cycles): + duty_off = 20 - duty + for i in range(cycles): + if duty: + led.value(1) + await uasyncio.sleep_ms(duty) + if duty_off: + led.value(0) + await uasyncio.sleep_ms(duty_off) + + +async def fade_in_out(LED): + while True: + # Fade in + for i in range(1, 21): + await pwm_cycle(LED, i, 2) + # Fade out + for i in range(20, 0, -1): + await pwm_cycle(LED, i, 2) + + +loop = uasyncio.get_event_loop() +loop.create_task(fade_in_out(LED)) +loop.call_later_ms(800, fade_in_out(LED2)) +loop.run_forever() diff --git a/src/openmv/src/micropython/examples/hwapi/soft_pwm_uasyncio.py b/src/openmv/src/micropython/examples/hwapi/soft_pwm_uasyncio.py new file mode 100755 index 0000000..8d7ad8c --- /dev/null +++ b/src/openmv/src/micropython/examples/hwapi/soft_pwm_uasyncio.py @@ -0,0 +1,28 @@ +# See original soft_pwm.py for detailed comments. +import uasyncio +from hwconfig import LED + + +async def pwm_cycle(led, duty, cycles): + duty_off = 20 - duty + for i in range(cycles): + if duty: + led.value(1) + await uasyncio.sleep_ms(duty) + if duty_off: + led.value(0) + await uasyncio.sleep_ms(duty_off) + + +async def fade_in_out(LED): + while True: + # Fade in + for i in range(1, 21): + await pwm_cycle(LED, i, 2) + # Fade out + for i in range(20, 0, -1): + await pwm_cycle(LED, i, 2) + + +loop = uasyncio.get_event_loop() +loop.run_until_complete(fade_in_out(LED)) diff --git a/src/openmv/src/micropython/examples/ledangle.py b/src/openmv/src/micropython/examples/ledangle.py new file mode 100755 index 0000000..8c8d9e9 --- /dev/null +++ b/src/openmv/src/micropython/examples/ledangle.py @@ -0,0 +1,25 @@ +import pyb + +def led_angle(seconds_to_run_for): + # make LED objects + l1 = pyb.LED(1) + l2 = pyb.LED(2) + accel = pyb.Accel() + + for i in range(20 * seconds_to_run_for): + # get x-axis + x = accel.x() + + # turn on LEDs depending on angle + if x < -10: + l1.on() + l2.off() + elif x > 10: + l1.off() + l2.on() + else: + l1.off() + l2.off() + + # delay so that loop runs at at 1/50ms = 20Hz + pyb.delay(50) diff --git a/src/openmv/src/micropython/examples/mandel.py b/src/openmv/src/micropython/examples/mandel.py new file mode 100755 index 0000000..bbb8086 --- /dev/null +++ b/src/openmv/src/micropython/examples/mandel.py @@ -0,0 +1,27 @@ +try: + import micropython +except: + pass + +def mandelbrot(): + # returns True if c, complex, is in the Mandelbrot set + #@micropython.native + def in_set(c): + z = 0 + for i in range(40): + z = z*z + c + if abs(z) > 60: + return False + return True + + lcd.clear() + for u in range(91): + for v in range(31): + if in_set((u / 30 - 2) + (v / 15 - 1) * 1j): + lcd.set(u, v) + lcd.show() + +# PC testing +import lcd +lcd = lcd.LCD(128, 32) +mandelbrot() diff --git a/src/openmv/src/micropython/examples/micropython.py b/src/openmv/src/micropython/examples/micropython.py new file mode 100755 index 0000000..f91da94 --- /dev/null +++ b/src/openmv/src/micropython/examples/micropython.py @@ -0,0 +1,8 @@ +# micropython module placeholder for CPython + +# Dummy function decorators + +def nodecor(x): + return x + +bytecode = native = viper = nodecor diff --git a/src/openmv/src/micropython/examples/network/http_client.py b/src/openmv/src/micropython/examples/network/http_client.py new file mode 100755 index 0000000..0791c80 --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_client.py @@ -0,0 +1,30 @@ +try: + import usocket as socket +except: + import socket + + +def main(use_stream=False): + s = socket.socket() + + ai = socket.getaddrinfo("google.com", 80) + print("Address infos:", ai) + addr = ai[0][-1] + + print("Connect address:", addr) + s.connect(addr) + + if use_stream: + # MicroPython socket objects support stream (aka file) interface + # directly, but the line below is needed for CPython. + s = s.makefile("rwb", 0) + s.write(b"GET / HTTP/1.0\r\n\r\n") + print(s.read()) + else: + s.send(b"GET / HTTP/1.0\r\n\r\n") + print(s.recv(4096)) + + s.close() + + +main() diff --git a/src/openmv/src/micropython/examples/network/http_client_ssl.py b/src/openmv/src/micropython/examples/network/http_client_ssl.py new file mode 100755 index 0000000..83f685f --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_client_ssl.py @@ -0,0 +1,38 @@ +try: + import usocket as _socket +except: + import _socket +try: + import ussl as ssl +except: + import ssl + + +def main(use_stream=True): + s = _socket.socket() + + ai = _socket.getaddrinfo("google.com", 443) + print("Address infos:", ai) + addr = ai[0][-1] + + print("Connect address:", addr) + s.connect(addr) + + s = ssl.wrap_socket(s) + print(s) + + if use_stream: + # Both CPython and MicroPython SSLSocket objects support read() and + # write() methods. + s.write(b"GET / HTTP/1.0\r\n\r\n") + print(s.read(4096)) + else: + # MicroPython SSLSocket objects implement only stream interface, not + # socket interface + s.send(b"GET / HTTP/1.0\r\n\r\n") + print(s.recv(4096)) + + s.close() + + +main() diff --git a/src/openmv/src/micropython/examples/network/http_server.py b/src/openmv/src/micropython/examples/network/http_server.py new file mode 100755 index 0000000..e3a66e8 --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_server.py @@ -0,0 +1,64 @@ +try: + import usocket as socket +except: + import socket + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(micropython_optimize=False): + s = socket.socket() + + # Binding to all interfaces - server will be accessible to other hosts! + ai = socket.getaddrinfo("0.0.0.0", 8080) + print("Bind address info:", ai) + addr = ai[0][-1] + + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to http://:8080/") + + counter = 0 + while True: + res = s.accept() + client_sock = res[0] + client_addr = res[1] + print("Client address:", client_addr) + print("Client socket:", client_sock) + + if not micropython_optimize: + # To read line-oriented protocol (like HTTP) from a socket (and + # avoid short read problem), it must be wrapped in a stream (aka + # file-like) object. That's how you do it in CPython: + client_stream = client_sock.makefile("rwb") + else: + # .. but MicroPython socket objects support stream interface + # directly, so calling .makefile() method is not required. If + # you develop application which will run only on MicroPython, + # especially on a resource-constrained embedded device, you + # may take this shortcut to save resources. + client_stream = client_sock + + print("Request:") + req = client_stream.readline() + print(req) + while True: + h = client_stream.readline() + if h == b"" or h == b"\r\n": + break + print(h) + client_stream.write(CONTENT % counter) + + client_stream.close() + if not micropython_optimize: + client_sock.close() + counter += 1 + print() + + +main() diff --git a/src/openmv/src/micropython/examples/network/http_server_simplistic.py b/src/openmv/src/micropython/examples/network/http_server_simplistic.py new file mode 100755 index 0000000..67ecb1a --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_server_simplistic.py @@ -0,0 +1,40 @@ +# Do not use this code in real projects! Read +# http_server_simplistic_commented.py for details. +try: + import usocket as socket +except: + import socket + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(): + s = socket.socket() + ai = socket.getaddrinfo("0.0.0.0", 8080) + addr = ai[0][-1] + + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to http://:8080/") + + counter = 0 + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + req = client_s.recv(4096) + print("Request:") + print(req) + client_s.send(CONTENT % counter) + client_s.close() + counter += 1 + print() + + +main() diff --git a/src/openmv/src/micropython/examples/network/http_server_simplistic_commented.py b/src/openmv/src/micropython/examples/network/http_server_simplistic_commented.py new file mode 100755 index 0000000..b58e9ee --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_server_simplistic_commented.py @@ -0,0 +1,76 @@ +# +# MicroPython http_server_simplistic.py example +# +# This example shows how to write the smallest possible HTTP +# server in MicroPython. With comments and convenience code +# removed, this example can be compressed literally to ten +# lines. There's a catch though - read comments below for +# details, and use this code only for quick hacks, preferring +# http_server.py for "real thing". +# +try: + import usocket as socket +except: + import socket + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(): + s = socket.socket() + + # Bind to (allow to be connected on ) all interfaces. This means + # this server will be accessible to other hosts on your local + # network, and if your server has direct (non-firewalled) connection + # to the Internet, then to anyone on the Internet. We bind to all + # interfaces to let this example work easily on embedded MicroPython + # targets, which you will likely access from another machine on your + # local network. Take care when running this on an Internet-connected + # machine though! Replace "0.0.0.0" with "127.0.0.1" if in doubt, to + # make the server accessible only on the machine it runs on. + ai = socket.getaddrinfo("0.0.0.0", 8080) + print("Bind address info:", ai) + addr = ai[0][-1] + + # A port on which a socket listened remains inactive during some time. + # This means that if you run this sample, terminate it, and run again + # you will likely get an error. To avoid this timeout, set SO_REUSEADDR + # socket option. + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to http://:8080/") + + counter = 0 + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + print("Client address:", client_addr) + print("Client socket:", client_s) + # We assume here that .recv() call will read entire HTTP request + # from client. This is usually true, at least on "big OS" systems + # like Linux/MacOS/Windows. But that doesn't have to be true in + # all cases, in particular on embedded systems, when there can + # easily be "short recv", where it returns much less than requested + # data size. That's why this example is called "simplistic" - it + # shows that writing a web server in Python that *usually works* is + # ten lines of code, and you can use this technique for quick hacks + # and experimentation. But don't do it like that in production + # applications - instead, parse HTTP request properly, as shown + # by http_server.py example. + req = client_s.recv(4096) + print("Request:") + print(req) + client_s.send(CONTENT % counter) + client_s.close() + counter += 1 + print() + + +main() diff --git a/src/openmv/src/micropython/examples/network/http_server_ssl.py b/src/openmv/src/micropython/examples/network/http_server_ssl.py new file mode 100755 index 0000000..9a69ca9 --- /dev/null +++ b/src/openmv/src/micropython/examples/network/http_server_ssl.py @@ -0,0 +1,64 @@ +try: + import usocket as socket +except: + import socket +import ussl as ssl + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + +def main(use_stream=True): + s = socket.socket() + + # Binding to all interfaces - server will be accessible to other hosts! + ai = socket.getaddrinfo("0.0.0.0", 8443) + print("Bind address info:", ai) + addr = ai[0][-1] + + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to https://:8443/") + + counter = 0 + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + print("Client address:", client_addr) + print("Client socket:", client_s) + client_s = ssl.wrap_socket(client_s, server_side=True) + print(client_s) + print("Request:") + if use_stream: + # Both CPython and MicroPython SSLSocket objects support read() and + # write() methods. + # Browsers are prone to terminate SSL connection abruptly if they + # see unknown certificate, etc. We must continue in such case - + # next request they issue will likely be more well-behaving and + # will succeed. + try: + req = client_s.readline() + print(req) + while True: + h = client_s.readline() + if h == b"" or h == b"\r\n": + break + print(h) + if req: + client_s.write(CONTENT % counter) + except Exception as e: + print("Exception serving request:", e) + else: + print(client_s.recv(4096)) + client_s.send(CONTENT % counter) + client_s.close() + counter += 1 + print() + + +main() diff --git a/src/openmv/src/micropython/examples/pins.py b/src/openmv/src/micropython/examples/pins.py new file mode 100755 index 0000000..aafdb48 --- /dev/null +++ b/src/openmv/src/micropython/examples/pins.py @@ -0,0 +1,58 @@ +# Print a nice list of pins, their current settings, and available afs. +# Requires pins_af.py from ports/stm32/build-PYBV10/ directory. + +import pyb +import pins_af + +def af(): + max_name_width = 0 + max_af_width = 0 + for pin_entry in pins_af.PINS_AF: + max_name_width = max(max_name_width, len(pin_entry[0])) + for af_entry in pin_entry[1:]: + max_af_width = max(max_af_width, len(af_entry[1])) + for pin_entry in pins_af.PINS_AF: + pin_name = pin_entry[0] + print('%-*s ' % (max_name_width, pin_name), end='') + for af_entry in pin_entry[1:]: + print('%2d: %-*s ' % (af_entry[0], max_af_width, af_entry[1]), end='') + print('') + +def pins(): + mode_str = { pyb.Pin.IN : 'IN', + pyb.Pin.OUT_PP : 'OUT_PP', + pyb.Pin.OUT_OD : 'OUT_OD', + pyb.Pin.AF_PP : 'AF_PP', + pyb.Pin.AF_OD : 'AF_OD', + pyb.Pin.ANALOG : 'ANALOG' } + pull_str = { pyb.Pin.PULL_NONE : '', + pyb.Pin.PULL_UP : 'PULL_UP', + pyb.Pin.PULL_DOWN : 'PULL_DOWN' } + width = [0, 0, 0, 0] + rows = [] + for pin_entry in pins_af.PINS_AF: + row = [] + pin_name = pin_entry[0] + pin = pyb.Pin(pin_name) + pin_mode = pin.mode() + row.append(pin_name) + row.append(mode_str[pin_mode]) + row.append(pull_str[pin.pull()]) + if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD: + pin_af = pin.af() + for af_entry in pin_entry[1:]: + if pin_af == af_entry[0]: + af_str = '%d: %s' % (pin_af, af_entry[1]) + break + else: + af_str = '%d' % pin_af + else: + af_str = '' + row.append(af_str) + for col in range(len(width)): + width[col] = max(width[col], len(row[col])) + rows.append(row) + for row in rows: + for col in range(len(width)): + print('%-*s ' % (width[col], row[col]), end='') + print('') diff --git a/src/openmv/src/micropython/examples/pyb.py b/src/openmv/src/micropython/examples/pyb.py new file mode 100755 index 0000000..b303777 --- /dev/null +++ b/src/openmv/src/micropython/examples/pyb.py @@ -0,0 +1,49 @@ +# pyboard testing functions for CPython +import time + +def delay(n): + #time.sleep(float(n) / 1000) + pass + +rand_seed = 1 +def rng(): + global rand_seed + # for these choice of numbers, see P L'Ecuyer, "Tables of linear congruential generators of different sizes and good lattice structure" + rand_seed = (rand_seed * 653276) % 8388593 + return rand_seed + +# LCD testing object for PC +# uses double buffering +class LCD: + def __init__(self, port): + self.width = 128 + self.height = 32 + self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)] + self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)] + + def light(self, value): + pass + + def fill(self, value): + for y in range(self.height): + for x in range(self.width): + self.buf1[y][x] = self.buf2[y][x] = value + + def show(self): + print('') # blank line to separate frames + for y in range(self.height): + for x in range(self.width): + self.buf1[y][x] = self.buf2[y][x] + for y in range(self.height): + row = ''.join(['*' if self.buf1[y][x] else ' ' for x in range(self.width)]) + print(row) + + def get(self, x, y): + if 0 <= x < self.width and 0 <= y < self.height: + return self.buf1[y][x] + else: + return 0 + + def pixel(self, x, y, value): + if 0 <= x < self.width and 0 <= y < self.height: + self.buf2[y][x] = value diff --git a/src/openmv/src/micropython/examples/switch.py b/src/openmv/src/micropython/examples/switch.py new file mode 100755 index 0000000..0efaf22 --- /dev/null +++ b/src/openmv/src/micropython/examples/switch.py @@ -0,0 +1,45 @@ +""" +switch.py +========= + +Light up some leds when the USR switch on the pyboard is pressed. + +Example Usage:: + + Micro Python v1.0.1 on 2014-05-12; PYBv1.0 with STM32F405RG + Type "help()" for more information. + >>> import switch + >>> switch.run_loop() + Loop started. + Press Ctrl+C to break out of the loop. + +""" + +import pyb + +switch = pyb.Switch() +red_led = pyb.LED(1) +green_led = pyb.LED(2) +orange_led = pyb.LED(3) +blue_led = pyb.LED(4) +all_leds = (red_led, green_led, orange_led, blue_led) + +def run_loop(leds=all_leds): + """ + Start the loop. + + :param `leds`: Which LEDs to light up upon switch press. + :type `leds`: sequence of LED objects + """ + print('Loop started.\nPress Ctrl+C to break out of the loop.') + while 1: + try: + if switch(): + [led.on() for led in leds] + else: + [led.off() for led in leds] + except OSError: # VCPInterrupt # Ctrl+C in interpreter mode. + break + +if __name__ == '__main__': + run_loop() diff --git a/src/openmv/src/micropython/examples/unix/ffi_example.py b/src/openmv/src/micropython/examples/unix/ffi_example.py new file mode 100755 index 0000000..3c3c3d2 --- /dev/null +++ b/src/openmv/src/micropython/examples/unix/ffi_example.py @@ -0,0 +1,39 @@ +import ffi +import uctypes + +libc = ffi.open("libc.so.6") +print("libc:", libc) +print() + +# Declare few functions +perror = libc.func("v", "perror", "s") +time = libc.func("i", "time", "p") +open = libc.func("i", "open", "si") +qsort = libc.func("v", "qsort", "piiC") +# And one variable +errno = libc.var("i", "errno") + +print("time:", time) +print("UNIX time is:", time(None)) +print() + +perror("perror before error") +open("somethingnonexistent__", 0) +print("errno object:", errno) +print("errno value:", errno.get()) +perror("perror after error") +print() + +def cmp(pa, pb): + a = uctypes.bytearray_at(pa, 1) + b = uctypes.bytearray_at(pb, 1) + print("cmp:", a, b) + return a[0] - b[0] + +cmp_cb = ffi.callback("i", cmp, "PP") +print("callback:", cmp_cb) + +s = bytearray(b"foobar") +print("org string:", s) +qsort(s, len(s), 1, cmp_cb) +print("qsort'ed string:", s) diff --git a/src/openmv/src/micropython/examples/unix/machine_bios.py b/src/openmv/src/micropython/examples/unix/machine_bios.py new file mode 100755 index 0000000..f62e4db --- /dev/null +++ b/src/openmv/src/micropython/examples/unix/machine_bios.py @@ -0,0 +1,9 @@ +# This example shows how to access Video BIOS memory area via machine.mem +# It requires root privilege and x86 legacy harfware (which has mentioned +# Video BIOS at all). +# It is expected to print 0xaa55, which is a signature at the start of +# Video BIOS. + +import umachine as machine + +print(hex(machine.mem16[0xc0000])) diff --git a/src/openmv/src/micropython/extmod/axtls-include/config.h b/src/openmv/src/micropython/extmod/axtls-include/config.h new file mode 100755 index 0000000..a0dd2b2 --- /dev/null +++ b/src/openmv/src/micropython/extmod/axtls-include/config.h @@ -0,0 +1,117 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#define CONFIG_PLATFORM_LINUX 1 +#undef CONFIG_PLATFORM_CYGWIN +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#define PREFIX "/usr/local" +#undef CONFIG_DEBUG +#undef CONFIG_STRIP_UNWANTED_SECTIONS +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#undef CONFIG_VISUAL_STUDIO_10_0 +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_VISUAL_STUDIO_10_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#undef CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_FULL_MODE +#define CONFIG_SSL_SKELETON_MODE 1 +#define CONFIG_SSL_ENABLE_SERVER 1 +#define CONFIG_SSL_ENABLE_CLIENT 1 +#undef CONFIG_SSL_DIAGNOSTICS +#define CONFIG_SSL_PROT_LOW 1 +#undef CONFIG_SSL_PROT_MEDIUM +#undef CONFIG_SSL_PROT_HIGH +#define CONFIG_SSL_AES 1 +#define CONFIG_SSL_USE_DEFAULT_KEY 1 +#define CONFIG_SSL_PRIVATE_KEY_LOCATION "" +#define CONFIG_SSL_PRIVATE_KEY_PASSWORD "" +#define CONFIG_SSL_X509_CERT_LOCATION "" +#undef CONFIG_SSL_GENERATE_X509_CERT +#define CONFIG_SSL_X509_COMMON_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME "" +#undef CONFIG_SSL_HAS_PEM +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME +#define CONFIG_X509_MAX_CA_CERTS 0 +#define CONFIG_SSL_MAX_CERTS 3 +#undef CONFIG_SSL_CTX_MUTEXING +#undef CONFIG_USE_DEV_URANDOM +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#undef CONFIG_SSL_TEST +#undef CONFIG_AXTLSWRAP +#undef CONFIG_AXHTTPD +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_PORT +#define CONFIG_HTTP_HTTPS_PORT +#define CONFIG_HTTP_SESSION_CACHE_SIZE +#define CONFIG_HTTP_WEBROOT "" +#define CONFIG_HTTP_TIMEOUT +#undef CONFIG_HTTP_HAS_CGI +#define CONFIG_HTTP_CGI_EXTENSIONS "" +#undef CONFIG_HTTP_ENABLE_LUA +#define CONFIG_HTTP_LUA_PREFIX "" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_CGI_LAUNCHER "" +#undef CONFIG_HTTP_DIRECTORIES +#undef CONFIG_HTTP_HAS_AUTHORIZATION +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#undef CONFIG_HTTP_VERBOSE +#undef CONFIG_HTTP_IS_DAEMON + +/* + * Language Bindings + */ +#undef CONFIG_BINDINGS +#undef CONFIG_CSHARP_BINDINGS +#undef CONFIG_VBNET_BINDINGS +#define CONFIG_DOT_NET_FRAMEWORK_BASE "" +#undef CONFIG_JAVA_BINDINGS +#define CONFIG_JAVA_HOME "" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" +#undef CONFIG_LUA_BINDINGS +#define CONFIG_LUA_CORE "" + +/* + * Samples + */ +#undef CONFIG_SAMPLES +#undef CONFIG_C_SAMPLES +#undef CONFIG_CSHARP_SAMPLES +#undef CONFIG_VBNET_SAMPLES +#undef CONFIG_JAVA_SAMPLES +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_LUA_SAMPLES +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#undef CONFIG_BIGINT_BARRETT +#undef CONFIG_BIGINT_CRT +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#undef CONFIG_BIGINT_SLIDING_WINDOW +#undef CONFIG_BIGINT_SQUARE +#undef CONFIG_BIGINT_CHECK_ON +#undef CONFIG_INTEGER_32BIT +#undef CONFIG_INTEGER_16BIT +#undef CONFIG_INTEGER_8BIT diff --git a/src/openmv/src/micropython/extmod/axtls-include/version.h b/src/openmv/src/micropython/extmod/axtls-include/version.h new file mode 100755 index 0000000..df2260e --- /dev/null +++ b/src/openmv/src/micropython/extmod/axtls-include/version.h @@ -0,0 +1 @@ +#define AXTLS_VERSION "(no version)" diff --git a/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.c b/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.c new file mode 100755 index 0000000..276611c --- /dev/null +++ b/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.c @@ -0,0 +1,157 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include "sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +static void sha256_transform(CRYAL_SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(CRYAL_SHA256_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(CRYAL_SHA256_CTX *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(CRYAL_SHA256_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} diff --git a/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.h b/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.h new file mode 100755 index 0000000..caa1f81 --- /dev/null +++ b/src/openmv/src/micropython/extmod/crypto-algorithms/sha256.h @@ -0,0 +1,34 @@ +/********************************************************************* +* Filename: sha256.h +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA1 implementation. +*********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} CRYAL_SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(CRYAL_SHA256_CTX *ctx); +void sha256_update(CRYAL_SHA256_CTX *ctx, const BYTE data[], size_t len); +void sha256_final(CRYAL_SHA256_CTX *ctx, BYTE hash[]); + +#endif // SHA256_H diff --git a/src/openmv/src/micropython/extmod/lwip-include/arch/cc.h b/src/openmv/src/micropython/extmod/lwip-include/arch/cc.h new file mode 100755 index 0000000..400dc6e --- /dev/null +++ b/src/openmv/src/micropython/extmod/lwip-include/arch/cc.h @@ -0,0 +1,41 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H +#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H + +#include + +// Generate lwip's internal types from stdint + +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; + +typedef u32_t mem_ptr_t; + +#define U16_F "hu" +#define S16_F "hd" +#define X16_F "hx" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" + +#define X8_F "02x" +#define SZT_F "u" + +#define BYTE_ORDER LITTLE_ENDIAN + +#define LWIP_CHKSUM_ALGORITHM 2 + +#include +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) { assert(1); } + +//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H diff --git a/src/openmv/src/micropython/extmod/lwip-include/arch/perf.h b/src/openmv/src/micropython/extmod/lwip-include/arch/perf.h new file mode 100755 index 0000000..d310fc3 --- /dev/null +++ b/src/openmv/src/micropython/extmod/lwip-include/arch/perf.h @@ -0,0 +1,7 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H +#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H diff --git a/src/openmv/src/micropython/extmod/lwip-include/lwipopts.h b/src/openmv/src/micropython/extmod/lwip-include/lwipopts.h new file mode 100755 index 0000000..2122f30 --- /dev/null +++ b/src/openmv/src/micropython/extmod/lwip-include/lwipopts.h @@ -0,0 +1,35 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H +#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H + +#include +#include +#include + +// We're running without an OS for this port. We don't provide any services except light protection. +#define NO_SYS 1 + +#define SYS_LIGHTWEIGHT_PROT 1 +#include +typedef uint32_t sys_prot_t; + +#define TCP_LISTEN_BACKLOG 1 + +// We'll put these into a proper ifdef once somebody implements an ethernet driver +#define LWIP_ARP 0 +#define LWIP_ETHERNET 0 + +#define LWIP_DNS 1 + +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 + +#ifdef MICROPY_PY_LWIP_SLIP +#define LWIP_HAVE_SLIPIF 1 +#endif + +// For now, we can simply define this as a macro for the timer code. But this function isn't +// universal and other ports will need to do something else. It may be necessary to move +// things like this into a port-provided header file. +#define sys_now mp_hal_ticks_ms + +#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H diff --git a/src/openmv/src/micropython/extmod/machine_i2c.c b/src/openmv/src/micropython/extmod/machine_i2c.c new file mode 100755 index 0000000..c1a93ab --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_i2c.c @@ -0,0 +1,640 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "extmod/machine_i2c.h" + +#if MICROPY_PY_MACHINE_I2C + +typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t; + +STATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) { + // We need to use an accurate delay to get acceptable I2C + // speeds (eg 1us should be not much more than 1us). + mp_hal_delay_us_fast(self->us_delay); +} + +STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) { + mp_hal_pin_od_low(self->scl); +} + +STATIC int mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { + uint32_t count = self->us_timeout; + + mp_hal_pin_od_high(self->scl); + mp_hal_i2c_delay(self); + // For clock stretching, wait for the SCL pin to be released, with timeout. + for (; mp_hal_pin_read(self->scl) == 0 && count; --count) { + mp_hal_delay_us_fast(1); + } + if (count == 0) { + return -MP_ETIMEDOUT; + } + return 0; // success +} + +STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) { + mp_hal_pin_od_low(self->sda); +} + +STATIC void mp_hal_i2c_sda_release(machine_i2c_obj_t *self) { + mp_hal_pin_od_high(self->sda); +} + +STATIC int mp_hal_i2c_sda_read(machine_i2c_obj_t *self) { + return mp_hal_pin_read(self->sda); +} + +STATIC int mp_hal_i2c_start(machine_i2c_obj_t *self) { + mp_hal_i2c_sda_release(self); + mp_hal_i2c_delay(self); + int ret = mp_hal_i2c_scl_release(self); + if (ret != 0) { + return ret; + } + mp_hal_i2c_sda_low(self); + mp_hal_i2c_delay(self); + return 0; // success +} + +STATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) { + mp_hal_i2c_delay(self); + mp_hal_i2c_sda_low(self); + mp_hal_i2c_delay(self); + int ret = mp_hal_i2c_scl_release(self); + mp_hal_i2c_sda_release(self); + mp_hal_i2c_delay(self); + return ret; +} + +STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) { + self->us_delay = 500000 / freq; + if (self->us_delay == 0) { + self->us_delay = 1; + } + mp_hal_pin_open_drain(self->scl); + mp_hal_pin_open_drain(self->sda); + mp_hal_i2c_stop(self); // ignore error +} + +// return value: +// 0 - byte written and ack received +// 1 - byte written and nack received +// <0 - error, with errno being the negative of the return value +STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) { + mp_hal_i2c_delay(self); + mp_hal_i2c_scl_low(self); + + for (int i = 7; i >= 0; i--) { + if ((val >> i) & 1) { + mp_hal_i2c_sda_release(self); + } else { + mp_hal_i2c_sda_low(self); + } + mp_hal_i2c_delay(self); + int ret = mp_hal_i2c_scl_release(self); + if (ret != 0) { + mp_hal_i2c_sda_release(self); + return ret; + } + mp_hal_i2c_scl_low(self); + } + + mp_hal_i2c_sda_release(self); + mp_hal_i2c_delay(self); + int ret = mp_hal_i2c_scl_release(self); + if (ret != 0) { + return ret; + } + + int ack = mp_hal_i2c_sda_read(self); + mp_hal_i2c_delay(self); + mp_hal_i2c_scl_low(self); + + return ack; +} + +// return value: +// 0 - success +// <0 - error, with errno being the negative of the return value +STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) { + mp_hal_i2c_delay(self); + mp_hal_i2c_scl_low(self); + mp_hal_i2c_delay(self); + + uint8_t data = 0; + for (int i = 7; i >= 0; i--) { + int ret = mp_hal_i2c_scl_release(self); + if (ret != 0) { + return ret; + } + data = (data << 1) | mp_hal_i2c_sda_read(self); + mp_hal_i2c_scl_low(self); + mp_hal_i2c_delay(self); + } + *val = data; + + // send ack/nack bit + if (!nack) { + mp_hal_i2c_sda_low(self); + } + mp_hal_i2c_delay(self); + int ret = mp_hal_i2c_scl_release(self); + if (ret != 0) { + mp_hal_i2c_sda_release(self); + return ret; + } + mp_hal_i2c_scl_low(self); + mp_hal_i2c_sda_release(self); + + return 0; // success +} + +// return value: +// >=0 - number of acks received +// <0 - error, with errno being the negative of the return value +int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; + + // start the I2C transaction + int ret = mp_hal_i2c_start(self); + if (ret != 0) { + return ret; + } + + // write the slave address + ret = mp_hal_i2c_write_byte(self, addr << 1); + if (ret < 0) { + return ret; + } else if (ret != 0) { + // nack received, release the bus cleanly + mp_hal_i2c_stop(self); + return -MP_ENODEV; + } + + // write the buffer to the I2C memory + int num_acks = 0; + while (len--) { + ret = mp_hal_i2c_write_byte(self, *src++); + if (ret < 0) { + return ret; + } else if (ret != 0) { + // nack received, stop sending + break; + } + ++num_acks; + } + + // finish the I2C transaction + if (stop) { + ret = mp_hal_i2c_stop(self); + if (ret != 0) { + return ret; + } + } + + return num_acks; +} + +// return value: +// 0 - success +// <0 - error, with errno being the negative of the return value +int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; + + // start the I2C transaction + int ret = mp_hal_i2c_start(self); + if (ret != 0) { + return ret; + } + + // write the slave address + ret = mp_hal_i2c_write_byte(self, (addr << 1) | 1); + if (ret < 0) { + return ret; + } else if (ret != 0) { + // nack received, release the bus cleanly + mp_hal_i2c_stop(self); + return -MP_ENODEV; + } + + // read the bytes from the slave + while (len--) { + ret = mp_hal_i2c_read_byte(self, dest++, len == 0); + if (ret != 0) { + return ret; + } + } + + // finish the I2C transaction + if (stop) { + ret = mp_hal_i2c_stop(self); + if (ret != 0) { + return ret; + } + } + + return 0; // success +} + +/******************************************************************************/ +// MicroPython bindings for I2C + +STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj); + self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj); + self->us_timeout = args[ARG_timeout].u_int; + mp_hal_i2c_init(self, args[ARG_freq].u_int); +} + +STATIC mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check the id argument, if given + if (n_args > 0) { + if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) { + #if defined(MICROPY_PY_MACHINE_I2C_MAKE_NEW) + // dispatch to port-specific constructor + extern mp_obj_t MICROPY_PY_MACHINE_I2C_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); + return MICROPY_PY_MACHINE_I2C_MAKE_NEW(type, n_args, n_kw, args); + #else + mp_raise_ValueError("invalid I2C peripheral"); + #endif + } + --n_args; + ++args; + } + + // create new soft I2C object + machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t); + self->base.type = &machine_i2c_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_i2c_obj_init_helper(self, n_args, args, &kw_args); + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_i2c_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_i2c_obj_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init); + +STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { + mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_obj_t list = mp_obj_new_list(0, NULL); + // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved + for (int addr = 0x08; addr < 0x78; ++addr) { + int ret = i2c_p->writeto(self, addr, NULL, 0, true); + if (ret == 0) { + mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); + } + } + return list; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_scan_obj, machine_i2c_scan); + +STATIC mp_obj_t machine_i2c_start(mp_obj_t self_in) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + if (i2c_p->start == NULL) { + mp_raise_msg(&mp_type_OSError, "I2C operation not supported"); + } + int ret = i2c_p->start(self); + if (ret != 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_start_obj, machine_i2c_start); + +STATIC mp_obj_t machine_i2c_stop(mp_obj_t self_in) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + if (i2c_p->stop == NULL) { + mp_raise_msg(&mp_type_OSError, "I2C operation not supported"); + } + int ret = i2c_p->stop(self); + if (ret != 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_stop_obj, machine_i2c_stop); + +STATIC mp_obj_t machine_i2c_readinto(size_t n_args, const mp_obj_t *args) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + if (i2c_p->read == NULL) { + mp_raise_msg(&mp_type_OSError, "I2C operation not supported"); + } + + // get the buffer to read into + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + + // work out if we want to send a nack at the end + bool nack = (n_args == 2) ? true : mp_obj_is_true(args[2]); + + // do the read + int ret = i2c_p->read(self, bufinfo.buf, bufinfo.len, nack); + if (ret != 0) { + mp_raise_OSError(-ret); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readinto_obj, 2, 3, machine_i2c_readinto); + +STATIC mp_obj_t machine_i2c_write(mp_obj_t self_in, mp_obj_t buf_in) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + if (i2c_p->write == NULL) { + mp_raise_msg(&mp_type_OSError, "I2C operation not supported"); + } + + // get the buffer to write from + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + // do the write + int ret = i2c_p->write(self, bufinfo.buf, bufinfo.len); + if (ret < 0) { + mp_raise_OSError(-ret); + } + + // return number of acks received + return MP_OBJ_NEW_SMALL_INT(ret); +} +MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write); + +STATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_int_t addr = mp_obj_get_int(args[1]); + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[2])); + bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); + int ret = i2c_p->readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_readfrom); + +STATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_int_t addr = mp_obj_get_int(args[1]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE); + bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); + int ret = i2c_p->readfrom(self, addr, bufinfo.buf, bufinfo.len, stop); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine_i2c_readfrom_into); + +STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + mp_int_t addr = mp_obj_get_int(args[1]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]); + int ret = i2c_p->writeto(self, addr, bufinfo.buf, bufinfo.len, stop); + if (ret < 0) { + mp_raise_OSError(-ret); + } + // return number of acks received + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto); + +STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + uint8_t memaddr_buf[4]; + size_t memaddr_len = 0; + for (int16_t i = addrsize - 8; i >= 0; i -= 8) { + memaddr_buf[memaddr_len++] = memaddr >> i; + } + int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false); + if (ret != memaddr_len) { + // must generate STOP + i2c_p->writeto(self, addr, NULL, 0, true); + return ret; + } + return i2c_p->readfrom(self, addr, buf, len, true); +} + +#define MAX_MEMADDR_SIZE (4) +#define BUF_STACK_SIZE (12) + +STATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) { + mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol; + + // need some memory to create the buffer to send; try to use stack if possible + uint8_t buf2_stack[MAX_MEMADDR_SIZE + BUF_STACK_SIZE]; + uint8_t *buf2; + size_t buf2_alloc = 0; + if (len <= BUF_STACK_SIZE) { + buf2 = buf2_stack; + } else { + buf2_alloc = MAX_MEMADDR_SIZE + len; + buf2 = m_new(uint8_t, buf2_alloc); + } + + // create the buffer to send + size_t memaddr_len = 0; + for (int16_t i = addrsize - 8; i >= 0; i -= 8) { + buf2[memaddr_len++] = memaddr >> i; + } + memcpy(buf2 + memaddr_len, buf, len); + + int ret = i2c_p->writeto(self, addr, buf2, memaddr_len + len, true); + if (buf2_alloc != 0) { + m_del(uint8_t, buf2, buf2_alloc); + } + return ret; +} + +STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_arg, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, +}; + +STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize }; + mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args); + + // create the buffer to store data into + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj)); + + // do the transfer + int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len); + if (ret < 0) { + mp_raise_OSError(-ret); + } + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem); + + +STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize }; + mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args); + + // get the buffer to store data into + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE); + + // do the transfer + int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); + if (ret < 0) { + mp_raise_OSError(-ret); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into); + +STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize }; + mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args); + + // get the buffer to write the data from + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ); + + // do the transfer + int ret = write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); + if (ret < 0) { + mp_raise_OSError(-ret); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem); + +STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) }, + + // primitive I2C operations + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_i2c_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_i2c_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_write_obj) }, + + // standard bus operations + { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) }, + + // memory operations + { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&machine_i2c_readfrom_mem_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) }, +}; + +MP_DEFINE_CONST_DICT(mp_machine_soft_i2c_locals_dict, machine_i2c_locals_dict_table); + +int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len, bool nack) { + machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; + while (len--) { + int ret = mp_hal_i2c_read_byte(self, dest++, nack && (len == 0)); + if (ret != 0) { + return ret; + } + } + return 0; // success +} + +int mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t len) { + machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in; + int num_acks = 0; + while (len--) { + int ret = mp_hal_i2c_write_byte(self, *src++); + if (ret < 0) { + return ret; + } else if (ret != 0) { + // nack received, stop sending + break; + } + ++num_acks; + } + return num_acks; +} + +STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = { + .start = (int(*)(mp_obj_base_t*))mp_hal_i2c_start, + .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop, + .read = mp_machine_soft_i2c_read, + .write = mp_machine_soft_i2c_write, + .readfrom = mp_machine_soft_i2c_readfrom, + .writeto = mp_machine_soft_i2c_writeto, +}; + +const mp_obj_type_t machine_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .make_new = machine_i2c_make_new, + .protocol = &mp_machine_soft_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_I2C diff --git a/src/openmv/src/micropython/extmod/machine_i2c.h b/src/openmv/src/micropython/extmod/machine_i2c.h new file mode 100755 index 0000000..f5af665 --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_i2c.h @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H + +#include "py/obj.h" + +// I2C protocol +// the first 4 methods can be NULL, meaning operation is not supported +typedef struct _mp_machine_i2c_p_t { + int (*start)(mp_obj_base_t *obj); + int (*stop)(mp_obj_base_t *obj); + int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack); + int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len); + int (*readfrom)(mp_obj_base_t *obj, uint16_t addr, uint8_t *dest, size_t len, bool stop); + int (*writeto)(mp_obj_base_t *obj, uint16_t addr, const uint8_t *src, size_t len, bool stop); +} mp_machine_i2c_p_t; + +typedef struct _mp_machine_soft_i2c_obj_t { + mp_obj_base_t base; + uint32_t us_delay; + uint32_t us_timeout; + mp_hal_pin_obj_t scl; + mp_hal_pin_obj_t sda; +} mp_machine_soft_i2c_obj_t; + +extern const mp_obj_type_t machine_i2c_type; +extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict; + +int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop); +int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop); + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H diff --git a/src/openmv/src/micropython/extmod/machine_mem.c b/src/openmv/src/micropython/extmod/machine_mem.c new file mode 100755 index 0000000..b9f1650 --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_mem.c @@ -0,0 +1,103 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "extmod/machine_mem.h" + +#if MICROPY_PY_MACHINE + +// If you wish to override the functions for mapping the machine_mem read/write +// address, then add a #define for MICROPY_MACHINE_MEM_GET_READ_ADDR and/or +// MICROPY_MACHINE_MEM_GET_WRITE_ADDR in your mpconfigport.h. Since the +// prototypes are identical, it is allowable for both of the macros to evaluate +// the to same function. +// +// It is expected that the modmachine.c file for a given port will provide the +// implementations, if the default implementation isn't used. + +#if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) || !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) +STATIC uintptr_t machine_mem_get_addr(mp_obj_t addr_o, uint align) { + uintptr_t addr = mp_obj_int_get_truncated(addr_o); + if ((addr & (align - 1)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + } + return addr; +} +#if !defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) +#define MICROPY_MACHINE_MEM_GET_READ_ADDR machine_mem_get_addr +#endif +#if !defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) +#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR machine_mem_get_addr +#endif +#endif + +STATIC void machine_mem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<%u-bit memory>", 8 * self->elem_size); +} + +STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + // TODO support slice index to read/write multiple values at once + machine_mem_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (value == MP_OBJ_NULL) { + // delete + return MP_OBJ_NULL; // op not supported + } else if (value == MP_OBJ_SENTINEL) { + // load + uintptr_t addr = MICROPY_MACHINE_MEM_GET_READ_ADDR(index, self->elem_size); + uint32_t val; + switch (self->elem_size) { + case 1: val = (*(uint8_t*)addr); break; + case 2: val = (*(uint16_t*)addr); break; + default: val = (*(uint32_t*)addr); break; + } + return mp_obj_new_int(val); + } else { + // store + uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size); + uint32_t val = mp_obj_get_int_truncated(value); + switch (self->elem_size) { + case 1: (*(uint8_t*)addr) = val; break; + case 2: (*(uint16_t*)addr) = val; break; + default: (*(uint32_t*)addr) = val; break; + } + return mp_const_none; + } +} + +const mp_obj_type_t machine_mem_type = { + { &mp_type_type }, + .name = MP_QSTR_mem, + .print = machine_mem_print, + .subscr = machine_mem_subscr, +}; + +const machine_mem_obj_t machine_mem8_obj = {{&machine_mem_type}, 1}; +const machine_mem_obj_t machine_mem16_obj = {{&machine_mem_type}, 2}; +const machine_mem_obj_t machine_mem32_obj = {{&machine_mem_type}, 4}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/extmod/machine_mem.h b/src/openmv/src/micropython/extmod/machine_mem.h new file mode 100755 index 0000000..a48a52c --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_mem.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H + +#include "py/obj.h" + +typedef struct _machine_mem_obj_t { + mp_obj_base_t base; + unsigned elem_size; // in bytes +} machine_mem_obj_t; + +extern const mp_obj_type_t machine_mem_type; + +extern const machine_mem_obj_t machine_mem8_obj; +extern const machine_mem_obj_t machine_mem16_obj; +extern const machine_mem_obj_t machine_mem32_obj; + +#if defined(MICROPY_MACHINE_MEM_GET_READ_ADDR) +uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align); +#endif +#if defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR) +uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align); +#endif + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H diff --git a/src/openmv/src/micropython/extmod/machine_pinbase.c b/src/openmv/src/micropython/extmod/machine_pinbase.c new file mode 100755 index 0000000..070c5cd --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_pinbase.c @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_MACHINE + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/virtpin.h" +#include "extmod/machine_pinbase.h" + +// PinBase class + +// As this is abstract class, its instance is null. +// But there should be an instance, as the rest of instance code +// expects that there will be concrete object for inheritance. +typedef struct _mp_pinbase_t { + mp_obj_base_t base; +} mp_pinbase_t; + +STATIC const mp_pinbase_t pinbase_singleton = { + .base = { &machine_pinbase_type }, +}; + +STATIC mp_obj_t pinbase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)args; + return MP_OBJ_FROM_PTR(&pinbase_singleton); +} + +mp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); +mp_uint_t pinbase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + switch (request) { + case MP_PIN_READ: { + mp_obj_t dest[2]; + mp_load_method(obj, MP_QSTR_value, dest); + return mp_obj_get_int(mp_call_method_n_kw(0, 0, dest)); + } + case MP_PIN_WRITE: { + mp_obj_t dest[3]; + mp_load_method(obj, MP_QSTR_value, dest); + dest[2] = (arg == 0 ? mp_const_false : mp_const_true); + mp_call_method_n_kw(1, 0, dest); + return 0; + } + } + return -1; +} + +STATIC const mp_pin_p_t pinbase_pin_p = { + .ioctl = pinbase_ioctl, +}; + +const mp_obj_type_t machine_pinbase_type = { + { &mp_type_type }, + .name = MP_QSTR_PinBase, + .make_new = pinbase_make_new, + .protocol = &pinbase_pin_p, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/extmod/machine_pinbase.h b/src/openmv/src/micropython/extmod/machine_pinbase.h new file mode 100755 index 0000000..c96abbc --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_pinbase.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pinbase_type; + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H diff --git a/src/openmv/src/micropython/extmod/machine_pulse.c b/src/openmv/src/micropython/extmod/machine_pulse.c new file mode 100755 index 0000000..5f83747 --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_pulse.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/machine_pulse.h" + +#if MICROPY_PY_MACHINE_PULSE + +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { + mp_uint_t start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) != pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-2; + } + } + start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) == pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-1; + } + } + return mp_hal_ticks_us() - start; +} + +STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]); + int level = 0; + if (mp_obj_is_true(args[1])) { + level = 1; + } + mp_uint_t timeout_us = 1000000; + if (n_args > 2) { + timeout_us = mp_obj_get_int(args[2]); + } + mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); + // May return -1 or -2 in case of timeout + return mp_obj_new_int(us); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); + +#endif diff --git a/src/openmv/src/micropython/extmod/machine_pulse.h b/src/openmv/src/micropython/extmod/machine_pulse.h new file mode 100755 index 0000000..e303dca --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_pulse.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H + +#include "py/obj.h" +#include "py/mphal.h" + +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H diff --git a/src/openmv/src/micropython/extmod/machine_signal.c b/src/openmv/src/micropython/extmod/machine_signal.c new file mode 100755 index 0000000..3f9f5af --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_signal.c @@ -0,0 +1,185 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_MACHINE + +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/virtpin.h" +#include "extmod/machine_signal.h" + +// Signal class + +typedef struct _machine_signal_t { + mp_obj_base_t base; + mp_obj_t pin; + bool invert; +} machine_signal_t; + +STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_t pin = args[0]; + bool invert = false; + + #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW) + mp_pin_p_t *pin_p = NULL; + + if (MP_OBJ_IS_OBJ(pin)) { + mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + pin_p = (mp_pin_p_t*)pin_base->type->protocol; + } + + if (pin_p == NULL) { + // If first argument isn't a Pin-like object, we filter out "invert" + // from keyword arguments and pass them all to the exported Pin + // constructor to create one. + mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t)); + memcpy(pin_args, args, n_args * sizeof(mp_obj_t)); + const mp_obj_t *src = args + n_args; + mp_obj_t *dst = pin_args + n_args; + mp_obj_t *sig_value = NULL; + for (size_t cnt = n_kw; cnt; cnt--) { + if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) { + invert = mp_obj_is_true(src[1]); + n_kw--; + } else { + *dst++ = *src; + *dst++ = src[1]; + } + if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) { + // Value is pertained to Signal, so we should invert + // it for Pin if needed, and we should do it only when + // inversion status is guaranteedly known. + sig_value = dst - 1; + } + src += 2; + } + + if (invert && sig_value != NULL) { + *sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1); + } + + // Here we pass NULL as a type, hoping that mp_pin_make_new() + // will just ignore it as set a concrete type. If not, we'd need + // to expose port's "default" pin type too. + pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args); + + mp_local_free(pin_args); + } + else + #endif + // Otherwise there should be 1 or 2 args + { + if (n_args == 1) { + if (n_kw == 0) { + } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) { + invert = mp_obj_is_true(args[2]); + } else { + goto error; + } + } else { + error: + mp_raise_TypeError(NULL); + } + } + + machine_signal_t *o = m_new_obj(machine_signal_t); + o->base.type = type; + o->pin = pin; + o->invert = invert; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_signal_t *self = MP_OBJ_TO_PTR(self_in); + + switch (request) { + case MP_PIN_READ: { + return mp_virtual_pin_read(self->pin) ^ self->invert; + } + case MP_PIN_WRITE: { + mp_virtual_pin_write(self->pin, arg ^ self->invert); + return 0; + } + } + return -1; +} + +// fast method for getting/setting signal value +STATIC mp_obj_t signal_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(mp_virtual_pin_read(self_in)); + } else { + // set pin + mp_virtual_pin_write(self_in, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +STATIC mp_obj_t signal_value(size_t n_args, const mp_obj_t *args) { + return signal_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_value_obj, 1, 2, signal_value); + +STATIC mp_obj_t signal_on(mp_obj_t self_in) { + mp_virtual_pin_write(self_in, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_on_obj, signal_on); + +STATIC mp_obj_t signal_off(mp_obj_t self_in) { + mp_virtual_pin_write(self_in, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(signal_off_obj, signal_off); + +STATIC const mp_rom_map_elem_t signal_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&signal_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&signal_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&signal_off_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(signal_locals_dict, signal_locals_dict_table); + +STATIC const mp_pin_p_t signal_pin_p = { + .ioctl = signal_ioctl, +}; + +const mp_obj_type_t machine_signal_type = { + { &mp_type_type }, + .name = MP_QSTR_Signal, + .make_new = signal_make_new, + .call = signal_call, + .protocol = &signal_pin_p, + .locals_dict = (void*)&signal_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/extmod/machine_signal.h b/src/openmv/src/micropython/extmod/machine_signal.h new file mode 100755 index 0000000..df1c3e2 --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_signal.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_signal_type; + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H diff --git a/src/openmv/src/micropython/extmod/machine_spi.c b/src/openmv/src/micropython/extmod/machine_spi.c new file mode 100755 index 0000000..f0c4896 --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_spi.c @@ -0,0 +1,283 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "extmod/machine_spi.h" + +#if MICROPY_PY_MACHINE_SPI + +// if a port didn't define MSB/LSB constants then provide them +#ifndef MICROPY_PY_MACHINE_SPI_MSB +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (1) +#endif + +/******************************************************************************/ +// MicroPython bindings for generic machine.SPI + +STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); + +mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check the id argument, if given + if (n_args > 0) { + if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) { + #if defined(MICROPY_PY_MACHINE_SPI_MAKE_NEW) + // dispatch to port-specific constructor + extern mp_obj_t MICROPY_PY_MACHINE_SPI_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); + return MICROPY_PY_MACHINE_SPI_MAKE_NEW(type, n_args, n_kw, args); + #else + mp_raise_ValueError("invalid SPI peripheral"); + #endif + } + --n_args; + ++args; + } + + // software SPI + return mp_machine_soft_spi_make_new(type, n_args, n_kw, args); +} + +STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol; + spi_p->init(s, n_args - 1, args + 1, kw_args); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init); + +STATIC mp_obj_t machine_spi_deinit(mp_obj_t self) { + mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol; + if (spi_p->deinit != NULL) { + spi_p->deinit(s); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit); + +STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest) { + mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol; + spi_p->transfer(s, len, src, dest); +} + +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len); + mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len); + mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + mp_raise_ValueError("buffers must be the same length"); + } + mp_machine_spi_transfer(self, src.len, src.buf, dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + +STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, + + { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) }, + { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) }, +}; + +MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table); + +/******************************************************************************/ +// Implementation of soft SPI + +STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + return MICROPY_HW_SOFTSPI_MAX_BAUDRATE; + } else + #endif + { + return 500000 / delay_half; + } +} + +STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) { + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) { + return MICROPY_HW_SOFTSPI_MIN_DELAY; + } else + #endif + { + uint32_t delay_half = 500000 / baudrate; + // round delay_half up so that: actual_baudrate <= requested_baudrate + if (500000 % baudrate != 0) { + delay_half += 1; + } + return delay_half; + } +} + +STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u," + " sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")", + baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase, + mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso)); +} + +STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // create new object + mp_machine_soft_spi_obj_t *self = m_new_obj(mp_machine_soft_spi_obj_t); + self->base.type = &mp_machine_soft_spi_type; + + // set parameters + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.polarity = args[ARG_polarity].u_int; + self->spi.phase = args[ARG_phase].u_int; + if (args[ARG_bits].u_int != 8) { + mp_raise_ValueError("bits must be 8"); + } + if (args[ARG_firstbit].u_int != MICROPY_PY_MACHINE_SPI_MSB) { + mp_raise_ValueError("firstbit must be MSB"); + } + if (args[ARG_sck].u_obj == MP_OBJ_NULL + || args[ARG_mosi].u_obj == MP_OBJ_NULL + || args[ARG_miso].u_obj == MP_OBJ_NULL) { + mp_raise_ValueError("must specify all of sck/mosi/miso"); + } + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; + + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_baudrate].u_int != -1) { + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + } + if (args[ARG_polarity].u_int != -1) { + self->spi.polarity = args[ARG_polarity].u_int; + } + if (args[ARG_phase].u_int != -1) { + self->spi.phase = args[ARG_phase].u_int; + } + if (args[ARG_sck].u_obj != MP_OBJ_NULL) { + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + } + if (args[ARG_mosi].u_obj != MP_OBJ_NULL) { + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + } + if (args[ARG_miso].u_obj != MP_OBJ_NULL) { + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + } + + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); +} + +STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; + mp_soft_spi_transfer(&self->spi, len, src, dest); +} + +const mp_machine_spi_p_t mp_machine_soft_spi_p = { + .init = mp_machine_soft_spi_init, + .deinit = NULL, + .transfer = mp_machine_soft_spi_transfer, +}; + +const mp_obj_type_t mp_machine_soft_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SoftSPI, + .print = mp_machine_soft_spi_print, + .make_new = mp_machine_spi_make_new, // delegate to master constructor + .protocol = &mp_machine_soft_spi_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/src/openmv/src/micropython/extmod/machine_spi.h b/src/openmv/src/micropython/extmod/machine_spi.h new file mode 100755 index 0000000..db21e1c --- /dev/null +++ b/src/openmv/src/micropython/extmod/machine_spi.h @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H + +#include "py/obj.h" +#include "py/mphal.h" +#include "drivers/bus/spi.h" + +// SPI protocol +typedef struct _mp_machine_spi_p_t { + void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + void (*deinit)(mp_obj_base_t *obj); // can be NULL + void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest); +} mp_machine_spi_p_t; + +typedef struct _mp_machine_soft_spi_obj_t { + mp_obj_base_t base; + mp_soft_spi_obj_t spi; +} mp_machine_soft_spi_obj_t; + +extern const mp_machine_spi_p_t mp_machine_soft_spi_p; +extern const mp_obj_type_t mp_machine_soft_spi_type; +extern const mp_obj_dict_t mp_machine_spi_locals_dict; + +mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H diff --git a/src/openmv/src/micropython/extmod/misc.h b/src/openmv/src/micropython/extmod/misc.h new file mode 100755 index 0000000..d6f6d85 --- /dev/null +++ b/src/openmv/src/micropython/extmod/misc.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MISC_H +#define MICROPY_INCLUDED_EXTMOD_MISC_H + +// This file contains cumulative declarations for extmod/ . + +#include +#include "py/runtime.h" + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); + +#if MICROPY_PY_OS_DUPTERM +int mp_uos_dupterm_rx_chr(void); +void mp_uos_dupterm_tx_strn(const char *str, size_t len); +void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); +#else +#define mp_uos_dupterm_tx_strn(s, l) +#endif + +#endif // MICROPY_INCLUDED_EXTMOD_MISC_H diff --git a/src/openmv/src/micropython/extmod/modbtree.c b/src/openmv/src/micropython/extmod/modbtree.c new file mode 100755 index 0000000..a2bff06 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modbtree.c @@ -0,0 +1,377 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include // for declaration of global errno variable +#include + +#include "py/runtime.h" +#include "py/stream.h" + +#if MICROPY_PY_BTREE + +#include +#include <../../btree/btree.h> + +typedef struct _mp_obj_btree_t { + mp_obj_base_t base; + DB *db; + mp_obj_t start_key; + mp_obj_t end_key; + #define FLAG_END_KEY_INCL 1 + #define FLAG_DESC 2 + #define FLAG_ITER_TYPE_MASK 0xc0 + #define FLAG_ITER_KEYS 0x40 + #define FLAG_ITER_VALUES 0x80 + #define FLAG_ITER_ITEMS 0xc0 + byte flags; + byte next_flags; +} mp_obj_btree_t; + +STATIC const mp_obj_type_t btree_type; + +#define CHECK_ERROR(res) \ + if (res == RET_ERROR) { \ + mp_raise_OSError(errno); \ + } + +void __dbpanic(DB *db) { + printf("__dbpanic(%p)\n", db); +} + +STATIC mp_obj_btree_t *btree_new(DB *db) { + mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t); + o->base.type = &btree_type; + o->db = db; + o->start_key = mp_const_none; + o->end_key = mp_const_none; + o->next_flags = 0; + return o; +} + +STATIC void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->db); +} + +STATIC mp_obj_t btree_flush(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(__bt_sync(self->db, 0)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_flush_obj, btree_flush); + +STATIC mp_obj_t btree_close(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_close_obj, btree_close); + +STATIC mp_obj_t btree_put(size_t n_args, const mp_obj_t *args) { + (void)n_args; + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + DBT key, val; + key.data = (void*)mp_obj_str_get_data(args[1], &key.size); + val.data = (void*)mp_obj_str_get_data(args[2], &val.size); + return MP_OBJ_NEW_SMALL_INT(__bt_put(self->db, &key, &val, 0)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_put_obj, 3, 4, btree_put); + +STATIC mp_obj_t btree_get(size_t n_args, const mp_obj_t *args) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + DBT key, val; + key.data = (void*)mp_obj_str_get_data(args[1], &key.size); + int res = __bt_get(self->db, &key, &val, 0); + if (res == RET_SPECIAL) { + if (n_args > 2) { + return args[2]; + } else { + return mp_const_none; + } + } + CHECK_ERROR(res); + return mp_obj_new_bytes(val.data, val.size); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_get_obj, 2, 3, btree_get); + +STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + int flags = MP_OBJ_SMALL_INT_VALUE(args[1]); + DBT key, val; + if (n_args > 2) { + key.data = (void*)mp_obj_str_get_data(args[2], &key.size); + } + + int res = __bt_seq(self->db, &key, &val, flags); + CHECK_ERROR(res); + if (res == RET_SPECIAL) { + return mp_const_none; + } + + mp_obj_t pair_o = mp_obj_new_tuple(2, NULL); + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o); + pair->items[0] = mp_obj_new_bytes(key.data, key.size); + pair->items[1] = mp_obj_new_bytes(val.data, val.size); + return pair_o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_seq_obj, 2, 4, btree_seq); + +STATIC mp_obj_t btree_init_iter(size_t n_args, const mp_obj_t *args, byte type) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]); + self->next_flags = type; + self->start_key = mp_const_none; + self->end_key = mp_const_none; + if (n_args > 1) { + self->start_key = args[1]; + if (n_args > 2) { + self->end_key = args[2]; + if (n_args > 3) { + self->next_flags = type | MP_OBJ_SMALL_INT_VALUE(args[3]); + } + } + } + return args[0]; +} + +STATIC mp_obj_t btree_keys(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_KEYS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_keys_obj, 1, 4, btree_keys); + +STATIC mp_obj_t btree_values(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_VALUES); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_values_obj, 1, 4, btree_values); + +STATIC mp_obj_t btree_items(size_t n_args, const mp_obj_t *args) { + return btree_init_iter(n_args, args, FLAG_ITER_ITEMS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_items_obj, 1, 4, btree_items); + +STATIC mp_obj_t btree_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + (void)iter_buf; + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + if (self->next_flags != 0) { + // If we're called immediately after keys(), values(), or items(), + // use their setup for iteration. + self->flags = self->next_flags; + self->next_flags = 0; + } else { + // Otherwise, iterate over all keys. + self->flags = FLAG_ITER_KEYS; + self->start_key = mp_const_none; + self->end_key = mp_const_none; + } + + return self_in; +} + +STATIC mp_obj_t btree_iternext(mp_obj_t self_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + DBT key, val; + int res; + bool desc = self->flags & FLAG_DESC; + if (self->start_key != MP_OBJ_NULL) { + int flags = R_FIRST; + if (self->start_key != mp_const_none) { + key.data = (void*)mp_obj_str_get_data(self->start_key, &key.size); + flags = R_CURSOR; + } else if (desc) { + flags = R_LAST; + } + res = __bt_seq(self->db, &key, &val, flags); + self->start_key = MP_OBJ_NULL; + } else { + res = __bt_seq(self->db, &key, &val, desc ? R_PREV : R_NEXT); + } + + if (res == RET_SPECIAL) { + return MP_OBJ_STOP_ITERATION; + } + CHECK_ERROR(res); + + if (self->end_key != mp_const_none) { + DBT end_key; + end_key.data = (void*)mp_obj_str_get_data(self->end_key, &end_key.size); + BTREE *t = self->db->internal; + int cmp = t->bt_cmp(&key, &end_key); + if (desc) { + cmp = -cmp; + } + if (self->flags & FLAG_END_KEY_INCL) { + cmp--; + } + if (cmp >= 0) { + self->end_key = MP_OBJ_NULL; + return MP_OBJ_STOP_ITERATION; + } + } + + switch (self->flags & FLAG_ITER_TYPE_MASK) { + case FLAG_ITER_KEYS: + return mp_obj_new_bytes(key.data, key.size); + case FLAG_ITER_VALUES: + return mp_obj_new_bytes(val.data, val.size); + default: { + mp_obj_t pair_o = mp_obj_new_tuple(2, NULL); + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o); + pair->items[0] = mp_obj_new_bytes(key.data, key.size); + pair->items[1] = mp_obj_new_bytes(val.data, val.size); + return pair_o; + } + } +} + +STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in); + if (value == MP_OBJ_NULL) { + // delete + DBT key; + key.data = (void*)mp_obj_str_get_data(index, &key.size); + int res = __bt_delete(self->db, &key, 0); + if (res == RET_SPECIAL) { + nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + } + CHECK_ERROR(res); + return mp_const_none; + } else if (value == MP_OBJ_SENTINEL) { + // load + DBT key, val; + key.data = (void*)mp_obj_str_get_data(index, &key.size); + int res = __bt_get(self->db, &key, &val, 0); + if (res == RET_SPECIAL) { + nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); + } + CHECK_ERROR(res); + return mp_obj_new_bytes(val.data, val.size); + } else { + // store + DBT key, val; + key.data = (void*)mp_obj_str_get_data(index, &key.size); + val.data = (void*)mp_obj_str_get_data(value, &val.size); + int res = __bt_put(self->db, &key, &val, 0); + CHECK_ERROR(res); + return mp_const_none; + } +} + +STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in); + switch (op) { + case MP_BINARY_OP_CONTAINS: { + DBT key, val; + key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size); + int res = __bt_get(self->db, &key, &val, 0); + CHECK_ERROR(res); + return mp_obj_new_bool(res != RET_SPECIAL); + } + default: + // op not supported + return MP_OBJ_NULL; + } +} + +STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&btree_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&btree_put_obj) }, + { MP_ROM_QSTR(MP_QSTR_seq), MP_ROM_PTR(&btree_seq_obj) }, + { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&btree_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&btree_values_obj) }, + { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&btree_items_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table); + +STATIC const mp_obj_type_t btree_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_btree, + .print = btree_print, + .getiter = btree_getiter, + .iternext = btree_iternext, + .binary_op = btree_binary_op, + .subscr = btree_subscr, + .locals_dict = (void*)&btree_locals_dict, +}; + +STATIC FILEVTABLE btree_stream_fvtable = { + mp_stream_posix_read, + mp_stream_posix_write, + mp_stream_posix_lseek, + mp_stream_posix_fsync +}; + +STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_cachesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pagesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_minkeypage, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + // Make sure we got a stream object + mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + struct { + mp_arg_val_t flags; + mp_arg_val_t cachesize; + mp_arg_val_t pagesize; + mp_arg_val_t minkeypage; + } args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + BTREEINFO openinfo = {0}; + openinfo.flags = args.flags.u_int; + openinfo.cachesize = args.cachesize.u_int; + openinfo.psize = args.pagesize.u_int; + openinfo.minkeypage = args.minkeypage.u_int; + + DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, /*dflags*/0); + if (db == NULL) { + mp_raise_OSError(errno); + } + return MP_OBJ_FROM_PTR(btree_new(db)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open); + +STATIC const mp_rom_map_elem_t mp_module_btree_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_btree) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_btree_open_obj) }, + { MP_ROM_QSTR(MP_QSTR_INCL), MP_ROM_INT(FLAG_END_KEY_INCL) }, + { MP_ROM_QSTR(MP_QSTR_DESC), MP_ROM_INT(FLAG_DESC) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_table); + +const mp_obj_module_t mp_module_btree = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_btree_globals, +}; + +#endif // MICROPY_PY_BTREE diff --git a/src/openmv/src/micropython/extmod/modframebuf.c b/src/openmv/src/micropython/extmod/modframebuf.c new file mode 100755 index 0000000..a7f6ba9 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modframebuf.c @@ -0,0 +1,648 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_FRAMEBUF + +#include "ports/stm32/font_petme128_8x8.h" + +typedef struct _mp_obj_framebuf_t { + mp_obj_base_t base; + mp_obj_t buf_obj; // need to store this to prevent GC from reclaiming buf + void *buf; + uint16_t width, height, stride; + uint8_t format; +} mp_obj_framebuf_t; + +typedef void (*setpixel_t)(const mp_obj_framebuf_t*, int, int, uint32_t); +typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t*, int, int); +typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t); + +typedef struct _mp_framebuf_p_t { + setpixel_t setpixel; + getpixel_t getpixel; + fill_rect_t fill_rect; +} mp_framebuf_p_t; + +// constants for formats +#define FRAMEBUF_MVLSB (0) +#define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS2_HMSB (5) +#define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_GS8 (6) +#define FRAMEBUF_MHLSB (3) +#define FRAMEBUF_MHMSB (4) + +// Functions for MHLSB and MHMSB + +STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + size_t index = (x + y * fb->stride) >> 3; + int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); + ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset); +} + +STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + size_t index = (x + y * fb->stride) >> 3; + int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); + return (((uint8_t*)fb->buf)[index] >> (offset)) & 0x01; +} + +STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + int reverse = fb->format == FRAMEBUF_MHMSB; + int advance = fb->stride >> 3; + while (w--) { + uint8_t *b = &((uint8_t*)fb->buf)[(x >> 3) + y * advance]; + int offset = reverse ? x & 7 : 7 - (x & 7); + for (int hh = h; hh; --hh) { + *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset); + b += advance; + } + ++x; + } +} + +// Functions for MVLSB format + +STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + size_t index = (y >> 3) * fb->stride + x; + uint8_t offset = y & 0x07; + ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset); +} + +STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return (((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01; +} + +STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + while (h--) { + uint8_t *b = &((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x]; + uint8_t offset = y & 0x07; + for (int ww = w; ww; --ww) { + *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset); + ++b; + } + ++y; + } +} + +// Functions for RGB565 format + +STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + ((uint16_t*)fb->buf)[x + y * fb->stride] = col; +} + +STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return ((uint16_t*)fb->buf)[x + y * fb->stride]; +} + +STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride]; + while (h--) { + for (int ww = w; ww; --ww) { + *b++ = col; + } + b += fb->stride - w; + } +} + +// Functions for GS2_HMSB format + +STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + uint8_t mask = 0x3 << shift; + uint8_t color = (col & 0x3) << shift; + *pixel = color | (*pixel & (~mask)); +} + +STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + return (pixel >> shift) & 0x3; +} + +STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + for (int xx=x; xx < x+w; xx++) { + for (int yy=y; yy < y+h; yy++) { + gs2_hmsb_setpixel(fb, xx, yy, col); + } + } +} + +// Functions for GS4_HMSB format + +STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1]; + + if (x % 2) { + *pixel = ((uint8_t)col & 0x0f) | (*pixel & 0xf0); + } else { + *pixel = ((uint8_t)col << 4) | (*pixel & 0x0f); + } +} + +STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + if (x % 2) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f; + } + + return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] >> 4; +} + +STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + col &= 0x0f; + uint8_t *pixel_pair = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1]; + uint8_t col_shifted_left = col << 4; + uint8_t col_pixel_pair = col_shifted_left | col; + int pixel_count_till_next_line = (fb->stride - w) >> 1; + bool odd_x = (x % 2 == 1); + + while (h--) { + int ww = w; + + if (odd_x && ww > 0) { + *pixel_pair = (*pixel_pair & 0xf0) | col; + pixel_pair++; + ww--; + } + + memset(pixel_pair, col_pixel_pair, ww >> 1); + pixel_pair += ww >> 1; + + if (ww % 2) { + *pixel_pair = col_shifted_left | (*pixel_pair & 0x0f); + if (!odd_x) { + pixel_pair++; + } + } + + pixel_pair += pixel_count_till_next_line; + } +} + +// Functions for GS8 format + +STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + *pixel = col & 0xff; +} + +STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride)]; +} + +STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + while (h--) { + memset(pixel, col, w); + pixel += fb->stride; + } +} + +STATIC mp_framebuf_p_t formats[] = { + [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, + [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, + [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, + [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect}, + [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, + [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, +}; + +static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + formats[fb->format].setpixel(fb, x, y, col); +} + +static inline uint32_t getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return formats[fb->format].getpixel(fb, x, y); +} + +STATIC void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + if (h < 1 || w < 1 || x + w <= 0 || y + h <= 0 || y >= fb->height || x >= fb->width) { + // No operation needed. + return; + } + + // clip to the framebuffer + int xend = MIN(fb->width, x + w); + int yend = MIN(fb->height, y + h); + x = MAX(x, 0); + y = MAX(y, 0); + + formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col); +} + +STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 4, 5, false); + + mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t); + o->base.type = type; + o->buf_obj = args[0]; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE); + o->buf = bufinfo.buf; + + o->width = mp_obj_get_int(args[1]); + o->height = mp_obj_get_int(args[2]); + o->format = mp_obj_get_int(args[3]); + if (n_args >= 5) { + o->stride = mp_obj_get_int(args[4]); + } else { + o->stride = o->width; + } + + switch (o->format) { + case FRAMEBUF_MVLSB: + case FRAMEBUF_RGB565: + break; + case FRAMEBUF_MHLSB: + case FRAMEBUF_MHMSB: + o->stride = (o->stride + 7) & ~7; + break; + case FRAMEBUF_GS2_HMSB: + o->stride = (o->stride + 3) & ~3; + break; + case FRAMEBUF_GS4_HMSB: + o->stride = (o->stride + 1) & ~1; + break; + case FRAMEBUF_GS8: + break; + default: + mp_raise_ValueError("invalid format"); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_int_t framebuf_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + (void)flags; + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in); + bufinfo->buf = self->buf; + bufinfo->len = self->stride * self->height * (self->format == FRAMEBUF_RGB565 ? 2 : 1); + bufinfo->typecode = 'B'; // view framebuf as bytes + return 0; +} + +STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) { + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t col = mp_obj_get_int(col_in); + formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf_fill_obj, framebuf_fill); + +STATIC mp_obj_t framebuf_fill_rect(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + mp_int_t width = mp_obj_get_int(args[3]); + mp_int_t height = mp_obj_get_int(args[4]); + mp_int_t col = mp_obj_get_int(args[5]); + + fill_rect(self, x, y, width, height, col); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect); + +STATIC mp_obj_t framebuf_pixel(size_t n_args, const mp_obj_t *args) { + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + if (0 <= x && x < self->width && 0 <= y && y < self->height) { + if (n_args == 3) { + // get + return MP_OBJ_NEW_SMALL_INT(getpixel(self, x, y)); + } else { + // set + setpixel(self, x, y, mp_obj_get_int(args[3])); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_pixel_obj, 3, 4, framebuf_pixel); + +STATIC mp_obj_t framebuf_hline(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + mp_int_t w = mp_obj_get_int(args[3]); + mp_int_t col = mp_obj_get_int(args[4]); + + fill_rect(self, x, y, w, 1, col); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_hline_obj, 5, 5, framebuf_hline); + +STATIC mp_obj_t framebuf_vline(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + mp_int_t h = mp_obj_get_int(args[3]); + mp_int_t col = mp_obj_get_int(args[4]); + + fill_rect(self, x, y, 1, h, col); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_vline_obj, 5, 5, framebuf_vline); + +STATIC mp_obj_t framebuf_rect(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + mp_int_t w = mp_obj_get_int(args[3]); + mp_int_t h = mp_obj_get_int(args[4]); + mp_int_t col = mp_obj_get_int(args[5]); + + fill_rect(self, x, y, w, 1, col); + fill_rect(self, x, y + h- 1, w, 1, col); + fill_rect(self, x, y, 1, h, col); + fill_rect(self, x + w- 1, y, 1, h, col); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_rect_obj, 6, 6, framebuf_rect); + +STATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t x1 = mp_obj_get_int(args[1]); + mp_int_t y1 = mp_obj_get_int(args[2]); + mp_int_t x2 = mp_obj_get_int(args[3]); + mp_int_t y2 = mp_obj_get_int(args[4]); + mp_int_t col = mp_obj_get_int(args[5]); + + mp_int_t dx = x2 - x1; + mp_int_t sx; + if (dx > 0) { + sx = 1; + } else { + dx = -dx; + sx = -1; + } + + mp_int_t dy = y2 - y1; + mp_int_t sy; + if (dy > 0) { + sy = 1; + } else { + dy = -dy; + sy = -1; + } + + bool steep; + if (dy > dx) { + mp_int_t temp; + temp = x1; x1 = y1; y1 = temp; + temp = dx; dx = dy; dy = temp; + temp = sx; sx = sy; sy = temp; + steep = true; + } else { + steep = false; + } + + mp_int_t e = 2 * dy - dx; + for (mp_int_t i = 0; i < dx; ++i) { + if (steep) { + if (0 <= y1 && y1 < self->width && 0 <= x1 && x1 < self->height) { + setpixel(self, y1, x1, col); + } + } else { + if (0 <= x1 && x1 < self->width && 0 <= y1 && y1 < self->height) { + setpixel(self, x1, y1, col); + } + } + while (e >= 0) { + y1 += sy; + e -= 2 * dx; + } + x1 += sx; + e += 2 * dy; + } + + if (0 <= x2 && x2 < self->width && 0 <= y2 && y2 < self->height) { + setpixel(self, x2, y2, col); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_line_obj, 6, 6, framebuf_line); + +STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) { + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(args[1]); + mp_int_t x = mp_obj_get_int(args[2]); + mp_int_t y = mp_obj_get_int(args[3]); + mp_int_t key = -1; + if (n_args > 4) { + key = mp_obj_get_int(args[4]); + } + + if ( + (x >= self->width) || + (y >= self->height) || + (-x >= source->width) || + (-y >= source->height) + ) { + // Out of bounds, no-op. + return mp_const_none; + } + + // Clip. + int x0 = MAX(0, x); + int y0 = MAX(0, y); + int x1 = MAX(0, -x); + int y1 = MAX(0, -y); + int x0end = MIN(self->width, x + source->width); + int y0end = MIN(self->height, y + source->height); + + for (; y0 < y0end; ++y0) { + int cx1 = x1; + for (int cx0 = x0; cx0 < x0end; ++cx0) { + uint32_t col = getpixel(source, cx1, y1); + if (col != (uint32_t)key) { + setpixel(self, cx0, y0, col); + } + ++cx1; + } + ++y1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit); + +STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) { + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t xstep = mp_obj_get_int(xstep_in); + mp_int_t ystep = mp_obj_get_int(ystep_in); + int sx, y, xend, yend, dx, dy; + if (xstep < 0) { + sx = 0; + xend = self->width + xstep; + dx = 1; + } else { + sx = self->width - 1; + xend = xstep - 1; + dx = -1; + } + if (ystep < 0) { + y = 0; + yend = self->height + ystep; + dy = 1; + } else { + y = self->height - 1; + yend = ystep - 1; + dy = -1; + } + for (; y != yend; y += dy) { + for (int x = sx; x != xend; x += dx) { + setpixel(self, x, y, getpixel(self, x - xstep, y - ystep)); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf_scroll_obj, framebuf_scroll); + +STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) { + // extract arguments + mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]); + const char *str = mp_obj_str_get_str(args[1]); + mp_int_t x0 = mp_obj_get_int(args[2]); + mp_int_t y0 = mp_obj_get_int(args[3]); + mp_int_t col = 1; + if (n_args >= 5) { + col = mp_obj_get_int(args[4]); + } + + // loop over chars + for (; *str; ++str) { + // get char and make sure its in range of font + int chr = *(uint8_t*)str; + if (chr < 32 || chr > 127) { + chr = 127; + } + // get char data + const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8]; + // loop over char data + for (int j = 0; j < 8; j++, x0++) { + if (0 <= x0 && x0 < self->width) { // clip x + uint vline_data = chr_data[j]; // each byte is a column of 8 pixels, LSB at top + for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column + if (vline_data & 1) { // only draw if pixel set + if (0 <= y && y < self->height) { // clip y + setpixel(self, x0, y, col); + } + } + } + } + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text); + +STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&framebuf_hline_obj) }, + { MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&framebuf_vline_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&framebuf_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&framebuf_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&framebuf_blit_obj) }, + { MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf_scroll_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf_text_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table); + +STATIC const mp_obj_type_t mp_type_framebuf = { + { &mp_type_type }, + .name = MP_QSTR_FrameBuffer, + .make_new = framebuf_make_new, + .buffer_p = { .get_buffer = framebuf_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict, +}; + +// this factory function is provided for backwards compatibility with old FrameBuffer1 class +STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) { + mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t); + o->base.type = &mp_type_framebuf; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE); + o->buf = bufinfo.buf; + + o->width = mp_obj_get_int(args[1]); + o->height = mp_obj_get_int(args[2]); + o->format = FRAMEBUF_MVLSB; + if (n_args >= 4) { + o->stride = mp_obj_get_int(args[3]); + } else { + o->stride = o->width; + } + + return MP_OBJ_FROM_PTR(o); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1); + +STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) }, + { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) }, + { MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) }, + { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, + { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) }, + { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, + { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, +}; + +STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table); + +const mp_obj_module_t mp_module_framebuf = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&framebuf_module_globals, +}; + +#endif // MICROPY_PY_FRAMEBUF diff --git a/src/openmv/src/micropython/extmod/modlwip.c b/src/openmv/src/micropython/extmod/modlwip.c new file mode 100755 index 0000000..33546a6 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modlwip.c @@ -0,0 +1,1463 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Galen Hazelwood + * Copyright (c) 2015-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +#include "lib/netutils/netutils.h" + +#include "lwip/init.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" +//#include "lwip/raw.h" +#include "lwip/dns.h" +#include "lwip/igmp.h" +#if LWIP_VERSION_MAJOR < 2 +#include "lwip/timers.h" +#include "lwip/tcp_impl.h" +#else +#include "lwip/timeouts.h" +#include "lwip/priv/tcp_priv.h" +#endif + +#if 0 // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +// All socket options should be globally distinct, +// because we ignore option levels for efficiency. +#define IP_ADD_MEMBERSHIP 0x400 + +// For compatibilily with older lwIP versions. +#ifndef ip_set_option +#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt)) +#endif +#ifndef ip_reset_option +#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) +#endif + +#ifdef MICROPY_PY_LWIP_SLIP +#include "netif/slipif.h" +#include "lwip/sio.h" +#endif + +#ifdef MICROPY_PY_LWIP_SLIP +/******************************************************************************/ +// Slip object for modlwip. Requires a serial driver for the port that supports +// the lwip serial callback functions. + +typedef struct _lwip_slip_obj_t { + mp_obj_base_t base; + struct netif lwip_netif; +} lwip_slip_obj_t; + +// Slip object is unique for now. Possibly can fix this later. FIXME +STATIC lwip_slip_obj_t lwip_slip_obj; + +// Declare these early. +void mod_lwip_register_poll(void (*poll)(void *arg), void *poll_arg); +void mod_lwip_deregister_poll(void (*poll)(void *arg), void *poll_arg); + +STATIC void slip_lwip_poll(void *netif) { + slipif_poll((struct netif*)netif); +} + +STATIC const mp_obj_type_t lwip_slip_type; + +// lwIP SLIP callback functions +sio_fd_t sio_open(u8_t dvnum) { + // We support singleton SLIP interface, so just return any truish value. + return (sio_fd_t)1; +} + +void sio_send(u8_t c, sio_fd_t fd) { + mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream)); + int error; + type->stream_p->write(MP_STATE_VM(lwip_slip_stream), &c, 1, &error); +} + +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len) { + mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream)); + int error; + mp_uint_t out_sz = type->stream_p->read(MP_STATE_VM(lwip_slip_stream), data, len, &error); + if (out_sz == MP_STREAM_ERROR) { + if (mp_is_nonblocking_error(error)) { + return 0; + } + // Can't do much else, can we? + return 0; + } + return out_sz; +} + +// constructor lwip.slip(device=integer, iplocal=string, ipremote=string) +STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 3, 3, false); + + lwip_slip_obj.base.type = &lwip_slip_type; + + MP_STATE_VM(lwip_slip_stream) = args[0]; + + ip_addr_t iplocal, ipremote; + if (!ipaddr_aton(mp_obj_str_get_str(args[1]), &iplocal)) { + mp_raise_ValueError("not a valid local IP"); + } + if (!ipaddr_aton(mp_obj_str_get_str(args[2]), &ipremote)) { + mp_raise_ValueError("not a valid remote IP"); + } + + struct netif *n = &lwip_slip_obj.lwip_netif; + if (netif_add(n, &iplocal, IP_ADDR_BROADCAST, &ipremote, NULL, slipif_init, ip_input) == NULL) { + mp_raise_ValueError("out of memory"); + } + netif_set_up(n); + netif_set_default(n); + mod_lwip_register_poll(slip_lwip_poll, n); + + return (mp_obj_t)&lwip_slip_obj; +} + +STATIC mp_obj_t lwip_slip_status(mp_obj_t self_in) { + // Null function for now. + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_slip_status_obj, lwip_slip_status); + +STATIC const mp_rom_map_elem_t lwip_slip_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lwip_slip_status_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(lwip_slip_locals_dict, lwip_slip_locals_dict_table); + +STATIC const mp_obj_type_t lwip_slip_type = { + { &mp_type_type }, + .name = MP_QSTR_slip, + .make_new = lwip_slip_make_new, + .locals_dict = (mp_obj_dict_t*)&lwip_slip_locals_dict, +}; + +#endif // MICROPY_PY_LWIP_SLIP + +/******************************************************************************/ +// Table to convert lwIP err_t codes to socket errno codes, from the lwIP +// socket API. + +// lwIP 2 changed LWIP_VERSION and it can no longer be used in macros, +// so we define our own equivalent version that can. +#define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \ + | LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +// Extension to lwIP error codes +#define _ERR_BADF -16 +// TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1, +// investigate in more detail. +#if LWIP_VERSION_MACRO < 0x01040100 +static const int error_lookup_table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -9 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -10 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected. */ + MP_EIO, /* ERR_ARG -12 Illegal argument. */ + MP_EADDRINUSE, /* ERR_USE -13 Address in use. */ + -1, /* ERR_IF -14 Low-level netif error */ + MP_EALREADY, /* ERR_ISCONN -15 Already connected. */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ +}; +#elif LWIP_VERSION_MACRO < 0x02000000 +static const int error_lookup_table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_EADDRINUSE, /* ERR_USE -8 Address in use. */ + MP_EALREADY, /* ERR_ISCONN -9 Already connected. */ + MP_ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -11 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -13 Not connected. */ + MP_EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ +}; +#else +// Matches lwIP 2.0.3 +#undef _ERR_BADF +#define _ERR_BADF -17 +static const int error_lookup_table[] = { + 0, /* ERR_OK 0 No error, everything OK */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block */ + MP_EADDRINUSE, /* ERR_USE -8 Address in use */ + MP_EALREADY, /* ERR_ALREADY -9 Already connecting */ + MP_EALREADY, /* ERR_ISCONN -10 Conn already established */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected */ + -1, /* ERR_IF -12 Low-level netif error */ + MP_ECONNABORTED, /* ERR_ABRT -13 Connection aborted */ + MP_ECONNRESET, /* ERR_RST -14 Connection reset */ + MP_ENOTCONN, /* ERR_CLSD -15 Connection closed */ + MP_EIO, /* ERR_ARG -16 Illegal argument. */ + MP_EBADF, /* _ERR_BADF -17 Closed socket (null pcb) */ +}; +#endif + +/*******************************************************************************/ +// The socket object provided by lwip.socket. + +#define MOD_NETWORK_AF_INET (2) +#define MOD_NETWORK_AF_INET6 (10) + +#define MOD_NETWORK_SOCK_STREAM (1) +#define MOD_NETWORK_SOCK_DGRAM (2) +#define MOD_NETWORK_SOCK_RAW (3) + +typedef struct _lwip_socket_obj_t { + mp_obj_base_t base; + + volatile union { + struct tcp_pcb *tcp; + struct udp_pcb *udp; + } pcb; + volatile union { + struct pbuf *pbuf; + struct tcp_pcb *connection; + } incoming; + mp_obj_t callback; + byte peer[4]; + mp_uint_t peer_port; + mp_uint_t timeout; + uint16_t recv_offset; + + uint8_t domain; + uint8_t type; + + #define STATE_NEW 0 + #define STATE_CONNECTING 1 + #define STATE_CONNECTED 2 + #define STATE_PEER_CLOSED 3 + // Negative value is lwIP error + int8_t state; +} lwip_socket_obj_t; + +static inline void poll_sockets(void) { +#ifdef MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK; +#else + mp_hal_delay_ms(1); +#endif +} + +/*******************************************************************************/ +// Callback functions for the lwIP raw API. + +static inline void exec_user_callback(lwip_socket_obj_t *socket) { + if (socket->callback != MP_OBJ_NULL) { + mp_call_function_1_protected(socket->callback, MP_OBJ_FROM_PTR(socket)); + } +} + +// Callback for incoming UDP packets. We simply stash the packet and the source address, +// in case we need it for recvfrom. +#if LWIP_VERSION_MAJOR < 2 +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +#else +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +#endif +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + if (socket->incoming.pbuf != NULL) { + // That's why they call it "unreliable". No room in the inn, drop the packet. + pbuf_free(p); + } else { + socket->incoming.pbuf = p; + socket->peer_port = (mp_uint_t)port; + memcpy(&socket->peer, addr, sizeof(socket->peer)); + } +} + +// Callback for general tcp errors. +STATIC void _lwip_tcp_error(void *arg, err_t err) { + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + // Pass the error code back via the connection variable. + socket->state = err; + // If we got here, the lwIP stack either has deallocated or will deallocate the pcb. + socket->pcb.tcp = NULL; +} + +// Callback for tcp connection requests. Error code err is unused. (See tcp.h) +STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + socket->state = STATE_CONNECTED; + return ERR_OK; +} + +// By default, a child socket of listen socket is created with recv +// handler which discards incoming pbuf's. We don't want to do that, +// so set this handler which requests lwIP to keep pbuf's and deliver +// them later. We cannot cache pbufs in child socket on Python side, +// until it is created in accept(). +STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { + return ERR_BUF; +} + +// "Poll" (idle) callback to be called ASAP after accept callback +// to execute Python callback function, as it can't be executed +// from accept callback itself. +STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + tcp_poll(pcb, NULL, 0); + exec_user_callback(socket); + return ERR_OK; +} + +// Callback for incoming tcp connections. +STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + tcp_recv(newpcb, _lwip_tcp_recv_unaccepted); + + if (socket->incoming.connection != NULL) { + DEBUG_printf("_lwip_tcp_accept: Tried to queue >1 pcb waiting for accept\n"); + // We need to handle this better. This single-level structure makes the + // backlog setting kind of pointless. FIXME + return ERR_BUF; + } else { + socket->incoming.connection = newpcb; + if (socket->callback != MP_OBJ_NULL) { + // Schedule accept callback to be called when lwIP is done + // with processing this incoming connection on its side and + // is idle. + tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); + } + return ERR_OK; + } +} + +// Callback for inbound tcp packets. +STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err_t err) { + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + + if (p == NULL) { + // Other side has closed connection. + DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket); + socket->state = STATE_PEER_CLOSED; + exec_user_callback(socket); + return ERR_OK; + } + + if (socket->incoming.pbuf == NULL) { + socket->incoming.pbuf = p; + } else { + #ifdef SOCKET_SINGLE_PBUF + return ERR_BUF; + #else + pbuf_cat(socket->incoming.pbuf, p); + #endif + } + + exec_user_callback(socket); + + return ERR_OK; +} + +/*******************************************************************************/ +// Functions for socket send/receive operations. Socket send/recv and friends call +// these to do the work. + +// Helper function for send/sendto to handle UDP packets. +STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + if (len > 0xffff) { + // Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try + len = 0xffff; + } + + // FIXME: maybe PBUF_ROM? + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (p == NULL) { + *_errno = MP_ENOMEM; + return -1; + } + + memcpy(p->payload, buf, len); + + err_t err; + if (ip == NULL) { + err = udp_send(socket->pcb.udp, p); + } else { + ip_addr_t dest; + IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); + err = udp_sendto(socket->pcb.udp, p, &dest, port); + } + + pbuf_free(p); + + // udp_sendto can return 1 on occasion for ESP8266 port. It's not known why + // but it seems that the send actually goes through without error in this case. + // So we treat such cases as a success until further investigation. + if (err != ERR_OK && err != 1) { + *_errno = error_lookup_table[-err]; + return -1; + } + + return len; +} + +// Helper function for recv/recvfrom to handle UDP packets +STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + + if (socket->incoming.pbuf == NULL) { + if (socket->timeout != -1) { + for (mp_uint_t retries = socket->timeout / 100; retries--;) { + mp_hal_delay_ms(100); + if (socket->incoming.pbuf != NULL) break; + } + if (socket->incoming.pbuf == NULL) { + *_errno = MP_ETIMEDOUT; + return -1; + } + } else { + while (socket->incoming.pbuf == NULL) { + poll_sockets(); + } + } + } + + if (ip != NULL) { + memcpy(ip, &socket->peer, sizeof(socket->peer)); + *port = socket->peer_port; + } + + struct pbuf *p = socket->incoming.pbuf; + + u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0); + pbuf_free(p); + socket->incoming.pbuf = NULL; + + return (mp_uint_t) result; +} + +// For use in stream virtual methods +#define STREAM_ERROR_CHECK(socket) \ + if (socket->state < 0) { \ + *_errno = error_lookup_table[-socket->state]; \ + return MP_STREAM_ERROR; \ + } \ + assert(socket->pcb.tcp); + + +// Helper function for send/sendto to handle TCP packets +STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + // Check for any pending errors + STREAM_ERROR_CHECK(socket); + + u16_t available = tcp_sndbuf(socket->pcb.tcp); + + if (available == 0) { + // Non-blocking socket + if (socket->timeout == 0) { + *_errno = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + mp_uint_t start = mp_hal_ticks_ms(); + // Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it + // sending direction, but not receiving. Consequently, check for both STATE_CONNECTED + // and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent. + // If peer fully closed socket, we would have socket->state set to ERR_RST (connection + // reset) by error callback. + // Avoid sending too small packets, so wait until at least 16 bytes available + while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { + if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { + *_errno = MP_ETIMEDOUT; + return MP_STREAM_ERROR; + } + poll_sockets(); + } + + // While we waited, something could happen + STREAM_ERROR_CHECK(socket); + } + + u16_t write_len = MIN(available, len); + + err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + + // If the output buffer is getting full then send the data to the lower layers + if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { + err = tcp_output(socket->pcb.tcp); + } + + if (err != ERR_OK) { + *_errno = error_lookup_table[-err]; + return MP_STREAM_ERROR; + } + + return write_len; +} + +// Helper function for recv/recvfrom to handle TCP packets +STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + // Check for any pending errors + STREAM_ERROR_CHECK(socket); + + if (socket->incoming.pbuf == NULL) { + + // Non-blocking socket + if (socket->timeout == 0) { + if (socket->state == STATE_PEER_CLOSED) { + return 0; + } + *_errno = MP_EAGAIN; + return -1; + } + + mp_uint_t start = mp_hal_ticks_ms(); + while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) { + if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { + *_errno = MP_ETIMEDOUT; + return -1; + } + poll_sockets(); + } + + if (socket->state == STATE_PEER_CLOSED) { + if (socket->incoming.pbuf == NULL) { + // socket closed and no data left in buffer + return 0; + } + } else if (socket->state != STATE_CONNECTED) { + assert(socket->state < 0); + *_errno = error_lookup_table[-socket->state]; + return -1; + } + } + + assert(socket->pcb.tcp != NULL); + + struct pbuf *p = socket->incoming.pbuf; + + mp_uint_t remaining = p->len - socket->recv_offset; + if (len > remaining) { + len = remaining; + } + + memcpy(buf, (byte*)p->payload + socket->recv_offset, len); + + remaining -= len; + if (remaining == 0) { + socket->incoming.pbuf = p->next; + // If we don't ref here, free() will free the entire chain, + // if we ref, it does what we need: frees 1st buf, and decrements + // next buf's refcount back to 1. + pbuf_ref(p->next); + pbuf_free(p); + socket->recv_offset = 0; + } else { + socket->recv_offset += len; + } + tcp_recved(socket->pcb.tcp, len); + + return len; +} + +/*******************************************************************************/ +// The socket functions provided by lwip.socket. + +STATIC const mp_obj_type_t lwip_socket_type; + +STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + lwip_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->state, self->timeout, + self->incoming.pbuf, self->recv_offset); +} + +// FIXME: Only supports two arguments at present +STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + lwip_socket_obj_t *socket = m_new_obj_with_finaliser(lwip_socket_obj_t); + socket->base.type = &lwip_socket_type; + socket->domain = MOD_NETWORK_AF_INET; + socket->type = MOD_NETWORK_SOCK_STREAM; + socket->callback = MP_OBJ_NULL; + if (n_args >= 1) { + socket->domain = mp_obj_get_int(args[0]); + if (n_args >= 2) { + socket->type = mp_obj_get_int(args[1]); + } + } + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break; + case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break; + //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; + default: mp_raise_OSError(MP_EINVAL); + } + + if (socket->pcb.tcp == NULL) { + mp_raise_OSError(MP_ENOMEM); + } + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + // Register the socket object as our callback argument. + tcp_arg(socket->pcb.tcp, (void*)socket); + // Register our error callback. + tcp_err(socket->pcb.tcp, _lwip_tcp_error); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + // Register our receive callback now. Since UDP sockets don't require binding or connection + // before use, there's no other good time to do it. + udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket); + break; + } + } + + socket->incoming.pbuf = NULL; + socket->timeout = -1; + socket->state = STATE_NEW; + socket->recv_offset = 0; + return MP_OBJ_FROM_PTR(socket); +} + +STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + + uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + ip_addr_t bind_addr; + IP4_ADDR(&bind_addr, ip[0], ip[1], ip[2], ip[3]); + + err_t err = ERR_ARG; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + err = tcp_bind(socket->pcb.tcp, &bind_addr, port); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + err = udp_bind(socket->pcb.udp, &bind_addr, port); + break; + } + } + + if (err != ERR_OK) { + mp_raise_OSError(error_lookup_table[-err]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_bind_obj, lwip_socket_bind); + +STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + mp_int_t backlog = mp_obj_get_int(backlog_in); + + if (socket->pcb.tcp == NULL) { + mp_raise_OSError(MP_EBADF); + } + if (socket->type != MOD_NETWORK_SOCK_STREAM) { + mp_raise_OSError(MP_EOPNOTSUPP); + } + + struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog); + if (new_pcb == NULL) { + mp_raise_OSError(MP_ENOMEM); + } + socket->pcb.tcp = new_pcb; + tcp_accept(new_pcb, _lwip_tcp_accept); + + // Socket is no longer considered "new" for purposes of polling + socket->state = STATE_CONNECTING; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen); + +STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + + if (socket->pcb.tcp == NULL) { + mp_raise_OSError(MP_EBADF); + } + if (socket->type != MOD_NETWORK_SOCK_STREAM) { + mp_raise_OSError(MP_EOPNOTSUPP); + } + // I need to do this because "tcp_accepted", later, is a macro. + struct tcp_pcb *listener = socket->pcb.tcp; + if (listener->state != LISTEN) { + mp_raise_OSError(MP_EINVAL); + } + + // accept incoming connection + if (socket->incoming.connection == NULL) { + if (socket->timeout == 0) { + mp_raise_OSError(MP_EAGAIN); + } else if (socket->timeout != -1) { + for (mp_uint_t retries = socket->timeout / 100; retries--;) { + mp_hal_delay_ms(100); + if (socket->incoming.connection != NULL) break; + } + if (socket->incoming.connection == NULL) { + mp_raise_OSError(MP_ETIMEDOUT); + } + } else { + while (socket->incoming.connection == NULL) { + poll_sockets(); + } + } + } + + // create new socket object + lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); + socket2->base.type = &lwip_socket_type; + + // We get a new pcb handle... + socket2->pcb.tcp = socket->incoming.connection; + socket->incoming.connection = NULL; + + // ...and set up the new socket for it. + socket2->domain = MOD_NETWORK_AF_INET; + socket2->type = MOD_NETWORK_SOCK_STREAM; + socket2->incoming.pbuf = NULL; + socket2->timeout = socket->timeout; + socket2->state = STATE_CONNECTED; + socket2->recv_offset = 0; + socket2->callback = MP_OBJ_NULL; + tcp_arg(socket2->pcb.tcp, (void*)socket2); + tcp_err(socket2->pcb.tcp, _lwip_tcp_error); + tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); + + tcp_accepted(listener); + + // make the return value + uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; + memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip)); + mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port; + mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + client->items[0] = MP_OBJ_FROM_PTR(socket2); + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return MP_OBJ_FROM_PTR(client); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_accept_obj, lwip_socket_accept); + +STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + + if (socket->pcb.tcp == NULL) { + mp_raise_OSError(MP_EBADF); + } + + // get address + uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + ip_addr_t dest; + IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]); + + err_t err = ERR_ARG; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->state != STATE_NEW) { + if (socket->state == STATE_CONNECTED) { + mp_raise_OSError(MP_EISCONN); + } else { + mp_raise_OSError(MP_EALREADY); + } + } + // Register our receive callback. + tcp_recv(socket->pcb.tcp, _lwip_tcp_recv); + socket->state = STATE_CONNECTING; + err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected); + if (err != ERR_OK) { + socket->state = STATE_NEW; + mp_raise_OSError(error_lookup_table[-err]); + } + socket->peer_port = (mp_uint_t)port; + memcpy(socket->peer, &dest, sizeof(socket->peer)); + // And now we wait... + if (socket->timeout != -1) { + for (mp_uint_t retries = socket->timeout / 100; retries--;) { + mp_hal_delay_ms(100); + if (socket->state != STATE_CONNECTING) break; + } + if (socket->state == STATE_CONNECTING) { + mp_raise_OSError(MP_EINPROGRESS); + } + } else { + while (socket->state == STATE_CONNECTING) { + poll_sockets(); + } + } + if (socket->state == STATE_CONNECTED) { + err = ERR_OK; + } else { + err = socket->state; + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + err = udp_connect(socket->pcb.udp, &dest, port); + break; + } + } + + if (err != ERR_OK) { + mp_raise_OSError(error_lookup_table[-err]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_connect_obj, lwip_socket_connect); + +STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) { + if (socket->pcb.tcp == NULL) { + // not connected + int _errno = error_lookup_table[-socket->state]; + socket->state = _ERR_BADF; + mp_raise_OSError(_errno); + } +} + +STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + int _errno; + + lwip_socket_check_connected(socket); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + mp_uint_t ret = 0; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno); + break; + } + } + if (ret == -1) { + mp_raise_OSError(_errno); + } + + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send); + +STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + int _errno; + + lwip_socket_check_connected(socket); + + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + + mp_uint_t ret = 0; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno); + break; + } + } + if (ret == -1) { + mp_raise_OSError(_errno); + } + + if (ret == 0) { + return mp_const_empty_bytes; + } + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv); + +STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + int _errno; + + lwip_socket_check_connected(socket); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + mp_uint_t ret = 0; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno); + break; + } + } + if (ret == -1) { + mp_raise_OSError(_errno); + } + + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto); + +STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + int _errno; + + lwip_socket_check_connected(socket); + + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + byte ip[4]; + mp_uint_t port; + + mp_uint_t ret = 0; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + memcpy(ip, &socket->peer, sizeof(socket->peer)); + port = (mp_uint_t) socket->peer_port; + ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno); + break; + } + case MOD_NETWORK_SOCK_DGRAM: { + ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno); + break; + } + } + if (ret == -1) { + mp_raise_OSError(_errno); + } + + mp_obj_t tuple[2]; + if (ret == 0) { + tuple[0] = mp_const_empty_bytes; + } else { + vstr.len = ret; + tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom); + +STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + lwip_socket_check_connected(socket); + + int _errno; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + mp_uint_t ret = 0; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->timeout == 0) { + // Behavior of sendall() for non-blocking sockets isn't explicitly specified. + // But it's specified that "On error, an exception is raised, there is no + // way to determine how much data, if any, was successfully sent." Then, the + // most useful behavior is: check whether we will be able to send all of input + // data without EAGAIN, and if won't be, raise it without sending any. + if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) { + mp_raise_OSError(MP_EAGAIN); + } + } + // TODO: In CPython3.5, socket timeout should apply to the + // entire sendall() operation, not to individual send() chunks. + while (bufinfo.len != 0) { + ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + bufinfo.len -= ret; + bufinfo.buf = (char*)bufinfo.buf + ret; + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: + mp_raise_NotImplementedError(NULL); + break; + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_sendall_obj, lwip_socket_sendall); + +STATIC mp_obj_t lwip_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + mp_uint_t timeout; + if (timeout_in == mp_const_none) { + timeout = -1; + } else { + #if MICROPY_PY_BUILTINS_FLOAT + timeout = 1000 * mp_obj_get_float(timeout_in); + #else + timeout = 1000 * mp_obj_get_int(timeout_in); + #endif + } + socket->timeout = timeout; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_settimeout_obj, lwip_socket_settimeout); + +STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + bool val = mp_obj_is_true(flag_in); + if (val) { + socket->timeout = -1; + } else { + socket->timeout = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking); + +STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]); + + int opt = mp_obj_get_int(args[2]); + if (opt == 20) { + if (args[3] == mp_const_none) { + socket->callback = MP_OBJ_NULL; + } else { + socket->callback = args[3]; + } + return mp_const_none; + } + + switch (opt) { + // level: SOL_SOCKET + case SOF_REUSEADDR: { + mp_int_t val = mp_obj_get_int(args[3]); + // Options are common for UDP and TCP pcb's. + if (val) { + ip_set_option(socket->pcb.tcp, SOF_REUSEADDR); + } else { + ip_reset_option(socket->pcb.tcp, SOF_REUSEADDR); + } + break; + } + + // level: IPPROTO_IP + case IP_ADD_MEMBERSHIP: { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != sizeof(ip_addr_t) * 2) { + mp_raise_ValueError(NULL); + } + + // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa + err_t err = igmp_joingroup((ip_addr_t*)bufinfo.buf + 1, bufinfo.buf); + if (err != ERR_OK) { + mp_raise_OSError(error_lookup_table[-err]); + } + break; + } + + default: + printf("Warning: lwip.setsockopt() not implemented\n"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt); + +STATIC mp_obj_t lwip_socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_makefile_obj, 1, 3, lwip_socket_makefile); + +STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + return lwip_tcp_receive(socket, buf, size, errcode); + case MOD_NETWORK_SOCK_DGRAM: + return lwip_udp_receive(socket, buf, size, NULL, NULL, errcode); + } + // Unreachable + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + return lwip_tcp_send(socket, buf, size, errcode); + case MOD_NETWORK_SOCK_DGRAM: + return lwip_udp_send(socket, buf, size, NULL, 0, errcode); + } + // Unreachable + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); + mp_uint_t ret; + + if (request == MP_STREAM_POLL) { + uintptr_t flags = arg; + ret = 0; + + if (flags & MP_STREAM_POLL_RD && socket->incoming.pbuf != NULL) { + ret |= MP_STREAM_POLL_RD; + } + + // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf + if (flags & MP_STREAM_POLL_WR && socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { + ret |= MP_STREAM_POLL_WR; + } + + if (socket->state == STATE_NEW) { + // New sockets are not connected so set HUP + ret |= flags & MP_STREAM_POLL_HUP; + } else if (socket->state == STATE_PEER_CLOSED) { + // Peer-closed socket is both readable and writable: read will + // return EOF, write - error. Without this poll will hang on a + // socket which was closed by peer. + ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); + } else if (socket->state == ERR_RST) { + // Socket was reset by peer, a write will return an error + ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP); + } else if (socket->state < 0) { + // Socket in some other error state, use catch-all ERR flag + // TODO: may need to set other return flags here + ret |= flags & MP_STREAM_POLL_ERR; + } + + } else if (request == MP_STREAM_CLOSE) { + bool socket_is_listener = false; + + if (socket->pcb.tcp == NULL) { + return 0; + } + + // Deregister callback (pcb.tcp is set to NULL below so must deregister now) + tcp_recv(socket->pcb.tcp, NULL); + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->pcb.tcp->state == LISTEN) { + socket_is_listener = true; + } + if (tcp_close(socket->pcb.tcp) != ERR_OK) { + DEBUG_printf("lwip_close: had to call tcp_abort()\n"); + tcp_abort(socket->pcb.tcp); + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; + //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + } + socket->pcb.tcp = NULL; + socket->state = _ERR_BADF; + if (socket->incoming.pbuf != NULL) { + if (!socket_is_listener) { + pbuf_free(socket->incoming.pbuf); + } else { + // Deregister callback and abort + tcp_poll(socket->incoming.connection, NULL, 0); + tcp_abort(socket->incoming.connection); + } + socket->incoming.pbuf = NULL; + } + ret = 0; + + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + + return ret; +} + +STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&lwip_socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&lwip_socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&lwip_socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&lwip_socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&lwip_socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&lwip_socket_sendall_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&lwip_socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&lwip_socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&lwip_socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&lwip_socket_makefile_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(lwip_socket_locals_dict, lwip_socket_locals_dict_table); + +STATIC const mp_stream_p_t lwip_socket_stream_p = { + .read = lwip_socket_read, + .write = lwip_socket_write, + .ioctl = lwip_socket_ioctl, +}; + +STATIC const mp_obj_type_t lwip_socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .print = lwip_socket_print, + .make_new = lwip_socket_make_new, + .protocol = &lwip_socket_stream_p, + .locals_dict = (mp_obj_dict_t*)&lwip_socket_locals_dict, +}; + +/******************************************************************************/ +// Support functions for memory protection. lwIP has its own memory management +// routines for its internal structures, and since they might be called in +// interrupt handlers, they need some protection. +sys_prot_t sys_arch_protect() { + return (sys_prot_t)MICROPY_BEGIN_ATOMIC_SECTION(); +} + +void sys_arch_unprotect(sys_prot_t state) { + MICROPY_END_ATOMIC_SECTION((mp_uint_t)state); +} + +/******************************************************************************/ +// Polling callbacks for the interfaces connected to lwIP. Right now it calls +// itself a "list" but isn't; we only support a single interface. + +typedef struct nic_poll { + void (* poll)(void *arg); + void *poll_arg; +} nic_poll_t; + +STATIC nic_poll_t lwip_poll_list; + +void mod_lwip_register_poll(void (* poll)(void *arg), void *poll_arg) { + lwip_poll_list.poll = poll; + lwip_poll_list.poll_arg = poll_arg; +} + +void mod_lwip_deregister_poll(void (* poll)(void *arg), void *poll_arg) { + lwip_poll_list.poll = NULL; +} + +/******************************************************************************/ +// The lwip global functions. + +STATIC mp_obj_t mod_lwip_reset() { + lwip_init(); + lwip_poll_list.poll = NULL; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_reset_obj, mod_lwip_reset); + +STATIC mp_obj_t mod_lwip_callback() { + if (lwip_poll_list.poll != NULL) { + lwip_poll_list.poll(lwip_poll_list.poll_arg); + } + sys_check_timeouts(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_callback_obj, mod_lwip_callback); + +typedef struct _getaddrinfo_state_t { + volatile int status; + volatile ip_addr_t ipaddr; +} getaddrinfo_state_t; + +// Callback for incoming DNS requests. +#if LWIP_VERSION_MAJOR < 2 +STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) +#else +STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg) +#endif +{ + getaddrinfo_state_t *state = arg; + if (ipaddr != NULL) { + state->status = 1; + state->ipaddr = *ipaddr; + } else { + // error + state->status = -2; + } +} + +// lwip.getaddrinfo +STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { + mp_obj_t host_in = args[0], port_in = args[1]; + const char *host = mp_obj_str_get_str(host_in); + mp_int_t port = mp_obj_get_int(port_in); + + // If constraints were passed then check they are compatible with the supported params + if (n_args > 2) { + mp_int_t family = mp_obj_get_int(args[2]); + mp_int_t type = 0; + mp_int_t proto = 0; + mp_int_t flags = 0; + if (n_args > 3) { + type = mp_obj_get_int(args[3]); + if (n_args > 4) { + proto = mp_obj_get_int(args[4]); + if (n_args > 5) { + flags = mp_obj_get_int(args[5]); + } + } + } + if (!((family == 0 || family == MOD_NETWORK_AF_INET) + && (type == 0 || type == MOD_NETWORK_SOCK_STREAM) + && proto == 0 + && flags == 0)) { + mp_warning("unsupported getaddrinfo constraints"); + } + } + + getaddrinfo_state_t state; + state.status = 0; + + err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state); + switch (ret) { + case ERR_OK: + // cached + state.status = 1; + break; + case ERR_INPROGRESS: + while (state.status == 0) { + poll_sockets(); + } + break; + default: + state.status = ret; + } + + if (state.status < 0) { + // TODO: CPython raises gaierror, we raise with native lwIP negative error + // values, to differentiate from normal errno's at least in such way. + mp_raise_OSError(state.status); + } + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo); + +// Debug functions + +STATIC mp_obj_t lwip_print_pcbs() { + tcp_debug_print_pcbs(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs); + +#ifdef MICROPY_PY_LWIP + +STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mod_lwip_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_lwip_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&lwip_getaddrinfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_print_pcbs), MP_ROM_PTR(&lwip_print_pcbs_obj) }, + // objects + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&lwip_socket_type) }, +#ifdef MICROPY_PY_LWIP_SLIP + { MP_ROM_QSTR(MP_QSTR_slip), MP_ROM_PTR(&lwip_slip_type) }, +#endif + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) }, + + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) }, + + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table); + +const mp_obj_module_t mp_module_lwip = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_lwip_globals, +}; + +#endif // MICROPY_PY_LWIP diff --git a/src/openmv/src/micropython/extmod/modonewire.c b/src/openmv/src/micropython/extmod/modonewire.c new file mode 100755 index 0000000..7ef4c3b --- /dev/null +++ b/src/openmv/src/micropython/extmod/modonewire.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/mphal.h" + +/******************************************************************************/ +// Low-level 1-Wire routines + +#define TIMING_RESET1 (480) +#define TIMING_RESET2 (70) +#define TIMING_RESET3 (410) +#define TIMING_READ1 (5) +#define TIMING_READ2 (5) +#define TIMING_READ3 (40) +#define TIMING_WRITE1 (10) +#define TIMING_WRITE2 (50) +#define TIMING_WRITE3 (10) + +STATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 0); + mp_hal_delay_us(TIMING_RESET1); + uint32_t i = mp_hal_quiet_timing_enter(); + mp_hal_pin_write(pin, 1); + mp_hal_delay_us_fast(TIMING_RESET2); + int status = !mp_hal_pin_read(pin); + mp_hal_quiet_timing_exit(i); + mp_hal_delay_us(TIMING_RESET3); + return status; +} + +STATIC int onewire_bus_readbit(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 1); + uint32_t i = mp_hal_quiet_timing_enter(); + mp_hal_pin_write(pin, 0); + mp_hal_delay_us_fast(TIMING_READ1); + mp_hal_pin_write(pin, 1); + mp_hal_delay_us_fast(TIMING_READ2); + int value = mp_hal_pin_read(pin); + mp_hal_quiet_timing_exit(i); + mp_hal_delay_us_fast(TIMING_READ3); + return value; +} + +STATIC void onewire_bus_writebit(mp_hal_pin_obj_t pin, int value) { + uint32_t i = mp_hal_quiet_timing_enter(); + mp_hal_pin_write(pin, 0); + mp_hal_delay_us_fast(TIMING_WRITE1); + if (value) { + mp_hal_pin_write(pin, 1); + } + mp_hal_delay_us_fast(TIMING_WRITE2); + mp_hal_pin_write(pin, 1); + mp_hal_delay_us_fast(TIMING_WRITE3); + mp_hal_quiet_timing_exit(i); +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC mp_obj_t onewire_reset(mp_obj_t pin_in) { + return mp_obj_new_bool(onewire_bus_reset(mp_hal_get_pin_obj(pin_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_reset_obj, onewire_reset); + +STATIC mp_obj_t onewire_readbit(mp_obj_t pin_in) { + return MP_OBJ_NEW_SMALL_INT(onewire_bus_readbit(mp_hal_get_pin_obj(pin_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbit_obj, onewire_readbit); + +STATIC mp_obj_t onewire_readbyte(mp_obj_t pin_in) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in); + uint8_t value = 0; + for (int i = 0; i < 8; ++i) { + value |= onewire_bus_readbit(pin) << i; + } + return MP_OBJ_NEW_SMALL_INT(value); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbyte_obj, onewire_readbyte); + +STATIC mp_obj_t onewire_writebit(mp_obj_t pin_in, mp_obj_t value_in) { + onewire_bus_writebit(mp_hal_get_pin_obj(pin_in), mp_obj_get_int(value_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebit_obj, onewire_writebit); + +STATIC mp_obj_t onewire_writebyte(mp_obj_t pin_in, mp_obj_t value_in) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in); + int value = mp_obj_get_int(value_in); + for (int i = 0; i < 8; ++i) { + onewire_bus_writebit(pin, value & 1); + value >>= 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebyte_obj, onewire_writebyte); + +STATIC mp_obj_t onewire_crc8(mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + uint8_t crc = 0; + for (size_t i = 0; i < bufinfo.len; ++i) { + uint8_t byte = ((uint8_t*)bufinfo.buf)[i]; + for (int b = 0; b < 8; ++b) { + uint8_t fb_bit = (crc ^ byte) & 0x01; + if (fb_bit == 0x01) { + crc = crc ^ 0x18; + } + crc = (crc >> 1) & 0x7f; + if (fb_bit == 0x01) { + crc = crc | 0x80; + } + byte = byte >> 1; + } + } + return MP_OBJ_NEW_SMALL_INT(crc); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_crc8_obj, onewire_crc8); + +STATIC const mp_rom_map_elem_t onewire_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_onewire) }, + + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&onewire_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_readbit), MP_ROM_PTR(&onewire_readbit_obj) }, + { MP_ROM_QSTR(MP_QSTR_readbyte), MP_ROM_PTR(&onewire_readbyte_obj) }, + { MP_ROM_QSTR(MP_QSTR_writebit), MP_ROM_PTR(&onewire_writebit_obj) }, + { MP_ROM_QSTR(MP_QSTR_writebyte), MP_ROM_PTR(&onewire_writebyte_obj) }, + { MP_ROM_QSTR(MP_QSTR_crc8), MP_ROM_PTR(&onewire_crc8_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(onewire_module_globals, onewire_module_globals_table); + +const mp_obj_module_t mp_module_onewire = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&onewire_module_globals, +}; diff --git a/src/openmv/src/micropython/extmod/modubinascii.c b/src/openmv/src/micropython/extmod/modubinascii.c new file mode 100755 index 0000000..8256a50 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modubinascii.c @@ -0,0 +1,253 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "extmod/modubinascii.h" + +mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { + // Second argument is for an extension to allow a separator to be used + // between values. + const char *sep = NULL; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + + // Code below assumes non-zero buffer length when computing size with + // separator, so handle the zero-length case here. + if (bufinfo.len == 0) { + return mp_const_empty_bytes; + } + + vstr_t vstr; + size_t out_len = bufinfo.len * 2; + if (n_args > 1) { + // 1-char separator between hex numbers + out_len += bufinfo.len - 1; + sep = mp_obj_str_get_str(args[1]); + } + vstr_init_len(&vstr, out_len); + byte *in = bufinfo.buf, *out = (byte*)vstr.buf; + for (mp_uint_t i = bufinfo.len; i--;) { + byte d = (*in >> 4); + if (d > 9) { + d += 'a' - '9' - 1; + } + *out++ = d + '0'; + d = (*in++ & 0xf); + if (d > 9) { + d += 'a' - '9' - 1; + } + *out++ = d + '0'; + if (sep != NULL && i != 0) { + *out++ = *sep; + } + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify); + +mp_obj_t mod_binascii_unhexlify(mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + if ((bufinfo.len & 1) != 0) { + mp_raise_ValueError("odd-length string"); + } + vstr_t vstr; + vstr_init_len(&vstr, bufinfo.len / 2); + byte *in = bufinfo.buf, *out = (byte*)vstr.buf; + byte hex_byte = 0; + for (mp_uint_t i = bufinfo.len; i--;) { + byte hex_ch = *in++; + if (unichar_isxdigit(hex_ch)) { + hex_byte += unichar_xdigit_value(hex_ch); + } else { + mp_raise_ValueError("non-hex digit found"); + } + if (i & 1) { + hex_byte <<= 4; + } else { + *out++ = hex_byte; + hex_byte = 0; + } + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify); + +// If ch is a character in the base64 alphabet, and is not a pad character, then +// the corresponding integer between 0 and 63, inclusively, is returned. +// Otherwise, -1 is returned. +static int mod_binascii_sextet(byte ch) { + if (ch >= 'A' && ch <= 'Z') { + return ch - 'A'; + } else if (ch >= 'a' && ch <= 'z') { + return ch - 'a' + 26; + } else if (ch >= '0' && ch <= '9') { + return ch - '0' + 52; + } else if (ch == '+') { + return 62; + } else if (ch == '/') { + return 63; + } else { + return -1; + } +} + +mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + byte *in = bufinfo.buf; + + vstr_t vstr; + vstr_init(&vstr, (bufinfo.len / 4) * 3 + 1); // Potentially over-allocate + byte *out = (byte *)vstr.buf; + + uint shift = 0; + int nbits = 0; // Number of meaningful bits in shift + bool hadpad = false; // Had a pad character since last valid character + for (size_t i = 0; i < bufinfo.len; i++) { + if (in[i] == '=') { + if ((nbits == 2) || ((nbits == 4) && hadpad)) { + nbits = 0; + break; + } + hadpad = true; + } + + int sextet = mod_binascii_sextet(in[i]); + if (sextet == -1) { + continue; + } + hadpad = false; + shift = (shift << 6) | sextet; + nbits += 6; + + if (nbits >= 8) { + nbits -= 8; + out[vstr.len++] = (shift >> nbits) & 0xFF; + } + } + + if (nbits) { + mp_raise_ValueError("incorrect padding"); + } + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64); + +mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + vstr_t vstr; + vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + 1); + + // First pass, we convert input buffer to numeric base 64 values + byte *in = bufinfo.buf, *out = (byte*)vstr.buf; + mp_uint_t i; + for (i = bufinfo.len; i >= 3; i -= 3) { + *out++ = (in[0] & 0xFC) >> 2; + *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4; + *out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6; + *out++ = in[2] & 0x3F; + in += 3; + } + if (i != 0) { + *out++ = (in[0] & 0xFC) >> 2; + if (i == 2) { + *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4; + *out++ = (in[1] & 0x0F) << 2; + } + else { + *out++ = (in[0] & 0x03) << 4; + *out++ = 64; + } + *out = 64; + } + + // Second pass, we convert number base 64 values to actual base64 ascii encoding + out = (byte*)vstr.buf; + for (mp_uint_t j = vstr.len - 1; j--;) { + if (*out < 26) { + *out += 'A'; + } else if (*out < 52) { + *out += 'a' - 26; + } else if (*out < 62) { + *out += '0' - 52; + } else if (*out == 62) { + *out ='+'; + } else if (*out == 63) { + *out = '/'; + } else { + *out = '='; + } + out++; + } + *out = '\n'; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); + +#if MICROPY_PY_UBINASCII_CRC32 +#include "uzlib/tinf.h" + +mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0; + crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); + return mp_obj_new_int_from_uint(crc ^ 0xffffffff); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); +#endif + +#if MICROPY_PY_UBINASCII + +STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubinascii) }, + { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) }, + { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) }, + { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) }, + { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) }, + #if MICROPY_PY_UBINASCII_CRC32 + { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table); + +const mp_obj_module_t mp_module_ubinascii = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_binascii_globals, +}; + +#endif //MICROPY_PY_UBINASCII diff --git a/src/openmv/src/micropython/extmod/modubinascii.h b/src/openmv/src/micropython/extmod/modubinascii.h new file mode 100755 index 0000000..fb31692 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modubinascii.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H +#define MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H + +extern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args); +extern mp_obj_t mod_binascii_unhexlify(mp_obj_t data); +extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data); +extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data); +extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H diff --git a/src/openmv/src/micropython/extmod/moducryptolib.c b/src/openmv/src/micropython/extmod/moducryptolib.c new file mode 100755 index 0000000..af9eec6 --- /dev/null +++ b/src/openmv/src/micropython/extmod/moducryptolib.c @@ -0,0 +1,292 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Paul Sokolovsky + * Copyright (c) 2018 Yonatan Goldschmidt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +#if MICROPY_PY_UCRYPTOLIB + +#include +#include + +#include "py/runtime.h" + +// This module implements crypto ciphers API, roughly following +// https://www.python.org/dev/peps/pep-0272/ . Exact implementation +// of PEP 272 can be made with a simple wrapper which adds all the +// needed boilerplate. + +// values follow PEP 272 +enum { + UCRYPTOLIB_MODE_MIN = 0, + UCRYPTOLIB_MODE_ECB, + UCRYPTOLIB_MODE_CBC, + UCRYPTOLIB_MODE_MAX, +}; + +#if MICROPY_SSL_AXTLS +#include "lib/axtls/crypto/crypto.h" + +#define AES_CTX_IMPL AES_CTX +#endif + +#if MICROPY_SSL_MBEDTLS +#include + +// we can't run mbedtls AES key schedule until we know whether we're used for encrypt or decrypt. +// therefore, we store the key & keysize and on the first call to encrypt/decrypt we override them +// with the mbedtls_aes_context, as they are not longer required. (this is done to save space) +struct mbedtls_aes_ctx_with_key { + union { + mbedtls_aes_context mbedtls_ctx; + struct { + uint8_t key[32]; + uint8_t keysize; + } init_data; + } u; + unsigned char iv[16]; +}; +#define AES_CTX_IMPL struct mbedtls_aes_ctx_with_key +#endif + +typedef struct _mp_obj_aes_t { + mp_obj_base_t base; + AES_CTX_IMPL ctx; + uint8_t block_mode: 6; +#define AES_KEYTYPE_NONE 0 +#define AES_KEYTYPE_ENC 1 +#define AES_KEYTYPE_DEC 2 + uint8_t key_type: 2; +} mp_obj_aes_t; + +#if MICROPY_SSL_AXTLS +STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) { + assert(16 == keysize || 32 == keysize); + AES_set_key(ctx, key, iv, (16 == keysize) ? AES_MODE_128 : AES_MODE_256); +} + +STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) { + if (!encrypt) { + AES_convert_key(ctx); + } +} + +STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) { + memcpy(out, in, 16); + // We assume that out (vstr.buf or given output buffer) is uint32_t aligned + uint32_t *p = (uint32_t*)out; + // axTLS likes it weird and complicated with byteswaps + for (int i = 0; i < 4; i++) { + p[i] = MP_HTOBE32(p[i]); + } + if (encrypt) { + AES_encrypt(ctx, p); + } else { + AES_decrypt(ctx, p); + } + for (int i = 0; i < 4; i++) { + p[i] = MP_BE32TOH(p[i]); + } +} + +STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) { + if (encrypt) { + AES_cbc_encrypt(ctx, in, out, in_len); + } else { + AES_cbc_decrypt(ctx, in, out, in_len); + } +} +#endif + +#if MICROPY_SSL_MBEDTLS +STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) { + ctx->u.init_data.keysize = keysize; + memcpy(ctx->u.init_data.key, key, keysize); + + if (NULL != iv) { + memcpy(ctx->iv, iv, sizeof(ctx->iv)); + } +} + +STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) { + // first, copy key aside + uint8_t key[32]; + uint8_t keysize = ctx->u.init_data.keysize; + memcpy(key, ctx->u.init_data.key, keysize); + // now, override key with the mbedtls context object + mbedtls_aes_init(&ctx->u.mbedtls_ctx); + + // setkey call will succeed, we've already checked the keysize earlier. + assert(16 == keysize || 32 == keysize); + if (encrypt) { + mbedtls_aes_setkey_enc(&ctx->u.mbedtls_ctx, key, keysize * 8); + } else { + mbedtls_aes_setkey_dec(&ctx->u.mbedtls_ctx, key, keysize * 8); + } +} + +STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) { + mbedtls_aes_crypt_ecb(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in, out); +} + +STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) { + mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out); +} +#endif + +STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + mp_obj_aes_t *o = m_new_obj(mp_obj_aes_t); + o->base.type = type; + + o->block_mode = mp_obj_get_int(args[1]); + o->key_type = AES_KEYTYPE_NONE; + + if (o->block_mode <= UCRYPTOLIB_MODE_MIN || o->block_mode >= UCRYPTOLIB_MODE_MAX) { + mp_raise_ValueError("mode"); + } + + mp_buffer_info_t keyinfo; + mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ); + if (32 != keyinfo.len && 16 != keyinfo.len) { + mp_raise_ValueError("key"); + } + + mp_buffer_info_t ivinfo; + ivinfo.buf = NULL; + if (n_args > 2 && args[2] != mp_const_none) { + mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ); + + if (16 != ivinfo.len) { + mp_raise_ValueError("IV"); + } + } else if (o->block_mode == UCRYPTOLIB_MODE_CBC) { + mp_raise_ValueError("IV"); + } + + aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) { + mp_obj_aes_t *self = MP_OBJ_TO_PTR(args[0]); + + mp_obj_t in_buf = args[1]; + mp_obj_t out_buf = MP_OBJ_NULL; + if (n_args > 2) { + out_buf = args[2]; + } + + mp_buffer_info_t in_bufinfo; + mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ); + + if (in_bufinfo.len % 16 != 0) { + mp_raise_ValueError("blksize % 16"); + } + + vstr_t vstr; + mp_buffer_info_t out_bufinfo; + uint8_t *out_buf_ptr; + + if (out_buf != MP_OBJ_NULL) { + mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE); + if (out_bufinfo.len < in_bufinfo.len) { + mp_raise_ValueError("output too small"); + } + out_buf_ptr = out_bufinfo.buf; + } else { + vstr_init_len(&vstr, in_bufinfo.len); + out_buf_ptr = (uint8_t*)vstr.buf; + } + + if (AES_KEYTYPE_NONE == self->key_type) { + aes_final_set_key_impl(&self->ctx, encrypt); + self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC; + } else { + if ((encrypt && self->key_type == AES_KEYTYPE_DEC) || + (!encrypt && self->key_type == AES_KEYTYPE_ENC)) { + + mp_raise_ValueError("can't encrypt & decrypt"); + } + } + + if (self->block_mode == UCRYPTOLIB_MODE_ECB) { + uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr; + uint8_t *top = in + in_bufinfo.len; + for (; in < top; in += 16, out += 16) { + aes_process_ecb_impl(&self->ctx, in, out, encrypt); + } + } else { + aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt); + } + + if (out_buf != MP_OBJ_NULL) { + return out_buf; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +STATIC mp_obj_t ucryptolib_aes_encrypt(size_t n_args, const mp_obj_t *args) { + return aes_process(n_args, args, true); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_encrypt_obj, 2, 3, ucryptolib_aes_encrypt); + +STATIC mp_obj_t ucryptolib_aes_decrypt(size_t n_args, const mp_obj_t *args) { + return aes_process(n_args, args, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_decrypt_obj, 2, 3, ucryptolib_aes_decrypt); + +STATIC const mp_rom_map_elem_t ucryptolib_aes_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&ucryptolib_aes_encrypt_obj) }, + { MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&ucryptolib_aes_decrypt_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(ucryptolib_aes_locals_dict, ucryptolib_aes_locals_dict_table); + +STATIC const mp_obj_type_t ucryptolib_aes_type = { + { &mp_type_type }, + .name = MP_QSTR_aes, + .make_new = ucryptolib_aes_make_new, + .locals_dict = (void*)&ucryptolib_aes_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_ucryptolib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucryptolib) }, + { MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&ucryptolib_aes_type) }, +#if MICROPY_PY_UCRYPTOLIB_CONSTS + { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) }, + { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ucryptolib_globals, mp_module_ucryptolib_globals_table); + +const mp_obj_module_t mp_module_ucryptolib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ucryptolib_globals, +}; + +#endif //MICROPY_PY_UCRYPTOLIB diff --git a/src/openmv/src/micropython/extmod/moductypes.c b/src/openmv/src/micropython/extmod/moductypes.c new file mode 100755 index 0000000..4baf36e --- /dev/null +++ b/src/openmv/src/micropython/extmod/moductypes.c @@ -0,0 +1,734 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/binary.h" + +#if MICROPY_PY_UCTYPES + +/// \module uctypes - Access data structures in memory +/// +/// The module allows to define layout of raw data structure (using terms +/// of C language), and then access memory buffers using this definition. +/// The module also provides convenience functions to access memory buffers +/// contained in Python objects or wrap memory buffers in Python objects. +/// \constant UINT8_1 - uint8_t value type + +/// \class struct - C-like structure +/// +/// Encapsulalation of in-memory data structure. This class doesn't define +/// any methods, only attribute access (for structure fields) and +/// indexing (for pointer and array fields). +/// +/// Usage: +/// +/// # Define layout of a structure with 2 fields +/// # 0 and 4 are byte offsets of fields from the beginning of struct +/// # they are logically ORed with field type +/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8} +/// +/// # Example memory buffer to access (contained in bytes object) +/// buf = b"\x64\0\0\0\0x14" +/// +/// # Create structure object referring to address of +/// # the data in the buffer above +/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf)) +/// +/// # Access fields +/// print(s.a, s.b) +/// # Result: +/// # 100, 20 + +#define LAYOUT_LITTLE_ENDIAN (0) +#define LAYOUT_BIG_ENDIAN (1) +#define LAYOUT_NATIVE (2) + +#define VAL_TYPE_BITS 4 +#define BITF_LEN_BITS 5 +#define BITF_OFF_BITS 5 +#define OFFSET_BITS 17 +#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31 +#error Invalid encoding field length +#endif + +enum { + UINT8, INT8, UINT16, INT16, + UINT32, INT32, UINT64, INT64, + + BFUINT8, BFINT8, BFUINT16, BFINT16, + BFUINT32, BFINT32, + + FLOAT32, FLOAT64, +}; + +#define AGG_TYPE_BITS 2 + +enum { + STRUCT, PTR, ARRAY, +}; + +// Here we need to set sign bit right +#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1) +#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1)) +// Bit 0 is "is_signed" +#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1)) +#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits) + +#define IS_SCALAR_ARRAY(tuple_desc) ((tuple_desc)->len == 2) +// We cannot apply the below to INT8, as their range [-128, 127] +#define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8) + +// "struct" in uctypes context means "structural", i.e. aggregate, type. +STATIC const mp_obj_type_t uctypes_struct_type; + +typedef struct _mp_obj_uctypes_struct_t { + mp_obj_base_t base; + mp_obj_t desc; + byte *addr; + uint32_t flags; +} mp_obj_uctypes_struct_t; + +STATIC NORETURN void syntax_error(void) { + mp_raise_TypeError("syntax error in uctypes descriptor"); +} + +STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); + o->base.type = type; + o->addr = (void*)(uintptr_t)mp_obj_int_get_truncated(args[0]); + o->desc = args[1]; + o->flags = LAYOUT_NATIVE; + if (n_args == 3) { + o->flags = mp_obj_get_int(args[2]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); + const char *typen = "unk"; + if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + || MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + #endif + ) { + typen = "STRUCT"; + } else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); + mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); + uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); + switch (agg_type) { + case PTR: typen = "PTR"; break; + case ARRAY: typen = "ARRAY"; break; + } + } else { + typen = "ERROR"; + } + mp_printf(print, "", typen, self->addr); +} + +// Get size of any type descriptor +STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size); + +// Get size of scalar type descriptor +static inline mp_uint_t uctypes_struct_scalar_size(int val_type) { + if (val_type == FLOAT32) { + return 4; + } else { + return GET_SCALAR_SIZE(val_type & 7); + } +} + +// Get size of aggregate type descriptor +STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_uint_t *max_field_size) { + mp_uint_t total_size = 0; + + mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]); + mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS); + + switch (agg_type) { + case STRUCT: + return uctypes_struct_size(t->items[1], layout_type, max_field_size); + case PTR: + if (sizeof(void*) > *max_field_size) { + *max_field_size = sizeof(void*); + } + return sizeof(void*); + case ARRAY: { + mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]); + uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); + arr_sz &= VALUE_MASK(VAL_TYPE_BITS); + mp_uint_t item_s; + if (t->len == 2) { + // Elements of array are scalar + item_s = GET_SCALAR_SIZE(val_type); + if (item_s > *max_field_size) { + *max_field_size = item_s; + } + } else { + // Elements of array are aggregates + item_s = uctypes_struct_size(t->items[2], layout_type, max_field_size); + } + + return item_s * arr_sz; + } + default: + assert(0); + } + + return total_size; +} + +STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) { + if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict) + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + && !MP_OBJ_IS_TYPE(desc_in, &mp_type_ordereddict) + #endif + ) { + if (MP_OBJ_IS_TYPE(desc_in, &mp_type_tuple)) { + return uctypes_struct_agg_size((mp_obj_tuple_t*)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size); + } else if (MP_OBJ_IS_SMALL_INT(desc_in)) { + // We allow sizeof on both type definitions and structures/structure fields, + // but scalar structure field is lowered into native Python int, so all + // type info is lost. So, we cannot say if it's scalar type description, + // or such lowered scalar. + mp_raise_TypeError("Cannot unambiguously get sizeof scalar"); + } + syntax_error(); + } + + mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in); + mp_uint_t total_size = 0; + + for (mp_uint_t i = 0; i < d->map.alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) { + mp_obj_t v = d->map.table[i].value; + if (MP_OBJ_IS_SMALL_INT(v)) { + mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v); + mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); + offset &= VALUE_MASK(VAL_TYPE_BITS); + if (val_type >= BFUINT8 && val_type <= BFINT32) { + offset &= (1 << OFFSET_BITS) - 1; + } + mp_uint_t s = uctypes_struct_scalar_size(val_type); + if (s > *max_field_size) { + *max_field_size = s; + } + if (offset + s > total_size) { + total_size = offset + s; + } + } else { + if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) { + syntax_error(); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v); + mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); + offset &= VALUE_MASK(AGG_TYPE_BITS); + mp_uint_t s = uctypes_struct_agg_size(t, layout_type, max_field_size); + if (offset + s > total_size) { + total_size = offset + s; + } + } + } + } + + // Round size up to alignment of biggest field + if (layout_type == LAYOUT_NATIVE) { + total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1); + } + return total_size; +} + +STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { + mp_obj_t obj_in = args[0]; + mp_uint_t max_field_size = 0; + if (MP_OBJ_IS_TYPE(obj_in, &mp_type_bytearray)) { + return mp_obj_len(obj_in); + } + int layout_type = LAYOUT_NATIVE; + // We can apply sizeof either to structure definition (a dict) + // or to instantiated structure + if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) { + if (n_args != 1) { + mp_raise_TypeError(NULL); + } + // Extract structure definition + mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in); + obj_in = obj->desc; + layout_type = obj->flags; + } else { + if (n_args == 2) { + layout_type = mp_obj_get_int(args[1]); + } + } + mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size); + return MP_OBJ_NEW_SMALL_INT(size); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof); + +static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { + char struct_type = big_endian ? '>' : '<'; + static const char type2char[16] = "BbHhIiQq------fd"; + return mp_binary_get_val(struct_type, type2char[val_type], &p); +} + +static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { + char struct_type = big_endian ? '>' : '<'; + static const char type2char[16] = "BbHhIiQq------fd"; + mp_binary_set_val(struct_type, type2char[val_type], val, &p); +} + +static inline mp_uint_t get_aligned_basic(uint val_type, void *p) { + switch (val_type) { + case UINT8: + return *(uint8_t*)p; + case UINT16: + return *(uint16_t*)p; + case UINT32: + return *(uint32_t*)p; + } + assert(0); + return 0; +} + +static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) { + switch (val_type) { + case UINT8: + *(uint8_t*)p = (uint8_t)v; return; + case UINT16: + *(uint16_t*)p = (uint16_t)v; return; + case UINT32: + *(uint32_t*)p = (uint32_t)v; return; + } + assert(0); +} + +STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) { + switch (val_type) { + case UINT8: + return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]); + case INT8: + return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]); + case UINT16: + return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]); + case INT16: + return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]); + case UINT32: + return mp_obj_new_int_from_uint(((uint32_t*)p)[index]); + case INT32: + return mp_obj_new_int(((int32_t*)p)[index]); + case UINT64: + return mp_obj_new_int_from_ull(((uint64_t*)p)[index]); + case INT64: + return mp_obj_new_int_from_ll(((int64_t*)p)[index]); + #if MICROPY_PY_BUILTINS_FLOAT + case FLOAT32: + return mp_obj_new_float(((float*)p)[index]); + case FLOAT64: + return mp_obj_new_float(((double*)p)[index]); + #endif + default: + assert(0); + return MP_OBJ_NULL; + } +} + +STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { + #if MICROPY_PY_BUILTINS_FLOAT + if (val_type == FLOAT32 || val_type == FLOAT64) { + mp_float_t v = mp_obj_get_float(val); + if (val_type == FLOAT32) { + ((float*)p)[index] = v; + } else { + ((double*)p)[index] = v; + } + return; + } + #endif + mp_int_t v = mp_obj_get_int_truncated(val); + switch (val_type) { + case UINT8: + ((uint8_t*)p)[index] = (uint8_t)v; return; + case INT8: + ((int8_t*)p)[index] = (int8_t)v; return; + case UINT16: + ((uint16_t*)p)[index] = (uint16_t)v; return; + case INT16: + ((int16_t*)p)[index] = (int16_t)v; return; + case UINT32: + ((uint32_t*)p)[index] = (uint32_t)v; return; + case INT32: + ((int32_t*)p)[index] = (int32_t)v; return; + case INT64: + case UINT64: + if (sizeof(mp_int_t) == 8) { + ((uint64_t*)p)[index] = (uint64_t)v; + } else { + // TODO: Doesn't offer atomic store semantics, but should at least try + set_unaligned(val_type, p, MP_ENDIANNESS_BIG, val); + } + return; + default: + assert(0); + } +} + +STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) { + mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); + + if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict) + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + && !MP_OBJ_IS_TYPE(self->desc, &mp_type_ordereddict) + #endif + ) { + mp_raise_TypeError("struct: no fields"); + } + + mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); + if (MP_OBJ_IS_SMALL_INT(deref)) { + mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref); + mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); + offset &= VALUE_MASK(VAL_TYPE_BITS); +//printf("scalar type=%d offset=%x\n", val_type, offset); + + if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) { +// printf("size=%d\n", GET_SCALAR_SIZE(val_type)); + if (self->flags == LAYOUT_NATIVE) { + if (set_val == MP_OBJ_NULL) { + return get_aligned(val_type, self->addr + offset, 0); + } else { + set_aligned(val_type, self->addr + offset, 0, set_val); + return set_val; // just !MP_OBJ_NULL + } + } else { + if (set_val == MP_OBJ_NULL) { + return get_unaligned(val_type, self->addr + offset, self->flags); + } else { + set_unaligned(val_type, self->addr + offset, self->flags, set_val); + return set_val; // just !MP_OBJ_NULL + } + } + } else if (val_type >= BFUINT8 && val_type <= BFINT32) { + uint bit_offset = (offset >> 17) & 31; + uint bit_len = (offset >> 22) & 31; + offset &= (1 << 17) - 1; + mp_uint_t val; + if (self->flags == LAYOUT_NATIVE) { + val = get_aligned_basic(val_type & 6, self->addr + offset); + } else { + val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset); + } + if (set_val == MP_OBJ_NULL) { + val >>= bit_offset; + val &= (1 << bit_len) - 1; + // TODO: signed + assert((val_type & 1) == 0); + return mp_obj_new_int(val); + } else { + mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val); + mp_uint_t mask = (1 << bit_len) - 1; + set_val_int &= mask; + set_val_int <<= bit_offset; + mask <<= bit_offset; + val = (val & ~mask) | set_val_int; + + if (self->flags == LAYOUT_NATIVE) { + set_aligned_basic(val_type & 6, self->addr + offset, val); + } else { + mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN, + self->addr + offset, val); + } + return set_val; // just !MP_OBJ_NULL + } + } + + assert(0); + return MP_OBJ_NULL; + } + + if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) { + syntax_error(); + } + + if (set_val != MP_OBJ_NULL) { + // Cannot assign to aggregate + syntax_error(); + } + + mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref); + mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]); + mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS); + offset &= VALUE_MASK(AGG_TYPE_BITS); +//printf("agg type=%d offset=%x\n", agg_type, offset); + + switch (agg_type) { + case STRUCT: { + mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); + o->base.type = &uctypes_struct_type; + o->desc = sub->items[1]; + o->addr = self->addr + offset; + o->flags = self->flags; + return MP_OBJ_FROM_PTR(o); + } + case ARRAY: { + mp_uint_t dummy; + if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) { + return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset); + } + // Fall thru to return uctypes struct object + } + case PTR: { + mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); + o->base.type = &uctypes_struct_type; + o->desc = MP_OBJ_FROM_PTR(sub); + o->addr = self->addr + offset; + o->flags = self->flags; +//printf("PTR/ARR base addr=%p\n", o->addr); + return MP_OBJ_FROM_PTR(o); + } + } + + // Should be unreachable once all cases are handled + return MP_OBJ_NULL; +} + +STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL); + dest[0] = val; + } else { + // delete/store attribute + if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } +} + +STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { + mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); + + if (value == MP_OBJ_NULL) { + // delete + return MP_OBJ_NULL; // op not supported + } else { + // load / store + if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) { + mp_raise_TypeError("struct: cannot index"); + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); + mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); + uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); + + mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in); + + if (agg_type == ARRAY) { + mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]); + uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); + arr_sz &= VALUE_MASK(VAL_TYPE_BITS); + if (index >= arr_sz) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range")); + } + + if (t->len == 2) { + // array of scalars + if (self->flags == LAYOUT_NATIVE) { + if (value == MP_OBJ_SENTINEL) { + return get_aligned(val_type, self->addr, index); + } else { + set_aligned(val_type, self->addr, index, value); + return value; // just !MP_OBJ_NULL + } + } else { + byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index; + if (value == MP_OBJ_SENTINEL) { + return get_unaligned(val_type, p, self->flags); + } else { + set_unaligned(val_type, p, self->flags, value); + return value; // just !MP_OBJ_NULL + } + } + } else if (value == MP_OBJ_SENTINEL) { + mp_uint_t dummy = 0; + mp_uint_t size = uctypes_struct_size(t->items[2], self->flags, &dummy); + mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); + o->base.type = &uctypes_struct_type; + o->desc = t->items[2]; + o->addr = self->addr + size * index; + o->flags = self->flags; + return MP_OBJ_FROM_PTR(o); + } else { + return MP_OBJ_NULL; // op not supported + } + + } else if (agg_type == PTR) { + byte *p = *(void**)self->addr; + if (MP_OBJ_IS_SMALL_INT(t->items[1])) { + uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS); + return get_aligned(val_type, p, index); + } else { + mp_uint_t dummy = 0; + mp_uint_t size = uctypes_struct_size(t->items[1], self->flags, &dummy); + mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); + o->base.type = &uctypes_struct_type; + o->desc = t->items[1]; + o->addr = p + size * index; + o->flags = self->flags; + return MP_OBJ_FROM_PTR(o); + } + } + + assert(0); + return MP_OBJ_NULL; + } +} + +STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + (void)flags; + mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t max_field_size = 0; + mp_uint_t size = uctypes_struct_size(self->desc, self->flags, &max_field_size); + + bufinfo->buf = self->addr; + bufinfo->len = size; + bufinfo->typecode = BYTEARRAY_TYPECODE; + return 0; +} + +/// \function addressof() +/// Return address of object's data (applies to object providing buffer +/// interface). +STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + return mp_obj_new_int((mp_int_t)(uintptr_t)bufinfo.buf); +} +MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof); + +/// \function bytearray_at() +/// Capture memory at given address of given size as bytearray. Memory is +/// captured by reference (and thus memory pointed by bytearray may change +/// or become invalid at later time). Use bytes_at() to capture by value. +STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) { + return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void*)(uintptr_t)mp_obj_int_get_truncated(ptr)); +} +MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at); + +/// \function bytes_at() +/// Capture memory at given address of given size as bytes. Memory is +/// captured by value, i.e. copied. Use bytearray_at() to capture by reference +/// ("zero copy"). +STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) { + return mp_obj_new_bytes((void*)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size)); +} +MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at); + + +STATIC const mp_obj_type_t uctypes_struct_type = { + { &mp_type_type }, + .name = MP_QSTR_struct, + .print = uctypes_struct_print, + .make_new = uctypes_struct_make_new, + .attr = uctypes_struct_attr, + .subscr = uctypes_struct_subscr, + .buffer_p = { .get_buffer = uctypes_get_buffer }, +}; + +STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uctypes) }, + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&uctypes_struct_type) }, + { MP_ROM_QSTR(MP_QSTR_sizeof), MP_ROM_PTR(&uctypes_struct_sizeof_obj) }, + { MP_ROM_QSTR(MP_QSTR_addressof), MP_ROM_PTR(&uctypes_struct_addressof_obj) }, + { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) }, + { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) }, + + /// \moduleref uctypes + + /// \constant NATIVE - Native structure layout - native endianness, + /// platform-specific field alignment + { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) }, + /// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed + /// (no alignment constraints) + { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) }, + /// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed + /// (no alignment constraints) + { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) }, + + /// \constant VOID - void value type, may be used only as pointer target type. + { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) }, + + /// \constant UINT8 - uint8_t value type + { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) }, + /// \constant INT8 - int8_t value type + { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) }, + /// \constant UINT16 - uint16_t value type + { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) }, + /// \constant INT16 - int16_t value type + { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) }, + /// \constant UINT32 - uint32_t value type + { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, + /// \constant INT32 - int32_t value type + { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, + /// \constant UINT64 - uint64_t value type + { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, + /// \constant INT64 - int64_t value type + { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, + + { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) }, + { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) }, + { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) }, + { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) }, + { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) }, + { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) }, + + { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) }, + { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) }, + + #if MICROPY_PY_BUILTINS_FLOAT + { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) }, + { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) }, + #endif + + { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) }, + { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table); + +const mp_obj_module_t mp_module_uctypes = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_uctypes_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/extmod/moduhashlib.c b/src/openmv/src/micropython/extmod/moduhashlib.c new file mode 100755 index 0000000..50df7ca --- /dev/null +++ b/src/openmv/src/micropython/extmod/moduhashlib.c @@ -0,0 +1,351 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_UHASHLIB + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/version.h" +#endif + +#if MICROPY_PY_UHASHLIB_SHA256 + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/sha256.h" +#else +#include "crypto-algorithms/sha256.h" +#endif + +#endif + +#if MICROPY_PY_UHASHLIB_SHA1 || MICROPY_PY_UHASHLIB_MD5 + +#if MICROPY_SSL_AXTLS +#include "lib/axtls/crypto/crypto.h" +#endif + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/md5.h" +#include "mbedtls/sha1.h" +#endif + +#endif + +typedef struct _mp_obj_hash_t { + mp_obj_base_t base; + char state[0]; +} mp_obj_hash_t; + +#if MICROPY_PY_UHASHLIB_SHA256 +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); + +#if MICROPY_SSL_MBEDTLS + +#if MBEDTLS_VERSION_NUMBER < 0x02070000 +#define mbedtls_sha256_starts_ret mbedtls_sha256_starts +#define mbedtls_sha256_update_ret mbedtls_sha256_update +#define mbedtls_sha256_finish_ret mbedtls_sha256_finish +#endif + +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context)); + o->base.type = type; + mbedtls_sha256_init((mbedtls_sha256_context*)&o->state); + mbedtls_sha256_starts_ret((mbedtls_sha256_context*)&o->state, 0); + if (n_args == 1) { + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha256_update_ret((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 32); + mbedtls_sha256_finish_ret((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +#else + +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); + o->base.type = type; + sha256_init((CRYAL_SHA256_CTX*)o->state); + if (n_args == 1) { + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, SHA256_BLOCK_SIZE); + sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); + +STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table); + +STATIC const mp_obj_type_t uhashlib_sha256_type = { + { &mp_type_type }, + .name = MP_QSTR_sha256, + .make_new = uhashlib_sha256_make_new, + .locals_dict = (void*)&uhashlib_sha256_locals_dict, +}; +#endif + +#if MICROPY_PY_UHASHLIB_SHA1 +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); + +#if MICROPY_SSL_AXTLS +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); + o->base.type = type; + SHA1_Init((SHA1_CTX*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, SHA1_SIZE); + SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +#if MICROPY_SSL_MBEDTLS + +#if MBEDTLS_VERSION_NUMBER < 0x02070000 +#define mbedtls_sha1_starts_ret mbedtls_sha1_starts +#define mbedtls_sha1_update_ret mbedtls_sha1_update +#define mbedtls_sha1_finish_ret mbedtls_sha1_finish +#endif + +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); + o->base.type = type; + mbedtls_sha1_init((mbedtls_sha1_context*)o->state); + mbedtls_sha1_starts_ret((mbedtls_sha1_context*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha1_update_ret((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 20); + mbedtls_sha1_finish_ret((mbedtls_sha1_context*)self->state, (byte*)vstr.buf); + mbedtls_sha1_free((mbedtls_sha1_context*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); + +STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table); + +STATIC const mp_obj_type_t uhashlib_sha1_type = { + { &mp_type_type }, + .name = MP_QSTR_sha1, + .make_new = uhashlib_sha1_make_new, + .locals_dict = (void*)&uhashlib_sha1_locals_dict, +}; +#endif + +#if MICROPY_PY_UHASHLIB_MD5 +STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg); + +#if MICROPY_SSL_AXTLS +STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX)); + o->base.type = type; + MD5_Init((MD5_CTX*)o->state); + if (n_args == 1) { + uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + MD5_Update((MD5_CTX*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, MD5_SIZE); + MD5_Final((byte*)vstr.buf, (MD5_CTX*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif // MICROPY_SSL_AXTLS + +#if MICROPY_SSL_MBEDTLS + +#if MBEDTLS_VERSION_NUMBER < 0x02070000 +#define mbedtls_md5_starts_ret mbedtls_md5_starts +#define mbedtls_md5_update_ret mbedtls_md5_update +#define mbedtls_md5_finish_ret mbedtls_md5_finish +#endif + +STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context)); + o->base.type = type; + mbedtls_md5_init((mbedtls_md5_context*)o->state); + mbedtls_md5_starts_ret((mbedtls_md5_context*)o->state); + if (n_args == 1) { + uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_md5_update_ret((mbedtls_md5_context*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 16); + mbedtls_md5_finish_ret((mbedtls_md5_context*)self->state, (byte*)vstr.buf); + mbedtls_md5_free((mbedtls_md5_context*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif // MICROPY_SSL_MBEDTLS + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_md5_update_obj, uhashlib_md5_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_md5_digest_obj, uhashlib_md5_digest); + +STATIC const mp_rom_map_elem_t uhashlib_md5_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_md5_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_md5_digest_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(uhashlib_md5_locals_dict, uhashlib_md5_locals_dict_table); + +STATIC const mp_obj_type_t uhashlib_md5_type = { + { &mp_type_type }, + .name = MP_QSTR_md5, + .make_new = uhashlib_md5_make_new, + .locals_dict = (void*)&uhashlib_md5_locals_dict, +}; +#endif // MICROPY_PY_UHASHLIB_MD5 + +STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, + #if MICROPY_PY_UHASHLIB_SHA256 + { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) }, + #endif + #if MICROPY_PY_UHASHLIB_SHA1 + { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) }, + #endif + #if MICROPY_PY_UHASHLIB_MD5 + { MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&uhashlib_md5_type) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table); + +const mp_obj_module_t mp_module_uhashlib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals, +}; + +#if MICROPY_PY_UHASHLIB_SHA256 +#include "crypto-algorithms/sha256.c" +#endif + +#endif //MICROPY_PY_UHASHLIB diff --git a/src/openmv/src/micropython/extmod/moduheapq.c b/src/openmv/src/micropython/extmod/moduheapq.c new file mode 100755 index 0000000..71c1536 --- /dev/null +++ b/src/openmv/src/micropython/extmod/moduheapq.c @@ -0,0 +1,120 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objlist.h" +#include "py/runtime.h" + +#if MICROPY_PY_UHEAPQ + +// the algorithm here is modelled on CPython's heapq.py + +STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) { + if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) { + mp_raise_TypeError("heap must be a list"); + } + return MP_OBJ_TO_PTR(heap_in); +} + +STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) { + mp_obj_t item = heap->items[pos]; + while (pos > start_pos) { + mp_uint_t parent_pos = (pos - 1) >> 1; + mp_obj_t parent = heap->items[parent_pos]; + if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) { + heap->items[pos] = parent; + pos = parent_pos; + } else { + break; + } + } + heap->items[pos] = item; +} + +STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) { + mp_uint_t start_pos = pos; + mp_uint_t end_pos = heap->len; + mp_obj_t item = heap->items[pos]; + for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) { + // choose right child if it's <= left child + if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) { + child_pos += 1; + } + // bubble up the smaller child + heap->items[pos] = heap->items[child_pos]; + pos = child_pos; + } + heap->items[pos] = item; + heap_siftdown(heap, start_pos, pos); +} + +STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) { + mp_obj_list_t *heap = get_heap(heap_in); + mp_obj_list_append(heap_in, item); + heap_siftdown(heap, 0, heap->len - 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush); + +STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { + mp_obj_list_t *heap = get_heap(heap_in); + if (heap->len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + } + mp_obj_t item = heap->items[0]; + heap->len -= 1; + heap->items[0] = heap->items[heap->len]; + heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer + if (heap->len) { + heap_siftup(heap, 0); + } + return item; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop); + +STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) { + mp_obj_list_t *heap = get_heap(heap_in); + for (mp_uint_t i = heap->len / 2; i > 0;) { + heap_siftup(heap, --i); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify); + +STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) }, + { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) }, + { MP_ROM_QSTR(MP_QSTR_heappop), MP_ROM_PTR(&mod_uheapq_heappop_obj) }, + { MP_ROM_QSTR(MP_QSTR_heapify), MP_ROM_PTR(&mod_uheapq_heapify_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uheapq_globals, mp_module_uheapq_globals_table); + +const mp_obj_module_t mp_module_uheapq = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals, +}; + +#endif //MICROPY_PY_UHEAPQ diff --git a/src/openmv/src/micropython/extmod/modujson.c b/src/openmv/src/micropython/extmod/modujson.c new file mode 100755 index 0000000..830b588 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modujson.c @@ -0,0 +1,307 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objlist.h" +#include "py/objstringio.h" +#include "py/parsenum.h" +#include "py/runtime.h" +#include "py/stream.h" + +#if MICROPY_PY_UJSON + +STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { + mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, obj, PRINT_JSON); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); + +STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 8, &print); + mp_obj_print_helper(&print, obj, PRINT_JSON); + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); + +// The function below implements a simple non-recursive JSON parser. +// +// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt +// The parser here will parse any valid JSON and return the correct +// corresponding Python object. It allows through a superset of JSON, since +// it treats commas and colons as "whitespace", and doesn't care if +// brackets/braces are correctly paired. It will raise a ValueError if the +// input is outside it's specs. +// +// Most of the work is parsing the primitives (null, false, true, numbers, +// strings). It does 1 pass over the input stream. It tries to be fast and +// small in code size, while not using more RAM than necessary. + +typedef struct _ujson_stream_t { + mp_obj_t stream_obj; + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + int errcode; + byte cur; +} ujson_stream_t; + +#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker +#define S_END(s) ((s).cur == S_EOF) +#define S_CUR(s) ((s).cur) +#define S_NEXT(s) (ujson_stream_next(&(s))) + +STATIC byte ujson_stream_next(ujson_stream_t *s) { + mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode); + if (s->errcode != 0) { + mp_raise_OSError(s->errcode); + } + if (ret == 0) { + s->cur = S_EOF; + } + return s->cur; +} + +STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ); + ujson_stream_t s = {stream_obj, stream_p->read, 0, 0}; + vstr_t vstr; + vstr_init(&vstr, 8); + mp_obj_list_t stack; // we use a list as a simple stack for nested JSON + stack.len = 0; + stack.items = NULL; + mp_obj_t stack_top = MP_OBJ_NULL; + mp_obj_type_t *stack_top_type = NULL; + mp_obj_t stack_key = MP_OBJ_NULL; + S_NEXT(s); + for (;;) { + cont: + if (S_END(s)) { + break; + } + mp_obj_t next = MP_OBJ_NULL; + bool enter = false; + byte cur = S_CUR(s); + S_NEXT(s); + switch (cur) { + case ',': + case ':': + case ' ': + case '\t': + case '\n': + case '\r': + goto cont; + case 'n': + if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') { + S_NEXT(s); + next = mp_const_none; + } else { + goto fail; + } + break; + case 'f': + if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') { + S_NEXT(s); + next = mp_const_false; + } else { + goto fail; + } + break; + case 't': + if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') { + S_NEXT(s); + next = mp_const_true; + } else { + goto fail; + } + break; + case '"': + vstr_reset(&vstr); + for (; !S_END(s) && S_CUR(s) != '"';) { + byte c = S_CUR(s); + if (c == '\\') { + c = S_NEXT(s); + switch (c) { + case 'b': c = 0x08; break; + case 'f': c = 0x0c; break; + case 'n': c = 0x0a; break; + case 'r': c = 0x0d; break; + case 't': c = 0x09; break; + case 'u': { + mp_uint_t num = 0; + for (int i = 0; i < 4; i++) { + c = (S_NEXT(s) | 0x20) - '0'; + if (c > 9) { + c -= ('a' - ('9' + 1)); + } + num = (num << 4) | c; + } + vstr_add_char(&vstr, num); + goto str_cont; + } + } + } + vstr_add_byte(&vstr, c); + str_cont: + S_NEXT(s); + } + if (S_END(s)) { + goto fail; + } + S_NEXT(s); + next = mp_obj_new_str(vstr.buf, vstr.len); + break; + case '-': + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { + bool flt = false; + vstr_reset(&vstr); + for (;;) { + vstr_add_byte(&vstr, cur); + cur = S_CUR(s); + if (cur == '.' || cur == 'E' || cur == 'e') { + flt = true; + } else if (cur == '-' || unichar_isdigit(cur)) { + // pass + } else { + break; + } + S_NEXT(s); + } + if (flt) { + next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL); + } else { + next = mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); + } + break; + } + case '[': + next = mp_obj_new_list(0, NULL); + enter = true; + break; + case '{': + next = mp_obj_new_dict(0); + enter = true; + break; + case '}': + case ']': { + if (stack_top == MP_OBJ_NULL) { + // no object at all + goto fail; + } + if (stack.len == 0) { + // finished; compound object + goto success; + } + stack.len -= 1; + stack_top = stack.items[stack.len]; + stack_top_type = mp_obj_get_type(stack_top); + goto cont; + } + default: + goto fail; + } + if (stack_top == MP_OBJ_NULL) { + stack_top = next; + stack_top_type = mp_obj_get_type(stack_top); + if (!enter) { + // finished; single primitive only + goto success; + } + } else { + // append to list or dict + if (stack_top_type == &mp_type_list) { + mp_obj_list_append(stack_top, next); + } else { + if (stack_key == MP_OBJ_NULL) { + stack_key = next; + if (enter) { + goto fail; + } + } else { + mp_obj_dict_store(stack_top, stack_key, next); + stack_key = MP_OBJ_NULL; + } + } + if (enter) { + if (stack.items == NULL) { + mp_obj_list_init(&stack, 1); + stack.items[0] = stack_top; + } else { + mp_obj_list_append(MP_OBJ_FROM_PTR(&stack), stack_top); + } + stack_top = next; + stack_top_type = mp_obj_get_type(stack_top); + } + } + } + success: + // eat trailing whitespace + while (unichar_isspace(S_CUR(s))) { + S_NEXT(s); + } + if (!S_END(s)) { + // unexpected chars + goto fail; + } + if (stack_top == MP_OBJ_NULL || stack.len != 0) { + // not exactly 1 object + goto fail; + } + vstr_clear(&vstr); + return stack_top; + + fail: + mp_raise_ValueError("syntax error in JSON"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); + +STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { + size_t len; + const char *buf = mp_obj_str_get_data(obj, &len); + vstr_t vstr = {len, len, (char*)buf, true}; + mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL}; + return mod_ujson_load(MP_OBJ_FROM_PTR(&sio)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); + +STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) }, + { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, + { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, + { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ujson_globals, mp_module_ujson_globals_table); + +const mp_obj_module_t mp_module_ujson = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ujson_globals, +}; + +#endif //MICROPY_PY_UJSON diff --git a/src/openmv/src/micropython/extmod/modurandom.c b/src/openmv/src/micropython/extmod/modurandom.c new file mode 100755 index 0000000..1512a3f --- /dev/null +++ b/src/openmv/src/micropython/extmod/modurandom.c @@ -0,0 +1,225 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_URANDOM + +// Yasmarang random number generator +// by Ilya Levin +// http://www.literatecode.com/yasmarang +// Public Domain + +STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233; +STATIC uint8_t yasmarang_dat = 0; + +STATIC uint32_t yasmarang(void) +{ + yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n; + yasmarang_pad = (yasmarang_pad<<3) + (yasmarang_pad>>29); + yasmarang_n = yasmarang_pad | 2; + yasmarang_d ^= (yasmarang_pad<<31) + (yasmarang_pad>>1); + yasmarang_dat ^= (char) yasmarang_pad ^ (yasmarang_d>>8) ^ 1; + + return (yasmarang_pad^(yasmarang_d<<5)^(yasmarang_pad>>18)^(yasmarang_dat<<1)); +} /* yasmarang */ + +// End of Yasmarang + +#if MICROPY_PY_URANDOM_EXTRA_FUNCS + +// returns an unsigned integer below the given argument +// n must not be zero +STATIC uint32_t yasmarang_randbelow(uint32_t n) { + uint32_t mask = 1; + while ((n & mask) < n) { + mask = (mask << 1) | 1; + } + uint32_t r; + do { + r = yasmarang() & mask; + } while (r >= n); + return r; +} + +#endif + +STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) { + int n = mp_obj_get_int(num_in); + if (n > 32 || n == 0) { + mp_raise_ValueError(NULL); + } + uint32_t mask = ~0; + // Beware of C undefined behavior when shifting by >= than bit size + mask >>= (32 - n); + return mp_obj_new_int_from_uint(yasmarang() & mask); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits); + +STATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) { + mp_uint_t seed = mp_obj_get_int_truncated(seed_in); + yasmarang_pad = seed; + yasmarang_n = 69; + yasmarang_d = 233; + yasmarang_dat = 0; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_seed_obj, mod_urandom_seed); + +#if MICROPY_PY_URANDOM_EXTRA_FUNCS + +STATIC mp_obj_t mod_urandom_randrange(size_t n_args, const mp_obj_t *args) { + mp_int_t start = mp_obj_get_int(args[0]); + if (n_args == 1) { + // range(stop) + if (start > 0) { + return mp_obj_new_int(yasmarang_randbelow(start)); + } else { + goto error; + } + } else { + mp_int_t stop = mp_obj_get_int(args[1]); + if (n_args == 2) { + // range(start, stop) + if (start < stop) { + return mp_obj_new_int(start + yasmarang_randbelow(stop - start)); + } else { + goto error; + } + } else { + // range(start, stop, step) + mp_int_t step = mp_obj_get_int(args[2]); + mp_int_t n; + if (step > 0) { + n = (stop - start + step - 1) / step; + } else if (step < 0) { + n = (stop - start + step + 1) / step; + } else { + goto error; + } + if (n > 0) { + return mp_obj_new_int(start + step * yasmarang_randbelow(n)); + } else { + goto error; + } + } + } + +error: + mp_raise_ValueError(NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_randrange_obj, 1, 3, mod_urandom_randrange); + +STATIC mp_obj_t mod_urandom_randint(mp_obj_t a_in, mp_obj_t b_in) { + mp_int_t a = mp_obj_get_int(a_in); + mp_int_t b = mp_obj_get_int(b_in); + if (a <= b) { + return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1)); + } else { + mp_raise_ValueError(NULL); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_randint_obj, mod_urandom_randint); + +STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) { + mp_int_t len = mp_obj_get_int(mp_obj_len(seq)); + if (len > 0) { + return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL); + } else { + nlr_raise(mp_obj_new_exception(&mp_type_IndexError)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice); + +#if MICROPY_PY_BUILTINS_FLOAT + +// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits +STATIC mp_float_t yasmarang_float(void) { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + typedef uint64_t mp_float_int_t; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + typedef uint32_t mp_float_int_t; + #endif + union { + mp_float_t f; + #if MP_ENDIANNESS_LITTLE + struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; + #else + struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; + #endif + } u; + u.p.sgn = 0; + u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1; + if (MP_FLOAT_FRAC_BITS <= 32) { + u.p.frc = yasmarang(); + } else { + u.p.frc = ((uint64_t)yasmarang() << 32) | (uint64_t)yasmarang(); + } + return u.f - 1; +} + +STATIC mp_obj_t mod_urandom_random(void) { + return mp_obj_new_float(yasmarang_float()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom_random_obj, mod_urandom_random); + +STATIC mp_obj_t mod_urandom_uniform(mp_obj_t a_in, mp_obj_t b_in) { + mp_float_t a = mp_obj_get_float(a_in); + mp_float_t b = mp_obj_get_float(b_in); + return mp_obj_new_float(a + (b - a) * yasmarang_float()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform); + +#endif + +#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS + +STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) }, + { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) }, + { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) }, + #if MICROPY_PY_URANDOM_EXTRA_FUNCS + { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_urandom_randrange_obj) }, + { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_urandom_randint_obj) }, + { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_urandom_choice_obj) }, + #if MICROPY_PY_BUILTINS_FLOAT + { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_urandom_random_obj) }, + { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_urandom_uniform_obj) }, + #endif + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals_table); + +const mp_obj_module_t mp_module_urandom = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_urandom_globals, +}; + +#endif //MICROPY_PY_URANDOM diff --git a/src/openmv/src/micropython/extmod/modure.c b/src/openmv/src/micropython/extmod/modure.c new file mode 100755 index 0000000..0d5330c --- /dev/null +++ b/src/openmv/src/micropython/extmod/modure.c @@ -0,0 +1,462 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/objstr.h" +#include "py/stackctrl.h" + +#if MICROPY_PY_URE + +#define re1_5_stack_chk() MP_STACK_CHECK() + +#include "re1.5/re1.5.h" + +#define FLAG_DEBUG 0x1000 + +typedef struct _mp_obj_re_t { + mp_obj_base_t base; + ByteProg re; +} mp_obj_re_t; + +typedef struct _mp_obj_match_t { + mp_obj_base_t base; + int num_matches; + mp_obj_t str; + const char *caps[0]; +} mp_obj_match_t; + + +STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->num_matches); +} + +STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) { + mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t no = mp_obj_get_int(no_in); + if (no < 0 || no >= self->num_matches) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in)); + } + + const char *start = self->caps[no * 2]; + if (start == NULL) { + // no match for this group + return mp_const_none; + } + return mp_obj_new_str_of_type(mp_obj_get_type(self->str), + (const byte*)start, self->caps[no * 2 + 1] - start); +} +MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group); + +#if MICROPY_PY_URE_MATCH_GROUPS + +STATIC mp_obj_t match_groups(mp_obj_t self_in) { + mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in); + if (self->num_matches <= 1) { + return mp_const_empty_tuple; + } + mp_obj_tuple_t *groups = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->num_matches - 1, NULL)); + for (int i = 1; i < self->num_matches; ++i) { + groups->items[i - 1] = match_group(self_in, MP_OBJ_NEW_SMALL_INT(i)); + } + return MP_OBJ_FROM_PTR(groups); +} +MP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups); + +#endif + +#if MICROPY_PY_URE_MATCH_SPAN_START_END + +STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) { + mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]); + + mp_int_t no = 0; + if (n_args == 2) { + no = mp_obj_get_int(args[1]); + if (no < 0 || no >= self->num_matches) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1])); + } + } + + mp_int_t s = -1; + mp_int_t e = -1; + const char *start = self->caps[no * 2]; + if (start != NULL) { + // have a match for this group + const char *begin = mp_obj_str_get_str(self->str); + s = start - begin; + e = self->caps[no * 2 + 1] - begin; + } + + span[0] = mp_obj_new_int(s); + span[1] = mp_obj_new_int(e); +} + +STATIC mp_obj_t match_span(size_t n_args, const mp_obj_t *args) { + mp_obj_t span[2]; + match_span_helper(n_args, args, span); + return mp_obj_new_tuple(2, span); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span); + +STATIC mp_obj_t match_start(size_t n_args, const mp_obj_t *args) { + mp_obj_t span[2]; + match_span_helper(n_args, args, span); + return span[0]; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start); + +STATIC mp_obj_t match_end(size_t n_args, const mp_obj_t *args) { + mp_obj_t span[2]; + match_span_helper(n_args, args, span); + return span[1]; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end); + +#endif + +STATIC const mp_rom_map_elem_t match_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) }, + #if MICROPY_PY_URE_MATCH_GROUPS + { MP_ROM_QSTR(MP_QSTR_groups), MP_ROM_PTR(&match_groups_obj) }, + #endif + #if MICROPY_PY_URE_MATCH_SPAN_START_END + { MP_ROM_QSTR(MP_QSTR_span), MP_ROM_PTR(&match_span_obj) }, + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&match_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_end), MP_ROM_PTR(&match_end_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table); + +STATIC const mp_obj_type_t match_type = { + { &mp_type_type }, + .name = MP_QSTR_match, + .print = match_print, + .locals_dict = (void*)&match_locals_dict, +}; + +STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self); +} + +STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { + (void)n_args; + mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]); + Subject subj; + size_t len; + subj.begin = mp_obj_str_get_data(args[1], &len); + subj.end = subj.begin + len; + int caps_num = (self->re.sub + 1) * 2; + mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char*, caps_num); + // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char + memset((char*)match->caps, 0, caps_num * sizeof(char*)); + int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored); + if (res == 0) { + m_del_var(mp_obj_match_t, char*, caps_num, match); + return mp_const_none; + } + + match->base.type = &match_type; + match->num_matches = caps_num / 2; // caps_num counts start and end pointers + match->str = args[1]; + return MP_OBJ_FROM_PTR(match); +} + +STATIC mp_obj_t re_match(size_t n_args, const mp_obj_t *args) { + return ure_exec(true, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match); + +STATIC mp_obj_t re_search(size_t n_args, const mp_obj_t *args) { + return ure_exec(false, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search); + +STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { + mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]); + Subject subj; + size_t len; + const mp_obj_type_t *str_type = mp_obj_get_type(args[1]); + subj.begin = mp_obj_str_get_data(args[1], &len); + subj.end = subj.begin + len; + int caps_num = (self->re.sub + 1) * 2; + + int maxsplit = 0; + if (n_args > 2) { + maxsplit = mp_obj_get_int(args[2]); + } + + mp_obj_t retval = mp_obj_new_list(0, NULL); + const char **caps = mp_local_alloc(caps_num * sizeof(char*)); + while (true) { + // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char + memset((char**)caps, 0, caps_num * sizeof(char*)); + int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false); + + // if we didn't have a match, or had an empty match, it's time to stop + if (!res || caps[0] == caps[1]) { + break; + } + + mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, caps[0] - subj.begin); + mp_obj_list_append(retval, s); + if (self->re.sub > 0) { + mp_raise_NotImplementedError("Splitting with sub-captures"); + } + subj.begin = caps[1]; + if (maxsplit > 0 && --maxsplit == 0) { + break; + } + } + // cast is a workaround for a bug in msvc (see above) + mp_local_free((char**)caps); + + mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin); + mp_obj_list_append(retval, s); + return retval; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split); + +#if MICROPY_PY_URE_SUB + +STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *args) { + mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t replace = args[1]; + mp_obj_t where = args[2]; + mp_int_t count = 0; + if (n_args > 3) { + count = mp_obj_get_int(args[3]); + // Note: flags are currently ignored + } + + size_t where_len; + const char *where_str = mp_obj_str_get_data(where, &where_len); + Subject subj; + subj.begin = where_str; + subj.end = subj.begin + where_len; + int caps_num = (self->re.sub + 1) * 2; + + vstr_t vstr_return; + vstr_return.buf = NULL; // We'll init the vstr after the first match + mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char*)); + match->base.type = &match_type; + match->num_matches = caps_num / 2; // caps_num counts start and end pointers + match->str = where; + + for (;;) { + // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char + memset((char*)match->caps, 0, caps_num * sizeof(char*)); + int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false); + + // If we didn't have a match, or had an empty match, it's time to stop + if (!res || match->caps[0] == match->caps[1]) { + break; + } + + // Initialise the vstr if it's not already + if (vstr_return.buf == NULL) { + vstr_init(&vstr_return, match->caps[0] - subj.begin); + } + + // Add pre-match string + vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin); + + // Get replacement string + const char* repl = mp_obj_str_get_str((mp_obj_is_callable(replace) ? mp_call_function_1(replace, MP_OBJ_FROM_PTR(match)) : replace)); + + // Append replacement string to result, substituting any regex groups + while (*repl != '\0') { + if (*repl == '\\') { + ++repl; + bool is_g_format = false; + if (*repl == 'g' && repl[1] == '<') { + // Group specified with syntax "\g" + repl += 2; + is_g_format = true; + } + + if ('0' <= *repl && *repl <= '9') { + // Group specified with syntax "\g" or "\number" + unsigned int match_no = 0; + do { + match_no = match_no * 10 + (*repl++ - '0'); + } while ('0' <= *repl && *repl <= '9'); + if (is_g_format && *repl == '>') { + ++repl; + } + + if (match_no >= (unsigned int)match->num_matches) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no))); + } + + const char *start_match = match->caps[match_no * 2]; + if (start_match != NULL) { + // Add the substring matched by group + const char *end_match = match->caps[match_no * 2 + 1]; + vstr_add_strn(&vstr_return, start_match, end_match - start_match); + } + } + } else { + // Just add the current byte from the replacement string + vstr_add_byte(&vstr_return, *repl++); + } + } + + // Move start pointer to end of last match + subj.begin = match->caps[1]; + + // Stop substitutions if count was given and gets to 0 + if (count > 0 && --count == 0) { + break; + } + } + + mp_local_free(match); + + if (vstr_return.buf == NULL) { + // Optimisation for case of no substitutions + return where; + } + + // Add post-match string + vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin); + + return mp_obj_new_str_from_vstr(mp_obj_get_type(where), &vstr_return); +} + +STATIC mp_obj_t re_sub(size_t n_args, const mp_obj_t *args) { + return re_sub_helper(args[0], n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub); + +#endif + +STATIC const mp_rom_map_elem_t re_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) }, + { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) }, + { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) }, + #if MICROPY_PY_URE_SUB + { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table); + +STATIC const mp_obj_type_t re_type = { + { &mp_type_type }, + .name = MP_QSTR_ure, + .print = re_print, + .locals_dict = (void*)&re_locals_dict, +}; + +STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { + const char *re_str = mp_obj_str_get_str(args[0]); + int size = re1_5_sizecode(re_str); + if (size == -1) { + goto error; + } + mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size); + o->base.type = &re_type; + int flags = 0; + if (n_args > 1) { + flags = mp_obj_get_int(args[1]); + } + int error = re1_5_compilecode(&o->re, re_str); + if (error != 0) { +error: + mp_raise_ValueError("Error in regex"); + } + if (flags & FLAG_DEBUG) { + re1_5_dumpcode(&o->re); + } + return MP_OBJ_FROM_PTR(o); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile); + +STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { + (void)n_args; + mp_obj_t self = mod_re_compile(1, args); + + const mp_obj_t args2[] = {self, args[1]}; + mp_obj_t match = ure_exec(is_anchored, 2, args2); + return match; +} + +STATIC mp_obj_t mod_re_match(size_t n_args, const mp_obj_t *args) { + return mod_re_exec(true, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_match_obj, 2, 4, mod_re_match); + +STATIC mp_obj_t mod_re_search(size_t n_args, const mp_obj_t *args) { + return mod_re_exec(false, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search); + +#if MICROPY_PY_URE_SUB +STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) { + mp_obj_t self = mod_re_compile(1, args); + return re_sub_helper(self, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub); +#endif + +STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) }, + { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) }, + { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&mod_re_match_obj) }, + { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&mod_re_search_obj) }, + #if MICROPY_PY_URE_SUB + { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table); + +const mp_obj_module_t mp_module_ure = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_re_globals, +}; + +// Source files #include'd here to make sure they're compiled in +// only if module is enabled by config setting. + +#define re1_5_fatal(x) assert(!x) +#include "re1.5/compilecode.c" +#include "re1.5/dumpcode.c" +#include "re1.5/recursiveloop.c" +#include "re1.5/charclass.c" + +#endif //MICROPY_PY_URE diff --git a/src/openmv/src/micropython/extmod/moduselect.c b/src/openmv/src/micropython/extmod/moduselect.c new file mode 100755 index 0000000..582814b --- /dev/null +++ b/src/openmv/src/micropython/extmod/moduselect.c @@ -0,0 +1,378 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_USELECT + +#include + +#include "py/runtime.h" +#include "py/obj.h" +#include "py/objlist.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +// Flags for poll() +#define FLAG_ONESHOT (1) + +/// \module select - Provides select function to wait for events on a stream +/// +/// This module provides the select function. + +typedef struct _poll_obj_t { + mp_obj_t obj; + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); + mp_uint_t flags; + mp_uint_t flags_ret; +} poll_obj_t; + +STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) { + for (mp_uint_t i = 0; i < obj_len; i++) { + mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + if (elem->value == MP_OBJ_NULL) { + // object not found; get its ioctl and add it to the poll list + const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL); + poll_obj_t *poll_obj = m_new_obj(poll_obj_t); + poll_obj->obj = obj[i]; + poll_obj->ioctl = stream_p->ioctl; + poll_obj->flags = flags; + poll_obj->flags_ret = 0; + elem->value = MP_OBJ_FROM_PTR(poll_obj); + } else { + // object exists; update its flags + if (or_flags) { + ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags |= flags; + } else { + ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags = flags; + } + } + } +} + +// poll each object in the map +STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) { + mp_uint_t n_ready = 0; + for (mp_uint_t i = 0; i < poll_map->alloc; ++i) { + if (!MP_MAP_SLOT_IS_FILLED(poll_map, i)) { + continue; + } + + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value); + int errcode; + mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode); + poll_obj->flags_ret = ret; + + if (ret == -1) { + // error doing ioctl + mp_raise_OSError(errcode); + } + + if (ret != 0) { + // object is ready + n_ready += 1; + if (rwx_num != NULL) { + if (ret & MP_STREAM_POLL_RD) { + rwx_num[0] += 1; + } + if (ret & MP_STREAM_POLL_WR) { + rwx_num[1] += 1; + } + if ((ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { + rwx_num[2] += 1; + } + } + } + } + return n_ready; +} + +/// \function select(rlist, wlist, xlist[, timeout]) +STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) { + // get array data from tuple/list arguments + size_t rwx_len[3]; + mp_obj_t *r_array, *w_array, *x_array; + mp_obj_get_array(args[0], &rwx_len[0], &r_array); + mp_obj_get_array(args[1], &rwx_len[1], &w_array); + mp_obj_get_array(args[2], &rwx_len[2], &x_array); + + // get timeout + mp_uint_t timeout = -1; + if (n_args == 4) { + if (args[3] != mp_const_none) { + #if MICROPY_PY_BUILTINS_FLOAT + float timeout_f = mp_obj_get_float(args[3]); + if (timeout_f >= 0) { + timeout = (mp_uint_t)(timeout_f * 1000); + } + #else + timeout = mp_obj_get_int(args[3]) * 1000; + #endif + } + } + + // merge separate lists and get the ioctl function for each object + mp_map_t poll_map; + mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]); + poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true); + poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true); + poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true); + + mp_uint_t start_tick = mp_hal_ticks_ms(); + rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; + for (;;) { + // poll the objects + mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len); + + if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + // one or more objects are ready, or we had a timeout + mp_obj_t list_array[3]; + list_array[0] = mp_obj_new_list(rwx_len[0], NULL); + list_array[1] = mp_obj_new_list(rwx_len[1], NULL); + list_array[2] = mp_obj_new_list(rwx_len[2], NULL); + rwx_len[0] = rwx_len[1] = rwx_len[2] = 0; + for (mp_uint_t i = 0; i < poll_map.alloc; ++i) { + if (!MP_MAP_SLOT_IS_FILLED(&poll_map, i)) { + continue; + } + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value); + if (poll_obj->flags_ret & MP_STREAM_POLL_RD) { + ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj; + } + if (poll_obj->flags_ret & MP_STREAM_POLL_WR) { + ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj; + } + if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) { + ((mp_obj_list_t*)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj; + } + } + mp_map_deinit(&poll_map); + return mp_obj_new_tuple(3, list_array); + } + MICROPY_EVENT_POLL_HOOK + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select); + +/// \class Poll - poll class + +typedef struct _mp_obj_poll_t { + mp_obj_base_t base; + mp_map_t poll_map; + short iter_cnt; + short iter_idx; + int flags; + // callee-owned tuple + mp_obj_t ret_tuple; +} mp_obj_poll_t; + +/// \method register(obj[, eventmask]) +STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + mp_uint_t flags; + if (n_args == 3) { + flags = mp_obj_get_int(args[2]); + } else { + flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR; + } + poll_map_add(&self->poll_map, &args[1], 1, flags, false); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); + +/// \method unregister(obj) +STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + // TODO raise KeyError if obj didn't exist in map + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister); + +/// \method modify(obj, eventmask) +STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP); + if (elem == NULL) { + mp_raise_OSError(MP_ENOENT); + } + ((poll_obj_t*)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify); + +STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + + // work out timeout (its given already in ms) + mp_uint_t timeout = -1; + int flags = 0; + if (n_args >= 2) { + if (args[1] != mp_const_none) { + mp_int_t timeout_i = mp_obj_get_int(args[1]); + if (timeout_i >= 0) { + timeout = timeout_i; + } + } + if (n_args >= 3) { + flags = mp_obj_get_int(args[2]); + } + } + + self->flags = flags; + + mp_uint_t start_tick = mp_hal_ticks_ms(); + mp_uint_t n_ready; + for (;;) { + // poll the objects + n_ready = poll_map_poll(&self->poll_map, NULL); + if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) { + break; + } + MICROPY_EVENT_POLL_HOOK + } + + return n_ready; +} + +STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + mp_uint_t n_ready = poll_poll_internal(n_args, args); + + // one or more objects are ready, or we had a timeout + mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); + n_ready = 0; + for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) { + if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + continue; + } + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); + if (poll_obj->flags_ret != 0) { + mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)}; + ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple); + if (self->flags & FLAG_ONESHOT) { + // Don't poll next time, until new event flags will be set explicitly + poll_obj->flags = 0; + } + } + } + return MP_OBJ_FROM_PTR(ret_list); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll); + +STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + + if (self->ret_tuple == MP_OBJ_NULL) { + self->ret_tuple = mp_obj_new_tuple(2, NULL); + } + + int n_ready = poll_poll_internal(n_args, args); + self->iter_cnt = n_ready; + self->iter_idx = 0; + + return args[0]; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll); + +STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->iter_cnt == 0) { + return MP_OBJ_STOP_ITERATION; + } + + self->iter_cnt--; + + for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) { + self->iter_idx++; + if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) { + continue; + } + poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value); + if (poll_obj->flags_ret != 0) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple); + t->items[0] = poll_obj->obj; + t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret); + if (self->flags & FLAG_ONESHOT) { + // Don't poll next time, until new event flags will be set explicitly + poll_obj->flags = 0; + } + return MP_OBJ_FROM_PTR(t); + } + } + + assert(!"inconsistent number of poll active entries"); + self->iter_cnt = 0; + return MP_OBJ_STOP_ITERATION; +} + +STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, + { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) }, + { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, + { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, + { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); + +STATIC const mp_obj_type_t mp_type_poll = { + { &mp_type_type }, + .name = MP_QSTR_poll, + .getiter = mp_identity_getiter, + .iternext = poll_iternext, + .locals_dict = (void*)&poll_locals_dict, +}; + +/// \function poll() +STATIC mp_obj_t select_poll(void) { + mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t); + poll->base.type = &mp_type_poll; + mp_map_init(&poll->poll_map, 0); + poll->iter_cnt = 0; + poll->ret_tuple = MP_OBJ_NULL; + return MP_OBJ_FROM_PTR(poll); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll); + +STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) }, + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_select_select_obj) }, + { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) }, + { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(MP_STREAM_POLL_RD) }, + { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(MP_STREAM_POLL_WR) }, + { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(MP_STREAM_POLL_ERR) }, + { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(MP_STREAM_POLL_HUP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table); + +const mp_obj_module_t mp_module_uselect = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_select_globals, +}; + +#endif // MICROPY_PY_USELECT diff --git a/src/openmv/src/micropython/extmod/modussl_axtls.c b/src/openmv/src/micropython/extmod/modussl_axtls.c new file mode 100755 index 0000000..2dab6ff --- /dev/null +++ b/src/openmv/src/micropython/extmod/modussl_axtls.c @@ -0,0 +1,262 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" + +#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS + +#include "ssl.h" + +typedef struct _mp_obj_ssl_socket_t { + mp_obj_base_t base; + mp_obj_t sock; + SSL_CTX *ssl_ctx; + SSL *ssl_sock; + byte *buf; + uint32_t bytes_left; +} mp_obj_ssl_socket_t; + +struct ssl_args { + mp_arg_val_t key; + mp_arg_val_t cert; + mp_arg_val_t server_side; + mp_arg_val_t server_hostname; +}; + +STATIC const mp_obj_type_t ussl_socket_type; + +STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { +#if MICROPY_PY_USSL_FINALISER + mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); +#else + mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); +#endif + o->base.type = &ussl_socket_type; + o->buf = NULL; + o->bytes_left = 0; + o->sock = sock; + + uint32_t options = SSL_SERVER_VERIFY_LATER; + if (args->key.u_obj != mp_const_none) { + options |= SSL_NO_DEFAULT_KEY; + } + if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { + mp_raise_OSError(MP_EINVAL); + } + + if (args->key.u_obj != mp_const_none) { + size_t len; + const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len); + int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid key"); + } + + data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len); + res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid cert"); + } + } + + if (args->server_side.u_bool) { + o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock); + } else { + SSL_EXTENSIONS *ext = ssl_ext_new(); + + if (args->server_hostname.u_obj != mp_const_none) { + ext->host_name = (char*)mp_obj_str_get_str(args->server_hostname.u_obj); + } + + o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext); + + int res = ssl_handshake_status(o->ssl_sock); + // Pointer to SSL_EXTENSIONS as being passed to ssl_client_new() + // is saved in ssl_sock->extensions. + // As of axTLS 2.1.3, extensions aren't used beyond the initial + // handshake, and that's pretty much how it's expected to be. So + // we allocate them on stack and reset the pointer after handshake. + + if (res != SSL_OK) { + printf("ssl_handshake_status: %d\n", res); + ssl_display_error(res); + mp_raise_OSError(MP_EIO); + } + + } + + return o; +} + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<_SSLSocket %p>", self->ssl_sock); +} + +STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + if (o->ssl_sock == NULL) { + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + while (o->bytes_left == 0) { + mp_int_t r = ssl_read(o->ssl_sock, &o->buf); + if (r == SSL_OK) { + // SSL_OK from ssl_read() means "everything is ok, but there's + // no user data yet". So, we just keep reading. + continue; + } + if (r < 0) { + if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) { + // EOF + return 0; + } + if (r == SSL_EAGAIN) { + r = MP_EAGAIN; + } + *errcode = r; + return MP_STREAM_ERROR; + } + o->bytes_left = r; + } + + if (size > o->bytes_left) { + size = o->bytes_left; + } + memcpy(buf, o->buf, size); + o->buf += size; + o->bytes_left -= size; + return size; +} + +STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + if (o->ssl_sock == NULL) { + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + mp_int_t r = ssl_write(o->ssl_sock, buf, size); + if (r < 0) { + *errcode = r; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) { + ssl_free(self->ssl_sock); + ssl_ctx_free(self->ssl_ctx); + self->ssl_sock = NULL; + } + // Pass all requests down to the underlying socket + return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); +} + +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + // Currently supports only blocking mode + (void)self_in; + if (!mp_obj_is_true(flag_in)) { + mp_raise_NotImplementedError(NULL); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, +#if MICROPY_PY_USSL_FINALISER + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); + +STATIC const mp_stream_p_t ussl_socket_stream_p = { + .read = socket_read, + .write = socket_write, + .ioctl = socket_ioctl, +}; + +STATIC const mp_obj_type_t ussl_socket_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_ussl, + .print = socket_print, + .getiter = NULL, + .iternext = NULL, + .protocol = &ussl_socket_stream_p, + .locals_dict = (void*)&ussl_socket_locals_dict, +}; + +STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO: Implement more args + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // TODO: Check that sock implements stream protocol + mp_obj_t sock = pos_args[0]; + + struct ssl_args args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + return MP_OBJ_FROM_PTR(socket_new(sock, &args)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); + +STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); + +const mp_obj_module_t mp_module_ussl = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ssl_globals, +}; + +#endif // MICROPY_PY_USSL diff --git a/src/openmv/src/micropython/extmod/modussl_mbedtls.c b/src/openmv/src/micropython/extmod/modussl_mbedtls.c new file mode 100755 index 0000000..ce3db0f --- /dev/null +++ b/src/openmv/src/micropython/extmod/modussl_mbedtls.c @@ -0,0 +1,350 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS + +#include +#include +#include // needed because mp_is_nonblocking_error uses system error codes + +#include "py/runtime.h" +#include "py/stream.h" + +// mbedtls_time_t +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/ssl.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/pk.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" + +typedef struct _mp_obj_ssl_socket_t { + mp_obj_base_t base; + mp_obj_t sock; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt cacert; + mbedtls_x509_crt cert; + mbedtls_pk_context pkey; +} mp_obj_ssl_socket_t; + +struct ssl_args { + mp_arg_val_t key; + mp_arg_val_t cert; + mp_arg_val_t server_side; + mp_arg_val_t server_hostname; +}; + +STATIC const mp_obj_type_t ussl_socket_type; + +#ifdef MBEDTLS_DEBUG_C +STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { + (void)ctx; + (void)level; + printf("DBG:%s:%04d: %s\n", file, line, str); +} +#endif + +STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t*)ctx; + + const mp_stream_p_t *sock_stream = mp_get_stream(sock); + int err; + + mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err); + if (out_sz == MP_STREAM_ERROR) { + if (mp_is_nonblocking_error(err)) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + return -err; + } else { + return out_sz; + } +} + +STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t*)ctx; + + const mp_stream_p_t *sock_stream = mp_get_stream(sock); + int err; + + mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err); + if (out_sz == MP_STREAM_ERROR) { + if (mp_is_nonblocking_error(err)) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + return -err; + } else { + return out_sz; + } +} + + +STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { + // Verify the socket object has the full stream protocol + mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + +#if MICROPY_PY_USSL_FINALISER + mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); +#else + mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); +#endif + o->base.type = &ussl_socket_type; + o->sock = sock; + + int ret; + mbedtls_ssl_init(&o->ssl); + mbedtls_ssl_config_init(&o->conf); + mbedtls_x509_crt_init(&o->cacert); + mbedtls_x509_crt_init(&o->cert); + mbedtls_pk_init(&o->pkey); + mbedtls_ctr_drbg_init(&o->ctr_drbg); + #ifdef MBEDTLS_DEBUG_C + // Debug level (0-4) + mbedtls_debug_set_threshold(0); + #endif + + mbedtls_entropy_init(&o->entropy); + const byte seed[] = "upy"; + ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_ssl_config_defaults(&o->conf, + args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + goto cleanup; + } + + mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); + #ifdef MBEDTLS_DEBUG_C + mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); + #endif + + ret = mbedtls_ssl_setup(&o->ssl, &o->conf); + if (ret != 0) { + goto cleanup; + } + + if (args->server_hostname.u_obj != mp_const_none) { + const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); + ret = mbedtls_ssl_set_hostname(&o->ssl, sni); + if (ret != 0) { + goto cleanup; + } + } + + mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); + + if (args->key.u_obj != MP_OBJ_NULL) { + size_t key_len; + const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); + // len should include terminating null + ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); + assert(ret == 0); + + size_t cert_len; + const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); + // len should include terminating null + ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); + assert(ret == 0); + + ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); + assert(ret == 0); + } + + while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + printf("mbedtls_ssl_handshake error: -%x\n", -ret); + goto cleanup; + } + } + + return o; + +cleanup: + mbedtls_pk_free(&o->pkey); + mbedtls_x509_crt_free(&o->cert); + mbedtls_x509_crt_free(&o->cacert); + mbedtls_ssl_free(&o->ssl); + mbedtls_ssl_config_free(&o->conf); + mbedtls_ctr_drbg_free(&o->ctr_drbg); + mbedtls_entropy_free(&o->entropy); + + if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { + mp_raise_OSError(MP_ENOMEM); + } else { + mp_raise_OSError(MP_EIO); + } +} + +STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + if (!mp_obj_is_true(binary_form)) { + mp_raise_NotImplementedError(NULL); + } + const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl); + return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert); + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<_SSLSocket %p>", self); +} + +STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + int ret = mbedtls_ssl_read(&o->ssl, buf, size); + if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + // end of stream + return 0; + } + if (ret >= 0) { + return ret; + } + if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + ret = MP_EWOULDBLOCK; + } + *errcode = ret; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + int ret = mbedtls_ssl_write(&o->ssl, buf, size); + if (ret >= 0) { + return ret; + } + if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + ret = MP_EWOULDBLOCK; + } + *errcode = ret; + return MP_STREAM_ERROR; +} + +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); + mp_obj_t sock = o->sock; + mp_obj_t dest[3]; + mp_load_method(sock, MP_QSTR_setblocking, dest); + dest[2] = flag_in; + return mp_call_method_n_kw(1, 0, dest); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + if (request == MP_STREAM_CLOSE) { + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + } + // Pass all requests down to the underlying socket + return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode); +} + +STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, +#if MICROPY_PY_USSL_FINALISER + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); + +STATIC const mp_stream_p_t ussl_socket_stream_p = { + .read = socket_read, + .write = socket_write, + .ioctl = socket_ioctl, +}; + +STATIC const mp_obj_type_t ussl_socket_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_ussl, + .print = socket_print, + .getiter = NULL, + .iternext = NULL, + .protocol = &ussl_socket_stream_p, + .locals_dict = (void*)&ussl_socket_locals_dict, +}; + +STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO: Implement more args + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // TODO: Check that sock implements stream protocol + mp_obj_t sock = pos_args[0]; + + struct ssl_args args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + return MP_OBJ_FROM_PTR(socket_new(sock, &args)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); + +STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); + +const mp_obj_module_t mp_module_ussl = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ssl_globals, +}; + +#endif // MICROPY_PY_USSL diff --git a/src/openmv/src/micropython/extmod/modutimeq.c b/src/openmv/src/micropython/extmod/modutimeq.c new file mode 100755 index 0000000..33db7fb --- /dev/null +++ b/src/openmv/src/micropython/extmod/modutimeq.c @@ -0,0 +1,231 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2016-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/smallint.h" + +#if MICROPY_PY_UTIMEQ + +#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD + +#undef DEBUG +#define DEBUG 0 + +// the algorithm here is modelled on CPython's heapq.py + +struct qentry { + mp_uint_t time; + mp_uint_t id; + mp_obj_t callback; + mp_obj_t args; +}; + +typedef struct _mp_obj_utimeq_t { + mp_obj_base_t base; + mp_uint_t alloc; + mp_uint_t len; + struct qentry items[]; +} mp_obj_utimeq_t; + +STATIC mp_uint_t utimeq_id; + +STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) { + return MP_OBJ_TO_PTR(heap_in); +} + +STATIC bool time_less_than(struct qentry *item, struct qentry *parent) { + mp_uint_t item_tm = item->time; + mp_uint_t parent_tm = parent->time; + mp_uint_t res = parent_tm - item_tm; + if (res == 0) { + // TODO: This actually should use the same "ring" logic + // as for time, to avoid artifacts when id's overflow. + return item->id < parent->id; + } + if ((mp_int_t)res < 0) { + res += MODULO; + } + return res && res < (MODULO / 2); +} + +STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_uint_t alloc = mp_obj_get_int(args[0]); + mp_obj_utimeq_t *o = m_new_obj_var(mp_obj_utimeq_t, struct qentry, alloc); + o->base.type = type; + memset(o->items, 0, sizeof(*o->items) * alloc); + o->alloc = alloc; + o->len = 0; + return MP_OBJ_FROM_PTR(o); +} + +STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) { + struct qentry item = heap->items[pos]; + while (pos > start_pos) { + mp_uint_t parent_pos = (pos - 1) >> 1; + struct qentry *parent = &heap->items[parent_pos]; + bool lessthan = time_less_than(&item, parent); + if (lessthan) { + heap->items[pos] = *parent; + pos = parent_pos; + } else { + break; + } + } + heap->items[pos] = item; +} + +STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) { + mp_uint_t start_pos = pos; + mp_uint_t end_pos = heap->len; + struct qentry item = heap->items[pos]; + for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) { + // choose right child if it's <= left child + if (child_pos + 1 < end_pos) { + bool lessthan = time_less_than(&heap->items[child_pos], &heap->items[child_pos + 1]); + if (!lessthan) { + child_pos += 1; + } + } + // bubble up the smaller child + heap->items[pos] = heap->items[child_pos]; + pos = child_pos; + } + heap->items[pos] = item; + heap_siftdown(heap, start_pos, pos); +} + +STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) { + (void)n_args; + mp_obj_t heap_in = args[0]; + mp_obj_utimeq_t *heap = get_heap(heap_in); + if (heap->len == heap->alloc) { + mp_raise_msg(&mp_type_IndexError, "queue overflow"); + } + mp_uint_t l = heap->len; + heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]); + heap->items[l].id = utimeq_id++; + heap->items[l].callback = args[2]; + heap->items[l].args = args[3]; + heap_siftdown(heap, 0, heap->len); + heap->len++; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush); + +STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { + mp_obj_utimeq_t *heap = get_heap(heap_in); + if (heap->len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + } + mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); + if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 3) { + mp_raise_TypeError(NULL); + } + + struct qentry *item = &heap->items[0]; + ret->items[0] = MP_OBJ_NEW_SMALL_INT(item->time); + ret->items[1] = item->callback; + ret->items[2] = item->args; + heap->len -= 1; + heap->items[0] = heap->items[heap->len]; + heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer + heap->items[heap->len].args = MP_OBJ_NULL; + if (heap->len) { + heap_siftup(heap, 0); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop); + +STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { + mp_obj_utimeq_t *heap = get_heap(heap_in); + if (heap->len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap")); + } + + struct qentry *item = &heap->items[0]; + return MP_OBJ_NEW_SMALL_INT(item->time); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime); + +#if DEBUG +STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) { + mp_obj_utimeq_t *heap = get_heap(heap_in); + for (int i = 0; i < heap->len; i++) { + printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time, + MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args)); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_dump_obj, mod_utimeq_dump); +#endif + +STATIC mp_obj_t utimeq_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_utimeq_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&mod_utimeq_heappush_obj) }, + { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&mod_utimeq_heappop_obj) }, + { MP_ROM_QSTR(MP_QSTR_peektime), MP_ROM_PTR(&mod_utimeq_peektime_obj) }, + #if DEBUG + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_utimeq_dump_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(utimeq_locals_dict, utimeq_locals_dict_table); + +STATIC const mp_obj_type_t utimeq_type = { + { &mp_type_type }, + .name = MP_QSTR_utimeq, + .make_new = utimeq_make_new, + .unary_op = utimeq_unary_op, + .locals_dict = (void*)&utimeq_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utimeq) }, + { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&utimeq_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_utimeq_globals, mp_module_utimeq_globals_table); + +const mp_obj_module_t mp_module_utimeq = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_utimeq_globals, +}; + +#endif //MICROPY_PY_UTIMEQ diff --git a/src/openmv/src/micropython/extmod/moduzlib.c b/src/openmv/src/micropython/extmod/moduzlib.c new file mode 100755 index 0000000..940b728 --- /dev/null +++ b/src/openmv/src/micropython/extmod/moduzlib.c @@ -0,0 +1,225 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" + +#if MICROPY_PY_UZLIB + +#include "uzlib/tinf.h" + +#if 0 // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +typedef struct _mp_obj_decompio_t { + mp_obj_base_t base; + mp_obj_t src_stream; + TINF_DATA decomp; + bool eof; +} mp_obj_decompio_t; + +STATIC unsigned char read_src_stream(TINF_DATA *data) { + byte *p = (void*)data; + p -= offsetof(mp_obj_decompio_t, decomp); + mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; + + const mp_stream_p_t *stream = mp_get_stream(self->src_stream); + int err; + byte c; + mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); + if (out_sz == MP_STREAM_ERROR) { + mp_raise_OSError(err); + } + if (out_sz == 0) { + nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); + } + return c; +} + +STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); + o->base.type = type; + memset(&o->decomp, 0, sizeof(o->decomp)); + o->decomp.readSource = read_src_stream; + o->src_stream = args[0]; + o->eof = false; + + mp_int_t dict_opt = 0; + int dict_sz; + if (n_args > 1) { + dict_opt = mp_obj_get_int(args[1]); + } + + if (dict_opt >= 16) { + int st = uzlib_gzip_parse_header(&o->decomp); + if (st != TINF_OK) { + goto header_error; + } + dict_sz = 1 << (dict_opt - 16); + } else if (dict_opt >= 0) { + dict_opt = uzlib_zlib_parse_header(&o->decomp); + if (dict_opt < 0) { +header_error: + mp_raise_ValueError("compression header"); + } + dict_sz = 1 << dict_opt; + } else { + dict_sz = 1 << -dict_opt; + } + + uzlib_uncompress_init(&o->decomp, m_new(byte, dict_sz), dict_sz); + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in); + if (o->eof) { + return 0; + } + + o->decomp.dest = buf; + o->decomp.destSize = size; + int st = uzlib_uncompress_chksum(&o->decomp); + if (st == TINF_DONE) { + o->eof = true; + } + if (st < 0) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + return o->decomp.dest - (byte*)buf; +} + +STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); + +STATIC const mp_stream_p_t decompio_stream_p = { + .read = decompio_read, +}; + +STATIC const mp_obj_type_t decompio_type = { + { &mp_type_type }, + .name = MP_QSTR_DecompIO, + .make_new = decompio_make_new, + .protocol = &decompio_stream_p, + .locals_dict = (void*)&decompio_locals_dict, +}; + +STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { + mp_obj_t data = args[0]; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + TINF_DATA *decomp = m_new_obj(TINF_DATA); + memset(decomp, 0, sizeof(*decomp)); + DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp)); + uzlib_uncompress_init(decomp, NULL, 0); + mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15; + byte *dest_buf = m_new(byte, dest_buf_size); + + decomp->dest = dest_buf; + decomp->destSize = dest_buf_size; + DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", decomp->destSize); + decomp->source = bufinfo.buf; + + int st; + bool is_zlib = true; + + if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) { + is_zlib = false; + } + + if (is_zlib) { + st = uzlib_zlib_parse_header(decomp); + if (st < 0) { + goto error; + } + } + + while (1) { + st = uzlib_uncompress_chksum(decomp); + if (st < 0) { + goto error; + } + if (st == TINF_DONE) { + break; + } + size_t offset = decomp->dest - dest_buf; + dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256); + dest_buf_size += 256; + decomp->dest = dest_buf + offset; + decomp->destSize = 256; + } + + mp_uint_t final_sz = decomp->dest - dest_buf; + DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", dest_buf_size, final_sz); + dest_buf = (byte*)m_renew(byte, dest_buf, dest_buf_size, final_sz); + mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf); + m_del_obj(TINF_DATA, decomp); + return res; + +error: + nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress); + +STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, + { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) }, + { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table); + +const mp_obj_module_t mp_module_uzlib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals, +}; + +// Source files #include'd here to make sure they're compiled in +// only if module is enabled by config setting. + +#include "uzlib/tinflate.c" +#include "uzlib/tinfzlib.c" +#include "uzlib/tinfgzip.c" +#include "uzlib/adler32.c" +#include "uzlib/crc32.c" + +#endif // MICROPY_PY_UZLIB diff --git a/src/openmv/src/micropython/extmod/modwebrepl.c b/src/openmv/src/micropython/extmod/modwebrepl.c new file mode 100755 index 0000000..06da210 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modwebrepl.c @@ -0,0 +1,360 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/builtin.h" +#ifdef MICROPY_PY_WEBREPL_DELAY +#include "py/mphal.h" +#endif +#include "extmod/modwebsocket.h" +#include "genhdr/mpversion.h" + +#if MICROPY_PY_WEBREPL + +#if 0 // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +struct webrepl_file { + char sig[2]; + char type; + char flags; + uint64_t offset; + uint32_t size; + uint16_t fname_len; + char fname[64]; +} __attribute__((packed)); + +enum { PUT_FILE = 1, GET_FILE, GET_VER }; +enum { STATE_PASSWD, STATE_NORMAL }; + +typedef struct _mp_obj_webrepl_t { + mp_obj_base_t base; + mp_obj_t sock; + byte state; + byte hdr_to_recv; + uint32_t data_to_recv; + struct webrepl_file hdr; + mp_obj_t cur_file; +} mp_obj_webrepl_t; + +// These get passed to functions which aren't force-l32, so can't be const +STATIC char passwd_prompt[] = "Password: "; +STATIC char connected_prompt[] = "\r\nWebREPL connected\r\n>>> "; +STATIC char denied_prompt[] = "\r\nAccess denied\r\n"; + +STATIC char webrepl_passwd[10]; + +STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) { + const mp_stream_p_t *sock_stream = mp_get_stream(websock); + int err; + int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err); + sock_stream->write(websock, buf, len, &err); + sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, old_opts, &err); +} + +#define SSTR(s) s, sizeof(s) - 1 +STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) { + int err; + const mp_stream_p_t *sock_stream = mp_get_stream(websock); + sock_stream->write(websock, str, sz, &err); +} + +STATIC void write_webrepl_resp(mp_obj_t websock, uint16_t code) { + char buf[4] = {'W', 'B', code & 0xff, code >> 8}; + write_webrepl(websock, buf, sizeof(buf)); +} + +STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + DEBUG_printf("sizeof(struct webrepl_file) = %lu\n", sizeof(struct webrepl_file)); + mp_obj_webrepl_t *o = m_new_obj(mp_obj_webrepl_t); + o->base.type = type; + o->sock = args[0]; + o->hdr_to_recv = sizeof(struct webrepl_file); + o->data_to_recv = 0; + o->state = STATE_PASSWD; + write_webrepl_str(args[0], SSTR(passwd_prompt)); + return o; +} + +STATIC int write_file_chunk(mp_obj_webrepl_t *self) { + const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file); + byte readbuf[2 + 256]; + int err; + mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err); + if (out_sz == MP_STREAM_ERROR) { + return out_sz; + } + readbuf[0] = out_sz; + readbuf[1] = out_sz >> 8; + DEBUG_printf("webrepl: Sending %d bytes of file\n", out_sz); + write_webrepl(self->sock, readbuf, 2 + out_sz); + return out_sz; +} + +STATIC void handle_op(mp_obj_webrepl_t *self) { + + // Handle operations not requiring opened file + + switch (self->hdr.type) { + case GET_VER: { + static char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO}; + write_webrepl(self->sock, ver, sizeof(ver)); + self->hdr_to_recv = sizeof(struct webrepl_file); + return; + } + } + + // Handle operations requiring opened file + + mp_obj_t open_args[2] = { + mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)), + MP_OBJ_NEW_QSTR(MP_QSTR_rb) + }; + + if (self->hdr.type == PUT_FILE) { + open_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_wb); + } + + self->cur_file = mp_builtin_open(2, open_args, (mp_map_t*)&mp_const_empty_map); + + #if 0 + struct mp_stream_seek_t seek = { .offset = self->hdr.offset, .whence = 0 }; + int err; + mp_uint_t res = file_stream->ioctl(self->cur_file, MP_STREAM_SEEK, (uintptr_t)&seek, &err); + assert(res != MP_STREAM_ERROR); + #endif + + write_webrepl_resp(self->sock, 0); + + if (self->hdr.type == PUT_FILE) { + self->data_to_recv = self->hdr.size; + } else if (self->hdr.type == GET_FILE) { + self->data_to_recv = 1; + } +} + +STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode); + +STATIC mp_uint_t webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + mp_uint_t out_sz; + do { + out_sz = _webrepl_read(self_in, buf, size, errcode); + } while (out_sz == -2); + return out_sz; +} + +STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + // We know that os.dupterm always calls with size = 1 + assert(size == 1); + mp_obj_webrepl_t *self = self_in; + const mp_stream_p_t *sock_stream = mp_get_stream(self->sock); + mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode); + //DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz); + if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { + return out_sz; + } + + if (self->state == STATE_PASSWD) { + char c = *(char*)buf; + if (c == '\r' || c == '\n') { + self->hdr.fname[self->data_to_recv] = 0; + DEBUG_printf("webrepl: entered password: %s\n", self->hdr.fname); + + if (strcmp(self->hdr.fname, webrepl_passwd) != 0) { + write_webrepl_str(self->sock, SSTR(denied_prompt)); + return 0; + } + + self->state = STATE_NORMAL; + self->data_to_recv = 0; + write_webrepl_str(self->sock, SSTR(connected_prompt)); + } else if (self->data_to_recv < 10) { + self->hdr.fname[self->data_to_recv++] = c; + } + return -2; + } + + // If last read data belonged to text record (== REPL) + int err; + if (sock_stream->ioctl(self->sock, MP_STREAM_GET_DATA_OPTS, 0, &err) == 1) { + return out_sz; + } + + DEBUG_printf("webrepl: received bin data, hdr_to_recv: %d, data_to_recv=%d\n", self->hdr_to_recv, self->data_to_recv); + + if (self->hdr_to_recv != 0) { + char *p = (char*)&self->hdr + sizeof(self->hdr) - self->hdr_to_recv; + *p++ = *(char*)buf; + if (--self->hdr_to_recv != 0) { + mp_uint_t hdr_sz = sock_stream->read(self->sock, p, self->hdr_to_recv, errcode); + if (hdr_sz == MP_STREAM_ERROR) { + return hdr_sz; + } + self->hdr_to_recv -= hdr_sz; + if (self->hdr_to_recv != 0) { + return -2; + } + } + + DEBUG_printf("webrepl: op: %d, file: %s, chunk @%x, sz=%d\n", self->hdr.type, self->hdr.fname, (uint32_t)self->hdr.offset, self->hdr.size); + + handle_op(self); + + return -2; + } + + if (self->data_to_recv != 0) { + static byte filebuf[512]; + filebuf[0] = *(byte*)buf; + mp_uint_t buf_sz = 1; + if (--self->data_to_recv != 0) { + size_t to_read = MIN(sizeof(filebuf) - 1, self->data_to_recv); + mp_uint_t sz = sock_stream->read(self->sock, filebuf + 1, to_read, errcode); + if (sz == MP_STREAM_ERROR) { + return sz; + } + self->data_to_recv -= sz; + buf_sz += sz; + } + + if (self->hdr.type == PUT_FILE) { + DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz); + int err; + mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err); + if (err != 0 || res != buf_sz) { + assert(0); + } + } else if (self->hdr.type == GET_FILE) { + assert(buf_sz == 1); + assert(self->data_to_recv == 0); + assert(filebuf[0] == 0); + mp_uint_t out_sz = write_file_chunk(self); + if (out_sz != 0) { + self->data_to_recv = 1; + } + } + + if (self->data_to_recv == 0) { + mp_stream_close(self->cur_file); + self->hdr_to_recv = sizeof(struct webrepl_file); + DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); + write_webrepl_resp(self->sock, 0); + } + + #ifdef MICROPY_PY_WEBREPL_DELAY + // Some platforms may have broken drivers and easily gets + // overloaded with modest traffic WebREPL file transfers + // generate. The basic workaround is a crude rate control + // done in such way. + mp_hal_delay_ms(MICROPY_PY_WEBREPL_DELAY); + #endif + } + + return -2; +} + +STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_webrepl_t *self = self_in; + if (self->state == STATE_PASSWD) { + // Don't forward output until passwd is entered + return size; + } + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); + return stream_p->write(self->sock, buf, size, errcode); +} + +STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // TODO: This is a place to do cleanup + mp_stream_close(self->sock); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { + size_t len; + const char *passwd = mp_obj_str_get_data(passwd_in, &len); + if (len > sizeof(webrepl_passwd) - 1) { + mp_raise_ValueError(NULL); + } + strcpy(webrepl_passwd, passwd); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password); + +STATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); + +STATIC const mp_stream_p_t webrepl_stream_p = { + .read = webrepl_read, + .write = webrepl_write, + .ioctl = webrepl_ioctl, +}; + +STATIC const mp_obj_type_t webrepl_type = { + { &mp_type_type }, + .name = MP_QSTR__webrepl, + .make_new = webrepl_make_new, + .protocol = &webrepl_stream_p, + .locals_dict = (mp_obj_dict_t*)&webrepl_locals_dict, +}; + +STATIC const mp_rom_map_elem_t webrepl_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__webrepl) }, + { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&webrepl_type) }, + { MP_ROM_QSTR(MP_QSTR_password), MP_ROM_PTR(&webrepl_set_password_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(webrepl_module_globals, webrepl_module_globals_table); + +const mp_obj_module_t mp_module_webrepl = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&webrepl_module_globals, +}; + +#endif // MICROPY_PY_WEBREPL diff --git a/src/openmv/src/micropython/extmod/modwebsocket.c b/src/openmv/src/micropython/extmod/modwebsocket.c new file mode 100755 index 0000000..c556f2b --- /dev/null +++ b/src/openmv/src/micropython/extmod/modwebsocket.c @@ -0,0 +1,314 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "extmod/modwebsocket.h" + +#if MICROPY_PY_WEBSOCKET + +enum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL }; + +enum { BLOCKING_WRITE = 0x80 }; + +typedef struct _mp_obj_websocket_t { + mp_obj_base_t base; + mp_obj_t sock; + uint32_t msg_sz; + byte mask[4]; + byte state; + byte to_recv; + byte mask_pos; + byte buf_pos; + byte buf[6]; + byte opts; + // Copy of last data frame flags + byte ws_flags; + // Copy of current frame flags + byte last_flags; +} mp_obj_websocket_t; + +STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode); + +STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t); + o->base.type = type; + o->sock = args[0]; + o->state = FRAME_HEADER; + o->to_recv = 2; + o->mask_pos = 0; + o->buf_pos = 0; + o->opts = FRAME_TXT; + if (n_args > 1 && args[1] == mp_const_true) { + o->opts |= BLOCKING_WRITE; + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); + while (1) { + if (self->to_recv != 0) { + mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode); + if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { + return out_sz; + } + self->buf_pos += out_sz; + self->to_recv -= out_sz; + if (self->to_recv != 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + } + + switch (self->state) { + case FRAME_HEADER: { + // TODO: Split frame handling below is untested so far, so conservatively disable it + assert(self->buf[0] & 0x80); + + // "Control frames MAY be injected in the middle of a fragmented message." + // So, they must be processed before data frames (and not alter + // self->ws_flags) + byte frame_type = self->buf[0]; + self->last_flags = frame_type; + frame_type &= FRAME_OPCODE_MASK; + + if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) { + // Preserve previous frame type + self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK); + } else { + self->ws_flags = self->buf[0]; + } + + // Reset mask in case someone will use "simplified" protocol + // without masks. + memset(self->mask, 0, sizeof(self->mask)); + + int to_recv = 0; + size_t sz = self->buf[1] & 0x7f; + if (sz == 126) { + // Msg size is next 2 bytes + to_recv += 2; + } else if (sz == 127) { + // Msg size is next 8 bytes + assert(0); + } + if (self->buf[1] & 0x80) { + // Next 4 bytes is mask + to_recv += 4; + } + + self->buf_pos = 0; + self->to_recv = to_recv; + self->msg_sz = sz; // May be overridden by FRAME_OPT + if (to_recv != 0) { + self->state = FRAME_OPT; + } else { + if (frame_type >= FRAME_CLOSE) { + self->state = CONTROL; + } else { + self->state = PAYLOAD; + } + } + continue; + } + + case FRAME_OPT: { + if ((self->buf_pos & 3) == 2) { + // First two bytes are message length + self->msg_sz = (self->buf[0] << 8) | self->buf[1]; + } + if (self->buf_pos >= 4) { + // Last 4 bytes is mask + memcpy(self->mask, self->buf + self->buf_pos - 4, 4); + } + self->buf_pos = 0; + if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) { + self->state = CONTROL; + } else { + self->state = PAYLOAD; + } + continue; + } + + case PAYLOAD: + case CONTROL: { + mp_uint_t out_sz = 0; + if (self->msg_sz == 0) { + // In case message had zero payload + goto no_payload; + } + + size_t sz = MIN(size, self->msg_sz); + out_sz = stream_p->read(self->sock, buf, sz, errcode); + if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { + return out_sz; + } + + sz = out_sz; + for (byte *p = buf; sz--; p++) { + *p ^= self->mask[self->mask_pos++ & 3]; + } + + self->msg_sz -= out_sz; + if (self->msg_sz == 0) { + byte last_state; +no_payload: + last_state = self->state; + self->state = FRAME_HEADER; + self->to_recv = 2; + self->mask_pos = 0; + self->buf_pos = 0; + + // Handle control frame + if (last_state == CONTROL) { + byte frame_type = self->last_flags & FRAME_OPCODE_MASK; + if (frame_type == FRAME_CLOSE) { + static char close_resp[2] = {0x88, 0}; + int err; + websocket_write(self_in, close_resp, sizeof(close_resp), &err); + return 0; + } + + //DEBUG_printf("Finished receiving ctrl message %x, ignoring\n", self->last_flags); + continue; + } + } + + if (out_sz != 0) { + return out_sz; + } + // Empty (data) frame received is not EOF + continue; + } + + } + } +} + +STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); + assert(size < 0x10000); + byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)}; + int hdr_sz; + if (size < 126) { + header[1] = size; + hdr_sz = 2; + } else { + header[1] = 126; + header[2] = size >> 8; + header[3] = size & 0xff; + hdr_sz = 4; + } + + mp_obj_t dest[3]; + if (self->opts & BLOCKING_WRITE) { + mp_load_method(self->sock, MP_QSTR_setblocking, dest); + dest[2] = mp_const_true; + mp_call_method_n_kw(1, 0, dest); + } + + mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode); + if (*errcode == 0) { + out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode); + } + + if (self->opts & BLOCKING_WRITE) { + dest[2] = mp_const_false; + mp_call_method_n_kw(1, 0, dest); + } + + if (*errcode != 0) { + return MP_STREAM_ERROR; + } + return out_sz; +} + +STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); + switch (request) { + case MP_STREAM_CLOSE: + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + mp_stream_close(self->sock); + return 0; + case MP_STREAM_GET_DATA_OPTS: + return self->ws_flags & FRAME_OPCODE_MASK; + case MP_STREAM_SET_DATA_OPTS: { + int cur = self->opts & FRAME_OPCODE_MASK; + self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK); + return cur; + } + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); + +STATIC const mp_stream_p_t websocket_stream_p = { + .read = websocket_read, + .write = websocket_write, + .ioctl = websocket_ioctl, +}; + +STATIC const mp_obj_type_t websocket_type = { + { &mp_type_type }, + .name = MP_QSTR_websocket, + .make_new = websocket_make_new, + .protocol = &websocket_stream_p, + .locals_dict = (void*)&websocket_locals_dict, +}; + +STATIC const mp_rom_map_elem_t websocket_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_websocket) }, + { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table); + +const mp_obj_module_t mp_module_websocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&websocket_module_globals, +}; + +#endif // MICROPY_PY_WEBSOCKET diff --git a/src/openmv/src/micropython/extmod/modwebsocket.h b/src/openmv/src/micropython/extmod/modwebsocket.h new file mode 100755 index 0000000..2720147 --- /dev/null +++ b/src/openmv/src/micropython/extmod/modwebsocket.h @@ -0,0 +1,10 @@ +#ifndef MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H +#define MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H + +#define FRAME_OPCODE_MASK 0x0f +enum { + FRAME_CONT, FRAME_TXT, FRAME_BIN, + FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG +}; + +#endif // MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H diff --git a/src/openmv/src/micropython/extmod/re1.5/charclass.c b/src/openmv/src/micropython/extmod/re1.5/charclass.c new file mode 100755 index 0000000..7f6388c --- /dev/null +++ b/src/openmv/src/micropython/extmod/re1.5/charclass.c @@ -0,0 +1,33 @@ +#include "re1.5.h" + +int _re1_5_classmatch(const char *pc, const char *sp) +{ + // pc points to "cnt" byte after opcode + int is_positive = (pc[-1] == Class); + int cnt = *pc++; + while (cnt--) { + if (*sp >= *pc && *sp <= pc[1]) return is_positive; + pc += 2; + } + return !is_positive; +} + +int _re1_5_namedclassmatch(const char *pc, const char *sp) +{ + // pc points to name of class + int off = (*pc >> 5) & 1; + if ((*pc | 0x20) == 'd') { + if (!(*sp >= '0' && *sp <= '9')) { + off ^= 1; + } + } else if ((*pc | 0x20) == 's') { + if (!(*sp == ' ' || (*sp >= '\t' && *sp <= '\r'))) { + off ^= 1; + } + } else { // w + if (!((*sp >= 'A' && *sp <= 'Z') || (*sp >= 'a' && *sp <= 'z') || (*sp >= '0' && *sp <= '9') || *sp == '_')) { + off ^= 1; + } + } + return off; +} diff --git a/src/openmv/src/micropython/extmod/re1.5/compilecode.c b/src/openmv/src/micropython/extmod/re1.5/compilecode.c new file mode 100755 index 0000000..a685a50 --- /dev/null +++ b/src/openmv/src/micropython/extmod/re1.5/compilecode.c @@ -0,0 +1,216 @@ +// Copyright 2014 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +#define INSERT_CODE(at, num, pc) \ + ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) +#define REL(at, to) (to - at - 2) +#define EMIT(at, byte) (code ? (code[at] = byte) : (at)) +#define PC (prog->bytelen) + +static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) +{ + char *code = sizecode ? NULL : prog->insts; + int start = PC; + int term = PC; + int alt_label = 0; + + for (; *re && *re != ')'; re++) { + switch (*re) { + case '\\': + re++; + if (!*re) return NULL; // Trailing backslash + if ((*re | 0x20) == 'd' || (*re | 0x20) == 's' || (*re | 0x20) == 'w') { + term = PC; + EMIT(PC++, NamedClass); + EMIT(PC++, *re); + prog->len++; + break; + } + default: + term = PC; + EMIT(PC++, Char); + EMIT(PC++, *re); + prog->len++; + break; + case '.': + term = PC; + EMIT(PC++, Any); + prog->len++; + break; + case '[': { + int cnt; + term = PC; + re++; + if (*re == '^') { + EMIT(PC++, ClassNot); + re++; + } else { + EMIT(PC++, Class); + } + PC++; // Skip # of pair byte + prog->len++; + for (cnt = 0; *re != ']'; re++, cnt++) { + if (!*re) return NULL; + EMIT(PC++, *re); + if (re[1] == '-' && re[2] != ']') { + re += 2; + } + EMIT(PC++, *re); + } + EMIT(term + 1, cnt); + break; + } + case '(': { + term = PC; + int sub = 0; + int capture = re[1] != '?' || re[2] != ':'; + + if (capture) { + sub = ++prog->sub; + EMIT(PC++, Save); + EMIT(PC++, 2 * sub); + prog->len++; + } else { + re += 2; + } + + re = _compilecode(re + 1, prog, sizecode); + if (re == NULL || *re != ')') return NULL; // error, or no matching paren + + if (capture) { + EMIT(PC++, Save); + EMIT(PC++, 2 * sub + 1); + prog->len++; + } + + break; + } + case '?': + if (PC == term) return NULL; // nothing to repeat + INSERT_CODE(term, 2, PC); + if (re[1] == '?') { + EMIT(term, RSplit); + re++; + } else { + EMIT(term, Split); + } + EMIT(term + 1, REL(term, PC)); + prog->len++; + term = PC; + break; + case '*': + if (PC == term) return NULL; // nothing to repeat + INSERT_CODE(term, 2, PC); + EMIT(PC, Jmp); + EMIT(PC + 1, REL(PC, term)); + PC += 2; + if (re[1] == '?') { + EMIT(term, RSplit); + re++; + } else { + EMIT(term, Split); + } + EMIT(term + 1, REL(term, PC)); + prog->len += 2; + term = PC; + break; + case '+': + if (PC == term) return NULL; // nothing to repeat + if (re[1] == '?') { + EMIT(PC, Split); + re++; + } else { + EMIT(PC, RSplit); + } + EMIT(PC + 1, REL(PC, term)); + PC += 2; + prog->len++; + term = PC; + break; + case '|': + if (alt_label) { + EMIT(alt_label, REL(alt_label, PC) + 1); + } + INSERT_CODE(start, 2, PC); + EMIT(PC++, Jmp); + alt_label = PC++; + EMIT(start, Split); + EMIT(start + 1, REL(start, PC)); + prog->len += 2; + term = PC; + break; + case '^': + EMIT(PC++, Bol); + prog->len++; + term = PC; + break; + case '$': + EMIT(PC++, Eol); + prog->len++; + term = PC; + break; + } + } + + if (alt_label) { + EMIT(alt_label, REL(alt_label, PC) + 1); + } + return re; +} + +int re1_5_sizecode(const char *re) +{ + ByteProg dummyprog = { + // Save 0, Save 1, Match; more bytes for "search" (vs "match") prefix code + .bytelen = 5 + NON_ANCHORED_PREFIX + }; + + if (_compilecode(re, &dummyprog, /*sizecode*/1) == NULL) return -1; + + return dummyprog.bytelen; +} + +int re1_5_compilecode(ByteProg *prog, const char *re) +{ + prog->len = 0; + prog->bytelen = 0; + prog->sub = 0; + + // Add code to implement non-anchored operation ("search"), + // for anchored operation ("match"), this code will be just skipped. + // TODO: Implement search in much more efficient manner + prog->insts[prog->bytelen++] = RSplit; + prog->insts[prog->bytelen++] = 3; + prog->insts[prog->bytelen++] = Any; + prog->insts[prog->bytelen++] = Jmp; + prog->insts[prog->bytelen++] = -5; + prog->len += 3; + + prog->insts[prog->bytelen++] = Save; + prog->insts[prog->bytelen++] = 0; + prog->len++; + + re = _compilecode(re, prog, /*sizecode*/0); + if (re == NULL || *re) return 1; + + prog->insts[prog->bytelen++] = Save; + prog->insts[prog->bytelen++] = 1; + prog->len++; + + prog->insts[prog->bytelen++] = Match; + prog->len++; + + return 0; +} + +#if 0 +int main(int argc, char *argv[]) +{ + int pc = 0; + ByteProg *code = re1_5_compilecode(argv[1]); + re1_5_dumpcode(code); +} +#endif diff --git a/src/openmv/src/micropython/extmod/re1.5/dumpcode.c b/src/openmv/src/micropython/extmod/re1.5/dumpcode.c new file mode 100755 index 0000000..d7781d8 --- /dev/null +++ b/src/openmv/src/micropython/extmod/re1.5/dumpcode.c @@ -0,0 +1,65 @@ +// Copyright 2014 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +void re1_5_dumpcode(ByteProg *prog) +{ + int pc = 0; + char *code = prog->insts; + while (pc < prog->bytelen) { + printf("%2d: ", pc); + switch(code[pc++]) { + default: + assert(0); +// re1_5_fatal("printprog"); + case Split: + printf("split %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case RSplit: + printf("rsplit %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case Jmp: + printf("jmp %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case Char: + printf("char %c\n", code[pc++]); + break; + case Any: + printf("any\n"); + break; + case Class: + case ClassNot: { + int num = code[pc]; + printf("class%s %d", (code[pc - 1] == ClassNot ? "not" : ""), num); + pc++; + while (num--) { + printf(" 0x%02x-0x%02x", code[pc], code[pc + 1]); + pc += 2; + } + printf("\n"); + break; + } + case NamedClass: + printf("namedclass %c\n", code[pc++]); + break; + case Match: + printf("match\n"); + break; + case Save: + printf("save %d\n", (unsigned char)code[pc++]); + break; + case Bol: + printf("assert bol\n"); + break; + case Eol: + printf("assert eol\n"); + break; + } + } + printf("Bytes: %d, insts: %d\n", prog->bytelen, prog->len); +} diff --git a/src/openmv/src/micropython/extmod/re1.5/re1.5.h b/src/openmv/src/micropython/extmod/re1.5/re1.5.h new file mode 100755 index 0000000..ba6f97b --- /dev/null +++ b/src/openmv/src/micropython/extmod/re1.5/re1.5.h @@ -0,0 +1,154 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Copyright 2014 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef _RE1_5_REGEXP__H +#define _RE1_5_REGEXP__H + +#include +#include +#include +#include +#include + +#define nil ((void*)0) +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + +typedef struct Regexp Regexp; +typedef struct Prog Prog; +typedef struct ByteProg ByteProg; +typedef struct Inst Inst; +typedef struct Subject Subject; + +struct Regexp +{ + int type; + int n; + int ch; + Regexp *left; + Regexp *right; +}; + +enum /* Regexp.type */ +{ + Alt = 1, + Cat, + Lit, + Dot, + Paren, + Quest, + Star, + Plus, +}; + +Regexp *parse(char*); +Regexp *reg(int type, Regexp *left, Regexp *right); +void printre(Regexp*); +#ifndef re1_5_fatal +void re1_5_fatal(char*); +#endif +#ifndef re1_5_stack_chk +#define re1_5_stack_chk() +#endif +void *mal(int); + +struct Prog +{ + Inst *start; + int len; +}; + +struct ByteProg +{ + int bytelen; + int len; + int sub; + char insts[0]; +}; + +struct Inst +{ + int opcode; + int c; + int n; + Inst *x; + Inst *y; + int gen; // global state, oooh! +}; + +enum /* Inst.opcode */ +{ + // Instructions which consume input bytes (and thus fail if none left) + CONSUMERS = 1, + Char = CONSUMERS, + Any, + Class, + ClassNot, + NamedClass, + + ASSERTS = 0x50, + Bol = ASSERTS, + Eol, + + // Instructions which take relative offset as arg + JUMPS = 0x60, + Jmp = JUMPS, + Split, + RSplit, + + // Other (special) instructions + Save = 0x7e, + Match = 0x7f, +}; + +#define inst_is_consumer(inst) ((inst) < ASSERTS) +#define inst_is_jump(inst) ((inst) & 0x70 == JUMPS) + +Prog *compile(Regexp*); +void printprog(Prog*); + +extern int gen; + +enum { + MAXSUB = 20 +}; + +typedef struct Sub Sub; + +struct Sub +{ + int ref; + int nsub; + const char *sub[MAXSUB]; +}; + +Sub *newsub(int n); +Sub *incref(Sub*); +Sub *copy(Sub*); +Sub *update(Sub*, int, const char*); +void decref(Sub*); + +struct Subject { + const char *begin; + const char *end; +}; + + +#define NON_ANCHORED_PREFIX 5 +#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode)) + +int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int); +int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int); +int re1_5_recursiveloopprog(ByteProg*, Subject*, const char**, int, int); +int re1_5_recursiveprog(ByteProg*, Subject*, const char**, int, int); +int re1_5_thompsonvm(ByteProg*, Subject*, const char**, int, int); + +int re1_5_sizecode(const char *re); +int re1_5_compilecode(ByteProg *prog, const char *re); +void re1_5_dumpcode(ByteProg *prog); +void cleanmarks(ByteProg *prog); +int _re1_5_classmatch(const char *pc, const char *sp); +int _re1_5_namedclassmatch(const char *pc, const char *sp); + +#endif /*_RE1_5_REGEXP__H*/ diff --git a/src/openmv/src/micropython/extmod/re1.5/recursiveloop.c b/src/openmv/src/micropython/extmod/re1.5/recursiveloop.c new file mode 100755 index 0000000..bb337de --- /dev/null +++ b/src/openmv/src/micropython/extmod/re1.5/recursiveloop.c @@ -0,0 +1,86 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +static int +recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int nsubp) +{ + const char *old; + int off; + + re1_5_stack_chk(); + + for(;;) { + if(inst_is_consumer(*pc)) { + // If we need to match a character, but there's none left, it's fail + if(sp >= input->end) + return 0; + } + switch(*pc++) { + case Char: + if(*sp != *pc++) + return 0; + case Any: + sp++; + continue; + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) + return 0; + pc += *(unsigned char*)pc * 2 + 1; + sp++; + continue; + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) + return 0; + pc++; + sp++; + continue; + case Match: + return 1; + case Jmp: + off = (signed char)*pc++; + pc = pc + off; + continue; + case Split: + off = (signed char)*pc++; + if(recursiveloop(pc, sp, input, subp, nsubp)) + return 1; + pc = pc + off; + continue; + case RSplit: + off = (signed char)*pc++; + if(recursiveloop(pc + off, sp, input, subp, nsubp)) + return 1; + continue; + case Save: + off = (unsigned char)*pc++; + if(off >= nsubp) { + continue; + } + old = subp[off]; + subp[off] = sp; + if(recursiveloop(pc, sp, input, subp, nsubp)) + return 1; + subp[off] = old; + return 0; + case Bol: + if(sp != input->begin) + return 0; + continue; + case Eol: + if(sp != input->end) + return 0; + continue; + } + re1_5_fatal("recursiveloop"); + } +} + +int +re1_5_recursiveloopprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + return recursiveloop(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp); +} diff --git a/src/openmv/src/micropython/extmod/uos_dupterm.c b/src/openmv/src/micropython/extmod/uos_dupterm.c new file mode 100755 index 0000000..dec3e1a --- /dev/null +++ b/src/openmv/src/micropython/extmod/uos_dupterm.c @@ -0,0 +1,136 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mpconfig.h" + +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/objarray.h" +#include "py/stream.h" +#include "lib/utils/interrupt_char.h" + +#if MICROPY_PY_OS_DUPTERM + +void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) { + mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]); + MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL; + mp_printf(&mp_plat_print, msg); + if (exc != MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, exc); + } + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_stream_close(term); + nlr_pop(); + } else { + // Ignore any errors during stream closing + } +} + +int mp_uos_dupterm_rx_chr(void) { + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { + continue; + } + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + byte buf[1]; + int errcode; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); + mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode); + if (out_sz == 0) { + nlr_pop(); + mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL); + } else if (out_sz == MP_STREAM_ERROR) { + // errcode is valid + if (mp_is_nonblocking_error(errcode)) { + nlr_pop(); + } else { + mp_raise_OSError(errcode); + } + } else { + // read 1 byte + nlr_pop(); + if (buf[0] == mp_interrupt_char) { + // Signal keyboard interrupt to be raised as soon as the VM resumes + mp_keyboard_interrupt(); + return -2; + } + return buf[0]; + } + } else { + mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } + + // No chars available + return -1; +} + +void mp_uos_dupterm_tx_strn(const char *str, size_t len) { + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { + continue; + } + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE); + nlr_pop(); + } else { + mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } +} + +STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) { + mp_int_t idx = 0; + if (n_args == 2) { + idx = mp_obj_get_int(args[1]); + } + + if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) { + mp_raise_ValueError("invalid dupterm index"); + } + + mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]); + if (previous_obj == MP_OBJ_NULL) { + previous_obj = mp_const_none; + } + if (args[0] == mp_const_none) { + MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; + } else { + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + MP_STATE_VM(dupterm_objs[idx]) = args[0]; + } + + return previous_obj; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm); + +#endif diff --git a/src/openmv/src/micropython/extmod/utime_mphal.c b/src/openmv/src/micropython/extmod/utime_mphal.c new file mode 100755 index 0000000..0fe3a3b --- /dev/null +++ b/src/openmv/src/micropython/extmod/utime_mphal.c @@ -0,0 +1,102 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME_MP_HAL + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "py/smallint.h" +#include "py/runtime.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + #if MICROPY_PY_BUILTINS_FLOAT + mp_hal_delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o))); + #else + mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); + #endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); + +STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { + mp_int_t ms = mp_obj_get_int(arg); + if (ms > 0) { + mp_hal_delay_ms(ms); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms); + +STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { + mp_int_t us = mp_obj_get_int(arg); + if (us > 0) { + mp_hal_delay_us(us); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); + +STATIC mp_obj_t time_ticks_ms(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); + +STATIC mp_obj_t time_ticks_us(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); + +STATIC mp_obj_t time_ticks_cpu(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); + +STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) { + // we assume that the arguments come from ticks_xx so are small ints + mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + // Optimized formula avoiding if conditions. We adjust difference "forward", + // wrap it around and adjust back. + mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)) + - MICROPY_PY_UTIME_TICKS_PERIOD / 2; + return MP_OBJ_NEW_SMALL_INT(diff); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); + +STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) { + // we assume that first argument come from ticks_xx so is small int + mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in); + mp_uint_t delta = mp_obj_get_int(delta_in); + return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); + +#endif // MICROPY_PY_UTIME_MP_HAL diff --git a/src/openmv/src/micropython/extmod/utime_mphal.h b/src/openmv/src/micropython/extmod/utime_mphal.h new file mode 100755 index 0000000..88a9ed4 --- /dev/null +++ b/src/openmv/src/micropython/extmod/utime_mphal.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H +#define MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H + +#include "py/obj.h" + +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H diff --git a/src/openmv/src/micropython/extmod/uzlib/adler32.c b/src/openmv/src/micropython/extmod/uzlib/adler32.c new file mode 100755 index 0000000..1f17594 --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/adler32.c @@ -0,0 +1,78 @@ +/* + * Adler-32 checksum + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +/* + * Adler-32 algorithm taken from the zlib source, which is + * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + */ + +#include "tinf.h" + +#define A32_BASE 65521 +#define A32_NMAX 5552 + +uint32_t uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum /* 1 */) +{ + const unsigned char *buf = (const unsigned char *)data; + + unsigned int s1 = prev_sum & 0xffff; + unsigned int s2 = prev_sum >> 16; + + while (length > 0) + { + int k = length < A32_NMAX ? length : A32_NMAX; + int i; + + for (i = k / 16; i; --i, buf += 16) + { + s1 += buf[0]; s2 += s1; s1 += buf[1]; s2 += s1; + s1 += buf[2]; s2 += s1; s1 += buf[3]; s2 += s1; + s1 += buf[4]; s2 += s1; s1 += buf[5]; s2 += s1; + s1 += buf[6]; s2 += s1; s1 += buf[7]; s2 += s1; + + s1 += buf[8]; s2 += s1; s1 += buf[9]; s2 += s1; + s1 += buf[10]; s2 += s1; s1 += buf[11]; s2 += s1; + s1 += buf[12]; s2 += s1; s1 += buf[13]; s2 += s1; + s1 += buf[14]; s2 += s1; s1 += buf[15]; s2 += s1; + } + + for (i = k % 16; i; --i) { s1 += *buf++; s2 += s1; } + + s1 %= A32_BASE; + s2 %= A32_BASE; + + length -= k; + } + + return (s2 << 16) | s1; +} diff --git a/src/openmv/src/micropython/extmod/uzlib/crc32.c b/src/openmv/src/micropython/extmod/uzlib/crc32.c new file mode 100755 index 0000000..e24c643 --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/crc32.c @@ -0,0 +1,63 @@ +/* + * CRC32 checksum + * + * Copyright (c) 1998-2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +/* + * CRC32 algorithm taken from the zlib source, which is + * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + */ + +#include "tinf.h" + +static const unsigned int tinf_crc32tab[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, + 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, + 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, + 0xbdbdf21c +}; + +/* crc is previous value for incremental computation, 0xffffffff initially */ +uint32_t uzlib_crc32(const void *data, unsigned int length, uint32_t crc) +{ + const unsigned char *buf = (const unsigned char *)data; + unsigned int i; + + for (i = 0; i < length; ++i) + { + crc ^= buf[i]; + crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4); + crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4); + } + + // return value suitable for passing in next time, for final value invert it + return crc/* ^ 0xffffffff*/; +} diff --git a/src/openmv/src/micropython/extmod/uzlib/tinf.h b/src/openmv/src/micropython/extmod/uzlib/tinf.h new file mode 100755 index 0000000..106203a --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/tinf.h @@ -0,0 +1,117 @@ +/* + * uzlib - tiny deflate/inflate library (deflate, gzip, zlib) + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2016 by Paul Sokolovsky + */ + +#ifndef TINF_H_INCLUDED +#define TINF_H_INCLUDED + +#include + +/* calling convention */ +#ifndef TINFCC + #ifdef __WATCOMC__ + #define TINFCC __cdecl + #else + #define TINFCC + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ok status, more data produced */ +#define TINF_OK 0 +/* end of compressed stream reached */ +#define TINF_DONE 1 +#define TINF_DATA_ERROR (-3) +#define TINF_CHKSUM_ERROR (-4) +#define TINF_DICT_ERROR (-5) + +/* checksum types */ +#define TINF_CHKSUM_NONE 0 +#define TINF_CHKSUM_ADLER 1 +#define TINF_CHKSUM_CRC 2 + +/* data structures */ + +typedef struct { + unsigned short table[16]; /* table of code length counts */ + unsigned short trans[288]; /* code -> symbol translation table */ +} TINF_TREE; + +struct TINF_DATA; +typedef struct TINF_DATA { + const unsigned char *source; + /* If source above is NULL, this function will be used to read + next byte from source stream */ + unsigned char (*readSource)(struct TINF_DATA *data); + + unsigned int tag; + unsigned int bitcount; + + /* Buffer start */ + unsigned char *destStart; + /* Buffer total size */ + unsigned int destSize; + /* Current pointer in buffer */ + unsigned char *dest; + /* Remaining bytes in buffer */ + unsigned int destRemaining; + + /* Accumulating checksum */ + unsigned int checksum; + char checksum_type; + + int btype; + int bfinal; + unsigned int curlen; + int lzOff; + unsigned char *dict_ring; + unsigned int dict_size; + unsigned int dict_idx; + + TINF_TREE ltree; /* dynamic length/symbol tree */ + TINF_TREE dtree; /* dynamic distance tree */ +} TINF_DATA; + +#define TINF_PUT(d, c) \ + { \ + *d->dest++ = c; \ + if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \ + } + +unsigned char TINFCC uzlib_get_byte(TINF_DATA *d); + +/* Decompression API */ + +void TINFCC uzlib_init(void); +void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen); +int TINFCC uzlib_uncompress(TINF_DATA *d); +int TINFCC uzlib_uncompress_chksum(TINF_DATA *d); + +int TINFCC uzlib_zlib_parse_header(TINF_DATA *d); +int TINFCC uzlib_gzip_parse_header(TINF_DATA *d); + +/* Compression API */ + +void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen); + +/* Checksum API */ + +/* prev_sum is previous value for incremental computation, 1 initially */ +uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum); +/* crc is previous value for incremental computation, 0xffffffff initially */ +uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* TINF_H_INCLUDED */ diff --git a/src/openmv/src/micropython/extmod/uzlib/tinfgzip.c b/src/openmv/src/micropython/extmod/uzlib/tinfgzip.c new file mode 100755 index 0000000..f1afdd0 --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/tinfgzip.c @@ -0,0 +1,110 @@ +/* + * tinfgzip - tiny gzip decompressor + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2016 by Paul Sokolovsky + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +#include "tinf.h" + +#define FTEXT 1 +#define FHCRC 2 +#define FEXTRA 4 +#define FNAME 8 +#define FCOMMENT 16 + +void tinf_skip_bytes(TINF_DATA *d, int num); +uint16_t tinf_get_uint16(TINF_DATA *d); + +void tinf_skip_bytes(TINF_DATA *d, int num) +{ + while (num--) uzlib_get_byte(d); +} + +uint16_t tinf_get_uint16(TINF_DATA *d) +{ + unsigned int v = uzlib_get_byte(d); + v = (uzlib_get_byte(d) << 8) | v; + return v; +} + +int uzlib_gzip_parse_header(TINF_DATA *d) +{ + unsigned char flg; + + /* -- check format -- */ + + /* check id bytes */ + if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR; + + /* check method is deflate */ + if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR; + + /* get flag byte */ + flg = uzlib_get_byte(d); + + /* check that reserved bits are zero */ + if (flg & 0xe0) return TINF_DATA_ERROR; + + /* -- find start of compressed data -- */ + + /* skip rest of base header of 10 bytes */ + tinf_skip_bytes(d, 6); + + /* skip extra data if present */ + if (flg & FEXTRA) + { + unsigned int xlen = tinf_get_uint16(d); + tinf_skip_bytes(d, xlen); + } + + /* skip file name if present */ + if (flg & FNAME) { while (uzlib_get_byte(d)); } + + /* skip file comment if present */ + if (flg & FCOMMENT) { while (uzlib_get_byte(d)); } + + /* check header crc if present */ + if (flg & FHCRC) + { + /*unsigned int hcrc =*/ tinf_get_uint16(d); + + // TODO: Check! +// if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff)) +// return TINF_DATA_ERROR; + } + + /* initialize for crc32 checksum */ + d->checksum_type = TINF_CHKSUM_CRC; + d->checksum = ~0; + + return TINF_OK; +} diff --git a/src/openmv/src/micropython/extmod/uzlib/tinflate.c b/src/openmv/src/micropython/extmod/uzlib/tinflate.c new file mode 100755 index 0000000..21558af --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/tinflate.c @@ -0,0 +1,553 @@ +/* + * tinflate - tiny inflate + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2016 by Paul Sokolovsky + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +#include +#include "tinf.h" + +uint32_t tinf_get_le_uint32(TINF_DATA *d); +uint32_t tinf_get_be_uint32(TINF_DATA *d); + +/* --------------------------------------------------- * + * -- uninitialized global data (static structures) -- * + * --------------------------------------------------- */ + +#ifdef RUNTIME_BITS_TABLES + +/* extra bits and base tables for length codes */ +unsigned char length_bits[30]; +unsigned short length_base[30]; + +/* extra bits and base tables for distance codes */ +unsigned char dist_bits[30]; +unsigned short dist_base[30]; + +#else + +const unsigned char length_bits[30] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5 +}; +const unsigned short length_base[30] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 258 +}; + +const unsigned char dist_bits[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 +}; +const unsigned short dist_base[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, + 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577 +}; + +#endif + +/* special ordering of code length codes */ +const unsigned char clcidx[] = { + 16, 17, 18, 0, 8, 7, 9, 6, + 10, 5, 11, 4, 12, 3, 13, 2, + 14, 1, 15 +}; + +/* ----------------------- * + * -- utility functions -- * + * ----------------------- */ + +#ifdef RUNTIME_BITS_TABLES +/* build extra bits and base tables */ +static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first) +{ + int i, sum; + + /* build bits table */ + for (i = 0; i < delta; ++i) bits[i] = 0; + for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta; + + /* build base table */ + for (sum = first, i = 0; i < 30; ++i) + { + base[i] = sum; + sum += 1 << bits[i]; + } +} +#endif + +/* build the fixed huffman trees */ +static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt) +{ + int i; + + /* build fixed length tree */ + for (i = 0; i < 7; ++i) lt->table[i] = 0; + + lt->table[7] = 24; + lt->table[8] = 152; + lt->table[9] = 112; + + for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i; + for (i = 0; i < 144; ++i) lt->trans[24 + i] = i; + for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i; + for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i; + + /* build fixed distance tree */ + for (i = 0; i < 5; ++i) dt->table[i] = 0; + + dt->table[5] = 32; + + for (i = 0; i < 32; ++i) dt->trans[i] = i; +} + +/* given an array of code lengths, build a tree */ +static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num) +{ + unsigned short offs[16]; + unsigned int i, sum; + + /* clear code length count table */ + for (i = 0; i < 16; ++i) t->table[i] = 0; + + /* scan symbol lengths, and sum code length counts */ + for (i = 0; i < num; ++i) t->table[lengths[i]]++; + + t->table[0] = 0; + + /* compute offset table for distribution sort */ + for (sum = 0, i = 0; i < 16; ++i) + { + offs[i] = sum; + sum += t->table[i]; + } + + /* create code->symbol translation table (symbols sorted by code) */ + for (i = 0; i < num; ++i) + { + if (lengths[i]) t->trans[offs[lengths[i]]++] = i; + } +} + +/* ---------------------- * + * -- decode functions -- * + * ---------------------- */ + +unsigned char uzlib_get_byte(TINF_DATA *d) +{ + if (d->source) { + return *d->source++; + } + return d->readSource(d); +} + +uint32_t tinf_get_le_uint32(TINF_DATA *d) +{ + uint32_t val = 0; + int i; + for (i = 4; i--;) { + val = val >> 8 | uzlib_get_byte(d) << 24; + } + return val; +} + +uint32_t tinf_get_be_uint32(TINF_DATA *d) +{ + uint32_t val = 0; + int i; + for (i = 4; i--;) { + val = val << 8 | uzlib_get_byte(d); + } + return val; +} + +/* get one bit from source stream */ +static int tinf_getbit(TINF_DATA *d) +{ + unsigned int bit; + + /* check if tag is empty */ + if (!d->bitcount--) + { + /* load next tag */ + d->tag = uzlib_get_byte(d); + d->bitcount = 7; + } + + /* shift bit out of tag */ + bit = d->tag & 0x01; + d->tag >>= 1; + + return bit; +} + +/* read a num bit value from a stream and add base */ +static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base) +{ + unsigned int val = 0; + + /* read num bits */ + if (num) + { + unsigned int limit = 1 << (num); + unsigned int mask; + + for (mask = 1; mask < limit; mask *= 2) + if (tinf_getbit(d)) val += mask; + } + + return val + base; +} + +/* given a data stream and a tree, decode a symbol */ +static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t) +{ + int sum = 0, cur = 0, len = 0; + + /* get more bits while code value is above sum */ + do { + + cur = 2*cur + tinf_getbit(d); + + ++len; + + sum += t->table[len]; + cur -= t->table[len]; + + } while (cur >= 0); + + return t->trans[sum + cur]; +} + +/* given a data stream, decode dynamic trees from it */ +static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) +{ + unsigned char lengths[288+32]; + unsigned int hlit, hdist, hclen; + unsigned int i, num, length; + + /* get 5 bits HLIT (257-286) */ + hlit = tinf_read_bits(d, 5, 257); + + /* get 5 bits HDIST (1-32) */ + hdist = tinf_read_bits(d, 5, 1); + + /* get 4 bits HCLEN (4-19) */ + hclen = tinf_read_bits(d, 4, 4); + + for (i = 0; i < 19; ++i) lengths[i] = 0; + + /* read code lengths for code length alphabet */ + for (i = 0; i < hclen; ++i) + { + /* get 3 bits code length (0-7) */ + unsigned int clen = tinf_read_bits(d, 3, 0); + + lengths[clcidx[i]] = clen; + } + + /* build code length tree, temporarily use length tree */ + tinf_build_tree(lt, lengths, 19); + + /* decode code lengths for the dynamic trees */ + for (num = 0; num < hlit + hdist; ) + { + int sym = tinf_decode_symbol(d, lt); + + switch (sym) + { + case 16: + /* copy previous code length 3-6 times (read 2 bits) */ + { + unsigned char prev = lengths[num - 1]; + for (length = tinf_read_bits(d, 2, 3); length; --length) + { + lengths[num++] = prev; + } + } + break; + case 17: + /* repeat code length 0 for 3-10 times (read 3 bits) */ + for (length = tinf_read_bits(d, 3, 3); length; --length) + { + lengths[num++] = 0; + } + break; + case 18: + /* repeat code length 0 for 11-138 times (read 7 bits) */ + for (length = tinf_read_bits(d, 7, 11); length; --length) + { + lengths[num++] = 0; + } + break; + default: + /* values 0-15 represent the actual code lengths */ + lengths[num++] = sym; + break; + } + } + + /* build dynamic trees */ + tinf_build_tree(lt, lengths, hlit); + tinf_build_tree(dt, lengths + hlit, hdist); +} + +/* ----------------------------- * + * -- block inflate functions -- * + * ----------------------------- */ + +/* given a stream and two trees, inflate a block of data */ +static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) +{ + if (d->curlen == 0) { + unsigned int offs; + int dist; + int sym = tinf_decode_symbol(d, lt); + //printf("huff sym: %02x\n", sym); + + /* literal byte */ + if (sym < 256) { + TINF_PUT(d, sym); + return TINF_OK; + } + + /* end of block */ + if (sym == 256) { + return TINF_DONE; + } + + /* substring from sliding dictionary */ + sym -= 257; + /* possibly get more bits from length code */ + d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]); + + dist = tinf_decode_symbol(d, dt); + /* possibly get more bits from distance code */ + offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); + if (d->dict_ring) { + if (offs > d->dict_size) { + return TINF_DICT_ERROR; + } + d->lzOff = d->dict_idx - offs; + if (d->lzOff < 0) { + d->lzOff += d->dict_size; + } + } else { + d->lzOff = -offs; + } + } + + /* copy next byte from dict substring */ + if (d->dict_ring) { + TINF_PUT(d, d->dict_ring[d->lzOff]); + if ((unsigned)++d->lzOff == d->dict_size) { + d->lzOff = 0; + } + } else { + d->dest[0] = d->dest[d->lzOff]; + d->dest++; + } + d->curlen--; + return TINF_OK; +} + +/* inflate an uncompressed block of data */ +static int tinf_inflate_uncompressed_block(TINF_DATA *d) +{ + if (d->curlen == 0) { + unsigned int length, invlength; + + /* get length */ + length = uzlib_get_byte(d); + length += 256 * uzlib_get_byte(d); + /* get one's complement of length */ + invlength = uzlib_get_byte(d); + invlength += 256 * uzlib_get_byte(d); + /* check length */ + if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR; + + /* increment length to properly return TINF_DONE below, without + producing data at the same time */ + d->curlen = length + 1; + + /* make sure we start next block on a byte boundary */ + d->bitcount = 0; + } + + if (--d->curlen == 0) { + return TINF_DONE; + } + + unsigned char c = uzlib_get_byte(d); + TINF_PUT(d, c); + return TINF_OK; +} + +/* ---------------------- * + * -- public functions -- * + * ---------------------- */ + +/* initialize global (static) data */ +void uzlib_init(void) +{ +#ifdef RUNTIME_BITS_TABLES + /* build extra bits and base tables */ + tinf_build_bits_base(length_bits, length_base, 4, 3); + tinf_build_bits_base(dist_bits, dist_base, 2, 1); + + /* fix a special case */ + length_bits[28] = 0; + length_base[28] = 258; +#endif +} + +/* initialize decompression structure */ +void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen) +{ + d->bitcount = 0; + d->bfinal = 0; + d->btype = -1; + d->dict_size = dictLen; + d->dict_ring = dict; + d->dict_idx = 0; + d->curlen = 0; +} + +/* inflate next byte of compressed stream */ +int uzlib_uncompress(TINF_DATA *d) +{ + do { + int res; + + /* start a new block */ + if (d->btype == -1) { +next_blk: + /* read final block flag */ + d->bfinal = tinf_getbit(d); + /* read block type (2 bits) */ + d->btype = tinf_read_bits(d, 2, 0); + + //printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); + + if (d->btype == 1) { + /* build fixed huffman trees */ + tinf_build_fixed_trees(&d->ltree, &d->dtree); + } else if (d->btype == 2) { + /* decode trees from stream */ + tinf_decode_trees(d, &d->ltree, &d->dtree); + } + } + + /* process current block */ + switch (d->btype) + { + case 0: + /* decompress uncompressed block */ + res = tinf_inflate_uncompressed_block(d); + break; + case 1: + case 2: + /* decompress block with fixed/dyanamic huffman trees */ + /* trees were decoded previously, so it's the same routine for both */ + res = tinf_inflate_block_data(d, &d->ltree, &d->dtree); + break; + default: + return TINF_DATA_ERROR; + } + + if (res == TINF_DONE && !d->bfinal) { + /* the block has ended (without producing more data), but we + can't return without data, so start procesing next block */ + goto next_blk; + } + + if (res != TINF_OK) { + return res; + } + + } while (--d->destSize); + + return TINF_OK; +} + +int uzlib_uncompress_chksum(TINF_DATA *d) +{ + int res; + unsigned char *data = d->dest; + + res = uzlib_uncompress(d); + + if (res < 0) return res; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + d->checksum = uzlib_adler32(data, d->dest - data, d->checksum); + break; + + case TINF_CHKSUM_CRC: + d->checksum = uzlib_crc32(data, d->dest - data, d->checksum); + break; + } + + if (res == TINF_DONE) { + unsigned int val; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + val = tinf_get_be_uint32(d); + if (d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + break; + + case TINF_CHKSUM_CRC: + val = tinf_get_le_uint32(d); + if (~d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + // Uncompressed size. TODO: Check + val = tinf_get_le_uint32(d); + break; + } + } + + return res; +} diff --git a/src/openmv/src/micropython/extmod/uzlib/tinfzlib.c b/src/openmv/src/micropython/extmod/uzlib/tinfzlib.c new file mode 100755 index 0000000..74fade3 --- /dev/null +++ b/src/openmv/src/micropython/extmod/uzlib/tinfzlib.c @@ -0,0 +1,66 @@ +/* + * tinfzlib - tiny zlib decompressor + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2016 by Paul Sokolovsky + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +#include "tinf.h" + +int uzlib_zlib_parse_header(TINF_DATA *d) +{ + unsigned char cmf, flg; + + /* -- get header bytes -- */ + + cmf = uzlib_get_byte(d); + flg = uzlib_get_byte(d); + + /* -- check format -- */ + + /* check checksum */ + if ((256*cmf + flg) % 31) return TINF_DATA_ERROR; + + /* check method is deflate */ + if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR; + + /* check window size is valid */ + if ((cmf >> 4) > 7) return TINF_DATA_ERROR; + + /* check there is no preset dictionary */ + if (flg & 0x20) return TINF_DATA_ERROR; + + /* initialize for adler32 checksum */ + d->checksum_type = TINF_CHKSUM_ADLER; + d->checksum = 1; + + return cmf >> 4; +} diff --git a/src/openmv/src/micropython/extmod/vfs.c b/src/openmv/src/micropython/extmod/vfs.c new file mode 100755 index 0000000..e3fc73d --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs.c @@ -0,0 +1,488 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" + +#if MICROPY_VFS + +#if MICROPY_VFS_FAT +#include "extmod/vfs_fat.h" +#endif + +#if MICROPY_VFS_POSIX +#include "extmod/vfs_posix.h" +#endif + +// For mp_vfs_proxy_call, the maximum number of additional args that can be passed. +// A fixed maximum size is used to avoid the need for a costly variable array. +#define PROXY_MAX_ARGS (2) + +// path is the path to lookup and *path_out holds the path within the VFS +// object (starts with / if an absolute path). +// Returns MP_VFS_ROOT for root dir (and then path_out is undefined) and +// MP_VFS_NONE for path not found. +mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) { + if (*path == '/' || MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { + // an absolute path, or the current volume is root, so search root dir + bool is_abs = 0; + if (*path == '/') { + ++path; + is_abs = 1; + } + if (*path == '\0') { + // path is "" or "/" so return virtual root + return MP_VFS_ROOT; + } + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + size_t len = vfs->len - 1; + if (len == 0) { + *path_out = path - is_abs; + return vfs; + } + if (strncmp(path, vfs->str + 1, len) == 0) { + if (path[len] == '/') { + *path_out = path + len; + return vfs; + } else if (path[len] == '\0') { + *path_out = "/"; + return vfs; + } + } + } + + // if we get here then there's nothing mounted on / + + if (is_abs) { + // path began with / and was not found + return MP_VFS_NONE; + } + } + + // a relative path within a mounted device + *path_out = path; + return MP_STATE_VM(vfs_cur); +} + +// Version of mp_vfs_lookup_path that takes and returns uPy string objects. +STATIC mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) { + const char *path = mp_obj_str_get_str(path_in); + const char *p_out; + mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &p_out); + if (vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) { + *path_out = mp_obj_new_str_of_type(mp_obj_get_type(path_in), + (const byte*)p_out, strlen(p_out)); + } + return vfs; +} + +STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) { + assert(n_args <= PROXY_MAX_ARGS); + if (vfs == MP_VFS_NONE) { + // mount point not found + mp_raise_OSError(MP_ENODEV); + } + if (vfs == MP_VFS_ROOT) { + // can't do operation on root dir + mp_raise_OSError(MP_EPERM); + } + mp_obj_t meth[2 + PROXY_MAX_ARGS]; + mp_load_method(vfs->obj, meth_name, meth); + if (args != NULL) { + memcpy(meth + 2, args, n_args * sizeof(*args)); + } + return mp_call_method_n_kw(n_args, 0, meth); +} +#if 0 +mp_import_stat_t mp_vfs_import_stat(const char *path) { + const char *path_out; + mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &path_out); + if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) { + return MP_IMPORT_STAT_NO_EXIST; + } + + // If the mounted object has the VFS protocol, call its import_stat helper + const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol; + if (proto != NULL) { + return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + } + + // delegate to vfs.stat() method + mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); + mp_obj_t stat; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o); + nlr_pop(); + } else { + // assume an exception means that the path is not found + return MP_IMPORT_STAT_NO_EXIST; + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(stat, 10, &items); + mp_int_t st_mode = mp_obj_get_int(items[0]); + if (st_mode & MP_S_IFDIR) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } +} +#endif +mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_readonly, ARG_mkfs }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, + { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the mount point + size_t mnt_len; + const char *mnt_str = mp_obj_str_get_data(pos_args[1], &mnt_len); + + // see if we need to auto-detect and create the filesystem + mp_obj_t vfs_obj = pos_args[0]; + mp_obj_t dest[2]; + mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest); + if (dest[0] == MP_OBJ_NULL) { + // Input object has no mount method, assume it's a block device and try to + // auto-detect the filesystem and create the corresponding VFS entity. + // (At the moment we only support FAT filesystems.) + #if MICROPY_VFS_FAT + vfs_obj = mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &vfs_obj); + #endif + } + + // create new object + mp_vfs_mount_t *vfs = m_new_obj(mp_vfs_mount_t); + vfs->str = mnt_str; + vfs->len = mnt_len; + vfs->obj = vfs_obj; + vfs->next = NULL; + + // call the underlying object to do any mounting operation + mp_vfs_proxy_call(vfs, MP_QSTR_mount, 2, (mp_obj_t*)&args); + + // check that the destination mount point is unused + const char *path_out; + mp_vfs_mount_t *existing_mount = mp_vfs_lookup_path(mp_obj_str_get_str(pos_args[1]), &path_out); + if (existing_mount != MP_VFS_NONE && existing_mount != MP_VFS_ROOT) { + if (vfs->len != 1 && existing_mount->len == 1) { + // if root dir is mounted, still allow to mount something within a subdir of root + } else { + // mount point in use + mp_raise_OSError(MP_EPERM); + } + } + + // insert the vfs into the mount table + mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); + while (*vfsp != NULL) { + if ((*vfsp)->len == 1) { + // make sure anything mounted at the root stays at the end of the list + vfs->next = *vfsp; + break; + } + vfsp = &(*vfsp)->next; + } + *vfsp = vfs; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj, 2, mp_vfs_mount); + +mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { + // remove vfs from the mount table + mp_vfs_mount_t *vfs = NULL; + size_t mnt_len; + const char *mnt_str = NULL; + if (MP_OBJ_IS_STR(mnt_in)) { + mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len); + } + for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) { + if ((mnt_str != NULL && !memcmp(mnt_str, (*vfsp)->str, mnt_len + 1)) || (*vfsp)->obj == mnt_in) { + vfs = *vfsp; + *vfsp = (*vfsp)->next; + break; + } + } + + if (vfs == NULL) { + mp_raise_OSError(MP_EINVAL); + } + + // if we unmounted the current device then set current to root + if (MP_STATE_VM(vfs_cur) == vfs) { + MP_STATE_VM(vfs_cur) = MP_VFS_ROOT; + } + + // call the underlying object to do any unmounting operation + mp_vfs_proxy_call(vfs, MP_QSTR_umount, 0, NULL); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount); + +// Note: buffering and encoding args are currently ignored +mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_file, ARG_mode, ARG_encoding }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + #if MICROPY_VFS_POSIX + // If the file is an integer then delegate straight to the POSIX handler + if (MP_OBJ_IS_SMALL_INT(args[ARG_file].u_obj)) { + return mp_vfs_posix_file_open(&mp_type_textio, args[ARG_file].u_obj, args[ARG_mode].u_obj); + } + #endif + + mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj); + return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open); + +mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + MP_STATE_VM(vfs_cur) = vfs; + if (vfs == MP_VFS_ROOT) { + // If we change to the root dir and a VFS is mounted at the root then + // we must change that VFS's current dir to the root dir so that any + // subsequent relative paths begin at the root of that VFS. + for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + if (vfs->len == 1) { + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root); + break; + } + } + } else { + mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir); + +mp_obj_t mp_vfs_getcwd(void) { + if (MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { + return MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + } + mp_obj_t cwd_o = mp_vfs_proxy_call(MP_STATE_VM(vfs_cur), MP_QSTR_getcwd, 0, NULL); + if (MP_STATE_VM(vfs_cur)->len == 1) { + // don't prepend "/" for vfs mounted at root + return cwd_o; + } + const char *cwd = mp_obj_str_get_str(cwd_o); + vstr_t vstr; + vstr_init(&vstr, MP_STATE_VM(vfs_cur)->len + strlen(cwd) + 1); + vstr_add_strn(&vstr, MP_STATE_VM(vfs_cur)->str, MP_STATE_VM(vfs_cur)->len); + if (!(cwd[0] == '/' && cwd[1] == 0)) { + vstr_add_str(&vstr, cwd); + } + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj, mp_vfs_getcwd); + +typedef struct _mp_vfs_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + union { + mp_vfs_mount_t *vfs; + mp_obj_t iter; + } cur; + bool is_str; + bool is_iter; +} mp_vfs_ilistdir_it_t; + +STATIC mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) { + mp_vfs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + if (self->is_iter) { + // continue delegating to root dir + return mp_iternext(self->cur.iter); + } else if (self->cur.vfs == NULL) { + // finished iterating mount points and no root dir is mounted + return MP_OBJ_STOP_ITERATION; + } else { + // continue iterating mount points + mp_vfs_mount_t *vfs = self->cur.vfs; + self->cur.vfs = vfs->next; + if (vfs->len == 1) { + // vfs is mounted at root dir, delegate to it + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + self->is_iter = true; + self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root); + return mp_iternext(self->cur.iter); + } else { + // a mounted directory + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + t->items[0] = mp_obj_new_str_of_type( + self->is_str ? &mp_type_str : &mp_type_bytes, + (const byte*)vfs->str + 1, vfs->len - 1); + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + return MP_OBJ_FROM_PTR(t); + } + } +} + +mp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args) { + mp_obj_t path_in; + if (n_args == 1) { + path_in = args[0]; + } else { + path_in = MP_OBJ_NEW_QSTR(MP_QSTR_); + } + + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + + if (vfs == MP_VFS_ROOT) { + // list the root directory + mp_vfs_ilistdir_it_t *iter = m_new_obj(mp_vfs_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = mp_vfs_ilistdir_it_iternext; + iter->cur.vfs = MP_STATE_VM(vfs_mount_table); + iter->is_str = mp_obj_get_type(path_in) == &mp_type_str; + iter->is_iter = false; + return MP_OBJ_FROM_PTR(iter); + } + + return mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj, 0, 1, mp_vfs_ilistdir); + +mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { + mp_obj_t iter = mp_vfs_ilistdir(n_args, args); + mp_obj_t dir_list = mp_obj_new_list(0, NULL); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); + } + return dir_list; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj, 0, 1, mp_vfs_listdir); + +mp_obj_t mp_vfs_mkdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + if (vfs == MP_VFS_ROOT || (vfs != MP_VFS_NONE && !strcmp(mp_obj_str_get_str(path_out), "/"))) { + mp_raise_OSError(MP_EEXIST); + } + return mp_vfs_proxy_call(vfs, MP_QSTR_mkdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj, mp_vfs_mkdir); + +mp_obj_t mp_vfs_remove(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_remove, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_remove_obj, mp_vfs_remove); + +mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { + mp_obj_t args[2]; + mp_vfs_mount_t *old_vfs = lookup_path(old_path_in, &args[0]); + mp_vfs_mount_t *new_vfs = lookup_path(new_path_in, &args[1]); + if (old_vfs != new_vfs) { + // can't rename across filesystems + mp_raise_OSError(MP_EPERM); + } + return mp_vfs_proxy_call(old_vfs, MP_QSTR_rename, 2, args); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_vfs_rename_obj, mp_vfs_rename); + +mp_obj_t mp_vfs_rmdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_rmdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj, mp_vfs_rmdir); + +mp_obj_t mp_vfs_stat(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + if (vfs == MP_VFS_ROOT) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); // st_mode + for (int i = 1; i <= 9; ++i) { + t->items[i] = MP_OBJ_NEW_SMALL_INT(0); // dev, nlink, uid, gid, size, atime, mtime, ctime + } + return MP_OBJ_FROM_PTR(t); + } + return mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_stat_obj, mp_vfs_stat); + +mp_obj_t mp_vfs_statvfs(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + if (vfs == MP_VFS_ROOT) { + // statvfs called on the root directory, see if there's anything mounted there + for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + if (vfs->len == 1) { + break; + } + } + + // If there's nothing mounted at root then return a mostly-empty tuple + if (vfs == NULL) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + + // fill in: bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flags + for (int i = 0; i <= 8; ++i) { + t->items[i] = MP_OBJ_NEW_SMALL_INT(0); + } + + // Put something sensible in f_namemax + t->items[9] = MP_OBJ_NEW_SMALL_INT(MICROPY_ALLOC_PATH_MAX); + + return MP_OBJ_FROM_PTR(t); + } + + // VFS mounted at root so delegate the call to it + path_out = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + } + return mp_vfs_proxy_call(vfs, MP_QSTR_statvfs, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs); + +#endif // MICROPY_VFS diff --git a/src/openmv/src/micropython/extmod/vfs.h b/src/openmv/src/micropython/extmod/vfs.h new file mode 100755 index 0000000..730dea0 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs.h @@ -0,0 +1,90 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_H +#define MICROPY_INCLUDED_EXTMOD_VFS_H + +#include "py/lexer.h" +#include "py/obj.h" + +// return values of mp_vfs_lookup_path +// ROOT is 0 so that the default current directory is the root directory +#define MP_VFS_NONE ((mp_vfs_mount_t*)1) +#define MP_VFS_ROOT ((mp_vfs_mount_t*)0) + +// MicroPython's port-standardized versions of stat constants +#define MP_S_IFDIR (0x4000) +#define MP_S_IFREG (0x8000) + +// constants for block protocol ioctl +#define BP_IOCTL_INIT (1) +#define BP_IOCTL_DEINIT (2) +#define BP_IOCTL_SYNC (3) +#define BP_IOCTL_SEC_COUNT (4) +#define BP_IOCTL_SEC_SIZE (5) + +// At the moment the VFS protocol just has import_stat, but could be extended to other methods +typedef struct _mp_vfs_proto_t { + mp_import_stat_t (*import_stat)(void *self, const char *path); +} mp_vfs_proto_t; + +typedef struct _mp_vfs_mount_t { + const char *str; // mount point with leading / + size_t len; + mp_obj_t obj; + struct _mp_vfs_mount_t *next; +} mp_vfs_mount_t; + +mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out); +mp_import_stat_t mp_vfs_import_stat(const char *path); +mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +mp_obj_t mp_vfs_umount(mp_obj_t mnt_in); +mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +mp_obj_t mp_vfs_chdir(mp_obj_t path_in); +mp_obj_t mp_vfs_getcwd(void); +mp_obj_t mp_vfs_ilistdir(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_vfs_mkdir(mp_obj_t path_in); +mp_obj_t mp_vfs_remove(mp_obj_t path_in); +mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in); +mp_obj_t mp_vfs_rmdir(mp_obj_t path_in); +mp_obj_t mp_vfs_stat(mp_obj_t path_in); +mp_obj_t mp_vfs_statvfs(mp_obj_t path_in); + +MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_umount_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_open_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ilistdir_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_remove_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_vfs_rename_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_stat_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_H diff --git a/src/openmv/src/micropython/extmod/vfs_fat.c b/src/openmv/src/micropython/extmod/vfs_fat.c new file mode 100755 index 0000000..4af836b --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_fat.c @@ -0,0 +1,438 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_VFS_FAT + +#if !MICROPY_VFS +#error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_VFS" +#endif + +#include +#include "py/runtime.h" +#include "py/mperrno.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" +#include "lib/timeutils/timeutils.h" + +#if _MAX_SS == _MIN_SS +#define SECSIZE(fs) (_MIN_SS) +#else +#define SECSIZE(fs) ((fs)->ssize) +#endif + +#define mp_obj_fat_vfs_t fs_user_mount_t + +STATIC mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) { + fs_user_mount_t *vfs = vfs_in; + FILINFO fno; + assert(vfs != NULL); + FRESULT res = f_stat(&vfs->fatfs, path, &fno); + if (res == FR_OK) { + if ((fno.fattrib & AM_DIR) != 0) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // create new object + fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); + vfs->base.type = type; + vfs->flags = FSUSER_FREE_OBJ; + vfs->fatfs.drv = vfs; + + // load block protocol methods + mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks); + mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks); + mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl); + if (vfs->u.ioctl[0] != MP_OBJ_NULL) { + // device supports new block protocol, so indicate it + vfs->flags |= FSUSER_HAVE_IOCTL; + } else { + // no ioctl method, so assume the device uses the old block protocol + mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync); + mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); + } + + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res == FR_NO_FILESYSTEM) { + // don't error out if no filesystem, to let mkfs()/mount() create one if wanted + vfs->flags |= FSUSER_NO_FILESYSTEM; + } else if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return MP_OBJ_FROM_PTR(vfs); +} + +#if _FS_REENTRANT +STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in); + // f_umount only needs to be called to release the sync object + f_umount(&self->fatfs); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del); +#endif + +STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { + // create new object + fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); + + // make the filesystem + uint8_t working_buf[_MAX_SS]; + FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj)); + +typedef struct _mp_vfs_fat_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + FF_DIR dir; +} mp_vfs_fat_ilistdir_it_t; + +STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { + mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + for (;;) { + FILINFO fno; + FRESULT res = f_readdir(&self->dir, &fno); + char *fn = fno.fname; + if (res != FR_OK || fn[0] == 0) { + // stop on error or end of dir + break; + } + + // Note that FatFS already filters . and .., so we don't need to + + // make 4-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + if (fno.fattrib & AM_DIR) { + // dir + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else { + // file + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + t->items[3] = mp_obj_new_int_from_uint(fno.fsize); + + return MP_OBJ_FROM_PTR(t); + } + + // ignore error because we may be closing a second time + f_closedir(&self->dir); + + return MP_OBJ_STOP_ITERATION; +} + +STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]); + bool is_str_type = true; + const char *path; + if (n_args == 2) { + if (mp_obj_get_type(args[1]) == &mp_type_bytes) { + is_str_type = false; + } + path = mp_obj_str_get_str(args[1]); + } else { + path = ""; + } + + // Create a new iterator object to list the dir + mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = mp_vfs_fat_ilistdir_it_iternext; + iter->is_str = is_str_type; + FRESULT res = f_opendir(&self->fatfs, &iter->dir, path); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return MP_OBJ_FROM_PTR(iter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func); + +STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_int_t attr) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *path = mp_obj_str_get_str(path_in); + + FILINFO fno; + FRESULT res = f_stat(&self->fatfs, path, &fno); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + // check if path is a file or directory + if ((fno.fattrib & AM_DIR) == attr) { + res = f_unlink(&self->fatfs, path); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; + } else { + mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR); + } +} + +STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { + return fat_vfs_remove_internal(vfs_in, path_in, 0); // 0 == file attribute +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); + +STATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) { + return fat_vfs_remove_internal(vfs_in, path_in, AM_DIR); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir); + +STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_out) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *old_path = mp_obj_str_get_str(path_in); + const char *new_path = mp_obj_str_get_str(path_out); + FRESULT res = f_rename(&self->fatfs, old_path, new_path); + if (res == FR_EXIST) { + // if new_path exists then try removing it (but only if it's a file) + fat_vfs_remove_internal(vfs_in, path_out, 0); // 0 == file attribute + // try to rename again + res = f_rename(&self->fatfs, old_path, new_path); + } + if (res == FR_OK) { + return mp_const_none; + } else { + mp_raise_OSError(fresult_to_errno_table[res]); + } + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_rename_obj, fat_vfs_rename); + +STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *path = mp_obj_str_get_str(path_o); + FRESULT res = f_mkdir(&self->fatfs, path); + if (res == FR_OK) { + return mp_const_none; + } else { + mp_raise_OSError(fresult_to_errno_table[res]); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); + +/// Change current directory. +STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *path; + path = mp_obj_str_get_str(path_in); + + FRESULT res = f_chdir(&self->fatfs, path); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); + +/// Get the current directory. +STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf)); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_obj_new_str(buf, strlen(buf)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); + +/// \function stat(path) +/// Get the status of a file or directory. +STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *path = mp_obj_str_get_str(path_in); + + FILINFO fno; + if (path[0] == 0 || (path[0] == '/' && path[1] == 0)) { + // stat root directory + fno.fsize = 0; + fno.fdate = 0x2821; // Jan 1, 2000 + fno.ftime = 0; + fno.fattrib = AM_DIR; + } else { + FRESULT res = f_stat(&self->fatfs, path, &fno); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + mp_int_t mode = 0; + if (fno.fattrib & AM_DIR) { + mode |= MP_S_IFDIR; + } else { + mode |= MP_S_IFREG; + } + mp_int_t seconds = timeutils_seconds_since_2000( + 1980 + ((fno.fdate >> 9) & 0x7f), + (fno.fdate >> 5) & 0x0f, + fno.fdate & 0x1f, + (fno.ftime >> 11) & 0x1f, + (fno.ftime >> 5) & 0x3f, + 2 * (fno.ftime & 0x1f) + ); + t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev + t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink + t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid + t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size + t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime + t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime + t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); + +// Get the status of a VFS. +STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + (void)path_in; + + DWORD nclst; + FATFS *fatfs = &self->fatfs; + FRESULT res = f_getfree(fatfs, &nclst); + if (FR_OK != res) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + + t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * SECSIZE(fatfs)); // f_bsize + t->items[1] = t->items[0]; // f_frsize + t->items[2] = MP_OBJ_NEW_SMALL_INT((fatfs->n_fatent - 2)); // f_blocks + t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree + t->items[4] = t->items[3]; // f_bavail + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files + t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree + t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail + t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags + t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); + +STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + + // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. + // User can specify read-only device by: + // 1. readonly=True keyword argument + // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) + if (mp_obj_is_true(readonly)) { + self->writeblocks[0] = MP_OBJ_NULL; + } + + // check if we need to make the filesystem + FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; + if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + } + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + self->flags &= ~FSUSER_NO_FILESYSTEM; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount); + +STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) { + (void)self_in; + // keep the FAT filesystem mounted internally so the VFS methods can still be used + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); + +STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { + #if _FS_REENTRANT + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&fat_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&fat_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_fat_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); + +STATIC const mp_vfs_proto_t fat_vfs_proto = { + .import_stat = fat_vfs_import_stat, +}; + +const mp_obj_type_t mp_fat_vfs_type = { + { &mp_type_type }, + .name = MP_QSTR_VfsFat, + .make_new = fat_vfs_make_new, + .protocol = &fat_vfs_proto, + .locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict, + +}; + +#endif // MICROPY_VFS_FAT diff --git a/src/openmv/src/micropython/extmod/vfs_fat.h b/src/openmv/src/micropython/extmod/vfs_fat.h new file mode 100755 index 0000000..ba29153 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_fat.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H +#define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H + +#include "py/lexer.h" +#include "py/obj.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs.h" + +// these are the values for fs_user_mount_t.flags +#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func +#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount +#define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl +#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it + +typedef struct _fs_user_mount_t { + mp_obj_base_t base; + uint16_t flags; + mp_obj_t readblocks[4]; + mp_obj_t writeblocks[4]; + // new protocol uses just ioctl, old uses sync (optional) and count + union { + mp_obj_t ioctl[4]; + struct { + mp_obj_t sync[2]; + mp_obj_t count[2]; + } old; + } u; + FATFS fatfs; +} fs_user_mount_t; + +extern const byte fresult_to_errno_table[20]; +extern const mp_obj_type_t mp_fat_vfs_type; +extern const mp_obj_type_t mp_type_vfs_fat_fileio; +extern const mp_obj_type_t mp_type_vfs_fat_textio; + +MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H diff --git a/src/openmv/src/micropython/extmod/vfs_fat_diskio.c b/src/openmv/src/micropython/extmod/vfs_fat_diskio.c new file mode 100755 index 0000000..fa013d2 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_fat_diskio.c @@ -0,0 +1,228 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Original template for this file comes from: + * Low level disk I/O module skeleton for FatFs, (C)ChaN, 2013 + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_VFS && MICROPY_VFS_FAT + +#include +#include + +#include "py/mphal.h" + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/objarray.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/vfs_fat.h" + +#if _MAX_SS == _MIN_SS +#define SECSIZE(fs) (_MIN_SS) +#else +#define SECSIZE(fs) ((fs)->ssize) +#endif + +typedef void *bdev_t; +STATIC fs_user_mount_t *disk_get_device(void *bdev) { + return (fs_user_mount_t*)bdev; +} + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_read ( + bdev_t pdrv, /* Physical drive nmuber (0..) */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Sector address (LBA) */ + UINT count /* Number of sectors to read (1..128) */ +) +{ + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; + } + + if (vfs->flags & FSUSER_NATIVE) { + mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2]; + if (f(buff, sector, count) != 0) { + return RES_ERROR; + } + } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; + vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, vfs->readblocks); + // TODO handle error return + } + + return RES_OK; +} + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_write ( + bdev_t pdrv, /* Physical drive nmuber (0..) */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Sector address (LBA) */ + UINT count /* Number of sectors to write (1..128) */ +) +{ + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; + } + + if (vfs->writeblocks[0] == MP_OBJ_NULL) { + // read-only block device + return RES_WRPRT; + } + + if (vfs->flags & FSUSER_NATIVE) { + mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2]; + if (f(buff, sector, count) != 0) { + return RES_ERROR; + } + } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; + vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); + mp_call_method_n_kw(2, 0, vfs->writeblocks); + // TODO handle error return + } + + return RES_OK; +} + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_ioctl ( + bdev_t pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; + } + + // First part: call the relevant method of the underlying block device + mp_obj_t ret = mp_const_none; + if (vfs->flags & FSUSER_HAVE_IOCTL) { + // new protocol with ioctl + static const uint8_t op_map[8] = { + [CTRL_SYNC] = BP_IOCTL_SYNC, + [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT, + [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE, + [IOCTL_INIT] = BP_IOCTL_INIT, + }; + uint8_t bp_op = op_map[cmd & 7]; + if (bp_op != 0) { + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); + } + } else { + // old protocol with sync and count + switch (cmd) { + case CTRL_SYNC: + if (vfs->u.old.sync[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, vfs->u.old.sync); + } + break; + + case GET_SECTOR_COUNT: + ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); + break; + + case GET_SECTOR_SIZE: + // old protocol has fixed sector size of 512 bytes + break; + + case IOCTL_INIT: + // old protocol doesn't have init + break; + } + } + + // Second part: convert the result for return + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + + case GET_SECTOR_COUNT: { + *((DWORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_SECTOR_SIZE: { + if (ret == mp_const_none) { + // Default sector size + *((WORD*)buff) = 512; + } else { + *((WORD*)buff) = mp_obj_get_int(ret); + } + #if _MAX_SS != _MIN_SS + // need to store ssize because we use it in disk_read/disk_write + vfs->fatfs.ssize = *((WORD*)buff); + #endif + return RES_OK; + } + + case GET_BLOCK_SIZE: + *((DWORD*)buff) = 1; // erase block size in units of sector size + return RES_OK; + + case IOCTL_INIT: + case IOCTL_STATUS: { + DSTATUS stat; + if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { + // error initialising + stat = STA_NOINIT; + } else if (vfs->writeblocks[0] == MP_OBJ_NULL) { + stat = STA_PROTECT; + } else { + stat = 0; + } + *((DSTATUS*)buff) = stat; + return RES_OK; + } + + default: + return RES_PARERR; + } +} + +#endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/src/openmv/src/micropython/extmod/vfs_fat_file.c b/src/openmv/src/micropython/extmod/vfs_fat_file.c new file mode 100755 index 0000000..1ace141 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_fat_file.c @@ -0,0 +1,320 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_VFS && MICROPY_VFS_FAT + +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" + +// this table converts from FRESULT to POSIX errno +const byte fresult_to_errno_table[20] = { + [FR_OK] = 0, + [FR_DISK_ERR] = MP_EIO, + [FR_INT_ERR] = MP_EIO, + [FR_NOT_READY] = MP_EBUSY, + [FR_NO_FILE] = MP_ENOENT, + [FR_NO_PATH] = MP_ENOENT, + [FR_INVALID_NAME] = MP_EINVAL, + [FR_DENIED] = MP_EACCES, + [FR_EXIST] = MP_EEXIST, + [FR_INVALID_OBJECT] = MP_EINVAL, + [FR_WRITE_PROTECTED] = MP_EROFS, + [FR_INVALID_DRIVE] = MP_ENODEV, + [FR_NOT_ENABLED] = MP_ENODEV, + [FR_NO_FILESYSTEM] = MP_ENODEV, + [FR_MKFS_ABORTED] = MP_EIO, + [FR_TIMEOUT] = MP_EIO, + [FR_LOCKED] = MP_EIO, + [FR_NOT_ENOUGH_CORE] = MP_ENOMEM, + [FR_TOO_MANY_OPEN_FILES] = MP_EMFILE, + [FR_INVALID_PARAMETER] = MP_EINVAL, +}; +/*hutu*/ +const char *ffs_strerror(FRESULT res) +{ + static const char *ffs_errors[]={ + "Succeeded", + "A hard error occurred in the low level disk I/O layer", + "Assertion failed", + "The physical drive cannot work", + "Could not find the file", + "Could not find the path", + "The path name format is invalid", + "Access denied due to prohibited access or directory full", + "Access denied due to prohibited access", + "The file/directory object is invalid", + "The physical drive is write protected", + "The logical drive number is invalid", + "The volume has no work area", + "There is no valid FAT volume", + "The f_mkfs() aborted due to any parameter error", + "Could not get a grant to access the volume within defined period", + "The operation is rejected according to the file sharing policy", + "LFN working buffer could not be allocated", + "Number of open files > _FS_SHARE", + "Given parameter is invalid", + }; + + if (res>sizeof(ffs_errors)/sizeof(ffs_errors[0])) { + return "unknown error"; + } else { + return ffs_errors[res]; + } +} + +typedef struct _pyb_file_obj_t { + mp_obj_base_t base; + FIL fp; +} pyb_file_obj_t; + +STATIC void file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_printf(print, "", mp_obj_get_type_str(self_in), MP_OBJ_TO_PTR(self_in)); +} + +STATIC mp_uint_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); + UINT sz_out; + FRESULT res = f_read(&self->fp, buf, size, &sz_out); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + return sz_out; +} + +STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); + UINT sz_out; + FRESULT res = f_write(&self->fp, buf, size, &sz_out); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + if (sz_out != size) { + // The FatFS documentation says that this means disk full. + *errcode = MP_ENOSPC; + return MP_STREAM_ERROR; + } + return sz_out; +} + + +STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__); + +STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(o_in); + + if (request == MP_STREAM_SEEK) { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)(uintptr_t)arg; + + switch (s->whence) { + case 0: // SEEK_SET + f_lseek(&self->fp, s->offset); + break; + + case 1: // SEEK_CUR + f_lseek(&self->fp, f_tell(&self->fp) + s->offset); + break; + + case 2: // SEEK_END + f_lseek(&self->fp, f_size(&self->fp) + s->offset); + break; + } + + s->offset = f_tell(&self->fp); + return 0; + + } else if (request == MP_STREAM_FLUSH) { + FRESULT res = f_sync(&self->fp); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + return 0; + + } else if (request == MP_STREAM_CLOSE) { + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fp.obj.fs != NULL) { + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + } + return 0; + + } else { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, +// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor +STATIC const mp_arg_t file_open_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, + { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, +}; +#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) + +STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_arg_val_t *args) { + int mode = 0; + const char *mode_s = mp_obj_str_get_str(args[1].u_obj); + // TODO make sure only one of r, w, x, a, and b, t are specified + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode |= FA_READ; + break; + case 'w': + mode |= FA_WRITE | FA_CREATE_ALWAYS; + break; + case 'x': + mode |= FA_WRITE | FA_CREATE_NEW; + break; + case 'a': + mode |= FA_WRITE | FA_OPEN_ALWAYS; + break; + case '+': + mode |= FA_READ | FA_WRITE; + break; + #if MICROPY_PY_IO_FILEIO + case 'b': + type = &mp_type_vfs_fat_fileio; + break; + #endif + case 't': + type = &mp_type_vfs_fat_textio; + break; + } + } + + pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t); + o->base.type = type; + + const char *fname = mp_obj_str_get_str(args[0].u_obj); + assert(vfs != NULL); + FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); + if (res != FR_OK) { + m_del_obj(pyb_file_obj_t, o); + mp_raise_OSError(fresult_to_errno_table[res]); + } + + // for 'a' mode, we must begin at the end of the file + if ((mode & FA_OPEN_ALWAYS) != 0) { + f_lseek(&o->fp, f_size(&o->fp)); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); + return file_open(NULL, type, arg_vals); +} + +// TODO gc hook to close the file if not already closed + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { + .read = file_obj_read, + .write = file_obj_write, + .ioctl = file_obj_ioctl, +}; + +const mp_obj_type_t mp_type_vfs_fat_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = file_obj_print, + .make_new = file_obj_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = file_obj_read, + .write = file_obj_write, + .ioctl = file_obj_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_vfs_fat_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = file_obj_print, + .make_new = file_obj_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +// Factory function for I/O stream classes +STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { + // TODO: analyze buffering args and instantiate appropriate type + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; + arg_vals[0].u_obj = path; + arg_vals[1].u_obj = mode; + arg_vals[2].u_obj = mp_const_none; + return file_open(self, &mp_type_vfs_fat_textio, arg_vals); +} +MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); + +#endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/src/openmv/src/micropython/extmod/vfs_posix.c b/src/openmv/src/micropython/extmod/vfs_posix.c new file mode 100755 index 0000000..4ca7f9b --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_posix.c @@ -0,0 +1,371 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include +#include +#include + +typedef struct _mp_obj_vfs_posix_t { + mp_obj_base_t base; + vstr_t root; + size_t root_len; + bool readonly; +} mp_obj_vfs_posix_t; + +STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return mp_obj_str_get_str(path); + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return vstr_null_terminated_str(&self->root); + } +} + +STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return path; + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return mp_obj_new_str(self->root.buf, self->root.len); + } +} + +STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = f(vfs_posix_get_path_str(self, path_in)); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} + +STATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) { + mp_obj_vfs_posix_t *self = self_in; + if (self->root_len != 0) { + self->root.len = self->root_len; + vstr_add_str(&self->root, path); + path = vstr_null_terminated_str(&self->root); + } + struct stat st; + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return MP_IMPORT_STAT_DIR; + } else if (S_ISREG(st.st_mode)) { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t); + vfs->base.type = type; + vstr_init(&vfs->root, 0); + if (n_args == 1) { + vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0])); + vstr_add_char(&vfs->root, '/'); + } + vfs->root_len = vfs->root.len; + vfs->readonly = false; + + return MP_OBJ_FROM_PTR(vfs); +} + +STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_obj_is_true(readonly)) { + self->readonly = true; + } + if (mp_obj_is_true(mkfs)) { + mp_raise_OSError(MP_EPERM); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount); + +STATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) { + (void)self_in; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount); + +STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *mode = mp_obj_str_get_str(mode_in); + if (self->readonly + && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { + mp_raise_OSError(MP_EROFS); + } + if (!MP_OBJ_IS_SMALL_INT(path_in)) { + path_in = vfs_posix_get_path_obj(self, path_in); + } + return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open); + +STATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, chdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir); + +STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + const char *ret = getcwd(buf, sizeof(buf)); + if (ret == NULL) { + mp_raise_OSError(errno); + } + ret += self->root_len; + return mp_obj_new_str(ret, strlen(ret)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd); + +typedef struct _vfs_posix_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + DIR *dir; +} vfs_posix_ilistdir_it_t; + +STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) { + vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->dir == NULL) { + return MP_OBJ_STOP_ITERATION; + } + + for (;;) { + struct dirent *dirent = readdir(self->dir); + if (dirent == NULL) { + closedir(self->dir); + self->dir = NULL; + return MP_OBJ_STOP_ITERATION; + } + const char *fn = dirent->d_name; + + if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) { + // skip . and .. + continue; + } + + // make 3-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + + #ifdef _DIRENT_HAVE_D_TYPE + #ifdef DTTOIF + t->items[1] = MP_OBJ_NEW_SMALL_INT(DTTOIF(dirent->d_type)); + #else + if (dirent->d_type == DT_DIR) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else if (dirent->d_type == DT_REG) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } else { + t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); + } + #endif + #else + // DT_UNKNOWN should have 0 value on any reasonable system + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); + #endif + + #ifdef _DIRENT_HAVE_D_INO + t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino); + #else + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); + #endif + + return MP_OBJ_FROM_PTR(t); + } +} + +STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = vfs_posix_ilistdir_it_iternext; + iter->is_str = mp_obj_get_type(path_in) == &mp_type_str; + const char *path = vfs_posix_get_path_str(self, path_in); + if (path[0] == '\0') { + path = "."; + } + iter->dir = opendir(path); + if (iter->dir == NULL) { + mp_raise_OSError(errno); + } + return MP_OBJ_FROM_PTR(iter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir); + +typedef struct _mp_obj_listdir_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + DIR *dir; +} mp_obj_listdir_t; + +STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); + +STATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, unlink); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); + +STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *old_path = vfs_posix_get_path_str(self, old_path_in); + const char *new_path = vfs_posix_get_path_str(self, new_path_in); + int ret = rename(old_path, new_path); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename); + +STATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, rmdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir); + +STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + struct stat sb; + int ret = stat(vfs_posix_get_path_str(self, path_in), &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size); + t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); + t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); + t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat); + +#ifdef __ANDROID__ +#define USE_STATFS 1 +#endif + +#if USE_STATFS +#include +#define STRUCT_STATVFS struct statfs +#define STATVFS statfs +#define F_FAVAIL sb.f_ffree +#define F_NAMEMAX sb.f_namelen +#define F_FLAG sb.f_flags +#else +#include +#define STRUCT_STATVFS struct statvfs +#define STATVFS statvfs +#define F_FAVAIL sb.f_favail +#define F_NAMEMAX sb.f_namemax +#define F_FLAG sb.f_flag +#endif + +STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + STRUCT_STATVFS sb; + const char *path = vfs_posix_get_path_str(self, path_in); + int ret = STATVFS(path, &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree); + t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL); + t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG); + t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs); + +STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table); + +STATIC const mp_vfs_proto_t vfs_posix_proto = { + .import_stat = mp_vfs_posix_import_stat, +}; + +const mp_obj_type_t mp_type_vfs_posix = { + { &mp_type_type }, + .name = MP_QSTR_VfsPosix, + .make_new = vfs_posix_make_new, + .protocol = &vfs_posix_proto, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict, +}; + +#endif // MICROPY_VFS_POSIX diff --git a/src/openmv/src/micropython/extmod/vfs_posix.h b/src/openmv/src/micropython/extmod/vfs_posix.h new file mode 100755 index 0000000..00756b4 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_posix.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H +#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H + +#include "py/lexer.h" +#include "py/obj.h" + +extern const mp_obj_type_t mp_type_vfs_posix; +extern const mp_obj_type_t mp_type_vfs_posix_fileio; +extern const mp_obj_type_t mp_type_vfs_posix_textio; + +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H diff --git a/src/openmv/src/micropython/extmod/vfs_posix_file.c b/src/openmv/src/micropython/extmod/vfs_posix_file.c new file mode 100755 index 0000000..435ac65 --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_posix_file.c @@ -0,0 +1,261 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include + +#ifdef _WIN32 +#define fsync _commit +#endif + +typedef struct _mp_obj_vfs_posix_file_t { + mp_obj_base_t base; + int fd; +} mp_obj_vfs_posix_file_t; + +#ifdef MICROPY_CPYTHON_COMPAT +STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { + if (o->fd < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + } +} +#else +#define check_fd_is_open(o) +#endif + +STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", mp_obj_get_type_str(self_in), self->fd); +} + +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t); + const char *mode_s = mp_obj_str_get_str(mode_in); + + int mode_rw = 0, mode_x = 0; + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode_rw = O_RDONLY; + break; + case 'w': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_TRUNC; + break; + case 'a': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_APPEND; + break; + case '+': + mode_rw = O_RDWR; + break; + #if MICROPY_PY_IO_FILEIO + // If we don't have io.FileIO, then files are in text mode implicitly + case 'b': + type = &mp_type_vfs_posix_fileio; + break; + case 't': + type = &mp_type_vfs_posix_textio; + break; + #endif + } + } + + o->base.type = type; + + mp_obj_t fid = file_in; + + if (MP_OBJ_IS_SMALL_INT(fid)) { + o->fd = MP_OBJ_SMALL_INT_VALUE(fid); + return MP_OBJ_FROM_PTR(o); + } + + const char *fname = mp_obj_str_get_str(fid); + int fd = open(fname, mode_x | mode_rw, 0644); + if (fd == -1) { + mp_raise_OSError(errno); + } + o->fd = fd; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + }; + + mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj); +} + +STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) { + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + check_fd_is_open(self); + return MP_OBJ_NEW_SMALL_INT(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno); + +STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__); + +STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + mp_int_t r = read(o->fd, buf, size); + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + #if MICROPY_PY_OS_DUPTERM + if (o->fd <= STDERR_FILENO) { + mp_hal_stdout_tx_strn(buf, size); + return size; + } + #endif + mp_int_t r = write(o->fd, buf, size); + while (r == -1 && errno == EINTR) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + r = write(o->fd, buf, size); + } + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + switch (request) { + case MP_STREAM_FLUSH: + if (fsync(o->fd) < 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return 0; + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + off_t off = lseek(o->fd, s->offset, s->whence); + if (off == (off_t)-1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + s->offset = off; + return 0; + } + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; + default: + *errcode = EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, +}; + +const mp_obj_type_t mp_type_vfs_posix_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_vfs_posix_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO}; + +#endif // MICROPY_VFS_POSIX diff --git a/src/openmv/src/micropython/extmod/vfs_reader.c b/src/openmv/src/micropython/extmod/vfs_reader.c new file mode 100755 index 0000000..e1ee45a --- /dev/null +++ b/src/openmv/src/micropython/extmod/vfs_reader.c @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/reader.h" +#include "extmod/vfs.h" + +#if MICROPY_READER_VFS + +typedef struct _mp_reader_vfs_t { + mp_obj_t file; + uint16_t len; + uint16_t pos; + byte buf[24]; +} mp_reader_vfs_t; + +STATIC mp_uint_t mp_reader_vfs_readbyte(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; + if (reader->pos >= reader->len) { + if (reader->len < sizeof(reader->buf)) { + return MP_READER_EOF; + } else { + int errcode; + reader->len = mp_stream_rw(reader->file, reader->buf, sizeof(reader->buf), + &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + // TODO handle errors properly + return MP_READER_EOF; + } + if (reader->len == 0) { + return MP_READER_EOF; + } + reader->pos = 0; + } + } + return reader->buf[reader->pos++]; +} + +STATIC void mp_reader_vfs_close(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; + mp_stream_close(reader->file); + m_del_obj(mp_reader_vfs_t, reader); +} + +void mp_reader_new_file(mp_reader_t *reader, const char *filename) { + mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); + rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); + int errcode; + rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_OSError(errcode); + } + rf->pos = 0; + reader->data = rf; + reader->readbyte = mp_reader_vfs_readbyte; + reader->close = mp_reader_vfs_close; +} + +#endif // MICROPY_READER_VFS diff --git a/src/openmv/src/micropython/extmod/virtpin.c b/src/openmv/src/micropython/extmod/virtpin.c new file mode 100755 index 0000000..dbfa21d --- /dev/null +++ b/src/openmv/src/micropython/extmod/virtpin.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "extmod/virtpin.h" + +int mp_virtual_pin_read(mp_obj_t pin) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol; + return pin_p->ioctl(pin, MP_PIN_READ, 0, NULL); +} + +void mp_virtual_pin_write(mp_obj_t pin, int value) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->protocol; + pin_p->ioctl(pin, MP_PIN_WRITE, value, NULL); +} diff --git a/src/openmv/src/micropython/extmod/virtpin.h b/src/openmv/src/micropython/extmod/virtpin.h new file mode 100755 index 0000000..706affc --- /dev/null +++ b/src/openmv/src/micropython/extmod/virtpin.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VIRTPIN_H +#define MICROPY_INCLUDED_EXTMOD_VIRTPIN_H + +#include "py/obj.h" + +#define MP_PIN_READ (1) +#define MP_PIN_WRITE (2) +#define MP_PIN_INPUT (3) +#define MP_PIN_OUTPUT (4) + +// Pin protocol +typedef struct _mp_pin_p_t { + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); +} mp_pin_p_t; + +int mp_virtual_pin_read(mp_obj_t pin); +void mp_virtual_pin_write(mp_obj_t pin, int value); + +// If a port exposes a Pin object, it's constructor should be like this +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); + +#endif // MICROPY_INCLUDED_EXTMOD_VIRTPIN_H diff --git a/src/openmv/src/micropython/lib/README.md b/src/openmv/src/micropython/lib/README.md new file mode 100755 index 0000000..e719821 --- /dev/null +++ b/src/openmv/src/micropython/lib/README.md @@ -0,0 +1,2 @@ +This directory contains standard, low-level C libraries with emphasis on +being independent and efficient. They can be used by any port. diff --git a/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc.h b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc.h new file mode 100755 index 0000000..74c49c6 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc.h @@ -0,0 +1,734 @@ +/**************************************************************************//** + * @file cmsis_armcc.h + * @brief CMSIS Cortex-M Core Function/Instruction Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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 __CMSIS_ARMCC_H +#define __CMSIS_ARMCC_H + + +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 400677) + #error "Please use ARM Compiler Toolchain V4.0.677 or later!" +#endif + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/* intrinsic void __enable_irq(); */ +/* intrinsic void __disable_irq(); */ + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__STATIC_INLINE uint32_t __get_CONTROL(void) +{ + register uint32_t __regControl __ASM("control"); + return(__regControl); +} + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + register uint32_t __regControl __ASM("control"); + __regControl = control; +} + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__STATIC_INLINE uint32_t __get_IPSR(void) +{ + register uint32_t __regIPSR __ASM("ipsr"); + return(__regIPSR); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__STATIC_INLINE uint32_t __get_APSR(void) +{ + register uint32_t __regAPSR __ASM("apsr"); + return(__regAPSR); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__STATIC_INLINE uint32_t __get_xPSR(void) +{ + register uint32_t __regXPSR __ASM("xpsr"); + return(__regXPSR); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__STATIC_INLINE uint32_t __get_PSP(void) +{ + register uint32_t __regProcessStackPointer __ASM("psp"); + return(__regProcessStackPointer); +} + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + register uint32_t __regProcessStackPointer __ASM("psp"); + __regProcessStackPointer = topOfProcStack; +} + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__STATIC_INLINE uint32_t __get_MSP(void) +{ + register uint32_t __regMainStackPointer __ASM("msp"); + return(__regMainStackPointer); +} + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + register uint32_t __regMainStackPointer __ASM("msp"); + __regMainStackPointer = topOfMainStack; +} + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + register uint32_t __regPriMask __ASM("primask"); + return(__regPriMask); +} + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + register uint32_t __regPriMask __ASM("primask"); + __regPriMask = (priMask); +} + + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +#define __enable_fault_irq __enable_fiq + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +#define __disable_fault_irq __disable_fiq + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__STATIC_INLINE uint32_t __get_BASEPRI(void) +{ + register uint32_t __regBasePri __ASM("basepri"); + return(__regBasePri); +} + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__STATIC_INLINE void __set_BASEPRI(uint32_t basePri) +{ + register uint32_t __regBasePri __ASM("basepri"); + __regBasePri = (basePri & 0xFFU); +} + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__STATIC_INLINE void __set_BASEPRI_MAX(uint32_t basePri) +{ + register uint32_t __regBasePriMax __ASM("basepri_max"); + __regBasePriMax = (basePri & 0xFFU); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__STATIC_INLINE uint32_t __get_FAULTMASK(void) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + return(__regFaultMask); +} + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + __regFaultMask = (faultMask & (uint32_t)1); +} + +#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ + + +#if (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__STATIC_INLINE uint32_t __get_FPSCR(void) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + register uint32_t __regfpscr __ASM("fpscr"); + return(__regfpscr); +#else + return(0U); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + register uint32_t __regfpscr __ASM("fpscr"); + __regfpscr = (fpscr); +#endif +} + +#endif /* (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) */ + + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __nop + + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() do {\ + __schedule_barrier();\ + __isb(0xF);\ + __schedule_barrier();\ + } while (0U) + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() do {\ + __schedule_barrier();\ + __dsb(0xF);\ + __schedule_barrier();\ + } while (0U) + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() do {\ + __schedule_barrier();\ + __dmb(0xF);\ + __schedule_barrier();\ + } while (0U) + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in integer value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV __rev + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in two unsigned short values. + \param [in] value Value to reverse + \return Reversed value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value) +{ + rev16 r0, r0 + bx lr +} +#endif + +/** + \brief Reverse byte order in signed short value + \details Reverses the byte order in a signed short value with sign extension to integer. + \param [in] value Value to reverse + \return Reversed value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value) +{ + revsh r0, r0 + bx lr +} +#endif + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] value Value to rotate + \param [in] value Number of Bits to rotate + \return Rotated value + */ +#define __ROR __ror + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __breakpoint(value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + #define __RBIT __rbit +#else +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ + return(result); +} +#endif + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ __clz + + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr)) +#else + #define __LDREXB(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint8_t ) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXH(ptr) ((uint16_t) __ldrex(ptr)) +#else + #define __LDREXH(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint16_t) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr)) +#else + #define __LDREXW(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((uint32_t ) __ldrex(ptr)) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXB(value, ptr) __strex(value, ptr) +#else + #define __STREXB(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXH(value, ptr) __strex(value, ptr) +#else + #define __STREXH(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 5060020) + #define __STREXW(value, ptr) __strex(value, ptr) +#else + #define __STREXW(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop") +#endif + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __clrex + + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT __ssat + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __usat + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +#ifndef __NO_EMBEDDED_ASM +__attribute__((section(".rrx_text"))) __STATIC_INLINE __ASM uint32_t __RRX(uint32_t value) +{ + rrx r0, r0 + bx lr +} +#endif + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDRBT(ptr) ((uint8_t ) __ldrt(ptr)) + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDRHT(ptr) ((uint16_t) __ldrt(ptr)) + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDRT(ptr) ((uint32_t ) __ldrt(ptr)) + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRBT(value, ptr) __strt(value, ptr) + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRHT(value, ptr) __strt(value, ptr) + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +#define __STRT(value, ptr) __strt(value, ptr) + +#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (__CORTEX_M >= 0x04U) /* only for Cortex-M4 and above */ + +#define __SADD8 __sadd8 +#define __QADD8 __qadd8 +#define __SHADD8 __shadd8 +#define __UADD8 __uadd8 +#define __UQADD8 __uqadd8 +#define __UHADD8 __uhadd8 +#define __SSUB8 __ssub8 +#define __QSUB8 __qsub8 +#define __SHSUB8 __shsub8 +#define __USUB8 __usub8 +#define __UQSUB8 __uqsub8 +#define __UHSUB8 __uhsub8 +#define __SADD16 __sadd16 +#define __QADD16 __qadd16 +#define __SHADD16 __shadd16 +#define __UADD16 __uadd16 +#define __UQADD16 __uqadd16 +#define __UHADD16 __uhadd16 +#define __SSUB16 __ssub16 +#define __QSUB16 __qsub16 +#define __SHSUB16 __shsub16 +#define __USUB16 __usub16 +#define __UQSUB16 __uqsub16 +#define __UHSUB16 __uhsub16 +#define __SASX __sasx +#define __QASX __qasx +#define __SHASX __shasx +#define __UASX __uasx +#define __UQASX __uqasx +#define __UHASX __uhasx +#define __SSAX __ssax +#define __QSAX __qsax +#define __SHSAX __shsax +#define __USAX __usax +#define __UQSAX __uqsax +#define __UHSAX __uhsax +#define __USAD8 __usad8 +#define __USADA8 __usada8 +#define __SSAT16 __ssat16 +#define __USAT16 __usat16 +#define __UXTB16 __uxtb16 +#define __UXTAB16 __uxtab16 +#define __SXTB16 __sxtb16 +#define __SXTAB16 __sxtab16 +#define __SMUAD __smuad +#define __SMUADX __smuadx +#define __SMLAD __smlad +#define __SMLADX __smladx +#define __SMLALD __smlald +#define __SMLALDX __smlaldx +#define __SMUSD __smusd +#define __SMUSDX __smusdx +#define __SMLSD __smlsd +#define __SMLSDX __smlsdx +#define __SMLSLD __smlsld +#define __SMLSLDX __smlsldx +#define __SEL __sel +#define __QADD __qadd +#define __QSUB __qsub + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ + ((int64_t)(ARG3) << 32U) ) >> 32U)) + +#endif /* (__CORTEX_M >= 0x04) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCC_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc_V6.h b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc_V6.h new file mode 100755 index 0000000..cd13240 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_armcc_V6.h @@ -0,0 +1,1800 @@ +/**************************************************************************//** + * @file cmsis_armcc_V6.h + * @brief CMSIS Cortex-M Core Function/Instruction Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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 __CMSIS_ARMCC_V6_H +#define __CMSIS_ARMCC_V6_H + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Control Register (non-secure) + \details Returns the content of the non-secure Control Register when in secure mode. + \return non-secure Control Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_CONTROL_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Control Register (non-secure) + \details Writes the given value to the non-secure Control Register when in secure state. + \param [in] control Control Register value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_CONTROL_NS(uint32_t control) +{ + __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); +} +#endif + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get IPSR Register (non-secure) + \details Returns the content of the non-secure IPSR Register when in secure state. + \return IPSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_IPSR_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get APSR Register (non-secure) + \details Returns the content of the non-secure APSR Register when in secure state. + \return APSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_APSR_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + \return xPSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get xPSR Register (non-secure) + \details Returns the content of the non-secure xPSR Register when in secure state. + \return xPSR Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_xPSR_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psp" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Process Stack Pointer (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. + \return PSP Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PSP_NS(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : "sp"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : "sp"); +} +#endif + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_MSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msp" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Main Stack Pointer (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. + \return MSP Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_MSP_NS(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : "sp"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Main Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : "sp"); +} +#endif + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Priority Mask (non-secure) + \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. + \return Priority Mask value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PRIMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Priority Mask (non-secure) + \details Assigns the given value to the non-secure Priority Mask Register when in secure state. + \param [in] priMask Priority Mask + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) +{ + __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); +} +#endif + + +#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ + +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Base Priority (non-secure) + \details Returns the current value of the non-secure Base Priority register when in secure state. + \return Base Priority register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_BASEPRI_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_BASEPRI(uint32_t value) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Base Priority (non-secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state. + \param [in] basePri Base Priority value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_BASEPRI_NS(uint32_t value) +{ + __ASM volatile ("MSR basepri_ns, %0" : : "r" (value) : "memory"); +} +#endif + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Base Priority with condition (non_secure) + \details Assigns the given value to the non-secure Base Priority register when in secure state only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_BASEPRI_MAX_NS(uint32_t value) +{ + __ASM volatile ("MSR basepri_max_ns, %0" : : "r" (value) : "memory"); +} +#endif + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get Fault Mask (non-secure) + \details Returns the current value of the non-secure Fault Mask register when in secure state. + \return Fault Mask register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_FAULTMASK_NS(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set Fault Mask (non-secure) + \details Assigns the given value to the non-secure Fault Mask register when in secure state. + \param [in] faultMask Fault Mask value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); +} +#endif + + +#endif /* ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ + + +#if (__ARM_ARCH_8M__ == 1U) + +/** + \brief Get Process Stack Pointer Limit + \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). + \return PSPLIM Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_PSPLIM(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psplim" : "=r" (result) ); + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +/** + \brief Get Process Stack Pointer Limit (non-secure) + \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \return PSPLIM Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_PSPLIM_NS(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Process Stack Pointer Limit + \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) +{ + __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); +} + + +#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +/** + \brief Set Process Stack Pointer (non-secure) + \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. + \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) +{ + __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); +} +#endif + + +/** + \brief Get Main Stack Pointer Limit + \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). + \return MSPLIM Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_MSPLIM(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msplim" : "=r" (result) ); + + return(result); +} + + +#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +/** + \brief Get Main Stack Pointer Limit (non-secure) + \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. + \return MSPLIM Register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_MSPLIM_NS(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); + return(result); +} +#endif + + +/** + \brief Set Main Stack Pointer Limit + \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). + \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) +{ + __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); +} + + +#if (__ARM_FEATURE_CMSE == 3U) && (__ARM_ARCH_PROFILE == 'M') /* ToDo: ARMCC_V6: check predefined macro for mainline */ +/** + \brief Set Main Stack Pointer Limit (non-secure) + \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. + \param [in] MainStackPtrLimit Main Stack Pointer value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) +{ + __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); +} +#endif + +#endif /* (__ARM_ARCH_8M__ == 1U) */ + + +#if ((__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=4 */ + +/** + \brief Get FPSCR + \details eturns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +#define __get_FPSCR __builtin_arm_get_fpscr +#if 0 +__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FPSCR(void) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + uint32_t result; + + __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ + __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + __ASM volatile (""); + return(result); +#else + return(0); +#endif +} +#endif + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Get FPSCR (non-secure) + \details Returns the current value of the non-secure Floating Point Status/Control register when in secure state. + \return Floating Point Status/Control register value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __TZ_get_FPSCR_NS(void) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + uint32_t result; + + __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ + __ASM volatile ("VMRS %0, fpscr_ns" : "=r" (result) ); + __ASM volatile (""); + return(result); +#else + return(0); +#endif +} +#endif + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +#define __set_FPSCR __builtin_arm_set_fpscr +#if 0 +__attribute__((always_inline)) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); + __ASM volatile (""); +#endif +} +#endif + +#if (__ARM_FEATURE_CMSE == 3U) +/** + \brief Set FPSCR (non-secure) + \details Assigns the given value to the non-secure Floating Point Status/Control register when in secure state. + \param [in] fpscr Floating Point Status/Control value to set + */ +__attribute__((always_inline)) __STATIC_INLINE void __TZ_set_FPSCR_NS(uint32_t fpscr) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + __ASM volatile (""); /* Empty asm statement works as a scheduling barrier */ + __ASM volatile ("VMSR fpscr_ns, %0" : : "r" (fpscr) : "vfpcc"); + __ASM volatile (""); +#endif +} +#endif + +#endif /* ((__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ + + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +#define __NOP __builtin_arm_nop + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +#define __WFI __builtin_arm_wfi + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +#define __WFE __builtin_arm_wfe + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +#define __SEV __builtin_arm_sev + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +#define __ISB() __builtin_arm_isb(0xF); + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +#define __DSB() __builtin_arm_dsb(0xF); + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +#define __DMB() __builtin_arm_dmb(0xF); + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in integer value. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV __builtin_bswap32 + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in two unsigned short values. + \param [in] value Value to reverse + \return Reversed value + */ +#define __REV16 __builtin_bswap16 /* ToDo: ARMCC_V6: check if __builtin_bswap16 could be used */ +#if 0 +__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} +#endif + + +/** + \brief Reverse byte order in signed short value + \details Reverses the byte order in a signed short value with sign extension to integer. + \param [in] value Value to reverse + \return Reversed value + */ + /* ToDo: ARMCC_V6: check if __builtin_bswap16 could be used */ +__attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) +{ + int32_t result; + + __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] op1 Value to rotate + \param [in] op2 Number of Bits to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ + /* ToDo: ARMCC_V6: check if __builtin_arm_rbit is supported */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + +#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +#else + int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ +#endif + return(result); +} + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ __builtin_clz + + +#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) /* ToDo: ARMCC_V6: check if this is ok for cortex >=3 */ + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDREXB (uint8_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDREXH (uint16_t)__builtin_arm_ldrex + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDREXW (uint32_t)__builtin_arm_ldrex + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXB (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXH (uint32_t)__builtin_arm_strex + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STREXW (uint32_t)__builtin_arm_strex + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +#define __CLREX __builtin_arm_clrex + + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +/*#define __SSAT __builtin_arm_ssat*/ +#define __SSAT(ARG1,ARG2) \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT __builtin_arm_usat +#if 0 +#define __USAT(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) +#endif + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); +} + +#endif /* ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_8M__ == 1U)) */ + + +#if (__ARM_ARCH_8M__ == 1U) + +/** + \brief Load-Acquire (8 bit) + \details Executes a LDAB instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDAB(volatile uint8_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint8_t) result); +} + + +/** + \brief Load-Acquire (16 bit) + \details Executes a LDAH instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDAH(volatile uint16_t *ptr) +{ + uint32_t result; + + __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); + return ((uint16_t) result); +} + + +/** + \brief Load-Acquire (32 bit) + \details Executes a LDA instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDA(volatile uint32_t *ptr) +{ + uint32_t result; + + __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); + return(result); +} + + +/** + \brief Store-Release (8 bit) + \details Executes a STLB instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STLB(uint8_t value, volatile uint8_t *ptr) +{ + __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (16 bit) + \details Executes a STLH instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STLH(uint16_t value, volatile uint16_t *ptr) +{ + __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Store-Release (32 bit) + \details Executes a STL instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STL(uint32_t value, volatile uint32_t *ptr) +{ + __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); +} + + +/** + \brief Load-Acquire Exclusive (8 bit) + \details Executes a LDAB exclusive instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +#define __LDAEXB (uint8_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (16 bit) + \details Executes a LDAH exclusive instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +#define __LDAEXH (uint16_t)__builtin_arm_ldaex + + +/** + \brief Load-Acquire Exclusive (32 bit) + \details Executes a LDA exclusive instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +#define __LDAEX (uint32_t)__builtin_arm_ldaex + + +/** + \brief Store-Release Exclusive (8 bit) + \details Executes a STLB exclusive instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXB (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (16 bit) + \details Executes a STLH exclusive instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEXH (uint32_t)__builtin_arm_stlex + + +/** + \brief Store-Release Exclusive (32 bit) + \details Executes a STL exclusive instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +#define __STLEX (uint32_t)__builtin_arm_stlex + +#endif /* (__ARM_ARCH_8M__ == 1U) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (__ARM_FEATURE_DSP == 1U) /* ToDo: ARMCC_V6: This should be ARCH >= ARMv7-M + SIMD */ + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +#define __USAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__((always_inline)) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__((always_inline)) __STATIC_INLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +#define __PKHBT(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +#define __PKHTB(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + if (ARG3 == 0) \ + __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ + else \ + __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +__attribute__((always_inline)) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__ARM_FEATURE_DSP == 1U) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#endif /* __CMSIS_ARMCC_V6_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/cmsis_gcc.h b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_gcc.h new file mode 100755 index 0000000..bb89fbb --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/cmsis_gcc.h @@ -0,0 +1,1373 @@ +/**************************************************************************//** + * @file cmsis_gcc.h + * @brief CMSIS Cortex-M Core Function/Instruction Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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 __CMSIS_GCC_H +#define __CMSIS_GCC_H + +/* ignore some GCC warnings */ +#if defined ( __GNUC__ ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); +} + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + + \return xPSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psp\n" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp"); +} + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msp\n" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); +} + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (__CORTEX_M >= 0x03U) + +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); +} + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + +#endif /* (__CORTEX_M >= 0x03U) */ + + +#if (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + uint32_t result; + + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); + __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + __ASM volatile (""); + return(result); +#else + return(0); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); + __ASM volatile (""); +#endif +} + +#endif /* (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) */ + + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __NOP(void) +{ + __ASM volatile ("nop"); +} + + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +__attribute__((always_inline)) __STATIC_INLINE void __WFI(void) +{ + __ASM volatile ("wfi"); +} + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +__attribute__((always_inline)) __STATIC_INLINE void __WFE(void) +{ + __ASM volatile ("wfe"); +} + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +__attribute__((always_inline)) __STATIC_INLINE void __SEV(void) +{ + __ASM volatile ("sev"); +} + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +__attribute__((always_inline)) __STATIC_INLINE void __ISB(void) +{ + __ASM volatile ("isb 0xF":::"memory"); +} + + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__attribute__((always_inline)) __STATIC_INLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); +} + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +__attribute__((always_inline)) __STATIC_INLINE void __DMB(void) +{ + __ASM volatile ("dmb 0xF":::"memory"); +} + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in integer value. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); +#else + uint32_t result; + + __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +#endif +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in two unsigned short values. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief Reverse byte order in signed short value + \details Reverses the byte order in a signed short value with sign extension to integer. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + return (short)__builtin_bswap16(value); +#else + int32_t result; + + __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +#endif +} + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] value Value to rotate + \param [in] value Number of Bits to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +#else + int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ +#endif + return(result); +} + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ __builtin_clz + + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDREXW(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); + return(result); +} + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +__attribute__((always_inline)) __STATIC_INLINE void __CLREX(void) +{ + __ASM volatile ("clrex" ::: "memory"); +} + + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volatile uint8_t *addr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, volatile uint16_t *addr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volatile uint32_t *addr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*addr) : "r" (value) ); +} + +#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (__CORTEX_M >= 0x04U) /* only for Cortex-M4 and above */ + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1,ARG2) \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +#define __USAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +#define __PKHBT(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +#define __PKHTB(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + if (ARG3 == 0) \ + __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ + else \ + __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__CORTEX_M >= 0x04) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#if defined ( __GNUC__ ) +#pragma GCC diagnostic pop +#endif + +#endif /* __CMSIS_GCC_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cm0.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cm0.h new file mode 100755 index 0000000..711dad5 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cm0.h @@ -0,0 +1,798 @@ +/**************************************************************************//** + * @file core_cm0.h + * @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM0_H_GENERIC +#define __CORE_CM0_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M0 + @{ + */ + +/* CMSIS CM0 definitions */ +#define __CM0_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM0_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0_CMSIS_VERSION ((__CM0_CMSIS_VERSION_MAIN << 16U) | \ + __CM0_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x00U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM0_H_DEPENDANT +#define __CORE_CM0_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM0_REV + #define __CM0_REV 0x0000U + #warning "__CM0_REV not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M0 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t _reserved0:1; /*!< bit: 0 Reserved */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + uint32_t RESERVED0; + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M0 Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M0 header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M0 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/* Interrupt Priorities are WORD accessible only under ARMv6M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cm0plus.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cm0plus.h new file mode 100755 index 0000000..b04aa39 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cm0plus.h @@ -0,0 +1,914 @@ +/**************************************************************************//** + * @file core_cm0plus.h + * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM0PLUS_H_GENERIC +#define __CORE_CM0PLUS_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex-M0+ + @{ + */ + +/* CMSIS CM0+ definitions */ +#define __CM0PLUS_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM0PLUS_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \ + __CM0PLUS_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x00U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM0PLUS_H_DEPENDANT +#define __CORE_CM0PLUS_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM0PLUS_REV + #define __CM0PLUS_REV 0x0000U + #warning "__CM0PLUS_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 0U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex-M0+ */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ +#if (__VTOR_PRESENT == 1U) + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ +#else + uint32_t RESERVED0; +#endif + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +#if (__VTOR_PRESENT == 1U) +/* SCB Interrupt Control State Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M0+ header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M0+ Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/* Interrupt Priorities are WORD accessible only under ARMv6M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cm3.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cm3.h new file mode 100755 index 0000000..b4ac4c7 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cm3.h @@ -0,0 +1,1763 @@ +/**************************************************************************//** + * @file core_cm3.h + * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM3_H_GENERIC +#define __CORE_CM3_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M3 + @{ + */ + +/* CMSIS CM3 definitions */ +#define __CM3_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM3_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16U) | \ + __CM3_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x03U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM3_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM3_H_DEPENDANT +#define __CORE_CM3_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM3_REV + #define __CM3_REV 0x0200U + #warning "__CM3_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 4U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M3 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24U]; + __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[5U]; + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#if (__CM3_REV < 0x0201U) /* core r2p1 */ +#define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ +#define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ + +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#else +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ +#if ((defined __CM3_REV) && (__CM3_REV >= 0x200U)) + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +#else + uint32_t RESERVED1[1U]; +#endif +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/* Auxiliary Control Register Definitions */ + +#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ +#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ + +#define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ +#define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ + +#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ +#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29U]; + __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ + __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ + __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[6U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Mask Register Definitions */ +#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ +#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ +#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ + +#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ +#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ +#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ + +#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ +#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ + +#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ +#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ + +#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ +#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ + +#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ +#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ +#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ +#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M3 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ +#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ +#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ +#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in NVIC and returns the active bit. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + */ +__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM3_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cm4.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cm4.h new file mode 100755 index 0000000..dc840eb --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cm4.h @@ -0,0 +1,1937 @@ +/**************************************************************************//** + * @file core_cm4.h + * @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM4_H_GENERIC +#define __CORE_CM4_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M4 + @{ + */ + +/* CMSIS CM4 definitions */ +#define __CM4_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM4_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM4_CMSIS_VERSION ((__CM4_CMSIS_VERSION_MAIN << 16U) | \ + __CM4_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x04U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #if (__FPU_PRESENT == 1) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ +#include "core_cmSimd.h" /* Compiler specific SIMD Intrinsics */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM4_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM4_H_DEPENDANT +#define __CORE_CM4_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM4_REV + #define __CM4_REV 0x0000U + #warning "__CM4_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 4U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M4 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */ + uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24U]; + __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[5U]; + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ +#define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ + +#define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ +#define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ + +#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ +#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ + +#define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ +#define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ + +#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ +#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29U]; + __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ + __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ + __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[6U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Mask Register Definitions */ +#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ +#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ +#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ + +#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ +#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ +#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ + +#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ +#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ + +#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ +#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ + +#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ +#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ + +#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ +#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ +#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ +#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if (__FPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/*@} end of group CMSIS_FPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M4 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ +#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ +#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ +#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +#if (__FPU_PRESENT == 1U) + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in NVIC and returns the active bit. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + */ +__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM4_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cm7.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cm7.h new file mode 100755 index 0000000..3b7530a --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cm7.h @@ -0,0 +1,2512 @@ +/**************************************************************************//** + * @file core_cm7.h + * @brief CMSIS Cortex-M7 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM7_H_GENERIC +#define __CORE_CM7_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M7 + @{ + */ + +/* CMSIS CM7 definitions */ +#define __CM7_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM7_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM7_CMSIS_VERSION ((__CM7_CMSIS_VERSION_MAIN << 16U) | \ + __CM7_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x07U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. +*/ +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #if (__FPU_PRESENT == 1) + #define __FPU_USED 1U + #else + #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #if (__FPU_PRESENT == 1U) + #define __FPU_USED 1U + #else + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #define __FPU_USED 0U + #endif + #else + #define __FPU_USED 0U + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ +#include "core_cmSimd.h" /* Compiler specific SIMD Intrinsics */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM7_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM7_H_DEPENDANT +#define __CORE_CM7_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM7_REV + #define __CM7_REV 0x0000U + #warning "__CM7_REV not defined in device header file; using default!" + #endif + + #ifndef __FPU_PRESENT + #define __FPU_PRESENT 0U + #warning "__FPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __ICACHE_PRESENT + #define __ICACHE_PRESENT 0U + #warning "__ICACHE_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DCACHE_PRESENT + #define __DCACHE_PRESENT 0U + #warning "__DCACHE_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __DTCM_PRESENT + #define __DTCM_PRESENT 0U + #warning "__DTCM_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 3U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M7 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + - Core FPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + +#define APSR_GE_Pos 16U /*!< APSR: GE Position */ +#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ +#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */ + uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ +#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ + +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24U]; + __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHPR[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t ID_PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t ID_DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ID_AFR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t ID_MFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ID_ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[1U]; + __IM uint32_t CLIDR; /*!< Offset: 0x078 (R/ ) Cache Level ID register */ + __IM uint32_t CTR; /*!< Offset: 0x07C (R/ ) Cache Type register */ + __IM uint32_t CCSIDR; /*!< Offset: 0x080 (R/ ) Cache Size ID Register */ + __IOM uint32_t CSSELR; /*!< Offset: 0x084 (R/W) Cache Size Selection Register */ + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + uint32_t RESERVED3[93U]; + __OM uint32_t STIR; /*!< Offset: 0x200 ( /W) Software Triggered Interrupt Register */ + uint32_t RESERVED4[15U]; + __IM uint32_t MVFR0; /*!< Offset: 0x240 (R/ ) Media and VFP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x244 (R/ ) Media and VFP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x248 (R/ ) Media and VFP Feature Register 1 */ + uint32_t RESERVED5[1U]; + __OM uint32_t ICIALLU; /*!< Offset: 0x250 ( /W) I-Cache Invalidate All to PoU */ + uint32_t RESERVED6[1U]; + __OM uint32_t ICIMVAU; /*!< Offset: 0x258 ( /W) I-Cache Invalidate by MVA to PoU */ + __OM uint32_t DCIMVAC; /*!< Offset: 0x25C ( /W) D-Cache Invalidate by MVA to PoC */ + __OM uint32_t DCISW; /*!< Offset: 0x260 ( /W) D-Cache Invalidate by Set-way */ + __OM uint32_t DCCMVAU; /*!< Offset: 0x264 ( /W) D-Cache Clean by MVA to PoU */ + __OM uint32_t DCCMVAC; /*!< Offset: 0x268 ( /W) D-Cache Clean by MVA to PoC */ + __OM uint32_t DCCSW; /*!< Offset: 0x26C ( /W) D-Cache Clean by Set-way */ + __OM uint32_t DCCIMVAC; /*!< Offset: 0x270 ( /W) D-Cache Clean and Invalidate by MVA to PoC */ + __OM uint32_t DCCISW; /*!< Offset: 0x274 ( /W) D-Cache Clean and Invalidate by Set-way */ + uint32_t RESERVED7[6U]; + __IOM uint32_t ITCMCR; /*!< Offset: 0x290 (R/W) Instruction Tightly-Coupled Memory Control Register */ + __IOM uint32_t DTCMCR; /*!< Offset: 0x294 (R/W) Data Tightly-Coupled Memory Control Registers */ + __IOM uint32_t AHBPCR; /*!< Offset: 0x298 (R/W) AHBP Control Register */ + __IOM uint32_t CACR; /*!< Offset: 0x29C (R/W) L1 Cache Control Register */ + __IOM uint32_t AHBSCR; /*!< Offset: 0x2A0 (R/W) AHB Slave Control Register */ + uint32_t RESERVED8[1U]; + __IOM uint32_t ABFSR; /*!< Offset: 0x2A8 (R/W) Auxiliary Bus Fault Status Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_BP_Pos 18U /*!< SCB CCR: Branch prediction enable bit Position */ +#define SCB_CCR_BP_Msk (1UL << SCB_CCR_BP_Pos) /*!< SCB CCR: Branch prediction enable bit Mask */ + +#define SCB_CCR_IC_Pos 17U /*!< SCB CCR: Instruction cache enable bit Position */ +#define SCB_CCR_IC_Msk (1UL << SCB_CCR_IC_Pos) /*!< SCB CCR: Instruction cache enable bit Mask */ + +#define SCB_CCR_DC_Pos 16U /*!< SCB CCR: Cache enable bit Position */ +#define SCB_CCR_DC_Msk (1UL << SCB_CCR_DC_Pos) /*!< SCB CCR: Cache enable bit Mask */ + +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/* SCB Cache Level ID Register Definitions */ +#define SCB_CLIDR_LOUU_Pos 27U /*!< SCB CLIDR: LoUU Position */ +#define SCB_CLIDR_LOUU_Msk (7UL << SCB_CLIDR_LOUU_Pos) /*!< SCB CLIDR: LoUU Mask */ + +#define SCB_CLIDR_LOC_Pos 24U /*!< SCB CLIDR: LoC Position */ +#define SCB_CLIDR_LOC_Msk (7UL << SCB_CLIDR_LOC_Pos) /*!< SCB CLIDR: LoC Mask */ + +/* SCB Cache Type Register Definitions */ +#define SCB_CTR_FORMAT_Pos 29U /*!< SCB CTR: Format Position */ +#define SCB_CTR_FORMAT_Msk (7UL << SCB_CTR_FORMAT_Pos) /*!< SCB CTR: Format Mask */ + +#define SCB_CTR_CWG_Pos 24U /*!< SCB CTR: CWG Position */ +#define SCB_CTR_CWG_Msk (0xFUL << SCB_CTR_CWG_Pos) /*!< SCB CTR: CWG Mask */ + +#define SCB_CTR_ERG_Pos 20U /*!< SCB CTR: ERG Position */ +#define SCB_CTR_ERG_Msk (0xFUL << SCB_CTR_ERG_Pos) /*!< SCB CTR: ERG Mask */ + +#define SCB_CTR_DMINLINE_Pos 16U /*!< SCB CTR: DminLine Position */ +#define SCB_CTR_DMINLINE_Msk (0xFUL << SCB_CTR_DMINLINE_Pos) /*!< SCB CTR: DminLine Mask */ + +#define SCB_CTR_IMINLINE_Pos 0U /*!< SCB CTR: ImInLine Position */ +#define SCB_CTR_IMINLINE_Msk (0xFUL /*<< SCB_CTR_IMINLINE_Pos*/) /*!< SCB CTR: ImInLine Mask */ + +/* SCB Cache Size ID Register Definitions */ +#define SCB_CCSIDR_WT_Pos 31U /*!< SCB CCSIDR: WT Position */ +#define SCB_CCSIDR_WT_Msk (1UL << SCB_CCSIDR_WT_Pos) /*!< SCB CCSIDR: WT Mask */ + +#define SCB_CCSIDR_WB_Pos 30U /*!< SCB CCSIDR: WB Position */ +#define SCB_CCSIDR_WB_Msk (1UL << SCB_CCSIDR_WB_Pos) /*!< SCB CCSIDR: WB Mask */ + +#define SCB_CCSIDR_RA_Pos 29U /*!< SCB CCSIDR: RA Position */ +#define SCB_CCSIDR_RA_Msk (1UL << SCB_CCSIDR_RA_Pos) /*!< SCB CCSIDR: RA Mask */ + +#define SCB_CCSIDR_WA_Pos 28U /*!< SCB CCSIDR: WA Position */ +#define SCB_CCSIDR_WA_Msk (1UL << SCB_CCSIDR_WA_Pos) /*!< SCB CCSIDR: WA Mask */ + +#define SCB_CCSIDR_NUMSETS_Pos 13U /*!< SCB CCSIDR: NumSets Position */ +#define SCB_CCSIDR_NUMSETS_Msk (0x7FFFUL << SCB_CCSIDR_NUMSETS_Pos) /*!< SCB CCSIDR: NumSets Mask */ + +#define SCB_CCSIDR_ASSOCIATIVITY_Pos 3U /*!< SCB CCSIDR: Associativity Position */ +#define SCB_CCSIDR_ASSOCIATIVITY_Msk (0x3FFUL << SCB_CCSIDR_ASSOCIATIVITY_Pos) /*!< SCB CCSIDR: Associativity Mask */ + +#define SCB_CCSIDR_LINESIZE_Pos 0U /*!< SCB CCSIDR: LineSize Position */ +#define SCB_CCSIDR_LINESIZE_Msk (7UL /*<< SCB_CCSIDR_LINESIZE_Pos*/) /*!< SCB CCSIDR: LineSize Mask */ + +/* SCB Cache Size Selection Register Definitions */ +#define SCB_CSSELR_LEVEL_Pos 1U /*!< SCB CSSELR: Level Position */ +#define SCB_CSSELR_LEVEL_Msk (7UL << SCB_CSSELR_LEVEL_Pos) /*!< SCB CSSELR: Level Mask */ + +#define SCB_CSSELR_IND_Pos 0U /*!< SCB CSSELR: InD Position */ +#define SCB_CSSELR_IND_Msk (1UL /*<< SCB_CSSELR_IND_Pos*/) /*!< SCB CSSELR: InD Mask */ + +/* SCB Software Triggered Interrupt Register Definitions */ +#define SCB_STIR_INTID_Pos 0U /*!< SCB STIR: INTID Position */ +#define SCB_STIR_INTID_Msk (0x1FFUL /*<< SCB_STIR_INTID_Pos*/) /*!< SCB STIR: INTID Mask */ + +/* SCB D-Cache Invalidate by Set-way Register Definitions */ +#define SCB_DCISW_WAY_Pos 30U /*!< SCB DCISW: Way Position */ +#define SCB_DCISW_WAY_Msk (3UL << SCB_DCISW_WAY_Pos) /*!< SCB DCISW: Way Mask */ + +#define SCB_DCISW_SET_Pos 5U /*!< SCB DCISW: Set Position */ +#define SCB_DCISW_SET_Msk (0x1FFUL << SCB_DCISW_SET_Pos) /*!< SCB DCISW: Set Mask */ + +/* SCB D-Cache Clean by Set-way Register Definitions */ +#define SCB_DCCSW_WAY_Pos 30U /*!< SCB DCCSW: Way Position */ +#define SCB_DCCSW_WAY_Msk (3UL << SCB_DCCSW_WAY_Pos) /*!< SCB DCCSW: Way Mask */ + +#define SCB_DCCSW_SET_Pos 5U /*!< SCB DCCSW: Set Position */ +#define SCB_DCCSW_SET_Msk (0x1FFUL << SCB_DCCSW_SET_Pos) /*!< SCB DCCSW: Set Mask */ + +/* SCB D-Cache Clean and Invalidate by Set-way Register Definitions */ +#define SCB_DCCISW_WAY_Pos 30U /*!< SCB DCCISW: Way Position */ +#define SCB_DCCISW_WAY_Msk (3UL << SCB_DCCISW_WAY_Pos) /*!< SCB DCCISW: Way Mask */ + +#define SCB_DCCISW_SET_Pos 5U /*!< SCB DCCISW: Set Position */ +#define SCB_DCCISW_SET_Msk (0x1FFUL << SCB_DCCISW_SET_Pos) /*!< SCB DCCISW: Set Mask */ + +/* Instruction Tightly-Coupled Memory Control Register Definitions */ +#define SCB_ITCMCR_SZ_Pos 3U /*!< SCB ITCMCR: SZ Position */ +#define SCB_ITCMCR_SZ_Msk (0xFUL << SCB_ITCMCR_SZ_Pos) /*!< SCB ITCMCR: SZ Mask */ + +#define SCB_ITCMCR_RETEN_Pos 2U /*!< SCB ITCMCR: RETEN Position */ +#define SCB_ITCMCR_RETEN_Msk (1UL << SCB_ITCMCR_RETEN_Pos) /*!< SCB ITCMCR: RETEN Mask */ + +#define SCB_ITCMCR_RMW_Pos 1U /*!< SCB ITCMCR: RMW Position */ +#define SCB_ITCMCR_RMW_Msk (1UL << SCB_ITCMCR_RMW_Pos) /*!< SCB ITCMCR: RMW Mask */ + +#define SCB_ITCMCR_EN_Pos 0U /*!< SCB ITCMCR: EN Position */ +#define SCB_ITCMCR_EN_Msk (1UL /*<< SCB_ITCMCR_EN_Pos*/) /*!< SCB ITCMCR: EN Mask */ + +/* Data Tightly-Coupled Memory Control Register Definitions */ +#define SCB_DTCMCR_SZ_Pos 3U /*!< SCB DTCMCR: SZ Position */ +#define SCB_DTCMCR_SZ_Msk (0xFUL << SCB_DTCMCR_SZ_Pos) /*!< SCB DTCMCR: SZ Mask */ + +#define SCB_DTCMCR_RETEN_Pos 2U /*!< SCB DTCMCR: RETEN Position */ +#define SCB_DTCMCR_RETEN_Msk (1UL << SCB_DTCMCR_RETEN_Pos) /*!< SCB DTCMCR: RETEN Mask */ + +#define SCB_DTCMCR_RMW_Pos 1U /*!< SCB DTCMCR: RMW Position */ +#define SCB_DTCMCR_RMW_Msk (1UL << SCB_DTCMCR_RMW_Pos) /*!< SCB DTCMCR: RMW Mask */ + +#define SCB_DTCMCR_EN_Pos 0U /*!< SCB DTCMCR: EN Position */ +#define SCB_DTCMCR_EN_Msk (1UL /*<< SCB_DTCMCR_EN_Pos*/) /*!< SCB DTCMCR: EN Mask */ + +/* AHBP Control Register Definitions */ +#define SCB_AHBPCR_SZ_Pos 1U /*!< SCB AHBPCR: SZ Position */ +#define SCB_AHBPCR_SZ_Msk (7UL << SCB_AHBPCR_SZ_Pos) /*!< SCB AHBPCR: SZ Mask */ + +#define SCB_AHBPCR_EN_Pos 0U /*!< SCB AHBPCR: EN Position */ +#define SCB_AHBPCR_EN_Msk (1UL /*<< SCB_AHBPCR_EN_Pos*/) /*!< SCB AHBPCR: EN Mask */ + +/* L1 Cache Control Register Definitions */ +#define SCB_CACR_FORCEWT_Pos 2U /*!< SCB CACR: FORCEWT Position */ +#define SCB_CACR_FORCEWT_Msk (1UL << SCB_CACR_FORCEWT_Pos) /*!< SCB CACR: FORCEWT Mask */ + +#define SCB_CACR_ECCEN_Pos 1U /*!< SCB CACR: ECCEN Position */ +#define SCB_CACR_ECCEN_Msk (1UL << SCB_CACR_ECCEN_Pos) /*!< SCB CACR: ECCEN Mask */ + +#define SCB_CACR_SIWT_Pos 0U /*!< SCB CACR: SIWT Position */ +#define SCB_CACR_SIWT_Msk (1UL /*<< SCB_CACR_SIWT_Pos*/) /*!< SCB CACR: SIWT Mask */ + +/* AHBS Control Register Definitions */ +#define SCB_AHBSCR_INITCOUNT_Pos 11U /*!< SCB AHBSCR: INITCOUNT Position */ +#define SCB_AHBSCR_INITCOUNT_Msk (0x1FUL << SCB_AHBPCR_INITCOUNT_Pos) /*!< SCB AHBSCR: INITCOUNT Mask */ + +#define SCB_AHBSCR_TPRI_Pos 2U /*!< SCB AHBSCR: TPRI Position */ +#define SCB_AHBSCR_TPRI_Msk (0x1FFUL << SCB_AHBPCR_TPRI_Pos) /*!< SCB AHBSCR: TPRI Mask */ + +#define SCB_AHBSCR_CTL_Pos 0U /*!< SCB AHBSCR: CTL Position*/ +#define SCB_AHBSCR_CTL_Msk (3UL /*<< SCB_AHBPCR_CTL_Pos*/) /*!< SCB AHBSCR: CTL Mask */ + +/* Auxiliary Bus Fault Status Register Definitions */ +#define SCB_ABFSR_AXIMTYPE_Pos 8U /*!< SCB ABFSR: AXIMTYPE Position*/ +#define SCB_ABFSR_AXIMTYPE_Msk (3UL << SCB_ABFSR_AXIMTYPE_Pos) /*!< SCB ABFSR: AXIMTYPE Mask */ + +#define SCB_ABFSR_EPPB_Pos 4U /*!< SCB ABFSR: EPPB Position*/ +#define SCB_ABFSR_EPPB_Msk (1UL << SCB_ABFSR_EPPB_Pos) /*!< SCB ABFSR: EPPB Mask */ + +#define SCB_ABFSR_AXIM_Pos 3U /*!< SCB ABFSR: AXIM Position*/ +#define SCB_ABFSR_AXIM_Msk (1UL << SCB_ABFSR_AXIM_Pos) /*!< SCB ABFSR: AXIM Mask */ + +#define SCB_ABFSR_AHBP_Pos 2U /*!< SCB ABFSR: AHBP Position*/ +#define SCB_ABFSR_AHBP_Msk (1UL << SCB_ABFSR_AHBP_Pos) /*!< SCB ABFSR: AHBP Mask */ + +#define SCB_ABFSR_DTCM_Pos 1U /*!< SCB ABFSR: DTCM Position*/ +#define SCB_ABFSR_DTCM_Msk (1UL << SCB_ABFSR_DTCM_Pos) /*!< SCB ABFSR: DTCM Mask */ + +#define SCB_ABFSR_ITCM_Pos 0U /*!< SCB ABFSR: ITCM Position*/ +#define SCB_ABFSR_ITCM_Msk (1UL /*<< SCB_ABFSR_ITCM_Pos*/) /*!< SCB ABFSR: ITCM Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_DISITMATBFLUSH_Pos 12U /*!< ACTLR: DISITMATBFLUSH Position */ +#define SCnSCB_ACTLR_DISITMATBFLUSH_Msk (1UL << SCnSCB_ACTLR_DISITMATBFLUSH_Pos) /*!< ACTLR: DISITMATBFLUSH Mask */ + +#define SCnSCB_ACTLR_DISRAMODE_Pos 11U /*!< ACTLR: DISRAMODE Position */ +#define SCnSCB_ACTLR_DISRAMODE_Msk (1UL << SCnSCB_ACTLR_DISRAMODE_Pos) /*!< ACTLR: DISRAMODE Mask */ + +#define SCnSCB_ACTLR_FPEXCODIS_Pos 10U /*!< ACTLR: FPEXCODIS Position */ +#define SCnSCB_ACTLR_FPEXCODIS_Msk (1UL << SCnSCB_ACTLR_FPEXCODIS_Pos) /*!< ACTLR: FPEXCODIS Mask */ + +#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ +#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ + +#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ +#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29U]; + __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ + __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ + __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[6U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ + uint32_t RESERVED3[981U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( W) Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R ) Lock Status Register */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Mask Register Definitions */ +#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ +#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ +#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ + +#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ +#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ +#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ + +#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ +#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ + +#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ +#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ + +#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ +#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ + +#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ +#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ +#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ +#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +#if (__FPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_FPU Floating Point Unit (FPU) + \brief Type definitions for the Floating Point Unit (FPU) + @{ + */ + +/** + \brief Structure type to access the Floating Point Unit (FPU). + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ + __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ + __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ + __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ + __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ + __IM uint32_t MVFR2; /*!< Offset: 0x018 (R/ ) Media and FP Feature Register 2 */ +} FPU_Type; + +/* Floating-Point Context Control Register Definitions */ +#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ +#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ + +#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ +#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ + +#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ +#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ + +#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ +#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ + +#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ +#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ + +#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ +#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ + +#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ +#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ + +#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ +#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ + +#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ +#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ + +/* Floating-Point Context Address Register Definitions */ +#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ +#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ + +/* Floating-Point Default Status Control Register Definitions */ +#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ +#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ + +#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ +#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ + +#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ +#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ + +#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ +#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ + +/* Media and FP Feature Register 0 Definitions */ +#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ +#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ + +#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ +#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ + +#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ +#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ + +#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ +#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ + +#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ +#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ + +#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ +#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ + +#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ +#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ + +#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ +#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ + +/* Media and FP Feature Register 1 Definitions */ +#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ +#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ + +#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ +#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ + +#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ +#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ + +#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ +#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ + +/* Media and FP Feature Register 2 Definitions */ + +/*@} end of group CMSIS_FPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M4 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ +#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ +#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ +#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +#if (__FPU_PRESENT == 1U) + #define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ + #define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in NVIC and returns the active bit. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + */ +__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHPR[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return(((uint32_t)SCB->SHPR[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + uint32_t mvfr0; + + mvfr0 = SCB->MVFR0; + if ((mvfr0 & 0x00000FF0UL) == 0x220UL) + { + return 2UL; /* Double + Single precision FPU */ + } + else if ((mvfr0 & 0x00000FF0UL) == 0x020UL) + { + return 1UL; /* Single precision FPU */ + } + else + { + return 0UL; /* No FPU */ + } +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ########################## Cache functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_CacheFunctions Cache Functions + \brief Functions that configure Instruction and Data cache. + @{ + */ + +/* Cache Size ID Register Macros */ +#define CCSIDR_WAYS(x) (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos) +#define CCSIDR_SETS(x) (((x) & SCB_CCSIDR_NUMSETS_Msk ) >> SCB_CCSIDR_NUMSETS_Pos ) + + +/** + \brief Enable I-Cache + \details Turns on I-Cache + */ +__STATIC_INLINE void SCB_EnableICache (void) +{ + #if (__ICACHE_PRESENT == 1U) + __DSB(); + __ISB(); + SCB->ICIALLU = 0UL; /* invalidate I-Cache */ + SCB->CCR |= (uint32_t)SCB_CCR_IC_Msk; /* enable I-Cache */ + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Disable I-Cache + \details Turns off I-Cache + */ +__STATIC_INLINE void SCB_DisableICache (void) +{ + #if (__ICACHE_PRESENT == 1U) + __DSB(); + __ISB(); + SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk; /* disable I-Cache */ + SCB->ICIALLU = 0UL; /* invalidate I-Cache */ + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Invalidate I-Cache + \details Invalidates I-Cache + */ +__STATIC_INLINE void SCB_InvalidateICache (void) +{ + #if (__ICACHE_PRESENT == 1U) + __DSB(); + __ISB(); + SCB->ICIALLU = 0UL; + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Enable D-Cache + \details Turns on D-Cache + */ +__STATIC_INLINE void SCB_EnableDCache (void) +{ + #if (__DCACHE_PRESENT == 1U) + uint32_t ccsidr; + uint32_t sets; + uint32_t ways; + + SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + __DSB(); + + ccsidr = SCB->CCSIDR; + + /* invalidate D-Cache */ + sets = (uint32_t)(CCSIDR_SETS(ccsidr)); + do { + ways = (uint32_t)(CCSIDR_WAYS(ccsidr)); + do { + SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) | + ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) ); + #if defined ( __CC_ARM ) + __schedule_barrier(); + #endif + } while (ways--); + } while(sets--); + __DSB(); + + SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */ + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Disable D-Cache + \details Turns off D-Cache + */ +__STATIC_INLINE void SCB_DisableDCache (void) +{ + #if (__DCACHE_PRESENT == 1U) + uint32_t ccsidr; + uint32_t sets; + uint32_t ways; + + SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + __DSB(); + + ccsidr = SCB->CCSIDR; + + SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */ + + /* clean & invalidate D-Cache */ + sets = (uint32_t)(CCSIDR_SETS(ccsidr)); + do { + ways = (uint32_t)(CCSIDR_WAYS(ccsidr)); + do { + SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) | + ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) ); + #if defined ( __CC_ARM ) + __schedule_barrier(); + #endif + } while (ways--); + } while(sets--); + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Invalidate D-Cache + \details Invalidates D-Cache + */ +__STATIC_INLINE void SCB_InvalidateDCache (void) +{ + #if (__DCACHE_PRESENT == 1U) + uint32_t ccsidr; + uint32_t sets; + uint32_t ways; + + SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + __DSB(); + + ccsidr = SCB->CCSIDR; + + /* invalidate D-Cache */ + sets = (uint32_t)(CCSIDR_SETS(ccsidr)); + do { + ways = (uint32_t)(CCSIDR_WAYS(ccsidr)); + do { + SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) | + ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) ); + #if defined ( __CC_ARM ) + __schedule_barrier(); + #endif + } while (ways--); + } while(sets--); + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Clean D-Cache + \details Cleans D-Cache + */ +__STATIC_INLINE void SCB_CleanDCache (void) +{ + #if (__DCACHE_PRESENT == 1U) + uint32_t ccsidr; + uint32_t sets; + uint32_t ways; + + SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + __DSB(); + + ccsidr = SCB->CCSIDR; + + /* clean D-Cache */ + sets = (uint32_t)(CCSIDR_SETS(ccsidr)); + do { + ways = (uint32_t)(CCSIDR_WAYS(ccsidr)); + do { + SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) | + ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk) ); + #if defined ( __CC_ARM ) + __schedule_barrier(); + #endif + } while (ways--); + } while(sets--); + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief Clean & Invalidate D-Cache + \details Cleans and Invalidates D-Cache + */ +__STATIC_INLINE void SCB_CleanInvalidateDCache (void) +{ + #if (__DCACHE_PRESENT == 1U) + uint32_t ccsidr; + uint32_t sets; + uint32_t ways; + + SCB->CSSELR = (0U << 1U) | 0U; /* Level 1 data cache */ + __DSB(); + + ccsidr = SCB->CCSIDR; + + /* clean & invalidate D-Cache */ + sets = (uint32_t)(CCSIDR_SETS(ccsidr)); + do { + ways = (uint32_t)(CCSIDR_WAYS(ccsidr)); + do { + SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) | + ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) ); + #if defined ( __CC_ARM ) + __schedule_barrier(); + #endif + } while (ways--); + } while(sets--); + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief D-Cache Invalidate by address + \details Invalidates D-Cache for the given address + \param[in] addr address (aligned to 32-byte boundary) + \param[in] dsize size of memory block (in number of bytes) +*/ +__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize) +{ + #if (__DCACHE_PRESENT == 1U) + int32_t op_size = dsize; + uint32_t op_addr = (uint32_t)addr; + int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + + __DSB(); + + while (op_size > 0) { + SCB->DCIMVAC = op_addr; + op_addr += linesize; + op_size -= linesize; + } + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief D-Cache Clean by address + \details Cleans D-Cache for the given address + \param[in] addr address (aligned to 32-byte boundary) + \param[in] dsize size of memory block (in number of bytes) +*/ +__STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize) +{ + #if (__DCACHE_PRESENT == 1) + int32_t op_size = dsize; + uint32_t op_addr = (uint32_t) addr; + int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + + __DSB(); + + while (op_size > 0) { + SCB->DCCMVAC = op_addr; + op_addr += linesize; + op_size -= linesize; + } + + __DSB(); + __ISB(); + #endif +} + + +/** + \brief D-Cache Clean and Invalidate by address + \details Cleans and invalidates D_Cache for the given address + \param[in] addr address (aligned to 32-byte boundary) + \param[in] dsize size of memory block (in number of bytes) +*/ +__STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize) +{ + #if (__DCACHE_PRESENT == 1U) + int32_t op_size = dsize; + uint32_t op_addr = (uint32_t) addr; + int32_t linesize = 32U; /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */ + + __DSB(); + + while (op_size > 0) { + SCB->DCCIMVAC = op_addr; + op_addr += linesize; + op_size -= linesize; + } + + __DSB(); + __ISB(); + #endif +} + + +/*@} end of CMSIS_Core_CacheFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM7_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cmFunc.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cmFunc.h new file mode 100755 index 0000000..652a48a --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cmFunc.h @@ -0,0 +1,87 @@ +/**************************************************************************//** + * @file core_cmFunc.h + * @brief CMSIS Cortex-M Core Function Access Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CMFUNC_H +#define __CORE_CMFUNC_H + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ +*/ + +/*------------------ RealView Compiler -----------------*/ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + +/*------------------ ARM Compiler V6 -------------------*/ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armcc_V6.h" + +/*------------------ GNU Compiler ----------------------*/ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + +/*------------------ ICC Compiler ----------------------*/ +#elif defined ( __ICCARM__ ) + #include + +/*------------------ TI CCS Compiler -------------------*/ +#elif defined ( __TMS470__ ) + #include + +/*------------------ TASKING Compiler ------------------*/ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + +/*------------------ COSMIC Compiler -------------------*/ +#elif defined ( __CSMC__ ) + #include + +#endif + +/*@} end of CMSIS_Core_RegAccFunctions */ + +#endif /* __CORE_CMFUNC_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cmInstr.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cmInstr.h new file mode 100755 index 0000000..f474b0e --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cmInstr.h @@ -0,0 +1,87 @@ +/**************************************************************************//** + * @file core_cmInstr.h + * @brief CMSIS Cortex-M Core Instruction Access Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CMINSTR_H +#define __CORE_CMINSTR_H + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/*------------------ RealView Compiler -----------------*/ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + +/*------------------ ARM Compiler V6 -------------------*/ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armcc_V6.h" + +/*------------------ GNU Compiler ----------------------*/ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + +/*------------------ ICC Compiler ----------------------*/ +#elif defined ( __ICCARM__ ) + #include + +/*------------------ TI CCS Compiler -------------------*/ +#elif defined ( __TMS470__ ) + #include + +/*------------------ TASKING Compiler ------------------*/ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + +/*------------------ COSMIC Compiler -------------------*/ +#elif defined ( __CSMC__ ) + #include + +#endif + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + +#endif /* __CORE_CMINSTR_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_cmSimd.h b/src/openmv/src/micropython/lib/cmsis/inc/core_cmSimd.h new file mode 100755 index 0000000..66bf5c2 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_cmSimd.h @@ -0,0 +1,96 @@ +/**************************************************************************//** + * @file core_cmSimd.h + * @brief CMSIS Cortex-M SIMD Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CMSIMD_H +#define __CORE_CMSIMD_H + +#ifdef __cplusplus + extern "C" { +#endif + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +/*------------------ RealView Compiler -----------------*/ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + +/*------------------ ARM Compiler V6 -------------------*/ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armcc_V6.h" + +/*------------------ GNU Compiler ----------------------*/ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + +/*------------------ ICC Compiler ----------------------*/ +#elif defined ( __ICCARM__ ) + #include + +/*------------------ TI CCS Compiler -------------------*/ +#elif defined ( __TMS470__ ) + #include + +/*------------------ TASKING Compiler ------------------*/ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + +/*------------------ COSMIC Compiler -------------------*/ +#elif defined ( __CSMC__ ) + #include + +#endif + +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CMSIMD_H */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_sc000.h b/src/openmv/src/micropython/lib/cmsis/inc/core_sc000.h new file mode 100755 index 0000000..514dbd8 --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_sc000.h @@ -0,0 +1,926 @@ +/**************************************************************************//** + * @file core_sc000.h + * @brief CMSIS SC000 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_SC000_H_GENERIC +#define __CORE_SC000_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup SC000 + @{ + */ + +/* CMSIS SC000 definitions */ +#define __SC000_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __SC000_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __SC000_CMSIS_VERSION ((__SC000_CMSIS_VERSION_MAIN << 16U) | \ + __SC000_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_SC (000U) /*!< Cortex secure core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SC000_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_SC000_H_DEPENDANT +#define __CORE_SC000_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __SC000_REV + #define __SC000_REV 0x0000U + #warning "__SC000_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group SC000 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t _reserved0:1; /*!< bit: 0 Reserved */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED0[1U]; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + uint32_t RESERVED1[154U]; + __IOM uint32_t SFCR; /*!< Offset: 0x290 (R/W) Security Features Control Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +} SCnSCB_Type; + +/* Auxiliary Control Register Definitions */ +#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ +#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief SC000 Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the SC000 header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of SC000 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/* Interrupt Priorities are WORD accessible only under ARMv6M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SC000_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/cmsis/inc/core_sc300.h b/src/openmv/src/micropython/lib/cmsis/inc/core_sc300.h new file mode 100755 index 0000000..8bd18aa --- /dev/null +++ b/src/openmv/src/micropython/lib/cmsis/inc/core_sc300.h @@ -0,0 +1,1745 @@ +/**************************************************************************//** + * @file core_sc300.h + * @brief CMSIS SC300 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_SC300_H_GENERIC +#define __CORE_SC300_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup SC3000 + @{ + */ + +/* CMSIS SC300 definitions */ +#define __SC300_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __SC300_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __SC300_CMSIS_VERSION ((__SC300_CMSIS_VERSION_MAIN << 16U) | \ + __SC300_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_SC (300U) /*!< Cortex secure core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SC300_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_SC300_H_DEPENDANT +#define __CORE_SC300_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __SC300_REV + #define __SC300_REV 0x0000U + #warning "__SC300_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 4U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group SC300 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + +#define APSR_Q_Pos 27U /*!< APSR: Q Position */ +#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ +#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ + +#define xPSR_IT_Pos 25U /*!< xPSR: IT Position */ +#define xPSR_IT_Msk (3UL << xPSR_IT_Pos) /*!< xPSR: IT Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24U]; + __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/* Software Triggered Interrupt Register Definitions */ +#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ +#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ + __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ + __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ + __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ + uint32_t RESERVED0[5U]; + __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ + uint32_t RESERVED1[129U]; + __IOM uint32_t SFCR; /*!< Offset: 0x290 (R/W) Security Features Control Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Vector Table Offset Register Definitions */ +#define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ +#define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ + +#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Register Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* SCB Hard Fault Status Register Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) + \brief Type definitions for the System Control and ID Register not in the SCB + @{ + */ + +/** + \brief Structure type to access the System Control and ID Register not in the SCB. + */ +typedef struct +{ + uint32_t RESERVED0[1U]; + __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ + uint32_t RESERVED1[1U]; +} SCnSCB_Type; + +/* Interrupt Controller Type Register Definitions */ +#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ +#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ + +/*@} end of group CMSIS_SCnotSCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) + \brief Type definitions for the Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** + \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __OM union + { + __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864U]; + __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15U]; + __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15U]; + __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29U]; + __OM uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ + __IM uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ + __IOM uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43U]; + __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ + __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ + uint32_t RESERVED5[6U]; + __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ + __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ + __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ + __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ + __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ + __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ + __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ + __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ + __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ + __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ + __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ + __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ +#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ + +#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0U /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL /*<< ITM_IWR_ATVALIDM_Pos*/) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0U /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL /*<< ITM_IRR_ATREADYM_Pos*/) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0U /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL /*<< ITM_IMCR_INTEGRATION_Pos*/) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) + \brief Type definitions for the Data Watchpoint and Trace (DWT) + @{ + */ + +/** + \brief Structure type to access the Data Watchpoint and Trace Register (DWT). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ + __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ + __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ + __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ + __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ + __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ + __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ + __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ + __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ + __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ + __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ + uint32_t RESERVED0[1U]; + __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ + __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ + __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ + uint32_t RESERVED1[1U]; + __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ + __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ + __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ + uint32_t RESERVED2[1U]; + __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ + __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ + __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ +} DWT_Type; + +/* DWT Control Register Definitions */ +#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ +#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ + +#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ +#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ + +#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ +#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ + +#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ +#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ + +#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ +#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ + +#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ +#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ + +#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ +#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ + +#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ +#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ + +#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ +#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ + +#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ +#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ + +#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ +#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ + +#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ +#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ + +#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ +#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ + +#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ +#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ + +#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ +#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ + +#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ +#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ + +#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ +#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ + +#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ +#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ + +/* DWT CPI Count Register Definitions */ +#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ +#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ + +/* DWT Exception Overhead Count Register Definitions */ +#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ +#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ + +/* DWT Sleep Count Register Definitions */ +#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ +#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ + +/* DWT LSU Count Register Definitions */ +#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ +#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ + +/* DWT Folded-instruction Count Register Definitions */ +#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ +#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ + +/* DWT Comparator Mask Register Definitions */ +#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ +#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ + +/* DWT Comparator Function Register Definitions */ +#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ +#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ + +#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ +#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ + +#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ +#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ + +#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ +#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ + +#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ +#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ + +#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ +#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ + +#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ +#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ + +#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ +#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ + +#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ +#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ + +/*@}*/ /* end of group CMSIS_DWT */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_TPI Trace Port Interface (TPI) + \brief Type definitions for the Trace Port Interface (TPI) + @{ + */ + +/** + \brief Structure type to access the Trace Port Interface Register (TPI). + */ +typedef struct +{ + __IOM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ + __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ + uint32_t RESERVED0[2U]; + __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ + uint32_t RESERVED1[55U]; + __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ + uint32_t RESERVED2[131U]; + __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ + __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ + __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ + uint32_t RESERVED3[759U]; + __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER */ + __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ + __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ + uint32_t RESERVED4[1U]; + __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ + __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ + __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ + uint32_t RESERVED5[39U]; + __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ + __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ + uint32_t RESERVED7[8U]; + __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ + __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ +} TPI_Type; + +/* TPI Asynchronous Clock Prescaler Register Definitions */ +#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ +#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ + +/* TPI Selected Pin Protocol Register Definitions */ +#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ +#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ + +/* TPI Formatter and Flush Status Register Definitions */ +#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ +#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ + +#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ +#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ + +#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ +#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ + +#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ +#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ + +/* TPI Formatter and Flush Control Register Definitions */ +#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ +#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ + +#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ +#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ + +/* TPI TRIGGER Register Definitions */ +#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ +#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ + +/* TPI Integration ETM Data Register Definitions (FIFO0) */ +#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ +#define TPI_FIFO0_ITM_ATVALID_Msk (0x3UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ + +#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ +#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ + +#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ +#define TPI_FIFO0_ETM_ATVALID_Msk (0x3UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ + +#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ +#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ + +#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ +#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ + +#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ +#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ + +#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ +#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ + +/* TPI ITATBCTR2 Register Definitions */ +#define TPI_ITATBCTR2_ATREADY_Pos 0U /*!< TPI ITATBCTR2: ATREADY Position */ +#define TPI_ITATBCTR2_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY_Pos*/) /*!< TPI ITATBCTR2: ATREADY Mask */ + +/* TPI Integration ITM Data Register Definitions (FIFO1) */ +#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ +#define TPI_FIFO1_ITM_ATVALID_Msk (0x3UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ + +#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ +#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ + +#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ +#define TPI_FIFO1_ETM_ATVALID_Msk (0x3UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ + +#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ +#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ + +#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ +#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ + +#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ +#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ + +#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ +#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ + +/* TPI ITATBCTR0 Register Definitions */ +#define TPI_ITATBCTR0_ATREADY_Pos 0U /*!< TPI ITATBCTR0: ATREADY Position */ +#define TPI_ITATBCTR0_ATREADY_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY_Pos*/) /*!< TPI ITATBCTR0: ATREADY Mask */ + +/* TPI Integration Mode Control Register Definitions */ +#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ +#define TPI_ITCTRL_Mode_Msk (0x1UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ + +/* TPI DEVID Register Definitions */ +#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ +#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ + +#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ +#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ + +#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ +#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ + +#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ +#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ + +#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ +#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ + +#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ +#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ + +/* TPI DEVTYPE Register Definitions */ +#define TPI_DEVTYPE_MajorType_Pos 4U /*!< TPI DEVTYPE: MajorType Position */ +#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ + +#define TPI_DEVTYPE_SubType_Pos 0U /*!< TPI DEVTYPE: SubType Position */ +#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ + +/*@}*/ /* end of group CMSIS_TPI */ + + +#if (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Type definitions for the Core Debug Registers + @{ + */ + +/** + \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register Definitions */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register Definitions */ +#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register Definitions */ +#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M3 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ +#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ +#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ +#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/** + \brief Set Priority Grouping + \details Sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Priority grouping field. + */ +__STATIC_INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ + reg_value = (reg_value | + ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8U) ); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** + \brief Get Priority Grouping + \details Reads the priority grouping field from the NVIC Interrupt Controller. + \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). + */ +__STATIC_INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); +} + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Active Interrupt + \details Reads the active register in NVIC and returns the active bit. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not active. + \return 1 Interrupt status is active. + */ +__STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->IABR[(((uint32_t)(int32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } + else + { + NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return(((uint32_t)SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return(((uint32_t)NVIC->IP[((uint32_t)(int32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions ITM Functions + \brief Functions that access the ITM debug interface. + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ +#define ITM_RXBUFFER_EMPTY 0x5AA55AA5U /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ + + +/** + \brief ITM Send Character + \details Transmits a character via the ITM channel 0, and + \li Just returns when no debugger is connected that has booked the output. + \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. + \param [in] ch Character to transmit. + \returns Character to transmit. + */ +__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0U].u32 == 0UL) + { + __NOP(); + } + ITM->PORT[0U].u8 = (uint8_t)ch; + } + return (ch); +} + + +/** + \brief ITM Receive Character + \details Inputs a character via the external variable \ref ITM_RxBuffer. + \return Received character. + \return -1 No character pending. + */ +__STATIC_INLINE int32_t ITM_ReceiveChar (void) +{ + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) + { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** + \brief ITM Check Character + \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. + \return 0 No character available. + \return 1 Character available. + */ +__STATIC_INLINE int32_t ITM_CheckChar (void) +{ + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) + { + return (0); /* no character available */ + } + else + { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SC300_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/openmv/src/micropython/lib/embed/abort_.c b/src/openmv/src/micropython/lib/embed/abort_.c new file mode 100755 index 0000000..2fba0de --- /dev/null +++ b/src/openmv/src/micropython/lib/embed/abort_.c @@ -0,0 +1,7 @@ +#include + +NORETURN void abort_(void); + +NORETURN void abort_(void) { + mp_raise_msg(&mp_type_RuntimeError, "abort() called"); +} diff --git a/src/openmv/src/micropython/lib/libc/string0.c b/src/openmv/src/micropython/lib/libc/string0.c new file mode 100755 index 0000000..c2f2abd --- /dev/null +++ b/src/openmv/src/micropython/lib/libc/string0.c @@ -0,0 +1,219 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#define likely(x) __builtin_expect((x), 1) + +void *memcpy(void *dst, const void *src, size_t n) { + if (likely(!(((uintptr_t)dst) & 3) && !(((uintptr_t)src) & 3))) { + // pointers aligned + uint32_t *d = dst; + const uint32_t *s = src; + + // copy words first + for (size_t i = (n >> 2); i; i--) { + *d++ = *s++; + } + + if (n & 2) { + // copy half-word + *(uint16_t*)d = *(const uint16_t*)s; + d = (uint32_t*)((uint16_t*)d + 1); + s = (const uint32_t*)((const uint16_t*)s + 1); + } + + if (n & 1) { + // copy byte + *((uint8_t*)d) = *((const uint8_t*)s); + } + } else { + // unaligned access, copy bytes + uint8_t *d = dst; + const uint8_t *s = src; + + for (; n; n--) { + *d++ = *s++; + } + } + + return dst; +} + +void *memmove(void *dest, const void *src, size_t n) { + if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) { + // need to copy backwards + uint8_t *d = (uint8_t*)dest + n - 1; + const uint8_t *s = (const uint8_t*)src + n - 1; + for (; n > 0; n--) { + *d-- = *s--; + } + return dest; + } else { + // can use normal memcpy + return memcpy(dest, src, n); + } +} + +void *memset(void *s, int c, size_t n) { + if (c == 0 && ((uintptr_t)s & 3) == 0) { + // aligned store of 0 + uint32_t *s32 = s; + for (size_t i = n >> 2; i > 0; i--) { + *s32++ = 0; + } + if (n & 2) { + *((uint16_t*)s32) = 0; + s32 = (uint32_t*)((uint16_t*)s32 + 1); + } + if (n & 1) { + *((uint8_t*)s32) = 0; + } + } else { + uint8_t *s2 = s; + for (; n > 0; n--) { + *s2++ = c; + } + } + return s; +} + +int memcmp(const void *s1, const void *s2, size_t n) { + const uint8_t *s1_8 = s1; + const uint8_t *s2_8 = s2; + while (n--) { + char c1 = *s1_8++; + char c2 = *s2_8++; + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + return 0; +} + +void *memchr(const void *s, int c, size_t n) { + if (n != 0) { + const unsigned char *p = s; + + do { + if (*p++ == c) + return ((void *)(p - 1)); + } while (--n != 0); + } + return 0; +} + +size_t strlen(const char *str) { + int len = 0; + for (const char *s = str; *s; s++) { + len += 1; + } + return len; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 && *s2) { + char c1 = *s1++; // XXX UTF8 get char, next char + char c2 = *s2++; // XXX UTF8 get char, next char + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + if (*s2) return -1; + else if (*s1) return 1; + else return 0; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (*s1 && *s2 && n > 0) { + char c1 = *s1++; // XXX UTF8 get char, next char + char c2 = *s2++; // XXX UTF8 get char, next char + n--; + if (c1 < c2) return -1; + else if (c1 > c2) return 1; + } + if (n == 0) return 0; + else if (*s2) return -1; + else if (*s1) return 1; + else return 0; +} + +char *strcpy(char *dest, const char *src) { + char *d = dest; + while (*src) { + *d++ = *src++; + } + *d = '\0'; + return dest; +} + +// needed because gcc optimises strcpy + strcat to this +char *stpcpy(char *dest, const char *src) { + while (*src) { + *dest++ = *src++; + } + *dest = '\0'; + return dest; +} + +char *strcat(char *dest, const char *src) { + char *d = dest; + while (*d) { + d++; + } + while (*src) { + *d++ = *src++; + } + *d = '\0'; + return dest; +} + +// Public Domain implementation of strchr from: +// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function +char *strchr(const char *s, int c) +{ + /* Scan s for the character. When this loop is finished, + s will either point to the end of the string or the + character we were looking for. */ + while (*s != '\0' && *s != (char)c) + s++; + return ((*s == c) ? (char *) s : 0); +} + + +// Public Domain implementation of strstr from: +// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function +char *strstr(const char *haystack, const char *needle) +{ + size_t needlelen; + /* Check for the null needle case. */ + if (*needle == '\0') + return (char *) haystack; + needlelen = strlen(needle); + for (; (haystack = strchr(haystack, *needle)) != 0; haystack++) + if (strncmp(haystack, needle, needlelen) == 0) + return (char *) haystack; + return 0; +} diff --git a/src/openmv/src/micropython/lib/libm/acoshf.c b/src/openmv/src/micropython/lib/libm/acoshf.c new file mode 100755 index 0000000..8a8409f --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/acoshf.c @@ -0,0 +1,32 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// acoshf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD==1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000+(1<<23)) + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); + if (a < 0x3f800000+(12<<23)) + /* |x| < 0x1p12 */ + return logf(2*x - 1/(x+sqrtf(x*x-1))); + /* x >= 0x1p12 */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/src/openmv/src/micropython/lib/libm/asinfacosf.c b/src/openmv/src/micropython/lib/libm/asinfacosf.c new file mode 100755 index 0000000..07ecad3 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/asinfacosf.c @@ -0,0 +1,130 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// asinf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +// dpgeorge: pio2 was double in original implementation of asinf +static const float +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08; /* 0x33a22168 */ + +static const float +/* coefficients for R(x^2) */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static float R(float z) +{ + float_t p, q; + p = z*(pS0+z*(pS1+z*pS2)); + q = 1.0f+z*qS1; + return p/q; +} + +float asinf(float x) +{ + // dpgeorge: s was double in original implementation + float s,z; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + if (ix >= 0x3f800000) { /* |x| >= 1 */ + if (ix == 0x3f800000) /* |x| == 1 */ + return x*pio2_hi + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */ + return 0/(x-x); /* asin(|x|>1) is NaN */ + } + if (ix < 0x3f000000) { /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000 && ix >= 0x00800000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabsf(x))*0.5f; + s = sqrtf(z); + x = pio2_hi - (2*(s+s*R(z)) - pio2_lo); // dpgeorge: use pio2_hi and pio2_lo + if (hx >> 31) + return -x; + return x; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// acosf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +float acosf(float x) +{ + float z,w,s,c,df; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3f800000) { + if (ix == 0x3f800000) { + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3f000000) { + if (ix <= 0x32800000) /* |x| < 2**-26 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1+x)*0.5f; + s = sqrtf(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1-x)*0.5f; + s = sqrtf(z); + GET_FLOAT_WORD(hx,s); + SET_FLOAT_WORD(df,hx&0xfffff000); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/src/openmv/src/micropython/lib/libm/asinhf.c b/src/openmv/src/micropython/lib/libm/asinhf.c new file mode 100755 index 0000000..4bcb3f9 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/asinhf.c @@ -0,0 +1,34 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// asinhf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12<<23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1<<23)) { + /* |x| >= 2 */ + x = logf(2*x + 1/(sqrtf(x*x+1)+x)); + } else if (i >= 0x3f800000 - (12<<23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1)+1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/src/openmv/src/micropython/lib/libm/atan2f.c b/src/openmv/src/micropython/lib/libm/atan2f.c new file mode 100755 index 0000000..03d000c --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/atan2f.c @@ -0,0 +1,89 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// atan2f from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float atan2f(float y, float x) +{ + float z; + uint32_t m,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + GET_FLOAT_WORD(ix, x); + GET_FLOAT_WORD(iy, y); + if (ix == 0x3f800000) /* x=1.0 */ + return atanf(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy == 0) { + switch (m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if (ix == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7f800000) { + if (iy == 0x7f800000) { + switch (m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /*atan(+INF,-INF)*/ + case 3: return -3*pi/4; /*atan(-INF,-INF)*/ + } + } else { + switch (m) { + case 0: return 0.0f; /* atan(+...,+INF) */ + case 1: return -0.0f; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p26 */ + if (ix+(26<<23) < iy || iy == 0x7f800000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) with correct underflow */ + if ((m&2) && iy+(26<<23) < ix) /*|y/x| < 0x1p-26, x < 0 */ + z = 0.0; + else + z = atanf(fabsf(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/src/openmv/src/micropython/lib/libm/atanf.c b/src/openmv/src/micropython/lib/libm/atanf.c new file mode 100755 index 0000000..053fc1b --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/atanf.c @@ -0,0 +1,100 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// atanf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +}; + +float atanf(float x) +{ + float_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x4c800000) { /* if |x| >= 2**26 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if (ix < 0x00800000) + /* raise underflow for subnormal x */ + FORCE_EVAL(x*x); + return x; + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0f*x - 1.0f)/(2.0f + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0f)/(x + 1.0f); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5f)/(1.0f + 1.5f*x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; + x = -1.0f/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); + s2 = w*(aT[1]+w*aT[3]); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} diff --git a/src/openmv/src/micropython/lib/libm/atanhf.c b/src/openmv/src/micropython/lib/libm/atanhf.c new file mode 100755 index 0000000..6f95f49 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/atanhf.c @@ -0,0 +1,34 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// atanhf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1<<23)) { + if (u.i < 0x3f800000 - (32<<23)) { + /* handle underflow */ + if (u.i < (1<<23)) + FORCE_EVAL((float)(y*y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5f*log1pf(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/src/openmv/src/micropython/lib/libm/ef_rem_pio2.c b/src/openmv/src/micropython/lib/libm/ef_rem_pio2.c new file mode 100755 index 0000000..ca55243 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/ef_rem_pio2.c @@ -0,0 +1,202 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* ef_rem_pio2.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2f() + */ + +#include "fdlibm.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +#ifdef __STDC__ +static const __int32_t two_over_pi[] = { +#else +static __int32_t two_over_pi[] = { +#endif +0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC, +0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62, +0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63, +0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A, +0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09, +0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29, +0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44, +0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41, +0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C, +0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8, +0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11, +0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF, +0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E, +0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5, +0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92, +0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08, +0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0, +0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3, +0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85, +0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80, +0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA, +0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B, +}; + +/* This array is like the one in e_rem_pio2.c, but the numbers are + single precision and the last 8 bits are forced to 0. */ +#ifdef __STDC__ +static const __int32_t npio2_hw[] = { +#else +static __int32_t npio2_hw[] = { +#endif +0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00, +0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00, +0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100, +0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00, +0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00, +0x4242c700, 0x42490f00 +}; + +/* + * invpio2: 24 bits of 2/pi + * pio2_1: first 17 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 17 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 17 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +#ifdef __STDC__ +static const float +#else +static float +#endif +zero = 0.0000000000e+00, /* 0x00000000 */ +half = 5.0000000000e-01, /* 0x3f000000 */ +two8 = 2.5600000000e+02, /* 0x43800000 */ +invpio2 = 6.3661980629e-01, /* 0x3f22f984 */ +pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */ +pio2_1t = 1.0804334124e-05, /* 0x37354443 */ +pio2_2 = 1.0804273188e-05, /* 0x37354400 */ +pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */ +pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */ +pio2_3t = 6.1232342629e-17; /* 0x248d3132 */ + +#ifdef __STDC__ + __int32_t __ieee754_rem_pio2f(float x, float *y) +#else + __int32_t __ieee754_rem_pio2f(x,y) + float x,y[]; +#endif +{ + float z,w,t,r,fn; + float tx[3]; + __int32_t i,j,n,ix,hx; + int e0,nx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */ + t = fabsf(x); + n = (__int32_t) (t*invpio2+half); + fn = (float)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 40 bit */ + if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + __uint32_t high; + j = ix>>23; + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>8) { /* 2nd iteration needed, good to 57 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>25) { /* 3rd iteration need, 74 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else return n; + } + /* + * all other (large) arguments + */ + if(!FLT_UWORD_IS_FINITE(ix)) { + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-7) */ + e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */ + SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23)); + for(i=0;i<2;i++) { + tx[i] = (float)((__int32_t)(z)); + z = (z-tx[i])*two8; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} diff --git a/src/openmv/src/micropython/lib/libm/ef_sqrt.c b/src/openmv/src/micropython/lib/libm/ef_sqrt.c new file mode 100755 index 0000000..87484d0 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/ef_sqrt.c @@ -0,0 +1,102 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* ef_sqrtf.c -- float version of e_sqrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const float one = 1.0, tiny=1.0e-30; +#else +static float one = 1.0, tiny=1.0e-30; +#endif + +// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined +float sqrtf(float x) +/* +#ifdef __STDC__ + float __ieee754_sqrtf(float x) +#else + float __ieee754_sqrtf(x) + float x; +#endif +*/ +{ + float z; + __uint32_t r,hx; + __int32_t ix,s,q,m,t,i; + + GET_FLOAT_WORD(ix,x); + hx = ix&0x7fffffff; + + /* take care of Inf and NaN */ + if(!FLT_UWORD_IS_FINITE(hx)) + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + /* take care of zero and -ves */ + if(FLT_UWORD_IS_ZERO(hx)) return x;/* sqrt(+-0) = +-0 */ + if(ix<0) return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + + /* normalize x */ + m = (ix>>23); + if(FLT_UWORD_IS_SUBNORMAL(hx)) { /* subnormal x */ + for(i=0;(ix&0x00800000L)==0;i++) ix<<=1; + m -= i-1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffffL)|0x00800000L; + if(m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000L; /* r = moving bit from right to left */ + + while(r!=0) { + t = s+r; + if(t<=ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if(ix!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (z>one) + q += 2; + else + q += (q&1); + } + } + ix = (q>>1)+0x3f000000L; + ix += (m <<23); + SET_FLOAT_WORD(z,ix); + return z; +} diff --git a/src/openmv/src/micropython/lib/libm/erf_lgamma.c b/src/openmv/src/micropython/lib/libm/erf_lgamma.c new file mode 100755 index 0000000..877816a --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/erf_lgamma.c @@ -0,0 +1,255 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* erf_lgamma.c -- float version of er_lgamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "fdlibm.h" + +#define __ieee754_logf logf + +#ifdef __STDC__ +static const float +#else +static float +#endif +two23= 8.3886080000e+06, /* 0x4b000000 */ +half= 5.0000000000e-01, /* 0x3f000000 */ +one = 1.0000000000e+00, /* 0x3f800000 */ +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +#ifdef __STDC__ +static const float zero= 0.0000000000e+00; +#else +static float zero= 0.0000000000e+00; +#endif + +#ifdef __STDC__ + static float sin_pif(float x) +#else + static float sin_pif(x) + float x; +#endif +{ + float y,z; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; + + if(ix<0x3e800000) return __kernel_sinf(pi*x,zero,0); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorf(y); + if(z!=y) { /* inexact anyway */ + y *= (float)0.5; + y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */ + n = (__int32_t) (y*(float)4.0); + } else { + if(ix>=0x4b800000) { + y = zero; n = 0; /* y must be even */ + } else { + if(ix<0x4b000000) z = y+two23; /* exact */ + GET_FLOAT_WORD(n,z); + n &= 1; + y = n; + n<<= 2; + } + } + switch (n) { + case 0: y = __kernel_sinf(pi*y,zero,0); break; + case 1: + case 2: y = __kernel_cosf(pi*((float)0.5-y),zero); break; + case 3: + case 4: y = __kernel_sinf(pi*(one-y),zero,0); break; + case 5: + case 6: y = -__kernel_cosf(pi*(y-(float)1.5),zero); break; + default: y = __kernel_sinf(pi*(y-(float)2.0),zero,0); break; + } + return -y; +} + + +#ifdef __STDC__ + float __ieee754_lgammaf_r(float x, int *signgamp) +#else + float __ieee754_lgammaf_r(x,signgamp) + float x; int *signgamp; +#endif +{ + float t,y,z,nadj = 0.0,p,p1,p2,p3,q,r,w; + __int32_t i,hx,ix; + + GET_FLOAT_WORD(hx,x); + + /* purge off +-inf, NaN, +-0, and negative arguments */ + *signgamp = 1; + ix = hx&0x7fffffff; + if(ix>=0x7f800000) return x*x; + if(ix==0) return one/zero; + if(ix<0x1c800000) { /* |x|<2**-70, return -log(|x|) */ + if(hx<0) { + *signgamp = -1; + return -__ieee754_logf(-x); + } else return -__ieee754_logf(x); + } + if(hx<0) { + if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */ + return one/zero; + t = sin_pif(x); + if(t==zero) return one/zero; /* -integer */ + nadj = __ieee754_logf(pi/fabsf(t*x)); + if(t=0x3f3b4a20) {y = one-x; i= 0;} + else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;} + else {y = x; i=2;} + } else { + r = zero; + if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */ + else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */ + else {y=x-one;i=2;} + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-(float)0.5*y); break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += (-(float)0.5*y + p1/p2); + } + } + else if(ix<0x41000000) { /* x < 8.0 */ + i = (__int32_t)x; + t = zero; + y = x-(float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = half*y+p/q; + z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch(i) { + case 7: z *= (y+(float)6.0); /* FALLTHRU */ + case 6: z *= (y+(float)5.0); /* FALLTHRU */ + case 5: z *= (y+(float)4.0); /* FALLTHRU */ + case 4: z *= (y+(float)3.0); /* FALLTHRU */ + case 3: z *= (y+(float)2.0); /* FALLTHRU */ + r += __ieee754_logf(z); break; + } + /* 8.0 <= x < 2**58 */ + } else if (ix < 0x5c800000) { + t = __ieee754_logf(x); + z = one/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-half)*(t-one)+w; + } else + /* 2**58 <= x <= inf */ + r = x*(__ieee754_logf(x)-one); + if(hx<0) r = nadj - r; + return r; +} diff --git a/src/openmv/src/micropython/lib/libm/fdlibm.h b/src/openmv/src/micropython/lib/libm/fdlibm.h new file mode 100755 index 0000000..ace3b2d --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/fdlibm.h @@ -0,0 +1,227 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * This file is adapted from from newlib-nano-2, the newlib/libm/common/fdlib.h, + * available from https://github.com/32bitmicro/newlib-nano-2. The main change + * is removal of anything to do with double precision. + * + * Appropriate copyright headers are reproduced below. + */ + +/* @(#)fdlibm.h 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include + +/* Default to XOPEN_MODE. */ +#define _XOPEN_MODE + +/* Most routines need to check whether a float is finite, infinite, or not a + number, and many need to know whether the result of an operation will + overflow. These conditions depend on whether the largest exponent is + used for NaNs & infinities, or whether it's used for finite numbers. The + macros below wrap up that kind of information: + + FLT_UWORD_IS_FINITE(X) + True if a positive float with bitmask X is finite. + + FLT_UWORD_IS_NAN(X) + True if a positive float with bitmask X is not a number. + + FLT_UWORD_IS_INFINITE(X) + True if a positive float with bitmask X is +infinity. + + FLT_UWORD_MAX + The bitmask of FLT_MAX. + + FLT_UWORD_HALF_MAX + The bitmask of FLT_MAX/2. + + FLT_UWORD_EXP_MAX + The bitmask of the largest finite exponent (129 if the largest + exponent is used for finite numbers, 128 otherwise). + + FLT_UWORD_LOG_MAX + The bitmask of log(FLT_MAX), rounded down. This value is the largest + input that can be passed to exp() without producing overflow. + + FLT_UWORD_LOG_2MAX + The bitmask of log(2*FLT_MAX), rounded down. This value is the + largest input than can be passed to cosh() without producing + overflow. + + FLT_LARGEST_EXP + The largest biased exponent that can be used for finite numbers + (255 if the largest exponent is used for finite numbers, 254 + otherwise) */ + +#ifdef _FLT_LARGEST_EXPONENT_IS_NORMAL +#define FLT_UWORD_IS_FINITE(x) 1 +#define FLT_UWORD_IS_NAN(x) 0 +#define FLT_UWORD_IS_INFINITE(x) 0 +#define FLT_UWORD_MAX 0x7fffffff +#define FLT_UWORD_EXP_MAX 0x43010000 +#define FLT_UWORD_LOG_MAX 0x42b2d4fc +#define FLT_UWORD_LOG_2MAX 0x42b437e0 +#define HUGE ((float)0X1.FFFFFEP128) +#else +#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L) +#define FLT_UWORD_IS_NAN(x) ((x)>0x7f800000L) +#define FLT_UWORD_IS_INFINITE(x) ((x)==0x7f800000L) +#define FLT_UWORD_MAX 0x7f7fffffL +#define FLT_UWORD_EXP_MAX 0x43000000 +#define FLT_UWORD_LOG_MAX 0x42b17217 +#define FLT_UWORD_LOG_2MAX 0x42b2d4fc +#define HUGE ((float)3.40282346638528860e+38) +#endif +#define FLT_UWORD_HALF_MAX (FLT_UWORD_MAX-(1L<<23)) +#define FLT_LARGEST_EXP (FLT_UWORD_MAX>>23) + +/* Many routines check for zero and subnormal numbers. Such things depend + on whether the target supports denormals or not: + + FLT_UWORD_IS_ZERO(X) + True if a positive float with bitmask X is +0. Without denormals, + any float with a zero exponent is a +0 representation. With + denormals, the only +0 representation is a 0 bitmask. + + FLT_UWORD_IS_SUBNORMAL(X) + True if a non-zero positive float with bitmask X is subnormal. + (Routines should check for zeros first.) + + FLT_UWORD_MIN + The bitmask of the smallest float above +0. Call this number + REAL_FLT_MIN... + + FLT_UWORD_EXP_MIN + The bitmask of the float representation of REAL_FLT_MIN's exponent. + + FLT_UWORD_LOG_MIN + The bitmask of |log(REAL_FLT_MIN)|, rounding down. + + FLT_SMALLEST_EXP + REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported, + -22 if they are). +*/ + +#ifdef _FLT_NO_DENORMALS +#define FLT_UWORD_IS_ZERO(x) ((x)<0x00800000L) +#define FLT_UWORD_IS_SUBNORMAL(x) 0 +#define FLT_UWORD_MIN 0x00800000 +#define FLT_UWORD_EXP_MIN 0x42fc0000 +#define FLT_UWORD_LOG_MIN 0x42aeac50 +#define FLT_SMALLEST_EXP 1 +#else +#define FLT_UWORD_IS_ZERO(x) ((x)==0) +#define FLT_UWORD_IS_SUBNORMAL(x) ((x)<0x00800000L) +#define FLT_UWORD_MIN 0x00000001 +#define FLT_UWORD_EXP_MIN 0x43160000 +#define FLT_UWORD_LOG_MIN 0x42cff1b5 +#define FLT_SMALLEST_EXP -22 +#endif + +#ifdef __STDC__ +#undef __P +#define __P(p) p +#else +#define __P(p) () +#endif + +/* + * set X_TLOSS = pi*2**52, which is possibly defined in + * (one may replace the following line by "#include ") + */ + +#define X_TLOSS 1.41484755040568800000e+16 + +/* Functions that are not documented, and are not in . */ + +/* Undocumented float functions. */ +#ifdef _SCALB_INT +extern float scalbf __P((float, int)); +#else +extern float scalbf __P((float, float)); +#endif +extern float significandf __P((float)); + +/* ieee style elementary float functions */ +extern float __ieee754_sqrtf __P((float)); +extern float __ieee754_acosf __P((float)); +extern float __ieee754_acoshf __P((float)); +extern float __ieee754_logf __P((float)); +extern float __ieee754_atanhf __P((float)); +extern float __ieee754_asinf __P((float)); +extern float __ieee754_atan2f __P((float,float)); +extern float __ieee754_expf __P((float)); +extern float __ieee754_coshf __P((float)); +extern float __ieee754_fmodf __P((float,float)); +extern float __ieee754_powf __P((float,float)); +extern float __ieee754_lgammaf_r __P((float,int *)); +extern float __ieee754_gammaf_r __P((float,int *)); +extern float __ieee754_log10f __P((float)); +extern float __ieee754_sinhf __P((float)); +extern float __ieee754_hypotf __P((float,float)); +extern float __ieee754_j0f __P((float)); +extern float __ieee754_j1f __P((float)); +extern float __ieee754_y0f __P((float)); +extern float __ieee754_y1f __P((float)); +extern float __ieee754_jnf __P((int,float)); +extern float __ieee754_ynf __P((int,float)); +extern float __ieee754_remainderf __P((float,float)); +extern __int32_t __ieee754_rem_pio2f __P((float,float*)); +#ifdef _SCALB_INT +extern float __ieee754_scalbf __P((float,int)); +#else +extern float __ieee754_scalbf __P((float,float)); +#endif + +/* float versions of fdlibm kernel functions */ +extern float __kernel_sinf __P((float,float,int)); +extern float __kernel_cosf __P((float,float)); +extern float __kernel_tanf __P((float,float,int)); +extern int __kernel_rem_pio2f __P((float*,float*,int,int,int,const __int32_t*)); + +/* A union which permits us to convert between a float and a 32 bit + int. */ + +typedef union +{ + float value; + __uint32_t word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +/* Macros to avoid undefined behaviour that can arise if the amount + of a shift is exactly equal to the size of the shifted operand. */ + +#define SAFE_LEFT_SHIFT(op,amt) \ + (((amt) < 8 * sizeof(op)) ? ((op) << (amt)) : 0) + +#define SAFE_RIGHT_SHIFT(op,amt) \ + (((amt) < 8 * sizeof(op)) ? ((op) >> (amt)) : 0) diff --git a/src/openmv/src/micropython/lib/libm/fmodf.c b/src/openmv/src/micropython/lib/libm/fmodf.c new file mode 100755 index 0000000..69a9ad9 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/fmodf.c @@ -0,0 +1,70 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// fmodf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +#include "libm.h" + +float fmodf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/src/openmv/src/micropython/lib/libm/kf_cos.c b/src/openmv/src/micropython/lib/libm/kf_cos.c new file mode 100755 index 0000000..691f984 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/kf_cos.c @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* kf_cos.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const float +#else +static float +#endif +one = 1.0000000000e+00, /* 0x3f800000 */ +C1 = 4.1666667908e-02, /* 0x3d2aaaab */ +C2 = -1.3888889225e-03, /* 0xbab60b61 */ +C3 = 2.4801587642e-05, /* 0x37d00d01 */ +C4 = -2.7557314297e-07, /* 0xb493f27c */ +C5 = 2.0875723372e-09, /* 0x310f74f6 */ +C6 = -1.1359647598e-11; /* 0xad47d74e */ + +#ifdef __STDC__ + float __kernel_cosf(float x, float y) +#else + float __kernel_cosf(x, y) + float x,y; +#endif +{ + float a,hz,z,r,qx; + __int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* ix = |x|'s high word*/ + if(ix<0x32000000) { /* if x < 2**27 */ + if(((int)x)==0) return one; /* generate inexact */ + } + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); + if(ix < 0x3e99999a) /* if |x| < 0.3 */ + return one - ((float)0.5*z - (z*r - x*y)); + else { + if(ix > 0x3f480000) { /* x > 0.78125 */ + qx = (float)0.28125; + } else { + SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */ + } + hz = (float)0.5*z-qx; + a = one-qx; + return a - (hz - (z*r-x*y)); + } +} diff --git a/src/openmv/src/micropython/lib/libm/kf_rem_pio2.c b/src/openmv/src/micropython/lib/libm/kf_rem_pio2.c new file mode 100755 index 0000000..c7e9479 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/kf_rem_pio2.c @@ -0,0 +1,218 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* kf_rem_pio2.c -- float version of k_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +/* In the float version, the input parameter x contains 8 bit + integers, not 24 bit integers. 113 bit precision is not supported. */ + +#ifdef __STDC__ +static const int init_jk[] = {4,7,9}; /* initial value for jk */ +#else +static int init_jk[] = {4,7,9}; +#endif + +#ifdef __STDC__ +static const float PIo2[] = { +#else +static float PIo2[] = { +#endif + 1.5703125000e+00, /* 0x3fc90000 */ + 4.5776367188e-04, /* 0x39f00000 */ + 2.5987625122e-05, /* 0x37da0000 */ + 7.5437128544e-08, /* 0x33a20000 */ + 6.0026650317e-11, /* 0x2e840000 */ + 7.3896444519e-13, /* 0x2b500000 */ + 5.3845816694e-15, /* 0x27c20000 */ + 5.6378512969e-18, /* 0x22d00000 */ + 8.3009228831e-20, /* 0x1fc40000 */ + 3.2756352257e-22, /* 0x1bc60000 */ + 6.3331015649e-25, /* 0x17440000 */ +}; + +#ifdef __STDC__ +static const float +#else +static float +#endif +zero = 0.0, +one = 1.0, +two8 = 2.5600000000e+02, /* 0x43800000 */ +twon8 = 3.9062500000e-03; /* 0x3b800000 */ + +#ifdef __STDC__ + int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2) +#else + int __kernel_rem_pio2f(x,y,e0,nx,prec,ipio2) + float x[], y[]; int e0,nx,prec; __int32_t ipio2[]; +#endif +{ + __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + float z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/8; if(jv<0) jv=0; + q0 = e0-8*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (float)((__int32_t)(twon8* z)); + iq[i] = (__int32_t)(z-two8*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbnf(z,(int)q0); /* actual value of z */ + z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */ + n = (__int32_t) z; + z -= (float)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(8-q0)); n += i; + iq[jz-1] -= i<<(8-q0); + ih = iq[jz-1]>>(7-q0); + } + else if(q0==0) ih = iq[jz-1]>>8; + else if(z>=(float)0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7f; break; + case 2: + iq[jz-1] &= 0x3f; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbnf(one,(int)q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (float) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==(float)0.0) { + jz -= 1; q0 -= 8; + while(iq[jz]==0) { jz--; q0-=8;} + } else { /* break z into 8-bit if necessary */ + z = scalbnf(z,-(int)q0); + if(z>=two8) { + fw = (float)((__int32_t)(twon8*z)); + iq[jz] = (__int32_t)(z-two8*fw); + jz += 1; q0 += 8; + iq[jz] = (__int32_t) fw; + } else iq[jz] = (__int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbnf(one,(int)q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(float)iq[i]; fw*=twon8; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/src/openmv/src/micropython/lib/libm/kf_sin.c b/src/openmv/src/micropython/lib/libm/kf_sin.c new file mode 100755 index 0000000..07ea993 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/kf_sin.c @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* kf_sin.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const float +#else +static float +#endif +half = 5.0000000000e-01,/* 0x3f000000 */ +S1 = -1.6666667163e-01, /* 0xbe2aaaab */ +S2 = 8.3333337680e-03, /* 0x3c088889 */ +S3 = -1.9841270114e-04, /* 0xb9500d01 */ +S4 = 2.7557314297e-06, /* 0x3638ef1b */ +S5 = -2.5050759689e-08, /* 0xb2d72f34 */ +S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */ + +#ifdef __STDC__ + float __kernel_sinf(float x, float y, int iy) +#else + float __kernel_sinf(x, y, iy) + float x,y; int iy; /* iy=0 if y is zero */ +#endif +{ + float z,r,v; + __int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* high word of x */ + if(ix<0x32000000) /* |x| < 2**-27 */ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*S6))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/openmv/src/micropython/lib/libm/kf_tan.c b/src/openmv/src/micropython/lib/libm/kf_tan.c new file mode 100755 index 0000000..6da9bd8 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/kf_tan.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* kf_tan.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" +#ifdef __STDC__ +static const float +#else +static float +#endif +one = 1.0000000000e+00, /* 0x3f800000 */ +pio4 = 7.8539812565e-01, /* 0x3f490fda */ +pio4lo= 3.7748947079e-08, /* 0x33222168 */ +T[] = { + 3.3333334327e-01, /* 0x3eaaaaab */ + 1.3333334029e-01, /* 0x3e088889 */ + 5.3968254477e-02, /* 0x3d5d0dd1 */ + 2.1869488060e-02, /* 0x3cb327a4 */ + 8.8632395491e-03, /* 0x3c11371f */ + 3.5920790397e-03, /* 0x3b6b6916 */ + 1.4562094584e-03, /* 0x3abede48 */ + 5.8804126456e-04, /* 0x3a1a26c8 */ + 2.4646313977e-04, /* 0x398137b9 */ + 7.8179444245e-05, /* 0x38a3f445 */ + 7.1407252108e-05, /* 0x3895c07a */ + -1.8558637748e-05, /* 0xb79bae5f */ + 2.5907305826e-05, /* 0x37d95384 */ +}; + +#ifdef __STDC__ + float __kernel_tanf(float x, float y, int iy) +#else + float __kernel_tanf(x, y, iy) + float x,y; int iy; +#endif +{ + float z,r,v,w,s; + __int32_t ix,hx; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; /* high word of |x| */ + if(ix<0x31800000) /* x < 2**-28 */ + {if((int)x==0) { /* generate inexact */ + if((ix|(iy+1))==0) return one/fabsf(x); + else return (iy==1)? x: -one/x; + } + } + if(ix>=0x3f2ca140) { /* |x|>=0.6744 */ + if(hx<0) {x = -x; y = -y;} + z = pio4-x; + w = pio4lo-y; + x = z+w; y = 0.0; + } + z = x*x; + w = z*z; + /* Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11])))); + v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12]))))); + s = z*x; + r = y + z*(s*(r+v)+y); + r += T[0]*s; + w = x+r; + if(ix>=0x3f2ca140) { + v = (float)iy; + return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r))); + } + if(iy==1) return w; + else { /* if allow error up to 2 ulp, + simply return -1.0/(x+r) here */ + /* compute -1.0/(x+r) accurately */ + float a,t; + __int32_t i; + z = w; + GET_FLOAT_WORD(i,z); + SET_FLOAT_WORD(z,i&0xfffff000); + v = r-(z - x); /* z+v = r+x */ + t = a = -(float)1.0/w; /* a = -1.0/w */ + GET_FLOAT_WORD(i,t); + SET_FLOAT_WORD(t,i&0xfffff000); + s = (float)1.0+t*z; + return t+a*(s+t*v); + } +} diff --git a/src/openmv/src/micropython/lib/libm/libm.h b/src/openmv/src/micropython/lib/libm/libm.h new file mode 100755 index 0000000..f782249 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/libm.h @@ -0,0 +1,54 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// portions extracted from musl-0.9.15 libm.h +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +#define FLT_EVAL_METHOD 0 + +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + (void)__x; \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + (void)__x; \ + } else { \ + volatile long double __x; \ + __x = (x); \ + (void)__x; \ + } \ +} while(0) + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Set a float from a 32 bit int. */ +#define SET_FLOAT_WORD(d,w) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.i = (w); \ + (d) = __u.f; \ +} while (0) diff --git a/src/openmv/src/micropython/lib/libm/log1pf.c b/src/openmv/src/micropython/lib/libm/log1pf.c new file mode 100755 index 0000000..0d32b0a --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/log1pf.c @@ -0,0 +1,83 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// log1pf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t ix,iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0f; /* log1p(-1)=+inf */ + return (x-x)/0.0f; /* log1p(x<-1)=NaN */ + } + if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix&0x7f800000) == 0) + FORCE_EVAL(x*x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu>>23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu&0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/src/openmv/src/micropython/lib/libm/math.c b/src/openmv/src/micropython/lib/libm/math.c new file mode 100755 index 0000000..c23b9f8 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/math.c @@ -0,0 +1,826 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "libm.h" + +typedef float float_t; +typedef union { + float f; + struct { + uint32_t m : 23; + uint32_t e : 8; + uint32_t s : 1; + }; +} float_s_t; + +int __signbitf(float f) { + float_s_t u = {.f = f}; + return u.s; +} + +#ifndef NDEBUG +float copysignf(float x, float y) { + float_s_t fx={.f = x}; + float_s_t fy={.f = y}; + + // copy sign bit; + fx.s = fy.s; + + return fx.f; +} +#endif + +static const float _M_LN10 = 2.30258509299404; // 0x40135d8e +float log10f(float x) { return logf(x) / (float)_M_LN10; } + +float tanhf(float x) { + int sign = 0; + if (x < 0) { + sign = 1; + x = -x; + } + x = expm1f(-2 * x); + x = x / (x + 2); + return sign ? x : -x; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// __fpclassifyf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +int __fpclassifyf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// scalbnf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +float scalbnf(float x, int n) +{ + union {float f; uint32_t i;} u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) + n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) + n = -126; + } + } + u.i = (uint32_t)(0x7f+n)<<23; + x = y * u.f; + return x; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// powf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if (iy == 0) + return 1.0f; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3f800000) + return 1.0f; + /* NaN if either arg is NaN */ + if (ix > 0x7f800000 || iy > 0x7f800000) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x4b800000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3f800000) { + k = (iy>>23) - 0x7f; /* exponent */ + j = iy>>(23-k); + if ((j<<(23-k)) == iy) + yisint = 2 - (j & 1); + } + } + + /* special value of y */ + if (iy == 0x7f800000) { /* y is +-inf */ + if (ix == 0x3f800000) /* (-1)**+-inf is 1 */ + return 1.0f; + else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0f; + else if (ix != 0) /* (|x|<1)**+-inf = 0,inf if x!=0 */ + return hy >= 0 ? 0.0f: -y; + } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f/x; + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3f000000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0f/z; + if (hx < 0) { + if (((ix-0x3f800000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } + + /* |y| is huge */ + if (iy > 0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if (ix < 0x3f7ffff8) + return hy < 0 ? sn*huge*huge : sn*tiny*tiny; + if (ix > 0x3f800007) + return hy > 0 ? sn*huge*huge : sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1; /* t has 20 trailing zeros */ + w = (t*t)*(0.5f - t*(0.333333333333f - t*0.25f)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = v - (t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00800000) { + ax *= two24; + n -= 24; + GET_FLOAT_WORD(ix, ax); + } + n += ((ix)>>23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if (j <= 0x1cc471) /* |x|>1) & 0xfffff000) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k<<21)); + t_l = ax - (t_h - bp[k]); + s_l = v*((u - s_h*t_h) - s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3.0f + s2 + r; + GET_FLOAT_WORD(is, t_h); + SET_FLOAT_WORD(t_h, is & 0xfffff000); + t_l = r - ((t_h - 3.0f) - s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + GET_FLOAT_WORD(is, p_h); + SET_FLOAT_WORD(p_h, is & 0xfffff000); + p_l = v - (p_h - u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h + p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is, y); + SET_FLOAT_WORD(y1, is & 0xfffff000); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + GET_FLOAT_WORD(j, z); + if (j > 0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j == 0x43000000) { /* if z == 128 */ + if (p_l + ovt > z - p_h) + return sn*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) > 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn*tiny*tiny; /* underflow */ + else if (j == 0xc3160000) { /* z == -150 */ + if (p_l <= z-p_h) + return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>23) - 0x7f; + n = 0; + if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23) - 0x7f; /* new k for n */ + SET_FLOAT_WORD(t, n & ~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + GET_FLOAT_WORD(is, t); + SET_FLOAT_WORD(t, is & 0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z - u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0f) - (w+z*w); + z = 1.0f - (r - z); + GET_FLOAT_WORD(j, z); + j += n<<23; + if ((j>>23) <= 0) /* subnormal output */ + z = scalbnf(z, n); + else + SET_FLOAT_WORD(z, j); + return sn*z; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// expf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +half[2] = {0.5,-0.5}, +ln2hi = 6.9314575195e-1f, /* 0x3f317200 */ +ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */ +invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +expf_P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ +expf_P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ + +float expf(float x) +{ + float_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_FLOAT_WORD(hx, x); + sign = hx >> 31; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ + if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ + /* overflow */ + x *= 0x1p127f; + return x; + } + if (sign) { + /* underflow */ + FORCE_EVAL(-0x1p-149f/x); + if (hx >= 0x42cff1b5) /* x <= -103.972084f */ + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ + k = invln2*x + half[sign]; + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x39000000) { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0; + } else { + /* raise inexact */ + FORCE_EVAL(0x1p127f + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(expf_P1+xx*expf_P2); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbnf(y, k); +} + +/*****************************************************************************/ +/*****************************************************************************/ +// expm1f from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +o_threshold = 8.8721679688e+01, /* 0x42b17180 */ +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) +{ + float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) + FORCE_EVAL(x*x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f*x; + hxs = x*hfx; + r1 = 1.0f+hxs*(Q1+hxs*Q2); + t = 3.0f - r1*hfx; + e = hxs*((r1-t)/(6.0f - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5f*(x-e) - 0.5f; + if (k == 1) { + if (x < -0.25f) + return -2.0f*(e-(x+0.5f)); + return 1.0f + 2.0f*(x-e); + } + u.i = (0x7f+k)<<23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y*2.0f*0x1p127f; + else + y = y*twopk; + return y - 1.0f; + } + u.i = (0x7f-k)<<23; /* 2^-k */ + if (k < 23) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// __expo2f from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +float __expo2f(float x) +{ + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + return expf(x - kln2) * scale * scale; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// logf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float logf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// coshf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +float coshf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12<<23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f*(t + 1/t); + } + + /* |x| > log(FLT_MAX) or nan */ + t = __expo2f(x); + return t; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// sinhf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +float sinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) + h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12<<23)) + return x; + return h*(2*t - t*t/(t+1)); + } + return h*(t + t/(t+1)); + } + + /* |x| > logf(FLT_MAX) or nan */ + t = 2*h*__expo2f(absx); + return t; +} + +/*****************************************************************************/ +/*****************************************************************************/ +// ceilf, floorf and truncf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +float ceilf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} + +float floorf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/src/openmv/src/micropython/lib/libm/nearbyintf.c b/src/openmv/src/micropython/lib/libm/nearbyintf.c new file mode 100755 index 0000000..1c35459 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/nearbyintf.c @@ -0,0 +1,21 @@ +// adapted from the rintf() function from musl-1.1.16 + +#include "libm.h" + +float nearbyintf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + int s = u.i>>31; + float_t y; + + if (e >= 0x7f+23) + return x; + if (s) + y = x - 0x1p23f + 0x1p23f; + else + y = x + 0x1p23f - 0x1p23f; + if (y == 0) + return s ? -0.0f : 0.0f; + return y; +} diff --git a/src/openmv/src/micropython/lib/libm/roundf.c b/src/openmv/src/micropython/lib/libm/roundf.c new file mode 100755 index 0000000..3da1f05 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/roundf.c @@ -0,0 +1,33 @@ +/*****************************************************************************/ +/*****************************************************************************/ +// roundf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +#include "libm.h" + +float roundf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f+23) + return x; + if (u.i >> 31) + x = -x; + if (e < 0x7f-1) { + FORCE_EVAL(x + 0x1p23f); + return 0*u.f; + } + y = (float)(x + 0x1p23f) - 0x1p23f - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) + y = -y; + return y; +} diff --git a/src/openmv/src/micropython/lib/libm/sf_cos.c b/src/openmv/src/micropython/lib/libm/sf_cos.c new file mode 100755 index 0000000..fabb129 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_cos.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_cos.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ + float cosf(float x) +#else + float cosf(x) + float x; +#endif +{ + float y[2],z=0.0; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fd8) return __kernel_cosf(x,z); + + /* cos(Inf or NaN) is NaN */ + else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + switch(n&3) { + case 0: return __kernel_cosf(y[0],y[1]); + case 1: return -__kernel_sinf(y[0],y[1],1); + case 2: return -__kernel_cosf(y[0],y[1]); + default: + return __kernel_sinf(y[0],y[1],1); + } + } +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double cos(double x) +#else + double cos(x) + double x; +#endif +{ + return (double) cosf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_erf.c b/src/openmv/src/micropython/lib/libm/sf_erf.c new file mode 100755 index 0000000..3f0172c --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_erf.c @@ -0,0 +1,257 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_erf.c -- float version of s_erf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#define __ieee754_expf expf + +#ifdef __v810__ +#define const +#endif + +#ifdef __STDC__ +static const float +#else +static float +#endif +tiny = 1e-30, +half= 5.0000000000e-01, /* 0x3F000000 */ +one = 1.0000000000e+00, /* 0x3F800000 */ +two = 2.0000000000e+00, /* 0x40000000 */ + /* c = (subfloat)0.84506291151 */ +erx = 8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx = 1.2837916613e-01, /* 0x3e0375d4 */ +efx8= 1.0270333290e+00, /* 0x3f8375d4 */ +pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ +pp1 = -3.2504209876e-01, /* 0xbea66beb */ +pp2 = -2.8481749818e-02, /* 0xbce9528f */ +pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ +qq2 = 6.5022252500e-02, /* 0x3d852a63 */ +qq3 = 5.0813062117e-03, /* 0x3ba68116 */ +qq4 = 1.3249473704e-04, /* 0x390aee49 */ +qq5 = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1 = 4.1485610604e-01, /* 0x3ed46805 */ +pa2 = -3.7220788002e-01, /* 0xbebe9208 */ +pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ +pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ +pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ +qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ +qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ +qa4 = 1.2617121637e-01, /* 0x3e013307 */ +qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ +qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.8649440333e-03, /* 0xbc21a093 */ +ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2 = -1.0558626175e+01, /* 0xc128f022 */ +ra3 = -6.2375331879e+01, /* 0xc2798057 */ +ra4 = -1.6239666748e+02, /* 0xc322658c */ +ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6 = -8.1287437439e+01, /* 0xc2a2932b */ +ra7 = -9.8143291473e+00, /* 0xc11d077e */ +sa1 = 1.9651271820e+01, /* 0x419d35ce */ +sa2 = 1.3765776062e+02, /* 0x4309a863 */ +sa3 = 4.3456588745e+02, /* 0x43d9486f */ +sa4 = 6.4538726807e+02, /* 0x442158c9 */ +sa5 = 4.2900814819e+02, /* 0x43d6810b */ +sa6 = 1.0863500214e+02, /* 0x42d9451f */ +sa7 = 6.5702495575e+00, /* 0x40d23f7c */ +sa8 = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.8649431020e-03, /* 0xbc21a092 */ +rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2 = -1.7757955551e+01, /* 0xc18e104b */ +rb3 = -1.6063638306e+02, /* 0xc320a2ea */ +rb4 = -6.3756646729e+02, /* 0xc41f6441 */ +rb5 = -1.0250950928e+03, /* 0xc480230b */ +rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1 = 3.0338060379e+01, /* 0x41f2b459 */ +sb2 = 3.2579251099e+02, /* 0x43a2e571 */ +sb3 = 1.5367296143e+03, /* 0x44c01759 */ +sb4 = 3.1998581543e+03, /* 0x4547fdbb */ +sb5 = 2.5530502930e+03, /* 0x451f90ce */ +sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ +sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +#ifdef __STDC__ + float erff(float x) +#else + float erff(x) + float x; +#endif +{ + __int32_t hx,ix,i; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(!FLT_UWORD_IS_FINITE(ix)) { /* erf(nan)=nan */ + i = ((__uint32_t)hx>>31)<<1; + return (float)(1-i)+one/x; /* erf(+-inf)=+-1 */ + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x31800000) { /* |x|<2**-28 */ + if (ix < 0x04000000) + /*avoid underflow */ + return (float)0.125*((float)8.0*x+efx8*x); + return x + efx*x; + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) return erx + P/Q; else return -erx - P/Q; + } + if (ix >= 0x40c00000) { /* inf>|x|>=6 */ + if(hx>=0) return one-tiny; else return tiny-one; + } + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6E) { /* |x| < 1/0.35 */ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(z,ix&0xfffff000); + r = __ieee754_expf(-z*z-(float)0.5625)*__ieee754_expf((z-x)*(z+x)+R/S); + if(hx>=0) return one-r/x; else return r/x-one; +} + +#ifdef __STDC__ + float erfcf(float x) +#else + float erfcf(x) + float x; +#endif +{ + __int32_t hx,ix; + float R,S,P,Q,s,y,z,r; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(!FLT_UWORD_IS_FINITE(ix)) { /* erfc(nan)=nan */ + /* erfc(+-inf)=0,2 */ + return (float)(((__uint32_t)hx>>31)<<1)+one/x; + } + + if(ix < 0x3f580000) { /* |x|<0.84375 */ + if(ix < 0x23800000) /* |x|<2**-56 */ + return one-x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if(hx < 0x3e800000) { /* x<1/4 */ + return one-(x+x*y); + } else { + r = x*y; + r += (x-half); + return half - r ; + } + } + if(ix < 0x3fa00000) { /* 0.84375 <= |x| < 1.25 */ + s = fabsf(x)-one; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + if(hx>=0) { + z = one-erx; return z - P/Q; + } else { + z = erx+P/Q; return one+z; + } + } + if (ix < 0x41e00000) { /* |x|<28 */ + x = fabsf(x); + s = one/(x*x); + if(ix< 0x4036DB6D) { /* |x| < 1/.35 ~ 2.857143*/ + R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/.35 ~ 2.857143 */ + if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */ + R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(z,ix&0xfffff000); + r = __ieee754_expf(-z*z-(float)0.5625)* + __ieee754_expf((z-x)*(z+x)+R/S); + if(hx>0) return r/x; else return two-r/x; + } else { + if(hx>0) return tiny*tiny; else return two-tiny; + } +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double erf(double x) +#else + double erf(x) + double x; +#endif +{ + return (double) erff((float) x); +} + +#ifdef __STDC__ + double erfc(double x) +#else + double erfc(x) + double x; +#endif +{ + return (double) erfcf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_frexp.c b/src/openmv/src/micropython/lib/libm/sf_frexp.c new file mode 100755 index 0000000..df50fb7 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_frexp.c @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_frexp.c -- float version of s_frexp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const float +#else +static float +#endif +two25 = 3.3554432000e+07; /* 0x4c000000 */ + +#ifdef __STDC__ + float frexpf(float x, int *eptr) +#else + float frexpf(x, eptr) + float x; int *eptr; +#endif +{ + __int32_t hx, ix; + GET_FLOAT_WORD(hx,x); + ix = 0x7fffffff&hx; + *eptr = 0; + if(!FLT_UWORD_IS_FINITE(ix)||FLT_UWORD_IS_ZERO(ix)) return x; /* 0,inf,nan */ + if (FLT_UWORD_IS_SUBNORMAL(ix)) { /* subnormal */ + x *= two25; + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + *eptr = -25; + } + *eptr += (ix>>23)-126; + hx = (hx&0x807fffff)|0x3f000000; + SET_FLOAT_WORD(x,hx); + return x; +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double frexp(double x, int *eptr) +#else + double frexp(x, eptr) + double x; int *eptr; +#endif +{ + return (double) frexpf((float) x, eptr); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_ldexp.c b/src/openmv/src/micropython/lib/libm/sf_ldexp.c new file mode 100755 index 0000000..37968d4 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_ldexp.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_ldexp.c -- float version of s_ldexp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" +//#include + +#ifdef __STDC__ + float ldexpf(float value, int exp) +#else + float ldexpf(value, exp) + float value; int exp; +#endif +{ + if(!isfinite(value)||value==(float)0.0) return value; + value = scalbnf(value,exp); + //if(!finitef(value)||value==(float)0.0) errno = ERANGE; + return value; +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double ldexp(double value, int exp) +#else + double ldexp(value, exp) + double value; int exp; +#endif +{ + return (double) ldexpf((float) value, exp); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_modf.c b/src/openmv/src/micropython/lib/libm/sf_modf.c new file mode 100755 index 0000000..410db2a --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_modf.c @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/common + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_modf.c -- float version of s_modf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const float one = 1.0; +#else +static float one = 1.0; +#endif + +#ifdef __STDC__ + float modff(float x, float *iptr) +#else + float modff(x, iptr) + float x,*iptr; +#endif +{ + __int32_t i0,j0; + __uint32_t i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */ + if(j0<23) { /* integer part in x */ + if(j0<0) { /* |x|<1 */ + SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */ + return x; + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) { /* x is integral */ + __uint32_t ix; + *iptr = x; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } else { + SET_FLOAT_WORD(*iptr,i0&(~i)); + return x - *iptr; + } + } + } else { /* no fraction part */ + __uint32_t ix; + *iptr = x*one; + GET_FLOAT_WORD(ix,x); + SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */ + return x; + } +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double modf(double x, double *iptr) +#else + double modf(x, iptr) + double x,*iptr; +#endif +{ + return (double) modff((float) x, (float *) iptr); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_sin.c b/src/openmv/src/micropython/lib/libm/sf_sin.c new file mode 100755 index 0000000..d270507 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_sin.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_sin.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ + float sinf(float x) +#else + float sinf(x) + float x; +#endif +{ + float y[2],z=0.0; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0); + + /* sin(Inf or NaN) is NaN */ + else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + switch(n&3) { + case 0: return __kernel_sinf(y[0],y[1],1); + case 1: return __kernel_cosf(y[0],y[1]); + case 2: return -__kernel_sinf(y[0],y[1],1); + default: + return -__kernel_cosf(y[0],y[1]); + } + } +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double sin(double x) +#else + double sin(x) + double x; +#endif +{ + return (double) sinf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/sf_tan.c b/src/openmv/src/micropython/lib/libm/sf_tan.c new file mode 100755 index 0000000..148b16d --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/sf_tan.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* sf_tan.c -- float version of s_tan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "fdlibm.h" + +#ifdef __STDC__ + float tanf(float x) +#else + float tanf(x) + float x; +#endif +{ + float y[2],z=0.0; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1); + + /* tan(Inf or NaN) is NaN */ + else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; /* NaN */ + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even + -1 -- n odd */ + } +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double tan(double x) +#else + double tan(x) + double x; +#endif +{ + return (double) tanf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/thumb_vfp_sqrtf.c b/src/openmv/src/micropython/lib/libm/thumb_vfp_sqrtf.c new file mode 100755 index 0000000..12ffebf --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/thumb_vfp_sqrtf.c @@ -0,0 +1,11 @@ +// an implementation of sqrtf for Thumb using hardware VFP instructions + +#include + +float sqrtf(float x) { + asm volatile ( + "vsqrt.f32 %[r], %[x]\n" + : [r] "=t" (x) + : [x] "t" (x)); + return x; +} diff --git a/src/openmv/src/micropython/lib/libm/wf_lgamma.c b/src/openmv/src/micropython/lib/libm/wf_lgamma.c new file mode 100755 index 0000000..d86ede7 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/wf_lgamma.c @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* wf_lgamma.c -- float version of w_lgamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +#include "fdlibm.h" +#define _IEEE_LIBM 1 +//#include +//#include + +#ifdef __STDC__ + float lgammaf(float x) +#else + float lgammaf(x) + float x; +#endif +{ +#ifdef _IEEE_LIBM + int sign; + return __ieee754_lgammaf_r(x,&sign); +#else + float y; + struct exception exc; + y = __ieee754_lgammaf_r(x,&(_REENT_SIGNGAM(_REENT))); + if(_LIB_VERSION == _IEEE_) return y; + if(!finitef(y)&&finitef(x)) { +#ifndef HUGE_VAL +#define HUGE_VAL inf + double inf = 0.0; + + SET_HIGH_WORD(inf,0x7ff00000); /* set inf to infinite */ +#endif + exc.name = "lgammaf"; + exc.err = 0; + exc.arg1 = exc.arg2 = (double)x; + if (_LIB_VERSION == _SVID_) + exc.retval = HUGE; + else + exc.retval = HUGE_VAL; + if(floorf(x)==x&&x<=(float)0.0) { + /* lgammaf(-integer) */ + exc.type = SING; + if (_LIB_VERSION == _POSIX_) + errno = EDOM; + else if (!matherr(&exc)) { + errno = EDOM; + } + + } else { + /* lgammaf(finite) overflow */ + exc.type = OVERFLOW; + if (_LIB_VERSION == _POSIX_) + errno = ERANGE; + else if (!matherr(&exc)) { + errno = ERANGE; + } + } + if (exc.err != 0) + errno = exc.err; + return (float)exc.retval; + } else + return y; +#endif +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double lgamma(double x) +#else + double lgamma(x) + double x; +#endif +{ + return (double) lgammaf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm/wf_tgamma.c b/src/openmv/src/micropython/lib/libm/wf_tgamma.c new file mode 100755 index 0000000..3ff05f3 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm/wf_tgamma.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * These math functions are taken from newlib-nano-2, the newlib/libm/math + * directory, available from https://github.com/32bitmicro/newlib-nano-2. + * + * Appropriate copyright headers are reproduced below. + */ + +/* w_gammaf.c -- float version of w_gamma.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "math.h" +#include "fdlibm.h" +#define _IEEE_LIBM 1 + +#ifdef __STDC__ + float tgammaf(float x) +#else + float tgammaf(x) + float x; +#endif +{ + float y; + int local_signgam; + if (!isfinite(x)) { + /* special cases: tgammaf(nan)=nan, tgammaf(inf)=inf, tgammaf(-inf)=nan */ + return x + INFINITY; + } + y = expf(__ieee754_lgammaf_r(x,&local_signgam)); + if (local_signgam < 0) y = -y; +#ifdef _IEEE_LIBM + return y; +#else + if(_LIB_VERSION == _IEEE_) return y; + + if(!finitef(y)&&finitef(x)) { + if(floorf(x)==x&&x<=(float)0.0) + /* tgammaf pole */ + return (float)__kernel_standard((double)x,(double)x,141); + else + /* tgammaf overflow */ + return (float)__kernel_standard((double)x,(double)x,140); + } + return y; +#endif +} + +#ifdef _DOUBLE_IS_32BITS + +#ifdef __STDC__ + double tgamma(double x) +#else + double tgamma(x) + double x; +#endif +{ + return (double) tgammaf((float) x); +} + +#endif /* defined(_DOUBLE_IS_32BITS) */ diff --git a/src/openmv/src/micropython/lib/libm_dbl/README b/src/openmv/src/micropython/lib/libm_dbl/README new file mode 100755 index 0000000..4b58352 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/README @@ -0,0 +1,36 @@ +This directory contains source code for the standard double-precision math +functions. + +The files lgamma.c, log10.c and tanh.c are too small to have a meaningful +copyright or license. + +The file copysign.c contains a double version of the float copysignf provided +in libm/math.c for use in DEBUG builds where the standard library copy is +not available. + +The rest of the files in this directory are copied from the musl library, +v1.1.16, and, unless otherwise stated in the individual file, have the +following copyright and MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- diff --git a/src/openmv/src/micropython/lib/libm_dbl/__cos.c b/src/openmv/src/micropython/lib/libm_dbl/__cos.c new file mode 100755 index 0000000..46cefb3 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__cos.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "libm.h" + +static const double +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double __cos(double x, double y) +{ + double_t hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__expo2.c b/src/openmv/src/micropython/lib/libm_dbl/__expo2.c new file mode 100755 index 0000000..740ac68 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__expo2.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +double __expo2(double x) +{ + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__fpclassify.c b/src/openmv/src/micropython/lib/libm_dbl/__fpclassify.c new file mode 100755 index 0000000..5c908ba --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__fpclassify.c @@ -0,0 +1,11 @@ +#include +#include + +int __fpclassifyd(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2.c b/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2.c new file mode 100755 index 0000000..d403f81 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2.c @@ -0,0 +1,177 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +toint = 1.5/EPS, +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +int __rem_pio2(double x, double *y) +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2_large.c b/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2_large.c new file mode 100755 index 0000000..958f28c --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__rem_pio2_large.c @@ -0,0 +1,442 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __rem_pio2_large(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __rem_pio2_large return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__signbit.c b/src/openmv/src/micropython/lib/libm_dbl/__signbit.c new file mode 100755 index 0000000..18c6728 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__signbit.c @@ -0,0 +1,12 @@ +#include "libm.h" + +int __signbitd(double x) +{ + union { + double d; + uint64_t i; + } y = { x }; + return y.i>>63; +} + + diff --git a/src/openmv/src/micropython/lib/libm_dbl/__sin.c b/src/openmv/src/micropython/lib/libm_dbl/__sin.c new file mode 100755 index 0000000..4030949 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__sin.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "libm.h" + +static const double +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double __sin(double x, double y, int iy) +{ + double_t z,r,v,w; + + z = x*x; + w = z*z; + r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6); + v = z*x; + if (iy == 0) + return x + v*(S1 + z*r); + else + return x - ((z*(0.5*y - v*r) - y) - v*S1); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/__tan.c b/src/openmv/src/micropython/lib/libm_dbl/__tan.c new file mode 100755 index 0000000..8019844 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/__tan.c @@ -0,0 +1,110 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "libm.h" + +static const double T[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +}, +pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ +pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +double __tan(double x, double y, int odd) +{ + double_t z, r, v, w, s, a; + double w0, a0; + uint32_t hx; + int big, sign; + + GET_HIGH_WORD(hx,x); + big = (hx&0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if (big) { + sign = hx>>31; + if (sign) { + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w*(T[3] + w*(T[5] + w*(T[7] + w*(T[9] + w*T[11])))); + v = z*(T[2] + w*(T[4] + w*(T[6] + w*(T[8] + w*(T[10] + w*T[12]))))); + s = z * x; + r = y + z*(s*(r + v) + y) + s*T[0]; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w*w/(w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + w0 = w; + SET_LOW_WORD(w0, 0); + v = r - (w0 - x); /* w0+v = r+x */ + a0 = a = -1.0 / w; + SET_LOW_WORD(a0, 0); + return a0 + a*(1.0 + a0*w0 + a0*v); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/acos.c b/src/openmv/src/micropython/lib/libm_dbl/acos.c new file mode 100755 index 0000000..6104a32 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/acos.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double acos(double x) +{ + double z,w,s,c,df; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + + GET_LOW_WORD(lx,x); + if (((ix-0x3ff00000) | lx) == 0) { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + if (ix <= 0x3c600000) /* |x| < 2**-57 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1.0+x)*0.5; + s = sqrt(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1.0-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/acosh.c b/src/openmv/src/micropython/lib/libm_dbl/acosh.c new file mode 100755 index 0000000..badbf90 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))); + if (e < 0x3ff + 26) + /* |x| < 0x1p26 */ + return log(2*x - 1/(x+sqrt(x*x-1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/asin.c b/src/openmv/src/micropython/lib/libm_dbl/asin.c new file mode 100755 index 0000000..96b4cdf --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/asin.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double asin(double x) +{ + double z,r,s; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + GET_LOW_WORD(lx, x); + if (((ix-0x3ff00000) | lx) == 0) + /* asin(1) = +-pi/2 with inexact */ + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (ix < 0x3e500000 && ix >= 0x00100000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabs(x))*0.5; + s = sqrt(z); + r = R(z); + if (ix >= 0x3fef3333) { /* if |x| > 0.975 */ + x = pio2_hi-(2*(s+s*r)-pio2_lo); + } else { + double f,c; + /* f+c = sqrt(z) */ + f = s; + SET_LOW_WORD(f,0); + c = (z-f*f)/(s+f); + x = 0.5*pio2_hi - (2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + if (hx >> 31) + return -x; + return x; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/asinh.c b/src/openmv/src/micropython/lib/libm_dbl/asinh.c new file mode 100755 index 0000000..0829f22 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/asinh.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2*x + 1/(sqrt(x*x+1)+x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1)+1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/atan.c b/src/openmv/src/micropython/lib/libm_dbl/atan.c new file mode 100755 index 0000000..63b0ab2 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/atan.c @@ -0,0 +1,116 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + + +#include "libm.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +double atan(double x) +{ + double_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x44100000) { /* if |x| >= 2^66 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if (ix < 0x00100000) + /* raise underflow for subnormal x */ + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - (x*(s1+s2) - atanlo[id] - x); + return sign ? -z : z; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/atan2.c b/src/openmv/src/micropython/lib/libm_dbl/atan2.c new file mode 100755 index 0000000..91378b9 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/atan2.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double atan2(double y, double x) +{ + double z; + uint32_t m,lx,ly,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + EXTRACT_WORDS(ix, lx, x); + EXTRACT_WORDS(iy, ly, y); + if (((ix-0x3ff00000) | lx) == 0) /* x = 1.0 */ + return atan(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix = ix & 0x7fffffff; + iy = iy & 0x7fffffff; + + /* when y = 0 */ + if ((iy|ly) == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if ((ix|lx) == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7ff00000) { + if (iy == 0x7ff00000) { + switch(m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /* atan(+INF,-INF) */ + case 3: return -3*pi/4; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p64 */ + if (ix+(64<<20) < iy || iy == 0x7ff00000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && iy+(64<<20) < ix) /* |y/x| < 0x1p-64, x<0 */ + z = 0; + else + z = atan(fabs(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/atanh.c b/src/openmv/src/micropython/lib/libm_dbl/atanh.c new file mode 100755 index 0000000..63a035d --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/atanh.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1/2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5*log1p(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5*log1p(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/ceil.c b/src/openmv/src/micropython/lib/libm_dbl/ceil.c new file mode 100755 index 0000000..b13e6f2 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/ceil.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double ceil(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/copysign.c b/src/openmv/src/micropython/lib/libm_dbl/copysign.c new file mode 100755 index 0000000..f42b09b --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/copysign.c @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "libm.h" + +#ifndef NDEBUG +typedef union { + double d; + struct { + uint64_t m : 52; + uint64_t e : 11; + uint64_t s : 1; + }; +} double_s_t; + +double copysign(double x, double y) { + double_s_t dx={.d = x}; + double_s_t dy={.d = y}; + + // copy sign bit; + dx.s = dy.s; + + return dx.d; +} +#endif diff --git a/src/openmv/src/micropython/lib/libm_dbl/cos.c b/src/openmv/src/micropython/lib/libm_dbl/cos.c new file mode 100755 index 0000000..ee97f68 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/cos.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cosine function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double cos(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x-x; + + /* argument reduction */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __cos(y[0], y[1]); + case 1: return -__sin(y[0], y[1], 1); + case 2: return -__cos(y[0], y[1]); + default: + return __sin(y[0], y[1], 1); + } +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/cosh.c b/src/openmv/src/micropython/lib/libm_dbl/cosh.c new file mode 100755 index 0000000..100f823 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/cosh.c @@ -0,0 +1,40 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26<<20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5*(t + 1/t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/erf.c b/src/openmv/src/micropython/lib/libm_dbl/erf.c new file mode 100755 index 0000000..2f30a29 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/erf.c @@ -0,0 +1,273 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +static const double +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +static double erfc1(double x) +{ + double_t s,P,Q; + + s = fabs(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static double erfc2(uint32_t ix, double x) +{ + double_t s,R,S; + double z; + + if (ix < 0x3ff40000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabs(x); + s = 1/(x*x); + if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| > 1/.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + return exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S)/x; +} + +double erf(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3e300000) { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-1022; + return sign ? -y : y; +} + +double erfc(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3c700000) /* |x| < 2**-56 */ + return 1.0 - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3fd00000) { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-1022 : 0x1p-1022*0x1p-1022; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/exp.c b/src/openmv/src/micropython/lib/libm_dbl/exp.c new file mode 100755 index 0000000..9ea672f --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/exp.c @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +#include "libm.h" + +static const double +half[2] = {0.5,-0.5}, +ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +double exp(double x) +{ + double_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx>>31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) + return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x < -745.13321910194110842) + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2*x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5)))); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbn(y, k); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/expm1.c b/src/openmv/src/micropython/lib/libm_dbl/expm1.c new file mode 100755 index 0000000..ac1e61e --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/expm1.c @@ -0,0 +1,201 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) +{ + double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {double f; uint64_t i;} u = {x}; + uint32_t hx = u.i>>32 & 0x7fffffff; + int k, sign = u.i>>63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) + FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5*(x-e) - 0.5; + if (k == 1) { + if (x < -0.25) + return -2.0*(e-(x+0.5)); + return 1.0+2.0*(x-e); + } + u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y*2.0*0x1p1023; + else + y = y*twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */ + if (k < 20) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/floor.c b/src/openmv/src/micropython/lib/libm_dbl/floor.c new file mode 100755 index 0000000..14a31cd --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/floor.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double floor(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/fmod.c b/src/openmv/src/micropython/lib/libm_dbl/fmod.c new file mode 100755 index 0000000..6849722 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/fmod.c @@ -0,0 +1,68 @@ +#include +#include + +double fmod(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>52 == 0; uxi <<= 1, ex--); + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/frexp.c b/src/openmv/src/micropython/lib/libm_dbl/frexp.c new file mode 100755 index 0000000..27b6266 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/frexp.c @@ -0,0 +1,23 @@ +#include +#include + +double frexp(double x, int *e) +{ + union { double d; uint64_t i; } y = { x }; + int ee = y.i>>52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/ldexp.c b/src/openmv/src/micropython/lib/libm_dbl/ldexp.c new file mode 100755 index 0000000..f4d1cd6 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/ldexp.c @@ -0,0 +1,6 @@ +#include + +double ldexp(double x, int n) +{ + return scalbn(x, n); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/lgamma.c b/src/openmv/src/micropython/lib/libm_dbl/lgamma.c new file mode 100755 index 0000000..ed193da --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/lgamma.c @@ -0,0 +1,8 @@ +#include + +double __lgamma_r(double, int*); + +double lgamma(double x) { + int sign; + return __lgamma_r(x, &sign); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/libm.h b/src/openmv/src/micropython/lib/libm_dbl/libm.h new file mode 100755 index 0000000..dc0b431 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/libm.h @@ -0,0 +1,96 @@ +// Portions of this file are extracted from musl-1.1.16 src/internal/libm.h + +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +#define FLT_EVAL_METHOD 0 + +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + (void)__x; \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + (void)__x; \ + } else { \ + volatile long double __x; \ + __x = (x); \ + (void)__x; \ + } \ +} while(0) + +/* Get two 32 bit ints from a double. */ +#define EXTRACT_WORDS(hi,lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Set a double from two 32 bit ints. */ +#define INSERT_WORDS(d,hi,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_HIGH_WORD(d,hi) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff; \ + __u.i |= (uint64_t)(hi) << 32; \ + (d) = __u.f; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD(d,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff00000000ull; \ + __u.i |= (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +#define DBL_EPSILON 2.22044604925031308085e-16 + +int __rem_pio2(double, double*); +int __rem_pio2_large(double*, double*, int, int, int); +double __sin(double, double, int); +double __cos(double, double); +double __tan(double, double, int); +double __expo2(double); diff --git a/src/openmv/src/micropython/lib/libm_dbl/log.c b/src/openmv/src/micropython/lib/libm_dbl/log.c new file mode 100755 index 0000000..e61e113 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/log.c @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/log10.c b/src/openmv/src/micropython/lib/libm_dbl/log10.c new file mode 100755 index 0000000..bddedd6 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/log10.c @@ -0,0 +1,7 @@ +#include + +static const double _M_LN10 = 2.302585092994046; + +double log10(double x) { + return log(x) / (double)_M_LN10; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/log1p.c b/src/openmv/src/micropython/lib/libm_dbl/log1p.c new file mode 100755 index 0000000..0097134 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/log1p.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include "libm.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t hx,hu; + int k; + + hx = u.i>>32; + k = 1; + if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0; /* log1p(-1) = -inf */ + return (x-x)/0.0; /* log1p(x<-1) = NaN */ + } + if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx&0x7ff00000) == 0) + FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i>>32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu>>20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu<<32 | (u.i&0xffffffff); + f = u.f - 1; + } + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/modf.c b/src/openmv/src/micropython/lib/libm_dbl/modf.c new file mode 100755 index 0000000..1c8a1db --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/modf.c @@ -0,0 +1,34 @@ +#include "libm.h" + +double modf(double x, double *iptr) +{ + union {double f; uint64_t i;} u = {x}; + uint64_t mask; + int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i<<12 != 0) /* nan */ + return x; + u.i &= 1ULL<<63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL<<63; + *iptr = u.f; + return x; + } + + mask = -1ULL>>12>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL<<63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/nearbyint.c b/src/openmv/src/micropython/lib/libm_dbl/nearbyint.c new file mode 100755 index 0000000..6e9b0c1 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/nearbyint.c @@ -0,0 +1,20 @@ +//#include +#include + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/pow.c b/src/openmv/src/micropython/lib/libm_dbl/pow.c new file mode 100755 index 0000000..3ddc1b6 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/pow.c @@ -0,0 +1,328 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + uint32_t lx,ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if ((iy|ly) == 0) + return 1.0; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3ff00000 && lx == 0) + return 1.0; + /* NaN if either arg is NaN */ + if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || + iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0)) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x43400000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3ff00000) { + k = (iy>>20) - 0x3ff; /* exponent */ + if (k > 20) { + uint32_t j = ly>>(52-k); + if ((j<<(52-k)) == ly) + yisint = 2 - (j&1); + } else if (ly == 0) { + uint32_t j = iy>>(20-k); + if ((j<<(20-k)) == iy) + yisint = 2 - (j&1); + } + } + } + + /* special value of y */ + if (ly == 0) { + if (iy == 0x7ff00000) { /* y is +-inf */ + if (((ix-0x3ff00000)|lx) == 0) /* (-1)**+-inf is 1 */ + return 1.0; + else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0 : -y; + } + if (iy == 0x3ff00000) { /* y is +-1 */ + if (hy >= 0) + return x; + y = 1/x; +#if FLT_EVAL_METHOD!=0 + { + union {double f; uint64_t i;} u = {y}; + uint64_t i = u.i & -1ULL/2; + if (i>>52 == 0 && (i&(i-1))) + FORCE_EVAL((float)y); + } +#endif + return y; + } + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3fe00000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if (lx == 0) { + if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0/z; + if (hx < 0) { + if (((ix-0x3ff00000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + s = 1.0; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + s = -1.0; + } + + /* |y| is huge */ + if (iy > 0x41e00000) { /* if |y| > 2**31 */ + if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ + if (ix <= 0x3fefffff) + return hy < 0 ? huge*huge : tiny*tiny; + if (ix >= 0x3ff00000) + return hy > 0 ? huge*huge : tiny*tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3fefffff) + return hy < 0 ? s*huge*huge : s*tiny*tiny; + if (ix > 0x3ff00000) + return hy > 0 ? s*huge*huge : s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.0; /* t has 20 trailing zeros */ + w = (t*t)*(0.5 - t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + SET_LOW_WORD(t1, 0); + t2 = v - (t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00100000) { + ax *= two53; + n -= 53; + GET_HIGH_WORD(ix,ax); + } + n += ((ix)>>20) - 0x3ff; + j = ix & 0x000fffff; + /* determine interval */ + ix = j | 0x3ff00000; /* normalize ix */ + if (j <= 0x3988E) /* |x|>1)|0x20000000) + 0x00080000 + (k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0 + s2 + r; + SET_LOW_WORD(t_h, 0); + t_l = r - ((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u + v; + SET_LOW_WORD(p_h, 0); + p_l = v - (p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp + dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = ((z_h + z_l) + dp_h[k]) + t; + SET_LOW_WORD(t1, 0); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1, 0); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + EXTRACT_WORDS(j, i, z); + if (j >= 0x40900000) { /* z >= 1024 */ + if (((j-0x40900000)|i) != 0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + if (p_l + ovt > z - p_h) + return s*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j + if (((j-0xc090cc00)|i) != 0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + if (p_l <= z - p_h) + return s*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>20) - 0x3ff; + n = 0; + if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20) - 0x3ff; /* new k for n */ + t = 0.0; + SET_HIGH_WORD(t, n & ~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + SET_LOW_WORD(t, 0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0) - (w + z*w); + z = 1.0 - (r-z); + GET_HIGH_WORD(j, z); + j += n<<20; + if ((j>>20) <= 0) /* subnormal output */ + z = scalbn(z,n); + else + SET_HIGH_WORD(z, j); + return s*z; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/rint.c b/src/openmv/src/micropython/lib/libm_dbl/rint.c new file mode 100755 index 0000000..fbba390 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/rint.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double rint(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + int s = u.i>>63; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0 : 0; + return y; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/scalbn.c b/src/openmv/src/micropython/lib/libm_dbl/scalbn.c new file mode 100755 index 0000000..182f561 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/scalbn.c @@ -0,0 +1,33 @@ +#include +#include + +double scalbn(double x, int n) +{ + union {double f; uint64_t i;} u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) { + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff+n)<<52; + x = y * u.f; + return x; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/sin.c b/src/openmv/src/micropython/lib/libm_dbl/sin.c new file mode 100755 index 0000000..055e215 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/sin.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cose function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double sin(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + /* High word of x. */ + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e500000) { /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction needed */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __sin(y[0], y[1], 1); + case 1: return __cos(y[0], y[1]); + case 2: return -__sin(y[0], y[1], 1); + default: + return -__cos(y[0], y[1]); + } +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/sinh.c b/src/openmv/src/micropython/lib/libm_dbl/sinh.c new file mode 100755 index 0000000..00022c4 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/sinh.c @@ -0,0 +1,39 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) + h = -h; + /* |x| */ + u.i &= (uint64_t)-1/2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26<<20)) + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h*(2*t - t*t/(t+1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h*(t + t/(t+1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2*h*__expo2(absx); + return t; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/sqrt.c b/src/openmv/src/micropython/lib/libm_dbl/sqrt.c new file mode 100755 index 0000000..b277567 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/sqrt.c @@ -0,0 +1,185 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + +#include "libm.h" + +static const double tiny = 1.0e-300; + +double sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + uint32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0, ix1, x); + + /* take care of Inf and NaN */ + if ((ix0&0x7ff00000) == 0x7ff00000) { + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix0 <= 0) { + if (((ix0&~sign)|ix1) == 0) + return x; /* sqrt(+-0) = +-0 */ + if (ix0 < 0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix0>>20; + if (m == 0) { /* subnormal x */ + while (ix0 == 0) { + m -= 21; + ix0 |= (ix1>>11); + ix1 <<= 21; + } + for (i=0; (ix0&0x00100000) == 0; i++) + ix0<<=1; + m -= i - 1; + ix0 |= ix1>>(32-i); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m & 1) { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s0 + r; + if (t <= ix0) { + s0 = t + r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + r = sign; + while (r != 0) { + t1 = s1 + r; + t = s0; + if (t < ix0 || (t == ix0 && t1 <= ix1)) { + s1 = t1 + r; + if ((t1&sign) == sign && (s1&sign) == 0) + s0++; + ix0 -= t; + if (ix1 < t1) + ix0--; + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ((ix0|ix1) != 0) { + z = 1.0 - tiny; /* raise inexact flag */ + if (z >= 1.0) { + z = 1.0 + tiny; + if (q1 == (uint32_t)0xffffffff) { + q1 = 0; + q++; + } else if (z > 1.0) { + if (q1 == (uint32_t)0xfffffffe) + q++; + q1 += 2; + } else + q1 += q1 & 1; + } + } + ix0 = (q>>1) + 0x3fe00000; + ix1 = q1>>1; + if (q&1) + ix1 |= sign; + ix0 += m << 20; + INSERT_WORDS(z, ix0, ix1); + return z; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/tan.c b/src/openmv/src/micropython/lib/libm_dbl/tan.c new file mode 100755 index 0000000..9c724a4 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/tan.c @@ -0,0 +1,70 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __tan ... tangent function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double tan(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e400000) { /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction */ + n = __rem_pio2(x, y); + return __tan(y[0], y[1], n&1); +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/tanh.c b/src/openmv/src/micropython/lib/libm_dbl/tanh.c new file mode 100755 index 0000000..6bdb7c3 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/tanh.c @@ -0,0 +1,12 @@ +#include + +double tanh(double x) { + int sign = 0; + if (x < 0) { + sign = 1; + x = -x; + } + x = expm1(-2 * x); + x = x / (x + 2); + return sign ? x : -x; +} diff --git a/src/openmv/src/micropython/lib/libm_dbl/tgamma.c b/src/openmv/src/micropython/lib/libm_dbl/tgamma.c new file mode 100755 index 0000000..d1d0a04 --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/tgamma.c @@ -0,0 +1,222 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sinpi(double x) +{ + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n+1)/2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + return __sin(-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +//static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N+1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N+1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, + 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, + 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) +{ + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num/den; +} + +double tgamma(double x) +{ + union {double f; uint64_t i;} u = {x}; + double absx, y; + double_t dy, z, r; + uint32_t ix = u.i>>32 & 0x7fffffff; + int sign = u.i>>63; + + /* special cases */ + if (ix >= 0x7ff00000) + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + if (ix < (0x3ff-54)<<20) + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1/x; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (sign) + return 0/0.0; + if (x <= sizeof fact/sizeof *fact) + return fact[(int)x - 1]; + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (ix >= 0x40670000) { /* |x| >= 184 */ + if (sign) { + FORCE_EVAL((float)(0x1p-126/x)); + if (floor(x) * 0.5 == floor(x * 0.5)) + return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + absx = sign ? -x : x; + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} + +#if 1 +double __lgamma_r(double x, int *sign) +{ + double r, absx; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +//weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/src/openmv/src/micropython/lib/libm_dbl/trunc.c b/src/openmv/src/micropython/lib/libm_dbl/trunc.c new file mode 100755 index 0000000..d13711b --- /dev/null +++ b/src/openmv/src/micropython/lib/libm_dbl/trunc.c @@ -0,0 +1,19 @@ +#include "libm.h" + +double trunc(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) + return x; + if (e < 12) + e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/src/openmv/src/micropython/lib/memzip/README.md b/src/openmv/src/micropython/lib/memzip/README.md new file mode 100755 index 0000000..287d0fc --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/README.md @@ -0,0 +1,28 @@ +MEMZIP - a simple readonly file system + +memzip takes a zip file which is comprised of uncompressed files and +and presents it as a filesystem, allowing Python files to be imported. + +The script make-memzip.py takes a directory name and will create a zip file +containing uncompressed files found in the directory. It will then generate +a C file which contains the data from the zip file. + +A typical addition to a makefile would look like: +``` +SRC_C += \ + lib/memzip/import.c \ + lib/memzip/lexermemzip.c \ + lib/memzip/memzip.c \ + +OBJ += $(BUILD)/memzip-files.o + +MAKE_MEMZIP = ../lib/memzip/make-memzip.py + +$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c + $(call compile_c) + +$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f) + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR) +``` + diff --git a/src/openmv/src/micropython/lib/memzip/import.c b/src/openmv/src/micropython/lib/memzip/import.c new file mode 100755 index 0000000..2d5225b --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/import.c @@ -0,0 +1,17 @@ +#include + +#include "py/lexer.h" +#include "memzip.h" + +mp_import_stat_t mp_import_stat(const char *path) { + MEMZIP_FILE_INFO info; + + if (memzip_stat(path, &info) != MZ_OK) { + return MP_IMPORT_STAT_NO_EXIST; + } + + if (info.is_dir) { + return MP_IMPORT_STAT_DIR; + } + return MP_IMPORT_STAT_FILE; +} diff --git a/src/openmv/src/micropython/lib/memzip/lexermemzip.c b/src/openmv/src/micropython/lib/memzip/lexermemzip.c new file mode 100755 index 0000000..6b26961 --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/lexermemzip.c @@ -0,0 +1,19 @@ +#include + +#include "py/lexer.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "memzip.h" + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) +{ + void *data; + size_t len; + + if (memzip_locate(filename, &data, &len) != MZ_OK) { + mp_raise_OSError(MP_ENOENT); + } + + return mp_lexer_new_from_str_len(qstr_from_str(filename), (const char *)data, (mp_uint_t)len, 0); +} + diff --git a/src/openmv/src/micropython/lib/memzip/make-memzip.py b/src/openmv/src/micropython/lib/memzip/make-memzip.py new file mode 100755 index 0000000..9730f5e --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/make-memzip.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# Takes a directory of files and zips them up (as uncompressed files). +# This then gets converted into a C data structure which can be read +# like a filesystem at runtime. +# +# This is somewhat like frozen modules in python, but allows arbitrary files +# to be used. + +from __future__ import print_function + +import argparse +import os +import subprocess +import sys +import types + +def create_zip(zip_filename, zip_dir): + abs_zip_filename = os.path.abspath(zip_filename) + save_cwd = os.getcwd() + os.chdir(zip_dir) + if os.path.exists(abs_zip_filename): + os.remove(abs_zip_filename) + subprocess.check_call(['zip', '-0', '-r', '-D', abs_zip_filename, '.']) + os.chdir(save_cwd) + +def create_c_from_file(c_filename, zip_filename): + with open(zip_filename, 'rb') as zip_file: + with open(c_filename, 'wb') as c_file: + print('#include ', file=c_file) + print('', file=c_file) + print('const uint8_t memzip_data[] = {', file=c_file) + while True: + buf = zip_file.read(16) + if not buf: + break + print(' ', end='', file=c_file) + for byte in buf: + if type(byte) is types.StringType: + print(' 0x{:02x},'.format(ord(byte)), end='', file=c_file) + else: + print(' 0x{:02x},'.format(byte), end='', file=c_file) + print('', file=c_file) + print('};', file=c_file) + +def main(): + parser = argparse.ArgumentParser( + prog='make-memzip.py', + usage='%(prog)s [options] [command]', + description='Generates a C source memzip file.' + ) + parser.add_argument( + '-z', '--zip-file', + dest='zip_filename', + help='Specifies the name of the created zip file.', + default='memzip_files.zip' + ) + parser.add_argument( + '-c', '--c-file', + dest='c_filename', + help='Specifies the name of the created C source file.', + default='memzip_files.c' + ) + parser.add_argument( + dest='source_dir', + default='memzip_files' + ) + args = parser.parse_args(sys.argv[1:]) + + print('args.zip_filename =', args.zip_filename) + print('args.c_filename =', args.c_filename) + print('args.source_dir =', args.source_dir) + + create_zip(args.zip_filename, args.source_dir) + create_c_from_file(args.c_filename, args.zip_filename) + +if __name__ == "__main__": + main() + diff --git a/src/openmv/src/micropython/lib/memzip/memzip.c b/src/openmv/src/micropython/lib/memzip/memzip.c new file mode 100755 index 0000000..3fbea8e --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/memzip.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include "py/mpconfig.h" +#include "py/misc.h" +#include "memzip.h" + +extern uint8_t memzip_data[]; + +const MEMZIP_FILE_HDR *memzip_find_file_header(const char *filename) { + + const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)memzip_data; + uint8_t *mem_data; + + /* Zip file filenames don't have a leading /, so we strip it off */ + + if (*filename == '/') { + filename++; + } + while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) { + const char *file_hdr_filename = (const char *)&file_hdr[1]; + mem_data = (uint8_t *)file_hdr_filename; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; + if (!strncmp(file_hdr_filename, filename, file_hdr->filename_len)) { + /* We found a match */ + return file_hdr; + } + mem_data += file_hdr->uncompressed_size; + file_hdr = (const MEMZIP_FILE_HDR *)mem_data; + } + return NULL; +} + +bool memzip_is_dir(const char *filename) { + const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)memzip_data; + uint8_t *mem_data; + + if (strcmp(filename, "/") == 0) { + // The root directory is a directory. + return true; + } + + // Zip filenames don't have a leading /, so we strip it off + if (*filename == '/') { + filename++; + } + size_t filename_len = strlen(filename); + + while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) { + const char *file_hdr_filename = (const char *)&file_hdr[1]; + if (filename_len < file_hdr->filename_len && + strncmp(file_hdr_filename, filename, filename_len) == 0 && + file_hdr_filename[filename_len] == '/') { + return true; + } + + mem_data = (uint8_t *)file_hdr_filename; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; + mem_data += file_hdr->uncompressed_size; + file_hdr = (const MEMZIP_FILE_HDR *)mem_data; + } + return NULL; + +} + +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) +{ + const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(filename); + if (file_hdr == NULL) { + return MZ_NO_FILE; + } + if (file_hdr->compression_method != 0) { + return MZ_FILE_COMPRESSED; + } + + uint8_t *mem_data; + mem_data = (uint8_t *)&file_hdr[1]; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; + + *data = mem_data; + *len = file_hdr->uncompressed_size; + return MZ_OK; +} + +MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info) { + const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(path); + if (file_hdr == NULL) { + if (memzip_is_dir(path)) { + info->file_size = 0; + info->last_mod_date = 0; + info->last_mod_time = 0; + info->is_dir = 1; + return MZ_OK; + } + return MZ_NO_FILE; + } + info->file_size = file_hdr->uncompressed_size; + info->last_mod_date = file_hdr->last_mod_date; + info->last_mod_time = file_hdr->last_mod_time; + info->is_dir = 0; + + return MZ_OK; +} diff --git a/src/openmv/src/micropython/lib/memzip/memzip.h b/src/openmv/src/micropython/lib/memzip/memzip.h new file mode 100755 index 0000000..667e2df --- /dev/null +++ b/src/openmv/src/micropython/lib/memzip/memzip.h @@ -0,0 +1,83 @@ +#pragma pack(push, 1) + +#define MEMZIP_FILE_HEADER_SIGNATURE 0x04034b50 +typedef struct +{ + uint32_t signature; + uint16_t version; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; + + /* char filename[filename_len] */ + /* uint8_t extra[extra_len] */ + +} MEMZIP_FILE_HDR; + +#define MEMZIP_CENTRAL_DIRECTORY_SIGNATURE 0x02014b50 +typedef struct +{ + uint32_t signature; + uint16_t version_made_by; + uint16_t version_read_with; + uint16_t flags; + uint16_t compression_method; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_len; + uint16_t extra_len; + uint16_t disk_num; + uint16_t internal_file_attributes; + uint32_t external_file_attributes; + uint32_t file_header_offset; + + /* char filename[filename_len] */ + /* uint8_t extra[extra_len] */ + +} MEMZIP_CENTRAL_DIRECTORY_HDR; + +#define MEMZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE 0x06054b50 +typedef struct +{ + uint32_t signature; + uint16_t disk_num; + uint16_t central_directory_disk; + uint16_t num_central_directories_this_disk; + uint16_t total_central_directories; + uint32_t central_directory_size; + uint32_t central_directory_offset; + uint16_t comment_len; + + /* char comment[comment_len] */ + +} MEMZIP_END_OF_CENTRAL_DIRECTORY; + +#pragma pack(pop) + +typedef enum { + MZ_OK = 0, /* (0) Succeeded */ + MZ_NO_FILE, /* (1) Could not find the file. */ + MZ_FILE_COMPRESSED, /* (2) File is compressed (expecting uncompressed) */ + +} MEMZIP_RESULT; + +typedef struct { + uint32_t file_size; + uint16_t last_mod_date; + uint16_t last_mod_time; + uint8_t is_dir; + +} MEMZIP_FILE_INFO; + +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len); + +MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info); diff --git a/src/openmv/src/micropython/lib/mp-readline/readline.c b/src/openmv/src/micropython/lib/mp-readline/readline.c new file mode 100755 index 0000000..9d254d8 --- /dev/null +++ b/src/openmv/src/micropython/lib/mp-readline/readline.c @@ -0,0 +1,447 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpstate.h" +#include "py/repl.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" + +#if 0 // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +#define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist))) + +enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; + +void readline_init0(void) { + memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*)); +} + +STATIC char *str_dup_maybe(const char *str) { + uint32_t len = strlen(str); + char *s2 = m_new_maybe(char, len + 1); + if (s2 == NULL) { + return NULL; + } + memcpy(s2, str, len + 1); + return s2; +} + +// By default assume terminal which implements VT100 commands... +#ifndef MICROPY_HAL_HAS_VT100 +#define MICROPY_HAL_HAS_VT100 (1) +#endif + +// ...and provide the implementation using them +#if MICROPY_HAL_HAS_VT100 +STATIC void mp_hal_move_cursor_back(uint pos) { + if (pos <= 4) { + // fast path for most common case of 1 step back + mp_hal_stdout_tx_strn("\b\b\b\b", pos); + } else { + char vt100_command[6]; + // snprintf needs space for the terminating null character + int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos); + if (n > 0) { + vt100_command[n] = 'D'; // replace null char + mp_hal_stdout_tx_strn(vt100_command, n + 1); + } + } +} + +STATIC void mp_hal_erase_line_from_cursor(uint n_chars_to_erase) { + (void)n_chars_to_erase; + mp_hal_stdout_tx_strn("\x1b[K", 3); +} +#endif + +typedef struct _readline_t { + vstr_t *line; + size_t orig_line_len; + int escape_seq; + int hist_cur; + size_t cursor_pos; + char escape_seq_buf[1]; + const char *prompt; +} readline_t; + +STATIC readline_t rl; + +int readline_process_char(int c) { + size_t last_line_len = rl.line->len; + int redraw_step_back = 0; + bool redraw_from_cursor = false; + int redraw_step_forward = 0; + if (rl.escape_seq == ESEQ_NONE) { + if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_E && vstr_len(rl.line) == rl.orig_line_len) { + // control character with empty line + return c; + } else if (c == CHAR_CTRL_A) { + // CTRL-A with non-empty line is go-to-start-of-line + goto home_key; + #if MICROPY_REPL_EMACS_KEYS + } else if (c == CHAR_CTRL_B) { + // CTRL-B with non-empty line is go-back-one-char + goto left_arrow_key; + #endif + } else if (c == CHAR_CTRL_C) { + // CTRL-C with non-empty line is cancel + return c; + #if MICROPY_REPL_EMACS_KEYS + } else if (c == CHAR_CTRL_D) { + // CTRL-D with non-empty line is delete-at-cursor + goto delete_key; + #endif + } else if (c == CHAR_CTRL_E) { + // CTRL-E is go-to-end-of-line + goto end_key; + #if MICROPY_REPL_EMACS_KEYS + } else if (c == CHAR_CTRL_F) { + // CTRL-F with non-empty line is go-forward-one-char + goto right_arrow_key; + } else if (c == CHAR_CTRL_K) { + // CTRL-K is kill from cursor to end-of-line, inclusive + vstr_cut_tail_bytes(rl.line, last_line_len - rl.cursor_pos); + // set redraw parameters + redraw_from_cursor = true; + } else if (c == CHAR_CTRL_N) { + // CTRL-N is go to next line in history + goto down_arrow_key; + } else if (c == CHAR_CTRL_P) { + // CTRL-P is go to previous line in history + goto up_arrow_key; + } else if (c == CHAR_CTRL_U) { + // CTRL-U is kill from beginning-of-line up to cursor + vstr_cut_out_bytes(rl.line, rl.orig_line_len, rl.cursor_pos - rl.orig_line_len); + // set redraw parameters + redraw_step_back = rl.cursor_pos - rl.orig_line_len; + redraw_from_cursor = true; + #endif + } else if (c == '\r') { + // newline + mp_hal_stdout_tx_str("\r\n"); + readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len); + return 0; + } else if (c == 27) { + // escape sequence + rl.escape_seq = ESEQ_ESC; + } else if (c == 8 || c == 127) { + // backspace/delete + if (rl.cursor_pos > rl.orig_line_len) { + // work out how many chars to backspace + #if MICROPY_REPL_AUTO_INDENT + int nspace = 0; + for (size_t i = rl.orig_line_len; i < rl.cursor_pos; i++) { + if (rl.line->buf[i] != ' ') { + nspace = 0; + break; + } + nspace += 1; + } + if (nspace < 4) { + nspace = 1; + } else { + nspace = 4; + } + #else + int nspace = 1; + #endif + + // do the backspace + vstr_cut_out_bytes(rl.line, rl.cursor_pos - nspace, nspace); + // set redraw parameters + redraw_step_back = nspace; + redraw_from_cursor = true; + } + #if MICROPY_HELPER_REPL + } else if (c == 9) { + // tab magic + const char *compl_str; + size_t compl_len = mp_repl_autocomplete(rl.line->buf + rl.orig_line_len, rl.cursor_pos - rl.orig_line_len, &mp_plat_print, &compl_str); + if (compl_len == 0) { + // no match + } else if (compl_len == (size_t)(-1)) { + // many matches + mp_hal_stdout_tx_str(rl.prompt); + mp_hal_stdout_tx_strn(rl.line->buf + rl.orig_line_len, rl.cursor_pos - rl.orig_line_len); + redraw_from_cursor = true; + } else { + // one match + for (size_t i = 0; i < compl_len; ++i) { + vstr_ins_byte(rl.line, rl.cursor_pos + i, *compl_str++); + } + // set redraw parameters + redraw_from_cursor = true; + redraw_step_forward = compl_len; + } + #endif + } else if (32 <= c && c <= 126) { + // printable character + vstr_ins_char(rl.line, rl.cursor_pos, c); + // set redraw parameters + redraw_from_cursor = true; + redraw_step_forward = 1; + } + } else if (rl.escape_seq == ESEQ_ESC) { + switch (c) { + case '[': + rl.escape_seq = ESEQ_ESC_BRACKET; + break; + case 'O': + rl.escape_seq = ESEQ_ESC_O; + break; + default: + DEBUG_printf("(ESC %d)", c); + rl.escape_seq = ESEQ_NONE; + } + } else if (rl.escape_seq == ESEQ_ESC_BRACKET) { + if ('0' <= c && c <= '9') { + rl.escape_seq = ESEQ_ESC_BRACKET_DIGIT; + rl.escape_seq_buf[0] = c; + } else { + rl.escape_seq = ESEQ_NONE; + if (c == 'A') { +#if MICROPY_REPL_EMACS_KEYS +up_arrow_key: +#endif + // up arrow + if (rl.hist_cur + 1 < (int)READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[rl.hist_cur + 1] != NULL) { + // increase hist num + rl.hist_cur += 1; + // set line to history + rl.line->len = rl.orig_line_len; + vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]); + // set redraw parameters + redraw_step_back = rl.cursor_pos - rl.orig_line_len; + redraw_from_cursor = true; + redraw_step_forward = rl.line->len - rl.orig_line_len; + } + } else if (c == 'B') { +#if MICROPY_REPL_EMACS_KEYS +down_arrow_key: +#endif + // down arrow + if (rl.hist_cur >= 0) { + // decrease hist num + rl.hist_cur -= 1; + // set line to history + vstr_cut_tail_bytes(rl.line, rl.line->len - rl.orig_line_len); + if (rl.hist_cur >= 0) { + vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]); + } + // set redraw parameters + redraw_step_back = rl.cursor_pos - rl.orig_line_len; + redraw_from_cursor = true; + redraw_step_forward = rl.line->len - rl.orig_line_len; + } + } else if (c == 'C') { +#if MICROPY_REPL_EMACS_KEYS +right_arrow_key: +#endif + // right arrow + if (rl.cursor_pos < rl.line->len) { + redraw_step_forward = 1; + } + } else if (c == 'D') { +#if MICROPY_REPL_EMACS_KEYS +left_arrow_key: +#endif + // left arrow + if (rl.cursor_pos > rl.orig_line_len) { + redraw_step_back = 1; + } + } else if (c == 'H') { + // home + goto home_key; + } else if (c == 'F') { + // end + goto end_key; + } else { + DEBUG_printf("(ESC [ %d)", c); + } + } + } else if (rl.escape_seq == ESEQ_ESC_BRACKET_DIGIT) { + if (c == '~') { + if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') { +home_key: + redraw_step_back = rl.cursor_pos - rl.orig_line_len; + } else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') { +end_key: + redraw_step_forward = rl.line->len - rl.cursor_pos; + } else if (rl.escape_seq_buf[0] == '3') { + // delete +#if MICROPY_REPL_EMACS_KEYS +delete_key: +#endif + if (rl.cursor_pos < rl.line->len) { + vstr_cut_out_bytes(rl.line, rl.cursor_pos, 1); + redraw_from_cursor = true; + } + } else { + DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); + } + } else { + DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); + } + rl.escape_seq = ESEQ_NONE; + } else if (rl.escape_seq == ESEQ_ESC_O) { + switch (c) { + case 'H': + goto home_key; + case 'F': + goto end_key; + default: + DEBUG_printf("(ESC O %d)", c); + rl.escape_seq = ESEQ_NONE; + } + } else { + rl.escape_seq = ESEQ_NONE; + } + + // redraw command prompt, efficiently + if (redraw_step_back > 0) { + mp_hal_move_cursor_back(redraw_step_back); + rl.cursor_pos -= redraw_step_back; + } + if (redraw_from_cursor) { + if (rl.line->len < last_line_len) { + // erase old chars + mp_hal_erase_line_from_cursor(last_line_len - rl.cursor_pos); + } + // draw new chars + mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, rl.line->len - rl.cursor_pos); + // move cursor forward if needed (already moved forward by length of line, so move it back) + mp_hal_move_cursor_back(rl.line->len - (rl.cursor_pos + redraw_step_forward)); + rl.cursor_pos += redraw_step_forward; + } else if (redraw_step_forward > 0) { + // draw over old chars to move cursor forwards + mp_hal_stdout_tx_strn(rl.line->buf + rl.cursor_pos, redraw_step_forward); + rl.cursor_pos += redraw_step_forward; + } + + return -1; +} + +#if MICROPY_REPL_AUTO_INDENT +STATIC void readline_auto_indent(void) { + vstr_t *line = rl.line; + if (line->len > 1 && line->buf[line->len - 1] == '\n') { + int i; + for (i = line->len - 1; i > 0; i--) { + if (line->buf[i - 1] == '\n') { + break; + } + } + size_t j; + for (j = i; j < line->len; j++) { + if (line->buf[j] != ' ') { + break; + } + } + // i=start of line; j=first non-space + if (i > 0 && j + 1 == line->len) { + // previous line is not first line and is all spaces + for (size_t k = i - 1; k > 0; --k) { + if (line->buf[k - 1] == '\n') { + // don't auto-indent if last 2 lines are all spaces + return; + } else if (line->buf[k - 1] != ' ') { + // 2nd previous line is not all spaces + break; + } + } + } + int n = (j - i) / 4; + if (line->buf[line->len - 2] == ':') { + n += 1; + } + while (n-- > 0) { + vstr_add_strn(line, " ", 4); + mp_hal_stdout_tx_strn(" ", 4); + rl.cursor_pos += 4; + } + } +} +#endif + +void readline_note_newline(const char *prompt) { + rl.orig_line_len = rl.line->len; + rl.cursor_pos = rl.orig_line_len; + rl.prompt = prompt; + mp_hal_stdout_tx_str(prompt); + #if MICROPY_REPL_AUTO_INDENT + readline_auto_indent(); + #endif +} + +void readline_init(vstr_t *line, const char *prompt) { + rl.line = line; + rl.orig_line_len = line->len; + rl.escape_seq = ESEQ_NONE; + rl.escape_seq_buf[0] = 0; + rl.hist_cur = -1; + rl.cursor_pos = rl.orig_line_len; + rl.prompt = prompt; + mp_hal_stdout_tx_str(prompt); + #if MICROPY_REPL_AUTO_INDENT + readline_auto_indent(); + #endif +} + +int readline(vstr_t *line, const char *prompt) { + readline_init(line, prompt); + for (;;) { + int c = mp_hal_stdin_rx_chr(); + int r = readline_process_char(c); + if (r >= 0) { + return r; + } + } +} + +void readline_push_history(const char *line) { + if (line[0] != '\0' + && (MP_STATE_PORT(readline_hist)[0] == NULL + || strcmp(MP_STATE_PORT(readline_hist)[0], line) != 0)) { + // a line which is not empty and different from the last one + // so update the history + char *most_recent_hist = str_dup_maybe(line); + if (most_recent_hist != NULL) { + for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) { + MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1]; + } + MP_STATE_PORT(readline_hist)[0] = most_recent_hist; + } + } +} diff --git a/src/openmv/src/micropython/lib/mp-readline/readline.h b/src/openmv/src/micropython/lib/mp-readline/readline.h new file mode 100755 index 0000000..00aa962 --- /dev/null +++ b/src/openmv/src/micropython/lib/mp-readline/readline.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H +#define MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H + +#define CHAR_CTRL_A (1) +#define CHAR_CTRL_B (2) +#define CHAR_CTRL_C (3) +#define CHAR_CTRL_D (4) +#define CHAR_CTRL_E (5) +#define CHAR_CTRL_F (6) +#define CHAR_CTRL_K (11) +#define CHAR_CTRL_N (14) +#define CHAR_CTRL_P (16) +#define CHAR_CTRL_U (21) + +void readline_init0(void); +int readline(vstr_t *line, const char *prompt); +void readline_push_history(const char *line); + +void readline_init(vstr_t *line, const char *prompt); +void readline_note_newline(const char *prompt); +int readline_process_char(int c); + +#endif // MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H diff --git a/src/openmv/src/micropython/lib/netutils/netutils.c b/src/openmv/src/micropython/lib/netutils/netutils.c new file mode 100755 index 0000000..073f46b --- /dev/null +++ b/src/openmv/src/micropython/lib/netutils/netutils.c @@ -0,0 +1,94 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "lib/netutils/netutils.h" + +// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. +mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { + char ip_str[16]; + mp_uint_t ip_len; + if (endian == NETUTILS_LITTLE) { + ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[3], ip[2], ip[1], ip[0]); + } else { + ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + } + return mp_obj_new_str(ip_str, ip_len); +} + +// Takes an array with a raw IP address, and a port, and returns a net-address +// tuple such as ('192.168.0.1', 8080). +mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian) { + mp_obj_t tuple[2] = { + tuple[0] = netutils_format_ipv4_addr(ip, endian), + tuple[1] = mp_obj_new_int(port), + }; + return mp_obj_new_tuple(2, tuple); +} + +void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { + size_t addr_len; + const char *addr_str = mp_obj_str_get_data(addr_in, &addr_len); + if (addr_len == 0) { + // special case of no address given + memset(out_ip, 0, NETUTILS_IPV4ADDR_BUFSIZE); + return; + } + const char *s = addr_str; + const char *s_top = addr_str + addr_len; + for (mp_uint_t i = 3 ; ; i--) { + mp_uint_t val = 0; + for (; s < s_top && *s != '.'; s++) { + val = val * 10 + *s - '0'; + } + if (endian == NETUTILS_LITTLE) { + out_ip[i] = val; + } else { + out_ip[NETUTILS_IPV4ADDR_BUFSIZE - 1 - i] = val; + } + if (i == 0 && s == s_top) { + return; + } else if (i > 0 && s < s_top && *s == '.') { + s++; + } else { + mp_raise_ValueError("invalid arguments"); + } + } +} + +// Takes an address of the form ('192.168.0.1', 8080), returns the port and +// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). +mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); + netutils_parse_ipv4_addr(addr_items[0], out_ip, endian); + return mp_obj_get_int(addr_items[1]); +} diff --git a/src/openmv/src/micropython/lib/netutils/netutils.h b/src/openmv/src/micropython/lib/netutils/netutils.h new file mode 100755 index 0000000..4befc90 --- /dev/null +++ b/src/openmv/src/micropython/lib/netutils/netutils.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H +#define MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H + +#define NETUTILS_IPV4ADDR_BUFSIZE 4 + +typedef enum _netutils_endian_t { + NETUTILS_LITTLE, + NETUTILS_BIG, +} netutils_endian_t; + +// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. +mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian); + +// Takes an array with a raw IP address, and a port, and returns a net-address +// tuple such as ('192.168.0.1', 8080). +mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian); + +void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); + +// Takes an address of the form ('192.168.0.1', 8080), returns the port and +// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). +mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H diff --git a/src/openmv/src/micropython/lib/oofatfs/diskio.h b/src/openmv/src/micropython/lib/oofatfs/diskio.h new file mode 100755 index 0000000..8deb68e --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/diskio.h @@ -0,0 +1,83 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + +/*-----------------------------------------------------------------------/ +/ Low level disk interface modlue include file (C)ChaN, 2014 / +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (Used by FatFs) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define IOCTL_INIT 5 +#define IOCTL_STATUS 6 + +/* Generic command (Not used by FatFs) */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ +#define ISDIO_READ 55 /* Read data form SD iSDIO register */ +#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ +#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/openmv/src/micropython/lib/oofatfs/ff.c b/src/openmv/src/micropython/lib/oofatfs/ff.c new file mode 100755 index 0000000..2c4b13f --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/ff.c @@ -0,0 +1,5597 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12b / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2016, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +#include + +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of device I/O functions */ + +// DIR has been renamed FF_DIR in the public API so it doesn't clash with POSIX +#define DIR FF_DIR + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if _FATFS != 68020 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if _FS_NORTC == 1 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#error Invalid _FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if _FS_LOCK != 0 +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, directory (0:root) */ + DWORD ofs; /* Object ID 3, directory offset */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + + +/* DBCS code ranges and SBCS upper conversion tables */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 771 /* KBL */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Latin 1 */ +#define _DF1S 0 +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 860 /* Portuguese */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 861 /* Icelandic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 863 /* Canadian-French */ +#define _DF1S 0 +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 864 /* Arabic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 865 /* Nordic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 869 /* Greek 2 */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#if _USE_LFN != 0 +#error Cannot enable LFN without valid code page. +#endif +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + +/* Character code support macros */ +#define IsUpper(c) (((c)>='A')&&((c)<='Z')) +#define IsLower(c) (((c)>='a')&&((c)<='z')) +#define IsDigit(c) (((c)>='0')&&((c)<='9')) + +#if _DF1S != 0 /* Code page is DBCS */ + +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#endif + +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#endif + +#else /* Code page is SBCS */ + +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 + +#endif /* _DF1S */ + + +/* File attribute bits (internal use) */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* File access control and file status flags (internal use) */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + +/* Name status flags */ +#define NSFLAG 11 /* Index of name status byte in fn[] */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ +#define NS_NOLFN 0x40 /* Do not find LFN */ +#define NS_NONAME 0x80 /* Not followed */ + + +/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */ +#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */ +#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */ +#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */ +#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */ +#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ + + +/* FatFs refers the members in the FAT structures as byte array instead of +/ structure members because the structure is not binary compatible between +/ different platforms */ + +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ + +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ +#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ +#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN type (BYTE) */ +#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */ +#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ +#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* File attribute (WORD) */ +#define XDIR_CrtTime 8 /* Created time (DWORD) */ +#define XDIR_ModTime 12 /* Modified time (DWORD) */ +#define XDIR_AccTime 16 /* Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */ +#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ + + + + + +/*-------------------------------------------------------------------------- + + Module Private Work Area + +---------------------------------------------------------------------------*/ + +/* Remark: Variables here without initial value shall be guaranteed zero/null +/ at start-up. If not, either the linker or start-up routine being used is +/ not compliance with C standard. */ + +#if _VOLUMES < 1 || _VOLUMES > 9 +#error Wrong _VOLUMES setting +#endif +static WORD Fsid; /* File system mount ID */ + +#if _FS_LOCK != 0 +static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#endif + +#if _USE_LFN == 0 /* Non-LFN configuration */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() +#else +#if _MAX_LFN < 12 || _MAX_LFN > 255 +#error Wrong _MAX_LFN setting +#endif + +#if _USE_LFN == 1 /* LFN enabled with static working buffer */ +#if _FS_EXFAT +static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +#endif +static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() + +#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMBUF() +#else +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMBUF() +#endif + +#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#else +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#endif + +#else +#error Wrong _USE_LFN setting +#endif +#endif + +#ifdef _EXCVT +static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ +#endif + + + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static +WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static +DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if _FS_EXFAT +static +QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !_FS_READONLY +static +void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static +void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if _FS_EXFAT +static +void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !_FS_READONLY */ + + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +// These were originally provided by the FatFs library but we use externally +// provided versions from C stdlib to (hopefully) reduce code size and use +// more efficient versions. +#define mem_cpy memcpy +#define mem_set memset +#define mem_cmp memcmp + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ + while (*str && *str != chr) str++; + return *str; +} + + + + +#if _FS_REENTRANT +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +static +int lock_fs ( + FATFS* fs /* File system object */ +) +{ + return ff_req_grant(fs->sobj); +} + + +static +void unlock_fs ( + FATFS* fs, /* File system object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} + +#endif + + + +#if _FS_LOCK != 0 +/*-----------------------------------------------------------------------*/ +/* File lock control functions */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == _FS_LOCK) { /* The object is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + } + + /* The object has been opened. Reject any open against writing file and all write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + return (i == _FS_LOCK) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ + DIR* dp, /* Directory object pointing the file to register or increment */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i; + + + for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->obj.fs && + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } + + if (i == _FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; +} + + +static +FRESULT dec_lock ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + WORD n; + FRESULT res; + + + if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n > 0) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} + +#endif /* _FS_LOCK != 0 */ + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the file system object */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs /* File system object */ +) +{ + DWORD wsect; + UINT nf; + FRESULT res = FR_OK; + + + if (fs->wflag) { /* Write back the sector if it is dirty */ + wsect = fs->winsect; /* Current sector number */ + if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fs->wflag = 0; + if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ + for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } + } + return res; +} +#endif + + +static +FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) +{ + FRESULT res = FR_OK; + + + if (sector != fs->winsect) { /* Window offset changed? */ +#if !_FS_READONLY + res = sync_window(fs); /* Write-back changes */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { + sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + res = FR_DISK_ERR; + } + fs->winsect = sector; + } + } + return res; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize file system and strage device */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ + FATFS* fs /* File system object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + /* Update FSInfo sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + /* Create FSInfo structure */ + mem_set(fs->win, 0, SS(fs)); + st_word(fs->win + BS_55AA, 0xAA55); + st_dword(fs->win + FSI_LeadSig, 0x41615252); + st_dword(fs->win + FSI_StrucSig, 0x61417272); + st_dword(fs->win + FSI_Free_Count, fs->free_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); + /* Write it into the FSInfo sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->drv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + /*if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)*/ res = FR_DISK_ERR; + } + + return res; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ +) +{ + UINT wc, bc; + DWORD val; + FATFS *fs = obj->fs; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ + val = 1; /* Internal error */ + + } else { + val = 0xFFFFFFFF; /* Default value falls on disk error */ + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc = fs->win[bc++ % SS(fs)]; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc |= fs->win[bc % SS(fs)] << 8; + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); + break; + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; + val = ld_word(fs->win + clst * 2 % SS(fs)); + break; + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; + break; +#if _FS_EXFAT + case FS_EXFAT : + if (obj->objsize) { + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + + if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ + if (cofs <= clen) { + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ + break; + } + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + break; + } + } + /* go next */ +#endif + default: + val = 1; /* Internal error */ + } + } + + return val; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding file system object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ +) +{ + UINT bc; + BYTE *p; + FRESULT res = FR_INT_ERR; + + + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ + switch (fs->fs_type) { + case FS_FAT12 : /* Bitfield items */ + bc = (UINT)clst; bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc++ % SS(fs); + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc % SS(fs); + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + fs->wflag = 1; + break; + + case FS_FAT16 : /* WORD aligned items */ + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); + fs->wflag = 1; + break; + + case FS_FAT32 : /* DWORD aligned items */ +#if _FS_EXFAT + case FS_EXFAT : +#endif + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); + fs->wflag = 1; + break; + } + } + return res; +} + +#endif /* !_FS_READONLY */ + + + + +#if _FS_EXFAT && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* exFAT: Accessing FAT and Allocation Bitmap */ +/*-----------------------------------------------------------------------*/ + +/*---------------------------------------------*/ +/* exFAT: Find a contiguous free cluster block */ +/*---------------------------------------------*/ + +static +DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + i = val / 8 % SS(fs); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = 4096; + } + if (!bv) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check run length */ + } else { + scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm); + bm = 1; + } while (++i < SS(fs)); + } +} + + +/*------------------------------------*/ +/* exFAT: Set/Clear a block of bitmap */ +/*------------------------------------*/ + +static +FRESULT change_bitmap ( + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + DWORD sect; + + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + i = 0; + } +} + + +/*---------------------------------------------*/ +/* Complement contiguous part of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_fat_chain ( + _FDID* obj /* Pointer to the corresponding object */ +) +{ + FRESULT res; + DWORD cl, n; + + if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; + } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + +#endif /* _FS_EXFAT && !_FS_READONLY */ + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +static +FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + _FDID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0:an entire chain) */ +) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; +#if _FS_EXFAT || _USE_TRIM + DWORD scl = clst, ecl = clst; +#endif +#if _USE_TRIM + DWORD rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ + + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; + } + + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if _FS_EXFAT || _USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; + } +#endif +#if _USE_TRIM + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + //disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ +#endif + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Does object have no chain? */ + obj->stat = 0; /* Change the object status 'initial' */ + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ + obj->stat = 2; /* Change the object status 'contiguous' */ + } + } + } +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch a chain or Create a new chain */ +/*-----------------------------------------------------------------------*/ +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster# to stretch, 0:Create a new chain */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + FATFS *fs = obj->fs; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Get suggested cluster to start from */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch current chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid value */ + if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; + } + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous chain' */ + } else { /* This is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + } else +#endif + { /* On the FAT12/16/32 volume */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ + if (ncl == scl) return 0; /* No free cluster */ + } + } + + if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ + res = FR_OK; /* FAT does not need to be written */ + } else { + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + } + } + + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + } + + return ncl; /* Return new cluster number or error status */ +} + +#endif /* !_FS_READONLY */ + + + + +#if _USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl, *tbl; + FATFS *fs = fp->obj.fs; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (ncl == 0) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} + +#endif /* _USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to directory object */ + DWORD ofs /* Offset of directory table */ +) +{ + DWORD csz, clst; + FATFS *fs = dp->obj.fs; + + + if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + return FR_INT_ERR; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = fs->dirbase; + if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } + + if (clst == 0) { /* Static table (root-directory in FAT12/16) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; + } + dp->sect = clust2sect(fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (!dp->sect) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; +#if !_FS_READONLY + UINT n; +#endif + + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (!dp->clust) { /* Static table */ + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } + } + else { /* Dynamic table */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ +#if !_FS_READONLY + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + /* Clean-up the stretched table */ + if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ + fs->wflag = 1; + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; + } + fs->winsect -= n; /* Restore window offset */ +#else + if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(fs, clst); + } + } + } + dp->dptr = ofs; /* Current entry */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve a block of directory entries */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ +) +{ + FRESULT res; + UINT n; + FATFS *fs = dp->obj.fs; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; +#if _FS_EXFAT + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { +#endif + if (++n == nent) break; /* A block of contiguous free entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); + } while (res == FR_OK); /* Next entry with table stretch enabled */ + } + + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ + return res; +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT: Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ +) +{ + DWORD cl; + + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } + + return cl; +} + + +#if !_FS_READONLY +static +void st_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ + DWORD cl /* Value to be set */ +) +{ + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } +} +#endif + + + +#if _USE_LFN != 0 +/*------------------------------------------------------------------------*/ +/* FAT-LFN: LFN handling */ +/*------------------------------------------------------------------------*/ +static +const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ + + +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ +static +int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { + if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + return 0; /* Not matched */ + } + wc = uc; + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + + return 1; /* The part of LFN matched */ +} + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ +static +int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ + BYTE* dir /* Pointer to the LFN entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; /* The part of LFN is valid */ +} +#endif + + +#if !_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ +static +void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set checksum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + st_word(dir + LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ + } while (++s < 13); + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LFN != 0 */ + + + +#if _USE_LFN != 0 && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Create a Numbered SFN */ +/*-----------------------------------------------------------------------*/ + +static +void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sr; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ + sr = seq; + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (BYTE)((seq % 16) + '0'); + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif /* _USE_LFN != 0 && !_FS_READONLY */ + + + +#if _USE_LFN != 0 +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Calculate checksum of an SFN entry */ +/*-----------------------------------------------------------------------*/ + +static +BYTE sum_sfn ( + const BYTE* dir /* Pointer to the SFN entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + return sum; +} + +#endif /* _USE_LFN != 0 */ + + + +#if _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* exFAT: Checksum */ +/*-----------------------------------------------------------------------*/ + +static +WORD xdir_sum ( /* Get checksum of the directoly block */ + const BYTE* dir /* Directory entry block to be calculated */ +) +{ + UINT i, szblk; + WORD sum; + + + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip sum field */ + i++; + } else { + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; + } + } + return sum; +} + + + +static +WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +#if !_FS_READONLY && _USE_MKFS +static +DWORD xsum32 ( + BYTE dat, /* Data to be sumed */ + DWORD sum /* Previous value */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} +#endif + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +/*------------------------------------------------------*/ +/* exFAT: Get object information from a directory block */ +/*------------------------------------------------------*/ + +static +void get_xdir_info ( + BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ + FILINFO* fno /* Buffer to store the extracted file information */ +) +{ + UINT di, si; + WCHAR w; +#if !_LFN_UNICODE + UINT nc; +#endif + + /* Get file name */ +#if _LFN_UNICODE + if (dirb[XDIR_NumName] <= _MAX_LFN) { + for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + fno->fname[di] = w; /* Store it */ + } + } else { + di = 0; /* Buffer overflow and inaccessible object */ + } +#else + for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); + } + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ + fno->fname[di++] = (char)w; + } +#endif + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ + fno->fname[di] = 0; /* Terminate file name */ + + fno->altname[0] = 0; /* No SFN */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ +} + +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + +/*-----------------------------------*/ +/* exFAT: Get a directry entry block */ +/*-----------------------------------*/ + +static +FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +) +{ + FRESULT res; + UINT i, nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + + + /* Load 85 entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; + mem_cpy(dirb, dp->dir, SZDIRE); + nent = dirb[XDIR_NumSec] + 1; + + /* Load C0 entry */ + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; + mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + + /* Load C1 entries */ + if (nent < 3 || nent > 19) return FR_NO_FILE; + i = SZDIRE * 2; nent *= SZDIRE; + do { + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; + mem_cpy(dirb + i, dp->dir, SZDIRE); + i += SZDIRE; + } while (i < nent); + + /* Sanity check */ + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + + return FR_OK; +} + + +#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ +static +FRESULT load_obj_dir ( + DIR* dp, /* Blank directory object to be used to access containing direcotry */ + const _FDID* obj /* Object with containing directory information */ +) +{ + FRESULT res; + + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } + return res; +} +#endif + + +#if !_FS_READONLY +/*-----------------------------------------------*/ +/* exFAT: Store the directory block to the media */ +/*-----------------------------------------------*/ +static +FRESULT store_xdir ( + DIR* dp /* Pointer to the direcotry object */ +) +{ + FRESULT res; + UINT nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + + /* Create set sum */ + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); + nent = dirb[XDIR_NumSec] + 1; + + /* Store the set of directory to the volume */ + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + mem_cpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory enrty block */ +/*-------------------------------------------*/ + +static +void create_xdir ( + BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + const WCHAR* lfn /* Pointer to the nul terminated file name */ +) +{ + UINT i; + BYTE nb, nc; + WCHAR chr; + + + mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ + dirb[XDIR_Type] = 0x85; + dirb[XDIR_Type + SZDIRE] = 0xC0; + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ + + i = SZDIRE * 2; /* C1 offset */ + nc = 0; nb = 1; chr = 1; + do { + dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + do { /* Fill name field */ + if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ + st_word(dirb + i, chr); i += 2; /* Store it */ + } while (i % SZDIRE); + nb++; + } while (lfn[nc]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nc; /* Set name length */ + dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_EXFAT */ + + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE a, c; +#if _USE_LFN != 0 + BYTE ord = 0xFF, sum = 0xFF; +#endif + + while (dp->sect) { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; /* Test for the entry type */ + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (_USE_LABEL && vol) { + if (c == 0x83) break; /* Volume label entry? */ + } else { + if (c == 0x85) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* On the FAT12/16/32 volume */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if _USE_LFN != 0 /* LFN configuration */ + if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + break; + } +#endif + } + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ + return res; +} + +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; +#if _USE_LFN != 0 + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ + + while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + } + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* On the FAT12/16/32 volume */ +#if _USE_LFN != 0 + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN != 0 /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + DIR* dp /* Target directory with object name to be created */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + UINT n, nlen, nent; + BYTE sn[12], sum; + + + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + DIR dj; + + nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + + if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ + dp->obj.stat &= 3; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ + res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (res != FR_OK) return res; + res = load_obj_dir(&dj, &dp->obj); + if (res != FR_OK) return res; /* Load the object status */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* On the FAT12/16/32 volume */ + mem_cpy(sn, dp->fn, 12); + if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ + res = dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + dp->fn[NSFLAG] = sn[NSFLAG]; + } + + /* Create an SFN with/without LFNs. */ + nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->dptr - nent * SZDIRE); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); + fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } + +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + +#endif + + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if _USE_LFN != 0 + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + fs->wflag = 1; + } + } + + return res; +} + +#endif /* !_FS_READONLY */ + + + +#if !_FS_READONLY && _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + DWORD last = dp->dptr; + + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ + if (res == FR_OK) { + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + /* Mark an entry 'deleted' */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; + } else { /* On the FAT12/16/32 volume */ + dp->dir[DIR_Name] = DDEM; + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } +#else /* Non LFN configuration */ + + res = move_window(fs, dp->sect); + if (res == FR_OK) { + dp->dir[DIR_Name] = DDEM; + fs->wflag = 1; + } +#endif + + return res; +} + +#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ + + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ + +static +void get_fileinfo ( /* No return code */ + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT i, j; + TCHAR c; + DWORD tm; +#if _USE_LFN != 0 + WCHAR w, lfv; + FATFS *fs = dp->obj.fs; +#endif + + + fno->fname[0] = 0; /* Invaidate file info */ + if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + +#if _USE_LFN != 0 /* LFN configuration */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + get_xdir_info(fs->dirbuf, fno); + return; + } else +#endif + { /* On the FAT12/16/32 volume */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + i = j = 0; + while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[i++] = (char)(w >> 8); + } +#endif + if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ + fno->fname[i++] = (TCHAR)w; + } + fno->fname[i] = 0; /* Terminate the LFN */ + } + } + + i = j = 0; + lfv = fno->fname[i]; /* LFN is exist if non-zero */ + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) { /* Insert a . if extension is exist */ + if (!lfv) fno->fname[j] = '.'; + fno->altname[j++] = '.'; + } +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { + c = c << 8 | dp->dir[i++]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif + fno->altname[j] = c; + if (!lfv) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { + c += 0x20; /* To lower */ + } + fno->fname[j] = c; + } + j++; + } + if (!lfv) { + fno->fname[j] = 0; + if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ + } + fno->altname[j] = 0; /* Terminate the SFN */ + +#else /* Non-LFN configuration */ + i = j = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ + fno->fname[j++] = c; + } + fno->fname[j] = 0; +#endif + + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ + fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); +} + +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + + +#if _USE_FIND && _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Pattern matching */ +/*-----------------------------------------------------------------------*/ + +static +WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ + const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ +) +{ +#if !_LFN_UNICODE + WCHAR chr; + + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#ifdef _EXCVT + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#else + if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE)*(*ptr)++; + } +#endif + return chr; +#else + return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ +#endif +} + + +static +int pattern_matching ( /* 0:not matched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + int skip, /* Number of pre-skip chars (number of ?s) */ + int inf /* Infinite search (* specified) */ +) +{ + const TCHAR *pp, *np; + WCHAR pc, nc; + int nm, nx; + + + while (skip--) { /* Pre-skip name chars */ + if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ + } + if (!*pat && inf) return 1; /* (short circuit) */ + + do { + pp = pat; np = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pp == '?' || *pp == '*') { /* Wildcard? */ + nm = nx = 0; + do { /* Analyze the wildcard chars */ + if (*pp++ == '?') nm++; else nx = 1; + } while (*pp == '?' || *pp == '*'); + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ + nc = *np; break; /* Branch mismatched */ + } + pc = get_achar(&pp); /* Get a pattern char */ + nc = get_achar(&np); /* Get a name char */ + if (pc != nc) break; /* Branch mismatched? */ + if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (inf && nc); /* Retry until end of name if infinite search is specified */ + + return 0; +} + +#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ + + + +/*-----------------------------------------------------------------------*/ +/* Pick a top segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if _USE_LFN != 0 /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR *p; + + /* Create LFN in Unicode */ + p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ') break; /* Break if end of the path name */ + if (w == '/' || w == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ +#if !_LFN_UNICODE + w &= 0xFF; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + w = (w << 8) + b; /* Create a DBC */ + if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + lfn[di++] = w; /* Store the Unicode character */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ +#if _FS_RPATH != 0 + if ((di == 1 && lfn[di - 1] == '.') || + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ + lfn[di] = 0; + for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ + dp->fn[i] = (i < di) ? '.' : ' '; + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Snip off trailing spaces and dots if exist */ + w = lfn[di - 1]; + if (w != ' ' && w != '.') break; + di--; + } + lfn[di] = 0; /* LFN is created */ + if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ + + /* Create SFN in directory form */ + mem_set(dp->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ + if (si) cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + + i = b = 0; ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN character */ + if (!w) break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) break; /* No extension */ + si = di; i = 8; ni = 11; /* Enter extension section */ + b <<= 2; continue; + } + + if (w >= 0x80) { /* Non ASCII character */ +#ifdef _EXCVT + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ +#else + w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; i = ni; continue; + } + dp->fn[i++] = (BYTE)(w >> 8); + } else { /* SBC */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; w -= 0x20; + } + } + } + } + dp->fn[i++] = (BYTE)w; + } + + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + + if (ni == 8) b <<= 2; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created */ + + return FR_OK; + + +#else /* _USE_LFN != 0 : Non-LFN configuration */ + BYTE c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + p = *path; sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = 0; ni = 8; +#if _FS_RPATH != 0 + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = p + si; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ') break; /* Break if end of the path name */ + if (c == '/' || c == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (c == '.' || i >= ni) { /* End of body or over size? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ + i = 8; ni = 11; /* Goto extension */ + continue; + } + if (c >= 0x80) { /* Extended character? */ +#ifdef _EXCVT + c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else +#if !_DF1S + return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ +#endif +#endif + } + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (IsLower(c)) c -= 0x20; /* To upper */ + sfn[i++] = c; + } + } + *path = p + si; /* Return pointer to the next segment */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ + + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + + return FR_OK; +#endif /* _USE_LFN != 0 */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE ns; + _FDID *obj = &dp->obj; + FATFS *fs = obj->fs; + + +#if _FS_RPATH != 0 + if (*path != '/' && *path != '\\') { /* Without heading separator */ + obj->sclust = fs->cdir; /* Start from the current directory */ + } else +#endif + { /* With heading separator */ + while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ + obj->sclust = 0; /* Start from the root directory */ + } +#if _FS_EXFAT && _FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ + DIR dj; + + obj->c_scl = fs->cdc_scl; + obj->c_size = fs->cdc_size; + obj->c_ofs = fs->cdc_ofs; + res = load_obj_dir(&dj, obj); + if (res != FR_OK) return res; + obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; + res = dir_sdi(dp, 0); + + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) break; + res = dir_find(dp); /* Find an object with the segment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ + } + } + break; + } + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + /* Get into the sub-directory */ + if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + } else +#endif + { + obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + } + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT boot sector */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* File system object */ + DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */ +) +{ + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ + + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + + if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { + if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ + } +#if _FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; +#endif + return 2; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Find logical drive and check if the volume is mounted */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ + FATFS* fs, /* Pointer to the file system object */ + BYTE mode /* !=0: Check write protection for write access */ +) +{ + BYTE fmt, *pt; + DSTATUS stat = STA_NOINIT; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + WORD nrsv; + UINT i; + + + ENTER_FF(fs); /* Lock the volume */ + + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ + if (fs->fs_type) { /* If the volume has been mounted */ + //disk_ioctl(fs->drv, IOCTL_STATUS, &stat); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + } + return FR_OK; /* The file system object is valid */ + } + } + + /* The file system object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + //disk_ioctl(fs->drv, IOCTL_INIT, &stat); /* Initialize the physical drive */ + if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ + } + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; + } +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + //if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; +#endif + /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + bsect = 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(fs) != 0)) { /* Not an FAT-VBR or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + (MBR_Table + i * SZ_PTE); + br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; + } + i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ + if (i) i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } while (!LD2PT(fs) && fmt >= 2 && ++i < 4); + } + if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found. Following code initializes the file system object */ + +#if _FS_EXFAT + if (fmt == 1) { + QWORD maxlba; + + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; + + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ + + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ + + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ + + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ + + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = nclst + 2; + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + + /* Check if bitmap location is in assumption (at the first cluster) */ + if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; + for (i = 0; i < SS(fs); i += SZDIRE) { + if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + } + if (i == SS(fs)) return FR_NO_FILESYSTEM; +#if !_FS_READONLY + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif /* _FS_EXFAT */ + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ + +#if !_FS_READONLY + /* Get FSINFO if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->fsi_flag = 0x80; +#if (_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 1 + && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 + && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { +#if (_FS_NOFSINFO & 1) == 0 + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#endif +#if (_FS_NOFSINFO & 2) == 0 + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif /* (_FS_NOFSINFO & 3) != 3 */ +#endif /* !_FS_READONLY */ + } + + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ +#if _USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if _FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block working buuffer */ +#endif +#endif +#if _FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ +#endif +#if _FS_LOCK != 0 /* Clear file lock semaphores */ + clear_lock(fs); +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ + FATFS** fs /* Pointer to pointer to the owner file system object to return */ +) +{ + FRESULT res = FR_INVALID_OBJECT; +#if 0 + DSTATUS stat; + + + if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) != RES_OK || (stat & STA_NOINIT)) { + *fs = 0; /* The object is invalid */ + res = FR_INVALID_OBJECT; + } else { + *fs = obj->fs; /* Owner file sytem object */ + ENTER_FF(obj->fs); /* Lock file system */ + res = FR_OK; + } +#endif + return res; +} + + + + +/*--------------------------------------------------------------------------- + + Public Functions (FatFs API) + +----------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs /* Pointer to the file system object to mount */ +) +{ + FRESULT res; + + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj(fs, &fs->sobj)) return FR_INT_ERR; +#endif + + res = find_volume(fs, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); +} + + +FRESULT f_umount ( + FATFS* fs /* Pointer to the file system object to unmount */ +) +{ +#if _FS_LOCK + clear_lock(fs); +#endif +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(fs->sobj)) return FR_INT_ERR; +#endif + fs->fs_type = 0; /* Clear old fs object */ + + return FR_OK; +} + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FATFS *fs, + FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; +#if !_FS_READONLY + DWORD dw, cl, bcs, clst, sc; + FSIZE_t ofs; +#endif + DEF_NAMBUF + + + if (!fp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; + res = find_volume(fs, mode); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } +#if _FS_LOCK != 0 + else { + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + } +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ +#if _FS_LOCK != 0 + res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + mode |= FA_CREATE_ALWAYS; /* File is created */ + } + else { /* Any object is already existing */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = GET_FATTIME(); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ + fs->dirbuf[XDIR_CrtTime10] = 0; + st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ + st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ + st_qword(fs->dirbuf + XDIR_FileSize, 0); + st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Clean directory info */ + st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ + st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + cl = ld_clust(fs, dj.dir); /* Get cluster chain */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + + if (cl) { /* Remove the cluster chain if exist */ + dw = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, dw); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Following succeeded */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ + res = FR_DENIED; + } + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA_MODIFIED; + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if _FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->obj.lockid) res = FR_INT_ERR; +#endif + } +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } else { + if (dj.obj.attr & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } + } + } +#endif + + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + } else +#endif + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } +#if _USE_FASTSEEK + fp->cltbl = 0; /* Disable fast seek mode */ +#endif + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !_FS_READONLY +#if !_FS_TINY + mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + if ((sc = clust2sect(fs, clst)) == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !_FS_TINY + if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } + } +#endif + } + + FREE_NAMBUF(); + } + + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data read */ + rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } + } + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if _FS_TINY + if (fs->wflag && fs->winsect - sect < cc) { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } +#else + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { + mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } +#endif +#endif + rcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !_FS_TINY + if (fp->sect != sect) { /* Load data sector if not in cache */ +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + } +#endif + fp->sect = sect; + } + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ +#if _FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#else + mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#endif + } + + LEAVE_FF(fs, FR_OK); +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + UINT wcnt, cc, csect; + const BYTE *wbuff = (const BYTE*)buff; + + + *bw = 0; /* Clear write byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ + if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + for ( ; btw; /* Repeat until all data written */ + wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ + } +#if _FS_TINY + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ +#else + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if _FS_MINIMIZE <= 2 +#if _FS_TINY + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; + } +#else + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif +#endif + wcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if _FS_TINY + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; + } +#else + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } +#endif + fp->sect = sect; + } + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ +#if _FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fs->wflag = 1; +#else + mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; +#endif + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD tm; + BYTE *dir; +#if _FS_EXFAT + DEF_NAMBUF +#endif + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ +#if !_FS_TINY + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + /* Update the directory entry */ + tm = GET_FATTIME(); /* Modified time */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + if (res == FR_OK) { + DIR dj; + + INIT_NAMBUF(fs); + res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + FREE_NAMBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL* fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + +#if !_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(&fp->obj, &fs); /* Lock volume */ + if (res == FR_OK) { +#if _FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) +#endif + { + fp->obj.fs = 0; /* Invalidate file object */ + } +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +#if _FS_RPATH >= 1 +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chdir ( + FATFS *fs, + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + /* Get logical drive */ + res = find_volume(fs, 0); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { + fs->cdir = dj.obj.sclust; /* It is the start directory itself */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif + } else { + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { + res = FR_NO_PATH; /* Reached but a file */ + } + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(fs, res); +} + + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + FATFS *fs, + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ +) +{ + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMBUF + + + *buff = 0; + /* Get logical drive */ + res = find_volume(fs, 0); /* Get current volume */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + i = len; /* Bottom of buffer (directory stack base) */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + if (res != FR_OK) break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; + buff[--i] = '/'; + } + } + tp = buff; + if (res == FR_OK) { + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ + + + +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, bcs, nsect; + FSIZE_t ifptr; +#if _USE_FASTSEEK + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; +#endif + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ +#if _USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->obj.sclust; /* Origin of the chain */ + if (cl) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) { + *tbl = 0; /* Terminate table */ + } else { + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ + } + } else { /* Fast seek */ + if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fs, fp->clust); + if (!dsc) ABORT(fs, FR_INT_ERR); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ +#endif + fp->sect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#endif + if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->obj.sclust; /* start from the first cluster */ +#if !_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; +#if !_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; + } + } else +#endif + { + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); + fp->clust = clst; + } + fp->fptr += ofs; + if (ofs % SS(fs)) { + nsect = clust2sect(fs, clst); /* Current sector */ + if (!nsect) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); + } + } + } + if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ +#endif + fp->sect = nsect; + } + } + + LEAVE_FF(fs, res); +} + + + +#if _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directory Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + FATFS *fs, + DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + _FDID *obj; + DEF_NAMBUF + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + obj = &dp->obj; + res = find_volume(fs, 0); + if (res == FR_OK) { + obj->fs = fs; + INIT_NAMBUF(fs); + res = follow_path(dp, path); /* Follow the path to the directory */ + if (res == FR_OK) { /* Follow completed */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (obj->attr & AM_DIR) { /* This object is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory inforamation */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + } + } else { /* This object is a file */ + res = FR_NO_PATH; + } + } + if (res == FR_OK) { + obj->id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if _FS_LOCK != 0 + if (res == FR_OK) { + if (obj->sclust) { + obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; + } else { + obj->lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + + + res = validate(&dp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { +#if _FS_LOCK != 0 + if (dp->obj.lockid) { /* Decrement sub-directory open counter */ + res = dec_lock(dp->obj.lockid); + } + if (res == FR_OK) +#endif + { + dp->obj.fs = 0; /* Invalidate directory object */ + } +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entries in Sequence */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + FATFS *fs; + DEF_NAMBUF + + + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_NAMBUF(fs); + res = dir_read(dp, 0); /* Read an item */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ + } + FREE_NAMBUF(); + } + } + LEAVE_FF(fs, res); +} + + + +#if _USE_FIND +/*-----------------------------------------------------------------------*/ +/* Find Next File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findnext ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to the file information structure */ +) +{ + FRESULT res; + + + for (;;) { + res = f_readdir(dp, fno); /* Get a directory item */ + if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ +#if _USE_LFN != 0 && _USE_FIND == 2 + if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ +#endif + } + return res; +} + + + +/*-----------------------------------------------------------------------*/ +/* Find First File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findfirst ( + DIR* dp, /* Pointer to the blank directory object */ + FILINFO* fno, /* Pointer to the file information structure */ + const TCHAR* path, /* Pointer to the directory to open */ + const TCHAR* pattern /* Pointer to the matching pattern */ +) +{ + FRESULT res; + + + dp->pat = pattern; /* Save pointer to pattern string */ + res = f_opendir(dp, path); /* Open the target directory */ + if (res == FR_OK) { + res = f_findnext(dp, fno); /* Find the first item */ + } + return res; +} + +#endif /* _USE_FIND */ + + + +#if _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + FATFS *fs, + const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(fs, 0); + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(dj.obj.fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ + res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(dj.obj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + FATFS *fs, + DWORD* nclst /* Pointer to a variable to return number of free clusters */ +) +{ + FRESULT res; + DWORD nfree, clst, sect, stat; + UINT i; + BYTE *p; + _FDID obj; + + + /* Get logical drive */ + res = find_volume(fs, 0); + if (res == FR_OK) { + /* If free_clst is valid, return it without full cluster scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; + } else { + /* Get number of free clusters */ + nfree = 0; + if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + clst = 2; obj.fs = fs; + do { + stat = get_fat(&obj, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) nfree++; + } while (++clst < fs->n_fatent); + } else { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; + sect = fs->database; + i = 0; + do { + if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { + if (!(bm & 1)) nfree++; + bm >>= 1; + } + i = (i + 1) % SS(fs); + } while (clst); + } else +#endif + { /* FAT16/32: Sector alighed FAT entries */ + clst = fs->n_fatent; sect = fs->fatbase; + i = 0; p = 0; + do { + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(p) == 0) nfree++; + p += 2; i -= 2; + } else { + if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; + p += 4; i -= 4; + } + } while (--clst); + } + } + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FSInfo is to be updated */ + } + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD ncl; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->obj.objsize > fp->fptr) { + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); + } + } + fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA_MODIFIED; +#if !_FS_TINY + if (res == FR_OK && (fp->flag & FA_DIRTY)) { + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= (BYTE)~FA_DIRTY; + } + } +#endif + if (res != FR_OK) ABORT(fs, res); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + FATFS *fs, + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + DWORD dclst = 0; +#if _FS_EXFAT + _FDID obj; +#endif + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(fs, FA_WRITE); + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; /* Cannot remove dot entry */ + } +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + if (dj.fn[NSFLAG] & NS_NONAME) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* Cannot remove R/O object */ + } + } + if (res == FR_OK) { +#if _FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); + obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ +#if _FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = dir_read(&sdj, 0); /* Read an item */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ +#if _FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + FATFS *fs, + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + UINT n; + DWORD dsc, dcl, pcl, tm; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(fs, FA_WRITE); + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; + } + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ + dj.obj.objsize = (DWORD)fs->csize * SS(fs); + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + tm = GET_FATTIME(); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(fs, dcl); + dir = fs->win; + mem_set(dir, 0, SS(fs)); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + st_dword(dir + DIR_ModTime, tm); + st_clust(fs, dir, dcl); + mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ + dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; + st_clust(fs, dir + SZDIRE, pcl); + } + for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + fs->winsect = dsc++; + fs->wflag = 1; + res = sync_window(fs); + if (res != FR_OK) break; + mem_set(dir, 0, SS(fs)); + } + } + if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ + res = store_xdir(&dj); + } else +#endif + { + dir = dj.dir; + st_dword(dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dir, dcl); /* Table start cluster */ + dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + if (res == FR_OK) res = sync_fs(fs); + } else { + remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + FATFS *fs, + const TCHAR* path_old, /* Pointer to the object name to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; + DWORD dw; + DEF_NAMBUF + + + res = find_volume(fs, FA_WRITE); + if (res == FR_OK) { + djo.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&djo, path_old); /* Check old object */ + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Object to be renamed is found */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT */ + BYTE nf, nn; + WORD nh; + + mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + mem_cpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); +/* Start of critical section where any interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT12/FAT16/FAT32 */ + mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy information about object except name */ + mem_cpy(dir + 13, buf + 2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clust2sect(fs, ld_clust(fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { +/* Start of critical section where any interruption can cause a cross-link */ + res = move_window(fs, dw); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; + } + } + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +#if _USE_CHMOD && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + FATFS *fs, + const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + + res = find_volume(fs, FA_WRITE); /* Get logical drive */ + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else +#endif + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; + } + if (res == FR_OK) res = sync_fs(fs); + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + FATFS *fs, + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the time stamp to be set */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + + res = find_volume(fs, FA_WRITE); /* Get logical drive */ + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->wflag = 1; + } + if (res == FR_OK) res = sync_fs(fs); + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_CHMOD && !_FS_READONLY */ + + + +#if _USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + FATFS *fs, + TCHAR* label, /* Pointer to a buffer to return the volume label */ + DWORD* vsn /* Pointer to a variable to return the volume serial number */ +) +{ + FRESULT res; + DIR dj; + UINT si, di; +#if _LFN_UNICODE || _FS_EXFAT + WCHAR w; +#endif + + /* Get logical drive */ + res = find_volume(fs, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Find a volume label entry */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + w = ld_word(dj.dir + XDIR_Label + si * 2); +#if _LFN_UNICODE + label[di++] = w; +#else + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) w = '?'; /* Replace wrong character */ + if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); + label[di++] = (char)w; +#endif + } + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ + do { +#if _LFN_UNICODE + w = (si < 11) ? dj.dir[si++] : ' '; + if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { + w = w << 8 | dj.dir[si++]; + } + label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ +#else + label[di++] = dj.dir[si++]; +#endif + } while (di < 11); + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } + } + } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(fs, fs->volbase); + if (res == FR_OK) { + switch (fs->fs_type) { + case FS_EXFAT: di = BPB_VolIDEx; break; + case FS_FAT32: di = BS_VolID32; break; + default: di = BS_VolID; + } + *vsn = ld_dword(fs->win + di); + } + } + + LEAVE_FF(fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + FATFS *fs, + const TCHAR* label /* Pointer to the volume label to set */ +) +{ + FRESULT res; + DIR dj; + BYTE dirvn[22]; + UINT i, j, slen; + WCHAR w; + static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; + + + /* Get logical drive */ + res = find_volume(fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + dj.obj.fs = fs; + + /* Get length of given volume label */ + for (slen = 0; (UINT)label[slen] >= ' '; slen++) { } /* Get name length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ + w = label[i++]; +#if !_LFN_UNICODE + if (IsDBCS1(w)) { + w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } + w = ff_convert(w, 1); +#endif + if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + j, w); j += 2; + } + slen = j; + } else +#endif + { /* On the FAT12/16/32 volume */ + for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ + if (slen) { /* Is there a volume label to be set? */ + dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ + do { +#if _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); +#else + w = (BYTE)label[i++]; + if (IsDBCS1(w)) { + w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } +#if _USE_LFN != 0 + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); +#else + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ +#ifdef _EXCVT + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ +#endif +#endif +#endif + if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); + dirvn[j++] = (BYTE)w; + } while (i < slen); + while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } + } + + /* Set volume label */ + dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get volume label entry */ + if (res == FR_OK) { + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + if (slen) { + mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } + } + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry is found or error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (slen) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + mem_cpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); + } + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LABEL */ + + + +#if _USE_EXPAND && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { + if (opt) { + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + lclst = scl + tcl - 1; + } else { + lclst = scl - 1; + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + n = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (n == 1) { res = FR_INT_ERR; break; } + if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + } + if (res == FR_OK) { + if (opt) { + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); + if (res != FR_OK) break; + lclst = clst; + } + } else { + lclst = scl - 1; + } + } + } + + if (res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + if (opt) { + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_EXPAND && !_FS_READONLY */ + + + +#if _USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_forward ( + FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, csect; + BYTE *dbuf; + + + *bf = 0; /* Clear transfer byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + remain = fp->obj.objsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ + fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; +#if _FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (!rcnt) ABORT(fs, FR_INT_ERR); + } + + LEAVE_FF(fs, FR_OK); +} +#endif /* _USE_FORWARD */ + + + +#if _USE_MKFS && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create FAT file system on the logical drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkfs ( + FATFS *fs, + BYTE opt, /* Format option */ + DWORD au, /* Size of allocation unit [byte] */ + void* work, /* Pointer to working buffer */ + UINT len /* Size of working buffer */ +) +{ + const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ + BYTE fmt, sys, *buf, *pte, part; void *pdrv; + WORD ss; + DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; + DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ + DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ + UINT i; + DSTATUS stat; +#if _USE_TRIM || _FS_EXFAT + DWORD tbl[3]; +#endif + + + /* Check mounted drive and clear work area */ + fs->fs_type = 0; /* Clear mounted volume */ + pdrv = fs->drv; /* Physical drive */ + part = LD2PT(fs); /* Partition (0:create as new, 1-4:get from partition table) */ + + stat = STA_NOINIT | STA_PROTECT; + /* Check physical drive status */ + //disk_ioctl(pdrv, IOCTL_INIT, &stat); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + //if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ +#if _MAX_SS != _MIN_SS /* Get sector size of the medium */ + //if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = _MAX_SS; +#endif + if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in unit of sector */ + + /* Get working buffer */ + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + if (!szb_buf) return FR_MKFS_ABORTED; + + /* Determine where the volume to be located (b_vol, sz_vol) */ + if (_MULTI_PARTITION && part != 0) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ + pte = buf + (MBR_Table + (part - 1) * SZ_PTE); + if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ + } else { + /* Create a single-partition in this function */ + //if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + if (sz_vol < b_vol) return FR_MKFS_ABORTED; + sz_vol -= b_vol; /* Volume size */ + } + if (sz_vol < 50) return FR_MKFS_ABORTED; /* Check if volume size is >=50s */ + + /* Pre-determine the FAT type */ + do { + if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ + fmt = FS_EXFAT; break; + } + } + if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (opt & FM_FAT32) { /* FAT32 possible? */ + if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ + fmt = FS_FAT32; break; + } + } + if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + fmt = FS_FAT16; + } while (0); + +#if _FS_EXFAT + if (fmt == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nb, cl; + WCHAR ch, si; + UINT j, st; + BYTE b; + + if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + //disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Determine FAT location, data location and number of clusters */ + if (!au) { /* au auto-selection */ + au = 8; + if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ + } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ + if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ + if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ + + /* Create a compressed up-case table */ + sect = b_data + au * tbl[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = si = i = j = szb_case = 0; + do { + switch (st) { + case 0: + ch = ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ + } + st = 1; /* Do not compress short run */ + /* continue */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; + default: + ch = (WCHAR)j; si += j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; i = 0; + } + } while (si); + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[2] = 1; /* Number of root dir clusters */ + + /* Initialize the allocation bitmap */ + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the FAT */ + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; + } + do { /* Create chains of bitmap, up-case and root dir */ + while (nb && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb && i < szb_buf); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the root directory */ + mem_set(buf, 0, szb_buf); + buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ + buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + st_dword(buf + SZDIRE * 1 + 20, 2); + st_dword(buf + SZDIRE * 1 + 24, szb_bit); + buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + st_dword(buf + SZDIRE * 2 + 4, sum); + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); + st_dword(buf + SZDIRE * 2 + 24, szb_case); + sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + /* Extended bootstrap record (+1..+8) */ + mem_set(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* OEM/Reserved record (+9..+10) */ + mem_set(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + + } else +#endif /* _FS_EXFAT */ + { /* Create an FAT12/16/32 volume */ + do { + pau = au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fmt == FS_FAT32) { /* FAT32 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; + } else { /* FAT12/16 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fmt = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + + /* Align data base to erase block boundary (for flash memory media) */ + n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + sz_rsv += n; b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + sz_fat += n / n_fats; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; + if (fmt == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ + if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (!au && (pau * 2) <= 64) { + au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((opt & FM_FAT32)) { + fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); + +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + //disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Create FAT VBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ + if (fmt == FS_FAT32) { + st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fmt == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + mem_set(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ + } + + /* Initialize FAT area */ + mem_set(buf, 0, (UINT)szb_buf); + sect = b_fat; /* FAT start sector */ + for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ + if (fmt == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ + st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ + st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + } else { + st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ + } + nsect = sz_fat; /* Number of FAT sectors */ + do { /* Fill FAT sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + } + + /* Initialize root directory (fill with zero) */ + nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + do { + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + } + + /* Determine system ID in the partition table */ + if (_FS_EXFAT && fmt == FS_EXFAT) { + sys = 0x07; /* HPFS/NTFS/exFAT */ + } else { + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (>=64KS) */ + } else { + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + } + } + } + + if (_MULTI_PARTITION && part != 0) { + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ + } else { + if (!(opt & FM_SFD)) { + /* Create partition table in FDISK format */ + mem_set(buf, 0, ss); + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ + pte[PTE_Boot] = 0; /* Boot indicator */ + pte[PTE_StHead] = 1; /* Start head */ + pte[PTE_StSec] = 1; /* Start sector */ + pte[PTE_StCyl] = 0; /* Start cylinder */ + pte[PTE_System] = sys; /* System type */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */ + pte[PTE_EdHead] = 254; /* End head */ + pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ + st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ + st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + } + } + + /*if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK)*/ return FR_DISK_ERR; + + return FR_OK; +} + + + +#if _MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Create partition table on the physical drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + void *pdrv, /* Physical drive number */ + const DWORD* szt, /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer */ +) +{ + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + + + //disk_ioctl(pdrv, IOCTL_INIT, &stat); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + /*if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk))*/ return FR_DISK_ERR; + + /* Determine the CHS without any care of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; + if (n == 256) n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, _MAX_SS); + p = buf + MBR_Table; b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + if (!p_cyl) continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; + if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x06; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + st_dword(p + 8, s_part); /* Start sector in LBA */ + st_dword(p + 12, sz_part); /* Partition size */ + + /* Next partition */ + b_cyl += p_cyl; + } + st_word(p, 0xAA55); + + /* Write it to the MBR */ + return /*(disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? */FR_DISK_ERR /*: FR_OK*/; +} + +#endif /* _MULTI_PARTITION */ +#endif /* _USE_MKFS && !_FS_READONLY */ diff --git a/src/openmv/src/micropython/lib/oofatfs/ff.h b/src/openmv/src/micropython/lib/oofatfs/ff.h new file mode 100755 index 0000000..7915032 --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/ff.h @@ -0,0 +1,385 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12b / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2016, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +#ifndef _FATFS +#define _FATFS 68020 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* This type MUST be 8-bit */ +typedef uint8_t BYTE; + +/* These types MUST be 16-bit */ +typedef int16_t SHORT; +typedef uint16_t WORD; +typedef uint16_t WCHAR; + +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + +/* These types MUST be 32-bit */ +typedef int32_t LONG; +typedef uint32_t DWORD; + +/* This type MUST be 64-bit (Remove this for C89 compatibility) */ +typedef uint64_t QWORD; + +#ifdef FFCONF_H +#include FFCONF_H /* FatFs configuration options */ +#else +#include "ffconf.h" +#endif + + +#if _FATFS != _FFCONF +#error Wrong configuration file (ffconf.h). +#endif + + + +/* Definitions of volume management */ + +#if _MULTI_PARTITION /* Multiple partition configuration */ +#define LD2PT(fs) (fs->part) /* Get partition index */ +#else /* Single partition configuration */ +#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ +#endif + + + +/* Type of path name strings on FatFs API */ + +#if _LFN_UNICODE /* Unicode (UTF-16) string */ +#if _USE_LFN == 0 +#error _LFN_UNICODE must be 0 at non-LFN cfg. +#endif +#ifndef _INC_TCHAR +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#endif +#else /* ANSI/OEM string */ +#ifndef _INC_TCHAR +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif +#endif + + + +/* Type of file size variables */ + +#if _FS_EXFAT +#if _USE_LFN == 0 +#error LFN must be enabled when enable exFAT +#endif +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; +#endif + + + +/* File system object structure (FATFS) */ + +typedef struct { + void *drv; // block device underlying this filesystem +#if _MULTI_PARTITION /* Multiple partition configuration */ + BYTE part; // Partition: 0:Auto detect, 1-4:Forced partition +#endif + BYTE fs_type; /* File system type (0:N/A) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ +#if _MAX_SS != _MIN_SS + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if _USE_LFN != 0 + WCHAR* lfnbuf; /* LFN working buffer */ +#endif +#if _FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer */ +#endif +#if _FS_REENTRANT + _SYNC_t sobj; /* Identifier of sync object */ +#endif +#if !_FS_READONLY + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ +#endif +#if _FS_RPATH != 0 + DWORD cdir; /* Current directory start cluster (0:root) */ +#if _FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ +#endif +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Size of an FAT [sectors] */ + DWORD volbase; /* Volume base sector */ + DWORD fatbase; /* FAT base sector */ + DWORD dirbase; /* Root directory base sector/cluster */ + DWORD database; /* Data base sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ +} FATFS; + + + +/* Object ID and allocation information (_FDID) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ + DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if _FS_EXFAT + DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ +#endif +#if _FS_LOCK != 0 + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} _FDID; + + + +/* File object structure (FIL) */ + +typedef struct { + _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ + DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ +#if !_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ +#endif +#if _USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ +#endif +#if !_FS_TINY + BYTE buf[_MAX_SS]; /* File private data read/write window */ +#endif +} FIL; + + + +/* Directory object structure (FF_DIR) */ + +typedef struct { + _FDID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector */ + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ +#if _USE_LFN != 0 + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ +#endif +#if _USE_FIND + const TCHAR* pat; /* Pointer to the name matching pattern */ +#endif +} FF_DIR; + + + +/* File information structure (FILINFO) */ + +typedef struct { + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if _USE_LFN != 0 + TCHAR altname[13]; /* Altenative file name */ + TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#else + TCHAR fname[13]; /* File name */ +#endif +} FILINFO; + + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ + FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +} FRESULT; + + + +/*--------------------------------------------------------------*/ +/* FatFs module application interface */ + +FRESULT f_open (FATFS *fs, FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_close (FIL* fp); /* Close an open file object */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ +FRESULT f_opendir (FATFS *fs, FF_DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (FF_DIR* dp); /* Close an open directory */ +FRESULT f_readdir (FF_DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst (FF_DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext (FF_DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_mkdir (FATFS *fs, const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (FATFS *fs, const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (FATFS *fs, const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (FATFS *fs, const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (FATFS *fs, const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (FATFS *fs, const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ +FRESULT f_chdir (FATFS *fs, const TCHAR* path); /* Change current directory */ +FRESULT f_getcwd (FATFS *fs, TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (FATFS *fs, DWORD* nclst); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (FATFS *fs, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (FATFS *fs, const TCHAR* label); /* Set volume label */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_mount (FATFS* fs); /* Mount/Unmount a logical drive */ +FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ +FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ + +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) +#define f_error(fp) ((fp)->err) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->obj.objsize) +#define f_rewind(fp) f_lseek((fp), 0) +#define f_rewinddir(dp) f_readdir((dp), 0) + +#ifndef EOF +#define EOF (-1) +#endif + + + + +/*--------------------------------------------------------------*/ +/* Additional user defined functions */ + +/* RTC function */ +#if !_FS_READONLY && !_FS_NORTC +DWORD get_fattime (void); +#endif + +/* Unicode support functions */ +#if _USE_LFN != 0 /* Unicode - OEM code conversion */ +WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#endif + +/* Sync functions */ +#if _FS_REENTRANT +int ff_cre_syncobj (FATFS *fatfs, _SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and offset address */ + + +/* File access mode and open method flags (3rd argument of f_open) */ +#define FA_READ 0x01 +#define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA_OPEN_APPEND 0x30 + +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) + +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 + +/* Filesystem type (FATFS.fs_type) */ +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 +#define FS_EXFAT 4 + +/* File attribute bits for directory entry (FILINFO.fattrib) */ +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _FATFS */ diff --git a/src/openmv/src/micropython/lib/oofatfs/ffconf.h b/src/openmv/src/micropython/lib/oofatfs/ffconf.h new file mode 100755 index 0000000..315101f --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/ffconf.h @@ -0,0 +1,349 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Original file from: + * FatFs - FAT file system module configuration file R0.12a (C)ChaN, 2016 + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file +/---------------------------------------------------------------------------*/ + +#define _FFCONF 68020 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define _FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define _USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define _USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define _USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define _USE_CHMOD 1 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ + + +#ifdef MICROPY_FATFS_USE_LABEL +#define _USE_LABEL (MICROPY_FATFS_USE_LABEL) +#else +#define _USE_LABEL 0 +#endif +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#ifdef MICROPY_FATFS_LFN_CODE_PAGE +#define _CODE_PAGE (MICROPY_FATFS_LFN_CODE_PAGE) +#else +#define _CODE_PAGE 1 +#endif +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +*/ + + +#ifdef MICROPY_FATFS_ENABLE_LFN +#define _USE_LFN (MICROPY_FATFS_ENABLE_LFN) +#else +#define _USE_LFN 0 +#endif +#ifdef MICROPY_FATFS_MAX_LFN +#define _MAX_LFN (MICROPY_FATFS_MAX_LFN) +#else +#define _MAX_LFN 255 +#endif +/* The _USE_LFN switches the support of long file name (LFN). +/ +/ 0: Disable support of LFN. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + + +#define _LFN_UNICODE 0 +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ + + +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ This option has no effect when _LFN_UNICODE == 0. */ + + +#ifdef MICROPY_FATFS_RPATH +#define _FS_RPATH (MICROPY_FATFS_RPATH) +#else +#define _FS_RPATH 0 +#endif +/* This option configures support of relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* _STR_VOLUME_ID switches string support of volume ID. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ + + +#ifdef MICROPY_FATFS_MULTI_PARTITION +#define _MULTI_PARTITION (MICROPY_FATFS_MULTI_PARTITION) +#else +#define _MULTI_PARTITION 0 +#endif +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ + + +#define _MIN_SS 512 +#ifdef MICROPY_FATFS_MAX_SS +#define _MAX_SS (MICROPY_FATFS_MAX_SS) +#else +#define _MAX_SS 512 +#endif +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + + +#define _USE_TRIM 0 +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define _FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_TINY 1 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + + +#ifdef MICROPY_FATFS_EXFAT +#define _FS_EXFAT (MICROPY_FATFS_EXFAT) +#else +#define _FS_EXFAT 0 +#endif +/* This option switches support of exFAT file system. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) +/ Note that enabling exFAT discards C89 compatibility. */ + + +#ifdef MICROPY_FATFS_NORTC +#define _FS_NORTC (MICROPY_FATFS_NORTC) +#else +#define _FS_NORTC 0 +#endif +#define _NORTC_MON 1 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2016 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ + + +#define _FS_LOCK 0 +/* The option _FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +#ifdef MICROPY_FATFS_REENTRANT +#define _FS_REENTRANT (MICROPY_FATFS_REENTRANT) +#else +#define _FS_REENTRANT 0 +#endif + +// milliseconds +#ifdef MICROPY_FATFS_TIMEOUT +#define _FS_TIMEOUT (MICROPY_FATFS_TIMEOUT) +#else +#define _FS_TIMEOUT 1000 +#endif + +#ifdef MICROPY_FATFS_SYNC_T +#define _SYNC_t MICROPY_FATFS_SYNC_T +#else +#define _SYNC_t HANDLE +#endif +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + +/* #include // O/S definitions */ + + +/*--- End of configuration options ---*/ diff --git a/src/openmv/src/micropython/lib/oofatfs/option/ccsbcs.c b/src/openmv/src/micropython/lib/oofatfs/option/ccsbcs.c new file mode 100755 index 0000000..fdded96 --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/option/ccsbcs.c @@ -0,0 +1,388 @@ +/*------------------------------------------------------------------------*/ +/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. +/ 720 Arabic +/ 737 Greek +/ 771 KBL +/ 775 Baltic +/ 850 Latin 1 +/ 852 Latin 2 +/ 855 Cyrillic +/ 857 Turkish +/ 860 Portuguese +/ 861 Icelandic +/ 862 Hebrew +/ 863 Canadian French +/ 864 Arabic +/ 865 Nordic +/ 866 Russian +/ 869 Greek 2 +*/ + +#include "../ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 771 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 860 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 861 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 863 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 864 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 +}; + +#elif _CODE_PAGE == 865 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 869 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ + 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed at current configuration. Remove from the project. +#endif + + + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR chr, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +) +{ + WCHAR c; + + + if (chr < 0x80) { /* ASCII */ + c = chr; + + } else { + if (dir) { /* OEM code to Unicode */ + c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; + + } else { /* Unicode to OEM code */ + for (c = 0; c < 0x80; c++) { + if (chr == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + + +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ +) +{ + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 + }; + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 + }; + const WCHAR *p; + WCHAR bc, nc, cmd; + + + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; + } + + return chr; +} + diff --git a/src/openmv/src/micropython/lib/oofatfs/option/unicode.c b/src/openmv/src/micropython/lib/oofatfs/option/unicode.c new file mode 100755 index 0000000..e48d09c --- /dev/null +++ b/src/openmv/src/micropython/lib/oofatfs/option/unicode.c @@ -0,0 +1,17 @@ +#include "../ff.h" + +#if _USE_LFN != 0 + +#if _CODE_PAGE == 932 /* Japanese Shift_JIS */ +#include "cc932.c" +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#include "cc936.c" +#elif _CODE_PAGE == 949 /* Korean */ +#include "cc949.c" +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#include "cc950.c" +#else /* Single Byte Character-Set */ +#include "ccsbcs.c" +#endif + +#endif diff --git a/src/openmv/src/micropython/lib/timeutils/timeutils.c b/src/openmv/src/micropython/lib/timeutils/timeutils.c new file mode 100755 index 0000000..eb3dc80 --- /dev/null +++ b/src/openmv/src/micropython/lib/timeutils/timeutils.c @@ -0,0 +1,215 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#include "lib/timeutils/timeutils.h" + +// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately +// after Feb 29. We calculate seconds as a signed integer relative to that. +// +// Our timebase is relative to 2000-01-01. + +#define LEAPOCH ((31 + 29) * 86400) + +#define DAYS_PER_400Y (365*400 + 97) +#define DAYS_PER_100Y (365*100 + 24) +#define DAYS_PER_4Y (365*4 + 1) + +STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + +bool timeutils_is_leap_year(mp_uint_t year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; +} + +// month is one based +mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month) { + mp_uint_t mdays = days_since_jan1[month] - days_since_jan1[month - 1]; + if (month == 2 && timeutils_is_leap_year(year)) { + mdays++; + } + return mdays; +} + +// compute the day of the year, between 1 and 366 +// month should be between 1 and 12, date should start at 1 +mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) { + mp_uint_t yday = days_since_jan1[month - 1] + date; + if (month >= 3 && timeutils_is_leap_year(year)) { + yday += 1; + } + return yday; +} + +void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) { + // The following algorithm was adapted from musl's __secs_to_tm and adapted + // for differences in MicroPython's timebase. + + mp_int_t seconds = t - LEAPOCH; + + mp_int_t days = seconds / 86400; + seconds %= 86400; + if (seconds < 0) { + seconds += 86400; + days -= 1; + } + tm->tm_hour = seconds / 3600; + tm->tm_min = seconds / 60 % 60; + tm->tm_sec = seconds % 60; + + mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2) + if (wday < 0) { + wday += 7; + } + tm->tm_wday = wday; + + mp_int_t qc_cycles = days / DAYS_PER_400Y; + days %= DAYS_PER_400Y; + if (days < 0) { + days += DAYS_PER_400Y; + qc_cycles--; + } + mp_int_t c_cycles = days / DAYS_PER_100Y; + if (c_cycles == 4) { + c_cycles--; + } + days -= (c_cycles * DAYS_PER_100Y); + + mp_int_t q_cycles = days / DAYS_PER_4Y; + if (q_cycles == 25) { + q_cycles--; + } + days -= q_cycles * DAYS_PER_4Y; + + mp_int_t years = days / 365; + if (years == 4) { + years--; + } + days -= (years * 365); + + /* We will compute tm_yday at the very end + mp_int_t leap = !years && (q_cycles || !c_cycles); + + tm->tm_yday = days + 31 + 28 + leap; + if (tm->tm_yday >= 365 + leap) { + tm->tm_yday -= 365 + leap; + } + + tm->tm_yday++; // Make one based + */ + + tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; + + // Note: days_in_month[0] corresponds to March + STATIC const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; + + mp_int_t month; + for (month = 0; days_in_month[month] <= days; month++) { + days -= days_in_month[month]; + } + + tm->tm_mon = month + 2; + if (tm->tm_mon >= 12) { + tm->tm_mon -= 12; + tm->tm_year++; + } + tm->tm_mday = days + 1; // Make one based + tm->tm_mon++; // Make one based + + tm->tm_yday = timeutils_year_day(tm->tm_year, tm->tm_mon, tm->tm_mday); +} + +// returns the number of seconds, as an integer, since 2000-01-01 +mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, + mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return + second + + minute * 60 + + hour * 3600 + + (timeutils_year_day(year, month, date) - 1 + + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001 + - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001 + + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001 + ) * 86400 + + (year - 2000) * 31536000; +} + +mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + + // Normalize the tuple. This allows things like: + // + // tm_tomorrow = list(time.localtime()) + // tm_tomorrow[2] += 1 # Adds 1 to mday + // tomorrow = time.mktime(tm_tomorrow) + // + // And not have to worry about all the weird overflows. + // + // You can subtract dates/times this way as well. + + minutes += seconds / 60; + if ((seconds = seconds % 60) < 0) { + seconds += 60; + minutes--; + } + + hours += minutes / 60; + if ((minutes = minutes % 60) < 0) { + minutes += 60; + hours--; + } + + mday += hours / 24; + if ((hours = hours % 24) < 0) { + hours += 24; + mday--; + } + + month--; // make month zero based + year += month / 12; + if ((month = month % 12) < 0) { + month += 12; + year--; + } + month++; // back to one based + + while (mday < 1) { + if (--month == 0) { + month = 12; + year--; + } + mday += timeutils_days_in_month(year, month); + } + while ((mp_uint_t)mday > timeutils_days_in_month(year, month)) { + mday -= timeutils_days_in_month(year, month); + if (++month == 13) { + month = 1; + year++; + } + } + return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds); +} diff --git a/src/openmv/src/micropython/lib/timeutils/timeutils.h b/src/openmv/src/micropython/lib/timeutils/timeutils.h new file mode 100755 index 0000000..9b1abeb --- /dev/null +++ b/src/openmv/src/micropython/lib/timeutils/timeutils.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H +#define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H + +typedef struct _timeutils_struct_time_t { + uint16_t tm_year; // i.e. 2014 + uint8_t tm_mon; // 1..12 + uint8_t tm_mday; // 1..31 + uint8_t tm_hour; // 0..23 + uint8_t tm_min; // 0..59 + uint8_t tm_sec; // 0..59 + uint8_t tm_wday; // 0..6 0 = Monday + uint16_t tm_yday; // 1..366 +} timeutils_struct_time_t; + +bool timeutils_is_leap_year(mp_uint_t year); +mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); +mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); + +void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, + timeutils_struct_time_t *tm); + +mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, + mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); + +mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds); + +#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H diff --git a/src/openmv/src/micropython/lib/tinytest/README b/src/openmv/src/micropython/lib/tinytest/README new file mode 100755 index 0000000..902c4a2 --- /dev/null +++ b/src/openmv/src/micropython/lib/tinytest/README @@ -0,0 +1,18 @@ +Tinytest is a tiny little test framework written in C by Nick Mathewson. + +It is distributed under the 3-clause BSD license. You can use it in +your own programs so long as you follow the license's conditions. + +It's been tested on Windows, Mac, and many of the free Unixes. + +It knows how to fork before running certain tests, and it makes +text-mode output in a format I like. + +For info on how to use it, check out tinytest_demo.c. + +You can get the latest version using Git, by pulling from + git://github.com/nmathewson/tinytest.git + +Patches are welcome. Patches that turn this from tinytest to hugetest +will not be applied. If you want a huge test framework, use CUnit. + diff --git a/src/openmv/src/micropython/lib/tinytest/tinytest.c b/src/openmv/src/micropython/lib/tinytest/tinytest.c new file mode 100755 index 0000000..01772f3 --- /dev/null +++ b/src/openmv/src/micropython/lib/tinytest/tinytest.c @@ -0,0 +1,477 @@ +/* tinytest.c -- Copyright 2009-2012 Nick Mathewson + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 TINYTEST_LOCAL +#include "tinytest_local.h" +#endif + +#include +#include +#include +#include + +#ifndef NO_FORKING + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) +/* Workaround for a stupid bug in OSX 10.6 */ +#define FORK_BREAKS_GCOV +#include +#endif +#endif + +#endif /* !NO_FORKING */ + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +#include "tinytest.h" +#include "tinytest_macros.h" + +#define LONGEST_TEST_NAME 16384 + +static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ +static int n_ok = 0; /**< Number of tests that have passed */ +static int n_bad = 0; /**< Number of tests that have failed. */ +static int n_skipped = 0; /**< Number of tests that have been skipped. */ + +static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ +static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ +static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ +const char *verbosity_flag = ""; + +const struct testlist_alias_t *cfg_aliases=NULL; + +enum outcome { SKIP=2, OK=1, FAIL=0 }; +static enum outcome cur_test_outcome = 0; +const char *cur_test_prefix = NULL; /**< prefix of the current test group */ +/** Name of the current test, if we haven't logged is yet. Used for --quiet */ +const char *cur_test_name = NULL; + +#ifdef _WIN32 +/* Copy of argv[0] for win32. */ +static char commandname[MAX_PATH+1]; +#endif + +static void usage(struct testgroup_t *groups, int list_groups) + __attribute__((noreturn)); +static int process_test_option(struct testgroup_t *groups, const char *test); + +static enum outcome +testcase_run_bare_(const struct testcase_t *testcase) +{ + void *env = NULL; + int outcome; + if (testcase->setup) { + env = testcase->setup->setup_fn(testcase); + if (!env) + return FAIL; + else if (env == (void*)TT_SKIP) + return SKIP; + } + + cur_test_outcome = OK; + testcase->fn(env); + outcome = cur_test_outcome; + + if (testcase->setup) { + if (testcase->setup->cleanup_fn(testcase, env) == 0) + outcome = FAIL; + } + + return outcome; +} + +#define MAGIC_EXITCODE 42 + +#ifndef NO_FORKING + +static enum outcome +testcase_run_forked_(const struct testgroup_t *group, + const struct testcase_t *testcase) +{ +#ifdef _WIN32 + /* Fork? On Win32? How primitive! We'll do what the smart kids do: + we'll invoke our own exe (whose name we recall from the command + line) with a command line that tells it to run just the test we + want, and this time without forking. + + (No, threads aren't an option. The whole point of forking is to + share no state between tests.) + */ + int ok; + char buffer[LONGEST_TEST_NAME+256]; + STARTUPINFOA si; + PROCESS_INFORMATION info; + DWORD exitcode; + + if (!in_tinytest_main) { + printf("\nERROR. On Windows, testcase_run_forked_ must be" + " called from within tinytest_main.\n"); + abort(); + } + if (opt_verbosity>0) + printf("[forking] "); + + snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", + commandname, verbosity_flag, group->prefix, testcase->name); + + memset(&si, 0, sizeof(si)); + memset(&info, 0, sizeof(info)); + si.cb = sizeof(si); + + ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, + 0, NULL, NULL, &si, &info); + if (!ok) { + printf("CreateProcess failed!\n"); + return 0; + } + WaitForSingleObject(info.hProcess, INFINITE); + GetExitCodeProcess(info.hProcess, &exitcode); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + if (exitcode == 0) + return OK; + else if (exitcode == MAGIC_EXITCODE) + return SKIP; + else + return FAIL; +#else + int outcome_pipe[2]; + pid_t pid; + (void)group; + + if (pipe(outcome_pipe)) + perror("opening pipe"); + + if (opt_verbosity>0) + printf("[forking] "); + pid = fork(); +#ifdef FORK_BREAKS_GCOV + vproc_transaction_begin(0); +#endif + if (!pid) { + /* child. */ + int test_r, write_r; + char b[1]; + close(outcome_pipe[0]); + test_r = testcase_run_bare_(testcase); + assert(0<=(int)test_r && (int)test_r<=2); + b[0] = "NYS"[test_r]; + write_r = (int)write(outcome_pipe[1], b, 1); + if (write_r != 1) { + perror("write outcome to pipe"); + exit(1); + } + exit(0); + return FAIL; /* unreachable */ + } else { + /* parent */ + int status, r; + char b[1]; + /* Close this now, so that if the other side closes it, + * our read fails. */ + close(outcome_pipe[1]); + r = (int)read(outcome_pipe[0], b, 1); + if (r == 0) { + printf("[Lost connection!] "); + return 0; + } else if (r != 1) { + perror("read outcome from pipe"); + } + waitpid(pid, &status, 0); + close(outcome_pipe[0]); + return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); + } +#endif +} + +#endif /* !NO_FORKING */ + +int +testcase_run_one(const struct testgroup_t *group, + const struct testcase_t *testcase) +{ + enum outcome outcome; + + if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { + if (opt_verbosity>0) + printf("%s%s: %s\n", + group->prefix, testcase->name, + (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); + ++n_skipped; + return SKIP; + } + + printf("# starting %s%s\n", group->prefix, testcase->name); + if (opt_verbosity>0 && !opt_forked) { + //printf("%s%s: ", group->prefix, testcase->name); + } else { + if (opt_verbosity==0) printf("."); + cur_test_prefix = group->prefix; + cur_test_name = testcase->name; + } + +#ifndef NO_FORKING + if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { + outcome = testcase_run_forked_(group, testcase); + } else { +#else + { +#endif + outcome = testcase_run_bare_(testcase); + } + + printf("%s%s: ", group->prefix, testcase->name); + if (outcome == OK) { + ++n_ok; + if (opt_verbosity>0 && !opt_forked) + puts(opt_verbosity==1?"OK":""); + } else if (outcome == SKIP) { + ++n_skipped; + if (opt_verbosity>0 && !opt_forked) + puts("SKIPPED"); + } else { + ++n_bad; + if (!opt_forked) + //printf("\n [%s FAILED]\n", testcase->name); + puts("FAILED"); + } + + if (opt_forked) { + exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); + return 1; /* unreachable */ + } else { + return (int)outcome; + } +} + +int +tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) +{ + int i, j; + size_t length = LONGEST_TEST_NAME; + char fullname[LONGEST_TEST_NAME]; + int found=0; + if (strstr(arg, "..")) + length = strstr(arg,"..")-arg; + for (i=0; groups[i].prefix; ++i) { + for (j=0; groups[i].cases[j].name; ++j) { + struct testcase_t *testcase = &groups[i].cases[j]; + snprintf(fullname, sizeof(fullname), "%s%s", + groups[i].prefix, testcase->name); + if (!flag) { /* Hack! */ + printf(" %s", fullname); + if (testcase->flags & TT_OFF_BY_DEFAULT) + puts(" (Off by default)"); + else if (testcase->flags & TT_SKIP) + puts(" (DISABLED)"); + else + puts(""); + } + if (!strncmp(fullname, arg, length)) { + if (set) + testcase->flags |= flag; + else + testcase->flags &= ~flag; + ++found; + } + } + } + return found; +} + +static void +usage(struct testgroup_t *groups, int list_groups) +{ + puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); + puts(" Specify tests by name, or using a prefix ending with '..'"); + puts(" To skip a test, prefix its name with a colon."); + puts(" To enable a disabled test, prefix its name with a plus."); + puts(" Use --list-tests for a list of tests."); + if (list_groups) { + puts("Known tests are:"); + tinytest_set_flag_(groups, "..", 1, 0); + } + exit(0); +} + +static int +process_test_alias(struct testgroup_t *groups, const char *test) +{ + int i, j, n, r; + for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { + if (!strcmp(cfg_aliases[i].name, test)) { + n = 0; + for (j = 0; cfg_aliases[i].tests[j]; ++j) { + r = process_test_option(groups, cfg_aliases[i].tests[j]); + if (r<0) + return -1; + n += r; + } + return n; + } + } + printf("No such test alias as @%s!",test); + return -1; +} + +static int +process_test_option(struct testgroup_t *groups, const char *test) +{ + int flag = TT_ENABLED_; + int n = 0; + if (test[0] == '@') { + return process_test_alias(groups, test + 1); + } else if (test[0] == ':') { + ++test; + flag = TT_SKIP; + } else if (test[0] == '+') { + ++test; + ++n; + if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { + printf("No such test as %s!\n", test); + return -1; + } + } else { + ++n; + } + if (!tinytest_set_flag_(groups, test, 1, flag)) { + printf("No such test as %s!\n", test); + return -1; + } + return n; +} + +void +tinytest_set_aliases(const struct testlist_alias_t *aliases) +{ + cfg_aliases = aliases; +} + +int +tinytest_main(int c, const char **v, struct testgroup_t *groups) +{ + int i, j, n=0; + +#ifdef _WIN32 + const char *sp = strrchr(v[0], '.'); + const char *extension = ""; + if (!sp || stricmp(sp, ".exe")) + extension = ".exe"; /* Add an exe so CreateProcess will work */ + snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); + commandname[MAX_PATH]='\0'; +#endif + for (i=1; i= 1) + printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); + + return (n_bad == 0) ? 0 : 1; +} + +int +tinytest_get_verbosity_(void) +{ + return opt_verbosity; +} + +void +tinytest_set_test_failed_(void) +{ + if (opt_verbosity <= 0 && cur_test_name) { + if (opt_verbosity==0) puts(""); + printf("%s%s: ", cur_test_prefix, cur_test_name); + cur_test_name = NULL; + } + cur_test_outcome = 0; +} + +void +tinytest_set_test_skipped_(void) +{ + if (cur_test_outcome==OK) + cur_test_outcome = SKIP; +} + diff --git a/src/openmv/src/micropython/lib/tinytest/tinytest.h b/src/openmv/src/micropython/lib/tinytest/tinytest.h new file mode 100755 index 0000000..dff440e --- /dev/null +++ b/src/openmv/src/micropython/lib/tinytest/tinytest.h @@ -0,0 +1,98 @@ +/* tinytest.h -- Copyright 2009-2012 Nick Mathewson + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 TINYTEST_H_INCLUDED_ +#define TINYTEST_H_INCLUDED_ + +/** Flag for a test that needs to run in a subprocess. */ +#define TT_FORK (1<<0) +/** Runtime flag for a test we've decided to skip. */ +#define TT_SKIP (1<<1) +/** Internal runtime flag for a test we've decided to run. */ +#define TT_ENABLED_ (1<<2) +/** Flag for a test that's off by default. */ +#define TT_OFF_BY_DEFAULT (1<<3) +/** If you add your own flags, make them start at this point. */ +#define TT_FIRST_USER_FLAG (1<<4) + +typedef void (*testcase_fn)(void *); + +struct testcase_t; + +/** Functions to initialize/teardown a structure for a testcase. */ +struct testcase_setup_t { + /** Return a new structure for use by a given testcase. */ + void *(*setup_fn)(const struct testcase_t *); + /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ + int (*cleanup_fn)(const struct testcase_t *, void *); +}; + +/** A single test-case that you can run. */ +struct testcase_t { + const char *name; /**< An identifier for this case. */ + testcase_fn fn; /**< The function to run to implement this case. */ + unsigned long flags; /**< Bitfield of TT_* flags. */ + const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ + void *setup_data; /**< Extra data usable by setup function */ +}; +#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } + +/** A group of tests that are selectable together. */ +struct testgroup_t { + const char *prefix; /**< Prefix to prepend to testnames. */ + struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ +}; +#define END_OF_GROUPS { NULL, NULL} + +struct testlist_alias_t { + const char *name; + const char **tests; +}; +#define END_OF_ALIASES { NULL, NULL } + +/** Implementation: called from a test to indicate failure, before logging. */ +void tinytest_set_test_failed_(void); +/** Implementation: called from a test to indicate that we're skipping. */ +void tinytest_set_test_skipped_(void); +/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */ +int tinytest_get_verbosity_(void); +/** Implementation: Set a flag on tests matching a name; returns number + * of tests that matched. */ +int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); + +/** Set all tests in 'groups' matching the name 'named' to be skipped. */ +#define tinytest_skip(groups, named) \ + tinytest_set_flag_(groups, named, 1, TT_SKIP) + +/** Run a single testcase in a single group. */ +int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); + +void tinytest_set_aliases(const struct testlist_alias_t *aliases); + +/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups, + as selected from the command line. */ +int tinytest_main(int argc, const char **argv, struct testgroup_t *groups); + +#endif diff --git a/src/openmv/src/micropython/lib/tinytest/tinytest_macros.h b/src/openmv/src/micropython/lib/tinytest/tinytest_macros.h new file mode 100755 index 0000000..9ff69b1 --- /dev/null +++ b/src/openmv/src/micropython/lib/tinytest/tinytest_macros.h @@ -0,0 +1,184 @@ +/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 TINYTEST_MACROS_H_INCLUDED_ +#define TINYTEST_MACROS_H_INCLUDED_ + +/* Helpers for defining statement-like macros */ +#define TT_STMT_BEGIN do { +#define TT_STMT_END } while (0) + +/* Redefine this if your test functions want to abort with something besides + * "goto end;" */ +#ifndef TT_EXIT_TEST_FUNCTION +#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END +#endif + +/* Redefine this if you want to note success/failure in some different way. */ +#ifndef TT_DECLARE +#define TT_DECLARE(prefix, args) \ + TT_STMT_BEGIN \ + printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ + printf args ; \ + TT_STMT_END +#endif + +/* Announce a failure. Args are parenthesized printf args. */ +#define TT_GRIPE(args) TT_DECLARE("FAIL", args) + +/* Announce a non-failure if we're verbose. */ +#define TT_BLATHER(args) \ + TT_STMT_BEGIN \ + if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ + TT_STMT_END + +#define TT_DIE(args) \ + TT_STMT_BEGIN \ + tinytest_set_test_failed_(); \ + TT_GRIPE(args); \ + TT_EXIT_TEST_FUNCTION; \ + TT_STMT_END + +#define TT_FAIL(args) \ + TT_STMT_BEGIN \ + tinytest_set_test_failed_(); \ + TT_GRIPE(args); \ + TT_STMT_END + +/* Fail and abort the current test for the reason in msg */ +#define tt_abort_printf(msg) TT_DIE(msg) +#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) +#define tt_abort_msg(msg) TT_DIE(("%s", msg)) +#define tt_abort() TT_DIE(("%s", "(Failed.)")) + +/* Fail but do not abort the current test for the reason in msg. */ +#define tt_failprint_f(msg) TT_FAIL(msg) +#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) +#define tt_fail_msg(msg) TT_FAIL(("%s", msg)) +#define tt_fail() TT_FAIL(("%s", "(Failed.)")) + +/* End the current test, and indicate we are skipping it. */ +#define tt_skip() \ + TT_STMT_BEGIN \ + tinytest_set_test_skipped_(); \ + TT_EXIT_TEST_FUNCTION; \ + TT_STMT_END + +#define tt_want_(b, msg, fail) \ + TT_STMT_BEGIN \ + if (!(b)) { \ + tinytest_set_test_failed_(); \ + TT_GRIPE(("%s",msg)); \ + fail; \ + } else { \ + TT_BLATHER(("%s",msg)); \ + } \ + TT_STMT_END + +/* Assert b, but do not stop the test if b fails. Log msg on failure. */ +#define tt_want_msg(b, msg) \ + tt_want_(b, msg, ); + +/* Assert b and stop the test if b fails. Log msg on failure. */ +#define tt_assert_msg(b, msg) \ + tt_want_(b, msg, TT_EXIT_TEST_FUNCTION); + +/* Assert b, but do not stop the test if b fails. */ +#define tt_want(b) tt_want_msg( (b), "want("#b")") +/* Assert b, and stop the test if b fails. */ +#define tt_assert(b) tt_assert_msg((b), "assert("#b")") + +#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ + setup_block,cleanup_block,die_on_fail) \ + TT_STMT_BEGIN \ + type val1_ = (type)(a); \ + type val2_ = (type)(b); \ + int tt_status_ = (test); \ + if (!tt_status_ || tinytest_get_verbosity_()>1) { \ + printf_type print_; \ + printf_type print1_; \ + printf_type print2_; \ + type value_ = val1_; \ + setup_block; \ + print1_ = print_; \ + value_ = val2_; \ + setup_block; \ + print2_ = print_; \ + TT_DECLARE(tt_status_?" OK":"FAIL", \ + ("assert(%s): "printf_fmt" vs "printf_fmt, \ + str_test, print1_, print2_)); \ + print_ = print1_; \ + cleanup_block; \ + print_ = print2_; \ + cleanup_block; \ + if (!tt_status_) { \ + tinytest_set_test_failed_(); \ + die_on_fail ; \ + } \ + } \ + TT_STMT_END + +#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ + tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ + {print_=value_;},{},die_on_fail) + +/* Helper: assert that a op b, when cast to type. Format the values with + * printf format fmt on failure. */ +#define tt_assert_op_type(a,op,b,type,fmt) \ + tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ + TT_EXIT_TEST_FUNCTION) + +#define tt_int_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ + "%ld",TT_EXIT_TEST_FUNCTION) + +#define tt_uint_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ + (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) + +#define tt_ptr_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ + (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) + +#define tt_str_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ + (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION) + +#define tt_want_int_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) + +#define tt_want_uint_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ + (val1_ op val2_),"%lu",(void)0) + +#define tt_want_ptr_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ + (val1_ op val2_),"%p",(void)0) + +#define tt_want_str_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ + (strcmp(val1_,val2_) op 0),"<%s>",(void)0) + +#endif diff --git a/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.c b/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.c new file mode 100755 index 0000000..d28c5b9 --- /dev/null +++ b/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/mphal.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/compile.h" +#include "upytesthelper.h" + +static const char *test_exp_output; +static int test_exp_output_len, test_rem_output_len; +static int test_failed; +static void *heap_start, *heap_end; + +void upytest_set_heap(void *start, void *end) { + heap_start = start; + heap_end = end; +} + +void upytest_set_expected_output(const char *output, unsigned len) { + test_exp_output = output; + test_exp_output_len = test_rem_output_len = len; + test_failed = false; +} + +bool upytest_is_failed(void) { + if (test_failed) { + return true; + } + #if 0 + if (test_rem_output_len != 0) { + printf("remaining len: %d\n", test_rem_output_len); + } + #endif + return test_rem_output_len != 0; +} + +// MP_PLAT_PRINT_STRN() should be redirected to this function. +// It will pass-thru any content to mp_hal_stdout_tx_strn_cooked() +// (the dfault value of MP_PLAT_PRINT_STRN), but will also match +// it to the expected output as set by upytest_set_expected_output(). +// If mismatch happens, upytest_is_failed() returns true. +void upytest_output(const char *str, mp_uint_t len) { + if (!test_failed) { + if (len > test_rem_output_len) { + test_failed = true; + } else { + test_failed = memcmp(test_exp_output, str, len); + #if 0 + if (test_failed) { + printf("failed after char %u, within %d chars, res: %d\n", + test_exp_output_len - test_rem_output_len, (int)len, test_failed); + for (int i = 0; i < len; i++) { + if (str[i] != test_exp_output[i]) { + printf("%d %02x %02x\n", i, str[i], test_exp_output[i]); + } + } + } + #endif + test_exp_output += len; + test_rem_output_len -= len; + } + } + mp_hal_stdout_tx_strn_cooked(str, len); +} + +void upytest_execute_test(const char *src) { + // To provide clean room for each test, interpreter and heap are + // reinitialized before running each. + gc_init(heap_start, heap_end); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { + // Assume that sys.exit() is called to skip the test. + // TODO: That can be always true, we should set up convention to + // use specific exit code as skip indicator. + tinytest_set_test_skipped_(); + goto end; + } + mp_obj_print_exception(&mp_plat_print, exc); + tt_abort_msg("Uncaught exception\n"); + } + + if (upytest_is_failed()) { + tinytest_set_test_failed_(); + } + +end: + mp_deinit(); +} diff --git a/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.h b/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.h new file mode 100755 index 0000000..3a292be --- /dev/null +++ b/src/openmv/src/micropython/lib/upytesthelper/upytesthelper.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/mpconfig.h" +#include "lib/tinytest/tinytest.h" +#include "lib/tinytest/tinytest_macros.h" + +void upytest_set_heap(void *start, void *end); +void upytest_set_expected_output(const char *output, unsigned len); +void upytest_execute_test(const char *src); +void upytest_output(const char *str, mp_uint_t len); +bool upytest_is_failed(void); diff --git a/src/openmv/src/micropython/lib/utils/interrupt_char.c b/src/openmv/src/micropython/lib/utils/interrupt_char.c new file mode 100755 index 0000000..fca0f95 --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/interrupt_char.c @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/mpstate.h" + +#if MICROPY_KBD_EXCEPTION + +int mp_interrupt_char; + +void mp_hal_set_interrupt_char(int c) { + if (c != -1) { + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + } + mp_interrupt_char = c; +} + +void mp_keyboard_interrupt(void) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + #if MICROPY_ENABLE_SCHEDULER + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + #endif +} + +#endif diff --git a/src/openmv/src/micropython/lib/utils/interrupt_char.h b/src/openmv/src/micropython/lib/utils/interrupt_char.h new file mode 100755 index 0000000..ca50d4d --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/interrupt_char.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H +#define MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H + +extern int mp_interrupt_char; +void mp_hal_set_interrupt_char(int c); +void mp_keyboard_interrupt(void); + +#endif // MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H diff --git a/src/openmv/src/micropython/lib/utils/printf.c b/src/openmv/src/micropython/lib/utils/printf.c new file mode 100755 index 0000000..1ceeea3 --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/printf.c @@ -0,0 +1,131 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +#include +#include +#include + +#include "py/obj.h" +#include "py/mphal.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include "py/formatfloat.h" +#endif + +#if MICROPY_DEBUG_PRINTERS +int DEBUG_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(MICROPY_DEBUG_PRINTER, fmt, ap); + va_end(ap); + return ret; +} +#endif + +#if MICROPY_USE_INTERNAL_PRINTF + +#undef putchar // Some stdlibs have a #define for putchar +int printf(const char *fmt, ...); +int vprintf(const char *fmt, va_list ap); +int putchar(int c); +int puts(const char *s); +int vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int snprintf(char *str, size_t size, const char *fmt, ...); + +int printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(&mp_plat_print, fmt, ap); + va_end(ap); + return ret; +} + +int vprintf(const char *fmt, va_list ap) { + return mp_vprintf(&mp_plat_print, fmt, ap); +} + +// need this because gcc optimises printf("%c", c) -> putchar(c), and printf("a") -> putchar('a') +int putchar(int c) { + char chr = c; + mp_hal_stdout_tx_strn_cooked(&chr, 1); + return chr; +} + +// need this because gcc optimises printf("string\n") -> puts("string") +int puts(const char *s) { + mp_hal_stdout_tx_strn_cooked(s, strlen(s)); + char chr = '\n'; + mp_hal_stdout_tx_strn_cooked(&chr, 1); + return 1; +} + +typedef struct _strn_print_env_t { + char *cur; + size_t remain; +} strn_print_env_t; + +STATIC void strn_print_strn(void *data, const char *str, size_t len) { + strn_print_env_t *strn_print_env = data; + if (len > strn_print_env->remain) { + len = strn_print_env->remain; + } + memcpy(strn_print_env->cur, str, len); + strn_print_env->cur += len; + strn_print_env->remain -= len; +} + +#if defined(__GNUC__) && !defined(__clang__) +// uClibc requires this alias to be defined, or there may be link errors +// when linkings against it statically. +int __GI_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __attribute__((weak, alias ("vsnprintf"))); +#endif + +int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) { + strn_print_env_t strn_print_env = {str, size}; + mp_print_t print = {&strn_print_env, strn_print_strn}; + int len = mp_vprintf(&print, fmt, ap); + // add terminating null byte + if (size > 0) { + if (strn_print_env.remain == 0) { + strn_print_env.cur[-1] = 0; + } else { + strn_print_env.cur[0] = 0; + } + } + return len; +} + +int snprintf(char *str, size_t size, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = vsnprintf(str, size, fmt, ap); + va_end(ap); + return ret; +} + +#endif //MICROPY_USE_INTERNAL_PRINTF diff --git a/src/openmv/src/micropython/lib/utils/pyexec.c b/src/openmv/src/micropython/lib/utils/pyexec.c new file mode 100755 index 0000000..d8dc60b --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/pyexec.c @@ -0,0 +1,536 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/frozenmod.h" +#include "py/mphal.h" +#if MICROPY_HW_ENABLE_USB +#include "irq.h" +#include "usb.h" +#endif +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "genhdr/mpversion.h" + +pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; +int pyexec_system_exit = 0; +STATIC bool repl_display_debugging_info = 0; + +#define EXEC_FLAG_PRINT_EOF (1) +#define EXEC_FLAG_ALLOW_DEBUGGING (2) +#define EXEC_FLAG_IS_REPL (4) +#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8) +#define EXEC_FLAG_SOURCE_IS_VSTR (16) +#define EXEC_FLAG_SOURCE_IS_FILENAME (32) + +// parses, compiles and executes the code in the lexer +// frees the lexer before returning +// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output +// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code +// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile) +STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) { + int ret = 0; + uint32_t start = 0; + + // by default a SystemExit exception returns 0 + pyexec_system_exit = 0; + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t module_fun; + #if MICROPY_MODULE_FROZEN_MPY + if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { + // source is a raw_code object, create the function + module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL); + } else + #endif + { + #if MICROPY_ENABLE_COMPILER + mp_lexer_t *lex; + if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { + lex = mp_lexer_new_from_file(source); + } else { + lex = (mp_lexer_t*)source; + } + // source is a lexer, parse and compile the script + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL); + #else + mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported"); + #endif + } + + // execute code + mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us + start = mp_hal_ticks_ms(); + mp_call_function_0(module_fun); + mp_hal_set_interrupt_char(-1); // disable interrupt + nlr_pop(); + ret = 1; + if (exec_flags & EXEC_FLAG_PRINT_EOF) { + mp_hal_stdout_tx_strn("\x04", 1); + } + } else { + // uncaught exception + // FIXME it could be that an interrupt happens just before we disable it here + mp_hal_set_interrupt_char(-1); // disable interrupt + // print EOF after normal output + if (exec_flags & EXEC_FLAG_PRINT_EOF) { + mp_hal_stdout_tx_strn("\x04", 1); + } + // check for SystemExit + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + // at the moment, the value of SystemExit is unused + ret = pyexec_system_exit; + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + ret = 0; + } + } + + // display debugging info if wanted + if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { + mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly + printf("took " UINT_FMT " ms\n", ticks); + // qstr info + { + size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=%u\n n_qstr=%u\n " + "n_str_data_bytes=%u\n n_total_bytes=%u\n", + (unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes); + } + + #if MICROPY_ENABLE_GC + // run collection and print GC info + gc_collect(); + gc_dump_info(); + #endif + } + + if (exec_flags & EXEC_FLAG_PRINT_EOF) { + mp_hal_stdout_tx_strn("\x04", 1); + } + + return ret; +} + +#if MICROPY_ENABLE_COMPILER +#if MICROPY_REPL_EVENT_DRIVEN + +typedef struct _repl_t { + // This structure originally also held current REPL line, + // but it was moved to MP_STATE_VM(repl_line) as containing + // root pointer. Still keep structure in case more state + // will be added later. + //vstr_t line; + bool cont_line; +} repl_t; + +repl_t repl; + +STATIC int pyexec_raw_repl_process_char(int c); +STATIC int pyexec_friendly_repl_process_char(int c); + +void pyexec_event_repl_init(void) { + MP_STATE_VM(repl_line) = vstr_new(32); + repl.cont_line = false; + // no prompt before printing friendly REPL banner or entering raw REPL + readline_init(MP_STATE_VM(repl_line), ""); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + pyexec_raw_repl_process_char(CHAR_CTRL_A); + } else { + pyexec_friendly_repl_process_char(CHAR_CTRL_B); + } +} + +STATIC int pyexec_raw_repl_process_char(int c) { + if (c == CHAR_CTRL_A) { + // reset raw REPL + mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); + goto reset; + } else if (c == CHAR_CTRL_B) { + // change to friendly REPL + pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + vstr_reset(MP_STATE_VM(repl_line)); + repl.cont_line = false; + pyexec_friendly_repl_process_char(CHAR_CTRL_B); + return 0; + } else if (c == CHAR_CTRL_C) { + // clear line + vstr_reset(MP_STATE_VM(repl_line)); + return 0; + } else if (c == CHAR_CTRL_D) { + // input finished + } else { + // let through any other raw 8-bit value + vstr_add_byte(MP_STATE_VM(repl_line), c); + return 0; + } + + // indicate reception of command + mp_hal_stdout_tx_str("OK"); + + if (MP_STATE_VM(repl_line)->len == 0) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(MP_STATE_VM(repl_line)); + return PYEXEC_FORCED_EXIT; + } + + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + +reset: + vstr_reset(MP_STATE_VM(repl_line)); + mp_hal_stdout_tx_str(">"); + + return 0; +} + +STATIC int pyexec_friendly_repl_process_char(int c) { + int ret = readline_process_char(c); + + if (!repl.cont_line) { + + if (ret == CHAR_CTRL_A) { + // change to raw REPL + pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + mp_hal_stdout_tx_str("\r\n"); + pyexec_raw_repl_process_char(CHAR_CTRL_A); + return 0; + } else if (ret == CHAR_CTRL_B) { + // reset friendly REPL + mp_hal_stdout_tx_str("\r\n"); + mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + #if MICROPY_PY_BUILTINS_HELP + mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + #endif + goto input_restart; + } else if (ret == CHAR_CTRL_C) { + // break + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(MP_STATE_VM(repl_line)); + return PYEXEC_FORCED_EXIT; + } + + if (ret < 0) { + return 0; + } + + if (!mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) { + goto exec; + } + + vstr_add_byte(MP_STATE_VM(repl_line), '\n'); + repl.cont_line = true; + readline_note_newline("... "); + return 0; + + } else { + + if (ret == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + repl.cont_line = false; + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // stop entering compound statement + goto exec; + } + + if (ret < 0) { + return 0; + } + + if (mp_repl_continue_with_input(vstr_null_terminated_str(MP_STATE_VM(repl_line)))) { + vstr_add_byte(MP_STATE_VM(repl_line), '\n'); + readline_note_newline("... "); + return 0; + } + +exec: ; + int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + +input_restart: + vstr_reset(MP_STATE_VM(repl_line)); + repl.cont_line = false; + readline_init(MP_STATE_VM(repl_line), ">>> "); + return 0; + } +} + +uint8_t pyexec_repl_active; +int pyexec_event_repl_process_char(int c) { + pyexec_repl_active = 1; + int res; + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + res = pyexec_raw_repl_process_char(c); + } else { + res = pyexec_friendly_repl_process_char(c); + } + pyexec_repl_active = 0; + return res; +} + +#else // MICROPY_REPL_EVENT_DRIVEN + +int pyexec_raw_repl(void) { + vstr_t line; + vstr_init(&line, 32); + +raw_repl_reset: + mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); + + for (;;) { + vstr_reset(&line); + mp_hal_stdout_tx_str(">"); + for (;;) { + int c = mp_hal_stdin_rx_chr(); + if (c == CHAR_CTRL_A) { + // reset raw REPL + goto raw_repl_reset; + } else if (c == CHAR_CTRL_B) { + // change to friendly REPL + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&line); + pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + return 0; + } else if (c == CHAR_CTRL_C) { + // clear line + vstr_reset(&line); + } else if (c == CHAR_CTRL_D) { + // input finished + break; + } else { + // let through any other raw 8-bit value + vstr_add_byte(&line, c); + } + } + + // indicate reception of command + mp_hal_stdout_tx_str("OK"); + + if (line.len == 0) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&line); + return PYEXEC_FORCED_EXIT; + } + + int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + } +} + +int pyexec_friendly_repl(void) { + vstr_t line; + vstr_init(&line, 32); + +#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD + // in host mode, we enable the LCD for the repl + mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD"))); + mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true); +#endif + +friendly_repl_reset: + mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + #if MICROPY_PY_BUILTINS_HELP + mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + #endif + + // to test ctrl-C + /* + { + uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef}; + for (;;) { + nlr_buf_t nlr; + printf("pyexec_repl: %p\n", x); + mp_hal_set_interrupt_char(CHAR_CTRL_C); + if (nlr_push(&nlr) == 0) { + for (;;) { + } + } else { + printf("break\n"); + } + } + } + */ + + for (;;) { + input_restart: + + #if MICROPY_HW_ENABLE_USB + if (usb_vcp_is_enabled()) { + // If the user gets to here and interrupts are disabled then + // they'll never see the prompt, traceback etc. The USB REPL needs + // interrupts to be enabled or no transfers occur. So we try to + // do the user a favor and reenable interrupts. + if (query_irq() == IRQ_STATE_DISABLED) { + enable_irq(IRQ_STATE_ENABLED); + mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n"); + } + } + #endif + + // If the GC is locked at this point there is no way out except a reset, + // so force the GC to be unlocked to help the user debug what went wrong. + if (MP_STATE_MEM(gc_lock_depth) != 0) { + MP_STATE_MEM(gc_lock_depth) = 0; + } + + vstr_reset(&line); + int ret = readline(&line, ">>> "); + mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; + + if (ret == CHAR_CTRL_A) { + // change to raw REPL + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&line); + pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + return 0; + } else if (ret == CHAR_CTRL_B) { + // reset friendly REPL + mp_hal_stdout_tx_str("\r\n"); + goto friendly_repl_reset; + } else if (ret == CHAR_CTRL_C) { + // break + mp_hal_stdout_tx_str("\r\n"); + continue; + } else if (ret == CHAR_CTRL_D) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&line); + return PYEXEC_FORCED_EXIT; + } else if (ret == CHAR_CTRL_E) { + // paste mode + mp_hal_stdout_tx_str("\r\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\r\n=== "); + vstr_reset(&line); + for (;;) { + char c = mp_hal_stdin_rx_chr(); + if (c == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (c == CHAR_CTRL_D) { + // end of input + mp_hal_stdout_tx_str("\r\n"); + break; + } else { + // add char to buffer and echo + vstr_add_byte(&line, c); + if (c == '\r') { + mp_hal_stdout_tx_str("\r\n=== "); + } else { + mp_hal_stdout_tx_strn(&c, 1); + } + } + } + parse_input_kind = MP_PARSE_FILE_INPUT; + } else if (vstr_len(&line) == 0) { + continue; + } else { + // got a line with non-zero length, see if it needs continuing + while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { + vstr_add_byte(&line, '\n'); + ret = readline(&line, "... "); + if (ret == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // stop entering compound statement + break; + } + } + } + + ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + } +} + +#endif // MICROPY_REPL_EVENT_DRIVEN +#endif // MICROPY_ENABLE_COMPILER + +int pyexec_file(const char *filename) { + return parse_compile_execute(filename, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_FILENAME); +} + +#if MICROPY_MODULE_FROZEN +int pyexec_frozen_module(const char *name) { + void *frozen_data; + int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data); + + switch (frozen_type) { + #if MICROPY_MODULE_FROZEN_STR + case MP_FROZEN_STR: + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0); + #endif + + #if MICROPY_MODULE_FROZEN_MPY + case MP_FROZEN_MPY: + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE); + #endif + + default: + printf("could not find module '%s'\n", name); + return false; + } +} +#endif + +mp_obj_t pyb_set_repl_info(mp_obj_t o_value) { + repl_display_debugging_info = mp_obj_get_int(o_value); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info); diff --git a/src/openmv/src/micropython/lib/utils/pyexec.h b/src/openmv/src/micropython/lib/utils/pyexec.h new file mode 100755 index 0000000..a0d0b52 --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/pyexec.h @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H +#define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H + +#include "py/obj.h" + +typedef enum { + PYEXEC_MODE_RAW_REPL, + PYEXEC_MODE_FRIENDLY_REPL, +} pyexec_mode_kind_t; + +extern pyexec_mode_kind_t pyexec_mode_kind; + +// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through +// the pyexec functions if a SystemExit exception is raised by the running code. +// It will reset to 0 at the start of each execution (eg each REPL entry). +extern int pyexec_system_exit; + +#define PYEXEC_FORCED_EXIT (0x100) +#define PYEXEC_SWITCH_MODE (0x200) + +int pyexec_raw_repl(void); +int pyexec_friendly_repl(void); +int pyexec_file(const char *filename); +int pyexec_frozen_module(const char *name); +void pyexec_event_repl_init(void); +int pyexec_event_repl_process_char(int c); +extern uint8_t pyexec_repl_active; +mp_obj_t pyb_set_repl_info(mp_obj_t o_value); + +MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj); + +#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H diff --git a/src/openmv/src/micropython/lib/utils/stdout_helpers.c b/src/openmv/src/micropython/lib/utils/stdout_helpers.c new file mode 100755 index 0000000..3de1197 --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/stdout_helpers.c @@ -0,0 +1,26 @@ +#include +#include +#include "py/mpconfig.h" +#include "py/mphal.h" + +/* + * Extra stdout functions + * These can be either optimized for a particular port, or reference + * implementation below can be used. + */ + +// Send "cooked" string of given length, where every occurrence of +// LF character is replaced with CR LF. +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + while (len--) { + if (*str == '\n') { + mp_hal_stdout_tx_strn("\r", 1); + } + mp_hal_stdout_tx_strn(str++, 1); + } +} + +// Send zero-terminated string +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} diff --git a/src/openmv/src/micropython/lib/utils/sys_stdio_mphal.c b/src/openmv/src/micropython/lib/utils/sys_stdio_mphal.c new file mode 100755 index 0000000..234db08 --- /dev/null +++ b/src/openmv/src/micropython/lib/utils/sys_stdio_mphal.c @@ -0,0 +1,163 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" + +// TODO make stdin, stdout and stderr writable objects so they can +// be changed by Python code. This requires some changes, as these +// objects are in a read-only module (py/modsys.c). + +/******************************************************************************/ +// MicroPython bindings + +#define STDIO_FD_IN (0) +#define STDIO_FD_OUT (1) +#define STDIO_FD_ERR (2) + +typedef struct _sys_stdio_obj_t { + mp_obj_base_t base; + int fd; +} sys_stdio_obj_t; + +#if MICROPY_PY_SYS_STDIO_BUFFER +STATIC const sys_stdio_obj_t stdio_buffer_obj; +#endif + +void stdio_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->fd); +} + +STATIC mp_uint_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->fd == STDIO_FD_IN) { + for (uint i = 0; i < size; i++) { + int c = mp_hal_stdin_rx_chr(); + if (c == '\r') { + c = '\n'; + } + ((byte*)buf)[i] = c; + } + return size; + } else { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } +} + +STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->fd == STDIO_FD_OUT || self->fd == STDIO_FD_ERR) { + mp_hal_stdout_tx_strn_cooked(buf, size); + return size; + } else { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t stdio_obj___exit__(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stdio_obj___exit___obj, 4, 4, stdio_obj___exit__); + +// TODO gc hook to close the file if not already closed + +STATIC const mp_rom_map_elem_t stdio_locals_dict_table[] = { +#if MICROPY_PY_SYS_STDIO_BUFFER + { MP_ROM_QSTR(MP_QSTR_buffer), MP_ROM_PTR(&stdio_buffer_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)}, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stdio_obj___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(stdio_locals_dict, stdio_locals_dict_table); + +STATIC const mp_stream_p_t stdio_obj_stream_p = { + .read = stdio_read, + .write = stdio_write, + .is_text = true, +}; + +STATIC const mp_obj_type_t stdio_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + // TODO .make_new? + .print = stdio_obj_print, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &stdio_obj_stream_p, + .locals_dict = (mp_obj_dict_t*)&stdio_locals_dict, +}; + +const sys_stdio_obj_t mp_sys_stdin_obj = {{&stdio_obj_type}, .fd = STDIO_FD_IN}; +const sys_stdio_obj_t mp_sys_stdout_obj = {{&stdio_obj_type}, .fd = STDIO_FD_OUT}; +const sys_stdio_obj_t mp_sys_stderr_obj = {{&stdio_obj_type}, .fd = STDIO_FD_ERR}; + +#if MICROPY_PY_SYS_STDIO_BUFFER +STATIC mp_uint_t stdio_buffer_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + for (uint i = 0; i < size; i++) { + ((byte*)buf)[i] = mp_hal_stdin_rx_chr(); + } + return size; +} + +STATIC mp_uint_t stdio_buffer_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mp_hal_stdout_tx_strn(buf, size); + return size; +} + +STATIC const mp_stream_p_t stdio_buffer_obj_stream_p = { + .read = stdio_buffer_read, + .write = stdio_buffer_write, + .is_text = false, +}; + +STATIC const mp_obj_type_t stdio_buffer_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = stdio_obj_print, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &stdio_buffer_obj_stream_p, + .locals_dict = (mp_obj_dict_t*)&stdio_locals_dict, +}; + +STATIC const sys_stdio_obj_t stdio_buffer_obj = {{&stdio_buffer_obj_type}, .fd = 0}; // fd unused +#endif diff --git a/src/openmv/src/micropython/logo/1bit-logo.png b/src/openmv/src/micropython/logo/1bit-logo.png new file mode 100755 index 0000000..42927f3 Binary files /dev/null and b/src/openmv/src/micropython/logo/1bit-logo.png differ diff --git a/src/openmv/src/micropython/logo/FONT-LICENSE.txt b/src/openmv/src/micropython/logo/FONT-LICENSE.txt new file mode 100755 index 0000000..69c49d8 --- /dev/null +++ b/src/openmv/src/micropython/logo/FONT-LICENSE.txt @@ -0,0 +1,97 @@ +The font used for the MicroPython logo is "Exo", +http://www.google.com/fonts/specimen/Exo. + +Copyright (c) 2013, Natanael Gama (https://plus.google.com/u/0/+NatanaelGama), +with Reserved Font Name Exo. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/openmv/src/micropython/logo/logo.jpg b/src/openmv/src/micropython/logo/logo.jpg new file mode 100755 index 0000000..377aa8a Binary files /dev/null and b/src/openmv/src/micropython/logo/logo.jpg differ diff --git a/src/openmv/src/micropython/logo/micropythonpowered-art.png b/src/openmv/src/micropython/logo/micropythonpowered-art.png new file mode 100755 index 0000000..9045bb0 Binary files /dev/null and b/src/openmv/src/micropython/logo/micropythonpowered-art.png differ diff --git a/src/openmv/src/micropython/logo/trans-logo.png b/src/openmv/src/micropython/logo/trans-logo.png new file mode 100755 index 0000000..b114d90 Binary files /dev/null and b/src/openmv/src/micropython/logo/trans-logo.png differ diff --git a/src/openmv/src/micropython/logo/upython-with-micro.jpg b/src/openmv/src/micropython/logo/upython-with-micro.jpg new file mode 100755 index 0000000..4984d8e Binary files /dev/null and b/src/openmv/src/micropython/logo/upython-with-micro.jpg differ diff --git a/src/openmv/src/micropython/logo/upython-with-micro.png b/src/openmv/src/micropython/logo/upython-with-micro.png new file mode 100755 index 0000000..2b3431c Binary files /dev/null and b/src/openmv/src/micropython/logo/upython-with-micro.png differ diff --git a/src/openmv/src/micropython/logo/vector-logo-2-BW.svg b/src/openmv/src/micropython/logo/vector-logo-2-BW.svg new file mode 100755 index 0000000..d7ff920 --- /dev/null +++ b/src/openmv/src/micropython/logo/vector-logo-2-BW.svg @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/logo/vector-logo-2.png b/src/openmv/src/micropython/logo/vector-logo-2.png new file mode 100755 index 0000000..72ce88e Binary files /dev/null and b/src/openmv/src/micropython/logo/vector-logo-2.png differ diff --git a/src/openmv/src/micropython/logo/vector-logo-3.png b/src/openmv/src/micropython/logo/vector-logo-3.png new file mode 100755 index 0000000..ba75b05 Binary files /dev/null and b/src/openmv/src/micropython/logo/vector-logo-3.png differ diff --git a/src/openmv/src/micropython/logo/vector-logo-R2000.dxf b/src/openmv/src/micropython/logo/vector-logo-R2000.dxf new file mode 100755 index 0000000..4b28e7a --- /dev/null +++ b/src/openmv/src/micropython/logo/vector-logo-R2000.dxf @@ -0,0 +1,33724 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1015 + 9 +$ACADMAINTVER + 70 + 6 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +0.1721479520991333 + 20 +0.1940338359368368 + 30 +0.0 + 9 +$EXTMAX + 10 +3.827852047900866 + 20 +3.91966423026812 + 30 +0.0 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +12.0 + 20 +9.0 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 + 1 + 9 +$TEXTSIZE + 40 +0.2 + 9 +$TRACEWID + 40 +0.05 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +0 + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +0.18 + 9 +$DIMEXO + 40 +0.0625 + 9 +$DIMDLI + 40 +0.38 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +0.18 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +0.18 + 9 +$DIMCEN + 40 +0.09 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 1 + 9 +$DIMTOH + 70 + 1 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 0 + 9 +$DIMZIN + 70 + 0 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 2 + 9 +$DIMALTF + 40 +25.4 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 + 0 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +Standard + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.09 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 1 + 9 +$DIMTZIN + 70 + 0 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 4 + 9 +$DIMTDEC + 70 + 4 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 2 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 46 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +0.1 + 9 +$FILLETRAD + 40 +0.0196850393700787 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 0 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 + 0 + 9 +$TDCREATE + 40 +2452642.813384259 + 9 +$TDUCREATE + 40 +2452643.063384271 + 9 +$TDUPDATE + 40 +2456660.752361111 + 9 +$TDUUPDATE + 40 +2456661.002361111 + 9 +$TDINDWG + 40 +0.0 + 9 +$TDUSRTIMER + 40 +2456661.001018519 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 6 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +1B45 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PEXTMAX + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +0.0 + 20 +0.0 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +1.0 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 0 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 1 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$FINGERPRINTGUID + 2 +{FDEAD576-A652-11D2-9A35-0060089B3A3F} + 9 +$VERSIONGUID + 2 +{FBC2AE19-5C5C-49EC-81BC-71B1A3362A02} + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBPLACEHOLDER + 2 +AcDbPlaceHolder + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +LAYOUT + 2 +AcDbLayout + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 + 4095 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 + 4095 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +CELLSTYLEMAP + 2 +AcDbCellStyleMap + 3 +ObjectDBX Classes + 90 + 1152 +280 + 0 +281 + 0 + 0 +CLASS + 1 +RASTERVARIABLES + 2 +AcDbRasterVariables + 3 +ISM + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SUN + 2 +AcDbSun + 3 +SCENEOE + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +IMAGEDEF + 2 +AcDbRasterImageDef + 3 +ISM + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +IMAGE + 2 +AcDbRasterImage + 3 +ISM + 90 + 127 +280 + 0 +281 + 1 + 0 +CLASS + 1 +IMAGEDEF_REACTOR + 2 +AcDbRasterImageDefReactor + 3 +ISM + 90 + 1 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SORTENTSTABLE + 2 +AcDbSortentsTable + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +94 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +29.66959356597982 + 22 +21.59555199096451 + 13 +0.0 + 23 +0.0 + 14 +0.5 + 24 +0.5 + 15 +0.5 + 25 +0.5 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +-27.66959356597982 + 27 +-19.53870295786203 + 37 +0.0 + 40 +3.800143002217909 + 41 +2.172519083969465 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 16 + 72 + 1000 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 1 +281 + 5 + 65 + 1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 + 0 +146 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LTYPE + 5 +14 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +15 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +16 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +102 +{ACAD_XDICTIONARY +360 +133 +102 +} +330 +0 +100 +AcDbSymbolTable + 70 + 8 + 0 +LAYER + 5 +10 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +Continuous +370 + -3 +390 +F + 0 +LAYER + 5 +4B2 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +OUTLINE + 70 + 0 + 62 + 3 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +LAYER + 5 +B85 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +HATCH-BLACK + 70 + 0 + 62 + -178 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +LAYER + 5 +B86 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +HATCH-RED + 70 + 0 + 62 + -1 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +LAYER + 5 +B87 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +HATCH-YELLOW + 70 + 0 + 62 + -2 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +LAYER + 5 +C34 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +HATCH-WHITE + 70 + 0 + 62 + -7 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +LAYER + 5 +C35 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +CENTERLINE + 70 + 0 + 62 + 5 + 6 +Continuous +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +STYLE + 5 +11 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +arial.ttf + 4 + +1001 +ACAD +1000 +Arial +1071 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +APPID + 5 +12 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +4B3 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcAecLayerStandard + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 1 +100 +AcDbDimStyleTable + 0 +DIMSTYLE +105 +27 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 +178 + 0 +340 +11 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +BLOCK_RECORD + 5 +1F +102 +{ACAD_XDICTIONARY +360 +C3A +102 +} +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +22 + 0 +BLOCK_RECORD + 5 +58 +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +59 + 0 +BLOCK_RECORD + 5 +5D +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space0 +340 +5E + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +20 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 +*Model_Space + 0 +ENDBLK + 5 +21 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +5A +330 +58 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 +*Paper_Space + 0 +ENDBLK + 5 +5B +330 +58 +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +5F +330 +5D +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space0 + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space0 + 1 +*Paper_Space0 + 0 +ENDBLK + 5 +60 +330 +5D +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LWPOLYLINE + 5 +12A +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 12 + 70 + 1 + 43 +0.0 + 10 +2.051456726858387 + 20 +3.24742480916928 + 10 +2.123046084816941 + 20 +3.189691455976897 + 42 +0.4158687069147495 + 10 +2.238512791201705 + 20 +3.202392793679222 + 42 +0.26959558438999 + 10 +2.297400811457934 + 20 +3.601907597770506 + 42 +0.5584229650981822 + 10 +2.131128754263874 + 20 +3.630774274366697 + 42 +0.0728974356199314 + 10 +2.083688019187524 + 20 +3.556961618598168 + 10 +2.102120376925607 + 20 +3.616965010523272 + 42 +0.2082143708428352 + 10 +2.078212672061864 + 20 +3.708788569361961 + 42 +0.3964961476078332 + 10 +1.961304941181418 + 20 +3.726524255462661 + 42 +0.3247796006490571 + 10 +1.824130493996318 + 20 +3.336662468025144 + 42 +0.2118780432517558 + 10 +1.926924729355354 + 20 +3.21641832666371 + 42 +0.2797558288082047 + 10 +2.010060757952385 + 20 +3.224731929523413 + 0 +LWPOLYLINE + 5 +137 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.002382887993199 + 20 +2.593662641184479 + 42 +0.1140103683665206 + 10 +2.015684652568724 + 20 +2.695642836263502 + 0 +LWPOLYLINE + 5 +138 +102 +{ACAD_REACTORS +330 +C20 +330 +C24 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.020828542221933 + 20 +2.58678815101607 + 42 +0.1140103683665206 + 10 +2.035276511011441 + 20 +2.697555911735634 + 42 +1.000000000000011 + 10 +1.996092794126006 + 20 +2.693729760791369 + 42 +-0.1140103683665206 + 10 +1.983937233764465 + 20 +2.600537131352887 + 42 +0.9999999999999872 + 0 +LWPOLYLINE + 5 +14D +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.722674860472906 + 20 +2.732887777074972 + 42 +0.0678677703915072 + 10 +1.716999440920682 + 20 +2.659580274525414 + 0 +LWPOLYLINE + 5 +14E +102 +{ACAD_REACTORS +330 +C20 +330 +C25 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +1.697347802700083 + 20 +2.658434024008193 + 42 +-0.0678677703915072 + 10 +1.703433819452505 + 20 +2.73704507372698 + 42 +-0.999999999999989 + 10 +1.741915901493307 + 20 +2.728730480422965 + 42 +0.0678677703915072 + 10 +1.736651079141282 + 20 +2.660726525042634 + 42 +-0.9999999999999999 + 0 +LWPOLYLINE + 5 +164 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 11 + 70 + 0 + 43 +0.0 + 10 +1.811731838460656 + 20 +3.397331983591354 + 42 +0.2124467312467683 + 10 +1.672244722447104 + 20 +3.269516246350102 + 42 +0.1056357518612903 + 10 +1.585025186716269 + 20 +2.838970667001557 + 42 +0.1451314237734208 + 10 +1.646476928687697 + 20 +2.639513658809246 + 42 +0.1600067868781768 + 10 +1.833948673174001 + 20 +2.492097314767818 + 42 +0.1190176972929128 + 10 +1.973432454486796 + 20 +2.47639384269949 + 42 +0.0768957533116813 + 10 +2.089822894522638 + 20 +2.509648254138302 + 42 +0.0709021530444379 + 10 +2.251476283461308 + 20 +2.614030156710129 + 42 +0.2070922264234396 + 10 +2.404700602833892 + 20 +2.933295599864002 + 42 +0.0419975136654783 + 10 +2.393883717863114 + 20 +3.174067136850973 + 42 +0.2398427593227676 + 10 +2.300258287041964 + 20 +3.311026577316722 + 42 +0.027034225506599 + 0 +LWPOLYLINE + 5 +1D5 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.848504434043273 + 20 +2.228690132322405 + 42 +-0.3662698243153691 + 10 +1.793291568736173 + 20 +2.065168888754275 + 0 +LWPOLYLINE + 5 +1E1 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 4 + 70 + 0 + 43 +0.0 + 10 +1.838460881357442 + 20 +2.490495972621108 + 42 +0.1790279848154445 + 10 +1.825573029994973 + 20 +2.288268448973123 + 42 +0.0769094708198934 + 10 +1.880276536811822 + 20 +2.173319033432963 + 42 +-0.3080726058837938 + 10 +1.880276536811822 + 20 +2.030140317515856 + 0 +LWPOLYLINE + 5 +21B +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.842082767727739 + 20 +1.084629450592382 + 42 +0.1471000450502847 + 10 +2.973927140373517 + 20 +1.328615998752327 + 42 +0.012522411014275 + 0 +LWPOLYLINE + 5 +222 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.698425240848715 + 20 +1.242823919320058 + 42 +-0.1015039731478666 + 10 +2.611250576927156 + 20 +1.057272707094957 + 42 +-0.0126876031091603 + 0 +LWPOLYLINE + 5 +225 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.242747987090025 + 20 +1.529761688692975 + 42 +0.0725476044851412 + 10 +2.257696032217536 + 20 +1.639194230959991 + 42 +0.0343380551866947 + 0 +LWPOLYLINE + 5 +226 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.495551054582072 + 20 +1.53241438712026 + 42 +0.1036418617890253 + 10 +2.558948542514864 + 20 +1.68753297643855 + 42 +0.053253313175051 + 0 +LWPOLYLINE + 5 +227 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.821324146542795 + 20 +1.632324731905094 + 42 +0.1131246587363501 + 10 +2.830405427290065 + 20 +1.811571024886944 + 42 +0.0627672114645879 + 0 +LWPOLYLINE + 5 +22E +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 13 + 70 + 0 + 43 +0.0 + 10 +2.093724705533888 + 20 +1.557613530636603 + 42 +0.2441872791679012 + 10 +3.026855656910417 + 20 +1.767371768597087 + 42 +-0.2679491924311224 + 10 +3.157725822448509 + 20 +1.69686877794936 + 42 +-0.1202060689774955 + 10 +3.218222973836714 + 20 +1.510442253718783 + 42 +-0.1376749084255927 + 10 +3.164885690739821 + 20 +1.246107314101505 + 42 +-0.1576175352251851 + 10 +3.093739724933785 + 20 +1.174961348295469 + 42 +-0.0918492106817739 + 10 +2.728380896324767 + 20 +1.066112269787028 + 42 +-0.0504127972198909 + 10 +2.347761134221376 + 20 +1.063970822126171 + 42 +-0.1916344722089164 + 10 +2.225767565997291 + 20 +1.163124980703929 + 42 +-0.1572294045872512 + 10 +2.090834049478103 + 20 +1.818212016772601 + 42 +-0.082508630093775 + 10 +2.21598539544255 + 20 +2.26448668874584 + 42 +0.000862340954801 + 10 +2.279411658998576 + 20 +2.40050474988379 + 42 +0.1021773121869368 + 10 +2.404700602833892 + 20 +2.933295599864003 + 42 +0.1021773121869368 + 0 +LWPOLYLINE + 5 +231 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 4 + 70 + 0 + 43 +0.0 + 10 +2.099277124665835 + 20 +3.285428055915363 + 42 +0.5205670505517482 + 10 +2.139077350685995 + 20 +3.338013952617782 + 42 +0.1061689985690478 + 10 +2.120029457222835 + 20 +3.371005871873133 + 42 +0.613270554273111 + 10 +2.068634698539837 + 20 +3.335369986556996 + 0 +LWPOLYLINE + 5 +232 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 4 + 70 + 0 + 43 +0.0 + 10 +1.973661171909946 + 20 +3.292995281984995 + 42 +-0.3922502215719873 + 10 +1.946797519362752 + 20 +3.372829517019611 + 42 +-0.7101707266102861 + 10 +2.015384873593222 + 20 +3.366828901063208 + 42 +-0.0639643640494128 + 10 +2.018358052101874 + 20 +3.342323304531541 + 0 +LWPOLYLINE + 5 +235 +102 +{ACAD_REACTORS +330 +BFB +330 +C40 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 8 + 70 + 1 + 43 +0.0 + 10 +2.098548696321338 + 20 +3.265756498601605 + 42 +0.5205670505517482 + 10 +2.157811705099888 + 20 +3.344057522729578 + 42 +0.1134405246031883 + 10 +2.132468959817252 + 20 +3.3865310504764 + 42 +0.6360781342605795 + 10 +2.049130653843808 + 20 +3.332706714979239 + 42 +0.9999999999999999 + 10 +2.088138743235865 + 20 +3.338033258134752 + 42 +-0.5492430075431818 + 10 +2.107983316870547 + 20 +3.354815495403025 + 42 +-0.0921948717360171 + 10 +2.120342996272102 + 20 +3.331970382505986 + 42 +-0.5205670505517482 + 10 +2.100005553010331 + 20 +3.305099613229121 + 42 +0.999999999999977 + 0 +LWPOLYLINE + 5 +267 +102 +{ACAD_REACTORS +330 +BFC +330 +C40 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 8 + 70 + 1 + 43 +0.0 + 10 +1.998673497536078 + 20 +3.342461458603947 + 42 +0.0639643640494127 + 10 +1.996304467484263 + 20 +3.361987529592359 + 42 +0.7101707266102861 + 10 +1.964747355896155 + 20 +3.364748419109942 + 42 +0.3922502215719873 + 10 +1.983074304769177 + 20 +3.310283824571807 + 42 +-0.9999999999999997 + 10 +1.964248039050714 + 20 +3.275706739398183 + 42 +-0.3922502215719873 + 10 +1.92884768282935 + 20 +3.380910614929281 + 42 +-0.7101707266102861 + 10 +2.034465279702181 + 20 +3.371670272534057 + 42 +-0.0639643640494129 + 10 +2.038042606667671 + 20 +3.342185150459134 + 42 +-0.9999999999999888 + 0 +LWPOLYLINE + 5 +2AF +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.085608292827229 + 20 +1.648485389947214 + 42 +0.2371550452328881 + 10 +3.038263728075514 + 20 +1.980095333928444 + 42 +0.0363699080748577 + 0 +LWPOLYLINE + 5 +2B5 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.428981511922024 + 20 +1.228952354254482 + 42 +-0.1215147796354945 + 10 +2.347761134221376 + 20 +1.063970822126171 + 42 +-0.0158934016013214 + 0 +LWPOLYLINE + 5 +34A +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 6 + 70 + 0 + 43 +0.0 + 10 +2.100129120524675 + 20 +1.887439157700382 + 42 +0.1601220285391677 + 10 +2.669056601079002 + 20 +2.103591135847005 + 42 +0.3249446074510534 + 10 +2.710306617856964 + 20 +2.257538294275427 + 42 +0.3057060432679023 + 10 +2.64763418517673 + 20 +2.301422004076068 + 42 +0.1122985838264234 + 10 +2.540456015841269 + 20 +2.279007501710551 + 42 +0.067059303923133 + 10 +2.127272926405246 + 20 +2.017804783046922 + 42 +0.0105768622903034 + 0 +LWPOLYLINE + 5 +34C +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 5 + 70 + 0 + 43 +0.0 + 10 +2.669056601079002 + 20 +2.103591135847005 + 10 +2.735759906135099 + 20 +2.150297292870786 + 42 +-0.2679491924311215 + 10 +2.905437956246976 + 20 +2.165142198704758 + 42 +-0.3152987888789877 + 10 +3.038801514311188 + 20 +1.93414974025938 + 42 +-0.0857659994463428 + 10 +2.98610429311309 + 20 +1.734756081375588 + 42 +-0.0017098342482428 + 0 +LWPOLYLINE + 5 +38C +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.169209475319699 + 20 +1.278410952985928 + 42 +0.2549125200517152 + 10 +3.219511504449442 + 20 +1.483099110977059 + 42 +0.0218867276949896 + 0 +LWPOLYLINE + 5 +44D +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.380970941004577 + 20 +3.751630247646181 + 42 +0.2679491924311219 + 10 +2.309791821489833 + 20 +3.828814460633206 + 0 +LWPOLYLINE + 5 +44E +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +2.028658926483394 + 20 +3.899981872009325 + 42 +0.1316524975873958 + 10 +1.971574507059384 + 20 +3.857657770838914 + 0 +LWPOLYLINE + 5 +44F +102 +{ACAD_REACTORS +330 +BFE +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.035890886983224 + 20 +3.881673417068221 + 42 +0.1316524975873958 + 10 +1.986991796041955 + 20 +3.84541816400579 + 42 +-1.000000000000004 + 10 +1.956157218076813 + 20 +3.869897377672038 + 42 +-0.1316524975873958 + 10 +2.021426965983563 + 20 +3.918290326950429 + 42 +-1.0 + 0 +LWPOLYLINE + 5 +451 +102 +{ACAD_REACTORS +330 +BFD +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.36176616039695 + 20 +3.747308537705142 + 42 +0.2679491924311219 + 10 +2.303932141782747 + 20 +3.810021777782375 + 42 +-1.000000000000003 + 10 +2.315651501196919 + 20 +3.847607143484037 + 42 +-0.2679491924311219 + 10 +2.400175721612204 + 20 +3.755951957587221 + 42 +-1.0 + 0 +LWPOLYLINE + 5 +480 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 15 + 70 + 0 + 43 +0.0 + 10 +2.164414868289778 + 20 +1.116788876483231 + 42 +-0.1509933859269548 + 10 +2.011994434051636 + 20 +1.339405082556968 + 42 +-0.1070963951594745 + 10 +1.964337309124437 + 20 +1.884128513074088 + 42 +-0.0569571948585108 + 10 +1.999005825805648 + 20 +2.025855120814207 + 42 +0.1145587361047281 + 10 +2.02996377257399 + 20 +2.271091588487681 + 42 +0.1238858905685379 + 10 +1.988035257076031 + 20 +2.386289238049577 + 42 +0.3726487049030961 + 10 +1.897599265772163 + 20 +2.410521488886157 + 42 +0.1535645609181053 + 10 +1.752129598807603 + 20 +2.273262792103868 + 42 +0.013230494041686 + 10 +1.679912845283239 + 20 +2.135632504011972 + 42 +-0.0334295576837925 + 10 +1.547372627715803 + 20 +1.906066113138941 + 42 +0.1212729089747999 + 10 +1.459245452693659 + 20 +1.663938689725279 + 42 +0.142060045402927 + 10 +1.535615350530265 + 20 +1.230823476558462 + 42 +0.2110002865385294 + 10 +1.767733703190374 + 20 +1.036053052451884 + 42 +0.0977925466168199 + 10 +1.905714464335645 + 20 +1.023981300066994 + 42 +0.1523642735345087 + 10 +2.225767565997291 + 20 +1.16312498070393 + 42 +0.0131161693340735 + 0 +LWPOLYLINE + 5 +489 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.726540556633805 + 20 +2.226489993047315 + 42 +0.1491830429238438 + 10 +1.791794192050712 + 20 +2.183894323205893 + 0 +LWPOLYLINE + 5 +48A +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.654521263715424 + 20 +2.085752782994799 + 42 +0.2936017206055124 + 10 +1.910780338072042 + 20 +1.973525769477851 + 0 +LWPOLYLINE + 5 +48B +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.551496630284455 + 20 +1.912244632638939 + 42 +0.2413057746814911 + 10 +1.835672170020508 + 20 +1.78904239903142 + 0 +LWPOLYLINE + 5 +48C +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.460547644534427 + 20 +1.674926403649493 + 42 +0.2628135643200116 + 10 +1.85610884645455 + 20 +1.543874911031386 + 0 +LWPOLYLINE + 5 +48D +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.476099861503821 + 20 +1.396361427764304 + 42 +0.4559232792117359 + 10 +1.995510222782983 + 20 +1.397313095656098 + 42 +0.0249343028351756 + 0 +LWPOLYLINE + 5 +48E +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.940182455435743 + 20 +1.155046537921709 + 42 +-0.1735068790932082 + 10 +1.591939878857363 + 20 +1.147027352610094 + 42 +-0.0902466536252015 + 0 +LWPOLYLINE + 5 +48F +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 5 + 70 + 0 + 43 +0.0 + 10 +1.685157252816573 + 20 +1.071176985228859 + 42 +-0.0967671337827555 + 10 +1.386905873969099 + 20 +1.073654945933856 + 42 +-0.1283919655451407 + 10 +0.9396849704065366 + 20 +1.293355139281928 + 42 +-0.2277426076900994 + 10 +0.8184698262111015 + 20 +1.571535724136809 + 42 +-0.2585706959153292 + 10 +0.9396146897297675 + 20 +1.77228158619182 + 42 +-0.0016259949892818 + 0 +LWPOLYLINE + 5 +490 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 6 + 70 + 0 + 43 +0.0 + 10 +1.454805769320285 + 20 +1.564461529127514 + 42 +-0.1581711632332484 + 10 +1.079130851571503 + 20 +1.639243530487171 + 42 +-0.1439729528407531 + 10 +0.9262274383574314 + 20 +1.795491369527463 + 42 +-0.2034041621669866 + 10 +0.9154532561194422 + 20 +1.918640836027165 + 42 +-0.194428280448302 + 10 +1.041151067775051 + 20 +2.068441654648967 + 42 +-0.1994742666452343 + 10 +1.19286906097098 + 20 +2.082870785844477 + 42 +-0.0611756567655047 + 0 +LWPOLYLINE + 5 +492 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 5 + 70 + 0 + 43 +0.0 + 10 +1.527535040931072 + 20 +1.87410829973367 + 42 +-0.1177728459219032 + 10 +1.312388080418405 + 20 +1.947278913508062 + 42 +-0.1120190572174949 + 10 +1.206886139482316 + 20 +2.052780854444151 + 42 +-0.6961980985337713 + 10 +1.357198164134302 + 20 +2.248853535690163 + 42 +-0.1138630283068457 + 10 +1.650613743929805 + 20 +2.078374984748495 + 42 +-0.0035904482483965 + 0 +LWPOLYLINE + 5 +4AD +102 +{ACAD_REACTORS +330 +BAE +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +2.991096081171635 + 20 +1.314895048081054 + 42 +0.0536325233126152 + 10 +3.198865278725419 + 20 +1.441471338442461 + 42 +-0.1019234865027202 + 10 +3.147359585391412 + 20 +1.255070371967993 + 42 +-0.1576175352251851 + 10 +3.084776667067298 + 20 +1.19248745364388 + 42 +-0.0487853903884156 + 10 +2.898805094451518 + 20 +1.119232145882148 + 42 +0.1091929375390922 + 0 +LWPOLYLINE + 5 +4B5 +102 +{ACAD_REACTORS +330 +BBA +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 6 + 70 + 1 + 43 +0.0 + 10 +2.183868006181016 + 20 +1.294456920706576 + 42 +0.2503802653463202 + 10 +3.199550468590465 + 20 +1.49218169636237 + 42 +0.0087756063211912 + 10 +3.19859257272434 + 20 +1.508976604658183 + 42 +0.1202060689774955 + 10 +3.140975326177503 + 20 +1.686528485415947 + 42 +0.2542613217194215 + 10 +3.034045022847889 + 20 +1.747720550442733 + 42 +-0.2349955175811071 + 10 +2.117425810875627 + 20 +1.531432319991749 + 42 +0.0576901279999135 + 0 +LWPOLYLINE + 5 +4B9 +102 +{ACAD_REACTORS +330 +BAD +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +2.714378415408047 + 20 +1.225693872673844 + 42 +-0.0759384074577222 + 10 +2.650179425501943 + 20 +1.079126736500261 + 42 +0.0101996300129822 + 10 +2.726291014277126 + 20 +1.085686057566314 + 42 +0.0261370793966787 + 10 +2.832212463468567 + 20 +1.102630606438461 + 42 +0.1222814332374564 + 10 +2.945078532962091 + 20 +1.294462394011187 + 42 +-0.0530654994633163 + 0 +LWPOLYLINE + 5 +4BA +102 +{ACAD_REACTORS +330 +BAC +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.385206484967541 + 20 +1.080514837710239 + 42 +0.0878528142492813 + 10 +2.44424140664477 + 20 +1.208278724252974 + 42 +0.0501038956066548 + 10 +2.671374519065504 + 20 +1.218555099887139 + 42 +-0.0813315417893164 + 10 +2.600965728709292 + 20 +1.076545040917626 + 42 +-0.0288327089816677 + 0 +LWPOLYLINE + 5 +4BC +102 +{ACAD_REACTORS +330 +BAB +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.204441612310571 + 20 +1.2474540192852 + 42 +0.0447207077553119 + 10 +2.404217085512474 + 20 +1.211187767388987 + 42 +-0.0963940214031873 + 10 +2.341193762157614 + 20 +1.087133059592365 + 42 +-0.1740198039637825 + 10 +2.242925650927047 + 20 +1.172774016895618 + 42 +-0.0196351821885444 + 0 +LWPOLYLINE + 5 +4C0 +102 +{ACAD_REACTORS +330 +BAF +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.111590265540881 + 20 +1.573348926544125 + 42 +0.0291422971591348 + 10 +2.228085740598704 + 20 +1.551356274330868 + 42 +0.0473221239695471 + 10 +2.237652044114153 + 20 +1.619229653732975 + 42 +-0.0287252676909968 + 10 +2.106626866510892 + 20 +1.626116355527945 + 42 +0.0123842072538969 + 0 +LWPOLYLINE + 5 +4C1 +102 +{ACAD_REACTORS +330 +BB0 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.267503548545168 + 20 +1.547048928709969 + 42 +0.0533543951524521 + 10 +2.484089073429926 + 20 +1.550784222461052 + 42 +0.0768690501849397 + 10 +2.532391987223791 + 20 +1.659393561191435 + 42 +-0.0566860153224456 + 10 +2.277093772004332 + 20 +1.620104770218732 + 42 +-0.0458852076194563 + 0 +LWPOLYLINE + 5 +4C3 +102 +{ACAD_REACTORS +330 +BB1 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.575978434475863 + 20 +1.672202312238555 + 42 +-0.0711923834185597 + 10 +2.534187811152101 + 20 +1.558291292956125 + 42 +0.0701806584121727 + 10 +2.804649062203535 + 20 +1.646049204465365 + 42 +0.0880028594988734 + 10 +2.815004646385387 + 20 +1.779090298343385 + 42 +-0.0574665063324246 + 0 +LWPOLYLINE + 5 +4C7 +102 +{ACAD_REACTORS +330 +BBB +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 7 + 70 + 1 + 43 +0.0 + 10 +2.10461778187463 + 20 +1.665965877260762 + 42 +-0.0351389292849169 + 10 +2.110402761135924 + 20 +1.8160751267299 + 42 +-0.0095038145827776 + 10 +2.117156173606469 + 20 +1.868640946110094 + 42 +0.1557808751637161 + 10 +2.680907394207461 + 20 +2.087858154687554 + 10 +2.747050780866419 + 20 +2.134172252628876 + 42 +-0.2679491924311215 + 10 +2.897118699126096 + 20 +2.147301494235533 + 42 +-0.2502096061484992 + 10 +3.017490352158867 + 20 +1.987010103205812 + 42 +-0.2309255538296563 + 0 +LWPOLYLINE + 5 +4C8 +102 +{ACAD_REACTORS +330 +BBC +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 6 + 70 + 1 + 43 +0.0 + 10 +2.123645620818254 + 20 +1.90852967158985 + 42 +0.1535620368154201 + 10 +2.656669093820602 + 20 +2.118889842946778 + 42 +0.3249446074510534 + 10 +2.691929368331739 + 20 +2.250482978911167 + 42 +0.3057060432679023 + 10 +2.647289746908166 + 20 +2.281739978334781 + 42 +0.1122985838264234 + 10 +2.548658946753702 + 20 +2.261113013747846 + 42 +0.0661825067963756 + 10 +2.144771760651222 + 20 +2.006772737968957 + 42 +0.0180243406510753 + 0 +LWPOLYLINE + 5 +4C9 +102 +{ACAD_REACTORS +330 +C20 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 17 + 70 + 1 + 43 +0.0 + 10 +1.795927086013099 + 20 +3.369886028656918 + 42 +0.1834763883041901 + 10 +1.690295415947398 + 20 +3.261663015221454 + 42 +0.1056357518612903 + 10 +1.604709116716065 + 20 +2.839179652083978 + 42 +0.1451314237734208 + 10 +1.66286553317314 + 20 +2.650418447574797 + 42 +0.1600067868781768 + 10 +1.84068071995552 + 20 +2.510595431459335 + 42 +0.1190176972929128 + 10 +1.970981934519221 + 20 +2.495925758296534 + 42 +0.0768957533116813 + 10 +2.081584776821197 + 20 +2.527526570382813 + 42 +0.0709021530444379 + 10 +2.238571559817636 + 20 +2.628895178831943 + 42 +0.2070922264234396 + 10 +2.385030570405729 + 20 +2.934064104435615 + 42 +0.0419975136654783 + 10 +2.374361839564172 + 20 +3.171537899281493 + 42 +0.2041023265544078 + 10 +2.30953573868931 + 20 +3.281794913306262 + 42 +-0.0638786287537656 + 10 +2.253905428386551 + 20 +3.190122198930097 + 42 +-0.4158687069147495 + 10 +2.110688753100606 + 20 +3.174368364648643 + 10 +2.049360338450518 + 20 +3.223826763560005 + 10 +2.020698206844207 + 20 +3.208114453397319 + 42 +-0.275738643742557 + 10 +1.918435234414153 + 20 +3.198657998664349 + 42 +-0.2118780432517558 + 10 +1.805265959929118 + 20 +3.331038401042169 + 42 +-0.0269158367577847 + 0 +LWPOLYLINE + 5 +4CB +102 +{ACAD_REACTORS +330 +C28 +330 +C40 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 13 + 70 + 1 + 43 +0.0 + 10 +2.053553115266256 + 20 +3.271022854778554 + 10 +2.135403416533275 + 20 +3.205014547305152 + 42 +0.4158687069147495 + 10 +2.223120154016859 + 20 +3.214663388428346 + 42 +0.26959558438999 + 10 +2.279122382999181 + 20 +3.59460007917116 + 42 +0.5581360462772155 + 10 +2.145920537005866 + 20 +3.617785434351675 + 42 +0.0728307330332283 + 10 +2.101616152707511 + 20 +3.548832485588364 + 42 +-0.9381223686609327 + 10 +2.064870809553132 + 20 +3.562742050811843 + 10 +2.082872800905891 + 20 +3.621344458486482 + 42 +0.2046959930292842 + 10 +2.062725504642901 + 20 +3.696637502728181 + 42 +0.3964961476078332 + 10 +1.972491420232154 + 20 +3.71032661793588 + 42 +0.3247796006490571 + 10 +1.842995028063519 + 20 +3.342286535008118 + 42 +0.2118780432517558 + 10 +1.935414224296555 + 20 +3.23417865466307 + 42 +0.2856103122495783 + 10 +1.999267568517967 + 20 +3.241264030153233 + 0 +LWPOLYLINE + 5 +4CD +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.541590875260533 + 20 +1.219181584929098 + 42 +-0.2584842710932977 + 10 +0.820082757115996 + 20 +1.522632196851646 + 42 +-0.0230272271526239 + 0 +LWPOLYLINE + 5 +4CE +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.458123574270783 + 20 +1.652827431708805 + 42 +-0.2951443317480729 + 10 +0.941461714899275 + 20 +1.974891353638494 + 42 +-0.0281477710443027 + 0 +LWPOLYLINE + 5 +4CF +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.149191552360515 + 20 +1.154795257187257 + 42 +0.1554073147032292 + 10 +0.735992563639889 + 20 +1.096559104863405 + 42 +-0.383579166426189 + 10 +0.9194102381455578 + 20 +1.312304764434089 + 42 +-0.023050174561539 + 0 +LWPOLYLINE + 5 +4D0 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.24989523667859 + 20 +1.240900333949516 + 42 +0.1256439210154252 + 10 +1.345357819803049 + 20 +1.083069957917427 + 42 +0.0704007111098051 + 0 +LWPOLYLINE + 5 +4D1 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.037864942416157 + 20 +1.3303917414282 + 42 +0.0872453218025478 + 10 +1.042370972787492 + 20 +1.21582065403204 + 42 +0.0971278145482142 + 0 +LWPOLYLINE + 5 +4D2 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.252136016103313 + 20 +1.688388482710066 + 42 +0.0590285034647111 + 10 +1.266518295486159 + 20 +1.571079816805446 + 42 +0.040710128897272 + 0 +LWPOLYLINE + 5 +4D3 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.052845021272466 + 20 +1.816519721371516 + 42 +0.1113687809723345 + 10 +1.031596064763292 + 20 +1.670646745988808 + 42 +0.1054872080523193 + 0 +LWPOLYLINE + 5 +4E7 +102 +{ACAD_REACTORS +330 +BB6 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +1.055916139802069 + 20 +1.183858027338503 + 42 +0.1086902960134493 + 10 +0.7572717136065252 + 20 +1.127799089885956 + 42 +-0.3246303955088655 + 10 +0.9126882033208936 + 20 +1.29130332219202 + 42 +0.0129078914938259 + 10 +0.9268235401588977 + 20 +1.278452643283383 + 42 +0.0398388581973403 + 0 +LWPOLYLINE + 5 +4EB +102 +{ACAD_REACTORS +330 +BA6 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +1.060018004406812 + 20 +1.22781950439698 + 42 +-0.056608990335621 + 10 +1.05478008384554 + 20 +1.297904456500116 + 42 +0.0588177228710549 + 10 +1.234398517271265 + 20 +1.224686922587824 + 42 +0.0753850106847673 + 10 +1.287966831577129 + 20 +1.11990052780729 + 42 +-0.0655149355972575 + 0 +LWPOLYLINE + 5 +4EE +102 +{ACAD_REACTORS +330 +BB7 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 6 + 70 + 1 + 43 +0.0 + 10 +0.9337884234626875 + 20 +1.745337488462597 + 42 +0.1140426130224996 + 10 +1.069517024899449 + 20 +1.622065780002278 + 42 +0.1496103246747427 + 10 +1.435800351452426 + 20 +1.542762378894283 + 42 +0.098469544262505 + 10 +1.511203238184653 + 20 +1.236207952572697 + 42 +-0.2469581287149142 + 10 +0.8391304022153184 + 20 +1.53029339160826 + 42 +-0.0306677320577088 + 10 +0.8381414565311932 + 20 +1.570809270042459 + 42 +-0.2364748902496887 + 0 +LWPOLYLINE + 5 +4F0 +102 +{ACAD_REACTORS +330 +BA5 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +0.8557672849696794 + 20 +1.451424859785045 + 42 +0.0630395648108045 + 10 +1.01685683292838 + 20 +1.320182987586002 + 42 +0.0445931465006306 + 10 +1.016312593127104 + 20 +1.257746897185134 + 42 +-0.0210506403179615 + 10 +0.9525464006541762 + 20 +1.308257635280474 + 42 +-0.1329522052869259 + 0 +LWPOLYLINE + 5 +4F3 +102 +{ACAD_REACTORS +330 +C01 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 17 + 70 + 1 + 43 +0.0 + 10 +1.84986913761158 + 20 +2.466300860817559 + 42 +0.0673153145939977 + 10 +1.833988541120499 + 20 +2.395045529905472 + 42 +-0.0456048674756574 + 10 +1.889008320037764 + 20 +2.428232966136522 + 42 +-0.3726487049030961 + 10 +2.004330972949735 + 20 +2.397332354419744 + 42 +-0.1238858905685379 + 10 +2.049545393540757 + 20 +2.273106754812188 + 42 +-0.1145587361047281 + 10 +2.017472341220017 + 20 +2.019036867118983 + 42 +0.0569571948585108 + 10 +1.983866015583199 + 20 +1.881652548807571 + 42 +0.1070963951594745 + 10 +2.030796508895675 + 20 +1.345234555651572 + 42 +0.1426114747077699 + 10 +2.165557450307532 + 20 +1.141311124747446 + 42 +0.019413333947305 + 10 +2.200668024179765 + 20 +1.167752668813839 + 42 +-0.1534467262547569 + 10 +2.071265337820281 + 20 +1.820348906815302 + 42 +-0.082508630093775 + 10 +2.198159065568731 + 20 +2.272836703011166 + 42 +0.000862340954801 + 10 +2.261556633001577 + 20 +2.408793225114376 + 42 +0.0606801155133229 + 10 +2.360970556998814 + 20 +2.715554284918385 + 42 +-0.0817679966984111 + 10 +2.264381007104979 + 20 +2.599165134588315 + 42 +-0.0709021530444379 + 10 +2.098061012224078 + 20 +2.49176993789379 + 42 +-0.0768957533116813 + 10 +1.97588297445437 + 20 +2.456861927102445 + 42 +-0.1001198017354382 + 0 +LWPOLYLINE + 5 +4F4 +102 +{ACAD_REACTORS +330 +BB3 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 11 + 70 + 1 + 43 +0.0 + 10 +1.985708655480637 + 20 +1.35859138415058 + 42 +-0.3682846044885977 + 10 +1.514588534428652 + 20 +1.333441193996956 + 42 +0.0330251139842943 + 10 +1.553282361892708 + 20 +1.239505497320984 + 42 +0.0639008891509803 + 10 +1.603183045430495 + 20 +1.164065854453502 + 42 +0.1707629002601277 + 10 +1.933126177068946 + 20 +1.17342341770615 + 42 +-1.000000000000009 + 10 +1.94723873380254 + 20 +1.136669658137267 + 42 +-0.1354090889595181 + 10 +1.663131530982194 + 20 +1.10889954806288 + 42 +0.0869057462878126 + 10 +1.77321598022121 + 20 +1.054959279298051 + 42 +0.0977925466168199 + 10 +1.903598507249911 + 20 +1.043552286261177 + 42 +0.1070337225744706 + 10 +2.131038389154381 + 20 +1.11916439867858 + 42 +-0.1361955436546222 + 10 +1.993192359207598 + 20 +1.333575609462363 + 42 +-0.0049803061650251 + 0 +LWPOLYLINE + 5 +4F7 +102 +{ACAD_REACTORS +330 +BB4 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 36 + 70 + 1 + 43 +0.0 + 10 +1.800080314455621 + 20 +2.308917195085585 + 42 +0.0437118087611369 + 10 +1.769312650034374 + 20 +2.26365844280057 + 42 +0.0033308209162503 + 10 +1.750572816609542 + 20 +2.229600425683039 + 42 +0.1199820129190778 + 10 +1.797274715454282 + 20 +2.202801058466759 + 42 +-0.9999999999999999 + 10 +1.786313668647142 + 20 +2.164987587945027 + 42 +-0.1021140647943497 + 10 +1.731552642365071 + 20 +2.193892004093673 + 42 +0.0064323953109214 + 10 +1.697579856645681 + 20 +2.12695048324945 + 42 +-0.0055509425268816 + 10 +1.677510563493305 + 20 +2.087231690238655 + 42 +0.2805803818424905 + 10 +1.907675826757856 + 20 +1.99296446245093 + 42 +-1.000000000000002 + 10 +1.913884849386228 + 20 +1.954087076504771 + 42 +-0.2626963580826674 + 10 +1.65730585773017 + 20 +2.04932297149283 + 42 +-0.0197119133471879 + 10 +1.576111447954835 + 20 +1.913814831608159 + 42 +0.229407728918388 + 10 +1.834403866994767 + 20 +1.808686537659429 + 42 +-1.000000000000006 + 10 +1.836940473046249 + 20 +1.76939826040341 + 42 +-0.2218376429216039 + 10 +1.55389731810562 + 20 +1.879874561474816 + 42 +0.1027759246248995 + 10 +1.481321802657222 + 20 +1.68147851322532 + 42 +0.2567981434431833 + 10 +1.852312329231318 + 20 +1.563190377165427 + 42 +-0.9999999999999999 + 10 +1.859905363677781 + 20 +1.524559444897346 + 42 +-0.2372321476697851 + 10 +1.476143434862462 + 20 +1.631501691187762 + 42 +0.0739602798598165 + 10 +1.494131551859586 + 20 +1.40568894806263 + 42 +0.4420288920812132 + 10 +1.973843248718476 + 20 +1.402603074502723 + 42 +-0.0932841665178725 + 10 +1.944808602665675 + 20 +1.886604477340606 + 42 +-0.0569571948585108 + 10 +1.98053931039128 + 20 +2.032673374509431 + 42 +0.1145587361047281 + 10 +2.010382151607223 + 20 +2.269076422163175 + 42 +0.1238858905685379 + 10 +1.971739541202327 + 20 +2.375246121679411 + 42 +0.3726487049030961 + 10 +1.906190211506561 + 20 +2.392810011635793 + 42 +0.0692252662755674 + 10 +1.834372402647776 + 20 +2.344740013080819 + 42 +0.0476713025068407 + 10 +1.844432384008702 + 20 +2.293909862021855 + 42 +0.0769094708198934 + 10 +1.896548904341149 + 20 +2.184396525477287 + 42 +-0.3080726058837938 + 10 +1.896548904341149 + 20 +2.019062825471532 + 42 +-0.9999999999999999 + 10 +1.864004169282495 + 20 +2.041217809560179 + 42 +0.2582998793018828 + 10 +1.873587490264647 + 20 +2.144928461209456 + 42 +-0.2026932661734018 + 10 +1.803462564620088 + 20 +2.048315057803096 + 42 +-0.999999999999995 + 10 +1.783120572852258 + 20 +2.082022719705455 + 42 +0.3646986474062371 + 10 +1.830429247500239 + 20 +2.220863495048448 + 42 +-0.0379960309145583 + 10 +1.806713675981244 + 20 +2.282627035924392 + 42 +-0.0217555693507311 + 0 +LWPOLYLINE + 5 +505 +102 +{ACAD_REACTORS +330 +BB8 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 7 + 70 + 1 + 43 +0.0 + 10 +1.496545734250796 + 20 +1.858090362879029 + 42 +0.0874292139153708 + 10 +1.440409322525223 + 20 +1.672501008241135 + 42 +-0.2810079005908725 + 10 +0.963992618224232 + 20 +1.973488406523313 + 42 +-0.1221105918102025 + 10 +1.050391027094316 + 20 +2.051059942225276 + 42 +-0.1855272393840248 + 10 +1.177801591011496 + 20 +2.066644978446405 + 42 +0.0452485050555582 + 10 +1.190231879786862 + 20 +2.04228626493346 + 42 +0.1120190572174949 + 10 +1.301893490907713 + 20 +1.930624653812608 + 42 +0.1031607726849441 + 0 +LWPOLYLINE + 5 +507 +102 +{ACAD_REACTORS +330 +BA9 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +1.232680305288136 + 20 +1.674823294981787 + 42 +0.0376631697644602 + 10 +1.24092624183496 + 20 +1.596731177563018 + 42 +-0.0683286784235571 + 10 +1.088744678243557 + 20 +1.656421280972064 + 42 +-0.0308076295927463 + 10 +1.050667583615558 + 20 +1.680925971586079 + 42 +-0.0803202890882193 + 10 +1.061814443246697 + 20 +1.780967062069061 + 42 +0.0873178465018551 + 0 +LWPOLYLINE + 5 +509 +102 +{ACAD_REACTORS +330 +BA8 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +1.03011243645825 + 20 +1.811587717464269 + 42 +0.0701949736097343 + 10 +1.011360717734072 + 20 +1.714273589617648 + 42 +-0.0772792890158624 + 10 +0.9436091507811217 + 20 +1.804731328846728 + 42 +-0.2034041621669866 + 10 +0.9341754033724281 + 20 +1.912559555139139 + 42 +-0.021365350595909 + 10 +0.9413736096183022 + 20 +1.931870968260919 + 42 +0.0646639173137995 + 0 +LWPOLYLINE + 5 +50B +102 +{ACAD_REACTORS +330 +BB9 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 6 + 70 + 1 + 43 +0.0 + 10 +1.517012100394491 + 20 +1.895029973752357 + 42 +-0.1110664831625005 + 10 +1.322882669929097 + 20 +1.963933173203516 + 42 +-0.1120190572174949 + 10 +1.22354039917777 + 20 +2.063275443954843 + 42 +-0.6961980985337713 + 10 +1.351388497511153 + 20 +2.230045331397104 + 42 +-0.1086664830114359 + 10 +1.62603521686569 + 20 +2.074220841935225 + 42 +-0.0233827832969574 + 10 +1.531020271498053 + 20 +1.917025183406504 + 42 +0.0116709324309886 + 0 +LWPOLYLINE + 5 +510 +102 +{ACAD_REACTORS +330 +BB2 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +2.84997659259958 + 20 +1.669588479790926 + 42 +0.0790070326196522 + 10 +2.851886405500074 + 20 +1.80192109397708 + 42 +0.0465967056483061 + 10 +3.018962226551324 + 20 +1.933310565196752 + 42 +-0.0825476832350667 + 10 +2.970238833200536 + 20 +1.747438830578402 + 42 +-0.0352296221604151 + 0 +LWPOLYLINE + 5 +559 +102 +{ACAD_REACTORS +330 +BA7 +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +1.355385427777645 + 20 +1.100872595462885 + 42 +-0.0964781721945481 + 10 +1.280659164315312 + 20 +1.213328327577104 + 42 +0.0761322456062632 + 10 +1.530692586565761 + 20 +1.198306536487731 + 42 +0.0982025130561956 + 10 +1.632063828471465 + 20 +1.082968026772228 + 42 +-0.0801281899540377 + 10 +1.390840639583887 + 20 +1.092942724306655 + 42 +-0.009398208639944 + 0 +LWPOLYLINE + 5 +620 +102 +{ACAD_REACTORS +330 +BAA +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0.0 + 10 +1.272750873165488 + 20 +1.660423889558836 + 42 +0.0720111964992741 + 10 +1.436797603060258 + 20 +1.633190144890045 + 42 +0.0157631540077514 + 10 +1.434991753420616 + 20 +1.582208383349729 + 42 +-0.0636343006390252 + 10 +1.282776238934902 + 20 +1.588169636138475 + 42 +-0.0378416081317004 + 0 +LWPOLYLINE + 5 +8B3 +102 +{ACAD_REACTORS +330 +C28 +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 48 + 70 + 1 + 43 +0.0 + 10 +3.027996198643118 + 20 +1.787090153383295 + 42 +-0.2652120571486825 + 10 +3.174476318719514 + 20 +1.707209070482774 + 42 +-0.1202060689774955 + 10 +3.237853374949089 + 20 +1.511907902779382 + 42 +-0.1376749084255928 + 10 +3.182411796088231 + 20 +1.237144256235018 + 42 +-0.1576175352251852 + 10 +3.102702782800273 + 20 +1.157435242947061 + 42 +-0.091849210681774 + 10 +2.73047077837241 + 20 +1.046538482007744 + 42 +-0.0506776859186796 + 10 +2.34388013009181 + 20 +1.044567731825123 + 42 +-0.1678583337512084 + 10 +2.221067012551395 + 20 +1.133620430754517 + 42 +-0.1427259380349648 + 10 +1.907830421421379 + 20 +1.004410313872811 + 42 +-0.0977925466168198 + 10 +1.762251426159538 + 20 +1.017146825605717 + 42 +-0.0554068829065345 + 10 +1.681692239060136 + 20 +1.050537537701288 + 42 +-0.0944908669632265 + 10 +1.382971108354313 + 20 +1.054367167561056 + 42 +-0.063211812705244 + 10 +1.14310982680291 + 20 +1.135855466777803 + 42 +0.1543252686721255 + 10 +0.7445258947417084 + 20 +1.078819797230121 + 42 +-0.5434510775266247 + 10 +0.7163152163407374 + 20 +1.096008851948713 + 42 +-0.3401781029993987 + 10 +0.8820862850200285 + 20 +1.324403005153777 + 42 +-0.182531460234485 + 10 +0.79879819589101 + 20 +1.572262178231159 + 42 +-0.2383486190805098 + 10 +0.9129246094229353 + 20 +1.778768451782942 + 42 +-0.0052329189934023 + 10 +0.9088457259337407 + 20 +1.786251410208198 + 42 +-0.2034041621669866 + 10 +0.8967311088664565 + 20 +1.92472211691519 + 42 +-0.194428280448302 + 10 +1.031911108455786 + 20 +2.085823367072657 + 42 +-0.1617232608950327 + 10 +1.167586754433075 + 20 +2.108823943952719 + 42 +-0.5347302517393296 + 10 +1.363007830757451 + 20 +2.267661739983221 + 42 +-0.105444424534756 + 10 +1.644986728674037 + 20 +2.110043533348865 + 42 +0.0048822169168032 + 10 +1.662245833920796 + 20 +2.144314524774496 + 42 +-0.013230494041686 + 10 +1.734946547580834 + 20 +2.282867141407166 + 42 +-0.0694197792179022 + 10 +1.793844951212572 + 20 +2.360618102610478 + 42 +-0.097214664119097 + 10 +1.812670378378858 + 20 +2.479214960413685 + 42 +-0.1500723642402677 + 10 +1.630088324202255 + 20 +2.628608870043696 + 42 +-0.1451314237734207 + 10 +1.565341256716473 + 20 +2.838761681919137 + 42 +-0.1056357518612903 + 10 +1.65419402894681 + 20 +3.277369477478751 + 42 +-0.1962234048498945 + 10 +1.790739940431784 + 20 +3.410546342344788 + 42 +-0.2655031168224304 + 10 +1.950118462130682 + 20 +3.742721892989442 + 42 +-0.3964961476078332 + 10 +2.093699839480827 + 20 +3.720939635995741 + 42 +-0.1405234862865436 + 10 +2.122456164203622 + 20 +3.650189734969364 + 42 +-0.5343574555981587 + 10 +2.315679239916688 + 20 +3.609215116369852 + 42 +-0.1773163153754776 + 10 +2.324179645939324 + 20 +3.319578756296038 + 42 +-0.2178846001444296 + 10 +2.413405596162056 + 20 +3.176596374420452 + 42 +-0.0419776577731284 + 10 +2.424375140175325 + 20 +2.932642516763373 + 42 +-0.1021560486223639 + 10 +2.297266684995574 + 20 +2.392216274653201 + 42 +-0.0008623409548011 + 10 +2.233811725316336 + 20 +2.256136674480434 + 42 +0.0354069305283612 + 10 +2.162996833972185 + 20 +2.072072274041452 + 42 +-0.0586147259804529 + 10 +2.532253084928835 + 20 +2.296901989673256 + 42 +-0.1122985838264234 + 10 +2.647978623445294 + 20 +2.321104029817356 + 42 +-0.3057060432679023 + 10 +2.728683867382189 + 20 +2.264593609639688 + 42 +-0.1508928720957283 + 10 +2.734821253334247 + 20 +2.173180071930798 + 42 +-0.2505867392793861 + 10 +2.913757213367856 + 20 +2.182982903173984 + 42 +-0.3152987888789875 + 10 +3.058411646163387 + 20 +1.932434076032064 + 42 +-0.0595813595316129 + 0 +HATCH + 5 +BA5 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.454717916970981 + 20 +2.022108206218515 + 40 +0.8272976136018175 + 50 +223.615566083045 + 51 +238.0440774153107 + 73 + 1 + 72 + 2 + 10 +1.365920530767478 + 20 +1.285919869338796 + 40 +0.3507412528077177 + 50 +174.3939645983117 + 51 +184.6071947080589 + 73 + 1 + 72 + 2 + 10 +1.584035429735767 + 20 +2.039961850738251 + 40 +0.9665244191271588 + 50 +125.9717238731088 + 51 +130.7954628287447 + 73 + 0 + 72 + 2 + 10 +1.168606309785878 + 20 +1.558605525778289 + 40 +0.3306901126594289 + 50 +130.7954628287448 + 51 +161.0882096390424 + 73 + 0 + 97 + 1 +330 +4F0 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BA6 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.365920530767478 + 20 +1.285919869338796 + 40 +0.3113711740675595 + 50 +169.2458500319289 + 51 +182.205842988757 + 73 + 0 + 72 + 2 + 10 +1.454717916970979 + 20 +2.022108206218515 + 40 +0.827297613601817 + 50 +241.09054843511 + 51 +254.5550649161042 + 73 + 1 + 72 + 2 + 10 +1.606711922375474 + 20 +1.348933253591385 + 40 +0.3924976718251174 + 50 +198.4545948543501 + 51 +215.6989500329358 + 73 + 1 + 72 + 2 + 10 +1.584035429735761 + 20 +2.039961850738243 + 40 +0.9665244191271488 + 50 +107.8377726397921 + 51 +122.8312626374707 + 73 + 0 + 97 + 1 +330 +4EB + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BA7 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 2 + 10 +1.606711922375474 + 20 +1.348933253591385 + 40 +0.3531275930849602 + 50 +135.3746912145926 + 51 +157.4176362906217 + 73 + 0 + 72 + 2 + 10 +1.454717916970981 + 20 +2.022108206218514 + 40 +0.827297613601817 + 50 +257.8545362072944 + 51 +275.2691677284761 + 73 + 1 + 72 + 2 + 10 +1.872170704325741 + 20 +1.396215376152876 + 40 +0.3946836881941063 + 50 +210.0950891144055 + 51 +232.5295145799341 + 73 + 1 + 72 + 2 + 10 +1.542373482613905 + 20 +1.835739673019258 + 40 +0.75809597646572 + 50 +83.20542127045559 + 51 +101.5302981560868 + 73 + 0 + 72 + 2 + 10 +1.584035429735767 + 20 +2.039961850738253 + 40 +0.9665244191271609 + 50 +101.5302981560871 + 51 +103.684145503982 + 73 + 0 + 97 + 1 +330 +559 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BA8 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 2 + 10 +1.365613936631296 + 20 +1.696475315724716 + 40 +0.3547000446188475 + 50 +161.0626247765776 + 51 +177.1237827075663 + 73 + 1 + 72 + 2 + 10 +1.26836984905495 + 20 +1.977371145189359 + 40 +0.3677961627452389 + 50 +134.3293201388803 + 51 +152.0052969205894 + 73 + 0 + 72 + 2 + 10 +1.065938622495786 + 20 +1.869760556959495 + 40 +0.1385398865270621 + 50 +152.0052969205897 + 51 +197.9947030794107 + 73 + 0 + 72 + 2 + 10 +1.163637847655055 + 20 +1.838026139816656 + 40 +0.2412638458944715 + 50 +197.9947030794104 + 51 +202.8905358909278 + 73 + 0 + 72 + 2 + 10 +1.448830865211249 + 20 +2.213371853903019 + 40 +0.5803064835681331 + 50 +209.0183706588869 + 51 +223.8176444671686 + 73 + 1 + 97 + 1 +330 +509 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BA9 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 2 + 10 +1.75442661167109 + 20 +1.690434343062299 + 40 +0.5219798013778194 + 50 +181.7138221824677 + 51 +190.3415069086127 + 73 + 1 + 72 + 2 + 10 +1.382209127764958 + 20 +2.180776385554784 + 40 +0.6008907212088186 + 50 +103.5988396513469 + 51 +119.2343164314062 + 73 + 0 + 72 + 2 + 10 +1.26836984905495 + 20 +1.977371145189357 + 40 +0.3677961627452375 + 50 +119.2343164314065 + 51 +126.2926725539458 + 73 + 0 + 72 + 2 + 10 +1.365613936631298 + 20 +1.696475315724717 + 40 +0.3153299658786926 + 50 +177.17352188641 + 51 +195.5421431149888 + 73 + 0 + 72 + 2 + 10 +1.448830865211245 + 20 +2.213371853903018 + 40 +0.5803064835681301 + 50 +228.1704174204192 + 51 +248.1315658423051 + 73 + 1 + 97 + 1 +330 +507 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAA +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.448830865211245 + 20 +2.213371853903018 + 40 +0.5803064835681306 + 50 +252.3365152710513 + 51 +268.8118268997819 + 73 + 1 + 72 + 2 + 10 +2.244252791706375 + 20 +1.579066020312691 + 40 +0.8092671391653076 + 50 +176.1651718242215 + 51 +179.7775214345853 + 73 + 1 + 72 + 2 + 10 +1.382209127764961 + 20 +2.180776385554781 + 40 +0.6008907212088166 + 50 +84.96060718028212 + 51 +99.52487731460255 + 73 + 0 + 72 + 2 + 10 +1.754426611671092 + 20 +1.690434343062297 + 40 +0.4826097226376628 + 50 +167.7663152513758 + 51 +176.4348368363554 + 73 + 0 + 97 + 1 +330 +620 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAB +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.506661351932914 + 20 +2.343882490801417 + 40 +1.137317969685164 + 50 +254.5896536710559 + 51 +264.8320604814776 + 73 + 1 + 72 + 2 + 10 +2.053956362533489 + 20 +1.311094011306244 + 40 +0.3642304650017842 + 50 +15.91994768566973 + 51 +37.94378452603665 + 73 + 0 + 72 + 2 + 10 +2.41136725018985 + 20 +1.266852136052575 + 40 +0.1929333171495304 + 50 +111.3287610035634 + 51 +150.8157377309437 + 73 + 0 + 72 + 2 + 10 +3.174161319020494 + 20 +1.699913413586516 + 40 +1.070082152487879 + 50 +150.4873427015391 + 51 +154.9868167954895 + 73 + 0 + 97 + 1 +330 +4BC + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAC +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.05395636253349 + 20 +1.311094011306242 + 40 +0.40360054374194 + 50 +325.1586938734879 + 51 +345.2415144983743 + 73 + 1 + 72 + 2 + 10 +2.506661351932912 + 20 +2.343882490801414 + 40 +1.137317969685161 + 50 +266.8538285473494 + 51 +278.3272010683704 + 73 + 1 + 72 + 2 + 10 +2.202541654133556 + 20 +1.362543685931675 + 40 +0.4904456831815359 + 50 +17.0728403884595 + 51 +35.67171941040231 + 73 + 0 + 72 + 2 + 10 +2.527478440588521 + 20 +2.947760106017855 + 40 +1.87265752378095 + 50 +87.75100742187989 + 51 +94.35714735717728 + 73 + 0 + 97 + 1 +330 +4BA + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAD +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 2 + 10 +2.202541654133554 + 20 +1.362543685931673 + 40 +0.5298157619216942 + 50 +14.96903515149527 + 51 +32.33949759932654 + 73 + 0 + 72 + 2 + 10 +2.527478440588518 + 20 +2.947760106017868 + 40 +1.872657523780963 + 50 +273.7568474686516 + 51 +276.0943494215687 + 73 + 1 + 72 + 2 + 10 +2.617288604059703 + 20 +2.10660015529557 + 40 +1.026716669960875 + 50 +276.0943494215687 + 51 +282.0831632762506 + 73 + 1 + 72 + 2 + 10 +2.502316662315184 + 20 +1.425846770903515 + 40 +0.4618440522407246 + 50 +315.5859663701619 + 51 +343.4723636742463 + 73 + 1 + 72 + 2 + 10 +2.506661351932922 + 20 +2.3438824908014 + 40 +1.137317969685146 + 50 +67.32624731613089 + 51 +79.47656760874074 + 73 + 0 + 97 + 1 +330 +4B9 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAE +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 2 + 10 +2.506661351932912 + 20 +2.343882490801413 + 40 +1.137317969685161 + 50 +295.2104838476032 + 51 +307.4903876208237 + 73 + 1 + 72 + 2 + 10 +2.72065401068705 + 20 +1.473292657067691 + 40 +0.4792688318657009 + 50 +3.806985506611603 + 51 +27.08574039713036 + 73 + 0 + 72 + 2 + 10 +3.019270278182163 + 20 +1.32057676085313 + 40 +0.1438678477148946 + 50 +27.08574039713062 + 51 +62.91425960287042 + 73 + 0 + 72 + 2 + 10 +2.617288604059699 + 20 +2.106600155295566 + 40 +1.026716669960872 + 50 +62.91425960286999 + 51 +74.08618998756283 + 73 + 0 + 72 + 2 + 10 +2.502316662315185 + 20 +1.425846770903515 + 40 +0.5012141309808816 + 50 +322.28430360547 + 51 +347.21072780023 + 73 + 1 + 97 + 1 +330 +4AD + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BAF +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.358343856922912 + 20 +2.56087150497244 + 40 +1.017884167165223 + 50 +255.9706947110459 + 51 +262.6477274601202 + 73 + 1 + 72 + 2 + 10 +1.875100795739507 + 20 +1.635718008880588 + 40 +0.3629259890852237 + 50 +346.5587102880505 + 51 +357.396057379031 + 73 + 1 + 72 + 2 + 10 +2.23202592329045 + 20 +2.762062415766459 + 40 +1.142846610535554 + 50 +89.71793740532951 + 51 +96.29947398788597 + 73 + 0 + 72 + 2 + 10 +3.174161319020505 + 20 +1.699913413586497 + 40 +1.070082152487882 + 50 +183.9544802865682 + 51 +186.7925864334441 + 73 + 1 + 97 + 1 +330 +4C0 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB0 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.35834385692291 + 20 +2.560871504972433 + 40 +1.017884167165215 + 50 +264.8798691909198 + 51 +277.0962125668474 + 73 + 1 + 72 + 2 + 10 +2.157099264484859 + 20 +1.761255447038774 + 40 +0.3888707645596128 + 50 +327.2321171951457 + 51 +344.8146293833702 + 73 + 1 + 72 + 2 + 10 +2.232025923290449 + 20 +2.762062415766465 + 40 +1.14284661053556 + 50 +74.76238100741742 + 51 +87.73997032522614 + 73 + 0 + 72 + 2 + 10 +1.875100795739506 + 20 +1.635718008880588 + 40 +0.4022960678253824 + 50 +2.224226079808037 + 51 +12.73296995122379 + 73 + 0 + 97 + 1 +330 +4C1 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB1 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.157099264484858 + 20 +1.761255447038777 + 40 +0.4282408432997721 + 50 +12.00230574940428 + 51 +28.29091643485702 + 73 + 0 + 72 + 2 + 10 +2.358343856922911 + 20 +2.560871504972434 + 40 +1.017884167165216 + 50 +279.9480036533407 + 51 +296.005896865796 + 73 + 1 + 72 + 2 + 10 +2.43480848147727 + 20 +1.74176023846554 + 40 +0.3820244196138822 + 50 +345.4907424301736 + 51 +365.6076870699981 + 73 + 1 + 72 + 2 + 10 +2.232025923290445 + 20 +2.762062415766465 + 40 +1.142846610535562 + 50 +59.32877074017064 + 51 +72.48465458233305 + 73 + 0 + 97 + 1 +330 +4C3 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB2 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.434808481477273 + 20 +1.741760238465535 + 40 +0.4213944983540373 + 50 +350.138398092684 + 51 +368.2079411900966 + 73 + 1 + 72 + 2 + 10 +2.232025923290449 + 20 +2.76206241576646 + 40 +1.142846610535555 + 50 +302.8460023643591 + 51 +313.5174616433824 + 73 + 1 + 72 + 2 + 10 +2.435514026542539 + 20 +1.986930556286178 + 40 +0.5859069085937808 + 50 +5.250840664227033 + 51 +24.12657987446927 + 73 + 0 + 72 + 2 + 10 +2.358343856922903 + 20 +2.560871504972432 + 40 +1.017884167165218 + 50 +53.04812421612736 + 51 +61.11882105703474 + 73 + 0 + 97 + 1 +330 +510 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB3 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 11 + 72 + 2 + 10 +1.735391678484751 + 20 +1.622446814297793 + 40 +0.3637008069698632 + 50 +46.50828210019076 + 51 +127.3801843342055 + 73 + 0 + 72 + 2 + 10 +2.244252791706377 + 20 +1.579066020312692 + 40 +0.7698970604251519 + 50 +198.604632170139 + 51 +206.170680909061 + 73 + 1 + 72 + 2 + 10 +1.87217070432574 + 20 +1.396215376152875 + 40 +0.3553136094539483 + 50 +206.170680909061 + 51 +220.7958011940912 + 73 + 1 + 72 + 2 + 10 +1.754854449164134 + 20 +1.637701886096329 + 40 +0.4973281664865742 + 50 +252.2434918237404 + 51 +291.0055844420299 + 73 + 1 + 72 + 2 + 10 +1.940182455435743 + 20 +1.155046537921708 + 40 +0.0196850393700786 + 50 +248.9944155579697 + 51 +428.9944155579707 + 73 + 0 + 72 + 2 + 10 +1.754854449164133 + 20 +1.637701886096329 + 40 +0.5366982452267322 + 50 +68.99441555797011 + 51 +99.84027979757452 + 73 + 0 + 72 + 2 + 10 +1.872170704325739 + 20 +1.396215376152874 + 40 +0.3553136094539469 + 50 +233.9619057741986 + 51 +253.8293190909382 + 73 + 1 + 72 + 2 + 10 +1.867289566555308 + 20 +1.379382243234548 + 40 +0.3377870618823355 + 50 +253.8293190909384 + 51 +276.1706809090611 + 73 + 1 + 72 + 2 + 10 +1.842733556184505 + 20 +1.606506575382589 + 40 +0.5662349988373994 + 50 +276.170680909061 + 51 +300.6079669543535 + 73 + 1 + 72 + 2 + 10 +2.448387279831183 + 20 +1.47470612641788 + 40 +0.4765713362946238 + 50 +131.7514141291648 + 51 +162.7742566190203 + 73 + 0 + 72 + 2 + 10 +3.245154141911026 + 20 +1.721739021653879 + 40 +1.31075517924367 + 50 +162.7742566190193 + 51 +163.9156492780123 + 73 + 0 + 97 + 1 +330 +4F4 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB4 +330 +1F +100 +AcDbEntity + 8 +HATCH-YELLOW +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 36 + 72 + 2 + 10 +2.043049297315998 + 20 +2.110655210550977 + 40 +0.3135948678531067 + 50 +140.7856547310828 + 51 +150.7972901196548 + 73 + 1 + 72 + 2 + 10 +4.316192387813921 + 20 +0.8400973818280717 + 40 +2.91772556849152 + 50 +150.7972901196538 + 51 +151.5606552199046 + 73 + 1 + 72 + 2 + 10 +1.82896029060598 + 20 +2.312110103765454 + 40 +0.1138088004365485 + 50 +226.4676036039469 + 51 +253.8346334294888 + 73 + 1 + 72 + 2 + 10 +1.791794192050712 + 20 +2.183894323205893 + 40 +0.0196850393700787 + 50 +286.1653665705111 + 51 +466.1653665705111 + 73 + 0 + 72 + 2 + 10 +1.82896029060598 + 20 +2.312110103765454 + 40 +0.153178879176706 + 50 +106.1653665705111 + 51 +129.487348884315 + 73 + 0 + 72 + 2 + 10 +4.31619238781396 + 20 +0.8400973818280881 + 40 +2.917725568491546 + 50 +152.3551430085055 + 51 +153.8293190909382 + 73 + 1 + 72 + 2 + 10 +-0.1012307034243785 + 20 +3.010931950741638 + 40 +2.004281084551068 + 50 +26.17068090906094 + 51 +27.44285015917365 + 73 + 0 + 72 + 2 + 10 +1.869973878918131 + 20 +2.229032723885394 + 40 +0.2390599525801008 + 50 +216.3816426472188 + 51 +279.0739534633693 + 73 + 1 + 72 + 2 + 10 +1.910780338072042 + 20 +1.973525769477851 + 40 +0.0196850393700789 + 50 +260.9260465366305 + 51 +440.9260465366307 + 73 + 0 + 72 + 2 + 10 +1.869973878918132 + 20 +2.229032723885395 + 40 +0.278430031320259 + 50 +80.92604653663092 + 51 +139.8013610445865 + 73 + 0 + 72 + 2 + 10 +-0.101230703424352 + 20 +3.01093195074165 + 40 +2.004281084551049 + 50 +28.67087156360686 + 51 +33.18792433993601 + 73 + 0 + 72 + 2 + 10 +1.813793246529746 + 20 +2.127914574971419 + 40 +0.3198926968250738 + 50 +222.0119914468626 + 51 +273.6941141002521 + 73 + 1 + 72 + 2 + 10 +1.835672170020508 + 20 +1.78904239903142 + 40 +0.0196850393700788 + 50 +266.3058858997472 + 51 +446.3058858997478 + 73 + 0 + 72 + 2 + 10 +1.813793246529746 + 20 +2.127914574971419 + 40 +0.3592627755652315 + 50 +86.30588589974785 + 51 +136.3371185375852 + 73 + 0 + 72 + 2 + 10 +1.995105659775399 + 20 +1.606003070595645 + 40 +0.5192979821599312 + 50 +148.1708625321174 + 51 +171.6429565217715 + 73 + 1 + 72 + 2 + 10 +1.774379750743404 + 20 +1.9596864265737 + 40 +0.4040824222682091 + 50 +223.5109336967462 + 51 +281.1199173397384 + 73 + 1 + 72 + 2 + 10 +1.85610884645455 + 20 +1.543874911031386 + 40 +0.0196850393700787 + 50 +258.8800826602615 + 51 +438.8800826602615 + 73 + 0 + 72 + 2 + 10 +1.774379750743404 + 20 +1.9596864265737 + 40 +0.4434525010083663 + 50 +78.88008266026162 + 51 +132.2628434475095 + 73 + 0 + 72 + 2 + 10 +2.244252791706375 + 20 +1.579066020312694 + 40 +0.7698970604251502 + 50 +176.0947114644605 + 51 +193.0143530481955 + 73 + 1 + 72 + 2 + 10 +1.735391678484751 + 20 +1.622446814297793 + 40 +0.3243307282297058 + 50 +221.9378076910892 + 51 +317.3250616801697 + 73 + 1 + 72 + 2 + 10 +3.245154141910992 + 20 +1.721739021653846 + 40 +1.310755179243628 + 50 +165.9082787983328 + 51 +187.2257433809798 + 73 + 0 + 72 + 2 + 10 +2.601728566753492 + 20 +1.803316300498068 + 40 +0.6621787973190414 + 50 +187.2257433809798 + 51 +200.265282453191 + 73 + 0 + 72 + 2 + 10 +1.486332025585369 + 20 +2.215145842661859 + 40 +0.5268178451693419 + 50 +339.734717546809 + 51 +365.875687911445 + 73 + 1 + 72 + 2 + 10 +1.780100104900293 + 20 +2.245377841414935 + 40 +0.231498258665186 + 50 +5.875687911445098 + 51 +34.12431208855465 + 73 + 1 + 72 + 2 + 10 +1.928818024879454 + 20 +2.346159501416084 + 40 +0.0518487033762426 + 50 +34.12431208855484 + 51 +115.8756879114452 + 73 + 1 + 72 + 2 + 10 +2.043049297315996 + 20 +2.110655210550977 + 40 +0.3135948678531048 + 50 +115.8756879114451 + 51 +131.7156800642676 + 73 + 1 + 72 + 2 + 10 +2.105362384851459 + 20 +2.371962053549119 + 40 +0.2723538322513749 + 50 +185.7363493931126 + 51 +196.6535421822968 + 73 + 1 + 72 + 2 + 10 +2.224366300494004 + 20 +2.407559786221583 + 40 +0.3965678834278744 + 50 +196.6535421822967 + 51 +214.2452636527788 + 73 + 1 + 72 + 2 + 10 +1.775114796299714 + 20 +2.101729675474409 + 40 +0.1469014999420266 + 50 +325.7547363472213 + 51 +394.2452636527789 + 73 + 0 + 72 + 2 + 10 +1.880276536811822 + 20 +2.030140317515856 + 40 +0.0196850393700786 + 50 +34.24526365277875 + 51 +214.2452636527787 + 73 + 0 + 72 + 2 + 10 +1.775114796299714 + 20 +2.101729675474409 + 40 +0.1075314212018693 + 50 +325.7547363472211 + 51 +383.6864830926802 + 73 + 1 + 72 + 2 + 10 +1.724258670730545 + 20 +2.179559731729328 + 40 +0.1532919477378671 + 50 +13.05681211459937 + 51 +58.88974415557702 + 73 + 0 + 72 + 2 + 10 +1.793291568736173 + 20 +2.065168888754275 + 40 +0.0196850393700787 + 50 +58.88974415557702 + 51 +238.8897441555765 + 73 + 0 + 72 + 2 + 10 +1.724258670730541 + 20 +2.179559731729329 + 40 +0.1139218689977123 + 50 +301.1102558444241 + 51 +381.2576330469557 + 73 + 1 + 72 + 2 + 10 +2.224366300494005 + 20 +2.407559786221586 + 40 +0.435937962168034 + 50 +154.6425959514791 + 51 +163.3464578177032 + 73 + 0 + 72 + 2 + 10 +2.105362384851463 + 20 +2.371962053549115 + 40 +0.3117239109915352 + 50 +163.3464578177044 + 51 +168.3316806257954 + 73 + 0 + 97 + 1 +330 +4F7 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB6 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.034012571047431 + 20 +0.4770274671951757 + 40 +0.7071698573021327 + 50 +88.2250617963899 + 51 +113.037640194644 + 73 + 1 + 72 + 2 + 10 +0.9476260308821789 + 20 +1.102477175547732 + 40 +0.1920311575011529 + 50 +187.577294301379 + 51 +259.5173177193701 + 73 + 0 + 72 + 2 + 10 +1.168606309785881 + 20 +1.558605525778299 + 40 +0.3700601913995948 + 50 +226.2464306309096 + 51 +229.2045371712558 + 73 + 1 + 72 + 2 + 10 +1.584035429735768 + 20 +2.03996185073825 + 40 +1.005894497867316 + 50 +229.2045371712552 + 51 +238.3301051192357 + 73 + 1 + 97 + 1 +330 +4E7 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB7 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 6 + 72 + 2 + 10 +1.268369849054951 + 20 +1.97737114518936 + 40 +0.4071662414853972 + 50 +214.7414744545867 + 51 +240.7656835685936 + 73 + 1 + 72 + 2 + 10 +1.382209127764962 + 20 +2.180776385554782 + 40 +0.6402607999489762 + 50 +240.7656835685933 + 51 +274.8013992041994 + 73 + 1 + 72 + 2 + 10 +2.244252791706376 + 20 +1.579066020312693 + 40 +0.8092671391653085 + 50 +182.5711456908801 + 51 +205.0661840751609 + 73 + 1 + 72 + 2 + 10 +1.454717916970982 + 20 +2.022108206218515 + 40 +0.78792753486166 + 50 +85.88902674875129 + 51 +141.3773954764613 + 73 + 0 + 72 + 2 + 10 +1.168606309785876 + 20 +1.558605525778289 + 40 +0.3306901126594269 + 50 +175.0885918849935 + 51 +182.1149161181871 + 73 + 0 + 72 + 2 + 10 +1.060157361703603 + 20 +1.562610439508386 + 40 +0.2221672409957212 + 50 +182.1149161181872 + 51 +235.3333452342021 + 73 + 0 + 97 + 1 +330 +4EE + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB8 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 7 + 72 + 2 + 10 +1.995105659775398 + 20 +1.606003070595649 + 40 +0.5586680609000869 + 50 +153.1774302023765 + 51 +173.1639087815069 + 73 + 1 + 72 + 2 + 10 +1.448830865211247 + 20 +2.213371853903018 + 40 +0.5409364048279738 + 50 +90.89204265530425 + 51 +153.6751728635248 + 73 + 0 + 72 + 2 + 10 +1.163637847655053 + 20 +1.838026139816656 + 40 +0.2412638458944706 + 50 +214.15747754694 + 51 +242.0052969205898 + 73 + 0 + 72 + 2 + 10 +1.134374454956795 + 20 +1.893074853652674 + 40 +0.1789203855540918 + 50 +242.0052969205894 + 51 +284.046994134434 + 73 + 0 + 72 + 2 + 10 +1.318324160529892 + 20 +2.123002906229338 + 40 +0.1514028023784195 + 50 +201.853727881165 + 51 +212.2168526331622 + 73 + 1 + 72 + 2 + 10 +1.492137893232153 + 20 +2.232530667257897 + 40 +0.3568475494804613 + 50 +212.2168526331617 + 51 +237.7831473668378 + 73 + 1 + 72 + 2 + 10 +1.573128668857933 + 20 +2.361057982102735 + 40 +0.5087645544459671 + 50 +237.7831473668379 + 51 +261.3425166986952 + 73 + 1 + 97 + 1 +330 +505 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BB9 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 6 + 72 + 2 + 10 +1.573128668857933 + 20 +2.361057982102735 + 40 +0.4693944757058101 + 50 +96.86618894004766 + 51 +122.2168526331621 + 73 + 0 + 72 + 2 + 10 +1.492137893232154 + 20 +2.232530667257898 + 40 +0.3174774707403054 + 50 +122.2168526331621 + 51 +147.7831473668382 + 73 + 0 + 72 + 2 + 10 +1.318324160529893 + 20 +2.123002906229338 + 40 +0.1120327236382623 + 50 +147.783147366838 + 51 +287.1653967341294 + 73 + 0 + 72 + 2 + 10 +1.134452552508394 + 20 +1.527737292608446 + 40 +0.7350495123332927 + 50 +287.1653967341295 + 51 +311.9725813008354 + 73 + 0 + 72 + 2 + 10 +-0.1012307034243558 + 20 +3.010931950741639 + 40 +1.964911005810889 + 50 +28.47135626072658 + 51 +33.82931909093841 + 73 + 0 + 72 + 2 + 10 +1.9951056597754 + 20 +1.606003070595648 + 40 +0.5586680609000885 + 50 +146.1706809090616 + 51 +148.8453401595469 + 73 + 1 + 97 + 1 +330 +50B + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BBA +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 6 + 72 + 2 + 10 +2.506661351932914 + 20 +2.343882490801411 + 40 +1.097947890945 + 50 +252.9025993502986 + 51 +309.129589783908 + 73 + 1 + 72 + 2 + 10 +2.720654010687031 + 20 +1.473292657067699 + 40 +0.4792688318657188 + 50 +2.258737765182703 + 51 +4.269906958171121 + 73 + 1 + 72 + 2 + 10 +2.805854019540959 + 20 +1.479653877718507 + 40 +0.3938316816506187 + 50 +4.26990695817209 + 51 +31.68755658158391 + 73 + 1 + 72 + 2 + 10 +3.031233358735755 + 20 +1.618783385319762 + 40 +0.1289678177105734 + 50 +31.68755658158397 + 51 +88.75077942665364 + 73 + 1 + 72 + 2 + 10 +2.358343856922911 + 20 +2.560871504972435 + 40 +1.057254245905374 + 50 +50.27455552545634 + 51 +103.1717867618754 + 73 + 0 + 72 + 2 + 10 +3.174161319020478 + 20 +1.699913413586489 + 40 +1.070082152487853 + 50 +189.0587348045097 + 51 +202.2656996106713 + 73 + 1 + 97 + 1 +330 +4B5 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BBB +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 7 + 72 + 2 + 10 +3.174161319020492 + 20 +1.69991341358649 + 40 +1.070082152487867 + 50 +178.182030269148 + 51 +186.2319675330486 + 73 + 0 + 72 + 2 + 10 +3.496410384846752 + 20 +1.66472403412841 + 40 +1.394246852682911 + 50 +186.2319675330462 + 51 +188.4100158185151 + 73 + 0 + 72 + 2 + 10 +2.05576545700618 + 20 +2.861012413940887 + 40 +0.994268550367224 + 50 +273.5399568619239 + 51 +308.9576328012706 + 73 + 1 + 72 + 1 + 10 +2.680907394207461 + 20 +2.087858154687554 + 11 +2.747050780866419 + 21 +2.134172252628876 + 72 + 2 + 10 +2.833454996760046 + 20 +2.010774243926277 + 40 +0.1506411533278984 + 50 +235.0000000000002 + 51 +295.0 + 73 + 0 + 72 + 2 + 10 +2.807174025728471 + 20 +1.954414519671351 + 40 +0.2128272285895981 + 50 +294.9999999999998 + 51 +351.1901840561478 + 73 + 0 + 72 + 2 + 10 +2.232025923290446 + 20 +2.76206241576646 + 40 +1.1034765317954 + 50 +44.6177154324492 + 51 +96.63019658365178 + 73 + 0 + 97 + 1 +330 +4C7 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BBC +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 6 + 72 + 2 + 10 +2.05576545700618 + 20 +2.861012413940887 + 40 +0.9548984716270655 + 50 +274.0763809413058 + 51 +308.9974179950865 + 73 + 1 + 72 + 2 + 10 +2.583746606177169 + 20 +2.208949913643178 + 40 +0.1158814287879965 + 50 +308.9974179950865 + 51 +381.0025820049136 + 73 + 1 + 72 + 2 + 10 +2.64643710148901 + 20 +2.233017781588249 + 40 +0.0487296568838581 + 50 +21.00258200491355 + 51 +88.99741799508618 + 73 + 1 + 72 + 2 + 10 +2.643315164634613 + 20 +2.054622849494738 + 40 +0.2271519040571613 + 50 +88.99741799508604 + 51 +114.6269796357359 + 73 + 1 + 72 + 2 + 10 +3.303260542295614 + 20 +0.6149685670603082 + 40 +1.810860322430921 + 50 +114.6269796357358 + 51 +129.7728051417874 + 73 + 1 + 72 + 2 + 10 +3.496410384846758 + 20 +1.664724034128341 + 40 +1.394246852682927 + 50 +165.7987430109054 + 51 +169.9291703474848 + 73 + 1 + 97 + 1 +330 +4C8 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BFB +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 8 + 72 + 2 + 10 +2.10076671703864 + 20 +3.325655213407455 + 40 +0.0599397668605327 + 50 +267.8793336511986 + 51 +377.8793336511989 + 73 + 1 + 72 + 2 + 10 +2.052741812238583 + 20 +3.310162719091439 + 40 +0.1104017214519507 + 50 +17.87933365119892 + 51 +43.7673166448306 + 73 + 1 + 72 + 2 + 10 +2.103395451769339 + 20 +3.340116557206334 + 40 +0.0547683672910658 + 50 +57.93744139888317 + 51 +187.77563216475 + 73 + 1 + 72 + 2 + 10 +2.068634698539837 + 20 +3.335369986556996 + 40 +0.0196850393700788 + 50 +187.7756321647501 + 51 +367.7756321647502 + 73 + 1 + 72 + 2 + 10 +2.103395451769339 + 20 +3.340116557206334 + 40 +0.0153982885509082 + 50 +172.2243678352504 + 51 +287.334302618237 + 73 + 0 + 72 + 2 + 10 +2.052741812238584 + 20 +3.310162719091439 + 40 +0.0710316427117921 + 50 +321.0507208994834 + 51 +342.1206663488011 + 73 + 0 + 72 + 2 + 10 +2.100766717038639 + 20 +3.325655213407456 + 40 +0.0205696881203755 + 50 +342.1206663488009 + 51 +452.1206663488013 + 73 + 0 + 72 + 2 + 10 +2.099277124665835 + 20 +3.285428055915363 + 40 +0.0196850393700787 + 50 +87.8793336512005 + 51 +267.8793336511979 + 73 + 1 + 97 + 1 +330 +235 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BFC +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 8 + 72 + 2 + 10 +1.921485017130019 + 20 +3.343003198213819 + 40 +0.0771903814552135 + 50 +359.5978819190761 + 51 +374.2374903606301 + 73 + 1 + 72 + 2 + 10 +1.980044176928186 + 20 +3.357861720825169 + 40 +0.0167755580220592 + 50 +14.23749036062933 + 51 +155.7625096393687 + 73 + 1 + 72 + 2 + 10 +2.003282808101446 + 20 +3.34739958355454 + 40 +0.0422606574936387 + 50 +155.7625096393692 + 51 +241.4329313324614 + 73 + 1 + 72 + 2 + 10 +1.973661171909946 + 20 +3.292995281984995 + 40 +0.0196850393700789 + 50 +298.5670686675385 + 51 +478.5670686675385 + 73 + 0 + 72 + 2 + 10 +2.003282808101446 + 20 +3.34739958355454 + 40 +0.0816307362337962 + 50 +118.5670686675387 + 51 +204.2374903606309 + 73 + 0 + 72 + 2 + 10 +1.980044176928186 + 20 +3.357861720825169 + 40 +0.0561456367622165 + 50 +204.2374903606306 + 51 +345.7625096393699 + 73 + 0 + 72 + 2 + 10 +1.921485017130019 + 20 +3.34300319821382 + 40 +0.1165604601953712 + 50 +345.76250963937 + 51 +360.4021180809241 + 73 + 0 + 72 + 2 + 10 +2.018358052101874 + 20 +3.342323304531541 + 40 +0.0196850393700787 + 50 +0.4021180809244088 + 51 +180.4021180809231 + 73 + 0 + 97 + 1 +330 +267 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BFD +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.278537892029333 + 20 +3.728579428420916 + 40 +0.0853095785363673 + 50 +12.6821846844064 + 51 +72.68218468440622 + 73 + 1 + 72 + 2 + 10 +2.309791821489833 + 20 +3.828814460633206 + 40 +0.0196850393700787 + 50 +107.3178153155941 + 51 +287.3178153155944 + 73 + 0 + 72 + 2 + 10 +2.278537892029333 + 20 +3.728579428420916 + 40 +0.1246796572765245 + 50 +287.3178153155936 + 51 +347.3178153155935 + 73 + 0 + 72 + 2 + 10 +2.380970941004577 + 20 +3.751630247646181 + 40 +0.0196850393700789 + 50 +347.3178153155935 + 51 +527.3178153155935 + 73 + 0 + 97 + 1 +330 +451 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +BFE +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +2.07909456474772 + 20 +3.772298844618632 + 40 +0.1175982774997528 + 50 +111.5543469318192 + 51 +141.5543469318192 + 73 + 1 + 72 + 2 + 10 +1.971574507059384 + 20 +3.857657770838914 + 40 +0.0196850393700788 + 50 +38.44565306818044 + 51 +218.4456530681808 + 73 + 0 + 72 + 2 + 10 +2.079094564747719 + 20 +3.772298844618632 + 40 +0.1569683562399099 + 50 +218.4456530681809 + 51 +248.4456530681809 + 73 + 0 + 72 + 2 + 10 +2.028658926483394 + 20 +3.899981872009325 + 40 +0.0196850393700786 + 50 +248.4456530681804 + 51 +428.4456530681804 + 73 + 0 + 97 + 1 +330 +44F + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C01 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 17 + 72 + 2 + 10 +2.10536238485146 + 20 +2.371962053549118 + 40 +0.2723538322513761 + 50 +159.7337422418206 + 51 +175.1380365575864 + 73 + 1 + 72 + 2 + 10 +2.043049297315996 + 20 +2.110655210550977 + 40 +0.352964946593263 + 50 +233.6796832772765 + 51 +244.1243120885548 + 73 + 0 + 72 + 2 + 10 +1.928818024879453 + 20 +2.346159501416084 + 40 +0.0912187821164004 + 50 +244.1243120885551 + 51 +325.8756879114455 + 73 + 0 + 72 + 2 + 10 +1.780100104900293 + 20 +2.245377841414934 + 40 +0.2708683374053446 + 50 +325.8756879114452 + 51 +354.1243120885547 + 73 + 0 + 72 + 2 + 10 +1.486332025585371 + 20 +2.215145842661859 + 40 +0.5661879239094977 + 50 +354.124312088555 + 51 +380.265282453191 + 73 + 0 + 72 + 2 + 10 +2.601728566753494 + 20 +1.803316300498069 + 40 +0.622808718578886 + 50 +159.7347175468091 + 51 +172.7742566190203 + 73 + 1 + 72 + 2 + 10 +3.245154141910993 + 20 +1.721739021653846 + 40 +1.271385100503472 + 50 +172.7742566190202 + 51 +197.2257433809798 + 73 + 1 + 72 + 2 + 10 +2.448387279831183 + 20 +1.474706126417881 + 40 +0.4372012575544668 + 50 +197.2257433809797 + 51 +229.6909739682446 + 73 + 1 + 72 + 2 + 10 +1.84273355618451 + 20 +1.606506575382588 + 40 +0.5662349988373949 + 50 +304.7588400511317 + 51 +309.2074896477569 + 73 + 1 + 72 + 2 + 10 +3.174161319020478 + 20 +1.699913413586492 + 40 +1.109452231228011 + 50 +151.3367493281762 + 51 +186.2319675330486 + 73 + 0 + 72 + 2 + 10 +3.49641038484678 + 20 +1.664724034128332 + 40 +1.433616931423104 + 50 +186.2319675330492 + 51 +205.0988169699291 + 73 + 0 + 72 + 2 + 10 +-37.1850685335689 + 20 +20.72029698200291 + 40 +43.48962412887072 + 50 +334.901183030072 + 51 +335.0988169699286 + 73 + 1 + 72 + 2 + 10 +1.05207209728287 + 20 +2.970247608757844 + 40 +1.33344811187206 + 50 +335.0988169699285 + 51 +348.9886439523909 + 73 + 1 + 72 + 2 + 10 +1.959203223948364 + 20 +2.950701101027533 + 40 +0.4655223034750759 + 50 +30.33963089325502 + 51 +49.03787718203768 + 73 + 0 + 72 + 2 + 10 +1.804450685812644 + 20 +3.128961400613438 + 40 +0.701583910831935 + 50 +49.03787718203728 + 51 +65.26030603284518 + 73 + 0 + 72 + 2 + 10 +1.924151714798596 + 20 +2.869186907390315 + 40 +0.4155574720721139 + 50 +65.26030603284511 + 51 +82.84890216530907 + 73 + 0 + 72 + 2 + 10 +1.936208898089171 + 20 +2.773084900679216 + 40 +0.318702057340656 + 50 +82.84890216530943 + 51 +105.7184590811235 + 73 + 0 + 97 + 1 +330 +4F3 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C20 +330 +1F +100 +AcDbEntity + 8 +HATCH-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 3 + 92 + 1 + 93 + 17 + 72 + 2 + 10 +1.885608931176688 + 20 +3.176688874055116 + 40 +0.2129975912966591 + 50 +114.9006616575818 + 51 +156.4878117659684 + 73 + 1 + 72 + 2 + 10 +2.636203773812854 + 20 +2.850131072655588 + 40 +1.031552791296577 + 50 +156.4878117659688 + 51 +180.6082887577103 + 73 + 1 + 72 + 2 + 10 +1.952094170360633 + 20 +2.842867853274917 + 40 +0.3474046319836055 + 50 +180.6082887577101 + 51 +213.6393369978933 + 73 + 1 + 72 + 2 + 10 +1.964644164547905 + 20 +2.851218474936612 + 40 +0.3624789557242355 + 50 +213.6393369978933 + 51 +250.0019612921961 + 73 + 1 + 72 + 2 + 10 +1.936208898089171 + 20 +2.773084900679217 + 40 +0.2793319786004991 + 50 +250.001961292196 + 51 +277.1510978346906 + 73 + 1 + 72 + 2 + 10 +1.924151714798597 + 20 +2.869186907390317 + 40 +0.3761873933319576 + 50 +277.1510978346908 + 51 +294.7396939671547 + 73 + 1 + 72 + 2 + 10 +1.804450685812644 + 20 +3.128961400613437 + 40 +0.6622138320917775 + 50 +294.7396939671549 + 51 +310.9621228179628 + 73 + 1 + 72 + 2 + 10 +1.959203223948364 + 20 +2.950701101027533 + 40 +0.4261522247349184 + 50 +310.9621228179625 + 51 +357.7626023297964 + 73 + 1 + 72 + 2 + 10 +0.9685713550985386 + 20 +2.989404907072427 + 40 +1.417539880590719 + 50 +357.7626023297966 + 51 +367.3820705420636 + 73 + 1 + 72 + 2 + 10 +2.2125235694189 + 20 +3.150570273791624 + 40 +0.1631908912969642 + 50 +7.382070542063584 + 51 +53.5251061991567 + 73 + 1 + 72 + 2 + 10 +1.924407631021267 + 20 +3.452788946261674 + 40 +0.4213817967382122 + 50 +23.94086726929591 + 51 +38.56090658709021 + 73 + 0 + 72 + 2 + 10 +2.174464534980624 + 20 +3.253450334179865 + 40 +0.1015938396722196 + 50 +38.56090658709 + 51 +128.8844964337146 + 73 + 0 + 72 + 1 + 10 +2.110688753100606 + 20 +3.174368364648643 + 11 +2.049360338450518 + 21 +3.223826763560005 + 72 + 1 + 10 +2.049360338450518 + 20 +3.223826763560005 + 11 +2.020698206844207 + 21 +3.208114453397319 + 72 + 2 + 10 +1.961644849992286 + 20 +3.289054064709398 + 40 +0.1001924130602254 + 50 +53.88559445512062 + 51 +115.5479523260344 + 73 + 0 + 72 + 2 + 10 +2.0110372932182 + 20 +3.39238482801838 + 40 +0.2147212744613677 + 50 +115.5479523260344 + 51 +163.3991489022965 + 73 + 0 + 72 + 2 + 10 +2.161160122792123 + 20 +3.437140815427867 + 40 +0.371373635976537 + 50 +163.3991489022961 + 51 +169.5663152899231 + 73 + 0 + 97 + 1 +330 +4C9 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +1.788320029910184 + 20 +2.673441487468005 + 40 +0.2481310319481923 + 50 +339.5601350117603 + 51 +365.5770490458945 + 73 + 1 + 72 + 2 + 10 +2.015684652568724 + 20 +2.695642836263502 + 40 +0.0196850393700789 + 50 +5.57704904589411 + 51 +185.5770490458954 + 73 + 1 + 72 + 2 + 10 +1.788320029910183 + 20 +2.673441487468005 + 40 +0.2087609532080352 + 50 +354.4229509541054 + 51 +380.4398649882396 + 73 + 0 + 72 + 2 + 10 +2.002382887993199 + 20 +2.593662641184479 + 40 +0.0196850393700787 + 50 +159.5601350117616 + 51 +339.5601350117602 + 73 + 1 + 97 + 1 +330 +138 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +1.988631326711838 + 20 +2.675424154108706 + 40 +0.2917786076489145 + 50 +176.6618056290539 + 51 +192.1921376659049 + 73 + 0 + 72 + 2 + 10 +1.722674860472906 + 20 +2.732887777074972 + 40 +0.0196850393700788 + 50 +192.1921376659057 + 51 +372.1921376659045 + 73 + 0 + 72 + 2 + 10 +1.988631326711838 + 20 +2.675424154108705 + 40 +0.2524085289087564 + 50 +167.807862334095 + 51 +183.338194370946 + 73 + 1 + 72 + 2 + 10 +1.716999440920682 + 20 +2.659580274525414 + 40 +0.0196850393700787 + 50 +356.6618056290538 + 51 +536.6618056290539 + 73 + 0 + 97 + 1 +330 +14E + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C24 +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.788320029910184 + 20 +2.673441487468005 + 40 +0.2481310319481923 + 50 +339.5601350117603 + 51 +365.5770490458945 + 73 + 1 + 72 + 2 + 10 +2.015684652568724 + 20 +2.695642836263502 + 40 +0.0196850393700789 + 50 +5.57704904589411 + 51 +185.5770490458954 + 73 + 1 + 72 + 2 + 10 +1.788320029910183 + 20 +2.673441487468005 + 40 +0.2087609532080352 + 50 +354.4229509541054 + 51 +380.4398649882396 + 73 + 0 + 72 + 2 + 10 +2.002382887993199 + 20 +2.593662641184479 + 40 +0.0196850393700787 + 50 +159.5601350117616 + 51 +339.5601350117602 + 73 + 1 + 97 + 1 +330 +138 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C25 +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 4 + 72 + 2 + 10 +1.988631326711838 + 20 +2.675424154108706 + 40 +0.2917786076489145 + 50 +176.6618056290539 + 51 +192.1921376659049 + 73 + 0 + 72 + 2 + 10 +1.722674860472906 + 20 +2.732887777074972 + 40 +0.0196850393700788 + 50 +192.1921376659057 + 51 +372.1921376659045 + 73 + 0 + 72 + 2 + 10 +1.988631326711838 + 20 +2.675424154108705 + 40 +0.2524085289087564 + 50 +167.807862334095 + 51 +183.338194370946 + 73 + 1 + 72 + 2 + 10 +1.716999440920682 + 20 +2.659580274525414 + 40 +0.0196850393700787 + 50 +356.6618056290538 + 51 +536.6618056290539 + 73 + 0 + 97 + 1 +330 +14E + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C28 +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 27 + 92 + 1 + 93 + 48 + 72 + 2 + 10 +3.031233358735754 + 20 +1.618783385319762 + 40 +0.1683378964507315 + 50 +268.8981266360797 + 51 +328.3124434184161 + 73 + 0 + 72 + 2 + 10 +2.805854019540958 + 20 +1.479653877718506 + 40 +0.4332017603907771 + 50 +328.312443418416 + 51 +355.7300930418278 + 73 + 0 + 72 + 2 + 10 +2.720654010687053 + 20 +1.47329265706769 + 40 +0.5186389106058562 + 50 +355.7300930418277 + 51 +387.0857403971304 + 73 + 0 + 72 + 2 + 10 +3.019270278182164 + 20 +1.320576760853129 + 40 +0.1832379264550515 + 50 +27.08574039713041 + 51 +62.91425960287025 + 73 + 0 + 72 + 2 + 10 +2.617288604059704 + 20 +2.106600155295556 + 40 +1.066086748701018 + 50 +62.91425960286999 + 51 +83.90565057843106 + 73 + 0 + 72 + 2 + 10 +2.527478440588518 + 20 +2.94776010601788 + 40 +1.912027602521132 + 50 +83.90565057843116 + 51 +95.51019307772863 + 73 + 0 + 72 + 2 + 10 +2.411367250189849 + 20 +1.266852136052576 + 40 +0.2323033958896882 + 50 +106.8886617051031 + 51 +145.0036277051946 + 73 + 0 + 72 + 2 + 10 +1.842733556184506 + 20 +1.606506575382589 + 40 +0.6056050775775568 + 50 +51.33837874710574 + 51 +83.82931909093898 + 73 + 0 + 72 + 2 + 10 +1.867289566555309 + 20 +1.379382243234547 + 40 +0.3771571406224918 + 50 +83.82931909093904 + 51 +106.1706809090618 + 73 + 0 + 72 + 2 + 10 +1.872170704325742 + 20 +1.396215376152872 + 40 +0.3946836881941034 + 50 +106.1706809090621 + 51 +118.8560326885956 + 73 + 0 + 72 + 2 + 10 +1.542373482613905 + 20 +1.83573967301926 + 40 +0.7974660552058795 + 50 +79.93869473201835 + 51 +101.5302981560868 + 73 + 0 + 72 + 2 + 10 +1.584035429735764 + 20 +2.039961850738246 + 40 +1.00589449786731 + 50 +101.530298156087 + 51 +115.9981291148674 + 73 + 0 + 72 + 2 + 10 +1.03401257104743 + 20 +0.477027467195177 + 40 +0.6677997785619737 + 50 +80.5975463145049 + 51 +115.6894538187781 + 73 + 1 + 72 + 2 + 10 +0.7359925636398887 + 20 +1.096559104863404 + 40 +0.0196850393700787 + 50 +64.3105461812228 + 51 +178.3982111381467 + 73 + 0 + 72 + 2 + 10 +0.9476260308821786 + 20 +1.102477175547731 + 40 +0.2314012362413102 + 50 +178.3982111381469 + 51 +253.5469306045596 + 73 + 0 + 72 + 2 + 10 +1.168606309785877 + 20 +1.558605525778289 + 40 +0.3700601913995847 + 50 +140.7373098431768 + 51 +182.1149161181871 + 73 + 0 + 72 + 2 + 10 +1.060157361703604 + 20 +1.562610439508386 + 40 +0.2615373197358793 + 50 +182.1149161181871 + 51 +235.7398592611448 + 73 + 0 + 72 + 2 + 10 +1.268369849054956 + 20 +1.977371145189359 + 40 +0.4071662414854006 + 50 +150.8060111759436 + 51 +152.0052969205898 + 73 + 0 + 72 + 2 + 10 +1.065938622495786 + 20 +1.869760556959495 + 40 +0.1779099652672192 + 50 +152.0052969205898 + 51 +197.9947030794108 + 73 + 0 + 72 + 2 + 10 +1.163637847655054 + 20 +1.838026139816656 + 40 +0.2806339246346285 + 50 +197.9947030794104 + 51 +242.0052969205895 + 73 + 0 + 72 + 2 + 10 +1.134374454956794 + 20 +1.893074853652674 + 40 +0.2182904642942491 + 50 +242.0052969205897 + 51 +278.7513848946688 + 73 + 0 + 72 + 2 + 10 +1.318324160529893 + 20 +2.123002906229338 + 40 +0.1514028023784197 + 50 +174.626341759492 + 51 +287.1653967341294 + 73 + 0 + 72 + 2 + 10 +1.134452552508395 + 20 +1.527737292608446 + 40 +0.7744195910734504 + 50 +287.1653967341294 + 51 +311.2425077735102 + 73 + 0 + 72 + 2 + 10 +-0.1012307034243847 + 20 +3.010931950741654 + 40 +1.964911005810923 + 50 +332.7104062850323 + 51 +333.8293190909388 + 73 + 1 + 72 + 2 + 10 +4.316192387813981 + 20 +0.8400973818280608 + 40 +2.957095647231735 + 50 +206.1706809090621 + 51 +209.2027098803458 + 73 + 0 + 72 + 2 + 10 +2.043049297315993 + 20 +2.110655210550981 + 40 +0.3529649465932583 + 50 +209.2027098803451 + 51 +225.0870679104569 + 73 + 0 + 72 + 2 + 10 +2.105362384851456 + 20 +2.371962053549119 + 40 +0.3117239109915287 + 50 +177.914487685338 + 51 +200.1246558462194 + 73 + 0 + 72 + 2 + 10 +1.964644164547905 + 20 +2.851218474936612 + 40 +0.4018490344643929 + 50 +112.2213810159718 + 51 +146.3606630021067 + 73 + 0 + 72 + 2 + 10 +1.952094170360633 + 20 +2.842867853274918 + 40 +0.3867747107237632 + 50 +146.3606630021067 + 51 +179.3917112422899 + 73 + 0 + 72 + 2 + 10 +2.636203773812854 + 20 +2.850131072655586 + 40 +1.070922870036734 + 50 +179.3917112422899 + 51 +203.5121882340314 + 73 + 0 + 72 + 2 + 10 +1.885608931176689 + 20 +3.176688874055116 + 40 +0.2523676700368166 + 50 +203.5121882340314 + 51 +247.919074760323 + 73 + 0 + 72 + 2 + 10 +2.161160122792124 + 20 +3.437140815427865 + 40 +0.3713736359765378 + 50 +175.8934715069597 + 51 +235.3701061614485 + 73 + 0 + 72 + 2 + 10 +2.010334078755422 + 20 +3.655531747894149 + 40 +0.1059624550830902 + 50 +235.3701061614487 + 51 +321.8826468892163 + 73 + 0 + 72 + 2 + 10 +1.984695044370156 + 20 +3.635415634546031 + 40 +0.1385510742689834 + 50 +321.8826468892165 + 51 +353.8787479269093 + 73 + 0 + 72 + 2 + 10 +2.205371433700895 + 20 +3.565115244906948 + 40 +0.1187965099453075 + 50 +225.7363985376375 + 51 +338.2090024626373 + 73 + 0 + 72 + 2 + 10 +1.924407631021267 + 20 +3.452788946261673 + 40 +0.4213817967382119 + 50 +338.2090024626376 + 51 +378.4288669894065 + 73 + 0 + 72 + 2 + 10 +2.2125235694189 + 20 +3.150570273791623 + 40 +0.2025609700371219 + 50 +303.4508923017655 + 51 +352.6179294579363 + 73 + 0 + 72 + 2 + 10 +0.968571355098534 + 20 +2.989404907072428 + 40 +1.456909959330881 + 50 +352.6179294579365 + 51 +362.2328550433406 + 73 + 0 + 72 + 2 + 10 +1.052072097282865 + 20 +2.970247608757846 + 40 +1.372818190612224 + 50 +1.569678067828868 + 51 +24.90118303007151 + 73 + 0 + 72 + 2 + 10 +-37.185068533585 + 20 +20.72029698201224 + 40 +43.52899420762941 + 50 +24.90118303007369 + 51 +25.09881696993027 + 73 + 0 + 72 + 2 + 10 +3.496410384846288 + 20 +1.664724034128535 + 40 +1.394246852682421 + 50 +154.9011830300731 + 51 +163.0124653299814 + 73 + 1 + 72 + 2 + 10 +3.303260542295614 + 20 +0.6149685670603104 + 40 +1.850230401171077 + 50 +231.9548675004806 + 51 +245.3730203642641 + 73 + 0 + 72 + 2 + 10 +2.643315164634613 + 20 +2.054622849494737 + 40 +0.2665219827973205 + 50 +245.373020364264 + 51 +271.0025820049138 + 73 + 0 + 72 + 2 + 10 +2.646437101489009 + 20 +2.233017781588249 + 40 +0.0880997356240162 + 50 +271.0025820049141 + 51 +338.9974179950867 + 73 + 0 + 72 + 2 + 10 +2.583746606177169 + 20 +2.208949913643178 + 40 +0.1552515075281532 + 50 +338.9974179950864 + 51 +373.3205824975591 + 73 + 0 + 72 + 2 + 10 +2.833454996760046 + 20 +2.010774243926277 + 40 +0.1900112320680552 + 50 +238.728482917094 + 51 +295.0 + 73 + 0 + 72 + 2 + 10 +2.807174025728471 + 20 +1.954414519671351 + 40 +0.2521973073297553 + 50 +294.9999999999998 + 51 +365.0000000000006 + 73 + 0 + 72 + 2 + 10 +2.435514026542535 + 20 +1.986930556286176 + 40 +0.6252769873339419 + 50 +5.000000000000452 + 51 +18.63891789885247 + 73 + 0 + 97 + 1 +330 +8B3 + 92 + 16 + 93 + 5 + 72 + 2 + 10 +2.506661351932912 + 20 +2.343882490801413 + 40 +1.137317969685161 + 50 +295.2104838476032 + 51 +307.4903876208237 + 73 + 1 + 72 + 2 + 10 +2.72065401068705 + 20 +1.473292657067691 + 40 +0.4792688318657009 + 50 +3.806985506611603 + 51 +27.08574039713036 + 73 + 0 + 72 + 2 + 10 +3.019270278182163 + 20 +1.32057676085313 + 40 +0.1438678477148946 + 50 +27.08574039713062 + 51 +62.91425960287042 + 73 + 0 + 72 + 2 + 10 +2.617288604059699 + 20 +2.106600155295566 + 40 +1.026716669960872 + 50 +62.91425960286999 + 51 +74.08618998756283 + 73 + 0 + 72 + 2 + 10 +2.502316662315185 + 20 +1.425846770903515 + 40 +0.5012141309808816 + 50 +322.28430360547 + 51 +347.21072780023 + 73 + 1 + 97 + 1 +330 +4AD + 92 + 0 + 93 + 4 + 72 + 2 + 10 +2.35834385692291 + 20 +2.560871504972433 + 40 +1.017884167165215 + 50 +264.8798691909198 + 51 +277.0962125668474 + 73 + 1 + 72 + 2 + 10 +2.157099264484859 + 20 +1.761255447038774 + 40 +0.3888707645596128 + 50 +327.2321171951457 + 51 +344.8146293833702 + 73 + 1 + 72 + 2 + 10 +2.232025923290449 + 20 +2.762062415766465 + 40 +1.14284661053556 + 50 +74.76238100741742 + 51 +87.73997032522614 + 73 + 0 + 72 + 2 + 10 +1.875100795739506 + 20 +1.635718008880588 + 40 +0.4022960678253824 + 50 +2.224226079808037 + 51 +12.73296995122379 + 73 + 0 + 97 + 1 +330 +4C1 + 92 + 16 + 93 + 6 + 72 + 2 + 10 +2.506661351932914 + 20 +2.343882490801411 + 40 +1.097947890945 + 50 +252.9025993502986 + 51 +309.129589783908 + 73 + 1 + 72 + 2 + 10 +2.720654010687031 + 20 +1.473292657067699 + 40 +0.4792688318657188 + 50 +2.258737765182703 + 51 +4.269906958171121 + 73 + 1 + 72 + 2 + 10 +2.805854019540959 + 20 +1.479653877718507 + 40 +0.3938316816506187 + 50 +4.26990695817209 + 51 +31.68755658158391 + 73 + 1 + 72 + 2 + 10 +3.031233358735755 + 20 +1.618783385319762 + 40 +0.1289678177105734 + 50 +31.68755658158397 + 51 +88.75077942665364 + 73 + 1 + 72 + 2 + 10 +2.358343856922911 + 20 +2.560871504972435 + 40 +1.057254245905374 + 50 +50.27455552545634 + 51 +103.1717867618754 + 73 + 0 + 72 + 2 + 10 +3.174161319020478 + 20 +1.699913413586489 + 40 +1.070082152487853 + 50 +189.0587348045097 + 51 +202.2656996106713 + 73 + 1 + 97 + 1 +330 +4B5 + 92 + 16 + 93 + 5 + 72 + 2 + 10 +2.202541654133554 + 20 +1.362543685931673 + 40 +0.5298157619216942 + 50 +14.96903515149527 + 51 +32.33949759932654 + 73 + 0 + 72 + 2 + 10 +2.527478440588518 + 20 +2.947760106017868 + 40 +1.872657523780963 + 50 +273.7568474686516 + 51 +276.0943494215687 + 73 + 1 + 72 + 2 + 10 +2.617288604059703 + 20 +2.10660015529557 + 40 +1.026716669960875 + 50 +276.0943494215687 + 51 +282.0831632762506 + 73 + 1 + 72 + 2 + 10 +2.502316662315184 + 20 +1.425846770903515 + 40 +0.4618440522407246 + 50 +315.5859663701619 + 51 +343.4723636742463 + 73 + 1 + 72 + 2 + 10 +2.506661351932922 + 20 +2.3438824908014 + 40 +1.137317969685146 + 50 +67.32624731613089 + 51 +79.47656760874074 + 73 + 0 + 97 + 1 +330 +4B9 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +2.05395636253349 + 20 +1.311094011306242 + 40 +0.40360054374194 + 50 +325.1586938734879 + 51 +345.2415144983743 + 73 + 1 + 72 + 2 + 10 +2.506661351932912 + 20 +2.343882490801414 + 40 +1.137317969685161 + 50 +266.8538285473494 + 51 +278.3272010683704 + 73 + 1 + 72 + 2 + 10 +2.202541654133556 + 20 +1.362543685931675 + 40 +0.4904456831815359 + 50 +17.0728403884595 + 51 +35.67171941040231 + 73 + 0 + 72 + 2 + 10 +2.527478440588521 + 20 +2.947760106017855 + 40 +1.87265752378095 + 50 +87.75100742187989 + 51 +94.35714735717728 + 73 + 0 + 97 + 1 +330 +4BA + 92 + 16 + 93 + 4 + 72 + 2 + 10 +2.506661351932914 + 20 +2.343882490801417 + 40 +1.137317969685164 + 50 +254.5896536710559 + 51 +264.8320604814776 + 73 + 1 + 72 + 2 + 10 +2.053956362533489 + 20 +1.311094011306244 + 40 +0.3642304650017842 + 50 +15.91994768566973 + 51 +37.94378452603665 + 73 + 0 + 72 + 2 + 10 +2.41136725018985 + 20 +1.266852136052575 + 40 +0.1929333171495304 + 50 +111.3287610035634 + 51 +150.8157377309437 + 73 + 0 + 72 + 2 + 10 +3.174161319020494 + 20 +1.699913413586516 + 40 +1.070082152487879 + 50 +150.4873427015391 + 51 +154.9868167954895 + 73 + 0 + 97 + 1 +330 +4BC + 92 + 0 + 93 + 4 + 72 + 2 + 10 +2.358343856922912 + 20 +2.56087150497244 + 40 +1.017884167165223 + 50 +255.9706947110459 + 51 +262.6477274601202 + 73 + 1 + 72 + 2 + 10 +1.875100795739507 + 20 +1.635718008880588 + 40 +0.3629259890852237 + 50 +346.5587102880505 + 51 +357.396057379031 + 73 + 1 + 72 + 2 + 10 +2.23202592329045 + 20 +2.762062415766459 + 40 +1.142846610535554 + 50 +89.71793740532951 + 51 +96.29947398788597 + 73 + 0 + 72 + 2 + 10 +3.174161319020505 + 20 +1.699913413586497 + 40 +1.070082152487882 + 50 +183.9544802865682 + 51 +186.7925864334441 + 73 + 1 + 97 + 1 +330 +4C0 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +2.157099264484858 + 20 +1.761255447038777 + 40 +0.4282408432997721 + 50 +12.00230574940428 + 51 +28.29091643485702 + 73 + 0 + 72 + 2 + 10 +2.358343856922911 + 20 +2.560871504972434 + 40 +1.017884167165216 + 50 +279.9480036533407 + 51 +296.005896865796 + 73 + 1 + 72 + 2 + 10 +2.43480848147727 + 20 +1.74176023846554 + 40 +0.3820244196138822 + 50 +345.4907424301736 + 51 +365.6076870699981 + 73 + 1 + 72 + 2 + 10 +2.232025923290445 + 20 +2.762062415766465 + 40 +1.142846610535562 + 50 +59.32877074017064 + 51 +72.48465458233305 + 73 + 0 + 97 + 1 +330 +4C3 + 92 + 16 + 93 + 7 + 72 + 2 + 10 +3.174161319020492 + 20 +1.69991341358649 + 40 +1.070082152487867 + 50 +178.182030269148 + 51 +186.2319675330486 + 73 + 0 + 72 + 2 + 10 +3.496410384846752 + 20 +1.66472403412841 + 40 +1.394246852682911 + 50 +186.2319675330462 + 51 +188.4100158185151 + 73 + 0 + 72 + 2 + 10 +2.05576545700618 + 20 +2.861012413940887 + 40 +0.994268550367224 + 50 +273.5399568619239 + 51 +308.9576328012706 + 73 + 1 + 72 + 1 + 10 +2.680907394207461 + 20 +2.087858154687554 + 11 +2.747050780866419 + 21 +2.134172252628876 + 72 + 2 + 10 +2.833454996760046 + 20 +2.010774243926277 + 40 +0.1506411533278984 + 50 +235.0000000000002 + 51 +295.0 + 73 + 0 + 72 + 2 + 10 +2.807174025728471 + 20 +1.954414519671351 + 40 +0.2128272285895981 + 50 +294.9999999999998 + 51 +351.1901840561478 + 73 + 0 + 72 + 2 + 10 +2.232025923290446 + 20 +2.76206241576646 + 40 +1.1034765317954 + 50 +44.6177154324492 + 51 +96.63019658365178 + 73 + 0 + 97 + 1 +330 +4C7 + 92 + 16 + 93 + 6 + 72 + 2 + 10 +2.05576545700618 + 20 +2.861012413940887 + 40 +0.9548984716270655 + 50 +274.0763809413058 + 51 +308.9974179950865 + 73 + 1 + 72 + 2 + 10 +2.583746606177169 + 20 +2.208949913643178 + 40 +0.1158814287879965 + 50 +308.9974179950865 + 51 +381.0025820049136 + 73 + 1 + 72 + 2 + 10 +2.64643710148901 + 20 +2.233017781588249 + 40 +0.0487296568838581 + 50 +21.00258200491355 + 51 +88.99741799508618 + 73 + 1 + 72 + 2 + 10 +2.643315164634613 + 20 +2.054622849494738 + 40 +0.2271519040571613 + 50 +88.99741799508604 + 51 +114.6269796357359 + 73 + 1 + 72 + 2 + 10 +3.303260542295614 + 20 +0.6149685670603082 + 40 +1.810860322430921 + 50 +114.6269796357358 + 51 +129.7728051417874 + 73 + 1 + 72 + 2 + 10 +3.496410384846758 + 20 +1.664724034128341 + 40 +1.394246852682927 + 50 +165.7987430109054 + 51 +169.9291703474848 + 73 + 1 + 97 + 1 +330 +4C8 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +1.034012571047431 + 20 +0.4770274671951757 + 40 +0.7071698573021327 + 50 +88.2250617963899 + 51 +113.037640194644 + 73 + 1 + 72 + 2 + 10 +0.9476260308821789 + 20 +1.102477175547732 + 40 +0.1920311575011529 + 50 +187.577294301379 + 51 +259.5173177193701 + 73 + 0 + 72 + 2 + 10 +1.168606309785881 + 20 +1.558605525778299 + 40 +0.3700601913995948 + 50 +226.2464306309096 + 51 +229.2045371712558 + 73 + 1 + 72 + 2 + 10 +1.584035429735768 + 20 +2.03996185073825 + 40 +1.005894497867316 + 50 +229.2045371712552 + 51 +238.3301051192357 + 73 + 1 + 97 + 1 +330 +4E7 + 92 + 16 + 93 + 4 + 72 + 2 + 10 +1.365920530767478 + 20 +1.285919869338796 + 40 +0.3113711740675595 + 50 +169.2458500319289 + 51 +182.205842988757 + 73 + 0 + 72 + 2 + 10 +1.454717916970979 + 20 +2.022108206218515 + 40 +0.827297613601817 + 50 +241.09054843511 + 51 +254.5550649161042 + 73 + 1 + 72 + 2 + 10 +1.606711922375474 + 20 +1.348933253591385 + 40 +0.3924976718251174 + 50 +198.4545948543501 + 51 +215.6989500329358 + 73 + 1 + 72 + 2 + 10 +1.584035429735761 + 20 +2.039961850738243 + 40 +0.9665244191271488 + 50 +107.8377726397921 + 51 +122.8312626374707 + 73 + 0 + 97 + 1 +330 +4EB + 92 + 0 + 93 + 4 + 72 + 2 + 10 +1.454717916970981 + 20 +2.022108206218515 + 40 +0.8272976136018175 + 50 +223.615566083045 + 51 +238.0440774153107 + 73 + 1 + 72 + 2 + 10 +1.365920530767478 + 20 +1.285919869338796 + 40 +0.3507412528077177 + 50 +174.3939645983117 + 51 +184.6071947080589 + 73 + 1 + 72 + 2 + 10 +1.584035429735767 + 20 +2.039961850738251 + 40 +0.9665244191271588 + 50 +125.9717238731088 + 51 +130.7954628287447 + 73 + 0 + 72 + 2 + 10 +1.168606309785878 + 20 +1.558605525778289 + 40 +0.3306901126594289 + 50 +130.7954628287448 + 51 +161.0882096390424 + 73 + 0 + 97 + 1 +330 +4F0 + 92 + 0 + 93 + 4 + 72 + 2 + 10 +1.448830865211245 + 20 +2.213371853903018 + 40 +0.5803064835681306 + 50 +252.3365152710513 + 51 +268.8118268997819 + 73 + 1 + 72 + 2 + 10 +2.244252791706375 + 20 +1.579066020312691 + 40 +0.8092671391653076 + 50 +176.1651718242215 + 51 +179.7775214345853 + 73 + 1 + 72 + 2 + 10 +1.382209127764961 + 20 +2.180776385554781 + 40 +0.6008907212088166 + 50 +84.96060718028212 + 51 +99.52487731460255 + 73 + 0 + 72 + 2 + 10 +1.754426611671092 + 20 +1.690434343062297 + 40 +0.4826097226376628 + 50 +167.7663152513758 + 51 +176.4348368363554 + 73 + 0 + 97 + 1 +330 +620 + 92 + 16 + 93 + 6 + 72 + 2 + 10 +1.268369849054951 + 20 +1.97737114518936 + 40 +0.4071662414853972 + 50 +214.7414744545867 + 51 +240.7656835685936 + 73 + 1 + 72 + 2 + 10 +1.382209127764962 + 20 +2.180776385554782 + 40 +0.6402607999489762 + 50 +240.7656835685933 + 51 +274.8013992041994 + 73 + 1 + 72 + 2 + 10 +2.244252791706376 + 20 +1.579066020312693 + 40 +0.8092671391653085 + 50 +182.5711456908801 + 51 +205.0661840751609 + 73 + 1 + 72 + 2 + 10 +1.454717916970982 + 20 +2.022108206218515 + 40 +0.78792753486166 + 50 +85.88902674875129 + 51 +141.3773954764613 + 73 + 0 + 72 + 2 + 10 +1.168606309785876 + 20 +1.558605525778289 + 40 +0.3306901126594269 + 50 +175.0885918849935 + 51 +182.1149161181871 + 73 + 0 + 72 + 2 + 10 +1.060157361703603 + 20 +1.562610439508386 + 40 +0.2221672409957212 + 50 +182.1149161181872 + 51 +235.3333452342021 + 73 + 0 + 97 + 1 +330 +4EE + 92 + 16 + 93 + 11 + 72 + 2 + 10 +1.735391678484751 + 20 +1.622446814297793 + 40 +0.3637008069698632 + 50 +46.50828210019076 + 51 +127.3801843342055 + 73 + 0 + 72 + 2 + 10 +2.244252791706377 + 20 +1.579066020312692 + 40 +0.7698970604251519 + 50 +198.604632170139 + 51 +206.170680909061 + 73 + 1 + 72 + 2 + 10 +1.87217070432574 + 20 +1.396215376152875 + 40 +0.3553136094539483 + 50 +206.170680909061 + 51 +220.7958011940912 + 73 + 1 + 72 + 2 + 10 +1.754854449164134 + 20 +1.637701886096329 + 40 +0.4973281664865742 + 50 +252.2434918237404 + 51 +291.0055844420299 + 73 + 1 + 72 + 2 + 10 +1.940182455435743 + 20 +1.155046537921708 + 40 +0.0196850393700786 + 50 +248.9944155579697 + 51 +428.9944155579707 + 73 + 0 + 72 + 2 + 10 +1.754854449164133 + 20 +1.637701886096329 + 40 +0.5366982452267322 + 50 +68.99441555797011 + 51 +99.84027979757452 + 73 + 0 + 72 + 2 + 10 +1.872170704325739 + 20 +1.396215376152874 + 40 +0.3553136094539469 + 50 +233.9619057741986 + 51 +253.8293190909382 + 73 + 1 + 72 + 2 + 10 +1.867289566555308 + 20 +1.379382243234548 + 40 +0.3377870618823355 + 50 +253.8293190909384 + 51 +276.1706809090611 + 73 + 1 + 72 + 2 + 10 +1.842733556184505 + 20 +1.606506575382589 + 40 +0.5662349988373994 + 50 +276.170680909061 + 51 +300.6079669543535 + 73 + 1 + 72 + 2 + 10 +2.448387279831183 + 20 +1.47470612641788 + 40 +0.4765713362946238 + 50 +131.7514141291648 + 51 +162.7742566190203 + 73 + 0 + 72 + 2 + 10 +3.245154141911026 + 20 +1.721739021653879 + 40 +1.31075517924367 + 50 +162.7742566190193 + 51 +163.9156492780123 + 73 + 0 + 97 + 1 +330 +4F4 + 92 + 16 + 93 + 36 + 72 + 2 + 10 +2.043049297315998 + 20 +2.110655210550977 + 40 +0.3135948678531067 + 50 +140.7856547310828 + 51 +150.7972901196548 + 73 + 1 + 72 + 2 + 10 +4.316192387813921 + 20 +0.8400973818280717 + 40 +2.91772556849152 + 50 +150.7972901196538 + 51 +151.5606552199046 + 73 + 1 + 72 + 2 + 10 +1.82896029060598 + 20 +2.312110103765454 + 40 +0.1138088004365485 + 50 +226.4676036039469 + 51 +253.8346334294888 + 73 + 1 + 72 + 2 + 10 +1.791794192050712 + 20 +2.183894323205893 + 40 +0.0196850393700787 + 50 +286.1653665705111 + 51 +466.1653665705111 + 73 + 0 + 72 + 2 + 10 +1.82896029060598 + 20 +2.312110103765454 + 40 +0.153178879176706 + 50 +106.1653665705111 + 51 +129.487348884315 + 73 + 0 + 72 + 2 + 10 +4.31619238781396 + 20 +0.8400973818280881 + 40 +2.917725568491546 + 50 +152.3551430085055 + 51 +153.8293190909382 + 73 + 1 + 72 + 2 + 10 +-0.1012307034243785 + 20 +3.010931950741638 + 40 +2.004281084551068 + 50 +26.17068090906094 + 51 +27.44285015917365 + 73 + 0 + 72 + 2 + 10 +1.869973878918131 + 20 +2.229032723885394 + 40 +0.2390599525801008 + 50 +216.3816426472188 + 51 +279.0739534633693 + 73 + 1 + 72 + 2 + 10 +1.910780338072042 + 20 +1.973525769477851 + 40 +0.0196850393700789 + 50 +260.9260465366305 + 51 +440.9260465366307 + 73 + 0 + 72 + 2 + 10 +1.869973878918132 + 20 +2.229032723885395 + 40 +0.278430031320259 + 50 +80.92604653663092 + 51 +139.8013610445865 + 73 + 0 + 72 + 2 + 10 +-0.101230703424352 + 20 +3.01093195074165 + 40 +2.004281084551049 + 50 +28.67087156360686 + 51 +33.18792433993601 + 73 + 0 + 72 + 2 + 10 +1.813793246529746 + 20 +2.127914574971419 + 40 +0.3198926968250738 + 50 +222.0119914468626 + 51 +273.6941141002521 + 73 + 1 + 72 + 2 + 10 +1.835672170020508 + 20 +1.78904239903142 + 40 +0.0196850393700788 + 50 +266.3058858997472 + 51 +446.3058858997478 + 73 + 0 + 72 + 2 + 10 +1.813793246529746 + 20 +2.127914574971419 + 40 +0.3592627755652315 + 50 +86.30588589974785 + 51 +136.3371185375852 + 73 + 0 + 72 + 2 + 10 +1.995105659775399 + 20 +1.606003070595645 + 40 +0.5192979821599312 + 50 +148.1708625321174 + 51 +171.6429565217715 + 73 + 1 + 72 + 2 + 10 +1.774379750743404 + 20 +1.9596864265737 + 40 +0.4040824222682091 + 50 +223.5109336967462 + 51 +281.1199173397384 + 73 + 1 + 72 + 2 + 10 +1.85610884645455 + 20 +1.543874911031386 + 40 +0.0196850393700787 + 50 +258.8800826602615 + 51 +438.8800826602615 + 73 + 0 + 72 + 2 + 10 +1.774379750743404 + 20 +1.9596864265737 + 40 +0.4434525010083663 + 50 +78.88008266026162 + 51 +132.2628434475095 + 73 + 0 + 72 + 2 + 10 +2.244252791706375 + 20 +1.579066020312694 + 40 +0.7698970604251502 + 50 +176.0947114644605 + 51 +193.0143530481955 + 73 + 1 + 72 + 2 + 10 +1.735391678484751 + 20 +1.622446814297793 + 40 +0.3243307282297058 + 50 +221.9378076910892 + 51 +317.3250616801697 + 73 + 1 + 72 + 2 + 10 +3.245154141910992 + 20 +1.721739021653846 + 40 +1.310755179243628 + 50 +165.9082787983328 + 51 +187.2257433809798 + 73 + 0 + 72 + 2 + 10 +2.601728566753492 + 20 +1.803316300498068 + 40 +0.6621787973190414 + 50 +187.2257433809798 + 51 +200.265282453191 + 73 + 0 + 72 + 2 + 10 +1.486332025585369 + 20 +2.215145842661859 + 40 +0.5268178451693419 + 50 +339.734717546809 + 51 +365.875687911445 + 73 + 1 + 72 + 2 + 10 +1.780100104900293 + 20 +2.245377841414935 + 40 +0.231498258665186 + 50 +5.875687911445098 + 51 +34.12431208855465 + 73 + 1 + 72 + 2 + 10 +1.928818024879454 + 20 +2.346159501416084 + 40 +0.0518487033762426 + 50 +34.12431208855484 + 51 +115.8756879114452 + 73 + 1 + 72 + 2 + 10 +2.043049297315996 + 20 +2.110655210550977 + 40 +0.3135948678531048 + 50 +115.8756879114451 + 51 +131.7156800642676 + 73 + 1 + 72 + 2 + 10 +2.105362384851459 + 20 +2.371962053549119 + 40 +0.2723538322513749 + 50 +185.7363493931126 + 51 +196.6535421822968 + 73 + 1 + 72 + 2 + 10 +2.224366300494004 + 20 +2.407559786221583 + 40 +0.3965678834278744 + 50 +196.6535421822967 + 51 +214.2452636527788 + 73 + 1 + 72 + 2 + 10 +1.775114796299714 + 20 +2.101729675474409 + 40 +0.1469014999420266 + 50 +325.7547363472213 + 51 +394.2452636527789 + 73 + 0 + 72 + 2 + 10 +1.880276536811822 + 20 +2.030140317515856 + 40 +0.0196850393700786 + 50 +34.24526365277875 + 51 +214.2452636527787 + 73 + 0 + 72 + 2 + 10 +1.775114796299714 + 20 +2.101729675474409 + 40 +0.1075314212018693 + 50 +325.7547363472211 + 51 +383.6864830926802 + 73 + 1 + 72 + 2 + 10 +1.724258670730545 + 20 +2.179559731729328 + 40 +0.1532919477378671 + 50 +13.05681211459937 + 51 +58.88974415557702 + 73 + 0 + 72 + 2 + 10 +1.793291568736173 + 20 +2.065168888754275 + 40 +0.0196850393700787 + 50 +58.88974415557702 + 51 +238.8897441555765 + 73 + 0 + 72 + 2 + 10 +1.724258670730541 + 20 +2.179559731729329 + 40 +0.1139218689977123 + 50 +301.1102558444241 + 51 +381.2576330469557 + 73 + 1 + 72 + 2 + 10 +2.224366300494005 + 20 +2.407559786221586 + 40 +0.435937962168034 + 50 +154.6425959514791 + 51 +163.3464578177032 + 73 + 0 + 72 + 2 + 10 +2.105362384851463 + 20 +2.371962053549115 + 40 +0.3117239109915352 + 50 +163.3464578177044 + 51 +168.3316806257954 + 73 + 0 + 97 + 1 +330 +4F7 + 92 + 16 + 93 + 7 + 72 + 2 + 10 +1.995105659775398 + 20 +1.606003070595649 + 40 +0.5586680609000869 + 50 +153.1774302023765 + 51 +173.1639087815069 + 73 + 1 + 72 + 2 + 10 +1.448830865211247 + 20 +2.213371853903018 + 40 +0.5409364048279738 + 50 +90.89204265530425 + 51 +153.6751728635248 + 73 + 0 + 72 + 2 + 10 +1.163637847655053 + 20 +1.838026139816656 + 40 +0.2412638458944706 + 50 +214.15747754694 + 51 +242.0052969205898 + 73 + 0 + 72 + 2 + 10 +1.134374454956795 + 20 +1.893074853652674 + 40 +0.1789203855540918 + 50 +242.0052969205894 + 51 +284.046994134434 + 73 + 0 + 72 + 2 + 10 +1.318324160529892 + 20 +2.123002906229338 + 40 +0.1514028023784195 + 50 +201.853727881165 + 51 +212.2168526331622 + 73 + 1 + 72 + 2 + 10 +1.492137893232153 + 20 +2.232530667257897 + 40 +0.3568475494804613 + 50 +212.2168526331617 + 51 +237.7831473668378 + 73 + 1 + 72 + 2 + 10 +1.573128668857933 + 20 +2.361057982102735 + 40 +0.5087645544459671 + 50 +237.7831473668379 + 51 +261.3425166986952 + 73 + 1 + 97 + 1 +330 +505 + 92 + 16 + 93 + 5 + 72 + 2 + 10 +1.75442661167109 + 20 +1.690434343062299 + 40 +0.5219798013778194 + 50 +181.7138221824677 + 51 +190.3415069086127 + 73 + 1 + 72 + 2 + 10 +1.382209127764958 + 20 +2.180776385554784 + 40 +0.6008907212088186 + 50 +103.5988396513469 + 51 +119.2343164314062 + 73 + 0 + 72 + 2 + 10 +1.26836984905495 + 20 +1.977371145189357 + 40 +0.3677961627452375 + 50 +119.2343164314065 + 51 +126.2926725539458 + 73 + 0 + 72 + 2 + 10 +1.365613936631298 + 20 +1.696475315724717 + 40 +0.3153299658786926 + 50 +177.17352188641 + 51 +195.5421431149888 + 73 + 0 + 72 + 2 + 10 +1.448830865211245 + 20 +2.213371853903018 + 40 +0.5803064835681301 + 50 +228.1704174204192 + 51 +248.1315658423051 + 73 + 1 + 97 + 1 +330 +507 + 92 + 16 + 93 + 5 + 72 + 2 + 10 +1.365613936631296 + 20 +1.696475315724716 + 40 +0.3547000446188475 + 50 +161.0626247765776 + 51 +177.1237827075663 + 73 + 1 + 72 + 2 + 10 +1.26836984905495 + 20 +1.977371145189359 + 40 +0.3677961627452389 + 50 +134.3293201388803 + 51 +152.0052969205894 + 73 + 0 + 72 + 2 + 10 +1.065938622495786 + 20 +1.869760556959495 + 40 +0.1385398865270621 + 50 +152.0052969205897 + 51 +197.9947030794107 + 73 + 0 + 72 + 2 + 10 +1.163637847655055 + 20 +1.838026139816656 + 40 +0.2412638458944715 + 50 +197.9947030794104 + 51 +202.8905358909278 + 73 + 0 + 72 + 2 + 10 +1.448830865211249 + 20 +2.213371853903019 + 40 +0.5803064835681331 + 50 +209.0183706588869 + 51 +223.8176444671686 + 73 + 1 + 97 + 1 +330 +509 + 92 + 16 + 93 + 6 + 72 + 2 + 10 +1.573128668857933 + 20 +2.361057982102735 + 40 +0.4693944757058101 + 50 +96.86618894004766 + 51 +122.2168526331621 + 73 + 0 + 72 + 2 + 10 +1.492137893232154 + 20 +2.232530667257898 + 40 +0.3174774707403054 + 50 +122.2168526331621 + 51 +147.7831473668382 + 73 + 0 + 72 + 2 + 10 +1.318324160529893 + 20 +2.123002906229338 + 40 +0.1120327236382623 + 50 +147.783147366838 + 51 +287.1653967341294 + 73 + 0 + 72 + 2 + 10 +1.134452552508394 + 20 +1.527737292608446 + 40 +0.7350495123332927 + 50 +287.1653967341295 + 51 +311.9725813008354 + 73 + 0 + 72 + 2 + 10 +-0.1012307034243558 + 20 +3.010931950741639 + 40 +1.964911005810889 + 50 +28.47135626072658 + 51 +33.82931909093841 + 73 + 0 + 72 + 2 + 10 +1.9951056597754 + 20 +1.606003070595648 + 40 +0.5586680609000885 + 50 +146.1706809090616 + 51 +148.8453401595469 + 73 + 1 + 97 + 1 +330 +50B + 92 + 16 + 93 + 4 + 72 + 2 + 10 +2.434808481477273 + 20 +1.741760238465535 + 40 +0.4213944983540373 + 50 +350.138398092684 + 51 +368.2079411900966 + 73 + 1 + 72 + 2 + 10 +2.232025923290449 + 20 +2.76206241576646 + 40 +1.142846610535555 + 50 +302.8460023643591 + 51 +313.5174616433824 + 73 + 1 + 72 + 2 + 10 +2.435514026542539 + 20 +1.986930556286178 + 40 +0.5859069085937808 + 50 +5.250840664227033 + 51 +24.12657987446927 + 73 + 0 + 72 + 2 + 10 +2.358343856922903 + 20 +2.560871504972432 + 40 +1.017884167165218 + 50 +53.04812421612736 + 51 +61.11882105703474 + 73 + 0 + 97 + 1 +330 +510 + 92 + 16 + 93 + 5 + 72 + 2 + 10 +1.606711922375474 + 20 +1.348933253591385 + 40 +0.3531275930849602 + 50 +135.3746912145926 + 51 +157.4176362906217 + 73 + 0 + 72 + 2 + 10 +1.454717916970981 + 20 +2.022108206218514 + 40 +0.827297613601817 + 50 +257.8545362072944 + 51 +275.2691677284761 + 73 + 1 + 72 + 2 + 10 +1.872170704325741 + 20 +1.396215376152876 + 40 +0.3946836881941063 + 50 +210.0950891144055 + 51 +232.5295145799341 + 73 + 1 + 72 + 2 + 10 +1.542373482613905 + 20 +1.835739673019258 + 40 +0.75809597646572 + 50 +83.20542127045559 + 51 +101.5302981560868 + 73 + 0 + 72 + 2 + 10 +1.584035429735767 + 20 +2.039961850738253 + 40 +0.9665244191271609 + 50 +101.5302981560871 + 51 +103.684145503982 + 73 + 0 + 97 + 1 +330 +559 + 92 + 16 + 93 + 17 + 72 + 2 + 10 +2.10536238485146 + 20 +2.371962053549118 + 40 +0.2723538322513761 + 50 +159.7337422418206 + 51 +175.1380365575864 + 73 + 1 + 72 + 2 + 10 +2.043049297315996 + 20 +2.110655210550977 + 40 +0.352964946593263 + 50 +233.6796832772765 + 51 +244.1243120885548 + 73 + 0 + 72 + 2 + 10 +1.928818024879453 + 20 +2.346159501416084 + 40 +0.0912187821164004 + 50 +244.1243120885551 + 51 +325.8756879114455 + 73 + 0 + 72 + 2 + 10 +1.780100104900293 + 20 +2.245377841414934 + 40 +0.2708683374053446 + 50 +325.8756879114452 + 51 +354.1243120885547 + 73 + 0 + 72 + 2 + 10 +1.486332025585371 + 20 +2.215145842661859 + 40 +0.5661879239094977 + 50 +354.124312088555 + 51 +380.265282453191 + 73 + 0 + 72 + 2 + 10 +2.601728566753494 + 20 +1.803316300498069 + 40 +0.622808718578886 + 50 +159.7347175468091 + 51 +172.7742566190203 + 73 + 1 + 72 + 2 + 10 +3.245154141910993 + 20 +1.721739021653846 + 40 +1.271385100503472 + 50 +172.7742566190202 + 51 +197.2257433809798 + 73 + 1 + 72 + 2 + 10 +2.448387279831183 + 20 +1.474706126417881 + 40 +0.4372012575544668 + 50 +197.2257433809797 + 51 +229.6909739682446 + 73 + 1 + 72 + 2 + 10 +1.84273355618451 + 20 +1.606506575382588 + 40 +0.5662349988373949 + 50 +304.7588400511317 + 51 +309.2074896477569 + 73 + 1 + 72 + 2 + 10 +3.174161319020478 + 20 +1.699913413586492 + 40 +1.109452231228011 + 50 +151.3367493281762 + 51 +186.2319675330486 + 73 + 0 + 72 + 2 + 10 +3.49641038484678 + 20 +1.664724034128332 + 40 +1.433616931423104 + 50 +186.2319675330492 + 51 +205.0988169699291 + 73 + 0 + 72 + 2 + 10 +-37.1850685335689 + 20 +20.72029698200291 + 40 +43.48962412887072 + 50 +334.901183030072 + 51 +335.0988169699286 + 73 + 1 + 72 + 2 + 10 +1.05207209728287 + 20 +2.970247608757844 + 40 +1.33344811187206 + 50 +335.0988169699285 + 51 +348.9886439523909 + 73 + 1 + 72 + 2 + 10 +1.959203223948364 + 20 +2.950701101027533 + 40 +0.4655223034750759 + 50 +30.33963089325502 + 51 +49.03787718203768 + 73 + 0 + 72 + 2 + 10 +1.804450685812644 + 20 +3.128961400613438 + 40 +0.701583910831935 + 50 +49.03787718203728 + 51 +65.26030603284518 + 73 + 0 + 72 + 2 + 10 +1.924151714798596 + 20 +2.869186907390315 + 40 +0.4155574720721139 + 50 +65.26030603284511 + 51 +82.84890216530907 + 73 + 0 + 72 + 2 + 10 +1.936208898089171 + 20 +2.773084900679216 + 40 +0.318702057340656 + 50 +82.84890216530943 + 51 +105.7184590811235 + 73 + 0 + 97 + 1 +330 +4F3 + 92 + 16 + 93 + 17 + 72 + 2 + 10 +1.885608931176688 + 20 +3.176688874055116 + 40 +0.2129975912966591 + 50 +114.9006616575818 + 51 +156.4878117659684 + 73 + 1 + 72 + 2 + 10 +2.636203773812854 + 20 +2.850131072655588 + 40 +1.031552791296577 + 50 +156.4878117659688 + 51 +180.6082887577103 + 73 + 1 + 72 + 2 + 10 +1.952094170360633 + 20 +2.842867853274917 + 40 +0.3474046319836055 + 50 +180.6082887577101 + 51 +213.6393369978933 + 73 + 1 + 72 + 2 + 10 +1.964644164547905 + 20 +2.851218474936612 + 40 +0.3624789557242355 + 50 +213.6393369978933 + 51 +250.0019612921961 + 73 + 1 + 72 + 2 + 10 +1.936208898089171 + 20 +2.773084900679217 + 40 +0.2793319786004991 + 50 +250.001961292196 + 51 +277.1510978346906 + 73 + 1 + 72 + 2 + 10 +1.924151714798597 + 20 +2.869186907390317 + 40 +0.3761873933319576 + 50 +277.1510978346908 + 51 +294.7396939671547 + 73 + 1 + 72 + 2 + 10 +1.804450685812644 + 20 +3.128961400613437 + 40 +0.6622138320917775 + 50 +294.7396939671549 + 51 +310.9621228179628 + 73 + 1 + 72 + 2 + 10 +1.959203223948364 + 20 +2.950701101027533 + 40 +0.4261522247349184 + 50 +310.9621228179625 + 51 +357.7626023297964 + 73 + 1 + 72 + 2 + 10 +0.9685713550985386 + 20 +2.989404907072427 + 40 +1.417539880590719 + 50 +357.7626023297966 + 51 +367.3820705420636 + 73 + 1 + 72 + 2 + 10 +2.2125235694189 + 20 +3.150570273791624 + 40 +0.1631908912969642 + 50 +7.382070542063584 + 51 +53.5251061991567 + 73 + 1 + 72 + 2 + 10 +1.924407631021267 + 20 +3.452788946261674 + 40 +0.4213817967382122 + 50 +23.94086726929591 + 51 +38.56090658709021 + 73 + 0 + 72 + 2 + 10 +2.174464534980624 + 20 +3.253450334179865 + 40 +0.1015938396722196 + 50 +38.56090658709 + 51 +128.8844964337146 + 73 + 0 + 72 + 1 + 10 +2.110688753100606 + 20 +3.174368364648643 + 11 +2.049360338450518 + 21 +3.223826763560005 + 72 + 1 + 10 +2.049360338450518 + 20 +3.223826763560005 + 11 +2.020698206844207 + 21 +3.208114453397319 + 72 + 2 + 10 +1.961644849992286 + 20 +3.289054064709398 + 40 +0.1001924130602254 + 50 +53.88559445512062 + 51 +115.5479523260344 + 73 + 0 + 72 + 2 + 10 +2.0110372932182 + 20 +3.39238482801838 + 40 +0.2147212744613677 + 50 +115.5479523260344 + 51 +163.3991489022965 + 73 + 0 + 72 + 2 + 10 +2.161160122792123 + 20 +3.437140815427867 + 40 +0.371373635976537 + 50 +163.3991489022961 + 51 +169.5663152899231 + 73 + 0 + 97 + 1 +330 +4C9 + 92 + 16 + 93 + 13 + 72 + 1 + 10 +2.053553115266256 + 20 +3.271022854778554 + 11 +2.135403416533275 + 21 +3.205014547305152 + 72 + 2 + 10 +2.174464534980624 + 20 +3.253450334179865 + 40 +0.0622237609320623 + 50 +231.1155035662852 + 51 +321.4390934129098 + 73 + 1 + 72 + 2 + 10 +1.924407631021268 + 20 +3.452788946261673 + 40 +0.3820117179980535 + 50 +321.4390934129098 + 51 +381.7909975373624 + 73 + 1 + 72 + 2 + 10 +2.205371433700895 + 20 +3.565115244906947 + 40 +0.0794264312051501 + 50 +21.79099753736259 + 51 +138.4608414339663 + 73 + 1 + 72 + 2 + 10 +2.359201923855247 + 20 +3.432035664951207 + 40 +0.2828284405938025 + 50 +138.9469336075647 + 51 +155.609089205736 + 73 + 1 + 72 + 2 + 10 +2.083688019187524 + 20 +3.556961618598168 + 40 +0.0196850393700788 + 50 +24.39091079426373 + 51 +197.0763607466141 + 73 + 0 + 72 + 1 + 10 +2.064870809553132 + 20 +3.562742050811843 + 11 +2.082872800905891 + 21 +3.621344458486482 + 72 + 2 + 10 +1.984695044370157 + 20 +3.635415634546031 + 40 +0.099180995528825 + 50 +351.8437155425206 + 51 +398.1173531107838 + 73 + 1 + 72 + 2 + 10 +2.010334078755422 + 20 +3.655531747894149 + 40 +0.066592376342933 + 50 +38.11735311078365 + 51 +124.6298938385513 + 73 + 1 + 72 + 2 + 10 +2.161160122792124 + 20 +3.437140815427865 + 40 +0.3320035572363805 + 50 +124.6298938385515 + 51 +196.6008510977037 + 73 + 1 + 72 + 2 + 10 +2.011037293218199 + 20 +3.39238482801838 + 40 +0.1753511957212102 + 50 +196.6008510977036 + 51 +244.4520476739657 + 73 + 1 + 72 + 2 + 10 +1.961644849992285 + 20 +3.289054064709398 + 40 +0.0608223343200681 + 50 +244.4520476739658 + 51 +308.2116001220994 + 73 + 1 + 72 + 1 + 10 +1.999267568517967 + 20 +3.241264030153233 + 11 +2.053553115266256 + 21 +3.271022854778554 + 97 + 1 +330 +4CB + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +C40 +330 +1F +100 +AcDbEntity + 8 +HATCH-WHITE +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 3 + 92 + 1 + 93 + 13 + 72 + 1 + 10 +2.053553115266256 + 20 +3.271022854778554 + 11 +2.135403416533275 + 21 +3.205014547305152 + 72 + 2 + 10 +2.174464534980624 + 20 +3.253450334179865 + 40 +0.0622237609320623 + 50 +231.1155035662852 + 51 +321.4390934129098 + 73 + 1 + 72 + 2 + 10 +1.924407631021268 + 20 +3.452788946261673 + 40 +0.3820117179980535 + 50 +321.4390934129098 + 51 +381.7909975373624 + 73 + 1 + 72 + 2 + 10 +2.205371433700895 + 20 +3.565115244906947 + 40 +0.0794264312051501 + 50 +21.79099753736259 + 51 +138.4608414339663 + 73 + 1 + 72 + 2 + 10 +2.359201923855247 + 20 +3.432035664951207 + 40 +0.2828284405938025 + 50 +138.9469336075647 + 51 +155.609089205736 + 73 + 1 + 72 + 2 + 10 +2.083688019187524 + 20 +3.556961618598168 + 40 +0.0196850393700788 + 50 +24.39091079426373 + 51 +197.0763607466141 + 73 + 0 + 72 + 1 + 10 +2.064870809553132 + 20 +3.562742050811843 + 11 +2.082872800905891 + 21 +3.621344458486482 + 72 + 2 + 10 +1.984695044370157 + 20 +3.635415634546031 + 40 +0.099180995528825 + 50 +351.8437155425206 + 51 +398.1173531107838 + 73 + 1 + 72 + 2 + 10 +2.010334078755422 + 20 +3.655531747894149 + 40 +0.066592376342933 + 50 +38.11735311078365 + 51 +124.6298938385513 + 73 + 1 + 72 + 2 + 10 +2.161160122792124 + 20 +3.437140815427865 + 40 +0.3320035572363805 + 50 +124.6298938385515 + 51 +196.6008510977037 + 73 + 1 + 72 + 2 + 10 +2.011037293218199 + 20 +3.39238482801838 + 40 +0.1753511957212102 + 50 +196.6008510977036 + 51 +244.4520476739657 + 73 + 1 + 72 + 2 + 10 +1.961644849992285 + 20 +3.289054064709398 + 40 +0.0608223343200681 + 50 +244.4520476739658 + 51 +308.2116001220994 + 73 + 1 + 72 + 1 + 10 +1.999267568517967 + 20 +3.241264030153233 + 11 +2.053553115266256 + 21 +3.271022854778554 + 97 + 1 +330 +4CB + 92 + 16 + 93 + 8 + 72 + 2 + 10 +2.10076671703864 + 20 +3.325655213407455 + 40 +0.0599397668605327 + 50 +267.8793336511986 + 51 +377.8793336511989 + 73 + 1 + 72 + 2 + 10 +2.052741812238583 + 20 +3.310162719091439 + 40 +0.1104017214519507 + 50 +17.87933365119892 + 51 +43.7673166448306 + 73 + 1 + 72 + 2 + 10 +2.103395451769339 + 20 +3.340116557206334 + 40 +0.0547683672910658 + 50 +57.93744139888317 + 51 +187.77563216475 + 73 + 1 + 72 + 2 + 10 +2.068634698539837 + 20 +3.335369986556996 + 40 +0.0196850393700788 + 50 +187.7756321647501 + 51 +367.7756321647502 + 73 + 1 + 72 + 2 + 10 +2.103395451769339 + 20 +3.340116557206334 + 40 +0.0153982885509082 + 50 +172.2243678352504 + 51 +287.334302618237 + 73 + 0 + 72 + 2 + 10 +2.052741812238584 + 20 +3.310162719091439 + 40 +0.0710316427117921 + 50 +321.0507208994834 + 51 +342.1206663488011 + 73 + 0 + 72 + 2 + 10 +2.100766717038639 + 20 +3.325655213407456 + 40 +0.0205696881203755 + 50 +342.1206663488009 + 51 +452.1206663488013 + 73 + 0 + 72 + 2 + 10 +2.099277124665835 + 20 +3.285428055915363 + 40 +0.0196850393700787 + 50 +87.8793336512005 + 51 +267.8793336511979 + 73 + 1 + 97 + 1 +330 +235 + 92 + 16 + 93 + 8 + 72 + 2 + 10 +1.921485017130019 + 20 +3.343003198213819 + 40 +0.0771903814552135 + 50 +359.5978819190761 + 51 +374.2374903606301 + 73 + 1 + 72 + 2 + 10 +1.980044176928186 + 20 +3.357861720825169 + 40 +0.0167755580220592 + 50 +14.23749036062933 + 51 +155.7625096393687 + 73 + 1 + 72 + 2 + 10 +2.003282808101446 + 20 +3.34739958355454 + 40 +0.0422606574936387 + 50 +155.7625096393692 + 51 +241.4329313324614 + 73 + 1 + 72 + 2 + 10 +1.973661171909946 + 20 +3.292995281984995 + 40 +0.0196850393700789 + 50 +298.5670686675385 + 51 +478.5670686675385 + 73 + 0 + 72 + 2 + 10 +2.003282808101446 + 20 +3.34739958355454 + 40 +0.0816307362337962 + 50 +118.5670686675387 + 51 +204.2374903606309 + 73 + 0 + 72 + 2 + 10 +1.980044176928186 + 20 +3.357861720825169 + 40 +0.0561456367622165 + 50 +204.2374903606306 + 51 +345.7625096393699 + 73 + 0 + 72 + 2 + 10 +1.921485017130019 + 20 +3.34300319821382 + 40 +0.1165604601953712 + 50 +345.76250963937 + 51 +360.4021180809241 + 73 + 0 + 72 + 2 + 10 +2.018358052101874 + 20 +3.342323304531541 + 40 +0.0196850393700787 + 50 +0.4021180809244088 + 51 +180.4021180809231 + 73 + 0 + 97 + 1 +330 +267 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +LWPOLYLINE + 5 +CB7 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 2 + 70 + 0 + 43 +0.0 + 10 +1.999999999999999 + 20 +0.5021900451212454 + 10 +1.999999999999998 + 20 +0.2137188753069325 + 0 +LWPOLYLINE + 5 +129E +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.699999999999999 + 20 +0.4263456413348424 + 10 +1.590116389297469 + 20 +0.3629043091162095 + 10 +1.590116389297469 + 20 +0.2153520942475884 + 0 +LWPOLYLINE + 5 +12B7 +102 +{ACAD_REACTORS +330 +1B2B +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 68 + 70 + 1 + 43 +0.0 + 10 +0.211518030839291 + 20 +1.132195865069596 + 10 +0.2115180308392921 + 20 +0.8856214579511849 + 10 +0.3800563547419098 + 20 +0.8242785247175163 + 10 +0.4819904717841743 + 20 +0.8831302146314739 + 42 +-0.9999999999999999 + 10 +0.501675511154253 + 20 +0.8490347262935038 + 10 +0.4283509058011884 + 20 +0.8067007456546893 + 10 +0.4606008219772955 + 20 +0.7949627361090064 + 10 +0.56253493901956 + 20 +0.8538144260229641 + 42 +-0.9999999999999999 + 10 +0.5822199783896387 + 20 +0.8197189376849939 + 10 +0.5088953730365742 + 20 +0.7773849570461795 + 10 +0.5411452892126811 + 20 +0.7656469475004968 + 10 +0.6430794062549456 + 20 +0.8244986374144544 + 42 +-0.9999999999999999 + 10 +0.6627644456250243 + 20 +0.7904031490764842 + 10 +0.5894398402719598 + 20 +0.7480691684376697 + 10 +0.6216897564480669 + 20 +0.736331158891987 + 10 +0.7236238734903314 + 20 +0.7951828488059446 + 42 +-0.9999999999999999 + 10 +0.7433089128604101 + 20 +0.7610873604679744 + 10 +0.6699843075073457 + 20 +0.7187533798291599 + 10 +0.7022342236834526 + 20 +0.7070153702834772 + 10 +0.8041683407257171 + 20 +0.7658670601974349 + 42 +-0.9999999999999999 + 10 +0.8238533800957958 + 20 +0.7317715718594647 + 10 +0.7505287747427313 + 20 +0.6894375912206502 + 10 +0.7827786909188382 + 20 +0.6776995816749674 + 10 +0.8847128079611027 + 20 +0.7365512715889251 + 42 +-0.9999999999999999 + 10 +0.9043978473311814 + 20 +0.7024557832509549 + 10 +0.8310732419781172 + 20 +0.6601218026121404 + 10 +0.8633231581542239 + 20 +0.6483837930664577 + 10 +0.9652572751964884 + 20 +0.7072354829804153 + 42 +-0.9999999999999999 + 10 +0.9849423145665671 + 20 +0.6731399946424452 + 10 +0.9116177092135024 + 20 +0.6308060140036307 + 10 +0.9438676253896097 + 20 +0.619068004457948 + 10 +1.045801742431874 + 20 +0.6779196943719056 + 42 +-0.9999999999999999 + 10 +1.065486781801953 + 20 +0.6438242060339354 + 10 +0.992162176448888 + 20 +0.6014902253951211 + 10 +1.024412092624995 + 20 +0.5897522158494382 + 10 +1.12634620966726 + 20 +0.6486039057633959 + 42 +-0.9999999999999999 + 10 +1.146031249037339 + 20 +0.6145084174254256 + 10 +1.072706643684274 + 20 +0.5721744367866111 + 10 +1.104956559860381 + 20 +0.5604364272409283 + 10 +1.206890676902646 + 20 +0.6192881171548861 + 42 +-0.9999999999999999 + 10 +1.226575716272724 + 20 +0.5851926288169159 + 10 +1.15325111091966 + 20 +0.5428586481781015 + 10 +1.185501027095767 + 20 +0.5311206386324185 + 10 +1.287435144138031 + 20 +0.5899723285463763 + 42 +-0.9999999999999999 + 10 +1.30712018350811 + 20 +0.5558768402084061 + 10 +1.233795578155045 + 20 +0.5135428595695918 + 10 +1.266045494331153 + 20 +0.5018048500239088 + 10 +1.367979611373417 + 20 +0.5606565399378665 + 42 +-0.9999999999999999 + 10 +1.387664650743496 + 20 +0.5265610515998964 + 10 +1.314340045390431 + 20 +0.4842270709610819 + 10 +1.346589961566538 + 20 +0.4724890614153991 + 10 +1.448524078608803 + 20 +0.5313407513293568 + 42 +-0.9999999999999999 + 10 +1.468209117978881 + 20 +0.4972452629913866 + 10 +1.394884512625817 + 20 +0.4549112823525721 + 10 +1.427134428801924 + 20 +0.4431732728068893 + 10 +1.529068545844188 + 20 +0.5020249627208471 + 42 +-0.9999999999999999 + 10 +1.548753585214267 + 20 +0.4679294743828769 + 10 +1.475428979861203 + 20 +0.4255954937440624 + 10 +1.50767889603731 + 20 +0.4138574841983796 + 10 +1.609613013079574 + 20 +0.4727091741123373 + 42 +-0.9999999999999999 + 10 +1.629298052449653 + 20 +0.4386136857743671 + 10 +1.555973447096588 + 20 +0.3962797051355528 + 10 +1.588223363272695 + 20 +0.3845416955898698 + 10 +1.69015748031496 + 20 +0.4433933855038275 + 42 +-0.9999999999999999 + 10 +1.709842519685038 + 20 +0.4092978971658573 + 10 +1.636517914331974 + 20 +0.366963916527043 + 10 +1.980314960629922 + 20 +0.2418320250459505 + 10 +1.980314960629921 + 20 +0.4884064321643613 + 0 +LWPOLYLINE + 5 +12FB +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.4918329914692137 + 20 +0.8660824704624889 + 10 +0.3819493807666841 + 20 +0.802641138243856 + 10 +0.3819493807666836 + 20 +0.6550889233752348 + 0 +LWPOLYLINE + 5 +133B +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.619455532764613 + 20 +0.4556614299433522 + 10 +1.509571922062084 + 20 +0.3922200977247193 + 10 +1.509571922062083 + 20 +0.2446678828560982 + 0 +LWPOLYLINE + 5 +136A +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.538911065529228 + 20 +0.4849772185518619 + 10 +1.429027454826698 + 20 +0.421535886333229 + 10 +1.429027454826698 + 20 +0.2739836714646079 + 0 +LWPOLYLINE + 5 +1399 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.458366598293842 + 20 +0.5142930071603717 + 10 +1.348482987591312 + 20 +0.4508516749417388 + 10 +1.348482987591312 + 20 +0.3032994600731177 + 0 +LWPOLYLINE + 5 +13C8 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.377822131058456 + 20 +0.5436087957688814 + 10 +1.267938520355927 + 20 +0.4801674635502485 + 10 +1.267938520355926 + 20 +0.3326152486816275 + 0 +LWPOLYLINE + 5 +13F7 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.297277663823071 + 20 +0.5729245843773911 + 10 +1.187394053120541 + 20 +0.5094832521587582 + 10 +1.18739405312054 + 20 +0.3619310372901372 + 0 +LWPOLYLINE + 5 +1426 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.216733196587685 + 20 +0.6022403729859009 + 10 +1.106849585885155 + 20 +0.538799040767268 + 10 +1.106849585885155 + 20 +0.391246825898647 + 0 +LWPOLYLINE + 5 +1455 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.136188729352299 + 20 +0.6315561615944107 + 10 +1.02630511864977 + 20 +0.5681148293757778 + 10 +1.026305118649769 + 20 +0.4205626145071568 + 0 +LWPOLYLINE + 5 +1484 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +1.055644262116914 + 20 +0.6608719502029206 + 10 +0.9457606514143839 + 20 +0.5974306179842876 + 10 +0.9457606514143835 + 20 +0.4498784031156665 + 0 +LWPOLYLINE + 5 +14B3 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.9750997948815278 + 20 +0.6901877388114303 + 10 +0.8652161841789981 + 20 +0.6267464065927973 + 10 +0.8652161841789977 + 20 +0.4791941917241763 + 0 +LWPOLYLINE + 5 +14E2 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.8945553276461421 + 20 +0.71950352741994 + 10 +0.7846717169436125 + 20 +0.656062195201307 + 10 +0.784671716943612 + 20 +0.508509980332686 + 0 +LWPOLYLINE + 5 +1511 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.8140108604107564 + 20 +0.7488193160284498 + 10 +0.7041272497082268 + 20 +0.6853779838098168 + 10 +0.7041272497082264 + 20 +0.5378257689411958 + 0 +LWPOLYLINE + 5 +1540 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.7334663931753708 + 20 +0.7781351046369596 + 10 +0.6235827824728412 + 20 +0.7146937724183267 + 10 +0.6235827824728407 + 20 +0.5671415575497055 + 0 +LWPOLYLINE + 5 +156F +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.652921925939985 + 20 +0.8074508932454694 + 10 +0.5430383152374554 + 20 +0.7440095610268365 + 10 +0.5430383152374549 + 20 +0.5964573461582153 + 0 +LWPOLYLINE + 5 +159E +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +0.5723774587045993 + 20 +0.836766681853979 + 10 +0.4624938480020697 + 20 +0.773325349635346 + 10 +0.4624938480020693 + 20 +0.625773134766725 + 0 +LWPOLYLINE + 5 +19B1 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.300000000000002 + 20 +0.4263456413348424 + 10 +2.409883610702532 + 20 +0.3629043091162095 + 10 +2.409883610702533 + 20 +0.2153520942475884 + 0 +LWPOLYLINE + 5 +19B2 +102 +{ACAD_REACTORS +330 +1B2B +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 68 + 70 + 1 + 43 +0.0 + 10 +3.788481969160711 + 20 +1.132195865069596 + 10 +3.78848196916071 + 20 +0.8856214579511849 + 10 +3.619943645258092 + 20 +0.8242785247175163 + 10 +3.518009528215828 + 20 +0.8831302146314739 + 42 +0.9999999999999999 + 10 +3.498324488845749 + 20 +0.8490347262935038 + 10 +3.571649094198813 + 20 +0.8067007456546893 + 10 +3.539399178022706 + 20 +0.7949627361090064 + 10 +3.437465060980442 + 20 +0.8538144260229641 + 42 +0.9999999999999999 + 10 +3.417780021610363 + 20 +0.8197189376849939 + 10 +3.491104626963428 + 20 +0.7773849570461795 + 10 +3.458854710787321 + 20 +0.7656469475004968 + 10 +3.356920593745056 + 20 +0.8244986374144544 + 42 +0.9999999999999999 + 10 +3.337235554374978 + 20 +0.7904031490764842 + 10 +3.410560159728042 + 20 +0.7480691684376697 + 10 +3.378310243551935 + 20 +0.736331158891987 + 10 +3.27637612650967 + 20 +0.7951828488059446 + 42 +0.9999999999999999 + 10 +3.256691087139592 + 20 +0.7610873604679744 + 10 +3.330015692492656 + 20 +0.7187533798291599 + 10 +3.297765776316549 + 20 +0.7070153702834772 + 10 +3.195831659274285 + 20 +0.7658670601974349 + 42 +0.9999999999999999 + 10 +3.176146619904206 + 20 +0.7317715718594647 + 10 +3.24947122525727 + 20 +0.6894375912206502 + 10 +3.217221309081164 + 20 +0.6776995816749674 + 10 +3.115287192038899 + 20 +0.7365512715889251 + 42 +0.9999999999999999 + 10 +3.09560215266882 + 20 +0.7024557832509549 + 10 +3.168926758021885 + 20 +0.6601218026121404 + 10 +3.136676841845778 + 20 +0.6483837930664577 + 10 +3.034742724803513 + 20 +0.7072354829804153 + 42 +0.9999999999999999 + 10 +3.015057685433435 + 20 +0.6731399946424452 + 10 +3.0883822907865 + 20 +0.6308060140036307 + 10 +3.056132374610392 + 20 +0.619068004457948 + 10 +2.954198257568128 + 20 +0.6779196943719056 + 42 +0.9999999999999999 + 10 +2.934513218198049 + 20 +0.6438242060339354 + 10 +3.007837823551114 + 20 +0.6014902253951211 + 10 +2.975587907375006 + 20 +0.5897522158494382 + 10 +2.873653790332742 + 20 +0.6486039057633959 + 42 +0.9999999999999999 + 10 +2.853968750962663 + 20 +0.6145084174254256 + 10 +2.927293356315728 + 20 +0.5721744367866111 + 10 +2.895043440139621 + 20 +0.5604364272409283 + 10 +2.793109323097356 + 20 +0.6192881171548861 + 42 +0.9999999999999999 + 10 +2.773424283727278 + 20 +0.5851926288169159 + 10 +2.846748889080342 + 20 +0.5428586481781015 + 10 +2.814498972904235 + 20 +0.5311206386324185 + 10 +2.712564855861971 + 20 +0.5899723285463763 + 42 +0.9999999999999999 + 10 +2.692879816491892 + 20 +0.5558768402084061 + 10 +2.766204421844956 + 20 +0.5135428595695918 + 10 +2.733954505668849 + 20 +0.5018048500239088 + 10 +2.632020388626585 + 20 +0.5606565399378665 + 42 +0.9999999999999999 + 10 +2.612335349256506 + 20 +0.5265610515998964 + 10 +2.68565995460957 + 20 +0.4842270709610819 + 10 +2.653410038433464 + 20 +0.4724890614153991 + 10 +2.551475921391199 + 20 +0.5313407513293568 + 42 +0.9999999999999999 + 10 +2.53179088202112 + 20 +0.4972452629913866 + 10 +2.605115487374185 + 20 +0.4549112823525721 + 10 +2.572865571198078 + 20 +0.4431732728068893 + 10 +2.470931454155814 + 20 +0.5020249627208471 + 42 +0.9999999999999999 + 10 +2.451246414785735 + 20 +0.4679294743828769 + 10 +2.524571020138799 + 20 +0.4255954937440624 + 10 +2.492321103962692 + 20 +0.4138574841983796 + 10 +2.390386986920428 + 20 +0.4727091741123373 + 42 +0.9999999999999999 + 10 +2.370701947550349 + 20 +0.4386136857743671 + 10 +2.444026552903414 + 20 +0.3962797051355528 + 10 +2.411776636727307 + 20 +0.3845416955898698 + 10 +2.309842519685042 + 20 +0.4433933855038275 + 42 +0.9999999999999999 + 10 +2.290157480314964 + 20 +0.4092978971658573 + 10 +2.363482085668028 + 20 +0.366963916527043 + 10 +2.01968503937008 + 20 +0.2418320250459505 + 10 +2.019685039370081 + 20 +0.4884064321643613 + 0 +LWPOLYLINE + 5 +19B3 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.461088934470774 + 20 +0.4849772185518619 + 10 +2.570972545173304 + 20 +0.421535886333229 + 10 +2.570972545173304 + 20 +0.2739836714646079 + 0 +LWPOLYLINE + 5 +19B4 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.380544467235389 + 20 +0.4556614299433522 + 10 +2.490428077937918 + 20 +0.3922200977247193 + 10 +2.490428077937918 + 20 +0.2446678828560982 + 0 +LWPOLYLINE + 5 +19B5 +102 +{ACAD_REACTORS +330 +1B2B +102 +} +330 +1F +100 +AcDbEntity + 8 +OUTLINE +100 +AcDbPolyline + 90 + 145 + 70 + 1 + 43 +0.0 + 10 +0.1721479520991344 + 20 +0.8718378449943008 + 42 +0.3152987888789827 + 10 +0.1851003114824874 + 20 +0.8533399587583579 + 10 +0.3622643413966053 + 20 +0.7888575252869718 + 10 +0.3622643413966049 + 20 +0.6550889233752349 + 42 +0.9999999999999999 + 10 +0.4016344201367623 + 20 +0.6550889233752348 + 10 +0.4016344201367628 + 20 +0.7745279885048381 + 10 +0.442808808631991 + 20 +0.759541736678462 + 10 +0.4428088086319906 + 20 +0.625773134766725 + 42 +0.9999999999999999 + 10 +0.482178887372148 + 20 +0.625773134766725 + 10 +0.4821788873721484 + 20 +0.7452121998963283 + 10 +0.5233532758673767 + 20 +0.7302259480699523 + 10 +0.5233532758673762 + 20 +0.5964573461582154 + 42 +0.9999999999999999 + 10 +0.5627233546075336 + 20 +0.5964573461582152 + 10 +0.5627233546075341 + 20 +0.7158964112878186 + 10 +0.6038977431027625 + 20 +0.7009101594614425 + 10 +0.603897743102762 + 20 +0.5671415575497056 + 42 +0.9999999999999999 + 10 +0.6432678218429194 + 20 +0.5671415575497054 + 10 +0.6432678218429199 + 20 +0.6865806226793086 + 10 +0.6844422103381481 + 20 +0.6715943708529328 + 10 +0.6844422103381477 + 20 +0.5378257689411958 + 42 +0.9999999999999999 + 10 +0.7238122890783051 + 20 +0.5378257689411958 + 10 +0.7238122890783055 + 20 +0.6572648340707989 + 10 +0.7649866775735338 + 20 +0.642278582244423 + 10 +0.7649866775735333 + 20 +0.508509980332686 + 42 +0.9999999999999999 + 10 +0.8043567563136907 + 20 +0.508509980332686 + 10 +0.8043567563136912 + 20 +0.6279490454622892 + 10 +0.8455311448089194 + 20 +0.6129627936359132 + 10 +0.845531144808919 + 20 +0.4791941917241763 + 42 +0.9999999999999999 + 10 +0.8849012235490764 + 20 +0.4791941917241762 + 10 +0.8849012235490769 + 20 +0.5986332568537795 + 10 +0.9260756120443052 + 20 +0.5836470050274035 + 10 +0.9260756120443048 + 20 +0.4498784031156666 + 42 +0.9999999999999999 + 10 +0.9654456907844622 + 20 +0.4498784031156665 + 10 +0.9654456907844626 + 20 +0.5693174682452696 + 10 +1.006620079279691 + 20 +0.5543312164188938 + 10 +1.00662007927969 + 20 +0.4205626145071568 + 42 +0.9999999999999999 + 10 +1.045990158019848 + 20 +0.4205626145071567 + 10 +1.045990158019848 + 20 +0.5400016796367598 + 10 +1.087164546515077 + 20 +0.525015427810384 + 10 +1.087164546515076 + 20 +0.3912468258986471 + 42 +0.9999999999999999 + 10 +1.126534625255234 + 20 +0.391246825898647 + 10 +1.126534625255234 + 20 +0.5106858910282501 + 10 +1.167709013750462 + 20 +0.4956996392018742 + 10 +1.167709013750462 + 20 +0.3619310372901373 + 42 +0.9999999999999999 + 10 +1.207079092490619 + 20 +0.3619310372901371 + 10 +1.20707909249062 + 20 +0.4813701024197403 + 10 +1.248253480985848 + 20 +0.4663838505933645 + 10 +1.248253480985848 + 20 +0.3326152486816275 + 42 +0.9999999999999999 + 10 +1.287623559726005 + 20 +0.3326152486816274 + 10 +1.287623559726006 + 20 +0.4520543138112305 + 10 +1.328797948221234 + 20 +0.4370680619848547 + 10 +1.328797948221233 + 20 +0.3032994600731178 + 42 +0.9999999999999999 + 10 +1.368168026961391 + 20 +0.3032994600731176 + 10 +1.368168026961391 + 20 +0.4227385252027208 + 10 +1.409342415456619 + 20 +0.407752273376345 + 10 +1.409342415456619 + 20 +0.273983671464608 + 42 +0.9999999999999999 + 10 +1.448712494196776 + 20 +0.2739836714646079 + 10 +1.448712494196777 + 20 +0.393422736594211 + 10 +1.489886882692005 + 20 +0.3784364847678352 + 10 +1.489886882692005 + 20 +0.2446678828560983 + 42 +0.9999999999999999 + 10 +1.529256961432162 + 20 +0.2446678828560981 + 10 +1.529256961432162 + 20 +0.3641069479857013 + 10 +1.570431349927391 + 20 +0.3491206961593254 + 10 +1.57043134992739 + 20 +0.2153520942475885 + 42 +0.9999999999999999 + 10 +1.609801428667548 + 20 +0.2153520942475884 + 10 +1.609801428667548 + 20 +0.3347911593771915 + 10 +1.993267320013264 + 20 +0.1952209890709761 + 42 +0.1763269807087526 + 10 +2.006732679986736 + 20 +0.1952209890709762 + 10 +2.390198571332454 + 20 +0.3347911593771915 + 10 +2.390198571332454 + 20 +0.2153520942475884 + 42 +0.9999999999999999 + 10 +2.429568650072611 + 20 +0.2153520942475885 + 10 +2.429568650072611 + 20 +0.3491206961593254 + 10 +2.470743038567839 + 20 +0.3641069479857013 + 10 +2.47074303856784 + 20 +0.2446678828560981 + 42 +0.9999999999999999 + 10 +2.510113117307997 + 20 +0.2446678828560983 + 10 +2.510113117307997 + 20 +0.3784364847678352 + 10 +2.551287505803225 + 20 +0.393422736594211 + 10 +2.551287505803225 + 20 +0.2739836714646079 + 42 +0.9999999999999999 + 10 +2.590657584543383 + 20 +0.273983671464608 + 10 +2.590657584543382 + 20 +0.407752273376345 + 10 +2.631831973038611 + 20 +0.4227385252027208 + 10 +2.631831973038611 + 20 +0.3032994600731176 + 42 +0.9999999999999999 + 10 +2.671202051778768 + 20 +0.3032994600731178 + 10 +2.671202051778768 + 20 +0.4370680619848547 + 10 +2.712376440273996 + 20 +0.4520543138112305 + 10 +2.712376440273997 + 20 +0.3326152486816274 + 42 +0.9999999999999999 + 10 +2.751746519014154 + 20 +0.3326152486816275 + 10 +2.751746519014154 + 20 +0.4663838505933645 + 10 +2.792920907509382 + 20 +0.4813701024197403 + 10 +2.792920907509383 + 20 +0.3619310372901371 + 42 +0.9999999999999999 + 10 +2.83229098624954 + 20 +0.3619310372901373 + 10 +2.832290986249539 + 20 +0.4956996392018742 + 10 +2.873465374744768 + 20 +0.5106858910282501 + 10 +2.873465374744768 + 20 +0.391246825898647 + 42 +0.9999999999999999 + 10 +2.912835453484925 + 20 +0.3912468258986471 + 10 +2.912835453484925 + 20 +0.525015427810384 + 10 +2.954009841980153 + 20 +0.5400016796367598 + 10 +2.954009841980154 + 20 +0.4205626145071567 + 42 +0.9999999999999999 + 10 +2.993379920720312 + 20 +0.4205626145071568 + 10 +2.993379920720311 + 20 +0.5543312164188938 + 10 +3.034554309215539 + 20 +0.5693174682452696 + 10 +3.034554309215539 + 20 +0.4498784031156665 + 42 +0.9999999999999999 + 10 +3.073924387955697 + 20 +0.4498784031156666 + 10 +3.073924387955697 + 20 +0.5836470050274035 + 10 +3.115098776450925 + 20 +0.5986332568537795 + 10 +3.115098776450925 + 20 +0.4791941917241762 + 42 +0.9999999999999999 + 10 +3.154468855191083 + 20 +0.4791941917241763 + 10 +3.154468855191082 + 20 +0.6129627936359132 + 10 +3.195643243686311 + 20 +0.6279490454622892 + 10 +3.195643243686311 + 20 +0.508509980332686 + 42 +0.9999999999999999 + 10 +3.235013322426469 + 20 +0.508509980332686 + 10 +3.235013322426468 + 20 +0.642278582244423 + 10 +3.276187710921696 + 20 +0.6572648340707989 + 10 +3.276187710921697 + 20 +0.5378257689411958 + 42 +0.9999999999999999 + 10 +3.315557789661854 + 20 +0.5378257689411958 + 10 +3.315557789661854 + 20 +0.6715943708529328 + 10 +3.356732178157082 + 20 +0.6865806226793086 + 10 +3.356732178157082 + 20 +0.5671415575497054 + 42 +0.9999999999999999 + 10 +3.39610225689724 + 20 +0.5671415575497056 + 10 +3.396102256897239 + 20 +0.7009101594614425 + 10 +3.437276645392468 + 20 +0.7158964112878186 + 10 +3.437276645392468 + 20 +0.5964573461582152 + 42 +0.9999999999999999 + 10 +3.476646724132626 + 20 +0.5964573461582154 + 10 +3.476646724132625 + 20 +0.7302259480699523 + 10 +3.517821112627853 + 20 +0.7452121998963283 + 10 +3.517821112627854 + 20 +0.625773134766725 + 42 +0.9999999999999999 + 10 +3.557191191368011 + 20 +0.625773134766725 + 10 +3.557191191368011 + 20 +0.759541736678462 + 10 +3.598365579863239 + 20 +0.7745279885048381 + 10 +3.598365579863239 + 20 +0.6550889233752348 + 42 +0.9999999999999999 + 10 +3.637735658603397 + 20 +0.6550889233752349 + 10 +3.637735658603396 + 20 +0.7888575252869718 + 10 +3.814899688517512 + 20 +0.853339958758357 + 42 +0.3152987888789825 + 10 +3.827852047900865 + 20 +0.8718378449942998 + 10 +3.827852047900866 + 20 +1.160309014808614 + 42 +0.2914734195860939 + 10 +3.816486265651666 + 20 +1.17814971927784 + 10 +3.302025394556464 + 20 +1.418046763290625 + 42 +0.9999999999999994 + 10 +3.285386880314704 + 20 +1.382365354352174 + 10 +3.756776480718013 + 20 +1.162552773709486 + 10 +2.0 + 20 +0.5231384264691965 + 10 +0.2432235192819858 + 20 +1.162552773709486 + 10 +0.7689601562847856 + 20 +1.407707793716547 + 42 +1.000000000000008 + 10 +0.7523216420430257 + 20 +1.443389202654997 + 10 +0.1835137343483321 + 20 +1.178149719277839 + 42 +0.2914734195860883 + 10 +0.1721479520991333 + 20 +1.160309014808614 + 0 +LWPOLYLINE + 5 +19B6 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.702722336176931 + 20 +0.5729245843773911 + 10 +2.812605946879461 + 20 +0.5094832521587582 + 10 +2.812605946879462 + 20 +0.3619310372901372 + 0 +LWPOLYLINE + 5 +19B7 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.622177868941545 + 20 +0.5436087957688814 + 10 +2.732061479644075 + 20 +0.4801674635502485 + 10 +2.732061479644075 + 20 +0.3326152486816275 + 0 +LWPOLYLINE + 5 +19B8 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.54163340170616 + 20 +0.5142930071603717 + 10 +2.651517012408689 + 20 +0.4508516749417388 + 10 +2.65151701240869 + 20 +0.3032994600731177 + 0 +LWPOLYLINE + 5 +19B9 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.863811270647703 + 20 +0.6315561615944107 + 10 +2.973694881350232 + 20 +0.5681148293757778 + 10 +2.973694881350233 + 20 +0.4205626145071568 + 0 +LWPOLYLINE + 5 +19BA +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.783266803412317 + 20 +0.6022403729859009 + 10 +2.893150414114847 + 20 +0.538799040767268 + 10 +2.893150414114847 + 20 +0.391246825898647 + 0 +LWPOLYLINE + 5 +19BB +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.10544467235386 + 20 +0.71950352741994 + 10 +3.215328283056389 + 20 +0.656062195201307 + 10 +3.21532828305639 + 20 +0.508509980332686 + 0 +LWPOLYLINE + 5 +19BC +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +2.944355737883088 + 20 +0.6608719502029206 + 10 +3.054239348585618 + 20 +0.5974306179842876 + 10 +3.054239348585618 + 20 +0.4498784031156665 + 0 +LWPOLYLINE + 5 +19BD +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.024900205118474 + 20 +0.6901877388114303 + 10 +3.134783815821004 + 20 +0.6267464065927973 + 10 +3.134783815821004 + 20 +0.4791941917241763 + 0 +LWPOLYLINE + 5 +19BE +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.508167008530788 + 20 +0.8660824704624889 + 10 +3.618050619233318 + 20 +0.802641138243856 + 10 +3.618050619233318 + 20 +0.6550889233752348 + 0 +LWPOLYLINE + 5 +19BF +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.185989139589245 + 20 +0.7488193160284498 + 10 +3.295872750291775 + 20 +0.6853779838098168 + 10 +3.295872750291776 + 20 +0.5378257689411958 + 0 +LWPOLYLINE + 5 +19C0 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.266533606824631 + 20 +0.7781351046369596 + 10 +3.376417217527161 + 20 +0.7146937724183267 + 10 +3.376417217527161 + 20 +0.5671415575497055 + 0 +LWPOLYLINE + 5 +19C1 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.347078074060017 + 20 +0.8074508932454694 + 10 +3.456961684762546 + 20 +0.7440095610268365 + 10 +3.456961684762547 + 20 +0.5964573461582153 + 0 +LWPOLYLINE + 5 +19C2 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 3 + 70 + 0 + 43 +0.0 + 10 +3.427622541295403 + 20 +0.836766681853979 + 10 +3.537506151997932 + 20 +0.773325349635346 + 10 +3.537506151997933 + 20 +0.625773134766725 + 0 +LWPOLYLINE + 5 +1A86 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 5 + 70 + 0 + 43 +0.0 + 10 +3.808167008530787 + 20 +1.160309014808614 + 10 +3.808167008530789 + 20 +0.8718378449943008 + 10 +2.000000000000001 + 20 +0.2137188753069324 + 10 +0.1918329914692131 + 20 +0.8718378449943008 + 10 +0.1918329914692121 + 20 +1.160309014808614 + 0 +LWPOLYLINE + 5 +1A88 +330 +1F +100 +AcDbEntity + 8 +CENTERLINE +100 +AcDbPolyline + 90 + 5 + 70 + 0 + 43 +0.0 + 10 +0.7606408991639058 + 20 +1.425548498185772 + 10 +0.1918329914692121 + 20 +1.160309014808614 + 10 +1.999999999999999 + 20 +0.5021900451212454 + 10 +3.808167008530787 + 20 +1.160309014808614 + 10 +3.293706137435584 + 20 +1.4002060588214 + 0 +HATCH + 5 +1B2B +330 +1F +100 +AcDbEntity + 8 +HATCH-BLACK +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 3 + 92 + 1 + 93 + 145 + 72 + 2 + 10 +0.1918329914692131 + 20 +0.871837844994301 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +250.0 + 73 + 1 + 72 + 1 + 10 +0.1851003114824874 + 20 +0.8533399587583579 + 11 +0.3622643413966053 + 21 +0.7888575252869718 + 72 + 1 + 10 +0.3622643413966053 + 20 +0.7888575252869718 + 11 +0.3622643413966049 + 21 +0.6550889233752349 + 72 + 2 + 10 +0.3819493807666836 + 20 +0.6550889233752349 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +0.4016344201367623 + 20 +0.6550889233752348 + 11 +0.4016344201367628 + 21 +0.7745279885048381 + 72 + 1 + 10 +0.4016344201367628 + 20 +0.7745279885048381 + 11 +0.442808808631991 + 21 +0.759541736678462 + 72 + 1 + 10 +0.442808808631991 + 20 +0.759541736678462 + 11 +0.4428088086319906 + 21 +0.625773134766725 + 72 + 2 + 10 +0.4624938480020693 + 20 +0.625773134766725 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +0.482178887372148 + 20 +0.625773134766725 + 11 +0.4821788873721484 + 21 +0.7452121998963283 + 72 + 1 + 10 +0.4821788873721484 + 20 +0.7452121998963283 + 11 +0.5233532758673767 + 21 +0.7302259480699523 + 72 + 1 + 10 +0.5233532758673767 + 20 +0.7302259480699523 + 11 +0.5233532758673762 + 21 +0.5964573461582154 + 72 + 2 + 10 +0.5430383152374549 + 20 +0.5964573461582153 + 40 +0.0196850393700787 + 50 +179.9999999999997 + 51 +359.9999999999997 + 73 + 1 + 72 + 1 + 10 +0.5627233546075336 + 20 +0.5964573461582152 + 11 +0.5627233546075341 + 21 +0.7158964112878186 + 72 + 1 + 10 +0.5627233546075341 + 20 +0.7158964112878186 + 11 +0.6038977431027625 + 21 +0.7009101594614425 + 72 + 1 + 10 +0.6038977431027625 + 20 +0.7009101594614425 + 11 +0.603897743102762 + 21 +0.5671415575497056 + 72 + 2 + 10 +0.6235827824728407 + 20 +0.5671415575497055 + 40 +0.0196850393700787 + 50 +179.9999999999997 + 51 +359.9999999999997 + 73 + 1 + 72 + 1 + 10 +0.6432678218429194 + 20 +0.5671415575497054 + 11 +0.6432678218429199 + 21 +0.6865806226793086 + 72 + 1 + 10 +0.6432678218429199 + 20 +0.6865806226793086 + 11 +0.6844422103381481 + 21 +0.6715943708529328 + 72 + 1 + 10 +0.6844422103381481 + 20 +0.6715943708529328 + 11 +0.6844422103381477 + 21 +0.5378257689411958 + 72 + 2 + 10 +0.7041272497082264 + 20 +0.5378257689411958 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +0.7238122890783051 + 20 +0.5378257689411958 + 11 +0.7238122890783055 + 21 +0.6572648340707989 + 72 + 1 + 10 +0.7238122890783055 + 20 +0.6572648340707989 + 11 +0.7649866775735338 + 21 +0.642278582244423 + 72 + 1 + 10 +0.7649866775735338 + 20 +0.642278582244423 + 11 +0.7649866775735333 + 21 +0.508509980332686 + 72 + 2 + 10 +0.784671716943612 + 20 +0.508509980332686 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +0.8043567563136907 + 20 +0.508509980332686 + 11 +0.8043567563136912 + 21 +0.6279490454622892 + 72 + 1 + 10 +0.8043567563136912 + 20 +0.6279490454622892 + 11 +0.8455311448089194 + 21 +0.6129627936359132 + 72 + 1 + 10 +0.8455311448089194 + 20 +0.6129627936359132 + 11 +0.845531144808919 + 21 +0.4791941917241763 + 72 + 2 + 10 +0.8652161841789977 + 20 +0.4791941917241763 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +0.8849012235490764 + 20 +0.4791941917241762 + 11 +0.8849012235490769 + 21 +0.5986332568537795 + 72 + 1 + 10 +0.8849012235490769 + 20 +0.5986332568537795 + 11 +0.9260756120443052 + 21 +0.5836470050274035 + 72 + 1 + 10 +0.9260756120443052 + 20 +0.5836470050274035 + 11 +0.9260756120443048 + 21 +0.4498784031156666 + 72 + 2 + 10 +0.9457606514143835 + 20 +0.4498784031156665 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +0.9654456907844622 + 20 +0.4498784031156665 + 11 +0.9654456907844626 + 21 +0.5693174682452696 + 72 + 1 + 10 +0.9654456907844626 + 20 +0.5693174682452696 + 11 +1.006620079279691 + 21 +0.5543312164188938 + 72 + 1 + 10 +1.006620079279691 + 20 +0.5543312164188938 + 11 +1.00662007927969 + 21 +0.4205626145071568 + 72 + 2 + 10 +1.026305118649769 + 20 +0.4205626145071568 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.045990158019848 + 20 +0.4205626145071567 + 11 +1.045990158019848 + 21 +0.5400016796367598 + 72 + 1 + 10 +1.045990158019848 + 20 +0.5400016796367598 + 11 +1.087164546515077 + 21 +0.525015427810384 + 72 + 1 + 10 +1.087164546515077 + 20 +0.525015427810384 + 11 +1.087164546515076 + 21 +0.3912468258986471 + 72 + 2 + 10 +1.106849585885155 + 20 +0.391246825898647 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.126534625255234 + 20 +0.391246825898647 + 11 +1.126534625255234 + 21 +0.5106858910282501 + 72 + 1 + 10 +1.126534625255234 + 20 +0.5106858910282501 + 11 +1.167709013750462 + 21 +0.4956996392018742 + 72 + 1 + 10 +1.167709013750462 + 20 +0.4956996392018742 + 11 +1.167709013750462 + 21 +0.3619310372901373 + 72 + 2 + 10 +1.18739405312054 + 20 +0.3619310372901372 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.207079092490619 + 20 +0.3619310372901371 + 11 +1.20707909249062 + 21 +0.4813701024197403 + 72 + 1 + 10 +1.20707909249062 + 20 +0.4813701024197403 + 11 +1.248253480985848 + 21 +0.4663838505933645 + 72 + 1 + 10 +1.248253480985848 + 20 +0.4663838505933645 + 11 +1.248253480985848 + 21 +0.3326152486816275 + 72 + 2 + 10 +1.267938520355926 + 20 +0.3326152486816275 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.287623559726005 + 20 +0.3326152486816274 + 11 +1.287623559726006 + 21 +0.4520543138112305 + 72 + 1 + 10 +1.287623559726006 + 20 +0.4520543138112305 + 11 +1.328797948221234 + 21 +0.4370680619848547 + 72 + 1 + 10 +1.328797948221234 + 20 +0.4370680619848547 + 11 +1.328797948221233 + 21 +0.3032994600731178 + 72 + 2 + 10 +1.348482987591312 + 20 +0.3032994600731177 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.368168026961391 + 20 +0.3032994600731176 + 11 +1.368168026961391 + 21 +0.4227385252027208 + 72 + 1 + 10 +1.368168026961391 + 20 +0.4227385252027208 + 11 +1.409342415456619 + 21 +0.407752273376345 + 72 + 1 + 10 +1.409342415456619 + 20 +0.407752273376345 + 11 +1.409342415456619 + 21 +0.273983671464608 + 72 + 2 + 10 +1.429027454826698 + 20 +0.2739836714646079 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.448712494196776 + 20 +0.2739836714646079 + 11 +1.448712494196777 + 21 +0.393422736594211 + 72 + 1 + 10 +1.448712494196777 + 20 +0.393422736594211 + 11 +1.489886882692005 + 21 +0.3784364847678352 + 72 + 1 + 10 +1.489886882692005 + 20 +0.3784364847678352 + 11 +1.489886882692005 + 21 +0.2446678828560983 + 72 + 2 + 10 +1.509571922062083 + 20 +0.2446678828560982 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.529256961432162 + 20 +0.2446678828560981 + 11 +1.529256961432162 + 21 +0.3641069479857013 + 72 + 1 + 10 +1.529256961432162 + 20 +0.3641069479857013 + 11 +1.570431349927391 + 21 +0.3491206961593254 + 72 + 1 + 10 +1.570431349927391 + 20 +0.3491206961593254 + 11 +1.57043134992739 + 21 +0.2153520942475885 + 72 + 2 + 10 +1.590116389297469 + 20 +0.2153520942475884 + 40 +0.0196850393700787 + 50 +179.9999999999998 + 51 +359.9999999999998 + 73 + 1 + 72 + 1 + 10 +1.609801428667548 + 20 +0.2153520942475884 + 11 +1.609801428667548 + 21 +0.3347911593771915 + 72 + 1 + 10 +1.609801428667548 + 20 +0.3347911593771915 + 11 +1.993267320013264 + 21 +0.1952209890709761 + 72 + 2 + 10 +2.0 + 20 +0.2137188753069149 + 40 +0.0196850393700781 + 50 +249.9999999999685 + 51 +290.0000000000325 + 73 + 1 + 72 + 1 + 10 +2.006732679986736 + 20 +0.1952209890709762 + 11 +2.390198571332454 + 21 +0.3347911593771915 + 72 + 1 + 10 +2.390198571332454 + 20 +0.3347911593771915 + 11 +2.390198571332454 + 21 +0.2153520942475884 + 72 + 2 + 10 +2.409883610702533 + 20 +0.2153520942475884 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.429568650072611 + 20 +0.2153520942475885 + 11 +2.429568650072611 + 21 +0.3491206961593254 + 72 + 1 + 10 +2.429568650072611 + 20 +0.3491206961593254 + 11 +2.470743038567839 + 21 +0.3641069479857013 + 72 + 1 + 10 +2.470743038567839 + 20 +0.3641069479857013 + 11 +2.47074303856784 + 21 +0.2446678828560981 + 72 + 2 + 10 +2.490428077937918 + 20 +0.2446678828560982 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.510113117307997 + 20 +0.2446678828560983 + 11 +2.510113117307997 + 21 +0.3784364847678352 + 72 + 1 + 10 +2.510113117307997 + 20 +0.3784364847678352 + 11 +2.551287505803225 + 21 +0.393422736594211 + 72 + 1 + 10 +2.551287505803225 + 20 +0.393422736594211 + 11 +2.551287505803225 + 21 +0.2739836714646079 + 72 + 2 + 10 +2.570972545173304 + 20 +0.2739836714646079 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.590657584543383 + 20 +0.273983671464608 + 11 +2.590657584543382 + 21 +0.407752273376345 + 72 + 1 + 10 +2.590657584543382 + 20 +0.407752273376345 + 11 +2.631831973038611 + 21 +0.4227385252027208 + 72 + 1 + 10 +2.631831973038611 + 20 +0.4227385252027208 + 11 +2.631831973038611 + 21 +0.3032994600731176 + 72 + 2 + 10 +2.65151701240869 + 20 +0.3032994600731177 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.671202051778768 + 20 +0.3032994600731178 + 11 +2.671202051778768 + 21 +0.4370680619848547 + 72 + 1 + 10 +2.671202051778768 + 20 +0.4370680619848547 + 11 +2.712376440273996 + 21 +0.4520543138112305 + 72 + 1 + 10 +2.712376440273996 + 20 +0.4520543138112305 + 11 +2.712376440273997 + 21 +0.3326152486816274 + 72 + 2 + 10 +2.732061479644075 + 20 +0.3326152486816275 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.751746519014154 + 20 +0.3326152486816275 + 11 +2.751746519014154 + 21 +0.4663838505933645 + 72 + 1 + 10 +2.751746519014154 + 20 +0.4663838505933645 + 11 +2.792920907509382 + 21 +0.4813701024197403 + 72 + 1 + 10 +2.792920907509382 + 20 +0.4813701024197403 + 11 +2.792920907509383 + 21 +0.3619310372901371 + 72 + 2 + 10 +2.812605946879462 + 20 +0.3619310372901372 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.83229098624954 + 20 +0.3619310372901373 + 11 +2.832290986249539 + 21 +0.4956996392018742 + 72 + 1 + 10 +2.832290986249539 + 20 +0.4956996392018742 + 11 +2.873465374744768 + 21 +0.5106858910282501 + 72 + 1 + 10 +2.873465374744768 + 20 +0.5106858910282501 + 11 +2.873465374744768 + 21 +0.391246825898647 + 72 + 2 + 10 +2.893150414114847 + 20 +0.391246825898647 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.912835453484925 + 20 +0.3912468258986471 + 11 +2.912835453484925 + 21 +0.525015427810384 + 72 + 1 + 10 +2.912835453484925 + 20 +0.525015427810384 + 11 +2.954009841980153 + 21 +0.5400016796367598 + 72 + 1 + 10 +2.954009841980153 + 20 +0.5400016796367598 + 11 +2.954009841980154 + 21 +0.4205626145071567 + 72 + 2 + 10 +2.973694881350233 + 20 +0.4205626145071568 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.993379920720312 + 20 +0.4205626145071568 + 11 +2.993379920720311 + 21 +0.5543312164188938 + 72 + 1 + 10 +2.993379920720311 + 20 +0.5543312164188938 + 11 +3.034554309215539 + 21 +0.5693174682452696 + 72 + 1 + 10 +3.034554309215539 + 20 +0.5693174682452696 + 11 +3.034554309215539 + 21 +0.4498784031156665 + 72 + 2 + 10 +3.054239348585618 + 20 +0.4498784031156665 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +3.073924387955697 + 20 +0.4498784031156666 + 11 +3.073924387955697 + 21 +0.5836470050274035 + 72 + 1 + 10 +3.073924387955697 + 20 +0.5836470050274035 + 11 +3.115098776450925 + 21 +0.5986332568537795 + 72 + 1 + 10 +3.115098776450925 + 20 +0.5986332568537795 + 11 +3.115098776450925 + 21 +0.4791941917241762 + 72 + 2 + 10 +3.134783815821004 + 20 +0.4791941917241763 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +3.154468855191083 + 20 +0.4791941917241763 + 11 +3.154468855191082 + 21 +0.6129627936359132 + 72 + 1 + 10 +3.154468855191082 + 20 +0.6129627936359132 + 11 +3.195643243686311 + 21 +0.6279490454622892 + 72 + 1 + 10 +3.195643243686311 + 20 +0.6279490454622892 + 11 +3.195643243686311 + 21 +0.508509980332686 + 72 + 2 + 10 +3.21532828305639 + 20 +0.508509980332686 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +3.235013322426469 + 20 +0.508509980332686 + 11 +3.235013322426468 + 21 +0.642278582244423 + 72 + 1 + 10 +3.235013322426468 + 20 +0.642278582244423 + 11 +3.276187710921696 + 21 +0.6572648340707989 + 72 + 1 + 10 +3.276187710921696 + 20 +0.6572648340707989 + 11 +3.276187710921697 + 21 +0.5378257689411958 + 72 + 2 + 10 +3.295872750291776 + 20 +0.5378257689411958 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +3.315557789661854 + 20 +0.5378257689411958 + 11 +3.315557789661854 + 21 +0.6715943708529328 + 72 + 1 + 10 +3.315557789661854 + 20 +0.6715943708529328 + 11 +3.356732178157082 + 21 +0.6865806226793086 + 72 + 1 + 10 +3.356732178157082 + 20 +0.6865806226793086 + 11 +3.356732178157082 + 21 +0.5671415575497054 + 72 + 2 + 10 +3.376417217527161 + 20 +0.5671415575497055 + 40 +0.0196850393700787 + 50 +180.0000000000003 + 51 +360.0000000000003 + 73 + 1 + 72 + 1 + 10 +3.39610225689724 + 20 +0.5671415575497056 + 11 +3.396102256897239 + 21 +0.7009101594614425 + 72 + 1 + 10 +3.396102256897239 + 20 +0.7009101594614425 + 11 +3.437276645392468 + 21 +0.7158964112878186 + 72 + 1 + 10 +3.437276645392468 + 20 +0.7158964112878186 + 11 +3.437276645392468 + 21 +0.5964573461582152 + 72 + 2 + 10 +3.456961684762547 + 20 +0.5964573461582153 + 40 +0.0196850393700787 + 50 +180.0000000000003 + 51 +360.0000000000003 + 73 + 1 + 72 + 1 + 10 +3.476646724132626 + 20 +0.5964573461582154 + 11 +3.476646724132625 + 21 +0.7302259480699523 + 72 + 1 + 10 +3.476646724132625 + 20 +0.7302259480699523 + 11 +3.517821112627853 + 21 +0.7452121998963283 + 72 + 1 + 10 +3.517821112627853 + 20 +0.7452121998963283 + 11 +3.517821112627854 + 21 +0.625773134766725 + 72 + 2 + 10 +3.537506151997933 + 20 +0.625773134766725 + 40 +0.0196850393700787 + 50 +180.0 + 51 +360.0 + 73 + 1 + 72 + 1 + 10 +3.557191191368011 + 20 +0.625773134766725 + 11 +3.557191191368011 + 21 +0.759541736678462 + 72 + 1 + 10 +3.557191191368011 + 20 +0.759541736678462 + 11 +3.598365579863239 + 21 +0.7745279885048381 + 72 + 1 + 10 +3.598365579863239 + 20 +0.7745279885048381 + 11 +3.598365579863239 + 21 +0.6550889233752348 + 72 + 2 + 10 +3.618050619233318 + 20 +0.6550889233752349 + 40 +0.0196850393700787 + 50 +180.0000000000002 + 51 +360.0000000000002 + 73 + 1 + 72 + 1 + 10 +3.637735658603397 + 20 +0.6550889233752349 + 11 +3.637735658603396 + 21 +0.7888575252869718 + 72 + 1 + 10 +3.637735658603396 + 20 +0.7888575252869718 + 11 +3.814899688517512 + 21 +0.853339958758357 + 72 + 2 + 10 +3.808167008530786 + 20 +0.8718378449942998 + 40 +0.0196850393700785 + 50 +290.0000000000003 + 51 +360.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.827852047900865 + 20 +0.8718378449942998 + 11 +3.827852047900866 + 21 +1.160309014808614 + 72 + 2 + 10 +3.808167008530787 + 20 +1.160309014808614 + 40 +0.0196850393700788 + 50 +359.9999999999999 + 51 +425.0000000000013 + 73 + 1 + 72 + 1 + 10 +3.816486265651666 + 20 +1.17814971927784 + 11 +3.302025394556464 + 21 +1.418046763290625 + 72 + 2 + 10 +3.293706137435584 + 20 +1.4002060588214 + 40 +0.0196850393700788 + 50 +65.00000000000018 + 51 +245.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.285386880314704 + 20 +1.382365354352174 + 11 +3.756776480718013 + 21 +1.162552773709486 + 72 + 1 + 10 +3.756776480718013 + 20 +1.162552773709486 + 11 +2.0 + 21 +0.5231384264691965 + 72 + 1 + 10 +2.0 + 20 +0.5231384264691965 + 11 +0.2432235192819858 + 21 +1.162552773709486 + 72 + 1 + 10 +0.2432235192819858 + 20 +1.162552773709486 + 11 +0.7689601562847856 + 21 +1.407707793716547 + 72 + 2 + 10 +0.7606408991639058 + 20 +1.425548498185772 + 40 +0.0196850393700788 + 50 +294.9999999999998 + 51 +475.0000000000007 + 73 + 1 + 72 + 1 + 10 +0.7523216420430257 + 20 +1.443389202654997 + 11 +0.1835137343483322 + 21 +1.178149719277839 + 72 + 2 + 10 +0.1918329914692121 + 20 +1.160309014808614 + 40 +0.0196850393700788 + 50 +115.0000000000001 + 51 +180.0000000000002 + 73 + 1 + 72 + 1 + 10 +0.1721479520991333 + 20 +1.160309014808614 + 11 +0.1721479520991344 + 21 +0.8718378449943008 + 97 + 1 +330 +19B5 + 92 + 16 + 93 + 68 + 72 + 1 + 10 +3.788481969160711 + 20 +1.132195865069596 + 11 +3.78848196916071 + 21 +0.8856214579511849 + 72 + 1 + 10 +3.78848196916071 + 20 +0.8856214579511849 + 11 +3.619943645258092 + 21 +0.8242785247175163 + 72 + 1 + 10 +3.619943645258092 + 20 +0.8242785247175163 + 11 +3.518009528215828 + 21 +0.8831302146314739 + 72 + 2 + 10 +3.508167008530788 + 20 +0.8660824704624889 + 40 +0.0196850393700787 + 50 +60.00000000000008 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.498324488845749 + 20 +0.8490347262935038 + 11 +3.571649094198813 + 21 +0.8067007456546893 + 72 + 1 + 10 +3.571649094198813 + 20 +0.8067007456546893 + 11 +3.539399178022706 + 21 +0.7949627361090064 + 72 + 1 + 10 +3.539399178022706 + 20 +0.7949627361090064 + 11 +3.437465060980442 + 21 +0.8538144260229641 + 72 + 2 + 10 +3.427622541295402 + 20 +0.836766681853979 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.417780021610363 + 20 +0.8197189376849939 + 11 +3.491104626963428 + 21 +0.7773849570461795 + 72 + 1 + 10 +3.491104626963428 + 20 +0.7773849570461795 + 11 +3.458854710787321 + 21 +0.7656469475004968 + 72 + 1 + 10 +3.458854710787321 + 20 +0.7656469475004968 + 11 +3.356920593745056 + 21 +0.8244986374144544 + 72 + 2 + 10 +3.347078074060017 + 20 +0.8074508932454694 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.337235554374978 + 20 +0.7904031490764842 + 11 +3.410560159728042 + 21 +0.7480691684376697 + 72 + 1 + 10 +3.410560159728042 + 20 +0.7480691684376697 + 11 +3.378310243551935 + 21 +0.736331158891987 + 72 + 1 + 10 +3.378310243551935 + 20 +0.736331158891987 + 11 +3.27637612650967 + 21 +0.7951828488059446 + 72 + 2 + 10 +3.266533606824631 + 20 +0.7781351046369596 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.256691087139592 + 20 +0.7610873604679744 + 11 +3.330015692492656 + 21 +0.7187533798291599 + 72 + 1 + 10 +3.330015692492656 + 20 +0.7187533798291599 + 11 +3.297765776316549 + 21 +0.7070153702834772 + 72 + 1 + 10 +3.297765776316549 + 20 +0.7070153702834772 + 11 +3.195831659274285 + 21 +0.7658670601974349 + 72 + 2 + 10 +3.185989139589245 + 20 +0.7488193160284498 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.176146619904206 + 20 +0.7317715718594647 + 11 +3.24947122525727 + 21 +0.6894375912206502 + 72 + 1 + 10 +3.24947122525727 + 20 +0.6894375912206502 + 11 +3.217221309081164 + 21 +0.6776995816749674 + 72 + 1 + 10 +3.217221309081164 + 20 +0.6776995816749674 + 11 +3.115287192038899 + 21 +0.7365512715889251 + 72 + 2 + 10 +3.10544467235386 + 20 +0.71950352741994 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.09560215266882 + 20 +0.7024557832509549 + 11 +3.168926758021885 + 21 +0.6601218026121404 + 72 + 1 + 10 +3.168926758021885 + 20 +0.6601218026121404 + 11 +3.136676841845778 + 21 +0.6483837930664577 + 72 + 1 + 10 +3.136676841845778 + 20 +0.6483837930664577 + 11 +3.034742724803513 + 21 +0.7072354829804153 + 72 + 2 + 10 +3.024900205118474 + 20 +0.6901877388114303 + 40 +0.0196850393700787 + 50 +60.00000000000008 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +3.015057685433435 + 20 +0.6731399946424452 + 11 +3.0883822907865 + 21 +0.6308060140036307 + 72 + 1 + 10 +3.0883822907865 + 20 +0.6308060140036307 + 11 +3.056132374610392 + 21 +0.619068004457948 + 72 + 1 + 10 +3.056132374610392 + 20 +0.619068004457948 + 11 +2.954198257568128 + 21 +0.6779196943719056 + 72 + 2 + 10 +2.944355737883088 + 20 +0.6608719502029206 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.934513218198049 + 20 +0.6438242060339354 + 11 +3.007837823551114 + 21 +0.6014902253951211 + 72 + 1 + 10 +3.007837823551114 + 20 +0.6014902253951211 + 11 +2.975587907375006 + 21 +0.5897522158494382 + 72 + 1 + 10 +2.975587907375006 + 20 +0.5897522158494382 + 11 +2.873653790332742 + 21 +0.6486039057633959 + 72 + 2 + 10 +2.863811270647703 + 20 +0.6315561615944107 + 40 +0.0196850393700788 + 50 +60.00000000000023 + 51 +240.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.853968750962663 + 20 +0.6145084174254256 + 11 +2.927293356315728 + 21 +0.5721744367866111 + 72 + 1 + 10 +2.927293356315728 + 20 +0.5721744367866111 + 11 +2.895043440139621 + 21 +0.5604364272409283 + 72 + 1 + 10 +2.895043440139621 + 20 +0.5604364272409283 + 11 +2.793109323097356 + 21 +0.6192881171548861 + 72 + 2 + 10 +2.783266803412317 + 20 +0.6022403729859009 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.773424283727278 + 20 +0.5851926288169159 + 11 +2.846748889080342 + 21 +0.5428586481781015 + 72 + 1 + 10 +2.846748889080342 + 20 +0.5428586481781015 + 11 +2.814498972904235 + 21 +0.5311206386324185 + 72 + 1 + 10 +2.814498972904235 + 20 +0.5311206386324185 + 11 +2.712564855861971 + 21 +0.5899723285463763 + 72 + 2 + 10 +2.702722336176931 + 20 +0.5729245843773911 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.692879816491892 + 20 +0.5558768402084061 + 11 +2.766204421844956 + 21 +0.5135428595695918 + 72 + 1 + 10 +2.766204421844956 + 20 +0.5135428595695918 + 11 +2.733954505668849 + 21 +0.5018048500239088 + 72 + 1 + 10 +2.733954505668849 + 20 +0.5018048500239088 + 11 +2.632020388626585 + 21 +0.5606565399378665 + 72 + 2 + 10 +2.622177868941546 + 20 +0.5436087957688814 + 40 +0.0196850393700787 + 50 +60.00000000000008 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.612335349256506 + 20 +0.5265610515998964 + 11 +2.68565995460957 + 21 +0.4842270709610819 + 72 + 1 + 10 +2.68565995460957 + 20 +0.4842270709610819 + 11 +2.653410038433464 + 21 +0.4724890614153991 + 72 + 1 + 10 +2.653410038433464 + 20 +0.4724890614153991 + 11 +2.551475921391199 + 21 +0.5313407513293568 + 72 + 2 + 10 +2.541633401706159 + 20 +0.5142930071603717 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.53179088202112 + 20 +0.4972452629913866 + 11 +2.605115487374185 + 21 +0.4549112823525721 + 72 + 1 + 10 +2.605115487374185 + 20 +0.4549112823525721 + 11 +2.572865571198078 + 21 +0.4431732728068893 + 72 + 1 + 10 +2.572865571198078 + 20 +0.4431732728068893 + 11 +2.470931454155814 + 21 +0.5020249627208471 + 72 + 2 + 10 +2.461088934470774 + 20 +0.4849772185518619 + 40 +0.0196850393700788 + 50 +60.00000000000018 + 51 +240.0000000000002 + 73 + 1 + 72 + 1 + 10 +2.451246414785735 + 20 +0.4679294743828769 + 11 +2.524571020138799 + 21 +0.4255954937440624 + 72 + 1 + 10 +2.524571020138799 + 20 +0.4255954937440624 + 11 +2.492321103962692 + 21 +0.4138574841983796 + 72 + 1 + 10 +2.492321103962692 + 20 +0.4138574841983796 + 11 +2.390386986920428 + 21 +0.4727091741123373 + 72 + 2 + 10 +2.380544467235388 + 20 +0.4556614299433522 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.370701947550349 + 20 +0.4386136857743671 + 11 +2.444026552903414 + 21 +0.3962797051355528 + 72 + 1 + 10 +2.444026552903414 + 20 +0.3962797051355528 + 11 +2.411776636727307 + 21 +0.3845416955898698 + 72 + 1 + 10 +2.411776636727307 + 20 +0.3845416955898698 + 11 +2.309842519685042 + 21 +0.4433933855038275 + 72 + 2 + 10 +2.300000000000003 + 20 +0.4263456413348424 + 40 +0.0196850393700788 + 50 +60.00000000000015 + 51 +240.0000000000001 + 73 + 1 + 72 + 1 + 10 +2.290157480314964 + 20 +0.4092978971658573 + 11 +2.363482085668028 + 21 +0.366963916527043 + 72 + 1 + 10 +2.363482085668028 + 20 +0.366963916527043 + 11 +2.01968503937008 + 21 +0.2418320250459505 + 72 + 1 + 10 +2.01968503937008 + 20 +0.2418320250459505 + 11 +2.019685039370081 + 21 +0.4884064321643613 + 72 + 1 + 10 +2.019685039370081 + 20 +0.4884064321643613 + 11 +3.788481969160711 + 21 +1.132195865069596 + 97 + 1 +330 +19B2 + 92 + 16 + 93 + 68 + 72 + 1 + 10 +0.211518030839291 + 20 +1.132195865069596 + 11 +0.2115180308392921 + 21 +0.8856214579511849 + 72 + 1 + 10 +0.2115180308392921 + 20 +0.8856214579511849 + 11 +0.3800563547419098 + 21 +0.8242785247175163 + 72 + 1 + 10 +0.3800563547419098 + 20 +0.8242785247175163 + 11 +0.4819904717841743 + 21 +0.8831302146314739 + 72 + 2 + 10 +0.4918329914692137 + 20 +0.8660824704624889 + 40 +0.0196850393700787 + 50 +240.0 + 51 +420.0 + 73 + 0 + 72 + 1 + 10 +0.501675511154253 + 20 +0.8490347262935038 + 11 +0.4283509058011884 + 21 +0.8067007456546893 + 72 + 1 + 10 +0.4283509058011884 + 20 +0.8067007456546893 + 11 +0.4606008219772955 + 21 +0.7949627361090064 + 72 + 1 + 10 +0.4606008219772955 + 20 +0.7949627361090064 + 11 +0.56253493901956 + 21 +0.8538144260229641 + 72 + 2 + 10 +0.5723774587045993 + 20 +0.836766681853979 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +0.5822199783896387 + 20 +0.8197189376849939 + 11 +0.5088953730365742 + 21 +0.7773849570461795 + 72 + 1 + 10 +0.5088953730365742 + 20 +0.7773849570461795 + 11 +0.5411452892126811 + 21 +0.7656469475004968 + 72 + 1 + 10 +0.5411452892126811 + 20 +0.7656469475004968 + 11 +0.6430794062549456 + 21 +0.8244986374144544 + 72 + 2 + 10 +0.652921925939985 + 20 +0.8074508932454694 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +0.6627644456250243 + 20 +0.7904031490764842 + 11 +0.5894398402719598 + 21 +0.7480691684376697 + 72 + 1 + 10 +0.5894398402719598 + 20 +0.7480691684376697 + 11 +0.6216897564480669 + 21 +0.736331158891987 + 72 + 1 + 10 +0.6216897564480669 + 20 +0.736331158891987 + 11 +0.7236238734903314 + 21 +0.7951828488059446 + 72 + 2 + 10 +0.7334663931753708 + 20 +0.7781351046369596 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +0.7433089128604101 + 20 +0.7610873604679744 + 11 +0.6699843075073457 + 21 +0.7187533798291599 + 72 + 1 + 10 +0.6699843075073457 + 20 +0.7187533798291599 + 11 +0.7022342236834526 + 21 +0.7070153702834772 + 72 + 1 + 10 +0.7022342236834526 + 20 +0.7070153702834772 + 11 +0.8041683407257171 + 21 +0.7658670601974349 + 72 + 2 + 10 +0.8140108604107564 + 20 +0.7488193160284498 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +0.8238533800957958 + 20 +0.7317715718594647 + 11 +0.7505287747427313 + 21 +0.6894375912206502 + 72 + 1 + 10 +0.7505287747427313 + 20 +0.6894375912206502 + 11 +0.7827786909188382 + 21 +0.6776995816749674 + 72 + 1 + 10 +0.7827786909188382 + 20 +0.6776995816749674 + 11 +0.8847128079611027 + 21 +0.7365512715889251 + 72 + 2 + 10 +0.8945553276461421 + 20 +0.71950352741994 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +0.9043978473311814 + 20 +0.7024557832509549 + 11 +0.8310732419781172 + 21 +0.6601218026121404 + 72 + 1 + 10 +0.8310732419781172 + 20 +0.6601218026121404 + 11 +0.8633231581542239 + 21 +0.6483837930664577 + 72 + 1 + 10 +0.8633231581542239 + 20 +0.6483837930664577 + 11 +0.9652572751964884 + 21 +0.7072354829804153 + 72 + 2 + 10 +0.9750997948815278 + 20 +0.6901877388114303 + 40 +0.0196850393700787 + 50 +240.0 + 51 +420.0 + 73 + 0 + 72 + 1 + 10 +0.9849423145665671 + 20 +0.6731399946424452 + 11 +0.9116177092135024 + 21 +0.6308060140036307 + 72 + 1 + 10 +0.9116177092135024 + 20 +0.6308060140036307 + 11 +0.9438676253896097 + 21 +0.619068004457948 + 72 + 1 + 10 +0.9438676253896097 + 20 +0.619068004457948 + 11 +1.045801742431874 + 21 +0.6779196943719056 + 72 + 2 + 10 +1.055644262116914 + 20 +0.6608719502029206 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.065486781801953 + 20 +0.6438242060339354 + 11 +0.992162176448888 + 21 +0.6014902253951211 + 72 + 1 + 10 +0.992162176448888 + 20 +0.6014902253951211 + 11 +1.024412092624995 + 21 +0.5897522158494382 + 72 + 1 + 10 +1.024412092624995 + 20 +0.5897522158494382 + 11 +1.12634620966726 + 21 +0.6486039057633959 + 72 + 2 + 10 +1.136188729352299 + 20 +0.6315561615944107 + 40 +0.0196850393700788 + 50 +240.0000000000002 + 51 +420.0000000000003 + 73 + 0 + 72 + 1 + 10 +1.146031249037339 + 20 +0.6145084174254256 + 11 +1.072706643684274 + 21 +0.5721744367866111 + 72 + 1 + 10 +1.072706643684274 + 20 +0.5721744367866111 + 11 +1.104956559860381 + 21 +0.5604364272409283 + 72 + 1 + 10 +1.104956559860381 + 20 +0.5604364272409283 + 11 +1.206890676902646 + 21 +0.6192881171548861 + 72 + 2 + 10 +1.216733196587685 + 20 +0.6022403729859009 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.226575716272724 + 20 +0.5851926288169159 + 11 +1.15325111091966 + 21 +0.5428586481781015 + 72 + 1 + 10 +1.15325111091966 + 20 +0.5428586481781015 + 11 +1.185501027095767 + 21 +0.5311206386324185 + 72 + 1 + 10 +1.185501027095767 + 20 +0.5311206386324185 + 11 +1.287435144138031 + 21 +0.5899723285463763 + 72 + 2 + 10 +1.297277663823071 + 20 +0.5729245843773911 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.30712018350811 + 20 +0.5558768402084061 + 11 +1.233795578155045 + 21 +0.5135428595695918 + 72 + 1 + 10 +1.233795578155045 + 20 +0.5135428595695918 + 11 +1.266045494331153 + 21 +0.5018048500239088 + 72 + 1 + 10 +1.266045494331153 + 20 +0.5018048500239088 + 11 +1.367979611373417 + 21 +0.5606565399378665 + 72 + 2 + 10 +1.377822131058456 + 20 +0.5436087957688814 + 40 +0.0196850393700787 + 50 +240.0 + 51 +420.0 + 73 + 0 + 72 + 1 + 10 +1.387664650743496 + 20 +0.5265610515998964 + 11 +1.314340045390431 + 21 +0.4842270709610819 + 72 + 1 + 10 +1.314340045390431 + 20 +0.4842270709610819 + 11 +1.346589961566538 + 21 +0.4724890614153991 + 72 + 1 + 10 +1.346589961566538 + 20 +0.4724890614153991 + 11 +1.448524078608803 + 21 +0.5313407513293568 + 72 + 2 + 10 +1.458366598293842 + 20 +0.5142930071603717 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.468209117978881 + 20 +0.4972452629913866 + 11 +1.394884512625817 + 21 +0.4549112823525721 + 72 + 1 + 10 +1.394884512625817 + 20 +0.4549112823525721 + 11 +1.427134428801924 + 21 +0.4431732728068893 + 72 + 1 + 10 +1.427134428801924 + 20 +0.4431732728068893 + 11 +1.529068545844188 + 21 +0.5020249627208471 + 72 + 2 + 10 +1.538911065529228 + 20 +0.4849772185518619 + 40 +0.0196850393700788 + 50 +240.0000000000002 + 51 +420.0000000000002 + 73 + 0 + 72 + 1 + 10 +1.548753585214267 + 20 +0.4679294743828769 + 11 +1.475428979861203 + 21 +0.4255954937440624 + 72 + 1 + 10 +1.475428979861203 + 20 +0.4255954937440624 + 11 +1.50767889603731 + 21 +0.4138574841983796 + 72 + 1 + 10 +1.50767889603731 + 20 +0.4138574841983796 + 11 +1.609613013079574 + 21 +0.4727091741123373 + 72 + 2 + 10 +1.619455532764613 + 20 +0.4556614299433522 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.629298052449653 + 20 +0.4386136857743671 + 11 +1.555973447096588 + 21 +0.3962797051355528 + 72 + 1 + 10 +1.555973447096588 + 20 +0.3962797051355528 + 11 +1.588223363272695 + 21 +0.3845416955898698 + 72 + 1 + 10 +1.588223363272695 + 20 +0.3845416955898698 + 11 +1.69015748031496 + 21 +0.4433933855038275 + 72 + 2 + 10 +1.699999999999999 + 20 +0.4263456413348424 + 40 +0.0196850393700788 + 50 +240.0000000000001 + 51 +420.0000000000001 + 73 + 0 + 72 + 1 + 10 +1.709842519685038 + 20 +0.4092978971658573 + 11 +1.636517914331974 + 21 +0.366963916527043 + 72 + 1 + 10 +1.636517914331974 + 20 +0.366963916527043 + 11 +1.980314960629922 + 21 +0.2418320250459505 + 72 + 1 + 10 +1.980314960629922 + 20 +0.2418320250459505 + 11 +1.980314960629921 + 21 +0.4884064321643613 + 72 + 1 + 10 +1.980314960629921 + 20 +0.4884064321643613 + 11 +0.211518030839291 + 21 +1.132195865069596 + 97 + 1 +330 +12B7 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +0.0 + 20 +0.0 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_DETAILVIEWSTYLE +350 +122 + 3 +ACAD_GROUP +350 +D + 3 +ACAD_IMAGE_DICT +350 +124 + 3 +ACAD_IMAGE_VARS +350 +DC + 3 +ACAD_LAYOUT +350 +1A + 3 +ACAD_MLINESTYLE +350 +17 + 3 +ACAD_PLOTSETTINGS +350 +19 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +ACAD_SCALELIST +350 +B6 + 3 +ACAD_SECTIONVIEWSTYLE +350 +123 + 3 +AcDbVariableDictionary +350 +66 + 3 +APPDATA +350 +E1 + 3 +DWGPROPS +350 +1B44 + 0 +DICTIONARY + 5 +133 +330 +2 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_LAYERSTATES +360 +134 + 3 +ACLYDICTIONARY +360 +C6B + 0 +DICTIONARY + 5 +C3A +330 +1F +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_SORTENTS +360 +C3B + 0 +DICTIONARY + 5 +122 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +124 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +RASTERVARIABLES + 5 +DC +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbRasterVariables + 90 + 0 + 70 + 1 + 71 + 1 + 72 + 5 + 0 +DICTIONARY + 5 +1A +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Model +350 +22 + 3 +Sheet1 +350 +59 + 3 +Sheet2 +350 +5E + 0 +DICTIONARY + 5 +17 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +18 + 0 +DICTIONARY + 5 +19 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +DICTIONARY + 5 +B6 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +A0 +350 +B7 + 3 +A1 +350 +B8 + 3 +A2 +350 +B9 + 3 +A3 +350 +BA + 3 +A4 +350 +BB + 3 +A5 +350 +BC + 3 +A6 +350 +BD + 3 +A7 +350 +BE + 3 +A8 +350 +BF + 3 +A9 +350 +C0 + 3 +B0 +350 +C1 + 3 +B1 +350 +C2 + 3 +B2 +350 +C3 + 3 +B3 +350 +C4 + 3 +B4 +350 +C5 + 3 +B5 +350 +C6 + 3 +B6 +350 +C7 + 3 +B7 +350 +C8 + 3 +B8 +350 +C9 + 3 +B9 +350 +CA + 3 +C0 +350 +CB + 3 +C1 +350 +CC + 3 +C2 +350 +CD + 3 +C3 +350 +CE + 3 +C4 +350 +CF + 3 +C5 +350 +D0 + 3 +C6 +350 +D1 + 3 +C7 +350 +D2 + 3 +C8 +350 +D3 + 3 +C9 +350 +D4 + 3 +D0 +350 +D5 + 3 +D1 +350 +D6 + 3 +D2 +350 +D7 + 0 +DICTIONARY + 5 +123 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +66 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +DIMASSOC +350 +67 + 3 +HIDETEXT +350 +6B + 0 +DICTIONARY + 5 +E1 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +XRECORD + 5 +1B44 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 + 1 +DWGPROPS COOKIE + 2 +vector-logo + 3 + + 4 +Jonathan Greig + 6 +Original Art by Damien George + 7 +micropython logo + 8 + + 9 + +300 += +301 += +302 += +303 += +304 += +305 += +306 += +307 += +308 += +309 += + 40 +0.0 + 41 +2452643.063384271 + 42 +2456661.002361111 + 1 + + 90 + 0 + 0 +DICTIONARY + 5 +134 +102 +{ACAD_REACTORS +330 +133 +102 +} +330 +133 +100 +AcDbDictionary +281 + 1 + 3 +ARGON_LAYERP_1 +350 +135 + 3 +ARGON_LAYERP_10 +350 +C21 + 3 +ARGON_LAYERP_11 +350 +C22 + 3 +ARGON_LAYERP_12 +350 +C23 + 3 +ARGON_LAYERP_13 +350 +C26 + 3 +ARGON_LAYERP_14 +350 +C29 + 3 +ARGON_LAYERP_15 +350 +C2A + 3 +ARGON_LAYERP_16 +350 +C2B + 3 +ARGON_LAYERP_17 +350 +C2D + 3 +ARGON_LAYERP_18 +350 +C30 + 3 +ARGON_LAYERP_19 +350 +C31 + 3 +ARGON_LAYERP_2 +350 +4B1 + 3 +ARGON_LAYERP_20 +350 +C33 + 3 +ARGON_LAYERP_21 +350 +C38 + 3 +ARGON_LAYERP_22 +350 +C3C + 3 +ARGON_LAYERP_23 +350 +C3D + 3 +ARGON_LAYERP_24 +350 +C3E + 3 +ARGON_LAYERP_25 +350 +C41 + 3 +ARGON_LAYERP_26 +350 +C42 + 3 +ARGON_LAYERP_27 +350 +C43 + 3 +ARGON_LAYERP_28 +350 +C44 + 3 +ARGON_LAYERP_29 +350 +C46 + 3 +ARGON_LAYERP_3 +350 +6CF + 3 +ARGON_LAYERP_30 +350 +C49 + 3 +ARGON_LAYERP_31 +350 +C4C + 3 +ARGON_LAYERP_32 +350 +C4F + 3 +ARGON_LAYERP_33 +350 +C52 + 3 +ARGON_LAYERP_34 +350 +C54 + 3 +ARGON_LAYERP_35 +350 +C55 + 3 +ARGON_LAYERP_36 +350 +C56 + 3 +ARGON_LAYERP_37 +350 +C57 + 3 +ARGON_LAYERP_38 +350 +C58 + 3 +ARGON_LAYERP_39 +350 +C59 + 3 +ARGON_LAYERP_4 +350 +B84 + 3 +ARGON_LAYERP_40 +350 +C5A + 3 +ARGON_LAYERP_41 +350 +C5B + 3 +ARGON_LAYERP_42 +350 +C5D + 3 +ARGON_LAYERP_43 +350 +C5F + 3 +ARGON_LAYERP_44 +350 +C60 + 3 +ARGON_LAYERP_45 +350 +C61 + 3 +ARGON_LAYERP_46 +350 +C62 + 3 +ARGON_LAYERP_47 +350 +C63 + 3 +ARGON_LAYERP_48 +350 +C64 + 3 +ARGON_LAYERP_49 +350 +C65 + 3 +ARGON_LAYERP_5 +350 +B89 + 3 +ARGON_LAYERP_50 +350 +C66 + 3 +ARGON_LAYERP_51 +350 +C67 + 3 +ARGON_LAYERP_52 +350 +C68 + 3 +ARGON_LAYERP_53 +350 +C6A + 3 +ARGON_LAYERP_54 +350 +C6F + 3 +ARGON_LAYERP_55 +350 +C70 + 3 +ARGON_LAYERP_56 +350 +C71 + 3 +ARGON_LAYERP_57 +350 +C72 + 3 +ARGON_LAYERP_58 +350 +C73 + 3 +ARGON_LAYERP_59 +350 +D92 + 3 +ARGON_LAYERP_6 +350 +BB5 + 3 +ARGON_LAYERP_60 +350 +D93 + 3 +ARGON_LAYERP_61 +350 +1244 + 3 +ARGON_LAYERP_62 +350 +1B1D + 3 +ARGON_LAYERP_63 +350 +1B1E + 3 +ARGON_LAYERP_64 +350 +1B1F + 3 +ARGON_LAYERP_65 +350 +1B20 + 3 +ARGON_LAYERP_66 +350 +1B21 + 3 +ARGON_LAYERP_67 +350 +1B22 + 3 +ARGON_LAYERP_68 +350 +1B23 + 3 +ARGON_LAYERP_69 +350 +1B24 + 3 +ARGON_LAYERP_7 +350 +BF7 + 3 +ARGON_LAYERP_70 +350 +1B25 + 3 +ARGON_LAYERP_71 +350 +1B26 + 3 +ARGON_LAYERP_72 +350 +1B27 + 3 +ARGON_LAYERP_73 +350 +1B28 + 3 +ARGON_LAYERP_74 +350 +1B29 + 3 +ARGON_LAYERP_75 +350 +1B2C + 3 +ARGON_LAYERP_76 +350 +1B2D + 3 +ARGON_LAYERP_77 +350 +1B2E + 3 +ARGON_LAYERP_78 +350 +1B2F + 3 +ARGON_LAYERP_79 +350 +1B30 + 3 +ARGON_LAYERP_8 +350 +BF9 + 3 +ARGON_LAYERP_80 +350 +1B31 + 3 +ARGON_LAYERP_81 +350 +1B32 + 3 +ARGON_LAYERP_82 +350 +1B33 + 3 +ARGON_LAYERP_83 +350 +1B34 + 3 +ARGON_LAYERP_84 +350 +1B35 + 3 +ARGON_LAYERP_85 +350 +1B36 + 3 +ARGON_LAYERP_86 +350 +1B37 + 3 +ARGON_LAYERP_87 +350 +1B38 + 3 +ARGON_LAYERP_88 +350 +1B39 + 3 +ARGON_LAYERP_89 +350 +1B3A + 3 +ARGON_LAYERP_9 +350 +BFF + 3 +ARGON_LAYERP_90 +350 +1B3B + 3 +ARGON_LAYERP_91 +350 +1B3C + 3 +ARGON_LAYERP_92 +350 +1B3D + 3 +ARGON_LAYERP_93 +350 +1B3E + 0 +DICTIONARY + 5 +C6B +102 +{ACAD_REACTORS +330 +133 +102 +} +330 +133 +100 +AcDbDictionary +281 + 1 +1001 +ACAD +1000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/logo/vector-logo.svg b/src/openmv/src/micropython/logo/vector-logo.svg new file mode 100755 index 0000000..d5fb734 --- /dev/null +++ b/src/openmv/src/micropython/logo/vector-logo.svg @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/logo/vector-text-R2000.dxf b/src/openmv/src/micropython/logo/vector-text-R2000.dxf new file mode 100755 index 0000000..a963203 --- /dev/null +++ b/src/openmv/src/micropython/logo/vector-text-R2000.dxf @@ -0,0 +1,9888 @@ + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1015 + 9 +$ACADMAINTVER + 70 + 6 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$INSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$EXTMIN + 10 +0.0000000000000001 + 20 +0.0 + 30 +0.0 + 9 +$EXTMAX + 10 +3.692708053216686 + 20 +0.6839852852251591 + 30 +0.0 + 9 +$LIMMIN + 10 +0.0 + 20 +0.0 + 9 +$LIMMAX + 10 +12.0 + 20 +9.0 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 1 + 9 +$LTSCALE + 40 +1.0 + 9 +$ATTMODE + 70 + 1 + 9 +$TEXTSIZE + 40 +0.2 + 9 +$TRACEWID + 40 +0.05 + 9 +$TEXTSTYLE + 7 +Standard + 9 +$CLAYER + 8 +TEXT-RED + 9 +$CELTYPE + 6 +ByLayer + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1.0 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +1.0 + 9 +$DIMASZ + 40 +0.18 + 9 +$DIMEXO + 40 +0.0625 + 9 +$DIMDLI + 40 +0.38 + 9 +$DIMRND + 40 +0.0 + 9 +$DIMDLE + 40 +0.0 + 9 +$DIMEXE + 40 +0.18 + 9 +$DIMTP + 40 +0.0 + 9 +$DIMTM + 40 +0.0 + 9 +$DIMTXT + 40 +0.18 + 9 +$DIMCEN + 40 +0.09 + 9 +$DIMTSZ + 40 +0.0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 1 + 9 +$DIMTOH + 70 + 1 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 0 + 9 +$DIMZIN + 70 + 0 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 2 + 9 +$DIMALTF + 40 +25.4 + 9 +$DIMLFAC + 40 +1.0 + 9 +$DIMTOFL + 70 + 0 + 9 +$DIMTVP + 40 +0.0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +Standard + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1.0 + 9 +$DIMGAP + 40 +0.09 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 1 + 9 +$DIMTZIN + 70 + 0 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 3 + 9 +$DIMTDEC + 70 + 3 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 2 + 9 +$DIMTXSTY + 7 +Standard + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0.0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 46 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 + + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 2 + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 3 + 9 +$SKETCHINC + 40 +0.1 + 9 +$FILLETRAD + 40 +0.5 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 0 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0.0 + 9 +$PELEVATION + 40 +0.0 + 9 +$THICKNESS + 40 +0.0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0.0 + 9 +$CHAMFERB + 40 +0.0 + 9 +$CHAMFERC + 40 +0.0 + 9 +$CHAMFERD + 40 +0.0 + 9 +$SKPOLY + 70 + 0 + 9 +$TDCREATE + 40 +2456662.269745891 + 9 +$TDUCREATE + 40 +2456662.519745903 + 9 +$TDUPDATE + 40 +2456662.282164352 + 9 +$TDUUPDATE + 40 +2456662.532164352 + 9 +$TDINDWG + 40 +0.0000000116 + 9 +$TDUSRTIMER + 40 +2456662.519895833 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0.0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 0 + 9 +$PDSIZE + 40 +0.0 + 9 +$PLINEWID + 40 +0.0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 6 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +1D7 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$UCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSXDIR + 10 +1.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSYDIR + 10 +0.0 + 20 +1.0 + 30 +0.0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBOTTOM + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGLEFT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGRIGHT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGFRONT + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PUCSORGBACK + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0.0 + 9 +$USERR2 + 40 +0.0 + 9 +$USERR3 + 40 +0.0 + 9 +$USERR4 + 40 +0.0 + 9 +$USERR5 + 40 +0.0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0.0 + 20 +0.0 + 30 +0.0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +1.000000000000000E+20 + 20 +1.000000000000000E+20 + 30 +1.000000000000000E+20 + 9 +$PEXTMAX + 10 +-1.000000000000000E+20 + 20 +-1.000000000000000E+20 + 30 +-1.000000000000000E+20 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$PLIMMAX + 10 +0.0 + 20 +0.0 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +1.0 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 0 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 0 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$FINGERPRINTGUID + 2 +{394BC0E0-D500-95D9-65ED-9BB4C8BE75F1} + 9 +$VERSIONGUID + 2 +{FAEB1C32-E019-11D5-929B-00C0DF256EC4} + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0.0 + 9 +$OLESTARTUP +290 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +CLASS + 1 +ACDBDICTIONARYWDFLT + 2 +AcDbDictionaryWithDefault + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SCALE + 2 +AcDbScale + 3 +ObjectDBX Classes + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +VISUALSTYLE + 2 +AcDbVisualStyle + 3 +ObjectDBX Classes + 90 + 4095 +280 + 0 +281 + 0 + 0 +CLASS + 1 +MATERIAL + 2 +AcDbMaterial + 3 +ObjectDBX Classes + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +TABLESTYLE + 2 +AcDbTableStyle + 3 +ObjectDBX Classes + 90 + 4095 +280 + 0 +281 + 0 + 0 +CLASS + 1 +SUN + 2 +AcDbSun + 3 +SCENEOE + 90 + 1153 +280 + 0 +281 + 0 + 0 +CLASS + 1 +RASTERVARIABLES + 2 +AcDbRasterVariables + 3 +ISM + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +DICTIONARYVAR + 2 +AcDbDictionaryVar + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +ACDBPLACEHOLDER + 2 +AcDbPlaceHolder + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +CLASS + 1 +LAYOUT + 2 +AcDbLayout + 3 +ObjectDBX Classes + 90 + 0 +280 + 0 +281 + 0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +22 +330 +8 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*ACTIVE + 70 + 0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +1.846354026608343 + 22 +0.3419926426125796 + 13 +0.0 + 23 +0.0 + 14 +10.0 + 24 +10.0 + 15 +10.0 + 25 +10.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +1.733730323509535 + 41 +2.172519083969465 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 + 16 + 72 + 100 + 73 + 1 + 74 + 1 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 0 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 + 0 +146 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LTYPE + 5 +14 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +15 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +LTYPE + 5 +16 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CONTINUOUS + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +102 +{ACAD_XDICTIONARY +360 +1B3 +102 +} +330 +0 +100 +AcDbSymbolTable + 70 + 3 + 0 +LAYER + 5 +10 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +CONTINUOUS +370 + -3 +390 +F + 0 +LAYER + 5 +21 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +TEXT-GRAY + 70 + 0 + 62 + 254 + 6 +CONTINUOUS +370 + -3 +390 +F + 0 +LAYER + 5 +1B9 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +TEXT-RED + 70 + 0 + 62 + 1 + 6 +CONTINUOUS +370 + -3 +390 +F +1001 +AcAecLayerStandard +1000 + +1000 + + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +STYLE + 5 +11 +330 +3 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0.0 + 41 +1.0 + 50 +0.0 + 71 + 0 + 42 +0.2 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +APPID + 5 +12 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +1BA +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +AcAecLayerStandard + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 1 +100 +AcDbDimStyleTable + 0 +DIMSTYLE +105 +23 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 +178 + 0 +340 +11 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +BLOCK_RECORD + 5 +1D +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +1E + 0 +BLOCK_RECORD + 5 +1B +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +1C + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +18D +330 +1D +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 +*Model_Space + 0 +ENDBLK + 5 +18E +330 +1D +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +18F +330 +1B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 +*Paper_Space + 0 +ENDBLK + 5 +190 +330 +1B +100 +AcDbEntity + 67 + 1 + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LWPOLYLINE + 5 +24 +102 +{ACAD_REACTORS +330 +1BD +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 14 + 70 + 1 + 43 +0.0 + 10 +0.0000000000000001 + 20 +0.1752767944487085 + 10 +0.0416193345059499 + 20 +0.6506897567371471 + 10 +0.1681431038010463 + 20 +0.6506897567371471 + 10 +0.247338516041492 + 20 +0.3260572124180542 + 10 +0.3260590389156172 + 20 +0.6506897567371471 + 10 +0.4521056357224397 + 20 +0.6506897567371471 + 10 +0.4963403625301471 + 20 +0.1752767944487085 + 10 +0.4066806413363264 + 20 +0.1752767944487085 + 10 +0.3752877144762009 + 20 +0.4930112663057366 + 10 +0.2987087599944248 + 20 +0.1752767944487085 + 10 +0.1973944622688229 + 20 +0.1752767944487085 + 10 +0.1174851938975943 + 20 +0.4930112663057366 + 10 +0.0896600256100814 + 20 +0.1752767944487085 + 10 +0.0000000000000001 + 20 +0.1752767944487085 + 0 +LWPOLYLINE + 5 +34 +102 +{ACAD_REACTORS +330 +1BE +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 5 + 70 + 1 + 43 +0.0 + 10 +0.5505660310062117 + 20 +0.1752767944487085 + 10 +0.5505660310062117 + 20 +0.5201225784624666 + 10 +0.6416519423802962 + 20 +0.5201225784624666 + 10 +0.6416519423802962 + 20 +0.1752767944487085 + 10 +0.5505660310062117 + 20 +0.1752767944487085 + 0 +LWPOLYLINE + 5 +3B +102 +{ACAD_REACTORS +330 +1BF +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 13 + 70 + 1 + 43 +0.0 + 10 +0.5474731617999196 + 20 +0.5714928224153991 + 10 +0.5474731617999196 + 20 +0.6288098380164536 + 42 +-0.1883074803638932 + 10 +0.5513377262264826 + 20 +0.6414735544516654 + 42 +-0.2159435161643535 + 10 +0.5629314195061711 + 20 +0.6456942859029685 + 10 +0.6311876334269211 + 20 +0.6456942859029685 + 42 +-0.2288445935800111 + 10 +0.6418909091447587 + 20 +0.6414735544516654 + 42 +-0.1763562374232752 + 10 +0.6454571456360689 + 20 +0.6288098380164536 + 10 +0.6454571456360689 + 20 +0.5714928224153991 + 42 +-0.1943541296589125 + 10 +0.6418909091447587 + 20 +0.5602568182417533 + 42 +-0.2096410684182619 + 10 +0.6311876334269211 + 20 +0.5565109761567706 + 10 +0.5629314195061711 + 20 +0.5565109761567706 + 42 +-0.1965331617699563 + 10 +0.551636054161735 + 20 +0.5604349017541234 + 42 +-0.2135460038275524 + 10 +0.5474731617999196 + 20 +0.5714928224153991 + 0 +LWPOLYLINE + 5 +4A +102 +{ACAD_REACTORS +330 +1C5 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 12 + 70 + 1 + 43 +0.0 + 10 +1.855753791898883 + 20 +0.5703040769182958 + 10 +1.749208100737245 + 20 +0.5703040769182958 + 10 +1.749208100737245 + 20 +0.4311767133994287 + 10 +1.855281946695168 + 20 +0.4311767133994287 + 42 +0.1378892503752188 + 10 +1.880487613061407 + 20 +0.4371219629662482 + 42 +0.1061516643405155 + 10 +1.890061504452931 + 20 +0.4460702789425233 + 42 +0.0752237691491799 + 10 +1.896895649500299 + 20 +0.460071904842465 + 42 +0.0778530288832081 + 10 +1.902359921375588 + 20 +0.5032381305759515 + 42 +0.0564276025149389 + 10 +1.899452746088178 + 20 +0.5325792918405643 + 42 +0.095076106856608 + 10 +1.890715999412924 + 20 +0.5535383513733607 + 42 +0.1319298941216669 + 10 +1.876149681349825 + 20 +0.5661122650117364 + 42 +0.1129501247093477 + 10 +1.855753791898883 + 20 +0.5703040769182958 + 0 +LWPOLYLINE + 5 +58 +102 +{ACAD_REACTORS +330 +1C7 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 23 + 70 + 1 + 43 +0.0 + 10 +2.401085080890193 + 20 +0.451391475175396 + 10 +2.401085080890193 + 20 +0.502049385078848 + 10 +2.456975906310984 + 20 +0.5208364345932495 + 10 +2.471953186325706 + 20 +0.6169178168015124 + 10 +2.547828939245814 + 20 +0.6169178168015124 + 10 +2.547828939245814 + 20 +0.5208364345932495 + 10 +2.625120227777072 + 20 +0.5208364345932495 + 10 +2.625120227777072 + 20 +0.451391475175396 + 10 +2.547828939245814 + 20 +0.451391475175396 + 10 +2.547828939245814 + 20 +0.312977967787312 + 42 +0.0356379455033458 + 10 +2.549609774369517 + 20 +0.2833386307955768 + 42 +0.0811642329835157 + 10 +2.554952279740622 + 20 +0.2643422951021078 + 42 +0.1858874482849488 + 10 +2.577068121063173 + 20 +0.244721753866562 + 42 +0.0076184446139192 + 10 +2.607448863857263 + 20 +0.2345547073915278 + 42 +0.0469611640188665 + 10 +2.620599646309214 + 20 +0.2311657933719365 + 10 +2.620599646309214 + 20 +0.1752767944487085 + 10 +2.541405756150071 + 20 +0.1752767944487085 + 42 +-0.1146121843643247 + 10 +2.504464842943029 + 20 +0.1829913113213321 + 42 +-0.132229815857891 + 10 +2.478071953160988 + 20 +0.2061345575229422 + 42 +-0.0940182241125145 + 10 +2.462242307616974 + 20 +0.2447068374697993 + 42 +-0.0555506677049525 + 10 +2.456975906310984 + 20 +0.2987081511619036 + 10 +2.456975906310984 + 20 +0.451391475175396 + 10 +2.401085080890193 + 20 +0.451391475175396 + 0 +LWPOLYLINE + 5 +71 +102 +{ACAD_REACTORS +330 +1CA +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 22 + 70 + 1 + 43 +0.0 + 10 +3.589495720107105 + 20 +0.5260693501105883 + 42 +-0.0932412511784359 + 10 +3.634655872346617 + 20 +0.5185183047698327 + 42 +-0.1254375778784052 + 10 +3.666908775142547 + 20 +0.4958651687475662 + 42 +-0.1084619648488494 + 10 +3.686254428494896 + 20 +0.4581099420437885 + 42 +-0.0689905889343237 + 10 +3.692708053216686 + 20 +0.4052541467398021 + 10 +3.692708053216686 + 20 +0.1752767944487085 + 10 +3.601870241094878 + 20 +0.1752767944487085 + 10 +3.601870241094878 + 20 +0.4064428922369056 + 42 +0.0660852200863579 + 10 +3.59946535263723 + 20 +0.4269407611351025 + 42 +0.1056585132217627 + 10 +3.592296349703354 + 20 +0.4415816611820138 + 42 +0.1272161701661909 + 10 +3.580317569854181 + 20 +0.4503655923776398 + 42 +0.0972102752618352 + 10 +3.56357467552878 + 20 +0.4532940768032824 + 42 +0.0885878555139059 + 10 +3.519221226379493 + 20 +0.4465162487641 + 42 +0.077710311269079 + 10 +3.480332049105495 + 20 +0.4233288622047228 + 10 +3.480332049105495 + 20 +0.1752767944487085 + 10 +3.389479016170664 + 20 +0.1752767944487085 + 10 +3.389479016170664 + 20 +0.5201225784624666 + 10 +3.462264944047086 + 20 +0.5201225784624666 + 10 +3.480332049105495 + 20 +0.4832608134831443 + 42 +-0.0353892151285229 + 10 +3.522843779878989 + 20 +0.5102534032982943 + 42 +-0.0728322192286089 + 10 +3.555720736008866 + 20 +0.5227390362211358 + 42 +-0.0544633437581111 + 10 +3.589495720107105 + 20 +0.5260693501105883 + 0 +LWPOLYLINE + 5 +89 +102 +{ACAD_REACTORS +330 +1C6 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 17 + 70 + 1 + 43 +0.0 + 10 +2.026516093204943 + 20 +0.5201225784624666 + 10 +2.12187448679461 + 20 +0.5201225784624666 + 10 +2.181814048479542 + 20 +0.2784929327615455 + 42 +0.1680883445175794 + 10 +2.192925241986399 + 20 +0.2601209548182838 + 42 +0.1691212946679427 + 10 +2.213442897941526 + 20 +0.2539970129065732 + 42 +0.0518086164809523 + 10 +2.216060877781497 + 20 +0.2532834611920508 + 10 +2.285026381589124 + 20 +0.5201225784624666 + 10 +2.379912929975073 + 20 +0.5201225784624666 + 10 +2.2602925604266 + 20 +0.0661149499446615 + 10 +2.21297105273781 + 20 +0.0 + 10 +2.147795531372934 + 20 +0.0 + 10 +2.196547795485895 + 20 +0.1752767944487085 + 42 +-0.0815316895695442 + 10 +2.160444026995122 + 20 +0.1807616144215795 + 42 +-0.0970784439939463 + 10 +2.131326611681949 + 20 +0.1972162265483224 + 42 +-0.0875143454723418 + 10 +2.109195549546374 + 20 +0.2246403264126769 + 42 +-0.0638836232247607 + 10 +2.094050840588399 + 20 +0.2630342184309034 + 10 +2.026516093204943 + 20 +0.5201225784624666 + 0 +LWPOLYLINE + 5 +9C +102 +{ACAD_REACTORS +330 +1C8 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 22 + 70 + 1 + 43 +0.0 + 10 +2.66863653221009 + 20 +0.1752767944487085 + 10 +2.66863653221009 + 20 +0.683985285225159 + 10 +2.758774186932835 + 20 +0.683985285225159 + 10 +2.758774186932835 + 20 +0.4832608134831443 + 42 +-0.0349812911378511 + 10 +2.80104238469796 + 20 +0.5100159586151339 + 42 +-0.0697958386932639 + 10 +2.834162873836206 + 20 +0.5227390362211358 + 42 +-0.0522006296457192 + 10 +2.868653236146531 + 20 +0.5260693501105883 + 42 +-0.0932412511784358 + 10 +2.913798167573019 + 20 +0.5185183047698327 + 42 +-0.1254375778784047 + 10 +2.946066291181972 + 20 +0.4958651687475662 + 42 +-0.1084619648488494 + 10 +2.965411944534321 + 20 +0.4581099420437885 + 42 +-0.0689905889343073 + 10 +2.971865569256112 + 20 +0.4052541467398021 + 10 +2.971865569256112 + 20 +0.1752767944487085 + 10 +2.881012536321281 + 20 +0.1752767944487085 + 10 +2.881012536321281 + 20 +0.4064428922369056 + 42 +0.0660852200863579 + 10 +2.878622868676655 + 20 +0.4269407611351025 + 42 +0.1056585132217627 + 10 +2.871438644929757 + 20 +0.4415816611820138 + 42 +0.1272161701661909 + 10 +2.859475085893608 + 20 +0.4503655923776398 + 42 +0.0972102752618352 + 10 +2.842716970755184 + 20 +0.4532940768032824 + 42 +0.088587855513906 + 10 +2.798363521605896 + 20 +0.4465162487641 + 42 +0.0777103112690791 + 10 +2.759489565144921 + 20 +0.4233288622047228 + 10 +2.759489565144921 + 20 +0.1752767944487085 + 10 +2.66863653221009 + 20 +0.1752767944487085 + 0 +LWPOLYLINE + 5 +B4 +102 +{ACAD_REACTORS +330 +1C0 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 34 + 70 + 1 + 43 +0.0 + 10 +0.6946873432779551 + 20 +0.3481760979032103 + 42 +-0.0229891281782208 + 10 +0.6967086672474216 + 20 +0.3959192221127403 + 42 +-0.0328228697904816 + 10 +0.7027741612371234 + 20 +0.4354583281028243 + 42 +-0.0483316739793035 + 10 +0.7128214199136659 + 20 +0.4666716493692773 + 42 +-0.0727828188712317 + 10 +0.7267941262688635 + 20 +0.489443507733124 + 42 +-0.1227899169725496 + 10 +0.762229701067922 + 20 +0.5157237634987931 + 42 +-0.0944303865644604 + 10 +0.8083670295035159 + 20 +0.5234528923519188 + 42 +-0.0315898411800418 + 10 +0.8956492597031299 + 20 +0.5183995824282526 + 42 +-0.0456865147865019 + 10 +0.9667593760657095 + 20 +0.5032381305759515 + 10 +0.9667593760657095 + 20 +0.448776539498029 + 42 +0.0070437593452633 + 10 +0.8389882611433709 + 20 +0.4484492920180325 + 42 +0.0290350112768282 + 10 +0.82418297631581 + 20 +0.4474675495780431 + 42 +0.0847606935358247 + 10 +0.8076546954540353 + 20 +0.4410458885636011 + 42 +0.1825489438203349 + 10 +0.7945739287419907 + 20 +0.4249924970681467 + 42 +0.0517789759014607 + 10 +0.7877961007028083 + 20 +0.3930348780448645 + 42 +0.0296456838705223 + 10 +0.7855358099688792 + 20 +0.3499599771895165 + 42 +0.0216618761660938 + 10 +0.7870822445720254 + 20 +0.3081910220915498 + 42 +0.0471796273319681 + 10 +0.7917200263001613 + 20 +0.280157633081881 + 42 +0.072662787539697 + 10 +0.7993608744377529 + 20 +0.262588400817457 + 42 +0.1214661602111968 + 10 +0.8099134641066621 + 20 +0.2522132858283972 + 42 +0.0832516876593145 + 10 +0.8254021634389597 + 20 +0.247129686486815 + 42 +0.0435906078463293 + 10 +0.8478467743228099 + 20 +0.2454353055810845 + 42 +0.021166726074658 + 10 +0.9539175761181276 + 20 +0.2499539083432495 + 10 +0.9712784354522652 + 20 +0.2513808595641643 + 10 +0.9712784354522652 + 20 +0.1940650616281518 + 42 +-0.0978017422898016 + 10 +0.9130101190372676 + 20 +0.1759903461632311 + 42 +-0.0233934475797722 + 10 +0.8395225116804813 + 20 +0.1719472415999074 + 10 +0.8357173084247086 + 20 +0.1719472415999074 + 42 +-0.1019475670653864 + 10 +0.7625265069218723 + 20 +0.1805684623043164 + 42 +-0.117873950403685 + 10 +0.7277454270828068 + 20 +0.2064319722094134 + 42 +-0.0715503088956374 + 10 +0.7132826105482655 + 20 +0.2296496481867064 + 42 +-0.0491245187935067 + 10 +0.7029522447494936 + 20 +0.2610127422533067 + 42 +-0.0334830700706472 + 10 +0.6967528076051885 + 20 +0.3005215588254747 + 42 +-0.023527584931374 + 10 +0.6946873432779551 + 20 +0.3481760979032103 + 0 +LWPOLYLINE + 5 +D8 +102 +{ACAD_REACTORS +330 +1C1 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 16 + 70 + 1 + 43 +0.0 + 10 +1.020746077777311 + 20 +0.1752767944487085 + 10 +1.020746077777311 + 20 +0.5201225784624666 + 10 +1.097325032259088 + 20 +0.5201225784624666 + 10 +1.111594544468236 + 20 +0.4766017077855419 + 42 +-0.0805753976673698 + 10 +1.160646658597752 + 20 +0.5117404767306502 + 42 +-0.1124747672601628 + 10 +1.210292384435168 + 20 +0.5234528923519188 + 42 +-0.0241299749672376 + 10 +1.233896821271378 + 20 +0.5225015915379756 + 42 +-0.060832138395251 + 10 +1.248581861676056 + 20 +0.519647689096146 + 10 +1.248581861676056 + 20 +0.4318905695302117 + 42 +0.0248536783236681 + 10 +1.199353186115472 + 20 +0.4337931711580981 + 42 +0.0387057739818888 + 10 +1.170873522867967 + 20 +0.4317718471886316 + 42 +0.0551847743452131 + 10 +1.147743975398077 + 20 +0.4257063531989297 + 42 +0.080499651857314 + 10 +1.128480514436053 + 20 +0.4141126599192412 + 42 +0.0645077730986141 + 10 +1.111594544468236 + 20 +0.39550369391721 + 10 +1.111594544468236 + 20 +0.1752767944487085 + 10 +1.020746077777311 + 20 +0.1752767944487085 + 0 +LWPOLYLINE + 5 +EA +102 +{ACAD_REACTORS +330 +1C9 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 30 + 70 + 1 + 43 +0.0 + 10 +3.020617833369073 + 20 +0.3410405807579851 + 42 +-0.0409081205529831 + 10 +3.025732026544832 + 20 +0.4159559003763376 + 42 +-0.0781599297384411 + 10 +3.041896529975355 + 20 +0.4673261443292702 + 42 +-0.1364366144086533 + 10 +3.072459922525721 + 20 +0.5006216728172821 + 42 +-0.0882009175036989 + 10 +3.116752488422916 + 20 +0.5177450874682596 + 42 +-0.0529086836461284 + 10 +3.177818390271558 + 20 +0.5234528923519188 + 42 +-0.0321103580647159 + 10 +3.218868922994835 + 20 +0.5210145181056196 + 42 +-0.0444041287441238 + 10 +3.253054869044698 + 20 +0.5137024395293266 + 42 +-0.0605636228964518 + 10 +3.280406670047193 + 20 +0.5015136124604352 + 42 +-0.0762678881360705 + 10 +3.300893884376273 + 20 +0.4844495589802478 + 42 +-0.0695139514449708 + 10 +3.315825501951926 + 20 +0.4611571488110112 + 42 +-0.0499044136612151 + 10 +3.326495291881113 + 20 +0.4302847737562754 + 42 +-0.0350340529330662 + 10 +3.332888033350811 + 20 +0.3918309117347381 + 42 +-0.0250615206333876 + 10 +3.335018947174044 + 20 +0.3457970848277011 + 42 +-0.0247570817049555 + 10 +3.332933695789881 + 20 +0.2998822846785048 + 42 +-0.035093333100506 + 10 +3.326632279198321 + 20 +0.2617856551386192 + 42 +-0.0509721690967282 + 10 +3.316160359838434 + 20 +0.2315076528324352 + 42 +-0.0726634493786117 + 10 +3.301487496084174 + 20 +0.2090479733436921 + 42 +-0.0773754337522631 + 10 +3.281182931511371 + 20 +0.1928163461277374 + 42 +-0.0591962390389137 + 10 +3.253800688882829 + 20 +0.1812223484317884 + 42 +-0.0423681953096553 + 10 +3.219355989011574 + 20 +0.174265980255845 + 42 +-0.0302514249026995 + 10 +3.177818390271558 + 20 +0.1719472415999074 + 42 +-0.0327640807112059 + 10 +3.136935286491535 + 20 +0.1744296039958433 + 42 +-0.0448781589059774 + 10 +3.10273411962865 + 20 +0.1818763867673907 + 42 +-0.060332284523739 + 10 +3.075214889682901 + 20 +0.1942878943308099 + 42 +-0.0746618379907621 + 10 +3.054392817467312 + 20 +0.2116639744779708 + 42 +-0.0666236365557017 + 10 +3.03961340802189 + 20 +0.2341087375699512 + 42 +-0.0504061851560683 + 10 +3.029065384596889 + 20 +0.2631532451887439 + 42 +-0.0367317311855017 + 10 +3.022733526379283 + 20 +0.2987971929180886 + 42 +-0.0269050519350767 + 10 +3.020617833369073 + 20 +0.3410405807579851 + 0 +LWPOLYLINE + 5 +10A +102 +{ACAD_REACTORS +330 +1C2 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 21 + 70 + 1 + 43 +0.0 + 10 +1.390325682953593 + 20 +0.4318905695302117 + 42 +0.0242919032698246 + 10 +1.38033778544784 + 20 +0.3839084785562191 + 42 +0.0375411437912006 + 10 +1.377007471558388 + 20 +0.3446083393305977 + 42 +0.0398730504554166 + 10 +1.38033778544784 + 20 +0.2901464438364147 + 42 +0.0541422102818605 + 10 +1.38500448672072 + 20 +0.2730230291854372 + 42 +0.0823828350418203 + 10 +1.392347006923059 + 20 +0.2606561186041756 + 42 +0.1602559612730944 + 10 +1.412086879332706 + 20 +0.2480513067153631 + 42 +0.0555482263236158 + 10 +1.442053616012568 + 20 +0.2454353055810845 + 42 +0.0316904222703728 + 10 +1.470353673666401 + 20 +0.2467432300441587 + 42 +0.1007429782984575 + 10 +1.488551677716809 + 20 +0.2532834611920508 + 42 +0.1818370389300056 + 10 +1.501154510899928 + 20 +0.2694555750290851 + 42 +0.0526041808970857 + 10 +1.507395044239396 + 20 +0.2969244240837275 + 42 +0.0324432335036989 + 10 +1.50948029562356 + 20 +0.3327178401969589 + 42 +0.018652937942289 + 10 +1.507927772695204 + 20 +0.3912220792138144 + 42 +0.0530768467862457 + 10 +1.502463500819915 + 20 +0.4224962837323597 + 42 +0.1914595274942226 + 10 +1.48998243414098 + 20 +0.4402133100912379 + 42 +0.0889989641192241 + 10 +1.472167994578754 + 20 +0.4475269107488332 + 42 +0.0570509400215991 + 10 +1.448236310262548 + 20 +0.4499652849951324 + 42 +0.0204219730568417 + 10 +1.425137204418705 + 20 +0.4491616260675131 + 42 +0.045760246847436 + 10 +1.409828110680079 + 20 +0.4467536934472601 + 42 +0.1785155631256146 + 10 +1.390325682953593 + 20 +0.4318905695302117 + 0 +LWPOLYLINE + 5 +121 +102 +{ACAD_REACTORS +330 +1C9 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 21 + 70 + 1 + 43 +0.0 + 10 +3.124789077699108 + 20 +0.4318905695302117 + 42 +0.0242919032698246 + 10 +3.114804224355961 + 20 +0.3839084785562191 + 42 +0.0375411437912007 + 10 +3.111470866303904 + 20 +0.3446083393305977 + 42 +0.0398730504554166 + 10 +3.114804224355961 + 20 +0.2901464438364147 + 42 +0.0541422102818607 + 10 +3.119461793141027 + 20 +0.2730230291854372 + 42 +0.0823828350418199 + 10 +3.12681344583118 + 20 +0.2606561186041756 + 42 +0.1602559612730945 + 10 +3.146539619509106 + 20 +0.2480513067153631 + 42 +0.0555482263236158 + 10 +3.176509400351572 + 20 +0.2454353055810845 + 42 +0.0316904222703728 + 10 +3.204820112574522 + 20 +0.2467432300441587 + 42 +0.1007429782984576 + 10 +3.223008984137115 + 20 +0.2532834611920508 + 42 +0.1818370389300056 + 10 +3.235611817320236 + 20 +0.2694555750290851 + 42 +0.0526041808970857 + 10 +3.241852350659703 + 20 +0.2969244240837275 + 42 +0.0324432335036989 + 10 +3.243937602043866 + 20 +0.3327178401969589 + 42 +0.018652937942289 + 10 +3.242385079115511 + 20 +0.3912220792138144 + 42 +0.0530768467862456 + 10 +3.236920807240222 + 20 +0.4224962837323597 + 42 +0.1914595274942226 + 10 +3.224439740561286 + 20 +0.4402133100912379 + 42 +0.0889989641192241 + 10 +3.20663138932427 + 20 +0.4475269107488332 + 42 +0.0570509400215991 + 10 +3.182689050438947 + 20 +0.4499652849951324 + 42 +0.0204219730568417 + 10 +3.159599077082918 + 20 +0.4491616260675131 + 42 +0.045760246847436 + 10 +3.144286939181689 + 20 +0.4467536934472601 + 42 +0.178515563125615 + 10 +3.124789077699108 + 20 +0.4318905695302117 + 0 +LWPOLYLINE + 5 +138 +102 +{ACAD_REACTORS +330 +1C5 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbPolyline + 90 + 17 + 70 + 1 + 43 +0.0 + 10 +1.658111534794044 + 20 +0.1752767944487085 + 10 +1.658111534794044 + 20 +0.6506897567371471 + 10 +1.862892353206713 + 20 +0.6506897567371471 + 42 +-0.0918352741933524 + 10 +1.923821267738147 + 20 +0.6408190594916725 + 42 +-0.133922059302927 + 10 +1.965389308104209 + 20 +0.6112100119178533 + 42 +-0.1060028202258852 + 10 +1.987322499670483 + 20 +0.566558234833313 + 42 +-0.0661506729116568 + 10 +1.99464371073459 + 20 +0.5039519867067345 + 42 +-0.0710178368558241 + 10 +1.985846080807243 + 20 +0.4324841812381122 + 42 +-0.0374247138640044 + 10 +1.976089539659442 + 20 +0.4061156447569091 + 42 +-0.057718769966508 + 10 +1.964430396883754 + 20 +0.3867030198272586 + 42 +-0.1271250474471338 + 10 +1.932329702218055 + 20 +0.3624456101123582 + 42 +-0.110827379232239 + 10 +1.875723498585179 + 20 +0.3505535888974171 + 42 +-0.0258396192335467 + 10 +1.802480946318064 + 20 +0.3564988384642365 + 42 +-0.0037744416271255 + 10 +1.763835302052436 + 20 +0.3612568646152548 + 42 +-0.0304647996844293 + 10 +1.749208100737245 + 20 +0.3636343556094617 + 10 +1.749208100737245 + 20 +0.1752767944487085 + 10 +1.658111534794044 + 20 +0.1752767944487085 + 0 +LWPOLYLINE + 5 +14B +102 +{ACAD_REACTORS +330 +1C2 +102 +} +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbPolyline + 90 + 30 + 70 + 1 + 43 +0.0 + 10 +1.286159004867464 + 20 +0.3410405807579851 + 42 +-0.040908120552983 + 10 +1.29127167596192 + 20 +0.4159559003763376 + 42 +-0.0781599297384411 + 10 +1.307443789798954 + 20 +0.4673261443292702 + 42 +-0.1364366144086534 + 10 +1.338004138186717 + 20 +0.5006216728172821 + 42 +-0.088200917503699 + 10 +1.382299748246516 + 20 +0.5177450874682596 + 42 +-0.0529086836461285 + 10 +1.443361083851251 + 20 +0.5234528923519188 + 42 +-0.0321103580647177 + 10 +1.484408572411924 + 20 +0.5210145181056196 + 42 +-0.0444041287441238 + 10 +1.518597562624391 + 20 +0.5137024395293266 + 42 +-0.0605636228964518 + 10 +1.545949363626886 + 20 +0.5015136124604352 + 42 +-0.0762678881361016 + 10 +1.566436577955966 + 20 +0.4844495589802478 + 42 +-0.0695139514449315 + 10 +1.581368195531619 + 20 +0.4611571488110112 + 42 +-0.0499044136612151 + 10 +1.592037985460806 + 20 +0.4302847737562754 + 42 +-0.0350340529330662 + 10 +1.598430726930504 + 20 +0.3918309117347381 + 42 +-0.0250615206333974 + 10 +1.600561640753737 + 20 +0.3457970848277011 + 42 +-0.0247570817049556 + 10 +1.59846116855655 + 20 +0.2998822846785048 + 42 +-0.035093333100506 + 10 +1.592174972778014 + 20 +0.2617856551386192 + 42 +-0.0509721690967282 + 10 +1.581703053418127 + 20 +0.2315076528324352 + 42 +-0.0726634493786118 + 10 +1.567030189663867 + 20 +0.2090479733436921 + 42 +-0.0773754337522942 + 10 +1.546725625091063 + 20 +0.1928163461277374 + 42 +-0.0591962390389137 + 10 +1.519343382462522 + 20 +0.1812223484317884 + 42 +-0.0423681953096553 + 10 +1.484891072184755 + 20 +0.174265980255845 + 42 +-0.0302514249026978 + 10 +1.443361083851251 + 20 +0.1719472415999074 + 42 +-0.0327640807112059 + 10 +1.402470369664717 + 20 +0.1744296039958433 + 42 +-0.0448781589059774 + 10 +1.368267680720529 + 20 +0.1818763867673907 + 42 +-0.060332284523739 + 10 +1.340754539099989 + 20 +0.1942878943308099 + 42 +-0.0746618379907621 + 10 +1.319929422721796 + 20 +0.2116639744779708 + 42 +-0.0666236365556613 + 10 +1.305154579520281 + 20 +0.2341087375699512 + 42 +-0.0504061851560684 + 10 +1.294601989851372 + 20 +0.2631532451887439 + 42 +-0.0367317311855017 + 10 +1.288268609552464 + 20 +0.2987971929180886 + 42 +-0.0269050519351071 + 10 +1.286159004867464 + 20 +0.3410405807579851 + 0 +HATCH + 5 +1BD +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 14 + 72 + 1 + 10 +0.0000000000000001 + 20 +0.1752767944487085 + 11 +0.0416193345059499 + 21 +0.6506897567371471 + 72 + 1 + 10 +0.0416193345059499 + 20 +0.6506897567371471 + 11 +0.1681431038010463 + 21 +0.6506897567371471 + 72 + 1 + 10 +0.1681431038010463 + 20 +0.6506897567371471 + 11 +0.247338516041492 + 21 +0.3260572124180542 + 72 + 1 + 10 +0.247338516041492 + 20 +0.3260572124180542 + 11 +0.3260590389156172 + 21 +0.6506897567371471 + 72 + 1 + 10 +0.3260590389156172 + 20 +0.6506897567371471 + 11 +0.4521056357224397 + 21 +0.6506897567371471 + 72 + 1 + 10 +0.4521056357224397 + 20 +0.6506897567371471 + 11 +0.4963403625301471 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.4963403625301471 + 20 +0.1752767944487085 + 11 +0.4066806413363264 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.4066806413363264 + 20 +0.1752767944487085 + 11 +0.3752877144762009 + 21 +0.4930112663057366 + 72 + 1 + 10 +0.3752877144762009 + 20 +0.4930112663057366 + 11 +0.2987087599944248 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.2987087599944248 + 20 +0.1752767944487085 + 11 +0.1973944622688229 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.1973944622688229 + 20 +0.1752767944487085 + 11 +0.1174851938975943 + 21 +0.4930112663057366 + 72 + 1 + 10 +0.1174851938975943 + 20 +0.4930112663057366 + 11 +0.0896600256100814 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.0896600256100814 + 20 +0.1752767944487085 + 11 +0.0000000000000001 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.0000000000000001 + 20 +0.1752767944487085 + 11 +0.0000000000000001 + 21 +0.1752767944487085 + 97 + 1 +330 +24 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1BE +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 5 + 72 + 1 + 10 +0.5505660310062117 + 20 +0.1752767944487085 + 11 +0.5505660310062117 + 21 +0.5201225784624666 + 72 + 1 + 10 +0.5505660310062117 + 20 +0.5201225784624666 + 11 +0.6416519423802962 + 21 +0.5201225784624666 + 72 + 1 + 10 +0.6416519423802962 + 20 +0.5201225784624666 + 11 +0.6416519423802962 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.6416519423802962 + 20 +0.1752767944487085 + 11 +0.5505660310062117 + 21 +0.1752767944487085 + 72 + 1 + 10 +0.5505660310062117 + 20 +0.1752767944487085 + 11 +0.5505660310062117 + 21 +0.1752767944487085 + 97 + 1 +330 +34 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1BF +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 13 + 72 + 1 + 10 +0.5474731617999196 + 20 +0.5714928224153991 + 11 +0.5474731617999196 + 21 +0.6288098380164536 + 72 + 2 + 10 +0.5656218268345913 + 20 +0.630192970755272 + 40 +0.0182012938747197 + 50 +175.6418407014946 + 51 +218.2992114073367 + 73 + 0 + 72 + 2 + 10 +0.5617930966007493 + 20 +0.6307876795407876 + 40 +0.0149500064305679 + 50 +225.6246753032742 + 51 +274.3668398711414 + 73 + 0 + 72 + 1 + 10 +0.5629314195061711 + 20 +0.6456942859029685 + 11 +0.6311876334269211 + 21 +0.6456942859029685 + 72 + 2 + 10 +0.6321698296440981 + 20 +0.6325035330064808 + 40 +0.0132272699898821 + 50 +265.7415594617891 + 51 +317.3010585925538 + 73 + 0 + 72 + 2 + 10 +0.6262804611730807 + 20 +0.6302434840168466 + 40 +0.0192301993709753 + 50 +324.2689673804306 + 51 +364.2754703081528 + 73 + 0 + 72 + 1 + 10 +0.6454571456360689 + 20 +0.6288098380164536 + 11 +0.6454571456360689 + 21 +0.5714928224153991 + 72 + 2 + 10 +0.6297669641888812 + 20 +0.5702888340215038 + 40 +0.0157363077593922 + 50 +355.611999000231 + 51 +399.6062175218991 + 73 + 0 + 72 + 2 + 10 +0.6322686211170757 + 20 +0.5705867464421508 + 40 +0.0141172179806454 + 50 +47.03124341518984 + 51 +94.39156764264102 + 73 + 0 + 72 + 1 + 10 +0.6311876334269211 + 20 +0.5565109761567706 + 11 +0.5629314195061711 + 21 +0.5565109761567706 + 72 + 2 + 10 +0.5620823708457157 + 20 +0.572286229491247 + 40 +0.0157980853711685 + 50 +86.91922452913958 + 51 +131.3944660406891 + 73 + 0 + 72 + 2 + 10 +0.5619098596911134 + 20 +0.570615150925454 + 40 +0.0144633520750158 + 50 +135.2620677004958 + 51 +183.4789850614727 + 73 + 0 + 72 + 1 + 10 +0.5474731617999196 + 20 +0.5714928224153991 + 11 +0.5474731617999196 + 21 +0.5714928224153991 + 97 + 1 +330 +3B + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C0 +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 34 + 72 + 2 + 10 +1.214616030315336 + 20 +0.350077974119305 + 40 +0.5199321655154222 + 50 +179.7904154992175 + 51 +185.0582076977404 + 73 + 0 + 72 + 2 + 10 +1.000572124284262 + 20 +0.3695398595471971 + 40 +0.3050063463138826 + 50 +184.961591177561 + 51 +192.4813391512255 + 73 + 0 + 72 + 2 + 10 +0.8688743989493632 + 20 +0.3992160253637114 + 40 +0.170008215907044 + 50 +192.3087569665484 + 51 +203.3769478223085 + 73 + 0 + 72 + 2 + 10 +0.7976119460679242 + 20 +0.4303172999651613 + 40 +0.0922554716323781 + 50 +203.2074684948184 + 51 +219.8587008780153 + 73 + 0 + 72 + 2 + 10 +0.7972117188097253 + 20 +0.4315246663413517 + 40 +0.0911769133466147 + 50 +219.4374770529955 + 51 +247.4386863416477 + 73 + 0 + 72 + 2 + 10 +0.8055784036639897 + 20 +0.398531115770543 + 40 +0.124952897918856 + 50 +249.7009350090099 + 51 +271.2787999327404 + 73 + 0 + 72 + 2 + 10 +0.8120564786102148 + 20 +-0.1691304899318403 + 40 +0.6925932092147039 + 50 +269.6947835186498 + 51 +276.9322349981942 + 73 + 0 + 72 + 2 + 10 +0.8484128964611991 + 20 +0.1225112149529162 + 40 +0.3986964678983381 + 50 +276.8042143326444 + 51 +287.2675164228719 + 73 + 0 + 72 + 1 + 10 +0.9667593760657095 + 20 +0.5032381305759515 + 11 +0.9667593760657095 + 21 +0.448776539498029 + 72 + 2 + 10 +0.9144880443227094 + 20 +-4.086066981505726 + 40 +4.535144766389704 + 50 +89.3396036583715 + 51 +90.9538876909594 + 73 + 1 + 72 + 2 + 10 +0.8400315841062043 + 20 +0.3205880251107224 + 40 +0.1278655234922502 + 50 +90.46751199340585 + 51 +97.1199774171112 + 73 + 1 + 72 + 2 + 10 +0.8347233227483223 + 20 +0.3958571165940125 + 40 +0.0526757600392865 + 50 +101.54272561012 + 51 +120.9221245987022 + 73 + 1 + 72 + 2 + 10 +0.8223667308685831 + 20 +0.4157021086294436 + 40 +0.029304456442492 + 50 +120.1351163505028 + 51 +161.5166003585789 + 73 + 1 + 72 + 2 + 10 +0.9450695696956614 + 20 +0.3763766174814469 + 40 +0.1581532222056973 + 50 +162.0975481756131 + 51 +173.9538270794763 + 73 + 1 + 72 + 2 + 10 +1.149594366372439 + 20 +0.3524533042818777 + 40 +0.3640670943255288 + 50 +173.6000944629489 + 51 +180.3923953532557 + 73 + 1 + 72 + 2 + 10 +1.268138893295446 + 20 +0.346914547227496 + 40 +0.4826126922076991 + 50 +179.638444150984 + 51 +184.6022041776311 + 73 + 1 + 72 + 2 + 10 +0.9376165336263994 + 20 +0.3186947544718952 + 40 +0.1509003001157511 + 50 +183.9914206989488 + 51 +194.7961827171795 + 73 + 1 + 72 + 2 + 10 +0.8556691262907683 + 20 +0.2975229405501065 + 40 +0.0662649326044679 + 50 +195.1922580686626 + 51 +211.8161260167849 + 73 + 1 + 72 + 2 + 10 +0.8256760335810848 + 20 +0.2787995943136916 + 40 +0.0309077724093995 + 50 +211.6347351863199 + 51 +239.3370203444206 + 73 + 1 + 72 + 2 + 10 +0.8328177638353177 + 20 +0.2958607887822569 + 40 +0.0492921034260791 + 50 +242.3114767787511 + 51 +261.3474606529535 + 73 + 1 + 72 + 2 + 10 +0.8463235842781011 + 20 +0.3747617950344397 + 40 +0.1293354591063143 + 50 +260.6908797927596 + 51 +270.6747908046021 + 73 + 1 + 72 + 2 + 10 +0.8475369120546362 + 20 +1.499934543466537 + 40 +1.25449927615356 + 50 +270.0141521009336 + 51 +274.864484102984 + 73 + 1 + 72 + 1 + 10 +0.9539175761181276 + 20 +0.2499539083432495 + 11 +0.9712784354522652 + 21 +0.2513808595641643 + 72 + 1 + 10 +0.9712784354522652 + 20 +0.2513808595641643 + 11 +0.9712784354522652 + 21 +0.1940650616281518 + 72 + 2 + 10 +0.8963837746081258 + 20 +0.3325480038481863 + 40 +0.1574380370459314 + 50 +61.59448955636654 + 51 +83.93793890179708 + 73 + 0 + 72 + 2 + 10 +0.8330823004026875 + 20 +0.9588829323823655 + 40 +0.7869620433976263 + 50 +84.17070136778845 + 51 +89.53110693540054 + 73 + 0 + 72 + 1 + 10 +0.8395225116804813 + 20 +0.1719472415999074 + 11 +0.8357173084247086 + 21 +0.1719472415999074 + 72 + 2 + 10 +0.8200434901136805 + 20 +0.3538739274501789 + 40 +0.1826006232325358 + 50 +85.075865127039 + 51 +108.3600821200968 + 73 + 0 + 72 + 2 + 10 +0.7992279764644755 + 20 +0.2662427996310877 + 40 +0.093204559668334 + 50 +113.1894915396505 + 51 +140.0801272454766 + 73 + 0 + 72 + 2 + 10 +0.8012223158134221 + 20 +0.2683158374418412 + 40 +0.0960649049009913 + 50 +139.8951733394063 + 51 +156.2653987660679 + 73 + 0 + 72 + 2 + 10 +0.867342438096846 + 20 +0.2977766777590661 + 40 +0.168450950198126 + 50 +156.1444339138709 + 51 +167.3939009796797 + 73 + 0 + 72 + 2 + 10 +0.99451280167804 + 20 +0.3270031053307328 + 40 +0.2989352544876143 + 50 +167.2468323736907 + 51 +174.9177209790342 + 73 + 0 + 72 + 2 + 10 +1.20180856877263 + 20 +0.3462839419889538 + 40 +0.5071247554608478 + 50 +174.8226486749857 + 51 +180.2137793480696 + 73 + 0 + 72 + 1 + 10 +0.6946873432779551 + 20 +0.3481760979032103 + 11 +0.6946873432779551 + 21 +0.3481760979032103 + 97 + 1 +330 +B4 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C1 +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 16 + 72 + 1 + 10 +1.020746077777311 + 20 +0.1752767944487085 + 11 +1.020746077777311 + 21 +0.5201225784624666 + 72 + 1 + 10 +1.020746077777311 + 20 +0.5201225784624666 + 11 +1.097325032259088 + 21 +0.5201225784624666 + 72 + 1 + 10 +1.097325032259088 + 20 +0.5201225784624666 + 11 +1.111594544468236 + 21 +0.4766017077855419 + 72 + 2 + 10 +1.244437268897258 + 20 +0.3429659792394641 + 40 +0.1884295554783436 + 50 +225.1705040479414 + 51 +243.5972159016927 + 73 + 0 + 72 + 2 + 10 +1.211173613045121 + 20 +0.4086440720149234 + 40 +0.114812202274129 + 50 +243.8907918763913 + 51 +269.5602281386679 + 73 + 0 + 72 + 2 + 10 +1.212244334515651 + 20 +0.2785645037372034 + 40 +0.2448961677679514 + 50 +269.5433179430547 + 51 +275.0724278925614 + 73 + 0 + 72 + 2 + 10 +1.229554147138809 + 20 +0.4609473043473566 + 40 +0.0617072855517635 + 50 +274.0355485122913 + 51 +287.9600884366593 + 73 + 0 + 72 + 1 + 10 +1.248581861676056 + 20 +0.519647689096146 + 11 +1.248581861676056 + 21 +0.4318905695302117 + 72 + 2 + 10 +1.204841316941958 + 20 +-0.0620372588614032 + 40 +0.4958608019528185 + 50 +84.9392850010685 + 51 +90.63415610337293 + 73 + 1 + 72 + 2 + 10 +1.198149495755201 + 20 +0.2491083832840643 + 40 +0.1846887103819838 + 50 +89.62657779356016 + 51 +98.49286189291752 + 73 + 1 + 72 + 2 + 10 +1.186703181985212 + 20 +0.32427591283572 + 40 +0.1086552070090232 + 50 +98.37706810352306 + 51 +111.0116715202816 + 73 + 1 + 72 + 2 + 10 +1.173884337196004 + 20 +0.3604725103818166 + 40 +0.070276402608659 + 50 +111.8368548044861 + 51 +130.2463188715139 + 73 + 1 + 72 + 2 + 10 +1.191856507616234 + 20 +0.3396388865736808 + 40 +0.0977898738515406 + 50 +130.3972532514171 + 51 +145.1608900952568 + 73 + 1 + 72 + 1 + 10 +1.111594544468236 + 20 +0.39550369391721 + 11 +1.111594544468236 + 21 +0.1752767944487085 + 72 + 1 + 10 +1.111594544468236 + 20 +0.1752767944487085 + 11 +1.020746077777311 + 21 +0.1752767944487085 + 72 + 1 + 10 +1.020746077777311 + 20 +0.1752767944487085 + 11 +1.020746077777311 + 21 +0.1752767944487085 + 97 + 1 +330 +D8 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C2 +330 +1D +100 +AcDbEntity + 8 +TEXT-GRAY +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 2 + 92 + 1 + 93 + 30 + 72 + 2 + 10 +1.745775880860402 + 20 +0.3473056857538349 + 40 +0.4596595742917985 + 50 +179.219041199578 + 51 +188.5892672078823 + 73 + 0 + 72 + 2 + 10 +1.462665276168372 + 20 +0.3902293883547505 + 40 +0.1733136452000416 + 50 +188.5364777731353 + 51 +206.4130707393759 + 73 + 0 + 72 + 2 + 10 +1.382597433515457 + 20 +0.4290189590384098 + 40 +0.0843534860499277 + 50 +207.0087701028281 + 51 +238.085854021312 + 73 + 0 + 72 + 2 + 10 +1.408309618919584 + 20 +0.3846069642931946 + 40 +0.1356549785854117 + 50 +238.7839320009168 + 51 +258.9459185787553 + 73 + 0 + 72 + 2 + 10 +1.439724993974423 + 20 +0.2328843812063898 + 40 +0.29059126074079 + 50 +258.6024639297659 + 51 +270.7169453069864 + 73 + 0 + 72 + 2 + 10 +1.444920074652102 + 20 +0.2029818501508946 + 40 +0.3204748341784855 + 50 +269.7212762564572 + 51 +277.0779005236373 + 73 + 0 + 72 + 2 + 10 +1.460416453713881 + 20 +0.3252503357550985 + 40 +0.1972288945641309 + 50 +276.9871111277841 + 51 +287.1571071678799 + 73 + 0 + 72 + 2 + 10 +1.482143870267849 + 20 +0.3951169191449219 + 40 +0.1240620704779083 + 50 +287.0876504098538 + 51 +300.9508770078874 + 73 + 0 + 72 + 2 + 10 +1.500583736465673 + 20 +0.4262167749073336 + 40 +0.0879070752171196 + 50 +301.0685629566324 + 51 +318.5141019927507 + 73 + 0 + 72 + 2 + 10 +1.490538341293795 + 20 +0.4193627680062952 + 40 +0.0999841621843878 + 50 +319.38514811862 + 51 +335.2909851831375 + 73 + 0 + 72 + 2 + 10 +1.432430719209494 + 20 +0.3924029450769723 + 40 +0.1640411911207225 + 50 +335.220473520381 + 51 +346.6482421759119 + 73 + 0 + 72 + 2 + 10 +1.321167690210193 + 20 +0.3654957782609066 + 40 +0.2785109168173717 + 50 +346.5482508793782 + 51 +354.5741818072581 + 73 + 0 + 72 + 2 + 10 +1.140576365463508 + 20 +0.34757052037717 + 40 +0.459988693945271 + 50 +354.4784226911817 + 51 +360.2208980900735 + 73 + 0 + 72 + 2 + 10 +1.136142388530695 + 20 +0.3440375062016253 + 40 +0.4644225855321327 + 50 +359.7829203976418 + 51 +365.4556667991741 + 73 + 0 + 72 + 2 + 10 +1.324257241032597 + 20 +0.3255607991203732 + 40 +0.2754036673203588 + 50 +5.350003779949623 + 51 +13.38950403845408 + 73 + 0 + 72 + 2 + 10 +1.438822228558409 + 20 +0.2978741757969074 + 40 +0.1575418848528459 + 50 +13.24247481022855 + 51 +24.9143339913515 + 73 + 0 + 72 + 2 + 10 +1.49750166023149 + 20 +0.2704935387993822 + 40 +0.0927888674313809 + 50 +24.84449572776879 + 51 +41.46851456153187 + 73 + 0 + 72 + 2 + 10 +1.504747507691185 + 20 +0.2661434323058319 + 40 +0.0844927447051385 + 50 +42.51194694689715 + 51 +60.20982750498259 + 73 + 0 + 72 + 2 + 10 +1.484241834436404 + 20 +0.3022559330899828 + 40 +0.1260208208552944 + 50 +60.27608629427618 + 51 +73.82705129133484 + 73 + 0 + 72 + 2 + 10 +1.461143797848464 + 20 +0.3806703565348255 + 40 +0.2077659731176355 + 50 +73.73258141531123 + 51 +83.43685270361343 + 73 + 0 + 72 + 2 + 10 +1.444981387538941 + 20 +0.5159994031828512 + 40 +0.3440559769484268 + 50 +83.33882871764017 + 51 +90.26983081888446 + 73 + 0 + 72 + 2 + 10 +1.441836581268094 + 20 +0.4848621958152928 + 40 +0.3129186678351786 + 50 +89.72086066320244 + 51 +97.22714964633519 + 73 + 0 + 72 + 2 + 10 +1.426768810557204 + 20 +0.3683000729345016 + 40 +0.1953872384683834 + 50 +97.14382290172345 + 51 +107.4222425802834 + 73 + 0 + 72 + 2 + 10 +1.405753699036433 + 20 +0.3016738701941614 + 40 +0.1255254500273459 + 50 +107.3755052356472 + 51 +121.1859060075268 + 73 + 0 + 72 + 2 + 10 +1.388200250824436 + 20 +0.2723186857145772 + 40 +0.091323052757868 + 50 +121.3012045363258 + 51 +138.3807483919028 + 73 + 0 + 72 + 2 + 10 +1.396390386155313 + 20 +0.2780817143578742 + 40 +0.1012797862356359 + 50 +139.0208188923022 + 51 +154.2673000625914 + 73 + 0 + 72 + 2 + 10 +1.443564578953644 + 20 +0.3008357842563767 + 40 +0.153654894821596 + 50 +154.2614231301619 + 51 +165.8039007823683 + 73 + 0 + 72 + 2 + 10 +1.533704415876427 + 20 +0.3240227080426966 + 40 +0.2467287207424286 + 50 +165.7173228384291 + 51 +174.1318325417901 + 73 + 0 + 72 + 2 + 10 +1.679452490871063 + 20 +0.3395070071807061 + 40 +0.3932964759323175 + 50 +174.0587164483615 + 51 +180.2234129253398 + 73 + 0 + 72 + 1 + 10 +1.286159004867464 + 20 +0.3410405807579851 + 11 +1.286159004867464 + 21 +0.3410405807579851 + 97 + 1 +330 +14B + 92 + 16 + 93 + 21 + 72 + 2 + 10 +1.87884778741299 + 20 +0.3051697834906549 + 40 +0.5046900079850218 + 50 +165.4581922653545 + 51 +171.0243917073363 + 73 + 1 + 72 + 2 + 10 +1.640017569701684 + 20 +0.3421119050184488 + 40 +0.2630219456806235 + 50 +170.856419407449 + 51 +179.4561773269252 + 73 + 1 + 72 + 2 + 10 +1.719600323247084 + 20 +0.3382249259339413 + 40 +0.342652316488281 + 50 +178.9325511963493 + 51 +188.0659430044691 + 73 + 1 + 72 + 2 + 10 +1.461506204624639 + 20 +0.3030699205237911 + 40 +0.0821908055767169 + 50 +189.0465869719995 + 51 +201.4429641704123 + 73 + 1 + 72 + 2 + 10 +1.425949825821255 + 20 +0.2889700547677836 + 40 +0.0439411927350844 + 50 +201.2794750422889 + 51 +220.1176890207309 + 73 + 1 + 72 + 2 + 10 +1.421375505703486 + 20 +0.2843571418367111 + 40 +0.0374752217300239 + 50 +219.2307545260716 + 51 +255.6490576647813 + 73 + 1 + 72 + 2 + 10 +1.438807477461641 + 20 +0.3811952640733502 + 40 +0.1357987619432282 + 50 +258.6520849549118 + 51 +271.3697308658793 + 73 + 1 + 72 + 2 + 10 +1.445896027874007 + 20 +0.4691190853840432 + 40 +0.2237167796028082 + 50 +269.0158770897956 + 51 +276.276357003502 + 73 + 1 + 72 + 2 + 10 +1.463387403735492 + 20 +0.2947145002894463 + 40 +0.0484744436347309 + 50 +278.2625944015626 + 51 +301.2735466815289 + 73 + 1 + 72 + 2 + 10 +1.473353916121774 + 20 +0.2781237012056268 + 40 +0.0291206023535156 + 50 +301.4591386210279 + 51 +342.6827079184787 + 73 + 1 + 72 + 2 + 10 +1.374091031750538 + 20 +0.3127659022243659 + 40 +0.1342419911030445 + 50 +341.1780241039497 + 51 +353.2229122868627 + 73 + 1 + 72 + 2 + 10 +1.232912256678613 + 20 +0.3308726804904729 + 40 +0.2765741939881523 + 50 +352.9494162843384 + 51 +360.3822505868759 + 73 + 1 + 72 + 2 + 10 +0.7248612462910731 + 20 +0.3411691780724345 + 40 +0.7846645638024572 + 50 +359.3828759745637 + 51 +363.6573187603917 + 73 + 1 + 72 + 2 + 10 +1.358304373290006 + 20 +0.3811941386031548 + 40 +0.1499590652226746 + 50 +3.834298057692314 + 51 +15.98721166096502 + 73 + 1 + 72 + 2 + 10 +1.473936824340389 + 20 +0.4156549366241289 + 40 +0.0293355637618033 + 50 +13.48613242730697 + 51 +56.84075856181408 + 73 + 1 + 72 + 2 + 10 +1.460693878894012 + 20 +0.3942253340844751 + 40 +0.054522595367914 + 50 +57.50799133160251 + 51 +77.8514521481949 + 73 + 1 + 72 + 2 + 10 +1.449551855505779 + 20 +0.3442176219715277 + 40 +0.1057558456740848 + 50 +77.65179244717869 + 51 +90.71274674017063 + 73 + 1 + 72 + 2 + 10 +1.446520818841627 + 20 +0.1669086878434607 + 40 +0.2830617955533721 + 50 +89.65275773185921 + 51 +94.33247869604129 + 73 + 1 + 72 + 2 + 10 +1.430610265978255 + 20 +0.3644952794934767 + 40 +0.0848430589089613 + 50 +93.69860806412952 + 51 +104.1787730439532 + 73 + 1 + 72 + 2 + 10 +1.420228457430697 + 20 +0.4128805599428683 + 40 +0.0354338310931719 + 50 +107.0684876277999 + 51 +147.5547663680418 + 73 + 1 + 72 + 1 + 10 +1.390325682953593 + 20 +0.4318905695302117 + 11 +1.390325682953593 + 21 +0.4318905695302117 + 97 + 1 +330 +10A + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C5 +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 2 + 92 + 1 + 93 + 17 + 72 + 1 + 10 +1.658111534794044 + 20 +0.1752767944487085 + 11 +1.658111534794044 + 21 +0.6506897567371471 + 72 + 1 + 10 +1.658111534794044 + 20 +0.6506897567371471 + 11 +1.862892353206713 + 21 +0.6506897567371471 + 72 + 2 + 10 +1.866712771298765 + 20 +0.4812885811102773 + 40 +0.1694442501183315 + 50 +268.7080565864779 + 51 +289.696280270266 + 73 + 0 + 72 + 2 + 10 +1.890323704356795 + 20 +0.5498088066581733 + 40 +0.0969791362784035 + 50 +290.2068256429989 + 51 +320.7179581453081 + 73 + 0 + 72 + 2 + 10 +1.872231214265821 + 20 +0.5377375192902893 + 40 +0.1186450067238793 + 50 +321.7376468722154 + 51 +345.941318148983 + 73 + 0 + 72 + 2 + 10 +1.755413737650509 + 20 +0.5077074919349243 + 40 +0.239259448802611 + 50 +345.7608112632561 + 51 +360.8993727822122 + 73 + 0 + 72 + 2 + 10 +1.739929769421669 + 20 +0.4990316766439469 + 40 +0.2547614597035357 + 50 +358.8933548673149 + 51 +375.1421636632072 + 73 + 0 + 72 + 2 + 10 +1.805070643979139 + 20 +0.4843830829172414 + 40 +0.1880777885766737 + 50 +16.01826700445136 + 51 +24.59137858751017 + 73 + 0 + 72 + 2 + 10 +1.886457278838033 + 20 +0.4467408832612785 + 40 +0.098409106202089 + 50 +24.38210075542359 + 51 +37.59560803165674 + 73 + 0 + 72 + 2 + 10 +1.901447144532471 + 20 +0.4366823005906129 + 40 +0.0804040955571766 + 50 +38.43315571073376 + 51 +67.41262732859074 + 73 + 0 + 72 + 2 + 10 +1.877530541683213 + 20 +0.482621245957908 + 40 +0.1320800191028363 + 50 +65.48738102872184 + 51 +90.78391246376287 + 73 + 0 + 72 + 2 + 10 +1.89658449370416 + 20 +1.061679540017775 + 40 +0.711431865658397 + 50 +91.68029910103571 + 51 +97.60098612101147 + 73 + 0 + 72 + 2 + 10 +2.098301318614009 + 20 +2.918534187606983 + 40 +2.579056963876972 + 50 +96.58637858697409 + 51 +97.45141278012369 + 73 + 0 + 72 + 2 + 10 +1.776013741879782 + 20 +0.4823678310216308 + 40 +0.1217217342158525 + 50 +95.74213501202033 + 51 +102.7219939836472 + 73 + 0 + 72 + 1 + 10 +1.749208100737245 + 20 +0.3636343556094617 + 11 +1.749208100737245 + 21 +0.1752767944487085 + 72 + 1 + 10 +1.749208100737245 + 20 +0.1752767944487085 + 11 +1.658111534794044 + 21 +0.1752767944487085 + 72 + 1 + 10 +1.658111534794044 + 20 +0.1752767944487085 + 11 +1.658111534794044 + 21 +0.1752767944487085 + 97 + 1 +330 +138 + 92 + 16 + 93 + 12 + 72 + 1 + 10 +1.855753791898883 + 20 +0.5703040769182958 + 11 +1.749208100737245 + 21 +0.5703040769182958 + 72 + 1 + 10 +1.749208100737245 + 20 +0.5703040769182958 + 11 +1.749208100737245 + 21 +0.4311767133994287 + 72 + 1 + 10 +1.749208100737245 + 20 +0.4311767133994287 + 11 +1.855281946695168 + 21 +0.4311767133994287 + 72 + 2 + 10 +1.857310696196809 + 20 +0.4789795547126073 + 40 +0.0478458719447492 + 50 +267.5698291459668 + 51 +298.9736848744403 + 73 + 1 + 72 + 2 + 10 +1.864437662714773 + 20 +0.4638897212446849 + 40 +0.0312107960389064 + 50 +300.9469057674883 + 51 +325.1843100261158 + 73 + 1 + 72 + 2 + 10 +1.847208640489655 + 20 +0.4756552874383635 + 40 +0.0520734162270339 + 50 +325.3793523193102 + 51 +342.5869620344669 + 73 + 1 + 72 + 2 + 10 +1.761853469548879 + 20 +0.499095419473726 + 40 +0.1405675106851083 + 50 +343.8821453186945 + 51 +361.6888272002417 + 73 + 1 + 72 + 2 + 10 +1.771325527872711 + 20 +0.505069610767784 + 40 +0.1310471922643137 + 50 +359.1992235790916 + 51 +372.1177778779552 + 73 + 1 + 72 + 2 + 10 +1.840471280377904 + 20 +0.5202934512206887 + 40 +0.0602474495482526 + 50 +11.76645972748428 + 51 +33.49099599484823 + 73 + 1 + 72 + 2 + 10 +1.86002067419837 + 20 +0.5327033580204925 + 40 +0.0370985166555385 + 50 +34.16739135196509 + 51 +64.22988058382727 + 73 + 1 + 72 + 2 + 10 +1.856792087819456 + 20 +0.5236405260900577 + 40 +0.0466751007960158 + 50 +65.49764645855024 + 51 +91.27465994990668 + 73 + 1 + 72 + 1 + 10 +1.855753791898883 + 20 +0.5703040769182958 + 11 +1.855753791898883 + 21 +0.5703040769182958 + 97 + 1 +330 +4A + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C6 +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 17 + 72 + 1 + 10 +2.026516093204943 + 20 +0.5201225784624666 + 11 +2.12187448679461 + 21 +0.5201225784624666 + 72 + 1 + 10 +2.12187448679461 + 20 +0.5201225784624666 + 11 +2.181814048479542 + 21 +0.2784929327615455 + 72 + 2 + 10 +2.213922500215711 + 20 +0.2853658521330381 + 40 +0.0328357989636449 + 50 +192.0820235727047 + 51 +230.2482576268844 + 73 + 1 + 72 + 2 + 10 +2.211977736162895 + 20 +0.2865212844941371 + 40 +0.0325572563546005 + 50 +234.1829062182941 + 51 +272.5793312178134 + 73 + 1 + 72 + 2 + 10 +2.218185855487651 + 20 +0.2662392650291758 + 40 +0.0131289140189778 + 50 +248.8223744883709 + 51 +260.6854283382104 + 73 + 1 + 72 + 1 + 10 +2.216060877781497 + 20 +0.2532834611920508 + 11 +2.285026381589124 + 21 +0.5201225784624666 + 72 + 1 + 10 +2.285026381589124 + 20 +0.5201225784624666 + 11 +2.379912929975073 + 21 +0.5201225784624666 + 72 + 1 + 10 +2.379912929975073 + 20 +0.5201225784624666 + 11 +2.2602925604266 + 21 +0.0661149499446615 + 72 + 1 + 10 +2.2602925604266 + 20 +0.0661149499446615 + 11 +2.21297105273781 + 21 +0.0 + 72 + 1 + 10 +2.21297105273781 + 20 +0.0 + 11 +2.147795531372934 + 21 +0.0 + 72 + 1 + 10 +2.147795531372934 + 20 +0.0 + 11 +2.196547795485895 + 21 +0.1752767944487085 + 72 + 2 + 10 +2.195202176373045 + 20 +0.2879880150203464 + 40 +0.1127192527190687 + 50 +89.31599859402309 + 51 +107.9604459396842 + 73 + 0 + 72 + 2 + 10 +2.187860498124107 + 20 +0.2632664971382323 + 40 +0.0869408911919764 + 50 +108.3817089051841 + 51 +130.5609495896915 + 73 + 0 + 72 + 2 + 10 +2.198002807128255 + 20 +0.2736653212156158 + 40 +0.101440520082671 + 50 +131.0937856248721 + 51 +151.0996267706195 + 73 + 0 + 72 + 2 + 10 +2.251259362016389 + 20 +0.3028621870346081 + 40 +0.1621751716283119 + 50 +151.1623473832895 + 51 +165.7835266974244 + 73 + 0 + 72 + 1 + 10 +2.094050840588399 + 20 +0.2630342184309034 + 11 +2.026516093204943 + 21 +0.5201225784624666 + 72 + 1 + 10 +2.026516093204943 + 20 +0.5201225784624666 + 11 +2.026516093204943 + 21 +0.5201225784624666 + 97 + 1 +330 +89 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C7 +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 23 + 72 + 1 + 10 +2.401085080890193 + 20 +0.451391475175396 + 11 +2.401085080890193 + 21 +0.502049385078848 + 72 + 1 + 10 +2.401085080890193 + 20 +0.502049385078848 + 11 +2.456975906310984 + 21 +0.5208364345932495 + 72 + 1 + 10 +2.456975906310984 + 20 +0.5208364345932495 + 11 +2.471953186325706 + 21 +0.6169178168015124 + 72 + 1 + 10 +2.471953186325706 + 20 +0.6169178168015124 + 11 +2.547828939245814 + 21 +0.6169178168015124 + 72 + 1 + 10 +2.547828939245814 + 20 +0.6169178168015124 + 11 +2.547828939245814 + 21 +0.5208364345932495 + 72 + 1 + 10 +2.547828939245814 + 20 +0.5208364345932495 + 11 +2.625120227777072 + 21 +0.5208364345932495 + 72 + 1 + 10 +2.625120227777072 + 20 +0.5208364345932495 + 11 +2.625120227777072 + 21 +0.451391475175396 + 72 + 1 + 10 +2.625120227777072 + 20 +0.451391475175396 + 11 +2.547828939245814 + 21 +0.451391475175396 + 72 + 1 + 10 +2.547828939245814 + 20 +0.451391475175396 + 11 +2.547828939245814 + 21 +0.312977967787312 + 72 + 2 + 10 +2.756375078424425 + 20 +0.3106349819782397 + 40 +0.208559300317214 + 50 +179.3563172584847 + 51 +187.5204775666663 + 73 + 1 + 72 + 2 + 10 +2.610407599922477 + 20 +0.2901879066221412 + 40 +0.0611824171745163 + 50 +186.4276465021346 + 51 +204.9884326299174 + 73 + 1 + 72 + 2 + 10 +2.591486060141609 + 20 +0.2832478516776391 + 40 +0.0411355950463604 + 50 +207.3607300982318 + 51 +249.4822289731461 + 73 + 1 + 72 + 2 + 10 +2.925871745813213 + 20 +1.236527392855755 + 40 +1.05135264976578 + 50 +250.6239679589966 + 51 +252.369953071448 + 73 + 1 + 72 + 2 + 10 +2.632025513918952 + 20 +0.3027146749676596 + 40 +0.0724554546479011 + 50 +250.172060625216 + 51 +260.9268652271251 + 73 + 1 + 72 + 1 + 10 +2.620599646309214 + 20 +0.2311657933719365 + 11 +2.620599646309214 + 21 +0.1752767944487085 + 72 + 1 + 10 +2.620599646309214 + 20 +0.1752767944487085 + 11 +2.541405756150071 + 21 +0.1752767944487085 + 72 + 2 + 10 +2.539541691321775 + 20 +0.2586536504670411 + 40 +0.0833976909583584 + 50 +88.71924580725035 + 51 +114.8723068619946 + 73 + 0 + 72 + 2 + 10 +2.534259066943731 + 20 +0.2435901096002027 + 40 +0.0675271066805567 + 50 +116.1816665503854 + 51 +146.3117142175992 + 73 + 0 + 72 + 2 + 10 +2.571816472169667 + 20 +0.2671405893161746 + 40 +0.1118470865035182 + 50 +146.9451672649385 + 51 +168.4294027765594 + 73 + 0 + 72 + 2 + 10 +2.701886448180166 + 20 +0.2953352474010394 + 40 +0.2449337665542188 + 50 +168.070822892956 + 51 +180.7890266060776 + 73 + 0 + 72 + 1 + 10 +2.456975906310984 + 20 +0.2987081511619036 + 11 +2.456975906310984 + 21 +0.451391475175396 + 72 + 1 + 10 +2.456975906310984 + 20 +0.451391475175396 + 11 +2.401085080890193 + 21 +0.451391475175396 + 72 + 1 + 10 +2.401085080890193 + 20 +0.451391475175396 + 11 +2.401085080890193 + 21 +0.451391475175396 + 97 + 1 +330 +58 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C8 +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 22 + 72 + 1 + 10 +2.66863653221009 + 20 +0.1752767944487085 + 11 +2.66863653221009 + 21 +0.6839852852251591 + 72 + 1 + 10 +2.66863653221009 + 20 +0.683985285225159 + 11 +2.758774186932835 + 21 +0.683985285225159 + 72 + 1 + 10 +2.758774186932835 + 20 +0.683985285225159 + 11 +2.758774186932835 + 21 +0.4832608134831443 + 72 + 2 + 10 +2.970884692343786 + 20 +0.1949308647558484 + 40 +0.3579455626750722 + 50 +233.6598667174819 + 51 +241.6737203338166 + 73 + 0 + 72 + 2 + 10 +2.862953103918855 + 20 +0.398321949096261 + 40 +0.1277046941848677 + 50 +241.0008951743301 + 51 +256.9710241053807 + 73 + 0 + 72 + 2 + 10 +2.867314180648163 + 20 +0.3596725627348979 + 40 +0.1664021752218955 + 50 +258.5084157090225 + 51 +270.4610700343784 + 73 + 0 + 72 + 2 + 10 +2.871155730201377 + 20 +0.4023028257494028 + 40 +0.1237918213330042 + 50 +268.8416672957483 + 51 +290.1493812176847 + 73 + 0 + 72 + 2 + 10 +2.88549439287798 + 20 +0.4438925273392474 + 40 +0.0798129708700709 + 50 +290.7705399537808 + 51 +319.3693426350027 + 73 + 0 + 72 + 2 + 10 +2.86973875277353 + 20 +0.4329212526250472 + 40 +0.0989334609539707 + 50 +320.4891190671877 + 51 +345.2499775321184 + 73 + 0 + 72 + 2 + 10 +2.778017766714932 + 20 +0.4084074663129932 + 40 +0.1938734483480787 + 50 +345.1454837561613 + 51 +360.9319474711875 + 73 + 0 + 72 + 1 + 10 +2.971865569256112 + 20 +0.4052541467398021 + 11 +2.971865569256112 + 21 +0.1752767944487085 + 72 + 1 + 10 +2.971865569256112 + 20 +0.1752767944487085 + 11 +2.881012536321281 + 21 +0.1752767944487085 + 72 + 1 + 10 +2.881012536321281 + 20 +0.1752767944487085 + 11 +2.881012536321281 + 21 +0.4064428922369056 + 72 + 2 + 10 +2.802613036220481 + 20 +0.4076912084297279 + 40 +0.0784094376294883 + 50 +359.0877849241664 + 51 +374.2114110518409 + 73 + 1 + 72 + 2 + 10 +2.840775464266772 + 20 +0.4174522933113873 + 40 +0.0390186755568009 + 50 +14.07416101436572 + 51 +38.19979694511947 + 73 + 1 + 72 + 2 + 10 +2.848474408609313 + 20 +0.4228438207727886 + 40 +0.0296388733419943 + 50 +39.21298268016682 + 51 +68.21300572178883 + 73 + 1 + 72 + 2 + 10 +2.843635884024977 + 20 +0.4091395078042849 + 40 +0.0441641298463429 + 50 +68.98305490508943 + 51 +91.1922266305568 + 73 + 1 + 72 + 2 + 10 +2.839517556631515 + 20 +0.3257194842430624 + 40 +0.1276147049428117 + 50 +88.56339333889899 + 51 +108.8133720429226 + 73 + 1 + 72 + 2 + 10 +2.853071660183995 + 20 +0.3106172986056333 + 40 +0.146497457591775 + 50 +111.9279820567162 + 51 +129.7021521663467 + 73 + 1 + 72 + 1 + 10 +2.759489565144921 + 20 +0.4233288622047228 + 11 +2.759489565144921 + 21 +0.1752767944487085 + 72 + 1 + 10 +2.759489565144921 + 20 +0.1752767944487085 + 11 +2.66863653221009 + 21 +0.1752767944487085 + 72 + 1 + 10 +2.66863653221009 + 20 +0.1752767944487085 + 11 +2.66863653221009 + 21 +0.1752767944487085 + 97 + 1 +330 +9C + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1C9 +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 2 + 92 + 1 + 93 + 30 + 72 + 2 + 10 +3.480235470402663 + 20 +0.3472963994916086 + 40 +0.4596602087851077 + 50 +179.2201999001178 + 51 +188.5904259084221 + 73 + 0 + 72 + 2 + 10 +3.197121821548028 + 20 +0.3902535820648669 + 40 +0.1733062924357386 + 50 +188.5287545821982 + 51 +206.4053475484388 + 73 + 0 + 72 + 2 + 10 +3.11705169577316 + 20 +0.4290134848926255 + 40 +0.084357328189102 + 50 +207.0116131808711 + 51 +238.088697099355 + 73 + 0 + 72 + 2 + 10 +3.142763881177286 + 20 +0.3846155256577634 + 40 +0.1356468679361114 + 50 +238.7826076590414 + 51 +258.9445942368799 + 73 + 0 + 72 + 2 + 10 +3.174180017272777 + 20 +0.2328628655440478 + 40 +0.2906128032937941 + 50 +258.6028609455173 + 51 +270.7173423227377 + 73 + 0 + 72 + 2 + 10 +3.179378903153711 + 20 +0.2029581738044638 + 40 +0.3204985176522159 + 50 +269.7210247461867 + 51 +277.0776490133664 + 73 + 0 + 72 + 2 + 10 +3.19487528221549 + 20 +0.325267440923209 + 40 +0.1972121016147459 + 50 +276.9881545773719 + 51 +287.1581506174676 + 73 + 0 + 72 + 2 + 10 +3.216601176688156 + 20 +0.3951169191449229 + 40 +0.1240620704779073 + 50 +287.0876504098541 + 51 +300.9508770078876 + 73 + 0 + 72 + 2 + 10 +3.235041042885957 + 20 +0.4262167749073067 + 40 +0.0879070752171545 + 50 +301.0685629566362 + 51 +318.5141019927475 + 73 + 0 + 72 + 2 + 10 +3.22499564771415 + 20 +0.4193627680063226 + 40 +0.0999841621843335 + 50 +319.385148118614 + 51 +335.2909851831404 + 73 + 0 + 72 + 2 + 10 +3.166888025629801 + 20 +0.3924029450769745 + 40 +0.1640411911207218 + 50 +335.2204735203817 + 51 +346.6482421759127 + 73 + 0 + 72 + 2 + 10 +3.055624996630501 + 20 +0.3654957782609082 + 40 +0.2785109168173713 + 50 +346.5482508793785 + 51 +354.5741818072585 + 73 + 0 + 72 + 2 + 10 +2.875033671883636 + 20 +0.3475705203771616 + 40 +0.4599886939454501 + 50 +354.4784226911829 + 51 +360.2208980900725 + 73 + 0 + 72 + 2 + 10 +2.870607305357513 + 20 +0.3438838987998202 + 40 +0.4644155825717984 + 50 +359.7639661566379 + 51 +365.4367125581701 + 73 + 0 + 72 + 2 + 10 +3.058722157859415 + 20 +0.3256690965276672 + 40 +0.2754213630050057 + 50 +5.372287081245953 + 51 +13.41178733975041 + 73 + 0 + 72 + 2 + 10 +3.173279534978716 + 20 +0.2978741757969097 + 40 +0.1575418848528468 + 50 +13.24247481022931 + 51 +24.91433399135224 + 73 + 0 + 72 + 2 + 10 +3.231958966651797 + 20 +0.27049353879938 + 40 +0.0927888674313799 + 50 +24.84449572776762 + 51 +41.46851456153065 + 73 + 0 + 72 + 2 + 10 +3.239204814111471 + 20 +0.2661434323058576 + 40 +0.0844927447051714 + 50 +42.51194694690035 + 51 +60.20982750497873 + 73 + 0 + 72 + 2 + 10 +3.218699140856711 + 20 +0.3022559330899847 + 40 +0.1260208208552961 + 50 +60.27608629427653 + 51 +73.8270512913352 + 73 + 0 + 72 + 2 + 10 +3.195604909472027 + 20 +0.3806255307799783 + 40 +0.207721876247583 + 50 +73.73012549511914 + 51 +83.43439678342133 + 73 + 0 + 72 + 2 + 10 +3.179442499162505 + 20 +0.5160622385854792 + 40 +0.3441188295924385 + 50 +83.33941300651419 + 51 +90.27041510775888 + 73 + 0 + 72 + 2 + 10 +3.176297692891656 + 20 +0.4848041884129171 + 40 +0.3128606426025486 + 50 +89.72150576644664 + 51 +97.22779474957937 + 73 + 0 + 72 + 2 + 10 +3.161234488424673 + 20 +0.3682916110468403 + 40 +0.1953789369211231 + 50 +97.14435294680244 + 51 +107.4227726253624 + 73 + 0 + 72 + 2 + 10 +3.140217093781949 + 20 +0.301699006668967 + 40 +0.1255485308215694 + 50 +107.370753656409 + 51 +121.1811544282885 + 73 + 0 + 72 + 2 + 10 +3.12266212348865 + 20 +0.2723085493673603 + 40 +0.0913151827909786 + 50 +121.3053248468621 + 51 +138.3848687024391 + 73 + 0 + 72 + 2 + 10 +3.130851497778824 + 20 +0.2780987727770228 + 40 +0.1012892502687907 + 50 +139.0126872013657 + 51 +154.2591683716641 + 73 + 0 + 72 + 2 + 10 +3.178025690577206 + 20 +0.3008131945580285 + 40 +0.1536471429745666 + 50 +154.2693808990751 + 51 +165.8118585512815 + 73 + 0 + 72 + 2 + 10 +3.268168571662594 + 20 +0.3240123625755021 + 40 +0.2467269061818614 + 50 +165.7196946403268 + 51 +174.1342043436877 + 73 + 0 + 72 + 2 + 10 +3.413914363535721 + 20 +0.3395635385525735 + 40 +0.3932993037049538 + 50 +174.0504793005304 + 51 +180.2151757775018 + 73 + 0 + 72 + 1 + 10 +3.020617833369073 + 20 +0.3410405807579851 + 11 +3.020617833369073 + 21 +0.3410405807579851 + 97 + 1 +330 +EA + 92 + 16 + 93 + 21 + 72 + 2 + 10 +3.613312704239808 + 20 +0.3052010939876257 + 40 +0.5046836205998101 + 50 +165.4616764010741 + 51 +171.0278758430559 + 73 + 1 + 72 + 2 + 10 +3.374482486528501 + 20 +0.3420916614133984 + 40 +0.2630236606104225 + 50 +170.85201298578 + 51 +179.4517709052564 + 73 + 1 + 72 + 2 + 10 +3.454065240073902 + 20 +0.3382439821810626 + 40 +0.3426534838299237 + 50 +178.9357418182288 + 51 +188.0691336263486 + 73 + 1 + 72 + 2 + 10 +3.195968077288853 + 20 +0.3030278751539043 + 40 +0.0821796951545775 + 50 +189.0181381128171 + 51 +201.4145153112299 + 73 + 1 + 72 + 2 + 10 +3.160411698485469 + 20 +0.2889975802415061 + 40 +0.0439554436806379 + 50 +201.3107480863471 + 51 +220.1489620647889 + 73 + 1 + 72 + 2 + 10 +3.155835095245747 + 20 +0.2843363205812091 + 40 +0.037456749731058 + 50 +219.2127101386138 + 51 +255.6310132773234 + 73 + 1 + 72 + 2 + 10 +3.173261739719343 + 20 +0.3812089223380726 + 40 +0.1358124526943521 + 50 +258.6525891616267 + 51 +271.3702350725942 + 73 + 1 + 72 + 2 + 10 +3.180357139497569 + 20 +0.4692030529375931 + 40 +0.2238008263021876 + 50 +269.0148826539333 + 51 +276.2753625676396 + 73 + 1 + 72 + 2 + 10 +3.197849276399706 + 20 +0.2946920674583943 + 40 +0.0484529004947375 + 50 +278.2717501461559 + 51 +301.2827024261222 + 73 + 1 + 72 + 2 + 10 +3.207811222542081 + 20 +0.2781237012056277 + 40 +0.0291206023535162 + 50 +301.4591386210265 + 51 +342.6827079184772 + 73 + 1 + 72 + 2 + 10 +3.108548338170845 + 20 +0.3127659022243659 + 40 +0.1342419911030445 + 50 +341.1780241039497 + 51 +353.2229122868627 + 73 + 1 + 72 + 2 + 10 +2.967369563098919 + 20 +0.330872680490466 + 40 +0.2765741939881519 + 50 +352.9494162843399 + 51 +360.3822505868774 + 73 + 1 + 72 + 2 + 10 +2.459318552711379 + 20 +0.3411691780724464 + 40 +0.7846645638024574 + 50 +359.3828759745628 + 51 +363.6573187603909 + 73 + 1 + 72 + 2 + 10 +3.092761679710313 + 20 +0.3811941386031558 + 40 +0.1499590652226746 + 50 +3.834298057691928 + 51 +15.98721166096461 + 73 + 1 + 72 + 2 + 10 +3.208394130760695 + 20 +0.4156549366241278 + 40 +0.029335563761804 + 50 +13.48613242730889 + 51 +56.84075856181601 + 73 + 1 + 72 + 2 + 10 +3.195154229476923 + 20 +0.3942423008569769 + 40 +0.0545066495896497 + 50 +57.50110974384233 + 51 +77.84457056043473 + 73 + 1 + 72 + 2 + 10 +3.184009922966737 + 20 +0.344171085093621 + 40 +0.1058024453263516 + 50 +77.65436364628005 + 51 +90.71531793927198 + 73 + 1 + 72 + 2 + 10 +3.180978125261934 + 20 +0.1670204385423348 + 40 +0.2829500192598661 + 50 +89.65354521146901 + 51 +94.33326617565109 + 73 + 1 + 72 + 2 + 10 +3.165070616561166 + 20 +0.3644786832754941 + 40 +0.084859522413094 + 50 +93.69685967486203 + 51 +104.1770246546857 + 73 + 1 + 72 + 2 + 10 +3.15468956905426 + 20 +0.4128867508985087 + 40 +0.0354285831761041 + 50 +107.0749560136262 + 51 +147.5612347538681 + 73 + 1 + 72 + 1 + 10 +3.124789077699108 + 20 +0.4318905695302117 + 11 +3.124789077699108 + 21 +0.4318905695302117 + 97 + 1 +330 +121 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +HATCH + 5 +1CA +330 +1D +100 +AcDbEntity + 8 +TEXT-RED +100 +AcDbHatch + 10 +0.0 + 20 +0.0 + 30 +0.0 +210 +0.0 +220 +0.0 +230 +1.0 + 2 +SOLID + 70 + 1 + 71 + 1 + 91 + 1 + 92 + 1 + 93 + 22 + 72 + 2 + 10 +3.592005824568463 + 20 +0.4022623702532142 + 40 +0.1238324225952604 + 50 +268.8385251676425 + 51 +290.1462390895788 + 73 + 0 + 72 + 2 + 10 +3.606344487245067 + 20 +0.4439223854568978 + 40 +0.0797877541011788 + 50 +290.7832534290268 + 51 +319.3820561102488 + 73 + 0 + 72 + 2 + 10 +3.590581236734105 + 20 +0.4329212526250472 + 40 +0.0989334609539707 + 50 +320.4891190671877 + 51 +345.2499775321184 + 73 + 0 + 72 + 2 + 10 +3.498860250675552 + 20 +0.4084074663130021 + 40 +0.1938734483480326 + 50 +345.1454837561604 + 51 +360.9319474711903 + 73 + 0 + 72 + 1 + 10 +3.692708053216686 + 20 +0.4052541467398021 + 11 +3.692708053216686 + 21 +0.1752767944487085 + 72 + 1 + 10 +3.692708053216686 + 20 +0.1752767944487085 + 11 +3.601870241094878 + 21 +0.1752767944487085 + 72 + 1 + 10 +3.601870241094878 + 20 +0.1752767944487085 + 11 +3.601870241094878 + 21 +0.4064428922369056 + 72 + 2 + 10 +3.523463130587567 + 20 +0.4076338796510298 + 40 +0.0784161554089863 + 50 +359.1297561618085 + 51 +374.2533822894829 + 73 + 1 + 72 + 2 + 10 +3.561625558633858 + 20 +0.4174879054254667 + 40 +0.0390026472343202 + 50 +14.02613509500026 + 51 +38.15177102575402 + 73 + 1 + 72 + 2 + 10 +3.569324502976398 + 20 +0.4228143935386817 + 40 +0.029663379390137 + 50 +39.24772886833219 + 51 +68.2477519099542 + 73 + 1 + 72 + 2 + 10 +3.564485978392062 + 20 +0.4091782819430569 + 40 +0.0441252062777969 + 50 +68.97422263922098 + 51 +91.18339436468834 + 73 + 1 + 72 + 2 + 10 +3.560375261405112 + 20 +0.3257194842430623 + 40 +0.1276147049428117 + 50 +88.56339333889899 + 51 +108.8133720429226 + 73 + 1 + 72 + 2 + 10 +3.573921754551081 + 20 +0.3105686277924473 + 40 +0.1465397674015583 + 50 +111.9181151967782 + 51 +129.6922853064086 + 73 + 1 + 72 + 1 + 10 +3.480332049105495 + 20 +0.4233288622047228 + 11 +3.480332049105495 + 21 +0.1752767944487085 + 72 + 1 + 10 +3.480332049105495 + 20 +0.1752767944487085 + 11 +3.389479016170664 + 21 +0.1752767944487085 + 72 + 1 + 10 +3.389479016170664 + 20 +0.1752767944487085 + 11 +3.389479016170664 + 21 +0.5201225784624666 + 72 + 1 + 10 +3.389479016170664 + 20 +0.5201225784624666 + 11 +3.462264944047086 + 21 +0.5201225784624666 + 72 + 1 + 10 +3.462264944047086 + 20 +0.5201225784624666 + 11 +3.480332049105495 + 21 +0.4832608134831443 + 72 + 2 + 10 +3.692032830344103 + 20 +0.1968176418438357 + 40 +0.3561838168078713 + 50 +233.5331050519283 + 51 +241.6403323622616 + 73 + 0 + 72 + 2 + 10 +3.581912438010629 + 20 +0.4042431550954748 + 40 +0.1213560014894028 + 50 +240.8735520743203 + 51 +257.5360464861715 + 73 + 0 + 72 + 2 + 10 +3.587849834142919 + 20 +0.3698286725878678 + 40 +0.1562493464094038 + 50 +258.1337893490277 + 51 +270.603548530042 + 73 + 0 + 72 + 1 + 10 +3.589495720107105 + 20 +0.5260693501105883 + 11 +3.589495720107105 + 21 +0.5260693501105883 + 97 + 1 +330 +71 + 75 + 0 + 76 + 1 + 98 + 1 + 10 +-0.0349603810164775 + 20 +0.1524455749140718 +1001 +ACAD +1010 +0.0 +1020 +0.0 +1030 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_DETAILVIEWSTYLE +350 +1D4 + 3 +ACAD_GROUP +350 +D + 3 +ACAD_IMAGE_VARS +350 +1B2 + 3 +ACAD_LAYOUT +350 +1A + 3 +ACAD_MLINESTYLE +350 +17 + 3 +ACAD_PLOTSETTINGS +350 +19 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +ACAD_SCALELIST +350 +16B + 3 +ACAD_SECTIONVIEWSTYLE +350 +1D5 + 3 +AcDbVariableDictionary +350 +1CF + 3 +APPDATA +350 +1B0 + 3 +DWGPROPS +350 +1D6 + 0 +DICTIONARY + 5 +1B3 +330 +2 +100 +AcDbDictionary +280 + 1 +281 + 1 + 3 +ACAD_LAYERSTATES +360 +1B4 + 3 +ACLYDICTIONARY +360 +1BB + 0 +DICTIONARY + 5 +1D4 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +D +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +RASTERVARIABLES + 5 +1B2 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbRasterVariables + 90 + 0 + 70 + 1 + 71 + 1 + 72 + 0 + 0 +DICTIONARY + 5 +1A +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Model +350 +1E + 3 +Sheet 1 +350 +1C + 0 +DICTIONARY + 5 +17 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Standard +350 +18 + 0 +DICTIONARY + 5 +19 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +DICTIONARY + 5 +16B +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 3 +A0 +350 +16C + 3 +A1 +350 +16D + 3 +A2 +350 +16E + 3 +A3 +350 +16F + 3 +A4 +350 +170 + 3 +A5 +350 +171 + 3 +A6 +350 +172 + 3 +A7 +350 +173 + 3 +A8 +350 +174 + 3 +A9 +350 +175 + 3 +B0 +350 +176 + 3 +B1 +350 +177 + 3 +B2 +350 +178 + 3 +B3 +350 +179 + 3 +B4 +350 +17A + 3 +B5 +350 +17B + 3 +B6 +350 +17C + 3 +B7 +350 +17D + 3 +B8 +350 +17E + 3 +B9 +350 +17F + 3 +C0 +350 +180 + 3 +C1 +350 +181 + 3 +C2 +350 +182 + 3 +C3 +350 +183 + 3 +C4 +350 +184 + 3 +C5 +350 +185 + 3 +C6 +350 +186 + 3 +C7 +350 +187 + 3 +C8 +350 +188 + 3 +C9 +350 +189 + 3 +D0 +350 +18A + 3 +D1 +350 +18B + 3 +D2 +350 +18C + 0 +DICTIONARY + 5 +1D5 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +1CF +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +DICTIONARY + 5 +1B0 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbDictionary +281 + 1 + 0 +XRECORD + 5 +1D6 +102 +{ACAD_REACTORS +330 +C +102 +} +330 +C +100 +AcDbXrecord +280 + 1 + 1 +DWGPROPS COOKIE + 2 +vector-text + 3 + + 4 +Jonathan Greig + 6 +Generated outlines with CNCFontFab using the "Exo Bold" font. + 7 +MicroPython Text + 8 + + 9 + +300 += +301 += +302 += +303 += +304 += +305 += +306 += +307 += +308 += +309 += + 40 +0.0 + 41 +2456662.519745903 + 42 +2456662.532164352 + 1 + + 90 + 0 + 0 +DICTIONARY + 5 +1B4 +102 +{ACAD_REACTORS +330 +1B3 +102 +} +330 +1B3 +100 +AcDbDictionary +281 + 1 + 3 +ARGON_LAYERP_1 +350 +1B5 + 3 +ARGON_LAYERP_2 +350 +1B8 + 3 +ARGON_LAYERP_3 +350 +1C3 + 0 +DICTIONARY + 5 +1BB +102 +{ACAD_REACTORS +330 +1B3 +102 +} +330 +1B3 +100 +AcDbDictionary +281 + 1 +1001 +ACAD +1000 + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/mpy-cross/Makefile b/src/openmv/src/micropython/mpy-cross/Makefile new file mode 100755 index 0000000..c42c2c5 --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/Makefile @@ -0,0 +1,76 @@ +# The following is a temporary hack to forefully undefine vars that might have +# be defined by a calling Makefile (from recursive make). +# TODO: Find a better way to be able to call this Makefile recursively. +ifneq ($(findstring undefine,$(.FEATURES)),) +override undefine COPT +override undefine CFLAGS_EXTRA +override undefine LDFLAGS_EXTRA +override undefine MICROPY_FORCE_32BIT +override undefine CROSS_COMPILE +override undefine FROZEN_DIR +override undefine FROZEN_MPY_DIR +override undefine BUILD +override undefine PROG +endif + +include ../py/mkenv.mk + +# define main target +PROG = mpy-cross + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# OS name, for simple autoconfig +UNAME_S := $(shell uname -s) + +# include py core make definitions +include $(TOP)/py/py.mk + +INC += -I. +INC += -I$(BUILD) +INC += -I$(TOP) + +# compiler settings +CWARN = -Wall -Werror +CWARN += -Wpointer-arith -Wuninitialized +CFLAGS = $(INC) $(CWARN) -std=gnu99 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) +CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables + +# Debugging/Optimization +ifdef DEBUG +CFLAGS += -g +COPT = -O0 +else +COPT = -Os #-DNDEBUG +endif + +# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. +# The unix port of MicroPython on OSX must be compiled with clang, +# while cross-compile ports require gcc, so we test here for OSX and +# if necessary override the value of 'CC' set in py/mkenv.mk +ifeq ($(UNAME_S),Darwin) +CC = clang +# Use clang syntax for map file +LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip +else +# Use gcc syntax for map file +LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections +endif +LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) + +# source files +SRC_C = \ + main.c \ + gccollect.c \ + +# Add fmode when compiling with mingw gcc +COMPILER_TARGET := $(shell $(CC) -dumpmachine) +ifneq (,$(findstring mingw,$(COMPILER_TARGET))) + SRC_C += ports/windows/fmode.c +endif + +OBJ = $(PY_CORE_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/mpy-cross/README.md b/src/openmv/src/micropython/mpy-cross/README.md new file mode 100755 index 0000000..e35b28b --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/README.md @@ -0,0 +1,25 @@ +MicroPython cross compiler +========================== + +This directory contains the MicroPython cross compiler, which runs under any +Unix-like system and compiles .py scripts into .mpy files. + +Build it as usual: + + $ make + +The compiler is called `mpy-cross`. Invoke it as: + + $ ./mpy-cross foo.py + +This will create a file foo.mpy which can then be copied to a place accessible +by the target MicroPython runtime (eg onto a pyboard's filesystem), and then +imported like any other Python module using `import foo`. + +Different target runtimes may require a different format of the compiled +bytecode, and such options can be passed to the cross compiler. For example, +the unix port of MicroPython requires the following: + + $ ./mpy-cross -mcache-lookup-bc foo.py + +Run `./mpy-cross -h` to get a full list of options. diff --git a/src/openmv/src/micropython/mpy-cross/gccollect.c b/src/openmv/src/micropython/mpy-cross/gccollect.c new file mode 100755 index 0000000..75891a2 --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/gccollect.c @@ -0,0 +1,152 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpstate.h" +#include "py/gc.h" + +#if MICROPY_ENABLE_GC + +// Even if we have specific support for an architecture, it is +// possible to force use of setjmp-based implementation. +#if !MICROPY_GCREGS_SETJMP + +// We capture here callee-save registers, i.e. ones which may contain +// interesting values held there by our callers. It doesn't make sense +// to capture caller-saved registers, because they, well, put on the +// stack already by the caller. +#if defined(__x86_64__) +typedef mp_uint_t regs_t[6]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long rbx asm ("rbx"); + register long rbp asm ("rbp"); + register long r12 asm ("r12"); + register long r13 asm ("r13"); + register long r14 asm ("r14"); + register long r15 asm ("r15"); +#ifdef __clang__ + // TODO: + // This is dirty workaround for Clang. It tries to get around + // uncompliant (wrt to GCC) behavior of handling register variables. + // Application of this patch here is random, and done only to unbreak + // MacOS build. Better, cross-arch ways to deal with Clang issues should + // be found. + asm("" : "=r"(rbx)); + asm("" : "=r"(rbp)); + asm("" : "=r"(r12)); + asm("" : "=r"(r13)); + asm("" : "=r"(r14)); + asm("" : "=r"(r15)); +#endif + arr[0] = rbx; + arr[1] = rbp; + arr[2] = r12; + arr[3] = r13; + arr[4] = r14; + arr[5] = r15; +} + +#elif defined(__i386__) + +typedef mp_uint_t regs_t[4]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long ebx asm ("ebx"); + register long esi asm ("esi"); + register long edi asm ("edi"); + register long ebp asm ("ebp"); + arr[0] = ebx; + arr[1] = esi; + arr[2] = edi; + arr[3] = ebp; +} + +#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) + +typedef mp_uint_t regs_t[10]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long r4 asm ("r4"); + register long r5 asm ("r5"); + register long r6 asm ("r6"); + register long r7 asm ("r7"); + register long r8 asm ("r8"); + register long r9 asm ("r9"); + register long r10 asm ("r10"); + register long r11 asm ("r11"); + register long r12 asm ("r12"); + register long r13 asm ("r13"); + arr[0] = r4; + arr[1] = r5; + arr[2] = r6; + arr[3] = r7; + arr[4] = r8; + arr[5] = r9; + arr[6] = r10; + arr[7] = r11; + arr[8] = r12; + arr[9] = r13; +} + +#else + +// If we don't have architecture-specific optimized support, +// just fall back to setjmp-based implementation. +#undef MICROPY_GCREGS_SETJMP +#define MICROPY_GCREGS_SETJMP (1) + +#endif // Arch-specific selection +#endif // !MICROPY_GCREGS_SETJMP + +// If MICROPY_GCREGS_SETJMP was requested explicitly, or if +// we enabled it as a fallback above. +#if MICROPY_GCREGS_SETJMP +#include + +typedef jmp_buf regs_t; + +STATIC void gc_helper_get_regs(regs_t arr) { + setjmp(arr); +} + +#endif // MICROPY_GCREGS_SETJMP + +void gc_collect(void) { + gc_collect_start(); + regs_t regs; + gc_helper_get_regs(regs); + // GC stack (and regs because we captured them) + void **regs_ptr = (void**)(void*)®s; + gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t)); + #if MICROPY_EMIT_NATIVE + mp_unix_mark_exec(); + #endif + gc_collect_end(); +} + +#endif //MICROPY_ENABLE_GC diff --git a/src/openmv/src/micropython/mpy-cross/main.c b/src/openmv/src/micropython/mpy-cross/main.c new file mode 100755 index 0000000..d819f74 --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/main.c @@ -0,0 +1,286 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/compile.h" +#include "py/persistentcode.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/stackctrl.h" +#ifdef _WIN32 +#include "ports/windows/fmode.h" +#endif + +// Command line options, with their defaults +STATIC uint emit_opt = MP_EMIT_OPT_NONE; +mp_uint_t mp_verbose_flag = 0; + +// Heap size of GC heap (if enabled) +// Make it larger on a 64 bit machine, because pointers are larger. +long heap_size = 1024*1024 * (sizeof(mp_uint_t) / 4); + +STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) { + (void)env; + ssize_t dummy = write(STDERR_FILENO, str, len); + (void)dummy; +} + +STATIC const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; + +STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_file(file); + + qstr source_name; + if (source_file == NULL) { + source_name = lex->source_name; + } else { + source_name = qstr_from_str(source_file); + } + + #if MICROPY_PY___FILE__ + if (input_kind == MP_PARSE_FILE_INPUT) { + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + } + #endif + + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, emit_opt, false); + + vstr_t vstr; + vstr_init(&vstr, 16); + if (output_file == NULL) { + vstr_add_str(&vstr, file); + vstr_cut_tail_bytes(&vstr, 2); + vstr_add_str(&vstr, "mpy"); + } else { + vstr_add_str(&vstr, output_file); + } + mp_raw_code_save_file(rc, vstr_null_terminated_str(&vstr)); + vstr_clear(&vstr); + + nlr_pop(); + return 0; + } else { + // uncaught exception + mp_obj_print_exception(&mp_stderr_print, (mp_obj_t)nlr.ret_val); + return 1; + } +} + +STATIC int usage(char **argv) { + printf( +"usage: %s [] [-X ] \n" +"Options:\n" +"-o : output file for compiled bytecode (defaults to input with .mpy extension)\n" +"-s : source filename to embed in the compiled bytecode (defaults to input file)\n" +"-v : verbose (trace various operations); can be multiple\n" +"-O[N] : apply bytecode optimizations of level N\n" +"\n" +"Target specific options:\n" +"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" +"-mno-unicode : don't support unicode in compiled strings\n" +"-mcache-lookup-bc : cache map lookups in the bytecode\n" +"\n" +"Implementation specific options:\n", argv[0] +); + int impl_opts_cnt = 0; + printf( +" emit={bytecode,native,viper} -- set the default code emitter\n" +); + impl_opts_cnt++; + printf( +" heapsize= -- set the heap size for the GC (default %ld)\n" +, heap_size); + impl_opts_cnt++; + + if (impl_opts_cnt == 0) { + printf(" (none)\n"); + } + + return 1; +} + +// Process options which set interpreter init options +STATIC void pre_process_options(int argc, char **argv) { + for (int a = 1; a < argc; a++) { + if (argv[a][0] == '-') { + if (strcmp(argv[a], "-X") == 0) { + if (a + 1 >= argc) { + exit(usage(argv)); + } + if (strcmp(argv[a + 1], "emit=bytecode") == 0) { + emit_opt = MP_EMIT_OPT_BYTECODE; + } else if (strcmp(argv[a + 1], "emit=native") == 0) { + emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; + } else if (strcmp(argv[a + 1], "emit=viper") == 0) { + emit_opt = MP_EMIT_OPT_VIPER; + } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { + char *end; + heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0); + // Don't bring unneeded libc dependencies like tolower() + // If there's 'w' immediately after number, adjust it for + // target word size. Note that it should be *before* size + // suffix like K or M, to avoid confusion with kilowords, + // etc. the size is still in bytes, just can be adjusted + // for word size (taking 32bit as baseline). + bool word_adjust = false; + if ((*end | 0x20) == 'w') { + word_adjust = true; + end++; + } + if ((*end | 0x20) == 'k') { + heap_size *= 1024; + } else if ((*end | 0x20) == 'm') { + heap_size *= 1024 * 1024; + } + if (word_adjust) { + heap_size = heap_size * BYTES_PER_WORD / 4; + } + } else { + exit(usage(argv)); + } + a++; + } + } + } +} + +MP_NOINLINE int main_(int argc, char **argv) { + mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + + pre_process_options(argc, argv); + + char *heap = malloc(heap_size); + gc_init(heap, heap + heap_size); + + mp_init(); +#ifdef _WIN32 + set_fmode_binary(); +#endif + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + // set default compiler configuration + mp_dynamic_compiler.small_int_bits = 31; + mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; + mp_dynamic_compiler.py_builtins_str_unicode = 1; + + const char *input_file = NULL; + const char *output_file = NULL; + const char *source_file = NULL; + + // parse main options + for (int a = 1; a < argc; a++) { + if (argv[a][0] == '-') { + if (strcmp(argv[a], "-X") == 0) { + a += 1; + } else if (strcmp(argv[a], "-v") == 0) { + mp_verbose_flag++; + } else if (strncmp(argv[a], "-O", 2) == 0) { + if (unichar_isdigit(argv[a][2])) { + MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf; + } else { + MP_STATE_VM(mp_optimise_value) = 0; + for (char *p = argv[a] + 1; *p && *p == 'O'; p++, MP_STATE_VM(mp_optimise_value)++); + } + } else if (strcmp(argv[a], "-o") == 0) { + if (a + 1 >= argc) { + exit(usage(argv)); + } + a += 1; + output_file = argv[a]; + } else if (strcmp(argv[a], "-s") == 0) { + if (a + 1 >= argc) { + exit(usage(argv)); + } + a += 1; + source_file = argv[a]; + } else if (strncmp(argv[a], "-msmall-int-bits=", sizeof("-msmall-int-bits=") - 1) == 0) { + char *end; + mp_dynamic_compiler.small_int_bits = + strtol(argv[a] + sizeof("-msmall-int-bits=") - 1, &end, 0); + if (*end) { + return usage(argv); + } + // TODO check that small_int_bits is within range of host's capabilities + } else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) { + mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; + } else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) { + mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1; + } else if (strcmp(argv[a], "-mno-unicode") == 0) { + mp_dynamic_compiler.py_builtins_str_unicode = 0; + } else if (strcmp(argv[a], "-municode") == 0) { + mp_dynamic_compiler.py_builtins_str_unicode = 1; + } else { + return usage(argv); + } + } else { + if (input_file != NULL) { + mp_printf(&mp_stderr_print, "multiple input files\n"); + exit(1); + } + input_file = argv[a]; + } + } + + if (input_file == NULL) { + mp_printf(&mp_stderr_print, "no input file\n"); + exit(1); + } + + int ret = compile_and_save(input_file, output_file, source_file); + + #if MICROPY_PY_MICROPYTHON_MEM_INFO + if (mp_verbose_flag) { + mp_micropython_mem_info(0, NULL); + } + #endif + + mp_deinit(); + + return ret & 0xff; +} + +int main(int argc, char **argv) { + mp_stack_ctrl_init(); + return main_(argc, argv); +} + +uint mp_import_stat(const char *path) { + (void)path; + return MP_IMPORT_STAT_NO_EXIST; +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught NLR %p\n", val); + exit(1); +} diff --git a/src/openmv/src/micropython/mpy-cross/mpconfigport.h b/src/openmv/src/micropython/mpy-cross/mpconfigport.h new file mode 100755 index 0000000..e227d1b --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/mpconfigport.h @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_PERSISTENT_CODE_SAVE (1) + +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_X86 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) +#define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) +#define MICROPY_EMIT_ARM (0) + +#define MICROPY_DYNAMIC_COMPILER (1) +#define MICROPY_COMP_CONST_FOLDING (1) +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_RETURN_IF_EXPR (1) + +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) + +#define MICROPY_READER_POSIX (1) +#define MICROPY_ENABLE_RUNTIME (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_WARNINGS (1) + +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) + +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) + +// Define to 1 to use undertested inefficient GC helper implementation +// (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP + #ifdef __mips__ + #define MICROPY_GCREGS_SETJMP (1) + #else + #define MICROPY_GCREGS_SETJMP (0) + #endif +#endif + +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_SYS (0) + +// type definitions for the specific machine + +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#elif defined ( __MINGW32__ ) && defined( _WIN64 ) +#include +typedef __int64 mp_int_t; +typedef unsigned __int64 mp_uint_t; +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +#define MP_PLAT_PRINT_STRN(str, len) (void)0 + +#ifndef MP_NOINLINE +#define MP_NOINLINE __attribute__((noinline)) +#endif + +// We need to provide a declaration/definition of alloca() +#ifdef __FreeBSD__ +#include +#elif defined( _WIN32 ) +#include +#else +#include +#endif + +#include diff --git a/src/openmv/src/micropython/mpy-cross/mphalport.h b/src/openmv/src/micropython/mpy-cross/mphalport.h new file mode 100755 index 0000000..3835928 --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/mphalport.h @@ -0,0 +1,2 @@ +// prevent including extmod/virtpin.h +#define mp_hal_pin_obj_t diff --git a/src/openmv/src/micropython/mpy-cross/qstrdefsport.h b/src/openmv/src/micropython/mpy-cross/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/mpy-cross/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/bare-arm/Makefile b/src/openmv/src/micropython/ports/bare-arm/Makefile new file mode 100755 index 0000000..a515db8 --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/Makefile @@ -0,0 +1,48 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion +CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) + +#Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -O0 -ggdb +else +CFLAGS += -Os -DNDEBUG +endif + +LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref +LIBS = + +SRC_C = \ + main.c \ +# printf.c \ + string0.c \ + malloc0.c \ + gccollect.c \ + +SRC_S = \ +# startup_stm32f40xx.s \ + gchelper.s \ + +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) + +all: $(BUILD)/firmware.elf + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/bare-arm/main.c b/src/openmv/src/micropython/ports/bare-arm/main.c new file mode 100755 index 0000000..b96fb47 --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/main.c @@ -0,0 +1,96 @@ +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/mperrno.h" + +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + +int main(int argc, char **argv) { + mp_init(); + do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT); + do_str("for i in range(10):\n print(i)", MP_PARSE_FILE_INPUT); + mp_deinit(); + return 0; +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + while (1); +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif + +/* +int _lseek() {return 0;} +int _read() {return 0;} +int _write() {return 0;} +int _close() {return 0;} +void _exit(int x) {for(;;){}} +int _sbrk() {return 0;} +int _kill() {return 0;} +int _getpid() {return 0;} +int _fstat() {return 0;} +int _isatty() {return 0;} +*/ + +void *malloc(size_t n) {return NULL;} +void *calloc(size_t nmemb, size_t size) {return NULL;} +void *realloc(void *ptr, size_t size) {return NULL;} +void free(void *p) {} +int printf(const char *m, ...) {return 0;} +void *memcpy(void *dest, const void *src, size_t n) {return NULL;} +int memcmp(const void *s1, const void *s2, size_t n) {return 0;} +void *memmove(void *dest, const void *src, size_t n) {return NULL;} +void *memset(void *s, int c, size_t n) {return NULL;} +int strcmp(const char *s1, const char* s2) {return 0;} +int strncmp(const char *s1, const char* s2, size_t n) {return 0;} +size_t strlen(const char *s) {return 0;} +char *strcat(char *dest, const char *src) {return NULL;} +char *strchr(const char *dest, int c) {return NULL;} +#include +int vprintf(const char *format, va_list ap) {return 0;} +int vsnprintf(char *str, size_t size, const char *format, va_list ap) {return 0;} + +#undef putchar +int putchar(int c) {return 0;} +int puts(const char *s) {return 0;} + +void _start(void) {main(0, NULL);} diff --git a/src/openmv/src/micropython/ports/bare-arm/mpconfigport.h b/src/openmv/src/micropython/ports/bare-arm/mpconfigport.h new file mode 100755 index 0000000..22d8e2f --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/mpconfigport.h @@ -0,0 +1,68 @@ +#include + +// options to control how MicroPython is built + +#define MICROPY_QSTR_BYTES_IN_HASH (1) +#define MICROPY_ALLOC_PATH_MAX (512) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (0) +#define MICROPY_HELPER_REPL (0) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (0) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_USE_INTERNAL_PRINTF (0) + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +#define UINT_FMT "%lu" +#define INT_FMT "%ld" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; + +// dummy print +#define MP_PLAT_PRINT_STRN(str, len) (void)0 + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// We need to provide a declaration/definition of alloca() +#include diff --git a/src/openmv/src/micropython/ports/bare-arm/mphalport.h b/src/openmv/src/micropython/ports/bare-arm/mphalport.h new file mode 100755 index 0000000..4bd8276 --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/mphalport.h @@ -0,0 +1 @@ +// empty file diff --git a/src/openmv/src/micropython/ports/bare-arm/qstrdefsport.h b/src/openmv/src/micropython/ports/bare-arm/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/bare-arm/stm32f405.ld b/src/openmv/src/micropython/ports/bare-arm/stm32f405.ld new file mode 100755 index 0000000..dd688a0 --- /dev/null +++ b/src/openmv/src/micropython/ports/bare-arm/stm32f405.ld @@ -0,0 +1,117 @@ +/* + GNU linker script for STM32F405 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */ + CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */ +} + +/* top end of the stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_end = 0x2001c000; /* tunable */ + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH_ISR + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ + } >FLASH_TEXT + + /* + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } >FLASH + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + */ + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + _ram_start = .; /* create a global symbol at ram start for garbage collector */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + _heap_start = .; /* define a global symbol at heap start */ + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + } >RAM + + /* Remove information from the standard libraries */ + /* + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + */ + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/FreeRTOSConfig.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/FreeRTOSConfig.h new file mode 100755 index 0000000..2f25bbd --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/FreeRTOSConfig.h @@ -0,0 +1,173 @@ +/* + FreeRTOS V8.1.2 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 1 +#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) +#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( \ + 16384 /* 16kbytes for FreeRTOS data structures and heap */ \ + - sizeof(StaticTask_t) - configMINIMAL_STACK_SIZE * sizeof(StackType_t) /* TCB+stack for idle task */ \ + - sizeof(StaticTask_t) - 1024 /* TCB+stack for servers task */ \ + - sizeof(StaticTask_t) - 6656 /* TCB+stack for main MicroPython task */ \ + - sizeof(StaticTask_t) - 896 /* TCB+stack for simplelink spawn task */ \ + ) ) +#define configMAX_TASK_NAME_LEN ( 8 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 0 +#define configUSE_RECURSIVE_MUTEXES 0 +#ifdef DEBUG +#define configCHECK_FOR_STACK_OVERFLOW 1 +#else +#define configCHECK_FOR_STACK_OVERFLOW 0 +#endif +#define configUSE_QUEUE_SETS 0 +#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_ALTERNATIVE_API 0 + +#define configMAX_PRIORITIES ( 4UL ) +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) +#define configQUEUE_REGISTRY_SIZE 0 + +/* Timer related defines. */ +#define configUSE_TIMERS 0 +#define configTIMER_TASK_PRIORITY 2 +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) +#ifdef DEBUG +#define configUSE_MALLOC_FAILED_HOOK 1 +#else +#define configUSE_MALLOC_FAILED_HOOK 0 +#endif +#define configENABLE_BACKWARD_COMPATIBILITY 0 +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_vTaskDelayUntil 0 +#define INCLUDE_vTaskDelay 1 +#ifdef DEBUG +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#else +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#endif +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#ifdef DEBUG +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#else +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#endif +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xSemaphoreGetMutexHolder 0 + +#define configKERNEL_INTERRUPT_PRIORITY ( 7 << 5 ) /* Priority 7, or 255 as only the top three bits are implemented. This is the lowest priority. */ +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 1 << 5 ) /* Priority 5, or 160 as only the top three bits are implemented. */ + +/* Use the Cortex-M3 optimised task selection rather than the generic C code +version. */ +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 + +/* We provide a definition of ucHeap so it can go in a special segment. */ +#define configAPPLICATION_ALLOCATED_HEAP 1 + +/* We use static versions of functions (like xTaskCreateStatic) */ +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* For threading */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#undef configUSE_MUTEXES +#define configUSE_MUTEXES 1 +#undef INCLUDE_vTaskDelete +#define INCLUDE_vTaskDelete 1 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/License/license.txt b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/License/license.txt new file mode 100755 index 0000000..5d243b8 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/License/license.txt @@ -0,0 +1,399 @@ +The FreeRTOS open source license covers the FreeRTOS source files, +which are located in the /FreeRTOS/Source directory of the official FreeRTOS +download. It also covers most of the source files in the demo application +projects, which are located in the /FreeRTOS/Demo directory of the official +FreeRTOS download. The demo projects may also include third party software that +is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of +third party software includes header files provided by chip or tools vendors, +linker scripts, peripheral drivers, etc. All the software in subdirectories of +the /FreeRTOS directory is either open source or distributed with permission, +and is free for use. For the avoidance of doubt, refer to the comments at the +top of each source file. + +---------------------------------------------------------------------------- + +NOTE: The modification to the GPL is included to allow you to distribute a +combined work that includes FreeRTOS without being obliged to provide the source +code for proprietary components. + +---------------------------------------------------------------------------- + +Applying to FreeRTOS V8.2.3 up to the latest version, the FreeRTOS GPL Exception +Text follows: + +Any FreeRTOS *source code*, whether modified or in it's original release form, +or whether in whole or in part, can only be distributed by you under the terms +of the GNU General Public License plus this exception. An independent module is +a module which is not derived from or based on FreeRTOS. + +Clause 1: + +Linking FreeRTOS with other modules is making a combined work based on FreeRTOS. +Thus, the terms and conditions of the GNU General Public License V2 cover the +whole combination. + +As a special exception, the copyright holders of FreeRTOS give you permission to +link FreeRTOS with independent modules to produce a statically linked +executable, regardless of the license terms of these independent modules, and to +copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms and +conditions of the license of that module. An independent module is a module +which is not derived from or based on FreeRTOS. + +Clause 2: + +FreeRTOS may not be used for any competitive or comparative purpose, including +the publication of any form of run time or compile time metric, without the +express permission of Real Time Engineers Ltd. (this is the norm within the +industry and is intended to ensure information accuracy). + + + +-------------------------------------------------------------------- + + + +The standard GPL V2 text: + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/croutine.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/croutine.c new file mode 100755 index 0000000..993e09b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/croutine.c @@ -0,0 +1,395 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include "FreeRTOS.h" +#include "task.h" +#include "croutine.h" + +/* Remove the whole file is co-routines are not being used. */ +#if( configUSE_CO_ROUTINES != 0 ) + +/* + * Some kernel aware debuggers require data to be viewed to be global, rather + * than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + + +/* Lists for ready and blocked co-routines. --------------------*/ +static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */ +static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */ +static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ +static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */ +static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ +static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ + +/* Other file private variables. --------------------------------*/ +CRCB_t * pxCurrentCoRoutine = NULL; +static UBaseType_t uxTopCoRoutineReadyPriority = 0; +static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0; + +/* The initial state of the co-routine when it is created. */ +#define corINITIAL_STATE ( 0 ) + +/* + * Place the co-routine represented by pxCRCB into the appropriate ready queue + * for the priority. It is inserted at the end of the list. + * + * This macro accesses the co-routine ready lists and therefore must not be + * used from within an ISR. + */ +#define prvAddCoRoutineToReadyQueue( pxCRCB ) \ +{ \ + if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \ + { \ + uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \ + } \ + vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \ +} + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first co-routine. + */ +static void prvInitialiseCoRoutineLists( void ); + +/* + * Co-routines that are readied by an interrupt cannot be placed directly into + * the ready lists (there is no mutual exclusion). Instead they are placed in + * in the pending ready list in order that they can later be moved to the ready + * list by the co-routine scheduler. + */ +static void prvCheckPendingReadyList( void ); + +/* + * Macro that looks at the list of co-routines that are currently delayed to + * see if any require waking. + * + * Co-routines are stored in the queue in the order of their wake time - + * meaning once one co-routine has been found whose timer has not expired + * we need not look any further down the list. + */ +static void prvCheckDelayedList( void ); + +/*-----------------------------------------------------------*/ + +BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex ) +{ +BaseType_t xReturn; +CRCB_t *pxCoRoutine; + + /* Allocate the memory that will store the co-routine control block. */ + pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) ); + if( pxCoRoutine ) + { + /* If pxCurrentCoRoutine is NULL then this is the first co-routine to + be created and the co-routine data structures need initialising. */ + if( pxCurrentCoRoutine == NULL ) + { + pxCurrentCoRoutine = pxCoRoutine; + prvInitialiseCoRoutineLists(); + } + + /* Check the priority is within limits. */ + if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES ) + { + uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1; + } + + /* Fill out the co-routine control block from the function parameters. */ + pxCoRoutine->uxState = corINITIAL_STATE; + pxCoRoutine->uxPriority = uxPriority; + pxCoRoutine->uxIndex = uxIndex; + pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode; + + /* Initialise all the other co-routine control block parameters. */ + vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) ); + vListInitialiseItem( &( pxCoRoutine->xEventListItem ) ); + + /* Set the co-routine control block as a link back from the ListItem_t. + This is so we can get back to the containing CRCB from a generic item + in a list. */ + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine ); + listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) ); + + /* Now the co-routine has been initialised it can be added to the ready + list at the correct priority. */ + prvAddCoRoutineToReadyQueue( pxCoRoutine ); + + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList ) +{ +TickType_t xTimeToWake; + + /* Calculate the time to wake - this may overflow but this is + not a problem. */ + xTimeToWake = xCoRoutineTickCount + xTicksToDelay; + + /* We must remove ourselves from the ready list before adding + ourselves to the blocked list as the same list item is used for + both lists. */ + ( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xCoRoutineTickCount ) + { + /* Wake time has overflowed. Place this item in the + overflow list. */ + vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the + current block list. */ + vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); + } + + if( pxEventList ) + { + /* Also add the co-routine to an event list. If this is done then the + function must be called with interrupts disabled. */ + vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckPendingReadyList( void ) +{ + /* Are there any co-routines waiting to get moved to the ready list? These + are co-routines that have been readied by an ISR. The ISR cannot access + the ready lists itself. */ + while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) + { + CRCB_t *pxUnblockedCRCB; + + /* The pending ready list can be accessed by an ISR. */ + portDISABLE_INTERRUPTS(); + { + pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + } + portENABLE_INTERRUPTS(); + + ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) ); + prvAddCoRoutineToReadyQueue( pxUnblockedCRCB ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCheckDelayedList( void ) +{ +CRCB_t *pxCRCB; + + xPassedTicks = xTaskGetTickCount() - xLastTickCount; + while( xPassedTicks ) + { + xCoRoutineTickCount++; + xPassedTicks--; + + /* If the tick count has overflowed we need to swap the ready lists. */ + if( xCoRoutineTickCount == 0 ) + { + List_t * pxTemp; + + /* Tick count has overflowed so we need to swap the delay lists. If there are + any items in pxDelayedCoRoutineList here then there is an error! */ + pxTemp = pxDelayedCoRoutineList; + pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList; + pxOverflowDelayedCoRoutineList = pxTemp; + } + + /* See if this tick has made a timeout expire. */ + while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) + { + pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); + + if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) + { + /* Timeout not yet expired. */ + break; + } + + portDISABLE_INTERRUPTS(); + { + /* The event could have occurred just before this critical + section. If this is the case then the generic list item will + have been moved to the pending ready list and the following + line is still valid. Also the pvContainer parameter will have + been set to NULL so the following lines are also valid. */ + ( void ) uxListRemove( &( pxCRCB->xGenericListItem ) ); + + /* Is the co-routine waiting on an event also? */ + if( pxCRCB->xEventListItem.pvContainer ) + { + ( void ) uxListRemove( &( pxCRCB->xEventListItem ) ); + } + } + portENABLE_INTERRUPTS(); + + prvAddCoRoutineToReadyQueue( pxCRCB ); + } + } + + xLastTickCount = xCoRoutineTickCount; +} +/*-----------------------------------------------------------*/ + +void vCoRoutineSchedule( void ) +{ + /* See if any co-routines readied by events need moving to the ready lists. */ + prvCheckPendingReadyList(); + + /* See if any delayed co-routines have timed out. */ + prvCheckDelayedList(); + + /* Find the highest priority queue that contains ready co-routines. */ + while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) ) + { + if( uxTopCoRoutineReadyPriority == 0 ) + { + /* No more co-routines to check. */ + return; + } + --uxTopCoRoutineReadyPriority; + } + + /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines + of the same priority get an equal share of the processor time. */ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ); + + /* Call the co-routine. */ + ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex ); + + return; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseCoRoutineLists( void ) +{ +UBaseType_t uxPriority; + + for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ ) + { + vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) ); + } + + vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 ); + vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 ); + vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList ); + + /* Start with pxDelayedCoRoutineList using list1 and the + pxOverflowDelayedCoRoutineList using list2. */ + pxDelayedCoRoutineList = &xDelayedCoRoutineList1; + pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2; +} +/*-----------------------------------------------------------*/ + +BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList ) +{ +CRCB_t *pxUnblockedCRCB; +BaseType_t xReturn; + + /* This function is called from within an interrupt. It can only access + event lists and the pending ready list. This function assumes that a + check has already been made to ensure pxEventList is not empty. */ + pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); + vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); + + if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} + +#endif /* configUSE_CO_ROUTINES == 0 */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/event_groups.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/event_groups.c new file mode 100755 index 0000000..b8df5fd --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/event_groups.c @@ -0,0 +1,752 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "event_groups.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +/* The following bit fields convey control information in a task's event list +item value. It is important they don't clash with the +taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */ +#if configUSE_16_BIT_TICKS == 1 + #define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U + #define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U + #define eventWAIT_FOR_ALL_BITS 0x0400U + #define eventEVENT_BITS_CONTROL_BYTES 0xff00U +#else + #define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL + #define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL + #define eventWAIT_FOR_ALL_BITS 0x04000000UL + #define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL +#endif + +typedef struct xEventGroupDefinition +{ + EventBits_t uxEventBits; + List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */ + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxEventGroupNumber; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ + #endif +} EventGroup_t; + +/*-----------------------------------------------------------*/ + +/* + * Test the bits set in uxCurrentEventBits to see if the wait condition is met. + * The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is + * pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor + * are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the + * wait condition is met if any of the bits set in uxBitsToWait for are also set + * in uxCurrentEventBits. + */ +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) + { + EventGroup_t *pxEventBits; + + /* A StaticEventGroup_t object must be provided. */ + configASSERT( pxEventGroupBuffer ); + + /* The user has provided a statically allocated event group - use it. */ + pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note that + this event group was created statically in case the event group + is later deleted. */ + pxEventBits->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + EventGroupHandle_t xEventGroupCreate( void ) + { + EventGroup_t *pxEventBits; + + /* Allocate the event group. */ + pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Both static and dynamic allocation can be used, so note this + event group was allocated statically in case the event group is + later deleted. */ + pxEventBits->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + traceEVENT_GROUP_CREATE( pxEventBits ); + } + else + { + traceEVENT_GROUP_CREATE_FAILED(); + } + + return ( EventGroupHandle_t ) pxEventBits; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) +{ +EventBits_t uxOriginalBitValue, uxReturn; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +BaseType_t xAlreadyYielded; +BaseType_t xTimeoutOccurred = pdFALSE; + + configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + configASSERT( uxBitsToWaitFor != 0 ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + vTaskSuspendAll(); + { + uxOriginalBitValue = pxEventBits->uxEventBits; + + ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet ); + + if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + /* All the rendezvous bits are now set - no need to block. */ + uxReturn = ( uxOriginalBitValue | uxBitsToSet ); + + /* Rendezvous always clear the bits. They will have been cleared + already unless this is the only task in the rendezvous. */ + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + + xTicksToWait = 0; + } + else + { + if( xTicksToWait != ( TickType_t ) 0 ) + { + traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ); + + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait ); + + /* This assignment is obsolete as uxReturn will get set after + the task unblocks, but some compilers mistakenly generate a + warning about uxReturn being returned without being set if the + assignment is omitted. */ + uxReturn = 0; + } + else + { + /* The rendezvous bits were not set, but no block time was + specified - just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + } + } + } + xAlreadyYielded = xTaskResumeAll(); + + if( xTicksToWait != ( TickType_t ) 0 ) + { + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) + { + /* The task timed out, just return the current event bit value. */ + taskENTER_CRITICAL(); + { + uxReturn = pxEventBits->uxEventBits; + + /* Although the task got here because it timed out before the + bits it was waiting for were set, it is possible that since it + unblocked another task has set the bits. If this is the case + then it needs to clear the bits before exiting. */ + if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + xTimeoutOccurred = pdTRUE; + } + else + { + /* The task unblocked because the bits were set. */ + } + + /* Control bits might be set as the task had blocked should not be + returned. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + } + + traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn, uxControlBits = 0; +BaseType_t xWaitConditionMet, xAlreadyYielded; +BaseType_t xTimeoutOccurred = pdFALSE; + + /* Check the user is not attempting to wait on the bits used by the kernel + itself, and that at least one bit is being requested. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + configASSERT( uxBitsToWaitFor != 0 ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + vTaskSuspendAll(); + { + const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; + + /* Check to see if the wait condition is already met or not. */ + xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits ); + + if( xWaitConditionMet != pdFALSE ) + { + /* The wait condition has already been met so there is no need to + block. */ + uxReturn = uxCurrentEventBits; + xTicksToWait = ( TickType_t ) 0; + + /* Clear the wait bits if requested to do so. */ + if( xClearOnExit != pdFALSE ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The wait condition has not been met, but no block time was + specified, so just return the current value. */ + uxReturn = uxCurrentEventBits; + } + else + { + /* The task is going to block to wait for its required bits to be + set. uxControlBits are used to remember the specified behaviour of + this call to xEventGroupWaitBits() - for use when the event bits + unblock the task. */ + if( xClearOnExit != pdFALSE ) + { + uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xWaitForAllBits != pdFALSE ) + { + uxControlBits |= eventWAIT_FOR_ALL_BITS; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait ); + + /* This is obsolete as it will get set after the task unblocks, but + some compilers mistakenly generate a warning about the variable + being returned without being set if it is not done. */ + uxReturn = 0; + + traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); + } + } + xAlreadyYielded = xTaskResumeAll(); + + if( xTicksToWait != ( TickType_t ) 0 ) + { + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) + { + taskENTER_CRITICAL(); + { + /* The task timed out, just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + + /* It is possible that the event bits were updated between this + task leaving the Blocked state and running again. */ + if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ) + { + if( xClearOnExit != pdFALSE ) + { + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Prevent compiler warnings when trace macros are not used. */ + xTimeoutOccurred = pdFALSE; + } + else + { + /* The task unblocked because the bits were set. */ + } + + /* The task blocked so control bits may have been set. */ + uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; + } + traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn; + + /* Check the user is not attempting to clear the bits used by the kernel + itself. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + + taskENTER_CRITICAL(); + { + traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); + + /* The value returned is the event group value prior to the bits being + cleared. */ + uxReturn = pxEventBits->uxEventBits; + + /* Clear the bits. */ + pxEventBits->uxEventBits &= ~uxBitsToClear; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) + { + BaseType_t xReturn; + + traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) +{ +UBaseType_t uxSavedInterruptStatus; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +EventBits_t uxReturn; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + uxReturn = pxEventBits->uxEventBits; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) +{ +ListItem_t *pxListItem, *pxNext; +ListItem_t const *pxListEnd; +List_t *pxList; +EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits; +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +BaseType_t xMatchFound = pdFALSE; + + /* Check the user is not attempting to set the bits used by the kernel + itself. */ + configASSERT( xEventGroup ); + configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); + + pxList = &( pxEventBits->xTasksWaitingForBits ); + pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + vTaskSuspendAll(); + { + traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ); + + pxListItem = listGET_HEAD_ENTRY( pxList ); + + /* Set the bits. */ + pxEventBits->uxEventBits |= uxBitsToSet; + + /* See if the new bit value should unblock any tasks. */ + while( pxListItem != pxListEnd ) + { + pxNext = listGET_NEXT( pxListItem ); + uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem ); + xMatchFound = pdFALSE; + + /* Split the bits waited for from the control bits. */ + uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES; + uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES; + + if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 ) + { + /* Just looking for single bit being set. */ + if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 ) + { + xMatchFound = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor ) + { + /* All bits are set. */ + xMatchFound = pdTRUE; + } + else + { + /* Need all bits to be set, but not all the bits were set. */ + } + + if( xMatchFound != pdFALSE ) + { + /* The bits match. Should the bits be cleared on exit? */ + if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 ) + { + uxBitsToClear |= uxBitsWaitedFor; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Store the actual event flag value in the task's event list + item before removing the task from the event list. The + eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows + that is was unblocked due to its required bits matching, rather + than because it timed out. */ + ( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); + } + + /* Move onto the next list item. Note pxListItem->pxNext is not + used here as the list item may have been removed from the event list + and inserted into the ready/pending reading list. */ + pxListItem = pxNext; + } + + /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT + bit was set in the control word. */ + pxEventBits->uxEventBits &= ~uxBitsToClear; + } + ( void ) xTaskResumeAll(); + + return pxEventBits->uxEventBits; +} +/*-----------------------------------------------------------*/ + +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) +{ +EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; +const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); + + vTaskSuspendAll(); + { + traceEVENT_GROUP_DELETE( xEventGroup ); + + while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ) + { + /* Unblock the task, returning 0 as the event list is being deleted + and cannot therefore have any bits set. */ + configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); + ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); + } + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The event group can only have been allocated dynamically - free + it again. */ + vPortFree( pxEventBits ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The event group could have been allocated statically or + dynamically, so check before attempting to free the memory. */ + if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxEventBits ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + ( void ) xTaskResumeAll(); +} +/*-----------------------------------------------------------*/ + +/* For internal use only - execute a 'set bits' command that was pended from +an interrupt. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) +{ + ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); +} +/*-----------------------------------------------------------*/ + +/* For internal use only - execute a 'clear bits' command that was pended from +an interrupt. */ +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) +{ + ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) +{ +BaseType_t xWaitConditionMet = pdFALSE; + + if( xWaitForAllBits == pdFALSE ) + { + /* Task only has to wait for one bit within uxBitsToWaitFor to be + set. Is one already set? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 ) + { + xWaitConditionMet = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Task has to wait for all the bits in uxBitsToWaitFor to be set. + Are they set already? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + xWaitConditionMet = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return xWaitConditionMet; +} +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) + + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) + { + BaseType_t xReturn; + + traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ); + xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +#if (configUSE_TRACE_FACILITY == 1) + + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) + { + UBaseType_t xReturn; + EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; + + if( xEventGroup == NULL ) + { + xReturn = 0; + } + else + { + xReturn = pxEventBits->uxEventGroupNumber; + } + + return xReturn; + } + +#endif + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/FreeRTOS.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/FreeRTOS.h new file mode 100755 index 0000000..f81172d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/FreeRTOS.h @@ -0,0 +1,1063 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef INC_FREERTOS_H +#define INC_FREERTOS_H + +/* + * Include the generic headers required for the FreeRTOS port being used. + */ +#include + +/* + * If stdint.h cannot be located then: + * + If using GCC ensure the -nostdint options is *not* being used. + * + Ensure the project's include path includes the directory in which your + * compiler stores stdint.h. + * + Set any compiler options necessary for it to support C99, as technically + * stdint.h is only mandatory with C99 (FreeRTOS does not require C99 in any + * other way). + * + The FreeRTOS download includes a simple stdint.h definition that can be + * used in cases where none is provided by the compiler. The files only + * contains the typedefs required to build FreeRTOS. Read the instructions + * in FreeRTOS/source/stdint.readme for more information. + */ +#include /* READ COMMENT ABOVE. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application specific configuration options. */ +#include "FreeRTOSConfig.h" + +/* Basic FreeRTOS definitions. */ +#include "projdefs.h" + +/* Definitions specific to the port being used. */ +#include "portable.h" + +/* Must be defaulted before configUSE_NEWLIB_REENTRANT is used below. */ +#ifndef configUSE_NEWLIB_REENTRANT + #define configUSE_NEWLIB_REENTRANT 0 +#endif + +/* Required if struct _reent is used. */ +#if ( configUSE_NEWLIB_REENTRANT == 1 ) + #include +#endif +/* + * Check all the required application specific macros have been defined. + * These macros are application specific and (as downloaded) are defined + * within FreeRTOSConfig.h. + */ + +#ifndef configMINIMAL_STACK_SIZE + #error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value. +#endif + +#ifndef configMAX_PRIORITIES + #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_PREEMPTION + #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_IDLE_HOOK + #error Missing definition: configUSE_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_TICK_HOOK + #error Missing definition: configUSE_TICK_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configUSE_16_BIT_TICKS + #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. +#endif + +#ifndef configMAX_PRIORITIES + #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + +#ifndef configUSE_CO_ROUTINES + #define configUSE_CO_ROUTINES 0 +#endif + +#ifndef INCLUDE_vTaskPrioritySet + #define INCLUDE_vTaskPrioritySet 0 +#endif + +#ifndef INCLUDE_uxTaskPriorityGet + #define INCLUDE_uxTaskPriorityGet 0 +#endif + +#ifndef INCLUDE_vTaskDelete + #define INCLUDE_vTaskDelete 0 +#endif + +#ifndef INCLUDE_vTaskSuspend + #define INCLUDE_vTaskSuspend 0 +#endif + +#ifndef INCLUDE_vTaskDelayUntil + #define INCLUDE_vTaskDelayUntil 0 +#endif + +#ifndef INCLUDE_vTaskDelay + #define INCLUDE_vTaskDelay 0 +#endif + +#ifndef INCLUDE_xTaskGetIdleTaskHandle + #define INCLUDE_xTaskGetIdleTaskHandle 0 +#endif + +#ifndef INCLUDE_xTaskAbortDelay + #define INCLUDE_xTaskAbortDelay 0 +#endif + +#ifndef INCLUDE_xQueueGetMutexHolder + #define INCLUDE_xQueueGetMutexHolder 0 +#endif + +#ifndef INCLUDE_xSemaphoreGetMutexHolder + #define INCLUDE_xSemaphoreGetMutexHolder INCLUDE_xQueueGetMutexHolder +#endif + +#ifndef INCLUDE_xTaskGetHandle + #define INCLUDE_xTaskGetHandle 0 +#endif + +#ifndef INCLUDE_uxTaskGetStackHighWaterMark + #define INCLUDE_uxTaskGetStackHighWaterMark 0 +#endif + +#ifndef INCLUDE_eTaskGetState + #define INCLUDE_eTaskGetState 0 +#endif + +#ifndef INCLUDE_xTaskResumeFromISR + #define INCLUDE_xTaskResumeFromISR 1 +#endif + +#ifndef INCLUDE_xTimerPendFunctionCall + #define INCLUDE_xTimerPendFunctionCall 0 +#endif + +#ifndef INCLUDE_xTaskGetSchedulerState + #define INCLUDE_xTaskGetSchedulerState 0 +#endif + +#ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 +#endif + +#if configUSE_CO_ROUTINES != 0 + #ifndef configMAX_CO_ROUTINE_PRIORITIES + #error configMAX_CO_ROUTINE_PRIORITIES must be greater than or equal to 1. + #endif +#endif + +#ifndef configUSE_DAEMON_TASK_STARTUP_HOOK + #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#endif + +#ifndef configUSE_APPLICATION_TASK_TAG + #define configUSE_APPLICATION_TASK_TAG 0 +#endif + +#ifndef configNUM_THREAD_LOCAL_STORAGE_POINTERS + #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#endif + +#ifndef configUSE_RECURSIVE_MUTEXES + #define configUSE_RECURSIVE_MUTEXES 0 +#endif + +#ifndef configUSE_MUTEXES + #define configUSE_MUTEXES 0 +#endif + +#ifndef configUSE_TIMERS + #define configUSE_TIMERS 0 +#endif + +#ifndef configUSE_COUNTING_SEMAPHORES + #define configUSE_COUNTING_SEMAPHORES 0 +#endif + +#ifndef configUSE_ALTERNATIVE_API + #define configUSE_ALTERNATIVE_API 0 +#endif + +#ifndef portCRITICAL_NESTING_IN_TCB + #define portCRITICAL_NESTING_IN_TCB 0 +#endif + +#ifndef configMAX_TASK_NAME_LEN + #define configMAX_TASK_NAME_LEN 16 +#endif + +#ifndef configIDLE_SHOULD_YIELD + #define configIDLE_SHOULD_YIELD 1 +#endif + +#if configMAX_TASK_NAME_LEN < 1 + #error configMAX_TASK_NAME_LEN must be set to a minimum of 1 in FreeRTOSConfig.h +#endif + +#ifndef configASSERT + #define configASSERT( x ) + #define configASSERT_DEFINED 0 +#else + #define configASSERT_DEFINED 1 +#endif + +/* The timers module relies on xTaskGetSchedulerState(). */ +#if configUSE_TIMERS == 1 + + #ifndef configTIMER_TASK_PRIORITY + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined. + #endif /* configTIMER_TASK_PRIORITY */ + + #ifndef configTIMER_QUEUE_LENGTH + #error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined. + #endif /* configTIMER_QUEUE_LENGTH */ + + #ifndef configTIMER_TASK_STACK_DEPTH + #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined. + #endif /* configTIMER_TASK_STACK_DEPTH */ + +#endif /* configUSE_TIMERS */ + +#ifndef portSET_INTERRUPT_MASK_FROM_ISR + #define portSET_INTERRUPT_MASK_FROM_ISR() 0 +#endif + +#ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) uxSavedStatusValue +#endif + +#ifndef portCLEAN_UP_TCB + #define portCLEAN_UP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef portPRE_TASK_DELETE_HOOK + #define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxYieldPending ) +#endif + +#ifndef portSETUP_TCB + #define portSETUP_TCB( pxTCB ) ( void ) pxTCB +#endif + +#ifndef configQUEUE_REGISTRY_SIZE + #define configQUEUE_REGISTRY_SIZE 0U +#endif + +#if ( configQUEUE_REGISTRY_SIZE < 1 ) + #define vQueueAddToRegistry( xQueue, pcName ) + #define vQueueUnregisterQueue( xQueue ) + #define pcQueueGetName( xQueue ) +#endif + +#ifndef portPOINTER_SIZE_TYPE + #define portPOINTER_SIZE_TYPE uint32_t +#endif + +/* Remove any unused trace macros. */ +#ifndef traceSTART + /* Used to perform any necessary initialisation - for example, open a file + into which trace is to be written. */ + #define traceSTART() +#endif + +#ifndef traceEND + /* Use to close a trace, for example close a file into which trace has been + written. */ + #define traceEND() +#endif + +#ifndef traceTASK_SWITCHED_IN + /* Called after a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the selected task. */ + #define traceTASK_SWITCHED_IN() +#endif + +#ifndef traceINCREASE_TICK_COUNT + /* Called before stepping the tick count after waking from tickless idle + sleep. */ + #define traceINCREASE_TICK_COUNT( x ) +#endif + +#ifndef traceLOW_POWER_IDLE_BEGIN + /* Called immediately before entering tickless idle. */ + #define traceLOW_POWER_IDLE_BEGIN() +#endif + +#ifndef traceLOW_POWER_IDLE_END + /* Called when returning to the Idle task after a tickless idle. */ + #define traceLOW_POWER_IDLE_END() +#endif + +#ifndef traceTASK_SWITCHED_OUT + /* Called before a task has been selected to run. pxCurrentTCB holds a pointer + to the task control block of the task being switched out. */ + #define traceTASK_SWITCHED_OUT() +#endif + +#ifndef traceTASK_PRIORITY_INHERIT + /* Called when a task attempts to take a mutex that is already held by a + lower priority task. pxTCBOfMutexHolder is a pointer to the TCB of the task + that holds the mutex. uxInheritedPriority is the priority the mutex holder + will inherit (the priority of the task that is attempting to obtain the + muted. */ + #define traceTASK_PRIORITY_INHERIT( pxTCBOfMutexHolder, uxInheritedPriority ) +#endif + +#ifndef traceTASK_PRIORITY_DISINHERIT + /* Called when a task releases a mutex, the holding of which had resulted in + the task inheriting the priority of a higher priority task. + pxTCBOfMutexHolder is a pointer to the TCB of the task that is releasing the + mutex. uxOriginalPriority is the task's configured (base) priority. */ + #define traceTASK_PRIORITY_DISINHERIT( pxTCBOfMutexHolder, uxOriginalPriority ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_RECEIVE + /* Task is about to block because it cannot read from a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the read was attempted. pxCurrentTCB points to the TCB of the + task that attempted the read. */ + #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceBLOCKING_ON_QUEUE_SEND + /* Task is about to block because it cannot write to a + queue/mutex/semaphore. pxQueue is a pointer to the queue/mutex/semaphore + upon which the write was attempted. pxCurrentTCB points to the TCB of the + task that attempted the write. */ + #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) +#endif + +#ifndef configCHECK_FOR_STACK_OVERFLOW + #define configCHECK_FOR_STACK_OVERFLOW 0 +#endif + +/* The following event macros are embedded in the kernel API calls. */ + +#ifndef traceMOVED_TASK_TO_READY_STATE + #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef tracePOST_MOVED_TASK_TO_READY_STATE + #define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +#endif + +#ifndef traceQUEUE_CREATE + #define traceQUEUE_CREATE( pxNewQueue ) +#endif + +#ifndef traceQUEUE_CREATE_FAILED + #define traceQUEUE_CREATE_FAILED( ucQueueType ) +#endif + +#ifndef traceCREATE_MUTEX + #define traceCREATE_MUTEX( pxNewQueue ) +#endif + +#ifndef traceCREATE_MUTEX_FAILED + #define traceCREATE_MUTEX_FAILED() +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE + #define traceGIVE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceGIVE_MUTEX_RECURSIVE_FAILED + #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE + #define traceTAKE_MUTEX_RECURSIVE( pxMutex ) +#endif + +#ifndef traceTAKE_MUTEX_RECURSIVE_FAILED + #define traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ) +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE + #define traceCREATE_COUNTING_SEMAPHORE() +#endif + +#ifndef traceCREATE_COUNTING_SEMAPHORE_FAILED + #define traceCREATE_COUNTING_SEMAPHORE_FAILED() +#endif + +#ifndef traceQUEUE_SEND + #define traceQUEUE_SEND( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FAILED + #define traceQUEUE_SEND_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE + #define traceQUEUE_RECEIVE( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK + #define traceQUEUE_PEEK( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR + #define traceQUEUE_PEEK_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FAILED + #define traceQUEUE_RECEIVE_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR + #define traceQUEUE_SEND_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_SEND_FROM_ISR_FAILED + #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR + #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) +#endif + +#ifndef traceQUEUE_RECEIVE_FROM_ISR_FAILED + #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_PEEK_FROM_ISR_FAILED + #define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) +#endif + +#ifndef traceQUEUE_DELETE + #define traceQUEUE_DELETE( pxQueue ) +#endif + +#ifndef traceTASK_CREATE + #define traceTASK_CREATE( pxNewTCB ) +#endif + +#ifndef traceTASK_CREATE_FAILED + #define traceTASK_CREATE_FAILED() +#endif + +#ifndef traceTASK_DELETE + #define traceTASK_DELETE( pxTaskToDelete ) +#endif + +#ifndef traceTASK_DELAY_UNTIL + #define traceTASK_DELAY_UNTIL( x ) +#endif + +#ifndef traceTASK_DELAY + #define traceTASK_DELAY() +#endif + +#ifndef traceTASK_PRIORITY_SET + #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) +#endif + +#ifndef traceTASK_SUSPEND + #define traceTASK_SUSPEND( pxTaskToSuspend ) +#endif + +#ifndef traceTASK_RESUME + #define traceTASK_RESUME( pxTaskToResume ) +#endif + +#ifndef traceTASK_RESUME_FROM_ISR + #define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) +#endif + +#ifndef traceTASK_INCREMENT_TICK + #define traceTASK_INCREMENT_TICK( xTickCount ) +#endif + +#ifndef traceTIMER_CREATE + #define traceTIMER_CREATE( pxNewTimer ) +#endif + +#ifndef traceTIMER_CREATE_FAILED + #define traceTIMER_CREATE_FAILED() +#endif + +#ifndef traceTIMER_COMMAND_SEND + #define traceTIMER_COMMAND_SEND( xTimer, xMessageID, xMessageValueValue, xReturn ) +#endif + +#ifndef traceTIMER_EXPIRED + #define traceTIMER_EXPIRED( pxTimer ) +#endif + +#ifndef traceTIMER_COMMAND_RECEIVED + #define traceTIMER_COMMAND_RECEIVED( pxTimer, xMessageID, xMessageValue ) +#endif + +#ifndef traceMALLOC + #define traceMALLOC( pvAddress, uiSize ) +#endif + +#ifndef traceFREE + #define traceFREE( pvAddress, uiSize ) +#endif + +#ifndef traceEVENT_GROUP_CREATE + #define traceEVENT_GROUP_CREATE( xEventGroup ) +#endif + +#ifndef traceEVENT_GROUP_CREATE_FAILED + #define traceEVENT_GROUP_CREATE_FAILED() +#endif + +#ifndef traceEVENT_GROUP_SYNC_BLOCK + #define traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_SYNC_END + #define traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_BLOCK + #define traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ) +#endif + +#ifndef traceEVENT_GROUP_WAIT_BITS_END + #define traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ) ( void ) xTimeoutOccurred +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS + #define traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR + #define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS + #define traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_SET_BITS_FROM_ISR + #define traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet ) +#endif + +#ifndef traceEVENT_GROUP_DELETE + #define traceEVENT_GROUP_DELETE( xEventGroup ) +#endif + +#ifndef tracePEND_FUNC_CALL + #define tracePEND_FUNC_CALL(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef tracePEND_FUNC_CALL_FROM_ISR + #define tracePEND_FUNC_CALL_FROM_ISR(xFunctionToPend, pvParameter1, ulParameter2, ret) +#endif + +#ifndef traceQUEUE_REGISTRY_ADD + #define traceQUEUE_REGISTRY_ADD(xQueue, pcQueueName) +#endif + +#ifndef traceTASK_NOTIFY_TAKE_BLOCK + #define traceTASK_NOTIFY_TAKE_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_TAKE + #define traceTASK_NOTIFY_TAKE() +#endif + +#ifndef traceTASK_NOTIFY_WAIT_BLOCK + #define traceTASK_NOTIFY_WAIT_BLOCK() +#endif + +#ifndef traceTASK_NOTIFY_WAIT + #define traceTASK_NOTIFY_WAIT() +#endif + +#ifndef traceTASK_NOTIFY + #define traceTASK_NOTIFY() +#endif + +#ifndef traceTASK_NOTIFY_FROM_ISR + #define traceTASK_NOTIFY_FROM_ISR() +#endif + +#ifndef traceTASK_NOTIFY_GIVE_FROM_ISR + #define traceTASK_NOTIFY_GIVE_FROM_ISR() +#endif + +#ifndef configGENERATE_RUN_TIME_STATS + #define configGENERATE_RUN_TIME_STATS 0 +#endif + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. + #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ + + #ifndef portGET_RUN_TIME_COUNTER_VALUE + #ifndef portALT_GET_RUN_TIME_COUNTER_VALUE + #error If configGENERATE_RUN_TIME_STATS is defined then either portGET_RUN_TIME_COUNTER_VALUE or portALT_GET_RUN_TIME_COUNTER_VALUE must also be defined. See the examples provided and the FreeRTOS web site for more information. + #endif /* portALT_GET_RUN_TIME_COUNTER_VALUE */ + #endif /* portGET_RUN_TIME_COUNTER_VALUE */ + +#endif /* configGENERATE_RUN_TIME_STATS */ + +#ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS + #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() +#endif + +#ifndef configUSE_MALLOC_FAILED_HOOK + #define configUSE_MALLOC_FAILED_HOOK 0 +#endif + +#ifndef portPRIVILEGE_BIT + #define portPRIVILEGE_BIT ( ( UBaseType_t ) 0x00 ) +#endif + +#ifndef portYIELD_WITHIN_API + #define portYIELD_WITHIN_API portYIELD +#endif + +#ifndef portSUPPRESS_TICKS_AND_SLEEP + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) +#endif + +#ifndef configEXPECTED_IDLE_TIME_BEFORE_SLEEP + #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 +#endif + +#if configEXPECTED_IDLE_TIME_BEFORE_SLEEP < 2 + #error configEXPECTED_IDLE_TIME_BEFORE_SLEEP must not be less than 2 +#endif + +#ifndef configUSE_TICKLESS_IDLE + #define configUSE_TICKLESS_IDLE 0 +#endif + +#ifndef configPRE_SLEEP_PROCESSING + #define configPRE_SLEEP_PROCESSING( x ) +#endif + +#ifndef configPOST_SLEEP_PROCESSING + #define configPOST_SLEEP_PROCESSING( x ) +#endif + +#ifndef configUSE_QUEUE_SETS + #define configUSE_QUEUE_SETS 0 +#endif + +#ifndef portTASK_USES_FLOATING_POINT + #define portTASK_USES_FLOATING_POINT() +#endif + +#ifndef configUSE_TIME_SLICING + #define configUSE_TIME_SLICING 1 +#endif + +#ifndef configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS + #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 +#endif + +#ifndef configUSE_STATS_FORMATTING_FUNCTIONS + #define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#endif + +#ifndef portASSERT_IF_INTERRUPT_PRIORITY_INVALID + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() +#endif + +#ifndef configUSE_TRACE_FACILITY + #define configUSE_TRACE_FACILITY 0 +#endif + +#ifndef mtCOVERAGE_TEST_MARKER + #define mtCOVERAGE_TEST_MARKER() +#endif + +#ifndef mtCOVERAGE_TEST_DELAY + #define mtCOVERAGE_TEST_DELAY() +#endif + +#ifndef portASSERT_IF_IN_ISR + #define portASSERT_IF_IN_ISR() +#endif + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#endif + +#ifndef configAPPLICATION_ALLOCATED_HEAP + #define configAPPLICATION_ALLOCATED_HEAP 0 +#endif + +#ifndef configUSE_TASK_NOTIFICATIONS + #define configUSE_TASK_NOTIFICATIONS 1 +#endif + +#ifndef portTICK_TYPE_IS_ATOMIC + #define portTICK_TYPE_IS_ATOMIC 0 +#endif + +#ifndef configSUPPORT_STATIC_ALLOCATION + /* Defaults to 0 for backward compatibility. */ + #define configSUPPORT_STATIC_ALLOCATION 0 +#endif + +#ifndef configSUPPORT_DYNAMIC_ALLOCATION + /* Defaults to 1 for backward compatibility. */ + #define configSUPPORT_DYNAMIC_ALLOCATION 1 +#endif + +/* Sanity check the configuration. */ +#if( configUSE_TICKLESS_IDLE != 0 ) + #if( INCLUDE_vTaskSuspend != 1 ) + #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0 + #endif /* INCLUDE_vTaskSuspend */ +#endif /* configUSE_TICKLESS_IDLE */ + +#if( ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) ) + #error configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION cannot both be 0, but can both be 1. +#endif + +#if( ( configUSE_RECURSIVE_MUTEXES == 1 ) && ( configUSE_MUTEXES != 1 ) ) + #error configUSE_MUTEXES must be set to 1 to use recursive mutexes +#endif + +#if( portTICK_TYPE_IS_ATOMIC == 0 ) + /* Either variables of tick type cannot be read atomically, or + portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when + the tick count is returned to the standard critical section macros. */ + #define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( ( x ) ) +#else + /* The tick type can be read atomically, so critical sections used when the + tick count is returned can be defined away. */ + #define portTICK_TYPE_ENTER_CRITICAL() + #define portTICK_TYPE_EXIT_CRITICAL() + #define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0 + #define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( x ) ( void ) x +#endif + +/* Definitions to allow backward compatibility with FreeRTOS versions prior to +V8 if desired. */ +#ifndef configENABLE_BACKWARD_COMPATIBILITY + #define configENABLE_BACKWARD_COMPATIBILITY 1 +#endif + +#if configENABLE_BACKWARD_COMPATIBILITY == 1 + #define eTaskStateGet eTaskGetState + #define portTickType TickType_t + #define xTaskHandle TaskHandle_t + #define xQueueHandle QueueHandle_t + #define xSemaphoreHandle SemaphoreHandle_t + #define xQueueSetHandle QueueSetHandle_t + #define xQueueSetMemberHandle QueueSetMemberHandle_t + #define xTimeOutType TimeOut_t + #define xMemoryRegion MemoryRegion_t + #define xTaskParameters TaskParameters_t + #define xTaskStatusType TaskStatus_t + #define xTimerHandle TimerHandle_t + #define xCoRoutineHandle CoRoutineHandle_t + #define pdTASK_HOOK_CODE TaskHookFunction_t + #define portTICK_RATE_MS portTICK_PERIOD_MS + #define pcTaskGetTaskName pcTaskGetName + #define pcTimerGetTimerName pcTimerGetName + #define pcQueueGetQueueName pcQueueGetName + #define vTaskGetTaskInfo vTaskGetInfo + + /* Backward compatibility within the scheduler code only - these definitions + are not really required but are included for completeness. */ + #define tmrTIMER_CALLBACK TimerCallbackFunction_t + #define pdTASK_CODE TaskFunction_t + #define xListItem ListItem_t + #define xList List_t +#endif /* configENABLE_BACKWARD_COMPATIBILITY */ + +#if( configUSE_ALTERNATIVE_API != 0 ) + #error The alternative API was deprecated some time ago, and was removed in FreeRTOS V9.0 0 +#endif + +/* Set configUSE_TASK_FPU_SUPPORT to 0 to omit floating point support even +if floating point hardware is otherwise supported by the FreeRTOS port in use. +This constant is not supported by all FreeRTOS ports that include floating +point support. */ +#ifndef configUSE_TASK_FPU_SUPPORT + #define configUSE_TASK_FPU_SUPPORT 1 +#endif + +/* + * In line with software engineering best practice, FreeRTOS implements a strict + * data hiding policy, so the real structures used by FreeRTOS to maintain the + * state of tasks, queues, semaphores, etc. are not accessible to the application + * code. However, if the application writer wants to statically allocate such + * an object then the size of the object needs to be know. Dummy structures + * that are guaranteed to have the same size and alignment requirements of the + * real objects are used for this purpose. The dummy list and list item + * structures below are used for inclusion in such a dummy structure. + */ +struct xSTATIC_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 4 ]; +}; +typedef struct xSTATIC_LIST_ITEM StaticListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +struct xSTATIC_MINI_LIST_ITEM +{ + TickType_t xDummy1; + void *pvDummy2[ 2 ]; +}; +typedef struct xSTATIC_MINI_LIST_ITEM StaticMiniListItem_t; + +/* See the comments above the struct xSTATIC_LIST_ITEM definition. */ +typedef struct xSTATIC_LIST +{ + UBaseType_t uxDummy1; + void *pvDummy2; + StaticMiniListItem_t xDummy3; +} StaticList_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. + */ +typedef struct xSTATIC_TCB +{ + void *pxDummy1; + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; + #endif + StaticListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + #if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; + #endif + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; + #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; + #endif + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; + #endif + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; + #endif + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; + #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + uint8_t ucDummy19; + #endif + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t uxDummy20; + #endif + +} StaticTask_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. + */ +typedef struct xSTATIC_QUEUE +{ + void *pvDummy1[ 3 ]; + + union + { + void *pvDummy2; + UBaseType_t uxDummy2; + } u; + + StaticList_t xDummy3[ 2 ]; + UBaseType_t uxDummy4[ 3 ]; + uint8_t ucDummy5[ 2 ]; + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy6; + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + void *pvDummy7; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy8; + uint8_t ucDummy9; + #endif + +} StaticQueue_t; +typedef StaticQueue_t StaticSemaphore_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the event group structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create an event group then the size of the event group object needs to be + * know. The StaticEventGroup_t structure below is provided for this purpose. + * Its sizes and alignment requirements are guaranteed to match those of the + * genuine structure, no matter which architecture is being used, and no matter + * how the values in FreeRTOSConfig.h are set. Its contents are somewhat + * obfuscated in the hope users will recognise that it would be unwise to make + * direct use of the structure members. + */ +typedef struct xSTATIC_EVENT_GROUP +{ + TickType_t xDummy1; + StaticList_t xDummy2; + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy3; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy4; + #endif + +} StaticEventGroup_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the software timer structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create a software timer then the size of the queue object needs to be know. + * The StaticTimer_t structure below is provided for this purpose. Its sizes + * and alignment requirements are guaranteed to match those of the genuine + * structure, no matter which architecture is being used, and no matter how the + * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in + * the hope users will recognise that it would be unwise to make direct use of + * the structure members. + */ +typedef struct xSTATIC_TIMER +{ + void *pvDummy1; + StaticListItem_t xDummy2; + TickType_t xDummy3; + UBaseType_t uxDummy4; + void *pvDummy5[ 2 ]; + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy6; + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucDummy7; + #endif + +} StaticTimer_t; + +#ifdef __cplusplus +} +#endif + +#endif /* INC_FREERTOS_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/StackMacros.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/StackMacros.h new file mode 100755 index 0000000..13c6b82 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/StackMacros.h @@ -0,0 +1,171 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef STACK_MACROS_H +#define STACK_MACROS_H + +/* + * Call the stack overflow hook function if the stack of the task being swapped + * out is currently overflowed, or looks like it might have overflowed in the + * past. + * + * Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check + * the current stack state only - comparing the current top of stack value to + * the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1 + * will also cause the last few stack bytes to be checked to ensure the value + * to which the bytes were set when the task was created have not been + * overwritten. Note this second test does not guarantee that an overflowed + * stack will always be recognised. + */ + +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) ) + + /* Only the current stack state is to be checked. */ + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + \ + /* Is the currently saved stack pointer within the stack limit? */ \ + if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \ + const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \ + \ + if( ( pulStack[ 0 ] != ulCheckValue ) || \ + ( pulStack[ 1 ] != ulCheckValue ) || \ + ( pulStack[ 2 ] != ulCheckValue ) || \ + ( pulStack[ 3 ] != ulCheckValue ) ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) ) + + #define taskCHECK_FOR_STACK_OVERFLOW() \ + { \ + int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \ + static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \ + tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \ + \ + \ + pcEndOfStack -= sizeof( ucExpectedStackBytes ); \ + \ + /* Has the extremity of the task stack ever been written over? */ \ + if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \ + { \ + vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \ + } \ + } + +#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */ +/*-----------------------------------------------------------*/ + +/* Remove stack overflow macro if not being used. */ +#ifndef taskCHECK_FOR_STACK_OVERFLOW + #define taskCHECK_FOR_STACK_OVERFLOW() +#endif + + + +#endif /* STACK_MACROS_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/croutine.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/croutine.h new file mode 100755 index 0000000..4f003a0 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/croutine.h @@ -0,0 +1,762 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef CO_ROUTINE_H +#define CO_ROUTINE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include croutine.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Used to hide the implementation of the co-routine control block. The +control block structure however has to be included in the header due to +the macro implementation of the co-routine functionality. */ +typedef void * CoRoutineHandle_t; + +/* Defines the prototype to which co-routine functions must conform. */ +typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t ); + +typedef struct corCoRoutineControlBlock +{ + crCOROUTINE_CODE pxCoRoutineFunction; + ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */ + ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */ + UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */ + UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */ + uint16_t uxState; /*< Used internally by the co-routine implementation. */ +} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */ + +/** + * croutine. h + *
+ BaseType_t xCoRoutineCreate(
+                                 crCOROUTINE_CODE pxCoRoutineCode,
+                                 UBaseType_t uxPriority,
+                                 UBaseType_t uxIndex
+                               );
+ * + * Create a new co-routine and add it to the list of co-routines that are + * ready to run. + * + * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine + * functions require special syntax - see the co-routine section of the WEB + * documentation for more information. + * + * @param uxPriority The priority with respect to other co-routines at which + * the co-routine will run. + * + * @param uxIndex Used to distinguish between different co-routines that + * execute the same function. See the example below and the co-routine section + * of the WEB documentation for further information. + * + * @return pdPASS if the co-routine was successfully created and added to a ready + * list, otherwise an error code defined with ProjDefs.h. + * + * Example usage: +
+ // Co-routine to be created.
+ void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // This co-routine just delays for a fixed period, then toggles
+         // an LED.  Two co-routines are created using this function, so
+         // the uxIndex parameter is used to tell the co-routine which
+         // LED to flash and how int32_t to delay.  This assumes xQueue has
+         // already been created.
+         vParTestToggleLED( cLedToFlash[ uxIndex ] );
+         crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ uint8_t ucParameterToPass;
+ TaskHandle_t xHandle;
+
+     // Create two co-routines at priority 0.  The first is given index 0
+     // so (from the code above) toggles LED 5 every 200 ticks.  The second
+     // is given index 1 so toggles LED 6 every 400 ticks.
+     for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+     {
+         xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+     }
+ }
+   
+ * \defgroup xCoRoutineCreate xCoRoutineCreate + * \ingroup Tasks + */ +BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex ); + + +/** + * croutine. h + *
+ void vCoRoutineSchedule( void );
+ * + * Run a co-routine. + * + * vCoRoutineSchedule() executes the highest priority co-routine that is able + * to run. The co-routine will execute until it either blocks, yields or is + * preempted by a task. Co-routines execute cooperatively so one + * co-routine cannot be preempted by another, but can be preempted by a task. + * + * If an application comprises of both tasks and co-routines then + * vCoRoutineSchedule should be called from the idle task (in an idle task + * hook). + * + * Example usage: +
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+	vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+    for( ;; )
+    {
+        vCoRoutineSchedule();
+    }
+ }
+ 
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule + * \ingroup Tasks + */ +void vCoRoutineSchedule( void ); + +/** + * croutine. h + *
+ crSTART( CoRoutineHandle_t xHandle );
+ * + * This macro MUST always be called at the start of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static int32_t ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0: + +/** + * croutine. h + *
+ crEND();
+ * + * This macro MUST always be called at the end of a co-routine function. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static int32_t ulAVariable;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+          // Co-routine functionality goes here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crSTART crSTART + * \ingroup Tasks + */ +#define crEND() } + +/* + * These macros are intended for internal use by the co-routine implementation + * only. The macros should not be used directly by application writers. + */ +#define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2): +#define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1): + +/** + * croutine. h + *
+ crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );
+ * + * Delay a co-routine for a fixed period of time. + * + * crDELAY can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * @param xHandle The handle of the co-routine to delay. This is the xHandle + * parameter of the co-routine function. + * + * @param xTickToDelay The number of ticks that the co-routine should delay + * for. The actual amount of time this equates to is defined by + * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS + * can be used to convert ticks to milliseconds. + * + * Example usage: +
+ // Co-routine to be created.
+ void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
+
+     // Must start every co-routine with a call to crSTART();
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+        // Delay for 200ms.
+        crDELAY( xHandle, xDelayTime );
+
+        // Do something here.
+     }
+
+     // Must end every co-routine with a call to crEND();
+     crEND();
+ }
+ * \defgroup crDELAY crDELAY + * \ingroup Tasks + */ +#define crDELAY( xHandle, xTicksToDelay ) \ + if( ( xTicksToDelay ) > 0 ) \ + { \ + vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \ + } \ + crSET_STATE0( ( xHandle ) ); + +/** + *
+ crQUEUE_SEND(
+                  CoRoutineHandle_t xHandle,
+                  QueueHandle_t pxQueue,
+                  void *pvItemToQueue,
+                  TickType_t xTicksToWait,
+                  BaseType_t *pxResult
+             )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_SEND can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue on which the data will be posted. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvItemToQueue A pointer to the data being posted onto the queue. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied from pvItemToQueue into the queue + * itself. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for space to become available on the queue, should space not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example + * below). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully posted onto the queue, otherwise it will be set to an + * error defined within ProjDefs.h. + * + * Example usage: +
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static BaseType_t xNumberToPost = 0;
+ static BaseType_t xResult;
+
+    // Co-routines must begin with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // This assumes the queue has already been created.
+        crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+        if( xResult != pdPASS )
+        {
+            // The message was not posted!
+        }
+
+        // Increment the number to be posted onto the queue.
+        xNumberToPost++;
+
+        // Delay for 100 ticks.
+        crDELAY( xHandle, 100 );
+    }
+
+    // Co-routines must end with a call to crEND().
+    crEND();
+ }
+ * \defgroup crQUEUE_SEND crQUEUE_SEND + * \ingroup Tasks + */ +#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \ + } \ + if( *pxResult == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *pxResult = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_RECEIVE(
+                     CoRoutineHandle_t xHandle,
+                     QueueHandle_t pxQueue,
+                     void *pvBuffer,
+                     TickType_t xTicksToWait,
+                     BaseType_t *pxResult
+                 )
+ * + * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine + * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks. + * + * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas + * xQueueSend() and xQueueReceive() can only be used from tasks. + * + * crQUEUE_RECEIVE can only be called from the co-routine function itself - not + * from within a function called by the co-routine function. This is because + * co-routines do not maintain their own stack. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xHandle The handle of the calling co-routine. This is the xHandle + * parameter of the co-routine function. + * + * @param pxQueue The handle of the queue from which the data will be received. + * The handle is obtained as the return value when the queue is created using + * the xQueueCreate() API function. + * + * @param pvBuffer The buffer into which the received item is to be copied. + * The number of bytes of each queued item is specified when the queue is + * created. This number of bytes is copied into pvBuffer. + * + * @param xTickToDelay The number of ticks that the co-routine should block + * to wait for data to become available from the queue, should data not be + * available immediately. The actual amount of time this equates to is defined + * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant + * portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the + * crQUEUE_SEND example). + * + * @param pxResult The variable pointed to by pxResult will be set to pdPASS if + * data was successfully retrieved from the queue, otherwise it will be set to + * an error code as defined within ProjDefs.h. + * + * Example usage: +
+ // A co-routine receives the number of an LED to flash from a queue.  It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static BaseType_t xResult;
+ static UBaseType_t uxLEDToFlash;
+
+    // All co-routines must start with a call to crSTART().
+    crSTART( xHandle );
+
+    for( ;; )
+    {
+        // Wait for data to become available on the queue.
+        crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+        if( xResult == pdPASS )
+        {
+            // We received the LED to flash - flash it!
+            vParTestToggleLED( uxLEDToFlash );
+        }
+    }
+
+    crEND();
+ }
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \ +{ \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \ + if( *( pxResult ) == errQUEUE_BLOCKED ) \ + { \ + crSET_STATE0( ( xHandle ) ); \ + *( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \ + } \ + if( *( pxResult ) == errQUEUE_YIELD ) \ + { \ + crSET_STATE1( ( xHandle ) ); \ + *( pxResult ) = pdPASS; \ + } \ +} + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            QueueHandle_t pxQueue,
+                            void *pvItemToQueue,
+                            BaseType_t xCoRoutinePreviouslyWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue + * that is being used from within a co-routine. + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. + * + * @return pdTRUE if a co-routine was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage: +
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ char cRxedChar;
+ BaseType_t xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Wait for data to become available on the queue.  This assumes the
+         // queue xCommsRxQueue has already been created!
+         crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+         // Was a character received?
+         if( xResult == pdPASS )
+         {
+             // Process the character here.
+         }
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ char cRxedChar;
+ BaseType_t xCRWokenByPost = pdFALSE;
+
+     // We loop around reading characters until there are none left in the UART.
+     while( UART_RX_REG_NOT_EMPTY() )
+     {
+         // Obtain the character from the UART.
+         cRxedChar = UART_RX_REG;
+
+         // Post the character onto a queue.  xCRWokenByPost will be pdFALSE
+         // the first time around the loop.  If the post causes a co-routine
+         // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+         // In this manner we can ensure that if more than one co-routine is
+         // blocked on the queue only one is woken by this ISR no matter how
+         // many characters are posted to the queue.
+         xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+     }
+ }
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) ) + + +/** + * croutine. h + *
+  crQUEUE_SEND_FROM_ISR(
+                            QueueHandle_t pxQueue,
+                            void *pvBuffer,
+                            BaseType_t * pxCoRoutineWoken
+                       )
+ * + * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the + * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR() + * functions used by tasks. + * + * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to + * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and + * xQueueReceiveFromISR() can only be used to pass data between a task and and + * ISR. + * + * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data + * from a queue that is being used from within a co-routine (a co-routine + * posted to the queue). + * + * See the co-routine section of the WEB documentation for information on + * passing data between tasks and co-routines and between ISR's and + * co-routines. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvBuffer A pointer to a buffer into which the received item will be + * placed. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from the queue into + * pvBuffer. + * + * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become + * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a + * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise + * *pxCoRoutineWoken will remain unchanged. + * + * @return pdTRUE an item was successfully received from the queue, otherwise + * pdFALSE. + * + * Example usage: +
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period.  The character is incremented each time.
+ static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static char cCharToTx = 'a';
+ BaseType_t xResult;
+
+     // All co-routines must start with a call to crSTART().
+     crSTART( xHandle );
+
+     for( ;; )
+     {
+         // Send the next character to the queue.
+         crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+         if( xResult == pdPASS )
+         {
+             // The character was successfully posted to the queue.
+         }
+		 else
+		 {
+			// Could not post the character to the queue.
+		 }
+
+         // Enable the UART Tx interrupt to cause an interrupt in this
+		 // hypothetical UART.  The interrupt will obtain the character
+		 // from the queue and send it.
+		 ENABLE_RX_INTERRUPT();
+
+		 // Increment to the next character then block for a fixed period.
+		 // cCharToTx will maintain its value across the delay as it is
+		 // declared static.
+		 cCharToTx++;
+		 if( cCharToTx > 'x' )
+		 {
+			cCharToTx = 'a';
+		 }
+		 crDELAY( 100 );
+     }
+
+     // All co-routines must end with a call to crEND().
+     crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ char cCharToTx;
+ BaseType_t xCRWokenByPost = pdFALSE;
+
+     while( UART_TX_REG_EMPTY() )
+     {
+         // Are there any characters in the queue waiting to be sent?
+		 // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+		 // is woken by the post - ensuring that only a single co-routine is
+		 // woken no matter how many times we go around this loop.
+         if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+		 {
+			 SEND_CHARACTER( cCharToTx );
+		 }
+     }
+ }
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR + * \ingroup Tasks + */ +#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) ) + +/* + * This function is intended for internal use by the co-routine macros only. + * The macro nature of the co-routine implementation requires that the + * prototype appears here. The function should not be used by application + * writers. + * + * Removes the current co-routine from its ready list and places it in the + * appropriate delayed list. + */ +void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList ); + +/* + * This function is intended for internal use by the queue implementation only. + * The function should not be used by application writers. + * + * Removes the highest priority co-routine from the event list and places it in + * the pending ready list. + */ +BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList ); + +#ifdef __cplusplus +} +#endif + +#endif /* CO_ROUTINE_H */ diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/deprecated_definitions.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/deprecated_definitions.h new file mode 100755 index 0000000..4ea816c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/deprecated_definitions.h @@ -0,0 +1,321 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEPRECATED_DEFINITIONS_H +#define DEPRECATED_DEFINITIONS_H + + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. The +definitions below remain in the code for backward compatibility only. New +projects should not use them. */ + +#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT + #include "..\..\Source\portable\owatcom\16bitdos\pc\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT + #include "..\..\Source\portable\owatcom\16bitdos\flsh186\portmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef GCC_MEGA_AVR + #include "../portable/GCC/ATMega323/portmacro.h" +#endif + +#ifdef IAR_MEGA_AVR + #include "../portable/IAR/ATMega323/portmacro.h" +#endif + +#ifdef MPLAB_PIC24_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_DSPIC_PORT + #include "../../Source/portable/MPLAB/PIC24_dsPIC/portmacro.h" +#endif + +#ifdef MPLAB_PIC18F_PORT + #include "../../Source/portable/MPLAB/PIC18F/portmacro.h" +#endif + +#ifdef MPLAB_PIC32MX_PORT + #include "../../Source/portable/MPLAB/PIC32MX/portmacro.h" +#endif + +#ifdef _FEDPICC + #include "libFreeRTOS/Include/portmacro.h" +#endif + +#ifdef SDCC_CYGNAL + #include "../../Source/portable/SDCC/Cygnal/portmacro.h" +#endif + +#ifdef GCC_ARM7 + #include "../../Source/portable/GCC/ARM7_LPC2000/portmacro.h" +#endif + +#ifdef GCC_ARM7_ECLIPSE + #include "portmacro.h" +#endif + +#ifdef ROWLEY_LPC23xx + #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h" +#endif + +#ifdef IAR_MSP430 + #include "..\..\Source\portable\IAR\MSP430\portmacro.h" +#endif + +#ifdef GCC_MSP430 + #include "../../Source/portable/GCC/MSP430F449/portmacro.h" +#endif + +#ifdef ROWLEY_MSP430 + #include "../../Source/portable/Rowley/MSP430F449/portmacro.h" +#endif + +#ifdef ARM7_LPC21xx_KEIL_RVDS + #include "..\..\Source\portable\RVDS\ARM7_LPC21xx\portmacro.h" +#endif + +#ifdef SAM7_GCC + #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h" +#endif + +#ifdef SAM7_IAR + #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h" +#endif + +#ifdef SAM9XE_IAR + #include "..\..\Source\portable\IAR\AtmelSAM9XE\portmacro.h" +#endif + +#ifdef LPC2000_IAR + #include "..\..\Source\portable\IAR\LPC2000\portmacro.h" +#endif + +#ifdef STR71X_IAR + #include "..\..\Source\portable\IAR\STR71x\portmacro.h" +#endif + +#ifdef STR75X_IAR + #include "..\..\Source\portable\IAR\STR75x\portmacro.h" +#endif + +#ifdef STR75X_GCC + #include "..\..\Source\portable\GCC\STR75x\portmacro.h" +#endif + +#ifdef STR91X_IAR + #include "..\..\Source\portable\IAR\STR91x\portmacro.h" +#endif + +#ifdef GCC_H8S + #include "../../Source/portable/GCC/H8S2329/portmacro.h" +#endif + +#ifdef GCC_AT91FR40008 + #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h" +#endif + +#ifdef RVDS_ARMCM3_LM3S102 + #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3_LM3S102 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef GCC_ARMCM3 + #include "../../Source/portable/GCC/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARM_CM3 + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef IAR_ARMCM3_LM + #include "../../Source/portable/IAR/ARM_CM3/portmacro.h" +#endif + +#ifdef HCS12_CODE_WARRIOR + #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h" +#endif + +#ifdef MICROBLAZE_GCC + #include "../../Source/portable/GCC/MicroBlaze/portmacro.h" +#endif + +#ifdef TERN_EE + #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h" +#endif + +#ifdef GCC_HCS12 + #include "../../Source/portable/GCC/HCS12/portmacro.h" +#endif + +#ifdef GCC_MCF5235 + #include "../../Source/portable/GCC/MCF5235/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_GCC + #include "../../../Source/portable/GCC/ColdFire_V2/portmacro.h" +#endif + +#ifdef COLDFIRE_V2_CODEWARRIOR + #include "../../Source/portable/CodeWarrior/ColdFire_V2/portmacro.h" +#endif + +#ifdef GCC_PPC405 + #include "../../Source/portable/GCC/PPC405_Xilinx/portmacro.h" +#endif + +#ifdef GCC_PPC440 + #include "../../Source/portable/GCC/PPC440_Xilinx/portmacro.h" +#endif + +#ifdef _16FX_SOFTUNE + #include "..\..\Source\portable\Softune\MB96340\portmacro.h" +#endif + +#ifdef BCC_INDUSTRIAL_PC_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\PC\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef BCC_FLASH_LITE_186_PORT + /* A short file name has to be used in place of the normal + FreeRTOSConfig.h when using the Borland compiler. */ + #include "frconfig.h" + #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h" + typedef void ( __interrupt __far *pxISR )(); +#endif + +#ifdef __GNUC__ + #ifdef __AVR32_AVR32A__ + #include "portmacro.h" + #endif +#endif + +#ifdef __ICCAVR32__ + #ifdef __CORE__ + #if __CORE__ == __AVR32A__ + #include "portmacro.h" + #endif + #endif +#endif + +#ifdef __91467D + #include "portmacro.h" +#endif + +#ifdef __96340 + #include "portmacro.h" +#endif + + +#ifdef __IAR_V850ES_Fx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx3_L__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Jx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_V850ES_Hx2__ + #include "../../Source/portable/IAR/V850ES/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#ifdef __IAR_78K0R_Kx3L__ + #include "../../Source/portable/IAR/78K0R/portmacro.h" +#endif + +#endif /* DEPRECATED_DEFINITIONS_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/event_groups.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/event_groups.h new file mode 100755 index 0000000..7331c91 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/event_groups.h @@ -0,0 +1,797 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef EVENT_GROUPS_H +#define EVENT_GROUPS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include event_groups.h" +#endif + +/* FreeRTOS includes. */ +#include "timers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An event group is a collection of bits to which an application can assign a + * meaning. For example, an application may create an event group to convey + * the status of various CAN bus related events in which bit 0 might mean "A CAN + * message has been received and is ready for processing", bit 1 might mean "The + * application has queued a message that is ready for sending onto the CAN + * network", and bit 2 might mean "It is time to send a SYNC message onto the + * CAN network" etc. A task can then test the bit values to see which events + * are active, and optionally enter the Blocked state to wait for a specified + * bit or a group of specified bits to be active. To continue the CAN bus + * example, a CAN controlling task can enter the Blocked state (and therefore + * not consume any processing time) until either bit 0, bit 1 or bit 2 are + * active, at which time the bit that was actually active would inform the task + * which action it had to take (process a received message, send a message, or + * send a SYNC). + * + * The event groups implementation contains intelligence to avoid race + * conditions that would otherwise occur were an application to use a simple + * variable for the same purpose. This is particularly important with respect + * to when a bit within an event group is to be cleared, and when bits have to + * be set and then tested atomically - as is the case where event groups are + * used to create a synchronisation point between multiple tasks (a + * 'rendezvous'). + * + * \defgroup EventGroup + */ + + + +/** + * event_groups.h + * + * Type by which event groups are referenced. For example, a call to + * xEventGroupCreate() returns an EventGroupHandle_t variable that can then + * be used as a parameter to other event group functions. + * + * \defgroup EventGroupHandle_t EventGroupHandle_t + * \ingroup EventGroup + */ +typedef void * EventGroupHandle_t; + +/* + * The type that holds event bits always matches TickType_t - therefore the + * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, + * 32 bits if set to 0. + * + * \defgroup EventBits_t EventBits_t + * \ingroup EventGroup + */ +typedef TickType_t EventBits_t; + +/** + * event_groups.h + *
+ EventGroupHandle_t xEventGroupCreate( void );
+ 
+ * + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store + * event bits within an event group. + * + * @return If the event group was created then a handle to the event group is + * returned. If there was insufficient FreeRTOS heap available to create the + * event group then NULL is returned. See http://www.freertos.org/a00111.html + * + * Example usage: +
+	// Declare a variable to hold the created event group.
+	EventGroupHandle_t xCreatedEventGroup;
+
+	// Attempt to create the event group.
+	xCreatedEventGroup = xEventGroupCreate();
+
+	// Was the event group created successfully?
+	if( xCreatedEventGroup == NULL )
+	{
+		// The event group was not created because there was insufficient
+		// FreeRTOS heap available.
+	}
+	else
+	{
+		// The event group was created.
+	}
+   
+ * \defgroup xEventGroupCreate xEventGroupCreate + * \ingroup EventGroup + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; +#endif + +/** + * event_groups.h + *
+ EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
+ 
+ * + * Create a new event group. + * + * Internally, within the FreeRTOS implementation, event groups use a [small] + * block of memory, in which the event group's structure is stored. If an event + * groups is created using xEventGropuCreate() then the required memory is + * automatically dynamically allocated inside the xEventGroupCreate() function. + * (see http://www.freertos.org/a00111.html). If an event group is created + * using xEventGropuCreateStatic() then the application writer must instead + * provide the memory that will get used by the event group. + * xEventGroupCreateStatic() therefore allows an event group to be created + * without using any dynamic memory allocation. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store + * event bits within an event group. + * + * @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type + * StaticEventGroup_t, which will be then be used to hold the event group's data + * structures, removing the need for the memory to be allocated dynamically. + * + * @return If the event group was created then a handle to the event group is + * returned. If pxEventGroupBuffer was NULL then NULL is returned. + * + * Example usage: +
+	// StaticEventGroup_t is a publicly accessible structure that has the same
+	// size and alignment requirements as the real event group structure.  It is
+	// provided as a mechanism for applications to know the size of the event
+	// group (which is dependent on the architecture and configuration file
+	// settings) without breaking the strict data hiding policy by exposing the
+	// real event group internals.  This StaticEventGroup_t variable is passed
+	// into the xSemaphoreCreateEventGroupStatic() function and is used to store
+	// the event group's data structures
+	StaticEventGroup_t xEventGroupBuffer;
+
+	// Create the event group without dynamically allocating any memory.
+	xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
+   
+ */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION; +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupWaitBits( 	EventGroupHandle_t xEventGroup,
+										const EventBits_t uxBitsToWaitFor,
+										const BaseType_t xClearOnExit,
+										const BaseType_t xWaitForAllBits,
+										const TickType_t xTicksToWait );
+ 
+ * + * [Potentially] block to wait for one or more bits to be set within a + * previously created event group. + * + * This function cannot be called from an interrupt. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and/or bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within + * uxBitsToWaitFor that are set within the event group will be cleared before + * xEventGroupWaitBits() returns if the wait condition was met (if the function + * returns for a reason other than a timeout). If xClearOnExit is set to + * pdFALSE then the bits set in the event group are not altered when the call to + * xEventGroupWaitBits() returns. + * + * @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then + * xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor + * are set or the specified block time expires. If xWaitForAllBits is set to + * pdFALSE then xEventGroupWaitBits() will return when any one of the bits set + * in uxBitsToWaitFor is set or the specified block time expires. The block + * time is specified by the xTicksToWait parameter. + * + * @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait + * for one/all (depending on the xWaitForAllBits value) of the bits specified by + * uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupWaitBits() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupWaitBits() returned because the bits it was waiting for were set + * then the returned value is the event group value before any bits were + * automatically cleared in the case that xClearOnExit parameter was set to + * pdTRUE. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+   const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
+
+		// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
+		// the event group.  Clear the bits before exiting.
+		uxBits = xEventGroupWaitBits(
+					xEventGroup,	// The event group being tested.
+					BIT_0 | BIT_4,	// The bits within the event group to wait for.
+					pdTRUE,			// BIT_0 and BIT_4 should be cleared before returning.
+					pdFALSE,		// Don't wait for both bits, either bit will do.
+					xTicksToWait );	// Wait a maximum of 100ms for either bit to be set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// xEventGroupWaitBits() returned because both bits were set.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_0 was set.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_4 was set.
+		}
+		else
+		{
+			// xEventGroupWaitBits() returned because xTicksToWait ticks passed
+			// without either BIT_0 or BIT_4 becoming set.
+		}
+   }
+   
+ * \defgroup xEventGroupWaitBits xEventGroupWaitBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
+ 
+ * + * Clear bits within an event group. This function cannot be called from an + * interrupt. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear + * in the event group. For example, to clear bit 3 only, set uxBitsToClear to + * 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09. + * + * @return The value of the event group before the specified bits were cleared. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+
+		// Clear bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupClearBits(
+								xEventGroup,	// The event group being updated.
+								BIT_0 | BIT_4 );// The bits being cleared.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
+			// called.  Both will now be clear (not set).
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 were set in the first place.
+		}
+   }
+   
+ * \defgroup xEventGroupClearBits xEventGroupClearBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
+ 
+ * + * A version of xEventGroupClearBits() that can be called from an interrupt. + * + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed + * while interrupts are disabled, so protects event groups that are accessed + * from tasks by suspending the scheduler rather than disabling interrupts. As + * a result event groups cannot be accessed directly from an interrupt service + * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the + * timer task to have the clear operation performed in the context of the timer + * task. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear. + * For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3 + * and bit 0 set uxBitsToClear to 0x09. + * + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * if the timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assumed has already been created by a call to
+   // xEventGroupCreate().
+   EventGroupHandle_t xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+		// Clear bit 0 and bit 4 in xEventGroup.
+		xResult = xEventGroupClearBitsFromISR(
+							xEventGroup,	 // The event group being updated.
+							BIT_0 | BIT_4 ); // The bits being set.
+
+		if( xResult == pdPASS )
+		{
+			// The message was posted successfully.
+		}
+  }
+   
+ * \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR + * \ingroup EventGroup + */ +#if( configUSE_TRACE_FACILITY == 1 ) + BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; +#else + #define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL ) +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
+ 
+ * + * Set bits within an event group. + * This function cannot be called from an interrupt. xEventGroupSetBitsFromISR() + * is a version that can be called from an interrupt. + * + * Setting bits in an event group will automatically unblock tasks that are + * blocked waiting for the bits. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @return The value of the event group at the time the call to + * xEventGroupSetBits() returns. There are two reasons why the returned value + * might have the bits specified by the uxBitsToSet parameter cleared. First, + * if setting a bit results in a task that was waiting for the bit leaving the + * blocked state then it is possible the bit will be cleared automatically + * (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any + * unblocked (or otherwise Ready state) task that has a priority above that of + * the task that called xEventGroupSetBits() will execute and may change the + * event group value before the call to xEventGroupSetBits() returns. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( EventGroupHandle_t xEventGroup )
+   {
+   EventBits_t uxBits;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupSetBits(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4 );// The bits being set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 remained set when the function returned.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 remained set when the function returned, but bit 4 was
+			// cleared.  It might be that bit 4 was cleared automatically as a
+			// task that was waiting for bit 4 was removed from the Blocked
+			// state.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 remained set when the function returned, but bit 0 was
+			// cleared.  It might be that bit 0 was cleared automatically as a
+			// task that was waiting for bit 0 was removed from the Blocked
+			// state.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 remained set.  It might be that a task
+			// was waiting for both of the bits to be set, and the bits were
+			// cleared as the task left the Blocked state.
+		}
+   }
+   
+ * \defgroup xEventGroupSetBits xEventGroupSetBits + * \ingroup EventGroup + */ +EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
+ 
+ * + * A version of xEventGroupSetBits() that can be called from an interrupt. + * + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed in + * interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR() + * sends a message to the timer task to have the set operation performed in the + * context of the timer task - where a scheduler lock is used in place of a + * critical section. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @param pxHigherPriorityTaskWoken As mentioned above, calling this function + * will result in a message being sent to the timer daemon task. If the + * priority of the timer daemon task is higher than the priority of the + * currently running task (the task the interrupt interrupted) then + * *pxHigherPriorityTaskWoken will be set to pdTRUE by + * xEventGroupSetBitsFromISR(), indicating that a context switch should be + * requested before the interrupt exits. For that reason + * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * if the timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assumed has already been created by a call to
+   // xEventGroupCreate().
+   EventGroupHandle_t xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+   BaseType_t xHigherPriorityTaskWoken, xResult;
+
+		// xHigherPriorityTaskWoken must be initialised to pdFALSE.
+		xHigherPriorityTaskWoken = pdFALSE;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		xResult = xEventGroupSetBitsFromISR(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4   // The bits being set.
+							&xHigherPriorityTaskWoken );
+
+		// Was the message posted successfully?
+		if( xResult == pdPASS )
+		{
+			// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
+			// switch should be requested.  The macro used is port specific and
+			// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
+			// refer to the documentation page for the port being used.
+			portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+		}
+  }
+   
+ * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR + * \ingroup EventGroup + */ +#if( configUSE_TRACE_FACILITY == 1 ) + BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; +#else + #define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken ) +#endif + +/** + * event_groups.h + *
+	EventBits_t xEventGroupSync(	EventGroupHandle_t xEventGroup,
+									const EventBits_t uxBitsToSet,
+									const EventBits_t uxBitsToWaitFor,
+									TickType_t xTicksToWait );
+ 
+ * + * Atomically set bits within an event group, then wait for a combination of + * bits to be set within the same event group. This functionality is typically + * used to synchronise multiple tasks, where each task has to wait for the other + * tasks to reach a synchronisation point before proceeding. + * + * This function cannot be used from an interrupt. + * + * The function will return before its block time expires if the bits specified + * by the uxBitsToWait parameter are set, or become set within that time. In + * this case all the bits specified by uxBitsToWait will be automatically + * cleared before the function returns. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToSet The bits to set in the event group before determining + * if, and possibly waiting for, all the bits specified by the uxBitsToWait + * parameter are set. + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait + * for all of the bits specified by uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupSync() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupSync() returned because all the bits it was waiting for were + * set then the returned value is the event group value before any bits were + * automatically cleared. + * + * Example usage: +
+ // Bits used by the three tasks.
+ #define TASK_0_BIT		( 1 << 0 )
+ #define TASK_1_BIT		( 1 << 1 )
+ #define TASK_2_BIT		( 1 << 2 )
+
+ #define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
+
+ // Use an event group to synchronise three tasks.  It is assumed this event
+ // group has already been created elsewhere.
+ EventGroupHandle_t xEventBits;
+
+ void vTask0( void *pvParameters )
+ {
+ EventBits_t uxReturn;
+ TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
+
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 0 in the event flag to note this task has reached the
+		// sync point.  The other two tasks will set the other two bits defined
+		// by ALL_SYNC_BITS.  All three tasks have reached the synchronisation
+		// point when all the ALL_SYNC_BITS are set.  Wait a maximum of 100ms
+		// for this to happen.
+		uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
+
+		if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
+		{
+			// All three tasks reached the synchronisation point before the call
+			// to xEventGroupSync() timed out.
+		}
+	}
+ }
+
+ void vTask1( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 1 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	 }
+ }
+
+ void vTask2( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 2 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	}
+ }
+
+ 
+ * \defgroup xEventGroupSync xEventGroupSync + * \ingroup EventGroup + */ +EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + + +/** + * event_groups.h + *
+	EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
+ 
+ * + * Returns the current value of the bits in an event group. This function + * cannot be used from an interrupt. + * + * @param xEventGroup The event group being queried. + * + * @return The event group bits at the time xEventGroupGetBits() was called. + * + * \defgroup xEventGroupGetBits xEventGroupGetBits + * \ingroup EventGroup + */ +#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 ) + +/** + * event_groups.h + *
+	EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
+ 
+ * + * A version of xEventGroupGetBits() that can be called from an ISR. + * + * @param xEventGroup The event group being queried. + * + * @return The event group bits at the time xEventGroupGetBitsFromISR() was called. + * + * \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR + * \ingroup EventGroup + */ +EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	void xEventGroupDelete( EventGroupHandle_t xEventGroup );
+ 
+ * + * Delete an event group that was previously created by a call to + * xEventGroupCreate(). Tasks that are blocked on the event group will be + * unblocked and obtain 0 as the event group's value. + * + * @param xEventGroup The event group being deleted. + */ +void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; + +/* For internal use only. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION; +void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; + + +#if (configUSE_TRACE_FACILITY == 1) + UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT_GROUPS_H */ + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/list.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/list.h new file mode 100755 index 0000000..a080d27 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/list.h @@ -0,0 +1,453 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This is the list implementation used by the scheduler. While it is tailored + * heavily for the schedulers needs, it is also available for use by + * application code. + * + * list_ts can only store pointers to list_item_ts. Each ListItem_t contains a + * numeric value (xItemValue). Most of the time the lists are sorted in + * descending item value order. + * + * Lists are created already containing one list item. The value of this + * item is the maximum possible that can be stored, it is therefore always at + * the end of the list and acts as a marker. The list member pxHead always + * points to this marker - even though it is at the tail of the list. This + * is because the tail contains a wrap back pointer to the true head of + * the list. + * + * In addition to it's value, each list item contains a pointer to the next + * item in the list (pxNext), a pointer to the list it is in (pxContainer) + * and a pointer to back to the object that contains it. These later two + * pointers are included for efficiency of list manipulation. There is + * effectively a two way link between the object containing the list item and + * the list item itself. + * + * + * \page ListIntroduction List Implementation + * \ingroup FreeRTOSIntro + */ + +#ifndef INC_FREERTOS_H + #error FreeRTOS.h must be included before list.h +#endif + +#ifndef LIST_H +#define LIST_H + +/* + * The list structure members are modified from within interrupts, and therefore + * by rights should be declared volatile. However, they are only modified in a + * functionally atomic way (within critical sections of with the scheduler + * suspended) and are either passed by reference into a function or indexed via + * a volatile variable. Therefore, in all use cases tested so far, the volatile + * qualifier can be omitted in order to provide a moderate performance + * improvement without adversely affecting functional behaviour. The assembly + * instructions generated by the IAR, ARM and GCC compilers when the respective + * compiler's options were set for maximum optimisation has been inspected and + * deemed to be as intended. That said, as compiler technology advances, and + * especially if aggressive cross module optimisation is used (a use case that + * has not been exercised to any great extend) then it is feasible that the + * volatile qualifier will be needed for correct optimisation. It is expected + * that a compiler removing essential code because, without the volatile + * qualifier on the list structure members and with aggressive cross module + * optimisation, the compiler deemed the code unnecessary will result in + * complete and obvious failure of the scheduler. If this is ever experienced + * then the volatile qualifier can be inserted in the relevant places within the + * list structures by simply defining configLIST_VOLATILE to volatile in + * FreeRTOSConfig.h (as per the example at the bottom of this comment block). + * If configLIST_VOLATILE is not defined then the preprocessor directives below + * will simply #define configLIST_VOLATILE away completely. + * + * To use volatile list structure members then add the following line to + * FreeRTOSConfig.h (without the quotes): + * "#define configLIST_VOLATILE volatile" + */ +#ifndef configLIST_VOLATILE + #define configLIST_VOLATILE +#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Macros that can be used to place known values within the list structures, +then check that the known values do not get corrupted during the execution of +the application. These may catch the list data structures being overwritten in +memory. They will not catch data errors caused by incorrect configuration or +use of FreeRTOS.*/ +#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) + /* Define the macros to do nothing. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) + #define listTEST_LIST_INTEGRITY( pxList ) +#else + /* Define macros that add new members into the list structures. */ + #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1; + #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2; + #define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1; + #define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2; + + /* Define macros that set the new structure members to known values. */ + #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE + #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE + + /* Define macros that will assert if one of the structure members does not + contain its expected value. */ + #define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) + #define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) ) +#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */ + + +/* + * Definition of the only type of object that a list can contain. + */ +struct xLIST_ITEM +{ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ + struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ + void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ + void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */ + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +}; +typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ + +struct xMINI_LIST_ITEM +{ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; + struct xLIST_ITEM * configLIST_VOLATILE pxNext; + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; +}; +typedef struct xMINI_LIST_ITEM MiniListItem_t; + +/* + * Definition of the type of queue used by the scheduler. + */ +typedef struct xLIST +{ + listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE UBaseType_t uxNumberOfItems; + ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ + MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ +} List_t; + +/* + * Access macro to set the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) + +/* + * Access macro to get the owner of a list item. The owner of a list item + * is the object (usually a TCB) that contains the list item. + * + * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) + +/* + * Access macro to set the value of the list item. In most cases the value is + * used to sort the list in descending order. + * + * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) ) + +/* + * Access macro to retrieve the value of the list item. The value can + * represent anything - for example the priority of a task, or the time at + * which a task should be unblocked. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue ) + +/* + * Access macro to retrieve the value of the list item at the head of a given + * list. + * + * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE + * \ingroup LinkedList + */ +#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_NEXT listGET_NEXT + * \ingroup LinkedList + */ +#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext ) + +/* + * Return the list item that marks the end of the list + * + * \page listGET_END_MARKER listGET_END_MARKER + * \ingroup LinkedList + */ +#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) ) + +/* + * Access macro to determine if a list contains any items. The macro will + * only have the value true if the list is empty. + * + * \page listLIST_IS_EMPTY listLIST_IS_EMPTY + * \ingroup LinkedList + */ +#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ) + +/* + * Access macro to return the number of items in the list. + */ +#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) + +/* + * Access function to obtain the owner of the next entry in a list. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list + * and returns that entry's pxOwner parameter. Using multiple calls to this + * function it is therefore possible to move through every item contained in + * a list. + * + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxTCB pxTCB is set to the address of the owner of the next list item. + * @param pxList The list from which the next item owner is to be returned. + * + * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \ +{ \ +List_t * const pxConstList = ( pxList ); \ + /* Increment the index to the next item and return the item, ensuring */ \ + /* we don't return the marker used at the end of the list. */ \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \ + { \ + ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \ + } \ + ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ +} + + +/* + * Access function to obtain the owner of the first entry in a list. Lists + * are normally sorted in ascending item value order. + * + * This function returns the pxOwner member of the first item in the list. + * The pxOwner parameter of a list item is a pointer to the object that owns + * the list item. In the scheduler this is normally a task control block. + * The pxOwner parameter effectively creates a two way link between the list + * item and its owner. + * + * @param pxList The list from which the owner of the head item is to be + * returned. + * + * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) + +/* + * Check to see if a list item is within a list. The list item maintains a + * "container" pointer that points to the list it is in. All this macro does + * is check to see if the container and the list match. + * + * @param pxList The list we want to know if the list item is within. + * @param pxListItem The list item we want to know if is in the list. + * @return pdTRUE if the list item is in the list, otherwise pdFALSE. + */ +#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) + +/* + * Return the list a list item is contained within (referenced from). + * + * @param pxListItem The list item being queried. + * @return A pointer to the List_t object that references the pxListItem + */ +#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) + +/* + * This provides a crude means of knowing if a list has been initialised, as + * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise() + * function. + */ +#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY ) + +/* + * Must be called before a list is used! This initialises all the members + * of the list structure and inserts the xListEnd item into the list as a + * marker to the back of the list. + * + * @param pxList Pointer to the list being initialised. + * + * \page vListInitialise vListInitialise + * \ingroup LinkedList + */ +void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION; + +/* + * Must be called before a list item is used. This sets the list container to + * null so the item does not think that it is already contained in a list. + * + * @param pxItem Pointer to the list item being initialised. + * + * \page vListInitialiseItem vListInitialiseItem + * \ingroup LinkedList + */ +void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted into the list in + * a position determined by its item value (descending item value order). + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The item that is to be placed in the list. + * + * \page vListInsert vListInsert + * \ingroup LinkedList + */ +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; + +/* + * Insert a list item into a list. The item will be inserted in a position + * such that it will be the last item within the list returned by multiple + * calls to listGET_OWNER_OF_NEXT_ENTRY. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list. + * Placing an item in a list using vListInsertEnd effectively places the item + * in the list position pointed to by pxIndex. This means that every other + * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before + * the pxIndex parameter again points to the item being inserted. + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The list item to be inserted into the list. + * + * \page vListInsertEnd vListInsertEnd + * \ingroup LinkedList + */ +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION; + +/* + * Remove an item from a list. The list item has a pointer to the list that + * it is in, so only the list item need be passed into the function. + * + * @param uxListRemove The item to be removed. The item will remove itself from + * the list pointed to by it's pxContainer parameter. + * + * @return The number of items that remain in the list after the list item has + * been removed. + * + * \page uxListRemove uxListRemove + * \ingroup LinkedList + */ +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_prototypes.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_prototypes.h new file mode 100755 index 0000000..8f7500b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_prototypes.h @@ -0,0 +1,177 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * When the MPU is used the standard (non MPU) API functions are mapped to + * equivalents that start "MPU_", the prototypes for which are defined in this + * header files. This will cause the application code to call the MPU_ version + * which wraps the non-MPU version with privilege promoting then demoting code, + * so the kernel code always runs will full privileges. + */ + + +#ifndef MPU_PROTOTYPES_H +#define MPU_PROTOTYPES_H + +/* MPU versions of tasks.h API function. */ +BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); +TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); +BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); +void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); +void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); +void MPU_vTaskDelay( const TickType_t xTicksToDelay ); +void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ); +BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask ); +UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t xTask ); +eTaskState MPU_eTaskGetState( TaskHandle_t xTask ); +void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ); +void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); +void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend ); +void MPU_vTaskResume( TaskHandle_t xTaskToResume ); +void MPU_vTaskStartScheduler( void ); +void MPU_vTaskSuspendAll( void ); +BaseType_t MPU_xTaskResumeAll( void ); +TickType_t MPU_xTaskGetTickCount( void ); +UBaseType_t MPU_uxTaskGetNumberOfTasks( void ); +char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery ); +TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery ); +UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); +void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ); +TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ); +void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ); +void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ); +BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); +TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ); +UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ); +void MPU_vTaskList( char * pcWriteBuffer ); +void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ); +BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ); +BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); +uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ); +BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ); +BaseType_t MPU_xTaskIncrementTick( void ); +TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ); +void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ); +BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ); +void MPU_vTaskMissedYield( void ); +BaseType_t MPU_xTaskGetSchedulerState( void ); + +/* MPU versions of queue.h API function. */ +BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); +BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); +UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); +UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); +void MPU_vQueueDelete( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ); +QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ); +QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ); +void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); +BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex ); +void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ); +void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue ); +const char * MPU_pcQueueGetName( QueueHandle_t xQueue ); +QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ); +QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ); +QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength ); +BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); +QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ); +BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ); +void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ); +UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue ); +uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue ); + +/* MPU versions of timers.h API function. */ +TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ); +TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer ); +void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer ); +void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); +BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer ); +TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ); +BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ); +const char * MPU_pcTimerGetName( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ); +TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ); +BaseType_t MPU_xTimerCreateTimerTask( void ); +BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ); + +/* MPU versions of event_group.h API function. */ +EventGroupHandle_t MPU_xEventGroupCreate( void ); +EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ); +EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ); +EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ); +EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ); +EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ); +void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup ); +UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup ); + +#endif /* MPU_PROTOTYPES_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_wrappers.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_wrappers.h new file mode 100755 index 0000000..78f5a9a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/mpu_wrappers.h @@ -0,0 +1,201 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef MPU_WRAPPERS_H +#define MPU_WRAPPERS_H + +/* This file redefines API functions to be called through a wrapper macro, but +only for ports that are using the MPU. */ +#ifdef portUSING_MPU_WRAPPERS + + /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is + included from queue.c or task.c to prevent it from having an effect within + those files. */ + #ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + + /* + * Map standard (non MPU) API functions to equivalents that start + * "MPU_". This will cause the application code to call the MPU_ + * version, which wraps the non-MPU version with privilege promoting + * then demoting code, so the kernel code always runs will full + * privileges. + */ + + /* Map standard tasks.h API functions to the MPU equivalents. */ + #define xTaskCreate MPU_xTaskCreate + #define xTaskCreateStatic MPU_xTaskCreateStatic + #define xTaskCreateRestricted MPU_xTaskCreateRestricted + #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions + #define vTaskDelete MPU_vTaskDelete + #define vTaskDelay MPU_vTaskDelay + #define vTaskDelayUntil MPU_vTaskDelayUntil + #define xTaskAbortDelay MPU_xTaskAbortDelay + #define uxTaskPriorityGet MPU_uxTaskPriorityGet + #define eTaskGetState MPU_eTaskGetState + #define vTaskGetInfo MPU_vTaskGetInfo + #define vTaskPrioritySet MPU_vTaskPrioritySet + #define vTaskSuspend MPU_vTaskSuspend + #define vTaskResume MPU_vTaskResume + #define vTaskSuspendAll MPU_vTaskSuspendAll + #define xTaskResumeAll MPU_xTaskResumeAll + #define xTaskGetTickCount MPU_xTaskGetTickCount + #define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks + #define pcTaskGetName MPU_pcTaskGetName + #define xTaskGetHandle MPU_xTaskGetHandle + #define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark + #define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag + #define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag + #define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer + #define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer + #define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook + #define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle + #define uxTaskGetSystemState MPU_uxTaskGetSystemState + #define vTaskList MPU_vTaskList + #define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats + #define xTaskGenericNotify MPU_xTaskGenericNotify + #define xTaskNotifyWait MPU_xTaskNotifyWait + #define ulTaskNotifyTake MPU_ulTaskNotifyTake + #define xTaskNotifyStateClear MPU_xTaskNotifyStateClear + + #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle + #define vTaskSetTimeOutState MPU_vTaskSetTimeOutState + #define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut + #define xTaskGetSchedulerState MPU_xTaskGetSchedulerState + + /* Map standard queue.h API functions to the MPU equivalents. */ + #define xQueueGenericSend MPU_xQueueGenericSend + #define xQueueGenericReceive MPU_xQueueGenericReceive + #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting + #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable + #define vQueueDelete MPU_vQueueDelete + #define xQueueCreateMutex MPU_xQueueCreateMutex + #define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic + #define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore + #define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic + #define xQueueGetMutexHolder MPU_xQueueGetMutexHolder + #define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive + #define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive + #define xQueueGenericCreate MPU_xQueueGenericCreate + #define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic + #define xQueueCreateSet MPU_xQueueCreateSet + #define xQueueAddToSet MPU_xQueueAddToSet + #define xQueueRemoveFromSet MPU_xQueueRemoveFromSet + #define xQueueSelectFromSet MPU_xQueueSelectFromSet + #define xQueueGenericReset MPU_xQueueGenericReset + + #if( configQUEUE_REGISTRY_SIZE > 0 ) + #define vQueueAddToRegistry MPU_vQueueAddToRegistry + #define vQueueUnregisterQueue MPU_vQueueUnregisterQueue + #define pcQueueGetName MPU_pcQueueGetName + #endif + + /* Map standard timer.h API functions to the MPU equivalents. */ + #define xTimerCreate MPU_xTimerCreate + #define xTimerCreateStatic MPU_xTimerCreateStatic + #define pvTimerGetTimerID MPU_pvTimerGetTimerID + #define vTimerSetTimerID MPU_vTimerSetTimerID + #define xTimerIsTimerActive MPU_xTimerIsTimerActive + #define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle + #define xTimerPendFunctionCall MPU_xTimerPendFunctionCall + #define pcTimerGetName MPU_pcTimerGetName + #define xTimerGetPeriod MPU_xTimerGetPeriod + #define xTimerGetExpiryTime MPU_xTimerGetExpiryTime + #define xTimerGenericCommand MPU_xTimerGenericCommand + + /* Map standard event_group.h API functions to the MPU equivalents. */ + #define xEventGroupCreate MPU_xEventGroupCreate + #define xEventGroupCreateStatic MPU_xEventGroupCreateStatic + #define xEventGroupWaitBits MPU_xEventGroupWaitBits + #define xEventGroupClearBits MPU_xEventGroupClearBits + #define xEventGroupSetBits MPU_xEventGroupSetBits + #define xEventGroupSync MPU_xEventGroupSync + #define vEventGroupDelete MPU_vEventGroupDelete + + /* Remove the privileged function macro. */ + #define PRIVILEGED_FUNCTION + + #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + + /* Ensure API functions go in the privileged execution section. */ + #define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions"))) + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) + + #endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ + +#else /* portUSING_MPU_WRAPPERS */ + + #define PRIVILEGED_FUNCTION + #define PRIVILEGED_DATA + #define portUSING_MPU_WRAPPERS 0 + +#endif /* portUSING_MPU_WRAPPERS */ + + +#endif /* MPU_WRAPPERS_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/portable.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/portable.h new file mode 100755 index 0000000..b9f8be3 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/portable.h @@ -0,0 +1,207 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Portable layer API. Each function must be defined for each port. + *----------------------------------------------------------*/ + +#ifndef PORTABLE_H +#define PORTABLE_H + +/* Each FreeRTOS port has a unique portmacro.h header file. Originally a +pre-processor definition was used to ensure the pre-processor found the correct +portmacro.h file for the port being used. That scheme was deprecated in favour +of setting the compiler's include path such that it found the correct +portmacro.h file - removing the need for the constant and allowing the +portmacro.h file to be located anywhere in relation to the port being used. +Purely for reasons of backward compatibility the old method is still valid, but +to make it clear that new projects should not use it, support for the port +specific constants has been moved into the deprecated_definitions.h header +file. */ +#include "deprecated_definitions.h" + +/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h +did not result in a portmacro.h header file being included - and it should be +included here. In this case the path to the correct portmacro.h header file +must be set in the compiler's include path. */ +#ifndef portENTER_CRITICAL + #include "portmacro.h" +#endif + +#if portBYTE_ALIGNMENT == 32 + #define portBYTE_ALIGNMENT_MASK ( 0x001f ) +#endif + +#if portBYTE_ALIGNMENT == 16 + #define portBYTE_ALIGNMENT_MASK ( 0x000f ) +#endif + +#if portBYTE_ALIGNMENT == 8 + #define portBYTE_ALIGNMENT_MASK ( 0x0007 ) +#endif + +#if portBYTE_ALIGNMENT == 4 + #define portBYTE_ALIGNMENT_MASK ( 0x0003 ) +#endif + +#if portBYTE_ALIGNMENT == 2 + #define portBYTE_ALIGNMENT_MASK ( 0x0001 ) +#endif + +#if portBYTE_ALIGNMENT == 1 + #define portBYTE_ALIGNMENT_MASK ( 0x0000 ) +#endif + +#ifndef portBYTE_ALIGNMENT_MASK + #error "Invalid portBYTE_ALIGNMENT definition" +#endif + +#ifndef portNUM_CONFIGURABLE_REGIONS + #define portNUM_CONFIGURABLE_REGIONS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mpu_wrappers.h" + +/* + * Setup the stack of a new task so it is ready to be placed under the + * scheduler control. The registers have to be placed on the stack in + * the order that the port expects to find them. + * + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION; +#else + StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION; +#endif + +/* Used by heap_5.c. */ +typedef struct HeapRegion +{ + uint8_t *pucStartAddress; + size_t xSizeInBytes; +} HeapRegion_t; + +/* + * Used to define multiple heap regions for use by heap_5.c. This function + * must be called before any calls to pvPortMalloc() - not creating a task, + * queue, semaphore, mutex, software timer, event group, etc. will result in + * pvPortMalloc being called. + * + * pxHeapRegions passes in an array of HeapRegion_t structures - each of which + * defines a region of memory that can be used as the heap. The array is + * terminated by a HeapRegions_t structure that has a size of 0. The region + * with the lowest start address must appear first in the array. + */ +void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION; + + +/* + * Map to the memory management routines required for the port. + */ +void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; +void vPortFree( void *pv ) PRIVILEGED_FUNCTION; +void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; +size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; +size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION; + +/* + * Setup the hardware ready for the scheduler to take control. This generally + * sets up a tick interrupt and sets timers for the correct tick frequency. + */ +BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so + * the hardware is left in its original condition after the scheduler stops + * executing. + */ +void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; + +/* + * The structures and methods of manipulating the MPU are contained within the + * port layer. + * + * Fills the xMPUSettings structure with the memory region information + * contained in xRegions. + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + struct xMEMORY_REGION; + void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PORTABLE_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/projdefs.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/projdefs.h new file mode 100755 index 0000000..0b63fd8 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/projdefs.h @@ -0,0 +1,161 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef PROJDEFS_H +#define PROJDEFS_H + +/* + * Defines the prototype to which task functions must conform. Defined in this + * file to ensure the type is known before portable.h is included. + */ +typedef void (*TaskFunction_t)( void * ); + +/* Converts a time in milliseconds to a time in ticks. This macro can be +overridden by a macro of the same name defined in FreeRTOSConfig.h in case the +definition here is not suitable for your application. */ +#ifndef pdMS_TO_TICKS + #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +#endif + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) +#define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) +#define errQUEUE_FULL ( ( BaseType_t ) 0 ) + +/* FreeRTOS error definitions. */ +#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +/* Macros used for basic data corruption checks. */ +#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES + #define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0 +#endif + +#if( configUSE_16_BIT_TICKS == 1 ) + #define pdINTEGRITY_CHECK_VALUE 0x5a5a +#else + #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL +#endif + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_ERRNO_NONE 0 /* No errors */ +#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ +#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ +#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ +#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ +#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ +#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ +#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ +#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ +#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ +#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ +#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ +#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ +#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ +#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ +#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ +#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ +#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ +#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ +#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ +#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ +#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ +#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ +#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ +#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ +#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ +#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ +#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ +#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ +#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ +#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ +#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ +#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ +#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ +#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ +#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ +#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ +#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ +#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + +/* The following endian values are used by FreeRTOS+ components, not FreeRTOS +itself. */ +#define pdFREERTOS_LITTLE_ENDIAN 0 +#define pdFREERTOS_BIG_ENDIAN 1 + +#endif /* PROJDEFS_H */ + + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/queue.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/queue.h new file mode 100755 index 0000000..30be360 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/queue.h @@ -0,0 +1,1798 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef QUEUE_H +#define QUEUE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include queue.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Type by which queues are referenced. For example, a call to xQueueCreate() + * returns an QueueHandle_t variable that can then be used as a parameter to + * xQueueSend(), xQueueReceive(), etc. + */ +typedef void * QueueHandle_t; + +/** + * Type by which queue sets are referenced. For example, a call to + * xQueueCreateSet() returns an xQueueSet variable that can then be used as a + * parameter to xQueueSelectFromSet(), xQueueAddToSet(), etc. + */ +typedef void * QueueSetHandle_t; + +/** + * Queue sets can contain both queues and semaphores, so the + * QueueSetMemberHandle_t is defined as a type to be used where a parameter or + * return value can be either an QueueHandle_t or an SemaphoreHandle_t. + */ +typedef void * QueueSetMemberHandle_t; + +/* For internal use only. */ +#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) +#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) +#define queueOVERWRITE ( ( BaseType_t ) 2 ) + +/* For internal use only. These definitions *must* match those in queue.c. */ +#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) + +/** + * queue. h + *
+ QueueHandle_t xQueueCreate(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @return If the queue is successfully create then a handle to the newly + * created queue is returned. If the queue cannot be created then 0 is + * returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+	if( xQueue1 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue2 == 0 )
+	{
+		// Queue was not created and must not be used.
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreate xQueueCreate + * \ingroup QueueManagement + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) +#endif + +/** + * queue. h + *
+ QueueHandle_t xQueueCreateStatic(
+							  UBaseType_t uxQueueLength,
+							  UBaseType_t uxItemSize,
+							  uint8_t *pucQueueStorageBuffer,
+							  StaticQueue_t *pxQueueBuffer
+						  );
+ * 
+ * + * Creates a new queue instance, and returns a handle by which the new queue + * can be referenced. + * + * Internally, within the FreeRTOS implementation, queues use two blocks of + * memory. The first block is used to hold the queue's data structures. The + * second block is used to hold items placed into the queue. If a queue is + * created using xQueueCreate() then both blocks of memory are automatically + * dynamically allocated inside the xQueueCreate() function. (see + * http://www.freertos.org/a00111.html). If a queue is created using + * xQueueCreateStatic() then the application writer must provide the memory that + * will get used by the queue. xQueueCreateStatic() therefore allows a queue to + * be created without using any dynamic memory allocation. + * + * http://www.FreeRTOS.org/Embedded-RTOS-Queues.html + * + * @param uxQueueLength The maximum number of items that the queue can contain. + * + * @param uxItemSize The number of bytes each item in the queue will require. + * Items are queued by copy, not by reference, so this is the number of bytes + * that will be copied for each posted item. Each item on the queue must be + * the same size. + * + * @param pucQueueStorageBuffer If uxItemSize is not zero then + * pucQueueStorageBuffer must point to a uint8_t array that is at least large + * enough to hold the maximum number of items that can be in the queue at any + * one time - which is ( uxQueueLength * uxItemsSize ) bytes. If uxItemSize is + * zero then pucQueueStorageBuffer can be NULL. + * + * @param pxQueueBuffer Must point to a variable of type StaticQueue_t, which + * will be used to hold the queue's data structure. + * + * @return If the queue is created then a handle to the created queue is + * returned. If pxQueueBuffer is NULL then NULL is returned. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ };
+
+ #define QUEUE_LENGTH 10
+ #define ITEM_SIZE sizeof( uint32_t )
+
+ // xQueueBuffer will hold the queue structure.
+ StaticQueue_t xQueueBuffer;
+
+ // ucQueueStorage will hold the items posted to the queue.  Must be at least
+ // [(queue length) * ( queue item size)] bytes long.
+ uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( QUEUE_LENGTH, // The number of items the queue can hold.
+							ITEM_SIZE	  // The size of each item in the queue
+							&( ucQueueStorage[ 0 ] ), // The buffer that will hold the items in the queue.
+							&xQueueBuffer ); // The buffer that will hold the queue structure.
+
+	// The queue is guaranteed to be created successfully as no dynamic memory
+	// allocation is used.  Therefore xQueue1 is now a handle to a valid queue.
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueCreateStatic xQueueCreateStatic + * \ingroup QueueManagement + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer ) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * queue. h + *
+ BaseType_t xQueueSendToToFront(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the front of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT ) + +/** + * queue. h + *
+ BaseType_t xQueueSendToBack(
+								   QueueHandle_t	xQueue,
+								   const void		*pvItemToQueue,
+								   TickType_t		xTicksToWait
+							   );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the back of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the queue + * is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueSend(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  TickType_t xTicksToWait
+						 );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). It is included for + * backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToFront() and xQueueSendToBack() macros. It is + * equivalent to xQueueSendToBack(). + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10 ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0 );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwrite(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue
+						 );
+ * 
+ * + * Only for use with queues that have a length of one - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * This function must not be called from an interrupt service routine. + * See xQueueOverwriteFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle of the queue to which the data is being sent. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @return xQueueOverwrite() is a macro that calls xQueueGenericSend(), and + * therefore has the same return values as xQueueSendToFront(). However, pdPASS + * is the only value that can be returned because xQueueOverwrite() will write + * to the queue even when the queue is already full. + * + * Example usage: +
+
+ void vFunction( void *pvParameters )
+ {
+ QueueHandle_t xQueue;
+ uint32_t ulVarToSend, ulValReceived;
+
+	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwrite() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+
+	// Write the value 10 to the queue using xQueueOverwrite().
+	ulVarToSend = 10;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// Peeking the queue should now return 10, but leave the value 10 in
+	// the queue.  A block time of zero is used as it is known that the
+	// queue holds a value.
+	ulValReceived = 0;
+	xQueuePeek( xQueue, &ulValReceived, 0 );
+
+	if( ulValReceived != 10 )
+	{
+		// Error unless the item was removed by a different task.
+	}
+
+	// The queue is still full.  Use xQueueOverwrite() to overwrite the
+	// value held in the queue with 100.
+	ulVarToSend = 100;
+	xQueueOverwrite( xQueue, &ulVarToSend );
+
+	// This time read from the queue, leaving the queue empty once more.
+	// A block time of 0 is used again.
+	xQueueReceive( xQueue, &ulValReceived, 0 );
+
+	// The value read should be the last value written, even though the
+	// queue was already full when the value was written.
+	if( ulValReceived != 100 )
+	{
+		// Error!
+	}
+
+	// ...
+}
+ 
+ * \defgroup xQueueOverwrite xQueueOverwrite + * \ingroup QueueManagement + */ +#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericSend(
+									QueueHandle_t xQueue,
+									const void * pvItemToQueue,
+									TickType_t xTicksToWait
+									BaseType_t xCopyPosition
+								);
+ * 
+ * + * It is preferred that the macros xQueueSend(), xQueueSendToFront() and + * xQueueSendToBack() are used in place of calling this function directly. + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0 and the + * queue is full. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ uint32_t ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ QueueHandle_t xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 uint32_t values.
+	xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) );
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+	// ...
+
+	if( xQueue1 != 0 )
+	{
+		// Send an uint32_t.  Wait for 10 ticks for space to become
+		// available if necessary.
+		if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( TickType_t ) 10, queueSEND_TO_BACK ) != pdPASS )
+		{
+			// Failed to post the message, even after 10 ticks.
+		}
+	}
+
+	if( xQueue2 != 0 )
+	{
+		// Send a pointer to a struct AMessage object.  Don't block if the
+		// queue is already full.
+		pxMessage = & xMessage;
+		xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( TickType_t ) 0, queueSEND_TO_BACK );
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueuePeek(
+							 QueueHandle_t xQueue,
+							 void *pvBuffer,
+							 TickType_t xTicksToWait
+						 );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * This macro must not be used in an interrupt service routine. See + * xQueuePeekFromISR() for an alternative that can be called from an interrupt + * service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue + * is empty. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Peek a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueuePeek( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask, but the item still remains on the queue.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) + +/** + * queue. h + *
+ BaseType_t xQueuePeekFromISR(
+									QueueHandle_t xQueue,
+									void *pvBuffer,
+								);
+ * + * A version of xQueuePeek() that can be called from an interrupt service + * routine (ISR). + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * \defgroup xQueuePeekFromISR xQueuePeekFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceive(
+								 QueueHandle_t xQueue,
+								 void *pvBuffer,
+								 TickType_t xTicksToWait
+							);
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * Successfully received items are removed from the queue. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. xQueueReceive() will return immediately if xTicksToWait + * is zero and the queue is empty. The time is defined in tick periods so the + * constant portTICK_PERIOD_MS should be used to convert to real time if this is + * required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) + + +/** + * queue. h + *
+ BaseType_t xQueueGenericReceive(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   TickType_t	xTicksToWait
+									   BaseType_t	xJustPeek
+									);
+ * + * It is preferred that the macro xQueueReceive() be used rather than calling + * this function directly. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_PERIOD_MS should be used to convert to real time if this is required. + * xQueueGenericReceive() will return immediately if the queue is empty and + * xTicksToWait is 0. + * + * @param xJustPeek When set to true, the item received from the queue is not + * actually removed from the queue - meaning a subsequent call to + * xQueueReceive() will return the same item. When set to false, the item + * being received from the queue is also removed from the queue. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+	char ucMessageID;
+	char ucData[ 20 ];
+ } xMessage;
+
+ QueueHandle_t xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+	// Create a queue capable of containing 10 pointers to AMessage structures.
+	// These should be passed by pointer as they contain a lot of data.
+	xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Send a pointer to a struct AMessage object.  Don't block if the
+	// queue is already full.
+	pxMessage = & xMessage;
+	xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+	if( xQueue != 0 )
+	{
+		// Receive a message on the created queue.  Block for 10 ticks if a
+		// message is not immediately available.
+		if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
+		{
+			// pcRxedMessage now points to the struct AMessage variable posted
+			// by vATask.
+		}
+	}
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue );
+ * + * Return the number of messages stored in a queue. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of messages available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );
+ * + * Return the number of free spaces available in a queue. This is equal to the + * number of items that can be sent to the queue before the queue becomes full + * if no items are removed. + * + * @param xQueue A handle to the queue being queried. + * + * @return The number of spaces available in the queue. + * + * \defgroup uxQueueMessagesWaiting uxQueueMessagesWaiting + * \ingroup QueueManagement + */ +UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
void vQueueDelete( QueueHandle_t xQueue );
+ * + * Delete a queue - freeing all the memory allocated for storing of items + * placed on the queue. + * + * @param xQueue A handle to the queue to be deleted. + * + * \defgroup vQueueDelete vQueueDelete + * \ingroup QueueManagement + */ +void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueSendToFrontFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the front of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToFrontFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToFromFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPrioritTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToFrontFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT ) + + +/** + * queue. h + *
+ BaseType_t xQueueSendToBackFromISR(
+										 QueueHandle_t xQueue,
+										 const void *pvItemToQueue,
+										 BaseType_t *pxHigherPriorityTaskWoken
+									  );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the back of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendToBackFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendToBackFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueOverwriteFromISR(
+							  QueueHandle_t xQueue,
+							  const void * pvItemToQueue,
+							  BaseType_t *pxHigherPriorityTaskWoken
+						 );
+ * 
+ * + * A version of xQueueOverwrite() that can be used in an interrupt service + * routine (ISR). + * + * Only for use with queues that can hold a single item - so the queue is either + * empty or full. + * + * Post an item on a queue. If the queue is already full then overwrite the + * value held in the queue. The item is queued by copy, not by reference. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueOverwriteFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueOverwriteFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return xQueueOverwriteFromISR() is a macro that calls + * xQueueGenericSendFromISR(), and therefore has the same return values as + * xQueueSendToFrontFromISR(). However, pdPASS is the only value that can be + * returned because xQueueOverwriteFromISR() will write to the queue even when + * the queue is already full. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ void vFunction( void *pvParameters )
+ {
+ 	// Create a queue to hold one uint32_t value.  It is strongly
+	// recommended *not* to use xQueueOverwriteFromISR() on queues that can
+	// contain more than one value, and doing so will trigger an assertion
+	// if configASSERT() is defined.
+	xQueue = xQueueCreate( 1, sizeof( uint32_t ) );
+}
+
+void vAnInterruptHandler( void )
+{
+// xHigherPriorityTaskWoken must be set to pdFALSE before it is used.
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+uint32_t ulVarToSend, ulValReceived;
+
+	// Write the value 10 to the queue using xQueueOverwriteFromISR().
+	ulVarToSend = 10;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// The queue is full, but calling xQueueOverwriteFromISR() again will still
+	// pass because the value held in the queue will be overwritten with the
+	// new value.
+	ulVarToSend = 100;
+	xQueueOverwriteFromISR( xQueue, &ulVarToSend, &xHigherPriorityTaskWoken );
+
+	// Reading from the queue will now return 100.
+
+	// ...
+
+	if( xHigherPrioritytaskWoken == pdTRUE )
+	{
+		// Writing to the queue caused a task to unblock and the unblocked task
+		// has a priority higher than or equal to the priority of the currently
+		// executing task (the task this interrupt interrupted).  Perform a context
+		// switch so this interrupt returns directly to the unblocked task.
+		portYIELD_FROM_ISR(); // or portEND_SWITCHING_ISR() depending on the port.
+	}
+}
+ 
+ * \defgroup xQueueOverwriteFromISR xQueueOverwriteFromISR + * \ingroup QueueManagement + */ +#define xQueueOverwriteFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueOVERWRITE ) + +/** + * queue. h + *
+ BaseType_t xQueueSendFromISR(
+									 QueueHandle_t xQueue,
+									 const void *pvItemToQueue,
+									 BaseType_t *pxHigherPriorityTaskWoken
+								);
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). It is included + * for backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() + * macros. + * + * Post an item to the back of a queue. It is safe to use this function from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWoken;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWoken = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post the byte.
+		xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.
+	if( xHigherPriorityTaskWoken )
+	{
+		// Actual macro used here is port specific.
+		portYIELD_FROM_ISR ();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK ) + +/** + * queue. h + *
+ BaseType_t xQueueGenericSendFromISR(
+										   QueueHandle_t		xQueue,
+										   const	void	*pvItemToQueue,
+										   BaseType_t	*pxHigherPriorityTaskWoken,
+										   BaseType_t	xCopyPosition
+									   );
+ 
+ * + * It is preferred that the macros xQueueSendFromISR(), + * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place + * of calling this function directly. xQueueGiveFromISR() is an + * equivalent for use by semaphores that don't actually copy any data. + * + * Post an item on a queue. It is safe to use this function from within an + * interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param pxHigherPriorityTaskWoken xQueueGenericSendFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending to the queue caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xQueueGenericSendFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if the data was successfully sent to the queue, otherwise + * errQUEUE_FULL. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ char cIn;
+ BaseType_t xHigherPriorityTaskWokenByPost;
+
+	// We have not woken a task at the start of the ISR.
+	xHigherPriorityTaskWokenByPost = pdFALSE;
+
+	// Loop until the buffer is empty.
+	do
+	{
+		// Obtain a byte from the buffer.
+		cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+		// Post each byte.
+		xQueueGenericSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWokenByPost, queueSEND_TO_BACK );
+
+	} while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+	// Now the buffer is empty we can switch context if necessary.  Note that the
+	// name of the yield function required is port specific.
+	if( xHigherPriorityTaskWokenByPost )
+	{
+		taskYIELD_YIELD_FROM_ISR();
+	}
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/** + * queue. h + *
+ BaseType_t xQueueReceiveFromISR(
+									   QueueHandle_t	xQueue,
+									   void	*pvBuffer,
+									   BaseType_t *pxTaskWoken
+								   );
+ * 
+ * + * Receive an item from a queue. It is safe to use this function from within an + * interrupt service routine. + * + * @param xQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param pxTaskWoken A task may be blocked waiting for space to become + * available on the queue. If xQueueReceiveFromISR causes such a task to + * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will + * remain unchanged. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+
+ QueueHandle_t xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ char cValueToPost;
+ const TickType_t xTicksToWait = ( TickType_t )0xff;
+
+	// Create a queue capable of containing 10 characters.
+	xQueue = xQueueCreate( 10, sizeof( char ) );
+	if( xQueue == 0 )
+	{
+		// Failed to create the queue.
+	}
+
+	// ...
+
+	// Post some characters that will be used within an ISR.  If the queue
+	// is full then this task will block for xTicksToWait ticks.
+	cValueToPost = 'a';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+	cValueToPost = 'b';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+
+	// ... keep posting characters ... this task may block when the queue
+	// becomes full.
+
+	cValueToPost = 'c';
+	xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ BaseType_t xTaskWokenByReceive = pdFALSE;
+ char cRxedChar;
+
+	while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+	{
+		// A character was received.  Output the character now.
+		vOutputCharacter( cRxedChar );
+
+		// If removing the character from the queue woke the task that was
+		// posting onto the queue cTaskWokenByReceive will have been set to
+		// pdTRUE.  No matter how many times this loop iterates only one
+		// task will be woken.
+	}
+
+	if( cTaskWokenByPost != ( char ) pdFALSE;
+	{
+		taskYIELD ();
+	}
+ }
+ 
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR + * \ingroup QueueManagement + */ +BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + +/* + * Utilities to query queues that are safe to use from an ISR. These utilities + * should be used only from witin an ISR, or within a critical section. + */ +BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + +/* + * The functions defined above are for passing data to and from tasks. The + * functions below are the equivalents for passing data to and from + * co-routines. + * + * These functions are called from the co-routine macro implementation and + * should not be called directly from application code. Instead use the macro + * wrappers defined within croutine.h. + */ +BaseType_t xQueueCRSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken ); +BaseType_t xQueueCRReceiveFromISR( QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxTaskWoken ); +BaseType_t xQueueCRSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait ); +BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ); + +/* + * For internal use only. Use xSemaphoreCreateMutex(), + * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling + * these functions directly. + */ +QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; +QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Use xSemaphoreTakeMutexRecursive() or + * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. + */ +BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION; + +/* + * Reset a queue back to its original empty state. The return value is now + * obsolete and is always set to pdPASS. + */ +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger. If you are not using a kernel + * aware debugger then this function can be ignored. + * + * configQUEUE_REGISTRY_SIZE defines the maximum number of handles the + * registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0 + * within FreeRTOSConfig.h for the registry to be available. Its value + * does not effect the number of queues, semaphores and mutexes that can be + * created - just the number that the registry can hold. + * + * @param xQueue The handle of the queue being added to the registry. This + * is the handle returned by a call to xQueueCreate(). Semaphore and mutex + * handles can also be passed in here. + * + * @param pcName The name to be associated with the handle. This is the + * name that the kernel aware debugger will display. The queue registry only + * stores a pointer to the string - so the string must be persistent (global or + * preferably in ROM/Flash), not on the stack. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * The registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call vQueueAddToRegistry() add + * a queue, semaphore or mutex handle to the registry if you want the handle + * to be available to a kernel aware debugger, and vQueueUnregisterQueue() to + * remove the queue, semaphore or mutex from the register. If you are not using + * a kernel aware debugger then this function can be ignored. + * + * @param xQueue The handle of the queue being removed from the registry. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + void vQueueUnregisterQueue( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +#endif + +/* + * The queue registry is provided as a means for kernel aware debuggers to + * locate queues, semaphores and mutexes. Call pcQueueGetName() to look + * up and return the name of a queue in the queue registry from the queue's + * handle. + * + * @param xQueue The handle of the queue the name of which will be returned. + * @return If the queue is in the registry then a pointer to the name of the + * queue is returned. If the queue is not in the registry then NULL is + * returned. + */ +#if( configQUEUE_REGISTRY_SIZE > 0 ) + const char *pcQueueGetName( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Generic version of the function used to creaet a queue using dynamic memory + * allocation. This is called by other functions and macros that create other + * RTOS objects that use the queue structure as their base. + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; +#endif + +/* + * Queue sets provide a mechanism to allow a task to block (pend) on a read + * operation from multiple queues or semaphores simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * A queue set must be explicitly created using a call to xQueueCreateSet() + * before it can be used. Once created, standard FreeRTOS queues and semaphores + * can be added to the set using calls to xQueueAddToSet(). + * xQueueSelectFromSet() is then used to determine which, if any, of the queues + * or semaphores contained in the set is in a state where a queue read or + * semaphore take operation would be successful. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: An additional 4 bytes of RAM is required for each space in a every + * queue added to a queue set. Therefore counting semaphores that have a high + * maximum count value should not be added to a queue set. + * + * Note 4: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param uxEventQueueLength Queue sets store events that occur on + * the queues and semaphores contained in the set. uxEventQueueLength specifies + * the maximum number of events that can be queued at once. To be absolutely + * certain that events are not lost uxEventQueueLength should be set to the + * total sum of the length of the queues added to the set, where binary + * semaphores and mutexes have a length of 1, and counting semaphores have a + * length set by their maximum count value. Examples: + * + If a queue set is to hold a queue of length 5, another queue of length 12, + * and a binary semaphore, then uxEventQueueLength should be set to + * (5 + 12 + 1), or 18. + * + If a queue set is to hold three binary semaphores then uxEventQueueLength + * should be set to (1 + 1 + 1 ), or 3. + * + If a queue set is to hold a counting semaphore that has a maximum count of + * 5, and a counting semaphore that has a maximum count of 3, then + * uxEventQueueLength should be set to (5 + 3), or 8. + * + * @return If the queue set is created successfully then a handle to the created + * queue set is returned. Otherwise NULL is returned. + */ +QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) PRIVILEGED_FUNCTION; + +/* + * Adds a queue or semaphore to a queue set that was previously created by a + * call to xQueueCreateSet(). + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being added to + * the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set to which the queue or semaphore + * is being added. + * + * @return If the queue or semaphore was successfully added to the queue set + * then pdPASS is returned. If the queue could not be successfully added to the + * queue set because it is already a member of a different queue set then pdFAIL + * is returned. + */ +BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * Removes a queue or semaphore from a queue set. A queue or semaphore can only + * be removed from a set if the queue or semaphore is empty. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueueOrSemaphore The handle of the queue or semaphore being removed + * from the queue set (cast to an QueueSetMemberHandle_t type). + * + * @param xQueueSet The handle of the queue set in which the queue or semaphore + * is included. + * + * @return If the queue or semaphore was successfully removed from the queue set + * then pdPASS is returned. If the queue was not in the queue set, or the + * queue (or semaphore) was not empty, then pdFAIL is returned. + */ +BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* + * xQueueSelectFromSet() selects from the members of a queue set a queue or + * semaphore that either contains data (in the case of a queue) or is available + * to take (in the case of a semaphore). xQueueSelectFromSet() effectively + * allows a task to block (pend) on a read operation on all the queues and + * semaphores in a queue set simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org/RTOS-queue-sets.html + * for reasons why queue sets are very rarely needed in practice as there are + * simpler methods of blocking on multiple objects. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: A receive (in the case of a queue) or take (in the case of a + * semaphore) operation must not be performed on a member of a queue set unless + * a call to xQueueSelectFromSet() has first returned a handle to that set member. + * + * @param xQueueSet The queue set on which the task will (potentially) block. + * + * @param xTicksToWait The maximum time, in ticks, that the calling task will + * remain in the Blocked state (with other tasks executing) to wait for a member + * of the queue set to be ready for a successful queue read or semaphore take + * operation. + * + * @return xQueueSelectFromSet() will return the handle of a queue (cast to + * a QueueSetMemberHandle_t type) contained in the queue set that contains data, + * or the handle of a semaphore (cast to a QueueSetMemberHandle_t type) contained + * in the queue set that is available, or NULL if no such queue or semaphore + * exists before before the specified block time expires. + */ +QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * A version of xQueueSelectFromSet() that can be used from an ISR. + */ +QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION; + +/* Not public API functions. */ +void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; +BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION; +void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION; +UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; +uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; + + +#ifdef __cplusplus +} +#endif + +#endif /* QUEUE_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/semphr.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/semphr.h new file mode 100755 index 0000000..a674b02 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/semphr.h @@ -0,0 +1,1171 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include semphr.h" +#endif + +#include "queue.h" + +typedef QueueHandle_t SemaphoreHandle_t; + +#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) +#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U ) + + +/** + * semphr. h + *
vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )
+ * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * Macro that implements a semaphore by using the existing queue mechanism. + * The queue length is 1 as this is a binary semaphore. The data size is 0 + * as we don't want to actually store any data - we just want to know if the + * queue is empty or full. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param xSemaphore Handle to the created semaphore. Should be of type SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+    // This is a macro so pass the variable in directly.
+    vSemaphoreCreateBinary( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define vSemaphoreCreateBinary( xSemaphore ) \ + { \ + ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ + if( ( xSemaphore ) != NULL ) \ + { \ + ( void ) xSemaphoreGive( ( xSemaphore ) ); \ + } \ + } +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinary( void )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this + * xSemaphoreCreateBinary() function. Note that binary semaphores created using + * the vSemaphoreCreateBinary() macro are created in a state such that the + * first call to 'take' the semaphore would pass, whereas binary semaphores + * created using xSemaphoreCreateBinary() are created in a state such that the + * the semaphore must first be 'given' before it can be 'taken'. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @return Handle to the created semaphore, or NULL if the memory required to + * hold the semaphore's data structures could not be allocated. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateBinary xSemaphoreCreateBinary + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new binary semaphore instance, and returns a handle by which the + * new semaphore can be referenced. + * + * NOTE: In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a binary semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, binary semaphores use a block + * of memory, in which the semaphore structure is stored. If a binary semaphore + * is created using xSemaphoreCreateBinary() then the required memory is + * automatically dynamically allocated inside the xSemaphoreCreateBinary() + * function. (see http://www.freertos.org/a00111.html). If a binary semaphore + * is created using xSemaphoreCreateBinaryStatic() then the application writer + * must provide the memory. xSemaphoreCreateBinaryStatic() therefore allows a + * binary semaphore to be created without using any dynamic memory allocation. + * + * This type of semaphore can be used for pure synchronisation between tasks or + * between an interrupt and a task. The semaphore need not be given back once + * obtained, so one task/interrupt can continuously 'give' the semaphore while + * another continuously 'takes' the semaphore. For this reason this type of + * semaphore does not use a priority inheritance mechanism. For an alternative + * that does use priority inheritance see xSemaphoreCreateMutex(). + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the semaphore is created then a handle to the created semaphore is + * returned. If pxSemaphoreBuffer is NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateBinary().
+    // The semaphore's data structures will be placed in the xSemaphoreBuffer
+    // variable, the address of which is passed into the function.  The
+    // function's parameter is not NULL, so the function will not attempt any
+    // dynamic memory allocation, and therefore the function will not return
+    // return NULL.
+    xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );
+
+    // Rest of task code goes here.
+ }
+ 
+ * \defgroup xSemaphoreCreateBinaryStatic xSemaphoreCreateBinaryStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
xSemaphoreTake(
+ *                   SemaphoreHandle_t xSemaphore,
+ *                   TickType_t xBlockTime
+ *               )
+ * + * Macro to obtain a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). + * + * @param xSemaphore A handle to the semaphore being taken - obtained when + * the semaphore was created. + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. A block + * time of portMAX_DELAY can be used to block indefinitely (provided + * INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h). + * + * @return pdTRUE if the semaphore was obtained. pdFALSE + * if xBlockTime expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = xSemaphoreCreateBinary();
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xSemaphore != NULL )
+    {
+        // See if we can obtain the semaphore.  If the semaphore is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the semaphore and can now access the
+            // shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource.  Release the
+            // semaphore.
+            xSemaphoreGive( xSemaphore );
+        }
+        else
+        {
+            // We could not obtain the semaphore and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTake xSemaphoreTake + * \ingroup Semaphores + */ +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) + +/** + * semphr. h + * xSemaphoreTakeRecursive( + * SemaphoreHandle_t xMutex, + * TickType_t xBlockTime + * ) + * + * Macro to recursively obtain, or 'take', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being obtained. This is the + * handle returned by xSemaphoreCreateRecursiveMutex(); + * + * @param xBlockTime The time in ticks to wait for the semaphore to become + * available. The macro portTICK_PERIOD_MS can be used to convert this to a + * real time. A block time of zero can be used to poll the semaphore. If + * the task already owns the semaphore then xSemaphoreTakeRecursive() will + * return immediately no matter what the value of xBlockTime. + * + * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime + * expired without the semaphore becoming available. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, but instead buried in a more complex
+			// call structure.  This is just for illustrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreTakeRecursive xSemaphoreTakeRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) +#endif + +/** + * semphr. h + *
xSemaphoreGive( SemaphoreHandle_t xSemaphore )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or + * xSemaphoreCreateCounting(). and obtained using sSemaphoreTake(). + * + * This macro must not be used from an ISR. See xSemaphoreGiveFromISR () for + * an alternative which can be used from an ISR. + * + * This macro must also not be used on semaphores created using + * xSemaphoreCreateRecursiveMutex(). + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred. + * Semaphores are implemented using queues. An error can occur if there is + * no space on the queue to post a message - indicating that the + * semaphore was not first obtained correctly. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+    // Create the semaphore to guard a shared resource.
+    xSemaphore = vSemaphoreCreateBinary();
+
+    if( xSemaphore != NULL )
+    {
+        if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+        {
+            // We would expect this call to fail because we cannot give
+            // a semaphore without first "taking" it!
+        }
+
+        // Obtain the semaphore - don't block if the semaphore is not
+        // immediately available.
+        if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) )
+        {
+            // We now have the semaphore and can access the shared resource.
+
+            // ...
+
+            // We have finished accessing the shared resource so can free the
+            // semaphore.
+            if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+            {
+                // We would not expect this call to fail because we must have
+                // obtained the semaphore to get here.
+            }
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGive xSemaphoreGive + * \ingroup Semaphores + */ +#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) + +/** + * semphr. h + *
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
+ * + * Macro to recursively release, or 'give', a mutex type semaphore. + * The mutex must have previously been created using a call to + * xSemaphoreCreateRecursiveMutex(); + * + * configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this + * macro to be available. + * + * This macro must not be used on mutexes created using xSemaphoreCreateMutex(). + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * @param xMutex A handle to the mutex being released, or 'given'. This is the + * handle returned by xSemaphoreCreateMutex(); + * + * @return pdTRUE if the semaphore was given. + * + * Example usage: +
+ SemaphoreHandle_t xMutex = NULL;
+
+ // A task that creates a mutex.
+ void vATask( void * pvParameters )
+ {
+    // Create the mutex to guard a shared resource.
+    xMutex = xSemaphoreCreateRecursiveMutex();
+ }
+
+ // A task that uses the mutex.
+ void vAnotherTask( void * pvParameters )
+ {
+    // ... Do other things.
+
+    if( xMutex != NULL )
+    {
+        // See if we can obtain the mutex.  If the mutex is not available
+        // wait 10 ticks to see if it becomes free.
+        if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
+        {
+            // We were able to obtain the mutex and can now access the
+            // shared resource.
+
+            // ...
+            // For some reason due to the nature of the code further calls to
+			// xSemaphoreTakeRecursive() are made on the same mutex.  In real
+			// code these would not be just sequential calls as this would make
+			// no sense.  Instead the calls are likely to be buried inside
+			// a more complex call structure.
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+            xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
+
+            // The mutex has now been 'taken' three times, so will not be
+			// available to another task until it has also been given back
+			// three times.  Again it is unlikely that real code would have
+			// these calls sequentially, it would be more likely that the calls
+			// to xSemaphoreGiveRecursive() would be called as a call stack
+			// unwound.  This is just for demonstrative purposes.
+            xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+			xSemaphoreGiveRecursive( xMutex );
+
+			// Now the mutex can be taken by other tasks.
+        }
+        else
+        {
+            // We could not obtain the mutex and can therefore not access
+            // the shared resource safely.
+        }
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveRecursive xSemaphoreGiveRecursive + * \ingroup Semaphores + */ +#if( configUSE_RECURSIVE_MUTEXES == 1 ) + #define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) +#endif + +/** + * semphr. h + *
+ xSemaphoreGiveFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to release a semaphore. The semaphore must have previously been + * created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR. + * + * @param xSemaphore A handle to the semaphore being released. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreGiveFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if giving the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreGiveFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully given, otherwise errQUEUE_FULL. + * + * Example usage: +
+ \#define LONG_TIME 0xffff
+ \#define TICKS_TO_WAIT	10
+ SemaphoreHandle_t xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+    for( ;; )
+    {
+        // We want this task to run every 10 ticks of a timer.  The semaphore
+        // was created before this task was started.
+
+        // Block waiting for the semaphore to become available.
+        if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+        {
+            // It is time to execute.
+
+            // ...
+
+            // We have finished our task.  Return to the top of the loop where
+            // we will block on the semaphore until it is time to execute
+            // again.  Note when using the semaphore for synchronisation with an
+			// ISR in this manner there is no need to 'give' the semaphore back.
+        }
+    }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static uint8_t ucLocalTickCount = 0;
+ static BaseType_t xHigherPriorityTaskWoken;
+
+    // A timer tick has occurred.
+
+    // ... Do other time functions.
+
+    // Is it time for vATask () to run?
+	xHigherPriorityTaskWoken = pdFALSE;
+    ucLocalTickCount++;
+    if( ucLocalTickCount >= TICKS_TO_WAIT )
+    {
+        // Unblock the task by releasing the semaphore.
+        xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
+
+        // Reset the count so we release the semaphore again in 10 ticks time.
+        ucLocalTickCount = 0;
+    }
+
+    if( xHigherPriorityTaskWoken != pdFALSE )
+    {
+        // We can force a context switch here.  Context switching from an
+        // ISR uses port specific syntax.  Check the demo task for your port
+        // to find the syntax required.
+    }
+ }
+ 
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR + * \ingroup Semaphores + */ +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
+ xSemaphoreTakeFromISR(
+                          SemaphoreHandle_t xSemaphore,
+                          BaseType_t *pxHigherPriorityTaskWoken
+                      )
+ * + * Macro to take a semaphore from an ISR. The semaphore must have + * previously been created with a call to xSemaphoreCreateBinary() or + * xSemaphoreCreateCounting(). + * + * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) + * must not be used with this macro. + * + * This macro can be used from an ISR, however taking a semaphore from an ISR + * is not a common operation. It is likely to only be useful when taking a + * counting semaphore when an interrupt is obtaining an object from a resource + * pool (when the semaphore count indicates the number of resources available). + * + * @param xSemaphore A handle to the semaphore being taken. This is the + * handle returned when the semaphore was created. + * + * @param pxHigherPriorityTaskWoken xSemaphoreTakeFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if taking the semaphore caused a task + * to unblock, and the unblocked task has a priority higher than the currently + * running task. If xSemaphoreTakeFromISR() sets this value to pdTRUE then + * a context switch should be requested before the interrupt is exited. + * + * @return pdTRUE if the semaphore was successfully taken, otherwise + * pdFALSE + */ +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) ) + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutex( void )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return If the mutex was successfully created then a handle to the created + * semaphore is returned. If there was not enough heap to allocate the mutex + * data structures then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateMutex xSemaphoreCreateMutex + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new mutex type semaphore instance, and returns a handle by which + * the new mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, mutex semaphores use a block + * of memory, in which the mutex structure is stored. If a mutex is created + * using xSemaphoreCreateMutex() then the required memory is automatically + * dynamically allocated inside the xSemaphoreCreateMutex() function. (see + * http://www.freertos.org/a00111.html). If a mutex is created using + * xSemaphoreCreateMutexStatic() then the application writer must provided the + * memory. xSemaphoreCreateMutexStatic() therefore allows a mutex to be created + * without using any dynamic memory allocation. + * + * Mutexes created using this function can be accessed using the xSemaphoreTake() + * and xSemaphoreGive() macros. The xSemaphoreTakeRecursive() and + * xSemaphoreGiveRecursive() macros must not be used. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will be used to hold the mutex's data structure, removing the need for + * the memory to be allocated dynamically. + * + * @return If the mutex was successfully created then a handle to the created + * mutex is returned. If pxMutexBuffer was NULL then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A mutex cannot be used before it has been created.  xMutexBuffer is
+    // into xSemaphoreCreateMutexStatic() so no dynamic memory allocation is
+    // attempted.
+    xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateMutexStatic xSemaphoreCreateMutexStatic + * \ingroup Semaphores + */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @return xSemaphore Handle to the created mutex semaphore. Should be of type + * SemaphoreHandle_t. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to xSemaphoreCreateMutex().
+    // This is a macro so pass the variable in directly.
+    xSemaphore = xSemaphoreCreateRecursiveMutex();
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutex xSemaphoreCreateRecursiveMutex + * \ingroup Semaphores + */ +#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
+ * + * Creates a new recursive mutex type semaphore instance, and returns a handle + * by which the new recursive mutex can be referenced. + * + * Internally, within the FreeRTOS implementation, recursive mutexs use a block + * of memory, in which the mutex structure is stored. If a recursive mutex is + * created using xSemaphoreCreateRecursiveMutex() then the required memory is + * automatically dynamically allocated inside the + * xSemaphoreCreateRecursiveMutex() function. (see + * http://www.freertos.org/a00111.html). If a recursive mutex is created using + * xSemaphoreCreateRecursiveMutexStatic() then the application writer must + * provide the memory that will get used by the mutex. + * xSemaphoreCreateRecursiveMutexStatic() therefore allows a recursive mutex to + * be created without using any dynamic memory allocation. + * + * Mutexes created using this macro can be accessed using the + * xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() macros. The + * xSemaphoreTake() and xSemaphoreGive() macros must not be used. + * + * A mutex used recursively can be 'taken' repeatedly by the owner. The mutex + * doesn't become available again until the owner has called + * xSemaphoreGiveRecursive() for each successful 'take' request. For example, + * if a task successfully 'takes' the same mutex 5 times then the mutex will + * not be available to any other task until it has also 'given' the mutex back + * exactly five times. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implementation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param pxMutexBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the recursive mutex's data structure, + * removing the need for the memory to be allocated dynamically. + * + * @return If the recursive mutex was successfully created then a handle to the + * created recursive mutex is returned. If pxMutexBuffer was NULL then NULL is + * returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xMutexBuffer;
+
+ void vATask( void * pvParameters )
+ {
+    // A recursive semaphore cannot be used before it is created.  Here a
+    // recursive mutex is created using xSemaphoreCreateRecursiveMutexStatic().
+    // The address of xMutexBuffer is passed into the function, and will hold
+    // the mutexes data structures - so no dynamic memory allocation will be
+    // attempted.
+    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
+
+    // As no dynamic memory allocation was performed, xSemaphore cannot be NULL,
+    // so there is no need to check it.
+ }
+ 
+ * \defgroup xSemaphoreCreateRecursiveMutexStatic xSemaphoreCreateRecursiveMutexStatic + * \ingroup Semaphores + */ +#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) ) + #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer can + * instead optionally provide the memory that will get used by the counting + * semaphore. xSemaphoreCreateCountingStatic() therefore allows a counting + * semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @return Handle to the created semaphore. Null if the semaphore could not be + * created. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Semaphore cannot be used before a call to xSemaphoreCreateCounting().
+    // The max value to which the semaphore can count should be 10, and the
+    // initial value assigned to the count should be 0.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0 );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.
+    }
+ }
+ 
+ * \defgroup xSemaphoreCreateCounting xSemaphoreCreateCounting + * \ingroup Semaphores + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) +#endif + +/** + * semphr. h + *
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
+ * + * Creates a new counting semaphore instance, and returns a handle by which the + * new counting semaphore can be referenced. + * + * In many usage scenarios it is faster and more memory efficient to use a + * direct to task notification in place of a counting semaphore! + * http://www.freertos.org/RTOS-task-notifications.html + * + * Internally, within the FreeRTOS implementation, counting semaphores use a + * block of memory, in which the counting semaphore structure is stored. If a + * counting semaphore is created using xSemaphoreCreateCounting() then the + * required memory is automatically dynamically allocated inside the + * xSemaphoreCreateCounting() function. (see + * http://www.freertos.org/a00111.html). If a counting semaphore is created + * using xSemaphoreCreateCountingStatic() then the application writer must + * provide the memory. xSemaphoreCreateCountingStatic() therefore allows a + * counting semaphore to be created without using any dynamic memory allocation. + * + * Counting semaphores are typically used for two things: + * + * 1) Counting events. + * + * In this usage scenario an event handler will 'give' a semaphore each time + * an event occurs (incrementing the semaphore count value), and a handler + * task will 'take' a semaphore each time it processes an event + * (decrementing the semaphore count value). The count value is therefore + * the difference between the number of events that have occurred and the + * number that have been processed. In this case it is desirable for the + * initial count value to be zero. + * + * 2) Resource management. + * + * In this usage scenario the count value indicates the number of resources + * available. To obtain control of a resource a task must first obtain a + * semaphore - decrementing the semaphore count value. When the count value + * reaches zero there are no free resources. When a task finishes with the + * resource it 'gives' the semaphore back - incrementing the semaphore count + * value. In this case it is desirable for the initial count value to be + * equal to the maximum count value, indicating that all resources are free. + * + * @param uxMaxCount The maximum count value that can be reached. When the + * semaphore reaches this value it can no longer be 'given'. + * + * @param uxInitialCount The count value assigned to the semaphore when it is + * created. + * + * @param pxSemaphoreBuffer Must point to a variable of type StaticSemaphore_t, + * which will then be used to hold the semaphore's data structure, removing the + * need for the memory to be allocated dynamically. + * + * @return If the counting semaphore was successfully created then a handle to + * the created counting semaphore is returned. If pxSemaphoreBuffer was NULL + * then NULL is returned. + * + * Example usage: +
+ SemaphoreHandle_t xSemaphore;
+ StaticSemaphore_t xSemaphoreBuffer;
+
+ void vATask( void * pvParameters )
+ {
+ SemaphoreHandle_t xSemaphore = NULL;
+
+    // Counting semaphore cannot be used before they have been created.  Create
+    // a counting semaphore using xSemaphoreCreateCountingStatic().  The max
+    // value to which the semaphore can count is 10, and the initial value
+    // assigned to the count will be 0.  The address of xSemaphoreBuffer is
+    // passed in and will be used to hold the semaphore structure, so no dynamic
+    // memory allocation will be used.
+    xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );
+
+    // No memory allocation was attempted so xSemaphore cannot be NULL, so there
+    // is no need to check its value.
+ }
+ 
+ * \defgroup xSemaphoreCreateCountingStatic xSemaphoreCreateCountingStatic + * \ingroup Semaphores + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * semphr. h + *
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
+ * + * Delete a semaphore. This function must be used with care. For example, + * do not delete a mutex type semaphore if the mutex is held by a task. + * + * @param xSemaphore A handle to the semaphore to be deleted. + * + * \defgroup vSemaphoreDelete vSemaphoreDelete + * \ingroup Semaphores + */ +#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) ) + +/** + * semphr.h + *
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
+ * + * If xMutex is indeed a mutex type semaphore, return the current mutex holder. + * If xMutex is not a mutex type semaphore, or the mutex is available (not held + * by a task), return NULL. + * + * Note: This is a good way of determining if the calling task is the mutex + * holder, but not a good way of determining the identity of the mutex holder as + * the holder may change between the function exiting and the returned value + * being tested. + */ +#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) + +/** + * semphr.h + *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
+ * + * If the semaphore is a counting semaphore then uxSemaphoreGetCount() returns + * its current count value. If the semaphore is a binary semaphore then + * uxSemaphoreGetCount() returns 1 if the semaphore is available, and 0 if the + * semaphore is not available. + * + */ +#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) + +#endif /* SEMAPHORE_H */ + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/task.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/task.h new file mode 100755 index 0000000..d0643c0 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/task.h @@ -0,0 +1,2267 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef INC_TASK_H +#define INC_TASK_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include task.h" +#endif + +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +#define tskKERNEL_VERSION_NUMBER "V9.0.0" +#define tskKERNEL_VERSION_MAJOR 9 +#define tskKERNEL_VERSION_MINOR 0 +#define tskKERNEL_VERSION_BUILD 0 + +/** + * task. h + * + * Type by which tasks are referenced. For example, a call to xTaskCreate + * returns (via a pointer parameter) an TaskHandle_t variable that can then + * be used as a parameter to vTaskDelete to delete the task. + * + * \defgroup TaskHandle_t TaskHandle_t + * \ingroup Tasks + */ +typedef void * TaskHandle_t; + +/* + * Defines the prototype to which the application task hook function must + * conform. + */ +typedef BaseType_t (*TaskHookFunction_t)( void * ); + +/* Task states returned by eTaskGetState. */ +typedef enum +{ + eRunning = 0, /* A task is querying the state of itself, so must be running. */ + eReady, /* The task being queried is in a read or pending ready list. */ + eBlocked, /* The task being queried is in the Blocked state. */ + eSuspended, /* The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ + eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */ + eInvalid /* Used as an 'invalid state' value. */ +} eTaskState; + +/* Actions that can be performed when vTaskNotify() is called. */ +typedef enum +{ + eNoAction = 0, /* Notify the task without updating its notify value. */ + eSetBits, /* Set bits in the task's notification value. */ + eIncrement, /* Increment the task's notification value. */ + eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ + eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ +} eNotifyAction; + +/* + * Used internally only. + */ +typedef struct xTIME_OUT +{ + BaseType_t xOverflowCount; + TickType_t xTimeOnEntering; +} TimeOut_t; + +/* + * Defines the memory ranges allocated to the task when an MPU is used. + */ +typedef struct xMEMORY_REGION +{ + void *pvBaseAddress; + uint32_t ulLengthInBytes; + uint32_t ulParameters; +} MemoryRegion_t; + +/* + * Parameters required to create an MPU protected task. + */ +typedef struct xTASK_PARAMETERS +{ + TaskFunction_t pvTaskCode; + const char * const pcName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + uint16_t usStackDepth; + void *pvParameters; + UBaseType_t uxPriority; + StackType_t *puxStackBuffer; + MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; +} TaskParameters_t; + +/* Used with the uxTaskGetSystemState() function to return the state of each task +in the system. */ +typedef struct xTASK_STATUS +{ + TaskHandle_t xHandle; /* The handle of the task to which the rest of the information in the structure relates. */ + const char *pcTaskName; /* A pointer to the task's name. This value will be invalid if the task was deleted since the structure was populated! */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + UBaseType_t xTaskNumber; /* A number unique to the task. */ + eTaskState eCurrentState; /* The state in which the task existed when the structure was populated. */ + UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ + UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ + uint32_t ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See http://www.freertos.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ + StackType_t *pxStackBase; /* Points to the lowest address of the task's stack area. */ + uint16_t usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */ +} TaskStatus_t; + +/* Possible return values for eTaskConfirmSleepModeStatus(). */ +typedef enum +{ + eAbortSleep = 0, /* A task has been made ready or a context switch pended since portSUPPORESS_TICKS_AND_SLEEP() was called - abort entering a sleep mode. */ + eStandardSleep, /* Enter a sleep mode that will not last any longer than the expected idle time. */ + eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ +} eSleepModeStatus; + +/** + * Defines the priority used by the idle task. This must not be modified. + * + * \ingroup TaskUtils + */ +#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U ) + +/** + * task. h + * + * Macro for forcing a context switch. + * + * \defgroup taskYIELD taskYIELD + * \ingroup SchedulerControl + */ +#define taskYIELD() portYIELD() + +/** + * task. h + * + * Macro to mark the start of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL + * \ingroup SchedulerControl + */ +#define taskENTER_CRITICAL() portENTER_CRITICAL() +#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() + +/** + * task. h + * + * Macro to mark the end of a critical code region. Preemptive context + * switches cannot occur when in a critical region. + * + * NOTE: This may alter the stack (depending on the portable implementation) + * so must be used with care! + * + * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL + * \ingroup SchedulerControl + */ +#define taskEXIT_CRITICAL() portEXIT_CRITICAL() +#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) +/** + * task. h + * + * Macro to disable all maskable interrupts. + * + * \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() + +/** + * task. h + * + * Macro to enable microcontroller interrupts. + * + * \defgroup taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS + * \ingroup SchedulerControl + */ +#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() + +/* Definitions returned by xTaskGetSchedulerState(). taskSCHEDULER_SUSPENDED is +0 to generate more optimal code when configASSERT() is defined as the constant +is used in assert() statements. */ +#define taskSCHEDULER_SUSPENDED ( ( BaseType_t ) 0 ) +#define taskSCHEDULER_NOT_STARTED ( ( BaseType_t ) 1 ) +#define taskSCHEDULER_RUNNING ( ( BaseType_t ) 2 ) + + +/*----------------------------------------------------------- + * TASK CREATION API + *----------------------------------------------------------*/ + +/** + * task. h + *
+ BaseType_t xTaskCreate(
+							  TaskFunction_t pvTaskCode,
+							  const char * const pcName,
+							  uint16_t usStackDepth,
+							  void *pvParameters,
+							  UBaseType_t uxPriority,
+							  TaskHandle_t *pvCreatedTask
+						  );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * See xTaskCreateStatic() for a version that does not use any dynamic memory + * allocation. + * + * xTaskCreate() can only be used to create a task that has unrestricted + * access to the entire microcontroller memory map. Systems that include MPU + * support can alternatively create an MPU constrained task using + * xTaskCreateRestricted(). + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default + * is 16. + * + * @param usStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task should run. Systems that + * include MPU support can optionally create tasks in a privileged (system) + * mode by setting bit portPRIVILEGE_BIT of the priority parameter. For + * example, to create a privileged task at priority 2 the uxPriority parameter + * should be set to ( 2 | portPRIVILEGE_BIT ). + * + * @param pvCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+	 }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static uint8_t ucParameterToPass;
+ TaskHandle_t xHandle = NULL;
+
+	 // Create the task, storing the handle.  Note that the passed parameter ucParameterToPass
+	 // must exist for the lifetime of the task, so in this case is declared static.  If it was just an
+	 // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
+	 // the new task attempts to access it.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+     configASSERT( xHandle );
+
+	 // Use the handle to delete the task.
+     if( xHandle != NULL )
+     {
+	     vTaskDelete( xHandle );
+     }
+ }
+   
+ * \defgroup xTaskCreate xTaskCreate + * \ingroup Tasks + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * task. h + *
+ TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode,
+								 const char * const pcName,
+								 uint32_t ulStackDepth,
+								 void *pvParameters,
+								 UBaseType_t uxPriority,
+								 StackType_t *pxStackBuffer,
+								 StaticTask_t *pxTaskBuffer );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * + * Internally, within the FreeRTOS implementation, tasks use two blocks of + * memory. The first block is used to hold the task's data structures. The + * second block is used by the task as its stack. If a task is created using + * xTaskCreate() then both blocks of memory are automatically dynamically + * allocated inside the xTaskCreate() function. (see + * http://www.freertos.org/a00111.html). If a task is created using + * xTaskCreateStatic() then the application writer must provide the required + * memory. xTaskCreateStatic() therefore allows a task to be created without + * using any dynamic memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param ulStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pxStackBuffer Must point to a StackType_t array that has at least + * ulStackDepth indexes - the array will then be used as the task's stack, + * removing the need for the stack to be allocated dynamically. + * + * @param pxTaskBuffer Must point to a variable of type StaticTask_t, which will + * then be used to hold the task's data structures, removing the need for the + * memory to be allocated dynamically. + * + * @return If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will + * be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer + * are NULL then the task will not be created and + * errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned. + * + * Example usage: +
+
+    // Dimensions the buffer that the task being created will use as its stack.
+    // NOTE:  This is the number of words the stack will hold, not the number of
+    // bytes.  For example, if each stack item is 32-bits, and this is set to 100,
+    // then 400 bytes (100 * 32-bits) will be allocated.
+    #define STACK_SIZE 200
+
+    // Structure that will hold the TCB of the task being created.
+    StaticTask_t xTaskBuffer;
+
+    // Buffer that the task being created will use as its stack.  Note this is
+    // an array of StackType_t variables.  The size of StackType_t is dependent on
+    // the RTOS port.
+    StackType_t xStack[ STACK_SIZE ];
+
+    // Function that implements the task being created.
+    void vTaskCode( void * pvParameters )
+    {
+        // The parameter value is expected to be 1 as 1 is passed in the
+        // pvParameters value in the call to xTaskCreateStatic().
+        configASSERT( ( uint32_t ) pvParameters == 1UL );
+
+        for( ;; )
+        {
+            // Task code goes here.
+        }
+    }
+
+    // Function that creates a task.
+    void vOtherFunction( void )
+    {
+        TaskHandle_t xHandle = NULL;
+
+        // Create the task without using any dynamic memory allocation.
+        xHandle = xTaskCreateStatic(
+                      vTaskCode,       // Function that implements the task.
+                      "NAME",          // Text name for the task.
+                      STACK_SIZE,      // Stack size in words, not bytes.
+                      ( void * ) 1,    // Parameter passed into the task.
+                      tskIDLE_PRIORITY,// Priority at which the task is created.
+                      xStack,          // Array to use as the task's stack.
+                      &xTaskBuffer );  // Variable to hold the task's data structure.
+
+        // puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
+        // been created, and xHandle will be the task's handle.  Use the handle
+        // to suspend the task.
+        vTaskSuspend( xHandle );
+    }
+   
+ * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * task. h + *
+ BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
+ * + * xTaskCreateRestricted() should only be used in systems that include an MPU + * implementation. + * + * Create a new task and add it to the list of tasks that are ready to run. + * The function parameters define the memory regions and associated access + * permissions allocated to the task. + * + * @param pxTaskDefinition Pointer to a structure that contains a member + * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API + * documentation) plus an optional stack buffer and the memory region + * definitions. + * + * @param pxCreatedTask Used to pass back a handle by which the created task + * can be referenced. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+// Create an TaskParameters_t structure that defines the task to be created.
+static const TaskParameters_t xCheckTaskParameters =
+{
+	vATask,		// pvTaskCode - the function that implements the task.
+	"ATask",	// pcName - just a text name for the task to assist debugging.
+	100,		// usStackDepth	- the stack size DEFINED IN WORDS.
+	NULL,		// pvParameters - passed into the task function as the function parameters.
+	( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
+	cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
+
+	// xRegions - Allocate up to three separate memory regions for access by
+	// the task, with appropriate access permissions.  Different processors have
+	// different memory alignment requirements - refer to the FreeRTOS documentation
+	// for full information.
+	{
+		// Base address					Length	Parameters
+        { cReadWriteArray,				32,		portMPU_REGION_READ_WRITE },
+        { cReadOnlyArray,				32,		portMPU_REGION_READ_ONLY },
+        { cPrivilegedOnlyAccessArray,	128,	portMPU_REGION_PRIVILEGED_READ_WRITE }
+	}
+};
+
+int main( void )
+{
+TaskHandle_t xHandle;
+
+	// Create a task from the const structure defined above.  The task handle
+	// is requested (the second parameter is not NULL) but in this case just for
+	// demonstration purposes as its not actually used.
+	xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
+
+	// Start the scheduler.
+	vTaskStartScheduler();
+
+	// Will only get here if there was insufficient memory to create the idle
+	// and/or timer task.
+	for( ;; );
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +#if( portUSING_MPU_WRAPPERS == 1 ) + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif + +/** + * task. h + *
+ void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
+ * + * Memory regions are assigned to a restricted task when the task is created by + * a call to xTaskCreateRestricted(). These regions can be redefined using + * vTaskAllocateMPURegions(). + * + * @param xTask The handle of the task being updated. + * + * @param xRegions A pointer to an MemoryRegion_t structure that contains the + * new memory region definitions. + * + * Example usage: +
+// Define an array of MemoryRegion_t structures that configures an MPU region
+// allowing read/write access for 1024 bytes starting at the beginning of the
+// ucOneKByte array.  The other two of the maximum 3 definable regions are
+// unused so set to zero.
+static const MemoryRegion_t xAltRegions[ portNUM_CONFIGURABLE_REGIONS ] =
+{
+	// Base address		Length		Parameters
+	{ ucOneKByte,		1024,		portMPU_REGION_READ_WRITE },
+	{ 0,				0,			0 },
+	{ 0,				0,			0 }
+};
+
+void vATask( void *pvParameters )
+{
+	// This task was created such that it has access to certain regions of
+	// memory as defined by the MPU configuration.  At some point it is
+	// desired that these MPU regions are replaced with that defined in the
+	// xAltRegions const struct above.  Use a call to vTaskAllocateMPURegions()
+	// for this purpose.  NULL is used as the task handle to indicate that this
+	// function should modify the MPU regions of the calling task.
+	vTaskAllocateMPURegions( NULL, xAltRegions );
+
+	// Now the task can continue its function, but from this point on can only
+	// access its stack and the ucOneKByte array (unless any other statically
+	// defined or shared regions have been declared elsewhere).
+}
+   
+ * \defgroup xTaskCreateRestricted xTaskCreateRestricted + * \ingroup Tasks + */ +void vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelete( TaskHandle_t xTask );
+ * + * INCLUDE_vTaskDelete must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Remove a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * NOTE: The idle task is responsible for freeing the kernel allocated + * memory from tasks that have been deleted. It is therefore important that + * the idle task is not starved of microcontroller processing time if your + * application makes any calls to vTaskDelete (). Memory allocated by the + * task code is not automatically freed, and should be freed before the task + * is deleted. + * + * See the demo application file death.c for sample code that utilises + * vTaskDelete (). + * + * @param xTask The handle of the task to be deleted. Passing NULL will + * cause the calling task to be deleted. + * + * Example usage: +
+ void vOtherFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create the task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // Use the handle to delete the task.
+	 vTaskDelete( xHandle );
+ }
+   
+ * \defgroup vTaskDelete vTaskDelete + * \ingroup Tasks + */ +void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK CONTROL API + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskDelay( const TickType_t xTicksToDelay );
+ * + * Delay a task for a given number of ticks. The actual time that the + * task remains blocked depends on the tick rate. The constant + * portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * INCLUDE_vTaskDelay must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * + * vTaskDelay() specifies a time at which the task wishes to unblock relative to + * the time at which vTaskDelay() is called. For example, specifying a block + * period of 100 ticks will cause the task to unblock 100 ticks after + * vTaskDelay() is called. vTaskDelay() does not therefore provide a good method + * of controlling the frequency of a periodic task as the path taken through the + * code, as well as other task and interrupt activity, will effect the frequency + * at which vTaskDelay() gets called and therefore the time at which the task + * next executes. See vTaskDelayUntil() for an alternative API function designed + * to facilitate fixed frequency execution. It does this by specifying an + * absolute time (rather than a relative time) at which the calling task should + * unblock. + * + * @param xTicksToDelay The amount of time, in tick periods, that + * the calling task should block. + * + * Example usage: + + void vTaskFunction( void * pvParameters ) + { + // Block for 500ms. + const TickType_t xDelay = 500 / portTICK_PERIOD_MS; + + for( ;; ) + { + // Simply toggle the LED every 500ms, blocking between each toggle. + vToggleLED(); + vTaskDelay( xDelay ); + } + } + + * \defgroup vTaskDelay vTaskDelay + * \ingroup TaskCtrl + */ +void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
+ * + * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Delay a task until a specified time. This function can be used by periodic + * tasks to ensure a constant execution frequency. + * + * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will + * cause a task to block for the specified number of ticks from the time vTaskDelay () is + * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed + * execution frequency as the time between a task starting to execute and that task + * calling vTaskDelay () may not be fixed [the task may take a different path though the + * code between calls, or may get interrupted or preempted a different number of times + * each time it executes]. + * + * Whereas vTaskDelay () specifies a wake time relative to the time at which the function + * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to + * unblock. + * + * The constant portTICK_PERIOD_MS can be used to calculate real time from the tick + * rate - with the resolution of one tick period. + * + * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the + * task was last unblocked. The variable must be initialised with the current time + * prior to its first use (see the example below). Following this the variable is + * automatically updated within vTaskDelayUntil (). + * + * @param xTimeIncrement The cycle time period. The task will be unblocked at + * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the + * same xTimeIncrement parameter value will cause the task to execute with + * a fixed interface period. + * + * Example usage: +
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ TickType_t xLastWakeTime;
+ const TickType_t xFrequency = 10;
+
+	 // Initialise the xLastWakeTime variable with the current time.
+	 xLastWakeTime = xTaskGetTickCount ();
+	 for( ;; )
+	 {
+		 // Wait for the next cycle.
+		 vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+		 // Perform action here.
+	 }
+ }
+   
+ * \defgroup vTaskDelayUntil vTaskDelayUntil + * \ingroup TaskCtrl + */ +void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskAbortDelay( TaskHandle_t xTask );
+ * + * INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this + * function to be available. + * + * A task will enter the Blocked state when it is waiting for an event. The + * event it is waiting for can be a temporal event (waiting for a time), such + * as when vTaskDelay() is called, or an event on an object, such as when + * xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task + * that is in the Blocked state is used in a call to xTaskAbortDelay() then the + * task will leave the Blocked state, and return from whichever function call + * placed the task into the Blocked state. + * + * @param xTask The handle of the task to remove from the Blocked state. + * + * @return If the task referenced by xTask was not in the Blocked state then + * pdFAIL is returned. Otherwise pdPASS is returned. + * + * \defgroup xTaskAbortDelay xTaskAbortDelay + * \ingroup TaskCtrl + */ +BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskPriorityGet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the priority of any task. + * + * @param xTask Handle of the task to be queried. Passing a NULL + * handle results in the priority of the calling task being returned. + * + * @return The priority of xTask. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to obtain the priority of the created task.
+	 // It was created with tskIDLE_PRIORITY, but may have changed
+	 // it itself.
+	 if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+	 {
+		 // The task has changed it's priority.
+	 }
+
+	 // ...
+
+	 // Is our priority higher than the created task?
+	 if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+	 {
+		 // Our priority (obtained using NULL handle) is higher.
+	 }
+ }
+   
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet + * \ingroup TaskCtrl + */ +UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask );
+ * + * A version of uxTaskPriorityGet() that can be used from an ISR. + */ +UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
eTaskState eTaskGetState( TaskHandle_t xTask );
+ * + * INCLUDE_eTaskGetState must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Obtain the state of any task. States are encoded by the eTaskState + * enumerated type. + * + * @param xTask Handle of the task to be queried. + * + * @return The state of xTask at the time the function was called. Note the + * state of the task might change between the function being called, and the + * functions return value being tested by the calling task. + */ +eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
+ * + * configUSE_TRACE_FACILITY must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * Populates a TaskStatus_t structure with information about a task. + * + * @param xTask Handle of the task being queried. If xTask is NULL then + * information will be returned about the calling task. + * + * @param pxTaskStatus A pointer to the TaskStatus_t structure that will be + * filled with information about the task referenced by the handle passed using + * the xTask parameter. + * + * @xGetFreeStackSpace The TaskStatus_t structure contains a member to report + * the stack high water mark of the task being queried. Calculating the stack + * high water mark takes a relatively long time, and can make the system + * temporarily unresponsive - so the xGetFreeStackSpace parameter is provided to + * allow the high water mark checking to be skipped. The high watermark value + * will only be written to the TaskStatus_t structure if xGetFreeStackSpace is + * not set to pdFALSE; + * + * @param eState The TaskStatus_t structure contains a member to report the + * state of the task being queried. Obtaining the task state is not as fast as + * a simple assignment - so the eState parameter is provided to allow the state + * information to be omitted from the TaskStatus_t structure. To obtain state + * information then set eState to eInvalid - otherwise the value passed in + * eState will be reported as the task state in the TaskStatus_t structure. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+ TaskStatus_t xTaskDetails;
+
+    // Obtain the handle of a task from its name.
+    xHandle = xTaskGetHandle( "Task_Name" );
+
+    // Check the handle is not NULL.
+    configASSERT( xHandle );
+
+    // Use the handle to obtain further information about the task.
+    vTaskGetInfo( xHandle,
+                  &xTaskDetails,
+                  pdTRUE, // Include the high water mark in xTaskDetails.
+                  eInvalid ); // Include the task state in xTaskDetails.
+ }
+   
+ * \defgroup vTaskGetInfo vTaskGetInfo + * \ingroup TaskCtrl + */ +void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
+ * + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Set the priority of any task. + * + * A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @param xTask Handle to the task for which the priority is being set. + * Passing a NULL handle results in the priority of the calling task being set. + * + * @param uxNewPriority The priority to which the task will be set. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to raise the priority of the created task.
+	 vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+	 // ...
+
+	 // Use a NULL handle to raise our priority to the same value.
+	 vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+   
+ * \defgroup vTaskPrioritySet vTaskPrioritySet + * \ingroup TaskCtrl + */ +void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Suspend any task. When suspended a task will never get any microcontroller + * processing time, no matter what its priority. + * + * Calls to vTaskSuspend are not accumulative - + * i.e. calling vTaskSuspend () twice on the same task still only requires one + * call to vTaskResume () to ready the suspended task. + * + * @param xTaskToSuspend Handle to the task being suspended. Passing a NULL + * handle will cause the calling task to be suspended. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Suspend ourselves.
+	 vTaskSuspend( NULL );
+
+	 // We cannot get here unless another task calls vTaskResume
+	 // with our handle as the parameter.
+ }
+   
+ * \defgroup vTaskSuspend vTaskSuspend + * \ingroup TaskCtrl + */ +void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskResume( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Resumes a suspended task. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * vTaskResume (). + * + * @param xTaskToResume Handle to the task being readied. + * + * Example usage: +
+ void vAFunction( void )
+ {
+ TaskHandle_t xHandle;
+
+	 // Create a task, storing the handle.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+	 // ...
+
+	 // Use the handle to suspend the created task.
+	 vTaskSuspend( xHandle );
+
+	 // ...
+
+	 // The created task will not run during this period, unless
+	 // another task calls vTaskResume( xHandle ).
+
+	 //...
+
+
+	 // Resume the suspended task ourselves.
+	 vTaskResume( xHandle );
+
+	 // The created task will once again get microcontroller processing
+	 // time in accordance with its priority within the system.
+ }
+   
+ * \defgroup vTaskResume vTaskResume + * \ingroup TaskCtrl + */ +void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void xTaskResumeFromISR( TaskHandle_t xTaskToResume );
+ * + * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be + * available. See the configuration section for more information. + * + * An implementation of vTaskResume() that can be called from within an ISR. + * + * A task that has been suspended by one or more calls to vTaskSuspend () + * will be made available for running again by a single call to + * xTaskResumeFromISR (). + * + * xTaskResumeFromISR() should not be used to synchronise a task with an + * interrupt if there is a chance that the interrupt could arrive prior to the + * task being suspended - as this can lead to interrupts being missed. Use of a + * semaphore as a synchronisation mechanism would avoid this eventuality. + * + * @param xTaskToResume Handle to the task being readied. + * + * @return pdTRUE if resuming the task should result in a context switch, + * otherwise pdFALSE. This is used by the ISR to determine if a context switch + * may be required following the ISR. + * + * \defgroup vTaskResumeFromISR vTaskResumeFromISR + * \ingroup TaskCtrl + */ +BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * SCHEDULER CONTROL + *----------------------------------------------------------*/ + +/** + * task. h + *
void vTaskStartScheduler( void );
+ * + * Starts the real time kernel tick processing. After calling the kernel + * has control over which tasks are executed and when. + * + * See the demo application file main.c for an example of creating + * tasks and starting the kernel. + * + * Example usage: +
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+   
+ * + * \defgroup vTaskStartScheduler vTaskStartScheduler + * \ingroup SchedulerControl + */ +void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskEndScheduler( void );
+ * + * NOTE: At the time of writing only the x86 real mode port, which runs on a PC + * in place of DOS, implements this function. + * + * Stops the real time kernel tick. All created tasks will be automatically + * deleted and multitasking (either preemptive or cooperative) will + * stop. Execution then resumes from the point where vTaskStartScheduler () + * was called, as if vTaskStartScheduler () had just returned. + * + * See the demo application file main. c in the demo/PC directory for an + * example that uses vTaskEndScheduler (). + * + * vTaskEndScheduler () requires an exit function to be defined within the + * portable layer (see vPortEndScheduler () in port. c for the PC port). This + * performs hardware specific operations such as stopping the kernel tick. + * + * vTaskEndScheduler () will cause all of the resources allocated by the + * kernel to be freed - but will not free resources allocated by application + * tasks. + * + * Example usage: +
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // At some point we want to end the real time kernel processing
+		 // so call ...
+		 vTaskEndScheduler ();
+	 }
+ }
+
+ void vAFunction( void )
+ {
+	 // Create at least one task before starting the kernel.
+	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+	 // Start the real time kernel with preemption.
+	 vTaskStartScheduler ();
+
+	 // Will only get here when the vTaskCode () task has called
+	 // vTaskEndScheduler ().  When we get here we are back to single task
+	 // execution.
+ }
+   
+ * + * \defgroup vTaskEndScheduler vTaskEndScheduler + * \ingroup SchedulerControl + */ +void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskSuspendAll( void );
+ * + * Suspends the scheduler without disabling interrupts. Context switches will + * not occur while the scheduler is suspended. + * + * After calling vTaskSuspendAll () the calling task will continue to execute + * without risk of being swapped out until a call to xTaskResumeAll () has been + * made. + * + * API functions that have the potential to cause a context switch (for example, + * vTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler + * is suspended. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the kernel
+		 // tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.
+		 xTaskResumeAll ();
+	 }
+ }
+   
+ * \defgroup vTaskSuspendAll vTaskSuspendAll + * \ingroup SchedulerControl + */ +void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskResumeAll( void );
+ * + * Resumes scheduler activity after it was suspended by a call to + * vTaskSuspendAll(). + * + * xTaskResumeAll() only resumes the scheduler. It does not unsuspend tasks + * that were previously suspended by a call to vTaskSuspend(). + * + * @return If resuming the scheduler caused a context switch then pdTRUE is + * returned, otherwise pdFALSE is returned. + * + * Example usage: +
+ void vTask1( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+
+		 // ...
+
+		 // At some point the task wants to perform a long operation during
+		 // which it does not want to get swapped out.  It cannot use
+		 // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+		 // operation may cause interrupts to be missed - including the
+		 // ticks.
+
+		 // Prevent the real time kernel swapping out the task.
+		 vTaskSuspendAll ();
+
+		 // Perform the operation here.  There is no need to use critical
+		 // sections as we have all the microcontroller processing time.
+		 // During this time interrupts will still operate and the real
+		 // time kernel tick count will be maintained.
+
+		 // ...
+
+		 // The operation is complete.  Restart the kernel.  We want to force
+		 // a context switch - but there is no point if resuming the scheduler
+		 // caused a context switch already.
+		 if( !xTaskResumeAll () )
+		 {
+			  taskYIELD ();
+		 }
+	 }
+ }
+   
+ * \defgroup xTaskResumeAll xTaskResumeAll + * \ingroup SchedulerControl + */ +BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION; + +/*----------------------------------------------------------- + * TASK UTILITIES + *----------------------------------------------------------*/ + +/** + * task. h + *
TickType_t xTaskGetTickCount( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * \defgroup xTaskGetTickCount xTaskGetTickCount + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCount( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
TickType_t xTaskGetTickCountFromISR( void );
+ * + * @return The count of ticks since vTaskStartScheduler was called. + * + * This is a version of xTaskGetTickCount() that is safe to be called from an + * ISR - provided that TickType_t is the natural word size of the + * microcontroller being used or interrupt nesting is either not supported or + * not being used. + * + * \defgroup xTaskGetTickCountFromISR xTaskGetTickCountFromISR + * \ingroup TaskUtils + */ +TickType_t xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
uint16_t uxTaskGetNumberOfTasks( void );
+ * + * @return The number of tasks that the real time kernel is currently managing. + * This includes all ready, blocked and suspended tasks. A task that + * has been deleted but not yet freed by the idle task will also be + * included in the count. + * + * \defgroup uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks + * \ingroup TaskUtils + */ +UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
char *pcTaskGetName( TaskHandle_t xTaskToQuery );
+ * + * @return The text (human readable) name of the task referenced by the handle + * xTaskToQuery. A task can query its own name by either passing in its own + * handle, or by setting xTaskToQuery to NULL. + * + * \defgroup pcTaskGetName pcTaskGetName + * \ingroup TaskUtils + */ +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );
+ * + * NOTE: This function takes a relatively long time to complete and should be + * used sparingly. + * + * @return The handle of the task that has the human readable name pcNameToQuery. + * NULL is returned if no matching name is found. INCLUDE_xTaskGetHandle + * must be set to 1 in FreeRTOSConfig.h for pcTaskGetHandle() to be available. + * + * \defgroup pcTaskGetHandle pcTaskGetHandle + * \ingroup TaskUtils + */ +TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task.h + *
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
+ * + * INCLUDE_uxTaskGetStackHighWaterMark must be set to 1 in FreeRTOSConfig.h for + * this function to be available. + * + * Returns the high water mark of the stack associated with xTask. That is, + * the minimum free stack space there has been (in words, so on a 32 bit machine + * a value of 1 means 4 bytes) since the task started. The smaller the returned + * number the closer the task has come to overflowing its stack. + * + * @param xTask Handle of the task associated with the stack to be checked. + * Set xTask to NULL to check the stack of the calling task. + * + * @return The smallest amount of free stack space there has been (in words, so + * actual spaces on the stack rather than bytes) since the task referenced by + * xTask was created. + */ +UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/* When using trace macros it is sometimes necessary to include task.h before +FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined, +so the following two prototypes will cause a compilation error. This can be +fixed by simply guarding against the inclusion of these two prototypes unless +they are explicitly required by the configUSE_APPLICATION_TASK_TAG configuration +constant. */ +#ifdef configUSE_APPLICATION_TASK_TAG + #if configUSE_APPLICATION_TASK_TAG == 1 + /** + * task.h + *
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
+ * + * Sets pxHookFunction to be the task hook function used by the task xTask. + * Passing xTask as NULL has the effect of setting the calling tasks hook + * function. + */ + void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) PRIVILEGED_FUNCTION; + + /** + * task.h + *
void xTaskGetApplicationTaskTag( TaskHandle_t xTask );
+ * + * Returns the pxHookFunction value assigned to the task xTask. + */ + TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + #endif /* configUSE_APPLICATION_TASK_TAG ==1 */ +#endif /* ifdef configUSE_APPLICATION_TASK_TAG */ + +#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + + /* Each task contains an array of pointers that is dimensioned by the + configNUM_THREAD_LOCAL_STORAGE_POINTERS setting in FreeRTOSConfig.h. The + kernel does not use the pointers itself, so the application writer can use + the pointers for any purpose they wish. The following two functions are + used to set and query a pointer respectively. */ + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) PRIVILEGED_FUNCTION; + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) PRIVILEGED_FUNCTION; + +#endif + +/** + * task.h + *
BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );
+ * + * Calls the hook function associated with xTask. Passing xTask as NULL has + * the effect of calling the Running tasks (the calling task) hook function. + * + * pvParameter is passed to the hook function for the task to interpret as it + * wants. The return value is the value returned by the task hook function + * registered by the user. + */ +BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) PRIVILEGED_FUNCTION; + +/** + * xTaskGetIdleTaskHandle() is only available if + * INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h. + * + * Simply returns the handle of the idle task. It is not valid to call + * xTaskGetIdleTaskHandle() before the scheduler has been started. + */ +TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; + +/** + * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for + * uxTaskGetSystemState() to be available. + * + * uxTaskGetSystemState() populates an TaskStatus_t structure for each task in + * the system. TaskStatus_t structures contain, among other things, members + * for the task handle, task name, task priority, task state, and total amount + * of run time consumed by the task. See the TaskStatus_t structure + * definition in this file for the full member list. + * + * NOTE: This function is intended for debugging use only as its use results in + * the scheduler remaining suspended for an extended period. + * + * @param pxTaskStatusArray A pointer to an array of TaskStatus_t structures. + * The array must contain at least one TaskStatus_t structure for each task + * that is under the control of the RTOS. The number of tasks under the control + * of the RTOS can be determined using the uxTaskGetNumberOfTasks() API function. + * + * @param uxArraySize The size of the array pointed to by the pxTaskStatusArray + * parameter. The size is specified as the number of indexes in the array, or + * the number of TaskStatus_t structures contained in the array, not by the + * number of bytes in the array. + * + * @param pulTotalRunTime If configGENERATE_RUN_TIME_STATS is set to 1 in + * FreeRTOSConfig.h then *pulTotalRunTime is set by uxTaskGetSystemState() to the + * total run time (as defined by the run time stats clock, see + * http://www.freertos.org/rtos-run-time-stats.html) since the target booted. + * pulTotalRunTime can be set to NULL to omit the total run time information. + * + * @return The number of TaskStatus_t structures that were populated by + * uxTaskGetSystemState(). This should equal the number returned by the + * uxTaskGetNumberOfTasks() API function, but will be zero if the value passed + * in the uxArraySize parameter was too small. + * + * Example usage: +
+    // This example demonstrates how a human readable table of run time stats
+	// information is generated from raw data provided by uxTaskGetSystemState().
+	// The human readable table is written to pcWriteBuffer
+	void vTaskGetRunTimeStats( char *pcWriteBuffer )
+	{
+	TaskStatus_t *pxTaskStatusArray;
+	volatile UBaseType_t uxArraySize, x;
+	uint32_t ulTotalRunTime, ulStatsAsPercentage;
+
+		// Make sure the write buffer does not contain a string.
+		*pcWriteBuffer = 0x00;
+
+		// Take a snapshot of the number of tasks in case it changes while this
+		// function is executing.
+		uxArraySize = uxTaskGetNumberOfTasks();
+
+		// Allocate a TaskStatus_t structure for each task.  An array could be
+		// allocated statically at compile time.
+		pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) );
+
+		if( pxTaskStatusArray != NULL )
+		{
+			// Generate raw status information about each task.
+			uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
+
+			// For percentage calculations.
+			ulTotalRunTime /= 100UL;
+
+			// Avoid divide by zero errors.
+			if( ulTotalRunTime > 0 )
+			{
+				// For each populated position in the pxTaskStatusArray array,
+				// format the raw data as human readable ASCII data
+				for( x = 0; x < uxArraySize; x++ )
+				{
+					// What percentage of the total run time has the task used?
+					// This will always be rounded down to the nearest integer.
+					// ulTotalRunTimeDiv100 has already been divided by 100.
+					ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;
+
+					if( ulStatsAsPercentage > 0UL )
+					{
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
+					}
+					else
+					{
+						// If the percentage is zero here then the task has
+						// consumed less than 1% of the total run time.
+						sprintf( pcWriteBuffer, "%s\t\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].pcTaskName, pxTaskStatusArray[ x ].ulRunTimeCounter );
+					}
+
+					pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
+				}
+			}
+
+			// The array is no longer needed, free the memory it consumes.
+			vPortFree( pxTaskStatusArray );
+		}
+	}
+	
+ */ +UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
void vTaskList( char *pcWriteBuffer );
+ * + * configUSE_TRACE_FACILITY and configUSE_STATS_FORMATTING_FUNCTIONS must + * both be defined as 1 for this function to be available. See the + * configuration section of the FreeRTOS.org website for more information. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Lists all the current tasks, along with their current state and stack + * usage high water mark. + * + * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or + * suspended ('S'). + * + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays task + * names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that might + * bloat the code size, use a lot of stack, and provide different results on + * different platforms. An alternative, tiny, third party, and limited + * functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly through a + * call to vTaskList(). + * + * @param pcWriteBuffer A buffer into which the above mentioned details + * will be written, in ASCII form. This buffer is assumed to be large + * enough to contain the generated report. Approximately 40 bytes per + * task should be sufficient. + * + * \defgroup vTaskList vTaskList + * \ingroup TaskUtils + */ +void vTaskList( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
void vTaskGetRunTimeStats( char *pcWriteBuffer );
+ * + * configGENERATE_RUN_TIME_STATS and configUSE_STATS_FORMATTING_FUNCTIONS + * must both be defined as 1 for this function to be available. The application + * must also then provide definitions for + * portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and portGET_RUN_TIME_COUNTER_VALUE() + * to configure a peripheral timer/counter and return the timers current count + * value respectively. The counter should be at least 10 times the frequency of + * the tick count. + * + * NOTE 1: This function will disable interrupts for its duration. It is + * not intended for normal application runtime use but as a debug aid. + * + * Setting configGENERATE_RUN_TIME_STATS to 1 will result in a total + * accumulated execution time being stored for each task. The resolution + * of the accumulated time value depends on the frequency of the timer + * configured by the portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro. + * Calling vTaskGetRunTimeStats() writes the total execution time of each + * task into a buffer, both as an absolute count value and as a percentage + * of the total system execution time. + * + * NOTE 2: + * + * This function is provided for convenience only, and is used by many of the + * demo applications. Do not consider it to be part of the scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that displays the + * amount of time each task has spent in the Running state in both absolute and + * percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library function + * that might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, and + * limited functionality implementation of sprintf() is provided in many of the + * FreeRTOS/Demo sub-directories in a file called printf-stdarg.c (note + * printf-stdarg.c does not provide a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() directly + * to get access to raw stats data, rather than indirectly through a call to + * vTaskGetRunTimeStats(). + * + * @param pcWriteBuffer A buffer into which the execution times will be + * written, in ASCII form. This buffer is assumed to be large enough to + * contain the generated report. Approximately 40 bytes per task should + * be sufficient. + * + * \defgroup vTaskGetRunTimeStats vTaskGetRunTimeStats + * \ingroup TaskUtils + */ +void vTaskGetRunTimeStats( char *pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * task. h + *
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * pulPreviousNotificationValue - + * Can be used to pass out the subject task's notification value before any + * bits are modified by the notify function. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION; +#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL ) +#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * A version of xTaskNotify() that can be used from an interrupt service routine + * (ISR). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @param ulValue Data that can be sent with the notification. How the data is + * used depends on the value of the eAction parameter. + * + * @param eAction Specifies how the notification updates the task's notification + * value, if at all. Valid values for eAction are as follows: + * + * eSetBits - + * The task's notification value is bitwise ORed with ulValue. xTaskNofify() + * always returns pdPASS in this case. + * + * eIncrement - + * The task's notification value is incremented. ulValue is not used and + * xTaskNotify() always returns pdPASS in this case. + * + * eSetValueWithOverwrite - + * The task's notification value is set to the value of ulValue, even if the + * task being notified had not yet processed the previous notification (the + * task already had a notification pending). xTaskNotify() always returns + * pdPASS in this case. + * + * eSetValueWithoutOverwrite - + * If the task being notified did not already have a notification pending then + * the task's notification value is set to ulValue and xTaskNotify() will + * return pdPASS. If the task being notified already had a notification + * pending then no action is performed and pdFAIL is returned. + * + * eNoAction - + * The task receives a notification without its notification value being + * updated. ulValue is not used and xTaskNotify() always returns pdPASS in + * this case. + * + * @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set + * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the + * task to which the notification was sent to leave the Blocked state, and the + * unblocked task has a priority higher than the currently running task. If + * xTaskNotifyFromISR() sets this value to pdTRUE then a context switch should + * be requested before the interrupt is exited. How a context switch is + * requested from an ISR is dependent on the port - see the documentation page + * for the port in use. + * + * @return Dependent on the value of eAction. See the description of the + * eAction parameter. + * + * \defgroup xTaskNotify xTaskNotify + * \ingroup TaskNotifications + */ +BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; +#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) ) +#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) ) + +/** + * task. h + *
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * A notification sent to a task will remain pending until it is cleared by the + * task calling xTaskNotifyWait() or ulTaskNotifyTake(). If the task was + * already in the Blocked state to wait for a notification when the notification + * arrives then the task will automatically be removed from the Blocked state + * (unblocked) and the notification cleared. + * + * A task can use xTaskNotifyWait() to [optionally] block to wait for a + * notification to be pending, or ulTaskNotifyTake() to [optionally] block + * to wait for its notification value to have a non-zero value. The task does + * not consume any CPU time while it is in the Blocked state. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param ulBitsToClearOnEntry Bits that are set in ulBitsToClearOnEntry value + * will be cleared in the calling task's notification value before the task + * checks to see if any notifications are pending, and optionally blocks if no + * notifications are pending. Setting ulBitsToClearOnEntry to ULONG_MAX (if + * limits.h is included) or 0xffffffffUL (if limits.h is not included) will have + * the effect of resetting the task's notification value to 0. Setting + * ulBitsToClearOnEntry to 0 will leave the task's notification value unchanged. + * + * @param ulBitsToClearOnExit If a notification is pending or received before + * the calling task exits the xTaskNotifyWait() function then the task's + * notification value (see the xTaskNotify() API function) is passed out using + * the pulNotificationValue parameter. Then any bits that are set in + * ulBitsToClearOnExit will be cleared in the task's notification value (note + * *pulNotificationValue is set before any bits are cleared). Setting + * ulBitsToClearOnExit to ULONG_MAX (if limits.h is included) or 0xffffffffUL + * (if limits.h is not included) will have the effect of resetting the task's + * notification value to 0 before the function exits. Setting + * ulBitsToClearOnExit to 0 will leave the task's notification value unchanged + * when the function exits (in which case the value passed out in + * pulNotificationValue will match the task's notification value). + * + * @param pulNotificationValue Used to pass the task's notification value out + * of the function. Note the value passed out will not be effected by the + * clearing of any bits caused by ulBitsToClearOnExit being non-zero. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for a notification to be received, should a notification + * not already be pending when xTaskNotifyWait() was called. The task + * will not consume any processing time while it is in the Blocked state. This + * is specified in kernel ticks, the macro pdMS_TO_TICSK( value_in_ms ) can be + * used to convert a time specified in milliseconds to a time specified in + * ticks. + * + * @return If a notification was received (including notifications that were + * already pending when xTaskNotifyWait was called) then pdPASS is + * returned. Otherwise pdFAIL is returned. + * + * \defgroup xTaskNotifyWait xTaskNotifyWait + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro + * to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * xTaskNotifyGive() is a helper macro intended for use when task notifications + * are used as light weight and faster binary or counting semaphore equivalents. + * Actual FreeRTOS semaphores are given using the xSemaphoreGive() API function, + * the equivalent action that instead uses a task notification is + * xTaskNotifyGive(). + * + * When task notifications are being used as a binary or counting semaphore + * equivalent then the task being notified should wait for the notification + * using the ulTaskNotificationTake() API function rather than the + * xTaskNotifyWait() API function. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details. + * + * @param xTaskToNotify The handle of the task being notified. The handle to a + * task can be returned from the xTaskCreate() API function used to create the + * task, and the handle of the currently running task can be obtained by calling + * xTaskGetCurrentTaskHandle(). + * + * @return xTaskNotifyGive() is a macro that calls xTaskNotify() with the + * eAction parameter set to eIncrement - so pdPASS is always returned. + * + * \defgroup xTaskNotifyGive xTaskNotifyGive + * \ingroup TaskNotifications + */ +#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL ) + +/** + * task. h + *
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
+ *
+ * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this macro
+ * to be available.
+ *
+ * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private
+ * "notification value", which is a 32-bit unsigned integer (uint32_t).
+ *
+ * A version of xTaskNotifyGive() that can be called from an interrupt service
+ * routine (ISR).
+ *
+ * Events can be sent to a task using an intermediary object.  Examples of such
+ * objects are queues, semaphores, mutexes and event groups.  Task notifications
+ * are a method of sending an event directly to a task without the need for such
+ * an intermediary object.
+ *
+ * A notification sent to a task can optionally perform an action, such as
+ * update, overwrite or increment the task's notification value.  In that way
+ * task notifications can be used to send data to a task, or be used as light
+ * weight and fast binary or counting semaphores.
+ *
+ * vTaskNotifyGiveFromISR() is intended for use when task notifications are
+ * used as light weight and faster binary or counting semaphore equivalents.
+ * Actual FreeRTOS semaphores are given from an ISR using the
+ * xSemaphoreGiveFromISR() API function, the equivalent action that instead uses
+ * a task notification is vTaskNotifyGiveFromISR().
+ *
+ * When task notifications are being used as a binary or counting semaphore
+ * equivalent then the task being notified should wait for the notification
+ * using the ulTaskNotificationTake() API function rather than the
+ * xTaskNotifyWait() API function.
+ *
+ * See http://www.FreeRTOS.org/RTOS-task-notifications.html for more details.
+ *
+ * @param xTaskToNotify The handle of the task being notified.  The handle to a
+ * task can be returned from the xTaskCreate() API function used to create the
+ * task, and the handle of the currently running task can be obtained by calling
+ * xTaskGetCurrentTaskHandle().
+ *
+ * @param pxHigherPriorityTaskWoken  vTaskNotifyGiveFromISR() will set
+ * *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the
+ * task to which the notification was sent to leave the Blocked state, and the
+ * unblocked task has a priority higher than the currently running task.  If
+ * vTaskNotifyGiveFromISR() sets this value to pdTRUE then a context switch
+ * should be requested before the interrupt is exited.  How a context switch is
+ * requested from an ISR is dependent on the port - see the documentation page
+ * for the port in use.
+ *
+ * \defgroup xTaskNotifyWait xTaskNotifyWait
+ * \ingroup TaskNotifications
+ */
+void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
+
+/**
+ * task. h
+ * 
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
+ * + * configUSE_TASK_NOTIFICATIONS must be undefined or defined as 1 for this + * function to be available. + * + * When configUSE_TASK_NOTIFICATIONS is set to one each task has its own private + * "notification value", which is a 32-bit unsigned integer (uint32_t). + * + * Events can be sent to a task using an intermediary object. Examples of such + * objects are queues, semaphores, mutexes and event groups. Task notifications + * are a method of sending an event directly to a task without the need for such + * an intermediary object. + * + * A notification sent to a task can optionally perform an action, such as + * update, overwrite or increment the task's notification value. In that way + * task notifications can be used to send data to a task, or be used as light + * weight and fast binary or counting semaphores. + * + * ulTaskNotifyTake() is intended for use when a task notification is used as a + * faster and lighter weight binary or counting semaphore alternative. Actual + * FreeRTOS semaphores are taken using the xSemaphoreTake() API function, the + * equivalent action that instead uses a task notification is + * ulTaskNotifyTake(). + * + * When a task is using its notification value as a binary or counting semaphore + * other tasks should send notifications to it using the xTaskNotifyGive() + * macro, or xTaskNotify() function with the eAction parameter set to + * eIncrement. + * + * ulTaskNotifyTake() can either clear the task's notification value to + * zero on exit, in which case the notification value acts like a binary + * semaphore, or decrement the task's notification value on exit, in which case + * the notification value acts like a counting semaphore. + * + * A task can use ulTaskNotifyTake() to [optionally] block to wait for a + * the task's notification value to be non-zero. The task does not consume any + * CPU time while it is in the Blocked state. + * + * Where as xTaskNotifyWait() will return when a notification is pending, + * ulTaskNotifyTake() will return when the task's notification value is + * not zero. + * + * See http://www.FreeRTOS.org/RTOS-task-notifications.html for details. + * + * @param xClearCountOnExit if xClearCountOnExit is pdFALSE then the task's + * notification value is decremented when the function exits. In this way the + * notification value acts like a counting semaphore. If xClearCountOnExit is + * not pdFALSE then the task's notification value is cleared to zero when the + * function exits. In this way the notification value acts like a binary + * semaphore. + * + * @param xTicksToWait The maximum amount of time that the task should wait in + * the Blocked state for the task's notification value to be greater than zero, + * should the count not already be greater than zero when + * ulTaskNotifyTake() was called. The task will not consume any processing + * time while it is in the Blocked state. This is specified in kernel ticks, + * the macro pdMS_TO_TICSK( value_in_ms ) can be used to convert a time + * specified in milliseconds to a time specified in ticks. + * + * @return The task's notification count before it is either cleared to zero or + * decremented (see the xClearCountOnExit parameter). + * + * \defgroup ulTaskNotifyTake ulTaskNotifyTake + * \ingroup TaskNotifications + */ +uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * task. h + *
BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask );
+ * + * If the notification state of the task referenced by the handle xTask is + * eNotified, then set the task's notification state to eNotWaitingNotification. + * The task's notification value is not altered. Set xTask to NULL to clear the + * notification state of the calling task. + * + * @return pdTRUE if the task's notification state was set to + * eNotWaitingNotification, otherwise pdFALSE. + * \defgroup xTaskNotifyStateClear xTaskNotifyStateClear + * \ingroup TaskNotifications + */ +BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); + +/*----------------------------------------------------------- + * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES + *----------------------------------------------------------*/ + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Called from the real time kernel tick (either preemptive or cooperative), + * this increments the tick count and checks if any tasks that are blocked + * for a finite period required removing from a blocked list and placing on + * a ready list. If a non-zero value is returned then a context switch is + * required because either: + * + A task was removed from a blocked list because its timeout had expired, + * or + * + Time slicing is in use and there is a task of equal priority to the + * currently running task. + */ +BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes the calling task from the ready list and places it both + * on the list of tasks waiting for a particular event, and the + * list of delayed tasks. The task will be removed from both lists + * and replaced on the ready list should either the event occur (and + * there be no higher priority tasks waiting on the same event) or + * the delay period expires. + * + * The 'unordered' version replaces the event list item value with the + * xItemValue value, and inserts the list item at the end of the list. + * + * The 'ordered' version uses the existing event list item value (which is the + * owning tasks priority) to insert the list item into the event list is task + * priority order. + * + * @param pxEventList The list containing tasks that are blocked waiting + * for the event to occur. + * + * @param xItemValue The item value to use for the event list item when the + * event list is not ordered by task priority. + * + * @param xTicksToWait The maximum amount of time that the task should wait + * for the event to occur. This is specified in kernel ticks,the constant + * portTICK_PERIOD_MS can be used to convert kernel ticks into a real time + * period. + */ +void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * This function performs nearly the same function as vTaskPlaceOnEventList(). + * The difference being that this function does not permit tasks to block + * indefinitely, whereas vTaskPlaceOnEventList() does. + * + */ +void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN + * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED. + * + * Removes a task from both the specified event list and the list of blocked + * tasks, and places it on a ready queue. + * + * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called + * if either an event occurs to unblock a task, or the block timeout period + * expires. + * + * xTaskRemoveFromEventList() is used when the event list is in task priority + * order. It removes the list item from the head of the event list as that will + * have the highest priority owning task of all the tasks on the event list. + * xTaskRemoveFromUnorderedEventList() is used when the event list is not + * ordered and the event list items hold something other than the owning tasks + * priority. In this case the event list item value is updated to the value + * passed in the xItemValue parameter. + * + * @return pdTRUE if the task being removed has a higher priority than the task + * making the call, otherwise pdFALSE. + */ +BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION; +BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION; + +/* + * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY + * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS + * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER. + * + * Sets the pointer to the current TCB to the TCB of the highest priority task + * that is ready to run. + */ +void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; + +/* + * THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY + * THE EVENT BITS MODULE. + */ +TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; + +/* + * Return the handle of the calling task. + */ +TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; + +/* + * Capture the current time status for future reference. + */ +void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; + +/* + * Compare the time status now with that previously captured to see if the + * timeout has expired. + */ +BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION; + +/* + * Shortcut used by the queue implementation to prevent unnecessary call to + * taskYIELD(); + */ +void vTaskMissedYield( void ) PRIVILEGED_FUNCTION; + +/* + * Returns the scheduler state as taskSCHEDULER_RUNNING, + * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED. + */ +BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION; + +/* + * Raises the priority of the mutex holder to that of the calling task should + * the mutex holder have a priority less than the calling task. + */ +void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Set the priority of a task back to its proper priority in the case that it + * inherited a higher priority while it was holding a semaphore. + */ +BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; + +/* + * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. + */ +UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/* + * Set the uxTaskNumber of the task referenced by the xTask parameter to + * uxHandle. + */ +void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) PRIVILEGED_FUNCTION; + +/* + * Only available when configUSE_TICKLESS_IDLE is set to 1. + * If tickless mode is being used, or a low power mode is implemented, then + * the tick interrupt will not execute during idle periods. When this is the + * case, the tick count value maintained by the scheduler needs to be kept up + * to date with the actual execution time by being skipped forward by a time + * equal to the idle period. + */ +void vTaskStepTick( const TickType_t xTicksToJump ) PRIVILEGED_FUNCTION; + +/* + * Only avilable when configUSE_TICKLESS_IDLE is set to 1. + * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port + * specific sleep function to determine if it is ok to proceed with the sleep, + * and if it is ok to proceed, if it is ok to sleep indefinitely. + * + * This function is necessary because portSUPPRESS_TICKS_AND_SLEEP() is only + * called with the scheduler suspended, not from within a critical section. It + * is therefore possible for an interrupt to request a context switch between + * portSUPPRESS_TICKS_AND_SLEEP() and the low power mode actually being + * entered. eTaskConfirmSleepModeStatus() should be called from a short + * critical section between the timer being stopped and the sleep mode being + * entered to ensure it is ok to proceed into the sleep mode. + */ +eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; + +/* + * For internal use only. Increment the mutex held count when a mutex is + * taken and return the handle of the task that has taken the mutex. + */ +void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* INC_TASK_H */ + + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/timers.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/timers.h new file mode 100755 index 0000000..798c955 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/include/timers.h @@ -0,0 +1,1314 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef TIMERS_H +#define TIMERS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include timers.h" +#endif + +/*lint -e537 This headers are only multiply included if the application code +happens to also be including task.h. */ +#include "task.h" +/*lint +e537 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * MACROS AND DEFINITIONS + *----------------------------------------------------------*/ + +/* IDs for commands that can be sent/received on the timer queue. These are to +be used solely through the macros that make up the public software timer API, +as defined below. The commands that are sent from interrupts must use the +highest numbers as tmrFIRST_FROM_ISR_COMMAND is used to determine if the task +or interrupt version of the queue send function should be used. */ +#define tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR ( ( BaseType_t ) -2 ) +#define tmrCOMMAND_EXECUTE_CALLBACK ( ( BaseType_t ) -1 ) +#define tmrCOMMAND_START_DONT_TRACE ( ( BaseType_t ) 0 ) +#define tmrCOMMAND_START ( ( BaseType_t ) 1 ) +#define tmrCOMMAND_RESET ( ( BaseType_t ) 2 ) +#define tmrCOMMAND_STOP ( ( BaseType_t ) 3 ) +#define tmrCOMMAND_CHANGE_PERIOD ( ( BaseType_t ) 4 ) +#define tmrCOMMAND_DELETE ( ( BaseType_t ) 5 ) + +#define tmrFIRST_FROM_ISR_COMMAND ( ( BaseType_t ) 6 ) +#define tmrCOMMAND_START_FROM_ISR ( ( BaseType_t ) 6 ) +#define tmrCOMMAND_RESET_FROM_ISR ( ( BaseType_t ) 7 ) +#define tmrCOMMAND_STOP_FROM_ISR ( ( BaseType_t ) 8 ) +#define tmrCOMMAND_CHANGE_PERIOD_FROM_ISR ( ( BaseType_t ) 9 ) + + +/** + * Type by which software timers are referenced. For example, a call to + * xTimerCreate() returns an TimerHandle_t variable that can then be used to + * reference the subject timer in calls to other software timer API functions + * (for example, xTimerStart(), xTimerReset(), etc.). + */ +typedef void * TimerHandle_t; + +/* + * Defines the prototype to which timer callback functions must conform. + */ +typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer ); + +/* + * Defines the prototype to which functions used with the + * xTimerPendFunctionCallFromISR() function must conform. + */ +typedef void (*PendedFunction_t)( void *, uint32_t ); + +/** + * TimerHandle_t xTimerCreate( const char * const pcTimerName, + * TickType_t xTimerPeriodInTicks, + * UBaseType_t uxAutoReload, + * void * pvTimerID, + * TimerCallbackFunction_t pxCallbackFunction ); + * + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a + * timer into the active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer + * by its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick + * periods so the constant portTICK_PERIOD_MS can be used to convert a time that + * has been specified in milliseconds. For example, if the timer must expire + * after 100 ticks, then xTimerPeriodInTicks should be set to 100. + * Alternatively, if the timer must expire after 500ms, then xPeriod can be set + * to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or + * equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. + * If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by TimerCallbackFunction_t, + * which is "void vCallbackFunction( TimerHandle_t xTimer );". + * + * @return If the timer is successfully created then a handle to the newly + * created timer is returned. If the timer cannot be created (because either + * there is insufficient FreeRTOS heap remaining to allocate the timer + * structures, or the timer period was set to 0) then NULL is returned. + * + * Example usage: + * @verbatim + * #define NUM_TIMERS 5 + * + * // An array to hold handles to the created timers. + * TimerHandle_t xTimers[ NUM_TIMERS ]; + * + * // An array to hold a count of the number of times each timer expires. + * int32_t lExpireCounters[ NUM_TIMERS ] = { 0 }; + * + * // Define a callback function that will be used by multiple timer instances. + * // The callback function does nothing but count the number of times the + * // associated timer expires, and stop the timer once the timer has expired + * // 10 times. + * void vTimerCallback( TimerHandle_t pxTimer ) + * { + * int32_t lArrayIndex; + * const int32_t xMaxExpiryCountBeforeStopping = 10; + * + * // Optionally do something if the pxTimer parameter is NULL. + * configASSERT( pxTimer ); + * + * // Which timer expired? + * lArrayIndex = ( int32_t ) pvTimerGetTimerID( pxTimer ); + * + * // Increment the number of times that pxTimer has expired. + * lExpireCounters[ lArrayIndex ] += 1; + * + * // If the timer has expired 10 times then stop it from running. + * if( lExpireCounters[ lArrayIndex ] == xMaxExpiryCountBeforeStopping ) + * { + * // Do not use a block time if calling a timer API function from a + * // timer callback function, as doing so could cause a deadlock! + * xTimerStop( pxTimer, 0 ); + * } + * } + * + * void main( void ) + * { + * int32_t x; + * + * // Create then start some timers. Starting the timers before the scheduler + * // has been started means the timers will start running immediately that + * // the scheduler starts. + * for( x = 0; x < NUM_TIMERS; x++ ) + * { + * xTimers[ x ] = xTimerCreate( "Timer", // Just a text name, not used by the kernel. + * ( 100 * x ), // The timer period in ticks. + * pdTRUE, // The timers will auto-reload themselves when they expire. + * ( void * ) x, // Assign each timer a unique id equal to its array index. + * vTimerCallback // Each timer calls the same callback when it expires. + * ); + * + * if( xTimers[ x ] == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xTimers[ x ], 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif + +/** + * TimerHandle_t xTimerCreateStatic(const char * const pcTimerName, + * TickType_t xTimerPeriodInTicks, + * UBaseType_t uxAutoReload, + * void * pvTimerID, + * TimerCallbackFunction_t pxCallbackFunction, + * StaticTimer_t *pxTimerBuffer ); + * + * Creates a new software timer instance, and returns a handle by which the + * created software timer can be referenced. + * + * Internally, within the FreeRTOS implementation, software timers use a block + * of memory, in which the timer data structure is stored. If a software timer + * is created using xTimerCreate() then the required memory is automatically + * dynamically allocated inside the xTimerCreate() function. (see + * http://www.freertos.org/a00111.html). If a software timer is created using + * xTimerCreateStatic() then the application writer must provide the memory that + * will get used by the software timer. xTimerCreateStatic() therefore allows a + * software timer to be created without using any dynamic memory allocation. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a + * timer into the active state. + * + * @param pcTimerName A text name that is assigned to the timer. This is done + * purely to assist debugging. The kernel itself only ever references a timer + * by its handle, and never by its name. + * + * @param xTimerPeriodInTicks The timer period. The time is defined in tick + * periods so the constant portTICK_PERIOD_MS can be used to convert a time that + * has been specified in milliseconds. For example, if the timer must expire + * after 100 ticks, then xTimerPeriodInTicks should be set to 100. + * Alternatively, if the timer must expire after 500ms, then xPeriod can be set + * to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than or + * equal to 1000. + * + * @param uxAutoReload If uxAutoReload is set to pdTRUE then the timer will + * expire repeatedly with a frequency set by the xTimerPeriodInTicks parameter. + * If uxAutoReload is set to pdFALSE then the timer will be a one-shot timer and + * enter the dormant state after it expires. + * + * @param pvTimerID An identifier that is assigned to the timer being created. + * Typically this would be used in the timer callback function to identify which + * timer expired when the same callback function is assigned to more than one + * timer. + * + * @param pxCallbackFunction The function to call when the timer expires. + * Callback functions must have the prototype defined by TimerCallbackFunction_t, + * which is "void vCallbackFunction( TimerHandle_t xTimer );". + * + * @param pxTimerBuffer Must point to a variable of type StaticTimer_t, which + * will be then be used to hold the software timer's data structures, removing + * the need for the memory to be allocated dynamically. + * + * @return If the timer is created then a handle to the created timer is + * returned. If pxTimerBuffer was NULL then NULL is returned. + * + * Example usage: + * @verbatim + * + * // The buffer used to hold the software timer's data structure. + * static StaticTimer_t xTimerBuffer; + * + * // A variable that will be incremented by the software timer's callback + * // function. + * UBaseType_t uxVariableToIncrement = 0; + * + * // A software timer callback function that increments a variable passed to + * // it when the software timer was created. After the 5th increment the + * // callback function stops the software timer. + * static void prvTimerCallback( TimerHandle_t xExpiredTimer ) + * { + * UBaseType_t *puxVariableToIncrement; + * BaseType_t xReturned; + * + * // Obtain the address of the variable to increment from the timer ID. + * puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); + * + * // Increment the variable to show the timer callback has executed. + * ( *puxVariableToIncrement )++; + * + * // If this callback has executed the required number of times, stop the + * // timer. + * if( *puxVariableToIncrement == 5 ) + * { + * // This is called from a timer callback so must not block. + * xTimerStop( xExpiredTimer, staticDONT_BLOCK ); + * } + * } + * + * + * void main( void ) + * { + * // Create the software time. xTimerCreateStatic() has an extra parameter + * // than the normal xTimerCreate() API function. The parameter is a pointer + * // to the StaticTimer_t structure that will hold the software timer + * // structure. If the parameter is passed as NULL then the structure will be + * // allocated dynamically, just as if xTimerCreate() had been called. + * xTimer = xTimerCreateStatic( "T1", // Text name for the task. Helps debugging only. Not used by FreeRTOS. + * xTimerPeriod, // The period of the timer in ticks. + * pdTRUE, // This is an auto-reload timer. + * ( void * ) &uxVariableToIncrement, // A variable incremented by the software timer's callback function + * prvTimerCallback, // The function to execute when the timer expires. + * &xTimerBuffer ); // The buffer that will hold the software timer structure. + * + * // The scheduler has not started yet so a block time is not used. + * xReturned = xTimerStart( xTimer, 0 ); + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timers running as they have already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#endif /* configSUPPORT_STATIC_ALLOCATION */ + +/** + * void *pvTimerGetTimerID( TimerHandle_t xTimer ); + * + * Returns the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer, and by calling the + * vTimerSetTimerID() API function. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used as time specific (timer local) storage. + * + * @param xTimer The timer being queried. + * + * @return The ID assigned to the timer being queried. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** + * void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ); + * + * Sets the ID assigned to the timer. + * + * IDs are assigned to timers using the pvTimerID parameter of the call to + * xTimerCreated() that was used to create the timer. + * + * If the same callback function is assigned to multiple timers then the timer + * ID can be used as time specific (timer local) storage. + * + * @param xTimer The timer being updated. + * + * @param pvNewID The ID to assign to the timer. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + */ +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION; + +/** + * BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ); + * + * Queries a timer to see if it is active or dormant. + * + * A timer will be dormant if: + * 1) It has been created but not started, or + * 2) It is an expired one-shot timer that has not been restarted. + * + * Timers are created in the dormant state. The xTimerStart(), xTimerReset(), + * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and + * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the + * active state. + * + * @param xTimer The timer being queried. + * + * @return pdFALSE will be returned if the timer is dormant. A value other than + * pdFALSE will be returned if the timer is active. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. + * void vAFunction( TimerHandle_t xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is active, do something. + * } + * else + * { + * // xTimer is not active, do something else. + * } + * } + * @endverbatim + */ +BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** + * TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ); + * + * Simply returns the handle of the timer service/daemon task. It it not valid + * to call xTimerGetTimerDaemonTaskHandle() before the scheduler has been started. + */ +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) PRIVILEGED_FUNCTION; + +/** + * BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStart() starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerStart() has equivalent functionality + * to the xTimerReset() API function. + * + * Starting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerStart() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerStart() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerStart() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStart() + * to be available. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the start command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStart() was called. xTicksToWait is ignored if xTimerStart() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStart( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerStop() stops a timer that was previously started using either of the + * The xTimerStart(), xTimerReset(), xTimerStartFromISR(), xTimerResetFromISR(), + * xTimerChangePeriod() or xTimerChangePeriodFromISR() API functions. + * + * Stopping a timer ensures the timer is not in the active state. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerStop() + * to be available. + * + * @param xTimer The handle of the timer being stopped. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the stop command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerStop() was called. xTicksToWait is ignored if xTimerStop() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerCreate() API function example usage scenario. + * + */ +#define xTimerStop( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, + * TickType_t xNewPeriod, + * TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerChangePeriod() changes the period of a timer that was previously + * created using the xTimerCreate() API function. + * + * xTimerChangePeriod() can be called to change the period of an active or + * dormant state timer. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerChangePeriod() to be available. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_PERIOD_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the change period command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerChangePeriod() was called. xTicksToWait is ignored if + * xTimerChangePeriod() is called before the scheduler is started. + * + * @return pdFAIL will be returned if the change period command could not be + * sent to the timer command queue even after xTicksToWait ticks had passed. + * pdPASS will be returned if the command was successfully sent to the timer + * command queue. When the command is actually processed will depend on the + * priority of the timer service/daemon task relative to other tasks in the + * system. The timer service/daemon task priority is set by the + * configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This function assumes xTimer has already been created. If the timer + * // referenced by xTimer is already active when it is called, then the timer + * // is deleted. If the timer referenced by xTimer is not active when it is + * // called, then the period of the timer is set to 500ms and the timer is + * // started. + * void vAFunction( TimerHandle_t xTimer ) + * { + * if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )" + * { + * // xTimer is already active - delete it. + * xTimerDelete( xTimer ); + * } + * else + * { + * // xTimer is not active, change its period to 500ms. This will also + * // cause the timer to start. Block for a maximum of 100 ticks if the + * // change period command cannot immediately be sent to the timer + * // command queue. + * if( xTimerChangePeriod( xTimer, 500 / portTICK_PERIOD_MS, 100 ) == pdPASS ) + * { + * // The command was successfully sent. + * } + * else + * { + * // The command could not be sent, even after waiting for 100 ticks + * // to pass. Take appropriate action here. + * } + * } + * } + * @endverbatim + */ + #define xTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerDelete() deletes a timer that was previously created using the + * xTimerCreate() API function. + * + * The configUSE_TIMERS configuration constant must be set to 1 for + * xTimerDelete() to be available. + * + * @param xTimer The handle of the timer being deleted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the delete command to be + * successfully sent to the timer command queue, should the queue already be + * full when xTimerDelete() was called. xTicksToWait is ignored if xTimerDelete() + * is called before the scheduler is started. + * + * @return pdFAIL will be returned if the delete command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * + * See the xTimerChangePeriod() API function example usage scenario. + */ +#define xTimerDelete( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait ); + * + * Timer functionality is provided by a timer service/daemon task. Many of the + * public FreeRTOS timer API functions send commands to the timer service task + * through a queue called the timer command queue. The timer command queue is + * private to the kernel itself and is not directly accessible to application + * code. The length of the timer command queue is set by the + * configTIMER_QUEUE_LENGTH configuration constant. + * + * xTimerReset() re-starts a timer that was previously created using the + * xTimerCreate() API function. If the timer had already been started and was + * already in the active state, then xTimerReset() will cause the timer to + * re-evaluate its expiry time so that it is relative to when xTimerReset() was + * called. If the timer was in the dormant state then xTimerReset() has + * equivalent functionality to the xTimerStart() API function. + * + * Resetting a timer ensures the timer is in the active state. If the timer + * is not stopped, deleted, or reset in the mean time, the callback function + * associated with the timer will get called 'n' ticks after xTimerReset() was + * called, where 'n' is the timers defined period. + * + * It is valid to call xTimerReset() before the scheduler has been started, but + * when this is done the timer will not actually start until the scheduler is + * started, and the timers expiry time will be relative to when the scheduler is + * started, not relative to when xTimerReset() was called. + * + * The configUSE_TIMERS configuration constant must be set to 1 for xTimerReset() + * to be available. + * + * @param xTimer The handle of the timer being reset/started/restarted. + * + * @param xTicksToWait Specifies the time, in ticks, that the calling task should + * be held in the Blocked state to wait for the reset command to be successfully + * sent to the timer command queue, should the queue already be full when + * xTimerReset() was called. xTicksToWait is ignored if xTimerReset() is called + * before the scheduler is started. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue even after xTicksToWait ticks had passed. pdPASS will + * be returned if the command was successfully sent to the timer command queue. + * When the command is actually processed will depend on the priority of the + * timer service/daemon task relative to other tasks in the system, although the + * timers expiry time is relative to when xTimerStart() is actually called. The + * timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * @verbatim + * // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer. + * + * TimerHandle_t xBacklightTimer = NULL; + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press event handler. + * void vKeyPressEventHandler( char cKey ) + * { + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. Wait 10 ticks for the command to be successfully sent + * // if it cannot be sent immediately. + * vSetBacklightState( BACKLIGHT_ON ); + * if( xTimerReset( xBacklightTimer, 100 ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * } + * + * void main( void ) + * { + * int32_t x; + * + * // Create then start the one-shot timer that is responsible for turning + * // the back-light off if no keys are pressed within a 5 second period. + * xBacklightTimer = xTimerCreate( "BacklightTimer", // Just a text name, not used by the kernel. + * ( 5000 / portTICK_PERIOD_MS), // The timer period in ticks. + * pdFALSE, // The timer is a one-shot timer. + * 0, // The id is not used by the callback so can take any value. + * vBacklightTimerCallback // The callback function that switches the LCD back-light off. + * ); + * + * if( xBacklightTimer == NULL ) + * { + * // The timer was not created. + * } + * else + * { + * // Start the timer. No block time is specified, and even if one was + * // it would be ignored because the scheduler has not yet been + * // started. + * if( xTimerStart( xBacklightTimer, 0 ) != pdPASS ) + * { + * // The timer could not be set into the Active state. + * } + * } + * + * // ... + * // Create tasks here. + * // ... + * + * // Starting the scheduler will start the timer running as it has already + * // been set into the active state. + * vTaskStartScheduler(); + * + * // Should not reach here. + * for( ;; ); + * } + * @endverbatim + */ +#define xTimerReset( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) ) + +/** + * BaseType_t xTimerStartFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStart() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being started/restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStartFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStartFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStartFromISR() function. If + * xTimerStartFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the start command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerStartFromISR() is actually called. The timer + * service/daemon task priority is set by the configTIMER_TASK_PRIORITY + * configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then restart the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerStartFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The start command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerStop() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer being stopped. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerStopFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerStopFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerStopFromISR() function. If + * xTimerStopFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the stop command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the timer should be simply stopped. + * + * // The interrupt service routine that stops the timer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - simply stop the timer. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The stop command was not executed successfully. Take appropriate + * // action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP_FROM_ISR, 0, ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer, + * TickType_t xNewPeriod, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerChangePeriod() that can be called from an interrupt + * service routine. + * + * @param xTimer The handle of the timer that is having its period changed. + * + * @param xNewPeriod The new period for xTimer. Timer periods are specified in + * tick periods, so the constant portTICK_PERIOD_MS can be used to convert a time + * that has been specified in milliseconds. For example, if the timer must + * expire after 100 ticks, then xNewPeriod should be set to 100. Alternatively, + * if the timer must expire after 500ms, then xNewPeriod can be set to + * ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less than + * or equal to 1000. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerChangePeriodFromISR() writes a message to the + * timer command queue, so has the potential to transition the timer service/ + * daemon task out of the Blocked state. If calling xTimerChangePeriodFromISR() + * causes the timer service/daemon task to leave the Blocked state, and the + * timer service/daemon task has a priority equal to or greater than the + * currently executing task (the task that was interrupted), then + * *pxHigherPriorityTaskWoken will get set to pdTRUE internally within the + * xTimerChangePeriodFromISR() function. If xTimerChangePeriodFromISR() sets + * this value to pdTRUE then a context switch should be performed before the + * interrupt exits. + * + * @return pdFAIL will be returned if the command to change the timers period + * could not be sent to the timer command queue. pdPASS will be returned if the + * command was successfully sent to the timer command queue. When the command + * is actually processed will depend on the priority of the timer service/daemon + * task relative to other tasks in the system. The timer service/daemon task + * priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xTimer has already been created and started. When + * // an interrupt occurs, the period of xTimer should be changed to 500ms. + * + * // The interrupt service routine that changes the period of xTimer. + * void vAnExampleInterruptServiceRoutine( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // The interrupt has occurred - change the period of xTimer to 500ms. + * // xHigherPriorityTaskWoken was set to pdFALSE where it was defined + * // (within this function). As this is an interrupt service routine, only + * // FreeRTOS API functions that end in "FromISR" can be used. + * if( xTimerChangePeriodFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The command to change the timers period was not executed + * // successfully. Take appropriate action here. + * } + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD_FROM_ISR, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * BaseType_t xTimerResetFromISR( TimerHandle_t xTimer, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * A version of xTimerReset() that can be called from an interrupt service + * routine. + * + * @param xTimer The handle of the timer that is to be started, reset, or + * restarted. + * + * @param pxHigherPriorityTaskWoken The timer service/daemon task spends most + * of its time in the Blocked state, waiting for messages to arrive on the timer + * command queue. Calling xTimerResetFromISR() writes a message to the timer + * command queue, so has the potential to transition the timer service/daemon + * task out of the Blocked state. If calling xTimerResetFromISR() causes the + * timer service/daemon task to leave the Blocked state, and the timer service/ + * daemon task has a priority equal to or greater than the currently executing + * task (the task that was interrupted), then *pxHigherPriorityTaskWoken will + * get set to pdTRUE internally within the xTimerResetFromISR() function. If + * xTimerResetFromISR() sets this value to pdTRUE then a context switch should + * be performed before the interrupt exits. + * + * @return pdFAIL will be returned if the reset command could not be sent to + * the timer command queue. pdPASS will be returned if the command was + * successfully sent to the timer command queue. When the command is actually + * processed will depend on the priority of the timer service/daemon task + * relative to other tasks in the system, although the timers expiry time is + * relative to when xTimerResetFromISR() is actually called. The timer service/daemon + * task priority is set by the configTIMER_TASK_PRIORITY configuration constant. + * + * Example usage: + * @verbatim + * // This scenario assumes xBacklightTimer has already been created. When a + * // key is pressed, an LCD back-light is switched on. If 5 seconds pass + * // without a key being pressed, then the LCD back-light is switched off. In + * // this case, the timer is a one-shot timer, and unlike the example given for + * // the xTimerReset() function, the key press event handler is an interrupt + * // service routine. + * + * // The callback function assigned to the one-shot timer. In this case the + * // parameter is not used. + * void vBacklightTimerCallback( TimerHandle_t pxTimer ) + * { + * // The timer expired, therefore 5 seconds must have passed since a key + * // was pressed. Switch off the LCD back-light. + * vSetBacklightState( BACKLIGHT_OFF ); + * } + * + * // The key press interrupt service routine. + * void vKeyPressEventInterruptHandler( void ) + * { + * BaseType_t xHigherPriorityTaskWoken = pdFALSE; + * + * // Ensure the LCD back-light is on, then reset the timer that is + * // responsible for turning the back-light off after 5 seconds of + * // key inactivity. This is an interrupt service routine so can only + * // call FreeRTOS API functions that end in "FromISR". + * vSetBacklightState( BACKLIGHT_ON ); + * + * // xTimerStartFromISR() or xTimerResetFromISR() could be called here + * // as both cause the timer to re-calculate its expiry time. + * // xHigherPriorityTaskWoken was initialised to pdFALSE when it was + * // declared (in this function). + * if( xTimerResetFromISR( xBacklightTimer, &xHigherPriorityTaskWoken ) != pdPASS ) + * { + * // The reset command was not executed successfully. Take appropriate + * // action here. + * } + * + * // Perform the rest of the key processing here. + * + * // If xHigherPriorityTaskWoken equals pdTRUE, then a context switch + * // should be performed. The syntax required to perform a context switch + * // from inside an ISR varies from port to port, and from compiler to + * // compiler. Inspect the demos for the port you are using to find the + * // actual syntax required. + * if( xHigherPriorityTaskWoken != pdFALSE ) + * { + * // Call the interrupt safe yield function here (actual function + * // depends on the FreeRTOS port being used). + * } + * } + * @endverbatim + */ +#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + + +/** + * BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, + * void *pvParameter1, + * uint32_t ulParameter2, + * BaseType_t *pxHigherPriorityTaskWoken ); + * + * + * Used from application interrupt service routines to defer the execution of a + * function to the RTOS daemon task (the timer service task, hence this function + * is implemented in timers.c and is prefixed with 'Timer'). + * + * Ideally an interrupt service routine (ISR) is kept as short as possible, but + * sometimes an ISR either has a lot of processing to do, or needs to perform + * processing that is not deterministic. In these cases + * xTimerPendFunctionCallFromISR() can be used to defer processing of a function + * to the RTOS daemon task. + * + * A mechanism is provided that allows the interrupt to return directly to the + * task that will subsequently execute the pended callback function. This + * allows the callback function to execute contiguously in time with the + * interrupt - just as if the callback had executed in the interrupt itself. + * + * @param xFunctionToPend The function to execute from the timer service/ + * daemon task. The function must conform to the PendedFunction_t + * prototype. + * + * @param pvParameter1 The value of the callback function's first parameter. + * The parameter has a void * type to allow it to be used to pass any type. + * For example, unsigned longs can be cast to a void *, or the void * can be + * used to point to a structure. + * + * @param ulParameter2 The value of the callback function's second parameter. + * + * @param pxHigherPriorityTaskWoken As mentioned above, calling this function + * will result in a message being sent to the timer daemon task. If the + * priority of the timer daemon task (which is set using + * configTIMER_TASK_PRIORITY in FreeRTOSConfig.h) is higher than the priority of + * the currently running task (the task the interrupt interrupted) then + * *pxHigherPriorityTaskWoken will be set to pdTRUE within + * xTimerPendFunctionCallFromISR(), indicating that a context switch should be + * requested before the interrupt exits. For that reason + * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * @return pdPASS is returned if the message was successfully sent to the + * timer daemon task, otherwise pdFALSE is returned. + * + * Example usage: + * @verbatim + * + * // The callback function that will execute in the context of the daemon task. + * // Note callback functions must all use this same prototype. + * void vProcessInterface( void *pvParameter1, uint32_t ulParameter2 ) + * { + * BaseType_t xInterfaceToService; + * + * // The interface that requires servicing is passed in the second + * // parameter. The first parameter is not used in this case. + * xInterfaceToService = ( BaseType_t ) ulParameter2; + * + * // ...Perform the processing here... + * } + * + * // An ISR that receives data packets from multiple interfaces + * void vAnISR( void ) + * { + * BaseType_t xInterfaceToService, xHigherPriorityTaskWoken; + * + * // Query the hardware to determine which interface needs processing. + * xInterfaceToService = prvCheckInterfaces(); + * + * // The actual processing is to be deferred to a task. Request the + * // vProcessInterface() callback function is executed, passing in the + * // number of the interface that needs processing. The interface to + * // service is passed in the second parameter. The first parameter is + * // not used in this case. + * xHigherPriorityTaskWoken = pdFALSE; + * xTimerPendFunctionCallFromISR( vProcessInterface, NULL, ( uint32_t ) xInterfaceToService, &xHigherPriorityTaskWoken ); + * + * // If xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and will + * // be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to + * // the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + * + * } + * @endverbatim + */ +BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION; + + /** + * BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, + * void *pvParameter1, + * uint32_t ulParameter2, + * TickType_t xTicksToWait ); + * + * + * Used to defer the execution of a function to the RTOS daemon task (the timer + * service task, hence this function is implemented in timers.c and is prefixed + * with 'Timer'). + * + * @param xFunctionToPend The function to execute from the timer service/ + * daemon task. The function must conform to the PendedFunction_t + * prototype. + * + * @param pvParameter1 The value of the callback function's first parameter. + * The parameter has a void * type to allow it to be used to pass any type. + * For example, unsigned longs can be cast to a void *, or the void * can be + * used to point to a structure. + * + * @param ulParameter2 The value of the callback function's second parameter. + * + * @param xTicksToWait Calling this function will result in a message being + * sent to the timer daemon task on a queue. xTicksToWait is the amount of + * time the calling task should remain in the Blocked state (so not using any + * processing time) for space to become available on the timer queue if the + * queue is found to be full. + * + * @return pdPASS is returned if the message was successfully sent to the + * timer daemon task, otherwise pdFALSE is returned. + * + */ +BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +/** + * const char * const pcTimerGetName( TimerHandle_t xTimer ); + * + * Returns the name that was assigned to a timer when the timer was created. + * + * @param xTimer The handle of the timer being queried. + * + * @return The name assigned to the timer specified by the xTimer parameter. + */ +const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/** + * TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); + * + * Returns the period of a timer. + * + * @param xTimer The handle of the timer being queried. + * + * @return The period of the timer in ticks. + */ +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/** +* TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ); +* +* Returns the time in ticks at which the timer will expire. If this is less +* than the current tick count then the expiry time has overflowed from the +* current time. +* +* @param xTimer The handle of the timer being queried. +* +* @return If the timer is running then the time in ticks at which the timer +* will next expire is returned. If the timer is not running then the return +* value is undefined. +*/ +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; + +/* + * Functions beyond this part are not part of the public API and are intended + * for use by the kernel only. + */ +BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; +BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; + +#ifdef __cplusplus +} +#endif +#endif /* TIMERS_H */ + + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/list.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/list.c new file mode 100755 index 0000000..5e207c1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/list.c @@ -0,0 +1,240 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#include +#include "FreeRTOS.h" +#include "list.h" + +/*----------------------------------------------------------- + * PUBLIC LIST API documented in list.h + *----------------------------------------------------------*/ + +void vListInitialise( List_t * const pxList ) +{ + /* The list structure contains a list item which is used to mark the + end of the list. To initialise the list the list end is inserted + as the only list entry. */ + pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + /* The list end value is the highest possible value in the list to + ensure it remains at the end of the list. */ + pxList->xListEnd.xItemValue = portMAX_DELAY; + + /* The list end next and previous pointers point to itself so we know + when the list is empty. */ + pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + + pxList->uxNumberOfItems = ( UBaseType_t ) 0U; + + /* Write known values into the list if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); + listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); +} +/*-----------------------------------------------------------*/ + +void vListInitialiseItem( ListItem_t * const pxItem ) +{ + /* Make sure the list item is not recorded as being on a list. */ + pxItem->pvContainer = NULL; + + /* Write known values into the list item if + configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); + listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); +} +/*-----------------------------------------------------------*/ + +void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) +{ +ListItem_t * const pxIndex = pxList->pxIndex; + + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + + /* Insert a new list item into pxList, but rather than sort the list, + makes the new list item the last item to be removed by a call to + listGET_OWNER_OF_NEXT_ENTRY(). */ + pxNewListItem->pxNext = pxIndex; + pxNewListItem->pxPrevious = pxIndex->pxPrevious; + + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + + pxIndex->pxPrevious->pxNext = pxNewListItem; + pxIndex->pxPrevious = pxNewListItem; + + /* Remember which list the item is in. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) +{ +ListItem_t *pxIterator; +const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; + + /* Only effective when configASSERT() is also defined, these tests may catch + the list data structures being overwritten in memory. They will not catch + data errors caused by incorrect configuration or use of FreeRTOS. */ + listTEST_LIST_INTEGRITY( pxList ); + listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); + + /* Insert the new list item into the list, sorted in xItemValue order. + + If the list already contains a list item with the same item value then the + new list item should be placed after it. This ensures that TCB's which are + stored in ready lists (all of which have the same xItemValue value) get a + share of the CPU. However, if the xItemValue is the same as the back marker + the iteration loop below will not end. Therefore the value is checked + first, and the algorithm slightly modified if necessary. */ + if( xValueOfInsertion == portMAX_DELAY ) + { + pxIterator = pxList->xListEnd.pxPrevious; + } + else + { + /* *** NOTE *********************************************************** + If you find your application is crashing here then likely causes are + listed below. In addition see http://www.freertos.org/FAQHelp.html for + more tips, and ensure configASSERT() is defined! + http://www.freertos.org/a00110.html#configASSERT + + 1) Stack overflow - + see http://www.freertos.org/Stacks-and-stack-overflow-checking.html + 2) Incorrect interrupt priority assignment, especially on Cortex-M + parts where numerically high priority values denote low actual + interrupt priorities, which can seem counter intuitive. See + http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition + of configMAX_SYSCALL_INTERRUPT_PRIORITY on + http://www.freertos.org/a00110.html + 3) Calling an API function from within a critical section or when + the scheduler is suspended, or calling an API function that does + not end in "FromISR" from an interrupt. + 4) Using a queue or semaphore before it has been initialised or + before the scheduler has been started (are interrupts firing + before vTaskStartScheduler() has been called?). + **********************************************************************/ + + for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + { + /* There is nothing to do here, just iterating to the wanted + insertion position. */ + } + } + + pxNewListItem->pxNext = pxIterator->pxNext; + pxNewListItem->pxNext->pxPrevious = pxNewListItem; + pxNewListItem->pxPrevious = pxIterator; + pxIterator->pxNext = pxNewListItem; + + /* Remember which list the item is in. This allows fast removal of the + item later. */ + pxNewListItem->pvContainer = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) +{ +/* The list item knows which list it is in. Obtain the list from the list +item. */ +List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; + + pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; + pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; + + /* Only used during decision coverage testing. */ + mtCOVERAGE_TEST_DELAY(); + + /* Make sure the index is left pointing to a valid item. */ + if( pxList->pxIndex == pxItemToRemove ) + { + pxList->pxIndex = pxItemToRemove->pxPrevious; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxItemToRemove->pvContainer = NULL; + ( pxList->uxNumberOfItems )--; + + return pxList->uxNumberOfItems; +} +/*-----------------------------------------------------------*/ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c new file mode 100755 index 0000000..f6fe755 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -0,0 +1,710 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the ARM CM3 port. + *----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is +defined. The value should also ensure backward compatibility. +FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ +#ifndef configKERNEL_INTERRUPT_PRIORITY + #define configKERNEL_INTERRUPT_PRIORITY 255 +#endif + +#ifndef configSYSTICK_CLOCK_HZ + #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ + /* Ensure the SysTick is clocked at the same frequency as the core. */ + #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) +#else + /* The way the SysTick is clocked is not modified in case it is not the same + as the core. */ + #define portNVIC_SYSTICK_CLK_BIT ( 0 ) +#endif + +/* Constants required to manipulate the core. Registers first... */ +#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) +#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) +#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) ) +#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) +/* ...then bits in the registers. */ +#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) +#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) +#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL ) +#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL ) +#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) + +#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) +#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) + +/* Constants required to check the validity of an interrupt priority. */ +#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) +#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) +#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) ) +#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff ) +#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 ) +#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 ) +#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) +#define portPRIGROUP_SHIFT ( 8UL ) + +/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */ +#define portVECTACTIVE_MASK ( 0xFFUL ) + +/* Constants required to set up the initial stack. */ +#define portINITIAL_XPSR ( 0x01000000UL ) + +/* The systick is a 24-bit counter. */ +#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) + +/* A fiddle factor to estimate the number of SysTick counts that would have +occurred while the SysTick counter is stopped during tickless idle +calculations. */ +#define portMISSED_COUNTS_FACTOR ( 45UL ) + +/* For strict compliance with the Cortex-M spec the task start address should +have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ +#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) + +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case it messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + +/* Each task maintains its own interrupt status in the critical nesting +variable. */ +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; + +/* + * Setup the timer to generate the tick interrupts. The implementation in this + * file is weak to allow application writers to change the timer used to + * generate the tick interrupt. + */ +void vPortSetupTimerInterrupt( void ); + +/* + * Exception handlers. + */ +void xPortPendSVHandler( void ) __attribute__ (( naked )); +void xPortSysTickHandler( void ); +void vPortSVCHandler( void ) __attribute__ (( naked )); + +/* + * Start first task is a separate function so it can be tested in isolation. + */ +static void prvPortStartFirstTask( void ) __attribute__ (( naked )); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/*-----------------------------------------------------------*/ + +/* + * The number of SysTick increments that make up one tick period. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t ulTimerCountsForOneTick = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * The maximum number of tick periods that can be suppressed is limited by the + * 24 bit resolution of the SysTick timer. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t xMaximumPossibleSuppressedTicks = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Compensate for the CPU cycles that pass while the SysTick is stopped (low + * power functionality only. + */ +#if configUSE_TICKLESS_IDLE == 1 + static uint32_t ulStoppedTimerCompensation = 0; +#endif /* configUSE_TICKLESS_IDLE */ + +/* + * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure + * FreeRTOS API functions are not called from interrupts that have been assigned + * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. + */ +#if ( configASSERT_DEFINED == 1 ) + static uint8_t ucMaxSysCallPriority = 0; + static uint32_t ulMaxPRIGROUPValue = 0; + static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; +#endif /* configASSERT_DEFINED */ + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) +{ + /* Simulate the stack frame as it would be created by a context switch + interrupt. */ + pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ + *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ + pxTopOfStack--; + *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ + pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + +void vPortSVCHandler( void ) +{ + __asm volatile ( + " ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */ + " ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ + " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ + " ldmia r0!, {r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */ + " msr psp, r0 \n" /* Restore the task stack pointer. */ + " isb \n" + " mov r0, #0 \n" + " msr basepri, r0 \n" + " orr r14, #0xd \n" + " bx r14 \n" + " \n" + " .align 4 \n" + "pxCurrentTCBConst2: .word pxCurrentTCB \n" + ); +} +/*-----------------------------------------------------------*/ + +static void prvPortStartFirstTask( void ) +{ + __asm volatile( + " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ + " ldr r0, [r0] \n" + " ldr r0, [r0] \n" + " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ + " cpsie i \n" /* Globally enable interrupts. */ + " cpsie f \n" + " dsb \n" + " isb \n" + " svc 0 \n" /* System call to start first task. */ + " nop \n" + ); +} +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +BaseType_t xPortStartScheduler( void ) +{ + /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. + See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ + configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); + + #if( configASSERT_DEFINED == 1 ) + { + volatile uint32_t ulOriginalPriority; + volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER ); + volatile uint8_t ucMaxPriorityValue; + + /* Determine the maximum priority from which ISR safe FreeRTOS API + functions can be called. ISR safe functions are those that end in + "FromISR". FreeRTOS maintains separate thread and ISR API functions to + ensure interrupt entry is as fast and simple as possible. + + Save the interrupt priority value that is about to be clobbered. */ + ulOriginalPriority = *pucFirstUserPriorityRegister; + + /* Determine the number of priority bits available. First write to all + possible bits. */ + *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; + + /* Read the value back to see how many bits stuck. */ + ucMaxPriorityValue = *pucFirstUserPriorityRegister; + + /* Use the same mask on the maximum system call priority. */ + ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; + + /* Calculate the maximum acceptable priority group value for the number + of bits read back. */ + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; + while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) + { + ulMaxPRIGROUPValue--; + ucMaxPriorityValue <<= ( uint8_t ) 0x01; + } + + /* Shift the priority group value back to its position within the AIRCR + register. */ + ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; + ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; + + /* Restore the clobbered interrupt priority register to its original + value. */ + *pucFirstUserPriorityRegister = ulOriginalPriority; + } + #endif /* conifgASSERT_DEFINED */ + + /* Make PendSV and SysTick the lowest priority interrupts. */ + portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; + portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; + + /* Start the timer that generates the tick ISR. Interrupts are disabled + here already. */ + vPortSetupTimerInterrupt(); + + /* Initialise the critical nesting count ready for the first task. */ + uxCriticalNesting = 0; + + /* Start the first task. */ + prvPortStartFirstTask(); + + /* Should never get here as the tasks will now be executing! Call the task + exit error function to prevent compiler warnings about a static function + not being called in the case that the application writer overrides this + functionality by defining configTASK_RETURN_ADDRESS. */ + prvTaskExitError(); + + /* Should not get here! */ + return 0; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + Artificially force an assert. */ + configASSERT( uxCriticalNesting == 1000UL ); +} +/*-----------------------------------------------------------*/ + +void vPortEnterCritical( void ) +{ + portDISABLE_INTERRUPTS(); + uxCriticalNesting++; + + /* This is not the interrupt safe version of the enter critical function so + assert() if it is being called from an interrupt context. Only API + functions that end in "FromISR" can be used in an interrupt. Only assert if + the critical nesting count is 1 to protect against recursive calls if the + assert function also uses a critical section. */ + if( uxCriticalNesting == 1 ) + { + configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); + } +} +/*-----------------------------------------------------------*/ + +void vPortExitCritical( void ) +{ + configASSERT( uxCriticalNesting ); + uxCriticalNesting--; + if( uxCriticalNesting == 0 ) + { + portENABLE_INTERRUPTS(); + } +} +/*-----------------------------------------------------------*/ + +void xPortPendSVHandler( void ) +{ + /* This is a naked function. */ + + __asm volatile + ( + " mrs r0, psp \n" + " isb \n" + " \n" + " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */ + " ldr r2, [r3] \n" + " \n" + " stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */ + " str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */ + " \n" + " stmdb sp!, {r3, r14} \n" + " mov r0, %0 \n" + " msr basepri, r0 \n" + " bl vTaskSwitchContext \n" + " mov r0, #0 \n" + " msr basepri, r0 \n" + " ldmia sp!, {r3, r14} \n" + " \n" /* Restore the context, including the critical nesting count. */ + " ldr r1, [r3] \n" + " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ + " ldmia r0!, {r4-r11} \n" /* Pop the registers. */ + " msr psp, r0 \n" + " isb \n" + " bx r14 \n" + " \n" + " .align 4 \n" + "pxCurrentTCBConst: .word pxCurrentTCB \n" + ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY) + ); +} +/*-----------------------------------------------------------*/ + +void xPortSysTickHandler( void ) +{ + /* The SysTick runs at the lowest interrupt priority, so when this interrupt + executes all interrupts must be unmasked. There is therefore no need to + save and then restore the interrupt mask value as its value is already + known. */ + portDISABLE_INTERRUPTS(); + { + /* Increment the RTOS tick. */ + if( xTaskIncrementTick() != pdFALSE ) + { + /* A context switch is required. Context switching is performed in + the PendSV interrupt. Pend the PendSV interrupt. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } + } + portENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +#if configUSE_TICKLESS_IDLE == 1 + + __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) + { + uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; + TickType_t xModifiableIdleTime; + + /* Make sure the SysTick reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* Stop the SysTick momentarily. The time the SysTick is stopped for + is accounted for as best it can be, but using the tickless mode will + inevitably result in some tiny drift of the time maintained by the + kernel with respect to calendar time. */ + portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; + + /* Calculate the reload value required to wait xExpectedIdleTime + tick periods. -1 is used because this code will execute part way + through one of the tick periods. */ + ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); + if( ulReloadValue > ulStoppedTimerCompensation ) + { + ulReloadValue -= ulStoppedTimerCompensation; + } + + /* Enter a critical section but don't use the taskENTER_CRITICAL() + method as that will mask interrupts that should exit sleep mode. */ + __asm volatile( "cpsid i" ); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); + + /* If a context switch is pending or a task is waiting for the scheduler + to be unsuspended then abandon the low power entry. */ + if( eTaskConfirmSleepModeStatus() == eAbortSleep ) + { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + __asm volatile( "cpsie i" ); + } + else + { + /* Set the new reload value. */ + portNVIC_SYSTICK_LOAD_REG = ulReloadValue; + + /* Clear the SysTick count flag and set the count value back to + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + + /* Restart SysTick. */ + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + + /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can + set its parameter to 0 to indicate that its implementation contains + its own wait for interrupt or wait for event instruction, and so wfi + should not be executed again. However, the original expected idle + time variable must remain unmodified, so a copy is taken. */ + xModifiableIdleTime = xExpectedIdleTime; + configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); + if( xModifiableIdleTime > 0 ) + { + __asm volatile( "dsb" ); + __asm volatile( "wfi" ); + __asm volatile( "isb" ); + } + configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); + + /* Stop SysTick. Again, the time the SysTick is stopped for is + accounted for as best it can be, but using the tickless mode will + inevitably result in some tiny drift of the time maintained by the + kernel with respect to calendar time. */ + ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG; + portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT ); + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + __asm volatile( "cpsie i" ); + + if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) + { + uint32_t ulCalculatedLoadValue; + + /* The tick interrupt has already executed, and the SysTick + count reloaded with ulReloadValue. Reset the + portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick + period. */ + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be + processed as soon as this function exits, the tick value + maintained by the tick is stepped forward by one less than the + time spent waiting. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + else + { + /* Something other than the tick interrupt ended the sleep. + Work out how long the sleep lasted rounded to complete tick + periods (not the ulReload value which accounted for part + ticks). */ + ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; + + /* How many complete tick periods passed while the processor + was waiting? */ + ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; + } + + /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG + again, then set portNVIC_SYSTICK_LOAD_REG back to its standard + value. The critical section is used to ensure the tick interrupt + can only execute once in the case that the reload register is near + zero. */ + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + portENTER_CRITICAL(); + { + portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; + vTaskStepTick( ulCompleteTickPeriods ); + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + } + portEXIT_CRITICAL(); + } + } + +#endif /* #if configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +/* + * Setup the systick timer to generate the tick interrupts at the required + * frequency. + */ +__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) +{ + /* Calculate the constants required to configure the tick interrupt. */ + #if configUSE_TICKLESS_IDLE == 1 + { + ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); + xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; + ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); + } + #endif /* configUSE_TICKLESS_IDLE */ + + /* Configure SysTick to interrupt at the requested rate. */ + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); +} +/*-----------------------------------------------------------*/ + +#if( configASSERT_DEFINED == 1 ) + + void vPortValidateInterruptPriority( void ) + { + uint32_t ulCurrentInterrupt; + uint8_t ucCurrentPriority; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + /* Is the interrupt number a user defined interrupt? */ + if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) + { + /* Look up the interrupt's priority. */ + ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; + + /* The following assertion will fail if a service routine (ISR) for + an interrupt that has been assigned a priority above + configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API + function. ISR safe FreeRTOS API functions must *only* be called + from interrupts that have been assigned a priority at or below + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Numerically low interrupt priority numbers represent logically high + interrupt priorities, therefore the priority of the interrupt must + be set to a value equal to or numerically *higher* than + configMAX_SYSCALL_INTERRUPT_PRIORITY. + + Interrupts that use the FreeRTOS API must not be left at their + default priority of zero as that is the highest possible priority, + which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, + and therefore also guaranteed to be invalid. + + FreeRTOS maintains separate thread and ISR API functions to ensure + interrupt entry is as fast and simple as possible. + + The following links provide detailed information: + http://www.freertos.org/RTOS-Cortex-M3-M4.html + http://www.freertos.org/FAQHelp.html */ + configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); + } + + /* Priority grouping: The interrupt controller (NVIC) allows the bits + that define each interrupt's priority to be split between bits that + define the interrupt's pre-emption priority bits and bits that define + the interrupt's sub-priority. For simplicity all bits must be defined + to be pre-emption priority bits. The following assertion will fail if + this is not the case (if some bits represent a sub-priority). + + If the application only uses CMSIS libraries for interrupt + configuration then the correct setting can be achieved on all Cortex-M + devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the + scheduler. Note however that some vendor specific peripheral libraries + assume a non-zero priority group setting, in which cases using a value + of zero will result in unpredicable behaviour. */ + configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); + } + +#endif /* configASSERT_DEFINED */ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h new file mode 100755 index 0000000..d44fc92 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h @@ -0,0 +1,284 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + +#if( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL + + /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do + not need to be guarded with a critical section. */ + #define portTICK_TYPE_IS_ATOMIC 1 +#endif +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +/*-----------------------------------------------------------*/ + +/* Scheduler utilities. */ +#define portYIELD() \ +{ \ + /* Set a PendSV to request a context switch. */ \ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ + \ + /* Barriers are normally not required but do ensure the code is completely \ + within the specified behaviour for the architecture. */ \ + __asm volatile( "dsb" ); \ + __asm volatile( "isb" ); \ +} + +#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) +#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) +#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD() +#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) +/*-----------------------------------------------------------*/ + +/* Critical section management. */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) +#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() +#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() + +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. These are +not necessary for to use this port. They are defined so the common demo files +(which build with all the ports) will build. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) +/*-----------------------------------------------------------*/ + +/* Tickless idle/low power functionality. */ +#ifndef portSUPPRESS_TICKS_AND_SLEEP + extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ); + #define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime ) +#endif +/*-----------------------------------------------------------*/ + +/* Architecture specific optimisations. */ +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 + + /* Generic helper function. */ + __attribute__( ( always_inline ) ) static inline uint8_t ucPortCountLeadingZeros( uint32_t ulBitmap ) + { + uint8_t ucReturn; + + __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) ); + return ucReturn; + } + + /* Check the configuration. */ + #if( configMAX_PRIORITIES > 32 ) + #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. + #endif + + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + /*-----------------------------------------------------------*/ + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( uint32_t ) ucPortCountLeadingZeros( ( uxReadyPriorities ) ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +#ifdef configASSERT + void vPortValidateInterruptPriority( void ); + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority() +#endif + +/* portNOP() is not required by this port. */ +#define portNOP() + +#define portINLINE __inline + +#ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__(( always_inline)) +#endif + +portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) +{ +uint32_t ulCurrentInterrupt; +BaseType_t xReturn; + + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); + + if( ulCurrentInterrupt == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortRaiseBASEPRI( void ) +{ +uint32_t ulNewBASEPRI; + + __asm volatile + ( + " mov %0, %1 \n" \ + " msr basepri, %0 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); +} + +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void ) +{ +uint32_t ulOriginalBASEPRI, ulNewBASEPRI; + + __asm volatile + ( + " mrs %0, basepri \n" \ + " mov %1, %2 \n" \ + " msr basepri, %1 \n" \ + " isb \n" \ + " dsb \n" \ + :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) + ); + + /* This return will not be reached but is necessary to prevent compiler + warnings. */ + return ulOriginalBASEPRI; +} +/*-----------------------------------------------------------*/ + +portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue ) +{ + __asm volatile + ( + " msr basepri, %0 " :: "r" ( ulNewMaskValue ) + ); +} +/*-----------------------------------------------------------*/ + + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c new file mode 100755 index 0000000..e7c7ade --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -0,0 +1,478 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A sample implementation of pvPortMalloc() and vPortFree() that combines + * (coalescences) adjacent memory blocks as they are freed, and in so doing + * limits memory fragmentation. + * + * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) + #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 +#endif + +/* Block sizes must not get too small. */ +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) ) + +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) + +/* Allocate the memory for the heap. */ +#if( configAPPLICATION_ALLOCATED_HEAP == 1 ) + /* The application writer has already defined the array used for the RTOS + heap - probably so it can be placed in a special segment or address. */ + extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#else + static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#endif /* configAPPLICATION_ALLOCATED_HEAP */ + +/* Define the linked list structure. This is used to link free blocks in order +of their memory address. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + +/*-----------------------------------------------------------*/ + +/* + * Inserts a block of memory that is being freed into the correct position in + * the list of free memory blocks. The block being freed will be merged with + * the block in front it and/or the block behind it if the memory blocks are + * adjacent to each other. + */ +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ); + +/* + * Called automatically to setup the required heap structures the first time + * pvPortMalloc() is called. + */ +static void prvHeapInit( void ); + +/*-----------------------------------------------------------*/ + +/* The size of the structure placed at the beginning of each allocated memory +block must by correctly byte aligned. */ +static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); + +/* Create a couple of list links to mark the start and end of the list. */ +static BlockLink_t xStart, *pxEnd = NULL; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +static size_t xFreeBytesRemaining = 0U; +static size_t xMinimumEverFreeBytesRemaining = 0U; + +/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize +member of an BlockLink_t structure is set then the block belongs to the +application. When the bit is free the block is still part of the free heap +space. */ +static size_t xBlockAllocatedBit = 0; + +/*-----------------------------------------------------------*/ + +void *pvPortMalloc( size_t xWantedSize ) +{ +BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +void *pvReturn = NULL; + + vTaskSuspendAll(); + { + /* If this is the first call to malloc then the heap will require + initialisation to setup the list of free blocks. */ + if( pxEnd == NULL ) + { + prvHeapInit(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Check the requested block size is not so large that the top bit is + set. The top bit of the block size member of the BlockLink_t structure + is used to determine who owns the block - the application or the + kernel, so it must be free. */ + if( ( xWantedSize & xBlockAllocatedBit ) == 0 ) + { + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += xHeapStructSize; + + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If the end marker was reached then a block of adequate size + was not found. */ + if( pxBlock != pxEnd ) + { + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize ); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 ); + + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( pxNewBlockLink ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + + if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) + { + xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xBlockSize |= xBlockAllocatedBit; + pxBlock->pxNextFreeBlock = NULL; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceMALLOC( pvReturn, xWantedSize ); + } + ( void ) xTaskResumeAll(); + + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif + + configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 ); + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ +uint8_t *puc = ( uint8_t * ) pv; +BlockLink_t *pxLink; + + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= xHeapStructSize; + + /* This casting is to keep the compiler from issuing warnings. */ + pxLink = ( void * ) puc; + + /* Check the block is actually allocated. */ + configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); + + if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + { + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + allocated. */ + pxLink->xBlockSize &= ~xBlockAllocatedBit; + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + } + ( void ) xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +size_t xPortGetMinimumEverFreeHeapSize( void ) +{ + return xMinimumEverFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* This just exists to keep the linker quiet. */ +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) +{ +BlockLink_t *pxFirstFreeBlock; +uint8_t *pucAlignedHeap; +size_t uxAddress; +size_t xTotalHeapSize = configTOTAL_HEAP_SIZE; + + /* Ensure the heap starts on a correctly aligned boundary. */ + uxAddress = ( size_t ) ucHeap; + + if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + uxAddress += ( portBYTE_ALIGNMENT - 1 ); + uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); + xTotalHeapSize -= uxAddress - ( size_t ) ucHeap; + } + + pucAlignedHeap = ( uint8_t * ) uxAddress; + + /* xStart is used to hold a pointer to the first item in the list of free + blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + + /* pxEnd is used to mark the end of the list of free blocks and is inserted + at the end of the heap space. */ + uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize; + uxAddress -= xHeapStructSize; + uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); + pxEnd = ( void * ) uxAddress; + pxEnd->xBlockSize = 0; + pxEnd->pxNextFreeBlock = NULL; + + /* To start with there is a single free block that is sized to take up the + entire heap space, minus the space taken by pxEnd. */ + pxFirstFreeBlock = ( void * ) pucAlignedHeap; + pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock; + pxFirstFreeBlock->pxNextFreeBlock = pxEnd; + + /* Only one block exists - and it covers the entire usable heap space. */ + xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; + xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; + + /* Work out the position of the top bit in a size_t variable. */ + xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); +} +/*-----------------------------------------------------------*/ + +static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ) +{ +BlockLink_t *pxIterator; +uint8_t *puc; + + /* Iterate through the list until a block is found that has a higher address + than the block being inserted. */ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) + { + /* Nothing to do here, just iterate to the right position. */ + } + + /* Do the block being inserted, and the block it is being inserted after + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxIterator; + if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ) + { + pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; + pxBlockToInsert = pxIterator; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Do the block being inserted, and the block it is being inserted before + make a contiguous block of memory? */ + puc = ( uint8_t * ) pxBlockToInsert; + if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ) + { + if( pxIterator->pxNextFreeBlock != pxEnd ) + { + /* Form one big block from the two blocks. */ + pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxEnd; + } + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + } + + /* If the block being inserted plugged a gab, so was merged with the block + before and the block after, then it's pxNextFreeBlock pointer will have + already been set, and should not be set here as that would make it point + to itself. */ + if( pxIterator != pxBlockToInsert ) + { + pxIterator->pxNextFreeBlock = pxBlockToInsert; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/queue.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/queue.c new file mode 100755 index 0000000..ce623be --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/queue.c @@ -0,0 +1,2566 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +#if ( configUSE_CO_ROUTINES == 1 ) + #include "croutine.h" +#endif + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* Constants used with the cRxLock and cTxLock structure members. */ +#define queueUNLOCKED ( ( int8_t ) -1 ) +#define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) + +/* When the Queue_t structure is used to represent a base queue its pcHead and +pcTail members are used as pointers into the queue storage area. When the +Queue_t structure is used to represent a mutex pcHead and pcTail pointers are +not necessary, and the pcHead pointer is set to NULL to indicate that the +pcTail pointer actually points to the mutex holder (if any). Map alternative +names to the pcHead and pcTail structure members to ensure the readability of +the code is maintained despite this dual use of two structure members. An +alternative implementation would be to use a union, but use of a union is +against the coding standard (although an exception to the standard has been +permitted where the dual use also significantly changes the type of the +structure member). */ +#define pxMutexHolder pcTail +#define uxQueueType pcHead +#define queueQUEUE_IS_MUTEX NULL + +/* Semaphores do not actually store or copy data, so have an item size of +zero. */ +#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 ) +#define queueMUTEX_GIVE_BLOCK_TIME ( ( TickType_t ) 0U ) + +#if( configUSE_PREEMPTION == 0 ) + /* If the cooperative scheduler is being used then a yield should not be + performed just because a higher priority task has been woken. */ + #define queueYIELD_IF_USING_PREEMPTION() +#else + #define queueYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() +#endif + +/* + * Definition of the queue used by the scheduler. + * Items are queued by copy, not reference. See the following link for the + * rationale: http://www.freertos.org/Embedded-RTOS-Queues.html + */ +typedef struct QueueDefinition +{ + int8_t *pcHead; /*< Points to the beginning of the queue storage area. */ + int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ + int8_t *pcWriteTo; /*< Points to the free next place in the storage area. */ + + union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */ + { + int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */ + UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */ + } u; + + List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ + List_t xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */ + + volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */ + UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ + UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */ + + volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if ( configUSE_QUEUE_SETS == 1 ) + struct QueueDefinition *pxQueueSetContainer; + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxQueueNumber; + uint8_t ucQueueType; + #endif + +} xQUEUE; + +/* The old xQUEUE name is maintained above then typedefed to the new Queue_t +name below to enable the use of older kernel aware debuggers. */ +typedef xQUEUE Queue_t; + +/*-----------------------------------------------------------*/ + +/* + * The queue registry is just a means for kernel aware debuggers to locate + * queue structures. It has no other purpose so is an optional component. + */ +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + /* The type stored within the queue registry array. This allows a name + to be assigned to each queue making kernel aware debugging a little + more user friendly. */ + typedef struct QUEUE_REGISTRY_ITEM + { + const char *pcQueueName; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + QueueHandle_t xHandle; + } xQueueRegistryItem; + + /* The old xQueueRegistryItem name is maintained above then typedefed to the + new xQueueRegistryItem name below to enable the use of older kernel aware + debuggers. */ + typedef xQueueRegistryItem QueueRegistryItem_t; + + /* The queue registry is simply an array of QueueRegistryItem_t structures. + The pcQueueName member of a structure being NULL is indicative of the + array position being vacant. */ + PRIVILEGED_DATA QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ]; + +#endif /* configQUEUE_REGISTRY_SIZE */ + +/* + * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not + * prevent an ISR from adding or removing items to the queue, but does prevent + * an ISR from removing tasks from the queue event lists. If an ISR finds a + * queue is locked it will instead increment the appropriate queue lock count + * to indicate that a task may require unblocking. When the queue in unlocked + * these lock counts are inspected, and the appropriate action taken. + */ +static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any data in a queue. + * + * @return pdTRUE if the queue contains no items, otherwise pdFALSE. + */ +static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Uses a critical section to determine if there is any space in a queue. + * + * @return pdTRUE if there is no space, otherwise pdFALSE; + */ +static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ) PRIVILEGED_FUNCTION; + +/* + * Copies an item into the queue, either at the front of the queue or the + * back of the queue. + */ +static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) PRIVILEGED_FUNCTION; + +/* + * Copies an item out of a queue. + */ +static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; + +#if ( configUSE_QUEUE_SETS == 1 ) + /* + * Checks to see if a queue is a member of a queue set, and if so, notifies + * the queue set that the queue contains data. + */ + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION; +#endif + +/* + * Called after a Queue_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; + +/* + * Mutexes are a special type of queue. When a mutex is created, first the + * queue is created, then prvInitialiseMutex() is called to configure the queue + * as a mutex. + */ +#if( configUSE_MUTEXES == 1 ) + static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; +#endif + +/*-----------------------------------------------------------*/ + +/* + * Macro to mark a queue as locked. Locking a queue prevents an ISR from + * accessing the queue event lists. + */ +#define prvLockQueue( pxQueue ) \ + taskENTER_CRITICAL(); \ + { \ + if( ( pxQueue )->cRxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \ + } \ + if( ( pxQueue )->cTxLock == queueUNLOCKED ) \ + { \ + ( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \ + } \ + } \ + taskEXIT_CRITICAL() +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) +{ +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + + taskENTER_CRITICAL(); + { + pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize ); + pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U; + pxQueue->pcWriteTo = pxQueue->pcHead; + pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize ); + pxQueue->cRxLock = queueUNLOCKED; + pxQueue->cTxLock = queueUNLOCKED; + + if( xNewQueue == pdFALSE ) + { + /* If there are tasks blocked waiting to read from the queue, then + the tasks will remain blocked as after this function exits the queue + will still be empty. If there are tasks blocked waiting to write to + the queue, then one should be unblocked as after this function exits + it will be possible to write to it. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Ensure the event queues start in the correct state. */ + vListInitialise( &( pxQueue->xTasksWaitingToSend ) ); + vListInitialise( &( pxQueue->xTasksWaitingToReceive ) ); + } + } + taskEXIT_CRITICAL(); + + /* A value is returned for calling semantic consistency with previous + versions. */ + return pdPASS; +} +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + /* The StaticQueue_t structure and the queue storage area must be + supplied. */ + configASSERT( pxStaticQueue != NULL ); + + /* A queue storage area should be provided if the item size is not 0, and + should not be provided if the item size is 0. */ + configASSERT( !( ( pucQueueStorage != NULL ) && ( uxItemSize == 0 ) ) ); + configASSERT( !( ( pucQueueStorage == NULL ) && ( uxItemSize != 0 ) ) ); + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticQueue_t or StaticSemaphore_t equals the size of + the real queue and semaphore structures. */ + volatile size_t xSize = sizeof( StaticQueue_t ); + configASSERT( xSize == sizeof( Queue_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* The address of a statically allocated queue was passed in, use it. + The address of a statically allocated storage area was also passed in + but is already set. */ + pxNewQueue = ( Queue_t * ) pxStaticQueue; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewQueue != NULL ) + { + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Queues can be allocated wither statically or dynamically, so + note this queue was allocated statically in case the queue is + later deleted. */ + pxNewQueue->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + size_t xQueueSizeInBytes; + uint8_t *pucQueueStorage; + + configASSERT( uxQueueLength > ( UBaseType_t ) 0 ); + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* There is not going to be a queue storage area. */ + xQueueSizeInBytes = ( size_t ) 0; + } + else + { + /* Allocate enough space to hold the maximum number of items that + can be in the queue at any time. */ + xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); + + if( pxNewQueue != NULL ) + { + /* Jump past the queue structure to find the location of the queue + storage area. */ + pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Queues can be created either statically or dynamically, so + note this task was created dynamically in case it is later + deleted. */ + pxNewQueue->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); + } + + return pxNewQueue; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue ) +{ + /* Remove compiler warnings about unused parameters should + configUSE_TRACE_FACILITY not be set to 1. */ + ( void ) ucQueueType; + + if( uxItemSize == ( UBaseType_t ) 0 ) + { + /* No RAM was allocated for the queue storage area, but PC head cannot + be set to NULL because NULL is used as a key to say the queue is used as + a mutex. Therefore just set pcHead to point to the queue as a benign + value that is known to be within the memory map. */ + pxNewQueue->pcHead = ( int8_t * ) pxNewQueue; + } + else + { + /* Set the head to the start of the queue storage area. */ + pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage; + } + + /* Initialise the queue members as described where the queue type is + defined. */ + pxNewQueue->uxLength = uxQueueLength; + pxNewQueue->uxItemSize = uxItemSize; + ( void ) xQueueGenericReset( pxNewQueue, pdTRUE ); + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxNewQueue->ucQueueType = ucQueueType; + } + #endif /* configUSE_TRACE_FACILITY */ + + #if( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif /* configUSE_QUEUE_SETS */ + + traceQUEUE_CREATE( pxNewQueue ); +} +/*-----------------------------------------------------------*/ + +#if( configUSE_MUTEXES == 1 ) + + static void prvInitialiseMutex( Queue_t *pxNewQueue ) + { + if( pxNewQueue != NULL ) + { + /* The queue create function will set all the queue structure members + correctly for a generic queue, but this function is creating a + mutex. Overwrite those members that need to be set differently - + in particular the information required for priority inheritance. */ + pxNewQueue->pxMutexHolder = NULL; + pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; + + /* In case this is a recursive mutex. */ + pxNewQueue->u.uxRecursiveCallCount = 0; + + traceCREATE_MUTEX( pxNewQueue ); + + /* Start with the semaphore in the expected state. */ + ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK ); + } + else + { + traceCREATE_MUTEX_FAILED(); + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) + { + Queue_t *pxNewQueue; + const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; + + /* Prevent compiler warnings about unused parameters if + configUSE_TRACE_FACILITY does not equal 1. */ + ( void ) ucQueueType; + + pxNewQueue = ( Queue_t * ) xQueueGenericCreateStatic( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); + prvInitialiseMutex( pxNewQueue ); + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) + + void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) + { + void *pxReturn; + + /* This function is called by xSemaphoreGetMutexHolder(), and should not + be called directly. Note: This is a good way of determining if the + calling task is the mutex holder, but not a good way of determining the + identity of the mutex holder, as the holder may change between the + following critical section exiting and the function returning. */ + taskENTER_CRITICAL(); + { + if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX ) + { + pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder; + } + else + { + pxReturn = NULL; + } + } + taskEXIT_CRITICAL(); + + return pxReturn; + } /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */ + +#endif +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) + { + BaseType_t xReturn; + Queue_t * const pxMutex = ( Queue_t * ) xMutex; + + configASSERT( pxMutex ); + + /* If this is the task that holds the mutex then pxMutexHolder will not + change outside of this task. If this task does not hold the mutex then + pxMutexHolder can never coincidentally equal the tasks handle, and as + this is the only condition we are interested in it does not matter if + pxMutexHolder is accessed simultaneously by another task. Therefore no + mutual exclusion is required to test the pxMutexHolder variable. */ + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as TaskHandle_t is a typedef. */ + { + traceGIVE_MUTEX_RECURSIVE( pxMutex ); + + /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to + the task handle, therefore no underflow check is required. Also, + uxRecursiveCallCount is only modified by the mutex holder, and as + there can only be one, no mutual exclusion is required to modify the + uxRecursiveCallCount member. */ + ( pxMutex->u.uxRecursiveCallCount )--; + + /* Has the recursive call count unwound to 0? */ + if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) + { + /* Return the mutex. This will automatically unblock any other + task that might be waiting to access the mutex. */ + ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = pdPASS; + } + else + { + /* The mutex cannot be given because the calling task is not the + holder. */ + xReturn = pdFAIL; + + traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) + + BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxMutex = ( Queue_t * ) xMutex; + + configASSERT( pxMutex ); + + /* Comments regarding mutual exclusion as per those within + xQueueGiveMutexRecursive(). */ + + traceTAKE_MUTEX_RECURSIVE( pxMutex ); + + if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + { + ( pxMutex->u.uxRecursiveCallCount )++; + xReturn = pdPASS; + } + else + { + xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); + + /* pdPASS will only be returned if the mutex was successfully + obtained. The calling task may have entered the Blocked state + before reaching here. */ + if( xReturn != pdFAIL ) + { + ( pxMutex->u.uxRecursiveCallCount )++; + } + else + { + traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); + } + } + + return xReturn; + } + +#endif /* configUSE_RECURSIVE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreateStatic( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) + { + QueueHandle_t xHandle; + + configASSERT( uxMaxCount != 0 ); + configASSERT( uxInitialCount <= uxMaxCount ); + + xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); + + if( xHandle != NULL ) + { + ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; + + traceCREATE_COUNTING_SEMAPHORE(); + } + else + { + traceCREATE_COUNTING_SEMAPHORE_FAILED(); + } + + return xHandle; + } + +#endif /* ( ( configUSE_COUNTING_SEMAPHORES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ) +{ +BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired; +TimeOut_t xTimeOut; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + for( ;; ) + { + taskENTER_CRITICAL(); + { + /* Is there room on the queue now? The running task must be the + highest priority task wanting to access the queue. If the head item + in the queue is to be overwritten then it does not matter if the + queue is full. */ + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + traceQUEUE_SEND( pxQueue ); + xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to + do this from within the critical section - the + kernel takes care of that. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xYieldRequired != pdFALSE ) + { + /* This path is a special case that will only get + executed if the task was holding multiple mutexes + and the mutexes were given back in an order that is + different to that in which they were taken. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* If there was a task waiting for data to arrive on the + queue then unblock it now. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The unblocked task has a priority higher than + our own so yield immediately. Yes it is ok to do + this from within the critical section - the kernel + takes care of that. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else if( xYieldRequired != pdFALSE ) + { + /* This path is a special case that will only get + executed if the task was holding multiple mutexes and + the mutexes were given back in an order that is + different to that in which they were taken. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The queue was full and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + + /* Return to the original privilege level before exiting + the function. */ + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was full and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_SEND( pxQueue ); + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); + + /* Unlocking the queue means queue events can effect the + event list. It is possible that interrupts occurring now + remove this task from the event list again - but as the + scheduler is suspended the task will go onto the pending + ready last instead of the actual ready list. */ + prvUnlockQueue( pxQueue ); + + /* Resuming the scheduler will move tasks from the pending + ready list into the ready list - so it is feasible that this + task is already in a ready list before it yields - in which + case the yield will not cause a context switch unless there + is also a higher priority task in the pending ready list. */ + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + /* The timeout has expired. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + traceQUEUE_SEND_FAILED( pxQueue ); + return errQUEUE_FULL; + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue, const void * const pvItemToQueue, BaseType_t * const pxHigherPriorityTaskWoken, const BaseType_t xCopyPosition ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + /* Similar to xQueueGenericSend, except without blocking if there is no room + in the queue. Also don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) ) + { + const int8_t cTxLock = pxQueue->cTxLock; + + traceQUEUE_SEND_FROM_ISR( pxQueue ); + + /* Semaphores use xQueueGiveFromISR(), so pxQueue will not be a + semaphore or mutex. That means prvCopyDataToQueue() cannot result + in a task disinheriting a priority and prvCopyDataToQueue() can be + called here even though the disinherit function does not check if + the scheduler is suspended before accessing the ready lists. */ + ( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); + + /* The event list is not altered if the queue is locked. This will + be done when the queue is unlocked later. */ + if( cTxLock == queueUNLOCKED ) + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting + to the queue set caused a higher priority task to + unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so + record that a context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * const pxHigherPriorityTaskWoken ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* Similar to xQueueGenericSendFromISR() but used with semaphores where the + item size is 0. Don't directly wake a task that was blocked on a queue + read, instead return a flag to say whether a context switch is required or + not (i.e. has a task with a higher priority than us been woken by this + post). */ + + configASSERT( pxQueue ); + + /* xQueueGenericSendFromISR() should be used instead of xQueueGiveFromISR() + if the item size is not 0. */ + configASSERT( pxQueue->uxItemSize == 0 ); + + /* Normally a mutex would not be given from an interrupt, especially if + there is a mutex holder, as priority inheritance makes no sense for an + interrupts, only tasks. */ + configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* When the queue is used to implement a semaphore no data is ever + moved through the queue but it is still valid to see if the queue 'has + space'. */ + if( uxMessagesWaiting < pxQueue->uxLength ) + { + const int8_t cTxLock = pxQueue->cTxLock; + + traceQUEUE_SEND_FROM_ISR( pxQueue ); + + /* A task can only have an inherited priority if it is a mutex + holder - and if there is a mutex holder then the mutex cannot be + given from an ISR. As this is the ISR version of the function it + can be assumed there is no mutex holder and no need to determine if + priority disinheritance is needed. Simply increase the count of + messages (semaphores) available. */ + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + + /* The event list is not altered if the queue is locked. This will + be done when the queue is unlocked later. */ + if( cTxLock == queueUNLOCKED ) + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + { + /* The semaphore is a member of a queue set, and + posting to the queue set caused a higher priority + task to unblock. A context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so + record that a context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_QUEUE_SETS */ + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was posted while it was locked. */ + pxQueue->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ); + xReturn = errQUEUE_FULL; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking ) +{ +BaseType_t xEntryTimeSet = pdFALSE; +TimeOut_t xTimeOut; +int8_t *pcOriginalReadPosition; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + { + configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); + } + #endif + + /* This function relaxes the coding standard somewhat to allow return + statements within the function itself. This is done in the interest + of execution time efficiency. */ + + for( ;; ) + { + taskENTER_CRITICAL(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Is there data in the queue now? To be running the calling task + must be the highest priority task wanting to access the queue. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Remember the read position in case the queue is only being + peeked. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + + if( xJustPeeking == pdFALSE ) + { + traceQUEUE_RECEIVE( pxQueue ); + + /* Actually removing data, not just peeking. */ + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_MUTEXES */ + + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + traceQUEUE_PEEK( pxQueue ); + + /* The data is not being removed, so reset the read + pointer. */ + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + /* The data is being left in the queue, so see if there are + any other tasks waiting for the data. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than this task. */ + queueYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + taskEXIT_CRITICAL(); + return pdPASS; + } + else + { + if( xTicksToWait == ( TickType_t ) 0 ) + { + /* The queue was empty and no block time is specified (or + the block time has expired) so leave now. */ + taskEXIT_CRITICAL(); + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else if( xEntryTimeSet == pdFALSE ) + { + /* The queue was empty and a block time was specified so + configure the timeout structure. */ + vTaskSetTimeOutState( &xTimeOut ); + xEntryTimeSet = pdTRUE; + } + else + { + /* Entry time was already set. */ + mtCOVERAGE_TEST_MARKER(); + } + } + } + taskEXIT_CRITICAL(); + + /* Interrupts and other tasks can send to and receive from the queue + now the critical section has been exited. */ + + vTaskSuspendAll(); + prvLockQueue( pxQueue ); + + /* Update the timeout state to see if it has expired yet. */ + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) + { + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + taskENTER_CRITICAL(); + { + vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif + + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); + prvUnlockQueue( pxQueue ); + if( xTaskResumeAll() == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Try again. */ + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + } + } + else + { + prvUnlockQueue( pxQueue ); + ( void ) xTaskResumeAll(); + + if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) + { + traceQUEUE_RECEIVE_FAILED( pxQueue ); + return errQUEUE_EMPTY; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, void * const pvBuffer, BaseType_t * const pxHigherPriorityTaskWoken ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + /* Cannot block in an ISR, so check there is data available. */ + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + const int8_t cRxLock = pxQueue->cRxLock; + + traceQUEUE_RECEIVE_FROM_ISR( pxQueue ); + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; + + /* If the queue is locked the event list will not be modified. + Instead update the lock count so the task that unlocks the queue + will know that an ISR has removed data while the queue was + locked. */ + if( cRxLock == queueUNLOCKED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + /* The task waiting has a higher priority than us so + force a context switch. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Increment the lock count so the task that unlocks the queue + knows that data was removed while it was locked. */ + pxQueue->cRxLock = ( int8_t ) ( cRxLock + 1 ); + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) +{ +BaseType_t xReturn; +UBaseType_t uxSavedInterruptStatus; +int8_t *pcOriginalReadPosition; +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); + configASSERT( pxQueue->uxItemSize != 0 ); /* Can't peek a semaphore. */ + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* Cannot block in an ISR, so check there is data available. */ + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + traceQUEUE_PEEK_FROM_ISR( pxQueue ); + + /* Remember the read position so it can be reset as nothing is + actually being removed from the queue. */ + pcOriginalReadPosition = pxQueue->u.pcReadFrom; + prvCopyDataFromQueue( pxQueue, pvBuffer ); + pxQueue->u.pcReadFrom = pcOriginalReadPosition; + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; + + configASSERT( xQueue ); + + taskENTER_CRITICAL(); + { + uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; +Queue_t *pxQueue; + + pxQueue = ( Queue_t * ) xQueue; + configASSERT( pxQueue ); + + taskENTER_CRITICAL(); + { + uxReturn = pxQueue->uxLength - pxQueue->uxMessagesWaiting; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue ) +{ +UBaseType_t uxReturn; + + configASSERT( xQueue ); + + uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting; + + return uxReturn; +} /*lint !e818 Pointer cannot be declared const as xQueue is a typedef not pointer. */ +/*-----------------------------------------------------------*/ + +void vQueueDelete( QueueHandle_t xQueue ) +{ +Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + configASSERT( pxQueue ); + traceQUEUE_DELETE( pxQueue ); + + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueUnregisterQueue( pxQueue ); + } + #endif + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The queue can only have been allocated dynamically - free it + again. */ + vPortFree( pxQueue ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The queue could have been allocated statically or dynamically, so + check before attempting to free the memory. */ + if( pxQueue->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxQueue ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #else + { + /* The queue must have been statically allocated, so is not going to be + deleted. Avoid compiler warnings about the unused parameter. */ + ( void ) pxQueue; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) + { + return ( ( Queue_t * ) xQueue )->uxQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) + { + ( ( Queue_t * ) xQueue )->uxQueueNumber = uxQueueNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + uint8_t ucQueueGetQueueType( QueueHandle_t xQueue ) + { + return ( ( Queue_t * ) xQueue )->ucQueueType; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) +{ +BaseType_t xReturn = pdFALSE; +UBaseType_t uxMessagesWaiting; + + /* This function is called from a critical section. */ + + uxMessagesWaiting = pxQueue->uxMessagesWaiting; + + if( pxQueue->uxItemSize == ( UBaseType_t ) 0 ) + { + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* The mutex is no longer being held. */ + xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); + pxQueue->pxMutexHolder = NULL; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_MUTEXES */ + } + else if( xPosition == queueSEND_TO_BACK ) + { + ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports, plus previous logic ensures a null pointer can only be passed to memcpy() if the copy size is 0. */ + pxQueue->pcWriteTo += pxQueue->uxItemSize; + if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->pcWriteTo = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */ + { + pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xPosition == queueOVERWRITE ) + { + if( uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* An item is not being added but overwritten, so subtract + one from the recorded number of items in the queue so when + one is added again below the number of recorded items remains + correct. */ + --uxMessagesWaiting; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) +{ + if( pxQueue->uxItemSize != ( UBaseType_t ) 0 ) + { + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) /*lint !e946 MISRA exception justified as use of the relational operator is the cleanest solutions. */ + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports. Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */ + } +} +/*-----------------------------------------------------------*/ + +static void prvUnlockQueue( Queue_t * const pxQueue ) +{ + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ + + /* The lock counts contains the number of extra data items placed or + removed from the queue while the queue was locked. When a queue is + locked items can be added or removed, but the event lists cannot be + updated. */ + taskENTER_CRITICAL(); + { + int8_t cTxLock = pxQueue->cTxLock; + + /* See if data was added to the queue while it was locked. */ + while( cTxLock > queueLOCKED_UNMODIFIED ) + { + /* Data was posted while the queue was locked. Are any tasks + blocked waiting for data to become available? */ + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) != pdFALSE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* Tasks that are removed from the event list will get + added to the pending ready list as the scheduler is still + suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that a + context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + break; + } + } + } + #else /* configUSE_QUEUE_SETS */ + { + /* Tasks that are removed from the event list will get added to + the pending ready list as the scheduler is still suspended. */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority so record that + a context switch is required. */ + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + break; + } + } + #endif /* configUSE_QUEUE_SETS */ + + --cTxLock; + } + + pxQueue->cTxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); + + /* Do the same for the Rx lock. */ + taskENTER_CRITICAL(); + { + int8_t cRxLock = pxQueue->cRxLock; + + while( cRxLock > queueLOCKED_UNMODIFIED ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + vTaskMissedYield(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + --cRxLock; + } + else + { + break; + } + } + + pxQueue->cRxLock = queueUNLOCKED; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvIsQueueEmpty( const Queue_t *pxQueue ) +{ +BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue ) +{ +BaseType_t xReturn; + + configASSERT( xQueue ); + if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +static BaseType_t prvIsQueueFull( const Queue_t *pxQueue ) +{ +BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( pxQueue->uxMessagesWaiting == pxQueue->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) +{ +BaseType_t xReturn; + + configASSERT( xQueue ); + if( ( ( Queue_t * ) xQueue )->uxMessagesWaiting == ( ( Queue_t * ) xQueue )->uxLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* If the queue is already full we may have to block. A critical section + is required to prevent an interrupt removing something from the queue + between the check to see if the queue is full and blocking on the queue. */ + portDISABLE_INTERRUPTS(); + { + if( prvIsQueueFull( pxQueue ) != pdFALSE ) + { + /* The queue is full - do we want to block or just leave without + posting? */ + if( xTicksToWait > ( TickType_t ) 0 ) + { + /* As this is called from a coroutine we cannot block directly, but + return indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } + } + } + portENABLE_INTERRUPTS(); + + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + /* There is room in the queue, copy the data into the queue. */ + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + xReturn = pdPASS; + + /* Were any co-routines waiting for data to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The co-routine waiting has a higher priority so record + that a yield might be appropriate. */ + xReturn = errQUEUE_YIELD; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xReturn = errQUEUE_FULL; + } + } + portENABLE_INTERRUPTS(); + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* If the queue is already empty we may have to block. A critical section + is required to prevent an interrupt adding something to the queue + between the check to see if the queue is empty and blocking on the queue. */ + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) + { + /* There are no messages in the queue, do we want to block or just + leave with nothing? */ + if( xTicksToWait > ( TickType_t ) 0 ) + { + /* As this is a co-routine we cannot block directly, but return + indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + portENABLE_INTERRUPTS(); + + portDISABLE_INTERRUPTS(); + { + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Data is available from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + xReturn = pdPASS; + + /* Were any co-routines waiting for space to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if + the event were caused from within an interrupt. */ + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + xReturn = errQUEUE_YIELD; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xReturn = pdFAIL; + } + } + portENABLE_INTERRUPTS(); + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t xCoRoutinePreviouslyWoken ) + { + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* Cannot block within an ISR so if there is no space on the queue then + exit without doing anything. */ + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + { + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + + /* We only want to wake one co-routine per ISR, so check that a + co-routine has not already been woken. */ + if( xCoRoutinePreviouslyWoken == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + return pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xCoRoutinePreviouslyWoken; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_CO_ROUTINES == 1 ) + + BaseType_t xQueueCRReceiveFromISR( QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxCoRoutineWoken ) + { + BaseType_t xReturn; + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* We cannot block from an ISR, so check there is data available. If + not then just leave without doing anything. */ + if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ) + { + /* Copy the data from the queue. */ + pxQueue->u.pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->u.pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->u.pcReadFrom = pxQueue->pcHead; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --( pxQueue->uxMessagesWaiting ); + ( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + if( ( *pxCoRoutineWoken ) == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + { + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + *pxCoRoutineWoken = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_CO_ROUTINES */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t ux; + + /* See if there is an empty space in the registry. A NULL name denotes + a free slot. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].pcQueueName == NULL ) + { + /* Store the information on this queue. */ + xQueueRegistry[ ux ].pcQueueName = pcQueueName; + xQueueRegistry[ ux ].xHandle = xQueue; + + traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ); + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + const char *pcQueueGetName( QueueHandle_t xQueue ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t ux; + const char *pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + /* Note there is nothing here to protect against another task adding or + removing entries from the registry while it is being searched. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + pcReturn = xQueueRegistry[ ux ].pcQueueName; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return pcReturn; + } + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configQUEUE_REGISTRY_SIZE > 0 ) + + void vQueueUnregisterQueue( QueueHandle_t xQueue ) + { + UBaseType_t ux; + + /* See if the handle of the queue being unregistered in actually in the + registry. */ + for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) + { + if( xQueueRegistry[ ux ].xHandle == xQueue ) + { + /* Set the name to NULL to show that this slot if free again. */ + xQueueRegistry[ ux ].pcQueueName = NULL; + + /* Set the handle to NULL to ensure the same queue handle cannot + appear in the registry twice if it is added, removed, then + added again. */ + xQueueRegistry[ ux ].xHandle = ( QueueHandle_t ) 0; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + } /*lint !e818 xQueue could not be pointer to const because it is a typedef. */ + +#endif /* configQUEUE_REGISTRY_SIZE */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TIMERS == 1 ) + + void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) + { + Queue_t * const pxQueue = ( Queue_t * ) xQueue; + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements. + It can result in vListInsert() being called on a list that can only + possibly ever have one item in it, so the list will be fast, but even + so it should be called with the scheduler locked and not from a critical + section. */ + + /* Only do anything if there are no messages in the queue. This function + will not actually cause the task to block, just place it on a blocked + list. It will not block until the scheduler is unlocked - at which + time a yield will be performed. If an item is added to the queue while + the queue is locked, and the calling task blocks on the queue, then the + calling task will be immediately unblocked when the queue is unlocked. */ + prvLockQueue( pxQueue ); + if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U ) + { + /* There is nothing in the queue, block for the specified period. */ + vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + prvUnlockQueue( pxQueue ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +#if( ( configUSE_QUEUE_SETS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + + QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength ) + { + QueueSetHandle_t pxQueue; + + pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET ); + + return pxQueue; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) + { + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL ) + { + /* Cannot add a queue/semaphore to more than one queue set. */ + xReturn = pdFAIL; + } + else if( ( ( Queue_t * ) xQueueOrSemaphore )->uxMessagesWaiting != ( UBaseType_t ) 0 ) + { + /* Cannot add a queue/semaphore to a queue set if there are already + items in the queue/semaphore. */ + xReturn = pdFAIL; + } + else + { + ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet; + xReturn = pdPASS; + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) + { + BaseType_t xReturn; + Queue_t * const pxQueueOrSemaphore = ( Queue_t * ) xQueueOrSemaphore; + + if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet ) + { + /* The queue was not a member of the set. */ + xReturn = pdFAIL; + } + else if( pxQueueOrSemaphore->uxMessagesWaiting != ( UBaseType_t ) 0 ) + { + /* It is dangerous to remove a queue from a set when the queue is + not empty because the queue set will still hold pending events for + the queue. */ + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + /* The queue is no longer contained in the set. */ + pxQueueOrSemaphore->pxQueueSetContainer = NULL; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } /*lint !e818 xQueueSet could not be declared as pointing to const as it is a typedef. */ + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, TickType_t const xTicksToWait ) + { + QueueSetMemberHandle_t xReturn = NULL; + + ( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) + { + QueueSetMemberHandle_t xReturn = NULL; + + ( void ) xQueueReceiveFromISR( ( QueueHandle_t ) xQueueSet, &xReturn, NULL ); /*lint !e961 Casting from one typedef to another is not redundant. */ + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) + { + Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer; + BaseType_t xReturn = pdFALSE; + + /* This function must be called form a critical section. */ + + configASSERT( pxQueueSetContainer ); + configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); + + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + { + const int8_t cTxLock = pxQueueSetContainer->cTxLock; + + traceQUEUE_SEND( pxQueueSetContainer ); + + /* The data copied is the handle of the queue that contains data. */ + xReturn = prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + + if( cTxLock == queueUNLOCKED ) + { + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + pxQueueSetContainer->cTxLock = ( int8_t ) ( cTxLock + 1 ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/tasks.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/tasks.c new file mode 100755 index 0000000..6c261a6 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/tasks.c @@ -0,0 +1,4807 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "StackMacros.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting +functions but without including stdio.h here. */ +#if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) + /* At the bottom of this file are two optional functions that can be used + to generate human readable text from the raw data generated by the + uxTaskGetSystemState() function. Note the formatting functions are provided + for convenience only, and are NOT considered part of the kernel. */ + #include +#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */ + +#if( configUSE_PREEMPTION == 0 ) + /* If the cooperative scheduler is being used then a yield should not be + performed just because a higher priority task has been woken. */ + #define taskYIELD_IF_USING_PREEMPTION() +#else + #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() +#endif + +/* Values that can be assigned to the ucNotifyState member of the TCB. */ +#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) +#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) +#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) + +/* + * The value used to fill the stack of a task when the task is created. This + * is used purely for checking the high water mark for tasks. + */ +#define tskSTACK_FILL_BYTE ( 0xa5U ) + +/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using +dynamically allocated RAM, in which case when any task is deleted it is known +that both the task's stack and TCB need to be freed. Sometimes the +FreeRTOSConfig.h settings only allow a task to be created using statically +allocated RAM, in which case when any task is deleted it is known that neither +the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h +settings allow a task to be created using either statically or dynamically +allocated RAM, in which case a member of the TCB is used to record whether the +stack and/or TCB were allocated statically or dynamically, so when a task is +deleted the RAM that was allocated dynamically is freed again and no attempt is +made to free the RAM that was allocated statically. +tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a +task to be created using either statically or dynamically allocated RAM. Note +that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with +a statically allocated stack and a dynamically allocated TCB. */ +#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) +#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) +#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) +#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) + +/* + * Macros used by vListTask to indicate which state a task is in. + */ +#define tskBLOCKED_CHAR ( 'B' ) +#define tskREADY_CHAR ( 'R' ) +#define tskDELETED_CHAR ( 'D' ) +#define tskSUSPENDED_CHAR ( 'S' ) + +/* + * Some kernel aware debuggers require the data the debugger needs access to be + * global, rather than file scope. + */ +#ifdef portREMOVE_STATIC_QUALIFIER + #define static +#endif + +#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is + performed in a generic way that is not optimised to any particular + microcontroller architecture. */ + + /* uxTopReadyPriority holds the priority of the highest priority ready + state task. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) \ + { \ + if( ( uxPriority ) > uxTopReadyPriority ) \ + { \ + uxTopReadyPriority = ( uxPriority ); \ + } \ + } /* taskRECORD_READY_PRIORITY */ + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority = uxTopReadyPriority; \ + \ + /* Find the highest priority queue that contains ready tasks. */ \ + while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \ + { \ + configASSERT( uxTopPriority ); \ + --uxTopPriority; \ + } \ + \ + /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ + the same priority get an equal share of the processor time. */ \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + uxTopReadyPriority = uxTopPriority; \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK */ + + /*-----------------------------------------------------------*/ + + /* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as + they are only required when a port optimised method of task selection is + being used. */ + #define taskRESET_READY_PRIORITY( uxPriority ) + #define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + +#else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + + /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is + performed in a way that is tailored to the particular microcontroller + architecture being used. */ + + /* A port optimised version is provided. Call the port defined macros. */ + #define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority ) + + /*-----------------------------------------------------------*/ + + #define taskSELECT_HIGHEST_PRIORITY_TASK() \ + { \ + UBaseType_t uxTopPriority; \ + \ + /* Find the highest priority list that contains ready tasks. */ \ + portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \ + configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \ + listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ + } /* taskSELECT_HIGHEST_PRIORITY_TASK() */ + + /*-----------------------------------------------------------*/ + + /* A port optimised version is provided, call it only if the TCB being reset + is being referenced from a ready list. If it is referenced from a delayed + or suspended list then it won't be in a ready list. */ + #define taskRESET_READY_PRIORITY( uxPriority ) \ + { \ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \ + { \ + portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) ); \ + } \ + } + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/*-----------------------------------------------------------*/ + +/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick +count overflows. */ +#define taskSWITCH_DELAYED_LISTS() \ +{ \ + List_t *pxTemp; \ + \ + /* The delayed tasks list should be empty when the lists are switched. */ \ + configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) ); \ + \ + pxTemp = pxDelayedTaskList; \ + pxDelayedTaskList = pxOverflowDelayedTaskList; \ + pxOverflowDelayedTaskList = pxTemp; \ + xNumOfOverflows++; \ + prvResetNextTaskUnblockTime(); \ +} + +/*-----------------------------------------------------------*/ + +/* + * Place the task represented by pxTCB into the appropriate ready list for + * the task. It is inserted at the end of the list. + */ +#define prvAddTaskToReadyList( pxTCB ) \ + traceMOVED_TASK_TO_READY_STATE( pxTCB ); \ + taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ + vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \ + tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) +/*-----------------------------------------------------------*/ + +/* + * Several functions take an TaskHandle_t parameter that can optionally be NULL, + * where NULL is used to indicate that the handle of the currently executing + * task should be used in place of the parameter. This macro simply checks to + * see if the parameter is NULL and returns a pointer to the appropriate TCB. + */ +#define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? ( TCB_t * ) pxCurrentTCB : ( TCB_t * ) ( pxHandle ) ) + +/* The item value of the event list item is normally used to hold the priority +of the task to which it belongs (coded to allow it to be held in reverse +priority order). However, it is occasionally borrowed for other purposes. It +is important its value is not updated due to a task priority change while it is +being used for another purpose. The following bit definition is used to inform +the scheduler that the value should not be changed - in which case it is the +responsibility of whichever module is using the value to ensure it gets set back +to its original value when it is released. */ +#if( configUSE_16_BIT_TICKS == 1 ) + #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U +#else + #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL +#endif + +/* + * Task control block. A task control block (TCB) is allocated for each task, + * and stores task state information, including a pointer to the task's context + * (the task's run time environment, including register values) + */ +typedef struct tskTaskControlBlock +{ + volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ + #endif + + ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ + ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ + UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ + StackType_t *pxStack; /*< Points to the start of the stack. */ + char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + + #if ( portSTACK_GROWTH > 0 ) + StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ + #endif + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + #endif + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; + #endif + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + TaskHookFunction_t pxTaskTag; + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + + #if( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + /* Allocate a Newlib reent structure that is specific to this task. + Note Newlib support has been included by popular demand, but is not + used by the FreeRTOS maintainers themselves. FreeRTOS is not + responsible for resulting newlib operation. User must be familiar with + newlib and must provide system-wide implementations of the necessary + stubs. Be warned that (at the time of writing) the current newlib design + implements a system-wide malloc() that must be provided with locks. */ + struct _reent xNewLib_reent; + #endif + + #if( configUSE_TASK_NOTIFICATIONS == 1 ) + volatile uint32_t ulNotifiedValue; + volatile uint8_t ucNotifyState; + #endif + + /* See the comments above the definition of + tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDelayAborted; + #endif + +} tskTCB; + +/* The old tskTCB name is maintained above then typedefed to the new TCB_t name +below to enable the use of older kernel aware debuggers. */ +typedef tskTCB TCB_t; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; + +/* Lists for ready and blocked tasks. --------------------*/ +PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */ +PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */ +PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */ +PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */ + +#if( INCLUDE_vTaskDelete == 1 ) + + PRIVILEGED_DATA static List_t xTasksWaitingTermination; /*< Tasks that have been deleted - but their memory not yet freed. */ + PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U; + +#endif + +#if ( INCLUDE_vTaskSuspend == 1 ) + + PRIVILEGED_DATA static List_t xSuspendedTaskList; /*< Tasks that are currently suspended. */ + +#endif + +/* Other file private variables. --------------------------------*/ +PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; +PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY; +PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE; +PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; +PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; +PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; +PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ + +/* Context switches are held pending while the scheduler is suspended. Also, +interrupts must not manipulate the xStateListItem of a TCB, or any of the +lists the xStateListItem can be referenced from, if the scheduler is suspended. +If an interrupt needs to unblock a task while the scheduler is suspended then it +moves the task's event list item into the xPendingReadyList, ready for the +kernel to move the task from the pending ready list into the real ready list +when the scheduler is unsuspended. The pending ready list itself can only be +accessed from a critical section. */ +PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE; + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ + +#endif + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + +/* Callback function prototypes. --------------------------*/ +#if( configCHECK_FOR_STACK_OVERFLOW > 0 ) + extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); +#endif + +#if( configUSE_TICK_HOOK > 0 ) + extern void vApplicationTickHook( void ); +#endif + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); +#endif + +/* File private functions. --------------------------------*/ + +/** + * Utility task that simply returns pdTRUE if the task referenced by xTask is + * currently in the Suspended state, or pdFALSE if the task referenced by xTask + * is in any other state. + */ +#if ( INCLUDE_vTaskSuspend == 1 ) + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +#endif /* INCLUDE_vTaskSuspend */ + +/* + * Utility to ready all the lists used by the scheduler. This is called + * automatically upon the creation of the first task. + */ +static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; + +/* + * The idle task, which as all tasks is implemented as a never ending loop. + * The idle task is automatically created and added to the ready lists upon + * creation of the first user task. + * + * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); + +/* + * Utility to free all memory allocated by the scheduler to hold a TCB, + * including the stack pointed to by the TCB. + * + * This does not free memory allocated by the task itself (i.e. memory + * allocated by calls to pvPortMalloc from within the tasks application code). + */ +#if ( INCLUDE_vTaskDelete == 1 ) + + static void prvDeleteTCB( TCB_t *pxTCB ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Used only by the idle task. This checks to see if anything has been placed + * in the list of tasks waiting to be deleted. If so the task is cleaned up + * and its TCB deleted. + */ +static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; + +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION; + +/* + * Fills an TaskStatus_t structure with information on each task that is + * referenced from the pxList list (which may be a ready list, a delayed list, + * a suspended list, etc.). + * + * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM + * NORMAL APPLICATION CODE. + */ +#if ( configUSE_TRACE_FACILITY == 1 ) + + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Searches pxList for a task with name pcNameToQuery - returning a handle to + * the task if it is found, or NULL if the task is not found. + */ +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) PRIVILEGED_FUNCTION; + +#endif + +/* + * When a task is created, the stack of the task is filled with a known value. + * This function determines the 'high water mark' of the task stack by + * determining how much of the stack remains at the original preset value. + */ +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Return the amount of time, in ticks, that will pass before the kernel will + * next move a task from the Blocked state to the Running state. + * + * This conditional compilation should use inequality to 0, not equality to 1. + * This is to ensure portSUPPRESS_TICKS_AND_SLEEP() can be called when user + * defined low power mode implementations require configUSE_TICKLESS_IDLE to be + * set to a value other than 1. + */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + static TickType_t prvGetExpectedIdleTime( void ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Set xNextTaskUnblockTime to the time at which the next Blocked state task + * will exit the Blocked state. + */ +static void prvResetNextTaskUnblockTime( void ); + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + /* + * Helper function used to pad task names with spaces when printing out + * human readable tables of task information. + */ + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) PRIVILEGED_FUNCTION; + +#endif + +/* + * Called after a Task_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + +/* + * Called after a new task has been created and initialised to place the task + * under the control of the scheduler. + */ +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + TCB_t *pxNewTCB; + TaskHandle_t xReturn; + + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); + + if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ) + { + /* The memory used for the task's TCB and stack are passed into this + function - use them. */ + pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer; + + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created statically in case the task is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + } + else + { + xReturn = NULL; + } + + return xReturn; + } + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( portUSING_MPU_WRAPPERS == 1 ) + + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) + { + TCB_t *pxNewTCB; + BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + + configASSERT( pxTaskDefinition->puxStackBuffer ); + + if( pxTaskDefinition->puxStackBuffer != NULL ) + { + /* Allocate space for the TCB. Where the memory comes from depends + on the implementation of the port malloc function and whether or + not static allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer; + + /* Tasks can be created statically or dynamically, so note + this task had a statically allocated stack in case it is + later deleted. The TCB was allocated dynamically. */ + pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY; + + prvInitialiseNewTask( pxTaskDefinition->pvTaskCode, + pxTaskDefinition->pcName, + ( uint32_t ) pxTaskDefinition->usStackDepth, + pxTaskDefinition->pvParameters, + pxTaskDefinition->uxPriority, + pxCreatedTask, pxNewTCB, + pxTaskDefinition->xRegions ); + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + } + + return xReturn; + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + TCB_t *pxNewTCB; + BaseType_t xReturn; + + /* If the stack grows down then allocate the stack then the TCB so the stack + does not grow into the TCB. Likewise if the stack grows up then allocate + the TCB then the stack. */ + #if( portSTACK_GROWTH > 0 ) + { + /* Allocate space for the TCB. Where the memory comes from depends on + the implementation of the port malloc function and whether or not static + allocation is being used. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + + if( pxNewTCB != NULL ) + { + /* Allocate space for the stack used by the task being created. + The base of the stack memory stored in the TCB so the task can + be deleted later if required. */ + pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + if( pxNewTCB->pxStack == NULL ) + { + /* Could not allocate the stack. Delete the allocated TCB. */ + vPortFree( pxNewTCB ); + pxNewTCB = NULL; + } + } + } + #else /* portSTACK_GROWTH */ + { + StackType_t *pxStack; + + /* Allocate space for the stack used by the task being created. */ + pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + if( pxStack != NULL ) + { + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ + + if( pxNewTCB != NULL ) + { + /* Store the stack location in the TCB. */ + pxNewTCB->pxStack = pxStack; + } + else + { + /* The stack cannot be used as the TCB was not created. Free + it again. */ + vPortFree( pxStack ); + } + } + else + { + pxNewTCB = NULL; + } + } + #endif /* portSTACK_GROWTH */ + + if( pxNewTCB != NULL ) + { + #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) + { + /* Tasks can be created statically or dynamically, so note this + task was created dynamically in case it is later deleted. */ + pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + return xReturn; + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + TCB_t *pxNewTCB, + const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +StackType_t *pxTopOfStack; +UBaseType_t x; + + #if( portUSING_MPU_WRAPPERS == 1 ) + /* Should the task be created in privileged mode? */ + BaseType_t xRunPrivileged; + if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) + { + xRunPrivileged = pdTRUE; + } + else + { + xRunPrivileged = pdFALSE; + } + uxPriority &= ~portPRIVILEGE_BIT; + #endif /* portUSING_MPU_WRAPPERS == 1 */ + + /* Avoid dependency on memset() if it is not required. */ + #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + { + /* Fill the stack with a known value to assist debugging. */ + ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) ); + } + #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + + /* Calculate the top of stack address. This depends on whether the stack + grows from high memory to low (as per the 80x86) or vice versa. + portSTACK_GROWTH is used to make the result positive or negative as required + by the port. */ + #if( portSTACK_GROWTH < 0 ) + { + pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ + + /* Check the alignment of the calculated top of stack is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + } + #else /* portSTACK_GROWTH */ + { + pxTopOfStack = pxNewTCB->pxStack; + + /* Check the alignment of the stack buffer is correct. */ + configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); + + /* The other extreme of the stack space is required if stack checking is + performed. */ + pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 ); + } + #endif /* portSTACK_GROWTH */ + + /* Store the task name in the TCB. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + pxNewTCB->pcTaskName[ x ] = pcName[ x ]; + + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + configMAX_TASK_NAME_LEN characters just in case the memory after the + string is not accessible (extremely unlikely). */ + if( pcName[ x ] == 0x00 ) + { + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Ensure the name string is terminated in the case that the string length + was greater or equal to configMAX_TASK_NAME_LEN. */ + pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0'; + + /* This is used as an array index so must ensure it's not too large. First + remove the privilege bit if one is present. */ + if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxNewTCB->uxPriority = uxPriority; + #if ( configUSE_MUTEXES == 1 ) + { + pxNewTCB->uxBasePriority = uxPriority; + pxNewTCB->uxMutexesHeld = 0; + } + #endif /* configUSE_MUTEXES */ + + vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); + vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); + + /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get + back to the containing TCB from a generic item in a list. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB ); + + /* Event lists are always in priority order. */ + listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB ); + + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + { + pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U; + } + #endif /* portCRITICAL_NESTING_IN_TCB */ + + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + { + pxNewTCB->pxTaskTag = NULL; + } + #endif /* configUSE_APPLICATION_TASK_TAG */ + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxNewTCB->ulRunTimeCounter = 0UL; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + #if ( portUSING_MPU_WRAPPERS == 1 ) + { + vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth ); + } + #else + { + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) xRegions; + } + #endif + + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + { + for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ ) + { + pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL; + } + } + #endif + + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + { + pxNewTCB->ulNotifiedValue = 0; + pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + #endif + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Initialise this task's Newlib reent structure. */ + _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) ); + } + #endif + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + pxNewTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Initialize the TCB stack to look as if the task was already running, + but had been interrupted by the scheduler. The return address is set + to the start of the task function. Once the stack has been initialised + the top of stack variable is updated. */ + #if( portUSING_MPU_WRAPPERS == 1 ) + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); + } + #else /* portUSING_MPU_WRAPPERS */ + { + pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); + } + #endif /* portUSING_MPU_WRAPPERS */ + + if( ( void * ) pxCreatedTask != NULL ) + { + /* Pass the handle out in an anonymous way. The handle can be used to + change the created task's priority, delete the created task, etc.*/ + *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) +{ + /* Ensure interrupts don't access the task lists while the lists are being + updated. */ + taskENTER_CRITICAL(); + { + uxCurrentNumberOfTasks++; + if( pxCurrentTCB == NULL ) + { + /* There are no other tasks, or all the other tasks are in + the suspended state - make this the current task. */ + pxCurrentTCB = pxNewTCB; + + if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 ) + { + /* This is the first task to be created so do the preliminary + initialisation required. We will not recover if this call + fails, but we will report the failure. */ + prvInitialiseTaskLists(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If the scheduler is not already running, make this task the + current task if it is the highest priority task to be created + so far. */ + if( xSchedulerRunning == pdFALSE ) + { + if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority ) + { + pxCurrentTCB = pxNewTCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + uxTaskNumber++; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + } + #endif /* configUSE_TRACE_FACILITY */ + traceTASK_CREATE( pxNewTCB ); + + prvAddTaskToReadyList( pxNewTCB ); + + portSETUP_TCB( pxNewTCB ); + } + taskEXIT_CRITICAL(); + + if( xSchedulerRunning != pdFALSE ) + { + /* If the created task is of a higher priority than the current task + then it should run now. */ + if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + void vTaskDelete( TaskHandle_t xTaskToDelete ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the calling task that is + being deleted. */ + pxTCB = prvGetTCBFromHandle( xTaskToDelete ); + + /* Remove task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Increment the uxTaskNumber also so kernel aware debuggers can + detect that the task lists need re-generating. This is done before + portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will + not return. */ + uxTaskNumber++; + + if( pxTCB == pxCurrentTCB ) + { + /* A task is deleting itself. This cannot complete within the + task itself, as a context switch to another task is required. + Place the task in the termination list. The idle task will + check the termination list and free up any memory allocated by + the scheduler for the TCB and stack of the deleted task. */ + vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) ); + + /* Increment the ucTasksDeleted variable so the idle task knows + there is a task that has been deleted and that it should therefore + check the xTasksWaitingTermination list. */ + ++uxDeletedTasksWaitingCleanUp; + + /* The pre-delete hook is primarily for the Windows simulator, + in which Windows specific clean up operations are performed, + after which it is not possible to yield away from this task - + hence xYieldPending is used to latch that a context switch is + required. */ + portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending ); + } + else + { + --uxCurrentNumberOfTasks; + prvDeleteTCB( pxTCB ); + + /* Reset the next expected unblock time in case it referred to + the task that has just been deleted. */ + prvResetNextTaskUnblockTime(); + } + + traceTASK_DELETE( pxTCB ); + } + taskEXIT_CRITICAL(); + + /* Force a reschedule if it is the currently running task that has just + been deleted. */ + if( xSchedulerRunning != pdFALSE ) + { + if( pxTCB == pxCurrentTCB ) + { + configASSERT( uxSchedulerSuspended == 0 ); + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelayUntil == 1 ) + + void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) + { + TickType_t xTimeToWake; + BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE; + + configASSERT( pxPreviousWakeTime ); + configASSERT( ( xTimeIncrement > 0U ) ); + configASSERT( uxSchedulerSuspended == 0 ); + + vTaskSuspendAll(); + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount; + + /* Generate the tick time at which the task wants to wake. */ + xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; + + if( xConstTickCount < *pxPreviousWakeTime ) + { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) ) + { + xShouldDelay = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Update the wake time ready for the next call. */ + *pxPreviousWakeTime = xTimeToWake; + + if( xShouldDelay != pdFALSE ) + { + traceTASK_DELAY_UNTIL( xTimeToWake ); + + /* prvAddCurrentTaskToDelayedList() needs the block time, not + the time to wake, so subtract the current tick count. */ + prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xAlreadyYielded = xTaskResumeAll(); + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskDelayUntil */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelay == 1 ) + + void vTaskDelay( const TickType_t xTicksToDelay ) + { + BaseType_t xAlreadyYielded = pdFALSE; + + /* A delay time of zero just forces a reschedule. */ + if( xTicksToDelay > ( TickType_t ) 0U ) + { + configASSERT( uxSchedulerSuspended == 0 ); + vTaskSuspendAll(); + { + traceTASK_DELAY(); + + /* A task that is removed from the event list while the + scheduler is suspended will not get placed in the ready + list or removed from the blocked list until the scheduler + is resumed. + + This task cannot be in an event list as it is the currently + executing task. */ + prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); + } + xAlreadyYielded = xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Force a reschedule if xTaskResumeAll has not already done so, we may + have put ourselves to sleep. */ + if( xAlreadyYielded == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskDelay */ +/*-----------------------------------------------------------*/ + +#if( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) ) + + eTaskState eTaskGetState( TaskHandle_t xTask ) + { + eTaskState eReturn; + List_t *pxStateList; + const TCB_t * const pxTCB = ( TCB_t * ) xTask; + + configASSERT( pxTCB ); + + if( pxTCB == pxCurrentTCB ) + { + /* The task calling this function is querying its own state. */ + eReturn = eRunning; + } + else + { + taskENTER_CRITICAL(); + { + pxStateList = ( List_t * ) listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) ); + } + taskEXIT_CRITICAL(); + + if( ( pxStateList == pxDelayedTaskList ) || ( pxStateList == pxOverflowDelayedTaskList ) ) + { + /* The task being queried is referenced from one of the Blocked + lists. */ + eReturn = eBlocked; + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + else if( pxStateList == &xSuspendedTaskList ) + { + /* The task being queried is referenced from the suspended + list. Is it genuinely suspended or is it block + indefinitely? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ) + { + eReturn = eSuspended; + } + else + { + eReturn = eBlocked; + } + } + #endif + + #if ( INCLUDE_vTaskDelete == 1 ) + else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) + { + /* The task being queried is referenced from the deleted + tasks list, or it is not referenced from any lists at + all. */ + eReturn = eDeleted; + } + #endif + + else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */ + { + /* If the task is not in any other state, it must be in the + Ready (including pending ready) state. */ + eReturn = eReady; + } + } + + return eReturn; + } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_eTaskGetState */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the that + called uxTaskPriorityGet() that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + taskEXIT_CRITICAL(); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskPriorityGet == 1 ) + + UBaseType_t uxTaskPriorityGetFromISR( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + UBaseType_t uxReturn, uxSavedInterruptState; + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptState = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* If null is passed in here then it is the priority of the calling + task that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxPriority; + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptState ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskPriorityGet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + + void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) + { + TCB_t *pxTCB; + UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the priority of the calling + task that is being changed. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); + + #if ( configUSE_MUTEXES == 1 ) + { + uxCurrentBasePriority = pxTCB->uxBasePriority; + } + #else + { + uxCurrentBasePriority = pxTCB->uxPriority; + } + #endif + + if( uxCurrentBasePriority != uxNewPriority ) + { + /* The priority change may have readied a task of higher + priority than the calling task. */ + if( uxNewPriority > uxCurrentBasePriority ) + { + if( pxTCB != pxCurrentTCB ) + { + /* The priority of a task other than the currently + running task is being raised. Is the priority being + raised above that of the running task? */ + if( uxNewPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The priority of the running task is being raised, + but the running task must already be the highest + priority task able to run so no yield is required. */ + } + } + else if( pxTCB == pxCurrentTCB ) + { + /* Setting the priority of the running task down means + there may now be another task of higher priority that + is ready to execute. */ + xYieldRequired = pdTRUE; + } + else + { + /* Setting the priority of any other task down does not + require a yield as the running task must be above the + new priority of the task being modified. */ + } + + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + #if ( configUSE_MUTEXES == 1 ) + { + /* Only change the priority being used if the task is not + currently using an inherited priority. */ + if( pxTCB->uxBasePriority == pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The base priority gets set whatever. */ + pxTCB->uxBasePriority = uxNewPriority; + } + #else + { + pxTCB->uxPriority = uxNewPriority; + } + #endif + + /* Only reset the event list item value if the value is not + being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task is in the blocked or suspended list we need do + nothing more than change it's priority variable. However, if + the task is in a ready list it needs to be removed and placed + in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before adding + it to it's new ready list. As we are in a critical section we + can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + there is no need to check again and the port level + reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + prvAddTaskToReadyList( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xYieldRequired != pdFALSE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Remove compiler warning about unused variables when the port + optimised task selection is not being used. */ + ( void ) uxPriorityUsedOnEntry; + } + } + taskEXIT_CRITICAL(); + } + +#endif /* INCLUDE_vTaskPrioritySet */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void vTaskSuspend( TaskHandle_t xTaskToSuspend ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the running task that is + being suspended. */ + pxTCB = prvGetTCBFromHandle( xTaskToSuspend ); + + traceTASK_SUSPEND( pxTCB ); + + /* Remove task from the ready/delayed list and place in the + suspended list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Is the task waiting on an event also? */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ); + } + taskEXIT_CRITICAL(); + + if( xSchedulerRunning != pdFALSE ) + { + /* Reset the next expected unblock time in case it referred to the + task that is now in the Suspended state. */ + taskENTER_CRITICAL(); + { + prvResetNextTaskUnblockTime(); + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( pxTCB == pxCurrentTCB ) + { + if( xSchedulerRunning != pdFALSE ) + { + /* The current task has just been suspended. */ + configASSERT( uxSchedulerSuspended == 0 ); + portYIELD_WITHIN_API(); + } + else + { + /* The scheduler is not running, but the task that was pointed + to by pxCurrentTCB has just been suspended and pxCurrentTCB + must be adjusted to point to a different task. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) + { + /* No other tasks are ready, so set pxCurrentTCB back to + NULL so when the next task is created pxCurrentTCB will + be set to point to it no matter what its relative priority + is. */ + pxCurrentTCB = NULL; + } + else + { + vTaskSwitchContext(); + } + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) + { + BaseType_t xReturn = pdFALSE; + const TCB_t * const pxTCB = ( TCB_t * ) xTask; + + /* Accesses xPendingReadyList so must be called from a critical + section. */ + + /* It does not make sense to check if the calling task is suspended. */ + configASSERT( xTask ); + + /* Is the task being resumed actually in the suspended list? */ + if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* Has the task already been resumed from within an ISR? */ + if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) + { + /* Is it in the suspended list because it is in the Suspended + state, or because is is blocked with no timeout? */ + if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) + { + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */ + +#endif /* INCLUDE_vTaskSuspend */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskSuspend == 1 ) + + void vTaskResume( TaskHandle_t xTaskToResume ) + { + TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + + /* It does not make sense to resume the calling task. */ + configASSERT( xTaskToResume ); + + /* The parameter cannot be NULL as it is impossible to resume the + currently executing task. */ + if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) ) + { + taskENTER_CRITICAL(); + { + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) + { + traceTASK_RESUME( pxTCB ); + + /* As we are in a critical section we can access the ready + lists even if the scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* We may have just resumed a higher priority task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + /* This yield may not cause the task just resumed to run, + but will leave the lists in the correct state for the + next yield. */ + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* INCLUDE_vTaskSuspend */ + +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) + + BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) + { + BaseType_t xYieldRequired = pdFALSE; + TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToResume ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE ) + { + traceTASK_RESUME_FROM_ISR( pxTCB ); + + /* Check the ready lists can be accessed. */ + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + /* Ready lists can be accessed so move the task from the + suspended list to the ready list directly. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xYieldRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed or ready lists cannot be accessed so the task + is held in the pending ready list until the scheduler is + unsuspended. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xYieldRequired; + } + +#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ +/*-----------------------------------------------------------*/ + +void vTaskStartScheduler( void ) +{ +BaseType_t xReturn; + + /* Add the idle task at the lowest priority. */ + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t *pxIdleTaskTCBBuffer = NULL; + StackType_t *pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, + "IDLE", + ulIdleTaskStackSize, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + + if( xIdleTaskHandle != NULL ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + #else + { + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreate( prvIdleTask, + "IDLE", configMINIMAL_STACK_SIZE, + ( void * ) NULL, + ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), + &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + #if ( configUSE_TIMERS == 1 ) + { + if( xReturn == pdPASS ) + { + xReturn = xTimerCreateTimerTask(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TIMERS */ + + if( xReturn == pdPASS ) + { + /* Interrupts are turned off here, to ensure a tick does not occur + before or during the call to xPortStartScheduler(). The stacks of + the created tasks contain a status word with interrupts switched on + so interrupts will automatically get re-enabled when the first task + starts to run. */ + portDISABLE_INTERRUPTS(); + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to the task that will run first. */ + _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + + xNextTaskUnblockTime = portMAX_DELAY; + xSchedulerRunning = pdTRUE; + xTickCount = ( TickType_t ) 0U; + + /* If configGENERATE_RUN_TIME_STATS is defined then the following + macro must be defined to configure the timer/counter used to generate + the run time counter time base. */ + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + + /* Setting up the timer tick is hardware specific and thus in the + portable interface. */ + if( xPortStartScheduler() != pdFALSE ) + { + /* Should not reach here as if the scheduler is running the + function will not return. */ + } + else + { + /* Should only reach here if a task calls xTaskEndScheduler(). */ + } + } + else + { + /* This line will only be reached if the kernel could not be started, + because there was not enough FreeRTOS heap to create the idle task + or the timer task. */ + configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); + } + + /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, + meaning xIdleTaskHandle is not used anywhere else. */ + ( void ) xIdleTaskHandle; +} +/*-----------------------------------------------------------*/ + +void vTaskEndScheduler( void ) +{ + /* Stop the scheduler interrupts and call the portable scheduler end + routine so the original ISRs can be restored if necessary. The port + layer must ensure interrupts enable bit is left in the correct state. */ + portDISABLE_INTERRUPTS(); + xSchedulerRunning = pdFALSE; + vPortEndScheduler(); +} +/*----------------------------------------------------------*/ + +void vTaskSuspendAll( void ) +{ + /* A critical section is not required as the variable is of type + BaseType_t. Please read Richard Barry's reply in the following link to a + post in the FreeRTOS support forum before reporting this as a bug! - + http://goo.gl/wu4acr */ + ++uxSchedulerSuspended; +} +/*----------------------------------------------------------*/ + +#if ( configUSE_TICKLESS_IDLE != 0 ) + + static TickType_t prvGetExpectedIdleTime( void ) + { + TickType_t xReturn; + UBaseType_t uxHigherPriorityReadyTasks = pdFALSE; + + /* uxHigherPriorityReadyTasks takes care of the case where + configUSE_PREEMPTION is 0, so there may be tasks above the idle priority + task that are in the Ready state, even though the idle task is + running. */ + #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) + { + if( uxTopReadyPriority > tskIDLE_PRIORITY ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #else + { + const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01; + + /* When port optimised task selection is used the uxTopReadyPriority + variable is used as a bit map. If bits other than the least + significant bit are set then there are tasks that have a priority + above the idle priority that are in the Ready state. This takes + care of the case where the co-operative scheduler is in use. */ + if( uxTopReadyPriority > uxLeastSignificantBit ) + { + uxHigherPriorityReadyTasks = pdTRUE; + } + } + #endif + + if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY ) + { + xReturn = 0; + } + else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) + { + /* There are other idle priority tasks in the ready state. If + time slicing is used then the very next tick interrupt must be + processed. */ + xReturn = 0; + } + else if( uxHigherPriorityReadyTasks != pdFALSE ) + { + /* There are tasks in the Ready state that have a priority above the + idle priority. This path can only be reached if + configUSE_PREEMPTION is 0. */ + xReturn = 0; + } + else + { + xReturn = xNextTaskUnblockTime - xTickCount; + } + + return xReturn; + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskResumeAll( void ) +{ +TCB_t *pxTCB = NULL; +BaseType_t xAlreadyYielded = pdFALSE; + + /* If uxSchedulerSuspended is zero then this function does not match a + previous call to vTaskSuspendAll(). */ + configASSERT( uxSchedulerSuspended ); + + /* It is possible that an ISR caused a task to be removed from an event + list while the scheduler was suspended. If this was the case then the + removed task will have been added to the xPendingReadyList. Once the + scheduler has been resumed it is safe to move all the pending ready + tasks from this list into their appropriate ready list. */ + taskENTER_CRITICAL(); + { + --uxSchedulerSuspended; + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) + { + /* Move any readied tasks from the pending list into the + appropriate ready list. */ + while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) + { + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* If the moved task has a priority higher than the current + task then a yield must be performed. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( pxTCB != NULL ) + { + /* A task was unblocked while the scheduler was suspended, + which may have prevented the next unblock time from being + re-calculated, in which case re-calculate it now. Mainly + important for low power tickless implementations, where + this can prevent an unnecessary exit from low power + state. */ + prvResetNextTaskUnblockTime(); + } + + /* If any ticks occurred while the scheduler was suspended then + they should be processed now. This ensures the tick count does + not slip, and that any delayed tasks are resumed at the correct + time. */ + { + UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */ + + if( uxPendedCounts > ( UBaseType_t ) 0U ) + { + do + { + if( xTaskIncrementTick() != pdFALSE ) + { + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + --uxPendedCounts; + } while( uxPendedCounts > ( UBaseType_t ) 0U ); + + uxPendedTicks = 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( xYieldPending != pdFALSE ) + { + #if( configUSE_PREEMPTION != 0 ) + { + xAlreadyYielded = pdTRUE; + } + #endif + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xAlreadyYielded; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCount( void ) +{ +TickType_t xTicks; + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + xTicks = xTickCount; + } + portTICK_TYPE_EXIT_CRITICAL(); + + return xTicks; +} +/*-----------------------------------------------------------*/ + +TickType_t xTaskGetTickCountFromISR( void ) +{ +TickType_t xReturn; +UBaseType_t uxSavedInterruptStatus; + + /* RTOS ports that support interrupt nesting have the concept of a maximum + system call (or maximum API call) interrupt priority. Interrupts that are + above the maximum system call priority are kept permanently enabled, even + when the RTOS kernel is in a critical section, but cannot make any calls to + FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h + then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has been + assigned a priority above the configured maximum system call priority. + Only FreeRTOS functions that end in FromISR can be called from interrupts + that have been assigned a priority at or (logically) below the maximum + system call interrupt priority. FreeRTOS maintains a separate interrupt + safe API to ensure interrupt entry is as fast and as simple as possible. + More information (albeit Cortex-M specific) is provided on the following + link: http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); + { + xReturn = xTickCount; + } + portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxTaskGetNumberOfTasks( void ) +{ + /* A critical section is not required because the variables are of type + BaseType_t. */ + return uxCurrentNumberOfTasks; +} +/*-----------------------------------------------------------*/ + +char *pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +TCB_t *pxTCB; + + /* If null is passed in here then the name of the calling task is being + queried. */ + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + configASSERT( pxTCB ); + return &( pxTCB->pcTaskName[ 0 ] ); +} +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetHandle == 1 ) + + static TCB_t *prvSearchForNameWithinSingleList( List_t *pxList, const char pcNameToQuery[] ) + { + TCB_t *pxNextTCB, *pxFirstTCB, *pxReturn = NULL; + UBaseType_t x; + char cNextChar; + + /* This function is called with the scheduler suspended. */ + + if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + + /* Check each character in the name looking for a match or + mismatch. */ + for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ) + { + cNextChar = pxNextTCB->pcTaskName[ x ]; + + if( cNextChar != pcNameToQuery[ x ] ) + { + /* Characters didn't match. */ + break; + } + else if( cNextChar == 0x00 ) + { + /* Both strings terminated, a match must have been + found. */ + pxReturn = pxNextTCB; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( pxReturn != NULL ) + { + /* The handle has been found. */ + break; + } + + } while( pxNextTCB != pxFirstTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return pxReturn; + } + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetHandle == 1 ) + + TaskHandle_t xTaskGetHandle( const char *pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + UBaseType_t uxQueue = configMAX_PRIORITIES; + TCB_t* pxTCB; + + /* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */ + configASSERT( strlen( pcNameToQuery ) < configMAX_TASK_NAME_LEN ); + + vTaskSuspendAll(); + { + /* Search the ready lists. */ + do + { + uxQueue--; + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) &( pxReadyTasksLists[ uxQueue ] ), pcNameToQuery ); + + if( pxTCB != NULL ) + { + /* Found the handle. */ + break; + } + + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Search the delayed lists. */ + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxDelayedTaskList, pcNameToQuery ); + } + + if( pxTCB == NULL ) + { + pxTCB = prvSearchForNameWithinSingleList( ( List_t * ) pxOverflowDelayedTaskList, pcNameToQuery ); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the suspended list. */ + pxTCB = prvSearchForNameWithinSingleList( &xSuspendedTaskList, pcNameToQuery ); + } + } + #endif + + #if( INCLUDE_vTaskDelete == 1 ) + { + if( pxTCB == NULL ) + { + /* Search the deleted list. */ + pxTCB = prvSearchForNameWithinSingleList( &xTasksWaitingTermination, pcNameToQuery ); + } + } + #endif + } + ( void ) xTaskResumeAll(); + + return ( TaskHandle_t ) pxTCB; + } + +#endif /* INCLUDE_xTaskGetHandle */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) + { + UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; + + vTaskSuspendAll(); + { + /* Is there a space in the array for each task in the system? */ + if( uxArraySize >= uxCurrentNumberOfTasks ) + { + /* Fill in an TaskStatus_t structure with information on each + task in the Ready state. */ + do + { + uxQueue--; + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady ); + + } while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + /* Fill in an TaskStatus_t structure with information on each + task in the Blocked state. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked ); + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked ); + + #if( INCLUDE_vTaskDelete == 1 ) + { + /* Fill in an TaskStatus_t structure with information on + each task that has been deleted but not yet cleaned up. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted ); + } + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* Fill in an TaskStatus_t structure with information on + each task in the Suspended state. */ + uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended ); + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1) + { + if( pulTotalRunTime != NULL ) + { + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) ); + #else + *pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + } + } + #else + { + if( pulTotalRunTime != NULL ) + { + *pulTotalRunTime = 0; + } + } + #endif + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + ( void ) xTaskResumeAll(); + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + + TaskHandle_t xTaskGetIdleTaskHandle( void ) + { + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + started, then xIdleTaskHandle will be NULL. */ + configASSERT( ( xIdleTaskHandle != NULL ) ); + return xIdleTaskHandle; + } + +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ +/*----------------------------------------------------------*/ + +/* This conditional compilation should use inequality to 0, not equality to 1. +This is to ensure vTaskStepTick() is available when user defined low power mode +implementations require configUSE_TICKLESS_IDLE to be set to a value other than +1. */ +#if ( configUSE_TICKLESS_IDLE != 0 ) + + void vTaskStepTick( const TickType_t xTicksToJump ) + { + /* Correct the tick count value after a period during which the tick + was suppressed. Note this does *not* call the tick hook function for + each stepped tick. */ + configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); + xTickCount += xTicksToJump; + traceINCREASE_TICK_COUNT( xTicksToJump ); + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ + +#if ( INCLUDE_xTaskAbortDelay == 1 ) + + BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) + { + TCB_t *pxTCB = ( TCB_t * ) xTask; + BaseType_t xReturn = pdFALSE; + + configASSERT( pxTCB ); + + vTaskSuspendAll(); + { + /* A task can only be prematurely removed from the Blocked state if + it is actually in the Blocked state. */ + if( eTaskGetState( xTask ) == eBlocked ) + { + /* Remove the reference to the task from the blocked list. An + interrupt won't touch the xStateListItem because the + scheduler is suspended. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + + /* Is the task waiting on an event also? If so remove it from + the event list too. Interrupts can touch the event list item, + even though the scheduler is suspended, so a critical section + is used. */ + taskENTER_CRITICAL(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + pxTCB->ucDelayAborted = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + /* Place the unblocked task into the appropriate ready list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate context + switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should only be + performed if the unblocked task has a priority that is + equal to or higher than the currently executing task. */ + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Pend the yield to be performed when the scheduler + is unsuspended. */ + xYieldPending = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + xTaskResumeAll(); + + return xReturn; + } + +#endif /* INCLUDE_xTaskAbortDelay */ +/*----------------------------------------------------------*/ + +BaseType_t xTaskIncrementTick( void ) +{ +TCB_t * pxTCB; +TickType_t xItemValue; +BaseType_t xSwitchRequired = pdFALSE; + + /* Called by the portable layer each time a tick interrupt occurs. + Increments the tick then checks to see if the new tick value will cause any + tasks to be unblocked. */ + traceTASK_INCREMENT_TICK( xTickCount ); + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + /* Minor optimisation. The tick count cannot change in this + block. */ + const TickType_t xConstTickCount = xTickCount + 1; + + /* Increment the RTOS tick, switching the delayed and overflowed + delayed lists if it wraps to 0. */ + xTickCount = xConstTickCount; + + if( xConstTickCount == ( TickType_t ) 0U ) + { + taskSWITCH_DELAYED_LISTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* See if this tick has made a timeout expire. Tasks are stored in + the queue in the order of their wake time - meaning once one task + has been found whose block time has not expired there is no need to + look any further down the list. */ + if( xConstTickCount >= xNextTaskUnblockTime ) + { + for( ;; ) + { + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The delayed list is empty. Set xNextTaskUnblockTime + to the maximum possible value so it is extremely + unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass + next time through. */ + xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + break; + } + else + { + /* The delayed list is not empty, get the value of the + item at the head of the delayed list. This is the time + at which the task at the head of the delayed list must + be removed from the Blocked state. */ + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); + + if( xConstTickCount < xItemValue ) + { + /* It is not time to unblock this item yet, but the + item value is the time at which the task at the head + of the blocked list must be removed from the Blocked + state - so record the item value in + xNextTaskUnblockTime. */ + xNextTaskUnblockTime = xItemValue; + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* It is time to remove the item from the Blocked state. */ + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + + /* Is the task waiting on an event also? If so remove + it from the event list. */ + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Place the unblocked task into the appropriate ready + list. */ + prvAddTaskToReadyList( pxTCB ); + + /* A task being unblocked cannot cause an immediate + context switch if preemption is turned off. */ + #if ( configUSE_PREEMPTION == 1 ) + { + /* Preemption is on, but a context switch should + only be performed if the unblocked task has a + priority that is equal to or higher than the + currently executing task. */ + if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + } + } + } + + /* Tasks of equal priority to the currently running task will share + processing time (time slice) if preemption is on, and the application + writer has not explicitly turned time slicing off. */ + #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) + { + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ + + #if ( configUSE_TICK_HOOK == 1 ) + { + /* Guard against the tick hook being called when the pended tick + count is being unwound (when the scheduler is being unlocked). */ + if( uxPendedTicks == ( UBaseType_t ) 0U ) + { + vApplicationTickHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TICK_HOOK */ + } + else + { + ++uxPendedTicks; + + /* The tick hook gets called at regular intervals, even if the + scheduler is locked. */ + #if ( configUSE_TICK_HOOK == 1 ) + { + vApplicationTickHook(); + } + #endif + } + + #if ( configUSE_PREEMPTION == 1 ) + { + if( xYieldPending != pdFALSE ) + { + xSwitchRequired = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_PREEMPTION */ + + return xSwitchRequired; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) + { + TCB_t *xTCB; + + /* If xTask is NULL then it is the task hook of the calling task that is + getting set. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + xTCB->pxTaskTag = pxHookFunction; + taskEXIT_CRITICAL(); + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) + { + TCB_t *xTCB; + TaskHookFunction_t xReturn; + + /* If xTask is NULL then we are setting our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + /* Save the hook function in the TCB. A critical section is required as + the value can be accessed from an interrupt. */ + taskENTER_CRITICAL(); + { + xReturn = xTCB->pxTaskTag; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_APPLICATION_TASK_TAG == 1 ) + + BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) + { + TCB_t *xTCB; + BaseType_t xReturn; + + /* If xTask is NULL then we are calling our own task hook. */ + if( xTask == NULL ) + { + xTCB = ( TCB_t * ) pxCurrentTCB; + } + else + { + xTCB = ( TCB_t * ) xTask; + } + + if( xTCB->pxTaskTag != NULL ) + { + xReturn = xTCB->pxTaskTag( pvParameter ); + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* configUSE_APPLICATION_TASK_TAG */ +/*-----------------------------------------------------------*/ + +void vTaskSwitchContext( void ) +{ + if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) + { + /* The scheduler is currently suspended - do not allow a context + switch. */ + xYieldPending = pdTRUE; + } + else + { + xYieldPending = pdFALSE; + traceTASK_SWITCHED_OUT(); + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE + portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime ); + #else + ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + #endif + + /* Add the amount of time the task has been running to the + accumulated time so far. The time the task started running was + stored in ulTaskSwitchedInTime. Note that there is no overflow + protection here so count values are only valid until the timer + overflows. The guard against negative values is to protect + against suspect run time stat counter implementations - which + are provided by the application, not the kernel. */ + if( ulTotalRunTime > ulTaskSwitchedInTime ) + { + pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + ulTaskSwitchedInTime = ulTotalRunTime; + } + #endif /* configGENERATE_RUN_TIME_STATS */ + + /* Check for stack overflow, if configured. */ + taskCHECK_FOR_STACK_OVERFLOW(); + + /* Select a new task to run using either the generic C or port + optimised asm code. */ + taskSELECT_HIGHEST_PRIORITY_TASK(); + traceTASK_SWITCHED_IN(); + + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + /* Switch Newlib's _impure_ptr variable to point to the _reent + structure specific to this task. */ + _impure_ptr = &( pxCurrentTCB->xNewLib_reent ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + } +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) +{ + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ + + /* Place the event list item of the TCB in the appropriate event list. + This is placed in the list in priority order so the highest priority task + is the first to be woken by the event. The queue that contains the event + list is locked, preventing simultaneous access from interrupts. */ + vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); +} +/*-----------------------------------------------------------*/ + +void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) +{ + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event groups implementation. */ + configASSERT( uxSchedulerSuspended != 0 ); + + /* Store the item value in the event list item. It is safe to access the + event list item here as interrupts won't access the event list item of a + task that is not in the Blocked state. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Place the event list item of the TCB at the end of the appropriate event + list. It is safe to access the event list here because it is part of an + event group implementation - and interrupts don't access event groups + directly (instead they access them indirectly by pending function calls to + the task level). */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TIMERS == 1 ) + + void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) + { + configASSERT( pxEventList ); + + /* This function should not be called by application code hence the + 'Restricted' in its name. It is not part of the public API. It is + designed for use by kernel code, and has special calling requirements - + it should be called with the scheduler suspended. */ + + + /* Place the event list item of the TCB in the appropriate event list. + In this case it is assume that this is the only task that is going to + be waiting on this event list, so the faster vListInsertEnd() function + can be used in place of vListInsert. */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + /* If the task should block indefinitely then set the block time to a + value that will be recognised as an indefinite delay inside the + prvAddCurrentTaskToDelayedList() function. */ + if( xWaitIndefinitely != pdFALSE ) + { + xTicksToWait = portMAX_DELAY; + } + + traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) ); + prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely ); + } + +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) +{ +TCB_t *pxUnblockedTCB; +BaseType_t xReturn; + + /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be + called from a critical section within an ISR. */ + + /* The event list is sorted in priority order, so the first in the list can + be removed as it is known to be the highest priority. Remove the TCB from + the delayed list, and add it to the ready list. + + If an event is for a queue that is locked then this function will never + get called - the lock count on the queue will get modified instead. This + means exclusive access to the event list is guaranteed here. + + This function assumes that a check has already been made to ensure that + pxEventList is not empty. */ + pxUnblockedTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold this task + pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); + } + + if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has a higher + priority than the calling task. This allows the calling task to know if + it should force a context switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked on a kernel object then xNextTaskUnblockTime + might be set to the blocked task's time out time. If the task is + unblocked for a reason other than a timeout xNextTaskUnblockTime is + normally left unchanged, because it is automatically reset to a new + value when the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter sleep mode + at the earliest possible time - so reset xNextTaskUnblockTime here to + ensure it is updated at the earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) +{ +TCB_t *pxUnblockedTCB; +BaseType_t xReturn; + + /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by + the event flags implementation. */ + configASSERT( uxSchedulerSuspended != pdFALSE ); + + /* Store the new item value in the event list. */ + listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ); + + /* Remove the event list form the event flag. Interrupts do not access + event flags. */ + pxUnblockedTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( pxEventListItem ); + + /* Remove the task from the delayed list and add it to the ready list. The + scheduler is suspended so interrupts will not be accessing the ready + lists. */ + ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + + if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has + a higher priority than the calling task. This allows + the calling task to know if it should force a context + switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) +{ + configASSERT( pxTimeOut ); + pxTimeOut->xOverflowCount = xNumOfOverflows; + pxTimeOut->xTimeOnEntering = xTickCount; +} +/*-----------------------------------------------------------*/ + +BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) +{ +BaseType_t xReturn; + + configASSERT( pxTimeOut ); + configASSERT( pxTicksToWait ); + + taskENTER_CRITICAL(); + { + /* Minor optimisation. The tick count cannot change in this block. */ + const TickType_t xConstTickCount = xTickCount; + + #if( INCLUDE_xTaskAbortDelay == 1 ) + if( pxCurrentTCB->ucDelayAborted != pdFALSE ) + { + /* The delay was aborted, which is not the same as a time out, + but has the same result. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + xReturn = pdTRUE; + } + else + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + if( *pxTicksToWait == portMAX_DELAY ) + { + /* If INCLUDE_vTaskSuspend is set to 1 and the block time + specified is the maximum block time then the task should block + indefinitely, and therefore never time out. */ + xReturn = pdFALSE; + } + else + #endif + + if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xConstTickCount >= pxTimeOut->xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */ + { + /* The tick count is greater than the time at which + vTaskSetTimeout() was called, but has also overflowed since + vTaskSetTimeOut() was called. It must have wrapped all the way + around and gone past again. This passed since vTaskSetTimeout() + was called. */ + xReturn = pdTRUE; + } + else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ + { + /* Not a genuine timeout. Adjust parameters for time remaining. */ + *pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering ); + vTaskSetTimeOutState( pxTimeOut ); + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vTaskMissedYield( void ) +{ + xYieldPending = pdTRUE; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) + { + UBaseType_t uxReturn; + TCB_t *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( TCB_t * ) xTask; + uxReturn = pxTCB->uxTaskNumber; + } + else + { + uxReturn = 0U; + } + + return uxReturn; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) + { + TCB_t *pxTCB; + + if( xTask != NULL ) + { + pxTCB = ( TCB_t * ) xTask; + pxTCB->uxTaskNumber = uxHandle; + } + } + +#endif /* configUSE_TRACE_FACILITY */ + +/* + * ----------------------------------------------------------- + * The Idle task. + * ---------------------------------------------------------- + * + * The portTASK_FUNCTION() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvIdleTask( void *pvParameters ); + * + */ +static portTASK_FUNCTION( prvIdleTask, pvParameters ) +{ + /* Stop warnings. */ + ( void ) pvParameters; + + /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE + SCHEDULER IS STARTED. **/ + + for( ;; ) + { + /* See if any tasks have deleted themselves - if so then the idle task + is responsible for freeing the deleted task's TCB and stack. */ + prvCheckTasksWaitingTermination(); + + #if ( configUSE_PREEMPTION == 0 ) + { + /* If we are not using preemption we keep forcing a task switch to + see if any other task has become available. If we are using + preemption we don't need to do this as any task becoming available + will automatically get the processor anyway. */ + taskYIELD(); + } + #endif /* configUSE_PREEMPTION */ + + #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) + { + /* When using preemption tasks of equal priority will be + timesliced. If a task that is sharing the idle priority is ready + to run then the idle task should yield before the end of the + timeslice. + + A critical region is not required here as we are just reading from + the list, and an occasional incorrect value will not matter. If + the ready list at the idle priority contains more than one task + then a task other than the idle task is ready to execute. */ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 ) + { + taskYIELD(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ + + #if ( configUSE_IDLE_HOOK == 1 ) + { + extern void vApplicationIdleHook( void ); + + /* Call the user defined function from within the idle task. This + allows the application designer to add background functionality + without the overhead of a separate task. + NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + CALL A FUNCTION THAT MIGHT BLOCK. */ + vApplicationIdleHook(); + } + #endif /* configUSE_IDLE_HOOK */ + + /* This conditional compilation should use inequality to 0, not equality + to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when + user defined low power mode implementations require + configUSE_TICKLESS_IDLE to be set to a value other than 1. */ + #if ( configUSE_TICKLESS_IDLE != 0 ) + { + TickType_t xExpectedIdleTime; + + /* It is not desirable to suspend then resume the scheduler on + each iteration of the idle task. Therefore, a preliminary + test of the expected idle time is performed without the + scheduler suspended. The result here is not necessarily + valid. */ + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + vTaskSuspendAll(); + { + /* Now the scheduler is suspended, the expected idle + time can be sampled again, and this time its value can + be used. */ + configASSERT( xNextTaskUnblockTime >= xTickCount ); + xExpectedIdleTime = prvGetExpectedIdleTime(); + + if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) + { + traceLOW_POWER_IDLE_BEGIN(); + portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); + traceLOW_POWER_IDLE_END(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + ( void ) xTaskResumeAll(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configUSE_TICKLESS_IDLE */ + } +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TICKLESS_IDLE != 0 ) + + eSleepModeStatus eTaskConfirmSleepModeStatus( void ) + { + /* The idle task exists in addition to the application tasks. */ + const UBaseType_t uxNonApplicationTasks = 1; + eSleepModeStatus eReturn = eStandardSleep; + + if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 ) + { + /* A task was made ready while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else if( xYieldPending != pdFALSE ) + { + /* A yield was pended while the scheduler was suspended. */ + eReturn = eAbortSleep; + } + else + { + /* If all the tasks are in the suspended list (which might mean they + have an infinite block time rather than actually being suspended) + then it is safe to turn all clocks off and just wait for external + interrupts. */ + if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) ) + { + eReturn = eNoTasksWaitingTimeout; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + return eReturn; + } + +#endif /* configUSE_TICKLESS_IDLE */ +/*-----------------------------------------------------------*/ + +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + + void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue ) + { + TCB_t *pxTCB; + + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToSet ); + pxTCB->pvThreadLocalStoragePointers[ xIndex ] = pvValue; + } + } + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 ) + + void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex ) + { + void *pvReturn = NULL; + TCB_t *pxTCB; + + if( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) + { + pxTCB = prvGetTCBFromHandle( xTaskToQuery ); + pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ]; + } + else + { + pvReturn = NULL; + } + + return pvReturn; + } + +#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */ +/*-----------------------------------------------------------*/ + +#if ( portUSING_MPU_WRAPPERS == 1 ) + + void vTaskAllocateMPURegions( TaskHandle_t xTaskToModify, const MemoryRegion_t * const xRegions ) + { + TCB_t *pxTCB; + + /* If null is passed in here then we are modifying the MPU settings of + the calling task. */ + pxTCB = prvGetTCBFromHandle( xTaskToModify ); + + vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); + } + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseTaskLists( void ) +{ +UBaseType_t uxPriority; + + for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ ) + { + vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) ); + } + + vListInitialise( &xDelayedTaskList1 ); + vListInitialise( &xDelayedTaskList2 ); + vListInitialise( &xPendingReadyList ); + + #if ( INCLUDE_vTaskDelete == 1 ) + { + vListInitialise( &xTasksWaitingTermination ); + } + #endif /* INCLUDE_vTaskDelete */ + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + vListInitialise( &xSuspendedTaskList ); + } + #endif /* INCLUDE_vTaskSuspend */ + + /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList + using list2. */ + pxDelayedTaskList = &xDelayedTaskList1; + pxOverflowDelayedTaskList = &xDelayedTaskList2; +} +/*-----------------------------------------------------------*/ + +static void prvCheckTasksWaitingTermination( void ) +{ + + /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/ + + #if ( INCLUDE_vTaskDelete == 1 ) + { + BaseType_t xListIsEmpty; + + /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called + too often in the idle task. */ + while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U ) + { + vTaskSuspendAll(); + { + xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); + } + ( void ) xTaskResumeAll(); + + if( xListIsEmpty == pdFALSE ) + { + TCB_t *pxTCB; + + taskENTER_CRITICAL(); + { + pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) ); + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + --uxCurrentNumberOfTasks; + --uxDeletedTasksWaitingCleanUp; + } + taskEXIT_CRITICAL(); + + prvDeleteTCB( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + #endif /* INCLUDE_vTaskDelete */ +} +/*-----------------------------------------------------------*/ + +#if( configUSE_TRACE_FACILITY == 1 ) + + void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) + { + TCB_t *pxTCB; + + /* xTask is NULL then get the state of the calling task. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB; + pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] ); + pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority; + pxTaskStatus->pxStackBase = pxTCB->pxStack; + pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber; + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + /* If the task is in the suspended list then there is a chance it is + actually just blocked indefinitely - so really it should be reported as + being in the Blocked state. */ + if( pxTaskStatus->eCurrentState == eSuspended ) + { + vTaskSuspendAll(); + { + if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) + { + pxTaskStatus->eCurrentState = eBlocked; + } + } + xTaskResumeAll(); + } + } + #endif /* INCLUDE_vTaskSuspend */ + + #if ( configUSE_MUTEXES == 1 ) + { + pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority; + } + #else + { + pxTaskStatus->uxBasePriority = 0; + } + #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter; + } + #else + { + pxTaskStatus->ulRunTimeCounter = 0; + } + #endif + + /* Obtaining the task state is a little fiddly, so is only done if the value + of eState passed into this function is eInvalid - otherwise the state is + just set to whatever is passed in. */ + if( eState != eInvalid ) + { + pxTaskStatus->eCurrentState = eState; + } + else + { + pxTaskStatus->eCurrentState = eTaskGetState( xTask ); + } + + /* Obtaining the stack space takes some time, so the xGetFreeStackSpace + parameter is provided to allow it to be skipped. */ + if( xGetFreeStackSpace != pdFALSE ) + { + #if ( portSTACK_GROWTH > 0 ) + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack ); + } + #else + { + pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack ); + } + #endif + } + else + { + pxTaskStatus->usStackHighWaterMark = 0; + } + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState ) + { + volatile TCB_t *pxNextTCB, *pxFirstTCB; + UBaseType_t uxTask = 0; + + if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) + { + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + + /* Populate an TaskStatus_t structure within the + pxTaskStatusArray array for each task that is referenced from + pxList. See the definition of TaskStatus_t in task.h for the + meaning of each TaskStatus_t structure member. */ + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + vTaskGetInfo( ( TaskHandle_t ) pxNextTCB, &( pxTaskStatusArray[ uxTask ] ), pdTRUE, eState ); + uxTask++; + } while( pxNextTCB != pxFirstTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return uxTask; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) + + static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) + { + uint32_t ulCount = 0U; + + while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE ) + { + pucStackByte -= portSTACK_GROWTH; + ulCount++; + } + + ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */ + + return ( uint16_t ) ulCount; + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) + + UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + uint8_t *pucEndOfStack; + UBaseType_t uxReturn; + + pxTCB = prvGetTCBFromHandle( xTask ); + + #if portSTACK_GROWTH < 0 + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxStack; + } + #else + { + pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack; + } + #endif + + uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack ); + + return uxReturn; + } + +#endif /* INCLUDE_uxTaskGetStackHighWaterMark */ +/*-----------------------------------------------------------*/ + +#if ( INCLUDE_vTaskDelete == 1 ) + + static void prvDeleteTCB( TCB_t *pxTCB ) + { + /* This call is required specifically for the TriCore port. It must be + above the vPortFree() calls. The call is also used by ports/demos that + want to allocate and clean RAM statically. */ + portCLEAN_UP_TCB( pxTCB ); + + /* Free up the memory allocated by the scheduler for the task. It is up + to the task to free any memory allocated at the application level. */ + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + { + _reclaim_reent( &( pxTCB->xNewLib_reent ) ); + } + #endif /* configUSE_NEWLIB_REENTRANT */ + + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) ) + { + /* The task can only have been allocated dynamically - free both + the stack and TCB. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 ) + { + /* The task could have been allocated statically or dynamically, so + check what was statically allocated before trying to free the + memory. */ + if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ) + { + /* Both the stack and TCB were allocated dynamically, so both + must be freed. */ + vPortFree( pxTCB->pxStack ); + vPortFree( pxTCB ); + } + else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY ) + { + /* Only the stack was statically allocated, so the TCB is the + only memory that must be freed. */ + vPortFree( pxTCB ); + } + else + { + /* Neither the stack nor the TCB were allocated dynamically, so + nothing needs to be freed. */ + configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ + +static void prvResetNextTaskUnblockTime( void ) +{ +TCB_t *pxTCB; + + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The new current delayed list is empty. Set xNextTaskUnblockTime to + the maximum possible value so it is extremely unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass until + there is an item in the delayed list. */ + xNextTaskUnblockTime = portMAX_DELAY; + } + else + { + /* The new current delayed list is not empty, get the value of + the item at the head of the delayed list. This is the time at + which the task at the head of the delayed list should be removed + from the Blocked state. */ + ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) ); + } +} +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) + + TaskHandle_t xTaskGetCurrentTaskHandle( void ) + { + TaskHandle_t xReturn; + + /* A critical section is not required as this is not called from + an interrupt and the current TCB will always be the same for any + individual execution thread. */ + xReturn = pxCurrentTCB; + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) + + BaseType_t xTaskGetSchedulerState( void ) + { + BaseType_t xReturn; + + if( xSchedulerRunning == pdFALSE ) + { + xReturn = taskSCHEDULER_NOT_STARTED; + } + else + { + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + xReturn = taskSCHEDULER_RUNNING; + } + else + { + xReturn = taskSCHEDULER_SUSPENDED; + } + } + + return xReturn; + } + +#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) + { + TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + + /* If the mutex was given back by an interrupt while the queue was + locked then the mutex holder might now be NULL. */ + if( pxMutexHolder != NULL ) + { + /* If the holder of the mutex has a priority below the priority of + the task attempting to obtain the mutex then it will temporarily + inherit the priority of the task attempting to obtain the mutex. */ + if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) + { + /* Adjust the mutex holder state to account for its new + priority. Only reset the event list item value if the value is + not being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task being modified is in the ready state it will need + to be moved into a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Inherit the priority before being moved into the new list. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* Just inherit the priority. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + } + + traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) + { + TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; + BaseType_t xReturn = pdFALSE; + + if( pxMutexHolder != NULL ) + { + /* A task can only have an inherited priority if it holds the mutex. + If the mutex is held by a task then it cannot be given from an + interrupt, and if a mutex is given by the holding task then it must + be the running state task. */ + configASSERT( pxTCB == pxCurrentTCB ); + + configASSERT( pxTCB->uxMutexesHeld ); + ( pxTCB->uxMutexesHeld )--; + + /* Has the holder of the mutex inherited the priority of another + task? */ + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) + { + /* Only disinherit if no other mutexes are held. */ + if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) + { + /* A task can only have an inherited priority if it holds + the mutex. If the mutex is held by a task then it cannot be + given from an interrupt, and if a mutex is given by the + holding task then it must be the running state task. Remove + the holding task from the ready list. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + taskRESET_READY_PRIORITY( pxTCB->uxPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Disinherit the priority before adding the task into the + new ready list. */ + traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); + pxTCB->uxPriority = pxTCB->uxBasePriority; + + /* Reset the event list item value. It cannot be in use for + any other purpose if this task is running, and it must be + running to give back the mutex. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + prvAddTaskToReadyList( pxTCB ); + + /* Return true to indicate that a context switch is required. + This is only actually required in the corner case whereby + multiple mutexes were held and the mutexes were given back + in an order different to that in which they were taken. + If a context switch did not occur when the first mutex was + returned, even if a task was waiting on it, then a context + switch should occur when the last mutex is returned whether + a task is waiting on it or not. */ + xReturn = pdTRUE; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void vTaskEnterCritical( void ) + { + portDISABLE_INTERRUPTS(); + + if( xSchedulerRunning != pdFALSE ) + { + ( pxCurrentTCB->uxCriticalNesting )++; + + /* This is not the interrupt safe version of the enter critical + function so assert() if it is being called from an interrupt + context. Only API functions that end in "FromISR" can be used in an + interrupt. Only assert if the critical nesting count is 1 to + protect against recursive calls if the assert function also uses a + critical section. */ + if( pxCurrentTCB->uxCriticalNesting == 1 ) + { + portASSERT_IF_IN_ISR(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( portCRITICAL_NESTING_IN_TCB == 1 ) + + void vTaskExitCritical( void ) + { + if( xSchedulerRunning != pdFALSE ) + { + if( pxCurrentTCB->uxCriticalNesting > 0U ) + { + ( pxCurrentTCB->uxCriticalNesting )--; + + if( pxCurrentTCB->uxCriticalNesting == 0U ) + { + portENABLE_INTERRUPTS(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* portCRITICAL_NESTING_IN_TCB */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static char *prvWriteNameToBuffer( char *pcBuffer, const char *pcTaskName ) + { + size_t x; + + /* Start by copying the entire string. */ + strcpy( pcBuffer, pcTaskName ); + + /* Pad the end of the string with spaces to ensure columns line up when + printed out. */ + for( x = strlen( pcBuffer ); x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ); x++ ) + { + pcBuffer[ x ] = ' '; + } + + /* Terminate. */ + pcBuffer[ x ] = 0x00; + + /* Return the new end of string. */ + return &( pcBuffer[ x ] ); + } + +#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */ +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + void vTaskList( char * pcWriteBuffer ) + { + TaskStatus_t *pxTaskStatusArray; + volatile UBaseType_t uxArraySize, x; + char cStatus; + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskList() calls uxTaskGetSystemState(), then formats part of the + * uxTaskGetSystemState() output into a human readable table that + * displays task names, states and stack usage. + * + * vTaskList() has a dependency on the sprintf() C library function that + * might bloat the code size, use a lot of stack, and provide different + * results on different platforms. An alternative, tiny, third party, + * and limited functionality implementation of sprintf() is provided in + * many of the FreeRTOS/Demo sub-directories in a file called + * printf-stdarg.c (note printf-stdarg.c does not provide a full + * snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskList(). + */ + + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! if + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, NULL ); + + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + switch( pxTaskStatusArray[ x ].eCurrentState ) + { + case eReady: cStatus = tskREADY_CHAR; + break; + + case eBlocked: cStatus = tskBLOCKED_CHAR; + break; + + case eSuspended: cStatus = tskSUSPENDED_CHAR; + break; + + case eDeleted: cStatus = tskDELETED_CHAR; + break; + + default: /* Should not get here, but it is included + to prevent static checking errors. */ + cStatus = 0x00; + break; + } + + /* Write the task name to the string, padding with spaces so it + can be printed in tabular form more easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + /* Write the rest of the string. */ + sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); + pcWriteBuffer += strlen( pcWriteBuffer ); + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree( pxTaskStatusArray ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +/*----------------------------------------------------------*/ + +#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + void vTaskGetRunTimeStats( char *pcWriteBuffer ) + { + TaskStatus_t *pxTaskStatusArray; + volatile UBaseType_t uxArraySize, x; + uint32_t ulTotalTime, ulStatsAsPercentage; + + #if( configUSE_TRACE_FACILITY != 1 ) + { + #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats(). + } + #endif + + /* + * PLEASE NOTE: + * + * This function is provided for convenience only, and is used by many + * of the demo applications. Do not consider it to be part of the + * scheduler. + * + * vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats part + * of the uxTaskGetSystemState() output into a human readable table that + * displays the amount of time each task has spent in the Running state + * in both absolute and percentage terms. + * + * vTaskGetRunTimeStats() has a dependency on the sprintf() C library + * function that might bloat the code size, use a lot of stack, and + * provide different results on different platforms. An alternative, + * tiny, third party, and limited functionality implementation of + * sprintf() is provided in many of the FreeRTOS/Demo sub-directories in + * a file called printf-stdarg.c (note printf-stdarg.c does not provide + * a full snprintf() implementation!). + * + * It is recommended that production systems call uxTaskGetSystemState() + * directly to get access to raw stats data, rather than indirectly + * through a call to vTaskGetRunTimeStats(). + */ + + /* Make sure the write buffer does not contain a string. */ + *pcWriteBuffer = 0x00; + + /* Take a snapshot of the number of tasks in case it changes while this + function is executing. */ + uxArraySize = uxCurrentNumberOfTasks; + + /* Allocate an array index for each task. NOTE! If + configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc() will + equate to NULL. */ + pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) ); + + if( pxTaskStatusArray != NULL ) + { + /* Generate the (binary) data. */ + uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime ); + + /* For percentage calculations. */ + ulTotalTime /= 100UL; + + /* Avoid divide by zero errors. */ + if( ulTotalTime > 0 ) + { + /* Create a human readable table from the binary data. */ + for( x = 0; x < uxArraySize; x++ ) + { + /* What percentage of the total run time has the task used? + This will always be rounded down to the nearest integer. + ulTotalRunTimeDiv100 has already been divided by 100. */ + ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime; + + /* Write the task name to the string, padding with + spaces so it can be printed in tabular form more + easily. */ + pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArray[ x ].pcTaskName ); + + if( ulStatsAsPercentage > 0UL ) + { + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage ); + } + #endif + } + else + { + /* If the percentage is zero here then the task has + consumed less than 1% of the total run time. */ + #ifdef portLU_PRINTF_SPECIFIER_REQUIRED + { + sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #else + { + /* sizeof( int ) == sizeof( long ) so a smaller + printf() library can be used. */ + sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) pxTaskStatusArray[ x ].ulRunTimeCounter ); + } + #endif + } + + pcWriteBuffer += strlen( pcWriteBuffer ); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION + is 0 then vPortFree() will be #defined to nothing. */ + vPortFree( pxTaskStatusArray ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + +#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +/*-----------------------------------------------------------*/ + +TickType_t uxTaskResetEventItemValue( void ) +{ +TickType_t uxReturn; + + uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) ); + + /* Reset the event list item to its normal value - so it can be used with + queues and semaphores. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_MUTEXES == 1 ) + + void *pvTaskIncrementMutexHeldCount( void ) + { + /* If xSemaphoreCreateMutex() is called before any tasks have been created + then pxCurrentTCB will be NULL. */ + if( pxCurrentTCB != NULL ) + { + ( pxCurrentTCB->uxMutexesHeld )++; + } + + return pxCurrentTCB; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) + { + uint32_t ulReturn; + + taskENTER_CRITICAL(); + { + /* Only block if the notification count is not already non-zero. */ + if( pxCurrentTCB->ulNotifiedValue == 0UL ) + { + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_TAKE_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_TAKE(); + ulReturn = pxCurrentTCB->ulNotifiedValue; + + if( ulReturn != 0UL ) + { + if( xClearCountOnExit != pdFALSE ) + { + pxCurrentTCB->ulNotifiedValue = 0UL; + } + else + { + pxCurrentTCB->ulNotifiedValue = ulReturn - 1; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return ulReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) + { + BaseType_t xReturn; + + taskENTER_CRITICAL(); + { + /* Only block if a notification is not already pending. */ + if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED ) + { + /* Clear bits in the task's notification value as bits may get + set by the notifying task or interrupt. This can be used to + clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; + + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); + traceTASK_NOTIFY_WAIT_BLOCK(); + + /* All ports are written to allow a yield in a critical + section (some will yield immediately, others wait until the + critical section exits) - but it is not something that + application code should ever do. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + taskENTER_CRITICAL(); + { + traceTASK_NOTIFY_WAIT(); + + if( pulNotificationValue != NULL ) + { + /* Output the current notification value, which may or may not + have changed. */ + *pulNotificationValue = pxCurrentTCB->ulNotifiedValue; + } + + /* If ucNotifyValue is set then either the task never entered the + blocked state (because a notification was already pending) or the + task unblocked because of a notification. Otherwise the task + unblocked because of a timeout. */ + if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION ) + { + /* A notification was not received. */ + xReturn = pdFALSE; + } + else + { + /* A notification was already pending or a notification was + received while the task was waiting. */ + pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit; + xReturn = pdTRUE; + } + + pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) + { + TCB_t * pxTCB; + BaseType_t xReturn = pdPASS; + uint8_t ucOriginalNotifyState; + + configASSERT( xTaskToNotify ); + pxTCB = ( TCB_t * ) xTaskToNotify; + + taskENTER_CRITICAL(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction: + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + #if( configUSE_TICKLESS_IDLE != 0 ) + { + /* If a task is blocked waiting for a notification then + xNextTaskUnblockTime might be set to the blocked task's time + out time. If the task is unblocked for a reason other than + a timeout xNextTaskUnblockTime is normally left unchanged, + because it will automatically get reset to a new value when + the tick count equals xNextTaskUnblockTime. However if + tickless idling is used it might be more important to enter + sleep mode at the earliest possible time - so reset + xNextTaskUnblockTime here to ensure it is updated at the + earliest possible time. */ + prvResetNextTaskUnblockTime(); + } + #endif + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + BaseType_t xReturn = pdPASS; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( pulPreviousNotificationValue != NULL ) + { + *pulPreviousNotificationValue = pxTCB->ulNotifiedValue; + } + + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + switch( eAction ) + { + case eSetBits : + pxTCB->ulNotifiedValue |= ulValue; + break; + + case eIncrement : + ( pxTCB->ulNotifiedValue )++; + break; + + case eSetValueWithOverwrite : + pxTCB->ulNotifiedValue = ulValue; + break; + + case eSetValueWithoutOverwrite : + if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ) + { + pxTCB->ulNotifiedValue = ulValue; + } + else + { + /* The value could not be written to the task. */ + xReturn = pdFAIL; + } + break; + + case eNoAction : + /* The task is being notified without its notify value being + updated. */ + break; + } + + traceTASK_NOTIFY_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) + { + TCB_t * pxTCB; + uint8_t ucOriginalNotifyState; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( xTaskToNotify ); + + /* RTOS ports that support interrupt nesting have the concept of a + maximum system call (or maximum API call) interrupt priority. + Interrupts that are above the maximum system call priority are keep + permanently enabled, even when the RTOS kernel is in a critical section, + but cannot make any calls to FreeRTOS API functions. If configASSERT() + is defined in FreeRTOSConfig.h then + portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + failure if a FreeRTOS API function is called from an interrupt that has + been assigned a priority above the configured maximum system call + priority. Only FreeRTOS functions that end in FromISR can be called + from interrupts that have been assigned a priority at or (logically) + below the maximum system call interrupt priority. FreeRTOS maintains a + separate interrupt safe API to ensure interrupt entry is as fast and as + simple as possible. More information (albeit Cortex-M specific) is + provided on the following link: + http://www.freertos.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + pxTCB = ( TCB_t * ) xTaskToNotify; + + uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + { + ucOriginalNotifyState = pxTCB->ucNotifyState; + pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; + + /* 'Giving' is equivalent to incrementing a count in a counting + semaphore. */ + ( pxTCB->ulNotifiedValue )++; + + traceTASK_NOTIFY_GIVE_FROM_ISR(); + + /* If the task is in the blocked state specifically to wait for a + notification then unblock it now. */ + if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) + { + /* The task should not have been on an event list. */ + configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL ); + + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) + { + ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + prvAddTaskToReadyList( pxTCB ); + } + else + { + /* The delayed and ready lists cannot be accessed, so hold + this task pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + } + + if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) + { + /* The notified task has a priority above the currently + executing task so a yield is required. */ + if( pxHigherPriorityTaskWoken != NULL ) + { + *pxHigherPriorityTaskWoken = pdTRUE; + } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ + +/*-----------------------------------------------------------*/ + +#if( configUSE_TASK_NOTIFICATIONS == 1 ) + + BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ) + { + TCB_t *pxTCB; + BaseType_t xReturn; + + /* If null is passed in here then it is the calling task that is having + its notification state cleared. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + taskENTER_CRITICAL(); + { + if( pxTCB->ucNotifyState == taskNOTIFICATION_RECEIVED ) + { + pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + } + taskEXIT_CRITICAL(); + + return xReturn; + } + +#endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + + +static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely ) +{ +TickType_t xTimeToWake; +const TickType_t xConstTickCount = xTickCount; + + #if( INCLUDE_xTaskAbortDelay == 1 ) + { + /* About to enter a delayed list, so ensure the ucDelayAborted flag is + reset to pdFALSE so it can be detected as having been set to pdTRUE + when the task leaves the Blocked state. */ + pxCurrentTCB->ucDelayAborted = pdFALSE; + } + #endif + + /* Remove the task from the ready list before adding it to the blocked list + as the same list item is used for both lists. */ + if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ) + { + /* Add the task to the suspended task list instead of a delayed task + list to ensure it is not woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the + kernel will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow + list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list + is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the + head of the list of blocked tasks then xNextTaskUnblockTime + needs to be updated too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be woken if the event + does not occur. This may overflow but this doesn't matter, the kernel + will manage it correctly. */ + xTimeToWake = xConstTickCount + xTicksToWait; + + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); + + if( xTimeToWake < xConstTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + } + else + { + /* The wake time has not overflowed, so the current block list is used. */ + vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + /* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */ + ( void ) xCanBlockIndefinitely; + } + #endif /* INCLUDE_vTaskSuspend */ +} + + +#ifdef FREERTOS_MODULE_TEST + #include "tasks_test_access_functions.h" +#endif + diff --git a/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/timers.c b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/timers.c new file mode 100755 index 0000000..d4a821a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/FreeRTOS/Source/timers.c @@ -0,0 +1,1092 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +#if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 ) + #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. +#endif + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. This #if is closed at the very bottom +of this file. If you want to include software timer functionality then ensure +configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#if ( configUSE_TIMERS == 1 ) + +/* Misc definitions. */ +#define tmrNO_DELAY ( TickType_t ) 0U + +/* The definition of the timers themselves. */ +typedef struct tmrTimerControl +{ + const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ + TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ + UBaseType_t uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one-shot timer. */ + void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ + TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */ + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ + #endif + + #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */ + #endif +} xTIMER; + +/* The old xTIMER name is maintained above then typedefed to the new Timer_t +name below to enable the use of older kernel aware debuggers. */ +typedef xTIMER Timer_t; + +/* The definition of messages that can be sent and received on the timer queue. +Two types of message can be queued - messages that manipulate a software timer, +and messages that request the execution of a non-timer related callback. The +two message types are defined in two separate structures, xTimerParametersType +and xCallbackParametersType respectively. */ +typedef struct tmrTimerParameters +{ + TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ + Timer_t * pxTimer; /*<< The timer to which the command will be applied. */ +} TimerParameter_t; + + +typedef struct tmrCallbackParameters +{ + PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */ + void *pvParameter1; /* << The value that will be used as the callback functions first parameter. */ + uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */ +} CallbackParameters_t; + +/* The structure that contains the two message types, along with an identifier +that is used to determine which message type is valid. */ +typedef struct tmrTimerQueueMessage +{ + BaseType_t xMessageID; /*<< The command being sent to the timer service task. */ + union + { + TimerParameter_t xTimerParameters; + + /* Don't include xCallbackParameters if it is not going to be used as + it makes the structure (and therefore the timer queue) larger. */ + #if ( INCLUDE_xTimerPendFunctionCall == 1 ) + CallbackParameters_t xCallbackParameters; + #endif /* INCLUDE_xTimerPendFunctionCall */ + } u; +} DaemonTaskMessage_t; + +/*lint -e956 A manual analysis and inspection has been used to determine which +static variables must be declared volatile. */ + +/* The list in which active timers are stored. Timers are referenced in expire +time order, with the nearest expiry time at the front of the list. Only the +timer service task is allowed to access these lists. */ +PRIVILEGED_DATA static List_t xActiveTimerList1; +PRIVILEGED_DATA static List_t xActiveTimerList2; +PRIVILEGED_DATA static List_t *pxCurrentTimerList; +PRIVILEGED_DATA static List_t *pxOverflowTimerList; + +/* A queue that is used to send commands to the timer service task. */ +PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; +PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; + +/*lint +e956 */ + +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + /* If static allocation is supported then the application must provide the + following callback function - which enables the application to optionally + provide the memory that will be used by the timer task as the task's stack + and TCB. */ + extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ); + +#endif + +/* + * Initialise the infrastructure used by the timer service task if it has not + * been initialised already. + */ +static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; + +/* + * The timer service task (daemon). Timer functionality is controlled by this + * task. Other tasks communicate with the timer service task using the + * xTimerQueue queue. + */ +static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; + +/* + * Called by the timer service task to interpret and process a command it + * received on the timer queue. + */ +static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; + +/* + * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, + * depending on if the expire time causes a timer counter overflow. + */ +static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; + +/* + * An active timer has reached its expire time. Reload the timer if it is an + * auto reload timer, then call its callback. + */ +static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; + +/* + * The tick count has overflowed. Switch the timer lists after ensuring the + * current timer list does not still reference some timers. + */ +static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION; + +/* + * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE + * if a tick count overflow occurred since prvSampleTimeNow() was last called. + */ +static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; + +/* + * If the timer list contains any active timers then return the expire time of + * the timer that will expire first and set *pxListWasEmpty to false. If the + * timer list does not contain any timers then return 0 and set *pxListWasEmpty + * to pdTRUE. + */ +static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * If a timer has expired, process it. Otherwise, block the timer service task + * until either a timer does expire or a command is received. + */ +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; + +/* + * Called after a Timer_t structure has been allocated either statically or + * dynamically to fill in the structure's members. + */ +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +/*-----------------------------------------------------------*/ + +BaseType_t xTimerCreateTimerTask( void ) +{ +BaseType_t xReturn = pdFAIL; + + /* This function is called when the scheduler is started if + configUSE_TIMERS is set to 1. Check that the infrastructure used by the + timer service task has been created/initialised. If timers have already + been created then the initialisation will already have been performed. */ + prvCheckForValidListAndQueue(); + + if( xTimerQueue != NULL ) + { + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t *pxTimerTaskTCBBuffer = NULL; + StackType_t *pxTimerTaskStackBuffer = NULL; + uint32_t ulTimerTaskStackSize; + + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); + xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, + "Tmr Svc", + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer ); + + if( xTimerTaskHandle != NULL ) + { + xReturn = pdPASS; + } + } + #else + { + xReturn = xTaskCreate( prvTimerTask, + "Tmr Svc", + configTIMER_TASK_STACK_DEPTH, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + &xTimerTaskHandle ); + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + configASSERT( xReturn ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + TimerHandle_t xTimerCreate( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + Timer_t *pxNewTimer; + + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + + if( pxNewTimer != NULL ) + { + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically, so note this + timer was created dynamically in case the timer is later + deleted. */ + pxNewTimer->ucStaticallyAllocated = pdFALSE; + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + + return pxNewTimer; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + { + Timer_t *pxNewTimer; + + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticTimer_t equals the size of the real timer + structures. */ + volatile size_t xSize = sizeof( StaticTimer_t ); + configASSERT( xSize == sizeof( Timer_t ) ); + } + #endif /* configASSERT_DEFINED */ + + /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ + configASSERT( pxTimerBuffer ); + pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + + if( pxNewTimer != NULL ) + { + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + + #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Timers can be created statically or dynamically so note this + timer was created statically in case it is later deleted. */ + pxNewTimer->ucStaticallyAllocated = pdTRUE; + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + } + + return pxNewTimer; + } + +#endif /* configSUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewTimer( const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ + /* 0 is not a valid value for xTimerPeriodInTicks. */ + configASSERT( ( xTimerPeriodInTicks > 0 ) ); + + if( pxNewTimer != NULL ) + { + /* Ensure the infrastructure used by the timer service task has been + created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function + parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->uxAutoReload = uxAutoReload; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + traceTIMER_CREATE( pxNewTimer ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) +{ +BaseType_t xReturn = pdFAIL; +DaemonTaskMessage_t xMessage; + + configASSERT( xTimer ); + + /* Send a message to the timer service task to perform a particular action + on a particular timer definition. */ + if( xTimerQueue != NULL ) + { + /* Send a command to the timer service task to start the xTimer timer. */ + xMessage.xMessageID = xCommandID; + xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; + xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer; + + if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) + { + if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); + } + else + { + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); + } + } + else + { + xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + } + + traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) +{ + /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been + started, then xTimerTaskHandle will be NULL. */ + configASSERT( ( xTimerTaskHandle != NULL ) ); + return xTimerTaskHandle; +} +/*-----------------------------------------------------------*/ + +TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) +{ +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + return pxTimer->xTimerPeriodInTicks; +} +/*-----------------------------------------------------------*/ + +TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) +{ +Timer_t * pxTimer = ( Timer_t * ) xTimer; +TickType_t xReturn; + + configASSERT( xTimer ); + xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +{ +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + return pxTimer->pcTimerName; +} +/*-----------------------------------------------------------*/ + +static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) +{ +BaseType_t xResult; +Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list of active timers. A check has already + been performed to ensure the list is not empty. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* If the timer is an auto reload timer then calculate the next + expiry time and re-insert the timer in the list of active timers. */ + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + /* The timer is inserted into a list using a time relative to anything + other than the current time. It will therefore be inserted into the + correct list relative to the time this task thinks it is now. */ + if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) + { + /* The timer expired before it was added to the active timer + list. Reload it now. */ + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Call the timer callback. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); +} +/*-----------------------------------------------------------*/ + +static void prvTimerTask( void *pvParameters ) +{ +TickType_t xNextExpireTime; +BaseType_t xListWasEmpty; + + /* Just to avoid compiler warnings. */ + ( void ) pvParameters; + + #if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) + { + extern void vApplicationDaemonTaskStartupHook( void ); + + /* Allow the application writer to execute some code in the context of + this task at the point the task starts executing. This is useful if the + application includes initialisation code that would benefit from + executing after the scheduler has been started. */ + vApplicationDaemonTaskStartupHook(); + } + #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */ + + for( ;; ) + { + /* Query the timers list to see if it contains any timers, and if so, + obtain the time at which the next timer will expire. */ + xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); + + /* If a timer has expired, process it. Otherwise, block this task + until either a timer does expire, or a command is received. */ + prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); + + /* Empty the command queue. */ + prvProcessReceivedCommands(); + } +} +/*-----------------------------------------------------------*/ + +static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) +{ +TickType_t xTimeNow; +BaseType_t xTimerListsWereSwitched; + + vTaskSuspendAll(); + { + /* Obtain the time now to make an assessment as to whether the timer + has expired or not. If obtaining the time causes the lists to switch + then don't process this timer as any timers that remained in the list + when the lists were switched will have been processed within the + prvSampleTimeNow() function. */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + if( xTimerListsWereSwitched == pdFALSE ) + { + /* The tick count has not overflowed, has the timer expired? */ + if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) + { + ( void ) xTaskResumeAll(); + prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); + } + else + { + /* The tick count has not overflowed, and the next expire + time has not been reached yet. This task should therefore + block to wait for the next expire time or a command to be + received - whichever comes first. The following line cannot + be reached unless xNextExpireTime > xTimeNow, except in the + case when the current timer list is empty. */ + if( xListWasEmpty != pdFALSE ) + { + /* The current timer list is empty - is the overflow list + also empty? */ + xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList ); + } + + vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); + + if( xTaskResumeAll() == pdFALSE ) + { + /* Yield to wait for either a command to arrive, or the + block time to expire. If a command arrived between the + critical section being exited and this yield then the yield + will not cause the task to block. */ + portYIELD_WITHIN_API(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + } + else + { + ( void ) xTaskResumeAll(); + } + } +} +/*-----------------------------------------------------------*/ + +static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) +{ +TickType_t xNextExpireTime; + + /* Timers are listed in expiry time order, with the head of the list + referencing the task that will expire first. Obtain the time at which + the timer with the nearest expiry time will expire. If there are no + active timers then just set the next expire time to 0. That will cause + this task to unblock when the tick count overflows, at which point the + timer lists will be switched and the next expiry time can be + re-assessed. */ + *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); + if( *pxListWasEmpty == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + } + else + { + /* Ensure the task unblocks when the tick count rolls over. */ + xNextExpireTime = ( TickType_t ) 0U; + } + + return xNextExpireTime; +} +/*-----------------------------------------------------------*/ + +static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) +{ +TickType_t xTimeNow; +PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */ + + xTimeNow = xTaskGetTickCount(); + + if( xTimeNow < xLastTime ) + { + prvSwitchTimerLists(); + *pxTimerListsWereSwitched = pdTRUE; + } + else + { + *pxTimerListsWereSwitched = pdFALSE; + } + + xLastTime = xTimeNow; + + return xTimeNow; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) +{ +BaseType_t xProcessTimerNow = pdFALSE; + + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + + if( xNextExpiryTime <= xTimeNow ) + { + /* Has the expiry time elapsed between the command to start/reset a + timer was issued, and the time the command was processed? */ + if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + { + /* The time between a command being issued and the command being + processed actually exceeds the timers period. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); + } + } + else + { + if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) ) + { + /* If, since the command was issued, the tick count has overflowed + but the expiry time has not, then the timer must have already passed + its expiry time and should be processed immediately. */ + xProcessTimerNow = pdTRUE; + } + else + { + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + } + + return xProcessTimerNow; +} +/*-----------------------------------------------------------*/ + +static void prvProcessReceivedCommands( void ) +{ +DaemonTaskMessage_t xMessage; +Timer_t *pxTimer; +BaseType_t xTimerListsWereSwitched, xResult; +TickType_t xTimeNow; + + while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */ + { + #if ( INCLUDE_xTimerPendFunctionCall == 1 ) + { + /* Negative commands are pended function calls rather than timer + commands. */ + if( xMessage.xMessageID < ( BaseType_t ) 0 ) + { + const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters ); + + /* The timer uses the xCallbackParameters member to request a + callback be executed. Check the callback is not NULL. */ + configASSERT( pxCallback ); + + /* Call the function. */ + pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* INCLUDE_xTimerPendFunctionCall */ + + /* Commands that are positive are timer commands rather than pended + function calls. */ + if( xMessage.xMessageID >= ( BaseType_t ) 0 ) + { + /* The messages uses the xTimerParameters member to work on a + software timer. */ + pxTimer = xMessage.u.xTimerParameters.pxTimer; + + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + { + /* The timer is in a list, remove it. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue ); + + /* In this case the xTimerListsWereSwitched parameter is not used, but + it must be present in the function call. prvSampleTimeNow() must be + called after the message is received from xTimerQueue so there is no + possibility of a higher priority task adding a message to the message + queue with a time that is ahead of the timer daemon task (because it + pre-empted the timer daemon task after the xTimeNow value was set). */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + + switch( xMessage.xMessageID ) + { + case tmrCOMMAND_START : + case tmrCOMMAND_START_FROM_ISR : + case tmrCOMMAND_RESET : + case tmrCOMMAND_RESET_FROM_ISR : + case tmrCOMMAND_START_DONT_TRACE : + /* Start or restart a timer. */ + if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) + { + /* The timer expired before it was added to the active + timer list. Process it now. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); + traceTIMER_EXPIRED( pxTimer ); + + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + break; + + case tmrCOMMAND_STOP : + case tmrCOMMAND_STOP_FROM_ISR : + /* The timer has already been removed from the active list. + There is nothing to do here. */ + break; + + case tmrCOMMAND_CHANGE_PERIOD : + case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR : + pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; + configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); + + /* The new period does not really have a reference, and can + be longer or shorter than the old one. The command time is + therefore set to the current time, and as the period cannot + be zero the next expiry time can only be in the future, + meaning (unlike for the xTimerStart() case above) there is + no fail case that needs to be handled here. */ + ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); + break; + + case tmrCOMMAND_DELETE : + /* The timer has already been removed from the active list, + just free up the memory if the memory was dynamically + allocated. */ + #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + { + /* The timer can only have been allocated dynamically - + free it again. */ + vPortFree( pxTimer ); + } + #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* The timer could have been allocated statically or + dynamically, so check before attempting to free the + memory. */ + if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + { + vPortFree( pxTimer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + break; + + default : + /* Don't expect to get here. */ + break; + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvSwitchTimerLists( void ) +{ +TickType_t xNextExpireTime, xReloadTime; +List_t *pxTemp; +Timer_t *pxTimer; +BaseType_t xResult; + + /* The tick count has overflowed. The timer lists must be switched. + If there are any timers still referenced from the current timer list + then they must have expired and should be processed before the lists + are switched. */ + while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) + { + xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); + + /* Remove the timer from the list. */ + pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + traceTIMER_EXPIRED( pxTimer ); + + /* Execute its callback, then send a command to restart the timer if + it is an auto-reload timer. It cannot be restarted here as the lists + have not yet been switched. */ + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); + + if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + { + /* Calculate the reload value, and if the reload value results in + the timer going into the same timer list then it has already expired + and the timer should be re-inserted into the current list so it is + processed again within this loop. Otherwise a command should be sent + to restart the timer to ensure it is only inserted into a list after + the lists have been swapped. */ + xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); + if( xReloadTime > xNextExpireTime ) + { + listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); + listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); + vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); + } + else + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + pxTemp = pxCurrentTimerList; + pxCurrentTimerList = pxOverflowTimerList; + pxOverflowTimerList = pxTemp; +} +/*-----------------------------------------------------------*/ + +static void prvCheckForValidListAndQueue( void ) +{ + /* Check that the list from which active timers are referenced, and the + queue used to communicate with the timer service, have been + initialised. */ + taskENTER_CRITICAL(); + { + if( xTimerQueue == NULL ) + { + vListInitialise( &xActiveTimerList1 ); + vListInitialise( &xActiveTimerList2 ); + pxCurrentTimerList = &xActiveTimerList1; + pxOverflowTimerList = &xActiveTimerList2; + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + /* The timer queue is allocated statically in case + configSUPPORT_DYNAMIC_ALLOCATION is 0. */ + static StaticQueue_t xStaticTimerQueue; + static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; + + xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); + } + #else + { + xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); + } + #endif + + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + if( xTimerQueue != NULL ) + { + vQueueAddToRegistry( xTimerQueue, "TmrQ" ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configQUEUE_REGISTRY_SIZE */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) +{ +BaseType_t xTimerIsInActiveList; +Timer_t *pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + + /* Is the timer in the list of active timers? */ + taskENTER_CRITICAL(); + { + /* Checking to see if it is in the NULL list in effect checks to see if + it is referenced from either the current or the overflow timer lists in + one go, but the logic has to be reversed, hence the '!'. */ + xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); + } + taskEXIT_CRITICAL(); + + return xTimerIsInActiveList; +} /*lint !e818 Can't be pointer to const due to the typedef. */ +/*-----------------------------------------------------------*/ + +void *pvTimerGetTimerID( const TimerHandle_t xTimer ) +{ +Timer_t * const pxTimer = ( Timer_t * ) xTimer; +void *pvReturn; + + configASSERT( xTimer ); + + taskENTER_CRITICAL(); + { + pvReturn = pxTimer->pvTimerID; + } + taskEXIT_CRITICAL(); + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) +{ +Timer_t * const pxTimer = ( Timer_t * ) xTimer; + + configASSERT( xTimer ); + + taskENTER_CRITICAL(); + { + pxTimer->pvTimerID = pvNewID; + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +#if( INCLUDE_xTimerPendFunctionCall == 1 ) + + BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) + { + DaemonTaskMessage_t xMessage; + BaseType_t xReturn; + + /* Complete the message with the function parameters and post it to the + daemon task. */ + xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR; + xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; + xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; + xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; + + xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + + tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); + + return xReturn; + } + +#endif /* INCLUDE_xTimerPendFunctionCall */ +/*-----------------------------------------------------------*/ + +#if( INCLUDE_xTimerPendFunctionCall == 1 ) + + BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) + { + DaemonTaskMessage_t xMessage; + BaseType_t xReturn; + + /* This function can only be called after a timer has been created or + after the scheduler has been started because, until then, the timer + queue does not exist. */ + configASSERT( xTimerQueue ); + + /* Complete the message with the function parameters and post it to the + daemon task. */ + xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; + xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; + xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; + xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; + + xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); + + tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); + + return xReturn; + } + +#endif /* INCLUDE_xTimerPendFunctionCall */ +/*-----------------------------------------------------------*/ + +/* This entire source file will be skipped if the application is not configured +to include software timer functionality. If you want to include software timer +functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ +#endif /* configUSE_TIMERS == 1 */ + + + diff --git a/src/openmv/src/micropython/ports/cc3200/Makefile b/src/openmv/src/micropython/ports/cc3200/Makefile new file mode 100755 index 0000000..81531b1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/Makefile @@ -0,0 +1,63 @@ +# Select the board to build for: if not given on the command line, +# then default to WIPY +BOARD ?= WIPY +ifeq ($(wildcard boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# Make 'release' the default build type +BTYPE ?= release + +# Port for flashing firmware +PORT ?= /dev/ttyUSB1 + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build/$(BOARD)/$(BTYPE) + +include ../../py/mkenv.mk +-include ../../localconfig.mk + +CROSS_COMPILE ?= arm-none-eabi- + +CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -march=armv7e-m -mabi=aapcs -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion +CFLAGS = -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) -Os +CFLAGS += -g -ffunction-sections -fdata-sections -fno-common -fsigned-char -mno-unaligned-access +CFLAGS += -Iboards/$(BOARD) +CFLAGS += $(CFLAGS_MOD) + +LDFLAGS = -Wl,-nostdlib -Wl,--gc-sections -Wl,-Map=$@.map + +FLASH_SIZE_WIPY = 2M +FLASH_SIZE_LAUNCHXL = 1M + +ifeq ($(BTARGET), application) +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h +# include MicroPython make definitions +include $(TOP)/py/py.mk +include application.mk +else +ifeq ($(BTARGET), bootloader) +include bootmgr/bootloader.mk +else +$(error Invalid BTARGET specified) +endif +endif + +# always include MicroPython make rules +include $(TOP)/py/mkrules.mk + +erase: + cc3200tool -p $(PORT) format_flash --size $(FLASH_SIZE_$(BOARD)) + +deploy: + cc3200tool -p $(PORT) \ + write_file bootmgr/build/$(BOARD)/$(BTYPE)/bootloader.bin /sys/mcuimg.bin \ + write_file build/$(BOARD)/$(BTYPE)/mcuimg.bin /sys/factimg.bin + +# Files *.ucf and *ucf.signed.bin come from CC3200SDK-SERVICEPACK +# package from http://www.ti.com/tool/cc3200sdk +servicepack: + cc3200tool -p $(PORT) \ + write_file --file-size=0x20000 --signature ota_1.0.1.6-2.7.0.0.ucf.signed.bin \ + ota_1.0.1.6-2.7.0.0.ucf /sys/servicepack.ucf diff --git a/src/openmv/src/micropython/ports/cc3200/README.md b/src/openmv/src/micropython/ports/cc3200/README.md new file mode 100755 index 0000000..53cad3b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/README.md @@ -0,0 +1,148 @@ +MicroPython port to CC3200 WiFi SoC +=================================== + +This is a MicroPython port to Texas Instruments CC3200 WiFi SoC (ARM Cortex-M4 +architecture). This port supports 2 boards: WiPy and TI CC3200-LAUNCHXL. + +## Build Instructions for the CC3200 + +Currently the CC3200 port of MicroPython builds under Linux and OSX, +but not under Windows. + +The toolchain required for the build can be found at +. + +In order to flash the image to the CC3200 you will need the +[cc3200tool](https://github.com/ALLTERCO/cc3200tool). An alternative is +to use CCS_Uniflash tool from TI, which works only under Windows, and all +support is provided by TI itself. + +Building the bootloader: + +``` +make BTARGET=bootloader BTYPE=release BOARD=LAUNCHXL +``` + +Building the "release" image: + +``` +make BTARGET=application BTYPE=release BOARD=LAUNCHXL +``` + +To build an image suitable for debugging: + +In order to debug the port specific code, optimizations need to be disabled on the +port file (check the Makefile for specific details). You can use CCS from TI. +Use the CC3200.ccxml file supplied with this distribution for the debuuger configuration. + +``` +make BTARGET=application BTYPE=debug BOARD=LAUNCHXL +``` + +## Flashing the CC3200-LAUNCHXL + +Note that WiPy comes factory programmed with a default version of MicroPython, +it cannot be programmed via serial, and can be upgraded only with OTA (see +below). + +- Make sure that you have built both the *bootloader* and the *application* in **release** mode. +- Make sure the SOP2 jumper is in position. +- Make sure you Linux system recognized the board and created `ttyUSB*` + devices (see below for configuration of `ftdi_sio` driver). +- Run "make erase" and immediately press Reset button on the device. +- Wait few seconds. +- Run "make deploy" and immediately press Reset button on the device. +- You are recommended to install the latest vendor WiFi firmware + servicepack from http://www.ti.com/tool/cc3200sdk. Download + CC3200SDK-SERVICEPACK package, install it, and locate `ota_*.ucf` + and `ota_*.ucf.signed.bin` files. Copy them to the port's directory + and run "make servicepack", with immediate press of Reset button. +- Remove the SOP2 jumper and reset the board. + +Flashing process using TI Uniflash: + +- Open CCS_Uniflash and connect to the board (by default on port 22). +- Format the serial flash (select 1MB size in case of the CC3200-LAUNCHXL, 2MB in case of the WiPy, leave the rest unchecked). +- Mark the following files for erasing: `/cert/ca.pem`, `/cert/client.pem`, `/cert/private.key` and `/tmp/pac.bin`. +- Add a new file with the name of /sys/mcuimg.bin, and select the URL to point to cc3200\bootmgr\build\\bootloader.bin. +- Add another file with the name of /sys/factimg.bin, and select the URL to point to cc3200\build\\mcuimg.bin. +- Click "Program" to apply all changes. +- Flash the latest service pack (servicepack_1.0.0.10.0.bin) using the "Service Pack Update" button. +- Close CCS_Uniflash, remove the SOP2 jumper and reset the board. + +## Playing with MicroPython and the CC3200: + +Once the software is running, you have two options to access the MicroPython REPL: + +- Through telnet. + * Connect to the network created by the board (as boots up in AP mode), **ssid = "wipy-wlan", key = "www.wipy.io"**. + * You can also reinitialize the WLAN in station mode and connect to another AP, or in AP mode but with a + different ssid and/or key. + * Use your favourite telnet client with the following settings: **host = 192.168.1.1, port = 23.** + * Log in with **user = "micro" and password = "python"** + +- Through UART (serial). + * This is enabled by default in the standard configuration, for UART0 (speed 115200). + * For CC3200-LAUNCHXL, you will need to configure Linux `ftdi_sio` driver as described + in the [blog post](http://www.achanceofbrainshowers.com/blog/tech/2014/8/19/cc3200-development-under-linux/). + After that, connecting a board will create two `/dev/ttyUSB*` devices, a serial + console is available on the 2nd one (usually `/dev/ttyUSB1`). + * WiPy doesn't have onboard USB-UART converter, so you will need an external one, + connected to GPIO01 (Tx) and GPIO02 (Rx). + * Usage of UART port for REPL is controlled by MICROPY_STDIO_UART setting (and + is done at the high level, using a suitable call to `os.dupterm()` function + in boot.py, so you can override it at runtime regardless of MICROPY_STDIO_UART + setting). + +The board has a small file system of 192K (WiPy) or 64K (Launchpad) located in the serial flash connected to the CC3200. +SD cards are also supported, you can connect any SD card and configure the pinout using the SD class API. + +## Uploading scripts: + +To upload your MicroPython scripts to the FTP server, open your FTP client of choice and connect to: +**ftp://192.168.1.1, user = "micro", password = "python"** + +Tested FTP clients are: FileZilla, FireFTP, FireFox, IE and Chrome. Other +clients should work as well, but you may need to configure them to use a +single connection (this should be the default for any compliant FTP client). + +## Upgrading the firmware Over The Air (OTA) + +OTA software updates can be performed through the builtin FTP server. After +building a new `mcuimg.bin` in release mode, upload it to: +`/flash/sys/mcuimg.bin`. It will take around 6s (The TI SimpleLink file +system is quite slow because every file is mirrored for safety). You won't +see the file being stored inside `/flash/sys/` because it's actually saved +bypassing FatFS, but rest assured that the file was successfully transferred, +and it has been signed with a MD5 checksum to verify its integrity. +Now, reset the MCU by pressing the switch on the board, or by typing: + +```python +import machine +machine.reset() +``` + +There's a script which automates this process from the host side: + +- Make sure the board is running and connected to the same network as the computer. + +```bash +make BTARGET=application BTYPE=release BOARD=LAUNCHXL WIPY_IP=192.168.1.1 WIPY_USER=micro WIPY_PWD=python deploy-ota +``` + +If `WIPY_IP`, `WIPY_USER` or `WIPY_PWD` are omitted the default values (the ones shown above) will be used. + + +## Notes and known issues + +## Regarding old revisions of the CC3200-LAUNCHXL + +First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and MicroPython cannot run +there. Make sure to use a **v4.1 (or higher) LAUNCHXL board** when trying this port, otherwise it won't work. + +### Note regarding FileZilla + +Do not use the quick connect button, instead, open the site manager and create a new configuration. In the "General" tab make +sure that encryption is set to: "Only use plain FTP (insecure)". In the Transfer Settings tab limit the max number of connections +to one, otherwise FileZilla will try to open a second command connection when retrieving and saving files, and for simplicity and +to reduce code size, only one command and one data connections are possible. diff --git a/src/openmv/src/micropython/ports/cc3200/application.lds b/src/openmv/src/micropython/ports/cc3200/application.lds new file mode 100755 index 0000000..3f5e72f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/application.lds @@ -0,0 +1,116 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +__stack_size__ = 2K; /* interrupts are handled within this stack */ +__min_heap_size__ = 8K; + +MEMORY +{ + SRAMB (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00004000 + SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 0x0003C000 +} + +ENTRY(ResetISR) + +SECTIONS +{ + /* place the FreeRTOS heap (the MicroPython stack will live here) */ + .rtos_heap (NOLOAD) : + { + . = ALIGN(8); + *(.rtos_heap*) + . = ALIGN(8); + } > SRAMB + + .text : + { + _text = .; + KEEP(*(.intvecs)) + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(8); + } > SRAM + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + _etext = .; + } > SRAM + + .data : + { + . = ALIGN(8); + _data = .; + *(.data*) + . = ALIGN(8); + _edata = .; + } > SRAM + + .bss : + { + . = ALIGN(8); + _bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _ebss = .; + } > SRAM + + /* place here functions that are only called during boot up, */ + /* that way, we can re-use this area for the MicroPython heap */ + .boot : + { + . = ALIGN(8); + _boot = .; + *(.boot*) + . = ALIGN(8); + _eboot = .; + } > SRAM + + /* allocate the MicroPython heap */ + .heap : + { + . = ALIGN(8); + _heap = .; + . = . + __min_heap_size__; + . = . + (ORIGIN(SRAM) + LENGTH(SRAM) - __stack_size__ - ABSOLUTE(.)); + . = ALIGN(8); + _eheap = .; + } > SRAM + + /* allocate the main stack */ + .stack ORIGIN(SRAM) + LENGTH(SRAM) - __stack_size__ : + { + . = ALIGN(8); + _stack = .; + . = . + __stack_size__; + . = ALIGN(8); + _estack = .; + } > SRAM +} diff --git a/src/openmv/src/micropython/ports/cc3200/application.mk b/src/openmv/src/micropython/ports/cc3200/application.mk new file mode 100755 index 0000000..19abe66 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/application.mk @@ -0,0 +1,240 @@ +APP_INC = -I. +APP_INC += -I$(TOP) +APP_INC += -Ifatfs/src +APP_INC += -Ifatfs/src/drivers +APP_INC += -IFreeRTOS +APP_INC += -IFreeRTOS/Source/include +APP_INC += -IFreeRTOS/Source/portable/GCC/ARM_CM3 +APP_INC += -Iftp +APP_INC += -Ihal +APP_INC += -Ihal/inc +APP_INC += -Imisc +APP_INC += -Imods +APP_INC += -I$(TOP)/drivers/cc3100/inc +APP_INC += -Isimplelink +APP_INC += -Isimplelink/oslib +APP_INC += -Itelnet +APP_INC += -Iutil +APP_INC += -Ibootmgr +APP_INC += -I$(BUILD) +APP_INC += -I$(BUILD)/genhdr +APP_INC += -I$(TOP)/ports/stm32 + +APP_CPPDEFINES = -Dgcc -DTARGET_IS_CC3200 -DSL_FULL -DUSE_FREERTOS + +APP_FATFS_SRC_C = $(addprefix fatfs/src/,\ + drivers/sflash_diskio.c \ + drivers/sd_diskio.c \ + ) + +APP_RTOS_SRC_C = $(addprefix FreeRTOS/Source/,\ + croutine.c \ + event_groups.c \ + list.c \ + queue.c \ + tasks.c \ + timers.c \ + portable/GCC/ARM_CM3/port.c \ + portable/MemMang/heap_4.c \ + ) + +APP_FTP_SRC_C = $(addprefix ftp/,\ + ftp.c \ + updater.c \ + ) + +APP_HAL_SRC_C = $(addprefix hal/,\ + adc.c \ + aes.c \ + cc3200_hal.c \ + cpu.c \ + crc.c \ + des.c \ + gpio.c \ + i2c.c \ + i2s.c \ + interrupt.c \ + pin.c \ + prcm.c \ + sdhost.c \ + shamd5.c \ + spi.c \ + startup_gcc.c \ + systick.c \ + timer.c \ + uart.c \ + utils.c \ + wdt.c \ + ) + +APP_MISC_SRC_C = $(addprefix misc/,\ + antenna.c \ + FreeRTOSHooks.c \ + help.c \ + mpirq.c \ + mperror.c \ + mpexception.c \ + ) + +APP_MODS_SRC_C = $(addprefix mods/,\ + modmachine.c \ + modnetwork.c \ + modubinascii.c \ + moduos.c \ + modusocket.c \ + modussl.c \ + modutime.c \ + modwipy.c \ + modwlan.c \ + pybadc.c \ + pybpin.c \ + pybi2c.c \ + pybrtc.c \ + pybflash.c \ + pybsd.c \ + pybsleep.c \ + pybspi.c \ + pybtimer.c \ + pybuart.c \ + pybwdt.c \ + ) + +APP_CC3100_SRC_C = $(addprefix drivers/cc3100/src/,\ + device.c \ + driver.c \ + flowcont.c \ + fs.c \ + netapp.c \ + netcfg.c \ + socket.c \ + wlan.c \ + ) + +APP_SL_SRC_C = $(addprefix simplelink/,\ + oslib/osi_freertos.c \ + cc_pal.c \ + ) + +APP_TELNET_SRC_C = $(addprefix telnet/,\ + telnet.c \ + ) + +APP_UTIL_SRC_C = $(addprefix util/,\ + cryptohash.c \ + fifo.c \ + gccollect.c \ + random.c \ + socketfifo.c \ + ) + +APP_UTIL_SRC_S = $(addprefix util/,\ + gchelper.s \ + sleeprestore.s \ + ) + +APP_MAIN_SRC_C = \ + main.c \ + mptask.c \ + mpthreadport.c \ + serverstask.c \ + fatfs_port.c \ + +APP_LIB_SRC_C = $(addprefix lib/,\ + oofatfs/ff.c \ + oofatfs/option/unicode.c \ + libc/string0.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +APP_STM_SRC_C = $(addprefix ports/stm32/,\ + bufhelper.c \ + irq.c \ + ) + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(APP_FATFS_SRC_C:.c=.o) $(APP_RTOS_SRC_C:.c=.o) $(APP_FTP_SRC_C:.c=.o) $(APP_HAL_SRC_C:.c=.o) $(APP_MISC_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(APP_MODS_SRC_C:.c=.o) $(APP_CC3100_SRC_C:.c=.o) $(APP_SL_SRC_C:.c=.o) $(APP_TELNET_SRC_C:.c=.o) $(APP_UTIL_SRC_C:.c=.o) $(APP_UTIL_SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(APP_MAIN_SRC_C:.c=.o) $(APP_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o)) +OBJ += $(BUILD)/pins.o + +# List of sources for qstr extraction +SRC_QSTR += $(APP_MODS_SRC_C) $(APP_MISC_SRC_C) $(APP_STM_SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +# Add the linker script +LINKER_SCRIPT = application.lds +LDFLAGS += -T $(LINKER_SCRIPT) + +# Add the application specific CFLAGS +CFLAGS += $(APP_CPPDEFINES) $(APP_INC) + +# Disable strict aliasing for the simplelink driver +$(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing + +# Check if we would like to debug the port code +ifeq ($(BTYPE), release) +CFLAGS += -DNDEBUG +else +ifeq ($(BTYPE), debug) +CFLAGS += -DNDEBUG +else +$(error Invalid BTYPE specified) +endif +endif + +SHELL = bash +APP_SIGN = appsign.sh +UPDATE_WIPY ?= tools/update-wipy.py +WIPY_IP ?= '192.168.1.1' +WIPY_USER ?= 'micro' +WIPY_PWD ?= 'python' + +all: $(BUILD)/mcuimg.bin + +.PHONY: deploy-ota + +deploy-ota: $(BUILD)/mcuimg.bin + $(ECHO) "Writing $< to the board" + $(Q)$(PYTHON) $(UPDATE_WIPY) --verify --ip $(WIPY_IP) --user $(WIPY_USER) --password $(WIPY_PWD) --file $< + +$(BUILD)/application.axf: $(OBJ) $(LINKER_SCRIPT) + $(ECHO) "LINK $@" + $(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/application.bin: $(BUILD)/application.axf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +$(BUILD)/mcuimg.bin: $(BUILD)/application.bin + $(ECHO) "Create $@" + $(Q)$(SHELL) $(APP_SIGN) $(BUILD) + +MAKE_PINS = boards/make-pins.py +BOARD_PINS = boards/$(BOARD)/pins.csv +AF_FILE = boards/cc3200_af.csv +PREFIX_FILE = boards/cc3200_prefix.c +GEN_PINS_SRC = $(BUILD)/pins.c +GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(BUILD)/pins_qstr.h + +# Making OBJ use an order-only dependency on the generated pins.h file +# has the side effect of making the pins.h file before we actually compile +# any of the objects. The normal dependency generation will deal with the +# case when pins.h is modified. But when it doesn't exist, we don't know +# which source files might need it. +$(OBJ): | $(GEN_PINS_HDR) + +# Call make-pins.py to generate both pins_gen.c and pins.h +$(GEN_PINS_SRC) $(GEN_PINS_HDR) $(GEN_PINS_QSTR): $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) > $(GEN_PINS_SRC) + +$(BUILD)/pins.o: $(BUILD)/pins.c + $(call compile_c) diff --git a/src/openmv/src/micropython/ports/cc3200/appsign.sh b/src/openmv/src/micropython/ports/cc3200/appsign.sh new file mode 100755 index 0000000..5752b40 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/appsign.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ "$#" -ne 1 ]; then + echo "Usage: appsign.sh *build dir*" + exit 1 +fi + +# Build location +BUILD=$1 + +# Generate the MD5 hash +# md5 on Darwin, md5sum on Unix +if [ `uname -s` = "Darwin" ]; then +echo -n `md5 -q $BUILD/application.bin` > __md5hash.bin +else +echo -n `md5sum --binary $BUILD/application.bin | awk '{ print $1 }'` > __md5hash.bin +fi + +# Concatenate it with the application binary +cat $BUILD/application.bin __md5hash.bin > $BUILD/mcuimg.bin +RET=$? + +# Remove the tmp files +rm -f __md5hash.bin + +# Remove the unsigned binary +rm -f $BUILD/application.bin + +exit $RET diff --git a/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/mpconfigboard.h b/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/mpconfigboard.h new file mode 100755 index 0000000..b3d766d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/mpconfigboard.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define LAUNCHXL + +#define MICROPY_HW_BOARD_NAME "LaunchPad" +#define MICROPY_HW_MCU_NAME "CC3200" + +#define MICROPY_HW_ANTENNA_DIVERSITY (0) + +#define MICROPY_STDIO_UART 1 +#define MICROPY_STDIO_UART_BAUD 115200 + +#define MICROPY_SYS_LED_PRCM PRCM_GPIOA1 +#define MICROPY_SAFE_BOOT_PRCM PRCM_GPIOA2 +#define MICROPY_SYS_LED_PORT GPIOA1_BASE +#define MICROPY_SAFE_BOOT_PORT GPIOA2_BASE +#define MICROPY_SYS_LED_GPIO pin_GP9 +#define MICROPY_SYS_LED_PIN_NUM PIN_64 // GP9 +#define MICROPY_SAFE_BOOT_PIN_NUM PIN_15 // GP22 +#define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1 +#define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_6 + +#define MICROPY_PORT_SFLASH_BLOCK_COUNT 32 + diff --git a/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/pins.csv b/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/pins.csv new file mode 100755 index 0000000..38071e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/LAUNCHXL/pins.csv @@ -0,0 +1,25 @@ +P12,58 +P13,4 +P14,3 +P15,61 +P16,59 +P17,5 +P18,62 +P19,1 +P110,2 +P33,57 +P34,60 +P37,63 +P38,53 +P39,64 +P310,50 +P49,16 +P410,17 +P22,18 +P23,8 +P24,45 +P26,7 +P27,6 +P28,21 +P29,55 +P210,15 \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/cc3200/boards/WIPY/mpconfigboard.h b/src/openmv/src/micropython/ports/cc3200/boards/WIPY/mpconfigboard.h new file mode 100755 index 0000000..af15cca --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/WIPY/mpconfigboard.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define WIPY + +#define MICROPY_HW_BOARD_NAME "WiPy" +#define MICROPY_HW_MCU_NAME "CC3200" + +#define MICROPY_HW_ANTENNA_DIVERSITY (1) + +#define MICROPY_STDIO_UART 1 +#define MICROPY_STDIO_UART_BAUD 115200 + +#define MICROPY_SYS_LED_PRCM PRCM_GPIOA3 +#define MICROPY_SAFE_BOOT_PRCM PRCM_GPIOA3 +#define MICROPY_SYS_LED_PORT GPIOA3_BASE +#define MICROPY_SAFE_BOOT_PORT GPIOA3_BASE +#define MICROPY_SYS_LED_GPIO pin_GP25 +#define MICROPY_SYS_LED_PIN_NUM PIN_21 // GP25 (SOP2) +#define MICROPY_SAFE_BOOT_PIN_NUM PIN_18 // GP28 +#define MICROPY_SYS_LED_PORT_PIN GPIO_PIN_1 +#define MICROPY_SAFE_BOOT_PORT_PIN GPIO_PIN_4 + +#define MICROPY_PORT_SFLASH_BLOCK_COUNT 96 diff --git a/src/openmv/src/micropython/ports/cc3200/boards/WIPY/pins.csv b/src/openmv/src/micropython/ports/cc3200/boards/WIPY/pins.csv new file mode 100755 index 0000000..c4e4376 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/WIPY/pins.csv @@ -0,0 +1,25 @@ +L2,GP2 +L3,GP1 +L4,GP23 +L5,GP24 +L6,GP11 +L7,GP12 +L8,GP13 +L9,GP14 +L10,GP15 +L11,GP16 +L12,GP17 +L13,GP22 +L14,GP28 +R4,GP10 +R5,GP9 +R6,GP8 +R7,GP7 +R8,GP6 +R9,GP30 +R10,GP31 +R11,GP3 +R12,GP0 +R13,GP4 +R14,GP5 +HBL,GP25 diff --git a/src/openmv/src/micropython/ports/cc3200/boards/cc3200_af.csv b/src/openmv/src/micropython/ports/cc3200/boards/cc3200_af.csv new file mode 100755 index 0000000..a93cb54 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/cc3200_af.csv @@ -0,0 +1,66 @@ +Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,ADC +1,GP10,GP10,GP10,I2C0_SCL,,TIM3_PWM,,,SD0_CLK,UART1_TX,,,,,TIM0_CC,,,, +2,GP11,GP11,GP11,I2C0_SDA,,TIM3_PWM,pXCLK(XVCLK),,SD0_CMD,UART1_RX,,,,,TIM1_CC,I2S0_FS,,, +3,GP12,GP12,GP12,,,I2S0_CLK,pVS(VSYNC),I2C0_SCL,,UART0_TX,,,,,TIM1_CC,,,, +4,GP13,GP13,GP13,,,,pHS(HSYNC),I2C0_SDA,,UART0_RX,,,,,TIM2_CC,,,, +5,GP14,GP14,GP14,,,,pDATA8(CAM_D4),I2C0_SCL,,SPI0_CLK,,,,,TIM2_CC,,,, +6,GP15,GP15,GP15,,,,pDATA9(CAM_D5),I2C0_SDA,,SPI0_MISO,SD0_DAT0,,,,,TIM3_CC,,, +7,GP16,GP16,GP16,,,,pDATA10(CAM_D6),UART1_TX,,SPI0_MOSI,SD0_CLK,,,,,TIM3_CC,,, +8,GP17,GP17,GP17,,,,pDATA11(CAM_D7),UART1_RX,,SPI0_CS0,SD0_CMD,,,,,,,, +9,VDD_DIG1,VDD_DIG1,VDD_DIG1,,,,,,,,,,,,,,,, +10,VIN_IO1,VIN_IO1,VIN_IO1,,,,,,,,,,,,,,,, +11,FLASH_SPI_CLK,FLASH_SPI_CLK,FLASH_SPI_CLK,,,,,,,,,,,,,,,, +12,FLASH_SPI_DOUT,FLASH_SPI_DOUT,FLASH_SPI_DOUT,,,,,,,,,,,,,,,, +13,FLASH_SPI_DIN,FLASH_SPI_DIN,FLASH_SPI_DIN,,,,,,,,,,,,,,,, +14,FLASH_SPI_CS,FLASH_SPI_CS,FLASH_SPI_CS,,,,,,,,,,,,,,,, +15,GP22,GP22,GP22,,,,,TIM2_CC,,I2S0_FS,,,,,,,,, +16,GP23,TDI,GP23,TDI,UART1_TX,,,,,,,I2C0_SCL,,,,,,, +17,GP24,TDO,GP24,TDO,UART1_RX,,TIM3_CC,TIM0_PWM,I2S0_FS,,,I2C0_SDA,,,,,,, +18,GP28,GP28,GP28,,,,,,,,,,,,,,,, +19,TCK,TCK,,TCK,,,,,,,TIM1_PWM,,,,,,,, +20,GP29,TMS,GP29,TMS,,,,,,,,,,,,,,, +21,GP25,SOP2,GP25,,I2S0_FS,,,,,,,TIM1_PWM,,,,,,, +22,WLAN_XTAL_N,WLAN_XTAL_N,WLAN_XTAL_N,,,,,,,,,,,,,,,, +23,WLAN_XTAL_P,WLAN_XTAL_P,WLAN_XTAL_P,,,,,,,,,,,,,,,, +24,VDD_PLL,VDD_PLL,VDD_PLL,,,,,,,,,,,,,,,, +25,LDO_IN2,LDO_IN2,LDO_IN2,,,,,,,,,,,,,,,, +26,NC,NC,NC,,,,,,,,,,,,,,,, +27,NC,NC,NC,,,,,,,,,,,,,,,, +28,NC,NC,NC,,,,,,,,,,,,,,,, +29,ANTSEL1,ANTSEL1,ANTSEL1,,,,,,,,,,,,,,,, +30,ANTSEL2,ANTSEL2,ANTSEL2,,,,,,,,,,,,,,,, +31,RF_BG,RF_BG,RF_BG,,,,,,,,,,,,,,,, +32,nRESET,nRESET,nRESET,,,,,,,,,,,,,,,, +33,VDD_PA_IN,VDD_PA_IN,VDD_PA_IN,,,,,,,,,,,,,,,, +34,SOP1,SOP1,SOP1,,,,,,,,,,,,,,,, +35,SOP0,SOP0,SOP0,,,,,,,,,,,,,,,, +36,LDO_IN1,LDO_IN1,LDO_IN1,,,,,,,,,,,,,,,, +37,VIN_DCDC_ANA,VIN_DCDC_ANA,VIN_DCDC_ANA,,,,,,,,,,,,,,,, +38,DCDC_ANA_SW,DCDC_ANA_SW,DCDC_ANA_SW,,,,,,,,,,,,,,,, +39,VIN_DCDC_PA,VIN_DCDC_ PA,VIN_DCDC_PA,,,,,,,,,,,,,,,, +40,DCDC_PA_SW_P,DCDC_PA_SW_P,DCDC_PA_SW_P,,,,,,,,,,,,,,,, +41,DCDC_PA_SW_N,DCDC_PA_SW_N,DCDC_PA_SW_N,,,,,,,,,,,,,,,, +42,DCDC_PA_OUT,DCDC_PA_O UT,DCDC_PA_O UT,,,,,,,,,,,,,,,, +43,DCDC_DIG_SW,DCDC_DIG_ SW,DCDC_DIG_ SW,,,,,,,,,,,,,,,, +44,VIN_DCDC_DIG,VIN_DCDC_ DIG,VIN_DCDC_ DIG,,,,,,,,,,,,,,,, +45,GP31,DCDC_ANA2_SW_P,GP31,,UART1_RX,,,,I2S0_DAT0,SPI0_CLK,,UART0_RX,,,I2S0_FS,,,, +46,DCDC_ANA2_SW_N,DCDC_ANA2_SW_N,DCDC_ANA2_SW_N,,,,,,,,,,,,,,,, +47,VDD_ANA2,VDD_ANA2,VDD_ANA2,,,,,,,,,,,,,,,, +48,VDD_ANA1,VDD_ANA1,VDD_ANA1,,,,,,,,,,,,,,,, +49,VDD_RAM,VDD_RAM,VDD_RAM,,,,,,,,,,,,,,,, +50,GP0,GP0,GP0,,,UART0_RTS,I2S0_DAT0,,I2S0_DAT1,TIM0_CC,,SPI0_CS0,UART1_RTS,,UART0_CTS,,,, +51,RTC_XTAL_P,RTC_XTAL_P,RTC_XTAL_P,,,,,,,,,,,,,,,, +52,RTC_XTAL_N,RTC_XTAL_N,GP32,,I2S0_CLK,,I2S0_DAT0,,UART0_RTS,,SPI0_MOSI,,,,,,,, +53,GP30,GP30,GP30,,I2S0_CLK,I2S0_FS,TIM2_CC,,,SPI0_MISO,,UART0_TX,,,,,,, +54,VIN_IO2,VIN_IO2,VIN_IO2,,,,,,,,,,,,,,,, +55,GP1,GP1,GP1,,,UART0_TX,pCLK (PIXCLK),,UART1_TX,TIM0_CC,,,,,,,,, +56,VDD_DIG2,VDD_DIG2,VDD_DIG2,,,,,,,,,,,,,,,, +57,GP2,GP2,GP2,,,UART0_RX,,,UART1_RX,TIM1_CC,,,,,,,,,ADC0_CH0 +58,GP3,GP3,GP3,,,,pDATA7(CAM_D3),,UART1_TX,,,,,,,,,,ADC0_CH1 +59,GP4,GP4,GP4,,,,pDATA6(CAM_D2),,UART1_RX,,,,,,,,,,ADC0_CH2 +60,GP5,GP5,GP5,,,,pDATA5(CAM_D1),,I2S0_DAT1,TIM2_CC,,,,,,,,,ADC0_CH3 +61,GP6,GP6,GP6,,,UART1_CTS,pDATA4(CAM_D0),UART0_RTS,UART0_CTS,TIM3_CC,,,,,,,,, +62,GP7,GP7,GP7,,,UART1_RTS,,,,,,,UART0_RTS,UART0_TX,,I2S0_CLK,,, +63,GP8,GP8,GP8,,,,,,SD0_IRQ,I2S0_FS,,,,,TIM3_CC,,,, +64,GP9,GP9,GP9,,,TIM2_PWM,,,SD0_DAT0,I2S0_DAT0,,,,,TIM0_CC,,,, +65,GND_TAB,GND_TAB,GND_TAB,,,,,,,,,,,,,,,, diff --git a/src/openmv/src/micropython/ports/cc3200/boards/cc3200_prefix.c b/src/openmv/src/micropython/ports/cc3200/boards/cc3200_prefix.c new file mode 100755 index 0000000..d03efe0 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/cc3200_prefix.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// cc3200_prefix.c becomes the initial portion of the generated pins file. + +#include +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "pin.h" +#include "gpio.h" +#include "pybpin.h" + + +#define AF(af_name, af_idx, af_fn, af_unit, af_type) \ +{ \ + .name = MP_QSTR_ ## af_name, \ + .idx = (af_idx), \ + .fn = PIN_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = PIN_TYPE_ ## af_fn ## _ ## af_type, \ +} + + +#define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_ ## p_pin_name, \ + .port = PORT_A ## p_port, \ + .af_list = (p_af_list), \ + .pull = PIN_TYPE_STD, \ + .bit = (p_bit), \ + .pin_num = (p_pin_num), \ + .af = PIN_MODE_0, \ + .strength = PIN_STRENGTH_4MA, \ + .mode = GPIO_DIR_MODE_IN, \ + .num_afs = (p_num_afs), \ + .value = 0, \ + .used = false, \ + .irq_trigger = 0, \ + .irq_flags = 0, \ +} diff --git a/src/openmv/src/micropython/ports/cc3200/boards/make-pins.py b/src/openmv/src/micropython/ports/cc3200/boards/make-pins.py new file mode 100755 index 0000000..30db4ac --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/boards/make-pins.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python +"""Generates the pins file for the CC3200.""" + +from __future__ import print_function + +import argparse +import sys +import csv + + +SUPPORTED_AFS = { 'UART': ('TX', 'RX', 'RTS', 'CTS'), + 'SPI': ('CLK', 'MOSI', 'MISO', 'CS0'), + #'I2S': ('CLK', 'FS', 'DAT0', 'DAT1'), + 'I2C': ('SDA', 'SCL'), + 'TIM': ('PWM'), + 'SD': ('CLK', 'CMD', 'DAT0'), + 'ADC': ('CH0', 'CH1', 'CH2', 'CH3') + } + +def parse_port_pin(name_str): + """Parses a string and returns a (port, gpio_bit) tuple.""" + if len(name_str) < 3: + raise ValueError("Expecting pin name to be at least 3 characters") + if name_str[:2] != 'GP': + raise ValueError("Expecting pin name to start with GP") + if not name_str[2:].isdigit(): + raise ValueError("Expecting numeric GPIO number") + port = int(int(name_str[2:]) / 8) + gpio_bit = 1 << int(int(name_str[2:]) % 8) + return (port, gpio_bit) + + +class AF: + """Holds the description of an alternate function""" + def __init__(self, name, idx, fn, unit, type): + self.name = name + self.idx = idx + if self.idx > 15: + self.idx = -1 + self.fn = fn + self.unit = unit + self.type = type + + def print(self): + print (' AF({:16s}, {:4d}, {:8s}, {:4d}, {:8s}), // {}'.format(self.name, self.idx, self.fn, self.unit, self.type, self.name)) + + +class Pin: + """Holds the information associated with a pin.""" + def __init__(self, name, port, gpio_bit, pin_num): + self.name = name + self.port = port + self.gpio_bit = gpio_bit + self.pin_num = pin_num + self.board_pin = False + self.afs = [] + + def add_af(self, af): + self.afs.append(af) + + def print(self): + print('// {}'.format(self.name)) + if len(self.afs): + print('const pin_af_t pin_{}_af[] = {{'.format(self.name)) + for af in self.afs: + af.print() + print('};') + print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, pin_{}_af, {});\n'.format( + self.name, self.name, self.port, self.gpio_bit, self.pin_num, self.name, len(self.afs))) + else: + print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, NULL, 0);\n'.format( + self.name, self.name, self.port, self.gpio_bit, self.pin_num)) + + def print_header(self, hdr_file): + hdr_file.write('extern pin_obj_t pin_{:s};\n'.format(self.name)) + + +class Pins: + def __init__(self): + self.board_pins = [] # list of pin objects + + def find_pin(self, port, gpio_bit): + for pin in self.board_pins: + if pin.port == port and pin.gpio_bit == gpio_bit: + return pin + + def find_pin_by_num(self, pin_num): + for pin in self.board_pins: + if pin.pin_num == pin_num: + return pin + + def find_pin_by_name(self, name): + for pin in self.board_pins: + if pin.name == name: + return pin + + def parse_af_file(self, filename, pin_col, pinname_col, af_start_col): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, gpio_bit) = parse_port_pin(row[pinname_col]) + except: + continue + if not row[pin_col].isdigit(): + raise ValueError("Invalid pin number {:s} in row {:s}".format(row[pin_col]), row) + # Pin numbers must start from 0 when used with the TI API + pin_num = int(row[pin_col]) - 1; + pin = Pin(row[pinname_col], port_num, gpio_bit, pin_num) + self.board_pins.append(pin) + af_idx = 0 + for af in row[af_start_col:]: + af_splitted = af.split('_') + fn_name = af_splitted[0].rstrip('0123456789') + if fn_name in SUPPORTED_AFS: + type_name = af_splitted[1] + if type_name in SUPPORTED_AFS[fn_name]: + unit_idx = af_splitted[0][-1] + pin.add_af(AF(af, af_idx, fn_name, int(unit_idx), type_name)) + af_idx += 1 + + def parse_board_file(self, filename, cpu_pin_col): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + # Pin numbers must start from 0 when used with the TI API + if row[cpu_pin_col].isdigit(): + pin = self.find_pin_by_num(int(row[cpu_pin_col]) - 1) + else: + pin = self.find_pin_by_name(row[cpu_pin_col]) + if pin: + pin.board_pin = True + + def print_named(self, label, pins): + print('') + print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) + for pin in pins: + if pin.board_pin: + print(' {{ MP_ROM_QSTR(MP_QSTR_{:6s}), MP_ROM_PTR(&pin_{:6s}) }},'.format(pin.name, pin.name)) + print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); + + def print(self): + for pin in self.board_pins: + if pin.board_pin: + pin.print() + self.print_named('board', self.board_pins) + print('') + + def print_header(self, hdr_filename): + with open(hdr_filename, 'wt') as hdr_file: + for pin in self.board_pins: + if pin.board_pin: + pin.print_header(hdr_file) + + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + pin_qstr_set = set([]) + af_qstr_set = set([]) + for pin in self.board_pins: + if pin.board_pin: + pin_qstr_set |= set([pin.name]) + for af in pin.afs: + af_qstr_set |= set([af.name]) + print('// Board pins', file=qstr_file) + for qstr in sorted(pin_qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + print('\n// Pin AFs', file=qstr_file) + for qstr in sorted(af_qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file" + ) + parser.add_argument( + "-a", "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="cc3200_af.csv" + ) + parser.add_argument( + "-b", "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="cc3200_prefix.c" + ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins_qstr.h" + ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print('// This file was automatically generated by make-pins.py') + print('//') + if args.af_filename: + print('// --af {:s}'.format(args.af_filename)) + pins.parse_af_file(args.af_filename, 0, 1, 3) + + if args.board_filename: + print('// --board {:s}'.format(args.board_filename)) + pins.parse_board_file(args.board_filename, 1) + + if args.prefix_filename: + print('// --prefix {:s}'.format(args.prefix_filename)) + print('') + with open(args.prefix_filename, 'r') as prefix_file: + print(prefix_file.read()) + pins.print() + pins.print_qstr(args.qstr_filename) + pins.print_header(args.hdr_filename) + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/bootgen.sh b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootgen.sh new file mode 100755 index 0000000..f4bf325 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootgen.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +if [ "$#" -ne 1 ]; then + echo "Usage: bootgen.sh *build dir*" + exit 1 +fi + +BUILD=$1 + +# Re-locator Path +RELOCATOR=bootmgr/relocator + +# Build location +BOOTMGR=${BUILD} + +# Check for re-locator binary +if [ ! -f $RELOCATOR/relocator.bin ]; then + + echo "Error : Relocator Not found!" + exit 1 +else + echo "Relocator found..." +fi + +# Check for boot manager binary +if [ ! -f $BOOTMGR/bootmgr.bin ]; then + + echo "Error : Boot Manager Not found!" + exit 1 +else + echo "Boot Manager found..." +fi + +# echo +echo "Generating bootloader..." + +# Generate an all 0 bin file +dd if=/dev/zero of=__tmp.bin ibs=1 count=256 conv=notrunc >/dev/null 2>&1 + +# Generate a 0 padded version of the relocator +dd if=$RELOCATOR/relocator.bin of=__tmp.bin ibs=1 conv=notrunc >/dev/null 2>&1 + +# Concatenate the re-locator and the boot-manager +cat __tmp.bin $BOOTMGR/bootmgr.bin > $BOOTMGR/bootloader.bin + +# Remove the tmp files +rm -f __tmp.bin + +# Remove bootmgr.bin +rm -f $BOOTMGR/bootmgr.bin diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/bootloader.mk b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootloader.mk new file mode 100755 index 0000000..44f1b7f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootloader.mk @@ -0,0 +1,132 @@ +BUILD = bootmgr/build/$(BOARD)/$(BTYPE) + +BOOT_INC = -Ibootmgr +BOOT_INC += -Ibootmgr/sl +BOOT_INC += -Ihal +BOOT_INC += -Ihal/inc +BOOT_INC += -I$(TOP)/drivers/cc3100/inc +BOOT_INC += -Imisc +BOOT_INC += -Imods +BOOT_INC += -Isimplelink +BOOT_INC += -Isimplelink/oslib +BOOT_INC += -Iutil +BOOT_INC += -I$(TOP) +BOOT_INC += -I. +BOOT_INC += -I$(BUILD) + +BOOT_CPPDEFINES = -Dgcc -DBOOTLOADER -DTARGET_IS_CC3200 -DSL_TINY + +BOOT_HAL_SRC_C = $(addprefix hal/,\ + cpu.c \ + interrupt.c \ + gpio.c \ + pin.c \ + prcm.c \ + shamd5.c \ + spi.c \ + startup_gcc.c \ + systick.c \ + utils.c \ + ) + +BOOT_CC3100_SRC_C = $(addprefix drivers/cc3100/,\ + src/device.c \ + src/driver.c \ + src/flowcont.c \ + src/fs.c \ + src/netapp.c \ + src/netcfg.c \ + src/nonos.c \ + src/socket.c \ + src/spawn.c \ + src/wlan.c \ + ) + +BOOT_MISC_SRC_C = $(addprefix misc/,\ + antenna.c \ + mperror.c \ + ) + +BOOT_SL_SRC_C = $(addprefix simplelink/,\ + cc_pal.c \ + ) + +BOOT_UTIL_SRC_C = $(addprefix util/,\ + cryptohash.c \ + ) + +BOOT_MAIN_SRC_C = \ + bootmgr/main.c + +BOOT_MAIN_SRC_S = \ + bootmgr/runapp.s + +BOOT_PY_SRC_C = $(addprefix py/,\ + mpprint.c \ + ) + +BOOT_LIB_SRC_C = $(addprefix lib/,\ + libc/string0.c \ + utils/printf.c \ + ) + +OBJ = $(addprefix $(BUILD)/, $(BOOT_HAL_SRC_C:.c=.o) $(BOOT_SL_SRC_C:.c=.o) $(BOOT_CC3100_SRC_C:.c=.o) $(BOOT_UTIL_SRC_C:.c=.o) $(BOOT_MISC_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(BOOT_MAIN_SRC_C:.c=.o) $(BOOT_MAIN_SRC_S:.s=.o) $(BOOT_PY_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(BOOT_LIB_SRC_C:.c=.o)) + +# Add the linker script +LINKER_SCRIPT = bootmgr/bootmgr.lds +LDFLAGS += -T $(LINKER_SCRIPT) + +# Add the bootloader specific CFLAGS +CFLAGS += $(BOOT_CPPDEFINES) $(BOOT_INC) + +# Disable strict aliasing for the simplelink driver +$(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing + +# Check if we would like to debug the port code +ifeq ($(BTYPE), release) +# Optimize everything and define the NDEBUG flag +CFLAGS += -Os -DNDEBUG +else +ifeq ($(BTYPE), debug) +# Define the DEBUG flag +CFLAGS += -DDEBUG=DEBUG +# Optimize the stable sources only +$(BUILD)/hal/%.o: CFLAGS += -Os +$(BUILD)/misc/%.o: CFLAGS += -Os +$(BUILD)/simplelink/%.o: CFLAGS += -Os +$(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os +$(BUILD)/py/%.o: CFLAGS += -Os +$(BUILD)/ports/stm32/%.o: CFLAGS += -Os +else +$(error Invalid BTYPE specified) +endif +endif + +SHELL = bash +BOOT_GEN = bootmgr/bootgen.sh +HEADER_BUILD = $(BUILD)/genhdr + +all: $(BUILD)/bootloader.bin + +$(BUILD)/bootmgr.axf: $(OBJ) $(LINKER_SCRIPT) + $(ECHO) "LINK $@" + $(Q)$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/bootmgr.bin: $(BUILD)/bootmgr.axf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +$(BUILD)/bootloader.bin: $(BUILD)/bootmgr.bin + $(ECHO) "Create $@" + $(Q)$(SHELL) $(BOOT_GEN) $(BUILD) + +# Create an empty "qstrdefs.generated.h" needed by py/mkrules.mk +$(HEADER_BUILD)/qstrdefs.generated.h: | $(HEADER_BUILD) + touch $@ + +# Create an empty "mpversion.h" needed by py/mkrules.mk +$(HEADER_BUILD)/mpversion.h: | $(HEADER_BUILD) + touch $@ diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.h b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.h new file mode 100755 index 0000000..5a370f8 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_BOOTMGR_BOOTMGR_H +#define MICROPY_INCLUDED_CC3200_BOOTMGR_BOOTMGR_H + +//**************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//**************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// User image tokens +//***************************************************************************** +#define FACTORY_IMG_TOKEN 0x5555AAAA +#define UPDATE_IMG_TOKEN 0xAA5555AA +#define USER_BOOT_INFO_TOKEN 0xA5A55A5A + +//***************************************************************************** +// Macros +//***************************************************************************** +#define APP_IMG_SRAM_OFFSET 0x20004000 +#define DEVICE_IS_CC3101RS 0x18 +#define DEVICE_IS_CC3101S 0x1B + +//***************************************************************************** +// Function prototype +//***************************************************************************** +extern void Run(unsigned long); + +//**************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//**************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // MICROPY_INCLUDED_CC3200_BOOTMGR_BOOTMGR_H diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.lds b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.lds new file mode 100755 index 0000000..9c911a0 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/bootmgr.lds @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +__stack_size__ = 1024; + +MEMORY +{ + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00004000 +} + +ENTRY(ResetISR) + +SECTIONS +{ + .text : + { + _text = .; + KEEP(*(.intvecs)) + *(.boot*) + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(8); + } > SRAM + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + _etext = .; + } > SRAM + + .data : + { + _data = .; + *(.data*) + . = ALIGN (8); + _edata = .; + } > SRAM + + .bss : + { + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > SRAM + + .stack ORIGIN(SRAM) + LENGTH(SRAM) - __stack_size__ : + { + . = ALIGN(8); + _stack = .; + . = . + __stack_size__; + . = ALIGN(8); + _estack = .; + } > SRAM +} + diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/flc.h b/src/openmv/src/micropython/ports/cc3200/bootmgr/flc.h new file mode 100755 index 0000000..8f05bb3 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/flc.h @@ -0,0 +1,95 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_BOOTMGR_FLC_H +#define MICROPY_INCLUDED_CC3200_BOOTMGR_FLC_H + +/****************************************************************************** + + If building with a C++ compiler, make all of the definitions in this header + have a C binding. + +*******************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** + Image file names +*******************************************************************************/ +#define IMG_BOOT_INFO "/sys/bootinfo.bin" +#define IMG_FACTORY "/sys/factimg.bin" +#define IMG_UPDATE1 "/sys/updtimg1.bin" +#define IMG_UPDATE2 "/sys/updtimg2.bin" +#define IMG_PREFIX "/sys/updtimg" + +#define IMG_SRVPACK "/sys/servicepack.ucf" +#define SRVPACK_SIGN "/sys/servicepack.sig" + +#define CA_FILE "/cert/ca.pem" +#define CERT_FILE "/cert/cert.pem" +#define KEY_FILE "/cert/private.key" + +/****************************************************************************** + Special file sizes +*******************************************************************************/ +#define IMG_SIZE (192 * 1024) /* 16KB are reserved for the bootloader and at least 48KB for the heap*/ +#define SRVPACK_SIZE (16 * 1024) +#define SIGN_SIZE (2 * 1024) +#define CA_KEY_SIZE (4 * 1024) + +/****************************************************************************** + Active Image +*******************************************************************************/ +#define IMG_ACT_FACTORY 0 +#define IMG_ACT_UPDATE1 1 +#define IMG_ACT_UPDATE2 2 + +#define IMG_STATUS_CHECK 0 +#define IMG_STATUS_READY 1 + +/****************************************************************************** + Boot Info structure +*******************************************************************************/ +typedef struct _sBootInfo_t +{ + _u8 ActiveImg; + _u8 Status; + _u8 PrevImg; + _u8 : 8; +} sBootInfo_t; + + +/****************************************************************************** + + Mark the end of the C bindings section for C++ compilers. + +*******************************************************************************/ +#ifdef __cplusplus +} +#endif + +#endif // MICROPY_INCLUDED_CC3200_BOOTMGR_FLC_H diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/main.c b/src/openmv/src/micropython/ports/cc3200/bootmgr/main.c new file mode 100755 index 0000000..cfb8dec --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/main.c @@ -0,0 +1,419 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include "hw_ints.h" +#include "hw_types.h" +#include "hw_gpio.h" +#include "hw_memmap.h" +#include "hw_gprcm.h" +#include "hw_common_reg.h" +#include "pin.h" +#include "gpio.h" +#include "rom_map.h" +#include "prcm.h" +#include "simplelink.h" +#include "interrupt.h" +#include "gpio.h" +#include "flc.h" +#include "bootmgr.h" +#include "shamd5.h" +#include "cryptohash.h" +#include "utils.h" +#include "cc3200_hal.h" +#include "debug.h" +#include "mperror.h" +#include "antenna.h" + + +//***************************************************************************** +// Local Constants +//***************************************************************************** +#define SL_STOP_TIMEOUT 35 +#define BOOTMGR_HASH_ALGO SHAMD5_ALGO_MD5 +#define BOOTMGR_HASH_SIZE 32 +#define BOOTMGR_BUFF_SIZE 512 + +#define BOOTMGR_WAIT_SAFE_MODE_0_MS 500 + +#define BOOTMGR_WAIT_SAFE_MODE_1_MS 3000 +#define BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS 500 + +#define BOOTMGR_WAIT_SAFE_MODE_2_MS 3000 +#define BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS 250 + +#define BOOTMGR_WAIT_SAFE_MODE_3_MS 1500 +#define BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS 100 + +//***************************************************************************** +// Exported functions declarations +//***************************************************************************** +extern void bootmgr_run_app (_u32 base); + +//***************************************************************************** +// Local functions declarations +//***************************************************************************** +static void bootmgr_board_init (void); +static bool bootmgr_verify (_u8 *image); +static void bootmgr_load_and_execute (_u8 *image); +static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait); +static bool safe_boot_request_start (uint32_t wait_time); +static void wait_for_safe_boot (sBootInfo_t *psBootInfo); +static void bootmgr_image_loader (sBootInfo_t *psBootInfo); + +//***************************************************************************** +// Private data +//***************************************************************************** +static _u8 bootmgr_file_buf[BOOTMGR_BUFF_SIZE]; +static _u8 bootmgr_hash_buf[BOOTMGR_HASH_SIZE + 1]; + +//***************************************************************************** +// Vector Table +//***************************************************************************** +extern void (* const g_pfnVectors[])(void); + +//***************************************************************************** +// WLAN Event handler callback hookup function +//***************************************************************************** +void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) +{ + +} + +//***************************************************************************** +// HTTP Server callback hookup function +//***************************************************************************** +void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent, + SlHttpServerResponse_t *pHttpResponse) +{ + +} + +//***************************************************************************** +// Net APP Event callback hookup function +//***************************************************************************** +void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent) +{ + +} + +//***************************************************************************** +// General Event callback hookup function +//***************************************************************************** +void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent) +{ + +} + +//***************************************************************************** +// Socket Event callback hookup function +//***************************************************************************** +void SimpleLinkSockEventHandler(SlSockEvent_t *pSock) +{ + +} + +//***************************************************************************** +//! Board Initialization & Configuration +//***************************************************************************** +static void bootmgr_board_init(void) { + // set the vector table base + MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); + + // enable processor interrupts + MAP_IntMasterEnable(); + MAP_IntEnable(FAULT_SYSTICK); + + // mandatory MCU initialization + PRCMCC3200MCUInit(); + + // clear all the special bits, since we can't trust their content after reset + // except for the WDT reset one!! + PRCMClearSpecialBit(PRCM_SAFE_BOOT_BIT); + PRCMClearSpecialBit(PRCM_FIRST_BOOT_BIT); + + // check the reset after clearing the special bits + mperror_bootloader_check_reset_cause(); + +#if MICROPY_HW_ANTENNA_DIVERSITY + // configure the antenna selection pins + antenna_init0(); +#endif + + // enable the data hashing engine + CRYPTOHASH_Init(); + + // init the system led and the system switch + mperror_init0(); +} + +//***************************************************************************** +//! Verifies the integrity of the new application binary +//***************************************************************************** +static bool bootmgr_verify (_u8 *image) { + SlFsFileInfo_t FsFileInfo; + _u32 reqlen, offset = 0; + _i32 fHandle; + + // open the file for reading + if (0 == sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fHandle)) { + // get the file size + sl_FsGetInfo(image, 0, &FsFileInfo); + + if (FsFileInfo.FileLen > BOOTMGR_HASH_SIZE) { + FsFileInfo.FileLen -= BOOTMGR_HASH_SIZE; + CRYPTOHASH_SHAMD5Start(BOOTMGR_HASH_ALGO, FsFileInfo.FileLen); + do { + if ((FsFileInfo.FileLen - offset) > BOOTMGR_BUFF_SIZE) { + reqlen = BOOTMGR_BUFF_SIZE; + } + else { + reqlen = FsFileInfo.FileLen - offset; + } + + offset += sl_FsRead(fHandle, offset, bootmgr_file_buf, reqlen); + CRYPTOHASH_SHAMD5Update(bootmgr_file_buf, reqlen); + } while (offset < FsFileInfo.FileLen); + + CRYPTOHASH_SHAMD5Read (bootmgr_file_buf); + + // convert the resulting hash to hex + for (_u32 i = 0; i < (BOOTMGR_HASH_SIZE / 2); i++) { + snprintf ((char *)&bootmgr_hash_buf[(i * 2)], 3, "%02x", bootmgr_file_buf[i]); + } + + // read the hash from the file and close it + sl_FsRead(fHandle, offset, bootmgr_file_buf, BOOTMGR_HASH_SIZE); + sl_FsClose (fHandle, NULL, NULL, 0); + bootmgr_file_buf[BOOTMGR_HASH_SIZE] = '\0'; + // compare both hashes + if (!strcmp((const char *)bootmgr_hash_buf, (const char *)bootmgr_file_buf)) { + // it's a match + return true; + } + } + // close the file + sl_FsClose(fHandle, NULL, NULL, 0); + } + return false; +} + +//***************************************************************************** +//! Loads the application from sFlash and executes +//***************************************************************************** +static void bootmgr_load_and_execute (_u8 *image) { + SlFsFileInfo_t pFsFileInfo; + _i32 fhandle; + // open the application binary + if (!sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fhandle)) { + // get the file size + if (!sl_FsGetInfo(image, 0, &pFsFileInfo)) { + // read the application into SRAM + if (pFsFileInfo.FileLen == sl_FsRead(fhandle, 0, (unsigned char *)APP_IMG_SRAM_OFFSET, pFsFileInfo.FileLen)) { + // close the file + sl_FsClose(fhandle, 0, 0, 0); + // stop the network services + sl_Stop(SL_STOP_TIMEOUT); + // execute the application + bootmgr_run_app(APP_IMG_SRAM_OFFSET); + } + } + } +} + +//***************************************************************************** +//! Wait while the safe mode pin is being held high and blink the system led +//! with the specified period +//***************************************************************************** +static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force_wait) { + _u32 count; + for (count = 0; (force_wait || MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) && + ((period * count) < wait_time); count++) { + // toogle the led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); + UtilsDelay(UTILS_DELAY_US_TO_COUNT(period * 1000)); + } + return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false; +} + +static bool safe_boot_request_start (uint32_t wait_time) { + if (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) { + UtilsDelay(UTILS_DELAY_US_TO_COUNT(wait_time * 1000)); + } + return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false; +} + +//***************************************************************************** +//! Check for the safe mode pin +//***************************************************************************** +static void wait_for_safe_boot (sBootInfo_t *psBootInfo) { + if (safe_boot_request_start(BOOTMGR_WAIT_SAFE_MODE_0_MS)) { + if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_1_MS, BOOTMGR_WAIT_SAFE_MODE_1_BLINK_MS, false)) { + // go back one step in time + psBootInfo->ActiveImg = psBootInfo->PrevImg; + if (wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_2_MS, BOOTMGR_WAIT_SAFE_MODE_2_BLINK_MS, false)) { + // go back directly to the factory image + psBootInfo->ActiveImg = IMG_ACT_FACTORY; + wait_while_blinking(BOOTMGR_WAIT_SAFE_MODE_3_MS, BOOTMGR_WAIT_SAFE_MODE_3_BLINK_MS, true); + } + } + // turn off the system led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0); + // request a safe boot to the application + PRCMSetSpecialBit(PRCM_SAFE_BOOT_BIT); + } + // deinit the safe boot pin + mperror_deinit_sfe_pin(); +} + +//***************************************************************************** +//! Load the proper image based on the information from the boot info +//! and launch it. +//***************************************************************************** +static void bootmgr_image_loader(sBootInfo_t *psBootInfo) { + _i32 fhandle; + _u8 *image; + + // search for the active image + switch (psBootInfo->ActiveImg) { + case IMG_ACT_UPDATE1: + image = (unsigned char *)IMG_UPDATE1; + break; + case IMG_ACT_UPDATE2: + image = (unsigned char *)IMG_UPDATE2; + break; + default: + image = (unsigned char *)IMG_FACTORY; + break; + } + + // do we have a new image that needs to be verified? + if ((psBootInfo->ActiveImg != IMG_ACT_FACTORY) && (psBootInfo->Status == IMG_STATUS_CHECK)) { + if (!bootmgr_verify(image)) { + // verification failed, delete the broken file + sl_FsDel(image, 0); + // switch to the previous image + psBootInfo->ActiveImg = psBootInfo->PrevImg; + psBootInfo->PrevImg = IMG_ACT_FACTORY; + } + // in any case, change the status to "READY" + psBootInfo->Status = IMG_STATUS_READY; + // write the new boot info + if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle)) { + sl_FsWrite(fhandle, 0, (unsigned char *)psBootInfo, sizeof(sBootInfo_t)); + // close the file + sl_FsClose(fhandle, 0, 0, 0); + } + } + + // this one might modify the boot info hence it MUST be called after + // bootmgr_verify! (so that the changes are not saved to flash) + wait_for_safe_boot(psBootInfo); + + // select the active image again, since it might have changed + switch (psBootInfo->ActiveImg) { + case IMG_ACT_UPDATE1: + image = (unsigned char *)IMG_UPDATE1; + break; + case IMG_ACT_UPDATE2: + image = (unsigned char *)IMG_UPDATE2; + break; + default: + image = (unsigned char *)IMG_FACTORY; + break; + } + bootmgr_load_and_execute(image); +} + +//***************************************************************************** +//! Main function +//***************************************************************************** +int main (void) { + sBootInfo_t sBootInfo = { .ActiveImg = IMG_ACT_FACTORY, .Status = IMG_STATUS_READY, .PrevImg = IMG_ACT_FACTORY }; + bool bootapp = false; + _i32 fhandle; + + // board setup + bootmgr_board_init(); + + // start simplelink since we need it to access the sflash + sl_Start(0, 0, 0); + + // if a boot info file is found, load it, else, create a new one with the default boot info + if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) { + if (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) { + bootapp = true; + } + sl_FsClose(fhandle, 0, 0, 0); + } + // boot info file not present, it means that this is the first boot after being programmed + if (!bootapp) { + // create a new boot info file + _u32 BootInfoCreateFlag = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ; + if (!sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)), + BootInfoCreateFlag), NULL, &fhandle)) { + // write the default boot info. + if (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) { + bootapp = true; + } + sl_FsClose(fhandle, 0, 0, 0); + } + // signal the first boot to the application + PRCMSetSpecialBit(PRCM_FIRST_BOOT_BIT); + } + + if (bootapp) { + // load and execute the image based on the boot info + bootmgr_image_loader(&sBootInfo); + } + + // stop simplelink + sl_Stop(SL_STOP_TIMEOUT); + + // if we've reached this point, then it means that a fatal error has occurred and the + // application could not be loaded, so, loop forever and signal the crash to the user + while (true) { + // keep the bld on + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN); + __asm volatile(" dsb \n" + " isb \n" + " wfi \n"); + } +} + +//***************************************************************************** +//! The following stub function is needed to link mp_vprintf +//***************************************************************************** +#include "py/qstr.h" + +const byte *qstr_data(qstr q, size_t *len) { + *len = 0; + return NULL; +} diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/relocator/relocator.bin b/src/openmv/src/micropython/ports/cc3200/bootmgr/relocator/relocator.bin new file mode 100755 index 0000000..b1ac510 Binary files /dev/null and b/src/openmv/src/micropython/ports/cc3200/bootmgr/relocator/relocator.bin differ diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/runapp.s b/src/openmv/src/micropython/ports/cc3200/bootmgr/runapp.s new file mode 100755 index 0000000..45c6dcb --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/runapp.s @@ -0,0 +1,19 @@ + .syntax unified + .cpu cortex-m4 + .thumb + .text + .align 2 + +@ void bootmgr_run_app(_u32 base) + .global bootmgr_run_app + .thumb + .thumb_func + .type bootmgr_run_app, %function +bootmgr_run_app: + @ set the SP + ldr sp, [r0] + add r0, r0, #4 + + @ jump to the entry code + ldr r1, [r0] + bx r1 diff --git a/src/openmv/src/micropython/ports/cc3200/bootmgr/sl/user.h b/src/openmv/src/micropython/ports/cc3200/bootmgr/sl/user.h new file mode 100755 index 0000000..be93029 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/bootmgr/sl/user.h @@ -0,0 +1,1063 @@ +/* + * user.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __USER_H__ +#define __USER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + + +/*! + ****************************************************************************** + + \defgroup porting_user_include Porting - User Include Files + + This section IS NOT REQUIRED in case user provided primitives are handled + in makefiles or project configurations (IDE) + + PORTING ACTION: + - Include all required header files for the definition of: + -# Transport layer library API (e.g. SPI, UART) + -# OS primitives definitions (e.g. Task spawn, Semaphores) + -# Memory management primitives (e.g. alloc, free) + + ****************************************************************************** + */ + +#include +#include "cc_pal.h" + +/*! + \def MAX_CONCURRENT_ACTIONS + + \brief Defines the maximum number of concurrent action in the system + Min:1 , Max: 32 + + Actions which has async events as return, can be + + \sa + + \note In case there are not enough resources for the actions needed in the system, + error is received: POOL_IS_EMPTY + one option is to increase MAX_CONCURRENT_ACTIONS + (improves performance but results in memory consumption) + Other option is to call the API later (decrease performance) + + \warning In case of setting to one, recommend to use non-blocking recv\recvfrom to allow + multiple socket recv +*/ +#define MAX_CONCURRENT_ACTIONS 10 +/*! + \def CPU_FREQ_IN_MHZ + \brief Defines CPU frequency for Host side, for better accuracy of busy loops, if any + \sa + \note + + \warning If not set the default CPU frequency is set to 200MHz + This option will be deprecated in future release +*/ + +#define CPU_FREQ_IN_MHZ 80 + + +/*! + ****************************************************************************** + + \defgroup porting_capabilities Porting - Capabilities Set + + This section IS NOT REQUIRED in case one of the following pre defined + capabilities set is in use: + - SL_TINY + - SL_SMALL + - SL_FULL + + PORTING ACTION: + - Define one of the pre-defined capabilities set or uncomment the + relevant definitions below to select the required capabilities + + @{ + + ******************************************************************************* +*/ + +/*! + \def SL_INC_ARG_CHECK + + \brief Defines whether the SimpleLink driver perform argument check + or not + + When defined, the SimpleLink driver perform argument check on + function call. Removing this define could reduce some code + size and improve slightly the performances but may impact in + unpredictable behavior in case of invalid arguments + + \sa + + \note belongs to \ref proting_sec + + \warning Removing argument check may cause unpredictable behavior in + case of invalid arguments. + In this case the user is responsible to argument validity + (for example all handlers must not be NULL) +*/ +#define SL_INC_ARG_CHECK + + +/*! + \def SL_INC_STD_BSD_API_NAMING + + \brief Defines whether SimpleLink driver should expose standard BSD + APIs or not + + When defined, the SimpleLink driver in addtion to its alternative + BSD APIs expose also standard BSD APIs. + Stadrad BSD API includs the following functions: + socket , close , accept , bind , listen , connect , select , + setsockopt , getsockopt , recv , recvfrom , write , send , sendto , + gethostbyname + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_STD_BSD_API_NAMING + + +/*! + \brief Defines whether to include extended API in SimpleLink driver + or not + + When defined, the SimpleLink driver will include also all + exteded API of the included packages + + \sa ext_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_EXT_API + +/*! + \brief Defines whether to include WLAN package in SimpleLink driver + or not + + When defined, the SimpleLink driver will include also + the WLAN package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_WLAN_PKG + +/*! + \brief Defines whether to include SOCKET package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also + the SOCKET package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCKET_PKG + +/*! + \brief Defines whether to include NET_APP package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also the + NET_APP package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NET_APP_PKG + +/*! + \brief Defines whether to include NET_CFG package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also + the NET_CFG package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NET_CFG_PKG + +/*! + \brief Defines whether to include NVMEM package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also the + NVMEM package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NVMEM_PKG + +/*! + \brief Defines whether to include socket server side APIs + in SimpleLink driver or not + + When defined, the SimpleLink driver will include also socket + server side APIs + + \sa server_side + + \note + + \warning +*/ +#define SL_INC_SOCK_SERVER_SIDE_API + +/*! + \brief Defines whether to include socket client side APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + client side APIs + + \sa client_side + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_CLIENT_SIDE_API + +/*! + \brief Defines whether to include socket receive APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + receive side APIs + + \sa recv_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_RECV_API + +/*! + \brief Defines whether to include socket send APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + send side APIs + + \sa send_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_SEND_API + +/*! + + Close the Doxygen group. + @} + + */ + + +/*! + ****************************************************************************** + + \defgroup ported_enable_device Ported on CC32XX - Device Enable/Disable + + The enable/disable API provide mechanism to enable/disable the network processor + + + PORTING ACTION: + - None + @{ + + ****************************************************************************** + */ + +/*! + \brief Preamble to the enabling the Network Processor. + Placeholder to implement any pre-process operations + before enabling networking operations. + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec + +*/ +#ifdef DEBUG +#define sl_DeviceEnablePreamble() NwpPowerOnPreamble() +#else +#define sl_DeviceEnablePreamble() +#endif + +/*! + \brief Enable the Network Processor + + \sa sl_DeviceDisable + + \note belongs to \ref ported_sec + +*/ +#define sl_DeviceEnable() NwpPowerOn() + +/*! + \brief Disable the Network Processor + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec +*/ +#define sl_DeviceDisable() NwpPowerOff() + +/*! + + Close the Doxygen group. + @} + + */ + +/*! + ****************************************************************************** + + \defgroup ported_interface Ported on CC32XX - Communication Interface + + The simple link device can work with different communication + channels (e.g. spi/uart). Texas Instruments provides single driver + that can work with all these types. This section bind between the + physical communication interface channel and the SimpleLink driver + + + \note Correct and efficient implementation of this driver is critical + for the performances of the SimpleLink device on this platform. + + + PORTING ACTION: + - None + + @{ + + ****************************************************************************** +*/ + +#define _SlFd_t Fd_t + +/*! + \brief Opens an interface communication port to be used for communicating + with a SimpleLink device + + Given an interface name and option flags, this function opens + the communication port and creates a file descriptor. + This file descriptor is used afterwards to read and write + data from and to this specific communication channel. + The speed, clock polarity, clock phase, chip select and all other + specific attributes of the channel are all should be set to hardcoded + in this function. + + \param ifName - points to the interface name/path. The interface name is an + optional attributes that the simple link driver receives + on opening the driver (sl_Start). + In systems that the spi channel is not implemented as + part of the os device drivers, this parameter could be NULL. + + \param flags - optional flags parameters for future use + + \return upon successful completion, the function shall open the channel + and return a non-negative integer representing the file descriptor. + Otherwise, -1 shall be returned + + \sa sl_IfClose , sl_IfRead , sl_IfWrite + + \note The prototype of the function is as follow: + Fd_t xxx_IfOpen(char* pIfName , unsigned long flags); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfOpen spi_Open + +/*! + \brief Closes an opened interface communication port + + \param fd - file descriptor of opened communication channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa sl_IfOpen , sl_IfRead , sl_IfWrite + + \note The prototype of the function is as follow: + int xxx_IfClose(Fd_t Fd); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfClose spi_Close + +/*! + \brief Attempts to read up to len bytes from an opened communication channel + into a buffer starting at pBuff. + + \param fd - file descriptor of an opened communication channel + + \param pBuff - pointer to the first location of a buffer that contains enough + space for all expected data + + \param len - number of bytes to read from the communication channel + + \return upon successful completion, the function shall return the number of read bytes. + Otherwise, 0 shall be returned + + \sa sl_IfClose , sl_IfOpen , sl_IfWrite + + + \note The prototype of the function is as follow: + int xxx_IfRead(Fd_t Fd , char* pBuff , int Len); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfRead spi_Read + +/*! + \brief attempts to write up to len bytes to the SPI channel + + \param fd - file descriptor of an opened communication channel + + \param pBuff - pointer to the first location of a buffer that contains + the data to send over the communication channel + + \param len - number of bytes to write to the communication channel + + \return upon successful completion, the function shall return the number of sent bytes. + therwise, 0 shall be returned + + \sa sl_IfClose , sl_IfOpen , sl_IfRead + + \note This function could be implemented as zero copy and return only upon successful completion + of writing the whole buffer, but in cases that memory allocation is not too tight, the + function could copy the data to internal buffer, return back and complete the write in + parallel to other activities as long as the other SPI activities would be blocked until + the entire buffer write would be completed + + The prototype of the function is as follow: + int xxx_IfWrite(Fd_t Fd , char* pBuff , int Len); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfWrite spi_Write + +/*! + \brief register an interrupt handler routine for the host IRQ + + \param InterruptHdl - pointer to interrupt handler routine + + \param pValue - pointer to a memory structure that is passed + to the interrupt handler. + + \return upon successful registration, the function shall return 0. + Otherwise, -1 shall be returned + + \sa + + \note If there is already registered interrupt handler, the function + should overwrite the old handler with the new one + + \note If the handler is a null pointer, the function should un-register the + interrupt handler, and the interrupts can be disabled. + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfRegIntHdlr(InterruptHdl , pValue) NwpRegisterInterruptHandler(InterruptHdl , pValue) + +/*! + \brief Masks the Host IRQ + + \sa sl_IfUnMaskIntHdlr + + + + \note belongs to \ref ported_sec + + \warning +*/ + + +#define sl_IfMaskIntHdlr() NwpMaskInterrupt() + +/*! + \brief Unmasks the Host IRQ + + \sa sl_IfMaskIntHdlr + + + + \note belongs to \ref ported_sec + + \warning +*/ + +#define sl_IfUnMaskIntHdlr() NwpUnMaskInterrupt() + +/*! + \brief Write Handers for statistics debug on write + + \param interface handler - pointer to interrupt handler routine + + + \return no return value + + \sa + + \note An optional hooks for monitoring before and after write info + + \note belongs to \ref ported_sec + + \warning +*/ +/* #define SL_START_WRITE_STAT */ + + +/*! + + Close the Doxygen group. + @} + +*/ + +/*! + ****************************************************************************** + + \defgroup ported_os Ported on CC32XX - Operating System + + The simple link driver can run on multi-threaded environment as well + as non-os environment (mail loop) + + This section IS NOT REQUIRED in case you are working on non-os environment. + + If you choose to work in multi-threaded environment under any operating system + you will have to provide some basic adaptation routines to allow the driver + to protect access to resources from different threads (locking object) and + to allow synchronization between threads (sync objects). + + PORTING ACTION: + -# Uncomment SL_PLATFORM_MULTI_THREADED define + -# Bind locking object routines + -# Bind synchronization object routines + -# Optional - Bind spawn thread routine + + @{ + + ****************************************************************************** +*/ + +/* +#define SL_PLATFORM_MULTI_THREADED +*/ + +#ifdef SL_PLATFORM_MULTI_THREADED +#include "osi.h" + + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_RET_CODE_OK ((int)OSI_OK) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_WAIT_FOREVER ((OsiTime_t)OSI_WAIT_FOREVER) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_NO_WAIT ((OsiTime_t)OSI_NO_WAIT) + +/*! + \brief type definition for a time value + + \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. + + \note belongs to \ref ported_sec +*/ +#define _SlTime_t OsiTime_t + +/*! + \brief type definition for a sync object container + + Sync object is object used to synchronize between two threads or thread and interrupt handler. + One thread is waiting on the object and the other thread send a signal, which then + release the waiting thread. + The signal must be able to be sent from interrupt context. + This object is generally implemented by binary semaphore or events. + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. + + \note belongs to \ref ported_sec +*/ +typedef OsiSyncObj_t _SlSyncObj_t; + + +/*! + \brief This function creates a sync object + + The sync object is used for synchronization between diffrent thread or ISR and + a thread. + + \param pSyncObj - pointer to the sync object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjCreate(pSyncObj,pName) osi_SyncObjCreate(pSyncObj) + + +/*! + \brief This function deletes a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjDelete(pSyncObj) osi_SyncObjDelete(pSyncObj) + + +/*! + \brief This function generates a sync signal for the object. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +#define sl_SyncObjSignal(pSyncObj) osi_SyncObjSignal(pSyncObj) + +/*! + \brief This function generates a sync signal for the object from Interrupt + + This is for RTOS that should signal from IRQ using a dedicated API + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +#define sl_SyncObjSignalFromIRQ(pSyncObj) osi_SyncObjSignalFromISR(pSyncObj) + +/*! + \brief This function waits for a sync signal of the specific sync object + + \param pSyncObj - pointer to the sync object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the sync signal + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + \return upon successful reception of the signal within the timeout window return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjWait(pSyncObj,Timeout) osi_SyncObjWait(pSyncObj,Timeout) + +/*! + \brief type definition for a locking object container + + Locking object are used to protect a resource from mutual accesses of two or more threads. + The locking object should suppurt reentrant locks by a signal thread. + This object is generally implemented by mutex semaphore + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. + \note belongs to \ref ported_sec +*/ +typedef OsiLockObj_t _SlLockObj_t; + +/*! + \brief This function creates a locking object. + + The locking object is used for protecting a shared resources between different + threads. + + \param pLockObj - pointer to the locking object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjCreate(pLockObj,pName) osi_LockObjCreate(pLockObj) + +/*! + \brief This function deletes a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjDelete(pLockObj) osi_LockObjDelete(pLockObj) + +/*! + \brief This function locks a locking object. + + All other threads that call this function before this thread calls + the osi_LockObjUnlock would be suspended + + \param pLockObj - pointer to the locking object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the locking object + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + + \return upon successful reception of the locking object the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjLock(pLockObj,Timeout) osi_LockObjLock(pLockObj,Timeout) + +/*! + \brief This function unlock a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjUnlock(pLockObj) osi_LockObjUnlock(pLockObj) + +#endif +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function should return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +//#define SL_PLATFORM_EXTERNAL_SPAWN + +#ifdef SL_PLATFORM_EXTERNAL_SPAWN +#define sl_Spawn(pEntry,pValue,flags) osi_Spawn(pEntry,pValue,flags) +#endif + +/*! + + Close the Doxygen group. + @} + + */ +/*! + ****************************************************************************** + + \defgroup porting_mem_mgm Porting - Memory Management + + This section declare in which memory management model the SimpleLink driver + will run: + -# Static + -# Dynamic + + This section IS NOT REQUIRED in case Static model is selected. + + The default memory model is Static + + PORTING ACTION: + - If dynamic model is selected, define the alloc and free functions. + + @{ + + ***************************************************************************** +*/ + +/*! + \brief Defines whether the SimpleLink driver is working in dynamic + memory model or not + + When defined, the SimpleLink driver use dynamic allocations + if dynamic allocation is selected malloc and free functions + must be retrieved + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define SL_MEMORY_MGMT_DYNAMIC 1 +#define SL_MEMORY_MGMT_STATIC 0 + +#define SL_MEMORY_MGMT SL_MEMORY_MGMT_STATIC + +#ifdef SL_MEMORY_MGMT_DYNAMIC +#ifdef SL_PLATFORM_MULTI_THREADED + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Malloc(Size) mem_Malloc(Size) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Free(pMem) mem_Free(pMem) +#else +#include +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Malloc(Size) malloc(Size) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Free(pMem) free(pMem) +#endif +#endif +/*! + + Close the Doxygen group. + @} + + */ + + +/*! + ****************************************************************************** + + \defgroup porting_events Porting - Event Handlers + + This section includes the asynchronous event handlers routines + + PORTING ACTION: + -Uncomment the required handler and define your routine as the value + of this handler + + @{ + + ****************************************************************************** + */ + +/*! + \brief + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_GeneralEvtHdlr SimpleLinkGeneralEventHandler + + +/*! + \brief An event handler for WLAN connection or disconnection indication + This event handles async WLAN events. + Possible events are: + SL_WLAN_CONNECT_EVENT - indicates WLAN is connected + SL_WLAN_DISCONNECT_EVENT - indicates WLAN is disconnected + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_WlanEvtHdlr SimpleLinkWlanEventHandler + + +/*! + \brief An event handler for IP address asynchronous event. Usually accepted after new WLAN connection. + This event handles networking events. + Possible events are: + SL_NETAPP_IPV4_ACQUIRED - IP address was acquired (DHCP or Static) + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_NetAppEvtHdlr SimpleLinkNetAppEventHandler + +/*! + \brief A callback for HTTP server events. + Possible events are: + SL_NETAPP_HTTPGETTOKENVALUE - NWP requests to get the value of a specific token + SL_NETAPP_HTTPPOSTTOKENVALUE - NWP post to the host a new value for a specific token + + \param pServerEvent - Contains the relevant event information (SL_NETAPP_HTTPGETTOKENVALUE or SL_NETAPP_HTTPPOSTTOKENVALUE) + + \param pServerResponse - Should be filled by the user with the relevant response information (i.e SL_NETAPP_HTTPSETTOKENVALUE as a response to SL_NETAPP_HTTPGETTOKENVALUE event) + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_HttpServerCallback SimpleLinkHttpServerCallback +/*! + \brief + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_SockEvtHdlr SimpleLinkSockEventHandler + + + +#define _SL_USER_TYPES +#define _u8 unsigned char +#define _i8 signed char + +#define _u16 unsigned short +#define _i16 signed short + +#define _u32 unsigned int +#define _i32 signed int +#define _volatile volatile +#define _const const + + + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __USER_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.c b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.c new file mode 100755 index 0000000..0a13791 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.c @@ -0,0 +1,433 @@ +//***************************************************************************** +// sd_diskio.c +// +// Low level SD Card access hookup for FatFS +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 "py/mpconfig.h" +#include "py/mphal.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "hw_types.h" +#include "hw_memmap.h" +#include "hw_ints.h" +#include "rom_map.h" +#include "sd_diskio.h" +#include "sdhost.h" +#include "pin.h" +#include "prcm.h" +#include "stdcmd.h" +#include "utils.h" + +//***************************************************************************** +// Macros +//***************************************************************************** +#define DISKIO_RETRY_TIMEOUT 0xFFFFFFFF + +#define CARD_TYPE_UNKNOWN 0 +#define CARD_TYPE_MMC 1 +#define CARD_TYPE_SDCARD 2 + +#define CARD_CAP_CLASS_SDSC 0 +#define CARD_CAP_CLASS_SDHC 1 + +#define CARD_VERSION_1 0 +#define CARD_VERSION_2 1 + +//***************************************************************************** +// Disk Info for attached disk +//***************************************************************************** +DiskInfo_t sd_disk_info = {CARD_TYPE_UNKNOWN, CARD_VERSION_1, CARD_CAP_CLASS_SDSC, 0, 0, STA_NOINIT, 0}; + +//***************************************************************************** +// +//! Send Command to card +//! +//! \param ulCmd is the command to be send +//! \paran ulArg is the command argument +//! +//! This function sends command to attached card and check the response status +//! if any. +//! +//! \return Returns 0 on success, 1 otherwise +// +//***************************************************************************** +static unsigned int CardSendCmd (unsigned int ulCmd, unsigned int ulArg) { + unsigned long ulStatus; + + // Clear the interrupt status + MAP_SDHostIntClear(SDHOST_BASE,0xFFFFFFFF); + + // Send command + MAP_SDHostCmdSend(SDHOST_BASE,ulCmd,ulArg); + + // Wait for command complete or error + do { + ulStatus = MAP_SDHostIntStatus(SDHOST_BASE); + ulStatus = (ulStatus & (SDHOST_INT_CC | SDHOST_INT_ERRI)); + } while (!ulStatus); + + // Check error status + if (ulStatus & SDHOST_INT_ERRI) { + // Reset the command line + MAP_SDHostCmdReset(SDHOST_BASE); + return 1; + } + else { + return 0; + } +} + +//***************************************************************************** +// +//! Get the capacity of specified card +//! +//! \param ulRCA is the Relative Card Address (RCA) +//! +//! This function gets the capacity of card addressed by \e ulRCA paramaeter. +//! +//! \return Returns 0 on success, 1 otherwise. +// +//***************************************************************************** +static unsigned int CardCapacityGet(DiskInfo_t *psDiskInfo) { + unsigned long ulRet; + unsigned long ulResp[4]; + unsigned long ulBlockSize; + unsigned long ulBlockCount; + unsigned long ulCSizeMult; + unsigned long ulCSize; + + // Read the CSD register + ulRet = CardSendCmd(CMD_SEND_CSD, (psDiskInfo->usRCA << 16)); + + if(ulRet == 0) { + // Read the response + MAP_SDHostRespGet(SDHOST_BASE,ulResp); + + // 136 bit CSD register is read into an array of 4 words. + // ulResp[0] = CSD[31:0] + // ulResp[1] = CSD[63:32] + // ulResp[2] = CSD[95:64] + // ulResp[3] = CSD[127:96] + if(ulResp[3] >> 30) { + ulBlockSize = SD_SECTOR_SIZE * 1024; + ulBlockCount = (ulResp[1] >> 16 | ((ulResp[2] & 0x3F) << 16)) + 1; + } + else { + ulBlockSize = 1 << ((ulResp[2] >> 16) & 0xF); + ulCSizeMult = ((ulResp[1] >> 15) & 0x7); + ulCSize = ((ulResp[1] >> 30) | (ulResp[2] & 0x3FF) << 2); + ulBlockCount = (ulCSize + 1) * (1 << (ulCSizeMult + 2)); + } + + // Calculate the card capacity in bytes + psDiskInfo->ulBlockSize = ulBlockSize; + psDiskInfo->ulNofBlock = ulBlockCount; + } + + return ulRet; +} + +//***************************************************************************** +// +//! Select a card for reading or writing +//! +//! \param Card is the pointer to card attribute structure. +//! +//! This function selects a card for reading or writing using its RCA from +//! \e Card parameter. +//! +//! \return Returns 0 success, 1 otherwise. +// +//***************************************************************************** +static unsigned int CardSelect (DiskInfo_t *sDiskInfo) { + unsigned long ulRCA; + unsigned long ulRet; + + ulRCA = sDiskInfo->usRCA; + + // Send select command with card's RCA. + ulRet = CardSendCmd(CMD_SELECT_CARD, (ulRCA << 16)); + + if (ulRet == 0) { + while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC)); + } + + // Delay 250ms for the card to become ready + mp_hal_delay_ms(250); + + return ulRet; +} + +//***************************************************************************** +// +//! Initializes physical drive +//! +//! This function initializes the physical drive +//! +//! \return Returns 0 on succeeded. +//***************************************************************************** +DSTATUS sd_disk_init (void) { + unsigned long ulRet; + unsigned long ulResp[4]; + + if (sd_disk_info.bStatus != 0) { + sd_disk_info.bStatus = STA_NODISK; + // Send std GO IDLE command + if (CardSendCmd(CMD_GO_IDLE_STATE, 0) == 0) { + // Get interface operating condition for the card + ulRet = CardSendCmd(CMD_SEND_IF_COND,0x000001A5); + MAP_SDHostRespGet(SDHOST_BASE,ulResp); + + // It's a SD ver 2.0 or higher card + if (ulRet == 0 && ((ulResp[0] & 0xFF) == 0xA5)) { + // Version 1 card do not respond to this command + sd_disk_info.ulVersion = CARD_VERSION_2; + sd_disk_info.ucCardType = CARD_TYPE_SDCARD; + + // Wait for card to become ready. + do { + // Send ACMD41 + CardSendCmd(CMD_APP_CMD, 0); + ulRet = CardSendCmd(CMD_SD_SEND_OP_COND, 0x40E00000); + + // Response contains 32-bit OCR register + MAP_SDHostRespGet(SDHOST_BASE, ulResp); + + } while (((ulResp[0] >> 31) == 0)); + + if (ulResp[0] & (1UL<<30)) { + sd_disk_info.ulCapClass = CARD_CAP_CLASS_SDHC; + } + sd_disk_info.bStatus = 0; + } + //It's a MMC or SD 1.x card + else { + // Wait for card to become ready. + do { + CardSendCmd(CMD_APP_CMD, 0); + ulRet = CardSendCmd(CMD_SD_SEND_OP_COND,0x00E00000); + if (ulRet == 0) { + // Response contains 32-bit OCR register + MAP_SDHostRespGet(SDHOST_BASE, ulResp); + } + } while (((ulRet == 0) && (ulResp[0] >> 31) == 0)); + + if (ulRet == 0) { + sd_disk_info.ucCardType = CARD_TYPE_SDCARD; + sd_disk_info.bStatus = 0; + } + else { + if (CardSendCmd(CMD_SEND_OP_COND, 0) == 0) { + // MMC not supported by the controller + sd_disk_info.ucCardType = CARD_TYPE_MMC; + } + } + } + } + + // Get the RCA of the attached card + if (sd_disk_info.bStatus == 0) { + ulRet = CardSendCmd(CMD_ALL_SEND_CID, 0); + if (ulRet == 0) { + CardSendCmd(CMD_SEND_REL_ADDR,0); + MAP_SDHostRespGet(SDHOST_BASE, ulResp); + + // Fill in the RCA + sd_disk_info.usRCA = (ulResp[0] >> 16); + + // Get tha card capacity + CardCapacityGet(&sd_disk_info); + } + + // Select the card. + ulRet = CardSelect(&sd_disk_info); + if (ulRet == 0) { + sd_disk_info.bStatus = 0; + } + } + } + + return sd_disk_info.bStatus; +} + +//***************************************************************************** +// +//! De-initializes the physical drive +//! +//! This function de-initializes the physical drive +//***************************************************************************** +void sd_disk_deinit (void) { + sd_disk_info.ucCardType = CARD_TYPE_UNKNOWN; + sd_disk_info.ulVersion = CARD_VERSION_1; + sd_disk_info.ulCapClass = CARD_CAP_CLASS_SDSC; + sd_disk_info.ulNofBlock = 0; + sd_disk_info.ulBlockSize = 0; + sd_disk_info.bStatus = STA_NOINIT; + sd_disk_info.usRCA = 0; +} + +//***************************************************************************** +// +//! Reads sector(s) from the disk drive. +//! +//! +//! This function reads specified number of sectors from the drive +//! +//! \return Returns RES_OK on success. +// +//***************************************************************************** +DRESULT sd_disk_read (BYTE* pBuffer, DWORD ulSectorNumber, UINT SectorCount) { + DRESULT Res = RES_ERROR; + unsigned long ulSize; + + if (SectorCount > 0) { + // Return if disk not initialized + if (sd_disk_info.bStatus & STA_NOINIT) { + return RES_NOTRDY; + } + + // SDSC uses linear address, SDHC uses block address + if (sd_disk_info.ulCapClass == CARD_CAP_CLASS_SDSC) { + ulSectorNumber = ulSectorNumber * SD_SECTOR_SIZE; + } + + // Set the block count + MAP_SDHostBlockCountSet(SDHOST_BASE, SectorCount); + + // Compute the number of words + ulSize = (SD_SECTOR_SIZE * SectorCount) / 4; + + // Check if 1 block or multi block transfer + if (SectorCount == 1) { + // Send single block read command + if (CardSendCmd(CMD_READ_SINGLE_BLK, ulSectorNumber) == 0) { + // Read the block of data + while (ulSize--) { + MAP_SDHostDataRead(SDHOST_BASE, (unsigned long *)pBuffer); + pBuffer += 4; + } + Res = RES_OK; + } + } + else { + // Send multi block read command + if (CardSendCmd(CMD_READ_MULTI_BLK, ulSectorNumber) == 0) { + // Read the data + while (ulSize--) { + MAP_SDHostDataRead(SDHOST_BASE, (unsigned long *)pBuffer); + pBuffer += 4; + } + CardSendCmd(CMD_STOP_TRANS, 0); + while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC)); + Res = RES_OK; + } + } + } + + return Res; +} + +//***************************************************************************** +// +//! Wrties sector(s) to the disk drive. +//! +//! +//! This function writes specified number of sectors to the drive +//! +//! \return Returns RES_OK on success. +// +//***************************************************************************** +DRESULT sd_disk_write (const BYTE* pBuffer, DWORD ulSectorNumber, UINT SectorCount) { + DRESULT Res = RES_ERROR; + unsigned long ulSize; + + if (SectorCount > 0) { + // Return if disk not initialized + if (sd_disk_info.bStatus & STA_NOINIT) { + return RES_NOTRDY; + } + + // SDSC uses linear address, SDHC uses block address + if (sd_disk_info.ulCapClass == CARD_CAP_CLASS_SDSC) { + ulSectorNumber = ulSectorNumber * SD_SECTOR_SIZE; + } + + // Set the block count + MAP_SDHostBlockCountSet(SDHOST_BASE, SectorCount); + + // Compute the number of words + ulSize = (SD_SECTOR_SIZE * SectorCount) / 4; + + // Check if 1 block or multi block transfer + if (SectorCount == 1) { + // Send single block write command + if (CardSendCmd(CMD_WRITE_SINGLE_BLK, ulSectorNumber) == 0) { + // Write the data + while (ulSize--) { + MAP_SDHostDataWrite (SDHOST_BASE, (*(unsigned long *)pBuffer)); + pBuffer += 4; + } + // Wait for data transfer complete + while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC)); + Res = RES_OK; + } + } + else { + // Set the card write block count + if (sd_disk_info.ucCardType == CARD_TYPE_SDCARD) { + CardSendCmd(CMD_APP_CMD,sd_disk_info.usRCA << 16); + CardSendCmd(CMD_SET_BLK_CNT, SectorCount); + } + + // Send multi block write command + if (CardSendCmd(CMD_WRITE_MULTI_BLK, ulSectorNumber) == 0) { + // Write the data buffer + while (ulSize--) { + MAP_SDHostDataWrite(SDHOST_BASE, (*(unsigned long *)pBuffer)); + pBuffer += 4; + } + // Wait for transfer complete + while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC)); + CardSendCmd(CMD_STOP_TRANS, 0); + while (!(MAP_SDHostIntStatus(SDHOST_BASE) & SDHOST_INT_TC)); + Res = RES_OK; + } + } + } + + return Res; +} diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.h b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.h new file mode 100755 index 0000000..b5a1944 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sd_diskio.h @@ -0,0 +1,27 @@ +#ifndef SD_DISKIO_H_ +#define SD_DISKIO_H_ + +#define SD_SECTOR_SIZE 512 + +//***************************************************************************** +// Disk Info Structure definition +//***************************************************************************** +typedef struct +{ + unsigned char ucCardType; + unsigned int ulVersion; + unsigned int ulCapClass; + unsigned int ulNofBlock; + unsigned int ulBlockSize; + DSTATUS bStatus; + unsigned short usRCA; +}DiskInfo_t; + +extern DiskInfo_t sd_disk_info; + +DSTATUS sd_disk_init (void); +void sd_disk_deinit (void); +DRESULT sd_disk_read (BYTE* pBuffer, DWORD ulSectorNumber, UINT bSectorCount); +DRESULT sd_disk_write (const BYTE* pBuffer, DWORD ulSectorNumber, UINT bSectorCount); + +#endif /* SD_DISKIO_H_ */ diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.c b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.c new file mode 100755 index 0000000..6a1fc40 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.c @@ -0,0 +1,182 @@ +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "simplelink.h" +#include "sflash_diskio.h" +#include "debug.h" +#include "modnetwork.h" +#include "modwlan.h" + +#define SFLASH_TIMEOUT_MAX_MS 5500 +#define SFLASH_WAIT_TIME_MS 5 + +static _u8 sflash_block_name[] = "__NNN__.fsb"; +static _u8 *sflash_block_cache; +static bool sflash_init_done = false; +static bool sflash_cache_is_dirty; +static uint32_t sflash_ublock; +static uint32_t sflash_prblock; + + +static void print_block_name (_u32 ublock) { + char _sblock[4]; + snprintf (_sblock, sizeof(_sblock), "%03u", ublock); + memcpy (&sflash_block_name[2], _sblock, 3); +} + +static bool sflash_access (_u32 mode, _i32 (* sl_FsFunction)(_i32 FileHdl, _u32 Offset, _u8* pData, _u32 Len)) { + _i32 fileHandle; + bool retval = false; + + // wlan must be enabled in order to access the serial flash + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + + if (0 == sl_FsOpen(sflash_block_name, mode, NULL, &fileHandle)) { + if (SFLASH_BLOCK_SIZE == sl_FsFunction (fileHandle, 0, sflash_block_cache, SFLASH_BLOCK_SIZE)) { + retval = true; + } + sl_FsClose (fileHandle, NULL, NULL, 0); + } + sl_LockObjUnlock (&wlan_LockObj); + return retval; +} + +DRESULT sflash_disk_init (void) { + _i32 fileHandle; + SlFsFileInfo_t FsFileInfo; + + if (!sflash_init_done) { + // Allocate space for the block cache + ASSERT ((sflash_block_cache = mem_Malloc(SFLASH_BLOCK_SIZE)) != NULL); + sflash_init_done = true; + sflash_prblock = UINT32_MAX; + sflash_cache_is_dirty = false; + + // In order too speed up booting, check the last block, if exists, then + // it means that the file system has been already created + print_block_name (SFLASH_BLOCK_COUNT - 1); + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + if (!sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo)) { + sl_LockObjUnlock (&wlan_LockObj); + return RES_OK; + } + sl_LockObjUnlock (&wlan_LockObj); + + // Proceed to format the memory + for (int i = 0; i < SFLASH_BLOCK_COUNT; i++) { + print_block_name (i); + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + // Create the block file if it doesn't exist + if (sl_FsGetInfo(sflash_block_name, 0, &FsFileInfo) != 0) { + if (!sl_FsOpen(sflash_block_name, FS_MODE_OPEN_CREATE(SFLASH_BLOCK_SIZE, 0), NULL, &fileHandle)) { + sl_FsClose(fileHandle, NULL, NULL, 0); + sl_LockObjUnlock (&wlan_LockObj); + memset(sflash_block_cache, 0xFF, SFLASH_BLOCK_SIZE); + if (!sflash_access(FS_MODE_OPEN_WRITE, sl_FsWrite)) { + return RES_ERROR; + } + } + else { + // Unexpected failure while creating the file + sl_LockObjUnlock (&wlan_LockObj); + return RES_ERROR; + } + } + sl_LockObjUnlock (&wlan_LockObj); + } + } + return RES_OK; +} + +DRESULT sflash_disk_status(void) { + if (!sflash_init_done) { + return STA_NOINIT; + } + return RES_OK; +} + +DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count) { + uint32_t secindex; + + if (!sflash_init_done) { + return STA_NOINIT; + } + + if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) { + return RES_PARERR; + } + + for (int i = 0; i < count; i++) { + secindex = (sector + i) % SFLASH_SECTORS_PER_BLOCK; + sflash_ublock = (sector + i) / SFLASH_SECTORS_PER_BLOCK; + // See if it's time to read a new block + if (sflash_prblock != sflash_ublock) { + if (sflash_disk_flush() != RES_OK) { + return RES_ERROR; + } + sflash_prblock = sflash_ublock; + print_block_name (sflash_ublock); + if (!sflash_access(FS_MODE_OPEN_READ, sl_FsRead)) { + return RES_ERROR; + } + } + // Copy the requested sector from the block cache + memcpy (buff, &sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], SFLASH_SECTOR_SIZE); + buff += SFLASH_SECTOR_SIZE; + } + return RES_OK; +} + +DRESULT sflash_disk_write(const BYTE *buff, DWORD sector, UINT count) { + uint32_t secindex; + int32_t index = 0; + + if (!sflash_init_done) { + return STA_NOINIT; + } + + if ((sector + count > SFLASH_SECTOR_COUNT) || (count == 0)) { + sflash_disk_flush(); + return RES_PARERR; + } + + do { + secindex = (sector + index) % SFLASH_SECTORS_PER_BLOCK; + sflash_ublock = (sector + index) / SFLASH_SECTORS_PER_BLOCK; + // Check if it's a different block than last time + if (sflash_prblock != sflash_ublock) { + if (sflash_disk_flush() != RES_OK) { + return RES_ERROR; + } + sflash_prblock = sflash_ublock; + print_block_name (sflash_ublock); + // Read the block into the cache + if (!sflash_access(FS_MODE_OPEN_READ, sl_FsRead)) { + return RES_ERROR; + } + } + // Copy the input sector to the block cache + memcpy (&sflash_block_cache[(secindex * SFLASH_SECTOR_SIZE)], buff, SFLASH_SECTOR_SIZE); + buff += SFLASH_SECTOR_SIZE; + sflash_cache_is_dirty = true; + } while (++index < count); + + return RES_OK; +} + +DRESULT sflash_disk_flush (void) { + // Write back the cache if it's dirty + if (sflash_cache_is_dirty) { + if (!sflash_access(FS_MODE_OPEN_WRITE, sl_FsWrite)) { + return RES_ERROR; + } + sflash_cache_is_dirty = false; + } + return RES_OK; +} + diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.h b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.h new file mode 100755 index 0000000..de30934 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/sflash_diskio.h @@ -0,0 +1,16 @@ +#ifndef SFLASH_DISKIO_H_ +#define SFLASH_DISKIO_H_ + +#define SFLASH_BLOCK_SIZE 2048 +#define SFLASH_BLOCK_COUNT MICROPY_PORT_SFLASH_BLOCK_COUNT +#define SFLASH_SECTOR_SIZE 512 +#define SFLASH_SECTOR_COUNT ((SFLASH_BLOCK_SIZE * SFLASH_BLOCK_COUNT) / SFLASH_SECTOR_SIZE) +#define SFLASH_SECTORS_PER_BLOCK (SFLASH_BLOCK_SIZE / SFLASH_SECTOR_SIZE) + +DRESULT sflash_disk_init(void); +DRESULT sflash_disk_status(void); +DRESULT sflash_disk_read(BYTE *buff, DWORD sector, UINT count); +DRESULT sflash_disk_write(const BYTE *buff, DWORD sector, UINT count); +DRESULT sflash_disk_flush(void); + +#endif /* SFLASH_DISKIO_H_ */ diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/stdcmd.h b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/stdcmd.h new file mode 100755 index 0000000..464e2dd --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs/src/drivers/stdcmd.h @@ -0,0 +1,62 @@ +//***************************************************************************** +// stdcmd.h +// +// Defines standard SD Card commands for CC3200 SDHOST module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __STDCMD_H__ +#define __STDCMD_H__ + +//***************************************************************************** +// Standard MMC/SD Card Commands +//***************************************************************************** +#define CMD_GO_IDLE_STATE SDHOST_CMD_0 +#define CMD_SEND_IF_COND SDHOST_CMD_8|SDHOST_RESP_LEN_48 +#define CMD_SEND_CSD SDHOST_CMD_9|SDHOST_RESP_LEN_136 +#define CMD_APP_CMD SDHOST_CMD_55|SDHOST_RESP_LEN_48 +#define CMD_SD_SEND_OP_COND SDHOST_CMD_41|SDHOST_RESP_LEN_48 +#define CMD_SEND_OP_COND SDHOST_CMD_1|SDHOST_RESP_LEN_48 +#define CMD_READ_SINGLE_BLK SDHOST_CMD_17|SDHOST_RD_CMD|SDHOST_RESP_LEN_48 +#define CMD_READ_MULTI_BLK SDHOST_CMD_18|SDHOST_RD_CMD|SDHOST_RESP_LEN_48|SDHOST_MULTI_BLK +#define CMD_WRITE_SINGLE_BLK SDHOST_CMD_24|SDHOST_WR_CMD|SDHOST_RESP_LEN_48 +#define CMD_WRITE_MULTI_BLK SDHOST_CMD_25|SDHOST_WR_CMD|SDHOST_RESP_LEN_48|SDHOST_MULTI_BLK +#define CMD_SELECT_CARD SDHOST_CMD_7|SDHOST_RESP_LEN_48B +#define CMD_DESELECT_CARD SDHOST_CMD_7 +#define CMD_STOP_TRANS SDHOST_CMD_12|SDHOST_RESP_LEN_48B +#define CMD_SET_BLK_CNT SDHOST_CMD_23|SDHOST_RESP_LEN_48 +#define CMD_ALL_SEND_CID SDHOST_CMD_2|SDHOST_RESP_LEN_136 +#define CMD_SEND_REL_ADDR SDHOST_CMD_3|SDHOST_RESP_LEN_48 + +#endif //__STDCMD_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/fatfs_port.c b/src/openmv/src/micropython/ports/cc3200/fatfs_port.c new file mode 100755 index 0000000..658c94e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/fatfs_port.c @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * Parts of this file are (C)ChaN, 2014, from FatFs option/syscall.c + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" +#include "lib/timeutils/timeutils.h" +#include "mods/pybrtc.h" + +#if _FS_REENTRANT +// Create a Synchronization Object +// This function is called in f_mount() function to create a new +// synchronization object, such as semaphore and mutex. +// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR. +int ff_cre_syncobj(FATFS *fatfs, _SYNC_t *sobj) { + vSemaphoreCreateBinary((*sobj)); + return (int)(*sobj != NULL); +} + +// Delete a Synchronization Object +// This function is called in f_mount() function to delete a synchronization +// object that created with ff_cre_syncobj function. +// A return of 0 indicates failure, and then f_mount() fails with FR_INT_ERR. +int ff_del_syncobj(_SYNC_t sobj) { + vSemaphoreDelete(sobj); + return 1; +} + +// Request Grant to Access the Volume +// This function is called on entering file functions to lock the volume. +// When a 0 is returned, the file function fails with FR_TIMEOUT. +int ff_req_grant(_SYNC_t sobj) { + return (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); +} + +// Release Grant to Access the Volume +// This function is called on leaving file functions to unlock the volume. +void ff_rel_grant(_SYNC_t sobj) { + xSemaphoreGive(sobj); +} + +#endif + +DWORD get_fattime(void) { + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm); + + return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) | + ((tm.tm_mday) << 16) | ((tm.tm_hour) << 11) | + ((tm.tm_min) << 5) | (tm.tm_sec >> 1); +} diff --git a/src/openmv/src/micropython/ports/cc3200/ftp/ftp.c b/src/openmv/src/micropython/ports/cc3200/ftp/ftp.c new file mode 100755 index 0000000..ee80e51 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/ftp/ftp.c @@ -0,0 +1,1152 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "pybrtc.h" +#include "ftp.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "modusocket.h" +#include "debug.h" +#include "serverstask.h" +#include "fifo.h" +#include "socketfifo.h" +#include "updater.h" +#include "moduos.h" + +/****************************************************************************** + DEFINE PRIVATE CONSTANTS + ******************************************************************************/ +#define FTP_CMD_PORT 21 +#define FTP_ACTIVE_DATA_PORT 20 +#define FTP_PASIVE_DATA_PORT 2024 +#define FTP_BUFFER_SIZE 512 +#define FTP_TX_RETRIES_MAX 25 +#define FTP_CMD_SIZE_MAX 6 +#define FTP_CMD_CLIENTS_MAX 1 +#define FTP_DATA_CLIENTS_MAX 1 +#define FTP_MAX_PARAM_SIZE (MICROPY_ALLOC_PATH_MAX + 1) +#define FTP_UNIX_TIME_20000101 946684800 +#define FTP_UNIX_TIME_20150101 1420070400 +#define FTP_UNIX_SECONDS_180_DAYS 15552000 +#define FTP_DATA_TIMEOUT_MS 5000 // 5 seconds +#define FTP_SOCKETFIFO_ELEMENTS_MAX 4 +#define FTP_CYCLE_TIME_MS (SERVERS_CYCLE_TIME_MS * 2) + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef enum { + E_FTP_RESULT_OK = 0, + E_FTP_RESULT_CONTINUE, + E_FTP_RESULT_FAILED +} ftp_result_t; + +typedef enum { + E_FTP_STE_DISABLED = 0, + E_FTP_STE_START, + E_FTP_STE_READY, + E_FTP_STE_END_TRANSFER, + E_FTP_STE_CONTINUE_LISTING, + E_FTP_STE_CONTINUE_FILE_TX, + E_FTP_STE_CONTINUE_FILE_RX +} ftp_state_t; + +typedef enum { + E_FTP_STE_SUB_DISCONNECTED = 0, + E_FTP_STE_SUB_LISTEN_FOR_DATA, + E_FTP_STE_SUB_DATA_CONNECTED +} ftp_substate_t; + +typedef struct { + bool uservalid : 1; + bool passvalid : 1; +} ftp_loggin_t; + +typedef enum { + E_FTP_NOTHING_OPEN = 0, + E_FTP_FILE_OPEN, + E_FTP_DIR_OPEN +} ftp_e_open_t; + +typedef enum { + E_FTP_CLOSE_NONE = 0, + E_FTP_CLOSE_DATA, + E_FTP_CLOSE_CMD_AND_DATA, +} ftp_e_closesocket_t; + +typedef struct { + uint8_t *dBuffer; + uint32_t ctimeout; + union { + FF_DIR dp; + FIL fp; + }; + int16_t lc_sd; + int16_t ld_sd; + int16_t c_sd; + int16_t d_sd; + int16_t dtimeout; + uint16_t volcount; + uint8_t state; + uint8_t substate; + uint8_t txRetries; + uint8_t logginRetries; + ftp_loggin_t loggin; + uint8_t e_open; + bool closechild; + bool enabled; + bool special_file; + bool listroot; +} ftp_data_t; + +typedef struct { + char * cmd; +} ftp_cmd_t; + +typedef struct { + char * month; +} ftp_month_t; + +typedef enum { + E_FTP_CMD_NOT_SUPPORTED = -1, + E_FTP_CMD_FEAT = 0, + E_FTP_CMD_SYST, + E_FTP_CMD_CDUP, + E_FTP_CMD_CWD, + E_FTP_CMD_PWD, + E_FTP_CMD_XPWD, + E_FTP_CMD_SIZE, + E_FTP_CMD_MDTM, + E_FTP_CMD_TYPE, + E_FTP_CMD_USER, + E_FTP_CMD_PASS, + E_FTP_CMD_PASV, + E_FTP_CMD_LIST, + E_FTP_CMD_RETR, + E_FTP_CMD_STOR, + E_FTP_CMD_DELE, + E_FTP_CMD_RMD, + E_FTP_CMD_MKD, + E_FTP_CMD_RNFR, + E_FTP_CMD_RNTO, + E_FTP_CMD_NOOP, + E_FTP_CMD_QUIT, + E_FTP_NUM_FTP_CMDS +} ftp_cmd_index_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +static ftp_data_t ftp_data; +static char *ftp_path; +static char *ftp_scratch_buffer; +static char *ftp_cmd_buffer; +static const ftp_cmd_t ftp_cmd_table[] = { { "FEAT" }, { "SYST" }, { "CDUP" }, { "CWD" }, + { "PWD" }, { "XPWD" }, { "SIZE" }, { "MDTM" }, + { "TYPE" }, { "USER" }, { "PASS" }, { "PASV" }, + { "LIST" }, { "RETR" }, { "STOR" }, { "DELE" }, + { "RMD" }, { "MKD" }, { "RNFR" }, { "RNTO" }, + { "NOOP" }, { "QUIT" } }; + +static const ftp_month_t ftp_month[] = { { "Jan" }, { "Feb" }, { "Mar" }, { "Apr" }, + { "May" }, { "Jun" }, { "Jul" }, { "Ago" }, + { "Sep" }, { "Oct" }, { "Nov" }, { "Dec" } }; + +static SocketFifoElement_t ftp_fifoelements[FTP_SOCKETFIFO_ELEMENTS_MAX]; +static FIFO_t ftp_socketfifo; + +/****************************************************************************** + DEFINE VFS WRAPPER FUNCTIONS + ******************************************************************************/ + +// These wrapper functions are used so that the FTP server can access the +// mounted FATFS devices directly without going through the costly mp_vfs_XXX +// functions. The latter may raise exceptions and we would then need to wrap +// all calls in an nlr handler. The wrapper functions below assume that there +// are only FATFS filesystems mounted. + +STATIC FATFS *lookup_path(const TCHAR **path) { + mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path); + if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) { + return NULL; + } + // here we assume that the mounted device is FATFS + return &((fs_user_mount_t*)MP_OBJ_TO_PTR(fs->obj))->fatfs; +} + +STATIC FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_open(fs, fp, path, mode); +} + +STATIC FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_opendir(fs, dp, path); +} + +STATIC FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_stat(fs, path, fno); +} + +STATIC FRESULT f_mkdir_helper(const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_mkdir(fs, path); +} + +STATIC FRESULT f_unlink_helper(const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_unlink(fs, path); +} + +STATIC FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new) { + FATFS *fs_old = lookup_path(&path_old); + if (fs_old == NULL) { + return FR_NO_PATH; + } + FATFS *fs_new = lookup_path(&path_new); + if (fs_new == NULL) { + return FR_NO_PATH; + } + if (fs_old != fs_new) { + return FR_NO_PATH; + } + return f_rename(fs_new, path_old, path_new); +} + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +static void ftp_wait_for_enabled (void); +static bool ftp_create_listening_socket (_i16 *sd, _u16 port, _u8 backlog); +static ftp_result_t ftp_wait_for_connection (_i16 l_sd, _i16 *n_sd); +static ftp_result_t ftp_send_non_blocking (_i16 sd, void *data, _i16 Len); +static void ftp_send_reply (_u16 status, char *message); +static void ftp_send_data (_u32 datasize); +static void ftp_send_from_fifo (void); +static ftp_result_t ftp_recv_non_blocking (_i16 sd, void *buff, _i16 Maxlen, _i32 *rxLen); +static void ftp_process_cmd (void); +static void ftp_close_files (void); +static void ftp_close_filesystem_on_error (void); +static void ftp_close_cmd_data (void); +static ftp_cmd_index_t ftp_pop_command (char **str); +static void ftp_pop_param (char **str, char *param); +static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno); +static int ftp_print_eplf_drive (char *dest, uint32_t destsize, const char *name); +static bool ftp_open_file (const char *path, int mode); +static ftp_result_t ftp_read_file (char *filebuf, uint32_t desiredsize, uint32_t *actualsize); +static ftp_result_t ftp_write_file (char *filebuf, uint32_t size); +static ftp_result_t ftp_open_dir_for_listing (const char *path); +static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *listsize); +static void ftp_open_child (char *pwd, char *dir); +static void ftp_close_child (char *pwd); +static void ftp_return_to_previous_path (char *pwd, char *dir); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void ftp_init (void) { + // Allocate memory for the data buffer, and the file system structs (from the RTOS heap) + ASSERT ((ftp_data.dBuffer = mem_Malloc(FTP_BUFFER_SIZE)) != NULL); + ASSERT ((ftp_path = mem_Malloc(FTP_MAX_PARAM_SIZE)) != NULL); + ASSERT ((ftp_scratch_buffer = mem_Malloc(FTP_MAX_PARAM_SIZE)) != NULL); + ASSERT ((ftp_cmd_buffer = mem_Malloc(FTP_MAX_PARAM_SIZE + FTP_CMD_SIZE_MAX)) != NULL); + SOCKETFIFO_Init (&ftp_socketfifo, (void *)ftp_fifoelements, FTP_SOCKETFIFO_ELEMENTS_MAX); + ftp_data.c_sd = -1; + ftp_data.d_sd = -1; + ftp_data.lc_sd = -1; + ftp_data.ld_sd = -1; + ftp_data.e_open = E_FTP_NOTHING_OPEN; + ftp_data.state = E_FTP_STE_DISABLED; + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + ftp_data.special_file = false; + ftp_data.volcount = 0; +} + +void ftp_run (void) { + switch (ftp_data.state) { + case E_FTP_STE_DISABLED: + ftp_wait_for_enabled(); + break; + case E_FTP_STE_START: + if (wlan_is_connected() && ftp_create_listening_socket(&ftp_data.lc_sd, FTP_CMD_PORT, FTP_CMD_CLIENTS_MAX - 1)) { + ftp_data.state = E_FTP_STE_READY; + } + break; + case E_FTP_STE_READY: + if (ftp_data.c_sd < 0 && ftp_data.substate == E_FTP_STE_SUB_DISCONNECTED) { + if (E_FTP_RESULT_OK == ftp_wait_for_connection(ftp_data.lc_sd, &ftp_data.c_sd)) { + ftp_data.txRetries = 0; + ftp_data.logginRetries = 0; + ftp_data.ctimeout = 0; + ftp_data.loggin.uservalid = false; + ftp_data.loggin.passvalid = false; + strcpy (ftp_path, "/"); + ftp_send_reply (220, "MicroPython FTP Server"); + break; + } + } + if (SOCKETFIFO_IsEmpty()) { + if (ftp_data.c_sd > 0 && ftp_data.substate != E_FTP_STE_SUB_LISTEN_FOR_DATA) { + ftp_process_cmd(); + if (ftp_data.state != E_FTP_STE_READY) { + break; + } + } + } + break; + case E_FTP_STE_END_TRANSFER: + break; + case E_FTP_STE_CONTINUE_LISTING: + // go on with listing only if the transmit buffer is empty + if (SOCKETFIFO_IsEmpty()) { + uint32_t listsize; + ftp_list_dir((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, &listsize); + if (listsize > 0) { + ftp_send_data(listsize); + } else { + ftp_send_reply(226, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + ftp_data.ctimeout = 0; + } + break; + case E_FTP_STE_CONTINUE_FILE_TX: + // read the next block from the file only if the previous one has been sent + if (SOCKETFIFO_IsEmpty()) { + uint32_t readsize; + ftp_result_t result; + ftp_data.ctimeout = 0; + result = ftp_read_file ((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, &readsize); + if (result == E_FTP_RESULT_FAILED) { + ftp_send_reply(451, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + else { + if (readsize > 0) { + ftp_send_data(readsize); + } + if (result == E_FTP_RESULT_OK) { + ftp_send_reply(226, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + } + } + break; + case E_FTP_STE_CONTINUE_FILE_RX: + if (SOCKETFIFO_IsEmpty()) { + _i32 len; + ftp_result_t result; + if (E_FTP_RESULT_OK == (result = ftp_recv_non_blocking(ftp_data.d_sd, ftp_data.dBuffer, FTP_BUFFER_SIZE, &len))) { + ftp_data.dtimeout = 0; + ftp_data.ctimeout = 0; + // its a software update + if (ftp_data.special_file) { + if (updater_write(ftp_data.dBuffer, len)) { + break; + } + } + // user file being received + else if (E_FTP_RESULT_OK == ftp_write_file ((char *)ftp_data.dBuffer, len)) { + break; + } + ftp_send_reply(451, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + else if (result == E_FTP_RESULT_CONTINUE) { + if (ftp_data.dtimeout++ > FTP_DATA_TIMEOUT_MS / FTP_CYCLE_TIME_MS) { + ftp_close_files(); + ftp_send_reply(426, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + } + else { + if (ftp_data.special_file) { + ftp_data.special_file = false; + updater_finnish(); + } + ftp_close_files(); + ftp_send_reply(226, NULL); + ftp_data.state = E_FTP_STE_END_TRANSFER; + } + } + break; + default: + break; + } + + switch (ftp_data.substate) { + case E_FTP_STE_SUB_DISCONNECTED: + break; + case E_FTP_STE_SUB_LISTEN_FOR_DATA: + if (E_FTP_RESULT_OK == ftp_wait_for_connection(ftp_data.ld_sd, &ftp_data.d_sd)) { + ftp_data.dtimeout = 0; + ftp_data.substate = E_FTP_STE_SUB_DATA_CONNECTED; + } + else if (ftp_data.dtimeout++ > FTP_DATA_TIMEOUT_MS / FTP_CYCLE_TIME_MS) { + ftp_data.dtimeout = 0; + // close the listening socket + servers_close_socket(&ftp_data.ld_sd); + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + } + break; + case E_FTP_STE_SUB_DATA_CONNECTED: + if (ftp_data.state == E_FTP_STE_READY && ftp_data.dtimeout++ > FTP_DATA_TIMEOUT_MS / FTP_CYCLE_TIME_MS) { + // close the listening and the data socket + servers_close_socket(&ftp_data.ld_sd); + servers_close_socket(&ftp_data.d_sd); + ftp_close_filesystem_on_error (); + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + } + break; + default: + break; + } + + // send data pending in the queue + ftp_send_from_fifo(); + + // check the state of the data sockets + if (ftp_data.d_sd < 0 && (ftp_data.state > E_FTP_STE_READY)) { + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + ftp_data.state = E_FTP_STE_READY; + } +} + +void ftp_enable (void) { + ftp_data.enabled = true; +} + +void ftp_disable (void) { + ftp_reset(); + ftp_data.enabled = false; + ftp_data.state = E_FTP_STE_DISABLED; +} + +void ftp_reset (void) { + // close all connections and start all over again + servers_close_socket(&ftp_data.lc_sd); + servers_close_socket(&ftp_data.ld_sd); + ftp_close_cmd_data(); + ftp_data.state = E_FTP_STE_START; + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + ftp_data.volcount = 0; + SOCKETFIFO_Flush(); +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +static void ftp_wait_for_enabled (void) { + // Check if the telnet service has been enabled + if (ftp_data.enabled) { + ftp_data.state = E_FTP_STE_START; + } +} + +static bool ftp_create_listening_socket (_i16 *sd, _u16 port, _u8 backlog) { + SlSockNonblocking_t nonBlockingOption; + SlSockAddrIn_t sServerAddress; + _i16 _sd; + _i16 result; + + // Open a socket for ftp data listen + ASSERT ((*sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_IPPROTO_IP)) > 0); + _sd = *sd; + + if (_sd > 0) { + // add the new socket to the network administration + modusocket_socket_add(_sd, false); + + // Enable non-blocking mode + nonBlockingOption.NonblockingEnabled = 1; + ASSERT ((result = sl_SetSockOpt(_sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK); + + // Bind the socket to a port number + sServerAddress.sin_family = SL_AF_INET; + sServerAddress.sin_addr.s_addr = SL_INADDR_ANY; + sServerAddress.sin_port = sl_Htons(port); + + ASSERT ((result |= sl_Bind(_sd, (const SlSockAddr_t *)&sServerAddress, sizeof(sServerAddress))) == SL_SOC_OK); + + // Start listening + ASSERT ((result |= sl_Listen (_sd, backlog)) == SL_SOC_OK); + + if (result == SL_SOC_OK) { + return true; + } + servers_close_socket(sd); + } + return false; +} + +static ftp_result_t ftp_wait_for_connection (_i16 l_sd, _i16 *n_sd) { + SlSockAddrIn_t sClientAddress; + SlSocklen_t in_addrSize; + + // accepts a connection from a TCP client, if there is any, otherwise returns SL_EAGAIN + *n_sd = sl_Accept(l_sd, (SlSockAddr_t *)&sClientAddress, (SlSocklen_t *)&in_addrSize); + _i16 _sd = *n_sd; + if (_sd == SL_EAGAIN) { + return E_FTP_RESULT_CONTINUE; + } + else if (_sd < 0) { + // error + ftp_reset(); + return E_FTP_RESULT_FAILED; + } + + // add the new socket to the network administration + modusocket_socket_add(_sd, false); + + // client connected, so go on + return E_FTP_RESULT_OK; +} + +static ftp_result_t ftp_send_non_blocking (_i16 sd, void *data, _i16 Len) { + int16_t result = sl_Send(sd, data, Len, 0); + + if (result > 0) { + ftp_data.txRetries = 0; + return E_FTP_RESULT_OK; + } + else if ((FTP_TX_RETRIES_MAX >= ++ftp_data.txRetries) && (result == SL_EAGAIN)) { + return E_FTP_RESULT_CONTINUE; + } + else { + // error + ftp_reset(); + return E_FTP_RESULT_FAILED; + } +} + +static void ftp_send_reply (_u16 status, char *message) { + SocketFifoElement_t fifoelement; + if (!message) { + message = ""; + } + snprintf((char *)ftp_cmd_buffer, 4, "%u", status); + strcat ((char *)ftp_cmd_buffer, " "); + strcat ((char *)ftp_cmd_buffer, message); + strcat ((char *)ftp_cmd_buffer, "\r\n"); + fifoelement.sd = &ftp_data.c_sd; + fifoelement.datasize = strlen((char *)ftp_cmd_buffer); + fifoelement.data = mem_Malloc(fifoelement.datasize); + if (status == 221) { + fifoelement.closesockets = E_FTP_CLOSE_CMD_AND_DATA; + } + else if (status == 426 || status == 451 || status == 550) { + fifoelement.closesockets = E_FTP_CLOSE_DATA; + } + else { + fifoelement.closesockets = E_FTP_CLOSE_NONE; + } + fifoelement.freedata = true; + if (fifoelement.data) { + memcpy (fifoelement.data, ftp_cmd_buffer, fifoelement.datasize); + if (!SOCKETFIFO_Push (&fifoelement)) { + mem_Free(fifoelement.data); + } + } +} + +static void ftp_send_data (_u32 datasize) { + SocketFifoElement_t fifoelement; + + fifoelement.data = ftp_data.dBuffer; + fifoelement.datasize = datasize; + fifoelement.sd = &ftp_data.d_sd; + fifoelement.closesockets = E_FTP_CLOSE_NONE; + fifoelement.freedata = false; + SOCKETFIFO_Push (&fifoelement); +} + +static void ftp_send_from_fifo (void) { + SocketFifoElement_t fifoelement; + if (SOCKETFIFO_Peek (&fifoelement)) { + _i16 _sd = *fifoelement.sd; + if (_sd > 0) { + if (E_FTP_RESULT_OK == ftp_send_non_blocking (_sd, fifoelement.data, fifoelement.datasize)) { + SOCKETFIFO_Pop (&fifoelement); + if (fifoelement.closesockets != E_FTP_CLOSE_NONE) { + servers_close_socket(&ftp_data.d_sd); + if (fifoelement.closesockets == E_FTP_CLOSE_CMD_AND_DATA) { + servers_close_socket(&ftp_data.ld_sd); + // this one is the command socket + servers_close_socket(fifoelement.sd); + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + } + ftp_close_filesystem_on_error(); + } + if (fifoelement.freedata) { + mem_Free(fifoelement.data); + } + } + } + // socket closed, remove from the queue + else { + SOCKETFIFO_Pop (&fifoelement); + if (fifoelement.freedata) { + mem_Free(fifoelement.data); + } + } + } + else if (ftp_data.state == E_FTP_STE_END_TRANSFER && (ftp_data.d_sd > 0)) { + // close the listening and the data sockets + servers_close_socket(&ftp_data.ld_sd); + servers_close_socket(&ftp_data.d_sd); + if (ftp_data.special_file) { + ftp_data.special_file = false; + } + } +} + +static ftp_result_t ftp_recv_non_blocking (_i16 sd, void *buff, _i16 Maxlen, _i32 *rxLen) { + *rxLen = sl_Recv(sd, buff, Maxlen, 0); + + if (*rxLen > 0) { + return E_FTP_RESULT_OK; + } + else if (*rxLen != SL_EAGAIN) { + // error + return E_FTP_RESULT_FAILED; + } + return E_FTP_RESULT_CONTINUE; +} + +static void ftp_get_param_and_open_child (char **bufptr) { + ftp_pop_param (bufptr, ftp_scratch_buffer); + ftp_open_child (ftp_path, ftp_scratch_buffer); + ftp_data.closechild = true; +} + +static void ftp_process_cmd (void) { + _i32 len; + char *bufptr = (char *)ftp_cmd_buffer; + ftp_result_t result; + FRESULT fres; + FILINFO fno; + + ftp_data.closechild = false; + // also use the reply buffer to receive new commands + if (E_FTP_RESULT_OK == (result = ftp_recv_non_blocking(ftp_data.c_sd, ftp_cmd_buffer, FTP_MAX_PARAM_SIZE + FTP_CMD_SIZE_MAX, &len))) { + // bufptr is moved as commands are being popped + ftp_cmd_index_t cmd = ftp_pop_command(&bufptr); + if (!ftp_data.loggin.passvalid && (cmd != E_FTP_CMD_USER && cmd != E_FTP_CMD_PASS && cmd != E_FTP_CMD_QUIT)) { + ftp_send_reply(332, NULL); + return; + } + switch (cmd) { + case E_FTP_CMD_FEAT: + ftp_send_reply(211, "no-features"); + break; + case E_FTP_CMD_SYST: + ftp_send_reply(215, "UNIX Type: L8"); + break; + case E_FTP_CMD_CDUP: + ftp_close_child(ftp_path); + ftp_send_reply(250, NULL); + break; + case E_FTP_CMD_CWD: + { + fres = FR_NO_PATH; + ftp_pop_param (&bufptr, ftp_scratch_buffer); + ftp_open_child (ftp_path, ftp_scratch_buffer); + if ((ftp_path[0] == '/' && ftp_path[1] == '\0') || ((fres = f_opendir_helper (&ftp_data.dp, ftp_path)) == FR_OK)) { + if (fres == FR_OK) { + f_closedir(&ftp_data.dp); + } + ftp_send_reply(250, NULL); + } + else { + ftp_close_child (ftp_path); + ftp_send_reply(550, NULL); + } + } + break; + case E_FTP_CMD_PWD: + case E_FTP_CMD_XPWD: + ftp_send_reply(257, ftp_path); + break; + case E_FTP_CMD_SIZE: + { + ftp_get_param_and_open_child (&bufptr); + if (FR_OK == f_stat_helper(ftp_path, &fno)) { + // send the size + snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "%u", (_u32)fno.fsize); + ftp_send_reply(213, (char *)ftp_data.dBuffer); + } + else { + ftp_send_reply(550, NULL); + } + } + break; + case E_FTP_CMD_MDTM: + ftp_get_param_and_open_child (&bufptr); + if (FR_OK == f_stat_helper(ftp_path, &fno)) { + // send the last modified time + snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "%u%02u%02u%02u%02u%02u", + 1980 + ((fno.fdate >> 9) & 0x7f), (fno.fdate >> 5) & 0x0f, + fno.fdate & 0x1f, (fno.ftime >> 11) & 0x1f, + (fno.ftime >> 5) & 0x3f, 2 * (fno.ftime & 0x1f)); + ftp_send_reply(213, (char *)ftp_data.dBuffer); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_TYPE: + ftp_send_reply(200, NULL); + break; + case E_FTP_CMD_USER: + ftp_pop_param (&bufptr, ftp_scratch_buffer); + if (!memcmp(ftp_scratch_buffer, servers_user, MAX(strlen(ftp_scratch_buffer), strlen(servers_user)))) { + ftp_data.loggin.uservalid = true && (strlen(servers_user) == strlen(ftp_scratch_buffer)); + } + ftp_send_reply(331, NULL); + break; + case E_FTP_CMD_PASS: + ftp_pop_param (&bufptr, ftp_scratch_buffer); + if (!memcmp(ftp_scratch_buffer, servers_pass, MAX(strlen(ftp_scratch_buffer), strlen(servers_pass))) && + ftp_data.loggin.uservalid) { + ftp_data.loggin.passvalid = true && (strlen(servers_pass) == strlen(ftp_scratch_buffer)); + if (ftp_data.loggin.passvalid) { + ftp_send_reply(230, NULL); + break; + } + } + ftp_send_reply(530, NULL); + break; + case E_FTP_CMD_PASV: + { + // some servers (e.g. google chrome) send PASV several times very quickly + servers_close_socket(&ftp_data.d_sd); + ftp_data.substate = E_FTP_STE_SUB_DISCONNECTED; + bool socketcreated = true; + if (ftp_data.ld_sd < 0) { + socketcreated = ftp_create_listening_socket(&ftp_data.ld_sd, FTP_PASIVE_DATA_PORT, FTP_DATA_CLIENTS_MAX - 1); + } + if (socketcreated) { + uint32_t ip; + uint8_t *pip = (uint8_t *)&ip; + ftp_data.dtimeout = 0; + wlan_get_ip(&ip); + snprintf((char *)ftp_data.dBuffer, FTP_BUFFER_SIZE, "(%u,%u,%u,%u,%u,%u)", + pip[3], pip[2], pip[1], pip[0], (FTP_PASIVE_DATA_PORT >> 8), (FTP_PASIVE_DATA_PORT & 0xFF)); + ftp_data.substate = E_FTP_STE_SUB_LISTEN_FOR_DATA; + ftp_send_reply(227, (char *)ftp_data.dBuffer); + } + else { + ftp_send_reply(425, NULL); + } + } + break; + case E_FTP_CMD_LIST: + if (ftp_open_dir_for_listing(ftp_path) == E_FTP_RESULT_CONTINUE) { + ftp_data.state = E_FTP_STE_CONTINUE_LISTING; + ftp_send_reply(150, NULL); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_RETR: + ftp_get_param_and_open_child (&bufptr); + if (ftp_open_file (ftp_path, FA_READ)) { + ftp_data.state = E_FTP_STE_CONTINUE_FILE_TX; + ftp_send_reply(150, NULL); + } + else { + ftp_data.state = E_FTP_STE_END_TRANSFER; + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_STOR: + ftp_get_param_and_open_child (&bufptr); + // first check if a software update is being requested + if (updater_check_path (ftp_path)) { + if (updater_start()) { + ftp_data.special_file = true; + ftp_data.state = E_FTP_STE_CONTINUE_FILE_RX; + ftp_send_reply(150, NULL); + } + else { + // to unlock the updater + updater_finnish(); + ftp_data.state = E_FTP_STE_END_TRANSFER; + ftp_send_reply(550, NULL); + } + } + else { + if (ftp_open_file (ftp_path, FA_WRITE | FA_CREATE_ALWAYS)) { + ftp_data.state = E_FTP_STE_CONTINUE_FILE_RX; + ftp_send_reply(150, NULL); + } + else { + ftp_data.state = E_FTP_STE_END_TRANSFER; + ftp_send_reply(550, NULL); + } + } + break; + case E_FTP_CMD_DELE: + case E_FTP_CMD_RMD: + ftp_get_param_and_open_child (&bufptr); + if (FR_OK == f_unlink_helper(ftp_path)) { + ftp_send_reply(250, NULL); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_MKD: + ftp_get_param_and_open_child (&bufptr); + if (FR_OK == f_mkdir_helper(ftp_path)) { + ftp_send_reply(250, NULL); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_RNFR: + ftp_get_param_and_open_child (&bufptr); + if (FR_OK == f_stat_helper(ftp_path, &fno)) { + ftp_send_reply(350, NULL); + // save the current path + strcpy ((char *)ftp_data.dBuffer, ftp_path); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_RNTO: + ftp_get_param_and_open_child (&bufptr); + // old path was saved in the data buffer + if (FR_OK == (fres = f_rename_helper((char *)ftp_data.dBuffer, ftp_path))) { + ftp_send_reply(250, NULL); + } + else { + ftp_send_reply(550, NULL); + } + break; + case E_FTP_CMD_NOOP: + ftp_send_reply(200, NULL); + break; + case E_FTP_CMD_QUIT: + ftp_send_reply(221, NULL); + break; + default: + // command not implemented + ftp_send_reply(502, NULL); + break; + } + + if (ftp_data.closechild) { + ftp_return_to_previous_path(ftp_path, ftp_scratch_buffer); + } + } + else if (result == E_FTP_RESULT_CONTINUE) { + if (ftp_data.ctimeout++ > (servers_get_timeout() / FTP_CYCLE_TIME_MS)) { + ftp_send_reply(221, NULL); + } + } + else { + ftp_close_cmd_data (); + } +} + +static void ftp_close_files (void) { + if (ftp_data.e_open == E_FTP_FILE_OPEN) { + f_close(&ftp_data.fp); + } + else if (ftp_data.e_open == E_FTP_DIR_OPEN) { + f_closedir(&ftp_data.dp); + } + ftp_data.e_open = E_FTP_NOTHING_OPEN; +} + +static void ftp_close_filesystem_on_error (void) { + ftp_close_files(); + if (ftp_data.special_file) { + updater_finnish (); + ftp_data.special_file = false; + } +} + +static void ftp_close_cmd_data (void) { + servers_close_socket(&ftp_data.c_sd); + servers_close_socket(&ftp_data.d_sd); + ftp_close_filesystem_on_error (); +} + +static void stoupper (char *str) { + while (str && *str != '\0') { + *str = (char)unichar_toupper((int)(*str)); + str++; + } +} + +static ftp_cmd_index_t ftp_pop_command (char **str) { + char _cmd[FTP_CMD_SIZE_MAX]; + ftp_pop_param (str, _cmd); + stoupper (_cmd); + for (ftp_cmd_index_t i = 0; i < E_FTP_NUM_FTP_CMDS; i++) { + if (!strcmp (_cmd, ftp_cmd_table[i].cmd)) { + // move one step further to skip the space + (*str)++; + return i; + } + } + return E_FTP_CMD_NOT_SUPPORTED; +} + +static void ftp_pop_param (char **str, char *param) { + while (**str != ' ' && **str != '\r' && **str != '\n' && **str != '\0') { + *param++ = **str; + (*str)++; + } + *param = '\0'; +} + +static int ftp_print_eplf_item (char *dest, uint32_t destsize, FILINFO *fno) { + + char *type = (fno->fattrib & AM_DIR) ? "d" : "-"; + uint32_t tseconds; + uint mindex = (((fno->fdate >> 5) & 0x0f) > 0) ? (((fno->fdate >> 5) & 0x0f) - 1) : 0; + uint day = ((fno->fdate & 0x1f) > 0) ? (fno->fdate & 0x1f) : 1; + uint fseconds = timeutils_seconds_since_2000(1980 + ((fno->fdate >> 9) & 0x7f), + (fno->fdate >> 5) & 0x0f, + fno->fdate & 0x1f, + (fno->ftime >> 11) & 0x1f, + (fno->ftime >> 5) & 0x3f, + 2 * (fno->ftime & 0x1f)); + tseconds = pyb_rtc_get_seconds(); + if (FTP_UNIX_SECONDS_180_DAYS < tseconds - fseconds) { + return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %5u %s\r\n", + type, (_u32)fno->fsize, ftp_month[mindex].month, day, + 1980 + ((fno->fdate >> 9) & 0x7f), fno->fname); + } + else { + return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %02u:%02u %s\r\n", + type, (_u32)fno->fsize, ftp_month[mindex].month, day, + (fno->ftime >> 11) & 0x1f, (fno->ftime >> 5) & 0x3f, fno->fname); + } +} + +static int ftp_print_eplf_drive (char *dest, uint32_t destsize, const char *name) { + timeutils_struct_time_t tm; + uint32_t tseconds; + char *type = "d"; + + timeutils_seconds_since_2000_to_struct_time((FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101), &tm); + + tseconds = pyb_rtc_get_seconds(); + if (FTP_UNIX_SECONDS_180_DAYS < tseconds - (FTP_UNIX_TIME_20150101 - FTP_UNIX_TIME_20000101)) { + return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %5u %s\r\n", + type, 0, ftp_month[(tm.tm_mon - 1)].month, tm.tm_mday, tm.tm_year, name); + } + else { + return snprintf(dest, destsize, "%srw-rw-r-- 1 root root %9u %s %2u %02u:%02u %s\r\n", + type, 0, ftp_month[(tm.tm_mon - 1)].month, tm.tm_mday, tm.tm_hour, tm.tm_min, name); + } +} + +static bool ftp_open_file (const char *path, int mode) { + FRESULT res = f_open_helper(&ftp_data.fp, path, mode); + if (res != FR_OK) { + return false; + } + ftp_data.e_open = E_FTP_FILE_OPEN; + return true; +} + +static ftp_result_t ftp_read_file (char *filebuf, uint32_t desiredsize, uint32_t *actualsize) { + ftp_result_t result = E_FTP_RESULT_CONTINUE; + FRESULT res = f_read(&ftp_data.fp, filebuf, desiredsize, (UINT *)actualsize); + if (res != FR_OK) { + ftp_close_files(); + result = E_FTP_RESULT_FAILED; + *actualsize = 0; + } + else if (*actualsize < desiredsize) { + ftp_close_files(); + result = E_FTP_RESULT_OK; + } + return result; +} + +static ftp_result_t ftp_write_file (char *filebuf, uint32_t size) { + ftp_result_t result = E_FTP_RESULT_FAILED; + uint32_t actualsize; + FRESULT res = f_write(&ftp_data.fp, filebuf, size, (UINT *)&actualsize); + if ((actualsize == size) && (FR_OK == res)) { + result = E_FTP_RESULT_OK; + } + else { + ftp_close_files(); + } + return result; +} + +static ftp_result_t ftp_open_dir_for_listing (const char *path) { + // "hack" to detect the root directory + if (path[0] == '/' && path[1] == '\0') { + ftp_data.listroot = true; + } else { + FRESULT res; + res = f_opendir_helper(&ftp_data.dp, path); /* Open the directory */ + if (res != FR_OK) { + return E_FTP_RESULT_FAILED; + } + ftp_data.e_open = E_FTP_DIR_OPEN; + ftp_data.listroot = false; + } + return E_FTP_RESULT_CONTINUE; +} + +static ftp_result_t ftp_list_dir (char *list, uint32_t maxlistsize, uint32_t *listsize) { + uint next = 0; + uint listcount = 0; + FRESULT res; + ftp_result_t result = E_FTP_RESULT_CONTINUE; + FILINFO fno; +#if _USE_LFN + // read up to 2 directory items + while (listcount < 2) { +#else + // read up to 4 directory items + while (listcount < 4) { +#endif + if (ftp_data.listroot) { + // root directory "hack" + mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); + int i = ftp_data.volcount; + while (vfs != NULL && i != 0) { + vfs = vfs->next; + i -= 1; + } + if (vfs == NULL) { + if (!next) { + // no volume found this time, we are done + ftp_data.volcount = 0; + } + break; + } else { + next += ftp_print_eplf_drive((list + next), (maxlistsize - next), vfs->str + 1); + } + ftp_data.volcount++; + } else { + // a "normal" directory + res = f_readdir(&ftp_data.dp, &fno); /* Read a directory item */ + if (res != FR_OK || fno.fname[0] == 0) { + result = E_FTP_RESULT_OK; + break; /* Break on error or end of dp */ + } + if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */ + if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */ + + // add the entry to the list + next += ftp_print_eplf_item((list + next), (maxlistsize - next), &fno); + } + listcount++; + } + if (result == E_FTP_RESULT_OK) { + ftp_close_files(); + } + *listsize = next; + return result; +} + +static void ftp_open_child (char *pwd, char *dir) { + if (dir[0] == '/') { + strcpy (pwd, dir); + } else { + if (strlen(pwd) > 1) { + strcat (pwd, "/"); + } + strcat (pwd, dir); + } + + uint len = strlen(pwd); + if ((len > 1) && (pwd[len - 1] == '/')) { + pwd[len - 1] = '\0'; + } +} + +static void ftp_close_child (char *pwd) { + uint len = strlen(pwd); + while (len && (pwd[len] != '/')) { + len--; + } + if (len == 0) { + strcpy (pwd, "/"); + } else { + pwd[len] = '\0'; + } +} + +static void ftp_return_to_previous_path (char *pwd, char *dir) { + uint newlen = strlen(pwd) - strlen(dir); + if ((newlen > 2) && (pwd[newlen - 1] == '/')) { + pwd[newlen - 1] = '\0'; + } + else { + if (newlen == 0) { + strcpy (pwd, "/"); + } else { + pwd[newlen] = '\0'; + } + } +} + diff --git a/src/openmv/src/micropython/ports/cc3200/ftp/ftp.h b/src/openmv/src/micropython/ports/cc3200/ftp/ftp.h new file mode 100755 index 0000000..af4c14f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/ftp/ftp.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_FTP_FTP_H +#define MICROPY_INCLUDED_CC3200_FTP_FTP_H + +/****************************************************************************** + DECLARE EXPORTED FUNCTIONS + ******************************************************************************/ +extern void ftp_init (void); +extern void ftp_run (void); +extern void ftp_enable (void); +extern void ftp_disable (void); +extern void ftp_reset (void); + +#endif // MICROPY_INCLUDED_CC3200_FTP_FTP_H diff --git a/src/openmv/src/micropython/ports/cc3200/ftp/updater.c b/src/openmv/src/micropython/ports/cc3200/ftp/updater.c new file mode 100755 index 0000000..5be2c60 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/ftp/updater.c @@ -0,0 +1,202 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "simplelink.h" +#include "flc.h" +#include "updater.h" +#include "shamd5.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "debug.h" +#include "osi.h" + +/****************************************************************************** + DEFINE PRIVATE CONSTANTS + ******************************************************************************/ +#define UPDATER_IMG_PATH "/flash/sys/mcuimg.bin" +#define UPDATER_SRVPACK_PATH "/flash/sys/servicepack.ucf" +#define UPDATER_SIGN_PATH "/flash/sys/servicepack.sig" +#define UPDATER_CA_PATH "/flash/cert/ca.pem" +#define UPDATER_CERT_PATH "/flash/cert/cert.pem" +#define UPDATER_KEY_PATH "/flash/cert/private.key" + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct { + char *path; + _i32 fhandle; + _u32 fsize; + _u32 foffset; +} updater_data_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +static updater_data_t updater_data = { .path = NULL, .fhandle = -1, .fsize = 0, .foffset = 0 }; +static OsiLockObj_t updater_LockObj; +static sBootInfo_t sBootInfo; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +__attribute__ ((section (".boot"))) +void updater_pre_init (void) { + // create the updater lock + ASSERT(OSI_OK == sl_LockObjCreate(&updater_LockObj, "UpdaterLock")); +} + +bool updater_check_path (void *path) { + sl_LockObjLock (&updater_LockObj, SL_OS_WAIT_FOREVER); + if (!strcmp(UPDATER_IMG_PATH, path)) { + updater_data.fsize = IMG_SIZE; + updater_data.path = IMG_UPDATE1; +// the launchxl doesn't have enough flash space for 2 user update images +#ifdef WIPY + // check which one should be the next active image + _i32 fhandle; + if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) { + ASSERT (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))); + sl_FsClose(fhandle, 0, 0, 0); + // if we still have an image pending for verification, keep overwriting it + if ((sBootInfo.Status == IMG_STATUS_CHECK && sBootInfo.ActiveImg == IMG_ACT_UPDATE2) || + (sBootInfo.ActiveImg == IMG_ACT_UPDATE1 && sBootInfo.Status != IMG_STATUS_CHECK)) { + updater_data.path = IMG_UPDATE2; + } + } +#endif + } else if (!strcmp(UPDATER_SRVPACK_PATH, path)) { + updater_data.path = IMG_SRVPACK; + updater_data.fsize = SRVPACK_SIZE; + } else if (!strcmp(UPDATER_SIGN_PATH, path)) { + updater_data.path = SRVPACK_SIGN; + updater_data.fsize = SIGN_SIZE; + } else if (!strcmp(UPDATER_CA_PATH, path)) { + updater_data.path = CA_FILE; + updater_data.fsize = CA_KEY_SIZE; + } else if (!strcmp(UPDATER_CERT_PATH, path)) { + updater_data.path = CERT_FILE; + updater_data.fsize = CA_KEY_SIZE; + } else if (!strcmp(UPDATER_KEY_PATH, path)) { + updater_data.path = KEY_FILE; + updater_data.fsize = CA_KEY_SIZE; + } else { + sl_LockObjUnlock (&updater_LockObj); + return false; + } + return true; +} + +bool updater_start (void) { + _u32 AccessModeAndMaxSize = FS_MODE_OPEN_WRITE; + SlFsFileInfo_t FsFileInfo; + bool result = false; + + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + if (0 != sl_FsGetInfo((_u8 *)updater_data.path, 0, &FsFileInfo)) { + // file doesn't exist, create it + AccessModeAndMaxSize = FS_MODE_OPEN_CREATE(updater_data.fsize, 0); + } + if (!sl_FsOpen((_u8 *)updater_data.path, AccessModeAndMaxSize, NULL, &updater_data.fhandle)) { + updater_data.foffset = 0; + result = true; + } + sl_LockObjUnlock (&wlan_LockObj); + return result; +} + +bool updater_write (uint8_t *buf, uint32_t len) { + bool result = false; + + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + if (len == sl_FsWrite(updater_data.fhandle, updater_data.foffset, buf, len)) { + updater_data.foffset += len; + result = true; + } + sl_LockObjUnlock (&wlan_LockObj); + + return result; +} + +void updater_finnish (void) { + _i32 fhandle; + + if (updater_data.fhandle > 0) { + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + // close the file being updated + sl_FsClose(updater_data.fhandle, NULL, NULL, 0); +#ifdef WIPY + // if we still have an image pending for verification, leave the boot info as it is + if (!strncmp(IMG_PREFIX, updater_data.path, strlen(IMG_PREFIX)) && sBootInfo.Status != IMG_STATUS_CHECK) { +#else + if (!strncmp(IMG_PREFIX, updater_data.path, strlen(IMG_PREFIX))) { +#endif +#ifdef DEBUG + if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) { + + ASSERT (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))); + sl_FsClose(fhandle, 0, 0, 0); +#endif + // open the boot info file for writing + ASSERT (sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle) == 0); +#ifdef DEBUG + } + else { + // the boot info file doesn't exist yet + _u32 BootInfoCreateFlag = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ; + ASSERT (sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)), + BootInfoCreateFlag), NULL, &fhandle) == 0); + } +#endif + + // save the new boot info +#ifdef WIPY + sBootInfo.PrevImg = sBootInfo.ActiveImg; + if (sBootInfo.ActiveImg == IMG_ACT_UPDATE1) { + sBootInfo.ActiveImg = IMG_ACT_UPDATE2; + } else { + sBootInfo.ActiveImg = IMG_ACT_UPDATE1; + } +// the launchxl doesn't have enough flash space for 2 user updates +#else + sBootInfo.PrevImg = IMG_ACT_FACTORY; + sBootInfo.ActiveImg = IMG_ACT_UPDATE1; +#endif + sBootInfo.Status = IMG_STATUS_CHECK; + ASSERT (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))); + sl_FsClose(fhandle, 0, 0, 0); + } + sl_LockObjUnlock (&wlan_LockObj); + updater_data.fhandle = -1; + } + sl_LockObjUnlock (&updater_LockObj); +} + diff --git a/src/openmv/src/micropython/ports/cc3200/ftp/updater.h b/src/openmv/src/micropython/ports/cc3200/ftp/updater.h new file mode 100755 index 0000000..51248e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/ftp/updater.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_FTP_UPDATER_H +#define MICROPY_INCLUDED_CC3200_FTP_UPDATER_H + +extern void updater_pre_init (void); +extern bool updater_check_path (void *path); +extern bool updater_start (void); +extern bool updater_write (uint8_t *buf, uint32_t len); +extern void updater_finnish (void); +extern bool updater_verify (uint8_t *rbuff, uint8_t *hasbuff); + +#endif // MICROPY_INCLUDED_CC3200_FTP_UPDATER_H diff --git a/src/openmv/src/micropython/ports/cc3200/hal/adc.c b/src/openmv/src/micropython/ports/cc3200/hal/adc.c new file mode 100755 index 0000000..23d219e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/adc.c @@ -0,0 +1,692 @@ +//***************************************************************************** +// +// adc.c +// +// Driver for the ADC module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup ADC_Analog_to_Digital_Converter_api +//! @{ +// +//***************************************************************************** +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_ints.h" +#include "inc/hw_adc.h" +#include "inc/hw_apps_config.h" +#include "interrupt.h" +#include "adc.h" + + +//***************************************************************************** +// +//! Enables the ADC +//! +//! \param ulBase is the base address of the ADC +//! +//! This function sets the ADC global enable +//! +//! \return None. +// +//***************************************************************************** +void ADCEnable(unsigned long ulBase) +{ + // + // Set the global enable bit in the control register. + // + HWREG(ulBase + ADC_O_ADC_CTRL) |= 0x1; +} + +//***************************************************************************** +// +//! Disable the ADC +//! +//! \param ulBase is the base address of the ADC +//! +//! This function clears the ADC global enable +//! +//! \return None. +// +//***************************************************************************** +void ADCDisable(unsigned long ulBase) +{ + // + // Clear the global enable bit in the control register. + // + HWREG(ulBase + ADC_O_ADC_CTRL) &= ~0x1 ; +} + +//***************************************************************************** +// +//! Enables specified ADC channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! +//! This function enables specified ADC channel and configures the +//! pin as analog pin. +//! +//! \return None. +// +//***************************************************************************** +void ADCChannelEnable(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulCh; + + ulCh = (ulChannel == ADC_CH_0)? 0x02 : + (ulChannel == ADC_CH_1)? 0x04 : + (ulChannel == ADC_CH_2)? 0x08 : 0x10; + + HWREG(ulBase + ADC_O_ADC_CH_ENABLE) |= ulCh; +} + +//***************************************************************************** +// +//! Disables specified ADC channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channelsber +//! +//! This function disables specified ADC channel. +//! +//! \return None. +// +//***************************************************************************** +void ADCChannelDisable(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulCh; + + ulCh = (ulChannel == ADC_CH_0)? 0x02 : + (ulChannel == ADC_CH_1)? 0x04 : + (ulChannel == ADC_CH_2)? 0x08 : 0x10; + + HWREG(ulBase + ADC_O_ADC_CH_ENABLE) &= ~ulCh; +} + +//***************************************************************************** +// +//! Enables and registers ADC interrupt handler for specified channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! \param pfnHandler is a pointer to the function to be called when the +//! ADC channel interrupt occurs. +//! +//! This function enables and registers ADC interrupt handler for specified +//! channel. Individual interrupt for each channel should be enabled using +//! \sa ADCIntEnable(). It is the interrupt handler's responsibility to clear +//! the interrupt source. +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \return None. +// +//***************************************************************************** +void ADCIntRegister(unsigned long ulBase, unsigned long ulChannel, + void (*pfnHandler)(void)) +{ + unsigned long ulIntNo; + + // + // Get the interrupt number associted with the specified channel + // + ulIntNo = (ulChannel == ADC_CH_0)? INT_ADCCH0 : + (ulChannel == ADC_CH_1)? INT_ADCCH1 : + (ulChannel == ADC_CH_2)? INT_ADCCH2 : INT_ADCCH3; + + // + // Register the interrupt handler + // + IntRegister(ulIntNo,pfnHandler); + + // + // Enable ADC interrupt + // + IntEnable(ulIntNo); +} + + +//***************************************************************************** +// +//! Disables and unregisters ADC interrupt handler for specified channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! +//! This function disables and unregisters ADC interrupt handler for specified +//! channel. This function also masks off the interrupt in the interrupt +//! controller so that the interrupt handler no longer is called. +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \return None. +// +//***************************************************************************** +void ADCIntUnregister(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulIntNo; + + // + // Get the interrupt number associted with the specified channel + // + ulIntNo = (ulChannel == ADC_CH_0)? INT_ADCCH0 : + (ulChannel == ADC_CH_1)? INT_ADCCH1 : + (ulChannel == ADC_CH_2)? INT_ADCCH2 : INT_ADCCH3; + + // + // Disable ADC interrupt + // + IntDisable(ulIntNo); + + // + // Unregister the interrupt handler + // + IntUnregister(ulIntNo); +} + +//***************************************************************************** +// +//! Enables individual interrupt sources for specified channel +//! +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated ADC interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! - \b ADC_DMA_DONE for DMA done +//! - \b ADC_FIFO_OVERFLOW for FIFO over flow +//! - \b ADC_FIFO_UNDERFLOW for FIFO under flow +//! - \b ADC_FIFO_EMPTY for FIFO empty +//! - \b ADC_FIFO_FULL for FIFO full +//! +//! \return None. +// +//***************************************************************************** +void ADCIntEnable(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags) +{ + unsigned long ulOffset; + unsigned long ulDmaMsk; + + // + // Enable DMA Done interrupt + // + if(ulIntFlags & ADC_DMA_DONE) + { + ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: + (ulChannel == ADC_CH_1)?0x00002000: + (ulChannel == ADC_CH_2)?0x00004000:0x00008000; + + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; + } + + ulIntFlags = ulIntFlags & 0x0F; + // + // Get the interrupt enable register offset for specified channel + // + ulOffset = ADC_O_adc_ch0_irq_en + ulChannel; + + // + // Unmask the specified interrupts + // + HWREG(ulBase + ulOffset) |= (ulIntFlags & 0xf); +} + + +//***************************************************************************** +// +//! Disables individual interrupt sources for specified channel +//! +//! +//! \param ulBase is the base address of the ADC. +//! \param ulChannel is one of the valid ADC channels +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function disables the indicated ADC interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The parameters\e ulIntFlags and \e ulChannel should be as explained in +//! ADCIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void ADCIntDisable(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags) +{ + unsigned long ulOffset; + unsigned long ulDmaMsk; + + // + // Disable DMA Done interrupt + // + if(ulIntFlags & ADC_DMA_DONE) + { + ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: + (ulChannel == ADC_CH_1)?0x00002000: + (ulChannel == ADC_CH_2)?0x00004000:0x00008000; + + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; + } + + // + // Get the interrupt enable register offset for specified channel + // + ulOffset = ADC_O_adc_ch0_irq_en + ulChannel; + + // + // Unmask the specified interrupts + // + HWREG(ulBase + ulOffset) &= ~ulIntFlags; +} + + +//***************************************************************************** +// +//! Gets the current channel interrupt status +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! +//! This function returns the interrupt status of the specified ADC channel. +//! +//! The parameter \e ulChannel should be as explained in \sa ADCIntEnable(). +//! +//! \return Return the ADC channel interrupt status, enumerated as a bit +//! field of values described in ADCIntEnable() +// +//***************************************************************************** +unsigned long ADCIntStatus(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulOffset; + unsigned long ulDmaMsk; + unsigned long ulIntStatus; + + // + // Get DMA Done interrupt status + // + ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: + (ulChannel == ADC_CH_1)?0x00002000: + (ulChannel == ADC_CH_2)?0x00004000:0x00008000; + + ulIntStatus = HWREG(APPS_CONFIG_BASE + + APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED)& ulDmaMsk; + + + // + // Get the interrupt enable register offset for specified channel + // + ulOffset = ADC_O_adc_ch0_irq_status + ulChannel; + + // + // Read ADC interrupt status + // + ulIntStatus |= HWREG(ulBase + ulOffset) & 0xf; + + // + // Return the current interrupt status + // + return(ulIntStatus); +} + + +//***************************************************************************** +// +//! Clears the current channel interrupt sources +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! \param ulIntFlags is the bit mask of the interrupt sources to be cleared. +//! +//! This function clears individual interrupt source for the specified +//! ADC channel. +//! +//! The parameter \e ulChannel should be as explained in \sa ADCIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void ADCIntClear(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags) +{ + unsigned long ulOffset; + unsigned long ulDmaMsk; + + // + // Clear DMA Done interrupt + // + if(ulIntFlags & ADC_DMA_DONE) + { + ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: + (ulChannel == ADC_CH_1)?0x00002000: + (ulChannel == ADC_CH_2)?0x00004000:0x00008000; + + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; + } + + // + // Get the interrupt enable register offset for specified channel + // + ulOffset = ADC_O_adc_ch0_irq_status + ulChannel; + + // + // Clear the specified interrupts + // + HWREG(ulBase + ulOffset) = (ulIntFlags & ~(ADC_DMA_DONE)); +} + +//***************************************************************************** +// +//! Enables the ADC DMA operation for specified channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! +//! This function enables the DMA operation for specified ADC channel +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \return None. +// +//***************************************************************************** +void ADCDMAEnable(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulBitMask; + + // + // Get the bit mask for enabling DMA for specified channel + // + ulBitMask = (ulChannel == ADC_CH_0)?0x01: + (ulChannel == ADC_CH_1)?0x04: + (ulChannel == ADC_CH_2)?0x10:0x40; + + // + // Enable DMA request for the specified channel + // + HWREG(ulBase + ADC_O_adc_dma_mode_en) |= ulBitMask; +} + +//***************************************************************************** +// +//! Disables the ADC DMA operation for specified channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels +//! +//! This function disables the DMA operation for specified ADC channel +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \return None. +// +//***************************************************************************** +void ADCDMADisable(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulBitMask; + + // + // Get the bit mask for disabling DMA for specified channel + // + ulBitMask = (ulChannel == ADC_CH_0)?0x01: + (ulChannel == ADC_CH_1)?0x04: + (ulChannel == ADC_CH_2)?0x10:0x40; + + // + // Disable DMA request for the specified channel + // + HWREG(ulBase + ADC_O_adc_dma_mode_en) &= ~ulBitMask; +} + +//***************************************************************************** +// +//! Configures the ADC internal timer +//! +//! \param ulBase is the base address of the ADC +//! \param ulValue is wrap arround value of the timer +//! +//! This function Configures the ADC internal timer. The ADC timer is a 17 bit +//! used to timestamp the ADC data samples internally. +//! User can read the timestamp along with the sample from the FIFO register(s). +//! Each sample in the FIFO contains 14 bit actual data and 18 bit timestamp +//! +//! The parameter \e ulValue can take any value between 0 - 2^17 +//! +//! \returns None. +// +//***************************************************************************** +void ADCTimerConfig(unsigned long ulBase, unsigned long ulValue) +{ + unsigned long ulReg; + + // + // Read the currrent config + // + ulReg = HWREG(ulBase + ADC_O_adc_timer_configuration); + + // + // Mask and set timer count field + // + ulReg = ((ulReg & ~0x1FFFF) | (ulValue & 0x1FFFF)); + + // + // Set the timer count value + // + HWREG(ulBase + ADC_O_adc_timer_configuration) = ulReg; +} + +//***************************************************************************** +// +//! Resets ADC internal timer +//! +//! \param ulBase is the base address of the ADC +//! +//! This function resets 17-bit ADC internal timer +//! +//! \returns None. +// +//***************************************************************************** +void ADCTimerReset(unsigned long ulBase) +{ + // + // Reset the timer + // + HWREG(ulBase + ADC_O_adc_timer_configuration) |= (1 << 24); +} + +//***************************************************************************** +// +//! Enables ADC internal timer +//! +//! \param ulBase is the base address of the ADC +//! +//! This function enables 17-bit ADC internal timer +//! +//! \returns None. +// +//***************************************************************************** +void ADCTimerEnable(unsigned long ulBase) +{ + // + // Enable the timer + // + HWREG(ulBase + ADC_O_adc_timer_configuration) |= (1 << 25); +} + +//***************************************************************************** +// +//! Disables ADC internal timer +//! +//! \param ulBase is the base address of the ADC +//! +//! This function disables 17-bit ADC internal timer +//! +//! \returns None. +// +//***************************************************************************** +void ADCTimerDisable(unsigned long ulBase) +{ + // + // Disable the timer + // + HWREG(ulBase + ADC_O_adc_timer_configuration) &= ~(1 << 25); +} + +//***************************************************************************** +// +//! Gets the current value of ADC internal timer +//! +//! \param ulBase is the base address of the ADC +//! +//! This function the current value of 17-bit ADC internal timer +//! +//! \returns Return the current value of ADC internal timer. +// +//***************************************************************************** +unsigned long ADCTimerValueGet(unsigned long ulBase) +{ + return(HWREG(ulBase + ADC_O_adc_timer_current_count)); +} + +//***************************************************************************** +// +//! Gets the current FIFO level for specified ADC channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels. +//! +//! This function returns the current FIFO level for specified ADC channel. +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \returns Return the current FIFO level for specified channel +// +//***************************************************************************** +unsigned char ADCFIFOLvlGet(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulOffset; + + // + // Get the fifo level register offset for specified channel + // + ulOffset = ADC_O_adc_ch0_fifo_lvl + ulChannel; + + // + // Return FIFO level + // + return(HWREG(ulBase + ulOffset) & 0x7); +} + +//***************************************************************************** +// +//! Reads FIFO for specified ADC channel +//! +//! \param ulBase is the base address of the ADC +//! \param ulChannel is one of the valid ADC channels. +//! +//! This function returns one data sample from the channel fifo as specified by +//! \e ulChannel parameter. +//! +//! The parameter \e ulChannel should be one of the following +//! +//! - \b ADC_CH_0 for channel 0 +//! - \b ADC_CH_1 for channel 1 +//! - \b ADC_CH_2 for channel 2 +//! - \b ADC_CH_3 for channel 3 +//! +//! \returns Return one data sample from the channel fifo. +// +//***************************************************************************** +unsigned long ADCFIFORead(unsigned long ulBase, unsigned long ulChannel) +{ + unsigned long ulOffset; + + // + // Get the fifo register offset for specified channel + // + ulOffset = ADC_O_channel0FIFODATA + ulChannel; + + // + // Return FIFO level + // + return(HWREG(ulBase + ulOffset)); +} + + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/adc.h b/src/openmv/src/micropython/ports/cc3200/hal/adc.h new file mode 100755 index 0000000..03e0ea5 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/adc.h @@ -0,0 +1,117 @@ +//***************************************************************************** +// +// adc.h +// +// Defines and Macros for the ADC. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __ADC_H__ +#define __ADC_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// Values that can be passed to APIs as ulChannel parameter +//***************************************************************************** +#define ADC_CH_0 0x00000000 +#define ADC_CH_1 0x00000008 +#define ADC_CH_2 0x00000010 +#define ADC_CH_3 0x00000018 + + +//***************************************************************************** +// +// Values that can be passed to ADCIntEnable(), ADCIntDisable() +// and ADCIntClear() as ulIntFlags, and returned from ADCIntStatus() +// +//***************************************************************************** +#define ADC_DMA_DONE 0x00000010 +#define ADC_FIFO_OVERFLOW 0x00000008 +#define ADC_FIFO_UNDERFLOW 0x00000004 +#define ADC_FIFO_EMPTY 0x00000002 +#define ADC_FIFO_FULL 0x00000001 + + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void ADCEnable(unsigned long ulBase); +extern void ADCDisable(unsigned long ulBase); +extern void ADCChannelEnable(unsigned long ulBase,unsigned long ulChannel); +extern void ADCChannelDisable(unsigned long ulBase,unsigned long ulChannel); +extern void ADCIntRegister(unsigned long ulBase, unsigned long ulChannel, + void (*pfnHandler)(void)); +extern void ADCIntUnregister(unsigned long ulBase, unsigned long ulChannel); +extern void ADCIntEnable(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags); +extern void ADCIntDisable(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags); +extern unsigned long ADCIntStatus(unsigned long ulBase,unsigned long ulChannel); +extern void ADCIntClear(unsigned long ulBase, unsigned long ulChannel, + unsigned long ulIntFlags); +extern void ADCDMAEnable(unsigned long ulBase, unsigned long ulChannel); +extern void ADCDMADisable(unsigned long ulBase, unsigned long ulChannel); +extern void ADCTimerConfig(unsigned long ulBase, unsigned long ulValue); +extern void ADCTimerEnable(unsigned long ulBase); +extern void ADCTimerDisable(unsigned long ulBase); +extern void ADCTimerReset(unsigned long ulBase); +extern unsigned long ADCTimerValueGet(unsigned long ulBase); +extern unsigned char ADCFIFOLvlGet(unsigned long ulBase, + unsigned long ulChannel); +extern unsigned long ADCFIFORead(unsigned long ulBase, + unsigned long ulChannel); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __ADC_H__ + diff --git a/src/openmv/src/micropython/ports/cc3200/hal/aes.c b/src/openmv/src/micropython/ports/cc3200/hal/aes.c new file mode 100755 index 0000000..e0e129e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/aes.c @@ -0,0 +1,1360 @@ +//***************************************************************************** +// +// aes.c +// +// Driver for the AES module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup AES_Advanced_Encryption_Standard_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_aes.h" +#include "inc/hw_dthe.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "aes.h" +#include "debug.h" +#include "interrupt.h" + +#define AES_BLOCK_SIZE_IN_BYTES 16 + +//***************************************************************************** +// +//! Configures the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32Config is the configuration of the AES module. +//! +//! This function configures the AES module based on the specified parameters. +//! It does not change any DMA- or interrupt-related parameters. +//! +//! The ui32Config parameter is a bit-wise OR of a number of configuration +//! flags. The valid flags are grouped based on their function. +//! +//! The direction of the operation is specified with only of following flags: +//! +//! - \b AES_CFG_DIR_ENCRYPT - Encryption mode +//! - \b AES_CFG_DIR_DECRYPT - Decryption mode +//! +//! The key size is specified with only one of the following flags: +//! +//! - \b AES_CFG_KEY_SIZE_128BIT - Key size of 128 bits +//! - \b AES_CFG_KEY_SIZE_192BIT - Key size of 192 bits +//! - \b AES_CFG_KEY_SIZE_256BIT - Key size of 256 bits +//! +//! The mode of operation is specified with only one of the following flags. +//! +//! - \b AES_CFG_MODE_ECB - Electronic codebook mode +//! - \b AES_CFG_MODE_CBC - Cipher-block chaining mode +//! - \b AES_CFG_MODE_CFB - Cipher feedback mode +//! - \b AES_CFG_MODE_CTR - Counter mode +//! - \b AES_CFG_MODE_ICM - Integer counter mode +//! - \b AES_CFG_MODE_XTS - Ciphertext stealing mode +//! - \b AES_CFG_MODE_XTS_TWEAKJL - XEX-based tweaked-codebook mode with +//! ciphertext stealing with previous/intermediate tweak value and j loaded +//! - \b AES_CFG_MODE_XTS_K2IJL - XEX-based tweaked-codebook mode with +//! ciphertext stealing with key2, i and j loaded +//! - \b AES_CFG_MODE_XTS_K2ILJ0 - XEX-based tweaked-codebook mode with +//! ciphertext stealing with key2 and i loaded, j = 0 +//! - \b AES_CFG_MODE_F8 - F8 mode +//! - \b AES_CFG_MODE_F9 - F9 mode +//! - \b AES_CFG_MODE_CBCMAC - Cipher block chaining message authentication +//! code mode +//! - \b AES_CFG_MODE_GCM - Galois/counter mode +//! - \b AES_CFG_MODE_GCM_HLY0ZERO - Galois/counter mode with GHASH with H +//! loaded and Y0-encrypted forced to zero +//! - \b AES_CFG_MODE_GCM_HLY0CALC - Galois/counter mode with GHASH with H +//! loaded and Y0-encrypted calculated internally +//! - \b AES_CFG_MODE_GCM_HY0CALC - Galois/Counter mode with autonomous GHASH +//! (both H and Y0-encrypted calculated internally) +//! - \b AES_CFG_MODE_CCM - Counter with CBC-MAC mode +//! +//! The following defines are used to specify the counter width. It is only +//! required to be defined when using CTR, CCM, or GCM modes, only one of the +//! following defines must be used to specify the counter width length: +//! +//! - \b AES_CFG_CTR_WIDTH_32 - Counter is 32 bits +//! - \b AES_CFG_CTR_WIDTH_64 - Counter is 64 bits +//! - \b AES_CFG_CTR_WIDTH_96 - Counter is 96 bits +//! - \b AES_CFG_CTR_WIDTH_128 - Counter is 128 bits +//! +//! Only one of the following defines must be used to specify the length field +//! for CCM operations (L): +//! +//! - \b AES_CFG_CCM_L_2 - 2 bytes +//! - \b AES_CFG_CCM_L_4 - 4 bytes +//! - \b AES_CFG_CCM_L_8 - 8 bytes +//! +//! Only one of the following defines must be used to specify the length of the +//! authentication field for CCM operations (M) through the \e ui32Config +//! argument in the AESConfigSet() function: +//! +//! - \b AES_CFG_CCM_M_4 - 4 bytes +//! - \b AES_CFG_CCM_M_6 - 6 bytes +//! - \b AES_CFG_CCM_M_8 - 8 bytes +//! - \b AES_CFG_CCM_M_10 - 10 bytes +//! - \b AES_CFG_CCM_M_12 - 12 bytes +//! - \b AES_CFG_CCM_M_14 - 14 bytes +//! - \b AES_CFG_CCM_M_16 - 16 bytes +//! +//! \return None. +// +//***************************************************************************** +void +AESConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32Config & AES_CFG_DIR_ENCRYPT) || + (ui32Config & AES_CFG_DIR_DECRYPT)); + ASSERT((ui32Config & AES_CFG_KEY_SIZE_128BIT) || + (ui32Config & AES_CFG_KEY_SIZE_192BIT) || + (ui32Config & AES_CFG_KEY_SIZE_256BIT)); + ASSERT((ui32Config & AES_CFG_MODE_ECB) || + (ui32Config & AES_CFG_MODE_CBC) || + (ui32Config & AES_CFG_MODE_CTR) || + (ui32Config & AES_CFG_MODE_ICM) || + (ui32Config & AES_CFG_MODE_CFB) || + (ui32Config & AES_CFG_MODE_XTS_TWEAKJL) || + (ui32Config & AES_CFG_MODE_XTS_K2IJL) || + (ui32Config & AES_CFG_MODE_XTS_K2ILJ0) || + (ui32Config & AES_CFG_MODE_F8) || + (ui32Config & AES_CFG_MODE_F9) || + (ui32Config & AES_CFG_MODE_CTR) || + (ui32Config & AES_CFG_MODE_CBCMAC) || + (ui32Config & AES_CFG_MODE_GCM_HLY0ZERO) || + (ui32Config & AES_CFG_MODE_GCM_HLY0CALC) || + (ui32Config & AES_CFG_MODE_GCM_HY0CALC) || + (ui32Config & AES_CFG_MODE_CCM)); + ASSERT(((ui32Config & AES_CFG_MODE_CTR) || + (ui32Config & AES_CFG_MODE_GCM_HLY0ZERO) || + (ui32Config & AES_CFG_MODE_GCM_HLY0CALC) || + (ui32Config & AES_CFG_MODE_GCM_HY0CALC) || + (ui32Config & AES_CFG_MODE_CCM)) && + ((ui32Config & AES_CFG_CTR_WIDTH_32) || + (ui32Config & AES_CFG_CTR_WIDTH_64) || + (ui32Config & AES_CFG_CTR_WIDTH_96) || + (ui32Config & AES_CFG_CTR_WIDTH_128))); + ASSERT((ui32Config & AES_CFG_MODE_CCM) && + ((ui32Config & AES_CFG_CCM_L_2) || + (ui32Config & AES_CFG_CCM_L_4) || + (ui32Config & AES_CFG_CCM_L_8)) && + ((ui32Config & AES_CFG_CCM_M_4) || + (ui32Config & AES_CFG_CCM_M_6) || + (ui32Config & AES_CFG_CCM_M_8) || + (ui32Config & AES_CFG_CCM_M_10) || + (ui32Config & AES_CFG_CCM_M_12) || + (ui32Config & AES_CFG_CCM_M_14) || + (ui32Config & AES_CFG_CCM_M_16))); + + // + // Backup the save context field before updating the register. + // + if(HWREG(ui32Base + AES_O_CTRL) & AES_CTRL_SAVE_CONTEXT) + { + ui32Config |= AES_CTRL_SAVE_CONTEXT; + } + + // + // Write the CTRL register with the new value + // + HWREG(ui32Base + AES_O_CTRL) = ui32Config; +} + +//***************************************************************************** +// +//! Writes the key 1 configuration registers, which are used for encryption or +//! decryption. +//! +//! \param ui32Base is the base address for the AES module. +//! \param pui8Key is an array of bytes, containing the key to be +//! configured. The least significant word in the 0th index. +//! \param ui32Keysize is the size of the key, which must be one of the +//! following values: \b AES_CFG_KEY_SIZE_128, \b AES_CFG_KEY_SIZE_192, or +//! \b AES_CFG_KEY_SIZE_256. +//! +//! This function writes key 1 configuration registers based on the key +//! size. This function is used in all modes. +//! +//! \return None. +// +//***************************************************************************** +void +AESKey1Set(uint32_t ui32Base, uint8_t *pui8Key, uint32_t ui32Keysize) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32Keysize == AES_CFG_KEY_SIZE_128BIT) || + (ui32Keysize == AES_CFG_KEY_SIZE_192BIT) || + (ui32Keysize == AES_CFG_KEY_SIZE_256BIT)); + + // + // With all key sizes, the first 4 words are written. + // + HWREG(ui32Base + AES_O_KEY1_0) = * ((uint32_t *)(pui8Key + 0)); + HWREG(ui32Base + AES_O_KEY1_1) = * ((uint32_t *)(pui8Key + 4)); + HWREG(ui32Base + AES_O_KEY1_2) = * ((uint32_t *)(pui8Key + 8)); + HWREG(ui32Base + AES_O_KEY1_3) = * ((uint32_t *)(pui8Key + 12)); + + // + // The key is 192 or 256 bits. Write the next 2 words. + // + if(ui32Keysize != AES_CFG_KEY_SIZE_128BIT) + { + HWREG(ui32Base + AES_O_KEY1_4) = * ((uint32_t *)(pui8Key + 16)); + HWREG(ui32Base + AES_O_KEY1_5) = * ((uint32_t *)(pui8Key + 20)); + } + + // + // The key is 256 bits. Write the last 2 words. + // + if(ui32Keysize == AES_CFG_KEY_SIZE_256BIT) + { + HWREG(ui32Base + AES_O_KEY1_6) = * ((uint32_t *)(pui8Key + 24)); + HWREG(ui32Base + AES_O_KEY1_7) = * ((uint32_t *)(pui8Key + 28)); + } +} + +//***************************************************************************** +// +//! Writes the key 2 configuration registers, which are used for encryption or +//! decryption. +//! +//! \param ui32Base is the base address for the AES module. +//! \param pui8Key is an array of bytes, containing the key to be +//! configured. The least significant word in the 0th index. +//! \param ui32Keysize is the size of the key, which must be one of the +//! following values: \b AES_CFG_KEY_SIZE_128, \b AES_CFG_KEY_SIZE_192, or +//! \b AES_CFG_KEY_SIZE_256. +//! +//! This function writes the key 2 configuration registers based on the key +//! size. This function is used in the F8, F9, XTS, CCM, and CBC-MAC modes. +//! +//! \return None. +// +//***************************************************************************** +void +AESKey2Set(uint32_t ui32Base, uint8_t *pui8Key, uint32_t ui32Keysize) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32Keysize == AES_CFG_KEY_SIZE_128BIT) || + (ui32Keysize == AES_CFG_KEY_SIZE_192BIT) || + (ui32Keysize == AES_CFG_KEY_SIZE_256BIT)); + + // + // With all key sizes, the first 4 words are written. + // + HWREG(ui32Base + AES_O_KEY2_0) = * ((uint32_t *)(pui8Key + 0)); + HWREG(ui32Base + AES_O_KEY2_1) = * ((uint32_t *)(pui8Key + 4)); + HWREG(ui32Base + AES_O_KEY2_2) = * ((uint32_t *)(pui8Key + 8)); + HWREG(ui32Base + AES_O_KEY2_3) = * ((uint32_t *)(pui8Key + 12)); + + // + // The key is 192 or 256 bits. Write the next 2 words. + // + if(ui32Keysize != AES_CFG_KEY_SIZE_128BIT) + { + HWREG(ui32Base + AES_O_KEY2_4) = * ((uint32_t *)(pui8Key + 16)); + HWREG(ui32Base + AES_O_KEY2_5) = * ((uint32_t *)(pui8Key + 20)); + } + + // + // The key is 256 bits. Write the last 2 words. + // + if(ui32Keysize == AES_CFG_KEY_SIZE_256BIT) + { + HWREG(ui32Base + AES_O_KEY2_6) = * ((uint32_t *)(pui8Key + 24)); + HWREG(ui32Base + AES_O_KEY2_7) = * ((uint32_t *)(pui8Key + 28)); + } +} + +//***************************************************************************** +// +//! Writes key 3 configuration registers, which are used for encryption or +//! decryption. +//! +//! \param ui32Base is the base address for the AES module. +//! \param pui8Key is a pointer to an array bytes, containing +//! the key to be configured. The least significant word is in the 0th index. +//! +//! This function writes the key 2 configuration registers with key 3 data +//! used in CBC-MAC and F8 modes. This key is always 128 bits. +//! +//! \return None. +// +//***************************************************************************** +void +AESKey3Set(uint32_t ui32Base, uint8_t *pui8Key) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the key into the upper 4 key registers + // + HWREG(ui32Base + AES_O_KEY2_4) = * ((uint32_t *)(pui8Key + 0)); + HWREG(ui32Base + AES_O_KEY2_5) = * ((uint32_t *)(pui8Key + 4)); + HWREG(ui32Base + AES_O_KEY2_6) = * ((uint32_t *)(pui8Key + 8)); + HWREG(ui32Base + AES_O_KEY2_7) = * ((uint32_t *)(pui8Key + 12)); +} + +//***************************************************************************** +// +//! Writes the Initial Vector (IV) register, needed in some of the AES Modes. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8IVdata is an array of 16 bytes (128 bits), containing the IV +//! value to be configured. The least significant word is in the 0th index. +//! +//! This functions writes the initial vector registers in the AES module. +//! +//! \return None. +// +//***************************************************************************** +void +AESIVSet(uint32_t ui32Base, uint8_t *pui8IVdata) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the initial vector registers. + // + HWREG(ui32Base + AES_O_IV_IN_0) = *((uint32_t *)(pui8IVdata+0)); + HWREG(ui32Base + AES_O_IV_IN_1) = *((uint32_t *)(pui8IVdata+4)); + HWREG(ui32Base + AES_O_IV_IN_2) = *((uint32_t *)(pui8IVdata+8)); + HWREG(ui32Base + AES_O_IV_IN_3) = *((uint32_t *)(pui8IVdata+12)); +} + + +//***************************************************************************** +// +//! Reads the Initial Vector (IV) register, needed in some of the AES Modes. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8IVdata is pointer to an array of 16 bytes. +//! +//! This functions reads the initial vector registers in the AES module. +//! +//! \return None. +// +//***************************************************************************** +void +AESIVGet(uint32_t ui32Base, uint8_t *pui8IVdata) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the initial vector registers. + // + *((uint32_t *)(pui8IVdata+ 0)) = HWREG(ui32Base + AES_O_IV_IN_0); + *((uint32_t *)(pui8IVdata+ 4)) = HWREG(ui32Base + AES_O_IV_IN_1); + *((uint32_t *)(pui8IVdata+ 8)) = HWREG(ui32Base + AES_O_IV_IN_2); + *((uint32_t *)(pui8IVdata+12)) = HWREG(ui32Base + AES_O_IV_IN_3); +} + +//***************************************************************************** +// +//! Saves the tag registers to a user-defined location. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8TagData is pointer to the location that stores the tag data. +//! +//! This function stores the tag data for use authenticated encryption and +//! decryption operations. +//! +//! \return None. +// +//***************************************************************************** +void +AESTagRead(uint32_t ui32Base, uint8_t *pui8TagData) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Read the tag data. + // + *((uint32_t *)(pui8TagData+0)) = HWREG((ui32Base + AES_O_TAG_OUT_0)); + *((uint32_t *)(pui8TagData+4)) = HWREG((ui32Base + AES_O_TAG_OUT_1)); + *((uint32_t *)(pui8TagData+8)) = HWREG((ui32Base + AES_O_TAG_OUT_2)); + *((uint32_t *)(pui8TagData+12)) = HWREG((ui32Base + AES_O_TAG_OUT_3)); +} + +//***************************************************************************** +// +//! Used to set the write crypto data length in the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui64Length is the crypto data length in bytes. +//! +//! This function stores the cryptographic data length in blocks for all modes. +//! Data lengths up to (2^61 - 1) bytes are allowed. For GCM, any value up +//! to (2^36 - 2) bytes are allowed because a 32-bit block counter is used. For +//! basic modes (ECB/CBC/CTR/ICM/CFB128), zero can be programmed into the +//! length field, indicating that the length is infinite. +//! +//! When this function is called, the engine is triggered to start using +//! this context. +//! +//! \note This length does not include the authentication-only data used in +//! some modes. Use the AESAuthLengthSet() function to specify the +//! authentication data length. +//! +//! \return None +// +//***************************************************************************** +void +AESDataLengthSet(uint32_t ui32Base, uint64_t ui64Length) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the length register by shifting the 64-bit ui64Length. + // + HWREG(ui32Base + AES_O_C_LENGTH_0) = (uint32_t)(ui64Length); + HWREG(ui32Base + AES_O_C_LENGTH_1) = (uint32_t)(ui64Length >> 32); +} + +//***************************************************************************** +// +//! Sets the optional additional authentication data (AAD) length. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32Length is the length in bytes. +//! +//! This function is only used to write the authentication data length in the +//! combined modes (GCM or CCM) and XTS mode. Supported AAD lengths for CCM +//! are from 0 to (2^16 - 28) bytes. For GCM, any value up to (2^32 - 1) can +//! be used. For XTS mode, this register is used to load j. Loading of j is +//! only required if j != 0. j represents the sequential number of the 128-bit +//! blocks inside the data unit. Consequently, j must be multiplied by 16 +//! when passed to this function, thereby placing the block number in +//! bits [31:4] of the register. +//! +//! When this function is called, the engine is triggered to start using +//! this context for GCM and CCM. +//! +//! \return None +// +//***************************************************************************** +void +AESAuthDataLengthSet(uint32_t ui32Base, uint32_t ui32Length) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the length into the register. + // + HWREG(ui32Base + AES_O_AUTH_LENGTH) = ui32Length; +} + +//***************************************************************************** +// +//! Reads plaintext/ciphertext from data registers without blocking. +//! This api writes data in blocks +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Dest is a pointer to an array of words of data. +//! \param ui8Length the length can be from 1 to 16 +//! +//! This function reads a block of either plaintext or ciphertext out of the +//! AES module. If the output data is not ready, the function returns +//! false. If the read completed successfully, the function returns true. +//! A block is 16 bytes or 4 words. +//! +//! \return true or false. +// +//***************************************************************************** +bool +AESDataReadNonBlocking(uint32_t ui32Base, uint8_t *pui8Dest, uint8_t ui8Length) +{ + volatile uint32_t pui32Dest[4]; + uint8_t ui8BytCnt; + uint8_t *pui8DestTemp; + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + if((ui8Length == 0)||(ui8Length>16)) + { + return(false); + } + + // + // Check if the output is ready before reading the data. If it not ready, + // return false. + // + if((AES_CTRL_OUTPUT_READY & (HWREG(ui32Base + AES_O_CTRL))) == 0) + { + return(false); + } + + // + // Read a block of data from the data registers + // + pui32Dest[0] = HWREG(ui32Base + AES_O_DATA_IN_3); + pui32Dest[1] = HWREG(ui32Base + AES_O_DATA_IN_2); + pui32Dest[2] = HWREG(ui32Base + AES_O_DATA_IN_1); + pui32Dest[3] = HWREG(ui32Base + AES_O_DATA_IN_0); + + // + //Copy the data to a block memory + // + pui8DestTemp = (uint8_t *)pui32Dest; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8Dest+ui8BytCnt) = *(pui8DestTemp+ui8BytCnt); + } + // + // Read successful, return true. + // + return(true); +} + + +//***************************************************************************** +// +//! Reads plaintext/ciphertext from data registers with blocking. +//! This api writes data in blocks +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Dest is a pointer to an array of words. +//! \param ui8Length is the length of data in bytes to be read. +//! ui8Length can be from 1 to 16 +//! +//! This function reads a block of either plaintext or ciphertext out of the +//! AES module. If the output is not ready, the function waits until it +//! is ready. A block is 16 bytes or 4 words. +//! +//! \return None. +// +//***************************************************************************** + +void +AESDataRead(uint32_t ui32Base, uint8_t *pui8Dest, uint8_t ui8Length) +{ + volatile uint32_t pui32Dest[4]; + uint8_t ui8BytCnt; + uint8_t *pui8DestTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + if((ui8Length == 0)||(ui8Length>16)) + { + return; + } + + + // + // Wait for the output to be ready before reading the data. + // + while((AES_CTRL_OUTPUT_READY & (HWREG(ui32Base + AES_O_CTRL))) == 0) + { + } + + // + // Read a block of data from the data registers + // + pui32Dest[0] = HWREG(ui32Base + AES_O_DATA_IN_3); + pui32Dest[1] = HWREG(ui32Base + AES_O_DATA_IN_2); + pui32Dest[2] = HWREG(ui32Base + AES_O_DATA_IN_1); + pui32Dest[3] = HWREG(ui32Base + AES_O_DATA_IN_0); + // + //Copy the data to a block memory + // + pui8DestTemp = (uint8_t *)pui32Dest; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8Dest+ui8BytCnt) = *(pui8DestTemp+ui8BytCnt); + } + + return; +} + +//***************************************************************************** +// +//! Writes plaintext/ciphertext to data registers without blocking. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Src is a pointer to an array of words of data. +//! \param ui8Length the length can be from 1 to 16 +//! +//! This function writes a block of either plaintext or ciphertext into the +//! AES module. If the input is not ready, the function returns false +//! If the write completed successfully, the function returns true. +//! +//! \return True or false. +// +//***************************************************************************** +bool +AESDataWriteNonBlocking(uint32_t ui32Base, uint8_t *pui8Src, uint8_t ui8Length) +{ + volatile uint32_t pui32Src[4]={0,0,0,0}; + uint8_t ui8BytCnt; + uint8_t *pui8SrcTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + if((ui8Length == 0)||(ui8Length>16)) + { + return(false); + } + + // + // Check if the input is ready. If not, then return false. + // + if(!(AES_CTRL_INPUT_READY & (HWREG(ui32Base + AES_O_CTRL)))) + { + return(false); + } + + + // + //Copy the data to a block memory + // + pui8SrcTemp = (uint8_t *)pui32Src; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8SrcTemp+ui8BytCnt) = *(pui8Src+ui8BytCnt); + } + // + // Write a block of data into the data registers. + // + HWREG(ui32Base + AES_O_DATA_IN_3) = pui32Src[0]; + HWREG(ui32Base + AES_O_DATA_IN_2) = pui32Src[1]; + HWREG(ui32Base + AES_O_DATA_IN_1) = pui32Src[2]; + HWREG(ui32Base + AES_O_DATA_IN_0) = pui32Src[3]; + + // + // Write successful, return true. + // + return(true); +} + + +//***************************************************************************** +// +//! Writes plaintext/ciphertext to data registers with blocking. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Src is a pointer to an array of bytes. +//! \param ui8Length the length can be from 1 to 16 +//! +//! This function writes a block of either plaintext or ciphertext into the +//! AES module. If the input is not ready, the function waits until it is +//! ready before performing the write. +//! +//! \return None. +// +//***************************************************************************** + +void +AESDataWrite(uint32_t ui32Base, uint8_t *pui8Src, uint8_t ui8Length) +{ + volatile uint32_t pui32Src[4]={0,0,0,0}; + uint8_t ui8BytCnt; + uint8_t *pui8SrcTemp; + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + if((ui8Length == 0)||(ui8Length>16)) + { + return; + } + // + // Wait for input ready. + // + while((AES_CTRL_INPUT_READY & (HWREG(ui32Base + AES_O_CTRL))) == 0) + { + } + + // + //Copy the data to a block memory + // + pui8SrcTemp = (uint8_t *)pui32Src; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8SrcTemp+ui8BytCnt) = *(pui8Src+ui8BytCnt); + } + + // + // Write a block of data into the data registers. + // + HWREG(ui32Base + AES_O_DATA_IN_3) = pui32Src[0]; + HWREG(ui32Base + AES_O_DATA_IN_2) = pui32Src[1]; + HWREG(ui32Base + AES_O_DATA_IN_1) = pui32Src[2]; + HWREG(ui32Base + AES_O_DATA_IN_0) = pui32Src[3]; +} + + +//***************************************************************************** +// +//! Used to process(transform) blocks of data, either encrypt or decrypt it. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Src is a pointer to the memory location where the input data +//! is stored. +//! \param pui8Dest is a pointer to the memory location output is written. +//! \param ui32Length is the length of the cryptographic data in bytes. +//! +//! This function iterates the encryption or decryption mechanism number over +//! the data length. Before calling this function, ensure that the AES +//! module is properly configured the key, data size, mode, etc. Only ECB, +//! CBC, CTR, ICM, CFB, XTS and F8 operating modes should be used. The data +//! is processed in 4-word (16-byte) blocks. +//! +//! \note This function only supports values of \e ui32Length less than 2^32, +//! because the memory size is restricted to between 0 to 2^32 bytes. +//! +//! \return Returns true if data was processed successfully. Returns false +//! if data processing failed. +// +//***************************************************************************** +bool +AESDataProcess(uint32_t ui32Base, uint8_t *pui8Src, uint8_t *pui8Dest, + uint32_t ui32Length) +{ + uint32_t ui32Count, ui32BlkCount, ui32ByteCount; + + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the length register first, which triggers the engine to start + // using this context. + // + AESDataLengthSet(AES_BASE, (uint64_t) ui32Length); + + // + // Now loop until the blocks are written. + // + ui32BlkCount = ui32Length/16; + for(ui32Count = 0; ui32Count < ui32BlkCount; ui32Count += 1) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8Src + (ui32Count*16) ,16); + + // + // Read the data registers. + // + AESDataRead(ui32Base, pui8Dest + (ui32Count*16) ,16); + + } + + // + //Now handle the residue bytes + // + ui32ByteCount = ui32Length%16; + if(ui32ByteCount) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8Src + (16*ui32BlkCount) ,ui32ByteCount); + + // + // Read the data registers. + // + AESDataRead(ui32Base, pui8Dest + (16*ui32BlkCount) ,ui32ByteCount); + } + + + + // + // Return true to indicate successful completion of the function. + // + return(true); +} +//***************************************************************************** +// +//! Used to generate message authentication code (MAC) using CBC-MAC and F9 mode. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Src is a pointer to the memory location where the input data +//! is stored. +//! \param ui32Length is the length of the cryptographic data in bytes. +//! \param pui8Tag is a pointer to a 4-word array where the hash tag is +//! written. +//! +//! This function processes data to produce a hash tag that can be used tor +//! authentication. Before calling this function, ensure that the AES +//! module is properly configured the key, data size, mode, etc. Only +//! CBC-MAC and F9 modes should be used. +//! +//! \return Returns true if data was processed successfully. Returns false +//! if data processing failed. +// +//***************************************************************************** +bool +AESDataMAC(uint32_t ui32Base, uint8_t *pui8Src, uint32_t ui32Length, + uint8_t *pui8Tag) +{ + uint32_t ui32Count, ui32BlkCount, ui32ByteCount; + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Write the length register first, which triggers the engine to start + // using this context. + // + AESDataLengthSet(AES_BASE, (uint64_t) ui32Length); + + // + // Write the data registers. + // + + // + // Now loop until the blocks are written. + // + ui32BlkCount = ui32Length/16; + for(ui32Count = 0; ui32Count < ui32BlkCount; ui32Count += 1) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8Src + ui32Count*16 ,16); + } + + // + //Now handle the residue bytes + // + ui32ByteCount = ui32Length%16; + if(ui32ByteCount) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8Src + (ui32Count*ui32BlkCount) ,ui32ByteCount); + } + + // + // Wait for the context data regsiters to be ready. + // + while((AES_CTRL_SVCTXTRDY & (HWREG(AES_BASE + AES_O_CTRL))) == 0) + { + } + + // + // Read the hash tag value. + // + AESTagRead(AES_BASE, pui8Tag); + + // + // Return true to indicate successful completion of the function. + // + return(true); +} + +//***************************************************************************** +// +//! Used for Authenticated encryption (AE) of the data. Processes and authenticates blocks of data, +//! either encrypt the data or decrypt the data. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pui8Src is a pointer to the memory location where the input data +//! is stored. The data must be padded to the 16-byte boundary. +//! \param pui8Dest is a pointer to the memory location output is written. +//! The space for written data must be rounded up to the 16-byte boundary. +//! \param ui32Length is the length of the cryptographic data in bytes. +//! \param pui8AuthSrc is a pointer to the memory location where the +//! additional authentication data is stored. The data must be padded to the +//! 16-byte boundary. +//! \param ui32AuthLength is the length of the additional authentication +//! data in bytes. +//! \param pui8Tag is a pointer to a 4-word array where the hash tag is +//! written. +//! +//! This function encrypts or decrypts blocks of data in addition to +//! authentication data. A hash tag is also produced. Before calling this +//! function, ensure that the AES module is properly configured the key, +//! data size, mode, etc. Only CCM and GCM modes should be used. +//! +//! \return Returns true if data was processed successfully. Returns false +//! if data processing failed. +// +//***************************************************************************** +bool +AESDataProcessAE(uint32_t ui32Base, uint8_t *pui8Src, uint8_t *pui8Dest, + uint32_t ui32Length, uint8_t *pui8AuthSrc, + uint32_t ui32AuthLength, uint8_t *pui8Tag) +{ + uint32_t ui32Count; + + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Set the data length. + // + AESDataLengthSet(AES_BASE, (uint64_t) ui32Length); + + // + // Set the additional authentication data length. + // + AESAuthDataLengthSet(AES_BASE, ui32AuthLength); + + // + // Now loop until the authentication data blocks are written. + // + for(ui32Count = 0; ui32Count < ui32AuthLength; ui32Count += 16) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8AuthSrc + (ui32Count),16); + } + + // + // Now loop until the data blocks are written. + // + for(ui32Count = 0; ui32Count < ui32Length; ui32Count += 16) + { + // + // Write the data registers. + // + AESDataWrite(ui32Base, pui8Src + (ui32Count),16); + + // + // + // Read the data registers. + // + AESDataRead(ui32Base, pui8Dest + (ui32Count),16); + } + + // + // Wait for the context data regsiters to be ready. + // + while((AES_CTRL_SVCTXTRDY & (HWREG(AES_BASE + AES_O_CTRL))) == 0) + { + } + + // + // Read the hash tag value. + // + AESTagRead(AES_BASE, pui8Tag); + + // + // Return true to indicate successful completion of the function. + // + return(true); +} + +//***************************************************************************** +// +//! Returns the current AES module interrupt status. +//! +//! \param ui32Base is the base address of the AES module. +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! \return Returns a bit mask of the interrupt sources, which is a logical OR +//! of any of the following: +//! +//! - \b AES_INT_CONTEXT_IN - Context interrupt +//! - \b AES_INT_CONTEXT_OUT - Authentication tag (and IV) interrupt. +//! - \b AES_INT_DATA_IN - Data input interrupt +//! - \b AES_INT_DATA_OUT - Data output interrupt +//! - \b AES_INT_DMA_CONTEXT_IN - Context DMA done interrupt +//! - \b AES_INT_DMA_CONTEXT_OUT - Authentication tag (and IV) DMA done +//! interrupt +//! - \b AES_INT_DMA_DATA_IN - Data input DMA done interrupt +//! - \b AES_INT_DMA_DATA_OUT - Data output DMA done interrupt +// +//***************************************************************************** +uint32_t +AESIntStatus(uint32_t ui32Base, bool bMasked) +{ + uint32_t ui32Temp; + uint32_t ui32IrqEnable; + + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Read the IRQ status register and return the value. + // + if(bMasked) + { + ui32Temp = HWREG(DTHE_BASE + DTHE_O_AES_MIS); + ui32IrqEnable = HWREG(ui32Base + AES_O_IRQENABLE); + return((HWREG(ui32Base + AES_O_IRQSTATUS) & + ui32IrqEnable) | ((ui32Temp & 0x0000000F) << 16)); + } + else + { + ui32Temp = HWREG(DTHE_BASE + DTHE_O_AES_RIS); + return(HWREG(ui32Base + AES_O_IRQSTATUS) | + ((ui32Temp & 0x0000000F) << 16)); + } +} + +//***************************************************************************** +// +//! Enables AES module interrupts. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32IntFlags is a bit mask of the interrupt sources to enable. +//! +//! This function enables the interrupts in the AES module. The \e ui32IntFlags +//! parameter is the logical OR of any of the following: +//! +//! - \b AES_INT_CONTEXT_IN - Context interrupt +//! - \b AES_INT_CONTEXT_OUT - Authentication tag (and IV) interrupt +//! - \b AES_INT_DATA_IN - Data input interrupt +//! - \b AES_INT_DATA_OUT - Data output interrupt +//! - \b AES_INT_DMA_CONTEXT_IN - Context DMA done interrupt +//! - \b AES_INT_DMA_CONTEXT_OUT - Authentication tag (and IV) DMA done +//! interrupt +//! - \b AES_INT_DMA_DATA_IN - Data input DMA done interrupt +//! - \b AES_INT_DMA_DATA_OUT - Data output DMA done interrupt +//! +//! \note Interrupts that have been previously been enabled are not disabled +//! when this function is called. +//! +//! \return None. +// +//***************************************************************************** +void +AESIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32IntFlags == AES_INT_CONTEXT_IN) || + (ui32IntFlags == AES_INT_CONTEXT_OUT) || + (ui32IntFlags == AES_INT_DATA_IN) || + (ui32IntFlags == AES_INT_DATA_OUT) || + (ui32IntFlags == AES_INT_DMA_CONTEXT_IN) || + (ui32IntFlags == AES_INT_DMA_CONTEXT_OUT) || + (ui32IntFlags == AES_INT_DMA_DATA_IN) || + (ui32IntFlags == AES_INT_DMA_DATA_OUT)); + + // + // Set the flags. + // + HWREG(DTHE_BASE + DTHE_O_AES_IM) &= ~((ui32IntFlags & 0x000F0000) >> 16); + HWREG(ui32Base + AES_O_IRQENABLE) |= ui32IntFlags & 0x0000ffff; +} + +//***************************************************************************** +// +//! Disables AES module interrupts. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32IntFlags is a bit mask of the interrupt sources to disable. +//! +//! This function disables the interrupt sources in the AES module. The +//! \e ui32IntFlags parameter is the logical OR of any of the following: +//! +//! - \b AES_INT_CONTEXT_IN - Context interrupt +//! - \b AES_INT_CONTEXT_OUT - Authentication tag (and IV) interrupt +//! - \b AES_INT_DATA_IN - Data input interrupt +//! - \b AES_INT_DATA_OUT - Data output interrupt +//! - \b AES_INT_DMA_CONTEXT_IN - Context DMA done interrupt +//! - \b AES_INT_DMA_CONTEXT_OUT - Authentication tag (and IV) DMA done +//! interrupt +//! - \b AES_INT_DMA_DATA_IN - Data input DMA done interrupt +//! - \b AES_INT_DMA_DATA_OUT - Data output DMA done interrupt +//! +//! \note The DMA done interrupts are the only interrupts that can be cleared. +//! The remaining interrupts can be disabled instead using AESIntDisable(). +//! +//! \return None. +// +//***************************************************************************** +void +AESIntDisable(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32IntFlags == AES_INT_CONTEXT_IN) || + (ui32IntFlags == AES_INT_CONTEXT_OUT) || + (ui32IntFlags == AES_INT_DATA_IN) || + (ui32IntFlags == AES_INT_DATA_OUT) || + (ui32IntFlags == AES_INT_DMA_CONTEXT_IN) || + (ui32IntFlags == AES_INT_DMA_CONTEXT_OUT) || + (ui32IntFlags == AES_INT_DMA_DATA_IN) || + (ui32IntFlags == AES_INT_DMA_DATA_OUT)); + + // + // Clear the flags. + // + HWREG(DTHE_BASE + DTHE_O_AES_IM) |= ((ui32IntFlags & 0x000F0000) >> 16); + HWREG(ui32Base + AES_O_IRQENABLE) &= ~(ui32IntFlags & 0x0000ffff); +} + +//***************************************************************************** +// +//! Clears AES module interrupts. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32IntFlags is a bit mask of the interrupt sources to disable. +//! +//! This function clears the interrupt sources in the AES module. The +//! \e ui32IntFlags parameter is the logical OR of any of the following: +//! +//! - \b AES_INT_DMA_CONTEXT_IN - Context DMA done interrupt +//! - \b AES_INT_DMA_CONTEXT_OUT - Authentication tag (and IV) DMA done +//! interrupt +//! - \b AES_INT_DMA_DATA_IN - Data input DMA done interrupt +//! - \b AES_INT_DMA_DATA_OUT - Data output DMA done interrupt +//! +//! \note Only the DMA done interrupts can be cleared. The remaining +//! interrupts should be disabled with AESIntDisable(). +//! +//! \return None. +// +//***************************************************************************** +void +AESIntClear(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32IntFlags == AES_INT_DMA_CONTEXT_IN) || + (ui32IntFlags == AES_INT_DMA_CONTEXT_OUT) || + (ui32IntFlags == AES_INT_DMA_DATA_IN) || + (ui32IntFlags == AES_INT_DMA_DATA_OUT)); + + HWREG(DTHE_BASE + DTHE_O_AES_IC) = ((ui32IntFlags >> 16) & 0x0000000F); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! \param pfnHandler is a pointer to the function to be called when the +//! enabled AES interrupts occur. +//! +//! This function registers the interrupt handler in the interrupt vector +//! table, and enables AES interrupts on the interrupt controller; specific AES +//! interrupt sources must be enabled using AESIntEnable(). The interrupt +//! handler being registered must clear the source of the interrupt using +//! AESIntClear(). +//! +//! If the application is using a static interrupt vector table stored in +//! flash, then it is not necessary to register the interrupt handler this way. +//! Instead, IntEnable() is used to enable AES interrupts on the +//! interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +AESIntRegister(uint32_t ui32Base, void(*pfnHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Register the interrupt handler. + // + IntRegister(INT_AES, pfnHandler); + + // + // Enable the interrupt + // + IntEnable(INT_AES); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! +//! This function unregisters the previously registered interrupt handler and +//! disables the interrupt in the interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +AESIntUnregister(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + + // + // Disable the interrupt. + // + IntDisable(INT_AES); + + // + // Unregister the interrupt handler. + // + IntUnregister(INT_AES); +} + +//***************************************************************************** +// +//! Enables uDMA requests for the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32Flags is a bit mask of the uDMA requests to be enabled. +//! +//! This function enables the uDMA request sources in the AES module. +//! The \e ui32Flags parameter is the logical OR of any of the following: +//! +//! - \b AES_DMA_DATA_IN +//! - \b AES_DMA_DATA_OUT +//! - \b AES_DMA_CONTEXT_IN +//! - \b AES_DMA_CONTEXT_OUT +//! +//! \return None. +// +//***************************************************************************** +void +AESDMAEnable(uint32_t ui32Base, uint32_t ui32Flags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32Flags == AES_DMA_DATA_IN) || + (ui32Flags == AES_DMA_DATA_OUT) || + (ui32Flags == AES_DMA_CONTEXT_IN) || + (ui32Flags == AES_DMA_CONTEXT_OUT)); + + // + // Set the flags in the current register value. + // + HWREG(ui32Base + AES_O_SYSCONFIG) |= ui32Flags; +} + +//***************************************************************************** +// +//! Disables uDMA requests for the AES module. +//! +//! \param ui32Base is the base address of the AES module. +//! \param ui32Flags is a bit mask of the uDMA requests to be disabled. +//! +//! This function disables the uDMA request sources in the AES module. +//! The \e ui32Flags parameter is the logical OR of any of the +//! following: +//! +//! - \b AES_DMA_DATA_IN +//! - \b AES_DMA_DATA_OUT +//! - \b AES_DMA_CONTEXT_IN +//! - \b AES_DMA_CONTEXT_OUT +//! +//! \return None. +// +//***************************************************************************** +void +AESDMADisable(uint32_t ui32Base, uint32_t ui32Flags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == AES_BASE); + ASSERT((ui32Flags == AES_DMA_DATA_IN) || + (ui32Flags == AES_DMA_DATA_OUT) || + (ui32Flags == AES_DMA_CONTEXT_IN) || + (ui32Flags == AES_DMA_CONTEXT_OUT)); + + // + // Clear the flags in the current register value. + // + HWREG(ui32Base + AES_O_SYSCONFIG) &= ~ui32Flags; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/aes.h b/src/openmv/src/micropython/ports/cc3200/hal/aes.h new file mode 100755 index 0000000..766d358 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/aes.h @@ -0,0 +1,218 @@ +//***************************************************************************** +// +// aes.h +// +// Defines and Macros for the AES module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __DRIVERLIB_AES_H__ +#define __DRIVERLIB_AES_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// The following defines are used to specify the operation direction in the +// ui32Config argument in the AESConfig function. Only one is permitted. +// +//***************************************************************************** +#define AES_CFG_DIR_ENCRYPT 0x00000004 +#define AES_CFG_DIR_DECRYPT 0x00000000 + +//***************************************************************************** +// +// The following defines are used to specify the key size in the ui32Config +// argument in the AESConfig function. Only one is permitted. +// +//***************************************************************************** +#define AES_CFG_KEY_SIZE_128BIT 0x00000008 +#define AES_CFG_KEY_SIZE_192BIT 0x00000010 +#define AES_CFG_KEY_SIZE_256BIT 0x00000018 + +//***************************************************************************** +// +// The following defines are used to specify the mode of operation in the +// ui32Config argument in the AESConfig function. Only one is permitted. +// +//***************************************************************************** +#define AES_CFG_MODE_M 0x2007fe60 +#define AES_CFG_MODE_ECB 0x00000000 +#define AES_CFG_MODE_CBC 0x00000020 +#define AES_CFG_MODE_CTR 0x00000040 +#define AES_CFG_MODE_ICM 0x00000200 +#define AES_CFG_MODE_CFB 0x00000400 +#define AES_CFG_MODE_XTS_TWEAKJL \ + 0x00000800 +#define AES_CFG_MODE_XTS_K2IJL \ + 0x00001000 +#define AES_CFG_MODE_XTS_K2ILJ0 \ + 0x00001800 +#define AES_CFG_MODE_F8 0x00002000 +#define AES_CFG_MODE_F9 0x20004000 +#define AES_CFG_MODE_CBCMAC 0x20008000 +#define AES_CFG_MODE_GCM_HLY0ZERO \ + 0x20010040 +#define AES_CFG_MODE_GCM_HLY0CALC \ + 0x20020040 +#define AES_CFG_MODE_GCM_HY0CALC \ + 0x20030040 +#define AES_CFG_MODE_CCM 0x20040040 + +//***************************************************************************** +// +// The following defines are used to specify the counter width in the +// ui32Config argument in the AESConfig function. It is only required to +// be defined when using CTR, CCM, or GCM modes. Only one length is permitted. +// +//***************************************************************************** +#define AES_CFG_CTR_WIDTH_32 0x00000000 +#define AES_CFG_CTR_WIDTH_64 0x00000080 +#define AES_CFG_CTR_WIDTH_96 0x00000100 +#define AES_CFG_CTR_WIDTH_128 0x00000180 + +//***************************************************************************** +// +// The following defines are used to define the width of the length field for +// CCM operation through the ui32Config argument in the AESConfig function. +// This value is also known as L. Only one is permitted. +// +//***************************************************************************** +#define AES_CFG_CCM_L_2 0x00080000 +#define AES_CFG_CCM_L_4 0x00180000 +#define AES_CFG_CCM_L_8 0x00380000 + +//***************************************************************************** +// +// The following defines are used to define the length of the authentication +// field for CCM operations through the ui32Config argument in the AESConfig +// function. This value is also known as M. Only one is permitted. +// +//***************************************************************************** +#define AES_CFG_CCM_M_4 0x00400000 +#define AES_CFG_CCM_M_6 0x00800000 +#define AES_CFG_CCM_M_8 0x00c00000 +#define AES_CFG_CCM_M_10 0x01000000 +#define AES_CFG_CCM_M_12 0x01400000 +#define AES_CFG_CCM_M_14 0x01800000 +#define AES_CFG_CCM_M_16 0x01c00000 + +//***************************************************************************** +// +// Interrupt flags for use with the AESIntEnable, AESIntDisable, and +// AESIntStatus functions. +// +//***************************************************************************** +#define AES_INT_CONTEXT_IN 0x00000001 +#define AES_INT_CONTEXT_OUT 0x00000008 +#define AES_INT_DATA_IN 0x00000002 +#define AES_INT_DATA_OUT 0x00000004 +#define AES_INT_DMA_CONTEXT_IN 0x00010000 +#define AES_INT_DMA_CONTEXT_OUT 0x00020000 +#define AES_INT_DMA_DATA_IN 0x00040000 +#define AES_INT_DMA_DATA_OUT 0x00080000 + +//***************************************************************************** +// +// Defines used when enabling and disabling DMA requests in the +// AESEnableDMA and AESDisableDMA functions. +// +//***************************************************************************** +#define AES_DMA_DATA_IN 0x00000040 +#define AES_DMA_DATA_OUT 0x00000020 +#define AES_DMA_CONTEXT_IN 0x00000080 +#define AES_DMA_CONTEXT_OUT 0x00000100 + +//***************************************************************************** +// +// Function prototypes. +// +//***************************************************************************** +extern void AESConfigSet(uint32_t ui32Base, uint32_t ui32Config); +extern void AESKey1Set(uint32_t ui32Base, uint8_t *pui8Key, + uint32_t ui32Keysize); +extern void AESKey2Set(uint32_t ui32Base, uint8_t *pui8Key, + uint32_t ui32Keysize); +extern void AESKey3Set(uint32_t ui32Base, uint8_t *pui8Key); +extern void AESIVSet(uint32_t ui32Base, uint8_t *pui8IVdata); +extern void AESIVGet(uint32_t ui32Base, uint8_t *pui8IVdata); +extern void AESTagRead(uint32_t ui32Base, uint8_t *pui8TagData); +extern void AESDataLengthSet(uint32_t ui32Base, uint64_t ui64Length); +extern void AESAuthDataLengthSet(uint32_t ui32Base, uint32_t ui32Length); +extern bool AESDataReadNonBlocking(uint32_t ui32Base, uint8_t *pui8Dest, + uint8_t ui8Length); +extern void AESDataRead(uint32_t ui32Base, uint8_t *pui8Dest, + uint8_t ui8Length); +extern bool AESDataWriteNonBlocking(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t ui8Length); +extern void AESDataWrite(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t ui8Length); +extern bool AESDataProcess(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t *pui8Dest, + uint32_t ui32Length); +extern bool AESDataMAC(uint32_t ui32Base, uint8_t *pui8Src, + uint32_t ui32Length, + uint8_t *pui8Tag); +extern bool AESDataProcessAE(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t *pui8Dest, uint32_t ui32Length, + uint8_t *pui8AuthSrc, uint32_t ui32AuthLength, + uint8_t *pui8Tag); +extern uint32_t AESIntStatus(uint32_t ui32Base, bool bMasked); +extern void AESIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void AESIntDisable(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void AESIntClear(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void AESIntRegister(uint32_t ui32Base, void(*pfnHandler)(void)); +extern void AESIntUnregister(uint32_t ui32Base); +extern void AESDMAEnable(uint32_t ui32Base, uint32_t ui32Flags); +extern void AESDMADisable(uint32_t ui32Base, uint32_t ui32Flags); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __DRIVERLIB_AES_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/cc3200_asm.h b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_asm.h new file mode 100755 index 0000000..742c9a6 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_asm.h @@ -0,0 +1,94 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CC3200_ASM_H_ +#define CC3200_ASM_H_ + +// We have inlined IRQ functions for efficiency (they are generally +// 1 machine instruction). +// +// Note on IRQ state: you should not need to know the specific +// value of the state variable, but rather just pass the return +// value from disable_irq back to enable_irq. If you really need +// to know the machine-specific values, see irq.h. + +#ifndef __disable_irq +#define __disable_irq() __asm__ volatile ("cpsid i"); +#endif + +#ifndef DEBUG +__attribute__(( always_inline )) +static inline void __WFI(void) { + __asm volatile (" dsb \n" + " isb \n" + " wfi \n"); +} +#else +// For some reason the debugger gets disconnected when entering any of the sleep modes +__attribute__(( always_inline )) +static inline void __WFI(void) { + __asm volatile (" dsb \n" + " isb \n"); +} +#endif + +__attribute__(( always_inline )) +static inline uint32_t __get_PRIMASK(void) { + uint32_t result; + __asm volatile ("mrs %0, primask" : "=r" (result)); + return(result); +} + +__attribute__(( always_inline )) +static inline void __set_PRIMASK(uint32_t priMask) { + __asm volatile ("msr primask, %0" : : "r" (priMask) : "memory"); +} + +__attribute__(( always_inline )) +static inline uint32_t __get_BASEPRI(void) { + uint32_t result; + __asm volatile ("mrs %0, basepri" : "=r" (result)); + return(result); +} + +__attribute__(( always_inline )) +static inline void __set_BASEPRI(uint32_t value) { + __asm volatile ("msr basepri, %0" : : "r" (value) : "memory"); +} + +__attribute__(( always_inline )) +static inline void enable_irq(mp_uint_t state) { + __set_PRIMASK(state); +} + +__attribute__(( always_inline )) +static inline mp_uint_t disable_irq(void) { + mp_uint_t state = __get_PRIMASK(); + __disable_irq(); + return state; +} + +#endif /* CC3200_ASM_H_ */ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.c b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.c new file mode 100755 index 0000000..0285d05 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.c @@ -0,0 +1,221 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + /****************************************************************************** + IMPORTS + ******************************************************************************/ +#include +#include +#include + + +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "hw_memmap.h" +#include "rom_map.h" +#include "interrupt.h" +#include "systick.h" +#include "prcm.h" +#include "pin.h" +#include "mpexception.h" +#include "telnet.h" +#include "pybuart.h" +#include "utils.h" +#include "irq.h" +#include "moduos.h" + +#ifdef USE_FREERTOS +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#endif + + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +#ifndef USE_FREERTOS +static void hal_TickInit (void); +#endif + +/****************************************************************************** + DECLARE LOCAL DATA + ******************************************************************************/ +static volatile uint32_t HAL_tickCount; + +/****************************************************************************** + DECLARE IMPORTED DATA + ******************************************************************************/ +extern void (* const g_pfnVectors[256])(void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ + +__attribute__ ((section (".boot"))) +void HAL_SystemInit (void) { + MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]); + + // in the case of a release image, these steps are already performed by + // the bootloader so we can skip it and gain some code space +#ifdef DEBUG + MAP_IntMasterEnable(); + PRCMCC3200MCUInit(); +#endif + +#ifndef USE_FREERTOS + hal_TickInit(); +#endif +} + +void HAL_SystemDeInit (void) { +} + +void HAL_IncrementTick(void) { + HAL_tickCount++; +} + +mp_uint_t mp_hal_ticks_ms(void) { + return HAL_tickCount; +} + +// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge +// to grab a microsecond counter. +mp_uint_t mp_hal_ticks_us(void) { + mp_uint_t irq_state = disable_irq(); + uint32_t counter = SysTickValueGet(); + uint32_t milliseconds = mp_hal_ticks_ms(); + enable_irq(irq_state); + + uint32_t load = SysTickPeriodGet(); + counter = load - counter; // Convert from decrementing to incrementing + return (milliseconds * 1000) + ((counter * 1000) / load); +} + +void mp_hal_delay_ms(mp_uint_t delay) { + // only if we are not within interrupt context and interrupts are enabled + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + MP_THREAD_GIL_EXIT(); + #ifdef USE_FREERTOS + vTaskDelay (delay / portTICK_PERIOD_MS); + #else + uint32_t start = HAL_tickCount; + // wraparound of tick is taken care of by 2's complement arithmetic. + while (HAL_tickCount - start < delay) { + // enter sleep mode, waiting for (at least) the SysTick interrupt. + __WFI(); + } + #endif + MP_THREAD_GIL_ENTER(); + } else { + for (int ms = 0; ms < delay; ms++) { + UtilsDelay(UTILS_DELAY_US_TO_COUNT(1000)); + } + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + if (MP_STATE_PORT(os_term_dup_obj)) { + if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { + uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len); + } else { + MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len); + mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write); + } + } + // and also to telnet + telnet_tx_strn(str, len); +} + +void mp_hal_stdout_tx_strn_cooked (const char *str, size_t len) { + int32_t nslen = 0; + const char *_str = str; + + for (int i = 0; i < len; i++) { + if (str[i] == '\n') { + mp_hal_stdout_tx_strn(_str, nslen); + mp_hal_stdout_tx_strn("\r\n", 2); + _str += nslen + 1; + nslen = 0; + } else { + nslen++; + } + } + if (_str < str + len) { + mp_hal_stdout_tx_strn(_str, nslen); + } +} + +int mp_hal_stdin_rx_chr(void) { + for ( ;; ) { + // read telnet first + if (telnet_rx_any()) { + return telnet_rx_char(); + } else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup + if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) { + if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) { + return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o); + } + } else { + MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1); + mp_obj_t data = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read); + // data len is > 0 + if (mp_obj_is_true(data)) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + return ((int *)(bufinfo.buf))[0]; + } + } + } + mp_hal_delay_ms(1); + } +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ + +#ifndef USE_FREERTOS +static void hal_TickInit (void) { + HAL_tickCount = 0; + MAP_SysTickIntRegister(HAL_IncrementTick); + MAP_IntEnable(FAULT_SYSTICK); + MAP_SysTickIntEnable(); + MAP_SysTickPeriodSet(HAL_FCPU_HZ / HAL_SYSTICK_PERIOD_US); + // Force a reload of the SysTick counter register + HWREG(NVIC_ST_CURRENT) = 0; + MAP_SysTickEnable(); +} +#endif diff --git a/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.h b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.h new file mode 100755 index 0000000..71e245e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/cc3200_hal.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "hal/utils.h" +#include "hal/systick.h" + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ + +#define HAL_FCPU_MHZ 80U +#define HAL_FCPU_HZ (1000000U * HAL_FCPU_MHZ) +#define HAL_SYSTICK_PERIOD_US 1000U +#define UTILS_DELAY_US_TO_COUNT(us) (((us) * HAL_FCPU_MHZ) / 6) + +#define HAL_NVIC_INT_CTRL_REG (*((volatile uint32_t *) 0xE000ED04 ) ) +#define HAL_VECTACTIVE_MASK (0x1FUL) + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ + +/****************************************************************************** + DEFINE FUNCTION-LIKE MACROS + ******************************************************************************/ + +#define HAL_INTRODUCE_SYNC_BARRIER() { \ + __asm(" dsb \n" \ + " isb \n"); \ + } + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ + +extern void HAL_SystemInit (void); +extern void HAL_SystemDeInit (void); +extern void HAL_IncrementTick(void); +extern void mp_hal_set_interrupt_char (int c); + +#define mp_hal_delay_us(usec) UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec)) +#define mp_hal_ticks_cpu() (SysTickPeriodGet() - SysTickValueGet()) diff --git a/src/openmv/src/micropython/ports/cc3200/hal/cpu.c b/src/openmv/src/micropython/ports/cc3200/hal/cpu.c new file mode 100755 index 0000000..29d10af --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/cpu.c @@ -0,0 +1,412 @@ +//***************************************************************************** +// +// cpu.c +// +// Instruction wrappers for special CPU instructions needed by the +// drivers. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 "cpu.h" + +//***************************************************************************** +// +// Wrapper function for the CPSID instruction. Returns the state of PRIMASK +// on entry. +// +//***************************************************************************** +#if defined(gcc) +unsigned long __attribute__((naked)) +CPUcpsid(void) +{ + unsigned long ulRet; + + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsid i\n" + " dsb \n" + " isb \n" + " bx lr\n" + : "=r" (ulRet)); + + // + // The return is handled in the inline assembly, but the compiler will + // still complain if there is not an explicit return here (despite the fact + // that this does not result in any code being produced because of the + // naked attribute). + // + return(ulRet); +} +#endif +#if defined(ewarm) +unsigned long +CPUcpsid(void) +{ + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsid i\n" + " dsb \n" + " isb \n"); + + // + // "Warning[Pe940]: missing return statement at end of non-void function" + // is suppressed here to avoid putting a "bx lr" in the inline assembly + // above and a superfluous return statement here. + // +#pragma diag_suppress=Pe940 +} +#pragma diag_default=Pe940 +#endif +#if defined(ccs) +unsigned long +CPUcpsid(void) +{ + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsid i\n" + " dsb \n" + " isb \n" + " bx lr\n"); + + // + // The following keeps the compiler happy, because it wants to see a + // return value from this function. It will generate code to return + // a zero. However, the real return is the "bx lr" above, so the + // return(0) is never executed and the function returns with the value + // you expect in R0. + // + return(0); +} +#endif + +//***************************************************************************** +// +// Wrapper function returning the state of PRIMASK (indicating whether +// interrupts are enabled or disabled). +// +//***************************************************************************** +#if defined(gcc) +unsigned long __attribute__((naked)) +CPUprimask(void) +{ + unsigned long ulRet; + + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " bx lr\n" + : "=r" (ulRet)); + + // + // The return is handled in the inline assembly, but the compiler will + // still complain if there is not an explicit return here (despite the fact + // that this does not result in any code being produced because of the + // naked attribute). + // + return(ulRet); +} +#endif +#if defined(ewarm) +unsigned long +CPUprimask(void) +{ + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n"); + + // + // "Warning[Pe940]: missing return statement at end of non-void function" + // is suppressed here to avoid putting a "bx lr" in the inline assembly + // above and a superfluous return statement here. + // +#pragma diag_suppress=Pe940 +} +#pragma diag_default=Pe940 +#endif +#if defined(ccs) +unsigned long +CPUprimask(void) +{ + // + // Read PRIMASK and disable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " bx lr\n"); + + // + // The following keeps the compiler happy, because it wants to see a + // return value from this function. It will generate code to return + // a zero. However, the real return is the "bx lr" above, so the + // return(0) is never executed and the function returns with the value + // you expect in R0. + // + return(0); +} +#endif + +//***************************************************************************** +// +// Wrapper function for the CPSIE instruction. Returns the state of PRIMASK +// on entry. +// +//***************************************************************************** +#if defined(gcc) +unsigned long __attribute__((naked)) +CPUcpsie(void) +{ + unsigned long ulRet; + + // + // Read PRIMASK and enable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsie i\n" + " dsb \n" + " isb \n" + " bx lr\n" + : "=r" (ulRet)); + + // + // The return is handled in the inline assembly, but the compiler will + // still complain if there is not an explicit return here (despite the fact + // that this does not result in any code being produced because of the + // naked attribute). + // + return(ulRet); +} +#endif +#if defined(ewarm) +unsigned long +CPUcpsie(void) +{ + // + // Read PRIMASK and enable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsie i\n" + " dsb \n" + " isb \n"); + + // + // "Warning[Pe940]: missing return statement at end of non-void function" + // is suppressed here to avoid putting a "bx lr" in the inline assembly + // above and a superfluous return statement here. + // +#pragma diag_suppress=Pe940 +} +#pragma diag_default=Pe940 +#endif +#if defined(ccs) +unsigned long +CPUcpsie(void) +{ + // + // Read PRIMASK and enable interrupts. + // + __asm(" mrs r0, PRIMASK\n" + " cpsie i\n" + " dsb \n" + " isb \n" + " bx lr\n"); + + // + // The following keeps the compiler happy, because it wants to see a + // return value from this function. It will generate code to return + // a zero. However, the real return is the "bx lr" above, so the + // return(0) is never executed and the function returns with the value + // you expect in R0. + // + return(0); +} +#endif + +//***************************************************************************** +// +// Wrapper function for the WFI instruction. +// +//***************************************************************************** +#if defined(gcc) +void __attribute__((naked)) +CPUwfi(void) +{ + // + // Wait for the next interrupt. + // + __asm(" dsb \n" + " isb \n" + " wfi \n" + " bx lr\n"); +} +#endif +#if defined(ewarm) +void +CPUwfi(void) +{ + // + // Wait for the next interrupt. + // + __asm(" dsb \n" + " isb \n" + " wfi \n"); +} +#endif +#if defined(ccs) +void +CPUwfi(void) +{ + // + // Wait for the next interrupt. + // + __asm(" dsb \n" + " isb \n" + " wfi \n"); +} +#endif + +//***************************************************************************** +// +// Wrapper function for writing the BASEPRI register. +// +//***************************************************************************** +#if defined(gcc) +void __attribute__((naked)) +CPUbasepriSet(unsigned long ulNewBasepri) +{ + + // + // Set the BASEPRI register + // + __asm(" msr BASEPRI, r0\n" + " dsb \n" + " isb \n" + " bx lr\n"); +} +#endif +#if defined(ewarm) +void +CPUbasepriSet(unsigned long ulNewBasepri) +{ + // + // Set the BASEPRI register + // + __asm(" msr BASEPRI, r0\n" + " dsb \n" + " isb \n"); +} +#endif +#if defined(ccs) +void +CPUbasepriSet(unsigned long ulNewBasepri) +{ + // + // Set the BASEPRI register + // + __asm(" msr BASEPRI, r0\n" + " dsb \n" + " isb \n"); +} +#endif + +//***************************************************************************** +// +// Wrapper function for reading the BASEPRI register. +// +//***************************************************************************** +#if defined(gcc) +unsigned long __attribute__((naked)) +CPUbasepriGet(void) +{ + unsigned long ulRet; + + // + // Read BASEPRI + // + __asm(" mrs r0, BASEPRI\n" + " bx lr\n" + : "=r" (ulRet)); + + // + // The return is handled in the inline assembly, but the compiler will + // still complain if there is not an explicit return here (despite the fact + // that this does not result in any code being produced because of the + // naked attribute). + // + return(ulRet); +} +#endif +#if defined(ewarm) +unsigned long +CPUbasepriGet(void) +{ + // + // Read BASEPRI + // + __asm(" mrs r0, BASEPRI\n"); + + // + // "Warning[Pe940]: missing return statement at end of non-void function" + // is suppressed here to avoid putting a "bx lr" in the inline assembly + // above and a superfluous return statement here. + // +#pragma diag_suppress=Pe940 +} +#pragma diag_default=Pe940 +#endif +#if defined(ccs) +unsigned long +CPUbasepriGet(void) +{ + // + // Read BASEPRI + // + __asm(" mrs r0, BASEPRI\n" + " bx lr\n"); + + // + // The following keeps the compiler happy, because it wants to see a + // return value from this function. It will generate code to return + // a zero. However, the real return is the "bx lr" above, so the + // return(0) is never executed and the function returns with the value + // you expect in R0. + // + return(0); +} +#endif diff --git a/src/openmv/src/micropython/ports/cc3200/hal/cpu.h b/src/openmv/src/micropython/ports/cc3200/hal/cpu.h new file mode 100755 index 0000000..4a0fc0d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/cpu.h @@ -0,0 +1,75 @@ +//***************************************************************************** +// +// cpu.h +// +// Prototypes for the CPU instruction wrapper functions. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __CPU_H__ +#define __CPU_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Prototypes. +// +//***************************************************************************** +extern unsigned long CPUcpsid(void); +extern unsigned long CPUcpsie(void); +extern unsigned long CPUprimask(void); +extern void CPUwfi(void); +extern unsigned long CPUbasepriGet(void); +extern void CPUbasepriSet(unsigned long ulNewBasepri); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __CPU_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/crc.c b/src/openmv/src/micropython/ports/cc3200/hal/crc.c new file mode 100755 index 0000000..9ccb92c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/crc.c @@ -0,0 +1,305 @@ +//***************************************************************************** +// +// crc.c +// +// Driver for the CRC module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup CRC_Cyclic_Redundancy_Check_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_dthe.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "crc.h" +#include "debug.h" + +//***************************************************************************** +// +//! Set the configuration of CRC functionality with the EC module. +//! +//! \param ui32Base is the base address of the EC module. +//! \param ui32CRCConfig is the configuration of the CRC engine. +//! +//! This function configures the operation of the CRC engine within the EC +//! module. The configuration is specified with the \e ui32CRCConfig argument. +//! It is the logical OR of any of the following options: +//! +//! CRC Initialization Value +//! - \b EC_CRC_CFG_INIT_SEED - Initialize with seed value +//! - \b EC_CRC_CFG_INIT_0 - Initialize to all '0s' +//! - \b EC_CRC_CFG_INIT_1 - Initialize to all '1s' +//! +//! Input Data Size +//! - \b EC_CRC_CFG_SIZE_8BIT - Input data size of 8 bits +//! - \b EC_CRC_CFG_SIZE_32BIT - Input data size of 32 bits +//! +//! Post Process Reverse/Inverse +//! - \b EC_CRC_CFG_RESINV - Result inverse enable +//! - \b EC_CRC_CFG_OBR - Output reverse enable +//! +//! Input Bit Reverse +//! - \b EC_CRC_CFG_IBR - Bit reverse enable +//! +//! Endian Control +//! - \b EC_CRC_CFG_ENDIAN_SBHW - Swap byte in half-word +//! - \b EC_CRC_CFG_ENDIAN_SHW - Swap half-word +//! +//! Operation Type +//! - \b EC_CRC_CFG_TYPE_P8005 - Polynomial 0x8005 +//! - \b EC_CRC_CFG_TYPE_P1021 - Polynomial 0x1021 +//! - \b EC_CRC_CFG_TYPE_P4C11DB7 - Polynomial 0x4C11DB7 +//! - \b EC_CRC_CFG_TYPE_P1EDC6F41 - Polynomial 0x1EDC6F41 +//! - \b EC_CRC_CFG_TYPE_TCPCHKSUM - TCP checksum +//! +//! \return None. +// +//***************************************************************************** +void +CRCConfigSet(uint32_t ui32Base, uint32_t ui32CRCConfig) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DTHE_BASE); + ASSERT((ui32CRCConfig & CRC_CFG_INIT_SEED) || + (ui32CRCConfig & CRC_CFG_INIT_0) || + (ui32CRCConfig & CRC_CFG_INIT_1) || + (ui32CRCConfig & CRC_CFG_SIZE_8BIT) || + (ui32CRCConfig & CRC_CFG_SIZE_32BIT) || + (ui32CRCConfig & CRC_CFG_RESINV) || + (ui32CRCConfig & CRC_CFG_OBR) || + (ui32CRCConfig & CRC_CFG_IBR) || + (ui32CRCConfig & CRC_CFG_ENDIAN_SBHW) || + (ui32CRCConfig & CRC_CFG_ENDIAN_SHW) || + (ui32CRCConfig & CRC_CFG_TYPE_P8005) || + (ui32CRCConfig & CRC_CFG_TYPE_P1021) || + (ui32CRCConfig & CRC_CFG_TYPE_P4C11DB7) || + (ui32CRCConfig & CRC_CFG_TYPE_P1EDC6F41) || + (ui32CRCConfig & CRC_CFG_TYPE_TCPCHKSUM)); + + // + // Write the control register with the configuration. + // + HWREG(ui32Base + DTHE_O_CRC_CTRL) = ui32CRCConfig; +} + +//***************************************************************************** +// +//! Write the seed value for CRC operations in the EC module. +//! +//! \param ui32Base is the base address of the EC module. +//! \param ui32Seed is the seed value. +//! +//! This function writes the seed value for use with CRC operations in the +//! EC module. This value is the start value for CRC operations. If this +//! value is not written, then the residual seed from the previous operation +//! is used as the starting value. +//! +//! \note The seed must be written only if \b EC_CRC_CFG_INIT_SEED is +//! set with the CRCConfigSet() function. +// +//***************************************************************************** +void +CRCSeedSet(uint32_t ui32Base, uint32_t ui32Seed) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DTHE_BASE); + + // + // Write the seed value to the seed register. + // + HWREG(ui32Base + DTHE_O_CRC_SEED) = ui32Seed; +} + +//***************************************************************************** +// +//! Write data into the EC module for CRC operations. +//! +//! \param ui32Base is the base address of the EC module. +//! \param ui32Data is the data to be written. +//! +//! This function writes either 8 or 32 bits of data into the EC module for +//! CRC operations. The distinction between 8 and 32 bits of data is made +//! when the \b EC_CRC_CFG_SIZE_8BIT or \b EC_CRC_CFG_SIZE_32BIT flag +//! is set using the CRCConfigSet() function. +//! +//! When writing 8 bits of data, ensure the data is in the least signficant +//! byte position. The remaining bytes should be written with zero. For +//! example, when writing 0xAB, \e ui32Data should be 0x000000AB. +//! +//! \return None +// +//***************************************************************************** +void +CRCDataWrite(uint32_t ui32Base, uint32_t ui32Data) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DTHE_BASE); + + // + // Write the data + // + HWREG(DTHE_BASE + DTHE_O_CRC_DIN) = ui32Data; +} + +//***************************************************************************** +// +//! Reads the result of a CRC operation in the EC module. +//! +//! \param ui32Base is the base address of the EC module. +//! +//! This function reads either the unmodified CRC result or the post +//! processed CRC result from the EC module. The post-processing options +//! are selectable through \b EC_CRC_CFG_RESINV and \b EC_CRC_CFG_OBR +//! parameters in the CRCConfigSet() function. +//! +//! \return The CRC result. +// +//***************************************************************************** +uint32_t +CRCResultRead(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DTHE_BASE); + + // + // return value. + // + return(HWREG(DTHE_BASE + DTHE_O_CRC_RSLT_PP)); + +} + +//***************************************************************************** +// +//! Process data to generate a CRC with the EC module. +//! +//! \param ui32Base is the base address of the EC module. +//! \param puiDataIn is a pointer to an array of data that is processed. +//! \param ui32DataLength is the number of data items that are processed +//! to produce the CRC. +//! \param ui32Config the config parameter to determine the CRC mode +//! +//! This function processes an array of data to produce a CRC result. +//! This function takes the CRC mode as the parameter. +//! +//! The data in the array pointed to be \e pui32DataIn is either an array +//! of bytes or an array or words depending on the selection of the input +//! data size options \b EC_CRC_CFG_SIZE_8BIT and +//! \b EC_CRC_CFG_SIZE_32BIT. +//! +//! This function returns either the unmodified CRC result or the +//! post- processed CRC result from the EC module. The post-processing +//! options are selectable through \b EC_CRC_CFG_RESINV and +//! \b EC_CRC_CFG_OBR parameters. +//! +//! \return The CRC result. +// +//***************************************************************************** +uint32_t +CRCDataProcess(uint32_t ui32Base, void *puiDataIn, + uint32_t ui32DataLength, uint32_t ui32Config) +{ + uint8_t *pui8DataIn; + uint32_t *pui32DataIn; + + // + // Check the arguments. + // + ASSERT(ui32Base == DTHE_BASE); + + // + // See if the CRC is operating in 8-bit or 32-bit mode. + // + if(ui32Config & DTHE_CRC_CTRL_SIZE) + { + // + // The CRC is operating in 8-bit mode, so create an 8-bit pointer to + // the data. + // + pui8DataIn = (uint8_t *)puiDataIn; + + // + // Loop through the input data. + // + while(ui32DataLength--) + { + // + // Write the next data byte. + // + HWREG(ui32Base + DTHE_O_CRC_DIN) = *pui8DataIn++; + } + } + else + { + // + // The CRC is operating in 32-bit mode, so loop through the input data. + // + pui32DataIn = (uint32_t *)puiDataIn; + while(ui32DataLength--) + { + // + // Write the next data word. + // + HWREG(ui32Base + DTHE_O_CRC_DIN) = *pui32DataIn++; + } + } + + // + // Return the result. + // + return(CRCResultRead(ui32Base)); +} + + + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/crc.h b/src/openmv/src/micropython/ports/cc3200/hal/crc.h new file mode 100755 index 0000000..c0858bb --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/crc.h @@ -0,0 +1,98 @@ +//***************************************************************************** +// +// crc.h +// +// Defines and Macros for CRC module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __DRIVERLIB_CRC_H__ +#define __DRIVERLIB_CRC_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// The following defines are used in the ui32Config argument of the +// ECConfig function. +// +//***************************************************************************** +#define CRC_CFG_INIT_SEED 0x00000000 // Initialize with seed +#define CRC_CFG_INIT_0 0x00004000 // Initialize to all '0s' +#define CRC_CFG_INIT_1 0x00006000 // Initialize to all '1s' +#define CRC_CFG_SIZE_8BIT 0x00001000 // Input Data Size +#define CRC_CFG_SIZE_32BIT 0x00000000 // Input Data Size +#define CRC_CFG_RESINV 0x00000200 // Result Inverse Enable +#define CRC_CFG_OBR 0x00000100 // Output Reverse Enable +#define CRC_CFG_IBR 0x00000080 // Bit reverse enable +#define CRC_CFG_ENDIAN_SBHW 0x00000000 // Swap byte in half-word +#define CRC_CFG_ENDIAN_SHW 0x00000010 // Swap half-word +#define CRC_CFG_TYPE_P8005 0x00000000 // Polynomial 0x8005 +#define CRC_CFG_TYPE_P1021 0x00000001 // Polynomial 0x1021 +#define CRC_CFG_TYPE_P4C11DB7 0x00000002 // Polynomial 0x4C11DB7 +#define CRC_CFG_TYPE_P1EDC6F41 0x00000003 // Polynomial 0x1EDC6F41 +#define CRC_CFG_TYPE_TCPCHKSUM 0x00000008 // TCP checksum + +//***************************************************************************** +// +// Function prototypes. +// +//***************************************************************************** +extern void CRCConfigSet(uint32_t ui32Base, uint32_t ui32CRCConfig); +extern uint32_t CRCDataProcess(uint32_t ui32Base, void *puiDataIn, + uint32_t ui32DataLength, uint32_t ui32Config); +extern void CRCDataWrite(uint32_t ui32Base, uint32_t ui32Data); +extern uint32_t CRCResultRead(uint32_t ui32Base); +extern void CRCSeedSet(uint32_t ui32Base, uint32_t ui32Seed); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __DRIVERLIB_CRC_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/debug.h b/src/openmv/src/micropython/ports/cc3200/hal/debug.h new file mode 100755 index 0000000..1f65567 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/debug.h @@ -0,0 +1,63 @@ +//***************************************************************************** +// +// debug.h +// +// Macros for assisting debug of the driver library. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __DEBUG_H__ +#define __DEBUG_H__ + +#include "assert.h" + +//***************************************************************************** +// +// Prototype for the function that is called when an invalid argument is passed +// to an API. This is only used when doing a DEBUG build. +// +//***************************************************************************** + +//***************************************************************************** +// +// The ASSERT macro, which does the actual assertion checking. Typically, this +// will be for procedure arguments. +// +//***************************************************************************** +#if defined(DEBUG) && !defined(BOOTLOADER) +#define ASSERT(expr) assert(expr) +#else +#define ASSERT(expr) (void)(expr) +#endif + +#endif // __DEBUG_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/des.c b/src/openmv/src/micropython/ports/cc3200/hal/des.c new file mode 100755 index 0000000..1620e6b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/des.c @@ -0,0 +1,887 @@ +//***************************************************************************** +// +// des.c +// +// Driver for the DES data transformation. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup DES_Data_Encryption_Standard_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_des.h" +#include "inc/hw_dthe.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "debug.h" +#include "des.h" +#include "interrupt.h" + + +//***************************************************************************** +// +//! Configures the DES module for operation. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32Config is the configuration of the DES module. +//! +//! This function configures the DES module for operation. +//! +//! The \e ui32Config parameter is a bit-wise OR of a number of configuration +//! flags. The valid flags are grouped below based on their function. +//! +//! The direction of the operation is specified with one of the following two +//! flags. Only one is permitted. +//! +//! - \b DES_CFG_DIR_ENCRYPT - Encryption +//! - \b DES_CFG_DIR_DECRYPT - Decryption +//! +//! The operational mode of the DES engine is specified with one of the +//! following flags. Only one is permitted. +//! +//! - \b DES_CFG_MODE_ECB - Electronic Codebook Mode +//! - \b DES_CFG_MODE_CBC - Cipher-Block Chaining Mode +//! - \b DES_CFG_MODE_CFB - Cipher Feedback Mode +//! +//! The selection of single DES or triple DES is specified with one of the +//! following two flags. Only one is permitted. +//! +//! - \b DES_CFG_SINGLE - Single DES +//! - \b DES_CFG_TRIPLE - Triple DES +//! +//! \return None. +// +//***************************************************************************** +void +DESConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Backup the save context field. + // + ui32Config |= (HWREG(ui32Base + DES_O_CTRL) & DES_CTRL_CONTEXT); + + // + // Write the control register. + // + HWREG(ui32Base + DES_O_CTRL) = ui32Config; +} + +//***************************************************************************** +// +//! Sets the key used for DES operations. +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Key is a pointer to an array that holds the key +//! +//! This function sets the key used for DES operations. +//! +//! \e pui8Key should be 64 bits long (2 words) if single DES is being used or +//! 192 bits (6 words) if triple DES is being used. +//! +//! \return None. +// +//***************************************************************************** +void +DESKeySet(uint32_t ui32Base, uint8_t *pui8Key) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Write the first part of the key. + // + HWREG(ui32Base + DES_O_KEY1_L) = * ((uint32_t *)(pui8Key + 0)); + HWREG(ui32Base + DES_O_KEY1_H) = * ((uint32_t *)(pui8Key + 4)); + + // + // If we are performing triple DES, then write the key registers for + // the second and third rounds. + // + if(HWREG(ui32Base + DES_O_CTRL) & DES_CFG_TRIPLE) + { + HWREG(ui32Base + DES_O_KEY2_L) = * ((uint32_t *)(pui8Key + 8)); + HWREG(ui32Base + DES_O_KEY2_H) = * ((uint32_t *)(pui8Key + 12)); + HWREG(ui32Base + DES_O_KEY3_L) = * ((uint32_t *)(pui8Key + 16)); + HWREG(ui32Base + DES_O_KEY3_H) = * ((uint32_t *)(pui8Key + 20)); + } +} + +//***************************************************************************** +// +//! Sets the initialization vector in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8IVdata is a pointer to an array of 64 bits (2 words) of data to +//! be written into the initialization vectors registers. +//! +//! This function sets the initialization vector in the DES module. It returns +//! true if the registers were successfully written. If the context registers +//! cannot be written at the time the function was called, then false is +//! returned. +//! +//! \return True or false. +// +//***************************************************************************** +bool +DESIVSet(uint32_t ui32Base, uint8_t *pui8IVdata) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Check to see if context registers can be overwritten. If not, return + // false. + // + if((HWREG(ui32Base + DES_O_CTRL) & DES_CTRL_CONTEXT) == 0) + { + return(false); + } + + // + // Write the initialization vector registers. + // + HWREG(ui32Base + DES_O_IV_L) = *((uint32_t *) (pui8IVdata + 0)); + HWREG(ui32Base + DES_O_IV_H) = *((uint32_t *) (pui8IVdata + 4)); + + // + // Return true to indicate the write was successful. + // + return(true); +} + +//***************************************************************************** +// +//! Sets the crytographic data length in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32Length is the length of the data in bytes. +//! +//! This function writes the cryptographic data length into the DES module. +//! When this register is written, the engine is triggersed to start using +//! this context. +//! +//! \note Data lengths up to (2^32 - 1) bytes are allowed. +//! +//! \return None. +// +//***************************************************************************** +void +DESDataLengthSet(uint32_t ui32Base, uint32_t ui32Length) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Write the length register. + // + HWREG(ui32Base + DES_O_LENGTH) = ui32Length; +} + +//***************************************************************************** +// +//! Reads plaintext/ciphertext from data registers without blocking +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Dest is a pointer to an array of 2 words. +//! \param ui8Length the length can be from 1 to 8 +//! +//! This function returns true if the data was ready when the function was +//! called. If the data was not ready, false is returned. +//! +//! \return True or false. +// +//***************************************************************************** +bool +DESDataReadNonBlocking(uint32_t ui32Base, uint8_t *pui8Dest, uint8_t ui8Length) +{ + volatile uint32_t pui32Dest[2]; + uint8_t ui8BytCnt; + uint8_t *pui8DestTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + if((ui8Length == 0)||(ui8Length>8)) + { + return(false); + } + + // + // Check to see if the data is ready to be read. + // + if((DES_CTRL_OUTPUT_READY & (HWREG(ui32Base + DES_O_CTRL))) == 0) + { + return(false); + } + + // + // Read two words of data from the data registers. + // + pui32Dest[0] = HWREG(DES_BASE + DES_O_DATA_L); + pui32Dest[1] = HWREG(DES_BASE + DES_O_DATA_H); + + // + //Copy the data to a block memory + // + pui8DestTemp = (uint8_t *)pui32Dest; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8Dest+ui8BytCnt) = *(pui8DestTemp+ui8BytCnt); + } + + // + // Return true to indicate a successful write. + // + return(true); +} + +//***************************************************************************** +// +//! Reads plaintext/ciphertext from data registers with blocking. +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Dest is a pointer to an array of bytes. +//! \param ui8Length the length can be from 1 to 8 +//! +//! This function waits until the DES module is finished and encrypted or +//! decrypted data is ready. The output data is then stored in the pui8Dest +//! array. +//! +//! \return None +// +//***************************************************************************** +void +DESDataRead(uint32_t ui32Base, uint8_t *pui8Dest, uint8_t ui8Length) +{ + volatile uint32_t pui32Dest[2]; + uint8_t ui8BytCnt; + uint8_t *pui8DestTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + if((ui8Length == 0)||(ui8Length>8)) + { + return; + } + // + // Wait for data output to be ready. + // + while((HWREG(ui32Base + DES_O_CTRL) & DES_CTRL_OUTPUT_READY) == 0) + { + } + + // + // Read two words of data from the data registers. + // + pui32Dest[0] = HWREG(DES_BASE + DES_O_DATA_L); + pui32Dest[1] = HWREG(DES_BASE + DES_O_DATA_H); + + // + //Copy the data to a block memory + // + pui8DestTemp = (uint8_t *)pui32Dest; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8Dest+ui8BytCnt) = *(pui8DestTemp+ui8BytCnt); + } +} + +//***************************************************************************** +// +//! Writes plaintext/ciphertext to data registers without blocking +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Src is a pointer to an array of 2 words. +//! \param ui8Length the length can be from 1 to 8 +//! +//! This function returns false if the DES module is not ready to accept +//! data. It returns true if the data was written successfully. +//! +//! \return true or false. +// +//***************************************************************************** +bool +DESDataWriteNonBlocking(uint32_t ui32Base, uint8_t *pui8Src, uint8_t ui8Length) +{ + + volatile uint32_t pui32Src[2]={0,0}; + uint8_t ui8BytCnt; + uint8_t *pui8SrcTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + if((ui8Length == 0)||(ui8Length>8)) + { + return(false); + } + + // + // Check if the DES module is ready to encrypt or decrypt data. If it + // is not, return false. + // + if(!(DES_CTRL_INPUT_READY & (HWREG(ui32Base + DES_O_CTRL)))) + { + return(false); + } + + // + // Copy the data to a block memory + // + pui8SrcTemp = (uint8_t *)pui32Src; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8SrcTemp+ui8BytCnt) = *(pui8Src+ui8BytCnt); + } + + // + // Write the data. + // + HWREG(DES_BASE + DES_O_DATA_L) = pui32Src[0]; + HWREG(DES_BASE + DES_O_DATA_H) = pui32Src[1]; + + // + // Return true to indicate a successful write. + // + return(true); +} + +//***************************************************************************** +// +//! Writes plaintext/ciphertext to data registers without blocking +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Src is a pointer to an array of bytes. +//! \param ui8Length the length can be from 1 to 8 +//! +//! This function waits until the DES module is ready before writing the +//! data contained in the pui8Src array. +//! +//! \return None. +// +//***************************************************************************** +void +DESDataWrite(uint32_t ui32Base, uint8_t *pui8Src, uint8_t ui8Length) +{ + volatile uint32_t pui32Src[2]={0,0}; + uint8_t ui8BytCnt; + uint8_t *pui8SrcTemp; + + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + if((ui8Length == 0)||(ui8Length>8)) + { + return; + } + + // + // Wait for the input ready bit to go high. + // + while(((HWREG(ui32Base + DES_O_CTRL) & DES_CTRL_INPUT_READY)) == 0) + { + } + + // + //Copy the data to a block memory + // + pui8SrcTemp = (uint8_t *)pui32Src; + for(ui8BytCnt = 0; ui8BytCnt < ui8Length ; ui8BytCnt++) + { + *(pui8SrcTemp+ui8BytCnt) = *(pui8Src+ui8BytCnt); + } + + // + // Write the data. + // + HWREG(DES_BASE + DES_O_DATA_L) = pui32Src[0]; + HWREG(DES_BASE + DES_O_DATA_H) = pui32Src[1]; +} + +//***************************************************************************** +// +//! Processes blocks of data through the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param pui8Src is a pointer to an array of words that contains the +//! source data for processing. +//! \param pui8Dest is a pointer to an array of words consisting of the +//! processed data. +//! \param ui32Length is the length of the cryptographic data in bytes. +//! It must be a multiple of eight. +//! +//! This function takes the data contained in the pui8Src array and processes +//! it using the DES engine. The resulting data is stored in the +//! pui8Dest array. The function blocks until all of the data has been +//! processed. If processing is successful, the function returns true. +//! +//! \note This functions assumes that the DES module has been configured, +//! and initialization values and keys have been written. +//! +//! \return true or false. +// +//***************************************************************************** +bool +DESDataProcess(uint32_t ui32Base, uint8_t *pui8Src, uint8_t *pui8Dest, + uint32_t ui32Length) +{ + uint32_t ui32Count, ui32BlkCount, ui32ByteCount; + + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + ASSERT((ui32Length % 8) == 0); + + // + // Write the length register first. This triggers the engine to start + // using this context. + // + HWREG(ui32Base + DES_O_LENGTH) = ui32Length; + + + // + // Now loop until the blocks are written. + // + ui32BlkCount = ui32Length/8; + for(ui32Count = 0; ui32Count > 16); + HWREG(ui32Base + DES_O_IRQENABLE) |= ui32IntFlags & 0x0000ffff; +} + +//***************************************************************************** +// +//! Disables interrupts in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32IntFlags is a bit mask of the interrupts to be disabled. +//! +//! This function disables interrupt sources in the DES module. +//! \e ui32IntFlags should be a logical OR of one or more of the following +//! values: +//! +//! - \b DES_INT_CONTEXT_IN - Context interrupt +//! - \b DES_INT_DATA_IN - Data input interrupt +//! - \b DES_INT_DATA_OUT - Data output interrupt +//! - \b DES_INT_DMA_CONTEXT_IN - Context DMA done interrupt +//! - \b DES_INT_DMA_DATA_IN - Data input DMA done interrupt +//! - \b DES_INT_DMA_DATA_OUT - Data output DMA done interrupt +//! +//! \return None. +// +//***************************************************************************** +void +DESIntDisable(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + ASSERT((ui32IntFlags & DES_INT_CONTEXT_IN) || + (ui32IntFlags & DES_INT_DATA_IN) || + (ui32IntFlags & DES_INT_DATA_OUT) || + (ui32IntFlags & DES_INT_DMA_CONTEXT_IN) || + (ui32IntFlags & DES_INT_DMA_DATA_IN) || + (ui32IntFlags & DES_INT_DMA_DATA_OUT)); + + // + // Clear the interrupts from the flags. + // + HWREG(DTHE_BASE + DTHE_O_AES_IM) |= ((ui32IntFlags & 0x00070000) >> 16); + HWREG(ui32Base + DES_O_IRQENABLE) &= ~(ui32IntFlags & 0x0000ffff); +} + +//***************************************************************************** +// +//! Clears interrupts in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32IntFlags is a bit mask of the interrupts to be disabled. +//! +//! This function disables interrupt sources in the DES module. +//! \e ui32IntFlags should be a logical OR of one or more of the following +//! values: +//! +//! - \b DES_INT_DMA_CONTEXT_IN - Context interrupt +//! - \b DES_INT_DMA_DATA_IN - Data input interrupt +//! - \b DES_INT_DMA_DATA_OUT - Data output interrupt +//! +//! \note The DMA done interrupts are the only interrupts that can be cleared. +//! The remaining interrupts can be disabled instead using DESIntDisable(). +//! +//! \return None. +// +//***************************************************************************** +void +DESIntClear(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + ASSERT((ui32IntFlags & DES_INT_DMA_CONTEXT_IN) || + (ui32IntFlags & DES_INT_DMA_DATA_IN) || + (ui32IntFlags & DES_INT_DMA_DATA_OUT)); + + HWREG(DTHE_BASE + DTHE_O_DES_IC) = ((ui32IntFlags & 0x00070000) >> 16); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param pfnHandler is a pointer to the function to be called when the +//! enabled DES interrupts occur. +//! +//! This function registers the interrupt handler in the interrupt vector +//! table, and enables DES interrupts on the interrupt controller; specific DES +//! interrupt sources must be enabled using DESIntEnable(). The interrupt +//! handler being registered must clear the source of the interrupt using +//! DESIntClear(). +//! +//! If the application is using a static interrupt vector table stored in +//! flash, then it is not necessary to register the interrupt handler this way. +//! Instead, IntEnable() should be used to enable DES interrupts on the +//! interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +DESIntRegister(uint32_t ui32Base, void(*pfnHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Register the interrupt handler. + // + IntRegister(INT_DES, pfnHandler); + + // + // Enable the interrupt. + // + IntEnable(INT_DES); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! +//! This function unregisters the previously registered interrupt handler and +//! disables the interrupt in the interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +DESIntUnregister(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + + // + // Disable the interrupt. + // + IntDisable(INT_DES); + + // + // Unregister the interrupt handler. + // + IntUnregister(INT_DES); +} + +//***************************************************************************** +// +//! Enables DMA request sources in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32Flags is a bit mask of the DMA requests to be enabled. +//! +//! This function enables DMA request sources in the DES module. The +//! \e ui32Flags parameter should be the logical OR of any of the following: +//! +//! - \b DES_DMA_CONTEXT_IN - Context In +//! - \b DES_DMA_DATA_OUT - Data Out +//! - \b DES_DMA_DATA_IN - Data In +//! +//! \return None. +// +//***************************************************************************** +void +DESDMAEnable(uint32_t ui32Base, uint32_t ui32Flags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + ASSERT((ui32Flags & DES_DMA_CONTEXT_IN) || + (ui32Flags & DES_DMA_DATA_OUT) || + (ui32Flags & DES_DMA_DATA_IN)); + + // + // Set the data in and data out DMA request enable bits. + // + HWREG(ui32Base + DES_O_SYSCONFIG) |= ui32Flags; +} + +//***************************************************************************** +// +//! Disables DMA request sources in the DES module. +//! +//! \param ui32Base is the base address of the DES module. +//! \param ui32Flags is a bit mask of the DMA requests to be disabled. +//! +//! This function disables DMA request sources in the DES module. The +//! \e ui32Flags parameter should be the logical OR of any of the following: +//! +//! - \b DES_DMA_CONTEXT_IN - Context In +//! - \b DES_DMA_DATA_OUT - Data Out +//! - \b DES_DMA_DATA_IN - Data In +//! +//! \return None. +// +//***************************************************************************** +void +DESDMADisable(uint32_t ui32Base, uint32_t ui32Flags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == DES_BASE); + ASSERT((ui32Flags & DES_DMA_CONTEXT_IN) || + (ui32Flags & DES_DMA_DATA_OUT) || + (ui32Flags & DES_DMA_DATA_IN)); + + // + // Disable the DMA sources. + // + HWREG(ui32Base + DES_O_SYSCONFIG) &= ~ui32Flags; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/des.h b/src/openmv/src/micropython/ports/cc3200/hal/des.h new file mode 100755 index 0000000..3bee5e6 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/des.h @@ -0,0 +1,143 @@ +//***************************************************************************** +// +// des.h +// +// Defines and Macros for the DES module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __DRIVERLIB_DES_H__ +#define __DRIVERLIB_DES_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// The following defines are used to specify the direction with the +// ui32Config argument in the DESConfig() function. Only one is permitted. +// +//***************************************************************************** +#define DES_CFG_DIR_DECRYPT 0x00000000 +#define DES_CFG_DIR_ENCRYPT 0x00000004 + +//***************************************************************************** +// +// The following defines are used to specify the operational with the +// ui32Config argument in the DESConfig() function. Only one is permitted. +// +//***************************************************************************** +#define DES_CFG_MODE_ECB 0x00000000 +#define DES_CFG_MODE_CBC 0x00000010 +#define DES_CFG_MODE_CFB 0x00000020 + +//***************************************************************************** +// +// The following defines are used to select between single DES and triple DES +// with the ui32Config argument in the DESConfig() function. Only one is +// permitted. +// +//***************************************************************************** +#define DES_CFG_SINGLE 0x00000000 +#define DES_CFG_TRIPLE 0x00000008 + +//***************************************************************************** +// +// The following defines are used with the DESIntEnable(), DESIntDisable() and +// DESIntStatus() functions. +// +//***************************************************************************** +#define DES_INT_CONTEXT_IN 0x00000001 +#define DES_INT_DATA_IN 0x00000002 +#define DES_INT_DATA_OUT 0x00000004 +#define DES_INT_DMA_CONTEXT_IN 0x00010000 +#define DES_INT_DMA_DATA_IN 0x00020000 +#define DES_INT_DMA_DATA_OUT 0x00040000 + +//***************************************************************************** +// +// The following defines are used with the DESEnableDMA() and DESDisableDMA() +// functions. +// +//***************************************************************************** +#define DES_DMA_CONTEXT_IN 0x00000080 +#define DES_DMA_DATA_OUT 0x00000040 +#define DES_DMA_DATA_IN 0x00000020 + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void DESConfigSet(uint32_t ui32Base, uint32_t ui32Config); +extern void DESDataRead(uint32_t ui32Base, uint8_t *pui8Dest, + uint8_t ui8Length); +extern bool DESDataReadNonBlocking(uint32_t ui32Base, uint8_t *pui8Dest, + uint8_t ui8Length); +extern bool DESDataProcess(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t *pui8Dest, uint32_t ui32Length); +extern void DESDataWrite(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t ui8Length); +extern bool DESDataWriteNonBlocking(uint32_t ui32Base, uint8_t *pui8Src, + uint8_t ui8Length); +extern void DESDMADisable(uint32_t ui32Base, uint32_t ui32Flags); +extern void DESDMAEnable(uint32_t ui32Base, uint32_t ui32Flags); +extern void DESIntClear(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void DESIntDisable(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void DESIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void DESIntRegister(uint32_t ui32Base, void(*pfnHandler)(void)); +extern uint32_t DESIntStatus(uint32_t ui32Base, bool bMasked); +extern void DESIntUnregister(uint32_t ui32Base); +extern bool DESIVSet(uint32_t ui32Base, uint8_t *pui8IVdata); +extern void DESKeySet(uint32_t ui32Base, uint8_t *pui8Key); +extern void DESDataLengthSet(uint32_t ui32Base, uint32_t ui32Length); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __DRIVERLIB_DES_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/fault_registers.h b/src/openmv/src/micropython/ports/cc3200/hal/fault_registers.h new file mode 100755 index 0000000..ade516b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/fault_registers.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef FAULT_REGISTERS_H_ +#define FAULT_REGISTERS_H_ + + +typedef struct +{ + uint32_t IERR :1; + uint32_t DERR :1; + uint32_t :1; + uint32_t MUSTKE :1; + uint32_t MSTKE :1; + uint32_t MLSPERR :1; + uint32_t :1; + uint32_t MMARV :1; + uint32_t IBUS :1; + uint32_t PRECISE :1; + uint32_t IMPRE :1; + uint32_t BUSTKE :1; + uint32_t BSTKE :1; + uint32_t BLSPERR :1; + uint32_t :1; + uint32_t BFARV :1; + uint32_t UNDEF :1; + uint32_t INVSTAT :1; + uint32_t INVCP :1; + uint32_t NOCP :1; + uint32_t :4; + uint32_t UNALIGN :1; + uint32_t DIVO0 :1; + uint32_t :6; + +}_CFSR_t; + + +typedef struct +{ + + uint32_t DBG :1; + uint32_t FORCED :1; + uint32_t :28; + uint32_t VECT :1; + uint32_t :1; + +}_HFSR_t; + + +#endif /* FAULT_REGISTERS_H_ */ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/gpio.c b/src/openmv/src/micropython/ports/cc3200/hal/gpio.c new file mode 100755 index 0000000..59aa71a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/gpio.c @@ -0,0 +1,706 @@ +//***************************************************************************** +// +// gpio.c +// +// Driver for the GPIO module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup GPIO_General_Purpose_InputOutput_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_common_reg.h" +#include "debug.h" +#include "gpio.h" +#include "interrupt.h" + + +//***************************************************************************** +// +//! \internal +//! Checks a GPIO base address. +//! +//! \param ulPort is the base address of the GPIO port. +//! +//! This function determines if a GPIO port base address is valid. +//! +//! \return Returns \b true if the base address is valid and \b false +//! otherwise. +// +//***************************************************************************** +#if defined(DEBUG) && !defined(BOOTLOADER) +static tBoolean +GPIOBaseValid(unsigned long ulPort) +{ + return((ulPort == GPIOA0_BASE) || + (ulPort == GPIOA1_BASE) || + (ulPort == GPIOA2_BASE) || + (ulPort == GPIOA3_BASE) || + (ulPort == GPIOA4_BASE)); +} +#else +#define GPIOBaseValid(ulPort) (ulPort) +#endif + +//***************************************************************************** +// +//! \internal +//! Gets the GPIO interrupt number. +//! +//! \param ulPort is the base address of the GPIO port. +//! +//! Given a GPIO base address, returns the corresponding interrupt number. +//! +//! \return Returns a GPIO interrupt number, or -1 if \e ulPort is invalid. +// +//***************************************************************************** +static long +GPIOGetIntNumber(unsigned long ulPort) +{ + unsigned int ulInt; + + // + // Determine the GPIO interrupt number for the given module. + // + switch(ulPort) + { + case GPIOA0_BASE: + { + ulInt = INT_GPIOA0; + break; + } + + case GPIOA1_BASE: + { + ulInt = INT_GPIOA1; + break; + } + + case GPIOA2_BASE: + { + ulInt = INT_GPIOA2; + break; + } + + case GPIOA3_BASE: + { + ulInt = INT_GPIOA3; + break; + } + + default: + { + return(-1); + } + } + + // + // Return GPIO interrupt number. + // + return(ulInt); +} + +//***************************************************************************** +// +//! Sets the direction and mode of the specified pin(s). +//! +//! \param ulPort is the base address of the GPIO port +//! \param ucPins is the bit-packed representation of the pin(s). +//! \param ulPinIO is the pin direction and/or mode. +//! +//! This function will set the specified pin(s) on the selected GPIO port +//! as either an input or output under software control, or it will set the +//! pin to be under hardware control. +//! +//! The parameter \e ulPinIO is an enumerated data type that can be one of +//! the following values: +//! +//! - \b GPIO_DIR_MODE_IN +//! - \b GPIO_DIR_MODE_OUT +//! +//! where \b GPIO_DIR_MODE_IN specifies that the pin will be programmed as +//! a software controlled input, \b GPIO_DIR_MODE_OUT specifies that the pin +//! will be programmed as a software controlled output. +//! +//! The pin(s) are specified using a bit-packed byte, where each bit that is +//! set identifies the pin to be accessed, and where bit 0 of the byte +//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on. +//! +//! \note GPIOPadConfigSet() must also be used to configure the corresponding +//! pad(s) in order for them to propagate the signal to/from the GPIO. +//! +//! \return None. +// +//***************************************************************************** +void +GPIODirModeSet(unsigned long ulPort, unsigned char ucPins, + unsigned long ulPinIO) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + ASSERT((ulPinIO == GPIO_DIR_MODE_IN) || (ulPinIO == GPIO_DIR_MODE_OUT)); + + // + // Set the pin direction and mode. + // + HWREG(ulPort + GPIO_O_GPIO_DIR) = ((ulPinIO & 1) ? + (HWREG(ulPort + GPIO_O_GPIO_DIR) | ucPins) : + (HWREG(ulPort + GPIO_O_GPIO_DIR) & ~(ucPins))); +} + +//***************************************************************************** +// +//! Gets the direction and mode of a pin. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ucPin is the pin number. +//! +//! This function gets the direction and control mode for a specified pin on +//! the selected GPIO port. The pin can be configured as either an input or +//! output under software control, or it can be under hardware control. The +//! type of control and direction are returned as an enumerated data type. +//! +//! \return Returns one of the enumerated data types described for +//! GPIODirModeSet(). +// +//***************************************************************************** +unsigned long +GPIODirModeGet(unsigned long ulPort, unsigned char ucPin) +{ + unsigned long ulDir; + + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Return the pin direction + // + ulDir = HWREG(ulPort + GPIO_O_GPIO_DIR); + return(((ulDir & ucPin) ? 1 : 0)); +} + +//***************************************************************************** +// +//! Sets the interrupt type for the specified pin(s). +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ucPins is the bit-packed representation of the pin(s). +//! \param ulIntType specifies the type of interrupt trigger mechanism. +//! +//! This function sets up the various interrupt trigger mechanisms for the +//! specified pin(s) on the selected GPIO port. +//! +//! The parameter \e ulIntType is an enumerated data type that can be one of +//! the following values: +//! +//! - \b GPIO_FALLING_EDGE +//! - \b GPIO_RISING_EDGE +//! - \b GPIO_BOTH_EDGES +//! - \b GPIO_LOW_LEVEL +//! - \b GPIO_HIGH_LEVEL +//! +//! The pin(s) are specified using a bit-packed byte, where each bit that is +//! set identifies the pin to be accessed, and where bit 0 of the byte +//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on. +//! +//! \note In order to avoid any spurious interrupts, the user must +//! ensure that the GPIO inputs remain stable for the duration of +//! this function. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntTypeSet(unsigned long ulPort, unsigned char ucPins, + unsigned long ulIntType) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + ASSERT((ulIntType == GPIO_FALLING_EDGE) || + (ulIntType == GPIO_RISING_EDGE) || (ulIntType == GPIO_BOTH_EDGES) || + (ulIntType == GPIO_LOW_LEVEL) || (ulIntType == GPIO_HIGH_LEVEL)); + + // + // Set the pin interrupt type. + // + HWREG(ulPort + GPIO_O_GPIO_IBE) = ((ulIntType & 1) ? + (HWREG(ulPort + GPIO_O_GPIO_IBE) | ucPins) : + (HWREG(ulPort + GPIO_O_GPIO_IBE) & ~(ucPins))); + HWREG(ulPort + GPIO_O_GPIO_IS) = ((ulIntType & 2) ? + (HWREG(ulPort + GPIO_O_GPIO_IS) | ucPins) : + (HWREG(ulPort + GPIO_O_GPIO_IS) & ~(ucPins))); + HWREG(ulPort + GPIO_O_GPIO_IEV) = ((ulIntType & 4) ? + (HWREG(ulPort + GPIO_O_GPIO_IEV) | ucPins) : + (HWREG(ulPort + GPIO_O_GPIO_IEV) & ~(ucPins))); +} + +//***************************************************************************** +// +//! Gets the interrupt type for a pin. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ucPin is the pin number. +//! +//! This function gets the interrupt type for a specified pin on the selected +//! GPIO port. The pin can be configured as a falling edge, rising edge, or +//! both edge detected interrupt, or it can be configured as a low level or +//! high level detected interrupt. The type of interrupt detection mechanism +//! is returned as an enumerated data type. +//! +//! \return Returns one of the enumerated data types described for +//! GPIOIntTypeSet(). +// +//***************************************************************************** +unsigned long +GPIOIntTypeGet(unsigned long ulPort, unsigned char ucPin) +{ + unsigned long ulIBE, ulIS, ulIEV; + + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Return the pin interrupt type. + // + ulIBE = HWREG(ulPort + GPIO_O_GPIO_IBE); + ulIS = HWREG(ulPort + GPIO_O_GPIO_IS); + ulIEV = HWREG(ulPort + GPIO_O_GPIO_IEV); + return(((ulIBE & ucPin) ? 1 : 0) | ((ulIS & ucPin) ? 2 : 0) | + ((ulIEV & ucPin) ? 4 : 0)); +} + +//***************************************************************************** +// +//! Enables the specified GPIO interrupts. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ulIntFlags is the bit mask of the interrupt sources to enable. +//! +//! This function enables the indicated GPIO interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b GPIO_INT_DMA - interrupt due to GPIO triggered DMA Done +//! - \b GPIO_INT_PIN_0 - interrupt due to activity on Pin 0. +//! - \b GPIO_INT_PIN_1 - interrupt due to activity on Pin 1. +//! - \b GPIO_INT_PIN_2 - interrupt due to activity on Pin 2. +//! - \b GPIO_INT_PIN_3 - interrupt due to activity on Pin 3. +//! - \b GPIO_INT_PIN_4 - interrupt due to activity on Pin 4. +//! - \b GPIO_INT_PIN_5 - interrupt due to activity on Pin 5. +//! - \b GPIO_INT_PIN_6 - interrupt due to activity on Pin 6. +//! - \b GPIO_INT_PIN_7 - interrupt due to activity on Pin 7. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntEnable(unsigned long ulPort, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Enable the interrupts. + // + HWREG(ulPort + GPIO_O_GPIO_IM) |= ulIntFlags; +} + +//***************************************************************************** +// +//! Disables the specified GPIO interrupts. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ulIntFlags is the bit mask of the interrupt sources to disable. +//! +//! This function disables the indicated GPIO interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b GPIO_INT_DMA - interrupt due to GPIO triggered DMA Done +//! - \b GPIO_INT_PIN_0 - interrupt due to activity on Pin 0. +//! - \b GPIO_INT_PIN_1 - interrupt due to activity on Pin 1. +//! - \b GPIO_INT_PIN_2 - interrupt due to activity on Pin 2. +//! - \b GPIO_INT_PIN_3 - interrupt due to activity on Pin 3. +//! - \b GPIO_INT_PIN_4 - interrupt due to activity on Pin 4. +//! - \b GPIO_INT_PIN_5 - interrupt due to activity on Pin 5. +//! - \b GPIO_INT_PIN_6 - interrupt due to activity on Pin 6. +//! - \b GPIO_INT_PIN_7 - interrupt due to activity on Pin 7. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntDisable(unsigned long ulPort, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Disable the interrupts. + // + HWREG(ulPort + GPIO_O_GPIO_IM) &= ~(ulIntFlags); +} + +//***************************************************************************** +// +//! Gets interrupt status for the specified GPIO port. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param bMasked specifies whether masked or raw interrupt status is +//! returned. +//! +//! If \e bMasked is set as \b true, then the masked interrupt status is +//! returned; otherwise, the raw interrupt status will be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in GPIOIntEnable(). +// +//***************************************************************************** +long +GPIOIntStatus(unsigned long ulPort, tBoolean bMasked) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Return the interrupt status. + // + if(bMasked) + { + return(HWREG(ulPort + GPIO_O_GPIO_MIS)); + } + else + { + return(HWREG(ulPort + GPIO_O_GPIO_RIS)); + } +} + +//***************************************************************************** +// +//! Clears the interrupt for the specified pin(s). +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! Clears the interrupt for the specified pin(s). +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to GPIOIntEnable(). +//! +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntClear(unsigned long ulPort, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Clear the interrupts. + // + HWREG(ulPort + GPIO_O_GPIO_ICR) = ulIntFlags; +} + +//***************************************************************************** +// +//! Registers an interrupt handler for a GPIO port. +//! +//! \param ulPort is the base address of the GPIO port. +//! \param pfnIntHandler is a pointer to the GPIO port interrupt handling +//! function. +//! +//! This function will ensure that the interrupt handler specified by +//! \e pfnIntHandler is called when an interrupt is detected from the selected +//! GPIO port. This function will also enable the corresponding GPIO interrupt +//! in the interrupt controller; individual pin interrupts and interrupt +//! sources must be enabled with GPIOIntEnable(). +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntRegister(unsigned long ulPort, void (*pfnIntHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Get the interrupt number associated with the specified GPIO. + // + ulPort = GPIOGetIntNumber(ulPort); + + // + // Register the interrupt handler. + // + IntRegister(ulPort, pfnIntHandler); + + // + // Enable the GPIO interrupt. + // + IntEnable(ulPort); +} + +//***************************************************************************** +// +//! Removes an interrupt handler for a GPIO port. +//! +//! \param ulPort is the base address of the GPIO port. +//! +//! This function will unregister the interrupt handler for the specified +//! GPIO port. This function will also disable the corresponding +//! GPIO port interrupt in the interrupt controller; individual GPIO interrupts +//! and interrupt sources must be disabled with GPIOIntDisable(). +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOIntUnregister(unsigned long ulPort) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Get the interrupt number associated with the specified GPIO. + // + ulPort = GPIOGetIntNumber(ulPort); + + // + // Disable the GPIO interrupt. + // + IntDisable(ulPort); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulPort); +} + +//***************************************************************************** +// +//! Reads the values present of the specified pin(s). +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ucPins is the bit-packed representation of the pin(s). +//! +//! The values at the specified pin(s) are read, as specified by \e ucPins. +//! Values are returned for both input and output pin(s), and the value +//! for pin(s) that are not specified by \e ucPins are set to 0. +//! +//! The pin(s) are specified using a bit-packed byte, where each bit that is +//! set identifies the pin to be accessed, and where bit 0 of the byte +//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on. +//! +//! \return Returns a bit-packed byte providing the state of the specified +//! pin, where bit 0 of the byte represents GPIO port pin 0, bit 1 represents +//! GPIO port pin 1, and so on. Any bit that is not specified by \e ucPins +//! is returned as a 0. Bits 31:8 should be ignored. +// +//***************************************************************************** +long +GPIOPinRead(unsigned long ulPort, unsigned char ucPins) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Return the pin value(s). + // + return(HWREG(ulPort + (GPIO_O_GPIO_DATA + (ucPins << 2)))); +} + +//***************************************************************************** +// +//! Writes a value to the specified pin(s). +//! +//! \param ulPort is the base address of the GPIO port. +//! \param ucPins is the bit-packed representation of the pin(s). +//! \param ucVal is the value to write to the pin(s). +//! +//! Writes the corresponding bit values to the output pin(s) specified by +//! \e ucPins. Writing to a pin configured as an input pin has no effect. +//! +//! The pin(s) are specified using a bit-packed byte, where each bit that is +//! set identifies the pin to be accessed, and where bit 0 of the byte +//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on. +//! +//! \return None. +// +//***************************************************************************** +void +GPIOPinWrite(unsigned long ulPort, unsigned char ucPins, unsigned char ucVal) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Write the pins. + // + HWREG(ulPort + (GPIO_O_GPIO_DATA + (ucPins << 2))) = ucVal; +} + +//***************************************************************************** +// +//! Enables a GPIO port as a trigger to start a DMA transaction. +//! +//! \param ulPort is the base address of the GPIO port. +//! +//! This function enables a GPIO port to be used as a trigger to start a uDMA +//! transaction. The GPIO pin will still generate interrupts if the interrupt is +//! enabled for the selected pin. +//! +//! \return None. +// +//***************************************************************************** +void +GPIODMATriggerEnable(unsigned long ulPort) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Set the pin as a DMA trigger. + // + if(ulPort == GPIOA0_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) |= 0x1; + } + else if(ulPort == GPIOA1_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) |= 0x2; + } + else if(ulPort == GPIOA2_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) |= 0x4; + } + else if(ulPort == GPIOA3_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) |= 0x8; + } +} + +//***************************************************************************** +// +//! Disables a GPIO port as a trigger to start a DMA transaction. +//! +//! \param ulPort is the base address of the GPIO port. +//! +//! This function disables a GPIO port to be used as a trigger to start a uDMA +//! transaction. This function can be used to disable this feature if it was +//! enabled via a call to GPIODMATriggerEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +GPIODMATriggerDisable(unsigned long ulPort) +{ + // + // Check the arguments. + // + ASSERT(GPIOBaseValid(ulPort)); + + // + // Set the pin as a DMA trigger. + // + if(ulPort == GPIOA0_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) &= ~0x1; + } + else if(ulPort == GPIOA1_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) &= ~0x2; + } + else if(ulPort == GPIOA2_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) &= ~0x4; + } + else if(ulPort == GPIOA3_BASE) + { + HWREG(COMMON_REG_BASE + COMMON_REG_O_APPS_GPIO_TRIG_EN) &= ~0x8; + } +} + + +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/gpio.h b/src/openmv/src/micropython/ports/cc3200/hal/gpio.h new file mode 100755 index 0000000..35acf79 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/gpio.h @@ -0,0 +1,139 @@ +//***************************************************************************** +// +// gpio.h +// +// Defines and Macros for GPIO API. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __GPIO_H__ +#define __GPIO_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// The following values define the bit field for the ucPins argument to several +// of the APIs. +// +//***************************************************************************** +#define GPIO_PIN_0 0x00000001 // GPIO pin 0 +#define GPIO_PIN_1 0x00000002 // GPIO pin 1 +#define GPIO_PIN_2 0x00000004 // GPIO pin 2 +#define GPIO_PIN_3 0x00000008 // GPIO pin 3 +#define GPIO_PIN_4 0x00000010 // GPIO pin 4 +#define GPIO_PIN_5 0x00000020 // GPIO pin 5 +#define GPIO_PIN_6 0x00000040 // GPIO pin 6 +#define GPIO_PIN_7 0x00000080 // GPIO pin 7 + +//***************************************************************************** +// +// Values that can be passed to GPIODirModeSet as the ulPinIO parameter, and +// returned from GPIODirModeGet. +// +//***************************************************************************** +#define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input +#define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output + +//***************************************************************************** +// +// Values that can be passed to GPIOIntTypeSet as the ulIntType parameter, and +// returned from GPIOIntTypeGet. +// +//***************************************************************************** +#define GPIO_FALLING_EDGE 0x00000000 // Interrupt on falling edge +#define GPIO_RISING_EDGE 0x00000004 // Interrupt on rising edge +#define GPIO_BOTH_EDGES 0x00000001 // Interrupt on both edges +#define GPIO_LOW_LEVEL 0x00000002 // Interrupt on low level +#define GPIO_HIGH_LEVEL 0x00000006 // Interrupt on high level + +//***************************************************************************** +// +// Values that can be passed to GPIOIntEnable() and GPIOIntDisable() functions +// in the ulIntFlags parameter. +// +//***************************************************************************** +#define GPIO_INT_DMA 0x00000100 +#define GPIO_INT_PIN_0 0x00000001 +#define GPIO_INT_PIN_1 0x00000002 +#define GPIO_INT_PIN_2 0x00000004 +#define GPIO_INT_PIN_3 0x00000008 +#define GPIO_INT_PIN_4 0x00000010 +#define GPIO_INT_PIN_5 0x00000020 +#define GPIO_INT_PIN_6 0x00000040 +#define GPIO_INT_PIN_7 0x00000080 + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern void GPIODirModeSet(unsigned long ulPort, unsigned char ucPins, + unsigned long ulPinIO); +extern unsigned long GPIODirModeGet(unsigned long ulPort, unsigned char ucPin); +extern void GPIOIntTypeSet(unsigned long ulPort, unsigned char ucPins, + unsigned long ulIntType); +extern void GPIODMATriggerEnable(unsigned long ulPort); +extern void GPIODMATriggerDisable(unsigned long ulPort); +extern unsigned long GPIOIntTypeGet(unsigned long ulPort, unsigned char ucPin); +extern void GPIOIntEnable(unsigned long ulPort, unsigned long ulIntFlags); +extern void GPIOIntDisable(unsigned long ulPort, unsigned long ulIntFlags); +extern long GPIOIntStatus(unsigned long ulPort, tBoolean bMasked); +extern void GPIOIntClear(unsigned long ulPort, unsigned long ulIntFlags); +extern void GPIOIntRegister(unsigned long ulPort, + void (*pfnIntHandler)(void)); +extern void GPIOIntUnregister(unsigned long ulPort); +extern long GPIOPinRead(unsigned long ulPort, unsigned char ucPins); +extern void GPIOPinWrite(unsigned long ulPort, unsigned char ucPins, + unsigned char ucVal); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __GPIO_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/i2c.c b/src/openmv/src/micropython/ports/cc3200/hal/i2c.c new file mode 100755 index 0000000..487f93c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/i2c.c @@ -0,0 +1,2043 @@ +//***************************************************************************** +// +// i2c.c +// +// Driver for Inter-IC (I2C) bus block. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup I2C_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_i2c.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "debug.h" +#include "i2c.h" +#include "interrupt.h" + +//***************************************************************************** +// +// A mapping of I2C base address to interrupt number. +// +//***************************************************************************** +static const uint32_t g_ppui32I2CIntMap[][2] = +{ + { I2CA0_BASE, INT_I2CA0}, +}; + +static const int_fast8_t g_i8I2CIntMapRows = + sizeof(g_ppui32I2CIntMap) / sizeof(g_ppui32I2CIntMap[0]); + +//***************************************************************************** +// +//! \internal +//! Checks an I2C base address. +//! +//! \param ui32Base is the base address of the I2C module. +//! +//! This function determines if a I2C module base address is valid. +//! +//! \return Returns \b true if the base address is valid and \b false +//! otherwise. +// +//***************************************************************************** +#ifdef DEBUG +static bool +_I2CBaseValid(uint32_t ui32Base) +{ + return((ui32Base == I2CA0_BASE)); +} +#else +#define _I2CBaseValid(ui32Base) (ui32Base) +#endif + +//***************************************************************************** +// +//! \internal +//! Gets the I2C interrupt number. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! Given a I2C base address, this function returns the corresponding +//! interrupt number. +//! +//! \return Returns an I2C interrupt number, or 0 if \e ui32Base is invalid. +// +//***************************************************************************** +static uint32_t +_I2CIntNumberGet(uint32_t ui32Base) +{ + int_fast8_t i8Idx, i8Rows; + const uint32_t (*ppui32I2CIntMap)[2]; + + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + ppui32I2CIntMap = g_ppui32I2CIntMap; + i8Rows = g_i8I2CIntMapRows; + + // + // Loop through the table that maps I2C base addresses to interrupt + // numbers. + // + for(i8Idx = 0; i8Idx < i8Rows; i8Idx++) + { + // + // See if this base address matches. + // + if(ppui32I2CIntMap[i8Idx][0] == ui32Base) + { + // + // Return the corresponding interrupt number. + // + return(ppui32I2CIntMap[i8Idx][1]); + } + } + + // + // The base address could not be found, so return an error. + // + return(0); +} + +//***************************************************************************** +// +//! Initializes the I2C Master block. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32I2CClk is the rate of the clock supplied to the I2C module. +//! \param bFast set up for fast data transfers. +//! +//! This function initializes operation of the I2C Master block by configuring +//! the bus speed for the master and enabling the I2C Master block. +//! +//! If the parameter \e bFast is \b true, then the master block is set up to +//! transfer data at 400 Kbps; otherwise, it is set up to transfer data at +//! 100 Kbps. If Fast Mode Plus (1 Mbps) is desired, software should manually +//! write the I2CMTPR after calling this function. For High Speed (3.4 Mbps) +//! mode, a specific command is used to switch to the faster clocks after the +//! initial communication with the slave is done at either 100 Kbps or +//! 400 Kbps. +//! +//! The peripheral clock is the same as the processor clock. This value is +//! returned by SysCtlClockGet(), or it can be explicitly hard coded if it is +//! constant and known (to save the code/execution overhead of a call to +//! SysCtlClockGet()). +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterInitExpClk(uint32_t ui32Base, uint32_t ui32SCLFreq) +{ + uint32_t ui32TPR; + + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Must enable the device before doing anything else. + // + I2CMasterEnable(ui32Base); + + // + // Compute the clock divider that achieves the fastest speed less than or + // equal to the desired speed. The numerator is biased to favor a larger + // clock divider so that the resulting clock is always less than or equal + // to the desired clock, never greater. + // + ui32TPR = ((80000000 + (2 * 10 * ui32SCLFreq) - 1) / + (2 * 10 * ui32SCLFreq)) - 1; + HWREG(ui32Base + I2C_O_MTPR) = ui32TPR; + + // + // Check to see if this I2C peripheral is High-Speed enabled. If yes, also + // choose the fastest speed that is less than or equal to 3.4 Mbps. + // + if(HWREG(ui32Base + I2C_O_PP) & I2C_PP_HS) + { + ui32TPR = ((80000000 + (2 * 3 * 3400000) - 1) / + (2 * 3 * 3400000)) - 1; + HWREG(ui32Base + I2C_O_MTPR) = I2C_MTPR_HS | ui32TPR; + } +} + +//***************************************************************************** +// +//! Initializes the I2C Slave block. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui8SlaveAddr 7-bit slave address +//! +//! This function initializes operation of the I2C Slave block by configuring +//! the slave address and enabling the I2C Slave block. +//! +//! The parameter \e ui8SlaveAddr is the value that is compared against the +//! slave address sent by an I2C master. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveInit(uint32_t ui32Base, uint8_t ui8SlaveAddr) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + ASSERT(!(ui8SlaveAddr & 0x80)); + + // + // Must enable the device before doing anything else. + // + I2CSlaveEnable(ui32Base); + + // + // Set up the slave address. + // + HWREG(ui32Base + I2C_O_SOAR) = ui8SlaveAddr; +} + +//***************************************************************************** +// +//! Sets the I2C slave address. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui8AddrNum determines which slave address is set. +//! \param ui8SlaveAddr is the 7-bit slave address +//! +//! This function writes the specified slave address. The \e ui32AddrNum field +//! dictates which slave address is configured. For example, a value of 0 +//! configures the primary address and a value of 1 configures the secondary. +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveAddressSet(uint32_t ui32Base, uint8_t ui8AddrNum, uint8_t ui8SlaveAddr) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + ASSERT(!(ui8AddrNum > 1)); + ASSERT(!(ui8SlaveAddr & 0x80)); + + // + // Determine which slave address is being set. + // + switch(ui8AddrNum) + { + // + // Set up the primary slave address. + // + case 0: + { + HWREG(ui32Base + I2C_O_SOAR) = ui8SlaveAddr; + break; + } + + // + // Set up and enable the secondary slave address. + // + case 1: + { + HWREG(ui32Base + I2C_O_SOAR2) = I2C_SOAR2_OAR2EN | ui8SlaveAddr; + break; + } + } +} + +//***************************************************************************** +// +//! Enables the I2C Master block. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function enables operation of the I2C Master block. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterEnable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the master block. + // + HWREG(ui32Base + I2C_O_MCR) |= I2C_MCR_MFE; +} + +//***************************************************************************** +// +//! Enables the I2C Slave block. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This fucntion enables operation of the I2C Slave block. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveEnable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the clock to the slave block. + // + HWREG(ui32Base + I2C_O_MCR) |= I2C_MCR_SFE; + + // + // Enable the slave. + // + HWREG(ui32Base + I2C_O_SCSR) = I2C_SCSR_DA; +} + +//***************************************************************************** +// +//! Disables the I2C master block. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function disables operation of the I2C master block. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterDisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the master block. + // + HWREG(ui32Base + I2C_O_MCR) &= ~(I2C_MCR_MFE); +} + +//***************************************************************************** +// +//! Disables the I2C slave block. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function disables operation of the I2C slave block. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveDisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the slave. + // + HWREG(ui32Base + I2C_O_SCSR) = 0; + + // + // Disable the clock to the slave block. + // + HWREG(ui32Base + I2C_O_MCR) &= ~(I2C_MCR_SFE); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the I2C module. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param pfnHandler is a pointer to the function to be called when the +//! I2C interrupt occurs. +//! +//! This function sets the handler to be called when an I2C interrupt occurs. +//! This function enables the global interrupt in the interrupt controller; +//! specific I2C interrupts must be enabled via I2CMasterIntEnable() and +//! I2CSlaveIntEnable(). If necessary, it is the interrupt handler's +//! responsibility to clear the interrupt source via I2CMasterIntClear() and +//! I2CSlaveIntClear(). +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +I2CIntRegister(uint32_t ui32Base, void (*pfnHandler)(void)) +{ + uint32_t ui32Int; + + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Determine the interrupt number based on the I2C port. + // + ui32Int = _I2CIntNumberGet(ui32Base); + + ASSERT(ui32Int != 0); + + // + // Register the interrupt handler, returning an error if an error occurs. + // + IntRegister(ui32Int, pfnHandler); + + // + // Enable the I2C interrupt. + // + IntEnable(ui32Int); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the I2C module. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function clears the handler to be called when an I2C interrupt +//! occurs. This function also masks off the interrupt in the interrupt r +//! controller so that the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +I2CIntUnregister(uint32_t ui32Base) +{ + uint32_t ui32Int; + + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Determine the interrupt number based on the I2C port. + // + ui32Int = _I2CIntNumberGet(ui32Base); + + ASSERT(ui32Int != 0); + + // + // Disable the interrupt. + // + IntDisable(ui32Int); + + // + // Unregister the interrupt handler. + // + IntUnregister(ui32Int); +} + +//***************************************************************************** +// +//! Enables the I2C Master interrupt. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function enables the I2C Master interrupt source. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntEnable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the master interrupt. + // + HWREG(ui32Base + I2C_O_MIMR) = 1; +} + +//***************************************************************************** +// +//! Enables individual I2C Master interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32IntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated I2C Master interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ui32IntFlags parameter is the logical OR of any of the following: +//! +//! - \b I2C_MASTER_INT_RX_FIFO_FULL - RX FIFO Full interrupt +//! - \b I2C_MASTER_INT_TX_FIFO_EMPTY - TX FIFO Empty interrupt +//! - \b I2C_MASTER_INT_RX_FIFO_REQ - RX FIFO Request interrupt +//! - \b I2C_MASTER_INT_TX_FIFO_REQ - TX FIFO Request interrupt +//! - \b I2C_MASTER_INT_ARB_LOST - Arbitration Lost interrupt +//! - \b I2C_MASTER_INT_STOP - Stop Condition interrupt +//! - \b I2C_MASTER_INT_START - Start Condition interrupt +//! - \b I2C_MASTER_INT_NACK - Address/Data NACK interrupt +//! - \b I2C_MASTER_INT_TX_DMA_DONE - TX DMA Complete interrupt +//! - \b I2C_MASTER_INT_RX_DMA_DONE - RX DMA Complete interrupt +//! - \b I2C_MASTER_INT_TIMEOUT - Clock Timeout interrupt +//! - \b I2C_MASTER_INT_DATA - Data interrupt +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntEnableEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the master interrupt. + // + HWREG(ui32Base + I2C_O_MIMR) |= ui32IntFlags; +} + +//***************************************************************************** +// +//! Enables the I2C Slave interrupt. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function enables the I2C Slave interrupt source. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntEnable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the slave interrupt. + // + HWREG(ui32Base + I2C_O_SIMR) |= I2C_SLAVE_INT_DATA; +} + +//***************************************************************************** +// +//! Enables individual I2C Slave interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui32IntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated I2C Slave interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ui32IntFlags parameter is the logical OR of any of the following: +//! +//! - \b I2C_SLAVE_INT_RX_FIFO_FULL - RX FIFO Full interrupt +//! - \b I2C_SLAVE_INT_TX_FIFO_EMPTY - TX FIFO Empty interrupt +//! - \b I2C_SLAVE_INT_RX_FIFO_REQ - RX FIFO Request interrupt +//! - \b I2C_SLAVE_INT_TX_FIFO_REQ - TX FIFO Request interrupt +//! - \b I2C_SLAVE_INT_TX_DMA_DONE - TX DMA Complete interrupt +//! - \b I2C_SLAVE_INT_RX_DMA_DONE - RX DMA Complete interrupt +//! - \b I2C_SLAVE_INT_STOP - Stop condition detected interrupt +//! - \b I2C_SLAVE_INT_START - Start condition detected interrupt +//! - \b I2C_SLAVE_INT_DATA - Data interrupt +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntEnableEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the slave interrupt. + // + HWREG(ui32Base + I2C_O_SIMR) |= ui32IntFlags; +} + +//***************************************************************************** +// +//! Disables the I2C Master interrupt. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function disables the I2C Master interrupt source. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntDisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the master interrupt. + // + HWREG(ui32Base + I2C_O_MIMR) = 0; +} + +//***************************************************************************** +// +//! Disables individual I2C Master interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32IntFlags is the bit mask of the interrupt sources to be +//! disabled. +//! +//! This function disables the indicated I2C Master interrupt sources. Only +//! the sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ui32IntFlags parameter has the same definition as the +//! \e ui32IntFlags parameter to I2CMasterIntEnableEx(). +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntDisableEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the master interrupt. + // + HWREG(ui32Base + I2C_O_MIMR) &= ~ui32IntFlags; +} + +//***************************************************************************** +// +//! Disables the I2C Slave interrupt. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function disables the I2C Slave interrupt source. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntDisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the slave interrupt. + // + HWREG(ui32Base + I2C_O_SIMR) &= ~I2C_SLAVE_INT_DATA; +} + +//***************************************************************************** +// +//! Disables individual I2C Slave interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui32IntFlags is the bit mask of the interrupt sources to be +//! disabled. +//! +//! This function disables the indicated I2C Slave interrupt sources. Only +//! the sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ui32IntFlags parameter has the same definition as the +//! \e ui32IntFlags parameter to I2CSlaveIntEnableEx(). +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntDisableEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable the slave interrupt. + // + HWREG(ui32Base + I2C_O_SIMR) &= ~ui32IntFlags; +} + +//***************************************************************************** +// +//! Gets the current I2C Master interrupt status. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param bMasked is false if the raw interrupt status is requested and +//! true if the masked interrupt status is requested. +//! +//! This function returns the interrupt status for the I2C Master module. +//! Either the raw interrupt status or the status of interrupts that are +//! allowed to reflect to the processor can be returned. +//! +//! \return The current interrupt status, returned as \b true if active +//! or \b false if not active. +// +//***************************************************************************** +bool +I2CMasterIntStatus(uint32_t ui32Base, bool bMasked) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return((HWREG(ui32Base + I2C_O_MMIS)) ? true : false); + } + else + { + return((HWREG(ui32Base + I2C_O_MRIS)) ? true : false); + } +} + +//***************************************************************************** +// +//! Gets the current I2C Master interrupt status. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param bMasked is false if the raw interrupt status is requested and +//! true if the masked interrupt status is requested. +//! +//! This function returns the interrupt status for the I2C Master module. +//! Either the raw interrupt status or the status of interrupts that are +//! allowed to reflect to the processor can be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in I2CMasterIntEnableEx(). +// +//***************************************************************************** +uint32_t +I2CMasterIntStatusEx(uint32_t ui32Base, bool bMasked) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return(HWREG(ui32Base + I2C_O_MMIS)); + } + else + { + return(HWREG(ui32Base + I2C_O_MRIS)); + } +} + +//***************************************************************************** +// +//! Gets the current I2C Slave interrupt status. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param bMasked is false if the raw interrupt status is requested and +//! true if the masked interrupt status is requested. +//! +//! This function returns the interrupt status for the I2C Slave module. +//! Either the raw interrupt status or the status of interrupts that are +//! allowed to reflect to the processor can be returned. +//! +//! \return The current interrupt status, returned as \b true if active +//! or \b false if not active. +// +//***************************************************************************** +bool +I2CSlaveIntStatus(uint32_t ui32Base, bool bMasked) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return((HWREG(ui32Base + I2C_O_SMIS)) ? true : false); + } + else + { + return((HWREG(ui32Base + I2C_O_SRIS)) ? true : false); + } +} + +//***************************************************************************** +// +//! Gets the current I2C Slave interrupt status. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param bMasked is false if the raw interrupt status is requested and +//! true if the masked interrupt status is requested. +//! +//! This function returns the interrupt status for the I2C Slave module. +//! Either the raw interrupt status or the status of interrupts that are +//! allowed to reflect to the processor can be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in I2CSlaveIntEnableEx(). +// +//***************************************************************************** +uint32_t +I2CSlaveIntStatusEx(uint32_t ui32Base, bool bMasked) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return(HWREG(ui32Base + I2C_O_SMIS)); + } + else + { + return(HWREG(ui32Base + I2C_O_SRIS)); + } +} + +//***************************************************************************** +// +//! Clears I2C Master interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! The I2C Master interrupt source is cleared, so that it no longer +//! asserts. This function must be called in the interrupt handler to keep the +//! interrupt from being triggered again immediately upon exit. +//! +//! \note Because there is a write buffer in the Cortex-M processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntClear(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear the I2C master interrupt source. + // + HWREG(ui32Base + I2C_O_MICR) = I2C_MICR_IC; + + // + // Workaround for I2C master interrupt clear errata for some + // devices. For later devices, this write is ignored and therefore + // harmless (other than the slight performance hit). + // + HWREG(ui32Base + I2C_O_MMIS) = I2C_MICR_IC; +} + +//***************************************************************************** +// +//! Clears I2C Master interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32IntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified I2C Master interrupt sources are cleared, so that they no +//! longer assert. This function must be called in the interrupt handler to +//! keep the interrupt from being triggered again immediately upon exit. +//! +//! The \e ui32IntFlags parameter has the same definition as the +//! \e ui32IntFlags parameter to I2CMasterIntEnableEx(). +//! +//! \note Because there is a write buffer in the Cortex-M processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterIntClearEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear the I2C master interrupt source. + // + HWREG(ui32Base + I2C_O_MICR) = ui32IntFlags; +} + +//***************************************************************************** +// +//! Clears I2C Slave interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! The I2C Slave interrupt source is cleared, so that it no longer asserts. +//! This function must be called in the interrupt handler to keep the interrupt +//! from being triggered again immediately upon exit. +//! +//! \note Because there is a write buffer in the Cortex-M processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntClear(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear the I2C slave interrupt source. + // + HWREG(ui32Base + I2C_O_SICR) = I2C_SICR_DATAIC; +} + +//***************************************************************************** +// +//! Clears I2C Slave interrupt sources. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui32IntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified I2C Slave interrupt sources are cleared, so that they no +//! longer assert. This function must be called in the interrupt handler to +//! keep the interrupt from being triggered again immediately upon exit. +//! +//! The \e ui32IntFlags parameter has the same definition as the +//! \e ui32IntFlags parameter to I2CSlaveIntEnableEx(). +//! +//! \note Because there is a write buffer in the Cortex-M processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveIntClearEx(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear the I2C slave interrupt source. + // + HWREG(ui32Base + I2C_O_SICR) = ui32IntFlags; +} + +//***************************************************************************** +// +//! Sets the address that the I2C Master places on the bus. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui8SlaveAddr 7-bit slave address +//! \param bReceive flag indicating the type of communication with the slave +//! +//! This function configures the address that the I2C Master places on the +//! bus when initiating a transaction. When the \e bReceive parameter is set +//! to \b true, the address indicates that the I2C Master is initiating a +//! read from the slave; otherwise the address indicates that the I2C +//! Master is initiating a write to the slave. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterSlaveAddrSet(uint32_t ui32Base, uint8_t ui8SlaveAddr, + bool bReceive) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + ASSERT(!(ui8SlaveAddr & 0x80)); + + // + // Set the address of the slave with which the master will communicate. + // + HWREG(ui32Base + I2C_O_MSA) = (ui8SlaveAddr << 1) | bReceive; +} + +//***************************************************************************** +// +//! Reads the state of the SDA and SCL pins. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function returns the state of the I2C bus by providing the real time +//! values of the SDA and SCL pins. +//! +//! +//! \return Returns the state of the bus with SDA in bit position 1 and SCL in +//! bit position 0. +// +//***************************************************************************** +uint32_t +I2CMasterLineStateGet(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return the line state. + // + return(HWREG(ui32Base + I2C_O_MBMON)); +} + +//***************************************************************************** +// +//! Indicates whether or not the I2C Master is busy. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function returns an indication of whether or not the I2C Master is +//! busy transmitting or receiving data. +//! +//! \return Returns \b true if the I2C Master is busy; otherwise, returns +//! \b false. +// +//***************************************************************************** +bool +I2CMasterBusy(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return the busy status. + // + if(HWREG(ui32Base + I2C_O_MCS) & I2C_MCS_BUSY) + { + return(true); + } + else + { + return(false); + } +} + +//***************************************************************************** +// +//! Indicates whether or not the I2C bus is busy. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function returns an indication of whether or not the I2C bus is busy. +//! This function can be used in a multi-master environment to determine if +//! another master is currently using the bus. +//! +//! \return Returns \b true if the I2C bus is busy; otherwise, returns +//! \b false. +// +//***************************************************************************** +bool +I2CMasterBusBusy(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return the bus busy status. + // + if(HWREG(ui32Base + I2C_O_MCS) & I2C_MCS_BUSBSY) + { + return(true); + } + else + { + return(false); + } +} + +//***************************************************************************** +// +//! Controls the state of the I2C Master module. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32Cmd command to be issued to the I2C Master module. +//! +//! This function is used to control the state of the Master module send and +//! receive operations. The \e ui8Cmd parameter can be one of the following +//! values: +//! +//! - \b I2C_MASTER_CMD_SINGLE_SEND +//! - \b I2C_MASTER_CMD_SINGLE_RECEIVE +//! - \b I2C_MASTER_CMD_BURST_SEND_START +//! - \b I2C_MASTER_CMD_BURST_SEND_CONT +//! - \b I2C_MASTER_CMD_BURST_SEND_FINISH +//! - \b I2C_MASTER_CMD_BURST_SEND_ERROR_STOP +//! - \b I2C_MASTER_CMD_BURST_RECEIVE_START +//! - \b I2C_MASTER_CMD_BURST_RECEIVE_CONT +//! - \b I2C_MASTER_CMD_BURST_RECEIVE_FINISH +//! - \b I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP +//! - \b I2C_MASTER_CMD_QUICK_COMMAND +//! - \b I2C_MASTER_CMD_HS_MASTER_CODE_SEND +//! - \b I2C_MASTER_CMD_FIFO_SINGLE_SEND +//! - \b I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE +//! - \b I2C_MASTER_CMD_FIFO_BURST_SEND_START +//! - \b I2C_MASTER_CMD_FIFO_BURST_SEND_CONT +//! - \b I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH +//! - \b I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP +//! - \b I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START +//! - \b I2C_MASTER_CMD_FIFO_BURST_RECEIVE_CONT +//! - \b I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH +//! - \b I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterControl(uint32_t ui32Base, uint32_t ui32Cmd) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + ASSERT((ui32Cmd == I2C_MASTER_CMD_SINGLE_SEND) || + (ui32Cmd == I2C_MASTER_CMD_SINGLE_RECEIVE) || + (ui32Cmd == I2C_MASTER_CMD_BURST_SEND_START) || + (ui32Cmd == I2C_MASTER_CMD_BURST_SEND_CONT) || + (ui32Cmd == I2C_MASTER_CMD_BURST_SEND_FINISH) || + (ui32Cmd == I2C_MASTER_CMD_BURST_SEND_ERROR_STOP) || + (ui32Cmd == I2C_MASTER_CMD_BURST_RECEIVE_START) || + (ui32Cmd == I2C_MASTER_CMD_BURST_RECEIVE_CONT) || + (ui32Cmd == I2C_MASTER_CMD_BURST_RECEIVE_FINISH) || + (ui32Cmd == I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP) || + (ui32Cmd == I2C_MASTER_CMD_QUICK_COMMAND) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_SINGLE_SEND) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_SEND_START) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_SEND_CONT) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_RECEIVE_CONT) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH) || + (ui32Cmd == I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP) || + (ui32Cmd == I2C_MASTER_CMD_HS_MASTER_CODE_SEND)); + + // + // Send the command. + // + HWREG(ui32Base + I2C_O_MCS) = ui32Cmd; +} + +//***************************************************************************** +// +//! Gets the error status of the I2C Master module. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function is used to obtain the error status of the Master module send +//! and receive operations. +//! +//! \return Returns the error status, as one of \b I2C_MASTER_ERR_NONE, +//! \b I2C_MASTER_ERR_ADDR_ACK, \b I2C_MASTER_ERR_DATA_ACK, or +//! \b I2C_MASTER_ERR_ARB_LOST. +// +//***************************************************************************** +uint32_t +I2CMasterErr(uint32_t ui32Base) +{ + uint32_t ui32Err; + + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Get the raw error state + // + ui32Err = HWREG(ui32Base + I2C_O_MCS); + + // + // If the I2C master is busy, then all the other bit are invalid, and + // don't have an error to report. + // + if(ui32Err & I2C_MCS_BUSY) + { + return(I2C_MASTER_ERR_NONE); + } + + // + // Check for errors. + // + if(ui32Err & (I2C_MCS_ERROR | I2C_MCS_ARBLST)) + { + return(ui32Err & (I2C_MCS_ARBLST | I2C_MCS_ACK | I2C_MCS_ADRACK)); + } + else + { + return(I2C_MASTER_ERR_NONE); + } +} + +//***************************************************************************** +// +//! Transmits a byte from the I2C Master. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui8Data data to be transmitted from the I2C Master. +//! +//! This function places the supplied data into I2C Master Data Register. +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterDataPut(uint32_t ui32Base, uint8_t ui8Data) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Write the byte. + // + HWREG(ui32Base + I2C_O_MDR) = ui8Data; +} + +//***************************************************************************** +// +//! Receives a byte that has been sent to the I2C Master. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function reads a byte of data from the I2C Master Data Register. +//! +//! \return Returns the byte received from by the I2C Master, cast as an +//! uint32_t. +// +//***************************************************************************** +uint32_t +I2CMasterDataGet(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Read a byte. + // + return(HWREG(ui32Base + I2C_O_MDR)); +} + +//***************************************************************************** +// +//! Sets the Master clock timeout value. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32Value is the number of I2C clocks before the timeout is +//! asserted. +//! +//! This function enables and configures the clock low timeout feature in the +//! I2C peripheral. This feature is implemented as a 12-bit counter, with the +//! upper 8-bits being programmable. For example, to program a timeout of 20ms +//! with a 100kHz SCL frequency, \e ui32Value would be 0x7d. +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterTimeoutSet(uint32_t ui32Base, uint32_t ui32Value) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Write the timeout value. + // + HWREG(ui32Base + I2C_O_MCLKOCNT) = ui32Value; +} + +//***************************************************************************** +// +//! Configures ACK override behavior of the I2C Slave. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param bEnable enables or disables ACK override. +//! +//! This function enables or disables ACK override, allowing the user +//! application to drive the value on SDA during the ACK cycle. +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveACKOverride(uint32_t ui32Base, bool bEnable) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable or disable based on bEnable. + // + if(bEnable) + { + HWREG(ui32Base + I2C_O_SACKCTL) |= I2C_SACKCTL_ACKOEN; + } + else + { + HWREG(ui32Base + I2C_O_SACKCTL) &= ~I2C_SACKCTL_ACKOEN; + } +} + +//***************************************************************************** +// +//! Writes the ACK value. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param bACK chooses whether to ACK (true) or NACK (false) the transfer. +//! +//! This function puts the desired ACK value on SDA during the ACK cycle. The +//! value written is only valid when ACK override is enabled using +//! I2CSlaveACKOverride(). +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveACKValueSet(uint32_t ui32Base, bool bACK) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // ACK or NACK based on the value of bACK. + // + if(bACK) + { + HWREG(ui32Base + I2C_O_SACKCTL) &= ~I2C_SACKCTL_ACKOVAL; + } + else + { + HWREG(ui32Base + I2C_O_SACKCTL) |= I2C_SACKCTL_ACKOVAL; + } +} + +//***************************************************************************** +// +//! Gets the I2C Slave module status +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function returns the action requested from a master, if any. +//! Possible values are: +//! +//! - \b I2C_SLAVE_ACT_NONE +//! - \b I2C_SLAVE_ACT_RREQ +//! - \b I2C_SLAVE_ACT_TREQ +//! - \b I2C_SLAVE_ACT_RREQ_FBR +//! - \b I2C_SLAVE_ACT_OWN2SEL +//! - \b I2C_SLAVE_ACT_QCMD +//! - \b I2C_SLAVE_ACT_QCMD_DATA +//! +//! \note Not all devices support the second I2C slave's own address +//! or the quick command function. Please consult the device data sheet to +//! determine if these features are supported. +//! +//! \return Returns \b I2C_SLAVE_ACT_NONE to indicate that no action has been +//! requested of the I2C Slave module, \b I2C_SLAVE_ACT_RREQ to indicate that +//! an I2C master has sent data to the I2C Slave module, \b I2C_SLAVE_ACT_TREQ +//! to indicate that an I2C master has requested that the I2C Slave module send +//! data, \b I2C_SLAVE_ACT_RREQ_FBR to indicate that an I2C master has sent +//! data to the I2C slave and the first byte following the slave's own address +//! has been received, \b I2C_SLAVE_ACT_OWN2SEL to indicate that the second I2C +//! slave address was matched, \b I2C_SLAVE_ACT_QCMD to indicate that a quick +//! command was received, and \b I2C_SLAVE_ACT_QCMD_DATA to indicate that the +//! data bit was set when the quick command was received. +// +//***************************************************************************** +uint32_t +I2CSlaveStatus(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return the slave status. + // + return(HWREG(ui32Base + I2C_O_SCSR)); +} + +//***************************************************************************** +// +//! Transmits a byte from the I2C Slave. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui8Data is the data to be transmitted from the I2C Slave +//! +//! This function places the supplied data into I2C Slave Data Register. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveDataPut(uint32_t ui32Base, uint8_t ui8Data) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Write the byte. + // + HWREG(ui32Base + I2C_O_SDR) = ui8Data; +} + +//***************************************************************************** +// +//! Receives a byte that has been sent to the I2C Slave. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function reads a byte of data from the I2C Slave Data Register. +//! +//! \return Returns the byte received from by the I2C Slave, cast as an +//! uint32_t. +// +//***************************************************************************** +uint32_t +I2CSlaveDataGet(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Read a byte. + // + return(HWREG(ui32Base + I2C_O_SDR)); +} + +//***************************************************************************** +// +//! Configures the I2C transmit (TX) FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! \param ui32Config is the configuration of the FIFO using specified macros. +//! +//! This configures the I2C peripheral's transmit FIFO. The transmit FIFO can +//! be used by the master or slave, but not both. The following macros are +//! used to configure the TX FIFO behavior for master or slave, with or without +//! DMA: +//! +//! \b I2C_FIFO_CFG_TX_MASTER, \b I2C_FIFO_CFG_TX_SLAVE, +//! \b I2C_FIFO_CFG_TX_MASTER_DMA, \b I2C_FIFO_CFG_TX_SLAVE_DMA +//! +//! To select the trigger level, one of the following macros should be used: +//! +//! \b I2C_FIFO_CFG_TX_TRIG_1, \b I2C_FIFO_CFG_TX_TRIG_2, +//! \b I2C_FIFO_CFG_TX_TRIG_3, \b I2C_FIFO_CFG_TX_TRIG_4, +//! \b I2C_FIFO_CFG_TX_TRIG_5, \b I2C_FIFO_CFG_TX_TRIG_6, +//! \b I2C_FIFO_CFG_TX_TRIG_7, \b I2C_FIFO_CFG_TX_TRIG_8 +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CTxFIFOConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear transmit configuration data. + // + HWREG(ui32Base + I2C_O_FIFOCTL) &= 0xffff0000; + + // + // Store new transmit configuration data. + // + HWREG(ui32Base + I2C_O_FIFOCTL) |= ui32Config; +} + +//***************************************************************************** +// +//! Flushes the transmit (TX) FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! +//! This function flushes the I2C transmit FIFO. +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CTxFIFOFlush(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Flush the TX FIFO. + // + HWREG(ui32Base + I2C_O_FIFOCTL) |= I2C_FIFOCTL_TXFLUSH; +} + +//***************************************************************************** +// +//! Configures the I2C receive (RX) FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! \param ui32Config is the configuration of the FIFO using specified macros. +//! +//! This configures the I2C peripheral's receive FIFO. The receive FIFO can be +//! used by the master or slave, but not both. The following macros are used +//! to configure the RX FIFO behavior for master or slave, with or without DMA: +//! +//! \b I2C_FIFO_CFG_RX_MASTER, \b I2C_FIFO_CFG_RX_SLAVE, +//! \b I2C_FIFO_CFG_RX_MASTER_DMA, \b I2C_FIFO_CFG_RX_SLAVE_DMA +//! +//! To select the trigger level, one of the following macros should be used: +//! +//! \b I2C_FIFO_CFG_RX_TRIG_1, \b I2C_FIFO_CFG_RX_TRIG_2, +//! \b I2C_FIFO_CFG_RX_TRIG_3, \b I2C_FIFO_CFG_RX_TRIG_4, +//! \b I2C_FIFO_CFG_RX_TRIG_5, \b I2C_FIFO_CFG_RX_TRIG_6, +//! \b I2C_FIFO_CFG_RX_TRIG_7, \b I2C_FIFO_CFG_RX_TRIG_8 +//! +//! +//! \return None. +// +//***************************************************************************** +void +I2CRxFIFOConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Clear receive configuration data. + // + HWREG(ui32Base + I2C_O_FIFOCTL) &= 0x0000ffff; + + // + // Store new receive configuration data. + // + HWREG(ui32Base + I2C_O_FIFOCTL) |= ui32Config; +} + +//***************************************************************************** +// +//! Flushes the receive (RX) FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! +//! This function flushes the I2C receive FIFO. +//! +//! \return None. +// +//***************************************************************************** +void +I2CRxFIFOFlush(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Flush the TX FIFO. + // + HWREG(ui32Base + I2C_O_FIFOCTL) |= I2C_FIFOCTL_RXFLUSH; +} + +//***************************************************************************** +// +//! Gets the current FIFO status. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! +//! This function retrieves the status for both the transmit (TX) and receive +//! (RX) FIFOs. The trigger level for the transmit FIFO is set using +//! I2CTxFIFOConfigSet() and for the receive FIFO using I2CTxFIFOConfigSet(). +//! +//! \return Returns the FIFO status, enumerated as a bit field containing +//! \b I2C_FIFO_RX_BELOW_TRIG_LEVEL, \b I2C_FIFO_RX_FULL, \b I2C_FIFO_RX_EMPTY, +//! \b I2C_FIFO_TX_BELOW_TRIG_LEVEL, \b I2C_FIFO_TX_FULL, and +//! \b I2C_FIFO_TX_EMPTY. +// +//***************************************************************************** +uint32_t +I2CFIFOStatus(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Return the contents of the FIFO status register. + // + return(HWREG(ui32Base + I2C_O_FIFOSTATUS)); +} + +//***************************************************************************** +// +//! Writes a data byte to the I2C transmit FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! \param ui8Data is the data to be placed into the transmit FIFO. +//! +//! This function adds a byte of data to the I2C transmit FIFO. If there is +//! no space available in the FIFO, this function waits for space to become +//! available before returning. +//! +//! \return None. +// +//***************************************************************************** +void +I2CFIFODataPut(uint32_t ui32Base, uint8_t ui8Data) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Wait until there is space. + // + while(HWREG(ui32Base + I2C_O_FIFOSTATUS) & I2C_FIFOSTATUS_TXFF) + { + } + + // + // Place data into the FIFO. + // + HWREG(ui32Base + I2C_O_FIFODATA) = ui8Data; +} + +//***************************************************************************** +// +//! Writes a data byte to the I2C transmit FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! \param ui8Data is the data to be placed into the transmit FIFO. +//! +//! This function adds a byte of data to the I2C transmit FIFO. If there is +//! no space available in the FIFO, this function returns a zero. +//! +//! \return The number of elements added to the I2C transmit FIFO. +// +//***************************************************************************** +uint32_t +I2CFIFODataPutNonBlocking(uint32_t ui32Base, uint8_t ui8Data) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // If FIFO is full, return zero. + // + if(HWREG(ui32Base + I2C_O_FIFOSTATUS) & I2C_FIFOSTATUS_TXFF) + { + return(0); + } + else + { + HWREG(ui32Base + I2C_O_FIFODATA) = ui8Data; + return(1); + } +} + +//***************************************************************************** +// +//! Reads a byte from the I2C receive FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! +//! This function reads a byte of data from I2C receive FIFO and places it in +//! the location specified by the \e pui8Data parameter. If there is no data +//! available, this function waits until data is received before returning. +//! +//! \return The data byte. +// +//***************************************************************************** +uint32_t +I2CFIFODataGet(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Wait until there is data to read. + // + while(HWREG(ui32Base + I2C_O_FIFOSTATUS) & I2C_FIFOSTATUS_RXFE) + { + } + + // + // Read a byte. + // + return(HWREG(ui32Base + I2C_O_FIFODATA)); +} + +//***************************************************************************** +// +//! Reads a byte from the I2C receive FIFO. +//! +//! \param ui32Base is the base address of the I2C Master or Slave module. +//! \param pui8Data is a pointer where the read data is stored. +//! +//! This function reads a byte of data from I2C receive FIFO and places it in +//! the location specified by the \e pui8Data parameter. If there is no data +//! available, this functions returns 0. +//! +//! \return The number of elements read from the I2C receive FIFO. +// +//***************************************************************************** +uint32_t +I2CFIFODataGetNonBlocking(uint32_t ui32Base, uint8_t *pui8Data) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // If nothing in the FIFO, return zero. + // + if(HWREG(ui32Base + I2C_O_FIFOSTATUS) & I2C_FIFOSTATUS_RXFE) + { + return(0); + } + else + { + *pui8Data = HWREG(ui32Base + I2C_O_FIFODATA); + return(1); + } +} + +//***************************************************************************** +// +//! Set the burst length for a I2C master FIFO operation. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui8Length is the length of the burst transfer. +//! +//! This function configures the burst length for a I2C Master FIFO operation. +//! The burst field is limited to 8 bits or 256 bytes. The burst length +//! applies to a single I2CMCS BURST operation meaning that it specifies the +//! burst length for only the current operation (can be TX or RX). Each burst +//! operation must configure the burst length prior to writing the BURST bit +//! in the I2CMCS using I2CMasterControl(). +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterBurstLengthSet(uint32_t ui32Base, uint8_t ui8Length) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base) && (ui8Length < 255)); + + // + // Set the burst length. + // + HWREG(ui32Base + I2C_O_MBLEN) = ui8Length; +} + +//***************************************************************************** +// +//! Returns the current value of the burst transfer counter. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! +//! This function returns the current value of the burst transfer counter that +//! is used by the FIFO mechanism. Software can use this value to determine +//! how many bytes remain in a transfer, or where in the transfer the burst +//! operation was if an error has occurred. +//! +//! \return None. +// +//***************************************************************************** +uint32_t +I2CMasterBurstCountGet(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Get burst count. + // + return(HWREG(ui32Base + I2C_O_MBCNT)); +} + +//***************************************************************************** +// +//! Configures the I2C Master glitch filter. +//! +//! \param ui32Base is the base address of the I2C Master module. +//! \param ui32Config is the glitch filter configuration. +//! +//! This function configures the I2C Master glitch filter. The value passed in +//! to \e ui32Config determines the sampling range of the glitch filter, which +//! is configurable between 1 and 32 system clock cycles. The default +//! configuration of the glitch filter is 0 system clock cycles, which means +//! that it's disabled. +//! +//! The \e ui32Config field should be any of the following values: +//! +//! - \b I2C_MASTER_GLITCH_FILTER_DISABLED +//! - \b I2C_MASTER_GLITCH_FILTER_1 +//! - \b I2C_MASTER_GLITCH_FILTER_2 +//! - \b I2C_MASTER_GLITCH_FILTER_3 +//! - \b I2C_MASTER_GLITCH_FILTER_4 +//! - \b I2C_MASTER_GLITCH_FILTER_8 +//! - \b I2C_MASTER_GLITCH_FILTER_16 +//! - \b I2C_MASTER_GLITCH_FILTER_32 +//! +//! \return None. +// +//***************************************************************************** +void +I2CMasterGlitchFilterConfigSet(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Configure the glitch filter field of MTPR. + // + HWREG(ui32Base + I2C_O_MTPR) |= ui32Config; +} + +//***************************************************************************** +// +//! Enables FIFO usage for the I2C Slave module. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! \param ui32Config is the desired FIFO configuration of the I2C Slave. +//! +//! This function configures the I2C Slave module to use the FIFO(s). This +//! function should be used in combination with I2CTxFIFOConfigSet() and/or +//! I2CRxFIFOConfigSet(), which configure the FIFO trigger level and tell +//! the FIFO hardware whether to interact with the I2C Master or Slave. The +//! application appropriate combination of \b I2C_SLAVE_TX_FIFO_ENABLE and +//! \b I2C_SLAVE_RX_FIFO_ENABLE should be passed in to the \e ui32Config +//! field. +//! +//! The Slave I2CSCSR register is write-only, so any call to I2CSlaveEnable(), +//! I2CSlaveDisable or I2CSlaveFIFOEnable() overwrites the slave configuration. +//! Therefore, application software should call I2CSlaveEnable() followed by +//! I2CSlaveFIFOEnable() with the desired FIFO configuration. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveFIFOEnable(uint32_t ui32Base, uint32_t ui32Config) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Enable the FIFOs for the slave. + // + HWREG(ui32Base + I2C_O_SCSR) = ui32Config | I2C_SCSR_DA; +} + +//***************************************************************************** +// +//! Disable FIFO usage for the I2C Slave module. +//! +//! \param ui32Base is the base address of the I2C Slave module. +//! +//! This function disables the FIFOs for the I2C Slave. After calling this +//! this function, the FIFOs are disabled, but the Slave remains active. +//! +//! \return None. +// +//***************************************************************************** +void +I2CSlaveFIFODisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(_I2CBaseValid(ui32Base)); + + // + // Disable slave FIFOs. + // + HWREG(ui32Base + I2C_O_SCSR) = I2C_SCSR_DA; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/i2c.h b/src/openmv/src/micropython/ports/cc3200/hal/i2c.h new file mode 100755 index 0000000..d966dbf --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/i2c.h @@ -0,0 +1,360 @@ +//***************************************************************************** +// +// i2c.h +// +// Prototypes for the I2C Driver. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __DRIVERLIB_I2C_H__ +#define __DRIVERLIB_I2C_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Defines for the API. +// +//***************************************************************************** + +//***************************************************************************** +// +// Interrupt defines. +// +//***************************************************************************** +#define I2C_INT_MASTER 0x00000001 +#define I2C_INT_SLAVE 0x00000002 + +//***************************************************************************** +// +// I2C Master commands. +// +//***************************************************************************** +#define I2C_MASTER_CMD_SINGLE_SEND \ + 0x00000007 +#define I2C_MASTER_CMD_SINGLE_RECEIVE \ + 0x00000007 +#define I2C_MASTER_CMD_BURST_SEND_START \ + 0x00000003 +#define I2C_MASTER_CMD_BURST_SEND_CONT \ + 0x00000001 +#define I2C_MASTER_CMD_BURST_SEND_FINISH \ + 0x00000005 +#define I2C_MASTER_CMD_BURST_SEND_STOP \ + 0x00000004 +#define I2C_MASTER_CMD_BURST_SEND_ERROR_STOP \ + 0x00000004 +#define I2C_MASTER_CMD_BURST_RECEIVE_START \ + 0x0000000b +#define I2C_MASTER_CMD_BURST_RECEIVE_CONT \ + 0x00000009 +#define I2C_MASTER_CMD_BURST_RECEIVE_FINISH \ + 0x00000005 +#define I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP \ + 0x00000004 +#define I2C_MASTER_CMD_QUICK_COMMAND \ + 0x00000027 +#define I2C_MASTER_CMD_HS_MASTER_CODE_SEND \ + 0x00000013 +#define I2C_MASTER_CMD_FIFO_SINGLE_SEND \ + 0x00000046 +#define I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE \ + 0x00000046 +#define I2C_MASTER_CMD_FIFO_BURST_SEND_START \ + 0x00000042 +#define I2C_MASTER_CMD_FIFO_BURST_SEND_CONT \ + 0x00000040 +#define I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH \ + 0x00000044 +#define I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP \ + 0x00000004 +#define I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START \ + 0x0000004a +#define I2C_MASTER_CMD_FIFO_BURST_RECEIVE_CONT \ + 0x00000048 +#define I2C_MASTER_CMD_FIFO_BURST_RECEIVE_FINISH \ + 0x00000044 +#define I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP \ + 0x00000004 + +//***************************************************************************** +// +// I2C Master glitch filter configuration. +// +//***************************************************************************** +#define I2C_MASTER_GLITCH_FILTER_DISABLED \ + 0 +#define I2C_MASTER_GLITCH_FILTER_1 \ + 0x00010000 +#define I2C_MASTER_GLITCH_FILTER_2 \ + 0x00020000 +#define I2C_MASTER_GLITCH_FILTER_3 \ + 0x00030000 +#define I2C_MASTER_GLITCH_FILTER_4 \ + 0x00040000 +#define I2C_MASTER_GLITCH_FILTER_8 \ + 0x00050000 +#define I2C_MASTER_GLITCH_FILTER_16 \ + 0x00060000 +#define I2C_MASTER_GLITCH_FILTER_32 \ + 0x00070000 + +//***************************************************************************** +// +// I2C Master error status. +// +//***************************************************************************** +#define I2C_MASTER_ERR_NONE 0 +#define I2C_MASTER_ERR_ADDR_ACK 0x00000004 +#define I2C_MASTER_ERR_DATA_ACK 0x00000008 +#define I2C_MASTER_ERR_ARB_LOST 0x00000010 +#define I2C_MASTER_ERR_CLK_TOUT 0x00000080 + +//***************************************************************************** +// +// I2C Slave action requests +// +//***************************************************************************** +#define I2C_SLAVE_ACT_NONE 0 +#define I2C_SLAVE_ACT_RREQ 0x00000001 // Master has sent data +#define I2C_SLAVE_ACT_TREQ 0x00000002 // Master has requested data +#define I2C_SLAVE_ACT_RREQ_FBR 0x00000005 // Master has sent first byte +#define I2C_SLAVE_ACT_OWN2SEL 0x00000008 // Master requested secondary slave +#define I2C_SLAVE_ACT_QCMD 0x00000010 // Master has sent a Quick Command +#define I2C_SLAVE_ACT_QCMD_DATA 0x00000020 // Master Quick Command value + +//***************************************************************************** +// +// Miscellaneous I2C driver definitions. +// +//***************************************************************************** +#define I2C_MASTER_MAX_RETRIES 1000 // Number of retries + +//***************************************************************************** +// +// I2C Master interrupts. +// +//***************************************************************************** +#define I2C_MASTER_INT_RX_FIFO_FULL \ + 0x00000800 // RX FIFO Full Interrupt +#define I2C_MASTER_INT_TX_FIFO_EMPTY \ + 0x00000400 // TX FIFO Empty Interrupt +#define I2C_MASTER_INT_RX_FIFO_REQ \ + 0x00000200 // RX FIFO Request Interrupt +#define I2C_MASTER_INT_TX_FIFO_REQ \ + 0x00000100 // TX FIFO Request Interrupt +#define I2C_MASTER_INT_ARB_LOST \ + 0x00000080 // Arb Lost Interrupt +#define I2C_MASTER_INT_STOP 0x00000040 // Stop Condition Interrupt +#define I2C_MASTER_INT_START 0x00000020 // Start Condition Interrupt +#define I2C_MASTER_INT_NACK 0x00000010 // Addr/Data NACK Interrupt +#define I2C_MASTER_INT_TX_DMA_DONE \ + 0x00000008 // TX DMA Complete Interrupt +#define I2C_MASTER_INT_RX_DMA_DONE \ + 0x00000004 // RX DMA Complete Interrupt +#define I2C_MASTER_INT_TIMEOUT 0x00000002 // Clock Timeout Interrupt +#define I2C_MASTER_INT_DATA 0x00000001 // Data Interrupt + +//***************************************************************************** +// +// I2C Slave interrupts. +// +//***************************************************************************** +#define I2C_SLAVE_INT_RX_FIFO_FULL \ + 0x00000100 // RX FIFO Full Interrupt +#define I2C_SLAVE_INT_TX_FIFO_EMPTY \ + 0x00000080 // TX FIFO Empty Interrupt +#define I2C_SLAVE_INT_RX_FIFO_REQ \ + 0x00000040 // RX FIFO Request Interrupt +#define I2C_SLAVE_INT_TX_FIFO_REQ \ + 0x00000020 // TX FIFO Request Interrupt +#define I2C_SLAVE_INT_TX_DMA_DONE \ + 0x00000010 // TX DMA Complete Interrupt +#define I2C_SLAVE_INT_RX_DMA_DONE \ + 0x00000008 // RX DMA Complete Interrupt +#define I2C_SLAVE_INT_STOP 0x00000004 // Stop Condition Interrupt +#define I2C_SLAVE_INT_START 0x00000002 // Start Condition Interrupt +#define I2C_SLAVE_INT_DATA 0x00000001 // Data Interrupt + +//***************************************************************************** +// +// I2C Slave FIFO configuration macros. +// +//***************************************************************************** +#define I2C_SLAVE_TX_FIFO_ENABLE \ + 0x00000002 +#define I2C_SLAVE_RX_FIFO_ENABLE \ + 0x00000004 + +//***************************************************************************** +// +// I2C FIFO configuration macros. +// +//***************************************************************************** +#define I2C_FIFO_CFG_TX_MASTER 0x00000000 +#define I2C_FIFO_CFG_TX_SLAVE 0x00008000 +#define I2C_FIFO_CFG_RX_MASTER 0x00000000 +#define I2C_FIFO_CFG_RX_SLAVE 0x80000000 +#define I2C_FIFO_CFG_TX_MASTER_DMA \ + 0x00002000 +#define I2C_FIFO_CFG_TX_SLAVE_DMA \ + 0x0000a000 +#define I2C_FIFO_CFG_RX_MASTER_DMA \ + 0x20000000 +#define I2C_FIFO_CFG_RX_SLAVE_DMA \ + 0xa0000000 +#define I2C_FIFO_CFG_TX_NO_TRIG 0x00000000 +#define I2C_FIFO_CFG_TX_TRIG_1 0x00000001 +#define I2C_FIFO_CFG_TX_TRIG_2 0x00000002 +#define I2C_FIFO_CFG_TX_TRIG_3 0x00000003 +#define I2C_FIFO_CFG_TX_TRIG_4 0x00000004 +#define I2C_FIFO_CFG_TX_TRIG_5 0x00000005 +#define I2C_FIFO_CFG_TX_TRIG_6 0x00000006 +#define I2C_FIFO_CFG_TX_TRIG_7 0x00000007 +#define I2C_FIFO_CFG_TX_TRIG_8 0x00000008 +#define I2C_FIFO_CFG_RX_NO_TRIG 0x00000000 +#define I2C_FIFO_CFG_RX_TRIG_1 0x00010000 +#define I2C_FIFO_CFG_RX_TRIG_2 0x00020000 +#define I2C_FIFO_CFG_RX_TRIG_3 0x00030000 +#define I2C_FIFO_CFG_RX_TRIG_4 0x00040000 +#define I2C_FIFO_CFG_RX_TRIG_5 0x00050000 +#define I2C_FIFO_CFG_RX_TRIG_6 0x00060000 +#define I2C_FIFO_CFG_RX_TRIG_7 0x00070000 +#define I2C_FIFO_CFG_RX_TRIG_8 0x00080000 + +//***************************************************************************** +// +// I2C FIFO status. +// +//***************************************************************************** +#define I2C_FIFO_RX_BELOW_TRIG_LEVEL \ + 0x00040000 +#define I2C_FIFO_RX_FULL 0x00020000 +#define I2C_FIFO_RX_EMPTY 0x00010000 +#define I2C_FIFO_TX_BELOW_TRIG_LEVEL \ + 0x00000004 +#define I2C_FIFO_TX_FULL 0x00000002 +#define I2C_FIFO_TX_EMPTY 0x00000001 + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern void I2CIntRegister(uint32_t ui32Base, void(pfnHandler)(void)); +extern void I2CIntUnregister(uint32_t ui32Base); +extern void I2CTxFIFOConfigSet(uint32_t ui32Base, uint32_t ui32Config); +extern void I2CTxFIFOFlush(uint32_t ui32Base); +extern void I2CRxFIFOConfigSet(uint32_t ui32Base, uint32_t ui32Config); +extern void I2CRxFIFOFlush(uint32_t ui32Base); +extern uint32_t I2CFIFOStatus(uint32_t ui32Base); +extern void I2CFIFODataPut(uint32_t ui32Base, uint8_t ui8Data); +extern uint32_t I2CFIFODataPutNonBlocking(uint32_t ui32Base, + uint8_t ui8Data); +extern uint32_t I2CFIFODataGet(uint32_t ui32Base); +extern uint32_t I2CFIFODataGetNonBlocking(uint32_t ui32Base, + uint8_t *pui8Data); +extern void I2CMasterBurstLengthSet(uint32_t ui32Base, + uint8_t ui8Length); +extern uint32_t I2CMasterBurstCountGet(uint32_t ui32Base); +extern void I2CMasterGlitchFilterConfigSet(uint32_t ui32Base, + uint32_t ui32Config); +extern void I2CSlaveFIFOEnable(uint32_t ui32Base, uint32_t ui32Config); +extern void I2CSlaveFIFODisable(uint32_t ui32Base); +extern bool I2CMasterBusBusy(uint32_t ui32Base); +extern bool I2CMasterBusy(uint32_t ui32Base); +extern void I2CMasterControl(uint32_t ui32Base, uint32_t ui32Cmd); +extern uint32_t I2CMasterDataGet(uint32_t ui32Base); +extern void I2CMasterDataPut(uint32_t ui32Base, uint8_t ui8Data); +extern void I2CMasterDisable(uint32_t ui32Base); +extern void I2CMasterEnable(uint32_t ui32Base); +extern uint32_t I2CMasterErr(uint32_t ui32Base); +extern void I2CMasterInitExpClk(uint32_t ui32Base, uint32_t ui32SCLFreq); +extern void I2CMasterIntClear(uint32_t ui32Base); +extern void I2CMasterIntDisable(uint32_t ui32Base); +extern void I2CMasterIntEnable(uint32_t ui32Base); +extern bool I2CMasterIntStatus(uint32_t ui32Base, bool bMasked); +extern void I2CMasterIntEnableEx(uint32_t ui32Base, + uint32_t ui32IntFlags); +extern void I2CMasterIntDisableEx(uint32_t ui32Base, + uint32_t ui32IntFlags); +extern uint32_t I2CMasterIntStatusEx(uint32_t ui32Base, + bool bMasked); +extern void I2CMasterIntClearEx(uint32_t ui32Base, + uint32_t ui32IntFlags); +extern void I2CMasterTimeoutSet(uint32_t ui32Base, uint32_t ui32Value); +extern void I2CSlaveACKOverride(uint32_t ui32Base, bool bEnable); +extern void I2CSlaveACKValueSet(uint32_t ui32Base, bool bACK); +extern uint32_t I2CMasterLineStateGet(uint32_t ui32Base); +extern void I2CMasterSlaveAddrSet(uint32_t ui32Base, + uint8_t ui8SlaveAddr, + bool bReceive); +extern uint32_t I2CSlaveDataGet(uint32_t ui32Base); +extern void I2CSlaveDataPut(uint32_t ui32Base, uint8_t ui8Data); +extern void I2CSlaveDisable(uint32_t ui32Base); +extern void I2CSlaveEnable(uint32_t ui32Base); +extern void I2CSlaveInit(uint32_t ui32Base, uint8_t ui8SlaveAddr); +extern void I2CSlaveAddressSet(uint32_t ui32Base, uint8_t ui8AddrNum, + uint8_t ui8SlaveAddr); +extern void I2CSlaveIntClear(uint32_t ui32Base); +extern void I2CSlaveIntDisable(uint32_t ui32Base); +extern void I2CSlaveIntEnable(uint32_t ui32Base); +extern void I2CSlaveIntClearEx(uint32_t ui32Base, uint32_t ui32IntFlags); +extern void I2CSlaveIntDisableEx(uint32_t ui32Base, + uint32_t ui32IntFlags); +extern void I2CSlaveIntEnableEx(uint32_t ui32Base, uint32_t ui32IntFlags); +extern bool I2CSlaveIntStatus(uint32_t ui32Base, bool bMasked); +extern uint32_t I2CSlaveIntStatusEx(uint32_t ui32Base, + bool bMasked); +extern uint32_t I2CSlaveStatus(uint32_t ui32Base); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __DRIVERLIB_I2C_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/i2s.c b/src/openmv/src/micropython/ports/cc3200/hal/i2s.c new file mode 100755 index 0000000..dbbb936 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/i2s.c @@ -0,0 +1,1012 @@ +//***************************************************************************** +// +// i2s.c +// +// Driver for the I2S interface. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup I2S_api +//! @{ +// +//***************************************************************************** +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_mcasp.h" +#include "inc/hw_apps_config.h" +#include "interrupt.h" +#include "i2s.h" + +//***************************************************************************** +// Macros +//***************************************************************************** +#define MCASP_GBL_RCLK 0x00000001 +#define MCASP_GBL_RHCLK 0x00000002 +#define MCASP_GBL_RSER 0x00000004 +#define MCASP_GBL_RSM 0x00000008 +#define MCASP_GBL_RFSYNC 0x00000010 +#define MCASP_GBL_XCLK 0x00000100 +#define MCASP_GBL_XHCLK 0x00000200 +#define MCASP_GBL_XSER 0x00000400 +#define MCASP_GBL_XSM 0x00000800 +#define MCASP_GBL_XFSYNC 0x00001000 + + +//***************************************************************************** +// +//! \internal +//! Releases the specifed submodule out of reset. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulFlag is one of the valid sub module. +//! +//! This function Releases the specifed submodule out of reset. +//! +//! \return None. +// +//***************************************************************************** +static void I2SGBLEnable(unsigned long ulBase, unsigned long ulFlag) +{ + unsigned long ulReg; + + // + // Read global control register + // + ulReg = HWREG(ulBase + MCASP_O_GBLCTL); + + // + // Remove the sub modules reset as specified by ulFlag parameter + // + ulReg |= ulFlag; + + // + // Write the configuration + // + HWREG(ulBase + MCASP_O_GBLCTL) = ulReg; + + // + // Wait for write completeion + // + while(HWREG(ulBase + MCASP_O_GBLCTL) != ulReg) + { + + } + +} + +//***************************************************************************** +// +//! Enables transmit and/or receive. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulMode is one of the valid modes. +//! +//! This function enables the I2S module in specified mode. The parameter +//! \e ulMode should be one of the following +//! +//! -\b I2S_MODE_TX_ONLY +//! -\b I2S_MODE_TX_RX_SYNC +//! +//! \return None. +// +//***************************************************************************** +void I2SEnable(unsigned long ulBase, unsigned long ulMode) +{ + // + // FSYNC and Bit clock are output only in master mode + // + if( HWREG(ulBase + MCASP_O_ACLKXCTL) & 0x20) + { + // + // Set FSYNC anc BitClk as output + // + HWREG(ulBase + MCASP_O_PDIR) |= 0x14000000; + } + + + if(ulMode & 0x2) + { + // + // Remove Rx HCLK reset + // + I2SGBLEnable(ulBase, MCASP_GBL_RHCLK); + + // + // Remove Rx XCLK reset + // + I2SGBLEnable(ulBase, MCASP_GBL_RCLK); + + // + // Enable Rx SERDES(s) + // + I2SGBLEnable(ulBase, MCASP_GBL_RSER); + + // + // Enable Rx state machine + // + I2SGBLEnable(ulBase, MCASP_GBL_RSM); + + // + // Enable FSync generator + // + I2SGBLEnable(ulBase, MCASP_GBL_RFSYNC); + } + + + // + // Remove Tx HCLK reset + // + I2SGBLEnable(ulBase, MCASP_GBL_XHCLK); + + // + // Remove Tx XCLK reset + // + I2SGBLEnable(ulBase, MCASP_GBL_XCLK); + + + if(ulMode & 0x1) + { + // + // Enable Tx SERDES(s) + // + I2SGBLEnable(ulBase, MCASP_GBL_XSER); + + // + // Enable Tx state machine + // + I2SGBLEnable(ulBase, MCASP_GBL_XSM); + } + + // + // Enable FSync generator + // + I2SGBLEnable(ulBase, MCASP_GBL_XFSYNC); +} + +//***************************************************************************** +// +//! Disables transmit and/or receive. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function disables transmit and/or receive from I2S module. +//! +//! \return None. +// +//***************************************************************************** +void I2SDisable(unsigned long ulBase) +{ + // + // Reset all sub modules + // + HWREG(ulBase + MCASP_O_GBLCTL) = 0; + + // + // Wait for write to complete + // + while( HWREG(ulBase + MCASP_O_GBLCTL) != 0) + { + + } +} + +//***************************************************************************** +// +//! Waits to send data over the specified data line +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulDataLine is one of the valid data lines. +//! \param ulData is the data to be transmitted. +//! +//! This function sends the \e ucData to the transmit register for the +//! specified data line. If there is no space available, this +//! function waits until there is space available before returning. +//! +//! \return None. +// +//***************************************************************************** +void I2SDataPut(unsigned long ulBase, unsigned long ulDataLine, + unsigned long ulData) +{ + // + // Compute register the offeset + // + ulDataLine = (ulDataLine-1) << 2; + + // + // Wait for free space in fifo + // + while(!( HWREG(ulBase + MCASP_O_TXSTAT) & MCASP_TXSTAT_XDATA)) + { + + } + + // + // Write Data into the FIFO + // + HWREG(ulBase + MCASP_O_TXBUF0 + ulDataLine) = ulData; +} + +//***************************************************************************** +// +//! Sends data over the specified data line +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulDataLine is one of the valid data lines. +//! \param ulData is the data to be transmitted. +//! +//! This function writes the \e ucData to the transmit register for +//! the specified data line. This function does not block, so if there is no +//! space available, then \b -1 is returned, and the application must retry the +//! function later. +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +long I2SDataPutNonBlocking(unsigned long ulBase, unsigned long ulDataLine, + unsigned long ulData) +{ + + // + // Compute register the offeset + // + ulDataLine = (ulDataLine-1) << 2; + + // + // Send Data if fifo has free space + // + if( HWREG(ulBase + MCASP_O_TXSTAT) & MCASP_TXSTAT_XDATA) + { + // + // Write data into the FIFO + // + HWREG(ulBase + MCASP_O_TXBUF0 + ulDataLine) = ulData; + return 0; + } + + // + // FIFO is full + // + return(-1); +} + +//***************************************************************************** +// +//! Waits for data from the specified data line. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulDataLine is one of the valid data lines. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets data from the receive register for the specified +//! data line. If there are no data available, this function waits until a +//! receive before returning. +//! +//! \return None. +// +//***************************************************************************** +void I2SDataGet(unsigned long ulBase, unsigned long ulDataLine, + unsigned long *pulData) +{ + + // + // Compute register the offeset + // + ulDataLine = (ulDataLine-1) << 2; + + // + // Wait for atleat on word in FIFO + // + while(!(HWREG(ulBase + MCASP_O_RXSTAT) & MCASP_RXSTAT_RDATA)) + { + + } + + // + // Read the Data + // + *pulData = HWREG(ulBase + MCASP_O_RXBUF0 + ulDataLine); +} + + +//***************************************************************************** +// +//! Receives data from the specified data line. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulDataLine is one of the valid data lines. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets data from the receive register for the specified +//! data line. +//! +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +long I2SDataGetNonBlocking(unsigned long ulBase, unsigned long ulDataLine, + unsigned long *pulData) +{ + + // + // Compute register the offeset + // + ulDataLine = (ulDataLine-1) << 2; + + // + // Check if data is available in FIFO + // + if(HWREG(ulBase + MCASP_O_RXSTAT) & MCASP_RXSTAT_RDATA) + { + // + // Read the Data + // + *pulData = HWREG(ulBase + MCASP_O_RXBUF0 + ulDataLine); + return 0; + } + + // + // FIFO is empty + // + return -1; +} + + +//***************************************************************************** +// +//! Sets the configuration of the I2S module. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulI2SClk is the rate of the clock supplied to the I2S module. +//! \param ulBitClk is the desired bit rate. +//! \param ulConfig is the data format. +//! +//! This function configures the I2S for operation in the specified data +//! format. The bit rate is provided in the \e ulBitClk parameter and the data +//! format in the \e ulConfig parameter. +//! +//! The \e ulConfig parameter is the logical OR of three values: the slot size +//! the data read/write port select, Master or Slave mode +//! +//! Follwoing selects the Master-Slave mode +//! -\b I2S_MODE_MASTER +//! -\b I2S_MODE_SLAVE +//! +//! Following selects the slot size: +//! -\b I2S_SLOT_SIZE_24 +//! -\b I2S_SLOT_SIZE_16 +//! +//! Following selects the data read/write port: +//! -\b I2S_PORT_DMA +//! -\b I2S_PORT_CPU +//! +//! \return None. +// +//***************************************************************************** +void I2SConfigSetExpClk(unsigned long ulBase, unsigned long ulI2SClk, + unsigned long ulBitClk, unsigned long ulConfig) +{ + unsigned long ulHClkDiv; + unsigned long ulClkDiv; + unsigned long ulSlotSize; + unsigned long ulBitMask; + + // + // Calculate clock dividers + // + ulHClkDiv = ((ulI2SClk/ulBitClk)-1); + ulClkDiv = 0; + + // + // Check if HCLK divider is overflowing + // + if(ulHClkDiv > 0xFFF) + { + ulHClkDiv = 0xFFF; + + // + // Calculate clock divider + // + ulClkDiv = ((ulI2SClk/(ulBitClk * (ulHClkDiv + 1))) & 0x1F); + } + + // + // + // + ulClkDiv = ((ulConfig & I2S_MODE_SLAVE )?0x80:0xA0|ulClkDiv); + + HWREG(ulBase + MCASP_O_ACLKXCTL) = ulClkDiv; + + HWREG(ulBase + MCASP_O_AHCLKXCTL) = (0x8000|ulHClkDiv); + + // + // Write the Tx format register + // + HWREG(ulBase + MCASP_O_TXFMT) = (0x18000 | (ulConfig & 0x7FFF)); + + // + // Write the Rx format register + // + HWREG(ulBase + MCASP_O_RXFMT) = (0x18000 | ((ulConfig >> 16) &0x7FFF)); + + // + // Check if in master mode + // + if( ulConfig & I2S_MODE_SLAVE) + { + // + // Configure Tx FSync generator in I2S mode + // + HWREG(ulBase + MCASP_O_TXFMCTL) = 0x111; + + // + // Configure Rx FSync generator in I2S mode + // + HWREG(ulBase + MCASP_O_RXFMCTL) = 0x111; + } + else + { + // + // Configure Tx FSync generator in I2S mode + // + HWREG(ulBase + MCASP_O_TXFMCTL) = 0x113; + + // + // Configure Rx FSync generator in I2S mode + // + HWREG(ulBase + MCASP_O_RXFMCTL) = 0x113; + } + + // + // Compute Slot Size + // + ulSlotSize = ((((ulConfig & 0xFF) >> 4) + 1) * 2); + + // + // Creat the bit mask + // + ulBitMask = (0xFFFFFFFF >> (32 - ulSlotSize)); + + // + // Set Tx bit valid mask + // + HWREG(ulBase + MCASP_O_TXMASK) = ulBitMask; + + // + // Set Rx bit valid mask + // + HWREG(ulBase + MCASP_O_RXMASK) = ulBitMask; + + // + // Set Tx slot valid mask + // + HWREG(ulBase + MCASP_O_TXTDM) = 0x3; + + // + // Set Rx slot valid mask + // + HWREG(ulBase + MCASP_O_RXTDM) = 0x3; +} + +//***************************************************************************** +// +//! Configure and enable transmit FIFO. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulTxLevel is the transmit FIFO DMA request level. +//! \param ulWordsPerTransfer is the nuber of words transferred from the FIFO. +//! +//! This function configures and enable I2S transmit FIFO. +//! +//! The parameter \e ulTxLevel sets the level at which transmit DMA requests +//! are generated. This should be non-zero integer multiple of number of +//! serializers enabled as transmitters +//! +//! The parameter \e ulWordsPerTransfer sets the number of words that are +//! transferred from the transmit FIFO to the data line(s). This value must +//! equal the number of serializers used as transmitters. +//! +//! \return None. +// +//***************************************************************************** +void I2STxFIFOEnable(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulWordsPerTransfer) +{ + // + // Set transmit FIFO configuration and + // enable it + // + HWREG(ulBase + MCASP_0_WFIFOCTL) = ((1 <<16) | ((ulTxLevel & 0xFF) << 8) + | (ulWordsPerTransfer & 0x1F)); + +} + +//***************************************************************************** +// +//! Disables transmit FIFO. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function disables the I2S transmit FIFO. +//! +//! \return None. +// +//***************************************************************************** +void I2STxFIFODisable(unsigned long ulBase) +{ + // + // Disable transmit FIFO. + // + HWREG(ulBase + MCASP_0_WFIFOCTL) = 0; +} + +//***************************************************************************** +// +//! Configure and enable receive FIFO. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulRxLevel is the receive FIFO DMA request level. +//! \param ulWordsPerTransfer is the nuber of words transferred from the FIFO. +//! +//! This function configures and enable I2S receive FIFO. +//! +//! The parameter \e ulRxLevel sets the level at which receive DMA requests +//! are generated. This should be non-zero integer multiple of number of +//! serializers enabled as receivers. +//! +//! The parameter \e ulWordsPerTransfer sets the number of words that are +//! transferred to the receive FIFO from the data line(s). This value must +//! equal the number of serializers used as receivers. +//! +//! \return None. +// +//***************************************************************************** +void I2SRxFIFOEnable(unsigned long ulBase, unsigned long ulRxLevel, + unsigned long ulWordsPerTransfer) +{ + // + // Set FIFO configuration + // + HWREG(ulBase + MCASP_0_RFIFOCTL) = ( (1 <<16) | ((ulRxLevel & 0xFF) << 8) + | (ulWordsPerTransfer & 0x1F)); + +} + +//***************************************************************************** +// +//! Disables receive FIFO. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function disables the I2S receive FIFO. +//! +//! \return None. +// +//***************************************************************************** +void I2SRxFIFODisable(unsigned long ulBase) +{ + // + // Disable receive FIFO. + // + HWREG(ulBase + MCASP_0_RFIFOCTL) = 0; +} + +//***************************************************************************** +// +//! Get the transmit FIFO status. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function gets the number of 32-bit words currently in the transmit +//! FIFO. +//! +//! \return Returns transmit FIFO status. +// +//***************************************************************************** +unsigned long I2STxFIFOStatusGet(unsigned long ulBase) +{ + // + // Return transmit FIFO level + // + return HWREG(ulBase + MCASP_0_WFIFOSTS); +} + +//***************************************************************************** +// +//! Get the receive FIFO status. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function gets the number of 32-bit words currently in the receive +//! FIFO. +//! +//! \return Returns receive FIFO status. +// +//***************************************************************************** +unsigned long I2SRxFIFOStatusGet(unsigned long ulBase) +{ + // + // Return receive FIFO level + // + return HWREG(ulBase + MCASP_0_RFIFOSTS); +} + +//***************************************************************************** +// +//! Configure the serializer in specified mode. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulDataLine is the data line (serilizer) to be configured. +//! \param ulSerMode is the required serializer mode. +//! \param ulInActState sets the inactive state of the data line. +//! +//! This function configure and enable the serializer associated with the given +//! data line in specified mode. +//! +//! The paramenter \e ulDataLine selects to data line to be configured and +//! can be one of the following: +//! -\b I2S_DATA_LINE_0 +//! -\b I2S_DATA_LINE_1 +//! +//! The parameter \e ulSerMode can be one of the following: +//! -\b I2S_SER_MODE_TX +//! -\b I2S_SER_MODE_RX +//! -\b I2S_SER_MODE_DISABLE +//! +//! The parameter \e ulInActState can be one of the following +//! -\b I2S_INACT_TRI_STATE +//! -\b I2S_INACT_LOW_LEVEL +//! -\b I2S_INACT_LOW_HIGH +//! +//! \return Returns receive FIFO status. +// +//***************************************************************************** +void I2SSerializerConfig(unsigned long ulBase, unsigned long ulDataLine, + unsigned long ulSerMode, unsigned long ulInActState) +{ + if( ulSerMode == I2S_SER_MODE_TX) + { + // + // Set the data line in output mode + // + HWREG(ulBase + MCASP_O_PDIR) |= ulDataLine; + } + else + { + // + // Set the data line in input mode + // + HWREG(ulBase + MCASP_O_PDIR) &= ~ulDataLine; + } + + // + // Set the serializer configuration. + // + HWREG(ulBase + MCASP_O_XRSRCTL0 + ((ulDataLine-1) << 2)) + = (ulSerMode | ulInActState); +} + +//***************************************************************************** +// +//! Enables individual I2S interrupt sources. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated I2S interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! -\b I2S_INT_XUNDRN +//! -\b I2S_INT_XSYNCERR +//! -\b I2S_INT_XLAST +//! -\b I2S_INT_XDATA +//! -\b I2S_INT_XSTAFRM +//! -\b I2S_INT_XDMA +//! -\b I2S_INT_ROVRN +//! -\b I2S_INT_RSYNCERR +//! -\b I2S_INT_RLAST +//! -\b I2S_INT_RDATA +//! -\b I2S_INT_RSTAFRM +//! -\b I2S_INT_RDMA +//! +//! \return None. +// +//***************************************************************************** +void I2SIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + + // + // Enable DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR ) + |= ((ulIntFlags &0xC0000000) >> 20); + + // + // Enable specific Tx Interrupts + // + HWREG(ulBase + MCASP_O_EVTCTLX) |= (ulIntFlags & 0xFF); + + // + // Enable specific Rx Interrupts + // + HWREG(ulBase + MCASP_O_EVTCTLR) |= ((ulIntFlags >> 16) & 0xFF); +} + +//***************************************************************************** +// +//! Disables individual I2S interrupt sources. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! This function disables the indicated I2S interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to I2SIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void I2SIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Disable DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) + |= ((ulIntFlags &0xC0000000) >> 20); + + // + // Disable specific Tx Interrupts + // + HWREG(ulBase + MCASP_O_EVTCTLX) &= ~(ulIntFlags & 0xFF); + + // + // Disable specific Rx Interrupts + // + HWREG(ulBase + MCASP_O_EVTCTLR) &= ~((ulIntFlags >> 16) & 0xFF); +} + + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function returns the raw interrupt status for I2S enumerated +//! as a bit field of values: +//! -\b I2S_STS_XERR +//! -\b I2S_STS_XDMAERR +//! -\b I2S_STS_XSTAFRM +//! -\b I2S_STS_XDATA +//! -\b I2S_STS_XLAST +//! -\b I2S_STS_XSYNCERR +//! -\b I2S_STS_XUNDRN +//! -\b I2S_STS_XDMA +//! -\b I2S_STS_RERR +//! -\b I2S_STS_RDMAERR +//! -\b I2S_STS_RSTAFRM +//! -\b I2S_STS_RDATA +//! -\b I2S_STS_RLAST +//! -\b I2S_STS_RSYNCERR +//! -\b I2S_STS_ROVERN +//! -\b I2S_STS_RDMA +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described above. +// +//***************************************************************************** +unsigned long I2SIntStatus(unsigned long ulBase) +{ + unsigned long ulStatus; + + // + // Get DMA interrupt status + // + ulStatus = + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW) << 20; + + ulStatus &= 0xC0000000; + + // + // Read Tx Interrupt status + // + ulStatus |= HWREG(ulBase + MCASP_O_TXSTAT); + + // + // Read Rx Interrupt status + // + ulStatus |= HWREG(ulBase + MCASP_O_RXSTAT) << 16; + + // + // Return the status + // + return ulStatus; +} + +//***************************************************************************** +// +//! Clears I2S interrupt sources. +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulStatFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified I2S interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being recognized again immediately upon exit. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the value +//! describe in I2SIntStatus(). +//! +//! \return None. +// +//***************************************************************************** +void I2SIntClear(unsigned long ulBase, unsigned long ulStatFlags) +{ + // + // Clear DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) + |= ((ulStatFlags &0xC0000000) >> 20); + + // + // Clear Tx Interrupt + // + HWREG(ulBase + MCASP_O_TXSTAT) = ulStatFlags & 0x1FF ; + + // + // Clear Rx Interrupt + // + HWREG(ulBase + MCASP_O_RXSTAT) = (ulStatFlags >> 16) & 0x1FF; +} + +//***************************************************************************** +// +//! Registers an interrupt handler for a I2S interrupt. +//! +//! \param ulBase is the base address of the I2S module. +//! \param pfnHandler is a pointer to the function to be called when the +//! I2S interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; specific +//! I2S interrupts must be enabled via I2SIntEnable(). It is the interrupt +//! handler's responsibility to clear the interrupt source. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void I2SIntRegister(unsigned long ulBase, void (*pfnHandler)(void)) +{ + // + // Register the interrupt handler + // + IntRegister(INT_I2S,pfnHandler); + + // + // Enable the interrupt + // + IntEnable(INT_I2S); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for a I2S interrupt. +//! +//! \param ulBase is the base address of the I2S module. +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a I2S interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void I2SIntUnregister(unsigned long ulBase) +{ + // + // Disable interrupt + // + IntDisable(INT_I2S); + + // + // Unregister the handler + // + IntUnregister(INT_I2S); + +} + +//***************************************************************************** +// +//! Set the active slots for Trasmitter +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulActSlot is the bit-mask of activ slots +//! +//! This function sets the active slots for the transmitter. By default both +//! the slots are active. The parameter \e ulActSlot is logical OR follwoing +//! values: +//! -\b I2S_ACT_SLOT_EVEN +//! -\b I2S_ACT_SLOT_ODD +//! +//! \return None. +// +//***************************************************************************** +void I2STxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot) +{ + HWREG(ulBase + MCASP_O_TXTDM) = ulActSlot; +} + +//***************************************************************************** +// +//! Set the active slots for Receiver +//! +//! \param ulBase is the base address of the I2S module. +//! \param ulActSlot is the bit-mask of activ slots +//! +//! This function sets the active slots for the receiver. By default both +//! the slots are active. The parameter \e ulActSlot is logical OR follwoing +//! values: +//! -\b I2S_ACT_SLOT_EVEN +//! -\b I2S_ACT_SLOT_ODD +//! +//! \return None. +// +//***************************************************************************** +void I2SRxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot) +{ + HWREG(ulBase + MCASP_O_RXTDM) = ulActSlot; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/i2s.h b/src/openmv/src/micropython/ports/cc3200/hal/i2s.h new file mode 100755 index 0000000..38620ae --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/i2s.h @@ -0,0 +1,218 @@ +//***************************************************************************** +// +// i2s.h +// +// Defines and Macros for the I2S. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __I2S_H__ +#define __I2S_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// I2S DMA ports. +// +//***************************************************************************** +#define I2S_TX_DMA_PORT 0x4401E200 +#define I2S_RX_DMA_PORT 0x4401E280 + +//***************************************************************************** +// +// Values that can be passed to I2SConfigSetExpClk() as the ulConfig parameter. +// +//***************************************************************************** +#define I2S_SLOT_SIZE_8 0x00300032 +#define I2S_SLOT_SIZE_16 0x00700074 +#define I2S_SLOT_SIZE_24 0x00B000B6 + + +#define I2S_PORT_CPU 0x00080008 +#define I2S_PORT_DMA 0x00000000 + +#define I2S_MODE_MASTER 0x00000000 +#define I2S_MODE_SLAVE 0x00008000 + +//***************************************************************************** +// +// Values that can be passed as ulDataLine parameter. +// +//***************************************************************************** +#define I2S_DATA_LINE_0 0x00000001 +#define I2S_DATA_LINE_1 0x00000002 + +//***************************************************************************** +// +// Values that can be passed to I2SSerializerConfig() as the ulSerMode +// parameter. +// +//***************************************************************************** +#define I2S_SER_MODE_TX 0x00000001 +#define I2S_SER_MODE_RX 0x00000002 +#define I2S_SER_MODE_DISABLE 0x00000000 + +//***************************************************************************** +// +// Values that can be passed to I2SSerializerConfig() as the ulInActState +// parameter. +// +//***************************************************************************** +#define I2S_INACT_TRI_STATE 0x00000000 +#define I2S_INACT_LOW_LEVEL 0x00000008 +#define I2S_INACT_HIGH_LEVEL 0x0000000C + +//***************************************************************************** +// +// Values that can be passed to I2SIntEnable() and I2SIntDisable() as the +// ulIntFlags parameter. +// +//***************************************************************************** +#define I2S_INT_XUNDRN 0x00000001 +#define I2S_INT_XSYNCERR 0x00000002 +#define I2S_INT_XLAST 0x00000010 +#define I2S_INT_XDATA 0x00000020 +#define I2S_INT_XSTAFRM 0x00000080 +#define I2S_INT_XDMA 0x80000000 +#define I2S_INT_ROVRN 0x00010000 +#define I2S_INT_RSYNCERR 0x00020000 +#define I2S_INT_RLAST 0x00100000 +#define I2S_INT_RDATA 0x00200000 +#define I2S_INT_RSTAFRM 0x00800000 +#define I2S_INT_RDMA 0x40000000 + + +//***************************************************************************** +// +// Values that can be passed to I2SRxActiveSlotSet() and I2STxActiveSlotSet +// +//***************************************************************************** +#define I2S_ACT_SLOT_EVEN 0x00000001 +#define I2S_ACT_SLOT_ODD 0x00000002 + +//***************************************************************************** +// +// Values that can be passed to I2SIntClear() as the +// ulIntFlags parameter and returned from I2SIntStatus(). +// +//***************************************************************************** +#define I2S_STS_XERR 0x00000100 +#define I2S_STS_XDMAERR 0x00000080 +#define I2S_STS_XSTAFRM 0x00000040 +#define I2S_STS_XDATA 0x00000020 +#define I2S_STS_XLAST 0x00000010 +#define I2S_STS_XSYNCERR 0x00000002 +#define I2S_STS_XUNDRN 0x00000001 +#define I2S_STS_XDMA 0x80000000 +#define I2S_STS_RERR 0x01000000 +#define I2S_STS_RDMAERR 0x00800000 +#define I2S_STS_RSTAFRM 0x00400000 +#define I2S_STS_RDATA 0x00200000 +#define I2S_STS_RLAST 0x00100000 +#define I2S_STS_RSYNCERR 0x00020000 +#define I2S_STS_ROVERN 0x00010000 +#define I2S_STS_RDMA 0x40000000 + +//***************************************************************************** +// +// Values that can be passed to I2SEnable() as the ulMode parameter. +// +//***************************************************************************** +#define I2S_MODE_TX_ONLY 0x00000001 +#define I2S_MODE_TX_RX_SYNC 0x00000003 + + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void I2SEnable(unsigned long ulBase, unsigned long ulMode); +extern void I2SDisable(unsigned long ulBase); + +extern void I2SDataPut(unsigned long ulBase, unsigned long ulDataLine, + unsigned long ulData); +extern long I2SDataPutNonBlocking(unsigned long ulBase, + unsigned long ulDataLine, unsigned long ulData); + +extern void I2SDataGet(unsigned long ulBase, unsigned long ulDataLine, + unsigned long *pulData); +extern long I2SDataGetNonBlocking(unsigned long ulBase, + unsigned long ulDataLine, unsigned long *pulData); + +extern void I2SConfigSetExpClk(unsigned long ulBase, unsigned long ulI2SClk, + unsigned long ulBitClk, unsigned long ulConfig); + +extern void I2STxFIFOEnable(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulWordsPerTransfer); +extern void I2STxFIFODisable(unsigned long ulBase); +extern void I2SRxFIFOEnable(unsigned long ulBase, unsigned long ulRxLevel, + unsigned long ulWordsPerTransfer); +extern void I2SRxFIFODisable(unsigned long ulBase); +extern unsigned long I2STxFIFOStatusGet(unsigned long ulBase); +extern unsigned long I2SRxFIFOStatusGet(unsigned long ulBase); + +extern void I2SSerializerConfig(unsigned long ulBase, unsigned long ulDataLine, + unsigned long ulSerMode, unsigned long ulInActState); + +extern void I2SIntEnable(unsigned long ulBase, unsigned long ulIntFlags); +extern void I2SIntDisable(unsigned long ulBase, unsigned long ulIntFlags); +extern unsigned long I2SIntStatus(unsigned long ulBase); +extern void I2SIntClear(unsigned long ulBase, unsigned long ulIntFlags); +extern void I2SIntRegister(unsigned long ulBase, void (*pfnHandler)(void)); +extern void I2SIntUnregister(unsigned long ulBase); +extern void I2STxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot); +extern void I2SRxActiveSlotSet(unsigned long ulBase, unsigned long ulActSlot); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif //__I2S_H__ + diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/asmdefs.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/asmdefs.h new file mode 100755 index 0000000..c2a6f97 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/asmdefs.h @@ -0,0 +1,229 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +// asmdefs.h - Macros to allow assembly code be portable among toolchains. +// +//***************************************************************************** + +#ifndef __ASMDEFS_H__ +#define __ASMDEFS_H__ + +//***************************************************************************** +// +// The defines required for code_red. +// +//***************************************************************************** +#ifdef codered + +// +// The assembly code preamble required to put the assembler into the correct +// configuration. +// + .syntax unified + .thumb + +// +// Section headers. +// +#define __LIBRARY__ @ +#define __TEXT__ .text +#define __DATA__ .data +#define __BSS__ .bss +#define __TEXT_NOROOT__ .text + +// +// Assembler nmenonics. +// +#define __ALIGN__ .balign 4 +#define __END__ .end +#define __EXPORT__ .globl +#define __IMPORT__ .extern +#define __LABEL__ : +#define __STR__ .ascii +#define __THUMB_LABEL__ .thumb_func +#define __WORD__ .word +#define __INLINE_DATA__ + +#endif // codered + +//***************************************************************************** +// +// The defines required for EW-ARM. +// +//***************************************************************************** +#ifdef ewarm + +// +// Section headers. +// +#define __LIBRARY__ module +#define __TEXT__ rseg CODE:CODE(2) +#define __DATA__ rseg DATA:DATA(2) +#define __BSS__ rseg DATA:DATA(2) +#define __TEXT_NOROOT__ rseg CODE:CODE:NOROOT(2) + +// +// Assembler nmenonics. +// +#define __ALIGN__ alignrom 2 +#define __END__ end +#define __EXPORT__ export +#define __IMPORT__ import +#define __LABEL__ +#define __STR__ dcb +#define __THUMB_LABEL__ thumb +#define __WORD__ dcd +#define __INLINE_DATA__ data + +#endif // ewarm + +//***************************************************************************** +// +// The defines required for GCC. +// +//***************************************************************************** +#if defined(gcc) + +// +// The assembly code preamble required to put the assembler into the correct +// configuration. +// + .syntax unified + .thumb + +// +// Section headers. +// +#define __LIBRARY__ @ +#define __TEXT__ .text +#define __DATA__ .data +#define __BSS__ .bss +#define __TEXT_NOROOT__ .text + +// +// Assembler nmenonics. +// +#define __ALIGN__ .balign 4 +#define __END__ .end +#define __EXPORT__ .globl +#define __IMPORT__ .extern +#define __LABEL__ : +#define __STR__ .ascii +#define __THUMB_LABEL__ .thumb_func +#define __WORD__ .word +#define __INLINE_DATA__ + +#endif // gcc + +//***************************************************************************** +// +// The defines required for RV-MDK. +// +//***************************************************************************** +#ifdef rvmdk + +// +// The assembly code preamble required to put the assembler into the correct +// configuration. +// + thumb + require8 + preserve8 + +// +// Section headers. +// +#define __LIBRARY__ ; +#define __TEXT__ area ||.text||, code, readonly, align=2 +#define __DATA__ area ||.data||, data, align=2 +#define __BSS__ area ||.bss||, noinit, align=2 +#define __TEXT_NOROOT__ area ||.text||, code, readonly, align=2 + +// +// Assembler nmenonics. +// +#define __ALIGN__ align 4 +#define __END__ end +#define __EXPORT__ export +#define __IMPORT__ import +#define __LABEL__ +#define __STR__ dcb +#define __THUMB_LABEL__ +#define __WORD__ dcd +#define __INLINE_DATA__ + +#endif // rvmdk + +//***************************************************************************** +// +// The defines required for Sourcery G++. +// +//***************************************************************************** +#if defined(sourcerygxx) + +// +// The assembly code preamble required to put the assembler into the correct +// configuration. +// + .syntax unified + .thumb + +// +// Section headers. +// +#define __LIBRARY__ @ +#define __TEXT__ .text +#define __DATA__ .data +#define __BSS__ .bss +#define __TEXT_NOROOT__ .text + +// +// Assembler nmenonics. +// +#define __ALIGN__ .balign 4 +#define __END__ .end +#define __EXPORT__ .globl +#define __IMPORT__ .extern +#define __LABEL__ : +#define __STR__ .ascii +#define __THUMB_LABEL__ .thumb_func +#define __WORD__ .word +#define __INLINE_DATA__ + +#endif // sourcerygxx + +#endif // __ASMDEF_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_adc.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_adc.h new file mode 100755 index 0000000..525ce90 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_adc.h @@ -0,0 +1,888 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_ADC_H__ +#define __HW_ADC_H__ + +//***************************************************************************** +// +// The following are defines for the ADC register offsets. +// +//***************************************************************************** +#define ADC_O_ADC_CTRL 0x00000000 // ADC control register. +#define ADC_O_adc_ch0_gain 0x00000004 // Channel 0 gain setting +#define ADC_O_adc_ch1_gain 0x00000008 // Channel 1 gain setting +#define ADC_O_adc_ch2_gain 0x0000000C // Channel 2 gain setting +#define ADC_O_adc_ch3_gain 0x00000010 // Channel 3 gain setting +#define ADC_O_adc_ch4_gain 0x00000014 // Channel 4 gain setting +#define ADC_O_adc_ch5_gain 0x00000018 // Channel 5 gain setting +#define ADC_O_adc_ch6_gain 0x0000001C // Channel 6 gain setting +#define ADC_O_adc_ch7_gain 0x00000020 // Channel 7 gain setting +#define ADC_O_adc_ch0_irq_en 0x00000024 // Channel 0 interrupt enable + // register +#define ADC_O_adc_ch1_irq_en 0x00000028 // Channel 1 interrupt enable + // register +#define ADC_O_adc_ch2_irq_en 0x0000002C // Channel 2 interrupt enable + // register +#define ADC_O_adc_ch3_irq_en 0x00000030 // Channel 3 interrupt enable + // register +#define ADC_O_adc_ch4_irq_en 0x00000034 // Channel 4 interrupt enable + // register +#define ADC_O_adc_ch5_irq_en 0x00000038 // Channel 5 interrupt enable + // register +#define ADC_O_adc_ch6_irq_en 0x0000003C // Channel 6 interrupt enable + // register +#define ADC_O_adc_ch7_irq_en 0x00000040 // Channel 7 interrupt enable + // register +#define ADC_O_adc_ch0_irq_status \ + 0x00000044 // Channel 0 interrupt status + // register + +#define ADC_O_adc_ch1_irq_status \ + 0x00000048 // Channel 1 interrupt status + // register + +#define ADC_O_adc_ch2_irq_status \ + 0x0000004C + +#define ADC_O_adc_ch3_irq_status \ + 0x00000050 // Channel 3 interrupt status + // register + +#define ADC_O_adc_ch4_irq_status \ + 0x00000054 // Channel 4 interrupt status + // register + +#define ADC_O_adc_ch5_irq_status \ + 0x00000058 + +#define ADC_O_adc_ch6_irq_status \ + 0x0000005C // Channel 6 interrupt status + // register + +#define ADC_O_adc_ch7_irq_status \ + 0x00000060 // Channel 7 interrupt status + // register + +#define ADC_O_adc_dma_mode_en 0x00000064 // DMA mode enable register +#define ADC_O_adc_timer_configuration \ + 0x00000068 // ADC timer configuration register + +#define ADC_O_adc_timer_current_count \ + 0x00000070 // ADC timer current count register + +#define ADC_O_channel0FIFODATA 0x00000074 // CH0 FIFO DATA register +#define ADC_O_channel1FIFODATA 0x00000078 // CH1 FIFO DATA register +#define ADC_O_channel2FIFODATA 0x0000007C // CH2 FIFO DATA register +#define ADC_O_channel3FIFODATA 0x00000080 // CH3 FIFO DATA register +#define ADC_O_channel4FIFODATA 0x00000084 // CH4 FIFO DATA register +#define ADC_O_channel5FIFODATA 0x00000088 // CH5 FIFO DATA register +#define ADC_O_channel6FIFODATA 0x0000008C // CH6 FIFO DATA register +#define ADC_O_channel7FIFODATA 0x00000090 // CH7 FIFO DATA register +#define ADC_O_adc_ch0_fifo_lvl 0x00000094 // channel 0 FIFO Level register +#define ADC_O_adc_ch1_fifo_lvl 0x00000098 // Channel 1 interrupt status + // register +#define ADC_O_adc_ch2_fifo_lvl 0x0000009C +#define ADC_O_adc_ch3_fifo_lvl 0x000000A0 // Channel 3 interrupt status + // register +#define ADC_O_adc_ch4_fifo_lvl 0x000000A4 // Channel 4 interrupt status + // register +#define ADC_O_adc_ch5_fifo_lvl 0x000000A8 +#define ADC_O_adc_ch6_fifo_lvl 0x000000AC // Channel 6 interrupt status + // register +#define ADC_O_adc_ch7_fifo_lvl 0x000000B0 // Channel 7 interrupt status + // register + +#define ADC_O_ADC_CH_ENABLE 0x000000B8 + +//****************************************************************************** +// +// The following are defines for the bit fields in the ADC_O_ADC_CTRL register. +// +//****************************************************************************** +#define ADC_ADC_CTRL_adc_cap_scale \ + 0x00000020 // ADC CAP SCALE. + +#define ADC_ADC_CTRL_adc_buf_bypass \ + 0x00000010 // ADC ANA CIO buffer bypass. + // Signal is modelled in ANA TOP. + // When '1': ADC buffer is bypassed. + +#define ADC_ADC_CTRL_adc_buf_en 0x00000008 // ADC ANA buffer enable. When 1: + // ADC buffer is enabled. +#define ADC_ADC_CTRL_adc_core_en \ + 0x00000004 // ANA ADC core en. This signal act + // as glbal enable to ADC CIO. When + // 1: ADC core is enabled. + +#define ADC_ADC_CTRL_adc_soft_reset \ + 0x00000002 // ADC soft reset. When '1' : reset + // ADC internal logic. + +#define ADC_ADC_CTRL_adc_en 0x00000001 // ADC global enable. When set ADC + // module is enabled +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch0_gain register. +// +//****************************************************************************** +#define ADC_adc_ch0_gain_adc_channel0_gain_M \ + 0x00000003 // gain setting for ADC channel 0. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch0_gain_adc_channel0_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch1_gain register. +// +//****************************************************************************** +#define ADC_adc_ch1_gain_adc_channel1_gain_M \ + 0x00000003 // gain setting for ADC channel 1. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch1_gain_adc_channel1_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch2_gain register. +// +//****************************************************************************** +#define ADC_adc_ch2_gain_adc_channel2_gain_M \ + 0x00000003 // gain setting for ADC channel 2. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch2_gain_adc_channel2_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch3_gain register. +// +//****************************************************************************** +#define ADC_adc_ch3_gain_adc_channel3_gain_M \ + 0x00000003 // gain setting for ADC channel 3. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch3_gain_adc_channel3_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch4_gain register. +// +//****************************************************************************** +#define ADC_adc_ch4_gain_adc_channel4_gain_M \ + 0x00000003 // gain setting for ADC channel 4 + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch4_gain_adc_channel4_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch5_gain register. +// +//****************************************************************************** +#define ADC_adc_ch5_gain_adc_channel5_gain_M \ + 0x00000003 // gain setting for ADC channel 5. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch5_gain_adc_channel5_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch6_gain register. +// +//****************************************************************************** +#define ADC_adc_ch6_gain_adc_channel6_gain_M \ + 0x00000003 // gain setting for ADC channel 6 + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch6_gain_adc_channel6_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch7_gain register. +// +//****************************************************************************** +#define ADC_adc_ch7_gain_adc_channel7_gain_M \ + 0x00000003 // gain setting for ADC channel 7. + // when "00": 1x when "01: 2x when + // "10":3x when "11" 4x + +#define ADC_adc_ch7_gain_adc_channel7_gain_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch0_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch0_irq_en_adc_channel0_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch0_irq_en_adc_channel0_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch1_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch1_irq_en_adc_channel1_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch1_irq_en_adc_channel1_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch2_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch2_irq_en_adc_channel2_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch2_irq_en_adc_channel2_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch3_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch3_irq_en_adc_channel3_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch3_irq_en_adc_channel3_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch4_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch4_irq_en_adc_channel4_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch4_irq_en_adc_channel4_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch5_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch5_irq_en_adc_channel5_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch5_irq_en_adc_channel5_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch6_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch6_irq_en_adc_channel6_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch6_irq_en_adc_channel6_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch7_irq_en register. +// +//****************************************************************************** +#define ADC_adc_ch7_irq_en_adc_channel7_irq_en_M \ + 0x0000000F // interrupt enable register for + // per ADC channel bit 3: when '1' + // -> enable FIFO overflow interrupt + // bit 2: when '1' -> enable FIFO + // underflow interrupt bit 1: when + // "1' -> enable FIFO empty + // interrupt bit 0: when "1" -> + // enable FIFO full interrupt + +#define ADC_adc_ch7_irq_en_adc_channel7_irq_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch0_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch0_irq_status_adc_channel0_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch0_irq_status_adc_channel0_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch1_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch1_irq_status_adc_channel1_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch1_irq_status_adc_channel1_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch2_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch2_irq_status_adc_channel2_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch2_irq_status_adc_channel2_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch3_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch3_irq_status_adc_channel3_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch3_irq_status_adc_channel3_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch4_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch4_irq_status_adc_channel4_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch4_irq_status_adc_channel4_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch5_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch5_irq_status_adc_channel5_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch5_irq_status_adc_channel5_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch6_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch6_irq_status_adc_channel6_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch6_irq_status_adc_channel6_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch7_irq_status register. +// +//****************************************************************************** +#define ADC_adc_ch7_irq_status_adc_channel7_irq_status_M \ + 0x0000000F // interrupt status register for + // per ADC channel. Interrupt status + // can be cleared on write. bit 3: + // when value '1' is written -> + // would clear FIFO overflow + // interrupt status in the next + // cycle. if same interrupt is set + // in the same cycle then interurpt + // would be set and clear command + // will be ignored. bit 2: when + // value '1' is written -> would + // clear FIFO underflow interrupt + // status in the next cycle. bit 1: + // when value '1' is written -> + // would clear FIFO empty interrupt + // status in the next cycle. bit 0: + // when value '1' is written -> + // would clear FIFO full interrupt + // status in the next cycle. + +#define ADC_adc_ch7_irq_status_adc_channel7_irq_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_dma_mode_en register. +// +//****************************************************************************** +#define ADC_adc_dma_mode_en_DMA_MODEenable_M \ + 0x000000FF // this register enable DMA mode. + // when '1' respective ADC channel + // is enabled for DMA. When '0' only + // interrupt mode is enabled. Bit 0: + // channel 0 DMA mode enable. Bit 1: + // channel 1 DMA mode enable. Bit 2: + // channel 2 DMA mode enable. Bit 3: + // channel 3 DMA mode enable. bit 4: + // channel 4 DMA mode enable. bit 5: + // channel 5 DMA mode enable. bit 6: + // channel 6 DMA mode enable. bit 7: + // channel 7 DMA mode enable. + +#define ADC_adc_dma_mode_en_DMA_MODEenable_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_timer_configuration register. +// +//****************************************************************************** +#define ADC_adc_timer_configuration_timeren \ + 0x02000000 // when '1' timer is enabled. + +#define ADC_adc_timer_configuration_timerreset \ + 0x01000000 // when '1' reset timer. + +#define ADC_adc_timer_configuration_timercount_M \ + 0x00FFFFFF // Timer count configuration. 17 + // bit counter is supported. Other + // MSB's are redundent. + +#define ADC_adc_timer_configuration_timercount_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_timer_current_count register. +// +//****************************************************************************** +#define ADC_adc_timer_current_count_timercurrentcount_M \ + 0x0001FFFF // Timer count configuration + +#define ADC_adc_timer_current_count_timercurrentcount_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel0FIFODATA register. +// +//****************************************************************************** +#define ADC_channel0FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel0FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel1FIFODATA register. +// +//****************************************************************************** +#define ADC_channel1FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel1FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel2FIFODATA register. +// +//****************************************************************************** +#define ADC_channel2FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel2FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel3FIFODATA register. +// +//****************************************************************************** +#define ADC_channel3FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel3FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel4FIFODATA register. +// +//****************************************************************************** +#define ADC_channel4FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel4FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel5FIFODATA register. +// +//****************************************************************************** +#define ADC_channel5FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel5FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel6FIFODATA register. +// +//****************************************************************************** +#define ADC_channel6FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel6FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_channel7FIFODATA register. +// +//****************************************************************************** +#define ADC_channel7FIFODATA_FIFO_RD_DATA_M \ + 0xFFFFFFFF // read to this register would + // return ADC data along with time + // stamp information in following + // format: bits [13:0] : ADC sample + // bits [31:14]: : time stamp per + // ADC sample + +#define ADC_channel7FIFODATA_FIFO_RD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch0_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch0_fifo_lvl_adc_channel0_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch0_fifo_lvl_adc_channel0_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch1_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch1_fifo_lvl_adc_channel1_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch1_fifo_lvl_adc_channel1_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch2_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch2_fifo_lvl_adc_channel2_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch2_fifo_lvl_adc_channel2_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch3_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch3_fifo_lvl_adc_channel3_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch3_fifo_lvl_adc_channel3_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch4_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch4_fifo_lvl_adc_channel4_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch4_fifo_lvl_adc_channel4_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch5_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch5_fifo_lvl_adc_channel5_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch5_fifo_lvl_adc_channel5_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch6_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch6_fifo_lvl_adc_channel6_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch6_fifo_lvl_adc_channel6_fifo_lvl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// ADC_O_adc_ch7_fifo_lvl register. +// +//****************************************************************************** +#define ADC_adc_ch7_fifo_lvl_adc_channel7_fifo_lvl_M \ + 0x00000007 // This register shows current FIFO + // level. FIFO is 4 word wide. + // Possible supported levels are : + // 0x0 to 0x3 + +#define ADC_adc_ch7_fifo_lvl_adc_channel7_fifo_lvl_S 0 + + + +#endif // __HW_ADC_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_aes.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_aes.h new file mode 100755 index 0000000..3ab0398 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_aes.h @@ -0,0 +1,802 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_AES_H__ +#define __HW_AES_H__ + +//***************************************************************************** +// +// The following are defines for the AES_P register offsets. +// +//***************************************************************************** +#define AES_O_KEY2_6 0x00000000 // XTS second key / CBC-MAC third + // key +#define AES_O_KEY2_7 0x00000004 // XTS second key (MSW for 256-bit + // key) / CBC-MAC third key (MSW) +#define AES_O_KEY2_4 0x00000008 // XTS / CCM second key / CBC-MAC + // third key (LSW) +#define AES_O_KEY2_5 0x0000000C // XTS second key (MSW for 192-bit + // key) / CBC-MAC third key +#define AES_O_KEY2_2 0x00000010 // XTS / CCM / CBC-MAC second key / + // Hash Key input +#define AES_O_KEY2_3 0x00000014 // XTS second key (MSW for 128-bit + // key) + CCM/CBC-MAC second key + // (MSW) / Hash Key input (MSW) +#define AES_O_KEY2_0 0x00000018 // XTS / CCM / CBC-MAC second key + // (LSW) / Hash Key input (LSW) +#define AES_O_KEY2_1 0x0000001C // XTS / CCM / CBC-MAC second key / + // Hash Key input +#define AES_O_KEY1_6 0x00000020 // Key (LSW for 256-bit key) +#define AES_O_KEY1_7 0x00000024 // Key (MSW for 256-bit key) +#define AES_O_KEY1_4 0x00000028 // Key (LSW for 192-bit key) +#define AES_O_KEY1_5 0x0000002C // Key (MSW for 192-bit key) +#define AES_O_KEY1_2 0x00000030 // Key +#define AES_O_KEY1_3 0x00000034 // Key (MSW for 128-bit key) +#define AES_O_KEY1_0 0x00000038 // Key (LSW for 128-bit key) +#define AES_O_KEY1_1 0x0000003C // Key +#define AES_O_IV_IN_0 0x00000040 // Initialization Vector input + // (LSW) +#define AES_O_IV_IN_1 0x00000044 // Initialization vector input +#define AES_O_IV_IN_2 0x00000048 // Initialization vector input +#define AES_O_IV_IN_3 0x0000004C // Initialization Vector input + // (MSW) +#define AES_O_CTRL 0x00000050 // register determines the mode of + // operation of the AES Engine +#define AES_O_C_LENGTH_0 0x00000054 // Crypto data length registers + // (LSW and MSW) store the + // cryptographic data length in + // bytes for all modes. Once + // processing with this context is + // started@@ this length decrements + // to zero. Data lengths up to (2^61 + // – 1) bytes are allowed. For GCM@@ + // any value up to 2^36 - 32 bytes + // can be used. This is because a + // 32-bit counter mode is used; the + // maximum number of 128-bit blocks + // is 2^32 – 2@@ resulting in a + // maximum number of bytes of 2^36 - + // 32. A write to this register + // triggers the engine to start + // using this context. This is valid + // for all modes except GCM and CCM. + // Note that for the combined + // modes@@ this length does not + // include the authentication only + // data; the authentication length + // is specified in the + // AES_AUTH_LENGTH register below. + // All modes must have a length > 0. + // For the combined modes@@ it is + // allowed to have one of the + // lengths equal to zero. For the + // basic encryption modes + // (ECB/CBC/CTR/ICM/CFB128) it is + // allowed to program zero to the + // length field; in that case the + // length is assumed infinite. All + // data must be byte (8-bit) + // aligned; bit aligned data streams + // are not supported by the AES + // Engine. For a Host read + // operation@@ these registers + // return all-zeroes. +#define AES_O_C_LENGTH_1 0x00000058 // Crypto data length registers + // (LSW and MSW) store the + // cryptographic data length in + // bytes for all modes. Once + // processing with this context is + // started@@ this length decrements + // to zero. Data lengths up to (2^61 + // – 1) bytes are allowed. For GCM@@ + // any value up to 2^36 - 32 bytes + // can be used. This is because a + // 32-bit counter mode is used; the + // maximum number of 128-bit blocks + // is 2^32 – 2@@ resulting in a + // maximum number of bytes of 2^36 - + // 32. A write to this register + // triggers the engine to start + // using this context. This is valid + // for all modes except GCM and CCM. + // Note that for the combined + // modes@@ this length does not + // include the authentication only + // data; the authentication length + // is specified in the + // AES_AUTH_LENGTH register below. + // All modes must have a length > 0. + // For the combined modes@@ it is + // allowed to have one of the + // lengths equal to zero. For the + // basic encryption modes + // (ECB/CBC/CTR/ICM/CFB128) it is + // allowed to program zero to the + // length field; in that case the + // length is assumed infinite. All + // data must be byte (8-bit) + // aligned; bit aligned data streams + // are not supported by the AES + // Engine. For a Host read + // operation@@ these registers + // return all-zeroes. +#define AES_O_AUTH_LENGTH 0x0000005C // AAD data length. The + // authentication length register + // store the authentication data + // length in bytes for combined + // modes only (GCM or CCM) Supported + // AAD-lengths for CCM are from 0 to + // (2^16 - 2^8) bytes. For GCM any + // value up to (2^32 - 1) bytes can + // be used. Once processing with + // this context is started@@ this + // length decrements to zero. A + // write to this register triggers + // the engine to start using this + // context for GCM and CCM. For XTS + // this register is optionally used + // to load ‘j’. Loading of ‘j’ is + // only required if ‘j’ != 0. ‘j’ is + // a 28-bit value and must be + // written to bits [31-4] of this + // register. ‘j’ represents the + // sequential number of the 128-bit + // block inside the data unit. For + // the first block in a unit@@ this + // value is zero. It is not required + // to provide a ‘j’ for each new + // data block within a unit. Note + // that it is possible to start with + // a ‘j’ unequal to zero; refer to + // Table 4 for more details. For a + // Host read operation@@ these + // registers return all-zeroes. +#define AES_O_DATA_IN_0 0x00000060 // Data register to read and write + // plaintext/ciphertext (MSW) +#define AES_O_DATA_IN_1 0x00000064 // Data register to read and write + // plaintext/ciphertext +#define AES_O_DATA_IN_2 0x00000068 // Data register to read and write + // plaintext/ciphertext +#define AES_O_DATA_IN_3 0x0000006C // Data register to read and write + // plaintext/ciphertext (LSW) +#define AES_O_TAG_OUT_0 0x00000070 +#define AES_O_TAG_OUT_1 0x00000074 +#define AES_O_TAG_OUT_2 0x00000078 +#define AES_O_TAG_OUT_3 0x0000007C +#define AES_O_REVISION 0x00000080 // Register AES_REVISION +#define AES_O_SYSCONFIG 0x00000084 // Register AES_SYSCONFIG.This + // register configures the DMA + // signals and controls the IDLE and + // reset logic +#define AES_O_SYSSTATUS 0x00000088 +#define AES_O_IRQSTATUS 0x0000008C // This register indicates the + // interrupt status. If one of the + // interrupt bits is set the + // interrupt output will be asserted +#define AES_O_IRQENABLE 0x00000090 // This register contains an enable + // bit for each unique interrupt + // generated by the module. It + // matches the layout of + // AES_IRQSTATUS register. An + // interrupt is enabled when the bit + // in this register is set to ‘1’. + // An interrupt that is enabled is + // propagated to the SINTREQUEST_x + // output. All interrupts need to be + // enabled explicitly by writing + // this register. + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_6 register. +// +//****************************************************************************** +#define AES_KEY2_6_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_6_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_7 register. +// +//****************************************************************************** +#define AES_KEY2_7_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_7_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_4 register. +// +//****************************************************************************** +#define AES_KEY2_4_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_4_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_5 register. +// +//****************************************************************************** +#define AES_KEY2_5_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_5_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_2 register. +// +//****************************************************************************** +#define AES_KEY2_2_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_2_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_3 register. +// +//****************************************************************************** +#define AES_KEY2_3_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_3_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_0 register. +// +//****************************************************************************** +#define AES_KEY2_0_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_0_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY2_1 register. +// +//****************************************************************************** +#define AES_KEY2_1_KEY_M 0xFFFFFFFF // key data +#define AES_KEY2_1_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_6 register. +// +//****************************************************************************** +#define AES_KEY1_6_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_6_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_7 register. +// +//****************************************************************************** +#define AES_KEY1_7_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_7_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_4 register. +// +//****************************************************************************** +#define AES_KEY1_4_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_4_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_5 register. +// +//****************************************************************************** +#define AES_KEY1_5_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_5_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_2 register. +// +//****************************************************************************** +#define AES_KEY1_2_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_2_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_3 register. +// +//****************************************************************************** +#define AES_KEY1_3_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_3_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_0 register. +// +//****************************************************************************** +#define AES_KEY1_0_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_0_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_KEY1_1 register. +// +//****************************************************************************** +#define AES_KEY1_1_KEY_M 0xFFFFFFFF // key data +#define AES_KEY1_1_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IV_IN_0 register. +// +//****************************************************************************** +#define AES_IV_IN_0_DATA_M 0xFFFFFFFF // IV data +#define AES_IV_IN_0_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IV_IN_1 register. +// +//****************************************************************************** +#define AES_IV_IN_1_DATA_M 0xFFFFFFFF // IV data +#define AES_IV_IN_1_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IV_IN_2 register. +// +//****************************************************************************** +#define AES_IV_IN_2_DATA_M 0xFFFFFFFF // IV data +#define AES_IV_IN_2_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IV_IN_3 register. +// +//****************************************************************************** +#define AES_IV_IN_3_DATA_M 0xFFFFFFFF // IV data +#define AES_IV_IN_3_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_CTRL register. +// +//****************************************************************************** +#define AES_CTRL_CONTEXT_READY \ + 0x80000000 // If ‘1’@@ this read-only status + // bit indicates that the context + // data registers can be overwritten + // and the host is permitted to + // write the next context. + +#define AES_CTRL_SVCTXTRDY \ + 0x40000000 // If ‘1’@@ this read-only status + // bit indicates that an AES + // authentication TAG and/or IV + // block(s) is/are available for the + // host to retrieve. This bit is + // only asserted if the + // ‘save_context’ bit is set to ‘1’. + // The bit is mutual exclusive with + // the ‘context_ready’ bit. + +#define AES_CTRL_SAVE_CONTEXT 0x20000000 // This bit is used to indicate + // that an authentication TAG or + // result IV needs to be stored as a + // result context. If this bit is + // set@@ context output DMA and/or + // interrupt will be asserted if the + // operation is finished and related + // signals are enabled. +#define AES_CTRL_CCM_M 0x01C00000 // Defines “M†that indicated the + // length of the authentication + // field for CCM operations; the + // authentication field length + // equals two times (the value of + // CCM-M plus one). Note that the + // AES Engine always returns a + // 128-bit authentication field@@ of + // which the M least significant + // bytes are valid. All values are + // supported. +#define AES_CTRL_CCM_S 22 +#define AES_CTRL_CCM_L_M 0x00380000 // Defines “L†that indicated the + // width of the length field for CCM + // operations; the length field in + // bytes equals the value of CMM-L + // plus one. Supported values for L + // are (programmed value): 2 (1)@@ 4 + // (3) and 8 (7). +#define AES_CTRL_CCM_L_S 19 +#define AES_CTRL_CCM 0x00040000 // AES-CCM is selected@@ this is a + // combined mode@@ using AES for + // both authentication and + // encryption. No additional mode + // selection is required. 0 Other + // mode selected 1 ccm mode selected +#define AES_CTRL_GCM_M 0x00030000 // AES-GCM mode is selected.this is + // a combined mode@@ using the + // Galois field multiplier GF(2^128) + // for authentication and AES-CTR + // mode for encryption@@ the bits + // specify the GCM mode. 0x0 No + // operation 0x1 GHASH with H loaded + // and Y0-encrypted forced to zero + // 0x2 GHASH with H loaded and + // Y0-encrypted calculated + // internally 0x3 Autonomous GHASH + // (both H and Y0-encrypted + // calculated internally) +#define AES_CTRL_GCM_S 16 +#define AES_CTRL_CBCMAC 0x00008000 // AES-CBC MAC is selected@@ the + // Direction bit must be set to ‘1’ + // for this mode. 0 Other mode + // selected 1 cbcmac mode selected +#define AES_CTRL_F9 0x00004000 // AES f9 mode is selected@@ the + // AES key size must be set to + // 128-bit for this mode. 0 Other + // mode selected 1 f9 selected +#define AES_CTRL_F8 0x00002000 // AES f8 mode is selected@@ the + // AES key size must be set to + // 128-bit for this mode. 0 Other + // mode selected 1 f8 selected +#define AES_CTRL_XTS_M 0x00001800 // AES-XTS operation is selected; + // the bits specify the XTS mode.01 + // = Previous/intermediate tweak + // value and ‘j’ loaded (value is + // loaded via IV@@ j is loaded via + // the AAD length register) 0x0 No + // operation 0x1 + // Previous/intermediate tweak value + // and ‘j’ loaded (value is loaded + // via IV@@ j is loaded via the AAD + // length register) 0x2 Key2@@ i and + // j loaded (i is loaded via IV@@ j + // is loaded via the AAD length + // register) 0x3 Key2 and i loaded@@ + // j=0 (i is loaded via IV) +#define AES_CTRL_XTS_S 11 +#define AES_CTRL_CFB 0x00000400 // full block AES cipher feedback + // mode (CFB128) is selected. 0 + // other mode selected 1 cfb + // selected +#define AES_CTRL_ICM 0x00000200 // AES integer counter mode (ICM) + // is selected@@ this is a counter + // mode with a 16-bit wide counter. + // 0 Other mode selected. 1 ICM mode + // selected +#define AES_CTRL_CTR_WIDTH_M 0x00000180 // Specifies the counter width for + // AES-CTR mode 0x0 Counter is 32 + // bits 0x1 Counter is 64 bits 0x2 + // Counter is 128 bits 0x3 Counter + // is 192 bits +#define AES_CTRL_CTR_WIDTH_S 7 +#define AES_CTRL_CTR 0x00000040 // Tthis bit must also be set for + // GCM and CCM@@ when + // encryption/decryption is + // required. 0 Other mode selected 1 + // Counter mode +#define AES_CTRL_MODE 0x00000020 // ecb/cbc mode 0 ecb mode 1 cbc + // mode +#define AES_CTRL_KEY_SIZE_M 0x00000018 // key size 0x0 reserved 0x1 Key is + // 128 bits. 0x2 Key is 192 bits 0x3 + // Key is 256 +#define AES_CTRL_KEY_SIZE_S 3 +#define AES_CTRL_DIRECTION 0x00000004 // If set to ‘1’ an encrypt + // operation is performed. If set to + // ‘0’ a decrypt operation is + // performed. Read 0 decryption is + // selected Read 1 Encryption is + // selected +#define AES_CTRL_INPUT_READY 0x00000002 // If ‘1’@@ this read-only status + // bit indicates that the 16-byte + // input buffer is empty@@ and the + // host is permitted to write the + // next block of data. +#define AES_CTRL_OUTPUT_READY 0x00000001 // If ‘1’@@ this read-only status + // bit indicates that an AES output + // block is available for the host + // to retrieve. +//****************************************************************************** +// +// The following are defines for the bit fields in the +// AES_O_C_LENGTH_0 register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the +// AES_O_C_LENGTH_1 register. +// +//****************************************************************************** +#define AES_C_LENGTH_1_LENGTH_M \ + 0x1FFFFFFF // Data length (MSW) length + // registers (LSW and MSW) store the + // cryptographic data length in + // bytes for all modes. Once + // processing with this context is + // started@@ this length decrements + // to zero. Data lengths up to (2^61 + // – 1) bytes are allowed. For GCM@@ + // any value up to 2^36 - 32 bytes + // can be used. This is because a + // 32-bit counter mode is used; the + // maximum number of 128-bit blocks + // is 2^32 – 2@@ resulting in a + // maximum number of bytes of 2^36 - + // 32. A write to this register + // triggers the engine to start + // using this context. This is valid + // for all modes except GCM and CCM. + // Note that for the combined + // modes@@ this length does not + // include the authentication only + // data; the authentication length + // is specified in the + // AES_AUTH_LENGTH register below. + // All modes must have a length > 0. + // For the combined modes@@ it is + // allowed to have one of the + // lengths equal to zero. For the + // basic encryption modes + // (ECB/CBC/CTR/ICM/CFB128) it is + // allowed to program zero to the + // length field; in that case the + // length is assumed infinite. All + // data must be byte (8-bit) + // aligned; bit aligned data streams + // are not supported by the AES + // Engine. For a Host read + // operation@@ these registers + // return all-zeroes. + +#define AES_C_LENGTH_1_LENGTH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// AES_O_AUTH_LENGTH register. +// +//****************************************************************************** +#define AES_AUTH_LENGTH_AUTH_M \ + 0xFFFFFFFF // data + +#define AES_AUTH_LENGTH_AUTH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_DATA_IN_0 register. +// +//****************************************************************************** +#define AES_DATA_IN_0_DATA_M 0xFFFFFFFF // Data to encrypt/decrypt +#define AES_DATA_IN_0_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_DATA_IN_1 register. +// +//****************************************************************************** +#define AES_DATA_IN_1_DATA_M 0xFFFFFFFF // Data to encrypt/decrypt +#define AES_DATA_IN_1_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_DATA_IN_2 register. +// +//****************************************************************************** +#define AES_DATA_IN_2_DATA_M 0xFFFFFFFF // Data to encrypt/decrypt +#define AES_DATA_IN_2_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_DATA_IN_3 register. +// +//****************************************************************************** +#define AES_DATA_IN_3_DATA_M 0xFFFFFFFF // Data to encrypt/decrypt +#define AES_DATA_IN_3_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_TAG_OUT_0 register. +// +//****************************************************************************** +#define AES_TAG_OUT_0_HASH_M 0xFFFFFFFF // Hash result (MSW) +#define AES_TAG_OUT_0_HASH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_TAG_OUT_1 register. +// +//****************************************************************************** +#define AES_TAG_OUT_1_HASH_M 0xFFFFFFFF // Hash result (MSW) +#define AES_TAG_OUT_1_HASH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_TAG_OUT_2 register. +// +//****************************************************************************** +#define AES_TAG_OUT_2_HASH_M 0xFFFFFFFF // Hash result (MSW) +#define AES_TAG_OUT_2_HASH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_TAG_OUT_3 register. +// +//****************************************************************************** +#define AES_TAG_OUT_3_HASH_M 0xFFFFFFFF // Hash result (LSW) +#define AES_TAG_OUT_3_HASH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_REVISION register. +// +//****************************************************************************** +#define AES_REVISION_SCHEME_M 0xC0000000 +#define AES_REVISION_SCHEME_S 30 +#define AES_REVISION_FUNC_M 0x0FFF0000 // Function indicates a software + // compatible module family. If + // there is no level of software + // compatibility a new Func number + // (and hence REVISION) should be + // assigned. +#define AES_REVISION_FUNC_S 16 +#define AES_REVISION_R_RTL_M 0x0000F800 // RTL Version (R)@@ maintained by + // IP design owner. RTL follows a + // numbering such as X.Y.R.Z which + // are explained in this table. R + // changes ONLY when: (1) PDS + // uploads occur which may have been + // due to spec changes (2) Bug fixes + // occur (3) Resets to '0' when X or + // Y changes. Design team has an + // internal 'Z' (customer invisible) + // number which increments on every + // drop that happens due to DV and + // RTL updates. Z resets to 0 when R + // increments. +#define AES_REVISION_R_RTL_S 11 +#define AES_REVISION_X_MAJOR_M \ + 0x00000700 // Major Revision (X)@@ maintained + // by IP specification owner. X + // changes ONLY when: (1) There is a + // major feature addition. An + // example would be adding Master + // Mode to Utopia Level2. The Func + // field (or Class/Type in old PID + // format) will remain the same. X + // does NOT change due to: (1) Bug + // fixes (2) Change in feature + // parameters. + +#define AES_REVISION_X_MAJOR_S 8 +#define AES_REVISION_CUSTOM_M 0x000000C0 +#define AES_REVISION_CUSTOM_S 6 +#define AES_REVISION_Y_MINOR_M \ + 0x0000003F // Minor Revision (Y)@@ maintained + // by IP specification owner. Y + // changes ONLY when: (1) Features + // are scaled (up or down). + // Flexibility exists in that this + // feature scalability may either be + // represented in the Y change or a + // specific register in the IP that + // indicates which features are + // exactly available. (2) When + // feature creeps from Is-Not list + // to Is list. But this may not be + // the case once it sees silicon; in + // which case X will change. Y does + // NOT change due to: (1) Bug fixes + // (2) Typos or clarifications (3) + // major functional/feature + // change/addition/deletion. Instead + // these changes may be reflected + // via R@@ S@@ X as applicable. Spec + // owner maintains a + // customer-invisible number 'S' + // which changes due to: (1) + // Typos/clarifications (2) Bug + // documentation. Note that this bug + // is not due to a spec change but + // due to implementation. + // Nevertheless@@ the spec tracks + // the IP bugs. An RTL release (say + // for silicon PG1.1) that occurs + // due to bug fix should document + // the corresponding spec number + // (X.Y.S) in its release notes. + +#define AES_REVISION_Y_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_SYSCONFIG register. +// +//****************************************************************************** +#define AES_SYSCONFIG_MACONTEXT_OUT_ON_DATA_OUT \ + 0x00000200 // If set to '1' the two context + // out requests + // (dma_req_context_out_en@@ Bit [8] + // above@@ and context_out interrupt + // enable@@ Bit [3] of AES_IRQENABLE + // register) are mapped on the + // corresponding data output request + // bit. In this case@@ the original + // ‘context out’ bit values are + // ignored. + +#define AES_SYSCONFIG_DMA_REQ_CONTEXT_OUT_EN \ + 0x00000100 // If set to ‘1’@@ the DMA context + // output request is enabled (for + // context data out@@ e.g. TAG for + // authentication modes). 0 Dma + // disabled 1 Dma enabled + +#define AES_SYSCONFIG_DMA_REQ_CONTEXT_IN_EN \ + 0x00000080 // If set to ‘1’@@ the DMA context + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +#define AES_SYSCONFIG_DMA_REQ_DATA_OUT_EN \ + 0x00000040 // If set to ‘1’@@ the DMA output + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +#define AES_SYSCONFIG_DMA_REQ_DATA_IN_EN \ + 0x00000020 // If set to ‘1’@@ the DMA input + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_SYSSTATUS register. +// +//****************************************************************************** +#define AES_SYSSTATUS_RESETDONE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IRQSTATUS register. +// +//****************************************************************************** +#define AES_IRQSTATUS_CONTEXT_OUT \ + 0x00000008 // This bit indicates + // authentication tag (and IV) + // interrupt(s) is/are active and + // triggers the interrupt output. + +#define AES_IRQSTATUS_DATA_OUT \ + 0x00000004 // This bit indicates data output + // interrupt is active and triggers + // the interrupt output. + +#define AES_IRQSTATUS_DATA_IN 0x00000002 // This bit indicates data input + // interrupt is active and triggers + // the interrupt output. +#define AES_IRQSTATUS_CONTEX_IN \ + 0x00000001 // This bit indicates context + // interrupt is active and triggers + // the interrupt output. + +//****************************************************************************** +// +// The following are defines for the bit fields in the AES_O_IRQENABLE register. +// +//****************************************************************************** +#define AES_IRQENABLE_CONTEXT_OUT \ + 0x00000008 // This bit indicates + // authentication tag (and IV) + // interrupt(s) is/are active and + // triggers the interrupt output. + +#define AES_IRQENABLE_DATA_OUT \ + 0x00000004 // This bit indicates data output + // interrupt is active and triggers + // the interrupt output. + +#define AES_IRQENABLE_DATA_IN 0x00000002 // This bit indicates data input + // interrupt is active and triggers + // the interrupt output. +#define AES_IRQENABLE_CONTEX_IN \ + 0x00000001 // This bit indicates context + // interrupt is active and triggers + // the interrupt output. + + + + +#endif // __HW_AES_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_config.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_config.h new file mode 100755 index 0000000..b8789b9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_config.h @@ -0,0 +1,747 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_APPS_CONFIG_H__ +#define __HW_APPS_CONFIG_H__ + +//***************************************************************************** +// +// The following are defines for the APPS_CONFIG register offsets. +// +//***************************************************************************** +#define APPS_CONFIG_O_PATCH_TRAP_ADDR_REG \ + 0x00000000 // Patch trap address Register + // array + +#define APPS_CONFIG_O_PATCH_TRAP_EN_REG \ + 0x00000078 + +#define APPS_CONFIG_O_FAULT_STATUS_REG \ + 0x0000007C + +#define APPS_CONFIG_O_MEMSS_WR_ERR_CLR_REG \ + 0x00000080 + +#define APPS_CONFIG_O_MEMSS_WR_ERR_ADDR_REG \ + 0x00000084 + +#define APPS_CONFIG_O_DMA_DONE_INT_MASK \ + 0x0000008C + +#define APPS_CONFIG_O_DMA_DONE_INT_MASK_SET \ + 0x00000090 + +#define APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR \ + 0x00000094 + +#define APPS_CONFIG_O_DMA_DONE_INT_STS_CLR \ + 0x00000098 + +#define APPS_CONFIG_O_DMA_DONE_INT_ACK \ + 0x0000009C + +#define APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED \ + 0x000000A0 + +#define APPS_CONFIG_O_DMA_DONE_INT_STS_RAW \ + 0x000000A4 + +#define APPS_CONFIG_O_FAULT_STATUS_CLR_REG \ + 0x000000A8 + +#define APPS_CONFIG_O_RESERVD_REG_0 \ + 0x000000AC + +#define APPS_CONFIG_O_GPT_TRIG_SEL \ + 0x000000B0 + +#define APPS_CONFIG_O_TOP_DIE_SPARE_DIN_REG \ + 0x000000B4 + +#define APPS_CONFIG_O_TOP_DIE_SPARE_DOUT_REG \ + 0x000000B8 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_PATCH_TRAP_ADDR_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_PATCH_TRAP_ADDR_REG_PATCH_TRAP_ADDR_M \ + 0xFFFFFFFF // When PATCH_TRAP_EN[n] is set bus + // fault is generated for the + // address + // PATCH_TRAP_ADDR_REG[n][31:0] from + // Idcode bus. The exception routine + // should take care to jump to the + // location where the patch + // correspond to this address is + // kept. + +#define APPS_CONFIG_PATCH_TRAP_ADDR_REG_PATCH_TRAP_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_PATCH_TRAP_EN_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_PATCH_TRAP_EN_REG_PATCH_TRAP_EN_M \ + 0x3FFFFFFF // When PATCH_TRAP_EN[n] is set bus + // fault is generated for the + // address PATCH_TRAP_ADD[n][31:0] + // from Idcode bus. The exception + // routine should take care to jump + // to the location where the patch + // correspond to this address is + // kept. + +#define APPS_CONFIG_PATCH_TRAP_EN_REG_PATCH_TRAP_EN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_FAULT_STATUS_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_FAULT_STATUS_REG_PATCH_ERR_INDEX_M \ + 0x0000003E // This field shows because of + // which patch trap address the + // bus_fault is generated. If the + // PATCH_ERR bit is set, then it + // means the bus fault is generated + // because of + // PATCH_TRAP_ADDR_REG[2^PATCH_ERR_INDEX] + +#define APPS_CONFIG_FAULT_STATUS_REG_PATCH_ERR_INDEX_S 1 +#define APPS_CONFIG_FAULT_STATUS_REG_PATCH_ERR \ + 0x00000001 // This bit is set when there is a + // bus fault because of patched + // address access to the Apps boot + // rom. Write 0 to clear this + // register. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_MEMSS_WR_ERR_CLR_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_MEMSS_WR_ERR_CLR_REG_MEMSS_WR_ERR_CLR \ + 0x00000001 // This bit is set when there is a + // an error in memss write access. + // And the address causing this + // error is captured in + // MEMSS_ERR_ADDR_REG. To capture + // the next error address one have + // to clear this bit. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_MEMSS_WR_ERR_ADDR_REG register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_MASK register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_MASK_ADC_WR_DMA_DONE_INT_MASK_M \ + 0x0000F000 // 1= disable corresponding + // interrupt;0 = interrupt enabled + // bit 14: ADC channel 7 interrupt + // enable/disable bit 13: ADC + // channel 5 interrupt + // enable/disable bit 12: ADC + // channel 3 interrupt + // enable/disable bit 11: ADC + // channel 1 interrupt + // enable/disable + +#define APPS_CONFIG_DMA_DONE_INT_MASK_ADC_WR_DMA_DONE_INT_MASK_S 12 +#define APPS_CONFIG_DMA_DONE_INT_MASK_MCASP_WR_DMA_DONE_INT_MASK \ + 0x00000800 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_MCASP_RD_DMA_DONE_INT_MASK \ + 0x00000400 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CAM_FIFO_EMPTY_DMA_DONE_INT_MASK \ + 0x00000200 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CAM_THRESHHOLD_DMA_DONE_INT_MASK \ + 0x00000100 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SHSPI_WR_DMA_DONE_INT_MASK \ + 0x00000080 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SHSPI_RD_DMA_DONE_INT_MASK \ + 0x00000040 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_HOSTSPI_WR_DMA_DONE_INT_MASK \ + 0x00000020 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_HOSTSPI_RD_DMA_DONE_INT_MASK \ + 0x00000010 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_APPS_SPI_WR_DMA_DONE_INT_MASK \ + 0x00000008 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_APPS_SPI_RD_DMA_DONE_INT_MASK \ + 0x00000004 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SDIOM_WR_DMA_DONE_INT_MASK \ + 0x00000002 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SDIOM_RD_DMA_DONE_INT_MASK \ + 0x00000001 // 1= disable corresponding + // interrupt;0 = interrupt enabled + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_MASK_SET register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_ADC_WR_DMA_DONE_INT_MASK_SET_M \ + 0x0000F000 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect bit 14: ADC channel 7 DMA + // Done IRQ bit 13: ADC channel 5 + // DMA Done IRQ bit 12: ADC channel + // 3 DMA Done IRQ bit 11: ADC + // channel 1 DMA Done IRQ + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_ADC_WR_DMA_DONE_INT_MASK_SET_S 12 +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_MCASP_WR_DMA_DONE_INT_MASK_SET \ + 0x00000800 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_MCASP_RD_DMA_DONE_INT_MASK_SET \ + 0x00000400 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_CAM_FIFO_EMPTY_DMA_DONE_INT_MASK_SET \ + 0x00000200 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_CAM_THRESHHOLD_DMA_DONE_INT_MASK_SET \ + 0x00000100 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_SHSPI_WR_DMA_DONE_INT_MASK_SET \ + 0x00000080 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_SHSPI_RD_DMA_DONE_INT_MASK_SET \ + 0x00000040 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_HOSTSPI_WR_DMA_DONE_INT_MASK_SET \ + 0x00000020 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_HOSTSPI_RD_DMA_DONE_INT_MASK_SET \ + 0x00000010 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_APPS_SPI_WR_DMA_DONE_INT_MASK_SET \ + 0x00000008 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_APPS_SPI_RD_DMA_DONE_INT_MASK_SET \ + 0x00000004 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_SDIOM_WR_DMA_DONE_INT_MASK_SET \ + 0x00000002 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_SET_SDIOM_RD_DMA_DONE_INT_MASK_SET \ + 0x00000001 // write 1 to set mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_ADC_WR_DMA_DONE_INT_MASK_CLR_M \ + 0x0000F000 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect bit 14: ADC channel 7 DMA + // Done IRQ mask bit 13: ADC channel + // 5 DMA Done IRQ mask bit 12: ADC + // channel 3 DMA Done IRQ mask bit + // 11: ADC channel 1 DMA Done IRQ + // mask + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_ADC_WR_DMA_DONE_INT_MASK_CLR_S 12 +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_MACASP_WR_DMA_DONE_INT_MASK_CLR \ + 0x00000800 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_MCASP_RD_DMA_DONE_INT_MASK_CLR \ + 0x00000400 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_CAM_FIFO_EMPTY_DMA_DONE_INT_MASK_CLR \ + 0x00000200 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_CAM_THRESHHOLD_DMA_DONE_INT_MASK_CLR \ + 0x00000100 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_SHSPI_WR_DMA_DONE_INT_MASK_CLR \ + 0x00000080 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_SHSPI_RD_DMA_DONE_INT_MASK_CLR \ + 0x00000040 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_HOSTSPI_WR_DMA_DONE_INT_MASK_CLR \ + 0x00000020 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_HOSTSPI_RD_DMA_DONE_INT_MASK_CLR \ + 0x00000010 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_APPS_SPI_WR_DMA_DONE_INT_MASK_CLR \ + 0x00000008 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_APPS_SPI_RD_DMA_DONE_INT_MASK_CLR \ + 0x00000004 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_SDIOM_WR_DMA_DONE_INT_MASK_CLR \ + 0x00000002 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +#define APPS_CONFIG_DMA_DONE_INT_MASK_CLR_SDIOM_RD_DMA_DONE_INT_MASK_CLR \ + 0x00000001 // write 1 to clear mask of the + // corresponding DMA DONE IRQ;0 = no + // effect + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_STS_CLR register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_STS_CLR_DMA_INT_STS_CLR_M \ + 0xFFFFFFFF // write 1 or 0 to clear all + // DMA_DONE interrupt; + +#define APPS_CONFIG_DMA_DONE_INT_STS_CLR_DMA_INT_STS_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_ACK register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_ACK_ADC_WR_DMA_DONE_INT_ACK_M \ + 0x0000F000 // write 1 to clear corresponding + // interrupt; 0 = no effect; bit 14: + // ADC channel 7 DMA Done IRQ bit + // 13: ADC channel 5 DMA Done IRQ + // bit 12: ADC channel 3 DMA Done + // IRQ bit 11: ADC channel 1 DMA + // Done IRQ + +#define APPS_CONFIG_DMA_DONE_INT_ACK_ADC_WR_DMA_DONE_INT_ACK_S 12 +#define APPS_CONFIG_DMA_DONE_INT_ACK_MCASP_WR_DMA_DONE_INT_ACK \ + 0x00000800 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_MCASP_RD_DMA_DONE_INT_ACK \ + 0x00000400 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_CAM_FIFO_EMPTY_DMA_DONE_INT_ACK \ + 0x00000200 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_CAM_THRESHHOLD_DMA_DONE_INT_ACK \ + 0x00000100 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_SHSPI_WR_DMA_DONE_INT_ACK \ + 0x00000080 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_SHSPI_RD_DMA_DONE_INT_ACK \ + 0x00000040 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_HOSTSPI_WR_DMA_DONE_INT_ACK \ + 0x00000020 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_HOSTSPI_RD_DMA_DONE_INT_ACK \ + 0x00000010 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_APPS_SPI_WR_DMA_DONE_INT_ACK \ + 0x00000008 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_APPS_SPI_RD_DMA_DONE_INT_ACK \ + 0x00000004 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_SDIOM_WR_DMA_DONE_INT_ACK \ + 0x00000002 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +#define APPS_CONFIG_DMA_DONE_INT_ACK_SDIOM_RD_DMA_DONE_INT_ACK \ + 0x00000001 // write 1 to clear corresponding + // interrupt; 0 = no effect; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_ADC_WR_DMA_DONE_INT_STS_MASKED_M \ + 0x0000F000 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask bit 14: ADC + // channel 7 DMA Done IRQ bit 13: + // ADC channel 5 DMA Done IRQ bit + // 12: ADC channel 3 DMA Done IRQ + // bit 11: ADC channel 1 DMA Done + // IRQ + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_ADC_WR_DMA_DONE_INT_STS_MASKED_S 12 +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_MCASP_WR_DMA_DONE_INT_STS_MASKED \ + 0x00000800 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_MCASP_RD_DMA_DONE_INT_STS_MASKED \ + 0x00000400 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_CAM_FIFO_EMPTY_DMA_DONE_INT_STS_MASKED \ + 0x00000200 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_CAM_THRESHHOLD_DMA_DONE_INT_STS_MASKED \ + 0x00000100 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_SHSPI_WR_DMA_DONE_INT_STS_MASKED \ + 0x00000080 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_SHSPI_RD_DMA_DONE_INT_STS_MASKED \ + 0x00000040 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_HOSTSPI_WR_DMA_DONE_INT_STS_MASKED \ + 0x00000020 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_HOSTSPI_RD_DMA_DONE_INT_STS_MASKED \ + 0x00000010 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_APPS_SPI_WR_DMA_DONE_INT_STS_MASKED \ + 0x00000008 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_APPS_SPI_RD_DMA_DONE_INT_STS_MASKED \ + 0x00000004 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_SDIOM_WR_DMA_DONE_INT_STS_MASKED \ + 0x00000002 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +#define APPS_CONFIG_DMA_DONE_INT_STS_MASKED_SDIOM_RD_DMA_DONE_INT_STS_MASKED \ + 0x00000001 // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by DMA_DONE_INT mask + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_DMA_DONE_INT_STS_RAW register. +// +//****************************************************************************** +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_ADC_WR_DMA_DONE_INT_STS_RAW_M \ + 0x0000F000 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive bit 14: ADC channel 7 + // DMA Done IRQ bit 13: ADC channel + // 5 DMA Done IRQ bit 12: ADC + // channel 3 DMA Done IRQ bit 11: + // ADC channel 1 DMA Done IRQ + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_ADC_WR_DMA_DONE_INT_STS_RAW_S 12 +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_MCASP_WR_DMA_DONE_INT_STS_RAW \ + 0x00000800 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_MCASP_RD_DMA_DONE_INT_STS_RAW \ + 0x00000400 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_CAM_EPMTY_FIFO_DMA_DONE_INT_STS_RAW \ + 0x00000200 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_CAM_THRESHHOLD_DMA_DONE_INT_STS_RAW \ + 0x00000100 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_SHSPI_WR_DMA_DONE_INT_STS_RAW \ + 0x00000080 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_SHSPI_RD_DMA_DONE_INT_STS_RAW \ + 0x00000040 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_HOSTSPI_WR_DMA_DONE_INT_STS_RAW \ + 0x00000020 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_HOSTSPI_RD_DMA_DONE_INT_STS_RAW \ + 0x00000010 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_APPS_SPI_WR_DMA_DONE_INT_STS_RAW \ + 0x00000008 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_APPS_SPI_RD_DMA_DONE_INT_STS_RAW \ + 0x00000004 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_SDIOM_WR_DMA_DONE_INT_STS_RAW \ + 0x00000002 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define APPS_CONFIG_DMA_DONE_INT_STS_RAW_SDIOM_RD_DMA_DONE_INT_STS_RAW \ + 0x00000001 // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_FAULT_STATUS_CLR_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_FAULT_STATUS_CLR_REG_PATCH_ERR_CLR \ + 0x00000001 // Write 1 to clear the LSB of + // FAULT_STATUS_REG + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_RESERVD_REG_0 register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_GPT_TRIG_SEL register. +// +//****************************************************************************** +#define APPS_CONFIG_GPT_TRIG_SEL_GPT_TRIG_SEL_M \ + 0x000000FF // This bit is implemented for GPT + // trigger mode select. GPT IP + // support 2 modes: RTC mode and + // external trigger. When this bit + // is set to logic '1': enable + // external trigger mode for APPS + // GPT CP0 and CP1 pin. bit 0: when + // set '1' enable external GPT + // trigger 0 on GPIO0 CP0 pin else + // RTC mode is selected. bit 1: when + // set '1' enable external GPT + // trigger 1 on GPIO0 CP1 pin else + // RTC mode is selected. bit 2: when + // set '1' enable external GPT + // trigger 2 on GPIO1 CP0 pin else + // RTC mode is selected. bit 3: when + // set '1' enable external GPT + // trigger 3 on GPIO1 CP1 pin else + // RTC mode is selected. bit 4: when + // set '1' enable external GPT + // trigger 4 on GPIO2 CP0 pin else + // RTC mode is selected. bit 5: when + // set '1' enable external GPT + // trigger 5 on GPIO2 CP1 pin else + // RTC mode is selected. bit 6: when + // set '1' enable external GPT + // trigger 6 on GPIO3 CP0 pin else + // RTC mode is selected. bit 7: when + // set '1' enable external GPT + // trigger 7 on GPIO3 CP1 pin else + // RTC mode is selected. + +#define APPS_CONFIG_GPT_TRIG_SEL_GPT_TRIG_SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_TOP_DIE_SPARE_DIN_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_TOP_DIE_SPARE_DIN_REG_D2D_SPARE_DIN_M \ + 0x00000007 // Capture data from d2d_spare pads + +#define APPS_CONFIG_TOP_DIE_SPARE_DIN_REG_D2D_SPARE_DIN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_CONFIG_O_TOP_DIE_SPARE_DOUT_REG register. +// +//****************************************************************************** +#define APPS_CONFIG_TOP_DIE_SPARE_DOUT_REG_D2D_SPARE_DOUT_M \ + 0x00000007 // Send data to d2d_spare pads - + // eventually this will get + // registered in top die + +#define APPS_CONFIG_TOP_DIE_SPARE_DOUT_REG_D2D_SPARE_DOUT_S 0 + + + +#endif // __HW_APPS_CONFIG_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_rcm.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_rcm.h new file mode 100755 index 0000000..edb52d2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_apps_rcm.h @@ -0,0 +1,1506 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_APPS_RCM_H__ +#define __HW_APPS_RCM_H__ + +//***************************************************************************** +// +// The following are defines for the APPS_RCM register offsets. +// +//***************************************************************************** +#define APPS_RCM_O_CAMERA_CLK_GEN \ + 0x00000000 + +#define APPS_RCM_O_CAMERA_CLK_GATING \ + 0x00000004 + +#define APPS_RCM_O_CAMERA_SOFT_RESET \ + 0x00000008 + +#define APPS_RCM_O_MCASP_CLK_GATING \ + 0x00000014 + +#define APPS_RCM_O_MCASP_SOFT_RESET \ + 0x00000018 + +#define APPS_RCM_O_MMCHS_CLK_GEN \ + 0x00000020 + +#define APPS_RCM_O_MMCHS_CLK_GATING \ + 0x00000024 + +#define APPS_RCM_O_MMCHS_SOFT_RESET \ + 0x00000028 + +#define APPS_RCM_O_MCSPI_A1_CLK_GEN \ + 0x0000002C + +#define APPS_RCM_O_MCSPI_A1_CLK_GATING \ + 0x00000030 + +#define APPS_RCM_O_MCSPI_A1_SOFT_RESET \ + 0x00000034 + +#define APPS_RCM_O_MCSPI_A2_CLK_GEN \ + 0x00000038 + +#define APPS_RCM_O_MCSPI_A2_CLK_GATING \ + 0x00000040 + +#define APPS_RCM_O_MCSPI_A2_SOFT_RESET \ + 0x00000044 + +#define APPS_RCM_O_UDMA_A_CLK_GATING \ + 0x00000048 + +#define APPS_RCM_O_UDMA_A_SOFT_RESET \ + 0x0000004C + +#define APPS_RCM_O_GPIO_A_CLK_GATING \ + 0x00000050 + +#define APPS_RCM_O_GPIO_A_SOFT_RESET \ + 0x00000054 + +#define APPS_RCM_O_GPIO_B_CLK_GATING \ + 0x00000058 + +#define APPS_RCM_O_GPIO_B_SOFT_RESET \ + 0x0000005C + +#define APPS_RCM_O_GPIO_C_CLK_GATING \ + 0x00000060 + +#define APPS_RCM_O_GPIO_C_SOFT_RESET \ + 0x00000064 + +#define APPS_RCM_O_GPIO_D_CLK_GATING \ + 0x00000068 + +#define APPS_RCM_O_GPIO_D_SOFT_RESET \ + 0x0000006C + +#define APPS_RCM_O_GPIO_E_CLK_GATING \ + 0x00000070 + +#define APPS_RCM_O_GPIO_E_SOFT_RESET \ + 0x00000074 + +#define APPS_RCM_O_WDOG_A_CLK_GATING \ + 0x00000078 + +#define APPS_RCM_O_WDOG_A_SOFT_RESET \ + 0x0000007C + +#define APPS_RCM_O_UART_A0_CLK_GATING \ + 0x00000080 + +#define APPS_RCM_O_UART_A0_SOFT_RESET \ + 0x00000084 + +#define APPS_RCM_O_UART_A1_CLK_GATING \ + 0x00000088 + +#define APPS_RCM_O_UART_A1_SOFT_RESET \ + 0x0000008C + +#define APPS_RCM_O_GPT_A0_CLK_GATING \ + 0x00000090 + +#define APPS_RCM_O_GPT_A0_SOFT_RESET \ + 0x00000094 + +#define APPS_RCM_O_GPT_A1_CLK_GATING \ + 0x00000098 + +#define APPS_RCM_O_GPT_A1_SOFT_RESET \ + 0x0000009C + +#define APPS_RCM_O_GPT_A2_CLK_GATING \ + 0x000000A0 + +#define APPS_RCM_O_GPT_A2_SOFT_RESET \ + 0x000000A4 + +#define APPS_RCM_O_GPT_A3_CLK_GATING \ + 0x000000A8 + +#define APPS_RCM_O_GPT_A3_SOFT_RESET \ + 0x000000AC + +#define APPS_RCM_O_MCASP_FRAC_CLK_CONFIG0 \ + 0x000000B0 + +#define APPS_RCM_O_MCASP_FRAC_CLK_CONFIG1 \ + 0x000000B4 + +#define APPS_RCM_O_CRYPTO_CLK_GATING \ + 0x000000B8 + +#define APPS_RCM_O_CRYPTO_SOFT_RESET \ + 0x000000BC + +#define APPS_RCM_O_MCSPI_S0_CLK_GATING \ + 0x000000C8 + +#define APPS_RCM_O_MCSPI_S0_SOFT_RESET \ + 0x000000CC + +#define APPS_RCM_O_MCSPI_S0_CLKDIV_CFG \ + 0x000000D0 + +#define APPS_RCM_O_I2C_CLK_GATING \ + 0x000000D8 + +#define APPS_RCM_O_I2C_SOFT_RESET \ + 0x000000DC + +#define APPS_RCM_O_APPS_LPDS_REQ \ + 0x000000E4 + +#define APPS_RCM_O_APPS_TURBO_REQ \ + 0x000000EC + +#define APPS_RCM_O_APPS_DSLP_WAKE_CONFIG \ + 0x00000108 + +#define APPS_RCM_O_APPS_DSLP_WAKE_TIMER_CFG \ + 0x0000010C + +#define APPS_RCM_O_APPS_RCM_SLP_WAKE_ENABLE \ + 0x00000110 + +#define APPS_RCM_O_APPS_SLP_WAKETIMER_CFG \ + 0x00000114 + +#define APPS_RCM_O_APPS_TO_NWP_WAKE_REQUEST \ + 0x00000118 + +#define APPS_RCM_O_APPS_RCM_INTERRUPT_STATUS \ + 0x00000120 + +#define APPS_RCM_O_APPS_RCM_INTERRUPT_ENABLE \ + 0x00000124 + + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_CAMERA_CLK_GEN register. +// +//****************************************************************************** +#define APPS_RCM_CAMERA_CLK_GEN_CAMERA_PLLCKDIV_OFF_TIME_M \ + 0x00000700 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of Camera func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_CAMERA_CLK_GEN_CAMERA_PLLCKDIV_OFF_TIME_S 8 +#define APPS_RCM_CAMERA_CLK_GEN_NU1_M \ + 0x000000F8 + +#define APPS_RCM_CAMERA_CLK_GEN_NU1_S 3 +#define APPS_RCM_CAMERA_CLK_GEN_CAMERA_PLLCKDIV_ON_TIME_M \ + 0x00000007 // Configuration of ON-TIME for + // dividing PLL clk (240 MHz) in + // generation of Camera func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_CAMERA_CLK_GEN_CAMERA_PLLCKDIV_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_CAMERA_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_CAMERA_CLK_GATING_NU1_M \ + 0x00FE0000 + +#define APPS_RCM_CAMERA_CLK_GATING_NU1_S 17 +#define APPS_RCM_CAMERA_CLK_GATING_CAMERA_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable camera clk during + // deep-sleep mode + +#define APPS_RCM_CAMERA_CLK_GATING_NU2_M \ + 0x0000FE00 + +#define APPS_RCM_CAMERA_CLK_GATING_NU2_S 9 +#define APPS_RCM_CAMERA_CLK_GATING_CAMERA_SLP_CLK_ENABLE \ + 0x00000100 // 1- Enable camera clk during + // sleep mode ; 0- Disable camera + // clk during sleep mode + +#define APPS_RCM_CAMERA_CLK_GATING_NU3_M \ + 0x000000FE + +#define APPS_RCM_CAMERA_CLK_GATING_NU3_S 1 +#define APPS_RCM_CAMERA_CLK_GATING_CAMERA_RUN_CLK_ENABLE \ + 0x00000001 // 1- Enable camera clk during run + // mode ; 0- Disable camera clk + // during run mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_CAMERA_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_CAMERA_SOFT_RESET_CAMERA_ENABLED_STATUS \ + 0x00000002 // 1 - Camera clocks/resets are + // enabled ; 0 - Camera + // clocks/resets are disabled + +#define APPS_RCM_CAMERA_SOFT_RESET_CAMERA_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for Camera-core + // ; 0 - De-assert reset for + // Camera-core + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCASP_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_MCASP_CLK_GATING_NU1_M \ + 0x00FE0000 + +#define APPS_RCM_MCASP_CLK_GATING_NU1_S 17 +#define APPS_RCM_MCASP_CLK_GATING_MCASP_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable MCASP clk during + // deep-sleep mode + +#define APPS_RCM_MCASP_CLK_GATING_NU2_M \ + 0x0000FE00 + +#define APPS_RCM_MCASP_CLK_GATING_NU2_S 9 +#define APPS_RCM_MCASP_CLK_GATING_MCASP_SLP_CLK_ENABLE \ + 0x00000100 // 1- Enable MCASP clk during sleep + // mode ; 0- Disable MCASP clk + // during sleep mode + +#define APPS_RCM_MCASP_CLK_GATING_NU3_M \ + 0x000000FE + +#define APPS_RCM_MCASP_CLK_GATING_NU3_S 1 +#define APPS_RCM_MCASP_CLK_GATING_MCASP_RUN_CLK_ENABLE \ + 0x00000001 // 1- Enable MCASP clk during run + // mode ; 0- Disable MCASP clk + // during run mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCASP_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_MCASP_SOFT_RESET_MCASP_ENABLED_STATUS \ + 0x00000002 // 1 - MCASP Clocks/resets are + // enabled ; 0 - MCASP Clocks/resets + // are disabled + +#define APPS_RCM_MCASP_SOFT_RESET_MCASP_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for MCASP-core + // ; 0 - De-assert reset for + // MCASP-core + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MMCHS_CLK_GEN register. +// +//****************************************************************************** +#define APPS_RCM_MMCHS_CLK_GEN_MMCHS_PLLCKDIV_OFF_TIME_M \ + 0x00000700 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of MMCHS func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MMCHS_CLK_GEN_MMCHS_PLLCKDIV_OFF_TIME_S 8 +#define APPS_RCM_MMCHS_CLK_GEN_NU1_M \ + 0x000000F8 + +#define APPS_RCM_MMCHS_CLK_GEN_NU1_S 3 +#define APPS_RCM_MMCHS_CLK_GEN_MMCHS_PLLCKDIV_ON_TIME_M \ + 0x00000007 // Configuration of ON-TIME for + // dividing PLL clk (240 MHz) in + // generation of MMCHS func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MMCHS_CLK_GEN_MMCHS_PLLCKDIV_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MMCHS_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_MMCHS_CLK_GATING_NU1_M \ + 0x00FE0000 + +#define APPS_RCM_MMCHS_CLK_GATING_NU1_S 17 +#define APPS_RCM_MMCHS_CLK_GATING_MMCHS_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable MMCHS clk during + // deep-sleep mode + +#define APPS_RCM_MMCHS_CLK_GATING_NU2_M \ + 0x0000FE00 + +#define APPS_RCM_MMCHS_CLK_GATING_NU2_S 9 +#define APPS_RCM_MMCHS_CLK_GATING_MMCHS_SLP_CLK_ENABLE \ + 0x00000100 // 1- Enable MMCHS clk during sleep + // mode ; 0- Disable MMCHS clk + // during sleep mode + +#define APPS_RCM_MMCHS_CLK_GATING_NU3_M \ + 0x000000FE + +#define APPS_RCM_MMCHS_CLK_GATING_NU3_S 1 +#define APPS_RCM_MMCHS_CLK_GATING_MMCHS_RUN_CLK_ENABLE \ + 0x00000001 // 1- Enable MMCHS clk during run + // mode ; 0- Disable MMCHS clk + // during run mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MMCHS_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_MMCHS_SOFT_RESET_MMCHS_ENABLED_STATUS \ + 0x00000002 // 1 - MMCHS Clocks/resets are + // enabled ; 0 - MMCHS Clocks/resets + // are disabled + +#define APPS_RCM_MMCHS_SOFT_RESET_MMCHS_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for MMCHS-core + // ; 0 - De-assert reset for + // MMCHS-core + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A1_CLK_GEN register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A1_CLK_GEN_MCSPI_A1_BAUD_CLK_SEL \ + 0x00010000 // 0 - XTAL clk is used as baud clk + // for MCSPI_A1 ; 1 - PLL divclk is + // used as baud clk for MCSPI_A1. + +#define APPS_RCM_MCSPI_A1_CLK_GEN_NU1_M \ + 0x0000F800 + +#define APPS_RCM_MCSPI_A1_CLK_GEN_NU1_S 11 +#define APPS_RCM_MCSPI_A1_CLK_GEN_MCSPI_A1_PLLCLKDIV_OFF_TIME_M \ + 0x00000700 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_A1 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_A1_CLK_GEN_MCSPI_A1_PLLCLKDIV_OFF_TIME_S 8 +#define APPS_RCM_MCSPI_A1_CLK_GEN_NU2_M \ + 0x000000F8 + +#define APPS_RCM_MCSPI_A1_CLK_GEN_NU2_S 3 +#define APPS_RCM_MCSPI_A1_CLK_GEN_MCSPI_A1_PLLCLKDIV_ON_TIME_M \ + 0x00000007 // Configuration of ON-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_A1 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_A1_CLK_GEN_MCSPI_A1_PLLCLKDIV_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A1_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU1_M \ + 0x00FE0000 + +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU1_S 17 +#define APPS_RCM_MCSPI_A1_CLK_GATING_MCSPI_A1_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable MCSPI_A1 clk during + // deep-sleep mode + +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU2_M \ + 0x0000FE00 + +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU2_S 9 +#define APPS_RCM_MCSPI_A1_CLK_GATING_MCSPI_A1_SLP_CLK_ENABLE \ + 0x00000100 // 1- Enable MCSPI_A1 clk during + // sleep mode ; 0- Disable MCSPI_A1 + // clk during sleep mode + +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU3_M \ + 0x000000FE + +#define APPS_RCM_MCSPI_A1_CLK_GATING_NU3_S 1 +#define APPS_RCM_MCSPI_A1_CLK_GATING_MCSPI_A1_RUN_CLK_ENABLE \ + 0x00000001 // 1- Enable MCSPI_A1 clk during + // run mode ; 0- Disable MCSPI_A1 + // clk during run mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A1_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A1_SOFT_RESET_MCSPI_A1_ENABLED_STATUS \ + 0x00000002 // 1 - MCSPI_A1 Clocks/Resets are + // enabled ; 0 - MCSPI_A1 + // Clocks/Resets are disabled + +#define APPS_RCM_MCSPI_A1_SOFT_RESET_MCSPI_A1_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for + // MCSPI_A1-core ; 0 - De-assert + // reset for MCSPI_A1-core + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A2_CLK_GEN register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A2_CLK_GEN_MCSPI_A2_BAUD_CLK_SEL \ + 0x00010000 // 0 - XTAL clk is used as baud-clk + // for MCSPI_A2 ; 1 - PLL divclk is + // used as baud-clk for MCSPI_A2 + +#define APPS_RCM_MCSPI_A2_CLK_GEN_NU1_M \ + 0x0000F800 + +#define APPS_RCM_MCSPI_A2_CLK_GEN_NU1_S 11 +#define APPS_RCM_MCSPI_A2_CLK_GEN_MCSPI_A2_PLLCKDIV_OFF_TIME_M \ + 0x00000700 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_A2 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_A2_CLK_GEN_MCSPI_A2_PLLCKDIV_OFF_TIME_S 8 +#define APPS_RCM_MCSPI_A2_CLK_GEN_NU2_M \ + 0x000000F8 + +#define APPS_RCM_MCSPI_A2_CLK_GEN_NU2_S 3 +#define APPS_RCM_MCSPI_A2_CLK_GEN_MCSPI_A2_PLLCKDIV_ON_TIME_M \ + 0x00000007 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_A2 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_A2_CLK_GEN_MCSPI_A2_PLLCKDIV_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A2_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU1_M \ + 0x00FE0000 + +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU1_S 17 +#define APPS_RCM_MCSPI_A2_CLK_GATING_MCSPI_A2_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable MCSPI_A2 clk during + // deep-sleep mode + +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU2_M \ + 0x0000FE00 + +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU2_S 9 +#define APPS_RCM_MCSPI_A2_CLK_GATING_MCSPI_A2_SLP_CLK_ENABLE \ + 0x00000100 // 1- Enable MCSPI_A2 clk during + // sleep mode ; 0- Disable MCSPI_A2 + // clk during sleep mode + +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU3_M \ + 0x000000FE + +#define APPS_RCM_MCSPI_A2_CLK_GATING_NU3_S 1 +#define APPS_RCM_MCSPI_A2_CLK_GATING_MCSPI_A2_RUN_CLK_ENABLE \ + 0x00000001 // 1- Enable MCSPI_A2 clk during + // run mode ; 0- Disable MCSPI_A2 + // clk during run mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_A2_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_A2_SOFT_RESET_MCSPI_A2_ENABLED_STATUS \ + 0x00000002 // 1 - MCSPI_A2 Clocks/Resets are + // enabled ; 0 - MCSPI_A2 + // Clocks/Resets are disabled + +#define APPS_RCM_MCSPI_A2_SOFT_RESET_MCSPI_A2_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for + // MCSPI_A2-core ; 0 - De-assert + // reset for MCSPI_A2-core + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UDMA_A_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_UDMA_A_CLK_GATING_UDMA_A_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable UDMA_A clk during + // deep-sleep mode 0 - Disable + // UDMA_A clk during deep-sleep mode + // ; + +#define APPS_RCM_UDMA_A_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_UDMA_A_CLK_GATING_NU1_S 9 +#define APPS_RCM_UDMA_A_CLK_GATING_UDMA_A_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable UDMA_A clk during + // sleep mode 0 - Disable UDMA_A clk + // during sleep mode ; + +#define APPS_RCM_UDMA_A_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_UDMA_A_CLK_GATING_NU2_S 1 +#define APPS_RCM_UDMA_A_CLK_GATING_UDMA_A_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable UDMA_A clk during run + // mode 0 - Disable UDMA_A clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UDMA_A_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_UDMA_A_SOFT_RESET_UDMA_A_ENABLED_STATUS \ + 0x00000002 // 1 - UDMA_A Clocks/Resets are + // enabled ; 0 - UDMA_A + // Clocks/Resets are disabled + +#define APPS_RCM_UDMA_A_SOFT_RESET_UDMA_A_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for DMA_A ; 0 - + // De-assert reset for DMA_A + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_A_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_A_CLK_GATING_GPIO_A_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable GPIO_A clk during + // deep-sleep mode 0 - Disable + // GPIO_A clk during deep-sleep mode + // ; + +#define APPS_RCM_GPIO_A_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPIO_A_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPIO_A_CLK_GATING_GPIO_A_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable GPIO_A clk during + // sleep mode 0 - Disable GPIO_A clk + // during sleep mode ; + +#define APPS_RCM_GPIO_A_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPIO_A_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPIO_A_CLK_GATING_GPIO_A_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable GPIO_A clk during run + // mode 0 - Disable GPIO_A clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_A_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_A_SOFT_RESET_GPIO_A_ENABLED_STATUS \ + 0x00000002 // 1 - GPIO_A Clocks/Resets are + // enabled ; 0 - GPIO_A + // Clocks/Resets are disabled + +#define APPS_RCM_GPIO_A_SOFT_RESET_GPIO_A_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for GPIO_A ; 0 + // - De-assert reset for GPIO_A + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_B_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_B_CLK_GATING_GPIO_B_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable GPIO_B clk during + // deep-sleep mode 0 - Disable + // GPIO_B clk during deep-sleep mode + // ; + +#define APPS_RCM_GPIO_B_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPIO_B_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPIO_B_CLK_GATING_GPIO_B_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable GPIO_B clk during + // sleep mode 0 - Disable GPIO_B clk + // during sleep mode ; + +#define APPS_RCM_GPIO_B_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPIO_B_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPIO_B_CLK_GATING_GPIO_B_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable GPIO_B clk during run + // mode 0 - Disable GPIO_B clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_B_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_B_SOFT_RESET_GPIO_B_ENABLED_STATUS \ + 0x00000002 // 1 - GPIO_B Clocks/Resets are + // enabled ; 0 - GPIO_B + // Clocks/Resets are disabled + +#define APPS_RCM_GPIO_B_SOFT_RESET_GPIO_B_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for GPIO_B ; 0 + // - De-assert reset for GPIO_B + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_C_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_C_CLK_GATING_GPIO_C_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable GPIO_C clk during + // deep-sleep mode 0 - Disable + // GPIO_C clk during deep-sleep mode + // ; + +#define APPS_RCM_GPIO_C_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPIO_C_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPIO_C_CLK_GATING_GPIO_C_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable GPIO_C clk during + // sleep mode 0 - Disable GPIO_C clk + // during sleep mode ; + +#define APPS_RCM_GPIO_C_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPIO_C_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPIO_C_CLK_GATING_GPIO_C_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable GPIO_C clk during run + // mode 0 - Disable GPIO_C clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_C_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_C_SOFT_RESET_GPIO_C_ENABLED_STATUS \ + 0x00000002 // 1 - GPIO_C Clocks/Resets are + // enabled ; 0 - GPIO_C + // Clocks/Resets are disabled + +#define APPS_RCM_GPIO_C_SOFT_RESET_GPIO_C_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for GPIO_C ; 0 + // - De-assert reset for GPIO_C + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_D_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_D_CLK_GATING_GPIO_D_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable GPIO_D clk during + // deep-sleep mode 0 - Disable + // GPIO_D clk during deep-sleep mode + // ; + +#define APPS_RCM_GPIO_D_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPIO_D_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPIO_D_CLK_GATING_GPIO_D_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable GPIO_D clk during + // sleep mode 0 - Disable GPIO_D clk + // during sleep mode ; + +#define APPS_RCM_GPIO_D_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPIO_D_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPIO_D_CLK_GATING_GPIO_D_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable GPIO_D clk during run + // mode 0 - Disable GPIO_D clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_D_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_D_SOFT_RESET_GPIO_D_ENABLED_STATUS \ + 0x00000002 // 1 - GPIO_D Clocks/Resets are + // enabled ; 0 - GPIO_D + // Clocks/Resets are disabled + +#define APPS_RCM_GPIO_D_SOFT_RESET_GPIO_D_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for GPIO_D ; 0 + // - De-assert reset for GPIO_D + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_E_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_E_CLK_GATING_GPIO_E_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable GPIO_E clk during + // deep-sleep mode 0 - Disable + // GPIO_E clk during deep-sleep mode + // ; + +#define APPS_RCM_GPIO_E_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPIO_E_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPIO_E_CLK_GATING_GPIO_E_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable GPIO_E clk during + // sleep mode 0 - Disable GPIO_E clk + // during sleep mode ; + +#define APPS_RCM_GPIO_E_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPIO_E_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPIO_E_CLK_GATING_GPIO_E_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable GPIO_E clk during run + // mode 0 - Disable GPIO_E clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPIO_E_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPIO_E_SOFT_RESET_GPIO_E_ENABLED_STATUS \ + 0x00000002 // 1 - GPIO_E Clocks/Resets are + // enabled ; 0 - GPIO_E + // Clocks/Resets are disabled + +#define APPS_RCM_GPIO_E_SOFT_RESET_GPIO_E_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for GPIO_E ; 0 + // - De-assert reset for GPIO_E + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_WDOG_A_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_WDOG_A_CLK_GATING_WDOG_A_BAUD_CLK_SEL_M \ + 0x03000000 // "00" - Sysclk ; "01" - REF_CLK + // (38.4 MHz) ; "10/11" - Slow_clk + +#define APPS_RCM_WDOG_A_CLK_GATING_WDOG_A_BAUD_CLK_SEL_S 24 +#define APPS_RCM_WDOG_A_CLK_GATING_WDOG_A_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable WDOG_A clk during + // deep-sleep mode 0 - Disable + // WDOG_A clk during deep-sleep mode + // ; + +#define APPS_RCM_WDOG_A_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_WDOG_A_CLK_GATING_NU1_S 9 +#define APPS_RCM_WDOG_A_CLK_GATING_WDOG_A_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable WDOG_A clk during + // sleep mode 0 - Disable WDOG_A clk + // during sleep mode ; + +#define APPS_RCM_WDOG_A_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_WDOG_A_CLK_GATING_NU2_S 1 +#define APPS_RCM_WDOG_A_CLK_GATING_WDOG_A_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable WDOG_A clk during run + // mode 0 - Disable WDOG_A clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_WDOG_A_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_WDOG_A_SOFT_RESET_WDOG_A_ENABLED_STATUS \ + 0x00000002 // 1 - WDOG_A Clocks/Resets are + // enabled ; 0 - WDOG_A + // Clocks/Resets are disabled + +#define APPS_RCM_WDOG_A_SOFT_RESET_WDOG_A_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for WDOG_A ; 0 + // - De-assert reset for WDOG_A + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UART_A0_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_UART_A0_CLK_GATING_UART_A0_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable UART_A0 clk during + // deep-sleep mode 0 - Disable + // UART_A0 clk during deep-sleep + // mode ; + +#define APPS_RCM_UART_A0_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_UART_A0_CLK_GATING_NU1_S 9 +#define APPS_RCM_UART_A0_CLK_GATING_UART_A0_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable UART_A0 clk during + // sleep mode 0 - Disable UART_A0 + // clk during sleep mode ; + +#define APPS_RCM_UART_A0_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_UART_A0_CLK_GATING_NU2_S 1 +#define APPS_RCM_UART_A0_CLK_GATING_UART_A0_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable UART_A0 clk during + // run mode 0 - Disable UART_A0 clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UART_A0_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_UART_A0_SOFT_RESET_UART_A0_ENABLED_STATUS \ + 0x00000002 // 1 - UART_A0 Clocks/Resets are + // enabled ; 0 - UART_A0 + // Clocks/Resets are disabled + +#define APPS_RCM_UART_A0_SOFT_RESET_UART_A0_SOFT_RESET \ + 0x00000001 // 1 - Assert reset for UART_A0 ; 0 + // - De-assert reset for UART_A0 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UART_A1_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_UART_A1_CLK_GATING_UART_A1_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable UART_A1 clk during + // deep-sleep mode 0 - Disable + // UART_A1 clk during deep-sleep + // mode ; + +#define APPS_RCM_UART_A1_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_UART_A1_CLK_GATING_NU1_S 9 +#define APPS_RCM_UART_A1_CLK_GATING_UART_A1_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable UART_A1 clk during + // sleep mode 0 - Disable UART_A1 + // clk during sleep mode ; + +#define APPS_RCM_UART_A1_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_UART_A1_CLK_GATING_NU2_S 1 +#define APPS_RCM_UART_A1_CLK_GATING_UART_A1_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable UART_A1 clk during + // run mode 0 - Disable UART_A1 clk + // during run mode ; + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_UART_A1_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_UART_A1_SOFT_RESET_UART_A1_ENABLED_STATUS \ + 0x00000002 // 1 - UART_A1 Clocks/Resets are + // enabled ; 0 - UART_A1 + // Clocks/Resets are disabled + +#define APPS_RCM_UART_A1_SOFT_RESET_UART_A1_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // UART_A1 ; 0 - De-assert the soft + // reset for UART_A1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A0_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A0_CLK_GATING_GPT_A0_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable the GPT_A0 clock + // during deep-sleep ; 0 - Disable + // the GPT_A0 clock during + // deep-sleep + +#define APPS_RCM_GPT_A0_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPT_A0_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPT_A0_CLK_GATING_GPT_A0_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the GPT_A0 clock + // during sleep ; 0 - Disable the + // GPT_A0 clock during sleep + +#define APPS_RCM_GPT_A0_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPT_A0_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPT_A0_CLK_GATING_GPT_A0_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the GPT_A0 clock + // during run ; 0 - Disable the + // GPT_A0 clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A0_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A0_SOFT_RESET_GPT_A0_ENABLED_STATUS \ + 0x00000002 // 1 - GPT_A0 clocks/resets are + // enabled ; 0 - GPT_A0 + // clocks/resets are disabled + +#define APPS_RCM_GPT_A0_SOFT_RESET_GPT_A0_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // GPT_A0 ; 0 - De-assert the soft + // reset for GPT_A0 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A1_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A1_CLK_GATING_GPT_A1_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable the GPT_A1 clock + // during deep-sleep ; 0 - Disable + // the GPT_A1 clock during + // deep-sleep + +#define APPS_RCM_GPT_A1_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPT_A1_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPT_A1_CLK_GATING_GPT_A1_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the GPT_A1 clock + // during sleep ; 0 - Disable the + // GPT_A1 clock during sleep + +#define APPS_RCM_GPT_A1_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPT_A1_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPT_A1_CLK_GATING_GPT_A1_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the GPT_A1 clock + // during run ; 0 - Disable the + // GPT_A1 clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A1_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A1_SOFT_RESET_GPT_A1_ENABLED_STATUS \ + 0x00000002 // 1 - GPT_A1 clocks/resets are + // enabled ; 0 - GPT_A1 + // clocks/resets are disabled + +#define APPS_RCM_GPT_A1_SOFT_RESET_GPT_A1_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // GPT_A1 ; 0 - De-assert the soft + // reset for GPT_A1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A2_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A2_CLK_GATING_GPT_A2_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable the GPT_A2 clock + // during deep-sleep ; 0 - Disable + // the GPT_A2 clock during + // deep-sleep + +#define APPS_RCM_GPT_A2_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPT_A2_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPT_A2_CLK_GATING_GPT_A2_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the GPT_A2 clock + // during sleep ; 0 - Disable the + // GPT_A2 clock during sleep + +#define APPS_RCM_GPT_A2_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPT_A2_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPT_A2_CLK_GATING_GPT_A2_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the GPT_A2 clock + // during run ; 0 - Disable the + // GPT_A2 clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A2_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A2_SOFT_RESET_GPT_A2_ENABLED_STATUS \ + 0x00000002 // 1 - GPT_A2 clocks/resets are + // enabled ; 0 - GPT_A2 + // clocks/resets are disabled + +#define APPS_RCM_GPT_A2_SOFT_RESET_GPT_A2_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // GPT_A2 ; 0 - De-assert the soft + // reset for GPT_A2 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A3_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A3_CLK_GATING_GPT_A3_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable the GPT_A3 clock + // during deep-sleep ; 0 - Disable + // the GPT_A3 clock during + // deep-sleep + +#define APPS_RCM_GPT_A3_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_GPT_A3_CLK_GATING_NU1_S 9 +#define APPS_RCM_GPT_A3_CLK_GATING_GPT_A3_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the GPT_A3 clock + // during sleep ; 0 - Disable the + // GPT_A3 clock during sleep + +#define APPS_RCM_GPT_A3_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_GPT_A3_CLK_GATING_NU2_S 1 +#define APPS_RCM_GPT_A3_CLK_GATING_GPT_A3_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the GPT_A3 clock + // during run ; 0 - Disable the + // GPT_A3 clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_GPT_A3_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_GPT_A3_SOFT_RESET_GPT_A3_ENABLED_STATUS \ + 0x00000002 // 1 - GPT_A3 Clocks/resets are + // enabled ; 0 - GPT_A3 + // Clocks/resets are disabled + +#define APPS_RCM_GPT_A3_SOFT_RESET_GPT_A3_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // GPT_A3 ; 0 - De-assert the soft + // reset for GPT_A3 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCASP_FRAC_CLK_CONFIG0 register. +// +//****************************************************************************** +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG0_MCASP_FRAC_DIV_DIVISOR_M \ + 0x03FF0000 + +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG0_MCASP_FRAC_DIV_DIVISOR_S 16 +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG0_MCASP_FRAC_DIV_FRACTION_M \ + 0x0000FFFF + +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG0_MCASP_FRAC_DIV_FRACTION_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCASP_FRAC_CLK_CONFIG1 register. +// +//****************************************************************************** +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG1_MCASP_FRAC_DIV_SOFT_RESET \ + 0x00010000 // 1 - Assert the reset for MCASP + // Frac-clk div; 0 - Donot assert + // the reset for MCASP frac clk-div + +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG1_MCASP_FRAC_DIV_PERIOD_M \ + 0x000003FF + +#define APPS_RCM_MCASP_FRAC_CLK_CONFIG1_MCASP_FRAC_DIV_PERIOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_CRYPTO_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_CRYPTO_CLK_GATING_CRYPTO_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable the Crypto clock + // during deep-sleep + +#define APPS_RCM_CRYPTO_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_CRYPTO_CLK_GATING_NU1_S 9 +#define APPS_RCM_CRYPTO_CLK_GATING_CRYPTO_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the Crypto clock + // during sleep ; 0 - Disable the + // Crypto clock during sleep + +#define APPS_RCM_CRYPTO_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_CRYPTO_CLK_GATING_NU2_S 1 +#define APPS_RCM_CRYPTO_CLK_GATING_CRYPTO_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the Crypto clock + // during run ; 0 - Disable the + // Crypto clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_CRYPTO_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_CRYPTO_SOFT_RESET_CRYPTO_ENABLED_STATUS \ + 0x00000002 // 1 - Crypto clocks/resets are + // enabled ; 0 - Crypto + // clocks/resets are disabled + +#define APPS_RCM_CRYPTO_SOFT_RESET_CRYPTO_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // Crypto ; 0 - De-assert the soft + // reset for Crypto + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_S0_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_S0_CLK_GATING_MCSPI_S0_DSLP_CLK_ENABLE \ + 0x00010000 // 0 - Disable the MCSPI_S0 clock + // during deep-sleep + +#define APPS_RCM_MCSPI_S0_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_MCSPI_S0_CLK_GATING_NU1_S 9 +#define APPS_RCM_MCSPI_S0_CLK_GATING_MCSPI_S0_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the MCSPI_S0 clock + // during sleep ; 0 - Disable the + // MCSPI_S0 clock during sleep + +#define APPS_RCM_MCSPI_S0_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_MCSPI_S0_CLK_GATING_NU2_S 1 +#define APPS_RCM_MCSPI_S0_CLK_GATING_MCSPI_S0_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the MCSPI_S0 clock + // during run ; 0 - Disable the + // MCSPI_S0 clock during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_S0_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_S0_SOFT_RESET_MCSPI_S0_ENABLED_STATUS \ + 0x00000002 // 1 - MCSPI_S0 Clocks/Resets are + // enabled ; 0 - MCSPI_S0 + // Clocks/resets are disabled + +#define APPS_RCM_MCSPI_S0_SOFT_RESET_MCSPI_S0_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // MCSPI_S0 ; 0 - De-assert the soft + // reset for MCSPI_S0 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_MCSPI_S0_CLKDIV_CFG register. +// +//****************************************************************************** +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_MCSPI_S0_BAUD_CLK_SEL \ + 0x00010000 // 0 - XTAL clk is used as baud-clk + // for MCSPI_S0 ; 1 - PLL divclk is + // used as buad-clk for MCSPI_S0 + +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_NU1_M \ + 0x0000F800 + +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_NU1_S 11 +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_MCSPI_S0_PLLCLKDIV_OFF_TIME_M \ + 0x00000700 // Configuration of OFF-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_S0 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_MCSPI_S0_PLLCLKDIV_OFF_TIME_S 8 +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_NU2_M \ + 0x000000F8 + +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_NU2_S 3 +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_MCSPI_S0_PLLCLKDIV_ON_TIME_M \ + 0x00000007 // Configuration of ON-TIME for + // dividing PLL clk (240 MHz) in + // generation of MCSPI_S0 func-clk : + // "000" - 1 "001" - 2 "010" - 3 + // "011" - 4 "100" - 5 "101" - 6 + // "110" - 7 "111" - 8 + +#define APPS_RCM_MCSPI_S0_CLKDIV_CFG_MCSPI_S0_PLLCLKDIV_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_I2C_CLK_GATING register. +// +//****************************************************************************** +#define APPS_RCM_I2C_CLK_GATING_I2C_DSLP_CLK_ENABLE \ + 0x00010000 // 1 - Enable the I2C Clock during + // deep-sleep 0 - Disable the I2C + // clock during deep-sleep + +#define APPS_RCM_I2C_CLK_GATING_NU1_M \ + 0x0000FE00 + +#define APPS_RCM_I2C_CLK_GATING_NU1_S 9 +#define APPS_RCM_I2C_CLK_GATING_I2C_SLP_CLK_ENABLE \ + 0x00000100 // 1 - Enable the I2C clock during + // sleep ; 0 - Disable the I2C clock + // during sleep + +#define APPS_RCM_I2C_CLK_GATING_NU2_M \ + 0x000000FE + +#define APPS_RCM_I2C_CLK_GATING_NU2_S 1 +#define APPS_RCM_I2C_CLK_GATING_I2C_RUN_CLK_ENABLE \ + 0x00000001 // 1 - Enable the I2C clock during + // run ; 0 - Disable the I2C clock + // during run + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_I2C_SOFT_RESET register. +// +//****************************************************************************** +#define APPS_RCM_I2C_SOFT_RESET_I2C_ENABLED_STATUS \ + 0x00000002 // 1 - I2C Clocks/Resets are + // enabled ; 0 - I2C clocks/resets + // are disabled + +#define APPS_RCM_I2C_SOFT_RESET_I2C_SOFT_RESET \ + 0x00000001 // 1 - Assert the soft reset for + // Shared-I2C ; 0 - De-assert the + // soft reset for Shared-I2C + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_LPDS_REQ register. +// +//****************************************************************************** +#define APPS_RCM_APPS_LPDS_REQ_APPS_LPDS_REQ \ + 0x00000001 // 1 - Request for LPDS + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_TURBO_REQ register. +// +//****************************************************************************** +#define APPS_RCM_APPS_TURBO_REQ_APPS_TURBO_REQ \ + 0x00000001 // 1 - Request for TURBO + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_DSLP_WAKE_CONFIG register. +// +//****************************************************************************** +#define APPS_RCM_APPS_DSLP_WAKE_CONFIG_DSLP_WAKE_FROM_NWP_ENABLE \ + 0x00000002 // 1 - Enable the NWP to wake APPS + // from deep-sleep ; 0 - Disable NWP + // to wake APPS from deep-sleep + +#define APPS_RCM_APPS_DSLP_WAKE_CONFIG_DSLP_WAKE_TIMER_ENABLE \ + 0x00000001 // 1 - Enable deep-sleep wake timer + // in APPS RCM for deep-sleep; 0 - + // Disable deep-sleep wake timer in + // APPS RCM + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_DSLP_WAKE_TIMER_CFG register. +// +//****************************************************************************** +#define APPS_RCM_APPS_DSLP_WAKE_TIMER_CFG_DSLP_WAKE_TIMER_OPP_CFG_M \ + 0xFFFF0000 // Configuration (in slow_clks) + // which says when to request for + // OPP during deep-sleep exit + +#define APPS_RCM_APPS_DSLP_WAKE_TIMER_CFG_DSLP_WAKE_TIMER_OPP_CFG_S 16 +#define APPS_RCM_APPS_DSLP_WAKE_TIMER_CFG_DSLP_WAKE_TIMER_WAKE_CFG_M \ + 0x0000FFFF // Configuration (in slow_clks) + // which says when to request for + // WAKE during deep-sleep exit + +#define APPS_RCM_APPS_DSLP_WAKE_TIMER_CFG_DSLP_WAKE_TIMER_WAKE_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_RCM_SLP_WAKE_ENABLE register. +// +//****************************************************************************** +#define APPS_RCM_APPS_RCM_SLP_WAKE_ENABLE_SLP_WAKE_FROM_NWP_ENABLE \ + 0x00000002 // 1- Enable the sleep wakeup due + // to NWP request. 0- Disable the + // sleep wakeup due to NWP request + +#define APPS_RCM_APPS_RCM_SLP_WAKE_ENABLE_SLP_WAKE_TIMER_ENABLE \ + 0x00000001 // 1- Enable the sleep wakeup due + // to sleep-timer; 0-Disable the + // sleep wakeup due to sleep-timer + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_SLP_WAKETIMER_CFG register. +// +//****************************************************************************** +#define APPS_RCM_APPS_SLP_WAKETIMER_CFG_SLP_WAKE_TIMER_CFG_M \ + 0xFFFFFFFF // Configuration (number of + // sysclks-80MHz) for the Sleep + // wakeup timer + +#define APPS_RCM_APPS_SLP_WAKETIMER_CFG_SLP_WAKE_TIMER_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_TO_NWP_WAKE_REQUEST register. +// +//****************************************************************************** +#define APPS_RCM_APPS_TO_NWP_WAKE_REQUEST_APPS_TO_NWP_WAKEUP_REQUEST \ + 0x00000001 // When 1 => APPS generated a wake + // request to NWP (When NWP is in + // any of its low-power modes : + // SLP/DSLP/LPDS) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// APPS_RCM_O_APPS_RCM_INTERRUPT_STATUS register. +// +//****************************************************************************** +#define APPS_RCM_APPS_RCM_INTERRUPT_STATUS_apps_deep_sleep_timer_wake \ + 0x00000008 // 1 - Indicates that deep-sleep + // timer expiry had caused the + // wakeup from deep-sleep + +#define APPS_RCM_APPS_RCM_INTERRUPT_STATUS_apps_sleep_timer_wake \ + 0x00000004 // 1 - Indicates that sleep timer + // expiry had caused the wakeup from + // sleep + +#define APPS_RCM_APPS_RCM_INTERRUPT_STATUS_apps_deep_sleep_wake_from_nwp \ + 0x00000002 // 1 - Indicates that NWP had + // caused the wakeup from deep-sleep + +#define APPS_RCM_APPS_RCM_INTERRUPT_STATUS_apps_sleep_wake_from_nwp \ + 0x00000001 // 1 - Indicates that NWP had + // caused the wakeup from Sleep + + + + +#endif // __HW_APPS_RCM_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_camera.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_camera.h new file mode 100755 index 0000000..4461a28 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_camera.h @@ -0,0 +1,519 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_CAMERA_H__ +#define __HW_CAMERA_H__ + +//***************************************************************************** +// +// The following are defines for the CAMERA register offsets. +// +//***************************************************************************** +#define CAMERA_O_CC_REVISION 0x00000000 // This register contains the IP + // revision code ( Parallel Mode) +#define CAMERA_O_CC_SYSCONFIG 0x00000010 // This register controls the + // various parameters of the OCP + // interface (CCP and Parallel Mode) +#define CAMERA_O_CC_SYSSTATUS 0x00000014 // This register provides status + // information about the module + // excluding the interrupt status + // information (CCP and Parallel + // Mode) +#define CAMERA_O_CC_IRQSTATUS 0x00000018 // The interrupt status regroups + // all the status of the module + // internal events that can generate + // an interrupt (CCP & Parallel + // Mode) +#define CAMERA_O_CC_IRQENABLE 0x0000001C // The interrupt enable register + // allows to enable/disable the + // module internal sources of + // interrupt on an event-by-event + // basis (CCP & Parallel Mode) +#define CAMERA_O_CC_CTRL 0x00000040 // This register controls the + // various parameters of the Camera + // Core block (CCP & Parallel Mode) +#define CAMERA_O_CC_CTRL_DMA 0x00000044 // This register controls the DMA + // interface of the Camera Core + // block (CCP & Parallel Mode) +#define CAMERA_O_CC_CTRL_XCLK 0x00000048 // This register control the value + // of the clock divisor used to + // generate the external clock + // (Parallel Mode) +#define CAMERA_O_CC_FIFO_DATA 0x0000004C // This register allows to write to + // the FIFO and read from the FIFO + // (CCP & Parallel Mode) +#define CAMERA_O_CC_TEST 0x00000050 // This register shows the status + // of some important variables of + // the camera core module (CCP & + // Parallel Mode) +#define CAMERA_O_CC_GEN_PAR 0x00000054 // This register shows the values + // of the generic parameters of the + // module + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_REVISION register. +// +//****************************************************************************** +#define CAMERA_CC_REVISION_REV_M \ + 0x000000FF // IP revision [7:4] Major revision + // [3:0] Minor revision Examples: + // 0x10 for 1.0 0x21 for 2.1 + +#define CAMERA_CC_REVISION_REV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_SYSCONFIG register. +// +//****************************************************************************** +#define CAMERA_CC_SYSCONFIG_S_IDLE_MODE_M \ + 0x00000018 // Slave interface power management + // req/ack control """00"" + // Force-idle. An idle request is + // acknoledged unconditionally" + // """01"" No-idle. An idle request + // is never acknowledged" """10"" + // reserved (Smart-idle not + // implemented)" + +#define CAMERA_CC_SYSCONFIG_S_IDLE_MODE_S 3 +#define CAMERA_CC_SYSCONFIG_SOFT_RESET \ + 0x00000002 // Software reset. Set this bit to + // 1 to trigger a module reset. The + // bit is automatically reset by the + // hardware. During reset it always + // returns 0. 0 Normal mode 1 The + // module is reset + +#define CAMERA_CC_SYSCONFIG_AUTO_IDLE \ + 0x00000001 // Internal OCP clock gating + // strategy 0 OCP clock is + // free-running 1 Automatic OCP + // clock gating strategy is applied + // based on the OCP interface + // activity + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_SYSSTATUS register. +// +//****************************************************************************** +#define CAMERA_CC_SYSSTATUS_RESET_DONE2 \ + 0x00000001 // Internal Reset Monitoring 0 + // Internal module reset is on-going + // 1 Reset completed + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_IRQSTATUS register. +// +//****************************************************************************** +#define CAMERA_CC_IRQSTATUS_FS_IRQ \ + 0x00080000 // Frame Start has occurred 0 Event + // false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_LE_IRQ \ + 0x00040000 // Line End has occurred 0 Event + // false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_LS_IRQ \ + 0x00020000 // Line Start has occurred 0 Event + // false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_FE_IRQ \ + 0x00010000 // Frame End has occurred 0 Event + // false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_FSP_ERR_IRQ \ + 0x00000800 // FSP code error 0 Event false "1 + // Event is true (""pending"")" 0 + // Event status bit unchanged 1 + // Event status bit is reset + +#define CAMERA_CC_IRQSTATUS_FW_ERR_IRQ \ + 0x00000400 // Frame Height Error 0 Event false + // "1 Event is true (""pending"")" 0 + // Event status bit unchanged 1 + // Event status bit is reset + +#define CAMERA_CC_IRQSTATUS_FSC_ERR_IRQ \ + 0x00000200 // False Synchronization Code 0 + // Event false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_SSC_ERR_IRQ \ + 0x00000100 // Shifted Synchronization Code 0 + // Event false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_FIFO_NONEMPTY_IRQ \ + 0x00000010 // FIFO is not empty 0 Event false + // "1 Event is true (""pending"")" 0 + // Event status bit unchanged 1 + // Event status bit is reset + +#define CAMERA_CC_IRQSTATUS_FIFO_FULL_IRQ \ + 0x00000008 // FIFO is full 0 Event false "1 + // Event is true (""pending"")" 0 + // Event status bit unchanged 1 + // Event status bit is reset + +#define CAMERA_CC_IRQSTATUS_FIFO_THR_IRQ \ + 0x00000004 // FIFO threshold has been reached + // 0 Event false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_FIFO_OF_IRQ \ + 0x00000002 // FIFO overflow has occurred 0 + // Event false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +#define CAMERA_CC_IRQSTATUS_FIFO_UF_IRQ \ + 0x00000001 // FIFO underflow has occurred 0 + // Event false "1 Event is true + // (""pending"")" 0 Event status bit + // unchanged 1 Event status bit is + // reset + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_IRQENABLE register. +// +//****************************************************************************** +#define CAMERA_CC_IRQENABLE_FS_IRQ_EN \ + 0x00080000 // Frame Start Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_LE_IRQ_EN \ + 0x00040000 // Line End Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_LS_IRQ_EN \ + 0x00020000 // Line Start Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_FE_IRQ_EN \ + 0x00010000 // Frame End Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_FSP_IRQ_EN \ + 0x00000800 // FSP code Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_FW_ERR_IRQ_EN \ + 0x00000400 // Frame Height Error Interrupt + // Enable 0 Event is masked 1 Event + // generates an interrupt when it + // occurs + +#define CAMERA_CC_IRQENABLE_FSC_ERR_IRQ_EN \ + 0x00000200 // False Synchronization Code + // Interrupt Enable 0 Event is + // masked 1 Event generates an + // interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_SSC_ERR_IRQ_EN \ + 0x00000100 // False Synchronization Code + // Interrupt Enable 0 Event is + // masked 1 Event generates an + // interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_FIFO_NONEMPTY_IRQ_EN \ + 0x00000010 // FIFO Threshold Interrupt Enable + // 0 Event is masked 1 Event + // generates an interrupt when it + // occurs + +#define CAMERA_CC_IRQENABLE_FIFO_FULL_IRQ_EN \ + 0x00000008 // FIFO Threshold Interrupt Enable + // 0 Event is masked 1 Event + // generates an interrupt when it + // occurs + +#define CAMERA_CC_IRQENABLE_FIFO_THR_IRQ_EN \ + 0x00000004 // FIFO Threshold Interrupt Enable + // 0 Event is masked 1 Event + // generates an interrupt when it + // occurs + +#define CAMERA_CC_IRQENABLE_FIFO_OF_IRQ_EN \ + 0x00000002 // FIFO Overflow Interrupt Enable 0 + // Event is masked 1 Event generates + // an interrupt when it occurs + +#define CAMERA_CC_IRQENABLE_FIFO_UF_IRQ_EN \ + 0x00000001 // FIFO Underflow Interrupt Enable + // 0 Event is masked 1 Event + // generates an interrupt when it + // occurs + +//****************************************************************************** +// +// The following are defines for the bit fields in the CAMERA_O_CC_CTRL register. +// +//****************************************************************************** +#define CAMERA_CC_CTRL_CC_IF_SYNCHRO \ + 0x00080000 // Synchronize all camera sensor + // inputs This must be set during + // the configuration phase before + // CC_EN set to '1'. This can be + // used in very high frequency to + // avoid dependancy to the IO + // timings. 0 No synchro (most of + // applications) 1 Synchro enabled + // (should never be required) + +#define CAMERA_CC_CTRL_CC_RST 0x00040000 // Resets all the internal finite + // states machines of the camera + // core module - by writing a 1 to + // this bit. must be applied when + // CC_EN = 0 Reads returns 0 +#define CAMERA_CC_CTRL_CC_FRAME_TRIG \ + 0x00020000 // Set the modality in which CC_EN + // works when a disabling of the + // sensor camera core is wanted "If + // CC_FRAME_TRIG = 1 by writing + // ""0"" to CC_EN" the module is + // disabled at the end of the frame + // "If CC_FRAME_TRIG = 0 by writing + // ""0"" to CC_EN" the module is + // disabled immediately + +#define CAMERA_CC_CTRL_CC_EN 0x00010000 // Enables the sensor interface of + // the camera core module "By + // writing ""1"" to this field the + // module is enabled." "By writing + // ""0"" to this field the module is + // disabled at" the end of the frame + // if CC_FRAM_TRIG =1 and is + // disabled immediately if + // CC_FRAM_TRIG = 0 +#define CAMERA_CC_CTRL_NOBT_SYNCHRO \ + 0x00002000 // Enables to start at the + // beginning of the frame or not in + // NoBT 0 Acquisition starts when + // Vertical synchro is high 1 + // Acquisition starts when Vertical + // synchro goes from low to high + // (beginning of the frame) - + // Recommended. + +#define CAMERA_CC_CTRL_BT_CORRECT \ + 0x00001000 // Enables the correction within + // the sync codes in BT mode 0 + // correction is not enabled 1 + // correction is enabled + +#define CAMERA_CC_CTRL_PAR_ORDERCAM \ + 0x00000800 // Enables swap between image-data + // in parallel mode 0 swap is not + // enabled 1 swap is enabled + +#define CAMERA_CC_CTRL_PAR_CLK_POL \ + 0x00000400 // Inverts the clock coming from + // the sensor in parallel mode 0 + // clock not inverted - data sampled + // on rising edge 1 clock inverted - + // data sampled on falling edge + +#define CAMERA_CC_CTRL_NOBT_HS_POL \ + 0x00000200 // Sets the polarity of the + // synchronization signals in NOBT + // parallel mode 0 CAM_P_HS is + // active high 1 CAM_P_HS is active + // low + +#define CAMERA_CC_CTRL_NOBT_VS_POL \ + 0x00000100 // Sets the polarity of the + // synchronization signals in NOBT + // parallel mode 0 CAM_P_VS is + // active high 1 CAM_P_VS is active + // low + +#define CAMERA_CC_CTRL_PAR_MODE_M \ + 0x0000000E // Sets the Protocol Mode of the + // Camera Core module in parallel + // mode (when CCP_MODE = 0) """000"" + // Parallel NOBT 8-bit" """001"" + // Parallel NOBT 10-bit" """010"" + // Parallel NOBT 12-bit" """011"" + // reserved" """100"" Parallet BT + // 8-bit" """101"" Parallel BT + // 10-bit" """110"" reserved" + // """111"" FIFO test mode. Refer to + // Table 12 - FIFO Write and Read + // access" + +#define CAMERA_CC_CTRL_PAR_MODE_S 1 +#define CAMERA_CC_CTRL_CCP_MODE 0x00000001 // Set the Camera Core in CCP mode + // 0 CCP mode disabled 1 CCP mode + // enabled +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_CTRL_DMA register. +// +//****************************************************************************** +#define CAMERA_CC_CTRL_DMA_DMA_EN \ + 0x00000100 // Sets the number of dma request + // lines 0 DMA interface disabled + // The DMA request line stays + // inactive 1 DMA interface enabled + // The DMA request line is + // operational + +#define CAMERA_CC_CTRL_DMA_FIFO_THRESHOLD_M \ + 0x0000007F // Sets the threshold of the FIFO + // the assertion of the dmarequest + // line takes place when the + // threshold is reached. + // """0000000"" threshold set to 1" + // """0000001"" threshold set to 2" + // … """1111111"" threshold set to + // 128" + +#define CAMERA_CC_CTRL_DMA_FIFO_THRESHOLD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_CTRL_XCLK register. +// +//****************************************************************************** +#define CAMERA_CC_CTRL_XCLK_XCLK_DIV_M \ + 0x0000001F // Sets the clock divisor value for + // CAM_XCLK generation. based on + // CAM_MCK (value of CAM_MCLK is + // 96MHz) """00000"" CAM_XCLK Stable + // Low Level" Divider not enabled + // """00001"" CAM_XCLK Stable High + // Level" Divider not enabled from 2 + // to 30 CAM_XCLK = CAM_MCLK / + // XCLK_DIV """11111"" Bypass - + // CAM_XCLK = CAM_MCLK" + +#define CAMERA_CC_CTRL_XCLK_XCLK_DIV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_FIFO_DATA register. +// +//****************************************************************************** +#define CAMERA_CC_FIFO_DATA_FIFO_DATA_M \ + 0xFFFFFFFF // Writes the 32-bit word into the + // FIFO Reads the 32-bit word from + // the FIFO + +#define CAMERA_CC_FIFO_DATA_FIFO_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the CAMERA_O_CC_TEST register. +// +//****************************************************************************** +#define CAMERA_CC_TEST_FIFO_RD_POINTER_M \ + 0xFF000000 // FIFO READ Pointer This field + // shows the value of the FIFO read + // pointer Expected value ranges + // from 0 to 127 + +#define CAMERA_CC_TEST_FIFO_RD_POINTER_S 24 +#define CAMERA_CC_TEST_FIFO_WR_POINTER_M \ + 0x00FF0000 // FIFO WRITE pointer This field + // shows the value of the FIFO write + // pointer Expected value ranges + // from 0 to 127 + +#define CAMERA_CC_TEST_FIFO_WR_POINTER_S 16 +#define CAMERA_CC_TEST_FIFO_LEVEL_M \ + 0x0000FF00 // FIFO level (how many 32-bit + // words the FIFO contains) This + // field shows the value of the FIFO + // level and can assume values from + // 0 to 128 + +#define CAMERA_CC_TEST_FIFO_LEVEL_S 8 +#define CAMERA_CC_TEST_FIFO_LEVEL_PEAK_M \ + 0x000000FF // FIFO level peak This field shows + // the max value of the FIFO level + // and can assume values from 0 to + // 128 + +#define CAMERA_CC_TEST_FIFO_LEVEL_PEAK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// CAMERA_O_CC_GEN_PAR register. +// +//****************************************************************************** +#define CAMERA_CC_GEN_PAR_CC_FIFO_DEPTH_M \ + 0x00000007 // Camera Core FIFO DEPTH generic + // parameter + +#define CAMERA_CC_GEN_PAR_CC_FIFO_DEPTH_S 0 + + + +#endif // __HW_CAMERA_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_common_reg.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_common_reg.h new file mode 100755 index 0000000..417544a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_common_reg.h @@ -0,0 +1,1117 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_COMMON_REG_H__ +#define __HW_COMMON_REG_H__ + +//***************************************************************************** +// +// The following are defines for the COMMON_REG register offsets. +// +//***************************************************************************** +#define COMMON_REG_O_I2C_Properties_Register \ + 0x00000000 + +#define COMMON_REG_O_SPI_Properties_Register \ + 0x00000004 + +#define COMMON_REG_O_APPS_sh_resource_Interrupt_enable \ + 0x0000000C + +#define COMMON_REG_O_APPS_sh_resource_Interrupt_status \ + 0x00000010 + +#define COMMON_REG_O_NWP_sh_resource_Interrupt_enable \ + 0x00000014 + +#define COMMON_REG_O_NWP_sh_resource_Interrupt_status \ + 0x00000018 + +#define COMMON_REG_O_Flash_ctrl_reg \ + 0x0000001C + +#define COMMON_REG_O_Bus_matrix_M0_segment_access_config \ + 0x00000024 + +#define COMMON_REG_O_Bus_matrix_M1_segment_access_config \ + 0x00000028 + +#define COMMON_REG_O_Bus_matrix_M2_segment_access_config \ + 0x0000002C + +#define COMMON_REG_O_Bus_matrix_M3_segment_access_config \ + 0x00000030 + +#define COMMON_REG_O_Bus_matrix_M4_segment_access_config \ + 0x00000034 + +#define COMMON_REG_O_Bus_matrix_M5_segment_access_config \ + 0x00000038 + +#define COMMON_REG_O_GPIO_properties_register \ + 0x0000003C + +#define COMMON_REG_O_APPS_NW_SEMAPHORE1 \ + 0x00000040 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE2 \ + 0x00000044 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE3 \ + 0x00000048 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE4 \ + 0x0000004C + +#define COMMON_REG_O_APPS_NW_SEMAPHORE5 \ + 0x00000050 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE6 \ + 0x00000054 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE7 \ + 0x00000058 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE8 \ + 0x0000005C + +#define COMMON_REG_O_APPS_NW_SEMAPHORE9 \ + 0x00000060 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE10 \ + 0x00000064 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE11 \ + 0x00000068 + +#define COMMON_REG_O_APPS_NW_SEMAPHORE12 \ + 0x0000006C + +#define COMMON_REG_O_APPS_SEMAPPHORE_PEND \ + 0x00000070 + +#define COMMON_REG_O_NW_SEMAPPHORE_PEND \ + 0x00000074 + +#define COMMON_REG_O_SEMAPHORE_STATUS \ + 0x00000078 + +#define COMMON_REG_O_IDMEM_TIM_Update \ + 0x0000007C + +#define COMMON_REG_O_FPGA_ROM_WR_EN \ + 0x00000080 + +#define COMMON_REG_O_NW_INT_MASK \ + 0x00000084 + +#define COMMON_REG_O_NW_INT_MASK_SET \ + 0x00000088 + +#define COMMON_REG_O_NW_INT_MASK_CLR \ + 0x0000008C + +#define COMMON_REG_O_NW_INT_STS_CLR \ + 0x00000090 + +#define COMMON_REG_O_NW_INT_ACK 0x00000094 +#define COMMON_REG_O_NW_INT_TRIG \ + 0x00000098 + +#define COMMON_REG_O_NW_INT_STS_MASKED \ + 0x0000009C + +#define COMMON_REG_O_NW_INT_STS_RAW \ + 0x000000A0 + +#define COMMON_REG_O_APPS_INT_MASK \ + 0x000000A4 + +#define COMMON_REG_O_APPS_INT_MASK_SET \ + 0x000000A8 + +#define COMMON_REG_O_APPS_INT_MASK_CLR \ + 0x000000AC + +#define COMMON_REG_O_APPS_INT_STS_CLR \ + 0x000000B0 + +#define COMMON_REG_O_APPS_INT_ACK \ + 0x000000B4 + +#define COMMON_REG_O_APPS_INT_TRIG \ + 0x000000B8 + +#define COMMON_REG_O_APPS_INT_STS_MASKED \ + 0x000000BC + +#define COMMON_REG_O_APPS_INT_STS_RAW \ + 0x000000C0 + +#define COMMON_REG_O_IDMEM_TIM_Updated \ + 0x000000C4 + +#define COMMON_REG_O_APPS_GPIO_TRIG_EN \ + 0x000000C8 + +#define COMMON_REG_O_EMU_DEBUG_REG \ + 0x000000CC + +#define COMMON_REG_O_SEMAPHORE_STATUS2 \ + 0x000000D0 + +#define COMMON_REG_O_SEMAPHORE_PREV_OWNER1 \ + 0x000000D4 + +#define COMMON_REG_O_SEMAPHORE_PREV_OWNER2 \ + 0x000000D8 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_I2C_Properties_Register register. +// +//****************************************************************************** +#define COMMON_REG_I2C_Properties_Register_I2C_Properties_Register_M \ + 0x00000003 // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_I2C_Properties_Register_I2C_Properties_Register_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_SPI_Properties_Register register. +// +//****************************************************************************** +#define COMMON_REG_SPI_Properties_Register_SPI_Properties_Register_M \ + 0x00000003 // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_SPI_Properties_Register_SPI_Properties_Register_S 0 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_sh_resource_Interrupt_enable register. +// +//****************************************************************************** +#define COMMON_REG_APPS_sh_resource_Interrupt_enable_APPS_sh_resource_Interrupt_enable_M \ + 0x0000000F // Interrupt enable APPS bit 0 -> + // when '1' enable I2C interrupt bit + // 1 -> when '1' enable SPI + // interrupt bit 3 -> + // when '1' enable GPIO interrupt + +#define COMMON_REG_APPS_sh_resource_Interrupt_enable_APPS_sh_resource_Interrupt_enable_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_sh_resource_Interrupt_status register. +// +//****************************************************************************** +#define COMMON_REG_APPS_sh_resource_Interrupt_status_APPS_sh_resource_Interrupt_status_M \ + 0x0000000F // Interrupt enable APPS bit 0 -> + // when '1' enable I2C interrupt bit + // 1 -> when '1' enable SPI + // interrupt bit 3 -> + // when '1' enable GPIO interrupt + +#define COMMON_REG_APPS_sh_resource_Interrupt_status_APPS_sh_resource_Interrupt_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NWP_sh_resource_Interrupt_enable register. +// +//****************************************************************************** +#define COMMON_REG_NWP_sh_resource_Interrupt_enable_NWP_sh_resource_Interrupt_enable_M \ + 0x0000000F // Interrupt enable NWP bit 0 -> + // when '1' enable I2C interrupt bit + // 1 -> when '1' enable SPI + // interrupt bit 3 -> + // when '1' enable GPIO interrupt + +#define COMMON_REG_NWP_sh_resource_Interrupt_enable_NWP_sh_resource_Interrupt_enable_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NWP_sh_resource_Interrupt_status register. +// +//****************************************************************************** +#define COMMON_REG_NWP_sh_resource_Interrupt_status_NWP_sh_resource_Interrupt_status_M \ + 0x0000000F // Interrupt enable NWP bit 0 -> + // when '1' enable I2C interrupt bit + // 1 -> when '1' enable SPI + // interrupt bit 3 -> + // when '1' enable GPIO interrupt + +#define COMMON_REG_NWP_sh_resource_Interrupt_status_NWP_sh_resource_Interrupt_status_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Flash_ctrl_reg register. +// +//****************************************************************************** +#define COMMON_REG_Flash_ctrl_reg_Flash_ctrl_reg_M \ + 0x00000003 // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_Flash_ctrl_reg_Flash_ctrl_reg_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M0_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M0_segment_access_config_Bus_matrix_M0_segment_access_config_M \ + 0x0003FFFF // Master 0 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M0_segment_access_config_Bus_matrix_M0_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M1_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M1_segment_access_config_Bus_matrix_M1_segment_access_config_M \ + 0x0003FFFF // Master 1 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M1_segment_access_config_Bus_matrix_M1_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M2_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M2_segment_access_config_Bus_matrix_M2_segment_access_config_M \ + 0x0003FFFF // Master 2 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M2_segment_access_config_Bus_matrix_M2_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M3_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M3_segment_access_config_Bus_matrix_M3_segment_access_config_M \ + 0x0003FFFF // Master 3 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M3_segment_access_config_Bus_matrix_M3_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M4_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M4_segment_access_config_Bus_matrix_M4_segment_access_config_M \ + 0x0003FFFF // Master 4 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M4_segment_access_config_Bus_matrix_M4_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_Bus_matrix_M5_segment_access_config register. +// +//****************************************************************************** +#define COMMON_REG_Bus_matrix_M5_segment_access_config_Bus_matrix_M5_segment_access_config_M \ + 0x0003FFFF // Master 5 control word matrix to + // each segment. Tieoff. Bit value 1 + // indicates segment is accesable. + +#define COMMON_REG_Bus_matrix_M5_segment_access_config_Bus_matrix_M5_segment_access_config_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_GPIO_properties_register register. +// +//****************************************************************************** +#define COMMON_REG_GPIO_properties_register_GPIO_properties_register_M \ + 0x000003FF // Shared GPIO configuration + // register. Bit [1:0] to configure + // GPIO0 Bit [3:2] to configure + // GPIO1 Bit [5:4] to configure + // GPIO2 Bit [7:6] to configure + // GPIO3 Bit [9:8] to configure + // GPIO4 each GPIO can be + // individully selected. When “00†+ // GPIO is free resource. When “01†+ // GPIO is APPS resource. When “10†+ // GPIO is NWP resource. Writing 11 + // doesnt have any affect, i.e. If + // one write only relevant gpio + // semaphore and other bits are 1s, + // it'll not disturb the other + // semaphore bits. For example : Say + // If NW wants to take control of + // gpio-1, one should write + // 10'b11_1111_1011 and if one wants + // to release it write + // 10'b11_1111_0011. + +#define COMMON_REG_GPIO_properties_register_GPIO_properties_register_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE1 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE1_APPS_NW_SEMAPHORE1_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE1_APPS_NW_SEMAPHORE1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE2 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE2_APPS_NW_SEMAPHORE2_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE2_APPS_NW_SEMAPHORE2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE3 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE3_APPS_NW_SEMAPHORE3_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE3_APPS_NW_SEMAPHORE3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE4 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE4_APPS_NW_SEMAPHORE4_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE4_APPS_NW_SEMAPHORE4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE5 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE5_APPS_NW_SEMAPHORE5_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE5_APPS_NW_SEMAPHORE5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE6 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE6_APPS_NW_SEMAPHORE6_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE6_APPS_NW_SEMAPHORE6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE7 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE7_APPS_NW_SEMAPHORE7_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE7_APPS_NW_SEMAPHORE7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE8 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE8_APPS_NW_SEMAPHORE8_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE8_APPS_NW_SEMAPHORE8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE9 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE9_APPS_NW_SEMAPHORE9_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE9_APPS_NW_SEMAPHORE9_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE10 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE10_APPS_NW_SEMAPHORE10_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE10_APPS_NW_SEMAPHORE10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE11 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE11_APPS_NW_SEMAPHORE11_M \ + 0xFFFFFFFF // • Each semaphore register is of + // 2 bit. • When this register is + // set to 2’b01 – Apps have access + // and when set to 2’b10 – NW have + // access. • Ideally both the master + // can modify any of this 2 bit, but + // assumption apps will write only + // 2’b01 or 2’b00 to this register + // and nw will write only 2’b10 or + // 2’b00. • Implementation is when + // any of the bit of this register + // is set, only next write + // allowedvis 2’b00 – Again + // assumption is one master will not + // write 2’b00 if other is already + // holding the semaphore. + +#define COMMON_REG_APPS_NW_SEMAPHORE11_APPS_NW_SEMAPHORE11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_NW_SEMAPHORE12 register. +// +//****************************************************************************** +#define COMMON_REG_APPS_NW_SEMAPHORE12_APPS_NW_SEMAPHORE12_M \ + 0xFFFFFFFF // APPS NW semaphore register - not + // reflected in status. + +#define COMMON_REG_APPS_NW_SEMAPHORE12_APPS_NW_SEMAPHORE12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_SEMAPPHORE_PEND register. +// +//****************************************************************************** +#define COMMON_REG_APPS_SEMAPPHORE_PEND_APPS_SEMAPPHORE_PEND_M \ + 0xFFFFFFFF // APPS SEMAPOHORE STATUS + +#define COMMON_REG_APPS_SEMAPPHORE_PEND_APPS_SEMAPPHORE_PEND_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_SEMAPPHORE_PEND register. +// +//****************************************************************************** +#define COMMON_REG_NW_SEMAPPHORE_PEND_NW_SEMAPPHORE_PEND_M \ + 0xFFFFFFFF // NW SEMAPHORE STATUS + +#define COMMON_REG_NW_SEMAPPHORE_PEND_NW_SEMAPPHORE_PEND_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_SEMAPHORE_STATUS register. +// +//****************************************************************************** +#define COMMON_REG_SEMAPHORE_STATUS_SEMAPHORE_STATUS_M \ + 0xFFFFFFFF // SEMAPHORE STATUS 9:8 :semaphore + // status of flash_control 7:6 + // :semaphore status of + // gpio_properties 5:4 + // :semaphore status of + // spi_propertie 1:0 :semaphore + // status of i2c_propertie + +#define COMMON_REG_SEMAPHORE_STATUS_SEMAPHORE_STATUS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_IDMEM_TIM_Update register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_FPGA_ROM_WR_EN register. +// +//****************************************************************************** +#define COMMON_REG_FPGA_ROM_WR_EN_FPGA_ROM_WR_EN \ + 0x00000001 // when '1' enables Write into + // IDMEM CORE ROM, APPS ROM, NWP ROM + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_MASK register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_MASK_NW_INT_MASK_M \ + 0xFFFFFFFF // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define COMMON_REG_NW_INT_MASK_NW_INT_MASK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_MASK_SET register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_MASK_SET_NW_INT_MASK_SET_M \ + 0xFFFFFFFF // write 1 to set corresponding bit + // in NW_INT_MASK;0 = no effect + +#define COMMON_REG_NW_INT_MASK_SET_NW_INT_MASK_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_MASK_CLR register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_MASK_CLR_NW_INT_MASK_CLR_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // bit in NW_INT_MASK;0 = no effect + +#define COMMON_REG_NW_INT_MASK_CLR_NW_INT_MASK_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_STS_CLR register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_STS_CLR_NW_INT_STS_CLR_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // interrupt; 0 = no effect; + // interrupt is not lost if coincide + // with write operation + +#define COMMON_REG_NW_INT_STS_CLR_NW_INT_STS_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_ACK register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_ACK_NW_INT_ACK_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // interrupt;0 = no effect + +#define COMMON_REG_NW_INT_ACK_NW_INT_ACK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_TRIG register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_TRIG_NW_INT_TRIG_M \ + 0xFFFFFFFF // Writing a 1 to a bit in this + // register causes the the Host CPU + // if enabled (not masked). This + // register is self-clearing. + // Writing 0 has no effect + +#define COMMON_REG_NW_INT_TRIG_NW_INT_TRIG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_STS_MASKED register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_STS_MASKED_NW_INT_STS_MASKED_M \ + 0xFFFFFFFF // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by NW_INT mask + +#define COMMON_REG_NW_INT_STS_MASKED_NW_INT_STS_MASKED_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_NW_INT_STS_RAW register. +// +//****************************************************************************** +#define COMMON_REG_NW_INT_STS_RAW_NW_INT_STS_RAW_M \ + 0xFFFFFFFF // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define COMMON_REG_NW_INT_STS_RAW_NW_INT_STS_RAW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_MASK register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_MASK_APPS_INT_MASK_M \ + 0xFFFFFFFF // 1= disable corresponding + // interrupt;0 = interrupt enabled + +#define COMMON_REG_APPS_INT_MASK_APPS_INT_MASK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_MASK_SET register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_MASK_SET_APPS_INT_MASK_SET_M \ + 0xFFFFFFFF // write 1 to set corresponding bit + // in APPS_INT_MASK;0 = no effect + +#define COMMON_REG_APPS_INT_MASK_SET_APPS_INT_MASK_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_MASK_CLR register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_MASK_CLR_APPS_INT_MASK_CLR_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // bit in APPS_INT_MASK;0 = no + // effect + +#define COMMON_REG_APPS_INT_MASK_CLR_APPS_INT_MASK_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_STS_CLR register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_STS_CLR_APPS_INT_STS_CLR_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // interrupt; 0 = no effect; + // interrupt is not lost if coincide + // with write operation + +#define COMMON_REG_APPS_INT_STS_CLR_APPS_INT_STS_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_ACK register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_ACK_APPS_INT_ACK_M \ + 0xFFFFFFFF // write 1 to clear corresponding + // interrupt;0 = no effect + +#define COMMON_REG_APPS_INT_ACK_APPS_INT_ACK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_TRIG register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_TRIG_APPS_INT_TRIG_M \ + 0xFFFFFFFF // Writing a 1 to a bit in this + // register causes the the Host CPU + // if enabled (not masked). This + // register is self-clearing. + // Writing 0 has no effect + +#define COMMON_REG_APPS_INT_TRIG_APPS_INT_TRIG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_STS_MASKED register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_STS_MASKED_APPS_INT_STS_MASKED_M \ + 0xFFFFFFFF // 1= corresponding interrupt is + // active and not masked. read is + // non-destructive;0 = corresponding + // interrupt is inactive or masked + // by APPS_INT mask + +#define COMMON_REG_APPS_INT_STS_MASKED_APPS_INT_STS_MASKED_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_INT_STS_RAW register. +// +//****************************************************************************** +#define COMMON_REG_APPS_INT_STS_RAW_APPS_INT_STS_RAW_M \ + 0xFFFFFFFF // 1= corresponding interrupt is + // active. read is non-destructive;0 + // = corresponding interrupt is + // inactive + +#define COMMON_REG_APPS_INT_STS_RAW_APPS_INT_STS_RAW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_IDMEM_TIM_Updated register. +// +//****************************************************************************** +#define COMMON_REG_IDMEM_TIM_Updated_TIM_UPDATED \ + 0x00000001 // toggle in this signal + // indicatesIDMEM_TIM_UPDATE + // register mentioned above is + // updated. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_APPS_GPIO_TRIG_EN register. +// +//****************************************************************************** +#define COMMON_REG_APPS_GPIO_TRIG_EN_APPS_GPIO_TRIG_EN_M \ + 0x0000001F // APPS GPIO Trigger EN control. + // Bit 0: when '1' enable GPIO 0 + // trigger. This bit enables trigger + // for all GPIO 0 pins (GPIO 0 to + // GPIO7). Bit 1: when '1' enable + // GPIO 1 trigger. This bit enables + // trigger for all GPIO 1 pins ( + // GPIO8 to GPIO15). Bit 2: when '1' + // enable GPIO 2 trigger. This bit + // enables trigger for all GPIO 2 + // pins (GPIO16 to GPIO23). Bit 3: + // when '1' enable GPIO 3 trigger. + // This bit enables trigger for all + // GPIO 3 pins (GPIO24 to GPIO31). + // Bit 4: when '1' enable GPIO 4 + // trigger. This bit enables trigger + // for all GPIO 4 pins.(GPIO32 to + // GPIO39) + +#define COMMON_REG_APPS_GPIO_TRIG_EN_APPS_GPIO_TRIG_EN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_EMU_DEBUG_REG register. +// +//****************************************************************************** +#define COMMON_REG_EMU_DEBUG_REG_EMU_DEBUG_REG_M \ + 0xFFFFFFFF // 0 th bit used for stalling APPS + // DMA and 1st bit is used for + // stalling NWP DMA for debug + // purpose. Other bits are unused. + +#define COMMON_REG_EMU_DEBUG_REG_EMU_DEBUG_REG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_SEMAPHORE_STATUS2 register. +// +//****************************************************************************** +#define COMMON_REG_SEMAPHORE_STATUS2_SEMPAPHORE_STATUS2_M \ + 0x00FFFFFF // SEMAPHORE STATUS 23:22 + // :semaphore status of + // apps_nw_semaphore11 21:20 + // :semaphore status of + // apps_nw_semaphore11 19:18 + // :semaphore status of + // apps_nw_semaphore10 17:16 + // :semaphore status of + // apps_nw_semaphore9 15:14 + // :semaphore status of + // apps_nw_semaphore8 13:12 + // :semaphore status of + // apps_nw_semaphore7 11:10 + // :semaphore status of + // apps_nw_semaphore6 9:8 :semaphore + // status of apps_nw_semaphore5 7:6 + // :semaphore status of + // apps_nw_semaphore4 5:4 :semaphore + // status of apps_nw_semaphore3 3:2 + // :semaphore status of + // apps_nw_semaphore2 1:0 :semaphore + // status of apps_nw_semaphore1 + +#define COMMON_REG_SEMAPHORE_STATUS2_SEMPAPHORE_STATUS2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_SEMAPHORE_PREV_OWNER1 register. +// +//****************************************************************************** +#define COMMON_REG_SEMAPHORE_PREV_OWNER1_SEMAPHORE_PREV_OWNER1_M \ + 0x0003FFFF // 1:0 : prvious owner of + // i2c_properties_reg[1:0] 3:2 : + // prvious owner of + // spi_properties_reg[1:0] 5:4 : + // prvious owner of + // gpio_properties_reg[1:0] 9:8 : + // prvious owner of + // gpio_properties_reg[3:2] 11:10 : + // prvious owner of + // gpio_properties_reg[5:4] 13:12 : + // prvious owner of + // gpio_properties_reg[7:6] 15:14 : + // prvious owner of + // gpio_properties_reg[9:8] 17:16 : + // prvious owner of + // flash_control_reg[1:0] + +#define COMMON_REG_SEMAPHORE_PREV_OWNER1_SEMAPHORE_PREV_OWNER1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// COMMON_REG_O_SEMAPHORE_PREV_OWNER2 register. +// +//****************************************************************************** +#define COMMON_REG_SEMAPHORE_PREV_OWNER2_SEMAPHORE_PREV_OWNER2_M \ + 0x00FFFFFF // 1:0 : previous owner of + // apps_nw_semaphore1_reg[1:0] 3:2 : + // previous owner of + // apps_nw_semaphore2_reg[1:0] 5:4 : + // previous owner of + // apps_nw_semaphore3_reg[1:0] 7:6 : + // previous owner of + // apps_nw_semaphore4_reg[1:0] 9:8 : + // previous owner of + // apps_nw_semaphore5_reg[1:0] 11:10 + // : previous owner of + // apps_nw_semaphore6_reg[1:0] 13:12 + // : previous owner of + // apps_nw_semaphore7_reg[1:0] 15:14 + // : previous owner of + // apps_nw_semaphore8_reg[1:0] 17:16 + // : previous owner of + // apps_nw_semaphore9_reg[1:0] 19:18 + // : previous owner of + // apps_nw_semaphore10_reg[1:0] + // 21:20 : previous owner of + // apps_nw_semaphore11_reg[1:0] + // 23:22 : previous owner of + // apps_nw_semaphore12_reg[1:0] + +#define COMMON_REG_SEMAPHORE_PREV_OWNER2_SEMAPHORE_PREV_OWNER2_S 0 + + + +#endif // __HW_COMMON_REG_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_des.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_des.h new file mode 100755 index 0000000..c3aed65 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_des.h @@ -0,0 +1,339 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_DES_H__ +#define __HW_DES_H__ + +//***************************************************************************** +// +// The following are defines for the DES_P register offsets. +// +//***************************************************************************** +#define DES_O_KEY3_L 0x00000000 // KEY3 (LSW) for 192-bit key +#define DES_O_KEY3_H 0x00000004 // KEY3 (MSW) for 192-bit key +#define DES_O_KEY2_L 0x00000008 // KEY2 (LSW) for 192-bit key +#define DES_O_KEY2_H 0x0000000C // KEY2 (MSW) for 192-bit key +#define DES_O_KEY1_L 0x00000010 // KEY1 (LSW) for 128-bit + // key/192-bit key +#define DES_O_KEY1_H 0x00000014 // KEY1 (LSW) for 128-bit + // key/192-bit key +#define DES_O_IV_L 0x00000018 // Initialization vector LSW +#define DES_O_IV_H 0x0000001C // Initialization vector MSW +#define DES_O_CTRL 0x00000020 +#define DES_O_LENGTH 0x00000024 // Indicates the cryptographic data + // length in bytes for all modes. + // Once processing is started with + // this context this length + // decrements to zero. Data lengths + // up to (2^32 – 1) bytes are + // allowed. A write to this register + // triggers the engine to start + // using this context. For a Host + // read operation these registers + // return all-zeroes. +#define DES_O_DATA_L 0x00000028 // Data register(LSW) to read/write + // encrypted/decrypted data. +#define DES_O_DATA_H 0x0000002C // Data register(MSW) to read/write + // encrypted/decrypted data. +#define DES_O_REVISION 0x00000030 +#define DES_O_SYSCONFIG 0x00000034 +#define DES_O_SYSSTATUS 0x00000038 +#define DES_O_IRQSTATUS 0x0000003C // This register indicates the + // interrupt status. If one of the + // interrupt bits is set the + // interrupt output will be asserted +#define DES_O_IRQENABLE 0x00000040 // This register contains an enable + // bit for each unique interrupt + // generated by the module. It + // matches the layout of + // DES_IRQSTATUS register. An + // interrupt is enabled when the bit + // in this register is set to 1 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY3_L register. +// +//****************************************************************************** +#define DES_KEY3_L_KEY3_L_M 0xFFFFFFFF // data for key3 +#define DES_KEY3_L_KEY3_L_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY3_H register. +// +//****************************************************************************** +#define DES_KEY3_H_KEY3_H_M 0xFFFFFFFF // data for key3 +#define DES_KEY3_H_KEY3_H_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY2_L register. +// +//****************************************************************************** +#define DES_KEY2_L_KEY2_L_M 0xFFFFFFFF // data for key2 +#define DES_KEY2_L_KEY2_L_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY2_H register. +// +//****************************************************************************** +#define DES_KEY2_H_KEY2_H_M 0xFFFFFFFF // data for key2 +#define DES_KEY2_H_KEY2_H_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY1_L register. +// +//****************************************************************************** +#define DES_KEY1_L_KEY1_L_M 0xFFFFFFFF // data for key1 +#define DES_KEY1_L_KEY1_L_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_KEY1_H register. +// +//****************************************************************************** +#define DES_KEY1_H_KEY1_H_M 0xFFFFFFFF // data for key1 +#define DES_KEY1_H_KEY1_H_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_IV_L register. +// +//****************************************************************************** +#define DES_IV_L_IV_L_M 0xFFFFFFFF // initialization vector for CBC + // CFB modes +#define DES_IV_L_IV_L_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_IV_H register. +// +//****************************************************************************** +#define DES_IV_H_IV_H_M 0xFFFFFFFF // initialization vector for CBC + // CFB modes +#define DES_IV_H_IV_H_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_CTRL register. +// +//****************************************************************************** +#define DES_CTRL_CONTEXT 0x80000000 // If ‘1’ this read-only status bit + // indicates that the context data + // registers can be overwritten and + // the host is permitted to write + // the next context. +#define DES_CTRL_MODE_M 0x00000030 // Select CBC ECB or CFB mode 0x0 + // ecb mode 0x1 cbc mode 0x2 cfb + // mode 0x3 reserved +#define DES_CTRL_MODE_S 4 +#define DES_CTRL_TDES 0x00000008 // Select DES or triple DES + // encryption/decryption. 0 des mode + // 1 tdes mode +#define DES_CTRL_DIRECTION 0x00000004 // select encryption/decryption 0 + // decryption is selected 1 + // Encryption is selected +#define DES_CTRL_INPUT_READY 0x00000002 // When '1' ready to + // encrypt/decrypt data +#define DES_CTRL_OUTPUT_READY 0x00000001 // When '1' Data + // decrypted/encrypted ready +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_LENGTH register. +// +//****************************************************************************** +#define DES_LENGTH_LENGTH_M 0xFFFFFFFF +#define DES_LENGTH_LENGTH_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_DATA_L register. +// +//****************************************************************************** +#define DES_DATA_L_DATA_L_M 0xFFFFFFFF // data for encryption/decryption +#define DES_DATA_L_DATA_L_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_DATA_H register. +// +//****************************************************************************** +#define DES_DATA_H_DATA_H_M 0xFFFFFFFF // data for encryption/decryption +#define DES_DATA_H_DATA_H_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_REVISION register. +// +//****************************************************************************** +#define DES_REVISION_SCHEME_M 0xC0000000 +#define DES_REVISION_SCHEME_S 30 +#define DES_REVISION_FUNC_M 0x0FFF0000 // Function indicates a software + // compatible module family. If + // there is no level of software + // compatibility a new Func number + // (and hence REVISION) should be + // assigned. +#define DES_REVISION_FUNC_S 16 +#define DES_REVISION_R_RTL_M 0x0000F800 // RTL Version (R) maintained by IP + // design owner. RTL follows a + // numbering such as X.Y.R.Z which + // are explained in this table. R + // changes ONLY when: (1) PDS + // uploads occur which may have been + // due to spec changes (2) Bug fixes + // occur (3) Resets to '0' when X or + // Y changes. Design team has an + // internal 'Z' (customer invisible) + // number which increments on every + // drop that happens due to DV and + // RTL updates. Z resets to 0 when R + // increments. +#define DES_REVISION_R_RTL_S 11 +#define DES_REVISION_X_MAJOR_M \ + 0x00000700 // Major Revision (X) maintained by + // IP specification owner. X changes + // ONLY when: (1) There is a major + // feature addition. An example + // would be adding Master Mode to + // Utopia Level2. The Func field (or + // Class/Type in old PID format) + // will remain the same. X does NOT + // change due to: (1) Bug fixes (2) + // Change in feature parameters. + +#define DES_REVISION_X_MAJOR_S 8 +#define DES_REVISION_CUSTOM_M 0x000000C0 +#define DES_REVISION_CUSTOM_S 6 +#define DES_REVISION_Y_MINOR_M \ + 0x0000003F // Minor Revision (Y) maintained by + // IP specification owner. Y changes + // ONLY when: (1) Features are + // scaled (up or down). Flexibility + // exists in that this feature + // scalability may either be + // represented in the Y change or a + // specific register in the IP that + // indicates which features are + // exactly available. (2) When + // feature creeps from Is-Not list + // to Is list. But this may not be + // the case once it sees silicon; in + // which case X will change. Y does + // NOT change due to: (1) Bug fixes + // (2) Typos or clarifications (3) + // major functional/feature + // change/addition/deletion. Instead + // these changes may be reflected + // via R S X as applicable. Spec + // owner maintains a + // customer-invisible number 'S' + // which changes due to: (1) + // Typos/clarifications (2) Bug + // documentation. Note that this bug + // is not due to a spec change but + // due to implementation. + // Nevertheless the spec tracks the + // IP bugs. An RTL release (say for + // silicon PG1.1) that occurs due to + // bug fix should document the + // corresponding spec number (X.Y.S) + // in its release notes. + +#define DES_REVISION_Y_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_SYSCONFIG register. +// +//****************************************************************************** +#define DES_SYSCONFIG_DMA_REQ_CONTEXT_IN_EN \ + 0x00000080 // If set to ‘1’ the DMA context + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +#define DES_SYSCONFIG_DMA_REQ_DATA_OUT_EN \ + 0x00000040 // If set to ‘1’ the DMA output + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +#define DES_SYSCONFIG_DMA_REQ_DATA_IN_EN \ + 0x00000020 // If set to ‘1’ the DMA input + // request is enabled. 0 Dma + // disabled 1 Dma enabled + +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_SYSSTATUS register. +// +//****************************************************************************** +#define DES_SYSSTATUS_RESETDONE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_IRQSTATUS register. +// +//****************************************************************************** +#define DES_IRQSTATUS_DATA_OUT \ + 0x00000004 // This bit indicates data output + // interrupt is active and triggers + // the interrupt output. + +#define DES_IRQSTATUS_DATA_IN 0x00000002 // This bit indicates data input + // interrupt is active and triggers + // the interrupt output. +#define DES_IRQSTATUS_CONTEX_IN \ + 0x00000001 // This bit indicates context + // interrupt is active and triggers + // the interrupt output. + +//****************************************************************************** +// +// The following are defines for the bit fields in the DES_O_IRQENABLE register. +// +//****************************************************************************** +#define DES_IRQENABLE_M_DATA_OUT \ + 0x00000004 // If this bit is set to ‘1’ the + // secure data output interrupt is + // enabled. + +#define DES_IRQENABLE_M_DATA_IN \ + 0x00000002 // If this bit is set to ‘1’ the + // secure data input interrupt is + // enabled. + +#define DES_IRQENABLE_M_CONTEX_IN \ + 0x00000001 // If this bit is set to ‘1’ the + // secure context interrupt is + // enabled. + + + + +#endif // __HW_DES_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_dthe.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_dthe.h new file mode 100755 index 0000000..1d302f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_dthe.h @@ -0,0 +1,392 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_DTHE_H__ +#define __HW_DTHE_H__ + +//***************************************************************************** +// +// The following are defines for the DTHE register offsets. +// +//***************************************************************************** +#define DTHE_O_SHA_IM 0x00000810 +#define DTHE_O_SHA_RIS 0x00000814 +#define DTHE_O_SHA_MIS 0x00000818 +#define DTHE_O_SHA_IC 0x0000081C +#define DTHE_O_AES_IM 0x00000820 +#define DTHE_O_AES_RIS 0x00000824 +#define DTHE_O_AES_MIS 0x00000828 +#define DTHE_O_AES_IC 0x0000082C +#define DTHE_O_DES_IM 0x00000830 +#define DTHE_O_DES_RIS 0x00000834 +#define DTHE_O_DES_MIS 0x00000838 +#define DTHE_O_DES_IC 0x0000083C +#define DTHE_O_EIP_CGCFG 0x00000A00 +#define DTHE_O_EIP_CGREQ 0x00000A04 +#define DTHE_O_CRC_CTRL 0x00000C00 +#define DTHE_O_CRC_SEED 0x00000C10 +#define DTHE_O_CRC_DIN 0x00000C14 +#define DTHE_O_CRC_RSLT_PP 0x00000C18 +#define DTHE_O_RAND_KEY0 0x00000F00 +#define DTHE_O_RAND_KEY1 0x00000F04 +#define DTHE_O_RAND_KEY2 0x00000F08 +#define DTHE_O_RAND_KEY3 0x00000F0C + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_SHAMD5_IMST register. +// +//****************************************************************************** +#define DTHE_SHAMD5_IMST_DIN 0x00000004 // Data in: this interrupt is + // raised when DMA writes last word + // of input data to internal FIFO of + // the engine +#define DTHE_SHAMD5_IMST_COUT 0x00000002 // Context out: this interrupt is + // raised when DMA complets the + // output context movement from + // internal register +#define DTHE_SHAMD5_IMST_CIN 0x00000001 // context in: this interrupt is + // raised when DMA complets Context + // write to internal register +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_SHAMD5_IRIS register. +// +//****************************************************************************** +#define DTHE_SHAMD5_IRIS_DIN 0x00000004 // input Data movement is done +#define DTHE_SHAMD5_IRIS_COUT 0x00000002 // Context output is done +#define DTHE_SHAMD5_IRIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_SHAMD5_IMIS register. +// +//****************************************************************************** +#define DTHE_SHAMD5_IMIS_DIN 0x00000004 // input Data movement is done +#define DTHE_SHAMD5_IMIS_COUT 0x00000002 // Context output is done +#define DTHE_SHAMD5_IMIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_SHAMD5_ICIS register. +// +//****************************************************************************** +#define DTHE_SHAMD5_ICIS_DIN 0x00000004 // Clear “input Data movement done†+ // flag +#define DTHE_SHAMD5_ICIS_COUT 0x00000002 // Clear “Context output done†flag +#define DTHE_SHAMD5_ICIS_CIN 0x00000001 // Clear “context input done†flag +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_AES_IMST register. +// +//****************************************************************************** +#define DTHE_AES_IMST_DOUT 0x00000008 // Data out: this interrupt is + // raised when DMA finishes writing + // last word of the process result +#define DTHE_AES_IMST_DIN 0x00000004 // Data in: this interrupt is + // raised when DMA writes last word + // of input data to internal FIFO of + // the engine +#define DTHE_AES_IMST_COUT 0x00000002 // Context out: this interrupt is + // raised when DMA complets the + // output context movement from + // internal register +#define DTHE_AES_IMST_CIN 0x00000001 // context in: this interrupt is + // raised when DMA complets Context + // write to internal register +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_AES_IRIS register. +// +//****************************************************************************** +#define DTHE_AES_IRIS_DOUT 0x00000008 // Output Data movement is done +#define DTHE_AES_IRIS_DIN 0x00000004 // input Data movement is done +#define DTHE_AES_IRIS_COUT 0x00000002 // Context output is done +#define DTHE_AES_IRIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_AES_IMIS register. +// +//****************************************************************************** +#define DTHE_AES_IMIS_DOUT 0x00000008 // Output Data movement is done +#define DTHE_AES_IMIS_DIN 0x00000004 // input Data movement is done +#define DTHE_AES_IMIS_COUT 0x00000002 // Context output is done +#define DTHE_AES_IMIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_AES_ICIS register. +// +//****************************************************************************** +#define DTHE_AES_ICIS_DOUT 0x00000008 // Clear “output Data movement + // done†flag +#define DTHE_AES_ICIS_DIN 0x00000004 // Clear “input Data movement done†+ // flag +#define DTHE_AES_ICIS_COUT 0x00000002 // Clear “Context output done†flag +#define DTHE_AES_ICIS_CIN 0x00000001 // Clear “context input done†flag +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_DES_IMST register. +// +//****************************************************************************** +#define DTHE_DES_IMST_DOUT 0x00000008 // Data out: this interrupt is + // raised when DMA finishes writing + // last word of the process result +#define DTHE_DES_IMST_DIN 0x00000004 // Data in: this interrupt is + // raised when DMA writes last word + // of input data to internal FIFO of + // the engine +#define DTHE_DES_IMST_CIN 0x00000001 // context in: this interrupt is + // raised when DMA complets Context + // write to internal register +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_DES_IRIS register. +// +//****************************************************************************** +#define DTHE_DES_IRIS_DOUT 0x00000008 // Output Data movement is done +#define DTHE_DES_IRIS_DIN 0x00000004 // input Data movement is done +#define DTHE_DES_IRIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_DES_IMIS register. +// +//****************************************************************************** +#define DTHE_DES_IMIS_DOUT 0x00000008 // Output Data movement is done +#define DTHE_DES_IMIS_DIN 0x00000004 // input Data movement is done +#define DTHE_DES_IMIS_CIN 0x00000001 // context input is done +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_DES_ICIS register. +// +//****************************************************************************** +#define DTHE_DES_ICIS_DOUT 0x00000008 // Clear “output Data movement + // done†flag +#define DTHE_DES_ICIS_DIN 0x00000004 // Clear “input Data movement done†+ // flag +#define DTHE_DES_ICIS_CIN 0x00000001 // Clear "context input done†flag +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_EIP_CGCFG register. +// +//****************************************************************************** +#define DTHE_EIP_CGCFG_EIP29_CFG \ + 0x00000010 // Clock gating protocol setting + // for EIP29T. 0 – Follow direct + // protocol 1 – Follow idle_req/ack + // protocol. + +#define DTHE_EIP_CGCFG_EIP75_CFG \ + 0x00000008 // Clock gating protocol setting + // for EIP75T. 0 – Follow direct + // protocol 1 – Follow idle_req/ack + // protocol. + +#define DTHE_EIP_CGCFG_EIP16_CFG \ + 0x00000004 // Clock gating protocol setting + // for DES. 0 – Follow direct + // protocol 1 – Follow idle_req/ack + // protocol. + +#define DTHE_EIP_CGCFG_EIP36_CFG \ + 0x00000002 // Clock gating protocol setting + // for AES. 0 – Follow direct + // protocol 1 – Follow idle_req/ack + // protocol. + +#define DTHE_EIP_CGCFG_EIP57_CFG \ + 0x00000001 // Clock gating protocol setting + // for SHAMD5. 0 – Follow direct + // protocol 1 – Follow idle_req/ack + // protocol. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_EIP_CGREQ register. +// +//****************************************************************************** +#define DTHE_EIP_CGREQ_Key_M 0xF0000000 // When “0x5†write “1†to lower + // bits [4:0] will set the bit. + // Write “0†will be ignored When + // “0x2†write “1†to lower bit + // [4:0] will clear the bit. Write + // “0†will be ignored for other key + // value, regular read write + // operation +#define DTHE_EIP_CGREQ_Key_S 28 +#define DTHE_EIP_CGREQ_EIP29_REQ \ + 0x00000010 // 0 – request clock gating 1 – + // request to un-gate the clock. + +#define DTHE_EIP_CGREQ_EIP75_REQ \ + 0x00000008 // 0 – request clock gating 1 – + // request to un-gate the clock. + +#define DTHE_EIP_CGREQ_EIP16_REQ \ + 0x00000004 // 0 – request clock gating 1 – + // request to un-gate the clock. + +#define DTHE_EIP_CGREQ_EIP36_REQ \ + 0x00000002 // 0 – request clock gating 1 – + // request to un-gate the clock. + +#define DTHE_EIP_CGREQ_EIP57_REQ \ + 0x00000001 // 0 – request clock gating 1 – + // request to un-gate the clock. + +//****************************************************************************** +// +// The following are defines for the bit fields in the DTHE_O_CRC_CTRL register. +// +//****************************************************************************** +#define DTHE_CRC_CTRL_INIT_M 0x00006000 // Initialize the CRC 00 – use SEED + // register context as starting + // value 10 – all “zero†11 – all + // “one†This is self clearing. With + // first write to data register this + // value clears to zero and remain + // zero for rest of the operation + // unless written again +#define DTHE_CRC_CTRL_INIT_S 13 +#define DTHE_CRC_CTRL_SIZE 0x00001000 // Input data size 0 – 32 bit 1 – 8 + // bit +#define DTHE_CRC_CTRL_OINV 0x00000200 // Inverse the bits of result + // before storing to CRC_RSLT_PP0 +#define DTHE_CRC_CTRL_OBR 0x00000100 // Bit reverse the output result + // byte before storing to + // CRC_RSLT_PP0. applicable for all + // bytes in word +#define DTHE_CRC_CTRL_IBR 0x00000080 // Bit reverse the input byte. For + // all bytes in word +#define DTHE_CRC_CTRL_ENDIAN_M \ + 0x00000030 // Endian control [0] – swap byte + // in half-word [1] – swap half word + +#define DTHE_CRC_CTRL_ENDIAN_S 4 +#define DTHE_CRC_CTRL_TYPE_M 0x0000000F // Type of operation 0000 – + // polynomial 0x8005 0001 – + // polynomial 0x1021 0010 – + // polynomial 0x4C11DB7 0011 – + // polynomial 0x1EDC6F41 1000 – TCP + // checksum TYPE in DTHE_S_CRC_CTRL + // & DTHE_S_CRC_CTRL should be + // exclusive +#define DTHE_CRC_CTRL_TYPE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DTHE_O_CRC_SEED register. +// +//****************************************************************************** +#define DTHE_CRC_SEED_SEED_M 0xFFFFFFFF // Starting seed of CRC and + // checksum operation. Please see + // CTRL register for more detail. + // This resister also holds the + // latest result of CRC or checksum + // operation +#define DTHE_CRC_SEED_SEED_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the DTHE_O_CRC_DIN register. +// +//****************************************************************************** +#define DTHE_CRC_DIN_DATA_IN_M \ + 0xFFFFFFFF // Input data for CRC or checksum + // operation + +#define DTHE_CRC_DIN_DATA_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_CRC_RSLT_PP register. +// +//****************************************************************************** +#define DTHE_CRC_RSLT_PP_RSLT_PP_M \ + 0xFFFFFFFF // Input data for CRC or checksum + // operation + +#define DTHE_CRC_RSLT_PP_RSLT_PP_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_RAND_KEY0 register. +// +//****************************************************************************** +#define DTHE_RAND_KEY0_KEY_M 0xFFFFFFFF // Device Specific Randon key + // [31:0] +#define DTHE_RAND_KEY0_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_RAND_KEY1 register. +// +//****************************************************************************** +#define DTHE_RAND_KEY1_KEY_M 0xFFFFFFFF // Device Specific Randon key + // [63:32] +#define DTHE_RAND_KEY1_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_RAND_KEY2 register. +// +//****************************************************************************** +#define DTHE_RAND_KEY2_KEY_M 0xFFFFFFFF // Device Specific Randon key + // [95:34] +#define DTHE_RAND_KEY2_KEY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// DTHE_O_RAND_KEY3 register. +// +//****************************************************************************** +#define DTHE_RAND_KEY3_KEY_M 0xFFFFFFFF // Device Specific Randon key + // [127:96] +#define DTHE_RAND_KEY3_KEY_S 0 + + + +#endif // __HW_DTHE_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_flash_ctrl.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_flash_ctrl.h new file mode 100755 index 0000000..b57044a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_flash_ctrl.h @@ -0,0 +1,1862 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_FLASH_CTRL_H__ +#define __HW_FLASH_CTRL_H__ + +//***************************************************************************** +// +// The following are defines for the FLASH_CTRL register offsets. +// +//***************************************************************************** +#define FLASH_CTRL_O_FMA 0x00000000 // Flash Memory Address (FMA) + // offset 0x000 During a write + // operation this register contains + // a 4-byte-aligned address and + // specifies where the data is + // written. During erase operations + // this register contains a 1 + // KB-aligned CPU byte address and + // specifies which block is erased. + // Note that the alignment + // requirements must be met by + // software or the results of the + // operation are unpredictable. +#define FLASH_CTRL_O_FMD 0x00000004 // Flash Memory Data (FMD) offset + // 0x004 This register contains the + // data to be written during the + // programming cycle or read during + // the read cycle. Note that the + // contents of this register are + // undefined for a read access of an + // execute-only block. This register + // is not used during erase cycles. +#define FLASH_CTRL_O_FMC 0x00000008 // Flash Memory Control (FMC) + // offset 0x008 When this register + // is written the Flash memory + // controller initiates the + // appropriate access cycle for the + // location specified by the Flash + // Memory Address (FMA) register . + // If the access is a write access + // the data contained in the Flash + // Memory Data (FMD) register is + // written to the specified address. + // This register must be the final + // register written and initiates + // the memory operation. The four + // control bits in the lower byte of + // this register are used to + // initiate memory operations. +#define FLASH_CTRL_O_FCRIS 0x0000000C // Flash Controller Raw Interrupt + // Status (FCRIS) offset 0x00C This + // register indicates that the Flash + // memory controller has an + // interrupt condition. An interrupt + // is sent to the interrupt + // controller only if the + // corresponding FCIM register bit + // is set. +#define FLASH_CTRL_O_FCIM 0x00000010 // Flash Controller Interrupt Mask + // (FCIM) offset 0x010 This register + // controls whether the Flash memory + // controller generates interrupts + // to the controller. +#define FLASH_CTRL_O_FCMISC 0x00000014 // Flash Controller Masked + // Interrupt Status and Clear + // (FCMISC) offset 0x014 This + // register provides two functions. + // First it reports the cause of an + // interrupt by indicating which + // interrupt source or sources are + // signalling the interrupt. Second + // it serves as the method to clear + // the interrupt reporting. +#define FLASH_CTRL_O_FMC2 0x00000020 // Flash Memory Control 2 (FMC2) + // offset 0x020 When this register + // is written the Flash memory + // controller initiates the + // appropriate access cycle for the + // location specified by the Flash + // Memory Address (FMA) register . + // If the access is a write access + // the data contained in the Flash + // Write Buffer (FWB) registers is + // written. This register must be + // the final register written as it + // initiates the memory operation. +#define FLASH_CTRL_O_FWBVAL 0x00000030 // Flash Write Buffer Valid + // (FWBVAL) offset 0x030 This + // register provides a bitwise + // status of which FWBn registers + // have been written by the + // processor since the last write of + // the Flash memory write buffer. + // The entries with a 1 are written + // on the next write of the Flash + // memory write buffer. This + // register is cleared after the + // write operation by hardware. A + // protection violation on the write + // operation also clears this + // status. Software can program the + // same 32 words to various Flash + // memory locations by setting the + // FWB[n] bits after they are + // cleared by the write operation. + // The next write operation then + // uses the same data as the + // previous one. In addition if a + // FWBn register change should not + // be written to Flash memory + // software can clear the + // corresponding FWB[n] bit to + // preserve the existing data when + // the next write operation occurs. +#define FLASH_CTRL_O_FWB1 0x00000100 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB2 0x00000104 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB3 0x00000108 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB4 0x0000010C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB5 0x00000110 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB6 0x00000114 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB7 0x00000118 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB8 0x0000011C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB9 0x00000120 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB10 0x00000124 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB11 0x00000128 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB12 0x0000012C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB13 0x00000130 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB14 0x00000134 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB15 0x00000138 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB16 0x0000013C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB17 0x00000140 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB18 0x00000144 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB19 0x00000148 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB20 0x0000014C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB21 0x00000150 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB22 0x00000154 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB23 0x00000158 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB24 0x0000015C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB25 0x00000160 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB26 0x00000164 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB27 0x00000168 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB28 0x0000016C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB29 0x00000170 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB30 0x00000174 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB31 0x00000178 // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FWB32 0x0000017C // Flash Write Buffer n (FWBn) + // offset 0x100 - 0x17C These 32 + // registers hold the contents of + // the data to be written into the + // Flash memory on a buffered Flash + // memory write operation. The + // offset selects one of the 32-bit + // registers. Only FWBn registers + // that have been updated since the + // preceding buffered Flash memory + // write operation are written into + // the Flash memory so it is not + // necessary to write the entire + // bank of registers in order to + // write 1 or 2 words. The FWBn + // registers are written into the + // Flash memory with the FWB0 + // register corresponding to the + // address contained in FMA. FWB1 is + // written to the address FMA+0x4 + // etc. Note that only data bits + // that are 0 result in the Flash + // memory being modified. A data bit + // that is 1 leaves the content of + // the Flash memory bit at its + // previous value. +#define FLASH_CTRL_O_FSIZE 0x00000FC0 // Flash Size (FSIZE) offset 0xFC0 + // This register indicates the size + // of the on-chip Flash memory. + // Important: This register should + // be used to determine the size of + // the Flash memory that is + // implemented on this + // microcontroller. However to + // support legacy software the DC0 + // register is available. A read of + // the DC0 register correctly + // identifies legacy memory sizes. + // Software must use the FSIZE + // register for memory sizes that + // are not listed in the DC0 + // register description. +#define FLASH_CTRL_O_SSIZE 0x00000FC4 // SRAM Size (SSIZE) offset 0xFC4 + // This register indicates the size + // of the on-chip SRAM. Important: + // This register should be used to + // determine the size of the SRAM + // that is implemented on this + // microcontroller. However to + // support legacy software the DC0 + // register is available. A read of + // the DC0 register correctly + // identifies legacy memory sizes. + // Software must use the SSIZE + // register for memory sizes that + // are not listed in the DC0 + // register description. + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FMA register. +// +//****************************************************************************** +#define FLASH_CTRL_FMA_OFFSET_M 0x0003FFFF // Address Offset Address offset in + // Flash memory where operation is + // performed except for nonvolatile + // registers +#define FLASH_CTRL_FMA_OFFSET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FMD register. +// +//****************************************************************************** +#define FLASH_CTRL_FMD_DATA_M 0xFFFFFFFF // Data Value Data value for write + // operation. +#define FLASH_CTRL_FMD_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FMC register. +// +//****************************************************************************** +#define FLASH_CTRL_FMC_WRKEY_M 0xFFFF0000 // Flash Memory Write Key This + // field contains a write key which + // is used to minimize the incidence + // of accidental Flash memory + // writes. The value 0xA442 must be + // written into this field for a + // Flash memory write to occur. + // Writes to the FMC register + // without this WRKEY value are + // ignored. A read of this field + // returns the value 0. +#define FLASH_CTRL_FMC_WRKEY_S 16 +#define FLASH_CTRL_FMC_COMT 0x00000008 // Commit Register Value This bit + // is used to commit writes to + // Flash-memory-resident registers + // and to monitor the progress of + // that process. Value Description 1 + // Set this bit to commit (write) + // the register value to a + // Flash-memory-resident register. + // When read a 1 indicates that the + // previous commit access is not + // complete. 0 A write of 0 has no + // effect on the state of this bit. + // When read a 0 indicates that the + // previous commit access is + // complete. +#define FLASH_CTRL_FMC_MERASE1 0x00000004 // Mass Erase Flash Memory This bit + // is used to mass erase the Flash + // main memory and to monitor the + // progress of that process. Value + // Description 1 Set this bit to + // erase the Flash main memory. When + // read a 1 indicates that the + // previous mass erase access is not + // complete. 0 A write of 0 has no + // effect on the state of this bit. + // When read a 0 indicates that the + // previous mass erase access is + // complete. +#define FLASH_CTRL_FMC_ERASE 0x00000002 // Erase a Page of Flash Memory + // This bit is used to erase a page + // of Flash memory and to monitor + // the progress of that process. + // Value Description 1 Set this bit + // to erase the Flash memory page + // specified by the contents of the + // FMA register. When read a 1 + // indicates that the previous page + // erase access is not complete. 0 A + // write of 0 has no effect on the + // state of this bit. When read a 0 + // indicates that the previous page + // erase access is complete. +#define FLASH_CTRL_FMC_WRITE 0x00000001 // Write a Word into Flash Memory + // This bit is used to write a word + // into Flash memory and to monitor + // the progress of that process. + // Value Description 1 Set this bit + // to write the data stored in the + // FMD register into the Flash + // memory location specified by the + // contents of the FMA register. + // When read a 1 indicates that the + // write update access is not + // complete. 0 A write of 0 has no + // effect on the state of this bit. + // When read a 0 indicates that the + // previous write update access is + // complete. +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FCRIS register. +// +//****************************************************************************** +#define FLASH_CTRL_FCRIS_PROGRIS \ + 0x00002000 // Program Verify Error Raw + // Interrupt Status Value + // Description 1 An interrupt is + // pending because the verify of a + // PROGRAM operation failed. 0 An + // interrupt has not occurred. This + // bit is cleared by writing a 1 to + // the PROGMISC bit in the FCMISC + // register. + +#define FLASH_CTRL_FCRIS_ERRIS 0x00000800 // Erase Verify Error Raw Interrupt + // Status Value Description 1 An + // interrupt is pending because the + // verify of an ERASE operation + // failed. 0 An interrupt has not + // occurred. This bit is cleared by + // writing a 1 to the ERMISC bit in + // the FCMISC register. +#define FLASH_CTRL_FCRIS_INVDRIS \ + 0x00000400 // Invalid Data Raw Interrupt + // Status Value Description 1 An + // interrupt is pending because a + // bit that was previously + // programmed as a 0 is now being + // requested to be programmed as a + // 1. 0 An interrupt has not + // occurred. This bit is cleared by + // writing a 1 to the INVMISC bit in + // the FCMISC register. + +#define FLASH_CTRL_FCRIS_VOLTRIS \ + 0x00000200 // Pump Voltage Raw Interrupt + // Status Value Description 1 An + // interrupt is pending because the + // regulated voltage of the pump + // went out of spec during the Flash + // operation and the operation was + // terminated. 0 An interrupt has + // not occurred. This bit is cleared + // by writing a 1 to the VOLTMISC + // bit in the FCMISC register. + +#define FLASH_CTRL_FCRIS_ERIS 0x00000004 // EEPROM Raw Interrupt Status This + // bit provides status EEPROM + // operation. Value Description 1 An + // EEPROM interrupt has occurred. 0 + // An EEPROM interrupt has not + // occurred. This bit is cleared by + // writing a 1 to the EMISC bit in + // the FCMISC register. +#define FLASH_CTRL_FCRIS_PRIS 0x00000002 // Programming Raw Interrupt Status + // This bit provides status on + // programming cycles which are + // write or erase actions generated + // through the FMC or FMC2 register + // bits (see page 537 and page 549). + // Value Description 1 The + // programming or erase cycle has + // completed. 0 The programming or + // erase cycle has not completed. + // This status is sent to the + // interrupt controller when the + // PMASK bit in the FCIM register is + // set. This bit is cleared by + // writing a 1 to the PMISC bit in + // the FCMISC register. +#define FLASH_CTRL_FCRIS_ARIS 0x00000001 // Access Raw Interrupt Status + // Value Description 1 A program or + // erase action was attempted on a + // block of Flash memory that + // contradicts the protection policy + // for that block as set in the + // FMPPEn registers. 0 No access has + // tried to improperly program or + // erase the Flash memory. This + // status is sent to the interrupt + // controller when the AMASK bit in + // the FCIM register is set. This + // bit is cleared by writing a 1 to + // the AMISC bit in the FCMISC + // register. +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FCIM register. +// +//****************************************************************************** +#define FLASH_CTRL_FCIM_ILLMASK 0x00004000 // Illegal Address Interrupt Mask + // Value Description 1 An interrupt + // is sent to the interrupt + // controller when the ILLARIS bit + // is set. 0 The ILLARIS interrupt + // is suppressed and not sent to the + // interrupt controller. +#define FLASH_CTRL_FCIM_PROGMASK \ + 0x00002000 // PROGVER Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the PROGRIS bit is set. 0 + // The PROGRIS interrupt is + // suppressed and not sent to the + // interrupt controller. + +#define FLASH_CTRL_FCIM_PREMASK 0x00001000 // PREVER Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the PRERIS bit is set. 0 The + // PRERIS interrupt is suppressed + // and not sent to the interrupt + // controller. +#define FLASH_CTRL_FCIM_ERMASK 0x00000800 // ERVER Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the ERRIS bit is set. 0 The + // ERRIS interrupt is suppressed and + // not sent to the interrupt + // controller. +#define FLASH_CTRL_FCIM_INVDMASK \ + 0x00000400 // Invalid Data Interrupt Mask + // Value Description 1 An interrupt + // is sent to the interrupt + // controller when the INVDRIS bit + // is set. 0 The INVDRIS interrupt + // is suppressed and not sent to the + // interrupt controller. + +#define FLASH_CTRL_FCIM_VOLTMASK \ + 0x00000200 // VOLT Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the VOLTRIS bit is set. 0 + // The VOLTRIS interrupt is + // suppressed and not sent to the + // interrupt controller. + +#define FLASH_CTRL_FCIM_LOCKMASK \ + 0x00000100 // LOCK Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the LOCKRIS bit is set. 0 + // The LOCKRIS interrupt is + // suppressed and not sent to the + // interrupt controller. + +#define FLASH_CTRL_FCIM_EMASK 0x00000004 // EEPROM Interrupt Mask Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the ERIS bit is set. 0 The + // ERIS interrupt is suppressed and + // not sent to the interrupt + // controller. +#define FLASH_CTRL_FCIM_PMASK 0x00000002 // Programming Interrupt Mask This + // bit controls the reporting of the + // programming raw interrupt status + // to the interrupt controller. + // Value Description 1 An interrupt + // is sent to the interrupt + // controller when the PRIS bit is + // set. 0 The PRIS interrupt is + // suppressed and not sent to the + // interrupt controller. +#define FLASH_CTRL_FCIM_AMASK 0x00000001 // Access Interrupt Mask This bit + // controls the reporting of the + // access raw interrupt status to + // the interrupt controller. Value + // Description 1 An interrupt is + // sent to the interrupt controller + // when the ARIS bit is set. 0 The + // ARIS interrupt is suppressed and + // not sent to the interrupt + // controller. +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FCMISC register. +// +//****************************************************************************** +#define FLASH_CTRL_FCMISC_ILLMISC \ + 0x00004000 // Illegal Address Masked Interrupt + // Status and Clear Value + // Description 1 When read a 1 + // indicates that an unmasked + // interrupt was signaled. Writing a + // 1 to this bit clears ILLAMISC and + // also the ILLARIS bit in the FCRIS + // register (see page 540). 0 When + // read a 0 indicates that an + // interrupt has not occurred. A + // write of 0 has no effect on the + // state of this bit. + +#define FLASH_CTRL_FCMISC_PROGMISC \ + 0x00002000 // PROGVER Masked Interrupt Status + // and Clear Value Description 1 + // When read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // PROGMISC and also the PROGRIS bit + // in the FCRIS register (see page + // 540). 0 When read a 0 indicates + // that an interrupt has not + // occurred. A write of 0 has no + // effect on the state of this bit. + +#define FLASH_CTRL_FCMISC_PREMISC \ + 0x00001000 // PREVER Masked Interrupt Status + // and Clear Value Description 1 + // When read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // PREMISC and also the PRERIS bit + // in the FCRIS register . 0 When + // read a 0 indicates that an + // interrupt has not occurred. A + // write of 0 has no effect on the + // state of this bit. + +#define FLASH_CTRL_FCMISC_ERMISC \ + 0x00000800 // ERVER Masked Interrupt Status + // and Clear Value Description 1 + // When read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // ERMISC and also the ERRIS bit in + // the FCRIS register 0 When read a + // 0 indicates that an interrupt has + // not occurred. A write of 0 has no + // effect on the state of this bit. + +#define FLASH_CTRL_FCMISC_INVDMISC \ + 0x00000400 // Invalid Data Masked Interrupt + // Status and Clear Value + // Description 1 When read a 1 + // indicates that an unmasked + // interrupt was signaled. Writing a + // 1 to this bit clears INVDMISC and + // also the INVDRIS bit in the FCRIS + // register (see page 540). 0 When + // read a 0 indicates that an + // interrupt has not occurred. A + // write of 0 has no effect on the + // state of this bit. + +#define FLASH_CTRL_FCMISC_VOLTMISC \ + 0x00000200 // VOLT Masked Interrupt Status and + // Clear Value Description 1 When + // read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // VOLTMISC and also the VOLTRIS bit + // in the FCRIS register (see page + // 540). 0 When read a 0 indicates + // that an interrupt has not + // occurred. A write of 0 has no + // effect on the state of this bit. + +#define FLASH_CTRL_FCMISC_LOCKMISC \ + 0x00000100 // LOCK Masked Interrupt Status and + // Clear Value Description 1 When + // read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // LOCKMISC and also the LOCKRIS bit + // in the FCRIS register (see page + // 540). 0 When read a 0 indicates + // that an interrupt has not + // occurred. A write of 0 has no + // effect on the state of this bit. + +#define FLASH_CTRL_FCMISC_EMISC 0x00000004 // EEPROM Masked Interrupt Status + // and Clear Value Description 1 + // When read a 1 indicates that an + // unmasked interrupt was signaled. + // Writing a 1 to this bit clears + // EMISC and also the ERIS bit in + // the FCRIS register 0 When read a + // 0 indicates that an interrupt has + // not occurred. A write of 0 has no + // effect on the state of this bit. +#define FLASH_CTRL_FCMISC_PMISC 0x00000002 // Programming Masked Interrupt + // Status and Clear Value + // Description 1 When read a 1 + // indicates that an unmasked + // interrupt was signaled because a + // programming cycle completed. + // Writing a 1 to this bit clears + // PMISC and also the PRIS bit in + // the FCRIS register 0 When read a + // 0 indicates that a programming + // cycle complete interrupt has not + // occurred. A write of 0 has no + // effect on the state of this bit. +#define FLASH_CTRL_FCMISC_AMISC 0x00000001 // Access Masked Interrupt Status + // and Clear Value Description 1 + // When read a 1 indicates that an + // unmasked interrupt was signaled + // because a program or erase action + // was attempted on a block of Flash + // memory that contradicts the + // protection policy for that block + // as set in the FMPPEn registers. + // Writing a 1 to this bit clears + // AMISC and also the ARIS bit in + // the FCRIS register 0 When read a + // 0 indicates that no improper + // accesses have occurred. A write + // of 0 has no effect on the state + // of this bit. +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FMC2 register. +// +//****************************************************************************** +#define FLASH_CTRL_FMC2_WRKEY_M 0xFFFF0000 // Flash Memory Write Key This + // field contains a write key which + // is used to minimize the incidence + // of accidental Flash memory + // writes. The value 0xA442 must be + // written into this field for a + // write to occur. Writes to the + // FMC2 register without this WRKEY + // value are ignored. A read of this + // field returns the value 0. +#define FLASH_CTRL_FMC2_WRKEY_S 16 +#define FLASH_CTRL_FMC2_WRBUF 0x00000001 // Buffered Flash Memory Write This + // bit is used to start a buffered + // write to Flash memory. Value + // Description 1 Set this bit to + // write the data stored in the FWBn + // registers to the location + // specified by the contents of the + // FMA register. When read a 1 + // indicates that the previous + // buffered Flash memory write + // access is not complete. 0 A write + // of 0 has no effect on the state + // of this bit. When read a 0 + // indicates that the previous + // buffered Flash memory write + // access is complete. +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWBVAL register. +// +//****************************************************************************** +#define FLASH_CTRL_FWBVAL_FWBN_M \ + 0xFFFFFFFF // Flash Memory Write Buffer Value + // Description 1 The corresponding + // FWBn register has been updated + // since the last buffer write + // operation and is ready to be + // written to Flash memory. 0 The + // corresponding FWBn register has + // no new data to be written. Bit 0 + // corresponds to FWB0 offset 0x100 + // and bit 31 corresponds to FWB31 + // offset 0x13C. + +#define FLASH_CTRL_FWBVAL_FWBN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB1 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB1_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB1_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB2 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB2_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB2_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB3 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB3_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB3_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB4 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB4_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB4_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB5 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB5_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB5_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB6 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB6_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB6_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB7 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB7_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB7_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB8 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB8_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB8_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the FLASH_CTRL_O_FWB9 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB9_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB9_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB10 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB10_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB10_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB11 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB11_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB11_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB12 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB12_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB12_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB13 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB13_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB13_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB14 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB14_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB14_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB15 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB15_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB15_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB16 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB16_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB16_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB17 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB17_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB17_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB18 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB18_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB18_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB19 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB19_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB19_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB20 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB20_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB20_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB21 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB21_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB21_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB22 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB22_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB22_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB23 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB23_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB23_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB24 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB24_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB24_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB25 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB25_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB25_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB26 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB26_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB26_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB27 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB27_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB27_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB28 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB28_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB28_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB29 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB29_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB29_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB30 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB30_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB30_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB31 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB31_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB31_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FWB32 register. +// +//****************************************************************************** +#define FLASH_CTRL_FWB32_DATA_M 0xFFFFFFFF // Data Data to be written into the + // Flash memory. +#define FLASH_CTRL_FWB32_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_FSIZE register. +// +//****************************************************************************** +#define FLASH_CTRL_FSIZE_SIZE_M 0x0000FFFF // Flash Size Indicates the size of + // the on-chip Flash memory. Value + // Description 0x0003 8 KB of Flash + // 0x0007 16 KB of Flash 0x000F 32 + // KB of Flash 0x001F 64 KB of Flash + // 0x002F 96 KB of Flash 0x003F 128 + // KB of Flash 0x005F 192 KB of + // Flash 0x007F 256 KB of Flash +#define FLASH_CTRL_FSIZE_SIZE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// FLASH_CTRL_O_SSIZE register. +// +//****************************************************************************** +#define FLASH_CTRL_SSIZE_SRAM_SIZE_M \ + 0x0000FFFF // SRAM Size Indicates the size of + // the on-chip SRAM. Value + // Description 0x0007 2 KB of SRAM + // 0x000F 4 KB of SRAM 0x0017 6 KB + // of SRAM 0x001F 8 KB of SRAM + // 0x002F 12 KB of SRAM 0x003F 16 KB + // of SRAM 0x004F 20 KB of SRAM + // 0x005F 24 KB of SRAM 0x007F 32 KB + // of SRAM + +#define FLASH_CTRL_SSIZE_SRAM_SIZE_S 0 +#define FLASH_CTRL_FMC_WRKEY 0xA4420000 // FLASH write key +#define FLASH_CTRL_FMC2_WRKEY 0xA4420000 // FLASH write key +#define FLASH_CTRL_O_FWBN FLASH_CTRL_O_FWB1 +#define FLASH_ERASE_SIZE 0x00000400 +#define FLASH_PROTECT_SIZE 0x00000800 +#define FLASH_FMP_BLOCK_0 0x00000001 // Enable for block 0 + +#define FLASH_FMPRE0 0x400FE200 // Flash Memory Protection Read + // Enable 0 +#define FLASH_FMPRE1 0x400FE204 // Flash Memory Protection Read + // Enable 1 +#define FLASH_FMPRE2 0x400FE208 // Flash Memory Protection Read + // Enable 2 +#define FLASH_FMPRE3 0x400FE20C // Flash Memory Protection Read + // Enable 3 +#define FLASH_FMPRE4 0x400FE210 // Flash Memory Protection Read + // Enable 4 +#define FLASH_FMPRE5 0x400FE214 // Flash Memory Protection Read + // Enable 5 +#define FLASH_FMPRE6 0x400FE218 // Flash Memory Protection Read + // Enable 6 +#define FLASH_FMPRE7 0x400FE21C // Flash Memory Protection Read + // Enable 7 +#define FLASH_FMPRE8 0x400FE220 // Flash Memory Protection Read + // Enable 8 +#define FLASH_FMPRE9 0x400FE224 // Flash Memory Protection Read + // Enable 9 +#define FLASH_FMPRE10 0x400FE228 // Flash Memory Protection Read + // Enable 10 +#define FLASH_FMPRE11 0x400FE22C // Flash Memory Protection Read + // Enable 11 +#define FLASH_FMPRE12 0x400FE230 // Flash Memory Protection Read + // Enable 12 +#define FLASH_FMPRE13 0x400FE234 // Flash Memory Protection Read + // Enable 13 +#define FLASH_FMPRE14 0x400FE238 // Flash Memory Protection Read + // Enable 14 +#define FLASH_FMPRE15 0x400FE23C // Flash Memory Protection Read + // Enable 15 + +#define FLASH_FMPPE0 0x400FE400 // Flash Memory Protection Program + // Enable 0 +#define FLASH_FMPPE1 0x400FE404 // Flash Memory Protection Program + // Enable 1 +#define FLASH_FMPPE2 0x400FE408 // Flash Memory Protection Program + // Enable 2 +#define FLASH_FMPPE3 0x400FE40C // Flash Memory Protection Program + // Enable 3 +#define FLASH_FMPPE4 0x400FE410 // Flash Memory Protection Program + // Enable 4 +#define FLASH_FMPPE5 0x400FE414 // Flash Memory Protection Program + // Enable 5 +#define FLASH_FMPPE6 0x400FE418 // Flash Memory Protection Program + // Enable 6 +#define FLASH_FMPPE7 0x400FE41C // Flash Memory Protection Program + // Enable 7 +#define FLASH_FMPPE8 0x400FE420 // Flash Memory Protection Program + // Enable 8 +#define FLASH_FMPPE9 0x400FE424 // Flash Memory Protection Program + // Enable 9 +#define FLASH_FMPPE10 0x400FE428 // Flash Memory Protection Program + // Enable 10 +#define FLASH_FMPPE11 0x400FE42C // Flash Memory Protection Program + // Enable 11 +#define FLASH_FMPPE12 0x400FE430 // Flash Memory Protection Program + // Enable 12 +#define FLASH_FMPPE13 0x400FE434 // Flash Memory Protection Program + // Enable 13 +#define FLASH_FMPPE14 0x400FE438 // Flash Memory Protection Program + // Enable 14 +#define FLASH_FMPPE15 0x400FE43C // Flash Memory Protection Program + // Enable 15 + +#define FLASH_USECRL 0x400FE140 // USec Reload +#define FLASH_CTRL_ERASE_SIZE 0x00000400 + + +#endif // __HW_FLASH_CTRL_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gpio.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gpio.h new file mode 100755 index 0000000..2bd6e0f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gpio.h @@ -0,0 +1,1349 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_GPIO_H__ +#define __HW_GPIO_H__ + +//***************************************************************************** +// +// The following are defines for the GPIO register offsets. +// +//***************************************************************************** +#define GPIO_O_GPIO_DATA 0x00000000 // 0x4000 5000 0x4000 6000 0x4000 + // 7000 0x4002 4000 GPIO Data + // (GPIODATA)@@ offset 0x000 The + // GPIODATA register is the data + // register. In software control + // mode@@ values written in the + // GPIODATA register are transferred + // onto the GPIO port pins if the + // respective pins have been + // configured as outputs through the + // GPIO Direction (GPIODIR) register + // (see page 653). In order to write + // to GPIODATA@@ the corresponding + // bits in the mask@@ resulting from + // the address bus bits [9:2]@@ must + // be set. Otherwise@@ the bit + // values remain unchanged by the + // write. Similarly@@ the values + // read from this register are + // determined for each bit by the + // mask bit derived from the address + // used to access the data + // register@@ bits [9:2]. Bits that + // are set in the address mask cause + // the corresponding bits in + // GPIODATA to be read@@ and bits + // that are clear in the address + // mask cause the corresponding bits + // in GPIODATA to be read as 0@@ + // regardless of their value. A read + // from GPIODATA returns the last + // bit value written if the + // respective pins are configured as + // outputs@@ or it returns the value + // on the corresponding input pin + // when these are configured as + // inputs. All bits are cleared by a + // reset. +#define GPIO_O_GPIO_DIR 0x00000400 // 0x4000 5400 0x4000 6400 0x4000 + // 7400 0x4002 4400 GPIO Direction + // (GPIODIR)@@ offset 0x400 The + // GPIODIR register is the data + // direction register. Setting a bit + // in the GPIODIR register + // configures the corresponding pin + // to be an output@@ while clearing + // a bit configures the + // corresponding pin to be an input. + // All bits are cleared by a reset@@ + // meaning all GPIO pins are inputs + // by default. +#define GPIO_O_GPIO_IS 0x00000404 // 0x4000 5404 0x4000 6404 0x4000 + // 7404 0x4002 4404 GPIO Interrupt + // Sense (GPIOIS)@@ offset 0x404 The + // GPIOIS register is the interrupt + // sense register. Setting a bit in + // the GPIOIS register configures + // the corresponding pin to detect + // levels@@ while clearing a bit + // configures the corresponding pin + // to detect edges. All bits are + // cleared by a reset. +#define GPIO_O_GPIO_IBE 0x00000408 // 0x4000 5408 0x4000 6408 0x4000 + // 7408 0x4002 4408 GPIO Interrupt + // Both Edges (GPIOIBE)@@ offset + // 0x408 The GPIOIBE register allows + // both edges to cause interrupts. + // When the corresponding bit in the + // GPIO Interrupt Sense (GPIOIS) + // register is set to detect edges@@ + // setting a bit in the GPIOIBE + // register configures the + // corresponding pin to detect both + // rising and falling edges@@ + // regardless of the corresponding + // bit in the GPIO Interrupt Event + // (GPIOIEV) register . Clearing a + // bit configures the pin to be + // controlled by the GPIOIEV + // register. All bits are cleared by + // a reset. +#define GPIO_O_GPIO_IEV 0x0000040C // 0x4000 540C 0x4000 640C 0x4000 + // 740C 0x4002 440C GPIO Interrupt + // Event (GPIOIEV)@@ offset 0x40C + // The GPIOIEV register is the + // interrupt event register. Setting + // a bit in the GPIOIEV register + // configures the corresponding pin + // to detect rising edges or high + // levels@@ depending on the + // corresponding bit value in the + // GPIO Interrupt Sense (GPIOIS) + // register . Clearing a bit + // configures the pin to detect + // falling edges or low levels@@ + // depending on the corresponding + // bit value in the GPIOIS register. + // All bits are cleared by a reset. +#define GPIO_O_GPIO_IM 0x00000410 // 0x4000 5410 0x4000 6410 0x4000 + // 7410 0x4002 4410 GPIO Interrupt + // Mask (GPIOIM)@@ offset 0x410 The + // GPIOIM register is the interrupt + // mask register. Setting a bit in + // the GPIOIM register allows + // interrupts that are generated by + // the corresponding pin to be sent + // to the interrupt controller on + // the combined interrupt signal. + // Clearing a bit prevents an + // interrupt on the corresponding + // pin from being sent to the + // interrupt controller. All bits + // are cleared by a reset. +#define GPIO_O_GPIO_RIS 0x00000414 // 0x4000 5414 0x4000 6414 0x4000 + // 7414 0x4002 4414 GPIO Raw + // Interrupt Status (GPIORIS)@@ + // offset 0x414 The GPIORIS register + // is the raw interrupt status + // register. A bit in this register + // is set when an interrupt + // condition occurs on the + // corresponding GPIO pin. If the + // corresponding bit in the GPIO + // Interrupt Mask (GPIOIM) register + // is set@@ the interrupt is sent to + // the interrupt controller. Bits + // read as zero indicate that + // corresponding input pins have not + // initiated an interrupt. A bit in + // this register can be cleared by + // writing a 1 to the corresponding + // bit in the GPIO Interrupt Clear + // (GPIOICR) register. +#define GPIO_O_GPIO_MIS 0x00000418 // 0x4000 5418 0x4000 6418 0x4000 + // 7418 0x4002 4418 GPIO Masked + // Interrupt Status (GPIOMIS)@@ + // offset 0x418 The GPIOMIS register + // is the masked interrupt status + // register. If a bit is set in this + // register@@ the corresponding + // interrupt has triggered an + // interrupt to the interrupt + // controller. If a bit is clear@@ + // either no interrupt has been + // generated@@ or the interrupt is + // masked. If no port pin@@ other + // than the one that is being used + // as an ADC trigger@@ is being used + // to generate interrupts@@ the + // appropriate Interrupt Set Enable + // (ENn) register can disable the + // interrupts for the port@@ and the + // ADC interrupt can be used to read + // back the converted data. + // Otherwise@@ the port interrupt + // handler must ignore and clear + // interrupts on the port pin and + // wait for the ADC interrupt@@ or + // the ADC interrupt must be + // disabled in the EN0 register and + // the port interrupt handler must + // poll the ADC registers until the + // conversion is completed. If no + // port pin@@ other than the one + // that is being used as an ADC + // trigger@@ is being used to + // generate interrupts@@ the + // appropriate Interrupt Set Enable + // (ENn) register can disable the + // interrupts for the port@@ and the + // ADC interrupt can be used to read + // back the converted data. + // Otherwise@@ the port interrupt + // handler must ignore and clear + // interrupts on the port pin and + // wait for the ADC interrupt@@ or + // the ADC interrupt must be + // disabled in the EN0 register and + // the port interrupt handler must + // poll the ADC registers until the + // conversion is completed. Note + // that if the Port B GPIOADCCTL + // register is cleared@@ PB4 can + // still be used as an external + // trigger for the ADC. This is a + // legacy mode which allows code + // written for previous Stellaris + // devices to operate on this + // microcontroller. GPIOMIS is the + // state of the interrupt after + // masking. +#define GPIO_O_GPIO_ICR 0x0000041C // 0x4000 541C 0x4000 641C 0x4000 + // 741C 0x4002 441C GPIO Interrupt + // Clear (GPIOICR)@@ offset 0x41C + // The GPIOICR register is the + // interrupt clear register. Writing + // a 1 to a bit in this register + // clears the corresponding + // interrupt bit in the GPIORIS and + // GPIOMIS registers. Writing a 0 + // has no effect. +#define GPIO_O_GPIO_AFSEL 0x00000420 // 0x4000 5420 0x4000 6420 0x4000 + // 7420 0x4002 4420 GPIO Alternate + // Function Select (GPIOAFSEL)@@ + // offset 0x420 The GPIOAFSEL + // register is the mode control + // select register. If a bit is + // clear@@ the pin is used as a GPIO + // and is controlled by the GPIO + // registers. Setting a bit in this + // register configures the + // corresponding GPIO line to be + // controlled by an associated + // peripheral. Several possible + // peripheral functions are + // multiplexed on each GPIO. The + // GPIO Port Control (GPIOPCTL) + // register is used to select one of + // the possible functions. +#define GPIO_O_GPIO_DR2R 0x00000500 // 0x4000 5500 0x4000 6500 0x4000 + // 7500 0x4002 4500 GPIO 2-mA Drive + // Select (GPIODR2R)@@ offset 0x500 + // The GPIODR2R register is the 2-mA + // drive control register. Each GPIO + // signal in the port can be + // individually configured without + // affecting the other pads. When + // setting the DRV2 bit for a GPIO + // signal@@ the corresponding DRV4 + // bit in the GPIODR4R register and + // DRV8 bit in the GPIODR8R register + // are automatically cleared by + // hardware. By default@@ all GPIO + // pins have 2-mA drive. +#define GPIO_O_GPIO_DR4R 0x00000504 // 0x4000 5504 0x4000 6504 0x4000 + // 7504 0x4002 4504 GPIO 4-mA Drive + // Select (GPIODR4R)@@ offset 0x504 + // The GPIODR4R register is the 4-mA + // drive control register. Each GPIO + // signal in the port can be + // individually configured without + // affecting the other pads. When + // setting the DRV4 bit for a GPIO + // signal@@ the corresponding DRV2 + // bit in the GPIODR2R register and + // DRV8 bit in the GPIODR8R register + // are automatically cleared by + // hardware. +#define GPIO_O_GPIO_DR8R 0x00000508 // 0x4000 5508 0x4000 6508 0x4000 + // 7508 0x4002 4508 GPIO 8-mA Drive + // Select (GPIODR8R)@@ offset 0x508 + // The GPIODR8R register is the 8-mA + // drive control register. Each GPIO + // signal in the port can be + // individually configured without + // affecting the other pads. When + // setting the DRV8 bit for a GPIO + // signal@@ the corresponding DRV2 + // bit in the GPIODR2R register and + // DRV4 bit in the GPIODR4R register + // are automatically cleared by + // hardware. The 8-mA setting is + // also used for high-current + // operation. Note: There is no + // configuration difference between + // 8-mA and high-current operation. + // The additional current capacity + // results from a shift in the + // VOH/VOL levels. +#define GPIO_O_GPIO_ODR 0x0000050C // 0x4000 550C 0x4000 650C 0x4000 + // 750C 0x4002 450C GPIO Open Drain + // Select (GPIOODR)@@ offset 0x50C + // The GPIOODR register is the open + // drain control register. Setting a + // bit in this register enables the + // open-drain configuration of the + // corresponding GPIO pad. When + // open-drain mode is enabled@@ the + // corresponding bit should also be + // set in the GPIO Digital Input + // Enable (GPIODEN) register . + // Corresponding bits in the drive + // strength and slew rate control + // registers (GPIODR2R@@ GPIODR4R@@ + // GPIODR8R@@ and GPIOSLR) can be + // set to achieve the desired rise + // and fall times. The GPIO acts as + // an open-drain input if the + // corresponding bit in the GPIODIR + // register is cleared. If open + // drain is selected while the GPIO + // is configured as an input@@ the + // GPIO will remain an input and the + // open-drain selection has no + // effect until the GPIO is changed + // to an output. When using the I2C + // module@@ in addition to + // configuring the pin to open + // drain@@ the GPIO Alternate + // Function Select (GPIOAFSEL) + // register bits for the I2C clock + // and data pins should be set +#define GPIO_O_GPIO_PUR 0x00000510 // 0x4000 5510 0x4000 6510 0x4000 + // 7510 0x4002 4510 GPIO Pull-Up + // Select (GPIOPUR)@@ offset 0x510 + // The GPIOPUR register is the + // pull-up control register. When a + // bit is set@@ a weak pull-up + // resistor on the corresponding + // GPIO signal is enabled. Setting a + // bit in GPIOPUR automatically + // clears the corresponding bit in + // the GPIO Pull-Down Select + // (GPIOPDR) register . Write access + // to this register is protected + // with the GPIOCR register. Bits in + // GPIOCR that are cleared prevent + // writes to the equivalent bit in + // this register. +#define GPIO_O_GPIO_PDR 0x00000514 // 0x4000 5514 0x4000 6514 0x4000 + // 7514 0x4002 4514 GPIO Pull-Down + // Select (GPIOPDR)@@ offset 0x514 + // The GPIOPDR register is the + // pull-down control register. When + // a bit is set@@ a weak pull-down + // resistor on the corresponding + // GPIO signal is enabled. Setting a + // bit in GPIOPDR automatically + // clears the corresponding bit in + // the GPIO Pull-Up Select (GPIOPUR) + // register +#define GPIO_O_GPIO_SLR 0x00000518 // 0x4000 5518 0x4000 6518 0x4000 + // 7518 0x4002 4518 The GPIOSLR + // register is the slew rate control + // register. Slew rate control is + // only available when using the + // 8-mA drive strength option via + // the GPIO 8-mA Drive Select + // (GPIODR8R) register +#define GPIO_O_GPIO_DEN 0x0000051C // 0x4000 551C 0x4000 651C 0x4000 + // 751C 0x4002 451C GPIO Digital + // Enable (GPIODEN)@@ offset 0x51C + // Note: Pins configured as digital + // inputs are Schmitt-triggered. The + // GPIODEN register is the digital + // enable register. By default@@ all + // GPIO signals except those listed + // below are configured out of reset + // to be undriven (tristate). Their + // digital function is disabled; + // they do not drive a logic value + // on the pin and they do not allow + // the pin voltage into the GPIO + // receiver. To use the pin as a + // digital input or output (either + // GPIO or alternate function)@@ the + // corresponding GPIODEN bit must be + // set. +#define GPIO_O_GPIO_LOCK 0x00000520 // 0x4000 5520 0x4000 6520 0x4000 + // 7520 0x4002 4520 GPIO Lock + // (GPIOLOCK)@@ offset 0x520 The + // GPIOLOCK register enables write + // access to the GPIOCR register . + // Writing 0x4C4F.434B to the + // GPIOLOCK register unlocks the + // GPIOCR register. Writing any + // other value to the GPIOLOCK + // register re-enables the locked + // state. Reading the GPIOLOCK + // register returns the lock status + // rather than the 32-bit value that + // was previously written. + // Therefore@@ when write accesses + // are disabled@@ or locked@@ + // reading the GPIOLOCK register + // returns 0x0000.0001. When write + // accesses are enabled@@ or + // unlocked@@ reading the GPIOLOCK + // register returns 0x0000.0000. +#define GPIO_O_GPIO_CR 0x00000524 // 0x4000 5524 0x4000 6524 0x4000 + // 7524 0x4002 4524 GPIO Commit + // (GPIOCR)@@ offset 0x524 The + // GPIOCR register is the commit + // register. The value of the GPIOCR + // register determines which bits of + // the GPIOAFSEL@@ GPIOPUR@@ + // GPIOPDR@@ and GPIODEN registers + // are committed when a write to + // these registers is performed. If + // a bit in the GPIOCR register is + // cleared@@ the data being written + // to the corresponding bit in the + // GPIOAFSEL@@ GPIOPUR@@ GPIOPDR@@ + // or GPIODEN registers cannot be + // committed and retains its + // previous value. If a bit in the + // GPIOCR register is set@@ the data + // being written to the + // corresponding bit of the + // GPIOAFSEL@@ GPIOPUR@@ GPIOPDR@@ + // or GPIODEN registers is committed + // to the register and reflects the + // new value. The contents of the + // GPIOCR register can only be + // modified if the status in the + // GPIOLOCK register is unlocked. + // Writes to the GPIOCR register are + // ignored if the status in the + // GPIOLOCK register is locked. +#define GPIO_O_GPIO_AMSEL 0x00000528 // 0x4000 5528 0x4000 6528 0x4000 + // 7528 0x4002 4528 The GPIOAMSEL + // register controls isolation + // circuits to the analog side of a + // unified I/O pad. Because the + // GPIOs may be driven by a 5-V + // source and affect analog + // operation@@ analog circuitry + // requires isolation from the pins + // when they are not used in their + // analog function. Each bit of this + // register controls the isolation + // circuitry for the corresponding + // GPIO signal. +#define GPIO_O_GPIO_PCTL 0x0000052C // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) 0x4000 552C + // 0x4000 652C 0x4000 752C 0x4002 + // 452C GPIO Port Control + // (GPIOPCTL)@@ offset 0x52C The + // GPIOPCTL register is used in + // conjunction with the GPIOAFSEL + // register and selects the specific + // peripheral signal for each GPIO + // pin when using the alternate + // function mode. Most bits in the + // GPIOAFSEL register are cleared on + // reset@@ therefore most GPIO pins + // are configured as GPIOs by + // default. When a bit is set in the + // GPIOAFSEL register@@ the + // corresponding GPIO signal is + // controlled by an associated + // peripheral. The GPIOPCTL register + // selects one out of a set of + // peripheral functions for each + // GPIO@@ providing additional + // flexibility in signal definition. +#define GPIO_O_GPIO_ADCCTL 0x00000530 // This register is not used in + // cc3xx. ADC trigger via GPIO is + // not supported. 0x4000 5530 0x4000 + // 6530 0x4000 7530 0x4002 4530 GPIO + // ADC Control (GPIOADCCTL)@@ offset + // 0x530 This register is used to + // configure a GPIO pin as a source + // for the ADC trigger. Note that if + // the Port B GPIOADCCTL register is + // cleared@@ PB4 can still be used + // as an external trigger for the + // ADC. This is a legacy mode which + // allows code written for previous + // Stellaris devices to operate on + // this microcontroller. +#define GPIO_O_GPIO_DMACTL 0x00000534 // 0x4000 5534 0x4000 6534 0x4000 + // 7534 0x4002 4534 GPIO DMA Control + // (GPIODMACTL)@@ offset 0x534 This + // register is used to configure a + // GPIO pin as a source for the ?DMA + // trigger. +#define GPIO_O_GPIO_SI 0x00000538 // 0x4000 5538 0x4000 6538 0x4000 + // 7538 0x4002 4538 GPIO Select + // Interrupt (GPIOSI)@@ offset 0x538 + // This register is used to enable + // individual interrupts for each + // pin. Note: This register is only + // available on Port P and Port Q. +#define GPIO_O_GPIO_PERIPHID4 0x00000FD0 // 0x4000 5FD0 0x4000 6FD0 0x4000 + // 7FD0 0x4002 4FD0 GPIO Peripheral + // Identification 4 + // (GPIOPeriphID4)@@ offset 0xFD0 + // The GPIOPeriphID4@@ + // GPIOPeriphID5@@ GPIOPeriphID6@@ + // and GPIOPeriphID7 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID5 0x00000FD4 // 0x4000 5FD4 0x4000 6FD4 0x4000 + // 7FD4 0x4002 4FD4 GPIO Peripheral + // Identification 5 + // (GPIOPeriphID5)@@ offset 0xFD4 + // The GPIOPeriphID4@@ + // GPIOPeriphID5@@ GPIOPeriphID6@@ + // and GPIOPeriphID7 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID6 0x00000FD8 // 0x4000 5FD8 0x4000 6FD8 0x4000 + // 7FD8 0x4002 4FD8 GPIO Peripheral + // Identification 6 + // (GPIOPeriphID6)@@ offset 0xFD8 + // The GPIOPeriphID4@@ + // GPIOPeriphID5@@ GPIOPeriphID6@@ + // and GPIOPeriphID7 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID7 0x00000FDC // 0x4000 5FDC 0x4000 6FDC 0x4000 + // 7FDC 0x4002 4FDC GPIO Peripheral + // Identification 7 + // (GPIOPeriphID7)@@ offset 0xFDC + // The GPIOPeriphID4@@ + // GPIOPeriphID5@@ GPIOPeriphID6@@ + // and GPIOPeriphID7 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID0 0x00000FE0 // 0x4000 5FE0 0x4000 6FE0 0x4000 + // 7FE0 0x4002 4FE0 GPIO Peripheral + // Identification 0 + // (GPIOPeriphID0)@@ offset 0xFE0 + // The GPIOPeriphID0@@ + // GPIOPeriphID1@@ GPIOPeriphID2@@ + // and GPIOPeriphID3 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID1 0x00000FE4 // 0x4000 5FE4 0x4000 6FE4 0x4000 + // 7FE4 0x4002 4FE4 GPIO Peripheral + // Identification 1 + // (GPIOPeriphID1)@@ offset 0xFE4 + // The GPIOPeriphID0@@ + // GPIOPeriphID1@@ GPIOPeriphID2@@ + // and GPIOPeriphID3 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID2 0x00000FE8 // 0x4000 5FE8 0x4000 6FE8 0x4000 + // 7FE8 0x4002 4FE8 GPIO Peripheral + // Identification 2 + // (GPIOPeriphID2)@@ offset 0xFE8 + // The GPIOPeriphID0@@ + // GPIOPeriphID1@@ GPIOPeriphID2@@ + // and GPIOPeriphID3 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PERIPHID3 0x00000FEC // 0x4000 5FEC 0x4000 6FEC 0x4000 + // 7FEC 0x4002 4FEC GPIO Peripheral + // Identification 3 + // (GPIOPeriphID3)@@ offset 0xFEC + // The GPIOPeriphID0@@ + // GPIOPeriphID1@@ GPIOPeriphID2@@ + // and GPIOPeriphID3 registers can + // conceptually be treated as one + // 32-bit register; each register + // contains eight bits of the 32-bit + // register@@ used by software to + // identify the peripheral. +#define GPIO_O_GPIO_PCELLID0 0x00000FF0 // 0x4000 5FF0 0x4000 6FF0 0x4000 + // 7FF0 0x4002 4FF0 GPIO PrimeCell + // Identification 0 (GPIOPCellID0)@@ + // offset 0xFF0 The GPIOPCellID0@@ + // GPIOPCellID1@@ GPIOPCellID2@@ and + // GPIOPCellID3 registers are four + // 8-bit wide registers@@ that can + // conceptually be treated as one + // 32-bit register. The register is + // used as a standard + // cross-peripheral identification + // system. +#define GPIO_O_GPIO_PCELLID1 0x00000FF4 // 0x4000 5FF4 0x4000 6FF4 0x4000 + // 7FF4 0x4002 4FF4 GPIO PrimeCell + // Identification 1 (GPIOPCellID1)@@ + // offset 0xFF4 The GPIOPCellID0@@ + // GPIOPCellID1@@ GPIOPCellID2@@ and + // GPIOPCellID3 registers are four + // 8-bit wide registers@@ that can + // conceptually be treated as one + // 32-bit register. The register is + // used as a standard + // cross-peripheral identification + // system. +#define GPIO_O_GPIO_PCELLID2 0x00000FF8 // 0x4000 5FF8 0x4000 6FF8 0x4000 + // 7FF8 0x4002 4FF8 GPIO PrimeCell + // Identification 2 (GPIOPCellID2)@@ + // offset 0xFF8 The GPIOPCellID0@@ + // GPIOPCellID1@@ GPIOPCellID2@@ and + // GPIOPCellID3 registers are four + // 8-bit wide registers@@ that can + // conceptually be treated as one + // 32-bit register. The register is + // used as a standard + // cross-peripheral identification + // system. +#define GPIO_O_GPIO_PCELLID3 0x00000FFC // 0x4000 5FFC 0x4000 6FFC 0x4000 + // 7FFC 0x4002 4FFC GPIO PrimeCell + // Identification 3 (GPIOPCellID3)@@ + // offset 0xFFC The GPIOPCellID0@@ + // GPIOPCellID1@@ GPIOPCellID2@@ and + // GPIOPCellID3 registers are four + // 8-bit wide registers@@ that can + // conceptually be treated as one + // 32-bit register. The register is + // used as a standard + // cross-peripheral identification + // system.0xb1 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DATA register. +// +//****************************************************************************** +#define GPIO_GPIO_DATA_DATA_M 0x000000FF // GPIO Data This register is + // virtually mapped to 256 locations + // in the address space. To + // facilitate the reading and + // writing of data to these + // registers by independent + // drivers@@ the data read from and + // written to the registers are + // masked by the eight address lines + // [9:2]. Reads from this register + // return its current state. Writes + // to this register only affect bits + // that are not masked by ADDR[9:2] + // and are configured as outputs. +#define GPIO_GPIO_DATA_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DIR register. +// +//****************************************************************************** +#define GPIO_GPIO_DIR_DIR_M 0x000000FF // GPIO Data Direction Value + // Description 0 Corresponding pin + // is an input. 1 Corresponding pins + // is an output. +#define GPIO_GPIO_DIR_DIR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_IS register. +// +//****************************************************************************** +#define GPIO_GPIO_IS_IS_M 0x000000FF // GPIO Interrupt Sense Value + // Description 0 The edge on the + // corresponding pin is detected + // (edge-sensitive). 1 The level on + // the corresponding pin is detected + // (level-sensitive). +#define GPIO_GPIO_IS_IS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_IBE register. +// +//****************************************************************************** +#define GPIO_GPIO_IBE_IBE_M 0x000000FF // GPIO Interrupt Both Edges Value + // Description 0 Interrupt + // generation is controlled by the + // GPIO Interrupt Event (GPIOIEV) + // register. 1 Both edges on the + // corresponding pin trigger an + // interrupt. +#define GPIO_GPIO_IBE_IBE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_IEV register. +// +//****************************************************************************** +#define GPIO_GPIO_IEV_IEV_M 0x000000FF // GPIO Interrupt Event Value + // Description 1 A falling edge or a + // Low level on the corresponding + // pin triggers an interrupt. 0 A + // rising edge or a High level on + // the corresponding pin triggers an + // interrupt. +#define GPIO_GPIO_IEV_IEV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_IM register. +// +//****************************************************************************** +#define GPIO_GPIO_IM_IME_M 0x000000FF // GPIO Interrupt Mask Enable Value + // Description 0 The interrupt from + // the corresponding pin is masked. + // 1 The interrupt from the + // corresponding pin is sent to the + // interrupt controller. +#define GPIO_GPIO_IM_IME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_RIS register. +// +//****************************************************************************** +#define GPIO_GPIO_RIS_RIS_M 0x000000FF // GPIO Interrupt Raw Status Value + // Description 1 An interrupt + // condition has occurred on the + // corresponding pin. 0 interrupt + // condition has not occurred on the + // corresponding pin. A bit is + // cleared by writing a 1 to the + // corresponding bit in the GPIOICR + // register. +#define GPIO_GPIO_RIS_RIS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_MIS register. +// +//****************************************************************************** +#define GPIO_GPIO_MIS_MIS_M 0x000000FF // GPIO Masked Interrupt Status + // Value Description 1 An interrupt + // condition on the corresponding + // pin has triggered an interrupt to + // the interrupt controller. 0 An + // interrupt condition on the + // corresponding pin is masked or + // has not occurred. A bit is + // cleared by writing a 1 to the + // corresponding bit in the GPIOICR + // register. +#define GPIO_GPIO_MIS_MIS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_ICR register. +// +//****************************************************************************** +#define GPIO_GPIO_ICR_IC_M 0x000000FF // GPIO Interrupt Clear Value + // Description 1 The corresponding + // interrupt is cleared. 0 The + // corresponding interrupt is + // unaffected. +#define GPIO_GPIO_ICR_IC_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_AFSEL register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DR2R register. +// +//****************************************************************************** +#define GPIO_GPIO_DR2R_DRV2_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Output Pad + // 2-mA Drive Enable Value + // Description 1 The corresponding + // GPIO pin has 2-mA drive. The + // drive for the corresponding GPIO + // pin is controlled by the GPIODR4R + // or GPIODR8R register. 0 Setting a + // bit in either the GPIODR4 + // register or the GPIODR8 register + // clears the corresponding 2-mA + // enable bit. The change is + // effective on the second clock + // cycle after the write if + // accessing GPIO via the APB memory + // aperture. If using AHB access@@ + // the change is effective on the + // next clock cycle. +#define GPIO_GPIO_DR2R_DRV2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DR4R register. +// +//****************************************************************************** +#define GPIO_GPIO_DR4R_DRV4_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Output Pad + // 4-mA Drive Enable Value + // Description 1 The corresponding + // GPIO pin has 4-mA drive. The + // drive for the corresponding GPIO + // pin is controlled by the GPIODR2R + // or GPIODR8R register. 0 Setting a + // bit in either the GPIODR2 + // register or the GPIODR8 register + // clears the corresponding 4-mA + // enable bit. The change is + // effective on the second clock + // cycle after the write if + // accessing GPIO via the APB memory + // aperture. If using AHB access@@ + // the change is effective on the + // next clock cycle. +#define GPIO_GPIO_DR4R_DRV4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DR8R register. +// +//****************************************************************************** +#define GPIO_GPIO_DR8R_DRV8_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Output Pad + // 8-mA Drive Enable Value + // Description 1 The corresponding + // GPIO pin has 8-mA drive. The + // drive for the corresponding GPIO + // pin is controlled by the GPIODR2R + // or GPIODR4R register. 0 Setting a + // bit in either the GPIODR2 + // register or the GPIODR4 register + // clears the corresponding 8-mA + // enable bit. The change is + // effective on the second clock + // cycle after the write if + // accessing GPIO via the APB memory + // aperture. If using AHB access@@ + // the change is effective on the + // next clock cycle. +#define GPIO_GPIO_DR8R_DRV8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_ODR register. +// +//****************************************************************************** +#define GPIO_GPIO_ODR_ODE_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Output Pad + // Open Drain Enable Value + // Description 1 The corresponding + // pin is configured as open drain. + // 0 The corresponding pin is not + // configured as open drain. +#define GPIO_GPIO_ODR_ODE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_PUR register. +// +//****************************************************************************** +#define GPIO_GPIO_PUR_PUE_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Pad Weak + // Pull-Up Enable Value Description + // 1 The corresponding pin has a + // weak pull-up resistor. 0 The + // corresponding pin is not + // affected. Setting a bit in the + // GPIOPDR register clears the + // corresponding bit in the GPIOPUR + // register. The change is effective + // on the second clock cycle after + // the write if accessing GPIO via + // the APB memory aperture. If using + // AHB access@@ the change is + // effective on the next clock + // cycle. +#define GPIO_GPIO_PUR_PUE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_PDR register. +// +//****************************************************************************** +#define GPIO_GPIO_PDR_PDE_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Pad Weak + // Pull-Down Enable Value + // Description 1 The corresponding + // pin has a weak pull-down + // resistor. 0 The corresponding pin + // is not affected. Setting a bit in + // the GPIOPUR register clears the + // corresponding bit in the GPIOPDR + // register. The change is effective + // on the second clock cycle after + // the write if accessing GPIO via + // the APB memory aperture. If using + // AHB access@@ the change is + // effective on the next clock + // cycle. +#define GPIO_GPIO_PDR_PDE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_SLR register. +// +//****************************************************************************** +#define GPIO_GPIO_SLR_SRL_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Slew Rate + // Limit Enable (8-mA drive only) + // Value Description 1 Slew rate + // control is enabled for the + // corresponding pin. 0 Slew rate + // control is disabled for the + // corresponding pin. +#define GPIO_GPIO_SLR_SRL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_DEN register. +// +//****************************************************************************** +#define GPIO_GPIO_DEN_DEN_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Digital Enable + // Value Description 0 The digital + // functions for the corresponding + // pin are disabled. 1 The digital + // functions for the corresponding + // pin are enabled. +#define GPIO_GPIO_DEN_DEN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_LOCK register. +// +//****************************************************************************** +#define GPIO_GPIO_LOCK_LOCK_M 0xFFFFFFFF // This register is not used in + // cc3xx. GPIO Lock A write of the + // value 0x4C4F.434B unlocks the + // GPIO Commit (GPIOCR) register for + // write access.A write of any other + // value or a write to the GPIOCR + // register reapplies the lock@@ + // preventing any register updates. + // A read of this register returns + // the following values: Value + // Description 0x1 The GPIOCR + // register is locked and may not be + // modified. 0x0 The GPIOCR register + // is unlocked and may be modified. +#define GPIO_GPIO_LOCK_LOCK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_CR register. +// +//****************************************************************************** +#define GPIO_GPIO_CR_CR_M 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) GPIO Commit + // Value Description The + // corresponding GPIOAFSEL@@ + // GPIOPUR@@ GPIOPDR@@ or GPIODEN + // bits can be written. 1 The + // corresponding GPIOAFSEL@@ + // GPIOPUR@@ GPIOPDR@@ or GPIODEN + // bits cannot be written. 0 Note: + // The default register type for the + // GPIOCR register is RO for all + // GPIO pins with the exception of + // the NMI pin and the four JTAG/SWD + // pins (PD7@@ PF0@@ and PC[3:0]). + // These six pins are the only GPIOs + // that are protected by the GPIOCR + // register. Because of this@@ the + // register type for GPIO Port D7@@ + // GPIO Port F0@@ and GPIO Port + // C[3:0] is R/W. The default reset + // value for the GPIOCR register is + // 0x0000.00FF for all GPIO pins@@ + // with the exception of the NMI pin + // and the four JTAG/SWD pins (PD7@@ + // PF0@@ and PC[3:0]). To ensure + // that the JTAG port is not + // accidentally programmed as GPIO + // pins@@ the PC[3:0] pins default + // to non-committable. Similarly@@ + // to ensure that the NMI pin is not + // accidentally programmed as a GPIO + // pin@@ the PD7 and PF0 pins + // default to non-committable. + // Because of this@@ the default + // reset value of GPIOCR for GPIO + // Port C is 0x0000.00F0@@ for GPIO + // Port D is 0x0000.007F@@ and for + // GPIO Port F is 0x0000.00FE. +#define GPIO_GPIO_CR_CR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_AMSEL register. +// +//****************************************************************************** +#define GPIO_GPIO_AMSEL_GPIO_AMSEL_M \ + 0x000000FF // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) GPIO Analog + // Mode Select Value Description 1 + // The analog function of the pin is + // enabled@@ the isolation is + // disabled@@ and the pin is capable + // of analog functions. 0 The analog + // function of the pin is disabled@@ + // the isolation is enabled@@ and + // the pin is capable of digital + // functions as specified by the + // other GPIO configuration + // registers. Note: This register + // and bits are only valid for GPIO + // signals that share analog + // function through a unified I/O + // pad. The reset state of this + // register is 0 for all signals. + +#define GPIO_GPIO_AMSEL_GPIO_AMSEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_PCTL register. +// +//****************************************************************************** +#define GPIO_GPIO_PCTL_PMC7_M 0xF0000000 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 7 This field controls the + // configuration for GPIO pin 7. +#define GPIO_GPIO_PCTL_PMC7_S 28 +#define GPIO_GPIO_PCTL_PMC6_M 0x0F000000 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 6 This field controls the + // configuration for GPIO pin 6. +#define GPIO_GPIO_PCTL_PMC6_S 24 +#define GPIO_GPIO_PCTL_PMC5_M 0x00F00000 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 5 This field controls the + // configuration for GPIO pin 5. +#define GPIO_GPIO_PCTL_PMC5_S 20 +#define GPIO_GPIO_PCTL_PMC4_M 0x000F0000 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 4 This field controls the + // configuration for GPIO pin 4. +#define GPIO_GPIO_PCTL_PMC4_S 16 +#define GPIO_GPIO_PCTL_PMC3_M 0x0000F000 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 43 This field controls + // the configuration for GPIO pin 3. +#define GPIO_GPIO_PCTL_PMC3_S 12 +#define GPIO_GPIO_PCTL_PMC1_M 0x00000F00 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 1 This field controls the + // configuration for GPIO pin 1. +#define GPIO_GPIO_PCTL_PMC1_S 8 +#define GPIO_GPIO_PCTL_PMC2_M 0x000000F0 // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 2 This field controls the + // configuration for GPIO pin 2. +#define GPIO_GPIO_PCTL_PMC2_S 4 +#define GPIO_GPIO_PCTL_PMC0_M 0x0000000F // This register is not used in + // cc3xx. equivalant register exsist + // outside GPIO IP (refer + // PAD*_config register in the + // shared comn space) Port Mux + // Control 0 This field controls the + // configuration for GPIO pin 0. +#define GPIO_GPIO_PCTL_PMC0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_ADCCTL register. +// +//****************************************************************************** +#define GPIO_GPIO_ADCCTL_ADCEN_M \ + 0x000000FF // This register is not used in + // cc3xx. ADC trigger via GPIO is + // not supported. ADC Trigger Enable + // Value Description 1 The + // corresponding pin is used to + // trigger the ADC. 0 The + // corresponding pin is not used to + // trigger the ADC. + +#define GPIO_GPIO_ADCCTL_ADCEN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_DMACTL register. +// +//****************************************************************************** +#define GPIO_GPIO_DMACTL_DMAEN_M \ + 0x000000FF // This register is not used in the + // cc3xx. Alternate register to + // support this feature is coded in + // the APPS_NWP_CMN space. refer + // register as offset 0x400F70D8 + // ?DMA Trigger Enable Value + // Description 1 The corresponding + // pin is used to trigger the ?DMA. + // 0 The corresponding pin is not + // used to trigger the ?DMA. + +#define GPIO_GPIO_DMACTL_DMAEN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPIO_O_GPIO_SI register. +// +//****************************************************************************** +#define GPIO_GPIO_SI_SUM 0x00000001 // Summary Interrupt Value + // Description 1 Each pin has its + // own interrupt vector. 0 All port + // pin interrupts are OR'ed together + // to produce a summary interrupt. +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID4 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID4_PID4_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [7:0] + +#define GPIO_GPIO_PERIPHID4_PID4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID5 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID5_PID5_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [15:8] + +#define GPIO_GPIO_PERIPHID5_PID5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID6 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID6_PID6_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [23:16] + +#define GPIO_GPIO_PERIPHID6_PID6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID7 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID7_PID7_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [31:24] + +#define GPIO_GPIO_PERIPHID7_PID7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID0 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID0_PID0_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [7:0] Can be used by + // software to identify the presence + // of this peripheral. + +#define GPIO_GPIO_PERIPHID0_PID0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID1 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID1_PID1_M \ + 0x000000FF // GPIO Peripheral ID Register + // [15:8] Can be used by software to + // identify the presence of this + // peripheral. + +#define GPIO_GPIO_PERIPHID1_PID1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID2 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID2_PID2_M \ + 0x000000FF // This register is not used in + // CC3XX.v GPIO Peripheral ID + // Register [23:16] Can be used by + // software to identify the presence + // of this peripheral. + +#define GPIO_GPIO_PERIPHID2_PID2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PERIPHID3 register. +// +//****************************************************************************** +#define GPIO_GPIO_PERIPHID3_PID3_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO Peripheral ID + // Register [31:24] Can be used by + // software to identify the presence + // of this peripheral. + +#define GPIO_GPIO_PERIPHID3_PID3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PCELLID0 register. +// +//****************************************************************************** +#define GPIO_GPIO_PCELLID0_CID0_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO PrimeCell ID Register + // [7:0] Provides software a + // standard cross-peripheral + // identification system. + +#define GPIO_GPIO_PCELLID0_CID0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PCELLID1 register. +// +//****************************************************************************** +#define GPIO_GPIO_PCELLID1_CID1_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO PrimeCell ID Register + // [15:8] Provides software a + // standard cross-peripheral + // identification system. + +#define GPIO_GPIO_PCELLID1_CID1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PCELLID2 register. +// +//****************************************************************************** +#define GPIO_GPIO_PCELLID2_CID2_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO PrimeCell ID Register + // [23:16] Provides software a + // standard cross-peripheral + // identification system. + +#define GPIO_GPIO_PCELLID2_CID2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPIO_O_GPIO_PCELLID3 register. +// +//****************************************************************************** +#define GPIO_GPIO_PCELLID3_CID3_M \ + 0x000000FF // This register is not used in + // CC3XX. GPIO PrimeCell ID Register + // [31:24] Provides software a + // standard cross-peripheral + // identification system. + +#define GPIO_GPIO_PCELLID3_CID3_S 0 + + + +#endif // __HW_GPIO_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gprcm.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gprcm.h new file mode 100755 index 0000000..43628f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_gprcm.h @@ -0,0 +1,3322 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_GPRCM_H__ +#define __HW_GPRCM_H__ + +//***************************************************************************** +// +// The following are defines for the GPRCM register offsets. +// +//***************************************************************************** +#define GPRCM_O_APPS_SOFT_RESET 0x00000000 +#define GPRCM_O_APPS_LPDS_WAKEUP_CFG \ + 0x00000004 + +#define GPRCM_O_APPS_LPDS_WAKEUP_SRC \ + 0x00000008 + +#define GPRCM_O_APPS_RESET_CAUSE \ + 0x0000000C + +#define GPRCM_O_APPS_LPDS_WAKETIME_OPP_CFG \ + 0x00000010 + +#define GPRCM_O_APPS_SRAM_DSLP_CFG \ + 0x00000018 + +#define GPRCM_O_APPS_SRAM_LPDS_CFG \ + 0x0000001C + +#define GPRCM_O_APPS_LPDS_WAKETIME_WAKE_CFG \ + 0x00000020 + +#define GPRCM_O_TOP_DIE_ENABLE 0x00000100 +#define GPRCM_O_TOP_DIE_ENABLE_PARAMETERS \ + 0x00000104 + +#define GPRCM_O_MCU_GLOBAL_SOFT_RESET \ + 0x00000108 + +#define GPRCM_O_ADC_CLK_CONFIG 0x0000010C +#define GPRCM_O_APPS_GPIO_WAKE_CONF \ + 0x00000110 + +#define GPRCM_O_EN_NWP_BOOT_WO_DEVINIT \ + 0x00000114 + +#define GPRCM_O_MEM_HCLK_DIV_CFG \ + 0x00000118 + +#define GPRCM_O_MEM_SYSCLK_DIV_CFG \ + 0x0000011C + +#define GPRCM_O_APLLMCS_LOCK_TIME_CONF \ + 0x00000120 + +#define GPRCM_O_NWP_SOFT_RESET 0x00000400 +#define GPRCM_O_NWP_LPDS_WAKEUP_CFG \ + 0x00000404 + +#define GPRCM_O_NWP_LPDS_WAKEUP_SRC \ + 0x00000408 + +#define GPRCM_O_NWP_RESET_CAUSE 0x0000040C +#define GPRCM_O_NWP_LPDS_WAKETIME_OPP_CFG \ + 0x00000410 + +#define GPRCM_O_NWP_SRAM_DSLP_CFG \ + 0x00000418 + +#define GPRCM_O_NWP_SRAM_LPDS_CFG \ + 0x0000041C + +#define GPRCM_O_NWP_LPDS_WAKETIME_WAKE_CFG \ + 0x00000420 + +#define GPRCM_O_NWP_AUTONMS_SPI_MASTER_SEL \ + 0x00000424 + +#define GPRCM_O_NWP_AUTONMS_SPI_IDLE_REQ \ + 0x00000428 + +#define GPRCM_O_WLAN_TO_NWP_WAKE_REQUEST \ + 0x0000042C + +#define GPRCM_O_NWP_TO_WLAN_WAKE_REQUEST \ + 0x00000430 + +#define GPRCM_O_NWP_GPIO_WAKE_CONF \ + 0x00000434 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG12 \ + 0x00000438 + +#define GPRCM_O_GPRCM_DIEID_READ_REG5 \ + 0x00000448 + +#define GPRCM_O_GPRCM_DIEID_READ_REG6 \ + 0x0000044C + +#define GPRCM_O_REF_FSM_CFG0 0x00000800 +#define GPRCM_O_REF_FSM_CFG1 0x00000804 +#define GPRCM_O_APLLMCS_WLAN_CONFIG0_40 \ + 0x00000808 + +#define GPRCM_O_APLLMCS_WLAN_CONFIG1_40 \ + 0x0000080C + +#define GPRCM_O_APLLMCS_WLAN_CONFIG0_26 \ + 0x00000810 + +#define GPRCM_O_APLLMCS_WLAN_CONFIG1_26 \ + 0x00000814 + +#define GPRCM_O_APLLMCS_WLAN_OVERRIDES \ + 0x00000818 + +#define GPRCM_O_APLLMCS_MCU_RUN_CONFIG0_38P4 \ + 0x0000081C + +#define GPRCM_O_APLLMCS_MCU_RUN_CONFIG1_38P4 \ + 0x00000820 + +#define GPRCM_O_APLLMCS_MCU_RUN_CONFIG0_26 \ + 0x00000824 + +#define GPRCM_O_APLLMCS_MCU_RUN_CONFIG1_26 \ + 0x00000828 + +#define GPRCM_O_SPARE_RW0 0x0000082C +#define GPRCM_O_SPARE_RW1 0x00000830 +#define GPRCM_O_APLLMCS_MCU_OVERRIDES \ + 0x00000834 + +#define GPRCM_O_SYSCLK_SWITCH_STATUS \ + 0x00000838 + +#define GPRCM_O_REF_LDO_CONTROLS \ + 0x0000083C + +#define GPRCM_O_REF_RTRIM_CONTROL \ + 0x00000840 + +#define GPRCM_O_REF_SLICER_CONTROLS0 \ + 0x00000844 + +#define GPRCM_O_REF_SLICER_CONTROLS1 \ + 0x00000848 + +#define GPRCM_O_REF_ANA_BGAP_CONTROLS0 \ + 0x0000084C + +#define GPRCM_O_REF_ANA_BGAP_CONTROLS1 \ + 0x00000850 + +#define GPRCM_O_REF_ANA_SPARE_CONTROLS0 \ + 0x00000854 + +#define GPRCM_O_REF_ANA_SPARE_CONTROLS1 \ + 0x00000858 + +#define GPRCM_O_MEMSS_PSCON_OVERRIDES0 \ + 0x0000085C + +#define GPRCM_O_MEMSS_PSCON_OVERRIDES1 \ + 0x00000860 + +#define GPRCM_O_PLL_REF_LOCK_OVERRIDES \ + 0x00000864 + +#define GPRCM_O_MCU_PSCON_DEBUG 0x00000868 +#define GPRCM_O_MEMSS_PWR_PS 0x0000086C +#define GPRCM_O_REF_FSM_DEBUG 0x00000870 +#define GPRCM_O_MEM_SYS_OPP_REQ_OVERRIDE \ + 0x00000874 + +#define GPRCM_O_MEM_TESTCTRL_PD_OPP_CONFIG \ + 0x00000878 + +#define GPRCM_O_MEM_WL_FAST_CLK_REQ_OVERRIDES \ + 0x0000087C + +#define GPRCM_O_MEM_MCU_PD_MODE_REQ_OVERRIDES \ + 0x00000880 + +#define GPRCM_O_MEM_MCSPI_SRAM_OFF_REQ_OVERRIDES \ + 0x00000884 + +#define GPRCM_O_MEM_WLAN_APLLMCS_OVERRIDES \ + 0x00000888 + +#define GPRCM_O_MEM_REF_FSM_CFG2 \ + 0x0000088C + +#define GPRCM_O_TESTCTRL_POWER_CTRL \ + 0x00000C10 + +#define GPRCM_O_SSDIO_POWER_CTRL \ + 0x00000C14 + +#define GPRCM_O_MCSPI_N1_POWER_CTRL \ + 0x00000C18 + +#define GPRCM_O_WELP_POWER_CTRL 0x00000C1C +#define GPRCM_O_WL_SDIO_POWER_CTRL \ + 0x00000C20 + +#define GPRCM_O_WLAN_SRAM_ACTIVE_PWR_CFG \ + 0x00000C24 + +#define GPRCM_O_WLAN_SRAM_SLEEP_PWR_CFG \ + 0x00000C28 + +#define GPRCM_O_APPS_SECURE_INIT_DONE \ + 0x00000C30 + +#define GPRCM_O_APPS_DEV_MODE_INIT_DONE \ + 0x00000C34 + +#define GPRCM_O_EN_APPS_REBOOT 0x00000C38 +#define GPRCM_O_MEM_APPS_PERIPH_PRESENT \ + 0x00000C3C + +#define GPRCM_O_MEM_NWP_PERIPH_PRESENT \ + 0x00000C40 + +#define GPRCM_O_MEM_SHARED_PERIPH_PRESENT \ + 0x00000C44 + +#define GPRCM_O_NWP_PWR_STATE 0x00000C48 +#define GPRCM_O_APPS_PWR_STATE 0x00000C4C +#define GPRCM_O_MCU_PWR_STATE 0x00000C50 +#define GPRCM_O_WTOP_PM_PS 0x00000C54 +#define GPRCM_O_WTOP_PD_RESETZ_OVERRIDE_REG \ + 0x00000C58 + +#define GPRCM_O_WELP_PD_RESETZ_OVERRIDE_REG \ + 0x00000C5C + +#define GPRCM_O_WL_SDIO_PD_RESETZ_OVERRIDE_REG \ + 0x00000C60 + +#define GPRCM_O_SSDIO_PD_RESETZ_OVERRIDE_REG \ + 0x00000C64 + +#define GPRCM_O_MCSPI_N1_PD_RESETZ_OVERRIDE_REG \ + 0x00000C68 + +#define GPRCM_O_TESTCTRL_PD_RESETZ_OVERRIDE_REG \ + 0x00000C6C + +#define GPRCM_O_MCU_PD_RESETZ_OVERRIDE_REG \ + 0x00000C70 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG0 \ + 0x00000C78 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG1 \ + 0x00000C7C + +#define GPRCM_O_GPRCM_EFUSE_READ_REG2 \ + 0x00000C80 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG3 \ + 0x00000C84 + +#define GPRCM_O_WTOP_MEM_RET_CFG \ + 0x00000C88 + +#define GPRCM_O_COEX_CLK_SWALLOW_CFG0 \ + 0x00000C8C + +#define GPRCM_O_COEX_CLK_SWALLOW_CFG1 \ + 0x00000C90 + +#define GPRCM_O_COEX_CLK_SWALLOW_CFG2 \ + 0x00000C94 + +#define GPRCM_O_COEX_CLK_SWALLOW_ENABLE \ + 0x00000C98 + +#define GPRCM_O_DCDC_CLK_GEN_CONFIG \ + 0x00000C9C + +#define GPRCM_O_GPRCM_EFUSE_READ_REG4 \ + 0x00000CA0 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG5 \ + 0x00000CA4 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG6 \ + 0x00000CA8 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG7 \ + 0x00000CAC + +#define GPRCM_O_GPRCM_EFUSE_READ_REG8 \ + 0x00000CB0 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG9 \ + 0x00000CB4 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG10 \ + 0x00000CB8 + +#define GPRCM_O_GPRCM_EFUSE_READ_REG11 \ + 0x00000CBC + +#define GPRCM_O_GPRCM_DIEID_READ_REG0 \ + 0x00000CC0 + +#define GPRCM_O_GPRCM_DIEID_READ_REG1 \ + 0x00000CC4 + +#define GPRCM_O_GPRCM_DIEID_READ_REG2 \ + 0x00000CC8 + +#define GPRCM_O_GPRCM_DIEID_READ_REG3 \ + 0x00000CCC + +#define GPRCM_O_GPRCM_DIEID_READ_REG4 \ + 0x00000CD0 + +#define GPRCM_O_APPS_SS_OVERRIDES \ + 0x00000CD4 + +#define GPRCM_O_NWP_SS_OVERRIDES \ + 0x00000CD8 + +#define GPRCM_O_SHARED_SS_OVERRIDES \ + 0x00000CDC + +#define GPRCM_O_IDMEM_CORE_RST_OVERRIDES \ + 0x00000CE0 + +#define GPRCM_O_TOP_DIE_FSM_OVERRIDES \ + 0x00000CE4 + +#define GPRCM_O_MCU_PSCON_OVERRIDES \ + 0x00000CE8 + +#define GPRCM_O_WTOP_PSCON_OVERRIDES \ + 0x00000CEC + +#define GPRCM_O_WELP_PSCON_OVERRIDES \ + 0x00000CF0 + +#define GPRCM_O_WL_SDIO_PSCON_OVERRIDES \ + 0x00000CF4 + +#define GPRCM_O_MCSPI_PSCON_OVERRIDES \ + 0x00000CF8 + +#define GPRCM_O_SSDIO_PSCON_OVERRIDES \ + 0x00000CFC + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_SOFT_RESET register. +// +//****************************************************************************** +#define GPRCM_APPS_SOFT_RESET_APPS_SOFT_RESET1 \ + 0x00000002 // Soft-reset1 for APPS : Cortex + // sysrstn is asserted and in + // addition to that the associated + // APPS Peripherals are also reset. + // This is an auto-clear bit. + +#define GPRCM_APPS_SOFT_RESET_APPS_SOFT_RESET0 \ + 0x00000001 // Soft-reset0 for APPS : Only + // sys-resetn for Cortex will be + // asserted. This is an auto-clear + // bit. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_LPDS_WAKEUP_CFG register. +// +//****************************************************************************** +#define GPRCM_APPS_LPDS_WAKEUP_CFG_APPS_LPDS_WAKEUP_CFG_M \ + 0x000000FF // Mask for LPDS Wakeup interrupt : + // [7] - Host IRQ from NWP [6] - + // NWP_LPDS_Wake_irq (TRUE_LPDS) [5] + // - NWP Wake-request to APPS [4] - + // GPIO [3:1] - Reserved [0] - LPDS + // Wakeup-timer + +#define GPRCM_APPS_LPDS_WAKEUP_CFG_APPS_LPDS_WAKEUP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_LPDS_WAKEUP_SRC register. +// +//****************************************************************************** +#define GPRCM_APPS_LPDS_WAKEUP_SRC_APPS_LPDS_WAKEUP_SRC_M \ + 0x000000FF // Indicates the cause for wakeup + // from LPDS : [7] - Host IRQ from + // NWP [6] - NWP_LPDS_Wake_irq + // (TRUE_LPDS) [5] - NWP + // Wake-request to APPS [4] - GPIO + // [3:1] - Reserved [0] - LPDS + // Wakeup-timer + +#define GPRCM_APPS_LPDS_WAKEUP_SRC_APPS_LPDS_WAKEUP_SRC_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_RESET_CAUSE register. +// +//****************************************************************************** +#define GPRCM_APPS_RESET_CAUSE_APPS_RESET_CAUSE_M \ + 0x000000FF // Indicates the reset cause for + // APPS : "0000" - Wake from HIB/OFF + // mode; "0001" - Wake from LPDS ; + // "0010" - Reserved ; "0011" - + // Soft-reset0 (Only APPS + // Cortex-sysrstn is asserted); + // "0100" - Soft-reset1 (APPS + // Cortex-sysrstn and APPS + // peripherals are reset); "0101" - + // WDOG0 (APPS Cortex-sysrstn and + // APPS peripherals are reset); + // "0110" - MCU Soft-reset (APPS + + // NWP Cortex-sysrstn + Peripherals + // are reset); "0111" - Secure Init + // done (Indication that reset has + // happened after DevInit); "1000" - + // Dev Mode Patch Init done (During + // development mode, patch + // downloading and Cortex + // re-vectoring is completed) + +#define GPRCM_APPS_RESET_CAUSE_APPS_RESET_CAUSE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_LPDS_WAKETIME_OPP_CFG register. +// +//****************************************************************************** +#define GPRCM_APPS_LPDS_WAKETIME_OPP_CFG_APPS_LPDS_WAKETIME_OPP_CFG_M \ + 0xFFFFFFFF // OPP Request Configuration + // (Number of slow-clk cycles) for + // LPDS Wake-timer : This + // configuration implies the RTC + // time-stamp, which must be few + // slow-clks prior to + // APPS_LPDS_WAKETIME_WAKE_CFG, such + // that by the time actual wakeup is + // given, OPP is already switched to + // ACTIVE (RUN). + +#define GPRCM_APPS_LPDS_WAKETIME_OPP_CFG_APPS_LPDS_WAKETIME_OPP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_SRAM_DSLP_CFG register. +// +//****************************************************************************** +#define GPRCM_APPS_SRAM_DSLP_CFG_APPS_SRAM_DSLP_CFG_M \ + 0x000FFFFF // Configuration of APPS Memories + // during Deep-sleep : 0 - SRAMs are + // OFF ; 1 - SRAMs are Retained. + // APPS SRAM Cluster information : + // [0] - 1st column in MEMSS + // (Applicable only when owned by + // APPS); [1] - 2nd column in MEMSS + // (Applicable only when owned by + // APPS); [2] - 3rd column in MEMSS + // (Applicable only when owned by + // APPS) ; [3] - 4th column in MEMSS + // (Applicable only when owned by + // APPS) ; [16] - MCU-PD - Apps + // cluster 0 (TBD); [19:18] - + // Reserved. + +#define GPRCM_APPS_SRAM_DSLP_CFG_APPS_SRAM_DSLP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_SRAM_LPDS_CFG register. +// +//****************************************************************************** +#define GPRCM_APPS_SRAM_LPDS_CFG_APPS_SRAM_LPDS_CFG_M \ + 0x000FFFFF // Configuration of APPS Memories + // during LPDS : 0 - SRAMs are OFF ; + // 1 - SRAMs are Retained. APPS SRAM + // Cluster information : [0] - 1st + // column in MEMSS (Applicable only + // when owned by APPS); [1] - 2nd + // column in MEMSS (Applicable only + // when owned by APPS); [2] - 3rd + // column in MEMSS (Applicable only + // when owned by APPS) ; [3] - 4th + // column in MEMSS (Applicable only + // when owned by APPS) ; [16] - + // MCU-PD - Apps cluster 0 (TBD); + // [19:18] - Reserved. + +#define GPRCM_APPS_SRAM_LPDS_CFG_APPS_SRAM_LPDS_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_LPDS_WAKETIME_WAKE_CFG register. +// +//****************************************************************************** +#define GPRCM_APPS_LPDS_WAKETIME_WAKE_CFG_APPS_LPDS_WAKETIME_WAKE_CFG_M \ + 0xFFFFFFFF // Configuration (in no of + // slow_clks) which says when the + // actual wakeup request for + // removing the PD-reset be given. + +#define GPRCM_APPS_LPDS_WAKETIME_WAKE_CFG_APPS_LPDS_WAKETIME_WAKE_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_TOP_DIE_ENABLE register. +// +//****************************************************************************** +#define GPRCM_TOP_DIE_ENABLE_FLASH_BUSY \ + 0x00001000 + +#define GPRCM_TOP_DIE_ENABLE_TOP_DIE_PWR_PS_M \ + 0x00000F00 + +#define GPRCM_TOP_DIE_ENABLE_TOP_DIE_PWR_PS_S 8 +#define GPRCM_TOP_DIE_ENABLE_TOP_DIE_ENABLE_STATUS \ + 0x00000002 // 1 - Top-die is enabled ; + +#define GPRCM_TOP_DIE_ENABLE_TOP_DIE_ENABLE \ + 0x00000001 // 1 - Enable the top-die ; 0 - + // Disable the top-die + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_TOP_DIE_ENABLE_PARAMETERS register. +// +//****************************************************************************** +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_FLASH_3P3_RSTN2D2D_POR_RSTN_M \ + 0xF0000000 // Configuration (in slow_clks) for + // number of clks between + // Flash-3p3-rstn to D2D POR Resetn. + +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_FLASH_3P3_RSTN2D2D_POR_RSTN_S 28 +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_TOP_DIE_SW_EN2TOP_DIE_FLASH_3P3_RSTN_M \ + 0x00FF0000 // Configuration (in slow_clks) for + // number of clks between Top-die + // Switch-Enable and Top-die Flash + // 3p3 Reset removal + +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_TOP_DIE_SW_EN2TOP_DIE_FLASH_3P3_RSTN_S 16 +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_TOP_DIE_POR_RSTN2BOTT_DIE_FMC_RSTN_M \ + 0x000000FF // Configuration (in slow_clks) for + // number of clks between D2D POR + // Reset removal and bottom die FMC + // reset removal + +#define GPRCM_TOP_DIE_ENABLE_PARAMETERS_TOP_DIE_POR_RSTN2BOTT_DIE_FMC_RSTN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCU_GLOBAL_SOFT_RESET register. +// +//****************************************************************************** +#define GPRCM_MCU_GLOBAL_SOFT_RESET_MCU_GLOBAL_SOFT_RESET \ + 0x00000001 // 1 - Assert the global reset for + // MCU (APPS + NWP) ; Asserts both + // Cortex sysrstn and its + // peripherals 0 - Deassert the + // global reset for MCU (APPS + NWP) + // ; Asserts both Cortex sysrstn and + // its peripherals Note : Reset for + // shared peripherals is not + // affected here. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_ADC_CLK_CONFIG register. +// +//****************************************************************************** +#define GPRCM_ADC_CLK_CONFIG_ADC_CLKGEN_OFF_TIME_M \ + 0x000007C0 // Configuration (in number of 38.4 + // MHz clks) for the OFF-Time in + // generation of ADC_CLK + +#define GPRCM_ADC_CLK_CONFIG_ADC_CLKGEN_OFF_TIME_S 6 +#define GPRCM_ADC_CLK_CONFIG_ADC_CLKGEN_ON_TIME_M \ + 0x0000003E // Configuration (in number of 38.4 + // MHz clks) for the ON-Time in + // generation of ADC_CLK + +#define GPRCM_ADC_CLK_CONFIG_ADC_CLKGEN_ON_TIME_S 1 +#define GPRCM_ADC_CLK_CONFIG_ADC_CLK_ENABLE \ + 0x00000001 // 1 - Enable the ADC_CLK ; 0 - + // Disable the ADC_CLK + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_GPIO_WAKE_CONF register. +// +//****************************************************************************** +#define GPRCM_APPS_GPIO_WAKE_CONF_APPS_GPIO_WAKE_CONF_M \ + 0x00000003 // "00" - Wake on Level0 on + // selected GPIO pin (GPIO is + // selected inside the HIB3p3 + // module); "01" - Wakeup on + // fall-edge of GPIO pin. + +#define GPRCM_APPS_GPIO_WAKE_CONF_APPS_GPIO_WAKE_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_EN_NWP_BOOT_WO_DEVINIT register. +// +//****************************************************************************** +#define GPRCM_EN_NWP_BOOT_WO_DEVINIT_reserved_M \ + 0xFFFFFFFE + +#define GPRCM_EN_NWP_BOOT_WO_DEVINIT_reserved_S 1 +#define GPRCM_EN_NWP_BOOT_WO_DEVINIT_mem_en_nwp_boot_wo_devinit \ + 0x00000001 // 1 - Override the secure-mode + // done for booting up NWP (Wakeup + // NWP on its event independent of + // CM4 state) ; 0 - Donot override + // the secure-mode done for NWP boot + // (NWP must be enabled by CM4 only) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_HCLK_DIV_CFG register. +// +//****************************************************************************** +#define GPRCM_MEM_HCLK_DIV_CFG_mem_hclk_div_cfg_M \ + 0x00000007 // Division configuration for + // HCLKDIVOUT : "000" - Divide by 1 + // ; "001" - Divide by 2 ; "010" - + // Divide by 3 ; "011" - Divide by 4 + // ; "100" - Divide by 5 ; "101" - + // Divide by 6 ; "110" - Divide by 7 + // ; "111" - Divide by 8 + +#define GPRCM_MEM_HCLK_DIV_CFG_mem_hclk_div_cfg_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_SYSCLK_DIV_CFG register. +// +//****************************************************************************** +#define GPRCM_MEM_SYSCLK_DIV_CFG_mem_sysclk_div_off_time_M \ + 0x00000038 + +#define GPRCM_MEM_SYSCLK_DIV_CFG_mem_sysclk_div_off_time_S 3 +#define GPRCM_MEM_SYSCLK_DIV_CFG_mem_sysclk_div_on_time_M \ + 0x00000007 + +#define GPRCM_MEM_SYSCLK_DIV_CFG_mem_sysclk_div_on_time_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_LOCK_TIME_CONF register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_LOCK_TIME_CONF_mem_apllmcs_wlan_lock_time_M \ + 0x0000FF00 + +#define GPRCM_APLLMCS_LOCK_TIME_CONF_mem_apllmcs_wlan_lock_time_S 8 +#define GPRCM_APLLMCS_LOCK_TIME_CONF_mem_apllmcs_mcu_lock_time_M \ + 0x000000FF + +#define GPRCM_APLLMCS_LOCK_TIME_CONF_mem_apllmcs_mcu_lock_time_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_SOFT_RESET register. +// +//****************************************************************************** +#define GPRCM_NWP_SOFT_RESET_NWP_SOFT_RESET1 \ + 0x00000002 // Soft-reset1 for NWP - Cortex + // sysrstn and NWP associated + // peripherals are - This is an + // auto-clr bit. + +#define GPRCM_NWP_SOFT_RESET_NWP_SOFT_RESET0 \ + 0x00000001 // Soft-reset0 for NWP - Only + // Cortex-sysrstn is asserted - This + // is an auto-clear bit. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_LPDS_WAKEUP_CFG register. +// +//****************************************************************************** +#define GPRCM_NWP_LPDS_WAKEUP_CFG_NWP_LPDS_WAKEUP_CFG_M \ + 0x000000FF // Mask for LPDS Wakeup interrupt : + // 7 - WLAN Host Interrupt ; 6 - + // WLAN to NWP Wake request ; 5 - + // APPS to NWP Wake request; 4 - + // GPIO Wakeup ; 3 - Autonomous UART + // Wakeup ; 2 - SSDIO Wakeup ; 1 - + // Autonomous SPI Wakeup ; 0 - LPDS + // Wakeup-timer + +#define GPRCM_NWP_LPDS_WAKEUP_CFG_NWP_LPDS_WAKEUP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_LPDS_WAKEUP_SRC register. +// +//****************************************************************************** +#define GPRCM_NWP_LPDS_WAKEUP_SRC_NWP_LPDS_WAKEUP_SRC_M \ + 0x000000FF // Indicates the cause for NWP + // LPDS-Wakeup : 7 - WLAN Host + // Interrupt ; 6 - WLAN to NWP Wake + // request ; 5 - APPS to NWP Wake + // request; 4 - GPIO Wakeup ; 3 - + // Autonomous UART Wakeup ; 2 - + // SSDIO Wakeup ; 1 - Autonomous SPI + // Wakeup ; 0 - LPDS Wakeup-timer + +#define GPRCM_NWP_LPDS_WAKEUP_SRC_NWP_LPDS_WAKEUP_SRC_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_RESET_CAUSE register. +// +//****************************************************************************** +#define GPRCM_NWP_RESET_CAUSE_NWP_RESET_CAUSE_M \ + 0x000000FF // Indicates the reset cause for + // NWP : "0000" - Wake from HIB/OFF + // mode; "0001" - Wake from LPDS ; + // "0010" - Reserved ; "0011" - + // Soft-reset0 (Only NWP + // Cortex-sysrstn is asserted); + // "0100" - Soft-reset1 (NWP + // Cortex-sysrstn and NWP + // peripherals are reset); "0101" - + // WDOG0 (NWP Cortex-sysrstn and NWP + // peripherals are reset); "0110" - + // MCU Soft-reset (APPS + NWP + // Cortex-sysrstn + Peripherals are + // reset); "0111" - SSDIO Function2 + // reset (Only Cortex-sysrstn is + // asserted) ; "1000" - Reset due to + // WDOG of APPS (NWP Cortex-sysrstn + // and NWP peripherals are reset); + +#define GPRCM_NWP_RESET_CAUSE_NWP_RESET_CAUSE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_LPDS_WAKETIME_OPP_CFG register. +// +//****************************************************************************** +#define GPRCM_NWP_LPDS_WAKETIME_OPP_CFG_NWP_LPDS_WAKETIME_OPP_CFG_M \ + 0xFFFFFFFF // OPP Request Configuration + // (Number of slow-clk cycles) for + // LPDS Wake-timer + +#define GPRCM_NWP_LPDS_WAKETIME_OPP_CFG_NWP_LPDS_WAKETIME_OPP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_SRAM_DSLP_CFG register. +// +//****************************************************************************** +#define GPRCM_NWP_SRAM_DSLP_CFG_NWP_SRAM_DSLP_CFG_M \ + 0x000FFFFF // Configuration of NWP Memories + // during DSLP : 0 - SRAMs are OFF ; + // 1 - SRAMs are Retained. NWP SRAM + // Cluster information : [2] - 3rd + // column in MEMSS (Applicable only + // when owned by NWP) ; [3] - 4th + // column in MEMSS (Applicable only + // when owned by NWP) ; [4] - 5th + // column in MEMSS (Applicable only + // when owned by NWP) ; [5] - 6th + // column in MEMSS (Applicable only + // when owned by NWP) ; [6] - 7th + // column in MEMSS (Applicable only + // when owned by NWP) ; [7] - 8th + // column in MEMSS (Applicable only + // when owned by NWP) ; [8] - 9th + // column in MEMSS (Applicable only + // when owned by NWP) ; [9] - 10th + // column in MEMSS (Applicable only + // when owned by NWP) ; [10] - 11th + // column in MEMSS (Applicable only + // when owned by NWP) ; [11] - 12th + // column in MEMSS (Applicable only + // when owned by NWP) ; [12] - 13th + // column in MEMSS (Applicable only + // when owned by NWP) ; [13] - 14th + // column in MEMSS (Applicable only + // when owned by NWP) ; [14] - 15th + // column in MEMSS (Applicable only + // when owned by NWP) ; [19:18] - + // Reserved. + +#define GPRCM_NWP_SRAM_DSLP_CFG_NWP_SRAM_DSLP_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_SRAM_LPDS_CFG register. +// +//****************************************************************************** +#define GPRCM_NWP_SRAM_LPDS_CFG_NWP_SRAM_LPDS_CFG_M \ + 0x000FFFFF // Configuration of NWP Memories + // during LPDS : 0 - SRAMs are OFF ; + // 1 - SRAMs are Retained. NWP SRAM + // Cluster information : [2] - 3rd + // column in MEMSS (Applicable only + // when owned by NWP) ; [3] - 4th + // column in MEMSS (Applicable only + // when owned by NWP) ; [4] - 5th + // column in MEMSS (Applicable only + // when owned by NWP) ; [5] - 6th + // column in MEMSS (Applicable only + // when owned by NWP) ; [6] - 7th + // column in MEMSS (Applicable only + // when owned by NWP) ; [7] - 8th + // column in MEMSS (Applicable only + // when owned by NWP) ; [8] - 9th + // column in MEMSS (Applicable only + // when owned by NWP) ; [9] - 10th + // column in MEMSS (Applicable only + // when owned by NWP) ; [10] - 11th + // column in MEMSS (Applicable only + // when owned by NWP) ; [11] - 12th + // column in MEMSS (Applicable only + // when owned by NWP) ; [12] - 13th + // column in MEMSS (Applicable only + // when owned by NWP) ; [13] - 14th + // column in MEMSS (Applicable only + // when owned by NWP) ; [14] - 15th + // column in MEMSS (Applicable only + // when owned by NWP) ; [19:18] - + // Reserved. + +#define GPRCM_NWP_SRAM_LPDS_CFG_NWP_SRAM_LPDS_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_LPDS_WAKETIME_WAKE_CFG register. +// +//****************************************************************************** +#define GPRCM_NWP_LPDS_WAKETIME_WAKE_CFG_NWP_LPDS_WAKETIME_WAKE_CFG_M \ + 0xFFFFFFFF // Wake time configuration (no of + // slow clks) for NWP wake from + // LPDS. + +#define GPRCM_NWP_LPDS_WAKETIME_WAKE_CFG_NWP_LPDS_WAKETIME_WAKE_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_AUTONMS_SPI_MASTER_SEL register. +// +//****************************************************************************** +#define GPRCM_NWP_AUTONMS_SPI_MASTER_SEL_F_M \ + 0xFFFE0000 + +#define GPRCM_NWP_AUTONMS_SPI_MASTER_SEL_F_S 17 +#define GPRCM_NWP_AUTONMS_SPI_MASTER_SEL_MEM_AUTONMS_SPI_MASTER_SEL \ + 0x00010000 // 0 - APPS is selected as host for + // Autonms SPI ; 1 - External host + // is selected as host for Autonms + // SPI + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_AUTONMS_SPI_IDLE_REQ register. +// +//****************************************************************************** +#define GPRCM_NWP_AUTONMS_SPI_IDLE_REQ_NWP_AUTONMS_SPI_IDLE_WAKEUP \ + 0x00010000 + +#define GPRCM_NWP_AUTONMS_SPI_IDLE_REQ_NWP_AUTONMS_SPI_IDLE_ACK \ + 0x00000002 // When 1 => IDLE-mode is + // acknowledged by the SPI-IP. (This + // is for MCSPI_N1) + +#define GPRCM_NWP_AUTONMS_SPI_IDLE_REQ_NWP_AUTONMS_SPI_IDLE_REQ \ + 0x00000001 // When 1 => Request for IDLE-mode + // for autonomous SPI. (This is for + // MCSPI_N1) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WLAN_TO_NWP_WAKE_REQUEST register. +// +//****************************************************************************** +#define GPRCM_WLAN_TO_NWP_WAKE_REQUEST_WLAN_TO_NWP_WAKE_REQUEST \ + 0x00000001 // 1 - Request for waking up NWP + // from any of its low-power modes + // (SLP/DSLP/LPDS) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_TO_WLAN_WAKE_REQUEST register. +// +//****************************************************************************** +#define GPRCM_NWP_TO_WLAN_WAKE_REQUEST_NWP_TO_WLAN_WAKE_REQUEST \ + 0x00000001 // 1 - Request for wakinp up WLAN + // from its ELP Mode (This gets + // triggered to ELP-logic of WLAN) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_GPIO_WAKE_CONF register. +// +//****************************************************************************** +#define GPRCM_NWP_GPIO_WAKE_CONF_NWP_GPIO_WAKE_CONF_M \ + 0x00000003 // "00" - Wakeup on level0 of the + // selected GPIO (GPIO gets selected + // inside HIB3P3-module); "01" - + // Wakeup on fall-edge of selected + // GPIO. + +#define GPRCM_NWP_GPIO_WAKE_CONF_NWP_GPIO_WAKE_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG12 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG12_FUSEFARM_ROW_32_MSW_M \ + 0x0000FFFF // This corrsponds to ROW_32 + // [31:16] of the FUSEFARM. SPARE + +#define GPRCM_GPRCM_EFUSE_READ_REG12_FUSEFARM_ROW_32_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG5 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG5_FUSEFARM_ROW_10_M \ + 0xFFFFFFFF // Corresponds to ROW10 of FUSEFARM + // : [5:0] - ADC OFFSET ; [13:6] - + // TEMP_SENSE ; [14:14] - DFT_GSG ; + // [15:15] - FMC_DISABLE ; [31:16] - + // WLAN_MAC ID + +#define GPRCM_GPRCM_DIEID_READ_REG5_FUSEFARM_ROW_10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG6 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG6_FUSEFARM_ROW_11_M \ + 0xFFFFFFFF // Corresponds to ROW11 of FUSEFARM + // : [31:0] : WLAN MAC ID + +#define GPRCM_GPRCM_DIEID_READ_REG6_FUSEFARM_ROW_11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_FSM_CFG0 register. +// +//****************************************************************************** +#define GPRCM_REF_FSM_CFG0_BGAP_SETTLING_TIME_M \ + 0x00FF0000 // ANA-BGAP Settling time (In + // number of slow_clks) + +#define GPRCM_REF_FSM_CFG0_BGAP_SETTLING_TIME_S 16 +#define GPRCM_REF_FSM_CFG0_FREF_LDO_SETTLING_TIME_M \ + 0x0000FF00 // Slicer LDO settling time (In + // number of slow clks) + +#define GPRCM_REF_FSM_CFG0_FREF_LDO_SETTLING_TIME_S 8 +#define GPRCM_REF_FSM_CFG0_DIG_BUF_SETTLING_TIME_M \ + 0x000000FF // Dig-buffer settling time (In + // number of slow clks) + +#define GPRCM_REF_FSM_CFG0_DIG_BUF_SETTLING_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_FSM_CFG1 register. +// +//****************************************************************************** +#define GPRCM_REF_FSM_CFG1_XTAL_SETTLING_TIME_M \ + 0xFF000000 // XTAL settling time (In number of + // slow clks) + +#define GPRCM_REF_FSM_CFG1_XTAL_SETTLING_TIME_S 24 +#define GPRCM_REF_FSM_CFG1_SLICER_LV_SETTLING_TIME_M \ + 0x00FF0000 // LV Slicer settling time + +#define GPRCM_REF_FSM_CFG1_SLICER_LV_SETTLING_TIME_S 16 +#define GPRCM_REF_FSM_CFG1_SLICER_HV_PD_SETTLING_TIME_M \ + 0x0000FF00 // HV Slicer Pull-down settling + // time + +#define GPRCM_REF_FSM_CFG1_SLICER_HV_PD_SETTLING_TIME_S 8 +#define GPRCM_REF_FSM_CFG1_SLICER_HV_SETTLING_TIME_M \ + 0x000000FF // HV Slicer settling time + +#define GPRCM_REF_FSM_CFG1_SLICER_HV_SETTLING_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_WLAN_CONFIG0_40 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_WLAN_CONFIG0_40_APLLMCS_WLAN_N_40_M \ + 0x00007F00 // Configuration for WLAN APLLMCS - + // N[6:0], if the XTAL frequency is + // 40 MHz (Selected by efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG0_40_APLLMCS_WLAN_N_40_S 8 +#define GPRCM_APLLMCS_WLAN_CONFIG0_40_APLLMCS_WLAN_M_40_M \ + 0x000000FF // Configuration for WLAN APLLMCS - + // M[7:0], if the XTAL frequency is + // 40 MHz (Selected by efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG0_40_APLLMCS_WLAN_M_40_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_WLAN_CONFIG1_40 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_WLAN_CONFIG1_40_APLLMCS_HISPEED_40 \ + 0x00000010 // Configuration for WLAN APLLMCS - + // if the XTAL frequency if 40 MHz + // (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_40_APLLMCS_SEL96_40 \ + 0x00000008 // Configuration for WLAN APLLMCS - + // Sel96, if the XTAL frequency is + // 40 MHz (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_40_APLLMCS_SELINPFREQ_40_M \ + 0x00000007 // Configuration for WLAN APLLMCS - + // Selinpfreq, if the XTAL frequency + // is 40 MHz (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_40_APLLMCS_SELINPFREQ_40_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_WLAN_CONFIG0_26 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_WLAN_CONFIG0_26_APLLMCS_WLAN_N_26_M \ + 0x00007F00 // Configuration for WLAN APLLMCS - + // N[6:0], if the XTAL frequency is + // 26 MHz (Selected by efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG0_26_APLLMCS_WLAN_N_26_S 8 +#define GPRCM_APLLMCS_WLAN_CONFIG0_26_APLLMCS_WLAN_M_26_M \ + 0x000000FF // Configuration for WLAN APLLMCS - + // M[7:0], if the XTAL frequency is + // 26 MHz (Selected by efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG0_26_APLLMCS_WLAN_M_26_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_WLAN_CONFIG1_26 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_WLAN_CONFIG1_26_APLLMCS_HISPEED_26 \ + 0x00000010 // Configuration for WLAN APLLMCS - + // if the XTAL frequency if 26 MHz + // (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_26_APLLMCS_SEL96_26 \ + 0x00000008 // Configuration for WLAN APLLMCS - + // Sel96, if the XTAL frequency is + // 26 MHz (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_26_APLLMCS_SELINPFREQ_26_M \ + 0x00000007 // Configuration for WLAN APLLMCS - + // Selinpfreq, if the XTAL frequency + // is 26 MHz (Selected by Efuse) + +#define GPRCM_APLLMCS_WLAN_CONFIG1_26_APLLMCS_SELINPFREQ_26_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_WLAN_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_POSTDIV_OVERRIDE_CTRL \ + 0x00080000 + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_POSTDIV_OVERRIDE_M \ + 0x00070000 + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_POSTDIV_OVERRIDE_S 16 +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_SPARE_M \ + 0x00000700 + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_SPARE_S 8 +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_M_8_OVERRIDE_CTRL \ + 0x00000020 // Override control for + // WLAN_APLLMCS_M[8]. When set to1, + // M[8] will be selected by bit [3]. + // (Else controlled from WTOP) + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_M_8_OVERRIDE \ + 0x00000010 // Override for WLAN_APLLMCS_M[8]. + // Applicable only when bit [4] is + // set to 1. (Else controlled from + // WTOP) + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_N_7_8_OVERRIDE_CTRL \ + 0x00000004 // Override control for + // WLAN_APLLMCS_N[8:7]. When set + // to1, N[8:7] will be selected by + // bits [2:1]. (Else controlled from + // WTOP) + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_N_7_8_OVERRIDE_M \ + 0x00000003 // Override value for + // WLAN_APLLMCS_N[8:7] bits. + // Applicable only when bit [1] is + // set to 1. (Else controlled from + // WTOP) + +#define GPRCM_APLLMCS_WLAN_OVERRIDES_APLLMCS_WLAN_N_7_8_OVERRIDE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_MCU_RUN_CONFIG0_38P4 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_POSTDIV_M \ + 0x38000000 + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_POSTDIV_S 27 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_SPARE_M \ + 0x07000000 + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_SPARE_S 24 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_N_38P4_M \ + 0x007F0000 // Configuration for MCU-APLLMCS : + // N during RUN mode. Selected if + // the XTAL frequency is 38.4 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_N_38P4_S 16 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_M_38P4_M \ + 0x0000FF00 // Configuration for MCU-APLLMCS : + // M during RUN mode. Selected if + // the XTAL frequency is 38.4 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_M_38P4_S 8 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_M_8_38P4 \ + 0x00000010 // Configuration for MCU-APLLMCS : + // M[8] during RUN mode. Selected if + // the XTAL frequency is 38.4 MHz + // (From Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_N_7_8_38P4_M \ + 0x00000003 // Configuration for MCU-APLLMCS : + // N[8:7] during RUN mode. Selected + // if the XTAL frequency is 38.4 MHz + // (From Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_38P4_APLLMCS_MCU_RUN_N_7_8_38P4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_MCU_RUN_CONFIG1_38P4 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_38P4_APLLMCS_MCU_RUN_HISPEED_38P4 \ + 0x00000010 // Configuration for MCU-APLLMCS : + // HISPEED during RUN mode. Selected + // if the XTAL frequency is 38.4 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_38P4_APLLMCS_MCU_RUN_SEL96_38P4 \ + 0x00000008 // Configuration for MCU-APLLMCS : + // SEL96 during RUN mode. Selected + // if the XTAL frequency is 38.4 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_38P4_APLLMCS_MCU_RUN_SELINPFREQ_38P4_M \ + 0x00000007 // Configuration for MCU-APLLMCS : + // SELINPFREQ during RUN mode. + // Selected if the XTAL frequency is + // 38.4 MHz (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_38P4_APLLMCS_MCU_RUN_SELINPFREQ_38P4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_MCU_RUN_CONFIG0_26 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_N_26_M \ + 0x007F0000 // Configuration for MCU-APLLMCS : + // N during RUN mode. Selected if + // the XTAL frequency is 26 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_N_26_S 16 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_M_26_M \ + 0x0000FF00 // Configuration for MCU-APLLMCS : + // M during RUN mode. Selected if + // the XTAL frequency is 26 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_M_26_S 8 +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_M_8_26 \ + 0x00000010 // Configuration for MCU-APLLMCS : + // M[8] during RUN mode. Selected if + // the XTAL frequency is 26 MHz + // (From Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_N_7_8_26_M \ + 0x00000003 // Configuration for MCU-APLLMCS : + // N[8:7] during RUN mode. Selected + // if the XTAL frequency is 26 MHz + // (From Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG0_26_APLLMCS_MCU_RUN_N_7_8_26_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_MCU_RUN_CONFIG1_26 register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_26_APLLMCS_MCU_RUN_HISPEED_26 \ + 0x00000010 // Configuration for MCU-APLLMCS : + // HISPEED during RUN mode. Selected + // if the XTAL frequency is 26 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_26_APLLMCS_MCU_RUN_SEL96_26 \ + 0x00000008 // Configuration for MCU-APLLMCS : + // SEL96 during RUN mode. Selected + // if the XTAL frequency is 26 MHz + // (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_26_APLLMCS_MCU_RUN_SELINPFREQ_26_M \ + 0x00000007 // Configuration for MCU-APLLMCS : + // SELINPFREQ during RUN mode. + // Selected if the XTAL frequency is + // 26 MHz (from Efuse) + +#define GPRCM_APLLMCS_MCU_RUN_CONFIG1_26_APLLMCS_MCU_RUN_SELINPFREQ_26_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the GPRCM_O_SPARE_RW0 register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the GPRCM_O_SPARE_RW1 register. +// +//****************************************************************************** +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APLLMCS_MCU_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_APLLMCS_MCU_OVERRIDES_APLLMCS_MCU_LOCK \ + 0x00000400 // 1 - APLLMCS_MCU is locked ; 0 - + // APLLMCS_MCU is not locked + +#define GPRCM_APLLMCS_MCU_OVERRIDES_APLLMCS_MCU_ENABLE_OVERRIDE \ + 0x00000200 // Override for APLLMCS_MCU Enable. + // Applicable if bit [8] is set + +#define GPRCM_APLLMCS_MCU_OVERRIDES_APLLMCS_MCU_ENABLE_OVERRIDE_CTRL \ + 0x00000100 // 1 - Enable for APLLMCS_MCU comes + // from bit [9]. 0 - Enable for + // APLLMCS_MCU comes from FSM. + +#define GPRCM_APLLMCS_MCU_OVERRIDES_SYSCLK_SRC_OVERRIDE_M \ + 0x00000006 // Override for sysclk src + // (applicable only if bit [0] is + // set to 1. "00"- SLOW_CLK "01"- + // XTAL_CLK "10"- PLL_CLK + +#define GPRCM_APLLMCS_MCU_OVERRIDES_SYSCLK_SRC_OVERRIDE_S 1 +#define GPRCM_APLLMCS_MCU_OVERRIDES_SYSCLK_SRC_OVERRIDE_CTRL \ + 0x00000001 // 1 - Sysclk src is selected from + // bits [2:1] of this register. 0 - + // Sysclk src is selected from FSM + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_SYSCLK_SWITCH_STATUS register. +// +//****************************************************************************** +#define GPRCM_SYSCLK_SWITCH_STATUS_SYSCLK_SWITCH_STATUS \ + 0x00000001 // 1 - Sysclk switching is + // complete. 0 - Sysclk switching is + // in progress. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_LDO_CONTROLS register. +// +//****************************************************************************** +#define GPRCM_REF_LDO_CONTROLS_REF_LDO_ENABLE_OVERRIDE_CTRL \ + 0x00010000 // 1 - Enable for REF_LDO comes + // from bit [0] of this register ; 0 + // - Enable for REF_LDO comes from + // the FSM. Note : Final REF_LDO_EN + // reaches on the port + // TOP_PM_REG2[0] of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_SPARE_CONTROL_M \ + 0x0000C000 // Spare bits for REF_CTRL_FSM. + // Reaches directly on port + // TOP_PM_REG2[15:14] of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_SPARE_CONTROL_S 14 +#define GPRCM_REF_LDO_CONTROLS_REF_TLOAD_ENABLE_M \ + 0x00003800 // REF TLOAD Enable. Reaches + // directly on port + // TOP_PM_REG2[13:11] of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_TLOAD_ENABLE_S 11 +#define GPRCM_REF_LDO_CONTROLS_REF_LDO_TMUX_CONTROL_M \ + 0x00000700 // REF_LDO Test-mux control. + // Reaches directly on port + // TOP_PM_REG2[10:8] of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_LDO_TMUX_CONTROL_S 8 +#define GPRCM_REF_LDO_CONTROLS_REF_BW_CONTROL_M \ + 0x000000C0 // REF BW Control. Reaches directly + // on port TOP_PM_REG2[7:6] of + // gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_BW_CONTROL_S 6 +#define GPRCM_REF_LDO_CONTROLS_REF_VTRIM_CONTROL_M \ + 0x0000003C // REF VTRIM Control. Reaches + // directly on port TOP_PM_REG2[5:2] + // of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_VTRIM_CONTROL_S 2 +#define GPRCM_REF_LDO_CONTROLS_REF_LDO_BYPASS_ENABLE \ + 0x00000002 // REF LDO Bypass Enable. Reaches + // directly on port TOP_PM_REG2[1] + // of gprcm. + +#define GPRCM_REF_LDO_CONTROLS_REF_LDO_ENABLE \ + 0x00000001 // Override for REF_LDO Enable. + // Applicable only if bit [16] of + // this register is set. Note : + // Final REF_LDO_EN reaches on the + // port TOP_PM_REG2[0] of gprcm. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_RTRIM_CONTROL register. +// +//****************************************************************************** +#define GPRCM_REF_RTRIM_CONTROL_TOP_PM_REG0_5_4_M \ + 0x18000000 // This is [5:4] bits of + // TOP_PM_REG0 + +#define GPRCM_REF_RTRIM_CONTROL_TOP_PM_REG0_5_4_S 27 +#define GPRCM_REF_RTRIM_CONTROL_TOP_CLKM_REG0_15_5_M \ + 0x07FF0000 // This is [15:5] bits of + // TOP_CLKM_REG0 + +#define GPRCM_REF_RTRIM_CONTROL_TOP_CLKM_REG0_15_5_S 16 +#define GPRCM_REF_RTRIM_CONTROL_REF_CLKM_RTRIM_OVERRIDE_CTRL \ + 0x00000100 // 1 - CLKM_RTRIM comes for + // bits[4:0] of this register. 0 - + // CLKM_RTRIM comes from Efuse + // (after efuse_done = 1). + +#define GPRCM_REF_RTRIM_CONTROL_REF_CLKM_RTRIM_M \ + 0x0000001F // CLKM_TRIM Override. Applicable + // when efuse_done = 0 or bit[8] is + // set to 1. + +#define GPRCM_REF_RTRIM_CONTROL_REF_CLKM_RTRIM_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_SLICER_CONTROLS0 register. +// +//****************************************************************************** +#define GPRCM_REF_SLICER_CONTROLS0_CLK_EN_WLAN_LOWV_OVERRIDE_CTRL \ + 0x00200000 // 1 - EN_DIG_BUF_TOP comes from + // bit [14] of this register. 0 - + // EN_DIG_BUF_TOP comes from the + // FSM. Note : Final EN_DIG_BUF_WLAN + // reaches on TOP_CLKM_REG1_IN[14] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_CLK_EN_TOP_LOWV_OVERRIDE_CTRL \ + 0x00100000 // 1 - EN_DIG_BUF_TOP comes from + // bit [15] of this register. 0 - + // EN_DIG_BUF_TOP comes from the + // FSM. Note : Final EN_DIG_BUF_TOP + // reaches on TOP_CLKM_REG1_IN[15] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_XTAL_OVERRIDE_CTRL \ + 0x00080000 // 1 - EN_XTAL comes from bit [3] + // of this register. 0 - EN_XTAL + // comes from FSM. Note : Final + // XTAL_EN reaches on + // TOP_CLKM_REG1_IN[3] of gprcm. + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLI_HV_OVERRIDE_CTRL \ + 0x00040000 // 1 - Enable HV Slicer comes from + // bit [2] of this register. 0 - + // Enable HV Slicer comes from FSM. + // Note : Final HV_SLICER_EN reaches + // on port TOP_CLKM_REG1_IN[1] of + // gprcm. + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLI_LV_OVERRIDE_CTRL \ + 0x00020000 // 1 - Enable LV Slicer comes from + // bit[1] of this register. 0 - + // Enable LV Slicer comes from FSM. + // Note : final LV_SLICER_EN reaches + // on port TOP_CLKM_REG1_IN[2] of + // gprcm. + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLI_HV_PDN_OVERRIDE_CTRL \ + 0x00010000 // 1 - Enable HV Pull-down comes + // from bit[0] of this register. 0 - + // Enable HV Pull-down comes from + // FSM. Note : Final HV_PULL_DOWN + // reaches on port + // TOP_CLKM_REG1_IN[0] of gprcm. + +#define GPRCM_REF_SLICER_CONTROLS0_CLK_EN_TOP_LOWV \ + 0x00008000 // Override for EN_DIG_BUF_TOP. + // Applicable if bit[20] is set to + // 1. Note : Final EN_DIG_BUF_TOP + // reaches on TOP_CLKM_REG1_IN[15] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_CLK_EN_WLAN_LOWV \ + 0x00004000 // Override for EN_DIG_BUF_WLAN. + // Applicable if bit[19] is set to + // 1. Note : Final EN_DIG_BUF_WLAN + // reaches on TOP_CLKM_REG1_IN[14] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_CLKOUT_FLIP_EN \ + 0x00002000 // CLKOUT Flip Enable. Reaches on + // bit[13] of TOP_CLKM_REG1_IN[13] + // port of gprcm. + +#define GPRCM_REF_SLICER_CONTROLS0_EN_DIV2_WLAN_CLK \ + 0x00001000 // Enable divide2 in WLAN Clk-path. + // Reaches on TOP_CLKM_REG1_IN[12] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_DIV3_WLAN_CLK \ + 0x00000800 // Enable divide3 in WLAN Clk-path. + // Reaches on TOP_CLKM_REG1_IN[11] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_DIV4_WLAN_CLK \ + 0x00000400 // Enable divide4 in WLAN Clk-path. + // Reaches on TOP_CLKM_REG1_IN[10] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_CM_TMUX_SEL_LOWV_M \ + 0x000003C0 // CM Test-mux select. Reaches on + // TOP_CLMM_REG1_IN[9:6] port of + // gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_CM_TMUX_SEL_LOWV_S 6 +#define GPRCM_REF_SLICER_CONTROLS0_SLICER_SPARE0_M \ + 0x00000030 // Slicer spare0 control. Reaches + // on TOP_CLKM_REG1_IN[5:4] port of + // gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_SLICER_SPARE0_S 4 +#define GPRCM_REF_SLICER_CONTROLS0_EN_XTAL \ + 0x00000008 // Enable XTAL override. Reaches on + // TOP_CLKM_REG1_IN[3] port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLICER_HV \ + 0x00000004 // Enable HV Slicer override. + // Reaches on TOP_CLKM_REG1_IN[1] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLICER_LV \ + 0x00000002 // Enable LV Slicer override. + // Reaches on TOP_CLKM_REG1_IN[2] + // port of gprcm + +#define GPRCM_REF_SLICER_CONTROLS0_EN_SLICER_HV_PDN \ + 0x00000001 // Enable HV Pull-down override. + // Reaches on TOP_CLKM_REG1_IN[0] + // port of gprcm + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_SLICER_CONTROLS1 register. +// +//****************************************************************************** +#define GPRCM_REF_SLICER_CONTROLS1_SLICER_SPARE1_M \ + 0x0000FC00 // Slicer spare1. Reaches on port + // TOP_CLKM_REG2_IN[15:10] of gprcm. + +#define GPRCM_REF_SLICER_CONTROLS1_SLICER_SPARE1_S 10 +#define GPRCM_REF_SLICER_CONTROLS1_XOSC_TRIM_M \ + 0x000003F0 // XOSC Trim. Reaches on port + // TOP_CLKM_REG2_IN[9:4] of gprcm + +#define GPRCM_REF_SLICER_CONTROLS1_XOSC_TRIM_S 4 +#define GPRCM_REF_SLICER_CONTROLS1_SLICER_ITRIM_CHANGE_TOGGLE \ + 0x00000008 // Slicer ITRIM Toggle. Reaches on + // port TOP_CLKM_REG2_IN[3] of + // gprcm. + +#define GPRCM_REF_SLICER_CONTROLS1_SLICER_LV_TRIM_M \ + 0x00000007 // LV Slicer trim. Reaches on port + // TOP_CLKM_REG2_IN[2:0] of gprcm. + +#define GPRCM_REF_SLICER_CONTROLS1_SLICER_LV_TRIM_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_ANA_BGAP_CONTROLS0 register. +// +//****************************************************************************** +#define GPRCM_REF_ANA_BGAP_CONTROLS0_reserved_M \ + 0xFF800000 + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_reserved_S 23 +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_mag_trim_override_ctrl \ + 0x00400000 // 1 - REF_MAG_TRIM comes from + // bit[4:0] of register + // REF_ANA_BGAP_CONTROLS1 [Addr : + // 0x0850]; 0 - REF_MAG_TRIM comes + // from efuse (After efc_done = 1). + // Note : Final REF_MAG_TRIM reaches + // on port TOP_PM_REG1[4:0] of gprcm + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_v2i_trim_override_ctrl \ + 0x00200000 // 1 - REF_V2I_TRIM comes from + // bit[9:6] of this register ; 0 - + // REF_V2I_TRIM comes from efuse + // (After efc_done = 1). Note : + // Final REF_V2I_TRIM reaches on + // port TOP_PM_REG0[9:6] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_temp_trim_override_ctrl \ + 0x00100000 // 1 - REF_TEMP_TRIM comes from + // bit[15:10] of this register ; 0 - + // REF_TEMP_TRIM comes from efuse + // (After efc_done = 1). Note : + // Final REF_TEMP_TRIM reaches on + // port TOP_PM_REG0[15:10] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_startup_en_override_ctrl \ + 0x00080000 // 1 - REF_STARTUP_EN comes from + // bit [3] of this register ; 0 - + // REF_STARTUP_EN comes from FSM. + // Note : Final REF_STARTUP_EN + // reaches on port TOP_PM_REG0[3] of + // gprcm + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_v2i_en_override_ctrl \ + 0x00040000 // 1 - REF_V2I_EN comes from bit + // [2] of this register ; 0 - + // REF_V2I_EN comes from FSM. Note : + // Final REF_V2I_EN reaches on port + // TOP_PM_REG0[2] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_fc_en_override_ctrl \ + 0x00020000 // 1 - REF_FC_EN comes from bit [1] + // of this register ; 0 - REF_FC_EN + // comes from FSM. Note : Final + // REF_FC_EN reaches on port + // TOP_PM_REG0[1] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_bgap_en_override_ctrl \ + 0x00010000 // 1 - REF_BGAP_EN comes from bit + // [0] of this register ; 0 - + // REF_BGAP_EN comes from FSM. Note + // : Final REF_BGAP_EN reaches on + // port TOP_PM_REG0[0] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_temp_trim_M \ + 0x0000FC00 // REF_TEMP_TRIM override. + // Applicable when bit [20] of this + // register set to 1. (or efc_done = + // 0) Note : Final REF_TEMP_TRIM + // reaches on port + // TOP_PM_REG0[15:10] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_temp_trim_S 10 +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_v2i_trim_M \ + 0x000003C0 // REF_V2I_TRIM Override. + // Applicable when bit [21] of this + // register set to 1 . (of efc_done + // = 0) Note : Final REF_V2I_TRIM + // reaches on port TOP_PM_REG0[9:6] + // of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_v2i_trim_S 6 +#define GPRCM_REF_ANA_BGAP_CONTROLS0_NU1_M \ + 0x00000030 + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_NU1_S 4 +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_startup_en \ + 0x00000008 // REF_STARTUP_EN override. + // Applicable when bit [19] of this + // register is set to 1. Note : + // Final REF_STARTUP_EN reaches on + // port TOP_PM_REG0[3] of gprcm + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_v2i_en \ + 0x00000004 // REF_V2I_EN override. Applicable + // when bit [21] of this register is + // set to 1. Note : Final REF_V2I_EN + // reaches on port TOP_PM_REG0[2] of + // gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_fc_en \ + 0x00000002 // REF_FC_EN override. Applicable + // when bit [17] of this register is + // set to 1. Note : Final REF_FC_EN + // reaches on port TOP_PM_REG0[1] of + // gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS0_mem_ref_bgap_en \ + 0x00000001 // REF_BGAP_EN override. Applicable + // when bit [16] of this register + // set to 1. Note : Final + // REF_BGAP_EN reaches on port + // TOP_PM_REG0[0] of gprcm. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_ANA_BGAP_CONTROLS1 register. +// +//****************************************************************************** +#define GPRCM_REF_ANA_BGAP_CONTROLS1_reserved_M \ + 0xFFFF0000 + +#define GPRCM_REF_ANA_BGAP_CONTROLS1_reserved_S 16 +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_bg_spare_M \ + 0x0000C000 // REF_BGAP_SPARE. Reaches on port + // TOP_PM_REG1[15:14] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_bg_spare_S 14 +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_bgap_tmux_ctrl_M \ + 0x00003E00 // REF_BGAP_TMUX_CTRL. Reaches on + // port TOP_PM_REG1[13:9] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_bgap_tmux_ctrl_S 9 +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_filt_trim_M \ + 0x000001E0 // REF_FILT_TRIM. Reaches on port + // TOP_PM_REG1[8:5] of gprcm. + +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_filt_trim_S 5 +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_mag_trim_M \ + 0x0000001F // REF_MAG_TRIM Override. + // Applicable when bit[22] of + // REF_ANA_BGAP_CONTROLS0 [0x084C] + // set to 1 (of efc_done = 0). Note + // : Final REF_MAG_TRIM reaches on + // port TOP_PM_REG1[4:0] of gprcm + +#define GPRCM_REF_ANA_BGAP_CONTROLS1_mem_ref_mag_trim_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_ANA_SPARE_CONTROLS0 register. +// +//****************************************************************************** +#define GPRCM_REF_ANA_SPARE_CONTROLS0_reserved_M \ + 0xFFFF0000 + +#define GPRCM_REF_ANA_SPARE_CONTROLS0_reserved_S 16 +#define GPRCM_REF_ANA_SPARE_CONTROLS0_mem_top_pm_reg3_M \ + 0x0000FFFF // Spare control. Reaches on + // TOP_PM_REG3 [15:0] of gprcm. + +#define GPRCM_REF_ANA_SPARE_CONTROLS0_mem_top_pm_reg3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_ANA_SPARE_CONTROLS1 register. +// +//****************************************************************************** +#define GPRCM_REF_ANA_SPARE_CONTROLS1_mem_top_clkm_reg3_M \ + 0xFFFF0000 // Spare control. Reaches on + // TOP_CLKM_REG3 [15:0] of gprcm. + +#define GPRCM_REF_ANA_SPARE_CONTROLS1_mem_top_clkm_reg3_S 16 +#define GPRCM_REF_ANA_SPARE_CONTROLS1_mem_top_clkm_reg4_M \ + 0x0000FFFF // Spare control. Reaches on + // TOP_CLKM_REG4 [15:0] of gprcm. + +#define GPRCM_REF_ANA_SPARE_CONTROLS1_mem_top_clkm_reg4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEMSS_PSCON_OVERRIDES0 register. +// +//****************************************************************************** +#define GPRCM_MEMSS_PSCON_OVERRIDES0_mem_memss_pscon_mem_off_override_M \ + 0xFFFF0000 + +#define GPRCM_MEMSS_PSCON_OVERRIDES0_mem_memss_pscon_mem_off_override_S 16 +#define GPRCM_MEMSS_PSCON_OVERRIDES0_mem_memss_pscon_mem_retain_override_M \ + 0x0000FFFF + +#define GPRCM_MEMSS_PSCON_OVERRIDES0_mem_memss_pscon_mem_retain_override_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEMSS_PSCON_OVERRIDES1 register. +// +//****************************************************************************** +#define GPRCM_MEMSS_PSCON_OVERRIDES1_reserved_M \ + 0xFFFFFFC0 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_reserved_S 6 +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memss_pscon_mem_update_override_ctrl \ + 0x00000020 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memss_pscon_mem_update_override \ + 0x00000010 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memss_pscon_sleep_override_ctrl \ + 0x00000008 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memss_pscon_sleep_override \ + 0x00000004 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memss_pscon_mem_off_override_ctrl \ + 0x00000002 + +#define GPRCM_MEMSS_PSCON_OVERRIDES1_mem_memms_pscon_mem_retain_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_PLL_REF_LOCK_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_PLL_REF_LOCK_OVERRIDES_reserved_M \ + 0xFFFFFFF8 + +#define GPRCM_PLL_REF_LOCK_OVERRIDES_reserved_S 3 +#define GPRCM_PLL_REF_LOCK_OVERRIDES_mem_mcu_apllmcs_lock_override \ + 0x00000004 + +#define GPRCM_PLL_REF_LOCK_OVERRIDES_mem_wlan_apllmcs_lock_override \ + 0x00000002 + +#define GPRCM_PLL_REF_LOCK_OVERRIDES_mem_ref_clk_valid_override \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCU_PSCON_DEBUG register. +// +//****************************************************************************** +#define GPRCM_MCU_PSCON_DEBUG_reserved_M \ + 0xFFFFFFC0 + +#define GPRCM_MCU_PSCON_DEBUG_reserved_S 6 +#define GPRCM_MCU_PSCON_DEBUG_mcu_pscon_rtc_ps_M \ + 0x00000038 // MCU_PSCON_RTC_ON = "0000"; + // MCU_PSCON_RTC_OFF = "0001"; + // MCU_PSCON_RTC_RET = "0010"; + // MCU_PSCON_RTC_OFF_TO_ON = "0011"; + // MCU_PSCON_RTC_RET_TO_ON = "0100"; + // MCU_PSCON_RTC_ON_TO_RET = "0101"; + // MCU_PSCON_RTC_ON_TO_OFF = "0110"; + // MCU_PSCON_RTC_RET_TO_ON_WAIT_OPP + // = "0111"; + // MCU_PSCON_RTC_OFF_TO_ON_WAIT_OPP + // = "1000"; + +#define GPRCM_MCU_PSCON_DEBUG_mcu_pscon_rtc_ps_S 3 +#define GPRCM_MCU_PSCON_DEBUG_mcu_pscon_sys_ps_M \ + 0x00000007 + +#define GPRCM_MCU_PSCON_DEBUG_mcu_pscon_sys_ps_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEMSS_PWR_PS register. +// +//****************************************************************************** +#define GPRCM_MEMSS_PWR_PS_reserved_M \ + 0xFFFFFFF8 + +#define GPRCM_MEMSS_PWR_PS_reserved_S 3 +#define GPRCM_MEMSS_PWR_PS_pwr_ps_memss_M \ + 0x00000007 // MEMSS_PM_SLEEP = "000"; + // MEMSS_PM_WAIT_OPP = "010"; + // MEMSS_PM_ACTIVE = "011"; + // MEMSS_PM_SLEEP_TO_ACTIVE = "100"; + // MEMSS_PM_ACTIVE_TO_SLEEP = "101"; + +#define GPRCM_MEMSS_PWR_PS_pwr_ps_memss_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_REF_FSM_DEBUG register. +// +//****************************************************************************** +#define GPRCM_REF_FSM_DEBUG_reserved_M \ + 0xFFFFFFC0 + +#define GPRCM_REF_FSM_DEBUG_reserved_S 6 +#define GPRCM_REF_FSM_DEBUG_fref_mode_M \ + 0x00000030 // 01 - HV Mode ; 10 - LV Mode ; 11 + // - XTAL Mode + +#define GPRCM_REF_FSM_DEBUG_fref_mode_S 4 +#define GPRCM_REF_FSM_DEBUG_ref_fsm_ps_M \ + 0x0000000F // constant FREF_CLK_OFF = "00000"; + // constant FREF_EN_BGAP = "00001"; + // constant FREF_EN_LDO = "00010"; + // constant FREF_EN_SLI_HV = + // "00011"; constant + // FREF_EN_SLI_HV_PD = "00100"; + // constant FREF_EN_DIG_BUF = + // "00101"; constant FREF_EN_OSC = + // "00110"; constant FREF_EN_SLI_LV + // = "00111"; constant + // FREF_EN_CLK_REQ = "01000"; + // constant FREF_CLK_VALID = + // "01001"; constant FREF_MODE_DET0 + // = "01010"; constant + // FREF_MODE_DET1 = "01011"; + // constant FREF_MODE_DET2 = + // "10010"; constant FREF_MODE_DET3 + // = "10011"; constant FREF_VALID = + // "01100"; constant FREF_VALID0 = + // "01101"; constant FREF_VALID1 = + // "01110"; constant FREF_VALID2 = + // "01111"; constant + // FREF_WAIT_EXT_TCXO0 = "10000"; + // constant FREF_WAIT_EXT_TCXO1 = + // "10001"; + +#define GPRCM_REF_FSM_DEBUG_ref_fsm_ps_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_SYS_OPP_REQ_OVERRIDE register. +// +//****************************************************************************** +#define GPRCM_MEM_SYS_OPP_REQ_OVERRIDE_reserved_M \ + 0xFFFFFFE0 + +#define GPRCM_MEM_SYS_OPP_REQ_OVERRIDE_reserved_S 5 +#define GPRCM_MEM_SYS_OPP_REQ_OVERRIDE_mem_sys_opp_req_override_ctrl \ + 0x00000010 // 1 - Override the sytem-opp + // request to ANATOP using bit0 of + // this register + +#define GPRCM_MEM_SYS_OPP_REQ_OVERRIDE_mem_sys_opp_req_override_M \ + 0x0000000F // "0001" - RUN ; "0010" - DSLP ; + // "0100" - LPDS ; Others - NA + +#define GPRCM_MEM_SYS_OPP_REQ_OVERRIDE_mem_sys_opp_req_override_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_TESTCTRL_PD_OPP_CONFIG register. +// +//****************************************************************************** +#define GPRCM_MEM_TESTCTRL_PD_OPP_CONFIG_reserved_M \ + 0xFFFFFFFE + +#define GPRCM_MEM_TESTCTRL_PD_OPP_CONFIG_reserved_S 1 +#define GPRCM_MEM_TESTCTRL_PD_OPP_CONFIG_mem_sleep_opp_enter_with_testpd_on \ + 0x00000001 // 1 - Enable sleep-opp (DSLP/LPDS) + // entry even if Test-Pd is kept ON + // ; 0 - Donot enable sleep-opp + // (DSLP/LPDS) entry with Test-Pd + // ON. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_WL_FAST_CLK_REQ_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MEM_WL_FAST_CLK_REQ_OVERRIDES_reserved_M \ + 0xFFFFFFF8 + +#define GPRCM_MEM_WL_FAST_CLK_REQ_OVERRIDES_reserved_S 3 +#define GPRCM_MEM_WL_FAST_CLK_REQ_OVERRIDES_mem_wl_fast_clk_req_override_ctrl \ + 0x00000004 // NA + +#define GPRCM_MEM_WL_FAST_CLK_REQ_OVERRIDES_mem_wl_fast_clk_req_override \ + 0x00000002 // NA + +#define GPRCM_MEM_WL_FAST_CLK_REQ_OVERRIDES_mem_wl_sleep_with_clk_req_override \ + 0x00000001 // NA + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_MCU_PD_MODE_REQ_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MEM_MCU_PD_MODE_REQ_OVERRIDES_mem_mcu_pd_mode_req_override_ctrl \ + 0x00000004 // 1 - Override the MCU-PD power + // modes using bits [1] & [0] ; + +#define GPRCM_MEM_MCU_PD_MODE_REQ_OVERRIDES_mem_mcu_pd_pwrdn_req_override \ + 0x00000002 // 1 - Request for power-down of + // MCU-PD ; + +#define GPRCM_MEM_MCU_PD_MODE_REQ_OVERRIDES_mem_mcu_pd_ret_req_override \ + 0x00000001 // 1 - Request for retention mode + // of MCU-PD. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_MCSPI_SRAM_OFF_REQ_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MEM_MCSPI_SRAM_OFF_REQ_OVERRIDES_mem_mcspi_sram_off_req_override_ctrl \ + 0x00000002 // 1- Override the MCSPI + // (Autonomous SPI) memory state + // using bit [0] + +#define GPRCM_MEM_MCSPI_SRAM_OFF_REQ_OVERRIDES_mem_mcspi_sram_off_req_override \ + 0x00000001 // 1 - Request for power-down of + // Autonomous SPI 8k memory ; 0 - + // Donot request power-down of + // Autonomous SPI 8k Memory + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_WLAN_APLLMCS_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MEM_WLAN_APLLMCS_OVERRIDES_wlan_apllmcs_lock \ + 0x00000100 + +#define GPRCM_MEM_WLAN_APLLMCS_OVERRIDES_mem_wlan_apllmcs_enable_override \ + 0x00000002 + +#define GPRCM_MEM_WLAN_APLLMCS_OVERRIDES_mem_wlan_apllmcs_enable_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_REF_FSM_CFG2 register. +// +//****************************************************************************** +#define GPRCM_MEM_REF_FSM_CFG2_MEM_FC_DEASSERT_DELAY_M \ + 0x00380000 // Number of RTC clocks for keeping + // the FC_EN asserted high + +#define GPRCM_MEM_REF_FSM_CFG2_MEM_FC_DEASSERT_DELAY_S 19 +#define GPRCM_MEM_REF_FSM_CFG2_MEM_STARTUP_DEASSERT_DELAY_M \ + 0x00070000 // Number of RTC clocks for keeping + // the STARTUP_EN asserted high + +#define GPRCM_MEM_REF_FSM_CFG2_MEM_STARTUP_DEASSERT_DELAY_S 16 +#define GPRCM_MEM_REF_FSM_CFG2_MEM_EXT_TCXO_SETTLING_TIME_M \ + 0x0000FFFF // Number of RTC clocks for waiting + // for clock to settle. + +#define GPRCM_MEM_REF_FSM_CFG2_MEM_EXT_TCXO_SETTLING_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_TESTCTRL_POWER_CTRL register. +// +//****************************************************************************** +#define GPRCM_TESTCTRL_POWER_CTRL_TESTCTRL_PD_STATUS_M \ + 0x00000006 + +#define GPRCM_TESTCTRL_POWER_CTRL_TESTCTRL_PD_STATUS_S 1 +#define GPRCM_TESTCTRL_POWER_CTRL_TESTCTRL_PD_ENABLE \ + 0x00000001 // 0 - Disable the TestCtrl-pd ; 1 + // - Enable the TestCtrl-pd. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_SSDIO_POWER_CTRL register. +// +//****************************************************************************** +#define GPRCM_SSDIO_POWER_CTRL_SSDIO_PD_STATUS_M \ + 0x00000006 // 1 - SSDIO-PD is ON ; 0 - + // SSDIO-PD is OFF + +#define GPRCM_SSDIO_POWER_CTRL_SSDIO_PD_STATUS_S 1 +#define GPRCM_SSDIO_POWER_CTRL_SSDIO_PD_ENABLE \ + 0x00000001 // 0 - Disable the SSDIO-pd ; 1 - + // Enable the SSDIO-pd. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCSPI_N1_POWER_CTRL register. +// +//****************************************************************************** +#define GPRCM_MCSPI_N1_POWER_CTRL_MCSPI_N1_PD_STATUS_M \ + 0x00000006 // 1 - MCSPI_N1-PD is ON ; 0 - + // MCSPI_N1-PD if OFF + +#define GPRCM_MCSPI_N1_POWER_CTRL_MCSPI_N1_PD_STATUS_S 1 +#define GPRCM_MCSPI_N1_POWER_CTRL_MCSPI_N1_PD_ENABLE \ + 0x00000001 // 0 - Disable the MCSPI_N1-pd ; 1 + // - Enable the MCSPI_N1-pd. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WELP_POWER_CTRL register. +// +//****************************************************************************** +#define GPRCM_WELP_POWER_CTRL_WTOP_PD_STATUS_M \ + 0x00001C00 + +#define GPRCM_WELP_POWER_CTRL_WTOP_PD_STATUS_S 10 +#define GPRCM_WELP_POWER_CTRL_WTOP_PD_REQ_OVERRIDE \ + 0x00000200 + +#define GPRCM_WELP_POWER_CTRL_WTOP_PD_REQ_OVERRIDE_CTRL \ + 0x00000100 + +#define GPRCM_WELP_POWER_CTRL_WELP_PD_STATUS_M \ + 0x00000006 + +#define GPRCM_WELP_POWER_CTRL_WELP_PD_STATUS_S 1 +#define GPRCM_WELP_POWER_CTRL_WELP_PD_ENABLE \ + 0x00000001 // 0 - Disable the WELP-pd ; 1 - + // Enable the WELP-pd. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WL_SDIO_POWER_CTRL register. +// +//****************************************************************************** +#define GPRCM_WL_SDIO_POWER_CTRL_WL_SDIO_PD_STATUS_M \ + 0x00000006 + +#define GPRCM_WL_SDIO_POWER_CTRL_WL_SDIO_PD_STATUS_S 1 +#define GPRCM_WL_SDIO_POWER_CTRL_WL_SDIO_PD_ENABLE \ + 0x00000001 // 0 - Disable the WL_SDIO-pd ; 1 - + // Enable the WL_SDIO-pd. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WLAN_SRAM_ACTIVE_PWR_CFG register. +// +//****************************************************************************** +#define GPRCM_WLAN_SRAM_ACTIVE_PWR_CFG_WLAN_SRAM_ACTIVE_PWR_CFG_M \ + 0x00FFFFFF // SRAM (WTOP+DRP) state during + // Active-mode : 1 - SRAMs are ON ; + // 0 - SRAMs are OFF. Cluster + // information : [0] - 1st column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) [1] - 2nd column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [2] - 3rd column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [3] - 4th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [4] - + // 5th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [5] - 6th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [6] - 7th column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [7] - 8th column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [8] - 9th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [9] - + // 10th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [10] - 11th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [11] - 12th column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [12] - 13th column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [13] - 14th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [14] - + // 15th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [15] - 16th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [23:16] - Internal to + // WTOP Cluster + +#define GPRCM_WLAN_SRAM_ACTIVE_PWR_CFG_WLAN_SRAM_ACTIVE_PWR_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WLAN_SRAM_SLEEP_PWR_CFG register. +// +//****************************************************************************** +#define GPRCM_WLAN_SRAM_SLEEP_PWR_CFG_WLAN_SRAM_SLEEP_PWR_CFG_M \ + 0x00FFFFFF // SRAM (WTOP+DRP) state during + // Sleep-mode : 1 - SRAMs are RET ; + // 0 - SRAMs are OFF. Cluster + // information : [0] - 1st column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) [1] - 2nd column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [2] - 3rd column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [3] - 4th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [4] - + // 5th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [5] - 6th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [6] - 7th column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [7] - 8th column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [8] - 9th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [9] - + // 10th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [10] - 11th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [11] - 12th column of + // MEMSS (Applicable only when owned + // by WTOP/PHY) ; [12] - 13th column + // of MEMSS (Applicable only when + // owned by WTOP/PHY) ; [13] - 14th + // column of MEMSS (Applicable only + // when owned by WTOP/PHY) ; [14] - + // 15th column of MEMSS (Applicable + // only when owned by WTOP/PHY) ; + // [15] - 16th column of MEMSS + // (Applicable only when owned by + // WTOP/PHY) ; [23:16] - Internal to + // WTOP Cluster + +#define GPRCM_WLAN_SRAM_SLEEP_PWR_CFG_WLAN_SRAM_SLEEP_PWR_CFG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_SECURE_INIT_DONE register. +// +//****************************************************************************** +#define GPRCM_APPS_SECURE_INIT_DONE_SECURE_INIT_DONE_STATUS \ + 0x00000002 // 1-Secure mode init is done ; + // 0-Secure mode init is not done + +#define GPRCM_APPS_SECURE_INIT_DONE_APPS_SECURE_INIT_DONE \ + 0x00000001 // Must be programmed 1 in order to + // say that secure-mode device init + // is done + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_DEV_MODE_INIT_DONE register. +// +//****************************************************************************** +#define GPRCM_APPS_DEV_MODE_INIT_DONE_APPS_DEV_MODE_INIT_DONE \ + 0x00000001 // 1 - Patch download and other + // initializations are done (before + // removing APPS resetn) for + // development mode (#3) . 0 - + // Development mode (#3) init is not + // done yet + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_EN_APPS_REBOOT register. +// +//****************************************************************************** +#define GPRCM_EN_APPS_REBOOT_EN_APPS_REBOOT \ + 0x00000001 // 1 - When 1, disable the reboot + // of APPS after DevInit is + // completed. In this case, APPS + // will permanantly help in reset. 0 + // - When 0, enable the reboot of + // APPS after DevInit is completed. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_APPS_PERIPH_PRESENT register. +// +//****************************************************************************** +#define GPRCM_MEM_APPS_PERIPH_PRESENT_WLAN_GEM_PP \ + 0x00010000 // 1 - Enable ; 0 - Disable + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_AES_PP \ + 0x00008000 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_DES_PP \ + 0x00004000 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_SHA_PP \ + 0x00002000 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_CAMERA_PP \ + 0x00001000 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_MMCHS_PP \ + 0x00000800 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_MCASP_PP \ + 0x00000400 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_MCSPI_A1_PP \ + 0x00000200 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_MCSPI_A2_PP \ + 0x00000100 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_UDMA_PP \ + 0x00000080 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_WDOG_PP \ + 0x00000040 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_UART_A0_PP \ + 0x00000020 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_UART_A1_PP \ + 0x00000010 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_GPT_A0_PP \ + 0x00000008 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_GPT_A1_PP \ + 0x00000004 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_GPT_A2_PP \ + 0x00000002 + +#define GPRCM_MEM_APPS_PERIPH_PRESENT_APPS_GPT_A3_PP \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_NWP_PERIPH_PRESENT register. +// +//****************************************************************************** +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_ASYNC_BRIDGE_PP \ + 0x00000200 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_MCSPI_N2_PP \ + 0x00000100 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_GPT_N0_PP \ + 0x00000080 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_GPT_N1_PP \ + 0x00000040 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_WDOG_PP \ + 0x00000020 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_UDMA_PP \ + 0x00000010 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_UART_N0_PP \ + 0x00000008 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_UART_N1_PP \ + 0x00000004 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_SSDIO_PP \ + 0x00000002 + +#define GPRCM_MEM_NWP_PERIPH_PRESENT_NWP_MCSPI_N1_PP \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MEM_SHARED_PERIPH_PRESENT register. +// +//****************************************************************************** + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_MCSPI_PP \ + 0x00000040 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_I2C_PP \ + 0x00000020 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_GPIO_A_PP \ + 0x00000010 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_GPIO_B_PP \ + 0x00000008 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_GPIO_C_PP \ + 0x00000004 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_GPIO_D_PP \ + 0x00000002 + +#define GPRCM_MEM_SHARED_PERIPH_PRESENT_SHARED_GPIO_E_PP \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_PWR_STATE register. +// +//****************************************************************************** +#define GPRCM_NWP_PWR_STATE_NWP_PWR_STATE_PS_M \ + 0x00000F00 // "0000"- PORZ :- NWP is yet to be + // enabled by APPS during powerup + // (from HIB/OFF) ; "0011"- ACTIVE + // :- NWP is enabled, clocks and + // resets to NWP-SubSystem are + // enabled ; "0010"- LPDS :- NWP is + // in LPDS-mode ; Clocks and reset + // to NWP-SubSystem are gated ; + // "0101"- WAIT_FOR_OPP :- NWP is in + // transition from LPDS to ACTIVE, + // where it is waiting for OPP to be + // stable ; "1000"- + // WAKE_TIMER_OPP_REQ :- NWP is in + // transition from LPDS, where the + // wakeup cause is LPDS_Wake timer + // OTHERS : NA + +#define GPRCM_NWP_PWR_STATE_NWP_PWR_STATE_PS_S 8 +#define GPRCM_NWP_PWR_STATE_NWP_RCM_PS_M \ + 0x00000007 // "000" - NWP_RUN : NWP is in RUN + // state (default) - Applicable only + // when NWP_PWR_STATE_PS = ACTIVE ; + // "001" - NWP_SLP : NWP is in SLEEP + // state (default) - Applicable only + // when NWP_PWR_STATE_PS = ACTIVE ; + // "010" - NWP_DSLP : NWP is in + // Deep-Sleep state (default) - + // Applicable only when + // NWP_PWR_STATE_PS = ACTIVE ; "011" + // - WAIT_FOR_ACTIVE : NWP is in + // transition from Deep-sleep to + // Run, where it is waiting for OPP + // to be stable ; "100" - + // WAIT_FOR_DSLP_TIMER_WAKE_REQ : + // NWP is in transition from + // Deep-sleep to Run, where the + // wakeup cause is deep-sleep + // wake-timer + +#define GPRCM_NWP_PWR_STATE_NWP_RCM_PS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_PWR_STATE register. +// +//****************************************************************************** +#define GPRCM_APPS_PWR_STATE_APPS_PWR_STATE_PS_M \ + 0x00000F00 // "0000"- PORZ :- APPS is waiting + // for PLL_clock during powerup + // (from HIB/OFF) ; "0011"- ACTIVE + // :- APPS is enabled, clocks and + // resets to APPS-SubSystem are + // enabled ; APPS might be either in + // Secure or Un-secure mode during + // this state. "1001" - + // SECURE_MODE_LPDS :- While in + // ACTIVE (Secure-mode), APPS had to + // program the DevInit_done bit at + // the end, after which it enters + // into this state, where the reset + // to APPS will be asserted. From + // this state APPS might either + // re-boot itself or enter into LPDS + // depending upon whether the device + // is 3200 or 3100. "0010"- LPDS :- + // APPS is in LPDS-mode ; Clocks and + // reset to APPS-SubSystem are gated + // ; "0101"- WAIT_FOR_OPP :- APPS is + // in transition from LPDS to + // ACTIVE, where it is waiting for + // OPP to be stable ; "1000" - + // WAKE_TIMER_OPP_REQ : APPS is in + // transition from LPDS, where the + // wakeup cause is LPDS_Wake timer ; + // "1010" - WAIT_FOR_PATCH_INIT : + // APPS enters into this state + // during development-mode #3 (SOP = + // 3), where it is waiting for patch + // download to complete and 0x4 hack + // is programmed. OTHERS : NA + +#define GPRCM_APPS_PWR_STATE_APPS_PWR_STATE_PS_S 8 +#define GPRCM_APPS_PWR_STATE_APPS_RCM_PS_M \ + 0x00000007 // "000" - APPS_RUN : APPS is in + // RUN state (default) - Applicable + // only when APPS_PWR_STATE_PS = + // ACTIVE ; "001" - APPS_SLP : APPS + // is in SLEEP state (default) - + // Applicable only when + // APPS_PWR_STATE_PS = ACTIVE ; + // "010" - APPS_DSLP : APPS is in + // Deep-Sleep state (default) - + // Applicable only when + // APPS_PWR_STATE_PS = ACTIVE ; + // "011" - WAIT_FOR_ACTIVE : APPS is + // in transition from Deep-sleep to + // Run, where it is waiting for OPP + // to be stable ; "100" - + // WAIT_FOR_DSLP_TIMER_WAKE_REQ : + // APPS is in transition from + // Deep-sleep to Run, where the + // wakeup cause is deep-sleep + // wake-timer + +#define GPRCM_APPS_PWR_STATE_APPS_RCM_PS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCU_PWR_STATE register. +// +//****************************************************************************** +#define GPRCM_MCU_PWR_STATE_MCU_OPP_PS_M \ + 0x0000001F // TBD + +#define GPRCM_MCU_PWR_STATE_MCU_OPP_PS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WTOP_PM_PS register. +// +//****************************************************************************** +#define GPRCM_WTOP_PM_PS_WTOP_PM_PS_M \ + 0x00000007 // "011" - WTOP_PM_ACTIVE (Default) + // :- WTOP_Pd is in ACTIVE mode; + // "100" - WTOP_PM_ACTIVE_TO_SLEEP + // :- WTOP_Pd is in transition from + // ACTIVE to SLEEP ; "000" - + // WTOP_PM_SLEEP : WTOP-Pd is in + // Sleep-state ; "100" - + // WTOP_PM_SLEEP_TO_ACTIVE : WTOP_Pd + // is in transition from SLEEP to + // ACTIVE ; "000" - + // WTOP_PM_WAIT_FOR_OPP : Wait for + // OPP to be stable ; + +#define GPRCM_WTOP_PM_PS_WTOP_PM_PS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WTOP_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_WTOP_PD_RESETZ_OVERRIDE_REG_WTOP_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for WTOP PD + // Resetz. When set to 1, + // WTOP_Resetz will be controlled by + // bit [0] + +#define GPRCM_WTOP_PD_RESETZ_OVERRIDE_REG_WTOP_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for WTOP PD Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WELP_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_WELP_PD_RESETZ_OVERRIDE_REG_WELP_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for WELP PD + // Resetz. When set to 1, + // WELP_Resetz will be controlled by + // bit [0] + +#define GPRCM_WELP_PD_RESETZ_OVERRIDE_REG_WELP_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for WELP PD Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WL_SDIO_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_WL_SDIO_PD_RESETZ_OVERRIDE_REG_WL_SDIO_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for WL_SDIO + // Resetz. When set to 1, + // WL_SDIO_Resetz will be controlled + // by bit [0] + +#define GPRCM_WL_SDIO_PD_RESETZ_OVERRIDE_REG_WL_SDIO_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for WL_SDIO Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_SSDIO_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_SSDIO_PD_RESETZ_OVERRIDE_REG_SSDIO_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for SSDIO + // Resetz. When set to 1, + // SSDIO_Resetz will be controlled + // by bit [0] + +#define GPRCM_SSDIO_PD_RESETZ_OVERRIDE_REG_SSDIO_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for SSDIO Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCSPI_N1_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_MCSPI_N1_PD_RESETZ_OVERRIDE_REG_MCSPI_N1_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for MCSPI_N1 + // Resetz. When set to 1, + // MCSPI_N1_Resetz will be + // controlled by bit [0] + +#define GPRCM_MCSPI_N1_PD_RESETZ_OVERRIDE_REG_MCSPI_N1_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for MCSPI_N1 Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_TESTCTRL_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_TESTCTRL_PD_RESETZ_OVERRIDE_REG_TESTCTRL_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for TESTCTRL-PD + // Resetz. When set to 1, + // TESTCTRL_Resetz will be + // controlled by bit [0] + +#define GPRCM_TESTCTRL_PD_RESETZ_OVERRIDE_REG_TESTCTRL_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for TESTCTRL Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCU_PD_RESETZ_OVERRIDE_REG register. +// +//****************************************************************************** +#define GPRCM_MCU_PD_RESETZ_OVERRIDE_REG_MCU_PD_RESETZ_OVERRIDE_CTRL \ + 0x00000100 // Override control for MCU-PD + // Resetz. When set to 1, MCU_Resetz + // will be controlled by bit [0] + +#define GPRCM_MCU_PD_RESETZ_OVERRIDE_REG_MCU_PD_RESETZ_OVERRIDE \ + 0x00000001 // Override for MCU Resetz. + // Applicable only when bit[8] is + // set to 1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG0 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG0_FUSEFARM_ROW_14_M \ + 0xFFFFFFFF // This is ROW_14 [31:0] of + // FUSEFARM. [0:0] : XTAL_IS_26MHZ + // [5:1] : TOP_CLKM_RTRIM[4:0] + // [10:6] : ANA_BGAP_MAG_TRIM[4:0] + // [16:11] : ANA_BGAP_TEMP_TRIM[5:0] + // [20:17] : ANA_BGAP_V2I_TRIM[3:0] + // [25:22] : PROCESS INDICATOR + // [26:26] : Reserved [31:27] : + // FUSEROM Version + +#define GPRCM_GPRCM_EFUSE_READ_REG0_FUSEFARM_ROW_14_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG1 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG1_FUSEFARM_ROW_15_LSW_M \ + 0x0000FFFF // This is ROW_15[15:0] of FUSEFARM + // 1. NWP Peripheral Present bits + // [15:8] NWP_GPT_N0_PP [15:15] + // NWP_GPT_N1_PP [14:14] NWP_WDOG_PP + // [13:13] NWP_UDMA_PP [12:12] + // NWP_UART_N0_PP [11:11] + // NWP_UART_N1_PP [10:10] + // NWP_SSDIO_PP [9:9] + // NWP_MCSPI_N1_PP [8:8] 2. Shared + // Peripheral Present bits [7:0] + // SHARED SPI PP [6:6] + // SHARED I2C PP [5:5] SHARED + // GPIO-A PP [4:4] SHARED GPIO-B PP + // [3:3] SHARED GPIO-C PP [2:2] + // SHARED GPIO-D PP [1:1] SHARED + // GPIO-E PP [0:0] + +#define GPRCM_GPRCM_EFUSE_READ_REG1_FUSEFARM_ROW_15_LSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG2 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG2_FUSEFARM_ROW_16_LSW_ROW_15_MSW_M \ + 0xFFFFFFFF // This is ROW_16[15:0] & + // ROW_15[31:16] of FUSEFARM. + // [31:21] - Reserved [20:16] - + // CHIP_ID [15:15] - SSBD SOP + // Control [14:14] - SSBD TAP + // Control [13:2] - APPS Peripheral + // Present bits : APPS_CAMERA_PP + // [13:13] APPS_MMCHS_PP [12:12] + // APPS_MCASP_PP [11:11] + // APPS_MCSPI_A1_PP [10:10] + // APPS_MCSPI_A2_PP [9:9] + // APPS_UDMA_PP [8:8] APPS_WDOG_PP + // [7:7] APPS_UART_A0_PP [6:6] + // APPS_UART_A1_PP [5:5] + // APPS_GPT_A0_PP [4:4] + // APPS_GPT_A1_PP [3:3] + // APPS_GPT_A2_PP [2:2] + // APPS_GPT_A3_PP [1:1] [0:0] - NWP + // Peripheral present bits + // NWP_ACSPI_PP [0:0] + +#define GPRCM_GPRCM_EFUSE_READ_REG2_FUSEFARM_ROW_16_LSW_ROW_15_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG3 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG3_FUSEFARM_ROW_17_LSW_ROW_16_MSW_M \ + 0xFFFFFFFF // This is ROW_17[15:0] & + // ROW_16[31:16] of FUSEFARM : + // [31:16] - TEST_TAP_KEY(15:0) + // [15:0] - Reserved + +#define GPRCM_GPRCM_EFUSE_READ_REG3_FUSEFARM_ROW_17_LSW_ROW_16_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WTOP_MEM_RET_CFG register. +// +//****************************************************************************** +#define GPRCM_WTOP_MEM_RET_CFG_WTOP_MEM_RET_CFG \ + 0x00000001 // 1 - Soft-compile memories in + // WTOP can be turned-off during + // WTOP-sleep mode ; 0 - + // Soft-compile memories in WTOP + // must be kept on during WTOP-sleep + // mode. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_COEX_CLK_SWALLOW_CFG0 register. +// +//****************************************************************************** +#define GPRCM_COEX_CLK_SWALLOW_CFG0_Q_FACTOR_M \ + 0x007FFFFF // TBD + +#define GPRCM_COEX_CLK_SWALLOW_CFG0_Q_FACTOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_COEX_CLK_SWALLOW_CFG1 register. +// +//****************************************************************************** +#define GPRCM_COEX_CLK_SWALLOW_CFG1_P_FACTOR_M \ + 0x000FFFFF // TBD + +#define GPRCM_COEX_CLK_SWALLOW_CFG1_P_FACTOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_COEX_CLK_SWALLOW_CFG2 register. +// +//****************************************************************************** +#define GPRCM_COEX_CLK_SWALLOW_CFG2_CONSECUTIVE_SWALLOW_M \ + 0x00000018 + +#define GPRCM_COEX_CLK_SWALLOW_CFG2_CONSECUTIVE_SWALLOW_S 3 +#define GPRCM_COEX_CLK_SWALLOW_CFG2_PRBS_GAIN \ + 0x00000004 + +#define GPRCM_COEX_CLK_SWALLOW_CFG2_PRBS_ENABLE \ + 0x00000002 + +#define GPRCM_COEX_CLK_SWALLOW_CFG2_SWALLOW_ENABLE \ + 0x00000001 // TBD + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_COEX_CLK_SWALLOW_ENABLE register. +// +//****************************************************************************** +#define GPRCM_COEX_CLK_SWALLOW_ENABLE_COEX_CLK_SWALLOW_ENABLE \ + 0x00000001 // 1 - Enable switching of sysclk + // to Coex-clk path ; 0 - Disable + // switching of sysclk to Coex-clk + // path. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_DCDC_CLK_GEN_CONFIG register. +// +//****************************************************************************** +#define GPRCM_DCDC_CLK_GEN_CONFIG_DCDC_CLK_ENABLE \ + 0x00000001 // 1 - Enable the clock for DCDC + // (PWM-mode) ; 0 - Disable the + // clock for DCDC (PWM-mode) + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG4 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG4_FUSEFARM_ROW_17_MSW_M \ + 0x0000FFFF // This corresponds to + // ROW_17[31:16] of the FUSEFARM : + // [15:0] : TEST_TAP_KEY(31:16) + +#define GPRCM_GPRCM_EFUSE_READ_REG4_FUSEFARM_ROW_17_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG5 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG5_FUSEFARM_ROW_18_M \ + 0xFFFFFFFF // Corresponds to ROW_18 of + // FUSEFARM. [29:0] - + // MEMSS_COLUMN_SEL_LSW ; [30:30] - + // WLAN GEM DISABLE ; [31:31] - + // SERIAL WIRE JTAG SELECT + +#define GPRCM_GPRCM_EFUSE_READ_REG5_FUSEFARM_ROW_18_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG6 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG6_FUSEFARM_ROW_19_LSW_M \ + 0x0000FFFF // Corresponds to ROW_19[15:0] of + // FUSEFARM. [15:0] : + // MEMSS_COLUMN_SEL_MSW + +#define GPRCM_GPRCM_EFUSE_READ_REG6_FUSEFARM_ROW_19_LSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG7 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG7_FUSEFARM_ROW_20_LSW_ROW_19_MSW_M \ + 0xFFFFFFFF // Corresponds to ROW_20[15:0] & + // ROW_19[31:16] of FUSEFARM. + // FLASH_REGION0 + +#define GPRCM_GPRCM_EFUSE_READ_REG7_FUSEFARM_ROW_20_LSW_ROW_19_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG8 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG8_FUSEFARM_ROW_21_LSW_ROW_20_MSW_M \ + 0xFFFFFFFF // Corresponds to ROW_21[15:0] & + // ROW_20[31:16] of FUSEFARM. + // FLASH_REGION1 + +#define GPRCM_GPRCM_EFUSE_READ_REG8_FUSEFARM_ROW_21_LSW_ROW_20_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG9 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG9_FUSEFARM_ROW_22_LSW_ROW_21_MSW_M \ + 0xFFFFFFFF // Corresponds to ROW_22[15:0] & + // ROW_21[31:16] of FUSEFARM. + // FLASH_REGION2 + +#define GPRCM_GPRCM_EFUSE_READ_REG9_FUSEFARM_ROW_22_LSW_ROW_21_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG10 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG10_FUSEFARM_ROW_23_LSW_ROW_22_MSW_M \ + 0xFFFFFFFF // Corresponds to ROW_23[15:0] & + // ROW_22[31:16] of FUSEFARM. + // FLASH_REGION3 + +#define GPRCM_GPRCM_EFUSE_READ_REG10_FUSEFARM_ROW_23_LSW_ROW_22_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_EFUSE_READ_REG11 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_EFUSE_READ_REG11_FUSEFARM_ROW_24_LSW_ROW_23_MSW_M \ + 0xFFFFFFFF // Corresponds to ROW_24[15:0] & + // ROW_23[31:16] of FUSEFARM. + // FLASH_DESCRIPTOR + +#define GPRCM_GPRCM_EFUSE_READ_REG11_FUSEFARM_ROW_24_LSW_ROW_23_MSW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG0 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG0_FUSEFARM_191_160_M \ + 0xFFFFFFFF // Corresponds to bits [191:160] of + // the FUSEFARM. This is ROW_5 of + // FUSEFARM [191:160] : [31:0] : + // DIE_ID0 [31:0] : DEVX [11:0] DEVY + // [23:12] DEVWAF [29:24] DEV_SPARE + // [31:30] + +#define GPRCM_GPRCM_DIEID_READ_REG0_FUSEFARM_191_160_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG1 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG1_FUSEFARM_223_192_M \ + 0xFFFFFFFF // Corresponds to bits [223:192] of + // the FUSEFARM. This is ROW_6 of + // FUSEFARM :- DEVLOT [23:0] DEVFAB + // [28:24] DEVFABBE [31:29] + +#define GPRCM_GPRCM_DIEID_READ_REG1_FUSEFARM_223_192_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG2 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG2_FUSEFARM_255_224_M \ + 0xFFFFFFFF // Corresponds to bits [255:224] of + // the FUSEFARM. This is ROW_7 of + // FUSEFARM:- DEVDESREV[4:0] + // Memrepair[5:5] MakeDefined[16:6] + // CHECKSUM[30:17] Reserved : + // [31:31] + +#define GPRCM_GPRCM_DIEID_READ_REG2_FUSEFARM_255_224_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG3 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG3_FUSEFARM_287_256_M \ + 0xFFFFFFFF // Corresponds to bits [287:256] of + // the FUSEFARM. This is ROW_8 of + // FUSEFARM :- DIEID0 - DEVREG + // [31:0] + +#define GPRCM_GPRCM_DIEID_READ_REG3_FUSEFARM_287_256_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_GPRCM_DIEID_READ_REG4 register. +// +//****************************************************************************** +#define GPRCM_GPRCM_DIEID_READ_REG4_FUSEFARM_319_288_M \ + 0xFFFFFFFF // Corresponds to bits [319:288] of + // the FUSEFARM. This is ROW_9 of + // FUSEFARM :- [7:0] - VBATMON ; + // [13:8] - BUFF_OFFSET ; [15:15] - + // DFT_GXG ; [14:14] - DFT_GLX ; + // [19:16] - PHY ROM Version ; + // [23:20] - MAC ROM Version ; + // [27:24] - NWP ROM Version ; + // [31:28] - APPS ROM Version + +#define GPRCM_GPRCM_DIEID_READ_REG4_FUSEFARM_319_288_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_APPS_SS_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_APPS_SS_OVERRIDES_reserved_M \ + 0xFFFFFC00 + +#define GPRCM_APPS_SS_OVERRIDES_reserved_S 10 +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_refclk_gating_override \ + 0x00000200 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_refclk_gating_override_ctrl \ + 0x00000100 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_pllclk_gating_override \ + 0x00000080 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_pllclk_gating_override_ctrl \ + 0x00000040 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_por_rstn_override \ + 0x00000020 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_sysrstn_override \ + 0x00000010 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_sysclk_gating_override \ + 0x00000008 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_por_rstn_override_ctrl \ + 0x00000004 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_sysrstn_override_ctrl \ + 0x00000002 + +#define GPRCM_APPS_SS_OVERRIDES_mem_apps_sysclk_gating_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_NWP_SS_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_NWP_SS_OVERRIDES_reserved_M \ + 0xFFFFFC00 + +#define GPRCM_NWP_SS_OVERRIDES_reserved_S 10 +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_refclk_gating_override \ + 0x00000200 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_refclk_gating_override_ctrl \ + 0x00000100 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_pllclk_gating_override \ + 0x00000080 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_pllclk_gating_override_ctrl \ + 0x00000040 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_por_rstn_override \ + 0x00000020 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_sysrstn_override \ + 0x00000010 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_sysclk_gating_override \ + 0x00000008 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_por_rstn_override_ctrl \ + 0x00000004 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_sysrstn_override_ctrl \ + 0x00000002 + +#define GPRCM_NWP_SS_OVERRIDES_mem_nwp_sysclk_gating_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_SHARED_SS_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_SHARED_SS_OVERRIDES_reserved_M \ + 0xFFFFFF00 + +#define GPRCM_SHARED_SS_OVERRIDES_reserved_S 8 +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_pllclk_gating_override_ctrl \ + 0x00000080 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_pllclk_gating_override \ + 0x00000040 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_refclk_gating_override_ctrl \ + 0x00000020 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_refclk_gating_override \ + 0x00000010 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_rstn_override \ + 0x00000008 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_sysclk_gating_override \ + 0x00000004 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_rstn_override_ctrl \ + 0x00000002 + +#define GPRCM_SHARED_SS_OVERRIDES_mem_shared_sysclk_gating_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_IDMEM_CORE_RST_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_reserved_M \ + 0xFFFFFF00 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_reserved_S 8 +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_sysrstn_override \ + 0x00000080 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_fmc_rstn_override \ + 0x00000040 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_SPARE_RW1 \ + 0x00000020 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_piosc_gating_override \ + 0x00000010 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_sysrstn_override_ctrl \ + 0x00000008 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_fmc_rstn_override_ctrl \ + 0x00000004 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_SPARE_RW0 \ + 0x00000002 + +#define GPRCM_IDMEM_CORE_RST_OVERRIDES_mem_idmem_core_piosc_gating_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_TOP_DIE_FSM_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_TOP_DIE_FSM_OVERRIDES_reserved_M \ + 0xFFFFF000 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_reserved_S 12 +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_pwr_switch_pgoodin_override_ctrl \ + 0x00000800 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_pwr_switch_pgoodin_override \ + 0x00000400 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_hclk_gating_override \ + 0x00000200 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_piosc_gating_override \ + 0x00000100 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_rstn_override \ + 0x00000080 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_pwr_switch_ponin_override \ + 0x00000040 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_flash_ready_override \ + 0x00000020 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_hclk_gating_override_ctrl \ + 0x00000010 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_piosc_gating_override_ctrl \ + 0x00000008 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_rstn_override_ctrl \ + 0x00000004 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_d2d_pwr_switch_ponin_override_ctrl \ + 0x00000002 + +#define GPRCM_TOP_DIE_FSM_OVERRIDES_mem_flash_ready_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCU_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MCU_PSCON_OVERRIDES_reserved_M \ + 0xFFF00000 + +#define GPRCM_MCU_PSCON_OVERRIDES_reserved_S 20 +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_sleep_override_ctrl \ + 0x00080000 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_update_override_ctrl \ + 0x00040000 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_off_override_ctrl \ + 0x00020000 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_retain_override_ctrl \ + 0x00010000 + +#define GPRCM_MCU_PSCON_OVERRIDES_NU1_M \ + 0x0000FC00 + +#define GPRCM_MCU_PSCON_OVERRIDES_NU1_S 10 +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_sleep_override \ + 0x00000200 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_update_override \ + 0x00000100 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_off_override_M \ + 0x000000F0 + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_off_override_S 4 +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_retain_override_M \ + 0x0000000F + +#define GPRCM_MCU_PSCON_OVERRIDES_mem_mcu_pscon_mem_retain_override_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WTOP_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_WTOP_PSCON_OVERRIDES_reserved_M \ + 0xFFC00000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_reserved_S 22 +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_sleep_override_ctrl \ + 0x00200000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_update_override_ctrl \ + 0x00100000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_off_override_ctrl \ + 0x00080000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_retain_override_ctrl \ + 0x00040000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_sleep_override \ + 0x00020000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_update_override \ + 0x00010000 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_off_override_M \ + 0x0000FF00 + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_off_override_S 8 +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_retain_override_M \ + 0x000000FF + +#define GPRCM_WTOP_PSCON_OVERRIDES_mem_wtop_pscon_mem_retain_override_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WELP_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_WELP_PSCON_OVERRIDES_reserved_M \ + 0xFFFFFFFC + +#define GPRCM_WELP_PSCON_OVERRIDES_reserved_S 2 +#define GPRCM_WELP_PSCON_OVERRIDES_mem_welp_pscon_sleep_override_ctrl \ + 0x00000002 + +#define GPRCM_WELP_PSCON_OVERRIDES_mem_welp_pscon_sleep_override \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_WL_SDIO_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_WL_SDIO_PSCON_OVERRIDES_reserved_M \ + 0xFFFFFFFC + +#define GPRCM_WL_SDIO_PSCON_OVERRIDES_reserved_S 2 +#define GPRCM_WL_SDIO_PSCON_OVERRIDES_mem_wl_sdio_pscon_sleep_override_ctrl \ + 0x00000002 + +#define GPRCM_WL_SDIO_PSCON_OVERRIDES_mem_wl_sdio_pscon_sleep_override \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_MCSPI_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_MCSPI_PSCON_OVERRIDES_reserved_M \ + 0xFFFFFF00 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_reserved_S 8 +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_retain_override_ctrl \ + 0x00000080 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_off_override_ctrl \ + 0x00000040 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_retain_override \ + 0x00000020 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_off_override \ + 0x00000010 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_update_override_ctrl \ + 0x00000008 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_mem_update_override \ + 0x00000004 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_sleep_override_ctrl \ + 0x00000002 + +#define GPRCM_MCSPI_PSCON_OVERRIDES_mem_mcspi_pscon_sleep_override \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// GPRCM_O_SSDIO_PSCON_OVERRIDES register. +// +//****************************************************************************** +#define GPRCM_SSDIO_PSCON_OVERRIDES_reserved_M \ + 0xFFFFFFFC + +#define GPRCM_SSDIO_PSCON_OVERRIDES_reserved_S 2 +#define GPRCM_SSDIO_PSCON_OVERRIDES_mem_ssdio_pscon_sleep_override_ctrl \ + 0x00000002 + +#define GPRCM_SSDIO_PSCON_OVERRIDES_mem_ssdio_pscon_sleep_override \ + 0x00000001 + + + + +#endif // __HW_GPRCM_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib1p2.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib1p2.h new file mode 100755 index 0000000..95e25ff --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib1p2.h @@ -0,0 +1,1750 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_HIB1P2_H__ +#define __HW_HIB1P2_H__ + +//***************************************************************************** +// +// The following are defines for the HIB1P2 register offsets. +// +//***************************************************************************** +#define HIB1P2_O_SRAM_SKA_LDO_PARAMETERS0 \ + 0x00000000 + +#define HIB1P2_O_SRAM_SKA_LDO_PARAMETERS1 \ + 0x00000004 + +#define HIB1P2_O_DIG_DCDC_PARAMETERS0 \ + 0x00000008 + +#define HIB1P2_O_DIG_DCDC_PARAMETERS1 \ + 0x0000000C + +#define HIB1P2_O_DIG_DCDC_PARAMETERS2 \ + 0x00000010 + +#define HIB1P2_O_DIG_DCDC_PARAMETERS3 \ + 0x00000014 + +#define HIB1P2_O_DIG_DCDC_PARAMETERS4 \ + 0x00000018 + +#define HIB1P2_O_DIG_DCDC_PARAMETERS5 \ + 0x0000001C + +#define HIB1P2_O_DIG_DCDC_PARAMETERS6 \ + 0x00000020 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS0 \ + 0x00000024 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS1 \ + 0x00000028 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS16 \ + 0x00000064 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS17 \ + 0x00000068 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS18 \ + 0x0000006C + +#define HIB1P2_O_ANA_DCDC_PARAMETERS19 \ + 0x00000070 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS0 \ + 0x00000074 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS1 \ + 0x00000078 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS2 \ + 0x0000007C + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS3 \ + 0x00000080 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS4 \ + 0x00000084 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS5 \ + 0x00000088 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS6 \ + 0x0000008C + +#define HIB1P2_O_PMBIST_PARAMETERS0 \ + 0x00000094 + +#define HIB1P2_O_PMBIST_PARAMETERS1 \ + 0x00000098 + +#define HIB1P2_O_PMBIST_PARAMETERS2 \ + 0x0000009C + +#define HIB1P2_O_PMBIST_PARAMETERS3 \ + 0x000000A0 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS8 \ + 0x000000A4 + +#define HIB1P2_O_ANA_DCDC_PARAMETERS_OVERRIDE \ + 0x000000A8 + +#define HIB1P2_O_FLASH_DCDC_PARAMETERS_OVERRIDE \ + 0x000000AC + +#define HIB1P2_O_DIG_DCDC_VTRIM_CFG \ + 0x000000B0 + +#define HIB1P2_O_DIG_DCDC_FSM_PARAMETERS \ + 0x000000B4 + +#define HIB1P2_O_ANA_DCDC_FSM_PARAMETERS \ + 0x000000B8 + +#define HIB1P2_O_SRAM_SKA_LDO_FSM_PARAMETERS \ + 0x000000BC + +#define HIB1P2_O_BGAP_DUTY_CYCLING_EXIT_CFG \ + 0x000000C0 + +#define HIB1P2_O_CM_OSC_16M_CONFIG \ + 0x000000C4 + +#define HIB1P2_O_SOP_SENSE_VALUE \ + 0x000000C8 + +#define HIB1P2_O_HIB_RTC_TIMER_LSW_1P2 \ + 0x000000CC + +#define HIB1P2_O_HIB_RTC_TIMER_MSW_1P2 \ + 0x000000D0 + +#define HIB1P2_O_HIB1P2_BGAP_TRIM_OVERRIDES \ + 0x000000D4 + +#define HIB1P2_O_HIB1P2_EFUSE_READ_REG0 \ + 0x000000D8 + +#define HIB1P2_O_HIB1P2_EFUSE_READ_REG1 \ + 0x000000DC + +#define HIB1P2_O_HIB1P2_POR_TEST_CTRL \ + 0x000000E0 + +#define HIB1P2_O_HIB_TIMER_SYNC_CALIB_CFG0 \ + 0x000000E4 + +#define HIB1P2_O_HIB_TIMER_SYNC_CALIB_CFG1 \ + 0x000000E8 + +#define HIB1P2_O_HIB_TIMER_SYNC_CFG2 \ + 0x000000EC + +#define HIB1P2_O_HIB_TIMER_SYNC_TSF_ADJ_VAL \ + 0x000000F0 + +#define HIB1P2_O_HIB_TIMER_RTC_GTS_TIMESTAMP_LSW \ + 0x000000F4 + +#define HIB1P2_O_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW \ + 0x000000F8 + +#define HIB1P2_O_HIB_TIMER_RTC_WUP_TIMESTAMP_LSW \ + 0x000000FC + +#define HIB1P2_O_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW \ + 0x00000100 + +#define HIB1P2_O_HIB_TIMER_SYNC_WAKE_OFFSET_ERR \ + 0x00000104 + +#define HIB1P2_O_HIB_TIMER_SYNC_TSF_CURR_VAL_LSW \ + 0x00000108 + +#define HIB1P2_O_HIB_TIMER_SYNC_TSF_CURR_VAL_MSW \ + 0x0000010C + +#define HIB1P2_O_CM_SPARE 0x00000110 +#define HIB1P2_O_PORPOL_SPARE 0x00000114 +#define HIB1P2_O_MEM_DIG_DCDC_CLK_CONFIG \ + 0x00000118 + +#define HIB1P2_O_MEM_ANA_DCDC_CLK_CONFIG \ + 0x0000011C + +#define HIB1P2_O_MEM_FLASH_DCDC_CLK_CONFIG \ + 0x00000120 + +#define HIB1P2_O_MEM_PA_DCDC_CLK_CONFIG \ + 0x00000124 + +#define HIB1P2_O_MEM_SLDO_VNWA_OVERRIDE \ + 0x00000128 + +#define HIB1P2_O_MEM_BGAP_DUTY_CYCLING_ENABLE_OVERRIDE \ + 0x0000012C + +#define HIB1P2_O_MEM_HIB_FSM_DEBUG \ + 0x00000130 + +#define HIB1P2_O_MEM_SLDO_VNWA_SW_CTRL \ + 0x00000134 + +#define HIB1P2_O_MEM_SLDO_WEAK_PROCESS \ + 0x00000138 + +#define HIB1P2_O_MEM_PA_DCDC_OV_UV_STATUS \ + 0x0000013C + +#define HIB1P2_O_MEM_CM_TEST_MODE \ + 0x00000140 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_SRAM_SKA_LDO_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_sc_itrim_lowv_M \ + 0xC0000000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_sc_itrim_lowv_S 30 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_iq_trim_lowv_M \ + 0x30000000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_iq_trim_lowv_S 28 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_sc_prot_lowv \ + 0x08000000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_lowv_override \ + 0x04000000 // FSM Override value for SLDO_EN : + // Applicable only when bit [4] of + // this register is set to 1. + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_low_pwr_lowv \ + 0x02000000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_int_cap_sel_lowv \ + 0x01000000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_vtrim_lowv_M \ + 0x00FC0000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_vtrim_lowv_S 18 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_spare_lowv_M \ + 0x0003FF00 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_spare_lowv_S 8 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_skaldo_en_lowv_override \ + 0x00000080 // FSM Override value for + // SKA_LDO_EN : Applicable only when + // bit [3] of this register is set + // to 1. + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_skaldo_en_cap_ref_lowv \ + 0x00000040 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_skaldo_en_resdiv_ref_lowv \ + 0x00000020 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_sldo_en_lowv_fsm_override_ctrl \ + 0x00000010 // When 1, bit[26] of this register + // will be used as SLDO_EN + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_mem_skaldo_en_lowv_fsm_override_ctrl \ + 0x00000008 // When 1, bit[26] of this register + // will be used as SKA_LDO_EN + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_NA1_M \ + 0x00000007 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS0_NA1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_SRAM_SKA_LDO_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_ctrl_lowv_M \ + 0xFFC00000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_ctrl_lowv_S 22 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_vtrim_lowv_M \ + 0x003F0000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_vtrim_lowv_S 16 +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_sldo_en_tload_lowv \ + 0x00008000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_en_tload_lowv \ + 0x00004000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_cap_sw_en_lowv \ + 0x00002000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_en_hib_lowv \ + 0x00001000 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_mem_skaldo_en_vref_buf_lowv \ + 0x00000800 + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_NA2_M \ + 0x000007FF + +#define HIB1P2_SRAM_SKA_LDO_PARAMETERS1_NA2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_lowv_override \ + 0x80000000 // Override value for DCDC_DIG_EN : + // Applicable only when bit [31] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. Else from FSM + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_delayed_en_lowv \ + 0x40000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_subreg_1p8v_lowv_override \ + 0x20000000 // Override value for + // DCDC_DIG_EN_SUBREG_1P8V : + // Applicable only when bit [30] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. Else from FSM + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_subreg_1p2v_lowv_override \ + 0x10000000 // Override value for + // DCDC_DIG_EN_SUBREG_1P2V : + // Applicable only when bit [29] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. Else from FSM + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_slp_mode_lowv_override \ + 0x08000000 // Override value for + // DCDC_DIG_SLP_EN : Applicable only + // when bit [28] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. Else from FSM + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_ldo_mode_lowv \ + 0x04000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_nfet_rds_mode_lowv \ + 0x02000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_pfet_rds_mode_lowv \ + 0x01000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_ext_smps_override_mode_lowv \ + 0x00800000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_clk_in_lowv_enable \ + 0x00400000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_vtrim_lowv_override_M \ + 0x003F0000 // Override value for + // DCDC_DIG_VTRIM : Applicable only + // when bit [27] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_vtrim_lowv_override_S 16 +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_pfm_ripple_trim_lowv_M \ + 0x0000C000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_pfm_ripple_trim_lowv_S 14 +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_iq_ctrl_lowv_M \ + 0x00003000 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_iq_ctrl_lowv_S 12 +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_en_cl_non_ov_lowv \ + 0x00000800 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_non_ov_ctrl_lowv_M \ + 0x00000780 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_non_ov_ctrl_lowv_S 7 +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_slp_drv_dly_sel_lowv_M \ + 0x00000078 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_mem_dcdc_dig_slp_drv_dly_sel_lowv_S 3 +#define HIB1P2_DIG_DCDC_PARAMETERS0_NA3_M \ + 0x00000007 + +#define HIB1P2_DIG_DCDC_PARAMETERS0_NA3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_en_lowv_fsm_override_ctrl \ + 0x80000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_en_subreg_1p8v_fsm_override_ctrl \ + 0x40000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_en_subreg_1p2v_fsm_override_ctrl \ + 0x20000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_en_slp_mode_lowv_fsm_override_ctrl \ + 0x10000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_vtrim_fsm_override_ctrl \ + 0x08000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_cot_mode_en_lowv_fsm_override_ctrl \ + 0x04000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_mem_dcdc_dig_ilim_trim_lowv_efc_override_ctrl \ + 0x02000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS1_NA4_M \ + 0x01FFFFFF + +#define HIB1P2_DIG_DCDC_PARAMETERS1_NA4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS2 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pfet_sel_lowv_M \ + 0xF0000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pfet_sel_lowv_S 28 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_nfet_sel_lowv_M \ + 0x0F000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_nfet_sel_lowv_S 24 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pdrv_stagger_ctrl_lowv_M \ + 0x00C00000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pdrv_stagger_ctrl_lowv_S 22 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ndrv_stagger_ctrl_lowv_M \ + 0x00300000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ndrv_stagger_ctrl_lowv_S 20 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pdrv_str_sel_lowv_M \ + 0x000F0000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_pdrv_str_sel_lowv_S 16 +#define HIB1P2_DIG_DCDC_PARAMETERS2_NA5 \ + 0x00008000 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ndrv_str_sel_lowv_M \ + 0x00007800 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ndrv_str_sel_lowv_S 11 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_en_shootthru_ctrl_lowv \ + 0x00000400 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ton_trim_lowv_M \ + 0x000003FC + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_ton_trim_lowv_S 2 +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_swcap_res_hf_clk_lowv \ + 0x00000002 + +#define HIB1P2_DIG_DCDC_PARAMETERS2_mem_dcdc_dig_cot_mode_en_lowv_override \ + 0x00000001 // Override value for + // DCDC_DIG_COT_EN : Applicable only + // when bit[26] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS3 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS3_NA6 \ + 0x80000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_cot_ctrl_lowv_M \ + 0x7F800000 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_cot_ctrl_lowv_S 23 +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_ilim_lowv \ + 0x00400000 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_ilim_hib_lowv \ + 0x00200000 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ilim_trim_lowv_override_M \ + 0x001FE000 // Override value for + // DCDC_DIG_ILIM_TRIM : Applicable + // only when bit [25] of + // DIG_DCDC_PARAMETERS1 [0x000C] is + // set to 1 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ilim_trim_lowv_override_S 13 +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ilim_mask_dly_sel_lowv_M \ + 0x00001800 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ilim_mask_dly_sel_lowv_S 11 +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_ncomp_lowv \ + 0x00000400 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_ncomp_hib_lowv \ + 0x00000200 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ncomp_trim_lowv_M \ + 0x000001F0 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ncomp_trim_lowv_S 4 +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ncomp_mask_dly_sel_lowv_M \ + 0x0000000C + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_ncomp_mask_dly_sel_lowv_S 2 +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_uv_prot_lowv \ + 0x00000002 + +#define HIB1P2_DIG_DCDC_PARAMETERS3_mem_dcdc_dig_en_ov_prot_lowv \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS4 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS4_dcdc_dig_uv_prot_out_lowv \ + 0x80000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS4_dcdc_dig_ov_prot_out_lowv \ + 0x40000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS4_mem_dcdc_dig_en_tmux_lowv \ + 0x20000000 + +#define HIB1P2_DIG_DCDC_PARAMETERS4_NA7_M \ + 0x1FFFFFFF + +#define HIB1P2_DIG_DCDC_PARAMETERS4_NA7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS5 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS5_mem_dcdc_dig_tmux_ctrl_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_DIG_DCDC_PARAMETERS5_mem_dcdc_dig_tmux_ctrl_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_PARAMETERS6 register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_PARAMETERS6_mem_dcdc_dig_spare_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_DIG_DCDC_PARAMETERS6_mem_dcdc_dig_spare_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_lowv_override \ + 0x80000000 // Override for ANA DCDC EN + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_delayed_en_lowv \ + 0x40000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_subreg_1p8v_lowv \ + 0x20000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_subreg_1p2v_lowv \ + 0x10000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_pwm_mode_lowv_override \ + 0x08000000 // Override for ANA DCDC PWM + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_slp_mode_lowv_override \ + 0x04000000 // Override for ANA DCDC SLP + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_ldo_mode_lowv \ + 0x02000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_pfet_rds_mode_lowv \ + 0x01000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_nfet_rds_mode_lowv \ + 0x00800000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_ext_smps_override_mode_lowv \ + 0x00400000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_clk_in_lowv_enable \ + 0x00200000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_vtrim_lowv_M \ + 0x001E0000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_vtrim_lowv_S 17 +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_pfm_ripple_trim_lowv_M \ + 0x00018000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_pfm_ripple_trim_lowv_S 15 +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_iq_ctrl_lowv_M \ + 0x00006000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_iq_ctrl_lowv_S 13 +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_en_cl_non_ov_lowv \ + 0x00001000 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_non_ov_ctrl_lowv_M \ + 0x00000F00 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_non_ov_ctrl_lowv_S 8 +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_slp_drv_dly_sel_lowv_M \ + 0x000000F0 + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_slp_drv_dly_sel_lowv_S 4 +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_pfet_sel_lowv_M \ + 0x0000000F + +#define HIB1P2_ANA_DCDC_PARAMETERS0_mem_dcdc_ana_pfet_sel_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_nfet_sel_lowv_M \ + 0xF0000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_nfet_sel_lowv_S 28 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_pdrv_stagger_ctrl_lowv_M \ + 0x0C000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_pdrv_stagger_ctrl_lowv_S 26 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ndrv_stagger_ctrl_lowv_M \ + 0x03000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ndrv_stagger_ctrl_lowv_S 24 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_pdrv_str_sel_lowv_M \ + 0x00F00000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_pdrv_str_sel_lowv_S 20 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ndrv_str_sel_lowv_M \ + 0x000F0000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ndrv_str_sel_lowv_S 16 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_en_rtrim_lowv \ + 0x00008000 // (Earlier SHOOTTHRU CTRL) + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_apwm_en_lowv \ + 0x00004000 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ramp_hgt_lowv_M \ + 0x00003E00 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_ramp_hgt_lowv_S 9 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_en_anti_glitch_lowv \ + 0x00000100 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_en_hi_clamp_lowv \ + 0x00000080 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_hi_clamp_trim_lowv_M \ + 0x00000060 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_hi_clamp_trim_lowv_S 5 +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_en_lo_clamp_lowv \ + 0x00000010 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_lo_clamp_trim_lowv_M \ + 0x0000000C + +#define HIB1P2_ANA_DCDC_PARAMETERS1_mem_dcdc_ana_lo_clamp_trim_lowv_S 2 +#define HIB1P2_ANA_DCDC_PARAMETERS1_NA8_M \ + 0x00000003 + +#define HIB1P2_ANA_DCDC_PARAMETERS1_NA8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS16 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_en_ilim_lowv \ + 0x00200000 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_en_ilim_hib_lowv \ + 0x00100000 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ilim_trim_lowv_override_M \ + 0x000FF000 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ilim_trim_lowv_override_S 12 +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ilim_mask_dly_sel_lowv_M \ + 0x00000C00 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ilim_mask_dly_sel_lowv_S 10 +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_en_ncomp_lowv \ + 0x00000200 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_en_ncomp_hib_lowv \ + 0x00000100 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ncomp_trim_lowv_M \ + 0x000000F8 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ncomp_trim_lowv_S 3 +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ncomp_mask_dly_sel_lowv_M \ + 0x00000006 + +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_ncomp_mask_dly_sel_lowv_S 1 +#define HIB1P2_ANA_DCDC_PARAMETERS16_mem_dcdc_ana_en_ov_prot_lowv \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS17 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS17_dcdc_ana_ov_prot_out_lowv \ + 0x80000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS17_mem_dcdc_ana_en_tmux_lowv \ + 0x40000000 + +#define HIB1P2_ANA_DCDC_PARAMETERS17_NA17_M \ + 0x3FFFFFFF + +#define HIB1P2_ANA_DCDC_PARAMETERS17_NA17_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS18 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS18_mem_dcdc_ana_tmux_ctrl_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_ANA_DCDC_PARAMETERS18_mem_dcdc_ana_tmux_ctrl_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS19 register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS19_mem_dcdc_ana_spare_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_ANA_DCDC_PARAMETERS19_mem_dcdc_ana_spare_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_lowv \ + 0x80000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_delayed_en_lowv \ + 0x40000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_clk_in_lowv_enable \ + 0x20000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_iq_ctrl_lowv_M \ + 0x18000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_iq_ctrl_lowv_S 27 +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_buck_mode_lowv \ + 0x04000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_boost_mode_lowv \ + 0x02000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_buck_boost_mode_lowv \ + 0x01000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_bb_alt_cycles_lowv \ + 0x00800000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_cl_non_ov_lowv \ + 0x00400000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_non_ov_ctrl_lowv_M \ + 0x003C0000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_non_ov_ctrl_lowv_S 18 +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_drv_lowv \ + 0x00020000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_pwm_mode_lowv \ + 0x00010000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_pfm_comp_lowv \ + 0x00008000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_slp_mode_lowv \ + 0x00004000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_n1fet_rds_mode_lowv \ + 0x00002000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_n2fet_rds_mode_lowv \ + 0x00001000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_p1fet_rds_mode_lowv \ + 0x00000800 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_en_p2fet_rds_mode_lowv \ + 0x00000400 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_ext_smps_mode_override_lowv \ + 0x00000200 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_p1fet_sel_lowv_M \ + 0x000001E0 + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_p1fet_sel_lowv_S 5 +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_n1fet_sel_lowv_M \ + 0x0000001E + +#define HIB1P2_FLASH_DCDC_PARAMETERS0_mem_dcdc_flash_n1fet_sel_lowv_S 1 +#define HIB1P2_FLASH_DCDC_PARAMETERS0_NA18 \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2fet_sel_lowv_M \ + 0xF0000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2fet_sel_lowv_S 28 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2fet_sel_lowv_M \ + 0x0F000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2fet_sel_lowv_S 24 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p1drv_str_sel_lowv_M \ + 0x00F00000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p1drv_str_sel_lowv_S 20 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n1drv_str_sel_lowv_M \ + 0x000F0000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n1drv_str_sel_lowv_S 16 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2drv_str_sel_lowv_M \ + 0x0000F000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2drv_str_sel_lowv_S 12 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2drv_str_sel_lowv_M \ + 0x00000F00 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2drv_str_sel_lowv_S 8 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p1fet_non_ov_lowv_M \ + 0x000000C0 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p1fet_non_ov_lowv_S 6 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n1fet_non_ov_lowv_M \ + 0x00000030 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n1fet_non_ov_lowv_S 4 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2fet_non_ov_lowv_M \ + 0x0000000C + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_p2fet_non_ov_lowv_S 2 +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2fet_non_ov_lowv_M \ + 0x00000003 + +#define HIB1P2_FLASH_DCDC_PARAMETERS1_mem_dcdc_flash_n2fet_non_ov_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS2 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_p1fet_stagger_lowv_M \ + 0xC0000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_p1fet_stagger_lowv_S 30 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_n1fet_stagger_lowv_M \ + 0x30000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_n1fet_stagger_lowv_S 28 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_p2fet_stagger_lowv_M \ + 0x0C000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_p2fet_stagger_lowv_S 26 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_n2fet_stagger_lowv_M \ + 0x03000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_n2fet_stagger_lowv_S 24 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_shoot_thru_ctrl_lowv \ + 0x00800000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_en_ncomp_lowv \ + 0x00400000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_en_ncomp_hib_lowv \ + 0x00200000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ncomp_trim_lowv_M \ + 0x001F0000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ncomp_trim_lowv_S 16 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ncomp_mask_dly_trim_lowv_M \ + 0x0000F000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ncomp_mask_dly_trim_lowv_S 12 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_en_ilim_lowv \ + 0x00000800 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_en_ilim_hib_lowv \ + 0x00000400 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ilim_trim_lowv_override_M \ + 0x000003FC + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ilim_trim_lowv_override_S 2 +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ilim_mask_dly_sel_lowv_M \ + 0x00000003 + +#define HIB1P2_FLASH_DCDC_PARAMETERS2_mem_dcdc_flash_ilim_mask_dly_sel_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS3 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_anti_glitch_lowv \ + 0x80000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_hi_clamp_lowv \ + 0x40000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_lo_clamp_lowv \ + 0x20000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_ramp_hgt_lowv_M \ + 0x1F000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_ramp_hgt_lowv_S 24 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vclamph_trim_lowv_M \ + 0x00E00000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vclamph_trim_lowv_S 21 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vclampl_trim_lowv_M \ + 0x001C0000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vclampl_trim_lowv_S 18 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vtrim_lowv_M \ + 0x0003C000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_vtrim_lowv_S 14 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_pfm_ripple_trim_lowv_M \ + 0x00003C00 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_pfm_ripple_trim_lowv_S 10 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_slp_drv_dly_sel_lowv_M \ + 0x00000300 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_slp_drv_dly_sel_lowv_S 8 +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_ov_prot_lowv \ + 0x00000080 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_uv_prot_lowv \ + 0x00000040 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_mem_dcdc_flash_en_tmux_lowv \ + 0x00000020 + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_NA19_M \ + 0x0000001F + +#define HIB1P2_FLASH_DCDC_PARAMETERS3_NA19_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS4 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS4_mem_dcdc_flash_tmux_ctrl_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_FLASH_DCDC_PARAMETERS4_mem_dcdc_flash_tmux_ctrl_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS5 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS5_mem_dcdc_flash_spare_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_FLASH_DCDC_PARAMETERS5_mem_dcdc_flash_spare_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS6 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS6_dcdc_flash_ov_prot_out_lowv \ + 0x80000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS6_dcdc_flash_uv_prot_out_lowv \ + 0x40000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS6_NA20_M \ + 0x3FFFFFFF + +#define HIB1P2_FLASH_DCDC_PARAMETERS6_NA20_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_PMBIST_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB1P2_PMBIST_PARAMETERS0_mem_pm_bist_en_lowv \ + 0x80000000 + +#define HIB1P2_PMBIST_PARAMETERS0_mem_pm_bist_ctrl_lowv_M \ + 0x7FFFF800 + +#define HIB1P2_PMBIST_PARAMETERS0_mem_pm_bist_ctrl_lowv_S 11 +#define HIB1P2_PMBIST_PARAMETERS0_NA21_M \ + 0x000007FF + +#define HIB1P2_PMBIST_PARAMETERS0_NA21_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_PMBIST_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB1P2_PMBIST_PARAMETERS1_mem_pm_bist_spare_lowv_M \ + 0xFFFF0000 + +#define HIB1P2_PMBIST_PARAMETERS1_mem_pm_bist_spare_lowv_S 16 +#define HIB1P2_PMBIST_PARAMETERS1_mem_pmtest_en_lowv \ + 0x00008000 + +#define HIB1P2_PMBIST_PARAMETERS1_NA22_M \ + 0x00007FFF + +#define HIB1P2_PMBIST_PARAMETERS1_NA22_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_PMBIST_PARAMETERS2 register. +// +//****************************************************************************** +#define HIB1P2_PMBIST_PARAMETERS2_mem_pmtest_tmux_ctrl_lowv_M \ + 0xFFFFFFFF + +#define HIB1P2_PMBIST_PARAMETERS2_mem_pmtest_tmux_ctrl_lowv_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_PMBIST_PARAMETERS3 register. +// +//****************************************************************************** +#define HIB1P2_PMBIST_PARAMETERS3_mem_pmtest_spare_lowv_M \ + 0xFFFF0000 + +#define HIB1P2_PMBIST_PARAMETERS3_mem_pmtest_spare_lowv_S 16 +#define HIB1P2_PMBIST_PARAMETERS3_mem_pmtest_load_trim_lowv_M \ + 0x0000E000 + +#define HIB1P2_PMBIST_PARAMETERS3_mem_pmtest_load_trim_lowv_S 13 +#define HIB1P2_PMBIST_PARAMETERS3_mem_rnwell_calib_en_lowv \ + 0x00001000 + +#define HIB1P2_PMBIST_PARAMETERS3_NA23_M \ + 0x00000FFF + +#define HIB1P2_PMBIST_PARAMETERS3_NA23_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS8 register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS8_mem_en_flash_sup_comp_lowv \ + 0x80000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS8_mem_flash_high_sup_trim_lowv_M \ + 0x7C000000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS8_mem_flash_high_sup_trim_lowv_S 26 +#define HIB1P2_FLASH_DCDC_PARAMETERS8_mem_flash_low_sup_trim_lowv_M \ + 0x03E00000 + +#define HIB1P2_FLASH_DCDC_PARAMETERS8_mem_flash_low_sup_trim_lowv_S 21 +#define HIB1P2_FLASH_DCDC_PARAMETERS8_NA24_M \ + 0x001FFFFF + +#define HIB1P2_FLASH_DCDC_PARAMETERS8_NA24_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_PARAMETERS_OVERRIDE register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_reserved_M \ + 0xFFFFFFC0 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_reserved_S 6 +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_en_subreg_1p2v_lowv_override_ctrl \ + 0x00000020 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_en_subreg_1p8v_lowv_override_ctrl \ + 0x00000010 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_ilim_trim_lowv_efc_override_ctrl \ + 0x00000008 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_en_slp_mode_lowv_fsm_override_ctrl \ + 0x00000004 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_en_pwm_mode_lowv_fsm_override_ctrl \ + 0x00000002 + +#define HIB1P2_ANA_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_ana_en_lowv_fsm_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_FLASH_DCDC_PARAMETERS_OVERRIDE register. +// +//****************************************************************************** +#define HIB1P2_FLASH_DCDC_PARAMETERS_OVERRIDE_reserved_M \ + 0xFFFFFFFC + +#define HIB1P2_FLASH_DCDC_PARAMETERS_OVERRIDE_reserved_S 2 +#define HIB1P2_FLASH_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_flash_en_lowv_override_ctrl \ + 0x00000002 + +#define HIB1P2_FLASH_DCDC_PARAMETERS_OVERRIDE_mem_dcdc_flash_ilim_trim_lowv_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_VTRIM_CFG register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_VTRIM_CFG_reserved_M \ + 0xFF000000 + +#define HIB1P2_DIG_DCDC_VTRIM_CFG_reserved_S 24 +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_run_vtrim_M \ + 0x00FC0000 + +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_run_vtrim_S 18 +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_dslp_vtrim_M \ + 0x0003F000 + +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_dslp_vtrim_S 12 +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_lpds_vtrim_M \ + 0x00000FC0 + +#define HIB1P2_DIG_DCDC_VTRIM_CFG_mem_dcdc_dig_lpds_vtrim_S 6 +#define HIB1P2_DIG_DCDC_VTRIM_CFG_Spare_RW_M \ + 0x0000003F + +#define HIB1P2_DIG_DCDC_VTRIM_CFG_Spare_RW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_DIG_DCDC_FSM_PARAMETERS register. +// +//****************************************************************************** +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_reserved_M \ + 0xFFFF8000 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_reserved_S 15 +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_enter_cot_to_vtrim_M \ + 0x00007000 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_enter_cot_to_vtrim_S 12 +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_enter_vtrim_to_sleep_M \ + 0x00000E00 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_enter_vtrim_to_sleep_S 9 +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_sleep_to_vtrim_M \ + 0x000001C0 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_sleep_to_vtrim_S 6 +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_vtrim_to_cot_M \ + 0x00000038 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_vtrim_to_cot_S 3 +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_cot_to_run_M \ + 0x00000007 + +#define HIB1P2_DIG_DCDC_FSM_PARAMETERS_mem_dcdc_dig_dslp_exit_cot_to_run_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_ANA_DCDC_FSM_PARAMETERS register. +// +//****************************************************************************** +#define HIB1P2_ANA_DCDC_FSM_PARAMETERS_reserved_M \ + 0xFFFFFFF8 + +#define HIB1P2_ANA_DCDC_FSM_PARAMETERS_reserved_S 3 +#define HIB1P2_ANA_DCDC_FSM_PARAMETERS_mem_dcdc_ana_dslp_exit_sleep_to_run_M \ + 0x00000007 + +#define HIB1P2_ANA_DCDC_FSM_PARAMETERS_mem_dcdc_ana_dslp_exit_sleep_to_run_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_SRAM_SKA_LDO_FSM_PARAMETERS register. +// +//****************************************************************************** +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_reserved_M \ + 0xFFFFFFC0 + +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_reserved_S 6 +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_mem_ska_ldo_en_to_sram_ldo_dis_M \ + 0x00000038 + +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_mem_ska_ldo_en_to_sram_ldo_dis_S 3 +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_mem_sram_ldo_en_to_ska_ldo_dis_M \ + 0x00000007 + +#define HIB1P2_SRAM_SKA_LDO_FSM_PARAMETERS_mem_sram_ldo_en_to_ska_ldo_dis_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_BGAP_DUTY_CYCLING_EXIT_CFG register. +// +//****************************************************************************** +#define HIB1P2_BGAP_DUTY_CYCLING_EXIT_CFG_reserved_M \ + 0xFFFFFFF8 + +#define HIB1P2_BGAP_DUTY_CYCLING_EXIT_CFG_reserved_S 3 +#define HIB1P2_BGAP_DUTY_CYCLING_EXIT_CFG_mem_bgap_duty_cycling_exit_time_M \ + 0x00000007 + +#define HIB1P2_BGAP_DUTY_CYCLING_EXIT_CFG_mem_bgap_duty_cycling_exit_time_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_CM_OSC_16M_CONFIG register. +// +//****************************************************************************** +#define HIB1P2_CM_OSC_16M_CONFIG_reserved_M \ + 0xFFFC0000 + +#define HIB1P2_CM_OSC_16M_CONFIG_reserved_S 18 +#define HIB1P2_CM_OSC_16M_CONFIG_cm_clk_good_16m \ + 0x00020000 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_en_osc_16m \ + 0x00010000 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_osc_16m_trim_M \ + 0x0000FC00 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_osc_16m_trim_S 10 +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_osc_16m_spare_M \ + 0x000003F0 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_osc_16m_spare_S 4 +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_osc_en_sli_16m \ + 0x00000008 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_sli_16m_trim_M \ + 0x00000007 + +#define HIB1P2_CM_OSC_16M_CONFIG_mem_cm_sli_16m_trim_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_SOP_SENSE_VALUE register. +// +//****************************************************************************** +#define HIB1P2_SOP_SENSE_VALUE_reserved_M \ + 0xFFFFFF00 + +#define HIB1P2_SOP_SENSE_VALUE_reserved_S 8 +#define HIB1P2_SOP_SENSE_VALUE_sop_sense_value_M \ + 0x000000FF + +#define HIB1P2_SOP_SENSE_VALUE_sop_sense_value_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_RTC_TIMER_LSW_1P2 register. +// +//****************************************************************************** +#define HIB1P2_HIB_RTC_TIMER_LSW_1P2_hib_rtc_timer_lsw_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_RTC_TIMER_LSW_1P2_hib_rtc_timer_lsw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_RTC_TIMER_MSW_1P2 register. +// +//****************************************************************************** +#define HIB1P2_HIB_RTC_TIMER_MSW_1P2_hib_rtc_timer_msw_M \ + 0x0000FFFF + +#define HIB1P2_HIB_RTC_TIMER_MSW_1P2_hib_rtc_timer_msw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB1P2_BGAP_TRIM_OVERRIDES register. +// +//****************************************************************************** +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_reserved_M \ + 0xFF800000 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_reserved_S 23 +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_mag_trim_override_ctrl \ + 0x00400000 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_mag_trim_override_M \ + 0x003FC000 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_mag_trim_override_S 14 +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_temp_trim_override_ctrl \ + 0x00002000 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_temp_trim_override_M \ + 0x00001FC0 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_temp_trim_override_S 6 +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_rtrim_override_ctrl \ + 0x00000020 + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_rtrim_override_M \ + 0x0000001F + +#define HIB1P2_HIB1P2_BGAP_TRIM_OVERRIDES_mem_bgap_rtrim_override_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB1P2_EFUSE_READ_REG0 register. +// +//****************************************************************************** +#define HIB1P2_HIB1P2_EFUSE_READ_REG0_FUSEFARM_ROW_12_M \ + 0xFFFFFFFF // Corresponds to ROW_12 of + // FUSEFARM. [7:0] : + // DCDC_DIG_ILIM_TRIM_LOWV(7:0) + // [15:8] : + // DCDC_ANA_ILIM_TRIM_LOWV(7:0) + // [23:16] : + // DCDC_FLASH_ILIM_TRIM_LOWV(7:0) + // [24:24] : DTHE SHA DISABLE + // [25:25] : DTHE DES DISABLE + // [26:26] : DTHE AES DISABLE + // [31:27] : HD_BG_RTRIM (4:0) + +#define HIB1P2_HIB1P2_EFUSE_READ_REG0_FUSEFARM_ROW_12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB1P2_EFUSE_READ_REG1 register. +// +//****************************************************************************** +#define HIB1P2_HIB1P2_EFUSE_READ_REG1_FUSEFARM_ROW_13_M \ + 0xFFFFFFFF // Corresponds to ROW_13 of the + // FUSEFARM. [7:0] : HD_BG_MAG_TRIM + // (7:0) [14:8] : HD_BG_TEMP_TRIM + // (6:0) [15:15] : GREYOUT ENABLE + // DUTY CYCLING [31:16] : + // Reserved/Checksum + +#define HIB1P2_HIB1P2_EFUSE_READ_REG1_FUSEFARM_ROW_13_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB1P2_POR_TEST_CTRL register. +// +//****************************************************************************** +#define HIB1P2_HIB1P2_POR_TEST_CTRL_reserved_M \ + 0xFFFFFF00 + +#define HIB1P2_HIB1P2_POR_TEST_CTRL_reserved_S 8 +#define HIB1P2_HIB1P2_POR_TEST_CTRL_mem_prcm_por_test_ctrl_M \ + 0x000000FF + +#define HIB1P2_HIB1P2_POR_TEST_CTRL_mem_prcm_por_test_ctrl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_CALIB_CFG0 register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_reserved_M \ + 0xFFFF0000 + +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_reserved_S 16 +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_mem_cfg_calib_time_M \ + 0x0000FF00 + +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_mem_cfg_calib_time_S 8 +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_NU1_M \ + 0x000000FE + +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_NU1_S 1 +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG0_mem_cfg_calib_start \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_CALIB_CFG1 register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG1_reserved_M \ + 0xFFF00000 + +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG1_reserved_S 20 +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG1_fast_calib_count_M \ + 0x000FFFFF + +#define HIB1P2_HIB_TIMER_SYNC_CALIB_CFG1_fast_calib_count_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_CFG2 register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_CFG2_reserved_M \ + 0xFFFFFE00 + +#define HIB1P2_HIB_TIMER_SYNC_CFG2_reserved_S 9 +#define HIB1P2_HIB_TIMER_SYNC_CFG2_mem_cfg_hib_unload \ + 0x00000100 + +#define HIB1P2_HIB_TIMER_SYNC_CFG2_NU1_M \ + 0x000000FC + +#define HIB1P2_HIB_TIMER_SYNC_CFG2_NU1_S 2 +#define HIB1P2_HIB_TIMER_SYNC_CFG2_mem_cfg_tsf_adj \ + 0x00000002 + +#define HIB1P2_HIB_TIMER_SYNC_CFG2_mem_cfg_update_tsf \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_TSF_ADJ_VAL register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_TSF_ADJ_VAL_mem_tsf_adj_val_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_TIMER_SYNC_TSF_ADJ_VAL_mem_tsf_adj_val_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_RTC_GTS_TIMESTAMP_LSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_LSW_rtc_gts_timestamp_lsw_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_LSW_rtc_gts_timestamp_lsw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW_reserved_M \ + 0xFFFF0000 + +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW_reserved_S 16 +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW_rtc_gts_timestamp_msw_M \ + 0x0000FFFF + +#define HIB1P2_HIB_TIMER_RTC_GTS_TIMESTAMP_MSW_rtc_gts_timestamp_msw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_RTC_WUP_TIMESTAMP_LSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_LSW_rtc_wup_timestamp_lsw_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_LSW_rtc_wup_timestamp_lsw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW_reserved_M \ + 0xFFFF0000 + +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW_reserved_S 16 +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW_rtc_wup_timestamp_msw_M \ + 0x0000FFFF + +#define HIB1P2_HIB_TIMER_RTC_WUP_TIMESTAMP_MSW_rtc_wup_timestamp_msw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_WAKE_OFFSET_ERR register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_WAKE_OFFSET_ERR_reserved_M \ + 0xFFFFF000 + +#define HIB1P2_HIB_TIMER_SYNC_WAKE_OFFSET_ERR_reserved_S 12 +#define HIB1P2_HIB_TIMER_SYNC_WAKE_OFFSET_ERR_wup_offset_error_M \ + 0x00000FFF + +#define HIB1P2_HIB_TIMER_SYNC_WAKE_OFFSET_ERR_wup_offset_error_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_TSF_CURR_VAL_LSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_TSF_CURR_VAL_LSW_tsf_curr_val_lsw_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_TIMER_SYNC_TSF_CURR_VAL_LSW_tsf_curr_val_lsw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_HIB_TIMER_SYNC_TSF_CURR_VAL_MSW register. +// +//****************************************************************************** +#define HIB1P2_HIB_TIMER_SYNC_TSF_CURR_VAL_MSW_tsf_curr_val_msw_M \ + 0xFFFFFFFF + +#define HIB1P2_HIB_TIMER_SYNC_TSF_CURR_VAL_MSW_tsf_curr_val_msw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the HIB1P2_O_CM_SPARE register. +// +//****************************************************************************** +#define HIB1P2_CM_SPARE_CM_SPARE_OUT_M \ + 0xFF000000 + +#define HIB1P2_CM_SPARE_CM_SPARE_OUT_S 24 +#define HIB1P2_CM_SPARE_MEM_CM_TEST_CTRL_M \ + 0x00FF0000 + +#define HIB1P2_CM_SPARE_MEM_CM_TEST_CTRL_S 16 +#define HIB1P2_CM_SPARE_MEM_CM_SPARE_M \ + 0x0000FFFF + +#define HIB1P2_CM_SPARE_MEM_CM_SPARE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_PORPOL_SPARE register. +// +//****************************************************************************** +#define HIB1P2_PORPOL_SPARE_MEM_PORPOL_SPARE_M \ + 0xFFFFFFFF + +#define HIB1P2_PORPOL_SPARE_MEM_PORPOL_SPARE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_DIG_DCDC_CLK_CONFIG register. +// +//****************************************************************************** +#define HIB1P2_MEM_DIG_DCDC_CLK_CONFIG_MEM_DIG_DCDC_CLK_ENABLE \ + 0x00000100 + +#define HIB1P2_MEM_DIG_DCDC_CLK_CONFIG_MEM_DIG_DCDC_CLK_PLLGEN_OFF_TIME_M \ + 0x000000F0 + +#define HIB1P2_MEM_DIG_DCDC_CLK_CONFIG_MEM_DIG_DCDC_CLK_PLLGEN_OFF_TIME_S 4 +#define HIB1P2_MEM_DIG_DCDC_CLK_CONFIG_MEM_DIG_DCDC_CLK_PLLGEN_ON_TIME_M \ + 0x0000000F + +#define HIB1P2_MEM_DIG_DCDC_CLK_CONFIG_MEM_DIG_DCDC_CLK_PLLGEN_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_ANA_DCDC_CLK_CONFIG register. +// +//****************************************************************************** +#define HIB1P2_MEM_ANA_DCDC_CLK_CONFIG_MEM_ANA_DCDC_CLK_ENABLE \ + 0x00000100 + +#define HIB1P2_MEM_ANA_DCDC_CLK_CONFIG_MEM_ANA_DCDC_CLK_PLLGEN_OFF_TIME_M \ + 0x000000F0 + +#define HIB1P2_MEM_ANA_DCDC_CLK_CONFIG_MEM_ANA_DCDC_CLK_PLLGEN_OFF_TIME_S 4 +#define HIB1P2_MEM_ANA_DCDC_CLK_CONFIG_MEM_ANA_DCDC_CLK_PLLGEN_ON_TIME_M \ + 0x0000000F + +#define HIB1P2_MEM_ANA_DCDC_CLK_CONFIG_MEM_ANA_DCDC_CLK_PLLGEN_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_FLASH_DCDC_CLK_CONFIG register. +// +//****************************************************************************** +#define HIB1P2_MEM_FLASH_DCDC_CLK_CONFIG_MEM_FLASH_DCDC_CLK_ENABLE \ + 0x00000100 + +#define HIB1P2_MEM_FLASH_DCDC_CLK_CONFIG_MEM_FLASH_DCDC_CLK_PLLGEN_OFF_TIME_M \ + 0x000000F0 + +#define HIB1P2_MEM_FLASH_DCDC_CLK_CONFIG_MEM_FLASH_DCDC_CLK_PLLGEN_OFF_TIME_S 4 +#define HIB1P2_MEM_FLASH_DCDC_CLK_CONFIG_MEM_FLASH_DCDC_CLK_PLLGEN_ON_TIME_M \ + 0x0000000F + +#define HIB1P2_MEM_FLASH_DCDC_CLK_CONFIG_MEM_FLASH_DCDC_CLK_PLLGEN_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_PA_DCDC_CLK_CONFIG register. +// +//****************************************************************************** +#define HIB1P2_MEM_PA_DCDC_CLK_CONFIG_MEM_PA_DCDC_CLK_ENABLE \ + 0x00000100 + +#define HIB1P2_MEM_PA_DCDC_CLK_CONFIG_MEM_PA_DCDC_CLK_PLLGEN_OFF_TIME_M \ + 0x000000F0 + +#define HIB1P2_MEM_PA_DCDC_CLK_CONFIG_MEM_PA_DCDC_CLK_PLLGEN_OFF_TIME_S 4 +#define HIB1P2_MEM_PA_DCDC_CLK_CONFIG_MEM_PA_DCDC_CLK_PLLGEN_ON_TIME_M \ + 0x0000000F + +#define HIB1P2_MEM_PA_DCDC_CLK_CONFIG_MEM_PA_DCDC_CLK_PLLGEN_ON_TIME_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_SLDO_VNWA_OVERRIDE register. +// +//****************************************************************************** +#define HIB1P2_MEM_SLDO_VNWA_OVERRIDE_MEM_SLDO_EN_TOP_VNWA_OVERRIDE_CTRL \ + 0x00000002 + +#define HIB1P2_MEM_SLDO_VNWA_OVERRIDE_MEM_SLDO_EN_TOP_VNWA_OVERRIDE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_BGAP_DUTY_CYCLING_ENABLE_OVERRIDE register. +// +//****************************************************************************** +#define HIB1P2_MEM_BGAP_DUTY_CYCLING_ENABLE_OVERRIDE_MEM_BGAP_DUTY_CYCLING_OVERRIDE_CTRL \ + 0x00000002 + +#define HIB1P2_MEM_BGAP_DUTY_CYCLING_ENABLE_OVERRIDE_MEM_BGAP_DUTY_CYCLING_OVERRIDE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_HIB_FSM_DEBUG register. +// +//****************************************************************************** +#define HIB1P2_MEM_HIB_FSM_DEBUG_SRAM_PS_M \ + 0x00000700 + +#define HIB1P2_MEM_HIB_FSM_DEBUG_SRAM_PS_S 8 +#define HIB1P2_MEM_HIB_FSM_DEBUG_ANA_DCDC_PS_M \ + 0x000000F0 + +#define HIB1P2_MEM_HIB_FSM_DEBUG_ANA_DCDC_PS_S 4 +#define HIB1P2_MEM_HIB_FSM_DEBUG_DIG_DCDC_PS_M \ + 0x0000000F + +#define HIB1P2_MEM_HIB_FSM_DEBUG_DIG_DCDC_PS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_SLDO_VNWA_SW_CTRL register. +// +//****************************************************************************** +#define HIB1P2_MEM_SLDO_VNWA_SW_CTRL_MEM_SLDO_VNWA_SW_CTRL_M \ + 0x000FFFFF + +#define HIB1P2_MEM_SLDO_VNWA_SW_CTRL_MEM_SLDO_VNWA_SW_CTRL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_SLDO_WEAK_PROCESS register. +// +//****************************************************************************** +#define HIB1P2_MEM_SLDO_WEAK_PROCESS_MEM_SLDO_WEAK_PROCESS \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_PA_DCDC_OV_UV_STATUS register. +// +//****************************************************************************** +#define HIB1P2_MEM_PA_DCDC_OV_UV_STATUS_dcdc_pa_ov_prot_out_lowv \ + 0x00000002 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB1P2_O_MEM_CM_TEST_MODE register. +// +//****************************************************************************** +#define HIB1P2_MEM_CM_TEST_MODE_mem_cm_test_mode \ + 0x00000001 + + + + +#endif // __HW_HIB1P2_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib3p3.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib3p3.h new file mode 100755 index 0000000..9701689 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_hib3p3.h @@ -0,0 +1,1138 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_HIB3P3_H__ +#define __HW_HIB3P3_H__ + +//***************************************************************************** +// +// The following are defines for the HIB3P3 register offsets. +// +//***************************************************************************** +#define HIB3P3_O_MEM_HIB_REQ 0x00000000 +#define HIB3P3_O_MEM_HIB_RTC_TIMER_ENABLE \ + 0x00000004 + +#define HIB3P3_O_MEM_HIB_RTC_TIMER_RESET \ + 0x00000008 + +#define HIB3P3_O_MEM_HIB_RTC_TIMER_READ \ + 0x0000000C + +#define HIB3P3_O_MEM_HIB_RTC_TIMER_LSW \ + 0x00000010 + +#define HIB3P3_O_MEM_HIB_RTC_TIMER_MSW \ + 0x00000014 + +#define HIB3P3_O_MEM_HIB_RTC_WAKE_EN \ + 0x00000018 + +#define HIB3P3_O_MEM_HIB_RTC_WAKE_LSW_CONF \ + 0x0000001C + +#define HIB3P3_O_MEM_HIB_RTC_WAKE_MSW_CONF \ + 0x00000020 + +#define HIB3P3_O_MEM_INT_OSC_CONF \ + 0x0000002C + +#define HIB3P3_O_MEM_XTAL_OSC_CONF \ + 0x00000034 + +#define HIB3P3_O_MEM_BGAP_PARAMETERS0 \ + 0x00000038 + +#define HIB3P3_O_MEM_BGAP_PARAMETERS1 \ + 0x0000003C + +#define HIB3P3_O_MEM_HIB_DETECTION_STATUS \ + 0x00000040 + +#define HIB3P3_O_MEM_HIB_MISC_CONTROLS \ + 0x00000044 + +#define HIB3P3_O_MEM_HIB_CONFIG 0x00000050 +#define HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE \ + 0x00000054 + +#define HIB3P3_O_MEM_HIB_RTC_IRQ_LSW_CONF \ + 0x00000058 + +#define HIB3P3_O_MEM_HIB_RTC_IRQ_MSW_CONF \ + 0x0000005C + +#define HIB3P3_O_MEM_HIB_UART_CONF \ + 0x00000400 + +#define HIB3P3_O_MEM_GPIO_WAKE_EN \ + 0x00000404 + +#define HIB3P3_O_MEM_GPIO_WAKE_CONF \ + 0x00000408 + +#define HIB3P3_O_MEM_PAD_OEN_RET33_CONF \ + 0x0000040C + +#define HIB3P3_O_MEM_UART_RTS_OEN_RET33_CONF \ + 0x00000410 + +#define HIB3P3_O_MEM_JTAG_CONF 0x00000414 +#define HIB3P3_O_MEM_HIB_REG0 0x00000418 +#define HIB3P3_O_MEM_HIB_REG1 0x0000041C +#define HIB3P3_O_MEM_HIB_REG2 0x00000420 +#define HIB3P3_O_MEM_HIB_REG3 0x00000424 +#define HIB3P3_O_MEM_HIB_SEQUENCER_CFG0 \ + 0x0000045C + +#define HIB3P3_O_MEM_HIB_SEQUENCER_CFG1 \ + 0x00000460 + +#define HIB3P3_O_MEM_HIB_MISC_CONFIG \ + 0x00000464 + +#define HIB3P3_O_MEM_HIB_WAKE_STATUS \ + 0x00000468 + +#define HIB3P3_O_MEM_HIB_LPDS_GPIO_SEL \ + 0x0000046C + +#define HIB3P3_O_MEM_HIB_SEQUENCER_CFG2 \ + 0x00000470 + +#define HIB3P3_O_HIBANA_SPARE_LOWV \ + 0x00000474 + +#define HIB3P3_O_HIB_TMUX_CTRL 0x00000478 +#define HIB3P3_O_HIB_1P2_1P8_LDO_TRIM \ + 0x0000047C + +#define HIB3P3_O_HIB_COMP_TRIM 0x00000480 +#define HIB3P3_O_HIB_EN_TS 0x00000484 +#define HIB3P3_O_HIB_1P8V_DET_EN \ + 0x00000488 + +#define HIB3P3_O_HIB_VBAT_MON_EN \ + 0x0000048C + +#define HIB3P3_O_HIB_NHIB_ENABLE \ + 0x00000490 + +#define HIB3P3_O_HIB_UART_RTS_SW_ENABLE \ + 0x00000494 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_REQ register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_REQ_reserved_M \ + 0xFFFFFE00 + +#define HIB3P3_MEM_HIB_REQ_reserved_S 9 +#define HIB3P3_MEM_HIB_REQ_NU1_M \ + 0x000001FC + +#define HIB3P3_MEM_HIB_REQ_NU1_S 2 +#define HIB3P3_MEM_HIB_REQ_mem_hib_clk_disable \ + 0x00000002 // 1 - Specifies that the Hiberante + // mode is without clocks ; 0 - + // Specified that the Hibernate mode + // is with clocks This register will + // be reset during Hibernate + // -WO-Clks mode (but not during + // Hibernate-W-Clks mode). + +#define HIB3P3_MEM_HIB_REQ_mem_hib_req \ + 0x00000001 // 1 - Request for hibernate mode + // (This is an auto-clear bit) ; 0 - + // Donot request for hibernate mode + // This register will be reset + // during Hibernate -WO-Clks mode + // (but not during Hibernate-W-Clks + // mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_TIMER_ENABLE register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_TIMER_ENABLE_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_MEM_HIB_RTC_TIMER_ENABLE_reserved_S 1 +#define HIB3P3_MEM_HIB_RTC_TIMER_ENABLE_mem_hib_rtc_timer_enable \ + 0x00000001 // 1 - Enable the RTC timer to + // start running ; 0 - Keep the RTC + // timer disabled This register will + // be reset during Hibernate + // -WO-Clks mode (but not during + // Hibernate-W-Clks mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_TIMER_RESET register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_TIMER_RESET_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_MEM_HIB_RTC_TIMER_RESET_reserved_S 1 +#define HIB3P3_MEM_HIB_RTC_TIMER_RESET_mem_hib_rtc_timer_reset \ + 0x00000001 // 1 - Reset the RTC timer ; 0 - + // Donot reset the RTC timer. This + // is an auto-clear bit. This + // register will be reset during + // Hibernate -WO-Clks mode (but not + // during Hibernate-W-Clks mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_TIMER_READ register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_TIMER_READ_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_MEM_HIB_RTC_TIMER_READ_reserved_S 1 +#define HIB3P3_MEM_HIB_RTC_TIMER_READ_mem_hib_rtc_timer_read \ + 0x00000001 // 1 - Latch the running RTC timer + // into local registers. After + // programming this bit to 1, the + // F/w can read the latched RTC + // timer values from + // MEM_HIB_RTC_TIMER_LSW and + // MEM_HIB_RTC_TIMER_MSW. Before the + // F/w (APPS or NWP) wants to read + // the RTC-Timer, it has to program + // this bit to 1, then only read the + // MSW and LSW values. This is an + // auto-clear bit. This register + // will be reset during Hibernate + // -WO-Clks mode (but not during + // Hibernate-W-Clks mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_TIMER_LSW register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_TIMER_LSW_hib_rtc_timer_lsw_M \ + 0xFFFFFFFF // Lower 32b value of the latched + // RTC-Timer. + +#define HIB3P3_MEM_HIB_RTC_TIMER_LSW_hib_rtc_timer_lsw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_TIMER_MSW register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_TIMER_MSW_reserved_M \ + 0xFFFF0000 + +#define HIB3P3_MEM_HIB_RTC_TIMER_MSW_reserved_S 16 +#define HIB3P3_MEM_HIB_RTC_TIMER_MSW_hib_rtc_timer_msw_M \ + 0x0000FFFF // Upper 32b value of the latched + // RTC-Timer. + +#define HIB3P3_MEM_HIB_RTC_TIMER_MSW_hib_rtc_timer_msw_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_WAKE_EN register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_WAKE_EN_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_MEM_HIB_RTC_WAKE_EN_reserved_S 1 +#define HIB3P3_MEM_HIB_RTC_WAKE_EN_mem_hib_rtc_wake_en \ + 0x00000001 // 1 - Enable the RTC timer based + // wakeup during Hibernate mode ; 0 + // - Disable the RTC timer based + // wakeup during Hibernate mode This + // register will be reset during + // Hibernate-WO-Clks mode (but not + // during Hibernate-W-Clks mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_WAKE_LSW_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_WAKE_LSW_CONF_mem_hib_rtc_wake_lsw_conf_M \ + 0xFFFFFFFF // Configuration for RTC-Timer + // Wakeup (Lower 32b word) + +#define HIB3P3_MEM_HIB_RTC_WAKE_LSW_CONF_mem_hib_rtc_wake_lsw_conf_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_WAKE_MSW_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_WAKE_MSW_CONF_reserved_M \ + 0xFFFF0000 + +#define HIB3P3_MEM_HIB_RTC_WAKE_MSW_CONF_reserved_S 16 +#define HIB3P3_MEM_HIB_RTC_WAKE_MSW_CONF_mem_hib_rtc_wake_msw_conf_M \ + 0x0000FFFF // Configuration for RTC-Timer + // Wakeup (Upper 16b word) + +#define HIB3P3_MEM_HIB_RTC_WAKE_MSW_CONF_mem_hib_rtc_wake_msw_conf_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_INT_OSC_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_INT_OSC_CONF_reserved_M \ + 0xFFFF0000 + +#define HIB3P3_MEM_INT_OSC_CONF_reserved_S 16 +#define HIB3P3_MEM_INT_OSC_CONF_cm_clk_good_32k_int \ + 0x00008000 // 1 - Internal 32kHz Oscillator is + // valid ; 0 - Internal 32k + // oscillator clk is not valid + +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_intosc_32k_spare_M \ + 0x00007E00 + +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_intosc_32k_spare_S 9 +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_en_intosc_32k_override_ctrl \ + 0x00000100 // When 1, the INT_32K_OSC_EN comes + // from bit [0] of this register, + // else comes from the FSM. This + // register will be reset during + // Hibernate-WO-Clks mode (but not + // during Hibernate-W-Clks mode) + +#define HIB3P3_MEM_INT_OSC_CONF_NU1 \ + 0x00000080 + +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_intosc_32k_trim_M \ + 0x0000007E + +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_intosc_32k_trim_S 1 +#define HIB3P3_MEM_INT_OSC_CONF_mem_cm_en_intosc_32k \ + 0x00000001 // Override value for INT_OSC_EN. + // Applicable only when bit [3] of + // this register is set to 1. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_XTAL_OSC_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_XTAL_OSC_CONF_reserved_M \ + 0xFFF00000 + +#define HIB3P3_MEM_XTAL_OSC_CONF_reserved_S 20 +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_sli_32k_override_ctrl \ + 0x00080000 // When 1, the SLICER_EN comes from + // bit [10] of this register, else + // comes from the FSM. + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_xtal_32k_override_ctrl \ + 0x00040000 // When 1, the XTAL_EN comes from + // bit [0] of this register, else + // comes from the FSM. + +#define HIB3P3_MEM_XTAL_OSC_CONF_cm_clk_good_xtal \ + 0x00020000 // 1 - XTAL Clk is good ; 0 - XTAL + // Clk is yet to be valid. + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_xtal_trim_M \ + 0x0001F800 + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_xtal_trim_S 11 +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_sli_32k \ + 0x00000400 // SLICER_EN Override value : + // Applicable only when bit [19] of + // this register is set to 1. + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_sli_32k_trim_M \ + 0x00000380 + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_sli_32k_trim_S 7 +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_fref_32k_slicer_itrim_M \ + 0x00000070 + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_fref_32k_slicer_itrim_S 4 +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_fref_32k_slicer \ + 0x00000008 + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_input_sense_M \ + 0x00000006 + +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_input_sense_S 1 +#define HIB3P3_MEM_XTAL_OSC_CONF_mem_cm_en_xtal_32k \ + 0x00000001 // XTAL_EN Override value : + // Applicable only when bit [18] of + // this register is set to 1. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_BGAP_PARAMETERS0 register. +// +//****************************************************************************** +#define HIB3P3_MEM_BGAP_PARAMETERS0_reserved_M \ + 0xFFF80000 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_reserved_S 19 +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_en_seq \ + 0x00040000 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_vbok4bg_comp_trim_M \ + 0x0001C000 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_vbok4bg_comp_trim_S 14 +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_bgap_en_vbat_ok_4bg \ + 0x00001000 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_bgap_en_vbok4bg_comp \ + 0x00000800 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_bgap_en_vbok4bg_comp_ref \ + 0x00000400 + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_bgap_spare_M \ + 0x000003FF + +#define HIB3P3_MEM_BGAP_PARAMETERS0_mem_bgap_spare_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_BGAP_PARAMETERS1 register. +// +//****************************************************************************** +#define HIB3P3_MEM_BGAP_PARAMETERS1_reserved_M \ + 0xE0000000 + +#define HIB3P3_MEM_BGAP_PARAMETERS1_reserved_S 29 +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_act_iref_itrim_M \ + 0x1F000000 + +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_act_iref_itrim_S 24 +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_en_act_iref \ + 0x00000008 + +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_en_v2i \ + 0x00000004 + +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_en_cap_sw \ + 0x00000002 + +#define HIB3P3_MEM_BGAP_PARAMETERS1_mem_bgap_en \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_DETECTION_STATUS register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_DETECTION_STATUS_reserved_M \ + 0xFFFFFF80 + +#define HIB3P3_MEM_HIB_DETECTION_STATUS_reserved_S 7 +#define HIB3P3_MEM_HIB_DETECTION_STATUS_hib_forced_ana_status \ + 0x00000040 // 1 - 1.8 V supply forced mode. + +#define HIB3P3_MEM_HIB_DETECTION_STATUS_hib_forced_flash_status \ + 0x00000004 // 1 - 3.3 V supply forced mode for + // Flash supply + +#define HIB3P3_MEM_HIB_DETECTION_STATUS_hib_ext_clk_det_out_status \ + 0x00000002 // 1 - Forced clock mode + +#define HIB3P3_MEM_HIB_DETECTION_STATUS_hib_xtal_det_out_status \ + 0x00000001 // 1 - XTAL clock mode + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_MISC_CONTROLS register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_MISC_CONTROLS_reserved_M \ + 0xFFFFF800 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_reserved_S 11 +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_en_pok_por_comp \ + 0x00000400 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_en_pok_por_comp_ref \ + 0x00000200 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_pok_por_comp_trim_M \ + 0x000001C0 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_pok_por_comp_trim_S 6 +#define HIB3P3_MEM_HIB_MISC_CONTROLS_NU1 \ + 0x00000020 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_flash_det_en \ + 0x00000010 + +#define HIB3P3_MEM_HIB_MISC_CONTROLS_mem_hib_en_tmux \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_CONFIG register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_CONFIG_TOP_MUX_CTRL_SOP_SPIO_M \ + 0xFF000000 + +#define HIB3P3_MEM_HIB_CONFIG_TOP_MUX_CTRL_SOP_SPIO_S 24 +#define HIB3P3_MEM_HIB_CONFIG_EN_ANA_DIG_SHARED3 \ + 0x00080000 // 1 - Enable VDD_FLASH_INDP_PAD + // for digital path (SHARED4) ; 0 - + // Disable VDD_FLASH_INDP_PAD for + // digital path (SHARED4) ; Before + // programming this bit to 1, ensure + // that the device is in FORCED 3.3 + // supply Mode, which can be + // inferred from the register : + // MEM_HIB_DETECTION_STATUS : 0x0040 + +#define HIB3P3_MEM_HIB_CONFIG_EN_ANA_DIG_SHARED2 \ + 0x00040000 // 1 - Enable the + // VDD_FB_GPIO_MUX_PAD for digital + // path (SHARED3) ; 0 - Disable the + // VDD_FB_GPIO_MUX_PAD for digital + // path (SHARED3) ; This pin can be + // used only in modes other than + // SOP("111") + +#define HIB3P3_MEM_HIB_CONFIG_EN_ANA_DIG_SHARED1 \ + 0x00020000 // 1 - Enable the PM_TEST_PAD for + // digital GPIO path (SHARED2) ; 0 - + // Disable the PM_TEST_PAD for + // digital GPIO path (SHARED2) This + // pin can be used for digital only + // in modes other then SOP-111 + +#define HIB3P3_MEM_HIB_CONFIG_EN_ANA_DIG_SHARED0 \ + 0x00010000 // 1 - Enable the XTAL_N pin + // digital GPIO path (SHARED1); 0 - + // Disable the XTAL_N pin digital + // GPIO path (SHARED1). Before + // programming this bit to 1, ensure + // that the device is in FORCED CLK + // Mode, which can inferred from the + // register : + // MEM_HIB_DETECTION_STATUS : + // 0x0040. + +#define HIB3P3_MEM_HIB_CONFIG_mem_hib_xtal_enable \ + 0x00000100 // 1 - Enable the XTAL Clock ; 0 - + // Donot enable the XTAL Clock. This + // bit has to be programmed to 1 (by + // APPS Devinit F/w), during exit + // from OFF or Hib_wo_clks modes, + // after checking if the slow_clk + // mode is XTAL_CLK mode. Once + // enabled the XTAL will be disabled + // only after entering HIB_WO_CLKS + // mode. This register will be reset + // during Hibernate -WO-Clks mode + // (but not during Hibernate-W-Clks + // mode). + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_IRQ_ENABLE_HIB_RTC_IRQ_ENABLE \ + 0x00000001 // 1 - Enable the HIB RTC - IRQ ; 0 + // - Disable the HIB RTC - IRQ + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_IRQ_LSW_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_IRQ_LSW_CONF_HIB_RTC_IRQ_LSW_CONF_M \ + 0xFFFFFFFF // Configuration for LSW of the + // RTC-Timestamp at which interrupt + // need to be generated + +#define HIB3P3_MEM_HIB_RTC_IRQ_LSW_CONF_HIB_RTC_IRQ_LSW_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_RTC_IRQ_MSW_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_RTC_IRQ_MSW_CONF_HIB_RTC_IRQ_MSW_CONF_M \ + 0x0000FFFF // Configuration for MSW of thr + // RTC-Timestamp at which the + // interrupt need to be generated + +#define HIB3P3_MEM_HIB_RTC_IRQ_MSW_CONF_HIB_RTC_IRQ_MSW_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_UART_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_UART_CONF_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_MEM_HIB_UART_CONF_reserved_S 1 +#define HIB3P3_MEM_HIB_UART_CONF_mem_hib_uart_wake_en \ + 0x00000001 // 1 - Enable the UART-Autonomous + // mode wakeup during Hibernate mode + // ; This is an auto-clear bit, once + // programmed to 1, it will latched + // into an internal register which + // remain asserted until the + // Hib-wakeup is initiated. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_GPIO_WAKE_EN register. +// +//****************************************************************************** +#define HIB3P3_MEM_GPIO_WAKE_EN_reserved_M \ + 0xFFFFFF00 + +#define HIB3P3_MEM_GPIO_WAKE_EN_reserved_S 8 +#define HIB3P3_MEM_GPIO_WAKE_EN_mem_gpio_wake_en_M \ + 0x000000FF // 1 - Enable the GPIO-Autonomous + // mode wakeup during Hibernate mode + // ; This is an auto-clear bit, once + // programmed to 1, it will latched + // into an internal register which + // remain asserted until the + // Hib-wakeup is initiated. + +#define HIB3P3_MEM_GPIO_WAKE_EN_mem_gpio_wake_en_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_GPIO_WAKE_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_GPIO_WAKE_CONF_reserved_M \ + 0xFFFF0000 + +#define HIB3P3_MEM_GPIO_WAKE_CONF_reserved_S 16 +#define HIB3P3_MEM_GPIO_WAKE_CONF_mem_gpio_wake_conf_M \ + 0x0000FFFF // Configuration to say whether the + // GPIO wakeup has to happen on + // Level0 or falling-edge for the + // given group. “00†– Level0 “01†– + // Level1 “10â€- Fall-edge “11â€- + // Rise-edge [1:0] – Conf for GPIO0 + // [3:2] – Conf for GPIO1 [5:4] – + // Conf for GPIO2 [7:6] – Conf for + // GPIO3 [9:8] – Conf for GPIO4 + // [11:10] – Conf for GPIO5 [13:12] + // – Conf for GPIO6 + +#define HIB3P3_MEM_GPIO_WAKE_CONF_mem_gpio_wake_conf_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_PAD_OEN_RET33_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_PAD_OEN_RET33_CONF_mem_pad_oen_ret33_override_ctrl \ + 0x00000004 // 1 - Override the OEN33 and RET33 + // controls of GPIOs during + // SOP-Bootdebug mode ; 0 - Donot + // override the OEN33 and RET33 + // controls of GPIOs during + // SOP-Bootdebug mode + +#define HIB3P3_MEM_PAD_OEN_RET33_CONF_PAD_OEN33_CONF \ + 0x00000002 + +#define HIB3P3_MEM_PAD_OEN_RET33_CONF_PAD_RET33_CONF \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_UART_RTS_OEN_RET33_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_UART_RTS_OEN_RET33_CONF_mem_uart_nrts_oen_ret33_override_ctrl \ + 0x00000004 // 1 - Override the OEN33 and RET33 + // controls of UART NRTS GPIO during + // SOP-Bootdebug mode ; 0 - Donot + // override the OEN33 and RET33 + // controls of UART NRTS GPIO during + // SOP-Bootdebug mode + +#define HIB3P3_MEM_UART_RTS_OEN_RET33_CONF_PAD_UART_RTS_OEN33_CONF \ + 0x00000002 + +#define HIB3P3_MEM_UART_RTS_OEN_RET33_CONF_PAD_UART_RTS_RET33_CONF \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_JTAG_CONF register. +// +//****************************************************************************** +#define HIB3P3_MEM_JTAG_CONF_mem_jtag1_oen_ret33_override_ctrl \ + 0x00000200 + +#define HIB3P3_MEM_JTAG_CONF_mem_jtag0_oen_ret33_override_ctrl \ + 0x00000100 + +#define HIB3P3_MEM_JTAG_CONF_PAD_JTAG1_RTS_OEN33_CONF \ + 0x00000008 + +#define HIB3P3_MEM_JTAG_CONF_PAD_JTAG1_RTS_RET33_CONF \ + 0x00000004 + +#define HIB3P3_MEM_JTAG_CONF_PAD_JTAG0_RTS_OEN33_CONF \ + 0x00000002 + +#define HIB3P3_MEM_JTAG_CONF_PAD_JTAG0_RTS_RET33_CONF \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_REG0 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_REG0_mem_hib_reg0_M \ + 0xFFFFFFFF + +#define HIB3P3_MEM_HIB_REG0_mem_hib_reg0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_REG1 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_REG1_mem_hib_reg1_M \ + 0xFFFFFFFF + +#define HIB3P3_MEM_HIB_REG1_mem_hib_reg1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_REG2 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_REG2_mem_hib_reg2_M \ + 0xFFFFFFFF + +#define HIB3P3_MEM_HIB_REG2_mem_hib_reg2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_REG3 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_REG3_mem_hib_reg3_M \ + 0xFFFFFFFF + +#define HIB3P3_MEM_HIB_REG3_mem_hib_reg3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_SEQUENCER_CFG0 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev0_to_ev1_time_M \ + 0xFFFF0000 // Configuration for the number of + // slow-clks between de-assertion of + // EN_BG_3P3V to assertion of + // EN_BG_3P3V + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev0_to_ev1_time_S 16 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_NU1 \ + 0x00008000 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev3_to_ev4_time_M \ + 0x00006000 // Configuration for the number of + // slow-clks between assertion of + // EN_COMP_3P3V and assertion of + // EN_COMP_LATCH_3P3V + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev3_to_ev4_time_S 13 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev2_to_ev3_time_M \ + 0x00001800 // Configuration for the number of + // slow-clks between assertion of + // (EN_CAP_SW_3P3V,EN_COMP_REF) and + // assertion of (EN_COMP_3P3V) + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev2_to_ev3_time_S 11 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev1_to_ev2_time_M \ + 0x00000600 // Configuration for the number of + // slow-clks between assertion of + // (EN_BG_3P3V) and assertion of + // (EN_CAP_SW_3P3V, + // EN_COMP_REF_3P3V) + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bdc_ev1_to_ev2_time_S 9 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_en_crude_ref_comp \ + 0x00000100 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_en_vbok4bg_ref_override_ctrl \ + 0x00000080 // 1 - EN_VBOK4BG_REF comes from + // bit[10] of the register + // MEM_BGAP_PARAMETERS0 [0x0038]. 0 + // - EN_VBOK4BG_REF comes directly + // from the Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_en_vbok4bg_comp_override_ctrl \ + 0x00000040 // 1 - EN_VBOK4BG comes from + // bit[11] of the register + // MEM_BGAP_PARAMETERS0 [0x0038]. 0 + // - EN_VBOK4BG comes directly from + // the Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_en_v2i_override_ctrl \ + 0x00000020 // 1 - EN_V2I comes from bit[2] of + // the register MEM_BGAP_PARAMETERS1 + // [0x003C]. 0 - EN_V2I comes + // directly from the Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_por_comp_ref_override_ctrl \ + 0x00000010 // 1 - EN_POR_COMP_REF comes from + // bit[9] of the register + // MEM_HIB_MISC_CONTROLS [0x0044]. 0 + // - EN_POR_COMP_REF comes directly + // from the Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_en_por_comp_override_ctrl \ + 0x00000008 // 1 - EN_POR_COMP comes from + // bit[10] of the register + // MEM_HIB_MISC_CONTROLS [0x044]. 0 + // - EN_POR_COMP comes directly from + // the Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_cap_sw_override_ctrl \ + 0x00000004 // 1 - EN_CAP_SW comes from bit[1] + // of the register + // MEM_BGAP_PARAMETERS1 [0x003C]. 0 + // - EN_CAP_SW comes directly from + // Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_bg_override_ctrl \ + 0x00000002 // 1 - EN_BGAP comes from bit[0] of + // the register MEM_BGAP_PARAMETERS1 + // [0x003C]. 0 - EN_BGAP comes + // directly from Hib-Sequencer. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG0_mem_act_iref_override_ctrl \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_SEQUENCER_CFG1 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_reserved_M \ + 0xFFFF0000 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_reserved_S 16 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_ev5_to_ev6_time_M \ + 0x0000C000 // Configuration for number of + // slow-clks between de-assertion of + // EN_COMP_LATCH and assertion of + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_ev5_to_ev6_time_S 14 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev1_to_ev2_time_M \ + 0x00003000 // Configuration for number of + // slow-clks between assertion of + // EN_COMP_REF to assertion of + // EN_COMP during HIB-Exit + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev1_to_ev2_time_S 12 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev0_to_ev1_time_M \ + 0x00000C00 // TBD + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev0_to_ev1_time_S 10 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev0_to_active_M \ + 0x00000300 // Configuration in number of + // slow-clks between assertion of + // (EN_BGAP_3P3V, EN_CAP_SW_3P3V, + // EN_ACT_IREF_3P3V, EN_COMP_REF) to + // assertion of EN_COMP_3P3V + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_bdc_to_active_ev0_to_active_S 8 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_active_to_bdc_ev1_to_bdc_ev0_time_M \ + 0x000000C0 // Configuration in number of + // slow-clks between de-assertion of + // (EN_COMP_3P3V, EN_COMP_REF_3P3V, + // EN_ACT_IREF_3P3V, EN_CAP_SW_3P3V) + // to deassertion of EN_BGAP_3P3V. + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_mem_active_to_bdc_ev1_to_bdc_ev0_time_S 6 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_NU1_M \ + 0x0000003F + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG1_NU1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_MISC_CONFIG register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_MISC_CONFIG_mem_en_pll_untrim_current \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_WAKE_STATUS register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_WAKE_STATUS_hib_wake_src_M \ + 0x0000001E // "0100" - GPIO ; "0010" - RTC ; + // "0001" - UART Others - Reserved + +#define HIB3P3_MEM_HIB_WAKE_STATUS_hib_wake_src_S 1 +#define HIB3P3_MEM_HIB_WAKE_STATUS_hib_wake_status \ + 0x00000001 // 1 - Wake from Hibernate ; 0 - + // Wake from OFF + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_LPDS_GPIO_SEL register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_LPDS_GPIO_SEL_HIB_LPDS_GPIO_SEL_M \ + 0x00000007 + +#define HIB3P3_MEM_HIB_LPDS_GPIO_SEL_HIB_LPDS_GPIO_SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_MEM_HIB_SEQUENCER_CFG2 register. +// +//****************************************************************************** +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_reserved_M \ + 0xFFFFF800 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_reserved_S 11 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_active_to_bdc_ev0_to_active_to_bdc_ev1_time_M \ + 0x00000600 // Deassertion of EN_COMP_LATCH_3P3 + // to deassertion of (EN_COMP_3P3, + // EN_COMP_REF_3P3, EN_ACT_IREF_3P3, + // EN_CAP_SW_3P3) + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_active_to_bdc_ev0_to_active_to_bdc_ev1_time_S 9 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_ev4_to_ev5_time_M \ + 0x000001C0 // Assertion of EN_COMP_LATCH_3P3 + // to deassertion of + // EN_COMP_LATCH_3P3 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_ev4_to_ev5_time_S 6 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_ev6_to_ev7_time_M \ + 0x00000030 // Deassertion of (EN_CAP_SW_3P3, + // EN_COMP_REF_3P3, EN_COMP_3P3, + // EN_COMP_OUT_LATCH_3P3) to + // deassertion of EN_BGAP_3P3 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_ev6_to_ev7_time_S 4 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_to_active_ev1_to_ev2_time_M \ + 0x0000000C // Assertion of EN_COMP_3P3 to + // assertion of EN_COMPOUT_LATCH_3P3 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_bdc_to_active_ev1_to_ev2_time_S 2 +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_hib_to_active_ev2_to_ev3_time_M \ + 0x00000003 // Assertion of EN_COMP_3P3 to + // assertion of EN_COMPOUT_LATCH_3P3 + +#define HIB3P3_MEM_HIB_SEQUENCER_CFG2_mem_hib_to_active_ev2_to_ev3_time_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIBANA_SPARE_LOWV register. +// +//****************************************************************************** +#define HIB3P3_HIBANA_SPARE_LOWV_mem_hibana_spare1_M \ + 0xFFC00000 + +#define HIB3P3_HIBANA_SPARE_LOWV_mem_hibana_spare1_S 22 +#define HIB3P3_HIBANA_SPARE_LOWV_mem_hibana_spare0_M \ + 0x0001FFFF + +#define HIB3P3_HIBANA_SPARE_LOWV_mem_hibana_spare0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_TMUX_CTRL register. +// +//****************************************************************************** +#define HIB3P3_HIB_TMUX_CTRL_reserved_M \ + 0xFFFFFC00 + +#define HIB3P3_HIB_TMUX_CTRL_reserved_S 10 +#define HIB3P3_HIB_TMUX_CTRL_mem_hd_tmux_cntrl_M \ + 0x000003FF + +#define HIB3P3_HIB_TMUX_CTRL_mem_hd_tmux_cntrl_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_1P2_1P8_LDO_TRIM register. +// +//****************************************************************************** +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_reserved_M \ + 0xFFFFF000 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_reserved_S 12 +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p2_ldo_en_override_ctrl \ + 0x00000800 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p8_ldo_en_override_ctrl \ + 0x00000400 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p2_ldo_en_override \ + 0x00000200 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p8_ldo_en_override \ + 0x00000100 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p2_ldo_vtrim_M \ + 0x000000F0 + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p2_ldo_vtrim_S 4 +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p8_ldo_vtrim_M \ + 0x0000000F + +#define HIB3P3_HIB_1P2_1P8_LDO_TRIM_mem_hd_1p8_ldo_vtrim_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_COMP_TRIM register. +// +//****************************************************************************** +#define HIB3P3_HIB_COMP_TRIM_reserved_M \ + 0xFFFFFFF8 + +#define HIB3P3_HIB_COMP_TRIM_reserved_S 3 +#define HIB3P3_HIB_COMP_TRIM_mem_hd_comp_trim_M \ + 0x00000007 + +#define HIB3P3_HIB_COMP_TRIM_mem_hd_comp_trim_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_EN_TS register. +// +//****************************************************************************** +#define HIB3P3_HIB_EN_TS_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_HIB_EN_TS_reserved_S 1 +#define HIB3P3_HIB_EN_TS_mem_hd_en_ts \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_1P8V_DET_EN register. +// +//****************************************************************************** +#define HIB3P3_HIB_1P8V_DET_EN_reserved_M \ + 0xFFFFFFFE + +#define HIB3P3_HIB_1P8V_DET_EN_reserved_S 1 +#define HIB3P3_HIB_1P8V_DET_EN_mem_hib_1p8v_det_en \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_VBAT_MON_EN register. +// +//****************************************************************************** +#define HIB3P3_HIB_VBAT_MON_EN_reserved_M \ + 0xFFFFFFFC + +#define HIB3P3_HIB_VBAT_MON_EN_reserved_S 2 +#define HIB3P3_HIB_VBAT_MON_EN_mem_hib_vbat_mon_del_en \ + 0x00000002 + +#define HIB3P3_HIB_VBAT_MON_EN_mem_hib_vbat_mon_en \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_NHIB_ENABLE register. +// +//****************************************************************************** +#define HIB3P3_HIB_NHIB_ENABLE_mem_hib_nhib_enable \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// HIB3P3_O_HIB_UART_RTS_SW_ENABLE register. +// +//****************************************************************************** +#define HIB3P3_HIB_UART_RTS_SW_ENABLE_mem_hib_uart_rts_sw_enable \ + 0x00000001 + + + + +#endif // __HW_HIB3P3_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_i2c.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_i2c.h new file mode 100755 index 0000000..17536d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_i2c.h @@ -0,0 +1,503 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_I2C_H__ +#define __HW_I2C_H__ + +//***************************************************************************** +// +// The following are defines for the I2C register offsets. +// +//***************************************************************************** +#define I2C_O_MSA 0x00000000 +#define I2C_O_MCS 0x00000004 +#define I2C_O_MDR 0x00000008 +#define I2C_O_MTPR 0x0000000C +#define I2C_O_MIMR 0x00000010 +#define I2C_O_MRIS 0x00000014 +#define I2C_O_MMIS 0x00000018 +#define I2C_O_MICR 0x0000001C +#define I2C_O_MCR 0x00000020 +#define I2C_O_MCLKOCNT 0x00000024 +#define I2C_O_MBMON 0x0000002C +#define I2C_O_MBLEN 0x00000030 +#define I2C_O_MBCNT 0x00000034 +#define I2C_O_SOAR 0x00000800 +#define I2C_O_SCSR 0x00000804 +#define I2C_O_SDR 0x00000808 +#define I2C_O_SIMR 0x0000080C +#define I2C_O_SRIS 0x00000810 +#define I2C_O_SMIS 0x00000814 +#define I2C_O_SICR 0x00000818 +#define I2C_O_SOAR2 0x0000081C +#define I2C_O_SACKCTL 0x00000820 +#define I2C_O_FIFODATA 0x00000F00 +#define I2C_O_FIFOCTL 0x00000F04 +#define I2C_O_FIFOSTATUS 0x00000F08 +#define I2C_O_OBSMUXSEL0 0x00000F80 +#define I2C_O_OBSMUXSEL1 0x00000F84 +#define I2C_O_MUXROUTE 0x00000F88 +#define I2C_O_PV 0x00000FB0 +#define I2C_O_PP 0x00000FC0 +#define I2C_O_PC 0x00000FC4 +#define I2C_O_CC 0x00000FC8 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MSA register. +// +//****************************************************************************** +#define I2C_MSA_SA_M 0x000000FE // I2C Slave Address +#define I2C_MSA_SA_S 1 +#define I2C_MSA_RS 0x00000001 // Receive not send +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MCS register. +// +//****************************************************************************** +#define I2C_MCS_ACTDMARX 0x80000000 // DMA RX Active Status +#define I2C_MCS_ACTDMATX 0x40000000 // DMA TX Active Status +#define I2C_MCS_CLKTO 0x00000080 // Clock Timeout Error +#define I2C_MCS_BUSBSY 0x00000040 // Bus Busy +#define I2C_MCS_IDLE 0x00000020 // I2C Idle +#define I2C_MCS_ARBLST 0x00000010 // Arbitration Lost +#define I2C_MCS_ACK 0x00000008 // Data Acknowledge Enable +#define I2C_MCS_ADRACK 0x00000004 // Acknowledge Address +#define I2C_MCS_ERROR 0x00000002 // Error +#define I2C_MCS_BUSY 0x00000001 // I2C Busy +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MDR register. +// +//****************************************************************************** +#define I2C_MDR_DATA_M 0x000000FF // Data Transferred +#define I2C_MDR_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MTPR register. +// +//****************************************************************************** +#define I2C_MTPR_HS 0x00000080 // High-Speed Enable +#define I2C_MTPR_TPR_M 0x0000007F // SCL Clock Period +#define I2C_MTPR_TPR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MIMR register. +// +//****************************************************************************** +#define I2C_MIMR_RXFFIM 0x00000800 // Receive FIFO Full Interrupt Mask +#define I2C_MIMR_TXFEIM 0x00000400 // Transmit FIFO Empty Interrupt + // Mask +#define I2C_MIMR_RXIM 0x00000200 // Receive FIFO Request Interrupt + // Mask +#define I2C_MIMR_TXIM 0x00000100 // Transmit FIFO Request Interrupt + // Mask +#define I2C_MIMR_ARBLOSTIM 0x00000080 // Arbitration Lost Interrupt Mask +#define I2C_MIMR_STOPIM 0x00000040 // STOP Detection Interrupt Mask +#define I2C_MIMR_STARTIM 0x00000020 // START Detection Interrupt Mask +#define I2C_MIMR_NACKIM 0x00000010 // Address/Data NACK Interrupt Mask +#define I2C_MIMR_DMATXIM 0x00000008 // Transmit DMA Interrupt Mask +#define I2C_MIMR_DMARXIM 0x00000004 // Receive DMA Interrupt Mask +#define I2C_MIMR_CLKIM 0x00000002 // Clock Timeout Interrupt Mask +#define I2C_MIMR_IM 0x00000001 // Master Interrupt Mask +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MRIS register. +// +//****************************************************************************** +#define I2C_MRIS_RXFFRIS 0x00000800 // Receive FIFO Full Raw Interrupt + // Status +#define I2C_MRIS_TXFERIS 0x00000400 // Transmit FIFO Empty Raw + // Interrupt Status +#define I2C_MRIS_RXRIS 0x00000200 // Receive FIFO Request Raw + // Interrupt Status +#define I2C_MRIS_TXRIS 0x00000100 // Transmit Request Raw Interrupt + // Status +#define I2C_MRIS_ARBLOSTRIS 0x00000080 // Arbitration Lost Raw Interrupt + // Status +#define I2C_MRIS_STOPRIS 0x00000040 // STOP Detection Raw Interrupt + // Status +#define I2C_MRIS_STARTRIS 0x00000020 // START Detection Raw Interrupt + // Status +#define I2C_MRIS_NACKRIS 0x00000010 // Address/Data NACK Raw Interrupt + // Status +#define I2C_MRIS_DMATXRIS 0x00000008 // Transmit DMA Raw Interrupt + // Status +#define I2C_MRIS_DMARXRIS 0x00000004 // Receive DMA Raw Interrupt Status +#define I2C_MRIS_CLKRIS 0x00000002 // Clock Timeout Raw Interrupt + // Status +#define I2C_MRIS_RIS 0x00000001 // Master Raw Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MMIS register. +// +//****************************************************************************** +#define I2C_MMIS_RXFFMIS 0x00000800 // Receive FIFO Full Interrupt Mask +#define I2C_MMIS_TXFEMIS 0x00000400 // Transmit FIFO Empty Interrupt + // Mask +#define I2C_MMIS_RXMIS 0x00000200 // Receive FIFO Request Interrupt + // Mask +#define I2C_MMIS_TXMIS 0x00000100 // Transmit Request Interrupt Mask +#define I2C_MMIS_ARBLOSTMIS 0x00000080 // Arbitration Lost Interrupt Mask +#define I2C_MMIS_STOPMIS 0x00000040 // STOP Detection Interrupt Mask +#define I2C_MMIS_STARTMIS 0x00000020 // START Detection Interrupt Mask +#define I2C_MMIS_NACKMIS 0x00000010 // Address/Data NACK Interrupt Mask +#define I2C_MMIS_DMATXMIS 0x00000008 // Transmit DMA Interrupt Status +#define I2C_MMIS_DMARXMIS 0x00000004 // Receive DMA Interrupt Status +#define I2C_MMIS_CLKMIS 0x00000002 // Clock Timeout Masked Interrupt + // Status +#define I2C_MMIS_MIS 0x00000001 // Masked Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MICR register. +// +//****************************************************************************** +#define I2C_MICR_RXFFIC 0x00000800 // Receive FIFO Full Interrupt + // Clear +#define I2C_MICR_TXFEIC 0x00000400 // Transmit FIFO Empty Interrupt + // Clear +#define I2C_MICR_RXIC 0x00000200 // Receive FIFO Request Interrupt + // Clear +#define I2C_MICR_TXIC 0x00000100 // Transmit FIFO Request Interrupt + // Clear +#define I2C_MICR_ARBLOSTIC 0x00000080 // Arbitration Lost Interrupt Clear +#define I2C_MICR_STOPIC 0x00000040 // STOP Detection Interrupt Clear +#define I2C_MICR_STARTIC 0x00000020 // START Detection Interrupt Clear +#define I2C_MICR_NACKIC 0x00000010 // Address/Data NACK Interrupt + // Clear +#define I2C_MICR_DMATXIC 0x00000008 // Transmit DMA Interrupt Clear +#define I2C_MICR_DMARXIC 0x00000004 // Receive DMA Interrupt Clear +#define I2C_MICR_CLKIC 0x00000002 // Clock Timeout Interrupt Clear +#define I2C_MICR_IC 0x00000001 // Master Interrupt Clear +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MCR register. +// +//****************************************************************************** +#define I2C_MCR_MMD 0x00000040 // Multi-master Disable +#define I2C_MCR_SFE 0x00000020 // I2C Slave Function Enable +#define I2C_MCR_MFE 0x00000010 // I2C Master Function Enable +#define I2C_MCR_LPBK 0x00000001 // I2C Loopback +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MCLKOCNT register. +// +//****************************************************************************** +#define I2C_MCLKOCNT_CNTL_M 0x000000FF // I2C Master Count +#define I2C_MCLKOCNT_CNTL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MBMON register. +// +//****************************************************************************** +#define I2C_MBMON_SDA 0x00000002 // I2C SDA Status +#define I2C_MBMON_SCL 0x00000001 // I2C SCL Status +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MBLEN register. +// +//****************************************************************************** +#define I2C_MBLEN_CNTL_M 0x000000FF // I2C Burst Length +#define I2C_MBLEN_CNTL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MBCNT register. +// +//****************************************************************************** +#define I2C_MBCNT_CNTL_M 0x000000FF // I2C Master Burst Count +#define I2C_MBCNT_CNTL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SOAR register. +// +//****************************************************************************** +#define I2C_SOAR_OAR_M 0x0000007F // I2C Slave Own Address +#define I2C_SOAR_OAR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SCSR register. +// +//****************************************************************************** +#define I2C_SCSR_ACTDMARX 0x80000000 // DMA RX Active Status +#define I2C_SCSR_ACTDMATX 0x40000000 // DMA TX Active Status +#define I2C_SCSR_QCMDRW 0x00000020 // Quick Command Read / Write +#define I2C_SCSR_QCMDST 0x00000010 // Quick Command Status +#define I2C_SCSR_OAR2SEL 0x00000008 // OAR2 Address Matched +#define I2C_SCSR_FBR 0x00000004 // First Byte Received +#define I2C_SCSR_TREQ 0x00000002 // Transmit Request +#define I2C_SCSR_DA 0x00000001 // Device Active +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SDR register. +// +//****************************************************************************** +#define I2C_SDR_DATA_M 0x000000FF // Data for Transfer +#define I2C_SDR_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SIMR register. +// +//****************************************************************************** +#define I2C_SIMR_IM 0x00000100 // Interrupt Mask +#define I2C_SIMR_TXFEIM 0x00000080 // Transmit FIFO Empty Interrupt + // Mask +#define I2C_SIMR_RXIM 0x00000040 // Receive FIFO Request Interrupt + // Mask +#define I2C_SIMR_TXIM 0x00000020 // Transmit FIFO Request Interrupt + // Mask +#define I2C_SIMR_DMATXIM 0x00000010 // Transmit DMA Interrupt Mask +#define I2C_SIMR_DMARXIM 0x00000008 // Receive DMA Interrupt Mask +#define I2C_SIMR_STOPIM 0x00000004 // Stop Condition Interrupt Mask +#define I2C_SIMR_STARTIM 0x00000002 // Start Condition Interrupt Mask +#define I2C_SIMR_DATAIM 0x00000001 // Data Interrupt Mask +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SRIS register. +// +//****************************************************************************** +#define I2C_SRIS_RIS 0x00000100 // Raw Interrupt Status +#define I2C_SRIS_TXFERIS 0x00000080 // Transmit FIFO Empty Raw + // Interrupt Status +#define I2C_SRIS_RXRIS 0x00000040 // Receive FIFO Request Raw + // Interrupt Status +#define I2C_SRIS_TXRIS 0x00000020 // Transmit Request Raw Interrupt + // Status +#define I2C_SRIS_DMATXRIS 0x00000010 // Transmit DMA Raw Interrupt + // Status +#define I2C_SRIS_DMARXRIS 0x00000008 // Receive DMA Raw Interrupt Status +#define I2C_SRIS_STOPRIS 0x00000004 // Stop Condition Raw Interrupt + // Status +#define I2C_SRIS_STARTRIS 0x00000002 // Start Condition Raw Interrupt + // Status +#define I2C_SRIS_DATARIS 0x00000001 // Data Raw Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SMIS register. +// +//****************************************************************************** +#define I2C_SMIS_RXFFMIS 0x00000100 // Receive FIFO Full Interrupt Mask +#define I2C_SMIS_TXFEMIS 0x00000080 // Transmit FIFO Empty Interrupt + // Mask +#define I2C_SMIS_RXMIS 0x00000040 // Receive FIFO Request Interrupt + // Mask +#define I2C_SMIS_TXMIS 0x00000020 // Transmit FIFO Request Interrupt + // Mask +#define I2C_SMIS_DMATXMIS 0x00000010 // Transmit DMA Masked Interrupt + // Status +#define I2C_SMIS_DMARXMIS 0x00000008 // Receive DMA Masked Interrupt + // Status +#define I2C_SMIS_STOPMIS 0x00000004 // Stop Condition Masked Interrupt + // Status +#define I2C_SMIS_STARTMIS 0x00000002 // Start Condition Masked Interrupt + // Status +#define I2C_SMIS_DATAMIS 0x00000001 // Data Masked Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SICR register. +// +//****************************************************************************** +#define I2C_SICR_RXFFIC 0x00000100 // Receive FIFO Full Interrupt Mask +#define I2C_SICR_TXFEIC 0x00000080 // Transmit FIFO Empty Interrupt + // Mask +#define I2C_SICR_RXIC 0x00000040 // Receive Request Interrupt Mask +#define I2C_SICR_TXIC 0x00000020 // Transmit Request Interrupt Mask +#define I2C_SICR_DMATXIC 0x00000010 // Transmit DMA Interrupt Clear +#define I2C_SICR_DMARXIC 0x00000008 // Receive DMA Interrupt Clear +#define I2C_SICR_STOPIC 0x00000004 // Stop Condition Interrupt Clear +#define I2C_SICR_STARTIC 0x00000002 // Start Condition Interrupt Clear +#define I2C_SICR_DATAIC 0x00000001 // Data Interrupt Clear +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SOAR2 register. +// +//****************************************************************************** +#define I2C_SOAR2_OAR2EN 0x00000080 // I2C Slave Own Address 2 Enable +#define I2C_SOAR2_OAR2_M 0x0000007F // I2C Slave Own Address 2 +#define I2C_SOAR2_OAR2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_SACKCTL register. +// +//****************************************************************************** +#define I2C_SACKCTL_ACKOVAL 0x00000002 // I2C Slave ACK Override Value +#define I2C_SACKCTL_ACKOEN 0x00000001 // I2C Slave ACK Override Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_FIFODATA register. +// +//****************************************************************************** +#define I2C_FIFODATA_DATA_M 0x000000FF // I2C FIFO Data Byte +#define I2C_FIFODATA_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_FIFOCTL register. +// +//****************************************************************************** +#define I2C_FIFOCTL_RXASGNMT 0x80000000 // RX Control Assignment +#define I2C_FIFOCTL_RXFLUSH 0x40000000 // RX FIFO Flush +#define I2C_FIFOCTL_DMARXENA 0x20000000 // DMA RX Channel Enable +#define I2C_FIFOCTL_RXTRIG_M 0x00070000 // RX FIFO Trigger +#define I2C_FIFOCTL_RXTRIG_S 16 +#define I2C_FIFOCTL_TXASGNMT 0x00008000 // TX Control Assignment +#define I2C_FIFOCTL_TXFLUSH 0x00004000 // TX FIFO Flush +#define I2C_FIFOCTL_DMATXENA 0x00002000 // DMA TX Channel Enable +#define I2C_FIFOCTL_TXTRIG_M 0x00000007 // TX FIFO Trigger +#define I2C_FIFOCTL_TXTRIG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_FIFOSTATUS register. +// +//****************************************************************************** +#define I2C_FIFOSTATUS_RXABVTRIG \ + 0x00040000 // RX FIFO Above Trigger Level + +#define I2C_FIFOSTATUS_RXFF 0x00020000 // RX FIFO Full +#define I2C_FIFOSTATUS_RXFE 0x00010000 // RX FIFO Empty +#define I2C_FIFOSTATUS_TXBLWTRIG \ + 0x00000004 // TX FIFO Below Trigger Level + +#define I2C_FIFOSTATUS_TXFF 0x00000002 // TX FIFO Full +#define I2C_FIFOSTATUS_TXFE 0x00000001 // TX FIFO Empty +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_OBSMUXSEL0 register. +// +//****************************************************************************** +#define I2C_OBSMUXSEL0_LN3_M 0x07000000 // Observation Mux Lane 3 +#define I2C_OBSMUXSEL0_LN3_S 24 +#define I2C_OBSMUXSEL0_LN2_M 0x00070000 // Observation Mux Lane 2 +#define I2C_OBSMUXSEL0_LN2_S 16 +#define I2C_OBSMUXSEL0_LN1_M 0x00000700 // Observation Mux Lane 1 +#define I2C_OBSMUXSEL0_LN1_S 8 +#define I2C_OBSMUXSEL0_LN0_M 0x00000007 // Observation Mux Lane 0 +#define I2C_OBSMUXSEL0_LN0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_OBSMUXSEL1 register. +// +//****************************************************************************** +#define I2C_OBSMUXSEL1_LN7_M 0x07000000 // Observation Mux Lane 7 +#define I2C_OBSMUXSEL1_LN7_S 24 +#define I2C_OBSMUXSEL1_LN6_M 0x00070000 // Observation Mux Lane 6 +#define I2C_OBSMUXSEL1_LN6_S 16 +#define I2C_OBSMUXSEL1_LN5_M 0x00000700 // Observation Mux Lane 5 +#define I2C_OBSMUXSEL1_LN5_S 8 +#define I2C_OBSMUXSEL1_LN4_M 0x00000007 // Observation Mux Lane 4 +#define I2C_OBSMUXSEL1_LN4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_MUXROUTE register. +// +//****************************************************************************** +#define I2C_MUXROUTE_LN7ROUTE_M \ + 0x70000000 // Lane 7 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN7ROUTE_S 28 +#define I2C_MUXROUTE_LN6ROUTE_M \ + 0x07000000 // Lane 6 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN6ROUTE_S 24 +#define I2C_MUXROUTE_LN5ROUTE_M \ + 0x00700000 // Lane 5 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN5ROUTE_S 20 +#define I2C_MUXROUTE_LN4ROUTE_M \ + 0x00070000 // Lane 4 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN4ROUTE_S 16 +#define I2C_MUXROUTE_LN3ROUTE_M \ + 0x00007000 // Lane 3 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN3ROUTE_S 12 +#define I2C_MUXROUTE_LN2ROUTE_M \ + 0x00000700 // Lane 2 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN2ROUTE_S 8 +#define I2C_MUXROUTE_LN1ROUTE_M \ + 0x00000070 // Lane 1 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN1ROUTE_S 4 +#define I2C_MUXROUTE_LN0ROUTE_M \ + 0x00000007 // Lane 0 output is routed to the + // lane pointed to by the offset in + // this bit field + +#define I2C_MUXROUTE_LN0ROUTE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_PV register. +// +//****************************************************************************** +#define I2C_PV_MAJOR_M 0x0000FF00 // Major Revision +#define I2C_PV_MAJOR_S 8 +#define I2C_PV_MINOR_M 0x000000FF // Minor Revision +#define I2C_PV_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_PP register. +// +//****************************************************************************** +#define I2C_PP_HS 0x00000001 // High-Speed Capable +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_PC register. +// +//****************************************************************************** +#define I2C_PC_HS 0x00000001 // High-Speed Capable +//****************************************************************************** +// +// The following are defines for the bit fields in the I2C_O_CC register. +// +//****************************************************************************** + + + +#endif // __HW_I2C_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ints.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ints.h new file mode 100755 index 0000000..6b40193 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ints.h @@ -0,0 +1,117 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +// hw_ints.h - Macros that define the interrupt assignment on CC3200. +// +//***************************************************************************** + +#ifndef __HW_INTS_H__ +#define __HW_INTS_H__ + +//***************************************************************************** +// +// The following are defines for the fault assignments. +// +//***************************************************************************** +#define FAULT_NMI 2 // NMI fault +#define FAULT_HARD 3 // Hard fault +#define FAULT_MPU 4 // MPU fault +#define FAULT_BUS 5 // Bus fault +#define FAULT_USAGE 6 // Usage fault +#define FAULT_SVCALL 11 // SVCall +#define FAULT_DEBUG 12 // Debug monitor +#define FAULT_PENDSV 14 // PendSV +#define FAULT_SYSTICK 15 // System Tick + +//***************************************************************************** +// +// The following are defines for the interrupt assignments. +// +//***************************************************************************** +#define INT_GPIOA0 16 // GPIO Port S0 +#define INT_GPIOA1 17 // GPIO Port S1 +#define INT_GPIOA2 18 // GPIO Port S2 +#define INT_GPIOA3 19 // GPIO Port S3 +#define INT_UARTA0 21 // UART0 Rx and Tx +#define INT_UARTA1 22 // UART1 Rx and Tx +#define INT_I2CA0 24 // I2C controller +#define INT_ADCCH0 30 // ADC Sequence 0 +#define INT_ADCCH1 31 // ADC Sequence 1 +#define INT_ADCCH2 32 // ADC Sequence 2 +#define INT_ADCCH3 33 // ADC Sequence 3 +#define INT_WDT 34 // Watchdog Timer0 +#define INT_TIMERA0A 35 // Timer 0 subtimer A +#define INT_TIMERA0B 36 // Timer 0 subtimer B +#define INT_TIMERA1A 37 // Timer 1 subtimer A +#define INT_TIMERA1B 38 // Timer 1 subtimer B +#define INT_TIMERA2A 39 // Timer 2 subtimer A +#define INT_TIMERA2B 40 // Timer 2 subtimer B +#define INT_FLASH 45 // FLASH Control +#define INT_TIMERA3A 51 // Timer 3 subtimer A +#define INT_TIMERA3B 52 // Timer 3 subtimer B +#define INT_UDMA 62 // uDMA controller +#define INT_UDMAERR 63 // uDMA Error +#define INT_SHA 164 // SHA +#define INT_AES 167 // AES +#define INT_DES 169 // DES +#define INT_MMCHS 175 // SDIO +#define INT_I2S 177 // McAPS +#define INT_CAMERA 179 // Camera +#define INT_NWPIC 187 // Interprocessor communication +#define INT_PRCM 188 // Power, Reset and Clock Module +#define INT_SSPI 191 // Shared SPI +#define INT_GSPI 192 // Generic SPI +#define INT_LSPI 193 // Link SPI + +//***************************************************************************** +// +// The following are defines for the total number of interrupts. +// +//***************************************************************************** +#define NUM_INTERRUPTS 195 //The above number plus 2? + + +//***************************************************************************** +// +// The following are defines for the total number of priority levels. +// +//***************************************************************************** +#define NUM_PRIORITY 8 +#define NUM_PRIORITY_BITS 3 + + +#endif // __HW_INTS_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcasp.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcasp.h new file mode 100755 index 0000000..c27a007 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcasp.h @@ -0,0 +1,1706 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_MCASP_H__ +#define __HW_MCASP_H__ + +//***************************************************************************** +// +// The following are defines for the MCASP register offsets. +// +//***************************************************************************** +#define MCASP_O_PID 0x00000000 +#define MCASP_O_ESYSCONFIG 0x00000004 // Power Idle SYSCONFIG register. +#define MCASP_O_PFUNC 0x00000010 +#define MCASP_O_PDIR 0x00000014 +#define MCASP_O_PDOUT 0x00000018 +#define MCASP_O_PDSET 0x0000001C // The pin data set register + // (PDSET) is an alias of the pin + // data output register (PDOUT) for + // writes only. Writing a 1 to the + // PDSET bit sets the corresponding + // bit in PDOUT and if PFUNC = 1 + // (GPIO function) and PDIR = 1 + // (output) drives a logic high on + // the pin. +#define MCASP_O_PDIN 0x0000001C // The pin data input register + // (PDIN) holds the I/O pin state of + // each of the McASP pins. PDIN + // allows the actual value of the + // pin to be read regardless of the + // state of PFUNC and PDIR. +#define MCASP_O_PDCLR 0x00000020 // The pin data clear register + // (PDCLR) is an alias of the pin + // data output register (PDOUT) for + // writes only. Writing a 1 to the + // PDCLR bit clears the + // corresponding bit in PDOUT and if + // PFUNC = 1 (GPIO function) and + // PDIR = 1 (output) drives a logic + // low on the pin. +#define MCASP_O_TLGC 0x00000030 // for IODFT +#define MCASP_O_TLMR 0x00000034 // for IODFT +#define MCASP_O_TLEC 0x00000038 // for IODFT +#define MCASP_O_GBLCTL 0x00000044 +#define MCASP_O_AMUTE 0x00000048 +#define MCASP_O_LBCTL 0x0000004C +#define MCASP_O_TXDITCTL 0x00000050 +#define MCASP_O_GBLCTLR 0x00000060 +#define MCASP_O_RXMASK 0x00000064 +#define MCASP_O_RXFMT 0x00000068 +#define MCASP_O_RXFMCTL 0x0000006C +#define MCASP_O_ACLKRCTL 0x00000070 +#define MCASP_O_AHCLKRCTL 0x00000074 +#define MCASP_O_RXTDM 0x00000078 +#define MCASP_O_EVTCTLR 0x0000007C +#define MCASP_O_RXSTAT 0x00000080 +#define MCASP_O_RXTDMSLOT 0x00000084 +#define MCASP_O_RXCLKCHK 0x00000088 +#define MCASP_O_REVTCTL 0x0000008C +#define MCASP_O_GBLCTLX 0x000000A0 +#define MCASP_O_TXMASK 0x000000A4 +#define MCASP_O_TXFMT 0x000000A8 +#define MCASP_O_TXFMCTL 0x000000AC +#define MCASP_O_ACLKXCTL 0x000000B0 +#define MCASP_O_AHCLKXCTL 0x000000B4 +#define MCASP_O_TXTDM 0x000000B8 +#define MCASP_O_EVTCTLX 0x000000BC +#define MCASP_O_TXSTAT 0x000000C0 +#define MCASP_O_TXTDMSLOT 0x000000C4 +#define MCASP_O_TXCLKCHK 0x000000C8 +#define MCASP_O_XEVTCTL 0x000000CC +#define MCASP_O_CLKADJEN 0x000000D0 +#define MCASP_O_DITCSRA0 0x00000100 +#define MCASP_O_DITCSRA1 0x00000104 +#define MCASP_O_DITCSRA2 0x00000108 +#define MCASP_O_DITCSRA3 0x0000010C +#define MCASP_O_DITCSRA4 0x00000110 +#define MCASP_O_DITCSRA5 0x00000114 +#define MCASP_O_DITCSRB0 0x00000118 +#define MCASP_O_DITCSRB1 0x0000011C +#define MCASP_O_DITCSRB2 0x00000120 +#define MCASP_O_DITCSRB3 0x00000124 +#define MCASP_O_DITCSRB4 0x00000128 +#define MCASP_O_DITCSRB5 0x0000012C +#define MCASP_O_DITUDRA0 0x00000130 +#define MCASP_O_DITUDRA1 0x00000134 +#define MCASP_O_DITUDRA2 0x00000138 +#define MCASP_O_DITUDRA3 0x0000013C +#define MCASP_O_DITUDRA4 0x00000140 +#define MCASP_O_DITUDRA5 0x00000144 +#define MCASP_O_DITUDRB0 0x00000148 +#define MCASP_O_DITUDRB1 0x0000014C +#define MCASP_O_DITUDRB2 0x00000150 +#define MCASP_O_DITUDRB3 0x00000154 +#define MCASP_O_DITUDRB4 0x00000158 +#define MCASP_O_DITUDRB5 0x0000015C +#define MCASP_O_XRSRCTL0 0x00000180 +#define MCASP_O_XRSRCTL1 0x00000184 +#define MCASP_O_XRSRCTL2 0x00000188 +#define MCASP_O_XRSRCTL3 0x0000018C +#define MCASP_O_XRSRCTL4 0x00000190 +#define MCASP_O_XRSRCTL5 0x00000194 +#define MCASP_O_XRSRCTL6 0x00000198 +#define MCASP_O_XRSRCTL7 0x0000019C +#define MCASP_O_XRSRCTL8 0x000001A0 +#define MCASP_O_XRSRCTL9 0x000001A4 +#define MCASP_O_XRSRCTL10 0x000001A8 +#define MCASP_O_XRSRCTL11 0x000001AC +#define MCASP_O_XRSRCTL12 0x000001B0 +#define MCASP_O_XRSRCTL13 0x000001B4 +#define MCASP_O_XRSRCTL14 0x000001B8 +#define MCASP_O_XRSRCTL15 0x000001BC +#define MCASP_O_TXBUF0 0x00000200 +#define MCASP_O_TXBUF1 0x00000204 +#define MCASP_O_TXBUF2 0x00000208 +#define MCASP_O_TXBUF3 0x0000020C +#define MCASP_O_TXBUF4 0x00000210 +#define MCASP_O_TXBUF5 0x00000214 +#define MCASP_O_TXBUF6 0x00000218 +#define MCASP_O_TXBUF7 0x0000021C +#define MCASP_O_TXBUF8 0x00000220 +#define MCASP_O_TXBUF9 0x00000224 +#define MCASP_O_TXBUF10 0x00000228 +#define MCASP_O_TXBUF11 0x0000022C +#define MCASP_O_TXBUF12 0x00000230 +#define MCASP_O_TXBUF13 0x00000234 +#define MCASP_O_TXBUF14 0x00000238 +#define MCASP_O_TXBUF15 0x0000023C +#define MCASP_O_RXBUF0 0x00000280 +#define MCASP_O_RXBUF1 0x00000284 +#define MCASP_O_RXBUF2 0x00000288 +#define MCASP_O_RXBUF3 0x0000028C +#define MCASP_O_RXBUF4 0x00000290 +#define MCASP_O_RXBUF5 0x00000294 +#define MCASP_O_RXBUF6 0x00000298 +#define MCASP_O_RXBUF7 0x0000029C +#define MCASP_O_RXBUF8 0x000002A0 +#define MCASP_O_RXBUF9 0x000002A4 +#define MCASP_O_RXBUF10 0x000002A8 +#define MCASP_O_RXBUF11 0x000002AC +#define MCASP_O_RXBUF12 0x000002B0 +#define MCASP_O_RXBUF13 0x000002B4 +#define MCASP_O_RXBUF14 0x000002B8 +#define MCASP_O_RXBUF15 0x000002BC +#define MCASP_0_WFIFOCTL 0x00001000 +#define MCASP_0_WFIFOSTS 0x00001004 +#define MCASP_0_RFIFOCTL 0x00001008 +#define MCASP_0_RFIFOSTS 0x0000100C + + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PID register. +// +//****************************************************************************** +#define MCASP_PID_SCHEME_M 0xC0000000 +#define MCASP_PID_SCHEME_S 30 +#define MCASP_PID_RESV_M 0x30000000 +#define MCASP_PID_RESV_S 28 +#define MCASP_PID_FUNCTION_M 0x0FFF0000 // McASP +#define MCASP_PID_FUNCTION_S 16 +#define MCASP_PID_RTL_M 0x0000F800 +#define MCASP_PID_RTL_S 11 +#define MCASP_PID_REVMAJOR_M 0x00000700 +#define MCASP_PID_REVMAJOR_S 8 +#define MCASP_PID_CUSTOM_M 0x000000C0 // non-custom +#define MCASP_PID_CUSTOM_S 6 +#define MCASP_PID_REVMINOR_M 0x0000003F +#define MCASP_PID_REVMINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// MCASP_O_ESYSCONFIG register. +// +//****************************************************************************** +#define MCASP_ESYSCONFIG_RSV_M 0xFFFFFFC0 // Reserved as per PDR 3.5 +#define MCASP_ESYSCONFIG_RSV_S 6 +#define MCASP_ESYSCONFIG_OTHER_M \ + 0x0000003C // Reserved for future expansion + +#define MCASP_ESYSCONFIG_OTHER_S 2 +#define MCASP_ESYSCONFIG_IDLE_MODE_M \ + 0x00000003 // Idle Mode + +#define MCASP_ESYSCONFIG_IDLE_MODE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PFUNC register. +// +//****************************************************************************** +#define MCASP_PFUNC_AFSR 0x80000000 // AFSR PFUNC 31 0 1 +#define MCASP_PFUNC_AHCLKR 0x40000000 // AHCLKR PFUNC 30 0 1 +#define MCASP_PFUNC_ACLKR 0x20000000 // ACLKR PFUNC 29 0 1 +#define MCASP_PFUNC_AFSX 0x10000000 // AFSX PFUNC 28 0 1 +#define MCASP_PFUNC_AHCLKX 0x08000000 // AHCLKX PFUNC 27 0 1 +#define MCASP_PFUNC_ACLKX 0x04000000 // ACLKX PFUNC 26 0 1 +#define MCASP_PFUNC_AMUTE 0x02000000 // AMUTE PFUNC 25 0 1 +#define MCASP_PFUNC_RESV1_M 0x01FF0000 // Reserved +#define MCASP_PFUNC_RESV1_S 16 +#define MCASP_PFUNC_AXR15 0x00008000 // AXR PFUNC BIT 15 0 1 +#define MCASP_PFUNC_AXR14 0x00004000 // AXR PFUNC BIT 14 0 1 +#define MCASP_PFUNC_AXR13 0x00002000 // AXR PFUNC BIT 13 0 1 +#define MCASP_PFUNC_AXR12 0x00001000 // AXR PFUNC BIT 12 0 1 +#define MCASP_PFUNC_AXR11 0x00000800 // AXR PFUNC BIT 11 0 1 +#define MCASP_PFUNC_AXR10 0x00000400 // AXR PFUNC BIT 10 0 1 +#define MCASP_PFUNC_AXR9 0x00000200 // AXR PFUNC BIT 9 0 1 +#define MCASP_PFUNC_AXR8 0x00000100 // AXR PFUNC BIT 8 0 1 +#define MCASP_PFUNC_AXR7 0x00000080 // AXR PFUNC BIT 7 0 1 +#define MCASP_PFUNC_AXR6 0x00000040 // AXR PFUNC BIT 6 0 1 +#define MCASP_PFUNC_AXR5 0x00000020 // AXR PFUNC BIT 5 0 1 +#define MCASP_PFUNC_AXR4 0x00000010 // AXR PFUNC BIT 4 0 1 +#define MCASP_PFUNC_AXR3 0x00000008 // AXR PFUNC BIT 3 0 1 +#define MCASP_PFUNC_AXR2 0x00000004 // AXR PFUNC BIT 2 0 1 +#define MCASP_PFUNC_AXR1 0x00000002 // AXR PFUNC BIT 1 0 1 +#define MCASP_PFUNC_AXR0 0x00000001 // AXR PFUNC BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PDIR register. +// +//****************************************************************************** +#define MCASP_PDIR_AFSR 0x80000000 // AFSR PDIR 31 0 1 +#define MCASP_PDIR_AHCLKR 0x40000000 // AHCLKR PDIR 30 0 1 +#define MCASP_PDIR_ACLKR 0x20000000 // ACLKR PDIR 29 0 1 +#define MCASP_PDIR_AFSX 0x10000000 // AFSX PDIR 28 0 1 +#define MCASP_PDIR_AHCLKX 0x08000000 // AHCLKX PDIR 27 0 1 +#define MCASP_PDIR_ACLKX 0x04000000 // ACLKX PDIR 26 0 1 +#define MCASP_PDIR_AMUTE 0x02000000 // AMUTE PDIR 25 0 1 +#define MCASP_PDIR_RESV_M 0x01FF0000 // Reserved +#define MCASP_PDIR_RESV_S 16 +#define MCASP_PDIR_AXR15 0x00008000 // AXR PDIR BIT 15 0 1 +#define MCASP_PDIR_AXR14 0x00004000 // AXR PDIR BIT 14 0 1 +#define MCASP_PDIR_AXR13 0x00002000 // AXR PDIR BIT 13 0 1 +#define MCASP_PDIR_AXR12 0x00001000 // AXR PDIR BIT 12 0 1 +#define MCASP_PDIR_AXR11 0x00000800 // AXR PDIR BIT 11 0 1 +#define MCASP_PDIR_AXR10 0x00000400 // AXR PDIR BIT 10 0 1 +#define MCASP_PDIR_AXR9 0x00000200 // AXR PDIR BIT 9 0 1 +#define MCASP_PDIR_AXR8 0x00000100 // AXR PDIR BIT 8 0 1 +#define MCASP_PDIR_AXR7 0x00000080 // AXR PDIR BIT 7 0 1 +#define MCASP_PDIR_AXR6 0x00000040 // AXR PDIR BIT 6 0 1 +#define MCASP_PDIR_AXR5 0x00000020 // AXR PDIR BIT 5 0 1 +#define MCASP_PDIR_AXR4 0x00000010 // AXR PDIR BIT 4 0 1 +#define MCASP_PDIR_AXR3 0x00000008 // AXR PDIR BIT 3 0 1 +#define MCASP_PDIR_AXR2 0x00000004 // AXR PDIR BIT 2 0 1 +#define MCASP_PDIR_AXR1 0x00000002 // AXR PDIR BIT 1 0 1 +#define MCASP_PDIR_AXR0 0x00000001 // AXR PDIR BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PDOUT register. +// +//****************************************************************************** +#define MCASP_PDOUT_AFSR 0x80000000 // AFSR PDOUT 31 0 1 +#define MCASP_PDOUT_AHCLKR 0x40000000 // AHCLKR PDOUT 30 0 1 +#define MCASP_PDOUT_ACLKR 0x20000000 // ACLKR PDOUT 29 0 1 +#define MCASP_PDOUT_AFSX 0x10000000 // AFSX PDOUT 28 0 1 +#define MCASP_PDOUT_AHCLKX 0x08000000 // AHCLKX PDOUT 27 0 1 +#define MCASP_PDOUT_ACLKX 0x04000000 // ACLKX PDOUT 26 0 1 +#define MCASP_PDOUT_AMUTE 0x02000000 // AMUTE PDOUT 25 0 1 +#define MCASP_PDOUT_RESV_M 0x01FF0000 // Reserved +#define MCASP_PDOUT_RESV_S 16 +#define MCASP_PDOUT_AXR15 0x00008000 // AXR PDOUT BIT 15 0 1 +#define MCASP_PDOUT_AXR14 0x00004000 // AXR PDOUT BIT 14 0 1 +#define MCASP_PDOUT_AXR13 0x00002000 // AXR PDOUT BIT 13 0 1 +#define MCASP_PDOUT_AXR12 0x00001000 // AXR PDOUT BIT 12 0 1 +#define MCASP_PDOUT_AXR11 0x00000800 // AXR PDOUT BIT 11 0 1 +#define MCASP_PDOUT_AXR10 0x00000400 // AXR PDOUT BIT 10 0 1 +#define MCASP_PDOUT_AXR9 0x00000200 // AXR PDOUT BIT 9 0 1 +#define MCASP_PDOUT_AXR8 0x00000100 // AXR PDOUT BIT 8 0 1 +#define MCASP_PDOUT_AXR7 0x00000080 // AXR PDOUT BIT 7 0 1 +#define MCASP_PDOUT_AXR6 0x00000040 // AXR PDOUT BIT 6 0 1 +#define MCASP_PDOUT_AXR5 0x00000020 // AXR PDOUT BIT 5 0 1 +#define MCASP_PDOUT_AXR4 0x00000010 // AXR PDOUT BIT 4 0 1 +#define MCASP_PDOUT_AXR3 0x00000008 // AXR PDOUT BIT 3 0 1 +#define MCASP_PDOUT_AXR2 0x00000004 // AXR PDOUT BIT 2 0 1 +#define MCASP_PDOUT_AXR1 0x00000002 // AXR PDOUT BIT 1 0 1 +#define MCASP_PDOUT_AXR0 0x00000001 // AXR PDOUT BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PDSET register. +// +//****************************************************************************** +#define MCASP_PDSET_AFSR 0x80000000 +#define MCASP_PDSET_AHCLKR 0x40000000 +#define MCASP_PDSET_ACLKR 0x20000000 +#define MCASP_PDSET_AFSX 0x10000000 +#define MCASP_PDSET_AHCLKX 0x08000000 +#define MCASP_PDSET_ACLKX 0x04000000 +#define MCASP_PDSET_AMUTE 0x02000000 +#define MCASP_PDSET_RESV_M 0x01FF0000 // Reserved +#define MCASP_PDSET_RESV_S 16 +#define MCASP_PDSET_AXR15 0x00008000 +#define MCASP_PDSET_AXR14 0x00004000 +#define MCASP_PDSET_AXR13 0x00002000 +#define MCASP_PDSET_AXR12 0x00001000 +#define MCASP_PDSET_AXR11 0x00000800 +#define MCASP_PDSET_AXR10 0x00000400 +#define MCASP_PDSET_AXR9 0x00000200 +#define MCASP_PDSET_AXR8 0x00000100 +#define MCASP_PDSET_AXR7 0x00000080 +#define MCASP_PDSET_AXR6 0x00000040 +#define MCASP_PDSET_AXR5 0x00000020 +#define MCASP_PDSET_AXR4 0x00000010 +#define MCASP_PDSET_AXR3 0x00000008 +#define MCASP_PDSET_AXR2 0x00000004 +#define MCASP_PDSET_AXR1 0x00000002 +#define MCASP_PDSET_AXR0 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PDIN register. +// +//****************************************************************************** +#define MCASP_PDIN_AFSR 0x80000000 +#define MCASP_PDIN_AHCLKR 0x40000000 +#define MCASP_PDIN_ACLKR 0x20000000 +#define MCASP_PDIN_AFSX 0x10000000 +#define MCASP_PDIN_AHCLKX 0x08000000 +#define MCASP_PDIN_ACLKX 0x04000000 +#define MCASP_PDIN_AMUTE 0x02000000 +#define MCASP_PDIN_RESV_M 0x01FF0000 // Reserved +#define MCASP_PDIN_RESV_S 16 +#define MCASP_PDIN_AXR15 0x00008000 +#define MCASP_PDIN_AXR14 0x00004000 +#define MCASP_PDIN_AXR13 0x00002000 +#define MCASP_PDIN_AXR12 0x00001000 +#define MCASP_PDIN_AXR11 0x00000800 +#define MCASP_PDIN_AXR10 0x00000400 +#define MCASP_PDIN_AXR9 0x00000200 +#define MCASP_PDIN_AXR8 0x00000100 +#define MCASP_PDIN_AXR7 0x00000080 +#define MCASP_PDIN_AXR6 0x00000040 +#define MCASP_PDIN_AXR5 0x00000020 +#define MCASP_PDIN_AXR4 0x00000010 +#define MCASP_PDIN_AXR3 0x00000008 +#define MCASP_PDIN_AXR2 0x00000004 +#define MCASP_PDIN_AXR1 0x00000002 +#define MCASP_PDIN_AXR0 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_PDCLR register. +// +//****************************************************************************** +#define MCASP_PDCLR_AFSR 0x80000000 // AFSR PDCLR 31 0 1 +#define MCASP_PDCLR_AHCLKR 0x40000000 // AHCLKR PDCLR 30 0 1 +#define MCASP_PDCLR_ACLKR 0x20000000 // ACLKR PDCLR 29 0 1 +#define MCASP_PDCLR_AFSX 0x10000000 // AFSX PDCLR 28 0 1 +#define MCASP_PDCLR_AHCLKX 0x08000000 // AHCLKX PDCLR 27 0 1 +#define MCASP_PDCLR_ACLKX 0x04000000 // ACLKX PDCLR 26 0 1 +#define MCASP_PDCLR_AMUTE 0x02000000 // AMUTE PDCLR 25 0 1 +#define MCASP_PDCLR_RESV_M 0x01FF0000 // Reserved +#define MCASP_PDCLR_RESV_S 16 +#define MCASP_PDCLR_AXR15 0x00008000 // AXR PDCLR BIT 15 0 1 +#define MCASP_PDCLR_AXR14 0x00004000 // AXR PDCLR BIT 14 0 1 +#define MCASP_PDCLR_AXR13 0x00002000 // AXR PDCLR BIT 13 0 1 +#define MCASP_PDCLR_AXR12 0x00001000 // AXR PDCLR BIT 12 0 1 +#define MCASP_PDCLR_AXR11 0x00000800 // AXR PDCLR BIT 11 0 1 +#define MCASP_PDCLR_AXR10 0x00000400 // AXR PDCLR BIT 10 0 1 +#define MCASP_PDCLR_AXR9 0x00000200 // AXR PDCLR BIT 9 0 1 +#define MCASP_PDCLR_AXR8 0x00000100 // AXR PDCLR BIT 8 0 1 +#define MCASP_PDCLR_AXR7 0x00000080 // AXR PDCLR BIT 7 0 1 +#define MCASP_PDCLR_AXR6 0x00000040 // AXR PDCLR BIT 6 0 1 +#define MCASP_PDCLR_AXR5 0x00000020 // AXR PDCLR BIT 5 0 1 +#define MCASP_PDCLR_AXR4 0x00000010 // AXR PDCLR BIT 4 0 1 +#define MCASP_PDCLR_AXR3 0x00000008 // AXR PDCLR BIT 3 0 1 +#define MCASP_PDCLR_AXR2 0x00000004 // AXR PDCLR BIT 2 0 1 +#define MCASP_PDCLR_AXR1 0x00000002 // AXR PDCLR BIT 1 0 1 +#define MCASP_PDCLR_AXR0 0x00000001 // AXR PDCLR BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TLGC register. +// +//****************************************************************************** +#define MCASP_TLGC_RESV_M 0xFFFF0000 // Reserved +#define MCASP_TLGC_RESV_S 16 +#define MCASP_TLGC_MT_M 0x0000C000 // MISR on/off trigger command 0x0 + // 0x1 0x2 0x3 +#define MCASP_TLGC_MT_S 14 +#define MCASP_TLGC_RESV1_M 0x00003E00 // Reserved +#define MCASP_TLGC_RESV1_S 9 +#define MCASP_TLGC_MMS 0x00000100 // Source of MISR input 0 1 +#define MCASP_TLGC_ESEL 0x00000080 // Output enable select 0 1 +#define MCASP_TLGC_TOEN 0x00000040 // Test output enable control. 0 1 +#define MCASP_TLGC_MC_M 0x00000030 // States of MISR 0x0 0x1 0x2 0x3 +#define MCASP_TLGC_MC_S 4 +#define MCASP_TLGC_PC_M 0x0000000E // Pattern code 0x0 0x1 0x2 0x3 0x4 + // 0x5 0x6 0x7 +#define MCASP_TLGC_PC_S 1 +#define MCASP_TLGC_TM 0x00000001 // Tie high; do not write to this + // bit 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TLMR register. +// +//****************************************************************************** +#define MCASP_TLMR_TLMR_M 0xFFFFFFFF // Contains test result signature. +#define MCASP_TLMR_TLMR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TLEC register. +// +//****************************************************************************** +#define MCASP_TLEC_TLEC_M 0xFFFFFFFF // Contains number of cycles during + // which MISR sig will be + // accumulated. +#define MCASP_TLEC_TLEC_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_GBLCTL register. +// +//****************************************************************************** +#define MCASP_GBLCTL_XFRST 0x00001000 // Frame sync generator reset 0 1 +#define MCASP_GBLCTL_XSMRST 0x00000800 // XMT state machine reset 0 1 +#define MCASP_GBLCTL_XSRCLR 0x00000400 // XMT serializer clear 0 1 +#define MCASP_GBLCTL_XHCLKRST 0x00000200 // XMT High Freq. clk Divider 0 1 +#define MCASP_GBLCTL_XCLKRST 0x00000100 // XMT clock divder reset 0 1 +#define MCASP_GBLCTL_RFRST 0x00000010 // Frame sync generator reset 0 1 +#define MCASP_GBLCTL_RSMRST 0x00000008 // RCV state machine reset 0 1 +#define MCASP_GBLCTL_RSRCLR 0x00000004 // RCV serializer clear 0 1 +#define MCASP_GBLCTL_RHCLKRST 0x00000002 // RCV High Freq. clk Divider 0 1 +#define MCASP_GBLCTL_RCLKRST 0x00000001 // RCV clock divder reset 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_AMUTE register. +// +//****************************************************************************** +#define MCASP_AMUTE_XDMAERR 0x00001000 // MUTETXDMAERR occur 0 1 +#define MCASP_AMUTE_RDMAERR 0x00000800 // MUTERXDMAERR occur 0 1 +#define MCASP_AMUTE_XCKFAIL 0x00000400 // XMT bad clock 0 1 +#define MCASP_AMUTE_RCKFAIL 0x00000200 // RCV bad clock 0 1 +#define MCASP_AMUTE_XSYNCERR 0x00000100 // XMT unexpected FS 0 1 +#define MCASP_AMUTE_RSYNCERR 0x00000080 // RCV unexpected FS 0 1 +#define MCASP_AMUTE_XUNDRN 0x00000040 // XMT underrun occurs 0 1 +#define MCASP_AMUTE_ROVRN 0x00000020 // RCV overun occurs 0 1 +#define MCASP_AMUTE_INSTAT 0x00000010 +#define MCASP_AMUTE_INEN 0x00000008 // drive AMUTE active on mute in + // active 0 1 +#define MCASP_AMUTE_INPOL 0x00000004 // Mute input polarity 0 1 +#define MCASP_AMUTE_MUTEN_M 0x00000003 // AMUTE pin enable 0x0 0x1 0x2 +#define MCASP_AMUTE_MUTEN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_LBCTL register. +// +//****************************************************************************** +#define MCASP_LBCTL_IOLBEN 0x00000010 // IO loopback enable 0 1 +#define MCASP_LBCTL_MODE_M 0x0000000C // Loop back clock source generator + // 0x0 0x1 0x2 0x3 +#define MCASP_LBCTL_MODE_S 2 +#define MCASP_LBCTL_ORD 0x00000002 // Loopback order 0 1 +#define MCASP_LBCTL_DLBEN 0x00000001 // Loop back mode 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXDITCTL register. +// +//****************************************************************************** +#define MCASP_TXDITCTL_VB 0x00000008 // Valib bit for odd TDM 0 1 +#define MCASP_TXDITCTL_VA 0x00000004 // Valib bit for even TDM 0 1 +#define MCASP_TXDITCTL_DITEN 0x00000001 // XMT DIT Mode Enable 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_GBLCTLR register. +// +//****************************************************************************** +#define MCASP_GBLCTLR_XFRST 0x00001000 +#define MCASP_GBLCTLR_XSMRST 0x00000800 +#define MCASP_GBLCTLR_XSRCLR 0x00000400 +#define MCASP_GBLCTLR_XHCLKRST 0x00000200 +#define MCASP_GBLCTLR_XCLKRST 0x00000100 +#define MCASP_GBLCTLR_RFRST 0x00000010 // Frame sync generator reset 0 1 +#define MCASP_GBLCTLR_RSMRST 0x00000008 // RCV state machine reset 0 1 +#define MCASP_GBLCTLR_RSRCLR 0x00000004 // RCV serializer clear 0 1 +#define MCASP_GBLCTLR_RHCLKRST 0x00000002 // RCV High Freq. clk Divider 0 1 +#define MCASP_GBLCTLR_RCLKRST 0x00000001 // RCV clock divder reset 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXMASK register. +// +//****************************************************************************** +#define MCASP_RXMASK_RMASK31 0x80000000 // RMASK BIT 31 0 1 +#define MCASP_RXMASK_RMASK30 0x40000000 // RMASK BIT 30 0 1 +#define MCASP_RXMASK_RMASK29 0x20000000 // RMASK BIT 29 0 1 +#define MCASP_RXMASK_RMASK28 0x10000000 // RMASK BIT 28 0 1 +#define MCASP_RXMASK_RMASK27 0x08000000 // RMASK BIT 27 0 1 +#define MCASP_RXMASK_RMASK26 0x04000000 // RMASK BIT 26 0 1 +#define MCASP_RXMASK_RMASK25 0x02000000 // RMASK BIT 25 0 1 +#define MCASP_RXMASK_RMASK24 0x01000000 // RMASK BIT 24 0 1 +#define MCASP_RXMASK_RMASK23 0x00800000 // RMASK BIT 23 0 1 +#define MCASP_RXMASK_RMASK22 0x00400000 // RMASK BIT 22 0 1 +#define MCASP_RXMASK_RMASK21 0x00200000 // RMASK BIT 21 0 1 +#define MCASP_RXMASK_RMASK20 0x00100000 // RMASK BIT 20 0 1 +#define MCASP_RXMASK_RMASK19 0x00080000 // RMASK BIT 19 0 1 +#define MCASP_RXMASK_RMASK18 0x00040000 // RMASK BIT 18 0 1 +#define MCASP_RXMASK_RMASK17 0x00020000 // RMASK BIT 17 0 1 +#define MCASP_RXMASK_RMASK16 0x00010000 // RMASK BIT 16 0 1 +#define MCASP_RXMASK_RMASK15 0x00008000 // RMASK BIT 15 0 1 +#define MCASP_RXMASK_RMASK14 0x00004000 // RMASK BIT 14 0 1 +#define MCASP_RXMASK_RMASK13 0x00002000 // RMASK BIT 13 0 1 +#define MCASP_RXMASK_RMASK12 0x00001000 // RMASK BIT 12 0 1 +#define MCASP_RXMASK_RMASK11 0x00000800 // RMASK BIT 11 0 1 +#define MCASP_RXMASK_RMASK10 0x00000400 // RMASK BIT 10 0 1 +#define MCASP_RXMASK_RMASK9 0x00000200 // RMASK BIT 9 0 1 +#define MCASP_RXMASK_RMASK8 0x00000100 // RMASK BIT 8 0 1 +#define MCASP_RXMASK_RMASK7 0x00000080 // RMASK BIT 7 0 1 +#define MCASP_RXMASK_RMASK6 0x00000040 // RMASK BIT 6 0 1 +#define MCASP_RXMASK_RMASK5 0x00000020 // RMASK BIT 5 0 1 +#define MCASP_RXMASK_RMASK4 0x00000010 // RMASK BIT 4 0 1 +#define MCASP_RXMASK_RMASK3 0x00000008 // RMASK BIT 3 0 1 +#define MCASP_RXMASK_RMASK2 0x00000004 // RMASK BIT 2 0 1 +#define MCASP_RXMASK_RMASK1 0x00000002 // RMASK BIT 1 0 1 +#define MCASP_RXMASK_RMASK0 0x00000001 // RMASK BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXFMT register. +// +//****************************************************************************** +#define MCASP_RXFMT_RDATDLY_M 0x00030000 // RCV Frame sync delay 0x0 0 Bit + // delay 0x1 1 Bit delay 0x2 2 Bit + // delay +#define MCASP_RXFMT_RDATDLY_S 16 +#define MCASP_RXFMT_RRVRS 0x00008000 // RCV serial stream bit order 0 1 +#define MCASP_RXFMT_RPAD_M 0x00006000 // Pad value 0x0 0x1 0x2 +#define MCASP_RXFMT_RPAD_S 13 +#define MCASP_RXFMT_RPBIT_M 0x00001F00 // Pad bit position +#define MCASP_RXFMT_RPBIT_S 8 +#define MCASP_RXFMT_RSSZ_M 0x000000F0 // RCV slot Size 0x0 0x1 0x2 0x3 + // 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB + // 0xC 0xD 0xE 0xF +#define MCASP_RXFMT_RSSZ_S 4 +#define MCASP_RXFMT_RBUSEL 0x00000008 // Write to RBUF using CPU/DMA 0 + // DMA port access 1 CPU port Access +#define MCASP_RXFMT_RROT_M 0x00000007 // Right Rotate Value 0x0 0x1 0x2 + // 0x3 0x4 0x5 0x6 0x7 +#define MCASP_RXFMT_RROT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXFMCTL register. +// +//****************************************************************************** +#define MCASP_RXFMCTL_RMOD_M 0x0000FF80 // RCV Frame sync mode +#define MCASP_RXFMCTL_RMOD_S 7 +#define MCASP_RXFMCTL_FRWID 0x00000010 // RCV Frame sync Duration 0 1 +#define MCASP_RXFMCTL_FSRM 0x00000002 // RCV frame sync External 0 1 +#define MCASP_RXFMCTL_FSRP 0x00000001 // RCV Frame sync Polarity 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_ACLKRCTL register. +// +//****************************************************************************** +#define MCASP_ACLKRCTL_BUSY 0x00100000 +#define MCASP_ACLKRCTL_DIVBUSY 0x00080000 +#define MCASP_ACLKRCTL_ADJBUSY 0x00040000 +#define MCASP_ACLKRCTL_CLKRADJ_M \ + 0x00030000 + +#define MCASP_ACLKRCTL_CLKRADJ_S 16 +#define MCASP_ACLKRCTL_CLKRP 0x00000080 // RCV Clock Polarity 0 1 +#define MCASP_ACLKRCTL_CLKRM 0x00000020 // RCV clock source 0 1 +#define MCASP_ACLKRCTL_CLKRDIV_M \ + 0x0000001F // RCV clock devide ratio + +#define MCASP_ACLKRCTL_CLKRDIV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_AHCLKRCTL register. +// +//****************************************************************************** +#define MCASP_AHCLKRCTL_BUSY 0x00100000 +#define MCASP_AHCLKRCTL_DIVBUSY 0x00080000 +#define MCASP_AHCLKRCTL_ADJBUSY 0x00040000 +#define MCASP_AHCLKRCTL_HCLKRADJ_M \ + 0x00030000 + +#define MCASP_AHCLKRCTL_HCLKRADJ_S 16 +#define MCASP_AHCLKRCTL_HCLKRM 0x00008000 // High Freq. RCV clock Source 0 1 +#define MCASP_AHCLKRCTL_HCLKRP 0x00004000 // High Freq. clock Polarity Before + // diviser 0 1 +#define MCASP_AHCLKRCTL_HCLKRDIV_M \ + 0x00000FFF // RCV clock Divide Ratio + +#define MCASP_AHCLKRCTL_HCLKRDIV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXTDM register. +// +//****************************************************************************** +#define MCASP_RXTDM_RTDMS31 0x80000000 // RCV mode during TDM time slot 31 + // 0 1 +#define MCASP_RXTDM_RTDMS30 0x40000000 // RCV mode during TDM time slot 30 + // 0 1 +#define MCASP_RXTDM_RTDMS29 0x20000000 // RCV mode during TDM time slot 29 + // 0 1 +#define MCASP_RXTDM_RTDMS28 0x10000000 // RCV mode during TDM time slot 28 + // 0 1 +#define MCASP_RXTDM_RTDMS27 0x08000000 // RCV mode during TDM time slot 27 + // 0 1 +#define MCASP_RXTDM_RTDMS26 0x04000000 // RCV mode during TDM time slot 26 + // 0 1 +#define MCASP_RXTDM_RTDMS25 0x02000000 // RCV mode during TDM time slot 25 + // 0 1 +#define MCASP_RXTDM_RTDMS24 0x01000000 // RCV mode during TDM time slot 24 + // 0 1 +#define MCASP_RXTDM_RTDMS23 0x00800000 // RCV mode during TDM time slot 23 + // 0 1 +#define MCASP_RXTDM_RTDMS22 0x00400000 // RCV mode during TDM time slot 22 + // 0 1 +#define MCASP_RXTDM_RTDMS21 0x00200000 // RCV mode during TDM time slot 21 + // 0 1 +#define MCASP_RXTDM_RTDMS20 0x00100000 // RCV mode during TDM time slot 20 + // 0 1 +#define MCASP_RXTDM_RTDMS19 0x00080000 // RCV mode during TDM time slot 19 + // 0 1 +#define MCASP_RXTDM_RTDMS18 0x00040000 // RCV mode during TDM time slot 18 + // 0 1 +#define MCASP_RXTDM_RTDMS17 0x00020000 // RCV mode during TDM time slot 17 + // 0 1 +#define MCASP_RXTDM_RTDMS16 0x00010000 // RCV mode during TDM time slot 16 + // 0 1 +#define MCASP_RXTDM_RTDMS15 0x00008000 // RCV mode during TDM time slot 15 + // 0 1 +#define MCASP_RXTDM_RTDMS14 0x00004000 // RCV mode during TDM time slot 14 + // 0 1 +#define MCASP_RXTDM_RTDMS13 0x00002000 // RCV mode during TDM time slot 13 + // 0 1 +#define MCASP_RXTDM_RTDMS12 0x00001000 // RCV mode during TDM time slot 12 + // 0 1 +#define MCASP_RXTDM_RTDMS11 0x00000800 // RCV mode during TDM time slot 11 + // 0 1 +#define MCASP_RXTDM_RTDMS10 0x00000400 // RCV mode during TDM time slot 10 + // 0 1 +#define MCASP_RXTDM_RTDMS9 0x00000200 // RCV mode during TDM time slot 9 + // 0 1 +#define MCASP_RXTDM_RTDMS8 0x00000100 // RCV mode during TDM time slot 8 + // 0 1 +#define MCASP_RXTDM_RTDMS7 0x00000080 // RCV mode during TDM time slot 7 + // 0 1 +#define MCASP_RXTDM_RTDMS6 0x00000040 // RCV mode during TDM time slot 6 + // 0 1 +#define MCASP_RXTDM_RTDMS5 0x00000020 // RCV mode during TDM time slot 5 + // 0 1 +#define MCASP_RXTDM_RTDMS4 0x00000010 // RCV mode during TDM time slot 4 + // 0 1 +#define MCASP_RXTDM_RTDMS3 0x00000008 // RCV mode during TDM time slot 3 + // 0 1 +#define MCASP_RXTDM_RTDMS2 0x00000004 // RCV mode during TDM time slot 2 + // 0 1 +#define MCASP_RXTDM_RTDMS1 0x00000002 // RCV mode during TDM time slot 1 + // 0 1 +#define MCASP_RXTDM_RTDMS0 0x00000001 // RCV mode during TDM time slot 0 + // 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_EVTCTLR register. +// +//****************************************************************************** +#define MCASP_EVTCTLR_RSTAFRM 0x00000080 // RCV Start of Frame Interrupt 0 1 +#define MCASP_EVTCTLR_RDATA 0x00000020 // RCV Data Interrupt 0 1 +#define MCASP_EVTCTLR_RLAST 0x00000010 // RCV Last Slot Interrupt 0 1 +#define MCASP_EVTCTLR_RDMAERR 0x00000008 // RCV DMA Bus Error 0 1 +#define MCASP_EVTCTLR_RCKFAIL 0x00000004 // Bad Clock Interrupt 0 1 +#define MCASP_EVTCTLR_RSYNCERR 0x00000002 // RCV Unexpected FSR Interrupt 0 1 +#define MCASP_EVTCTLR_ROVRN 0x00000001 // RCV Underrun Flag 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXSTAT register. +// +//****************************************************************************** +#define MCASP_RXSTAT_RERR 0x00000100 // RCV Error 0 1 +#define MCASP_RXSTAT_RDMAERR 0x00000080 // RCV DMA bus error 0 1 +#define MCASP_RXSTAT_RSTAFRM 0x00000040 // Start of Frame-RCV 0 1 +#define MCASP_RXSTAT_RDATA 0x00000020 // Data Ready Flag 0 1 +#define MCASP_RXSTAT_RLAST 0x00000010 // Last Slot Interrupt Flag 0 1 +#define MCASP_RXSTAT_RTDMSLOT 0x00000008 // EvenOdd Slot 0 1 +#define MCASP_RXSTAT_RCKFAIL 0x00000004 // Bad Transmit Flag 0 1 +#define MCASP_RXSTAT_RSYNCERR 0x00000002 // Unexpected RCV Frame sync flag 0 + // 1 +#define MCASP_RXSTAT_ROVRN 0x00000001 // RCV Underrun Flag 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXTDMSLOT register. +// +//****************************************************************************** +#define MCASP_RXTDMSLOT_RSLOTCNT_M \ + 0x000003FF // Current RCV time slot count + +#define MCASP_RXTDMSLOT_RSLOTCNT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXCLKCHK register. +// +//****************************************************************************** +#define MCASP_RXCLKCHK_RCNT_M 0xFF000000 // RCV clock count value +#define MCASP_RXCLKCHK_RCNT_S 24 +#define MCASP_RXCLKCHK_RMAX_M 0x00FF0000 // RCV clock maximum boundary +#define MCASP_RXCLKCHK_RMAX_S 16 +#define MCASP_RXCLKCHK_RMIN_M 0x0000FF00 // RCV clock minimum boundary +#define MCASP_RXCLKCHK_RMIN_S 8 +#define MCASP_RXCLKCHK_RPS_M 0x0000000F // RCV clock check prescaler 0x0 + // 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 +#define MCASP_RXCLKCHK_RPS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_REVTCTL register. +// +//****************************************************************************** +#define MCASP_REVTCTL_RDATDMA 0x00000001 // RCV data DMA request 0 Enable + // DMA Transfer 1 Disable DMA + // Transfer +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_GBLCTLX register. +// +//****************************************************************************** +#define MCASP_GBLCTLX_XFRST 0x00001000 // Frame sync generator reset 0 1 +#define MCASP_GBLCTLX_XSMRST 0x00000800 // XMT state machine reset 0 1 +#define MCASP_GBLCTLX_XSRCLR 0x00000400 // XMT serializer clear 0 1 +#define MCASP_GBLCTLX_XHCLKRST 0x00000200 // XMT High Freq. clk Divider 0 1 +#define MCASP_GBLCTLX_XCLKRST 0x00000100 // XMT clock divder reset 0 1 +#define MCASP_GBLCTLX_RFRST 0x00000010 +#define MCASP_GBLCTLX_RSMRST 0x00000008 +#define MCASP_GBLCTLX_RSRCLKR 0x00000004 +#define MCASP_GBLCTLX_RHCLKRST 0x00000002 +#define MCASP_GBLCTLX_RCLKRST 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXMASK register. +// +//****************************************************************************** +#define MCASP_TXMASK_XMASK31 0x80000000 // XMASK BIT 31 0 1 +#define MCASP_TXMASK_XMASK30 0x40000000 // XMASK BIT 30 0 1 +#define MCASP_TXMASK_XMASK29 0x20000000 // XMASK BIT 29 0 1 +#define MCASP_TXMASK_XMASK28 0x10000000 // XMASK BIT 28 0 1 +#define MCASP_TXMASK_XMASK27 0x08000000 // XMASK BIT 27 0 1 +#define MCASP_TXMASK_XMASK26 0x04000000 // XMASK BIT 26 0 1 +#define MCASP_TXMASK_XMASK25 0x02000000 // XMASK BIT 25 0 1 +#define MCASP_TXMASK_XMASK24 0x01000000 // XMASK BIT 24 0 1 +#define MCASP_TXMASK_XMASK23 0x00800000 // XMASK BIT 23 0 1 +#define MCASP_TXMASK_XMASK22 0x00400000 // XMASK BIT 22 0 1 +#define MCASP_TXMASK_XMASK21 0x00200000 // XMASK BIT 21 0 1 +#define MCASP_TXMASK_XMASK20 0x00100000 // XMASK BIT 20 0 1 +#define MCASP_TXMASK_XMASK19 0x00080000 // XMASK BIT 19 0 1 +#define MCASP_TXMASK_XMASK18 0x00040000 // XMASK BIT 18 0 1 +#define MCASP_TXMASK_XMASK17 0x00020000 // XMASK BIT 17 0 1 +#define MCASP_TXMASK_XMASK16 0x00010000 // XMASK BIT 16 0 1 +#define MCASP_TXMASK_XMASK15 0x00008000 // XMASK BIT 15 0 1 +#define MCASP_TXMASK_XMASK14 0x00004000 // XMASK BIT 14 0 1 +#define MCASP_TXMASK_XMASK13 0x00002000 // XMASK BIT 13 0 1 +#define MCASP_TXMASK_XMASK12 0x00001000 // XMASK BIT 12 0 1 +#define MCASP_TXMASK_XMASK11 0x00000800 // XMASK BIT 11 0 1 +#define MCASP_TXMASK_XMASK10 0x00000400 // XMASK BIT 10 0 1 +#define MCASP_TXMASK_XMASK9 0x00000200 // XMASK BIT 9 0 1 +#define MCASP_TXMASK_XMASK8 0x00000100 // XMASK BIT 8 0 1 +#define MCASP_TXMASK_XMASK7 0x00000080 // XMASK BIT 7 0 1 +#define MCASP_TXMASK_XMASK6 0x00000040 // XMASK BIT 6 0 1 +#define MCASP_TXMASK_XMASK5 0x00000020 // XMASK BIT 5 0 1 +#define MCASP_TXMASK_XMASK4 0x00000010 // XMASK BIT 4 0 1 +#define MCASP_TXMASK_XMASK3 0x00000008 // XMASK BIT 3 0 1 +#define MCASP_TXMASK_XMASK2 0x00000004 // XMASK BIT 2 0 1 +#define MCASP_TXMASK_XMASK1 0x00000002 // XMASK BIT 1 0 1 +#define MCASP_TXMASK_XMASK0 0x00000001 // XMASK BIT 0 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXFMT register. +// +//****************************************************************************** +#define MCASP_TXFMT_XDATDLY_M 0x00030000 // XMT Frame sync delay 0x0 0 Bit + // delay 0x1 1 Bit delay 0x2 2 Bit + // delay +#define MCASP_TXFMT_XDATDLY_S 16 +#define MCASP_TXFMT_XRVRS 0x00008000 // XMT serial stream bit order 0 1 +#define MCASP_TXFMT_XPAD_M 0x00006000 // Pad value 0x0 0x1 0x2 +#define MCASP_TXFMT_XPAD_S 13 +#define MCASP_TXFMT_XPBIT_M 0x00001F00 // Pad bit position +#define MCASP_TXFMT_XPBIT_S 8 +#define MCASP_TXFMT_XSSZ_M 0x000000F0 // XMT slot Size 0x0 0x1 0x2 0x3 + // 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB + // 0xC 0xD 0xE 0xF +#define MCASP_TXFMT_XSSZ_S 4 +#define MCASP_TXFMT_XBUSEL 0x00000008 // Write to XBUF using CPU/DMA 0 + // DMA port access 1 CPU port Access +#define MCASP_TXFMT_XROT_M 0x00000007 // Right Rotate Value 0x0 0x1 0x2 + // 0x3 0x4 0x5 0x6 0x7 +#define MCASP_TXFMT_XROT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXFMCTL register. +// +//****************************************************************************** +#define MCASP_TXFMCTL_XMOD_M 0x0000FF80 // XMT Frame sync mode +#define MCASP_TXFMCTL_XMOD_S 7 +#define MCASP_TXFMCTL_FXWID 0x00000010 // XMT Frame sync Duration 0 1 +#define MCASP_TXFMCTL_FSXM 0x00000002 // XMT frame sync External 0 1 +#define MCASP_TXFMCTL_FSXP 0x00000001 // XMT Frame sync Polarity 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_ACLKXCTL register. +// +//****************************************************************************** +#define MCASP_ACLKXCTL_BUSY 0x00100000 +#define MCASP_ACLKXCTL_DIVBUSY 0x00080000 +#define MCASP_ACLKXCTL_ADJBUSY 0x00040000 +#define MCASP_ACLKXCTL_CLKXADJ_M \ + 0x00030000 + +#define MCASP_ACLKXCTL_CLKXADJ_S 16 +#define MCASP_ACLKXCTL_CLKXP 0x00000080 // XMT Clock Polarity 0 1 +#define MCASP_ACLKXCTL_ASYNC 0x00000040 // XMT/RCV operation sync /Async 0 + // 1 +#define MCASP_ACLKXCTL_CLKXM 0x00000020 // XMT clock source 0 1 +#define MCASP_ACLKXCTL_CLKXDIV_M \ + 0x0000001F // XMT clock devide ratio + +#define MCASP_ACLKXCTL_CLKXDIV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_AHCLKXCTL register. +// +//****************************************************************************** +#define MCASP_AHCLKXCTL_BUSY 0x00100000 +#define MCASP_AHCLKXCTL_DIVBUSY 0x00080000 +#define MCASP_AHCLKXCTL_ADJBUSY 0x00040000 +#define MCASP_AHCLKXCTL_HCLKXADJ_M \ + 0x00030000 + +#define MCASP_AHCLKXCTL_HCLKXADJ_S 16 +#define MCASP_AHCLKXCTL_HCLKXM 0x00008000 // High Freq. XMT clock Source 0 1 +#define MCASP_AHCLKXCTL_HCLKXP 0x00004000 // High Freq. clock Polarity Before + // diviser 0 1 +#define MCASP_AHCLKXCTL_HCLKXDIV_M \ + 0x00000FFF // XMT clock Divide Ratio + +#define MCASP_AHCLKXCTL_HCLKXDIV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXTDM register. +// +//****************************************************************************** +#define MCASP_TXTDM_XTDMS31 0x80000000 // XMT mode during TDM time slot 31 + // 0 1 +#define MCASP_TXTDM_XTDMS30 0x40000000 // XMT mode during TDM time slot 30 + // 0 1 +#define MCASP_TXTDM_XTDMS29 0x20000000 // XMT mode during TDM time slot 29 + // 0 1 +#define MCASP_TXTDM_XTDMS28 0x10000000 // XMT mode during TDM time slot 28 + // 0 1 +#define MCASP_TXTDM_XTDMS27 0x08000000 // XMT mode during TDM time slot 27 + // 0 1 +#define MCASP_TXTDM_XTDMS26 0x04000000 // XMT mode during TDM time slot 26 + // 0 1 +#define MCASP_TXTDM_XTDMS25 0x02000000 // XMT mode during TDM time slot 25 + // 0 1 +#define MCASP_TXTDM_XTDMS24 0x01000000 // XMT mode during TDM time slot 24 + // 0 1 +#define MCASP_TXTDM_XTDMS23 0x00800000 // XMT mode during TDM time slot 23 + // 0 1 +#define MCASP_TXTDM_XTDMS22 0x00400000 // XMT mode during TDM time slot 22 + // 0 1 +#define MCASP_TXTDM_XTDMS21 0x00200000 // XMT mode during TDM time slot 21 + // 0 1 +#define MCASP_TXTDM_XTDMS20 0x00100000 // XMT mode during TDM time slot 20 + // 0 1 +#define MCASP_TXTDM_XTDMS19 0x00080000 // XMT mode during TDM time slot 19 + // 0 1 +#define MCASP_TXTDM_XTDMS18 0x00040000 // XMT mode during TDM time slot 18 + // 0 1 +#define MCASP_TXTDM_XTDMS17 0x00020000 // XMT mode during TDM time slot 17 + // 0 1 +#define MCASP_TXTDM_XTDMS16 0x00010000 // XMT mode during TDM time slot 16 + // 0 1 +#define MCASP_TXTDM_XTDMS15 0x00008000 // XMT mode during TDM time slot 15 + // 0 1 +#define MCASP_TXTDM_XTDMS14 0x00004000 // XMT mode during TDM time slot 14 + // 0 1 +#define MCASP_TXTDM_XTDMS13 0x00002000 // XMT mode during TDM time slot 13 + // 0 1 +#define MCASP_TXTDM_XTDMS12 0x00001000 // XMT mode during TDM time slot 12 + // 0 1 +#define MCASP_TXTDM_XTDMS11 0x00000800 // XMT mode during TDM time slot 11 + // 0 1 +#define MCASP_TXTDM_XTDMS10 0x00000400 // XMT mode during TDM time slot 10 + // 0 1 +#define MCASP_TXTDM_XTDMS9 0x00000200 // XMT mode during TDM time slot 9 + // 0 1 +#define MCASP_TXTDM_XTDMS8 0x00000100 // XMT mode during TDM time slot 8 + // 0 1 +#define MCASP_TXTDM_XTDMS7 0x00000080 // XMT mode during TDM time slot 7 + // 0 1 +#define MCASP_TXTDM_XTDMS6 0x00000040 // XMT mode during TDM time slot 6 + // 0 1 +#define MCASP_TXTDM_XTDMS5 0x00000020 // XMT mode during TDM time slot 5 + // 0 1 +#define MCASP_TXTDM_XTDMS4 0x00000010 // XMT mode during TDM time slot 4 + // 0 1 +#define MCASP_TXTDM_XTDMS3 0x00000008 // XMT mode during TDM time slot 3 + // 0 1 +#define MCASP_TXTDM_XTDMS2 0x00000004 // XMT mode during TDM time slot 2 + // 0 1 +#define MCASP_TXTDM_XTDMS1 0x00000002 // XMT mode during TDM time slot 1 + // 0 1 +#define MCASP_TXTDM_XTDMS0 0x00000001 // XMT mode during TDM time slot 0 + // 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_EVTCTLX register. +// +//****************************************************************************** +#define MCASP_EVTCTLX_XSTAFRM 0x00000080 // XMT Start of Frame Interrupt 0 1 +#define MCASP_EVTCTLX_XDATA 0x00000020 // XMT Data Interrupt 0 1 +#define MCASP_EVTCTLX_XLAST 0x00000010 // XMT Last Slot Interrupt 0 1 +#define MCASP_EVTCTLX_XDMAERR 0x00000008 // XMT DMA Bus Error 0 1 +#define MCASP_EVTCTLX_XCKFAIL 0x00000004 // Bad Clock Interrupt 0 1 +#define MCASP_EVTCTLX_XSYNCERR 0x00000002 // XMT Unexpected FSR Interrupt 0 1 +#define MCASP_EVTCTLX_XUNDRN 0x00000001 // XMT Underrun Interrupt 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXSTAT register. +// +//****************************************************************************** +#define MCASP_TXSTAT_XERR 0x00000100 // XMT Error 0 1 +#define MCASP_TXSTAT_XDMAERR 0x00000080 // XMT DMA bus error 0 1 +#define MCASP_TXSTAT_XSTAFRM 0x00000040 // Start of Frame-XMT 0 1 +#define MCASP_TXSTAT_XDATA 0x00000020 // Data Ready Flag 0 1 +#define MCASP_TXSTAT_XLAST 0x00000010 // Last Slot Interrupt Flag 0 1 +#define MCASP_TXSTAT_XTDMSLOT 0x00000008 // EvenOdd Slot 0 1 +#define MCASP_TXSTAT_XCKFAIL 0x00000004 // Bad Transmit Flag 0 1 +#define MCASP_TXSTAT_XSYNCERR 0x00000002 // Unexpected XMT Frame sync flag 0 + // 1 +#define MCASP_TXSTAT_XUNDRN 0x00000001 // XMT Underrun Flag 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXTDMSLOT register. +// +//****************************************************************************** +#define MCASP_TXTDMSLOT_XSLOTCNT_M \ + 0x000003FF // Current XMT time slot count + // during reset the value of this + // register is 0b0101111111 (0x17f) + // and after reset 0 + +#define MCASP_TXTDMSLOT_XSLOTCNT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXCLKCHK register. +// +//****************************************************************************** +#define MCASP_TXCLKCHK_XCNT_M 0xFF000000 // XMT clock count value +#define MCASP_TXCLKCHK_XCNT_S 24 +#define MCASP_TXCLKCHK_XMAX_M 0x00FF0000 // XMT clock maximum boundary +#define MCASP_TXCLKCHK_XMAX_S 16 +#define MCASP_TXCLKCHK_XMIN_M 0x0000FF00 // XMT clock minimum boundary +#define MCASP_TXCLKCHK_XMIN_S 8 +#define MCASP_TXCLKCHK_RESV 0x00000080 // Reserved +#define MCASP_TXCLKCHK_XPS_M 0x0000000F // XMT clock check prescaler 0x0 + // 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 +#define MCASP_TXCLKCHK_XPS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XEVTCTL register. +// +//****************************************************************************** +#define MCASP_XEVTCTL_XDATDMA 0x00000001 // XMT data DMA request 0 Enable + // DMA Transfer 1 Disable DMA + // Transfer +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_CLKADJEN register. +// +//****************************************************************************** +#define MCASP_CLKADJEN_ENABLE 0x00000001 // One-shot clock adjust enable 0 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA0 register. +// +//****************************************************************************** +#define MCASP_DITCSRA0_DITCSRA0_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status + +#define MCASP_DITCSRA0_DITCSRA0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA1 register. +// +//****************************************************************************** +#define MCASP_DITCSRA1_DITCSRA1_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status + +#define MCASP_DITCSRA1_DITCSRA1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA2 register. +// +//****************************************************************************** +#define MCASP_DITCSRA2_DITCSRA2_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status Register + +#define MCASP_DITCSRA2_DITCSRA2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA3 register. +// +//****************************************************************************** +#define MCASP_DITCSRA3_DITCSRA3_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status Register + +#define MCASP_DITCSRA3_DITCSRA3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA4 register. +// +//****************************************************************************** +#define MCASP_DITCSRA4_DITCSRA4_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status + +#define MCASP_DITCSRA4_DITCSRA4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRA5 register. +// +//****************************************************************************** +#define MCASP_DITCSRA5_DITCSRA5_M \ + 0xFFFFFFFF // Left (Even TDM slot ) Channel + // status + +#define MCASP_DITCSRA5_DITCSRA5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB0 register. +// +//****************************************************************************** +#define MCASP_DITCSRB0_DITCSRB0_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB0_DITCSRB0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB1 register. +// +//****************************************************************************** +#define MCASP_DITCSRB1_DITCSRB1_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB1_DITCSRB1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB2 register. +// +//****************************************************************************** +#define MCASP_DITCSRB2_DITCSRB2_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB2_DITCSRB2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB3 register. +// +//****************************************************************************** +#define MCASP_DITCSRB3_DITCSRB3_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB3_DITCSRB3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB4 register. +// +//****************************************************************************** +#define MCASP_DITCSRB4_DITCSRB4_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB4_DITCSRB4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITCSRB5 register. +// +//****************************************************************************** +#define MCASP_DITCSRB5_DITCSRB5_M \ + 0xFFFFFFFF // Right (odd TDM slot ) Channel + // status + +#define MCASP_DITCSRB5_DITCSRB5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA0 register. +// +//****************************************************************************** +#define MCASP_DITUDRA0_DITUDRA0_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA0_DITUDRA0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA1 register. +// +//****************************************************************************** +#define MCASP_DITUDRA1_DITUDRA1_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA1_DITUDRA1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA2 register. +// +//****************************************************************************** +#define MCASP_DITUDRA2_DITUDRA2_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA2_DITUDRA2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA3 register. +// +//****************************************************************************** +#define MCASP_DITUDRA3_DITUDRA3_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA3_DITUDRA3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA4 register. +// +//****************************************************************************** +#define MCASP_DITUDRA4_DITUDRA4_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA4_DITUDRA4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRA5 register. +// +//****************************************************************************** +#define MCASP_DITUDRA5_DITUDRA5_M \ + 0xFFFFFFFF // Left (Even TDM slot ) User Data + +#define MCASP_DITUDRA5_DITUDRA5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB0 register. +// +//****************************************************************************** +#define MCASP_DITUDRB0_DITUDRB0_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB0_DITUDRB0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB1 register. +// +//****************************************************************************** +#define MCASP_DITUDRB1_DITUDRB1_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB1_DITUDRB1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB2 register. +// +//****************************************************************************** +#define MCASP_DITUDRB2_DITUDRB2_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB2_DITUDRB2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB3 register. +// +//****************************************************************************** +#define MCASP_DITUDRB3_DITUDRB3_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB3_DITUDRB3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB4 register. +// +//****************************************************************************** +#define MCASP_DITUDRB4_DITUDRB4_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB4_DITUDRB4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_DITUDRB5 register. +// +//****************************************************************************** +#define MCASP_DITUDRB5_DITUDRB5_M \ + 0xFFFFFFFF // Right (odd TDM slot ) User Data + +#define MCASP_DITUDRB5_DITUDRB5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL0 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL0_RRDY 0x00000020 +#define MCASP_XRSRCTL0_XRDY 0x00000010 +#define MCASP_XRSRCTL0_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL0_DISMOD_S 2 +#define MCASP_XRSRCTL0_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL0_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL1 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL1_RRDY 0x00000020 +#define MCASP_XRSRCTL1_XRDY 0x00000010 +#define MCASP_XRSRCTL1_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL1_DISMOD_S 2 +#define MCASP_XRSRCTL1_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL1_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL2 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL2_RRDY 0x00000020 +#define MCASP_XRSRCTL2_XRDY 0x00000010 +#define MCASP_XRSRCTL2_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL2_DISMOD_S 2 +#define MCASP_XRSRCTL2_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL2_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL3 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL3_RRDY 0x00000020 +#define MCASP_XRSRCTL3_XRDY 0x00000010 +#define MCASP_XRSRCTL3_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL3_DISMOD_S 2 +#define MCASP_XRSRCTL3_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL3_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL4 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL4_RRDY 0x00000020 +#define MCASP_XRSRCTL4_XRDY 0x00000010 +#define MCASP_XRSRCTL4_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL4_DISMOD_S 2 +#define MCASP_XRSRCTL4_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL4_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL5 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL5_RRDY 0x00000020 +#define MCASP_XRSRCTL5_XRDY 0x00000010 +#define MCASP_XRSRCTL5_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL5_DISMOD_S 2 +#define MCASP_XRSRCTL5_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL5_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL6 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL6_RRDY 0x00000020 +#define MCASP_XRSRCTL6_XRDY 0x00000010 +#define MCASP_XRSRCTL6_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL6_DISMOD_S 2 +#define MCASP_XRSRCTL6_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL6_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL7 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL7_RRDY 0x00000020 +#define MCASP_XRSRCTL7_XRDY 0x00000010 +#define MCASP_XRSRCTL7_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL7_DISMOD_S 2 +#define MCASP_XRSRCTL7_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL7_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL8 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL8_RRDY 0x00000020 +#define MCASP_XRSRCTL8_XRDY 0x00000010 +#define MCASP_XRSRCTL8_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL8_DISMOD_S 2 +#define MCASP_XRSRCTL8_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL8_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL9 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL9_RRDY 0x00000020 +#define MCASP_XRSRCTL9_XRDY 0x00000010 +#define MCASP_XRSRCTL9_DISMOD_M 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high +#define MCASP_XRSRCTL9_DISMOD_S 2 +#define MCASP_XRSRCTL9_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL9_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL10 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL10_RRDY 0x00000020 +#define MCASP_XRSRCTL10_XRDY 0x00000010 +#define MCASP_XRSRCTL10_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL10_DISMOD_S 2 +#define MCASP_XRSRCTL10_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL10_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL11 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL11_RRDY 0x00000020 +#define MCASP_XRSRCTL11_XRDY 0x00000010 +#define MCASP_XRSRCTL11_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL11_DISMOD_S 2 +#define MCASP_XRSRCTL11_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL11_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL12 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL12_RRDY 0x00000020 +#define MCASP_XRSRCTL12_XRDY 0x00000010 +#define MCASP_XRSRCTL12_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL12_DISMOD_S 2 +#define MCASP_XRSRCTL12_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL12_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL13 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL13_RRDY 0x00000020 +#define MCASP_XRSRCTL13_XRDY 0x00000010 +#define MCASP_XRSRCTL13_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL13_DISMOD_S 2 +#define MCASP_XRSRCTL13_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL13_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL14 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL14_RRDY 0x00000020 +#define MCASP_XRSRCTL14_XRDY 0x00000010 +#define MCASP_XRSRCTL14_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL14_DISMOD_S 2 +#define MCASP_XRSRCTL14_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL14_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_XRSRCTL15 register. +// +//****************************************************************************** +#define MCASP_XRSRCTL15_RRDY 0x00000020 +#define MCASP_XRSRCTL15_XRDY 0x00000010 +#define MCASP_XRSRCTL15_DISMOD_M \ + 0x0000000C // Serializer drive state 0x0 Tri + // state 0x1 Reserved 0x2 Drive pin + // low 0x3 Drive pin high + +#define MCASP_XRSRCTL15_DISMOD_S 2 +#define MCASP_XRSRCTL15_SRMOD_M 0x00000003 // Serializer Mode 0x0 InActive + // mode 0x1 Transmit mode 0x2 + // Receive mode +#define MCASP_XRSRCTL15_SRMOD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF0 register. +// +//****************************************************************************** +#define MCASP_TXBUF0_XBUF0_M 0xFFFFFFFF // Transmit Buffer 0 +#define MCASP_TXBUF0_XBUF0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF1 register. +// +//****************************************************************************** +#define MCASP_TXBUF1_XBUF1_M 0xFFFFFFFF // Transmit Buffer 1 +#define MCASP_TXBUF1_XBUF1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF2 register. +// +//****************************************************************************** +#define MCASP_TXBUF2_XBUF2_M 0xFFFFFFFF // Transmit Buffer 2 +#define MCASP_TXBUF2_XBUF2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF3 register. +// +//****************************************************************************** +#define MCASP_TXBUF3_XBUF3_M 0xFFFFFFFF // Transmit Buffer 3 +#define MCASP_TXBUF3_XBUF3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF4 register. +// +//****************************************************************************** +#define MCASP_TXBUF4_XBUF4_M 0xFFFFFFFF // Transmit Buffer 4 +#define MCASP_TXBUF4_XBUF4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF5 register. +// +//****************************************************************************** +#define MCASP_TXBUF5_XBUF5_M 0xFFFFFFFF // Transmit Buffer 5 +#define MCASP_TXBUF5_XBUF5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF6 register. +// +//****************************************************************************** +#define MCASP_TXBUF6_XBUF6_M 0xFFFFFFFF // Transmit Buffer 6 +#define MCASP_TXBUF6_XBUF6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF7 register. +// +//****************************************************************************** +#define MCASP_TXBUF7_XBUF7_M 0xFFFFFFFF // Transmit Buffer 7 +#define MCASP_TXBUF7_XBUF7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF8 register. +// +//****************************************************************************** +#define MCASP_TXBUF8_XBUF8_M 0xFFFFFFFF // Transmit Buffer 8 +#define MCASP_TXBUF8_XBUF8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF9 register. +// +//****************************************************************************** +#define MCASP_TXBUF9_XBUF9_M 0xFFFFFFFF // Transmit Buffer 9 +#define MCASP_TXBUF9_XBUF9_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF10 register. +// +//****************************************************************************** +#define MCASP_TXBUF10_XBUF10_M 0xFFFFFFFF // Transmit Buffer 10 +#define MCASP_TXBUF10_XBUF10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF11 register. +// +//****************************************************************************** +#define MCASP_TXBUF11_XBUF11_M 0xFFFFFFFF // Transmit Buffer 11 +#define MCASP_TXBUF11_XBUF11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF12 register. +// +//****************************************************************************** +#define MCASP_TXBUF12_XBUF12_M 0xFFFFFFFF // Transmit Buffer 12 +#define MCASP_TXBUF12_XBUF12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF13 register. +// +//****************************************************************************** +#define MCASP_TXBUF13_XBUF13_M 0xFFFFFFFF // Transmit Buffer 13 +#define MCASP_TXBUF13_XBUF13_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF14 register. +// +//****************************************************************************** +#define MCASP_TXBUF14_XBUF14_M 0xFFFFFFFF // Transmit Buffer 14 +#define MCASP_TXBUF14_XBUF14_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_TXBUF15 register. +// +//****************************************************************************** +#define MCASP_TXBUF15_XBUF15_M 0xFFFFFFFF // Transmit Buffer 15 +#define MCASP_TXBUF15_XBUF15_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF0 register. +// +//****************************************************************************** +#define MCASP_RXBUF0_RBUF0_M 0xFFFFFFFF // Receive Buffer 0 +#define MCASP_RXBUF0_RBUF0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF1 register. +// +//****************************************************************************** +#define MCASP_RXBUF1_RBUF1_M 0xFFFFFFFF // Receive Buffer 1 +#define MCASP_RXBUF1_RBUF1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF2 register. +// +//****************************************************************************** +#define MCASP_RXBUF2_RBUF2_M 0xFFFFFFFF // Receive Buffer 2 +#define MCASP_RXBUF2_RBUF2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF3 register. +// +//****************************************************************************** +#define MCASP_RXBUF3_RBUF3_M 0xFFFFFFFF // Receive Buffer 3 +#define MCASP_RXBUF3_RBUF3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF4 register. +// +//****************************************************************************** +#define MCASP_RXBUF4_RBUF4_M 0xFFFFFFFF // Receive Buffer 4 +#define MCASP_RXBUF4_RBUF4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF5 register. +// +//****************************************************************************** +#define MCASP_RXBUF5_RBUF5_M 0xFFFFFFFF // Receive Buffer 5 +#define MCASP_RXBUF5_RBUF5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF6 register. +// +//****************************************************************************** +#define MCASP_RXBUF6_RBUF6_M 0xFFFFFFFF // Receive Buffer 6 +#define MCASP_RXBUF6_RBUF6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF7 register. +// +//****************************************************************************** +#define MCASP_RXBUF7_RBUF7_M 0xFFFFFFFF // Receive Buffer 7 +#define MCASP_RXBUF7_RBUF7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF8 register. +// +//****************************************************************************** +#define MCASP_RXBUF8_RBUF8_M 0xFFFFFFFF // Receive Buffer 8 +#define MCASP_RXBUF8_RBUF8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF9 register. +// +//****************************************************************************** +#define MCASP_RXBUF9_RBUF9_M 0xFFFFFFFF // Receive Buffer 9 +#define MCASP_RXBUF9_RBUF9_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF10 register. +// +//****************************************************************************** +#define MCASP_RXBUF10_RBUF10_M 0xFFFFFFFF // Receive Buffer 10 +#define MCASP_RXBUF10_RBUF10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF11 register. +// +//****************************************************************************** +#define MCASP_RXBUF11_RBUF11_M 0xFFFFFFFF // Receive Buffer 11 +#define MCASP_RXBUF11_RBUF11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF12 register. +// +//****************************************************************************** +#define MCASP_RXBUF12_RBUF12_M 0xFFFFFFFF // Receive Buffer 12 +#define MCASP_RXBUF12_RBUF12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF13 register. +// +//****************************************************************************** +#define MCASP_RXBUF13_RBUF13_M 0xFFFFFFFF // Receive Buffer 13 +#define MCASP_RXBUF13_RBUF13_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF14 register. +// +//****************************************************************************** +#define MCASP_RXBUF14_RBUF14_M 0xFFFFFFFF // Receive Buffer 14 +#define MCASP_RXBUF14_RBUF14_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCASP_O_RXBUF15 register. +// +//****************************************************************************** +#define MCASP_RXBUF15_RBUF15_M 0xFFFFFFFF // Receive Buffer 15 +#define MCASP_RXBUF15_RBUF15_S 0 + + + +#endif // __HW_MCASP_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcspi.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcspi.h new file mode 100755 index 0000000..079e4b6 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mcspi.h @@ -0,0 +1,1745 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_MCSPI_H__ +#define __HW_MCSPI_H__ + +//***************************************************************************** +// +// The following are defines for the MCSPI register offsets. +// +//***************************************************************************** +#define MCSPI_O_HL_REV 0x00000000 // IP Revision Identifier (X.Y.R) + // Used by software to track + // features bugs and compatibility +#define MCSPI_O_HL_HWINFO 0x00000004 // Information about the IP + // module's hardware configuration + // i.e. typically the module's HDL + // generics (if any). Actual field + // format and encoding is up to the + // module's designer to decide. +#define MCSPI_O_HL_SYSCONFIG 0x00000010 // 0x4402 1010 0x4402 2010 Clock + // management configuration +#define MCSPI_O_REVISION 0x00000100 // 0x4402 1100 0x4402 2100 This + // register contains the hard coded + // RTL revision number. +#define MCSPI_O_SYSCONFIG 0x00000110 // 0x4402 1110 0x4402 2110 This + // register allows controlling + // various parameters of the OCP + // interface. +#define MCSPI_O_SYSSTATUS 0x00000114 // 0x4402 1114 0x4402 2114 This + // register provides status + // information about the module + // excluding the interrupt status + // information +#define MCSPI_O_IRQSTATUS 0x00000118 // 0x4402 1118 0x4402 2118 The + // interrupt status regroups all the + // status of the module internal + // events that can generate an + // interrupt +#define MCSPI_O_IRQENABLE 0x0000011C // 0x4402 111C 0x4402 211C This + // register allows to enable/disable + // the module internal sources of + // interrupt on an event-by-event + // basis. +#define MCSPI_O_WAKEUPENABLE 0x00000120 // 0x4402 1120 0x4402 2120 The + // wakeup enable register allows to + // enable/disable the module + // internal sources of wakeup on + // event-by-event basis. +#define MCSPI_O_SYST 0x00000124 // 0x4402 1124 0x4402 2124 This + // register is used to check the + // correctness of the system + // interconnect either internally to + // peripheral bus or externally to + // device IO pads when the module is + // configured in system test + // (SYSTEST) mode. +#define MCSPI_O_MODULCTRL 0x00000128 // 0x4402 1128 0x4402 2128 This + // register is dedicated to the + // configuration of the serial port + // interface. +#define MCSPI_O_CH0CONF 0x0000012C // 0x4402 112C 0x4402 212C This + // register is dedicated to the + // configuration of the channel 0 +#define MCSPI_O_CH0STAT 0x00000130 // 0x4402 1130 0x4402 2130 This + // register provides status + // information about transmitter and + // receiver registers of channel 0 +#define MCSPI_O_CH0CTRL 0x00000134 // 0x4402 1134 0x4402 2134 This + // register is dedicated to enable + // the channel 0 +#define MCSPI_O_TX0 0x00000138 // 0x4402 1138 0x4402 2138 This + // register contains a single SPI + // word to transmit on the serial + // link what ever SPI word length + // is. +#define MCSPI_O_RX0 0x0000013C // 0x4402 113C 0x4402 213C This + // register contains a single SPI + // word received through the serial + // link what ever SPI word length + // is. +#define MCSPI_O_CH1CONF 0x00000140 // 0x4402 1140 0x4402 2140 This + // register is dedicated to the + // configuration of the channel. +#define MCSPI_O_CH1STAT 0x00000144 // 0x4402 1144 0x4402 2144 This + // register provides status + // information about transmitter and + // receiver registers of channel 1 +#define MCSPI_O_CH1CTRL 0x00000148 // 0x4402 1148 0x4402 2148 This + // register is dedicated to enable + // the channel 1 +#define MCSPI_O_TX1 0x0000014C // 0x4402 114C 0x4402 214C This + // register contains a single SPI + // word to transmit on the serial + // link what ever SPI word length + // is. +#define MCSPI_O_RX1 0x00000150 // 0x4402 1150 0x4402 2150 This + // register contains a single SPI + // word received through the serial + // link what ever SPI word length + // is. +#define MCSPI_O_CH2CONF 0x00000154 // 0x4402 1154 0x4402 2154 This + // register is dedicated to the + // configuration of the channel 2 +#define MCSPI_O_CH2STAT 0x00000158 // 0x4402 1158 0x4402 2158 This + // register provides status + // information about transmitter and + // receiver registers of channel 2 +#define MCSPI_O_CH2CTRL 0x0000015C // 0x4402 115C 0x4402 215C This + // register is dedicated to enable + // the channel 2 +#define MCSPI_O_TX2 0x00000160 // 0x4402 1160 0x4402 2160 This + // register contains a single SPI + // word to transmit on the serial + // link what ever SPI word length + // is. +#define MCSPI_O_RX2 0x00000164 // 0x4402 1164 0x4402 2164 This + // register contains a single SPI + // word received through the serial + // link what ever SPI word length + // is. +#define MCSPI_O_CH3CONF 0x00000168 // 0x4402 1168 0x4402 2168 This + // register is dedicated to the + // configuration of the channel 3 +#define MCSPI_O_CH3STAT 0x0000016C // 0x4402 116C 0x4402 216C This + // register provides status + // information about transmitter and + // receiver registers of channel 3 +#define MCSPI_O_CH3CTRL 0x00000170 // 0x4402 1170 0x4402 2170 This + // register is dedicated to enable + // the channel 3 +#define MCSPI_O_TX3 0x00000174 // 0x4402 1174 0x4402 2174 This + // register contains a single SPI + // word to transmit on the serial + // link what ever SPI word length + // is. +#define MCSPI_O_RX3 0x00000178 // 0x4402 1178 0x4402 2178 This + // register contains a single SPI + // word received through the serial + // link what ever SPI word length + // is. +#define MCSPI_O_XFERLEVEL 0x0000017C // 0x4402 117C 0x4402 217C This + // register provides transfer levels + // needed while using FIFO buffer + // during transfer. +#define MCSPI_O_DAFTX 0x00000180 // 0x4402 1180 0x4402 2180 This + // register contains the SPI words + // to transmit on the serial link + // when FIFO used and DMA address is + // aligned on 256 bit.This register + // is an image of one of MCSPI_TX(i) + // register corresponding to the + // channel which have its FIFO + // enabled. +#define MCSPI_O_DAFRX 0x000001A0 // 0x4402 11A0 0x4402 21A0 This + // register contains the SPI words + // to received on the serial link + // when FIFO used and DMA address is + // aligned on 256 bit.This register + // is an image of one of MCSPI_RX(i) + // register corresponding to the + // channel which have its FIFO + // enabled. + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_HL_REV register. +// +//****************************************************************************** +#define MCSPI_HL_REV_SCHEME_M 0xC0000000 +#define MCSPI_HL_REV_SCHEME_S 30 +#define MCSPI_HL_REV_RSVD_M 0x30000000 // Reserved These bits are + // initialized to zero and writes to + // them are ignored. +#define MCSPI_HL_REV_RSVD_S 28 +#define MCSPI_HL_REV_FUNC_M 0x0FFF0000 // Function indicates a software + // compatible module family. If + // there is no level of software + // compatibility a new Func number + // (and hence REVISION) should be + // assigned. +#define MCSPI_HL_REV_FUNC_S 16 +#define MCSPI_HL_REV_R_RTL_M 0x0000F800 // RTL Version (R) maintained by IP + // design owner. RTL follows a + // numbering such as X.Y.R.Z which + // are explained in this table. R + // changes ONLY when: (1) PDS + // uploads occur which may have been + // due to spec changes (2) Bug fixes + // occur (3) Resets to '0' when X or + // Y changes. Design team has an + // internal 'Z' (customer invisible) + // number which increments on every + // drop that happens due to DV and + // RTL updates. Z resets to 0 when R + // increments. +#define MCSPI_HL_REV_R_RTL_S 11 +#define MCSPI_HL_REV_X_MAJOR_M 0x00000700 // Major Revision (X) maintained by + // IP specification owner. X changes + // ONLY when: (1) There is a major + // feature addition. An example + // would be adding Master Mode to + // Utopia Level2. The Func field (or + // Class/Type in old PID format) + // will remain the same. X does NOT + // change due to: (1) Bug fixes (2) + // Change in feature parameters. +#define MCSPI_HL_REV_X_MAJOR_S 8 +#define MCSPI_HL_REV_CUSTOM_M 0x000000C0 +#define MCSPI_HL_REV_CUSTOM_S 6 +#define MCSPI_HL_REV_Y_MINOR_M 0x0000003F // Minor Revision (Y) maintained by + // IP specification owner. Y changes + // ONLY when: (1) Features are + // scaled (up or down). Flexibility + // exists in that this feature + // scalability may either be + // represented in the Y change or a + // specific register in the IP that + // indicates which features are + // exactly available. (2) When + // feature creeps from Is-Not list + // to Is list. But this may not be + // the case once it sees silicon; in + // which case X will change. Y does + // NOT change due to: (1) Bug fixes + // (2) Typos or clarifications (3) + // major functional/feature + // change/addition/deletion. Instead + // these changes may be reflected + // via R S X as applicable. Spec + // owner maintains a + // customer-invisible number 'S' + // which changes due to: (1) + // Typos/clarifications (2) Bug + // documentation. Note that this bug + // is not due to a spec change but + // due to implementation. + // Nevertheless the spec tracks the + // IP bugs. An RTL release (say for + // silicon PG1.1) that occurs due to + // bug fix should document the + // corresponding spec number (X.Y.S) + // in its release notes. +#define MCSPI_HL_REV_Y_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_HL_HWINFO register. +// +//****************************************************************************** +#define MCSPI_HL_HWINFO_RETMODE 0x00000040 +#define MCSPI_HL_HWINFO_FFNBYTE_M \ + 0x0000003E + +#define MCSPI_HL_HWINFO_FFNBYTE_S 1 +#define MCSPI_HL_HWINFO_USEFIFO 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// MCSPI_O_HL_SYSCONFIG register. +// +//****************************************************************************** +#define MCSPI_HL_SYSCONFIG_IDLEMODE_M \ + 0x0000000C // Configuration of the local + // target state management mode. By + // definition target can handle + // read/write transaction as long as + // it is out of IDLE state. 0x0 + // Force-idle mode: local target's + // idle state follows (acknowledges) + // the system's idle requests + // unconditionally i.e. regardless + // of the IP module's internal + // requirements.Backup mode for + // debug only. 0x1 No-idle mode: + // local target never enters idle + // state.Backup mode for debug only. + // 0x2 Smart-idle mode: local + // target's idle state eventually + // follows (acknowledges) the + // system's idle requests depending + // on the IP module's internal + // requirements.IP module shall not + // generate (IRQ- or + // DMA-request-related) wakeup + // events. 0x3 "Smart-idle + // wakeup-capable mode: local + // target's idle state eventually + // follows (acknowledges) the + // system's idle requests depending + // on the IP module's internal + // requirements.IP module may + // generate (IRQ- or + // DMA-request-related) wakeup + // events when in idle state.Mode is + // only relevant if the appropriate + // IP module ""swakeup"" output(s) + // is (are) implemented." + +#define MCSPI_HL_SYSCONFIG_IDLEMODE_S 2 +#define MCSPI_HL_SYSCONFIG_FREEEMU \ + 0x00000002 // Sensitivity to emulation (debug) + // suspend input signal. 0 IP module + // is sensitive to emulation suspend + // 1 IP module is not sensitive to + // emulation suspend + +#define MCSPI_HL_SYSCONFIG_SOFTRESET \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_REVISION register. +// +//****************************************************************************** +#define MCSPI_REVISION_REV_M 0x000000FF // IP revision [7:4] Major revision + // [3:0] Minor revision Examples: + // 0x10 for 1.0 0x21 for 2.1 +#define MCSPI_REVISION_REV_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_SYSCONFIG register. +// +//****************************************************************************** +#define MCSPI_SYSCONFIG_CLOCKACTIVITY_M \ + 0x00000300 // Clocks activity during wake up + // mode period 0x0 OCP and + // Functional clocks may be switched + // off. 0x1 OCP clock is maintained. + // Functional clock may be + // switched-off. 0x2 Functional + // clock is maintained. OCP clock + // may be switched-off. 0x3 OCP and + // Functional clocks are maintained. + +#define MCSPI_SYSCONFIG_CLOCKACTIVITY_S 8 +#define MCSPI_SYSCONFIG_SIDLEMODE_M \ + 0x00000018 // Power management 0x0 If an idle + // request is detected the McSPI + // acknowledges it unconditionally + // and goes in Inactive mode. + // Interrupt DMA requests and wake + // up lines are unconditionally + // de-asserted and the module wakeup + // capability is deactivated even if + // the bit + // MCSPI_SYSCONFIG[EnaWakeUp] is + // set. 0x1 If an idle request is + // detected the request is ignored + // and the module does not switch to + // wake up mode and keeps on + // behaving normally. 0x2 If an idle + // request is detected the module + // will switch to idle mode based on + // its internal activity. The wake + // up capability cannot be used. 0x3 + // If an idle request is detected + // the module will switch to idle + // mode based on its internal + // activity and the wake up + // capability can be used if the bit + // MCSPI_SYSCONFIG[EnaWakeUp] is + // set. + +#define MCSPI_SYSCONFIG_SIDLEMODE_S 3 +#define MCSPI_SYSCONFIG_ENAWAKEUP \ + 0x00000004 // WakeUp feature control 0 WakeUp + // capability is disabled 1 WakeUp + // capability is enabled + +#define MCSPI_SYSCONFIG_SOFTRESET \ + 0x00000002 // Software reset. During reads it + // always returns 0. 0 (write) + // Normal mode 1 (write) Set this + // bit to 1 to trigger a module + // reset.The bit is automatically + // reset by the hardware. + +#define MCSPI_SYSCONFIG_AUTOIDLE \ + 0x00000001 // Internal OCP Clock gating + // strategy 0 OCP clock is + // free-running 1 Automatic OCP + // clock gating strategy is applied + // based on the OCP interface + // activity + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_SYSSTATUS register. +// +//****************************************************************************** +#define MCSPI_SYSSTATUS_RESETDONE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_IRQSTATUS register. +// +//****************************************************************************** +#define MCSPI_IRQSTATUS_EOW 0x00020000 +#define MCSPI_IRQSTATUS_WKS 0x00010000 +#define MCSPI_IRQSTATUS_RX3_FULL \ + 0x00004000 + +#define MCSPI_IRQSTATUS_TX3_UNDERFLOW \ + 0x00002000 + +#define MCSPI_IRQSTATUS_TX3_EMPTY \ + 0x00001000 + +#define MCSPI_IRQSTATUS_RX2_FULL \ + 0x00000400 + +#define MCSPI_IRQSTATUS_TX2_UNDERFLOW \ + 0x00000200 + +#define MCSPI_IRQSTATUS_TX2_EMPTY \ + 0x00000100 + +#define MCSPI_IRQSTATUS_RX1_FULL \ + 0x00000040 + +#define MCSPI_IRQSTATUS_TX1_UNDERFLOW \ + 0x00000020 + +#define MCSPI_IRQSTATUS_TX1_EMPTY \ + 0x00000010 + +#define MCSPI_IRQSTATUS_RX0_OVERFLOW \ + 0x00000008 + +#define MCSPI_IRQSTATUS_RX0_FULL \ + 0x00000004 + +#define MCSPI_IRQSTATUS_TX0_UNDERFLOW \ + 0x00000002 + +#define MCSPI_IRQSTATUS_TX0_EMPTY \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_IRQENABLE register. +// +//****************************************************************************** +#define MCSPI_IRQENABLE_EOW_ENABLE \ + 0x00020000 // End of Word count Interrupt + // Enable. 0 Interrupt disabled 1 + // Interrupt enabled + +#define MCSPI_IRQENABLE_WKE 0x00010000 // Wake Up event interrupt Enable + // in slave mode when an active + // control signal is detected on the + // SPIEN line programmed in the + // field MCSPI_CH0CONF[SPIENSLV] 0 + // Interrupt disabled 1 Interrupt + // enabled +#define MCSPI_IRQENABLE_RX3_FULL_ENABLE \ + 0x00004000 // Receiver register Full Interrupt + // Enable. Ch 3 0 Interrupt disabled + // 1 Interrupt enabled + +#define MCSPI_IRQENABLE_TX3_UNDERFLOW_ENABLE \ + 0x00002000 // Transmitter register Underflow + // Interrupt Enable. Ch 3 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_TX3_EMPTY_ENABLE \ + 0x00001000 // Transmitter register Empty + // Interrupt Enable. Ch3 0 Interrupt + // disabled 1 Interrupt enabled + +#define MCSPI_IRQENABLE_RX2_FULL_ENABLE \ + 0x00000400 // Receiver register Full Interrupt + // Enable. Ch 2 0 Interrupt disabled + // 1 Interrupt enabled + +#define MCSPI_IRQENABLE_TX2_UNDERFLOW_ENABLE \ + 0x00000200 // Transmitter register Underflow + // Interrupt Enable. Ch 2 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_TX2_EMPTY_ENABLE \ + 0x00000100 // Transmitter register Empty + // Interrupt Enable. Ch 2 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_RX1_FULL_ENABLE \ + 0x00000040 // Receiver register Full Interrupt + // Enable. Ch 1 0 Interrupt disabled + // 1 Interrupt enabled + +#define MCSPI_IRQENABLE_TX1_UNDERFLOW_ENABLE \ + 0x00000020 // Transmitter register Underflow + // Interrupt Enable. Ch 1 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_TX1_EMPTY_ENABLE \ + 0x00000010 // Transmitter register Empty + // Interrupt Enable. Ch 1 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_RX0_OVERFLOW_ENABLE \ + 0x00000008 // Receiver register Overflow + // Interrupt Enable. Ch 0 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_RX0_FULL_ENABLE \ + 0x00000004 // Receiver register Full Interrupt + // Enable. Ch 0 0 Interrupt disabled + // 1 Interrupt enabled + +#define MCSPI_IRQENABLE_TX0_UNDERFLOW_ENABLE \ + 0x00000002 // Transmitter register Underflow + // Interrupt Enable. Ch 0 0 + // Interrupt disabled 1 Interrupt + // enabled + +#define MCSPI_IRQENABLE_TX0_EMPTY_ENABLE \ + 0x00000001 // Transmitter register Empty + // Interrupt Enable. Ch 0 0 + // Interrupt disabled 1 Interrupt + // enabled + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// MCSPI_O_WAKEUPENABLE register. +// +//****************************************************************************** +#define MCSPI_WAKEUPENABLE_WKEN 0x00000001 // WakeUp functionality in slave + // mode when an active control + // signal is detected on the SPIEN + // line programmed in the field + // MCSPI_CH0CONF[SPIENSLV] 0 The + // event is not allowed to wakeup + // the system even if the global + // control bit + // MCSPI_SYSCONF[EnaWakeUp] is set. + // 1 The event is allowed to wakeup + // the system if the global control + // bit MCSPI_SYSCONF[EnaWakeUp] is + // set. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_SYST register. +// +//****************************************************************************** +#define MCSPI_SYST_SSB 0x00000800 // Set status bit 0 No action. + // Writing 0 does not clear already + // set status bits; This bit must be + // cleared prior attempting to clear + // a status bit of the + // register. 1 + // Force to 1 all status bits of + // MCSPI_IRQSTATUS register. Writing + // 1 into this bit sets to 1 all + // status bits contained in the + // register. +#define MCSPI_SYST_SPIENDIR 0x00000400 // Set the direction of the + // SPIEN[3:0] lines and SPICLK line + // 0 output (as in master mode) 1 + // input (as in slave mode) +#define MCSPI_SYST_SPIDATDIR1 0x00000200 // Set the direction of the + // SPIDAT[1] 0 output 1 input +#define MCSPI_SYST_SPIDATDIR0 0x00000100 // Set the direction of the + // SPIDAT[0] 0 output 1 input +#define MCSPI_SYST_WAKD 0x00000080 // SWAKEUP output (signal data + // value of internal signal to + // system). The signal is driven + // high or low according to the + // value written into this register + // bit. 0 The pin is driven low. 1 + // The pin is driven high. +#define MCSPI_SYST_SPICLK 0x00000040 // SPICLK line (signal data value) + // If MCSPI_SYST[SPIENDIR] = 1 + // (input mode direction) this bit + // returns the value on the CLKSPI + // line (high or low) and a write + // into this bit has no effect. If + // MCSPI_SYST[SPIENDIR] = 0 (output + // mode direction) the CLKSPI line + // is driven high or low according + // to the value written into this + // register. +#define MCSPI_SYST_SPIDAT_1 0x00000020 // SPIDAT[1] line (signal data + // value) If MCSPI_SYST[SPIDATDIR1] + // = 0 (output mode direction) the + // SPIDAT[1] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIDATDIR1] = 1 (input + // mode direction) this bit returns + // the value on the SPIDAT[1] line + // (high or low) and a write into + // this bit has no effect. +#define MCSPI_SYST_SPIDAT_0 0x00000010 // SPIDAT[0] line (signal data + // value) If MCSPI_SYST[SPIDATDIR0] + // = 0 (output mode direction) the + // SPIDAT[0] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIDATDIR0] = 1 (input + // mode direction) this bit returns + // the value on the SPIDAT[0] line + // (high or low) and a write into + // this bit has no effect. +#define MCSPI_SYST_SPIEN_3 0x00000008 // SPIEN[3] line (signal data + // value) If MCSPI_SYST[SPIENDIR] = + // 0 (output mode direction) the + // SPIENT[3] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIENDIR] = 1 (input + // mode direction) this bit returns + // the value on the SPIEN[3] line + // (high or low) and a write into + // this bit has no effect. +#define MCSPI_SYST_SPIEN_2 0x00000004 // SPIEN[2] line (signal data + // value) If MCSPI_SYST[SPIENDIR] = + // 0 (output mode direction) the + // SPIENT[2] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIENDIR] = 1 (input + // mode direction) this bit returns + // the value on the SPIEN[2] line + // (high or low) and a write into + // this bit has no effect. +#define MCSPI_SYST_SPIEN_1 0x00000002 // SPIEN[1] line (signal data + // value) If MCSPI_SYST[SPIENDIR] = + // 0 (output mode direction) the + // SPIENT[1] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIENDIR] = 1 (input + // mode direction) this bit returns + // the value on the SPIEN[1] line + // (high or low) and a write into + // this bit has no effect. +#define MCSPI_SYST_SPIEN_0 0x00000001 // SPIEN[0] line (signal data + // value) If MCSPI_SYST[SPIENDIR] = + // 0 (output mode direction) the + // SPIENT[0] line is driven high or + // low according to the value + // written into this register. If + // MCSPI_SYST[SPIENDIR] = 1 (input + // mode direction) this bit returns + // the value on the SPIEN[0] line + // (high or low) and a write into + // this bit has no effect. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_MODULCTRL register. +// +//****************************************************************************** +#define MCSPI_MODULCTRL_FDAA 0x00000100 // FIFO DMA Address 256-bit aligned + // This register is used when a FIFO + // is managed by the module and DMA + // connected to the controller + // provides only 256 bit aligned + // address. If this bit is set the + // enabled channel which uses the + // FIFO has its datas managed + // through MCSPI_DAFTX and + // MCSPI_DAFRX registers instead of + // MCSPI_TX(i) and MCSPI_RX(i) + // registers. 0 FIFO data managed by + // MCSPI_TX(i) and MCSPI_RX(i) + // registers. 1 FIFO data managed by + // MCSPI_DAFTX and MCSPI_DAFRX + // registers. +#define MCSPI_MODULCTRL_MOA 0x00000080 // Multiple word ocp access: This + // register can only be used when a + // channel is enabled using a FIFO. + // It allows the system to perform + // multiple SPI word access for a + // single 32-bit OCP word access. + // This is possible for WL < 16. 0 + // Multiple word access disabled 1 + // Multiple word access enabled with + // FIFO +#define MCSPI_MODULCTRL_INITDLY_M \ + 0x00000070 // Initial spi delay for first + // transfer: This register is an + // option only available in SINGLE + // master mode The controller waits + // for a delay to transmit the first + // spi word after channel enabled + // and corresponding TX register + // filled. This Delay is based on + // SPI output frequency clock No + // clock output provided to the + // boundary and chip select is not + // active in 4 pin mode within this + // period. 0x0 No delay for first + // spi transfer. 0x1 The controller + // wait 4 spi bus clock 0x2 The + // controller wait 8 spi bus clock + // 0x3 The controller wait 16 spi + // bus clock 0x4 The controller wait + // 32 spi bus clock + +#define MCSPI_MODULCTRL_INITDLY_S 4 +#define MCSPI_MODULCTRL_SYSTEM_TEST \ + 0x00000008 // Enables the system test mode 0 + // Functional mode 1 System test + // mode (SYSTEST) + +#define MCSPI_MODULCTRL_MS 0x00000004 // Master/ Slave 0 Master - The + // module generates the SPICLK and + // SPIEN[3:0] 1 Slave - The module + // receives the SPICLK and + // SPIEN[3:0] +#define MCSPI_MODULCTRL_PIN34 0x00000002 // Pin mode selection: This + // register is used to configure the + // SPI pin mode in master or slave + // mode. If asserted the controller + // only use SIMOSOMI and SPICLK + // clock pin for spi transfers. 0 + // SPIEN is used as a chip select. 1 + // SPIEN is not used.In this mode + // all related option to chip select + // have no meaning. +#define MCSPI_MODULCTRL_SINGLE 0x00000001 // Single channel / Multi Channel + // (master mode only) 0 More than + // one channel will be used in + // master mode. 1 Only one channel + // will be used in master mode. This + // bit must be set in Force SPIEN + // mode. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH0CONF register. +// +//****************************************************************************** +#define MCSPI_CH0CONF_CLKG 0x20000000 // Clock divider granularity This + // register defines the granularity + // of channel clock divider: power + // of two or one clock cycle + // granularity. When this bit is set + // the register MCSPI_CHCTRL[EXTCLK] + // must be configured to reach a + // maximum of 4096 clock divider + // ratio. Then The clock divider + // ratio is a concatenation of + // MCSPI_CHCONF[CLKD] and + // MCSPI_CHCTRL[EXTCLK] values 0 + // Clock granularity of power of two + // 1 One clock cycle ganularity +#define MCSPI_CH0CONF_FFER 0x10000000 // FIFO enabled for receive:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to receive data. 1 The + // buffer is used to receive data. +#define MCSPI_CH0CONF_FFEW 0x08000000 // FIFO enabled for Transmit:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to transmit data. 1 The + // buffer is used to transmit data. +#define MCSPI_CH0CONF_TCS0_M 0x06000000 // Chip Select Time Control This + // 2-bits field defines the number + // of interface clock cycles between + // CS toggling and first or last + // edge of SPI clock. 0x0 0.5 clock + // cycle 0x1 1.5 clock cycle 0x2 2.5 + // clock cycle 0x3 3.5 clock cycle +#define MCSPI_CH0CONF_TCS0_S 25 +#define MCSPI_CH0CONF_SBPOL 0x01000000 // Start bit polarity 0 Start bit + // polarity is held to 0 during SPI + // transfer. 1 Start bit polarity is + // held to 1 during SPI transfer. +#define MCSPI_CH0CONF_SBE 0x00800000 // Start bit enable for SPI + // transfer 0 Default SPI transfer + // length as specified by WL bit + // field 1 Start bit D/CX added + // before SPI transfer polarity is + // defined by MCSPI_CH0CONF[SBPOL] +#define MCSPI_CH0CONF_SPIENSLV_M \ + 0x00600000 // Channel 0 only and slave mode + // only: SPI slave select signal + // detection. Reserved bits for + // other cases. 0x0 Detection + // enabled only on SPIEN[0] 0x1 + // Detection enabled only on + // SPIEN[1] 0x2 Detection enabled + // only on SPIEN[2] 0x3 Detection + // enabled only on SPIEN[3] + +#define MCSPI_CH0CONF_SPIENSLV_S 21 +#define MCSPI_CH0CONF_FORCE 0x00100000 // Manual SPIEN assertion to keep + // SPIEN active between SPI words. + // (single channel master mode only) + // 0 Writing 0 into this bit drives + // low the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it high when + // MCSPI_CHCONF(i)[EPOL]=1. 1 + // Writing 1 into this bit drives + // high the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it low when + // MCSPI_CHCONF(i)[EPOL]=1 +#define MCSPI_CH0CONF_TURBO 0x00080000 // Turbo mode 0 Turbo is + // deactivated (recommended for + // single SPI word transfer) 1 Turbo + // is activated to maximize the + // throughput for multi SPI words + // transfer. +#define MCSPI_CH0CONF_IS 0x00040000 // Input Select 0 Data Line0 + // (SPIDAT[0]) selected for + // reception. 1 Data Line1 + // (SPIDAT[1]) selected for + // reception +#define MCSPI_CH0CONF_DPE1 0x00020000 // Transmission Enable for data + // line 1 (SPIDATAGZEN[1]) 0 Data + // Line1 (SPIDAT[1]) selected for + // transmission 1 No transmission on + // Data Line1 (SPIDAT[1]) +#define MCSPI_CH0CONF_DPE0 0x00010000 // Transmission Enable for data + // line 0 (SPIDATAGZEN[0]) 0 Data + // Line0 (SPIDAT[0]) selected for + // transmission 1 No transmission on + // Data Line0 (SPIDAT[0]) +#define MCSPI_CH0CONF_DMAR 0x00008000 // DMA Read request The DMA Read + // request line is asserted when the + // channel is enabled and a new data + // is available in the receive + // register of the channel. The DMA + // Read request line is deasserted + // on read completion of the receive + // register of the channel. 0 DMA + // Read Request disabled 1 DMA Read + // Request enabled +#define MCSPI_CH0CONF_DMAW 0x00004000 // DMA Write request. The DMA Write + // request line is asserted when The + // channel is enabled and the + // transmitter register of the + // channel is empty. The DMA Write + // request line is deasserted on + // load completion of the + // transmitter register of the + // channel. 0 DMA Write Request + // disabled 1 DMA Write Request + // enabled +#define MCSPI_CH0CONF_TRM_M 0x00003000 // Transmit/Receive modes 0x0 + // Transmit and Receive mode 0x1 + // Receive only mode 0x2 Transmit + // only mode 0x3 Reserved +#define MCSPI_CH0CONF_TRM_S 12 +#define MCSPI_CH0CONF_WL_M 0x00000F80 // SPI word length 0x00 Reserved + // 0x01 Reserved 0x02 Reserved 0x03 + // The SPI word is 4-bits long 0x04 + // The SPI word is 5-bits long 0x05 + // The SPI word is 6-bits long 0x06 + // The SPI word is 7-bits long 0x07 + // The SPI word is 8-bits long 0x08 + // The SPI word is 9-bits long 0x09 + // The SPI word is 10-bits long 0x0A + // The SPI word is 11-bits long 0x0B + // The SPI word is 12-bits long 0x0C + // The SPI word is 13-bits long 0x0D + // The SPI word is 14-bits long 0x0E + // The SPI word is 15-bits long 0x0F + // The SPI word is 16-bits long 0x10 + // The SPI word is 17-bits long 0x11 + // The SPI word is 18-bits long 0x12 + // The SPI word is 19-bits long 0x13 + // The SPI word is 20-bits long 0x14 + // The SPI word is 21-bits long 0x15 + // The SPI word is 22-bits long 0x16 + // The SPI word is 23-bits long 0x17 + // The SPI word is 24-bits long 0x18 + // The SPI word is 25-bits long 0x19 + // The SPI word is 26-bits long 0x1A + // The SPI word is 27-bits long 0x1B + // The SPI word is 28-bits long 0x1C + // The SPI word is 29-bits long 0x1D + // The SPI word is 30-bits long 0x1E + // The SPI word is 31-bits long 0x1F + // The SPI word is 32-bits long +#define MCSPI_CH0CONF_WL_S 7 +#define MCSPI_CH0CONF_EPOL 0x00000040 // SPIEN polarity 0 SPIEN is held + // high during the active state. 1 + // SPIEN is held low during the + // active state. +#define MCSPI_CH0CONF_CLKD_M 0x0000003C // Frequency divider for SPICLK. + // (only when the module is a Master + // SPI device). A programmable clock + // divider divides the SPI reference + // clock (CLKSPIREF) with a 4-bit + // value and results in a new clock + // SPICLK available to shift-in and + // shift-out data. By default the + // clock divider ratio has a power + // of two granularity when + // MCSPI_CHCONF[CLKG] is cleared + // Otherwise this register is the 4 + // LSB bit of a 12-bit register + // concatenated with clock divider + // extension MCSPI_CHCTRL[EXTCLK] + // register.The value description + // below defines the clock ratio + // when MCSPI_CHCONF[CLKG] is set to + // 0. 0x0 1 0x1 2 0x2 4 0x3 8 0x4 16 + // 0x5 32 0x6 64 0x7 128 0x8 256 0x9 + // 512 0xA 1024 0xB 2048 0xC 4096 + // 0xD 8192 0xE 16384 0xF 32768 +#define MCSPI_CH0CONF_CLKD_S 2 +#define MCSPI_CH0CONF_POL 0x00000002 // SPICLK polarity 0 SPICLK is held + // high during the active state 1 + // SPICLK is held low during the + // active state +#define MCSPI_CH0CONF_PHA 0x00000001 // SPICLK phase 0 Data are latched + // on odd numbered edges of SPICLK. + // 1 Data are latched on even + // numbered edges of SPICLK. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH0STAT register. +// +//****************************************************************************** +#define MCSPI_CH0STAT_RXFFF 0x00000040 +#define MCSPI_CH0STAT_RXFFE 0x00000020 +#define MCSPI_CH0STAT_TXFFF 0x00000010 +#define MCSPI_CH0STAT_TXFFE 0x00000008 +#define MCSPI_CH0STAT_EOT 0x00000004 +#define MCSPI_CH0STAT_TXS 0x00000002 +#define MCSPI_CH0STAT_RXS 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH0CTRL register. +// +//****************************************************************************** +#define MCSPI_CH0CTRL_EXTCLK_M 0x0000FF00 // Clock ratio extension: This + // register is used to concatenate + // with MCSPI_CHCONF[CLKD] register + // for clock ratio only when + // granularity is one clock cycle + // (MCSPI_CHCONF[CLKG] set to 1). + // Then the max value reached is + // 4096 clock divider ratio. 0x00 + // Clock ratio is CLKD + 1 0x01 + // Clock ratio is CLKD + 1 + 16 0xFF + // Clock ratio is CLKD + 1 + 4080 +#define MCSPI_CH0CTRL_EXTCLK_S 8 +#define MCSPI_CH0CTRL_EN 0x00000001 // Channel Enable 0 "Channel ""i"" + // is not active" 1 "Channel ""i"" + // is active" +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_TX0 register. +// +//****************************************************************************** +#define MCSPI_TX0_TDATA_M 0xFFFFFFFF // Channel 0 Data to transmit +#define MCSPI_TX0_TDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_RX0 register. +// +//****************************************************************************** +#define MCSPI_RX0_RDATA_M 0xFFFFFFFF // Channel 0 Received Data +#define MCSPI_RX0_RDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH1CONF register. +// +//****************************************************************************** +#define MCSPI_CH1CONF_CLKG 0x20000000 // Clock divider granularity This + // register defines the granularity + // of channel clock divider: power + // of two or one clock cycle + // granularity. When this bit is set + // the register MCSPI_CHCTRL[EXTCLK] + // must be configured to reach a + // maximum of 4096 clock divider + // ratio. Then The clock divider + // ratio is a concatenation of + // MCSPI_CHCONF[CLKD] and + // MCSPI_CHCTRL[EXTCLK] values 0 + // Clock granularity of power of two + // 1 One clock cycle ganularity +#define MCSPI_CH1CONF_FFER 0x10000000 // FIFO enabled for receive:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to receive data. 1 The + // buffer is used to receive data. +#define MCSPI_CH1CONF_FFEW 0x08000000 // FIFO enabled for Transmit:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to transmit data. 1 The + // buffer is used to transmit data. +#define MCSPI_CH1CONF_TCS1_M 0x06000000 // Chip Select Time Control This + // 2-bits field defines the number + // of interface clock cycles between + // CS toggling and first or last + // edge of SPI clock. 0x0 0.5 clock + // cycle 0x1 1.5 clock cycle 0x2 2.5 + // clock cycle 0x3 3.5 clock cycle +#define MCSPI_CH1CONF_TCS1_S 25 +#define MCSPI_CH1CONF_SBPOL 0x01000000 // Start bit polarity 0 Start bit + // polarity is held to 0 during SPI + // transfer. 1 Start bit polarity is + // held to 1 during SPI transfer. +#define MCSPI_CH1CONF_SBE 0x00800000 // Start bit enable for SPI + // transfer 0 Default SPI transfer + // length as specified by WL bit + // field 1 Start bit D/CX added + // before SPI transfer polarity is + // defined by MCSPI_CH1CONF[SBPOL] +#define MCSPI_CH1CONF_FORCE 0x00100000 // Manual SPIEN assertion to keep + // SPIEN active between SPI words. + // (single channel master mode only) + // 0 Writing 0 into this bit drives + // low the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it high when + // MCSPI_CHCONF(i)[EPOL]=1. 1 + // Writing 1 into this bit drives + // high the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it low when + // MCSPI_CHCONF(i)[EPOL]=1 +#define MCSPI_CH1CONF_TURBO 0x00080000 // Turbo mode 0 Turbo is + // deactivated (recommended for + // single SPI word transfer) 1 Turbo + // is activated to maximize the + // throughput for multi SPI words + // transfer. +#define MCSPI_CH1CONF_IS 0x00040000 // Input Select 0 Data Line0 + // (SPIDAT[0]) selected for + // reception. 1 Data Line1 + // (SPIDAT[1]) selected for + // reception +#define MCSPI_CH1CONF_DPE1 0x00020000 // Transmission Enable for data + // line 1 (SPIDATAGZEN[1]) 0 Data + // Line1 (SPIDAT[1]) selected for + // transmission 1 No transmission on + // Data Line1 (SPIDAT[1]) +#define MCSPI_CH1CONF_DPE0 0x00010000 // Transmission Enable for data + // line 0 (SPIDATAGZEN[0]) 0 Data + // Line0 (SPIDAT[0]) selected for + // transmission 1 No transmission on + // Data Line0 (SPIDAT[0]) +#define MCSPI_CH1CONF_DMAR 0x00008000 // DMA Read request The DMA Read + // request line is asserted when the + // channel is enabled and a new data + // is available in the receive + // register of the channel. The DMA + // Read request line is deasserted + // on read completion of the receive + // register of the channel. 0 DMA + // Read Request disabled 1 DMA Read + // Request enabled +#define MCSPI_CH1CONF_DMAW 0x00004000 // DMA Write request. The DMA Write + // request line is asserted when The + // channel is enabled and the + // transmitter register of the + // channel is empty. The DMA Write + // request line is deasserted on + // load completion of the + // transmitter register of the + // channel. 0 DMA Write Request + // disabled 1 DMA Write Request + // enabled +#define MCSPI_CH1CONF_TRM_M 0x00003000 // Transmit/Receive modes 0x0 + // Transmit and Receive mode 0x1 + // Receive only mode 0x2 Transmit + // only mode 0x3 Reserved +#define MCSPI_CH1CONF_TRM_S 12 +#define MCSPI_CH1CONF_WL_M 0x00000F80 // SPI word length 0x00 Reserved + // 0x01 Reserved 0x02 Reserved 0x03 + // The SPI word is 4-bits long 0x04 + // The SPI word is 5-bits long 0x05 + // The SPI word is 6-bits long 0x06 + // The SPI word is 7-bits long 0x07 + // The SPI word is 8-bits long 0x08 + // The SPI word is 9-bits long 0x09 + // The SPI word is 10-bits long 0x0A + // The SPI word is 11-bits long 0x0B + // The SPI word is 12-bits long 0x0C + // The SPI word is 13-bits long 0x0D + // The SPI word is 14-bits long 0x0E + // The SPI word is 15-bits long 0x0F + // The SPI word is 16-bits long 0x10 + // The SPI word is 17-bits long 0x11 + // The SPI word is 18-bits long 0x12 + // The SPI word is 19-bits long 0x13 + // The SPI word is 20-bits long 0x14 + // The SPI word is 21-bits long 0x15 + // The SPI word is 22-bits long 0x16 + // The SPI word is 23-bits long 0x17 + // The SPI word is 24-bits long 0x18 + // The SPI word is 25-bits long 0x19 + // The SPI word is 26-bits long 0x1A + // The SPI word is 27-bits long 0x1B + // The SPI word is 28-bits long 0x1C + // The SPI word is 29-bits long 0x1D + // The SPI word is 30-bits long 0x1E + // The SPI word is 31-bits long 0x1F + // The SPI word is 32-bits long +#define MCSPI_CH1CONF_WL_S 7 +#define MCSPI_CH1CONF_EPOL 0x00000040 // SPIEN polarity 0 SPIEN is held + // high during the active state. 1 + // SPIEN is held low during the + // active state. +#define MCSPI_CH1CONF_CLKD_M 0x0000003C // Frequency divider for SPICLK. + // (only when the module is a Master + // SPI device). A programmable clock + // divider divides the SPI reference + // clock (CLKSPIREF) with a 4-bit + // value and results in a new clock + // SPICLK available to shift-in and + // shift-out data. By default the + // clock divider ratio has a power + // of two granularity when + // MCSPI_CHCONF[CLKG] is cleared + // Otherwise this register is the 4 + // LSB bit of a 12-bit register + // concatenated with clock divider + // extension MCSPI_CHCTRL[EXTCLK] + // register.The value description + // below defines the clock ratio + // when MCSPI_CHCONF[CLKG] is set to + // 0. 0x0 1 0x1 2 0x2 4 0x3 8 0x4 16 + // 0x5 32 0x6 64 0x7 128 0x8 256 0x9 + // 512 0xA 1024 0xB 2048 0xC 4096 + // 0xD 8192 0xE 16384 0xF 32768 +#define MCSPI_CH1CONF_CLKD_S 2 +#define MCSPI_CH1CONF_POL 0x00000002 // SPICLK polarity 0 SPICLK is held + // high during the active state 1 + // SPICLK is held low during the + // active state +#define MCSPI_CH1CONF_PHA 0x00000001 // SPICLK phase 0 Data are latched + // on odd numbered edges of SPICLK. + // 1 Data are latched on even + // numbered edges of SPICLK. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH1STAT register. +// +//****************************************************************************** +#define MCSPI_CH1STAT_RXFFF 0x00000040 +#define MCSPI_CH1STAT_RXFFE 0x00000020 +#define MCSPI_CH1STAT_TXFFF 0x00000010 +#define MCSPI_CH1STAT_TXFFE 0x00000008 +#define MCSPI_CH1STAT_EOT 0x00000004 +#define MCSPI_CH1STAT_TXS 0x00000002 +#define MCSPI_CH1STAT_RXS 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH1CTRL register. +// +//****************************************************************************** +#define MCSPI_CH1CTRL_EXTCLK_M 0x0000FF00 // Clock ratio extension: This + // register is used to concatenate + // with MCSPI_CHCONF[CLKD] register + // for clock ratio only when + // granularity is one clock cycle + // (MCSPI_CHCONF[CLKG] set to 1). + // Then the max value reached is + // 4096 clock divider ratio. 0x00 + // Clock ratio is CLKD + 1 0x01 + // Clock ratio is CLKD + 1 + 16 0xFF + // Clock ratio is CLKD + 1 + 4080 +#define MCSPI_CH1CTRL_EXTCLK_S 8 +#define MCSPI_CH1CTRL_EN 0x00000001 // Channel Enable 0 "Channel ""i"" + // is not active" 1 "Channel ""i"" + // is active" +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_TX1 register. +// +//****************************************************************************** +#define MCSPI_TX1_TDATA_M 0xFFFFFFFF // Channel 1 Data to transmit +#define MCSPI_TX1_TDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_RX1 register. +// +//****************************************************************************** +#define MCSPI_RX1_RDATA_M 0xFFFFFFFF // Channel 1 Received Data +#define MCSPI_RX1_RDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH2CONF register. +// +//****************************************************************************** +#define MCSPI_CH2CONF_CLKG 0x20000000 // Clock divider granularity This + // register defines the granularity + // of channel clock divider: power + // of two or one clock cycle + // granularity. When this bit is set + // the register MCSPI_CHCTRL[EXTCLK] + // must be configured to reach a + // maximum of 4096 clock divider + // ratio. Then The clock divider + // ratio is a concatenation of + // MCSPI_CHCONF[CLKD] and + // MCSPI_CHCTRL[EXTCLK] values 0 + // Clock granularity of power of two + // 1 One clock cycle ganularity +#define MCSPI_CH2CONF_FFER 0x10000000 // FIFO enabled for receive:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to receive data. 1 The + // buffer is used to receive data. +#define MCSPI_CH2CONF_FFEW 0x08000000 // FIFO enabled for Transmit:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to transmit data. 1 The + // buffer is used to transmit data. +#define MCSPI_CH2CONF_TCS2_M 0x06000000 // Chip Select Time Control This + // 2-bits field defines the number + // of interface clock cycles between + // CS toggling and first or last + // edge of SPI clock. 0x0 0.5 clock + // cycle 0x1 1.5 clock cycle 0x2 2.5 + // clock cycle 0x3 3.5 clock cycle +#define MCSPI_CH2CONF_TCS2_S 25 +#define MCSPI_CH2CONF_SBPOL 0x01000000 // Start bit polarity 0 Start bit + // polarity is held to 0 during SPI + // transfer. 1 Start bit polarity is + // held to 1 during SPI transfer. +#define MCSPI_CH2CONF_SBE 0x00800000 // Start bit enable for SPI + // transfer 0 Default SPI transfer + // length as specified by WL bit + // field 1 Start bit D/CX added + // before SPI transfer polarity is + // defined by MCSPI_CH2CONF[SBPOL] +#define MCSPI_CH2CONF_FORCE 0x00100000 // Manual SPIEN assertion to keep + // SPIEN active between SPI words. + // (single channel master mode only) + // 0 Writing 0 into this bit drives + // low the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it high when + // MCSPI_CHCONF(i)[EPOL]=1. 1 + // Writing 1 into this bit drives + // high the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it low when + // MCSPI_CHCONF(i)[EPOL]=1 +#define MCSPI_CH2CONF_TURBO 0x00080000 // Turbo mode 0 Turbo is + // deactivated (recommended for + // single SPI word transfer) 1 Turbo + // is activated to maximize the + // throughput for multi SPI words + // transfer. +#define MCSPI_CH2CONF_IS 0x00040000 // Input Select 0 Data Line0 + // (SPIDAT[0]) selected for + // reception. 1 Data Line1 + // (SPIDAT[1]) selected for + // reception +#define MCSPI_CH2CONF_DPE1 0x00020000 // Transmission Enable for data + // line 1 (SPIDATAGZEN[1]) 0 Data + // Line1 (SPIDAT[1]) selected for + // transmission 1 No transmission on + // Data Line1 (SPIDAT[1]) +#define MCSPI_CH2CONF_DPE0 0x00010000 // Transmission Enable for data + // line 0 (SPIDATAGZEN[0]) 0 Data + // Line0 (SPIDAT[0]) selected for + // transmission 1 No transmission on + // Data Line0 (SPIDAT[0]) +#define MCSPI_CH2CONF_DMAR 0x00008000 // DMA Read request The DMA Read + // request line is asserted when the + // channel is enabled and a new data + // is available in the receive + // register of the channel. The DMA + // Read request line is deasserted + // on read completion of the receive + // register of the channel. 0 DMA + // Read Request disabled 1 DMA Read + // Request enabled +#define MCSPI_CH2CONF_DMAW 0x00004000 // DMA Write request. The DMA Write + // request line is asserted when The + // channel is enabled and the + // transmitter register of the + // channel is empty. The DMA Write + // request line is deasserted on + // load completion of the + // transmitter register of the + // channel. 0 DMA Write Request + // disabled 1 DMA Write Request + // enabled +#define MCSPI_CH2CONF_TRM_M 0x00003000 // Transmit/Receive modes 0x0 + // Transmit and Receive mode 0x1 + // Receive only mode 0x2 Transmit + // only mode 0x3 Reserved +#define MCSPI_CH2CONF_TRM_S 12 +#define MCSPI_CH2CONF_WL_M 0x00000F80 // SPI word length 0x00 Reserved + // 0x01 Reserved 0x02 Reserved 0x03 + // The SPI word is 4-bits long 0x04 + // The SPI word is 5-bits long 0x05 + // The SPI word is 6-bits long 0x06 + // The SPI word is 7-bits long 0x07 + // The SPI word is 8-bits long 0x08 + // The SPI word is 9-bits long 0x09 + // The SPI word is 10-bits long 0x0A + // The SPI word is 11-bits long 0x0B + // The SPI word is 12-bits long 0x0C + // The SPI word is 13-bits long 0x0D + // The SPI word is 14-bits long 0x0E + // The SPI word is 15-bits long 0x0F + // The SPI word is 16-bits long 0x10 + // The SPI word is 17-bits long 0x11 + // The SPI word is 18-bits long 0x12 + // The SPI word is 19-bits long 0x13 + // The SPI word is 20-bits long 0x14 + // The SPI word is 21-bits long 0x15 + // The SPI word is 22-bits long 0x16 + // The SPI word is 23-bits long 0x17 + // The SPI word is 24-bits long 0x18 + // The SPI word is 25-bits long 0x19 + // The SPI word is 26-bits long 0x1A + // The SPI word is 27-bits long 0x1B + // The SPI word is 28-bits long 0x1C + // The SPI word is 29-bits long 0x1D + // The SPI word is 30-bits long 0x1E + // The SPI word is 31-bits long 0x1F + // The SPI word is 32-bits long +#define MCSPI_CH2CONF_WL_S 7 +#define MCSPI_CH2CONF_EPOL 0x00000040 // SPIEN polarity 0 SPIEN is held + // high during the active state. 1 + // SPIEN is held low during the + // active state. +#define MCSPI_CH2CONF_CLKD_M 0x0000003C // Frequency divider for SPICLK. + // (only when the module is a Master + // SPI device). A programmable clock + // divider divides the SPI reference + // clock (CLKSPIREF) with a 4-bit + // value and results in a new clock + // SPICLK available to shift-in and + // shift-out data. By default the + // clock divider ratio has a power + // of two granularity when + // MCSPI_CHCONF[CLKG] is cleared + // Otherwise this register is the 4 + // LSB bit of a 12-bit register + // concatenated with clock divider + // extension MCSPI_CHCTRL[EXTCLK] + // register.The value description + // below defines the clock ratio + // when MCSPI_CHCONF[CLKG] is set to + // 0. 0x0 1 0x1 2 0x2 4 0x3 8 0x4 16 + // 0x5 32 0x6 64 0x7 128 0x8 256 0x9 + // 512 0xA 1024 0xB 2048 0xC 4096 + // 0xD 8192 0xE 16384 0xF 32768 +#define MCSPI_CH2CONF_CLKD_S 2 +#define MCSPI_CH2CONF_POL 0x00000002 // SPICLK polarity 0 SPICLK is held + // high during the active state 1 + // SPICLK is held low during the + // active state +#define MCSPI_CH2CONF_PHA 0x00000001 // SPICLK phase 0 Data are latched + // on odd numbered edges of SPICLK. + // 1 Data are latched on even + // numbered edges of SPICLK. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH2STAT register. +// +//****************************************************************************** +#define MCSPI_CH2STAT_RXFFF 0x00000040 +#define MCSPI_CH2STAT_RXFFE 0x00000020 +#define MCSPI_CH2STAT_TXFFF 0x00000010 +#define MCSPI_CH2STAT_TXFFE 0x00000008 +#define MCSPI_CH2STAT_EOT 0x00000004 +#define MCSPI_CH2STAT_TXS 0x00000002 +#define MCSPI_CH2STAT_RXS 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH2CTRL register. +// +//****************************************************************************** +#define MCSPI_CH2CTRL_EXTCLK_M 0x0000FF00 // Clock ratio extension: This + // register is used to concatenate + // with MCSPI_CHCONF[CLKD] register + // for clock ratio only when + // granularity is one clock cycle + // (MCSPI_CHCONF[CLKG] set to 1). + // Then the max value reached is + // 4096 clock divider ratio. 0x00 + // Clock ratio is CLKD + 1 0x01 + // Clock ratio is CLKD + 1 + 16 0xFF + // Clock ratio is CLKD + 1 + 4080 +#define MCSPI_CH2CTRL_EXTCLK_S 8 +#define MCSPI_CH2CTRL_EN 0x00000001 // Channel Enable 0 "Channel ""i"" + // is not active" 1 "Channel ""i"" + // is active" +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_TX2 register. +// +//****************************************************************************** +#define MCSPI_TX2_TDATA_M 0xFFFFFFFF // Channel 2 Data to transmit +#define MCSPI_TX2_TDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_RX2 register. +// +//****************************************************************************** +#define MCSPI_RX2_RDATA_M 0xFFFFFFFF // Channel 2 Received Data +#define MCSPI_RX2_RDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH3CONF register. +// +//****************************************************************************** +#define MCSPI_CH3CONF_CLKG 0x20000000 // Clock divider granularity This + // register defines the granularity + // of channel clock divider: power + // of two or one clock cycle + // granularity. When this bit is set + // the register MCSPI_CHCTRL[EXTCLK] + // must be configured to reach a + // maximum of 4096 clock divider + // ratio. Then The clock divider + // ratio is a concatenation of + // MCSPI_CHCONF[CLKD] and + // MCSPI_CHCTRL[EXTCLK] values 0 + // Clock granularity of power of two + // 1 One clock cycle ganularity +#define MCSPI_CH3CONF_FFER 0x10000000 // FIFO enabled for receive:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to receive data. 1 The + // buffer is used to receive data. +#define MCSPI_CH3CONF_FFEW 0x08000000 // FIFO enabled for Transmit:Only + // one channel can have this bit + // field set. 0 The buffer is not + // used to transmit data. 1 The + // buffer is used to transmit data. +#define MCSPI_CH3CONF_TCS3_M 0x06000000 // Chip Select Time Control This + // 2-bits field defines the number + // of interface clock cycles between + // CS toggling and first or last + // edge of SPI clock. 0x0 0.5 clock + // cycle 0x1 1.5 clock cycle 0x2 2.5 + // clock cycle 0x3 3.5 clock cycle +#define MCSPI_CH3CONF_TCS3_S 25 +#define MCSPI_CH3CONF_SBPOL 0x01000000 // Start bit polarity 0 Start bit + // polarity is held to 0 during SPI + // transfer. 1 Start bit polarity is + // held to 1 during SPI transfer. +#define MCSPI_CH3CONF_SBE 0x00800000 // Start bit enable for SPI + // transfer 0 Default SPI transfer + // length as specified by WL bit + // field 1 Start bit D/CX added + // before SPI transfer polarity is + // defined by MCSPI_CH3CONF[SBPOL] +#define MCSPI_CH3CONF_FORCE 0x00100000 // Manual SPIEN assertion to keep + // SPIEN active between SPI words. + // (single channel master mode only) + // 0 Writing 0 into this bit drives + // low the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it high when + // MCSPI_CHCONF(i)[EPOL]=1. 1 + // Writing 1 into this bit drives + // high the SPIEN line when + // MCSPI_CHCONF(i)[EPOL]=0 and + // drives it low when + // MCSPI_CHCONF(i)[EPOL]=1 +#define MCSPI_CH3CONF_TURBO 0x00080000 // Turbo mode 0 Turbo is + // deactivated (recommended for + // single SPI word transfer) 1 Turbo + // is activated to maximize the + // throughput for multi SPI words + // transfer. +#define MCSPI_CH3CONF_IS 0x00040000 // Input Select 0 Data Line0 + // (SPIDAT[0]) selected for + // reception. 1 Data Line1 + // (SPIDAT[1]) selected for + // reception +#define MCSPI_CH3CONF_DPE1 0x00020000 // Transmission Enable for data + // line 1 (SPIDATAGZEN[1]) 0 Data + // Line1 (SPIDAT[1]) selected for + // transmission 1 No transmission on + // Data Line1 (SPIDAT[1]) +#define MCSPI_CH3CONF_DPE0 0x00010000 // Transmission Enable for data + // line 0 (SPIDATAGZEN[0]) 0 Data + // Line0 (SPIDAT[0]) selected for + // transmission 1 No transmission on + // Data Line0 (SPIDAT[0]) +#define MCSPI_CH3CONF_DMAR 0x00008000 // DMA Read request The DMA Read + // request line is asserted when the + // channel is enabled and a new data + // is available in the receive + // register of the channel. The DMA + // Read request line is deasserted + // on read completion of the receive + // register of the channel. 0 DMA + // Read Request disabled 1 DMA Read + // Request enabled +#define MCSPI_CH3CONF_DMAW 0x00004000 // DMA Write request. The DMA Write + // request line is asserted when The + // channel is enabled and the + // transmitter register of the + // channel is empty. The DMA Write + // request line is deasserted on + // load completion of the + // transmitter register of the + // channel. 0 DMA Write Request + // disabled 1 DMA Write Request + // enabled +#define MCSPI_CH3CONF_TRM_M 0x00003000 // Transmit/Receive modes 0x0 + // Transmit and Receive mode 0x1 + // Receive only mode 0x2 Transmit + // only mode 0x3 Reserved +#define MCSPI_CH3CONF_TRM_S 12 +#define MCSPI_CH3CONF_WL_M 0x00000F80 // SPI word length 0x00 Reserved + // 0x01 Reserved 0x02 Reserved 0x03 + // The SPI word is 4-bits long 0x04 + // The SPI word is 5-bits long 0x05 + // The SPI word is 6-bits long 0x06 + // The SPI word is 7-bits long 0x07 + // The SPI word is 8-bits long 0x08 + // The SPI word is 9-bits long 0x09 + // The SPI word is 10-bits long 0x0A + // The SPI word is 11-bits long 0x0B + // The SPI word is 12-bits long 0x0C + // The SPI word is 13-bits long 0x0D + // The SPI word is 14-bits long 0x0E + // The SPI word is 15-bits long 0x0F + // The SPI word is 16-bits long 0x10 + // The SPI word is 17-bits long 0x11 + // The SPI word is 18-bits long 0x12 + // The SPI word is 19-bits long 0x13 + // The SPI word is 20-bits long 0x14 + // The SPI word is 21-bits long 0x15 + // The SPI word is 22-bits long 0x16 + // The SPI word is 23-bits long 0x17 + // The SPI word is 24-bits long 0x18 + // The SPI word is 25-bits long 0x19 + // The SPI word is 26-bits long 0x1A + // The SPI word is 27-bits long 0x1B + // The SPI word is 28-bits long 0x1C + // The SPI word is 29-bits long 0x1D + // The SPI word is 30-bits long 0x1E + // The SPI word is 31-bits long 0x1F + // The SPI word is 32-bits long +#define MCSPI_CH3CONF_WL_S 7 +#define MCSPI_CH3CONF_EPOL 0x00000040 // SPIEN polarity 0 SPIEN is held + // high during the active state. 1 + // SPIEN is held low during the + // active state. +#define MCSPI_CH3CONF_CLKD_M 0x0000003C // Frequency divider for SPICLK. + // (only when the module is a Master + // SPI device). A programmable clock + // divider divides the SPI reference + // clock (CLKSPIREF) with a 4-bit + // value and results in a new clock + // SPICLK available to shift-in and + // shift-out data. By default the + // clock divider ratio has a power + // of two granularity when + // MCSPI_CHCONF[CLKG] is cleared + // Otherwise this register is the 4 + // LSB bit of a 12-bit register + // concatenated with clock divider + // extension MCSPI_CHCTRL[EXTCLK] + // register.The value description + // below defines the clock ratio + // when MCSPI_CHCONF[CLKG] is set to + // 0. 0x0 1 0x1 2 0x2 4 0x3 8 0x4 16 + // 0x5 32 0x6 64 0x7 128 0x8 256 0x9 + // 512 0xA 1024 0xB 2048 0xC 4096 + // 0xD 8192 0xE 16384 0xF 32768 +#define MCSPI_CH3CONF_CLKD_S 2 +#define MCSPI_CH3CONF_POL 0x00000002 // SPICLK polarity 0 SPICLK is held + // high during the active state 1 + // SPICLK is held low during the + // active state +#define MCSPI_CH3CONF_PHA 0x00000001 // SPICLK phase 0 Data are latched + // on odd numbered edges of SPICLK. + // 1 Data are latched on even + // numbered edges of SPICLK. +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH3STAT register. +// +//****************************************************************************** +#define MCSPI_CH3STAT_RXFFF 0x00000040 +#define MCSPI_CH3STAT_RXFFE 0x00000020 +#define MCSPI_CH3STAT_TXFFF 0x00000010 +#define MCSPI_CH3STAT_TXFFE 0x00000008 +#define MCSPI_CH3STAT_EOT 0x00000004 +#define MCSPI_CH3STAT_TXS 0x00000002 +#define MCSPI_CH3STAT_RXS 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_CH3CTRL register. +// +//****************************************************************************** +#define MCSPI_CH3CTRL_EXTCLK_M 0x0000FF00 // Clock ratio extension: This + // register is used to concatenate + // with MCSPI_CHCONF[CLKD] register + // for clock ratio only when + // granularity is one clock cycle + // (MCSPI_CHCONF[CLKG] set to 1). + // Then the max value reached is + // 4096 clock divider ratio. 0x00 + // Clock ratio is CLKD + 1 0x01 + // Clock ratio is CLKD + 1 + 16 0xFF + // Clock ratio is CLKD + 1 + 4080 +#define MCSPI_CH3CTRL_EXTCLK_S 8 +#define MCSPI_CH3CTRL_EN 0x00000001 // Channel Enable 0 "Channel ""i"" + // is not active" 1 "Channel ""i"" + // is active" +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_TX3 register. +// +//****************************************************************************** +#define MCSPI_TX3_TDATA_M 0xFFFFFFFF // Channel 3 Data to transmit +#define MCSPI_TX3_TDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_RX3 register. +// +//****************************************************************************** +#define MCSPI_RX3_RDATA_M 0xFFFFFFFF // Channel 3 Received Data +#define MCSPI_RX3_RDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_XFERLEVEL register. +// +//****************************************************************************** +#define MCSPI_XFERLEVEL_WCNT_M 0xFFFF0000 // Spi word counterThis register + // holds the programmable value of + // number of SPI word to be + // transferred on channel which is + // using the FIFO buffer.When + // transfer had started a read back + // in this register returns the + // current SPI word transfer index. + // 0x0000 Counter not used 0x0001 + // one word 0xFFFE 65534 spi word + // 0xFFFF 65535 spi word +#define MCSPI_XFERLEVEL_WCNT_S 16 +#define MCSPI_XFERLEVEL_AFL_M 0x0000FF00 // Buffer Almost Full This register + // holds the programmable almost + // full level value used to + // determine almost full buffer + // condition. If the user wants an + // interrupt or a DMA read request + // to be issued during a receive + // operation when the data buffer + // holds at least n bytes then the + // buffer MCSPI_MODULCTRL[AFL] must + // be set with n-1.The size of this + // register is defined by the + // generic parameter FFNBYTE. 0x00 + // one byte 0x01 2 bytes 0xFE + // 255bytes 0xFF 256bytes +#define MCSPI_XFERLEVEL_AFL_S 8 +#define MCSPI_XFERLEVEL_AEL_M 0x000000FF // Buffer Almost EmptyThis register + // holds the programmable almost + // empty level value used to + // determine almost empty buffer + // condition. If the user wants an + // interrupt or a DMA write request + // to be issued during a transmit + // operation when the data buffer is + // able to receive n bytes then the + // buffer MCSPI_MODULCTRL[AEL] must + // be set with n-1. 0x00 one byte + // 0x01 2 bytes 0xFE 255 bytes 0xFF + // 256bytes +#define MCSPI_XFERLEVEL_AEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_DAFTX register. +// +//****************************************************************************** +#define MCSPI_DAFTX_DAFTDATA_M 0xFFFFFFFF // FIFO Data to transmit with DMA + // 256 bit aligned address. "This + // Register is only is used when + // MCSPI_MODULCTRL[FDAA] is set to + // ""1"" and only one of the + // MCSPI_CH(i)CONF[FFEW] of enabled + // channels is set. If these + // conditions are not respected any + // access to this register return a + // null value." +#define MCSPI_DAFTX_DAFTDATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MCSPI_O_DAFRX register. +// +//****************************************************************************** +#define MCSPI_DAFRX_DAFRDATA_M 0xFFFFFFFF // FIFO Data to transmit with DMA + // 256 bit aligned address. "This + // Register is only is used when + // MCSPI_MODULCTRL[FDAA] is set to + // ""1"" and only one of the + // MCSPI_CH(i)CONF[FFEW] of enabled + // channels is set. If these + // conditions are not respected any + // access to this register return a + // null value." +#define MCSPI_DAFRX_DAFRDATA_S 0 + + + +#endif // __HW_MCSPI_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_memmap.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_memmap.h new file mode 100755 index 0000000..244905d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_memmap.h @@ -0,0 +1,84 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_MEMMAP_H__ +#define __HW_MEMMAP_H__ + +//***************************************************************************** +// +// The following are defines for the base address of the memories and +// peripherals on the slave_1 interface. +// +//***************************************************************************** +#define FLASH_BASE 0x01000000 +#define SRAM_BASE 0x20000000 +#define WDT_BASE 0x40000000 +#define GPIOA0_BASE 0x40004000 +#define GPIOA1_BASE 0x40005000 +#define GPIOA2_BASE 0x40006000 +#define GPIOA3_BASE 0x40007000 +#define GPIOA4_BASE 0x40024000 +#define UARTA0_BASE 0x4000C000 +#define UARTA1_BASE 0x4000D000 +#define I2CA0_BASE 0x40020000 +#define TIMERA0_BASE 0x40030000 +#define TIMERA1_BASE 0x40031000 +#define TIMERA2_BASE 0x40032000 +#define TIMERA3_BASE 0x40033000 +#define STACKDIE_CTRL_BASE 0x400F5000 +#define COMMON_REG_BASE 0x400F7000 +#define FLASH_CONTROL_BASE 0x400FD000 +#define SYSTEM_CONTROL_BASE 0x400FE000 +#define UDMA_BASE 0x400FF000 +#define SDHOST_BASE 0x44010000 +#define CAMERA_BASE 0x44018000 +#define I2S_BASE 0x4401C000 +#define SSPI_BASE 0x44020000 +#define GSPI_BASE 0x44021000 +#define LSPI_BASE 0x44022000 +#define ARCM_BASE 0x44025000 +#define APPS_CONFIG_BASE 0x44026000 +#define GPRCM_BASE 0x4402D000 +#define OCP_SHARED_BASE 0x4402E000 +#define ADC_BASE 0x4402E800 +#define HIB1P2_BASE 0x4402F000 +#define HIB3P3_BASE 0x4402F800 +#define DTHE_BASE 0x44030000 +#define SHAMD5_BASE 0x44035000 +#define AES_BASE 0x44037000 +#define DES_BASE 0x44039000 + + +#endif // __HW_MEMMAP_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mmchs.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mmchs.h new file mode 100755 index 0000000..3096d13 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_mmchs.h @@ -0,0 +1,1919 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_MMCHS_H__ +#define __HW_MMCHS_H__ + +//***************************************************************************** +// +// The following are defines for the MMCHS register offsets. +// +//***************************************************************************** +#define MMCHS_O_HL_REV 0x00000000 // IP Revision Identifier (X.Y.R) + // Used by software to track + // features bugs and compatibility +#define MMCHS_O_HL_HWINFO 0x00000004 // Information about the IP + // module's hardware configuration + // i.e. typically the module's HDL + // generics (if any). Actual field + // format and encoding is up to the + // module's designer to decide. +#define MMCHS_O_HL_SYSCONFIG 0x00000010 // Clock management configuration +#define MMCHS_O_SYSCONFIG 0x00000110 // System Configuration Register + // This register allows controlling + // various parameters of the OCP + // interface. +#define MMCHS_O_SYSSTATUS 0x00000114 // System Status Register This + // register provides status + // information about the module + // excluding the interrupt status + // information +#define MMCHS_O_CSRE 0x00000124 // Card status response error This + // register enables the host + // controller to detect card status + // errors of response type R1 R1b + // for all cards and of R5 R5b and + // R6 response for cards types SD or + // SDIO. When a bit MMCHS_CSRE[i] is + // set to 1 if the corresponding bit + // at the same position in the + // response MMCHS_RSP0[i] is set to + // 1 the host controller indicates a + // card error (MMCHS_STAT[CERR]) + // interrupt status to avoid the + // host driver reading the response + // register (MMCHS_RSP0). Note: No + // automatic card error detection + // for autoCMD12 is implemented; the + // host system has to check + // autoCMD12 response register + // (MMCHS_RESP76) for possible card + // errors. +#define MMCHS_O_SYSTEST 0x00000128 // System Test register This + // register is used to control the + // signals that connect to I/O pins + // when the module is configured in + // system test (SYSTEST) mode for + // boundary connectivity + // verification. Note: In SYSTEST + // mode a write into MMCHS_CMD + // register will not start a + // transfer. The buffer behaves as a + // stack accessible only by the + // local host (push and pop + // operations). In this mode the + // Transfer Block Size + // (MMCHS_BLK[BLEN]) and the Blocks + // count for current transfer + // (MMCHS_BLK[NBLK]) are needed to + // generate a Buffer write ready + // interrupt (MMCHS_STAT[BWR]) or a + // Buffer read ready interrupt + // (MMCHS_STAT[BRR]) and DMA + // requests if enabled. +#define MMCHS_O_CON 0x0000012C // Configuration register This + // register is used: - to select the + // functional mode or the SYSTEST + // mode for any card. - to send an + // initialization sequence to any + // card. - to enable the detection + // on DAT[1] of a card interrupt for + // SDIO cards only. and also to + // configure : - specific data and + // command transfers for MMC cards + // only. - the parameters related to + // the card detect and write protect + // input signals. +#define MMCHS_O_PWCNT 0x00000130 // Power counter register This + // register is used to program a mmc + // counter to delay command + // transfers after activating the + // PAD power this value depends on + // PAD characteristics and voltage. +#define MMCHS_O_BLK 0x00000204 // Transfer Length Configuration + // register MMCHS_BLK[BLEN] is the + // block size register. + // MMCHS_BLK[NBLK] is the block + // count register. This register + // shall be used for any card. +#define MMCHS_O_ARG 0x00000208 // Command argument Register This + // register contains command + // argument specified as bit 39-8 of + // Command-Format These registers + // must be initialized prior to + // sending the command itself to the + // card (write action into the + // register MMCHS_CMD register). + // Only exception is for a command + // index specifying stuff bits in + // arguments making a write + // unnecessary. +#define MMCHS_O_CMD 0x0000020C // Command and transfer mode + // register MMCHS_CMD[31:16] = the + // command register MMCHS_CMD[15:0] + // = the transfer mode. This + // register configures the data and + // command transfers. A write into + // the most significant byte send + // the command. A write into + // MMCHS_CMD[15:0] registers during + // data transfer has no effect. This + // register shall be used for any + // card. Note: In SYSTEST mode a + // write into MMCHS_CMD register + // will not start a transfer. +#define MMCHS_O_RSP10 0x00000210 // Command response[31:0] Register + // This 32-bit register holds bits + // positions [31:0] of command + // response type + // R1/R1b/R2/R3/R4/R5/R5b/R6 +#define MMCHS_O_RSP32 0x00000214 // Command response[63:32] Register + // This 32-bit register holds bits + // positions [63:32] of command + // response type R2 +#define MMCHS_O_RSP54 0x00000218 // Command response[95:64] Register + // This 32-bit register holds bits + // positions [95:64] of command + // response type R2 +#define MMCHS_O_RSP76 0x0000021C // Command response[127:96] + // Register This 32-bit register + // holds bits positions [127:96] of + // command response type R2 +#define MMCHS_O_DATA 0x00000220 // Data Register This register is + // the 32-bit entry point of the + // buffer for read or write data + // transfers. The buffer size is + // 32bits x256(1024 bytes). Bytes + // within a word are stored and read + // in little endian format. This + // buffer can be used as two 512 + // byte buffers to transfer data + // efficiently without reducing the + // throughput. Sequential and + // contiguous access is necessary to + // increment the pointer correctly. + // Random or skipped access is not + // allowed. In little endian if the + // local host accesses this register + // byte-wise or 16bit-wise the least + // significant byte (bits [7:0]) + // must always be written/read + // first. The update of the buffer + // address is done on the most + // significant byte write for full + // 32-bit DATA register or on the + // most significant byte of the last + // word of block transfer. Example + // 1: Byte or 16-bit access + // Mbyteen[3:0]=0001 (1-byte) => + // Mbyteen[3:0]=0010 (1-byte) => + // Mbyteen[3:0]=1100 (2-bytes) OK + // Mbyteen[3:0]=0001 (1-byte) => + // Mbyteen[3:0]=0010 (1-byte) => + // Mbyteen[3:0]=0100 (1-byte) OK + // Mbyteen[3:0]=0001 (1-byte) => + // Mbyteen[3:0]=0010 (1-byte) => + // Mbyteen[3:0]=1000 (1-byte) Bad +#define MMCHS_O_PSTATE 0x00000224 // Present state register The Host + // can get status of the Host + // Controller from this 32-bit read + // only register. +#define MMCHS_O_HCTL 0x00000228 // Control register This register + // defines the host controls to set + // power wakeup and transfer + // parameters. MMCHS_HCTL[31:24] = + // Wakeup control MMCHS_HCTL[23:16] + // = Block gap control + // MMCHS_HCTL[15:8] = Power control + // MMCHS_HCTL[7:0] = Host control +#define MMCHS_O_SYSCTL 0x0000022C // SD system control register This + // register defines the system + // controls to set software resets + // clock frequency management and + // data timeout. MMCHS_SYSCTL[31:24] + // = Software resets + // MMCHS_SYSCTL[23:16] = Timeout + // control MMCHS_SYSCTL[15:0] = + // Clock control +#define MMCHS_O_STAT 0x00000230 // Interrupt status register The + // interrupt status regroups all the + // status of the module internal + // events that can generate an + // interrupt. MMCHS_STAT[31:16] = + // Error Interrupt Status + // MMCHS_STAT[15:0] = Normal + // Interrupt Status +#define MMCHS_O_IE 0x00000234 // Interrupt SD enable register + // This register allows to + // enable/disable the module to set + // status bits on an event-by-event + // basis. MMCHS_IE[31:16] = Error + // Interrupt Status Enable + // MMCHS_IE[15:0] = Normal Interrupt + // Status Enable +#define MMCHS_O_ISE 0x00000238 // Interrupt signal enable register + // This register allows to + // enable/disable the module + // internal sources of status on an + // event-by-event basis. + // MMCHS_ISE[31:16] = Error + // Interrupt Signal Enable + // MMCHS_ISE[15:0] = Normal + // Interrupt Signal Enable +#define MMCHS_O_AC12 0x0000023C // Auto CMD12 Error Status Register + // The host driver may determine + // which of the errors cases related + // to Auto CMD12 has occurred by + // checking this MMCHS_AC12 register + // when an Auto CMD12 Error + // interrupt occurs. This register + // is valid only when Auto CMD12 is + // enabled (MMCHS_CMD[ACEN]) and + // Auto CMD12Error (MMCHS_STAT[ACE]) + // is set to 1. Note: These bits are + // automatically reset when starting + // a new adtc command with data. +#define MMCHS_O_CAPA 0x00000240 // Capabilities register This + // register lists the capabilities + // of the MMC/SD/SDIO host + // controller. +#define MMCHS_O_CUR_CAPA 0x00000248 // Maximum current capabilities + // Register This register indicates + // the maximum current capability + // for each voltage. The value is + // meaningful if the voltage support + // is set in the capabilities + // register (MMCHS_CAPA). + // Initialization of this register + // (via a write access to this + // register) depends on the system + // capabilities. The host driver + // shall not modify this register + // after the initilaization. This + // register is only reinitialized by + // a hard reset (via RESETN signal) +#define MMCHS_O_FE 0x00000250 // Force Event Register for Error + // Interrupt status The force Event + // Register is not a physically + // implemented register. Rather it + // is an address at which the Error + // Interrupt Status register can be + // written. The effect of a write to + // this address will be reflected in + // the Error Interrupt Status + // Register if corresponding bit of + // the Error Interrupt Status Enable + // Register is set. +#define MMCHS_O_ADMAES 0x00000254 // ADMA Error Status Register When + // ADMA Error Interrupt is occurred + // the ADMA Error States field in + // this register holds the ADMA + // state and the ADMA System Address + // Register holds the address around + // the error descriptor. For + // recovering the error the Host + // Driver requires the ADMA state to + // identify the error descriptor + // address as follows: ST_STOP: + // Previous location set in the ADMA + // System Address register is the + // error descriptor address ST_FDS: + // Current location set in the ADMA + // System Address register is the + // error descriptor address ST_CADR: + // This sate is never set because do + // not generate ADMA error in this + // state. ST_TFR: Previous location + // set in the ADMA System Address + // register is the error descriptor + // address In case of write + // operation the Host Driver should + // use ACMD22 to get the number of + // written block rather than using + // this information since unwritten + // data may exist in the Host + // Controller. The Host Controller + // generates the ADMA Error + // Interrupt when it detects invalid + // descriptor data (Valid=0) at the + // ST_FDS state. In this case ADMA + // Error State indicates that an + // error occurs at ST_FDS state. The + // Host Driver may find that the + // Valid bit is not set in the error + // descriptor. +#define MMCHS_O_ADMASAL 0x00000258 // ADMA System address Low bits +#define MMCHS_O_REV 0x000002FC // Versions Register This register + // contains the hard coded RTL + // vendor revision number the + // version number of SD + // specification compliancy and a + // slot status bit. MMCHS_REV[31:16] + // = Host controller version + // MMCHS_REV[15:0] = Slot Interrupt + // Status + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_HL_REV register. +// +//****************************************************************************** +#define MMCHS_HL_REV_SCHEME_M 0xC0000000 +#define MMCHS_HL_REV_SCHEME_S 30 +#define MMCHS_HL_REV_FUNC_M 0x0FFF0000 // Function indicates a software + // compatible module family. If + // there is no level of software + // compatibility a new Func number + // (and hence REVISION) should be + // assigned. +#define MMCHS_HL_REV_FUNC_S 16 +#define MMCHS_HL_REV_R_RTL_M 0x0000F800 // RTL Version (R) maintained by IP + // design owner. RTL follows a + // numbering such as X.Y.R.Z which + // are explained in this table. R + // changes ONLY when: (1) PDS + // uploads occur which may have been + // due to spec changes (2) Bug fixes + // occur (3) Resets to '0' when X or + // Y changes. Design team has an + // internal 'Z' (customer invisible) + // number which increments on every + // drop that happens due to DV and + // RTL updates. Z resets to 0 when R + // increments. +#define MMCHS_HL_REV_R_RTL_S 11 +#define MMCHS_HL_REV_X_MAJOR_M 0x00000700 // Major Revision (X) maintained by + // IP specification owner. X changes + // ONLY when: (1) There is a major + // feature addition. An example + // would be adding Master Mode to + // Utopia Level2. The Func field (or + // Class/Type in old PID format) + // will remain the same. X does NOT + // change due to: (1) Bug fixes (2) + // Change in feature parameters. +#define MMCHS_HL_REV_X_MAJOR_S 8 +#define MMCHS_HL_REV_CUSTOM_M 0x000000C0 +#define MMCHS_HL_REV_CUSTOM_S 6 +#define MMCHS_HL_REV_Y_MINOR_M 0x0000003F // Minor Revision (Y) maintained by + // IP specification owner. Y changes + // ONLY when: (1) Features are + // scaled (up or down). Flexibility + // exists in that this feature + // scalability may either be + // represented in the Y change or a + // specific register in the IP that + // indicates which features are + // exactly available. (2) When + // feature creeps from Is-Not list + // to Is list. But this may not be + // the case once it sees silicon; in + // which case X will change. Y does + // NOT change due to: (1) Bug fixes + // (2) Typos or clarifications (3) + // major functional/feature + // change/addition/deletion. Instead + // these changes may be reflected + // via R S X as applicable. Spec + // owner maintains a + // customer-invisible number 'S' + // which changes due to: (1) + // Typos/clarifications (2) Bug + // documentation. Note that this bug + // is not due to a spec change but + // due to implementation. + // Nevertheless the spec tracks the + // IP bugs. An RTL release (say for + // silicon PG1.1) that occurs due to + // bug fix should document the + // corresponding spec number (X.Y.S) + // in its release notes. +#define MMCHS_HL_REV_Y_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_HL_HWINFO register. +// +//****************************************************************************** +#define MMCHS_HL_HWINFO_RETMODE 0x00000040 +#define MMCHS_HL_HWINFO_MEM_SIZE_M \ + 0x0000003C + +#define MMCHS_HL_HWINFO_MEM_SIZE_S 2 +#define MMCHS_HL_HWINFO_MERGE_MEM \ + 0x00000002 + +#define MMCHS_HL_HWINFO_MADMA_EN \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// MMCHS_O_HL_SYSCONFIG register. +// +//****************************************************************************** +#define MMCHS_HL_SYSCONFIG_STANDBYMODE_M \ + 0x00000030 // Configuration of the local + // initiator state management mode. + // By definition initiator may + // generate read/write transaction + // as long as it is out of STANDBY + // state. 0x0 Force-standby mode: + // local initiator is + // unconditionally placed in standby + // state.Backup mode for debug only. + // 0x1 No-standby mode: local + // initiator is unconditionally + // placed out of standby + // state.Backup mode for debug only. + // 0x2 Smart-standby mode: local + // initiator standby status depends + // on local conditions i.e. the + // module's functional requirement + // from the initiator.IP module + // shall not generate + // (initiator-related) wakeup + // events. 0x3 "Smart-Standby + // wakeup-capable mode: local + // initiator standby status depends + // on local conditions i.e. the + // module's functional requirement + // from the initiator. IP module may + // generate (master-related) wakeup + // events when in standby state.Mode + // is only relevant if the + // appropriate IP module ""mwakeup"" + // output is implemented." + +#define MMCHS_HL_SYSCONFIG_STANDBYMODE_S 4 +#define MMCHS_HL_SYSCONFIG_IDLEMODE_M \ + 0x0000000C // Configuration of the local + // target state management mode. By + // definition target can handle + // read/write transaction as long as + // it is out of IDLE state. 0x0 + // Force-idle mode: local target's + // idle state follows (acknowledges) + // the system's idle requests + // unconditionally i.e. regardless + // of the IP module's internal + // requirements.Backup mode for + // debug only. 0x1 No-idle mode: + // local target never enters idle + // state.Backup mode for debug only. + // 0x2 Smart-idle mode: local + // target's idle state eventually + // follows (acknowledges) the + // system's idle requests depending + // on the IP module's internal + // requirements.IP module shall not + // generate (IRQ- or + // DMA-request-related) wakeup + // events. 0x3 "Smart-idle + // wakeup-capable mode: local + // target's idle state eventually + // follows (acknowledges) the + // system's idle requests depending + // on the IP module's internal + // requirements.IP module may + // generate (IRQ- or + // DMA-request-related) wakeup + // events when in idle state.Mode is + // only relevant if the appropriate + // IP module ""swakeup"" output(s) + // is (are) implemented." + +#define MMCHS_HL_SYSCONFIG_IDLEMODE_S 2 +#define MMCHS_HL_SYSCONFIG_FREEEMU \ + 0x00000002 // Sensitivity to emulation (debug) + // suspend input signal. + // Functionality NOT implemented in + // MMCHS. 0 IP module is sensitive + // to emulation suspend 1 IP module + // is not sensitive to emulation + // suspend + +#define MMCHS_HL_SYSCONFIG_SOFTRESET \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_SYSCONFIG register. +// +//****************************************************************************** +#define MMCHS_SYSCONFIG_STANDBYMODE_M \ + 0x00003000 // Master interface power + // Management standby/wait control. + // The bit field is only useful when + // generic parameter MADMA_EN + // (Master ADMA enable) is set as + // active otherwise it is a read + // only register read a '0'. 0x0 + // Force-standby. Mstandby is forced + // unconditionnaly. 0x1 No-standby. + // Mstandby is never asserted. 0x2 + // Smart-standby mode: local + // initiator standby status depends + // on local conditions i.e. the + // module's functional requirement + // from the initiator.IP module + // shall not generate + // (initiator-related) wakeup + // events. 0x3 Smart-Standby + // wakeup-capable mode: "local + // initiator standby status depends + // on local conditions i.e. the + // module's functional requirement + // from the initiator. IP module may + // generate (master-related) wakeup + // events when in standby state.Mode + // is only relevant if the + // appropriate IP module ""mwakeup"" + // output is implemented." + +#define MMCHS_SYSCONFIG_STANDBYMODE_S 12 +#define MMCHS_SYSCONFIG_CLOCKACTIVITY_M \ + 0x00000300 // Clocks activity during wake up + // mode period. Bit8: OCP interface + // clock Bit9: Functional clock 0x0 + // OCP and Functional clock may be + // switched off. 0x1 OCP clock is + // maintained. Functional clock may + // be switched-off. 0x2 Functional + // clock is maintained. OCP clock + // may be switched-off. 0x3 OCP and + // Functional clocks are maintained. + +#define MMCHS_SYSCONFIG_CLOCKACTIVITY_S 8 +#define MMCHS_SYSCONFIG_SIDLEMODE_M \ + 0x00000018 // Power management 0x0 If an idle + // request is detected the MMCHS + // acknowledges it unconditionally + // and goes in Inactive mode. + // Interrupt and DMA requests are + // unconditionally de-asserted. 0x1 + // If an idle request is detected + // the request is ignored and the + // module keeps on behaving + // normally. 0x2 Smart-idle mode: + // local target's idle state + // eventually follows (acknowledges) + // the system's idle requests + // depending on the IP module's + // internal requirements.IP module + // shall not generate (IRQ- or + // DMA-request-related) wakeup + // events. 0x3 Smart-idle + // wakeup-capable mode: "local + // target's idle state eventually + // follows (acknowledges) the + // system's idle requests depending + // on the IP module's internal + // requirements.IP module may + // generate (IRQ- or + // DMA-request-related) wakeup + // events when in idle state.Mode is + // only relevant if the appropriate + // IP module ""swakeup"" output(s) + // is (are) implemented." + +#define MMCHS_SYSCONFIG_SIDLEMODE_S 3 +#define MMCHS_SYSCONFIG_ENAWAKEUP \ + 0x00000004 // Wakeup feature control 0 Wakeup + // capability is disabled 1 Wakeup + // capability is enabled + +#define MMCHS_SYSCONFIG_SOFTRESET \ + 0x00000002 + +#define MMCHS_SYSCONFIG_AUTOIDLE \ + 0x00000001 // Internal Clock gating strategy 0 + // Clocks are free-running 1 + // Automatic clock gating strategy + // is applied based on the OCP and + // MMC interface activity + +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_SYSSTATUS register. +// +//****************************************************************************** +#define MMCHS_SYSSTATUS_RESETDONE \ + 0x00000001 + +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_CSRE register. +// +//****************************************************************************** +#define MMCHS_CSRE_CSRE_M 0xFFFFFFFF // Card status response error +#define MMCHS_CSRE_CSRE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_SYSTEST register. +// +//****************************************************************************** +#define MMCHS_SYSTEST_OBI 0x00010000 +#define MMCHS_SYSTEST_SDCD 0x00008000 +#define MMCHS_SYSTEST_SDWP 0x00004000 +#define MMCHS_SYSTEST_WAKD 0x00002000 +#define MMCHS_SYSTEST_SSB 0x00001000 +#define MMCHS_SYSTEST_D7D 0x00000800 +#define MMCHS_SYSTEST_D6D 0x00000400 +#define MMCHS_SYSTEST_D5D 0x00000200 +#define MMCHS_SYSTEST_D4D 0x00000100 +#define MMCHS_SYSTEST_D3D 0x00000080 +#define MMCHS_SYSTEST_D2D 0x00000040 +#define MMCHS_SYSTEST_D1D 0x00000020 +#define MMCHS_SYSTEST_D0D 0x00000010 +#define MMCHS_SYSTEST_DDIR 0x00000008 +#define MMCHS_SYSTEST_CDAT 0x00000004 +#define MMCHS_SYSTEST_CDIR 0x00000002 +#define MMCHS_SYSTEST_MCKD 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_CON register. +// +//****************************************************************************** +#define MMCHS_CON_SDMA_LNE 0x00200000 // Slave DMA Level/Edge Request: + // The waveform of the DMA request + // can be configured either edge + // sensitive with early de-assertion + // on first access to MMCHS_DATA + // register or late de-assertion + // request remains active until last + // allowed data written into + // MMCHS_DATA. 0 Slave DMA edge + // sensitive Early DMA de-assertion + // 1 Slave DMA level sensitive Late + // DMA de-assertion +#define MMCHS_CON_DMA_MNS 0x00100000 // DMA Master or Slave selection: + // When this bit is set and the + // controller is configured to use + // the DMA Ocp master interface is + // used to get datas from system + // using ADMA2 procedure (direct + // access to the memory).This option + // is only available if generic + // parameter MADMA_EN is asserted to + // '1'. 0 The controller is slave on + // data transfers with system. 1 The + // controller is master on data + // exchange with system controller + // must be configured as using DMA. +#define MMCHS_CON_DDR 0x00080000 // Dual Data Rate mode: When this + // register is set the controller + // uses both clock edge to emit or + // receive data. Odd bytes are + // transmitted on falling edges and + // even bytes are transmitted on + // rise edges. It only applies on + // Data bytes and CRC Start end bits + // and CRC status are kept full + // cycle. This bit field is only + // meaningful and active for even + // clock divider ratio of + // MMCHS_SYSCTL[CLKD] it is + // insensitive to MMCHS_HCTL[HSPE] + // setting. 0 Standard mode : data + // are transmitted on a single edge + // depending on MMCHS_HCTRL[HSPE]. 1 + // Data Bytes and CRC are + // transmitted on both edge. +#define MMCHS_CON_BOOT_CF0 0x00040000 +#define MMCHS_CON_BOOT_ACK 0x00020000 // Book acknowledge received: When + // this bit is set the controller + // should receive a boot status on + // DAT0 line after next command + // issued. If no status is received + // a data timeout will be generated. + // 0 No acknowledge to be received 1 + // A boot status will be received on + // DAT0 line after issuing a + // command. +#define MMCHS_CON_CLKEXTFREE 0x00010000 // External clock free running: + // This register is used to maintain + // card clock out of transfer + // transaction to enable slave + // module for example to generate a + // synchronous interrupt on DAT[1]. + // The Clock will be maintain only + // if MMCHS_SYSCTL[CEN] is set. 0 + // External card clock is cut off + // outside active transaction + // period. 1 External card clock is + // maintain even out of active + // transaction period only if + // MMCHS_SYSCTL[CEN] is set. +#define MMCHS_CON_PADEN 0x00008000 // Control Power for MMC Lines: + // This register is only useful when + // MMC PADs contain power saving + // mechanism to minimize its leakage + // power. It works as a GPIO that + // directly control the ACTIVE pin + // of PADs. Excepted for DAT[1] the + // signal is also combine outside + // the module with the dedicated + // power control MMCHS_CON[CTPL] + // bit. 0 ADPIDLE module pin is not + // forced it is automatically + // generated by the MMC fsms. 1 + // ADPIDLE module pin is forced to + // active state. +#define MMCHS_CON_OBIE 0x00004000 // Out-of-Band Interrupt Enable MMC + // cards only: This bit enables the + // detection of Out-of-Band + // Interrupt on MMCOBI input pin. + // The usage of the Out-of-Band + // signal (OBI) is optional and + // depends on the system + // integration. 0 Out-of-Band + // interrupt detection disabled 1 + // Out-of-Band interrupt detection + // enabled +#define MMCHS_CON_OBIP 0x00002000 // Out-of-Band Interrupt Polarity + // MMC cards only: This bit selects + // the active level of the + // out-of-band interrupt coming from + // MMC cards. The usage of the + // Out-of-Band signal (OBI) is + // optional and depends on the + // system integration. 0 active high + // level 1 active low level +#define MMCHS_CON_CEATA 0x00001000 // CE-ATA control mode MMC cards + // compliant with CE-ATA:By default + // this bit is set to 0. It is use + // to indicate that next commands + // are considered as specific CE-ATA + // commands that potentially use + // 'command completion' features. 0 + // Standard MMC/SD/SDIO mode. 1 + // CE-ATA mode next commands are + // considered as CE-ATA commands. +#define MMCHS_CON_CTPL 0x00000800 // Control Power for DAT[1] line + // MMC and SD cards: By default this + // bit is set to 0 and the host + // controller automatically disables + // all the input buffers outside of + // a transaction to minimize the + // leakage current. SDIO cards: When + // this bit is set to 1 the host + // controller automatically disables + // all the input buffers except the + // buffer of DAT[1] outside of a + // transaction in order to detect + // asynchronous card interrupt on + // DAT[1] line and minimize the + // leakage current of the buffers. 0 + // Disable all the input buffers + // outside of a transaction. 1 + // Disable all the input buffers + // except the buffer of DAT[1] + // outside of a transaction. +#define MMCHS_CON_DVAL_M 0x00000600 // Debounce filter value All cards + // This register is used to define a + // debounce period to filter the + // card detect input signal (SDCD). + // The usage of the card detect + // input signal (SDCD) is optional + // and depends on the system + // integration and the type of the + // connector housing that + // accommodates the card. 0x0 33 us + // debounce period 0x1 231 us + // debounce period 0x2 1 ms debounce + // period 0x3 84 ms debounce period +#define MMCHS_CON_DVAL_S 9 +#define MMCHS_CON_WPP 0x00000100 // Write protect polarity For SD + // and SDIO cards only This bit + // selects the active level of the + // write protect input signal + // (SDWP). The usage of the write + // protect input signal (SDWP) is + // optional and depends on the + // system integration and the type + // of the connector housing that + // accommodates the card. 0 active + // high level 1 active low level +#define MMCHS_CON_CDP 0x00000080 // Card detect polarity All cards + // This bit selects the active level + // of the card detect input signal + // (SDCD). The usage of the card + // detect input signal (SDCD) is + // optional and depends on the + // system integration and the type + // of the connector housing that + // accommodates the card. 0 active + // high level 1 active low level +#define MMCHS_CON_MIT 0x00000040 // MMC interrupt command Only for + // MMC cards. This bit must be set + // to 1 when the next write access + // to the command register + // (MMCHS_CMD) is for writing a MMC + // interrupt command (CMD40) + // requiring the command timeout + // detection to be disabled for the + // command response. 0 Command + // timeout enabled 1 Command timeout + // disabled +#define MMCHS_CON_DW8 0x00000020 // 8-bit mode MMC select For + // SD/SDIO cards this bit must be + // set to 0. For MMC card this bit + // must be set following a valid + // SWITCH command (CMD6) with the + // correct value and extend CSD + // index written in the argument. + // Prior to this command the MMC + // card configuration register (CSD + // and EXT_CSD) must be verified for + // compliancy with MMC standard + // specification 4.x (see section + // 3.6). 0 1-bit or 4-bit Data width + // (DAT[0] used MMC SD cards) 1 + // 8-bit Data width (DAT[7:0] used + // MMC cards) +#define MMCHS_CON_MODE 0x00000010 // Mode select All cards These bits + // select between Functional mode + // and SYSTEST mode. 0 Functional + // mode. Transfers to the + // MMC/SD/SDIO cards follow the card + // protocol. MMC clock is enabled. + // MMC/SD transfers are operated + // under the control of the CMD + // register. 1 SYSTEST mode The + // signal pins are configured as + // general-purpose input/output and + // the 1024-byte buffer is + // configured as a stack memory + // accessible only by the local host + // or system DMA. The pins retain + // their default type (input output + // or in-out). SYSTEST mode is + // operated under the control of the + // SYSTEST register. +#define MMCHS_CON_STR 0x00000008 // Stream command Only for MMC + // cards. This bit must be set to 1 + // only for the stream data + // transfers (read or write) of the + // adtc commands. Stream read is a + // class 1 command (CMD11: + // READ_DAT_UNTIL_STOP). Stream + // write is a class 3 command + // (CMD20: WRITE_DAT_UNTIL_STOP). 0 + // Block oriented data transfer 1 + // Stream oriented data transfer +#define MMCHS_CON_HR 0x00000004 // Broadcast host response Only for + // MMC cards. This register is used + // to force the host to generate a + // 48-bit response for bc command + // type. "It can be used to + // terminate the interrupt mode by + // generating a CMD40 response by + // the core (see section 4.3 + // ""Interrupt Mode"" in the MMC [1] + // specification). In order to have + // the host response to be generated + // in open drain mode the register + // MMCHS_CON[OD] must be set to 1." + // When MMCHS_CON[CEATA] is set to 1 + // and MMCHS_ARG set to 0x00000000 + // when writing 0x00000000 into + // MMCHS_CMD register the host + // controller performs a 'command + // completion signal disable' token + // i.e. CMD line held to '0' during + // 47 cycles followed by a 1. 0 The + // host does not generate a 48-bit + // response instead of a command. 1 + // The host generates a 48-bit + // response instead of a command or + // a command completion signal + // disable token. +#define MMCHS_CON_INIT 0x00000002 // Send initialization stream All + // cards. When this bit is set to 1 + // and the card is idle an + // initialization sequence is sent + // to the card. "An initialization + // sequence consists of setting the + // CMD line to 1 during 80 clock + // cycles. The initialisation + // sequence is mandatory - but it is + // not required to do it through + // this bit - this bit makes it + // easier. Clock divider + // (MMCHS_SYSCTL[CLKD]) should be + // set to ensure that 80 clock + // periods are greater than 1ms. + // (see section 9.3 ""Power-Up"" in + // the MMC card specification [1] or + // section 6.4 in the SD card + // specification [2])." Note: in + // this mode there is no command + // sent to the card and no response + // is expected 0 The host does not + // send an initialization sequence. + // 1 The host sends an + // initialization sequence. +#define MMCHS_CON_OD 0x00000001 // Card open drain mode. Only for + // MMC cards. This bit must be set + // to 1 for MMC card commands 1 2 3 + // and 40 and if the MMC card bus is + // operating in open-drain mode + // during the response phase to the + // command sent. Typically during + // card identification mode when the + // card is either in idle ready or + // ident state. It is also necessary + // to set this bit to 1 for a + // broadcast host response (see + // Broadcast host response register + // MMCHS_CON[HR]) 0 No Open Drain 1 + // Open Drain or Broadcast host + // response +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_PWCNT register. +// +//****************************************************************************** +#define MMCHS_PWCNT_PWRCNT_M 0x0000FFFF // Power counter register. This + // register is used to introduce a + // delay between the PAD ACTIVE pin + // assertion and the command issued. + // 0x0000 No additional delay added + // 0x0001 TCF delay (card clock + // period) 0x0002 TCF x 2 delay + // (card clock period) 0xFFFE TCF x + // 65534 delay (card clock period) + // 0xFFFF TCF x 65535 delay (card + // clock period) +#define MMCHS_PWCNT_PWRCNT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_BLK register. +// +//****************************************************************************** +#define MMCHS_BLK_NBLK_M 0xFFFF0000 // Blocks count for current + // transfer This register is enabled + // when Block count Enable + // (MMCHS_CMD[BCE]) is set to 1 and + // is valid only for multiple block + // transfers. Setting the block + // count to 0 results no data blocks + // being transferred. Note: The host + // controller decrements the block + // count after each block transfer + // and stops when the count reaches + // zero. This register can be + // accessed only if no transaction + // is executing (i.e after a + // transaction has stopped). Read + // operations during transfers may + // return an invalid value and write + // operation will be ignored. In + // suspend context the number of + // blocks yet to be transferred can + // be determined by reading this + // register. When restoring transfer + // context prior to issuing a Resume + // command The local host shall + // restore the previously saved + // block count. 0x0000 Stop count + // 0x0001 1 block 0x0002 2 blocks + // 0xFFFF 65535 blocks +#define MMCHS_BLK_NBLK_S 16 +#define MMCHS_BLK_BLEN_M 0x00000FFF // Transfer Block Size. This + // register specifies the block size + // for block data transfers. Read + // operations during transfers may + // return an invalid value and write + // operations are ignored. When a + // CMD12 command is issued to stop + // the transfer a read of the BLEN + // field after transfer completion + // (MMCHS_STAT[TC] set to 1) will + // not return the true byte number + // of data length while the stop + // occurs but the value written in + // this register before transfer is + // launched. 0x000 No data transfer + // 0x001 1 byte block length 0x002 2 + // bytes block length 0x003 3 bytes + // block length 0x1FF 511 bytes + // block length 0x200 512 bytes + // block length 0x7FF 2047 bytes + // block length 0x800 2048 bytes + // block length +#define MMCHS_BLK_BLEN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_ARG register. +// +//****************************************************************************** +#define MMCHS_ARG_ARG_M 0xFFFFFFFF // Command argument bits [31:0] +#define MMCHS_ARG_ARG_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_CMD register. +// +//****************************************************************************** +#define MMCHS_CMD_INDX_M 0x3F000000 // Command index Binary encoded + // value from 0 to 63 specifying the + // command number send to card 0x00 + // CMD0 or ACMD0 0x01 CMD1 or ACMD1 + // 0x02 CMD2 or ACMD2 0x03 CMD3 or + // ACMD3 0x04 CMD4 or ACMD4 0x05 + // CMD5 or ACMD5 0x06 CMD6 or ACMD6 + // 0x07 CMD7 or ACMD7 0x08 CMD8 or + // ACMD8 0x09 CMD9 or ACMD9 0x0A + // CMD10 or ACMD10 0x0B CMD11 or + // ACMD11 0x0C CMD12 or ACMD12 0x0D + // CMD13 or ACMD13 0x0E CMD14 or + // ACMD14 0x0F CMD15 or ACMD15 0x10 + // CMD16 or ACMD16 0x11 CMD17 or + // ACMD17 0x12 CMD18 or ACMD18 0x13 + // CMD19 or ACMD19 0x14 CMD20 or + // ACMD20 0x15 CMD21 or ACMD21 0x16 + // CMD22 or ACMD22 0x17 CMD23 or + // ACMD23 0x18 CMD24 or ACMD24 0x19 + // CMD25 or ACMD25 0x1A CMD26 or + // ACMD26 0x1B CMD27 or ACMD27 0x1C + // CMD28 or ACMD28 0x1D CMD29 or + // ACMD29 0x1E CMD30 or ACMD30 0x1F + // CMD31 or ACMD31 0x20 CMD32 or + // ACMD32 0x21 CMD33 or ACMD33 0x22 + // CMD34 or ACMD34 0x23 CMD35 or + // ACMD35 0x24 CMD36 or ACMD36 0x25 + // CMD37 or ACMD37 0x26 CMD38 or + // ACMD38 0x27 CMD39 or ACMD39 0x28 + // CMD40 or ACMD40 0x29 CMD41 or + // ACMD41 0x2A CMD42 or ACMD42 0x2B + // CMD43 or ACMD43 0x2C CMD44 or + // ACMD44 0x2D CMD45 or ACMD45 0x2E + // CMD46 or ACMD46 0x2F CMD47 or + // ACMD47 0x30 CMD48 or ACMD48 0x31 + // CMD49 or ACMD49 0x32 CMD50 or + // ACMD50 0x33 CMD51 or ACMD51 0x34 + // CMD52 or ACMD52 0x35 CMD53 or + // ACMD53 0x36 CMD54 or ACMD54 0x37 + // CMD55 or ACMD55 0x38 CMD56 or + // ACMD56 0x39 CMD57 or ACMD57 0x3A + // CMD58 or ACMD58 0x3B CMD59 or + // ACMD59 0x3C CMD60 or ACMD60 0x3D + // CMD61 or ACMD61 0x3E CMD62 or + // ACMD62 0x3F CMD63 or ACMD63 +#define MMCHS_CMD_INDX_S 24 +#define MMCHS_CMD_CMD_TYPE_M 0x00C00000 // Command type This register + // specifies three types of special + // command: Suspend Resume and + // Abort. These bits shall be set to + // 00b for all other commands. 0x0 + // Others Commands 0x1 "CMD52 for + // writing ""Bus Suspend"" in CCCR" + // 0x2 "CMD52 for writing ""Function + // Select"" in CCCR" 0x3 "Abort + // command CMD12 CMD52 for writing + // "" I/O Abort"" in CCCR" +#define MMCHS_CMD_CMD_TYPE_S 22 +#define MMCHS_CMD_DP 0x00200000 // Data present select This + // register indicates that data is + // present and DAT line shall be + // used. It must be set to 0 in the + // following conditions: - command + // using only CMD line - command + // with no data transfer but using + // busy signal on DAT[0] - Resume + // command 0 Command with no data + // transfer 1 Command with data + // transfer +#define MMCHS_CMD_CICE 0x00100000 // Command Index check enable This + // bit must be set to 1 to enable + // index check on command response + // to compare the index field in the + // response against the index of the + // command. If the index is not the + // same in the response as in the + // command it is reported as a + // command index error + // (MMCHS_STAT[CIE] set to1) Note: + // The register CICE cannot be + // configured for an Auto CMD12 then + // index check is automatically + // checked when this command is + // issued. 0 Index check disable 1 + // Index check enable +#define MMCHS_CMD_CCCE 0x00080000 // Command CRC check enable This + // bit must be set to 1 to enable + // CRC7 check on command response to + // protect the response against + // transmission errors on the bus. + // If an error is detected it is + // reported as a command CRC error + // (MMCHS_STAT[CCRC] set to 1). + // Note: The register CCCE cannot be + // configured for an Auto CMD12 and + // then CRC check is automatically + // checked when this command is + // issued. 0 CRC7 check disable 1 + // CRC7 check enable +#define MMCHS_CMD_RSP_TYPE_M 0x00030000 // Response type This bits defines + // the response type of the command + // 0x0 No response 0x1 Response + // Length 136 bits 0x2 Response + // Length 48 bits 0x3 Response + // Length 48 bits with busy after + // response +#define MMCHS_CMD_RSP_TYPE_S 16 +#define MMCHS_CMD_MSBS 0x00000020 // Multi/Single block select This + // bit must be set to 1 for data + // transfer in case of multi block + // command. For any others command + // this bit shall be set to 0. 0 + // Single block. If this bit is 0 it + // is not necessary to set the + // register MMCHS_BLK[NBLK]. 1 Multi + // block. When Block Count is + // disabled (MMCHS_CMD[BCE] is set + // to 0) in Multiple block transfers + // (MMCHS_CMD[MSBS] is set to 1) the + // module can perform infinite + // transfer. +#define MMCHS_CMD_DDIR 0x00000010 // Data transfer Direction Select + // This bit defines either data + // transfer will be a read or a + // write. 0 Data Write (host to + // card) 1 Data Read (card to host) +#define MMCHS_CMD_ACEN 0x00000004 // Auto CMD12 Enable SD card only. + // When this bit is set to 1 the + // host controller issues a CMD12 + // automatically after the transfer + // completion of the last block. The + // Host Driver shall not set this + // bit to issue commands that do not + // require CMD12 to stop data + // transfer. In particular secure + // commands do not require CMD12. 0 + // Auto CMD12 disable 1 Auto CMD12 + // enable or CCS detection enabled. +#define MMCHS_CMD_BCE 0x00000002 // Block Count Enable Multiple + // block transfers only. This bit is + // used to enable the block count + // register (MMCHS_BLK[NBLK]). When + // Block Count is disabled + // (MMCHS_CMD[BCE] is set to 0) in + // Multiple block transfers + // (MMCHS_CMD[MSBS] is set to 1) the + // module can perform infinite + // transfer. 0 Block count disabled + // for infinite transfer. 1 Block + // count enabled for multiple block + // transfer with known number of + // blocks +#define MMCHS_CMD_DE 0x00000001 // DMA Enable This bit is used to + // enable DMA mode for host data + // access. 0 DMA mode disable 1 DMA + // mode enable +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_RSP10 register. +// +//****************************************************************************** +#define MMCHS_RSP10_RSP1_M 0xFFFF0000 // Command Response [31:16] +#define MMCHS_RSP10_RSP1_S 16 +#define MMCHS_RSP10_RSP0_M 0x0000FFFF // Command Response [15:0] +#define MMCHS_RSP10_RSP0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_RSP32 register. +// +//****************************************************************************** +#define MMCHS_RSP32_RSP3_M 0xFFFF0000 // Command Response [63:48] +#define MMCHS_RSP32_RSP3_S 16 +#define MMCHS_RSP32_RSP2_M 0x0000FFFF // Command Response [47:32] +#define MMCHS_RSP32_RSP2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_RSP54 register. +// +//****************************************************************************** +#define MMCHS_RSP54_RSP5_M 0xFFFF0000 // Command Response [95:80] +#define MMCHS_RSP54_RSP5_S 16 +#define MMCHS_RSP54_RSP4_M 0x0000FFFF // Command Response [79:64] +#define MMCHS_RSP54_RSP4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_RSP76 register. +// +//****************************************************************************** +#define MMCHS_RSP76_RSP7_M 0xFFFF0000 // Command Response [127:112] +#define MMCHS_RSP76_RSP7_S 16 +#define MMCHS_RSP76_RSP6_M 0x0000FFFF // Command Response [111:96] +#define MMCHS_RSP76_RSP6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_DATA register. +// +//****************************************************************************** +#define MMCHS_DATA_DATA_M 0xFFFFFFFF // Data Register [31:0] In + // functional mode (MMCHS_CON[MODE] + // set to the default value 0) A + // read access to this register is + // allowed only when the buffer read + // enable status is set to 1 + // (MMCHS_PSTATE[BRE]) otherwise a + // bad access (MMCHS_STAT[BADA]) is + // signaled. A write access to this + // register is allowed only when the + // buffer write enable status is set + // to 1(MMCHS_STATE[BWE]) otherwise + // a bad access (MMCHS_STAT[BADA]) + // is signaled and the data is not + // written. +#define MMCHS_DATA_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_PSTATE register. +// +//****************************************************************************** +#define MMCHS_PSTATE_CLEV 0x01000000 +#define MMCHS_PSTATE_DLEV_M 0x00F00000 // DAT[3:0] line signal level + // DAT[3] => bit 23 DAT[2] => bit 22 + // DAT[1] => bit 21 DAT[0] => bit 20 + // This status is used to check DAT + // line level to recover from errors + // and for debugging. This is + // especially useful in detecting + // the busy signal level from + // DAT[0]. The value of these + // registers after reset depends on + // the DAT lines level at that time. +#define MMCHS_PSTATE_DLEV_S 20 +#define MMCHS_PSTATE_WP 0x00080000 +#define MMCHS_PSTATE_CDPL 0x00040000 +#define MMCHS_PSTATE_CSS 0x00020000 +#define MMCHS_PSTATE_CINS 0x00010000 +#define MMCHS_PSTATE_BRE 0x00000800 +#define MMCHS_PSTATE_BWE 0x00000400 +#define MMCHS_PSTATE_RTA 0x00000200 +#define MMCHS_PSTATE_WTA 0x00000100 +#define MMCHS_PSTATE_DLA 0x00000004 +#define MMCHS_PSTATE_DATI 0x00000002 +#define MMCHS_PSTATE_CMDI 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_HCTL register. +// +//****************************************************************************** +#define MMCHS_HCTL_OBWE 0x08000000 // Wakeup event enable for + // 'Out-of-Band' Interrupt. This bit + // enables wakeup events for + // 'Out-of-Band' assertion. Wakeup + // is generated if the wakeup + // feature is enabled + // (MMCHS_SYSCONFIG[ENAWAKEUP]). The + // write to this register is ignored + // when MMCHS_CON[OBIE] is not set. + // 0 Disable wakeup on 'Out-of-Band' + // Interrupt 1 Enable wakeup on + // 'Out-of-Band' Interrupt +#define MMCHS_HCTL_REM 0x04000000 // Wakeup event enable on SD card + // removal This bit enables wakeup + // events for card removal + // assertion. Wakeup is generated if + // the wakeup feature is enabled + // (MMCHS_SYSCONFIG[ENAWAKEUP]). 0 + // Disable wakeup on card removal 1 + // Enable wakeup on card removal +#define MMCHS_HCTL_INS 0x02000000 // Wakeup event enable on SD card + // insertion This bit enables wakeup + // events for card insertion + // assertion. Wakeup is generated if + // the wakeup feature is enabled + // (MMCHS_SYSCONFIG[ENAWAKEUP]). 0 + // Disable wakeup on card insertion + // 1 Enable wakeup on card insertion +#define MMCHS_HCTL_IWE 0x01000000 // Wakeup event enable on SD card + // interrupt This bit enables wakeup + // events for card interrupt + // assertion. Wakeup is generated if + // the wakeup feature is enabled + // (MMCHS_SYSCONFIG[ENAWAKEUP]). 0 + // Disable wakeup on card interrupt + // 1 Enable wakeup on card interrupt +#define MMCHS_HCTL_IBG 0x00080000 // Interrupt block at gap This bit + // is valid only in 4-bit mode of + // SDIO card to enable interrupt + // detection in the interrupt cycle + // at block gap for a multiple block + // transfer. For MMC cards and for + // SD card this bit should be set to + // 0. 0 Disable interrupt detection + // at the block gap in 4-bit mode 1 + // Enable interrupt detection at the + // block gap in 4-bit mode +#define MMCHS_HCTL_RWC 0x00040000 // Read wait control The read wait + // function is optional only for + // SDIO cards. If the card supports + // read wait this bit must be + // enabled then requesting a stop at + // block gap (MMCHS_HCTL[SBGR]) + // generates a read wait period + // after the current end of block. + // Be careful if read wait is not + // supported it may cause a conflict + // on DAT line. 0 Disable Read Wait + // Control. Suspend/Resume cannot be + // supported. 1 Enable Read Wait + // Control +#define MMCHS_HCTL_CR 0x00020000 // Continue request This bit is + // used to restart a transaction + // that was stopped by requesting a + // stop at block gap + // (MMCHS_HCTL[SBGR]). Set this bit + // to 1 restarts the transfer. The + // bit is automatically set to 0 by + // the host controller when transfer + // has restarted i.e DAT line is + // active (MMCHS_PSTATE[DLA]) or + // transferring data + // (MMCHS_PSTATE[WTA]). The Stop at + // block gap request must be + // disabled (MMCHS_HCTL[SBGR]=0) + // before setting this bit. 0 No + // affect 1 transfer restart +#define MMCHS_HCTL_SBGR 0x00010000 // Stop at block gap request This + // bit is used to stop executing a + // transaction at the next block + // gap. The transfer can restart + // with a continue request + // (MMHS_HCTL[CR]) or during a + // suspend/resume sequence. In case + // of read transfer the card must + // support read wait control. In + // case of write transfer the host + // driver shall set this bit after + // all block data written. Until the + // transfer completion + // (MMCHS_STAT[TC] set to 1) the + // host driver shall leave this bit + // set to 1. If this bit is set the + // local host shall not write to the + // data register (MMCHS_DATA). 0 + // Transfer mode 1 Stop at block gap +#define MMCHS_HCTL_SDVS_M 0x00000E00 // SD bus voltage select All cards. + // The host driver should set to + // these bits to select the voltage + // level for the card according to + // the voltage supported by the + // system (MMCHS_CAPA[VS18VS30VS33]) + // before starting a transfer. 0x5 + // 1.8V (Typical) 0x6 3.0V (Typical) + // 0x7 3.3V (Typical) +#define MMCHS_HCTL_SDVS_S 9 +#define MMCHS_HCTL_SDBP 0x00000100 // SD bus power Before setting this + // bit the host driver shall select + // the SD bus voltage + // (MMCHS_HCTL[SDVS]). If the host + // controller detects the No card + // state this bit is automatically + // set to 0. If the module is power + // off a write in the command + // register (MMCHS_CMD) will not + // start the transfer. A write to + // this bit has no effect if the + // selected SD bus voltage + // MMCHS_HCTL[SDVS] is not supported + // according to capability register + // (MMCHS_CAPA[VS*]). 0 Power off 1 + // Power on +#define MMCHS_HCTL_CDSS 0x00000080 // Card Detect Signal Selection + // This bit selects source for the + // card detection.When the source + // for the card detection is + // switched the interrupt should be + // disabled during the switching + // period by clearing the Interrupt + // Status/Signal Enable register in + // order to mask unexpected + // interrupt being caused by the + // glitch. The Interrupt + // Status/Signal Enable should be + // disabled during over the period + // of debouncing. 0 SDCD# is + // selected (for normal use) 1 The + // Card Detect Test Level is + // selected (for test purpose) +#define MMCHS_HCTL_CDTL 0x00000040 // Card Detect Test Level: This bit + // is enabled while the Card Detect + // Signal Selection is set to 1 and + // it indicates card inserted or + // not. 0 No Card 1 Card Inserted +#define MMCHS_HCTL_DMAS_M 0x00000018 // DMA Select Mode: One of + // supported DMA modes can be + // selected. The host driver shall + // check support of DMA modes by + // referring the Capabilities + // register. Use of selected DMA is + // determined by DMA Enable of the + // Transfer Mode register. This + // register is only meaningful when + // MADMA_EN is set to 1. When + // MADMA_EN is set to 0 the bit + // field is read only and returned + // value is 0. 0x0 Reserved 0x1 + // Reserved 0x2 32-bit Address ADMA2 + // is selected 0x3 Reserved +#define MMCHS_HCTL_DMAS_S 3 +#define MMCHS_HCTL_HSPE 0x00000004 // High Speed Enable: Before + // setting this bit the Host Driver + // shall check the High Speed + // Support in the Capabilities + // register. If this bit is set to 0 + // (default) the Host Controller + // outputs CMD line and DAT lines at + // the falling edge of the SD Clock. + // If this bit is set to 1 the Host + // Controller outputs CMD line and + // DAT lines at the rising edge of + // the SD Clock.This bit shall not + // be set when dual data rate mode + // is activated in MMCHS_CON[DDR]. 0 + // Normal speed mode 1 High speed + // mode +#define MMCHS_HCTL_DTW 0x00000002 // Data transfer width For MMC card + // this bit must be set following a + // valid SWITCH command (CMD6) with + // the correct value and extend CSD + // index written in the argument. + // Prior to this command the MMC + // card configuration register (CSD + // and EXT_CSD) must be verified for + // compliance with MMC standard + // specification 4.x (see section + // 3.6). This register has no effect + // when the MMC 8-bit mode is + // selected (register MMCHS_CON[DW8] + // set to1 ) For SD/SDIO cards this + // bit must be set following a valid + // SET_BUS_WIDTH command (ACMD6) + // with the value written in bit 1 + // of the argument. Prior to this + // command the SD card configuration + // register (SCR) must be verified + // for the supported bus width by + // the SD card. 0 1-bit Data width + // (DAT[0] used) 1 4-bit Data width + // (DAT[3:0] used) +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_SYSCTL register. +// +//****************************************************************************** +#define MMCHS_SYSCTL_SRD 0x04000000 // Software reset for DAT line This + // bit is set to 1 for reset and + // released to 0 when completed. DAT + // finite state machine in both + // clock domain are also reset. Here + // below are the registers cleared + // by MMCHS_SYSCTL[SRD]: #VALUE! - + // MMCHS_PSTATE: BRE BWE RTA WTA DLA + // and DATI - MMCHS_HCTL: SBGR and + // CR - MMCHS_STAT: BRR BWR BGE and + // TC OCP and MMC buffer data + // management is reinitialized. 0 + // Reset completed 1 Software reset + // for DAT line +#define MMCHS_SYSCTL_SRC 0x02000000 // Software reset for CMD line This + // bit is set to 1 for reset and + // released to 0 when completed. CMD + // finite state machine in both + // clock domain are also reset. Here + // below the registers cleared by + // MMCHS_SYSCTL[SRC]: - + // MMCHS_PSTATE: CMDI - MMCHS_STAT: + // CC OCP and MMC command status + // management is reinitialized. 0 + // Reset completed 1 Software reset + // for CMD line +#define MMCHS_SYSCTL_SRA 0x01000000 // Software reset for all This bit + // is set to 1 for reset and + // released to 0 when completed. + // This reset affects the entire + // host controller except for the + // card detection circuit and + // capabilities registers. 0 Reset + // completed 1 Software reset for + // all the design +#define MMCHS_SYSCTL_DTO_M 0x000F0000 // Data timeout counter value and + // busy timeout. This value + // determines the interval by which + // DAT lines timeouts are detected. + // The host driver needs to set this + // bitfield based on - the maximum + // read access time (NAC) (Refer to + // the SD Specification Part1 + // Physical Layer) - the data read + // access time values (TAAC and + // NSAC) in the card specific data + // register (CSD) of the card - the + // timeout clock base frequency + // (MMCHS_CAPA[TCF]). If the card + // does not respond within the + // specified number of cycles a data + // timeout error occurs + // (MMCHS_STA[DTO]). The + // MMCHS_SYSCTL[DTO] register is + // also used to check busy duration + // to generate busy timeout for + // commands with busy response or + // for busy programming during a + // write command. Timeout on CRC + // status is generated if no CRC + // token is present after a block + // write. 0x0 TCF x 2^13 0x1 TCF x + // 2^14 0xE TCF x 2^27 0xF Reserved +#define MMCHS_SYSCTL_DTO_S 16 +#define MMCHS_SYSCTL_CLKD_M 0x0000FFC0 // Clock frequency select These + // bits define the ratio between a + // reference clock frequency (system + // dependant) and the output clock + // frequency on the CLK pin of + // either the memory card (MMC SD or + // SDIO). 0x000 Clock Ref bypass + // 0x001 Clock Ref bypass 0x002 + // Clock Ref / 2 0x003 Clock Ref / 3 + // 0x3FF Clock Ref / 1023 +#define MMCHS_SYSCTL_CLKD_S 6 +#define MMCHS_SYSCTL_CEN 0x00000004 // Clock enable This bit controls + // if the clock is provided to the + // card or not. 0 The clock is not + // provided to the card . Clock + // frequency can be changed . 1 The + // clock is provided to the card and + // can be automatically gated when + // MMCHS_SYSCONFIG[AUTOIDLE] is set + // to 1 (default value) . The host + // driver shall wait to set this bit + // to 1 until the Internal clock is + // stable (MMCHS_SYSCTL[ICS]). +#define MMCHS_SYSCTL_ICS 0x00000002 +#define MMCHS_SYSCTL_ICE 0x00000001 // Internal clock enable This + // register controls the internal + // clock activity. In very low power + // state the internal clock is + // stopped. Note: The activity of + // the debounce clock (used for + // wakeup events) and the OCP clock + // (used for reads and writes to the + // module register map) are not + // affected by this register. 0 The + // internal clock is stopped (very + // low power state). 1 The internal + // clock oscillates and can be + // automatically gated when + // MMCHS_SYSCONFIG[AUTOIDLE] is set + // to 1 (default value) . +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_STAT register. +// +//****************************************************************************** +#define MMCHS_STAT_BADA 0x20000000 +#define MMCHS_STAT_CERR 0x10000000 +#define MMCHS_STAT_ADMAE 0x02000000 +#define MMCHS_STAT_ACE 0x01000000 +#define MMCHS_STAT_DEB 0x00400000 +#define MMCHS_STAT_DCRC 0x00200000 +#define MMCHS_STAT_DTO 0x00100000 +#define MMCHS_STAT_CIE 0x00080000 +#define MMCHS_STAT_CEB 0x00040000 +#define MMCHS_STAT_CCRC 0x00020000 +#define MMCHS_STAT_CTO 0x00010000 +#define MMCHS_STAT_ERRI 0x00008000 +#define MMCHS_STAT_BSR 0x00000400 +#define MMCHS_STAT_OBI 0x00000200 +#define MMCHS_STAT_CIRQ 0x00000100 +#define MMCHS_STAT_CREM 0x00000080 +#define MMCHS_STAT_CINS 0x00000040 +#define MMCHS_STAT_BRR 0x00000020 +#define MMCHS_STAT_BWR 0x00000010 +#define MMCHS_STAT_DMA 0x00000008 +#define MMCHS_STAT_BGE 0x00000004 +#define MMCHS_STAT_TC 0x00000002 +#define MMCHS_STAT_CC 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_IE register. +// +//****************************************************************************** +#define MMCHS_IE_BADA_ENABLE 0x20000000 // Bad access to data space + // Interrupt Enable 0 Masked 1 + // Enabled +#define MMCHS_IE_CERR_ENABLE 0x10000000 // Card error interrupt Enable 0 + // Masked 1 Enabled +#define MMCHS_IE_ADMAE_ENABLE 0x02000000 // ADMA error Interrupt Enable 0 + // Masked 1 Enabled +#define MMCHS_IE_ACE_ENABLE 0x01000000 // Auto CMD12 error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_DEB_ENABLE 0x00400000 // Data end bit error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_DCRC_ENABLE 0x00200000 // Data CRC error Interrupt Enable + // 0 Masked 1 Enabled +#define MMCHS_IE_DTO_ENABLE 0x00100000 // Data timeout error Interrupt + // Enable 0 The data timeout + // detection is deactivated. The + // host controller provides the + // clock to the card until the card + // sends the data or the transfer is + // aborted. 1 The data timeout + // detection is enabled. +#define MMCHS_IE_CIE_ENABLE 0x00080000 // Command index error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_CEB_ENABLE 0x00040000 // Command end bit error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_CCRC_ENABLE 0x00020000 // Command CRC error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_CTO_ENABLE 0x00010000 // Command timeout error Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_NULL 0x00008000 // Fixed to 0 The host driver shall + // control error interrupts using + // the Error Interrupt Signal Enable + // register. Writes to this bit are + // ignored +#define MMCHS_IE_BSR_ENABLE 0x00000400 // Boot status interrupt Enable A + // write to this register when + // MMCHS_CON[BOOT_ACK] is set to 0x0 + // is ignored. 0 Masked 1 Enabled +#define MMCHS_IE_OBI_ENABLE 0x00000200 // Out-of-Band interrupt Enable A + // write to this register when + // MMCHS_CON[OBIE] is set to '0' is + // ignored. 0 Masked 1 Enabled +#define MMCHS_IE_CIRQ_ENABLE 0x00000100 // Card interrupt Enable A clear of + // this bit also clears the + // corresponding status bit. During + // 1-bit mode if the interrupt + // routine doesn't remove the source + // of a card interrupt in the SDIO + // card the status bit is reasserted + // when this bit is set to 1. 0 + // Masked 1 Enabled +#define MMCHS_IE_CREM_ENABLE 0x00000080 // Card removal Interrupt Enable 0 + // Masked 1 Enabled +#define MMCHS_IE_CINS_ENABLE 0x00000040 // Card insertion Interrupt Enable + // 0 Masked 1 Enabled +#define MMCHS_IE_BRR_ENABLE 0x00000020 // Buffer Read Ready Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_BWR_ENABLE 0x00000010 // Buffer Write Ready Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_DMA_ENABLE 0x00000008 // DMA interrupt Enable 0 Masked 1 + // Enabled +#define MMCHS_IE_BGE_ENABLE 0x00000004 // Block Gap Event Interrupt Enable + // 0 Masked 1 Enabled +#define MMCHS_IE_TC_ENABLE 0x00000002 // Transfer completed Interrupt + // Enable 0 Masked 1 Enabled +#define MMCHS_IE_CC_ENABLE 0x00000001 // Command completed Interrupt + // Enable 0 Masked 1 Enabled +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_ISE register. +// +//****************************************************************************** +#define MMCHS_ISE_BADA_SIGEN 0x20000000 // Bad access to data space signal + // status Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CERR_SIGEN 0x10000000 // Card error interrupt signal + // status Enable 0 Masked 1 Enabled +#define MMCHS_ISE_ADMAE_SIGEN 0x02000000 // ADMA error signal status Enable + // 0 Masked 1 Enabled +#define MMCHS_ISE_ACE_SIGEN 0x01000000 // Auto CMD12 error signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_DEB_SIGEN 0x00400000 // Data end bit error signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_DCRC_SIGEN 0x00200000 // Data CRC error signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_DTO_SIGEN 0x00100000 // Data timeout error signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CIE_SIGEN 0x00080000 // Command index error signal + // status Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CEB_SIGEN 0x00040000 // Command end bit error signal + // status Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CCRC_SIGEN 0x00020000 // Command CRC error signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CTO_SIGEN 0x00010000 // Command timeout error signal + // status Enable 0 Masked 1 Enabled +#define MMCHS_ISE_NULL 0x00008000 // Fixed to 0 The host driver shall + // control error interrupts using + // the Error Interrupt Signal Enable + // register. Writes to this bit are + // ignored +#define MMCHS_ISE_BSR_SIGEN 0x00000400 // Boot status signal status + // EnableA write to this register + // when MMCHS_CON[BOOT_ACK] is set + // to 0x0 is ignored. 0 Masked 1 + // Enabled +#define MMCHS_ISE_OBI_SIGEN 0x00000200 // Out-Of-Band Interrupt signal + // status Enable A write to this + // register when MMCHS_CON[OBIE] is + // set to '0' is ignored. 0 Masked 1 + // Enabled +#define MMCHS_ISE_CIRQ_SIGEN 0x00000100 // Card interrupt signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CREM_SIGEN 0x00000080 // Card removal signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CINS_SIGEN 0x00000040 // Card insertion signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_BRR_SIGEN 0x00000020 // Buffer Read Ready signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_BWR_SIGEN 0x00000010 // Buffer Write Ready signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_DMA_SIGEN 0x00000008 // DMA interrupt Signal status + // enable 0 Masked 1 Enabled +#define MMCHS_ISE_BGE_SIGEN 0x00000004 // Black Gap Event signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_TC_SIGEN 0x00000002 // Transfer completed signal status + // Enable 0 Masked 1 Enabled +#define MMCHS_ISE_CC_SIGEN 0x00000001 // Command completed signal status + // Enable 0 Masked 1 Enabled +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_AC12 register. +// +//****************************************************************************** +#define MMCHS_AC12_CNI 0x00000080 +#define MMCHS_AC12_ACIE 0x00000010 +#define MMCHS_AC12_ACEB 0x00000008 +#define MMCHS_AC12_ACCE 0x00000004 +#define MMCHS_AC12_ACTO 0x00000002 +#define MMCHS_AC12_ACNE 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_CAPA register. +// +//****************************************************************************** +#define MMCHS_CAPA_BIT64 0x10000000 +#define MMCHS_CAPA_VS18 0x04000000 +#define MMCHS_CAPA_VS30 0x02000000 +#define MMCHS_CAPA_VS33 0x01000000 +#define MMCHS_CAPA_SRS 0x00800000 +#define MMCHS_CAPA_DS 0x00400000 +#define MMCHS_CAPA_HSS 0x00200000 +#define MMCHS_CAPA_AD2S 0x00080000 +#define MMCHS_CAPA_MBL_M 0x00030000 +#define MMCHS_CAPA_MBL_S 16 +#define MMCHS_CAPA_BCF_M 0x00003F00 +#define MMCHS_CAPA_BCF_S 8 +#define MMCHS_CAPA_TCU 0x00000080 +#define MMCHS_CAPA_TCF_M 0x0000003F +#define MMCHS_CAPA_TCF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_CUR_CAPA register. +// +//****************************************************************************** +#define MMCHS_CUR_CAPA_CUR_1V8_M \ + 0x00FF0000 + +#define MMCHS_CUR_CAPA_CUR_1V8_S 16 +#define MMCHS_CUR_CAPA_CUR_3V0_M \ + 0x0000FF00 + +#define MMCHS_CUR_CAPA_CUR_3V0_S 8 +#define MMCHS_CUR_CAPA_CUR_3V3_M \ + 0x000000FF + +#define MMCHS_CUR_CAPA_CUR_3V3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_FE register. +// +//****************************************************************************** +#define MMCHS_FE_FE_BADA 0x20000000 +#define MMCHS_FE_FE_CERR 0x10000000 +#define MMCHS_FE_FE_ADMAE 0x02000000 +#define MMCHS_FE_FE_ACE 0x01000000 +#define MMCHS_FE_FE_DEB 0x00400000 +#define MMCHS_FE_FE_DCRC 0x00200000 +#define MMCHS_FE_FE_DTO 0x00100000 +#define MMCHS_FE_FE_CIE 0x00080000 +#define MMCHS_FE_FE_CEB 0x00040000 +#define MMCHS_FE_FE_CCRC 0x00020000 +#define MMCHS_FE_FE_CTO 0x00010000 +#define MMCHS_FE_FE_CNI 0x00000080 +#define MMCHS_FE_FE_ACIE 0x00000010 +#define MMCHS_FE_FE_ACEB 0x00000008 +#define MMCHS_FE_FE_ACCE 0x00000004 +#define MMCHS_FE_FE_ACTO 0x00000002 +#define MMCHS_FE_FE_ACNE 0x00000001 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_ADMAES register. +// +//****************************************************************************** +#define MMCHS_ADMAES_LME 0x00000004 // ADMA Length Mismatch Error: (1) + // While Block Count Enable being + // set the total data length + // specified by the Descriptor table + // is different from that specified + // by the Block Count and Block + // Length. (2) Total data length can + // not be divided by the block + // length. 0 No Error 1 Error +#define MMCHS_ADMAES_AES_M 0x00000003 // ADMA Error State his field + // indicates the state of ADMA when + // error is occurred during ADMA + // data transfer. "This field never + // indicates ""10"" because ADMA + // never stops in this state." 0x0 + // ST_STOP (Stop DMA)Contents of + // SYS_SDR register 0x1 ST_STOP + // (Stop DMA)Points the error + // descriptor 0x2 Never set this + // state(Not used) 0x3 ST_TFR + // (Transfer Data)Points the next of + // the error descriptor +#define MMCHS_ADMAES_AES_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_ADMASAL register. +// +//****************************************************************************** +#define MMCHS_ADMASAL_ADMA_A32B_M \ + 0xFFFFFFFF // ADMA System address 32 bits.This + // register holds byte address of + // executing command of the + // Descriptor table. 32-bit Address + // Descriptor uses lower 32-bit of + // this register. At the start of + // ADMA the Host Driver shall set + // start address of the Descriptor + // table. The ADMA increments this + // register address which points to + // next line when every fetching a + // Descriptor line. When the ADMA + // Error Interrupt is generated this + // register shall hold valid + // Descriptor address depending on + // the ADMA state. The Host Driver + // shall program Descriptor Table on + // 32-bit boundary and set 32-bit + // boundary address to this + // register. ADMA2 ignores lower + // 2-bit of this register and + // assumes it to be 00b. + +#define MMCHS_ADMASAL_ADMA_A32B_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the MMCHS_O_REV register. +// +//****************************************************************************** +#define MMCHS_REV_VREV_M 0xFF000000 // Vendor Version Number: IP + // revision [7:4] Major revision + // [3:0] Minor revision Examples: + // 0x10 for 1.0 0x21 for 2.1 +#define MMCHS_REV_VREV_S 24 +#define MMCHS_REV_SREV_M 0x00FF0000 +#define MMCHS_REV_SREV_S 16 +#define MMCHS_REV_SIS 0x00000001 // Slot Interrupt Status This + // status bit indicates the inverted + // state of interrupt signal for the + // module. By a power on reset or by + // setting a software reset for all + // (MMCHS_HCTL[SRA]) the interrupt + // signal shall be de-asserted and + // this status shall read 0. + + + +#endif // __HW_MMCHS_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_nvic.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_nvic.h new file mode 100755 index 0000000..1545f22 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_nvic.h @@ -0,0 +1,1710 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +// hw_nvic.h - Macros used when accessing the NVIC hardware. +// +//***************************************************************************** + +#ifndef __HW_NVIC_H__ +#define __HW_NVIC_H__ + +//***************************************************************************** +// +// The following are defines for the NVIC register addresses. +// +//***************************************************************************** +#define NVIC_INT_TYPE 0xE000E004 // Interrupt Controller Type Reg +#define NVIC_ACTLR 0xE000E008 // Auxiliary Control +#define NVIC_ST_CTRL 0xE000E010 // SysTick Control and Status + // Register +#define NVIC_ST_RELOAD 0xE000E014 // SysTick Reload Value Register +#define NVIC_ST_CURRENT 0xE000E018 // SysTick Current Value Register +#define NVIC_ST_CAL 0xE000E01C // SysTick Calibration Value Reg + +#define NVIC_EN0 0xE000E100 // Interrupt 0-31 Set Enable +#define NVIC_EN1 0xE000E104 // Interrupt 32-54 Set Enable +#define NVIC_EN2 0xE000E108 // Interrupt 64-95 Set Enable +#define NVIC_EN3 0xE000E10C // Interrupt 96-127 Set Enable +#define NVIC_EN4 0xE000E110 // Interrupt 128-131 Set Enable +#define NVIC_EN5 0xE000E114 // Interrupt 160-191 Set Enable + +#define NVIC_DIS0 0xE000E180 // Interrupt 0-31 Clear Enable +#define NVIC_DIS1 0xE000E184 // Interrupt 32-54 Clear Enable + +#define NVIC_DIS2 0xE000E188 // Interrupt 64-95 Clear Enable +#define NVIC_DIS3 0xE000E18C // Interrupt 96-127 Clear Enable +#define NVIC_DIS4 0xE000E190 // Interrupt 128-131 Clear Enable +#define NVIC_DIS5 0xE000E194 // Interrupt 160-191 Clear Enable + +#define NVIC_PEND0 0xE000E200 // Interrupt 0-31 Set Pending +#define NVIC_PEND1 0xE000E204 // Interrupt 32-54 Set Pending + +#define NVIC_PEND2 0xE000E208 // Interrupt 64-95 Set Pending +#define NVIC_PEND3 0xE000E20C // Interrupt 96-127 Set Pending +#define NVIC_PEND4 0xE000E210 // Interrupt 128-131 Set Pending +#define NVIC_PEND5 0xE000E214 // Interrupt 160-191 Set Pending + +#define NVIC_UNPEND0 0xE000E280 // Interrupt 0-31 Clear Pending +#define NVIC_UNPEND1 0xE000E284 // Interrupt 32-54 Clear Pending + +#define NVIC_UNPEND2 0xE000E288 // Interrupt 64-95 Clear Pending +#define NVIC_UNPEND3 0xE000E28C // Interrupt 96-127 Clear Pending +#define NVIC_UNPEND4 0xE000E290 // Interrupt 128-131 Clear Pending +#define NVIC_UNPEND5 0xE000E294 // Interrupt 160-191 Clear Pending + +#define NVIC_ACTIVE0 0xE000E300 // Interrupt 0-31 Active Bit +#define NVIC_ACTIVE1 0xE000E304 // Interrupt 32-54 Active Bit + +#define NVIC_ACTIVE2 0xE000E308 // Interrupt 64-95 Active Bit +#define NVIC_ACTIVE3 0xE000E30C // Interrupt 96-127 Active Bit +#define NVIC_ACTIVE4 0xE000E310 // Interrupt 128-131 Active Bit +#define NVIC_ACTIVE5 0xE000E314 // Interrupt 160-191 Active Bit + +#define NVIC_PRI0 0xE000E400 // Interrupt 0-3 Priority +#define NVIC_PRI1 0xE000E404 // Interrupt 4-7 Priority +#define NVIC_PRI2 0xE000E408 // Interrupt 8-11 Priority +#define NVIC_PRI3 0xE000E40C // Interrupt 12-15 Priority +#define NVIC_PRI4 0xE000E410 // Interrupt 16-19 Priority +#define NVIC_PRI5 0xE000E414 // Interrupt 20-23 Priority +#define NVIC_PRI6 0xE000E418 // Interrupt 24-27 Priority +#define NVIC_PRI7 0xE000E41C // Interrupt 28-31 Priority +#define NVIC_PRI8 0xE000E420 // Interrupt 32-35 Priority +#define NVIC_PRI9 0xE000E424 // Interrupt 36-39 Priority +#define NVIC_PRI10 0xE000E428 // Interrupt 40-43 Priority +#define NVIC_PRI11 0xE000E42C // Interrupt 44-47 Priority +#define NVIC_PRI12 0xE000E430 // Interrupt 48-51 Priority +#define NVIC_PRI13 0xE000E434 // Interrupt 52-53 Priority + +#define NVIC_PRI14 0xE000E438 // Interrupt 56-59 Priority +#define NVIC_PRI15 0xE000E43C // Interrupt 60-63 Priority +#define NVIC_PRI16 0xE000E440 // Interrupt 64-67 Priority +#define NVIC_PRI17 0xE000E444 // Interrupt 68-71 Priority +#define NVIC_PRI18 0xE000E448 // Interrupt 72-75 Priority +#define NVIC_PRI19 0xE000E44C // Interrupt 76-79 Priority +#define NVIC_PRI20 0xE000E450 // Interrupt 80-83 Priority +#define NVIC_PRI21 0xE000E454 // Interrupt 84-87 Priority +#define NVIC_PRI22 0xE000E458 // Interrupt 88-91 Priority +#define NVIC_PRI23 0xE000E45C // Interrupt 92-95 Priority +#define NVIC_PRI24 0xE000E460 // Interrupt 96-99 Priority +#define NVIC_PRI25 0xE000E464 // Interrupt 100-103 Priority +#define NVIC_PRI26 0xE000E468 // Interrupt 104-107 Priority +#define NVIC_PRI27 0xE000E46C // Interrupt 108-111 Priority +#define NVIC_PRI28 0xE000E470 // Interrupt 112-115 Priority +#define NVIC_PRI29 0xE000E474 // Interrupt 116-119 Priority +#define NVIC_PRI30 0xE000E478 // Interrupt 120-123 Priority +#define NVIC_PRI31 0xE000E47C // Interrupt 124-127 Priority +#define NVIC_PRI32 0xE000E480 // Interrupt 128-131 Priority +#define NVIC_PRI33 0xE000E484 // Interrupt 132-135 Priority +#define NVIC_PRI34 0xE000E488 // Interrupt 136-139 Priority +#define NVIC_PRI35 0xE000E48C // Interrupt 140-143 Priority +#define NVIC_PRI36 0xE000E490 // Interrupt 144-147 Priority +#define NVIC_PRI37 0xE000E494 // Interrupt 148-151 Priority +#define NVIC_PRI38 0xE000E498 // Interrupt 152-155 Priority +#define NVIC_PRI39 0xE000E49C // Interrupt 156-159 Priority +#define NVIC_PRI40 0xE000E4A0 // Interrupt 160-163 Priority +#define NVIC_PRI41 0xE000E4A4 // Interrupt 164-167 Priority +#define NVIC_PRI42 0xE000E4A8 // Interrupt 168-171 Priority +#define NVIC_PRI43 0xE000E4AC // Interrupt 172-175 Priority +#define NVIC_PRI44 0xE000E4B0 // Interrupt 176-179 Priority +#define NVIC_PRI45 0xE000E4B4 // Interrupt 180-183 Priority +#define NVIC_PRI46 0xE000E4B8 // Interrupt 184-187 Priority +#define NVIC_PRI47 0xE000E4BC // Interrupt 188-191 Priority +#define NVIC_PRI48 0xE000E4C0 // Interrupt 192-195 Priority + + + +#define NVIC_CPUID 0xE000ED00 // CPU ID Base +#define NVIC_INT_CTRL 0xE000ED04 // Interrupt Control and State +#define NVIC_VTABLE 0xE000ED08 // Vector Table Offset +#define NVIC_APINT 0xE000ED0C // Application Interrupt and Reset + // Control +#define NVIC_SYS_CTRL 0xE000ED10 // System Control +#define NVIC_CFG_CTRL 0xE000ED14 // Configuration and Control +#define NVIC_SYS_PRI1 0xE000ED18 // System Handler Priority 1 +#define NVIC_SYS_PRI2 0xE000ED1C // System Handler Priority 2 +#define NVIC_SYS_PRI3 0xE000ED20 // System Handler Priority 3 +#define NVIC_SYS_HND_CTRL 0xE000ED24 // System Handler Control and State +#define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status +#define NVIC_HFAULT_STAT 0xE000ED2C // Hard Fault Status +#define NVIC_DEBUG_STAT 0xE000ED30 // Debug Status Register +#define NVIC_MM_ADDR 0xE000ED34 // Memory Management Fault Address +#define NVIC_FAULT_ADDR 0xE000ED38 // Bus Fault Address +#define NVIC_MPU_TYPE 0xE000ED90 // MPU Type +#define NVIC_MPU_CTRL 0xE000ED94 // MPU Control +#define NVIC_MPU_NUMBER 0xE000ED98 // MPU Region Number +#define NVIC_MPU_BASE 0xE000ED9C // MPU Region Base Address +#define NVIC_MPU_ATTR 0xE000EDA0 // MPU Region Attribute and Size +#define NVIC_MPU_BASE1 0xE000EDA4 // MPU Region Base Address Alias 1 +#define NVIC_MPU_ATTR1 0xE000EDA8 // MPU Region Attribute and Size + // Alias 1 +#define NVIC_MPU_BASE2 0xE000EDAC // MPU Region Base Address Alias 2 +#define NVIC_MPU_ATTR2 0xE000EDB0 // MPU Region Attribute and Size + // Alias 2 +#define NVIC_MPU_BASE3 0xE000EDB4 // MPU Region Base Address Alias 3 +#define NVIC_MPU_ATTR3 0xE000EDB8 // MPU Region Attribute and Size + // Alias 3 +#define NVIC_DBG_CTRL 0xE000EDF0 // Debug Control and Status Reg +#define NVIC_DBG_XFER 0xE000EDF4 // Debug Core Reg. Transfer Select +#define NVIC_DBG_DATA 0xE000EDF8 // Debug Core Register Data +#define NVIC_DBG_INT 0xE000EDFC // Debug Reset Interrupt Control +#define NVIC_SW_TRIG 0xE000EF00 // Software Trigger Interrupt + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_INT_TYPE register. +// +//***************************************************************************** +#define NVIC_INT_TYPE_LINES_M 0x0000001F // Number of interrupt lines (x32) +#define NVIC_INT_TYPE_LINES_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTLR register. +// +//***************************************************************************** +#define NVIC_ACTLR_DISFOLD 0x00000004 // Disable IT Folding +#define NVIC_ACTLR_DISWBUF 0x00000002 // Disable Write Buffer +#define NVIC_ACTLR_DISMCYC 0x00000001 // Disable Interrupts of Multiple + // Cycle Instructions + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ST_CTRL register. +// +//***************************************************************************** +#define NVIC_ST_CTRL_COUNT 0x00010000 // Count Flag +#define NVIC_ST_CTRL_CLK_SRC 0x00000004 // Clock Source +#define NVIC_ST_CTRL_INTEN 0x00000002 // Interrupt Enable +#define NVIC_ST_CTRL_ENABLE 0x00000001 // Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ST_RELOAD register. +// +//***************************************************************************** +#define NVIC_ST_RELOAD_M 0x00FFFFFF // Reload Value +#define NVIC_ST_RELOAD_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ST_CURRENT +// register. +// +//***************************************************************************** +#define NVIC_ST_CURRENT_M 0x00FFFFFF // Current Value +#define NVIC_ST_CURRENT_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ST_CAL register. +// +//***************************************************************************** +#define NVIC_ST_CAL_NOREF 0x80000000 // No reference clock +#define NVIC_ST_CAL_SKEW 0x40000000 // Clock skew +#define NVIC_ST_CAL_ONEMS_M 0x00FFFFFF // 1ms reference value +#define NVIC_ST_CAL_ONEMS_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_EN0 register. +// +//***************************************************************************** +#define NVIC_EN0_INT_M 0xFFFFFFFF // Interrupt Enable +#define NVIC_EN0_INT0 0x00000001 // Interrupt 0 enable +#define NVIC_EN0_INT1 0x00000002 // Interrupt 1 enable +#define NVIC_EN0_INT2 0x00000004 // Interrupt 2 enable +#define NVIC_EN0_INT3 0x00000008 // Interrupt 3 enable +#define NVIC_EN0_INT4 0x00000010 // Interrupt 4 enable +#define NVIC_EN0_INT5 0x00000020 // Interrupt 5 enable +#define NVIC_EN0_INT6 0x00000040 // Interrupt 6 enable +#define NVIC_EN0_INT7 0x00000080 // Interrupt 7 enable +#define NVIC_EN0_INT8 0x00000100 // Interrupt 8 enable +#define NVIC_EN0_INT9 0x00000200 // Interrupt 9 enable +#define NVIC_EN0_INT10 0x00000400 // Interrupt 10 enable +#define NVIC_EN0_INT11 0x00000800 // Interrupt 11 enable +#define NVIC_EN0_INT12 0x00001000 // Interrupt 12 enable +#define NVIC_EN0_INT13 0x00002000 // Interrupt 13 enable +#define NVIC_EN0_INT14 0x00004000 // Interrupt 14 enable +#define NVIC_EN0_INT15 0x00008000 // Interrupt 15 enable +#define NVIC_EN0_INT16 0x00010000 // Interrupt 16 enable +#define NVIC_EN0_INT17 0x00020000 // Interrupt 17 enable +#define NVIC_EN0_INT18 0x00040000 // Interrupt 18 enable +#define NVIC_EN0_INT19 0x00080000 // Interrupt 19 enable +#define NVIC_EN0_INT20 0x00100000 // Interrupt 20 enable +#define NVIC_EN0_INT21 0x00200000 // Interrupt 21 enable +#define NVIC_EN0_INT22 0x00400000 // Interrupt 22 enable +#define NVIC_EN0_INT23 0x00800000 // Interrupt 23 enable +#define NVIC_EN0_INT24 0x01000000 // Interrupt 24 enable +#define NVIC_EN0_INT25 0x02000000 // Interrupt 25 enable +#define NVIC_EN0_INT26 0x04000000 // Interrupt 26 enable +#define NVIC_EN0_INT27 0x08000000 // Interrupt 27 enable +#define NVIC_EN0_INT28 0x10000000 // Interrupt 28 enable +#define NVIC_EN0_INT29 0x20000000 // Interrupt 29 enable +#define NVIC_EN0_INT30 0x40000000 // Interrupt 30 enable +#define NVIC_EN0_INT31 0x80000000 // Interrupt 31 enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_EN1 register. +// +//***************************************************************************** +#define NVIC_EN1_INT_M 0x007FFFFF // Interrupt Enable + +#undef NVIC_EN1_INT_M +#define NVIC_EN1_INT_M 0xFFFFFFFF // Interrupt Enable + +#define NVIC_EN1_INT32 0x00000001 // Interrupt 32 enable +#define NVIC_EN1_INT33 0x00000002 // Interrupt 33 enable +#define NVIC_EN1_INT34 0x00000004 // Interrupt 34 enable +#define NVIC_EN1_INT35 0x00000008 // Interrupt 35 enable +#define NVIC_EN1_INT36 0x00000010 // Interrupt 36 enable +#define NVIC_EN1_INT37 0x00000020 // Interrupt 37 enable +#define NVIC_EN1_INT38 0x00000040 // Interrupt 38 enable +#define NVIC_EN1_INT39 0x00000080 // Interrupt 39 enable +#define NVIC_EN1_INT40 0x00000100 // Interrupt 40 enable +#define NVIC_EN1_INT41 0x00000200 // Interrupt 41 enable +#define NVIC_EN1_INT42 0x00000400 // Interrupt 42 enable +#define NVIC_EN1_INT43 0x00000800 // Interrupt 43 enable +#define NVIC_EN1_INT44 0x00001000 // Interrupt 44 enable +#define NVIC_EN1_INT45 0x00002000 // Interrupt 45 enable +#define NVIC_EN1_INT46 0x00004000 // Interrupt 46 enable +#define NVIC_EN1_INT47 0x00008000 // Interrupt 47 enable +#define NVIC_EN1_INT48 0x00010000 // Interrupt 48 enable +#define NVIC_EN1_INT49 0x00020000 // Interrupt 49 enable +#define NVIC_EN1_INT50 0x00040000 // Interrupt 50 enable +#define NVIC_EN1_INT51 0x00080000 // Interrupt 51 enable +#define NVIC_EN1_INT52 0x00100000 // Interrupt 52 enable +#define NVIC_EN1_INT53 0x00200000 // Interrupt 53 enable +#define NVIC_EN1_INT54 0x00400000 // Interrupt 54 enable + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_EN2 register. +// +//***************************************************************************** +#define NVIC_EN2_INT_M 0xFFFFFFFF // Interrupt Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_EN3 register. +// +//***************************************************************************** +#define NVIC_EN3_INT_M 0xFFFFFFFF // Interrupt Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_EN4 register. +// +//***************************************************************************** +#define NVIC_EN4_INT_M 0x0000000F // Interrupt Enable + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DIS0 register. +// +//***************************************************************************** +#define NVIC_DIS0_INT_M 0xFFFFFFFF // Interrupt Disable +#define NVIC_DIS0_INT0 0x00000001 // Interrupt 0 disable +#define NVIC_DIS0_INT1 0x00000002 // Interrupt 1 disable +#define NVIC_DIS0_INT2 0x00000004 // Interrupt 2 disable +#define NVIC_DIS0_INT3 0x00000008 // Interrupt 3 disable +#define NVIC_DIS0_INT4 0x00000010 // Interrupt 4 disable +#define NVIC_DIS0_INT5 0x00000020 // Interrupt 5 disable +#define NVIC_DIS0_INT6 0x00000040 // Interrupt 6 disable +#define NVIC_DIS0_INT7 0x00000080 // Interrupt 7 disable +#define NVIC_DIS0_INT8 0x00000100 // Interrupt 8 disable +#define NVIC_DIS0_INT9 0x00000200 // Interrupt 9 disable +#define NVIC_DIS0_INT10 0x00000400 // Interrupt 10 disable +#define NVIC_DIS0_INT11 0x00000800 // Interrupt 11 disable +#define NVIC_DIS0_INT12 0x00001000 // Interrupt 12 disable +#define NVIC_DIS0_INT13 0x00002000 // Interrupt 13 disable +#define NVIC_DIS0_INT14 0x00004000 // Interrupt 14 disable +#define NVIC_DIS0_INT15 0x00008000 // Interrupt 15 disable +#define NVIC_DIS0_INT16 0x00010000 // Interrupt 16 disable +#define NVIC_DIS0_INT17 0x00020000 // Interrupt 17 disable +#define NVIC_DIS0_INT18 0x00040000 // Interrupt 18 disable +#define NVIC_DIS0_INT19 0x00080000 // Interrupt 19 disable +#define NVIC_DIS0_INT20 0x00100000 // Interrupt 20 disable +#define NVIC_DIS0_INT21 0x00200000 // Interrupt 21 disable +#define NVIC_DIS0_INT22 0x00400000 // Interrupt 22 disable +#define NVIC_DIS0_INT23 0x00800000 // Interrupt 23 disable +#define NVIC_DIS0_INT24 0x01000000 // Interrupt 24 disable +#define NVIC_DIS0_INT25 0x02000000 // Interrupt 25 disable +#define NVIC_DIS0_INT26 0x04000000 // Interrupt 26 disable +#define NVIC_DIS0_INT27 0x08000000 // Interrupt 27 disable +#define NVIC_DIS0_INT28 0x10000000 // Interrupt 28 disable +#define NVIC_DIS0_INT29 0x20000000 // Interrupt 29 disable +#define NVIC_DIS0_INT30 0x40000000 // Interrupt 30 disable +#define NVIC_DIS0_INT31 0x80000000 // Interrupt 31 disable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DIS1 register. +// +//***************************************************************************** +#define NVIC_DIS1_INT_M 0x00FFFFFF // Interrupt Disable + +#undef NVIC_DIS1_INT_M +#define NVIC_DIS1_INT_M 0xFFFFFFFF // Interrupt Disable + +#define NVIC_DIS1_INT32 0x00000001 // Interrupt 32 disable +#define NVIC_DIS1_INT33 0x00000002 // Interrupt 33 disable +#define NVIC_DIS1_INT34 0x00000004 // Interrupt 34 disable +#define NVIC_DIS1_INT35 0x00000008 // Interrupt 35 disable +#define NVIC_DIS1_INT36 0x00000010 // Interrupt 36 disable +#define NVIC_DIS1_INT37 0x00000020 // Interrupt 37 disable +#define NVIC_DIS1_INT38 0x00000040 // Interrupt 38 disable +#define NVIC_DIS1_INT39 0x00000080 // Interrupt 39 disable +#define NVIC_DIS1_INT40 0x00000100 // Interrupt 40 disable +#define NVIC_DIS1_INT41 0x00000200 // Interrupt 41 disable +#define NVIC_DIS1_INT42 0x00000400 // Interrupt 42 disable +#define NVIC_DIS1_INT43 0x00000800 // Interrupt 43 disable +#define NVIC_DIS1_INT44 0x00001000 // Interrupt 44 disable +#define NVIC_DIS1_INT45 0x00002000 // Interrupt 45 disable +#define NVIC_DIS1_INT46 0x00004000 // Interrupt 46 disable +#define NVIC_DIS1_INT47 0x00008000 // Interrupt 47 disable +#define NVIC_DIS1_INT48 0x00010000 // Interrupt 48 disable +#define NVIC_DIS1_INT49 0x00020000 // Interrupt 49 disable +#define NVIC_DIS1_INT50 0x00040000 // Interrupt 50 disable +#define NVIC_DIS1_INT51 0x00080000 // Interrupt 51 disable +#define NVIC_DIS1_INT52 0x00100000 // Interrupt 52 disable +#define NVIC_DIS1_INT53 0x00200000 // Interrupt 53 disable +#define NVIC_DIS1_INT54 0x00400000 // Interrupt 54 disable +#define NVIC_DIS1_INT55 0x00800000 // Interrupt 55 disable + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DIS2 register. +// +//***************************************************************************** +#define NVIC_DIS2_INT_M 0xFFFFFFFF // Interrupt Disable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DIS3 register. +// +//***************************************************************************** +#define NVIC_DIS3_INT_M 0xFFFFFFFF // Interrupt Disable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DIS4 register. +// +//***************************************************************************** +#define NVIC_DIS4_INT_M 0x0000000F // Interrupt Disable + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PEND0 register. +// +//***************************************************************************** +#define NVIC_PEND0_INT_M 0xFFFFFFFF // Interrupt Set Pending +#define NVIC_PEND0_INT0 0x00000001 // Interrupt 0 pend +#define NVIC_PEND0_INT1 0x00000002 // Interrupt 1 pend +#define NVIC_PEND0_INT2 0x00000004 // Interrupt 2 pend +#define NVIC_PEND0_INT3 0x00000008 // Interrupt 3 pend +#define NVIC_PEND0_INT4 0x00000010 // Interrupt 4 pend +#define NVIC_PEND0_INT5 0x00000020 // Interrupt 5 pend +#define NVIC_PEND0_INT6 0x00000040 // Interrupt 6 pend +#define NVIC_PEND0_INT7 0x00000080 // Interrupt 7 pend +#define NVIC_PEND0_INT8 0x00000100 // Interrupt 8 pend +#define NVIC_PEND0_INT9 0x00000200 // Interrupt 9 pend +#define NVIC_PEND0_INT10 0x00000400 // Interrupt 10 pend +#define NVIC_PEND0_INT11 0x00000800 // Interrupt 11 pend +#define NVIC_PEND0_INT12 0x00001000 // Interrupt 12 pend +#define NVIC_PEND0_INT13 0x00002000 // Interrupt 13 pend +#define NVIC_PEND0_INT14 0x00004000 // Interrupt 14 pend +#define NVIC_PEND0_INT15 0x00008000 // Interrupt 15 pend +#define NVIC_PEND0_INT16 0x00010000 // Interrupt 16 pend +#define NVIC_PEND0_INT17 0x00020000 // Interrupt 17 pend +#define NVIC_PEND0_INT18 0x00040000 // Interrupt 18 pend +#define NVIC_PEND0_INT19 0x00080000 // Interrupt 19 pend +#define NVIC_PEND0_INT20 0x00100000 // Interrupt 20 pend +#define NVIC_PEND0_INT21 0x00200000 // Interrupt 21 pend +#define NVIC_PEND0_INT22 0x00400000 // Interrupt 22 pend +#define NVIC_PEND0_INT23 0x00800000 // Interrupt 23 pend +#define NVIC_PEND0_INT24 0x01000000 // Interrupt 24 pend +#define NVIC_PEND0_INT25 0x02000000 // Interrupt 25 pend +#define NVIC_PEND0_INT26 0x04000000 // Interrupt 26 pend +#define NVIC_PEND0_INT27 0x08000000 // Interrupt 27 pend +#define NVIC_PEND0_INT28 0x10000000 // Interrupt 28 pend +#define NVIC_PEND0_INT29 0x20000000 // Interrupt 29 pend +#define NVIC_PEND0_INT30 0x40000000 // Interrupt 30 pend +#define NVIC_PEND0_INT31 0x80000000 // Interrupt 31 pend + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PEND1 register. +// +//***************************************************************************** +#define NVIC_PEND1_INT_M 0x00FFFFFF // Interrupt Set Pending + +#undef NVIC_PEND1_INT_M +#define NVIC_PEND1_INT_M 0xFFFFFFFF // Interrupt Set Pending + +#define NVIC_PEND1_INT32 0x00000001 // Interrupt 32 pend +#define NVIC_PEND1_INT33 0x00000002 // Interrupt 33 pend +#define NVIC_PEND1_INT34 0x00000004 // Interrupt 34 pend +#define NVIC_PEND1_INT35 0x00000008 // Interrupt 35 pend +#define NVIC_PEND1_INT36 0x00000010 // Interrupt 36 pend +#define NVIC_PEND1_INT37 0x00000020 // Interrupt 37 pend +#define NVIC_PEND1_INT38 0x00000040 // Interrupt 38 pend +#define NVIC_PEND1_INT39 0x00000080 // Interrupt 39 pend +#define NVIC_PEND1_INT40 0x00000100 // Interrupt 40 pend +#define NVIC_PEND1_INT41 0x00000200 // Interrupt 41 pend +#define NVIC_PEND1_INT42 0x00000400 // Interrupt 42 pend +#define NVIC_PEND1_INT43 0x00000800 // Interrupt 43 pend +#define NVIC_PEND1_INT44 0x00001000 // Interrupt 44 pend +#define NVIC_PEND1_INT45 0x00002000 // Interrupt 45 pend +#define NVIC_PEND1_INT46 0x00004000 // Interrupt 46 pend +#define NVIC_PEND1_INT47 0x00008000 // Interrupt 47 pend +#define NVIC_PEND1_INT48 0x00010000 // Interrupt 48 pend +#define NVIC_PEND1_INT49 0x00020000 // Interrupt 49 pend +#define NVIC_PEND1_INT50 0x00040000 // Interrupt 50 pend +#define NVIC_PEND1_INT51 0x00080000 // Interrupt 51 pend +#define NVIC_PEND1_INT52 0x00100000 // Interrupt 52 pend +#define NVIC_PEND1_INT53 0x00200000 // Interrupt 53 pend +#define NVIC_PEND1_INT54 0x00400000 // Interrupt 54 pend +#define NVIC_PEND1_INT55 0x00800000 // Interrupt 55 pend + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PEND2 register. +// +//***************************************************************************** +#define NVIC_PEND2_INT_M 0xFFFFFFFF // Interrupt Set Pending + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PEND3 register. +// +//***************************************************************************** +#define NVIC_PEND3_INT_M 0xFFFFFFFF // Interrupt Set Pending + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PEND4 register. +// +//***************************************************************************** +#define NVIC_PEND4_INT_M 0x0000000F // Interrupt Set Pending + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_UNPEND0 register. +// +//***************************************************************************** +#define NVIC_UNPEND0_INT_M 0xFFFFFFFF // Interrupt Clear Pending +#define NVIC_UNPEND0_INT0 0x00000001 // Interrupt 0 unpend +#define NVIC_UNPEND0_INT1 0x00000002 // Interrupt 1 unpend +#define NVIC_UNPEND0_INT2 0x00000004 // Interrupt 2 unpend +#define NVIC_UNPEND0_INT3 0x00000008 // Interrupt 3 unpend +#define NVIC_UNPEND0_INT4 0x00000010 // Interrupt 4 unpend +#define NVIC_UNPEND0_INT5 0x00000020 // Interrupt 5 unpend +#define NVIC_UNPEND0_INT6 0x00000040 // Interrupt 6 unpend +#define NVIC_UNPEND0_INT7 0x00000080 // Interrupt 7 unpend +#define NVIC_UNPEND0_INT8 0x00000100 // Interrupt 8 unpend +#define NVIC_UNPEND0_INT9 0x00000200 // Interrupt 9 unpend +#define NVIC_UNPEND0_INT10 0x00000400 // Interrupt 10 unpend +#define NVIC_UNPEND0_INT11 0x00000800 // Interrupt 11 unpend +#define NVIC_UNPEND0_INT12 0x00001000 // Interrupt 12 unpend +#define NVIC_UNPEND0_INT13 0x00002000 // Interrupt 13 unpend +#define NVIC_UNPEND0_INT14 0x00004000 // Interrupt 14 unpend +#define NVIC_UNPEND0_INT15 0x00008000 // Interrupt 15 unpend +#define NVIC_UNPEND0_INT16 0x00010000 // Interrupt 16 unpend +#define NVIC_UNPEND0_INT17 0x00020000 // Interrupt 17 unpend +#define NVIC_UNPEND0_INT18 0x00040000 // Interrupt 18 unpend +#define NVIC_UNPEND0_INT19 0x00080000 // Interrupt 19 unpend +#define NVIC_UNPEND0_INT20 0x00100000 // Interrupt 20 unpend +#define NVIC_UNPEND0_INT21 0x00200000 // Interrupt 21 unpend +#define NVIC_UNPEND0_INT22 0x00400000 // Interrupt 22 unpend +#define NVIC_UNPEND0_INT23 0x00800000 // Interrupt 23 unpend +#define NVIC_UNPEND0_INT24 0x01000000 // Interrupt 24 unpend +#define NVIC_UNPEND0_INT25 0x02000000 // Interrupt 25 unpend +#define NVIC_UNPEND0_INT26 0x04000000 // Interrupt 26 unpend +#define NVIC_UNPEND0_INT27 0x08000000 // Interrupt 27 unpend +#define NVIC_UNPEND0_INT28 0x10000000 // Interrupt 28 unpend +#define NVIC_UNPEND0_INT29 0x20000000 // Interrupt 29 unpend +#define NVIC_UNPEND0_INT30 0x40000000 // Interrupt 30 unpend +#define NVIC_UNPEND0_INT31 0x80000000 // Interrupt 31 unpend + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_UNPEND1 register. +// +//***************************************************************************** +#define NVIC_UNPEND1_INT_M 0x00FFFFFF // Interrupt Clear Pending + +#undef NVIC_UNPEND1_INT_M +#define NVIC_UNPEND1_INT_M 0xFFFFFFFF // Interrupt Clear Pending + +#define NVIC_UNPEND1_INT32 0x00000001 // Interrupt 32 unpend +#define NVIC_UNPEND1_INT33 0x00000002 // Interrupt 33 unpend +#define NVIC_UNPEND1_INT34 0x00000004 // Interrupt 34 unpend +#define NVIC_UNPEND1_INT35 0x00000008 // Interrupt 35 unpend +#define NVIC_UNPEND1_INT36 0x00000010 // Interrupt 36 unpend +#define NVIC_UNPEND1_INT37 0x00000020 // Interrupt 37 unpend +#define NVIC_UNPEND1_INT38 0x00000040 // Interrupt 38 unpend +#define NVIC_UNPEND1_INT39 0x00000080 // Interrupt 39 unpend +#define NVIC_UNPEND1_INT40 0x00000100 // Interrupt 40 unpend +#define NVIC_UNPEND1_INT41 0x00000200 // Interrupt 41 unpend +#define NVIC_UNPEND1_INT42 0x00000400 // Interrupt 42 unpend +#define NVIC_UNPEND1_INT43 0x00000800 // Interrupt 43 unpend +#define NVIC_UNPEND1_INT44 0x00001000 // Interrupt 44 unpend +#define NVIC_UNPEND1_INT45 0x00002000 // Interrupt 45 unpend +#define NVIC_UNPEND1_INT46 0x00004000 // Interrupt 46 unpend +#define NVIC_UNPEND1_INT47 0x00008000 // Interrupt 47 unpend +#define NVIC_UNPEND1_INT48 0x00010000 // Interrupt 48 unpend +#define NVIC_UNPEND1_INT49 0x00020000 // Interrupt 49 unpend +#define NVIC_UNPEND1_INT50 0x00040000 // Interrupt 50 unpend +#define NVIC_UNPEND1_INT51 0x00080000 // Interrupt 51 unpend +#define NVIC_UNPEND1_INT52 0x00100000 // Interrupt 52 unpend +#define NVIC_UNPEND1_INT53 0x00200000 // Interrupt 53 unpend +#define NVIC_UNPEND1_INT54 0x00400000 // Interrupt 54 unpend +#define NVIC_UNPEND1_INT55 0x00800000 // Interrupt 55 unpend + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_UNPEND2 register. +// +//***************************************************************************** +#define NVIC_UNPEND2_INT_M 0xFFFFFFFF // Interrupt Clear Pending + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_UNPEND3 register. +// +//***************************************************************************** +#define NVIC_UNPEND3_INT_M 0xFFFFFFFF // Interrupt Clear Pending + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_UNPEND4 register. +// +//***************************************************************************** +#define NVIC_UNPEND4_INT_M 0x0000000F // Interrupt Clear Pending + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTIVE0 register. +// +//***************************************************************************** +#define NVIC_ACTIVE0_INT_M 0xFFFFFFFF // Interrupt Active +#define NVIC_ACTIVE0_INT0 0x00000001 // Interrupt 0 active +#define NVIC_ACTIVE0_INT1 0x00000002 // Interrupt 1 active +#define NVIC_ACTIVE0_INT2 0x00000004 // Interrupt 2 active +#define NVIC_ACTIVE0_INT3 0x00000008 // Interrupt 3 active +#define NVIC_ACTIVE0_INT4 0x00000010 // Interrupt 4 active +#define NVIC_ACTIVE0_INT5 0x00000020 // Interrupt 5 active +#define NVIC_ACTIVE0_INT6 0x00000040 // Interrupt 6 active +#define NVIC_ACTIVE0_INT7 0x00000080 // Interrupt 7 active +#define NVIC_ACTIVE0_INT8 0x00000100 // Interrupt 8 active +#define NVIC_ACTIVE0_INT9 0x00000200 // Interrupt 9 active +#define NVIC_ACTIVE0_INT10 0x00000400 // Interrupt 10 active +#define NVIC_ACTIVE0_INT11 0x00000800 // Interrupt 11 active +#define NVIC_ACTIVE0_INT12 0x00001000 // Interrupt 12 active +#define NVIC_ACTIVE0_INT13 0x00002000 // Interrupt 13 active +#define NVIC_ACTIVE0_INT14 0x00004000 // Interrupt 14 active +#define NVIC_ACTIVE0_INT15 0x00008000 // Interrupt 15 active +#define NVIC_ACTIVE0_INT16 0x00010000 // Interrupt 16 active +#define NVIC_ACTIVE0_INT17 0x00020000 // Interrupt 17 active +#define NVIC_ACTIVE0_INT18 0x00040000 // Interrupt 18 active +#define NVIC_ACTIVE0_INT19 0x00080000 // Interrupt 19 active +#define NVIC_ACTIVE0_INT20 0x00100000 // Interrupt 20 active +#define NVIC_ACTIVE0_INT21 0x00200000 // Interrupt 21 active +#define NVIC_ACTIVE0_INT22 0x00400000 // Interrupt 22 active +#define NVIC_ACTIVE0_INT23 0x00800000 // Interrupt 23 active +#define NVIC_ACTIVE0_INT24 0x01000000 // Interrupt 24 active +#define NVIC_ACTIVE0_INT25 0x02000000 // Interrupt 25 active +#define NVIC_ACTIVE0_INT26 0x04000000 // Interrupt 26 active +#define NVIC_ACTIVE0_INT27 0x08000000 // Interrupt 27 active +#define NVIC_ACTIVE0_INT28 0x10000000 // Interrupt 28 active +#define NVIC_ACTIVE0_INT29 0x20000000 // Interrupt 29 active +#define NVIC_ACTIVE0_INT30 0x40000000 // Interrupt 30 active +#define NVIC_ACTIVE0_INT31 0x80000000 // Interrupt 31 active + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTIVE1 register. +// +//***************************************************************************** +#define NVIC_ACTIVE1_INT_M 0x00FFFFFF // Interrupt Active + +#undef NVIC_ACTIVE1_INT_M +#define NVIC_ACTIVE1_INT_M 0xFFFFFFFF // Interrupt Active + +#define NVIC_ACTIVE1_INT32 0x00000001 // Interrupt 32 active +#define NVIC_ACTIVE1_INT33 0x00000002 // Interrupt 33 active +#define NVIC_ACTIVE1_INT34 0x00000004 // Interrupt 34 active +#define NVIC_ACTIVE1_INT35 0x00000008 // Interrupt 35 active +#define NVIC_ACTIVE1_INT36 0x00000010 // Interrupt 36 active +#define NVIC_ACTIVE1_INT37 0x00000020 // Interrupt 37 active +#define NVIC_ACTIVE1_INT38 0x00000040 // Interrupt 38 active +#define NVIC_ACTIVE1_INT39 0x00000080 // Interrupt 39 active +#define NVIC_ACTIVE1_INT40 0x00000100 // Interrupt 40 active +#define NVIC_ACTIVE1_INT41 0x00000200 // Interrupt 41 active +#define NVIC_ACTIVE1_INT42 0x00000400 // Interrupt 42 active +#define NVIC_ACTIVE1_INT43 0x00000800 // Interrupt 43 active +#define NVIC_ACTIVE1_INT44 0x00001000 // Interrupt 44 active +#define NVIC_ACTIVE1_INT45 0x00002000 // Interrupt 45 active +#define NVIC_ACTIVE1_INT46 0x00004000 // Interrupt 46 active +#define NVIC_ACTIVE1_INT47 0x00008000 // Interrupt 47 active +#define NVIC_ACTIVE1_INT48 0x00010000 // Interrupt 48 active +#define NVIC_ACTIVE1_INT49 0x00020000 // Interrupt 49 active +#define NVIC_ACTIVE1_INT50 0x00040000 // Interrupt 50 active +#define NVIC_ACTIVE1_INT51 0x00080000 // Interrupt 51 active +#define NVIC_ACTIVE1_INT52 0x00100000 // Interrupt 52 active +#define NVIC_ACTIVE1_INT53 0x00200000 // Interrupt 53 active +#define NVIC_ACTIVE1_INT54 0x00400000 // Interrupt 54 active +#define NVIC_ACTIVE1_INT55 0x00800000 // Interrupt 55 active + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTIVE2 register. +// +//***************************************************************************** +#define NVIC_ACTIVE2_INT_M 0xFFFFFFFF // Interrupt Active + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTIVE3 register. +// +//***************************************************************************** +#define NVIC_ACTIVE3_INT_M 0xFFFFFFFF // Interrupt Active + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_ACTIVE4 register. +// +//***************************************************************************** +#define NVIC_ACTIVE4_INT_M 0x0000000F // Interrupt Active + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI0 register. +// +//***************************************************************************** +#define NVIC_PRI0_INT3_M 0xE0000000 // Interrupt 3 Priority Mask +#define NVIC_PRI0_INT2_M 0x00E00000 // Interrupt 2 Priority Mask +#define NVIC_PRI0_INT1_M 0x0000E000 // Interrupt 1 Priority Mask +#define NVIC_PRI0_INT0_M 0x000000E0 // Interrupt 0 Priority Mask +#define NVIC_PRI0_INT3_S 29 +#define NVIC_PRI0_INT2_S 21 +#define NVIC_PRI0_INT1_S 13 +#define NVIC_PRI0_INT0_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI1 register. +// +//***************************************************************************** +#define NVIC_PRI1_INT7_M 0xE0000000 // Interrupt 7 Priority Mask +#define NVIC_PRI1_INT6_M 0x00E00000 // Interrupt 6 Priority Mask +#define NVIC_PRI1_INT5_M 0x0000E000 // Interrupt 5 Priority Mask +#define NVIC_PRI1_INT4_M 0x000000E0 // Interrupt 4 Priority Mask +#define NVIC_PRI1_INT7_S 29 +#define NVIC_PRI1_INT6_S 21 +#define NVIC_PRI1_INT5_S 13 +#define NVIC_PRI1_INT4_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI2 register. +// +//***************************************************************************** +#define NVIC_PRI2_INT11_M 0xE0000000 // Interrupt 11 Priority Mask +#define NVIC_PRI2_INT10_M 0x00E00000 // Interrupt 10 Priority Mask +#define NVIC_PRI2_INT9_M 0x0000E000 // Interrupt 9 Priority Mask +#define NVIC_PRI2_INT8_M 0x000000E0 // Interrupt 8 Priority Mask +#define NVIC_PRI2_INT11_S 29 +#define NVIC_PRI2_INT10_S 21 +#define NVIC_PRI2_INT9_S 13 +#define NVIC_PRI2_INT8_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI3 register. +// +//***************************************************************************** +#define NVIC_PRI3_INT15_M 0xE0000000 // Interrupt 15 Priority Mask +#define NVIC_PRI3_INT14_M 0x00E00000 // Interrupt 14 Priority Mask +#define NVIC_PRI3_INT13_M 0x0000E000 // Interrupt 13 Priority Mask +#define NVIC_PRI3_INT12_M 0x000000E0 // Interrupt 12 Priority Mask +#define NVIC_PRI3_INT15_S 29 +#define NVIC_PRI3_INT14_S 21 +#define NVIC_PRI3_INT13_S 13 +#define NVIC_PRI3_INT12_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI4 register. +// +//***************************************************************************** +#define NVIC_PRI4_INT19_M 0xE0000000 // Interrupt 19 Priority Mask +#define NVIC_PRI4_INT18_M 0x00E00000 // Interrupt 18 Priority Mask +#define NVIC_PRI4_INT17_M 0x0000E000 // Interrupt 17 Priority Mask +#define NVIC_PRI4_INT16_M 0x000000E0 // Interrupt 16 Priority Mask +#define NVIC_PRI4_INT19_S 29 +#define NVIC_PRI4_INT18_S 21 +#define NVIC_PRI4_INT17_S 13 +#define NVIC_PRI4_INT16_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI5 register. +// +//***************************************************************************** +#define NVIC_PRI5_INT23_M 0xE0000000 // Interrupt 23 Priority Mask +#define NVIC_PRI5_INT22_M 0x00E00000 // Interrupt 22 Priority Mask +#define NVIC_PRI5_INT21_M 0x0000E000 // Interrupt 21 Priority Mask +#define NVIC_PRI5_INT20_M 0x000000E0 // Interrupt 20 Priority Mask +#define NVIC_PRI5_INT23_S 29 +#define NVIC_PRI5_INT22_S 21 +#define NVIC_PRI5_INT21_S 13 +#define NVIC_PRI5_INT20_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI6 register. +// +//***************************************************************************** +#define NVIC_PRI6_INT27_M 0xE0000000 // Interrupt 27 Priority Mask +#define NVIC_PRI6_INT26_M 0x00E00000 // Interrupt 26 Priority Mask +#define NVIC_PRI6_INT25_M 0x0000E000 // Interrupt 25 Priority Mask +#define NVIC_PRI6_INT24_M 0x000000E0 // Interrupt 24 Priority Mask +#define NVIC_PRI6_INT27_S 29 +#define NVIC_PRI6_INT26_S 21 +#define NVIC_PRI6_INT25_S 13 +#define NVIC_PRI6_INT24_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI7 register. +// +//***************************************************************************** +#define NVIC_PRI7_INT31_M 0xE0000000 // Interrupt 31 Priority Mask +#define NVIC_PRI7_INT30_M 0x00E00000 // Interrupt 30 Priority Mask +#define NVIC_PRI7_INT29_M 0x0000E000 // Interrupt 29 Priority Mask +#define NVIC_PRI7_INT28_M 0x000000E0 // Interrupt 28 Priority Mask +#define NVIC_PRI7_INT31_S 29 +#define NVIC_PRI7_INT30_S 21 +#define NVIC_PRI7_INT29_S 13 +#define NVIC_PRI7_INT28_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI8 register. +// +//***************************************************************************** +#define NVIC_PRI8_INT35_M 0xE0000000 // Interrupt 35 Priority Mask +#define NVIC_PRI8_INT34_M 0x00E00000 // Interrupt 34 Priority Mask +#define NVIC_PRI8_INT33_M 0x0000E000 // Interrupt 33 Priority Mask +#define NVIC_PRI8_INT32_M 0x000000E0 // Interrupt 32 Priority Mask +#define NVIC_PRI8_INT35_S 29 +#define NVIC_PRI8_INT34_S 21 +#define NVIC_PRI8_INT33_S 13 +#define NVIC_PRI8_INT32_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI9 register. +// +//***************************************************************************** +#define NVIC_PRI9_INT39_M 0xE0000000 // Interrupt 39 Priority Mask +#define NVIC_PRI9_INT38_M 0x00E00000 // Interrupt 38 Priority Mask +#define NVIC_PRI9_INT37_M 0x0000E000 // Interrupt 37 Priority Mask +#define NVIC_PRI9_INT36_M 0x000000E0 // Interrupt 36 Priority Mask +#define NVIC_PRI9_INT39_S 29 +#define NVIC_PRI9_INT38_S 21 +#define NVIC_PRI9_INT37_S 13 +#define NVIC_PRI9_INT36_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI10 register. +// +//***************************************************************************** +#define NVIC_PRI10_INT43_M 0xE0000000 // Interrupt 43 Priority Mask +#define NVIC_PRI10_INT42_M 0x00E00000 // Interrupt 42 Priority Mask +#define NVIC_PRI10_INT41_M 0x0000E000 // Interrupt 41 Priority Mask +#define NVIC_PRI10_INT40_M 0x000000E0 // Interrupt 40 Priority Mask +#define NVIC_PRI10_INT43_S 29 +#define NVIC_PRI10_INT42_S 21 +#define NVIC_PRI10_INT41_S 13 +#define NVIC_PRI10_INT40_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI11 register. +// +//***************************************************************************** +#define NVIC_PRI11_INT47_M 0xE0000000 // Interrupt 47 Priority Mask +#define NVIC_PRI11_INT46_M 0x00E00000 // Interrupt 46 Priority Mask +#define NVIC_PRI11_INT45_M 0x0000E000 // Interrupt 45 Priority Mask +#define NVIC_PRI11_INT44_M 0x000000E0 // Interrupt 44 Priority Mask +#define NVIC_PRI11_INT47_S 29 +#define NVIC_PRI11_INT46_S 21 +#define NVIC_PRI11_INT45_S 13 +#define NVIC_PRI11_INT44_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI12 register. +// +//***************************************************************************** +#define NVIC_PRI12_INT51_M 0xE0000000 // Interrupt 51 Priority Mask +#define NVIC_PRI12_INT50_M 0x00E00000 // Interrupt 50 Priority Mask +#define NVIC_PRI12_INT49_M 0x0000E000 // Interrupt 49 Priority Mask +#define NVIC_PRI12_INT48_M 0x000000E0 // Interrupt 48 Priority Mask +#define NVIC_PRI12_INT51_S 29 +#define NVIC_PRI12_INT50_S 21 +#define NVIC_PRI12_INT49_S 13 +#define NVIC_PRI12_INT48_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI13 register. +// +//***************************************************************************** +#define NVIC_PRI13_INT55_M 0xE0000000 // Interrupt 55 Priority Mask +#define NVIC_PRI13_INT54_M 0x00E00000 // Interrupt 54 Priority Mask +#define NVIC_PRI13_INT53_M 0x0000E000 // Interrupt 53 Priority Mask +#define NVIC_PRI13_INT52_M 0x000000E0 // Interrupt 52 Priority Mask +#define NVIC_PRI13_INT55_S 29 +#define NVIC_PRI13_INT54_S 21 +#define NVIC_PRI13_INT53_S 13 +#define NVIC_PRI13_INT52_S 5 + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI14 register. +// +//***************************************************************************** +#define NVIC_PRI14_INTD_M 0xE0000000 // Interrupt 59 Priority Mask +#define NVIC_PRI14_INTC_M 0x00E00000 // Interrupt 58 Priority Mask +#define NVIC_PRI14_INTB_M 0x0000E000 // Interrupt 57 Priority Mask +#define NVIC_PRI14_INTA_M 0x000000E0 // Interrupt 56 Priority Mask +#define NVIC_PRI14_INTD_S 29 +#define NVIC_PRI14_INTC_S 21 +#define NVIC_PRI14_INTB_S 13 +#define NVIC_PRI14_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI15 register. +// +//***************************************************************************** +#define NVIC_PRI15_INTD_M 0xE0000000 // Interrupt 63 Priority Mask +#define NVIC_PRI15_INTC_M 0x00E00000 // Interrupt 62 Priority Mask +#define NVIC_PRI15_INTB_M 0x0000E000 // Interrupt 61 Priority Mask +#define NVIC_PRI15_INTA_M 0x000000E0 // Interrupt 60 Priority Mask +#define NVIC_PRI15_INTD_S 29 +#define NVIC_PRI15_INTC_S 21 +#define NVIC_PRI15_INTB_S 13 +#define NVIC_PRI15_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI16 register. +// +//***************************************************************************** +#define NVIC_PRI16_INTD_M 0xE0000000 // Interrupt 67 Priority Mask +#define NVIC_PRI16_INTC_M 0x00E00000 // Interrupt 66 Priority Mask +#define NVIC_PRI16_INTB_M 0x0000E000 // Interrupt 65 Priority Mask +#define NVIC_PRI16_INTA_M 0x000000E0 // Interrupt 64 Priority Mask +#define NVIC_PRI16_INTD_S 29 +#define NVIC_PRI16_INTC_S 21 +#define NVIC_PRI16_INTB_S 13 +#define NVIC_PRI16_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI17 register. +// +//***************************************************************************** +#define NVIC_PRI17_INTD_M 0xE0000000 // Interrupt 71 Priority Mask +#define NVIC_PRI17_INTC_M 0x00E00000 // Interrupt 70 Priority Mask +#define NVIC_PRI17_INTB_M 0x0000E000 // Interrupt 69 Priority Mask +#define NVIC_PRI17_INTA_M 0x000000E0 // Interrupt 68 Priority Mask +#define NVIC_PRI17_INTD_S 29 +#define NVIC_PRI17_INTC_S 21 +#define NVIC_PRI17_INTB_S 13 +#define NVIC_PRI17_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI18 register. +// +//***************************************************************************** +#define NVIC_PRI18_INTD_M 0xE0000000 // Interrupt 75 Priority Mask +#define NVIC_PRI18_INTC_M 0x00E00000 // Interrupt 74 Priority Mask +#define NVIC_PRI18_INTB_M 0x0000E000 // Interrupt 73 Priority Mask +#define NVIC_PRI18_INTA_M 0x000000E0 // Interrupt 72 Priority Mask +#define NVIC_PRI18_INTD_S 29 +#define NVIC_PRI18_INTC_S 21 +#define NVIC_PRI18_INTB_S 13 +#define NVIC_PRI18_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI19 register. +// +//***************************************************************************** +#define NVIC_PRI19_INTD_M 0xE0000000 // Interrupt 79 Priority Mask +#define NVIC_PRI19_INTC_M 0x00E00000 // Interrupt 78 Priority Mask +#define NVIC_PRI19_INTB_M 0x0000E000 // Interrupt 77 Priority Mask +#define NVIC_PRI19_INTA_M 0x000000E0 // Interrupt 76 Priority Mask +#define NVIC_PRI19_INTD_S 29 +#define NVIC_PRI19_INTC_S 21 +#define NVIC_PRI19_INTB_S 13 +#define NVIC_PRI19_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI20 register. +// +//***************************************************************************** +#define NVIC_PRI20_INTD_M 0xE0000000 // Interrupt 83 Priority Mask +#define NVIC_PRI20_INTC_M 0x00E00000 // Interrupt 82 Priority Mask +#define NVIC_PRI20_INTB_M 0x0000E000 // Interrupt 81 Priority Mask +#define NVIC_PRI20_INTA_M 0x000000E0 // Interrupt 80 Priority Mask +#define NVIC_PRI20_INTD_S 29 +#define NVIC_PRI20_INTC_S 21 +#define NVIC_PRI20_INTB_S 13 +#define NVIC_PRI20_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI21 register. +// +//***************************************************************************** +#define NVIC_PRI21_INTD_M 0xE0000000 // Interrupt 87 Priority Mask +#define NVIC_PRI21_INTC_M 0x00E00000 // Interrupt 86 Priority Mask +#define NVIC_PRI21_INTB_M 0x0000E000 // Interrupt 85 Priority Mask +#define NVIC_PRI21_INTA_M 0x000000E0 // Interrupt 84 Priority Mask +#define NVIC_PRI21_INTD_S 29 +#define NVIC_PRI21_INTC_S 21 +#define NVIC_PRI21_INTB_S 13 +#define NVIC_PRI21_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI22 register. +// +//***************************************************************************** +#define NVIC_PRI22_INTD_M 0xE0000000 // Interrupt 91 Priority Mask +#define NVIC_PRI22_INTC_M 0x00E00000 // Interrupt 90 Priority Mask +#define NVIC_PRI22_INTB_M 0x0000E000 // Interrupt 89 Priority Mask +#define NVIC_PRI22_INTA_M 0x000000E0 // Interrupt 88 Priority Mask +#define NVIC_PRI22_INTD_S 29 +#define NVIC_PRI22_INTC_S 21 +#define NVIC_PRI22_INTB_S 13 +#define NVIC_PRI22_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI23 register. +// +//***************************************************************************** +#define NVIC_PRI23_INTD_M 0xE0000000 // Interrupt 95 Priority Mask +#define NVIC_PRI23_INTC_M 0x00E00000 // Interrupt 94 Priority Mask +#define NVIC_PRI23_INTB_M 0x0000E000 // Interrupt 93 Priority Mask +#define NVIC_PRI23_INTA_M 0x000000E0 // Interrupt 92 Priority Mask +#define NVIC_PRI23_INTD_S 29 +#define NVIC_PRI23_INTC_S 21 +#define NVIC_PRI23_INTB_S 13 +#define NVIC_PRI23_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI24 register. +// +//***************************************************************************** +#define NVIC_PRI24_INTD_M 0xE0000000 // Interrupt 99 Priority Mask +#define NVIC_PRI24_INTC_M 0x00E00000 // Interrupt 98 Priority Mask +#define NVIC_PRI24_INTB_M 0x0000E000 // Interrupt 97 Priority Mask +#define NVIC_PRI24_INTA_M 0x000000E0 // Interrupt 96 Priority Mask +#define NVIC_PRI24_INTD_S 29 +#define NVIC_PRI24_INTC_S 21 +#define NVIC_PRI24_INTB_S 13 +#define NVIC_PRI24_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI25 register. +// +//***************************************************************************** +#define NVIC_PRI25_INTD_M 0xE0000000 // Interrupt 103 Priority Mask +#define NVIC_PRI25_INTC_M 0x00E00000 // Interrupt 102 Priority Mask +#define NVIC_PRI25_INTB_M 0x0000E000 // Interrupt 101 Priority Mask +#define NVIC_PRI25_INTA_M 0x000000E0 // Interrupt 100 Priority Mask +#define NVIC_PRI25_INTD_S 29 +#define NVIC_PRI25_INTC_S 21 +#define NVIC_PRI25_INTB_S 13 +#define NVIC_PRI25_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI26 register. +// +//***************************************************************************** +#define NVIC_PRI26_INTD_M 0xE0000000 // Interrupt 107 Priority Mask +#define NVIC_PRI26_INTC_M 0x00E00000 // Interrupt 106 Priority Mask +#define NVIC_PRI26_INTB_M 0x0000E000 // Interrupt 105 Priority Mask +#define NVIC_PRI26_INTA_M 0x000000E0 // Interrupt 104 Priority Mask +#define NVIC_PRI26_INTD_S 29 +#define NVIC_PRI26_INTC_S 21 +#define NVIC_PRI26_INTB_S 13 +#define NVIC_PRI26_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI27 register. +// +//***************************************************************************** +#define NVIC_PRI27_INTD_M 0xE0000000 // Interrupt 111 Priority Mask +#define NVIC_PRI27_INTC_M 0x00E00000 // Interrupt 110 Priority Mask +#define NVIC_PRI27_INTB_M 0x0000E000 // Interrupt 109 Priority Mask +#define NVIC_PRI27_INTA_M 0x000000E0 // Interrupt 108 Priority Mask +#define NVIC_PRI27_INTD_S 29 +#define NVIC_PRI27_INTC_S 21 +#define NVIC_PRI27_INTB_S 13 +#define NVIC_PRI27_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI28 register. +// +//***************************************************************************** +#define NVIC_PRI28_INTD_M 0xE0000000 // Interrupt 115 Priority Mask +#define NVIC_PRI28_INTC_M 0x00E00000 // Interrupt 114 Priority Mask +#define NVIC_PRI28_INTB_M 0x0000E000 // Interrupt 113 Priority Mask +#define NVIC_PRI28_INTA_M 0x000000E0 // Interrupt 112 Priority Mask +#define NVIC_PRI28_INTD_S 29 +#define NVIC_PRI28_INTC_S 21 +#define NVIC_PRI28_INTB_S 13 +#define NVIC_PRI28_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI29 register. +// +//***************************************************************************** +#define NVIC_PRI29_INTD_M 0xE0000000 // Interrupt 119 Priority Mask +#define NVIC_PRI29_INTC_M 0x00E00000 // Interrupt 118 Priority Mask +#define NVIC_PRI29_INTB_M 0x0000E000 // Interrupt 117 Priority Mask +#define NVIC_PRI29_INTA_M 0x000000E0 // Interrupt 116 Priority Mask +#define NVIC_PRI29_INTD_S 29 +#define NVIC_PRI29_INTC_S 21 +#define NVIC_PRI29_INTB_S 13 +#define NVIC_PRI29_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI30 register. +// +//***************************************************************************** +#define NVIC_PRI30_INTD_M 0xE0000000 // Interrupt 123 Priority Mask +#define NVIC_PRI30_INTC_M 0x00E00000 // Interrupt 122 Priority Mask +#define NVIC_PRI30_INTB_M 0x0000E000 // Interrupt 121 Priority Mask +#define NVIC_PRI30_INTA_M 0x000000E0 // Interrupt 120 Priority Mask +#define NVIC_PRI30_INTD_S 29 +#define NVIC_PRI30_INTC_S 21 +#define NVIC_PRI30_INTB_S 13 +#define NVIC_PRI30_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI31 register. +// +//***************************************************************************** +#define NVIC_PRI31_INTD_M 0xE0000000 // Interrupt 127 Priority Mask +#define NVIC_PRI31_INTC_M 0x00E00000 // Interrupt 126 Priority Mask +#define NVIC_PRI31_INTB_M 0x0000E000 // Interrupt 125 Priority Mask +#define NVIC_PRI31_INTA_M 0x000000E0 // Interrupt 124 Priority Mask +#define NVIC_PRI31_INTD_S 29 +#define NVIC_PRI31_INTC_S 21 +#define NVIC_PRI31_INTB_S 13 +#define NVIC_PRI31_INTA_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_PRI32 register. +// +//***************************************************************************** +#define NVIC_PRI32_INTD_M 0xE0000000 // Interrupt 131 Priority Mask +#define NVIC_PRI32_INTC_M 0x00E00000 // Interrupt 130 Priority Mask +#define NVIC_PRI32_INTB_M 0x0000E000 // Interrupt 129 Priority Mask +#define NVIC_PRI32_INTA_M 0x000000E0 // Interrupt 128 Priority Mask +#define NVIC_PRI32_INTD_S 29 +#define NVIC_PRI32_INTC_S 21 +#define NVIC_PRI32_INTB_S 13 +#define NVIC_PRI32_INTA_S 5 + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_CPUID register. +// +//***************************************************************************** +#define NVIC_CPUID_IMP_M 0xFF000000 // Implementer Code +#define NVIC_CPUID_IMP_ARM 0x41000000 // ARM +#define NVIC_CPUID_VAR_M 0x00F00000 // Variant Number +#define NVIC_CPUID_CON_M 0x000F0000 // Constant +#define NVIC_CPUID_PARTNO_M 0x0000FFF0 // Part Number +#define NVIC_CPUID_PARTNO_CM3 0x0000C230 // Cortex-M3 processor + +#define NVIC_CPUID_PARTNO_CM4 0x0000C240 // Cortex-M4 processor + +#define NVIC_CPUID_REV_M 0x0000000F // Revision Number + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_INT_CTRL register. +// +//***************************************************************************** +#define NVIC_INT_CTRL_NMI_SET 0x80000000 // NMI Set Pending +#define NVIC_INT_CTRL_PEND_SV 0x10000000 // PendSV Set Pending +#define NVIC_INT_CTRL_UNPEND_SV 0x08000000 // PendSV Clear Pending +#define NVIC_INT_CTRL_PENDSTSET 0x04000000 // SysTick Set Pending +#define NVIC_INT_CTRL_PENDSTCLR 0x02000000 // SysTick Clear Pending +#define NVIC_INT_CTRL_ISR_PRE 0x00800000 // Debug Interrupt Handling +#define NVIC_INT_CTRL_ISR_PEND 0x00400000 // Interrupt Pending +#define NVIC_INT_CTRL_VEC_PEN_M 0x0007F000 // Interrupt Pending Vector Number + +#undef NVIC_INT_CTRL_VEC_PEN_M +#define NVIC_INT_CTRL_VEC_PEN_M 0x000FF000 // Interrupt Pending Vector Number + +#define NVIC_INT_CTRL_VEC_PEN_NMI \ + 0x00002000 // NMI +#define NVIC_INT_CTRL_VEC_PEN_HARD \ + 0x00003000 // Hard fault +#define NVIC_INT_CTRL_VEC_PEN_MEM \ + 0x00004000 // Memory management fault +#define NVIC_INT_CTRL_VEC_PEN_BUS \ + 0x00005000 // Bus fault +#define NVIC_INT_CTRL_VEC_PEN_USG \ + 0x00006000 // Usage fault +#define NVIC_INT_CTRL_VEC_PEN_SVC \ + 0x0000B000 // SVCall +#define NVIC_INT_CTRL_VEC_PEN_PNDSV \ + 0x0000E000 // PendSV +#define NVIC_INT_CTRL_VEC_PEN_TICK \ + 0x0000F000 // SysTick +#define NVIC_INT_CTRL_RET_BASE 0x00000800 // Return to Base +#define NVIC_INT_CTRL_VEC_ACT_M 0x0000007F // Interrupt Pending Vector Number + +#undef NVIC_INT_CTRL_VEC_ACT_M +#define NVIC_INT_CTRL_VEC_ACT_M 0x000000FF // Interrupt Pending Vector Number + +#define NVIC_INT_CTRL_VEC_PEN_S 12 +#define NVIC_INT_CTRL_VEC_ACT_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_VTABLE register. +// +//***************************************************************************** +#define NVIC_VTABLE_BASE 0x20000000 // Vector Table Base +#define NVIC_VTABLE_OFFSET_M 0x1FFFFE00 // Vector Table Offset + +#undef NVIC_VTABLE_OFFSET_M +#define NVIC_VTABLE_OFFSET_M 0x1FFFFC00 // Vector Table Offset + +#define NVIC_VTABLE_OFFSET_S 9 + +#undef NVIC_VTABLE_OFFSET_S +#define NVIC_VTABLE_OFFSET_S 10 + + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_APINT register. +// +//***************************************************************************** +#define NVIC_APINT_VECTKEY_M 0xFFFF0000 // Register Key +#define NVIC_APINT_VECTKEY 0x05FA0000 // Vector key +#define NVIC_APINT_ENDIANESS 0x00008000 // Data Endianess +#define NVIC_APINT_PRIGROUP_M 0x00000700 // Interrupt Priority Grouping +#define NVIC_APINT_PRIGROUP_7_1 0x00000000 // Priority group 7.1 split +#define NVIC_APINT_PRIGROUP_6_2 0x00000100 // Priority group 6.2 split +#define NVIC_APINT_PRIGROUP_5_3 0x00000200 // Priority group 5.3 split +#define NVIC_APINT_PRIGROUP_4_4 0x00000300 // Priority group 4.4 split +#define NVIC_APINT_PRIGROUP_3_5 0x00000400 // Priority group 3.5 split +#define NVIC_APINT_PRIGROUP_2_6 0x00000500 // Priority group 2.6 split +#define NVIC_APINT_PRIGROUP_1_7 0x00000600 // Priority group 1.7 split +#define NVIC_APINT_PRIGROUP_0_8 0x00000700 // Priority group 0.8 split +#define NVIC_APINT_SYSRESETREQ 0x00000004 // System Reset Request +#define NVIC_APINT_VECT_CLR_ACT 0x00000002 // Clear Active NMI / Fault +#define NVIC_APINT_VECT_RESET 0x00000001 // System Reset + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SYS_CTRL register. +// +//***************************************************************************** +#define NVIC_SYS_CTRL_SEVONPEND 0x00000010 // Wake Up on Pending +#define NVIC_SYS_CTRL_SLEEPDEEP 0x00000004 // Deep Sleep Enable +#define NVIC_SYS_CTRL_SLEEPEXIT 0x00000002 // Sleep on ISR Exit + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_CFG_CTRL register. +// +//***************************************************************************** +#define NVIC_CFG_CTRL_STKALIGN 0x00000200 // Stack Alignment on Exception + // Entry +#define NVIC_CFG_CTRL_BFHFNMIGN 0x00000100 // Ignore Bus Fault in NMI and + // Fault +#define NVIC_CFG_CTRL_DIV0 0x00000010 // Trap on Divide by 0 +#define NVIC_CFG_CTRL_UNALIGNED 0x00000008 // Trap on Unaligned Access +#define NVIC_CFG_CTRL_MAIN_PEND 0x00000002 // Allow Main Interrupt Trigger +#define NVIC_CFG_CTRL_BASE_THR 0x00000001 // Thread State Control + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SYS_PRI1 register. +// +//***************************************************************************** +#define NVIC_SYS_PRI1_USAGE_M 0x00E00000 // Usage Fault Priority +#define NVIC_SYS_PRI1_BUS_M 0x0000E000 // Bus Fault Priority +#define NVIC_SYS_PRI1_MEM_M 0x000000E0 // Memory Management Fault Priority +#define NVIC_SYS_PRI1_USAGE_S 21 +#define NVIC_SYS_PRI1_BUS_S 13 +#define NVIC_SYS_PRI1_MEM_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SYS_PRI2 register. +// +//***************************************************************************** +#define NVIC_SYS_PRI2_SVC_M 0xE0000000 // SVCall Priority +#define NVIC_SYS_PRI2_SVC_S 29 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SYS_PRI3 register. +// +//***************************************************************************** +#define NVIC_SYS_PRI3_TICK_M 0xE0000000 // SysTick Exception Priority +#define NVIC_SYS_PRI3_PENDSV_M 0x00E00000 // PendSV Priority +#define NVIC_SYS_PRI3_DEBUG_M 0x000000E0 // Debug Priority +#define NVIC_SYS_PRI3_TICK_S 29 +#define NVIC_SYS_PRI3_PENDSV_S 21 +#define NVIC_SYS_PRI3_DEBUG_S 5 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SYS_HND_CTRL +// register. +// +//***************************************************************************** +#define NVIC_SYS_HND_CTRL_USAGE 0x00040000 // Usage Fault Enable +#define NVIC_SYS_HND_CTRL_BUS 0x00020000 // Bus Fault Enable +#define NVIC_SYS_HND_CTRL_MEM 0x00010000 // Memory Management Fault Enable +#define NVIC_SYS_HND_CTRL_SVC 0x00008000 // SVC Call Pending +#define NVIC_SYS_HND_CTRL_BUSP 0x00004000 // Bus Fault Pending +#define NVIC_SYS_HND_CTRL_MEMP 0x00002000 // Memory Management Fault Pending +#define NVIC_SYS_HND_CTRL_USAGEP \ + 0x00001000 // Usage Fault Pending +#define NVIC_SYS_HND_CTRL_TICK 0x00000800 // SysTick Exception Active +#define NVIC_SYS_HND_CTRL_PNDSV 0x00000400 // PendSV Exception Active +#define NVIC_SYS_HND_CTRL_MON 0x00000100 // Debug Monitor Active +#define NVIC_SYS_HND_CTRL_SVCA 0x00000080 // SVC Call Active +#define NVIC_SYS_HND_CTRL_USGA 0x00000008 // Usage Fault Active +#define NVIC_SYS_HND_CTRL_BUSA 0x00000002 // Bus Fault Active +#define NVIC_SYS_HND_CTRL_MEMA 0x00000001 // Memory Management Fault Active + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_FAULT_STAT +// register. +// +//***************************************************************************** +#define NVIC_FAULT_STAT_DIV0 0x02000000 // Divide-by-Zero Usage Fault +#define NVIC_FAULT_STAT_UNALIGN 0x01000000 // Unaligned Access Usage Fault +#define NVIC_FAULT_STAT_NOCP 0x00080000 // No Coprocessor Usage Fault +#define NVIC_FAULT_STAT_INVPC 0x00040000 // Invalid PC Load Usage Fault +#define NVIC_FAULT_STAT_INVSTAT 0x00020000 // Invalid State Usage Fault +#define NVIC_FAULT_STAT_UNDEF 0x00010000 // Undefined Instruction Usage + // Fault +#define NVIC_FAULT_STAT_BFARV 0x00008000 // Bus Fault Address Register Valid + +#define NVIC_FAULT_STAT_BLSPERR 0x00002000 // Bus Fault on Floating-Point Lazy + // State Preservation + +#define NVIC_FAULT_STAT_BSTKE 0x00001000 // Stack Bus Fault +#define NVIC_FAULT_STAT_BUSTKE 0x00000800 // Unstack Bus Fault +#define NVIC_FAULT_STAT_IMPRE 0x00000400 // Imprecise Data Bus Error +#define NVIC_FAULT_STAT_PRECISE 0x00000200 // Precise Data Bus Error +#define NVIC_FAULT_STAT_IBUS 0x00000100 // Instruction Bus Error +#define NVIC_FAULT_STAT_MMARV 0x00000080 // Memory Management Fault Address + // Register Valid + +#define NVIC_FAULT_STAT_MLSPERR 0x00000020 // Memory Management Fault on + // Floating-Point Lazy State + // Preservation + +#define NVIC_FAULT_STAT_MSTKE 0x00000010 // Stack Access Violation +#define NVIC_FAULT_STAT_MUSTKE 0x00000008 // Unstack Access Violation +#define NVIC_FAULT_STAT_DERR 0x00000002 // Data Access Violation +#define NVIC_FAULT_STAT_IERR 0x00000001 // Instruction Access Violation + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_HFAULT_STAT +// register. +// +//***************************************************************************** +#define NVIC_HFAULT_STAT_DBG 0x80000000 // Debug Event +#define NVIC_HFAULT_STAT_FORCED 0x40000000 // Forced Hard Fault +#define NVIC_HFAULT_STAT_VECT 0x00000002 // Vector Table Read Fault + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DEBUG_STAT +// register. +// +//***************************************************************************** +#define NVIC_DEBUG_STAT_EXTRNL 0x00000010 // EDBGRQ asserted +#define NVIC_DEBUG_STAT_VCATCH 0x00000008 // Vector catch +#define NVIC_DEBUG_STAT_DWTTRAP 0x00000004 // DWT match +#define NVIC_DEBUG_STAT_BKPT 0x00000002 // Breakpoint instruction +#define NVIC_DEBUG_STAT_HALTED 0x00000001 // Halt request + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MM_ADDR register. +// +//***************************************************************************** +#define NVIC_MM_ADDR_M 0xFFFFFFFF // Fault Address +#define NVIC_MM_ADDR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_FAULT_ADDR +// register. +// +//***************************************************************************** +#define NVIC_FAULT_ADDR_M 0xFFFFFFFF // Fault Address +#define NVIC_FAULT_ADDR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_TYPE register. +// +//***************************************************************************** +#define NVIC_MPU_TYPE_IREGION_M 0x00FF0000 // Number of I Regions +#define NVIC_MPU_TYPE_DREGION_M 0x0000FF00 // Number of D Regions +#define NVIC_MPU_TYPE_SEPARATE 0x00000001 // Separate or Unified MPU +#define NVIC_MPU_TYPE_IREGION_S 16 +#define NVIC_MPU_TYPE_DREGION_S 8 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_CTRL register. +// +//***************************************************************************** +#define NVIC_MPU_CTRL_PRIVDEFEN 0x00000004 // MPU Default Region +#define NVIC_MPU_CTRL_HFNMIENA 0x00000002 // MPU Enabled During Faults +#define NVIC_MPU_CTRL_ENABLE 0x00000001 // MPU Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_NUMBER +// register. +// +//***************************************************************************** +#define NVIC_MPU_NUMBER_M 0x00000007 // MPU Region to Access +#define NVIC_MPU_NUMBER_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_BASE register. +// +//***************************************************************************** +#define NVIC_MPU_BASE_ADDR_M 0xFFFFFFE0 // Base Address Mask +#define NVIC_MPU_BASE_VALID 0x00000010 // Region Number Valid +#define NVIC_MPU_BASE_REGION_M 0x00000007 // Region Number +#define NVIC_MPU_BASE_ADDR_S 5 +#define NVIC_MPU_BASE_REGION_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_ATTR register. +// +//***************************************************************************** +#define NVIC_MPU_ATTR_M 0xFFFF0000 // Attributes +#define NVIC_MPU_ATTR_XN 0x10000000 // Instruction Access Disable +#define NVIC_MPU_ATTR_AP_M 0x07000000 // Access Privilege +#define NVIC_MPU_ATTR_AP_NO_NO 0x00000000 // prv: no access, usr: no access +#define NVIC_MPU_ATTR_AP_RW_NO 0x01000000 // prv: rw, usr: none +#define NVIC_MPU_ATTR_AP_RW_RO 0x02000000 // prv: rw, usr: read-only +#define NVIC_MPU_ATTR_AP_RW_RW 0x03000000 // prv: rw, usr: rw +#define NVIC_MPU_ATTR_AP_RO_NO 0x05000000 // prv: ro, usr: none +#define NVIC_MPU_ATTR_AP_RO_RO 0x06000000 // prv: ro, usr: ro +#define NVIC_MPU_ATTR_TEX_M 0x00380000 // Type Extension Mask +#define NVIC_MPU_ATTR_SHAREABLE 0x00040000 // Shareable +#define NVIC_MPU_ATTR_CACHEABLE 0x00020000 // Cacheable +#define NVIC_MPU_ATTR_BUFFRABLE 0x00010000 // Bufferable +#define NVIC_MPU_ATTR_SRD_M 0x0000FF00 // Subregion Disable Bits +#define NVIC_MPU_ATTR_SRD_0 0x00000100 // Sub-region 0 disable +#define NVIC_MPU_ATTR_SRD_1 0x00000200 // Sub-region 1 disable +#define NVIC_MPU_ATTR_SRD_2 0x00000400 // Sub-region 2 disable +#define NVIC_MPU_ATTR_SRD_3 0x00000800 // Sub-region 3 disable +#define NVIC_MPU_ATTR_SRD_4 0x00001000 // Sub-region 4 disable +#define NVIC_MPU_ATTR_SRD_5 0x00002000 // Sub-region 5 disable +#define NVIC_MPU_ATTR_SRD_6 0x00004000 // Sub-region 6 disable +#define NVIC_MPU_ATTR_SRD_7 0x00008000 // Sub-region 7 disable +#define NVIC_MPU_ATTR_SIZE_M 0x0000003E // Region Size Mask +#define NVIC_MPU_ATTR_SIZE_32B 0x00000008 // Region size 32 bytes +#define NVIC_MPU_ATTR_SIZE_64B 0x0000000A // Region size 64 bytes +#define NVIC_MPU_ATTR_SIZE_128B 0x0000000C // Region size 128 bytes +#define NVIC_MPU_ATTR_SIZE_256B 0x0000000E // Region size 256 bytes +#define NVIC_MPU_ATTR_SIZE_512B 0x00000010 // Region size 512 bytes +#define NVIC_MPU_ATTR_SIZE_1K 0x00000012 // Region size 1 Kbytes +#define NVIC_MPU_ATTR_SIZE_2K 0x00000014 // Region size 2 Kbytes +#define NVIC_MPU_ATTR_SIZE_4K 0x00000016 // Region size 4 Kbytes +#define NVIC_MPU_ATTR_SIZE_8K 0x00000018 // Region size 8 Kbytes +#define NVIC_MPU_ATTR_SIZE_16K 0x0000001A // Region size 16 Kbytes +#define NVIC_MPU_ATTR_SIZE_32K 0x0000001C // Region size 32 Kbytes +#define NVIC_MPU_ATTR_SIZE_64K 0x0000001E // Region size 64 Kbytes +#define NVIC_MPU_ATTR_SIZE_128K 0x00000020 // Region size 128 Kbytes +#define NVIC_MPU_ATTR_SIZE_256K 0x00000022 // Region size 256 Kbytes +#define NVIC_MPU_ATTR_SIZE_512K 0x00000024 // Region size 512 Kbytes +#define NVIC_MPU_ATTR_SIZE_1M 0x00000026 // Region size 1 Mbytes +#define NVIC_MPU_ATTR_SIZE_2M 0x00000028 // Region size 2 Mbytes +#define NVIC_MPU_ATTR_SIZE_4M 0x0000002A // Region size 4 Mbytes +#define NVIC_MPU_ATTR_SIZE_8M 0x0000002C // Region size 8 Mbytes +#define NVIC_MPU_ATTR_SIZE_16M 0x0000002E // Region size 16 Mbytes +#define NVIC_MPU_ATTR_SIZE_32M 0x00000030 // Region size 32 Mbytes +#define NVIC_MPU_ATTR_SIZE_64M 0x00000032 // Region size 64 Mbytes +#define NVIC_MPU_ATTR_SIZE_128M 0x00000034 // Region size 128 Mbytes +#define NVIC_MPU_ATTR_SIZE_256M 0x00000036 // Region size 256 Mbytes +#define NVIC_MPU_ATTR_SIZE_512M 0x00000038 // Region size 512 Mbytes +#define NVIC_MPU_ATTR_SIZE_1G 0x0000003A // Region size 1 Gbytes +#define NVIC_MPU_ATTR_SIZE_2G 0x0000003C // Region size 2 Gbytes +#define NVIC_MPU_ATTR_SIZE_4G 0x0000003E // Region size 4 Gbytes +#define NVIC_MPU_ATTR_ENABLE 0x00000001 // Region Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_BASE1 register. +// +//***************************************************************************** +#define NVIC_MPU_BASE1_ADDR_M 0xFFFFFFE0 // Base Address Mask +#define NVIC_MPU_BASE1_VALID 0x00000010 // Region Number Valid +#define NVIC_MPU_BASE1_REGION_M 0x00000007 // Region Number +#define NVIC_MPU_BASE1_ADDR_S 5 +#define NVIC_MPU_BASE1_REGION_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_ATTR1 register. +// +//***************************************************************************** +#define NVIC_MPU_ATTR1_XN 0x10000000 // Instruction Access Disable +#define NVIC_MPU_ATTR1_AP_M 0x07000000 // Access Privilege +#define NVIC_MPU_ATTR1_TEX_M 0x00380000 // Type Extension Mask +#define NVIC_MPU_ATTR1_SHAREABLE \ + 0x00040000 // Shareable +#define NVIC_MPU_ATTR1_CACHEABLE \ + 0x00020000 // Cacheable +#define NVIC_MPU_ATTR1_BUFFRABLE \ + 0x00010000 // Bufferable +#define NVIC_MPU_ATTR1_SRD_M 0x0000FF00 // Subregion Disable Bits +#define NVIC_MPU_ATTR1_SIZE_M 0x0000003E // Region Size Mask +#define NVIC_MPU_ATTR1_ENABLE 0x00000001 // Region Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_BASE2 register. +// +//***************************************************************************** +#define NVIC_MPU_BASE2_ADDR_M 0xFFFFFFE0 // Base Address Mask +#define NVIC_MPU_BASE2_VALID 0x00000010 // Region Number Valid +#define NVIC_MPU_BASE2_REGION_M 0x00000007 // Region Number +#define NVIC_MPU_BASE2_ADDR_S 5 +#define NVIC_MPU_BASE2_REGION_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_ATTR2 register. +// +//***************************************************************************** +#define NVIC_MPU_ATTR2_XN 0x10000000 // Instruction Access Disable +#define NVIC_MPU_ATTR2_AP_M 0x07000000 // Access Privilege +#define NVIC_MPU_ATTR2_TEX_M 0x00380000 // Type Extension Mask +#define NVIC_MPU_ATTR2_SHAREABLE \ + 0x00040000 // Shareable +#define NVIC_MPU_ATTR2_CACHEABLE \ + 0x00020000 // Cacheable +#define NVIC_MPU_ATTR2_BUFFRABLE \ + 0x00010000 // Bufferable +#define NVIC_MPU_ATTR2_SRD_M 0x0000FF00 // Subregion Disable Bits +#define NVIC_MPU_ATTR2_SIZE_M 0x0000003E // Region Size Mask +#define NVIC_MPU_ATTR2_ENABLE 0x00000001 // Region Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_BASE3 register. +// +//***************************************************************************** +#define NVIC_MPU_BASE3_ADDR_M 0xFFFFFFE0 // Base Address Mask +#define NVIC_MPU_BASE3_VALID 0x00000010 // Region Number Valid +#define NVIC_MPU_BASE3_REGION_M 0x00000007 // Region Number +#define NVIC_MPU_BASE3_ADDR_S 5 +#define NVIC_MPU_BASE3_REGION_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_MPU_ATTR3 register. +// +//***************************************************************************** +#define NVIC_MPU_ATTR3_XN 0x10000000 // Instruction Access Disable +#define NVIC_MPU_ATTR3_AP_M 0x07000000 // Access Privilege +#define NVIC_MPU_ATTR3_TEX_M 0x00380000 // Type Extension Mask +#define NVIC_MPU_ATTR3_SHAREABLE \ + 0x00040000 // Shareable +#define NVIC_MPU_ATTR3_CACHEABLE \ + 0x00020000 // Cacheable +#define NVIC_MPU_ATTR3_BUFFRABLE \ + 0x00010000 // Bufferable +#define NVIC_MPU_ATTR3_SRD_M 0x0000FF00 // Subregion Disable Bits +#define NVIC_MPU_ATTR3_SIZE_M 0x0000003E // Region Size Mask +#define NVIC_MPU_ATTR3_ENABLE 0x00000001 // Region Enable + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DBG_CTRL register. +// +//***************************************************************************** +#define NVIC_DBG_CTRL_DBGKEY_M 0xFFFF0000 // Debug key mask +#define NVIC_DBG_CTRL_DBGKEY 0xA05F0000 // Debug key +#define NVIC_DBG_CTRL_S_RESET_ST \ + 0x02000000 // Core has reset since last read +#define NVIC_DBG_CTRL_S_RETIRE_ST \ + 0x01000000 // Core has executed insruction + // since last read +#define NVIC_DBG_CTRL_S_LOCKUP 0x00080000 // Core is locked up +#define NVIC_DBG_CTRL_S_SLEEP 0x00040000 // Core is sleeping +#define NVIC_DBG_CTRL_S_HALT 0x00020000 // Core status on halt +#define NVIC_DBG_CTRL_S_REGRDY 0x00010000 // Register read/write available +#define NVIC_DBG_CTRL_C_SNAPSTALL \ + 0x00000020 // Breaks a stalled load/store +#define NVIC_DBG_CTRL_C_MASKINT 0x00000008 // Mask interrupts when stepping +#define NVIC_DBG_CTRL_C_STEP 0x00000004 // Step the core +#define NVIC_DBG_CTRL_C_HALT 0x00000002 // Halt the core +#define NVIC_DBG_CTRL_C_DEBUGEN 0x00000001 // Enable debug + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DBG_XFER register. +// +//***************************************************************************** +#define NVIC_DBG_XFER_REG_WNR 0x00010000 // Write or not read +#define NVIC_DBG_XFER_REG_SEL_M 0x0000001F // Register +#define NVIC_DBG_XFER_REG_R0 0x00000000 // Register R0 +#define NVIC_DBG_XFER_REG_R1 0x00000001 // Register R1 +#define NVIC_DBG_XFER_REG_R2 0x00000002 // Register R2 +#define NVIC_DBG_XFER_REG_R3 0x00000003 // Register R3 +#define NVIC_DBG_XFER_REG_R4 0x00000004 // Register R4 +#define NVIC_DBG_XFER_REG_R5 0x00000005 // Register R5 +#define NVIC_DBG_XFER_REG_R6 0x00000006 // Register R6 +#define NVIC_DBG_XFER_REG_R7 0x00000007 // Register R7 +#define NVIC_DBG_XFER_REG_R8 0x00000008 // Register R8 +#define NVIC_DBG_XFER_REG_R9 0x00000009 // Register R9 +#define NVIC_DBG_XFER_REG_R10 0x0000000A // Register R10 +#define NVIC_DBG_XFER_REG_R11 0x0000000B // Register R11 +#define NVIC_DBG_XFER_REG_R12 0x0000000C // Register R12 +#define NVIC_DBG_XFER_REG_R13 0x0000000D // Register R13 +#define NVIC_DBG_XFER_REG_R14 0x0000000E // Register R14 +#define NVIC_DBG_XFER_REG_R15 0x0000000F // Register R15 +#define NVIC_DBG_XFER_REG_FLAGS 0x00000010 // xPSR/Flags register +#define NVIC_DBG_XFER_REG_MSP 0x00000011 // Main SP +#define NVIC_DBG_XFER_REG_PSP 0x00000012 // Process SP +#define NVIC_DBG_XFER_REG_DSP 0x00000013 // Deep SP +#define NVIC_DBG_XFER_REG_CFBP 0x00000014 // Control/Fault/BasePri/PriMask + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DBG_DATA register. +// +//***************************************************************************** +#define NVIC_DBG_DATA_M 0xFFFFFFFF // Data temporary cache +#define NVIC_DBG_DATA_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_DBG_INT register. +// +//***************************************************************************** +#define NVIC_DBG_INT_HARDERR 0x00000400 // Debug trap on hard fault +#define NVIC_DBG_INT_INTERR 0x00000200 // Debug trap on interrupt errors +#define NVIC_DBG_INT_BUSERR 0x00000100 // Debug trap on bus error +#define NVIC_DBG_INT_STATERR 0x00000080 // Debug trap on usage fault state +#define NVIC_DBG_INT_CHKERR 0x00000040 // Debug trap on usage fault check +#define NVIC_DBG_INT_NOCPERR 0x00000020 // Debug trap on coprocessor error +#define NVIC_DBG_INT_MMERR 0x00000010 // Debug trap on mem manage fault +#define NVIC_DBG_INT_RESET 0x00000008 // Core reset status +#define NVIC_DBG_INT_RSTPENDCLR 0x00000004 // Clear pending core reset +#define NVIC_DBG_INT_RSTPENDING 0x00000002 // Core reset is pending +#define NVIC_DBG_INT_RSTVCATCH 0x00000001 // Reset vector catch + +//***************************************************************************** +// +// The following are defines for the bit fields in the NVIC_SW_TRIG register. +// +//***************************************************************************** +#define NVIC_SW_TRIG_INTID_M 0x0000003F // Interrupt ID + +#undef NVIC_SW_TRIG_INTID_M +#define NVIC_SW_TRIG_INTID_M 0x000000FF // Interrupt ID + +#define NVIC_SW_TRIG_INTID_S 0 + +#endif // __HW_NVIC_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ocp_shared.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ocp_shared.h new file mode 100755 index 0000000..a52f690 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_ocp_shared.h @@ -0,0 +1,3445 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_OCP_SHARED_H__ +#define __HW_OCP_SHARED_H__ + +//***************************************************************************** +// +// The following are defines for the OCP_SHARED register offsets. +// +//***************************************************************************** +#define OCP_SHARED_O_SEMAPHORE1 0x00000000 +#define OCP_SHARED_O_SEMAPHORE2 0x00000004 +#define OCP_SHARED_O_SEMAPHORE3 0x00000008 +#define OCP_SHARED_O_SEMAPHORE4 0x0000000C +#define OCP_SHARED_O_SEMAPHORE5 0x00000010 +#define OCP_SHARED_O_SEMAPHORE6 0x00000014 +#define OCP_SHARED_O_SEMAPHORE7 0x00000018 +#define OCP_SHARED_O_SEMAPHORE8 0x0000001C +#define OCP_SHARED_O_SEMAPHORE9 0x00000020 +#define OCP_SHARED_O_SEMAPHORE10 \ + 0x00000024 + +#define OCP_SHARED_O_SEMAPHORE11 \ + 0x00000028 + +#define OCP_SHARED_O_SEMAPHORE12 \ + 0x0000002C + +#define OCP_SHARED_O_IC_LOCKER_ID \ + 0x00000030 + +#define OCP_SHARED_O_MCU_SEMAPHORE_PEND \ + 0x00000034 + +#define OCP_SHARED_O_WL_SEMAPHORE_PEND \ + 0x00000038 + +#define OCP_SHARED_O_PLATFORM_DETECTION_RD_ONLY \ + 0x0000003C + +#define OCP_SHARED_O_SEMAPHORES_STATUS_RD_ONLY \ + 0x00000040 + +#define OCP_SHARED_O_CC3XX_CONFIG_CTRL \ + 0x00000044 + +#define OCP_SHARED_O_CC3XX_SHARED_MEM_SEL_LSB \ + 0x00000048 + +#define OCP_SHARED_O_CC3XX_SHARED_MEM_SEL_MSB \ + 0x0000004C + +#define OCP_SHARED_O_WLAN_ELP_WAKE_EN \ + 0x00000050 + +#define OCP_SHARED_O_DEVINIT_ROM_START_ADDR \ + 0x00000054 + +#define OCP_SHARED_O_DEVINIT_ROM_END_ADDR \ + 0x00000058 + +#define OCP_SHARED_O_SSBD_SEED 0x0000005C +#define OCP_SHARED_O_SSBD_CHK 0x00000060 +#define OCP_SHARED_O_SSBD_POLY_SEL \ + 0x00000064 + +#define OCP_SHARED_O_SPARE_REG_0 \ + 0x00000068 + +#define OCP_SHARED_O_SPARE_REG_1 \ + 0x0000006C + +#define OCP_SHARED_O_SPARE_REG_2 \ + 0x00000070 + +#define OCP_SHARED_O_SPARE_REG_3 \ + 0x00000074 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_0 \ + 0x000000A0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_1 \ + 0x000000A4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_2 \ + 0x000000A8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_3 \ + 0x000000AC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_4 \ + 0x000000B0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_5 \ + 0x000000B4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_6 \ + 0x000000B8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_7 \ + 0x000000BC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_8 \ + 0x000000C0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_9 \ + 0x000000C4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_10 \ + 0x000000C8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_11 \ + 0x000000CC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_12 \ + 0x000000D0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_13 \ + 0x000000D4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_14 \ + 0x000000D8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_15 \ + 0x000000DC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_16 \ + 0x000000E0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_17 \ + 0x000000E4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_18 \ + 0x000000E8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_19 \ + 0x000000EC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_20 \ + 0x000000F0 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_21 \ + 0x000000F4 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_22 \ + 0x000000F8 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_23 \ + 0x000000FC + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_24 \ + 0x00000100 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_25 \ + 0x00000104 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_26 \ + 0x00000108 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_27 \ + 0x0000010C + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_28 \ + 0x00000110 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_29 \ + 0x00000114 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_30 \ + 0x00000118 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_31 \ + 0x0000011C + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_32 \ + 0x00000120 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_33 \ + 0x00000124 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_34 \ + 0x00000128 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_35 \ + 0x0000012C + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_36 \ + 0x00000130 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_37 \ + 0x00000134 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_38 \ + 0x00000138 + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_39 \ + 0x0000013C + +#define OCP_SHARED_O_GPIO_PAD_CONFIG_40 \ + 0x00000140 + +#define OCP_SHARED_O_GPIO_PAD_CMN_CONFIG \ + 0x00000144 // This register provide control to + // GPIO_CC3XXV1 IO PAD. Common + // control signals to all bottom Die + // IO's are controlled via this. + +#define OCP_SHARED_O_D2D_DEV_PAD_CMN_CONFIG \ + 0x00000148 + +#define OCP_SHARED_O_D2D_TOSTACK_PAD_CONF \ + 0x0000014C + +#define OCP_SHARED_O_D2D_MISC_PAD_CONF \ + 0x00000150 + +#define OCP_SHARED_O_SOP_CONF_OVERRIDE \ + 0x00000154 + +#define OCP_SHARED_O_CC3XX_DEBUGSS_STATUS \ + 0x00000158 + +#define OCP_SHARED_O_CC3XX_DEBUGMUX_SEL \ + 0x0000015C + +#define OCP_SHARED_O_ALT_PC_VAL_NW \ + 0x00000160 + +#define OCP_SHARED_O_ALT_PC_VAL_APPS \ + 0x00000164 + +#define OCP_SHARED_O_SPARE_REG_4 \ + 0x00000168 + +#define OCP_SHARED_O_SPARE_REG_5 \ + 0x0000016C + +#define OCP_SHARED_O_SH_SPI_CS_MASK \ + 0x00000170 + +#define OCP_SHARED_O_CC3XX_DEVICE_TYPE \ + 0x00000174 + +#define OCP_SHARED_O_MEM_TOPMUXCTRL_IFORCE \ + 0x00000178 + +#define OCP_SHARED_O_CC3XX_DEV_PACKAGE_DETECT \ + 0x0000017C + +#define OCP_SHARED_O_AUTONMS_SPICLK_SEL \ + 0x00000180 + +#define OCP_SHARED_O_CC3XX_DEV_PADCONF \ + 0x00000184 + +#define OCP_SHARED_O_SPARE_REG_8 \ + 0x00000188 + +#define OCP_SHARED_O_SPARE_REG_6 \ + 0x0000018C + +#define OCP_SHARED_O_SPARE_REG_7 \ + 0x00000190 + +#define OCP_SHARED_O_APPS_WLAN_ORBIT \ + 0x00000194 + +#define OCP_SHARED_O_APPS_WLAN_SCRATCH_PAD \ + 0x00000198 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE1 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE1_MEM_SEMAPHORE1_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE1_MEM_SEMAPHORE1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE2 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE2_MEM_SEMAPHORE2_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE2_MEM_SEMAPHORE2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE3 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE3_MEM_SEMAPHORE3_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE3_MEM_SEMAPHORE3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE4 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE4_MEM_SEMAPHORE4_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE4_MEM_SEMAPHORE4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE5 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE5_MEM_SEMAPHORE5_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE5_MEM_SEMAPHORE5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE6 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE6_MEM_SEMAPHORE6_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE6_MEM_SEMAPHORE6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE7 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE7_MEM_SEMAPHORE7_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE7_MEM_SEMAPHORE7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE8 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE8_MEM_SEMAPHORE8_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE8_MEM_SEMAPHORE8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE9 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE9_MEM_SEMAPHORE9_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE9_MEM_SEMAPHORE9_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE10 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE10_MEM_SEMAPHORE10_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE10_MEM_SEMAPHORE10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE11 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE11_MEM_SEMAPHORE11_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE11_MEM_SEMAPHORE11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORE12 register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORE12_MEM_SEMAPHORE12_M \ + 0x00000003 // General Purpose Semaphore for SW + // Usage. If any of the 2 bits of a + // given register is set to 1, it + // means that the semaphore is + // locked by one of the masters. + // Each bit represents a master IP + // as follows: {WLAN,NWP}. The JTAG + // cannot capture the semaphore but + // it can release it. As a master IP + // reads the semaphore, it will be + // caputed and the masters + // correlating bit will be set to 1 + // (set upon read). As any IP writes + // to this address (independent of + // the written data) the semaphore + // will be set to 2'b00. + +#define OCP_SHARED_SEMAPHORE12_MEM_SEMAPHORE12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_IC_LOCKER_ID register. +// +//****************************************************************************** +#define OCP_SHARED_IC_LOCKER_ID_MEM_IC_LOCKER_ID_M \ + 0x00000007 // This register is used for + // allowing only one master OCP to + // perform write transactions to the + // OCP slaves. Each bit represents + // an IP in the following format: { + // JTAG,WLAN, NWP mcu}. As any of + // the bits is set to one, the + // correlating IP is preventing the + // other IP's from performing write + // transactions to the slaves. As + // the Inter Connect is locked, the + // only the locking IP can write to + // the register and by that + // releasing the lock. 3'b000 => IC + // is not locked. 3'b001 => IC is + // locked by NWP mcu. 3'b010 => IC + // is locked by WLAN. 3'b100 => IC + // is locked by JTAG. + +#define OCP_SHARED_IC_LOCKER_ID_MEM_IC_LOCKER_ID_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_MCU_SEMAPHORE_PEND register. +// +//****************************************************************************** +#define OCP_SHARED_MCU_SEMAPHORE_PEND_MEM_MCU_SEMAPHORE_PEND_M \ + 0x0000FFFF // This register specifies the + // semaphore for which the NWP mcu + // is waiting to be released. It is + // set to the serial number of a + // given locked semaphore after it + // was read by the NWP mcu. Only + // [11:0] is used. + +#define OCP_SHARED_MCU_SEMAPHORE_PEND_MEM_MCU_SEMAPHORE_PEND_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_WL_SEMAPHORE_PEND register. +// +//****************************************************************************** +#define OCP_SHARED_WL_SEMAPHORE_PEND_MEM_WL_SEMAPHORE_PEND_M \ + 0x0000FFFF // This register specifies the + // semaphore for which the WLAN is + // waiting to be released. It is set + // to the serial number of a given + // locked semaphore after it was + // read by the WLAN. Only [11:0] is + // used. + +#define OCP_SHARED_WL_SEMAPHORE_PEND_MEM_WL_SEMAPHORE_PEND_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_PLATFORM_DETECTION_RD_ONLY register. +// +//****************************************************************************** +#define OCP_SHARED_PLATFORM_DETECTION_RD_ONLY_PLATFORM_DETECTION_M \ + 0x0000FFFF // This information serves the IPs + // for knowing in which platform are + // they integrated at: 0 = CC31XX. + +#define OCP_SHARED_PLATFORM_DETECTION_RD_ONLY_PLATFORM_DETECTION_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SEMAPHORES_STATUS_RD_ONLY register. +// +//****************************************************************************** +#define OCP_SHARED_SEMAPHORES_STATUS_RD_ONLY_SEMAPHORES_STATUS_M \ + 0x00000FFF // Captured/released semaphores + // status for the 12 semaphores. + // Each bit of the 12 bits + // represents a semaphore. 0 => + // Semaphore Free. 1 => Semaphore + // Captured. + +#define OCP_SHARED_SEMAPHORES_STATUS_RD_ONLY_SEMAPHORES_STATUS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_CONFIG_CTRL register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_CONFIG_CTRL_MEM_IC_TO_EN \ + 0x00000010 // This bit is used to enable + // timeout mechanism for top_ocp_ic + // (for debug puropse). When 1 value + // , in case any ocp slave doesn't + // give sresponse within 16 cylcles + // top_ic will give error response + // itself to avoid bus hange. + +#define OCP_SHARED_CC3XX_CONFIG_CTRL_MEM_ALT_PC_EN_APPS \ + 0x00000008 // 1 bit should be accessible only + // in devinit. This will enable 0x4 + // hack for apps processor + +#define OCP_SHARED_CC3XX_CONFIG_CTRL_MEM_ALT_PC_EN_NW \ + 0x00000004 // 1 bit, should be accessible only + // in devinit. This will enable 0x4 + // hack for nw processor + +#define OCP_SHARED_CC3XX_CONFIG_CTRL_MEM_EXTEND_NW_ROM \ + 0x00000002 // When set NW can take over apps + // rom and flash via IDCODE bus. + // Apps will able to access this + // register only during devinit and + // reset value should be 0. + +#define OCP_SHARED_CC3XX_CONFIG_CTRL_MEM_WLAN_HOST_INTF_SEL \ + 0x00000001 // When this bit is set to 0 WPSI + // host interface wil be selected, + // when this bit is set to 1 , WLAN + // host async bridge will be + // selected. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_SHARED_MEM_SEL_LSB register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_SHARED_MEM_SEL_LSB_MEM_SHARED_MEM_SEL_LSB_M \ + 0x3FFFFFFF // This register provides memss RAM + // column configuration for column 0 + // to 9. 3 bits are allocated per + // column. This register is required + // to be configured before starting + // RAM access. Changing register + // setting while code is running + // will result into unpredictable + // memory behaviour. Register is + // supported to configured ones + // after core is booted up. 3 bit + // encoding per column is as + // follows: when 000 : WLAN, 001: + // NWP, 010: APPS, 011: PHY, 100: + // OCLA column 0 select: bit [2:0] + // :when 000 -> WLAN,001 -> NWP,010 + // -> APPS, 011 -> PHY, 100 -> OCLA + // column 1 select: bit [5:3] + // :column 2 select: bit [8 : 6]: + // column 3 select : bit [11: 9] + // column 4 select : bit [14:12] + // column 5 select : bit [17:15] + // column 6 select : bit [20:18] + // column 7 select : bit [23:21] + // column 8 select : bit [26:24] + // column 9 select : bit [29:27] + // column 10 select + +#define OCP_SHARED_CC3XX_SHARED_MEM_SEL_LSB_MEM_SHARED_MEM_SEL_LSB_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_SHARED_MEM_SEL_MSB register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_SHARED_MEM_SEL_MSB_MEM_SHARED_MEM_SEL_MSB_M \ + 0x00000FFF // This register provides memss RAM + // column configuration for column + // 10 to 15. 3 bits are allocated + // per column. This register is + // required to be configured before + // starting RAM access. Changing + // register setting while code is + // running will result into + // unpredictable memory behaviour. + // Register is supported to + // configured ones after core is + // booted up. 3 bit encoding per + // column is as follows: when 000 : + // WLAN, 001: NWP, 010: APPS, 011: + // PHY, 100: OCLA column 11 select : + // bit [2:0] column 12 select : bit + // [5:3] column 13 select : bit [8 : + // 6] column 14 select : + +#define OCP_SHARED_CC3XX_SHARED_MEM_SEL_MSB_MEM_SHARED_MEM_SEL_MSB_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_WLAN_ELP_WAKE_EN register. +// +//****************************************************************************** +#define OCP_SHARED_WLAN_ELP_WAKE_EN_MEM_WLAN_ELP_WAKE_EN \ + 0x00000001 // when '1' : signal will enabled + // ELP power doamin when '0': ELP is + // not powered up. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_DEVINIT_ROM_START_ADDR register. +// +//****************************************************************************** +#define OCP_SHARED_DEVINIT_ROM_START_ADDR_MEM_DEVINIT_ROM_START_ADDR_M \ + 0xFFFFFFFF // 32 bit, Writable only during + // devinit, and whole 32 bit should + // be output of the config register + // module. This register is not used + // , similar register availble in + // GPRCM space. + +#define OCP_SHARED_DEVINIT_ROM_START_ADDR_MEM_DEVINIT_ROM_START_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_DEVINIT_ROM_END_ADDR register. +// +//****************************************************************************** +#define OCP_SHARED_DEVINIT_ROM_END_ADDR_MEM_DEVINIT_ROM_END_ADDR_M \ + 0xFFFFFFFF // 32 bit, Writable only during + // devinit, and whole 32 bit should + // be output of the config register + // module. + +#define OCP_SHARED_DEVINIT_ROM_END_ADDR_MEM_DEVINIT_ROM_END_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SSBD_SEED register. +// +//****************************************************************************** +#define OCP_SHARED_SSBD_SEED_MEM_SSBD_SEED_M \ + 0xFFFFFFFF // 32 bit, Writable only during + // devinit, and whole 32 bit should + // be output of the config register + // module. + +#define OCP_SHARED_SSBD_SEED_MEM_SSBD_SEED_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SSBD_CHK register. +// +//****************************************************************************** +#define OCP_SHARED_SSBD_CHK_MEM_SSBD_CHK_M \ + 0xFFFFFFFF // 32 bit, Writable only during + // devinit, and whole 32 bit should + // be output of the config register + // module. + +#define OCP_SHARED_SSBD_CHK_MEM_SSBD_CHK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SSBD_POLY_SEL register. +// +//****************************************************************************** +#define OCP_SHARED_SSBD_POLY_SEL_MEM_SSBD_POLY_SEL_M \ + 0x00000003 // 2 bit, Writable only during + // devinit, and whole 2 bit should + // be output of the config register + // module. + +#define OCP_SHARED_SSBD_POLY_SEL_MEM_SSBD_POLY_SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_0 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_0_MEM_SPARE_REG_0_M \ + 0xFFFFFFFF // Devinit code should look for + // whether corresponding fuse is + // blown and if blown write to the + // 11th bit of this register to + // disable flshtst interface + +#define OCP_SHARED_SPARE_REG_0_MEM_SPARE_REG_0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_1 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_1_MEM_SPARE_REG_1_M \ + 0xFFFFFFFF // NWP Software register + +#define OCP_SHARED_SPARE_REG_1_MEM_SPARE_REG_1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_2 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_2_MEM_SPARE_REG_2_M \ + 0xFFFFFFFF // NWP Software register + +#define OCP_SHARED_SPARE_REG_2_MEM_SPARE_REG_2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_3 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_3_MEM_SPARE_REG_3_M \ + 0xFFFFFFFF // APPS Software register + +#define OCP_SHARED_SPARE_REG_3_MEM_SPARE_REG_3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_0 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_0_MEM_GPIO_PAD_CONFIG_0_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." "For example in + // case of I2C Value gets latched at + // rising edge of RET33.""" """ 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_0_MEM_GPIO_PAD_CONFIG_0_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_1 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_1_MEM_GPIO_PAD_CONFIG_1_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_1_MEM_GPIO_PAD_CONFIG_1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_2 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_2_MEM_GPIO_PAD_CONFIG_2_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_2_MEM_GPIO_PAD_CONFIG_2_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_3 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_3_MEM_GPIO_PAD_CONFIG_3_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_3_MEM_GPIO_PAD_CONFIG_3_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_4 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_4_MEM_GPIO_PAD_CONFIG_4_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_4_MEM_GPIO_PAD_CONFIG_4_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_5 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_5_MEM_GPIO_PAD_CONFIG_5_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_5_MEM_GPIO_PAD_CONFIG_5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_6 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_6_MEM_GPIO_PAD_CONFIG_6_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_6_MEM_GPIO_PAD_CONFIG_6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_7 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_7_MEM_GPIO_PAD_CONFIG_7_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_7_MEM_GPIO_PAD_CONFIG_7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_8 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_8_MEM_GPIO_PAD_CONFIG_8_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_8_MEM_GPIO_PAD_CONFIG_8_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_9 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_9_MEM_GPIO_PAD_CONFIG_9_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_9_MEM_GPIO_PAD_CONFIG_9_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_10 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_10_MEM_GPIO_PAD_CONFIG_10_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_10_MEM_GPIO_PAD_CONFIG_10_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_11 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_11_MEM_GPIO_PAD_CONFIG_11_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_11_MEM_GPIO_PAD_CONFIG_11_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_12 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_12_MEM_GPIO_PAD_CONFIG_12_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_12_MEM_GPIO_PAD_CONFIG_12_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_13 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_13_MEM_GPIO_PAD_CONFIG_13_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_13_MEM_GPIO_PAD_CONFIG_13_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_14 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_14_MEM_GPIO_PAD_CONFIG_14_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_14_MEM_GPIO_PAD_CONFIG_14_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_15 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_15_MEM_GPIO_PAD_CONFIG_15_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_15_MEM_GPIO_PAD_CONFIG_15_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_16 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_16_MEM_GPIO_PAD_CONFIG_16_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_16_MEM_GPIO_PAD_CONFIG_16_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_17 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_17_MEM_GPIO_PAD_CONFIG_17_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_17_MEM_GPIO_PAD_CONFIG_17_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_18 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_18_MEM_GPIO_PAD_CONFIG_18_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_18_MEM_GPIO_PAD_CONFIG_18_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_19 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_19_MEM_GPIO_PAD_CONFIG_19_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_19_MEM_GPIO_PAD_CONFIG_19_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_20 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_20_MEM_GPIO_PAD_CONFIG_20_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_20_MEM_GPIO_PAD_CONFIG_20_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_21 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_21_MEM_GPIO_PAD_CONFIG_21_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_21_MEM_GPIO_PAD_CONFIG_21_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_22 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_22_MEM_GPIO_PAD_CONFIG_22_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_22_MEM_GPIO_PAD_CONFIG_22_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_23 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_23_MEM_GPIO_PAD_CONFIG_23_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_23_MEM_GPIO_PAD_CONFIG_23_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_24 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_24_MEM_GPIO_PAD_CONFIG_24_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_24_MEM_GPIO_PAD_CONFIG_24_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_25 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_25_MEM_GPIO_PAD_CONFIG_25_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_25_MEM_GPIO_PAD_CONFIG_25_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_26 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_26_MEM_GPIO_PAD_CONFIG_26_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_26_MEM_GPIO_PAD_CONFIG_26_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_27 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_27_MEM_GPIO_PAD_CONFIG_27_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_27_MEM_GPIO_PAD_CONFIG_27_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_28 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_28_MEM_GPIO_PAD_CONFIG_28_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_28_MEM_GPIO_PAD_CONFIG_28_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_29 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_29_MEM_GPIO_PAD_CONFIG_29_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_29_MEM_GPIO_PAD_CONFIG_29_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_30 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_30_MEM_GPIO_PAD_CONFIG_30_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_30_MEM_GPIO_PAD_CONFIG_30_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_31 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_31_MEM_GPIO_PAD_CONFIG_31_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_31_MEM_GPIO_PAD_CONFIG_31_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_32 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_32_MEM_GPIO_PAD_CONFIG_32_M \ + 0x00000FFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." it can be used + // for I2C type of peripherals. 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_32_MEM_GPIO_PAD_CONFIG_32_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_33 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_33_MEM_GPIO_PAD_CONFIG_33_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_33_MEM_GPIO_PAD_CONFIG_33_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_34 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_34_MEM_GPIO_PAD_CONFIG_34_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_34_MEM_GPIO_PAD_CONFIG_34_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_35 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_35_MEM_GPIO_PAD_CONFIG_35_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_35_MEM_GPIO_PAD_CONFIG_35_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_36 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_36_MEM_GPIO_PAD_CONFIG_36_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_36_MEM_GPIO_PAD_CONFIG_36_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_37 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_37_MEM_GPIO_PAD_CONFIG_37_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_37_MEM_GPIO_PAD_CONFIG_37_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_38 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_38_MEM_GPIO_PAD_CONFIG_38_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_38_MEM_GPIO_PAD_CONFIG_38_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_39 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_39_MEM_GPIO_PAD_CONFIG_39_M \ + 0x0000003F // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 5 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. IODEN and I8MAEN + // is diesabled for all development + // IO's. These signals are tied to + // logic level '0'. common control + // is implemented for I2MAEN, + // I4MAEN, WKPU, WKPD control . + // refer dev_pad_cmn_config register + // bits. + +#define OCP_SHARED_GPIO_PAD_CONFIG_39_MEM_GPIO_PAD_CONFIG_39_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CONFIG_40 register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CONFIG_40_MEM_GPIO_PAD_CONFIG_40_M \ + 0x0007FFFF // GPIO 0 register: "Bit 0 - 3 is + // used for PAD IO mode selection. + // io_register={ "" 0 => + // """"CONFMODE[0]"""""" "" 1 => + // """"CONFMODE[1]"""""" "" 2 => + // """"CONFMODE[2]"""""" "" 3 => + // """"CONFMODE[3]"""" 4 => + // """"IODEN"""" --> When level ‘1’ + // this disables the PMOS xtors of + // the output stages making them + // open-drain type." "For example in + // case of I2C Value gets latched at + // rising edge of RET33.""" """ 5 => + // """"I2MAEN"""" --> Level ‘1’ + // enables the approx 2mA output + // stage""" """ 6 => """"I4MAEN"""" + // --> Level ‘1’ enables the approx + // 4mA output stage""" """ 7 => + // """"I8MAEN"""" --> Level ‘1’ + // enables the approx 8mA output + // stage. Note: any drive strength + // between 2mA and 14mA can be + // obtained with combination of 2mA + // 4mA and 8mA.""" """ 8 => + // """"IWKPUEN"""" --> 10uA pull up + // (weak strength)""" """ 9 => + // """"IWKPDEN"""" --> 10uA pull + // down (weak strength)""" """ 10 => + // """"IOE_N"""" --> output enable + // value. level ‘0’ enables the IDO + // to PAD path. Else PAD is + // tristated (except for the PU/PD + // which are independent)." "Value + // gets latched at rising edge of + // RET33""" """ 11 =>"""" + // IOE_N_OV"""" --> output enable + // overirde. when bit is set to + // logic '1' IOE_N (bit 4) value + // will control IO IOE_N signal else + // IOE_N is control via selected HW + // logic. strong PULL UP and PULL + // Down control is disabled for all + // IO's. both controls are tied to + // logic level '0'. + +#define OCP_SHARED_GPIO_PAD_CONFIG_40_MEM_GPIO_PAD_CONFIG_40_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_GPIO_PAD_CMN_CONFIG register. +// +//****************************************************************************** +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_D2D_ISO_A_EN \ + 0x00000080 // when '1' enable ISO A control to + // D2D Pads else ISO is disabled. + // For these PADS to be functional + // this signals should be set 0. + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_D2D_ISO_Y_EN \ + 0x00000040 // when '1' enable ISO Y control to + // D2D Pads else ISO is disabled. + // For these PADS to be functional + // this signals should be set 0. + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_JTAG_IDIEN \ + 0x00000020 // If level ‘1’ enables the PAD to + // ODI path for JTAG PADS [PAD 23, + // 24, 28, 29]. Else ODI is pulled + // ‘Low’ regardless of PAD level." + // "Value gets latched at rising + // edge of RET33.""" """ + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_HYSTVAL_M \ + 0x00000018 // 00’: hysteriris = 10% of VDDS + // (difference between upper and + // lower threshold of the schmit + // trigger) ‘01’: hysteriris = 20% + // of VDDS (difference between upper + // and lower threshold of the schmit + // trigger) ‘10’: hysteriris = 30% + // of VDDS (difference between upper + // and lower threshold of the schmit + // trigger) ‘11’: hysteriris = 40% + // of VDDS (difference between upper + // and lower threshold of the schmit + // trigger)" """ + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_HYSTVAL_S 3 +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_HYSTEN \ + 0x00000004 // If logic ‘0’ there is no + // hysteresis. Set to ‘1’ to enable + // hysteresis. Leave the choice to + // customers""" + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_IBIASEN \ + 0x00000002 // Normal functional operation set + // this to logic ‘1’ to increase the + // speed of the o/p buffer at the + // cost of 0.2uA static current + // consumption per IO. During IDDQ + // test and during Hibernate this + // would be forced to logic ‘0’. + // Value is not latched at rising + // edge of RET33."" + +#define OCP_SHARED_GPIO_PAD_CMN_CONFIG_MEM_PAD_IDIEN \ + 0x00000001 // If level ‘1’ enables the PAD to + // ODI path. Else ODI is pulled + // ‘Low’ regardless of PAD level." + // "Value gets latched at rising + // edge of RET33.""" """ + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_D2D_DEV_PAD_CMN_CONFIG register. +// +//****************************************************************************** +#define OCP_SHARED_D2D_DEV_PAD_CMN_CONFIG_MEM_DEV_PAD_CMN_CONF_M \ + 0x0000003F // this register implements common + // IO control to all devement mode + // PADs; these PADs are DEV_PAD33 to + // DEV_PAD39. Bit [1:0] : Drive + // strength control. These 2 bits + // are connected to DEV PAD drive + // strength control. possible drive + // stregnths are 2MA, 4MA and 6 MA + // for the these IO's. bit 0: when + // set to logic value '1' enable 2MA + // drive strength for DEVPAD01 to 07 + // bit 1: when set to logic value + // '1' enable 4MA drive strength for + // DEVPAD01 to 07. bit[3:2] : WK + // PULL UP and PULL down control. + // These 2 bits provide IWKPUEN and + // IWKPDEN control for all DEV IO's. + // bit 2: when set to logic value + // '1' enable WKPU to DEVPAD01 to 07 + // bit 3: when set to logic value + // '1' enable WKPD to DEVPAD01 to + // 07. bit 4: WK PULL control for + // DEV_PKG_DETECT pin. when '1' + // pullup enabled else it is + // disable. bit 5: when set to logic + // value '1' enable 8MA drive + // strength for DEVPAD01 to 07. + +#define OCP_SHARED_D2D_DEV_PAD_CMN_CONFIG_MEM_DEV_PAD_CMN_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_D2D_TOSTACK_PAD_CONF register. +// +//****************************************************************************** +#define OCP_SHARED_D2D_TOSTACK_PAD_CONF_MEM_D2D_TOSTACK_PAD_CONF_M \ + 0x1FFFFFFF // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + // this register control OEN2X pin + // of D2D TOSTACK PAD: OEN1X and + // OEN2X decoding is as follows: + // "when ""00"" :" "when ""01"" : + // dirve strength is '1' and output + // buffer enabled." "when ""10"" : + // drive strength is 2 and output + // buffer is disabled." "when ""11"" + // : dirve strength is '3' and + // output buffer enabled." + +#define OCP_SHARED_D2D_TOSTACK_PAD_CONF_MEM_D2D_TOSTACK_PAD_CONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_D2D_MISC_PAD_CONF register. +// +//****************************************************************************** +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_POR_RESET_N \ + 0x00000200 // This register provide OEN2X + // control to D2D PADS OEN/OEN2X + // control. When 0 : Act as input + // buffer else output buffer with + // drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_RESET_N \ + 0x00000100 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_HCLK \ + 0x00000080 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_JTAG_TCK \ + 0x00000040 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_JTAG_TMS \ + 0x00000020 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_JTAG_TDI \ + 0x00000010 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_PIOSC \ + 0x00000008 // OEN/OEN2X control. When 0 : Act + // as input buffer else output + // buffer with drive strength 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_SPARE_M \ + 0x00000007 // D2D SPARE PAD OEN/OEN2X control. + // When 0: Act as input buffer else + // output buffer with drive strength + // 2. + +#define OCP_SHARED_D2D_MISC_PAD_CONF_MEM_D2D_SPARE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SOP_CONF_OVERRIDE register. +// +//****************************************************************************** +#define OCP_SHARED_SOP_CONF_OVERRIDE_MEM_SOP_CONF_OVERRIDE \ + 0x00000001 // when '1' : signal will ovberride + // SoP setting of JTAG PADS. when + // '0': SoP setting will control + // JTAG PADs [ TDI, TDO, TMS, TCK] + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_DEBUGSS_STATUS register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_APPS_MCU_JTAGNSW \ + 0x00000020 // This register contains debug + // subsystem status bits From APPS + // MCU status bit to indicates + // whether serial wire or 4 pins + // jtag select. + +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_CJTAG_BYPASS_STATUS \ + 0x00000010 // cjtag bypass bit select + +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_SW_INTERFACE_SEL_STATUS \ + 0x00000008 // serial wire interface bit select + +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_APPS_TAP_ENABLE_STATUS \ + 0x00000004 // apps tap enable status + +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_TAPS_ENABLE_STATUS \ + 0x00000002 // tap enable status + +#define OCP_SHARED_CC3XX_DEBUGSS_STATUS_SSBD_UNLOCK \ + 0x00000001 // ssbd unlock status + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_DEBUGMUX_SEL register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_DEBUGMUX_SEL_MEM_CC3XX_DEBUGMUX_SEL_M \ + 0x0000FFFF // debug mux select register. Upper + // 8 bits are used for debug module + // selection. Lower 8 bit [7:0] used + // inside debug module for selecting + // module specific signals. + // Bits[15:8: when set x"00" : GPRCM + // debug bus. When "o1" : SDIO debug + // debug bus when x"02" : + // autonoumous SPI when x"03" : + // TOPIC when x"04": memss when + // x"25": mcu debug bus : APPS debug + // when x"45": mcu debug bus : NWP + // debug when x"65": mcu debug bus : + // AHB2VBUS debug when x"85": mcu + // debug bus : VBUS2HAB debug when + // x"95": mcu debug bus : RCM debug + // when x"A5": mcu debug bus : + // crypto debug when x"06": WLAN + // debug bus when x"07": debugss bus + // when x"08": ADC debug when x"09": + // SDIO PHY debug bus then "others" + // : no debug is selected + +#define OCP_SHARED_CC3XX_DEBUGMUX_SEL_MEM_CC3XX_DEBUGMUX_SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_ALT_PC_VAL_NW register. +// +//****************************************************************************** +#define OCP_SHARED_ALT_PC_VAL_NW_MEM_ALT_PC_VAL_NW_M \ + 0xFFFFFFFF // 32 bit. Program counter value + // for 0x4 address when Alt_pc_en_nw + // is set. + +#define OCP_SHARED_ALT_PC_VAL_NW_MEM_ALT_PC_VAL_NW_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_ALT_PC_VAL_APPS register. +// +//****************************************************************************** +#define OCP_SHARED_ALT_PC_VAL_APPS_MEM_ALT_PC_VAL_APPS_M \ + 0xFFFFFFFF // 32 bit. Program counter value + // for 0x4 address when + // Alt_pc_en_apps is set + +#define OCP_SHARED_ALT_PC_VAL_APPS_MEM_ALT_PC_VAL_APPS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_4 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_4_MEM_SPARE_REG_4_M \ + 0xFFFFFFFE // HW register + +#define OCP_SHARED_SPARE_REG_4_MEM_SPARE_REG_4_S 1 +#define OCP_SHARED_SPARE_REG_4_INVERT_D2D_INTERFACE \ + 0x00000001 // Data to the top die launched at + // negative edge instead of positive + // edge. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_5 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_5_MEM_SPARE_REG_5_M \ + 0xFFFFFFFF // HW register + +#define OCP_SHARED_SPARE_REG_5_MEM_SPARE_REG_5_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SH_SPI_CS_MASK register. +// +//****************************************************************************** +#define OCP_SHARED_SH_SPI_CS_MASK_MEM_SH_SPI_CS_MASK_M \ + 0x0000000F // ( chip select 0 is unmasked + // after reset. When ‘1’ : CS is + // unmasked or else masked. Valid + // configurations are 1000, 0100, + // 0010 or 0001. Any other setting + // can lead to unpredictable + // behavior. + +#define OCP_SHARED_SH_SPI_CS_MASK_MEM_SH_SPI_CS_MASK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_DEVICE_TYPE register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_DEVICE_TYPE_DEVICE_TYPE_reserved_M \ + 0x00000060 // reserved bits tied off "00". + +#define OCP_SHARED_CC3XX_DEVICE_TYPE_DEVICE_TYPE_reserved_S 5 +#define OCP_SHARED_CC3XX_DEVICE_TYPE_DEVICE_TYPE_M \ + 0x0000001F // CC3XX Device type information. + +#define OCP_SHARED_CC3XX_DEVICE_TYPE_DEVICE_TYPE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_MEM_TOPMUXCTRL_IFORCE register. +// +//****************************************************************************** +#define OCP_SHARED_MEM_TOPMUXCTRL_IFORCE_MEM_TOPMUXCTRL_IFORCE1_M \ + 0x000000F0 // [4] 1: switch between + // WLAN_I2C_SCL and + // TOP_GPIO_PORT4_I2C closes 0: + // switch opens [5] 1: switch + // between WLAN_I2C_SCL and + // TOP_VSENSE_PORT closes 0: switch + // opens [6] 1: switch between + // WLAN_I2C_SCL and WLAN_ANA_TP4 + // closes 0: switch opens [7] + // Reserved + +#define OCP_SHARED_MEM_TOPMUXCTRL_IFORCE_MEM_TOPMUXCTRL_IFORCE1_S 4 +#define OCP_SHARED_MEM_TOPMUXCTRL_IFORCE_MEM_TOPMUXCTRL_IFORCE_M \ + 0x0000000F // [0] 1: switch between + // WLAN_I2C_SDA and + // TOP_GPIO_PORT3_I2C closes 0: + // switch opens [1] 1: switch + // between WLAN_I2C_SDA and + // TOP_IFORCE_PORT closes 0: switch + // opens [2] 1: switch between + // WLAN_I2C_SDA and WLAN_ANA_TP3 + // closes 0: switch opens [3] + // Reserved + +#define OCP_SHARED_MEM_TOPMUXCTRL_IFORCE_MEM_TOPMUXCTRL_IFORCE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_DEV_PACKAGE_DETECT register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_DEV_PACKAGE_DETECT_DEV_PKG_DETECT \ + 0x00000001 // when '0' indicates package type + // is development. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_AUTONMS_SPICLK_SEL register. +// +//****************************************************************************** +#define OCP_SHARED_AUTONMS_SPICLK_SEL_MEM_AUTONOMOUS_BYPASS \ + 0x00000002 // This bit is used to bypass MCPSI + // autonomous mode .if this bit is 1 + // autonomous MCSPI logic will be + // bypassed and it will act as link + // SPI + +#define OCP_SHARED_AUTONMS_SPICLK_SEL_MEM_AUTONMS_SPICLK_SEL \ + 0x00000001 // This bit is used in SPI + // Autonomous mode to switch clock + // from system clock to SPI clk that + // is coming from PAD. When value 1 + // PAD SPI clk is used as system + // clock in LPDS mode by SPI as well + // as autonomous wrapper logic. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_CC3XX_DEV_PADCONF register. +// +//****************************************************************************** +#define OCP_SHARED_CC3XX_DEV_PADCONF_MEM_CC3XX_DEV_PADCONF_M \ + 0x0000FFFF + +#define OCP_SHARED_CC3XX_DEV_PADCONF_MEM_CC3XX_DEV_PADCONF_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_IDMEM_TIM_UPDATE register. +// +//****************************************************************************** +#define OCP_SHARED_IDMEM_TIM_UPDATE_MEM_IDMEM_TIM_UPDATE_M \ + 0xFFFFFFFF + +#define OCP_SHARED_IDMEM_TIM_UPDATE_MEM_IDMEM_TIM_UPDATE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_6 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_6_MEM_SPARE_REG_6_M \ + 0xFFFFFFFF // NWP Software register + +#define OCP_SHARED_SPARE_REG_6_MEM_SPARE_REG_6_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_SPARE_REG_7 register. +// +//****************************************************************************** +#define OCP_SHARED_SPARE_REG_7_MEM_SPARE_REG_7_M \ + 0xFFFFFFFF // NWP Software register + +#define OCP_SHARED_SPARE_REG_7_MEM_SPARE_REG_7_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_APPS_WLAN_ORBIT register. +// +//****************************************************************************** +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_spare_M \ + 0xFFFFFC00 // Spare bit + +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_spare_S 10 +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_test_status \ + 0x00000200 // A rising edge on this bit + // indicates that the test case + // passes. This bit would be brought + // out on the pin interface during + // ORBIT. + +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_test_exec \ + 0x00000100 // This register bit is writable by + // the FW and when set to 1 it + // indicates the start of a test + // execution. A failing edge on this + // bit indicates that the test + // execution is complete. This bit + // would be brought out on the pin + // interface during ORBIT. + +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_test_id_M \ + 0x000000FC // Implies the test case ID that + // needs to run. + +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_test_id_S 2 +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_halt_proc \ + 0x00000002 // This bit is used to trigger the + // execution of test cases within + // the (ROM based) IP. + +#define OCP_SHARED_APPS_WLAN_ORBIT_mem_orbit_test_mode \ + 0x00000001 // When this bit is 1 it implies + // ORBIT mode of operation and the + // (ROM based) IP start the + // execution from a test case + // perspective + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// OCP_SHARED_O_APPS_WLAN_SCRATCH_PAD register. +// +//****************************************************************************** +#define OCP_SHARED_APPS_WLAN_SCRATCH_PAD_MEM_APPS_WLAN_SCRATCH_PAD_M \ + 0xFFFFFFFF // scratch pad register. + +#define OCP_SHARED_APPS_WLAN_SCRATCH_PAD_MEM_APPS_WLAN_SCRATCH_PAD_S 0 + + + +#endif // __HW_OCP_SHARED_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_shamd5.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_shamd5.h new file mode 100755 index 0000000..cf6254f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_shamd5.h @@ -0,0 +1,1242 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_SHAMD5_H__ +#define __HW_SHAMD5_H__ + +//***************************************************************************** +// +// The following are defines for the SHAMD5_P register offsets. +// +//***************************************************************************** +#define SHAMD5_O_ODIGEST_A 0x00000000 // WRITE: Outer Digest [127:96] for + // MD5 [159:128] for SHA-1 [255:224] + // for SHA-2 / HMAC Key [31:0] for + // HMAC key proc READ: Outer Digest + // [127:96] for MD5 [159:128] for + // SHA-1 [255:224] for SHA-2 +#define SHAMD5_O_ODIGEST_B 0x00000004 // WRITE: Outer Digest [95:64] for + // MD5 [127:96] for SHA-1 [223:192] + // for SHA-2 / HMAC Key [63:32] for + // HMAC key proc READ: Outer Digest + // [95:64] for MD5 [127:96] for + // SHA-1 [223:192] for SHA-2 +#define SHAMD5_O_ODIGEST_C 0x00000008 // WRITE: Outer Digest [63:32] for + // MD5 [95:64] for SHA-1 [191:160] + // for SHA-2 / HMAC Key [95:64] for + // HMAC key proc READ: Outer Digest + // [63:32] for MD5 [95:64] for SHA-1 + // [191:160] for SHA-2 +#define SHAMD5_O_ODIGEST_D 0x0000000C // WRITE: Outer Digest [31:0] for + // MD5 [63:31] for SHA-1 [159:128] + // for SHA-2 / HMAC Key [127:96] for + // HMAC key proc READ: Outer Digest + // [31:0] for MD5 [63:32] for SHA-1 + // [159:128] for SHA-2 +#define SHAMD5_O_ODIGEST_E 0x00000010 // WRITE: Outer Digest [31:0] for + // SHA-1 [127:96] for SHA-2 / HMAC + // Key [159:128] for HMAC key proc + // READ: Outer Digest [31:0] for + // SHA-1 [127:96] for SHA-2 +#define SHAMD5_O_ODIGEST_F 0x00000014 // WRITE: Outer Digest [95:64] for + // SHA-2 / HMAC Key [191:160] for + // HMAC key proc READ: Outer Digest + // [95:64] for SHA-2 +#define SHAMD5_O_ODIGEST_G 0x00000018 // WRITE: Outer Digest [63:32] for + // SHA-2 / HMAC Key [223:192] for + // HMAC key proc READ: Outer Digest + // [63:32] for SHA-2 +#define SHAMD5_O_ODIGEST_H 0x0000001C // WRITE: Outer Digest [31:0] for + // SHA-2 / HMAC Key [255:224] for + // HMAC key proc READ: Outer Digest + // [31:0] for SHA-2 +#define SHAMD5_O_IDIGEST_A 0x00000020 // WRITE: Inner / Initial Digest + // [127:96] for MD5 [159:128] for + // SHA-1 [255:224] for SHA-2 / HMAC + // Key [287:256] for HMAC key proc + // READ: Intermediate / Inner Digest + // [127:96] for MD5 [159:128] for + // SHA-1 [255:224] for SHA-2 / + // Result Digest/MAC [127:96] for + // MD5 [159:128] for SHA-1 [223:192] + // for SHA-2 224 [255:224] for SHA-2 + // 256 +#define SHAMD5_O_IDIGEST_B 0x00000024 // WRITE: Inner / Initial Digest + // [95:64] for MD5 [127:96] for + // SHA-1 [223:192] for SHA-2 / HMAC + // Key [319:288] for HMAC key proc + // READ: Intermediate / Inner Digest + // [95:64] for MD5 [127:96] for + // SHA-1 [223:192] for SHA-2 / + // Result Digest/MAC [95:64] for MD5 + // [127:96] for SHA-1 [191:160] for + // SHA-2 224 [223:192] for SHA-2 256 +#define SHAMD5_O_IDIGEST_C 0x00000028 // WRITE: Inner / Initial Digest + // [63:32] for MD5 [95:64] for SHA-1 + // [191:160] for SHA- 2 / HMAC Key + // [351:320] for HMAC key proc READ: + // Intermediate / Inner Digest + // [63:32] for MD5 [95:64] for SHA-1 + // [191:160] for SHA-2 / Result + // Digest/MAC [63:32] for MD5 + // [95:64] for SHA-1 [159:128] for + // SHA-2 224 [191:160] for SHA-2 256 +#define SHAMD5_O_IDIGEST_D 0x0000002C // WRITE: Inner / Initial Digest + // [31:0] for MD5 [63:32] for SHA-1 + // [159:128] for SHA-2 / HMAC Key + // [383:352] for HMAC key proc READ: + // Intermediate / Inner Digest + // [31:0] for MD5 [63:32] for SHA-1 + // [159:128] for SHA-2 / Result + // Digest/MAC [31:0] for MD5 [63:32] + // for SHA-1 [127:96] for SHA-2 224 + // [159:128] for SHA-2 256 +#define SHAMD5_O_IDIGEST_E 0x00000030 // WRITE: Inner / Initial Digest + // [31:0] for SHA-1 [127:96] for + // SHA-2 / HMAC Key [415:384] for + // HMAC key proc READ: Intermediate + // / Inner Digest [31:0] for SHA-1 + // [127:96] for SHA-2 / Result + // Digest/MAC [31:0] for SHA-1 + // [95:64] for SHA-2 224 [127:96] + // for SHA-2 256 +#define SHAMD5_O_IDIGEST_F 0x00000034 // WRITE: Inner / Initial Digest + // [95:64] for SHA-2 / HMAC Key + // [447:416] for HMAC key proc READ: + // Intermediate / Inner Digest + // [95:64] for SHA-2 / Result + // Digest/MAC [63:32] for SHA-2 224 + // [95:64] for SHA-2 256 +#define SHAMD5_O_IDIGEST_G 0x00000038 // WRITE: Inner / Initial Digest + // [63:32] for SHA-2 / HMAC Key + // [479:448] for HMAC key proc READ: + // Intermediate / Inner Digest + // [63:32] for SHA-2 / Result + // Digest/MAC [31:0] for SHA-2 224 + // [63:32] for SHA-2 256 +#define SHAMD5_O_IDIGEST_H 0x0000003C // WRITE: Inner / Initial Digest + // [31:0] for SHA-2 / HMAC Key + // [511:480] for HMAC key proc READ: + // Intermediate / Inner Digest + // [31:0] for SHA-2 / Result + // Digest/MAC [31:0] for SHA-2 256 +#define SHAMD5_O_DIGEST_COUNT 0x00000040 // WRITE: Initial Digest Count + // ([31:6] only [5:0] assumed 0) + // READ: Result / IntermediateDigest + // Count The initial digest byte + // count for hash/HMAC continue + // operations (HMAC Key Processing = + // 0 and Use Algorithm Constants = + // 0) on the Secure World must be + // written to this register prior to + // starting the operation by writing + // to S_HASH_MODE. When either HMAC + // Key Processing is 1 or Use + // Algorithm Constants is 1 this + // register does not need to be + // written it will be overwritten + // with 64 (1 hash block of key XOR + // ipad) or 0 respectively + // automatically. When starting a + // HMAC operation from pre-computes + // (HMAC Key Processing is 0) then + // the value 64 must be written here + // to compensate for the appended + // key XOR ipad block. Note that the + // value written should always be a + // 64 byte multiple the lower 6 bits + // written are ignored. The updated + // digest byte count (initial digest + // byte count + bytes processed) can + // be read from this register when + // the status register indicates + // that the operation is done or + // suspended due to a context switch + // request or when a Secure World + // context out DMA is requested. In + // Advanced DMA mode when not + // suspended with a partial result + // reading the SHAMD5_DIGEST_COUNT + // register triggers the Hash/HMAC + // Engine to start the next context + // input DMA. Therefore reading the + // SHAMD5_DIGEST_COUNT register + // should always be the last + // context-read action if not + // suspended with a partial result + // (i.e. PartHashReady interrupt not + // pending). +#define SHAMD5_O_MODE 0x00000044 // Register SHAMD5_MODE +#define SHAMD5_O_LENGTH 0x00000048 // WRITE: Block Length / Remaining + // Byte Count (bytes) READ: + // Remaining Byte Count. The value + // programmed MUST be a 64-byte + // multiple if Close Hash is set to + // 0. This register is also the + // trigger to start processing: once + // this register is written the core + // will commence requesting input + // data via DMA or IRQ (if + // programmed length > 0) and start + // processing. The remaining byte + // count for the active operation + // can be read from this register + // when the interrupt status + // register indicates that the + // operation is suspended due to a + // context switch request. +#define SHAMD5_O_DATA0_IN 0x00000080 // Data input message 0 +#define SHAMD5_O_DATA1_IN 0x00000084 // Data input message 1 +#define SHAMD5_O_DATA2_IN 0x00000088 // Data input message 2 +#define SHAMD5_O_DATA3_IN 0x0000008C // Data input message 3 +#define SHAMD5_O_DATA4_IN 0x00000090 // Data input message 4 +#define SHAMD5_O_DATA5_IN 0x00000094 // Data input message 5 +#define SHAMD5_O_DATA6_IN 0x00000098 // Data input message 6 +#define SHAMD5_O_DATA7_IN 0x0000009C // Data input message 7 +#define SHAMD5_O_DATA8_IN 0x000000A0 // Data input message 8 +#define SHAMD5_O_DATA9_IN 0x000000A4 // Data input message 9 +#define SHAMD5_O_DATA10_IN 0x000000A8 // Data input message 10 +#define SHAMD5_O_DATA11_IN 0x000000AC // Data input message 11 +#define SHAMD5_O_DATA12_IN 0x000000B0 // Data input message 12 +#define SHAMD5_O_DATA13_IN 0x000000B4 // Data input message 13 +#define SHAMD5_O_DATA14_IN 0x000000B8 // Data input message 14 +#define SHAMD5_O_DATA15_IN 0x000000BC // Data input message 15 +#define SHAMD5_O_REVISION 0x00000100 // Register SHAMD5_REV +#define SHAMD5_O_SYSCONFIG 0x00000110 // Register SHAMD5_SYSCONFIG +#define SHAMD5_O_SYSSTATUS 0x00000114 // Register SHAMD5_SYSSTATUS +#define SHAMD5_O_IRQSTATUS 0x00000118 // Register SHAMD5_IRQSTATUS +#define SHAMD5_O_IRQENABLE 0x0000011C // Register SHAMD5_IRQENABLE. The + // SHAMD5_IRQENABLE register contains + // an enable bit for each unique + // interrupt for the public side. An + // interrupt is enabled when both + // the global enable in + // SHAMD5_SYSCONFIG (PIT_en) and the + // bit in this register are both set + // to 1. An interrupt that is + // enabled is propagated to the + // SINTREQUEST_P output. Please note + // that the dedicated partial hash + // output (SINTREQUEST_PART_P) is + // not affected by this register it + // is only affected by the global + // enable SHAMD5_SYSCONFIG (PIT_en). +#define SHAMD5_O_HASH512_ODIGEST_A \ + 0x00000200 + +#define SHAMD5_O_HASH512_ODIGEST_B \ + 0x00000204 + +#define SHAMD5_O_HASH512_ODIGEST_C \ + 0x00000208 + +#define SHAMD5_O_HASH512_ODIGEST_D \ + 0x0000020C + +#define SHAMD5_O_HASH512_ODIGEST_E \ + 0x00000210 + +#define SHAMD5_O_HASH512_ODIGEST_F \ + 0x00000214 + +#define SHAMD5_O_HASH512_ODIGEST_G \ + 0x00000218 + +#define SHAMD5_O_HASH512_ODIGEST_H \ + 0x0000021C + +#define SHAMD5_O_HASH512_ODIGEST_I \ + 0x00000220 + +#define SHAMD5_O_HASH512_ODIGEST_J \ + 0x00000224 + +#define SHAMD5_O_HASH512_ODIGEST_K \ + 0x00000228 + +#define SHAMD5_O_HASH512_ODIGEST_L \ + 0x0000022C + +#define SHAMD5_O_HASH512_ODIGEST_M \ + 0x00000230 + +#define SHAMD5_O_HASH512_ODIGEST_N \ + 0x00000234 + +#define SHAMD5_O_HASH512_ODIGEST_O \ + 0x00000238 + +#define SHAMD5_O_HASH512_ODIGEST_P \ + 0x0000023C + +#define SHAMD5_O_HASH512_IDIGEST_A \ + 0x00000240 + +#define SHAMD5_O_HASH512_IDIGEST_B \ + 0x00000244 + +#define SHAMD5_O_HASH512_IDIGEST_C \ + 0x00000248 + +#define SHAMD5_O_HASH512_IDIGEST_D \ + 0x0000024C + +#define SHAMD5_O_HASH512_IDIGEST_E \ + 0x00000250 + +#define SHAMD5_O_HASH512_IDIGEST_F \ + 0x00000254 + +#define SHAMD5_O_HASH512_IDIGEST_G \ + 0x00000258 + +#define SHAMD5_O_HASH512_IDIGEST_H \ + 0x0000025C + +#define SHAMD5_O_HASH512_IDIGEST_I \ + 0x00000260 + +#define SHAMD5_O_HASH512_IDIGEST_J \ + 0x00000264 + +#define SHAMD5_O_HASH512_IDIGEST_K \ + 0x00000268 + +#define SHAMD5_O_HASH512_IDIGEST_L \ + 0x0000026C + +#define SHAMD5_O_HASH512_IDIGEST_M \ + 0x00000270 + +#define SHAMD5_O_HASH512_IDIGEST_N \ + 0x00000274 + +#define SHAMD5_O_HASH512_IDIGEST_O \ + 0x00000278 + +#define SHAMD5_O_HASH512_IDIGEST_P \ + 0x0000027C + +#define SHAMD5_O_HASH512_DIGEST_COUNT \ + 0x00000280 + +#define SHAMD5_O_HASH512_MODE 0x00000284 +#define SHAMD5_O_HASH512_LENGTH 0x00000288 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_A register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_A_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_A_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_B register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_B_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_B_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_C register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_C_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_C_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_D register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_D_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_D_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_E register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_E_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_E_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_F register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_F_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_F_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_G register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_G_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_G_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_ODIGEST_H register. +// +//****************************************************************************** +#define SHAMD5_ODIGEST_H_DATA_M 0xFFFFFFFF // data +#define SHAMD5_ODIGEST_H_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_A register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_A_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_A_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_B register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_B_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_B_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_C register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_C_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_C_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_D register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_D_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_D_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_E register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_E_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_E_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_F register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_F_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_F_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_G register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_G_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_G_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IDIGEST_H register. +// +//****************************************************************************** +#define SHAMD5_IDIGEST_H_DATA_M 0xFFFFFFFF // data +#define SHAMD5_IDIGEST_H_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_DIGEST_COUNT register. +// +//****************************************************************************** +#define SHAMD5_DIGEST_COUNT_DATA_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DIGEST_COUNT_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_MODE register. +// +//****************************************************************************** +#define SHAMD5_MODE_HMAC_OUTER_HASH \ + 0x00000080 // The HMAC Outer Hash is performed + // on the hash digest when the inner + // hash hash finished (block length + // exhausted and final hash + // performed if close_hash is 1). + // This bit should normally be set + // together with close_hash to + // finish the inner hash first or + // Block Length should be zero (HMAC + // continue with the just outer hash + // to be done). Auto cleared + // internally when outer hash + // performed. 0 No operation 1 hmac + // processing + +#define SHAMD5_MODE_HMAC_KEY_PROC \ + 0x00000020 // Performs HMAC key processing on + // the 512 bit HMAC key loaded into + // the SHAMD5_IDIGEST_{A to H} and + // SHAMD5_ODIGEST_{A to H} register + // block. Once HMAC key processing + // is finished this bit is + // automatically cleared and the + // resulting Inner and Outer digest + // is available from + // SHAMD5_IDIGEST_{A to H} and + // SHAMD5_ODIGEST_{A to H} + // respectively after which regular + // hash processing (using + // SHAMD5_IDIGEST_{A to H} as initial + // digest) will commence until the + // Block Length is exhausted. 0 No + // operation. 1 Hmac processing. + +#define SHAMD5_MODE_CLOSE_HASH 0x00000010 // Performs the padding the + // hash/HMAC will be 'closed' at the + // end of the block as per + // MD5/SHA-1/SHA-2 specification + // (i.e. appropriate padding is + // added) or no padding is done + // allowing the hash to be continued + // later. However if the hash/HMAC + // is not closed then the Block + // Length MUST be a multiple of 64 + // bytes to ensure correct + // operation. Auto cleared + // internally when hash closed. 0 No + // padding hash computation can be + // contimued. 1 Last packet will be + // padded. +#define SHAMD5_MODE_ALGO_CONSTANT \ + 0x00000008 // The initial digest register will + // be overwritten with the algorithm + // constants for the selected + // algorithm when hashing and the + // initial digest count register + // will be reset to 0. This will + // start a normal hash operation. + // When continuing an existing hash + // or when performing an HMAC + // operation this register must be + // set to 0 and the + // intermediate/inner digest or HMAC + // key and digest count need to be + // written to the context input + // registers prior to writing + // SHAMD5_MODE. Auto cleared + // internally after first block + // processed. 0 Use pre-calculated + // digest (from an other operation) + // 1 Use constants of the selected + // algo. + +#define SHAMD5_MODE_ALGO_M 0x00000006 // These bits select the hash + // algorithm to be used for + // processing: 0x0 md5_128 algorithm + // 0x1 sha1_160 algorithm 0x2 + // sha2_224 algorithm 0x3 sha2_256 + // algorithm +#define SHAMD5_MODE_ALGO_S 1 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_LENGTH register. +// +//****************************************************************************** +#define SHAMD5_LENGTH_DATA_M 0xFFFFFFFF // data +#define SHAMD5_LENGTH_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA0_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA0_IN_DATA0_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA0_IN_DATA0_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA1_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA1_IN_DATA1_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA1_IN_DATA1_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA2_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA2_IN_DATA2_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA2_IN_DATA2_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA3_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA3_IN_DATA3_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA3_IN_DATA3_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA4_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA4_IN_DATA4_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA4_IN_DATA4_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA5_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA5_IN_DATA5_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA5_IN_DATA5_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA6_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA6_IN_DATA6_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA6_IN_DATA6_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA7_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA7_IN_DATA7_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA7_IN_DATA7_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA8_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA8_IN_DATA8_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA8_IN_DATA8_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA9_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA9_IN_DATA9_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA9_IN_DATA9_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA10_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA10_IN_DATA10_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA10_IN_DATA10_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA11_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA11_IN_DATA11_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA11_IN_DATA11_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA12_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA12_IN_DATA12_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA12_IN_DATA12_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA13_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA13_IN_DATA13_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA13_IN_DATA13_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA14_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA14_IN_DATA14_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA14_IN_DATA14_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_DATA15_IN register. +// +//****************************************************************************** +#define SHAMD5_DATA15_IN_DATA15_IN_M \ + 0xFFFFFFFF // data + +#define SHAMD5_DATA15_IN_DATA15_IN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_REVISION register. +// +//****************************************************************************** +#define SHAMD5_REVISION_SCHEME_M 0xC0000000 +#define SHAMD5_REVISION_SCHEME_S 30 +#define SHAMD5_REVISION_FUNC_M 0x0FFF0000 // Function indicates a software + // compatible module family. If + // there is no level of software + // compatibility a new Func number + // (and hence REVISION) should be + // assigned. +#define SHAMD5_REVISION_FUNC_S 16 +#define SHAMD5_REVISION_R_RTL_M 0x0000F800 // RTL Version (R) maintained by IP + // design owner. RTL follows a + // numbering such as X.Y.R.Z which + // are explained in this table. R + // changes ONLY when: (1) PDS + // uploads occur which may have been + // due to spec changes (2) Bug fixes + // occur (3) Resets to '0' when X or + // Y changes. Design team has an + // internal 'Z' (customer invisible) + // number which increments on every + // drop that happens due to DV and + // RTL updates. Z resets to 0 when R + // increments. +#define SHAMD5_REVISION_R_RTL_S 11 +#define SHAMD5_REVISION_X_MAJOR_M \ + 0x00000700 // Major Revision (X) maintained by + // IP specification owner. X changes + // ONLY when: (1) There is a major + // feature addition. An example + // would be adding Master Mode to + // Utopia Level2. The Func field (or + // Class/Type in old PID format) + // will remain the same. X does NOT + // change due to: (1) Bug fixes (2) + // Change in feature parameters. + +#define SHAMD5_REVISION_X_MAJOR_S 8 +#define SHAMD5_REVISION_CUSTOM_M 0x000000C0 +#define SHAMD5_REVISION_CUSTOM_S 6 +#define SHAMD5_REVISION_Y_MINOR_M \ + 0x0000003F // Minor Revision (Y) maintained by + // IP specification owner. Y changes + // ONLY when: (1) Features are + // scaled (up or down). Flexibility + // exists in that this feature + // scalability may either be + // represented in the Y change or a + // specific register in the IP that + // indicates which features are + // exactly available. (2) When + // feature creeps from Is-Not list + // to Is list. But this may not be + // the case once it sees silicon; in + // which case X will change. Y does + // NOT change due to: (1) Bug fixes + // (2) Typos or clarifications (3) + // major functional/feature + // change/addition/deletion. Instead + // these changes may be reflected + // via R S X as applicable. Spec + // owner maintains a + // customer-invisible number 'S' + // which changes due to: (1) + // Typos/clarifications (2) Bug + // documentation. Note that this bug + // is not due to a spec change but + // due to implementation. + // Nevertheless the spec tracks the + // IP bugs. An RTL release (say for + // silicon PG1.1) that occurs due to + // bug fix should document the + // corresponding spec number (X.Y.S) + // in its release notes. + +#define SHAMD5_REVISION_Y_MINOR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_SYSCONFIG register. +// +//****************************************************************************** +#define SHAMD5_SYSCONFIG_PADVANCED \ + 0x00000080 // If set to 1 Advanced mode is + // enabled for the Secure World. If + // set to 0 Legacy mode is enabled + // for the Secure World. + +#define SHAMD5_SYSCONFIG_PCONT_SWT \ + 0x00000040 // Finish all pending data and + // context DMA input requests (but + // will not assert any new requests) + // finish processing all data in the + // module and provide a saved + // context (partial hash result + // updated digest count remaining + // length updated mode information + // where applicable) for the last + // operation that was interrupted so + // that it can be resumed later. + +#define SHAMD5_SYSCONFIG_PDMA_EN 0x00000008 +#define SHAMD5_SYSCONFIG_PIT_EN 0x00000004 +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_SYSSTATUS register. +// +//****************************************************************************** +#define SHAMD5_SYSSTATUS_RESETDONE \ + 0x00000001 // data + +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IRQSTATUS register. +// +//****************************************************************************** +#define SHAMD5_IRQSTATUS_CONTEXT_READY \ + 0x00000008 // indicates that the secure side + // context input registers are + // available for a new context for + // the next packet to be processed. + +#define SHAMD5_IRQSTATUS_PARTHASH_READY \ + 0x00000004 // After a secure side context + // switch request this bit will read + // as 1 indicating that the saved + // context is available from the + // secure side context output + // registers. Note that if the + // context switch request coincides + // with a final hash (when hashing) + // or an outer hash (when doing + // HMAC) that PartHashReady will not + // become active but a regular + // Output Ready will occur instead + // (indicating that the result is + // final and therefore no + // continuation is required). + +#define SHAMD5_IRQSTATUS_INPUT_READY \ + 0x00000002 // indicates that the secure side + // data FIFO is ready to receive the + // next 64 byte data block. + +#define SHAMD5_IRQSTATUS_OUTPUT_READY \ + 0x00000001 // Indicates that a (partial) + // result or saved context is + // available from the secure side + // context output registers. + +//****************************************************************************** +// +// The following are defines for the bit fields in the SHAMD5_O_IRQENABLE register. +// +//****************************************************************************** +#define SHAMD5_IRQENABLE_M_CONTEXT_READY \ + 0x00000008 // mask for context ready + +#define SHAMD5_IRQENABLE_M_PARTHASH_READY \ + 0x00000004 // mask for partial hash + +#define SHAMD5_IRQENABLE_M_INPUT_READY \ + 0x00000002 // mask for input_ready + +#define SHAMD5_IRQENABLE_M_OUTPUT_READY \ + 0x00000001 // mask for output_ready + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_A register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_A_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_A_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_B register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_B_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_B_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_C register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_C_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_C_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_D register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_D_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_D_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_E register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_E_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_E_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_F register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_F_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_F_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_G register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_G_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_G_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_H register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_H_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_H_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_I register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_I_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_I_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_J register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_J_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_J_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_K register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_K_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_K_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_L register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_L_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_L_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_M register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_M_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_M_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_N register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_N_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_N_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_O register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_O_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_O_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_ODIGEST_P register. +// +//****************************************************************************** +#define SHAMD5_HASH512_ODIGEST_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_ODIGEST_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_A register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_A_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_A_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_B register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_B_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_B_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_C register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_C_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_C_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_D register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_D_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_D_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_E register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_E_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_E_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_F register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_F_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_F_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_G register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_G_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_G_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_H register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_H_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_H_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_I register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_I_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_I_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_J register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_J_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_J_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_K register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_K_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_K_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_L register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_L_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_L_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_M register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_M_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_M_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_N register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_N_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_N_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_O register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_O_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_O_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_IDIGEST_P register. +// +//****************************************************************************** +#define SHAMD5_HASH512_IDIGEST_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_IDIGEST_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_DIGEST_COUNT register. +// +//****************************************************************************** +#define SHAMD5_HASH512_DIGEST_COUNT_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_DIGEST_COUNT_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_MODE register. +// +//****************************************************************************** +#define SHAMD5_HASH512_MODE_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_MODE_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// SHAMD5_O_HASH512_LENGTH register. +// +//****************************************************************************** +#define SHAMD5_HASH512_LENGTH_DATA_M \ + 0xFFFFFFFF + +#define SHAMD5_HASH512_LENGTH_DATA_S 0 + + + +#endif // __HW_SHAMD5_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_stack_die_ctrl.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_stack_die_ctrl.h new file mode 100755 index 0000000..eba31e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_stack_die_ctrl.h @@ -0,0 +1,764 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_STACK_DIE_CTRL_H__ +#define __HW_STACK_DIE_CTRL_H__ + +//***************************************************************************** +// +// The following are defines for the STACK_DIE_CTRL register offsets. +// +//***************************************************************************** +#define STACK_DIE_CTRL_O_STK_UP_RESET \ + 0x00000000 // Can be written only by Base + // Processor. Writing to this + // register will reset the stack + // processor reset will be + // de-asserted upon clearing this + // register. + +#define STACK_DIE_CTRL_O_SR_MASTER_PRIORITY \ + 0x00000004 // This register defines who among + // base processor and stack + // processor have highest priority + // for Sram Access. Can be written + // only by Base Processor. + +#define STACK_DIE_CTRL_O_STK_SR_ACC_CTL_BK2 \ + 0x00000008 // In Spinlock mode this Register + // defines who among base processor + // and stack processor have access + // to Sram Bank2 right now. In + // Handshake mode this Register + // defines who among base processor + // and stack processor have access + // to Sram Bank2 and Bank3 right + // now. Its Clear only register and + // is set by hardware. Lower bit can + // be cleared only by Base Processor + // and Upper bit Cleared only by the + // Stack processor. + +#define STACK_DIE_CTRL_O_BASE_UP_ACC_REQ_BK2 \ + 0x0000000C // In Spinlock mode whenever Base + // processor wants the access to + // Sram Bank2 it should request for + // it by writing into this register. + // It'll get interrupt whenever it + // is granted. In Handshake mode + // this bit will be set by Stack + // processor. Its a set only bit and + // is cleared by HW when the request + // is granted. + +#define STACK_DIE_CTRL_O_STK_UP_ACC_REQ_BK2 \ + 0x00000010 // In Spinlock mode Whenever Stack + // processor wants the access to + // Sram Bank2 it should request for + // it by writing into this register. + // It'll get interrupt whenever it + // is granted. In Handshake mode + // this bit will be set by the Base + // processor. Its a set only bit and + // is cleared by HW when the request + // is granted. + +#define STACK_DIE_CTRL_O_STK_SR_ACC_CTL_BK3 \ + 0x00000014 // Register defines who among base + // processor and stack processor + // have access to Sram Bank3 right + // now. Its Clear only register and + // is set by hardware. Lower bit can + // be cleared only by Base Processor + // and Upper bit Cleared only by the + // Stack processor. + +#define STACK_DIE_CTRL_O_BASE_UP_ACC_REQ_BK3 \ + 0x00000018 // In Spinlock mode whenever Base + // processor wants the access to + // Sram Bank3 it should request for + // it by writing into this register. + // It'll get interrupt whenever it + // is granted. In Handshake mode + // this bit will be set by Stack + // processor. Its a set only bit and + // is cleared by HW when the request + // is granted. + +#define STACK_DIE_CTRL_O_STK_UP_ACC_REQ_BK3 \ + 0x0000001C // In Spinlock mode Whenever Stack + // processor wants the access to + // Sram Bank3 it should request for + // it by writing into this register. + // It'll get interrupt whenever it + // is granted. In Handshake mode + // this bit will be set by the Base + // processor. Its a set only bit and + // is cleared by HW when the request + // is granted. + +#define STACK_DIE_CTRL_O_RDSM_CFG_CPU \ + 0x00000020 // Read State Machine timing + // configuration register. Generally + // Bit 4 and 3 will be identical. + // For stacked die always 43 are 0 + // and 6:5 == 1 for 120Mhz. + +#define STACK_DIE_CTRL_O_RDSM_CFG_EE \ + 0x00000024 // Read State Machine timing + // configuration register. Generally + // Bit 4 and 3 will be identical. + // For stacked die always 43 are 0 + // and 6:5 == 1 for 120Mhz. + +#define STACK_DIE_CTRL_O_BASE_UP_IRQ_LOG \ + 0x00000028 // Reading this register Base + // procesor will able to know the + // reason for the interrupt. This is + // clear only register - set by HW + // upon an interrupt to Base + // processor and can be cleared only + // by BASE processor. + +#define STACK_DIE_CTRL_O_STK_UP_IRQ_LOG \ + 0x0000002C // Reading this register Stack + // procesor will able to know the + // reason for the interrupt. This is + // clear only register - set by HW + // upon an interrupt to Stack + // processor and can be cleared only + // by Stack processor. + +#define STACK_DIE_CTRL_O_STK_CLK_EN \ + 0x00000030 // Can be written only by base + // processor. Controls the enable + // pin of the cgcs for the clocks + // going to CM3 dft ctrl block and + // Sram. + +#define STACK_DIE_CTRL_O_SPIN_LOCK_MODE \ + 0x00000034 // Can be written only by the base + // processor. Decides the ram + // sharing mode :: handshake or + // Spinlock mode. + +#define STACK_DIE_CTRL_O_BUS_FAULT_ADDR \ + 0x00000038 // Stores the last bus fault + // address. + +#define STACK_DIE_CTRL_O_BUS_FAULT_CLR \ + 0x0000003C // write only registers on read + // returns 0.W Write 1 to clear the + // bust fault to store the new bus + // fault address + +#define STACK_DIE_CTRL_O_RESET_CAUSE \ + 0x00000040 // Reset cause value captured from + // the ICR_CLKRST block. + +#define STACK_DIE_CTRL_O_WDOG_TIMER_EVENT \ + 0x00000044 // Watchdog timer event value + // captured from the ICR_CLKRST + // block + +#define STACK_DIE_CTRL_O_DMA_REQ \ + 0x00000048 // To send Dma Request to bottom + // die. + +#define STACK_DIE_CTRL_O_SRAM_JUMP_OFFSET_ADDR \ + 0x0000004C // Address offset within SRAM to + // which CM3 should jump after + // reset. + +#define STACK_DIE_CTRL_O_SW_REG1 \ + 0x00000050 // These are sw registers for + // topdie processor and bottom die + // processor to communicate. Both + // can set and read these registers. + // In case of write clash bottom + // die's processor wins and top die + // processor access is ignored. + +#define STACK_DIE_CTRL_O_SW_REG2 \ + 0x00000054 // These are sw registers for + // topdie processor and bottom die + // processor to communicate. Both + // can set and read these registers. + // In case of write clash bottom + // die's processor wins and top die + // processor access is ignored. + +#define STACK_DIE_CTRL_O_FMC_SLEEP_CTL \ + 0x00000058 // By posting the request Flash can + // be put into low-power mode + // (Sleep) without powering down the + // Flash. Earlier (in Garnet) this + // was fully h/w controlled and the + // control for this was coming from + // SysCtl while entering into Cortex + // Deep-sleep mode. But for our + // device the D2D i/f doesnt support + // this. The Firmware has to program + // the register in the top-die for + // entering into this mode and wait + // for an interrupt. + +#define STACK_DIE_CTRL_O_MISC_CTL \ + 0x0000005C // Miscellanious control register. + +#define STACK_DIE_CTRL_O_SW_DFT_CTL \ + 0x000000FC // DFT control and status bits + +#define STACK_DIE_CTRL_O_PADN_CTL_0 \ + 0x00000100 // Mainly for For controlling the + // pads OEN pins. There are total 60 + // pads and hence 60 control registe + // i.e n value varies from 0 to 59. + // Here is the mapping for the + // pad_ctl register number and the + // functionality : 0 D2DPAD_DMAREQ1 + // 1 D2DPAD_DMAREQ0 2 + // D2DPAD_INT2BASE 3 D2DPAD_PIOSC 4 + // D2DPAD_RST_N 5 D2DPAD_POR_RST_N 6 + // D2DPAD_HCLK 7 D2DPAD_JTAG_TDO 8 + // D2DPAD_JTAG_TCK 9 D2DPAD_JTAG_TMS + // 10 D2DPAD_JTAG_TDI 11-27 + // D2DPAD_FROMSTACK[D2D_FROMSTACK_SIZE + // -1:0] 28-56 D2DPAD_TOSTACK + // [D2D_TOSTACK_SIZE -1:0] 57-59 + // D2DPAD_SPARE [D2D_SPARE_PAD_SIZE + // -1:0] 0:00 + + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_UP_RESET register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_UP_RESET_UP_RESET \ + 0x00000001 // 1 :Assert Reset 0 : Deassert the + // Reset + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SR_MASTER_PRIORITY register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SR_MASTER_PRIORITY_PRIORITY_M \ + 0x00000003 // 00 : Equal Priority 01 : Stack + // Processor have priority 10 : Base + // Processor have priority 11 : + // Unused + +#define STACK_DIE_CTRL_SR_MASTER_PRIORITY_PRIORITY_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_SR_ACC_CTL_BK2 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_SR_ACC_CTL_BK2_STK_UP_ACCSS \ + 0x00000002 // Stack Processor should clear it + // when it is done with the sram + // bank usage. Set by HW It is set + // when Stack Processor is granted + // the access to this bank + +#define STACK_DIE_CTRL_STK_SR_ACC_CTL_BK2_BASE_UP_ACCSS \ + 0x00000001 // Base Processor should clear it + // when it is done wth the sram + // usage. Set by HW It is set when + // Base Processor is granted the + // access to this bank + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_BASE_UP_ACC_REQ_BK2 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_BASE_UP_ACC_REQ_BK2_ACCSS_REQ \ + 0x00000001 // Base Processor will set when + // Sram access is needed in Spin + // Lock mode. In Handshake mode + // Stack Processor will set to + // inform Base Processor that it is + // done with the processing of data + // in SRAM and is now ready to use + // by the base processor. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_UP_ACC_REQ_BK2 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_UP_ACC_REQ_BK2_ACCSS_REQ \ + 0x00000001 // Stack Processor will set when + // Sram access is needed in Spin + // Lock mode. In Handshake mode Base + // Processor will set to inform + // Stack Processor to start + // processing the data in the Ram. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_SR_ACC_CTL_BK3 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_SR_ACC_CTL_BK3_STK_UP_ACCSS \ + 0x00000002 // Stack Processor should clear it + // when it is done with the sram + // bank usage. Set by HW It is set + // when Stack Processor is granted + // the access to this bank. + +#define STACK_DIE_CTRL_STK_SR_ACC_CTL_BK3_BASE_UP_ACCSS \ + 0x00000001 // Base Processor should clear it + // when it is done wth the sram + // usage. Set by HW it is set when + // Base Processor is granted the + // access to this bank. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_BASE_UP_ACC_REQ_BK3 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_BASE_UP_ACC_REQ_BK3_ACCSS_REQ \ + 0x00000001 // Base Processor will set when + // Sram access is needed in Spin + // Lock mode. Not used in handshake + // mode. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_UP_ACC_REQ_BK3 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_UP_ACC_REQ_BK3_ACCSS_REQ \ + 0x00000001 // Stack Processor will set when + // Sram access is needed in Spin + // Lock mode. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_RDSM_CFG_CPU register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_RDSM_CFG_CPU_FLCLK_PULSE_WIDTH_M \ + 0x000000C0 // Bank Clock Hi Time 00 : HCLK + // pulse 01 : 1 cycle of HCLK 10 : + // 1.5 cycles of HCLK 11 : 2 cycles + // of HCLK + +#define STACK_DIE_CTRL_RDSM_CFG_CPU_FLCLK_PULSE_WIDTH_S 6 +#define STACK_DIE_CTRL_RDSM_CFG_CPU_FLCLK_SENSE \ + 0x00000020 // FLCLK 0 : indicates flash clock + // rise aligns on HCLK rise 1 : + // indicates flash clock rise aligns + // on HCLK fall + +#define STACK_DIE_CTRL_RDSM_CFG_CPU_PIPELINE_FLDATA \ + 0x00000010 // 0 : Always register flash rdata + // before sending to CPU 1 : Drive + // Flash rdata directly out on MISS + // (Both ICODE / DCODE) + +#define STACK_DIE_CTRL_RDSM_CFG_CPU_READ_WAIT_STATE_M \ + 0x0000000F // Number of wait states inserted + +#define STACK_DIE_CTRL_RDSM_CFG_CPU_READ_WAIT_STATE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_RDSM_CFG_EE register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_RDSM_CFG_EE_FLCLK_PULSE_WIDTH_M \ + 0x000000C0 // Bank Clock Hi Time 00 : HCLK + // pulse 01 : 1 cycle of HCLK 10 : + // 1.5 cycles of HCLK 11 : 2 cycles + // of HCLK + +#define STACK_DIE_CTRL_RDSM_CFG_EE_FLCLK_PULSE_WIDTH_S 6 +#define STACK_DIE_CTRL_RDSM_CFG_EE_FLCLK_SENSE \ + 0x00000020 // FLCLK 0 : indicates flash clock + // rise aligns on HCLK rise 1 : + // indicates flash clock rise aligns + // on HCLK fall + +#define STACK_DIE_CTRL_RDSM_CFG_EE_PIPELINE_FLDATA \ + 0x00000010 // 0 : Always register flash rdata + // before sending to CPU 1 : Drive + // Flash rdata directly out on MISS + // (Both ICODE / DCODE) + +#define STACK_DIE_CTRL_RDSM_CFG_EE_READ_WAIT_STATE_M \ + 0x0000000F // Number of wait states inserted + +#define STACK_DIE_CTRL_RDSM_CFG_EE_READ_WAIT_STATE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_BASE_UP_IRQ_LOG register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_BASE_UP_IRQ_LOG_SR_BK3_REL \ + 0x00000010 // Set when Relinquish Interrupt + // sent to Base processor for Bank3. + +#define STACK_DIE_CTRL_BASE_UP_IRQ_LOG_SR_BK2_RELEASE \ + 0x00000008 // Set when Relinquish Interrupt + // sent to Base processor for Bank2. + +#define STACK_DIE_CTRL_BASE_UP_IRQ_LOG_SR_BK3_GRANT \ + 0x00000004 // Set when Bank3 is granted to + // Base processor. + +#define STACK_DIE_CTRL_BASE_UP_IRQ_LOG_SR_BK2_GRANT \ + 0x00000002 // Set when Bank2 is granted to + // BAse processor. + +#define STACK_DIE_CTRL_BASE_UP_IRQ_LOG_SR_INVAL_ACCSS \ + 0x00000001 // Set when there Base processor do + // an Invalid access to Sram. Ex : + // Accessing the bank which is not + // granted for BAse processor. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_UP_IRQ_LOG register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_UP_IRQ_LOG_SR_BK3_REL \ + 0x00000008 // Set when Relinquish Interrupt + // sent to Stack processor for + // Bank3. + +#define STACK_DIE_CTRL_STK_UP_IRQ_LOG_SR_BK2_REL \ + 0x00000004 // Set when Relinquish Interrupt + // sent to Stack processor for + // Bank2. + +#define STACK_DIE_CTRL_STK_UP_IRQ_LOG_SR_BK3_GRANT \ + 0x00000002 // Set when Bank3 is granted to + // Stack processor. + +#define STACK_DIE_CTRL_STK_UP_IRQ_LOG_SR_BK2_GRANT \ + 0x00000001 // Set when Bank2 is granted to + // Stack processor. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_STK_CLK_EN register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_STK_CLK_EN_SR_CLK \ + 0x00000004 // Enable the clock going to sram. + +#define STACK_DIE_CTRL_STK_CLK_EN_DFT_CTRL_CLK \ + 0x00000002 // Enable the clock going to dft + // control block + +#define STACK_DIE_CTRL_STK_CLK_EN_STK_UP_CLK \ + 0x00000001 // Enable the clock going to Cm3 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SPIN_LOCK_MODE register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SPIN_LOCK_MODE_MODE \ + 0x00000001 // 0 : Handshake Mode 1 : Spinlock + // mode. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_BUS_FAULT_ADDR register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_BUS_FAULT_ADDR_ADDRESS_M \ + 0xFFFFFFFF // Fault Address + +#define STACK_DIE_CTRL_BUS_FAULT_ADDR_ADDRESS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_BUS_FAULT_CLR register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_BUS_FAULT_CLR_CLEAR \ + 0x00000001 // When set it'll clear the bust + // fault address register to store + // the new bus fault address + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_RESET_CAUSE register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_RESET_CAUSE_RST_CAUSE_M \ + 0xFFFFFFFF + +#define STACK_DIE_CTRL_RESET_CAUSE_RST_CAUSE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_WDOG_TIMER_EVENT register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_WDOG_TIMER_EVENT_WDOG_TMR_EVNT_M \ + 0xFFFFFFFF + +#define STACK_DIE_CTRL_WDOG_TIMER_EVENT_WDOG_TMR_EVNT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_DMA_REQ register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_DMA_REQ_DMAREQ1 \ + 0x00000002 // Generate DMAREQ1 on setting this + // bit. + +#define STACK_DIE_CTRL_DMA_REQ_DMAREQ0 \ + 0x00000001 // Generate DMAREQ0 on setting this + // bit. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SRAM_JUMP_OFFSET_ADDR register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SRAM_JUMP_OFFSET_ADDR_ADDR_M \ + 0xFFFFFFFF + +#define STACK_DIE_CTRL_SRAM_JUMP_OFFSET_ADDR_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SW_REG1 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SW_REG1_NEWBITFIELD1_M \ + 0xFFFFFFFF + +#define STACK_DIE_CTRL_SW_REG1_NEWBITFIELD1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SW_REG2 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SW_REG2_NEWBITFIELD1_M \ + 0xFFFFFFFF + +#define STACK_DIE_CTRL_SW_REG2_NEWBITFIELD1_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_FMC_SLEEP_CTL register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_FMC_SLEEP_CTL_FMC_LPM_ACK \ + 0x00000002 // captures the status of of + // fmc_lpm_ack + +#define STACK_DIE_CTRL_FMC_SLEEP_CTL_FMC_LPM_REQ \ + 0x00000001 // When set assert + // iflpe2fmc_lpm_req to FMC. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_MISC_CTL register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_MISC_CTL_WDOG_RESET \ + 0x00000080 // 1 : will reset the async wdog + // timer runing on piosc clock + +#define STACK_DIE_CTRL_MISC_CTL_FW_IRQ2 \ + 0x00000020 // Setting this Will send to + // interttupt to CM3 + +#define STACK_DIE_CTRL_MISC_CTL_FW_IRQ1 \ + 0x00000010 // Setting this Will send to + // interttupt to CM3 + +#define STACK_DIE_CTRL_MISC_CTL_FW_IRQ0 \ + 0x00000008 // Setting this Will send to + // interttupt to CM3 + +#define STACK_DIE_CTRL_MISC_CTL_FLB_TEST_MUX_CTL_BK3 \ + 0x00000004 // While testing Flash Setting this + // bit will Control the + // CE/STR/AIN/CLKIN going to flash + // banks 12 and 3. 0 : Control + // signals coming from FMC for Bank + // 3 goes to Bank3 1 : Control + // signals coming from FMC for Bank + // 0 goes to Bank2 + +#define STACK_DIE_CTRL_MISC_CTL_FLB_TEST_MUX_CTL_BK2 \ + 0x00000002 // While testing Flash Setting this + // bit will Control the + // CE/STR/AIN/CLKIN going to flash + // banks 12 and 3. 0 : Control + // signals coming from FMC for Bank + // 2 goes to Bank2 1 : Control + // signals coming from FMC for Bank + // 0 goes to Bank2 + +#define STACK_DIE_CTRL_MISC_CTL_FLB_TEST_MUX_CTL_BK1 \ + 0x00000001 // While testing Flash Setting this + // bit will Control the + // CE/STR/AIN/CLKIN going to flash + // banks 12 and 3. 0 : Control + // signals coming from FMC for Bank + // 1 goes to Bank1 1 : Control + // signals coming from FMC for Bank + // 0 goes to Bank1 + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_SW_DFT_CTL register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_SW_DFT_CTL_FL_CTRL_OWNS \ + 0x20000000 // when set to '1' all flash + // control signals switch over to + // CM3 control when '0' it is under + // the D2D interface control + +#define STACK_DIE_CTRL_SW_DFT_CTL_SWIF_CPU_READ \ + 0x10000000 // 1 indicates in SWIF mode the + // control signals to flash are from + // FMC CPU read controls the clock + // and address. that is one can give + // address via FMC and read through + // IDMEM. + +#define STACK_DIE_CTRL_SW_DFT_CTL_CPU_DONE \ + 0x00800000 // 'CPU Done' bit for PBIST. Write + // '1' to indicate test done. + +#define STACK_DIE_CTRL_SW_DFT_CTL_CPU_FAIL \ + 0x00400000 // 'CPU Fail' bit for PBIST. Write + // '1' to indicate test failed. + +#define STACK_DIE_CTRL_SW_DFT_CTL_FLBK4_OWNS \ + 0x00001000 // when set to '1' flash bank 4 + // (EEPROM) is owned by the CM3for + // reads over DCODE bus. When '0' + // access control given to D2D + // interface. + +#define STACK_DIE_CTRL_SW_DFT_CTL_FLBK3_OWNS \ + 0x00000800 // when set to '1' flash bank 3 is + // owned by the CM3for reads over + // DCODE bus. When '0' access + // control given to D2D interface. + +#define STACK_DIE_CTRL_SW_DFT_CTL_FLBK2_OWNS \ + 0x00000400 // when set to '1' flash bank 2 is + // owned by the CM3for reads over + // DCODE bus. When '0' access + // control given to D2D interface. + +#define STACK_DIE_CTRL_SW_DFT_CTL_FLBK1_OWNS \ + 0x00000200 // when set to '1' flash bank 1 is + // owned by the CM3for reads over + // DCODE bus. When '0' access + // control given to D2D interface. + +#define STACK_DIE_CTRL_SW_DFT_CTL_FLBK0_OWNS \ + 0x00000100 // when set to '1' flash bank 0 is + // owned by the CM3 for reads over + // DCODE bus. When '0' access + // control given to D2D interface. + +//****************************************************************************** +// +// The following are defines for the bit fields in the +// STACK_DIE_CTRL_O_PADN_CTL_0 register. +// +//****************************************************************************** +#define STACK_DIE_CTRL_PADN_CTL_0_SPARE_PAD_DOUT \ + 0x00000008 // This bit is valid for only the + // spare pads ie for n=57 to 59. + // value to drive at the output of + // the pad + +#define STACK_DIE_CTRL_PADN_CTL_0_SPARE_PAD_DIN \ + 0x00000004 // This bit is valid for only the + // spare pads ie for n=57 to 59. + // captures the 'Y' pin of the pad + // which is the data being driven + // into the die + +#define STACK_DIE_CTRL_PADN_CTL_0_OEN2X \ + 0x00000002 // OEN2X control when '1' enables + // the output with 1x. Total drive + // strength is decided bu oen1x + // setting + oen2x setting. + +#define STACK_DIE_CTRL_PADN_CTL_0_OEN1X \ + 0x00000001 // OEN1X control when '1' enables + // the output with 1x . Total drive + // strength is decided bu oen1x + // setting + oen2x setting. + + + + +#endif // __HW_STACK_DIE_CTRL_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_timer.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_timer.h new file mode 100755 index 0000000..b6844ec --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_timer.h @@ -0,0 +1,778 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +// hw_timer.h - Defines and macros used when accessing the timer. +// +//***************************************************************************** + +//##### INTERNAL BEGIN ##### +// +// This is an auto-generated file. Do not edit by hand. +// Created by version 6779 of DriverLib. +// +//##### INTERNAL END ##### + +#ifndef __HW_TIMER_H__ +#define __HW_TIMER_H__ + +//***************************************************************************** +// +// The following are defines for the Timer register offsets. +// +//***************************************************************************** +#define TIMER_O_CFG 0x00000000 // GPTM Configuration +#define TIMER_O_TAMR 0x00000004 // GPTM Timer A Mode +#define TIMER_O_TBMR 0x00000008 // GPTM Timer B Mode +#define TIMER_O_CTL 0x0000000C // GPTM Control +//##### GARNET BEGIN ##### +#define TIMER_O_SYNC 0x00000010 // GPTM Synchronize +//##### GARNET END ##### +#define TIMER_O_IMR 0x00000018 // GPTM Interrupt Mask +#define TIMER_O_RIS 0x0000001C // GPTM Raw Interrupt Status +#define TIMER_O_MIS 0x00000020 // GPTM Masked Interrupt Status +#define TIMER_O_ICR 0x00000024 // GPTM Interrupt Clear +#define TIMER_O_TAILR 0x00000028 // GPTM Timer A Interval Load +#define TIMER_O_TBILR 0x0000002C // GPTM Timer B Interval Load +#define TIMER_O_TAMATCHR 0x00000030 // GPTM Timer A Match +#define TIMER_O_TBMATCHR 0x00000034 // GPTM Timer B Match +#define TIMER_O_TAPR 0x00000038 // GPTM Timer A Prescale +#define TIMER_O_TBPR 0x0000003C // GPTM Timer B Prescale +#define TIMER_O_TAPMR 0x00000040 // GPTM TimerA Prescale Match +#define TIMER_O_TBPMR 0x00000044 // GPTM TimerB Prescale Match +#define TIMER_O_TAR 0x00000048 // GPTM Timer A +#define TIMER_O_TBR 0x0000004C // GPTM Timer B +#define TIMER_O_TAV 0x00000050 // GPTM Timer A Value +#define TIMER_O_TBV 0x00000054 // GPTM Timer B Value +#define TIMER_O_RTCPD 0x00000058 // GPTM RTC Predivide +#define TIMER_O_TAPS 0x0000005C // GPTM Timer A Prescale Snapshot +#define TIMER_O_TBPS 0x00000060 // GPTM Timer B Prescale Snapshot +#define TIMER_O_TAPV 0x00000064 // GPTM Timer A Prescale Value +#define TIMER_O_TBPV 0x00000068 // GPTM Timer B Prescale Value +#define TIMER_O_DMAEV 0x0000006C // GPTM DMA Event +#define TIMER_O_PP 0x00000FC0 // GPTM Peripheral Properties + + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_CFG register. +// +//***************************************************************************** +#define TIMER_CFG_M 0x00000007 // GPTM Configuration +#define TIMER_CFG_32_BIT_TIMER 0x00000000 // 32-bit timer configuration +#define TIMER_CFG_32_BIT_RTC 0x00000001 // 32-bit real-time clock (RTC) + // counter configuration +#define TIMER_CFG_16_BIT 0x00000004 // 16-bit timer configuration. The + // function is controlled by bits + // 1:0 of GPTMTAMR and GPTMTBMR + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAMR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAMR_TAPLO 0x00000800 // GPTM Timer A PWM Legacy + // Operation +#define TIMER_TAMR_TAMRSU 0x00000400 // GPTM Timer A Match Register + // Update +#define TIMER_TAMR_TAPWMIE 0x00000200 // GPTM Timer A PWM Interrupt + // Enable +#define TIMER_TAMR_TAILD 0x00000100 // GPTM Timer A Interval Load Write +//##### GARNET END ##### +#define TIMER_TAMR_TASNAPS 0x00000080 // GPTM Timer A Snap-Shot Mode +#define TIMER_TAMR_TAWOT 0x00000040 // GPTM Timer A Wait-on-Trigger +#define TIMER_TAMR_TAMIE 0x00000020 // GPTM Timer A Match Interrupt + // Enable +#define TIMER_TAMR_TACDIR 0x00000010 // GPTM Timer A Count Direction +#define TIMER_TAMR_TAAMS 0x00000008 // GPTM Timer A Alternate Mode + // Select +#define TIMER_TAMR_TACMR 0x00000004 // GPTM Timer A Capture Mode +#define TIMER_TAMR_TAMR_M 0x00000003 // GPTM Timer A Mode +#define TIMER_TAMR_TAMR_1_SHOT 0x00000001 // One-Shot Timer mode +#define TIMER_TAMR_TAMR_PERIOD 0x00000002 // Periodic Timer mode +#define TIMER_TAMR_TAMR_CAP 0x00000003 // Capture mode + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBMR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBMR_TBPLO 0x00000800 // GPTM Timer B PWM Legacy + // Operation +#define TIMER_TBMR_TBMRSU 0x00000400 // GPTM Timer B Match Register + // Update +#define TIMER_TBMR_TBPWMIE 0x00000200 // GPTM Timer B PWM Interrupt + // Enable +#define TIMER_TBMR_TBILD 0x00000100 // GPTM Timer B Interval Load Write +//##### GARNET END ##### +#define TIMER_TBMR_TBSNAPS 0x00000080 // GPTM Timer B Snap-Shot Mode +#define TIMER_TBMR_TBWOT 0x00000040 // GPTM Timer B Wait-on-Trigger +#define TIMER_TBMR_TBMIE 0x00000020 // GPTM Timer B Match Interrupt + // Enable +#define TIMER_TBMR_TBCDIR 0x00000010 // GPTM Timer B Count Direction +#define TIMER_TBMR_TBAMS 0x00000008 // GPTM Timer B Alternate Mode + // Select +#define TIMER_TBMR_TBCMR 0x00000004 // GPTM Timer B Capture Mode +#define TIMER_TBMR_TBMR_M 0x00000003 // GPTM Timer B Mode +#define TIMER_TBMR_TBMR_1_SHOT 0x00000001 // One-Shot Timer mode +#define TIMER_TBMR_TBMR_PERIOD 0x00000002 // Periodic Timer mode +#define TIMER_TBMR_TBMR_CAP 0x00000003 // Capture mode + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_CTL register. +// +//***************************************************************************** +#define TIMER_CTL_TBPWML 0x00004000 // GPTM Timer B PWM Output Level +#define TIMER_CTL_TBOTE 0x00002000 // GPTM Timer B Output Trigger + // Enable +#define TIMER_CTL_TBEVENT_M 0x00000C00 // GPTM Timer B Event Mode +#define TIMER_CTL_TBEVENT_POS 0x00000000 // Positive edge +#define TIMER_CTL_TBEVENT_NEG 0x00000400 // Negative edge +#define TIMER_CTL_TBEVENT_BOTH 0x00000C00 // Both edges +#define TIMER_CTL_TBSTALL 0x00000200 // GPTM Timer B Stall Enable +#define TIMER_CTL_TBEN 0x00000100 // GPTM Timer B Enable +#define TIMER_CTL_TAPWML 0x00000040 // GPTM Timer A PWM Output Level +#define TIMER_CTL_TAOTE 0x00000020 // GPTM Timer A Output Trigger + // Enable +#define TIMER_CTL_RTCEN 0x00000010 // GPTM RTC Enable +#define TIMER_CTL_TAEVENT_M 0x0000000C // GPTM Timer A Event Mode +#define TIMER_CTL_TAEVENT_POS 0x00000000 // Positive edge +#define TIMER_CTL_TAEVENT_NEG 0x00000004 // Negative edge +#define TIMER_CTL_TAEVENT_BOTH 0x0000000C // Both edges +#define TIMER_CTL_TASTALL 0x00000002 // GPTM Timer A Stall Enable +#define TIMER_CTL_TAEN 0x00000001 // GPTM Timer A Enable +//##### GARNET BEGIN ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_SYNC register. +// +//***************************************************************************** +#define TIMER_SYNC_SYNC11_M 0x00C00000 // Synchronize GPTM Timer 11 +#define TIMER_SYNC_SYNC11_TA 0x00400000 // A timeout event for Timer A of + // GPTM11 is triggered +#define TIMER_SYNC_SYNC11_TB 0x00800000 // A timeout event for Timer B of + // GPTM11 is triggered +#define TIMER_SYNC_SYNC11_TATB 0x00C00000 // A timeout event for both Timer A + // and Timer B of GPTM11 is + // triggered +#define TIMER_SYNC_SYNC10_M 0x00300000 // Synchronize GPTM Timer 10 +#define TIMER_SYNC_SYNC10_TA 0x00100000 // A timeout event for Timer A of + // GPTM10 is triggered +#define TIMER_SYNC_SYNC10_TB 0x00200000 // A timeout event for Timer B of + // GPTM10 is triggered +#define TIMER_SYNC_SYNC10_TATB 0x00300000 // A timeout event for both Timer A + // and Timer B of GPTM10 is + // triggered +#define TIMER_SYNC_SYNC9_M 0x000C0000 // Synchronize GPTM Timer 9 +#define TIMER_SYNC_SYNC9_TA 0x00040000 // A timeout event for Timer A of + // GPTM9 is triggered +#define TIMER_SYNC_SYNC9_TB 0x00080000 // A timeout event for Timer B of + // GPTM9 is triggered +#define TIMER_SYNC_SYNC9_TATB 0x000C0000 // A timeout event for both Timer A + // and Timer B of GPTM9 is + // triggered +#define TIMER_SYNC_SYNC8_M 0x00030000 // Synchronize GPTM Timer 8 +#define TIMER_SYNC_SYNC8_TA 0x00010000 // A timeout event for Timer A of + // GPTM8 is triggered +#define TIMER_SYNC_SYNC8_TB 0x00020000 // A timeout event for Timer B of + // GPTM8 is triggered +#define TIMER_SYNC_SYNC8_TATB 0x00030000 // A timeout event for both Timer A + // and Timer B of GPTM8 is + // triggered +#define TIMER_SYNC_SYNC7_M 0x0000C000 // Synchronize GPTM Timer 7 +#define TIMER_SYNC_SYNC7_TA 0x00004000 // A timeout event for Timer A of + // GPTM7 is triggered +#define TIMER_SYNC_SYNC7_TB 0x00008000 // A timeout event for Timer B of + // GPTM7 is triggered +#define TIMER_SYNC_SYNC7_TATB 0x0000C000 // A timeout event for both Timer A + // and Timer B of GPTM7 is + // triggered +#define TIMER_SYNC_SYNC6_M 0x00003000 // Synchronize GPTM Timer 6 +#define TIMER_SYNC_SYNC6_TA 0x00001000 // A timeout event for Timer A of + // GPTM6 is triggered +#define TIMER_SYNC_SYNC6_TB 0x00002000 // A timeout event for Timer B of + // GPTM6 is triggered +#define TIMER_SYNC_SYNC6_TATB 0x00003000 // A timeout event for both Timer A + // and Timer B of GPTM6 is + // triggered +#define TIMER_SYNC_SYNC5_M 0x00000C00 // Synchronize GPTM Timer 5 +#define TIMER_SYNC_SYNC5_TA 0x00000400 // A timeout event for Timer A of + // GPTM5 is triggered +#define TIMER_SYNC_SYNC5_TB 0x00000800 // A timeout event for Timer B of + // GPTM5 is triggered +#define TIMER_SYNC_SYNC5_TATB 0x00000C00 // A timeout event for both Timer A + // and Timer B of GPTM5 is + // triggered +#define TIMER_SYNC_SYNC4_M 0x00000300 // Synchronize GPTM Timer 4 +#define TIMER_SYNC_SYNC4_TA 0x00000100 // A timeout event for Timer A of + // GPTM4 is triggered +#define TIMER_SYNC_SYNC4_TB 0x00000200 // A timeout event for Timer B of + // GPTM4 is triggered +#define TIMER_SYNC_SYNC4_TATB 0x00000300 // A timeout event for both Timer A + // and Timer B of GPTM4 is + // triggered +#define TIMER_SYNC_SYNC3_M 0x000000C0 // Synchronize GPTM Timer 3 +#define TIMER_SYNC_SYNC3_TA 0x00000040 // A timeout event for Timer A of + // GPTM3 is triggered +#define TIMER_SYNC_SYNC3_TB 0x00000080 // A timeout event for Timer B of + // GPTM3 is triggered +#define TIMER_SYNC_SYNC3_TATB 0x000000C0 // A timeout event for both Timer A + // and Timer B of GPTM3 is + // triggered +#define TIMER_SYNC_SYNC2_M 0x00000030 // Synchronize GPTM Timer 2 +#define TIMER_SYNC_SYNC2_TA 0x00000010 // A timeout event for Timer A of + // GPTM2 is triggered +#define TIMER_SYNC_SYNC2_TB 0x00000020 // A timeout event for Timer B of + // GPTM2 is triggered +#define TIMER_SYNC_SYNC2_TATB 0x00000030 // A timeout event for both Timer A + // and Timer B of GPTM2 is + // triggered +#define TIMER_SYNC_SYNC1_M 0x0000000C // Synchronize GPTM Timer 1 +#define TIMER_SYNC_SYNC1_TA 0x00000004 // A timeout event for Timer A of + // GPTM1 is triggered +#define TIMER_SYNC_SYNC1_TB 0x00000008 // A timeout event for Timer B of + // GPTM1 is triggered +#define TIMER_SYNC_SYNC1_TATB 0x0000000C // A timeout event for both Timer A + // and Timer B of GPTM1 is + // triggered +#define TIMER_SYNC_SYNC0_M 0x00000003 // Synchronize GPTM Timer 0 +#define TIMER_SYNC_SYNC0_TA 0x00000001 // A timeout event for Timer A of + // GPTM0 is triggered +#define TIMER_SYNC_SYNC0_TB 0x00000002 // A timeout event for Timer B of + // GPTM0 is triggered +#define TIMER_SYNC_SYNC0_TATB 0x00000003 // A timeout event for both Timer A + // and Timer B of GPTM0 is + // triggered +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_IMR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_IMR_WUEIM 0x00010000 // 32/64-Bit GPTM Write Update + // Error Interrupt Mask +//##### GARNET END ##### +#define TIMER_IMR_TBMIM 0x00000800 // GPTM Timer B Mode Match + // Interrupt Mask +#define TIMER_IMR_CBEIM 0x00000400 // GPTM Capture B Event Interrupt + // Mask +#define TIMER_IMR_CBMIM 0x00000200 // GPTM Capture B Match Interrupt + // Mask +#define TIMER_IMR_TBTOIM 0x00000100 // GPTM Timer B Time-Out Interrupt + // Mask +#define TIMER_IMR_TAMIM 0x00000010 // GPTM Timer A Mode Match + // Interrupt Mask +#define TIMER_IMR_RTCIM 0x00000008 // GPTM RTC Interrupt Mask +#define TIMER_IMR_CAEIM 0x00000004 // GPTM Capture A Event Interrupt + // Mask +#define TIMER_IMR_CAMIM 0x00000002 // GPTM Capture A Match Interrupt + // Mask +#define TIMER_IMR_TATOIM 0x00000001 // GPTM Timer A Time-Out Interrupt + // Mask + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_RIS register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_RIS_WUERIS 0x00010000 // 32/64-Bit GPTM Write Update + // Error Raw Interrupt Status +//##### GARNET END ##### +#define TIMER_RIS_TBMRIS 0x00000800 // GPTM Timer B Mode Match Raw + // Interrupt +#define TIMER_RIS_CBERIS 0x00000400 // GPTM Capture B Event Raw + // Interrupt +#define TIMER_RIS_CBMRIS 0x00000200 // GPTM Capture B Match Raw + // Interrupt +#define TIMER_RIS_TBTORIS 0x00000100 // GPTM Timer B Time-Out Raw + // Interrupt +#define TIMER_RIS_TAMRIS 0x00000010 // GPTM Timer A Mode Match Raw + // Interrupt +#define TIMER_RIS_RTCRIS 0x00000008 // GPTM RTC Raw Interrupt +#define TIMER_RIS_CAERIS 0x00000004 // GPTM Capture A Event Raw + // Interrupt +#define TIMER_RIS_CAMRIS 0x00000002 // GPTM Capture A Match Raw + // Interrupt +#define TIMER_RIS_TATORIS 0x00000001 // GPTM Timer A Time-Out Raw + // Interrupt + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_MIS register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_MIS_WUEMIS 0x00010000 // 32/64-Bit GPTM Write Update + // Error Masked Interrupt Status +//##### GARNET END ##### +#define TIMER_MIS_TBMMIS 0x00000800 // GPTM Timer B Mode Match Masked + // Interrupt +#define TIMER_MIS_CBEMIS 0x00000400 // GPTM Capture B Event Masked + // Interrupt +#define TIMER_MIS_CBMMIS 0x00000200 // GPTM Capture B Match Masked + // Interrupt +#define TIMER_MIS_TBTOMIS 0x00000100 // GPTM Timer B Time-Out Masked + // Interrupt +#define TIMER_MIS_TAMMIS 0x00000010 // GPTM Timer A Mode Match Masked + // Interrupt +#define TIMER_MIS_RTCMIS 0x00000008 // GPTM RTC Masked Interrupt +#define TIMER_MIS_CAEMIS 0x00000004 // GPTM Capture A Event Masked + // Interrupt +#define TIMER_MIS_CAMMIS 0x00000002 // GPTM Capture A Match Masked + // Interrupt +#define TIMER_MIS_TATOMIS 0x00000001 // GPTM Timer A Time-Out Masked + // Interrupt + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_ICR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_ICR_WUECINT 0x00010000 // 32/64-Bit GPTM Write Update + // Error Interrupt Clear +//##### GARNET END ##### +#define TIMER_ICR_TBMCINT 0x00000800 // GPTM Timer B Mode Match + // Interrupt Clear +#define TIMER_ICR_CBECINT 0x00000400 // GPTM Capture B Event Interrupt + // Clear +#define TIMER_ICR_CBMCINT 0x00000200 // GPTM Capture B Match Interrupt + // Clear +#define TIMER_ICR_TBTOCINT 0x00000100 // GPTM Timer B Time-Out Interrupt + // Clear +#define TIMER_ICR_TAMCINT 0x00000010 // GPTM Timer A Mode Match + // Interrupt Clear +#define TIMER_ICR_RTCCINT 0x00000008 // GPTM RTC Interrupt Clear +#define TIMER_ICR_CAECINT 0x00000004 // GPTM Capture A Event Interrupt + // Clear +#define TIMER_ICR_CAMCINT 0x00000002 // GPTM Capture A Match Interrupt + // Clear +#define TIMER_ICR_TATOCINT 0x00000001 // GPTM Timer A Time-Out Raw + // Interrupt + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAILR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAILR_M 0xFFFFFFFF // GPTM Timer A Interval Load + // Register +//##### GARNET END ##### +#define TIMER_TAILR_TAILRH_M 0xFFFF0000 // GPTM Timer A Interval Load + // Register High +#define TIMER_TAILR_TAILRL_M 0x0000FFFF // GPTM Timer A Interval Load + // Register Low +#define TIMER_TAILR_TAILRH_S 16 +#define TIMER_TAILR_TAILRL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TAILR_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBILR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBILR_M 0xFFFFFFFF // GPTM Timer B Interval Load + // Register +//##### GARNET END ##### +#define TIMER_TBILR_TBILRL_M 0x0000FFFF // GPTM Timer B Interval Load + // Register +#define TIMER_TBILR_TBILRL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TBILR_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAMATCHR +// register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAMATCHR_TAMR_M 0xFFFFFFFF // GPTM Timer A Match Register +//##### GARNET END ##### +#define TIMER_TAMATCHR_TAMRH_M 0xFFFF0000 // GPTM Timer A Match Register High +#define TIMER_TAMATCHR_TAMRL_M 0x0000FFFF // GPTM Timer A Match Register Low +#define TIMER_TAMATCHR_TAMRH_S 16 +#define TIMER_TAMATCHR_TAMRL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TAMATCHR_TAMR_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBMATCHR +// register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBMATCHR_TBMR_M 0xFFFFFFFF // GPTM Timer B Match Register +//##### GARNET END ##### +#define TIMER_TBMATCHR_TBMRL_M 0x0000FFFF // GPTM Timer B Match Register Low +//##### GARNET BEGIN ##### +#define TIMER_TBMATCHR_TBMR_S 0 +//##### GARNET END ##### +#define TIMER_TBMATCHR_TBMRL_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAPR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAPR_TAPSRH_M 0x0000FF00 // GPTM Timer A Prescale High Byte +//##### GARNET END ##### +#define TIMER_TAPR_TAPSR_M 0x000000FF // GPTM Timer A Prescale +//##### GARNET BEGIN ##### +#define TIMER_TAPR_TAPSRH_S 8 +//##### GARNET END ##### +#define TIMER_TAPR_TAPSR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBPR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBPR_TBPSRH_M 0x0000FF00 // GPTM Timer B Prescale High Byte +//##### GARNET END ##### +#define TIMER_TBPR_TBPSR_M 0x000000FF // GPTM Timer B Prescale +//##### GARNET BEGIN ##### +#define TIMER_TBPR_TBPSRH_S 8 +//##### GARNET END ##### +#define TIMER_TBPR_TBPSR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAPMR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAPMR_TAPSMRH_M 0x0000FF00 // GPTM Timer A Prescale Match High + // Byte +//##### GARNET END ##### +#define TIMER_TAPMR_TAPSMR_M 0x000000FF // GPTM TimerA Prescale Match +//##### GARNET BEGIN ##### +#define TIMER_TAPMR_TAPSMRH_S 8 +//##### GARNET END ##### +#define TIMER_TAPMR_TAPSMR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBPMR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBPMR_TBPSMRH_M 0x0000FF00 // GPTM Timer B Prescale Match High + // Byte +//##### GARNET END ##### +#define TIMER_TBPMR_TBPSMR_M 0x000000FF // GPTM TimerB Prescale Match +//##### GARNET BEGIN ##### +#define TIMER_TBPMR_TBPSMRH_S 8 +//##### GARNET END ##### +#define TIMER_TBPMR_TBPSMR_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAR_M 0xFFFFFFFF // GPTM Timer A Register +//##### GARNET END ##### +#define TIMER_TAR_TARH_M 0xFFFF0000 // GPTM Timer A Register High +#define TIMER_TAR_TARL_M 0x0000FFFF // GPTM Timer A Register Low +#define TIMER_TAR_TARH_S 16 +#define TIMER_TAR_TARL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TAR_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBR register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBR_M 0xFFFFFFFF // GPTM Timer B Register +//##### GARNET END ##### +#define TIMER_TBR_TBRL_M 0x00FFFFFF // GPTM Timer B +#define TIMER_TBR_TBRL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TBR_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAV register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TAV_M 0xFFFFFFFF // GPTM Timer A Value +//##### GARNET END ##### +#define TIMER_TAV_TAVH_M 0xFFFF0000 // GPTM Timer A Value High +#define TIMER_TAV_TAVL_M 0x0000FFFF // GPTM Timer A Register Low +#define TIMER_TAV_TAVH_S 16 +#define TIMER_TAV_TAVL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TAV_S 0 +//##### GARNET END ##### + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBV register. +// +//***************************************************************************** +//##### GARNET BEGIN ##### +#define TIMER_TBV_M 0xFFFFFFFF // GPTM Timer B Value +//##### GARNET END ##### +#define TIMER_TBV_TBVL_M 0x0000FFFF // GPTM Timer B Register +#define TIMER_TBV_TBVL_S 0 +//##### GARNET BEGIN ##### +#define TIMER_TBV_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_RTCPD register. +// +//***************************************************************************** +#define TIMER_RTCPD_RTCPD_M 0x0000FFFF // RTC Predivide Counter Value +#define TIMER_RTCPD_RTCPD_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAPS register. +// +//***************************************************************************** +#define TIMER_TAPS_PSS_M 0x0000FFFF // GPTM Timer A Prescaler Snapshot +#define TIMER_TAPS_PSS_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBPS register. +// +//***************************************************************************** +#define TIMER_TBPS_PSS_M 0x0000FFFF // GPTM Timer A Prescaler Value +#define TIMER_TBPS_PSS_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TAPV register. +// +//***************************************************************************** +#define TIMER_TAPV_PSV_M 0x0000FFFF // GPTM Timer A Prescaler Value +#define TIMER_TAPV_PSV_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_TBPV register. +// +//***************************************************************************** +#define TIMER_TBPV_PSV_M 0x0000FFFF // GPTM Timer B Prescaler Value +#define TIMER_TBPV_PSV_S 0 + +//***************************************************************************** +// +// The following are defines for the bit fields in the TIMER_O_PP register. +// +//***************************************************************************** +#define TIMER_PP_SYNCCNT 0x00000020 // Synchronize Start +#define TIMER_PP_CHAIN 0x00000010 // Chain with Other Timers +#define TIMER_PP_SIZE_M 0x0000000F // Count Size +#define TIMER_PP_SIZE__0 0x00000000 // Timer A and Timer B counters are + // 16 bits each with an 8-bit + // prescale counter +#define TIMER_PP_SIZE__1 0x00000001 // Timer A and Timer B counters are + // 32 bits each with an 16-bit + // prescale counter +//##### GARNET END ##### + +//***************************************************************************** +// +// The following definitions are deprecated. +// +//***************************************************************************** +#ifndef DEPRECATED + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_CFG +// register. +// +//***************************************************************************** +#define TIMER_CFG_CFG_MSK 0x00000007 // Configuration options mask + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_CTL +// register. +// +//***************************************************************************** +#define TIMER_CTL_TBEVENT_MSK 0x00000C00 // TimerB event mode mask +#define TIMER_CTL_TAEVENT_MSK 0x0000000C // TimerA event mode mask + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_RIS +// register. +// +//***************************************************************************** +#define TIMER_RIS_CBEMIS 0x00000400 // CaptureB event masked int status +#define TIMER_RIS_CBMMIS 0x00000200 // CaptureB match masked int status +#define TIMER_RIS_TBTOMIS 0x00000100 // TimerB time out masked int stat +#define TIMER_RIS_RTCMIS 0x00000008 // RTC masked int status +#define TIMER_RIS_CAEMIS 0x00000004 // CaptureA event masked int status +#define TIMER_RIS_CAMMIS 0x00000002 // CaptureA match masked int status +#define TIMER_RIS_TATOMIS 0x00000001 // TimerA time out masked int stat + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_TAILR +// register. +// +//***************************************************************************** +#define TIMER_TAILR_TAILRH 0xFFFF0000 // TimerB load val in 32 bit mode +#define TIMER_TAILR_TAILRL 0x0000FFFF // TimerA interval load value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_TBILR +// register. +// +//***************************************************************************** +#define TIMER_TBILR_TBILRL 0x0000FFFF // TimerB interval load value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the +// TIMER_O_TAMATCHR register. +// +//***************************************************************************** +#define TIMER_TAMATCHR_TAMRH 0xFFFF0000 // TimerB match val in 32 bit mode +#define TIMER_TAMATCHR_TAMRL 0x0000FFFF // TimerA match value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the +// TIMER_O_TBMATCHR register. +// +//***************************************************************************** +#define TIMER_TBMATCHR_TBMRL 0x0000FFFF // TimerB match load value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_TAR +// register. +// +//***************************************************************************** +#define TIMER_TAR_TARH 0xFFFF0000 // TimerB val in 32 bit mode +#define TIMER_TAR_TARL 0x0000FFFF // TimerA value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_O_TBR +// register. +// +//***************************************************************************** +#define TIMER_TBR_TBRL 0x0000FFFF // TimerB value + +//***************************************************************************** +// +// The following are deprecated defines for the reset values of the timer +// registers. +// +//***************************************************************************** +#define TIMER_RV_TAILR 0xFFFFFFFF // TimerA interval load reg RV +#define TIMER_RV_TAR 0xFFFFFFFF // TimerA register RV +#define TIMER_RV_TAMATCHR 0xFFFFFFFF // TimerA match register RV +#define TIMER_RV_TBILR 0x0000FFFF // TimerB interval load reg RV +#define TIMER_RV_TBMATCHR 0x0000FFFF // TimerB match register RV +#define TIMER_RV_TBR 0x0000FFFF // TimerB register RV +#define TIMER_RV_TAPR 0x00000000 // TimerA prescale register RV +#define TIMER_RV_CFG 0x00000000 // Configuration register RV +#define TIMER_RV_TBPMR 0x00000000 // TimerB prescale match regi RV +#define TIMER_RV_TAPMR 0x00000000 // TimerA prescale match reg RV +#define TIMER_RV_CTL 0x00000000 // Control register RV +#define TIMER_RV_ICR 0x00000000 // Interrupt clear register RV +#define TIMER_RV_TBMR 0x00000000 // TimerB mode register RV +#define TIMER_RV_MIS 0x00000000 // Masked interrupt status reg RV +#define TIMER_RV_RIS 0x00000000 // Interrupt status register RV +#define TIMER_RV_TBPR 0x00000000 // TimerB prescale register RV +#define TIMER_RV_IMR 0x00000000 // Interrupt mask register RV +#define TIMER_RV_TAMR 0x00000000 // TimerA mode register RV + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_TnMR +// register. +// +//***************************************************************************** +#define TIMER_TNMR_TNAMS 0x00000008 // Alternate mode select +#define TIMER_TNMR_TNCMR 0x00000004 // Capture mode - count or time +#define TIMER_TNMR_TNTMR_MSK 0x00000003 // Timer mode mask +#define TIMER_TNMR_TNTMR_1_SHOT 0x00000001 // Mode - one shot +#define TIMER_TNMR_TNTMR_PERIOD 0x00000002 // Mode - periodic +#define TIMER_TNMR_TNTMR_CAP 0x00000003 // Mode - capture + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_TnPR +// register. +// +//***************************************************************************** +#define TIMER_TNPR_TNPSR 0x000000FF // TimerN prescale value + +//***************************************************************************** +// +// The following are deprecated defines for the bit fields in the TIMER_TnPMR +// register. +// +//***************************************************************************** +#define TIMER_TNPMR_TNPSMR 0x000000FF // TimerN prescale match value + +#endif + +#endif // __HW_TIMER_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_types.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_types.h new file mode 100755 index 0000000..d7a6ab4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_types.h @@ -0,0 +1,76 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_TYPES_H__ +#define __HW_TYPES_H__ + +//***************************************************************************** +// +// Define a boolean type, and values for true and false. +// +//***************************************************************************** +typedef unsigned char tBoolean; + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +//***************************************************************************** +// +// Macros for hardware access, both direct and via the bit-band region. +// +//***************************************************************************** +#define HWREG(x) \ + (*((volatile unsigned long *)(x))) +#define HWREGH(x) \ + (*((volatile unsigned short *)(x))) +#define HWREGB(x) \ + (*((volatile unsigned char *)(x))) +#define HWREGBITW(x, b) \ + HWREG(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ + (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2)) +#define HWREGBITH(x, b) \ + HWREGH(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ + (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2)) +#define HWREGBITB(x, b) \ + HWREGB(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \ + (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2)) + + +#endif // __HW_TYPES_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_uart.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_uart.h new file mode 100755 index 0000000..ae50ac3 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_uart.h @@ -0,0 +1,417 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_UART_H__ +#define __HW_UART_H__ + +//***************************************************************************** +// +// The following are defines for the UART register offsets. +// +//***************************************************************************** +#define UART_O_DR 0x00000000 +#define UART_O_RSR 0x00000004 +#define UART_O_ECR 0x00000004 +#define UART_O_FR 0x00000018 +#define UART_O_ILPR 0x00000020 +#define UART_O_IBRD 0x00000024 +#define UART_O_FBRD 0x00000028 +#define UART_O_LCRH 0x0000002C +#define UART_O_CTL 0x00000030 +#define UART_O_IFLS 0x00000034 +#define UART_O_IM 0x00000038 +#define UART_O_RIS 0x0000003C +#define UART_O_MIS 0x00000040 +#define UART_O_ICR 0x00000044 +#define UART_O_DMACTL 0x00000048 +#define UART_O_LCTL 0x00000090 +#define UART_O_LSS 0x00000094 +#define UART_O_LTIM 0x00000098 +#define UART_O_9BITADDR 0x000000A4 +#define UART_O_9BITAMASK 0x000000A8 +#define UART_O_PP 0x00000FC0 +#define UART_O_CC 0x00000FC8 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_DR register. +// +//****************************************************************************** +#define UART_DR_OE 0x00000800 // UART Overrun Error +#define UART_DR_BE 0x00000400 // UART Break Error +#define UART_DR_PE 0x00000200 // UART Parity Error +#define UART_DR_FE 0x00000100 // UART Framing Error +#define UART_DR_DATA_M 0x000000FF // Data Transmitted or Received +#define UART_DR_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_RSR register. +// +//****************************************************************************** +#define UART_RSR_OE 0x00000008 // UART Overrun Error +#define UART_RSR_BE 0x00000004 // UART Break Error +#define UART_RSR_PE 0x00000002 // UART Parity Error +#define UART_RSR_FE 0x00000001 // UART Framing Error +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_ECR register. +// +//****************************************************************************** +#define UART_ECR_DATA_M 0x000000FF // Error Clear +#define UART_ECR_DATA_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_FR register. +// +//****************************************************************************** +#define UART_FR_RI 0x00000100 // Ring Indicator +#define UART_FR_TXFE 0x00000080 // UART Transmit FIFO Empty +#define UART_FR_RXFF 0x00000040 // UART Receive FIFO Full +#define UART_FR_TXFF 0x00000020 // UART Transmit FIFO Full +#define UART_FR_RXFE 0x00000010 // UART Receive FIFO Empty +#define UART_FR_BUSY 0x00000008 // UART Busy +#define UART_FR_DCD 0x00000004 // Data Carrier Detect +#define UART_FR_DSR 0x00000002 // Data Set Ready +#define UART_FR_CTS 0x00000001 // Clear To Send +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_ILPR register. +// +//****************************************************************************** +#define UART_ILPR_ILPDVSR_M 0x000000FF // IrDA Low-Power Divisor +#define UART_ILPR_ILPDVSR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_IBRD register. +// +//****************************************************************************** +#define UART_IBRD_DIVINT_M 0x0000FFFF // Integer Baud-Rate Divisor +#define UART_IBRD_DIVINT_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_FBRD register. +// +//****************************************************************************** +#define UART_FBRD_DIVFRAC_M 0x0000003F // Fractional Baud-Rate Divisor +#define UART_FBRD_DIVFRAC_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_LCRH register. +// +//****************************************************************************** +#define UART_LCRH_SPS 0x00000080 // UART Stick Parity Select +#define UART_LCRH_WLEN_M 0x00000060 // UART Word Length 0x00000000 : + // UART_LCRH_WLEN_5 : 5 bits + // (default) 0x00000020 : + // UART_LCRH_WLEN_6 : 6 bits + // 0x00000040 : UART_LCRH_WLEN_7 : 7 + // bits 0x00000060 : + // UART_LCRH_WLEN_8 : 8 bits +#define UART_LCRH_WLEN_S 5 +#define UART_LCRH_FEN 0x00000010 // UART Enable FIFOs +#define UART_LCRH_STP2 0x00000008 // UART Two Stop Bits Select +#define UART_LCRH_EPS 0x00000004 // UART Even Parity Select +#define UART_LCRH_PEN 0x00000002 // UART Parity Enable +#define UART_LCRH_BRK 0x00000001 // UART Send Break +#define UART_LCRH_WLEN_M 0x00000060 // UART Word Length +#define UART_LCRH_WLEN_5 0x00000000 // 5 bits (default) +#define UART_LCRH_WLEN_6 0x00000020 // 6 bits +#define UART_LCRH_WLEN_7 0x00000040 // 7 bits +#define UART_LCRH_WLEN_8 0x00000060 // 8 bits +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_CTL register. +// +//****************************************************************************** +#define UART_CTL_CTSEN 0x00008000 // Enable Clear To Send +#define UART_CTL_RTSEN 0x00004000 // Enable Request to Send +#define UART_CTL_RI 0x00002000 // Ring Indicator +#define UART_CTL_DCD 0x00001000 // Data Carrier Detect +#define UART_CTL_RTS 0x00000800 // Request to Send +#define UART_CTL_DTR 0x00000400 // Data Terminal Ready +#define UART_CTL_RXE 0x00000200 // UART Receive Enable +#define UART_CTL_TXE 0x00000100 // UART Transmit Enable +#define UART_CTL_LBE 0x00000080 // UART Loop Back Enable +#define UART_CTL_LIN 0x00000040 // LIN Mode Enable +#define UART_CTL_HSE 0x00000020 // High-Speed Enable +#define UART_CTL_EOT 0x00000010 // End of Transmission +#define UART_CTL_SMART 0x00000008 // ISO 7816 Smart Card Support +#define UART_CTL_SIRLP 0x00000004 // UART SIR Low-Power Mode +#define UART_CTL_SIREN 0x00000002 // UART SIR Enable +#define UART_CTL_UARTEN 0x00000001 // UART Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_IFLS register. +// +//****************************************************************************** +#define UART_IFLS_RX_M 0x00000038 // UART Receive Interrupt FIFO + // Level Select +#define UART_IFLS_RX_S 3 +#define UART_IFLS_TX_M 0x00000007 // UART Transmit Interrupt FIFO + // Level Select +#define UART_IFLS_TX_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_IM register. +// +//****************************************************************************** +#define UART_IM_DMATXIM 0x00020000 // Transmit DMA Interrupt Mask +#define UART_IM_DMARXIM 0x00010000 // Receive DMA Interrupt Mask +#define UART_IM_LME5IM 0x00008000 // LIN Mode Edge 5 Interrupt Mask +#define UART_IM_LME1IM 0x00004000 // LIN Mode Edge 1 Interrupt Mask +#define UART_IM_LMSBIM 0x00002000 // LIN Mode Sync Break Interrupt + // Mask +#define UART_IM_9BITIM 0x00001000 // 9-Bit Mode Interrupt Mask +#define UART_IM_EOTIM 0x00000800 // End of Transmission Interrupt + // Mask +#define UART_IM_OEIM 0x00000400 // UART Overrun Error Interrupt + // Mask +#define UART_IM_BEIM 0x00000200 // UART Break Error Interrupt Mask +#define UART_IM_PEIM 0x00000100 // UART Parity Error Interrupt Mask +#define UART_IM_FEIM 0x00000080 // UART Framing Error Interrupt + // Mask +#define UART_IM_RTIM 0x00000040 // UART Receive Time-Out Interrupt + // Mask +#define UART_IM_TXIM 0x00000020 // UART Transmit Interrupt Mask +#define UART_IM_RXIM 0x00000010 // UART Receive Interrupt Mask +#define UART_IM_DSRMIM 0x00000008 // UART Data Set Ready Modem + // Interrupt Mask +#define UART_IM_DCDMIM 0x00000004 // UART Data Carrier Detect Modem + // Interrupt Mask +#define UART_IM_CTSMIM 0x00000002 // UART Clear to Send Modem + // Interrupt Mask +#define UART_IM_RIMIM 0x00000001 // UART Ring Indicator Modem + // Interrupt Mask +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_RIS register. +// +//****************************************************************************** +#define UART_RIS_DMATXRIS 0x00020000 // Transmit DMA Raw Interrupt + // Status +#define UART_RIS_DMARXRIS 0x00010000 // Receive DMA Raw Interrupt Status +#define UART_RIS_LME5RIS 0x00008000 // LIN Mode Edge 5 Raw Interrupt + // Status +#define UART_RIS_LME1RIS 0x00004000 // LIN Mode Edge 1 Raw Interrupt + // Status +#define UART_RIS_LMSBRIS 0x00002000 // LIN Mode Sync Break Raw + // Interrupt Status +#define UART_RIS_9BITRIS 0x00001000 // 9-Bit Mode Raw Interrupt Status +#define UART_RIS_EOTRIS 0x00000800 // End of Transmission Raw + // Interrupt Status +#define UART_RIS_OERIS 0x00000400 // UART Overrun Error Raw Interrupt + // Status +#define UART_RIS_BERIS 0x00000200 // UART Break Error Raw Interrupt + // Status +#define UART_RIS_PERIS 0x00000100 // UART Parity Error Raw Interrupt + // Status +#define UART_RIS_FERIS 0x00000080 // UART Framing Error Raw Interrupt + // Status +#define UART_RIS_RTRIS 0x00000040 // UART Receive Time-Out Raw + // Interrupt Status +#define UART_RIS_TXRIS 0x00000020 // UART Transmit Raw Interrupt + // Status +#define UART_RIS_RXRIS 0x00000010 // UART Receive Raw Interrupt + // Status +#define UART_RIS_DSRRIS 0x00000008 // UART Data Set Ready Modem Raw + // Interrupt Status +#define UART_RIS_DCDRIS 0x00000004 // UART Data Carrier Detect Modem + // Raw Interrupt Status +#define UART_RIS_CTSRIS 0x00000002 // UART Clear to Send Modem Raw + // Interrupt Status +#define UART_RIS_RIRIS 0x00000001 // UART Ring Indicator Modem Raw + // Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_MIS register. +// +//****************************************************************************** +#define UART_MIS_DMATXMIS 0x00020000 // Transmit DMA Masked Interrupt + // Status +#define UART_MIS_DMARXMIS 0x00010000 // Receive DMA Masked Interrupt + // Status +#define UART_MIS_LME5MIS 0x00008000 // LIN Mode Edge 5 Masked Interrupt + // Status +#define UART_MIS_LME1MIS 0x00004000 // LIN Mode Edge 1 Masked Interrupt + // Status +#define UART_MIS_LMSBMIS 0x00002000 // LIN Mode Sync Break Masked + // Interrupt Status +#define UART_MIS_9BITMIS 0x00001000 // 9-Bit Mode Masked Interrupt + // Status +#define UART_MIS_EOTMIS 0x00000800 // End of Transmission Masked + // Interrupt Status +#define UART_MIS_OEMIS 0x00000400 // UART Overrun Error Masked + // Interrupt Status +#define UART_MIS_BEMIS 0x00000200 // UART Break Error Masked + // Interrupt Status +#define UART_MIS_PEMIS 0x00000100 // UART Parity Error Masked + // Interrupt Status +#define UART_MIS_FEMIS 0x00000080 // UART Framing Error Masked + // Interrupt Status +#define UART_MIS_RTMIS 0x00000040 // UART Receive Time-Out Masked + // Interrupt Status +#define UART_MIS_TXMIS 0x00000020 // UART Transmit Masked Interrupt + // Status +#define UART_MIS_RXMIS 0x00000010 // UART Receive Masked Interrupt + // Status +#define UART_MIS_DSRMIS 0x00000008 // UART Data Set Ready Modem Masked + // Interrupt Status +#define UART_MIS_DCDMIS 0x00000004 // UART Data Carrier Detect Modem + // Masked Interrupt Status +#define UART_MIS_CTSMIS 0x00000002 // UART Clear to Send Modem Masked + // Interrupt Status +#define UART_MIS_RIMIS 0x00000001 // UART Ring Indicator Modem Masked + // Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_ICR register. +// +//****************************************************************************** +#define UART_ICR_DMATXIC 0x00020000 // Transmit DMA Interrupt Clear +#define UART_ICR_DMARXIC 0x00010000 // Receive DMA Interrupt Clear +#define UART_ICR_LME5MIC 0x00008000 // LIN Mode Edge 5 Interrupt Clear +#define UART_ICR_LME1MIC 0x00004000 // LIN Mode Edge 1 Interrupt Clear +#define UART_ICR_LMSBMIC 0x00002000 // LIN Mode Sync Break Interrupt + // Clear +#define UART_ICR_9BITIC 0x00001000 // 9-Bit Mode Interrupt Clear +#define UART_ICR_EOTIC 0x00000800 // End of Transmission Interrupt + // Clear +#define UART_ICR_OEIC 0x00000400 // Overrun Error Interrupt Clear +#define UART_ICR_BEIC 0x00000200 // Break Error Interrupt Clear +#define UART_ICR_PEIC 0x00000100 // Parity Error Interrupt Clear +#define UART_ICR_FEIC 0x00000080 // Framing Error Interrupt Clear +#define UART_ICR_RTIC 0x00000040 // Receive Time-Out Interrupt Clear +#define UART_ICR_TXIC 0x00000020 // Transmit Interrupt Clear +#define UART_ICR_RXIC 0x00000010 // Receive Interrupt Clear +#define UART_ICR_DSRMIC 0x00000008 // UART Data Set Ready Modem + // Interrupt Clear +#define UART_ICR_DCDMIC 0x00000004 // UART Data Carrier Detect Modem + // Interrupt Clear +#define UART_ICR_CTSMIC 0x00000002 // UART Clear to Send Modem + // Interrupt Clear +#define UART_ICR_RIMIC 0x00000001 // UART Ring Indicator Modem + // Interrupt Clear +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_DMACTL register. +// +//****************************************************************************** +#define UART_DMACTL_DMAERR 0x00000004 // DMA on Error +#define UART_DMACTL_TXDMAE 0x00000002 // Transmit DMA Enable +#define UART_DMACTL_RXDMAE 0x00000001 // Receive DMA Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_LCTL register. +// +//****************************************************************************** +#define UART_LCTL_BLEN_M 0x00000030 // Sync Break Length 0x00000000 : + // UART_LCTL_BLEN_13T : Sync break + // length is 13T bits (default) + // 0x00000010 : UART_LCTL_BLEN_14T : + // Sync break length is 14T bits + // 0x00000020 : UART_LCTL_BLEN_15T : + // Sync break length is 15T bits + // 0x00000030 : UART_LCTL_BLEN_16T : + // Sync break length is 16T bits +#define UART_LCTL_BLEN_S 4 +#define UART_LCTL_MASTER 0x00000001 // LIN Master Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_LSS register. +// +//****************************************************************************** +#define UART_LSS_TSS_M 0x0000FFFF // Timer Snap Shot +#define UART_LSS_TSS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_LTIM register. +// +//****************************************************************************** +#define UART_LTIM_TIMER_M 0x0000FFFF // Timer Value +#define UART_LTIM_TIMER_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// UART_O_9BITADDR register. +// +//****************************************************************************** +#define UART_9BITADDR_9BITEN \ + 0x00008000 // Enable 9-Bit Mode + +#define UART_9BITADDR_ADDR_M \ + 0x000000FF // Self Address for 9-Bit Mode + +#define UART_9BITADDR_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// UART_O_9BITAMASK register. +// +//****************************************************************************** +#define UART_9BITAMASK_RANGE_M \ + 0x0000FF00 // Self Address Range for 9-Bit + // Mode + +#define UART_9BITAMASK_RANGE_S 8 +#define UART_9BITAMASK_MASK_M \ + 0x000000FF // Self Address Mask for 9-Bit Mode + +#define UART_9BITAMASK_MASK_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_PP register. +// +//****************************************************************************** +#define UART_PP_MSE 0x00000008 // Modem Support Extended +#define UART_PP_MS 0x00000004 // Modem Support +#define UART_PP_NB 0x00000002 // 9-Bit Support +#define UART_PP_SC 0x00000001 // Smart Card Support +//****************************************************************************** +// +// The following are defines for the bit fields in the UART_O_CC register. +// +//****************************************************************************** +#define UART_CC_CS_M 0x0000000F // UART Baud Clock Source + // 0x00000005 : UART_CC_CS_PIOSC : + // PIOSC 0x00000000 : + // UART_CC_CS_SYSCLK : The system + // clock (default) +#define UART_CC_CS_S 0 + + + +#endif // __HW_UART_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_udma.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_udma.h new file mode 100755 index 0000000..9a495ba --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_udma.h @@ -0,0 +1,336 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_UDMA_H__ +#define __HW_UDMA_H__ + +//***************************************************************************** +// +// The following are defines for the UDMA register offsets. +// +//***************************************************************************** +#define UDMA_O_STAT 0x00000000 +#define UDMA_O_CFG 0x00000004 +#define UDMA_O_CTLBASE 0x00000008 +#define UDMA_O_ALTBASE 0x0000000C +#define UDMA_O_WAITSTAT 0x00000010 +#define UDMA_O_SWREQ 0x00000014 +#define UDMA_O_USEBURSTSET 0x00000018 +#define UDMA_O_USEBURSTCLR 0x0000001C +#define UDMA_O_REQMASKSET 0x00000020 +#define UDMA_O_REQMASKCLR 0x00000024 +#define UDMA_O_ENASET 0x00000028 +#define UDMA_O_ENACLR 0x0000002C +#define UDMA_O_ALTSET 0x00000030 +#define UDMA_O_ALTCLR 0x00000034 +#define UDMA_O_PRIOSET 0x00000038 +#define UDMA_O_PRIOCLR 0x0000003C +#define UDMA_O_ERRCLR 0x0000004C +#define UDMA_O_CHASGN 0x00000500 +#define UDMA_O_CHIS 0x00000504 +#define UDMA_O_CHMAP0 0x00000510 +#define UDMA_O_CHMAP1 0x00000514 +#define UDMA_O_CHMAP2 0x00000518 +#define UDMA_O_CHMAP3 0x0000051C +#define UDMA_O_PV 0x00000FB0 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_STAT register. +// +//****************************************************************************** +#define UDMA_STAT_DMACHANS_M 0x001F0000 // Available uDMA Channels Minus 1 +#define UDMA_STAT_DMACHANS_S 16 +#define UDMA_STAT_STATE_M 0x000000F0 // Control State Machine Status + // 0x00000090 : UDMA_STAT_STATE_DONE + // : Done 0x00000000 : + // UDMA_STAT_STATE_IDLE : Idle + // 0x00000010 : + // UDMA_STAT_STATE_RD_CTRL : Reading + // channel controller data + // 0x00000030 : + // UDMA_STAT_STATE_RD_DSTENDP : + // Reading destination end pointer + // 0x00000040 : + // UDMA_STAT_STATE_RD_SRCDAT : + // Reading source data 0x00000020 : + // UDMA_STAT_STATE_RD_SRCENDP : + // Reading source end pointer + // 0x00000080 : + // UDMA_STAT_STATE_STALL : Stalled + // 0x000000A0 : + // UDMA_STAT_STATE_UNDEF : Undefined + // 0x00000060 : UDMA_STAT_STATE_WAIT + // : Waiting for uDMA request to + // clear 0x00000070 : + // UDMA_STAT_STATE_WR_CTRL : Writing + // channel controller data + // 0x00000050 : + // UDMA_STAT_STATE_WR_DSTDAT : + // Writing destination data +#define UDMA_STAT_STATE_S 4 +#define UDMA_STAT_MASTEN 0x00000001 // Master Enable Status +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CFG register. +// +//****************************************************************************** +#define UDMA_CFG_MASTEN 0x00000001 // Controller Master Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CTLBASE register. +// +//****************************************************************************** +#define UDMA_CTLBASE_ADDR_M 0xFFFFFC00 // Channel Control Base Address +#define UDMA_CTLBASE_ADDR_S 10 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ALTBASE register. +// +//****************************************************************************** +#define UDMA_ALTBASE_ADDR_M 0xFFFFFFFF // Alternate Channel Address + // Pointer +#define UDMA_ALTBASE_ADDR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_WAITSTAT register. +// +//****************************************************************************** +#define UDMA_WAITSTAT_WAITREQ_M \ + 0xFFFFFFFF // Channel [n] Wait Status + +#define UDMA_WAITSTAT_WAITREQ_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_SWREQ register. +// +//****************************************************************************** +#define UDMA_SWREQ_M 0xFFFFFFFF // Channel [n] Software Request +#define UDMA_SWREQ_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// UDMA_O_USEBURSTSET register. +// +//****************************************************************************** +#define UDMA_USEBURSTSET_SET_M \ + 0xFFFFFFFF // Channel [n] Useburst Set + +#define UDMA_USEBURSTSET_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the +// UDMA_O_USEBURSTCLR register. +// +//****************************************************************************** +#define UDMA_USEBURSTCLR_CLR_M \ + 0xFFFFFFFF // Channel [n] Useburst Clear + +#define UDMA_USEBURSTCLR_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_REQMASKSET register. +// +//****************************************************************************** +#define UDMA_REQMASKSET_SET_M 0xFFFFFFFF // Channel [n] Request Mask Set +#define UDMA_REQMASKSET_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_REQMASKCLR register. +// +//****************************************************************************** +#define UDMA_REQMASKCLR_CLR_M 0xFFFFFFFF // Channel [n] Request Mask Clear +#define UDMA_REQMASKCLR_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ENASET register. +// +//****************************************************************************** +#define UDMA_ENASET_CHENSET_M 0xFFFFFFFF // Channel [n] Enable Set +#define UDMA_ENASET_CHENSET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ENACLR register. +// +//****************************************************************************** +#define UDMA_ENACLR_CLR_M 0xFFFFFFFF // Clear Channel [n] Enable Clear +#define UDMA_ENACLR_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ALTSET register. +// +//****************************************************************************** +#define UDMA_ALTSET_SET_M 0xFFFFFFFF // Channel [n] Alternate Set +#define UDMA_ALTSET_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ALTCLR register. +// +//****************************************************************************** +#define UDMA_ALTCLR_CLR_M 0xFFFFFFFF // Channel [n] Alternate Clear +#define UDMA_ALTCLR_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_PRIOSET register. +// +//****************************************************************************** +#define UDMA_PRIOSET_SET_M 0xFFFFFFFF // Channel [n] Priority Set +#define UDMA_PRIOSET_SET_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_PRIOCLR register. +// +//****************************************************************************** +#define UDMA_PRIOCLR_CLR_M 0xFFFFFFFF // Channel [n] Priority Clear +#define UDMA_PRIOCLR_CLR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_ERRCLR register. +// +//****************************************************************************** +#define UDMA_ERRCLR_ERRCLR 0x00000001 // uDMA Bus Error Status +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHASGN register. +// +//****************************************************************************** +#define UDMA_CHASGN_M 0xFFFFFFFF // Channel [n] Assignment Select +#define UDMA_CHASGN_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHIS register. +// +//****************************************************************************** +#define UDMA_CHIS_M 0xFFFFFFFF // Channel [n] Interrupt Status +#define UDMA_CHIS_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHMAP0 register. +// +//****************************************************************************** +#define UDMA_CHMAP0_CH7SEL_M 0xF0000000 // uDMA Channel 7 Source Select +#define UDMA_CHMAP0_CH7SEL_S 28 +#define UDMA_CHMAP0_CH6SEL_M 0x0F000000 // uDMA Channel 6 Source Select +#define UDMA_CHMAP0_CH6SEL_S 24 +#define UDMA_CHMAP0_CH5SEL_M 0x00F00000 // uDMA Channel 5 Source Select +#define UDMA_CHMAP0_CH5SEL_S 20 +#define UDMA_CHMAP0_CH4SEL_M 0x000F0000 // uDMA Channel 4 Source Select +#define UDMA_CHMAP0_CH4SEL_S 16 +#define UDMA_CHMAP0_CH3SEL_M 0x0000F000 // uDMA Channel 3 Source Select +#define UDMA_CHMAP0_CH3SEL_S 12 +#define UDMA_CHMAP0_CH2SEL_M 0x00000F00 // uDMA Channel 2 Source Select +#define UDMA_CHMAP0_CH2SEL_S 8 +#define UDMA_CHMAP0_CH1SEL_M 0x000000F0 // uDMA Channel 1 Source Select +#define UDMA_CHMAP0_CH1SEL_S 4 +#define UDMA_CHMAP0_CH0SEL_M 0x0000000F // uDMA Channel 0 Source Select +#define UDMA_CHMAP0_CH0SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHMAP1 register. +// +//****************************************************************************** +#define UDMA_CHMAP1_CH15SEL_M 0xF0000000 // uDMA Channel 15 Source Select +#define UDMA_CHMAP1_CH15SEL_S 28 +#define UDMA_CHMAP1_CH14SEL_M 0x0F000000 // uDMA Channel 14 Source Select +#define UDMA_CHMAP1_CH14SEL_S 24 +#define UDMA_CHMAP1_CH13SEL_M 0x00F00000 // uDMA Channel 13 Source Select +#define UDMA_CHMAP1_CH13SEL_S 20 +#define UDMA_CHMAP1_CH12SEL_M 0x000F0000 // uDMA Channel 12 Source Select +#define UDMA_CHMAP1_CH12SEL_S 16 +#define UDMA_CHMAP1_CH11SEL_M 0x0000F000 // uDMA Channel 11 Source Select +#define UDMA_CHMAP1_CH11SEL_S 12 +#define UDMA_CHMAP1_CH10SEL_M 0x00000F00 // uDMA Channel 10 Source Select +#define UDMA_CHMAP1_CH10SEL_S 8 +#define UDMA_CHMAP1_CH9SEL_M 0x000000F0 // uDMA Channel 9 Source Select +#define UDMA_CHMAP1_CH9SEL_S 4 +#define UDMA_CHMAP1_CH8SEL_M 0x0000000F // uDMA Channel 8 Source Select +#define UDMA_CHMAP1_CH8SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHMAP2 register. +// +//****************************************************************************** +#define UDMA_CHMAP2_CH23SEL_M 0xF0000000 // uDMA Channel 23 Source Select +#define UDMA_CHMAP2_CH23SEL_S 28 +#define UDMA_CHMAP2_CH22SEL_M 0x0F000000 // uDMA Channel 22 Source Select +#define UDMA_CHMAP2_CH22SEL_S 24 +#define UDMA_CHMAP2_CH21SEL_M 0x00F00000 // uDMA Channel 21 Source Select +#define UDMA_CHMAP2_CH21SEL_S 20 +#define UDMA_CHMAP2_CH20SEL_M 0x000F0000 // uDMA Channel 20 Source Select +#define UDMA_CHMAP2_CH20SEL_S 16 +#define UDMA_CHMAP2_CH19SEL_M 0x0000F000 // uDMA Channel 19 Source Select +#define UDMA_CHMAP2_CH19SEL_S 12 +#define UDMA_CHMAP2_CH18SEL_M 0x00000F00 // uDMA Channel 18 Source Select +#define UDMA_CHMAP2_CH18SEL_S 8 +#define UDMA_CHMAP2_CH17SEL_M 0x000000F0 // uDMA Channel 17 Source Select +#define UDMA_CHMAP2_CH17SEL_S 4 +#define UDMA_CHMAP2_CH16SEL_M 0x0000000F // uDMA Channel 16 Source Select +#define UDMA_CHMAP2_CH16SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_CHMAP3 register. +// +//****************************************************************************** +#define UDMA_CHMAP3_CH31SEL_M 0xF0000000 // uDMA Channel 31 Source Select +#define UDMA_CHMAP3_CH31SEL_S 28 +#define UDMA_CHMAP3_CH30SEL_M 0x0F000000 // uDMA Channel 30 Source Select +#define UDMA_CHMAP3_CH30SEL_S 24 +#define UDMA_CHMAP3_CH29SEL_M 0x00F00000 // uDMA Channel 29 Source Select +#define UDMA_CHMAP3_CH29SEL_S 20 +#define UDMA_CHMAP3_CH28SEL_M 0x000F0000 // uDMA Channel 28 Source Select +#define UDMA_CHMAP3_CH28SEL_S 16 +#define UDMA_CHMAP3_CH27SEL_M 0x0000F000 // uDMA Channel 27 Source Select +#define UDMA_CHMAP3_CH27SEL_S 12 +#define UDMA_CHMAP3_CH26SEL_M 0x00000F00 // uDMA Channel 26 Source Select +#define UDMA_CHMAP3_CH26SEL_S 8 +#define UDMA_CHMAP3_CH25SEL_M 0x000000F0 // uDMA Channel 25 Source Select +#define UDMA_CHMAP3_CH25SEL_S 4 +#define UDMA_CHMAP3_CH24SEL_M 0x0000000F // uDMA Channel 24 Source Select +#define UDMA_CHMAP3_CH24SEL_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the UDMA_O_PV register. +// +//****************************************************************************** +#define UDMA_PV_MAJOR_M 0x0000FF00 // Major Revision +#define UDMA_PV_MAJOR_S 8 +#define UDMA_PV_MINOR_M 0x000000FF // Minor Revision +#define UDMA_PV_MINOR_S 0 + + + +#endif // __HW_UDMA_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_wdt.h b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_wdt.h new file mode 100755 index 0000000..00b14ac --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/inc/hw_wdt.h @@ -0,0 +1,131 @@ +//***************************************************************************** +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __HW_WDT_H__ +#define __HW_WDT_H__ + +//***************************************************************************** +// +// The following are defines for the WDT register offsets. +// +//***************************************************************************** +#define WDT_O_LOAD 0x00000000 +#define WDT_O_VALUE 0x00000004 +#define WDT_O_CTL 0x00000008 +#define WDT_O_ICR 0x0000000C +#define WDT_O_RIS 0x00000010 +#define WDT_O_MIS 0x00000014 +#define WDT_O_TEST 0x00000418 +#define WDT_O_LOCK 0x00000C00 + + + +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_LOAD register. +// +//****************************************************************************** +#define WDT_LOAD_M 0xFFFFFFFF // Watchdog Load Value +#define WDT_LOAD_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_VALUE register. +// +//****************************************************************************** +#define WDT_VALUE_M 0xFFFFFFFF // Watchdog Value +#define WDT_VALUE_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_CTL register. +// +//****************************************************************************** +#define WDT_CTL_WRC 0x80000000 // Write Complete +#define WDT_CTL_INTTYPE 0x00000004 // Watchdog Interrupt Type +#define WDT_CTL_RESEN 0x00000002 // Watchdog Reset Enable. This bit + // is not used in cc3xx, WDOG shall + // always generate RESET to system + // irrespective of this bit setting. +#define WDT_CTL_INTEN 0x00000001 // Watchdog Interrupt Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_ICR register. +// +//****************************************************************************** +#define WDT_ICR_M 0xFFFFFFFF // Watchdog Interrupt Clear +#define WDT_ICR_S 0 +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_RIS register. +// +//****************************************************************************** +#define WDT_RIS_WDTRIS 0x00000001 // Watchdog Raw Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_MIS register. +// +//****************************************************************************** +#define WDT_MIS_WDTMIS 0x00000001 // Watchdog Masked Interrupt Status +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_TEST register. +// +//****************************************************************************** +#define WDT_TEST_STALL_EN_M 0x00000C00 // Watchdog stall enable +#define WDT_TEST_STALL_EN_S 10 +#define WDT_TEST_STALL 0x00000100 // Watchdog Stall Enable +//****************************************************************************** +// +// The following are defines for the bit fields in the WDT_O_LOCK register. +// +//****************************************************************************** +#define WDT_LOCK_M 0xFFFFFFFF // Watchdog Lock +#define WDT_LOCK_S 0 +#define WDT_LOCK_UNLOCKED 0x00000000 // Unlocked +#define WDT_LOCK_LOCKED 0x00000001 // Locked +#define WDT_LOCK_UNLOCK 0x1ACCE551 // Unlocks the watchdog timer + +//***************************************************************************** +// +// The following are defines for the bit fields in the WDT_ISR, WDT_RIS, and +// WDT_MIS registers. +// +//***************************************************************************** +#define WDT_INT_TIMEOUT 0x00000001 // Watchdog timer expired + + + + + +#endif // __HW_WDT_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/interrupt.c b/src/openmv/src/micropython/ports/cc3200/hal/interrupt.c new file mode 100755 index 0000000..897ad96 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/interrupt.c @@ -0,0 +1,769 @@ +//***************************************************************************** +// +// interrupt.c +// +// Driver for the NVIC Interrupt Controller. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup interrupt_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "cpu.h" +#include "debug.h" +#include "interrupt.h" + +//***************************************************************************** +// +// This is a mapping between priority grouping encodings and the number of +// preemption priority bits. +// +//***************************************************************************** +static const unsigned long g_pulPriority[] = +{ + NVIC_APINT_PRIGROUP_0_8, NVIC_APINT_PRIGROUP_1_7, NVIC_APINT_PRIGROUP_2_6, + NVIC_APINT_PRIGROUP_3_5, NVIC_APINT_PRIGROUP_4_4, NVIC_APINT_PRIGROUP_5_3, + NVIC_APINT_PRIGROUP_6_2, NVIC_APINT_PRIGROUP_7_1 +}; + +//***************************************************************************** +// +// This is a mapping between interrupt number and the register that contains +// the priority encoding for that interrupt. +// +//***************************************************************************** +static const unsigned long g_pulRegs[] = +{ + 0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3, NVIC_PRI0, NVIC_PRI1, + NVIC_PRI2, NVIC_PRI3, NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7, + NVIC_PRI8, NVIC_PRI9, NVIC_PRI10, NVIC_PRI11, NVIC_PRI12, NVIC_PRI13, + NVIC_PRI14, NVIC_PRI15, NVIC_PRI16, NVIC_PRI17, NVIC_PRI18, NVIC_PRI19, + NVIC_PRI20, NVIC_PRI21, NVIC_PRI22, NVIC_PRI23, NVIC_PRI24, NVIC_PRI25, + NVIC_PRI26, NVIC_PRI27, NVIC_PRI28, NVIC_PRI29, NVIC_PRI30, NVIC_PRI31, + NVIC_PRI32, NVIC_PRI33, NVIC_PRI34, NVIC_PRI35, NVIC_PRI36, NVIC_PRI37, + NVIC_PRI38, NVIC_PRI39, NVIC_PRI40, NVIC_PRI41, NVIC_PRI42, NVIC_PRI43, + NVIC_PRI44, NVIC_PRI45, NVIC_PRI46, NVIC_PRI47, NVIC_PRI48 + +}; + + +//***************************************************************************** +// +// This is a mapping between interrupt number (for the peripheral interrupts +// only) and the register that contains the interrupt enable for that +// interrupt. +// +//***************************************************************************** +static const unsigned long g_pulEnRegs[] = +{ + NVIC_EN0, NVIC_EN1, NVIC_EN2, NVIC_EN3, NVIC_EN4, NVIC_EN5 +}; + +//***************************************************************************** +// +// This is a mapping between interrupt number (for the peripheral interrupts +// only) and the register that contains the interrupt disable for that +// interrupt. +// +//***************************************************************************** +static const unsigned long g_pulDisRegs[] = +{ + NVIC_DIS0, NVIC_DIS1, NVIC_DIS2, NVIC_DIS3, NVIC_DIS4, NVIC_DIS5 +}; + +//***************************************************************************** +// +// This is a mapping between interrupt number (for the peripheral interrupts +// only) and the register that contains the interrupt pend for that interrupt. +// +//***************************************************************************** +static const unsigned long g_pulPendRegs[] = +{ + NVIC_PEND0, NVIC_PEND1, NVIC_PEND2, NVIC_PEND3, NVIC_PEND4, NVIC_PEND5 +}; + +//***************************************************************************** +// +// This is a mapping between interrupt number (for the peripheral interrupts +// only) and the register that contains the interrupt unpend for that +// interrupt. +// +//***************************************************************************** +static const unsigned long g_pulUnpendRegs[] = +{ + NVIC_UNPEND0, NVIC_UNPEND1, NVIC_UNPEND2, NVIC_UNPEND3, NVIC_UNPEND4, + NVIC_UNPEND5 +}; + + +//***************************************************************************** +// +//! \internal +//! The default interrupt handler. +//! +//! This is the default interrupt handler for all interrupts. It simply loops +//! forever so that the system state is preserved for observation by a +//! debugger. Since interrupts should be disabled before unregistering the +//! corresponding handler, this should never be called. +//! +//! \return None. +// +//***************************************************************************** +static void +IntDefaultHandler(void) +{ + // + // Go into an infinite loop. + // + while(1) + { + } +} + +//***************************************************************************** +// +//! Enables the processor interrupt. +//! +//! Allows the processor to respond to interrupts. This does not affect the +//! set of interrupts enabled in the interrupt controller; it just gates the +//! single interrupt from the controller to the processor. +//! +//! \note Previously, this function had no return value. As such, it was +//! possible to include interrupt.h and call this function without +//! having included hw_types.h. Now that the return is a +//! tBoolean, a compiler error will occur in this case. The solution +//! is to include hw_types.h before including interrupt.h. +//! +//! \return Returns \b true if interrupts were disabled when the function was +//! called or \b false if they were initially enabled. +// +//***************************************************************************** +tBoolean +IntMasterEnable(void) +{ + // + // Enable processor interrupts. + // + return(CPUcpsie()); +} + +//***************************************************************************** +// +//! Disables the processor interrupt. +//! +//! Prevents the processor from receiving interrupts. This does not affect the +//! set of interrupts enabled in the interrupt controller; it just gates the +//! single interrupt from the controller to the processor. +//! +//! \note Previously, this function had no return value. As such, it was +//! possible to include interrupt.h and call this function without +//! having included hw_types.h. Now that the return is a +//! tBoolean, a compiler error will occur in this case. The solution +//! is to include hw_types.h before including interrupt.h. +//! +//! \return Returns \b true if interrupts were already disabled when the +//! function was called or \b false if they were initially enabled. +// +//***************************************************************************** +tBoolean +IntMasterDisable(void) +{ + // + // Disable processor interrupts. + // + return(CPUcpsid()); +} +//***************************************************************************** +// +//! Sets the NVIC VTable base. +//! +//! \param ulVtableBase specifies the new base address of VTable +//! +//! This function is used to specify a new base address for the VTable. +//! This function must be called before using IntRegister() for registering +//! any interrupt handler. +//! +//! +//! \return None. +// +//***************************************************************************** +void +IntVTableBaseSet(unsigned long ulVtableBase) +{ + HWREG(NVIC_VTABLE) = ulVtableBase; +} + +//***************************************************************************** +// +//! Registers a function to be called when an interrupt occurs. +//! +//! \param ulInterrupt specifies the interrupt in question. +//! \param pfnHandler is a pointer to the function to be called. +//! +//! This function is used to specify the handler function to be called when the +//! given interrupt is asserted to the processor. When the interrupt occurs, +//! if it is enabled (via IntEnable()), the handler function will be called in +//! interrupt context. Since the handler function can preempt other code, care +//! must be taken to protect memory or peripherals that are accessed by the +//! handler and other non-handler code. +//! +//! +//! \return None. +// +//***************************************************************************** +void +IntRegister(unsigned long ulInterrupt, void (*pfnHandler)(void)) +{ + unsigned long *ulNvicTbl; + + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + ulNvicTbl = (unsigned long *)HWREG(NVIC_VTABLE); + ulNvicTbl[ulInterrupt]= (unsigned long)pfnHandler; +} + +//***************************************************************************** +// +//! Unregisters the function to be called when an interrupt occurs. +//! +//! \param ulInterrupt specifies the interrupt in question. +//! +//! This function is used to indicate that no handler should be called when the +//! given interrupt is asserted to the processor. The interrupt source will be +//! automatically disabled (via IntDisable()) if necessary. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +IntUnregister(unsigned long ulInterrupt) +{ + unsigned long *ulNvicTbl; + + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + ulNvicTbl = (unsigned long *)HWREG(NVIC_VTABLE); + ulNvicTbl[ulInterrupt]= (unsigned long)IntDefaultHandler; +} + +//***************************************************************************** +// +//! Sets the priority grouping of the interrupt controller. +//! +//! \param ulBits specifies the number of bits of preemptable priority. +//! +//! This function specifies the split between preemptable priority levels and +//! subpriority levels in the interrupt priority specification. The range of +//! the grouping values are dependent upon the hardware implementation; on +//! the CC3200 , three bits are available for hardware interrupt +//! prioritization and therefore priority grouping values of three through +//! seven have the same effect. +//! +//! \return None. +// +//***************************************************************************** +void +IntPriorityGroupingSet(unsigned long ulBits) +{ + // + // Check the arguments. + // + ASSERT(ulBits < NUM_PRIORITY); + + // + // Set the priority grouping. + // + HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | g_pulPriority[ulBits]; +} + +//***************************************************************************** +// +//! Gets the priority grouping of the interrupt controller. +//! +//! This function returns the split between preemptable priority levels and +//! subpriority levels in the interrupt priority specification. +//! +//! \return The number of bits of preemptable priority. +// +//***************************************************************************** +unsigned long +IntPriorityGroupingGet(void) +{ + unsigned long ulLoop, ulValue; + + // + // Read the priority grouping. + // + ulValue = HWREG(NVIC_APINT) & NVIC_APINT_PRIGROUP_M; + + // + // Loop through the priority grouping values. + // + for(ulLoop = 0; ulLoop < NUM_PRIORITY; ulLoop++) + { + // + // Stop looping if this value matches. + // + if(ulValue == g_pulPriority[ulLoop]) + { + break; + } + } + + // + // Return the number of priority bits. + // + return(ulLoop); +} + +//***************************************************************************** +// +//! Sets the priority of an interrupt. +//! +//! \param ulInterrupt specifies the interrupt in question. +//! \param ucPriority specifies the priority of the interrupt. +//! +//! This function is used to set the priority of an interrupt. When multiple +//! interrupts are asserted simultaneously, the ones with the highest priority +//! are processed before the lower priority interrupts. Smaller numbers +//! correspond to higher interrupt priorities; priority 0 is the highest +//! interrupt priority. +//! +//! The hardware priority mechanism will only look at the upper N bits of the +//! priority level (where N is 3), so any prioritization must be performed in +//! those bits. The remaining bits can be used to sub-prioritize the interrupt +//! sources, and may be used by the hardware priority mechanism on a future +//! part. This arrangement allows priorities to migrate to different NVIC +//! implementations without changing the gross prioritization of the +//! interrupts. +//! +//! The parameter \e ucPriority can be any one of the following +//! -\b INT_PRIORITY_LVL_0 +//! -\b INT_PRIORITY_LVL_1 +//! -\b INT_PRIORITY_LVL_2 +//! -\b INT_PRIORITY_LVL_3 +//! -\b INT_PRIORITY_LVL_4 +//! -\b INT_PRIORITY_LVL_5 +//! -\b INT_PRIORITY_LVL_6 +//! -\b INT_PRIORITY_LVL_7 +//! +//! \return None. +// +//***************************************************************************** +void +IntPrioritySet(unsigned long ulInterrupt, unsigned char ucPriority) +{ + unsigned long ulTemp; + + // + // Check the arguments. + // + ASSERT((ulInterrupt >= 4) && (ulInterrupt < NUM_INTERRUPTS)); + + // + // Set the interrupt priority. + // + ulTemp = HWREG(g_pulRegs[ulInterrupt >> 2]); + ulTemp &= ~(0xFF << (8 * (ulInterrupt & 3))); + ulTemp |= ucPriority << (8 * (ulInterrupt & 3)); + HWREG(g_pulRegs[ulInterrupt >> 2]) = ulTemp; +} + +//***************************************************************************** +// +//! Gets the priority of an interrupt. +//! +//! \param ulInterrupt specifies the interrupt in question. +//! +//! This function gets the priority of an interrupt. See IntPrioritySet() for +//! a definition of the priority value. +//! +//! \return Returns the interrupt priority, or -1 if an invalid interrupt was +//! specified. +// +//***************************************************************************** +long +IntPriorityGet(unsigned long ulInterrupt) +{ + // + // Check the arguments. + // + ASSERT((ulInterrupt >= 4) && (ulInterrupt < NUM_INTERRUPTS)); + + // + // Return the interrupt priority. + // + return((HWREG(g_pulRegs[ulInterrupt >> 2]) >> (8 * (ulInterrupt & 3))) & + 0xFF); +} + +//***************************************************************************** +// +//! Enables an interrupt. +//! +//! \param ulInterrupt specifies the interrupt to be enabled. +//! +//! The specified interrupt is enabled in the interrupt controller. Other +//! enables for the interrupt (such as at the peripheral level) are unaffected +//! by this function. +//! +//! \return None. +// +//***************************************************************************** +void +IntEnable(unsigned long ulInterrupt) +{ + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + // + // Determine the interrupt to enable. + // + if(ulInterrupt == FAULT_MPU) + { + // + // Enable the MemManage interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_MEM; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_BUS) + { + // + // Enable the bus fault interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_BUS; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_USAGE) + { + // + // Enable the usage fault interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_USAGE; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_SYSTICK) + { + // + // Enable the System Tick interrupt. + // + HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt >= 16) + { + // + // Enable the general interrupt. + // + HWREG(g_pulEnRegs[(ulInterrupt - 16) / 32]) = + 1 << ((ulInterrupt - 16) & 31); + __asm(" dsb "); + __asm(" isb "); + } +} + +//***************************************************************************** +// +//! Disables an interrupt. +//! +//! \param ulInterrupt specifies the interrupt to be disabled. +//! +//! The specified interrupt is disabled in the interrupt controller. Other +//! enables for the interrupt (such as at the peripheral level) are unaffected +//! by this function. +//! +//! \return None. +// +//***************************************************************************** +void +IntDisable(unsigned long ulInterrupt) +{ + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + // + // Determine the interrupt to disable. + // + if(ulInterrupt == FAULT_MPU) + { + // + // Disable the MemManage interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_MEM); + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_BUS) + { + // + // Disable the bus fault interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_BUS); + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_USAGE) + { + // + // Disable the usage fault interrupt. + // + HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_USAGE); + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_SYSTICK) + { + // + // Disable the System Tick interrupt. + // + HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN); + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt >= 16) + { + // + // Disable the general interrupt. + // + HWREG(g_pulDisRegs[(ulInterrupt - 16) / 32]) = + 1 << ((ulInterrupt - 16) & 31); + __asm(" dsb "); + __asm(" isb "); + } + +} + +//***************************************************************************** +// +//! Pends an interrupt. +//! +//! \param ulInterrupt specifies the interrupt to be pended. +//! +//! The specified interrupt is pended in the interrupt controller. This will +//! cause the interrupt controller to execute the corresponding interrupt +//! handler at the next available time, based on the current interrupt state +//! priorities. For example, if called by a higher priority interrupt handler, +//! the specified interrupt handler will not be called until after the current +//! interrupt handler has completed execution. The interrupt must have been +//! enabled for it to be called. +//! +//! \return None. +// +//***************************************************************************** +void +IntPendSet(unsigned long ulInterrupt) +{ + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + // + // Determine the interrupt to pend. + // + if(ulInterrupt == FAULT_NMI) + { + // + // Pend the NMI interrupt. + // + HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_NMI_SET; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_PENDSV) + { + // + // Pend the PendSV interrupt. + // + HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PEND_SV; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt == FAULT_SYSTICK) + { + // + // Pend the SysTick interrupt. + // + HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET; + __asm(" dsb "); + __asm(" isb "); + } + else if(ulInterrupt >= 16) + { + // + // Pend the general interrupt. + // + HWREG(g_pulPendRegs[(ulInterrupt - 16) / 32]) = + 1 << ((ulInterrupt - 16) & 31); + __asm(" dsb "); + __asm(" isb "); + } + +} + +//***************************************************************************** +// +//! Unpends an interrupt. +//! +//! \param ulInterrupt specifies the interrupt to be unpended. +//! +//! The specified interrupt is unpended in the interrupt controller. This will +//! cause any previously generated interrupts that have not been handled yet +//! (due to higher priority interrupts or the interrupt no having been enabled +//! yet) to be discarded. +//! +//! \return None. +// +//***************************************************************************** +void +IntPendClear(unsigned long ulInterrupt) +{ + // + // Check the arguments. + // + ASSERT(ulInterrupt < NUM_INTERRUPTS); + + // + // Determine the interrupt to unpend. + // + if(ulInterrupt == FAULT_PENDSV) + { + // + // Unpend the PendSV interrupt. + // + HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_UNPEND_SV; + } + else if(ulInterrupt == FAULT_SYSTICK) + { + // + // Unpend the SysTick interrupt. + // + HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR; + } + else if(ulInterrupt >= 16) + { + // + // Unpend the general interrupt. + // + HWREG(g_pulUnpendRegs[(ulInterrupt - 16) / 32]) = + 1 << ((ulInterrupt - 16) & 31); + } +} + +//***************************************************************************** +// +//! Sets the priority masking level +//! +//! \param ulPriorityMask is the priority level that will be masked. +//! +//! This function sets the interrupt priority masking level so that all +//! interrupts at the specified or lesser priority level is masked. This +//! can be used to globally disable a set of interrupts with priority below +//! a predetermined threshold. A value of 0 disables priority +//! masking. +//! +//! Smaller numbers correspond to higher interrupt priorities. So for example +//! a priority level mask of 4 will allow interrupts of priority level 0-3, +//! and interrupts with a numerical priority of 4 and greater will be blocked. +//! +//! The hardware priority mechanism will only look at the upper N bits of the +//! priority level (where N is 3), so any +//! prioritization must be performed in those bits. +//! +//! \return None. +// +//***************************************************************************** +void +IntPriorityMaskSet(unsigned long ulPriorityMask) +{ + CPUbasepriSet(ulPriorityMask); +} + +//***************************************************************************** +// +//! Gets the priority masking level +//! +//! This function gets the current setting of the interrupt priority masking +//! level. The value returned is the priority level such that all interrupts +//! of that and lesser priority are masked. A value of 0 means that priority +//! masking is disabled. +//! +//! Smaller numbers correspond to higher interrupt priorities. So for example +//! a priority level mask of 4 will allow interrupts of priority level 0-3, +//! and interrupts with a numerical priority of 4 and greater will be blocked. +//! +//! The hardware priority mechanism will only look at the upper N bits of the +//! priority level (where N is 3), so any +//! prioritization must be performed in those bits. +//! +//! \return Returns the value of the interrupt priority level mask. +// +//***************************************************************************** +unsigned long +IntPriorityMaskGet(void) +{ + return(CPUbasepriGet()); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/interrupt.h b/src/openmv/src/micropython/ports/cc3200/hal/interrupt.h new file mode 100755 index 0000000..941a60f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/interrupt.h @@ -0,0 +1,120 @@ +//***************************************************************************** +// +// interrupt.h +// +// Prototypes for the NVIC Interrupt Controller Driver. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __INTERRUPT_H__ +#define __INTERRUPT_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// A union that describes the entries of the vector table. The union is needed +// since the first entry is the stack pointer and the remainder are function +// pointers. +// +//***************************************************************************** +typedef union +{ + void (*pfnHandler)(void); + unsigned long ulPtr; +} +uVectorEntry; + + +//***************************************************************************** +// +// Macro to generate an interrupt priority mask based on the number of bits +// of priority supported by the hardware. +// +//***************************************************************************** +#define INT_PRIORITY_MASK ((0xFF << (8 - NUM_PRIORITY_BITS)) & 0xFF) + +//***************************************************************************** +// Interrupt priority levels +//***************************************************************************** +#define INT_PRIORITY_LVL_0 0x00 +#define INT_PRIORITY_LVL_1 0x20 +#define INT_PRIORITY_LVL_2 0x40 +#define INT_PRIORITY_LVL_3 0x60 +#define INT_PRIORITY_LVL_4 0x80 +#define INT_PRIORITY_LVL_5 0xA0 +#define INT_PRIORITY_LVL_6 0xC0 +#define INT_PRIORITY_LVL_7 0xE0 + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern tBoolean IntMasterEnable(void); +extern tBoolean IntMasterDisable(void); +extern void IntVTableBaseSet(unsigned long ulVtableBase); +extern void IntRegister(unsigned long ulInterrupt, void (*pfnHandler)(void)); +extern void IntUnregister(unsigned long ulInterrupt); +extern void IntPriorityGroupingSet(unsigned long ulBits); +extern unsigned long IntPriorityGroupingGet(void); +extern void IntPrioritySet(unsigned long ulInterrupt, + unsigned char ucPriority); +extern long IntPriorityGet(unsigned long ulInterrupt); +extern void IntEnable(unsigned long ulInterrupt); +extern void IntDisable(unsigned long ulInterrupt); +extern void IntPendSet(unsigned long ulInterrupt); +extern void IntPendClear(unsigned long ulInterrupt); +extern void IntPriorityMaskSet(unsigned long ulPriorityMask); +extern unsigned long IntPriorityMaskGet(void); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __INTERRUPT_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/pin.c b/src/openmv/src/micropython/ports/cc3200/hal/pin.c new file mode 100755 index 0000000..4130a43 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/pin.c @@ -0,0 +1,658 @@ +//***************************************************************************** +// +// pin.c +// +// Mapping of peripherals to pins. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup pin_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_ocp_shared.h" +#include "pin.h" + +//***************************************************************************** +// PIN to PAD matrix +//***************************************************************************** +static const unsigned long g_ulPinToPadMap[64] = +{ + 10,11,12,13,14,15,16,17,255,255,18, + 19,20,21,22,23,24,40,28,29,25,255, + 255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255, + 31,255,255,255,255,0,255,32,30,255,1, + 255,2,3,4,5,6,7,8,9 +}; + + +//***************************************************************************** +// +//! Configures pin mux for the specified pin. +//! +//! \param ulPin is a valid pin. +//! \param ulPinMode is one of the valid mode +//! +//! This function configures the pin mux that selects the peripheral function +//! associated with a particular SOC pin. Only one peripheral function at a +//! time can be associated with a pin, and each peripheral function should +//! only be associated with a single pin at a time. +//! +//! \return none +// +//***************************************************************************** +void PinModeSet(unsigned long ulPin,unsigned long ulPinMode) +{ + + unsigned long ulPad; + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + // + // Set the mode. + // + HWREG(ulPad) = (((HWREG(ulPad) & ~PAD_MODE_MASK) | ulPinMode) & ~(3<<10)); + +} + +//***************************************************************************** +// +//! Gets current pin mux configuration of specified pin. +//! +//! \param ulPin is a valid pin. +//! +//! This function get the current configuration of the pin mux. +//! +//! \return Returns current pin mode if \e ulPin is valid, 0xFF otherwise. +// +//***************************************************************************** +unsigned long PinModeGet(unsigned long ulPin) +{ + + unsigned long ulPad; + + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE) ; + + // + // return the mode. + // + return (HWREG(ulPad) & PAD_MODE_MASK); + +} + +//***************************************************************************** +// +//! Sets the direction of the specified pin(s). +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinIO is the pin direction and/or mode. +//! +//! This function configures the specified pin(s) as either input only or +//! output only or it configures the pin to be under hardware control. +//! +//! The parameter \e ulPinIO is an enumerated data type that can be one of +//! the following values: +//! +//! - \b PIN_DIR_MODE_IN +//! - \b PIN_DIR_MODE_OUT +//! - \b PIN_DIR_MODE_HW +//! +//! where \b PIN_DIR_MODE_IN specifies that the pin is programmed as a +//! input only, \b PIN_DIR_MODE_OUT specifies that the pin is +//! programmed output only, and \b PIN_DIR_MODE_HW specifies that the pin is +//! placed under hardware control. +//! +//! +//! \return None. +// +//***************************************************************************** +void PinDirModeSet(unsigned long ulPin, unsigned long ulPinIO) +{ + unsigned long ulPad; + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + // + // Set the direction + // + HWREG(ulPad) = ((HWREG(ulPad) & ~0xC00) | ulPinIO); +} + +//***************************************************************************** +// +//! Gets the direction of a pin. +//! +//! \param ulPin is one of the valid pin. +//! +//! This function gets the direction and control mode for a specified pin on +//! the selected GPIO port. The pin can be configured as either an input only +//! or output only, or it can be under hardware control. The type of control +//! and direction are returned as an enumerated data type. +//! +//! \return Returns one of the enumerated data types described for +//! GPIODirModeSet(). +// +//***************************************************************************** +unsigned long PinDirModeGet(unsigned long ulPin) +{ + unsigned long ulPad; + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + // + // Return the direction + // + return ((HWREG(ulPad) & 0xC00)); +} + +//***************************************************************************** +// +//! Gets Pin output drive strength and Type +//! +//! \param ulPin is one of the valid pin +//! \param pulPinStrength is pointer to storage for output drive strength +//! \param pulPinType is pinter to storage for pin type +//! +//! This function gets the pin type and output drive strength for the pin +//! specified by \e ulPin parameter. Parameters \e pulPinStrength and +//! \e pulPinType corresponds to the values used in PinConfigSet(). +//! +//! +//! \return None. +// +//***************************************************************************** +void PinConfigGet(unsigned long ulPin,unsigned long *pulPinStrength, + unsigned long *pulPinType) +{ + + unsigned long ulPad; + + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + + // + // Get the type + // + *pulPinType = (HWREG(ulPad) & PAD_TYPE_MASK); + + // + // Get the output drive strength + // + *pulPinStrength = (HWREG(ulPad) & PAD_STRENGTH_MASK); + +} + +//***************************************************************************** +// +//! Configure Pin output drive strength and Type +//! +//! \param ulPin is one of the valid pin +//! \param ulPinStrength is logical OR of valid output drive strengths. +//! \param ulPinType is one of the valid pin type. +//! +//! This function sets the pin type and strength for the pin specified by +//! \e ulPin parameter. +//! +//! The parameter \e ulPinStrength should be one of the following +//! - \b PIN_STRENGTH_2MA +//! - \b PIN_STRENGTH_4MA +//! - \b PIN_STRENGTH_6MA +//! +//! +//! The parameter \e ulPinType should be one of the following +//! For standard type +//! +//! - \b PIN_TYPE_STD +//! - \b PIN_TYPE_STD_PU +//! - \b PIN_TYPE_STD_PD +//! +//! And for Open drain type +//! +//! - \b PIN_TYPE_OD +//! - \b PIN_TYPE_OD_PU +//! - \b PIN_TYPE_OD_PD +//! +//! \return None. +// +//***************************************************************************** +void PinConfigSet(unsigned long ulPin,unsigned long ulPinStrength, + unsigned long ulPinType) +{ + + unsigned long ulPad; + + // + // Get the corresponding Pad + // + ulPad = g_ulPinToPadMap[ulPin & 0x3F]; + + // + // Write the register + // + if(ulPinType == PIN_TYPE_ANALOG) + { + // + // Isolate the input + // + HWREG(0x4402E144) |= ((0x80 << ulPad) & (0x1E << 8)); + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + // + // Isolate the output + // + HWREG(ulPad) = 0xC00; + + } + else + { + // + // Enable the input + // + HWREG(0x4402E144) &= ~((0x80 << ulPad) & (0x1E << 8)); + + // + // Calculate the register address + // + ulPad = ((ulPad << 2) + PAD_CONFIG_BASE); + + // + // Write the configuration + // + HWREG(ulPad) = ((HWREG(ulPad) & ~(PAD_STRENGTH_MASK | PAD_TYPE_MASK)) | + (ulPinStrength | ulPinType )); + } + + +} + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by UART peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The UART pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin(s); other configurations may work as well depending upon the +//! board setup (for example, using the on-chip pull-ups). +//! +//! +//! \note This function cannot be used to turn any pin into a UART pin; it +//! only sets the pin mode and configures it for proper UART operation. +//! +//! +//! \return None. +// +//***************************************************************************** +void PinTypeUART(unsigned long ulPin,unsigned long ulPinMode) +{ + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for standard operation + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA,PIN_TYPE_STD); +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by I2C peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The I2C pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! the pin. +//! +//! +//! \note This function cannot be used to turn any pin into a I2C pin; it +//! only sets the pin mode and configures it for proper I2C operation. +//! +//! +//! \return None. +// +//***************************************************************************** +void PinTypeI2C(unsigned long ulPin,unsigned long ulPinMode) +{ + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for open-drain operation with a weak pull-up. + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA,PIN_TYPE_OD_PU); +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by SPI peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The SPI pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \note This function cannot be used to turn any pin into a SPI pin; it +//! only sets the pin mode and configures it for proper SPI operation. +//! +//! +//! \return None. +// +//***************************************************************************** +void PinTypeSPI(unsigned long ulPin,unsigned long ulPinMode) +{ + + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for standard operation + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA|PIN_STRENGTH_4MA,PIN_TYPE_STD); + +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by I2S peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The I2S pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \note This function cannot be used to turn any pin into a I2S pin; it +//! only sets the pin mode and configures it for proper I2S operation. +//! +//! \return None. +// +//***************************************************************************** +void PinTypeI2S(unsigned long ulPin,unsigned long ulPinMode) +{ + + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for standard operation + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA|PIN_STRENGTH_4MA,PIN_TYPE_STD); + +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by Timer peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The timer PWM pins must be properly configured for the Timer peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin; other configurations may work as well depending upon the +//! board setup (for example, using the on-chip pull-ups). +//! +//! +//! \note This function cannot be used to turn any pin into a timer PWM pin; it +//! only sets the pin mode and configures it for proper timer PWM operation. +//! +//! \return None. +// +//***************************************************************************** +void PinTypeTimer(unsigned long ulPin,unsigned long ulPinMode) +{ + + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for standard operation + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA|PIN_STRENGTH_4MA,PIN_TYPE_STD); +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by Camera peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The Camera pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \note This function cannot be used to turn any pin into a Camera pin; it +//! only sets the pin mode and configures it for proper Camera operation. +//! +//! \return None. +// +//***************************************************************************** +void PinTypeCamera(unsigned long ulPin,unsigned long ulPinMode) +{ + + // + // Set the pin to specified mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Set the pin for standard operation + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA|PIN_STRENGTH_4MA,PIN_TYPE_STD); + +} + + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by GPIO peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! \param bOpenDrain is one to decide either OpenDrain or STD +//! +//! The GPIO pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \return None. +// +//***************************************************************************** +void PinTypeGPIO(unsigned long ulPin,unsigned long ulPinMode,tBoolean bOpenDrain) +{ + + // + // Set the pin for standard push-pull operation. + // + if(bOpenDrain) + { + PinConfigSet(ulPin, PIN_STRENGTH_2MA, PIN_TYPE_OD); + } + else + { + PinConfigSet(ulPin, PIN_STRENGTH_2MA, PIN_TYPE_STD); + } + + // + // Set the pin to specified mode + // + PinModeSet(ulPin, ulPinMode); + +} + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by ADC +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The ADC pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \note This function cannot be used to turn any pin into a ADC pin; it +//! only sets the pin mode and configures it for proper ADC operation. +//! +//! \return None. +// +//***************************************************************************** +void PinTypeADC(unsigned long ulPin,unsigned long ulPinMode) +{ + // + // Configure the Pin + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA,PIN_TYPE_ANALOG); +} + +//***************************************************************************** +// +//! Sets the pin mode and configures the pin for use by SD Host peripheral +//! +//! \param ulPin is one of the valid pin. +//! \param ulPinMode is one of the valid pin mode. +//! +//! The MMC pins must be properly configured for the peripheral to +//! function correctly. This function provides a typical configuration for +//! those pin. +//! +//! +//! \note This function cannot be used to turn any pin into a SD Host pin; it +//! only sets the pin mode and configures it for proper SD Host operation. +//! +//! \return None. +// +//***************************************************************************** +void PinTypeSDHost(unsigned long ulPin,unsigned long ulPinMode) +{ + // + // Set pin mode + // + PinModeSet(ulPin,ulPinMode); + + // + // Configure the Pin + // + PinConfigSet(ulPin,PIN_STRENGTH_2MA,PIN_TYPE_STD); + +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/pin.h b/src/openmv/src/micropython/ports/cc3200/hal/pin.h new file mode 100755 index 0000000..784e9f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/pin.h @@ -0,0 +1,183 @@ +//***************************************************************************** +// +// pin.h +// +// Defines and Macros for the pin mux module +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __PIN_H__ +#define __PIN_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// Macros Defining Pins +//***************************************************************************** + +#define PIN_01 0x00000000 +#define PIN_02 0x00000001 +#define PIN_03 0x00000002 +#define PIN_04 0x00000003 +#define PIN_05 0x00000004 +#define PIN_06 0x00000005 +#define PIN_07 0x00000006 +#define PIN_08 0x00000007 +#define PIN_11 0x0000000A +#define PIN_12 0x0000000B +#define PIN_13 0x0000000C +#define PIN_14 0x0000000D +#define PIN_15 0x0000000E +#define PIN_16 0x0000000F +#define PIN_17 0x00000010 +#define PIN_18 0x00000011 +#define PIN_19 0x00000012 +#define PIN_20 0x00000013 +#define PIN_21 0x00000014 +#define PIN_45 0x0000002C +#define PIN_46 0x0000002D +#define PIN_47 0x0000002E +#define PIN_48 0x0000002F +#define PIN_49 0x00000030 +#define PIN_50 0x00000031 +#define PIN_52 0x00000033 +#define PIN_53 0x00000034 +#define PIN_55 0x00000036 +#define PIN_56 0x00000037 +#define PIN_57 0x00000038 +#define PIN_58 0x00000039 +#define PIN_59 0x0000003A +#define PIN_60 0x0000003B +#define PIN_61 0x0000003C +#define PIN_62 0x0000003D +#define PIN_63 0x0000003E +#define PIN_64 0x0000003F + + + +//***************************************************************************** +// Macros that can be used with PinConfigSet(), PinTypeGet(), PinStrengthGet() +//***************************************************************************** + +#define PIN_MODE_0 0x00000000 +#define PIN_MODE_1 0x00000001 +#define PIN_MODE_2 0x00000002 +#define PIN_MODE_3 0x00000003 +#define PIN_MODE_4 0x00000004 +#define PIN_MODE_5 0x00000005 +#define PIN_MODE_6 0x00000006 +#define PIN_MODE_7 0x00000007 +#define PIN_MODE_8 0x00000008 +#define PIN_MODE_9 0x00000009 +#define PIN_MODE_10 0x0000000A +#define PIN_MODE_11 0x0000000B +#define PIN_MODE_12 0x0000000C +#define PIN_MODE_13 0x0000000D +#define PIN_MODE_14 0x0000000E +#define PIN_MODE_15 0x0000000F +// Note : PIN_MODE_255 is a dummy define for pinmux utility code generation +// PIN_MODE_255 should never be used in any user code. +#define PIN_MODE_255 0x000000FF + +//***************************************************************************** +// Macros that can be used with PinDirModeSet() and returned from +// PinDirModeGet(). +//***************************************************************************** +#define PIN_DIR_MODE_IN 0x00000C00 // Pin is input +#define PIN_DIR_MODE_OUT 0x00000800 // Pin is output +#define PIN_DIR_MODE_HW 0x00000000 // Pin is peripheral function + +//***************************************************************************** +// Macros that can be used with PinConfigSet() +//***************************************************************************** +#define PIN_STRENGTH_2MA 0x00000020 +#define PIN_STRENGTH_4MA 0x00000040 +#define PIN_STRENGTH_6MA 0x00000060 + +#define PIN_TYPE_STD 0x00000000 +#define PIN_TYPE_STD_PU 0x00000100 +#define PIN_TYPE_STD_PD 0x00000200 + +#define PIN_TYPE_OD 0x00000010 +#define PIN_TYPE_OD_PU 0x00000110 +#define PIN_TYPE_OD_PD 0x00000210 +#define PIN_TYPE_ANALOG 0x10000000 + +//***************************************************************************** +// Macros for mode and type +//***************************************************************************** +#define PAD_MODE_MASK 0x0000000F +#define PAD_STRENGTH_MASK 0x000000E0 +#define PAD_TYPE_MASK 0x00000310 +#define PAD_CONFIG_BASE ((OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0)) + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void PinModeSet(unsigned long ulPin, unsigned long ulPinMode); +extern void PinDirModeSet(unsigned long ulPin, unsigned long ulPinIO); +extern unsigned long PinDirModeGet(unsigned long ulPin); +extern unsigned long PinModeGet(unsigned long ulPin); +extern void PinConfigGet(unsigned long ulPin,unsigned long *pulPinStrength, + unsigned long *pulPinType); +extern void PinConfigSet(unsigned long ulPin,unsigned long ulPinStrength, + unsigned long ulPinType); +extern void PinTypeUART(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeI2C(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeSPI(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeI2S(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeTimer(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeCamera(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeGPIO(unsigned long ulPin,unsigned long ulPinMode, + tBoolean bOpenDrain); +extern void PinTypeADC(unsigned long ulPin,unsigned long ulPinMode); +extern void PinTypeSDHost(unsigned long ulPin,unsigned long ulPinMode); + + +#ifdef __cplusplus +} +#endif + +#endif //__PIN_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/prcm.c b/src/openmv/src/micropython/ports/cc3200/hal/prcm.c new file mode 100755 index 0000000..4b66c0f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/prcm.c @@ -0,0 +1,1953 @@ +//***************************************************************************** +// +// prcm.c +// +// Driver for the Power, Reset and Clock Module (PRCM) +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup PRCM_Power_Reset_Clock_Module_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_apps_rcm.h" +#include "inc/hw_gprcm.h" +#include "inc/hw_hib1p2.h" +#include "inc/hw_hib3p3.h" +#include "prcm.h" +#include "interrupt.h" +#include "cpu.h" +#include "utils.h" +#include "rom_map.h" + + +//***************************************************************************** +// Macro definition +//***************************************************************************** +#define PRCM_SOFT_RESET 0x00000001 +#define PRCM_ENABLE_STATUS 0x00000002 +#define SYS_CLK 80000000 +#define XTAL_CLK 40000000 + + +//***************************************************************************** +// CC3200 does not have a true RTC capability. However, API(s) in this file +// provide an effective mechanism to support RTC feature in the device. +// +// The implementation to support RTC has been kept very simple. A set of +// HIB Memory Registers in conjunction with Slow Clock Counter are used +// to render RTC information to users. Core principle of design involves +// two steps (a) establish an association between user provided wall-clock +// and slow clock counter. (b) store reference value of this associattion +// in HIB Registers. This reference value and SCC value are then combined +// to create real-world calendar time. +// +// Across HIB cycles, value stored in HIB Registers is retained and slow +// clock counter continues to tick, thereby, this arragement is relevant +// and valid as long as device has a (tickle) battery power. +// +// Further, provision also has been made to set an alarm. When it RTC value +// matches that of set for alarm, an interrupt is generated. +// +// HIB MEM REG0 and REG1 are reserved for TI. +// +// If RTC feature is not used, then HIB REG2 & REG3 are available to user. +// +// Lower half of REG0 is used for TI HW ECO. +//***************************************************************************** +#define RTC_U64MSEC_MK(u32Secs, u16Msec) (((unsigned long long)u32Secs << 10)|\ + (u16Msec & 0x3FF)) + +#define RTC_SECS_IN_U64MSEC(u64Msec) ((unsigned long)(u64Msec >> 10)) +#define RTC_MSEC_IN_U64MSEC(u64Msec) ((unsigned short)(u64Msec & 0x3FF)) + +#define RTC_MSEC_U32_REG_ADDR (HIB3P3_BASE + HIB3P3_O_MEM_HIB_REG2) +#define RTC_SECS_U32_REG_ADDR (HIB3P3_BASE + HIB3P3_O_MEM_HIB_REG3) + +//***************************************************************************** +// Register Access and Updates +// +// Tick of SCC has a resolution of 32768Hz, meaning 1 sec is equal to 32768 +// clock ticks. Ideal way of getting time in millisecond will involve floating +// point arithmetic (division by 32.768). To avoid this, we simply divide it by +// 32, which will give a range from 0 -1023(instead of 0-999). To use this +// output correctly we have to take care of this inaccuracy externally. +// following wrapper can be used to convert the value from cycles to +// millisecond: +// +// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024), +// +// Similarly, before setting the value, it must be first converted (from ms to +// cycles). +// +// U16MS_CYCLES(msec) ((msec * 1024) / 1000) +// +// Note: There is a precision loss of 1 ms with the above scheme. +// +// +#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5) +#define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5)) +#define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5) + +//***************************************************************************** +// +// Bit: 31 is used to indicate use of RTC. If set as '1', RTC feature is used. +// Bit: 30 is used to indicate that a safe boot should be performed. +// bit: 29 is used to indicate that the last reset was caused by the WDT. +// bit: 28 is used to indicate that the board is booting for the first time after being programmed in factory. +// Bits: 27 and 26 are unused. +// Bits: 25 to 16 are used to save millisecond part of RTC reference. +// Bits: 15 to 0 are being used for HW Changes / ECO. +// +//***************************************************************************** + +//***************************************************************************** +// Set RTC USE Bit +//***************************************************************************** +static void RTCUseSet(void) +{ + unsigned int uiRegValue; + + uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) | (1 << 31); + + PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue); +} + +//***************************************************************************** +// Clear RTC USE Bit +//***************************************************************************** +static void RTCUseClear(void) +{ + unsigned int uiRegValue; + + uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(1 << 31)); + + PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue); +} + +//***************************************************************************** +// Checks if RTC-USE bit is set +//***************************************************************************** +static tBoolean IsRTCUsed(void) +{ + return (MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (1 << 31)) ? true : false; +} + +//***************************************************************************** +// Read 16-bit mSecs +//***************************************************************************** +static unsigned short RTCU32MSecRegRead(void) +{ + return ((MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) >> 16) & 0x03FF); +} + +//***************************************************************************** +// Write 16-bit mSecs +//***************************************************************************** +static void RTCU32MSecRegWrite(unsigned int u32Msec) +{ + unsigned int uiRegValue; + + // read the whole register and clear the msec bits + uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(0x03FF << 16)); + + // write the msec bits only + MAP_PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue | ((u32Msec & 0x03FF) << 16)); +} + +//***************************************************************************** +// Read 32-bit Secs +//***************************************************************************** +static unsigned long RTCU32SecRegRead(void) +{ + return (MAP_PRCMHIBRegRead(RTC_SECS_U32_REG_ADDR)); +} + +//***************************************************************************** +// Write 32-bit Secs +//***************************************************************************** +static void RTCU32SecRegWrite(unsigned long u32Msec) +{ + MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec); +} + +//***************************************************************************** +// Fast function to get the most accurate RTC counter value +//***************************************************************************** +static unsigned long long RTCFastDomainCounterGet (void) { + + #define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \ + itr++; \ + break; \ + } + + unsigned long long rtc_count1, rtc_count2, rtc_count3; + unsigned int itr; + + do { + rtc_count1 = PRCMSlowClkCtrFastGet(); + rtc_count2 = PRCMSlowClkCtrFastGet(); + rtc_count3 = PRCMSlowClkCtrFastGet(); + itr = 0; + + BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1); + BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2); + BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1); + + // Consistent values in two consecutive reads implies a correct + // value of the counter. Do note, the counter does not give the + // calendar time but a hardware that ticks upwards continuously. + // The 48-bit counter operates at 32,768 HZ. + + } while (true); + + return (1 == itr) ? rtc_count2 : rtc_count3; +} + +//***************************************************************************** +// Macros +//***************************************************************************** +#define IS_RTC_USED() IsRTCUsed() +#define RTC_USE_SET() RTCUseSet() +#define RTC_USE_CLR() RTCUseClear() + +#define RTC_U32MSEC_REG_RD() RTCU32MSecRegRead() +#define RTC_U32MSEC_REG_WR(u32Msec) RTCU32MSecRegWrite(u32Msec) + +#define RTC_U32SECS_REG_RD() RTCU32SecRegRead() +#define RTC_U32SECS_REG_WR(u32Secs) RTCU32SecRegWrite(u32Secs) + +#define SELECT_SCC_U42BITS(u64Msec) (u64Msec & 0x3ffffffffff) + +//***************************************************************************** +// Global Peripheral clock and rest Registers +//***************************************************************************** +static const PRCM_PeriphRegs_t PRCM_PeriphRegsList[] = +{ + + {APPS_RCM_O_CAMERA_CLK_GATING, APPS_RCM_O_CAMERA_SOFT_RESET }, + {APPS_RCM_O_MCASP_CLK_GATING, APPS_RCM_O_MCASP_SOFT_RESET }, + {APPS_RCM_O_MMCHS_CLK_GATING, APPS_RCM_O_MMCHS_SOFT_RESET }, + {APPS_RCM_O_MCSPI_A1_CLK_GATING, APPS_RCM_O_MCSPI_A1_SOFT_RESET }, + {APPS_RCM_O_MCSPI_A2_CLK_GATING, APPS_RCM_O_MCSPI_A2_SOFT_RESET }, + {APPS_RCM_O_UDMA_A_CLK_GATING, APPS_RCM_O_UDMA_A_SOFT_RESET }, + {APPS_RCM_O_GPIO_A_CLK_GATING, APPS_RCM_O_GPIO_A_SOFT_RESET }, + {APPS_RCM_O_GPIO_B_CLK_GATING, APPS_RCM_O_GPIO_B_SOFT_RESET }, + {APPS_RCM_O_GPIO_C_CLK_GATING, APPS_RCM_O_GPIO_C_SOFT_RESET }, + {APPS_RCM_O_GPIO_D_CLK_GATING, APPS_RCM_O_GPIO_D_SOFT_RESET }, + {APPS_RCM_O_GPIO_E_CLK_GATING, APPS_RCM_O_GPIO_E_SOFT_RESET }, + {APPS_RCM_O_WDOG_A_CLK_GATING, APPS_RCM_O_WDOG_A_SOFT_RESET }, + {APPS_RCM_O_UART_A0_CLK_GATING, APPS_RCM_O_UART_A0_SOFT_RESET }, + {APPS_RCM_O_UART_A1_CLK_GATING, APPS_RCM_O_UART_A1_SOFT_RESET }, + {APPS_RCM_O_GPT_A0_CLK_GATING , APPS_RCM_O_GPT_A0_SOFT_RESET }, + {APPS_RCM_O_GPT_A1_CLK_GATING, APPS_RCM_O_GPT_A1_SOFT_RESET }, + {APPS_RCM_O_GPT_A2_CLK_GATING, APPS_RCM_O_GPT_A2_SOFT_RESET }, + {APPS_RCM_O_GPT_A3_CLK_GATING, APPS_RCM_O_GPT_A3_SOFT_RESET }, + {APPS_RCM_O_CRYPTO_CLK_GATING, APPS_RCM_O_CRYPTO_SOFT_RESET }, + {APPS_RCM_O_MCSPI_S0_CLK_GATING, APPS_RCM_O_MCSPI_S0_SOFT_RESET }, + {APPS_RCM_O_I2C_CLK_GATING, APPS_RCM_O_I2C_SOFT_RESET } + +}; + +//***************************************************************************** +// +//! Set a special bit +//! +//! \return None. +// +//***************************************************************************** +void PRCMSetSpecialBit(unsigned char bit) +{ + unsigned int uiRegValue; + + uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) | (1 << bit); + + PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue); +} + +//***************************************************************************** +// +//! Clear a special bit +//! +//! \return None. +// +//***************************************************************************** +void PRCMClearSpecialBit(unsigned char bit) +{ + unsigned int uiRegValue; + + uiRegValue = MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (~(1 << bit)); + + PRCMHIBRegWrite(RTC_MSEC_U32_REG_ADDR, uiRegValue); +} + +//***************************************************************************** +// +//! Read a special bit +//! +//! \return Value of the bit +// +//***************************************************************************** +tBoolean PRCMGetSpecialBit(unsigned char bit) +{ + tBoolean value = (MAP_PRCMHIBRegRead(RTC_MSEC_U32_REG_ADDR) & (1 << bit)) ? true : false; + // special bits must be cleared immediatelly after reading + PRCMClearSpecialBit(bit); + return value; +} + +//***************************************************************************** +// +//! Performs a software reset of a SOC +//! +//! This function performs a software reset of a SOC +//! +//! \return None. +// +//***************************************************************************** +void PRCMSOCReset(void) +{ + // + // Reset MCU + // + HWREG(GPRCM_BASE+ GPRCM_O_MCU_GLOBAL_SOFT_RESET) |= 0x1; + +} + +//***************************************************************************** +// +//! Performs a software reset of a MCU and associated peripherals +//! +//! \param bIncludeSubsystem is \b true to reset associated peripherals. +//! +//! This function performs a software reset of a MCU and associated peripherals. +//! To reset the associated peripheral, the parameter \e bIncludeSubsystem +//! should be set to \b true. +//! +//! \return None. +// +//***************************************************************************** +void PRCMMCUReset(tBoolean bIncludeSubsystem) +{ + if(bIncludeSubsystem) + { + // + // Reset Apps processor and associated peripheral + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SOFT_RESET) = 0x2; + } + else + { + // + // Reset Apps processor only + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SOFT_RESET) = 0x1; + } +} + +//***************************************************************************** +// +//! Gets the reason for a reset. +//! +//! This function returns the reason(s) for a reset. The reset reason are:- +//! -\b PRCM_POWER_ON - Device is powering up. +//! -\b PRCM_LPDS_EXIT - Device is exiting from LPDS. +//! -\b PRCM_CORE_RESET - Device is exiting soft core only reset +//! -\b PRCM_MCU_RESET - Device is exiting soft subsystem reset. +//! -\b PRCM_WDT_RESET - Device was reset by watchdog. +//! -\b PRCM_SOC_RESET - Device is exting SOC reset. +//! -\b PRCM_HIB_EXIT - Device is exiting hibernate. +//! +//! \return Returns one of the cause defined above. +// +//***************************************************************************** +unsigned long PRCMSysResetCauseGet(void) +{ + unsigned long ulWakeupStatus; + + // + // Read the Reset status + // + ulWakeupStatus = (HWREG(GPRCM_BASE+ GPRCM_O_APPS_RESET_CAUSE) & 0xFF); + + // + // For hibernate do additional chaeck. + // + if(ulWakeupStatus == PRCM_POWER_ON) + { + if(MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_WAKE_STATUS) & 0x1) + { + ulWakeupStatus = PRCM_HIB_EXIT; + } + } + + // + // Return status. + // + return ulWakeupStatus; +} + +//***************************************************************************** +// +//! Enable clock(s) to peripheral. +//! +//! \param ulPeripheral is one of the valid peripherals +//! \param ulClkFlags are bitmask of clock(s) to be enabled. +//! +//! This function enables the clock for the specified peripheral. Peripherals +//! are by default clock gated (disabled) and generates a bus fault if +//! accessed. +//! +//! The parameter \e ulClkFlags can be logical OR of the following: +//! -\b PRCM_RUN_MODE_CLK - Ungates clock to the peripheral +//! -\b PRCM_SLP_MODE_CLK - Keeps the clocks ungated in sleep. +//! -\b PRCM_DSLP_MODE_CLK - Keeps the clock ungated in deepsleep. +//! +//! \return None. +// +//***************************************************************************** +void PRCMPeripheralClkEnable(unsigned long ulPeripheral, unsigned long ulClkFlags) +{ + // + // Enable the specified peripheral clocks, Nothing to be done for PRCM_ADC + // as it is a dummy define for pinmux utility code generation + // + if(ulPeripheral != PRCM_ADC) + { + HWREG(ARCM_BASE + PRCM_PeriphRegsList[ulPeripheral].ulClkReg) |= ulClkFlags; + } + // + // Set the default clock for camera + // + if(ulPeripheral == PRCM_CAMERA) + { + HWREG(ARCM_BASE + APPS_RCM_O_CAMERA_CLK_GEN) = 0x0404; + } +} + +//***************************************************************************** +// +//! Disables clock(s) to peripheral. +//! +//! \param ulPeripheral is one of the valid peripherals +//! \param ulClkFlags are bitmask of clock(s) to be enabled. +//! +//! This function disable the clock for the specified peripheral. Peripherals +//! are by default clock gated (disabled) and generated a bus fault if +//! accessed. +//! +//! The parameter \e ulClkFlags can be logical OR bit fields as defined in +//! PRCMEnablePeripheral(). +//! +//! \return None. +// +//***************************************************************************** +void PRCMPeripheralClkDisable(unsigned long ulPeripheral, unsigned long ulClkFlags) +{ + // + // Disable the specified peripheral clocks + // + HWREG(ARCM_BASE + PRCM_PeriphRegsList[ulPeripheral].ulClkReg) &= ~ulClkFlags; +} + +//***************************************************************************** +// +//! Gets the input clock for the specified peripheral. +//! +//! \param ulPeripheral is one of the valid peripherals. +//! +//! This function gets the input clock for the specified peripheral. +//! +//! The parameter \e ulPeripheral has the same definition as that in +//! PRCMPeripheralClkEnable(); +//! +//! \return Returns input clock frequency for specified peripheral. +// +//***************************************************************************** +unsigned long PRCMPeripheralClockGet(unsigned long ulPeripheral) +{ + unsigned long ulClockFreq; + unsigned long ulHiPulseDiv; + unsigned long ulLoPulseDiv; + + // + // Get the clock based on specified peripheral. + // + if(((ulPeripheral == PRCM_SSPI) | (ulPeripheral == PRCM_LSPI) + | (ulPeripheral == PRCM_GSPI))) + { + return XTAL_CLK; + } + else if(ulPeripheral == PRCM_CAMERA) + { + ulHiPulseDiv = ((HWREG(ARCM_BASE + APPS_RCM_O_CAMERA_CLK_GEN) >> 8) & 0x07); + ulLoPulseDiv = (HWREG(ARCM_BASE + APPS_RCM_O_CAMERA_CLK_GEN)& 0xFF); + } + else if(ulPeripheral == PRCM_SDHOST) + { + ulHiPulseDiv = ((HWREG(ARCM_BASE + APPS_RCM_O_MMCHS_CLK_GEN) >> 8) & 0x07); + ulLoPulseDiv = (HWREG(ARCM_BASE + APPS_RCM_O_MMCHS_CLK_GEN)& 0xFF); + } + else + { + return SYS_CLK; + } + + // + // Compute the clock freq. from the divider value + // + ulClockFreq = (240000000/((ulHiPulseDiv + 1) + (ulLoPulseDiv + 1))); + + // + // Return the clock rate. + // + return ulClockFreq; +} + +//***************************************************************************** +// +//! Performs a software reset of a peripheral. +//! +//! \param ulPeripheral is one of the valid peripheral. +//! +//! This assert or deassert reset to the specified peripheral based of the +//! \e bAssert parameter. +//! +//! \return None. +// +//***************************************************************************** +void PRCMPeripheralReset(unsigned long ulPeripheral) +{ + volatile unsigned long ulDelay; + + if( ulPeripheral != PRCM_DTHE) + { + // + // Assert the reset + // + HWREG(ARCM_BASE + PRCM_PeriphRegsList[ulPeripheral].ulRstReg) + |= PRCM_SOFT_RESET; + // + // Delay for a little bit. + // + for(ulDelay = 0; ulDelay < 16; ulDelay++) + { + } + + // + // Deassert the reset + // + HWREG(ARCM_BASE+PRCM_PeriphRegsList[ulPeripheral].ulRstReg) + &= ~PRCM_SOFT_RESET; + } +} + +//***************************************************************************** +// +//! Determines if a peripheral is ready. +//! +//! \param ulPeripheral is one of the valid modules +//! +//! This function determines if a particular peripheral is ready to be +//! accessed. The peripheral may be in a non-ready state if it is not enabled, +//! is being held in reset, or is in the process of becoming ready after being +//! enabled or taken out of reset. +//! +//! \return Returns \b true if the peripheral is ready, \b false otherwise. +// +//***************************************************************************** +tBoolean PRCMPeripheralStatusGet(unsigned long ulPeripheral) +{ + unsigned long ReadyBit; + + // + // Read the ready bit status + // + ReadyBit = HWREG(ARCM_BASE + PRCM_PeriphRegsList[ulPeripheral].ulRstReg); + ReadyBit = ReadyBit & PRCM_ENABLE_STATUS; + + if (ReadyBit) + { + // + // Module is ready + // + return(true); + } + else + { + // + // Module is not ready + // + return(false); + } +} + +//***************************************************************************** +// +//! Configure I2S fracactional divider +//! +//! \param ulI2CClkFreq is the required input clock for McAPS module +//! +//! This function configures I2S fractional divider. By default this +//! divider is set to output 24 Mhz clock to I2S module. +//! +//! The minimum frequency that can be obtained by configuring this divider is +//! +//! (240000KHz/1023.99) = 234.377 KHz +//! +//! \return None. +// +//***************************************************************************** +void PRCMI2SClockFreqSet(unsigned long ulI2CClkFreq) +{ + unsigned long long ullDiv; + unsigned short usInteger; + unsigned short usFrac; + + ullDiv = (((unsigned long long)240000000 * 65536)/ulI2CClkFreq); + + usInteger = (ullDiv/65536); + usFrac = (ullDiv%65536); + + HWREG(ARCM_BASE + APPS_RCM_O_MCASP_FRAC_CLK_CONFIG0) = + ((usInteger & 0x3FF) << 16 | usFrac); +} + +//***************************************************************************** +// +//! Sets the LPDS exit PC and SP restore vlaues. +//! +//! \param ulStackPtr is the SP restore value. +//! \param ulProgCntr is the PC restore value +//! +//! This function sets the LPDS exit PC and SP restore vlaues. Setting +//! \e ulProgCntr to a non-zero value, forces bootloader to jump to that +//! address with Stack Pointer initialized to \e ulStackPtr on LPDS exit, +//! otherwise the application's vector table entries are used. +//! +//! \return None. +// +//***************************************************************************** +void PRCMLPDSRestoreInfoSet(unsigned long ulStackPtr, unsigned long ulProgCntr) +{ + // + // Set The SP Value + // + HWREG(0x4402E18C) = ulStackPtr; + + // + // Set The PC Value + // + HWREG(0x4402E190) = ulProgCntr; +} + +//***************************************************************************** +// +//! Puts the system into Low Power Deel Sleep (LPDS) power mode. +//! +//! This function puts the system into Low Power Deel Sleep (LPDS) power mode. +//! A call to this function never returns and the execution starts from Reset. +//! \sa PRCMLPDSRestoreInfoSet(). +//! +//! \return None. +//! +//! \note The Test Power Domain is shutdown whenever the system +//! enters LPDS (by default). In order to avoid this and allow for +//! connecting back the debugger after waking up from LPDS, +//! the macro KEEP_TESTPD_ALIVE has to be defined while building the library. +//! This is recommended for development purposes only as it adds to +//! the current consumption of the system. +//! +// +//***************************************************************************** +void PRCMLPDSEnter(void) +{ +#ifndef DEBUG + // + // Disable TestPD + // + HWREG(0x4402E168) |= (1<<9); +#endif + + // + // Set bandgap duty cycle to 1 + // + HWREG(HIB1P2_BASE + HIB1P2_O_BGAP_DUTY_CYCLING_EXIT_CFG) = 0x1; + + // + // Request LPDS + // + HWREG(ARCM_BASE + APPS_RCM_O_APPS_LPDS_REQ) = APPS_RCM_APPS_LPDS_REQ_APPS_LPDS_REQ; + + __asm(" nop\n" + " nop\n" + " nop\n" + " nop\n"); +} + +//***************************************************************************** +// +//! Enable the individual LPDS wakeup source(s). +//! +//! \param ulLpdsWakeupSrc is logical OR of wakeup sources. +//! +//! This function enable the individual LPDS wakeup source(s) and following +//! three wakeup sources (\e ulLpdsWakeupSrc ) are supported by the device. +//! -\b PRCM_LPDS_HOST_IRQ +//! -\b PRCM_LPDS_GPIO +//! -\b PRCM_LPDS_TIMER +//! +//! \return None. +// +//***************************************************************************** +void PRCMLPDSWakeupSourceEnable(unsigned long ulLpdsWakeupSrc) +{ + unsigned long ulRegVal; + + // + // Read the current wakup sources + // + ulRegVal = HWREG(GPRCM_BASE+ GPRCM_O_APPS_LPDS_WAKEUP_CFG); + + // + // Enable individual wakeup source + // + ulRegVal = ((ulRegVal | ulLpdsWakeupSrc) & 0x91); + + // + // Set the configuration in the register + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_LPDS_WAKEUP_CFG) = ulRegVal; +} + +//***************************************************************************** +// +//! Disable the individual LPDS wakeup source(s). +//! +//! \param ulLpdsWakeupSrc is logical OR of wakeup sources. +//! +//! This function enable the individual LPDS wakeup source(s) and following +//! three wake up sources (\e ulLpdsWakeupSrc ) are supported by the device. +//! -\b PRCM_LPDS_HOST_IRQ +//! -\b PRCM_LPDS_GPIO +//! -\b PRCM_LPDS_TIMER +//! +//! \return None. +// +//***************************************************************************** +void PRCMLPDSWakeupSourceDisable(unsigned long ulLpdsWakeupSrc) +{ + HWREG(GPRCM_BASE+ GPRCM_O_APPS_LPDS_WAKEUP_CFG) &= ~ulLpdsWakeupSrc; +} + + +//***************************************************************************** +// +//! Get LPDS wakeup cause +//! +//! This function gets LPDS wakeup caouse +//! +//! \return Returns values enumerated as described in +//! PRCMLPDSWakeupSourceEnable(). +// +//***************************************************************************** +unsigned long PRCMLPDSWakeupCauseGet(void) +{ + return (HWREG(GPRCM_BASE+ GPRCM_O_APPS_LPDS_WAKEUP_SRC)); +} + +//***************************************************************************** +// +//! Sets LPDS wakeup Timer +//! +//! \param ulTicks is number of 32.768 KHz clocks +//! +//! This function sets internal LPDS wakeup timer running at 32.768 KHz. The +//! timer is only configured if the parameter \e ulTicks is in valid range i.e. +//! from 21 to 2^32. +//! +//! \return Returns \b true on success, \b false otherwise. +// +//***************************************************************************** +void PRCMLPDSIntervalSet(unsigned long ulTicks) +{ + // + // Check sleep is atleast for 21 cycles + // If not set the sleep time to 21 cycles + // + if( ulTicks < 21) + { + ulTicks = 21; + } + + HWREG(GPRCM_BASE + GPRCM_O_APPS_LPDS_WAKETIME_WAKE_CFG) = ulTicks; + HWREG(GPRCM_BASE + GPRCM_O_APPS_LPDS_WAKETIME_OPP_CFG) = ulTicks-20; +} + +//***************************************************************************** +// +//! Selects the GPIO for LPDS wakeup +//! +//! \param ulGPIOPin is one of the valid GPIO fro LPDS wakeup. +//! \param ulType is the wakeup trigger type. +//! +//! This function setects the wakeup GPIO for LPDS wakeup and can be +//! used to select one out of 7 pre-defined GPIO(s). +//! +//! The parameter \e ulLpdsGPIOSel should be one of the following:- +//! -\b PRCM_LPDS_GPIO2 +//! -\b PRCM_LPDS_GPIO4 +//! -\b PRCM_LPDS_GPIO13 +//! -\b PRCM_LPDS_GPIO17 +//! -\b PRCM_LPDS_GPIO11 +//! -\b PRCM_LPDS_GPIO24 +//! -\b PRCM_LPDS_GPIO26 +//! +//! The parameter \e ulType sets the trigger type and can be one of the +//! following: +//! - \b PRCM_LPDS_LOW_LEVEL +//! - \b PRCM_LPDS_HIGH_LEVEL +//! - \b PRCM_LPDS_FALL_EDGE +//! - \b PRCM_LPDS_RISE_EDGE +//! +//! \return None. +// +//***************************************************************************** +void PRCMLPDSWakeUpGPIOSelect(unsigned long ulGPIOPin, unsigned long ulType) +{ + // + // Set the wakeup GPIO + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE + HIB3P3_O_MEM_HIB_LPDS_GPIO_SEL, ulGPIOPin); + + // + // Set the trigger type. + // + HWREG(GPRCM_BASE + GPRCM_O_APPS_GPIO_WAKE_CONF) = (ulType & 0x3); +} + +//***************************************************************************** +// +//! Puts the system into Sleep. +//! +//! This function puts the system into sleep power mode. System exits the power +//! state on any one of the available interrupt. On exit from sleep mode the +//! function returns to the calling function with all the processor core +//! registers retained. +//! +//! \return None. +// +//***************************************************************************** +void PRCMSleepEnter(void) +{ + // + // Request Sleep + // + CPUwfi(); +} + +//***************************************************************************** +// +//! Puts the system into Deep Sleep power mode. +//! +//! This function puts the system into Deep Sleep power mode. System exits the +//! power state on any one of the available interrupt. On exit from deep +//! sleep the function returns to the calling function with all the processor +//! core registers retained. +//! +//! \return None. +// +//***************************************************************************** +void PRCMDeepSleepEnter(void) +{ + // + // Set bandgap duty cycle to 1 + // + HWREG(HIB1P2_BASE + HIB1P2_O_BGAP_DUTY_CYCLING_EXIT_CFG) = 0x1; + + // + // Enable DSLP in cortex + // + HWREG(0xE000ED10)|=1<<2; + + // + // Request Deep Sleep + // + CPUwfi(); + + // + // Disable DSLP in cortex before + // returning to the caller + // + HWREG(0xE000ED10) &= ~(1<<2); + +} + +//***************************************************************************** +// +//! Enable SRAM column retention during Deep Sleep and/or LPDS Power mode(s) +//! +//! \param ulSramColSel is bit mask of valid SRAM columns. +//! \param ulModeFlags is the bit mask of power modes. +//! +//! This functions enables the SRAM retention. The device supports configurable +//! SRAM column retention in Low Power Deep Sleep (LPDS) and Deep Sleep power +//! modes. Each column is of 64 KB size. +//! +//! The parameter \e ulSramColSel should be logical OR of the following:- +//! -\b PRCM_SRAM_COL_1 +//! -\b PRCM_SRAM_COL_2 +//! -\b PRCM_SRAM_COL_3 +//! -\b PRCM_SRAM_COL_4 +//! +//! The parameter \e ulModeFlags selects the power modes and sholud be logical +//! OR of one or more of the following +//! -\b PRCM_SRAM_DSLP_RET +//! -\b PRCM_SRAM_LPDS_RET +//! +//! \return None. +// +//**************************************************************************** +void PRCMSRAMRetentionEnable(unsigned long ulSramColSel, unsigned long ulModeFlags) +{ + if(ulModeFlags & PRCM_SRAM_DSLP_RET) + { + // + // Configure deep sleep SRAM retention register + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SRAM_DSLP_CFG) = (ulSramColSel & 0xF); + } + + if(ulModeFlags & PRCM_SRAM_LPDS_RET) + { + // + // Configure LPDS SRAM retention register + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SRAM_LPDS_CFG) = (ulSramColSel & 0xF); + } +} + +//***************************************************************************** +// +//! Disable SRAM column retention during Deep Sleep and/or LPDS Power mode(s). +//! +//! \param ulSramColSel is bit mask of valid SRAM columns. +//! \param ulFlags is the bit mask of power modes. +//! +//! This functions disable the SRAM retention. The device supports configurable +//! SRAM column retention in Low Power Deep Sleep (LPDS) and Deep Sleep power +//! modes. Each column is of 64 KB size. +//! +//! The parameter \e ulSramColSel should be logical OR of the following:- +//! -\b PRCM_SRAM_COL_1 +//! -\b PRCM_SRAM_COL_2 +//! -\b PRCM_SRAM_COL_3 +//! -\b PRCM_SRAM_COL_4 +//! +//! The parameter \e ulFlags selects the power modes and sholud be logical OR +//! of one or more of the following +//! -\b PRCM_SRAM_DSLP_RET +//! -\b PRCM_SRAM_LPDS_RET +//! +//! \return None. +// +//**************************************************************************** +void PRCMSRAMRetentionDisable(unsigned long ulSramColSel, unsigned long ulFlags) +{ + if(ulFlags & PRCM_SRAM_DSLP_RET) + { + // + // Configure deep sleep SRAM retention register + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SRAM_DSLP_CFG) &= ~(ulSramColSel & 0xF); + } + + if(ulFlags & PRCM_SRAM_LPDS_RET) + { + // + // Configure LPDS SRAM retention register + // + HWREG(GPRCM_BASE+ GPRCM_O_APPS_SRAM_LPDS_CFG) &= ~(ulSramColSel & 0xF); + } +} + + +//***************************************************************************** +// +//! Enables individual HIB wakeup source(s). +//! +//! \param ulHIBWakupSrc is logical OR of valid HIB wakeup sources. +//! +//! This function enables individual HIB wakeup source(s). The paramter +//! \e ulHIBWakupSrc is the bit mask of HIB wakeup sources and should be +//! logical OR of one or more of the follwoing :- +//! -\b PRCM_HIB_SLOW_CLK_CTR +//! -\b PRCM_HIB_GPIO2 +//! -\b PRCM_HIB_GPIO4 +//! -\b PRCM_HIB_GPIO13 +//! -\b PRCM_HIB_GPIO17 +//! -\b PRCM_HIB_GPIO11 +//! -\b PRCM_HIB_GPIO24 +//! -\b PRCM_HIB_GPIO26 +//! +//! \return None. +// +//***************************************************************************** +void PRCMHibernateWakeupSourceEnable(unsigned long ulHIBWakupSrc) +{ + unsigned long ulRegValue; + + // + // Read the RTC register + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_EN); + + // + // Enable the RTC as wakeup source if specified + // + ulRegValue |= (ulHIBWakupSrc & 0x1); + + // + // Enable HIB wakeup sources + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_EN,ulRegValue); + + // + // REad the GPIO wakeup configuration register + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_GPIO_WAKE_EN); + + // + // Enable the specified GPIOs a wakeup sources + // + ulRegValue |= ((ulHIBWakupSrc>>16)&0xFF); + + // + // Write the new register configuration + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_GPIO_WAKE_EN,ulRegValue); +} + +//***************************************************************************** +// +//! Disable individual HIB wakeup source(s). +//! +//! \param ulHIBWakupSrc is logical OR of valid HIB wakeup sources. +//! +//! This function disable individual HIB wakeup source(s). The paramter +//! \e ulHIBWakupSrc is same as bit fileds defined in +//! PRCMEnableHibernateWakeupSource() +//! +//! \return None. +// +//***************************************************************************** +void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc) +{ + unsigned long ulRegValue; + + // + // Read the RTC register + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_EN); + + // + // Disable the RTC as wakeup source if specified + // + ulRegValue &= ~(ulHIBWakupSrc & 0x1); + + // + // Disable HIB wakeup sources + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_EN,ulRegValue); + + // + // Read the GPIO wakeup configuration register + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_GPIO_WAKE_EN); + + // + // Enable the specified GPIOs a wakeup sources + // + ulRegValue &= ~((ulHIBWakupSrc>>16)&0xFF); + + // + // Write the new register configuration + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_GPIO_WAKE_EN,ulRegValue); +} + + +//***************************************************************************** +// +//! Get hibernate wakeup cause +//! +//! This function gets the hibernate wakeup cause. +//! +//! \return Returns \b PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK or +//! \b PRCM_HIB_WAKEUP_CAUSE_GPIO +// +//***************************************************************************** +unsigned long PRCMHibernateWakeupCauseGet(void) +{ + return ((MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_WAKE_STATUS)>>1)&0xF); +} + +//***************************************************************************** +// +//! Sets Hibernate wakeup Timer +//! +//! \param ullTicks is number of 32.768 KHz clocks +//! +//! This function sets internal hibernate wakeup timer running at 32.768 KHz. +//! +//! \return Returns \b true on success, \b false otherwise. +// +//***************************************************************************** +void PRCMHibernateIntervalSet(unsigned long long ullTicks) +{ + unsigned long long ullRTCVal; + + // + // Latch the RTC vlaue + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_TIMER_READ ,0x1); + + // + // Read latched values as 2 32-bit vlaues + // + ullRTCVal = MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_TIMER_MSW); + ullRTCVal = ullRTCVal << 32; + ullRTCVal |= MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_TIMER_LSW); + + // + // Add the interval + // + ullRTCVal = ullRTCVal + ullTicks; + + // + // Set RTC match value + // + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_LSW_CONF, + (unsigned long)(ullRTCVal)); + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_RTC_WAKE_MSW_CONF, + (unsigned long)(ullRTCVal>>32)); +} + + +//***************************************************************************** +// +//! Selects the GPIO(s) for hibernate wakeup +//! +//! \param ulGPIOBitMap is the bit-map of valid hibernate wakeup GPIO. +//! \param ulType is the wakeup trigger type. +//! +//! This function setects the wakeup GPIO for hibernate and can be +//! used to select any combination of 7 pre-defined GPIO(s). +//! +//! This function enables individual HIB wakeup source(s). The paramter +//! \e ulGPIOBitMap should be one of the follwoing :- +//! -\b PRCM_HIB_GPIO2 +//! -\b PRCM_HIB_GPIO4 +//! -\b PRCM_HIB_GPIO13 +//! -\b PRCM_HIB_GPIO17 +//! -\b PRCM_HIB_GPIO11 +//! -\b PRCM_HIB_GPIO24 +//! -\b PRCM_HIB_GPIO26 +//! +//! The parameter \e ulType sets the trigger type and can be one of the +//! following: +//! - \b PRCM_HIB_LOW_LEVEL +//! - \b PRCM_HIB_HIGH_LEVEL +//! - \b PRCM_HIB_FALL_EDGE +//! - \b PRCM_HIB_RISE_EDGE +//! +//! \return None. +// +//***************************************************************************** +void PRCMHibernateWakeUpGPIOSelect(unsigned long ulGPIOBitMap, unsigned long ulType) +{ + unsigned char ucLoop; + unsigned long ulRegValue; + + // + // Shift the bits to extract the GPIO selection + // + ulGPIOBitMap >>= 16; + + // + // Set the configuration for each GPIO + // + for(ucLoop=0; ucLoop < 7; ucLoop++) + { + if(ulGPIOBitMap & (1<>32)); +} + +//***************************************************************************** +// +//! Gets slow clock counter match value. +//! +//! This function gets the match value for slow clock counter. This is use +//! to interrupt the processor when RTC counts to the specified value. +//! +//! \return None. +// +//***************************************************************************** +unsigned long long PRCMSlowClkCtrMatchGet(void) +{ + unsigned long long ullValue; + + // + // Get RTC match value + // + ullValue = MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_MSW_CONF); + ullValue = ullValue<<32; + ullValue |= MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_LSW_CONF); + + // + // Return the value + // + return ullValue; +} + + +//***************************************************************************** +// +//! Write to On-Chip Retention (OCR) register. +//! +//! This function writes to On-Chip retention register. The device supports two +//! 4-byte OCR register which are retained across all power mode. +//! +//! The parameter \e ucIndex is an index of the OCR and can be \b 0 or \b 1. +//! +//! \return None. +// +//***************************************************************************** +void PRCMOCRRegisterWrite(unsigned char ucIndex, unsigned long ulRegValue) +{ + MAP_PRCMHIBRegWrite(HIB3P3_BASE+HIB3P3_O_MEM_HIB_REG2+(ucIndex << 2),ulRegValue); +} + +//***************************************************************************** +// +//! Read from On-Chip Retention (OCR) register. +//! +//! This function reads from On-Chip retention register. The device supports two +//! 4-byte OCR register which are retained across all power mode. +//! +//! The parameter \e ucIndex is an index of the OCR and can be \b 0 or \b 1. +//! +//! \return None. +// +//***************************************************************************** +unsigned long PRCMOCRRegisterRead(unsigned char ucIndex) +{ + // + // Return the read value. + // + return MAP_PRCMHIBRegRead(HIB3P3_BASE+HIB3P3_O_MEM_HIB_REG2 + (ucIndex << 2)); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the PRCM. +//! +//! \param pfnHandler is a pointer to the function to be called when the +//! interrupt is activated. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; +//! +//! \return None. +// +//***************************************************************************** +void PRCMIntRegister(void (*pfnHandler)(void)) +{ + // + // Register the interrupt handler. + // + IntRegister(INT_PRCM, pfnHandler); + + // + // Enable the PRCM interrupt. + // + IntEnable(INT_PRCM); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the PRCM. +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a PRCM interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \return None. +// +//***************************************************************************** +void PRCMIntUnregister(void) +{ + // + // Enable the UART interrupt. + // + IntDisable(INT_PRCM); + + // + // Register the interrupt handler. + // + IntUnregister(INT_PRCM); +} + +//***************************************************************************** +// +//! Enables individual PRCM interrupt sources. +//! +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated ARCM interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! -\b PRCM_INT_SLOW_CLK_CTR +//! +// +//***************************************************************************** +void PRCMIntEnable(unsigned long ulIntFlags) +{ + unsigned long ulRegValue; + + if(ulIntFlags & PRCM_INT_SLOW_CLK_CTR ) + { + // + // Enable PRCM interrupt + // + HWREG(ARCM_BASE + APPS_RCM_O_APPS_RCM_INTERRUPT_ENABLE) |= 0x4; + + // + // Enable RTC interrupt + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE); + ulRegValue |= 0x1; + MAP_PRCMHIBRegWrite(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE, ulRegValue); + } +} + +//***************************************************************************** +// +//! Disables individual PRCM interrupt sources. +//! +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! This function disables the indicated ARCM interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to PRCMEnableInterrupt(). +//! +//! \return None. +// +//***************************************************************************** +void PRCMIntDisable(unsigned long ulIntFlags) +{ + unsigned long ulRegValue; + + if(ulIntFlags & PRCM_INT_SLOW_CLK_CTR ) + { + // + // Disable PRCM interrupt + // + HWREG(ARCM_BASE + APPS_RCM_O_APPS_RCM_INTERRUPT_ENABLE) &= ~0x4; + + // + // Disable RTC interrupt + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE); + ulRegValue &= ~0x1; + MAP_PRCMHIBRegWrite(HIB3P3_BASE + HIB3P3_O_MEM_HIB_RTC_IRQ_ENABLE, ulRegValue); + } +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! This function returns the PRCM interrupt status of interrupts that are +//! allowed to reflect to the processor. The interrupts are cleared on read. +//! +//! \return Returns the current interrupt status. +// +//***************************************************************************** +unsigned long PRCMIntStatus(void) +{ + return HWREG(ARCM_BASE + APPS_RCM_O_APPS_RCM_INTERRUPT_STATUS); +} + +//***************************************************************************** +// +//! Mark the function of RTC as being used +//! +//! This function marks in HW that feature to maintain calendar time in device +//! is being used. +//! +//! Specifically, this feature reserves user's HIB Register-1 accessed through +//! PRCMOCRRegisterWrite(1) for internal work / purpose, therefore, the stated +//! register is not available to user. Also, users must not excercise the Slow +//! Clock Counter API(s), if RTC has been set for use. +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCInUseSet(void) +{ + RTC_USE_SET(); + return; +} + +//***************************************************************************** +// +//! Clear the function of RTC as being used +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCInUseClear(void) +{ + RTC_USE_CLR(); + return; +} + +//***************************************************************************** +// +//! Ascertain whether function of RTC is being used +//! +//! This function indicates whether function of RTC is being used on the device +//! or not. +//! +//! This routine should be utilized by the application software, when returning +//! from low-power, to confirm that RTC has been put to use and may not need to +//! set the value of the RTC. +//! +//! The RTC feature, if set or marked, can be only reset either through reboot +//! or power cycle. +//! +//! \return None. +// +//***************************************************************************** +tBoolean PRCMRTCInUseGet(void) +{ + return IS_RTC_USED()? true : false; +} + +//***************************************************************************** +// +//! Set the calendar time in the device. +//! +//! \param ulSecs refers to the seconds part of the calendar time +//! \param usMsec refers to the fractional (ms) part of the second +//! +//! This function sets the specified calendar time in the device. The calendar +//! time is outlined in terms of seconds and milliseconds. However, the device +//! makes no assumption about the origin or reference of the calendar time. +//! +//! The device uses the indicated calendar value to update and maintain the +//! wall-clock time across active and low power states. +//! +//! The function PRCMRTCInUseSet() must be invoked prior to use of this feature. +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCSet(unsigned long ulSecs, unsigned short usMsec) +{ + unsigned long long ullMsec = 0; + + if(IS_RTC_USED()) { + ullMsec = RTC_U64MSEC_MK(ulSecs, usMsec) - SCC_U64MSEC_GET(); + + RTC_U32SECS_REG_WR(RTC_SECS_IN_U64MSEC(ullMsec)); + RTC_U32MSEC_REG_WR(RTC_MSEC_IN_U64MSEC(ullMsec)); + } + + return; +} + +//***************************************************************************** +// +//! Get the instantaneous calendar time from the device. +//! +//! \param ulSecs refers to the seconds part of the calendar time +//! \param usMsec refers to the fractional (ms) part of the second +//! +//! This function fetches the instantaneous value of the ticking calendar time +//! from the device. The calendar time is outlined in terms of seconds and +//! milliseconds. +//! +//! The device provides the calendar value that has been maintained across +//! active and low power states. +//! +//! The function PRCMRTCSet() must have been invoked once to set a reference. +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCGet(unsigned long *ulSecs, unsigned short *usMsec) +{ + unsigned long long ullMsec = 0; + + if(IS_RTC_USED()) { + ullMsec = RTC_U64MSEC_MK(RTC_U32SECS_REG_RD(), + RTC_U32MSEC_REG_RD()); + ullMsec += SCC_U64MSEC_GET(); + } + + *ulSecs = RTC_SECS_IN_U64MSEC(ullMsec); + *usMsec = RTC_MSEC_IN_U64MSEC(ullMsec); + + return; +} + +//***************************************************************************** +// +//! Set a calendar time alarm. +//! +//! \param ulSecs refers to the seconds part of the calendar time +//! \param usMsec refers to the fractional (ms) part of the second +//! +//! This function sets an wall-clock alarm in the device to be reported for a +//! futuristic calendar time. The calendar time is outlined in terms of seconds +//! and milliseconds. +//! +//! The device provides uses the calendar value that has been maintained across +//! active and low power states to report attainment of alarm time. +//! +//! The function PRCMRTCSet() must have been invoked once to set a reference. +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCMatchSet(unsigned long ulSecs, unsigned short usMsec) +{ + unsigned long long ullMsec = 0; + + if(IS_RTC_USED()) { + ullMsec = RTC_U64MSEC_MK(ulSecs, usMsec); + ullMsec -= RTC_U64MSEC_MK(RTC_U32SECS_REG_RD(), + RTC_U32MSEC_REG_RD()); + SCC_U64MSEC_MATCH_SET(SELECT_SCC_U42BITS(ullMsec)); + } + + return; +} + +//***************************************************************************** +// +//! Get a previously set calendar time alarm. +//! +//! \param ulSecs refers to the seconds part of the calendar time +//! \param usMsec refers to the fractional (ms) part of the second +//! +//! This function fetches from the device a wall-clock alarm that would have +//! been previously set in the device. The calendar time is outlined in terms +//! of seconds and milliseconds. +//! +//! If no alarm was set in the past, then this function would fetch a random +//! information. +//! +//! The function PRCMRTCMatchSet() must have been invoked once to set an alarm. +//! +//! \return None. +// +//***************************************************************************** +void PRCMRTCMatchGet(unsigned long *ulSecs, unsigned short *usMsec) +{ + unsigned long long ullMsec = 0; + + if(IS_RTC_USED()) { + ullMsec = SCC_U64MSEC_MATCH_GET(); + ullMsec += RTC_U64MSEC_MK(RTC_U32SECS_REG_RD(), + RTC_U32MSEC_REG_RD()); + } + + *ulSecs = RTC_SECS_IN_U64MSEC(ullMsec); + *usMsec = RTC_MSEC_IN_U64MSEC(ullMsec); + + return; +} + +//***************************************************************************** +// +//! MCU Initialization Routine +//! +//! This function sets mandatory configurations for the MCU +//! +//! \return None +// +//***************************************************************************** +void PRCMCC3200MCUInit(void) +{ + unsigned long ulRegValue; + + // + // DIG DCDC LPDS ECO Enable + // + HWREG(0x4402F064) |= 0x800000; + + // + // Enable hibernate ECO for PG 1.32 devices only. With this ECO enabled, + // any hibernate wakeup source will be kept masked until the device enters + // hibernate completely (analog + digital) + // + ulRegValue = MAP_PRCMHIBRegRead(HIB3P3_BASE + HIB3P3_O_MEM_HIB_REG0); + MAP_PRCMHIBRegWrite(HIB3P3_BASE + HIB3P3_O_MEM_HIB_REG0, ulRegValue | (1<<4)); + + // + // Handling the clock switching (for 1.32 only) + // + HWREG(0x4402E16C) |= 0x3C; + + // + // Enable uDMA + // + MAP_PRCMPeripheralClkEnable(PRCM_UDMA,PRCM_RUN_MODE_CLK); + + // + // Reset uDMA + // + MAP_PRCMPeripheralReset(PRCM_UDMA); + + // + // Disable uDMA + // + MAP_PRCMPeripheralClkDisable(PRCM_UDMA,PRCM_RUN_MODE_CLK); + + // + // Enable RTC + // + if(MAP_PRCMSysResetCauseGet()== PRCM_POWER_ON) + { + MAP_PRCMHIBRegWrite(0x4402F804,0x1); + } + + // + // SWD mode + // + if (((HWREG(0x4402F0C8) & 0xFF) == 0x2)) + { + HWREG(0x4402E110) = ((HWREG(0x4402E110) & ~0xC0F) | 0x2); + HWREG(0x4402E114) = ((HWREG(0x4402E110) & ~0xC0F) | 0x2); + } + + // + // Override JTAG mux + // + HWREG(0x4402E184) |= 0x2; + + // + // Change UART pins(55,57) mode to PIN_MODE_0 if they are in PIN_MODE_1 + // + if ((HWREG(0x4402E0A4) & 0xF) == 0x1) + { + HWREG(0x4402E0A4) = ((HWREG(0x4402E0A4) & ~0xF)); + } + + if ((HWREG(0x4402E0A8) & 0xF) == 0x1) + { + HWREG(0x4402E0A8) = ((HWREG(0x4402E0A8) & ~0xF)); + } + + // + // DIG DCDC VOUT trim settings based on PROCESS INDICATOR + // + if (((HWREG(0x4402DC78) >> 22) & 0xF) == 0xE) + { + HWREG(0x4402F0B0) = ((HWREG(0x4402F0B0) & ~(0x00FC0000))|(0x32 << 18)); + } + else + { + HWREG(0x4402F0B0) = ((HWREG(0x4402F0B0) & ~(0x00FC0000))|(0x29 << 18)); + } + + // + // Enable SOFT RESTART in case of DIG DCDC collapse + // + HWREG(0x4402FC74) &= ~(0x10000000); + + + // + // Disable the sleep for ANA DCDC + // + HWREG(0x4402F0A8) |= 0x00000004 ; +} + +//***************************************************************************** +// +//! Reads 32-bit value from register at specified address +//! +//! \param ulRegAddr is the address of register to be read. +//! +//! This function reads 32-bit value from the register as specified by +//! \e ulRegAddr. +//! +//! \return Return the value of the register. +// +//***************************************************************************** +unsigned long PRCMHIBRegRead(unsigned long ulRegAddr) +{ + unsigned long ulValue; + + // + // Read the Reg value + // + ulValue = HWREG(ulRegAddr); + + // + // Wait for 200 uSec + // + UtilsDelay((80*200)/3); + + // + // Return the value + // + return ulValue; +} + +//***************************************************************************** +// +//! Writes 32-bit value to register at specified address +//! +//! \param ulRegAddr is the address of register to be read. +//! \param ulValue is the 32-bit value to be written. +//! +//! This function writes 32-bit value passed as \e ulValue to the register as +//! specified by \e ulRegAddr +//! +//! \return None +// +//***************************************************************************** +void PRCMHIBRegWrite(unsigned long ulRegAddr, unsigned long ulValue) +{ + // + // Read the Reg value + // + HWREG(ulRegAddr) = ulValue; + + // + // Wait for 200 uSec + // + UtilsDelay((80*200)/3); +} + +//***************************************************************************** +// +//! \param ulDivider is clock frequency divider value +//! \param ulWidth is the width of the high pulse +//! +//! This function sets the input frequency for camera module. +//! +//! The frequency is calculated as follows: +//! +//! f_out = 240MHz/ulDivider; +//! +//! The parameter \e ulWidth sets the width of the high pulse. +//! +//! For e.g.: +//! +//! ulDivider = 4; +//! ulWidth = 2; +//! +//! f_out = 30 MHz and 50% duty cycle +//! +//! And, +//! +//! ulDivider = 4; +//! ulWidth = 1; +//! +//! f_out = 30 MHz and 25% duty cycle +//! +//! \return 0 on success, 1 on error +// +//***************************************************************************** +unsigned long PRCMCameraFreqSet(unsigned char ulDivider, unsigned char ulWidth) +{ + if(ulDivider > ulWidth && ulWidth != 0 ) + { + // + // Set the hifh pulse width + // + HWREG(ARCM_BASE + + APPS_RCM_O_CAMERA_CLK_GEN) = (((ulWidth & 0x07) -1) << 8); + + // + // Set the low pulse width + // + HWREG(ARCM_BASE + + APPS_RCM_O_CAMERA_CLK_GEN) = ((ulDivider - ulWidth - 1) & 0x07); + // + // Return success + // + return 0; + } + + // + // Success; + // + return 1; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/prcm.h b/src/openmv/src/micropython/ports/cc3200/hal/prcm.h new file mode 100755 index 0000000..2f700ae --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/prcm.h @@ -0,0 +1,285 @@ +//***************************************************************************** +// +// prcm.h +// +// Prototypes for the PRCM control driver. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __PRCM_H__ +#define __PRCM_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Peripheral clock and reset control registers +// +//***************************************************************************** +typedef struct _PRCM_PeripheralRegs_ +{ + +unsigned char ulClkReg; +unsigned char ulRstReg; + +}PRCM_PeriphRegs_t; + +//***************************************************************************** +// Values that can be passed to PRCMPeripheralEnable() and +// PRCMPeripheralDisable() +//***************************************************************************** +#define PRCM_RUN_MODE_CLK 0x00000001 +#define PRCM_SLP_MODE_CLK 0x00000100 +#define PRCM_DSLP_MODE_CLK 0x00010000 + +//***************************************************************************** +// Values that can be passed to PRCMSRAMRetentionEnable() and +// PRCMSRAMRetentionDisable() as ulSramColSel. +//***************************************************************************** +#define PRCM_SRAM_COL_1 0x00000001 +#define PRCM_SRAM_COL_2 0x00000002 +#define PRCM_SRAM_COL_3 0x00000004 +#define PRCM_SRAM_COL_4 0x00000008 + +//***************************************************************************** +// Values that can be passed to PRCMSRAMRetentionEnable() and +// PRCMSRAMRetentionDisable() as ulModeFlags. +//***************************************************************************** +#define PRCM_SRAM_DSLP_RET 0x00000001 +#define PRCM_SRAM_LPDS_RET 0x00000002 + +//***************************************************************************** +// Values that can be passed to PRCMLPDSWakeupSourceEnable(), +// PRCMLPDSWakeupCauseGet() and PRCMLPDSWakeupSourceDisable(). +//***************************************************************************** +#define PRCM_LPDS_HOST_IRQ 0x00000080 +#define PRCM_LPDS_GPIO 0x00000010 +#define PRCM_LPDS_TIMER 0x00000001 + +//***************************************************************************** +// Values that can be passed to PRCMLPDSWakeUpGPIOSelect() as Type +//***************************************************************************** +#define PRCM_LPDS_LOW_LEVEL 0x00000002 +#define PRCM_LPDS_HIGH_LEVEL 0x00000000 +#define PRCM_LPDS_FALL_EDGE 0x00000001 +#define PRCM_LPDS_RISE_EDGE 0x00000003 + +//***************************************************************************** +// Values that can be passed to PRCMLPDSWakeUpGPIOSelect() +//***************************************************************************** +#define PRCM_LPDS_GPIO2 0x00000000 +#define PRCM_LPDS_GPIO4 0x00000001 +#define PRCM_LPDS_GPIO13 0x00000002 +#define PRCM_LPDS_GPIO17 0x00000003 +#define PRCM_LPDS_GPIO11 0x00000004 +#define PRCM_LPDS_GPIO24 0x00000005 +#define PRCM_LPDS_GPIO26 0x00000006 + +//***************************************************************************** +// Values that can be passed to PRCMHibernateWakeupSourceEnable(), +// PRCMHibernateWakeupSourceDisable(). +//***************************************************************************** +#define PRCM_HIB_SLOW_CLK_CTR 0x00000001 + +//***************************************************************************** +// Values that can be passed to PRCMHibernateWakeUpGPIOSelect() as ulType +//***************************************************************************** +#define PRCM_HIB_LOW_LEVEL 0x00000000 +#define PRCM_HIB_HIGH_LEVEL 0x00000001 +#define PRCM_HIB_FALL_EDGE 0x00000002 +#define PRCM_HIB_RISE_EDGE 0x00000003 + +//***************************************************************************** +// Values that can be passed to PRCMHibernateWakeupSourceEnable(), +// PRCMHibernateWakeupSourceDisable(), PRCMHibernateWakeUpGPIOSelect() +//***************************************************************************** +#define PRCM_HIB_GPIO2 0x00010000 +#define PRCM_HIB_GPIO4 0x00020000 +#define PRCM_HIB_GPIO13 0x00040000 +#define PRCM_HIB_GPIO17 0x00080000 +#define PRCM_HIB_GPIO11 0x00100000 +#define PRCM_HIB_GPIO24 0x00200000 +#define PRCM_HIB_GPIO26 0x00400000 + +//***************************************************************************** +// Values that will be returned from PRCMSysResetCauseGet(). +//***************************************************************************** +#define PRCM_POWER_ON 0x00000000 +#define PRCM_LPDS_EXIT 0x00000001 +#define PRCM_CORE_RESET 0x00000003 +#define PRCM_MCU_RESET 0x00000004 +#define PRCM_WDT_RESET 0x00000005 +#define PRCM_SOC_RESET 0x00000006 +#define PRCM_HIB_EXIT 0x00000007 + +//***************************************************************************** +// Values that can be passed to PRCMHibernateWakeupCauseGet(). +//***************************************************************************** +#define PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK 0x00000002 +#define PRCM_HIB_WAKEUP_CAUSE_GPIO 0x00000004 + +//***************************************************************************** +// Values that can be passed to PRCMIntEnable +//***************************************************************************** +#define PRCM_INT_SLOW_CLK_CTR 0x00004000 + +//***************************************************************************** +// Values that can be passed to PRCMPeripheralClkEnable(), +// PRCMPeripheralClkDisable(), PRCMPeripheralReset() +//***************************************************************************** +#define PRCM_CAMERA 0x00000000 +#define PRCM_I2S 0x00000001 +#define PRCM_SDHOST 0x00000002 +#define PRCM_GSPI 0x00000003 +#define PRCM_LSPI 0x00000004 +#define PRCM_UDMA 0x00000005 +#define PRCM_GPIOA0 0x00000006 +#define PRCM_GPIOA1 0x00000007 +#define PRCM_GPIOA2 0x00000008 +#define PRCM_GPIOA3 0x00000009 +#define PRCM_GPIOA4 0x0000000A +#define PRCM_WDT 0x0000000B +#define PRCM_UARTA0 0x0000000C +#define PRCM_UARTA1 0x0000000D +#define PRCM_TIMERA0 0x0000000E +#define PRCM_TIMERA1 0x0000000F +#define PRCM_TIMERA2 0x00000010 +#define PRCM_TIMERA3 0x00000011 +#define PRCM_DTHE 0x00000012 +#define PRCM_SSPI 0x00000013 +#define PRCM_I2CA0 0x00000014 +// Note : PRCM_ADC is a dummy define for pinmux utility code generation +// PRCM_ADC should never be used in any user code. +#define PRCM_ADC 0x000000FF + +//***************************************************************************** +// User bits in the PRCM persistent registers +//***************************************************************************** +#define PRCM_SAFE_BOOT_BIT 30 +#define PRCM_WDT_RESET_BIT 29 +#define PRCM_FIRST_BOOT_BIT 28 + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void PRCMSetSpecialBit(unsigned char bit); +extern void PRCMClearSpecialBit(unsigned char bit); +extern tBoolean PRCMGetSpecialBit(unsigned char bit); +extern void PRCMSOCReset(void); +extern void PRCMMCUReset(tBoolean bIncludeSubsystem); +extern unsigned long PRCMSysResetCauseGet(void); + +extern void PRCMPeripheralClkEnable(unsigned long ulPeripheral, + unsigned long ulClkFlags); +extern void PRCMPeripheralClkDisable(unsigned long ulPeripheral, + unsigned long ulClkFlags); +extern void PRCMPeripheralReset(unsigned long ulPeripheral); +extern tBoolean PRCMPeripheralStatusGet(unsigned long ulPeripheral); + +extern void PRCMI2SClockFreqSet(unsigned long ulI2CClkFreq); +extern unsigned long PRCMPeripheralClockGet(unsigned long ulPeripheral); + +extern void PRCMSleepEnter(void); +extern void PRCMDeepSleepEnter(void); + +extern void PRCMSRAMRetentionEnable(unsigned long ulSramColSel, + unsigned long ulFlags); +extern void PRCMSRAMRetentionDisable(unsigned long ulSramColSel, + unsigned long ulFlags); +extern void PRCMLPDSRestoreInfoSet(unsigned long ulRestoreSP, + unsigned long ulRestorePC); +extern void PRCMLPDSEnter(void); +extern void PRCMLPDSIntervalSet(unsigned long ulTicks); +extern void PRCMLPDSWakeupSourceEnable(unsigned long ulLpdsWakeupSrc); +extern unsigned long PRCMLPDSWakeupCauseGet(void); +extern void PRCMLPDSWakeUpGPIOSelect(unsigned long ulGPIOPin, + unsigned long ulType); +extern void PRCMLPDSWakeupSourceDisable(unsigned long ulLpdsWakeupSrc); + +extern void PRCMHibernateEnter(void); +extern void PRCMHibernateWakeupSourceEnable(unsigned long ulHIBWakupSrc); +extern unsigned long PRCMHibernateWakeupCauseGet(void); +extern void PRCMHibernateWakeUpGPIOSelect(unsigned long ulMultiGPIOBitMap, + unsigned long ulType); +extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc); +extern void PRCMHibernateIntervalSet(unsigned long long ullTicks); + +extern unsigned long long PRCMSlowClkCtrGet(void); +extern unsigned long long PRCMSlowClkCtrFastGet(void); +extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks); +extern unsigned long long PRCMSlowClkCtrMatchGet(void); + +extern void PRCMOCRRegisterWrite(unsigned char ucIndex, + unsigned long ulRegValue); +extern unsigned long PRCMOCRRegisterRead(unsigned char ucIndex); + +extern void PRCMIntRegister(void (*pfnHandler)(void)); +extern void PRCMIntUnregister(void); +extern void PRCMIntEnable(unsigned long ulIntFlags); +extern void PRCMIntDisable(unsigned long ulIntFlags); +extern unsigned long PRCMIntStatus(void); +extern void PRCMRTCInUseSet(void); +extern void PRCMRTCInUseClear(void); +extern tBoolean PRCMRTCInUseGet(void); +extern void PRCMRTCSet(unsigned long ulSecs, unsigned short usMsec); +extern void PRCMRTCGet(unsigned long *ulSecs, unsigned short *usMsec); +extern void PRCMRTCMatchSet(unsigned long ulSecs, unsigned short usMsec); +extern void PRCMRTCMatchGet(unsigned long *ulSecs, unsigned short *usMsec); +extern void PRCMCC3200MCUInit(void); +extern unsigned long PRCMHIBRegRead(unsigned long ulRegAddr); +extern void PRCMHIBRegWrite(unsigned long ulRegAddr, unsigned long ulValue); +extern unsigned long PRCMCameraFreqSet(unsigned char ulDivider, unsigned char ulWidth); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __PRCM_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/rom.h b/src/openmv/src/micropython/ports/cc3200/hal/rom.h new file mode 100755 index 0000000..33a18b6 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/rom.h @@ -0,0 +1,2237 @@ +//***************************************************************************** +// +// rom.h +// +// Macros to facilitate calling functions in the ROM. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 AN AUTO-GENERATED FILE. DO NOT EDIT BY HAND. +// +//***************************************************************************** + +#ifndef __ROM_H__ +#define __ROM_H__ + +//***************************************************************************** +// +// Pointers to the main API tables. +// +//***************************************************************************** +#define ROM_APITABLE ((unsigned long *)0x0000040C) +#define ROM_VERSION (ROM_APITABLE[0]) +#define ROM_UARTTABLE ((unsigned long *)(ROM_APITABLE[1])) +#define ROM_TIMERTABLE ((unsigned long *)(ROM_APITABLE[2])) +#define ROM_WATCHDOGTABLE ((unsigned long *)(ROM_APITABLE[3])) +#define ROM_INTERRUPTTABLE ((unsigned long *)(ROM_APITABLE[4])) +#define ROM_UDMATABLE ((unsigned long *)(ROM_APITABLE[5])) +#define ROM_PRCMTABLE ((unsigned long *)(ROM_APITABLE[6])) +#define ROM_I2CTABLE ((unsigned long *)(ROM_APITABLE[7])) +#define ROM_SPITABLE ((unsigned long *)(ROM_APITABLE[8])) +#define ROM_CAMERATABLE ((unsigned long *)(ROM_APITABLE[9])) +#define ROM_FLASHTABLE ((unsigned long *)(ROM_APITABLE[10])) +#define ROM_PINTABLE ((unsigned long *)(ROM_APITABLE[11])) +#define ROM_SYSTICKTABLE ((unsigned long *)(ROM_APITABLE[12])) +#define ROM_UTILSTABLE ((unsigned long *)(ROM_APITABLE[13])) +#define ROM_I2STABLE ((unsigned long *)(ROM_APITABLE[14])) +#define ROM_HWSPINLOCKTABLE ((unsigned long *)(ROM_APITABLE[15])) +#define ROM_GPIOTABLE ((unsigned long *)(ROM_APITABLE[16])) +#define ROM_AESTABLE ((unsigned long *)(ROM_APITABLE[17])) +#define ROM_DESTABLE ((unsigned long *)(ROM_APITABLE[18])) +#define ROM_SHAMD5TABLE ((unsigned long *)(ROM_APITABLE[19])) +#define ROM_CRCTABLE ((unsigned long *)(ROM_APITABLE[20])) +#define ROM_SDHOSTTABLE ((unsigned long *)(ROM_APITABLE[21])) +#define ROM_ADCTABLE ((unsigned long *)(ROM_APITABLE[22])) + +//***************************************************************************** +// +// Macros for calling ROM functions in the Interrupt API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_IntEnable \ + ((void (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntMasterEnable \ + ((tBoolean (*)(void))ROM_INTERRUPTTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntMasterDisable \ + ((tBoolean (*)(void))ROM_INTERRUPTTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntDisable \ + ((void (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPriorityGroupingSet \ + ((void (*)(unsigned long ulBits))ROM_INTERRUPTTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPriorityGroupingGet \ + ((unsigned long (*)(void))ROM_INTERRUPTTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPrioritySet \ + ((void (*)(unsigned long ulInterrupt, \ + unsigned char ucPriority))ROM_INTERRUPTTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPriorityGet \ + ((long (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPendSet \ + ((void (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPendClear \ + ((void (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPriorityMaskSet \ + ((void (*)(unsigned long ulPriorityMask))ROM_INTERRUPTTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntPriorityMaskGet \ + ((unsigned long (*)(void))ROM_INTERRUPTTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntRegister \ + ((void (*)(unsigned long ulInterrupt, \ + void (*pfnHandler)(void)))ROM_INTERRUPTTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntUnregister \ + ((void (*)(unsigned long ulInterrupt))ROM_INTERRUPTTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_IntVTableBaseSet \ + ((void (*)(unsigned long ulVtableBase))ROM_INTERRUPTTABLE[14]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the Timer API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_TimerEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerConfigure \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulConfig))ROM_TIMERTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerControlLevel \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + tBoolean bInvert))ROM_TIMERTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerControlEvent \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + unsigned long ulEvent))ROM_TIMERTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerControlStall \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + tBoolean bStall))ROM_TIMERTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerPrescaleSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + unsigned long ulValue))ROM_TIMERTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerPrescaleGet \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerPrescaleMatchSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + unsigned long ulValue))ROM_TIMERTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerPrescaleMatchGet \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerLoadSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + unsigned long ulValue))ROM_TIMERTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerLoadGet \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerValueGet \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerMatchSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + unsigned long ulValue))ROM_TIMERTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerMatchGet \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntRegister \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer, \ + void (*pfnHandler)(void)))ROM_TIMERTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntUnregister \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTimer))ROM_TIMERTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_TIMERTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_TIMERTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntStatus \ + ((unsigned long (*)(unsigned long ulBase, \ + tBoolean bMasked))ROM_TIMERTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_TimerIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_TIMERTABLE[20]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the UART API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_UARTParityModeSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulParity))ROM_UARTTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTParityModeGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFIFOLevelSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTxLevel, \ + unsigned long ulRxLevel))ROM_UARTTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFIFOLevelGet \ + ((void (*)(unsigned long ulBase, \ + unsigned long *pulTxLevel, \ + unsigned long *pulRxLevel))ROM_UARTTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTConfigSetExpClk \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulUARTClk, \ + unsigned long ulBaud, \ + unsigned long ulConfig))ROM_UARTTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTConfigGetExpClk \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulUARTClk, \ + unsigned long *pulBaud, \ + unsigned long *pulConfig))ROM_UARTTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTEnable \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTDisable \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFIFOEnable \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFIFODisable \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTCharsAvail \ + ((tBoolean (*)(unsigned long ulBase))ROM_UARTTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTSpaceAvail \ + ((tBoolean (*)(unsigned long ulBase))ROM_UARTTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTCharGetNonBlocking \ + ((long (*)(unsigned long ulBase))ROM_UARTTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTCharGet \ + ((long (*)(unsigned long ulBase))ROM_UARTTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTCharPutNonBlocking \ + ((tBoolean (*)(unsigned long ulBase, \ + unsigned char ucData))ROM_UARTTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTCharPut \ + ((void (*)(unsigned long ulBase, \ + unsigned char ucData))ROM_UARTTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTBreakCtl \ + ((void (*)(unsigned long ulBase, \ + tBoolean bBreakState))ROM_UARTTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTBusy \ + ((tBoolean (*)(unsigned long ulBase))ROM_UARTTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntRegister \ + ((void (*)(unsigned long ulBase, \ + void(*pfnHandler)(void)))ROM_UARTTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_UARTTABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_UARTTABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntStatus \ + ((unsigned long (*)(unsigned long ulBase, \ + tBoolean bMasked))ROM_UARTTABLE[22]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_UARTTABLE[23]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTDMAEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulDMAFlags))ROM_UARTTABLE[24]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTDMADisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulDMAFlags))ROM_UARTTABLE[25]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTRxErrorGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[26]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTRxErrorClear \ + ((void (*)(unsigned long ulBase))ROM_UARTTABLE[27]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTModemControlSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulControl))ROM_UARTTABLE[28]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTModemControlClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulControl))ROM_UARTTABLE[29]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTModemControlGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[30]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTModemStatusGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[31]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFlowControlSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulMode))ROM_UARTTABLE[32]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTFlowControlGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[33]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTTxIntModeSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulMode))ROM_UARTTABLE[34]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_UARTTxIntModeGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_UARTTABLE[35]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the uDMA API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelTransferSet \ + ((void (*)(unsigned long ulChannelStructIndex, \ + unsigned long ulMode, \ + void *pvSrcAddr, \ + void *pvDstAddr, \ + unsigned long ulTransferSize))ROM_UDMATABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAEnable \ + ((void (*)(void))ROM_UDMATABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMADisable \ + ((void (*)(void))ROM_UDMATABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAErrorStatusGet \ + ((unsigned long (*)(void))ROM_UDMATABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAErrorStatusClear \ + ((void (*)(void))ROM_UDMATABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelEnable \ + ((void (*)(unsigned long ulChannelNum))ROM_UDMATABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelDisable \ + ((void (*)(unsigned long ulChannelNum))ROM_UDMATABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelIsEnabled \ + ((tBoolean (*)(unsigned long ulChannelNum))ROM_UDMATABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAControlBaseSet \ + ((void (*)(void *pControlTable))ROM_UDMATABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAControlBaseGet \ + ((void * (*)(void))ROM_UDMATABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelRequest \ + ((void (*)(unsigned long ulChannelNum))ROM_UDMATABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelAttributeEnable \ + ((void (*)(unsigned long ulChannelNum, \ + unsigned long ulAttr))ROM_UDMATABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelAttributeDisable \ + ((void (*)(unsigned long ulChannelNum, \ + unsigned long ulAttr))ROM_UDMATABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelAttributeGet \ + ((unsigned long (*)(unsigned long ulChannelNum))ROM_UDMATABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelControlSet \ + ((void (*)(unsigned long ulChannelStructIndex, \ + unsigned long ulControl))ROM_UDMATABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelSizeGet \ + ((unsigned long (*)(unsigned long ulChannelStructIndex))ROM_UDMATABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelModeGet \ + ((unsigned long (*)(unsigned long ulChannelStructIndex))ROM_UDMATABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAIntStatus \ + ((unsigned long (*)(void))ROM_UDMATABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAIntClear \ + ((void (*)(unsigned long ulChanMask))ROM_UDMATABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAControlAlternateBaseGet \ + ((void * (*)(void))ROM_UDMATABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelScatterGatherSet \ + ((void (*)(unsigned long ulChannelNum, \ + unsigned ulTaskCount, \ + void *pvTaskList, \ + unsigned long ulIsPeriphSG))ROM_UDMATABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAChannelAssign \ + ((void (*)(unsigned long ulMapping))ROM_UDMATABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAIntRegister \ + ((void (*)(unsigned long ulIntChannel, \ + void (*pfnHandler)(void)))ROM_UDMATABLE[22]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_uDMAIntUnregister \ + ((void (*)(unsigned long ulIntChannel))ROM_UDMATABLE[23]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the Watchdog API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogIntClear \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogRunning \ + ((tBoolean (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogEnable \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogLock \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogUnlock \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogLockState \ + ((tBoolean (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogReloadSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulLoadVal))ROM_WATCHDOGTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogReloadGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogValueGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogIntStatus \ + ((unsigned long (*)(unsigned long ulBase, \ + tBoolean bMasked))ROM_WATCHDOGTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogStallEnable \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogStallDisable \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogIntRegister \ + ((void (*)(unsigned long ulBase, \ + void(*pfnHandler)(void)))ROM_WATCHDOGTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_WatchdogIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_WATCHDOGTABLE[14]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the I2C API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_I2CIntRegister \ + ((void (*)(uint32_t ui32Base, \ + void(pfnHandler)(void)))ROM_I2CTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CIntUnregister \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CTxFIFOConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_I2CTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CTxFIFOFlush \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CRxFIFOConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_I2CTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CRxFIFOFlush \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CFIFOStatus \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CFIFODataPut \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8Data))ROM_I2CTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CFIFODataPutNonBlocking \ + ((uint32_t (*)(uint32_t ui32Base, \ + uint8_t ui8Data))ROM_I2CTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CFIFODataGet \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CFIFODataGetNonBlocking \ + ((uint32_t (*)(uint32_t ui32Base, \ + uint8_t *pui8Data))ROM_I2CTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterBurstLengthSet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8Length))ROM_I2CTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterBurstCountGet \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterGlitchFilterConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_I2CTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveFIFOEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_I2CTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveFIFODisable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterBusBusy \ + ((bool (*)(uint32_t ui32Base))ROM_I2CTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterBusy \ + ((bool (*)(uint32_t ui32Base))ROM_I2CTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterControl \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Cmd))ROM_I2CTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterDataGet \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterDataPut \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8Data))ROM_I2CTABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterDisable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterEnable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[22]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterErr \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[23]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntClear \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[24]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntDisable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[25]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntEnable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[26]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntStatus \ + ((bool (*)(uint32_t ui32Base, \ + bool bMasked))ROM_I2CTABLE[27]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntEnableEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[28]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntDisableEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[29]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntStatusEx \ + ((uint32_t (*)(uint32_t ui32Base, \ + bool bMasked))ROM_I2CTABLE[30]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterIntClearEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[31]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterTimeoutSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Value))ROM_I2CTABLE[32]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveACKOverride \ + ((void (*)(uint32_t ui32Base, \ + bool bEnable))ROM_I2CTABLE[33]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveACKValueSet \ + ((void (*)(uint32_t ui32Base, \ + bool bACK))ROM_I2CTABLE[34]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterLineStateGet \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[35]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterSlaveAddrSet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8SlaveAddr, \ + bool bReceive))ROM_I2CTABLE[36]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveDataGet \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[37]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveDataPut \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8Data))ROM_I2CTABLE[38]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveDisable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[39]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveEnable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[40]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveInit \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8SlaveAddr))ROM_I2CTABLE[41]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveAddressSet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t ui8AddrNum, \ + uint8_t ui8SlaveAddr))ROM_I2CTABLE[42]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntClear \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[43]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntDisable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[44]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntEnable \ + ((void (*)(uint32_t ui32Base))ROM_I2CTABLE[45]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntClearEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[46]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntDisableEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[47]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntEnableEx \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_I2CTABLE[48]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntStatus \ + ((bool (*)(uint32_t ui32Base, \ + bool bMasked))ROM_I2CTABLE[49]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveIntStatusEx \ + ((uint32_t (*)(uint32_t ui32Base, \ + bool bMasked))ROM_I2CTABLE[50]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CSlaveStatus \ + ((uint32_t (*)(uint32_t ui32Base))ROM_I2CTABLE[51]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2CMasterInitExpClk \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32I2CClk, \ + bool bFast))ROM_I2CTABLE[52]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the SPI API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_SPIEnable \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDisable \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIReset \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIConfigSetExpClk \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulSPIClk, \ + unsigned long ulBitRate, \ + unsigned long ulMode, \ + unsigned long ulSubMode, \ + unsigned long ulConfig))ROM_SPITABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDataGetNonBlocking \ + ((long (*)(unsigned long ulBase, \ + unsigned long * pulData))ROM_SPITABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDataGet \ + ((void (*)(unsigned long ulBase, \ + unsigned long *pulData))ROM_SPITABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDataPutNonBlocking \ + ((long (*)(unsigned long ulBase, \ + unsigned long ulData))ROM_SPITABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDataPut \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulData))ROM_SPITABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIFIFOEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulFlags))ROM_SPITABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIFIFODisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulFlags))ROM_SPITABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIFIFOLevelSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTxLevel, \ + unsigned long ulRxLevel))ROM_SPITABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIFIFOLevelGet \ + ((void (*)(unsigned long ulBase, \ + unsigned long *pulTxLevel, \ + unsigned long *pulRxLevel))ROM_SPITABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIWordCountSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulWordCount))ROM_SPITABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntRegister \ + ((void (*)(unsigned long ulBase, \ + void(*pfnHandler)(void)))ROM_SPITABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SPITABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SPITABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntStatus \ + ((unsigned long (*)(unsigned long ulBase, \ + tBoolean bMasked))ROM_SPITABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SPITABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDmaEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulFlags))ROM_SPITABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPIDmaDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulFlags))ROM_SPITABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPICSEnable \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPICSDisable \ + ((void (*)(unsigned long ulBase))ROM_SPITABLE[22]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SPITransfer \ + ((long (*)(unsigned long ulBase, \ + unsigned char *ucDout, \ + unsigned char *ucDin, \ + unsigned long ulSize, \ + unsigned long ulFlags))ROM_SPITABLE[23]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the CAM API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_CameraReset \ + ((void (*)(unsigned long ulBase))ROM_CAMERATABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraParamsConfig \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulHSPol, \ + unsigned long ulVSPol, \ + unsigned long ulFlags))ROM_CAMERATABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraXClkConfig \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulCamClkIn, \ + unsigned long ulXClk))ROM_CAMERATABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraXClkSet \ + ((void (*)(unsigned long ulBase, \ + unsigned char bXClkFlags))ROM_CAMERATABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraDMAEnable \ + ((void (*)(unsigned long ulBase))ROM_CAMERATABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraDMADisable \ + ((void (*)(unsigned long ulBase))ROM_CAMERATABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraThresholdSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulThreshold))ROM_CAMERATABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntRegister \ + ((void (*)(unsigned long ulBase, \ + void (*pfnHandler)(void)))ROM_CAMERATABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_CAMERATABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_CAMERATABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_CAMERATABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntStatus \ + ((unsigned long (*)(unsigned long ulBase))ROM_CAMERATABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_CAMERATABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraCaptureStop \ + ((void (*)(unsigned long ulBase, \ + tBoolean bImmediate))ROM_CAMERATABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraCaptureStart \ + ((void (*)(unsigned long ulBase))ROM_CAMERATABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CameraBufferRead \ + ((void (*)(unsigned long ulBase, \ + unsigned long *pBuffer, \ + unsigned char ucSize))ROM_CAMERATABLE[15]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the FLASH API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_FlashDisable \ + ((void (*)(void))ROM_FLASHTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashErase \ + ((long (*)(unsigned long ulAddress))ROM_FLASHTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashMassErase \ + ((long (*)(void))ROM_FLASHTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashMassEraseNonBlocking \ + ((void (*)(void))ROM_FLASHTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashEraseNonBlocking \ + ((void (*)(unsigned long ulAddress))ROM_FLASHTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashProgram \ + ((long (*)(unsigned long *pulData, \ + unsigned long ulAddress, \ + unsigned long ulCount))ROM_FLASHTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashProgramNonBlocking \ + ((long (*)(unsigned long *pulData, \ + unsigned long ulAddress, \ + unsigned long ulCount))ROM_FLASHTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntRegister \ + ((void (*)(void (*pfnHandler)(void)))ROM_FLASHTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntUnregister \ + ((void (*)(void))ROM_FLASHTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntEnable \ + ((void (*)(unsigned long ulIntFlags))ROM_FLASHTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntDisable \ + ((void (*)(unsigned long ulIntFlags))ROM_FLASHTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntStatus \ + ((unsigned long (*)(tBoolean bMasked))ROM_FLASHTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashIntClear \ + ((void (*)(unsigned long ulIntFlags))ROM_FLASHTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_FlashProtectGet \ + ((tFlashProtection (*)(unsigned long ulAddress))ROM_FLASHTABLE[13]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the Pin API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_PinModeSet \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinDirModeSet \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinIO))ROM_PINTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinDirModeGet \ + ((unsigned long (*)(unsigned long ulPin))ROM_PINTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinModeGet \ + ((unsigned long (*)(unsigned long ulPin))ROM_PINTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinConfigGet \ + ((void (*)(unsigned long ulPin, \ + unsigned long *pulPinStrength, \ + unsigned long *pulPinType))ROM_PINTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinConfigSet \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinStrength, \ + unsigned long ulPinType))ROM_PINTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeUART \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeI2C \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeSPI \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeI2S \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeTimer \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeCamera \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeGPIO \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode, \ + tBoolean bOpenDrain))ROM_PINTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeADC \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PinTypeSDHost \ + ((void (*)(unsigned long ulPin, \ + unsigned long ulPinMode))ROM_PINTABLE[14]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the SYSTICK API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickEnable \ + ((void (*)(void))ROM_SYSTICKTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickDisable \ + ((void (*)(void))ROM_SYSTICKTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickIntRegister \ + ((void (*)(void (*pfnHandler)(void)))ROM_SYSTICKTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickIntUnregister \ + ((void (*)(void))ROM_SYSTICKTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickIntEnable \ + ((void (*)(void))ROM_SYSTICKTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickIntDisable \ + ((void (*)(void))ROM_SYSTICKTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickPeriodSet \ + ((void (*)(unsigned long ulPeriod))ROM_SYSTICKTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickPeriodGet \ + ((unsigned long (*)(void))ROM_SYSTICKTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SysTickValueGet \ + ((unsigned long (*)(void))ROM_SYSTICKTABLE[8]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the UTILS API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_UtilsDelay \ + ((void (*)(unsigned long ulCount))ROM_UTILSTABLE[0]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the I2S API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_I2SEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulMode))ROM_I2STABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SDisable \ + ((void (*)(unsigned long ulBase))ROM_I2STABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SDataPut \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulDataLine, \ + unsigned long ulData))ROM_I2STABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SDataPutNonBlocking \ + ((long (*)(unsigned long ulBase, \ + unsigned long ulDataLine, \ + unsigned long ulData))ROM_I2STABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SDataGet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulDataLine, \ + unsigned long *pulData))ROM_I2STABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SDataGetNonBlocking \ + ((long (*)(unsigned long ulBase, \ + unsigned long ulDataLine, \ + unsigned long *pulData))ROM_I2STABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SConfigSetExpClk \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulI2SClk, \ + unsigned long ulBitClk, \ + unsigned long ulConfig))ROM_I2STABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2STxFIFOEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulTxLevel, \ + unsigned long ulWordsPerTransfer))ROM_I2STABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2STxFIFODisable \ + ((void (*)(unsigned long ulBase))ROM_I2STABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SRxFIFOEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulRxLevel, \ + unsigned long ulWordsPerTransfer))ROM_I2STABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SRxFIFODisable \ + ((void (*)(unsigned long ulBase))ROM_I2STABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2STxFIFOStatusGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_I2STABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SRxFIFOStatusGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_I2STABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SSerializerConfig \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulDataLine, \ + unsigned long ulSerMode, \ + unsigned long ulInActState))ROM_I2STABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_I2STABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_I2STABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntStatus \ + ((unsigned long (*)(unsigned long ulBase))ROM_I2STABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_I2STABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntRegister \ + ((void (*)(unsigned long ulBase, \ + void (*pfnHandler)(void)))ROM_I2STABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_I2SIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_I2STABLE[19]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the GPIO API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_GPIODirModeSet \ + ((void (*)(unsigned long ulPort, \ + unsigned char ucPins, \ + unsigned long ulPinIO))ROM_GPIOTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIODirModeGet \ + ((unsigned long (*)(unsigned long ulPort, \ + unsigned char ucPin))ROM_GPIOTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntTypeSet \ + ((void (*)(unsigned long ulPort, \ + unsigned char ucPins, \ + unsigned long ulIntType))ROM_GPIOTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIODMATriggerEnable \ + ((void (*)(unsigned long ulPort))ROM_GPIOTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIODMATriggerDisable \ + ((void (*)(unsigned long ulPort))ROM_GPIOTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntTypeGet \ + ((unsigned long (*)(unsigned long ulPort, \ + unsigned char ucPin))ROM_GPIOTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntEnable \ + ((void (*)(unsigned long ulPort, \ + unsigned long ulIntFlags))ROM_GPIOTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntDisable \ + ((void (*)(unsigned long ulPort, \ + unsigned long ulIntFlags))ROM_GPIOTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntStatus \ + ((long (*)(unsigned long ulPort, \ + tBoolean bMasked))ROM_GPIOTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntClear \ + ((void (*)(unsigned long ulPort, \ + unsigned long ulIntFlags))ROM_GPIOTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntRegister \ + ((void (*)(unsigned long ulPort, \ + void (*pfnIntHandler)(void)))ROM_GPIOTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOIntUnregister \ + ((void (*)(unsigned long ulPort))ROM_GPIOTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOPinRead \ + ((long (*)(unsigned long ulPort, \ + unsigned char ucPins))ROM_GPIOTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_GPIOPinWrite \ + ((void (*)(unsigned long ulPort, \ + unsigned char ucPins, \ + unsigned char ucVal))ROM_GPIOTABLE[13]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the AES API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_AESConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_AESTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESKey1Set \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Key, \ + uint32_t ui32Keysize))ROM_AESTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESKey2Set \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Key, \ + uint32_t ui32Keysize))ROM_AESTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESKey3Set \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Key))ROM_AESTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIVSet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8IVdata))ROM_AESTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESTagRead \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8TagData))ROM_AESTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataLengthSet \ + ((void (*)(uint32_t ui32Base, \ + uint64_t ui64Length))ROM_AESTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESAuthDataLengthSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Length))ROM_AESTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataReadNonBlocking \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Dest, \ + uint8_t ui8Length))ROM_AESTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataRead \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Dest, \ + uint8_t ui8Length))ROM_AESTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataWriteNonBlocking \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t ui8Length))ROM_AESTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataWrite \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t ui8Length))ROM_AESTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataProcess \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t *pui8Dest, \ + uint32_t ui32Length))ROM_AESTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataMAC \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint32_t ui32Length, \ + uint8_t *pui8Tag))ROM_AESTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDataProcessAE \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t *pui8Dest, \ + uint32_t ui32Length, \ + uint8_t *pui8AuthSrc, \ + uint32_t ui32AuthLength, \ + uint8_t *pui8Tag))ROM_AESTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntStatus \ + ((uint32_t (*)(uint32_t ui32Base, \ + bool bMasked))ROM_AESTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_AESTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntDisable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_AESTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntClear \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_AESTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntRegister \ + ((void (*)(uint32_t ui32Base, \ + void(*pfnHandler)(void)))ROM_AESTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESIntUnregister \ + ((void (*)(uint32_t ui32Base))ROM_AESTABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDMAEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Flags))ROM_AESTABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_AESDMADisable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Flags))ROM_AESTABLE[22]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the DES API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_DESConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Config))ROM_DESTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataRead \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Dest, \ + uint8_t ui8Length))ROM_DESTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataReadNonBlocking \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Dest, \ + uint8_t ui8Length))ROM_DESTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataProcess \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t *pui8Dest, \ + uint32_t ui32Length))ROM_DESTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataWrite \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t ui8Length))ROM_DESTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataWriteNonBlocking \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src, \ + uint8_t ui8Length))ROM_DESTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDMADisable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Flags))ROM_DESTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDMAEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Flags))ROM_DESTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntClear \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_DESTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntDisable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_DESTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_DESTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntRegister \ + ((void (*)(uint32_t ui32Base, \ + void(*pfnHandler)(void)))ROM_DESTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntStatus \ + ((uint32_t (*)(uint32_t ui32Base, \ + bool bMasked))ROM_DESTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIntUnregister \ + ((void (*)(uint32_t ui32Base))ROM_DESTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESIVSet \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8IVdata))ROM_DESTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESKeySet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Key))ROM_DESTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_DESDataLengthSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Length))ROM_DESTABLE[16]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the SHAMD5 API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5ConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Mode))ROM_SHAMD5TABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DataProcess \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8DataSrc, \ + uint32_t ui32DataLength, \ + uint8_t *pui8HashResult))ROM_SHAMD5TABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DataWrite \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Src))ROM_SHAMD5TABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DataWriteNonBlocking \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8Src))ROM_SHAMD5TABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DMADisable \ + ((void (*)(uint32_t ui32Base))ROM_SHAMD5TABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DMAEnable \ + ((void (*)(uint32_t ui32Base))ROM_SHAMD5TABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5DataLengthSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Length))ROM_SHAMD5TABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5HMACKeySet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Src))ROM_SHAMD5TABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5HMACPPKeyGenerate \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Key, \ + uint8_t *pui8PPKey))ROM_SHAMD5TABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5HMACPPKeySet \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Src))ROM_SHAMD5TABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5HMACProcess \ + ((bool (*)(uint32_t ui32Base, \ + uint8_t *pui8DataSrc, \ + uint32_t ui32DataLength, \ + uint8_t *pui8HashResult))ROM_SHAMD5TABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntClear \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_SHAMD5TABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntDisable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_SHAMD5TABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntEnable \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32IntFlags))ROM_SHAMD5TABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntRegister \ + ((void (*)(uint32_t ui32Base, \ + void(*pfnHandler)(void)))ROM_SHAMD5TABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntStatus \ + ((uint32_t (*)(uint32_t ui32Base, \ + bool bMasked))ROM_SHAMD5TABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5IntUnregister \ + ((void (*)(uint32_t ui32Base))ROM_SHAMD5TABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SHAMD5ResultRead \ + ((void (*)(uint32_t ui32Base, \ + uint8_t *pui8Dest))ROM_SHAMD5TABLE[17]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the CRC API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_CRCConfigSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32CRCConfig))ROM_CRCTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CRCDataProcess \ + ((uint32_t (*)(uint32_t ui32Base, \ + void *puiDataIn, \ + uint32_t ui32DataLength, \ + uint32_t ui32Config))ROM_CRCTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CRCDataWrite \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Data))ROM_CRCTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CRCResultRead \ + ((uint32_t (*)(uint32_t ui32Base))ROM_CRCTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_CRCSeedSet \ + ((void (*)(uint32_t ui32Base, \ + uint32_t ui32Seed))ROM_CRCTABLE[4]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the SDHOST API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostCmdReset \ + ((void (*)(unsigned long ulBase))ROM_SDHOSTTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostInit \ + ((void (*)(unsigned long ulBase))ROM_SDHOSTTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostCmdSend \ + ((long (*)(unsigned long ulBase, \ + unsigned long ulCmd, \ + unsigned ulArg))ROM_SDHOSTTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntRegister \ + ((void (*)(unsigned long ulBase, \ + void (*pfnHandler)(void)))ROM_SDHOSTTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntUnregister \ + ((void (*)(unsigned long ulBase))ROM_SDHOSTTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SDHOSTTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SDHOSTTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntStatus \ + ((unsigned long (*)(unsigned long ulBase))ROM_SDHOSTTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulIntFlags))ROM_SDHOSTTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostRespStatus \ + ((unsigned long (*)(unsigned long ulBase))ROM_SDHOSTTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostRespGet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulRespnse[4]))ROM_SDHOSTTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostBlockSizeSet \ + ((void (*)(unsigned long ulBase, \ + unsigned short ulBlkSize))ROM_SDHOSTTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostBlockCountSet \ + ((void (*)(unsigned long ulBase, \ + unsigned short ulBlkCount))ROM_SDHOSTTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostDataNonBlockingWrite \ + ((tBoolean (*)(unsigned long ulBase, \ + unsigned long ulData))ROM_SDHOSTTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostDataNonBlockingRead \ + ((tBoolean (*)(unsigned long ulBase, \ + unsigned long *pulData))ROM_SDHOSTTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostDataWrite \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulData))ROM_SDHOSTTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostDataRead \ + ((void (*)(unsigned long ulBase, \ + unsigned long *ulData))ROM_SDHOSTTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_SDHostSetExpClk \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulSDHostClk, \ + unsigned long ulCardClk))ROM_SDHOSTTABLE[17]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the PRCM API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMMCUReset \ + ((void (*)(tBoolean bIncludeSubsystem))ROM_PRCMTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSysResetCauseGet \ + ((unsigned long (*)(void))ROM_PRCMTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMPeripheralClkEnable \ + ((void (*)(unsigned long ulPeripheral, \ + unsigned long ulClkFlags))ROM_PRCMTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMPeripheralClkDisable \ + ((void (*)(unsigned long ulPeripheral, \ + unsigned long ulClkFlags))ROM_PRCMTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMPeripheralReset \ + ((void (*)(unsigned long ulPeripheral))ROM_PRCMTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMPeripheralStatusGet \ + ((tBoolean (*)(unsigned long ulPeripheral))ROM_PRCMTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMI2SClockFreqSet \ + ((void (*)(unsigned long ulI2CClkFreq))ROM_PRCMTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMPeripheralClockGet \ + ((unsigned long (*)(unsigned long ulPeripheral))ROM_PRCMTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSleepEnter \ + ((void (*)(void))ROM_PRCMTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMDeepSleepEnter \ + ((void (*)(void))ROM_PRCMTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSRAMRetentionEnable \ + ((void (*)(unsigned long ulSramColSel, \ + unsigned long ulFlags))ROM_PRCMTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSRAMRetentionDisable \ + ((void (*)(unsigned long ulSramColSel, \ + unsigned long ulFlags))ROM_PRCMTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSEnter \ + ((void (*)(void))ROM_PRCMTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSIntervalSet \ + ((void (*)(unsigned long ulTicks))ROM_PRCMTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSWakeupSourceEnable \ + ((void (*)(unsigned long ulLpdsWakeupSrc))ROM_PRCMTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSWakeupCauseGet \ + ((unsigned long (*)(void))ROM_PRCMTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSWakeUpGPIOSelect \ + ((void (*)(unsigned long ulGPIOPin, \ + unsigned long ulType))ROM_PRCMTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSWakeupSourceDisable \ + ((void (*)(unsigned long ulLpdsWakeupSrc))ROM_PRCMTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateEnter \ + ((void (*)(void))ROM_PRCMTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateWakeupSourceEnable \ + ((void (*)(unsigned long ulHIBWakupSrc))ROM_PRCMTABLE[20]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateWakeupCauseGet \ + ((unsigned long (*)(void))ROM_PRCMTABLE[21]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateWakeUpGPIOSelect \ + ((void (*)(unsigned long ulMultiGPIOBitMap, \ + unsigned long ulType))ROM_PRCMTABLE[22]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateWakeupSourceDisable \ + ((void (*)(unsigned long ulHIBWakupSrc))ROM_PRCMTABLE[23]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMHibernateIntervalSet \ + ((void (*)(unsigned long long ullTicks))ROM_PRCMTABLE[24]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSlowClkCtrGet \ + ((unsigned long long (*)(void))ROM_PRCMTABLE[25]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSlowClkCtrMatchSet \ + ((void (*)(unsigned long long ullTicks))ROM_PRCMTABLE[26]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMSlowClkCtrMatchGet \ + ((unsigned long long (*)(void))ROM_PRCMTABLE[27]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMOCRRegisterWrite \ + ((void (*)(unsigned char ucIndex, \ + unsigned long ulRegValue))ROM_PRCMTABLE[28]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMOCRRegisterRead \ + ((unsigned long (*)(unsigned char ucIndex))ROM_PRCMTABLE[29]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMIntRegister \ + ((void (*)(void (*pfnHandler)(void)))ROM_PRCMTABLE[30]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMIntUnregister \ + ((void (*)(void))ROM_PRCMTABLE[31]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMIntEnable \ + ((void (*)(unsigned long ulIntFlags))ROM_PRCMTABLE[32]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMIntDisable \ + ((void (*)(unsigned long ulIntFlags))ROM_PRCMTABLE[33]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMIntStatus \ + ((unsigned long (*)(void))ROM_PRCMTABLE[34]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCInUseSet \ + ((void (*)(void))ROM_PRCMTABLE[35]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCInUseGet \ + ((tBoolean (*)(void))ROM_PRCMTABLE[36]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCSet \ + ((void (*)(unsigned long ulSecs, \ + unsigned short usMsec))ROM_PRCMTABLE[37]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCGet \ + ((void (*)(unsigned long *ulSecs, \ + unsigned short *usMsec))ROM_PRCMTABLE[38]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCMatchSet \ + ((void (*)(unsigned long ulSecs, \ + unsigned short usMsec))ROM_PRCMTABLE[39]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMRTCMatchGet \ + ((void (*)(unsigned long *ulSecs, \ + unsigned short *usMsec))ROM_PRCMTABLE[40]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_PRCMLPDSRestoreInfoSet \ + ((void (*)(unsigned long ulRestoreSP, \ + unsigned long ulRestorePC))ROM_PRCMTABLE[41]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the HWSPINLOCK API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_HwSpinLockAcquire \ + ((void (*)(uint32_t ui32LockID))ROM_HWSPINLOCKTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_HwSpinLockTryAcquire \ + ((int32_t (*)(uint32_t ui32LockID, \ + uint32_t ui32Retry))ROM_HWSPINLOCKTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_HwSpinLockRelease \ + ((void (*)(uint32_t ui32LockID))ROM_HWSPINLOCKTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_HwSpinLockTest \ + ((uint32_t (*)(uint32_t ui32LockID, \ + bool bCurrentStatus))ROM_HWSPINLOCKTABLE[3]) +#endif + +//***************************************************************************** +// +// Macros for calling ROM functions in the ADC API. +// +//***************************************************************************** +#if defined(TARGET_IS_CC3200) +#define ROM_ADCEnable \ + ((void (*)(unsigned long ulBase))ROM_ADCTABLE[0]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCDisable \ + ((void (*)(unsigned long ulBase))ROM_ADCTABLE[1]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCChannelEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[2]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCChannelDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[3]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntRegister \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel, \ + void (*pfnHandler)(void)))ROM_ADCTABLE[4]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntUnregister \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[5]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel, \ + unsigned long ulIntFlags))ROM_ADCTABLE[6]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntDisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel, \ + unsigned long ulIntFlags))ROM_ADCTABLE[7]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntStatus \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[8]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCIntClear \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel, \ + unsigned long ulIntFlags))ROM_ADCTABLE[9]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCDMAEnable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[10]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCDMADisable \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[11]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCChannelGainSet \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulChannel, \ + unsigned char ucGain))ROM_ADCTABLE[12]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCChannleGainGet \ + ((unsigned char (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[13]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCTimerConfig \ + ((void (*)(unsigned long ulBase, \ + unsigned long ulValue))ROM_ADCTABLE[14]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCTimerEnable \ + ((void (*)(unsigned long ulBase))ROM_ADCTABLE[15]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCTimerDisable \ + ((void (*)(unsigned long ulBase))ROM_ADCTABLE[16]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCTimerReset \ + ((void (*)(unsigned long ulBase))ROM_ADCTABLE[17]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCTimerValueGet \ + ((unsigned long (*)(unsigned long ulBase))ROM_ADCTABLE[18]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCFIFOLvlGet \ + ((unsigned char (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[19]) +#endif +#if defined(TARGET_IS_CC3200) +#define ROM_ADCFIFORead \ + ((unsigned long (*)(unsigned long ulBase, \ + unsigned long ulChannel))ROM_ADCTABLE[20]) +#endif + +#endif // __ROM_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/rom_map.h b/src/openmv/src/micropython/ports/cc3200/hal/rom_map.h new file mode 100755 index 0000000..86a6c75 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/rom_map.h @@ -0,0 +1,3177 @@ +//***************************************************************************** +// +// rom_map.h +// +// Macros to facilitate calling functions in the ROM when they are +// available and in flash otherwise. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 AN AUTO-GENERATED FILE. DO NOT EDIT BY HAND. +// +//***************************************************************************** + +#ifndef __ROM_MAP_H__ +#define __ROM_MAP_H__ +#ifndef DEBUG +#include "rom.h" +#endif +#include "rom_patch.h" + +//***************************************************************************** +// +// Macros for the Interrupt API. +// +//***************************************************************************** +#ifdef ROM_IntEnable +#define MAP_IntEnable \ + ROM_IntEnable +#else +#define MAP_IntEnable \ + IntEnable +#endif +#ifdef ROM_IntMasterEnable +#define MAP_IntMasterEnable \ + ROM_IntMasterEnable +#else +#define MAP_IntMasterEnable \ + IntMasterEnable +#endif +#ifdef ROM_IntMasterDisable +#define MAP_IntMasterDisable \ + ROM_IntMasterDisable +#else +#define MAP_IntMasterDisable \ + IntMasterDisable +#endif +#ifdef ROM_IntDisable +#define MAP_IntDisable \ + ROM_IntDisable +#else +#define MAP_IntDisable \ + IntDisable +#endif +#ifdef ROM_IntPriorityGroupingSet +#define MAP_IntPriorityGroupingSet \ + ROM_IntPriorityGroupingSet +#else +#define MAP_IntPriorityGroupingSet \ + IntPriorityGroupingSet +#endif +#ifdef ROM_IntPriorityGroupingGet +#define MAP_IntPriorityGroupingGet \ + ROM_IntPriorityGroupingGet +#else +#define MAP_IntPriorityGroupingGet \ + IntPriorityGroupingGet +#endif +#ifdef ROM_IntPrioritySet +#define MAP_IntPrioritySet \ + ROM_IntPrioritySet +#else +#define MAP_IntPrioritySet \ + IntPrioritySet +#endif +#ifdef ROM_IntPriorityGet +#define MAP_IntPriorityGet \ + ROM_IntPriorityGet +#else +#define MAP_IntPriorityGet \ + IntPriorityGet +#endif +#ifdef ROM_IntPendSet +#define MAP_IntPendSet \ + ROM_IntPendSet +#else +#define MAP_IntPendSet \ + IntPendSet +#endif +#ifdef ROM_IntPendClear +#define MAP_IntPendClear \ + ROM_IntPendClear +#else +#define MAP_IntPendClear \ + IntPendClear +#endif +#ifdef ROM_IntPriorityMaskSet +#define MAP_IntPriorityMaskSet \ + ROM_IntPriorityMaskSet +#else +#define MAP_IntPriorityMaskSet \ + IntPriorityMaskSet +#endif +#ifdef ROM_IntPriorityMaskGet +#define MAP_IntPriorityMaskGet \ + ROM_IntPriorityMaskGet +#else +#define MAP_IntPriorityMaskGet \ + IntPriorityMaskGet +#endif +#ifdef ROM_IntRegister +#define MAP_IntRegister \ + ROM_IntRegister +#else +#define MAP_IntRegister \ + IntRegister +#endif +#ifdef ROM_IntUnregister +#define MAP_IntUnregister \ + ROM_IntUnregister +#else +#define MAP_IntUnregister \ + IntUnregister +#endif +#ifdef ROM_IntVTableBaseSet +#define MAP_IntVTableBaseSet \ + ROM_IntVTableBaseSet +#else +#define MAP_IntVTableBaseSet \ + IntVTableBaseSet +#endif + +//***************************************************************************** +// +// Macros for the Timer API. +// +//***************************************************************************** +#ifdef ROM_TimerEnable +#define MAP_TimerEnable \ + ROM_TimerEnable +#else +#define MAP_TimerEnable \ + TimerEnable +#endif +#ifdef ROM_TimerDisable +#define MAP_TimerDisable \ + ROM_TimerDisable +#else +#define MAP_TimerDisable \ + TimerDisable +#endif +#ifdef ROM_TimerConfigure +#define MAP_TimerConfigure \ + ROM_TimerConfigure +#else +#define MAP_TimerConfigure \ + TimerConfigure +#endif +#ifdef ROM_TimerControlLevel +#define MAP_TimerControlLevel \ + ROM_TimerControlLevel +#else +#define MAP_TimerControlLevel \ + TimerControlLevel +#endif +#ifdef ROM_TimerControlEvent +#define MAP_TimerControlEvent \ + ROM_TimerControlEvent +#else +#define MAP_TimerControlEvent \ + TimerControlEvent +#endif +#ifdef ROM_TimerControlStall +#define MAP_TimerControlStall \ + ROM_TimerControlStall +#else +#define MAP_TimerControlStall \ + TimerControlStall +#endif +#ifdef ROM_TimerPrescaleSet +#define MAP_TimerPrescaleSet \ + ROM_TimerPrescaleSet +#else +#define MAP_TimerPrescaleSet \ + TimerPrescaleSet +#endif +#ifdef ROM_TimerPrescaleGet +#define MAP_TimerPrescaleGet \ + ROM_TimerPrescaleGet +#else +#define MAP_TimerPrescaleGet \ + TimerPrescaleGet +#endif +#ifdef ROM_TimerPrescaleMatchSet +#define MAP_TimerPrescaleMatchSet \ + ROM_TimerPrescaleMatchSet +#else +#define MAP_TimerPrescaleMatchSet \ + TimerPrescaleMatchSet +#endif +#ifdef ROM_TimerPrescaleMatchGet +#define MAP_TimerPrescaleMatchGet \ + ROM_TimerPrescaleMatchGet +#else +#define MAP_TimerPrescaleMatchGet \ + TimerPrescaleMatchGet +#endif +#ifdef ROM_TimerLoadSet +#define MAP_TimerLoadSet \ + ROM_TimerLoadSet +#else +#define MAP_TimerLoadSet \ + TimerLoadSet +#endif +#ifdef ROM_TimerLoadGet +#define MAP_TimerLoadGet \ + ROM_TimerLoadGet +#else +#define MAP_TimerLoadGet \ + TimerLoadGet +#endif +#ifdef ROM_TimerValueGet +#define MAP_TimerValueGet \ + ROM_TimerValueGet +#else +#define MAP_TimerValueGet \ + TimerValueGet +#endif +#ifdef ROM_TimerMatchSet +#define MAP_TimerMatchSet \ + ROM_TimerMatchSet +#else +#define MAP_TimerMatchSet \ + TimerMatchSet +#endif +#ifdef ROM_TimerMatchGet +#define MAP_TimerMatchGet \ + ROM_TimerMatchGet +#else +#define MAP_TimerMatchGet \ + TimerMatchGet +#endif +#ifdef ROM_TimerIntRegister +#define MAP_TimerIntRegister \ + ROM_TimerIntRegister +#else +#define MAP_TimerIntRegister \ + TimerIntRegister +#endif +#ifdef ROM_TimerIntUnregister +#define MAP_TimerIntUnregister \ + ROM_TimerIntUnregister +#else +#define MAP_TimerIntUnregister \ + TimerIntUnregister +#endif +#ifdef ROM_TimerIntEnable +#define MAP_TimerIntEnable \ + ROM_TimerIntEnable +#else +#define MAP_TimerIntEnable \ + TimerIntEnable +#endif +#ifdef ROM_TimerIntDisable +#define MAP_TimerIntDisable \ + ROM_TimerIntDisable +#else +#define MAP_TimerIntDisable \ + TimerIntDisable +#endif +#ifdef ROM_TimerIntStatus +#define MAP_TimerIntStatus \ + ROM_TimerIntStatus +#else +#define MAP_TimerIntStatus \ + TimerIntStatus +#endif +#ifdef ROM_TimerIntClear +#define MAP_TimerIntClear \ + ROM_TimerIntClear +#else +#define MAP_TimerIntClear \ + TimerIntClear +#endif +#ifdef ROM_TimerDMAEventSet +#define MAP_TimerDMAEventSet \ + ROM_TimerDMAEventSet +#else +#define MAP_TimerDMAEventSet \ + TimerDMAEventSet +#endif +#ifdef ROM_TimerDMAEventGet +#define MAP_TimerDMAEventGet \ + ROM_TimerDMAEventGet +#else +#define MAP_TimerDMAEventGet \ + TimerDMAEventGet +#endif + +//***************************************************************************** +// +// Macros for the UART API. +// +//***************************************************************************** +#ifdef ROM_UARTParityModeSet +#define MAP_UARTParityModeSet \ + ROM_UARTParityModeSet +#else +#define MAP_UARTParityModeSet \ + UARTParityModeSet +#endif +#ifdef ROM_UARTParityModeGet +#define MAP_UARTParityModeGet \ + ROM_UARTParityModeGet +#else +#define MAP_UARTParityModeGet \ + UARTParityModeGet +#endif +#ifdef ROM_UARTFIFOLevelSet +#define MAP_UARTFIFOLevelSet \ + ROM_UARTFIFOLevelSet +#else +#define MAP_UARTFIFOLevelSet \ + UARTFIFOLevelSet +#endif +#ifdef ROM_UARTFIFOLevelGet +#define MAP_UARTFIFOLevelGet \ + ROM_UARTFIFOLevelGet +#else +#define MAP_UARTFIFOLevelGet \ + UARTFIFOLevelGet +#endif +#ifdef ROM_UARTConfigSetExpClk +#define MAP_UARTConfigSetExpClk \ + ROM_UARTConfigSetExpClk +#else +#define MAP_UARTConfigSetExpClk \ + UARTConfigSetExpClk +#endif +#ifdef ROM_UARTConfigGetExpClk +#define MAP_UARTConfigGetExpClk \ + ROM_UARTConfigGetExpClk +#else +#define MAP_UARTConfigGetExpClk \ + UARTConfigGetExpClk +#endif +#ifdef ROM_UARTEnable +#define MAP_UARTEnable \ + ROM_UARTEnable +#else +#define MAP_UARTEnable \ + UARTEnable +#endif +#ifdef ROM_UARTDisable +#define MAP_UARTDisable \ + ROM_UARTDisable +#else +#define MAP_UARTDisable \ + UARTDisable +#endif +#ifdef ROM_UARTFIFOEnable +#define MAP_UARTFIFOEnable \ + ROM_UARTFIFOEnable +#else +#define MAP_UARTFIFOEnable \ + UARTFIFOEnable +#endif +#ifdef ROM_UARTFIFODisable +#define MAP_UARTFIFODisable \ + ROM_UARTFIFODisable +#else +#define MAP_UARTFIFODisable \ + UARTFIFODisable +#endif +#ifdef ROM_UARTCharsAvail +#define MAP_UARTCharsAvail \ + ROM_UARTCharsAvail +#else +#define MAP_UARTCharsAvail \ + UARTCharsAvail +#endif +#ifdef ROM_UARTSpaceAvail +#define MAP_UARTSpaceAvail \ + ROM_UARTSpaceAvail +#else +#define MAP_UARTSpaceAvail \ + UARTSpaceAvail +#endif +#ifdef ROM_UARTCharGetNonBlocking +#define MAP_UARTCharGetNonBlocking \ + ROM_UARTCharGetNonBlocking +#else +#define MAP_UARTCharGetNonBlocking \ + UARTCharGetNonBlocking +#endif +#ifdef ROM_UARTCharGet +#define MAP_UARTCharGet \ + ROM_UARTCharGet +#else +#define MAP_UARTCharGet \ + UARTCharGet +#endif +#ifdef ROM_UARTCharPutNonBlocking +#define MAP_UARTCharPutNonBlocking \ + ROM_UARTCharPutNonBlocking +#else +#define MAP_UARTCharPutNonBlocking \ + UARTCharPutNonBlocking +#endif +#ifdef ROM_UARTCharPut +#define MAP_UARTCharPut \ + ROM_UARTCharPut +#else +#define MAP_UARTCharPut \ + UARTCharPut +#endif +#ifdef ROM_UARTBreakCtl +#define MAP_UARTBreakCtl \ + ROM_UARTBreakCtl +#else +#define MAP_UARTBreakCtl \ + UARTBreakCtl +#endif +#ifdef ROM_UARTBusy +#define MAP_UARTBusy \ + ROM_UARTBusy +#else +#define MAP_UARTBusy \ + UARTBusy +#endif +#ifdef ROM_UARTIntRegister +#define MAP_UARTIntRegister \ + ROM_UARTIntRegister +#else +#define MAP_UARTIntRegister \ + UARTIntRegister +#endif +#ifdef ROM_UARTIntUnregister +#define MAP_UARTIntUnregister \ + ROM_UARTIntUnregister +#else +#define MAP_UARTIntUnregister \ + UARTIntUnregister +#endif +#ifdef ROM_UARTIntEnable +#define MAP_UARTIntEnable \ + ROM_UARTIntEnable +#else +#define MAP_UARTIntEnable \ + UARTIntEnable +#endif +#ifdef ROM_UARTIntDisable +#define MAP_UARTIntDisable \ + ROM_UARTIntDisable +#else +#define MAP_UARTIntDisable \ + UARTIntDisable +#endif +#ifdef ROM_UARTIntStatus +#define MAP_UARTIntStatus \ + ROM_UARTIntStatus +#else +#define MAP_UARTIntStatus \ + UARTIntStatus +#endif +#ifdef ROM_UARTIntClear +#define MAP_UARTIntClear \ + ROM_UARTIntClear +#else +#define MAP_UARTIntClear \ + UARTIntClear +#endif +#ifdef ROM_UARTDMAEnable +#define MAP_UARTDMAEnable \ + ROM_UARTDMAEnable +#else +#define MAP_UARTDMAEnable \ + UARTDMAEnable +#endif +#ifdef ROM_UARTDMADisable +#define MAP_UARTDMADisable \ + ROM_UARTDMADisable +#else +#define MAP_UARTDMADisable \ + UARTDMADisable +#endif +#ifdef ROM_UARTRxErrorGet +#define MAP_UARTRxErrorGet \ + ROM_UARTRxErrorGet +#else +#define MAP_UARTRxErrorGet \ + UARTRxErrorGet +#endif +#ifdef ROM_UARTRxErrorClear +#define MAP_UARTRxErrorClear \ + ROM_UARTRxErrorClear +#else +#define MAP_UARTRxErrorClear \ + UARTRxErrorClear +#endif +#ifdef ROM_UARTModemControlSet +#define MAP_UARTModemControlSet \ + ROM_UARTModemControlSet +#else +#define MAP_UARTModemControlSet \ + UARTModemControlSet +#endif +#ifdef ROM_UARTModemControlClear +#define MAP_UARTModemControlClear \ + ROM_UARTModemControlClear +#else +#define MAP_UARTModemControlClear \ + UARTModemControlClear +#endif +#ifdef ROM_UARTModemControlGet +#define MAP_UARTModemControlGet \ + ROM_UARTModemControlGet +#else +#define MAP_UARTModemControlGet \ + UARTModemControlGet +#endif +#ifdef ROM_UARTModemStatusGet +#define MAP_UARTModemStatusGet \ + ROM_UARTModemStatusGet +#else +#define MAP_UARTModemStatusGet \ + UARTModemStatusGet +#endif +#ifdef ROM_UARTFlowControlSet +#define MAP_UARTFlowControlSet \ + ROM_UARTFlowControlSet +#else +#define MAP_UARTFlowControlSet \ + UARTFlowControlSet +#endif +#ifdef ROM_UARTFlowControlGet +#define MAP_UARTFlowControlGet \ + ROM_UARTFlowControlGet +#else +#define MAP_UARTFlowControlGet \ + UARTFlowControlGet +#endif +#ifdef ROM_UARTTxIntModeSet +#define MAP_UARTTxIntModeSet \ + ROM_UARTTxIntModeSet +#else +#define MAP_UARTTxIntModeSet \ + UARTTxIntModeSet +#endif +#ifdef ROM_UARTTxIntModeGet +#define MAP_UARTTxIntModeGet \ + ROM_UARTTxIntModeGet +#else +#define MAP_UARTTxIntModeGet \ + UARTTxIntModeGet +#endif + +//***************************************************************************** +// +// Macros for the uDMA API. +// +//***************************************************************************** +#ifdef ROM_uDMAChannelTransferSet +#define MAP_uDMAChannelTransferSet \ + ROM_uDMAChannelTransferSet +#else +#define MAP_uDMAChannelTransferSet \ + uDMAChannelTransferSet +#endif +#ifdef ROM_uDMAEnable +#define MAP_uDMAEnable \ + ROM_uDMAEnable +#else +#define MAP_uDMAEnable \ + uDMAEnable +#endif +#ifdef ROM_uDMADisable +#define MAP_uDMADisable \ + ROM_uDMADisable +#else +#define MAP_uDMADisable \ + uDMADisable +#endif +#ifdef ROM_uDMAErrorStatusGet +#define MAP_uDMAErrorStatusGet \ + ROM_uDMAErrorStatusGet +#else +#define MAP_uDMAErrorStatusGet \ + uDMAErrorStatusGet +#endif +#ifdef ROM_uDMAErrorStatusClear +#define MAP_uDMAErrorStatusClear \ + ROM_uDMAErrorStatusClear +#else +#define MAP_uDMAErrorStatusClear \ + uDMAErrorStatusClear +#endif +#ifdef ROM_uDMAChannelEnable +#define MAP_uDMAChannelEnable \ + ROM_uDMAChannelEnable +#else +#define MAP_uDMAChannelEnable \ + uDMAChannelEnable +#endif +#ifdef ROM_uDMAChannelDisable +#define MAP_uDMAChannelDisable \ + ROM_uDMAChannelDisable +#else +#define MAP_uDMAChannelDisable \ + uDMAChannelDisable +#endif +#ifdef ROM_uDMAChannelIsEnabled +#define MAP_uDMAChannelIsEnabled \ + ROM_uDMAChannelIsEnabled +#else +#define MAP_uDMAChannelIsEnabled \ + uDMAChannelIsEnabled +#endif +#ifdef ROM_uDMAControlBaseSet +#define MAP_uDMAControlBaseSet \ + ROM_uDMAControlBaseSet +#else +#define MAP_uDMAControlBaseSet \ + uDMAControlBaseSet +#endif +#ifdef ROM_uDMAControlBaseGet +#define MAP_uDMAControlBaseGet \ + ROM_uDMAControlBaseGet +#else +#define MAP_uDMAControlBaseGet \ + uDMAControlBaseGet +#endif +#ifdef ROM_uDMAChannelRequest +#define MAP_uDMAChannelRequest \ + ROM_uDMAChannelRequest +#else +#define MAP_uDMAChannelRequest \ + uDMAChannelRequest +#endif +#ifdef ROM_uDMAChannelAttributeEnable +#define MAP_uDMAChannelAttributeEnable \ + ROM_uDMAChannelAttributeEnable +#else +#define MAP_uDMAChannelAttributeEnable \ + uDMAChannelAttributeEnable +#endif +#ifdef ROM_uDMAChannelAttributeDisable +#define MAP_uDMAChannelAttributeDisable \ + ROM_uDMAChannelAttributeDisable +#else +#define MAP_uDMAChannelAttributeDisable \ + uDMAChannelAttributeDisable +#endif +#ifdef ROM_uDMAChannelAttributeGet +#define MAP_uDMAChannelAttributeGet \ + ROM_uDMAChannelAttributeGet +#else +#define MAP_uDMAChannelAttributeGet \ + uDMAChannelAttributeGet +#endif +#ifdef ROM_uDMAChannelControlSet +#define MAP_uDMAChannelControlSet \ + ROM_uDMAChannelControlSet +#else +#define MAP_uDMAChannelControlSet \ + uDMAChannelControlSet +#endif +#ifdef ROM_uDMAChannelSizeGet +#define MAP_uDMAChannelSizeGet \ + ROM_uDMAChannelSizeGet +#else +#define MAP_uDMAChannelSizeGet \ + uDMAChannelSizeGet +#endif +#ifdef ROM_uDMAChannelModeGet +#define MAP_uDMAChannelModeGet \ + ROM_uDMAChannelModeGet +#else +#define MAP_uDMAChannelModeGet \ + uDMAChannelModeGet +#endif +#ifdef ROM_uDMAIntStatus +#define MAP_uDMAIntStatus \ + ROM_uDMAIntStatus +#else +#define MAP_uDMAIntStatus \ + uDMAIntStatus +#endif +#ifdef ROM_uDMAIntClear +#define MAP_uDMAIntClear \ + ROM_uDMAIntClear +#else +#define MAP_uDMAIntClear \ + uDMAIntClear +#endif +#ifdef ROM_uDMAControlAlternateBaseGet +#define MAP_uDMAControlAlternateBaseGet \ + ROM_uDMAControlAlternateBaseGet +#else +#define MAP_uDMAControlAlternateBaseGet \ + uDMAControlAlternateBaseGet +#endif +#ifdef ROM_uDMAChannelScatterGatherSet +#define MAP_uDMAChannelScatterGatherSet \ + ROM_uDMAChannelScatterGatherSet +#else +#define MAP_uDMAChannelScatterGatherSet \ + uDMAChannelScatterGatherSet +#endif +#ifdef ROM_uDMAChannelAssign +#define MAP_uDMAChannelAssign \ + ROM_uDMAChannelAssign +#else +#define MAP_uDMAChannelAssign \ + uDMAChannelAssign +#endif +#ifdef ROM_uDMAIntRegister +#define MAP_uDMAIntRegister \ + ROM_uDMAIntRegister +#else +#define MAP_uDMAIntRegister \ + uDMAIntRegister +#endif +#ifdef ROM_uDMAIntUnregister +#define MAP_uDMAIntUnregister \ + ROM_uDMAIntUnregister +#else +#define MAP_uDMAIntUnregister \ + uDMAIntUnregister +#endif + +//***************************************************************************** +// +// Macros for the Watchdog API. +// +//***************************************************************************** +#ifdef ROM_WatchdogIntClear +#define MAP_WatchdogIntClear \ + ROM_WatchdogIntClear +#else +#define MAP_WatchdogIntClear \ + WatchdogIntClear +#endif +#ifdef ROM_WatchdogRunning +#define MAP_WatchdogRunning \ + ROM_WatchdogRunning +#else +#define MAP_WatchdogRunning \ + WatchdogRunning +#endif +#ifdef ROM_WatchdogEnable +#define MAP_WatchdogEnable \ + ROM_WatchdogEnable +#else +#define MAP_WatchdogEnable \ + WatchdogEnable +#endif +#ifdef ROM_WatchdogLock +#define MAP_WatchdogLock \ + ROM_WatchdogLock +#else +#define MAP_WatchdogLock \ + WatchdogLock +#endif +#ifdef ROM_WatchdogUnlock +#define MAP_WatchdogUnlock \ + ROM_WatchdogUnlock +#else +#define MAP_WatchdogUnlock \ + WatchdogUnlock +#endif +#ifdef ROM_WatchdogLockState +#define MAP_WatchdogLockState \ + ROM_WatchdogLockState +#else +#define MAP_WatchdogLockState \ + WatchdogLockState +#endif +#ifdef ROM_WatchdogReloadSet +#define MAP_WatchdogReloadSet \ + ROM_WatchdogReloadSet +#else +#define MAP_WatchdogReloadSet \ + WatchdogReloadSet +#endif +#ifdef ROM_WatchdogReloadGet +#define MAP_WatchdogReloadGet \ + ROM_WatchdogReloadGet +#else +#define MAP_WatchdogReloadGet \ + WatchdogReloadGet +#endif +#ifdef ROM_WatchdogValueGet +#define MAP_WatchdogValueGet \ + ROM_WatchdogValueGet +#else +#define MAP_WatchdogValueGet \ + WatchdogValueGet +#endif +#ifdef ROM_WatchdogIntStatus +#define MAP_WatchdogIntStatus \ + ROM_WatchdogIntStatus +#else +#define MAP_WatchdogIntStatus \ + WatchdogIntStatus +#endif +#ifdef ROM_WatchdogStallEnable +#define MAP_WatchdogStallEnable \ + ROM_WatchdogStallEnable +#else +#define MAP_WatchdogStallEnable \ + WatchdogStallEnable +#endif +#ifdef ROM_WatchdogStallDisable +#define MAP_WatchdogStallDisable \ + ROM_WatchdogStallDisable +#else +#define MAP_WatchdogStallDisable \ + WatchdogStallDisable +#endif +#ifdef ROM_WatchdogIntRegister +#define MAP_WatchdogIntRegister \ + ROM_WatchdogIntRegister +#else +#define MAP_WatchdogIntRegister \ + WatchdogIntRegister +#endif +#ifdef ROM_WatchdogIntUnregister +#define MAP_WatchdogIntUnregister \ + ROM_WatchdogIntUnregister +#else +#define MAP_WatchdogIntUnregister \ + WatchdogIntUnregister +#endif + +//***************************************************************************** +// +// Macros for the I2C API. +// +//***************************************************************************** +#ifdef ROM_I2CIntRegister +#define MAP_I2CIntRegister \ + ROM_I2CIntRegister +#else +#define MAP_I2CIntRegister \ + I2CIntRegister +#endif +#ifdef ROM_I2CIntUnregister +#define MAP_I2CIntUnregister \ + ROM_I2CIntUnregister +#else +#define MAP_I2CIntUnregister \ + I2CIntUnregister +#endif +#ifdef ROM_I2CTxFIFOConfigSet +#define MAP_I2CTxFIFOConfigSet \ + ROM_I2CTxFIFOConfigSet +#else +#define MAP_I2CTxFIFOConfigSet \ + I2CTxFIFOConfigSet +#endif +#ifdef ROM_I2CTxFIFOFlush +#define MAP_I2CTxFIFOFlush \ + ROM_I2CTxFIFOFlush +#else +#define MAP_I2CTxFIFOFlush \ + I2CTxFIFOFlush +#endif +#ifdef ROM_I2CRxFIFOConfigSet +#define MAP_I2CRxFIFOConfigSet \ + ROM_I2CRxFIFOConfigSet +#else +#define MAP_I2CRxFIFOConfigSet \ + I2CRxFIFOConfigSet +#endif +#ifdef ROM_I2CRxFIFOFlush +#define MAP_I2CRxFIFOFlush \ + ROM_I2CRxFIFOFlush +#else +#define MAP_I2CRxFIFOFlush \ + I2CRxFIFOFlush +#endif +#ifdef ROM_I2CFIFOStatus +#define MAP_I2CFIFOStatus \ + ROM_I2CFIFOStatus +#else +#define MAP_I2CFIFOStatus \ + I2CFIFOStatus +#endif +#ifdef ROM_I2CFIFODataPut +#define MAP_I2CFIFODataPut \ + ROM_I2CFIFODataPut +#else +#define MAP_I2CFIFODataPut \ + I2CFIFODataPut +#endif +#ifdef ROM_I2CFIFODataPutNonBlocking +#define MAP_I2CFIFODataPutNonBlocking \ + ROM_I2CFIFODataPutNonBlocking +#else +#define MAP_I2CFIFODataPutNonBlocking \ + I2CFIFODataPutNonBlocking +#endif +#ifdef ROM_I2CFIFODataGet +#define MAP_I2CFIFODataGet \ + ROM_I2CFIFODataGet +#else +#define MAP_I2CFIFODataGet \ + I2CFIFODataGet +#endif +#ifdef ROM_I2CFIFODataGetNonBlocking +#define MAP_I2CFIFODataGetNonBlocking \ + ROM_I2CFIFODataGetNonBlocking +#else +#define MAP_I2CFIFODataGetNonBlocking \ + I2CFIFODataGetNonBlocking +#endif +#ifdef ROM_I2CMasterBurstLengthSet +#define MAP_I2CMasterBurstLengthSet \ + ROM_I2CMasterBurstLengthSet +#else +#define MAP_I2CMasterBurstLengthSet \ + I2CMasterBurstLengthSet +#endif +#ifdef ROM_I2CMasterBurstCountGet +#define MAP_I2CMasterBurstCountGet \ + ROM_I2CMasterBurstCountGet +#else +#define MAP_I2CMasterBurstCountGet \ + I2CMasterBurstCountGet +#endif +#ifdef ROM_I2CMasterGlitchFilterConfigSet +#define MAP_I2CMasterGlitchFilterConfigSet \ + ROM_I2CMasterGlitchFilterConfigSet +#else +#define MAP_I2CMasterGlitchFilterConfigSet \ + I2CMasterGlitchFilterConfigSet +#endif +#ifdef ROM_I2CSlaveFIFOEnable +#define MAP_I2CSlaveFIFOEnable \ + ROM_I2CSlaveFIFOEnable +#else +#define MAP_I2CSlaveFIFOEnable \ + I2CSlaveFIFOEnable +#endif +#ifdef ROM_I2CSlaveFIFODisable +#define MAP_I2CSlaveFIFODisable \ + ROM_I2CSlaveFIFODisable +#else +#define MAP_I2CSlaveFIFODisable \ + I2CSlaveFIFODisable +#endif +#ifdef ROM_I2CMasterBusBusy +#define MAP_I2CMasterBusBusy \ + ROM_I2CMasterBusBusy +#else +#define MAP_I2CMasterBusBusy \ + I2CMasterBusBusy +#endif +#ifdef ROM_I2CMasterBusy +#define MAP_I2CMasterBusy \ + ROM_I2CMasterBusy +#else +#define MAP_I2CMasterBusy \ + I2CMasterBusy +#endif +#ifdef ROM_I2CMasterControl +#define MAP_I2CMasterControl \ + ROM_I2CMasterControl +#else +#define MAP_I2CMasterControl \ + I2CMasterControl +#endif +#ifdef ROM_I2CMasterDataGet +#define MAP_I2CMasterDataGet \ + ROM_I2CMasterDataGet +#else +#define MAP_I2CMasterDataGet \ + I2CMasterDataGet +#endif +#ifdef ROM_I2CMasterDataPut +#define MAP_I2CMasterDataPut \ + ROM_I2CMasterDataPut +#else +#define MAP_I2CMasterDataPut \ + I2CMasterDataPut +#endif +#ifdef ROM_I2CMasterDisable +#define MAP_I2CMasterDisable \ + ROM_I2CMasterDisable +#else +#define MAP_I2CMasterDisable \ + I2CMasterDisable +#endif +#ifdef ROM_I2CMasterEnable +#define MAP_I2CMasterEnable \ + ROM_I2CMasterEnable +#else +#define MAP_I2CMasterEnable \ + I2CMasterEnable +#endif +#ifdef ROM_I2CMasterErr +#define MAP_I2CMasterErr \ + ROM_I2CMasterErr +#else +#define MAP_I2CMasterErr \ + I2CMasterErr +#endif +#ifdef ROM_I2CMasterIntClear +#define MAP_I2CMasterIntClear \ + ROM_I2CMasterIntClear +#else +#define MAP_I2CMasterIntClear \ + I2CMasterIntClear +#endif +#ifdef ROM_I2CMasterIntDisable +#define MAP_I2CMasterIntDisable \ + ROM_I2CMasterIntDisable +#else +#define MAP_I2CMasterIntDisable \ + I2CMasterIntDisable +#endif +#ifdef ROM_I2CMasterIntEnable +#define MAP_I2CMasterIntEnable \ + ROM_I2CMasterIntEnable +#else +#define MAP_I2CMasterIntEnable \ + I2CMasterIntEnable +#endif +#ifdef ROM_I2CMasterIntStatus +#define MAP_I2CMasterIntStatus \ + ROM_I2CMasterIntStatus +#else +#define MAP_I2CMasterIntStatus \ + I2CMasterIntStatus +#endif +#ifdef ROM_I2CMasterIntEnableEx +#define MAP_I2CMasterIntEnableEx \ + ROM_I2CMasterIntEnableEx +#else +#define MAP_I2CMasterIntEnableEx \ + I2CMasterIntEnableEx +#endif +#ifdef ROM_I2CMasterIntDisableEx +#define MAP_I2CMasterIntDisableEx \ + ROM_I2CMasterIntDisableEx +#else +#define MAP_I2CMasterIntDisableEx \ + I2CMasterIntDisableEx +#endif +#ifdef ROM_I2CMasterIntStatusEx +#define MAP_I2CMasterIntStatusEx \ + ROM_I2CMasterIntStatusEx +#else +#define MAP_I2CMasterIntStatusEx \ + I2CMasterIntStatusEx +#endif +#ifdef ROM_I2CMasterIntClearEx +#define MAP_I2CMasterIntClearEx \ + ROM_I2CMasterIntClearEx +#else +#define MAP_I2CMasterIntClearEx \ + I2CMasterIntClearEx +#endif +#ifdef ROM_I2CMasterTimeoutSet +#define MAP_I2CMasterTimeoutSet \ + ROM_I2CMasterTimeoutSet +#else +#define MAP_I2CMasterTimeoutSet \ + I2CMasterTimeoutSet +#endif +#ifdef ROM_I2CSlaveACKOverride +#define MAP_I2CSlaveACKOverride \ + ROM_I2CSlaveACKOverride +#else +#define MAP_I2CSlaveACKOverride \ + I2CSlaveACKOverride +#endif +#ifdef ROM_I2CSlaveACKValueSet +#define MAP_I2CSlaveACKValueSet \ + ROM_I2CSlaveACKValueSet +#else +#define MAP_I2CSlaveACKValueSet \ + I2CSlaveACKValueSet +#endif +#ifdef ROM_I2CMasterLineStateGet +#define MAP_I2CMasterLineStateGet \ + ROM_I2CMasterLineStateGet +#else +#define MAP_I2CMasterLineStateGet \ + I2CMasterLineStateGet +#endif +#ifdef ROM_I2CMasterSlaveAddrSet +#define MAP_I2CMasterSlaveAddrSet \ + ROM_I2CMasterSlaveAddrSet +#else +#define MAP_I2CMasterSlaveAddrSet \ + I2CMasterSlaveAddrSet +#endif +#ifdef ROM_I2CSlaveDataGet +#define MAP_I2CSlaveDataGet \ + ROM_I2CSlaveDataGet +#else +#define MAP_I2CSlaveDataGet \ + I2CSlaveDataGet +#endif +#ifdef ROM_I2CSlaveDataPut +#define MAP_I2CSlaveDataPut \ + ROM_I2CSlaveDataPut +#else +#define MAP_I2CSlaveDataPut \ + I2CSlaveDataPut +#endif +#ifdef ROM_I2CSlaveDisable +#define MAP_I2CSlaveDisable \ + ROM_I2CSlaveDisable +#else +#define MAP_I2CSlaveDisable \ + I2CSlaveDisable +#endif +#ifdef ROM_I2CSlaveEnable +#define MAP_I2CSlaveEnable \ + ROM_I2CSlaveEnable +#else +#define MAP_I2CSlaveEnable \ + I2CSlaveEnable +#endif +#ifdef ROM_I2CSlaveInit +#define MAP_I2CSlaveInit \ + ROM_I2CSlaveInit +#else +#define MAP_I2CSlaveInit \ + I2CSlaveInit +#endif +#ifdef ROM_I2CSlaveAddressSet +#define MAP_I2CSlaveAddressSet \ + ROM_I2CSlaveAddressSet +#else +#define MAP_I2CSlaveAddressSet \ + I2CSlaveAddressSet +#endif +#ifdef ROM_I2CSlaveIntClear +#define MAP_I2CSlaveIntClear \ + ROM_I2CSlaveIntClear +#else +#define MAP_I2CSlaveIntClear \ + I2CSlaveIntClear +#endif +#ifdef ROM_I2CSlaveIntDisable +#define MAP_I2CSlaveIntDisable \ + ROM_I2CSlaveIntDisable +#else +#define MAP_I2CSlaveIntDisable \ + I2CSlaveIntDisable +#endif +#ifdef ROM_I2CSlaveIntEnable +#define MAP_I2CSlaveIntEnable \ + ROM_I2CSlaveIntEnable +#else +#define MAP_I2CSlaveIntEnable \ + I2CSlaveIntEnable +#endif +#ifdef ROM_I2CSlaveIntClearEx +#define MAP_I2CSlaveIntClearEx \ + ROM_I2CSlaveIntClearEx +#else +#define MAP_I2CSlaveIntClearEx \ + I2CSlaveIntClearEx +#endif +#ifdef ROM_I2CSlaveIntDisableEx +#define MAP_I2CSlaveIntDisableEx \ + ROM_I2CSlaveIntDisableEx +#else +#define MAP_I2CSlaveIntDisableEx \ + I2CSlaveIntDisableEx +#endif +#ifdef ROM_I2CSlaveIntEnableEx +#define MAP_I2CSlaveIntEnableEx \ + ROM_I2CSlaveIntEnableEx +#else +#define MAP_I2CSlaveIntEnableEx \ + I2CSlaveIntEnableEx +#endif +#ifdef ROM_I2CSlaveIntStatus +#define MAP_I2CSlaveIntStatus \ + ROM_I2CSlaveIntStatus +#else +#define MAP_I2CSlaveIntStatus \ + I2CSlaveIntStatus +#endif +#ifdef ROM_I2CSlaveIntStatusEx +#define MAP_I2CSlaveIntStatusEx \ + ROM_I2CSlaveIntStatusEx +#else +#define MAP_I2CSlaveIntStatusEx \ + I2CSlaveIntStatusEx +#endif +#ifdef ROM_I2CSlaveStatus +#define MAP_I2CSlaveStatus \ + ROM_I2CSlaveStatus +#else +#define MAP_I2CSlaveStatus \ + I2CSlaveStatus +#endif +#ifdef ROM_I2CMasterInitExpClk +#define MAP_I2CMasterInitExpClk \ + ROM_I2CMasterInitExpClk +#else +#define MAP_I2CMasterInitExpClk \ + I2CMasterInitExpClk +#endif + +//***************************************************************************** +// +// Macros for the SPI API. +// +//***************************************************************************** +#ifdef ROM_SPIEnable +#define MAP_SPIEnable \ + ROM_SPIEnable +#else +#define MAP_SPIEnable \ + SPIEnable +#endif +#ifdef ROM_SPIDisable +#define MAP_SPIDisable \ + ROM_SPIDisable +#else +#define MAP_SPIDisable \ + SPIDisable +#endif +#ifdef ROM_SPIReset +#define MAP_SPIReset \ + ROM_SPIReset +#else +#define MAP_SPIReset \ + SPIReset +#endif +#ifdef ROM_SPIConfigSetExpClk +#define MAP_SPIConfigSetExpClk \ + ROM_SPIConfigSetExpClk +#else +#define MAP_SPIConfigSetExpClk \ + SPIConfigSetExpClk +#endif +#ifdef ROM_SPIDataGetNonBlocking +#define MAP_SPIDataGetNonBlocking \ + ROM_SPIDataGetNonBlocking +#else +#define MAP_SPIDataGetNonBlocking \ + SPIDataGetNonBlocking +#endif +#ifdef ROM_SPIDataGet +#define MAP_SPIDataGet \ + ROM_SPIDataGet +#else +#define MAP_SPIDataGet \ + SPIDataGet +#endif +#ifdef ROM_SPIDataPutNonBlocking +#define MAP_SPIDataPutNonBlocking \ + ROM_SPIDataPutNonBlocking +#else +#define MAP_SPIDataPutNonBlocking \ + SPIDataPutNonBlocking +#endif +#ifdef ROM_SPIDataPut +#define MAP_SPIDataPut \ + ROM_SPIDataPut +#else +#define MAP_SPIDataPut \ + SPIDataPut +#endif +#ifdef ROM_SPIFIFOEnable +#define MAP_SPIFIFOEnable \ + ROM_SPIFIFOEnable +#else +#define MAP_SPIFIFOEnable \ + SPIFIFOEnable +#endif +#ifdef ROM_SPIFIFODisable +#define MAP_SPIFIFODisable \ + ROM_SPIFIFODisable +#else +#define MAP_SPIFIFODisable \ + SPIFIFODisable +#endif +#ifdef ROM_SPIFIFOLevelSet +#define MAP_SPIFIFOLevelSet \ + ROM_SPIFIFOLevelSet +#else +#define MAP_SPIFIFOLevelSet \ + SPIFIFOLevelSet +#endif +#ifdef ROM_SPIFIFOLevelGet +#define MAP_SPIFIFOLevelGet \ + ROM_SPIFIFOLevelGet +#else +#define MAP_SPIFIFOLevelGet \ + SPIFIFOLevelGet +#endif +#ifdef ROM_SPIWordCountSet +#define MAP_SPIWordCountSet \ + ROM_SPIWordCountSet +#else +#define MAP_SPIWordCountSet \ + SPIWordCountSet +#endif +#ifdef ROM_SPIIntRegister +#define MAP_SPIIntRegister \ + ROM_SPIIntRegister +#else +#define MAP_SPIIntRegister \ + SPIIntRegister +#endif +#ifdef ROM_SPIIntUnregister +#define MAP_SPIIntUnregister \ + ROM_SPIIntUnregister +#else +#define MAP_SPIIntUnregister \ + SPIIntUnregister +#endif +#ifdef ROM_SPIIntEnable +#define MAP_SPIIntEnable \ + ROM_SPIIntEnable +#else +#define MAP_SPIIntEnable \ + SPIIntEnable +#endif +#ifdef ROM_SPIIntDisable +#define MAP_SPIIntDisable \ + ROM_SPIIntDisable +#else +#define MAP_SPIIntDisable \ + SPIIntDisable +#endif +#ifdef ROM_SPIIntStatus +#define MAP_SPIIntStatus \ + ROM_SPIIntStatus +#else +#define MAP_SPIIntStatus \ + SPIIntStatus +#endif +#ifdef ROM_SPIIntClear +#define MAP_SPIIntClear \ + ROM_SPIIntClear +#else +#define MAP_SPIIntClear \ + SPIIntClear +#endif +#ifdef ROM_SPIDmaEnable +#define MAP_SPIDmaEnable \ + ROM_SPIDmaEnable +#else +#define MAP_SPIDmaEnable \ + SPIDmaEnable +#endif +#ifdef ROM_SPIDmaDisable +#define MAP_SPIDmaDisable \ + ROM_SPIDmaDisable +#else +#define MAP_SPIDmaDisable \ + SPIDmaDisable +#endif +#ifdef ROM_SPICSEnable +#define MAP_SPICSEnable \ + ROM_SPICSEnable +#else +#define MAP_SPICSEnable \ + SPICSEnable +#endif +#ifdef ROM_SPICSDisable +#define MAP_SPICSDisable \ + ROM_SPICSDisable +#else +#define MAP_SPICSDisable \ + SPICSDisable +#endif +#ifdef ROM_SPITransfer +#define MAP_SPITransfer \ + ROM_SPITransfer +#else +#define MAP_SPITransfer \ + SPITransfer +#endif + +//***************************************************************************** +// +// Macros for the CAM API. +// +//***************************************************************************** +#ifdef ROM_CameraReset +#define MAP_CameraReset \ + ROM_CameraReset +#else +#define MAP_CameraReset \ + CameraReset +#endif +#ifdef ROM_CameraParamsConfig +#define MAP_CameraParamsConfig \ + ROM_CameraParamsConfig +#else +#define MAP_CameraParamsConfig \ + CameraParamsConfig +#endif +#ifdef ROM_CameraXClkConfig +#define MAP_CameraXClkConfig \ + ROM_CameraXClkConfig +#else +#define MAP_CameraXClkConfig \ + CameraXClkConfig +#endif +#ifdef ROM_CameraXClkSet +#define MAP_CameraXClkSet \ + ROM_CameraXClkSet +#else +#define MAP_CameraXClkSet \ + CameraXClkSet +#endif +#ifdef ROM_CameraDMAEnable +#define MAP_CameraDMAEnable \ + ROM_CameraDMAEnable +#else +#define MAP_CameraDMAEnable \ + CameraDMAEnable +#endif +#ifdef ROM_CameraDMADisable +#define MAP_CameraDMADisable \ + ROM_CameraDMADisable +#else +#define MAP_CameraDMADisable \ + CameraDMADisable +#endif +#ifdef ROM_CameraThresholdSet +#define MAP_CameraThresholdSet \ + ROM_CameraThresholdSet +#else +#define MAP_CameraThresholdSet \ + CameraThresholdSet +#endif +#ifdef ROM_CameraIntRegister +#define MAP_CameraIntRegister \ + ROM_CameraIntRegister +#else +#define MAP_CameraIntRegister \ + CameraIntRegister +#endif +#ifdef ROM_CameraIntUnregister +#define MAP_CameraIntUnregister \ + ROM_CameraIntUnregister +#else +#define MAP_CameraIntUnregister \ + CameraIntUnregister +#endif +#ifdef ROM_CameraIntEnable +#define MAP_CameraIntEnable \ + ROM_CameraIntEnable +#else +#define MAP_CameraIntEnable \ + CameraIntEnable +#endif +#ifdef ROM_CameraIntDisable +#define MAP_CameraIntDisable \ + ROM_CameraIntDisable +#else +#define MAP_CameraIntDisable \ + CameraIntDisable +#endif +#ifdef ROM_CameraIntStatus +#define MAP_CameraIntStatus \ + ROM_CameraIntStatus +#else +#define MAP_CameraIntStatus \ + CameraIntStatus +#endif +#ifdef ROM_CameraIntClear +#define MAP_CameraIntClear \ + ROM_CameraIntClear +#else +#define MAP_CameraIntClear \ + CameraIntClear +#endif +#ifdef ROM_CameraCaptureStop +#define MAP_CameraCaptureStop \ + ROM_CameraCaptureStop +#else +#define MAP_CameraCaptureStop \ + CameraCaptureStop +#endif +#ifdef ROM_CameraCaptureStart +#define MAP_CameraCaptureStart \ + ROM_CameraCaptureStart +#else +#define MAP_CameraCaptureStart \ + CameraCaptureStart +#endif +#ifdef ROM_CameraBufferRead +#define MAP_CameraBufferRead \ + ROM_CameraBufferRead +#else +#define MAP_CameraBufferRead \ + CameraBufferRead +#endif + +//***************************************************************************** +// +// Macros for the FLASH API. +// +//***************************************************************************** +#ifdef ROM_FlashDisable +#define MAP_FlashDisable \ + ROM_FlashDisable +#else +#define MAP_FlashDisable \ + FlashDisable +#endif +#ifdef ROM_FlashErase +#define MAP_FlashErase \ + ROM_FlashErase +#else +#define MAP_FlashErase \ + FlashErase +#endif +#ifdef ROM_FlashMassErase +#define MAP_FlashMassErase \ + ROM_FlashMassErase +#else +#define MAP_FlashMassErase \ + FlashMassErase +#endif +#ifdef ROM_FlashMassEraseNonBlocking +#define MAP_FlashMassEraseNonBlocking \ + ROM_FlashMassEraseNonBlocking +#else +#define MAP_FlashMassEraseNonBlocking \ + FlashMassEraseNonBlocking +#endif +#ifdef ROM_FlashEraseNonBlocking +#define MAP_FlashEraseNonBlocking \ + ROM_FlashEraseNonBlocking +#else +#define MAP_FlashEraseNonBlocking \ + FlashEraseNonBlocking +#endif +#ifdef ROM_FlashProgram +#define MAP_FlashProgram \ + ROM_FlashProgram +#else +#define MAP_FlashProgram \ + FlashProgram +#endif +#ifdef ROM_FlashProgramNonBlocking +#define MAP_FlashProgramNonBlocking \ + ROM_FlashProgramNonBlocking +#else +#define MAP_FlashProgramNonBlocking \ + FlashProgramNonBlocking +#endif +#ifdef ROM_FlashIntRegister +#define MAP_FlashIntRegister \ + ROM_FlashIntRegister +#else +#define MAP_FlashIntRegister \ + FlashIntRegister +#endif +#ifdef ROM_FlashIntUnregister +#define MAP_FlashIntUnregister \ + ROM_FlashIntUnregister +#else +#define MAP_FlashIntUnregister \ + FlashIntUnregister +#endif +#ifdef ROM_FlashIntEnable +#define MAP_FlashIntEnable \ + ROM_FlashIntEnable +#else +#define MAP_FlashIntEnable \ + FlashIntEnable +#endif +#ifdef ROM_FlashIntDisable +#define MAP_FlashIntDisable \ + ROM_FlashIntDisable +#else +#define MAP_FlashIntDisable \ + FlashIntDisable +#endif +#ifdef ROM_FlashIntStatus +#define MAP_FlashIntStatus \ + ROM_FlashIntStatus +#else +#define MAP_FlashIntStatus \ + FlashIntStatus +#endif +#ifdef ROM_FlashIntClear +#define MAP_FlashIntClear \ + ROM_FlashIntClear +#else +#define MAP_FlashIntClear \ + FlashIntClear +#endif +#ifdef ROM_FlashProtectGet +#define MAP_FlashProtectGet \ + ROM_FlashProtectGet +#else +#define MAP_FlashProtectGet \ + FlashProtectGet +#endif + +//***************************************************************************** +// +// Macros for the Pin API. +// +//***************************************************************************** +#ifdef ROM_PinModeSet +#define MAP_PinModeSet \ + ROM_PinModeSet +#else +#define MAP_PinModeSet \ + PinModeSet +#endif +#ifdef ROM_PinDirModeSet +#define MAP_PinDirModeSet \ + ROM_PinDirModeSet +#else +#define MAP_PinDirModeSet \ + PinDirModeSet +#endif +#ifdef ROM_PinDirModeGet +#define MAP_PinDirModeGet \ + ROM_PinDirModeGet +#else +#define MAP_PinDirModeGet \ + PinDirModeGet +#endif +#ifdef ROM_PinModeGet +#define MAP_PinModeGet \ + ROM_PinModeGet +#else +#define MAP_PinModeGet \ + PinModeGet +#endif +#ifdef ROM_PinConfigGet +#define MAP_PinConfigGet \ + ROM_PinConfigGet +#else +#define MAP_PinConfigGet \ + PinConfigGet +#endif +#ifdef ROM_PinConfigSet +#define MAP_PinConfigSet \ + ROM_PinConfigSet +#else +#define MAP_PinConfigSet \ + PinConfigSet +#endif +#ifdef ROM_PinTypeUART +#define MAP_PinTypeUART \ + ROM_PinTypeUART +#else +#define MAP_PinTypeUART \ + PinTypeUART +#endif +#ifdef ROM_PinTypeI2C +#define MAP_PinTypeI2C \ + ROM_PinTypeI2C +#else +#define MAP_PinTypeI2C \ + PinTypeI2C +#endif +#ifdef ROM_PinTypeSPI +#define MAP_PinTypeSPI \ + ROM_PinTypeSPI +#else +#define MAP_PinTypeSPI \ + PinTypeSPI +#endif +#ifdef ROM_PinTypeI2S +#define MAP_PinTypeI2S \ + ROM_PinTypeI2S +#else +#define MAP_PinTypeI2S \ + PinTypeI2S +#endif +#ifdef ROM_PinTypeTimer +#define MAP_PinTypeTimer \ + ROM_PinTypeTimer +#else +#define MAP_PinTypeTimer \ + PinTypeTimer +#endif +#ifdef ROM_PinTypeCamera +#define MAP_PinTypeCamera \ + ROM_PinTypeCamera +#else +#define MAP_PinTypeCamera \ + PinTypeCamera +#endif +#ifdef ROM_PinTypeGPIO +#define MAP_PinTypeGPIO \ + ROM_PinTypeGPIO +#else +#define MAP_PinTypeGPIO \ + PinTypeGPIO +#endif +#ifdef ROM_PinTypeADC +#define MAP_PinTypeADC \ + ROM_PinTypeADC +#else +#define MAP_PinTypeADC \ + PinTypeADC +#endif +#ifdef ROM_PinTypeSDHost +#define MAP_PinTypeSDHost \ + ROM_PinTypeSDHost +#else +#define MAP_PinTypeSDHost \ + PinTypeSDHost +#endif + +//***************************************************************************** +// +// Macros for the SYSTICK API. +// +//***************************************************************************** +#ifdef ROM_SysTickEnable +#define MAP_SysTickEnable \ + ROM_SysTickEnable +#else +#define MAP_SysTickEnable \ + SysTickEnable +#endif +#ifdef ROM_SysTickDisable +#define MAP_SysTickDisable \ + ROM_SysTickDisable +#else +#define MAP_SysTickDisable \ + SysTickDisable +#endif +#ifdef ROM_SysTickIntRegister +#define MAP_SysTickIntRegister \ + ROM_SysTickIntRegister +#else +#define MAP_SysTickIntRegister \ + SysTickIntRegister +#endif +#ifdef ROM_SysTickIntUnregister +#define MAP_SysTickIntUnregister \ + ROM_SysTickIntUnregister +#else +#define MAP_SysTickIntUnregister \ + SysTickIntUnregister +#endif +#ifdef ROM_SysTickIntEnable +#define MAP_SysTickIntEnable \ + ROM_SysTickIntEnable +#else +#define MAP_SysTickIntEnable \ + SysTickIntEnable +#endif +#ifdef ROM_SysTickIntDisable +#define MAP_SysTickIntDisable \ + ROM_SysTickIntDisable +#else +#define MAP_SysTickIntDisable \ + SysTickIntDisable +#endif +#ifdef ROM_SysTickPeriodSet +#define MAP_SysTickPeriodSet \ + ROM_SysTickPeriodSet +#else +#define MAP_SysTickPeriodSet \ + SysTickPeriodSet +#endif +#ifdef ROM_SysTickPeriodGet +#define MAP_SysTickPeriodGet \ + ROM_SysTickPeriodGet +#else +#define MAP_SysTickPeriodGet \ + SysTickPeriodGet +#endif +#ifdef ROM_SysTickValueGet +#define MAP_SysTickValueGet \ + ROM_SysTickValueGet +#else +#define MAP_SysTickValueGet \ + SysTickValueGet +#endif + +//***************************************************************************** +// +// Macros for the UTILS API. +// +//***************************************************************************** +#ifdef ROM_UtilsDelay +#define MAP_UtilsDelay \ + ROM_UtilsDelay +#else +#define MAP_UtilsDelay \ + UtilsDelay +#endif + +//***************************************************************************** +// +// Macros for the I2S API. +// +//***************************************************************************** +#ifdef ROM_I2SEnable +#define MAP_I2SEnable \ + ROM_I2SEnable +#else +#define MAP_I2SEnable \ + I2SEnable +#endif +#ifdef ROM_I2SDisable +#define MAP_I2SDisable \ + ROM_I2SDisable +#else +#define MAP_I2SDisable \ + I2SDisable +#endif +#ifdef ROM_I2SDataPut +#define MAP_I2SDataPut \ + ROM_I2SDataPut +#else +#define MAP_I2SDataPut \ + I2SDataPut +#endif +#ifdef ROM_I2SDataPutNonBlocking +#define MAP_I2SDataPutNonBlocking \ + ROM_I2SDataPutNonBlocking +#else +#define MAP_I2SDataPutNonBlocking \ + I2SDataPutNonBlocking +#endif +#ifdef ROM_I2SDataGet +#define MAP_I2SDataGet \ + ROM_I2SDataGet +#else +#define MAP_I2SDataGet \ + I2SDataGet +#endif +#ifdef ROM_I2SDataGetNonBlocking +#define MAP_I2SDataGetNonBlocking \ + ROM_I2SDataGetNonBlocking +#else +#define MAP_I2SDataGetNonBlocking \ + I2SDataGetNonBlocking +#endif +#ifdef ROM_I2SConfigSetExpClk +#define MAP_I2SConfigSetExpClk \ + ROM_I2SConfigSetExpClk +#else +#define MAP_I2SConfigSetExpClk \ + I2SConfigSetExpClk +#endif +#ifdef ROM_I2STxFIFOEnable +#define MAP_I2STxFIFOEnable \ + ROM_I2STxFIFOEnable +#else +#define MAP_I2STxFIFOEnable \ + I2STxFIFOEnable +#endif +#ifdef ROM_I2STxFIFODisable +#define MAP_I2STxFIFODisable \ + ROM_I2STxFIFODisable +#else +#define MAP_I2STxFIFODisable \ + I2STxFIFODisable +#endif +#ifdef ROM_I2SRxFIFOEnable +#define MAP_I2SRxFIFOEnable \ + ROM_I2SRxFIFOEnable +#else +#define MAP_I2SRxFIFOEnable \ + I2SRxFIFOEnable +#endif +#ifdef ROM_I2SRxFIFODisable +#define MAP_I2SRxFIFODisable \ + ROM_I2SRxFIFODisable +#else +#define MAP_I2SRxFIFODisable \ + I2SRxFIFODisable +#endif +#ifdef ROM_I2STxFIFOStatusGet +#define MAP_I2STxFIFOStatusGet \ + ROM_I2STxFIFOStatusGet +#else +#define MAP_I2STxFIFOStatusGet \ + I2STxFIFOStatusGet +#endif +#ifdef ROM_I2SRxFIFOStatusGet +#define MAP_I2SRxFIFOStatusGet \ + ROM_I2SRxFIFOStatusGet +#else +#define MAP_I2SRxFIFOStatusGet \ + I2SRxFIFOStatusGet +#endif +#ifdef ROM_I2SSerializerConfig +#define MAP_I2SSerializerConfig \ + ROM_I2SSerializerConfig +#else +#define MAP_I2SSerializerConfig \ + I2SSerializerConfig +#endif +#ifdef ROM_I2SIntEnable +#define MAP_I2SIntEnable \ + ROM_I2SIntEnable +#else +#define MAP_I2SIntEnable \ + I2SIntEnable +#endif +#ifdef ROM_I2SIntDisable +#define MAP_I2SIntDisable \ + ROM_I2SIntDisable +#else +#define MAP_I2SIntDisable \ + I2SIntDisable +#endif +#ifdef ROM_I2SIntStatus +#define MAP_I2SIntStatus \ + ROM_I2SIntStatus +#else +#define MAP_I2SIntStatus \ + I2SIntStatus +#endif +#ifdef ROM_I2SIntClear +#define MAP_I2SIntClear \ + ROM_I2SIntClear +#else +#define MAP_I2SIntClear \ + I2SIntClear +#endif +#ifdef ROM_I2SIntRegister +#define MAP_I2SIntRegister \ + ROM_I2SIntRegister +#else +#define MAP_I2SIntRegister \ + I2SIntRegister +#endif +#ifdef ROM_I2SIntUnregister +#define MAP_I2SIntUnregister \ + ROM_I2SIntUnregister +#else +#define MAP_I2SIntUnregister \ + I2SIntUnregister +#endif + +//***************************************************************************** +// +// Macros for the GPIO API. +// +//***************************************************************************** +#ifdef ROM_GPIODirModeSet +#define MAP_GPIODirModeSet \ + ROM_GPIODirModeSet +#else +#define MAP_GPIODirModeSet \ + GPIODirModeSet +#endif +#ifdef ROM_GPIODirModeGet +#define MAP_GPIODirModeGet \ + ROM_GPIODirModeGet +#else +#define MAP_GPIODirModeGet \ + GPIODirModeGet +#endif +#ifdef ROM_GPIOIntTypeSet +#define MAP_GPIOIntTypeSet \ + ROM_GPIOIntTypeSet +#else +#define MAP_GPIOIntTypeSet \ + GPIOIntTypeSet +#endif +#ifdef ROM_GPIODMATriggerEnable +#define MAP_GPIODMATriggerEnable \ + ROM_GPIODMATriggerEnable +#else +#define MAP_GPIODMATriggerEnable \ + GPIODMATriggerEnable +#endif +#ifdef ROM_GPIODMATriggerDisable +#define MAP_GPIODMATriggerDisable \ + ROM_GPIODMATriggerDisable +#else +#define MAP_GPIODMATriggerDisable \ + GPIODMATriggerDisable +#endif +#ifdef ROM_GPIOIntTypeGet +#define MAP_GPIOIntTypeGet \ + ROM_GPIOIntTypeGet +#else +#define MAP_GPIOIntTypeGet \ + GPIOIntTypeGet +#endif +#ifdef ROM_GPIOIntEnable +#define MAP_GPIOIntEnable \ + ROM_GPIOIntEnable +#else +#define MAP_GPIOIntEnable \ + GPIOIntEnable +#endif +#ifdef ROM_GPIOIntDisable +#define MAP_GPIOIntDisable \ + ROM_GPIOIntDisable +#else +#define MAP_GPIOIntDisable \ + GPIOIntDisable +#endif +#ifdef ROM_GPIOIntStatus +#define MAP_GPIOIntStatus \ + ROM_GPIOIntStatus +#else +#define MAP_GPIOIntStatus \ + GPIOIntStatus +#endif +#ifdef ROM_GPIOIntClear +#define MAP_GPIOIntClear \ + ROM_GPIOIntClear +#else +#define MAP_GPIOIntClear \ + GPIOIntClear +#endif +#ifdef ROM_GPIOIntRegister +#define MAP_GPIOIntRegister \ + ROM_GPIOIntRegister +#else +#define MAP_GPIOIntRegister \ + GPIOIntRegister +#endif +#ifdef ROM_GPIOIntUnregister +#define MAP_GPIOIntUnregister \ + ROM_GPIOIntUnregister +#else +#define MAP_GPIOIntUnregister \ + GPIOIntUnregister +#endif +#ifdef ROM_GPIOPinRead +#define MAP_GPIOPinRead \ + ROM_GPIOPinRead +#else +#define MAP_GPIOPinRead \ + GPIOPinRead +#endif +#ifdef ROM_GPIOPinWrite +#define MAP_GPIOPinWrite \ + ROM_GPIOPinWrite +#else +#define MAP_GPIOPinWrite \ + GPIOPinWrite +#endif + +//***************************************************************************** +// +// Macros for the AES API. +// +//***************************************************************************** +#ifdef ROM_AESConfigSet +#define MAP_AESConfigSet \ + ROM_AESConfigSet +#else +#define MAP_AESConfigSet \ + AESConfigSet +#endif +#ifdef ROM_AESKey1Set +#define MAP_AESKey1Set \ + ROM_AESKey1Set +#else +#define MAP_AESKey1Set \ + AESKey1Set +#endif +#ifdef ROM_AESKey2Set +#define MAP_AESKey2Set \ + ROM_AESKey2Set +#else +#define MAP_AESKey2Set \ + AESKey2Set +#endif +#ifdef ROM_AESKey3Set +#define MAP_AESKey3Set \ + ROM_AESKey3Set +#else +#define MAP_AESKey3Set \ + AESKey3Set +#endif +#ifdef ROM_AESIVSet +#define MAP_AESIVSet \ + ROM_AESIVSet +#else +#define MAP_AESIVSet \ + AESIVSet +#endif +#ifdef ROM_AESTagRead +#define MAP_AESTagRead \ + ROM_AESTagRead +#else +#define MAP_AESTagRead \ + AESTagRead +#endif +#ifdef ROM_AESDataLengthSet +#define MAP_AESDataLengthSet \ + ROM_AESDataLengthSet +#else +#define MAP_AESDataLengthSet \ + AESDataLengthSet +#endif +#ifdef ROM_AESAuthDataLengthSet +#define MAP_AESAuthDataLengthSet \ + ROM_AESAuthDataLengthSet +#else +#define MAP_AESAuthDataLengthSet \ + AESAuthDataLengthSet +#endif +#ifdef ROM_AESDataReadNonBlocking +#define MAP_AESDataReadNonBlocking \ + ROM_AESDataReadNonBlocking +#else +#define MAP_AESDataReadNonBlocking \ + AESDataReadNonBlocking +#endif +#ifdef ROM_AESDataRead +#define MAP_AESDataRead \ + ROM_AESDataRead +#else +#define MAP_AESDataRead \ + AESDataRead +#endif +#ifdef ROM_AESDataWriteNonBlocking +#define MAP_AESDataWriteNonBlocking \ + ROM_AESDataWriteNonBlocking +#else +#define MAP_AESDataWriteNonBlocking \ + AESDataWriteNonBlocking +#endif +#ifdef ROM_AESDataWrite +#define MAP_AESDataWrite \ + ROM_AESDataWrite +#else +#define MAP_AESDataWrite \ + AESDataWrite +#endif +#ifdef ROM_AESDataProcess +#define MAP_AESDataProcess \ + ROM_AESDataProcess +#else +#define MAP_AESDataProcess \ + AESDataProcess +#endif +#ifdef ROM_AESDataMAC +#define MAP_AESDataMAC \ + ROM_AESDataMAC +#else +#define MAP_AESDataMAC \ + AESDataMAC +#endif +#ifdef ROM_AESDataProcessAE +#define MAP_AESDataProcessAE \ + ROM_AESDataProcessAE +#else +#define MAP_AESDataProcessAE \ + AESDataProcessAE +#endif +#ifdef ROM_AESIntStatus +#define MAP_AESIntStatus \ + ROM_AESIntStatus +#else +#define MAP_AESIntStatus \ + AESIntStatus +#endif +#ifdef ROM_AESIntEnable +#define MAP_AESIntEnable \ + ROM_AESIntEnable +#else +#define MAP_AESIntEnable \ + AESIntEnable +#endif +#ifdef ROM_AESIntDisable +#define MAP_AESIntDisable \ + ROM_AESIntDisable +#else +#define MAP_AESIntDisable \ + AESIntDisable +#endif +#ifdef ROM_AESIntClear +#define MAP_AESIntClear \ + ROM_AESIntClear +#else +#define MAP_AESIntClear \ + AESIntClear +#endif +#ifdef ROM_AESIntRegister +#define MAP_AESIntRegister \ + ROM_AESIntRegister +#else +#define MAP_AESIntRegister \ + AESIntRegister +#endif +#ifdef ROM_AESIntUnregister +#define MAP_AESIntUnregister \ + ROM_AESIntUnregister +#else +#define MAP_AESIntUnregister \ + AESIntUnregister +#endif +#ifdef ROM_AESDMAEnable +#define MAP_AESDMAEnable \ + ROM_AESDMAEnable +#else +#define MAP_AESDMAEnable \ + AESDMAEnable +#endif +#ifdef ROM_AESDMADisable +#define MAP_AESDMADisable \ + ROM_AESDMADisable +#else +#define MAP_AESDMADisable \ + AESDMADisable +#endif + +//***************************************************************************** +// +// Macros for the DES API. +// +//***************************************************************************** +#ifdef ROM_DESConfigSet +#define MAP_DESConfigSet \ + ROM_DESConfigSet +#else +#define MAP_DESConfigSet \ + DESConfigSet +#endif +#ifdef ROM_DESDataRead +#define MAP_DESDataRead \ + ROM_DESDataRead +#else +#define MAP_DESDataRead \ + DESDataRead +#endif +#ifdef ROM_DESDataReadNonBlocking +#define MAP_DESDataReadNonBlocking \ + ROM_DESDataReadNonBlocking +#else +#define MAP_DESDataReadNonBlocking \ + DESDataReadNonBlocking +#endif +#ifdef ROM_DESDataProcess +#define MAP_DESDataProcess \ + ROM_DESDataProcess +#else +#define MAP_DESDataProcess \ + DESDataProcess +#endif +#ifdef ROM_DESDataWrite +#define MAP_DESDataWrite \ + ROM_DESDataWrite +#else +#define MAP_DESDataWrite \ + DESDataWrite +#endif +#ifdef ROM_DESDataWriteNonBlocking +#define MAP_DESDataWriteNonBlocking \ + ROM_DESDataWriteNonBlocking +#else +#define MAP_DESDataWriteNonBlocking \ + DESDataWriteNonBlocking +#endif +#ifdef ROM_DESDMADisable +#define MAP_DESDMADisable \ + ROM_DESDMADisable +#else +#define MAP_DESDMADisable \ + DESDMADisable +#endif +#ifdef ROM_DESDMAEnable +#define MAP_DESDMAEnable \ + ROM_DESDMAEnable +#else +#define MAP_DESDMAEnable \ + DESDMAEnable +#endif +#ifdef ROM_DESIntClear +#define MAP_DESIntClear \ + ROM_DESIntClear +#else +#define MAP_DESIntClear \ + DESIntClear +#endif +#ifdef ROM_DESIntDisable +#define MAP_DESIntDisable \ + ROM_DESIntDisable +#else +#define MAP_DESIntDisable \ + DESIntDisable +#endif +#ifdef ROM_DESIntEnable +#define MAP_DESIntEnable \ + ROM_DESIntEnable +#else +#define MAP_DESIntEnable \ + DESIntEnable +#endif +#ifdef ROM_DESIntRegister +#define MAP_DESIntRegister \ + ROM_DESIntRegister +#else +#define MAP_DESIntRegister \ + DESIntRegister +#endif +#ifdef ROM_DESIntStatus +#define MAP_DESIntStatus \ + ROM_DESIntStatus +#else +#define MAP_DESIntStatus \ + DESIntStatus +#endif +#ifdef ROM_DESIntUnregister +#define MAP_DESIntUnregister \ + ROM_DESIntUnregister +#else +#define MAP_DESIntUnregister \ + DESIntUnregister +#endif +#ifdef ROM_DESIVSet +#define MAP_DESIVSet \ + ROM_DESIVSet +#else +#define MAP_DESIVSet \ + DESIVSet +#endif +#ifdef ROM_DESKeySet +#define MAP_DESKeySet \ + ROM_DESKeySet +#else +#define MAP_DESKeySet \ + DESKeySet +#endif +#ifdef ROM_DESDataLengthSet +#define MAP_DESDataLengthSet \ + ROM_DESDataLengthSet +#else +#define MAP_DESDataLengthSet \ + DESDataLengthSet +#endif + +//***************************************************************************** +// +// Macros for the SHAMD5 API. +// +//***************************************************************************** +#ifdef ROM_SHAMD5ConfigSet +#define MAP_SHAMD5ConfigSet \ + ROM_SHAMD5ConfigSet +#else +#define MAP_SHAMD5ConfigSet \ + SHAMD5ConfigSet +#endif +#ifdef ROM_SHAMD5DataProcess +#define MAP_SHAMD5DataProcess \ + ROM_SHAMD5DataProcess +#else +#define MAP_SHAMD5DataProcess \ + SHAMD5DataProcess +#endif +#ifdef ROM_SHAMD5DataWrite +#define MAP_SHAMD5DataWrite \ + ROM_SHAMD5DataWrite +#else +#define MAP_SHAMD5DataWrite \ + SHAMD5DataWrite +#endif +#ifdef ROM_SHAMD5DataWriteNonBlocking +#define MAP_SHAMD5DataWriteNonBlocking \ + ROM_SHAMD5DataWriteNonBlocking +#else +#define MAP_SHAMD5DataWriteNonBlocking \ + SHAMD5DataWriteNonBlocking +#endif +#ifdef ROM_SHAMD5DMADisable +#define MAP_SHAMD5DMADisable \ + ROM_SHAMD5DMADisable +#else +#define MAP_SHAMD5DMADisable \ + SHAMD5DMADisable +#endif +#ifdef ROM_SHAMD5DMAEnable +#define MAP_SHAMD5DMAEnable \ + ROM_SHAMD5DMAEnable +#else +#define MAP_SHAMD5DMAEnable \ + SHAMD5DMAEnable +#endif +#ifdef ROM_SHAMD5DataLengthSet +#define MAP_SHAMD5DataLengthSet \ + ROM_SHAMD5DataLengthSet +#else +#define MAP_SHAMD5DataLengthSet \ + SHAMD5DataLengthSet +#endif +#ifdef ROM_SHAMD5HMACKeySet +#define MAP_SHAMD5HMACKeySet \ + ROM_SHAMD5HMACKeySet +#else +#define MAP_SHAMD5HMACKeySet \ + SHAMD5HMACKeySet +#endif +#ifdef ROM_SHAMD5HMACPPKeyGenerate +#define MAP_SHAMD5HMACPPKeyGenerate \ + ROM_SHAMD5HMACPPKeyGenerate +#else +#define MAP_SHAMD5HMACPPKeyGenerate \ + SHAMD5HMACPPKeyGenerate +#endif +#ifdef ROM_SHAMD5HMACPPKeySet +#define MAP_SHAMD5HMACPPKeySet \ + ROM_SHAMD5HMACPPKeySet +#else +#define MAP_SHAMD5HMACPPKeySet \ + SHAMD5HMACPPKeySet +#endif +#ifdef ROM_SHAMD5HMACProcess +#define MAP_SHAMD5HMACProcess \ + ROM_SHAMD5HMACProcess +#else +#define MAP_SHAMD5HMACProcess \ + SHAMD5HMACProcess +#endif +#ifdef ROM_SHAMD5IntClear +#define MAP_SHAMD5IntClear \ + ROM_SHAMD5IntClear +#else +#define MAP_SHAMD5IntClear \ + SHAMD5IntClear +#endif +#ifdef ROM_SHAMD5IntDisable +#define MAP_SHAMD5IntDisable \ + ROM_SHAMD5IntDisable +#else +#define MAP_SHAMD5IntDisable \ + SHAMD5IntDisable +#endif +#ifdef ROM_SHAMD5IntEnable +#define MAP_SHAMD5IntEnable \ + ROM_SHAMD5IntEnable +#else +#define MAP_SHAMD5IntEnable \ + SHAMD5IntEnable +#endif +#ifdef ROM_SHAMD5IntRegister +#define MAP_SHAMD5IntRegister \ + ROM_SHAMD5IntRegister +#else +#define MAP_SHAMD5IntRegister \ + SHAMD5IntRegister +#endif +#ifdef ROM_SHAMD5IntStatus +#define MAP_SHAMD5IntStatus \ + ROM_SHAMD5IntStatus +#else +#define MAP_SHAMD5IntStatus \ + SHAMD5IntStatus +#endif +#ifdef ROM_SHAMD5IntUnregister +#define MAP_SHAMD5IntUnregister \ + ROM_SHAMD5IntUnregister +#else +#define MAP_SHAMD5IntUnregister \ + SHAMD5IntUnregister +#endif +#ifdef ROM_SHAMD5ResultRead +#define MAP_SHAMD5ResultRead \ + ROM_SHAMD5ResultRead +#else +#define MAP_SHAMD5ResultRead \ + SHAMD5ResultRead +#endif + +//***************************************************************************** +// +// Macros for the CRC API. +// +//***************************************************************************** +#ifdef ROM_CRCConfigSet +#define MAP_CRCConfigSet \ + ROM_CRCConfigSet +#else +#define MAP_CRCConfigSet \ + CRCConfigSet +#endif +#ifdef ROM_CRCDataProcess +#define MAP_CRCDataProcess \ + ROM_CRCDataProcess +#else +#define MAP_CRCDataProcess \ + CRCDataProcess +#endif +#ifdef ROM_CRCDataWrite +#define MAP_CRCDataWrite \ + ROM_CRCDataWrite +#else +#define MAP_CRCDataWrite \ + CRCDataWrite +#endif +#ifdef ROM_CRCResultRead +#define MAP_CRCResultRead \ + ROM_CRCResultRead +#else +#define MAP_CRCResultRead \ + CRCResultRead +#endif +#ifdef ROM_CRCSeedSet +#define MAP_CRCSeedSet \ + ROM_CRCSeedSet +#else +#define MAP_CRCSeedSet \ + CRCSeedSet +#endif + +//***************************************************************************** +// +// Macros for the SDHOST API. +// +//***************************************************************************** +#ifdef ROM_SDHostCmdReset +#define MAP_SDHostCmdReset \ + ROM_SDHostCmdReset +#else +#define MAP_SDHostCmdReset \ + SDHostCmdReset +#endif +#ifdef ROM_SDHostInit +#define MAP_SDHostInit \ + ROM_SDHostInit +#else +#define MAP_SDHostInit \ + SDHostInit +#endif +#ifdef ROM_SDHostCmdSend +#define MAP_SDHostCmdSend \ + ROM_SDHostCmdSend +#else +#define MAP_SDHostCmdSend \ + SDHostCmdSend +#endif +#ifdef ROM_SDHostIntRegister +#define MAP_SDHostIntRegister \ + ROM_SDHostIntRegister +#else +#define MAP_SDHostIntRegister \ + SDHostIntRegister +#endif +#ifdef ROM_SDHostIntUnregister +#define MAP_SDHostIntUnregister \ + ROM_SDHostIntUnregister +#else +#define MAP_SDHostIntUnregister \ + SDHostIntUnregister +#endif +#ifdef ROM_SDHostIntEnable +#define MAP_SDHostIntEnable \ + ROM_SDHostIntEnable +#else +#define MAP_SDHostIntEnable \ + SDHostIntEnable +#endif +#ifdef ROM_SDHostIntDisable +#define MAP_SDHostIntDisable \ + ROM_SDHostIntDisable +#else +#define MAP_SDHostIntDisable \ + SDHostIntDisable +#endif +#ifdef ROM_SDHostIntStatus +#define MAP_SDHostIntStatus \ + ROM_SDHostIntStatus +#else +#define MAP_SDHostIntStatus \ + SDHostIntStatus +#endif +#ifdef ROM_SDHostIntClear +#define MAP_SDHostIntClear \ + ROM_SDHostIntClear +#else +#define MAP_SDHostIntClear \ + SDHostIntClear +#endif +#ifdef ROM_SDHostRespStatus +#define MAP_SDHostRespStatus \ + ROM_SDHostRespStatus +#else +#define MAP_SDHostRespStatus \ + SDHostRespStatus +#endif +#ifdef ROM_SDHostRespGet +#define MAP_SDHostRespGet \ + ROM_SDHostRespGet +#else +#define MAP_SDHostRespGet \ + SDHostRespGet +#endif +#ifdef ROM_SDHostBlockSizeSet +#define MAP_SDHostBlockSizeSet \ + ROM_SDHostBlockSizeSet +#else +#define MAP_SDHostBlockSizeSet \ + SDHostBlockSizeSet +#endif +#ifdef ROM_SDHostBlockCountSet +#define MAP_SDHostBlockCountSet \ + ROM_SDHostBlockCountSet +#else +#define MAP_SDHostBlockCountSet \ + SDHostBlockCountSet +#endif +#ifdef ROM_SDHostDataNonBlockingWrite +#define MAP_SDHostDataNonBlockingWrite \ + ROM_SDHostDataNonBlockingWrite +#else +#define MAP_SDHostDataNonBlockingWrite \ + SDHostDataNonBlockingWrite +#endif +#ifdef ROM_SDHostDataNonBlockingRead +#define MAP_SDHostDataNonBlockingRead \ + ROM_SDHostDataNonBlockingRead +#else +#define MAP_SDHostDataNonBlockingRead \ + SDHostDataNonBlockingRead +#endif +#ifdef ROM_SDHostDataWrite +#define MAP_SDHostDataWrite \ + ROM_SDHostDataWrite +#else +#define MAP_SDHostDataWrite \ + SDHostDataWrite +#endif +#ifdef ROM_SDHostDataRead +#define MAP_SDHostDataRead \ + ROM_SDHostDataRead +#else +#define MAP_SDHostDataRead \ + SDHostDataRead +#endif +#ifdef ROM_SDHostSetExpClk +#define MAP_SDHostSetExpClk \ + ROM_SDHostSetExpClk +#else +#define MAP_SDHostSetExpClk \ + SDHostSetExpClk +#endif + +//***************************************************************************** +// +// Macros for the PRCM API. +// +//***************************************************************************** +#ifdef ROM_PRCMMCUReset +#define MAP_PRCMMCUReset \ + ROM_PRCMMCUReset +#else +#define MAP_PRCMMCUReset \ + PRCMMCUReset +#endif +#ifdef ROM_PRCMSysResetCauseGet +#define MAP_PRCMSysResetCauseGet \ + ROM_PRCMSysResetCauseGet +#else +#define MAP_PRCMSysResetCauseGet \ + PRCMSysResetCauseGet +#endif +#ifdef ROM_PRCMPeripheralClkEnable +#define MAP_PRCMPeripheralClkEnable \ + ROM_PRCMPeripheralClkEnable +#else +#define MAP_PRCMPeripheralClkEnable \ + PRCMPeripheralClkEnable +#endif +#ifdef ROM_PRCMPeripheralClkDisable +#define MAP_PRCMPeripheralClkDisable \ + ROM_PRCMPeripheralClkDisable +#else +#define MAP_PRCMPeripheralClkDisable \ + PRCMPeripheralClkDisable +#endif +#ifdef ROM_PRCMPeripheralReset +#define MAP_PRCMPeripheralReset \ + ROM_PRCMPeripheralReset +#else +#define MAP_PRCMPeripheralReset \ + PRCMPeripheralReset +#endif +#ifdef ROM_PRCMPeripheralStatusGet +#define MAP_PRCMPeripheralStatusGet \ + ROM_PRCMPeripheralStatusGet +#else +#define MAP_PRCMPeripheralStatusGet \ + PRCMPeripheralStatusGet +#endif +#ifdef ROM_PRCMI2SClockFreqSet +#define MAP_PRCMI2SClockFreqSet \ + ROM_PRCMI2SClockFreqSet +#else +#define MAP_PRCMI2SClockFreqSet \ + PRCMI2SClockFreqSet +#endif +#ifdef ROM_PRCMPeripheralClockGet +#define MAP_PRCMPeripheralClockGet \ + ROM_PRCMPeripheralClockGet +#else +#define MAP_PRCMPeripheralClockGet \ + PRCMPeripheralClockGet +#endif +#ifdef ROM_PRCMSleepEnter +#define MAP_PRCMSleepEnter \ + ROM_PRCMSleepEnter +#else +#define MAP_PRCMSleepEnter \ + PRCMSleepEnter +#endif +#ifdef ROM_PRCMDeepSleepEnter +#define MAP_PRCMDeepSleepEnter \ + ROM_PRCMDeepSleepEnter +#else +#define MAP_PRCMDeepSleepEnter \ + PRCMDeepSleepEnter +#endif +#ifdef ROM_PRCMSRAMRetentionEnable +#define MAP_PRCMSRAMRetentionEnable \ + ROM_PRCMSRAMRetentionEnable +#else +#define MAP_PRCMSRAMRetentionEnable \ + PRCMSRAMRetentionEnable +#endif +#ifdef ROM_PRCMSRAMRetentionDisable +#define MAP_PRCMSRAMRetentionDisable \ + ROM_PRCMSRAMRetentionDisable +#else +#define MAP_PRCMSRAMRetentionDisable \ + PRCMSRAMRetentionDisable +#endif +#ifdef ROM_PRCMLPDSEnter +#define MAP_PRCMLPDSEnter \ + ROM_PRCMLPDSEnter +#else +#define MAP_PRCMLPDSEnter \ + PRCMLPDSEnter +#endif +#ifdef ROM_PRCMLPDSIntervalSet +#define MAP_PRCMLPDSIntervalSet \ + ROM_PRCMLPDSIntervalSet +#else +#define MAP_PRCMLPDSIntervalSet \ + PRCMLPDSIntervalSet +#endif +#ifdef ROM_PRCMLPDSWakeupSourceEnable +#define MAP_PRCMLPDSWakeupSourceEnable \ + ROM_PRCMLPDSWakeupSourceEnable +#else +#define MAP_PRCMLPDSWakeupSourceEnable \ + PRCMLPDSWakeupSourceEnable +#endif +#ifdef ROM_PRCMLPDSWakeupCauseGet +#define MAP_PRCMLPDSWakeupCauseGet \ + ROM_PRCMLPDSWakeupCauseGet +#else +#define MAP_PRCMLPDSWakeupCauseGet \ + PRCMLPDSWakeupCauseGet +#endif +#ifdef ROM_PRCMLPDSWakeUpGPIOSelect +#define MAP_PRCMLPDSWakeUpGPIOSelect \ + ROM_PRCMLPDSWakeUpGPIOSelect +#else +#define MAP_PRCMLPDSWakeUpGPIOSelect \ + PRCMLPDSWakeUpGPIOSelect +#endif +#ifdef ROM_PRCMLPDSWakeupSourceDisable +#define MAP_PRCMLPDSWakeupSourceDisable \ + ROM_PRCMLPDSWakeupSourceDisable +#else +#define MAP_PRCMLPDSWakeupSourceDisable \ + PRCMLPDSWakeupSourceDisable +#endif +#ifdef ROM_PRCMHibernateEnter +#define MAP_PRCMHibernateEnter \ + ROM_PRCMHibernateEnter +#else +#define MAP_PRCMHibernateEnter \ + PRCMHibernateEnter +#endif +#ifdef ROM_PRCMHibernateWakeupSourceEnable +#define MAP_PRCMHibernateWakeupSourceEnable \ + ROM_PRCMHibernateWakeupSourceEnable +#else +#define MAP_PRCMHibernateWakeupSourceEnable \ + PRCMHibernateWakeupSourceEnable +#endif +#ifdef ROM_PRCMHibernateWakeupCauseGet +#define MAP_PRCMHibernateWakeupCauseGet \ + ROM_PRCMHibernateWakeupCauseGet +#else +#define MAP_PRCMHibernateWakeupCauseGet \ + PRCMHibernateWakeupCauseGet +#endif +#ifdef ROM_PRCMHibernateWakeUpGPIOSelect +#define MAP_PRCMHibernateWakeUpGPIOSelect \ + ROM_PRCMHibernateWakeUpGPIOSelect +#else +#define MAP_PRCMHibernateWakeUpGPIOSelect \ + PRCMHibernateWakeUpGPIOSelect +#endif +#ifdef ROM_PRCMHibernateWakeupSourceDisable +#define MAP_PRCMHibernateWakeupSourceDisable \ + ROM_PRCMHibernateWakeupSourceDisable +#else +#define MAP_PRCMHibernateWakeupSourceDisable \ + PRCMHibernateWakeupSourceDisable +#endif +#ifdef ROM_PRCMHibernateIntervalSet +#define MAP_PRCMHibernateIntervalSet \ + ROM_PRCMHibernateIntervalSet +#else +#define MAP_PRCMHibernateIntervalSet \ + PRCMHibernateIntervalSet +#endif +#ifdef ROM_PRCMSlowClkCtrGet +#define MAP_PRCMSlowClkCtrGet \ + ROM_PRCMSlowClkCtrGet +#else +#define MAP_PRCMSlowClkCtrGet \ + PRCMSlowClkCtrGet +#endif +#ifdef ROM_PRCMSlowClkCtrMatchSet +#define MAP_PRCMSlowClkCtrMatchSet \ + ROM_PRCMSlowClkCtrMatchSet +#else +#define MAP_PRCMSlowClkCtrMatchSet \ + PRCMSlowClkCtrMatchSet +#endif +#ifdef ROM_PRCMSlowClkCtrMatchGet +#define MAP_PRCMSlowClkCtrMatchGet \ + ROM_PRCMSlowClkCtrMatchGet +#else +#define MAP_PRCMSlowClkCtrMatchGet \ + PRCMSlowClkCtrMatchGet +#endif +#ifdef ROM_PRCMOCRRegisterWrite +#define MAP_PRCMOCRRegisterWrite \ + ROM_PRCMOCRRegisterWrite +#else +#define MAP_PRCMOCRRegisterWrite \ + PRCMOCRRegisterWrite +#endif +#ifdef ROM_PRCMOCRRegisterRead +#define MAP_PRCMOCRRegisterRead \ + ROM_PRCMOCRRegisterRead +#else +#define MAP_PRCMOCRRegisterRead \ + PRCMOCRRegisterRead +#endif +#ifdef ROM_PRCMIntRegister +#define MAP_PRCMIntRegister \ + ROM_PRCMIntRegister +#else +#define MAP_PRCMIntRegister \ + PRCMIntRegister +#endif +#ifdef ROM_PRCMIntUnregister +#define MAP_PRCMIntUnregister \ + ROM_PRCMIntUnregister +#else +#define MAP_PRCMIntUnregister \ + PRCMIntUnregister +#endif +#ifdef ROM_PRCMIntEnable +#define MAP_PRCMIntEnable \ + ROM_PRCMIntEnable +#else +#define MAP_PRCMIntEnable \ + PRCMIntEnable +#endif +#ifdef ROM_PRCMIntDisable +#define MAP_PRCMIntDisable \ + ROM_PRCMIntDisable +#else +#define MAP_PRCMIntDisable \ + PRCMIntDisable +#endif +#ifdef ROM_PRCMIntStatus +#define MAP_PRCMIntStatus \ + ROM_PRCMIntStatus +#else +#define MAP_PRCMIntStatus \ + PRCMIntStatus +#endif +#ifdef ROM_PRCMRTCInUseSet +#define MAP_PRCMRTCInUseSet \ + ROM_PRCMRTCInUseSet +#else +#define MAP_PRCMRTCInUseSet \ + PRCMRTCInUseSet +#endif +#ifdef ROM_PRCMRTCInUseGet +#define MAP_PRCMRTCInUseGet \ + ROM_PRCMRTCInUseGet +#else +#define MAP_PRCMRTCInUseGet \ + PRCMRTCInUseGet +#endif +#ifdef ROM_PRCMRTCSet +#define MAP_PRCMRTCSet \ + ROM_PRCMRTCSet +#else +#define MAP_PRCMRTCSet \ + PRCMRTCSet +#endif +#ifdef ROM_PRCMRTCGet +#define MAP_PRCMRTCGet \ + ROM_PRCMRTCGet +#else +#define MAP_PRCMRTCGet \ + PRCMRTCGet +#endif +#ifdef ROM_PRCMRTCMatchSet +#define MAP_PRCMRTCMatchSet \ + ROM_PRCMRTCMatchSet +#else +#define MAP_PRCMRTCMatchSet \ + PRCMRTCMatchSet +#endif +#ifdef ROM_PRCMRTCMatchGet +#define MAP_PRCMRTCMatchGet \ + ROM_PRCMRTCMatchGet +#else +#define MAP_PRCMRTCMatchGet \ + PRCMRTCMatchGet +#endif +#ifdef ROM_PRCMLPDSRestoreInfoSet +#define MAP_PRCMLPDSRestoreInfoSet \ + ROM_PRCMLPDSRestoreInfoSet +#else +#define MAP_PRCMLPDSRestoreInfoSet \ + PRCMLPDSRestoreInfoSet +#endif + +#ifdef ROM_PRCMHIBRegRead +#define MAP_PRCMHIBRegRead \ + ROM_PRCMHIBRegRead +#else +#define MAP_PRCMHIBRegRead \ + PRCMHIBRegRead +#endif + +#ifdef ROM_PRCMHIBRegWrite +#define MAP_PRCMHIBRegWrite \ + ROM_PRCMHIBRegWrite +#else +#define MAP_PRCMHIBRegWrite \ + PRCMHIBRegWrite +#endif + +//***************************************************************************** +// +// Macros for the HWSPINLOCK API. +// +//***************************************************************************** +#ifdef ROM_HwSpinLockAcquire +#define MAP_HwSpinLockAcquire \ + ROM_HwSpinLockAcquire +#else +#define MAP_HwSpinLockAcquire \ + HwSpinLockAcquire +#endif +#ifdef ROM_HwSpinLockTryAcquire +#define MAP_HwSpinLockTryAcquire \ + ROM_HwSpinLockTryAcquire +#else +#define MAP_HwSpinLockTryAcquire \ + HwSpinLockTryAcquire +#endif +#ifdef ROM_HwSpinLockRelease +#define MAP_HwSpinLockRelease \ + ROM_HwSpinLockRelease +#else +#define MAP_HwSpinLockRelease \ + HwSpinLockRelease +#endif +#ifdef ROM_HwSpinLockTest +#define MAP_HwSpinLockTest \ + ROM_HwSpinLockTest +#else +#define MAP_HwSpinLockTest \ + HwSpinLockTest +#endif + +//***************************************************************************** +// +// Macros for the ADC API. +// +//***************************************************************************** +#ifdef ROM_ADCEnable +#define MAP_ADCEnable \ + ROM_ADCEnable +#else +#define MAP_ADCEnable \ + ADCEnable +#endif +#ifdef ROM_ADCDisable +#define MAP_ADCDisable \ + ROM_ADCDisable +#else +#define MAP_ADCDisable \ + ADCDisable +#endif +#ifdef ROM_ADCChannelEnable +#define MAP_ADCChannelEnable \ + ROM_ADCChannelEnable +#else +#define MAP_ADCChannelEnable \ + ADCChannelEnable +#endif +#ifdef ROM_ADCChannelDisable +#define MAP_ADCChannelDisable \ + ROM_ADCChannelDisable +#else +#define MAP_ADCChannelDisable \ + ADCChannelDisable +#endif +#ifdef ROM_ADCIntRegister +#define MAP_ADCIntRegister \ + ROM_ADCIntRegister +#else +#define MAP_ADCIntRegister \ + ADCIntRegister +#endif +#ifdef ROM_ADCIntUnregister +#define MAP_ADCIntUnregister \ + ROM_ADCIntUnregister +#else +#define MAP_ADCIntUnregister \ + ADCIntUnregister +#endif +#ifdef ROM_ADCIntEnable +#define MAP_ADCIntEnable \ + ROM_ADCIntEnable +#else +#define MAP_ADCIntEnable \ + ADCIntEnable +#endif +#ifdef ROM_ADCIntDisable +#define MAP_ADCIntDisable \ + ROM_ADCIntDisable +#else +#define MAP_ADCIntDisable \ + ADCIntDisable +#endif +#ifdef ROM_ADCIntStatus +#define MAP_ADCIntStatus \ + ROM_ADCIntStatus +#else +#define MAP_ADCIntStatus \ + ADCIntStatus +#endif +#ifdef ROM_ADCIntClear +#define MAP_ADCIntClear \ + ROM_ADCIntClear +#else +#define MAP_ADCIntClear \ + ADCIntClear +#endif +#ifdef ROM_ADCDMAEnable +#define MAP_ADCDMAEnable \ + ROM_ADCDMAEnable +#else +#define MAP_ADCDMAEnable \ + ADCDMAEnable +#endif +#ifdef ROM_ADCDMADisable +#define MAP_ADCDMADisable \ + ROM_ADCDMADisable +#else +#define MAP_ADCDMADisable \ + ADCDMADisable +#endif +#ifdef ROM_ADCChannelGainSet +#define MAP_ADCChannelGainSet \ + ROM_ADCChannelGainSet +#else +#define MAP_ADCChannelGainSet \ + ADCChannelGainSet +#endif +#ifdef ROM_ADCChannleGainGet +#define MAP_ADCChannleGainGet \ + ROM_ADCChannleGainGet +#else +#define MAP_ADCChannleGainGet \ + ADCChannleGainGet +#endif +#ifdef ROM_ADCTimerConfig +#define MAP_ADCTimerConfig \ + ROM_ADCTimerConfig +#else +#define MAP_ADCTimerConfig \ + ADCTimerConfig +#endif +#ifdef ROM_ADCTimerEnable +#define MAP_ADCTimerEnable \ + ROM_ADCTimerEnable +#else +#define MAP_ADCTimerEnable \ + ADCTimerEnable +#endif +#ifdef ROM_ADCTimerDisable +#define MAP_ADCTimerDisable \ + ROM_ADCTimerDisable +#else +#define MAP_ADCTimerDisable \ + ADCTimerDisable +#endif +#ifdef ROM_ADCTimerReset +#define MAP_ADCTimerReset \ + ROM_ADCTimerReset +#else +#define MAP_ADCTimerReset \ + ADCTimerReset +#endif +#ifdef ROM_ADCTimerValueGet +#define MAP_ADCTimerValueGet \ + ROM_ADCTimerValueGet +#else +#define MAP_ADCTimerValueGet \ + ADCTimerValueGet +#endif +#ifdef ROM_ADCFIFOLvlGet +#define MAP_ADCFIFOLvlGet \ + ROM_ADCFIFOLvlGet +#else +#define MAP_ADCFIFOLvlGet \ + ADCFIFOLvlGet +#endif +#ifdef ROM_ADCFIFORead +#define MAP_ADCFIFORead \ + ROM_ADCFIFORead +#else +#define MAP_ADCFIFORead \ + ADCFIFORead +#endif + +#endif // __ROM_MAP_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/rom_patch.h b/src/openmv/src/micropython/ports/cc3200/hal/rom_patch.h new file mode 100755 index 0000000..9fb8017 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/rom_patch.h @@ -0,0 +1,98 @@ +//***************************************************************************** +// +// rom_patch.h +// +// Macros to facilitate patching driverlib API's in the ROM. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +// List of API's in the ROM that need to be patched. +// For e.g. to patch ROM_UARTCharPut add the line #undef ROM_UARTCharPut +//***************************************************************************** +#undef ROM_ADCIntClear +#undef ROM_IntEnable +#undef ROM_IntDisable +#undef ROM_IntPendSet +#undef ROM_SDHostCardErrorMaskSet +#undef ROM_SDHostCardErrorMaskGet +#undef ROM_TimerConfigure +#undef ROM_TimerDMAEventSet +#undef ROM_TimerDMAEventGet +#undef ROM_SDHostDataNonBlockingWrite +#undef ROM_SDHostDataWrite +#undef ROM_SDHostDataRead +#undef ROM_SDHostDataNonBlockingRead +#undef ROM_PRCMSysResetCauseGet +#undef ROM_PRCMPeripheralClkEnable +#undef ROM_PRCMLPDSWakeUpGPIOSelect +#undef ROM_PRCMHibernateWakeupSourceEnable +#undef ROM_PRCMHibernateWakeupSourceDisable +#undef ROM_PRCMHibernateWakeupCauseGet +#undef ROM_PRCMHibernateIntervalSet +#undef ROM_PRCMHibernateWakeUpGPIOSelect +#undef ROM_PRCMHibernateEnter +#undef ROM_PRCMSlowClkCtrGet +#undef ROM_PRCMSlowClkCtrMatchSet +#undef ROM_PRCMSlowClkCtrMatchGet +#undef ROM_PRCMOCRRegisterWrite +#undef ROM_PRCMOCRRegisterRead +#undef ROM_PRCMIntEnable +#undef ROM_PRCMIntDisable +#undef ROM_PRCMRTCInUseSet +#undef ROM_PRCMRTCInUseGet +#undef ROM_PRCMRTCSet +#undef ROM_PRCMRTCGet +#undef ROM_PRCMRTCMatchSet +#undef ROM_PRCMRTCMatchGet +#undef ROM_PRCMPeripheralClkDisable +#undef ROM_PRCMPeripheralReset +#undef ROM_PRCMPeripheralStatusGet +#undef ROM_SPIConfigSetExpClk +#undef ROM_GPIODirModeGet +#undef ROM_GPIOIntTypeGet +#undef ROM_I2CMasterInitExpClk +#undef ROM_AESDataProcess +#undef ROM_DESDataProcess +#undef ROM_I2SEnable +#undef ROM_I2SConfigSetExpClk +#undef ROM_PinConfigSet +#undef ROM_PRCMLPDSEnter +#undef ROM_PRCMCC3200MCUInit +#undef ROM_SDHostIntStatus +#undef ROM_SDHostBlockCountSet +#undef ROM_UARTModemControlSet +#undef ROM_UARTModemControlClear + diff --git a/src/openmv/src/micropython/ports/cc3200/hal/sdhost.c b/src/openmv/src/micropython/ports/cc3200/hal/sdhost.c new file mode 100755 index 0000000..ba98e35 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/sdhost.c @@ -0,0 +1,744 @@ +//***************************************************************************** +// +// sdhost.c +// +// Driver for the SD Host (SDHost) Interface +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup Secure_Digital_Host_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_mmchs.h" +#include "inc/hw_ints.h" +#include "inc/hw_apps_config.h" +#include "interrupt.h" +#include "sdhost.h" + + +//***************************************************************************** +// +//! Configures SDHost module. +//! +//! \param ulBase is the base address of SDHost module. +//! +//! This function configures the SDHost module, enabling internal sub-modules. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostInit(unsigned long ulBase) +{ + // + // Assert module reset + // + HWREG(ulBase + MMCHS_O_SYSCONFIG) = 0x2; + + // + // Wait for soft reset to complete + // + while( !(HWREG(ulBase + MMCHS_O_SYSCONFIG) & 0x1) ) + { + + } + + // + // Assert internal reset + // + HWREG(ulBase + MMCHS_O_SYSCTL) |= (1 << 24); + + // + // Wait for Reset to complete + // + while( (HWREG(ulBase + MMCHS_O_SYSCTL) & (0x1 << 24)) ) + { + + } + + // + // Set capability register, 1.8 and 3.0 V + // + HWREG(ulBase + MMCHS_O_CAPA) = (0x7 <<24); + + // + // Select bus voltage, 3.0 V + // + HWREG(ulBase + MMCHS_O_HCTL) |= 0x7 << 9; + + // + // Power up the bus + // + HWREG(ulBase + MMCHS_O_HCTL) |= 1 << 8; + + // + // Wait for power on + // + while( !(HWREG(ulBase + MMCHS_O_HCTL) & (1<<8)) ) + { + + } + + HWREG(ulBase + MMCHS_O_CON) |= 1 << 21; + + // + // Un-mask all events + // + HWREG(ulBase + MMCHS_O_IE) = 0xFFFFFFFF; +} + + +//***************************************************************************** +// +//! Resets SDHost command line +//! +//! \param ulBase is the base address of SDHost module. +//! +//! This function assers a soft reset for the command line +//! +//! \return None. +// +//***************************************************************************** +void +SDHostCmdReset(unsigned long ulBase) +{ + HWREG(ulBase + MMCHS_O_SYSCTL) |= 1 << 25; + while( (HWREG(ulBase + MMCHS_O_SYSCTL) & (1 << 25)) ) + { + + } +} + +//***************************************************************************** +// +//! Sends command over SDHost interface +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulCmd is the command to send. +//! \param ulArg is the argument for the command. +//! +//! This function send command to the attached card over the SDHost interface. +//! +//! The \e ulCmd parameter can be one of \b SDHOST_CMD_0 to \b SDHOST_CMD_63. +//! It can be logically ORed with one or more of the following: +//! - \b SDHOST_MULTI_BLK for multi-block transfer +//! - \b SDHOST_WR_CMD if command is followed by write data +//! - \b SDHOST_RD_CMD if command is followed by read data +//! - \b SDHOST_DMA_EN if SDHost need to generate DMA request. +//! - \b SDHOST_RESP_LEN_136 if 136 bit response is expected +//! - \b SDHOST_RESP_LEN_48 if 48 bit response is expected +//! - \b SDHOST_RESP_LEN_48B if 48 bit response with busy bit is expected +//! +//! The parameter \e ulArg is the argument for the command +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +long +SDHostCmdSend(unsigned long ulBase, unsigned long ulCmd, unsigned ulArg) +{ + // + // Set Data Timeout + // + HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x000E0000; + + // + // Check for cmd inhabit + // + if( (HWREG(ulBase + MMCHS_O_PSTATE) & 0x1)) + { + return -1; + } + + // + // Set the argument + // + HWREG(ulBase + MMCHS_O_ARG) = ulArg; + + // + // Send the command + // + HWREG(ulBase + MMCHS_O_CMD) = ulCmd; + + return 0; +} + +//***************************************************************************** +// +//! Writes a data word into the SDHost write buffer. +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulData is data word to be transfered. +//! +//! This function writes a single data word into the SDHost write buffer. The +//! function returns \b true if there was a space available in the buffer else +//! returns \b false. +//! +//! \return Return \b true on success, \b false otherwise. +// +//***************************************************************************** +tBoolean +SDHostDataNonBlockingWrite(unsigned long ulBase, unsigned long ulData) +{ + + // + // See if there is a space in the write buffer + // + if( (HWREG(ulBase + MMCHS_O_PSTATE) & (1<<10)) ) + { + // + // Write the data into the buffer + // + HWREG(ulBase + MMCHS_O_DATA) = ulData; + + // + // Success. + // + return(true); + } + else + { + // + // No free sapce, failure. + // + return(false); + } +} + +//***************************************************************************** +// +//! Waits to write a data word into the SDHost write buffer. +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulData is data word to be transfered. +//! +//! This function writes \e ulData into the SDHost write buffer. If there is no +//! space in the write buffer this function waits until there is a space +//! available before returning. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostDataWrite(unsigned long ulBase, unsigned long ulData) +{ + // + // Wait until space is available + // + while( !(HWREG(ulBase + MMCHS_O_PSTATE) & (1<<10)) ) + { + + } + + // + // Write the data + // + HWREG(ulBase + MMCHS_O_DATA) = ulData; +} + + +//***************************************************************************** +// +//! Waits for a data word from the SDHost read buffer +//! +//! \param ulBase is the base address of SDHost module. +//! \param pulData is pointer to read data variable. +//! +//! This function reads a single data word from the SDHost read buffer. If there +//! is no data available in the buffer the function will wait until a data +//! word is received before returning. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostDataRead(unsigned long ulBase, unsigned long *pulData) +{ + // + // Wait until data is available + // + while( !(HWREG(ulBase + MMCHS_O_PSTATE) & (1<<11)) ) + { + + } + + // + // Read the data + // + *pulData = HWREG(ulBase + MMCHS_O_DATA); +} + +//***************************************************************************** +// +//! Reads single data word from the SDHost read buffer +//! +//! \param ulBase is the base address of SDHost module. +//! \param pulData is pointer to read data variable. +//! +//! This function reads a data word from the SDHost read buffer. The +//! function returns \b true if there was data available in to buffer else +//! returns \b false. +//! +//! \return Return \b true on success, \b false otherwise. +// +//***************************************************************************** +tBoolean +SDHostDataNonBlockingRead(unsigned long ulBase, unsigned long *pulData) +{ + + // + // See if there is any data in the read buffer. + // + if( (HWREG(ulBase + MMCHS_O_PSTATE) & (1<11)) ) + { + // + // Read the data word. + // + *pulData = HWREG(ulBase + MMCHS_O_DATA); + + // + // Success + // + return(true); + } + else + { + // + // No data available, failure. + // + return(false); + } +} + + +//***************************************************************************** +// +//! Registers the interrupt handler for SDHost interrupt +//! +//! \param ulBase is the base address of SDHost module +//! \param pfnHandler is a pointer to the function to be called when the +//! SDHost interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; specific +//! SDHost interrupts must be enabled via SDHostIntEnable(). It is the +//! interrupt handler's responsibility to clear the interrupt source. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostIntRegister(unsigned long ulBase, void (*pfnHandler)(void)) +{ + // + // Register the interrupt handler. + // + IntRegister(INT_MMCHS, pfnHandler); + + // + // Enable the SDHost interrupt. + // + IntEnable(INT_MMCHS); +} + +//***************************************************************************** +// +//! Unregisters the interrupt handler for SDHost interrupt +//! +//! \param ulBase is the base address of SDHost module +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a SDHost interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostIntUnregister(unsigned long ulBase) +{ + // + // Disable the SDHost interrupt. + // + IntDisable(INT_MMCHS); + + // + // Unregister the interrupt handler. + // + IntUnregister(INT_MMCHS); +} + +//***************************************************************************** +// +//! Enable individual interrupt source for the specified SDHost +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulIntFlags is a bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated SDHost interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! - \b SDHOST_INT_CC Command Complete interrupt +//! - \b SDHOST_INT_TC Transfer Complete interrupt +//! - \b SDHOST_INT_BWR Buffer Write Ready interrupt +//! - \b SDHOST_INT_BRR Buffer Read Ready interrupt +//! - \b SDHOST_INT_ERRI Error interrupt +//! - \b SDHOST_INT_CTO Command Timeout error interrupt +//! - \b SDHOST_INT_CEB Command End Bit error interrupt +//! - \b SDHOST_INT_DTO Data Timeout error interrupt +//! - \b SDHOST_INT_DCRC Data CRC error interrupt +//! - \b SDHOST_INT_DEB Data End Bit error +//! - \b SDHOST_INT_CERR Cart Status Error interrupt +//! - \b SDHOST_INT_BADA Bad Data error interrupt +//! - \b SDHOST_INT_DMARD Read DMA done interrupt +//! - \b SDHOST_INT_DMAWR Write DMA done interrupt +//! +//! Note that SDHOST_INT_ERRI can only be used with \sa SDHostIntStatus() +//! and is internally logical OR of all error status bits. Setting this bit +//! alone as \e ulIntFlags doesn't generates any interrupt. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostIntEnable(unsigned long ulBase,unsigned long ulIntFlags) +{ + // + // Enable DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = + (ulIntFlags >> 30); + + // + // Enable the individual interrupt sources + // + HWREG(ulBase + MMCHS_O_ISE) |= (ulIntFlags & 0x3FFFFFFF); +} + +//***************************************************************************** +// +//! Enable individual interrupt source for the specified SDHost +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulIntFlags is a bit mask of the interrupt sources to be enabled. +//! +//! This function disables the indicated SDHost interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SDHostIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SDHostIntDisable(unsigned long ulBase,unsigned long ulIntFlags) +{ + // + // Disable DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = + (ulIntFlags >> 30); + // + // Disable the individual interrupt sources + // + HWREG(ulBase + MMCHS_O_ISE) &= ~(ulIntFlags & 0x3FFFFFFF); +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of SDHost module. +//! +//! This function returns the interrupt status for the specified SDHost. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in SDHostIntEnable(). +// +//***************************************************************************** +unsigned long +SDHostIntStatus(unsigned long ulBase) +{ + unsigned long ulIntStatus; + + // + // Get DMA done interrupt status + // + ulIntStatus = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW); + ulIntStatus = (ulIntStatus << 30); + + // + // Return the status of individual interrupt sources + // + ulIntStatus |= (HWREG(ulBase + MMCHS_O_STAT) & 0x3FFFFFFF); + + return(ulIntStatus); +} + +//***************************************************************************** +// +//! Clears the individual interrupt sources. +//! +//! \param ulBase is the base address of SDHost module. +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified SDHost interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being recognized again immediately upon exit. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SDHostIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SDHostIntClear(unsigned long ulBase,unsigned long ulIntFlags) +{ + // + // Clear DMA done interrupts + // + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = + (ulIntFlags >> 30); + // + // Clear the individual interrupt sources + // + HWREG(ulBase + MMCHS_O_STAT) = (ulIntFlags & 0x3FFFFFFF); +} + +//***************************************************************************** +// +//! Sets the card status error mask. +//! +//! \param ulBase is the base address of SDHost module +//! \param ulErrMask is the bit mask of card status errors to be enabled +//! +//! This function sets the card status error mask for response type R1, R1b, +//! R5, R5b and R6 response. The parameter \e ulErrMask is the bit mask of card +//! status errors to be enabled, if the corresponding bits in the 'card status' +//! field of a respose are set then the host controller indicates a card error +//! interrupt status. Only bits referenced as type E (error) in status field in +//! the response can set a card status error. +//! +//! \return None +// +//***************************************************************************** +void +SDHostCardErrorMaskSet(unsigned long ulBase, unsigned long ulErrMask) +{ + // + // Set the card status error mask + // + HWREG(ulBase + MMCHS_O_CSRE) = ulErrMask; +} + + +//***************************************************************************** +// +//! Gets the card status error mask. +//! +//! \param ulBase is the base address of SDHost module +//! +//! This function gets the card status error mask for response type R1, R1b, +//! R5, R5b and R6 response. +//! +//! \return Returns the current card status error. +// +//***************************************************************************** +unsigned long +SDHostCardErrorMaskGet(unsigned long ulBase) +{ + // + // Return the card status error mask + // + return(HWREG(ulBase + MMCHS_O_CSRE)); +} + +//***************************************************************************** +// +//! Sets the SD Card clock. +//! +//! \param ulBase is the base address of SDHost module +//! \param ulSDHostClk is the rate of clock supplied to SDHost module +//! \param ulCardClk is the required SD interface clock +//! +//! This function configures the SDHost interface to supply the specified clock +//! to the connected card. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostSetExpClk(unsigned long ulBase, unsigned long ulSDHostClk, + unsigned long ulCardClk) +{ + unsigned long ulDiv; + + // + // Disable card clock + // + HWREG(ulBase + MMCHS_O_SYSCTL) &= ~0x4; + + // + // Enable internal clock + // + HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x1; + + ulDiv = ((ulSDHostClk/ulCardClk) & 0x3FF); + + // + // Set clock divider, + // + HWREG(ulBase + MMCHS_O_SYSCTL) = ((HWREG(ulBase + MMCHS_O_SYSCTL) & + ~0x0000FFC0)| (ulDiv) << 6); + + // + // Wait for clock to stablize + // + while( !(HWREG(ulBase + MMCHS_O_SYSCTL) & 0x2) ) + { + + } + + // + // Enable card clock + // + HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x4; +} + +//***************************************************************************** +// +//! Get the response for the last command. +//! +//! \param ulBase is the base address of SDHost module +//! \param ulRespnse is 128-bit response. +//! +//! This function gets the response from the SD card for the last command +//! send. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostRespGet(unsigned long ulBase, unsigned long ulRespnse[4]) +{ + + // + // Read the responses. + // + ulRespnse[0] = HWREG(ulBase + MMCHS_O_RSP10); + ulRespnse[1] = HWREG(ulBase + MMCHS_O_RSP32); + ulRespnse[2] = HWREG(ulBase + MMCHS_O_RSP54); + ulRespnse[3] = HWREG(ulBase + MMCHS_O_RSP76); + +} + +//***************************************************************************** +// +//! Set the block size for data transfer +//! +//! \param ulBase is the base address of SDHost module +//! \param ulBlkSize is the transfer block size in bytes +//! +//! This function sets the block size the data transfer. +//! +//! The parameter \e ulBlkSize is size of each data block in bytes. +//! This should be in range 0 - 2^10. +//! +//! \return None. +// +//***************************************************************************** +void +SDHostBlockSizeSet(unsigned long ulBase, unsigned short ulBlkSize) +{ + // + // Set the block size + // + HWREG(ulBase + MMCHS_O_BLK) = ((HWREG(ulBase + MMCHS_O_BLK) & 0x00000FFF)| + (ulBlkSize & 0xFFF)); +} + +//***************************************************************************** +// +//! Set the block size and count for data transfer +//! +//! \param ulBase is the base address of SDHost module +//! \param ulBlkCount is the number of blocks +//! +//! This function sets block count for the data transfer. This needs to be set +//! for each block transfer. \sa SDHostBlockSizeSet() +//! +//! \return None. +// +//***************************************************************************** +void +SDHostBlockCountSet(unsigned long ulBase, unsigned short ulBlkCount) +{ + unsigned long ulRegVal; + + // + // Read the current value + // + ulRegVal = HWREG(ulBase + MMCHS_O_BLK); + + // + // Set the number of blocks + // + HWREG(ulBase + MMCHS_O_BLK) = ((ulRegVal & 0x0000FFFF)| + (ulBlkCount << 16)); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/sdhost.h b/src/openmv/src/micropython/ports/cc3200/hal/sdhost.h new file mode 100755 index 0000000..d0d3984 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/sdhost.h @@ -0,0 +1,204 @@ +//***************************************************************************** +// +// sdhost.h +// +// Defines and Macros for the SDHost. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __SDHOST_H__ +#define __SDHOST_H__ + + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +//{ +#endif + + +//***************************************************************************** +// Values that can be passed to SDHostRespGet(). +//***************************************************************************** +#define SDHOST_RESP_10 0x00000003 +#define SDHOST_RESP_32 0x00000002 +#define SDHOST_RESP_54 0x00000001 +#define SDHOST_RESP_76 0x00000000 + + +//***************************************************************************** +// Values that can be passed to SDHostIntEnable(), SDHostIntDisable(), +// SDHostIntClear() ,and returned from SDHostIntStatus(). +//***************************************************************************** +#define SDHOST_INT_CC 0x00000001 +#define SDHOST_INT_TC 0x00000002 +#define SDHOST_INT_BWR 0x00000010 +#define SDHOST_INT_BRR 0x00000020 +#define SDHOST_INT_ERRI 0x00008000 +#define SDHOST_INT_CTO 0x00010000 +#define SDHOST_INT_CEB 0x00040000 +#define SDHOST_INT_DTO 0x00100000 +#define SDHOST_INT_DCRC 0x00200000 +#define SDHOST_INT_DEB 0x00400000 +#define SDHOST_INT_CERR 0x10000000 +#define SDHOST_INT_BADA 0x20000000 +#define SDHOST_INT_DMARD 0x40000000 +#define SDHOST_INT_DMAWR 0x80000000 + +//***************************************************************************** +// Values that can be passed to SDHostCmdSend(). +//***************************************************************************** +#define SDHOST_CMD_0 0x00000000 +#define SDHOST_CMD_1 0x01000000 +#define SDHOST_CMD_2 0x02000000 +#define SDHOST_CMD_3 0x03000000 +#define SDHOST_CMD_4 0x04000000 +#define SDHOST_CMD_5 0x05000000 +#define SDHOST_CMD_6 0x06000000 +#define SDHOST_CMD_7 0x07000000 +#define SDHOST_CMD_8 0x08000000 +#define SDHOST_CMD_9 0x09000000 +#define SDHOST_CMD_10 0x0A000000 +#define SDHOST_CMD_11 0x0B000000 +#define SDHOST_CMD_12 0x0C000000 +#define SDHOST_CMD_13 0x0D000000 +#define SDHOST_CMD_14 0x0E000000 +#define SDHOST_CMD_15 0x0F000000 +#define SDHOST_CMD_16 0x10000000 +#define SDHOST_CMD_17 0x11000000 +#define SDHOST_CMD_18 0x12000000 +#define SDHOST_CMD_19 0x13000000 +#define SDHOST_CMD_20 0x14000000 +#define SDHOST_CMD_21 0x15000000 +#define SDHOST_CMD_22 0x16000000 +#define SDHOST_CMD_23 0x17000000 +#define SDHOST_CMD_24 0x18000000 +#define SDHOST_CMD_25 0x19000000 +#define SDHOST_CMD_26 0x1A000000 +#define SDHOST_CMD_27 0x1B000000 +#define SDHOST_CMD_28 0x1C000000 +#define SDHOST_CMD_29 0x1D000000 +#define SDHOST_CMD_30 0x1E000000 +#define SDHOST_CMD_31 0x1F000000 +#define SDHOST_CMD_32 0x20000000 +#define SDHOST_CMD_33 0x21000000 +#define SDHOST_CMD_34 0x22000000 +#define SDHOST_CMD_35 0x23000000 +#define SDHOST_CMD_36 0x24000000 +#define SDHOST_CMD_37 0x25000000 +#define SDHOST_CMD_38 0x26000000 +#define SDHOST_CMD_39 0x27000000 +#define SDHOST_CMD_40 0x28000000 +#define SDHOST_CMD_41 0x29000000 +#define SDHOST_CMD_42 0x2A000000 +#define SDHOST_CMD_43 0x2B000000 +#define SDHOST_CMD_44 0x2C000000 +#define SDHOST_CMD_45 0x2D000000 +#define SDHOST_CMD_46 0x2E000000 +#define SDHOST_CMD_47 0x2F000000 +#define SDHOST_CMD_48 0x30000000 +#define SDHOST_CMD_49 0x31000000 +#define SDHOST_CMD_50 0x32000000 +#define SDHOST_CMD_51 0x33000000 +#define SDHOST_CMD_52 0x34000000 +#define SDHOST_CMD_53 0x35000000 +#define SDHOST_CMD_54 0x36000000 +#define SDHOST_CMD_55 0x37000000 +#define SDHOST_CMD_56 0x38000000 +#define SDHOST_CMD_57 0x39000000 +#define SDHOST_CMD_58 0x3A000000 +#define SDHOST_CMD_59 0x3B000000 +#define SDHOST_CMD_60 0x3C000000 +#define SDHOST_CMD_61 0x3D000000 +#define SDHOST_CMD_62 0x3E000000 +#define SDHOST_CMD_63 0x3F000000 + +//***************************************************************************** +// Values that can be logically ORed with ulCmd parameter for SDHostCmdSend(). +//***************************************************************************** +#define SDHOST_MULTI_BLK 0x00000022 +#define SDHOST_DMA_EN 0x00000001 +#define SDHOST_WR_CMD 0x00200000 +#define SDHOST_RD_CMD 0x00200010 +#define SDHOST_RESP_LEN_136 0x00010000 +#define SDHOST_RESP_LEN_48 0x00020000 +#define SDHOST_RESP_LEN_48B 0x00030000 + + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void SDHostCmdReset(unsigned long ulBase); +extern void SDHostInit(unsigned long ulBase); +extern long SDHostCmdSend(unsigned long ulBase,unsigned long ulCmd, + unsigned ulArg); +extern void SDHostIntRegister(unsigned long ulBase, void (*pfnHandler)(void)); +extern void SDHostIntUnregister(unsigned long ulBase); +extern void SDHostIntEnable(unsigned long ulBase,unsigned long ulIntFlags); +extern void SDHostIntDisable(unsigned long ulBase,unsigned long ulIntFlags); +extern unsigned long SDHostIntStatus(unsigned long ulBase); +extern void SDHostIntClear(unsigned long ulBase,unsigned long ulIntFlags); +extern void SDHostCardErrorMaskSet(unsigned long ulBase, + unsigned long ulErrMask); +extern unsigned long SDHostCardErrorMaskGet(unsigned long ulBase); +extern void SDHostSetExpClk(unsigned long ulBase, unsigned long ulSDHostClk, + unsigned long ulCardClk); +extern void SDHostRespGet(unsigned long ulBase, unsigned long ulRespnse[4]); +extern void SDHostBlockSizeSet(unsigned long ulBase, unsigned short ulBlkSize); +extern void SDHostBlockCountSet(unsigned long ulBase, + unsigned short ulBlkCount); +extern tBoolean SDHostDataNonBlockingWrite(unsigned long ulBase, + unsigned long ulData); +extern tBoolean SDHostDataNonBlockingRead(unsigned long ulBase, + unsigned long *pulData); +extern void SDHostDataWrite(unsigned long ulBase, unsigned long ulData); +extern void SDHostDataRead(unsigned long ulBase, unsigned long *ulData); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +//} +#endif + +#endif // __SDHOST_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/shamd5.c b/src/openmv/src/micropython/ports/cc3200/hal/shamd5.c new file mode 100755 index 0000000..6a3cc1c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/shamd5.c @@ -0,0 +1,1085 @@ +//***************************************************************************** +// +// shamd5.c +// +// Driver for the SHA/MD5 module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup SHA_Secure_Hash_Algorithm_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_dthe.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_shamd5.h" +#include "inc/hw_types.h" +#include "debug.h" +#include "interrupt.h" +#include "shamd5.h" +#include "rom_map.h" + +#define SHAMD5_MODE_ALGO_MD5 0x00000000 // MD5 +#define SHAMD5_MODE_ALGO_SHA1 0x00000002 // SHA-1 +#define SHAMD5_MODE_ALGO_SHA224 0x00000004 // SHA-224 +#define SHAMD5_MODE_ALGO_SHA256 0x00000006 // SHA-256 + +//***************************************************************************** +// +//! Enables the uDMA requests in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! +//! This function configures the DMA options of the SHA/MD5 module. +//! +//! \return None +// +//***************************************************************************** +void +SHAMD5DMAEnable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Write the new configuration into the register. + // + HWREG(ui32Base + SHAMD5_O_SYSCONFIG) |= + SHAMD5_SYSCONFIG_PADVANCED | SHAMD5_SYSCONFIG_PDMA_EN; +} + +//***************************************************************************** +// +//! Disables the uDMA requests in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! +//! This function configures the DMA options of the SHA/MD5 module. +//! +//! \return None +// +//***************************************************************************** +void +SHAMD5DMADisable(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Write the new configuration into the register. + // + HWREG(ui32Base + SHAMD5_O_SYSCONFIG) &= + ~(SHAMD5_SYSCONFIG_PADVANCED | SHAMD5_SYSCONFIG_PDMA_EN); +} + +//***************************************************************************** +// +//! Get the interrupt status of the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! This function returns the current value of the IRQSTATUS register. The +//! value will be a logical OR of the following: +//! +//! - \b SHAMD5_INT_CONTEXT_READY - Context input registers are ready. +//! - \b SHAMD5_INT_PARTHASH_READY - Context output registers are ready after +//! a context switch. +//! - \b SHAMD5_INT_INPUT_READY - Data FIFO is ready to receive data. +//! - \b SHAMD5_INT_OUTPUT_READY - Context output registers are ready. +//! +//! \return Interrupt status +// +//***************************************************************************** +uint32_t +SHAMD5IntStatus(uint32_t ui32Base, bool bMasked) +{ + uint32_t ui32Temp; + uint32_t ui32IrqEnable; + + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Return the value of the IRQSTATUS register. + // + if(bMasked) + { + ui32Temp = HWREG(DTHE_BASE + DTHE_O_SHA_MIS); + ui32IrqEnable = HWREG(ui32Base + SHAMD5_O_IRQENABLE); + return((HWREG(ui32Base + SHAMD5_O_IRQSTATUS) & + ui32IrqEnable) | (ui32Temp & 0x00000007) << 16); + } + else + { + ui32Temp = HWREG(DTHE_BASE + DTHE_O_SHA_RIS); + return(HWREG(ui32Base + SHAMD5_O_IRQSTATUS) | + (ui32Temp & 0x00000007) << 16); + + } +} + +//***************************************************************************** +// +//! Enable interrupt sources in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param ui32IntFlags contains desired interrupts to enable. +//! +//! This function enables interrupt sources in the SHA/MD5 module. +//! ui32IntFlags must be a logical OR of one or more of the following +//! values: +//! +//! - \b SHAMD5_INT_CONTEXT_READY - Context input registers are ready. +//! - \b SHAMD5_INT_PARTHASH_READY - Context output registers are ready after +//! a context switch. +//! - \b SHAMD5_INT_INPUT_READY - Data FIFO is ready to receive data. +//! - \b SHAMD5_INT_OUTPUT_READY - Context output registers are ready. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5IntEnable(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + ASSERT((ui32IntFlags == SHAMD5_INT_CONTEXT_READY) || + (ui32IntFlags == SHAMD5_INT_PARTHASH_READY) || + (ui32IntFlags == SHAMD5_INT_INPUT_READY) || + (ui32IntFlags == SHAMD5_INT_OUTPUT_READY)); + + // + // Enable the interrupt sources. + // + HWREG(DTHE_BASE + DTHE_O_SHA_IM) &= ~((ui32IntFlags & 0x00070000) >> 16); + HWREG(ui32Base + SHAMD5_O_IRQENABLE) |= ui32IntFlags & 0x0000ffff; + + // + // Enable all interrupts. + // + HWREG(ui32Base + SHAMD5_O_SYSCONFIG) |= SHAMD5_SYSCONFIG_PIT_EN; +} + +//***************************************************************************** +// +//! Disable interrupt sources in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param ui32IntFlags contains desired interrupts to disable. +//! +//! \e ui32IntFlags must be a logical OR of one or more of the following +//! values: +//! +//! - \b SHAMD5_INT_CONTEXT_READY - Context input registers are ready. +//! - \b SHAMD5_INT_PARTHASH_READY - Context output registers are ready after +//! a context switch. +//! - \b SHAMD5_INT_INPUT_READY - Data FIFO is ready to receive data. +//! - \b SHAMD5_INT_OUTPUT_READY - Context output registers are ready. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5IntDisable(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + ASSERT((ui32IntFlags == SHAMD5_INT_CONTEXT_READY) || + (ui32IntFlags == SHAMD5_INT_PARTHASH_READY) || + (ui32IntFlags == SHAMD5_INT_INPUT_READY) || + (ui32IntFlags == SHAMD5_INT_OUTPUT_READY)); + + // + // Clear the corresponding flags disabling the interrupt sources. + // + HWREG(DTHE_BASE + DTHE_O_SHA_IM) |= ((ui32IntFlags & 0x00070000) >> 16); + HWREG(ui32Base + SHAMD5_O_IRQENABLE) &= ~(ui32IntFlags & 0x0000ffff); + + // + // If there are no interrupts enabled, then disable all interrupts. + // + if(HWREG(ui32Base + SHAMD5_O_IRQENABLE) == 0x0) + { + HWREG(ui32Base + SHAMD5_O_SYSCONFIG) &= ~SHAMD5_SYSCONFIG_PIT_EN; + } +} + +//***************************************************************************** +// +//! Clears interrupt sources in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param ui32IntFlags contains desired interrupts to disable. +//! +//! \e ui32IntFlags must be a logical OR of one or more of the following +//! values: +//! +//! - \b SHAMD5_INT_CONTEXT_READY - Context input registers are ready. +//! - \b SHAMD5_INT_PARTHASH_READY - Context output registers are ready after +//! a context switch. +//! - \b SHAMD5_INT_INPUT_READY - Data FIFO is ready to receive data. +//! - \b SHAMD5_INT_OUTPUT_READY - Context output registers are ready. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5IntClear(uint32_t ui32Base, uint32_t ui32IntFlags) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + ASSERT((ui32IntFlags == SHAMD5_INT_CONTEXT_READY) || + (ui32IntFlags == SHAMD5_INT_PARTHASH_READY) || + (ui32IntFlags == SHAMD5_INT_INPUT_READY) || + (ui32IntFlags == SHAMD5_INT_OUTPUT_READY)); + + // + // Clear the corresponding flags disabling the interrupt sources. + // + HWREG(DTHE_BASE + DTHE_O_SHA_IC) = ((ui32IntFlags & 0x00070000) >> 16); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param pfnHandler is a pointer to the function to be called when the +//! enabled SHA/MD5 interrupts occur. +//! +//! This function registers the interrupt handler in the interrupt vector +//! table, and enables SHA/MD5 interrupts on the interrupt controller; +//! specific SHA/MD5 interrupt sources must be enabled using +//! SHAMD5IntEnable(). The interrupt handler being registered must clear +//! the source of the interrupt using SHAMD5IntClear(). +//! +//! If the application is using a static interrupt vector table stored in +//! flash, then it is not necessary to register the interrupt handler this way. +//! Instead, IntEnable() should be used to enable SHA/MD5 interrupts on the +//! interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5IntRegister(uint32_t ui32Base, void(*pfnHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Register the interrupt handler. + // + IntRegister(INT_SHA, pfnHandler); + + // + // Enable the interrupt + // + IntEnable(INT_SHA); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! +//! This function unregisters the previously registered interrupt handler and +//! disables the interrupt in the interrupt controller. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5IntUnregister(uint32_t ui32Base) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Disable the interrupt. + // + IntDisable(INT_SHA); + + // + // Unregister the interrupt handler. + // + IntUnregister(INT_SHA); +} + +//***************************************************************************** +// +//! Write the hash length to the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param ui32Length is the hash length in bytes. +//! +//! This function writes the length of the hash data of the current operation +//! to the SHA/MD5 module. The value must be a multiple of 64 if the close +//! hash is not set in the mode register. +//! +//! \note When this register is written, hash processing is triggered. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5DataLengthSet(uint32_t ui32Base, uint32_t ui32Length) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Set the LENGTH register and start processing. + // + HWREG(ui32Base + SHAMD5_O_LENGTH) = ui32Length; +} + +//***************************************************************************** +// +//! Writes the mode in the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param ui32Mode is the mode of the SHA/MD5 module. +//! +//! This function writes the mode register configuring the SHA/MD5 module. +//! +//! The ui32Mode paramerter is a bit-wise OR of values: +//! +//! - \b SHAMD5_ALGO_MD5 - Regular hash with MD5 +//! - \b SHAMD5_ALGO_SHA1 - Regular hash with SHA-1 +//! - \b SHAMD5_ALGO_SHA224 - Regular hash with SHA-224 +//! - \b SHAMD5_ALGO_SHA256 - Regular hash with SHA-256 +//! - \b SHAMD5_ALGO_HMAC_MD5 - HMAC with MD5 +//! - \b SHAMD5_ALGO_HMAC_SHA1 - HMAC with SHA-1 +//! - \b SHAMD5_ALGO_HMAC_SHA224 - HMAC with SHA-224 +//! - \b SHAMD5_ALGO_HMAC_SHA256 - HMAC with SHA-256 +//! +//! \return None +// +//***************************************************************************** +void +SHAMD5ConfigSet(uint32_t ui32Base, uint32_t ui32Mode) +{ + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + ASSERT((ui32Mode == SHAMD5_ALGO_MD5) || + (ui32Mode == SHAMD5_ALGO_SHA1) || + (ui32Mode == SHAMD5_ALGO_SHA224) || + (ui32Mode == SHAMD5_ALGO_SHA256) || + (ui32Mode == SHAMD5_ALGO_HMAC_MD5) || + (ui32Mode == SHAMD5_ALGO_HMAC_SHA1) || + (ui32Mode == SHAMD5_ALGO_HMAC_SHA224) || + (ui32Mode == SHAMD5_ALGO_HMAC_SHA256)); + + // + // Write the value in the MODE register. + // + HWREG(ui32Base + SHAMD5_O_MODE) = ui32Mode; +} + +//***************************************************************************** +// +//! Perform a non-blocking write of 16 words of data to the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param pui8Src is the pointer to the 16-word array of data that will be +//! written. +//! +//! This function writes 16 words of data into the data register. +//! +//! \return This function returns true if the write completed successfully. +//! It returns false if the module was not ready. +// +//***************************************************************************** +bool +SHAMD5DataWriteNonBlocking(uint32_t ui32Base, uint8_t *pui8Src) +{ + uint32_t ui8Counter; + + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Check that the SHA/MD5 module is ready for data. If not, return false. + // + if((HWREG(ui32Base + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_INPUT_READY) == 0) + { + return(false); + } + + // + // Write the 16 words of data. + // + for(ui8Counter = 0; ui8Counter < 64; ui8Counter += 4) + { + HWREG(ui32Base + SHAMD5_O_DATA0_IN + ui8Counter) = *((uint32_t *)(pui8Src + ui8Counter)); + } + + // + // Return true as a sign of successfully completing the function. + // + return(true); +} + +//***************************************************************************** +// +//! Perform a blocking write of 64 bytes of data to the SHA/MD5 module. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param pui8Src is the pointer to the 64-byte array of data that will be +//! written. +//! +//! This function does not return until the module is ready to accept data and +//! the data has been written. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5DataWrite(uint32_t ui32Base, uint8_t *pui8Src) +{ + uint8_t ui8Counter; + + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Wait for the module to be ready to accept data. + // + while((HWREG(ui32Base + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_INPUT_READY) == 0) + { + } + + // + // Write the 64 bytes of data. + // + for(ui8Counter = 0; ui8Counter < 64; ui8Counter += 4) + { + HWREG(ui32Base + SHAMD5_O_DATA0_IN + ui8Counter) = + *((uint32_t *) (pui8Src + ui8Counter)); + } +} + + +//***************************************************************************** +// +//! Reads the result of a hashing operation. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param pui8Dest is the pointer to the byte array of data that will be +//! written. +//! +//! This function does not return until the module is ready to accept data and +//! the data has been written. +//! ----------------------------------------- +//! | Algorithm | Number of Words in Result | +//! ----------------------------------------- +//! | MD5 | 16 Bytes (128 bits) | +//! | SHA-1 | 20 Bytes (160 bits) | +//! | SHA-224 | 28 Bytes (224 bits) | +//! | SHA-256 | 32 Bytes (256 bits) | +//! ----------------------------------------- +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5ResultRead(uint32_t ui32Base, uint8_t *pui8Dest) +{ + uint32_t ui32Idx, ui32Count; + + // + // Check the arguments. + // + ASSERT(ui32Base == SHAMD5_BASE); + + // + // Determine the number of bytes in the result, based on the hash type. + // + switch(HWREG(ui32Base + SHAMD5_O_MODE) & SHAMD5_MODE_ALGO_M) + { + // + // The MD5 hash is being used. + // + case SHAMD5_MODE_ALGO_MD5: + { + // + // There are 16 bytes in the MD5 hash. + // + ui32Count = 16; + + // + // Done. + // + break; + } + + // + // The SHA-1 hash is being used. + // + case SHAMD5_MODE_ALGO_SHA1: + { + // + // There are 20 bytes in the SHA-1 hash. + // + ui32Count = 20; + + // + // Done. + // + break; + } + + // + // The SHA-224 hash is being used. + // + case SHAMD5_MODE_ALGO_SHA224: + { + // + // There are 28 bytes in the SHA-224 hash. + // + ui32Count = 28; + + // + // Done. + // + break; + } + + // + // The SHA-256 hash is being used. + // + case SHAMD5_MODE_ALGO_SHA256: + { + // + // There are 32 bytes in the SHA-256 hash. + // + ui32Count = 32; + + // + // Done. + // + break; + } + + // + // The hash type is not recognized. + // + default: + { + // + // Return without reading a result since the hardware appears to be + // misconfigured. + // + return; + } + } + + // + // Read the hash result. + // + for(ui32Idx = 0; ui32Idx < ui32Count; ui32Idx += 4) + { + *((uint32_t *)(pui8Dest+ui32Idx)) = + HWREG(ui32Base + SHAMD5_O_IDIGEST_A + ui32Idx); + } +} + +//***************************************************************************** +// +//! Writes multiple words of data into the SHA/MD5 data registers. +//! +//! \param ui32Base is the base address of the SHA/MD5 module. +//! \param pui8DataSrc is a pointer to an array of data to be written. +//! \param ui32DataLength is the length of the data to be written in bytes. +//! +//! This function writes a variable number of words into the SHA/MD5 data +//! registers. The function waits for each block of data to be processed +//! before another is written. +//! +//! \note This function is used by SHAMD5HashCompute(), SHAMD5HMACWithKPP(), +//! and SHAMD5HMACNoKPP() to process data. +//! +//! \return None. +// +//***************************************************************************** +void +SHAMD5DataWriteMultiple(uint8_t *pui8DataSrc, uint32_t ui32DataLength) +{ + uint32_t ui32Idx, ui32Count, ui32Lastword, ui32TempData = 0; + uint8_t * ui8TempData; + + + // + // Calculate the number of blocks of data. + // + ui32Count = ui32DataLength / 64; + + // + // Loop through all the blocks and write them into the data registers + // making sure to block additional operations until we can write the + // next 16 words. + // + for (ui32Idx = 0; ui32Idx < ui32Count; ui32Idx++) + { + // + // Write the block of data. + // + MAP_SHAMD5DataWrite(SHAMD5_BASE, pui8DataSrc); + // + // Increment the pointer to next block of data. + // + pui8DataSrc += 64; + } + + // + // Calculate the remaining bytes of data that don't make up a full block. + // + ui32Count = ui32DataLength % 64; + + // + // If there are bytes that do not make up a whole block, then + // write them separately. + // + if(ui32Count) + { + // + // Wait until the engine has finished processing the previous block. + // + while ((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_INPUT_READY) == 0); + + // + // Loop through the remaining words. + // + ui32Count = ui32Count / 4; + for (ui32Idx = 0; ui32Idx < ui32Count; ui32Idx ++) + { + // + // Write the word into the data register. + // + HWREG(SHAMD5_BASE + SHAMD5_O_DATA0_IN + (ui32Idx * 4)) =* ( (uint32_t *) pui8DataSrc); + pui8DataSrc +=4; + } + // + // Loop through the remaining bytes + // + ui32Count = ui32DataLength % 4; + ui8TempData = (uint8_t *) &ui32TempData; + if(ui32Count) + { + ui32Lastword = 0; + if(ui32Idx) + { + ui32Lastword = (ui32Idx-1) *4; + } + for(ui32Idx=0 ; ui32Idx +//! Polarity Phase Sub-Mode +//! 0 0 0 +//! 0 1 1 +//! 1 0 2 +//! 1 1 3 +//!
+//! +//! Required sub mode can be select by setting \e ulSubMode parameter to one +//! of the following +//! - \b SPI_SUB_MODE_0 +//! - \b SPI_SUB_MODE_1 +//! - \b SPI_SUB_MODE_2 +//! - \b SPI_SUB_MODE_3 +//! +//! The parameter \e ulConfig is logical OR of five values: the word length, +//! active level for chip select, software or hardware controled chip select, +//! 3 or 4 pin mode and turbo mode. +//! mode. +//! +//! SPI support 8, 16 and 32 bit word lengths defined by:- +//! - \b SPI_WL_8 +//! - \b SPI_WL_16 +//! - \b SPI_WL_32 +//! +//! Active state of Chip Select can be defined by:- +//! - \b SPI_CS_ACTIVELOW +//! - \b SPI_CS_ACTIVEHIGH +//! +//! SPI chip select can be configured to be controlled either by hardware or +//! software:- +//! - \b SPI_SW_CS +//! - \b SPI_HW_CS +//! +//! The module can work in 3 or 4 pin mode defined by:- +//! - \b SPI_3PIN_MODE +//! - \b SPI_4PIN_MODE +//! +//! Turbo mode can be set on or turned off using:- +//! - \b SPI_TURBO_MODE_ON +//! - \b SPI_TURBO_MODE_OFF +//! +//! \return None. +// +//***************************************************************************** +void +SPIConfigSetExpClk(unsigned long ulBase,unsigned long ulSPIClk, + unsigned long ulBitRate, unsigned long ulMode, + unsigned long ulSubMode, unsigned long ulConfig) +{ + + unsigned long ulRegData; + unsigned long ulDivider; + + // + // Read MODULCTRL register + // + ulRegData = HWREG(ulBase + MCSPI_O_MODULCTRL); + + // + // Set Master mode with h/w chip select + // + ulRegData &= ~(MCSPI_MODULCTRL_MS | + MCSPI_MODULCTRL_SINGLE); + + // + // Enable software control Chip Select, Init delay + // and 3-pin mode + // + ulRegData |= (((ulConfig >> 24) | ulMode) & 0xFF); + + // + // Write the configuration + // + HWREG(ulBase + MCSPI_O_MODULCTRL) = ulRegData; + + // + // Set IS, DPE0, DPE1 based on master or slave mode + // + if(ulMode == SPI_MODE_MASTER) + { + ulRegData = 0x1 << 16; + } + else + { + ulRegData = 0x6 << 16; + } + + // + // set clock divider granularity to 1 cycle + // + ulRegData |= MCSPI_CH0CONF_CLKG; + + // + // Get the divider value + // + ulDivider = ((ulSPIClk/ulBitRate) - 1); + + // + // The least significant four bits of the divider is used to configure + // CLKD in MCSPI_CHCONF next eight least significant bits are used to + // configure the EXTCLK in MCSPI_CHCTRL + // + ulRegData |= ((ulDivider & 0x0000000F) << 2); + HWREG(ulBase + MCSPI_O_CH0CTRL) = ((ulDivider & 0x00000FF0) << 4); + + // + // Set the protocol, CS polarity, word length + // and turbo mode + // + ulRegData = ((ulRegData | + ulSubMode) | (ulConfig & 0x0008FFFF)); + + // + // Write back the CONF register + // + HWREG(ulBase + MCSPI_O_CH0CONF) = ulRegData; + +} + +//***************************************************************************** +// +//! Receives a word from the specified port. +//! +//! \param ulBase is the base address of the SPI module. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets a SPI word from the receive FIFO for the specified +//! port. +//! +//! \return Returns the number of elements read from the receive FIFO. +// +//***************************************************************************** +long +SPIDataGetNonBlocking(unsigned long ulBase, unsigned long *pulData) +{ + unsigned long ulRegVal; + + // + // Read register status register + // + ulRegVal = HWREG(ulBase + MCSPI_O_CH0STAT); + + // + // Check is data is available + // + if(ulRegVal & MCSPI_CH0STAT_RXS) + { + *pulData = HWREG(ulBase + MCSPI_O_RX0); + return(1); + } + + return(0); +} + +//***************************************************************************** +// +//! Waits for the word to be received on the specified port. +//! +//! \param ulBase is the base address of the SPI module. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets a SPI word from the receive FIFO for the specified +//! port. If there is no word available, this function waits until a +//! word is received before returning. +//! +//! \return Returns the word read from the specified port, cast as an +//! \e unsigned long. +// +//***************************************************************************** +void +SPIDataGet(unsigned long ulBase, unsigned long *pulData) +{ + // + // Wait for Rx data + // + while(!(HWREG(ulBase + MCSPI_O_CH0STAT) & MCSPI_CH0STAT_RXS)) + { + } + + // + // Read the value + // + *pulData = HWREG(ulBase + MCSPI_O_RX0); +} + +//***************************************************************************** +// +//! Transmits a word on the specified port. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulData is data to be transmitted. +//! +//! This function transmits a SPI word on the transmit FIFO for the specified +//! port. +//! +//! \return Returns the number of elements written to the transmit FIFO. +//! +//***************************************************************************** +long +SPIDataPutNonBlocking(unsigned long ulBase, unsigned long ulData) +{ + unsigned long ulRegVal; + + // + // Read status register + // + ulRegVal = HWREG(ulBase + MCSPI_O_CH0STAT); + + // + // Write value into Tx register/FIFO + // if space is available + // + if(ulRegVal & MCSPI_CH0STAT_TXS) + { + HWREG(ulBase + MCSPI_O_TX0) = ulData; + return(1); + } + + return(0); +} + +//***************************************************************************** +// +//! Waits until the word is transmitted on the specified port. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulData is data to be transmitted. +//! +//! This function transmits a SPI word on the transmit FIFO for the specified +//! port. This function waits until the space is available on transmit FIFO +//! +//! \return None +//! +//***************************************************************************** +void +SPIDataPut(unsigned long ulBase, unsigned long ulData) +{ + // + // Wait for space in FIFO + // + while(!(HWREG(ulBase + MCSPI_O_CH0STAT)&MCSPI_CH0STAT_TXS)) + { + } + + // + // Write the data + // + HWREG(ulBase + MCSPI_O_TX0) = ulData; +} + +//***************************************************************************** +// +//! Enables the transmit and/or receive FIFOs. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selects the FIFO(s) to be enabled +//! +//! This function enables the transmit and/or receive FIFOs as specified by +//! \e ulFlags. +//! The parameter \e ulFlags shoulde be logical OR of one or more of the +//! following: +//! - \b SPI_TX_FIFO +//! - \b SPI_RX_FIFO +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFOEnable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Set FIFO enable bits. + // + HWREG(ulBase + MCSPI_O_CH0CONF) |= ulFlags; +} + +//***************************************************************************** +// +//! Disables the transmit and/or receive FIFOs. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selects the FIFO(s) to be enabled +//! +//! This function disables transmit and/or receive FIFOs. as specified by +//! \e ulFlags. +//! The parameter \e ulFlags shoulde be logical OR of one or more of the +//! following: +//! - \b SPI_TX_FIFO +//! - \b SPI_RX_FIFO +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFODisable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Reset FIFO Enable bits. + // + HWREG(ulBase + MCSPI_O_CH0CONF) &= ~(ulFlags); +} + +//***************************************************************************** +// +//! Sets the FIFO level at which DMA requests or interrupts are generated. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulTxLevel is the Almost Empty Level for transmit FIFO. +//! \param ulRxLevel is the Almost Full Level for the receive FIFO. +//! +//! This function Sets the FIFO level at which DMA requests or interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void SPIFIFOLevelSet(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulRxLevel) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + // + // Mask and set new FIFO thresholds. + // + ulRegVal = ((ulRegVal & 0xFFFF0000) | (((ulRxLevel-1) << 8) | (ulTxLevel-1))); + + // + // Set the transmit and receive FIFO thresholds. + // + HWREG(ulBase + MCSPI_O_XFERLEVEL) = ulRegVal; + +} + +//***************************************************************************** +// +//! Gets the FIFO level at which DMA requests or interrupts are generated. +//! +//! \param ulBase is the base address of the SPI module +//! \param pulTxLevel is a pointer to storage for the transmit FIFO level +//! \param pulRxLevel is a pointer to storage for the receive FIFO level +//! +//! This function gets the FIFO level at which DMA requests or interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFOLevelGet(unsigned long ulBase, unsigned long *pulTxLevel, + unsigned long *pulRxLevel) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + *pulTxLevel = (ulRegVal & 0xFF); + + *pulRxLevel = ((ulRegVal >> 8) & 0xFF); + +} + +//***************************************************************************** +// +//! Sets the word count. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulWordCount is number of SPI words to be transmitted. +//! +//! This function sets the word count, which is the number of SPI word to +//! be transferred on channel when using the FIFO buffer. +//! +//! \return None. +// +//***************************************************************************** +void +SPIWordCountSet(unsigned long ulBase, unsigned long ulWordCount) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + // + // Mask and set the word count + // + HWREG(ulBase + MCSPI_O_XFERLEVEL) = ((ulRegVal & 0x0000FFFF)| + (ulWordCount & 0xFFFF) << 16); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for a SPI interrupt. +//! +//! \param ulBase is the base address of the SPI module +//! \param pfnHandler is a pointer to the function to be called when the +//! SPI interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; specific +//! SPI interrupts must be enabled via SPIIntEnable(). It is the interrupt +//! handler's responsibility to clear the interrupt source. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntRegister(unsigned long ulBase, void(*pfnHandler)(void)) +{ + unsigned long ulInt; + + // + // Determine the interrupt number based on the SPI module + // + ulInt = SPIIntNumberGet(ulBase); + + // + // Register the interrupt handler. + // + IntRegister(ulInt, pfnHandler); + + // + // Enable the SPI interrupt. + // + IntEnable(ulInt); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for a SPI interrupt. +//! +//! \param ulBase is the base address of the SPI module +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a SPI interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntUnregister(unsigned long ulBase) +{ + unsigned long ulInt; + + // + // Determine the interrupt number based on the SPI module + // + ulInt = SPIIntNumberGet(ulBase); + + // + // Disable the interrupt. + // + IntDisable(ulInt); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulInt); +} + +//***************************************************************************** +// +//! Enables individual SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated SPI interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b SPI_INT_DMATX +//! - \b SPI_INT_DMARX +//! - \b SPI_INT_EOW +//! - \b SPI_INT_RX_OVRFLOW +//! - \b SPI_INT_RX_FULL +//! - \b SPI_INT_TX_UDRFLOW +//! - \b SPI_INT_TX_EMPTY +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Enable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; + } + + // + // Enable DMA Rx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; + } + + // + // Enable the specific Interrupts + // + HWREG(ulBase + MCSPI_O_IRQENABLE) |= (ulIntFlags & 0x0003000F); +} + + +//***************************************************************************** +// +//! Disables individual SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! This function disables the indicated SPI interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SPIIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; + } + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; + } + + // + // Disable the specific Interrupts + // + HWREG(ulBase + MCSPI_O_IRQENABLE) &= ~(ulIntFlags & 0x0003000F); +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of the SPI module +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! This function returns the interrupt status for the specified SPI. +//! The status of interrupts that are allowed to reflect to the processor can +//! be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in SPIIntEnable(). +// +//***************************************************************************** +unsigned long +SPIIntStatus(unsigned long ulBase, tBoolean bMasked) +{ + unsigned long ulIntStat; + unsigned long ulIntFlag; + unsigned long ulDmaMsk; + + // + // Get SPI interrupt status + // + ulIntFlag = HWREG(ulBase + MCSPI_O_IRQSTATUS) & 0x0003000F; + + if(bMasked) + { + ulIntFlag &= HWREG(ulBase + MCSPI_O_IRQENABLE); + } + + // + // Get the interrupt bit + // + ulDmaMsk = SPIDmaMaskGet(ulBase); + + // + // Get the DMA interrupt status + // + if(bMasked) + { + ulIntStat = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED); + } + else + { + ulIntStat = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW); + } + + // + // Get SPI Tx DMA done status + // + if(ulIntStat & ulDmaMsk) + { + ulIntFlag |= SPI_INT_DMATX; + } + + // + // Get SPI Rx DMA done status + // + if(ulIntStat & (ulDmaMsk >> 1)) + { + ulIntFlag |= SPI_INT_DMARX; + } + + // + // Return status + // + return(ulIntFlag); +} + +//***************************************************************************** +// +//! Clears SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified SPI interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being recognized again immediately upon exit. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SPIIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntClear(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; + } + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; + } + + // + // Clear Interrupts + // + HWREG(ulBase + MCSPI_O_IRQSTATUS) = (ulIntFlags & 0x0003000F); +} + +//***************************************************************************** +// +//! Enables the chip select in software controlled mode +//! +//! \param ulBase is the base address of the SPI module. +//! +//! This function enables the Chip select in software controlled mode. The +//! active state of CS will depend on the configuration done via +//! \sa SPIConfigExpClkSet(). +//! +//! \return None. +// +//***************************************************************************** +void SPICSEnable(unsigned long ulBase) +{ + // + // Set Chip Select enable bit. + // + HWREG( ulBase+MCSPI_O_CH0CONF) |= MCSPI_CH0CONF_FORCE; +} + +//***************************************************************************** +// +//! Disables the chip select in software controlled mode +//! +//! \param ulBase is the base address of the SPI module. +//! +//! This function disables the Chip select in software controlled mode. The +//! active state of CS will depend on the configuration done via +//! sa SPIConfigSetExpClk(). +//! +//! \return None. +// +//***************************************************************************** +void SPICSDisable(unsigned long ulBase) +{ + // + // Reset Chip Select enable bit. + // + HWREG( ulBase+MCSPI_O_CH0CONF) &= ~MCSPI_CH0CONF_FORCE; +} + +//***************************************************************************** +// +//! Send/Receive data buffer over SPI channel +//! +//! \param ulBase is the base address of SPI module +//! \param ucDout is the pointer to Tx data buffer or 0. +//! \param ucDin is pointer to Rx data buffer or 0 +//! \param ulCount is the size of data in bytes. +//! \param ulFlags controlls chip select toggling. +//! +//! This function transfers \e ulCount bytes of data over SPI channel. Since +//! the API sends a SPI word at a time \e ulCount should be a multiple of +//! word length set using SPIConfigSetExpClk(). +//! +//! If the \e ucDout parameter is set to 0, the function will send 0xFF over +//! the SPI MOSI line. +//! +//! If the \e ucDin parameter is set to 0, the function will ignore data on SPI +//! MISO line. +//! +//! The parameter \e ulFlags is logical OR of one or more of the following +//! +//! - \b SPI_CS_ENABLE if CS needs to be enabled at start of transfer. +//! - \b SPI_CS_DISABLE if CS need to be disabled at the end of transfer. +//! +//! This function will not return until data has been transmitted +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +long SPITransfer(unsigned long ulBase, unsigned char *ucDout, + unsigned char *ucDin, unsigned long ulCount, + unsigned long ulFlags) +{ + unsigned long ulWordLength; + long lRet; + + // + // Get the word length + // + ulWordLength = (HWREG(ulBase + MCSPI_O_CH0CONF) & MCSPI_CH0CONF_WL_M); + + // + // Check for word length. + // + if( !((ulWordLength == SPI_WL_8) || (ulWordLength == SPI_WL_16) || + (ulWordLength == SPI_WL_32)) ) + { + return -1; + } + + if( ulWordLength == SPI_WL_8 ) + { + // + // Do byte transfer + // + lRet = SPITransfer8(ulBase,ucDout,ucDin,ulCount,ulFlags); + } + else if( ulWordLength == SPI_WL_16 ) + { + + // + // Do half-word transfer + // + lRet = SPITransfer16(ulBase,(unsigned short *)ucDout, + (unsigned short *)ucDin,ulCount,ulFlags); + } + else + { + // + // Do word transfer + // + lRet = SPITransfer32(ulBase,(unsigned long *)ucDout, + (unsigned long *)ucDin,ulCount,ulFlags); + } + + // + // return + // + return lRet; + +} +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/spi.h b/src/openmv/src/micropython/ports/cc3200/hal/spi.h new file mode 100755 index 0000000..593986b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/spi.h @@ -0,0 +1,163 @@ +//***************************************************************************** +// +// spi.h +// +// Defines and Macros for the SPI. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __SPI_H__ +#define __SPI_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// Values that can be passed to SPIConfigSetExpClk() as ulMode parameter +//***************************************************************************** +#define SPI_MODE_MASTER 0x00000000 +#define SPI_MODE_SLAVE 0x00000004 + +//***************************************************************************** +// Values that can be passed to SPIConfigSetExpClk() as ulSubMode parameter +//***************************************************************************** +#define SPI_SUB_MODE_0 0x00000000 +#define SPI_SUB_MODE_1 0x00000001 +#define SPI_SUB_MODE_2 0x00000002 +#define SPI_SUB_MODE_3 0x00000003 + + +//***************************************************************************** +// Values that can be passed to SPIConfigSetExpClk() as ulConfigFlags parameter +//***************************************************************************** +#define SPI_SW_CTRL_CS 0x01000000 +#define SPI_HW_CTRL_CS 0x00000000 +#define SPI_3PIN_MODE 0x02000000 +#define SPI_4PIN_MODE 0x00000000 +#define SPI_TURBO_ON 0x00080000 +#define SPI_TURBO_OFF 0x00000000 +#define SPI_CS_ACTIVEHIGH 0x00000000 +#define SPI_CS_ACTIVELOW 0x00000040 +#define SPI_WL_8 0x00000380 +#define SPI_WL_16 0x00000780 +#define SPI_WL_32 0x00000F80 + +//***************************************************************************** +// Values that can be passed to SPIFIFOEnable() and SPIFIFODisable() +//***************************************************************************** +#define SPI_TX_FIFO 0x08000000 +#define SPI_RX_FIFO 0x10000000 + +//***************************************************************************** +// Values that can be passed to SPIDMAEnable() and SPIDMADisable() +//***************************************************************************** +#define SPI_RX_DMA 0x00008000 +#define SPI_TX_DMA 0x00004000 + +//***************************************************************************** +// Values that can be passed to SPIIntEnable(), SPIIntDiasble(), +// SPIIntClear() or returned from SPIStatus() +//***************************************************************************** +#define SPI_INT_DMATX 0x20000000 +#define SPI_INT_DMARX 0x10000000 +#define SPI_INT_EOW 0x00020000 +#define SPI_INT_WKS 0x00010000 +#define SPI_INT_RX_OVRFLOW 0x00000008 +#define SPI_INT_RX_FULL 0x00000004 +#define SPI_INT_TX_UDRFLOW 0x00000002 +#define SPI_INT_TX_EMPTY 0x00000001 + +//***************************************************************************** +// Values that can be passed to SPITransfer() +//***************************************************************************** +#define SPI_CS_ENABLE 0x00000001 +#define SPI_CS_DISABLE 0x00000002 + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void SPIEnable(unsigned long ulBase); +extern void SPIDisable(unsigned long ulBase); +extern void SPIReset(unsigned long ulBase); +extern void SPIConfigSetExpClk(unsigned long ulBase,unsigned long ulSPIClk, + unsigned long ulBitRate, unsigned long ulMode, + unsigned long ulSubMode, unsigned long ulConfig); +extern long SPIDataGetNonBlocking(unsigned long ulBase, + unsigned long * pulData); +extern void SPIDataGet(unsigned long ulBase, unsigned long *pulData); +extern long SPIDataPutNonBlocking(unsigned long ulBase, + unsigned long ulData); +extern void SPIDataPut(unsigned long ulBase, unsigned long ulData); +extern void SPIFIFOEnable(unsigned long ulBase, unsigned long ulFlags); +extern void SPIFIFODisable(unsigned long ulBase, unsigned long ulFlags); +extern void SPIFIFOLevelSet(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulRxLevel); +extern void SPIFIFOLevelGet(unsigned long ulBase, unsigned long *pulTxLevel, + unsigned long *pulRxLevel); +extern void SPIWordCountSet(unsigned long ulBase, unsigned long ulWordCount); +extern void SPIIntRegister(unsigned long ulBase, void(*pfnHandler)(void)); +extern void SPIIntUnregister(unsigned long ulBase); +extern void SPIIntEnable(unsigned long ulBase, unsigned long ulIntFlags); +extern void SPIIntDisable(unsigned long ulBase, unsigned long ulIntFlags); +extern unsigned long SPIIntStatus(unsigned long ulBase, tBoolean bMasked); +extern void SPIIntClear(unsigned long ulBase, unsigned long ulIntFlags); +extern void SPIDmaEnable(unsigned long ulBase, unsigned long ulFlags); +extern void SPIDmaDisable(unsigned long ulBase, unsigned long ulFlags); +extern void SPICSEnable(unsigned long ulBase); +extern void SPICSDisable(unsigned long ulBase); +extern long SPITransfer(unsigned long ulBase, unsigned char *ucDout, + unsigned char *ucDin, unsigned long ulSize, + unsigned long ulFlags); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __SPI_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/startup_gcc.c b/src/openmv/src/micropython/ports/cc3200/hal/startup_gcc.c new file mode 100755 index 0000000..e173e8f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/startup_gcc.c @@ -0,0 +1,421 @@ +//***************************************************************************** +// startup_gcc.c +// +// Startup code for use with GCC. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "fault_registers.h" + +//***************************************************************************** +// +// The following are constructs created by the linker, indicating where the +// the "data" and "bss" segments reside in memory. The initializers for the +// for the "data" segment resides immediately following the "text" segment. +// +//***************************************************************************** +extern uint32_t _data; +extern uint32_t _edata; +extern uint32_t _bss; +extern uint32_t _ebss; +extern uint32_t _estack; + +//***************************************************************************** +// +// Forward declaration of the default fault handlers. +// +//***************************************************************************** +#ifndef BOOTLOADER +__attribute__ ((section (".boot"))) +#endif +void ResetISR(void); +#ifdef DEBUG +static void NmiSR(void) __attribute__( ( naked ) ); +static void FaultISR( void ) __attribute__( ( naked ) ); +void HardFault_HandlerC(uint32_t *pulFaultStackAddress); +static void BusFaultHandler(void) __attribute__( ( naked ) ); +#endif +static void IntDefaultHandler(void) __attribute__( ( naked ) ); + +//***************************************************************************** +// +// External declaration for the freeRTOS handlers +// +//***************************************************************************** +#ifdef USE_FREERTOS +extern void vPortSVCHandler(void); +extern void xPortPendSVHandler(void); +extern void xPortSysTickHandler(void); +#endif + +//***************************************************************************** +// +// The entry point for the application. +// +//***************************************************************************** +extern int main(void); + +//***************************************************************************** +// +// The vector table. Note that the proper constructs must be placed on this to +// ensure that it ends up at physical address 0x0000.0000. +// +//***************************************************************************** +__attribute__ ((section(".intvecs"))) +void (* const g_pfnVectors[256])(void) = +{ + (void (*)(void))((uint32_t)&_estack), // The initial stack pointer + ResetISR, // The reset handler +#ifdef DEBUG + NmiSR, // The NMI handler + FaultISR, // The hard fault handler +#else + IntDefaultHandler, // The NMI handler + IntDefaultHandler, // The hard fault handler +#endif + IntDefaultHandler, // The MPU fault handler +#ifdef DEBUG + BusFaultHandler, // The bus fault handler +#else + IntDefaultHandler, // The bus fault handler +#endif + IntDefaultHandler, // The usage fault handler + 0, // Reserved + 0, // Reserved + 0, // Reserved + 0, // Reserved +#ifdef USE_FREERTOS + vPortSVCHandler, // SVCall handler +#else + IntDefaultHandler, // SVCall handler +#endif + IntDefaultHandler, // Debug monitor handler + 0, // Reserved +#ifdef USE_FREERTOS + xPortPendSVHandler, // The PendSV handler + xPortSysTickHandler, // The SysTick handler +#else + IntDefaultHandler, // The PendSV handler + IntDefaultHandler, // The SysTick handler +#endif + IntDefaultHandler, // GPIO Port A + IntDefaultHandler, // GPIO Port B + IntDefaultHandler, // GPIO Port C + IntDefaultHandler, // GPIO Port D + 0, // Reserved + IntDefaultHandler, // UART0 Rx and Tx + IntDefaultHandler, // UART1 Rx and Tx + 0, // Reserved + IntDefaultHandler, // I2C0 Master and Slave + 0,0,0,0,0, // Reserved + IntDefaultHandler, // ADC Channel 0 + IntDefaultHandler, // ADC Channel 1 + IntDefaultHandler, // ADC Channel 2 + IntDefaultHandler, // ADC Channel 3 + IntDefaultHandler, // Watchdog Timer + IntDefaultHandler, // Timer 0 subtimer A + IntDefaultHandler, // Timer 0 subtimer B + IntDefaultHandler, // Timer 1 subtimer A + IntDefaultHandler, // Timer 1 subtimer B + IntDefaultHandler, // Timer 2 subtimer A + IntDefaultHandler, // Timer 2 subtimer B + 0,0,0,0, // Reserved + IntDefaultHandler, // Flash + 0,0,0,0,0, // Reserved + IntDefaultHandler, // Timer 3 subtimer A + IntDefaultHandler, // Timer 3 subtimer B + 0,0,0,0,0,0,0,0,0, // Reserved + IntDefaultHandler, // uDMA Software Transfer + IntDefaultHandler, // uDMA Error + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + IntDefaultHandler, // SHA + 0,0, // Reserved + IntDefaultHandler, // AES + 0, // Reserved + IntDefaultHandler, // DES + 0,0,0,0,0, // Reserved + IntDefaultHandler, // SDHost + 0, // Reserved + IntDefaultHandler, // I2S + 0, // Reserved + IntDefaultHandler, // Camera + 0,0,0,0,0,0,0, // Reserved + IntDefaultHandler, // NWP to APPS Interrupt + IntDefaultHandler, // Power, Reset and Clock module + 0,0, // Reserved + IntDefaultHandler, // Shared SPI + IntDefaultHandler, // Generic SPI + IntDefaultHandler, // Link SPI + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0,0,0,0,0,0,0,0,0, // Reserved + 0,0 // Reserved +}; + + + +//***************************************************************************** +// +// This is the code that gets called when the processor first starts execution +// following a reset event. Only the absolutely necessary set is performed, +// after which the application supplied entry() routine is called. Any fancy +// actions (such as making decisions based on the reset cause register, and +// resetting the bits in that register) are left solely in the hands of the +// application. +// +//***************************************************************************** + +void ResetISR(void) +{ +#if defined(DEBUG) && !defined(BOOTLOADER) + { + // + // Fill the main stack with a known value so that + // we can measure the main stack high water mark + // + __asm volatile + ( + "ldr r0, =_stack \n" + "ldr r1, =_estack \n" + "mov r2, #0x55555555 \n" + ".thumb_func \n" + "fill_loop: \n" + "cmp r0, r1 \n" + "it lt \n" + "strlt r2, [r0], #4 \n" + "blt fill_loop \n" + ); + } +#endif + + { + // Get the initial stack pointer location from the vector table + // and write this value to the msp register + __asm volatile + ( + "ldr r0, =_text \n" + "ldr r0, [r0] \n" + "msr msp, r0 \n" + ); + } + + { + // + // Zero fill the bss segment. + // + __asm volatile + ( + "ldr r0, =_bss \n" + "ldr r1, =_ebss \n" + "mov r2, #0 \n" + ".thumb_func \n" + "zero_loop: \n" + "cmp r0, r1 \n" + "it lt \n" + "strlt r2, [r0], #4 \n" + "blt zero_loop \n" + ); + } + + { + // + // Call the application's entry point. + // + main(); + } +} + +#ifdef DEBUG +//***************************************************************************** +// +// This is the code that gets called when the processor receives a NMI. This +// simply enters an infinite loop, preserving the system state for examination +// by a debugger. +// +//***************************************************************************** + +static void NmiSR(void) +{ + // Break into the debugger + __asm volatile ("bkpt #0 \n"); + + // + // Enter an infinite loop. + // + for ( ; ; ) + { + } +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives a hard fault +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** + +static void FaultISR(void) +{ + /* + * Get the appropriate stack pointer, depending on our mode, + * and use it as the parameter to the C handler. This function + * will never return + */ + + __asm volatile + ( + "movs r0, #4 \n" + "mov r1, lr \n" + "tst r0, r1 \n" + "beq _msp \n" + "mrs r0, psp \n" + "b HardFault_HandlerC \n" + "_msp: \n" + "mrs r0, msp \n" + "b HardFault_HandlerC \n" + ) ; +} + +//*********************************************************************************** +// HardFaultHandler_C: +// This is called from the FaultISR with a pointer the Fault stack +// as the parameter. We can then read the values from the stack and place them +// into local variables for ease of reading. +// We then read the various Fault Status and Address Registers to help decode +// cause of the fault. +// The function ends with a BKPT instruction to force control back into the debugger +//*********************************************************************************** +void HardFault_HandlerC(uint32_t *pulFaultStackAddress) +{ + volatile uint32_t r0 ; + volatile uint32_t r1 ; + volatile uint32_t r2 ; + volatile uint32_t r3 ; + volatile uint32_t r12 ; + volatile uint32_t lr ; + volatile uint32_t pc ; + volatile uint32_t psr ; + volatile _CFSR_t _CFSR ; + volatile _HFSR_t _HFSR ; + volatile uint32_t _BFAR ; + + + r0 = pulFaultStackAddress[0]; + r1 = pulFaultStackAddress[1]; + r2 = pulFaultStackAddress[2]; + r3 = pulFaultStackAddress[3]; + r12 = pulFaultStackAddress[4]; + lr = pulFaultStackAddress[5]; + pc = pulFaultStackAddress[6]; + psr = pulFaultStackAddress[7]; + + // Configurable Fault Status Register + // Consists of MMSR, BFSR and UFSR + _CFSR = (*((volatile _CFSR_t *)(0xE000ED28))); + // Hard Fault Status Register + _HFSR = (*((volatile _HFSR_t *)(0xE000ED2C))); + // Bus Fault Address Register + _BFAR = (*((volatile uint32_t *)(0xE000ED38))); + + // Break into the debugger + __asm volatile ("bkpt #0 \n"); + + for ( ; ; ) + { + // Keep the compiler happy + (void)r0, (void)r1, (void)r2, (void)r3, (void)r12, (void)lr, (void)pc, (void)psr; + (void)_CFSR, (void)_HFSR, (void)_BFAR; + } +} + +//***************************************************************************** +// +// This is the code that gets called when the processor receives an unexpected +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** + +static void BusFaultHandler(void) +{ + // Break into the debugger + __asm volatile ("bkpt #0 \n"); + + // + // Enter an infinite loop. + // + for ( ; ; ) + { + } +} +#endif + +//***************************************************************************** +// +// This is the code that gets called when the processor receives an unexpected +// interrupt. This simply enters an infinite loop, preserving the system state +// for examination by a debugger. +// +//***************************************************************************** +static void IntDefaultHandler(void) +{ +#ifdef DEBUG + // Break into the debugger + __asm volatile ("bkpt #0 \n"); +#endif + + // + // Enter an infinite loop. + // + for ( ; ; ) + { + } +} + diff --git a/src/openmv/src/micropython/ports/cc3200/hal/systick.c b/src/openmv/src/micropython/ports/cc3200/hal/systick.c new file mode 100755 index 0000000..550e3ed --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/systick.c @@ -0,0 +1,275 @@ +//***************************************************************************** +// +// systick.c +// +// Driver for the SysTick timer in NVIC. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup systick_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "debug.h" +#include "interrupt.h" +#include "systick.h" + +//***************************************************************************** +// +//! Enables the SysTick counter. +//! +//! This function starts the SysTick counter. If an interrupt handler has been +//! registered, it is called when the SysTick counter rolls over. +//! +//! \note Calling this function causes the SysTick counter to (re)commence +//! counting from its current value. The counter is not automatically reloaded +//! with the period as specified in a previous call to SysTickPeriodSet(). If +//! an immediate reload is required, the \b NVIC_ST_CURRENT register must be +//! written to force the reload. Any write to this register clears the SysTick +//! counter to 0 and causes a reload with the supplied period on the next +//! clock. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickEnable(void) +{ + // + // Enable SysTick. + // + HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_ENABLE; +} + +//***************************************************************************** +// +//! Disables the SysTick counter. +//! +//! This function stops the SysTick counter. If an interrupt handler has been +//! registered, it is not called until SysTick is restarted. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickDisable(void) +{ + // + // Disable SysTick. + // + HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_ENABLE); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for the SysTick interrupt. +//! +//! \param pfnHandler is a pointer to the function to be called when the +//! SysTick interrupt occurs. +//! +//! This function registers the handler to be called when a SysTick interrupt +//! occurs. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntRegister(void (*pfnHandler)(void)) +{ + // + // Register the interrupt handler, returning an error if an error occurs. + // + IntRegister(FAULT_SYSTICK, pfnHandler); + + // + // Enable the SysTick interrupt. + // + HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN; +} + +//***************************************************************************** +// +//! Unregisters the interrupt handler for the SysTick interrupt. +//! +//! This function unregisters the handler to be called when a SysTick interrupt +//! occurs. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntUnregister(void) +{ + // + // Disable the SysTick interrupt. + // + HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN); + + // + // Unregister the interrupt handler. + // + IntUnregister(FAULT_SYSTICK); +} + +//***************************************************************************** +// +//! Enables the SysTick interrupt. +//! +//! This function enables the SysTick interrupt, allowing it to be +//! reflected to the processor. +//! +//! \note The SysTick interrupt handler is not required to clear the SysTick +//! interrupt source because it is cleared automatically by the NVIC when the +//! interrupt handler is called. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntEnable(void) +{ + // + // Enable the SysTick interrupt. + // + HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN; +} + +//***************************************************************************** +// +//! Disables the SysTick interrupt. +//! +//! This function disables the SysTick interrupt, preventing it from being +//! reflected to the processor. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickIntDisable(void) +{ + // + // Disable the SysTick interrupt. + // + HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN); +} + +//***************************************************************************** +// +//! Sets the period of the SysTick counter. +//! +//! \param ulPeriod is the number of clock ticks in each period of the SysTick +//! counter and must be between 1 and 16,777,216, inclusive. +//! +//! This function sets the rate at which the SysTick counter wraps, which +//! equates to the number of processor clocks between interrupts. +//! +//! \note Calling this function does not cause the SysTick counter to reload +//! immediately. If an immediate reload is required, the \b NVIC_ST_CURRENT +//! register must be written. Any write to this register clears the SysTick +//! counter to 0 and causes a reload with the \e ulPeriod supplied here on +//! the next clock after SysTick is enabled. +//! +//! \return None. +// +//***************************************************************************** +void +SysTickPeriodSet(unsigned long ulPeriod) +{ + // + // Check the arguments. + // + ASSERT((ulPeriod > 0) && (ulPeriod <= 16777216)); + + // + // Set the period of the SysTick counter. + // + HWREG(NVIC_ST_RELOAD) = ulPeriod - 1; +} + +//***************************************************************************** +// +//! Gets the period of the SysTick counter. +//! +//! This function returns the rate at which the SysTick counter wraps, which +//! equates to the number of processor clocks between interrupts. +//! +//! \return Returns the period of the SysTick counter. +// +//***************************************************************************** +unsigned long +SysTickPeriodGet(void) +{ + // + // Return the period of the SysTick counter. + // + return(HWREG(NVIC_ST_RELOAD) + 1); +} + +//***************************************************************************** +// +//! Gets the current value of the SysTick counter. +//! +//! This function returns the current value of the SysTick counter, which is +//! a value between the period - 1 and zero, inclusive. +//! +//! \return Returns the current value of the SysTick counter. +// +//***************************************************************************** +unsigned long +SysTickValueGet(void) +{ + // + // Return the current value of the SysTick counter. + // + return(HWREG(NVIC_ST_CURRENT)); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/systick.h b/src/openmv/src/micropython/ports/cc3200/hal/systick.h new file mode 100755 index 0000000..3d1a33a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/systick.h @@ -0,0 +1,78 @@ +//***************************************************************************** +// +// systick.h +// +// Prototypes for the SysTick driver. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __SYSTICK_H__ +#define __SYSTICK_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern void SysTickEnable(void); +extern void SysTickDisable(void); +extern void SysTickIntRegister(void (*pfnHandler)(void)); +extern void SysTickIntUnregister(void); +extern void SysTickIntEnable(void); +extern void SysTickIntDisable(void); +extern void SysTickPeriodSet(unsigned long ulPeriod); +extern unsigned long SysTickPeriodGet(void); +extern unsigned long SysTickValueGet(void); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __SYSTICK_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/timer.c b/src/openmv/src/micropython/ports/cc3200/hal/timer.c new file mode 100755 index 0000000..eaa2ed1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/timer.c @@ -0,0 +1,1106 @@ +//***************************************************************************** +// +// timer.c +// +// Driver for the timer module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup GPT_General_Purpose_Timer_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_timer.h" +#include "inc/hw_types.h" +#include "debug.h" +#include "interrupt.h" +#include "timer.h" + + +//***************************************************************************** +// +//! \internal +//! Checks a timer base address. +//! +//! \param ulBase is the base address of the timer module. +//! +//! This function determines if a timer module base address is valid. +//! +//! \return Returns \b true if the base address is valid and \b false +//! otherwise. +// +//***************************************************************************** +#ifdef DEBUG +static tBoolean +TimerBaseValid(unsigned long ulBase) +{ + return((ulBase == TIMERA0_BASE) || (ulBase == TIMERA1_BASE) || + (ulBase == TIMERA2_BASE) || (ulBase == TIMERA3_BASE)); +} +#else +#define TimerBaseValid(ulBase) (ulBase) +#endif + +//***************************************************************************** +// +//! Enables the timer(s). +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to enable; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! +//! This function enables operation of the timer module. The timer must be +//! configured before it is enabled. +//! +//! \return None. +// +//***************************************************************************** +void +TimerEnable(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Enable the timer(s) module. + // + HWREG(ulBase + TIMER_O_CTL) |= ulTimer & (TIMER_CTL_TAEN | TIMER_CTL_TBEN); +} + +//***************************************************************************** +// +//! Disables the timer(s). +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to disable; must be one of +//! \b TIMER_A, \b TIMER_B, or \b TIMER_BOTH. +//! +//! This function disables operation of the timer module. +//! +//! \return None. +// +//***************************************************************************** +void +TimerDisable(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Disable the timer module. + // + HWREG(ulBase + TIMER_O_CTL) &= ~(ulTimer & + (TIMER_CTL_TAEN | TIMER_CTL_TBEN)); +} + +//***************************************************************************** +// +//! Configures the timer(s). +//! +//! \param ulBase is the base address of the timer module. +//! \param ulConfig is the configuration for the timer. +//! +//! This function configures the operating mode of the timer(s). The timer +//! module is disabled before being configured, and is left in the disabled +//! state. The 16/32-bit timer is comprised of two 16-bit timers that can +//! operate independently or be concatenated to form a 32-bit timer. +//! +//! The configuration is specified in \e ulConfig as one of the following +//! values: +//! +//! - \b TIMER_CFG_ONE_SHOT - Full-width one-shot timer +//! - \b TIMER_CFG_ONE_SHOT_UP - Full-width one-shot timer that counts up +//! instead of down (not available on all parts) +//! - \b TIMER_CFG_PERIODIC - Full-width periodic timer +//! - \b TIMER_CFG_PERIODIC_UP - Full-width periodic timer that counts up +//! instead of down (not available on all parts) +//! - \b TIMER_CFG_SPLIT_PAIR - Two half-width timers +//! +//! When configured for a pair of half-width timers, each timer is separately +//! configured. The first timer is configured by setting \e ulConfig to +//! the result of a logical OR operation between one of the following values +//! and \e ulConfig: +//! +//! - \b TIMER_CFG_A_ONE_SHOT - Half-width one-shot timer +//! - \b TIMER_CFG_A_ONE_SHOT_UP - Half-width one-shot timer that counts up +//! instead of down (not available on all parts) +//! - \b TIMER_CFG_A_PERIODIC - Half-width periodic timer +//! - \b TIMER_CFG_A_PERIODIC_UP - Half-width periodic timer that counts up +//! instead of down (not available on all parts) +//! - \b TIMER_CFG_A_CAP_COUNT - Half-width edge count capture +//! - \b TIMER_CFG_A_CAP_TIME - Half-width edge time capture +//! - \b TIMER_CFG_A_PWM - Half-width PWM output +//! +//! Similarly, the second timer is configured by setting \e ulConfig to +//! the result of a logical OR operation between one of the corresponding +//! \b TIMER_CFG_B_* values and \e ulConfig. +//! +//! \return None. +// +//***************************************************************************** +void +TimerConfigure(unsigned long ulBase, unsigned long ulConfig) +{ + + ASSERT((ulConfig == TIMER_CFG_ONE_SHOT) || + (ulConfig == TIMER_CFG_ONE_SHOT_UP) || + (ulConfig == TIMER_CFG_PERIODIC) || + (ulConfig == TIMER_CFG_PERIODIC_UP) || + ((ulConfig & 0xff000000) == TIMER_CFG_SPLIT_PAIR)); + ASSERT(((ulConfig & 0xff000000) != TIMER_CFG_SPLIT_PAIR) || + ((((ulConfig & 0x000000ff) == TIMER_CFG_A_ONE_SHOT) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_ONE_SHOT_UP) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_PERIODIC) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_PERIODIC_UP) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_CAP_COUNT) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_CAP_TIME) || + ((ulConfig & 0x000000ff) == TIMER_CFG_A_PWM)) && + (((ulConfig & 0x0000ff00) == TIMER_CFG_B_ONE_SHOT) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_ONE_SHOT_UP) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_PERIODIC) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_PERIODIC_UP) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_CAP_COUNT) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_CAP_TIME) || + ((ulConfig & 0x0000ff00) == TIMER_CFG_B_PWM)))); + + // + // Enable CCP to IO path + // + HWREG(0x440260B0) = 0xFF; + + // + // Disable the timers. + // + HWREG(ulBase + TIMER_O_CTL) &= ~(TIMER_CTL_TAEN | TIMER_CTL_TBEN); + + // + // Set the global timer configuration. + // + HWREG(ulBase + TIMER_O_CFG) = ulConfig >> 24; + + // + // Set the configuration of the A and B timers. Note that the B timer + // configuration is ignored by the hardware in 32-bit modes. + // + HWREG(ulBase + TIMER_O_TAMR) = ulConfig & 255; + HWREG(ulBase + TIMER_O_TBMR) = (ulConfig >> 8) & 255; +} + +//***************************************************************************** +// +//! Controls the output level. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to adjust; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! \param bInvert specifies the output level. +//! +//! This function sets the PWM output level for the specified timer. If the +//! \e bInvert parameter is \b true, then the timer's output is made active +//! low; otherwise, it is made active high. +//! +//! \return None. +// +//***************************************************************************** +void +TimerControlLevel(unsigned long ulBase, unsigned long ulTimer, + tBoolean bInvert) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Set the output levels as requested. + // + ulTimer &= TIMER_CTL_TAPWML | TIMER_CTL_TBPWML; + HWREG(ulBase + TIMER_O_CTL) = (bInvert ? + (HWREG(ulBase + TIMER_O_CTL) | ulTimer) : + (HWREG(ulBase + TIMER_O_CTL) & ~(ulTimer))); +} + +//***************************************************************************** +// +//! Controls the event type. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to be adjusted; must be one of +//! \b TIMER_A, \b TIMER_B, or \b TIMER_BOTH. +//! \param ulEvent specifies the type of event; must be one of +//! \b TIMER_EVENT_POS_EDGE, \b TIMER_EVENT_NEG_EDGE, or +//! \b TIMER_EVENT_BOTH_EDGES. +//! +//! This function sets the signal edge(s) that triggers the timer when in +//! capture mode. +//! +//! \return None. +// +//***************************************************************************** +void +TimerControlEvent(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulEvent) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Set the event type. + // + ulEvent &= ulTimer & (TIMER_CTL_TAEVENT_M | TIMER_CTL_TBEVENT_M); + HWREG(ulBase + TIMER_O_CTL) = ((HWREG(ulBase + TIMER_O_CTL) & + ~(TIMER_CTL_TAEVENT_M | + TIMER_CTL_TBEVENT_M)) | ulEvent); +} + +//***************************************************************************** +// +//! Controls the stall handling. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to be adjusted; must be one of +//! \b TIMER_A, \b TIMER_B, or \b TIMER_BOTH. +//! \param bStall specifies the response to a stall signal. +//! +//! This function controls the stall response for the specified timer. If the +//! \e bStall parameter is \b true, then the timer stops counting if the +//! processor enters debug mode; otherwise the timer keeps running while in +//! debug mode. +//! +//! \return None. +// +//***************************************************************************** +void +TimerControlStall(unsigned long ulBase, unsigned long ulTimer, + tBoolean bStall) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Set the stall mode. + // + ulTimer &= TIMER_CTL_TASTALL | TIMER_CTL_TBSTALL; + HWREG(ulBase + TIMER_O_CTL) = (bStall ? + (HWREG(ulBase + TIMER_O_CTL) | ulTimer) : + (HWREG(ulBase + TIMER_O_CTL) & ~(ulTimer))); +} + +//***************************************************************************** +// +//! Set the timer prescale value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to adjust; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! \param ulValue is the timer prescale value which must be between 0 and 255 +//! (inclusive) for 16/32-bit timers. +//! +//! This function sets the value of the input clock prescaler. The prescaler +//! is only operational when in half-width mode and is used to extend the range +//! of the half-width timer modes. +//! +//! \return None. +// +//***************************************************************************** +void +TimerPrescaleSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + ASSERT(ulValue < 256); + + // + // Set the timer A prescaler if requested. + // + if(ulTimer & TIMER_A) + { + HWREG(ulBase + TIMER_O_TAPR) = ulValue; + } + + // + // Set the timer B prescaler if requested. + // + if(ulTimer & TIMER_B) + { + HWREG(ulBase + TIMER_O_TBPR) = ulValue; + } +} + + +//***************************************************************************** +// +//! Get the timer prescale value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. +//! +//! This function gets the value of the input clock prescaler. The prescaler +//! is only operational when in half-width mode and is used to extend the range +//! of the half-width timer modes. +//! +//! \return The value of the timer prescaler. +// +//***************************************************************************** + +unsigned long +TimerPrescaleGet(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Return the appropriate prescale value. + // + return((ulTimer == TIMER_A) ? HWREG(ulBase + TIMER_O_TAPR) : + HWREG(ulBase + TIMER_O_TBPR)); +} + +//***************************************************************************** +// +//! Set the timer prescale match value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to adjust; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! \param ulValue is the timer prescale match value which must be between 0 +//! and 255 (inclusive) for 16/32-bit timers. +//! +//! This function sets the value of the input clock prescaler match value. +//! When in a half-width mode that uses the counter match and the prescaler, +//! the prescale match effectively extends the range of the match. +//! +//! \note The availability of the prescaler match varies with the +//! part and timer mode in use. Please consult the datasheet for the part you +//! are using to determine whether this support is available. +//! +//! \return None. +// +//***************************************************************************** +void +TimerPrescaleMatchSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + ASSERT(ulValue < 256); + + // + // Set the timer A prescale match if requested. + // + if(ulTimer & TIMER_A) + { + HWREG(ulBase + TIMER_O_TAPMR) = ulValue; + } + + // + // Set the timer B prescale match if requested. + // + if(ulTimer & TIMER_B) + { + HWREG(ulBase + TIMER_O_TBPMR) = ulValue; + } +} + +//***************************************************************************** +// +//! Get the timer prescale match value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. +//! +//! This function gets the value of the input clock prescaler match value. +//! When in a half-width mode that uses the counter match and prescaler, the +//! prescale match effectively extends the range of the match. +//! +//! \note The availability of the prescaler match varies with the +//! part and timer mode in use. Please consult the datasheet for the part you +//! are using to determine whether this support is available. +//! +//! \return The value of the timer prescale match. +// +//***************************************************************************** +unsigned long +TimerPrescaleMatchGet(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Return the appropriate prescale match value. + // + return((ulTimer == TIMER_A) ? HWREG(ulBase + TIMER_O_TAPMR) : + HWREG(ulBase + TIMER_O_TBPMR)); +} + +//***************************************************************************** +// +//! Sets the timer load value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to adjust; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. Only \b TIMER_A should be used when the +//! timer is configured for full-width operation. +//! \param ulValue is the load value. +//! +//! This function sets the timer load value; if the timer is running then the +//! value is immediately loaded into the timer. +//! +//! \note This function can be used for both full- and half-width modes of +//! 16/32-bit timers. +//! +//! \return None. +// +//***************************************************************************** +void +TimerLoadSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Set the timer A load value if requested. + // + if(ulTimer & TIMER_A) + { + HWREG(ulBase + TIMER_O_TAILR) = ulValue; + } + + // + // Set the timer B load value if requested. + // + if(ulTimer & TIMER_B) + { + HWREG(ulBase + TIMER_O_TBILR) = ulValue; + } +} + +//***************************************************************************** +// +//! Gets the timer load value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. Only \b TIMER_A should be used when the timer is configured +//! for full-width operation. +//! +//! This function gets the currently programmed interval load value for the +//! specified timer. +//! +//! \note This function can be used for both full- and half-width modes of +//! 16/32-bit timers. +//! +//! \return Returns the load value for the timer. +// +//***************************************************************************** +unsigned long +TimerLoadGet(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B)); + + // + // Return the appropriate load value. + // + return((ulTimer == TIMER_A) ? HWREG(ulBase + TIMER_O_TAILR) : + HWREG(ulBase + TIMER_O_TBILR)); +} + +//***************************************************************************** +// +//! Gets the current timer value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. Only \b TIMER_A should be used when the timer is configured +//! for 32-bit operation. +//! +//! This function reads the current value of the specified timer. +//! +//! \return Returns the current value of the timer. +// +//***************************************************************************** +unsigned long +TimerValueGet(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B)); + + // + // Return the appropriate timer value. + // + return((ulTimer == TIMER_A) ? HWREG(ulBase + TIMER_O_TAR) : + HWREG(ulBase + TIMER_O_TBR)); +} + +//***************************************************************************** +// +//! Sets the current timer value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. Only \b TIMER_A should be used when the timer is configured +//! for 32-bit operation. +//! \param ulValue is the new value of the timer to be set. +//! +//! This function sets the current value of the specified timer. +//! +//! \return None. +// +//***************************************************************************** +void +TimerValueSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B)); + + // + // Set the appropriate timer value. + // + if( (ulTimer == TIMER_A) ) + { + HWREG(ulBase + TIMER_O_TAV) = ulValue; + } + else + { + HWREG(ulBase + TIMER_O_TBV) = ulValue; + } +} + + +//***************************************************************************** +// +//! Sets the timer match value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s) to adjust; must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. Only \b TIMER_A should be used when the +//! timer is configured for 32-bit operation. +//! \param ulValue is the match value. +//! +//! This function sets the match value for a timer. This is used in capture +//! count mode to determine when to interrupt the processor and in PWM mode to +//! determine the duty cycle of the output signal. +//! +//! \return None. +// +//***************************************************************************** +void +TimerMatchSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Set the timer A match value if requested. + // + if(ulTimer & TIMER_A) + { + HWREG(ulBase + TIMER_O_TAMATCHR) = ulValue; + } + + // + // Set the timer B match value if requested. + // + if(ulTimer & TIMER_B) + { + HWREG(ulBase + TIMER_O_TBMATCHR) = ulValue; + } +} + +//***************************************************************************** +// +//! Gets the timer match value. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer; must be one of \b TIMER_A or +//! \b TIMER_B. Only \b TIMER_A should be used when the timer is configured +//! for 32-bit operation. +//! +//! This function gets the match value for the specified timer. +//! +//! \return Returns the match value for the timer. +// +//******************************************************************************** +unsigned long +TimerMatchGet(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B)); + + // + // Return the appropriate match value. + // + return((ulTimer == TIMER_A) ? HWREG(ulBase + TIMER_O_TAMATCHR) : + HWREG(ulBase + TIMER_O_TBMATCHR)); +} + + +//***************************************************************************** +// +//! Registers an interrupt handler for the timer interrupt. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s); must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! \param pfnHandler is a pointer to the function to be called when the timer +//! interrupt occurs. +//! +//! This function sets the handler to be called when a timer interrupt occurs. +//! In addition, this function enables the global interrupt in the interrupt +//! controller; specific timer interrupts must be enabled via TimerIntEnable(). +//! It is the interrupt handler's responsibility to clear the interrupt source +//! via TimerIntClear(). +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +TimerIntRegister(unsigned long ulBase, unsigned long ulTimer, + void (*pfnHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + ulBase = ((ulBase == TIMERA0_BASE) ? INT_TIMERA0A : + ((ulBase == TIMERA1_BASE) ? INT_TIMERA1A : + ((ulBase == TIMERA2_BASE) ? INT_TIMERA2A : INT_TIMERA3A))); + + // + // Register an interrupt handler for timer A if requested. + // + if(ulTimer & TIMER_A) + { + // + // Register the interrupt handler. + // + IntRegister(ulBase, pfnHandler); + + // + // Enable the interrupt. + // + IntEnable(ulBase); + } + + // + // Register an interrupt handler for timer B if requested. + // + if(ulTimer & TIMER_B) + { + // + // Register the interrupt handler. + // + IntRegister(ulBase + 1, pfnHandler); + + // + // Enable the interrupt. + // + IntEnable(ulBase + 1); + } +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the timer interrupt. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulTimer specifies the timer(s); must be one of \b TIMER_A, +//! \b TIMER_B, or \b TIMER_BOTH. +//! +//! This function clears the handler to be called when a timer interrupt +//! occurs. This function also masks off the interrupt in the interrupt +//! controller so that the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +TimerIntUnregister(unsigned long ulBase, unsigned long ulTimer) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + ASSERT((ulTimer == TIMER_A) || (ulTimer == TIMER_B) || + (ulTimer == TIMER_BOTH)); + + // + // Get the interrupt number for this timer module. + // + + ulBase = ((ulBase == TIMERA0_BASE) ? INT_TIMERA0A : + ((ulBase == TIMERA1_BASE) ? INT_TIMERA1A : + ((ulBase == TIMERA2_BASE) ? INT_TIMERA2A : INT_TIMERA3A))); + + + + // + // Unregister the interrupt handler for timer A if requested. + // + if(ulTimer & TIMER_A) + { + // + // Disable the interrupt. + // + IntDisable(ulBase); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulBase); + } + + // + // Unregister the interrupt handler for timer B if requested. + // + if(ulTimer & TIMER_B) + { + // + // Disable the interrupt. + // + IntDisable(ulBase + 1); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulBase + 1); + } +} + +//***************************************************************************** +// +//! Enables individual timer interrupt sources. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! Enables the indicated timer interrupt sources. Only the sources that are +//! enabled can be reflected to the processor interrupt; disabled sources have +//! no effect on the processor. +//! +//! The \e ulIntFlags parameter must be the logical OR of any combination of +//! the following: +//! +//! - \b TIMER_CAPB_EVENT - Capture B event interrupt +//! - \b TIMER_CAPB_MATCH - Capture B match interrupt +//! - \b TIMER_TIMB_TIMEOUT - Timer B timeout interrupt +//! - \b TIMER_CAPA_EVENT - Capture A event interrupt +//! - \b TIMER_CAPA_MATCH - Capture A match interrupt +//! - \b TIMER_TIMA_TIMEOUT - Timer A timeout interrupt +//! +//! \return None. +// +//***************************************************************************** +void +TimerIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Enable the specified interrupts. + // + HWREG(ulBase + TIMER_O_IMR) |= ulIntFlags; +} + +//***************************************************************************** +// +//! Disables individual timer interrupt sources. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! Disables the indicated timer interrupt sources. Only the sources that are +//! enabled can be reflected to the processor interrupt; disabled sources have +//! no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to TimerIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +TimerIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Disable the specified interrupts. + // + HWREG(ulBase + TIMER_O_IMR) &= ~(ulIntFlags); +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of the timer module. +//! \param bMasked is false if the raw interrupt status is required and true if +//! the masked interrupt status is required. +//! +//! This function returns the interrupt status for the timer module. Either +//! the raw interrupt status or the status of interrupts that are allowed to +//! reflect to the processor can be returned. +//! +//! \return The current interrupt status, enumerated as a bit field of +//! values described in TimerIntEnable(). +// +//***************************************************************************** +unsigned long +TimerIntStatus(unsigned long ulBase, tBoolean bMasked) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + return(bMasked ? HWREG(ulBase + TIMER_O_MIS) : + HWREG(ulBase + TIMER_O_RIS)); +} + +//***************************************************************************** +// +//! Clears timer interrupt sources. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified timer interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being triggered again immediately upon exit. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to TimerIntEnable(). +//! +//! \note Because there is a write buffer in the Cortex-M3 processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +TimerIntClear(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Clear the requested interrupt sources. + // + HWREG(ulBase + TIMER_O_ICR) = ulIntFlags; +} + +//***************************************************************************** +// +//! Enables the events that can trigger a DMA request. +//! +//! \param ulBase is the base address of the timer module. +//! \param ulDMAEvent is a bit mask of the events that can trigger DMA. +//! +//! This function enables the timer events that can trigger the start of a DMA +//! sequence. The DMA trigger events are specified in the \e ui32DMAEvent +//! parameter by passing in the logical OR of the following values: +//! +//! - \b TIMER_DMA_MODEMATCH_B - The mode match DMA trigger for timer B is +//! enabled. +//! - \b TIMER_DMA_CAPEVENT_B - The capture event DMA trigger for timer B is +//! enabled. +//! - \b TIMER_DMA_CAPMATCH_B - The capture match DMA trigger for timer B is +//! enabled. +//! - \b TIMER_DMA_TIMEOUT_B - The timeout DMA trigger for timer B is enabled. +//! - \b TIMER_DMA_MODEMATCH_A - The mode match DMA trigger for timer A is +//! enabled. +//! - \b TIMER_DMA_CAPEVENT_A - The capture event DMA trigger for timer A is +//! enabled. +//! - \b TIMER_DMA_CAPMATCH_A - The capture match DMA trigger for timer A is +//! enabled. +//! - \b TIMER_DMA_TIMEOUT_A - The timeout DMA trigger for timer A is enabled. +//! +//! \return None. +// +//***************************************************************************** +void +TimerDMAEventSet(unsigned long ulBase, unsigned long ulDMAEvent) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Set the DMA triggers. + // + HWREG(ulBase + TIMER_O_DMAEV) = ulDMAEvent; +} + +//***************************************************************************** +// +//! Returns the events that can trigger a DMA request. +//! +//! \param ulBase is the base address of the timer module. +//! +//! This function returns the timer events that can trigger the start of a DMA +//! sequence. The DMA trigger events are the logical OR of the following +//! values: +//! +//! - \b TIMER_DMA_MODEMATCH_B - Enables the mode match DMA trigger for timer +//! B. +//! - \b TIMER_DMA_CAPEVENT_B - Enables the capture event DMA trigger for +//! timer B. +//! - \b TIMER_DMA_CAPMATCH_B - Enables the capture match DMA trigger for +//! timer B. +//! - \b TIMER_DMA_TIMEOUT_B - Enables the timeout DMA trigger for timer B. +//! - \b TIMER_DMA_MODEMATCH_A - Enables the mode match DMA trigger for timer +//! A. +//! - \b TIMER_DMA_CAPEVENT_A - Enables the capture event DMA trigger for +//! timer A. +//! - \b TIMER_DMA_CAPMATCH_A - Enables the capture match DMA trigger for +//! timer A. +//! - \b TIMER_DMA_TIMEOUT_A - Enables the timeout DMA trigger for timer A. +//! +//! \return The timer events that trigger the uDMA. +// +//***************************************************************************** +unsigned long +TimerDMAEventGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(TimerBaseValid(ulBase)); + + // + // Return the current DMA triggers. + // + return(HWREG(ulBase + TIMER_O_DMAEV)); +} +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/timer.h b/src/openmv/src/micropython/ports/cc3200/hal/timer.h new file mode 100755 index 0000000..cbe4d2c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/timer.h @@ -0,0 +1,210 @@ +//***************************************************************************** +// +// timer.h +// +// Prototypes for the timer module +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __TIMER_H__ +#define __TIMER_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Values that can be passed to TimerConfigure as the ulConfig parameter. +// +//***************************************************************************** + +#define TIMER_CFG_ONE_SHOT 0x00000021 // Full-width one-shot timer +#define TIMER_CFG_ONE_SHOT_UP 0x00000031 // Full-width one-shot up-count + // timer +#define TIMER_CFG_PERIODIC 0x00000022 // Full-width periodic timer +#define TIMER_CFG_PERIODIC_UP 0x00000032 // Full-width periodic up-count + // timer +#define TIMER_CFG_SPLIT_PAIR 0x04000000 // Two half-width timers + +#define TIMER_CFG_A_ONE_SHOT 0x00000021 // Timer A one-shot timer +#define TIMER_CFG_A_ONE_SHOT_UP 0x00000031 // Timer A one-shot up-count timer +#define TIMER_CFG_A_PERIODIC 0x00000022 // Timer A periodic timer +#define TIMER_CFG_A_PERIODIC_UP 0x00000032 // Timer A periodic up-count timer +#define TIMER_CFG_A_CAP_COUNT 0x00000003 // Timer A event counter +#define TIMER_CFG_A_CAP_COUNT_UP 0x00000013 // Timer A event up-counter +#define TIMER_CFG_A_CAP_TIME 0x00000007 // Timer A event timer +#define TIMER_CFG_A_CAP_TIME_UP 0x00000017 // Timer A event up-count timer +#define TIMER_CFG_A_PWM 0x0000000A // Timer A PWM output +#define TIMER_CFG_B_ONE_SHOT 0x00002100 // Timer B one-shot timer +#define TIMER_CFG_B_ONE_SHOT_UP 0x00003100 // Timer B one-shot up-count timer +#define TIMER_CFG_B_PERIODIC 0x00002200 // Timer B periodic timer +#define TIMER_CFG_B_PERIODIC_UP 0x00003200 // Timer B periodic up-count timer +#define TIMER_CFG_B_CAP_COUNT 0x00000300 // Timer B event counter +#define TIMER_CFG_B_CAP_COUNT_UP 0x00001300 // Timer B event up-counter +#define TIMER_CFG_B_CAP_TIME 0x00000700 // Timer B event timer +#define TIMER_CFG_B_CAP_TIME_UP 0x00001700 // Timer B event up-count timer +#define TIMER_CFG_B_PWM 0x00000A00 // Timer B PWM output + +//***************************************************************************** +// +// Values that can be passed to TimerIntEnable, TimerIntDisable, and +// TimerIntClear as the ulIntFlags parameter, and returned from TimerIntStatus. +// +//***************************************************************************** + +#define TIMER_TIMB_DMA 0x00002000 // TimerB DMA Done interrupt +#define TIMER_TIMB_MATCH 0x00000800 // TimerB match interrupt +#define TIMER_CAPB_EVENT 0x00000400 // CaptureB event interrupt +#define TIMER_CAPB_MATCH 0x00000200 // CaptureB match interrupt +#define TIMER_TIMB_TIMEOUT 0x00000100 // TimerB time out interrupt +#define TIMER_TIMA_DMA 0x00000020 // TimerA DMA Done interrupt +#define TIMER_TIMA_MATCH 0x00000010 // TimerA match interrupt +#define TIMER_CAPA_EVENT 0x00000004 // CaptureA event interrupt +#define TIMER_CAPA_MATCH 0x00000002 // CaptureA match interrupt +#define TIMER_TIMA_TIMEOUT 0x00000001 // TimerA time out interrupt + +//***************************************************************************** +// +// Values that can be passed to TimerControlEvent as the ulEvent parameter. +// +//***************************************************************************** +#define TIMER_EVENT_POS_EDGE 0x00000000 // Count positive edges +#define TIMER_EVENT_NEG_EDGE 0x00000404 // Count negative edges +#define TIMER_EVENT_BOTH_EDGES 0x00000C0C // Count both edges + +//***************************************************************************** +// +// Values that can be passed to most of the timer APIs as the ulTimer +// parameter. +// +//***************************************************************************** +#define TIMER_A 0x000000ff // Timer A +#define TIMER_B 0x0000ff00 // Timer B +#define TIMER_BOTH 0x0000ffff // Timer Both + + +//***************************************************************************** +// +// Values that can be passed to TimerSynchronize as the ulTimers parameter. +// +//***************************************************************************** +#define TIMER_0A_SYNC 0x00000001 // Synchronize Timer 0A +#define TIMER_0B_SYNC 0x00000002 // Synchronize Timer 0B +#define TIMER_1A_SYNC 0x00000004 // Synchronize Timer 1A +#define TIMER_1B_SYNC 0x00000008 // Synchronize Timer 1B +#define TIMER_2A_SYNC 0x00000010 // Synchronize Timer 2A +#define TIMER_2B_SYNC 0x00000020 // Synchronize Timer 2B +#define TIMER_3A_SYNC 0x00000040 // Synchronize Timer 3A +#define TIMER_3B_SYNC 0x00000080 // Synchronize Timer 3B + +//***************************************************************************** +// +// Values that can be passed to TimerDMAEventSet() or returned from +// TimerDMAEventGet(). +// +//***************************************************************************** +#define TIMER_DMA_MODEMATCH_B 0x00000800 +#define TIMER_DMA_CAPEVENT_B 0x00000400 +#define TIMER_DMA_CAPMATCH_B 0x00000200 +#define TIMER_DMA_TIMEOUT_B 0x00000100 +#define TIMER_DMA_MODEMATCH_A 0x00000010 +#define TIMER_DMA_CAPEVENT_A 0x00000004 +#define TIMER_DMA_CAPMATCH_A 0x00000002 +#define TIMER_DMA_TIMEOUT_A 0x00000001 + + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern void TimerEnable(unsigned long ulBase, unsigned long ulTimer); +extern void TimerDisable(unsigned long ulBase, unsigned long ulTimer); +extern void TimerConfigure(unsigned long ulBase, unsigned long ulConfig); +extern void TimerControlLevel(unsigned long ulBase, unsigned long ulTimer, + tBoolean bInvert); +extern void TimerControlEvent(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulEvent); +extern void TimerControlStall(unsigned long ulBase, unsigned long ulTimer, + tBoolean bStall); +extern void TimerPrescaleSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue); +extern unsigned long TimerPrescaleGet(unsigned long ulBase, + unsigned long ulTimer); +extern void TimerPrescaleMatchSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue); +extern unsigned long TimerPrescaleMatchGet(unsigned long ulBase, + unsigned long ulTimer); +extern void TimerLoadSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue); +extern unsigned long TimerLoadGet(unsigned long ulBase, unsigned long ulTimer); + +extern unsigned long TimerValueGet(unsigned long ulBase, + unsigned long ulTimer); +extern void TimerValueSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue); + +extern void TimerMatchSet(unsigned long ulBase, unsigned long ulTimer, + unsigned long ulValue); +extern unsigned long TimerMatchGet(unsigned long ulBase, + unsigned long ulTimer); +extern void TimerIntRegister(unsigned long ulBase, unsigned long ulTimer, + void (*pfnHandler)(void)); +extern void TimerIntUnregister(unsigned long ulBase, unsigned long ulTimer); +extern void TimerIntEnable(unsigned long ulBase, unsigned long ulIntFlags); +extern void TimerIntDisable(unsigned long ulBase, unsigned long ulIntFlags); +extern unsigned long TimerIntStatus(unsigned long ulBase, tBoolean bMasked); +extern void TimerIntClear(unsigned long ulBase, unsigned long ulIntFlags); +extern void TimerDMAEventSet(unsigned long ulBase, unsigned long ulDMAEvent); +extern unsigned long TimerDMAEventGet(unsigned long ulBase); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __TIMER_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/uart.c b/src/openmv/src/micropython/ports/cc3200/hal/uart.c new file mode 100755 index 0000000..33d9141 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/uart.c @@ -0,0 +1,1508 @@ +//***************************************************************************** +// +// uart.c +// +// Driver for the UART. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup UART_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "inc/hw_uart.h" +#include "debug.h" +#include "interrupt.h" +#include "uart.h" + + +//***************************************************************************** +// +// A mapping of UART base address to interupt number. +// +//***************************************************************************** +static const unsigned long g_ppulUARTIntMap[][2] = +{ + { UARTA0_BASE, INT_UARTA0 }, + { UARTA1_BASE, INT_UARTA1 }, +}; + +//***************************************************************************** +// +//! \internal +//! Checks a UART base address. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function determines if a UART port base address is valid. +//! +//! \return Returns \b true if the base address is valid and \b false +//! otherwise. +// +//***************************************************************************** +#ifdef DEBUG +static tBoolean +UARTBaseValid(unsigned long ulBase) +{ + return((ulBase == UARTA0_BASE) || (ulBase == UARTA1_BASE)); +} +#else +#define UARTBaseValid(ulBase) (ulBase) +#endif + +//***************************************************************************** +// +//! \internal +//! Gets the UART interrupt number. +//! +//! \param ulBase is the base address of the UART port. +//! +//! Given a UART base address, returns the corresponding interrupt number. +//! +//! \return Returns a UART interrupt number, or -1 if \e ulBase is invalid. +// +//***************************************************************************** +static long +UARTIntNumberGet(unsigned long ulBase) +{ + unsigned long ulIdx; + + // + // Loop through the table that maps UART base addresses to interrupt + // numbers. + // + for(ulIdx = 0; ulIdx < (sizeof(g_ppulUARTIntMap) / + sizeof(g_ppulUARTIntMap[0])); ulIdx++) + { + // + // See if this base address matches. + // + if(g_ppulUARTIntMap[ulIdx][0] == ulBase) + { + // + // Return the corresponding interrupt number. + // + return(g_ppulUARTIntMap[ulIdx][1]); + } + } + + // + // The base address could not be found, so return an error. + // + return(-1); +} + +//***************************************************************************** +// +//! Sets the type of parity. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulParity specifies the type of parity to use. +//! +//! This function sets the type of parity to use for transmitting and expect +//! when receiving. The \e ulParity parameter must be one of +//! \b UART_CONFIG_PAR_NONE, \b UART_CONFIG_PAR_EVEN, \b UART_CONFIG_PAR_ODD, +//! \b UART_CONFIG_PAR_ONE, or \b UART_CONFIG_PAR_ZERO. The last two allow +//! direct control of the parity bit; it is always either one or zero based on +//! the mode. +//! +//! \return None. +// +//***************************************************************************** +void +UARTParityModeSet(unsigned long ulBase, unsigned long ulParity) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + ASSERT((ulParity == UART_CONFIG_PAR_NONE) || + (ulParity == UART_CONFIG_PAR_EVEN) || + (ulParity == UART_CONFIG_PAR_ODD) || + (ulParity == UART_CONFIG_PAR_ONE) || + (ulParity == UART_CONFIG_PAR_ZERO)); + + // + // Set the parity mode. + // + HWREG(ulBase + UART_O_LCRH) = ((HWREG(ulBase + UART_O_LCRH) & + ~(UART_LCRH_SPS | UART_LCRH_EPS | + UART_LCRH_PEN)) | ulParity); +} + +//***************************************************************************** +// +//! Gets the type of parity currently being used. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function gets the type of parity used for transmitting data and +//! expected when receiving data. +//! +//! \return Returns the current parity settings, specified as one of +//! \b UART_CONFIG_PAR_NONE, \b UART_CONFIG_PAR_EVEN, \b UART_CONFIG_PAR_ODD, +//! \b UART_CONFIG_PAR_ONE, or \b UART_CONFIG_PAR_ZERO. +// +//***************************************************************************** +unsigned long +UARTParityModeGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return the current parity setting. + // + return(HWREG(ulBase + UART_O_LCRH) & + (UART_LCRH_SPS | UART_LCRH_EPS | UART_LCRH_PEN)); +} + +//***************************************************************************** +// +//! Sets the FIFO level at which interrupts are generated. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulTxLevel is the transmit FIFO interrupt level, specified as one of +//! \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, \b UART_FIFO_TX4_8, +//! \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8. +//! \param ulRxLevel is the receive FIFO interrupt level, specified as one of +//! \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, \b UART_FIFO_RX4_8, +//! \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8. +//! +//! This function sets the FIFO level at which transmit and receive interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFIFOLevelSet(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulRxLevel) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + ASSERT((ulTxLevel == UART_FIFO_TX1_8) || + (ulTxLevel == UART_FIFO_TX2_8) || + (ulTxLevel == UART_FIFO_TX4_8) || + (ulTxLevel == UART_FIFO_TX6_8) || + (ulTxLevel == UART_FIFO_TX7_8)); + ASSERT((ulRxLevel == UART_FIFO_RX1_8) || + (ulRxLevel == UART_FIFO_RX2_8) || + (ulRxLevel == UART_FIFO_RX4_8) || + (ulRxLevel == UART_FIFO_RX6_8) || + (ulRxLevel == UART_FIFO_RX7_8)); + + // + // Set the FIFO interrupt levels. + // + HWREG(ulBase + UART_O_IFLS) = ulTxLevel | ulRxLevel; +} + +//***************************************************************************** +// +//! Gets the FIFO level at which interrupts are generated. +//! +//! \param ulBase is the base address of the UART port. +//! \param pulTxLevel is a pointer to storage for the transmit FIFO level, +//! returned as one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, +//! \b UART_FIFO_TX4_8, \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8. +//! \param pulRxLevel is a pointer to storage for the receive FIFO level, +//! returned as one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, +//! \b UART_FIFO_RX4_8, \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8. +//! +//! This function gets the FIFO level at which transmit and receive interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFIFOLevelGet(unsigned long ulBase, unsigned long *pulTxLevel, + unsigned long *pulRxLevel) +{ + unsigned long ulTemp; + + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Read the FIFO level register. + // + ulTemp = HWREG(ulBase + UART_O_IFLS); + + // + // Extract the transmit and receive FIFO levels. + // + *pulTxLevel = ulTemp & UART_IFLS_TX_M; + *pulRxLevel = ulTemp & UART_IFLS_RX_M; +} + +//***************************************************************************** +// +//! Sets the configuration of a UART. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulUARTClk is the rate of the clock supplied to the UART module. +//! \param ulBaud is the desired baud rate. +//! \param ulConfig is the data format for the port (number of data bits, +//! number of stop bits, and parity). +//! +//! This function configures the UART for operation in the specified data +//! format. The baud rate is provided in the \e ulBaud parameter and the data +//! format in the \e ulConfig parameter. +//! +//! The \e ulConfig parameter is the logical OR of three values: the number of +//! data bits, the number of stop bits, and the parity. \b UART_CONFIG_WLEN_8, +//! \b UART_CONFIG_WLEN_7, \b UART_CONFIG_WLEN_6, and \b UART_CONFIG_WLEN_5 +//! select from eight to five data bits per byte (respectively). +//! \b UART_CONFIG_STOP_ONE and \b UART_CONFIG_STOP_TWO select one or two stop +//! bits (respectively). \b UART_CONFIG_PAR_NONE, \b UART_CONFIG_PAR_EVEN, +//! \b UART_CONFIG_PAR_ODD, \b UART_CONFIG_PAR_ONE, and \b UART_CONFIG_PAR_ZERO +//! select the parity mode (no parity bit, even parity bit, odd parity bit, +//! parity bit always one, and parity bit always zero, respectively). +//! +//! The peripheral clock is the same as the processor clock. The frequency of +//! the system clock is the value returned by SysCtlClockGet(), or it can be +//! explicitly hard coded if it is constant and known (to save the +//! code/execution overhead of a call to SysCtlClockGet()). +//! +//! +//! \return None. +// +//***************************************************************************** +void +UARTConfigSetExpClk(unsigned long ulBase, unsigned long ulUARTClk, + unsigned long ulBaud, unsigned long ulConfig) +{ + unsigned long ulDiv; + + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + ASSERT(ulBaud != 0); + + // + // Stop the UART. + // + UARTDisable(ulBase); + + // + // Is the required baud rate greater than the maximum rate supported + // without the use of high speed mode? + // + if((ulBaud * 16) > ulUARTClk) + { + // + // Enable high speed mode. + // + HWREG(ulBase + UART_O_CTL) |= UART_CTL_HSE; + + // + // Half the supplied baud rate to compensate for enabling high speed + // mode. This allows the following code to be common to both cases. + // + ulBaud /= 2; + } + else + { + // + // Disable high speed mode. + // + HWREG(ulBase + UART_O_CTL) &= ~(UART_CTL_HSE); + } + + // + // Compute the fractional baud rate divider. + // + ulDiv = (((ulUARTClk * 8) / ulBaud) + 1) / 2; + + // + // Set the baud rate. + // + HWREG(ulBase + UART_O_IBRD) = ulDiv / 64; + HWREG(ulBase + UART_O_FBRD) = ulDiv % 64; + + // + // Set parity, data length, and number of stop bits. + // + HWREG(ulBase + UART_O_LCRH) = ulConfig; + + // + // Clear the flags register. + // + HWREG(ulBase + UART_O_FR) = 0; + + // + // Start the UART. + // + UARTEnable(ulBase); +} + +//***************************************************************************** +// +//! Gets the current configuration of a UART. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulUARTClk is the rate of the clock supplied to the UART module. +//! \param pulBaud is a pointer to storage for the baud rate. +//! \param pulConfig is a pointer to storage for the data format. +//! +//! The baud rate and data format for the UART is determined, given an +//! explicitly provided peripheral clock (hence the ExpClk suffix). The +//! returned baud rate is the actual baud rate; it may not be the exact baud +//! rate requested or an ``official'' baud rate. The data format returned in +//! \e pulConfig is enumerated the same as the \e ulConfig parameter of +//! UARTConfigSetExpClk(). +//! +//! The peripheral clock is the same as the processor clock. The frequency of +//! the system clock is the value returned by SysCtlClockGet(), or it can be +//! explicitly hard coded if it is constant and known (to save the +//! code/execution overhead of a call to SysCtlClockGet()). +//! +//! +//! \return None. +// +//***************************************************************************** +void +UARTConfigGetExpClk(unsigned long ulBase, unsigned long ulUARTClk, + unsigned long *pulBaud, unsigned long *pulConfig) +{ + unsigned long ulInt, ulFrac; + + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Compute the baud rate. + // + ulInt = HWREG(ulBase + UART_O_IBRD); + ulFrac = HWREG(ulBase + UART_O_FBRD); + *pulBaud = (ulUARTClk * 4) / ((64 * ulInt) + ulFrac); + + // + // See if high speed mode enabled. + // + if(HWREG(ulBase + UART_O_CTL) & UART_CTL_HSE) + { + // + // High speed mode is enabled so the actual baud rate is actually + // double what was just calculated. + // + *pulBaud *= 2; + } + + // + // Get the parity, data length, and number of stop bits. + // + *pulConfig = (HWREG(ulBase + UART_O_LCRH) & + (UART_LCRH_SPS | UART_LCRH_WLEN_M | UART_LCRH_STP2 | + UART_LCRH_EPS | UART_LCRH_PEN)); +} + +//***************************************************************************** +// +//! Enables transmitting and receiving. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function sets the UARTEN, TXE, and RXE bits, and enables the transmit +//! and receive FIFOs. +//! +//! \return None. +// +//***************************************************************************** +void +UARTEnable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Enable the FIFO. + // + HWREG(ulBase + UART_O_LCRH) |= UART_LCRH_FEN; + + // + // Enable RX, TX, and the UART. + // + HWREG(ulBase + UART_O_CTL) |= (UART_CTL_UARTEN | UART_CTL_TXE | + UART_CTL_RXE); +} + +//***************************************************************************** +// +//! Disables transmitting and receiving. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function clears the UARTEN, TXE, and RXE bits, waits for the end of +//! transmission of the current character, and flushes the transmit FIFO. +//! +//! \return None. +// +//***************************************************************************** +void +UARTDisable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Wait for end of TX. + // + while(HWREG(ulBase + UART_O_FR) & UART_FR_BUSY) + { + } + + // + // Disable the FIFO. + // + HWREG(ulBase + UART_O_LCRH) &= ~(UART_LCRH_FEN); + + // + // Disable the UART. + // + HWREG(ulBase + UART_O_CTL) &= ~(UART_CTL_UARTEN | UART_CTL_TXE | + UART_CTL_RXE); +} + +//***************************************************************************** +// +//! Enables the transmit and receive FIFOs. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This functions enables the transmit and receive FIFOs in the UART. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFIFOEnable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Enable the FIFO. + // + HWREG(ulBase + UART_O_LCRH) |= UART_LCRH_FEN; +} + +//***************************************************************************** +// +//! Disables the transmit and receive FIFOs. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This functions disables the transmit and receive FIFOs in the UART. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFIFODisable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Disable the FIFO. + // + HWREG(ulBase + UART_O_LCRH) &= ~(UART_LCRH_FEN); +} + +//***************************************************************************** +// +//! Sets the states of the RTS modem control signals. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulControl is a bit-mapped flag indicating which modem control bits +//! should be set. +//! +//! This function sets the states of the RTS modem handshake outputs +//! from the UART. +//! +//! The \e ulControl parameter is the logical OR of any of the following: +//! +//! - \b UART_OUTPUT_RTS - The Modem Control RTS signal +//! +//! \note The availability of hardware modem handshake signals varies with the +//! part and UART in use. Please consult the datasheet for the part +//! you are using to determine whether this support is available. +//! +//! \return None. +// +//***************************************************************************** +void +UARTModemControlSet(unsigned long ulBase, unsigned long ulControl) +{ + unsigned long ulTemp; + + // + // Check the arguments. + // + + ASSERT(ulBase == UARTA1_BASE); + ASSERT((ulControl & ~(UART_OUTPUT_RTS)) == 0); + + // + // Set the appropriate modem control output bits. + // + ulTemp = HWREG(ulBase + UART_O_CTL); + ulTemp |= (ulControl & (UART_OUTPUT_RTS)); + HWREG(ulBase + UART_O_CTL) = ulTemp; +} + +//***************************************************************************** +// +//! Clears the states of the RTS modem control signals. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulControl is a bit-mapped flag indicating which modem control bits +//! should be set. +//! +//! This function clears the states of the RTS modem handshake outputs +//! from the UART. +//! +//! The \e ulControl parameter is the logical OR of any of the following: +//! +//! - \b UART_OUTPUT_RTS - The Modem Control RTS signal +//! +//! \note The availability of hardware modem handshake signals varies with the +//! part and UART in use. Please consult the datasheet for the part +//! you are using to determine whether this support is available. +//! +//! \return None. +// +//***************************************************************************** +void +UARTModemControlClear(unsigned long ulBase, unsigned long ulControl) +{ + unsigned long ulTemp; + + // + // Check the arguments. + // + ASSERT(ulBase == UARTA1_BASE); + ASSERT((ulControl & ~(UART_OUTPUT_RTS)) == 0); + + // + // Set the appropriate modem control output bits. + // + ulTemp = HWREG(ulBase + UART_O_CTL); + ulTemp &= ~(ulControl & (UART_OUTPUT_RTS)); + HWREG(ulBase + UART_O_CTL) = ulTemp; +} + +//***************************************************************************** +// +//! Gets the states of the RTS modem control signals. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns the current states of each of the UART modem +//! control signal, RTS. +//! +//! \note The availability of hardware modem handshake signals varies with the +//! part and UART in use. Please consult the datasheet for the part +//! you are using to determine whether this support is available. +//! +//! \return Returns the states of the handshake output signal. +// +//***************************************************************************** +unsigned long +UARTModemControlGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(ulBase == UARTA1_BASE); + + return(HWREG(ulBase + UART_O_CTL) & (UART_OUTPUT_RTS)); +} + +//***************************************************************************** +// +//! Gets the states of the CTS modem status signal. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns the current states of the UART modem status signal, +//! CTS. +//! +//! \note The availability of hardware modem handshake signals varies with the +//! part and UART in use. Please consult the datasheet for the part +//! you are using to determine whether this support is available. +//! +//! \return Returns the states of the handshake output signal +// +//***************************************************************************** +unsigned long +UARTModemStatusGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + + ASSERT(ulBase == UARTA1_BASE); + + return(HWREG(ulBase + UART_O_FR) & (UART_INPUT_CTS)); +} + +//***************************************************************************** +// +//! Sets the UART hardware flow control mode to be used. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulMode indicates the flow control modes to be used. This parameter +//! is a logical OR combination of values \b UART_FLOWCONTROL_TX and +//! \b UART_FLOWCONTROL_RX to enable hardware transmit (CTS) and receive (RTS) +//! flow control or \b UART_FLOWCONTROL_NONE to disable hardware flow control. +//! +//! This function sets the required hardware flow control modes. If \e ulMode +//! contains flag \b UART_FLOWCONTROL_TX, data is only transmitted if the +//! incoming CTS signal is asserted. If \e ulMode contains flag +//! \b UART_FLOWCONTROL_RX, the RTS output is controlled by the hardware and is +//! asserted only when there is space available in the receive FIFO. If no +//! hardware flow control is required, \b UART_FLOWCONTROL_NONE should be +//! passed. +//! +//! \note The availability of hardware flow control varies with the +//! part and UART in use. Please consult the datasheet for the part you are +//! using to determine whether this support is available. +//! +//! \return None. +// +//***************************************************************************** +void +UARTFlowControlSet(unsigned long ulBase, unsigned long ulMode) +{ + // + // Check the arguments. + // + + ASSERT(UARTBaseValid(ulBase)); + ASSERT((ulMode & ~(UART_FLOWCONTROL_TX | UART_FLOWCONTROL_RX)) == 0); + + // + // Set the flow control mode as requested. + // + HWREG(ulBase + UART_O_CTL) = ((HWREG(ulBase + UART_O_CTL) & + ~(UART_FLOWCONTROL_TX | + UART_FLOWCONTROL_RX)) | ulMode); +} + +//***************************************************************************** +// +//! Returns the UART hardware flow control mode currently in use. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns the current hardware flow control mode. +//! +//! \note The availability of hardware flow control varies with the +//! part and UART in use. Please consult the datasheet for the part you are +//! using to determine whether this support is available. +//! +//! \return Returns the current flow control mode in use. This is a +//! logical OR combination of values \b UART_FLOWCONTROL_TX if transmit +//! (CTS) flow control is enabled and \b UART_FLOWCONTROL_RX if receive (RTS) +//! flow control is in use. If hardware flow control is disabled, +//! \b UART_FLOWCONTROL_NONE is returned. +// +//***************************************************************************** +unsigned long +UARTFlowControlGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + + ASSERT(UARTBaseValid(ulBase)); + + return(HWREG(ulBase + UART_O_CTL) & (UART_FLOWCONTROL_TX | + UART_FLOWCONTROL_RX)); +} + +//***************************************************************************** +// +//! Sets the operating mode for the UART transmit interrupt. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulMode is the operating mode for the transmit interrupt. It may be +//! \b UART_TXINT_MODE_EOT to trigger interrupts when the transmitter is idle +//! or \b UART_TXINT_MODE_FIFO to trigger based on the current transmit FIFO +//! level. +//! +//! This function allows the mode of the UART transmit interrupt to be set. By +//! default, the transmit interrupt is asserted when the FIFO level falls past +//! a threshold set via a call to UARTFIFOLevelSet(). Alternatively, if this +//! function is called with \e ulMode set to \b UART_TXINT_MODE_EOT, the +//! transmit interrupt is asserted once the transmitter is completely idle - +//! the transmit FIFO is empty and all bits, including any stop bits, have +//! cleared the transmitter. +//! +//! \note The availability of end-of-transmission mode varies with the +//! part in use. Please consult the datasheet for the part you are +//! using to determine whether this support is available. +//! +//! \return None. +// +//***************************************************************************** +void +UARTTxIntModeSet(unsigned long ulBase, unsigned long ulMode) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + ASSERT((ulMode == UART_TXINT_MODE_EOT) || + (ulMode == UART_TXINT_MODE_FIFO)); + + // + // Set or clear the EOT bit of the UART control register as appropriate. + // + HWREG(ulBase + UART_O_CTL) = ((HWREG(ulBase + UART_O_CTL) & + ~(UART_TXINT_MODE_EOT | + UART_TXINT_MODE_FIFO)) | ulMode); +} + +//***************************************************************************** +// +//! Returns the current operating mode for the UART transmit interrupt. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns the current operating mode for the UART transmit +//! interrupt. The return value is \b UART_TXINT_MODE_EOT if the transmit +//! interrupt is currently set to be asserted once the transmitter is +//! completely idle - the transmit FIFO is empty and all bits, including any +//! stop bits, have cleared the transmitter. The return value is +//! \b UART_TXINT_MODE_FIFO if the interrupt is set to be asserted based upon +//! the level of the transmit FIFO. +//! +//! \note The availability of end-of-transmission mode varies with the +//! part in use. Please consult the datasheet for the part you are +//! using to determine whether this support is available. +//! +//! \return Returns \b UART_TXINT_MODE_FIFO or \b UART_TXINT_MODE_EOT. +// +//***************************************************************************** +unsigned long +UARTTxIntModeGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return the current transmit interrupt mode. + // + return(HWREG(ulBase + UART_O_CTL) & (UART_TXINT_MODE_EOT | + UART_TXINT_MODE_FIFO)); +} + +//***************************************************************************** +// +//! Determines if there are any characters in the receive FIFO. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns a flag indicating whether or not there is data +//! available in the receive FIFO. +//! +//! \return Returns \b true if there is data in the receive FIFO or \b false +//! if there is no data in the receive FIFO. +// +//***************************************************************************** +tBoolean +UARTCharsAvail(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return the availability of characters. + // + return((HWREG(ulBase + UART_O_FR) & UART_FR_RXFE) ? false : true); +} + +//***************************************************************************** +// +//! Determines if there is any space in the transmit FIFO. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns a flag indicating whether or not there is space +//! available in the transmit FIFO. +//! +//! \return Returns \b true if there is space available in the transmit FIFO +//! or \b false if there is no space available in the transmit FIFO. +// +//***************************************************************************** +tBoolean +UARTSpaceAvail(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return the availability of space. + // + return((HWREG(ulBase + UART_O_FR) & UART_FR_TXFF) ? false : true); +} + +//***************************************************************************** +// +//! Receives a character from the specified port. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function gets a character from the receive FIFO for the specified +//! port. +//! +//! +//! \return Returns the character read from the specified port, cast as a +//! \e long. A \b -1 is returned if there are no characters present in the +//! receive FIFO. The UARTCharsAvail() function should be called before +//! attempting to call this function. +// +//***************************************************************************** +long +UARTCharGetNonBlocking(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // See if there are any characters in the receive FIFO. + // + if(!(HWREG(ulBase + UART_O_FR) & UART_FR_RXFE)) + { + // + // Read and return the next character. + // + return(HWREG(ulBase + UART_O_DR)); + } + else + { + // + // There are no characters, so return a failure. + // + return(-1); + } +} + +//***************************************************************************** +// +//! Waits for a character from the specified port. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function gets a character from the receive FIFO for the specified +//! port. If there are no characters available, this function waits until a +//! character is received before returning. +//! +//! \return Returns the character read from the specified port, cast as a +//! \e long. +// +//***************************************************************************** +long +UARTCharGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Wait until a char is available. + // + while(HWREG(ulBase + UART_O_FR) & UART_FR_RXFE) + { + } + + // + // Now get the char. + // + return(HWREG(ulBase + UART_O_DR)); +} + +//***************************************************************************** +// +//! Sends a character to the specified port. +//! +//! \param ulBase is the base address of the UART port. +//! \param ucData is the character to be transmitted. +//! +//! This function writes the character \e ucData to the transmit FIFO for the +//! specified port. This function does not block, so if there is no space +//! available, then a \b false is returned, and the application must retry the +//! function later. +//! +//! \return Returns \b true if the character was successfully placed in the +//! transmit FIFO or \b false if there was no space available in the transmit +//! FIFO. +// +//***************************************************************************** +tBoolean +UARTCharPutNonBlocking(unsigned long ulBase, unsigned char ucData) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // See if there is space in the transmit FIFO. + // + if(!(HWREG(ulBase + UART_O_FR) & UART_FR_TXFF)) + { + // + // Write this character to the transmit FIFO. + // + HWREG(ulBase + UART_O_DR) = ucData; + + // + // Success. + // + return(true); + } + else + { + // + // There is no space in the transmit FIFO, so return a failure. + // + return(false); + } +} + +//***************************************************************************** +// +//! Waits to send a character from the specified port. +//! +//! \param ulBase is the base address of the UART port. +//! \param ucData is the character to be transmitted. +//! +//! This function sends the character \e ucData to the transmit FIFO for the +//! specified port. If there is no space available in the transmit FIFO, this +//! function waits until there is space available before returning. +//! +//! \return None. +// +//***************************************************************************** +void +UARTCharPut(unsigned long ulBase, unsigned char ucData) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Wait until space is available. + // + while(HWREG(ulBase + UART_O_FR) & UART_FR_TXFF) + { + } + + // + // Send the char. + // + HWREG(ulBase + UART_O_DR) = ucData; +} + +//***************************************************************************** +// +//! Causes a BREAK to be sent. +//! +//! \param ulBase is the base address of the UART port. +//! \param bBreakState controls the output level. +//! +//! Calling this function with \e bBreakState set to \b true asserts a break +//! condition on the UART. Calling this function with \e bBreakState set to +//! \b false removes the break condition. For proper transmission of a break +//! command, the break must be asserted for at least two complete frames. +//! +//! \return None. +// +//***************************************************************************** +void +UARTBreakCtl(unsigned long ulBase, tBoolean bBreakState) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Set the break condition as requested. + // + HWREG(ulBase + UART_O_LCRH) = + (bBreakState ? + (HWREG(ulBase + UART_O_LCRH) | UART_LCRH_BRK) : + (HWREG(ulBase + UART_O_LCRH) & ~(UART_LCRH_BRK))); +} + +//***************************************************************************** +// +//! Determines whether the UART transmitter is busy or not. +//! +//! \param ulBase is the base address of the UART port. +//! +//! Allows the caller to determine whether all transmitted bytes have cleared +//! the transmitter hardware. If \b false is returned, the transmit FIFO is +//! empty and all bits of the last transmitted character, including all stop +//! bits, have left the hardware shift register. +//! +//! \return Returns \b true if the UART is transmitting or \b false if all +//! transmissions are complete. +// +//***************************************************************************** +tBoolean +UARTBusy(unsigned long ulBase) +{ + // + // Check the argument. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Determine if the UART is busy. + // + return((HWREG(ulBase + UART_O_FR) & UART_FR_BUSY) ? true : false); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for a UART interrupt. +//! +//! \param ulBase is the base address of the UART port. +//! \param pfnHandler is a pointer to the function to be called when the +//! UART interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; specific +//! UART interrupts must be enabled via UARTIntEnable(). It is the interrupt +//! handler's responsibility to clear the interrupt source. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +UARTIntRegister(unsigned long ulBase, void (*pfnHandler)(void)) +{ + unsigned long ulInt; + + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Determine the interrupt number based on the UART port. + // + + ulInt = UARTIntNumberGet(ulBase); + + // + // Register the interrupt handler. + // + IntRegister(ulInt, pfnHandler); + + // + // Enable the UART interrupt. + // + IntEnable(ulInt); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for a UART interrupt. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a UART interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +UARTIntUnregister(unsigned long ulBase) +{ + unsigned long ulInt; + + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Determine the interrupt number based on the UART port. + // + ulInt = UARTIntNumberGet(ulBase); + + // + // Disable the interrupt. + // + IntDisable(ulInt); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulInt); +} + +//***************************************************************************** +// +//! Enables individual UART interrupt sources. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated UART interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b UART_INT_OE - Overrun Error interrupt +//! - \b UART_INT_BE - Break Error interrupt +//! - \b UART_INT_PE - Parity Error interrupt +//! - \b UART_INT_FE - Framing Error interrupt +//! - \b UART_INT_RT - Receive Timeout interrupt +//! - \b UART_INT_TX - Transmit interrupt +//! - \b UART_INT_RX - Receive interrupt +//! - \b UART_INT_CTS - CTS interrupt +//! +//! \return None. +// +//***************************************************************************** +void +UARTIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Enable the specified interrupts. + // + HWREG(ulBase + UART_O_IM) |= ulIntFlags; +} + +//***************************************************************************** +// +//! Disables individual UART interrupt sources. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! This function disables the indicated UART interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to UARTIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +UARTIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Disable the specified interrupts. + // + HWREG(ulBase + UART_O_IM) &= ~(ulIntFlags); +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of the UART port. +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! This function returns the interrupt status for the specified UART. Either +//! the raw interrupt status or the status of interrupts that are allowed to +//! reflect to the processor can be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in UARTIntEnable(). +// +//***************************************************************************** +unsigned long +UARTIntStatus(unsigned long ulBase, tBoolean bMasked) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return(HWREG(ulBase + UART_O_MIS)); + } + else + { + return(HWREG(ulBase + UART_O_RIS)); + } +} + +//***************************************************************************** +// +//! Clears UART interrupt sources. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified UART interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being recognized again immediately upon exit. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to UARTIntEnable(). +//! +//! \note Because there is a write buffer in the Cortex-M3 processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +UARTIntClear(unsigned long ulBase, unsigned long ulIntFlags) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Clear the requested interrupt sources. + // + HWREG(ulBase + UART_O_ICR) = ulIntFlags; +} + +//***************************************************************************** +// +//! Enable UART DMA operation. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulDMAFlags is a bit mask of the DMA features to enable. +//! +//! The specified UART DMA features are enabled. The UART can be +//! configured to use DMA for transmit or receive, and to disable +//! receive if an error occurs. The \e ulDMAFlags parameter is the +//! logical OR of any of the following values: +//! +//! - UART_DMA_RX - enable DMA for receive +//! - UART_DMA_TX - enable DMA for transmit +//! - UART_DMA_ERR_RXSTOP - disable DMA receive on UART error +//! +//! \note The uDMA controller must also be set up before DMA can be used +//! with the UART. +//! +//! \return None. +// +//***************************************************************************** +void +UARTDMAEnable(unsigned long ulBase, unsigned long ulDMAFlags) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Set the requested bits in the UART DMA control register. + // + HWREG(ulBase + UART_O_DMACTL) |= ulDMAFlags; +} + +//***************************************************************************** +// +//! Disable UART DMA operation. +//! +//! \param ulBase is the base address of the UART port. +//! \param ulDMAFlags is a bit mask of the DMA features to disable. +//! +//! This function is used to disable UART DMA features that were enabled +//! by UARTDMAEnable(). The specified UART DMA features are disabled. The +//! \e ulDMAFlags parameter is the logical OR of any of the following values: +//! +//! - UART_DMA_RX - disable DMA for receive +//! - UART_DMA_TX - disable DMA for transmit +//! - UART_DMA_ERR_RXSTOP - do not disable DMA receive on UART error +//! +//! \return None. +// +//***************************************************************************** +void +UARTDMADisable(unsigned long ulBase, unsigned long ulDMAFlags) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Clear the requested bits in the UART DMA control register. + // + HWREG(ulBase + UART_O_DMACTL) &= ~ulDMAFlags; +} + +//***************************************************************************** +// +//! Gets current receiver errors. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function returns the current state of each of the 4 receiver error +//! sources. The returned errors are equivalent to the four error bits +//! returned via the previous call to UARTCharGet() or UARTCharGetNonBlocking() +//! with the exception that the overrun error is set immediately the overrun +//! occurs rather than when a character is next read. +//! +//! \return Returns a logical OR combination of the receiver error flags, +//! \b UART_RXERROR_FRAMING, \b UART_RXERROR_PARITY, \b UART_RXERROR_BREAK +//! and \b UART_RXERROR_OVERRUN. +// +//***************************************************************************** +unsigned long +UARTRxErrorGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Return the current value of the receive status register. + // + return(HWREG(ulBase + UART_O_RSR) & 0x0000000F); +} + +//***************************************************************************** +// +//! Clears all reported receiver errors. +//! +//! \param ulBase is the base address of the UART port. +//! +//! This function is used to clear all receiver error conditions reported via +//! UARTRxErrorGet(). If using the overrun, framing error, parity error or +//! break interrupts, this function must be called after clearing the interrupt +//! to ensure that later errors of the same type trigger another interrupt. +//! +//! \return None. +// +//***************************************************************************** +void +UARTRxErrorClear(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT(UARTBaseValid(ulBase)); + + // + // Any write to the Error Clear Register will clear all bits which are + // currently set. + // + HWREG(ulBase + UART_O_ECR) = 0; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/uart.h b/src/openmv/src/micropython/ports/cc3200/hal/uart.h new file mode 100755 index 0000000..503cd2c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/uart.h @@ -0,0 +1,234 @@ +//***************************************************************************** +// +// uart.h +// +// Defines and Macros for the UART. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __UART_H__ +#define __UART_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Values that can be passed to UARTIntEnable, UARTIntDisable, and UARTIntClear +// as the ulIntFlags parameter, and returned from UARTIntStatus. +// +//***************************************************************************** +#define UART_INT_DMATX 0x20000 // DMA Tx Done interrupt Mask +#define UART_INT_DMARX 0x10000 // DMA Rx Done interrupt Mask +#define UART_INT_EOT 0x800 // End of transfer interrupt Mask +#define UART_INT_OE 0x400 // Overrun Error Interrupt Mask +#define UART_INT_BE 0x200 // Break Error Interrupt Mask +#define UART_INT_PE 0x100 // Parity Error Interrupt Mask +#define UART_INT_FE 0x080 // Framing Error Interrupt Mask +#define UART_INT_RT 0x040 // Receive Timeout Interrupt Mask +#define UART_INT_TX 0x020 // Transmit Interrupt Mask +#define UART_INT_RX 0x010 // Receive Interrupt Mask +#define UART_INT_CTS 0x002 // CTS Modem Interrupt Mask + + +//***************************************************************************** +// +// Values that can be passed to UARTConfigSetExpClk as the ulConfig parameter +// and returned by UARTConfigGetExpClk in the pulConfig parameter. +// Additionally, the UART_CONFIG_PAR_* subset can be passed to +// UARTParityModeSet as the ulParity parameter, and are returned by +// UARTParityModeGet. +// +//***************************************************************************** +#define UART_CONFIG_WLEN_MASK 0x00000060 // Mask for extracting word length +#define UART_CONFIG_WLEN_8 0x00000060 // 8 bit data +#define UART_CONFIG_WLEN_7 0x00000040 // 7 bit data +#define UART_CONFIG_WLEN_6 0x00000020 // 6 bit data +#define UART_CONFIG_WLEN_5 0x00000000 // 5 bit data +#define UART_CONFIG_STOP_MASK 0x00000008 // Mask for extracting stop bits +#define UART_CONFIG_STOP_ONE 0x00000000 // One stop bit +#define UART_CONFIG_STOP_TWO 0x00000008 // Two stop bits +#define UART_CONFIG_PAR_MASK 0x00000086 // Mask for extracting parity +#define UART_CONFIG_PAR_NONE 0x00000000 // No parity +#define UART_CONFIG_PAR_EVEN 0x00000006 // Even parity +#define UART_CONFIG_PAR_ODD 0x00000002 // Odd parity +#define UART_CONFIG_PAR_ONE 0x00000082 // Parity bit is one +#define UART_CONFIG_PAR_ZERO 0x00000086 // Parity bit is zero + +//***************************************************************************** +// +// Values that can be passed to UARTFIFOLevelSet as the ulTxLevel parameter and +// returned by UARTFIFOLevelGet in the pulTxLevel. +// +//***************************************************************************** +#define UART_FIFO_TX1_8 0x00000000 // Transmit interrupt at 1/8 Full +#define UART_FIFO_TX2_8 0x00000001 // Transmit interrupt at 1/4 Full +#define UART_FIFO_TX4_8 0x00000002 // Transmit interrupt at 1/2 Full +#define UART_FIFO_TX6_8 0x00000003 // Transmit interrupt at 3/4 Full +#define UART_FIFO_TX7_8 0x00000004 // Transmit interrupt at 7/8 Full + +//***************************************************************************** +// +// Values that can be passed to UARTFIFOLevelSet as the ulRxLevel parameter and +// returned by UARTFIFOLevelGet in the pulRxLevel. +// +//***************************************************************************** +#define UART_FIFO_RX1_8 0x00000000 // Receive interrupt at 1/8 Full +#define UART_FIFO_RX2_8 0x00000008 // Receive interrupt at 1/4 Full +#define UART_FIFO_RX4_8 0x00000010 // Receive interrupt at 1/2 Full +#define UART_FIFO_RX6_8 0x00000018 // Receive interrupt at 3/4 Full +#define UART_FIFO_RX7_8 0x00000020 // Receive interrupt at 7/8 Full + +//***************************************************************************** +// +// Values that can be passed to UARTDMAEnable() and UARTDMADisable(). +// +//***************************************************************************** +#define UART_DMA_ERR_RXSTOP 0x00000004 // Stop DMA receive if UART error +#define UART_DMA_TX 0x00000002 // Enable DMA for transmit +#define UART_DMA_RX 0x00000001 // Enable DMA for receive + +//***************************************************************************** +// +// Values returned from UARTRxErrorGet(). +// +//***************************************************************************** +#define UART_RXERROR_OVERRUN 0x00000008 +#define UART_RXERROR_BREAK 0x00000004 +#define UART_RXERROR_PARITY 0x00000002 +#define UART_RXERROR_FRAMING 0x00000001 + +//***************************************************************************** +// +// Values that can be passed to UARTModemControlSet()and UARTModemControlClear() +// or returned from UARTModemControlGet(). +// +//***************************************************************************** +#define UART_OUTPUT_RTS 0x00000800 + +//***************************************************************************** +// +// Values that can be returned from UARTModemStatusGet(). +// +//***************************************************************************** +#define UART_INPUT_CTS 0x00000001 + +//***************************************************************************** +// +// Values that can be passed to UARTFlowControl() or returned from +// UARTFlowControlGet(). +// +//***************************************************************************** +#define UART_FLOWCONTROL_TX 0x00008000 +#define UART_FLOWCONTROL_RX 0x00004000 +#define UART_FLOWCONTROL_NONE 0x00000000 + +//***************************************************************************** +// +// Values that can be passed to UARTTxIntModeSet() or returned from +// UARTTxIntModeGet(). +// +//***************************************************************************** +#define UART_TXINT_MODE_FIFO 0x00000000 +#define UART_TXINT_MODE_EOT 0x00000010 + + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void UARTParityModeSet(unsigned long ulBase, unsigned long ulParity); +extern unsigned long UARTParityModeGet(unsigned long ulBase); +extern void UARTFIFOLevelSet(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulRxLevel); +extern void UARTFIFOLevelGet(unsigned long ulBase, unsigned long *pulTxLevel, + unsigned long *pulRxLevel); +extern void UARTConfigSetExpClk(unsigned long ulBase, unsigned long ulUARTClk, + unsigned long ulBaud, unsigned long ulConfig); +extern void UARTConfigGetExpClk(unsigned long ulBase, unsigned long ulUARTClk, + unsigned long *pulBaud, + unsigned long *pulConfig); +extern void UARTEnable(unsigned long ulBase); +extern void UARTDisable(unsigned long ulBase); +extern void UARTFIFOEnable(unsigned long ulBase); +extern void UARTFIFODisable(unsigned long ulBase); +extern tBoolean UARTCharsAvail(unsigned long ulBase); +extern tBoolean UARTSpaceAvail(unsigned long ulBase); +extern long UARTCharGetNonBlocking(unsigned long ulBase); +extern long UARTCharGet(unsigned long ulBase); +extern tBoolean UARTCharPutNonBlocking(unsigned long ulBase, + unsigned char ucData); +extern void UARTCharPut(unsigned long ulBase, unsigned char ucData); +extern void UARTBreakCtl(unsigned long ulBase, tBoolean bBreakState); +extern tBoolean UARTBusy(unsigned long ulBase); +extern void UARTIntRegister(unsigned long ulBase, void(*pfnHandler)(void)); +extern void UARTIntUnregister(unsigned long ulBase); +extern void UARTIntEnable(unsigned long ulBase, unsigned long ulIntFlags); +extern void UARTIntDisable(unsigned long ulBase, unsigned long ulIntFlags); +extern unsigned long UARTIntStatus(unsigned long ulBase, tBoolean bMasked); +extern void UARTIntClear(unsigned long ulBase, unsigned long ulIntFlags); +extern void UARTDMAEnable(unsigned long ulBase, unsigned long ulDMAFlags); +extern void UARTDMADisable(unsigned long ulBase, unsigned long ulDMAFlags); +extern unsigned long UARTRxErrorGet(unsigned long ulBase); +extern void UARTRxErrorClear(unsigned long ulBase); +extern void UARTModemControlSet(unsigned long ulBase, + unsigned long ulControl); +extern void UARTModemControlClear(unsigned long ulBase, + unsigned long ulControl); +extern unsigned long UARTModemControlGet(unsigned long ulBase); +extern unsigned long UARTModemStatusGet(unsigned long ulBase); +extern void UARTFlowControlSet(unsigned long ulBase, unsigned long ulMode); +extern unsigned long UARTFlowControlGet(unsigned long ulBase); +extern void UARTTxIntModeSet(unsigned long ulBase, unsigned long ulMode); +extern unsigned long UARTTxIntModeGet(unsigned long ulBase); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __UART_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/utils.c b/src/openmv/src/micropython/ports/cc3200/hal/utils.c new file mode 100755 index 0000000..d0b13d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/utils.c @@ -0,0 +1,104 @@ +//***************************************************************************** +// +// utils.c +// +// Utility APIs +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup Utils_api +//! @{ +// +//***************************************************************************** +#include "utils.h" + + +//***************************************************************************** +// +//! Provides a small delay. +//! +//! \param ulCount is the number of delay loop iterations to perform. +//! +//! This function provides a means of generating a constant length delay. It +//! is written in assembly to keep the delay consistent across tool chains, +//! avoiding the need to tune the delay based on the tool chain in use. +//! +//! The loop takes 3 cycles/loop. +//! +//! \return None. +// +//***************************************************************************** +#if defined(ewarm) || defined(DOXYGEN) +void +UtilsDelay(unsigned long ulCount) +{ + __asm(" subs r0, #1\n" + " bne.n UtilsDelay\n"); +} +#endif + +#if defined(gcc) +void __attribute__((naked)) +UtilsDelay(unsigned long ulCount) +{ + __asm(" subs r0, #1\n" + " bne UtilsDelay\n" + " bx lr"); +} +#endif + +// +// For CCS implement this function in pure assembly. This prevents the TI +// compiler from doing funny things with the optimizer. +// +#if defined(ccs) + __asm(" .sect \".text:UtilsDelay\"\n" + " .clink\n" + " .thumbfunc UtilsDelay\n" + " .thumb\n" + " .global UtilsDelay\n" + "UtilsDelay:\n" + " subs r0, #1\n" + " bne.n UtilsDelay\n" + " bx lr\n"); +#endif + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/utils.h b/src/openmv/src/micropython/ports/cc3200/hal/utils.h new file mode 100755 index 0000000..a6fa78d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/utils.h @@ -0,0 +1,71 @@ +//***************************************************************************** +// +// utils.h +// +// Prototypes and macros for utility APIs +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __UTILS_H__ +#define __UTILS_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// API Function prototypes +// +//***************************************************************************** +extern void UtilsDelay(unsigned long ulCount); + + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif //__UTILS_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/hal/wdt.c b/src/openmv/src/micropython/ports/cc3200/hal/wdt.c new file mode 100755 index 0000000..8d8a9e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/wdt.c @@ -0,0 +1,491 @@ +//***************************************************************************** +// +// wdt.c +// +// Driver for the Watchdog Timer Module. +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup WDT_Watchdog_Timer_api +//! @{ +// +//***************************************************************************** + +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "inc/hw_wdt.h" +#include "debug.h" +#include "interrupt.h" +#include "wdt.h" + +//***************************************************************************** +// +//! Determines if the watchdog timer is enabled. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This will check to see if the watchdog timer is enabled. +//! +//! \return Returns \b true if the watchdog timer is enabled, and \b false +//! if it is not. +// +//***************************************************************************** +tBoolean +WatchdogRunning(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // See if the watchdog timer module is enabled, and return. + // + return(HWREG(ulBase + WDT_O_CTL) & WDT_CTL_INTEN); +} + +//***************************************************************************** +// +//! Enables the watchdog timer. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This will enable the watchdog timer counter and interrupt. +//! +//! \note This function will have no effect if the watchdog timer has +//! been locked. +//! +//! \sa WatchdogLock(), WatchdogUnlock() +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogEnable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Enable the watchdog timer module. + // + HWREG(ulBase + WDT_O_CTL) |= WDT_CTL_INTEN; +} + +//***************************************************************************** +// +//! Enables the watchdog timer lock mechanism. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! Locks out write access to the watchdog timer configuration registers. +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogLock(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Lock out watchdog register writes. Writing anything to the WDT_O_LOCK + // register causes the lock to go into effect. + // + HWREG(ulBase + WDT_O_LOCK) = WDT_LOCK_LOCKED; +} + +//***************************************************************************** +// +//! Disables the watchdog timer lock mechanism. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! Enables write access to the watchdog timer configuration registers. +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogUnlock(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Unlock watchdog register writes. + // + HWREG(ulBase + WDT_O_LOCK) = WDT_LOCK_UNLOCK; +} + +//***************************************************************************** +// +//! Gets the state of the watchdog timer lock mechanism. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! Returns the lock state of the watchdog timer registers. +//! +//! \return Returns \b true if the watchdog timer registers are locked, and +//! \b false if they are not locked. +// +//***************************************************************************** +tBoolean +WatchdogLockState(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Get the lock state. + // + return((HWREG(ulBase + WDT_O_LOCK) == WDT_LOCK_LOCKED) ? true : false); +} + +//***************************************************************************** +// +//! Sets the watchdog timer reload value. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! \param ulLoadVal is the load value for the watchdog timer. +//! +//! This function sets the value to load into the watchdog timer when the count +//! reaches zero for the first time; if the watchdog timer is running when this +//! function is called, then the value will be immediately loaded into the +//! watchdog timer counter. If the \e ulLoadVal parameter is 0, then an +//! interrupt is immediately generated. +//! +//! \note This function will have no effect if the watchdog timer has +//! been locked. +//! +//! \sa WatchdogLock(), WatchdogUnlock(), WatchdogReloadGet() +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogReloadSet(unsigned long ulBase, unsigned long ulLoadVal) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Set the load register. + // + HWREG(ulBase + WDT_O_LOAD) = ulLoadVal; +} + +//***************************************************************************** +// +//! Gets the watchdog timer reload value. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This function gets the value that is loaded into the watchdog timer when +//! the count reaches zero for the first time. +//! +//! \sa WatchdogReloadSet() +//! +//! \return None. +// +//***************************************************************************** +unsigned long +WatchdogReloadGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Get the load register. + // + return(HWREG(ulBase + WDT_O_LOAD)); +} + +//***************************************************************************** +// +//! Gets the current watchdog timer value. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This function reads the current value of the watchdog timer. +//! +//! \return Returns the current value of the watchdog timer. +// +//***************************************************************************** +unsigned long +WatchdogValueGet(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Get the current watchdog timer register value. + // + return(HWREG(ulBase + WDT_O_VALUE)); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for watchdog timer interrupt. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! \param pfnHandler is a pointer to the function to be called when the +//! watchdog timer interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! will enable the global interrupt in the interrupt controller; the watchdog +//! timer interrupt must be enabled via WatchdogEnable(). It is the interrupt +//! handler's responsibility to clear the interrupt source via +//! WatchdogIntClear(). +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \note This function will only register the standard watchdog interrupt +//! handler. To register the NMI watchdog handler, use IntRegister() +//! to register the handler for the \b FAULT_NMI interrupt. +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogIntRegister(unsigned long ulBase, void (*pfnHandler)(void)) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Register the interrupt handler and + // Enable the watchdog timer interrupt. + // + IntRegister(INT_WDT, pfnHandler); + IntEnable(INT_WDT); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for the watchdog timer interrupt. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This function does the actual unregistering of the interrupt handler. This +//! function will clear the handler to be called when a watchdog timer +//! interrupt occurs. This will also mask off the interrupt in the interrupt +//! controller so that the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \note This function will only unregister the standard watchdog interrupt +//! handler. To unregister the NMI watchdog handler, use IntUnregister() +//! to unregister the handler for the \b FAULT_NMI interrupt. +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogIntUnregister(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Disable the interrupt + IntDisable(INT_WDT); + + // + // Unregister the interrupt handler. + // + IntUnregister(INT_WDT); +} + +//***************************************************************************** +// +//! Gets the current watchdog timer interrupt status. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! This returns the interrupt status for the watchdog timer module. Either +//! the raw interrupt status or the status of interrupt that is allowed to +//! reflect to the processor can be returned. +//! +//! \return Returns the current interrupt status, where a 1 indicates that the +//! watchdog interrupt is active, and a 0 indicates that it is not active. +// +//***************************************************************************** +unsigned long +WatchdogIntStatus(unsigned long ulBase, tBoolean bMasked) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Return either the interrupt status or the raw interrupt status as + // requested. + // + if(bMasked) + { + return(HWREG(ulBase + WDT_O_MIS)); + } + else + { + return(HWREG(ulBase + WDT_O_RIS)); + } +} + +//***************************************************************************** +// +//! Clears the watchdog timer interrupt. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! The watchdog timer interrupt source is cleared, so that it no longer +//! asserts. +//! +//! \note Because there is a write buffer in the Cortex-M3 processor, it may +//! take several clock cycles before the interrupt source is actually cleared. +//! Therefore, it is recommended that the interrupt source be cleared early in +//! the interrupt handler (as opposed to the very last action) to avoid +//! returning from the interrupt handler before the interrupt source is +//! actually cleared. Failure to do so may result in the interrupt handler +//! being immediately reentered (because the interrupt controller still sees +//! the interrupt source asserted). +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogIntClear(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Clear the interrupt source. + // + HWREG(ulBase + WDT_O_ICR) = WDT_INT_TIMEOUT; +} + +//***************************************************************************** +// +//! Enables stalling of the watchdog timer during debug events. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This function allows the watchdog timer to stop counting when the processor +//! is stopped by the debugger. By doing so, the watchdog is prevented from +//! expiring (typically almost immediately from a human time perspective) and +//! resetting the system (if reset is enabled). The watchdog will instead +//! expired after the appropriate number of processor cycles have been executed +//! while debugging (or at the appropriate time after the processor has been +//! restarted). +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogStallEnable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Enable timer stalling. + // + HWREG(ulBase + WDT_O_TEST) |= WDT_TEST_STALL; +} + +//***************************************************************************** +// +//! Disables stalling of the watchdog timer during debug events. +//! +//! \param ulBase is the base address of the watchdog timer module. +//! +//! This function disables the debug mode stall of the watchdog timer. By +//! doing so, the watchdog timer continues to count regardless of the processor +//! debug state. +//! +//! \return None. +// +//***************************************************************************** +void +WatchdogStallDisable(unsigned long ulBase) +{ + // + // Check the arguments. + // + ASSERT((ulBase == WDT_BASE)); + + // + // Disable timer stalling. + // + HWREG(ulBase + WDT_O_TEST) &= ~(WDT_TEST_STALL); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/src/openmv/src/micropython/ports/cc3200/hal/wdt.h b/src/openmv/src/micropython/ports/cc3200/hal/wdt.h new file mode 100755 index 0000000..2e52db4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/hal/wdt.h @@ -0,0 +1,82 @@ +//***************************************************************************** +// +// wdt.h - Prototypes for the Watchdog Timer API +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __WATCHDOG_H__ +#define __WATCHDOG_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + + +//***************************************************************************** +// +// Prototypes for the APIs. +// +//***************************************************************************** +extern tBoolean WatchdogRunning(unsigned long ulBase); +extern void WatchdogEnable(unsigned long ulBase); +extern void WatchdogLock(unsigned long ulBase); +extern void WatchdogUnlock(unsigned long ulBase); +extern tBoolean WatchdogLockState(unsigned long ulBase); +extern void WatchdogReloadSet(unsigned long ulBase, unsigned long ulLoadVal); +extern unsigned long WatchdogReloadGet(unsigned long ulBase); +extern unsigned long WatchdogValueGet(unsigned long ulBase); +extern void WatchdogIntRegister(unsigned long ulBase, void(*pfnHandler)(void)); +extern void WatchdogIntUnregister(unsigned long ulBase); +extern unsigned long WatchdogIntStatus(unsigned long ulBase, tBoolean bMasked); +extern void WatchdogIntClear(unsigned long ulBase); +extern void WatchdogStallEnable(unsigned long ulBase); +extern void WatchdogStallDisable(unsigned long ulBase); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +#endif // __WATCHDOG_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/main.c b/src/openmv/src/micropython/ports/cc3200/main.c new file mode 100755 index 0000000..e2299e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/main.c @@ -0,0 +1,108 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "mptask.h" +#include "simplelink.h" +#include "pybwdt.h" +#include "debug.h" +#include "antenna.h" +#include "mperror.h" +#include "task.h" + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ + +// This is the static memory (TCB and stack) for the idle task +static StaticTask_t xIdleTaskTCB __attribute__ ((section (".rtos_heap"))); +static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +#ifdef DEBUG +OsiTaskHandle mpTaskHandle; +#endif + +// This is the FreeRTOS heap, defined here so we can put it in a special segment +uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +// This is the static memory (TCB and stack) for the main MicroPython task +StaticTask_t mpTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t mpTaskStack[MICROPY_TASK_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ + +__attribute__ ((section (".boot"))) +int main (void) { + + // Initialize the clocks and the interrupt system + HAL_SystemInit(); + +#if MICROPY_HW_ANTENNA_DIVERSITY + // configure the antenna selection pins + antenna_init0(); +#endif + + // Init the watchdog + pybwdt_init0(); + +#ifndef DEBUG + OsiTaskHandle mpTaskHandle; +#endif + mpTaskHandle = xTaskCreateStatic(TASK_MicroPython, "MicroPy", + MICROPY_TASK_STACK_LEN, NULL, MICROPY_TASK_PRIORITY, mpTaskStack, &mpTaskTCB); + ASSERT(mpTaskHandle != NULL); + + osi_start(); + + for ( ; ; ); +} + +// We need this when configSUPPORT_STATIC_ALLOCATION is enabled +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize ) { + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} diff --git a/src/openmv/src/micropython/ports/cc3200/misc/FreeRTOSHooks.c b/src/openmv/src/micropython/ports/cc3200/misc/FreeRTOSHooks.c new file mode 100755 index 0000000..c618279 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/FreeRTOSHooks.c @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "py/obj.h" +#include "inc/hw_memmap.h" +#include "pybuart.h" +#include "osi.h" +#include "mperror.h" + + +//***************************************************************************** +// +//! \brief Application defined idle task hook +//! +//! \param none +//! +//! \return none +//! +//***************************************************************************** +void vApplicationIdleHook (void) +{ + // signal that we are alive and kicking + mperror_heartbeat_signal(); + // gate the processor's clock to save power + __WFI(); +} + +//***************************************************************************** +// +//! \brief Application defined malloc failed hook +//! +//! \param none +//! +//! \return none +//! +//***************************************************************************** +void vApplicationMallocFailedHook (void) +{ +#ifdef DEBUG + // break into the debugger + __asm volatile ("bkpt #0 \n"); +#endif + + __fatal_error("FreeRTOS malloc failed!"); +} + +//***************************************************************************** +// +//! \brief Application defined stack overflow hook +//! +//! \param none +//! +//! \return none +//! +//***************************************************************************** +void vApplicationStackOverflowHook (OsiTaskHandle *pxTask, signed char *pcTaskName) +{ +#ifdef DEBUG + // Break into the debugger + __asm volatile ("bkpt #0 \n"); +#endif + + __fatal_error("Stack overflow!"); +} + +//***************************************************************************** +// +//! \brief Application defined tick hook +//! +//! \param none +//! +//! \return none +//! +//***************************************************************************** +void vApplicationTickHook (void) +{ + HAL_IncrementTick(); +} diff --git a/src/openmv/src/micropython/ports/cc3200/misc/antenna.c b/src/openmv/src/micropython/ports/cc3200/misc/antenna.c new file mode 100755 index 0000000..afeed85 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/antenna.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "mpconfigboard.h" +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "gpio.h" +#include "antenna.h" + + +#if MICROPY_HW_ANTENNA_DIVERSITY + +/****************************************************************************** +DEFINE CONSTANTS +******************************************************************************/ +#define REG_PAD_CONFIG_26 (0x4402E108) +#define REG_PAD_CONFIG_27 (0x4402E10C) + +/****************************************************************************** +DEFINE PRIVATE DATA +******************************************************************************/ +static antenna_type_t antenna_type_selected = ANTENNA_TYPE_INTERNAL; + +/****************************************************************************** +DEFINE PUBLIC FUNCTIONS +******************************************************************************/ +void antenna_init0(void) { + // enable the peripheral clock and set the gpio direction for + // both antenna 1 and antenna 2 pins + MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_GPIODirModeSet(GPIOA3_BASE, 0x0C, GPIO_DIR_MODE_OUT); + + // configure antenna 1 pin type and strength + HWREG(REG_PAD_CONFIG_26) = ((HWREG(REG_PAD_CONFIG_26) & ~(PAD_STRENGTH_MASK | PAD_TYPE_MASK)) | (0x00000020 | 0x00000000)); + // set the mode + HWREG(REG_PAD_CONFIG_26) = ((HWREG(REG_PAD_CONFIG_26) & ~PAD_MODE_MASK) | 0x00000000) & ~(3 << 10); + // set the direction + HWREG(REG_PAD_CONFIG_26) = ((HWREG(REG_PAD_CONFIG_26) & ~0xC00) | 0x00000800); + + // configure antenna 2 pin type and strength + HWREG(REG_PAD_CONFIG_27) = ((HWREG(REG_PAD_CONFIG_27) & ~(PAD_STRENGTH_MASK | PAD_TYPE_MASK)) | (0x00000020 | 0x00000000)); + // set the mode + HWREG(REG_PAD_CONFIG_27) = ((HWREG(REG_PAD_CONFIG_27) & ~PAD_MODE_MASK) | 0x00000000) & ~(3 << 10); + // set the direction + HWREG(REG_PAD_CONFIG_27) = ((HWREG(REG_PAD_CONFIG_27) & ~0xC00) | 0x00000800); + + // select the currently active antenna + antenna_select(antenna_type_selected); +} + +void antenna_select (antenna_type_t _antenna) { + if (_antenna == ANTENNA_TYPE_INTERNAL) { + MAP_GPIOPinWrite(GPIOA3_BASE, 0x0C, 0x04); + // also configure the pull-up and pull-down accordingly + HWREG(REG_PAD_CONFIG_26) = ((HWREG(REG_PAD_CONFIG_26) & ~PAD_TYPE_MASK)) | PIN_TYPE_STD_PU; + HWREG(REG_PAD_CONFIG_27) = ((HWREG(REG_PAD_CONFIG_27) & ~PAD_TYPE_MASK)) | PIN_TYPE_STD_PD; + } else { + MAP_GPIOPinWrite(GPIOA3_BASE, 0x0C, 0x08); + // also configure the pull-up and pull-down accordingly + HWREG(REG_PAD_CONFIG_26) = ((HWREG(REG_PAD_CONFIG_26) & ~PAD_TYPE_MASK)) | PIN_TYPE_STD_PD; + HWREG(REG_PAD_CONFIG_27) = ((HWREG(REG_PAD_CONFIG_27) & ~PAD_TYPE_MASK)) | PIN_TYPE_STD_PU; + } + antenna_type_selected = _antenna; +} + +#endif + diff --git a/src/openmv/src/micropython/ports/cc3200/misc/antenna.h b/src/openmv/src/micropython/ports/cc3200/misc/antenna.h new file mode 100755 index 0000000..c9d8454 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/antenna.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MISC_ANTENNA_H +#define MICROPY_INCLUDED_CC3200_MISC_ANTENNA_H + +typedef enum { + ANTENNA_TYPE_INTERNAL = 0, + ANTENNA_TYPE_EXTERNAL +} antenna_type_t; + +extern void antenna_init0 (void); +extern void antenna_select (antenna_type_t antenna_type); + +#endif // MICROPY_INCLUDED_CC3200_MISC_ANTENNA_H diff --git a/src/openmv/src/micropython/ports/cc3200/misc/help.c b/src/openmv/src/micropython/ports/cc3200/misc/help.c new file mode 100755 index 0000000..ea0c950 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/help.c @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char cc3200_help_text[] = "Welcome to MicroPython!\n" + "For online help please visit http://micropython.org/help/.\n" + "For further help on a specific object, type help(obj)\n"; diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mperror.c b/src/openmv/src/micropython/ports/cc3200/misc/mperror.c new file mode 100755 index 0000000..082d940 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mperror.c @@ -0,0 +1,210 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "hw_ints.h" +#include "hw_types.h" +#include "hw_gpio.h" +#include "hw_memmap.h" +#include "hw_gprcm.h" +#include "hw_common_reg.h" +#include "pin.h" +#include "gpio.h" +#ifndef BOOTLOADER +#include "pybpin.h" +#include "pins.h" +#endif +#include "rom_map.h" +#include "prcm.h" +#include "pybuart.h" +#include "utils.h" +#include "mperror.h" + + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define MPERROR_TOOGLE_MS (50) +#define MPERROR_SIGNAL_ERROR_MS (1200) +#define MPERROR_HEARTBEAT_ON_MS (80) +#define MPERROR_HEARTBEAT_OFF_MS (3920) + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +struct mperror_heart_beat { + uint32_t off_time; + uint32_t on_time; + bool beating; + bool enabled; + bool do_disable; +} mperror_heart_beat = {.off_time = 0, .on_time = 0, .beating = false, .enabled = false, .do_disable = false}; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void mperror_init0 (void) { +#ifdef BOOTLOADER + // enable the system led and the safe boot pin peripheral clocks + MAP_PRCMPeripheralClkEnable(MICROPY_SYS_LED_PRCM, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralClkEnable(MICROPY_SAFE_BOOT_PRCM, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // configure the safe boot pin + MAP_PinTypeGPIO(MICROPY_SAFE_BOOT_PIN_NUM, PIN_MODE_0, false); + MAP_PinConfigSet(MICROPY_SAFE_BOOT_PIN_NUM, PIN_STRENGTH_4MA, PIN_TYPE_STD_PD); + MAP_GPIODirModeSet(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN, GPIO_DIR_MODE_IN); + // configure the bld + MAP_PinTypeGPIO(MICROPY_SYS_LED_PIN_NUM, PIN_MODE_0, false); + MAP_PinConfigSet(MICROPY_SYS_LED_PIN_NUM, PIN_STRENGTH_6MA, PIN_TYPE_STD); + MAP_GPIODirModeSet(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, GPIO_DIR_MODE_OUT); +#else + // configure the system led + pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, 0, PIN_STRENGTH_6MA); +#endif + mperror_heart_beat.enabled = true; + mperror_heartbeat_switch_off(); +} + +void mperror_bootloader_check_reset_cause (void) { + // if we are recovering from a WDT reset, trigger + // a hibernate cycle for a clean boot + if (MAP_PRCMSysResetCauseGet() == PRCM_WDT_RESET) { + HWREG(0x400F70B8) = 1; + UtilsDelay(800000/5); + HWREG(0x400F70B0) = 1; + UtilsDelay(800000/5); + + HWREG(0x4402E16C) |= 0x2; + UtilsDelay(800); + HWREG(0x4402F024) &= 0xF7FFFFFF; + + // since the reset cause will be changed, we must store the right reason + // so that the application knows it when booting for the next time + PRCMSetSpecialBit(PRCM_WDT_RESET_BIT); + + MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); + // set the sleep interval to 10ms + MAP_PRCMHibernateIntervalSet(330); + MAP_PRCMHibernateEnter(); + } +} + +void mperror_deinit_sfe_pin (void) { + // disable the pull-down + MAP_PinConfigSet(MICROPY_SAFE_BOOT_PIN_NUM, PIN_STRENGTH_4MA, PIN_TYPE_STD); +} + +void mperror_signal_error (void) { + uint32_t count = 0; + while ((MPERROR_TOOGLE_MS * count++) < MPERROR_SIGNAL_ERROR_MS) { + // toogle the led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN)); + UtilsDelay(UTILS_DELAY_US_TO_COUNT(MPERROR_TOOGLE_MS * 1000)); + } +} + +void mperror_heartbeat_switch_off (void) { + if (mperror_heart_beat.enabled) { + mperror_heart_beat.on_time = 0; + mperror_heart_beat.off_time = 0; + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0); + } +} + +void mperror_heartbeat_signal (void) { + if (mperror_heart_beat.do_disable) { + mperror_heart_beat.do_disable = false; + } else if (mperror_heart_beat.enabled) { + if (!mperror_heart_beat.beating) { + if ((mperror_heart_beat.on_time = mp_hal_ticks_ms()) - mperror_heart_beat.off_time > MPERROR_HEARTBEAT_OFF_MS) { + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN); + mperror_heart_beat.beating = true; + } + } else { + if ((mperror_heart_beat.off_time = mp_hal_ticks_ms()) - mperror_heart_beat.on_time > MPERROR_HEARTBEAT_ON_MS) { + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0); + mperror_heart_beat.beating = false; + } + } + } +} + +void NORETURN __fatal_error(const char *msg) { +#ifdef DEBUG + if (msg != NULL) { + // wait for 20ms + UtilsDelay(UTILS_DELAY_US_TO_COUNT(20000)); + mp_hal_stdout_tx_str("\r\nFATAL ERROR:"); + mp_hal_stdout_tx_str(msg); + mp_hal_stdout_tx_str("\r\n"); + } +#endif + // signal the crash with the system led + MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN); + for ( ;; ) {__WFI();} +} + +void __assert_func(const char *file, int line, const char *func, const char *expr) { + (void) func; + printf("Assertion failed: %s, file %s, line %d\n", expr, file, line); + __fatal_error(NULL); +} + +void nlr_jump_fail(void *val) { +#ifdef DEBUG + char msg[64]; + snprintf(msg, sizeof(msg), "uncaught exception %p\n", val); + __fatal_error(msg); +#else + __fatal_error(NULL); +#endif +} + +void mperror_enable_heartbeat (bool enable) { + if (enable) { + #ifndef BOOTLOADER + // configure the led again + pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, 0, PIN_STRENGTH_6MA); + #endif + mperror_heart_beat.enabled = true; + mperror_heart_beat.do_disable = false; + mperror_heartbeat_switch_off(); + } else { + mperror_heart_beat.do_disable = true; + mperror_heart_beat.enabled = false; + } +} + +bool mperror_is_heartbeat_enabled (void) { + return mperror_heart_beat.enabled; +} diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mperror.h b/src/openmv/src/micropython/ports/cc3200/misc/mperror.h new file mode 100755 index 0000000..1c3eb62 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mperror.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MISC_MPERROR_H +#define MICROPY_INCLUDED_CC3200_MISC_MPERROR_H + +extern void NORETURN __fatal_error(const char *msg); + +void mperror_init0 (void); +void mperror_bootloader_check_reset_cause (void); +void mperror_deinit_sfe_pin (void); +void mperror_signal_error (void); +void mperror_heartbeat_switch_off (void); +void mperror_heartbeat_signal (void); +void mperror_enable_heartbeat (bool enable); +bool mperror_is_heartbeat_enabled (void); + +#endif // MICROPY_INCLUDED_CC3200_MISC_MPERROR_H diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mpexception.c b/src/openmv/src/micropython/ports/cc3200/misc/mpexception.c new file mode 100755 index 0000000..72d4a15 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mpexception.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "mpexception.h" + + +/****************************************************************************** +DECLARE EXPORTED DATA + ******************************************************************************/ +const char mpexception_value_invalid_arguments[] = "invalid argument(s) value"; +const char mpexception_num_type_invalid_arguments[] = "invalid argument(s) num/type"; +const char mpexception_uncaught[] = "uncaught exception"; diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mpexception.h b/src/openmv/src/micropython/ports/cc3200/misc/mpexception.h new file mode 100755 index 0000000..e84a1ed --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mpexception.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H +#define MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H + +extern const char mpexception_value_invalid_arguments[]; +extern const char mpexception_num_type_invalid_arguments[]; +extern const char mpexception_uncaught[]; + +#endif // MICROPY_INCLUDED_CC3200_MISC_MPEXCEPTION_H diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mpirq.c b/src/openmv/src/micropython/ports/cc3200/misc/mpirq.c new file mode 100755 index 0000000..d54e746 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mpirq.c @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "inc/hw_types.h" +#include "interrupt.h" +#include "pybsleep.h" +#include "mpexception.h" +#include "mperror.h" +#include "mpirq.h" + + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +const mp_arg_t mp_irq_init_args[] = { + { MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority + { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +}; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4, + INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 }; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void mp_irq_init0 (void) { + // initialize the callback objects list + mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0); +} + +mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) { + mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t); + self->base.type = &mp_irq_type; + self->handler = handler; + self->parent = parent; + self->methods = (mp_irq_methods_t *)methods; + self->isenabled = true; + // remove it in case it was already registered + mp_irq_remove(parent); + mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self); + return self; +} + +mp_irq_obj_t *mp_irq_find (mp_obj_t parent) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); + if (callback_obj->parent == parent) { + return callback_obj; + } + } + return NULL; +} + +void mp_irq_wake_all (void) { + // re-enable all active callback objects one by one + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); + if (callback_obj->isenabled) { + callback_obj->methods->enable(callback_obj->parent); + } + } +} + +void mp_irq_disable_all (void) { + // re-enable all active callback objects one by one + for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) { + mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i])); + callback_obj->methods->disable(callback_obj->parent); + } +} + +void mp_irq_remove (const mp_obj_t parent) { + mp_irq_obj_t *callback_obj; + if ((callback_obj = mp_irq_find(parent))) { + mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj); + } +} + +uint mp_irq_translate_priority (uint priority) { + if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + return mp_irq_priorities[priority - 1]; +} + +void mp_irq_handler (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; + if (self && self->handler != mp_const_none) { + // when executing code within a handler we must lock the GC to prevent + // any memory allocations. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(self->handler, self->parent); + nlr_pop(); + } + else { + // uncaught exception; disable the callback so that it doesn't run again + self->methods->disable (self->parent); + self->handler = mp_const_none; + // signal the error using the heart beat led and + // by printing a message + printf("Uncaught exception in callback handler\n"); + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + mperror_signal_error(); + } + gc_unlock(); + } +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC mp_obj_t mp_irq_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_irq_obj_t *self = pos_args[0]; + // this is a bit of a hack, but it let us reuse the callback_create method from our parent + ((mp_obj_t *)pos_args)[0] = self->parent; + self->methods->init (n_args, pos_args, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init); + +STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; + self->methods->enable(self->parent); + self->isenabled = true; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable); + +STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; + self->methods->disable(self->parent); + self->isenabled = false; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable); + +STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) { + mp_irq_obj_t *self = self_in; + return mp_obj_new_int(self->methods->flags(self->parent)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags); + +STATIC mp_obj_t mp_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_irq_handler (self_in); + return mp_const_none; +} + +STATIC const mp_rom_map_elem_t mp_irq_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mp_irq_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&mp_irq_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&mp_irq_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_flags), MP_ROM_PTR(&mp_irq_flags_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table); + +const mp_obj_type_t mp_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_irq, + .call = mp_irq_call, + .locals_dict = (mp_obj_t)&mp_irq_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/misc/mpirq.h b/src/openmv/src/micropython/ports/cc3200/misc/mpirq.h new file mode 100755 index 0000000..223a34c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/misc/mpirq.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H +#define MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define mp_irq_INIT_NUM_ARGS 4 + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef mp_obj_t (*mp_irq_init_t) (size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +typedef void (*mp_irq_void_method_t) (mp_obj_t self); +typedef int (*mp_irq_int_method_t) (mp_obj_t self); + +typedef struct { + mp_irq_init_t init; + mp_irq_void_method_t enable; + mp_irq_void_method_t disable; + mp_irq_int_method_t flags; +} mp_irq_methods_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t parent; + mp_obj_t handler; + mp_irq_methods_t *methods; + bool isenabled; +} mp_irq_obj_t; + +/****************************************************************************** + DECLARE EXPORTED DATA + ******************************************************************************/ +extern const mp_arg_t mp_irq_init_args[]; +extern const mp_obj_type_t mp_irq_type; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void mp_irq_init0 (void); +mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods); +mp_irq_obj_t *mp_irq_find (mp_obj_t parent); +void mp_irq_wake_all (void); +void mp_irq_disable_all (void); +void mp_irq_remove (const mp_obj_t parent); +void mp_irq_handler (mp_obj_t self_in); +uint mp_irq_translate_priority (uint priority); + +#endif // MICROPY_INCLUDED_CC3200_MISC_MPIRQ_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modmachine.c b/src/openmv/src/micropython/ports/cc3200/mods/modmachine.c new file mode 100755 index 0000000..6051497 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modmachine.c @@ -0,0 +1,212 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "irq.h" +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_uart.h" +#include "rom_map.h" +#include "prcm.h" +#include "pybuart.h" +#include "pybpin.h" +#include "pybrtc.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "moduos.h" +#include "FreeRTOS.h" +#include "portable.h" +#include "task.h" +#include "mpexception.h" +#include "random.h" +#include "pybadc.h" +#include "pybi2c.h" +#include "pybsd.h" +#include "pybwdt.h" +#include "pybsleep.h" +#include "pybspi.h" +#include "pybtimer.h" +#include "utils.h" +#include "gccollect.h" + + +#ifdef DEBUG +extern OsiTaskHandle mpTaskHandle; +extern OsiTaskHandle svTaskHandle; +extern OsiTaskHandle xSimpleLinkSpawnTaskHndl; +#endif + + +/// \module machine - functions related to the SoC +/// + +/******************************************************************************/ +// MicroPython bindings; + +STATIC mp_obj_t machine_reset(void) { + // disable wlan + wlan_stop(SL_STOP_TIMEOUT_LONG); + // reset the cpu and it's peripherals + MAP_PRCMMCUReset(true); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +#ifdef DEBUG +STATIC mp_obj_t machine_info(uint n_args, const mp_obj_t *args) { + // FreeRTOS info + { + printf("---------------------------------------------\n"); + printf("FreeRTOS\n"); + printf("---------------------------------------------\n"); + printf("Total heap: %u\n", configTOTAL_HEAP_SIZE); + printf("Free heap: %u\n", xPortGetFreeHeapSize()); + printf("MpTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)mpTaskHandle)); + printf("ServersTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark((TaskHandle_t)svTaskHandle)); + printf("SlTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xSimpleLinkSpawnTaskHndl)); + printf("IdleTask min free stack: %u\n", (unsigned int)uxTaskGetStackHighWaterMark(xTaskGetIdleTaskHandle())); + + uint32_t *pstack = (uint32_t *)&_stack; + while (*pstack == 0x55555555) { + pstack++; + } + printf("MAIN min free stack: %u\n", pstack - ((uint32_t *)&_stack)); + printf("---------------------------------------------\n"); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info); +#endif + +STATIC mp_obj_t machine_freq(void) { + return mp_obj_new_int(HAL_FCPU_HZ); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); + +STATIC mp_obj_t machine_unique_id(void) { + uint8_t mac[SL_BSSID_LENGTH]; + wlan_get_mac (mac); + return mp_obj_new_bytes(mac, SL_BSSID_LENGTH); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_main(mp_obj_t main) { + if (MP_OBJ_IS_STR(main)) { + MP_STATE_PORT(machine_config_main) = main; + } else { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_main_obj, machine_main); + +STATIC mp_obj_t machine_idle(void) { + __WFI(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_sleep (void) { + pyb_sleep_sleep(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); + +STATIC mp_obj_t machine_deepsleep (void) { + pyb_sleep_deepsleep(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause (void) { + return mp_obj_new_int(pyb_sleep_get_reset_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason (void) { + return mp_obj_new_int(pyb_sleep_get_wake_reason()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, +#ifdef DEBUG + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&machine_main_obj) }, + { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&machine_rng_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) }, + { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sd_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IDLE), MP_ROM_INT(PYB_PWR_MODE_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(PYB_PWR_MODE_LPDS) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(PYB_PWR_MODE_HIBERNATE) }, + { MP_ROM_QSTR(MP_QSTR_POWER_ON), MP_ROM_INT(PYB_SLP_PWRON_RESET) }, // legacy constant + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_SLP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_SLP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_SLP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(PYB_SLP_HIB_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_SLP_SOFT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WLAN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_WLAN) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_GPIO) }, + { MP_ROM_QSTR(MP_QSTR_RTC_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_RTC) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t machine_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.c b/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.c new file mode 100755 index 0000000..37dffe7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "modnetwork.h" +#include "mpexception.h" +#include "serverstask.h" +#include "simplelink.h" + + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct { + mp_obj_base_t base; +} network_server_obj_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC network_server_obj_t network_server_obj; +STATIC const mp_obj_type_t network_server_type; + +/// \module network - network configuration +/// +/// This module provides network drivers and server configuration. + +void mod_network_init0(void) { +} + +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) +STATIC mp_obj_t network_server_init_helper(mp_obj_t self, const mp_arg_val_t *args) { + const char *user = SERVERS_DEF_USER; + const char *pass = SERVERS_DEF_PASS; + if (args[0].u_obj != MP_OBJ_NULL) { + mp_obj_t *login; + mp_obj_get_array_fixed_n(args[0].u_obj, 2, &login); + user = mp_obj_str_get_str(login[0]); + pass = mp_obj_str_get_str(login[1]); + } + + uint32_t timeout = SERVERS_DEF_TIMEOUT_MS / 1000; + if (args[1].u_obj != MP_OBJ_NULL) { + timeout = mp_obj_get_int(args[1].u_obj); + } + + // configure the new login + servers_set_login ((char *)user, (char *)pass); + + // configure the timeout + servers_set_timeout(timeout * 1000); + + // start the servers + servers_start(); + + return mp_const_none; +} + +STATIC const mp_arg_t network_server_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_login, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), network_server_args, args); + + // check the server id + if (args[0].u_obj != MP_OBJ_NULL) { + if (mp_obj_get_int(args[0].u_obj) != 0) { + mp_raise_OSError(MP_ENODEV); + } + } + + // setup the object and initialize it + network_server_obj_t *self = &network_server_obj; + self->base.type = &network_server_type; + network_server_init_helper(self, &args[1]); + + return (mp_obj_t)self; +} + +STATIC mp_obj_t network_server_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &network_server_args[1], args); + return network_server_init_helper(pos_args[0], args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_server_init_obj, 1, network_server_init); + +// timeout value given in seconds +STATIC mp_obj_t network_server_timeout(size_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + uint32_t timeout = mp_obj_get_int(args[1]); + servers_set_timeout(timeout * 1000); + return mp_const_none; + } else { + // get + return mp_obj_new_int(servers_get_timeout() / 1000); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 1, 2, network_server_timeout); + +STATIC mp_obj_t network_server_running(mp_obj_t self_in) { + // get + return mp_obj_new_bool(servers_are_enabled()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_running_obj, network_server_running); + +STATIC mp_obj_t network_server_deinit(mp_obj_t self_in) { + // simply stop the servers + servers_stop(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_deinit_obj, network_server_deinit); +#endif + +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_wlan) }, + +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + { MP_ROM_QSTR(MP_QSTR_Server), MP_ROM_PTR(&network_server_type) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; + +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) +STATIC const mp_rom_map_elem_t network_server_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&network_server_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&network_server_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&network_server_timeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_isrunning), MP_ROM_PTR(&network_server_running_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_dict_table); + +STATIC const mp_obj_type_t network_server_type = { + { &mp_type_type }, + .name = MP_QSTR_Server, + .make_new = network_server_make_new, + .locals_dict = (mp_obj_t)&network_server_locals_dict, +}; +#endif diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.h b/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.h new file mode 100755 index 0000000..6ec90a2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modnetwork.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_MODNETWORK_H +#define MICROPY_INCLUDED_CC3200_MODS_MODNETWORK_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define MOD_NETWORK_IPV4ADDR_BUF_SIZE (4) + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct _mod_network_nic_type_t { + mp_obj_type_t base; +} mod_network_nic_type_t; + +typedef struct _mod_network_socket_base_t { + union { + struct { + // this order is important so that fileno gets > 0 once + // the socket descriptor is assigned after being created. + uint8_t domain; + int8_t fileno; + uint8_t type; + uint8_t proto; + } u_param; + int16_t sd; + }; + uint32_t timeout_ms; // 0 for no timeout + bool cert_req; +} mod_network_socket_base_t; + +typedef struct _mod_network_socket_obj_t { + mp_obj_base_t base; + mod_network_socket_base_t sock_base; +} mod_network_socket_obj_t; + +/****************************************************************************** + EXPORTED DATA + ******************************************************************************/ +extern const mod_network_nic_type_t mod_network_nic_type_wlan; + +/****************************************************************************** + DECLARE FUNCTIONS + ******************************************************************************/ +void mod_network_init0(void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_MODNETWORK_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.c b/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.c new file mode 100755 index 0000000..6b020ab --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/binary.h" +#include "extmod/modubinascii.h" +#include "modubinascii.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_dthe.h" +#include "hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "crc.h" +#include "cryptohash.h" +#include "mpexception.h" + + +/******************************************************************************/ +// MicroPython bindings + +STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubinascii) }, + { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) }, + { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) }, + { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) }, + { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table); + +const mp_obj_module_t mp_module_ubinascii = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_binascii_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.h b/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.h new file mode 100755 index 0000000..eb9fc4f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modubinascii.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUBINASCII_H +#define MICROPY_INCLUDED_CC3200_MODS_MODUBINASCII_H + + +#endif // MICROPY_INCLUDED_CC3200_MODS_MODUBINASCII_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/moduhashlib.c b/src/openmv/src/micropython/ports/cc3200/mods/moduhashlib.c new file mode 100755 index 0000000..96f5149 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/moduhashlib.c @@ -0,0 +1,208 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpconfig.h" +#include MICROPY_HAL_H +#include "py/runtime.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_shamd5.h" +#include "inc/hw_dthe.h" +#include "hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "shamd5.h" +#include "cryptohash.h" +#include "mpexception.h" + + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef struct _mp_obj_hash_t { + mp_obj_base_t base; + uint8_t *buffer; + uint32_t b_size; + uint32_t c_size; + uint8_t algo; + uint8_t h_size; + bool fixedlen; + bool digested; + uint8_t hash[32]; +} mp_obj_hash_t; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest); +STATIC mp_obj_t hash_read (mp_obj_t self_in); + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) { + mp_obj_hash_t *self = self_in; + mp_buffer_info_t bufinfo; + + if (data) { + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + } + + if (digest) { + CRYPTOHASH_SHAMD5Start (self->algo, self->b_size); + } + + if (self->c_size < self->b_size || !data || !self->fixedlen) { + if (digest || self->fixedlen) { + // no data means we want to process our internal buffer + CRYPTOHASH_SHAMD5Update (data ? bufinfo.buf : self->buffer, data ? bufinfo.len : self->b_size); + self->c_size += data ? bufinfo.len : 0; + } else { + self->buffer = m_renew(byte, self->buffer, self->b_size, self->b_size + bufinfo.len); + mp_seq_copy((byte*)self->buffer + self->b_size, bufinfo.buf, bufinfo.len, byte); + self->b_size += bufinfo.len; + self->digested = false; + } + } else { + mp_raise_OSError(MP_EPERM); + } +} + +STATIC mp_obj_t hash_read (mp_obj_t self_in) { + mp_obj_hash_t *self = self_in; + + if (!self->fixedlen) { + if (!self->digested) { + hash_update_internal(self, MP_OBJ_NULL, true); + } + } else if (self->c_size < self->b_size) { + // it's a fixed len block which is still incomplete + mp_raise_OSError(MP_EPERM); + } + + if (!self->digested) { + CRYPTOHASH_SHAMD5Read ((uint8_t *)self->hash); + self->digested = true; + } + return mp_obj_new_bytes(self->hash, self->h_size); +} + +/******************************************************************************/ +// MicroPython bindings + +/// \classmethod \constructor([data[, block_size]]) +/// initial data must be given if block_size wants to be passed +STATIC mp_obj_t hash_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 2, false); + mp_obj_hash_t *self = m_new0(mp_obj_hash_t, 1); + self->base.type = type_in; + if (self->base.type->name == MP_QSTR_sha1) { + self->algo = SHAMD5_ALGO_SHA1; + self->h_size = 20; + } else /* if (self->base.type->name == MP_QSTR_sha256) */ { + self->algo = SHAMD5_ALGO_SHA256; + self->h_size = 32; + } /* else { + self->algo = SHAMD5_ALGO_MD5; + self->h_size = 32; + } */ + + if (n_args) { + // CPython extension to avoid buffering the data before digesting it + // Note: care must be taken to provide all intermediate blocks as multiple + // of four bytes, otherwise the resulting hash will be incorrect. + // the final block can be of any length + if (n_args > 1) { + // block size given, we will feed the data directly into the hash engine + self->fixedlen = true; + self->b_size = mp_obj_get_int(args[1]); + hash_update_internal(self, args[0], true); + } else { + hash_update_internal(self, args[0], false); + } + } + return self; +} + +STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = self_in; + hash_update_internal(self, arg, false); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update); + +STATIC mp_obj_t hash_digest(mp_obj_t self_in) { + return hash_read(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest); + +STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table); + +//STATIC const mp_obj_type_t md5_type = { +// { &mp_type_type }, +// .name = MP_QSTR_md5, +// .make_new = hash_make_new, +// .locals_dict = (mp_obj_t)&hash_locals_dict, +//}; + +STATIC const mp_obj_type_t sha1_type = { + { &mp_type_type }, + .name = MP_QSTR_sha1, + .make_new = hash_make_new, + .locals_dict = (mp_obj_t)&hash_locals_dict, +}; + +STATIC const mp_obj_type_t sha256_type = { + { &mp_type_type }, + .name = MP_QSTR_sha256, + .make_new = hash_make_new, + .locals_dict = (mp_obj_t)&hash_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) }, + //{ MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&md5_type) }, + { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) }, + { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table); + +const mp_obj_module_t mp_module_uhashlib = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/moduos.c b/src/openmv/src/micropython/ports/cc3200/mods/moduos.c new file mode 100755 index 0000000..7d99c8e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/moduos.c @@ -0,0 +1,182 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "genhdr/mpversion.h" +#include "moduos.h" +#include "sflash_diskio.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "random.h" +#include "mpexception.h" +#include "version.h" +#include "pybsd.h" +#include "pybuart.h" + +/// \module os - basic "operating system" services +/// +/// The `os` module contains functions for filesystem access and `urandom`. +/// +/// The filesystem has `/` as the root directory, and the available physical +/// drives are accessible from here. They are currently: +/// +/// /flash -- the serial flash filesystem +/// +/// On boot up, the current directory is `/flash`. + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC os_term_dup_obj_t os_term_dup_obj; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ + +void osmount_unmount_all (void) { + //TODO + /* + for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) { + os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i])); + unmount(mount_obj); + } + */ +} + +/******************************************************************************/ +// MicroPython bindings +// + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, WIPY_SW_VERSION_NUMBER); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_sync(void) { + sflash_disk_flush(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = rng_get(); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) { + return mp_const_none; + } else { + return MP_STATE_PORT(os_term_dup_obj)->stream_o; + } + } else { + mp_obj_t stream_o = args[0]; + if (stream_o == mp_const_none) { + MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL; + } else { + if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) { + // must be a stream-like object providing at least read and write methods + mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read); + mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write); + } + os_term_dup_obj.stream_o = stream_o; + MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj; + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm); + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + + { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&os_sync_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + + // MicroPython additions + // removed: mkfs + // renamed: unmount -> umount + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/moduos.h b/src/openmv/src/micropython/ports/cc3200/mods/moduos.h new file mode 100755 index 0000000..f183715 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/moduos.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUOS_H +#define MICROPY_INCLUDED_CC3200_MODS_MODUOS_H + +#include "py/obj.h" + +/****************************************************************************** + DEFINE PUBLIC TYPES + ******************************************************************************/ + +typedef struct _os_term_dup_obj_t { + mp_obj_t stream_o; + mp_obj_t read[3]; + mp_obj_t write[3]; +} os_term_dup_obj_t; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void osmount_unmount_all (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_MODUOS_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modusocket.c b/src/openmv/src/micropython/ports/cc3200/mods/modusocket.c new file mode 100755 index 0000000..286b1fb --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modusocket.c @@ -0,0 +1,819 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "simplelink.h" +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" +#include "modusocket.h" +#include "mpexception.h" + +/******************************************************************************/ +// The following set of macros and functions provide a glue between the CC3100 +// simplelink layer and the functions/methods provided by the usocket module. +// They were historically in a separate file because usocket was designed to +// work with multiple NICs, and the wlan_XXX functions just provided one +// particular NIC implementation (that of the CC3100). But the CC3200 port only +// supports a single NIC (being the CC3100) so it's unnecessary and inefficient +// to provide an intermediate wrapper layer. Hence the wlan_XXX functions +// are provided below as static functions so they can be inlined directly by +// the corresponding usocket calls. + +#define WLAN_MAX_RX_SIZE 16000 +#define WLAN_MAX_TX_SIZE 1476 + +#define MAKE_SOCKADDR(addr, ip, port) SlSockAddr_t addr; \ + addr.sa_family = SL_AF_INET; \ + addr.sa_data[0] = port >> 8; \ + addr.sa_data[1] = port; \ + addr.sa_data[2] = ip[3]; \ + addr.sa_data[3] = ip[2]; \ + addr.sa_data[4] = ip[1]; \ + addr.sa_data[5] = ip[0]; + +#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \ + ip[0] = addr.sa_data[5]; \ + ip[1] = addr.sa_data[4]; \ + ip[2] = addr.sa_data[3]; \ + ip[3] = addr.sa_data[2]; + +#define SOCKET_TIMEOUT_QUANTA_MS (20) + +STATIC int convert_sl_errno(int sl_errno) { + return -sl_errno; +} + +// This function is left as non-static so it's not inlined. +int check_timedout(mod_network_socket_obj_t *s, int ret, uint32_t *timeout_ms, int *_errno) { + if (*timeout_ms == 0 || ret != SL_EAGAIN) { + if (s->sock_base.timeout_ms > 0 && ret == SL_EAGAIN) { + *_errno = MP_ETIMEDOUT; + } else { + *_errno = convert_sl_errno(ret); + } + return -1; + } + mp_hal_delay_ms(SOCKET_TIMEOUT_QUANTA_MS); + if (*timeout_ms < SOCKET_TIMEOUT_QUANTA_MS) { + *timeout_ms = 0; + } else { + *timeout_ms -= SOCKET_TIMEOUT_QUANTA_MS; + } + return 0; +} + +STATIC int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) { + uint32_t ip; + int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family); + out_ip[0] = ip; + out_ip[1] = ip >> 8; + out_ip[2] = ip >> 16; + out_ip[3] = ip >> 24; + return result; +} + +STATIC int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) { + int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto); + if (sd < 0) { + *_errno = sd; + return -1; + } + s->sock_base.sd = sd; + return 0; +} + +STATIC void wlan_socket_close(mod_network_socket_obj_t *s) { + // this is to prevent the finalizer to close a socket that failed when being created + if (s->sock_base.sd >= 0) { + modusocket_socket_delete(s->sock_base.sd); + sl_Close(s->sock_base.sd); + s->sock_base.sd = -1; + } +} + +STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr)); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) { + int ret = sl_Listen(s->sock_base.sd, backlog); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) { + // accept incoming connection + int16_t sd; + SlSockAddr_t addr; + SlSocklen_t addr_len = sizeof(addr); + + uint32_t timeout_ms = s->sock_base.timeout_ms; + for (;;) { + sd = sl_Accept(s->sock_base.sd, &addr, &addr_len); + if (sd >= 0) { + // save the socket descriptor + s2->sock_base.sd = sd; + // return ip and port + UNPACK_SOCKADDR(addr, ip, *port); + return 0; + } + if (check_timedout(s, sd, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + uint32_t timeout_ms = s->sock_base.timeout_ms; + + // For a non-blocking connect the CC3100 will return SL_EALREADY while the + // connection is in progress. + + for (;;) { + int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr)); + if (ret == 0) { + return 0; + } + + // Check if we are in non-blocking mode and the connection is in progress + if (s->sock_base.timeout_ms == 0 && ret == SL_EALREADY) { + // To match BSD we return EINPROGRESS here + *_errno = MP_EINPROGRESS; + return -1; + } + + // We are in blocking mode, so if the connection isn't in progress then error out + if (ret != SL_EALREADY) { + *_errno = convert_sl_errno(ret); + return -1; + } + + if (check_timedout(s, SL_EAGAIN, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) { + if (len == 0) { + return 0; + } + uint32_t timeout_ms = s->sock_base.timeout_ms; + for (;;) { + int ret = sl_Send(s->sock_base.sd, (const void *)buf, len, 0); + if (ret > 0) { + return ret; + } + if (check_timedout(s, ret, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) { + uint32_t timeout_ms = s->sock_base.timeout_ms; + for (;;) { + int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0); + if (ret >= 0) { + return ret; + } + if (check_timedout(s, ret, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + uint32_t timeout_ms = s->sock_base.timeout_ms; + for (;;) { + int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr)); + if (ret >= 0) { + return ret; + } + if (check_timedout(s, ret, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + SlSockAddr_t addr; + SlSocklen_t addr_len = sizeof(addr); + uint32_t timeout_ms = s->sock_base.timeout_ms; + for (;;) { + int ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len); + if (ret >= 0) { + UNPACK_SOCKADDR(addr, ip, *port); + return ret; + } + if (check_timedout(s, ret, &timeout_ms, _errno)) { + return -1; + } + } +} + +STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen); + if (ret < 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) { + SlSockNonblocking_t option; + if (timeout_s == 0 || timeout_s == -1) { + if (timeout_s == 0) { + // set non-blocking mode + option.NonblockingEnabled = 1; + } else { + // set blocking mode + option.NonblockingEnabled = 0; + } + timeout_s = 0; + } else { + // synthesize timeout via non-blocking behaviour with a loop + option.NonblockingEnabled = 1; + } + + int ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option)); + if (ret != 0) { + *_errno = convert_sl_errno(ret); + return -1; + } + + s->sock_base.timeout_ms = timeout_s * 1000; + return 0; +} + +STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) { + mp_int_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + int32_t sd = s->sock_base.sd; + + // init fds + SlFdSet_t rfds, wfds, xfds; + SL_FD_ZERO(&rfds); + SL_FD_ZERO(&wfds); + SL_FD_ZERO(&xfds); + + // set fds if needed + if (flags & MP_STREAM_POLL_RD) { + SL_FD_SET(sd, &rfds); + } + if (flags & MP_STREAM_POLL_WR) { + SL_FD_SET(sd, &wfds); + } + if (flags & MP_STREAM_POLL_HUP) { + SL_FD_SET(sd, &xfds); + } + + // call simplelink's select with minimum timeout + SlTimeval_t tv; + tv.tv_sec = 0; + tv.tv_usec = 1; + int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv); + + // check for errors + if (nfds == -1) { + *_errno = nfds; + return -1; + } + + // check return of select + if (SL_FD_ISSET(sd, &rfds)) { + ret |= MP_STREAM_POLL_RD; + } + if (SL_FD_ISSET(sd, &wfds)) { + ret |= MP_STREAM_POLL_WR; + } + if (SL_FD_ISSET(sd, &xfds)) { + ret |= MP_STREAM_POLL_HUP; + } + } else if (request == MP_STREAM_CLOSE) { + wlan_socket_close(s); + ret = 0; + } else { + *_errno = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +/****************************************************************************** + DEFINE PRIVATE CONSTANTS + ******************************************************************************/ +#define MOD_NETWORK_MAX_SOCKETS 10 + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef struct { + int16_t sd; + bool user; +} modusocket_sock_t; + +/****************************************************************************** + DEFINE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_obj_type_t socket_type; +STATIC OsiLockObj_t modusocket_LockObj; +STATIC modusocket_sock_t modusocket_sockets[MOD_NETWORK_MAX_SOCKETS] = {{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, + {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}}; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +__attribute__ ((section (".boot"))) +void modusocket_pre_init (void) { + // create the wlan lock + ASSERT(OSI_OK == sl_LockObjCreate(&modusocket_LockObj, "SockLock")); + sl_LockObjUnlock (&modusocket_LockObj); +} + +void modusocket_socket_add (int16_t sd, bool user) { + sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER); + for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) { + if (modusocket_sockets[i].sd < 0) { + modusocket_sockets[i].sd = sd; + modusocket_sockets[i].user = user; + break; + } + } + sl_LockObjUnlock (&modusocket_LockObj); +} + +void modusocket_socket_delete (int16_t sd) { + sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER); + for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) { + if (modusocket_sockets[i].sd == sd) { + modusocket_sockets[i].sd = -1; + break; + } + } + sl_LockObjUnlock (&modusocket_LockObj); +} + +void modusocket_enter_sleep (void) { + SlFdSet_t socketset; + int16_t maxfd = 0; + + for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) { + int16_t sd; + if ((sd = modusocket_sockets[i].sd) >= 0) { + SL_FD_SET(sd, &socketset); + maxfd = (maxfd > sd) ? maxfd : sd; + } + } + + if (maxfd > 0) { + // wait for any of the sockets to become ready... + sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL); + } +} + +void modusocket_close_all_user_sockets (void) { + sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER); + for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) { + if (modusocket_sockets[i].sd >= 0 && modusocket_sockets[i].user) { + sl_Close(modusocket_sockets[i].sd); + modusocket_sockets[i].sd = -1; + } + } + sl_LockObjUnlock (&modusocket_LockObj); +} + +/******************************************************************************/ +// socket class + +// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None) +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + // create socket object + mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t); + s->base.type = (mp_obj_t)&socket_type; + s->sock_base.u_param.domain = SL_AF_INET; + s->sock_base.u_param.type = SL_SOCK_STREAM; + s->sock_base.u_param.proto = SL_IPPROTO_TCP; + s->sock_base.u_param.fileno = -1; + s->sock_base.timeout_ms = 0; + s->sock_base.cert_req = false; + + if (n_args > 0) { + s->sock_base.u_param.domain = mp_obj_get_int(args[0]); + if (n_args > 1) { + s->sock_base.u_param.type = mp_obj_get_int(args[1]); + if (n_args > 2) { + s->sock_base.u_param.proto = mp_obj_get_int(args[2]); + if (n_args > 3) { + s->sock_base.u_param.fileno = mp_obj_get_int(args[3]); + } + } + } + } + + // create the socket + int _errno; + if (wlan_socket_socket(s, &_errno) != 0) { + mp_raise_OSError(-_errno); + } + // add the socket to the list + modusocket_socket_add(s->sock_base.sd, true); + return s; +} + +// method socket.bind(address) +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE); + + // call the NIC to bind the socket + int _errno = 0; + if (wlan_socket_bind(self, ip, port, &_errno) != 0) { + mp_raise_OSError(-_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +// method socket.listen([backlog]) +STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = args[0]; + + int32_t backlog = 0; + if (n_args > 1) { + backlog = mp_obj_get_int(args[1]); + backlog = (backlog < 0) ? 0 : backlog; + } + + int _errno; + if (wlan_socket_listen(self, backlog, &_errno) != 0) { + mp_raise_OSError(-_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen); + +// method socket.accept() +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + mod_network_socket_obj_t *self = self_in; + + // create new socket object + mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); + // the new socket inherits all properties from its parent + memcpy (socket2, self, sizeof(mod_network_socket_obj_t)); + + // accept the incoming connection + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = 0; + int _errno = 0; + if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + // add the socket to the list + modusocket_socket_add(socket2->sock_base.sd, true); + + // make the return value + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = socket2; + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE); + return client; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +// method socket.connect(address) +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE); + + // connect the socket + int _errno; + if (wlan_socket_connect(self, ip, port, &_errno) != 0) { + if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) { + return mp_const_none; + } + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +// method socket.send(bytes) +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mod_network_socket_obj_t *self = self_in; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int _errno; + mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno); + if (ret < 0) { + mp_raise_OSError(_errno); + } + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +// method socket.recv(bufsize) +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = self_in; + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + int _errno; + mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno); + if (ret < 0) { + mp_raise_OSError(_errno); + } + if (ret == 0) { + return mp_const_empty_bytes; + } + vstr.len = ret; + vstr.buf[vstr.len] = '\0'; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +// method socket.sendto(bytes, address) +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get the data + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE); + + // call the nic to sendto + int _errno = 0; + mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); + if (ret < 0) { + mp_raise_OSError(_errno); + } + return mp_obj_new_int(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +// method socket.recvfrom(bufsize) +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = self_in; + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(len_in)); + byte ip[4]; + mp_uint_t port = 0; + int _errno = 0; + mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); + if (ret < 0) { + mp_raise_OSError(_errno); + } + mp_obj_t tuple[2]; + if (ret == 0) { + tuple[0] = mp_const_empty_bytes; + } else { + vstr.len = ret; + vstr.buf[vstr.len] = '\0'; + tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +// method socket.setsockopt(level, optname, value) +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = args[0]; + + mp_int_t level = mp_obj_get_int(args[1]); + mp_int_t opt = mp_obj_get_int(args[2]); + + const void *optval; + mp_uint_t optlen; + mp_int_t val; + if (mp_obj_is_integer(args[3])) { + val = mp_obj_get_int_truncated(args[3]); + optval = &val; + optlen = sizeof(val); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + optval = bufinfo.buf; + optlen = bufinfo.len; + } + + int _errno; + if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { + mp_raise_OSError(-_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +// method socket.settimeout(value) +// timeout=0 means non-blocking +// timeout=None means blocking +// otherwise, timeout is in seconds +STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + mod_network_socket_obj_t *self = self_in; + mp_uint_t timeout; + if (timeout_in == mp_const_none) { + timeout = -1; + } else { + timeout = mp_obj_get_int(timeout_in); + } + int _errno = 0; + if (wlan_socket_settimeout(self, timeout, &_errno) != 0) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +// method socket.setblocking(flag) +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { + if (mp_obj_is_true(blocking)) { + return socket_settimeout(self_in, mp_const_none); + } else { + return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile); + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, + + // stream methods + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read1_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + mod_network_socket_obj_t *self = self_in; + mp_int_t ret = wlan_socket_recv(self, buf, size, errcode); + if (ret < 0) { + // we need to ignore the socket closed error here because a read() without params + // only returns when the socket is closed by the other end + if (*errcode != -SL_ESECCLOSED) { + ret = MP_STREAM_ERROR; + } else { + ret = 0; + } + } + return ret; +} + +STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mod_network_socket_obj_t *self = self_in; + mp_int_t ret = wlan_socket_send(self, buf, size, errcode); + if (ret < 0) { + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + mod_network_socket_obj_t *self = self_in; + return wlan_socket_ioctl(self, request, arg, errcode); +} + +const mp_stream_p_t socket_stream_p = { + .read = socket_read, + .write = socket_write, + .ioctl = socket_ioctl, + .is_text = false, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .make_new = socket_make_new, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +/******************************************************************************/ +// usocket module + +// function usocket.getaddrinfo(host, port) +/// \function getaddrinfo(host, port) +STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { + size_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + mp_int_t port = mp_obj_get_int(port_in); + + // ipv4 only + uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + int32_t result = wlan_gethostbyname(host, hlen, out_ip, SL_AF_INET); + if (result < 0) { + mp_raise_OSError(-result); + } + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SL_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SL_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_LITTLE); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo); + +STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(SL_AF_INET) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SL_SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SL_SOCK_DGRAM) }, + + { MP_ROM_QSTR(MP_QSTR_IPPROTO_SEC), MP_ROM_INT(SL_SEC_SOCKET) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(SL_IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(SL_IPPROTO_UDP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modusocket.h b/src/openmv/src/micropython/ports/cc3200/mods/modusocket.h new file mode 100755 index 0000000..aaee04c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modusocket.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H +#define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H + +#include "py/stream.h" + +extern const mp_obj_dict_t socket_locals_dict; +extern const mp_stream_p_t socket_stream_p; + +extern void modusocket_pre_init (void); +extern void modusocket_socket_add (int16_t sd, bool user); +extern void modusocket_socket_delete (int16_t sd); +extern void modusocket_enter_sleep (void); +extern void modusocket_close_all_user_sockets (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modussl.c b/src/openmv/src/micropython/ports/cc3200/mods/modussl.c new file mode 100755 index 0000000..3211570 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modussl.c @@ -0,0 +1,164 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "simplelink.h" +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "modnetwork.h" +#include "modusocket.h" +#include "mpexception.h" + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define SSL_CERT_NONE (0) +#define SSL_CERT_OPTIONAL (1) +#define SSL_CERT_REQUIRED (2) + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct _mp_obj_ssl_socket_t { + mp_obj_base_t base; + mod_network_socket_base_t sock_base; + mp_obj_t o_sock; +} mp_obj_ssl_socket_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_obj_type_t ssl_socket_type; + +/******************************************************************************/ +// MicroPython bindings; SSL class + +// ssl sockets inherit from normal socket, so we take its +// locals and stream methods +STATIC const mp_obj_type_t ssl_socket_type = { + { &mp_type_type }, + .name = MP_QSTR_ussl, + .getiter = NULL, + .iternext = NULL, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_keyfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} }, + { MP_QSTR_ssl_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SO_SEC_METHOD_TLSV1} }, + { MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse arguments + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // chech if ca validation is required + if (args[4].u_int != SSL_CERT_NONE && args[5].u_obj == mp_const_none) { + goto arg_error; + } + + // retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix) + const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]); + const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]); + const char *cafile = (args[6].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ? + NULL : &(mp_obj_str_get_str(args[6].u_obj)[6]); + + // server side requires both certfile and keyfile + if (args[3].u_bool && (!keyfile || !certfile)) { + goto arg_error; + } + + _i16 _errno; + _i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd; + + // set the requested SSL method + _u8 method = args[5].u_int; + if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) { + goto socket_error; + } + if (keyfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, keyfile, strlen(keyfile))) < 0) { + goto socket_error; + } + if (certfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, certfile, strlen(certfile))) < 0) { + goto socket_error; + } + if (cafile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, cafile, strlen(cafile))) < 0) { + goto socket_error; + } + + // create the ssl socket + mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t); + // ssl sockets inherit all properties from the original socket + memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t)); + ssl_sock->base.type = &ssl_socket_type; + ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false; + ssl_sock->o_sock = args[0].u_obj; + + return ssl_sock; + +socket_error: + mp_raise_OSError(_errno); + +arg_error: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket); + +STATIC const mp_rom_map_elem_t mp_module_ussl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, + + // class exceptions + { MP_ROM_QSTR(MP_QSTR_SSLError), MP_ROM_PTR(&mp_type_OSError) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(SSL_CERT_NONE) }, + { MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(SSL_CERT_OPTIONAL) }, + { MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(SSL_CERT_REQUIRED) }, + + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_SSLv3), MP_ROM_INT(SL_SO_SEC_METHOD_SSLV3) }, + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1) }, + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_1) }, + { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_2), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_2) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ussl_globals, mp_module_ussl_globals_table); + +const mp_obj_module_t mp_module_ussl = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ussl_globals, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modutime.c b/src/openmv/src/micropython/ports/cc3200/mods/modutime.c new file mode 100755 index 0000000..13750f9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modutime.c @@ -0,0 +1,157 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpconfig.h" +#include "py/runtime.h" +#include "py/obj.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "lib/timeutils/timeutils.h" +#include "extmod/utime_mphal.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "systick.h" +#include "pybrtc.h" +#include "mpexception.h" +#include "utils.h" + +/// \module time - time related functions +/// +/// The `time` module provides functions for getting the current time and date, +/// and for sleeping. + +/******************************************************************************/ +// MicroPython bindings + +/// \function localtime([secs]) +/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which +/// contains: (year, month, mday, hour, minute, second, weekday, yearday) +/// If secs is not provided or None, then the current time from the RTC is used. +/// year includes the century (for example 2015) +/// month is 1-12 +/// mday is 1-31 +/// hour is 0-23 +/// minute is 0-59 +/// second is 0-59 +/// weekday is 0-6 for Mon-Sun. +/// yearday is 1-366 +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + if (n_args == 0 || args[0] == mp_const_none) { + timeutils_struct_time_t tm; + + // get the seconds from the RTC + timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm); + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_yday) + }; + return mp_obj_new_tuple(8, tuple); + } else { + mp_int_t seconds = mp_obj_get_int(args[0]); + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + mp_raise_TypeError(mpexception_num_type_invalid_arguments); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), + mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +STATIC mp_obj_t time_time(void) { + return mp_obj_new_int(pyb_rtc_get_seconds()); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + int32_t sleep_s = mp_obj_get_int(seconds_o); + if (sleep_s > 0) { + mp_hal_delay_ms(sleep_s * 1000); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&time_sleep_obj) }, + + // MicroPython additions + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modwipy.c b/src/openmv/src/micropython/ports/cc3200/mods/modwipy.c new file mode 100755 index 0000000..0f16e73 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modwipy.c @@ -0,0 +1,30 @@ +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "mperror.h" + + +/******************************************************************************/ +// MicroPython bindings + +STATIC mp_obj_t mod_wipy_heartbeat(size_t n_args, const mp_obj_t *args) { + if (n_args) { + mperror_enable_heartbeat (mp_obj_is_true(args[0])); + return mp_const_none; + } else { + return mp_obj_new_bool(mperror_is_heartbeat_enabled()); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_wipy_heartbeat_obj, 0, 1, mod_wipy_heartbeat); + +STATIC const mp_rom_map_elem_t wipy_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wipy) }, + { MP_ROM_QSTR(MP_QSTR_heartbeat), MP_ROM_PTR(&mod_wipy_heartbeat_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table); + +const mp_obj_module_t wipy_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&wipy_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modwlan.c b/src/openmv/src/micropython/ports/cc3200/mods/modwlan.c new file mode 100755 index 0000000..8acc89d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modwlan.c @@ -0,0 +1,1303 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "simplelink.h" +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "lib/timeutils/timeutils.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" +#include "modusocket.h" +#include "modwlan.h" +#include "pybrtc.h" +#include "debug.h" +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) +#include "serverstask.h" +#endif +#include "mpexception.h" +#include "mpirq.h" +#include "pybsleep.h" +#include "antenna.h" + + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +// Status bits - These are used to set/reset the corresponding bits in a given variable +typedef enum{ + STATUS_BIT_NWP_INIT = 0, // If this bit is set: Network Processor is + // powered up + + STATUS_BIT_CONNECTION, // If this bit is set: the device is connected to + // the AP or client is connected to device (AP) + + STATUS_BIT_IP_LEASED, // If this bit is set: the device has leased IP to + // any connected client + + STATUS_BIT_IP_ACQUIRED, // If this bit is set: the device has acquired an IP + + STATUS_BIT_SMARTCONFIG_START, // If this bit is set: the SmartConfiguration + // process is started from SmartConfig app + + STATUS_BIT_P2P_DEV_FOUND, // If this bit is set: the device (P2P mode) + // found any p2p-device in scan + + STATUS_BIT_P2P_REQ_RECEIVED, // If this bit is set: the device (P2P mode) + // found any p2p-negotiation request + + STATUS_BIT_CONNECTION_FAILED, // If this bit is set: the device(P2P mode) + // connection to client(or reverse way) is failed + + STATUS_BIT_PING_DONE // If this bit is set: the device has completed + // the ping operation +} e_StatusBits; + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define CLR_STATUS_BIT_ALL(status) (status = 0) +#define SET_STATUS_BIT(status, bit) (status |= ( 1 << (bit))) +#define CLR_STATUS_BIT(status, bit) (status &= ~(1 << (bit))) +#define GET_STATUS_BIT(status, bit) (0 != (status & (1 << (bit)))) + +#define IS_NW_PROCSR_ON(status) GET_STATUS_BIT(status, STATUS_BIT_NWP_INIT) +#define IS_CONNECTED(status) GET_STATUS_BIT(status, STATUS_BIT_CONNECTION) +#define IS_IP_LEASED(status) GET_STATUS_BIT(status, STATUS_BIT_IP_LEASED) +#define IS_IP_ACQUIRED(status) GET_STATUS_BIT(status, STATUS_BIT_IP_ACQUIRED) +#define IS_SMART_CFG_START(status) GET_STATUS_BIT(status, STATUS_BIT_SMARTCONFIG_START) +#define IS_P2P_DEV_FOUND(status) GET_STATUS_BIT(status, STATUS_BIT_P2P_DEV_FOUND) +#define IS_P2P_REQ_RCVD(status) GET_STATUS_BIT(status, STATUS_BIT_P2P_REQ_RECEIVED) +#define IS_CONNECT_FAILED(status) GET_STATUS_BIT(status, STATUS_BIT_CONNECTION_FAILED) +#define IS_PING_DONE(status) GET_STATUS_BIT(status, STATUS_BIT_PING_DONE) + +#define MODWLAN_SL_SCAN_ENABLE 1 +#define MODWLAN_SL_SCAN_DISABLE 0 +#define MODWLAN_SL_MAX_NETWORKS 20 + +#define MODWLAN_MAX_NETWORKS 20 +#define MODWLAN_SCAN_PERIOD_S 3600 // 1 hour +#define MODWLAN_WAIT_FOR_SCAN_MS 1050 +#define MODWLAN_CONNECTION_WAIT_MS 2 + +#define ASSERT_ON_ERROR(x) ASSERT((x) >= 0) + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC wlan_obj_t wlan_obj = { + .mode = -1, + .status = 0, + .ip = 0, + .auth = MICROPY_PORT_WLAN_AP_SECURITY, + .channel = MICROPY_PORT_WLAN_AP_CHANNEL, + .ssid = MICROPY_PORT_WLAN_AP_SSID, + .key = MICROPY_PORT_WLAN_AP_KEY, + .mac = {0}, + //.ssid_o = {0}, + //.bssid = {0}, + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + .servers_enabled = false, + #endif +}; + +STATIC const mp_irq_methods_t wlan_irq_methods; + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +#ifdef SL_PLATFORM_MULTI_THREADED +OsiLockObj_t wlan_LockObj; +#endif + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void wlan_clear_data (void); +STATIC void wlan_reenable (SlWlanMode_t mode); +STATIC void wlan_servers_start (void); +STATIC void wlan_servers_stop (void); +STATIC void wlan_reset (void); +STATIC void wlan_validate_mode (uint mode); +STATIC void wlan_set_mode (uint mode); +STATIC void wlan_validate_ssid_len (uint32_t len); +STATIC void wlan_set_ssid (const char *ssid, uint8_t len, bool add_mac); +STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len); +STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len); +STATIC void wlan_validate_channel (uint8_t channel); +STATIC void wlan_set_channel (uint8_t channel); +#if MICROPY_HW_ANTENNA_DIVERSITY +STATIC void wlan_validate_antenna (uint8_t antenna); +STATIC void wlan_set_antenna (uint8_t antenna); +#endif +STATIC void wlan_sl_disconnect (void); +STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec, + const char* key, uint32_t key_len, int32_t timeout); +STATIC void wlan_get_sl_mac (void); +STATIC void wlan_wep_key_unhexlify (const char *key, char *key_out); +STATIC void wlan_lpds_irq_enable (mp_obj_t self_in); +STATIC void wlan_lpds_irq_disable (mp_obj_t self_in); +STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid); + +//***************************************************************************** +// +//! \brief The Function Handles WLAN Events +//! +//! \param[in] pWlanEvent - Pointer to WLAN Event Info +//! +//! \return None +//! +//***************************************************************************** +void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) { + if (!pWlanEvent) { + return; + } + + switch(pWlanEvent->Event) + { + case SL_WLAN_CONNECT_EVENT: + { + //slWlanConnectAsyncResponse_t *pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected; + // copy the new connection data + //memcpy(wlan_obj.bssid, pEventData->bssid, SL_BSSID_LENGTH); + //memcpy(wlan_obj.ssid_o, pEventData->ssid_name, pEventData->ssid_len); + //wlan_obj.ssid_o[pEventData->ssid_len] = '\0'; + SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + // we must reset the servers in case that the last connection + // was lost without any notification being received + servers_reset(); + #endif + } + break; + case SL_WLAN_DISCONNECT_EVENT: + CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); + CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED); + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + servers_reset(); + servers_wlan_cycle_power(); + #endif + break; + case SL_WLAN_STA_CONNECTED_EVENT: + { + //slPeerInfoAsyncResponse_t *pEventData = &pWlanEvent->EventData.APModeStaConnected; + // get the mac address and name of the connected device + //memcpy(wlan_obj.bssid, pEventData->mac, SL_BSSID_LENGTH); + //memcpy(wlan_obj.ssid_o, pEventData->go_peer_device_name, pEventData->go_peer_device_name_len); + //wlan_obj.ssid_o[pEventData->go_peer_device_name_len] = '\0'; + SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + // we must reset the servers in case that the last connection + // was lost without any notification being received + servers_reset(); + #endif + } + break; + case SL_WLAN_STA_DISCONNECTED_EVENT: + CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); + #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + servers_reset(); + servers_wlan_cycle_power(); + #endif + break; + case SL_WLAN_P2P_DEV_FOUND_EVENT: + // TODO + break; + case SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT: + // TODO + break; + case SL_WLAN_CONNECTION_FAILED_EVENT: + // TODO + break; + default: + break; + } +} + +//***************************************************************************** +// +//! \brief This function handles network events such as IP acquisition, IP +//! leased, IP released etc. +//! +//! \param[in] pNetAppEvent - Pointer to NetApp Event Info +//! +//! \return None +//! +//***************************************************************************** +void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent) { + if(!pNetAppEvent) { + return; + } + + switch(pNetAppEvent->Event) + { + case SL_NETAPP_IPV4_IPACQUIRED_EVENT: + { + SlIpV4AcquiredAsync_t *pEventData = NULL; + + SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED); + + // Ip Acquired Event Data + pEventData = &pNetAppEvent->EventData.ipAcquiredV4; + + // Get the ip + wlan_obj.ip = pEventData->ip; + } + break; + case SL_NETAPP_IPV6_IPACQUIRED_EVENT: + break; + case SL_NETAPP_IP_LEASED_EVENT: + break; + case SL_NETAPP_IP_RELEASED_EVENT: + break; + default: + break; + } +} + +//***************************************************************************** +// +//! \brief This function handles HTTP server events +//! +//! \param[in] pServerEvent - Contains the relevant event information +//! \param[in] pServerResponse - Should be filled by the user with the +//! relevant response information +//! +//! \return None +//! +//**************************************************************************** +void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent, SlHttpServerResponse_t *pHttpResponse) { + if (!pHttpEvent) { + return; + } + + switch (pHttpEvent->Event) { + case SL_NETAPP_HTTPGETTOKENVALUE_EVENT: + break; + case SL_NETAPP_HTTPPOSTTOKENVALUE_EVENT: + break; + default: + break; + } +} + +//***************************************************************************** +// +//! \brief This function handles General Events +//! +//! \param[in] pDevEvent - Pointer to General Event Info +//! +//! \return None +//! +//***************************************************************************** +void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent) { + if (!pDevEvent) { + return; + } +} + +//***************************************************************************** +// +//! This function handles socket events indication +//! +//! \param[in] pSock - Pointer to Socket Event Info +//! +//! \return None +//! +//***************************************************************************** +void SimpleLinkSockEventHandler(SlSockEvent_t *pSock) { + if (!pSock) { + return; + } + + switch( pSock->Event ) { + case SL_SOCKET_TX_FAILED_EVENT: + switch( pSock->socketAsyncEvent.SockTxFailData.status) { + case SL_ECLOSE: + break; + default: + break; + } + break; + case SL_SOCKET_ASYNC_EVENT: + switch(pSock->socketAsyncEvent.SockAsyncData.type) { + case SSL_ACCEPT: + break; + case RX_FRAGMENTATION_TOO_BIG: + break; + case OTHER_SIDE_CLOSE_SSL_DATA_NOT_ENCRYPTED: + break; + default: + break; + } + break; + default: + break; + } +} + +//***************************************************************************** +// SimpleLink Asynchronous Event Handlers -- End +//***************************************************************************** + +__attribute__ ((section (".boot"))) +void wlan_pre_init (void) { + // create the wlan lock + #ifdef SL_PLATFORM_MULTI_THREADED + ASSERT(OSI_OK == sl_LockObjCreate(&wlan_LockObj, "WlanLock")); + #endif +} + +void wlan_first_start (void) { + if (wlan_obj.mode < 0) { + CLR_STATUS_BIT_ALL(wlan_obj.status); + wlan_obj.mode = sl_Start(0, 0, 0); + #ifdef SL_PLATFORM_MULTI_THREADED + sl_LockObjUnlock (&wlan_LockObj); + #endif + } + + // get the mac address + wlan_get_sl_mac(); +} + +void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len, + uint8_t channel, uint8_t antenna, bool add_mac) { + + // stop the servers + wlan_servers_stop(); + + // do a basic start + wlan_first_start(); + + // close any active connections + wlan_sl_disconnect(); + + // Remove all profiles + ASSERT_ON_ERROR(sl_WlanProfileDel(0xFF)); + + // Enable the DHCP client + uint8_t value = 1; + ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE, 1, 1, &value)); + + // Set PM policy to normal + ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_PM, SL_NORMAL_POLICY, NULL, 0)); + + // Unregister mDNS services + ASSERT_ON_ERROR(sl_NetAppMDNSUnRegisterService(0, 0)); + + // Stop the internal HTTP server + sl_NetAppStop(SL_NET_APP_HTTP_SERVER_ID); + + // Remove all 64 filters (8 * 8) + _WlanRxFilterOperationCommandBuff_t RxFilterIdMask; + memset ((void *)&RxFilterIdMask, 0 ,sizeof(RxFilterIdMask)); + memset(RxFilterIdMask.FilterIdMask, 0xFF, 8); + ASSERT_ON_ERROR(sl_WlanRxFilterSet(SL_REMOVE_RX_FILTER, (_u8 *)&RxFilterIdMask, sizeof(_WlanRxFilterOperationCommandBuff_t))); + +#if MICROPY_HW_ANTENNA_DIVERSITY + // set the antenna type + wlan_set_antenna (antenna); +#endif + + // switch to the requested mode + wlan_set_mode(mode); + + // stop and start again (we need to in the propper mode from now on) + wlan_reenable(mode); + + // Set Tx power level for station or AP mode + // Number between 0-15, as dB offset from max power - 0 will set max power + uint8_t ucPower = 0; + if (mode == ROLE_AP) { + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_AP_TX_POWER, sizeof(ucPower), + (unsigned char *)&ucPower)); + + // configure all parameters + wlan_set_ssid (ssid, ssid_len, add_mac); + wlan_set_security (auth, key, key_len); + wlan_set_channel (channel); + + // set the country + _u8* country = (_u8*)"EU"; + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE, 2, country)); + + SlNetCfgIpV4Args_t ipV4; + ipV4.ipV4 = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 IP address + ipV4.ipV4Mask = (_u32)SL_IPV4_VAL(255,255,255,0); // _u32 Subnet mask for this AP + ipV4.ipV4Gateway = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 Default gateway address + ipV4.ipV4DnsServer = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 DNS server address + ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_AP_P2P_GO_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, + sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4)); + + SlNetAppDhcpServerBasicOpt_t dhcpParams; + dhcpParams.lease_time = 4096; // lease time (in seconds) of the IP Address + dhcpParams.ipv4_addr_start = SL_IPV4_VAL(192,168,1,2); // first IP Address for allocation. + dhcpParams.ipv4_addr_last = SL_IPV4_VAL(192,168,1,254); // last IP Address for allocation. + ASSERT_ON_ERROR(sl_NetAppStop(SL_NET_APP_DHCP_SERVER_ID)); // Stop DHCP server before settings + ASSERT_ON_ERROR(sl_NetAppSet(SL_NET_APP_DHCP_SERVER_ID, NETAPP_SET_DHCP_SRV_BASIC_OPT, + sizeof(SlNetAppDhcpServerBasicOpt_t), (_u8* )&dhcpParams)); // set parameters + ASSERT_ON_ERROR(sl_NetAppStart(SL_NET_APP_DHCP_SERVER_ID)); // Start DHCP server with new settings + + // stop and start again + wlan_reenable(mode); + } else { // STA and P2P modes + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, + sizeof(ucPower), (unsigned char *)&ucPower)); + // set connection policy to Auto + Fast (tries to connect to the last connected AP) + ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(1, 1, 0, 0, 0), NULL, 0)); + } + + // set current time and date (needed to validate certificates) + wlan_set_current_time (pyb_rtc_get_seconds()); + + // start the servers before returning + wlan_servers_start(); +} + +void wlan_update(void) { +#ifndef SL_PLATFORM_MULTI_THREADED + _SlTaskEntry(); +#endif +} + +void wlan_stop (uint32_t timeout) { + wlan_servers_stop(); + #ifdef SL_PLATFORM_MULTI_THREADED + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + #endif + sl_Stop(timeout); + wlan_clear_data(); + wlan_obj.mode = -1; +} + +void wlan_get_mac (uint8_t *macAddress) { + if (macAddress) { + memcpy (macAddress, wlan_obj.mac, SL_MAC_ADDR_LEN); + } +} + +void wlan_get_ip (uint32_t *ip) { + if (ip) { + *ip = IS_IP_ACQUIRED(wlan_obj.status) ? wlan_obj.ip : 0; + } +} + +bool wlan_is_connected (void) { + return (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION) && + (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED) || wlan_obj.mode != ROLE_STA)); +} + +void wlan_set_current_time (uint32_t seconds_since_2000) { + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(seconds_since_2000, &tm); + + SlDateTime_t sl_datetime = {0}; + sl_datetime.sl_tm_day = tm.tm_mday; + sl_datetime.sl_tm_mon = tm.tm_mon; + sl_datetime.sl_tm_year = tm.tm_year; + sl_datetime.sl_tm_hour = tm.tm_hour; + sl_datetime.sl_tm_min = tm.tm_min; + sl_datetime.sl_tm_sec = tm.tm_sec; + sl_DevSet(SL_DEVICE_GENERAL_CONFIGURATION, SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME, sizeof(SlDateTime_t), (_u8 *)(&sl_datetime)); +} + +void wlan_off_on (void) { + // no need to lock the WLAN object on every API call since the servers and the MicroPtyhon + // task have the same priority + wlan_reenable(wlan_obj.mode); +} + +//***************************************************************************** +// DEFINE STATIC FUNCTIONS +//***************************************************************************** + +STATIC void wlan_clear_data (void) { + CLR_STATUS_BIT_ALL(wlan_obj.status); + wlan_obj.ip = 0; + //memset(wlan_obj.ssid_o, 0, sizeof(wlan_obj.ssid)); + //memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid)); +} + +STATIC void wlan_reenable (SlWlanMode_t mode) { + // stop and start again + #ifdef SL_PLATFORM_MULTI_THREADED + sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); + #endif + sl_Stop(SL_STOP_TIMEOUT); + wlan_clear_data(); + wlan_obj.mode = sl_Start(0, 0, 0); + #ifdef SL_PLATFORM_MULTI_THREADED + sl_LockObjUnlock (&wlan_LockObj); + #endif + ASSERT (wlan_obj.mode == mode); +} + +STATIC void wlan_servers_start (void) { +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + // start the servers if they were enabled before + if (wlan_obj.servers_enabled) { + servers_start(); + } +#endif +} + +STATIC void wlan_servers_stop (void) { +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + // Stop all other processes using the wlan engine + if ((wlan_obj.servers_enabled = servers_are_enabled())) { + servers_stop(); + } +#endif +} + +STATIC void wlan_reset (void) { + wlan_servers_stop(); + wlan_reenable (wlan_obj.mode); + wlan_servers_start(); +} + +STATIC void wlan_validate_mode (uint mode) { + if (mode != ROLE_STA && mode != ROLE_AP) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void wlan_set_mode (uint mode) { + wlan_obj.mode = mode; + ASSERT_ON_ERROR(sl_WlanSetMode(mode)); +} + +STATIC void wlan_validate_ssid_len (uint32_t len) { + if (len > MODWLAN_SSID_LEN_MAX) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void wlan_set_ssid (const char *ssid, uint8_t len, bool add_mac) { + if (ssid != NULL) { + // save the ssid + memcpy(&wlan_obj.ssid, ssid, len); + // append the last 2 bytes of the MAC address, since the use of this functionality is under our control + // we can assume that the lenght of the ssid is less than (32 - 5) + if (add_mac) { + snprintf((char *)&wlan_obj.ssid[len], sizeof(wlan_obj.ssid) - len, "-%02x%02x", wlan_obj.mac[4], wlan_obj.mac[5]); + len += 5; + } + wlan_obj.ssid[len] = '\0'; + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SSID, len, (unsigned char *)wlan_obj.ssid)); + } +} + +STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len) { + if (auth != SL_SEC_TYPE_WEP && auth != SL_SEC_TYPE_WPA_WPA2) { + goto invalid_args; + } + if (auth == SL_SEC_TYPE_WEP) { + for (mp_uint_t i = strlen(key); i > 0; i--) { + if (!unichar_isxdigit(*key++)) { + goto invalid_args; + } + } + } + return; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { + wlan_obj.auth = auth; + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SECURITY_TYPE, sizeof(uint8_t), &auth)); + if (key != NULL) { + memcpy(&wlan_obj.key, key, len); + wlan_obj.key[len] = '\0'; + if (auth == SL_SEC_TYPE_WEP) { + _u8 wep_key[32]; + wlan_wep_key_unhexlify(key, (char *)&wep_key); + key = (const char *)&wep_key; + len /= 2; + } + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_PASSWORD, len, (unsigned char *)key)); + } else { + wlan_obj.key[0] = '\0'; + } +} + +STATIC void wlan_validate_channel (uint8_t channel) { + if (channel < 1 || channel > 11) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void wlan_set_channel (uint8_t channel) { + wlan_obj.channel = channel; + ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_CHANNEL, 1, &channel)); +} + +#if MICROPY_HW_ANTENNA_DIVERSITY +STATIC void wlan_validate_antenna (uint8_t antenna) { + if (antenna != ANTENNA_TYPE_INTERNAL && antenna != ANTENNA_TYPE_EXTERNAL) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void wlan_set_antenna (uint8_t antenna) { + wlan_obj.antenna = antenna; + antenna_select(antenna); +} +#endif + +STATIC void wlan_sl_disconnect (void) { + // Device in station-mode. Disconnect previous connection if any + // The function returns 0 if 'Disconnected done', negative number if already + // disconnected Wait for 'disconnection' event if 0 is returned, Ignore + // other return-codes + if (0 == sl_WlanDisconnect()) { + while (IS_CONNECTED(wlan_obj.status)) { + mp_hal_delay_ms(MODWLAN_CONNECTION_WAIT_MS); + wlan_update(); + } + } +} + +STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec, + const char* key, uint32_t key_len, int32_t timeout) { + SlSecParams_t secParams; + secParams.Key = (_i8*)key; + secParams.KeyLen = ((key != NULL) ? key_len : 0); + secParams.Type = sec; + + // first close any active connections + wlan_sl_disconnect(); + + if (!sl_WlanConnect((_i8*)ssid, ssid_len, (_u8*)bssid, &secParams, NULL)) { + // wait for the WLAN Event + uint32_t waitForConnectionMs = 0; + while (timeout && !IS_CONNECTED(wlan_obj.status)) { + mp_hal_delay_ms(MODWLAN_CONNECTION_WAIT_MS); + waitForConnectionMs += MODWLAN_CONNECTION_WAIT_MS; + if (timeout > 0 && waitForConnectionMs > timeout) { + return MODWLAN_ERROR_TIMEOUT; + } + wlan_update(); + } + return MODWLAN_OK; + } + return MODWLAN_ERROR_INVALID_PARAMS; +} + +STATIC void wlan_get_sl_mac (void) { + // Get the MAC address + uint8_t macAddrLen = SL_MAC_ADDR_LEN; + sl_NetCfgGet(SL_MAC_ADDRESS_GET, NULL, &macAddrLen, wlan_obj.mac); +} + +STATIC void wlan_wep_key_unhexlify (const char *key, char *key_out) { + byte hex_byte = 0; + for (mp_uint_t i = strlen(key); i > 0 ; i--) { + hex_byte += unichar_xdigit_value(*key++); + if (i & 1) { + hex_byte <<= 4; + } else { + *key_out++ = hex_byte; + hex_byte = 0; + } + } +} + +STATIC void wlan_lpds_irq_enable (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + self->irq_enabled = true; +} + +STATIC void wlan_lpds_irq_disable (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + self->irq_enabled = false; +} + +STATIC int wlan_irq_flags (mp_obj_t self_in) { + wlan_obj_t *self = self_in; + return self->irq_flags; +} + +STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid) { + for (int i = 0; i < nets->len; i++) { + // index 1 in the list is the bssid + mp_obj_str_t *_bssid = (mp_obj_str_t *)((mp_obj_tuple_t *)nets->items[i])->items[1]; + if (!memcmp (_bssid->data, bssid, SL_BSSID_LENGTH)) { + return false; + } + } + return true; +} + +/******************************************************************************/ +// MicroPython bindings; WLAN class + +/// \class WLAN - WiFi driver + +STATIC mp_obj_t wlan_init_helper(wlan_obj_t *self, const mp_arg_val_t *args) { + // get the mode + int8_t mode = args[0].u_int; + wlan_validate_mode(mode); + + // get the ssid + size_t ssid_len = 0; + const char *ssid = NULL; + if (args[1].u_obj != NULL) { + ssid = mp_obj_str_get_data(args[1].u_obj, &ssid_len); + wlan_validate_ssid_len(ssid_len); + } + + // get the auth config + uint8_t auth = SL_SEC_TYPE_OPEN; + size_t key_len = 0; + const char *key = NULL; + if (args[2].u_obj != mp_const_none) { + mp_obj_t *sec; + mp_obj_get_array_fixed_n(args[2].u_obj, 2, &sec); + auth = mp_obj_get_int(sec[0]); + key = mp_obj_str_get_data(sec[1], &key_len); + wlan_validate_security(auth, key, key_len); + } + + // get the channel + uint8_t channel = args[3].u_int; + wlan_validate_channel(channel); + + // get the antenna type + uint8_t antenna = 0; +#if MICROPY_HW_ANTENNA_DIVERSITY + antenna = args[4].u_int; + wlan_validate_antenna(antenna); +#endif + + // initialize the wlan subsystem + wlan_sl_init(mode, (const char *)ssid, ssid_len, auth, (const char *)key, key_len, channel, antenna, false); + + return mp_const_none; +} + +STATIC const mp_arg_t wlan_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_mode, MP_ARG_INT, {.u_int = ROLE_STA} }, + { MP_QSTR_ssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + #if MICROPY_HW_ANTENNA_DIVERSITY + { MP_QSTR_antenna, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ANTENNA_TYPE_INTERNAL} }, + #endif +}; +STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(wlan_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), wlan_init_args, args); + + // setup the object + wlan_obj_t *self = &wlan_obj; + self->base.type = (mp_obj_t)&mod_network_nic_type_wlan; + + // give it to the sleep module + pyb_sleep_set_wlan_obj(self); + + if (n_args > 1 || n_kw > 0) { + // check the peripheral id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + // start the peripheral + wlan_init_helper(self, &args[1]); + } + + return (mp_obj_t)self; +} + +STATIC mp_obj_t wlan_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(wlan_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &wlan_init_args[1], args); + return wlan_init_helper(pos_args[0], args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_init_obj, 1, wlan_init); + +STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { + STATIC const qstr wlan_scan_info_fields[] = { + MP_QSTR_ssid, MP_QSTR_bssid, MP_QSTR_sec, MP_QSTR_channel, MP_QSTR_rssi + }; + + // check for correct wlan mode + if (wlan_obj.mode == ROLE_AP) { + mp_raise_OSError(MP_EPERM); + } + + Sl_WlanNetworkEntry_t wlanEntry; + mp_obj_t nets = mp_obj_new_list(0, NULL); + uint8_t _index = 0; + + // trigger a new network scan + uint32_t scanSeconds = MODWLAN_SCAN_PERIOD_S; + ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_SCAN , MODWLAN_SL_SCAN_ENABLE, (_u8 *)&scanSeconds, sizeof(scanSeconds))); + + // wait for the scan to complete + mp_hal_delay_ms(MODWLAN_WAIT_FOR_SCAN_MS); + + do { + if (sl_WlanGetNetworkList(_index++, 1, &wlanEntry) <= 0) { + break; + } + + // we must skip any duplicated results + if (!wlan_scan_result_is_unique(nets, wlanEntry.bssid)) { + continue; + } + + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len); + tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH); + // 'normalize' the security type + if (wlanEntry.sec_type > 2) { + wlanEntry.sec_type = 2; + } + tuple[2] = mp_obj_new_int(wlanEntry.sec_type); + tuple[3] = mp_const_none; + tuple[4] = mp_obj_new_int(wlanEntry.rssi); + + // add the network to the list + mp_obj_list_append(nets, mp_obj_new_attrtuple(wlan_scan_info_fields, 5, tuple)); + + } while (_index < MODWLAN_SL_MAX_NETWORKS); + + return nets; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan); + +STATIC mp_obj_t wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_auth, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // check for the correct wlan mode + if (wlan_obj.mode == ROLE_AP) { + mp_raise_OSError(MP_EPERM); + } + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the ssid + size_t ssid_len; + const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len); + wlan_validate_ssid_len(ssid_len); + + // get the auth config + uint8_t auth = SL_SEC_TYPE_OPEN; + size_t key_len = 0; + const char *key = NULL; + if (args[1].u_obj != mp_const_none) { + mp_obj_t *sec; + mp_obj_get_array_fixed_n(args[1].u_obj, 2, &sec); + auth = mp_obj_get_int(sec[0]); + key = mp_obj_str_get_data(sec[1], &key_len); + wlan_validate_security(auth, key, key_len); + + // convert the wep key if needed + if (auth == SL_SEC_TYPE_WEP) { + _u8 wep_key[32]; + wlan_wep_key_unhexlify(key, (char *)&wep_key); + key = (const char *)&wep_key; + key_len /= 2; + } + } + + // get the bssid + const char *bssid = NULL; + if (args[2].u_obj != mp_const_none) { + bssid = mp_obj_str_get_str(args[2].u_obj); + } + + // get the timeout + int32_t timeout = -1; + if (args[3].u_obj != mp_const_none) { + timeout = mp_obj_get_int(args[3].u_obj); + } + + // connect to the requested access point + modwlan_Status_t status; + status = wlan_do_connect (ssid, ssid_len, bssid, auth, key, key_len, timeout); + if (status == MODWLAN_ERROR_TIMEOUT) { + mp_raise_OSError(MP_ETIMEDOUT); + } else if (status == MODWLAN_ERROR_INVALID_PARAMS) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_connect_obj, 1, wlan_connect); + +STATIC mp_obj_t wlan_disconnect(mp_obj_t self_in) { + wlan_sl_disconnect(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_disconnect_obj, wlan_disconnect); + +STATIC mp_obj_t wlan_isconnected(mp_obj_t self_in) { + return wlan_is_connected() ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected); + +STATIC mp_obj_t wlan_ifconfig(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t wlan_ifconfig_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_config, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(wlan_ifconfig_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), wlan_ifconfig_args, args); + + // check the interface id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_EPERM); + } + + // get the configuration + if (args[1].u_obj == MP_OBJ_NULL) { + // get + unsigned char len = sizeof(SlNetCfgIpV4Args_t); + unsigned char dhcpIsOn; + SlNetCfgIpV4Args_t ipV4; + sl_NetCfgGet(SL_IPV4_STA_P2P_CL_GET_INFO, &dhcpIsOn, &len, (uint8_t *)&ipV4); + + mp_obj_t ifconfig[4] = { + netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4, NETUTILS_LITTLE), + netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4Mask, NETUTILS_LITTLE), + netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4Gateway, NETUTILS_LITTLE), + netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4DnsServer, NETUTILS_LITTLE) + }; + return mp_obj_new_tuple(4, ifconfig); + } else { // set the configuration + if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { + // set a static ip + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1].u_obj, 4, &items); + + SlNetCfgIpV4Args_t ipV4; + netutils_parse_ipv4_addr(items[0], (uint8_t *)&ipV4.ipV4, NETUTILS_LITTLE); + netutils_parse_ipv4_addr(items[1], (uint8_t *)&ipV4.ipV4Mask, NETUTILS_LITTLE); + netutils_parse_ipv4_addr(items[2], (uint8_t *)&ipV4.ipV4Gateway, NETUTILS_LITTLE); + netutils_parse_ipv4_addr(items[3], (uint8_t *)&ipV4.ipV4DnsServer, NETUTILS_LITTLE); + + if (wlan_obj.mode == ROLE_AP) { + ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_AP_P2P_GO_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4)); + SlNetAppDhcpServerBasicOpt_t dhcpParams; + dhcpParams.lease_time = 4096; // lease time (in seconds) of the IP Address + dhcpParams.ipv4_addr_start = ipV4.ipV4 + 1; // first IP Address for allocation. + dhcpParams.ipv4_addr_last = (ipV4.ipV4 & 0xFFFFFF00) + 254; // last IP Address for allocation. + ASSERT_ON_ERROR(sl_NetAppStop(SL_NET_APP_DHCP_SERVER_ID)); // stop DHCP server before settings + ASSERT_ON_ERROR(sl_NetAppSet(SL_NET_APP_DHCP_SERVER_ID, NETAPP_SET_DHCP_SRV_BASIC_OPT, + sizeof(SlNetAppDhcpServerBasicOpt_t), (_u8* )&dhcpParams)); // set parameters + ASSERT_ON_ERROR(sl_NetAppStart(SL_NET_APP_DHCP_SERVER_ID)); // start DHCP server with new settings + } else { + ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_STA_P2P_CL_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4)); + } + } else { + // check for the correct string + const char *mode = mp_obj_str_get_str(args[1].u_obj); + if (strcmp("dhcp", mode)) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + + // only if we are not in AP mode + if (wlan_obj.mode != ROLE_AP) { + _u8 val = 1; + sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, 1, &val); + } + } + // config values have changed, so reset + wlan_reset(); + // set current time and date (needed to validate certificates) + wlan_set_current_time (pyb_rtc_get_seconds()); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_ifconfig_obj, 1, wlan_ifconfig); + +STATIC mp_obj_t wlan_mode(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_int(self->mode); + } else { + uint mode = mp_obj_get_int(args[1]); + wlan_validate_mode(mode); + wlan_set_mode(mode); + wlan_reset(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode); + +STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid)); + } else { + size_t len; + const char *ssid = mp_obj_str_get_data(args[1], &len); + wlan_validate_ssid_len(len); + wlan_set_ssid(ssid, len, false); + wlan_reset(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_ssid_obj, 1, 2, wlan_ssid); + +STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + if (self->auth == SL_SEC_TYPE_OPEN) { + return mp_const_none; + } else { + mp_obj_t security[2]; + security[0] = mp_obj_new_int(self->auth); + security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key)); + return mp_obj_new_tuple(2, security); + } + } else { + // get the auth config + uint8_t auth = SL_SEC_TYPE_OPEN; + size_t key_len = 0; + const char *key = NULL; + if (args[1] != mp_const_none) { + mp_obj_t *sec; + mp_obj_get_array_fixed_n(args[1], 2, &sec); + auth = mp_obj_get_int(sec[0]); + key = mp_obj_str_get_data(sec[1], &key_len); + wlan_validate_security(auth, key, key_len); + } + wlan_set_security(auth, key, key_len); + wlan_reset(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_auth_obj, 1, 2, wlan_auth); + +STATIC mp_obj_t wlan_channel(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_int(self->channel); + } else { + uint8_t channel = mp_obj_get_int(args[1]); + wlan_validate_channel(channel); + wlan_set_channel(channel); + wlan_reset(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_channel_obj, 1, 2, wlan_channel); + +STATIC mp_obj_t wlan_antenna(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_int(self->antenna); + } else { + #if MICROPY_HW_ANTENNA_DIVERSITY + uint8_t antenna = mp_obj_get_int(args[1]); + wlan_validate_antenna(antenna); + wlan_set_antenna(antenna); + #endif + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_antenna_obj, 1, 2, wlan_antenna); + +STATIC mp_obj_t wlan_mac(size_t n_args, const mp_obj_t *args) { + wlan_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_bytes((const byte *)self->mac, SL_BSSID_LENGTH); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + memcpy(self->mac, bufinfo.buf, SL_MAC_ADDR_LEN); + sl_NetCfgSet(SL_MAC_ADDRESS_SET, 1, SL_MAC_ADDR_LEN, (_u8 *)self->mac); + wlan_reset(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mac_obj, 1, 2, wlan_mac); + +STATIC mp_obj_t wlan_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); + + wlan_obj_t *self = pos_args[0]; + + // check the trigger, only one type is supported + if (mp_obj_get_int(args[0].u_obj) != MODWLAN_WIFI_EVENT_ANY) { + goto invalid_args; + } + + // check the power mode + if (mp_obj_get_int(args[3].u_obj) != PYB_PWR_MODE_LPDS) { + goto invalid_args; + } + + // create the callback + mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &wlan_irq_methods); + self->irq_obj = _irq; + + // enable the irq just before leaving + wlan_lpds_irq_enable(self); + + return _irq; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); + +//STATIC mp_obj_t wlan_connections (mp_obj_t self_in) { +// mp_obj_t device[2]; +// mp_obj_t connections = mp_obj_new_list(0, NULL); +// +// if (wlan_is_connected()) { +// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o)); +// device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH); +// // add the device to the list +// mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device)); +// } +// return connections; +//} +//STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_connections_obj, wlan_connections); + +//STATIC mp_obj_t wlan_urn (uint n_args, const mp_obj_t *args) { +// char urn[MAX_DEVICE_URN_LEN]; +// uint8_t len = MAX_DEVICE_URN_LEN; +// +// // an URN is given, so set it +// if (n_args == 2) { +// const char *p = mp_obj_str_get_str(args[1]); +// uint8_t len = strlen(p); +// +// // the call to sl_NetAppSet corrupts the input string URN=args[1], so we copy into a local buffer +// if (len > MAX_DEVICE_URN_LEN) { +// mp_raise_ValueError(mpexception_value_invalid_arguments); +// } +// strcpy(urn, p); +// +// if (sl_NetAppSet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, len, (unsigned char *)urn) < 0) { +// mp_raise_OSError(MP_EIO); +// } +// } +// else { +// // get the URN +// if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { +// mp_raise_OSError(MP_EIO); +// } +// return mp_obj_new_str(urn, (len - 1)); +// } +// +// return mp_const_none; +//} +//STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_urn_obj, 1, 2, wlan_urn); + +STATIC mp_obj_t wlan_print_ver(void) { + SlVersionFull ver; + byte config_opt = SL_DEVICE_GENERAL_VERSION; + byte config_len = sizeof(ver); + sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION, &config_opt, &config_len, (byte*)&ver); + printf("NWP: %d.%d.%d.%d\n", (int)ver.NwpVersion[0], (int)ver.NwpVersion[1], (int)ver.NwpVersion[2], (int)ver.NwpVersion[3]); + printf("MAC: %d.%d.%d.%d\n", (int)ver.ChipFwAndPhyVersion.FwVersion[0], (int)ver.ChipFwAndPhyVersion.FwVersion[1], + (int)ver.ChipFwAndPhyVersion.FwVersion[2], (int)ver.ChipFwAndPhyVersion.FwVersion[3]); + printf("PHY: %d.%d.%d.%d\n", ver.ChipFwAndPhyVersion.PhyVersion[0], ver.ChipFwAndPhyVersion.PhyVersion[1], + ver.ChipFwAndPhyVersion.PhyVersion[2], ver.ChipFwAndPhyVersion.PhyVersion[3]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(wlan_print_ver_fun_obj, wlan_print_ver); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(wlan_print_ver_obj, MP_ROM_PTR(&wlan_print_ver_fun_obj)); + +STATIC const mp_rom_map_elem_t wlan_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&wlan_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&wlan_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wlan_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&wlan_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wlan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wlan_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&wlan_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_ssid), MP_ROM_PTR(&wlan_ssid_obj) }, + { MP_ROM_QSTR(MP_QSTR_auth), MP_ROM_PTR(&wlan_auth_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wlan_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_antenna), MP_ROM_PTR(&wlan_antenna_obj) }, + { MP_ROM_QSTR(MP_QSTR_mac), MP_ROM_PTR(&wlan_mac_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&wlan_irq_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_connections), MP_ROM_PTR(&wlan_connections_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_urn), MP_ROM_PTR(&wlan_urn_obj) }, + { MP_ROM_QSTR(MP_QSTR_print_ver), MP_ROM_PTR(&wlan_print_ver_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_STA), MP_ROM_INT(ROLE_STA) }, + { MP_ROM_QSTR(MP_QSTR_AP), MP_ROM_INT(ROLE_AP) }, + { MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(SL_SEC_TYPE_WEP) }, + { MP_ROM_QSTR(MP_QSTR_WPA), MP_ROM_INT(SL_SEC_TYPE_WPA_WPA2) }, + { MP_ROM_QSTR(MP_QSTR_WPA2), MP_ROM_INT(SL_SEC_TYPE_WPA_WPA2) }, + #if MICROPY_HW_ANTENNA_DIVERSITY + { MP_ROM_QSTR(MP_QSTR_INT_ANT), MP_ROM_INT(ANTENNA_TYPE_INTERNAL) }, + { MP_ROM_QSTR(MP_QSTR_EXT_ANT), MP_ROM_INT(ANTENNA_TYPE_EXTERNAL) }, + #endif + { MP_ROM_QSTR(MP_QSTR_ANY_EVENT), MP_ROM_INT(MODWLAN_WIFI_EVENT_ANY) }, +}; +STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table); + +const mod_network_nic_type_t mod_network_nic_type_wlan = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_WLAN, + .make_new = wlan_make_new, + .locals_dict = (mp_obj_t)&wlan_locals_dict, + }, +}; + +STATIC const mp_irq_methods_t wlan_irq_methods = { + .init = wlan_irq, + .enable = wlan_lpds_irq_enable, + .disable = wlan_lpds_irq_disable, + .flags = wlan_irq_flags, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/modwlan.h b/src/openmv/src/micropython/ports/cc3200/mods/modwlan.h new file mode 100755 index 0000000..b806644 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/modwlan.h @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_MODWLAN_H +#define MICROPY_INCLUDED_CC3200_MODS_MODWLAN_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define SIMPLELINK_SPAWN_TASK_PRIORITY 3 +#define SIMPLELINK_TASK_STACK_SIZE 2048 +#define SL_STOP_TIMEOUT 35 +#define SL_STOP_TIMEOUT_LONG 575 + +#define MODWLAN_WIFI_EVENT_ANY 0x01 + +#define MODWLAN_SSID_LEN_MAX 32 + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef enum { + MODWLAN_OK = 0, + MODWLAN_ERROR_INVALID_PARAMS = -1, + MODWLAN_ERROR_TIMEOUT = -2, + MODWLAN_ERROR_UNKNOWN = -3, +} modwlan_Status_t; + +typedef struct _wlan_obj_t { + mp_obj_base_t base; + mp_obj_t irq_obj; + uint32_t status; + + uint32_t ip; + + int8_t mode; + uint8_t auth; + uint8_t channel; + uint8_t antenna; + + // my own ssid, key and mac + uint8_t ssid[(MODWLAN_SSID_LEN_MAX + 1)]; + uint8_t key[65]; + uint8_t mac[SL_MAC_ADDR_LEN]; + + // the sssid (or name) and mac of the other device + uint8_t ssid_o[33]; + uint8_t bssid[6]; + uint8_t irq_flags; + bool irq_enabled; + +#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) + bool servers_enabled; +#endif +} wlan_obj_t; + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +extern _SlLockObj_t wlan_LockObj; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +extern void wlan_pre_init (void); +extern void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len, + uint8_t channel, uint8_t antenna, bool add_mac); +extern void wlan_first_start (void); +extern void wlan_update(void); +extern void wlan_stop (uint32_t timeout); +extern void wlan_get_mac (uint8_t *macAddress); +extern void wlan_get_ip (uint32_t *ip); +extern bool wlan_is_connected (void); +extern void wlan_set_current_time (uint32_t seconds_since_2000); +extern void wlan_off_on (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_MODWLAN_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybadc.c b/src/openmv/src/micropython/ports/cc3200/mods/pybadc.c new file mode 100755 index 0000000..c73b8c1 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybadc.c @@ -0,0 +1,310 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "bufhelper.h" +#include "inc/hw_types.h" +#include "inc/hw_adc.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "interrupt.h" +#include "pin.h" +#include "gpio.h" +#include "prcm.h" +#include "adc.h" +#include "pybadc.h" +#include "pybpin.h" +#include "pybsleep.h" +#include "pins.h" +#include "mpexception.h" + + +/****************************************************************************** + DECLARE CONSTANTS + ******************************************************************************/ +#define PYB_ADC_NUM_CHANNELS 4 + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct { + mp_obj_base_t base; + bool enabled; +} pyb_adc_obj_t; + +typedef struct { + mp_obj_base_t base; + pin_obj_t *pin; + byte channel; + byte id; + bool enabled; +} pyb_adc_channel_obj_t; + + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC pyb_adc_channel_obj_t pyb_adc_channel_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 0, .enabled = false}, + {.pin = &pin_GP3, .channel = ADC_CH_1, .id = 1, .enabled = false}, + {.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2, .enabled = false}, + {.pin = &pin_GP5, .channel = ADC_CH_3, .id = 3, .enabled = false} }; +STATIC pyb_adc_obj_t pyb_adc_obj = {.enabled = false}; + +STATIC const mp_obj_type_t pyb_adc_channel_type; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +STATIC void pyb_adc_init (pyb_adc_obj_t *self) { + // enable and configure the timer + MAP_ADCTimerConfig(ADC_BASE, (1 << 17) - 1); + MAP_ADCTimerEnable(ADC_BASE); + // enable the ADC peripheral + MAP_ADCEnable(ADC_BASE); + self->enabled = true; +} + +STATIC void pyb_adc_check_init(void) { + // not initialized + if (!pyb_adc_obj.enabled) { + mp_raise_OSError(MP_EPERM); + } +} + +STATIC void pyb_adc_channel_init (pyb_adc_channel_obj_t *self) { + // the ADC block must be enabled first + pyb_adc_check_init(); + // configure the pin in analog mode + pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA); + // enable the ADC channel + MAP_ADCChannelEnable(ADC_BASE, self->channel); + self->enabled = true; +} + +STATIC void pyb_adc_deinit_all_channels (void) { + for (int i = 0; i < PYB_ADC_NUM_CHANNELS; i++) { + adc_channel_deinit(&pyb_adc_channel_obj[i]); + } +} + +/******************************************************************************/ +/* MicroPython bindings : adc object */ + +STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_adc_obj_t *self = self_in; + if (self->enabled) { + mp_printf(print, "ADC(0, bits=12)"); + } else { + mp_printf(print, "ADC(0)"); + } +} + +STATIC const mp_arg_t pyb_adc_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 12} }, +}; +STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_adc_init_args, args); + + // check the peripheral id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + + // check the number of bits + if (args[1].u_int != 12) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + + // setup the object + pyb_adc_obj_t *self = &pyb_adc_obj; + self->base.type = &pyb_adc_type; + + // initialize and register with the sleep module + pyb_adc_init(self); + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init); + return self; +} + +STATIC mp_obj_t adc_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args); + // check the number of bits + if (args[0].u_int != 12) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + pyb_adc_init(pos_args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_init_obj, 1, adc_init); + +STATIC mp_obj_t adc_deinit(mp_obj_t self_in) { + pyb_adc_obj_t *self = self_in; + // first deinit all channels + pyb_adc_deinit_all_channels(); + MAP_ADCDisable(ADC_BASE); + self->enabled = false; + // unregister it with the sleep module + pyb_sleep_remove ((const mp_obj_t)self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit); + +STATIC mp_obj_t adc_channel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_adc_channel_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_channel_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args); + + uint ch_id; + if (args[0].u_obj != MP_OBJ_NULL) { + ch_id = mp_obj_get_int(args[0].u_obj); + if (ch_id >= PYB_ADC_NUM_CHANNELS) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } else if (args[1].u_obj != mp_const_none) { + uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); + if (ch_id != pin_ch_id) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + } + } else { + ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); + } + + // setup the object + pyb_adc_channel_obj_t *self = &pyb_adc_channel_obj[ch_id]; + self->base.type = &pyb_adc_channel_type; + pyb_adc_channel_init (self); + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel); + +STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&adc_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&adc_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&adc_channel_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); + +const mp_obj_type_t pyb_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = adc_print, + .make_new = adc_make_new, + .locals_dict = (mp_obj_t)&adc_locals_dict, +}; + +STATIC void adc_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_adc_channel_obj_t *self = self_in; + if (self->enabled) { + mp_printf(print, "ADCChannel(%u, pin=%q)", self->id, self->pin->name); + } else { + mp_printf(print, "ADCChannel(%u)", self->id); + } +} + +STATIC mp_obj_t adc_channel_init(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + // re-enable it + pyb_adc_channel_init(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_init_obj, adc_channel_init); + +STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + + MAP_ADCChannelDisable(ADC_BASE, self->channel); + // unregister it with the sleep module + pyb_sleep_remove ((const mp_obj_t)self); + self->enabled = false; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_deinit_obj, adc_channel_deinit); + +STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + uint32_t value; + + // the channel must be enabled + if (!self->enabled) { + mp_raise_OSError(MP_EPERM); + } + + // wait until a new value is available + while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel)); + // read the sample + value = MAP_ADCFIFORead(ADC_BASE, self->channel); + // the 12 bit sampled value is stored in bits [13:2] + return MP_OBJ_NEW_SMALL_INT((value & 0x3FFF) >> 2); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_value_obj, adc_channel_value); + +STATIC mp_obj_t adc_channel_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return adc_channel_value (self_in); +} + +STATIC const mp_rom_map_elem_t adc_channel_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&adc_channel_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&adc_channel_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&adc_channel_value_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adc_channel_locals_dict, adc_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_adc_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_ADCChannel, + .print = adc_channel_print, + .call = adc_channel_call, + .locals_dict = (mp_obj_t)&adc_channel_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybadc.h b/src/openmv/src/micropython/ports/cc3200/mods/pybadc.h new file mode 100755 index 0000000..db04b00 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybadc.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBADC_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBADC_H + +extern const mp_obj_type_t pyb_adc_type; + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBADC_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybflash.c b/src/openmv/src/micropython/ports/cc3200/mods/pybflash.c new file mode 100755 index 0000000..51f4cb5 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybflash.c @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//#include +//#include + +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/vfs_fat.h" + +#include "fatfs/src/drivers/sflash_diskio.h" +#include "mods/pybflash.h" + +/******************************************************************************/ +// MicroPython bindings to expose the internal flash as an object with the +// block protocol. + +// there is a singleton Flash object +STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type}; + +STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return singleton object + return (mp_obj_t)&pyb_flash_obj; +} + +STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + DRESULT res = sflash_disk_read(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SFLASH_SECTOR_SIZE); + return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks); + +STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + DRESULT res = sflash_disk_write(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SFLASH_SECTOR_SIZE); + return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks); + +STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(sflash_disk_init() != RES_OK); + case BP_IOCTL_DEINIT: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SYNC: sflash_disk_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_COUNT); + case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(SFLASH_SECTOR_SIZE); + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl); + +STATIC const mp_rom_map_elem_t pyb_flash_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_flash_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_flash_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_flash_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table); + +const mp_obj_type_t pyb_flash_type = { + { &mp_type_type }, + .name = MP_QSTR_Flash, + .make_new = pyb_flash_make_new, + .locals_dict = (mp_obj_t)&pyb_flash_locals_dict, +}; + +void pyb_flash_init_vfs(fs_user_mount_t *vfs) { + vfs->base.type = &mp_fat_vfs_type; + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->fatfs.drv = vfs; + vfs->readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj; + vfs->readblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->readblocks[2] = (mp_obj_t)sflash_disk_read; // native version + vfs->writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj; + vfs->writeblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->writeblocks[2] = (mp_obj_t)sflash_disk_write; // native version + vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; + vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; +} diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybflash.h b/src/openmv/src/micropython/ports/cc3200/mods/pybflash.h new file mode 100755 index 0000000..6f8ddf2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybflash.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H + +#include "py/obj.h" + +extern const mp_obj_type_t pyb_flash_type; + +void pyb_flash_init_vfs(fs_user_mount_t *vfs); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBFLASH_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.c b/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.c new file mode 100755 index 0000000..d08627f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.c @@ -0,0 +1,531 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "bufhelper.h" +#include "inc/hw_types.h" +#include "inc/hw_i2c.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "i2c.h" +#include "pybi2c.h" +#include "mpexception.h" +#include "pybsleep.h" +#include "utils.h" +#include "pybpin.h" +#include "pins.h" + +/// \moduleref pyb +/// \class I2C - a two-wire serial protocol + +typedef struct _pyb_i2c_obj_t { + mp_obj_base_t base; + uint baudrate; +} pyb_i2c_obj_t; + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define PYBI2C_MIN_BAUD_RATE_HZ (50000) +#define PYBI2C_MAX_BAUD_RATE_HZ (400000) + +#define PYBI2C_TRANSC_TIMEOUT_MS (20) +#define PYBI2C_TRANSAC_WAIT_DELAY_US (10) + +#define PYBI2C_TIMEOUT_TO_COUNT(to_us, baud) (((baud) * to_us) / 16000000) + +#define RET_IF_ERR(Func) { \ + if (!Func) { \ + return false; \ + } \ + } + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0}; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop); + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +// only master mode is available for the moment +STATIC void i2c_init (pyb_i2c_obj_t *self) { + // Enable the I2C Peripheral + MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralReset(PRCM_I2CA0); + // Configure I2C module with the specified baudrate + MAP_I2CMasterInitExpClk(I2CA0_BASE, self->baudrate); +} + +STATIC bool pyb_i2c_transaction(uint cmd) { + // Convert the timeout to microseconds + int32_t timeout = PYBI2C_TRANSC_TIMEOUT_MS * 1000; + // Sanity check, t_timeout must be between 1 and 255 + uint t_timeout = MIN(PYBI2C_TIMEOUT_TO_COUNT(timeout, pyb_i2c_obj.baudrate), 255); + // Clear all interrupts + MAP_I2CMasterIntClearEx(I2CA0_BASE, MAP_I2CMasterIntStatusEx(I2CA0_BASE, false)); + // Set the time-out in terms of clock cycles. Not to be used with breakpoints. + MAP_I2CMasterTimeoutSet(I2CA0_BASE, t_timeout); + // Initiate the transfer. + MAP_I2CMasterControl(I2CA0_BASE, cmd); + // Wait until the current byte has been transferred. + // Poll on the raw interrupt status. + while ((MAP_I2CMasterIntStatusEx(I2CA0_BASE, false) & (I2C_MASTER_INT_DATA | I2C_MASTER_INT_TIMEOUT)) == 0) { + if (timeout < 0) { + // the peripheral is not responding, so stop + return false; + } + // wait for a few microseconds + UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US)); + timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US; + } + + // Check for any errors in the transfer + if (MAP_I2CMasterErr(I2CA0_BASE) != I2C_MASTER_ERR_NONE) { + switch(cmd) { + case I2C_MASTER_CMD_BURST_SEND_START: + case I2C_MASTER_CMD_BURST_SEND_CONT: + case I2C_MASTER_CMD_BURST_SEND_STOP: + MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP); + break; + case I2C_MASTER_CMD_BURST_RECEIVE_START: + case I2C_MASTER_CMD_BURST_RECEIVE_CONT: + case I2C_MASTER_CMD_BURST_RECEIVE_FINISH: + MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP); + break; + default: + break; + } + return false; + } + return true; +} + +STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) { + // not initialized + if (!self->baudrate) { + mp_raise_OSError(MP_EPERM); + } +} + +STATIC bool pyb_i2c_scan_device(byte devAddr) { + bool ret = false; + // Set the I2C slave address + MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true); + // Initiate the transfer. + if (pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE)) { + ret = true; + } + // Send the stop bit to cancel the read transaction + MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP); + if (!ret) { + uint8_t data = 0; + if (pyb_i2c_write(devAddr, &data, sizeof(data), true)) { + ret = true; + } + } + return ret; +} + +STATIC bool pyb_i2c_mem_addr_write (byte addr, byte *mem_addr, uint mem_addr_len) { + // Set I2C codec slave address + MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false); + // Write the first byte to the controller. + MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++); + // Initiate the transfer. + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_START)); + + // Loop until the completion of transfer or error + while (--mem_addr_len) { + // Write the next byte of data + MAP_I2CMasterDataPut(I2CA0_BASE, *mem_addr++); + // Transact over I2C to send the next byte + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT)); + } + return true; +} + +STATIC bool pyb_i2c_mem_write (byte addr, byte *mem_addr, uint mem_addr_len, byte *data, uint data_len) { + if (pyb_i2c_mem_addr_write (addr, mem_addr, mem_addr_len)) { + // Loop until the completion of transfer or error + while (data_len--) { + // Write the next byte of data + MAP_I2CMasterDataPut(I2CA0_BASE, *data++); + // Transact over I2C to send the byte + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT)); + } + // send the stop bit + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP)); + return true; + } + return false; +} + +STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop) { + // Set I2C codec slave address + MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, false); + // Write the first byte to the controller. + MAP_I2CMasterDataPut(I2CA0_BASE, *data++); + // Initiate the transfer. + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_START)); + + // Loop until the completion of transfer or error + while (--len) { + // Write the next byte of data + MAP_I2CMasterDataPut(I2CA0_BASE, *data++); + // Transact over I2C to send the byte + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_CONT)); + } + + // If a stop bit is to be sent, do it. + if (stop) { + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_SEND_STOP)); + } + return true; +} + +STATIC bool pyb_i2c_read(byte addr, byte *data, uint len) { + // Initiate a burst or single receive sequence + uint cmd = --len > 0 ? I2C_MASTER_CMD_BURST_RECEIVE_START : I2C_MASTER_CMD_SINGLE_RECEIVE; + // Set I2C codec slave address + MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, addr, true); + // Initiate the transfer. + RET_IF_ERR(pyb_i2c_transaction(cmd)); + // Loop until the completion of reception or error + while (len) { + // Receive the byte over I2C + *data++ = MAP_I2CMasterDataGet(I2CA0_BASE); + if (--len) { + // Continue with reception + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_CONT)); + } else { + // Complete the last reception + RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_BURST_RECEIVE_FINISH)); + } + } + + // Receive the last byte over I2C + *data = MAP_I2CMasterDataGet(I2CA0_BASE); + return true; +} + +STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) { + pyb_i2c_check_init(&pyb_i2c_obj); + // get the buffer to receive into + pyb_buf_get_for_recv(args[1].u_obj, vstr); + + // receive the data + if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) { + mp_raise_OSError(MP_EIO); + } +} + +STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) { + pyb_i2c_check_init(&pyb_i2c_obj); + // get the buffer to receive into + pyb_buf_get_for_recv(args[2].u_obj, vstr); + + // get the addresses + mp_uint_t i2c_addr = args[0].u_int; + mp_uint_t mem_addr = args[1].u_int; + // determine the width of mem_addr (1 or 2 bytes) + mp_uint_t mem_addr_size = args[3].u_int >> 3; + + // write the register address to be read from + if (pyb_i2c_mem_addr_write (i2c_addr, (byte *)&mem_addr, mem_addr_size)) { + // Read the specified length of data + if (!pyb_i2c_read (i2c_addr, (byte *)vstr->buf, vstr->len)) { + mp_raise_OSError(MP_EIO); + } + } else { + mp_raise_OSError(MP_EIO); + } +} + +/******************************************************************************/ +/* MicroPython bindings */ +/******************************************************************************/ +STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_i2c_obj_t *self = self_in; + if (self->baudrate > 0) { + mp_printf(print, "I2C(0, baudrate=%u)", self->baudrate); + } else { + mp_print_str(print, "I2C(0)"); + } +} + +STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_scl, ARG_sda, ARG_freq }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // make sure the baudrate is between the valid range + self->baudrate = MIN(MAX(args[ARG_freq].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ); + + // assign the pins + mp_obj_t pins[2] = {&pin_GP13, &pin_GP23}; // default (SDA, SCL) pins + if (args[ARG_scl].u_obj != MP_OBJ_NULL) { + pins[1] = args[ARG_scl].u_obj; + } + if (args[ARG_sda].u_obj != MP_OBJ_NULL) { + pins[0] = args[ARG_sda].u_obj; + } + pin_assign_pins_af(pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0); + + // init the I2C bus + i2c_init(self); + + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init); + + return mp_const_none; +} + +STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // check the id argument, if given + if (n_args > 0) { + if (all_args[0] != MP_OBJ_NEW_SMALL_INT(0)) { + mp_raise_OSError(MP_ENODEV); + } + --n_args; + ++all_args; + } + + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + + // setup the object + pyb_i2c_obj_t *self = &pyb_i2c_obj; + self->base.type = &pyb_i2c_type; + + // start the peripheral + pyb_i2c_init_helper(self, n_args, all_args, &kw_args); + + return (mp_obj_t)self; +} + +STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return pyb_i2c_init_helper(pos_args[0], n_args - 1, pos_args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init); + +STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) { + // disable the peripheral + MAP_I2CMasterDisable(I2CA0_BASE); + MAP_PRCMPeripheralClkDisable(PRCM_I2CA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // invalidate the baudrate + pyb_i2c_obj.baudrate = 0; + // unregister it with the sleep module + pyb_sleep_remove ((const mp_obj_t)self_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit); + +STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { + pyb_i2c_check_init(&pyb_i2c_obj); + mp_obj_t list = mp_obj_new_list(0, NULL); + for (uint addr = 0x08; addr <= 0x77; addr++) { + for (int i = 0; i < 3; i++) { + if (pyb_i2c_scan_device(addr)) { + mp_obj_list_append(list, mp_obj_new_int(addr)); + break; + } + } + } + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan); + +STATIC mp_obj_t pyb_i2c_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_i2c_readfrom_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_args, args); + + vstr_t vstr; + pyb_i2c_read_into(args, &vstr); + + // return the received data + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_obj, 3, pyb_i2c_readfrom); + +STATIC mp_obj_t pyb_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_i2c_readfrom_into_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_into_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_into_args, args); + + vstr_t vstr; + pyb_i2c_read_into(args, &vstr); + + // return the number of bytes received + return mp_obj_new_int(vstr.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 1, pyb_i2c_readfrom_into); + +STATIC mp_obj_t pyb_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_i2c_writeto_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_writeto_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_writeto_args, args); + + pyb_i2c_check_init(&pyb_i2c_obj); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[1].u_obj, &bufinfo, data); + + // send the data + if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) { + mp_raise_OSError(MP_EIO); + } + + // return the number of bytes written + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto); + +STATIC mp_obj_t pyb_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_i2c_readfrom_mem_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_args, args); + + vstr_t vstr; + pyb_i2c_readmem_into (args, &vstr); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 1, pyb_i2c_readfrom_mem); + +STATIC const mp_arg_t pyb_i2c_readfrom_mem_into_args[] = { + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, +}; + +STATIC mp_obj_t pyb_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_i2c_readfrom_mem_into_args, args); + + // get the buffer to read into + vstr_t vstr; + pyb_i2c_readmem_into (args, &vstr); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into); + +STATIC mp_obj_t pyb_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_readfrom_mem_into_args), pyb_i2c_readfrom_mem_into_args, args); + + pyb_i2c_check_init(&pyb_i2c_obj); + + // get the buffer to write from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[2].u_obj, &bufinfo, data); + + // get the addresses + mp_uint_t i2c_addr = args[0].u_int; + mp_uint_t mem_addr = args[1].u_int; + // determine the width of mem_addr (1 or 2 bytes) + mp_uint_t mem_addr_size = args[3].u_int >> 3; + + // write the register address to write to. + if (pyb_i2c_mem_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len)) { + return mp_const_none; + } + + mp_raise_OSError(MP_EIO); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem); + +STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&pyb_i2c_readfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&pyb_i2c_readfrom_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&pyb_i2c_writeto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&pyb_i2c_readfrom_mem_obj) }, + { MP_ROM_QSTR(MP_QSTR_readfrom_mem_into), MP_ROM_PTR(&pyb_i2c_readfrom_mem_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&pyb_i2c_writeto_mem_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); + +const mp_obj_type_t pyb_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = pyb_i2c_print, + .make_new = pyb_i2c_make_new, + .locals_dict = (mp_obj_t)&pyb_i2c_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.h b/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.h new file mode 100755 index 0000000..dcc3f04 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybi2c.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBI2C_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBI2C_H + +extern const mp_obj_type_t pyb_i2c_type; + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBI2C_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybpin.c b/src/openmv/src/micropython/ports/cc3200/mods/pybpin.c new file mode 100755 index 0000000..9e7526f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybpin.c @@ -0,0 +1,962 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "gpio.h" +#include "interrupt.h" +#include "pybpin.h" +#include "mpirq.h" +#include "pins.h" +#include "pybsleep.h" +#include "mpexception.h" +#include "mperror.h" + + +/// \moduleref pyb +/// \class Pin - control I/O pins +/// +/****************************************************************************** +DECLARE PRIVATE FUNCTIONS +******************************************************************************/ +STATIC pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); +STATIC pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit); +STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type); +STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type); +STATIC void pin_deassign (pin_obj_t* pin); +STATIC void pin_obj_configure (const pin_obj_t *self); +STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx); +STATIC void pin_irq_enable (mp_obj_t self_in); +STATIC void pin_irq_disable (mp_obj_t self_in); +STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority); +STATIC void pin_validate_mode (uint mode); +STATIC void pin_validate_pull (uint pull); +STATIC void pin_validate_drive (uint strength); +STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8_t *unit, uint8_t *type); +STATIC uint8_t pin_get_value(const pin_obj_t* self); +STATIC void GPIOA0IntHandler (void); +STATIC void GPIOA1IntHandler (void); +STATIC void GPIOA2IntHandler (void); +STATIC void GPIOA3IntHandler (void); +STATIC void EXTI_Handler(uint port); + +/****************************************************************************** +DEFINE CONSTANTS +******************************************************************************/ +#define PYBPIN_NUM_WAKE_PINS (6) +#define PYBPIN_WAKES_NOT (-1) + +#define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module +#define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode + +#define PYB_PIN_FALLING_EDGE 0x01 +#define PYB_PIN_RISING_EDGE 0x02 +#define PYB_PIN_LOW_LEVEL 0x04 +#define PYB_PIN_HIGH_LEVEL 0x08 + +/****************************************************************************** +DEFINE TYPES +******************************************************************************/ +typedef struct { + bool active; + int8_t lpds; + int8_t hib; +} pybpin_wake_pin_t; + +/****************************************************************************** +DECLARE PRIVATE DATA +******************************************************************************/ +STATIC const mp_irq_methods_t pin_irq_methods; +STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] = + { {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, + {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, + {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, + {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, + {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT}, + {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT} } ; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void pin_init0(void) { +// this initalization also reconfigures the JTAG/SWD pins +#ifndef DEBUG + // assign all pins to the GPIO module so that peripherals can be connected to any + // pins without conflicts after a soft reset + const mp_map_t *named_map = &pin_board_pins_locals_dict.map; + for (uint i = 0; i < named_map->used - 1; i++) { + pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value; + pin_deassign (pin); + } +#endif +} + +// C API used to convert a user-supplied pin name into an ordinal pin number. +pin_obj_t *pin_find(mp_obj_t user_obj) { + pin_obj_t *pin_obj; + + // if a pin was provided, use it + if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + pin_obj = user_obj; + return pin_obj; + } + + // otherwise see if the pin name matches a cpu pin + pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj); + if (pin_obj) { + return pin_obj; + } + + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint strength) { + self->mode = mode, self->pull = pull, self->strength = strength; + // if af is -1, then we want to keep it as it is + if (af != -1) { + self->af = af; + } + + // if value is -1, then we want to keep it as it is + if (value != -1) { + self->value = value; + } + + // mark the pin as used + self->used = true; + pin_obj_configure ((const pin_obj_t *)self); + + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure); +} + +void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit) { + for (int i = 0; i < n_pins; i++) { + pin_free_af_from_pins(fn, unit, i); + if (pins[i] != mp_const_none) { + pin_obj_t *pin = pin_find(pins[i]); + pin_config (pin, pin_find_af_index(pin, fn, unit, i), 0, pull, -1, PIN_STRENGTH_2MA); + } + } +} + +uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type) { + pin_obj_t *pin_o = pin_find(pin); + for (int i = 0; i < pin_o->num_afs; i++) { + if (pin_o->af_list[i].fn == fn && pin_o->af_list[i].type == type) { + return pin_o->af_list[i].unit; + } + } + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) { + pin_obj_t *pin_o = pin_find(pin); + for (int i = 0; i < pin_o->num_afs; i++) { + if (pin_o->af_list[i].fn == fn && pin_o->af_list[i].unit == unit) { + return pin_o->af_list[i].type; + } + } + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) { + int8_t af = pin_obj_find_af(pin, fn, unit, type); + if (af < 0) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + return af; +} + +/****************************************************************************** +DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { + const mp_map_t *named_map = &named_pins->map; + mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t*)named_map, name, MP_MAP_LOOKUP); + if (named_elem != NULL && named_elem->value != NULL) { + return named_elem->value; + } + return NULL; +} + +STATIC pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit) { + const mp_map_t *named_map = &named_pins->map; + for (uint i = 0; i < named_map->used; i++) { + if ((((pin_obj_t *)named_map->table[i].value)->port == port) && + (((pin_obj_t *)named_map->table[i].value)->bit == bit)) { + return named_map->table[i].value; + } + } + return NULL; +} + +STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) { + for (int i = 0; i < pin->num_afs; i++) { + if (pin->af_list[i].fn == fn && pin->af_list[i].unit == unit && pin->af_list[i].type == type) { + return pin->af_list[i].idx; + } + } + return -1; +} + +STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type) { + const mp_map_t *named_map = &pin_board_pins_locals_dict.map; + for (uint i = 0; i < named_map->used - 1; i++) { + pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value; + // af is different than GPIO + if (pin->af > PIN_MODE_0) { + // check if the pin supports the target af + int af = pin_obj_find_af(pin, fn, unit, type); + if (af > 0 && af == pin->af) { + // the pin supports the target af, de-assign it + pin_deassign (pin); + } + } + } +} + +STATIC void pin_deassign (pin_obj_t* pin) { + pin_config (pin, PIN_MODE_0, GPIO_DIR_MODE_IN, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA); + pin->used = false; +} + +STATIC void pin_obj_configure (const pin_obj_t *self) { + uint32_t type; + if (self->mode == PIN_TYPE_ANALOG) { + type = PIN_TYPE_ANALOG; + } else { + type = self->pull; + uint32_t direction = self->mode; + if (direction == PIN_TYPE_OD || direction == GPIO_DIR_MODE_ALT_OD) { + direction = GPIO_DIR_MODE_OUT; + type |= PIN_TYPE_OD; + } + if (self->mode != GPIO_DIR_MODE_ALT && self->mode != GPIO_DIR_MODE_ALT_OD) { + // enable the peripheral clock for the GPIO port of this pin + switch (self->port) { + case PORT_A0: + MAP_PRCMPeripheralClkEnable(PRCM_GPIOA0, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + break; + case PORT_A1: + MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + break; + case PORT_A2: + MAP_PRCMPeripheralClkEnable(PRCM_GPIOA2, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + break; + case PORT_A3: + MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + break; + default: + break; + } + // configure the direction + MAP_GPIODirModeSet(self->port, self->bit, direction); + // set the pin value + if (self->value) { + MAP_GPIOPinWrite(self->port, self->bit, self->bit); + } else { + MAP_GPIOPinWrite(self->port, self->bit, 0); + } + } + // now set the alternate function + MAP_PinModeSet (self->pin_num, self->af); + } + MAP_PinConfigSet(self->pin_num, self->strength, type); +} + +STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin, uint *idx) { + // pin_num is actually : (package_pin - 1) + switch (self->pin_num) { + case 56: // GP2 + *hib_pin = PRCM_HIB_GPIO2; + *idx = 0; + break; + case 58: // GP4 + *hib_pin = PRCM_HIB_GPIO4; + *idx = 1; + break; + case 3: // GP13 + *hib_pin = PRCM_HIB_GPIO13; + *idx = 2; + break; + case 7: // GP17 + *hib_pin = PRCM_HIB_GPIO17; + *idx = 3; + break; + case 1: // GP11 + *hib_pin = PRCM_HIB_GPIO11; + *idx = 4; + break; + case 16: // GP24 + *hib_pin = PRCM_HIB_GPIO24; + *idx = 5; + break; + default: + *idx = 0xFF; + break; + } +} + +STATIC void pin_irq_enable (mp_obj_t self_in) { + const pin_obj_t *self = self_in; + uint hib_pin, idx; + + pin_get_hibernate_pin_and_idx (self, &hib_pin, &idx); + if (idx < PYBPIN_NUM_WAKE_PINS) { + if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) { + // enable GPIO as a wake source during LPDS + MAP_PRCMLPDSWakeUpGPIOSelect(idx, pybpin_wake_pin[idx].lpds); + MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO); + } + + if (pybpin_wake_pin[idx].hib != PYBPIN_WAKES_NOT) { + // enable GPIO as a wake source during hibernate + MAP_PRCMHibernateWakeUpGPIOSelect(hib_pin, pybpin_wake_pin[idx].hib); + MAP_PRCMHibernateWakeupSourceEnable(hib_pin); + } + else { + MAP_PRCMHibernateWakeupSourceDisable(hib_pin); + } + } + // if idx is invalid, the pin supports active interrupts for sure + if (idx >= PYBPIN_NUM_WAKE_PINS || pybpin_wake_pin[idx].active) { + MAP_GPIOIntClear(self->port, self->bit); + MAP_GPIOIntEnable(self->port, self->bit); + } + // in case it was enabled before + else if (idx < PYBPIN_NUM_WAKE_PINS && !pybpin_wake_pin[idx].active) { + MAP_GPIOIntDisable(self->port, self->bit); + } +} + +STATIC void pin_irq_disable (mp_obj_t self_in) { + const pin_obj_t *self = self_in; + uint hib_pin, idx; + + pin_get_hibernate_pin_and_idx (self, &hib_pin, &idx); + if (idx < PYBPIN_NUM_WAKE_PINS) { + if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) { + // disable GPIO as a wake source during LPDS + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); + } + if (pybpin_wake_pin[idx].hib != PYBPIN_WAKES_NOT) { + // disable GPIO as a wake source during hibernate + MAP_PRCMHibernateWakeupSourceDisable(hib_pin); + } + } + // not need to check for the active flag, it's safe to disable it anyway + MAP_GPIOIntDisable(self->port, self->bit); +} + +STATIC int pin_irq_flags (mp_obj_t self_in) { + const pin_obj_t *self = self_in; + return self->irq_flags; +} + +STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) { + void *handler; + uint32_t intnum; + + // configure the interrupt type + MAP_GPIOIntTypeSet(self->port, self->bit, intmode); + switch (self->port) { + case GPIOA0_BASE: + handler = GPIOA0IntHandler; + intnum = INT_GPIOA0; + break; + case GPIOA1_BASE: + handler = GPIOA1IntHandler; + intnum = INT_GPIOA1; + break; + case GPIOA2_BASE: + handler = GPIOA2IntHandler; + intnum = INT_GPIOA2; + break; + case GPIOA3_BASE: + default: + handler = GPIOA3IntHandler; + intnum = INT_GPIOA3; + break; + } + MAP_GPIOIntRegister(self->port, handler); + // set the interrupt to the lowest priority, to make sure that + // no other ISRs will be preemted by this one + MAP_IntPrioritySet(intnum, priority); +} + +STATIC void pin_validate_mode (uint mode) { + if (mode != GPIO_DIR_MODE_IN && mode != GPIO_DIR_MODE_OUT && mode != PIN_TYPE_OD && + mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} +STATIC void pin_validate_pull (uint pull) { + if (pull != PIN_TYPE_STD && pull != PIN_TYPE_STD_PU && pull != PIN_TYPE_STD_PD) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void pin_validate_drive(uint strength) { + if (strength != PIN_STRENGTH_2MA && strength != PIN_STRENGTH_4MA && strength != PIN_STRENGTH_6MA) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } +} + +STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8_t *unit, uint8_t *type) { + for (int i = 0; i < pin->num_afs; i++) { + if (pin->af_list[i].idx == idx) { + *fn = pin->af_list[i].fn; + *unit = pin->af_list[i].unit; + *type = pin->af_list[i].type; + return; + } + } + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC uint8_t pin_get_value (const pin_obj_t* self) { + uint32_t value; + bool setdir = false; + if (self->mode == PIN_TYPE_OD || self->mode == GPIO_DIR_MODE_ALT_OD) { + setdir = true; + // configure the direction to IN for a moment in order to read the pin value + MAP_GPIODirModeSet(self->port, self->bit, GPIO_DIR_MODE_IN); + } + // now get the value + value = MAP_GPIOPinRead(self->port, self->bit); + if (setdir) { + // set the direction back to output + MAP_GPIODirModeSet(self->port, self->bit, GPIO_DIR_MODE_OUT); + if (self->value) { + MAP_GPIOPinWrite(self->port, self->bit, self->bit); + } else { + MAP_GPIOPinWrite(self->port, self->bit, 0); + } + } + // return it + return value ? 1 : 0; +} + +STATIC void GPIOA0IntHandler (void) { + EXTI_Handler(GPIOA0_BASE); +} + +STATIC void GPIOA1IntHandler (void) { + EXTI_Handler(GPIOA1_BASE); +} + +STATIC void GPIOA2IntHandler (void) { + EXTI_Handler(GPIOA2_BASE); +} + +STATIC void GPIOA3IntHandler (void) { + EXTI_Handler(GPIOA3_BASE); +} + +// common interrupt handler +STATIC void EXTI_Handler(uint port) { + uint32_t bits = MAP_GPIOIntStatus(port, true); + MAP_GPIOIntClear(port, bits); + + // might be that we have more than one pin interrupt pending + // therefore we must loop through all of the 8 possible bits + for (int i = 0; i < 8; i++) { + uint32_t bit = (1 << i); + if (bit & bits) { + pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit); + if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) { + // read the pin value (hoping that the pin level has remained stable) + self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE; + } else { + // same as the triggers + self->irq_flags = self->irq_trigger; + } + mp_irq_handler(mp_irq_find(self)); + // always clear the flags after leaving the user handler + self->irq_flags = 0; + } + } +} + + +/******************************************************************************/ +// MicroPython bindings + +STATIC const mp_arg_t pin_init_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} }, + { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, +}; +#define pin_INIT_NUM_ARGS MP_ARRAY_SIZE(pin_init_args) + +STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[pin_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args); + + // get the io mode + uint mode; + // default is input + if (args[0].u_obj == MP_OBJ_NULL) { + mode = GPIO_DIR_MODE_IN; + } else { + mode = mp_obj_get_int(args[0].u_obj); + pin_validate_mode (mode); + } + + // get the pull type + uint pull; + if (args[1].u_obj == mp_const_none) { + pull = PIN_TYPE_STD; + } else { + pull = mp_obj_get_int(args[1].u_obj); + pin_validate_pull (pull); + } + + // get the value + int value = -1; + if (args[2].u_obj != MP_OBJ_NULL) { + if (mp_obj_is_true(args[2].u_obj)) { + value = 1; + } else { + value = 0; + } + } + + // get the strenght + uint strength = args[3].u_int; + pin_validate_drive(strength); + + // get the alternate function + int af = args[4].u_int; + if (mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) { + if (af == -1) { + af = 0; + } else { + goto invalid_args; + } + } else if (af < -1 || af > 15) { + goto invalid_args; + } + + // check for a valid af and then free it from any other pins + if (af > PIN_MODE_0) { + uint8_t fn, unit, type; + pin_validate_af (self, af, &fn, &unit, &type); + pin_free_af_from_pins(fn, unit, type); + } + pin_config (self, af, mode, pull, value, strength); + + return mp_const_none; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_obj_t *self = self_in; + uint32_t pull = self->pull; + uint32_t drive = self->strength; + + // pin name + mp_printf(print, "Pin('%q'", self->name); + + // pin mode + qstr mode_qst; + uint32_t mode = self->mode; + if (mode == GPIO_DIR_MODE_IN) { + mode_qst = MP_QSTR_IN; + } else if (mode == GPIO_DIR_MODE_OUT) { + mode_qst = MP_QSTR_OUT; + } else if (mode == GPIO_DIR_MODE_ALT) { + mode_qst = MP_QSTR_ALT; + } else if (mode == GPIO_DIR_MODE_ALT_OD) { + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; + } else { + mode_qst = MP_QSTR_OPEN_DRAIN; + } + mp_printf(print, ", mode=Pin.%q", mode_qst); + + // pin pull + qstr pull_qst; + if (pull == PIN_TYPE_STD) { + mp_printf(print, ", pull=%q", MP_QSTR_None); + } else { + if (pull == PIN_TYPE_STD_PU) { + pull_qst = MP_QSTR_PULL_UP; + } else { + pull_qst = MP_QSTR_PULL_DOWN; + } + mp_printf(print, ", pull=Pin.%q", pull_qst); + } + + // pin drive + qstr drv_qst; + if (drive == PIN_STRENGTH_2MA) { + drv_qst = MP_QSTR_LOW_POWER; + } else if (drive == PIN_STRENGTH_4MA) { + drv_qst = MP_QSTR_MED_POWER; + } else { + drv_qst = MP_QSTR_HIGH_POWER; + } + mp_printf(print, ", drive=Pin.%q", drv_qst); + + // pin af + int alt = (self->af == 0) ? -1 : self->af; + mp_printf(print, ", alt=%d)", alt); +} + +STATIC mp_obj_t pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + + return (mp_obj_t)pin; +} + +STATIC mp_obj_t pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); + +STATIC mp_obj_t pin_value(size_t n_args, const mp_obj_t *args) { + pin_obj_t *self = args[0]; + if (n_args == 1) { + // get the value + return MP_OBJ_NEW_SMALL_INT(pin_get_value(self)); + } else { + // set the pin value + if (mp_obj_is_true(args[1])) { + self->value = 1; + MAP_GPIOPinWrite(self->port, self->bit, self->bit); + } else { + self->value = 0; + MAP_GPIOPinWrite(self->port, self->bit, 0); + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); + +STATIC mp_obj_t pin_id(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_QSTR(self->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_id_obj, pin_id); + +STATIC mp_obj_t pin_mode(size_t n_args, const mp_obj_t *args) { + pin_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_int(self->mode); + } else { + uint32_t mode = mp_obj_get_int(args[1]); + pin_validate_mode (mode); + self->mode = mode; + pin_obj_configure(self); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mode_obj, 1, 2, pin_mode); + +STATIC mp_obj_t pin_pull(size_t n_args, const mp_obj_t *args) { + pin_obj_t *self = args[0]; + if (n_args == 1) { + if (self->pull == PIN_TYPE_STD) { + return mp_const_none; + } + return mp_obj_new_int(self->pull); + } else { + uint32_t pull; + if (args[1] == mp_const_none) { + pull = PIN_TYPE_STD; + } else { + pull = mp_obj_get_int(args[1]); + pin_validate_pull (pull); + } + self->pull = pull; + pin_obj_configure(self); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_pull_obj, 1, 2, pin_pull); + +STATIC mp_obj_t pin_drive(size_t n_args, const mp_obj_t *args) { + pin_obj_t *self = args[0]; + if (n_args == 1) { + return mp_obj_new_int(self->strength); + } else { + uint32_t strength = mp_obj_get_int(args[1]); + pin_validate_drive (strength); + self->strength = strength; + pin_obj_configure(self); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_drive_obj, 1, 2, pin_drive); + +STATIC mp_obj_t pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_t _args[2] = {self_in, *args}; + return pin_value (n_args + 1, _args); +} + +STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t af[2]; + mp_obj_t afs = mp_obj_new_list(0, NULL); + + for (int i = 0; i < self->num_afs; i++) { + af[0] = MP_OBJ_NEW_QSTR(self->af_list[i].name); + af[1] = mp_obj_new_int(self->af_list[i].idx); + mp_obj_list_append(afs, mp_obj_new_tuple(MP_ARRAY_SIZE(af), af)); + } + return afs; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list); + +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); + pin_obj_t *self = pos_args[0]; + + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); + + // verify and translate the interrupt mode + uint mp_trigger = mp_obj_get_int(args[0].u_obj); + uint trigger; + if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) { + trigger = GPIO_BOTH_EDGES; + } else { + switch (mp_trigger) { + case PYB_PIN_FALLING_EDGE: + trigger = GPIO_FALLING_EDGE; + break; + case PYB_PIN_RISING_EDGE: + trigger = GPIO_RISING_EDGE; + break; + case PYB_PIN_LOW_LEVEL: + trigger = GPIO_LOW_LEVEL; + break; + case PYB_PIN_HIGH_LEVEL: + trigger = GPIO_HIGH_LEVEL; + break; + default: + goto invalid_args; + } + } + + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) { + goto invalid_args; + } + + // get the wake info from this pin + uint hib_pin, idx; + pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx); + if (pwrmode & PYB_PWR_MODE_LPDS) { + if (idx >= PYBPIN_NUM_WAKE_PINS) { + goto invalid_args; + } + // wake modes are different in LDPS + uint wake_mode; + switch (trigger) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_LPDS_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_LPDS_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_LPDS_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_LPDS_HIGH_LEVEL; + break; + default: + goto invalid_args; + break; + } + + // first clear the lpds value from all wake-able pins + for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) { + pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT; + } + + // enable this pin as a wake-up source during LPDS + pybpin_wake_pin[idx].lpds = wake_mode; + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + // this pin was the previous LPDS wake source, so disable it completely + if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) { + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); + } + pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT; + } + + if (pwrmode & PYB_PWR_MODE_HIBERNATE) { + if (idx >= PYBPIN_NUM_WAKE_PINS) { + goto invalid_args; + } + // wake modes are different in hibernate + uint wake_mode; + switch (trigger) { + case GPIO_FALLING_EDGE: + wake_mode = PRCM_HIB_FALL_EDGE; + break; + case GPIO_RISING_EDGE: + wake_mode = PRCM_HIB_RISE_EDGE; + break; + case GPIO_LOW_LEVEL: + wake_mode = PRCM_HIB_LOW_LEVEL; + break; + case GPIO_HIGH_LEVEL: + wake_mode = PRCM_HIB_HIGH_LEVEL; + break; + default: + goto invalid_args; + break; + } + + // enable this pin as wake-up source during hibernate + pybpin_wake_pin[idx].hib = wake_mode; + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT; + } + + // we need to update the callback atomically, so we disable the + // interrupt before we update anything. + pin_irq_disable(self); + if (pwrmode & PYB_PWR_MODE_ACTIVE) { + // register the interrupt + pin_extint_register((pin_obj_t *)self, trigger, priority); + if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].active = true; + } + } else if (idx < PYBPIN_NUM_WAKE_PINS) { + pybpin_wake_pin[idx].active = false; + } + + // all checks have passed, we can create the irq object + mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods); + if (pwrmode & PYB_PWR_MODE_LPDS) { + pyb_sleep_set_gpio_lpds_callback (_irq); + } + + // save the mp_trigge for later + self->irq_trigger = mp_trigger; + + // enable the interrupt just before leaving + pin_irq_enable(self); + + return _irq; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); + +STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&pin_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&pin_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&pin_pull_obj) }, + { MP_ROM_QSTR(MP_QSTR_drive), MP_ROM_PTR(&pin_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_alt_list), MP_ROM_PTR(&pin_alt_list_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) }, + + // class attributes + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DIR_MODE_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DIR_MODE_OUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(PIN_TYPE_OD) }, + { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_DIR_MODE_ALT) }, + { MP_ROM_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_ROM_INT(GPIO_DIR_MODE_ALT_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(PIN_TYPE_STD_PU) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(PIN_TYPE_STD_PD) }, + { MP_ROM_QSTR(MP_QSTR_LOW_POWER), MP_ROM_INT(PIN_STRENGTH_2MA) }, + { MP_ROM_QSTR(MP_QSTR_MED_POWER), MP_ROM_INT(PIN_STRENGTH_4MA) }, + { MP_ROM_QSTR(MP_QSTR_HIGH_POWER), MP_ROM_INT(PIN_STRENGTH_6MA) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(PYB_PIN_FALLING_EDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(PYB_PIN_RISING_EDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_ROM_INT(PYB_PIN_LOW_LEVEL) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_ROM_INT(PYB_PIN_HIGH_LEVEL) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); + +const mp_obj_type_t pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pin_print, + .make_new = pin_make_new, + .call = pin_call, + .locals_dict = (mp_obj_t)&pin_locals_dict, +}; + +STATIC const mp_irq_methods_t pin_irq_methods = { + .init = pin_irq, + .enable = pin_irq_enable, + .disable = pin_irq_disable, + .flags = pin_irq_flags, +}; + +STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_named_pins_obj_t *self = self_in; + mp_printf(print, "", self->name); +} + +const mp_obj_type_t pin_board_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_board, + .print = pin_named_pins_obj_print, + .locals_dict = (mp_obj_t)&pin_board_pins_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybpin.h b/src/openmv/src/micropython/ports/cc3200/mods/pybpin.h new file mode 100755 index 0000000..74f0af2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybpin.h @@ -0,0 +1,140 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBPIN_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBPIN_H + +enum { + PORT_A0 = GPIOA0_BASE, + PORT_A1 = GPIOA1_BASE, + PORT_A2 = GPIOA2_BASE, + PORT_A3 = GPIOA3_BASE, +}; + +enum { + PIN_FN_UART = 0, + PIN_FN_SPI, + PIN_FN_I2S, + PIN_FN_I2C, + PIN_FN_TIM, + PIN_FN_SD, + PIN_FN_ADC, +}; + +enum { + PIN_TYPE_UART_TX = 0, + PIN_TYPE_UART_RX, + PIN_TYPE_UART_RTS, + PIN_TYPE_UART_CTS, +}; + +enum { + PIN_TYPE_SPI_CLK = 0, + PIN_TYPE_SPI_MOSI, + PIN_TYPE_SPI_MISO, + PIN_TYPE_SPI_CS0, +}; + +enum { + PIN_TYPE_I2S_CLK = 0, + PIN_TYPE_I2S_FS, + PIN_TYPE_I2S_DAT0, + PIN_TYPE_I2S_DAT1, +}; + +enum { + PIN_TYPE_I2C_SDA = 0, + PIN_TYPE_I2C_SCL, +}; + +enum { + PIN_TYPE_TIM_PWM = 0, +}; + +enum { + PIN_TYPE_SD_CLK = 0, + PIN_TYPE_SD_CMD, + PIN_TYPE_SD_DAT0, +}; + +enum { + PIN_TYPE_ADC_CH0 = 0, + PIN_TYPE_ADC_CH1, + PIN_TYPE_ADC_CH2, + PIN_TYPE_ADC_CH3, +}; + +typedef struct { + qstr name; + int8_t idx; + uint8_t fn; + uint8_t unit; + uint8_t type; +} pin_af_t; + +typedef struct { + const mp_obj_base_t base; + const qstr name; + const uint32_t port; + const pin_af_t *af_list; + uint16_t pull; + const uint8_t bit; + const uint8_t pin_num; + int8_t af; + uint8_t strength; + uint8_t mode; // this is now a combination of type and mode + const uint8_t num_afs; // 255 AFs + uint8_t value; + uint8_t used; + uint8_t irq_trigger; + uint8_t irq_flags; +} pin_obj_t; + +extern const mp_obj_type_t pin_type; + +typedef struct { + const char *name; + const pin_obj_t *pin; +} pin_named_pin_t; + +typedef struct { + mp_obj_base_t base; + qstr name; + const pin_named_pin_t *named_pins; +} pin_named_pins_obj_t; + +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_dict_t pin_board_pins_locals_dict; + +void pin_init0(void); +void pin_config(pin_obj_t *self, int af, uint mode, uint type, int value, uint strength); +pin_obj_t *pin_find(mp_obj_t user_obj); +void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit); +uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type); +uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit); +int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);; + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBPIN_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.c b/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.c new file mode 100755 index 0000000..e7b9cf2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.c @@ -0,0 +1,485 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "lib/timeutils/timeutils.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "pybrtc.h" +#include "mpirq.h" +#include "pybsleep.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "mpexception.h" + +/// \moduleref pyb +/// \class RTC - real time clock + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_irq_methods_t pyb_rtc_irq_methods; +STATIC pyb_rtc_obj_t pyb_rtc_obj; + +/****************************************************************************** + FUNCTION-LIKE MACROS + ******************************************************************************/ +#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000) +#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024) + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs); +STATIC uint32_t pyb_rtc_reset (void); +STATIC void pyb_rtc_disable_interupt (void); +STATIC void pyb_rtc_irq_enable (mp_obj_t self_in); +STATIC void pyb_rtc_irq_disable (mp_obj_t self_in); +STATIC int pyb_rtc_irq_flags (mp_obj_t self_in); +STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds); +STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime); +STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds); +STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2); + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +__attribute__ ((section (".boot"))) +void pyb_rtc_pre_init(void) { + // only if comming out of a power-on reset + if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) { + // Mark the RTC in use first + MAP_PRCMRTCInUseSet(); + // reset the time and date + pyb_rtc_reset(); + } +} + +void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) { + uint16_t cycles; + MAP_PRCMRTCGet (secs, &cycles); + *msecs = RTC_CYCLES_U16MS(cycles); +} + +uint32_t pyb_rtc_get_seconds (void) { + uint32_t seconds; + uint16_t mseconds; + pyb_rtc_get_time(&seconds, &mseconds); + return seconds; +} + +void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) { + uint32_t c_seconds; + uint16_t c_mseconds; + // get the current time + pyb_rtc_get_time(&c_seconds, &c_mseconds); + // calculate the future seconds + *f_seconds = c_seconds + (a_mseconds / 1000); + // calculate the "remaining" future mseconds + *f_mseconds = a_mseconds % 1000; + // add the current milliseconds + rtc_msec_add (c_mseconds, f_seconds, f_mseconds); +} + +void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) { + if (self->repeat) { + uint32_t f_seconds, c_seconds; + uint16_t f_mseconds, c_mseconds; + + pyb_rtc_get_time(&c_seconds, &c_mseconds); + + // substract the time elapsed between waking up and setting up the alarm again + int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms); + int32_t next_alarm = self->alarm_ms - wake_ms; + next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS; + pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds); + + // now configure the alarm + pyb_rtc_set_alarm (self, f_seconds, f_mseconds); + } +} + +void pyb_rtc_disable_alarm (void) { + pyb_rtc_obj.alarmset = false; + pyb_rtc_disable_interupt(); +} + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) { + // add the RTC access time + rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs); + // convert from mseconds to cycles + msecs = RTC_U16MS_CYCLES(msecs); + // now set the time + MAP_PRCMRTCSet(secs, msecs); +} + +STATIC uint32_t pyb_rtc_reset (void) { + // fresh reset; configure the RTC Calendar + // set the date to 1st Jan 2015 + // set the time to 00:00:00 + uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0); + // disable any running alarm + pyb_rtc_disable_alarm(); + // Now set the RTC calendar time + pyb_rtc_set_time(seconds, 0); + return seconds; +} + +STATIC void pyb_rtc_disable_interupt (void) { + uint primsk = disable_irq(); + MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); + (void)MAP_PRCMIntStatus(); + enable_irq(primsk); +} + +STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) { + pyb_rtc_obj_t *self = self_in; + // we always need interrupts if repeat is enabled + if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) { + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + } else { // just in case it was already enabled before + MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); + } + self->irq_enabled = true; +} + +STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) { + pyb_rtc_obj_t *self = self_in; + self->irq_enabled = false; + if (!self->repeat) { // we always need interrupts if repeat is enabled + pyb_rtc_disable_interupt(); + } +} + +STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) { + pyb_rtc_obj_t *self = self_in; + return self->irq_flags; +} + +STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) { + timeutils_struct_time_t tm; + uint32_t useconds; + + // set date and time + mp_obj_t *items; + size_t len; + mp_obj_get_array(datetime, &len, &items); + + // verify the tuple + if (len < 3 || len > 8) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + + tm.tm_year = mp_obj_get_int(items[0]); + tm.tm_mon = mp_obj_get_int(items[1]); + tm.tm_mday = mp_obj_get_int(items[2]); + if (len < 7) { + useconds = 0; + } else { + useconds = mp_obj_get_int(items[6]); + } + if (len < 6) { + tm.tm_sec = 0; + } else { + tm.tm_sec = mp_obj_get_int(items[5]); + } + if (len < 5) { + tm.tm_min = 0; + } else { + tm.tm_min = mp_obj_get_int(items[4]); + } + if (len < 4) { + tm.tm_hour = 0; + } else { + tm.tm_hour = mp_obj_get_int(items[3]); + } + *seconds = timeutils_seconds_since_2000(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + return useconds; +} + +/// The 8-tuple has the same format as CPython's datetime object: +/// +/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None) +/// +STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) { + uint32_t seconds; + uint32_t useconds; + + if (datetime != MP_OBJ_NULL) { + useconds = pyb_rtc_datetime_s_us(datetime, &seconds); + pyb_rtc_set_time (seconds, useconds / 1000); + } else { + seconds = pyb_rtc_reset(); + } + + // set WLAN time and date, this is needed to verify certificates + wlan_set_current_time(seconds); + return mp_const_none; +} + +STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) { + // disable the interrupt before updating anything + if (self->irq_enabled) { + MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR); + } + // set the match value + MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds)); + self->alarmset = true; + self->alarm_time_s = seconds; + self->alarm_time_ms = mseconds; + // enabled the interrupts again if applicable + if (self->irq_enabled || self->repeat) { + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + } +} + +STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) { + if (msecs_1 + *msecs_2 >= 1000) { // larger than one second + *msecs_2 = (msecs_1 + *msecs_2) - 1000; + *secs += 1; // carry flag + } else { + // simply add the mseconds + *msecs_2 = msecs_1 + *msecs_2; + } +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC const mp_arg_t pyb_rtc_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_datetime, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_rtc_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_rtc_init_args, args); + + // check the peripheral id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + + // setup the object + pyb_rtc_obj_t *self = &pyb_rtc_obj; + self->base.type = &pyb_rtc_type; + + // set the time and date + pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj); + + // pass it to the sleep module + pyb_sleep_set_rtc_obj (self); + + // return constant object + return (mp_obj_t)&pyb_rtc_obj; +} + +STATIC mp_obj_t pyb_rtc_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_rtc_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_rtc_init_args[1], args); + return pyb_rtc_datetime(pos_args[0], args[0].u_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_init_obj, 1, pyb_rtc_init); + +STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) { + timeutils_struct_time_t tm; + uint32_t seconds; + uint16_t mseconds; + + // get the time from the RTC + pyb_rtc_get_time(&seconds, &mseconds); + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(mseconds * 1000), + mp_const_none + }; + return mp_obj_new_tuple(8, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now); + +STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) { + pyb_rtc_reset(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit); + +STATIC mp_obj_t pyb_rtc_alarm(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + pyb_rtc_obj_t *self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args); + + // check the alarm id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + + uint32_t f_seconds; + uint16_t f_mseconds; + bool repeat = args[2].u_bool; + if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given + // repeat cannot be used with a datetime tuple + if (repeat) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000; + } else { // then it must be an integer + self->alarm_ms = mp_obj_get_int(args[1].u_obj); + pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds); + } + + // store the repepat flag + self->repeat = repeat; + + // now configure the alarm + pyb_rtc_set_alarm (self, f_seconds, f_mseconds); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm); + +STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) { + pyb_rtc_obj_t *self = args[0]; + int32_t ms_left; + uint32_t c_seconds; + uint16_t c_mseconds; + + // only alarm id 0 is available + if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + mp_raise_OSError(MP_ENODEV); + } + + // get the current time + pyb_rtc_get_time(&c_seconds, &c_mseconds); + + // calculate the ms left + ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds); + if (!self->alarmset || ms_left < 0) { + ms_left = 0; + } + return mp_obj_new_int(ms_left); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left); + +STATIC mp_obj_t pyb_rtc_alarm_cancel(size_t n_args, const mp_obj_t *args) { + // only alarm id 0 is available + if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + mp_raise_OSError(MP_ENODEV); + } + // disable the alarm + pyb_rtc_disable_alarm(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel); + +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); + pyb_rtc_obj_t *self = pos_args[0]; + + // save the power mode data for later + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) { + goto invalid_args; + } + + // check the trigger + if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) { + self->pwrmode = pwrmode; + pyb_rtc_irq_enable((mp_obj_t)self); + } else { + goto invalid_args; + } + + // the interrupt priority is ignored since it's already set to to highest level by the sleep module + // to make sure that the wakeup irqs are always called first when resuming from sleep + + // create the callback + mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods); + self->irq_obj = _irq; + + return _irq; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq); + +STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_rtc_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_rtc_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_now), MP_ROM_PTR(&pyb_rtc_now_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm), MP_ROM_PTR(&pyb_rtc_alarm_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm_left), MP_ROM_PTR(&pyb_rtc_alarm_left_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm_cancel), MP_ROM_PTR(&pyb_rtc_alarm_cancel_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_rtc_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_ALARM0), MP_ROM_INT(PYB_RTC_ALARM0) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); + +const mp_obj_type_t pyb_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = pyb_rtc_make_new, + .locals_dict = (mp_obj_t)&pyb_rtc_locals_dict, +}; + +STATIC const mp_irq_methods_t pyb_rtc_irq_methods = { + .init = pyb_rtc_irq, + .enable = pyb_rtc_irq_enable, + .disable = pyb_rtc_irq_disable, + .flags = pyb_rtc_irq_flags +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.h b/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.h new file mode 100755 index 0000000..f73de3f --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybrtc.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBRTC_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBRTC_H + +// RTC triggers +#define PYB_RTC_ALARM0 (0x01) + +#define RTC_ACCESS_TIME_MSEC (5) +#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2) + +typedef struct _pyb_rtc_obj_t { + mp_obj_base_t base; + mp_obj_t irq_obj; + uint32_t irq_flags; + uint32_t alarm_ms; + uint32_t alarm_time_s; + uint16_t alarm_time_ms; + byte pwrmode; + bool alarmset; + bool repeat; + bool irq_enabled; +} pyb_rtc_obj_t; + +extern const mp_obj_type_t pyb_rtc_type; + +extern void pyb_rtc_pre_init(void); +extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs); +extern uint32_t pyb_rtc_get_seconds (void); +extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds); +extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self); +extern void pyb_rtc_disable_alarm (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBRTC_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybsd.c b/src/openmv/src/micropython/ports/cc3200/mods/pybsd.c new file mode 100755 index 0000000..c47d4e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybsd.c @@ -0,0 +1,221 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/vfs_fat.h" +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "gpio.h" +#include "sdhost.h" +#include "sd_diskio.h" +#include "pybsd.h" +#include "mpexception.h" +#include "pybsleep.h" +#include "pybpin.h" +#include "pins.h" + +/****************************************************************************** + DEFINE PRIVATE CONSTANTS + ******************************************************************************/ +#define PYBSD_FREQUENCY_HZ 15000000 // 15MHz + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +pybsd_obj_t pybsd_obj; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_obj_t pyb_sd_def_pin[3] = {&pin_GP10, &pin_GP11, &pin_GP15}; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void pyb_sd_hw_init (pybsd_obj_t *self); +STATIC mp_obj_t pyb_sd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); +STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in); + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +/// Initalizes the sd card hardware driver +STATIC void pyb_sd_hw_init (pybsd_obj_t *self) { + if (self->pin_clk) { + // Configure the clock pin as output only + MAP_PinDirModeSet(((pin_obj_t *)(self->pin_clk))->pin_num, PIN_DIR_MODE_OUT); + } + // Enable SD peripheral clock + MAP_PRCMPeripheralClkEnable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // Reset MMCHS + MAP_PRCMPeripheralReset(PRCM_SDHOST); + // Initialize MMCHS + MAP_SDHostInit(SDHOST_BASE); + // Configure the card clock + MAP_SDHostSetExpClk(SDHOST_BASE, MAP_PRCMPeripheralClockGet(PRCM_SDHOST), PYBSD_FREQUENCY_HZ); + // Set card rd/wr block len + MAP_SDHostBlockSizeSet(SDHOST_BASE, SD_SECTOR_SIZE); + self->enabled = true; +} + +STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) { + // assign the pins + mp_obj_t pins_o = args[0].u_obj; + if (pins_o != mp_const_none) { + mp_obj_t *pins; + if (pins_o == MP_OBJ_NULL) { + // use the default pins + pins = (mp_obj_t *)pyb_sd_def_pin; + } else { + mp_obj_get_array_fixed_n(pins_o, MP_ARRAY_SIZE(pyb_sd_def_pin), &pins); + } + pin_assign_pins_af (pins, MP_ARRAY_SIZE(pyb_sd_def_pin), PIN_TYPE_STD_PU, PIN_FN_SD, 0); + // save the pins clock + self->pin_clk = pin_find(pins[0]); + } + + pyb_sd_hw_init (self); + if (sd_disk_init() != 0) { + mp_raise_OSError(MP_EIO); + } + + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init); + return mp_const_none; +} + +/******************************************************************************/ +// MicroPython bindings +// + +STATIC const mp_arg_t pyb_sd_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t pyb_sd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_sd_init_args, args); + + // check the peripheral id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + + // setup and initialize the object + mp_obj_t self = &pybsd_obj; + pybsd_obj.base.type = &pyb_sd_type; + pyb_sd_init_helper (self, &args[1]); + return self; +} + +STATIC mp_obj_t pyb_sd_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_sd_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_sd_init_args[1], args); + return pyb_sd_init_helper(pos_args[0], args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_sd_init_obj, 1, pyb_sd_init); + +STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) { + pybsd_obj_t *self = self_in; + // disable the peripheral + self->enabled = false; + MAP_PRCMPeripheralClkDisable(PRCM_SDHOST, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // de-initialze the sd card at diskio level + sd_disk_deinit(); + // unregister it from the sleep module + pyb_sleep_remove (self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit); + +STATIC mp_obj_t pyb_sd_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + DRESULT res = sd_disk_read(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SD_SECTOR_SIZE); + return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_readblocks_obj, pyb_sd_readblocks); + +STATIC mp_obj_t pyb_sd_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + DRESULT res = sd_disk_write(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SD_SECTOR_SIZE); + return MP_OBJ_NEW_SMALL_INT(res != RES_OK); // return of 0 means success +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_writeblocks_obj, pyb_sd_writeblocks); + +STATIC mp_obj_t pyb_sd_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: + case BP_IOCTL_DEINIT: + case BP_IOCTL_SYNC: + // nothing to do + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SEC_COUNT: + return MP_OBJ_NEW_SMALL_INT(sd_disk_info.ulNofBlock * (sd_disk_info.ulBlockSize / 512)); + + case BP_IOCTL_SEC_SIZE: + return MP_OBJ_NEW_SMALL_INT(SD_SECTOR_SIZE); + + default: // unknown command + return MP_OBJ_NEW_SMALL_INT(-1); // error + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sd_ioctl_obj, pyb_sd_ioctl); + +STATIC const mp_rom_map_elem_t pyb_sd_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_sd_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_sd_deinit_obj) }, + // block device protocol + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_sd_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_sd_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_sd_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_sd_locals_dict, pyb_sd_locals_dict_table); + +const mp_obj_type_t pyb_sd_type = { + { &mp_type_type }, + .name = MP_QSTR_SD, + .make_new = pyb_sd_make_new, + .locals_dict = (mp_obj_t)&pyb_sd_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybsd.h b/src/openmv/src/micropython/ports/cc3200/mods/pybsd.h new file mode 100755 index 0000000..af94208 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybsd.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBSD_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBSD_H + +/****************************************************************************** + DEFINE PUBLIC TYPES + ******************************************************************************/ +typedef struct { + mp_obj_base_t base; + mp_obj_t pin_clk; + bool enabled; +} pybsd_obj_t; + +/****************************************************************************** + DECLARE EXPORTED DATA + ******************************************************************************/ +extern pybsd_obj_t pybsd_obj; +extern const mp_obj_type_t pyb_sd_type; + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBSD_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.c b/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.c new file mode 100755 index 0000000..b5990e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.c @@ -0,0 +1,656 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_common_reg.h" +#include "inc/hw_memmap.h" +#include "cc3200_asm.h" +#include "rom_map.h" +#include "interrupt.h" +#include "systick.h" +#include "prcm.h" +#include "spi.h" +#include "pin.h" +#include "pybsleep.h" +#include "mpirq.h" +#include "pybpin.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "osi.h" +#include "debug.h" +#include "mpexception.h" +#include "mperror.h" +#include "sleeprestore.h" +#include "serverstask.h" +#include "antenna.h" +#include "cryptohash.h" +#include "pybrtc.h" + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ +#define SPIFLASH_INSTR_READ_STATUS (0x05) +#define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9) +#define SPIFLASH_STATUS_BUSY (0x01) + +#define LPDS_UP_TIME (425) // 13 msec +#define LPDS_DOWN_TIME (98) // 3 msec +#define USER_OFFSET (131) // 4 smec +#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec +#define WAKEUP_TIME_HIB (32768) // 1 s + +#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS) +#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3) + +/****************************************************************************** + DECLARE PRIVATE TYPES + ******************************************************************************/ +// storage memory for Cortex M4 registers +typedef struct { + uint32_t msp; + uint32_t psp; + uint32_t psr; + uint32_t primask; + uint32_t faultmask; + uint32_t basepri; + uint32_t control; +} arm_cm4_core_regs_t; + +// storage memory for the NVIC registers +typedef struct { + uint32_t vector_table; // Vector Table Offset + uint32_t aux_ctrl; // Auxiliary control register + uint32_t int_ctrl_state; // Interrupt Control and State + uint32_t app_int; // Application Interrupt Reset control + uint32_t sys_ctrl; // System control + uint32_t config_ctrl; // Configuration control + uint32_t sys_pri_1; // System Handler Priority 1 + uint32_t sys_pri_2; // System Handler Priority 2 + uint32_t sys_pri_3; // System Handler Priority 3 + uint32_t sys_hcrs; // System Handler control and state register + uint32_t systick_ctrl; // SysTick Control Status + uint32_t systick_reload; // SysTick Reload + uint32_t systick_calib; // SysTick Calibration + uint32_t int_en[6]; // Interrupt set enable + uint32_t int_priority[49]; // Interrupt priority +} nvic_reg_store_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t obj; + WakeUpCB_t wakeup; +} pyb_sleep_obj_t; + +typedef struct { + mp_obj_t gpio_lpds_wake_cb; + wlan_obj_t *wlan_obj; + pyb_rtc_obj_t *rtc_obj; +} pybsleep_data_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC nvic_reg_store_t *nvic_reg_store; +STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL}; +volatile arm_cm4_core_regs_t vault_arm_registers; +STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET; +STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON; +STATIC const mp_obj_type_t pyb_sleep_type = { + { &mp_type_type }, + .name = MP_QSTR_sleep, +}; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj); +STATIC void pyb_sleep_flash_powerdown (void); +STATIC NORETURN void pyb_sleep_suspend_enter (void); +void pyb_sleep_suspend_exit (void); +STATIC void pyb_sleep_obj_wakeup (void); +STATIC void PRCMInterruptHandler (void); +STATIC void pyb_sleep_iopark (bool hibernate); +STATIC bool setup_timer_lpds_wake (void); +STATIC bool setup_timer_hibernate_wake (void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +__attribute__ ((section (".boot"))) +void pyb_sleep_pre_init (void) { + // allocate memory for nvic registers vault + ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL); +} + +void pyb_sleep_init0 (void) { + // initialize the sleep objects list + mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0); + + // register and enable the PRCM interrupt + osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1); + + // disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode) + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); + MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 | + PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26); + + // check the reset casue (if it's soft reset, leave it as it is) + if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) { + switch (MAP_PRCMSysResetCauseGet()) { + case PRCM_POWER_ON: + pybsleep_reset_cause = PYB_SLP_PWRON_RESET; + break; + case PRCM_CORE_RESET: + case PRCM_MCU_RESET: + case PRCM_SOC_RESET: + pybsleep_reset_cause = PYB_SLP_HARD_RESET; + break; + case PRCM_WDT_RESET: + pybsleep_reset_cause = PYB_SLP_WDT_RESET; + break; + case PRCM_HIB_EXIT: + if (PRCMGetSpecialBit(PRCM_WDT_RESET_BIT)) { + pybsleep_reset_cause = PYB_SLP_WDT_RESET; + } + else { + pybsleep_reset_cause = PYB_SLP_HIB_RESET; + // set the correct wake reason + switch (MAP_PRCMHibernateWakeupCauseGet()) { + case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK: + pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC; + // TODO repeat the alarm + break; + case PRCM_HIB_WAKEUP_CAUSE_GPIO: + pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO; + break; + default: + break; + } + } + break; + default: + break; + } + } +} + +void pyb_sleep_signal_soft_reset (void) { + pybsleep_reset_cause = PYB_SLP_SOFT_RESET; +} + +void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) { + pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t); + sleep_obj->base.type = &pyb_sleep_type; + sleep_obj->obj = obj; + sleep_obj->wakeup = wakeup; + // remove it in case it was already registered + pyb_sleep_remove (obj); + mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj); +} + +void pyb_sleep_remove (const mp_obj_t obj) { + pyb_sleep_obj_t *sleep_obj; + if ((sleep_obj = pyb_sleep_find(obj))) { + mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj); + } +} + +void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) { + pybsleep_data.gpio_lpds_wake_cb = cb_obj; +} + +void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) { + pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj; +} + +void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) { + pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj; +} + +void pyb_sleep_sleep (void) { + nlr_buf_t nlr; + + // check if we should enable timer wake-up + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) { + if (!setup_timer_lpds_wake()) { + // lpds entering is not possible, wait for the forced interrupt and return + mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS); + return; + } + } else { + // disable the timer as wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); + } + + // do we need network wake-up? + if (pybsleep_data.wlan_obj->irq_enabled) { + MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ); + server_sleep_sockets(); + } else { + MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ); + } + + // entering and exiting suspended mode must be an atomic operation + // therefore interrupts need to be disabled + uint primsk = disable_irq(); + if (nlr_push(&nlr) == 0) { + pyb_sleep_suspend_enter(); + nlr_pop(); + } + + // an exception is always raised when exiting suspend mode + enable_irq(primsk); +} + +void pyb_sleep_deepsleep (void) { + // check if we should enable timer wake-up + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) { + if (!setup_timer_hibernate_wake()) { + // hibernating is not possible, wait for the forced interrupt and return + mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS); + return; + } + } else { + // disable the timer as hibernate wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); + } + + wlan_stop(SL_STOP_TIMEOUT); + pyb_sleep_flash_powerdown(); + // must be done just before entering hibernate mode + pyb_sleep_iopark(true); + MAP_PRCMHibernateEnter(); +} + +pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) { + return pybsleep_reset_cause; +} + +pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) { + return pybsleep_wake_reason; +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) { + // search for the object and then remove it + pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i])); + if (sleep_obj->obj == obj) { + return sleep_obj; + } + } + return NULL; +} + +STATIC void pyb_sleep_flash_powerdown (void) { + uint32_t status; + + // Enable clock for SSPI module + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // Reset SSPI at PRCM level and wait for reset to complete + MAP_PRCMPeripheralReset(PRCM_SSPI); + while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI)); + + // Reset SSPI at module level + MAP_SPIReset(SSPI_BASE); + // Configure SSPI module + MAP_SPIConfigSetExpClk (SSPI_BASE, PRCMPeripheralClockGet(PRCM_SSPI), + 20000000, SPI_MODE_MASTER,SPI_SUB_MODE_0, + (SPI_SW_CTRL_CS | + SPI_4PIN_MODE | + SPI_TURBO_OFF | + SPI_CS_ACTIVELOW | + SPI_WL_8)); + + // Enable SSPI module + MAP_SPIEnable(SSPI_BASE); + // Enable chip select for the spi flash. + MAP_SPICSEnable(SSPI_BASE); + // Wait for the spi flash + do { + // Send the status register read instruction and read back a dummy byte. + MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_READ_STATUS); + MAP_SPIDataGet(SSPI_BASE, &status); + + // Write a dummy byte then read back the actual status. + MAP_SPIDataPut(SSPI_BASE, 0xFF); + MAP_SPIDataGet(SSPI_BASE, &status); + } while ((status & 0xFF) == SPIFLASH_STATUS_BUSY); + + // Disable chip select for the spi flash. + MAP_SPICSDisable(SSPI_BASE); + // Start another CS enable sequence for Power down command. + MAP_SPICSEnable(SSPI_BASE); + // Send Deep Power Down command to spi flash + MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN); + // Disable chip select for the spi flash. + MAP_SPICSDisable(SSPI_BASE); +} + +STATIC NORETURN void pyb_sleep_suspend_enter (void) { + // enable full RAM retention + MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET); + + // save the NVIC control registers + nvic_reg_store->vector_table = HWREG(NVIC_VTABLE); + nvic_reg_store->aux_ctrl = HWREG(NVIC_ACTLR); + nvic_reg_store->int_ctrl_state = HWREG(NVIC_INT_CTRL); + nvic_reg_store->app_int = HWREG(NVIC_APINT); + nvic_reg_store->sys_ctrl = HWREG(NVIC_SYS_CTRL); + nvic_reg_store->config_ctrl = HWREG(NVIC_CFG_CTRL); + nvic_reg_store->sys_pri_1 = HWREG(NVIC_SYS_PRI1); + nvic_reg_store->sys_pri_2 = HWREG(NVIC_SYS_PRI2); + nvic_reg_store->sys_pri_3 = HWREG(NVIC_SYS_PRI3); + nvic_reg_store->sys_hcrs = HWREG(NVIC_SYS_HND_CTRL); + + // save the systick registers + nvic_reg_store->systick_ctrl = HWREG(NVIC_ST_CTRL); + nvic_reg_store->systick_reload = HWREG(NVIC_ST_RELOAD); + nvic_reg_store->systick_calib = HWREG(NVIC_ST_CAL); + + // save the interrupt enable registers + uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + nvic_reg_store->int_en[i] = base_reg_addr[i]; + } + + // save the interrupt priority registers + base_reg_addr = (uint32_t *)NVIC_PRI0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + nvic_reg_store->int_priority[i] = base_reg_addr[i]; + } + + // switch off the heartbeat led (this makes sure it will blink as soon as we wake up) + mperror_heartbeat_switch_off(); + + // park the gpio pins + pyb_sleep_iopark(false); + + // store the cpu registers + sleep_store(); + + // save the restore info and enter LPDS + MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore); + MAP_PRCMLPDSEnter(); + + // let the cpu fade away... + for ( ; ; ); +} + +void pyb_sleep_suspend_exit (void) { + // take the I2C semaphore + uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register); + reg = (reg & ~0x3) | 0x1; + HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg; + + // take the GPIO semaphore + reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register); + reg = (reg & ~0x3FF) | 0x155; + HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg; + + // restore de NVIC control registers + HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table; + HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl; + HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state; + HWREG(NVIC_APINT) = nvic_reg_store->app_int; + HWREG(NVIC_SYS_CTRL) = nvic_reg_store->sys_ctrl; + HWREG(NVIC_CFG_CTRL) = nvic_reg_store->config_ctrl; + HWREG(NVIC_SYS_PRI1) = nvic_reg_store->sys_pri_1; + HWREG(NVIC_SYS_PRI2) = nvic_reg_store->sys_pri_2; + HWREG(NVIC_SYS_PRI3) = nvic_reg_store->sys_pri_3; + HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store->sys_hcrs; + + // restore the systick register + HWREG(NVIC_ST_CTRL) = nvic_reg_store->systick_ctrl; + HWREG(NVIC_ST_RELOAD) = nvic_reg_store->systick_reload; + HWREG(NVIC_ST_CAL) = nvic_reg_store->systick_calib; + + // restore the interrupt priority registers + uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0; + for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_priority[i]; + } + + // restore the interrupt enable registers + base_reg_addr = (uint32_t *)NVIC_EN0; + for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_en[i]; + } + + HAL_INTRODUCE_SYNC_BARRIER(); + + // ungate the clock to the shared spi bus + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + +#if MICROPY_HW_ANTENNA_DIVERSITY + // re-configure the antenna selection pins + antenna_init0(); +#endif + + // reinitialize simplelink's interface + sl_IfOpen (NULL, 0); + + // restore the configuration of all active peripherals + pyb_sleep_obj_wakeup(); + + // reconfigure all the previously enabled interrupts + mp_irq_wake_all(); + + // we need to init the crypto hash engine again + //CRYPTOHASH_Init(); + + // trigger a sw interrupt + MAP_IntPendSet(INT_PRCM); + + // force an exception to go back to the point where suspend mode was entered + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} + +STATIC void PRCMInterruptHandler (void) { + // reading the interrupt status automatically clears the interrupt + if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) { + // reconfigure it again (if repeat is true) + pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj); + pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0; + // need to check if irq's are enabled from the user point of view + if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) { + mp_irq_handler(pybsleep_data.rtc_obj->irq_obj); + } + pybsleep_data.rtc_obj->irq_flags = 0; + } else { + // interrupt has been triggered while waking up from LPDS + switch (MAP_PRCMLPDSWakeupCauseGet()) { + case PRCM_LPDS_HOST_IRQ: + pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY; + mp_irq_handler(pybsleep_data.wlan_obj->irq_obj); + pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN; + pybsleep_data.wlan_obj->irq_flags = 0; + break; + case PRCM_LPDS_GPIO: + mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb); + pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO; + break; + case PRCM_LPDS_TIMER: + // reconfigure it again if repeat is true + pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj); + pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0; + // next one clears the wake cause flag + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); + mp_irq_handler(pybsleep_data.rtc_obj->irq_obj); + pybsleep_data.rtc_obj->irq_flags = 0; + pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC; + break; + default: + break; + } + } +} + +STATIC void pyb_sleep_obj_wakeup (void) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) { + pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]); + sleep_obj->wakeup(sleep_obj->obj); + } +} + +STATIC void pyb_sleep_iopark (bool hibernate) { + const mp_map_t *named_map = &pin_board_pins_locals_dict.map; + for (uint i = 0; i < named_map->used; i++) { + pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value; + switch (pin->pin_num) { +#ifdef DEBUG + // skip the JTAG pins + case PIN_16: + case PIN_17: + case PIN_19: + case PIN_20: + break; +#endif + default: + // enable a weak pull-up if the pin is unused + if (!pin->used) { + MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU); + } + if (hibernate) { + // make it an input + MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN); + } + break; + } + } + + // park the sflash pins + HWREG(0x4402E0E8) &= ~(0x3 << 8); + HWREG(0x4402E0E8) |= (0x2 << 8); + HWREG(0x4402E0EC) &= ~(0x3 << 8); + HWREG(0x4402E0EC) |= (0x2 << 8); + HWREG(0x4402E0F0) &= ~(0x3 << 8); + HWREG(0x4402E0F0) |= (0x2 << 8); + HWREG(0x4402E0F4) &= ~(0x3 << 8); + HWREG(0x4402E0F4) |= (0x1 << 8); + + // if the board has antenna diversity, only park the antenna + // selection pins when going into hibernation +#if MICROPY_HW_ANTENNA_DIVERSITY + if (hibernate) { +#endif + // park the antenna selection pins + // (tri-stated with pull down enabled) + HWREG(0x4402E108) = 0x00000E61; + HWREG(0x4402E10C) = 0x00000E61; +#if MICROPY_HW_ANTENNA_DIVERSITY + } else { + // park the antenna selection pins + // (tri-stated without changing the pull up/down resistors) + HWREG(0x4402E108) &= ~0x000000FF; + HWREG(0x4402E108) |= 0x00000C61; + HWREG(0x4402E10C) &= ~0x000000FF; + HWREG(0x4402E10C) |= 0x00000C61; + } +#endif +} + +STATIC bool setup_timer_lpds_wake (void) { + uint64_t t_match, t_curr; + int64_t t_remaining; + + // get the time remaining for the RTC timer to expire + t_match = MAP_PRCMSlowClkCtrMatchGet(); + t_curr = MAP_PRCMSlowClkCtrGet(); + + // get the time remaining in terms of slow clocks + t_remaining = (t_match - t_curr); + if (t_remaining > WAKEUP_TIME_LPDS) { + // subtract the time it takes to wakeup from lpds + t_remaining -= WAKEUP_TIME_LPDS; + t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining; + // setup the LPDS wake time + MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining); + // enable the wake source + MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER); + return true; + } + + // disable the timer as wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); + + uint32_t f_seconds; + uint16_t f_mseconds; + // setup a timer interrupt immediately + pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds); + MAP_PRCMRTCMatchSet(f_seconds, f_mseconds); + // LPDS wake by timer was not possible, force an interrupt in active mode instead + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + + return false; +} + +STATIC bool setup_timer_hibernate_wake (void) { + uint64_t t_match, t_curr; + int64_t t_remaining; + + // get the time remaining for the RTC timer to expire + t_match = MAP_PRCMSlowClkCtrMatchGet(); + t_curr = MAP_PRCMSlowClkCtrGet(); + + // get the time remaining in terms of slow clocks + t_remaining = (t_match - t_curr); + if (t_remaining > WAKEUP_TIME_HIB) { + // subtract the time it takes for wakeup from hibernate + t_remaining -= WAKEUP_TIME_HIB; + // setup the LPDS wake time + MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining); + // enable the wake source + MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); + return true; + } + + + // disable the timer as wake source + MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); + + uint32_t f_seconds; + uint16_t f_mseconds; + // setup a timer interrupt immediately + pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds); + MAP_PRCMRTCMatchSet(f_seconds, f_mseconds); + // LPDS wake by timer was not possible, force an interrupt in active mode instead + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); + + return false; +} + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.h b/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.h new file mode 100755 index 0000000..e986361 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybsleep.h @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBSLEEP_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBSLEEP_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define PYB_PWR_MODE_ACTIVE (0x01) +#define PYB_PWR_MODE_LPDS (0x02) +#define PYB_PWR_MODE_HIBERNATE (0x04) + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef enum { + PYB_SLP_PWRON_RESET = 0, + PYB_SLP_HARD_RESET, + PYB_SLP_WDT_RESET, + PYB_SLP_HIB_RESET, + PYB_SLP_SOFT_RESET +} pybsleep_reset_cause_t; + +typedef enum { + PYB_SLP_WAKED_PWRON = 0, + PYB_SLP_WAKED_BY_WLAN, + PYB_SLP_WAKED_BY_GPIO, + PYB_SLP_WAKED_BY_RTC +} pybsleep_wake_reason_t; + +typedef void (*WakeUpCB_t)(const mp_obj_t self); + +/****************************************************************************** + DECLARE FUNCTIONS + ******************************************************************************/ +void pyb_sleep_pre_init (void); +void pyb_sleep_init0 (void); +void pyb_sleep_signal_soft_reset (void); +void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup); +void pyb_sleep_remove (const mp_obj_t obj); +void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj); +void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj); +void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj); +void pyb_sleep_sleep (void); +void pyb_sleep_deepsleep (void); +pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void); +pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBSLEEP_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybspi.c b/src/openmv/src/micropython/ports/cc3200/mods/pybspi.c new file mode 100755 index 0000000..27591e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybspi.c @@ -0,0 +1,387 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "bufhelper.h" +#include "inc/hw_types.h" +#include "inc/hw_mcspi.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "spi.h" +#include "pybspi.h" +#include "mpexception.h" +#include "pybsleep.h" +#include "pybpin.h" +#include "pins.h" + +/// \moduleref pyb +/// \class SPI - a master-driven serial protocol + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ +typedef struct _pyb_spi_obj_t { + mp_obj_base_t base; + uint baudrate; + uint config; + byte polarity; + byte phase; + byte submode; + byte wlen; +} pyb_spi_obj_t; + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define PYBSPI_FIRST_BIT_MSB 0 + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC pyb_spi_obj_t pyb_spi_obj = {.baudrate = 0}; + +STATIC const mp_obj_t pyb_spi_def_pin[3] = {&pin_GP14, &pin_GP16, &pin_GP30}; + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +// only master mode is available for the moment +STATIC void pybspi_init (const pyb_spi_obj_t *self) { + // enable the peripheral clock + MAP_PRCMPeripheralClkEnable(PRCM_GSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralReset(PRCM_GSPI); + MAP_SPIReset(GSPI_BASE); + + // configure the interface (only master mode supported) + MAP_SPIConfigSetExpClk (GSPI_BASE, MAP_PRCMPeripheralClockGet(PRCM_GSPI), + self->baudrate, SPI_MODE_MASTER, self->submode, self->config); + + // enable the interface + MAP_SPIEnable(GSPI_BASE); +} + +STATIC void pybspi_tx (pyb_spi_obj_t *self, const void *data) { + uint32_t txdata; + switch (self->wlen) { + case 1: + txdata = (uint8_t)(*(char *)data); + break; + case 2: + txdata = (uint16_t)(*(uint16_t *)data); + break; + case 4: + txdata = (uint32_t)(*(uint32_t *)data); + break; + default: + return; + } + MAP_SPIDataPut (GSPI_BASE, txdata); +} + +STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) { + uint32_t rxdata; + MAP_SPIDataGet (GSPI_BASE, &rxdata); + if (data) { + switch (self->wlen) { + case 1: + *(char *)data = rxdata; + break; + case 2: + *(uint16_t *)data = rxdata; + break; + case 4: + *(uint32_t *)data = rxdata; + break; + default: + return; + } + } +} + +STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) { + if (!self->baudrate) { + mp_raise_OSError(MP_EPERM); + } + // send and receive the data + MAP_SPICSEnable(GSPI_BASE); + for (int i = 0; i < len; i += self->wlen) { + pybspi_tx(self, txdata ? (const void *)&txdata[i] : txchar); + pybspi_rx(self, rxdata ? (void *)&rxdata[i] : NULL); + } + MAP_SPICSDisable(GSPI_BASE); +} + +/******************************************************************************/ +/* MicroPython bindings */ +/******************************************************************************/ +STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_spi_obj_t *self = self_in; + if (self->baudrate > 0) { + mp_printf(print, "SPI(0, baudrate=%u, bits=%u, polarity=%u, phase=%u, firstbit=SPI.MSB)", + self->baudrate, (self->wlen * 8), self->polarity, self->phase); + } else { + mp_print_str(print, "SPI(0)"); + } +} + +STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *args) { + uint bits; + switch (args[1].u_int) { + case 8: + bits = SPI_WL_8; + break; + case 16: + bits = SPI_WL_16; + break; + case 32: + bits = SPI_WL_32; + break; + default: + goto invalid_args; + break; + } + + uint polarity = args[2].u_int; + uint phase = args[3].u_int; + if (polarity > 1 || phase > 1) { + goto invalid_args; + } + + uint firstbit = args[4].u_int; + if (firstbit != PYBSPI_FIRST_BIT_MSB) { + goto invalid_args; + } + + // build the configuration + self->baudrate = args[0].u_int; + self->wlen = args[1].u_int >> 3; + self->config = bits | SPI_CS_ACTIVELOW | SPI_SW_CTRL_CS | SPI_4PIN_MODE | SPI_TURBO_OFF; + self->polarity = polarity; + self->phase = phase; + self->submode = (polarity << 1) | phase; + + // assign the pins + mp_obj_t pins_o = args[5].u_obj; + if (pins_o != mp_const_none) { + mp_obj_t *pins; + if (pins_o == MP_OBJ_NULL) { + // use the default pins + pins = (mp_obj_t *)pyb_spi_def_pin; + } else { + mp_obj_get_array_fixed_n(pins_o, 3, &pins); + } + pin_assign_pins_af (pins, 3, PIN_TYPE_STD_PU, PIN_FN_SPI, 0); + } + + // init the bus + pybspi_init((const pyb_spi_obj_t *)self); + + // register it with the sleep module + pyb_sleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init); + + return mp_const_none; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +static const mp_arg_t pyb_spi_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, // 1MHz + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBSPI_FIRST_BIT_MSB} }, + { MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_spi_init_args, args); + + // check the peripheral id + if (args[0].u_int != 0) { + mp_raise_OSError(MP_ENODEV); + } + + // setup the object + pyb_spi_obj_t *self = &pyb_spi_obj; + self->base.type = &pyb_spi_type; + + // start the peripheral + pyb_spi_init_helper(self, &args[1]); + + return self; +} + +STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_spi_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_spi_init_args[1], args); + return pyb_spi_init_helper(pos_args[0], args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init); + +/// \method deinit() +/// Turn off the spi bus. +STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) { + // disable the peripheral + MAP_SPIDisable(GSPI_BASE); + MAP_PRCMPeripheralClkDisable(PRCM_GSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + // invalidate the baudrate + pyb_spi_obj.baudrate = 0; + // unregister it with the sleep module + pyb_sleep_remove((const mp_obj_t)self_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit); + +STATIC mp_obj_t pyb_spi_write (mp_obj_t self_in, mp_obj_t buf) { + // parse args + pyb_spi_obj_t *self = self_in; + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(buf, &bufinfo, data); + + // just send + pybspi_transfer(self, (const char *)bufinfo.buf, NULL, bufinfo.len, NULL); + + // return the number of bytes written + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); + +STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, + }; + + // parse args + pyb_spi_obj_t *self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args); + + // get the buffer to receive into + vstr_t vstr; + pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // just receive + uint32_t write = args[1].u_int; + pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write); + + // return the received data + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read); + +STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, + }; + + // parse args + pyb_spi_obj_t *self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), allowed_args, args); + + // get the buffer to receive into + vstr_t vstr; + pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // just receive + uint32_t write = args[1].u_int; + pybspi_transfer(self, NULL, vstr.buf, vstr.len, &write); + + // return the number of bytes received + return mp_obj_new_int(vstr.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_readinto_obj, 1, pyb_spi_readinto); + +STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj_t readbuf) { + // get buffers to write from/read to + mp_buffer_info_t bufinfo_write; + uint8_t data_send[1]; + mp_buffer_info_t bufinfo_read; + + if (writebuf == readbuf) { + // same object for writing and reading, it must be a r/w buffer + mp_get_buffer_raise(writebuf, &bufinfo_write, MP_BUFFER_RW); + bufinfo_read = bufinfo_write; + } else { + // get the buffer to write from + pyb_buf_get_for_send(writebuf, &bufinfo_write, data_send); + + // get the read buffer + mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE); + if (bufinfo_read.len != bufinfo_write.len) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + } + + // send and receive + pybspi_transfer(self, (const char *)bufinfo_write.buf, bufinfo_read.buf, bufinfo_write.len, NULL); + + // return the number of transferred bytes + return mp_obj_new_int(bufinfo_write.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto); + +STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(PYBSPI_FIRST_BIT_MSB) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); + +const mp_obj_type_t pyb_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = pyb_spi_print, + .make_new = pyb_spi_make_new, + .locals_dict = (mp_obj_t)&pyb_spi_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybspi.h b/src/openmv/src/micropython/ports/cc3200/mods/pybspi.h new file mode 100755 index 0000000..b0fce88 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybspi.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBSPI_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBSPI_H + +extern const mp_obj_type_t pyb_spi_type; + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBSPI_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.c b/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.c new file mode 100755 index 0000000..ea795b8 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.c @@ -0,0 +1,732 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_timer.h" +#include "rom_map.h" +#include "interrupt.h" +#include "prcm.h" +#include "timer.h" +#include "pin.h" +#include "pybtimer.h" +#include "pybpin.h" +#include "pins.h" +#include "mpirq.h" +#include "pybsleep.h" +#include "mpexception.h" + + +/// \moduleref pyb +/// \class Timer - generate periodic events, count events, and create PWM signals. +/// +/// Each timer consists of a counter that counts up at a certain rate. The rate +/// at which it counts is the peripheral clock frequency (in Hz) divided by the +/// timer prescaler. When the counter reaches the timer period it triggers an +/// event, and the counter resets back to zero. By using the irq method, +/// the timer event can call a Python function. + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ +#define PYBTIMER_NUM_TIMERS (4) +#define PYBTIMER_POLARITY_POS (0x01) +#define PYBTIMER_POLARITY_NEG (0x02) + +#define PYBTIMER_TIMEOUT_TRIGGER (0x01) +#define PYBTIMER_MATCH_TRIGGER (0x02) + +#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef struct _pyb_timer_obj_t { + mp_obj_base_t base; + uint32_t timer; + uint32_t config; + uint16_t irq_trigger; + uint16_t irq_flags; + uint8_t peripheral; + uint8_t id; +} pyb_timer_obj_t; + +typedef struct _pyb_timer_channel_obj_t { + mp_obj_base_t base; + struct _pyb_timer_obj_t *timer; + uint32_t frequency; + uint32_t period; + uint16_t channel; + uint16_t duty_cycle; + uint8_t polarity; +} pyb_timer_channel_obj_t; + +/****************************************************************************** + DEFINE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods; +STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0}, + {.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1}, + {.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2}, + {.timer = TIMERA3_BASE, .peripheral = PRCM_TIMERA3}}; +STATIC const mp_obj_type_t pyb_timer_channel_type; +STATIC const mp_obj_t pyb_timer_pwm_pin[8] = {&pin_GP24, MP_OBJ_NULL, &pin_GP25, MP_OBJ_NULL, MP_OBJ_NULL, &pin_GP9, &pin_GP10, &pin_GP11}; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC mp_obj_t pyb_timer_channel_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +STATIC void timer_disable (pyb_timer_obj_t *tim); +STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch); +STATIC void TIMER0AIntHandler(void); +STATIC void TIMER0BIntHandler(void); +STATIC void TIMER1AIntHandler(void); +STATIC void TIMER1BIntHandler(void); +STATIC void TIMER2AIntHandler(void); +STATIC void TIMER2BIntHandler(void); +STATIC void TIMER3AIntHandler(void); +STATIC void TIMER3BIntHandler(void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void timer_init0 (void) { + mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0); +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) { + pyb_timer_channel_obj_t *self = self_in; + MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel); + MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel); +} + +STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) { + pyb_timer_channel_obj_t *self = self_in; + MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel); +} + +STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) { + pyb_timer_channel_obj_t *self = self_in; + return self->timer->irq_flags; +} + +STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) { + pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i])); + // any 32-bit timer must be matched by any of its 16-bit versions + if (ch->timer->timer == timer && ((ch->channel & TIMER_A) == channel_n || (ch->channel & TIMER_B) == channel_n)) { + return ch; + } + } + return MP_OBJ_NULL; +} + +STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) { + pyb_timer_channel_obj_t *channel; + if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) { + mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel); + // unregister it with the sleep module + pyb_sleep_remove((const mp_obj_t)channel); + } +} + +STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) { + // remove it in case it already exists + pyb_timer_channel_remove(ch); + mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch); + // register it with the sleep module + pyb_sleep_add((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init); +} + +STATIC void timer_disable (pyb_timer_obj_t *tim) { + // disable all timers and it's interrupts + MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B); + MAP_TimerIntDisable(tim->timer, tim->irq_trigger); + MAP_TimerIntClear(tim->timer, tim->irq_trigger); + pyb_timer_channel_obj_t *ch; + // disable its channels + if ((ch = pyb_timer_channel_find (tim->timer, TIMER_A))) { + pyb_sleep_remove(ch); + } + if ((ch = pyb_timer_channel_find (tim->timer, TIMER_B))) { + pyb_sleep_remove(ch); + } + MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); +} + +// computes prescaler period and match value so timer triggers at freq-Hz +STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t *ch, uint32_t *period_out, uint32_t *match_out) { + uint32_t maxcount = (ch->channel == (TIMER_A | TIMER_B)) ? 0xFFFFFFFF : 0xFFFF; + uint32_t prescaler; + uint32_t period_c = (ch->frequency > 0) ? PYBTIMER_SRC_FREQ_HZ / ch->frequency : ((PYBTIMER_SRC_FREQ_HZ / 1000000) * ch->period); + + period_c = MAX(1, period_c) - 1; + if (period_c == 0) { + goto error; + } + + prescaler = period_c >> 16; // The prescaler is an extension of the timer counter + *period_out = period_c; + + if (prescaler > 0xFF && maxcount == 0xFFFF) { + goto error; + } + // check limit values for the duty cycle + if (ch->duty_cycle == 0) { + *match_out = period_c - 1; + } else { + if (period_c > 0xFFFF) { + uint32_t match = (period_c * 100) / 10000; + *match_out = period_c - ((match * ch->duty_cycle) / 100); + } else { + *match_out = period_c - ((period_c * ch->duty_cycle) / 10000); + } + } + return prescaler; + +error: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC void timer_init (pyb_timer_obj_t *tim) { + MAP_PRCMPeripheralClkEnable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralReset(tim->peripheral); + MAP_TimerConfigure(tim->timer, tim->config); +} + +STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) { + // calculate the period, the prescaler and the match value + uint32_t period_c; + uint32_t match; + uint32_t prescaler = compute_prescaler_period_and_match_value(ch, &period_c, &match); + + // set the prescaler + MAP_TimerPrescaleSet(ch->timer->timer, ch->channel, (prescaler < 0xFF) ? prescaler : 0); + + // set the load value + MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c); + + // configure the pwm if we are in such mode + if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) { + // invert the timer output if required + MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false); + // set the match value (which is simply the duty cycle translated to ticks) + MAP_TimerMatchSet(ch->timer->timer, ch->channel, match); + MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16); + } + +#ifdef DEBUG + // stall the timer when the processor is halted while debugging + MAP_TimerControlStall(ch->timer->timer, ch->channel, true); +#endif + + // now enable the timer channel + MAP_TimerEnable(ch->timer->timer, ch->channel); +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_obj_t *tim = self_in; + uint32_t mode = tim->config & 0xFF; + + // timer mode + qstr mode_qst = MP_QSTR_PWM; + switch(mode) { + case TIMER_CFG_A_ONE_SHOT_UP: + mode_qst = MP_QSTR_ONE_SHOT; + break; + case TIMER_CFG_A_PERIODIC_UP: + mode_qst = MP_QSTR_PERIODIC; + break; + default: + break; + } + mp_printf(print, "Timer(%u, mode=Timer.%q)", tim->id, mode_qst); +} + +STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // check the mode + uint32_t _mode = args[0].u_int; + if (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP && _mode != TIMER_CFG_A_PWM) { + goto error; + } + + // check the width + if (args[1].u_int != 16 && args[1].u_int != 32) { + goto error; + } + bool is16bit = (args[1].u_int == 16); + + if (!is16bit && _mode == TIMER_CFG_A_PWM) { + // 32-bit mode is only available when in free running modes + goto error; + } + tim->config = is16bit ? ((_mode | (_mode << 8)) | TIMER_CFG_SPLIT_PAIR) : _mode; + + timer_init(tim); + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init); + + return mp_const_none; + +error: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create a new Timer object + int32_t timer_idx = mp_obj_get_int(args[0]); + if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) { + mp_raise_OSError(MP_ENODEV); + } + + pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx]; + tim->base.type = &pyb_timer_type; + tim->id = timer_idx; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args); + } + return (mp_obj_t)tim; +} + +STATIC mp_obj_t pyb_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); + +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { + pyb_timer_obj_t *self = self_in; + timer_disable(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); + +STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYBTIMER_POLARITY_POS} }, + { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + pyb_timer_obj_t *tim = pos_args[0]; + mp_int_t channel_n = mp_obj_get_int(pos_args[1]); + + // verify that the timer has been already initialized + if (!tim->config) { + mp_raise_OSError(MP_EPERM); + } + if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) { + // invalid channel + goto error; + } + if (channel_n == (TIMER_A | TIMER_B) && (tim->config & TIMER_CFG_SPLIT_PAIR)) { + // 32-bit channel selected when the timer is in 16-bit mode + goto error; + } + + // if only the channel number is given return the previously + // allocated channel (or None if no previous channel) + if (n_args == 2 && kw_args->used == 0) { + pyb_timer_channel_obj_t *ch; + if ((ch = pyb_timer_channel_find(tim->timer, channel_n))) { + return ch; + } + return mp_const_none; + } + + // parse the arguments + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // throw an exception if both frequency and period are given + if (args[0].u_int != 0 && args[1].u_int != 0) { + goto error; + } + // check that at least one of them has a valid value + if (args[0].u_int <= 0 && args[1].u_int <= 0) { + goto error; + } + // check that the polarity is not 'both' in pwm mode + if ((tim->config & TIMER_A) == TIMER_CFG_A_PWM && args[2].u_int == (PYBTIMER_POLARITY_POS | PYBTIMER_POLARITY_NEG)) { + goto error; + } + + // allocate a new timer channel + pyb_timer_channel_obj_t *ch = m_new_obj(pyb_timer_channel_obj_t); + ch->base.type = &pyb_timer_channel_type; + ch->timer = tim; + ch->channel = channel_n; + + // get the frequency the polarity and the duty cycle + ch->frequency = args[0].u_int; + ch->period = args[1].u_int; + ch->polarity = args[2].u_int; + ch->duty_cycle = MIN(10000, MAX(0, args[3].u_int)); + + timer_channel_init(ch); + + // assign the pin + if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) { + uint32_t ch_idx = (ch->channel == TIMER_A) ? 0 : 1; + // use the default pin if available + mp_obj_t pin_o = (mp_obj_t)pyb_timer_pwm_pin[(ch->timer->id * 2) + ch_idx]; + if (pin_o != MP_OBJ_NULL) { + pin_obj_t *pin = pin_find(pin_o); + pin_config (pin, pin_find_af_index(pin, PIN_FN_TIM, ch->timer->id, PIN_TYPE_TIM_PWM), + 0, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA); + } + } + + // add the timer to the list + pyb_timer_channel_add(ch); + + return ch; + +error: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); + +STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&pyb_timer_channel_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_A), MP_ROM_INT(TIMER_A) }, + { MP_ROM_QSTR(MP_QSTR_B), MP_ROM_INT(TIMER_B) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_CFG_A_ONE_SHOT_UP) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_CFG_A_PERIODIC_UP) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_INT(TIMER_CFG_A_PWM) }, + { MP_ROM_QSTR(MP_QSTR_POSITIVE), MP_ROM_INT(PYBTIMER_POLARITY_POS) }, + { MP_ROM_QSTR(MP_QSTR_NEGATIVE), MP_ROM_INT(PYBTIMER_POLARITY_NEG) }, + { MP_ROM_QSTR(MP_QSTR_TIMEOUT), MP_ROM_INT(PYBTIMER_TIMEOUT_TRIGGER) }, + { MP_ROM_QSTR(MP_QSTR_MATCH), MP_ROM_INT(PYBTIMER_MATCH_TRIGGER) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); + +const mp_obj_type_t pyb_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = pyb_timer_print, + .make_new = pyb_timer_make_new, + .locals_dict = (mp_obj_t)&pyb_timer_locals_dict, +}; + +STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = { + .init = pyb_timer_channel_irq, + .enable = pyb_timer_channel_irq_enable, + .disable = pyb_timer_channel_irq_disable, + .flags = pyb_timer_channel_irq_flags, +}; + +STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) { + pyb_timer_channel_obj_t *self; + uint32_t status; + if ((self = pyb_timer_channel_find(timer, channel))) { + status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel; + MAP_TimerIntClear(self->timer->timer, status); + mp_irq_handler(mp_irq_find(self)); + } +} + +STATIC void TIMER0AIntHandler(void) { + TIMERGenericIntHandler(TIMERA0_BASE, TIMER_A); +} + +STATIC void TIMER0BIntHandler(void) { + TIMERGenericIntHandler(TIMERA0_BASE, TIMER_B); +} + +STATIC void TIMER1AIntHandler(void) { + TIMERGenericIntHandler(TIMERA1_BASE, TIMER_A); +} + +STATIC void TIMER1BIntHandler(void) { + TIMERGenericIntHandler(TIMERA1_BASE, TIMER_B); +} + +STATIC void TIMER2AIntHandler(void) { + TIMERGenericIntHandler(TIMERA2_BASE, TIMER_A); +} + +STATIC void TIMER2BIntHandler(void) { + TIMERGenericIntHandler(TIMERA2_BASE, TIMER_B); +} + +STATIC void TIMER3AIntHandler(void) { + TIMERGenericIntHandler(TIMERA3_BASE, TIMER_A); +} + +STATIC void TIMER3BIntHandler(void) { + TIMERGenericIntHandler(TIMERA3_BASE, TIMER_B); +} + +STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_channel_obj_t *ch = self_in; + char *ch_id = "AB"; + // timer channel + if (ch->channel == TIMER_A) { + ch_id = "A"; + } else if (ch->channel == TIMER_B) { + ch_id = "B"; + } + + mp_printf(print, "timer.channel(Timer.%s, %q=%u", ch_id, MP_QSTR_freq, ch->frequency); + + uint32_t mode = ch->timer->config & 0xFF; + if (mode == TIMER_CFG_A_PWM) { + mp_printf(print, ", %q=Timer.", MP_QSTR_polarity); + switch (ch->polarity) { + case PYBTIMER_POLARITY_POS: + mp_printf(print, "POSITIVE"); + break; + case PYBTIMER_POLARITY_NEG: + mp_printf(print, "NEGATIVE"); + break; + default: + mp_printf(print, "BOTH"); + break; + } + mp_printf(print, ", %q=%u.%02u", MP_QSTR_duty_cycle, ch->duty_cycle / 100, ch->duty_cycle % 100); + } + mp_printf(print, ")"); +} + +STATIC mp_obj_t pyb_timer_channel_freq(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(ch->frequency); + } else { + // set + int32_t _frequency = mp_obj_get_int(args[1]); + if (_frequency <= 0) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + ch->frequency = _frequency; + ch->period = 1000000 / _frequency; + timer_channel_init(ch); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_freq_obj, 1, 2, pyb_timer_channel_freq); + +STATIC mp_obj_t pyb_timer_channel_period(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(ch->period); + } else { + // set + int32_t _period = mp_obj_get_int(args[1]); + if (_period <= 0) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + ch->period = _period; + ch->frequency = 1000000 / _period; + timer_channel_init(ch); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_period_obj, 1, 2, pyb_timer_channel_period); + +STATIC mp_obj_t pyb_timer_channel_duty_cycle(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *ch = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(ch->duty_cycle); + } else { + // duty cycle must be converted from percentage to ticks + // calculate the period, the prescaler and the match value + uint32_t period_c; + uint32_t match; + ch->duty_cycle = MIN(10000, MAX(0, mp_obj_get_int(args[1]))); + compute_prescaler_period_and_match_value(ch, &period_c, &match); + if (n_args == 3) { + // set the new polarity if requested + ch->polarity = mp_obj_get_int(args[2]); + MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false); + } + MAP_TimerMatchSet(ch->timer->timer, ch->channel, match); + MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle); + +STATIC mp_obj_t pyb_timer_channel_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); + pyb_timer_channel_obj_t *ch = pos_args[0]; + + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); + + // validate the power mode + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (pwrmode != PYB_PWR_MODE_ACTIVE) { + goto invalid_args; + } + + // get the trigger + uint trigger = mp_obj_get_int(args[0].u_obj); + + // disable the callback first + pyb_timer_channel_irq_disable(ch); + + uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0; + uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A); + switch (_config) { + case TIMER_CFG_A_ONE_SHOT_UP: + case TIMER_CFG_A_PERIODIC_UP: + ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift; + if (trigger != PYBTIMER_TIMEOUT_TRIGGER) { + goto invalid_args; + } + break; + case TIMER_CFG_A_PWM: + // special case for the PWM match interrupt + ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH; + if (trigger != PYBTIMER_MATCH_TRIGGER) { + goto invalid_args; + } + break; + default: + break; + } + // special case for a 32-bit timer + if (ch->channel == (TIMER_A | TIMER_B)) { + ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8); + } + + void (*pfnHandler)(void); + uint32_t intregister; + switch (ch->timer->timer) { + case TIMERA0_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER0BIntHandler; + intregister = INT_TIMERA0B; + } else { + pfnHandler = &TIMER0AIntHandler; + intregister = INT_TIMERA0A; + } + break; + case TIMERA1_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER1BIntHandler; + intregister = INT_TIMERA1B; + } else { + pfnHandler = &TIMER1AIntHandler; + intregister = INT_TIMERA1A; + } + break; + case TIMERA2_BASE: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER2BIntHandler; + intregister = INT_TIMERA2B; + } else { + pfnHandler = &TIMER2AIntHandler; + intregister = INT_TIMERA2A; + } + break; + default: + if (ch->channel == TIMER_B) { + pfnHandler = &TIMER3BIntHandler; + intregister = INT_TIMERA3B; + } else { + pfnHandler = &TIMER3AIntHandler; + intregister = INT_TIMERA3A; + } + break; + } + + // register the interrupt and configure the priority + MAP_IntPrioritySet(intregister, priority); + MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler); + + // create the callback + mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods); + + // enable the callback before returning + pyb_timer_channel_irq_enable(ch); + + return _irq; + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq); + +STATIC const mp_rom_map_elem_t pyb_timer_channel_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_timer_channel_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&pyb_timer_channel_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty_cycle), MP_ROM_PTR(&pyb_timer_channel_duty_cycle_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_timer_channel_irq_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_timer_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_TimerChannel, + .print = pyb_timer_channel_print, + .locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.h b/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.h new file mode 100755 index 0000000..0af0864 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybtimer.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBTIMER_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBTIMER_H + +/****************************************************************************** + DECLARE EXPORTED DATA + ******************************************************************************/ +extern const mp_obj_type_t pyb_timer_type; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void timer_init0 (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBTIMER_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybuart.c b/src/openmv/src/micropython/ports/cc3200/mods/pybuart.c new file mode 100755 index 0000000..35c0de9 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybuart.c @@ -0,0 +1,669 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/objlist.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "lib/utils/interrupt_char.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "inc/hw_uart.h" +#include "rom_map.h" +#include "interrupt.h" +#include "prcm.h" +#include "uart.h" +#include "pybuart.h" +#include "mpirq.h" +#include "pybsleep.h" +#include "mpexception.h" +#include "osi.h" +#include "utils.h" +#include "pin.h" +#include "pybpin.h" +#include "pins.h" +#include "moduos.h" + +/// \moduleref pyb +/// \class UART - duplex serial communication bus + +/****************************************************************************** + DEFINE CONSTANTS + *******-***********************************************************************/ +#define PYBUART_FRAME_TIME_US(baud) ((11 * 1000000) / baud) +#define PYBUART_2_FRAMES_TIME_US(baud) (PYBUART_FRAME_TIME_US(baud) * 2) +#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud) * 8) // we need at least characters in the FIFO + +#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1) +#define PYBUART_TX_MAX_TIMEOUT_MS (5) + +#define PYBUART_RX_BUFFER_LEN (256) + +// interrupt triggers +#define UART_TRIGGER_RX_ANY (0x01) +#define UART_TRIGGER_RX_HALF (0x02) +#define UART_TRIGGER_RX_FULL (0x04) +#define UART_TRIGGER_TX_DONE (0x08) + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void uart_init (pyb_uart_obj_t *self); +STATIC bool uart_rx_wait (pyb_uart_obj_t *self); +STATIC void uart_check_init(pyb_uart_obj_t *self); +STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler); +STATIC void UARTGenericIntHandler(uint32_t uart_id); +STATIC void UART0IntHandler(void); +STATIC void UART1IntHandler(void); +STATIC void uart_irq_enable (mp_obj_t self_in); +STATIC void uart_irq_disable (mp_obj_t self_in); + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +struct _pyb_uart_obj_t { + mp_obj_base_t base; + pyb_uart_id_t uart_id; + uint reg; + uint baudrate; + uint config; + uint flowcontrol; + byte *read_buf; // read buffer pointer + volatile uint16_t read_buf_head; // indexes first empty slot + uint16_t read_buf_tail; // indexes first full slot (not full if equals head) + byte peripheral; + byte irq_trigger; + bool irq_enabled; + byte irq_flags; +}; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0}, + {.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} }; +STATIC const mp_irq_methods_t uart_irq_methods; + +STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} }; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void uart_init0 (void) { + // save references of the UART objects, to prevent the read buffers from being trashed by the gc + MP_STATE_PORT(pyb_uart_objs)[0] = &pyb_uart_obj[0]; + MP_STATE_PORT(pyb_uart_objs)[1] = &pyb_uart_obj[1]; +} + +uint32_t uart_rx_any(pyb_uart_obj_t *self) { + if (self->read_buf_tail != self->read_buf_head) { + // buffering via irq + return (self->read_buf_head > self->read_buf_tail) ? self->read_buf_head - self->read_buf_tail : + PYBUART_RX_BUFFER_LEN - self->read_buf_tail + self->read_buf_head; + } + return MAP_UARTCharsAvail(self->reg) ? 1 : 0; +} + +int uart_rx_char(pyb_uart_obj_t *self) { + if (self->read_buf_tail != self->read_buf_head) { + // buffering via irq + int data = self->read_buf[self->read_buf_tail]; + self->read_buf_tail = (self->read_buf_tail + 1) % PYBUART_RX_BUFFER_LEN; + return data; + } else { + // no buffering + return MAP_UARTCharGetNonBlocking(self->reg); + } +} + +bool uart_tx_char(pyb_uart_obj_t *self, int c) { + uint32_t timeout = 0; + while (!MAP_UARTCharPutNonBlocking(self->reg, c)) { + if (timeout++ > ((PYBUART_TX_MAX_TIMEOUT_MS * 1000) / PYBUART_TX_WAIT_US(self->baudrate))) { + return false; + } + UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_TX_WAIT_US(self->baudrate))); + } + return true; +} + +bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (!uart_tx_char(self, *str)) { + return false; + } + } + return true; +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +// assumes init parameters have been set up correctly +STATIC void uart_init (pyb_uart_obj_t *self) { + // Enable the peripheral clock + MAP_PRCMPeripheralClkEnable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + + // Reset the uart + MAP_PRCMPeripheralReset(self->peripheral); + + // re-allocate the read buffer after resetting the uart (which automatically disables any irqs) + self->read_buf_head = 0; + self->read_buf_tail = 0; + self->read_buf = MP_OBJ_NULL; // free the read buffer before allocating again + self->read_buf = m_new(byte, PYBUART_RX_BUFFER_LEN); + + // Initialize the UART + MAP_UARTConfigSetExpClk(self->reg, MAP_PRCMPeripheralClockGet(self->peripheral), + self->baudrate, self->config); + + // Enable the FIFO + MAP_UARTFIFOEnable(self->reg); + + // Configure the FIFO interrupt levels + MAP_UARTFIFOLevelSet(self->reg, UART_FIFO_TX4_8, UART_FIFO_RX4_8); + + // Configure the flow control mode + UARTFlowControlSet(self->reg, self->flowcontrol); +} + +// Waits at most timeout microseconds for at least 1 char to become ready for +// reading (from buf or for direct reading). +// Returns true if something available, false if not. +STATIC bool uart_rx_wait (pyb_uart_obj_t *self) { + int timeout = PYBUART_RX_TIMEOUT_US(self->baudrate); + for ( ; ; ) { + if (uart_rx_any(self)) { + return true; // we have at least 1 char ready for reading + } + if (timeout > 0) { + UtilsDelay(UTILS_DELAY_US_TO_COUNT(1)); + timeout--; + } + else { + return false; + } + } +} + +STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) { + // disable the uart interrupts before updating anything + uart_irq_disable (self); + + if (self->uart_id == PYB_UART_0) { + MAP_IntPrioritySet(INT_UARTA0, priority); + MAP_UARTIntRegister(self->reg, UART0IntHandler); + } else { + MAP_IntPrioritySet(INT_UARTA1, priority); + MAP_UARTIntRegister(self->reg, UART1IntHandler); + } + + // create the callback + mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods); + + // enable the interrupts now + self->irq_trigger = trigger; + uart_irq_enable (self); + return _irq; +} + +STATIC void UARTGenericIntHandler(uint32_t uart_id) { + pyb_uart_obj_t *self; + uint32_t status; + + self = &pyb_uart_obj[uart_id]; + status = MAP_UARTIntStatus(self->reg, true); + // receive interrupt + if (status & (UART_INT_RX | UART_INT_RT)) { + // set the flags + self->irq_flags = UART_TRIGGER_RX_ANY; + MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT); + while (UARTCharsAvail(self->reg)) { + int data = MAP_UARTCharGetNonBlocking(self->reg); + if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == mp_interrupt_char) { + // raise an exception when interrupts are finished + mp_keyboard_interrupt(); + } else { // there's always a read buffer available + uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN; + if (next_head != self->read_buf_tail) { + // only store data if room in buf + self->read_buf[self->read_buf_head] = data; + self->read_buf_head = next_head; + } + } + } + } + + // check the flags to see if the user handler should be called + if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) { + // call the user defined handler + mp_irq_handler(mp_irq_find(self)); + } + + // clear the flags + self->irq_flags = 0; +} + +STATIC void uart_check_init(pyb_uart_obj_t *self) { + // not initialized + if (!self->baudrate) { + mp_raise_OSError(MP_EPERM); + } +} + +STATIC void UART0IntHandler(void) { + UARTGenericIntHandler(0); +} + +STATIC void UART1IntHandler(void) { + UARTGenericIntHandler(1); +} + +STATIC void uart_irq_enable (mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + // check for any of the rx interrupt types + if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) { + MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT); + MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT); + } + self->irq_enabled = true; +} + +STATIC void uart_irq_disable (mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + self->irq_enabled = false; +} + +STATIC int uart_irq_flags (mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + return self->irq_flags; +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_uart_obj_t *self = self_in; + if (self->baudrate > 0) { + mp_printf(print, "UART(%u, baudrate=%u, bits=", self->uart_id, self->baudrate); + switch (self->config & UART_CONFIG_WLEN_MASK) { + case UART_CONFIG_WLEN_5: + mp_print_str(print, "5"); + break; + case UART_CONFIG_WLEN_6: + mp_print_str(print, "6"); + break; + case UART_CONFIG_WLEN_7: + mp_print_str(print, "7"); + break; + case UART_CONFIG_WLEN_8: + mp_print_str(print, "8"); + break; + default: + break; + } + if ((self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_NONE) { + mp_print_str(print, ", parity=None"); + } else { + mp_printf(print, ", parity=UART.%q", (self->config & UART_CONFIG_PAR_MASK) == UART_CONFIG_PAR_EVEN ? MP_QSTR_EVEN : MP_QSTR_ODD); + } + mp_printf(print, ", stop=%u)", (self->config & UART_CONFIG_STOP_MASK) == UART_CONFIG_STOP_ONE ? 1 : 2); + } + else { + mp_printf(print, "UART(%u)", self->uart_id); + } +} + +STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *args) { + // get the baudrate + if (args[0].u_int <= 0) { + goto error; + } + uint baudrate = args[0].u_int; + uint config; + switch (args[1].u_int) { + case 5: + config = UART_CONFIG_WLEN_5; + break; + case 6: + config = UART_CONFIG_WLEN_6; + break; + case 7: + config = UART_CONFIG_WLEN_7; + break; + case 8: + config = UART_CONFIG_WLEN_8; + break; + default: + goto error; + break; + } + // parity + if (args[2].u_obj == mp_const_none) { + config |= UART_CONFIG_PAR_NONE; + } else { + uint parity = mp_obj_get_int(args[2].u_obj); + if (parity == 0) { + config |= UART_CONFIG_PAR_EVEN; + } else if (parity == 1) { + config |= UART_CONFIG_PAR_ODD; + } else { + goto error; + } + } + // stop bits + config |= (args[3].u_int == 1 ? UART_CONFIG_STOP_ONE : UART_CONFIG_STOP_TWO); + + // assign the pins + mp_obj_t pins_o = args[4].u_obj; + uint flowcontrol = UART_FLOWCONTROL_NONE; + if (pins_o != mp_const_none) { + mp_obj_t *pins; + size_t n_pins = 2; + if (pins_o == MP_OBJ_NULL) { + // use the default pins + pins = (mp_obj_t *)pyb_uart_def_pin[self->uart_id]; + } else { + mp_obj_get_array(pins_o, &n_pins, &pins); + if (n_pins != 2 && n_pins != 4) { + goto error; + } + if (n_pins == 4) { + if (pins[PIN_TYPE_UART_RTS] != mp_const_none && pins[PIN_TYPE_UART_RX] == mp_const_none) { + goto error; // RTS pin given in TX only mode + } else if (pins[PIN_TYPE_UART_CTS] != mp_const_none && pins[PIN_TYPE_UART_TX] == mp_const_none) { + goto error; // CTS pin given in RX only mode + } else { + if (pins[PIN_TYPE_UART_RTS] != mp_const_none) { + flowcontrol |= UART_FLOWCONTROL_RX; + } + if (pins[PIN_TYPE_UART_CTS] != mp_const_none) { + flowcontrol |= UART_FLOWCONTROL_TX; + } + } + } + } + pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_UART, self->uart_id); + } + + self->baudrate = baudrate; + self->config = config; + self->flowcontrol = flowcontrol; + + // initialize and enable the uart + uart_init (self); + // register it with the sleep module + pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init); + // enable the callback + uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none); + // disable the irq (from the user point of view) + uart_irq_disable(self); + + return mp_const_none; + +error: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} + +STATIC const mp_arg_t pyb_uart_init_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_uart_init_args, args); + + // work out the uart id + uint uart_id; + if (args[0].u_obj == MP_OBJ_NULL) { + if (args[5].u_obj != MP_OBJ_NULL) { + mp_obj_t *pins; + size_t n_pins = 2; + mp_obj_get_array(args[5].u_obj, &n_pins, &pins); + // check the Tx pin (or the Rx if Tx is None) + if (pins[0] == mp_const_none) { + uart_id = pin_find_peripheral_unit(pins[1], PIN_FN_UART, PIN_TYPE_UART_RX); + } else { + uart_id = pin_find_peripheral_unit(pins[0], PIN_FN_UART, PIN_TYPE_UART_TX); + } + } else { + // default id + uart_id = 0; + } + } else { + uart_id = mp_obj_get_int(args[0].u_obj); + } + + if (uart_id > PYB_UART_1) { + mp_raise_OSError(MP_ENODEV); + } + + // get the correct uart instance + pyb_uart_obj_t *self = &pyb_uart_obj[uart_id]; + self->base.type = &pyb_uart_type; + self->uart_id = uart_id; + + // start the peripheral + pyb_uart_init_helper(self, &args[1]); + + return self; +} + +STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_uart_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_uart_init_args[1], args); + return pyb_uart_init_helper(pos_args[0], args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); + +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + + // unregister it with the sleep module + pyb_sleep_remove (self); + // invalidate the baudrate + self->baudrate = 0; + // free the read buffer + m_del(byte, self->read_buf, PYBUART_RX_BUFFER_LEN); + MAP_UARTIntDisable(self->reg, UART_INT_RX | UART_INT_RT); + MAP_UARTDisable(self->reg); + MAP_PRCMPeripheralClkDisable(self->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit); + +STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + uart_check_init(self); + return mp_obj_new_int(uart_rx_any(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any); + +STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + uart_check_init(self); + // send a break signal for at least 2 complete frames + MAP_UARTBreakCtl(self->reg, true); + UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBUART_2_FRAMES_TIME_US(self->baudrate))); + MAP_UARTBreakCtl(self->reg, false); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak); + +/// \method irq(trigger, priority, handler, wake) +STATIC mp_obj_t pyb_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); + + // check if any parameters were passed + pyb_uart_obj_t *self = pos_args[0]; + uart_check_init(self); + + // convert the priority to the correct value + uint priority = mp_irq_translate_priority (args[1].u_int); + + // check the power mode + uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj); + if (PYB_PWR_MODE_ACTIVE != pwrmode) { + goto invalid_args; + } + + // check the trigger + uint trigger = mp_obj_get_int(args[0].u_obj); + if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) { + goto invalid_args; + } + + // register a new callback + return uart_irq_new (self, trigger, priority, args[2].u_obj); + +invalid_args: + mp_raise_ValueError(mpexception_value_invalid_arguments); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq); + +STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_uart_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&pyb_uart_sendbreak_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_uart_irq_obj) }, + + /// \method read([nbytes]) + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + /// \method readline() + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + /// \method readinto(buf[, nbytes]) + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + /// \method write(buf) + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_RX_ANY), MP_ROM_INT(UART_TRIGGER_RX_ANY) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); + +STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = self_in; + byte *buf = buf_in; + uart_check_init(self); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + // wait for first char to become available + if (!uart_rx_wait(self)) { + // return MP_EAGAIN error to indicate non-blocking (then read() method returns None) + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // read the data + byte *orig_buf = buf; + for ( ; ; ) { + *buf++ = uart_rx_char(self); + if (--size == 0 || !uart_rx_wait(self)) { + // return number of bytes read + return buf - orig_buf; + } + } +} + +STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = self_in; + const char *buf = buf_in; + uart_check_init(self); + + // write the data + if (!uart_tx_strn(self, buf, size)) { + mp_raise_OSError(MP_EIO); + } + return size; +} + +STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + pyb_uart_obj_t *self = self_in; + mp_uint_t ret; + uart_check_init(self); + + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self)) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && MAP_UARTSpaceAvail(self->reg)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = pyb_uart_read, + .write = pyb_uart_write, + .ioctl = pyb_uart_ioctl, + .is_text = false, +}; + +STATIC const mp_irq_methods_t uart_irq_methods = { + .init = pyb_uart_irq, + .enable = uart_irq_enable, + .disable = uart_irq_disable, + .flags = uart_irq_flags +}; + +const mp_obj_type_t pyb_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = pyb_uart_print, + .make_new = pyb_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_t)&pyb_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybuart.h b/src/openmv/src/micropython/ports/cc3200/mods/pybuart.h new file mode 100755 index 0000000..d481242 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybuart.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBUART_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBUART_H + +typedef enum { + PYB_UART_0 = 0, + PYB_UART_1 = 1, + PYB_NUM_UARTS +} pyb_uart_id_t; + +typedef struct _pyb_uart_obj_t pyb_uart_obj_t; +extern const mp_obj_type_t pyb_uart_type; + +void uart_init0(void); +uint32_t uart_rx_any(pyb_uart_obj_t *uart_obj); +int uart_rx_char(pyb_uart_obj_t *uart_obj); +bool uart_tx_char(pyb_uart_obj_t *self, int c); +bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBUART_H diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.c b/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.c new file mode 100755 index 0000000..4a9fafc --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.c @@ -0,0 +1,160 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "inc/hw_types.h" +#include "inc/hw_gpio.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "wdt.h" +#include "prcm.h" +#include "utils.h" +#include "pybwdt.h" +#include "mpexception.h" +#include "mperror.h" + + +/****************************************************************************** + DECLARE CONSTANTS + ******************************************************************************/ +#define PYBWDT_MILLISECONDS_TO_TICKS(ms) ((80000000 / 1000) * (ms)) +#define PYBWDT_MIN_TIMEOUT_MS (1000) + +/****************************************************************************** + DECLARE TYPES + ******************************************************************************/ +typedef struct { + mp_obj_base_t base; + bool servers; + bool servers_sleeping; + bool simplelink; + bool running; +} pyb_wdt_obj_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC pyb_wdt_obj_t pyb_wdt_obj = {.servers = false, .servers_sleeping = false, .simplelink = false, .running = false}; + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +// must be called in main.c just after initializing the hal +__attribute__ ((section (".boot"))) +void pybwdt_init0 (void) { +} + +void pybwdt_srv_alive (void) { + pyb_wdt_obj.servers = true; +} + +void pybwdt_srv_sleeping (bool state) { + pyb_wdt_obj.servers_sleeping = state; +} + +void pybwdt_sl_alive (void) { + pyb_wdt_obj.simplelink = true; +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC const mp_arg_t pyb_wdt_init_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} }, // 5 s +}; +STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // check the arguments + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_wdt_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_wdt_init_args, args); + + if (args[0].u_obj != mp_const_none && mp_obj_get_int(args[0].u_obj) > 0) { + mp_raise_OSError(MP_ENODEV); + } + uint timeout_ms = args[1].u_int; + if (timeout_ms < PYBWDT_MIN_TIMEOUT_MS) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + if (pyb_wdt_obj.running) { + mp_raise_OSError(MP_EPERM); + } + + // Enable the WDT peripheral clock + MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + + // Unlock to be able to configure the registers + MAP_WatchdogUnlock(WDT_BASE); + +#ifdef DEBUG + // make the WDT stall when the debugger stops on a breakpoint + MAP_WatchdogStallEnable (WDT_BASE); +#endif + + // set the watchdog timer reload value + // the WDT trigger a system reset after the second timeout + // so, divide by 2 the timeout value received + MAP_WatchdogReloadSet(WDT_BASE, PYBWDT_MILLISECONDS_TO_TICKS(timeout_ms / 2)); + + // start the timer. Once it's started, it cannot be disabled. + MAP_WatchdogEnable(WDT_BASE); + pyb_wdt_obj.base.type = &pyb_wdt_type; + pyb_wdt_obj.running = true; + + return (mp_obj_t)&pyb_wdt_obj; +} + +STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) { + pyb_wdt_obj_t *self = self_in; + if ((self->servers || self->servers_sleeping) && self->simplelink && self->running) { + self->servers = false; + self->simplelink = false; + MAP_WatchdogIntClear(WDT_BASE); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed); + +STATIC const mp_rom_map_elem_t pybwdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&pyb_wdt_feed_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pybwdt_locals_dict, pybwdt_locals_dict_table); + +const mp_obj_type_t pyb_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = pyb_wdt_make_new, + .locals_dict = (mp_obj_t)&pybwdt_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.h b/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.h new file mode 100755 index 0000000..275c494 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mods/pybwdt.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MODS_PYBWDT_H +#define MICROPY_INCLUDED_CC3200_MODS_PYBWDT_H + +#include "py/obj.h" + +extern const mp_obj_type_t pyb_wdt_type; + +void pybwdt_init0 (void); +void pybwdt_srv_alive (void); +void pybwdt_srv_sleeping (bool state); +void pybwdt_sl_alive (void); + +#endif // MICROPY_INCLUDED_CC3200_MODS_PYBWDT_H diff --git a/src/openmv/src/micropython/ports/cc3200/mpconfigport.h b/src/openmv/src/micropython/ports/cc3200/mpconfigport.h new file mode 100755 index 0000000..ee9a226 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mpconfigport.h @@ -0,0 +1,235 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#ifndef BOOTLOADER +#include "FreeRTOS.h" +#include "semphr.h" +#endif + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_READER_VFS (1) +#ifndef DEBUG // we need ram on the launchxl while debugging +#define MICROPY_CPYTHON_COMPAT (1) +#else +#define MICROPY_CPYTHON_COMPAT (0) +#endif +#define MICROPY_QSTR_BYTES_IN_HASH (1) + +// fatfs configuration used in ffconf.h +#define MICROPY_FATFS_ENABLE_LFN (2) +#define MICROPY_FATFS_MAX_LFN (MICROPY_ALLOC_PATH_MAX) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) // 1=SFN/ANSI 437=LFN/U.S.(OEM) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_REENTRANT (1) +#define MICROPY_FATFS_TIMEOUT (2500) +#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t + +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (1) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT cc3200_help_text +#ifndef DEBUG +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#else +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_EXECFILE (0) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) +#endif +#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UERRNO_ERRORCODE (0) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (1) +#define MICROPY_PY_UBINASCII (0) +#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIME_MP_HAL (1) + +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) +#define MICROPY_KBD_EXCEPTION (1) + +// We define our own list of errno constants to include in uerrno module +#define MICROPY_PY_UERRNO_LIST \ + X(EPERM) \ + X(EIO) \ + X(ENODEV) \ + X(EINVAL) \ + X(ETIMEDOUT) \ + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, \ + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t machine_module; +extern const struct _mp_obj_module_t wipy_module; +extern const struct _mp_obj_module_t mp_module_ure; +extern const struct _mp_obj_module_t mp_module_ujson; +extern const struct _mp_obj_module_t mp_module_uos; +extern const struct _mp_obj_module_t mp_module_utime; +extern const struct _mp_obj_module_t mp_module_uselect; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_ubinascii; +extern const struct _mp_obj_module_t mp_module_ussl; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_wipy), MP_ROM_PTR(&wipy_module) }, \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, \ + { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, \ + { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) }, \ + { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ + { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ + { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \ + { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, \ + { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ + { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + +// extra constants +#define MICROPY_PORT_CONSTANTS \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ + +// vm state and root pointers for the gc +#define MP_STATE_PORT MP_STATE_VM +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t mp_const_user_interrupt; \ + mp_obj_t machine_config_main; \ + mp_obj_list_t pyb_sleep_obj_list; \ + mp_obj_list_t mp_irq_obj_list; \ + mp_obj_list_t pyb_timer_channel_obj_list; \ + struct _pyb_uart_obj_t *pyb_uart_objs[2]; \ + struct _os_term_dup_obj_t *os_term_dup_obj; \ + + +// type definitions for the specific machine +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) +#define MP_SSIZE_MAX (0x7FFFFFFF) + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() +#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) +#define MICROPY_EVENT_POLL_HOOK __WFI(); + +// assembly functions to handle critical sections, interrupt +// disabling/enabling and sleep mode enter/exit +#include "cc3200_asm.h" + +// We need to provide a declaration/definition of alloca() +#include + +// Include board specific configuration +#include "mpconfigboard.h" + +#define MICROPY_MPHALPORT_H "cc3200_hal.h" +#define MICROPY_PORT_HAS_TELNET (1) +#define MICROPY_PORT_HAS_FTP (1) +#define MICROPY_PY_SYS_PLATFORM "WiPy" + +#define MICROPY_PORT_WLAN_AP_SSID "wipy-wlan" +#define MICROPY_PORT_WLAN_AP_KEY "www.wipy.io" +#define MICROPY_PORT_WLAN_AP_SECURITY SL_SEC_TYPE_WPA_WPA2 +#define MICROPY_PORT_WLAN_AP_CHANNEL 5 diff --git a/src/openmv/src/micropython/ports/cc3200/mptask.c b/src/openmv/src/micropython/ports/cc3200/mptask.c new file mode 100755 index 0000000..6143f72 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mptask.c @@ -0,0 +1,396 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/stackctrl.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pin.h" +#include "prcm.h" +#include "interrupt.h" +#include "pybuart.h" +#include "pybpin.h" +#include "pybrtc.h" +#include "lib/utils/pyexec.h" +#include "gccollect.h" +#include "gchelper.h" +#include "mperror.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modusocket.h" +#include "modwlan.h" +#include "serverstask.h" +#include "telnet.h" +#include "debug.h" +#include "sflash_diskio.h" +#include "random.h" +#include "pybi2c.h" +#include "pins.h" +#include "mods/pybflash.h" +#include "pybsleep.h" +#include "pybtimer.h" +#include "cryptohash.h" +#include "mpirq.h" +#include "updater.h" +#include "moduos.h" +#include "antenna.h" +#include "task.h" + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC void mptask_pre_init (void); +STATIC void mptask_init_sflash_filesystem (void); +STATIC void mptask_enter_ap_mode (void); +STATIC void mptask_create_main_py (void); + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ +#ifdef DEBUG +OsiTaskHandle svTaskHandle; +#endif + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +static fs_user_mount_t *sflash_vfs_fat; + +static const char fresh_main_py[] = "# main.py -- put your code here!\r\n"; +static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" + "# can run arbitrary Python, but best to keep it minimal\r\n" + #if MICROPY_STDIO_UART + "import os, machine\r\n" + "os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n" + #endif + ; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ + +void TASK_MicroPython (void *pvParameters) { + // get the top of the stack to initialize the garbage collector + uint32_t sp = gc_helper_get_sp(); + + bool safeboot = false; + mptask_pre_init(); + +#ifndef DEBUG + safeboot = PRCMGetSpecialBit(PRCM_SAFE_BOOT_BIT); +#endif + +soft_reset: + + // Thread init + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif + + // initialise the stack pointer for the main thread (must be done after mp_thread_init) + mp_stack_set_top((void*)sp); + + // GC init + gc_init(&_boot, &_eheap); + + // MicroPython init + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + + // execute all basic initializations + mp_irq_init0(); + pyb_sleep_init0(); + pin_init0(); + mperror_init0(); + uart_init0(); + timer_init0(); + readline_init0(); + mod_network_init0(); + rng_init0(); + + pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause(); + if (rstcause < PYB_SLP_SOFT_RESET) { + if (rstcause == PYB_SLP_HIB_RESET) { + // when waking up from hibernate we just want + // to enable simplelink and leave it as is + wlan_first_start(); + } + else { + // only if not comming out of hibernate or a soft reset + mptask_enter_ap_mode(); + } + + // enable telnet and ftp + servers_start(); + } + + // initialize the serial flash file system + mptask_init_sflash_filesystem(); + + // append the flash paths to the system path + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); + + // reset config variables; they should be set by boot.py + MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL; + + if (!safeboot) { + // run boot.py + int ret = pyexec_file("boot.py"); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + // flash the system led + mperror_signal_error(); + } + } + + // now we initialise sub-systems that need configuration from boot.py, + // or whose initialisation can be safely deferred until after running + // boot.py. + + // at this point everything is fully configured and initialised. + + if (!safeboot) { + // run the main script from the current directory. + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + const char *main_py; + if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) { + main_py = "main.py"; + } else { + main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main)); + } + int ret = pyexec_file(main_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + // flash the system led + mperror_signal_error(); + } + } + } + + // main script is finished, so now go into REPL mode. + // the REPL mode can change, or it can request a soft reset. + for ( ; ; ) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + +soft_reset_exit: + + // soft reset + pyb_sleep_signal_soft_reset(); + mp_printf(&mp_plat_print, "PYB: soft reboot\n"); + + // disable all callbacks to avoid undefined behaviour + // when coming out of a soft reset + mp_irq_disable_all(); + + // cancel the RTC alarm which might be running independent of the irq state + pyb_rtc_disable_alarm(); + + // flush the serial flash buffer + sflash_disk_flush(); + + // clean-up the user socket space + modusocket_close_all_user_sockets(); + + // unmount all user file systems + osmount_unmount_all(); + + // wait for pending transactions to complete + mp_hal_delay_ms(20); + + goto soft_reset; +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +__attribute__ ((section (".boot"))) +STATIC void mptask_pre_init (void) { + // this one only makes sense after a poweron reset + pyb_rtc_pre_init(); + + // Create the simple link spawn task + ASSERT (OSI_OK == VStartSimpleLinkSpawnTask(SIMPLELINK_SPAWN_TASK_PRIORITY)); + + // Allocate memory for the flash file system + ASSERT ((sflash_vfs_fat = mem_Malloc(sizeof(*sflash_vfs_fat))) != NULL); + + // this one allocates memory for the nvic vault + pyb_sleep_pre_init(); + + // this one allocates memory for the WLAN semaphore + wlan_pre_init(); + + // this one allocates memory for the updater semaphore + updater_pre_init(); + + // this one allocates memory for the socket semaphore + modusocket_pre_init(); + + //CRYPTOHASH_Init(); + +#ifndef DEBUG + OsiTaskHandle svTaskHandle; +#endif + svTaskHandle = xTaskCreateStatic(TASK_Servers, "Servers", + SERVERS_STACK_LEN, NULL, SERVERS_PRIORITY, svTaskStack, &svTaskTCB); + ASSERT(svTaskHandle != NULL); +} + +STATIC void mptask_init_sflash_filesystem (void) { + FILINFO fno; + + // Initialise the local flash filesystem. + // init the vfs object + fs_user_mount_t *vfs_fat = sflash_vfs_fat; + vfs_fat->flags = 0; + pyb_flash_init_vfs(vfs_fat); + + // Create it if needed, and mount in on /flash. + FRESULT res = f_mount(&vfs_fat->fatfs); + if (res == FR_NO_FILESYSTEM) { + // no filesystem, so create a fresh one + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&vfs_fat->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res == FR_OK) { + // success creating fresh LFS + } else { + __fatal_error("failed to create /flash"); + } + // create empty main.py + mptask_create_main_py(); + } else if (res == FR_OK) { + // mount sucessful + if (FR_OK != f_stat(&vfs_fat->fatfs, "/main.py", &fno)) { + // create empty main.py + mptask_create_main_py(); + } + } else { + fail: + __fatal_error("failed to create /flash"); + } + + // mount the flash device (there should be no other devices mounted at this point) + // we allocate this structure on the heap because vfs->next is a root pointer + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL) { + goto fail; + } + vfs->str = "/flash"; + vfs->len = 6; + vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); + vfs->next = NULL; + MP_STATE_VM(vfs_mount_table) = vfs; + + // The current directory is used as the boot up directory. + // It is set to the internal flash filesystem by default. + MP_STATE_PORT(vfs_cur) = vfs; + + // create /flash/sys, /flash/lib and /flash/cert if they don't exist + if (FR_OK != f_chdir(&vfs_fat->fatfs, "/sys")) { + f_mkdir(&vfs_fat->fatfs, "/sys"); + } + if (FR_OK != f_chdir(&vfs_fat->fatfs, "/lib")) { + f_mkdir(&vfs_fat->fatfs, "/lib"); + } + if (FR_OK != f_chdir(&vfs_fat->fatfs, "/cert")) { + f_mkdir(&vfs_fat->fatfs, "/cert"); + } + + f_chdir(&vfs_fat->fatfs, "/"); + + // make sure we have a /flash/boot.py. Create it if needed. + res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno); + if (res == FR_OK) { + if (fno.fattrib & AM_DIR) { + // exists as a directory + // TODO handle this case + // see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation + } else { + // exists as a file, good! + } + } else { + // doesn't exist, create fresh file + FIL fp; + f_open(&vfs_fat->fatfs, &fp, "/boot.py", FA_WRITE | FA_CREATE_ALWAYS); + UINT n; + f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n); + // TODO check we could write n bytes + f_close(&fp); + } +} + +STATIC void mptask_enter_ap_mode (void) { + // append the mac only if it's not the first boot + bool add_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT); + // enable simplelink in ap mode (use the MAC address to make the ssid unique) + wlan_sl_init (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID), + MICROPY_PORT_WLAN_AP_SECURITY, MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY), + MICROPY_PORT_WLAN_AP_CHANNEL, ANTENNA_TYPE_INTERNAL, add_mac); +} + +STATIC void mptask_create_main_py (void) { + // create empty main.py + FIL fp; + f_open(&sflash_vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS); + UINT n; + f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n); + f_close(&fp); +} diff --git a/src/openmv/src/micropython/ports/cc3200/mptask.h b/src/openmv/src/micropython/ports/cc3200/mptask.h new file mode 100755 index 0000000..a1c3eb2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mptask.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_MPTASK_H +#define MICROPY_INCLUDED_CC3200_MPTASK_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define MICROPY_TASK_PRIORITY (2) +#define MICROPY_TASK_STACK_SIZE ((6 * 1024) + 512) // in bytes +#define MICROPY_TASK_STACK_LEN (MICROPY_TASK_STACK_SIZE / sizeof(StackType_t)) + +/****************************************************************************** + EXPORTED DATA + ******************************************************************************/ +extern StackType_t mpTaskStack[]; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +extern void TASK_MicroPython (void *pvParameters); + +#endif // MICROPY_INCLUDED_CC3200_MPTASK_H diff --git a/src/openmv/src/micropython/ports/cc3200/mpthreadport.c b/src/openmv/src/micropython/ports/cc3200/mpthreadport.c new file mode 100755 index 0000000..9dbc518 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mpthreadport.c @@ -0,0 +1,188 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "py/mphal.h" +#include "mptask.h" +#include "task.h" +#include "irq.h" + +#if MICROPY_PY_THREAD + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + size_t stack_len; // number of words in the stack + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled bp mp_thread_gc_others + +void mp_thread_init(void) { + mp_thread_mutex_init(&thread_mutex); + mp_thread_set_state(&mp_state_ctx.thread); + + // create first entry in linked list of all threads + thread = &thread_entry0; + thread->id = xTaskGetCurrentTaskHandle(); + thread->ready = 1; + thread->arg = NULL; + thread->stack = mpTaskStack; + thread->stack_len = MICROPY_TASK_STACK_LEN; + thread->next = NULL; +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); // probably not needed + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); // probably not needed + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 0); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 0, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;) { + } +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (*stack_size == 0) { + *stack_size = 4096; // default stack size + } else if (*stack_size < 2048) { + *stack_size = 2048; // minimum stack size + } + + // allocate TCB, stack and linked-list node (must be outside thread_mutex lock) + StaticTask_t *tcb = m_new(StaticTask_t, 1); + StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t)); + thread_t *th = m_new_obj(thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", *stack_size / sizeof(void*), arg, 2, stack, tcb); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + mp_raise_msg(&mp_type_OSError, "can't create thread"); + } + + // add thread to linked list of all threads + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->stack_len = *stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); + + // adjust stack_size to provide room to recover from hitting the limit + *stack_size -= 512; +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + // TODO unlink from list + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); +} + +// To allow hard interrupts to work with threading we only take/give the semaphore +// if we are not within an interrupt context and interrupts are enabled. + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); + return ret == pdTRUE; + } else { + return 1; + } +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + xSemaphoreGive(mutex->handle); + // TODO check return value + } +} + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/ports/cc3200/mpthreadport.h b/src/openmv/src/micropython/ports/cc3200/mpthreadport.h new file mode 100755 index 0000000..dc9ba99 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/mpthreadport.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BOOTLOADER +#include "FreeRTOS.h" +#endif + +typedef struct _mp_thread_mutex_t { + #ifndef BOOTLOADER + SemaphoreHandle_t handle; + StaticSemaphore_t buffer; + #endif +} mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); diff --git a/src/openmv/src/micropython/ports/cc3200/qstrdefsport.h b/src/openmv/src/micropython/ports/cc3200/qstrdefsport.h new file mode 100755 index 0000000..d5f22d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/qstrdefsport.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// for machine module +Q(/) +// entries for sys.path +Q(/flash) +Q(/flash/lib) diff --git a/src/openmv/src/micropython/ports/cc3200/serverstask.c b/src/openmv/src/micropython/ports/cc3200/serverstask.c new file mode 100755 index 0000000..100b8d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/serverstask.c @@ -0,0 +1,210 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "serverstask.h" +#include "simplelink.h" +#include "debug.h" +#include "telnet.h" +#include "ftp.h" +#include "pybwdt.h" +#include "modusocket.h" +#include "mpexception.h" +#include "modnetwork.h" +#include "modwlan.h" + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef struct { + uint32_t timeout; + bool enabled; + bool do_disable; + bool do_enable; + bool do_reset; + bool do_wlan_cycle_power; +} servers_data_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +static servers_data_t servers_data = {.timeout = SERVERS_DEF_TIMEOUT_MS}; +static volatile bool sleep_sockets = false; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ + +/****************************************************************************** + DECLARE PUBLIC DATA + ******************************************************************************/ + +// This is the static memory (TCB and stack) for the servers task +StaticTask_t svTaskTCB __attribute__ ((section (".rtos_heap"))); +StackType_t svTaskStack[SERVERS_STACK_LEN] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +char servers_user[SERVERS_USER_PASS_LEN_MAX + 1]; +char servers_pass[SERVERS_USER_PASS_LEN_MAX + 1]; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +void TASK_Servers (void *pvParameters) { + + bool cycle = false; + + strcpy (servers_user, SERVERS_DEF_USER); + strcpy (servers_pass, SERVERS_DEF_PASS); + + telnet_init(); + ftp_init(); + + for ( ;; ) { + + if (servers_data.do_enable) { + // enable network services + telnet_enable(); + ftp_enable(); + // now set/clear the flags + servers_data.enabled = true; + servers_data.do_enable = false; + } + else if (servers_data.do_disable) { + // disable network services + telnet_disable(); + ftp_disable(); + // now clear the flags + servers_data.do_disable = false; + servers_data.enabled = false; + } + else if (servers_data.do_reset) { + // resetting the servers is needed to prevent half-open sockets + servers_data.do_reset = false; + if (servers_data.enabled) { + telnet_reset(); + ftp_reset(); + } + // and we should also close all user sockets. We do it here + // for convinience and to save on code size. + modusocket_close_all_user_sockets(); + } + + if (cycle) { + telnet_run(); + } + else { + ftp_run(); + } + + if (sleep_sockets) { + pybwdt_srv_sleeping(true); + modusocket_enter_sleep(); + pybwdt_srv_sleeping(false); + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 2); + if (servers_data.do_wlan_cycle_power) { + servers_data.do_wlan_cycle_power = false; + wlan_off_on(); + } + sleep_sockets = false; + + } + + // set the alive flag for the wdt + pybwdt_srv_alive(); + + // move to the next cycle + cycle = cycle ? false : true; + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS); + } +} + +void servers_start (void) { + servers_data.do_enable = true; + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 3); +} + +void servers_stop (void) { + servers_data.do_disable = true; + do { + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS); + } while (servers_are_enabled()); + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 3); +} + +void servers_reset (void) { + servers_data.do_reset = true; +} + +void servers_wlan_cycle_power (void) { + servers_data.do_wlan_cycle_power = true; +} + +bool servers_are_enabled (void) { + return servers_data.enabled; +} + +void server_sleep_sockets (void) { + sleep_sockets = true; + mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS + 1); +} + +void servers_close_socket (int16_t *sd) { + if (*sd > 0) { + modusocket_socket_delete(*sd); + sl_Close(*sd); + *sd = -1; + } +} + +void servers_set_login (char *user, char *pass) { + if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) { + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX); + memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX); +} + +void servers_set_timeout (uint32_t timeout) { + if (timeout < SERVERS_MIN_TIMEOUT_MS) { + // timeout is too low + mp_raise_ValueError(mpexception_value_invalid_arguments); + } + servers_data.timeout = timeout; +} + +uint32_t servers_get_timeout (void) { + return servers_data.timeout; +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ diff --git a/src/openmv/src/micropython/ports/cc3200/serverstask.h b/src/openmv/src/micropython/ports/cc3200/serverstask.h new file mode 100755 index 0000000..c4533d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/serverstask.h @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_SERVERSTASK_H +#define MICROPY_INCLUDED_CC3200_SERVERSTASK_H + +/****************************************************************************** + DEFINE CONSTANTS + ******************************************************************************/ +#define SERVERS_PRIORITY 2 +#define SERVERS_STACK_SIZE 1024 // in bytes +#define SERVERS_STACK_LEN (SERVERS_STACK_SIZE / sizeof(StackType_t)) + +#define SERVERS_SSID_LEN_MAX 16 +#define SERVERS_KEY_LEN_MAX 16 + +#define SERVERS_USER_PASS_LEN_MAX 32 + +#define SERVERS_CYCLE_TIME_MS 2 + +#define SERVERS_DEF_USER "micro" +#define SERVERS_DEF_PASS "python" +#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes +#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds + +/****************************************************************************** + DEFINE TYPES + ******************************************************************************/ + +/****************************************************************************** + EXPORTED DATA + ******************************************************************************/ +extern StaticTask_t svTaskTCB; +extern StackType_t svTaskStack[]; +extern char servers_user[]; +extern char servers_pass[]; + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +extern void TASK_Servers (void *pvParameters); +extern void servers_start (void); +extern void servers_stop (void); +extern void servers_reset (void); +extern void servers_wlan_cycle_power (void); +extern bool servers_are_enabled (void); +extern void servers_close_socket (int16_t *sd); +extern void servers_set_login (char *user, char *pass); +extern void server_sleep_sockets (void); +extern void servers_set_timeout (uint32_t timeout); +extern uint32_t servers_get_timeout (void); + +#endif // MICROPY_INCLUDED_CC3200_SERVERSTASK_H diff --git a/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.c b/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.c new file mode 100755 index 0000000..7b0be5d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.c @@ -0,0 +1,517 @@ +//***************************************************************************** +// cc_pal.c +// +// simplelink abstraction file for CC3200 +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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. +// +//***************************************************************************** + +//Simplelink includes +#include +#include + +//Driverlib includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define REG_INT_MASK_SET 0x400F7088 +#define REG_INT_MASK_CLR 0x400F708C +#define APPS_SOFT_RESET_REG 0x4402D000 +#define OCP_SHARED_MAC_RESET_REG 0x4402E168 + +#define SPI_RATE_20M 20000000 + +#define UNUSED(x) (x = x) + +// +// GLOBAL VARIABLES -- Start +// +volatile Fd_t g_SpiFd =0; +P_EVENT_HANDLER g_pHostIntHdl = NULL; + +// +// GLOBAL VARIABLES -- End +// + + +//**************************************************************************** +// LOCAL FUNCTION PROTOTYPES +//**************************************************************************** +static int spi_Read_CPU(unsigned char *pBuff, int len); +static int spi_Write_CPU(unsigned char *pBuff, int len); + +//**************************************************************************** +// LOCAL FUNCTION DEFINITIONS +//**************************************************************************** + +/*! + \brief attempts to read up to len bytes from SPI channel into a buffer starting at pBuff. + + \param pBuff - points to first location to start writing the data + + \param len - number of bytes to read from the SPI channel + + \return upon successful completion, the function shall return Read Size. + Otherwise, -1 shall be returned + + \sa spi_Read_CPU , spi_Write_CPU + \note + \warning +*/ +int spi_Read_CPU(unsigned char *pBuff, int len) +{ + unsigned long ulCnt; + unsigned long ulStatusReg; + unsigned long *ulDataIn; + unsigned long ulTxReg; + unsigned long ulRxReg; + + MAP_SPICSEnable(LSPI_BASE); + + // + // Initialize local variable. + // + ulDataIn = (unsigned long *)pBuff; + ulCnt = (len + 3) >> 2; + ulStatusReg = LSPI_BASE+MCSPI_O_CH0STAT; + ulTxReg = LSPI_BASE + MCSPI_O_TX0; + ulRxReg = LSPI_BASE + MCSPI_O_RX0; + + // + // Reading loop + // + while(ulCnt--) + { + while(!( HWREG(ulStatusReg)& MCSPI_CH0STAT_TXS )); + HWREG(ulTxReg) = 0xFFFFFFFF; + while(!( HWREG(ulStatusReg)& MCSPI_CH0STAT_RXS )); + *ulDataIn = HWREG(ulRxReg); + ulDataIn++; + } + + MAP_SPICSDisable(LSPI_BASE); + + return len; +} + +/*! + \brief attempts to write up to len bytes to the SPI channel + + \param pBuff - points to first location to start getting the data from + + \param len - number of bytes to write to the SPI channel + + \return upon successful completion, the function shall return write size. + Otherwise, -1 shall be returned + + \sa spi_Read_CPU , spi_Write_CPU + \note This function could be implemented as zero copy and return only upon successful completion + of writing the whole buffer, but in cases that memory allocation is not too tight, the + function could copy the data to internal buffer, return back and complete the write in + parallel to other activities as long as the other SPI activities would be blocked untill + the entire buffer write would be completed + \warning +*/ +int spi_Write_CPU(unsigned char *pBuff, int len) +{ + unsigned long ulCnt; + unsigned long ulStatusReg; + unsigned long *ulDataOut; + unsigned long ulDataIn; + unsigned long ulTxReg; + unsigned long ulRxReg; + + + MAP_SPICSEnable(LSPI_BASE); + + // + // Initialize local variable. + // + ulDataOut = (unsigned long *)pBuff; + ulCnt = (len +3 ) >> 2; + ulStatusReg = LSPI_BASE+MCSPI_O_CH0STAT; + ulTxReg = LSPI_BASE + MCSPI_O_TX0; + ulRxReg = LSPI_BASE + MCSPI_O_RX0; + + // + // Writing Loop + // + while(ulCnt--) + { + while(!( HWREG(ulStatusReg)& MCSPI_CH0STAT_TXS )); + HWREG(ulTxReg) = *ulDataOut; + while(!( HWREG(ulStatusReg)& MCSPI_CH0STAT_RXS )); + ulDataIn = HWREG(ulRxReg); + ulDataOut++; + } + + MAP_SPICSDisable(LSPI_BASE); + + UNUSED(ulDataIn); + return len; +} + +/*! + \brief open spi communication port to be used for communicating with a SimpleLink device + + Given an interface name and option flags, this function opens the spi communication port + and creates a file descriptor. This file descriptor can be used afterwards to read and + write data from and to this specific spi channel. + The SPI speed, clock polarity, clock phase, chip select and all other attributes are all + set to hardcoded values in this function. + + \param ifName - points to the interface name/path. The interface name is an + optional attributes that the simple link driver receives + on opening the device. in systems that the spi channel is + not implemented as part of the os device drivers, this + parameter could be NULL. + \param flags - option flags + + \return upon successful completion, the function shall open the spi channel and return + a non-negative integer representing the file descriptor. + Otherwise, -1 shall be returned + + \sa spi_Close , spi_Read , spi_Write + \note + \warning +*/ + +Fd_t spi_Open(char *ifName, unsigned long flags) +{ + unsigned long ulBase; + unsigned long ulSpiBitRate = SPI_RATE_20M; + + //NWP master interface + ulBase = LSPI_BASE; + + //Enable MCSPIA2 + MAP_PRCMPeripheralClkEnable(PRCM_LSPI,PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + + //Disable Chip Select + MAP_SPICSDisable(ulBase); + + //Disable SPI Channel + MAP_SPIDisable(ulBase); + + // Reset SPI + MAP_SPIReset(ulBase); + + // + // Configure SPI interface + // + + MAP_SPIConfigSetExpClk(ulBase,MAP_PRCMPeripheralClockGet(PRCM_LSPI), + ulSpiBitRate,SPI_MODE_MASTER,SPI_SUB_MODE_0, + (SPI_SW_CTRL_CS | + SPI_4PIN_MODE | + SPI_TURBO_OFF | + SPI_CS_ACTIVEHIGH | + SPI_WL_32)); + + MAP_SPIEnable(ulBase); + + g_SpiFd = 1; + return g_SpiFd; +} +/*! + \brief closes an opened spi communication port + + \param fd - file descriptor of an opened SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open + \note + \warning +*/ +int spi_Close(Fd_t fd) +{ + unsigned long ulBase = LSPI_BASE; + + g_SpiFd = 0; + + //Disable Chip Select + MAP_SPICSDisable(LSPI_BASE); + + + //Disable SPI Channel + MAP_SPIDisable(ulBase); + + // Reset SPI + MAP_SPIReset(ulBase); + + // Disable SPI Peripheral + MAP_PRCMPeripheralClkDisable(PRCM_LSPI,PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + + return 0; +} + +/*! + \brief closes an opened spi communication port + + \param fd - file descriptor of an opened SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open + \note + \warning +*/ + +int spi_Read(Fd_t fd, unsigned char *pBuff, int len) +{ + if (fd != 1 || g_SpiFd != 1) { + return -1; + } + + return spi_Read_CPU(pBuff, len); +} + +/*! + \brief attempts to write up to len bytes to the SPI channel + + \param fd - file descriptor of an opened SPI channel + + \param pBuff - points to first location to start getting the data from + + \param len - number of bytes to write to the SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open , spi_Read + \note This function could be implemented as zero copy and return only upon successful completion + of writing the whole buffer, but in cases that memory allocation is not too tight, the + function could copy the data to internal buffer, return back and complete the write in + parallel to other activities as long as the other SPI activities would be blocked untill + the entire buffer write would be completed + \warning +*/ +int spi_Write(Fd_t fd, unsigned char *pBuff, int len) +{ + if (fd != 1 || g_SpiFd != 1) { + return -1; + } + + return spi_Write_CPU(pBuff,len); +} + +/*! + \brief register an interrupt handler for the host IRQ + + \param InterruptHdl - pointer to interrupt handler function + + \param pValue - pointer to a memory strcuture that is passed to the interrupt handler. + + \return upon successful registration, the function shall return 0. + Otherwise, -1 shall be returned + + \sa + \note If there is already registered interrupt handler, the function should overwrite the old handler + with the new one + \warning +*/ + +int NwpRegisterInterruptHandler(P_EVENT_HANDLER InterruptHdl , void* pValue) +{ + + if(InterruptHdl == NULL) + { + //De-register Interprocessor communication interrupt between App and NWP + #ifdef SL_PLATFORM_MULTI_THREADED + osi_InterruptDeRegister(INT_NWPIC); + #else + MAP_IntDisable(INT_NWPIC); + MAP_IntUnregister(INT_NWPIC); + MAP_IntPendClear(INT_NWPIC); + #endif + } + else + { + #ifdef SL_PLATFORM_MULTI_THREADED + MAP_IntPendClear(INT_NWPIC); + osi_InterruptRegister(INT_NWPIC, (P_OSI_INTR_ENTRY)InterruptHdl,INT_PRIORITY_LVL_1); + #else + MAP_IntRegister(INT_NWPIC, InterruptHdl); + MAP_IntPrioritySet(INT_NWPIC, INT_PRIORITY_LVL_1); + MAP_IntPendClear(INT_NWPIC); + MAP_IntEnable(INT_NWPIC); + #endif + } + + return 0; +} + + +/*! + \brief Masks host IRQ + + + \sa NwpUnMaskInterrupt + + \warning +*/ +void NwpMaskInterrupt() +{ + (*(unsigned long *)REG_INT_MASK_SET) = 0x1; +} + + +/*! + \brief Unmasks host IRQ + + + \sa NwpMaskInterrupt + + \warning +*/ +void NwpUnMaskInterrupt() +{ + (*(unsigned long *)REG_INT_MASK_CLR) = 0x1; +} + +#ifdef DEBUG +/*! + \brief Preamble to the enabling the Network Processor. + Placeholder to implement any pre-process operations + before enabling networking operations. + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec + +*/ +void NwpPowerOnPreamble(void) +{ + #define MAX_RETRY_COUNT 1000 + + unsigned int sl_stop_ind, apps_int_sts_raw, nwp_lpds_wake_cfg; + unsigned int retry_count; + /* Perform the sl_stop equivalent to ensure network services + are turned off if active */ + HWREG(0x400F70B8) = 1; /* APPs to NWP interrupt */ + UtilsDelay(800000/5); + + retry_count = 0; + nwp_lpds_wake_cfg = HWREG(0x4402D404); + sl_stop_ind = HWREG(0x4402E16C); + + if((nwp_lpds_wake_cfg != 0x20) && /* Check for NWP POR condition */ + !(sl_stop_ind & 0x2)) /* Check if sl_stop was executed */ + { + /* Loop until APPs->NWP interrupt is cleared or timeout */ + while(retry_count < MAX_RETRY_COUNT) + { + apps_int_sts_raw = HWREG(0x400F70C0); + if(apps_int_sts_raw & 0x1) + { + UtilsDelay(800000/5); + retry_count++; + } + else + { + break; + } + } + } + HWREG(0x400F70B0) = 1; /* Clear APPs to NWP interrupt */ + UtilsDelay(800000/5); + + /* Stop the networking services */ + NwpPowerOff(); +} +#endif + +/*! + \brief Enable the Network Processor + + \sa sl_DeviceDisable + + \note belongs to \ref ported_sec + +*/ +void NwpPowerOn(void) +{ + //bring the 1.32 eco out of reset + HWREG(0x4402E16C) &= 0xFFFFFFFD; + + //NWP Wakeup + HWREG(0x44025118) = 1; +#ifdef DEBUG + UtilsDelay(8000000); +#endif + + //UnMask Host Interrupt + NwpUnMaskInterrupt(); +} + + +/*! + \brief Disable the Network Processor + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec +*/ +void NwpPowerOff(void) +{ + //Must delay 300 usec to enable the NWP to finish all sl_stop activities + UtilsDelay(300*80/3); + + //Mask Host Interrupt + NwpMaskInterrupt(); + + //Switch to PFM Mode + HWREG(0x4402F024) &= 0xF7FFFFFF; + + //sl_stop eco for PG1.32 devices + HWREG(0x4402E16C) |= 0x2; + + UtilsDelay(800000); +} diff --git a/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.h b/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.h new file mode 100755 index 0000000..1cf83e7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/simplelink/cc_pal.h @@ -0,0 +1,202 @@ +//***************************************************************************** +// cc_pal.h +// +// Simplelink abstraction header file for CC3200 +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __CC31xx_PAL_H__ +#define __CC31xx_PAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + +/*! + \brief type definition for the spi channel file descriptor + + \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. +*/ +typedef int Fd_t; + + +/*! + \brief type definition for the host interrupt handler + + \param pValue - pointer to any memory strcuture. The value of this pointer is givven on + registration of a new interrupt handler + + \note +*/ + +typedef void (*SL_P_EVENT_HANDLER)(void); + +#define P_EVENT_HANDLER SL_P_EVENT_HANDLER + +/*! + \brief open spi communication port to be used for communicating with a SimpleLink device + + Given an interface name and option flags, this function opens the spi communication port + and creates a file descriptor. This file descriptor can be used afterwards to read and + write data from and to this specific spi channel. + The SPI speed, clock polarity, clock phase, chip select and all other attributes are all + set to hardcoded values in this function. + + \param ifName - points to the interface name/path. The interface name is an + optional attributes that the simple link driver receives + on opening the device. in systems that the spi channel is + not implemented as part of the os device drivers, this + parameter could be NULL. + \param flags - option flags + + \return upon successful completion, the function shall open the spi channel and return + a non-negative integer representing the file descriptor. + Otherwise, -1 shall be returned + + \sa spi_Close , spi_Read , spi_Write + \note + \warning +*/ +Fd_t spi_Open(char *ifName, unsigned long flags); + +/*! + \brief closes an opened spi communication port + + \param fd - file descriptor of an opened SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open + \note + \warning +*/ +int spi_Close(Fd_t fd); + +/*! + \brief attempts to read up to len bytes from SPI channel into a buffer starting at pBuff. + + \param fd - file descriptor of an opened SPI channel + + \param pBuff - points to first location to start writing the data + + \param len - number of bytes to read from the SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open , spi_Write + \note + \warning +*/ +int spi_Read(Fd_t fd, unsigned char *pBuff, int len); + +/*! + \brief attempts to write up to len bytes to the SPI channel + + \param fd - file descriptor of an opened SPI channel + + \param pBuff - points to first location to start getting the data from + + \param len - number of bytes to write to the SPI channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa spi_Open , spi_Read + \note This function could be implemented as zero copy and return only upon successful completion + of writing the whole buffer, but in cases that memory allocation is not too tight, the + function could copy the data to internal buffer, return back and complete the write in + parallel to other activities as long as the other SPI activities would be blocked untill + the entire buffer write would be completed + \warning +*/ +int spi_Write(Fd_t fd, unsigned char *pBuff, int len); + +/*! + \brief register an interrupt handler for the host IRQ + + \param InterruptHdl - pointer to interrupt handler function + + \param pValue - pointer to a memory strcuture that is passed to the interrupt handler. + + \return upon successful registration, the function shall return 0. + Otherwise, -1 shall be returned + + \sa + \note If there is already registered interrupt handler, the function should overwrite the old handler + with the new one + \warning +*/ +int NwpRegisterInterruptHandler(P_EVENT_HANDLER InterruptHdl , void* pValue); + + +/*! + \brief Masks host IRQ + + + \sa NwpUnMaskInterrupt + + \warning +*/ +void NwpMaskInterrupt(); + + +/*! + \brief Unmasks host IRQ + + + \sa NwpMaskInterrupt + + \warning +*/ +void NwpUnMaskInterrupt(); + +void NwpPowerOnPreamble(void); + +void NwpPowerOff(void); + +void NwpPowerOn(void); + + +#ifdef __cplusplus +} +#endif // __cplusplus + + +#endif + diff --git a/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi.h b/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi.h new file mode 100755 index 0000000..11fe61b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi.h @@ -0,0 +1,580 @@ +//***************************************************************************** +// osi.h +// +// MACRO and Function prototypes for TI-RTOS and Free-RTOS API calls +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list zof conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 __OSI_H__ +#define __OSI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define OSI_WAIT_FOREVER (0xFFFFFFFF) + +#define OSI_NO_WAIT (0) + +typedef enum +{ + OSI_OK = 0, + OSI_FAILURE = -1, + OSI_OPERATION_FAILED = -2, + OSI_ABORTED = -3, + OSI_INVALID_PARAMS = -4, + OSI_MEMORY_ALLOCATION_FAILURE = -5, + OSI_TIMEOUT = -6, + OSI_EVENTS_IN_USE = -7, + OSI_EVENT_OPEARTION_FAILURE = -8 +}OsiReturnVal_e; + + +//#define ENTER_CRITICAL_SECTION osi_EnterCritical() +//#define EXIT_CRITICAL_SECTION osi_ExitCritical() + +typedef void* OsiMsgQ_t; + + /*! + \brief type definition for a time value + + \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. +*/ +//typedef unsigned int OsiTime_t; +typedef unsigned int OsiTime_t; +/*! + \brief type definition for a sync object container + + Sync object is object used to synchronize between two threads or thread and interrupt handler. + One thread is waiting on the object and the other thread send a signal, which then + release the waiting thread. + The signal must be able to be sent from interrupt context. + This object is generally implemented by binary semaphore or events. + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. +*/ +//typedef unsigned int OsiSyncObj_t; +typedef void * OsiSyncObj_t; + +/*! + \brief type definition for a locking object container + + Locking object are used to protect a resource from mutual accesses of two or more threads. + The locking object should support re-entrant locks by a signal thread. + This object is generally implemented by mutex semaphore + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. +*/ +//typedef unsigned int OsiLockObj_t; +typedef void * OsiLockObj_t; + +/*! + \brief type definition for a spawn entry callback + + the spawn mechanism enable to run a function on different context. + This mechanism allow to transfer the execution context from interrupt context to thread context + or changing the context from an unknown user thread to general context. + The implementation of the spawn mechanism depends on the user's system requirements and could varies + from implementation of serialized execution using single thread to creating thread per call + + \note The stack size of the execution thread must be at least of TBD bytes! +*/ +typedef void (*P_OSI_SPAWN_ENTRY)(void* pValue); + +typedef void (*P_OSI_EVENT_HANDLER)(void* pValue); + +typedef void (*P_OSI_TASK_ENTRY)(void* pValue); + +typedef void (*P_OSI_INTR_ENTRY)(void); + +typedef void* OsiTaskHandle; + +/*! + \brief This function registers an interrupt in NVIC table + + The sync object is used for synchronization between different thread or ISR and + a thread. + + \param iIntrNum - Interrupt number to register + \param pEntry - Pointer to the interrupt handler + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_InterruptRegister(int iIntrNum,P_OSI_INTR_ENTRY pEntry,unsigned char ucPriority); + +/*! + \brief This function De-registers an interrupt in NVIC table + + \param iIntrNum - Interrupt number to register + \param pEntry - Pointer to the interrupt handler + + \return upon successful creation the function should return Positive number + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +void osi_InterruptDeRegister(int iIntrNum); + + +/*! + \brief This function creates a sync object + + The sync object is used for synchronization between different thread or ISR and + a thread. + + \param pSyncObj - pointer to the sync object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjCreate(OsiSyncObj_t* pSyncObj); + + +/*! + \brief This function deletes a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjDelete(OsiSyncObj_t* pSyncObj); + +/*! + \brief This function generates a sync signal for the object. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signalling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +OsiReturnVal_e osi_SyncObjSignal(OsiSyncObj_t* pSyncObj); + +/*! + \brief This function generates a sync signal for the object. + from ISR context. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signalling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function is called from ISR context + \warning +*/ +OsiReturnVal_e osi_SyncObjSignalFromISR(OsiSyncObj_t* pSyncObj); + +/*! + \brief This function waits for a sync signal of the specific sync object + + \param pSyncObj - pointer to the sync object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the sync signal + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + \return upon successful reception of the signal within the timeout window return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjWait(OsiSyncObj_t* pSyncObj , OsiTime_t Timeout); + +/*! + \brief This function clears a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful clearing the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjClear(OsiSyncObj_t* pSyncObj); + +/*! + \brief This function creates a locking object. + + The locking object is used for protecting a shared resources between different + threads. + + \param pLockObj - pointer to the locking object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_LockObjCreate(OsiLockObj_t* pLockObj); + +/*! + \brief This function deletes a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define osi_LockObjDelete osi_SyncObjDelete + +/*! + \brief This function locks a locking object. + + All other threads that call this function before this thread calls + the osi_LockObjUnlock would be suspended + + \param pLockObj - pointer to the locking object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the locking object + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + + \return upon successful reception of the locking object the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define osi_LockObjLock osi_SyncObjWait + +/*! + \brief This function unlock a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +#define osi_LockObjUnlock osi_SyncObjSignal + + +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function should return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +/*! + \brief This function creates a Task. + + Creates a new Task and add it to the last of tasks that are ready to run + + \param pEntry - pointer to the Task Function + \param pcName - Task Name String + \param usStackDepth - Stack Size Stack Size in 32-bit long words + \param pvParameters - pointer to structure to be passed to the Task Function + \param uxPriority - Task Priority + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_TaskCreate(P_OSI_TASK_ENTRY pEntry,const signed char * const pcName,unsigned short usStackDepth,void *pvParameters,unsigned long uxPriority,OsiTaskHandle *pTaskHandle); + +/*! + \brief This function Deletes a Task. + + Deletes a Task and remove it from list of running task + + \param pTaskHandle - Task Handle + + \note + \warning +*/ +void osi_TaskDelete(OsiTaskHandle* pTaskHandle); + +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function should return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_Spawn(P_OSI_SPAWN_ENTRY pEntry , void* pValue , unsigned long flags); + + +/******************************************************************************* + +This function creates a message queue that is typically used for inter thread +communication. + +Parameters: + + pMsgQ - pointer to the message queue control block + pMsgQName - pointer to the name of the message queue + MsgSize - the size of the message. + + NOTICE: THE MESSGAE SIZE MUST BE SMALLER THAN 16 + + MaxMsgs - maximum number of messages. + +Please note that this function allocates the entire memory required +for the maximum number of messages (MsgSize * MaxMsgs). + +********************************************************************************/ +OsiReturnVal_e osi_MsgQCreate(OsiMsgQ_t* pMsgQ , + char* pMsgQName, + unsigned long MsgSize, + unsigned long MaxMsgs); + +/******************************************************************************* + +This function deletes a specific message queue. +All threads suspended waiting for a message from this queue are resumed with +an error return value. + +Parameters: + + pMsgQ - pointer to the message queue control block + +********************************************************************************/ +OsiReturnVal_e osi_MsgQDelete(OsiMsgQ_t* pMsgQ); + + +/******************************************************************************* + +This function writes a message to a specific message queue. + +Notice that the message is copied to the queue from the memory area specified +by pMsg pointer. + +-------------------------------------------------------------------------------- +THIS FUNCTION COULD BE CALLED FROM ISR AS LONG AS THE TIMEOUT PARAMETER IS +SET TO "OSI_NO_WAIT" +-------------------------------------------------------------------------------- + +Parameters: + + pMsgQ - pointer to the message queue control block + pMsg - pointer to the message + Timeout - numeric value specifies the maximum number of mSec to stay + suspended while waiting for available space for the message + +********************************************************************************/ +OsiReturnVal_e osi_MsgQWrite(OsiMsgQ_t* pMsgQ, void* pMsg , OsiTime_t Timeout); + + +/******************************************************************************* + +This function retrieves a message from the specified message queue. The +retrieved message is copied from the queue into the memory area specified by +the pMsg pointer + +Parameters: + + pMsgQ - pointer to the message queue control block + pMsg - pointer that specify the location where to copy the message + Timeout - numeric value specifies the maximum number of mSec to stay + suspended while waiting for a message to be available + +********************************************************************************/ +OsiReturnVal_e osi_MsgQRead(OsiMsgQ_t* pMsgQ, void* pMsg , OsiTime_t Timeout); + +/*! + \brief This function starts the OS Scheduler + \param - void + \return - void + \note + \warning +*/ +void osi_start(); + +/*! + \brief Allocates Memory on Heap + \param Size - Size of the Buffer to be allocated + \sa + \note + \warning +*/ +void * mem_Malloc(unsigned long Size); + + +/*! + \brief Deallocates Memory + \param pMem - Pointer to the Buffer to be freed + \return void + \sa + \note + \warning +*/ +void mem_Free(void *pMem); + + +/*! + \brief Set Memory + \param pBuf - Pointer to the Buffer + \param Val - Value to be set + \param Size - Size of the memory to be set + \sa + \note + \warning +*/ +void mem_set(void *pBuf,int Val,size_t Size); + +/*! + \brief Copy Memory + \param pDst - Pointer to the Destination Buffer + \param pSrc - Pointer to the Source Buffer + \param Size - Size of the memory to be copied + \return void + \note + \warning +*/ +void mem_copy(void *pDst, void *pSrc,size_t Size); + +/*! + \brief Enter Critical Section + \sa + \note + \warning +*/ +void osi_EnterCritical(void); + +/*! + \brief Exit Critical Section + \sa + \note + \warning +*/ +void osi_ExitCritical(void); + +/*! + \brief This function used to save the os context before sleep + \param void + \return void + \note + \warning +*/ +void osi_ContextSave(); +/*! + \brief This function used to retrieve the context after sleep + \param void + \return void + \note + \warning +*/ +void osi_ContextRestore(); + +/*! + \brief This function used to suspend the task for the specified number of milli secs + \param MilliSecs - Time in millisecs to suspend the task + \return void + \note + \warning +*/ +void osi_Sleep(unsigned int MilliSecs); + +/*! + \brief This function used to disable the tasks + \param - void + \return - void + \note + \warning +*/ +void osi_TaskDisable(void); + +/*! + \brief This function used to enable all tasks + \param - void + \return - void + \note + \warning +*/ +void osi_TaskEnable(void); + +/*! + \brief structure definition for simple link spawn message + + \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. +*/ +typedef struct +{ + P_OSI_SPAWN_ENTRY pEntry; + void* pValue; +}tSimpleLinkSpawnMsg; + +/* The queue used to send message to simple link spawn task. */ +extern void* xSimpleLinkSpawnQueue; + +/* API for SL Task*/ +OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned long uxPriority); +void VDeleteSimpleLinkSpawnTask( void ); + + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi_freertos.c b/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi_freertos.c new file mode 100755 index 0000000..53822ad --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/simplelink/oslib/osi_freertos.c @@ -0,0 +1,747 @@ +//***************************************************************************** +// osi_freertos.c +// +// Interface APIs for free-rtos function calls +// +// Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +// +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 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. +// +// Neither the name of Texas Instruments Incorporated 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 +// OWNER 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 +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" +#include "osi.h" +#include "rom_map.h" +#include "inc/hw_types.h" +#include "interrupt.h" +#include "pybwdt.h" +#include "debug.h" + +portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +//Local function definition +static void vSimpleLinkSpawnTask( void *pvParameters ); +//Queue Handler +QueueHandle_t xSimpleLinkSpawnQueue = NULL; +TaskHandle_t xSimpleLinkSpawnTaskHndl = NULL; +// Queue size +#define slQUEUE_SIZE ( 3 ) +#define SL_SPAWN_MAX_WAIT_MS ( 200 ) + +// This is the static memory (TCB and stack) for the SL spawn task +static StaticTask_t spawnTaskTCB __attribute__ ((section (".rtos_heap"))); +static portSTACK_TYPE spawnTaskStack[896 / sizeof(portSTACK_TYPE)] __attribute__ ((section (".rtos_heap"))) __attribute__((aligned (8))); + +/*! + \brief This function registers an interrupt in NVIC table + + The sync object is used for synchronization between different thread or ISR and + a thread. + + \param iIntrNum - Interrupt number to register + \param pEntry - Pointer to the interrupt handler + \param ucPriority - priority of the interrupt + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_InterruptRegister(int iIntrNum,P_OSI_INTR_ENTRY pEntry,unsigned char ucPriority) +{ + MAP_IntRegister(iIntrNum,(void(*)(void))pEntry); + MAP_IntPrioritySet(iIntrNum, ucPriority); + MAP_IntEnable(iIntrNum); + return OSI_OK; +} + +/*! + \brief This function De registers an interrupt in NVIC table + + + \param iIntrNum - Interrupt number to De register + + \return none + \note + \warning +*/ + +void osi_InterruptDeRegister(int iIntrNum) +{ + MAP_IntDisable(iIntrNum); + MAP_IntUnregister(iIntrNum); +} + +/*! + \brief This function creates a sync object + + The sync object is used for synchronization between different thread or ISR and + a thread. + + \param pSyncObj - pointer to the sync object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjCreate(OsiSyncObj_t* pSyncObj) +{ + SemaphoreHandle_t *pl_SyncObj = (SemaphoreHandle_t *)pSyncObj; + + *pl_SyncObj = xSemaphoreCreateBinary(); + + ASSERT (*pSyncObj != NULL); + + return OSI_OK; +} + +/*! + \brief This function deletes a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjDelete(OsiSyncObj_t* pSyncObj) +{ + vSemaphoreDelete(*pSyncObj ); + return OSI_OK; +} + +/*! + \brief This function generates a sync signal for the object. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +OsiReturnVal_e osi_SyncObjSignal(OsiSyncObj_t* pSyncObj) +{ + xSemaphoreGive( *pSyncObj ); + return OSI_OK; +} +/*! + \brief This function generates a sync signal for the object + from ISR context. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signalling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function is called from ISR context + \warning +*/ +OsiReturnVal_e osi_SyncObjSignalFromISR(OsiSyncObj_t* pSyncObj) +{ + xHigherPriorityTaskWoken = pdFALSE; + if(pdTRUE == xSemaphoreGiveFromISR( *pSyncObj, &xHigherPriorityTaskWoken )) + { + if( xHigherPriorityTaskWoken ) + { + taskYIELD (); + } + } + return OSI_OK; +} + +/*! + \brief This function waits for a sync signal of the specific sync object + + \param pSyncObj - pointer to the sync object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the sync signal + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + \return upon successful reception of the signal within the timeout window return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjWait(OsiSyncObj_t* pSyncObj , OsiTime_t Timeout) +{ + if(pdTRUE == xSemaphoreTake( (SemaphoreHandle_t)*pSyncObj, ( TickType_t )Timeout)) + { + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} + +/*! + \brief This function clears a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful clearing the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_SyncObjClear(OsiSyncObj_t* pSyncObj) +{ + if (OSI_OK == osi_SyncObjWait(pSyncObj,0) ) + { + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} + +/*! + \brief This function creates a locking object. + + The locking object is used for protecting a shared resources between different + threads. + + \param pLockObj - pointer to the locking object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_LockObjCreate(OsiLockObj_t* pLockObj) +{ + SemaphoreHandle_t *pl_LockObj = (SemaphoreHandle_t *)pLockObj; + + vSemaphoreCreateBinary(*pl_LockObj); + + ASSERT (*pLockObj != NULL); + + return OSI_OK; +} + +/*! + \brief This function creates a Task. + + Creates a new Task and add it to the last of tasks that are ready to run + + \param pEntry - pointer to the Task Function + \param pcName - Task Name String + \param usStackDepth - Stack Size in bytes + \param pvParameters - pointer to structure to be passed to the Task Function + \param uxPriority - Task Priority + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e osi_TaskCreate(P_OSI_TASK_ENTRY pEntry,const signed char * const pcName, + unsigned short usStackDepth, void *pvParameters, + unsigned long uxPriority,OsiTaskHandle* pTaskHandle) +{ + ASSERT (pdPASS == xTaskCreate( pEntry, (char const*)pcName, + (usStackDepth/(sizeof( portSTACK_TYPE ))), + pvParameters,(unsigned portBASE_TYPE)uxPriority, + (TaskHandle_t*)pTaskHandle )); + return OSI_OK; +} + + +/*! + \brief This function Deletes a Task. + + Deletes a Task and remove it from list of running task + + \param pTaskHandle - Task Handle + + \note + \warning +*/ +void osi_TaskDelete(OsiTaskHandle* pTaskHandle) +{ + vTaskDelete((TaskHandle_t)*pTaskHandle); +} + + + +/*! + \brief This function deletes a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e _osi_LockObjDelete(OsiLockObj_t* pLockObj) +{ + vSemaphoreDelete((SemaphoreHandle_t)*pLockObj ); + return OSI_OK; +} + +/*! + \brief This function locks a locking object. + + All other threads that call this function before this thread calls + the osi_LockObjUnlock would be suspended + + \param pLockObj - pointer to the locking object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the locking object + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + + \return upon successful reception of the locking object the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e _osi_LockObjLock(OsiLockObj_t* pLockObj , OsiTime_t Timeout) +{ + //Take Semaphore + if(pdTRUE == xSemaphoreTake( *pLockObj, ( TickType_t ) Timeout )) + { + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} + +/*! + \brief This function unlock a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ +OsiReturnVal_e _osi_LockObjUnlock(OsiLockObj_t* pLockObj) +{ + //Release Semaphore + if(pdTRUE == xSemaphoreGive( *pLockObj )) + { + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} + + +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function should return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note + \warning +*/ + +OsiReturnVal_e osi_Spawn(P_OSI_SPAWN_ENTRY pEntry , void* pValue , unsigned long flags) +{ + + tSimpleLinkSpawnMsg Msg; + Msg.pEntry = pEntry; + Msg.pValue = pValue; + xHigherPriorityTaskWoken = pdFALSE; + + if(pdTRUE == xQueueSendFromISR( xSimpleLinkSpawnQueue, &Msg, &xHigherPriorityTaskWoken )) + { + if( xHigherPriorityTaskWoken ) + { + taskYIELD (); + } + return OSI_OK; + } + return OSI_OPERATION_FAILED; +} + + +/*! + \brief This is the simplelink spawn task to call SL callback from a different context + + \param pvParameters - pointer to the task parameter + + \return void + \note + \warning +*/ +void vSimpleLinkSpawnTask(void *pvParameters) +{ + tSimpleLinkSpawnMsg Msg; + portBASE_TYPE ret; + + for(;;) + { + ret = xQueueReceive( xSimpleLinkSpawnQueue, &Msg, SL_SPAWN_MAX_WAIT_MS); + if(ret == pdPASS) + { + Msg.pEntry(Msg.pValue); + } + // set the alive flag for the wdt + pybwdt_sl_alive(); + } +} + +/*! + \brief This is the API to create SL spawn task and create the SL queue + + \param uxPriority - task priority + + \return void + \note + \warning +*/ +__attribute__ ((section (".boot"))) +OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned portBASE_TYPE uxPriority) +{ + xSimpleLinkSpawnQueue = xQueueCreate( slQUEUE_SIZE, sizeof( tSimpleLinkSpawnMsg ) ); + ASSERT (xSimpleLinkSpawnQueue != NULL); + + /* + // This is the original code to create a task dynamically + ASSERT (pdPASS == xTaskCreate( vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN",\ + 896 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl )); + */ + + // This code creates the task using static memory for the TCB and stack + xSimpleLinkSpawnTaskHndl = xTaskCreateStatic( + vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN", + 896 / sizeof(portSTACK_TYPE), NULL, uxPriority, + spawnTaskStack, &spawnTaskTCB); + + ASSERT(xSimpleLinkSpawnTaskHndl != NULL); + + return OSI_OK; +} + +/*! + \brief This is the API to delete SL spawn task and delete the SL queue + + \param none + + \return void + \note + \warning +*/ +void VDeleteSimpleLinkSpawnTask( void ) +{ + if(xSimpleLinkSpawnTaskHndl) + { + vTaskDelete( xSimpleLinkSpawnTaskHndl ); + xSimpleLinkSpawnTaskHndl = 0; + } + + if(xSimpleLinkSpawnQueue) + { + vQueueDelete( xSimpleLinkSpawnQueue ); + xSimpleLinkSpawnQueue = 0; + } +} + +/*! + \brief This function is used to create the MsgQ + + \param pMsgQ - pointer to the message queue + \param pMsgQName - msg queue name + \param MsgSize - size of message on the queue + \param MaxMsgs - max. number of msgs that the queue can hold + + \return - OsiReturnVal_e + \note + \warning +*/ +OsiReturnVal_e osi_MsgQCreate(OsiMsgQ_t* pMsgQ , + char* pMsgQName, + unsigned long MsgSize, + unsigned long MaxMsgs) +{ + QueueHandle_t handle; + + //Create Queue + handle = xQueueCreate( MaxMsgs, MsgSize ); + ASSERT (handle != NULL); + + *pMsgQ = (OsiMsgQ_t)handle; + return OSI_OK; +} +/*! + \brief This function is used to delete the MsgQ + + \param pMsgQ - pointer to the message queue + + \return - OsiReturnVal_e + \note + \warning +*/ +OsiReturnVal_e osi_MsgQDelete(OsiMsgQ_t* pMsgQ) +{ + vQueueDelete((QueueHandle_t) *pMsgQ ); + return OSI_OK; +} +/*! + \brief This function is used to write data to the MsgQ + + \param pMsgQ - pointer to the message queue + \param pMsg - pointer to the Msg strut to read into + \param Timeout - timeout to wait for the Msg to be available + + \return - OsiReturnVal_e + \note + \warning +*/ + +OsiReturnVal_e osi_MsgQWrite(OsiMsgQ_t* pMsgQ, void* pMsg , OsiTime_t Timeout) +{ + xHigherPriorityTaskWoken = pdFALSE; + if(pdPASS == xQueueSendFromISR((QueueHandle_t) *pMsgQ, pMsg, &xHigherPriorityTaskWoken )) + { + taskYIELD (); + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} +/*! + \brief This function is used to read data from the MsgQ + + \param pMsgQ - pointer to the message queue + \param pMsg - pointer to the Msg strut to read into + \param Timeout - timeout to wait for the Msg to be available + + \return - OsiReturnVal_e + \note + \warning +*/ + +OsiReturnVal_e osi_MsgQRead(OsiMsgQ_t* pMsgQ, void* pMsg , OsiTime_t Timeout) +{ + //Receive Item from Queue + if( pdTRUE == xQueueReceive((QueueHandle_t)*pMsgQ,pMsg,Timeout) ) + { + return OSI_OK; + } + else + { + return OSI_OPERATION_FAILED; + } +} + +/*! + \brief This function to call the memory de-allocation function of the FREERTOS + + \param Size - size of memory to alloc in bytes + + \return - void * + \note + \warning +*/ + +void * mem_Malloc(unsigned long Size) +{ + return ( void * ) pvPortMalloc( (size_t)Size ); +} + +/*! + \brief This function to call the memory de-allocation function of the FREERTOS + + \param pMem - pointer to the memory which needs to be freed + + \return - void + \note + \warning +*/ +void mem_Free(void *pMem) +{ + vPortFree( pMem ); +} + +/*! + \brief This function call the memset function + \param pBuf - pointer to the memory to be fill + \param Val - Value to be fill + \param Size - Size of the memory which needs to be fill + \return - void + \note + \warning +*/ + +void mem_set(void *pBuf,int Val,size_t Size) +{ + memset( pBuf,Val,Size); +} + +/*! + \brief This function call the memcopy function + \param pDst - pointer to the destination + \param pSrc - pointer to the source + \param Size - Size of the memory which needs to be copy + + \return - void + \note + \warning +*/ +void mem_copy(void *pDst, void *pSrc,size_t Size) +{ + memcpy(pDst,pSrc,Size); +} + + +/*! + \brief This function use to entering into critical section + \param void + \return - void + \note + \warning +*/ + +void osi_EnterCritical(void) +{ + vPortEnterCritical(); +} + +/*! + \brief This function use to exit critical section + \param void + \return - void + \note + \warning +*/ + +void osi_ExitCritical(void) +{ + vPortExitCritical(); +} +/*! + \brief This function used to start the scheduler + \param void + \return - void + \note + \warning +*/ +__attribute__ ((section (".boot"))) +void osi_start() +{ + vTaskStartScheduler(); +} +/*! + \brief This function used to suspend the task for the specified number of milli secs + \param MilliSecs - Time in millisecs to suspend the task + \return - void + \note + \warning +*/ +void osi_Sleep(unsigned int MilliSecs) +{ + vTaskDelay(MilliSecs); +} + + +/*! + \brief This function used to disable the tasks + \param - void + \return - Key with the suspended tasks + \note + \warning +*/ +void osi_TaskDisable(void) +{ + vTaskSuspendAll(); +} + + +/*! + \brief This function used to resume all the tasks + \param key - returned from suspend tasks + \return - void + \note + \warning +*/ +void osi_TaskEnable(void) +{ + xTaskResumeAll(); +} + +/*! + \brief This function used to save the OS context before sleep + \param void + \return - void + \note + \warning +*/ +void osi_ContextSave() +{ + +} +/*! + \brief This function used to restore the OS context after sleep + \param void + \return - void + \note + \warning +*/ +void osi_ContextRestore() +{ + +} diff --git a/src/openmv/src/micropython/ports/cc3200/simplelink/user.h b/src/openmv/src/micropython/ports/cc3200/simplelink/user.h new file mode 100755 index 0000000..d3f6d4a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/simplelink/user.h @@ -0,0 +1,1063 @@ +/* + * user.h - CC31xx/CC32xx Host Driver Implementation + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of Texas Instruments Incorporated 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 + * OWNER 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 __USER_H__ +#define __USER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + + + + +/*! + ****************************************************************************** + + \defgroup porting_user_include Porting - User Include Files + + This section IS NOT REQUIRED in case user provided primitives are handled + in makefiles or project configurations (IDE) + + PORTING ACTION: + - Include all required header files for the definition of: + -# Transport layer library API (e.g. SPI, UART) + -# OS primitives definitions (e.g. Task spawn, Semaphores) + -# Memory management primitives (e.g. alloc, free) + + ****************************************************************************** + */ + +#include +#include "cc_pal.h" +#include "debug.h" + +/*! + \def MAX_CONCURRENT_ACTIONS + + \brief Defines the maximum number of concurrent action in the system + Min:1 , Max: 32 + + Actions which has async events as return, can be + + \sa + + \note In case there are not enough resources for the actions needed in the system, + error is received: POOL_IS_EMPTY + one option is to increase MAX_CONCURRENT_ACTIONS + (improves performance but results in memory consumption) + Other option is to call the API later (decrease performance) + + \warning In case of setting to one, recommend to use non-blocking recv\recvfrom to allow + multiple socket recv +*/ +#define MAX_CONCURRENT_ACTIONS 10 +/*! + \def CPU_FREQ_IN_MHZ + \brief Defines CPU frequency for Host side, for better accuracy of busy loops, if any + \sa + \note + + \warning If not set the default CPU frequency is set to 200MHz + This option will be deprecated in future release +*/ + +#define CPU_FREQ_IN_MHZ 80 + + +/*! + ****************************************************************************** + + \defgroup porting_capabilities Porting - Capabilities Set + + This section IS NOT REQUIRED in case one of the following pre defined + capabilities set is in use: + - SL_TINY + - SL_SMALL + - SL_FULL + + PORTING ACTION: + - Define one of the pre-defined capabilities set or uncomment the + relevant definitions below to select the required capabilities + + @{ + + ******************************************************************************* +*/ + +/*! + \def SL_INC_ARG_CHECK + + \brief Defines whether the SimpleLink driver perform argument check + or not + + When defined, the SimpleLink driver perform argument check on + function call. Removing this define could reduce some code + size and improve slightly the performances but may impact in + unpredictable behavior in case of invalid arguments + + \sa + + \note belongs to \ref proting_sec + + \warning Removing argument check may cause unpredictable behavior in + case of invalid arguments. + In this case the user is responsible to argument validity + (for example all handlers must not be NULL) +*/ +#define SL_INC_ARG_CHECK + + +/*! + \def SL_INC_STD_BSD_API_NAMING + + \brief Defines whether SimpleLink driver should expose standard BSD + APIs or not + + When defined, the SimpleLink driver in addtion to its alternative + BSD APIs expose also standard BSD APIs. + Stadrad BSD API includs the following functions: + socket , close , accept , bind , listen , connect , select , + setsockopt , getsockopt , recv , recvfrom , write , send , sendto , + gethostbyname + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +/* #define SL_INC_STD_BSD_API_NAMING */ + + +/*! + \brief Defines whether to include extended API in SimpleLink driver + or not + + When defined, the SimpleLink driver will include also all + exteded API of the included packages + + \sa ext_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_EXT_API + +/*! + \brief Defines whether to include WLAN package in SimpleLink driver + or not + + When defined, the SimpleLink driver will include also + the WLAN package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_WLAN_PKG + +/*! + \brief Defines whether to include SOCKET package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also + the SOCKET package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCKET_PKG + +/*! + \brief Defines whether to include NET_APP package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also the + NET_APP package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NET_APP_PKG + +/*! + \brief Defines whether to include NET_CFG package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also + the NET_CFG package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NET_CFG_PKG + +/*! + \brief Defines whether to include NVMEM package in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also the + NVMEM package + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_NVMEM_PKG + +/*! + \brief Defines whether to include socket server side APIs + in SimpleLink driver or not + + When defined, the SimpleLink driver will include also socket + server side APIs + + \sa server_side + + \note + + \warning +*/ +#define SL_INC_SOCK_SERVER_SIDE_API + +/*! + \brief Defines whether to include socket client side APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + client side APIs + + \sa client_side + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_CLIENT_SIDE_API + +/*! + \brief Defines whether to include socket receive APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + receive side APIs + + \sa recv_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_RECV_API + +/*! + \brief Defines whether to include socket send APIs in SimpleLink + driver or not + + When defined, the SimpleLink driver will include also socket + send side APIs + + \sa send_api + + \note belongs to \ref porting_sec + + \warning +*/ +#define SL_INC_SOCK_SEND_API + +/*! + + Close the Doxygen group. + @} + + */ + + +/*! + ****************************************************************************** + + \defgroup ported_enable_device Ported on CC32XX - Device Enable/Disable + + The enable/disable API provide mechanism to enable/disable the network processor + + + PORTING ACTION: + - None + @{ + + ****************************************************************************** + */ + +/*! + \brief Preamble to the enabling the Network Processor. + Placeholder to implement any pre-process operations + before enabling networking operations. + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec + +*/ +#ifdef DEBUG +#define sl_DeviceEnablePreamble() NwpPowerOnPreamble() +#else +#define sl_DeviceEnablePreamble() +#endif + +/*! + \brief Enable the Network Processor + + \sa sl_DeviceDisable + + \note belongs to \ref ported_sec + +*/ +#define sl_DeviceEnable() NwpPowerOn() + +/*! + \brief Disable the Network Processor + + \sa sl_DeviceEnable + + \note belongs to \ref ported_sec +*/ +#define sl_DeviceDisable() NwpPowerOff() + +/*! + + Close the Doxygen group. + @} + + */ + +/*! + ****************************************************************************** + + \defgroup ported_interface Ported on CC32XX - Communication Interface + + The simple link device can work with different communication + channels (e.g. spi/uart). Texas Instruments provides single driver + that can work with all these types. This section bind between the + physical communication interface channel and the SimpleLink driver + + + \note Correct and efficient implementation of this driver is critical + for the performances of the SimpleLink device on this platform. + + + PORTING ACTION: + - None + + @{ + + ****************************************************************************** +*/ + +#define _SlFd_t Fd_t + +/*! + \brief Opens an interface communication port to be used for communicating + with a SimpleLink device + + Given an interface name and option flags, this function opens + the communication port and creates a file descriptor. + This file descriptor is used afterwards to read and write + data from and to this specific communication channel. + The speed, clock polarity, clock phase, chip select and all other + specific attributes of the channel are all should be set to hardcoded + in this function. + + \param ifName - points to the interface name/path. The interface name is an + optional attributes that the simple link driver receives + on opening the driver (sl_Start). + In systems that the spi channel is not implemented as + part of the os device drivers, this parameter could be NULL. + + \param flags - optional flags parameters for future use + + \return upon successful completion, the function shall open the channel + and return a non-negative integer representing the file descriptor. + Otherwise, -1 shall be returned + + \sa sl_IfClose , sl_IfRead , sl_IfWrite + + \note The prototype of the function is as follow: + Fd_t xxx_IfOpen(char* pIfName , unsigned long flags); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfOpen spi_Open + +/*! + \brief Closes an opened interface communication port + + \param fd - file descriptor of opened communication channel + + \return upon successful completion, the function shall return 0. + Otherwise, -1 shall be returned + + \sa sl_IfOpen , sl_IfRead , sl_IfWrite + + \note The prototype of the function is as follow: + int xxx_IfClose(Fd_t Fd); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfClose spi_Close + +/*! + \brief Attempts to read up to len bytes from an opened communication channel + into a buffer starting at pBuff. + + \param fd - file descriptor of an opened communication channel + + \param pBuff - pointer to the first location of a buffer that contains enough + space for all expected data + + \param len - number of bytes to read from the communication channel + + \return upon successful completion, the function shall return the number of read bytes. + Otherwise, 0 shall be returned + + \sa sl_IfClose , sl_IfOpen , sl_IfWrite + + + \note The prototype of the function is as follow: + int xxx_IfRead(Fd_t Fd , char* pBuff , int Len); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfRead spi_Read + +/*! + \brief attempts to write up to len bytes to the SPI channel + + \param fd - file descriptor of an opened communication channel + + \param pBuff - pointer to the first location of a buffer that contains + the data to send over the communication channel + + \param len - number of bytes to write to the communication channel + + \return upon successful completion, the function shall return the number of sent bytes. + therwise, 0 shall be returned + + \sa sl_IfClose , sl_IfOpen , sl_IfRead + + \note This function could be implemented as zero copy and return only upon successful completion + of writing the whole buffer, but in cases that memory allocation is not too tight, the + function could copy the data to internal buffer, return back and complete the write in + parallel to other activities as long as the other SPI activities would be blocked until + the entire buffer write would be completed + + The prototype of the function is as follow: + int xxx_IfWrite(Fd_t Fd , char* pBuff , int Len); + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfWrite spi_Write + +/*! + \brief register an interrupt handler routine for the host IRQ + + \param InterruptHdl - pointer to interrupt handler routine + + \param pValue - pointer to a memory structure that is passed + to the interrupt handler. + + \return upon successful registration, the function shall return 0. + Otherwise, -1 shall be returned + + \sa + + \note If there is already registered interrupt handler, the function + should overwrite the old handler with the new one + + \note If the handler is a null pointer, the function should un-register the + interrupt handler, and the interrupts can be disabled. + + \note belongs to \ref ported_sec + + \warning +*/ +#define sl_IfRegIntHdlr(InterruptHdl , pValue) NwpRegisterInterruptHandler(InterruptHdl , pValue) + +/*! + \brief Masks the Host IRQ + + \sa sl_IfUnMaskIntHdlr + + + + \note belongs to \ref ported_sec + + \warning +*/ + + +#define sl_IfMaskIntHdlr() NwpMaskInterrupt() + +/*! + \brief Unmasks the Host IRQ + + \sa sl_IfMaskIntHdlr + + + + \note belongs to \ref ported_sec + + \warning +*/ + +#define sl_IfUnMaskIntHdlr() NwpUnMaskInterrupt() + +/*! + \brief Write Handers for statistics debug on write + + \param interface handler - pointer to interrupt handler routine + + + \return no return value + + \sa + + \note An optional hooks for monitoring before and after write info + + \note belongs to \ref ported_sec + + \warning +*/ +/* #define SL_START_WRITE_STAT */ + + +/*! + + Close the Doxygen group. + @} + +*/ + +/*! + ****************************************************************************** + + \defgroup ported_os Ported on CC32XX - Operating System + + The simple link driver can run on multi-threaded environment as well + as non-os environment (mail loop) + + This section IS NOT REQUIRED in case you are working on non-os environment. + + If you choose to work in multi-threaded environment under any operating system + you will have to provide some basic adaptation routines to allow the driver + to protect access to resources from different threads (locking object) and + to allow synchronization between threads (sync objects). + + PORTING ACTION: + -# Uncomment SL_PLATFORM_MULTI_THREADED define + -# Bind locking object routines + -# Bind synchronization object routines + -# Optional - Bind spawn thread routine + + @{ + + ****************************************************************************** +*/ + +#define SL_PLATFORM_MULTI_THREADED + + +#ifdef SL_PLATFORM_MULTI_THREADED +#include "osi.h" + + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_RET_CODE_OK ((int)OSI_OK) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_WAIT_FOREVER ((OsiTime_t)OSI_WAIT_FOREVER) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define SL_OS_NO_WAIT ((OsiTime_t)OSI_NO_WAIT) + +/*! + \brief type definition for a time value + + \note On each porting or platform the type could be whatever is needed - integer, pointer to structure etc. + + \note belongs to \ref ported_sec +*/ +#define _SlTime_t OsiTime_t + +/*! + \brief type definition for a sync object container + + Sync object is object used to synchronize between two threads or thread and interrupt handler. + One thread is waiting on the object and the other thread send a signal, which then + release the waiting thread. + The signal must be able to be sent from interrupt context. + This object is generally implemented by binary semaphore or events. + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. + + \note belongs to \ref ported_sec +*/ +typedef OsiSyncObj_t _SlSyncObj_t; + + +/*! + \brief This function creates a sync object + + The sync object is used for synchronization between diffrent thread or ISR and + a thread. + + \param pSyncObj - pointer to the sync object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjCreate(pSyncObj,pName) osi_SyncObjCreate(pSyncObj) + + +/*! + \brief This function deletes a sync object + + \param pSyncObj - pointer to the sync object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjDelete(pSyncObj) osi_SyncObjDelete(pSyncObj) + + +/*! + \brief This function generates a sync signal for the object. + + All suspended threads waiting on this sync object are resumed + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +#define sl_SyncObjSignal(pSyncObj) osi_SyncObjSignal(pSyncObj) + +/*! + \brief This function generates a sync signal for the object from Interrupt + + This is for RTOS that should signal from IRQ using a dedicated API + + \param pSyncObj - pointer to the sync object control block + + \return upon successful signaling the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note the function could be called from ISR context + \warning +*/ +#define sl_SyncObjSignalFromIRQ(pSyncObj) osi_SyncObjSignalFromISR(pSyncObj) + +/*! + \brief This function waits for a sync signal of the specific sync object + + \param pSyncObj - pointer to the sync object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the sync signal + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + \return upon successful reception of the signal within the timeout window return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_SyncObjWait(pSyncObj,Timeout) osi_SyncObjWait(pSyncObj,Timeout) + +/*! + \brief type definition for a locking object container + + Locking object are used to protect a resource from mutual accesses of two or more threads. + The locking object should suppurt reentrant locks by a signal thread. + This object is generally implemented by mutex semaphore + + \note On each porting or platform the type could be whatever is needed - integer, structure etc. + \note belongs to \ref ported_sec +*/ +typedef OsiLockObj_t _SlLockObj_t; + +/*! + \brief This function creates a locking object. + + The locking object is used for protecting a shared resources between different + threads. + + \param pLockObj - pointer to the locking object control block + + \return upon successful creation the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjCreate(pLockObj,pName) osi_LockObjCreate(pLockObj) + +/*! + \brief This function deletes a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful deletion the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjDelete(pLockObj) osi_LockObjDelete(pLockObj) + +/*! + \brief This function locks a locking object. + + All other threads that call this function before this thread calls + the osi_LockObjUnlock would be suspended + + \param pLockObj - pointer to the locking object control block + \param Timeout - numeric value specifies the maximum number of mSec to + stay suspended while waiting for the locking object + Currently, the simple link driver uses only two values: + - OSI_WAIT_FOREVER + - OSI_NO_WAIT + + + \return upon successful reception of the locking object the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjLock(pLockObj,Timeout) osi_LockObjLock(pLockObj,Timeout) + +/*! + \brief This function unlock a locking object. + + \param pLockObj - pointer to the locking object control block + + \return upon successful unlocking the function should return 0 + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define sl_LockObjUnlock(pLockObj) osi_LockObjUnlock(pLockObj) + +#endif +/*! + \brief This function call the pEntry callback from a different context + + \param pEntry - pointer to the entry callback function + + \param pValue - pointer to any type of memory structure that would be + passed to pEntry callback from the execution thread. + + \param flags - execution flags - reserved for future usage + + \return upon successful registration of the spawn the function should return 0 + (the function is not blocked till the end of the execution of the function + and could be returned before the execution is actually completed) + Otherwise, a negative value indicating the error code shall be returned + \note belongs to \ref ported_sec + \warning +*/ +#define SL_PLATFORM_EXTERNAL_SPAWN + +#ifdef SL_PLATFORM_EXTERNAL_SPAWN +#define sl_Spawn(pEntry,pValue,flags) osi_Spawn(pEntry,pValue,flags) +#endif + +/*! + + Close the Doxygen group. + @} + + */ +/*! + ****************************************************************************** + + \defgroup porting_mem_mgm Porting - Memory Management + + This section declare in which memory management model the SimpleLink driver + will run: + -# Static + -# Dynamic + + This section IS NOT REQUIRED in case Static model is selected. + + The default memory model is Static + + PORTING ACTION: + - If dynamic model is selected, define the alloc and free functions. + + @{ + + ***************************************************************************** +*/ + +/*! + \brief Defines whether the SimpleLink driver is working in dynamic + memory model or not + + When defined, the SimpleLink driver use dynamic allocations + if dynamic allocation is selected malloc and free functions + must be retrieved + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define SL_MEMORY_MGMT_DYNAMIC 1 +#define SL_MEMORY_MGMT_STATIC 0 + +#define SL_MEMORY_MGMT SL_MEMORY_MGMT_DYNAMIC + +#ifdef SL_MEMORY_MGMT_DYNAMIC +#ifdef SL_PLATFORM_MULTI_THREADED + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Malloc(Size) mem_Malloc(Size) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Free(pMem) mem_Free(pMem) +#else +#include +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Malloc(Size) malloc(Size) + +/*! + \brief + \sa + \note belongs to \ref ported_sec + \warning +*/ +#define sl_Free(pMem) free(pMem) +#endif +#endif +/*! + + Close the Doxygen group. + @} + + */ + + +/*! + ****************************************************************************** + + \defgroup porting_events Porting - Event Handlers + + This section includes the asynchronous event handlers routines + + PORTING ACTION: + -Uncomment the required handler and define your routine as the value + of this handler + + @{ + + ****************************************************************************** + */ + +/*! + \brief + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_GeneralEvtHdlr SimpleLinkGeneralEventHandler + + +/*! + \brief An event handler for WLAN connection or disconnection indication + This event handles async WLAN events. + Possible events are: + SL_WLAN_CONNECT_EVENT - indicates WLAN is connected + SL_WLAN_DISCONNECT_EVENT - indicates WLAN is disconnected + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_WlanEvtHdlr SimpleLinkWlanEventHandler + + +/*! + \brief An event handler for IP address asynchronous event. Usually accepted after new WLAN connection. + This event handles networking events. + Possible events are: + SL_NETAPP_IPV4_ACQUIRED - IP address was acquired (DHCP or Static) + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_NetAppEvtHdlr SimpleLinkNetAppEventHandler + +/*! + \brief A callback for HTTP server events. + Possible events are: + SL_NETAPP_HTTPGETTOKENVALUE - NWP requests to get the value of a specific token + SL_NETAPP_HTTPPOSTTOKENVALUE - NWP post to the host a new value for a specific token + + \param pServerEvent - Contains the relevant event information (SL_NETAPP_HTTPGETTOKENVALUE or SL_NETAPP_HTTPPOSTTOKENVALUE) + + \param pServerResponse - Should be filled by the user with the relevant response information (i.e SL_NETAPP_HTTPSETTOKENVALUE as a response to SL_NETAPP_HTTPGETTOKENVALUE event) + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_HttpServerCallback SimpleLinkHttpServerCallback +/*! + \brief + + \sa + + \note belongs to \ref porting_sec + + \warning +*/ + +#define sl_SockEvtHdlr SimpleLinkSockEventHandler + + + +#define _SL_USER_TYPES +#define _u8 unsigned char +#define _i8 signed char + +#define _u16 unsigned short +#define _i16 signed short + +#define _u32 unsigned int +#define _i32 signed int +#define _volatile volatile +#define _const const + + + +/*! + + Close the Doxygen group. + @} + + */ + + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // __USER_H__ diff --git a/src/openmv/src/micropython/ports/cc3200/telnet/telnet.c b/src/openmv/src/micropython/ports/cc3200/telnet/telnet.c new file mode 100755 index 0000000..dbb77cd --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/telnet/telnet.c @@ -0,0 +1,498 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/obj.h" +#include "py/mphal.h" +#include "lib/utils/interrupt_char.h" +#include "telnet.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "modusocket.h" +#include "debug.h" +#include "mpexception.h" +#include "serverstask.h" +#include "genhdr/mpversion.h" +#include "irq.h" + +/****************************************************************************** + DEFINE PRIVATE CONSTANTS + ******************************************************************************/ +#define TELNET_PORT 23 +// rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 +#define TELNET_RX_BUFFER_SIZE 256 +#define TELNET_MAX_CLIENTS 1 +#define TELNET_TX_RETRIES_MAX 50 +#define TELNET_WAIT_TIME_MS 5 +#define TELNET_LOGIN_RETRIES_MAX 3 +#define TELNET_CYCLE_TIME_MS (SERVERS_CYCLE_TIME_MS * 2) + +/****************************************************************************** + DEFINE PRIVATE TYPES + ******************************************************************************/ +typedef enum { + E_TELNET_RESULT_OK = 0, + E_TELNET_RESULT_AGAIN, + E_TELNET_RESULT_FAILED +} telnet_result_t; + +typedef enum { + E_TELNET_STE_DISABLED = 0, + E_TELNET_STE_START, + E_TELNET_STE_LISTEN, + E_TELNET_STE_CONNECTED, + E_TELNET_STE_LOGGED_IN +} telnet_state_t; + +typedef enum { + E_TELNET_STE_SUB_WELCOME, + E_TELNET_STE_SUB_SND_USER_OPTIONS, + E_TELNET_STE_SUB_REQ_USER, + E_TELNET_STE_SUB_GET_USER, + E_TELNET_STE_SUB_REQ_PASSWORD, + E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS, + E_TELNET_STE_SUB_GET_PASSWORD, + E_TELNET_STE_SUB_INVALID_LOGGIN, + E_TELNET_STE_SUB_SND_REPL_OPTIONS, + E_TELNET_STE_SUB_LOGGIN_SUCCESS +} telnet_connected_substate_t; + +typedef union { + telnet_connected_substate_t connected; +} telnet_substate_t; + +typedef struct { + uint8_t *rxBuffer; + uint32_t timeout; + telnet_state_t state; + telnet_substate_t substate; + int16_t sd; + int16_t n_sd; + + // rxRindex and rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 + uint8_t rxWindex; + uint8_t rxRindex; + + uint8_t txRetries; + uint8_t logginRetries; + bool enabled; + bool credentialsValid; +} telnet_data_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +static telnet_data_t telnet_data; +static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"; +static const char* telnet_request_user = "Login as: "; +static const char* telnet_request_password = "Password: "; +static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n"; +static const char* telnet_loggin_success = "\r\nLogin succeeded!\r\nType \"help()\" for more information.\r\n"; +static const uint8_t telnet_options_user[] = // IAC WONT ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE + { 255, 252, 1, 255, 252, 3, 255, 251, 34 }; +static const uint8_t telnet_options_pass[] = // IAC WILL ECHO IAC WONT SUPPRESS_GO_AHEAD IAC WILL LINEMODE + { 255, 251, 1, 255, 252, 3, 255, 251, 34 }; +static const uint8_t telnet_options_repl[] = // IAC WILL ECHO IAC WILL SUPPRESS_GO_AHEAD IAC WONT LINEMODE + { 255, 251, 1, 255, 251, 3, 255, 252, 34 }; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +static void telnet_wait_for_enabled (void); +static bool telnet_create_socket (void); +static void telnet_wait_for_connection (void); +static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state); +static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len); +static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen); +static void telnet_process (void); +static int telnet_process_credential (char *credential, _i16 rxLen); +static void telnet_parse_input (uint8_t *str, int16_t *len); +static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len); +static void telnet_reset_buffer (void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void telnet_init (void) { + // Allocate memory for the receive buffer (from the RTOS heap) + ASSERT ((telnet_data.rxBuffer = mem_Malloc(TELNET_RX_BUFFER_SIZE)) != NULL); + telnet_data.state = E_TELNET_STE_DISABLED; +} + +void telnet_run (void) { + _i16 rxLen; + switch (telnet_data.state) { + case E_TELNET_STE_DISABLED: + telnet_wait_for_enabled(); + break; + case E_TELNET_STE_START: + if (wlan_is_connected() && telnet_create_socket()) { + telnet_data.state = E_TELNET_STE_LISTEN; + } + break; + case E_TELNET_STE_LISTEN: + telnet_wait_for_connection(); + break; + case E_TELNET_STE_CONNECTED: + switch (telnet_data.substate.connected) { + case E_TELNET_STE_SUB_WELCOME: + telnet_send_and_proceed((void *)telnet_welcome_msg, strlen(telnet_welcome_msg), E_TELNET_STE_SUB_SND_USER_OPTIONS); + break; + case E_TELNET_STE_SUB_SND_USER_OPTIONS: + telnet_send_and_proceed((void *)telnet_options_user, sizeof(telnet_options_user), E_TELNET_STE_SUB_REQ_USER); + break; + case E_TELNET_STE_SUB_REQ_USER: + // to catch any left over characters from the previous actions + telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen); + telnet_send_and_proceed((void *)telnet_request_user, strlen(telnet_request_user), E_TELNET_STE_SUB_GET_USER); + break; + case E_TELNET_STE_SUB_GET_USER: + if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex, + TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex, + &rxLen)) { + int result; + if ((result = telnet_process_credential (servers_user, rxLen))) { + telnet_data.credentialsValid = result > 0 ? true : false; + telnet_data.substate.connected = E_TELNET_STE_SUB_REQ_PASSWORD; + } + } + break; + case E_TELNET_STE_SUB_REQ_PASSWORD: + telnet_send_and_proceed((void *)telnet_request_password, strlen(telnet_request_password), E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS); + break; + case E_TELNET_STE_SUB_SND_PASSWORD_OPTIONS: + // to catch any left over characters from the previous actions + telnet_recv_text_non_blocking(telnet_data.rxBuffer, TELNET_RX_BUFFER_SIZE, &rxLen); + telnet_send_and_proceed((void *)telnet_options_pass, sizeof(telnet_options_pass), E_TELNET_STE_SUB_GET_PASSWORD); + break; + case E_TELNET_STE_SUB_GET_PASSWORD: + if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(telnet_data.rxBuffer + telnet_data.rxWindex, + TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex, + &rxLen)) { + int result; + if ((result = telnet_process_credential (servers_pass, rxLen))) { + if ((telnet_data.credentialsValid = telnet_data.credentialsValid && (result > 0 ? true : false))) { + telnet_data.substate.connected = E_TELNET_STE_SUB_SND_REPL_OPTIONS; + } + else { + telnet_data.substate.connected = E_TELNET_STE_SUB_INVALID_LOGGIN; + } + } + } + break; + case E_TELNET_STE_SUB_INVALID_LOGGIN: + if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_invalid_loggin, strlen(telnet_invalid_loggin))) { + telnet_data.credentialsValid = true; + if (++telnet_data.logginRetries >= TELNET_LOGIN_RETRIES_MAX) { + telnet_reset(); + } + else { + telnet_data.substate.connected = E_TELNET_STE_SUB_SND_USER_OPTIONS; + } + } + break; + case E_TELNET_STE_SUB_SND_REPL_OPTIONS: + telnet_send_and_proceed((void *)telnet_options_repl, sizeof(telnet_options_repl), E_TELNET_STE_SUB_LOGGIN_SUCCESS); + break; + case E_TELNET_STE_SUB_LOGGIN_SUCCESS: + if (E_TELNET_RESULT_OK == telnet_send_non_blocking((void *)telnet_loggin_success, strlen(telnet_loggin_success))) { + // clear the current line and force the prompt + telnet_reset_buffer(); + telnet_data.state= E_TELNET_STE_LOGGED_IN; + } + default: + break; + } + break; + case E_TELNET_STE_LOGGED_IN: + telnet_process(); + break; + default: + break; + } + + if (telnet_data.state >= E_TELNET_STE_CONNECTED) { + if (telnet_data.timeout++ > (servers_get_timeout() / TELNET_CYCLE_TIME_MS)) { + telnet_reset(); + } + } +} + +void telnet_tx_strn (const char *str, int len) { + if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) { + telnet_send_with_retries(telnet_data.n_sd, str, len); + } +} + +bool telnet_rx_any (void) { + return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex && + telnet_data.state == E_TELNET_STE_LOGGED_IN) : false; +} + +int telnet_rx_char (void) { + int rx_char = -1; + if (telnet_data.rxRindex != telnet_data.rxWindex) { + // rxRindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically + rx_char = (int)telnet_data.rxBuffer[telnet_data.rxRindex++]; + } + return rx_char; +} + +void telnet_enable (void) { + telnet_data.enabled = true; +} + +void telnet_disable (void) { + telnet_reset(); + telnet_data.enabled = false; + telnet_data.state = E_TELNET_STE_DISABLED; +} + +void telnet_reset (void) { + // close the connection and start all over again + servers_close_socket(&telnet_data.n_sd); + servers_close_socket(&telnet_data.sd); + telnet_data.state = E_TELNET_STE_START; +} + +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +static void telnet_wait_for_enabled (void) { + // Init telnet's data + telnet_data.n_sd = -1; + telnet_data.sd = -1; + + // Check if the telnet service has been enabled + if (telnet_data.enabled) { + telnet_data.state = E_TELNET_STE_START; + } +} + +static bool telnet_create_socket (void) { + SlSockNonblocking_t nonBlockingOption; + SlSockAddrIn_t sServerAddress; + _i16 result; + + // Open a socket for telnet + ASSERT ((telnet_data.sd = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_IPPROTO_TCP)) > 0); + if (telnet_data.sd > 0) { + // add the socket to the network administration + modusocket_socket_add(telnet_data.sd, false); + + // Enable non-blocking mode + nonBlockingOption.NonblockingEnabled = 1; + ASSERT ((result = sl_SetSockOpt(telnet_data.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &nonBlockingOption, sizeof(nonBlockingOption))) == SL_SOC_OK); + + // Bind the socket to a port number + sServerAddress.sin_family = SL_AF_INET; + sServerAddress.sin_addr.s_addr = SL_INADDR_ANY; + sServerAddress.sin_port = sl_Htons(TELNET_PORT); + + ASSERT ((result |= sl_Bind(telnet_data.sd, (const SlSockAddr_t *)&sServerAddress, sizeof(sServerAddress))) == SL_SOC_OK); + + // Start listening + ASSERT ((result |= sl_Listen (telnet_data.sd, TELNET_MAX_CLIENTS)) == SL_SOC_OK); + + if (result == SL_SOC_OK) { + return true; + } + servers_close_socket(&telnet_data.sd); + } + + return false; +} + +static void telnet_wait_for_connection (void) { + SlSocklen_t in_addrSize; + SlSockAddrIn_t sClientAddress; + + // accepts a connection from a TCP client, if there is any, otherwise returns SL_EAGAIN + telnet_data.n_sd = sl_Accept(telnet_data.sd, (SlSockAddr_t *)&sClientAddress, (SlSocklen_t *)&in_addrSize); + if (telnet_data.n_sd == SL_EAGAIN) { + return; + } + else { + if (telnet_data.n_sd <= 0) { + // error + telnet_reset(); + return; + } + + // close the listening socket, we don't need it anymore + servers_close_socket(&telnet_data.sd); + + // add the new socket to the network administration + modusocket_socket_add(telnet_data.n_sd, false); + + // client connected, so go on + telnet_data.rxWindex = 0; + telnet_data.rxRindex = 0; + telnet_data.txRetries = 0; + + telnet_data.state = E_TELNET_STE_CONNECTED; + telnet_data.substate.connected = E_TELNET_STE_SUB_WELCOME; + telnet_data.credentialsValid = true; + telnet_data.logginRetries = 0; + telnet_data.timeout = 0; + } +} + +static void telnet_send_and_proceed (void *data, _i16 Len, telnet_connected_substate_t next_state) { + if (E_TELNET_RESULT_OK == telnet_send_non_blocking(data, Len)) { + telnet_data.substate.connected = next_state; + } +} + +static telnet_result_t telnet_send_non_blocking (void *data, _i16 Len) { + int16_t result = sl_Send(telnet_data.n_sd, data, Len, 0); + + if (result > 0) { + telnet_data.txRetries = 0; + return E_TELNET_RESULT_OK; + } + else if ((TELNET_TX_RETRIES_MAX >= ++telnet_data.txRetries) && (result == SL_EAGAIN)) { + return E_TELNET_RESULT_AGAIN; + } + else { + // error + telnet_reset(); + return E_TELNET_RESULT_FAILED; + } +} + +static telnet_result_t telnet_recv_text_non_blocking (void *buff, _i16 Maxlen, _i16 *rxLen) { + *rxLen = sl_Recv(telnet_data.n_sd, buff, Maxlen, 0); + // if there's data received, parse it + if (*rxLen > 0) { + telnet_data.timeout = 0; + telnet_parse_input (buff, rxLen); + if (*rxLen > 0) { + return E_TELNET_RESULT_OK; + } + } + else if (*rxLen != SL_EAGAIN) { + // error + telnet_reset(); + return E_TELNET_RESULT_FAILED; + } + return E_TELNET_RESULT_AGAIN; +} + +static void telnet_process (void) { + _i16 rxLen; + _i16 maxLen = (telnet_data.rxWindex >= telnet_data.rxRindex) ? (TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex) : + ((telnet_data.rxRindex - telnet_data.rxWindex) - 1); + // to avoid an overrrun + maxLen = (telnet_data.rxRindex == 0) ? (maxLen - 1) : maxLen; + + if (maxLen > 0) { + if (E_TELNET_RESULT_OK == telnet_recv_text_non_blocking(&telnet_data.rxBuffer[telnet_data.rxWindex], maxLen, &rxLen)) { + // rxWindex must be uint8_t and TELNET_RX_BUFFER_SIZE == 256 so that it wraps around automatically + telnet_data.rxWindex = telnet_data.rxWindex + rxLen; + } + } +} + +static int telnet_process_credential (char *credential, _i16 rxLen) { + telnet_data.rxWindex += rxLen; + if (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX) { + telnet_data.rxWindex = SERVERS_USER_PASS_LEN_MAX; + } + + uint8_t *p = telnet_data.rxBuffer + SERVERS_USER_PASS_LEN_MAX; + // if a '\r' is found, or the length exceeds the max username length + if ((p = memchr(telnet_data.rxBuffer, '\r', telnet_data.rxWindex)) || (telnet_data.rxWindex >= SERVERS_USER_PASS_LEN_MAX)) { + uint8_t len = p - telnet_data.rxBuffer; + + telnet_data.rxWindex = 0; + if ((len > 0) && (memcmp(credential, telnet_data.rxBuffer, MAX(len, strlen(credential))) == 0)) { + return 1; + } + return -1; + } + return 0; +} + +static void telnet_parse_input (uint8_t *str, int16_t *len) { + int16_t b_len = *len; + uint8_t *b_str = str; + + for (uint8_t *_str = b_str; _str < b_str + b_len; ) { + if (*_str <= 127) { + if (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == mp_interrupt_char) { + // raise a keyboard exception + mp_keyboard_interrupt(); + (*len)--; + _str++; + } + else if (*_str > 0) { + *str++ = *_str++; + } + else { + _str++; + *len -= 1; + } + } + else { + // in case we have received an incomplete telnet option, unlikely, but possible + _str += MIN(3, *len); + *len -= MIN(3, *len); + } + } +} + +static bool telnet_send_with_retries (int16_t sd, const void *pBuf, int16_t len) { + int32_t retries = 0; + uint32_t delay = TELNET_WAIT_TIME_MS; + // only if we are not within interrupt context and interrupts are enabled + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + do { + _i16 result = sl_Send(sd, pBuf, len, 0); + if (result > 0) { + return true; + } + else if (SL_EAGAIN != result) { + return false; + } + // start with the default delay and increment it on each retry + mp_hal_delay_ms(delay++); + } while (++retries <= TELNET_TX_RETRIES_MAX); + } + return false; +} + +static void telnet_reset_buffer (void) { + // erase any characters present in the current line + memset (telnet_data.rxBuffer, '\b', TELNET_RX_BUFFER_SIZE / 2); + telnet_data.rxWindex = TELNET_RX_BUFFER_SIZE / 2; + // fake an "enter" key pressed to display the prompt + telnet_data.rxBuffer[telnet_data.rxWindex++] = '\r'; +} + diff --git a/src/openmv/src/micropython/ports/cc3200/telnet/telnet.h b/src/openmv/src/micropython/ports/cc3200/telnet/telnet.h new file mode 100755 index 0000000..51c5691 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/telnet/telnet.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_TELNET_TELNET_H +#define MICROPY_INCLUDED_CC3200_TELNET_TELNET_H + +/****************************************************************************** + DECLARE EXPORTED FUNCTIONS + ******************************************************************************/ +extern void telnet_init (void); +extern void telnet_run (void); +extern void telnet_tx_strn (const char *str, int len); +extern bool telnet_rx_any (void); +extern int telnet_rx_char (void); +extern void telnet_enable (void); +extern void telnet_disable (void); +extern void telnet_reset (void); + +#endif // MICROPY_INCLUDED_CC3200_TELNET_TELNET_H diff --git a/src/openmv/src/micropython/ports/cc3200/tools/smoke.py b/src/openmv/src/micropython/ports/cc3200/tools/smoke.py new file mode 100755 index 0000000..3ade11c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/tools/smoke.py @@ -0,0 +1,76 @@ +from machine import Pin +from machine import RTC +import time +import os + +""" +Execute it like this: + +python3 run-tests --target wipy --device 192.168.1.1 ../cc3200/tools/smoke.py +""" + +pin_map = [23, 24, 11, 12, 13, 14, 15, 16, 17, 22, 28, 10, 9, 8, 7, 6, 30, 31, 3, 0, 4, 5] +test_bytes = os.urandom(1024) + +def test_pin_read (pull): + # enable the pull resistor on all pins, then read the value + for p in pin_map: + pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull) + # read the pin value + print(pin()) + +def test_pin_shorts (pull): + if pull == Pin.PULL_UP: + pull_inverted = Pin.PULL_DOWN + else: + pull_inverted = Pin.PULL_UP + # enable all pulls of the specified type + for p in pin_map: + pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull_inverted) + # then change the pull one pin at a time and read its value + i = 0 + while i < len(pin_map): + pin = Pin('GP' + str(pin_map[i]), mode=Pin.IN, pull=pull) + Pin('GP' + str(pin_map[i - 1]), mode=Pin.IN, pull=pull_inverted) + i += 1 + # read the pin value + print(pin()) + +test_pin_read(Pin.PULL_UP) +test_pin_read(Pin.PULL_DOWN) +test_pin_shorts(Pin.PULL_UP) +test_pin_shorts(Pin.PULL_DOWN) + +# create a test directory +os.mkdir('/flash/test') +os.chdir('/flash/test') +print(os.getcwd()) +# create a new file +f = open('test.txt', 'w') +n_w = f.write(test_bytes) +print(n_w == len(test_bytes)) +f.close() +f = open('test.txt', 'r') +r = bytes(f.read(), 'ascii') +# check that we can write and read it correctly +print(r == test_bytes) +f.close() +os.remove('test.txt') +os.chdir('..') +os.rmdir('test') + +ls = os.listdir() +print('test' not in ls) +print(ls) + +# test the real time clock +rtc = RTC() +while rtc.now()[6] > 800: + pass + +time1 = rtc.now() +time.sleep_ms(1000) +time2 = rtc.now() +print(time2[5] - time1[5] == 1) +print(time2[6] - time1[6] < 5000) # microseconds + diff --git a/src/openmv/src/micropython/ports/cc3200/tools/smoke.py.exp b/src/openmv/src/micropython/ports/cc3200/tools/smoke.py.exp new file mode 100755 index 0000000..fdc958c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/tools/smoke.py.exp @@ -0,0 +1,95 @@ +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +/flash/test +True +True +True +['main.py', 'sys', 'lib', 'cert', 'boot.py'] +True +True diff --git a/src/openmv/src/micropython/ports/cc3200/tools/uniflash.py b/src/openmv/src/micropython/ports/cc3200/tools/uniflash.py new file mode 100755 index 0000000..21da46a --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/tools/uniflash.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +""" +Flash the WiPy (format, update service pack and program). + +Example: + +> python uniflash.py -u "C:\ti\uniflash_3.2\uniflashCLI.bat" -c "C:\VirtualBoxShared\GitHub\wipy_uniflash.usf" -p 8 -s "C:\ti\CC31xx_CC32xx_ServicePack_1.0.0.10.0\servicepack_1.0.0.10.0.bin" + +or: + +> python uniflash.py -u "C:\ti\uniflash_3.2\uniflashCLI.bat" -c "C:\VirtualBoxShared\GitHub\launchxl_uniflash.usf" -p 8 -s "C:\ti\CC31xx_CC32xx_ServicePack_1.0.0.10.0\servicepack_1.0.0.10.0.bin" + +""" + +import sys +import argparse +import subprocess + + +def print_exception(e): + print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno)) + + +def execute(command): + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + cmd_log = "" + + # Poll process for new output until finished + while True: + nextline = process.stdout.readline() + if nextline == '' and process.poll() != None: + break + sys.stdout.write(nextline) + sys.stdout.flush() + cmd_log += nextline + + output = process.communicate()[0] + exitCode = process.returncode + + if exitCode == 0: + return cmd_log + else: + raise ProcessException(command, exitCode, output) + +def main(): + cmd_parser = argparse.ArgumentParser(description='Flash the WiPy and optionally run a small test on it.') + cmd_parser.add_argument('-u', '--uniflash', default=None, help='the path to the uniflash cli executable') + cmd_parser.add_argument('-c', '--config', default=None, help='the path to the uniflash config file') + cmd_parser.add_argument('-p', '--port', default=8, help='the com serial port') + cmd_parser.add_argument('-s', '--servicepack', default=None, help='the path to the servicepack file') + args = cmd_parser.parse_args() + + output = "" + com_port = 'com=' + str(args.port) + servicepack_path = 'spPath=' + args.servicepack + + try: + if args.uniflash == None or args.config == None: + raise ValueError('uniflash path and config path are mandatory') + if args.servicepack == None: + output += execute([args.uniflash, '-config', args.config, '-setOptions', com_port, '-operations', 'format', 'program']) + else: + output += execute([args.uniflash, '-config', args.config, '-setOptions', com_port, servicepack_path, '-operations', 'format', 'servicePackUpdate', 'program']) + except Exception as e: + print_exception(e) + output = "" + finally: + if "Finish Executing operation: program" in output: + print("======================================") + print("Board programmed OK") + print("======================================") + sys.exit(0) + else: + print("======================================") + print("ERROR: Programming failed!") + print("======================================") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/cc3200/tools/update-wipy.py b/src/openmv/src/micropython/ports/cc3200/tools/update-wipy.py new file mode 100755 index 0000000..2d5fe57 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/tools/update-wipy.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python + +""" +The WiPy firmware update script. Transmits the specified firmware file +over FTP, and then resets the WiPy and optionally verifies that software +was correctly updated. + +Usage: + + ./update-wipy.py --file "path_to_mcuimg.bin" --verify + +Or: + + python update-wipy.py --file "path_to_mcuimg.bin" +""" + +import sys +import argparse +import time +import socket +from ftplib import FTP +from telnetlib import Telnet + + +def print_exception(e): + print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno)) + + +def ftp_directory_exists(ftpobj, directory_name): + filelist = [] + ftpobj.retrlines('LIST',filelist.append) + for f in filelist: + if f.split()[-1] == directory_name: + return True + return False + + +def transfer_file(args): + with FTP(args.ip, timeout=20) as ftp: + print ('FTP connection established') + + if '230' in ftp.login(args.user, args.password): + print ('Login successful') + + if '250' in ftp.cwd('/flash'): + if not ftp_directory_exists(ftp, 'sys'): + print ('/flash/sys directory does not exist') + if not '550' in ftp.mkd('sys'): + print ('/flash/sys directory created') + else: + print ('Error: cannot create /flash/sys directory') + return False + if '250' in ftp.cwd('sys'): + print ("Entered '/flash/sys' directory") + with open(args.file, "rb") as fwfile: + print ('Firmware image found, initiating transfer...') + if '226' in ftp.storbinary("STOR " + 'mcuimg.bin', fwfile, 512): + print ('File transfer complete') + return True + else: + print ('Error: file transfer failed') + else: + print ('Error: cannot enter /flash/sys directory') + else: + print ('Error: cannot enter /flash directory') + else: + print ('Error: ftp login failed') + + return False + + +def reset_board(args): + success = False + + try: + tn = Telnet(args.ip, timeout=5) + print("Connected via Telnet, trying to login now") + + if b'Login as:' in tn.read_until(b"Login as:", timeout=5): + tn.write(bytes(args.user, 'ascii') + b"\r\n") + + if b'Password:' in tn.read_until(b"Password:", timeout=5): + # needed because of internal implementation details of the WiPy's telnet server + time.sleep(0.2) + tn.write(bytes(args.password, 'ascii') + b"\r\n") + + if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5): + print("Telnet login succeeded") + tn.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program + time.sleep(1) + tn.write(b'\r\x02') # ctrl-B: enter friendly REPL + if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5): + tn.write(b"import machine\r\n") + tn.write(b"machine.reset()\r\n") + time.sleep(2) + print("Reset performed") + success = True + else: + print("Error: cannot enter friendly REPL") + else: + print("Error: telnet login failed") + + except Exception as e: + print_exception(e) + finally: + try: + tn.close() + except Exception as e: + pass + return success + + +def verify_update(args): + success = False + firmware_tag = '' + + def find_tag (tag): + if tag in firmware_tag: + print("Verification passed") + return True + else: + print("Error: verification failed, the git tag doesn't match") + return False + + retries = 0 + while True: + try: + # Specify a longer time out value here because the board has just been + # reset and the wireless connection might not be fully established yet + tn = Telnet(args.ip, timeout=10) + print("Connected via telnet again, lets check the git tag") + break + except socket.timeout: + if retries < 5: + print("Timeout while connecting via telnet, retrying...") + retries += 1 + else: + print('Error: Telnet connection timed out!') + return False + + try: + firmware_tag = tn.read_until (b'with CC3200') + tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h' + + if args.tag is not None: + success = find_tag(bytes(args.tag, 'ascii')) + else: + with open(tag_file_path) as tag_file: + for line in tag_file: + bline = bytes(line, 'ascii') + if b'MICROPY_GIT_HASH' in bline: + bline = bline.lstrip(b'#define MICROPY_GIT_HASH ').replace(b'"', b'').replace(b'\r', b'').replace(b'\n', b'') + success = find_tag(bline) + break + + except Exception as e: + print_exception(e) + finally: + try: + tn.close() + except Exception as e: + pass + return success + + +def main(): + cmd_parser = argparse.ArgumentParser(description='Update the WiPy firmware with the specified image file') + cmd_parser.add_argument('-f', '--file', default=None, help='the path of the firmware file') + cmd_parser.add_argument('-u', '--user', default='micro', help='the username') + cmd_parser.add_argument('-p', '--password', default='python', help='the login password') + cmd_parser.add_argument('--ip', default='192.168.1.1', help='the ip address of the WiPy') + cmd_parser.add_argument('--verify', action='store_true', help='verify that the update succeeded') + cmd_parser.add_argument('-t', '--tag', default=None, help='git tag of the firmware image') + args = cmd_parser.parse_args() + + result = 1 + + try: + if args.file is None: + raise ValueError('the image file path must be specified') + if transfer_file(args): + if reset_board(args): + if args.verify: + print ('Waiting for the WiFi connection to come up again...') + # this time is to allow the system's wireless network card to + # connect to the WiPy again. + time.sleep(5) + if verify_update(args): + result = 0 + else: + result = 0 + + except Exception as e: + print_exception(e) + finally: + sys.exit(result) + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/cc3200/util/cryptohash.c b/src/openmv/src/micropython/ports/cc3200/util/cryptohash.c new file mode 100755 index 0000000..909dadc --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/cryptohash.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_shamd5.h" +#include "inc/hw_dthe.h" +#include "hw_memmap.h" +#include "rom_map.h" +#include "prcm.h" +#include "shamd5.h" +#include "cryptohash.h" + + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void CRYPTOHASH_Init (void) { + // Enable the Data Hashing and Transform Engine + MAP_PRCMPeripheralClkEnable(PRCM_DTHE, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMPeripheralReset(PRCM_DTHE); +} + +void CRYPTOHASH_SHAMD5Start (uint32_t algo, uint32_t blocklen) { + // wait until the context is ready + while ((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_CONTEXT_READY) == 0); + + // Configure the SHA/MD5 module algorithm + MAP_SHAMD5ConfigSet(SHAMD5_BASE, algo); + + // if not a multiple of 64 bytes, close the hash + if (blocklen % 64) { + HWREG(SHAMD5_BASE + SHAMD5_O_MODE) |= SHAMD5_MODE_CLOSE_HASH; + } + + // set the lenght + HWREG(SHAMD5_BASE + SHAMD5_O_LENGTH) = blocklen; +} + +void CRYPTOHASH_SHAMD5Update (uint8_t *data, uint32_t datalen) { + // write the data + SHAMD5DataWriteMultiple(data, datalen); +} + +void CRYPTOHASH_SHAMD5Read (uint8_t *hash) { + // wait for the output to be ready + while((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_OUTPUT_READY) == 0); + // read the result + MAP_SHAMD5ResultRead(SHAMD5_BASE, hash); +} diff --git a/src/openmv/src/micropython/ports/cc3200/util/cryptohash.h b/src/openmv/src/micropython/ports/cc3200/util/cryptohash.h new file mode 100755 index 0000000..15d46b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/cryptohash.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_CRYPTOHASH_H +#define MICROPY_INCLUDED_CC3200_UTIL_CRYPTOHASH_H + +/****************************************************************************** + DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ +extern void CRYPTOHASH_Init (void); +extern void CRYPTOHASH_SHAMD5Start (uint32_t algo, uint32_t blocklen); +extern void CRYPTOHASH_SHAMD5Update (uint8_t *data, uint32_t datalen); +extern void CRYPTOHASH_SHAMD5Read (uint8_t *hash); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_CRYPTOHASH_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/fifo.c b/src/openmv/src/micropython/ports/cc3200/util/fifo.c new file mode 100755 index 0000000..421f837 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/fifo.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "fifo.h" + + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void FIFO_Init (FIFO_t *fifo, unsigned int uiElementsMax, + void (*pfElmentPush)(void * const pvFifo, const void * const pvElement), + void (*pfElementPop)(void * const pvFifo, void * const pvElement)) { + if (fifo) { + fifo->uiFirst = 0; + fifo->uiLast = uiElementsMax - 1; + fifo->uiElementCount = 0; + fifo->uiElementsMax = uiElementsMax; + fifo->pfElementPush = pfElmentPush; + fifo->pfElementPop = pfElementPop; + } +} + +bool FIFO_bPushElement (FIFO_t *fifo, const void * const pvElement) { + if (!fifo) { + return false; + } + // Check if the queue is full + if (true == FIFO_IsFull (fifo)) { + return false; + } + + // Increment the element count + if (fifo->uiElementsMax > fifo->uiElementCount) { + fifo->uiElementCount++; + } + fifo->uiLast++; + if (fifo->uiLast == fifo->uiElementsMax) { + fifo->uiLast = 0; + } + // Insert the element into the queue + fifo->pfElementPush(fifo, pvElement); + return true; +} + +bool FIFO_bPopElement (FIFO_t *fifo, void * const pvElement) { + if (!fifo) { + return false; + } + // Check if the queue is empty + if (true == FIFO_IsEmpty (fifo)) { + return false; + } + + // Get the element from the queue + fifo->pfElementPop(fifo, pvElement); + // Decrement the element count + if (fifo->uiElementCount > 0) { + fifo->uiElementCount--; + } + fifo->uiFirst++; + if (fifo->uiFirst == fifo->uiElementsMax) { + fifo->uiFirst = 0; + } + return true; +} + +bool FIFO_bPeekElement (FIFO_t *fifo, void * const pvElement) { + if (!fifo) { + return false; + } + // Check if the queue is empty + if (true == FIFO_IsEmpty (fifo)) { + return false; + } + // Get the element from the queue + fifo->pfElementPop(fifo, pvElement); + return true; +} + +bool FIFO_IsEmpty (FIFO_t *fifo) { + if (fifo) { + return ((fifo->uiElementCount == 0) ? true : false); + } + return false; +} + +bool FIFO_IsFull (FIFO_t *fifo) { + if (fifo) { + return ((fifo->uiElementCount < fifo->uiElementsMax) ? false : true); + } + return false; +} + +void FIFO_Flush (FIFO_t *fifo) { + if (fifo) { + fifo->uiElementCount = 0; + fifo->uiFirst = 0; + fifo->uiLast = fifo->uiElementsMax - 1; + } +} diff --git a/src/openmv/src/micropython/ports/cc3200/util/fifo.h b/src/openmv/src/micropython/ports/cc3200/util/fifo.h new file mode 100755 index 0000000..6ede57e --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/fifo.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_FIFO_H +#define MICROPY_INCLUDED_CC3200_UTIL_FIFO_H + +typedef struct { + void *pvElements; + unsigned int uiElementCount; + unsigned int uiElementsMax; + unsigned int uiFirst; + unsigned int uiLast; + void (*pfElementPush)(void * const pvFifo, const void * const pvElement); + void (*pfElementPop)(void * const pvFifo, void * const pvElement); +}FIFO_t; + +extern void FIFO_Init (FIFO_t *fifo, unsigned int uiElementsMax, +void (*pfElmentPush)(void * const pvFifo, const void * const pvElement), +void (*pfElementPop)(void * const pvFifo, void * const pvElement)); +extern bool FIFO_bPushElement (FIFO_t *fifo, const void * const pvElement); +extern bool FIFO_bPopElement (FIFO_t *fifo, void * const pvElement); +extern bool FIFO_bPeekElement (FIFO_t *fifo, void * const pvElement); +extern bool FIFO_IsEmpty (FIFO_t *fifo); +extern bool FIFO_IsFull (FIFO_t *fifo); +extern void FIFO_Flush (FIFO_t *fifo); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_FIFO_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/gccollect.c b/src/openmv/src/micropython/ports/cc3200/util/gccollect.c new file mode 100755 index 0000000..6e2a908 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/gccollect.c @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" +#include "gchelper.h" + +/****************************************************************************** +DECLARE PUBLIC FUNCTIONS + ******************************************************************************/ + +void gc_collect(void) { + // start the GC + gc_collect_start(); + + // get the registers and the sp + mp_uint_t regs[10]; + mp_uint_t sp = gc_helper_get_regs_and_sp(regs); + + // trace the stack, including the registers (since they live on the stack in this function) + gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + + // end the GC + gc_collect_end(); +} diff --git a/src/openmv/src/micropython/ports/cc3200/util/gccollect.h b/src/openmv/src/micropython/ports/cc3200/util/gccollect.h new file mode 100755 index 0000000..08d43d2 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/gccollect.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_GCCOLLECT_H +#define MICROPY_INCLUDED_CC3200_UTIL_GCCOLLECT_H + +// variables defining memory layout +extern uint32_t _etext; +extern uint32_t _data; +extern uint32_t _edata; +extern uint32_t _boot; +extern uint32_t _eboot; +extern uint32_t _bss; +extern uint32_t _ebss; +extern uint32_t _heap; +extern uint32_t _eheap; +extern uint32_t _stack; +extern uint32_t _estack; + +void gc_collect(void); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_GCCOLLECT_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/gchelper.h b/src/openmv/src/micropython/ports/cc3200/util/gchelper.h new file mode 100755 index 0000000..48e81bc --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/gchelper.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_GCHELPER_H +#define MICROPY_INCLUDED_CC3200_UTIL_GCHELPER_H + +extern mp_uint_t gc_helper_get_sp(void); +extern mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_GCHELPER_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/gchelper.s b/src/openmv/src/micropython/ports/cc3200/util/gchelper.s new file mode 100755 index 0000000..aa8fb49 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/gchelper.s @@ -0,0 +1,41 @@ + .syntax unified + .cpu cortex-m4 + .thumb + .text + .align 2 + + + +@ uint gc_helper_get_sp(void) + .global gc_helper_get_sp + .thumb + .thumb_func + .type gc_helper_get_sp, %function +gc_helper_get_sp: + @ return the sp + mov r0, sp + bx lr + + + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) + .global gc_helper_get_regs_and_sp + .thumb + .thumb_func + .type gc_helper_get_regs_and_sp, %function +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0], #4 + str r5, [r0], #4 + str r6, [r0], #4 + str r7, [r0], #4 + str r8, [r0], #4 + str r9, [r0], #4 + str r10, [r0], #4 + str r11, [r0], #4 + str r12, [r0], #4 + str r13, [r0], #4 + + @ return the sp + mov r0, sp + bx lr diff --git a/src/openmv/src/micropython/ports/cc3200/util/random.c b/src/openmv/src/micropython/ports/cc3200/util/random.c new file mode 100755 index 0000000..f8e9cdf --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/random.c @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_memmap.h" +#include "rom_map.h" +#include "pybrtc.h" +#include "simplelink.h" +#include "modnetwork.h" +#include "modwlan.h" +#include "random.h" +#include "debug.h" + +/****************************************************************************** +* LOCAL TYPES +******************************************************************************/ +typedef union _rng_id_t { + uint32_t id32; + uint16_t id16[3]; + uint8_t id8[6]; +} rng_id_t; + +/****************************************************************************** +* LOCAL VARIABLES +******************************************************************************/ +static uint32_t s_seed; + +/****************************************************************************** +* LOCAL FUNCTION DECLARATIONS +******************************************************************************/ +STATIC uint32_t lfsr (uint32_t input); + +/****************************************************************************** +* PRIVATE FUNCTIONS +******************************************************************************/ +STATIC uint32_t lfsr (uint32_t input) { + assert( input != 0 ); + return (input >> 1) ^ (-(input & 0x01) & 0x00E10000); +} + +/******************************************************************************/ +// MicroPython bindings; + +STATIC mp_obj_t machine_rng_get(void) { + return mp_obj_new_int(rng_get()); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_rng_get_obj, machine_rng_get); + +/****************************************************************************** +* PUBLIC FUNCTIONS +******************************************************************************/ +void rng_init0 (void) { + rng_id_t juggler; + uint32_t seconds; + uint16_t mseconds; + + // get the seconds and the milliseconds from the RTC + pyb_rtc_get_time(&seconds, &mseconds); + + wlan_get_mac (juggler.id8); + + // flatten the 48-bit board identification to 24 bits + juggler.id16[0] ^= juggler.id16[2]; + + juggler.id8[0] ^= juggler.id8[3]; + juggler.id8[1] ^= juggler.id8[4]; + juggler.id8[2] ^= juggler.id8[5]; + + s_seed = juggler.id32 & 0x00FFFFFF; + s_seed += (seconds & 0x000FFFFF) + mseconds; + + // the seed must not be zero + if (s_seed == 0) { + s_seed = 1; + } +} + +uint32_t rng_get (void) { + s_seed = lfsr( s_seed ); + return s_seed; +} diff --git a/src/openmv/src/micropython/ports/cc3200/util/random.h b/src/openmv/src/micropython/ports/cc3200/util/random.h new file mode 100755 index 0000000..02cde6b --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/random.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_RANDOM_H +#define MICROPY_INCLUDED_CC3200_UTIL_RANDOM_H + +void rng_init0 (void); +uint32_t rng_get (void); + +MP_DECLARE_CONST_FUN_OBJ_0(machine_rng_get_obj); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_RANDOM_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.h b/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.h new file mode 100755 index 0000000..e178f4c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_SLEEPRESTORE_H +#define MICROPY_INCLUDED_CC3200_UTIL_SLEEPRESTORE_H + +extern void sleep_store(void); +extern void sleep_restore(void); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_SLEEPRESTORE_H diff --git a/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.s b/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.s new file mode 100755 index 0000000..c7b0c7d --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/sleeprestore.s @@ -0,0 +1,61 @@ + .syntax unified + .cpu cortex-m4 + .thumb + .text + .align 2 + +@ global variable with the backup registers + .extern vault_arm_registers +@ global function that performs the wake up actions + .extern pyb_sleep_suspend_exit + +@ uint sleep_store(void) + .global sleep_store + .thumb + .thumb_func + .type sleep_store, %function +sleep_store: + dsb + isb + push {r0-r12, lr} + ldr r1, =vault_arm_registers + mrs r0, msp + str r0, [r1] + mrs r0, psp + str r0, [r1, #4] + mrs r0, primask + str r0, [r1, #12] + mrs r0, faultmask + str r0, [r1, #16] + mrs r0, basepri + str r0, [r1, #20] + mrs r0, control + str r0, [r1, #24] + dsb + isb + bx lr + +@ uint sleep_restore(void) + .global sleep_restore + .thumb + .thumb_func + .type sleep_restore, %function +sleep_restore: + dsb + isb + mrs r0, msp + msr psp, r0 + ldr r1, =vault_arm_registers + ldr r0, [r1, #24] + msr control, r0 + ldr r0, [r1] + msr msp, r0 + ldr r0, [r1, #12] + msr primask, r0 + ldr r0, [r1, #16] + msr faultmask, r0 + ldr r0, [r1, #20] + msr basepri, r0 + dsb + isb + bl pyb_sleep_suspend_exit diff --git a/src/openmv/src/micropython/ports/cc3200/util/socketfifo.c b/src/openmv/src/micropython/ports/cc3200/util/socketfifo.c new file mode 100755 index 0000000..d0a7150 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/socketfifo.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "osi.h" +#include "fifo.h" +#include "socketfifo.h" + + +/*---------------------------------------------------------------------------- + ** Declare private functions + */ +static void socketfifo_Push (void * const pvFifo, const void * const pvElement); +static void socketfifo_Pop (void * const pvFifo, void * const pvElement); + +/*---------------------------------------------------------------------------- + ** Declare private data + */ +static FIFO_t *socketfifo; + +/*---------------------------------------------------------------------------- + ** Define public functions + */ +void SOCKETFIFO_Init (FIFO_t *fifo, void *elements, uint32_t maxcount) { + // Initialize global data + socketfifo = fifo; + socketfifo->pvElements = elements; + FIFO_Init (socketfifo, maxcount, socketfifo_Push, socketfifo_Pop); +} + +bool SOCKETFIFO_Push (const void * const element) { + return FIFO_bPushElement (socketfifo, element); +} + +bool SOCKETFIFO_Pop (void * const element) { + return FIFO_bPopElement (socketfifo, element); +} + +bool SOCKETFIFO_Peek (void * const element) { + return FIFO_bPeekElement (socketfifo, element); +} + +bool SOCKETFIFO_IsEmpty (void) { + return FIFO_IsEmpty (socketfifo); +} + +bool SOCKETFIFO_IsFull (void) { + return FIFO_IsFull (socketfifo); +} + +void SOCKETFIFO_Flush (void) { + SocketFifoElement_t element; + while (SOCKETFIFO_Pop(&element)) { + if (element.freedata) { + mem_Free(element.data); + } + } +} + +unsigned int SOCKETFIFO_Count (void) { + return socketfifo->uiElementCount; +} + +/*---------------------------------------------------------------------------- + ** Define private functions + */ +static void socketfifo_Push (void * const pvFifo, const void * const pvElement) { + if ((pvFifo != NULL) && (NULL != pvElement)) { + unsigned int uiLast = ((FIFO_t *)pvFifo)->uiLast; + memcpy (&((SocketFifoElement_t *)((FIFO_t *)pvFifo)->pvElements)[uiLast], pvElement, sizeof(SocketFifoElement_t)); + } +} + +static void socketfifo_Pop (void * const pvFifo, void * const pvElement) { + if ((pvFifo != NULL) && (NULL != pvElement)) { + unsigned int uiFirst = ((FIFO_t *)pvFifo)->uiFirst; + memcpy (pvElement, &((SocketFifoElement_t *)((FIFO_t *)pvFifo)->pvElements)[uiFirst], sizeof(SocketFifoElement_t)); + } +} + diff --git a/src/openmv/src/micropython/ports/cc3200/util/socketfifo.h b/src/openmv/src/micropython/ports/cc3200/util/socketfifo.h new file mode 100755 index 0000000..e6cf851 --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/util/socketfifo.h @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_UTIL_SOCKETFIFO_H +#define MICROPY_INCLUDED_CC3200_UTIL_SOCKETFIFO_H + +/*---------------------------------------------------------------------------- + ** Imports + */ + +/*---------------------------------------------------------------------------- + ** Define constants + */ + +/*---------------------------------------------------------------------------- + ** Define types + */ + +typedef struct { + void *data; + signed short *sd; + unsigned short datasize; + unsigned char closesockets; + bool freedata; + +}SocketFifoElement_t; + +/*---------------------------------------------------------------------------- + ** Declare public functions + */ +extern void SOCKETFIFO_Init (FIFO_t *fifo, void *elements, uint32_t maxcount); +extern bool SOCKETFIFO_Push (const void * const element); +extern bool SOCKETFIFO_Pop (void * const element); +extern bool SOCKETFIFO_Peek (void * const element); +extern bool SOCKETFIFO_IsEmpty (void); +extern bool SOCKETFIFO_IsFull (void); +extern void SOCKETFIFO_Flush (void); +extern unsigned int SOCKETFIFO_Count (void); + +#endif // MICROPY_INCLUDED_CC3200_UTIL_SOCKETFIFO_H diff --git a/src/openmv/src/micropython/ports/cc3200/version.h b/src/openmv/src/micropython/ports/cc3200/version.h new file mode 100755 index 0000000..fccb95c --- /dev/null +++ b/src/openmv/src/micropython/ports/cc3200/version.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_CC3200_VERSION_H +#define MICROPY_INCLUDED_CC3200_VERSION_H + +#define WIPY_SW_VERSION_NUMBER "1.2.0" + +#endif // MICROPY_INCLUDED_CC3200_VERSION_H diff --git a/src/openmv/src/micropython/ports/esp32/Makefile b/src/openmv/src/micropython/ports/esp32/Makefile new file mode 100755 index 0000000..39ecced --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/Makefile @@ -0,0 +1,845 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +MICROPY_PY_USSL = 0 +MICROPY_SSL_AXTLS = 0 +MICROPY_FATFS = 1 +MICROPY_PY_BTREE = 1 + +#FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + +# include py core make definitions +include $(TOP)/py/py.mk + +PORT ?= /dev/ttyUSB0 +BAUD ?= 460800 +FLASH_MODE ?= dio +FLASH_FREQ ?= 40m +FLASH_SIZE ?= 4MB +CROSS_COMPILE ?= xtensa-esp32-elf- + +ESPIDF_SUPHASH := 30545f4cccec7460634b656d278782dd7151098e + +# paths to ESP IDF and its components +ifeq ($(ESPIDF),) +ifneq ($(IDF_PATH),) +ESPIDF = $(IDF_PATH) +else +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +$(error ESPIDF not set) +endif +endif +ESPCOMP = $(ESPIDF)/components +ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py + +# verify the ESP IDF version +ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') +ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) +$(info ** WARNING **) +$(info The git hash of ESP IDF does not match the supported version) +$(info The build may complete and the firmware may work but it is not guaranteed) +$(info ESP IDF path: $(ESPIDF)) +$(info Current git hash: $(ESPIDF_CURHASH)) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +endif + +# pretty format of ESP IDF version, used internally by the IDF +IDF_VER := $(shell git -C $(ESPIDF) describe) + +INC += -I. +INC += -I$(TOP) +INC += -I$(TOP)/lib/mp-readline +INC += -I$(TOP)/lib/netutils +INC += -I$(TOP)/lib/timeutils +INC += -I$(BUILD) + +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader +INC_ESPCOMP += -I$(ESPCOMP)/driver/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/expat/expat/lib +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/heap/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/log/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/include +INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/ulp/include +INC_ESPCOMP += -I$(ESPCOMP)/vfs/include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include +INC_ESPCOMP += -I$(ESPCOMP)/pthread/include +INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include + +# these flags are common to C and C++ compilation +CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ + -mlongcalls -nostdlib \ + -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable -Wno-error=deprecated-declarations \ + -DESP_PLATFORM + +CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H +CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) +CFLAGS += -DIDF_VER=\"$(IDF_VER)\" +CFLAGS += $(CFLAGS_MOD) + +# this is what ESPIDF uses for c++ compilation +CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) + +LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref +LDFLAGS += --gc-sections -static -EL +LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl +LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a +LDFLAGS += -L$(ESPCOMP)/esp32/ld +LDFLAGS += -T $(BUILD)/esp32_out.ld +LDFLAGS += -T ./esp32.custom_common.ld +LDFLAGS += -T esp32.rom.ld +LDFLAGS += -T esp32.peripherals.ld + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a) + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g +COPT = -O0 +else +#CFLAGS += -fdata-sections -ffunction-sections +COPT += -Os -DNDEBUG +#LDFLAGS += --gc-sections +endif + +# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=1 +ifeq ($(CONFIG_SPIRAM_SUPPORT),1) +CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_SUPPORT=1 +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a +else +LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a +endif + +################################################################################ +# List of MicroPython source and object files + +SRC_C = \ + main.c \ + uart.c \ + gccollect.c \ + mphalport.c \ + fatfs_port.c \ + help.c \ + modutime.c \ + moduos.c \ + machine_timer.c \ + machine_pin.c \ + machine_touchpad.c \ + machine_adc.c \ + machine_dac.c \ + machine_pwm.c \ + machine_uart.c \ + modmachine.c \ + modnetwork.c \ + network_lan.c \ + network_ppp.c \ + modsocket.c \ + modesp.c \ + esp32_ulp.c \ + modesp32.c \ + espneopixel.c \ + machine_hw_spi.c \ + machine_wdt.c \ + mpthreadport.c \ + machine_rtc.c \ + $(SRC_MOD) + +EXTMOD_SRC_C = $(addprefix extmod/,\ + modonewire.c \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/roundf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/unicode.c +endif + +DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + dht/dht.c \ + ) + +OBJ_MP = +OBJ_MP += $(PY_O) +OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) +# Append any auto-generated sources that are needed by sources listed in SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +################################################################################ +# List of object files from the ESP32 IDF components + +ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ + uart.o \ + periph_ctrl.o \ + ledc.o \ + gpio.o \ + timer.o \ + spi_master.o \ + spi_common.o \ + rtc_module.o \ + ) + +$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds +ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ + brownout.o \ + panic.o \ + esp_timer.o \ + esp_timer_esp32.o \ + ets_timer_legacy.o \ + event_default_handlers.o \ + fast_crypto_ops.o \ + task_wdt.o \ + cache_err_int.o \ + clk.o \ + core_dump.o \ + cpu_start.o \ + gdbstub.o \ + crosscore_int.o \ + ipc.o \ + int_wdt.o \ + event_loop.o \ + hwcrypto/sha.o \ + hwcrypto/aes.o \ + lib_printf.o \ + freertos_hooks.o \ + system_api.o \ + hw_random.o \ + phy_init.o \ + intr_alloc.o \ + dport_access.o \ + wifi_init.o \ + wifi_os_adapter.o \ + sleep_modes.o \ + spiram.o \ + spiram_psram.o \ + ) + +ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ + heap_caps.o \ + heap_caps_init.o \ + multi_heap.o \ + ) + +ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ + esp32/cpu_util.o \ + esp32/gpio_periph.o \ + esp32/rtc_clk.o \ + esp32/rtc_init.o \ + esp32/rtc_periph.o \ + esp32/rtc_pm.o \ + esp32/rtc_sleep.o \ + esp32/rtc_time.o \ + esp32/soc_memory_layout.o \ + esp32/spi_periph.o \ + src/memory_layout_utils.o \ + ) + +ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ + cxx_guards.o \ + ) + +ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\ + emac_dev.o \ + emac_main.o \ + eth_phy/phy_tlk110.o \ + eth_phy/phy_lan8720.o \ + eth_phy/phy_common.o \ + ) + +$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -DHAVE_EXPAT_CONFIG_H -DHAVE_GETRANDOM +ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\ + expat/expat/lib/xmltok_ns.o \ + expat/expat/lib/xmltok.o \ + expat/expat/lib/xmlparse.o \ + expat/expat/lib/xmlrole.o \ + expat/expat/lib/xmltok_impl.o \ + ) + +ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ + pthread.o \ + pthread_local_storage.o \ + ) + +# Assembler .S files need only basic flags, and in particular should not have +# -Os because that generates subtly different code. +# We also need custom CFLAGS for .c files because FreeRTOS has headers with +# generic names (eg queue.h) which can clash with other files in the port. +CFLAGS_ASM = -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. +$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL +ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ + croutine.o \ + event_groups.o \ + FreeRTOS-openocd.o \ + list.o \ + portasm.o \ + port.o \ + queue.o \ + ringbuf.o \ + tasks.o \ + timers.o \ + xtensa_context.o \ + xtensa_init.o \ + xtensa_intr_asm.o \ + xtensa_intr.o \ + xtensa_overlay_os_hook.o \ + xtensa_vector_defaults.o \ + xtensa_vectors.o \ + ) + +ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ + vfs_uart.o \ + vfs.o \ + ) + +ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\ + cJSON.o \ + cJSON_Utils.o \ + ) + +ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ + log.o \ + ) + +ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\ + eri.o \ + trax.o \ + ) + +ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\ + tcpip_adapter_lwip.o \ + ) + +ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ + app_trace.o \ + ) + +ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ + esp_ota_ops.o \ + ) + +ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ + time.o \ + select.o \ + syscalls.o \ + syscall_table.o \ + reent_init.o \ + locks.o \ + ) + +ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\ + nghttp2/lib/nghttp2_http.o \ + nghttp2/lib/nghttp2_version.o \ + nghttp2/lib/nghttp2_mem.o \ + nghttp2/lib/nghttp2_hd_huffman.o \ + nghttp2/lib/nghttp2_rcbuf.o \ + nghttp2/lib/nghttp2_callbacks.o \ + nghttp2/lib/nghttp2_session.o \ + nghttp2/lib/nghttp2_stream.o \ + nghttp2/lib/nghttp2_hd.o \ + nghttp2/lib/nghttp2_priority_spec.o \ + nghttp2/lib/nghttp2_buf.o \ + nghttp2/lib/nghttp2_option.o \ + nghttp2/lib/nghttp2_npn.o \ + nghttp2/lib/nghttp2_helper.o \ + nghttp2/lib/nghttp2_frame.o \ + nghttp2/lib/nghttp2_outbound_item.o \ + nghttp2/lib/nghttp2_hd_huffman_data.o \ + nghttp2/lib/nghttp2_pq.o \ + nghttp2/lib/nghttp2_queue.o \ + nghttp2/lib/nghttp2_submit.o \ + nghttp2/lib/nghttp2_map.o \ + port/http_parser.o \ + ) + +ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ + src/nvs_types.o \ + src/nvs_page.o \ + src/nvs_item_hash_list.o \ + src/nvs_pagemanager.o \ + src/nvs_storage.o \ + src/nvs_api.o \ + ) + +ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\ + ) + +ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\ + smartconfig_ack.o \ + ) + +ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ + flash_mmap.o \ + partition.o \ + spi_flash_rom_patch.o \ + cache_utils.o \ + flash_ops.o \ + ) + +ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\ + ulp.o \ + ) + +$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable +ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ + api/pppapi.o \ + api/netbuf.o \ + api/api_lib.o \ + api/netifapi.o \ + api/tcpip.o \ + api/netdb.o \ + api/err.o \ + api/api_msg.o \ + api/sockets.o \ + apps/sntp/sntp.o \ + apps/dhcpserver.o \ + core/ipv4/ip_frag.o \ + core/ipv4/dhcp.o \ + core/ipv4/ip4_addr.o \ + core/ipv4/igmp.o \ + core/ipv4/ip4.o \ + core/ipv4/autoip.o \ + core/ipv4/icmp.o \ + core/ipv6/ip6_frag.o \ + core/ipv6/dhcp6.o \ + core/ipv6/inet6.o \ + core/ipv6/ip6_addr.o \ + core/ipv6/ip6.o \ + core/ipv6/nd6.o \ + core/ipv6/mld6.o \ + core/ipv6/ethip6.o \ + core/ipv6/icmp6.o \ + core/mem.o \ + core/init.o \ + core/memp.o \ + core/sys.o \ + core/tcp_in.o \ + core/dns.o \ + core/ip.o \ + core/pbuf.o \ + core/raw.o \ + core/tcp.o \ + core/def.o \ + core/netif.o \ + core/stats.o \ + core/timers.o \ + core/inet_chksum.o \ + core/udp.o \ + core/tcp_out.o \ + netif/slipif.o \ + netif/etharp.o \ + netif/ethernet.o \ + netif/lowpan6.o \ + netif/ethernetif.o \ + netif/ppp/ppp.o \ + netif/ppp/magic.o \ + netif/ppp/lcp.o \ + netif/ppp/ipcp.o \ + netif/ppp/auth.o \ + netif/ppp/fsm.o \ + netif/ppp/ipv6cp.o \ + netif/ppp/utils.o \ + netif/ppp/vj.o \ + netif/ppp/pppos.o \ + port/freertos/sys_arch.o \ + port/netif/wlanif.o \ + port/netif/ethernetif.o \ + port/vfs_lwip.o \ + ) + +ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ + mbedtls/library/entropy.o \ + mbedtls/library/pkcs12.o \ + mbedtls/library/ccm.o \ + mbedtls/library/pk.o \ + mbedtls/library/sha1.o \ + mbedtls/library/x509_csr.o \ + mbedtls/library/ssl_cli.o \ + mbedtls/library/ecp.o \ + mbedtls/library/blowfish.o \ + mbedtls/library/x509.o \ + mbedtls/library/ecp_curves.o \ + mbedtls/library/error.o \ + mbedtls/library/ssl_ticket.o \ + mbedtls/library/entropy_poll.o \ + mbedtls/library/cipher.o \ + mbedtls/library/version_features.o \ + mbedtls/library/ripemd160.o \ + mbedtls/library/rsa.o \ + mbedtls/library/rsa_internal.o \ + mbedtls/library/md.o \ + mbedtls/library/md_wrap.o \ + mbedtls/library/sha256.o \ + mbedtls/library/dhm.o \ + mbedtls/library/ssl_cache.o \ + mbedtls/library/pkwrite.o \ + mbedtls/library/base64.o \ + mbedtls/library/asn1parse.o \ + mbedtls/library/ssl_tls.o \ + mbedtls/library/hmac_drbg.o \ + mbedtls/library/pem.o \ + mbedtls/library/version.o \ + mbedtls/library/gcm.o \ + mbedtls/library/memory_buffer_alloc.o \ + mbedtls/library/md2.o \ + mbedtls/library/ecdsa.o \ + mbedtls/library/ssl_srv.o \ + mbedtls/library/x509_crt.o \ + mbedtls/library/ecdh.o \ + mbedtls/library/asn1write.o \ + mbedtls/library/md4.o \ + mbedtls/library/debug.o \ + mbedtls/library/x509_create.o \ + mbedtls/library/ecjpake.o \ + mbedtls/library/oid.o \ + mbedtls/library/md5.o \ + mbedtls/library/ssl_ciphersuites.o \ + mbedtls/library/sha512.o \ + mbedtls/library/xtea.o \ + mbedtls/library/aes.o \ + mbedtls/library/cipher_wrap.o \ + mbedtls/library/arc4.o \ + mbedtls/library/bignum.o \ + mbedtls/library/pkparse.o \ + mbedtls/library/padlock.o \ + mbedtls/library/threading.o \ + mbedtls/library/x509_crl.o \ + mbedtls/library/pkcs11.o \ + mbedtls/library/aesni.o \ + mbedtls/library/timing.o \ + mbedtls/library/certs.o \ + mbedtls/library/pkcs5.o \ + mbedtls/library/ssl_cookie.o \ + mbedtls/library/camellia.o \ + mbedtls/library/havege.o \ + mbedtls/library/des.o \ + mbedtls/library/x509write_csr.o \ + mbedtls/library/platform.o \ + mbedtls/library/platform_util.o \ + mbedtls/library/ctr_drbg.o \ + mbedtls/library/x509write_crt.o \ + mbedtls/library/pk_wrap.o \ + port/esp_bignum.o \ + port/esp_hardware.o \ + port/esp_sha1.o \ + port/esp_sha256.o \ + port/esp_sha512.o \ + ) + +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing +ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ + src/crypto/aes-internal-enc.o \ + src/crypto/sha256-internal.o \ + src/crypto/md5-internal.o \ + src/crypto/aes-internal.o \ + src/crypto/sha1.o \ + src/crypto/aes-internal-dec.o \ + src/crypto/aes-unwrap.o \ + src/crypto/crypto_internal-rsa.o \ + src/crypto/dh_groups.o \ + src/crypto/crypto_internal.o \ + src/crypto/aes-wrap.o \ + src/crypto/sha1-internal.o \ + src/crypto/dh_group5.o \ + src/crypto/sha256.o \ + src/crypto/rc4.o \ + src/crypto/md5.o \ + src/crypto/aes-cbc.o \ + src/crypto/sha1-pbkdf2.o \ + src/crypto/bignum.o \ + src/crypto/crypto_internal-modexp.o \ + src/crypto/crypto_internal-cipher.o \ + src/fast_crypto/fast_aes-unwrap.o \ + src/fast_crypto/fast_aes-wrap.o \ + src/fast_crypto/fast_sha256.o \ + src/fast_crypto/fast_sha256-internal.o \ + port/os_xtensa.o \ + ) + +OBJ_ESPIDF = +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ETHERNET_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EXPAT_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_PTHREAD_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_FREERTOS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_VFS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_JSON_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LOG_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LWIP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +################################################################################ +# Main targets + +all: $(BUILD)/firmware.bin + +.PHONY: idf-version deploy erase + +idf-version: + $(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)" + +$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin + $(ECHO) "Create $@" + $(Q)$(PYTHON) makeimg.py $^ $@ + +deploy: $(BUILD)/firmware.bin + $(ECHO) "Writing $^ to the board" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^ + +erase: + $(ECHO) "Erasing flash" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash + +################################################################################ +# Declarations to build the application + +OBJ = $(OBJ_MP) $(OBJ_ESPIDF) + +APP_LD_ARGS = +APP_LD_ARGS += $(LDFLAGS_MOD) +APP_LD_ARGS += --start-group +APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ +APP_LD_ARGS += $(LIBC_LIBM) +APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a +APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 +APP_LD_ARGS += $(OBJ) +APP_LD_ARGS += --end-group + +$(BUILD)/esp32_out.ld: sdkconfig.h + $(Q)$(CC) -I. -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ + +$(BUILD)/application.bin: $(BUILD)/application.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/application.elf: $(OBJ) $(BUILD)/esp32_out.ld + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) + $(Q)$(SIZE) $@ + +define compile_cxx +$(ECHO) "CXX $<" +$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.cpp . $(TOP) +$(BUILD)/%.o: %.cpp + $(call compile_cxx) + +################################################################################ +# Declarations to build the bootloader + +BOOTLOADER_LIB_DIR = $(BUILD)/bootloader +BOOTLOADER_LIB_ALL = + +$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format + +# libbootloader_support.a +BOOTLOADER_LIB_ALL += bootloader_support +BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_clock.o \ + bootloader_support/src/bootloader_common.o \ + bootloader_support/src/bootloader_flash.o \ + bootloader_support/src/bootloader_init.o \ + bootloader_support/src/bootloader_random.o \ + bootloader_support/src/bootloader_sha.o \ + bootloader_support/src/bootloader_utility.o \ + bootloader_support/src/efuse.o \ + bootloader_support/src/flash_qio_mode.o \ + bootloader_support/src/secure_boot_signatures.o \ + bootloader_support/src/secure_boot.o \ + bootloader_support/src/esp_image_format.o \ + bootloader_support/src/flash_encrypt.o \ + bootloader_support/src/flash_partitions.o \ + ) +$(BOOTLOADER_LIB_DIR)/libbootloader_support.a: $(BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ + +# liblog.a +BOOTLOADER_LIB_ALL += log +BOOTLOADER_LIB_LOG_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + log/log.o \ + ) +$(BOOTLOADER_LIB_DIR)/liblog.a: $(BOOTLOADER_LIB_LOG_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ + +# libspi_flash.a +BOOTLOADER_LIB_ALL += spi_flash +BOOTLOADER_LIB_SPI_FLASH_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + spi_flash/spi_flash_rom_patch.o \ + ) +$(BOOTLOADER_LIB_DIR)/libspi_flash.a: $(BOOTLOADER_LIB_SPI_FLASH_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ + +# libmicro-ecc.a +BOOTLOADER_LIB_ALL += micro-ecc +BOOTLOADER_LIB_MICRO_ECC_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + micro-ecc/micro-ecc/uECC.o \ + ) +$(BOOTLOADER_LIB_DIR)/libmicro-ecc.a: $(BOOTLOADER_LIB_MICRO_ECC_OBJ) + $(ECHO) "AR $@" + $(Q)$(AR) cr $@ $^ + +# remaining object files +BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + soc/esp32/rtc_clk.o \ + soc/esp32/rtc_time.o \ + soc/esp32/cpu_util.o \ + bootloader/subproject/main/bootloader_start.o \ + ) + +# all objects files +BOOTLOADER_OBJ_ALL = \ + $(BOOTLOADER_LIB_BOOTLOADER_SUPPORT_OBJ) \ + $(BOOTLOADER_LIB_LOG_OBJ) \ + $(BOOTLOADER_LIB_SPI_FLASH_OBJ) \ + $(BOOTLOADER_LIB_MICRO_ECC_OBJ) \ + $(BOOTLOADER_OBJ) + +BOOTLOADER_LIBS = +BOOTLOADER_LIBS += -Wl,--start-group +BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) +BOOTLOADER_LIBS += -L$(BUILD)/bootloader $(addprefix -l,$(BOOTLOADER_LIB_ALL)) +BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc +BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +BOOTLOADER_LIBS += -Wl,--end-group + +BOOTLOADER_LDFLAGS = +BOOTLOADER_LDFLAGS += -nostdlib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld +BOOTLOADER_LDFLAGS += -u call_user_start_cpu0 +BOOTLOADER_LDFLAGS += -Wl,--gc-sections +BOOTLOADER_LDFLAGS += -static +BOOTLOADER_LDFLAGS += -Wl,-EL +BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld + +BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ_ALL))) +$(BOOTLOADER_OBJ_ALL): | $(BOOTLOADER_OBJ_DIRS) +$(BOOTLOADER_OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/bootloader/%.o: %.c + $(call compile_c) + +$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) $(addprefix $(BOOTLOADER_LIB_DIR)/lib,$(addsuffix .a,$(BOOTLOADER_LIB_ALL))) + $(ECHO) "LINK $@" + $(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS) + +################################################################################ +# Declarations to build the partitions + +PYTHON2 ?= python2 +PART_SRC = partitions.csv + +$(BUILD)/partitions.bin: $(PART_SRC) + $(ECHO) "Create $@" + $(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@ + +################################################################################ + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/esp32/README.md b/src/openmv/src/micropython/ports/esp32/README.md new file mode 100755 index 0000000..85df001 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/README.md @@ -0,0 +1,202 @@ +MicroPython port to the ESP32 +============================= + +This is an experimental port of MicroPython to the Espressif ESP32 +microcontroller. It uses the ESP-IDF framework and MicroPython runs as +a task under FreeRTOS. + +Supported features include: +- REPL (Python prompt) over UART0. +- 16k stack for the MicroPython task and 96k Python heap. +- Many of MicroPython's features are enabled: unicode, arbitrary-precision + integers, single-precision floats, complex numbers, frozen bytecode, as + well as many of the internal modules. +- Internal filesystem using the flash (currently 2M in size). +- The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM, + TouchPad, WDT and Timer. +- The network module with WLAN (WiFi) support. + +Development of this ESP32 port was sponsored in part by Microbric Pty Ltd. + +Setting up the toolchain and ESP-IDF +------------------------------------ + +There are two main components that are needed to build the firmware: +- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is + different to the compiler used by the ESP8266) +- the Espressif IDF (IoT development framework, aka SDK) + +The ESP-IDF changes quickly and MicroPython only supports a certain version. The +git hash of this version can be found by running `make` without a configured +`ESPIDF`. Then you can fetch only the given esp-idf using the following command: + + $ git clone https://github.com/espressif/esp-idf.git + $ git checkout + $ git submodule update --init --recursive + +The binary toolchain (binutils, gcc, etc.) can be installed using the following +guides: + + * [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) + * [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html) + * [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html) + +If you are on a Windows machine then the +[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) +is the most efficient way to install the ESP32 toolchain and build the project. +If you use WSL then follow the +[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) +for the ESP-IDF instead of the Windows ones. + +The Espressif ESP-IDF instructions above only install pyserial for Python 2, +so if you're running Python 3 or a non-system Python you'll also need to +install `pyserial` (or `esptool`) so that the Makefile can flash the board +and set parameters: +```bash +$ pip install pyserial +``` + +Once everything is set up you should have a functioning toolchain with +prefix xtensa-esp32-elf- (or otherwise if you configured it differently) +as well as a copy of the ESP-IDF repository. You will need to update your `PATH` +environment variable to include the ESP32 toolchain. For example, you can issue +the following commands on (at least) Linux: + + $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin + +You can put this command in your `.profile` or `.bash_login`. + +You then need to set the `ESPIDF` environment/makefile variable to point to +the root of the ESP-IDF repository. You can set the variable in your PATH, +or at the command line when calling make, or in your own custom `makefile`. +The last option is recommended as it allows you to easily configure other +variables for the build. In that case, create a new file in the esp32 +directory called `makefile` and add the following lines to that file: +``` +ESPIDF = +#PORT = /dev/ttyUSB0 +#FLASH_MODE = qio +#FLASH_SIZE = 4MB +#CROSS_COMPILE = xtensa-esp32-elf- +#CONFIG_SPIRAM_SUPPORT = 1 + +include Makefile +``` +Be sure to enter the correct path to your local copy of the IDF repository +(and use `$(HOME)`, not tilde, to reference your home directory). +If your filesystem is case-insensitive then you'll need to use `GNUmakefile` +instead of `makefile`. +If the Xtensa cross-compiler is not in your path you can use the +`CROSS_COMPILE` variable to set its location. Other options of interest +are `PORT` for the serial port of your esp32 module, and `FLASH_MODE` +(which may need to be `dio` for some modules) +and `FLASH_SIZE`. See the Makefile for further information. + +Building the firmware +--------------------- + +The MicroPython cross-compiler must be built to pre-compile some of the +built-in scripts to bytecode. This can be done by (from the root of +this repository): +```bash +$ make -C mpy-cross +``` + +The ESP32 port has a dependency on Berkeley DB, which is an external +dependency (git submodule). You'll need to have git initialize that +module using the commands: +```bash +$ git submodule init lib/berkeley-db-1.xx +$ git submodule update +``` + +Then to build MicroPython for the ESP32 run: +```bash +$ cd ports/esp32 +$ make +``` +This will produce binary firmware images in the `build/` subdirectory +(three of them: bootloader.bin, partitions.bin and application.bin). + +To flash the firmware you must have your ESP32 module in the bootloader +mode and connected to a serial port on your PC. Refer to the documentation +for your particular ESP32 module for how to do this. The serial port and +flash settings are set in the `Makefile`, and can be overridden in your +local `makefile`; see above for more details. + +You will also need to have user permissions to access the /dev/ttyUSB0 device. +On Linux, you can enable this by adding your user to the `dialout` group, +and rebooting or logging out and in again. +```bash +$ sudo adduser dialout +``` + +If you are installing MicroPython to your module for the first time, or +after installing any other firmware, you should first erase the flash +completely: +```bash +$ make erase +``` + +To flash the MicroPython firmware to your ESP32 use: +```bash +$ make deploy +``` +This will use the `esptool.py` script (provided by ESP-IDF) to download the +binary images. + +Getting a Python prompt +----------------------- + +You can get a prompt via the serial port, via UART0, which is the same UART +that is used for programming the firmware. The baudrate for the REPL is +115200 and you can use a command such as: +```bash +$ picocom -b 115200 /dev/ttyUSB0 +``` + +Configuring the WiFi and using the board +---------------------------------------- + +The ESP32 port is designed to be (almost) equivalent to the ESP8266 in +terms of the modules and user-facing API. There are some small differences, +notably that the ESP32 does not automatically connect to the last access +point when booting up. But for the most part the documentation and tutorials +for the ESP8266 should apply to the ESP32 (at least for the components that +are implemented). + +See http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html for +a quick reference, and http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html +for a tutorial. + +The following function can be used to connect to a WiFi access point (you can +either pass in your own SSID and password, or change the defaults so you can +quickly call `wlan_connect()` and it just works): +```python +def wlan_connect(ssid='MYSSID', password='MYPASS'): + import network + wlan = network.WLAN(network.STA_IF) + if not wlan.active() or not wlan.isconnected(): + wlan.active(True) + print('connecting to:', ssid) + wlan.connect(ssid, password) + while not wlan.isconnected(): + pass + print('network config:', wlan.ifconfig()) +``` + +Note that some boards require you to configure the WiFi antenna before using +the WiFi. On Pycom boards like the LoPy and WiPy 2.0 you need to execute the +following code to select the internal antenna (best to put this line in your +boot.py file): +```python +import machine +antenna = machine.Pin(16, machine.Pin.OUT, value=0) +``` + +Troubleshooting +--------------- + +* Continuous reboots after programming: Ensure FLASH_MODE is correct for your + board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild, + redeploy. diff --git a/src/openmv/src/micropython/ports/esp32/README.ulp.md b/src/openmv/src/micropython/ports/esp32/README.ulp.md new file mode 100755 index 0000000..cbc5771 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/README.ulp.md @@ -0,0 +1,126 @@ +# ULP + +To compile binarys for the ulp you need the ulp toolkit. Download it from https://github.com/espressif/binutils-esp32ulp/wiki#downloads +Then extract it, then add ```esp32ulp-elf-binutils/bin``` to your PATH + +## Example Makefile + +```make +ULP_S_SOURCES := main.S +ULP_APP_NAME := test +ULP_LD_SCRIPT := esp32.ulp.ld + +SRC_PATH := src +BUILD_PATH := build + +include $(ESPIDF)/components/ulp/Makefile.projbuild + +ULP_ELF := $(ULP_APP_NAME).elf +ULP_MAP := $(ULP_ELF:.elf=.map) +ULP_SYM := $(ULP_ELF:.elf=.sym) +ULP_BIN := $(ULP_ELF:.elf=.bin) +ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld) +ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h) + +ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o)) +ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d) +ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS)) +ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst)) + +.PHONY: all clean + +all: $(BUILD_PATH) $(BUILD_PATH)/$(ULP_BIN) + +clean: + rm -rf $(BUILD_PATH) + +$(BUILD_PATH): + mkdir $@ + +# Generate preprocessed linker file. +$(BUILD_PATH)/$(ULP_APP_NAME).ld: $(SRC_PATH)/$(ULP_LD_SCRIPT) + cpp -P $< -o $@ + +# Generate preprocessed assembly files. +# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule. +$(BUILD_PATH)/%.ulp.pS: $(SRC_PATH)/%.S + cpp $< -o $@ + +# Compiled preprocessed files into object files. +$(BUILD_PATH)/%.ulp.o: $(BUILD_PATH)/%.ulp.pS + $(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $< + +# Link object files and generate map file +$(BUILD_PATH)/$(ULP_ELF): $(BUILD_PATH)/$(ULP_OBJECTS) $(BUILD_PATH)/$(ULP_APP_NAME).ld + $(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(BUILD_PATH)/$(ULP_MAP) -T $(BUILD_PATH)/$(ULP_APP_NAME).ld $< + +# Dump the list of global symbols in a convenient format. +$(ULP_SYM): $(ULP_ELF) + $(ULP_NM) -g -f posix $< > $@ + +# Dump the binary for inclusion into the project +$(BUILD_PATH)/$(ULP_BIN): $(BUILD_PATH)/$(ULP_ELF) + $(ULP_OBJCOPY) -O binary $< $@ +``` + +## Example linker script for the ulp +``` +#define ULP_BIN_MAGIC 0x00706c75 +#define HEADER_SIZE 12 +#define CONFIG_ULP_COPROC_RESERVE_MEM 4096 + +MEMORY +{ + ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM +} + +SECTIONS +{ + .text : AT(HEADER_SIZE) + { + *(.text) + } >ram + .data : + { + . = ALIGN(4); + *(.data) + } >ram + .bss : + { + . = ALIGN(4); + *(.bss) + } >ram + + .header : AT(0) + { + LONG(ULP_BIN_MAGIC) + SHORT(LOADADDR(.text)) + SHORT(SIZEOF(.text)) + SHORT(SIZEOF(.data)) + SHORT(SIZEOF(.bss)) + } +} +``` + +## Example ulp code +```asm +move R3, 99 +move R0, 10 + +# mem[R0+0] = R3 +st R3, R0, 0 + +HALT +``` + +## Example python code using the ulp +```python +import esp32 +import time + +u = esp32.ULP() +with open('test.bin', 'rb') as f: + b = f.read() +u.load_binary(0,b) +u.run(0) +``` diff --git a/src/openmv/src/micropython/ports/esp32/esp32.custom_common.ld b/src/openmv/src/micropython/ports/esp32/esp32.custom_common.ld new file mode 100755 index 0000000..9762c0d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/esp32.custom_common.ld @@ -0,0 +1,274 @@ +/* Default entry point: */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } > rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* This section holds data that should not be initialized at power up + and will be retained during deep sleep. The section located in + RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed + into this section. See the file "esp_attr.h" for more information. + */ + .rtc_noinit (NOLOAD): + { + . = ALIGN(4); + _rtc_noinit_start = ABSOLUTE(.); + *(.rtc_noinit .rtc_noinit.*) + . = ALIGN(4) ; + _rtc_noinit_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* Send .iram0 code to iram */ + .iram0.vectors : + { + _iram_start = ABSOLUTE(.); + /* Vectors go to IRAM */ + _init_start = ABSOLUTE(.); + /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ + . = 0x0; + KEEP(*(.WindowVectors.text)); + . = 0x180; + KEEP(*(.Level2InterruptVector.text)); + . = 0x1c0; + KEEP(*(.Level3InterruptVector.text)); + . = 0x200; + KEEP(*(.Level4InterruptVector.text)); + . = 0x240; + KEEP(*(.Level5InterruptVector.text)); + . = 0x280; + KEEP(*(.DebugExceptionVector.text)); + . = 0x2c0; + KEEP(*(.NMIExceptionVector.text)); + . = 0x300; + KEEP(*(.KernelExceptionVector.text)); + . = 0x340; + KEEP(*(.UserExceptionVector.text)); + . = 0x3C0; + KEEP(*(.DoubleExceptionVector.text)); + . = 0x400; + *(.*Vector.literal) + + *(.UserEnter.literal); + *(.UserEnter.text); + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + _init_end = ABSOLUTE(.); + } > iram0_0_seg + + .iram0.text : + { + /* Code marked as runnning out of IRAM */ + _iram_text_start = ABSOLUTE(.); + *(.iram1 .iram1.*) + *freertos/*(.literal .text .literal.* .text.*) + *heap/multi_heap.o(.literal .text .literal.* .text.*) + *heap/multi_heap_poisoning.o(.literal .text .literal.* .text.*) + *esp32/panic.o(.literal .text .literal.* .text.*) + *esp32/core_dump.o(.literal .text .literal.* .text.*) + *app_trace/*(.literal .text .literal.* .text.*) + *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) + *librtc.a:(.literal .text .literal.* .text.*) + *soc/esp32/rtc_*.o(.literal .text .literal.* .text.*) + *soc/esp32/cpu_util.o(.literal .text .literal.* .text.*) + *libhal.a:(.literal .text .literal.* .text.*) + *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*) + *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*) + *libgcov.a:(.literal .text .literal.* .text.*) + INCLUDE esp32.spiram.rom-functions-iram.ld + *py/scheduler.o*(.literal .text .literal.* .text.*) + _iram_text_end = ABSOLUTE(.); + _iram_end = ABSOLUTE(.); + } > iram0_0_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + _bt_data_start = ABSOLUTE(.); + *libbt.a:(.data .data.*) + . = ALIGN (4); + _bt_data_end = ABSOLUTE(.); + _btdm_data_start = ABSOLUTE(.); + *libbtdm_app.a:(.data .data.*) + . = ALIGN (4); + _btdm_data_end = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + *(.dram1 .dram1.*) + *esp32/panic.o(.rodata .rodata.*) + *libphy.a:(.rodata .rodata.*) + *soc/esp32/rtc_clk.o(.rodata .rodata.*) + *app_trace/app_trace.o(.rodata .rodata.*) + *libgcov.a:(.rodata .rodata.*) + *heap/multi_heap.o(.rodata .rodata.*) + *heap/multi_heap_poisoning.o(.rodata .rodata.*) + INCLUDE esp32.spiram.rom-functions-dram.ld + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } > dram0_0_seg + + /*This section holds data that should not be initialized at power up. + The section located in Internal SRAM memory region. The macro _NOINIT + can be used as attribute to place data into this section. + See the esp_attr.h file for more information. + */ + .noinit (NOLOAD): + { + . = ALIGN(4); + _noinit_start = ABSOLUTE(.); + *(.noinit .noinit.*) + . = ALIGN(4) ; + _noinit_end = ABSOLUTE(.); + } > dram0_0_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + _bt_bss_start = ABSOLUTE(.); + *libbt.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _bt_bss_end = ABSOLUTE(.); + _btdm_bss_start = ABSOLUTE(.); + *libbtdm_app.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _btdm_bss_end = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + /* The heap starts right after end of this section */ + _heap_start = ABSOLUTE(.); + } > dram0_0_seg + + .flash.rodata : + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + /* Addresses of memory regions reserved via + SOC_RESERVE_MEMORY_REGION() */ + soc_reserved_memory_region_start = ABSOLUTE(.); + KEEP (*(.reserved_memory_address)) + soc_reserved_memory_region_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(4); + } >drom0_0_seg + + .flash.text : + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + + /* Similar to _iram_start, this symbol goes here so it is + resolved by addr2line in preference to the first symbol in + the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } >iram0_2_seg +} diff --git a/src/openmv/src/micropython/ports/esp32/esp32_ulp.c b/src/openmv/src/micropython/ports/esp32/esp32_ulp.c new file mode 100755 index 0000000..3772639 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/esp32_ulp.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 "Andreas Valder" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "esp32/ulp.h" +#include "esp_err.h" + +typedef struct _esp32_ulp_obj_t { + mp_obj_base_t base; +} esp32_ulp_obj_t; + +const mp_obj_type_t esp32_ulp_type; + +// singleton ULP object +STATIC const esp32_ulp_obj_t esp32_ulp_obj = {{&esp32_ulp_type}}; + +STATIC mp_obj_t esp32_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&esp32_ulp_obj; +} + +STATIC mp_obj_t esp32_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index_in, mp_obj_t period_us_in) { + mp_uint_t period_index = mp_obj_get_int(period_index_in); + mp_uint_t period_us = mp_obj_get_int(period_us_in); + int _errno = ulp_set_wakeup_period(period_index, period_us); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_set_wakeup_period_obj, esp32_ulp_set_wakeup_period); + +STATIC mp_obj_t esp32_ulp_load_binary(mp_obj_t self_in, mp_obj_t load_addr_in, mp_obj_t program_binary_in) { + mp_uint_t load_addr = mp_obj_get_int(load_addr_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ); + + int _errno = ulp_load_binary(load_addr, bufinfo.buf, bufinfo.len/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_load_binary_obj, esp32_ulp_load_binary); + +STATIC mp_obj_t esp32_ulp_run(mp_obj_t self_in, mp_obj_t entry_point_in) { + mp_uint_t entry_point = mp_obj_get_int(entry_point_in); + int _errno = ulp_run(entry_point/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_ulp_run_obj, esp32_ulp_run); + +STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) }, + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) }, + { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table); + +const mp_obj_type_t esp32_ulp_type = { + { &mp_type_type }, + .name = MP_QSTR_ULP, + .make_new = esp32_ulp_make_new, + .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/espneopixel.c b/src/openmv/src/micropython/ports/esp32/espneopixel.c new file mode 100755 index 0000000..829c8b1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/espneopixel.c @@ -0,0 +1,53 @@ +// Original version from https://github.com/adafruit/Adafruit_NeoPixel +// Modifications by dpgeorge to support auto-CPU-frequency detection + +// This is a mash-up of the Due show() code + insights from Michael Miller's +// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus +// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "modesp.h" + +void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) { + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime, pinMask; + + pinMask = 1 << pin; + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + + uint32_t fcpu = ets_get_cpu_frequency() * 1000000; + + if (timing == 1) { + // 800 KHz + time0 = (fcpu * 0.35) / 1000000; // 0.35us + time1 = (fcpu * 0.8) / 1000000; // 0.8us + period = (fcpu * 1.25) / 1000000; // 1.25us per bit + } else { + // 400 KHz + time0 = (fcpu * 0.5) / 1000000; // 0.35us + time1 = (fcpu * 1.2) / 1000000; // 0.8us + period = (fcpu * 2.5) / 1000000; // 1.25us per bit + } + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + for (t = time0;; t = time0) { + if (pix & mask) t = time1; // Bit high duration + while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start + GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high + startTime = c; // Save start time + while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration + GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low + if (!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit + mp_hal_quiet_timing_exit(irq_state); +} diff --git a/src/openmv/src/micropython/ports/esp32/esponewire.c b/src/openmv/src/micropython/ports/esp32/esponewire.c new file mode 100755 index 0000000..781616c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/esponewire.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "esp8266/esponewire.h" + +#define TIMING_RESET1 (0) +#define TIMING_RESET2 (1) +#define TIMING_RESET3 (2) +#define TIMING_READ1 (3) +#define TIMING_READ2 (4) +#define TIMING_READ3 (5) +#define TIMING_WRITE1 (6) +#define TIMING_WRITE2 (7) +#define TIMING_WRITE3 (8) + +uint16_t esp_onewire_timings[9] = {480, 40, 420, 5, 5, 40, 10, 50, 10}; + +#define DELAY_US mp_hal_delay_us_fast + +int esp_onewire_reset(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_RESET1]); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_RESET2]); + int status = !mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_RESET3]); + return status; +} + +int esp_onewire_readbit(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 1); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_READ1]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_READ2]); + int value = mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_READ3]); + return value; +} + +void esp_onewire_writebit(mp_hal_pin_obj_t pin, int value) { + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_WRITE1]); + if (value) { + mp_hal_pin_write(pin, 1); + } + DELAY_US(esp_onewire_timings[TIMING_WRITE2]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_WRITE3]); + MICROPY_END_ATOMIC_SECTION(i); +} diff --git a/src/openmv/src/micropython/ports/esp32/fatfs_port.c b/src/openmv/src/micropython/ports/esp32/fatfs_port.c new file mode 100755 index 0000000..880324e --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/fatfs_port.c @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "lib/oofatfs/ff.h" +#include "timeutils.h" + +DWORD get_fattime(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | + ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); +} diff --git a/src/openmv/src/micropython/ports/esp32/gccollect.c b/src/openmv/src/micropython/ports/esp32/gccollect.c new file mode 100755 index 0000000..9843cef --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/gccollect.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" +#include "soc/cpu.h" +#include "xtensa/hal.h" + + +static void gc_collect_inner(int level) { + if (level < XCHAL_NUM_AREGS / 8) { + gc_collect_inner(level + 1); + if (level != 0) { + return; + } + } + + if (level == XCHAL_NUM_AREGS / 8) { + // get the sp + volatile uint32_t sp = (uint32_t)get_sp(); + gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + return; + } + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif +} + +void gc_collect(void) { + gc_collect_start(); + gc_collect_inner(0); + gc_collect_end(); +} diff --git a/src/openmv/src/micropython/ports/esp32/gccollect.h b/src/openmv/src/micropython/ports/esp32/gccollect.h new file mode 100755 index 0000000..fe02cc6 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/gccollect.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +extern uint32_t _text_start; +extern uint32_t _text_end; +extern uint32_t _irom0_text_start; +extern uint32_t _irom0_text_end; +extern uint32_t _data_start; +extern uint32_t _data_end; +extern uint32_t _rodata_start; +extern uint32_t _rodata_end; +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern uint32_t _heap_start; +extern uint32_t _heap_end; + +void gc_collect(void); diff --git a/src/openmv/src/micropython/ports/esp32/help.c b/src/openmv/src/micropython/ports/esp32/help.c new file mode 100755 index 0000000..95d115c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/help.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char esp32_help_text[] = +"Welcome to MicroPython on the ESP32!\n" +"\n" +"For generic online docs please visit http://docs.micropython.org/\n" +"\n" +"For access to the hardware use the 'machine' module:\n" +"\n" +"import machine\n" +"pin12 = machine.Pin(12, machine.Pin.OUT)\n" +"pin12.value(1)\n" +"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n" +"print(pin13.value())\n" +"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n" +"i2c.scan()\n" +"i2c.writeto(addr, b'1234')\n" +"i2c.readfrom(addr, 4)\n" +"\n" +"Basic WiFi configuration:\n" +"\n" +"import network\n" +"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n" +"sta_if.scan() # Scan for available access points\n" +"sta_if.connect(\"\", \"\") # Connect to an AP\n" +"sta_if.isconnected() # Check for successful connection\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +"For a list of available modules, type help('modules')\n" +; diff --git a/src/openmv/src/micropython/ports/esp32/machine_adc.c b/src/openmv/src/micropython/ports/esp32/machine_adc.c new file mode 100755 index 0000000..d62f362 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_adc.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/adc.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _madc_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + adc1_channel_t adc1_id; +} madc_obj_t; + +STATIC const madc_obj_t madc_obj[] = { + {{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0}, + {{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1}, + {{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2}, + {{&machine_adc_type}, GPIO_NUM_39, ADC1_CHANNEL_3}, + {{&machine_adc_type}, GPIO_NUM_32, ADC1_CHANNEL_4}, + {{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5}, + {{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6}, + {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7}, +}; + +STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + static int initialized = 0; + if (!initialized) { + adc1_config_width(ADC_WIDTH_12Bit); + initialized = 1; + } + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const madc_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) { + if (pin_id == madc_obj[i].gpio_id) { self = &madc_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for ADC"); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + madc_obj_t *self = self_in; + mp_printf(print, "ADC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t madc_read(mp_obj_t self_in) { + madc_obj_t *self = self_in; + int val = adc1_get_raw(self->adc1_id); + if (val == -1) mp_raise_ValueError("Parameter Error"); + return MP_OBJ_NEW_SMALL_INT(val); +} +MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read); + +STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) { + madc_obj_t *self = self_in; + adc_atten_t atten = mp_obj_get_int(atten_in); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten); + +STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { + adc_bits_width_t width = mp_obj_get_int(width_in); + esp_err_t err = adc1_config_width(width); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_width_fun_obj, madc_width); +MP_DEFINE_CONST_CLASSMETHOD_OBJ(madc_width_obj, MP_ROM_PTR(&madc_width_fun_obj)); + +STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&madc_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) }, + + { MP_ROM_QSTR(MP_QSTR_ATTN_0DB), MP_ROM_INT(ADC_ATTEN_0db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_2_5DB), MP_ROM_INT(ADC_ATTEN_2_5db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) }, + + { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, +}; + +STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = madc_print, + .make_new = madc_make_new, + .locals_dict = (mp_obj_t)&madc_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_dac.c b/src/openmv/src/micropython/ports/esp32/machine_dac.c new file mode 100755 index 0000000..bd0804e --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_dac.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/dac.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mdac_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + dac_channel_t dac_id; +} mdac_obj_t; + +STATIC const mdac_obj_t mdac_obj[] = { + {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1}, + {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2}, +}; + +STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mdac_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(mdac_obj); i++) { + if (pin_id == mdac_obj[i].gpio_id) { self = &mdac_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for DAC"); + + esp_err_t err = dac_output_enable(self->dac_id); + if (err == ESP_OK) { + err = dac_output_voltage(self->dac_id, 0); + } + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void mdac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mdac_obj_t *self = self_in; + mp_printf(print, "DAC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t mdac_write(mp_obj_t self_in, mp_obj_t value_in) { + mdac_obj_t *self = self_in; + int value = mp_obj_get_int(value_in); + if (value < 0 || value > 255) mp_raise_ValueError("Value out of range"); + + esp_err_t err = dac_output_voltage(self->dac_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mdac_write_obj, mdac_write); + +STATIC const mp_rom_map_elem_t mdac_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mdac_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mdac_locals_dict, mdac_locals_dict_table); + +const mp_obj_type_t machine_dac_type = { + { &mp_type_type }, + .name = MP_QSTR_DAC, + .print = mdac_print, + .make_new = mdac_make_new, + .locals_dict = (mp_obj_t)&mdac_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_hw_spi.c b/src/openmv/src/micropython/ports/esp32/machine_hw_spi.c new file mode 100755 index 0000000..d011ce5 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_hw_spi.c @@ -0,0 +1,390 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" + +#include "driver/spi_master.h" + +#define MP_HW_SPI_MAX_XFER_BYTES (4092) +#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8 + +typedef struct _machine_hw_spi_obj_t { + mp_obj_base_t base; + spi_host_device_t host; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + uint8_t firstbit; + int8_t sck; + int8_t mosi; + int8_t miso; + spi_device_handle_t spi; + enum { + MACHINE_HW_SPI_STATE_NONE, + MACHINE_HW_SPI_STATE_INIT, + MACHINE_HW_SPI_STATE_DEINIT + } state; +} machine_hw_spi_obj_t; + +STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) { + switch (spi_bus_remove_device(self->spi)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already freed"); + return; + } + + switch (spi_bus_free(self->host)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI bus already freed"); + return; + } + + int8_t pins[3] = {self->miso, self->mosi, self->sck}; + + for (int i = 0; i < 3; i++) { + if (pins[i] != -1) { + gpio_pad_select_gpio(pins[i]); + gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false); + gpio_set_direction(pins[i], GPIO_MODE_INPUT); + } + } +} + +STATIC void machine_hw_spi_init_internal( + machine_hw_spi_obj_t *self, + int8_t host, + int32_t baudrate, + int8_t polarity, + int8_t phase, + int8_t bits, + int8_t firstbit, + int8_t sck, + int8_t mosi, + int8_t miso) { + + // if we're not initialized, then we're + // implicitly 'changed', since this is the init routine + bool changed = self->state != MACHINE_HW_SPI_STATE_INIT; + + esp_err_t ret; + + machine_hw_spi_obj_t old_self = *self; + + if (host != -1 && host != self->host) { + self->host = host; + changed = true; + } + + if (baudrate != -1 && baudrate != self->baudrate) { + self->baudrate = baudrate; + changed = true; + } + + if (polarity != -1 && polarity != self->polarity) { + self->polarity = polarity; + changed = true; + } + + if (phase != -1 && phase != self->phase) { + self->phase = phase; + changed = true; + } + + if (bits != -1 && bits != self->bits) { + self->bits = bits; + changed = true; + } + + if (firstbit != -1 && firstbit != self->firstbit) { + self->firstbit = firstbit; + changed = true; + } + + if (sck != -2 && sck != self->sck) { + self->sck = sck; + changed = true; + } + + if (mosi != -2 && mosi != self->mosi) { + self->mosi = mosi; + changed = true; + } + + if (miso != -2 && miso != self->miso) { + self->miso = miso; + changed = true; + } + + if (self->host != HSPI_HOST && self->host != VSPI_HOST) { + mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)"); + } + + if (changed) { + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(&old_self); + } + } else { + return; // no changes + } + + spi_bus_config_t buscfg = { + .miso_io_num = self->miso, + .mosi_io_num = self->mosi, + .sclk_io_num = self->sck, + .quadwp_io_num = -1, + .quadhd_io_num = -1 + }; + + spi_device_interface_config_t devcfg = { + .clock_speed_hz = self->baudrate, + .mode = self->phase | (self->polarity << 1), + .spics_io_num = -1, // No CS pin + .queue_size = 1, + .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0, + .pre_cb = NULL + }; + + //Initialize the SPI bus + // FIXME: Does the DMA matter? There are two + + ret = spi_bus_initialize(self->host, &buscfg, 1); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already in use"); + return; + } + + ret = spi_bus_add_device(self->host, &devcfg, &self->spi); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NO_MEM: + mp_raise_msg(&mp_type_OSError, "out of memory"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NOT_FOUND: + mp_raise_msg(&mp_type_OSError, "no free slots"); + spi_bus_free(self->host); + return; + } + self->state = MACHINE_HW_SPI_STATE_INIT; +} + +STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(self); + } +} + +STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->state == MACHINE_HW_SPI_STATE_DEINIT) { + mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI"); + return; + } + + struct spi_transaction_t transaction = { 0 }; + + // Round to nearest whole set of bits + int bits_to_send = len * 8 / self->bits * self->bits; + + + if (len <= 4) { + if (src != NULL) { + memcpy(&transaction.tx_data, src, len); + } + + transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; + transaction.length = bits_to_send; + spi_device_transmit(self->spi, &transaction); + + if (dest != NULL) { + memcpy(dest, &transaction.rx_data, len); + } + } else { + int offset = 0; + int bits_remaining = bits_to_send; + + while (bits_remaining) { + memset(&transaction, 0, sizeof(transaction)); + + transaction.length = + bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining; + + if (src != NULL) { + transaction.tx_buffer = src + offset; + } + if (dest != NULL) { + transaction.rx_buffer = dest + offset; + } + + spi_device_transmit(self->spi, &transaction); + bits_remaining -= transaction.length; + + // doesn't need ceil(); loop ends when bits_remaining is 0 + offset += transaction.length / 8; + } + } +} + +/******************************************************************************/ +// MicroPython bindings for hw_spi + +STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)", + self->host, self->baudrate, self->polarity, + self->phase, self->bits, self->firstbit, + self->sck, self->mosi, self->miso); +} + +STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), + allowed_args, args); + int8_t sck, mosi, miso; + + if (args[ARG_sck].u_obj == MP_OBJ_NULL) { + sck = -2; + } else if (args[ARG_sck].u_obj == mp_const_none) { + sck = -1; + } else { + sck = machine_pin_get_id(args[ARG_sck].u_obj); + } + + if (args[ARG_miso].u_obj == MP_OBJ_NULL) { + miso = -2; + } else if (args[ARG_miso].u_obj == mp_const_none) { + miso = -1; + } else { + miso = machine_pin_get_id(args[ARG_miso].u_obj); + } + + if (args[ARG_mosi].u_obj == MP_OBJ_NULL) { + mosi = -2; + } else if (args[ARG_mosi].u_obj == mp_const_none) { + mosi = -1; + } else { + mosi = machine_pin_get_id(args[ARG_mosi].u_obj); + } + + machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, + args[ARG_firstbit].u_int, sck, mosi, miso); +} + +mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t); + self->base.type = &machine_hw_spi_type; + + machine_hw_spi_init_internal( + self, + args[ARG_id].u_int, + args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, + args[ARG_phase].u_int, + args[ARG_bits].u_int, + args[ARG_firstbit].u_int, + args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj), + args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj), + args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj)); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_spi_p_t machine_hw_spi_p = { + .init = machine_hw_spi_init, + .deinit = machine_hw_spi_deinit, + .transfer = machine_hw_spi_transfer, +}; + +const mp_obj_type_t machine_hw_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hw_spi_print, + .make_new = machine_hw_spi_make_new, + .protocol = &machine_hw_spi_p, + .locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_pin.c b/src/openmv/src/micropython/ports/esp32/machine_pin.c new file mode 100755 index 0000000..0b9150f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_pin.c @@ -0,0 +1,416 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/gpio.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "mphalport.h" +#include "modmachine.h" +#include "extmod/virtpin.h" +#include "machine_rtc.h" +#include "modesp32.h" + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_obj_t; + +typedef struct _machine_pin_irq_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_irq_obj_t; + +STATIC const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, GPIO_NUM_0}, + {{&machine_pin_type}, GPIO_NUM_1}, + {{&machine_pin_type}, GPIO_NUM_2}, + {{&machine_pin_type}, GPIO_NUM_3}, + {{&machine_pin_type}, GPIO_NUM_4}, + {{&machine_pin_type}, GPIO_NUM_5}, + {{&machine_pin_type}, GPIO_NUM_6}, + {{&machine_pin_type}, GPIO_NUM_7}, + {{&machine_pin_type}, GPIO_NUM_8}, + {{&machine_pin_type}, GPIO_NUM_9}, + {{&machine_pin_type}, GPIO_NUM_10}, + {{&machine_pin_type}, GPIO_NUM_11}, + {{&machine_pin_type}, GPIO_NUM_12}, + {{&machine_pin_type}, GPIO_NUM_13}, + {{&machine_pin_type}, GPIO_NUM_14}, + {{&machine_pin_type}, GPIO_NUM_15}, + {{&machine_pin_type}, GPIO_NUM_16}, + {{&machine_pin_type}, GPIO_NUM_17}, + {{&machine_pin_type}, GPIO_NUM_18}, + {{&machine_pin_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_21}, + {{&machine_pin_type}, GPIO_NUM_22}, + {{&machine_pin_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_25}, + {{&machine_pin_type}, GPIO_NUM_26}, + {{&machine_pin_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_32}, + {{&machine_pin_type}, GPIO_NUM_33}, + {{&machine_pin_type}, GPIO_NUM_34}, + {{&machine_pin_type}, GPIO_NUM_35}, + {{&machine_pin_type}, GPIO_NUM_36}, + {{&machine_pin_type}, GPIO_NUM_37}, + {{&machine_pin_type}, GPIO_NUM_38}, + {{&machine_pin_type}, GPIO_NUM_39}, +}; + +// forward declaration +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[]; + +void machine_pins_init(void) { + static bool did_install = false; + if (!did_install) { + gpio_install_isr_service(0); + did_install = true; + } + memset(&MP_STATE_PORT(machine_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(machine_pin_irq_handler))); +} + +void machine_pins_deinit(void) { + for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) { + if (machine_pin_obj[i].id != (gpio_num_t)-1) { + gpio_isr_handler_remove(machine_pin_obj[i].id); + } + } +} + +STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) { + machine_pin_obj_t *self = arg; + mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id]; + mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); + mp_hal_wake_main_task_from_isr(); +} + +gpio_num_t machine_pin_get_id(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &machine_pin_type) { + mp_raise_ValueError("expecting a pin"); + } + machine_pin_obj_t *self = pin_in; + return self->id; +} + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "Pin(%u)", self->id); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // configure the pin for gpio + gpio_pad_select_gpio(self->id); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + } + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) { + mp_raise_ValueError("pin can only be input"); + } else { + gpio_set_direction(self->id, pin_io_mode); + } + } + + // configure pull + if (args[ARG_pull].u_obj != mp_const_none) { + gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj)); + } + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + const machine_pin_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) { + self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin]; + } + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id)); + } else { + // set pin + gpio_set_level(self->id, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) +STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_wake }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (n_args > 1 || kw_args->used != 0) { + // configure irq + mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t trigger = args[ARG_trigger].u_int; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + + if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) { + mp_int_t wake; + if (mp_obj_get_int_maybe(wake_obj, &wake)) { + if (wake < 2 || wake > 7) { + mp_raise_ValueError("bad wake value"); + } + } else { + mp_raise_ValueError("bad wake value"); + } + + if (machine_rtc_config.wake_on_touch) { // not compatible + mp_raise_ValueError("no resources"); + } + + if (!RTC_IS_VALID_EXT_PIN(self->id)) { + mp_raise_ValueError("invalid pin for wake"); + } + + if (machine_rtc_config.ext0_pin == -1) { + machine_rtc_config.ext0_pin = self->id; + } else if (machine_rtc_config.ext0_pin != self->id) { + mp_raise_ValueError("no resources"); + } + + machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1; + machine_rtc_config.ext0_wake_types = wake; + } else { + if (machine_rtc_config.ext0_pin == self->id) { + machine_rtc_config.ext0_pin = -1; + } + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); + } + } + + // return the irq object + return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) }, +}; + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return gpio_get_level(self->id); + } + case MP_PIN_WRITE: { + gpio_set_level(self->id, arg); + return 0; + } + } + return -1; +} + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +STATIC const mp_obj_type_t machine_pin_irq_type; + +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { + {{&machine_pin_irq_type}, GPIO_NUM_0}, + {{&machine_pin_irq_type}, GPIO_NUM_1}, + {{&machine_pin_irq_type}, GPIO_NUM_2}, + {{&machine_pin_irq_type}, GPIO_NUM_3}, + {{&machine_pin_irq_type}, GPIO_NUM_4}, + {{&machine_pin_irq_type}, GPIO_NUM_5}, + {{&machine_pin_irq_type}, GPIO_NUM_6}, + {{&machine_pin_irq_type}, GPIO_NUM_7}, + {{&machine_pin_irq_type}, GPIO_NUM_8}, + {{&machine_pin_irq_type}, GPIO_NUM_9}, + {{&machine_pin_irq_type}, GPIO_NUM_10}, + {{&machine_pin_irq_type}, GPIO_NUM_11}, + {{&machine_pin_irq_type}, GPIO_NUM_12}, + {{&machine_pin_irq_type}, GPIO_NUM_13}, + {{&machine_pin_irq_type}, GPIO_NUM_14}, + {{&machine_pin_irq_type}, GPIO_NUM_15}, + {{&machine_pin_irq_type}, GPIO_NUM_16}, + {{&machine_pin_irq_type}, GPIO_NUM_17}, + {{&machine_pin_irq_type}, GPIO_NUM_18}, + {{&machine_pin_irq_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_21}, + {{&machine_pin_irq_type}, GPIO_NUM_22}, + {{&machine_pin_irq_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_25}, + {{&machine_pin_irq_type}, GPIO_NUM_26}, + {{&machine_pin_irq_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_32}, + {{&machine_pin_irq_type}, GPIO_NUM_33}, + {{&machine_pin_irq_type}, GPIO_NUM_34}, + {{&machine_pin_irq_type}, GPIO_NUM_35}, + {{&machine_pin_irq_type}, GPIO_NUM_36}, + {{&machine_pin_irq_type}, GPIO_NUM_37}, + {{&machine_pin_irq_type}, GPIO_NUM_38}, + {{&machine_pin_irq_type}, GPIO_NUM_39}, +}; + +STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = self_in; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + machine_pin_isr_handler((void*)&machine_pin_obj[self->id]); + return mp_const_none; +} + +STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = args[0]; + uint32_t orig_trig = GPIO.pin[self->id].int_type; + if (n_args == 2) { + // set trigger + gpio_set_intr_type(self->id, mp_obj_get_int(args[1])); + } + // return original trigger value + return MP_OBJ_NEW_SMALL_INT(orig_trig); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_irq_trigger_obj, 1, 2, machine_pin_irq_trigger); + +STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&machine_pin_irq_trigger_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table); + +STATIC const mp_obj_type_t machine_pin_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = machine_pin_irq_call, + .locals_dict = (mp_obj_dict_t*)&machine_pin_irq_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_pwm.c b/src/openmv/src/micropython/ports/esp32/machine_pwm.c new file mode 100755 index 0000000..4d6c59f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_pwm.c @@ -0,0 +1,277 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "driver/ledc.h" +#include "esp_err.h" + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" + +// Forward dec'l +extern const mp_obj_type_t machine_pwm_type; + +typedef struct _esp32_pwm_obj_t { + mp_obj_base_t base; + gpio_num_t pin; + uint8_t active; + uint8_t channel; +} esp32_pwm_obj_t; + +// Which channel has which GPIO pin assigned? +// (-1 if not assigned) +STATIC int chan_gpio[LEDC_CHANNEL_MAX]; + +// Params for PW operation +// 5khz +#define PWFREQ (5000) +// High speed mode +#define PWMODE (LEDC_HIGH_SPEED_MODE) +// 10-bit resolution (compatible with esp8266 PWM) +#define PWRES (LEDC_TIMER_10_BIT) +// Timer 1 +#define PWTIMER (LEDC_TIMER_1) + +// Config of timer upon which we run all PWM'ed GPIO pins +STATIC bool pwm_inited = false; +STATIC ledc_timer_config_t timer_cfg = { + .bit_num = PWRES, + .freq_hz = PWFREQ, + .speed_mode = PWMODE, + .timer_num = PWTIMER +}; + +STATIC void pwm_init(void) { + + // Initial condition: no channels assigned + for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) { + chan_gpio[x] = -1; + } + + // Init with default timer params + ledc_timer_config(&timer_cfg); +} + +STATIC int set_freq(int newval) { + int oval = timer_cfg.freq_hz; + + timer_cfg.freq_hz = newval; + if (ledc_timer_config(&timer_cfg) != ESP_OK) { + timer_cfg.freq_hz = oval; + return 0; + } + return 1; +} + +/******************************************************************************/ + +// MicroPython bindings for PWM + +STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(%u", self->pin); + if (self->active) { + mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz, + ledc_get_duty(PWMODE, self->channel)); + } + mp_printf(print, ")"); +} + +STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int channel; + int avail = -1; + + // Find a free PWM channel, also spot if our pin is + // already mentioned. + for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) { + if (chan_gpio[channel] == self->pin) { + break; + } + if ((avail == -1) && (chan_gpio[channel] == -1)) { + avail = channel; + } + } + if (channel >= LEDC_CHANNEL_MAX) { + if (avail == -1) { + mp_raise_ValueError("out of PWM channels"); + } + channel = avail; + } + self->channel = channel; + + // New PWM assignment + self->active = 1; + if (chan_gpio[channel] == -1) { + ledc_channel_config_t cfg = { + .channel = channel, + .duty = (1 << PWRES) / 2, + .gpio_num = self->pin, + .intr_type = LEDC_INTR_DISABLE, + .speed_mode = PWMODE, + .timer_sel = PWTIMER, + }; + if (ledc_channel_config(&cfg) != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM not supported on pin %d", self->pin)); + } + chan_gpio[channel] = self->pin; + } + + // Maybe change PWM timer + int tval = args[ARG_freq].u_int; + if (tval != -1) { + if (tval != timer_cfg.freq_hz) { + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + } + } + + // Set duty cycle? + int dval = args[ARG_duty].u_int; + if (dval != -1) { + dval &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, channel, dval); + ledc_update_duty(PWMODE, channel); + } +} + +STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + + // create PWM object from the given pin + esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t); + self->base.type = &machine_pwm_type; + self->pin = pin_id; + self->active = 0; + self->channel = -1; + + // start the PWM subsystem if it's not already running + if (!pwm_inited) { + pwm_init(); + pwm_inited = true; + } + + // start the PWM running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t esp32_pwm_init(size_t n_args, + const mp_obj_t *args, mp_map_t *kw_args) { + esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init); + +STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + int chan = self->channel; + + // Valid channel? + if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { + // Mark it unused, and tell the hardware to stop routing + chan_gpio[chan] = -1; + ledc_stop(PWMODE, chan, 0); + self->active = 0; + self->channel = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit); + +STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz); + } + + // set + int tval = mp_obj_get_int(args[1]); + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq); + +STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int duty; + + if (n_args == 1) { + // get + duty = ledc_get_duty(PWMODE, self->channel); + return MP_OBJ_NEW_SMALL_INT(duty); + } + + // set + duty = mp_obj_get_int(args[1]); + duty &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, self->channel, duty); + ledc_update_duty(PWMODE, self->channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj, + 1, 2, esp32_pwm_duty); + +STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict, + esp32_pwm_locals_dict_table); + +const mp_obj_type_t machine_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = esp32_pwm_print, + .make_new = esp32_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_pwm_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_rtc.c b/src/openmv/src/micropython/ports/esp32/machine_rtc.c new file mode 100755 index 0000000..08c7b02 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_rtc.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; +} machine_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +/* There is 8K of rtc_slow_memory, but some is used by the system software + If the USER_MAXLEN is set to high, the following compile error will happen: + region `rtc_slow_seg' overflowed by N bytes + The current system software allows almost 4096 to be used. + To avoid running into issues if the system software uses more, 2048 was picked as a max length +*/ +#define MEM_USER_MAXLEN 2048 +RTC_DATA_ATTR uint32_t rtc_user_mem_magic; +RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN]; + +// singleton RTC object +STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; + +machine_rtc_config_t machine_rtc_config = { + .ext1_pins = 0, + .ext0_pin = -1 + }; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&machine_rtc_obj; +} + +STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + + struct timeval tv; + + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tv.tv_usec) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + struct timeval tv = {0}; + tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + settimeofday(&tv, NULL); + + return mp_const_none; + } +} +STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + return machine_rtc_datetime_helper(n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime); + +STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) { + mp_obj_t args[2] = {self_in, date}; + machine_rtc_datetime_helper(2, args); + + if (rtc_user_mem_magic != MEM_MAGIC) { + rtc_user_mem_magic = MEM_MAGIC; + rtc_user_mem_len = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); + +STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // read RTC memory + uint32_t len = rtc_user_mem_len; + uint8_t rtcram[MEM_USER_MAXLEN]; + memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); + rtc_user_mem_len = bufinfo.len; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); + +STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_t)&machine_rtc_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_rtc.h b/src/openmv/src/micropython/ports/esp32/machine_rtc.h new file mode 100755 index 0000000..e34deb9 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_rtc.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H +#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H + +#include "modmachine.h" + +typedef struct { + uint64_t ext1_pins; // set bit == pin# + int8_t ext0_pin; // just the pin#, -1 == None + bool wake_on_touch : 1; + bool ext0_level : 1; + wake_type_t ext0_wake_types; + bool ext1_level : 1; +} machine_rtc_config_t; + +extern machine_rtc_config_t machine_rtc_config; + +#endif diff --git a/src/openmv/src/micropython/ports/esp32/machine_timer.c b/src/openmv/src/micropython/ports/esp32/machine_timer.c new file mode 100755 index 0000000..7dca9e0 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_timer.c @@ -0,0 +1,221 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/timer.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" + +#define TIMER_INTR_SEL TIMER_INTR_LEVEL +#define TIMER_DIVIDER 8 + +// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) + +#define TIMER_FLAGS 0 + +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + mp_uint_t group; + mp_uint_t index; + + mp_uint_t repeat; + // ESP32 timers are 64-bit + uint64_t period; + + mp_obj_t callback; + + intr_handle_t handle; +} machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; + +STATIC esp_err_t check_esp_err(esp_err_t code) { + if (code) { + mp_raise_OSError(code); + } + + return code; +} + +STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_timer_obj_t *self = self_in; + + timer_config_t config; + mp_printf(print, "Timer(%p; ", self); + + timer_get_config(self->group, self->index, &config); + + mp_printf(print, "alarm_en=%d, ", config.alarm_en); + mp_printf(print, "auto_reload=%d, ", config.auto_reload); + mp_printf(print, "counter_en=%d)", config.counter_en); +} + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); + self->base.type = &machine_timer_type; + + self->group = (mp_obj_get_int(args[0]) >> 1) & 1; + self->index = mp_obj_get_int(args[0]) & 1; + + return self; +} + +STATIC void machine_timer_disable(machine_timer_obj_t *self) { + if (self->handle) { + timer_pause(self->group, self->index); + esp_intr_free(self->handle); + self->handle = NULL; + } +} + +STATIC void machine_timer_isr(void *self_in) { + machine_timer_obj_t *self = self_in; + timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0); + + device->hw_timer[self->index].update = 1; + if (self->index) { + device->int_clr_timers.t1 = 1; + } else { + device->int_clr_timers.t0 = 1; + } + device->hw_timer[self->index].config.alarm_en = self->repeat; + + mp_sched_schedule(self->callback, self); + mp_hal_wake_main_task_from_isr(); +} + +STATIC void machine_timer_enable(machine_timer_obj_t *self) { + timer_config_t config; + config.alarm_en = TIMER_ALARM_EN; + config.auto_reload = self->repeat; + config.counter_dir = TIMER_COUNT_UP; + config.divider = TIMER_DIVIDER; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + + check_esp_err(timer_init(self->group, self->index, &config)); + check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000)); + check_esp_err(timer_set_alarm_value(self->group, self->index, self->period)); + check_esp_err(timer_enable_intr(self->group, self->index)); + check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle)); + check_esp_err(timer_start(self->group, self->index)); +} + +STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_mode, + ARG_callback, + ARG_period, + ARG_tick_hz, + ARG_freq, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, +#if MICROPY_PY_BUILTINS_FLOAT + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +#else + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, +#endif + }; + + machine_timer_disable(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + +#if MICROPY_PY_BUILTINS_FLOAT + if (args[ARG_freq].u_obj != mp_const_none) { + self->period = (uint64_t)(TIMER_SCALE / mp_obj_get_float(args[ARG_freq].u_obj)); + } +#else + if (args[ARG_freq].u_int != 0xffffffff) { + self->period = TIMER_SCALE / ((uint64_t)args[ARG_freq].u_int); + } +#endif + else { + self->period = (((uint64_t)args[ARG_period].u_int) * TIMER_SCALE) / args[ARG_tick_hz].u_int; + } + + self->repeat = args[ARG_mode].u_int; + self->callback = args[ARG_callback].u_obj; + self->handle = NULL; + + machine_timer_enable(self); + + return mp_const_none; +} + +STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { + machine_timer_disable(self_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init); + +STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + double result; + + timer_get_counter_time_sec(self->group, self->index, &result); + + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = machine_timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_t)&machine_timer_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_touchpad.c b/src/openmv/src/micropython/ports/esp32/machine_touchpad.c new file mode 100755 index 0000000..96de1a2 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_touchpad.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/touch_pad.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mtp_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + touch_pad_t touchpad_id; +} mtp_obj_t; + +STATIC const mtp_obj_t touchpad_obj[] = { + {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0}, + {{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1}, + {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2}, + {{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_NUM3}, + {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM4}, + {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5}, + {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6}, + {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7}, + {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8}, + {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9}, +}; + +STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mtp_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(touchpad_obj); i++) { + if (pin_id == touchpad_obj[i].gpio_id) { self = &touchpad_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid pin for touchpad"); + + static int initialized = 0; + if (!initialized) { + touch_pad_init(); + initialized = 1; + } + esp_err_t err = touch_pad_config(self->touchpad_id, 0); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Touch pad error"); +} + +STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { + mtp_obj_t *self = self_in; + uint16_t value = mp_obj_get_int(value_in); + esp_err_t err = touch_pad_config(self->touchpad_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config); + +STATIC mp_obj_t mtp_read(mp_obj_t self_in) { + mtp_obj_t *self = self_in; + uint16_t value; + esp_err_t err = touch_pad_read(self->touchpad_id, &value); + if (err == ESP_OK) return MP_OBJ_NEW_SMALL_INT(value); + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read); + +STATIC const mp_rom_map_elem_t mtp_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mtp_locals_dict, mtp_locals_dict_table); + +const mp_obj_type_t machine_touchpad_type = { + { &mp_type_type }, + .name = MP_QSTR_TouchPad, + .make_new = mtp_make_new, + .locals_dict = (mp_obj_t)&mtp_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_uart.c b/src/openmv/src/micropython/ports/esp32/machine_uart.c new file mode 100755 index 0000000..474764b --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_uart.c @@ -0,0 +1,357 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "driver/uart.h" +#include "freertos/FreeRTOS.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +typedef struct _machine_uart_obj_t { + mp_obj_base_t base; + uart_port_t uart_num; + uint8_t bits; + uint8_t parity; + uint8_t stop; + int8_t tx; + int8_t rx; + int8_t rts; + int8_t cts; + uint16_t timeout; // timeout waiting for first char (in ms) + uint16_t timeout_char; // timeout waiting between chars (in ms) +} machine_uart_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t baudrate; + uart_get_baudrate(self->uart_num, &baudrate); + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, timeout=%u, timeout_char=%u)", + self->uart_num, baudrate, self->bits, _parity_name[self->parity], + self->stop, self->tx, self->rx, self->rts, self->cts, self->timeout, self->timeout_char); +} + +STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_timeout, ARG_timeout_char }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // wait for all data to be transmitted before changing settings + uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)); + + // set baudrate + uint32_t baudrate = 115200; + if (args[ARG_baudrate].u_int > 0) { + uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int); + uart_get_baudrate(self->uart_num, &baudrate); + } + + uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int); + if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) { + self->tx = args[ARG_tx].u_int; + } + + if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) { + self->rx = args[ARG_rx].u_int; + } + + if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) { + self->rts = args[ARG_rts].u_int; + } + + if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) { + self->cts = args[ARG_cts].u_int; + } + + // set data bits + switch (args[ARG_bits].u_int) { + case 0: + break; + case 5: + uart_set_word_length(self->uart_num, UART_DATA_5_BITS); + self->bits = 5; + break; + case 6: + uart_set_word_length(self->uart_num, UART_DATA_6_BITS); + self->bits = 6; + break; + case 7: + uart_set_word_length(self->uart_num, UART_DATA_7_BITS); + self->bits = 7; + break; + case 8: + uart_set_word_length(self->uart_num, UART_DATA_8_BITS); + self->bits = 8; + break; + default: + mp_raise_ValueError("invalid data bits"); + break; + } + + // set parity + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + uart_set_parity(self->uart_num, UART_PARITY_DISABLE); + self->parity = 0; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + if (parity & 1) { + uart_set_parity(self->uart_num, UART_PARITY_ODD); + self->parity = 1; + } else { + uart_set_parity(self->uart_num, UART_PARITY_EVEN); + self->parity = 2; + } + } + } + + // set stop bits + switch (args[ARG_stop].u_int) { + // FIXME: ESP32 also supports 1.5 stop bits + case 0: + break; + case 1: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1); + self->stop = 1; + break; + case 2: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2); + self->stop = 2; + break; + default: + mp_raise_ValueError("invalid stop bits"); + break; + } + + // set timeout + self->timeout = args[ARG_timeout].u_int; + + // set timeout_char + // make sure it is at least as long as a whole character (13 bits to be safe) + self->timeout_char = args[ARG_timeout_char].u_int; + uint32_t min_timeout_char = 13000 / baudrate + 1; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } +} + +STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get uart id + mp_int_t uart_num = mp_obj_get_int(args[0]); + if (uart_num < 0 || uart_num >= UART_NUM_MAX) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); + } + + // Attempts to use UART0 from Python has resulted in all sorts of fun errors. + // FIXME: UART0 is disabled for now. + if (uart_num == UART_NUM_0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) is disabled (dedicated to REPL)", uart_num)); + } + + // Defaults + uart_config_t uartcfg = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0 + }; + + // create instance + machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t); + self->base.type = &machine_uart_type; + self->uart_num = uart_num; + self->bits = 8; + self->parity = 0; + self->stop = 1; + self->rts = UART_PIN_NO_CHANGE; + self->cts = UART_PIN_NO_CHANGE; + self->timeout = 0; + self->timeout_char = 0; + + switch (uart_num) { + case UART_NUM_0: + self->rx = UART_PIN_NO_CHANGE; // GPIO 3 + self->tx = UART_PIN_NO_CHANGE; // GPIO 1 + break; + case UART_NUM_1: + self->rx = 9; + self->tx = 10; + break; + case UART_NUM_2: + self->rx = 16; + self->tx = 17; + break; + } + + // Remove any existing configuration + uart_driver_delete(self->uart_num); + + // init the peripheral + // Setup + uart_param_config(self->uart_num, &uartcfg); + + // RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum). + uart_driver_install(uart_num, 256, 256, 0, NULL, 0); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + + // Make sure pins are connected. + uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); + +STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + return MP_OBJ_NEW_SMALL_INT(rxbufsize); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); + +STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, + + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); + +STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + TickType_t time_to_wait; + if (self->timeout == 0) { + time_to_wait = 0; + } else { + time_to_wait = pdMS_TO_TICKS(self->timeout); + } + + int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); + + if (bytes_read <= 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + return bytes_read; +} + +STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int bytes_written = uart_write_bytes(self->uart_num, buf_in, size); + + if (bytes_written < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // return number of bytes written + return bytes_written; +} + +STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + machine_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num) + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_uart_read, + .write = machine_uart_write, + .ioctl = machine_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_uart_print, + .make_new = machine_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/machine_wdt.c b/src/openmv/src/micropython/ports/esp32/machine_wdt.c new file mode 100755 index 0000000..88a58f0 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/machine_wdt.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2017 Eric Poulsen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" + +#include "esp_task_wdt.h" + +const mp_obj_type_t machine_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + esp_task_wdt_add(NULL); + return &wdt_default; + default: + mp_raise_ValueError(NULL); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + esp_task_wdt_reset(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t machine_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_t)&machine_wdt_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/main.c b/src/openmv/src/micropython/ports/esp32/main.c new file mode 100755 index 0000000..5ef2675 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/main.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_task.h" +#include "soc/cpu.h" +#include "esp_log.h" + +#include "py/stackctrl.h" +#include "py/nlr.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "uart.h" +#include "modmachine.h" +#include "modnetwork.h" +#include "mpthreadport.h" + +// MicroPython runs as a task under FreeRTOS +#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) +#define MP_TASK_STACK_SIZE (16 * 1024) +#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) + +STATIC StaticTask_t mp_task_tcb; +STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); + +int vprintf_null(const char *format, va_list ap) { + // do nothing: this is used as a log target during raw repl mode + return 0; +} + +void mp_task(void *pvParameter) { + volatile uint32_t sp = (uint32_t)get_sp(); + #if MICROPY_PY_THREAD + mp_thread_init(&mp_task_stack[0], MP_TASK_STACK_LEN); + #endif + uart_init(); + + // Allocate the uPy heap using malloc and get the largest available region + size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + void *mp_task_heap = malloc(mp_task_heap_size); + +soft_reset: + // initialise the stack pointer for the main thread + mp_stack_set_top((void *)sp); + mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024); + gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); + mp_obj_list_init(mp_sys_argv, 0); + readline_init0(); + + // initialise peripherals + machine_pins_init(); + + // run boot-up scripts + pyexec_frozen_module("_boot.py"); + pyexec_file("boot.py"); + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + pyexec_file("main.py"); + } + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null); + if (pyexec_raw_repl() != 0) { + break; + } + esp_log_set_vprintf(vprintf_log); + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + #if MICROPY_PY_THREAD + mp_thread_deinit(); + #endif + + gc_sweep_all(); + + mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); + + // deinitialise peripherals + machine_pins_deinit(); + usocket_events_deinit(); + + mp_deinit(); + fflush(stdout); + goto soft_reset; +} + +void app_main(void) { + nvs_flash_init(); + mp_main_task_handle = xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, + &mp_task_stack[0], &mp_task_tcb, 0); +} + +void nlr_jump_fail(void *val) { + printf("NLR jump failed, val=%p\n", val); + esp_restart(); +} + +// modussl_mbedtls uses this function but it's not enabled in ESP IDF +void mbedtls_debug_set_threshold(int threshold) { + (void)threshold; +} diff --git a/src/openmv/src/micropython/ports/esp32/makeimg.py b/src/openmv/src/micropython/ports/esp32/makeimg.py new file mode 100755 index 0000000..aeedbff --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/makeimg.py @@ -0,0 +1,25 @@ +import sys + +OFFSET_BOOTLOADER = 0x1000 +OFFSET_PARTITIONS = 0x8000 +OFFSET_APPLICATION = 0x10000 + +files_in = [ + ('bootloader', OFFSET_BOOTLOADER, sys.argv[1]), + ('partitions', OFFSET_PARTITIONS, sys.argv[2]), + ('application', OFFSET_APPLICATION, sys.argv[3]), +] +file_out = sys.argv[4] + +cur_offset = OFFSET_BOOTLOADER +with open(file_out, 'wb') as fout: + for name, offset, file_in in files_in: + assert offset >= cur_offset + fout.write(b'\xff' * (offset - cur_offset)) + cur_offset = offset + with open(file_in, 'rb') as fin: + data = fin.read() + fout.write(data) + cur_offset += len(data) + print('%-12s% 8d' % (name, len(data))) + print('%-12s% 8d' % ('total', cur_offset)) diff --git a/src/openmv/src/micropython/ports/esp32/memory.h b/src/openmv/src/micropython/ports/esp32/memory.h new file mode 100755 index 0000000..f3777b0 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/memory.h @@ -0,0 +1,2 @@ +// this is needed for extmod/crypto-algorithms/sha256.c +#include diff --git a/src/openmv/src/micropython/ports/esp32/modesp.c b/src/openmv/src/micropython/ports/esp32/modesp.c new file mode 100755 index 0000000..e614f77 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modesp.c @@ -0,0 +1,157 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "rom/gpio.h" +#include "esp_log.h" +#include "esp_spi_flash.h" + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "drivers/dht/dht.h" +#include "modesp.h" + +STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) { + esp_log_level_t level = LOG_LOCAL_LEVEL; + if (n_args == 2) { + level = mp_obj_get_int(args[1]); + } + if (args[0] == mp_const_none) { + // Disable logging + esp_log_level_set("*", ESP_LOG_ERROR); + } else { + // Enable logging at the given level + // TODO args[0] should set the UART to which debug is sent + esp_log_level_set("*", level); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_osdebug_obj, 1, 2, esp_osdebug); + +STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + esp_err_t res = spi_flash_read(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read); + +STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + esp_err_t res = spi_flash_write(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write); + +STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { + mp_int_t sector = mp_obj_get_int(sector_in); + esp_err_t res = spi_flash_erase_sector(sector); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); + +STATIC mp_obj_t esp_flash_size(void) { + return mp_obj_new_int_from_uint(spi_flash_get_chip_size()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); + +STATIC mp_obj_t esp_flash_user_start(void) { + return MP_OBJ_NEW_SMALL_INT(0x200000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); + +STATIC mp_obj_t esp_gpio_matrix_in(mp_obj_t pin, mp_obj_t sig, mp_obj_t inv) { + gpio_matrix_in(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_gpio_matrix_in_obj, esp_gpio_matrix_in); + +STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) { + (void)n_args; + gpio_matrix_out(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out); + +STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_neopixel_write(mp_hal_get_pin_obj(pin), + (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); + +STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) }, + + { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) }, + + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) }, + + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) }, + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) }, + + { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + + // Constants for second arg of osdebug() + { MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT((mp_uint_t)ESP_LOG_NONE)}, + { MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT((mp_uint_t)ESP_LOG_ERROR)}, + { MP_ROM_QSTR(MP_QSTR_LOG_WARNING), MP_ROM_INT((mp_uint_t)ESP_LOG_WARN)}, + { MP_ROM_QSTR(MP_QSTR_LOG_INFO), MP_ROM_INT((mp_uint_t)ESP_LOG_INFO)}, + { MP_ROM_QSTR(MP_QSTR_LOG_DEBUG), MP_ROM_INT((mp_uint_t)ESP_LOG_DEBUG)}, + { MP_ROM_QSTR(MP_QSTR_LOG_VERBOSE), MP_ROM_INT((mp_uint_t)ESP_LOG_VERBOSE)}, +}; + +STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table); + +const mp_obj_module_t esp_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp_module_globals, +}; + diff --git a/src/openmv/src/micropython/ports/esp32/modesp.h b/src/openmv/src/micropython/ports/esp32/modesp.h new file mode 100755 index 0000000..a822c02 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modesp.h @@ -0,0 +1 @@ +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing); diff --git a/src/openmv/src/micropython/ports/esp32/modesp32.c b/src/openmv/src/micropython/ports/esp32/modesp32.c new file mode 100755 index 0000000..2e2d823 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modesp32.c @@ -0,0 +1,168 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" +#include "driver/gpio.h" +#include "driver/adc.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" +#include "modesp32.h" + +STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { + + if (machine_rtc_config.ext0_pin != -1) { + mp_raise_ValueError("no resources"); + } + //nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF")); + + machine_rtc_config.wake_on_touch = mp_obj_is_true(wake); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch); + +STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + if (machine_rtc_config.wake_on_touch) { + mp_raise_ValueError("no resources"); + } + enum {ARG_pin, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_pin].u_obj == mp_const_none) { + machine_rtc_config.ext0_pin = -1; // "None" + } else { + gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj); + if (pin_id != machine_rtc_config.ext0_pin) { + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + } + machine_rtc_config.ext0_pin = pin_id; + } + } + + machine_rtc_config.ext0_level = args[ARG_level].u_bool; + machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0); + +STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_pins, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint64_t ext1_pins = machine_rtc_config.ext1_pins; + + + // Check that all pins are allowed + if (args[ARG_pins].u_obj != mp_const_none) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem); + ext1_pins = 0; + + for (int i = 0; i < len; i++) { + + gpio_num_t pin_id = machine_pin_get_id(elem[i]); + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + break; + } + ext1_pins |= (1ll << pin_id); + } + } + + machine_rtc_config.ext1_level = args[ARG_level].u_bool; + machine_rtc_config.ext1_pins = ext1_pins; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); + +STATIC mp_obj_t esp32_raw_temperature(void) { + SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); + SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10, SENS_TSENS_CLK_DIV_S); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); + ets_delay_us(100); + SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); + ets_delay_us(5); + int res = GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT, SENS_TSENS_OUT_S); + + return mp_obj_new_int(res); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_raw_temperature_obj, esp32_raw_temperature); + +STATIC mp_obj_t esp32_hall_sensor(void) { + adc1_config_width(ADC_WIDTH_12Bit); + return MP_OBJ_NEW_SMALL_INT(hall_sensor_read()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor); + +STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) }, + + { MP_ROM_QSTR(MP_QSTR_wake_on_touch), MP_ROM_PTR(&esp32_wake_on_touch_obj) }, + { MP_ROM_QSTR(MP_QSTR_wake_on_ext0), MP_ROM_PTR(&esp32_wake_on_ext0_obj) }, + { MP_ROM_QSTR(MP_QSTR_wake_on_ext1), MP_ROM_PTR(&esp32_wake_on_ext1_obj) }, + { MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) }, + { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, + + { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, + + { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, + { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_PTR(&mp_const_true_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table); + +const mp_obj_module_t esp32_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp32_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp32/modesp32.h b/src/openmv/src/micropython/ports/esp32/modesp32.h new file mode 100755 index 0000000..1d18cb4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modesp32.h @@ -0,0 +1,31 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H +#define MICROPY_INCLUDED_ESP32_MODESP32_H + +#define RTC_VALID_EXT_PINS \ +( \ + (1ll << 0) | \ + (1ll << 2) | \ + (1ll << 4) | \ + (1ll << 12) | \ + (1ll << 13) | \ + (1ll << 14) | \ + (1ll << 15) | \ + (1ll << 25) | \ + (1ll << 26) | \ + (1ll << 27) | \ + (1ll << 32) | \ + (1ll << 33) | \ + (1ll << 34) | \ + (1ll << 35) | \ + (1ll << 36) | \ + (1ll << 37) | \ + (1ll << 38) | \ + (1ll << 39) \ +) + +#define RTC_LAST_EXT_PIN 39 +#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) + +extern const mp_obj_type_t esp32_ulp_type; + +#endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/src/openmv/src/micropython/ports/esp32/modmachine.c b/src/openmv/src/micropython/ports/esp32/modmachine.c new file mode 100755 index 0000000..2b98376 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modmachine.c @@ -0,0 +1,269 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/ets_sys.h" +#include "rom/rtc.h" +#include "esp_system.h" +#include "driver/touch_pad.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" +#include "machine_rtc.h" + +#if MICROPY_PY_MACHINE + +typedef enum { + MP_PWRON_RESET = 1, + MP_HARD_RESET, + MP_WDT_RESET, + MP_DEEPSLEEP_RESET, + MP_SOFT_RESET +} reset_reason_t; + +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // get + return mp_obj_new_int(ets_get_cpu_frequency() * 1000000); + } else { + // set + mp_int_t freq = mp_obj_get_int(args[0]) / 1000000; + if (freq != 80 && freq != 160 && freq != 240) { + mp_raise_ValueError("frequency can only be either 80Mhz, 160MHz or 240MHz"); + } + /* + system_update_cpu_freq(freq); + */ + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); + +STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum {ARG_sleep_ms}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_int_t expiry = args[ARG_sleep_ms].u_int; + + if (expiry != 0) { + esp_sleep_enable_timer_wakeup(((uint64_t)expiry) * 1000); + } + + if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) { + esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0); + } + + if (machine_rtc_config.ext1_pins != 0) { + esp_sleep_enable_ext1_wakeup( + machine_rtc_config.ext1_pins, + machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW); + } + + if (machine_rtc_config.wake_on_touch) { + if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed")); + } + } + + switch(wake_type) { + case MACHINE_WAKE_SLEEP: + esp_light_sleep_start(); + break; + case MACHINE_WAKE_DEEPSLEEP: + esp_deep_sleep_start(); + break; + } + return mp_const_none; +} + +STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF")); + return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + switch(rtc_get_reset_reason(0)) { + case POWERON_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET); + break; + case SW_RESET: + case SW_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + break; + case OWDT_RESET: + case TG0WDT_SYS_RESET: + case TG1WDT_SYS_RESET: + case RTCWDT_SYS_RESET: + case RTCWDT_BROWN_OUT_RESET: + case RTCWDT_CPU_RESET: + case RTCWDT_RTC_RESET: + case TGWDT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET); + break; + + case DEEPSLEEP_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET); + break; + + case EXT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET); + break; + + case NO_MEAN: + case SDIO_RESET: + case INTRUSION_RESET: + default: + return MP_OBJ_NEW_SMALL_INT(0); + break; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason); + +STATIC mp_obj_t machine_reset(void) { + esp_restart(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_unique_id(void) { + uint8_t chipid[6]; + esp_efuse_mac_get_default(chipid); + return mp_obj_new_bytes(chipid, 6); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_idle(void) { + taskYIELD(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_disable_irq(void) { + uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION(); + return mp_obj_new_int(state); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { + uint32_t state = mp_obj_get_int(state_in); + MICROPY_END_ATOMIC_SECTION(state); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, + + // Wake reasons + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) }, + { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) }, + { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/ports/esp32/modmachine.h b/src/openmv/src/micropython/ports/esp32/modmachine.h new file mode 100755 index 0000000..c8513a4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modmachine.h @@ -0,0 +1,26 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODMACHINE_H +#define MICROPY_INCLUDED_ESP32_MODMACHINE_H + +#include "py/obj.h" + +typedef enum { + //MACHINE_WAKE_IDLE=0x01, + MACHINE_WAKE_SLEEP=0x02, + MACHINE_WAKE_DEEPSLEEP=0x04 +} wake_type_t; + +extern const mp_obj_type_t machine_timer_type; +extern const mp_obj_type_t machine_wdt_type; +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_touchpad_type; +extern const mp_obj_type_t machine_adc_type; +extern const mp_obj_type_t machine_dac_type; +extern const mp_obj_type_t machine_pwm_type; +extern const mp_obj_type_t machine_hw_spi_type; +extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_rtc_type; + +void machine_pins_init(void); +void machine_pins_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H diff --git a/src/openmv/src/micropython/ports/esp32/modnetwork.c b/src/openmv/src/micropython/ports/esp32/modnetwork.c new file mode 100755 index 0000000..e2e1560 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modnetwork.c @@ -0,0 +1,717 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * Copyright (c) 2017 "Eric Poulsen" + * + * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky + * And the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "netutils.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "esp_log.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "lwip/dns.h" +#include "tcpip_adapter.h" + +#include "modnetwork.h" + +#define MODNETWORK_INCLUDE_CONSTANTS (1) + +NORETURN void _esp_exceptions(esp_err_t e) { + switch (e) { + case ESP_ERR_WIFI_NOT_INIT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Initialized"); + case ESP_ERR_WIFI_NOT_STARTED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Started"); + case ESP_ERR_WIFI_NOT_STOPPED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Stopped"); + case ESP_ERR_WIFI_IF: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Interface"); + case ESP_ERR_WIFI_MODE: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Mode"); + case ESP_ERR_WIFI_STATE: + mp_raise_msg(&mp_type_OSError, "Wifi Internal State Error"); + case ESP_ERR_WIFI_CONN: + mp_raise_msg(&mp_type_OSError, "Wifi Internal Error"); + case ESP_ERR_WIFI_NVS: + mp_raise_msg(&mp_type_OSError, "Wifi Internal NVS Error"); + case ESP_ERR_WIFI_MAC: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address"); + case ESP_ERR_WIFI_SSID: + mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid"); + case ESP_ERR_WIFI_PASSWORD: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password"); + case ESP_ERR_WIFI_TIMEOUT: + mp_raise_OSError(MP_ETIMEDOUT); + case ESP_ERR_WIFI_WAKE_FAIL: + mp_raise_msg(&mp_type_OSError, "Wifi Wakeup Failure"); + case ESP_ERR_WIFI_WOULD_BLOCK: + mp_raise_msg(&mp_type_OSError, "Wifi Would Block"); + case ESP_ERR_WIFI_NOT_CONNECT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Connected"); + case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS: + mp_raise_msg(&mp_type_OSError, "TCP/IP Invalid Parameters"); + case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY: + mp_raise_msg(&mp_type_OSError, "TCP/IP IF Not Ready"); + case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED: + mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed"); + case ESP_ERR_TCPIP_ADAPTER_NO_MEM: + mp_raise_OSError(MP_ENOMEM); + default: + nlr_raise(mp_obj_new_exception_msg_varg( + &mp_type_RuntimeError, "Wifi Unknown Error 0x%04x", e + )); + } +} + +static inline void esp_exceptions(esp_err_t e) { + if (e != ESP_OK) _esp_exceptions(e); +} + +#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0); + +typedef struct _wlan_if_obj_t { + mp_obj_base_t base; + int if_id; +} wlan_if_obj_t; + +const mp_obj_type_t wlan_if_type; +STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA}; +STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; + +// Set to "true" if esp_wifi_start() was called +static bool wifi_started = false; + +// Set to "true" if the STA interface is requested to be connected by the +// user, used for automatic reassociation. +static bool wifi_sta_connect_requested = false; + +// Set to "true" if the STA interface is connected to wifi and has IP address. +static bool wifi_sta_connected = false; + +// Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1. +static uint8_t wifi_sta_disconn_reason = 0; + +// This function is called by the system-event task and so runs in a different +// thread to the main MicroPython task. It must not raise any Python exceptions. +static esp_err_t event_handler(void *ctx, system_event_t *event) { + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + ESP_LOGI("wifi", "STA_START"); + break; + case SYSTEM_EVENT_STA_CONNECTED: + ESP_LOGI("network", "CONNECTED"); + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI("network", "GOT_IP"); + wifi_sta_connected = true; + wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway) + break; + case SYSTEM_EVENT_STA_DISCONNECTED: { + // This is a workaround as ESP32 WiFi libs don't currently + // auto-reassociate. + system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; + char *message = ""; + wifi_sta_disconn_reason = disconn->reason; + switch (disconn->reason) { + case WIFI_REASON_BEACON_TIMEOUT: + // AP has dropped out; try to reconnect. + message = "\nbeacon timeout"; + break; + case WIFI_REASON_NO_AP_FOUND: + // AP may not exist, or it may have momentarily dropped out; try to reconnect. + message = "\nno AP found"; + break; + case WIFI_REASON_AUTH_FAIL: + message = "\nauthentication failed"; + wifi_sta_connect_requested = false; + break; + default: + // Let other errors through and try to reconnect. + break; + } + ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); + + bool reconnected = false; + if (wifi_sta_connect_requested) { + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) == ESP_OK) { + if (mode & WIFI_MODE_STA) { + // STA is active so attempt to reconnect. + esp_err_t e = esp_wifi_connect(); + if (e != ESP_OK) { + ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); + } else { + reconnected = true; + } + } + } + } + if (wifi_sta_connected && !reconnected) { + // If already connected and we fail to reconnect + wifi_sta_connected = false; + } + break; + } + default: + ESP_LOGI("network", "event %d", event->event_id); + break; + } + return ESP_OK; +} + +/*void error_check(bool status, const char *msg) { + if (!status) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + } +} +*/ + +STATIC void require_if(mp_obj_t wlan_if, int if_no) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); + if (self->if_id != if_no) { + mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? "STA required" : "AP required"); + } +} + +STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + static int initialized = 0; + if (!initialized) { + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_LOGD("modnetwork", "Initializing WiFi"); + ESP_EXCEPTIONS( esp_wifi_init(&cfg) ); + ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_LOGD("modnetwork", "Initialized"); + initialized = 1; + } + + int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA; + if (idx == WIFI_IF_STA) { + return MP_OBJ_FROM_PTR(&wlan_sta_obj); + } else if (idx == WIFI_IF_AP) { + return MP_OBJ_FROM_PTR(&wlan_ap_obj); + } else { + mp_raise_ValueError("invalid WLAN interface identifier"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); + +STATIC mp_obj_t esp_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGD("modnetwork", "Initializing TCP/IP"); + tcpip_adapter_init(); + ESP_LOGD("modnetwork", "Initializing Event Loop"); + ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) ); + ESP_LOGD("modnetwork", "esp_event_loop_init done"); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize); + +#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA) +#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields! +#endif + +STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + wifi_mode_t mode; + if (!wifi_started) { + mode = WIFI_MODE_NULL; + } else { + ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); + } + + int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP; + + if (n_args > 1) { + bool active = mp_obj_is_true(args[1]); + mode = active ? (mode | bit) : (mode & ~bit); + if (mode == WIFI_MODE_NULL) { + if (wifi_started) { + ESP_EXCEPTIONS(esp_wifi_stop()); + wifi_started = false; + } + } else { + ESP_EXCEPTIONS(esp_wifi_set_mode(mode)); + if (!wifi_started) { + ESP_EXCEPTIONS(esp_wifi_start()); + wifi_started = true; + } + } + } + + return (mode & bit) ? mp_const_true : mp_const_false; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active); + +STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ssid, ARG_password, ARG_bssid }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + wifi_config_t wifi_sta_config = {{{0}}}; + + // configure any parameters that are given + if (n_args > 1) { + mp_uint_t len; + const char *p; + if (args[ARG_ssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + } + if (args[ARG_password].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); + memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); + } + if (args[ARG_bssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); + if (len != sizeof(wifi_sta_config.sta.bssid)) { + mp_raise_ValueError(NULL); + } + wifi_sta_config.sta.bssid_set = 1; + memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); + } + ESP_EXCEPTIONS( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config) ); + } + + // connect to the WiFi AP + MP_THREAD_GIL_EXIT(); + ESP_EXCEPTIONS( esp_wifi_connect() ); + MP_THREAD_GIL_ENTER(); + wifi_sta_connect_requested = true; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect); + +STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { + wifi_sta_connect_requested = false; + ESP_EXCEPTIONS( esp_wifi_disconnect() ); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); + +// Cases similar to ESP8266 user_interface.h +// Error cases are referenced from wifi_err_reason_t in ESP-IDF +enum { + STAT_IDLE = 1000, + STAT_CONNECTING = 1001, + STAT_GOT_IP = 1010, +}; + +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + if (self->if_id == WIFI_IF_STA) { + // Case of no arg is only for the STA interface + if (wifi_sta_connected) { + // Happy path, connected with IP + return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP); + } else if (wifi_sta_connect_requested) { + // No connection or error, but is requested = Still connecting + return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING); + } else if (wifi_sta_disconn_reason == 0) { + // No activity, No error = Idle + return MP_OBJ_NEW_SMALL_INT(STAT_IDLE); + } else { + // Simply pass the error through from ESP-identifier + return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason); + } + } + return mp_const_none; + } + + // one argument: return status based on query parameter + switch ((uintptr_t)args[1]) { + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { + // return list of connected stations, only if in soft-AP mode + require_if(args[0], WIFI_IF_AP); + wifi_sta_list_t station_list; + ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list)); + wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta; + mp_obj_t list = mp_obj_new_list(0, NULL); + for (int i = 0; i < station_list.num; ++i) { + mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); + t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); + mp_obj_list_append(list, t); + } + return list; + } + + default: + mp_raise_ValueError("unknown status param"); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); + +STATIC mp_obj_t esp_scan(mp_obj_t self_in) { + // check that STA mode is active + wifi_mode_t mode; + ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); + if ((mode & WIFI_MODE_STA) == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active")); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + wifi_scan_config_t config = { 0 }; + // XXX how do we scan hidden APs (and if we can scan them, are they really hidden?) + MP_THREAD_GIL_EXIT(); + esp_err_t status = esp_wifi_scan_start(&config, 1); + MP_THREAD_GIL_ENTER(); + if (status == 0) { + uint16_t count = 0; + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_num(&count) ); + wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t)); + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_records(&count, wifi_ap_records) ); + for (uint16_t i = 0; i < count; i++) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid)); + int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid); + t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len); + t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary); + t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode); + t->items[5] = mp_const_false; // XXX hidden? + mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); + } + free(wifi_ap_records); + } + return list; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); + +STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->if_id == WIFI_IF_STA) { + return mp_obj_new_bool(wifi_sta_connected); + } else { + wifi_sta_list_t sta; + esp_wifi_ap_get_sta_list(&sta); + return mp_obj_new_bool(sta.num != 0); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected); + +STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + tcpip_adapter_ip_info_t info; + tcpip_adapter_dns_info_t dns_info; + tcpip_adapter_get_ip_info(self->if_id, &info); + tcpip_adapter_get_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info); + if (n_args == 1) { + // get + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns_info.ip, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set + if (MP_OBJ_IS_TYPE(args[1], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG); + if (mp_obj_is_integer(items[1])) { + // allow numeric netmask, i.e.: + // 24 -> 255.255.255.0 + // 16 -> 255.255.0.0 + // etc... + uint32_t* m = (uint32_t*)&info.netmask; + *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1]))); + } else { + netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG); + } + netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG); + // To set a static IP we have to disable DHCP first + if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) { + esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + } else if (self->if_id == WIFI_IF_AP) { + esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); + } + } else { + // check for the correct string + const char *mode = mp_obj_str_get_str(args[1]); + if ((self->if_id != WIFI_IF_STA && self->if_id != ESP_IF_ETH) || strcmp("dhcp", mode)) { + mp_raise_ValueError("invalid arguments"); + } + ESP_EXCEPTIONS(tcpip_adapter_dhcpc_start(self->if_id)); + } + return mp_const_none; + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); + +STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError("either pos or kw args are allowed"); + } + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + // get the config for the interface + wifi_config_t cfg; + ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg)); + + if (kwargs->used != 0) { + + for (size_t i = 0; i < kwargs->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + int req_if = -1; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)kwargs->table[i].key) { + case QS(MP_QSTR_mac): { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError("invalid buffer length"); + } + ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf)); + break; + } + case QS(MP_QSTR_essid): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.ssid)); + memcpy(cfg.ap.ssid, s, len); + cfg.ap.ssid_len = len; + break; + } + case QS(MP_QSTR_hidden): { + req_if = WIFI_IF_AP; + cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_authmode): { + req_if = WIFI_IF_AP; + cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_password): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.password) - 1); + memcpy(cfg.ap.password, s, len); + cfg.ap.password[len] = 0; + break; + } + case QS(MP_QSTR_channel): { + req_if = WIFI_IF_AP; + cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_dhcp_hostname): { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); + break; + } + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + } + } + + ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg)); + + return mp_const_none; + } + + // Get config + + if (n_args != 2) { + mp_raise_TypeError("can query only one param"); + } + + int req_if = -1; + mp_obj_t val; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)args[1]) { + case QS(MP_QSTR_mac): { + uint8_t mac[6]; + ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac)); + return mp_obj_new_bytes(mac, sizeof(mac)); + } + case QS(MP_QSTR_essid): + if (self->if_id == WIFI_IF_STA) { + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + } else { + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + } + break; + case QS(MP_QSTR_hidden): + req_if = WIFI_IF_AP; + val = mp_obj_new_bool(cfg.ap.ssid_hidden); + break; + case QS(MP_QSTR_authmode): + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); + break; + case QS(MP_QSTR_channel): + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); + break; + case QS(MP_QSTR_dhcp_hostname): { + const char *s; + ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s)); + val = mp_obj_new_str(s, strlen(s)); + break; + } + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + return val; + +unknown: + mp_raise_ValueError("unknown config param"); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); + +STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); + +const mp_obj_type_t wlan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_WLAN, + .locals_dict = (mp_obj_t)&wlan_if_locals_dict, +}; + +STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); + + +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, + { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, + { MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) }, + { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, + +#if MODNETWORK_INCLUDE_CONSTANTS + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)}, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)}, + + { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) }, + + { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) }, + + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, + { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) }, + + { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)}, + { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)}, + { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STAT_GOT_IP)}, + // Errors from the ESP-IDF + { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(WIFI_REASON_NO_AP_FOUND)}, + { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(WIFI_REASON_AUTH_FAIL)}, + { MP_ROM_QSTR(MP_QSTR_STAT_BEACON_TIMEOUT), MP_ROM_INT(WIFI_REASON_BEACON_TIMEOUT)}, + { MP_ROM_QSTR(MP_QSTR_STAT_ASSOC_FAIL), MP_ROM_INT(WIFI_REASON_ASSOC_FAIL)}, + { MP_ROM_QSTR(MP_QSTR_STAT_HANDSHAKE_TIMEOUT), MP_ROM_INT(WIFI_REASON_HANDSHAKE_TIMEOUT)}, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp32/modnetwork.h b/src/openmv/src/micropython/ports/esp32/modnetwork.h new file mode 100755 index 0000000..f39a291 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modnetwork.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H +#define MICROPY_INCLUDED_ESP32_MODNETWORK_H + +enum { PHY_LAN8720, PHY_TLK110 }; + +MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); +MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj); + +void usocket_events_deinit(void); + +#endif diff --git a/src/openmv/src/micropython/ports/esp32/modsocket.c b/src/openmv/src/micropython/ports/esp32/modsocket.c new file mode 100755 index 0000000..d337760 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modsocket.c @@ -0,0 +1,708 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * + * Based on extmod/modlwip.c + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Galen Hazelwood + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/runtime0.h" +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" +#include "tcpip_adapter.h" +#include "modnetwork.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" +#include "lwip/ip4.h" +#include "lwip/igmp.h" +#include "esp_log.h" + +#define SOCKET_POLL_US (100000) + +typedef struct _socket_obj_t { + mp_obj_base_t base; + int fd; + uint8_t domain; + uint8_t type; + uint8_t proto; + bool peer_closed; + unsigned int retries; + #if MICROPY_PY_USOCKET_EVENTS + mp_obj_t events_callback; + struct _socket_obj_t *events_next; + #endif +} socket_obj_t; + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms); + +#if MICROPY_PY_USOCKET_EVENTS +// Support for callbacks on asynchronous socket events (when socket becomes readable) + +// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often +#define USOCKET_EVENTS_DIVISOR (8) + +STATIC uint8_t usocket_events_divisor; +STATIC socket_obj_t *usocket_events_head; + +void usocket_events_deinit(void) { + usocket_events_head = NULL; +} + +// Assumes the socket is not already in the linked list, and adds it +STATIC void usocket_events_add(socket_obj_t *sock) { + sock->events_next = usocket_events_head; + usocket_events_head = sock; +} + +// Assumes the socket is already in the linked list, and removes it +STATIC void usocket_events_remove(socket_obj_t *sock) { + for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) { + if (*s == sock) { + *s = (*s)->events_next; + return; + } + } +} + +// Polls all registered sockets for readability and calls their callback if they are readable +void usocket_events_handler(void) { + if (usocket_events_head == NULL) { + return; + } + if (--usocket_events_divisor) { + return; + } + usocket_events_divisor = USOCKET_EVENTS_DIVISOR; + + fd_set rfds; + FD_ZERO(&rfds); + int max_fd = 0; + + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + FD_SET(s->fd, &rfds); + max_fd = MAX(max_fd, s->fd); + } + + // Poll the sockets + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + int r = select(max_fd + 1, &rfds, NULL, NULL, &timeout); + if (r <= 0) { + return; + } + + // Call the callbacks + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + if (FD_ISSET(s->fd, &rfds)) { + mp_call_function_1_protected(s->events_callback, s); + } + } +} + +#endif // MICROPY_PY_USOCKET_EVENTS + +NORETURN static void exception_from_errno(int _errno) { + // Here we need to convert from lwip errno values to MicroPython's standard ones + if (_errno == EINPROGRESS) { + _errno = MP_EINPROGRESS; + } + mp_raise_OSError(_errno); +} + +static inline void check_for_exceptions(void) { + mp_handle_pending(); +} + +static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + + mp_obj_t port = portx; + if (MP_OBJ_IS_SMALL_INT(port)) { + // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but + // that's the API we have to work with ... + port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr("%s", 2), port); + } + + const char *host_str = mp_obj_str_get_str(host); + const char *port_str = mp_obj_str_get_str(port); + + if (host_str[0] == '\0') { + // a host of "" is equivalent to the default/all-local IP address + host_str = "0.0.0.0"; + } + + MP_THREAD_GIL_EXIT(); + int res = lwip_getaddrinfo(host_str, port_str, &hints, resp); + MP_THREAD_GIL_ENTER(); + + return res; +} + +int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(addrtuple, &len, &elem); + if (len != 2) return -1; + return _socket_getaddrinfo2(elem[0], elem[1], resp); +} + +STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + int r = lwip_bind_r(self->fd, res->ai_addr, res->ai_addrlen); + lwip_freeaddrinfo(res); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + int backlog = mp_obj_get_int(arg1); + int r = lwip_listen_r(self->fd, backlog); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + + int new_fd = -1; + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + new_fd = lwip_accept_r(self->fd, &addr, &addr_len); + MP_THREAD_GIL_ENTER(); + if (new_fd >= 0) break; + if (errno != EAGAIN) exception_from_errno(errno); + check_for_exceptions(); + } + if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT); + + // create new socket object + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = self->base.type; + sock->fd = new_fd; + sock->domain = self->domain; + sock->type = self->type; + sock->proto = self->proto; + sock->peer_closed = false; + _socket_settimeout(sock, UINT64_MAX); + + // make the return value + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&addr)->sin_port); + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = sock; + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return client; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + MP_THREAD_GIL_EXIT(); + int r = lwip_connect_r(self->fd, res->ai_addr, res->ai_addrlen); + MP_THREAD_GIL_ENTER(); + lwip_freeaddrinfo(res); + if (r != 0) { + exception_from_errno(errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + int opt = mp_obj_get_int(args[2]); + + switch (opt) { + // level: SOL_SOCKET + case SO_REUSEADDR: { + int val = mp_obj_get_int(args[3]); + int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); + if (ret != 0) { + exception_from_errno(errno); + } + break; + } + + #if MICROPY_PY_USOCKET_EVENTS + // level: SOL_SOCKET + // special "register callback" option + case 20: { + if (args[3] == mp_const_none) { + if (self->events_callback != MP_OBJ_NULL) { + usocket_events_remove(self); + self->events_callback = MP_OBJ_NULL; + } + } else { + if (self->events_callback == MP_OBJ_NULL) { + usocket_events_add(self); + } + self->events_callback = args[3]; + } + break; + } + #endif + + // level: IPPROTO_IP + case IP_ADD_MEMBERSHIP: { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != sizeof(ip4_addr_t) * 2) { + mp_raise_ValueError(NULL); + } + + // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa + err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf); + if (err != ERR_OK) { + mp_raise_OSError(-err); + } + break; + } + + default: + mp_printf(&mp_plat_print, "Warning: lwip.setsockopt() option not implemented\n"); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) { + // Rather than waiting for the entire timeout specified, we wait sock->retries times + // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts. + // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years. + // if timeout_ms == UINT64_MAX, wait forever. + sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US; + + struct timeval timeout = { + .tv_sec = 0, + .tv_usec = timeout_ms ? SOCKET_POLL_US : 0 + }; + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_fcntl_r(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK); +} + +STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX); + else { + #if MICROPY_PY_BUILTINS_FLOAT + _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L); + #else + _socket_settimeout(self, mp_obj_get_int(arg1) * 1000); + #endif + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX); + else _socket_settimeout(self, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +// XXX this can end up waiting a very long time if the content is dribbled in one character +// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not +// good behaviour. +STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, + struct sockaddr *from, socklen_t *from_len, int *errcode) { + socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + + // If the peer closed the connection then the lwIP socket API will only return "0" once + // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour, + // which continues to return "0" for each call on a closed socket, we set a flag when + // the peer closed the socket. + if (sock->peer_closed) { + return 0; + } + + // XXX Would be nicer to use RTC to handle timeouts + for (int i = 0; i <= sock->retries; ++i) { + MP_THREAD_GIL_EXIT(); + int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len); + MP_THREAD_GIL_ENTER(); + if (r == 0) { + sock->peer_closed = true; + } + if (r >= 0) { + return r; + } + if (errno != EWOULDBLOCK) { + *errcode = errno; + return MP_STREAM_ERROR; + } + check_for_exceptions(); + } + + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, + struct sockaddr *from, socklen_t *from_len) { + size_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + + int errcode; + mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode); + if (ret == MP_STREAM_ERROR) { + exception_from_errno(errcode); + } + + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + return _socket_recvfrom(self_in, len_in, NULL, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + struct sockaddr from; + socklen_t fromlen = sizeof(from); + + mp_obj_t tuple[2]; + tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen); + + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&from)->sin_port); + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { + int sentlen = 0; + for (int i=0; i<=sock->retries && sentlen < datalen; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen); + MP_THREAD_GIL_ENTER(); + if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno); + if (r > 0) sentlen += r; + check_for_exceptions(); + } + if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT); + return sentlen; +} + +STATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_uint_t datalen; + const char *data = mp_obj_str_get_data(arg1, &datalen); + int r = _socket_send(sock, data, datalen); + return mp_obj_new_int(r); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +STATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) { + // XXX behaviour when nonblocking (see extmod/modlwip.c) + // XXX also timeout behaviour. + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ); + int r = _socket_send(sock, bufinfo.buf, bufinfo.len); + if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall); + +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the buffer to send + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // create the destination address + struct sockaddr_in to; + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG)); + + // send the data + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to)); + MP_THREAD_GIL_ENTER(); + if (ret > 0) return mp_obj_new_int_from_uint(ret); + if (ret == -1 && errno != EWOULDBLOCK) { + exception_from_errno(errno); + } + check_for_exceptions(); + } + mp_raise_OSError(MP_ETIMEDOUT); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +STATIC mp_obj_t socket_fileno(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + return mp_obj_new_int(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + +STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + return _socket_read_data(self_in, buf, size, NULL, NULL, errcode); +} + +STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *sock = self_in; + for (int i=0; i<=sock->retries; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, buf, size); + MP_THREAD_GIL_ENTER(); + if (r > 0) return r; + if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } + check_for_exceptions(); + } + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t * socket = self_in; + if (request == MP_STREAM_POLL) { + + fd_set rfds; FD_ZERO(&rfds); + fd_set wfds; FD_ZERO(&wfds); + fd_set efds; FD_ZERO(&efds); + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds); + if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds); + if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds); + + int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout); + if (r < 0) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + mp_uint_t ret = 0; + if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD; + if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR; + if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP; + return ret; + } else if (request == MP_STREAM_CLOSE) { + if (socket->fd >= 0) { + #if MICROPY_PY_USOCKET_EVENTS + if (socket->events_callback != MP_OBJ_NULL) { + usocket_events_remove(socket); + socket->events_callback = MP_OBJ_NULL; + } + #endif + int ret = lwip_close_r(socket->fd); + if (ret != 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->fd = -1; + } + return 0; + } + + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; +} + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +STATIC const mp_stream_p_t socket_stream_p = { + .read = socket_stream_read, + .write = socket_stream_write, + .ioctl = socket_stream_ioctl +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = &socket_type; + sock->domain = AF_INET; + sock->type = SOCK_STREAM; + sock->proto = 0; + sock->peer_closed = false; + if (n_args > 0) { + sock->domain = mp_obj_get_int(args[0]); + if (n_args > 1) { + sock->type = mp_obj_get_int(args[1]); + if (n_args > 2) { + sock->proto = mp_obj_get_int(args[2]); + } + } + } + + sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); + if (sock->fd < 0) { + exception_from_errno(errno); + } + _socket_settimeout(sock, UINT64_MAX); + + return MP_OBJ_FROM_PTR(sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); + +STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { + // TODO support additional args beyond the first two + + struct addrinfo *res = NULL; + _socket_getaddrinfo2(args[0], args[1], &res); + mp_obj_t ret_list = mp_obj_new_list(0, NULL); + + for (struct addrinfo *resi = res; resi; resi = resi->ai_next) { + mp_obj_t addrinfo_objs[5] = { + mp_obj_new_int(resi->ai_family), + mp_obj_new_int(resi->ai_socktype), + mp_obj_new_int(resi->ai_protocol), + mp_obj_new_str(resi->ai_canonname, strlen(resi->ai_canonname)), + mp_const_none + }; + + if (resi->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)resi->ai_addr; + // This looks odd, but it's really just a u32_t + ip4_addr_t ip4_addr = { .addr = addr->sin_addr.s_addr }; + char buf[16]; + ip4addr_ntoa_r(&ip4_addr, buf, sizeof(buf)); + mp_obj_t inaddr_objs[2] = { + mp_obj_new_str(buf, strlen(buf)), + mp_obj_new_int(ntohs(addr->sin_port)) + }; + addrinfo_objs[4] = mp_obj_new_tuple(2, inaddr_objs); + } + mp_obj_list_append(ret_list, mp_obj_new_tuple(5, addrinfo_objs)); + } + + if (res) lwip_freeaddrinfo(res); + return ret_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo); + +STATIC mp_obj_t esp_socket_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGI("modsocket", "Initializing"); + tcpip_adapter_init(); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize); + +STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) }, + + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) }, + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_socket_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp32/modules/_boot.py b/src/openmv/src/micropython/ports/esp32/modules/_boot.py new file mode 100755 index 0000000..bf40ea3 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/_boot.py @@ -0,0 +1,12 @@ +import gc +import uos +from flashbdev import bdev + +try: + if bdev: + uos.mount(bdev, '/') +except OSError: + import inisetup + vfs = inisetup.setup() + +gc.collect() diff --git a/src/openmv/src/micropython/ports/esp32/modules/apa106.py b/src/openmv/src/micropython/ports/esp32/modules/apa106.py new file mode 100755 index 0000000..ef971d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/src/openmv/src/micropython/ports/esp32/modules/dht.py b/src/openmv/src/micropython/ports/esp32/modules/dht.py new file mode 100755 index 0000000..2aa2f5c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/ds18x20.py b/src/openmv/src/micropython/ports/esp32/modules/ds18x20.py new file mode 100755 index 0000000..9721929 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/ds18x20.py @@ -0,0 +1 @@ +../../esp8266/modules/ds18x20.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/flashbdev.py b/src/openmv/src/micropython/ports/esp32/modules/flashbdev.py new file mode 100755 index 0000000..935f534 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/flashbdev.py @@ -0,0 +1,34 @@ +import esp + +class FlashBdev: + + SEC_SIZE = 4096 + START_SEC = esp.flash_user_start() // SEC_SIZE + + def __init__(self, blocks): + self.blocks = blocks + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf) + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + #assert len(buf) <= self.SEC_SIZE, len(buf) + esp.flash_erase(n + self.START_SEC) + esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf) + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return self.blocks + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + +size = esp.flash_size() +if size < 1024*1024: + # flash too small for a filesystem + bdev = None +else: + # for now we use a fixed size for the filesystem + bdev = FlashBdev(2048 * 1024 // FlashBdev.SEC_SIZE) diff --git a/src/openmv/src/micropython/ports/esp32/modules/inisetup.py b/src/openmv/src/micropython/ports/esp32/modules/inisetup.py new file mode 100755 index 0000000..0e9c72f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/inisetup.py @@ -0,0 +1,42 @@ +import uos +from flashbdev import bdev + +def check_bootsec(): + buf = bytearray(bdev.SEC_SIZE) + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xff: + empty = False + break + if empty: + return True + fs_corrupted() + +def fs_corrupted(): + import time + while 1: + print("""\ +FAT filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""") + time.sleep(3) + +def setup(): + check_bootsec() + print("Performing initial setup") + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/flash') + uos.chdir('/flash') + with open("boot.py", "w") as f: + f.write("""\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""") + return vfs diff --git a/src/openmv/src/micropython/ports/esp32/modules/neopixel.py b/src/openmv/src/micropython/ports/esp32/modules/neopixel.py new file mode 100755 index 0000000..86c1586 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/neopixel.py @@ -0,0 +1,33 @@ +# NeoPixel driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from esp import neopixel_write + + +class NeoPixel: + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=0): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + self.timing = timing + + def __setitem__(self, index, val): + offset = index * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = val[i] + + def __getitem__(self, index): + offset = index * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] + for i in range(self.bpp)) + + def fill(self, color): + for i in range(self.n): + self[i] = color + + def write(self): + neopixel_write(self.pin, self.buf, self.timing) diff --git a/src/openmv/src/micropython/ports/esp32/modules/ntptime.py b/src/openmv/src/micropython/ports/esp32/modules/ntptime.py new file mode 100755 index 0000000..e90900d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/ntptime.py @@ -0,0 +1 @@ +../../esp8266/modules/ntptime.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/onewire.py b/src/openmv/src/micropython/ports/esp32/modules/onewire.py new file mode 100755 index 0000000..0916294 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/onewire.py @@ -0,0 +1 @@ +../../esp8266/modules/onewire.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/umqtt/robust.py b/src/openmv/src/micropython/ports/esp32/modules/umqtt/robust.py new file mode 100755 index 0000000..6bfbbcf --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/umqtt/robust.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.robust/umqtt/robust.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/umqtt/simple.py b/src/openmv/src/micropython/ports/esp32/modules/umqtt/simple.py new file mode 100755 index 0000000..6419a46 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/umqtt/simple.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.simple/umqtt/simple.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/upip.py b/src/openmv/src/micropython/ports/esp32/modules/upip.py new file mode 100755 index 0000000..130eb69 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/upip.py @@ -0,0 +1 @@ +../../../tools/upip.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/upip_utarfile.py b/src/openmv/src/micropython/ports/esp32/modules/upip_utarfile.py new file mode 100755 index 0000000..d9653d6 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/upip_utarfile.py @@ -0,0 +1 @@ +../../../tools/upip_utarfile.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/upysh.py b/src/openmv/src/micropython/ports/esp32/modules/upysh.py new file mode 100755 index 0000000..12d100c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/upysh.py @@ -0,0 +1 @@ +../../../../micropython-lib/upysh/upysh.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/urequests.py b/src/openmv/src/micropython/ports/esp32/modules/urequests.py new file mode 100755 index 0000000..7666111 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/urequests.py @@ -0,0 +1 @@ +../../../../micropython-lib/urequests/urequests.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/webrepl.py b/src/openmv/src/micropython/ports/esp32/modules/webrepl.py new file mode 100755 index 0000000..2a3987a --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/webrepl.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/webrepl_setup.py b/src/openmv/src/micropython/ports/esp32/modules/webrepl_setup.py new file mode 100755 index 0000000..999888b --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/webrepl_setup.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl_setup.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/modules/websocket_helper.py b/src/openmv/src/micropython/ports/esp32/modules/websocket_helper.py new file mode 100755 index 0000000..4bcf3bc --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modules/websocket_helper.py @@ -0,0 +1 @@ +../../esp8266/modules/websocket_helper.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp32/moduos.c b/src/openmv/src/micropython/ports/esp32/moduos.c new file mode 100755 index 0000000..dc85136 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/moduos.c @@ -0,0 +1,134 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "esp_system.h" + +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" + +extern const mp_obj_type_t mp_fat_vfs_type; + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + uint32_t r = 0; + for (int i = 0; i < n; i++) { + if ((i & 3) == 0) { + r = esp_random(); // returns 32-bit hardware random number + } + vstr.buf[i] = r; + r >>= 8; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +#if MICROPY_PY_OS_DUPTERM +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + for (;;) { + int c = mp_uos_dupterm_rx_chr(); + if (c < 0) { + break; + } + ringbuf_put(&stdin_ringbuf, c); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); +#endif + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, + #endif + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t uos_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp32/modutime.c b/src/openmv/src/micropython/ports/esp32/modutime.c new file mode 100755 index 0000000..0028542 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/modutime.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + struct timeval tv; + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + } else { + seconds = mp_obj_get_int(args[0]); + } + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +STATIC mp_obj_t time_time(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return mp_obj_new_int(tv.tv_sec); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t utime_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp32/mpconfigport.h b/src/openmv/src/micropython/ports/esp32/mpconfigport.h new file mode 100755 index 0000000..0f8deb1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/mpconfigport.h @@ -0,0 +1,269 @@ +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. + +#include +#include +#include "rom/ets_sys.h" + +// object representation and NLR handling +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) +#define MICROPY_NLR_SETJMP (1) + +// memory allocation policies +#define MICROPY_ALLOC_PATH_MAX (128) + +// emitters +#define MICROPY_PERSISTENT_CODE_LOAD (1) + +// compiler configuration +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) + +// optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_MPZ_BITWISE (1) + +// Python internal features +#define MICROPY_READER_VFS (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#define MICROPY_WARNINGS (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_MODULE_FROZEN_STR (0) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (1) + +// control over Python builtins +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_ATTRTUPLE (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO_BYTESIO (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_MODULES (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (1) +#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) + +// extended modules +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UHASHLIB_SHA1 (1) +#define MICROPY_PY_UHASHLIB_SHA256 (1) +#define MICROPY_PY_UCRYPTOLIB (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (1) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_PY_USSL (1) +#define MICROPY_SSL_MBEDTLS (1) +#define MICROPY_PY_USSL_FINALISER (1) +#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) + +// fatfs configuration +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t esp32_module; +extern const struct _mp_obj_module_t utime_module; +extern const struct _mp_obj_module_t uos_module; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_onewire; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_zlib), (mp_obj_t)&mp_module_uzlib }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t machine_pin_irq_handler[40]; \ + +// type definitions for the specific machine + +#define BYTES_PER_WORD (4) +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#define MP_SSIZE_MAX (0x7fffffff) + +// Note: these "critical nested" macros do not ensure cross-CPU exclusion, +// the only disable interrupts on the current CPU. To full manage exclusion +// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead. +#include "freertos/FreeRTOS.h" +#define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED() +#define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state) + +#if MICROPY_PY_USOCKET_EVENTS +#define MICROPY_PY_USOCKET_EVENTS_HANDLER extern void usocket_events_handler(void); usocket_events_handler(); +#else +#define MICROPY_PY_USOCKET_EVENTS_HANDLER +#endif + +#if MICROPY_PY_THREAD +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ + MP_THREAD_GIL_EXIT(); \ + MP_THREAD_GIL_ENTER(); \ + } while (0); +#else +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ + asm("waiti 0"); \ + } while (0); +#endif + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; +// ssize_t, off_t as required by POSIX-signatured functions in stream.h +#include + +// board specifics + +#define MICROPY_HW_BOARD_NAME "ESP32 module" +#define MICROPY_HW_MCU_NAME "ESP32" +#define MICROPY_PY_SYS_PLATFORM "esp32" diff --git a/src/openmv/src/micropython/ports/esp32/mphalport.c b/src/openmv/src/micropython/ports/esp32/mphalport.c new file mode 100755 index 0000000..aa79c87 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/mphalport.c @@ -0,0 +1,168 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/uart.h" + +#include "py/obj.h" +#include "py/mpstate.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "lib/utils/pyexec.h" +#include "mphalport.h" + +TaskHandle_t mp_main_task_handle; + +STATIC uint8_t stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; + } + MICROPY_EVENT_POLL_HOOK + ulTaskNotifyTake(pdFALSE, 1); + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { + MP_THREAD_GIL_EXIT(); + for (uint32_t i = 0; i < len; ++i) { + uart_tx_one_char(str[i]); + } + MP_THREAD_GIL_ENTER(); + mp_uos_dupterm_tx_strn(str, len); +} + +// Efficiently convert "\n" to "\r\n" +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + const char *last = str; + while (len--) { + if (*str == '\n') { + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } + mp_hal_stdout_tx_strn("\r\n", 2); + ++str; + last = str; + } else { + ++str; + } + } + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } +} + +uint32_t mp_hal_ticks_ms(void) { + return esp_timer_get_time() / 1000; +} + +uint32_t mp_hal_ticks_us(void) { + return esp_timer_get_time(); +} + +void mp_hal_delay_ms(uint32_t ms) { + uint64_t us = ms * 1000; + uint64_t dt; + uint64_t t0 = esp_timer_get_time(); + for (;;) { + uint64_t t1 = esp_timer_get_time(); + dt = t1 - t0; + if (dt + portTICK_PERIOD_MS * 1000 >= us) { + // doing a vTaskDelay would take us beyond requested delay time + break; + } + MICROPY_EVENT_POLL_HOOK + ulTaskNotifyTake(pdFALSE, 1); + } + if (dt < us) { + // do the remaining delay accurately + mp_hal_delay_us(us - dt); + } +} + +void mp_hal_delay_us(uint32_t us) { + // these constants are tested for a 240MHz clock + const uint32_t this_overhead = 5; + const uint32_t pend_overhead = 150; + + // return if requested delay is less than calling overhead + if (us < this_overhead) { + return; + } + us -= this_overhead; + + uint64_t t0 = esp_timer_get_time(); + for (;;) { + uint64_t dt = esp_timer_get_time() - t0; + if (dt >= us) { + return; + } + if (dt + pend_overhead < us) { + // we have enough time to service pending events + // (don't use MICROPY_EVENT_POLL_HOOK because it also yields) + mp_handle_pending(); + } + } +} + +// this function could do with improvements (eg use ets_delay_us) +void mp_hal_delay_us_fast(uint32_t us) { + uint32_t delay = ets_get_cpu_frequency() / 19; + while (--us) { + for (volatile uint32_t i = delay; i; --i) { + } + } +} + +/* +extern int mp_stream_errno; +int *__errno() { + return &mp_stream_errno; +} +*/ + +// Wake up the main task if it is sleeping +void mp_hal_wake_main_task_from_isr(void) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + vTaskNotifyGiveFromISR(mp_main_task_handle, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} diff --git a/src/openmv/src/micropython/ports/esp32/mphalport.h b/src/openmv/src/micropython/ports/esp32/mphalport.h new file mode 100755 index 0000000..b829627 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/mphalport.h @@ -0,0 +1,94 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef INCLUDED_MPHALPORT_H +#define INCLUDED_MPHALPORT_H + +#include "py/ringbuf.h" +#include "lib/utils/interrupt_char.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +extern TaskHandle_t mp_main_task_handle; + +extern ringbuf_t stdin_ringbuf; + +uint32_t mp_hal_ticks_us(void); +__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +void mp_hal_delay_us(uint32_t); +void mp_hal_delay_us_fast(uint32_t); +void mp_hal_set_interrupt_char(int c); +uint32_t mp_hal_get_cpu_freq(void); + +#define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION() +#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state) + +// Wake up the main task if it is sleeping +void mp_hal_wake_main_task_from_isr(void); + +// C-level pin HAL +#include "py/obj.h" +#include "driver/gpio.h" +#define MP_HAL_PIN_FMT "%u" +#define mp_hal_pin_obj_t gpio_num_t +mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in); +#define mp_hal_get_pin_obj(o) machine_pin_get_id(o) +#define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire +#define mp_hal_pin_name(p) (p) +static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT); +} +static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT); +} +static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD); +} +static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 0); +} +static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 1); +} +static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) { + return gpio_get_level(pin); +} +static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) { + gpio_set_level(pin, v); +} + +#endif // INCLUDED_MPHALPORT_H diff --git a/src/openmv/src/micropython/ports/esp32/mpthreadport.c b/src/openmv/src/micropython/ports/esp32/mpthreadport.c new file mode 100755 index 0000000..76d9431 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/mpthreadport.c @@ -0,0 +1,226 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "stdio.h" + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "mpthreadport.h" + +#include "esp_task.h" + +#if MICROPY_PY_THREAD + +#define MP_THREAD_MIN_STACK_SIZE (4 * 1024) +#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024) +#define MP_THREAD_PRIORITY (ESP_TASK_PRIO_MIN + 1) + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + StaticTask_t *tcb; // pointer to the Task Control Block + size_t stack_len; // number of words in the stack + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others + +void mp_thread_init(void *stack, uint32_t stack_len) { + mp_thread_set_state(&mp_state_ctx.thread); + // create the first entry in the linked list of all threads + thread = &thread_entry0; + thread->id = xTaskGetCurrentTaskHandle(); + thread->ready = 1; + thread->arg = NULL; + thread->stack = stack; + thread->stack_len = stack_len; + thread->next = NULL; + mp_thread_mutex_init(&thread_mutex); +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); // probably not needed + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); // probably not needed + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 1); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 1, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;); +} + +void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (*stack_size == 0) { + *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size + } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) { + *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size + } + + // allocate TCB, stack and linked-list node (must be outside thread_mutex lock) + StaticTask_t *tcb = m_new(StaticTask_t, 1); + StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t)); + thread_t *th = m_new_obj(thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + TaskHandle_t id = xTaskCreateStaticPinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, stack, tcb, 0); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + } + + // adjust the stack_size to provide room to recover from hitting the limit + *stack_size -= 1024; + + // add thread to linked list of all threads + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->tcb = tcb; + th->stack_len = *stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread"); +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void vPortCleanUpTCB(void *tcb) { + thread_t *prev = NULL; + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; prev = th, th = th->next) { + // unlink the node from the list + if (th->tcb == tcb) { + if (prev != NULL) { + prev->next = th->next; + } else { + // move the start pointer + thread = th->next; + } + // explicitly release all its memory + m_del(StaticTask_t, th->tcb, 1); + m_del(StackType_t, th->stack, th->stack_len); + m_del(thread_t, th, 1); + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + return (pdTRUE == xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0)); +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + xSemaphoreGive(mutex->handle); +} + +void mp_thread_deinit(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + // don't delete the current task + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + vTaskDelete(th->id); + } + mp_thread_mutex_unlock(&thread_mutex); + // allow FreeRTOS to clean-up the threads + vTaskDelay(2); +} + +#else + +void vPortCleanUpTCB(void *tcb) { +} + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/ports/esp32/mpthreadport.h b/src/openmv/src/micropython/ports/esp32/mpthreadport.h new file mode 100755 index 0000000..54e35d6 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/mpthreadport.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MPTHREADPORT_H +#define MICROPY_INCLUDED_ESP32_MPTHREADPORT_H + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +typedef struct _mp_thread_mutex_t { + SemaphoreHandle_t handle; + StaticSemaphore_t buffer; +} mp_thread_mutex_t; + +void mp_thread_init(void *stack, uint32_t stack_len); +void mp_thread_gc_others(void); +void mp_thread_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MPTHREADPORT_H diff --git a/src/openmv/src/micropython/ports/esp32/network_lan.c b/src/openmv/src/micropython/ports/esp32/network_lan.c new file mode 100755 index 0000000..fba4de7 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/network_lan.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Based on the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "eth_phy/phy.h" +#include "eth_phy/phy_tlk110.h" +#include "eth_phy/phy_lan8720.h" +#include "tcpip_adapter.h" + +#include "modnetwork.h" + +typedef struct _lan_if_obj_t { + mp_obj_base_t base; + int if_id; // MUST BE FIRST to match wlan_if_obj_t + bool initialized; + bool active; + uint8_t mdc_pin; + uint8_t mdio_pin; + int8_t phy_power_pin; + uint8_t phy_addr; + uint8_t phy_type; + eth_phy_check_link_func link_func; + eth_phy_power_enable_func power_func; +} lan_if_obj_t; + +const mp_obj_type_t lan_if_type; +STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false}; + +STATIC void phy_power_enable(bool enable) { + lan_if_obj_t* self = &lan_obj; + + if (self->phy_power_pin != -1) { + + if (!enable) { + // Do the PHY-specific power_enable(false) function before powering down + self->power_func(false); + } + + gpio_pad_select_gpio(self->phy_power_pin); + gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT); + if (enable) { + gpio_set_level(self->phy_power_pin, 1); + } else { + gpio_set_level(self->phy_power_pin, 0); + } + + // Allow the power up/down to take effect, min 300us + vTaskDelay(1); + + if (enable) { + // Run the PHY-specific power on operations now the PHY has power + self->power_func(true); + } + } +} + +STATIC void init_lan_rmii() { + lan_if_obj_t* self = &lan_obj; + phy_rmii_configure_data_interface_pins(); + phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin); +} + +STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + lan_if_obj_t* self = &lan_obj; + + if (self->initialized) { + return MP_OBJ_FROM_PTR(&lan_obj); + } + + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_id].u_obj != mp_const_none) { + if (mp_obj_get_int(args[ARG_id].u_obj) != 0) { + mp_raise_ValueError("invalid LAN interface identifier"); + } + } + + self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj); + self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj); + self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj); + + if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) { + mp_raise_ValueError("invalid phy address"); + } + + if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) { + mp_raise_ValueError("invalid phy type"); + } + + eth_config_t config; + + switch (args[ARG_phy_type].u_int) { + case PHY_TLK110: + config = phy_tlk110_default_ethernet_config; + break; + case PHY_LAN8720: + config = phy_lan8720_default_ethernet_config; + break; + } + + self->link_func = config.phy_check_link; + + // Replace default power func with our own + self->power_func = config.phy_power_enable; + config.phy_power_enable = phy_power_enable; + + config.phy_addr = args[ARG_phy_addr].u_int; + config.gpio_config = init_lan_rmii; + config.tcpip_input = tcpip_adapter_eth_input; + + if (esp_eth_init(&config) == ESP_OK) { + self->active = false; + self->initialized = true; + } else { + mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed"); + } + return MP_OBJ_FROM_PTR(&lan_obj); +} +MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan); + +STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (n_args > 1) { + if (mp_obj_is_true(args[1])) { + self->active = (esp_eth_enable() == ESP_OK); + if (!self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet enable failed"); + } + } else { + self->active = !(esp_eth_disable() == ESP_OK); + if (self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet disable failed"); + } + } + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active); + +STATIC mp_obj_t lan_status(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status); + +STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected); + +STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table); + +const mp_obj_type_t lan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_LAN, + .locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/network_ppp.c b/src/openmv/src/micropython/ports/esp32/network_ppp.c new file mode 100755 index 0000000..27dd5e0 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/network_ppp.c @@ -0,0 +1,221 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 "Eric Poulsen" + * + * Based on the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/objtype.h" +#include "py/stream.h" +#include "netutils.h" +#include "modmachine.h" + +#include "netif/ppp/ppp.h" +#include "netif/ppp/pppos.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" +#include "lwip/pppapi.h" + +typedef struct _ppp_if_obj_t { + mp_obj_base_t base; + bool active; + bool connected; + ppp_pcb *pcb; + mp_obj_t stream; + SemaphoreHandle_t inactiveWaitSem; + TaskHandle_t client_task_handle; + struct netif pppif; +} ppp_if_obj_t; + +const mp_obj_type_t ppp_if_type; + +static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { + ppp_if_obj_t* self = ctx; + struct netif *pppif = ppp_netif(self->pcb); + + switch (err_code) { + case PPPERR_NONE: + self->connected = (pppif->ip_addr.u_addr.ip4.addr != 0); + break; + case PPPERR_USER: + xSemaphoreGive(self->inactiveWaitSem); + break; + case PPPERR_CONNECT: + self->connected = false; + break; + default: + break; + } +} + +STATIC mp_obj_t ppp_make_new(mp_obj_t stream) { + mp_get_stream_raise(stream, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE); + + ppp_if_obj_t *self = m_new_obj_with_finaliser(ppp_if_obj_t); + + self->base.type = &ppp_if_type; + self->stream = stream; + self->active = false; + self->connected = false; + self->inactiveWaitSem = xSemaphoreCreateBinary(); + self->client_task_handle = NULL; + + assert(self->inactiveWaitSem != NULL); + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(ppp_make_new_obj, ppp_make_new); + +static u32_t ppp_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { + ppp_if_obj_t *self = ctx; + int err; + return mp_stream_rw(self->stream, data, len, &err, MP_STREAM_RW_WRITE); +} + +static void pppos_client_task(void *self_in) { + ppp_if_obj_t *self = (ppp_if_obj_t*)self_in; + uint8_t buf[256]; + + while (ulTaskNotifyTake(pdTRUE, 0) == 0) { + int err; + int len = mp_stream_rw(self->stream, buf, sizeof(buf), &err, 0); + if (len > 0) { + pppos_input_tcpip(self->pcb, (u8_t*)buf, len); + } + } + vTaskDelete(NULL); +} + +STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) { + ppp_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (n_args > 1) { + if (mp_obj_is_true(args[1])) { + if (self->active) { + return mp_const_true; + } + + self->pcb = pppapi_pppos_create(&self->pppif, ppp_output_callback, ppp_status_cb, self); + + if (self->pcb == NULL) { + mp_raise_msg(&mp_type_RuntimeError, "init failed"); + } + pppapi_set_default(self->pcb); + pppapi_connect(self->pcb, 0); + + xTaskCreate(pppos_client_task, "ppp", 2048, self, 1, &self->client_task_handle); + self->active = true; + } else { + if (!self->active) { + return mp_const_false; + } + + // Wait for PPPERR_USER + pppapi_close(self->pcb, 0); + xSemaphoreTake(self->inactiveWaitSem, portMAX_DELAY); + xSemaphoreGive(self->inactiveWaitSem); + + // Shutdown task + xTaskNotifyGive(self->client_task_handle); + while (eTaskGetState(self->client_task_handle) != eDeleted) { + mp_hal_delay_ms(10); + } + + // Release PPP + pppapi_free(self->pcb); + self->pcb = NULL; + self->active = false; + self->connected = false; + } + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ppp_active_obj, 1, 2, ppp_active); + +STATIC mp_obj_t ppp_delete(mp_obj_t self_in) { + ppp_if_obj_t* self = MP_OBJ_TO_PTR(self_in); + mp_obj_t args[] = {self, mp_const_false}; + ppp_active(2, args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(ppp_delete_obj, ppp_delete); + +STATIC mp_obj_t ppp_ifconfig(size_t n_args, const mp_obj_t *args) { + ppp_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + ip_addr_t dns; + if (n_args == 1) { + // get + if (self->pcb != NULL) { + dns = dns_getserver(0); + struct netif *pppif = ppp_netif(self->pcb); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&pppif->ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&pppif->gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&pppif->netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + mp_obj_t tuple[4] = { mp_const_none, mp_const_none, mp_const_none, mp_const_none }; + return mp_obj_new_tuple(4, tuple); + } + } else { + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns.u_addr.ip4, NETUTILS_BIG); + dns_setserver(0, &dns); + return mp_const_none; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ppp_ifconfig_obj, 1, 2, ppp_ifconfig); + +STATIC mp_obj_t ppp_status(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ppp_status_obj, ppp_status); + +STATIC mp_obj_t ppp_isconnected(mp_obj_t self_in) { + ppp_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->connected); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ppp_isconnected_obj, ppp_isconnected); + +STATIC const mp_rom_map_elem_t ppp_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&ppp_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&ppp_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&ppp_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&ppp_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ppp_delete_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(ppp_if_locals_dict, ppp_if_locals_dict_table); + +const mp_obj_type_t ppp_if_type = { + { &mp_type_type }, + .name = MP_QSTR_PPP, + .locals_dict = (mp_obj_dict_t*)&ppp_if_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp32/partitions.csv b/src/openmv/src/micropython/ports/esp32/partitions.csv new file mode 100755 index 0000000..98adcd2 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x180000, diff --git a/src/openmv/src/micropython/ports/esp32/qstrdefsport.h b/src/openmv/src/micropython/ports/esp32/qstrdefsport.h new file mode 100755 index 0000000..ff6c2cc --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/qstrdefsport.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port, only needed if they aren't auto-generated + +// Entries for sys.path +Q(/lib) diff --git a/src/openmv/src/micropython/ports/esp32/sdkconfig.h b/src/openmv/src/micropython/ports/esp32/sdkconfig.h new file mode 100755 index 0000000..5c6a4c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/sdkconfig.h @@ -0,0 +1,193 @@ +/* Start bootloader config */ +#define CONFIG_FLASHMODE_DIO 1 +#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1 +/* End bootloader config */ + +#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 +#define CONFIG_BT_RESERVE_DRAM 0x0 +#define CONFIG_ULP_COPROC_RESERVE_MEM 2040 +#define CONFIG_PHY_DATA_OFFSET 0xf000 +#define CONFIG_APP_OFFSET 0x10000 + +#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 +#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1 +#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4 + +#define CONFIG_BROWNOUT_DET 1 +#define CONFIG_BROWNOUT_DET_LVL 0 +#define CONFIG_BROWNOUT_DET_LVL_SEL_0 1 + +#define CONFIG_TCPIP_TASK_STACK_SIZE 2560 +#define CONFIG_TCPIP_RECVMBOX_SIZE 32 + +#define CONFIG_ESP32_APPTRACE_DEST_NONE 1 +#define CONFIG_ESP32_PHY_MAX_TX_POWER 20 +#define CONFIG_ESP32_PANIC_PRINT_REBOOT 1 +#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1 +#define CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES 100 +#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 +#define CONFIG_ESP32_DEBUG_OCDAWARE 1 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 +#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 +#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 +#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 +#define CONFIG_ESP32_WIFI_NVS_ENABLED 1 +#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10 +#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 0 +#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32 +#define CONFIG_ESP32_WIFI_RX_BA_WIN 6 +#define CONFIG_ESP32_WIFI_TX_BA_WIN 6 +#define CONFIG_ESP32_XTAL_FREQ_AUTO 1 +#define CONFIG_ESP32_XTAL_FREQ 0 +#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024 +#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT 5 +#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048 + +#if CONFIG_SPIRAM_SUPPORT +#define CONFIG_SPIRAM_TYPE_ESPPSRAM32 1 +#define CONFIG_SPIRAM_SIZE 4194304 +#define CONFIG_SPIRAM_SPEED_40M 1 +#define CONFIG_SPIRAM_CACHE_WORKAROUND 1 +#define CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL 16384 +#define CONFIG_SPIRAM_BOOT_INIT 1 +#define CONFIG_SPIRAM_MEMTEST 1 +#define CONFIG_SPIRAM_USE_MALLOC 1 +#define CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL 32768 +#define CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY 1 +#endif + +#define CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE 1 +#define CONFIG_DMA_RX_BUF_NUM 10 +#define CONFIG_DMA_TX_BUF_NUM 10 +#define CONFIG_EMAC_TASK_PRIORITY 20 + +#define CONFIG_INT_WDT 1 +#define CONFIG_INT_WDT_TIMEOUT_MS 300 +#define CONFIG_INT_WDT_CHECK_CPU1 0 +#define CONFIG_TASK_WDT 1 +#define CONFIG_TASK_WDT_PANIC 1 +#define CONFIG_TASK_WDT_TIMEOUT_S 5 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK 0 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 0 + +#define CONFIG_FREERTOS_UNICORE 1 +#define CONFIG_FREERTOS_CORETIMER_0 1 +#define CONFIG_FREERTOS_HZ 100 +#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1 +#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1 +#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE 1 +#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 2 +#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1024 +#define CONFIG_FREERTOS_ISR_STACKSIZE 1536 +#define CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG 1 +#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16 +#define CONFIG_SUPPORT_STATIC_ALLOCATION 1 +#define CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK 1 + +#define CONFIG_MAIN_TASK_STACK_SIZE 4096 +#define CONFIG_IPC_TASK_STACK_SIZE 1024 +#define CONFIG_BTC_TASK_STACK_SIZE 3072 +#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 4096 +#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE 32 +#define CONFIG_TIMER_TASK_STACK_SIZE 4096 +#define CONFIG_TIMER_TASK_PRIORITY 1 +#define CONFIG_TIMER_TASK_STACK_DEPTH 2048 +#define CONFIG_TIMER_QUEUE_LENGTH 10 + +#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1 +#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1 +#define CONFIG_PHY_ENABLED 1 +#define CONFIG_WIFI_ENABLED 1 +#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1 +#define CONFIG_MEMMAP_SMP 1 + +#define CONFIG_PARTITION_TABLE_OFFSET 0x8000 +#define CONFIG_PARTITION_TABLE_SINGLE_APP 1 +#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv" +#define CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET 0x10000 +#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv" + +#define CONFIG_CONSOLE_UART_BAUDRATE 115200 +#define CONFIG_CONSOLE_UART_NUM 0 +#define CONFIG_CONSOLE_UART_DEFAULT 1 + +#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL_WARN 1 +#define CONFIG_LOG_DEFAULT_LEVEL 3 +#define CONFIG_LOG_COLORS 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL 2 + +#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0 +#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 +#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60 +#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8 +#define CONFIG_LWIP_MAX_ACTIVE_TCP 16 +#define CONFIG_LWIP_MAX_SOCKETS 8 +#define CONFIG_LWIP_SO_REUSE 1 +#define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1 +#define CONFIG_PPP_SUPPORT 1 +#define CONFIG_IP_LOST_TIMER_INTERVAL 120 +#define CONFIG_UDP_RECVMBOX_SIZE 6 +#define CONFIG_TCP_MAXRTX 12 +#define CONFIG_TCP_SYNMAXRTX 6 +#define CONFIG_TCP_MSL 60000 +#define CONFIG_TCP_MSS 1436 +#define CONFIG_TCP_SND_BUF_DEFAULT 5744 +#define CONFIG_TCP_WND_DEFAULT 5744 +#define CONFIG_TCP_QUEUE_OOSEQ 1 +#define CONFIG_TCP_OVERSIZE_MSS 1 +#define CONFIG_TCP_RECVMBOX_SIZE 6 + +#define CONFIG_MBEDTLS_AES_C 1 +#define CONFIG_MBEDTLS_CCM_C 1 +#define CONFIG_MBEDTLS_ECDH_C 1 +#define CONFIG_MBEDTLS_ECDSA_C 1 +#define CONFIG_MBEDTLS_ECP_C 1 +#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1 +#define CONFIG_MBEDTLS_GCM_C 1 +#define CONFIG_MBEDTLS_HARDWARE_AES 1 +#define CONFIG_MBEDTLS_HAVE_TIME 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1 +#define CONFIG_MBEDTLS_PEM_PARSE_C 1 +#define CONFIG_MBEDTLS_PEM_WRITE_C 1 +#define CONFIG_MBEDTLS_RC4_DISABLED 1 +#define CONFIG_MBEDTLS_SSL_ALPN 1 +#define CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1 +#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1 +#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1 +#define CONFIG_MBEDTLS_TLS_CLIENT 1 +#define CONFIG_MBEDTLS_TLS_ENABLED 1 +#define CONFIG_MBEDTLS_TLS_SERVER 1 +#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1 +#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1 +#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1 + +#define CONFIG_MAKE_WARN_UNDEFINED_VARIABLES 1 +#define CONFIG_TOOLPREFIX "xtensa-esp32-elf-" +#define CONFIG_PYTHON "python2" diff --git a/src/openmv/src/micropython/ports/esp32/uart.c b/src/openmv/src/micropython/ports/esp32/uart.c new file mode 100755 index 0000000..10a4ba4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/uart.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "driver/uart.h" + +#include "py/mpstate.h" +#include "py/mphal.h" + +STATIC void uart_irq_handler(void *arg); + +void uart_init(void) { + uart_isr_handle_t handle; + uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle); + uart_enable_rx_intr(UART_NUM_0); +} + +// all code executed in ISR must be in IRAM, and any const data must be in DRAM +STATIC void IRAM_ATTR uart_irq_handler(void *arg) { + volatile uart_dev_t *uart = &UART0; + uart->int_clr.rxfifo_full = 1; + uart->int_clr.frm_err = 1; + uart->int_clr.rxfifo_tout = 1; + while (uart->status.rxfifo_cnt) { + uint8_t c = uart->fifo.rw_byte; + if (c == mp_interrupt_char) { + // inline version of mp_keyboard_interrupt(); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + #if MICROPY_ENABLE_SCHEDULER + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + #endif + } else { + // this is an inline function so will be in IRAM + ringbuf_put(&stdin_ringbuf, c); + } + } +} diff --git a/src/openmv/src/micropython/ports/esp32/uart.h b/src/openmv/src/micropython/ports/esp32/uart.h new file mode 100755 index 0000000..264c8b8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp32/uart.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_UART_H +#define MICROPY_INCLUDED_ESP32_UART_H + +void uart_init(void); + +#endif // MICROPY_INCLUDED_ESP32_UART_H diff --git a/src/openmv/src/micropython/ports/esp8266/Makefile b/src/openmv/src/micropython/ports/esp8266/Makefile new file mode 100755 index 0000000..8dc2062 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/Makefile @@ -0,0 +1,203 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h + +MICROPY_PY_USSL = 1 +MICROPY_SSL_AXTLS = 1 +AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096 -Wno-implicit-function-declaration +MICROPY_FATFS = 1 +MICROPY_PY_BTREE = 1 +BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3 + +FROZEN_DIR ?= scripts +FROZEN_MPY_DIR ?= modules + +# include py core make definitions +include $(TOP)/py/py.mk + +FWBIN = $(BUILD)/firmware-combined.bin +PORT ?= /dev/ttyACM0 +BAUD ?= 115200 +FLASH_MODE ?= qio +FLASH_SIZE ?= detect +CROSS_COMPILE = xtensa-lx106-elf- +ESP_SDK = $(shell $(CC) -print-sysroot)/usr + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(ESP_SDK)/include + +# UART for "os" messages. 0 is normal UART as used by MicroPython REPL, +# 1 is debug UART (tx only), -1 to disable. +UART_OS = 0 + +CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \ + -D__ets__ -DICACHE_FLASH \ + -fno-inline-functions \ + -Wl,-EL -mlongcalls -mtext-section-literals -mforce-l32 \ + -DLWIP_OPEN_SRC + +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \ + $(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) + +LDSCRIPT = esp8266.ld +LDFLAGS = -nostdlib -T $(LDSCRIPT) -Map=$(@:.elf=.map) --cref +LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211 $(LDFLAGS_MOD) + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g +COPT = -O0 +else +CFLAGS += -fdata-sections -ffunction-sections +COPT += -Os -DNDEBUG +LDFLAGS += --gc-sections +endif + +SRC_C = \ + strtoll.c \ + main.c \ + help.c \ + esp_mphal.c \ + esp_init_data.c \ + gccollect.c \ + lexerstr32.c \ + uart.c \ + esppwm.c \ + espneopixel.c \ + espapa102.c \ + intr.c \ + modpyb.c \ + modmachine.c \ + machine_pin.c \ + machine_pwm.c \ + machine_rtc.c \ + machine_adc.c \ + machine_uart.c \ + machine_wdt.c \ + machine_hspi.c \ + modesp.c \ + modnetwork.c \ + modutime.c \ + moduos.c \ + ets_alt_task.c \ + fatfs_port.c \ + posix_helpers.c \ + hspi.c \ + $(SRC_MOD) + +EXTMOD_SRC_C = $(addprefix extmod/,\ + modlwip.c \ + modonewire.c \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + libc/string0.c \ + libm/math.c \ + libm/fmodf.c \ + libm/nearbyintf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/unicode.c +endif + +DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + dht/dht.c \ + ) + +SRC_S = \ + gchelper.s \ + +OBJ = +OBJ += $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) +# Append any auto-generated sources that are needed by sources listed in SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +all: $(FWBIN) + +CONFVARS_FILE = $(BUILD)/confvars + +ifeq ($(wildcard $(CONFVARS_FILE)),) +$(shell $(MKDIR) -p $(BUILD)) +$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE)) +else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_DIR) $(UART_OS)) +$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE)) +endif + +$(BUILD)/uart.o: $(CONFVARS_FILE) + +FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) + +.PHONY: deploy + +deploy: $(BUILD)/firmware-combined.bin + $(ECHO) "Writing $< to the board" + $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $< + +erase: + $(ECHO) "Erase flash" + $(Q)esptool.py --port $(PORT) --baud $(BAUD) erase_flash + +reset: + echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT) + +$(FWBIN): $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)esptool.py elf2image $^ + $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +512k: + $(MAKE) LDSCRIPT=esp8266_512k.ld CFLAGS_EXTRA='-DMP_CONFIGFILE=""' MICROPY_FATFS=0 MICROPY_PY_BTREE=0 + +ota: + rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin + $(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin + +include $(TOP)/py/mkrules.mk + +clean-modules: + git clean -f -d modules + rm -f build/frozen*.c diff --git a/src/openmv/src/micropython/ports/esp8266/README.md b/src/openmv/src/micropython/ports/esp8266/README.md new file mode 100755 index 0000000..f4dddd1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/README.md @@ -0,0 +1,163 @@ +MicroPython port to ESP8266 +=========================== + +This is an experimental port of MicroPython for the WiFi modules based +on Espressif ESP8266 chip. + +WARNING: The port is experimental and many APIs are subject to change. + +Supported features include: +- REPL (Python prompt) over UART0. +- Garbage collector, exceptions. +- Unicode support. +- Builtin modules: gc, array, collections, io, struct, sys, esp, network, + many more. +- Arbitrary-precision long integers and 30-bit precision floats. +- WiFi support. +- Sockets using modlwip. +- GPIO and bit-banging I2C, SPI support. +- 1-Wire and WS2812 (aka Neopixel) protocols support. +- Internal filesystem using the flash. +- WebREPL over WiFi from a browser (clients at https://github.com/micropython/webrepl). +- Modules for HTTP, MQTT, many other formats and protocols via + https://github.com/micropython/micropython-lib . + +Work-in-progress documentation is available at +http://docs.micropython.org/en/latest/esp8266/ . + +Build instructions +------------------ + +The tool chain required for the build is the OpenSource ESP SDK, which can be +found at . Clone this repository and +run `make` in its directory to build and install the SDK locally. Make sure +to add toolchain bin directory to your PATH. Read esp-open-sdk's README for +additional important information on toolchain setup. + +Add the external dependencies to the MicroPython repository checkout: +```bash +$ git submodule update --init +``` +See the README in the repository root for more information about external +dependencies. + +The MicroPython cross-compiler must be built to pre-compile some of the +built-in scripts to bytecode. This can be done using: +```bash +$ make -C mpy-cross +``` + +Then, to build MicroPython for the ESP8266, just run: +```bash +$ cd ports/esp8266 +$ make axtls +$ make +``` +This will produce binary images in the `build/` subdirectory. If you install +MicroPython to your module for the first time, or after installing any other +firmware, you should erase flash completely: + +``` +esptool.py --port /dev/ttyXXX erase_flash +``` + +Erase flash also as a troubleshooting measure, if a module doesn't behave as +expected. + +To flash MicroPython image to your ESP8266, use: +```bash +$ make deploy +``` +This will use the `esptool.py` script to download the images. You must have +your ESP module in the bootloader mode, and connected to a serial port on your PC. +The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is +`detect` (auto-detect based on Flash ID). To specify other values, use, eg (note +that flash size is in megabits): +```bash +$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy +``` + +The image produced is `build/firmware-combined.bin`, to be flashed at 0x00000. + +__512KB FlashROM version__ + +The normal build described above requires modules with at least 1MB of FlashROM +onboard. There's a special configuration for 512KB modules, which can be +built with `make 512k`. This configuration is highly limited, lacks filesystem +support, WebREPL, and has many other features disabled. It's mostly suitable +for advanced users who are interested to fine-tune options to achieve a required +setup. If you are an end user, please consider using a module with at least 1MB +of FlashROM. + +First start +----------- + +Be sure to change ESP8266's WiFi access point password ASAP, see below. + +__Serial prompt__ + +You can access the REPL (Python prompt) over UART (the same as used for +programming). +- Baudrate: 115200 + +Run `help()` for some basic information. + +__WiFi__ + +Initially, the device configures itself as a WiFi access point (AP). +- ESSID: MicroPython-xxxxxx (x’s are replaced with part of the MAC address). +- Password: micropythoN (note the upper-case N). +- IP address of the board: 192.168.4.1. +- DHCP-server is activated. +- Please be sure to change the password to something non-guessable + immediately. `help()` gives information how. + +__WebREPL__ + +Python prompt over WiFi, connecting through a browser. +- Hosted at http://micropython.org/webrepl. +- GitHub repository https://github.com/micropython/webrepl. + Please follow the instructions there. + +__upip__ + +The ESP8266 port comes with builtin `upip` package manager, which can +be used to install additional modules (see the main README for more +information): + +``` +>>> import upip +>>> upip.install("micropython-pystone_lowmem") +[...] +>>> import pystone_lowmem +>>> pystone_lowmem.main() +``` + +Downloading and installing packages may requite a lot of free memory, +if you get an error, retry immediately after the hard reset. + +Documentation +------------- + +More detailed documentation and instructions can be found at +http://docs.micropython.org/en/latest/esp8266/ , which includes Quick +Reference, Tutorial, General Information related to ESP8266 port, and +to MicroPython in general. + +Troubleshooting +--------------- + +While the port is in beta, it's known to be generally stable. If you +experience strange bootloops, crashes, lockups, here's a list to check against: + +- You didn't erase flash before programming MicroPython firmware. +- Firmware can be occasionally flashed incorrectly. Just retry. Recent + esptool.py versions have --verify option. +- Power supply you use doesn't provide enough power for ESP8266 or isn't + stable enough. +- A module/flash may be defective (not unheard of for cheap modules). + +Please consult dedicated ESP8266 forums/resources for hardware-related +problems. + +Additional information may be available by the documentation links above. diff --git a/src/openmv/src/micropython/ports/esp8266/eagle.rom.addr.v6.ld b/src/openmv/src/micropython/ports/esp8266/eagle.rom.addr.v6.ld new file mode 100755 index 0000000..1b3ce55 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/eagle.rom.addr.v6.ld @@ -0,0 +1,351 @@ +PROVIDE ( Cache_Read_Disable = 0x400047f0 ); +PROVIDE ( Cache_Read_Enable = 0x40004678 ); +PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); +PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); +PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); +PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); +PROVIDE ( GetUartDevice = 0x40003f4c ); +PROVIDE ( MD5Final = 0x40009900 ); +PROVIDE ( MD5Init = 0x40009818 ); +PROVIDE ( MD5Update = 0x40009834 ); +PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); +PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); +PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); +PROVIDE ( RcvMsg = 0x40003eac ); +PROVIDE ( SHA1Final = 0x4000b648 ); +PROVIDE ( SHA1Init = 0x4000b584 ); +PROVIDE ( SHA1Transform = 0x4000a364 ); +PROVIDE ( SHA1Update = 0x4000b5a8 ); +PROVIDE ( SPI_read_status = 0x400043c8 ); +PROVIDE ( SPI_write_status = 0x40004400 ); +PROVIDE ( SPI_write_enable = 0x4000443c ); +PROVIDE ( Wait_SPI_Idle = 0x4000448c ); +PROVIDE ( Enable_QMode = 0x400044c0 ); +PROVIDE ( SPIEraseArea = 0x40004b44 ); +PROVIDE ( SPIEraseBlock = 0x400049b4 ); +PROVIDE ( SPIEraseChip = 0x40004984 ); +PROVIDE ( SPIEraseSector = 0x40004a00 ); +PROVIDE ( SPILock = 0x400048a8 ); +PROVIDE ( SPIParamCfg = 0x40004c2c ); +PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( SPIReadModeCnfig = 0x400048ec ); +PROVIDE ( SPIUnlock = 0x40004878 ); +PROVIDE ( SPIWrite = 0x40004a4c ); +PROVIDE ( SelectSpiFunction = 0x40003f58 ); +PROVIDE ( SendMsg = 0x40003cf4 ); +PROVIDE ( UartConnCheck = 0x40003230 ); +PROVIDE ( UartConnectProc = 0x400037a0 ); +PROVIDE ( UartDwnLdProc = 0x40003368 ); +PROVIDE ( UartGetCmdLn = 0x40003ef4 ); +PROVIDE ( UartRegReadProc = 0x4000381c ); +PROVIDE ( UartRegWriteProc = 0x400037ac ); +PROVIDE ( UartRxString = 0x40003c30 ); +PROVIDE ( Uart_Init = 0x40003a14 ); +PROVIDE ( _DebugExceptionVector = 0x40000010 ); +PROVIDE ( _DoubleExceptionVector = 0x40000070 ); +PROVIDE ( _KernelExceptionVector = 0x40000030 ); +PROVIDE ( _NMIExceptionVector = 0x40000020 ); +PROVIDE ( _ResetHandler = 0x400000a4 ); +PROVIDE ( _ResetVector = 0x40000080 ); +PROVIDE ( _UserExceptionVector = 0x40000050 ); +__adddf3 = 0x4000c538; +__addsf3 = 0x4000c180; +__divdf3 = 0x4000cb94; +__divdi3 = 0x4000ce60; +__divsi3 = 0x4000dc88; +__extendsfdf2 = 0x4000cdfc; +__fixdfsi = 0x4000ccb8; +__fixunsdfsi = 0x4000cd00; +__fixunssfsi = 0x4000c4c4; +__floatsidf = 0x4000e2f0; +__floatsisf = 0x4000e2ac; +__floatunsidf = 0x4000e2e8; +__floatunsisf = 0x4000e2a4; +__muldf3 = 0x4000c8f0; +__muldi3 = 0x40000650; +__mulsf3 = 0x4000c3dc; +__subdf3 = 0x4000c688; +__subsf3 = 0x4000c268; +__truncdfsf2 = 0x4000cd5c; +__udivdi3 = 0x4000d310; +__udivsi3 = 0x4000e21c; +__umoddi3 = 0x4000d770; +__umodsi3 = 0x4000e268; +__umulsidi3 = 0x4000dcf0; +PROVIDE ( _rom_store = 0x4000e388 ); +PROVIDE ( _rom_store_table = 0x4000e328 ); +PROVIDE ( _start = 0x4000042c ); +PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); +PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); +PROVIDE ( _xtos_cause3_handler = 0x40000590 ); +PROVIDE ( _xtos_ints_off = 0x4000bda4 ); +PROVIDE ( _xtos_ints_on = 0x4000bd84 ); +PROVIDE ( _xtos_l1int_handler = 0x4000048c ); +PROVIDE ( _xtos_p_none = 0x4000dbf8 ); +PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); +PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); +PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); +PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); +PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); +PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); +PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); +PROVIDE ( _xtos_set_vpri = 0x40000574 ); +PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); +PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); +PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); +PROVIDE ( aes_decrypt = 0x400092d4 ); +PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); +PROVIDE ( aes_decrypt_init = 0x40008ea4 ); +PROVIDE ( aes_unwrap = 0x40009410 ); +PROVIDE ( base64_decode = 0x40009648 ); +PROVIDE ( base64_encode = 0x400094fc ); +PROVIDE ( bzero = 0x4000de84 ); +PROVIDE ( cmd_parse = 0x40000814 ); +PROVIDE ( conv_str_decimal = 0x40000b24 ); +PROVIDE ( conv_str_hex = 0x40000cb8 ); +PROVIDE ( convert_para_str = 0x40000a60 ); +PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); +PROVIDE ( dtm_params_init = 0x4000269c ); +PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); +PROVIDE ( dtm_set_params = 0x400026dc ); +PROVIDE ( eprintf = 0x40001d14 ); +PROVIDE ( eprintf_init_buf = 0x40001cb8 ); +PROVIDE ( eprintf_to_host = 0x40001d48 ); +PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); +PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); +PROVIDE ( ets_bzero = 0x40002ae8 ); +PROVIDE ( ets_char2xdigit = 0x40002b74 ); +PROVIDE ( ets_delay_us = 0x40002ecc ); +PROVIDE ( ets_enter_sleep = 0x400027b8 ); +PROVIDE ( ets_external_printf = 0x40002578 ); +PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); +PROVIDE ( ets_getc = 0x40002bcc ); +PROVIDE ( ets_install_external_printf = 0x40002450 ); +PROVIDE ( ets_install_putc1 = 0x4000242c ); +PROVIDE ( ets_install_putc2 = 0x4000248c ); +PROVIDE ( ets_install_uart_printf = 0x40002438 ); +PROVIDE ( ets_intr_lock = 0x40000f74 ); +PROVIDE ( ets_intr_unlock = 0x40000f80 ); +PROVIDE ( ets_isr_attach = 0x40000f88 ); +PROVIDE ( ets_isr_mask = 0x40000f98 ); +PROVIDE ( ets_isr_unmask = 0x40000fa8 ); +PROVIDE ( ets_memcmp = 0x400018d4 ); +PROVIDE ( ets_memcpy = 0x400018b4 ); +PROVIDE ( ets_memmove = 0x400018c4 ); +PROVIDE ( ets_memset = 0x400018a4 ); +PROVIDE ( _ets_post = 0x40000e24 ); +PROVIDE ( ets_printf = 0x400024cc ); +PROVIDE ( ets_putc = 0x40002be8 ); +PROVIDE ( ets_rtc_int_register = 0x40002a40 ); +PROVIDE ( _ets_run = 0x40000e04 ); +PROVIDE ( _ets_set_idle_cb = 0x40000dc0 ); +PROVIDE ( ets_set_user_start = 0x40000fbc ); +PROVIDE ( ets_str2macaddr = 0x40002af8 ); +PROVIDE ( ets_strcmp = 0x40002aa8 ); +PROVIDE ( ets_strcpy = 0x40002a88 ); +PROVIDE ( ets_strlen = 0x40002ac8 ); +PROVIDE ( ets_strncmp = 0x40002ab8 ); +PROVIDE ( ets_strncpy = 0x40002a98 ); +PROVIDE ( ets_strstr = 0x40002ad8 ); +PROVIDE ( _ets_task = 0x40000dd0 ); +PROVIDE ( ets_timer_arm = 0x40002cc4 ); +PROVIDE ( ets_timer_disarm = 0x40002d40 ); +PROVIDE ( ets_timer_done = 0x40002d80 ); +PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); +PROVIDE ( _ets_timer_init = 0x40002e68 ); +PROVIDE ( ets_timer_setfn = 0x40002c48 ); +PROVIDE ( ets_uart_printf = 0x40002544 ); +PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); +PROVIDE ( ets_vprintf = 0x40001f00 ); +PROVIDE ( ets_wdt_disable = 0x400030f0 ); +PROVIDE ( ets_wdt_enable = 0x40002fa0 ); +PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); +PROVIDE ( ets_wdt_init = 0x40003170 ); +PROVIDE ( ets_wdt_restore = 0x40003158 ); +PROVIDE ( ets_write_char = 0x40001da0 ); +PROVIDE ( get_first_seg = 0x4000091c ); +PROVIDE ( gpio_init = 0x40004c50 ); +PROVIDE ( gpio_input_get = 0x40004cf0 ); +PROVIDE ( gpio_intr_ack = 0x40004dcc ); +PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); +PROVIDE ( gpio_intr_pending = 0x40004d88 ); +PROVIDE ( gpio_intr_test = 0x40004efc ); +PROVIDE ( gpio_output_set = 0x40004cd0 ); +PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); +PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); +PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); +PROVIDE ( gpio_register_get = 0x40004d5c ); +PROVIDE ( gpio_register_set = 0x40004d04 ); +PROVIDE ( hmac_md5 = 0x4000a2cc ); +PROVIDE ( hmac_md5_vector = 0x4000a160 ); +PROVIDE ( hmac_sha1 = 0x4000ba28 ); +PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); +PROVIDE ( lldesc_build_chain = 0x40004f40 ); +PROVIDE ( lldesc_num2link = 0x40005050 ); +PROVIDE ( lldesc_set_owner = 0x4000507c ); +PROVIDE ( main = 0x40000fec ); +PROVIDE ( md5_vector = 0x400097ac ); +PROVIDE ( mem_calloc = 0x40001c2c ); +PROVIDE ( mem_free = 0x400019e0 ); +PROVIDE ( mem_init = 0x40001998 ); +PROVIDE ( mem_malloc = 0x40001b40 ); +PROVIDE ( mem_realloc = 0x40001c6c ); +PROVIDE ( mem_trim = 0x40001a14 ); +PROVIDE ( mem_zalloc = 0x40001c58 ); +PROVIDE ( memcmp = 0x4000dea8 ); +PROVIDE ( memcpy = 0x4000df48 ); +PROVIDE ( memmove = 0x4000e04c ); +PROVIDE ( memset = 0x4000e190 ); +PROVIDE ( multofup = 0x400031c0 ); +PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); +PROVIDE ( phy_get_romfuncs = 0x40006b08 ); +PROVIDE ( rand = 0x40000600 ); +PROVIDE ( rc4_skip = 0x4000dd68 ); +PROVIDE ( recv_packet = 0x40003d08 ); +PROVIDE ( remove_head_space = 0x40000a04 ); +PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); +PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); +PROVIDE ( rom_abs_temp = 0x400060c0 ); +PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); +PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); +PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); +PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); +PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); +PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); +PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); +PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); +PROVIDE ( rom_dc_iq_est = 0x4000615c ); +PROVIDE ( rom_en_pwdet = 0x400061b8 ); +PROVIDE ( rom_get_bb_atten = 0x40006238 ); +PROVIDE ( rom_get_corr_power = 0x40006260 ); +PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); +PROVIDE ( rom_get_noisefloor = 0x40006394 ); +PROVIDE ( rom_get_power_db = 0x400063b0 ); +PROVIDE ( rom_i2c_readReg = 0x40007268 ); +PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); +PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); +PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); +PROVIDE ( rom_iq_est_disable = 0x40006400 ); +PROVIDE ( rom_iq_est_enable = 0x40006430 ); +PROVIDE ( rom_linear_to_db = 0x40006484 ); +PROVIDE ( rom_mhz2ieee = 0x400065a4 ); +PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); +PROVIDE ( rom_pbus_debugmode = 0x4000737c ); +PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); +PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); +PROVIDE ( rom_pbus_force_test = 0x4000747c ); +PROVIDE ( rom_pbus_rd = 0x400074d8 ); +PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); +PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); +PROVIDE ( rom_pbus_workmode = 0x40007648 ); +PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); +PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); +PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); +PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); +PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); +PROVIDE ( rom_phy_reset_req = 0x40007804 ); +PROVIDE ( rom_restart_cal = 0x4000781c ); +PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); +PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); +PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); +PROVIDE ( rom_rfcal_txcap = 0x40008388 ); +PROVIDE ( rom_rfcal_txiq = 0x40008610 ); +PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); +PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); +PROVIDE ( rom_rfpll_reset = 0x40007868 ); +PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); +PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); +PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); +PROVIDE ( rom_sar_init = 0x40006738 ); +PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); +PROVIDE ( rom_set_channel_freq = 0x40006c50 ); +PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); +PROVIDE ( rom_set_noise_floor = 0x40006830 ); +PROVIDE ( rom_set_rxclk_en = 0x40006550 ); +PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); +PROVIDE ( rom_set_txclk_en = 0x4000650c ); +PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); +PROVIDE ( rom_start_noisefloor = 0x40006874 ); +PROVIDE ( rom_start_tx_tone = 0x400068b4 ); +PROVIDE ( rom_stop_tx_tone = 0x4000698c ); +PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); +PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); +PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); +PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); +PROVIDE ( roundup2 = 0x400031b4 ); +PROVIDE ( rtc_enter_sleep = 0x40002870 ); +PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); +PROVIDE ( rtc_intr_handler = 0x400029ec ); +PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); +PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); +PROVIDE ( save_tsf_us = 0x400027ac ); +PROVIDE ( send_packet = 0x40003c80 ); +PROVIDE ( sha1_prf = 0x4000ba48 ); +PROVIDE ( sha1_vector = 0x4000a2ec ); +PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); +PROVIDE ( sip_get_ptr = 0x400058a8 ); +PROVIDE ( sip_get_state = 0x40005668 ); +PROVIDE ( sip_init_attach = 0x4000567c ); +PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); +PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); +PROVIDE ( sip_post = 0x400050fc ); +PROVIDE ( sip_post_init = 0x400056c4 ); +PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); +PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); +PROVIDE ( sip_send = 0x40005808 ); +PROVIDE ( sip_to_host_chain_append = 0x40005864 ); +PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); +PROVIDE ( slc_add_credits = 0x400060ac ); +PROVIDE ( slc_enable = 0x40005d90 ); +PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); +PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); +PROVIDE ( slc_init_attach = 0x40005c50 ); +PROVIDE ( slc_init_credit = 0x4000608c ); +PROVIDE ( slc_pause_from_host = 0x40006014 ); +PROVIDE ( slc_reattach = 0x40005c1c ); +PROVIDE ( slc_resume_from_host = 0x4000603c ); +PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); +PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); +PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); +PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); +PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); +PROVIDE ( software_reset = 0x4000264c ); +PROVIDE ( spi_flash_attach = 0x40004644 ); +PROVIDE ( srand = 0x400005f0 ); +PROVIDE ( strcmp = 0x4000bdc8 ); +PROVIDE ( strcpy = 0x4000bec8 ); +PROVIDE ( strlen = 0x4000bf4c ); +PROVIDE ( strncmp = 0x4000bfa8 ); +PROVIDE ( strncpy = 0x4000c0a0 ); +PROVIDE ( strstr = 0x4000e1e0 ); +PROVIDE ( timer_insert = 0x40002c64 ); +PROVIDE ( uartAttach = 0x4000383c ); +PROVIDE ( uart_baudrate_detect = 0x40003924 ); +PROVIDE ( uart_buff_switch = 0x400038a4 ); +PROVIDE ( uart_div_modify = 0x400039d8 ); +PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); +PROVIDE ( uart_rx_one_char = 0x40003b8c ); +PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); +PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); +PROVIDE ( uart_tx_one_char = 0x40003b30 ); +PROVIDE ( wepkey_128 = 0x4000bc40 ); +PROVIDE ( wepkey_64 = 0x4000bb3c ); +PROVIDE ( xthal_bcopy = 0x40000688 ); +PROVIDE ( xthal_copy123 = 0x4000074c ); +PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); +PROVIDE ( xthal_get_ccount = 0x4000dd38 ); +PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); +PROVIDE ( xthal_get_intread = 0x4000dd58 ); +PROVIDE ( xthal_memcpy = 0x400006c4 ); +PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); +PROVIDE ( xthal_set_intclear = 0x4000dd60 ); +PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); +PROVIDE ( xthal_window_spill = 0x4000e324 ); +PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); + +PROVIDE ( Te0 = 0x3fffccf0 ); +PROVIDE ( Td0 = 0x3fffd100 ); +PROVIDE ( Td4s = 0x3fffd500); +PROVIDE ( rcons = 0x3fffd0f0); +PROVIDE ( UartDev = 0x3fffde10 ); +PROVIDE ( flashchip = 0x3fffc714); diff --git a/src/openmv/src/micropython/ports/esp8266/esp8266.ld b/src/openmv/src/micropython/ports/esp8266/esp8266.ld new file mode 100755 index 0000000..deeb82b --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp8266.ld @@ -0,0 +1,12 @@ +/* GNU linker script for ESP8266 */ + +MEMORY +{ + dport0_0_seg : org = 0x3ff00000, len = 0x10 + dram0_0_seg : org = 0x3ffe8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40209000, len = 0x8f000 +} + +/* define common sections and symbols */ +INCLUDE esp8266_common.ld diff --git a/src/openmv/src/micropython/ports/esp8266/esp8266_512k.ld b/src/openmv/src/micropython/ports/esp8266/esp8266_512k.ld new file mode 100755 index 0000000..0ae663d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp8266_512k.ld @@ -0,0 +1,12 @@ +/* GNU linker script for ESP8266 */ + +MEMORY +{ + dport0_0_seg : org = 0x3ff00000, len = 0x10 + dram0_0_seg : org = 0x3ffe8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40209000, len = 0x72000 +} + +/* define common sections and symbols */ +INCLUDE esp8266_common.ld diff --git a/src/openmv/src/micropython/ports/esp8266/esp8266_common.ld b/src/openmv/src/micropython/ports/esp8266/esp8266_common.ld new file mode 100755 index 0000000..f4b4207 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp8266_common.ld @@ -0,0 +1,315 @@ +/* GNU linker script for ESP8266, common sections and symbols */ + +/* define the top of RAM */ +_heap_end = ORIGIN(dram0_0_seg) + LENGTH(dram0_0_seg); + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + +ENTRY(firmware_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) + +_firmware_size = ORIGIN(irom0_0_seg) + LENGTH(irom0_0_seg) - 0x40200000; + +PROVIDE(_memmap_vecbase_reset = 0x40000000); + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + + /* Vendor SDK in v2.1.0-7-gb8fd588 started to build these with + -ffunction-sections -fdata-sections, and require routing to + irom via linker: + https://github.com/espressif/ESP8266_NONOS_SDK/commit/b8fd588a33f0319dc135523b51655e97b483b205 + */ + + *libcrypto.a:(.literal.* .text.*) + *libnet80211.a:(.literal.* .text.*) + *libwpa.a:(.literal.* .text.*) + *libwpa2.a:(.literal.* .text.*) + + /* we put some specific text in this section */ + + *py/argcheck.o*(.literal* .text*) + *py/asm*.o*(.literal* .text*) + *py/bc.o*(.literal* .text*) + *py/binary.o*(.literal* .text*) + *py/builtin*.o*(.literal* .text*) + *py/compile.o*(.literal* .text*) + *py/emit*.o*(.literal* .text*) + *py/persistentcode*.o*(.literal* .text*) + *py/formatfloat.o*(.literal* .text*) + *py/frozenmod.o*(.literal* .text*) + *py/gc.o*(.literal* .text*) + *py/reader*.o*(.literal* .text*) + *py/lexer*.o*(.literal* .text*) + *py/malloc*.o*(.literal* .text*) + *py/map*.o*(.literal* .text*) + *py/mod*.o*(.literal* .text*) + *py/mpprint.o*(.literal* .text*) + *py/mpstate.o*(.literal* .text*) + *py/mpz.o*(.literal* .text*) + *py/native*.o*(.literal* .text*) + *py/nlr*.o*(.literal* .text*) + *py/obj*.o*(.literal* .text*) + *py/opmethods.o*(.literal* .text*) + *py/parse*.o*(.literal* .text*) + *py/qstr.o*(.literal* .text*) + *py/repl.o*(.literal* .text*) + *py/runtime.o*(.literal* .text*) + *py/scheduler.o*(.literal* .text*) + *py/scope.o*(.literal* .text*) + *py/sequence.o*(.literal* .text*) + *py/showbc.o*(.literal* .text*) + *py/smallint.o*(.literal* .text*) + *py/stackctrl.o*(.literal* .text*) + *py/stream.o*(.literal* .text*) + *py/unicode.o*(.literal* .text*) + *py/vm.o*(.literal* .text*) + *py/vstr.o*(.literal* .text*) + *py/warning.o*(.literal* .text*) + + *extmod/*.o*(.literal* .text*) + + *lib/oofatfs/*.o*(.literal*, .text*) + *lib/axtls/*.o(.literal*, .text*) + *lib/berkeley-db-1.xx/*.o(.literal*, .text*) + *lib/libm/*.o*(.literal*, .text*) + *lib/mp-readline/*.o(.literal*, .text*) + *lib/netutils/*.o*(.literal*, .text*) + *lib/timeutils/*.o*(.literal*, .text*) + *lib/utils/printf.o*(.literal*, .text*) + *lib/utils/sys_stdio_mphal.o*(.literal*, .text*) + *lib/utils/pyexec.o*(.literal*, .text*) + *lib/utils/stdout_helpers.o*(.literal*, .text*) + *lib/utils/interrupt_char.o*(.literal.mp_hal_set_interrupt_char, .text.mp_hal_set_interrupt_char) + *drivers/bus/*.o(.literal* .text*) + + build/main.o(.literal* .text*) + *fatfs_port.o(.literal* .text*) + *gccollect.o(.literal* .text*) + *gchelper.o(.literal* .text*) + *help.o(.literal* .text*) + *lexerstr32.o(.literal* .text*) + *utils.o(.literal* .text*) + *modpyb.o(.literal*, .text*) + *machine_pin.o(.literal*, .text*) + *machine_pwm.o(.literal*, .text*) + *machine_rtc.o(.literal*, .text*) + *machine_adc.o(.literal*, .text*) + *machine_uart.o(.literal*, .text*) + *modpybi2c.o(.literal*, .text*) + *modmachine.o(.literal*, .text*) + *machine_wdt.o(.literal*, .text*) + *machine_spi.o(.literal*, .text*) + *machine_hspi.o(.literal*, .text*) + *hspi.o(.literal*, .text*) + *modesp.o(.literal* .text*) + *modnetwork.o(.literal* .text*) + *moduos.o(.literal* .text*) + *modutime.o(.literal* .text*) + *modlwip.o(.literal* .text*) + *modsocket.o(.literal* .text*) + *modonewire.o(.literal* .text*) + + /* we put as much rodata as possible in this section */ + /* note that only rodata accessed as a machine word is allowed here */ + *py/qstr.o(.rodata.const_pool) + *.o(.rodata.mp_type_*) /* catches type: mp_obj_type_t */ + *.o(.rodata.*_locals_dict*) /* catches types: mp_obj_dict_t, mp_map_elem_t */ + *.o(.rodata.mp_module_*) /* catches types: mp_obj_module_t, mp_obj_dict_t, mp_map_elem_t */ + */frozen.o(.rodata.mp_frozen_sizes) /* frozen modules */ + */frozen.o(.rodata.mp_frozen_content) /* frozen modules */ + + /* for -mforce-l32 */ + build/*.o(.rodata*) + + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .iram0.literal .iram0.text .iram0.text.*.literal .iram0.text.*) + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_bss_phdr +} + +/* get ROM code address */ +INCLUDE "eagle.rom.addr.v6.ld" diff --git a/src/openmv/src/micropython/ports/esp8266/esp8266_ota.ld b/src/openmv/src/micropython/ports/esp8266/esp8266_ota.ld new file mode 100755 index 0000000..604480a --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp8266_ota.ld @@ -0,0 +1,13 @@ +/* GNU linker script for ESP8266 */ + +MEMORY +{ + dport0_0_seg : org = 0x3ff00000, len = 0x10 + dram0_0_seg : org = 0x3ffe8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + /* 0x3c000 is size of bootloader, 0x9000 is size of packed RAM segments */ + irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000 +} + +/* define common sections and symbols */ +INCLUDE esp8266_common.ld diff --git a/src/openmv/src/micropython/ports/esp8266/esp_init_data.c b/src/openmv/src/micropython/ports/esp8266/esp_init_data.c new file mode 100755 index 0000000..b14de57 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp_init_data.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "ets_sys.h" +#include "etshal.h" +#include "esp_mphal.h" +#include "user_interface.h" +#include "extmod/misc.h" + +NORETURN void call_user_start(void); +void ets_printf(const char *fmt, ...); +extern char flashchip; + +static const uint8_t default_init_data[] __attribute__((aligned(4))) = { +0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05, +0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00, +0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 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, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void firmware_start(void) { + // For SDK 1.5.2, either address has shifted and not mirrored in + // eagle.rom.addr.v6.ld, or extra initial member was added. + SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4); + + char buf[128]; + SPIRead(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + /*for (int i = 0; i < sizeof(buf); i++) { + static char hexf[] = "%x "; + ets_printf(hexf, buf[i]); + }*/ + + bool inited = false; + for (int i = 0; i < sizeof(buf); i++) { + if (buf[i] != 0xff) { + inited = true; + break; + } + } + + if (!inited) { + static char msg[] = "Writing init data\n"; + ets_printf(msg); + SPIRead((uint32_t)&default_init_data - 0x40200000, buf, sizeof(buf)); + SPIWrite(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + } + + asm("j call_user_start"); +} diff --git a/src/openmv/src/micropython/ports/esp8266/esp_mphal.c b/src/openmv/src/micropython/ports/esp8266/esp_mphal.c new file mode 100755 index 0000000..df97a73 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp_mphal.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "ets_sys.h" +#include "etshal.h" +#include "uart.h" +#include "esp_mphal.h" +#include "user_interface.h" +#include "ets_alt_task.h" +#include "py/runtime.h" +#include "extmod/misc.h" +#include "lib/utils/pyexec.h" + +STATIC byte stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; +void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); +const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; + +int uart_attached_to_dupterm; + +void mp_hal_init(void) { + //ets_wdt_disable(); // it's a pain while developing + mp_hal_rtc_init(); + uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); + uart_attached_to_dupterm = 0; +} + +void mp_hal_delay_us(uint32_t us) { + uint32_t start = system_get_time(); + while (system_get_time() - start < us) { + ets_event_poll(); + } +} + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; + } + #if 0 + // Idles CPU but need more testing before enabling + if (!ets_loop_iter()) { + asm("waiti 0"); + } + #else + mp_hal_delay_us(1); + #endif + } +} + +#if 0 +void mp_hal_debug_str(const char *str) { + while (*str) { + uart_tx_one_char(UART0, *str++); + } + uart_flush(UART0); +} +#endif + +void mp_hal_stdout_tx_str(const char *str) { + mp_uos_dupterm_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { + mp_uos_dupterm_tx_strn(str, len); +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { + const char *last = str; + while (len--) { + if (*str == '\n') { + if (str > last) { + mp_uos_dupterm_tx_strn(last, str - last); + } + mp_uos_dupterm_tx_strn("\r\n", 2); + ++str; + last = str; + } else { + ++str; + } + } + if (str > last) { + mp_uos_dupterm_tx_strn(last, str - last); + } +} + +void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) { + (void)env; + while (len--) { + if (*str == '\n') { + uart_tx_one_char(UART0, '\r'); + } + uart_tx_one_char(UART0, *str++); + } +} + +uint32_t mp_hal_ticks_ms(void) { + return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_get_time()) / 1000; +} + +uint32_t mp_hal_ticks_us(void) { + return system_get_time(); +} + +void mp_hal_delay_ms(uint32_t delay) { + mp_hal_delay_us(delay * 1000); +} + +void ets_event_poll(void) { + ets_loop_iter(); + mp_handle_pending(); +} + +void __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("assert:%s:%d:%s: %s\n", file, line, func, expr); + nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError, + "C-level assert")); +} + +void mp_hal_signal_input(void) { + #if MICROPY_REPL_EVENT_DRIVEN + system_os_post(UART_TASK_ID, 0, 0); + #endif +} + +STATIC void dupterm_task_handler(os_event_t *evt) { + static byte lock; + if (lock) { + return; + } + lock = 1; + while (1) { + int c = mp_uos_dupterm_rx_chr(); + if (c < 0) { + break; + } + ringbuf_put(&stdin_ringbuf, c); + } + mp_hal_signal_input(); + lock = 0; +} + +STATIC os_event_t dupterm_evt_queue[4]; + +void dupterm_task_init() { + system_os_task(dupterm_task_handler, DUPTERM_TASK_ID, dupterm_evt_queue, MP_ARRAY_SIZE(dupterm_evt_queue)); +} + +void mp_hal_signal_dupterm_input(void) { + system_os_post(DUPTERM_TASK_ID, 0, 0); +} + +// Get pointer to esf_buf bookkeeping structure +void *ets_get_esf_buf_ctlblk(void) { + // Get literal ptr before start of esf_rx_buf_alloc func + extern void *esf_rx_buf_alloc(); + return ((void**)esf_rx_buf_alloc)[-1]; +} + +// Get number of esf_buf free buffers of given type, as encoded by index +// idx 0 corresponds to buf types 1, 2; 1 - 4; 2 - 5; 3 - 7; 4 - 8 +// Only following buf types appear to be used: +// 1 - tx buffer, 5 - management frame tx buffer; 8 - rx buffer +int ets_esf_free_bufs(int idx) { + uint32_t *p = ets_get_esf_buf_ctlblk(); + uint32_t *b = (uint32_t*)p[idx]; + int cnt = 0; + while (b) { + b = (uint32_t*)b[0x20 / 4]; + cnt++; + } + return cnt; +} + +extern int mp_stream_errno; +int *__errno() { + return &mp_stream_errno; +} diff --git a/src/openmv/src/micropython/ports/esp8266/esp_mphal.h b/src/openmv/src/micropython/ports/esp8266/esp_mphal.h new file mode 100755 index 0000000..56d9fa3 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esp_mphal.h @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/ringbuf.h" +#include "lib/utils/interrupt_char.h" +#include "xtirq.h" + +void mp_keyboard_interrupt(void); + +struct _mp_print_t; +// Structure for UART-only output via mp_printf() +extern const struct _mp_print_t mp_debug_print; + +extern ringbuf_t stdin_ringbuf; +// Call this after putting data to stdin_ringbuf +void mp_hal_signal_input(void); +// Call this when data is available in dupterm object +void mp_hal_signal_dupterm_input(void); + +// This variable counts how many times the UART is attached to dupterm +extern int uart_attached_to_dupterm; + +void mp_hal_init(void); +void mp_hal_rtc_init(void); + +uint32_t mp_hal_ticks_us(void); +__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +void mp_hal_delay_us(uint32_t); +void mp_hal_set_interrupt_char(int c); +uint32_t mp_hal_get_cpu_freq(void); + +#define UART_TASK_ID 0 +#define DUPTERM_TASK_ID 1 +void uart_task_init(); +void dupterm_task_init(); + +void ets_event_poll(void); +#define ETS_POLL_WHILE(cond) { while (cond) ets_event_poll(); } + +// needed for machine.I2C +#include "osapi.h" +#define mp_hal_delay_us_fast(us) os_delay_us(us) + +#define mp_hal_quiet_timing_enter() disable_irq() +#define mp_hal_quiet_timing_exit(irq_state) enable_irq(irq_state) + +// C-level pin HAL +#include "etshal.h" +#include "gpio.h" +#include "modmachine.h" +#define MP_HAL_PIN_FMT "%u" +#define mp_hal_pin_obj_t uint32_t +#define mp_hal_get_pin_obj(o) mp_obj_get_pin(o) +#define mp_hal_pin_name(p) (p) +void mp_hal_pin_input(mp_hal_pin_obj_t pin); +void mp_hal_pin_output(mp_hal_pin_obj_t pin); +void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin); +#define mp_hal_pin_od_low(p) do { \ + if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); } \ + else { gpio_output_set(0, 1 << (p), 1 << (p), 0); } \ + } while (0) +#define mp_hal_pin_od_high(p) do { \ + if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \ + else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \ + } while (0) +#define mp_hal_pin_read(p) pin_get(p) +#define mp_hal_pin_write(p, v) pin_set((p), (v)) + +void *ets_get_esf_buf_ctlblk(void); +int ets_esf_free_bufs(int idx); diff --git a/src/openmv/src/micropython/ports/esp8266/espapa102.c b/src/openmv/src/micropython/ports/esp8266/espapa102.c new file mode 100755 index 0000000..4295fe4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/espapa102.c @@ -0,0 +1,115 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Robert Foss, Daniel Busch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_ESP8266_APA102 + +#include +#include "c_types.h" +#include "eagle_soc.h" +#include "user_interface.h" +#include "espapa102.h" + +#define NOP asm volatile(" nop \n\t") + +static inline void _esp_apa102_send_byte(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t byte) { + for (uint32_t i = 0; i < 8; i++) { + if (byte & 0x80) { + // set data pin high + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask); + } else { + // set data pin low + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, dataPinMask); + } + + // set clock pin high + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask); + byte <<= 1; + NOP; + NOP; + + // set clock pin low + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask); + NOP; + NOP; + } +} + +static inline void _esp_apa102_send_colors(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t *pixels, uint32_t numBytes) { + for (uint32_t i = 0; i < numBytes / 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 3] | 0xE0); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 2]); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 1]); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4]); + } +} + +static inline void _esp_apa102_start_frame(uint32_t clockPinMask, uint32_t dataPinMask) { + for (uint32_t i = 0; i < 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00); + } +} + +static inline void _esp_apa102_append_additionial_cycles(uint32_t clockPinMask, uint32_t dataPinMask, uint32_t numBytes) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask); + + // we need to write some more clock cycles, because each led + // delays the data by one edge after inverting the clock + for (uint32_t i = 0; i < numBytes / 8 + ((numBytes / 4) % 2); i++) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask); + NOP; + NOP; + + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask); + NOP; + NOP; + } +} + +static inline void _esp_apa102_end_frame(uint32_t clockPinMask, uint32_t dataPinMask) { + for (uint32_t i = 0; i < 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, 0xFF); + } +} + +void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes) { + uint32_t clockPinMask, dataPinMask; + + clockPinMask = 1 << clockPin; + dataPinMask = 1 << dataPin; + + // start the frame + _esp_apa102_start_frame(clockPinMask, dataPinMask); + + // write pixels + _esp_apa102_send_colors(clockPinMask, dataPinMask, pixels, numBytes); + + // end the frame + _esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes); + _esp_apa102_end_frame(clockPinMask, dataPinMask); +} + +#endif diff --git a/src/openmv/src/micropython/ports/esp8266/espapa102.h b/src/openmv/src/micropython/ports/esp8266/espapa102.h new file mode 100755 index 0000000..dd7c5ab --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/espapa102.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Robert Foss, Daniel Busch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP8266_ESPAPA102_H +#define MICROPY_INCLUDED_ESP8266_ESPAPA102_H + +void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes); + +#endif // MICROPY_INCLUDED_ESP8266_ESPAPA102_H diff --git a/src/openmv/src/micropython/ports/esp8266/espneopixel.c b/src/openmv/src/micropython/ports/esp8266/espneopixel.c new file mode 100755 index 0000000..6c76591 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/espneopixel.c @@ -0,0 +1,65 @@ +// Original version from https://github.com/adafruit/Adafruit_NeoPixel +// Modifications by dpgeorge to support auto-CPU-frequency detection + +// This is a mash-up of the Due show() code + insights from Michael Miller's +// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus +// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. + +#include "py/mpconfig.h" +#if MICROPY_ESP8266_NEOPIXEL + +#include "c_types.h" +#include "eagle_soc.h" +#include "user_interface.h" +#include "espneopixel.h" +#include "esp_mphal.h" + +#define NEO_KHZ400 (1) + +void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) { + + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime, pinMask; + + pinMask = 1 << pin; + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + + uint32_t fcpu = system_get_cpu_freq() * 1000000; + +#ifdef NEO_KHZ400 + if(is800KHz) { +#endif + time0 = fcpu / 2857143; // 0.35us + time1 = fcpu / 1250000; // 0.8us + period = fcpu / 800000; // 1.25us per bit +#ifdef NEO_KHZ400 + } else { // 400 KHz bitstream + time0 = fcpu / 2000000; // 0.5uS + time1 = fcpu / 833333; // 1.2us + period = fcpu / 400000; // 2.5us per bit + } +#endif + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + for(t = time0;; t = time0) { + if(pix & mask) t = time1; // Bit high duration + while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high + startTime = c; // Save start time + while(((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low + if(!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit + mp_hal_quiet_timing_exit(irq_state); +} + +#endif // MICROPY_ESP8266_NEOPIXEL diff --git a/src/openmv/src/micropython/ports/esp8266/espneopixel.h b/src/openmv/src/micropython/ports/esp8266/espneopixel.h new file mode 100755 index 0000000..c444740 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/espneopixel.h @@ -0,0 +1,6 @@ +#ifndef MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H +#define MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H + +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz); + +#endif // MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H diff --git a/src/openmv/src/micropython/ports/esp8266/esppwm.c b/src/openmv/src/micropython/ports/esp8266/esppwm.c new file mode 100755 index 0000000..33eaf3b --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/esppwm.c @@ -0,0 +1,421 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: pwm.c + * + * Description: pwm driver + * + * Modification history: + * 2014/5/1, v1.0 create this file. + * 2016/3/2: Modifications by dpgeorge to suit MicroPython +*******************************************************************************/ +#include +#include + +#include "etshal.h" +#include "os_type.h" +#include "gpio.h" + +#include "esppwm.h" + +#include "py/mpprint.h" +#define PWM_DBG(...) +//#define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__) + +#define ICACHE_RAM_ATTR // __attribute__((section(".text"))) + +#define PWM_CHANNEL 8 +#define PWM_DEPTH 1023 +#define PWM_FREQ_MAX 1000 +#define PWM_1S 1000000 + +struct pwm_single_param { + uint16_t gpio_set; + uint16_t gpio_clear; + uint32_t h_time; +}; + +struct pwm_param { + uint32_t period; + uint16_t freq; + uint16_t duty[PWM_CHANNEL]; +}; + +STATIC const uint8_t pin_num[PWM_CHANNEL] = {0, 2, 4, 5, 12, 13, 14, 15}; + +STATIC struct pwm_single_param pwm_single_toggle[2][PWM_CHANNEL + 1]; +STATIC struct pwm_single_param *pwm_single; + +STATIC struct pwm_param pwm; + +STATIC int8_t pwm_out_io_num[PWM_CHANNEL] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +STATIC uint8_t pwm_channel_toggle[2]; +STATIC uint8_t *pwm_channel; +STATIC uint8_t pwm_toggle = 1; +STATIC uint8_t pwm_timer_down = 1; +STATIC uint8_t pwm_current_channel = 0; +STATIC uint16_t pwm_gpio = 0; +STATIC uint8_t pwm_channel_num = 0; + +//XXX: 0xffffffff/(80000000/16)=35A +#define US_TO_RTC_TIMER_TICKS(t) \ + ((t) ? \ + (((t) > 0x35A) ? \ + (((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)) : \ + (((t) *(APB_CLK_FREQ>>4)) / 1000000)) : \ + 0) + +//FRC1 +#define FRC1_ENABLE_TIMER BIT7 + +typedef enum { + DIVDED_BY_1 = 0, + DIVDED_BY_16 = 4, + DIVDED_BY_256 = 8, +} TIMER_PREDIVED_MODE; + +typedef enum { + TM_LEVEL_INT = 1, + TM_EDGE_INT = 0, +} TIMER_INT_MODE; + +STATIC void ICACHE_FLASH_ATTR +pwm_insert_sort(struct pwm_single_param pwm[], uint8 n) +{ + uint8 i; + + for (i = 1; i < n; i++) { + if (pwm[i].h_time < pwm[i - 1].h_time) { + int8 j = i - 1; + struct pwm_single_param tmp; + + memcpy(&tmp, &pwm[i], sizeof(struct pwm_single_param)); + memcpy(&pwm[i], &pwm[i - 1], sizeof(struct pwm_single_param)); + + while (tmp.h_time < pwm[j].h_time) { + memcpy(&pwm[j + 1], &pwm[j], sizeof(struct pwm_single_param)); + j--; + if (j < 0) { + break; + } + } + + memcpy(&pwm[j + 1], &tmp, sizeof(struct pwm_single_param)); + } + } +} + +STATIC volatile uint8 critical = 0; + +#define LOCK_PWM(c) do { \ + while( (c)==1 ); \ + (c) = 1; \ +} while (0) + +#define UNLOCK_PWM(c) do { \ + (c) = 0; \ +} while (0) + +void ICACHE_FLASH_ATTR +pwm_start(void) +{ + uint8 i, j; + PWM_DBG("--Function pwm_start() is called\n"); + PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num); + PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]); + PWM_DBG("pwm.period:%d,pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.period,pwm.duty[0],pwm.duty[1],pwm.duty[2]); + + LOCK_PWM(critical); // enter critical + + struct pwm_single_param *local_single = pwm_single_toggle[pwm_toggle ^ 0x01]; + uint8 *local_channel = &pwm_channel_toggle[pwm_toggle ^ 0x01]; + + // step 1: init PWM_CHANNEL+1 channels param + for (i = 0; i < pwm_channel_num; i++) { + uint32 us = pwm.period * pwm.duty[i] / PWM_DEPTH; + local_single[i].h_time = US_TO_RTC_TIMER_TICKS(us); + PWM_DBG("i:%d us:%d ht:%d\n",i,us,local_single[i].h_time); + local_single[i].gpio_set = 0; + local_single[i].gpio_clear = 1 << pin_num[pwm_out_io_num[i]]; + } + + local_single[pwm_channel_num].h_time = US_TO_RTC_TIMER_TICKS(pwm.period); + local_single[pwm_channel_num].gpio_set = pwm_gpio; + local_single[pwm_channel_num].gpio_clear = 0; + PWM_DBG("i:%d period:%d ht:%d\n",pwm_channel_num,pwm.period,local_single[pwm_channel_num].h_time); + // step 2: sort, small to big + pwm_insert_sort(local_single, pwm_channel_num + 1); + + *local_channel = pwm_channel_num + 1; + PWM_DBG("1channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time); + // step 3: combine same duty channels + for (i = pwm_channel_num; i > 0; i--) { + if (local_single[i].h_time == local_single[i - 1].h_time) { + local_single[i - 1].gpio_set |= local_single[i].gpio_set; + local_single[i - 1].gpio_clear |= local_single[i].gpio_clear; + + for (j = i + 1; j < *local_channel; j++) { + memcpy(&local_single[j - 1], &local_single[j], sizeof(struct pwm_single_param)); + } + + (*local_channel)--; + } + } + PWM_DBG("2channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time); + // step 4: cacl delt time + for (i = *local_channel - 1; i > 0; i--) { + local_single[i].h_time -= local_single[i - 1].h_time; + } + + // step 5: last channel needs to clean + local_single[*local_channel-1].gpio_clear = 0; + + // step 6: if first channel duty is 0, remove it + if (local_single[0].h_time == 0) { + local_single[*local_channel - 1].gpio_set &= ~local_single[0].gpio_clear; + local_single[*local_channel - 1].gpio_clear |= local_single[0].gpio_clear; + + for (i = 1; i < *local_channel; i++) { + memcpy(&local_single[i - 1], &local_single[i], sizeof(struct pwm_single_param)); + } + + (*local_channel)--; + } + + // if timer is down, need to set gpio and start timer + if (pwm_timer_down == 1) { + pwm_channel = local_channel; + pwm_single = local_single; + // start + gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0); + + pwm_timer_down = 0; + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time); + } + + if (pwm_toggle == 1) { + pwm_toggle = 0; + } else { + pwm_toggle = 1; + } + + UNLOCK_PWM(critical); // leave critical + PWM_DBG("3channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time); +} + +/****************************************************************************** + * FunctionName : pwm_set_duty + * Description : set each channel's duty params + * Parameters : int16_t duty : 0 ~ PWM_DEPTH + * uint8 channel : channel index + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +pwm_set_duty(int16_t duty, uint8 channel) +{ + uint8 i; + for(i=0;i= PWM_DEPTH) { + pwm.duty[channel] = PWM_DEPTH; + } else { + pwm.duty[channel] = duty; + } + UNLOCK_PWM(critical); // leave critical +} + +/****************************************************************************** + * FunctionName : pwm_set_freq + * Description : set pwm frequency + * Parameters : uint16 freq : 100hz typically + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +pwm_set_freq(uint16 freq, uint8 channel) +{ + LOCK_PWM(critical); // enter critical + if (freq > PWM_FREQ_MAX) { + pwm.freq = PWM_FREQ_MAX; + } else if (freq < 1) { + pwm.freq = 1; + } else { + pwm.freq = freq; + } + + pwm.period = PWM_1S / pwm.freq; + UNLOCK_PWM(critical); // leave critical +} + +/****************************************************************************** + * FunctionName : pwm_get_duty + * Description : get duty of each channel + * Parameters : uint8 channel : channel index + * Returns : NONE +*******************************************************************************/ +uint16 ICACHE_FLASH_ATTR +pwm_get_duty(uint8 channel) +{ + uint8 i; + for(i=0;i= (*pwm_channel - 1)) { // *pwm_channel may change outside + pwm_single = pwm_single_toggle[local_toggle]; + pwm_channel = &pwm_channel_toggle[local_toggle]; + + gpio_output_set(pwm_single[*pwm_channel - 1].gpio_set, + pwm_single[*pwm_channel - 1].gpio_clear, + pwm_gpio, + 0); + + pwm_current_channel = 0; + + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time); + } else { + gpio_output_set(pwm_single[pwm_current_channel].gpio_set, + pwm_single[pwm_current_channel].gpio_clear, + pwm_gpio, 0); + + pwm_current_channel++; + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time); + } +} + +/****************************************************************************** + * FunctionName : pwm_init + * Description : pwm gpio, params and timer initialization + * Parameters : uint16 freq : pwm freq param + * uint16 *duty : each channel's duty + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +pwm_init(void) +{ + uint8 i; + + RTC_REG_WRITE(FRC1_CTRL_ADDRESS, //FRC2_AUTO_RELOAD| + DIVDED_BY_16 + | FRC1_ENABLE_TIMER + | TM_EDGE_INT); + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0); + + for (i = 0; i < PWM_CHANNEL; i++) { + pwm_gpio = 0; + pwm.duty[i] = 0; + } + + pwm_set_freq(500, 0); + pwm_start(); + + ETS_FRC_TIMER1_INTR_ATTACH(pwm_tim1_intr_handler, NULL); + TM1_EDGE_INT_ENABLE(); + ETS_FRC1_INTR_ENABLE(); +} + +int ICACHE_FLASH_ATTR +pwm_add(uint8_t pin_id, uint32_t pin_mux, uint32_t pin_func){ + PWM_DBG("--Function pwm_add() is called. channel:%d\n", channel); + PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num); + PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]); + PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]); + int channel = -1; + for (int i = 0; i < PWM_CHANNEL; ++i) { + if (pin_num[i] == pin_id) { + channel = i; + break; + } + } + if (channel == -1) { + return -1; + } + uint8 i; + for(i=0;i +#include + +void pwm_init(void); +void pwm_start(void); + +void pwm_set_duty(int16_t duty, uint8_t channel); +uint16_t pwm_get_duty(uint8_t channel); +void pwm_set_freq(uint16_t freq, uint8_t channel); +uint16_t pwm_get_freq(uint8_t channel); +int pwm_add(uint8_t pin_id, uint32_t pin_mux, uint32_t pin_func); +bool pwm_delete(uint8_t channel); + +#endif // MICROPY_INCLUDED_ESP8266_ESPPWM_H diff --git a/src/openmv/src/micropython/ports/esp8266/ets_alt_task.c b/src/openmv/src/micropython/ports/esp8266/ets_alt_task.c new file mode 100755 index 0000000..6f9ae67 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/ets_alt_task.c @@ -0,0 +1,228 @@ +#include +#include "osapi.h" +#include "os_type.h" +#include "ets_sys.h" +#include +#include "etshal.h" +#include "user_interface.h" +#include "ets_alt_task.h" + +// Use standard ets_task or alternative impl +#define USE_ETS_TASK 0 + +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +struct task_entry { + os_event_t *queue; + os_task_t task; + uint8_t qlen; + uint8_t prio; + int8_t i_get; + int8_t i_put; +}; + +static void (*idle_cb)(void *); +static void *idle_arg; + +#if ESP_SDK_VERSION >= 010500 +# define FIRST_PRIO 0 +#else +# define FIRST_PRIO 0x14 +#endif +#define LAST_PRIO 0x20 +#define PRIO2ID(prio) ((prio) - FIRST_PRIO) + +volatile struct task_entry emu_tasks[PRIO2ID(LAST_PRIO) + 1]; + +static inline int prio2id(uint8_t prio) { + int id = PRIO2ID(prio); + if (id < 0 || id >= MP_ARRAY_SIZE(emu_tasks)) { + printf("task prio out of range: %d\n", prio); + while (1); + } + return id; +} + +#if DEBUG +void dump_task(int prio, volatile struct task_entry *t) { + printf("q for task %d: queue: %p, get ptr: %d, put ptr: %d, qlen: %d\n", + prio, t->queue, t->i_get, t->i_put, t->qlen); +} + +void dump_tasks(void) { + for (int i = 0; i < MP_ARRAY_SIZE(emu_tasks); i++) { + if (emu_tasks[i].qlen) { + dump_task(i + FIRST_PRIO, &emu_tasks[i]); + } + } + printf("====\n"); +} +#endif + +bool ets_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen) { + static unsigned cnt; + printf("#%d ets_task(%p, %d, %p, %d)\n", cnt++, task, prio, queue, qlen); +#if USE_ETS_TASK + return _ets_task(task, prio, queue, qlen); +#else + int id = prio2id(prio); + emu_tasks[id].task = task; + emu_tasks[id].queue = queue; + emu_tasks[id].qlen = qlen; + emu_tasks[id].i_get = 0; + emu_tasks[id].i_put = 0; + return true; +#endif +} + +bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) { +// static unsigned cnt; printf("#%d ets_post(%d, %x, %x)\n", cnt++, prio, sig, param); +#if USE_ETS_TASK + return _ets_post(prio, sig, param); +#else + ets_intr_lock(); + + const int id = prio2id(prio); + os_event_t *q = emu_tasks[id].queue; + if (emu_tasks[id].i_put == -1) { + // queue is full + printf("ets_post: task %d queue full\n", prio); + return 1; + } + q = &q[emu_tasks[id].i_put++]; + q->sig = sig; + q->par = param; + if (emu_tasks[id].i_put == emu_tasks[id].qlen) { + emu_tasks[id].i_put = 0; + } + if (emu_tasks[id].i_put == emu_tasks[id].i_get) { + // queue got full + emu_tasks[id].i_put = -1; + } + //printf("after ets_post: "); dump_task(prio, &emu_tasks[id]); + //dump_tasks(); + + ets_intr_unlock(); + + return 0; +#endif +} + +int ets_loop_iter_disable = 0; +int ets_loop_dont_feed_sw_wdt = 0; + +// to implement a 64-bit wide microsecond counter +static uint32_t system_time_prev = 0; +uint32_t system_time_high_word = 0; + +bool ets_loop_iter(void) { + if (ets_loop_iter_disable) { + return false; + } + + // handle overflow of system microsecond counter + ets_intr_lock(); + uint32_t system_time_cur = system_get_time(); + if (system_time_cur < system_time_prev) { + system_time_high_word += 1; // record overflow of low 32-bits + } + system_time_prev = system_time_cur; + ets_intr_unlock(); + + // 6 words before pend_flag_noise_check is a variable that is used by + // the software WDT. A 1.6 second period timer will increment this + // variable and if it gets to 2 then the SW WDT will trigger a reset. + extern uint32_t pend_flag_noise_check; + uint32_t *sw_wdt = &pend_flag_noise_check - 6; + + //static unsigned cnt; + bool progress = false; + for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) { + if (!ets_loop_dont_feed_sw_wdt) { + system_soft_wdt_feed(); + } + ets_intr_lock(); + //printf("etc_loop_iter: "); dump_task(t - emu_tasks + FIRST_PRIO, t); + if (t->i_get != t->i_put) { + progress = true; + //printf("#%d Calling task %d(%p) (%x, %x)\n", cnt++, + // t - emu_tasks + FIRST_PRIO, t->task, t->queue[t->i_get].sig, t->queue[t->i_get].par); + int idx = t->i_get; + if (t->i_put == -1) { + t->i_put = t->i_get; + } + if (++t->i_get == t->qlen) { + t->i_get = 0; + } + //ets_intr_unlock(); + uint32_t old_sw_wdt = *sw_wdt; + t->task(&t->queue[idx]); + if (ets_loop_dont_feed_sw_wdt) { + // Restore previous SW WDT counter, in case task fed/cleared it + *sw_wdt = old_sw_wdt; + } + //ets_intr_lock(); + //printf("Done calling task %d\n", t - emu_tasks + FIRST_PRIO); + } + ets_intr_unlock(); + } + return progress; +} + +#if SDK_BELOW_1_1_1 +void my_timer_isr(void *arg) { +// uart0_write_char('+'); + ets_post(0x1f, 0, 0); +} + +// Timer init func is in ROM, and calls ets_task by relative addr directly in ROM +// so, we have to re-init task using our handler +void ets_timer_init() { + printf("ets_timer_init\n"); +// _ets_timer_init(); + ets_isr_attach(10, my_timer_isr, NULL); + SET_PERI_REG_MASK(0x3FF00004, 4); + ETS_INTR_ENABLE(10); + ets_task((os_task_t)0x40002E3C, 0x1f, (os_event_t*)0x3FFFDDC0, 4); + + WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0); + WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x28, 0x88); + WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0); + printf("Installed timer ISR\n"); +} +#endif + +bool ets_run(void) { +#if USE_ETS_TASK + #if SDK_BELOW_1_1_1 + ets_isr_attach(10, my_timer_isr, NULL); + #endif + _ets_run(); +#else +// ets_timer_init(); + *(char*)0x3FFFC6FC = 0; + ets_intr_lock(); + printf("ets_alt_task: ets_run\n"); +#if DEBUG + dump_tasks(); +#endif + ets_intr_unlock(); + while (1) { + if (!ets_loop_iter()) { + //printf("idle\n"); + ets_intr_lock(); + if (idle_cb) { + idle_cb(idle_arg); + } + asm("waiti 0"); + ets_intr_unlock(); + } + } +#endif +} + +void ets_set_idle_cb(void (*handler)(void *), void *arg) { + //printf("ets_set_idle_cb(%p, %p)\n", handler, arg); + idle_cb = handler; + idle_arg = arg; +} diff --git a/src/openmv/src/micropython/ports/esp8266/ets_alt_task.h b/src/openmv/src/micropython/ports/esp8266/ets_alt_task.h new file mode 100755 index 0000000..e7a15c3 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/ets_alt_task.h @@ -0,0 +1,10 @@ +#ifndef MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H +#define MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H + +extern int ets_loop_iter_disable; +extern int ets_loop_dont_feed_sw_wdt; +extern uint32_t system_time_high_word; + +bool ets_loop_iter(void); + +#endif // MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H diff --git a/src/openmv/src/micropython/ports/esp8266/etshal.h b/src/openmv/src/micropython/ports/esp8266/etshal.h new file mode 100755 index 0000000..8d64573 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/etshal.h @@ -0,0 +1,45 @@ +#ifndef MICROPY_INCLUDED_ESP8266_ETSHAL_H +#define MICROPY_INCLUDED_ESP8266_ETSHAL_H + +#include + +// see http://esp8266-re.foogod.com/wiki/Random_Number_Generator +#define WDEV_HWRNG ((volatile uint32_t*)0x3ff20e44) + +void ets_delay_us(uint16_t us); +void ets_intr_lock(void); +void ets_intr_unlock(void); +void ets_isr_mask(uint32_t mask); +void ets_isr_unmask(uint32_t mask); +void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg); +void ets_install_putc1(); +void uart_div_modify(uint8_t uart, uint32_t divisor); +void ets_set_idle_cb(void (*handler)(void *), void *arg); + +void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer); +void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data); +void ets_timer_disarm(os_timer_t *tim); + +extern void ets_wdt_disable(void); +extern void wdt_feed(void); + +// Opaque structure +#ifndef MD5_CTX +typedef char MD5_CTX[88]; +#endif + +void MD5Init(MD5_CTX *context); +void MD5Update(MD5_CTX *context, const void *data, unsigned int len); +void MD5Final(unsigned char digest[16], MD5_CTX *context); + +// These prototypes are for recent SDKs with "malloc tracking" +void *pvPortMalloc(size_t sz, const char *fname, unsigned line); +void *pvPortZalloc(size_t sz, const char *fname, unsigned line); +void *pvPortRealloc(void *p, unsigned sz, const char *fname, unsigned line); +void vPortFree(void *p, const char *fname, unsigned line); + +uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len); +uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len); +uint32_t SPIEraseSector(int sector); + +#endif // MICROPY_INCLUDED_ESP8266_ETSHAL_H diff --git a/src/openmv/src/micropython/ports/esp8266/fatfs_port.c b/src/openmv/src/micropython/ports/esp8266/fatfs_port.c new file mode 100755 index 0000000..a8865c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/fatfs_port.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "lib/timeutils/timeutils.h" +#include "lib/oofatfs/ff.h" +#include "modmachine.h" + +DWORD get_fattime(void) { + + // TODO: Optimize division (there's no HW division support on ESP8266, + // so it's expensive). + uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000); + + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(secs, &tm); + + return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | + ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); +} diff --git a/src/openmv/src/micropython/ports/esp8266/gccollect.c b/src/openmv/src/micropython/ports/esp8266/gccollect.c new file mode 100755 index 0000000..dbe7bc1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/gccollect.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "gccollect.h" + +// As we do not have control over the application entry point, there is no way +// to figure out the real stack base on runtime, so it needs to be hardcoded +#define STACK_END 0x40000000 + +mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs); + +void gc_collect(void) { + // start the GC + gc_collect_start(); + + // get the registers and the sp + mp_uint_t regs[8]; + mp_uint_t sp = gc_helper_get_regs_and_sp(regs); + + // trace the stack, including the registers (since they live on the stack in this function) + gc_collect_root((void**)sp, (STACK_END - sp) / sizeof(uint32_t)); + + // end the GC + gc_collect_end(); +} diff --git a/src/openmv/src/micropython/ports/esp8266/gccollect.h b/src/openmv/src/micropython/ports/esp8266/gccollect.h new file mode 100755 index 0000000..4323e95 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/gccollect.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP8266_GCCOLLECT_H +#define MICROPY_INCLUDED_ESP8266_GCCOLLECT_H + +extern uint32_t _text_start; +extern uint32_t _text_end; +extern uint32_t _irom0_text_start; +extern uint32_t _irom0_text_end; +extern uint32_t _data_start; +extern uint32_t _data_end; +extern uint32_t _rodata_start; +extern uint32_t _rodata_end; +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern uint32_t _heap_start; +extern uint32_t _heap_end; + +void gc_collect(void); + +#endif // MICROPY_INCLUDED_ESP8266_GCCOLLECT_H diff --git a/src/openmv/src/micropython/ports/esp8266/gchelper.s b/src/openmv/src/micropython/ports/esp8266/gchelper.s new file mode 100755 index 0000000..cf543be --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/gchelper.s @@ -0,0 +1,22 @@ + .file "gchelper.s" + .text + + .align 4 + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, @function +gc_helper_get_regs_and_sp: + # store regs into given array + s32i.n a8, a2, 0 + s32i.n a9, a2, 4 + s32i.n a10, a2, 8 + s32i.n a11, a2, 12 + s32i.n a12, a2, 16 + s32i.n a13, a2, 20 + s32i.n a14, a2, 24 + s32i.n a15, a2, 28 + + # return the sp + mov a2, a1 + ret.n + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/src/openmv/src/micropython/ports/esp8266/help.c b/src/openmv/src/micropython/ports/esp8266/help.c new file mode 100755 index 0000000..0a851f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/help.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char esp_help_text[] = +"Welcome to MicroPython!\n" +"\n" +"For online docs please visit http://docs.micropython.org/en/latest/esp8266/ .\n" +"For diagnostic information to include in bug reports execute 'import port_diag'.\n" +"\n" +"Basic WiFi configuration:\n" +"\n" +"import network\n" +"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n" +"sta_if.scan() # Scan for available access points\n" +"sta_if.connect(\"\", \"\") # Connect to an AP\n" +"sta_if.isconnected() # Check for successful connection\n" +"# Change name/password of ESP8266's AP:\n" +"ap_if = network.WLAN(network.AP_IF)\n" +"ap_if.config(essid=\"\", authmode=network.AUTH_WPA_WPA2_PSK, password=\"\")\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; diff --git a/src/openmv/src/micropython/ports/esp8266/hspi.c b/src/openmv/src/micropython/ports/esp8266/hspi.c new file mode 100755 index 0000000..554a504 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/hspi.c @@ -0,0 +1,331 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* Modified 2016 by Radomir Dopieralski +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#include "hspi.h" + +/* +Wrapper to setup HSPI/SPI GPIO pins and default SPI clock + spi_no - SPI (0) or HSPI (1) +Not used in MicroPython. +*/ +void spi_init(uint8_t spi_no) { + spi_init_gpio(spi_no, SPI_CLK_USE_DIV); + spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV); + spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); +} + + +/* +Configures SPI mode parameters for clock edge and clock polarity. + spi_no - SPI (0) or HSPI (1) + spi_cpha - (0) Data is valid on clock leading edge + (1) Data is valid on clock trailing edge + spi_cpol - (0) Clock is low when inactive + (1) Clock is high when inactive +For MicroPython this version is different from original. +*/ +void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) { + if (spi_cpol) { + SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); + } else { + CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); + } + if (spi_cpha == spi_cpol) { + // Mode 3 - MOSI is set on falling edge of clock + // Mode 0 - MOSI is set on falling edge of clock + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); + SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); + } else { + // Mode 2 - MOSI is set on rising edge of clock + // Mode 1 - MOSI is set on rising edge of clock + SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); + } +} + + +/* +Initialise the GPIO pins for use as SPI pins. + spi_no - SPI (0) or HSPI (1) + sysclk_as_spiclk - + SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock. + SPI_CLK_USE_DIV (0) if using divider for lower speed. +*/ +void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) { + uint32_t clock_div_flag = 0; + if (sysclk_as_spiclk) { + clock_div_flag = 0x0001; + } + if (spi_no == SPI) { + // Set bit 8 if 80MHz sysclock required + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8)); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1); + } else if (spi_no == HSPI) { + // Set bit 9 if 80MHz sysclock required + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9)); + // GPIO12 is HSPI MISO pin (Master Data In) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); + // GPIO13 is HSPI MOSI pin (Master Data Out) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); + // GPIO14 is HSPI CLK pin (Clock) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); + // GPIO15 is HSPI CS pin (Chip Select / Slave Select) + // In MicroPython, we are handling CS ourself in drivers. + // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); + } +} + + +/* +Set up the control registers for the SPI clock + spi_no - SPI (0) or HSPI (1) + prediv - predivider value (actual division value) + cntdiv - postdivider value (actual division value) +Set either divider to 0 to disable all division (80MHz sysclock) +*/ +void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) { + if (prediv == 0 || cntdiv == 0) { + WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); + } else { + WRITE_PERI_REG(SPI_CLOCK(spi_no), + (((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | + (((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | + (((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | + ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S) + ); + } +} + + +/* +Setup the byte order for shifting data out of buffer + spi_no - SPI (0) or HSPI (1) + byte_order - + SPI_BYTE_ORDER_HIGH_TO_LOW (1) + Data is sent out starting with Bit31 and down to Bit0 + SPI_BYTE_ORDER_LOW_TO_HIGH (0) + Data is sent out starting with the lowest BYTE, from MSB to LSB, + followed by the second lowest BYTE, from MSB to LSB, followed by + the second highest BYTE, from MSB to LSB, followed by the highest + BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB. +*/ +void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) { + if (byte_order) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } +} + + +/* +Setup the byte order for shifting data into buffer + spi_no - SPI (0) or HSPI (1) + byte_order - + SPI_BYTE_ORDER_HIGH_TO_LOW (1) + Data is read in starting with Bit31 and down to Bit0 + SPI_BYTE_ORDER_LOW_TO_HIGH (0) + Data is read in starting with the lowest BYTE, from MSB to LSB, + followed by the second lowest BYTE, from MSB to LSB, followed by + the second highest BYTE, from MSB to LSB, followed by the highest + BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB +*/ +void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) { + if (byte_order) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } +} + + +/* +SPI transaction function + spi_no - SPI (0) or HSPI (1) + cmd_bits - actual number of bits to transmit + cmd_data - command data + addr_bits - actual number of bits to transmit + addr_data - address data + dout_bits - actual number of bits to transmit + dout_data - output data + din_bits - actual number of bits to receive +Returns: read data - uint32_t containing read in data only if RX was set + 0 - something went wrong (or actual read data was 0) + 1 - data sent ok (or actual read data is 1) +Note: all data is assumed to be stored in the lower bits of the data variables +(for anything <32 bits). +*/ +uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, + uint32_t addr_bits, uint32_t addr_data, + uint32_t dout_bits, uint32_t dout_data, + uint32_t din_bits, uint32_t dummy_bits) { + while (spi_busy(spi_no)) {}; // Wait for SPI to be ready + +// Enable SPI Functions + // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | + SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); + + // Enable functions based on number of bits. 0 bits = disabled. + // This is rather inefficient but allows for a very generic function. + // CMD ADDR and MOSI are set below to save on an extra if statement. + if (din_bits) { + if (dout_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); + } else { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + } + } + if (dummy_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); + } + +// Setup Bitlengths + WRITE_PERI_REG(SPI_USER1(spi_no), + // Number of bits in Address + ((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S | + // Number of bits to Send + ((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | + // Number of bits to receive + ((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S | + // Number of Dummy bits to insert + ((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S); + +// Setup Command Data + if (cmd_bits) { + // Enable COMMAND function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); + // Align command data to high bits + uint16_t command = cmd_data << (16-cmd_bits); + // Swap byte order + command = ((command>>8)&0xff) | ((command<<8)&0xff00); + WRITE_PERI_REG(SPI_USER2(spi_no), ( + (((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | + (command & SPI_USR_COMMAND_VALUE) + )); + } + +// Setup Address Data + if (addr_bits) { + // Enable ADDRess function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR); + // Align address data to high bits + WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits)); + } + +// Setup DOUT data + if (dout_bits) { + // Enable MOSI function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); + // Copy data to W0 + if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits)); + } else { + uint8_t dout_extra_bits = dout_bits%8; + + if (dout_extra_bits) { + // If your data isn't a byte multiple (8/16/24/32 bits) and you + // don't have SPI_WR_BYTE_ORDER set, you need this to move the + // non-8bit remainder to the MSBs. Not sure if there's even a use + // case for this, but it's here if you need it... For example, + // 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output + // as if it were 0x0DA4, of which 0xA4, and then 0x0 would be + // shifted out (first 8 bits of low byte, then 4 MSB bits of high + // byte - ie reverse byte order). + // The code below shifts it out as 0xA4 followed by 0xD as you + // might require. + WRITE_PERI_REG(SPI_W0(spi_no), ( + (0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data) + << (8-dout_extra_bits) | + ((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits))) + & dout_data) + )); + } else { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data); + } + } +} + +// Begin SPI Transaction + SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); + +// Return DIN data + if (din_bits) { + while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete + if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) { + // Assuming data in is written to MSB. TBC + return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits); + } else { + // Read in the same way as DOUT is sent. Note existing contents of + // SPI_W0 remain unless overwritten! + return READ_PERI_REG(SPI_W0(spi_no)); + } + return 0; // Something went wrong + } + + // Transaction completed + return 1; // Success +} + + +/* +Just do minimal work needed to send 8 bits. +*/ +inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) { + while (spi_busy(spi_no)) {}; // Wait for SPI to be ready + +// Enable SPI Functions + // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | + SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); + +// Setup Bitlengths + WRITE_PERI_REG(SPI_USER1(spi_no), + // Number of bits to Send + ((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | + // Number of bits to receive + ((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S); + + +// Setup DOUT data + // Enable MOSI function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); + // Copy data to W0 + if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8)); + } else { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data); + } + +// Begin SPI Transaction + SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); +} diff --git a/src/openmv/src/micropython/ports/esp8266/hspi.h b/src/openmv/src/micropython/ports/esp8266/hspi.h new file mode 100755 index 0000000..c68366e --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/hspi.h @@ -0,0 +1,79 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* Modified 2016 by Radomir Dopieralski +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#ifndef SPI_APP_H +#define SPI_APP_H + +#include "hspi_register.h" +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" + +// Define SPI hardware modules +#define SPI 0 +#define HSPI 1 + +#define SPI_CLK_USE_DIV 0 +#define SPI_CLK_80MHZ_NODIV 1 + +#define SPI_BYTE_ORDER_HIGH_TO_LOW 1 +#define SPI_BYTE_ORDER_LOW_TO_HIGH 0 + +#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h +#define CPU_CLK_FREQ (80 * 1000000) +#endif + +// Define some default SPI clock settings +#define SPI_CLK_PREDIV 10 +#define SPI_CLK_CNTDIV 2 +#define SPI_CLK_FREQ (CPU_CLK_FREQ / (SPI_CLK_PREDIV * SPI_CLK_CNTDIV)) +// 80 / 20 = 4 MHz + +void spi_init(uint8_t spi_no); +void spi_mode(uint8_t spi_no, uint8_t spi_cpha,uint8_t spi_cpol); +void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk); +void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv); +void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order); +void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order); +uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, + uint32_t addr_bits, uint32_t addr_data, + uint32_t dout_bits, uint32_t dout_data, + uint32_t din_bits, uint32_t dummy_bits); +void spi_tx8fast(uint8_t spi_no, uint8_t dout_data); + +// Expansion Macros +#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR + +#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32_t) data, 0, 0) +#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32_t) data, 0, 0) +#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32_t) data, 0, 0) +#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32_t) data, 0, 0) + +#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0) +#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0) +#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0) +#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0) + +#endif diff --git a/src/openmv/src/micropython/ports/esp8266/hspi_register.h b/src/openmv/src/micropython/ports/esp8266/hspi_register.h new file mode 100755 index 0000000..4dd335b --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/hspi_register.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 - 2011 Espressif System + * Modified by David Ogilvy (MetalPhreak) + * Based on original file included in SDK 1.0.0 + * + * Missing defines from previous SDK versions have + * been added and are noted with comments. The + * names of these defines are likely to change. + */ + +#ifndef SPI_REGISTER_H_INCLUDED +#define SPI_REGISTER_H_INCLUDED + +#define REG_SPI_BASE(i) (0x60000200-i*0x100) + +#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) +#define SPI_FLASH_READ (BIT(31)) //From previous SDK +#define SPI_FLASH_WREN (BIT(30)) //From previous SDK +#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK +#define SPI_FLASH_RDID (BIT(28)) //From previous SDK +#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK +#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK +#define SPI_FLASH_PP (BIT(25)) //From previous SDK +#define SPI_FLASH_SE (BIT(24)) //From previous SDK +#define SPI_FLASH_BE (BIT(23)) //From previous SDK +#define SPI_FLASH_CE (BIT(22)) //From previous SDK +#define SPI_FLASH_DP (BIT(21)) //From previous SDK +#define SPI_FLASH_RES (BIT(20)) //From previous SDK +#define SPI_FLASH_HPM (BIT(19)) //From previous SDK +#define SPI_USR (BIT(18)) + +#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) + +#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) +#define SPI_WR_BIT_ORDER (BIT(26)) +#define SPI_RD_BIT_ORDER (BIT(25)) +#define SPI_QIO_MODE (BIT(24)) +#define SPI_DIO_MODE (BIT(23)) +#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK +#define SPI_WP_REG (BIT(21)) //From previous SDK +#define SPI_QOUT_MODE (BIT(20)) +#define SPI_SHARE_BUS (BIT(19)) //From previous SDK +#define SPI_HOLD_MODE (BIT(18)) //From previous SDK +#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK +#define SPI_SST_AAI (BIT(16)) //From previous SDK +#define SPI_RESANDRES (BIT(15)) //From previous SDK +#define SPI_DOUT_MODE (BIT(14)) +#define SPI_FASTRD_MODE (BIT(13)) + +#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS +#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS +#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK +#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK + + +#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) +#define SPI_STATUS_EXT 0x000000FF //From previous SDK +#define SPI_STATUS_EXT_S 24 //From previous SDK +#define SPI_WB_MODE 0x000000FF //From previous SDK +#define SPI_WB_MODE_S 16 //From previous SDK +#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK +#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK +#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK +#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK +#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK +#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK +#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK + +#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) +#define SPI_CS_DELAY_NUM 0x0000000F +#define SPI_CS_DELAY_NUM_S 28 +#define SPI_CS_DELAY_MODE 0x00000003 +#define SPI_CS_DELAY_MODE_S 26 +#define SPI_MOSI_DELAY_NUM 0x00000007 +#define SPI_MOSI_DELAY_NUM_S 23 +#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk + //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk + //mode 2 : Do not use this mode. +#define SPI_MOSI_DELAY_MODE_S 21 +#define SPI_MISO_DELAY_NUM 0x00000007 +#define SPI_MISO_DELAY_NUM_S 18 +#define SPI_MISO_DELAY_MODE 0x00000003 +#define SPI_MISO_DELAY_MODE_S 16 +#define SPI_CK_OUT_HIGH_MODE 0x0000000F +#define SPI_CK_OUT_HIGH_MODE_S 12 +#define SPI_CK_OUT_LOW_MODE 0x0000000F +#define SPI_CK_OUT_LOW_MODE_S 8 +#define SPI_HOLD_TIME 0x0000000F +#define SPI_HOLD_TIME_S 4 +#define SPI_SETUP_TIME 0x0000000F +#define SPI_SETUP_TIME_S 0 + +#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) +#define SPI_CLK_EQU_SYSCLK (BIT(31)) +#define SPI_CLKDIV_PRE 0x00001FFF +#define SPI_CLKDIV_PRE_S 18 +#define SPI_CLKCNT_N 0x0000003F +#define SPI_CLKCNT_N_S 12 +#define SPI_CLKCNT_H 0x0000003F +#define SPI_CLKCNT_H_S 6 +#define SPI_CLKCNT_L 0x0000003F +#define SPI_CLKCNT_L_S 0 + +#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) +#define SPI_USR_COMMAND (BIT(31)) +#define SPI_USR_ADDR (BIT(30)) +#define SPI_USR_DUMMY (BIT(29)) +#define SPI_USR_MISO (BIT(28)) +#define SPI_USR_MOSI (BIT(27)) +#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK +#define SPI_USR_MOSI_HIGHPART (BIT(25)) +#define SPI_USR_MISO_HIGHPART (BIT(24)) +#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK +#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK +#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK +#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK +#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK +#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK +#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK +#define SPI_SIO (BIT(16)) +#define SPI_FWRITE_QIO (BIT(15)) +#define SPI_FWRITE_DIO (BIT(14)) +#define SPI_FWRITE_QUAD (BIT(13)) +#define SPI_FWRITE_DUAL (BIT(12)) +#define SPI_WR_BYTE_ORDER (BIT(11)) +#define SPI_RD_BYTE_ORDER (BIT(10)) +#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK +#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK +#define SPI_CK_OUT_EDGE (BIT(7)) +#define SPI_CK_I_EDGE (BIT(6)) +#define SPI_CS_SETUP (BIT(5)) +#define SPI_CS_HOLD (BIT(4)) +#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK +#define SPI_FLASH_MODE (BIT(2)) +#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK +#define SPI_DOUTDIN (BIT(0)) //From previous SDK + +//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ? + + +#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) +#define SPI_USR_ADDR_BITLEN 0x0000003F +#define SPI_USR_ADDR_BITLEN_S 26 +#define SPI_USR_MOSI_BITLEN 0x000001FF +#define SPI_USR_MOSI_BITLEN_S 17 +#define SPI_USR_MISO_BITLEN 0x000001FF +#define SPI_USR_MISO_BITLEN_S 8 +#define SPI_USR_DUMMY_CYCLELEN 0x000000FF +#define SPI_USR_DUMMY_CYCLELEN_S 0 + +#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) +#define SPI_USR_COMMAND_BITLEN 0x0000000F +#define SPI_USR_COMMAND_BITLEN_S 28 +#define SPI_USR_COMMAND_VALUE 0x0000FFFF +#define SPI_USR_COMMAND_VALUE_S 0 + +#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) + //previously defined as SPI_FLASH_USER3. No further info available. + +#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) +#define SPI_IDLE_EDGE (BIT(29)) +#define SPI_CS2_DIS (BIT(2)) +#define SPI_CS1_DIS (BIT(1)) +#define SPI_CS0_DIS (BIT(0)) + +#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) +#define SPI_SYNC_RESET (BIT(31)) +#define SPI_SLAVE_MODE (BIT(30)) +#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) +#define SPI_SLV_WR_RD_STA_EN (BIT(28)) +#define SPI_SLV_CMD_DEFINE (BIT(27)) +#define SPI_TRANS_CNT 0x0000000F +#define SPI_TRANS_CNT_S 23 +#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK +#define SPI_SLV_LAST_STATE_S 20 //From previous SDK +#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK +#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK +#define SPI_CS_I_MODE 0x00000003 //From previous SDK +#define SPI_CS_I_MODE_S 10 //From previous SDK +#define SPI_TRANS_DONE_EN (BIT(9)) +#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) +#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) +#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) +#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) +#define SLV_SPI_INT_EN 0x0000001f +#define SLV_SPI_INT_EN_S 5 +#define SPI_TRANS_DONE (BIT(4)) +#define SPI_SLV_WR_STA_DONE (BIT(3)) +#define SPI_SLV_RD_STA_DONE (BIT(2)) +#define SPI_SLV_WR_BUF_DONE (BIT(1)) +#define SPI_SLV_RD_BUF_DONE (BIT(0)) + +#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) +#define SPI_SLV_STATUS_BITLEN 0x0000001F +#define SPI_SLV_STATUS_BITLEN_S 27 +#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK +#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK +#define SPI_SLV_BUF_BITLEN 0x000001FF +#define SPI_SLV_BUF_BITLEN_S 16 +#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F +#define SPI_SLV_RD_ADDR_BITLEN_S 10 +#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F +#define SPI_SLV_WR_ADDR_BITLEN_S 4 +#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) +#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) +#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) +#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) + + + +#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 + +#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) +#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_WRSTA_CMD_VALUE_S 24 +#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_RDSTA_CMD_VALUE_S 16 +#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_WRBUF_CMD_VALUE_S 8 +#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_RDBUF_CMD_VALUE_S 0 + +//Previous SDKs referred to these following registers as SPI_C0 etc. + +#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) +#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) +#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) +#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) +#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) +#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) +#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) +#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) +#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) +#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) +#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) +#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) +#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) +#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) +#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) +#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) + + // +0x80 to +0xBC could be SPI_W16 through SPI_W31? + + // +0xC0 to +0xEC not currently defined. + +#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_PP_ENA (BIT(31)) //From previous SDK +#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK +#define SPI_T_PP_SHIFT_S 16 //From previous SDK +#define SPI_T_PP_TIME 0x00000FFF //From previous SDK +#define SPI_T_PP_TIME_S 0 //From previous SDK + +#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK +#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK +#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK +#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK +#define SPI_T_ERASE_TIME_S 0 //From previous SDK + +#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_ST 0x00000007 //From previous SDK +#define SPI_ST_S 0 //From previous SDK + +#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) +#define SPI_INT_HOLD_ENA 0x00000003 +#define SPI_INT_HOLD_ENA_S 0 +#endif // SPI_REGISTER_H_INCLUDED diff --git a/src/openmv/src/micropython/ports/esp8266/intr.c b/src/openmv/src/micropython/ports/esp8266/intr.c new file mode 100755 index 0000000..456d6cb --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/intr.c @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "etshal.h" +#include "ets_alt_task.h" + +#include "modmachine.h" + +// this is in a separate file so it can go in iRAM +void pin_intr_handler_iram(void *arg) { + uint32_t status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, status); + pin_intr_handler(status); +} diff --git a/src/openmv/src/micropython/ports/esp8266/lexerstr32.c b/src/openmv/src/micropython/ports/esp8266/lexerstr32.c new file mode 100755 index 0000000..6fb84bb --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/lexerstr32.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/lexer.h" + +#if MICROPY_ENABLE_COMPILER + +typedef struct _mp_lexer_str32_buf_t { + const uint32_t *src_cur; + uint32_t val; + uint8_t byte_off; +} mp_lexer_str32_buf_t; + +STATIC mp_uint_t str32_buf_next_byte(void *sb_in) { + mp_lexer_str32_buf_t *sb = (mp_lexer_str32_buf_t*)sb_in; + byte c = sb->val & 0xff; + if (c == 0) { + return MP_READER_EOF; + } + + if (++sb->byte_off > 3) { + sb->byte_off = 0; + sb->val = *sb->src_cur++; + } else { + sb->val >>= 8; + } + + return c; +} + +STATIC void str32_buf_free(void *sb_in) { + mp_lexer_str32_buf_t *sb = (mp_lexer_str32_buf_t*)sb_in; + m_del_obj(mp_lexer_str32_buf_t, sb); +} + +mp_lexer_t *mp_lexer_new_from_str32(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) { + mp_lexer_str32_buf_t *sb = m_new_obj(mp_lexer_str32_buf_t); + sb->byte_off = (uint32_t)str & 3; + sb->src_cur = (uint32_t*)(str - sb->byte_off); + sb->val = *sb->src_cur++ >> sb->byte_off * 8; + mp_reader_t reader = {sb, str32_buf_next_byte, str32_buf_free}; + return mp_lexer_new(src_name, reader); +} + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/ports/esp8266/machine_adc.c b/src/openmv/src/micropython/ports/esp8266/machine_adc.c new file mode 100755 index 0000000..b422f0f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_adc.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "user_interface.h" + +const mp_obj_type_t pyb_adc_type; + +typedef struct _pyb_adc_obj_t { + mp_obj_base_t base; + bool isvdd; +} pyb_adc_obj_t; + +STATIC pyb_adc_obj_t pyb_adc_vdd3 = {{&pyb_adc_type}, true}; +STATIC pyb_adc_obj_t pyb_adc_adc = {{&pyb_adc_type}, false}; + +STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_int_t chn = mp_obj_get_int(args[0]); + + switch (chn) { + case 0: + return &pyb_adc_adc; + case 1: + return &pyb_adc_vdd3; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "not a valid ADC Channel: %d", chn)); + } +} + +STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) { + pyb_adc_obj_t *adc = self_in; + + if (adc->isvdd) { + return mp_obj_new_int(system_get_vdd33()); + } else { + return mp_obj_new_int(system_adc_read()); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_adc_read_obj, pyb_adc_read); + +STATIC const mp_rom_map_elem_t pyb_adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_adc_read_obj) } +}; +STATIC MP_DEFINE_CONST_DICT(pyb_adc_locals_dict, pyb_adc_locals_dict_table); + +const mp_obj_type_t pyb_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .make_new = pyb_adc_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_adc_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/machine_hspi.c b/src/openmv/src/micropython/ports/esp8266/machine_hspi.c new file mode 100755 index 0000000..07770c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_hspi.c @@ -0,0 +1,186 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "ets_sys.h" +#include "etshal.h" +#include "ets_alt_task.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" +#include "hspi.h" + +#if MICROPY_PY_MACHINE_SPI + +typedef struct _machine_hspi_obj_t { + mp_obj_base_t base; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; +} machine_hspi_obj_t; + +STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + (void)self_in; + + if (dest == NULL) { + // fast case when we only need to write data + size_t chunk_size = 1024; + size_t count = len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + spi_tx8fast(HSPI, src[i]); + ++i; + } + ets_loop_iter(); + } + while (i < len) { + spi_tx8fast(HSPI, src[i]); + ++i; + } + // wait for SPI transaction to complete + while (spi_busy(HSPI)) { + } + } else { + // we need to read and write data + + // Process data in chunks, let the pending tasks run in between + size_t chunk_size = 1024; // TODO this should depend on baudrate + size_t count = len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < len) { + dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0); + ++i; + } + } +} + +/******************************************************************************/ +// MicroPython bindings for HSPI + +STATIC void machine_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "HSPI(id=1, baudrate=%u, polarity=%u, phase=%u)", + self->baudrate, self->polarity, self->phase); +} + +STATIC void machine_hspi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_hspi_obj_t *self = (machine_hspi_obj_t*)self_in; + + enum { ARG_baudrate, ARG_polarity, ARG_phase }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), + allowed_args, args); + + if (args[ARG_baudrate].u_int != -1) { + self->baudrate = args[ARG_baudrate].u_int; + } + if (args[ARG_polarity].u_int != -1) { + self->polarity = args[ARG_polarity].u_int; + } + if (args[ARG_phase].u_int != -1) { + self->phase = args[ARG_phase].u_int; + } + if (self->baudrate == 80000000L) { + // Special case for full speed. + spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV); + spi_clock(HSPI, 0, 0); + } else if (self->baudrate > 40000000L) { + mp_raise_ValueError("impossible baudrate"); + } else { + uint32_t divider = 40000000L / self->baudrate; + uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1); + uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even + if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) { + mp_raise_ValueError("impossible baudrate"); + } + self->baudrate = 80000000L / (prediv * cntdiv); + spi_init_gpio(HSPI, SPI_CLK_USE_DIV); + spi_clock(HSPI, prediv, cntdiv); + } + // TODO: Make the byte order configurable too (discuss param names) + spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); + spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE | SPI_USR_MISO | + SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY); + // Clear Dual or Quad lines transmission mode + CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_QIO_MODE | SPI_DIO_MODE | + SPI_DOUT_MODE | SPI_QOUT_MODE); + spi_mode(HSPI, self->phase, self->polarity); +} + +mp_obj_t machine_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // args[0] holds the id of the peripheral + if (args[0] != MP_OBJ_NEW_SMALL_INT(1)) { + // FlashROM is on SPI0, so far we don't support its usage + mp_raise_ValueError(NULL); + } + + machine_hspi_obj_t *self = m_new_obj(machine_hspi_obj_t); + self->base.type = &machine_hspi_type; + // set defaults + self->baudrate = 80000000L; + self->polarity = 0; + self->phase = 0; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_hspi_init((mp_obj_base_t*)self, n_args - 1, args + 1, &kw_args); + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_spi_p_t machine_hspi_p = { + .init = machine_hspi_init, + .transfer = machine_hspi_transfer, +}; + +const mp_obj_type_t machine_hspi_type = { + { &mp_type_type }, + .name = MP_QSTR_HSPI, + .print = machine_hspi_print, + .make_new = mp_machine_spi_make_new, // delegate to master constructor + .protocol = &machine_hspi_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/src/openmv/src/micropython/ports/esp8266/machine_pin.c b/src/openmv/src/micropython/ports/esp8266/machine_pin.c new file mode 100755 index 0000000..14505c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_pin.c @@ -0,0 +1,518 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "etshal.h" +#include "c_types.h" +#include "user_interface.h" +#include "gpio.h" + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "extmod/virtpin.h" +#include "modmachine.h" + +#define GET_TRIGGER(phys_port) \ + GPIO_PIN_INT_TYPE_GET(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port))) +#define SET_TRIGGER(phys_port, trig) \ + (GPIO_REG_WRITE(GPIO_PIN_ADDR(phys_port), \ + (GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)) & ~GPIO_PIN_INT_TYPE_MASK) \ + | GPIO_PIN_INT_TYPE_SET(trig))) \ + +#define GPIO_MODE_INPUT (0) +#define GPIO_MODE_OUTPUT (1) +#define GPIO_MODE_OPEN_DRAIN (2) // synthesised +#define GPIO_PULL_NONE (0) +#define GPIO_PULL_UP (1) +// Removed in SDK 1.1.0 +//#define GPIO_PULL_DOWN (2) + +typedef struct _pin_irq_obj_t { + mp_obj_base_t base; + uint16_t phys_port; +} pin_irq_obj_t; + +const pyb_pin_obj_t pyb_pin_obj[16 + 1] = { + {{&pyb_pin_type}, 0, FUNC_GPIO0, PERIPHS_IO_MUX_GPIO0_U}, + {{&pyb_pin_type}, 1, FUNC_GPIO1, PERIPHS_IO_MUX_U0TXD_U}, + {{&pyb_pin_type}, 2, FUNC_GPIO2, PERIPHS_IO_MUX_GPIO2_U}, + {{&pyb_pin_type}, 3, FUNC_GPIO3, PERIPHS_IO_MUX_U0RXD_U}, + {{&pyb_pin_type}, 4, FUNC_GPIO4, PERIPHS_IO_MUX_GPIO4_U}, + {{&pyb_pin_type}, 5, FUNC_GPIO5, PERIPHS_IO_MUX_GPIO5_U}, + {{NULL}, 0, 0, 0}, + {{NULL}, 0, 0, 0}, + {{NULL}, 0, 0, 0}, + {{&pyb_pin_type}, 9, FUNC_GPIO9, PERIPHS_IO_MUX_SD_DATA2_U}, + {{&pyb_pin_type}, 10, FUNC_GPIO10, PERIPHS_IO_MUX_SD_DATA3_U}, + {{NULL}, 0, 0, 0}, + {{&pyb_pin_type}, 12, FUNC_GPIO12, PERIPHS_IO_MUX_MTDI_U}, + {{&pyb_pin_type}, 13, FUNC_GPIO13, PERIPHS_IO_MUX_MTCK_U}, + {{&pyb_pin_type}, 14, FUNC_GPIO14, PERIPHS_IO_MUX_MTMS_U}, + {{&pyb_pin_type}, 15, FUNC_GPIO15, PERIPHS_IO_MUX_MTDO_U}, + // GPIO16 is special, belongs to different register set, and + // otherwise handled specially. + {{&pyb_pin_type}, 16, -1, -1}, +}; + +STATIC uint8_t pin_mode[16 + 1]; + +// forward declaration +STATIC const pin_irq_obj_t pin_irq_obj[16]; + +// whether the irq is hard or soft +STATIC bool pin_irq_is_hard[16]; + +void pin_init0(void) { + ETS_GPIO_INTR_DISABLE(); + ETS_GPIO_INTR_ATTACH(pin_intr_handler_iram, NULL); + // disable all interrupts + memset(&MP_STATE_PORT(pin_irq_handler)[0], 0, 16 * sizeof(mp_obj_t)); + memset(pin_irq_is_hard, 0, sizeof(pin_irq_is_hard)); + for (int p = 0; p < 16; ++p) { + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << p); + SET_TRIGGER(p, 0); + } + ETS_GPIO_INTR_ENABLE(); +} + +void pin_intr_handler(uint32_t status) { + mp_sched_lock(); + gc_lock(); + status &= 0xffff; + for (int p = 0; status; ++p, status >>= 1) { + if (status & 1) { + mp_obj_t handler = MP_STATE_PORT(pin_irq_handler)[p]; + if (handler != MP_OBJ_NULL) { + if (pin_irq_is_hard[p]) { + mp_call_function_1_protected(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p])); + } else { + mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p])); + } + } + } + } + gc_unlock(); + mp_sched_unlock(); +} + +pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &pyb_pin_type) { + mp_raise_ValueError("expecting a pin"); + } + pyb_pin_obj_t *self = pin_in; + return self; +} + +uint mp_obj_get_pin(mp_obj_t pin_in) { + return mp_obj_get_pin_obj(pin_in)->phys_port; +} + +void mp_hal_pin_input(mp_hal_pin_obj_t pin_id) { + pin_mode[pin_id] = GPIO_MODE_INPUT; + if (pin_id == 16) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input + } else { + const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id]; + PIN_FUNC_SELECT(self->periph, self->func); + PIN_PULLUP_DIS(self->periph); + gpio_output_set(0, 0, 0, 1 << self->phys_port); + } +} + +void mp_hal_pin_output(mp_hal_pin_obj_t pin_id) { + pin_mode[pin_id] = GPIO_MODE_OUTPUT; + if (pin_id == 16) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); // output + } else { + const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id]; + PIN_FUNC_SELECT(self->periph, self->func); + PIN_PULLUP_DIS(self->periph); + gpio_output_set(0, 0, 1 << self->phys_port, 0); + } +} + +void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) { + const pyb_pin_obj_t *pin = &pyb_pin_obj[pin_id]; + + if (pin->phys_port == 16) { + // configure GPIO16 as input with output register holding 0 + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input + WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1)); // out=0 + return; + } + + ETS_GPIO_INTR_DISABLE(); + PIN_FUNC_SELECT(pin->periph, pin->func); + GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)), + GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port))) + | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain + GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, + GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << pin->phys_port)); + ETS_GPIO_INTR_ENABLE(); +} + +int pin_get(uint pin) { + if (pin == 16) { + return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1; + } + return GPIO_INPUT_GET(pin); +} + +void pin_set(uint pin, int value) { + if (pin == 16) { + int out_en = (pin_mode[pin] == GPIO_MODE_OUTPUT); + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | out_en); + WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1) | value); + return; + } + + uint32_t enable = 0; + uint32_t disable = 0; + switch (pin_mode[pin]) { + case GPIO_MODE_INPUT: + value = -1; + disable = 1; + break; + + case GPIO_MODE_OUTPUT: + enable = 1; + break; + + case GPIO_MODE_OPEN_DRAIN: + if (value == -1) { + return; + } else if (value == 0) { + enable = 1; + } else { + value = -1; + disable = 1; + } + break; + } + + enable <<= pin; + disable <<= pin; + if (value == -1) { + gpio_output_set(0, 0, enable, disable); + } else { + gpio_output_set(value << pin, (1 - value) << pin, enable, disable); + } +} + +STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_pin_obj_t *self = self_in; + + // pin name + mp_printf(print, "Pin(%u)", self->phys_port); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get io mode + uint mode = args[ARG_mode].u_int; + + // get pull mode + uint pull = GPIO_PULL_NONE; + if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + } + + // get initial value + int value; + if (args[ARG_value].u_obj == MP_OBJ_NULL) { + value = -1; + } else { + value = mp_obj_is_true(args[ARG_value].u_obj); + } + + // save the mode + pin_mode[self->phys_port] = mode; + + // configure the GPIO as requested + if (self->phys_port == 16) { + // only pull-down seems to be supported by the hardware, and + // we only expose pull-up behaviour in software + if (pull != GPIO_PULL_NONE) { + mp_raise_ValueError("Pin(16) doesn't support pull"); + } + } else { + PIN_FUNC_SELECT(self->periph, self->func); + #if 0 + // Removed in SDK 1.1.0 + if ((pull & GPIO_PULL_DOWN) == 0) { + PIN_PULLDWN_DIS(self->periph); + } + #endif + if ((pull & GPIO_PULL_UP) == 0) { + PIN_PULLUP_DIS(self->periph); + } + #if 0 + if ((pull & GPIO_PULL_DOWN) != 0) { + PIN_PULLDWN_EN(self->periph); + } + #endif + if ((pull & GPIO_PULL_UP) != 0) { + PIN_PULLUP_EN(self->periph); + } + } + + pin_set(self->phys_port, value); + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + pyb_pin_obj_t *pin = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) { + pin = (pyb_pin_obj_t*)&pyb_pin_obj[wanted_pin]; + } + if (pin == NULL || pin->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + pyb_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port)); + } else { + // set pin + pin_set(self->phys_port, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t pyb_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_init_obj, 1, pyb_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t pyb_pin_value(size_t n_args, const mp_obj_t *args) { + return pyb_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pin_value_obj, 1, 2, pyb_pin_value); + +STATIC mp_obj_t pyb_pin_off(mp_obj_t self_in) { + pyb_pin_obj_t *self = self_in; + pin_set(self->phys_port, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_off_obj, pyb_pin_off); + +STATIC mp_obj_t pyb_pin_on(mp_obj_t self_in) { + pyb_pin_obj_t *self = self_in; + pin_set(self->phys_port, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_on_obj, pyb_pin_on); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False) +STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_hard }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, + }; + pyb_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (self->phys_port >= 16) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities")); + } + + if (n_args > 1 || kw_args->used != 0) { + // configure irq + mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t trigger = args[ARG_trigger].u_int; + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + ETS_GPIO_INTR_DISABLE(); + MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler; + pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool; + SET_TRIGGER(self->phys_port, trigger); + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port); + ETS_GPIO_INTR_ENABLE(); + } + + // return the irq object + return MP_OBJ_FROM_PTR(&pin_irq_obj[self->phys_port]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_irq_obj, 1, pyb_pin_irq); + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode); +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + pyb_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return pin_get(self->phys_port); + } + case MP_PIN_WRITE: { + pin_set(self->phys_port, arg); + return 0; + } + } + return -1; +} + +STATIC const mp_rom_map_elem_t pyb_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pyb_pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pyb_pin_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_pin_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUTPUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OPEN_DRAIN) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) }, + //{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) }, + + // IRQ triggers, can be or'd together + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_pin_locals_dict, pyb_pin_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t pyb_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pyb_pin_print, + .make_new = mp_pin_make_new, + .call = pyb_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_dict_t*)&pyb_pin_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +STATIC const mp_obj_type_t pin_irq_type; + +STATIC const pin_irq_obj_t pin_irq_obj[16] = { + {{&pin_irq_type}, 0}, + {{&pin_irq_type}, 1}, + {{&pin_irq_type}, 2}, + {{&pin_irq_type}, 3}, + {{&pin_irq_type}, 4}, + {{&pin_irq_type}, 5}, + {{&pin_irq_type}, 6}, + {{&pin_irq_type}, 7}, + {{&pin_irq_type}, 8}, + {{&pin_irq_type}, 9}, + {{&pin_irq_type}, 10}, + {{&pin_irq_type}, 11}, + {{&pin_irq_type}, 12}, + {{&pin_irq_type}, 13}, + {{&pin_irq_type}, 14}, + {{&pin_irq_type}, 15}, +}; + +STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + pin_irq_obj_t *self = self_in; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + pin_intr_handler(1 << self->phys_port); + return mp_const_none; +} + +STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) { + pin_irq_obj_t *self = args[0]; + uint32_t orig_trig = GET_TRIGGER(self->phys_port); + if (n_args == 2) { + // set trigger + SET_TRIGGER(self->phys_port, mp_obj_get_int(args[1])); + } + // return original trigger value + return MP_OBJ_NEW_SMALL_INT(orig_trig); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger); + +STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table); + +STATIC const mp_obj_type_t pin_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = pin_irq_call, + .locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/machine_pwm.c b/src/openmv/src/micropython/ports/esp8266/machine_pwm.c new file mode 100755 index 0000000..4c5cb87 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_pwm.c @@ -0,0 +1,171 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "esppwm.h" + +#include "py/runtime.h" +#include "modmachine.h" + +typedef struct _pyb_pwm_obj_t { + mp_obj_base_t base; + pyb_pin_obj_t *pin; + uint8_t active; + uint8_t channel; +} pyb_pwm_obj_t; + +STATIC bool pwm_inited = false; + +/******************************************************************************/ +// MicroPython bindings for PWM + +STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(%u", self->pin->phys_port); + if (self->active) { + mp_printf(print, ", freq=%u, duty=%u", + pwm_get_freq(self->channel), pwm_get_duty(self->channel)); + } + mp_printf(print, ")"); +} + +STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int channel = pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func); + if (channel == -1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM not supported on pin %d", self->pin->phys_port)); + } + + self->channel = channel; + self->active = 1; + if (args[ARG_freq].u_int != -1) { + pwm_set_freq(args[ARG_freq].u_int, self->channel); + } + if (args[ARG_duty].u_int != -1) { + pwm_set_duty(args[ARG_duty].u_int, self->channel); + } + + pwm_start(); +} + +STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]); + + // create PWM object from the given pin + pyb_pwm_obj_t *self = m_new_obj(pyb_pwm_obj_t); + self->base.type = &pyb_pwm_type; + self->pin = pin; + self->active = 0; + self->channel = -1; + + // start the PWM subsystem if it's not already running + if (!pwm_inited) { + pwm_init(); + pwm_inited = true; + } + + // start the PWM running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pwm_init_obj, 1, pyb_pwm_init); + +STATIC mp_obj_t pyb_pwm_deinit(mp_obj_t self_in) { + pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + pwm_delete(self->channel); + self->active = 0; + pwm_start(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pwm_deinit_obj, pyb_pwm_deinit); + +STATIC mp_obj_t pyb_pwm_freq(size_t n_args, const mp_obj_t *args) { + //pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0)); + } else { + // set + pwm_set_freq(mp_obj_get_int(args[1]), 0); + pwm_start(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_freq_obj, 1, 2, pyb_pwm_freq); + +STATIC mp_obj_t pyb_pwm_duty(size_t n_args, const mp_obj_t *args) { + pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (!self->active) { + pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func); + self->active = 1; + } + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel)); + } else { + // set + pwm_set_duty(mp_obj_get_int(args[1]), self->channel); + pwm_start(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_duty_obj, 1, 2, pyb_pwm_duty); + +STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_pwm_locals_dict, pyb_pwm_locals_dict_table); + +const mp_obj_type_t pyb_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = pyb_pwm_print, + .make_new = pyb_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_pwm_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/machine_rtc.c b/src/openmv/src/micropython/ports/esp8266/machine_rtc.c new file mode 100755 index 0000000..bbfc172 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_rtc.c @@ -0,0 +1,270 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "user_interface.h" +#include "modmachine.h" + +typedef struct _pyb_rtc_obj_t { + mp_obj_base_t base; +} pyb_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +#define MEM_DELTA_ADDR 64 +#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2) +#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1) +#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1) +#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1) +#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4) + +// singleton RTC object +STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; + +// ALARM0 state +uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants +uint64_t pyb_rtc_alarm0_expiry; // in microseconds + +// RTC overflow checking +STATIC uint32_t rtc_last_ticks; + +void mp_hal_rtc_init(void) { + uint32_t magic; + + system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); + if (magic != MEM_MAGIC) { + magic = MEM_MAGIC; + system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); + uint32_t cal = system_rtc_clock_cali_proc(); + int64_t delta = 0; + system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); + uint32_t len = 0; + system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); + } + // system_get_rtc_time() is always 0 after reset/deepsleep + rtc_last_ticks = system_get_rtc_time(); + + // reset ALARM0 state + pyb_rtc_alarm0_wake = 0; + pyb_rtc_alarm0_expiry = 0; +} + +STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&pyb_rtc_obj; +} + +void pyb_rtc_set_us_since_2000(uint64_t nowus) { + uint32_t cal = system_rtc_clock_cali_proc(); + // Save RTC ticks for overflow detection. + rtc_last_ticks = system_get_rtc_time(); + int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12); + + // As the calibration value jitters quite a bit, to make the + // clock at least somewhat practically usable, we need to store it + system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); +}; + +uint64_t pyb_rtc_get_us_since_2000() { + uint32_t cal; + int64_t delta; + uint32_t rtc_ticks; + + system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal)); + system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta)); + + // ESP-SDK system_get_rtc_time() only returns uint32 and therefore + // overflow about every 7:45h. Thus, we have to check for + // overflow and handle it. + rtc_ticks = system_get_rtc_time(); + if (rtc_ticks < rtc_last_ticks) { + // Adjust delta because of RTC overflow. + delta += (uint64_t)cal << 20; + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); + } + rtc_last_ticks = rtc_ticks; + + return (((uint64_t)rtc_ticks * cal) >> 12) + delta; +}; + +void rtc_prepare_deepsleep(uint64_t sleep_us) { + // RTC time will reset at wake up. Let's be preared for this. + int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us; + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); +} + +STATIC mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + uint64_t msecs = pyb_rtc_get_us_since_2000() / 1000; + + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(msecs / 1000, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(msecs % 1000) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + pyb_rtc_set_us_since_2000( + ((uint64_t)timeutils_seconds_since_2000( + mp_obj_get_int(items[0]), + mp_obj_get_int(items[1]), + mp_obj_get_int(items[2]), + mp_obj_get_int(items[4]), + mp_obj_get_int(items[5]), + mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000); + + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime); + +STATIC mp_obj_t pyb_rtc_memory(size_t n_args, const mp_obj_t *args) { + uint8_t rtcram[MEM_USER_MAXLEN]; + uint32_t len; + + if (n_args == 1) { + // read RTC memory + + system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len)); + system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3); + + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + + len = bufinfo.len; + system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); + + int i = 0; + for (; i < bufinfo.len; i++) { + rtcram[i] = ((uint8_t *)bufinfo.buf)[i]; + } + + system_rtc_mem_write(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3); + + return mp_const_none; + } + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory); + +STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) { + (void)self_in; // unused + + // check we want alarm0 + if (mp_obj_get_int(alarm_id) != 0) { + mp_raise_ValueError("invalid alarm"); + } + + // set expiry time (in microseconds) + pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000; + + return mp_const_none; + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm); + +STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) { + // check we want alarm0 + if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { + mp_raise_ValueError("invalid alarm"); + } + + uint64_t now = pyb_rtc_get_us_since_2000(); + if (pyb_rtc_alarm0_expiry <= now) { + return MP_OBJ_NEW_SMALL_INT(0); + } else { + return mp_obj_new_int((pyb_rtc_alarm0_expiry - now) / 1000); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left); + +STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_trigger, ARG_wake }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // check we want alarm0 + if (args[ARG_trigger].u_int != 0) { + mp_raise_ValueError("invalid alarm"); + } + + // set the wake value + pyb_rtc_alarm0_wake = args[ARG_wake].u_int; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq); + +STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&pyb_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&pyb_rtc_memory_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm), MP_ROM_PTR(&pyb_rtc_alarm_obj) }, + { MP_ROM_QSTR(MP_QSTR_alarm_left), MP_ROM_PTR(&pyb_rtc_alarm_left_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_rtc_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_ALARM0), MP_ROM_INT(0) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); + +const mp_obj_type_t pyb_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = pyb_rtc_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_rtc_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/machine_uart.c b/src/openmv/src/micropython/ports/esp8266/machine_uart.c new file mode 100755 index 0000000..e8be5e5 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_uart.c @@ -0,0 +1,299 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "ets_sys.h" +#include "uart.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; + +typedef struct _pyb_uart_obj_t { + mp_obj_base_t base; + uint8_t uart_id; + uint8_t bits; + uint8_t parity; + uint8_t stop; + uint32_t baudrate; + uint16_t timeout; // timeout waiting for first char (in ms) + uint16_t timeout_char; // timeout waiting between chars (in ms) +} pyb_uart_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, timeout=%u, timeout_char=%u)", + self->uart_id, self->baudrate, self->bits, _parity_name[self->parity], + self->stop, self->timeout, self->timeout_char); +} + +STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_timeout_char }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, + //{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + //{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set baudrate + if (args[ARG_baudrate].u_int > 0) { + self->baudrate = args[ARG_baudrate].u_int; + UartDev.baut_rate = self->baudrate; // Sic! + } + + // set data bits + switch (args[ARG_bits].u_int) { + case 0: + break; + case 5: + UartDev.data_bits = UART_FIVE_BITS; + self->bits = 5; + break; + case 6: + UartDev.data_bits = UART_SIX_BITS; + self->bits = 6; + break; + case 7: + UartDev.data_bits = UART_SEVEN_BITS; + self->bits = 7; + break; + case 8: + UartDev.data_bits = UART_EIGHT_BITS; + self->bits = 8; + break; + default: + mp_raise_ValueError("invalid data bits"); + break; + } + + // set parity + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + UartDev.parity = UART_NONE_BITS; + UartDev.exist_parity = UART_STICK_PARITY_DIS; + self->parity = 0; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + UartDev.exist_parity = UART_STICK_PARITY_EN; + if (parity & 1) { + UartDev.parity = UART_ODD_BITS; + self->parity = 1; + } else { + UartDev.parity = UART_EVEN_BITS; + self->parity = 2; + } + } + } + + // set stop bits + switch (args[ARG_stop].u_int) { + case 0: + break; + case 1: + UartDev.stop_bits = UART_ONE_STOP_BIT; + self->stop = 1; + break; + case 2: + UartDev.stop_bits = UART_TWO_STOP_BIT; + self->stop = 2; + break; + default: + mp_raise_ValueError("invalid stop bits"); + break; + } + + // set timeout + self->timeout = args[ARG_timeout].u_int; + + // set timeout_char + // make sure it is at least as long as a whole character (13 bits to be safe) + self->timeout_char = args[ARG_timeout_char].u_int; + uint32_t min_timeout_char = 13000 / self->baudrate + 1; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } + + // setup + uart_setup(self->uart_id); +} + +STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get uart id + mp_int_t uart_id = mp_obj_get_int(args[0]); + if (uart_id != 0 && uart_id != 1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id)); + } + + // create instance + pyb_uart_obj_t *self = m_new_obj(pyb_uart_obj_t); + self->base.type = &pyb_uart_type; + self->uart_id = uart_id; + self->baudrate = 115200; + self->bits = 8; + self->parity = 0; + self->stop = 1; + self->timeout = 0; + self->timeout_char = 0; + + // init the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); + +STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self->uart_id)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any); + +STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) }, + + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); + +STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->uart_id == 1) { + mp_raise_msg(&mp_type_OSError, "UART(1) can't read"); + } + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + // wait for first char to become available + if (!uart_rx_wait(self->timeout * 1000)) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // read the data + uint8_t *buf = buf_in; + for (;;) { + *buf++ = uart_rx_char(); + if (--size == 0 || !uart_rx_wait(self->timeout_char * 1000)) { + // return number of bytes read + return buf - (uint8_t*)buf_in; + } + } +} + +STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + const byte *buf = buf_in; + + /* TODO implement non-blocking + // wait to be able to write the first character + if (!uart_tx_wait(self, timeout)) { + *errcode = EAGAIN; + return MP_STREAM_ERROR; + } + */ + + // write the data + for (size_t i = 0; i < size; ++i) { + uart_tx_one_char(self->uart_id, *buf++); + } + + // return number of bytes written + return size; +} + +STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + pyb_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self->uart_id)) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && uart_tx_any_room(self->uart_id)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = pyb_uart_read, + .write = pyb_uart_write, + .ioctl = pyb_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t pyb_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = pyb_uart_print, + .make_new = pyb_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/machine_wdt.c b/src/openmv/src/micropython/ports/esp8266/machine_wdt.c new file mode 100755 index 0000000..fad0b2e --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/machine_wdt.c @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//#include +#include + +#include "py/runtime.h" +#include "user_interface.h" +#include "etshal.h" +#include "ets_alt_task.h" + +const mp_obj_type_t esp_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + ets_loop_dont_feed_sw_wdt = 1; + system_soft_wdt_feed(); + return &wdt_default; + default: + mp_raise_ValueError(NULL); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + system_soft_wdt_feed(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC mp_obj_t machine_wdt_deinit(mp_obj_t self_in) { + (void)self_in; + ets_wdt_disable(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_deinit_obj, machine_wdt_deinit); + +STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_wdt_deinit_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t esp_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_wdt_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/main.c b/src/openmv/src/micropython/ports/esp8266/main.c new file mode 100755 index 0000000..7bb2d8d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/main.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/gc.h" + +// This needs to be defined before any ESP SDK headers are included +#define USE_US_TIMER 1 + +#include "extmod/misc.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "gccollect.h" +#include "user_interface.h" + +STATIC char heap[38 * 1024]; + +STATIC void mp_reset(void) { + mp_stack_set_top((void*)0x40000000); + mp_stack_set_limit(8192); + mp_hal_init(); + gc_init(heap, heap + sizeof(heap)); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_)); + mp_obj_list_init(mp_sys_argv, 0); + #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA + extern void esp_native_code_init(void); + esp_native_code_init(); + #endif + pin_init0(); + readline_init0(); + dupterm_task_init(); +#if MICROPY_MODULE_FROZEN + pyexec_frozen_module("_boot.py"); + pyexec_file("boot.py"); + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + pyexec_file("main.py"); + } +#endif + + // Check if there are any dupterm objects registered and if not then + // activate UART(0), or else there will never be any chance to get a REPL + size_t idx; + for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) { + break; + } + } + if (idx == MICROPY_PY_OS_DUPTERM) { + mp_obj_t args[2]; + args[0] = MP_OBJ_NEW_SMALL_INT(0); + args[1] = MP_OBJ_NEW_SMALL_INT(115200); + args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args); + args[1] = MP_OBJ_NEW_SMALL_INT(1); + extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args); + os_dupterm(2, args); + mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n"); + } +} + +void soft_reset(void) { + gc_sweep_all(); + mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); + mp_hal_delay_us(10000); // allow UART to flush output + mp_reset(); + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + #endif +} + +void init_done(void) { + #if MICROPY_REPL_EVENT_DRIVEN + uart_task_init(); + #endif + mp_reset(); + mp_hal_stdout_tx_str("\r\n"); + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + #endif + + #if !MICROPY_REPL_EVENT_DRIVEN +soft_reset: + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + soft_reset(); + goto soft_reset; + #endif +} + +void user_init(void) { + system_timer_reinit(); + system_init_done_cb(init_done); +} + +#if !MICROPY_VFS +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + (void)path; + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +#endif + +void MP_FASTCODE(nlr_jump_fail)(void *val) { + printf("NLR jump failed\n"); + for (;;) { + } +} + +//void __assert(const char *file, int line, const char *func, const char *expr) { +void __assert(const char *file, int line, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + for (;;) { + } +} + +#if !MICROPY_DEBUG_PRINTERS +// With MICROPY_DEBUG_PRINTERS disabled DEBUG_printf is not defined but it +// is still needed by esp-open-lwip for debugging output, so define it here. +#include +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); +int DEBUG_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(MICROPY_DEBUG_PRINTER, fmt, ap); + va_end(ap); + return ret; +} +#endif diff --git a/src/openmv/src/micropython/ports/esp8266/makeimg.py b/src/openmv/src/micropython/ports/esp8266/makeimg.py new file mode 100755 index 0000000..091854f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/makeimg.py @@ -0,0 +1,40 @@ +import sys +import struct +import hashlib + +SEGS_MAX_SIZE = 0x9000 + +assert len(sys.argv) == 4 + +md5 = hashlib.md5() + +with open(sys.argv[3], 'wb') as fout: + + with open(sys.argv[1], 'rb') as f: + data_flash = f.read() + fout.write(data_flash) + # First 4 bytes include flash size, etc. which may be changed + # by esptool.py, etc. + md5.update(data_flash[4:]) + print('flash ', len(data_flash)) + + with open(sys.argv[2], 'rb') as f: + data_rom = f.read() + + pad = b'\xff' * (SEGS_MAX_SIZE - len(data_flash)) + assert len(pad) >= 4 + fout.write(pad[:-4]) + md5.update(pad[:-4]) + len_data = struct.pack("I", SEGS_MAX_SIZE + len(data_rom)) + fout.write(len_data) + md5.update(len_data) + print('padding ', len(pad)) + + fout.write(data_rom) + md5.update(data_rom) + print('irom0text', len(data_rom)) + + fout.write(md5.digest()) + + print('total ', SEGS_MAX_SIZE + len(data_rom)) + print('md5 ', md5.hexdigest()) diff --git a/src/openmv/src/micropython/ports/esp8266/modesp.c b/src/openmv/src/micropython/ports/esp8266/modesp.c new file mode 100755 index 0000000..46cd24c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modesp.c @@ -0,0 +1,388 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "drivers/dht/dht.h" +#include "uart.h" +#include "user_interface.h" +#include "mem.h" +#include "ets_alt_task.h" +#include "espneopixel.h" +#include "espapa102.h" +#include "modmachine.h" + +#define MODESP_INCLUDE_CONSTANTS (1) + +void error_check(bool status, const char *msg) { + if (!status) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + } +} + +STATIC mp_obj_t esp_osdebug(mp_obj_t val) { + if (val == mp_const_none) { + uart_os_config(-1); + } else { + uart_os_config(mp_obj_get_int(val)); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_osdebug_obj, esp_osdebug); + +STATIC mp_obj_t esp_sleep_type(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return mp_obj_new_int(wifi_get_sleep_type()); + } else { + wifi_set_sleep_type(mp_obj_get_int(args[0])); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_sleep_type_obj, 0, 1, esp_sleep_type); + +STATIC mp_obj_t esp_deepsleep(size_t n_args, const mp_obj_t *args) { + uint32_t sleep_us = n_args > 0 ? mp_obj_get_int(args[0]) : 0; + // prepare for RTC reset at wake up + rtc_prepare_deepsleep(sleep_us); + system_deep_sleep_set_option(n_args > 1 ? mp_obj_get_int(args[1]) : 0); + system_deep_sleep(sleep_us); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_deepsleep_obj, 0, 2, esp_deepsleep); + +STATIC mp_obj_t esp_flash_id() { + return mp_obj_new_int(spi_flash_get_id()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_id_obj, esp_flash_id); + +STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + + mp_int_t len; + byte *buf; + bool alloc_buf = MP_OBJ_IS_INT(len_or_buf_in); + + if (alloc_buf) { + len = mp_obj_get_int(len_or_buf_in); + buf = m_new(byte, len); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(len_or_buf_in, &bufinfo, MP_BUFFER_WRITE); + len = bufinfo.len; + buf = bufinfo.buf; + } + + // We know that allocation will be 4-byte aligned for sure + SpiFlashOpResult res = spi_flash_read(offset, (uint32_t*)buf, len); + if (res == SPI_FLASH_RESULT_OK) { + if (alloc_buf) { + return mp_obj_new_bytes(buf, len); + } + return mp_const_none; + } + if (alloc_buf) { + m_del(byte, buf, len); + } + mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read); + +STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len & 0x3) { + mp_raise_ValueError("len must be multiple of 4"); + } + ets_loop_iter(); // flash access takes time so run any pending tasks + SpiFlashOpResult res = spi_flash_write(offset, bufinfo.buf, bufinfo.len); + ets_loop_iter(); + if (res == SPI_FLASH_RESULT_OK) { + return mp_const_none; + } + mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write); + +STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { + mp_int_t sector = mp_obj_get_int(sector_in); + ets_loop_iter(); // flash access takes time so run any pending tasks + SpiFlashOpResult res = spi_flash_erase_sector(sector); + ets_loop_iter(); + if (res == SPI_FLASH_RESULT_OK) { + return mp_const_none; + } + mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); + +STATIC mp_obj_t esp_flash_size(void) { + extern char flashchip; + // For SDK 1.5.2, either address has shifted and not mirrored in + // eagle.rom.addr.v6.ld, or extra initial member was added. + SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4); + #if 0 + printf("deviceId: %x\n", flash->deviceId); + printf("chip_size: %u\n", flash->chip_size); + printf("block_size: %u\n", flash->block_size); + printf("sector_size: %u\n", flash->sector_size); + printf("page_size: %u\n", flash->page_size); + printf("status_mask: %u\n", flash->status_mask); + #endif + return mp_obj_new_int_from_uint(flash->chip_size); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); + +// If there's just 1 loadable segment at the start of flash, +// we assume there's a yaota8266 bootloader. +#define IS_OTA_FIRMWARE() ((*(uint32_t*)0x40200000 & 0xff00) == 0x100) + +extern byte _firmware_size[]; + +STATIC mp_obj_t esp_flash_user_start(void) { + return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); + +STATIC mp_obj_t esp_check_fw(void) { + MD5_CTX ctx; + char *fw_start = (char*)0x40200000; + if (IS_OTA_FIRMWARE()) { + // Skip yaota8266 bootloader + fw_start += 0x3c000; + } + + uint32_t size = *(uint32_t*)(fw_start + 0x8ffc); + printf("size: %d\n", size); + if (size > 1024 * 1024) { + printf("Invalid size\n"); + return mp_const_false; + } + MD5Init(&ctx); + MD5Update(&ctx, fw_start + 4, size - 4); + unsigned char digest[16]; + MD5Final(digest, &ctx); + printf("md5: "); + for (int i = 0; i < 16; i++) { + printf("%02x", digest[i]); + } + printf("\n"); + return mp_obj_new_bool(memcmp(digest, fw_start + size, sizeof(digest)) == 0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw); + + +STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_neopixel_write(mp_obj_get_pin_obj(pin)->phys_port, + (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_is_true(is800k)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); + +#if MICROPY_ESP8266_APA102 +STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_apa102_write(mp_obj_get_pin_obj(clockPin)->phys_port, + mp_obj_get_pin_obj(dataPin)->phys_port, + (uint8_t*)bufinfo.buf, bufinfo.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_apa102_write_obj, esp_apa102_write_); +#endif + +STATIC mp_obj_t esp_freemem() { + return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_freemem_obj, esp_freemem); + +STATIC mp_obj_t esp_meminfo() { + system_print_meminfo(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_meminfo_obj, esp_meminfo); + +STATIC mp_obj_t esp_malloc(mp_obj_t size_in) { + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)os_malloc(mp_obj_get_int(size_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_malloc_obj, esp_malloc); + +STATIC mp_obj_t esp_free(mp_obj_t addr_in) { + os_free((void*)mp_obj_get_int(addr_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_free_obj, esp_free); + +STATIC mp_obj_t esp_esf_free_bufs(mp_obj_t idx_in) { + return MP_OBJ_NEW_SMALL_INT(ets_esf_free_bufs(mp_obj_get_int(idx_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_esf_free_bufs_obj, esp_esf_free_bufs); + +#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA + +// We provide here a way of committing executable data to a region from +// which it can be executed by the CPU. There are 2 such writable regions: +// - iram1, which may have some space left at the end of it +// - memory-mapped flash rom +// +// By default the iram1 region (the space at the end of it) is used. The +// user can select iram1 or a section of flash by calling the +// esp.set_native_code_location() function; see below. If flash is selected +// then it is erased as needed. + +#define IRAM1_END (0x40108000) +#define FLASH_START (0x40200000) +#define FLASH_END (0x40300000) +#define FLASH_SEC_SIZE (4096) + +#define ESP_NATIVE_CODE_IRAM1 (0) +#define ESP_NATIVE_CODE_FLASH (1) + +extern uint32_t _lit4_end; +STATIC uint32_t esp_native_code_location; +STATIC uint32_t esp_native_code_start; +STATIC uint32_t esp_native_code_end; +STATIC uint32_t esp_native_code_cur; +STATIC uint32_t esp_native_code_erased; + +void esp_native_code_init(void) { + esp_native_code_location = ESP_NATIVE_CODE_IRAM1; + esp_native_code_start = (uint32_t)&_lit4_end; + esp_native_code_end = IRAM1_END; + esp_native_code_cur = esp_native_code_start; + esp_native_code_erased = 0; +} + +void *esp_native_code_commit(void *buf, size_t len) { + //printf("COMMIT(buf=%p, len=%u, start=%08x, cur=%08x, end=%08x, erased=%08x)\n", buf, len, esp_native_code_start, esp_native_code_cur, esp_native_code_end, esp_native_code_erased); + + len = (len + 3) & ~3; + if (esp_native_code_cur + len > esp_native_code_end) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, + "memory allocation failed, allocating %u bytes for native code", (uint)len)); + } + + void *dest; + if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) { + dest = (void*)esp_native_code_cur; + memcpy(dest, buf, len); + } else { + SpiFlashOpResult res; + while (esp_native_code_erased < esp_native_code_cur + len) { + ets_loop_iter(); // flash access takes time so run any pending tasks + res = spi_flash_erase_sector(esp_native_code_erased / FLASH_SEC_SIZE); + if (res != SPI_FLASH_RESULT_OK) { + break; + } + esp_native_code_erased += FLASH_SEC_SIZE; + } + ets_loop_iter(); + if (res == SPI_FLASH_RESULT_OK) { + res = spi_flash_write(esp_native_code_cur, buf, len); + ets_loop_iter(); + } + if (res != SPI_FLASH_RESULT_OK) { + mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO); + } + dest = (void*)(FLASH_START + esp_native_code_cur); + } + + esp_native_code_cur += len; + + return dest; +} + +STATIC mp_obj_t esp_set_native_code_location(mp_obj_t start_in, mp_obj_t len_in) { + if (start_in == mp_const_none && len_in == mp_const_none) { + // use end of iram1 region + esp_native_code_init(); + } else { + // use flash; input params are byte offsets from start of flash + esp_native_code_location = ESP_NATIVE_CODE_FLASH; + esp_native_code_start = mp_obj_get_int(start_in); + esp_native_code_end = esp_native_code_start + mp_obj_get_int(len_in); + esp_native_code_cur = esp_native_code_start; + esp_native_code_erased = esp_native_code_start; + // memory-mapped flash is limited in extents to 1MByte + if (esp_native_code_end > FLASH_END - FLASH_START) { + mp_raise_ValueError("flash location must be below 1MByte"); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_set_native_code_location_obj, esp_set_native_code_location); + +#endif + +STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) }, + + { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_type), MP_ROM_PTR(&esp_sleep_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&esp_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_id), MP_ROM_PTR(&esp_flash_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) }, + #if MICROPY_ESP8266_NEOPIXEL + { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) }, + #endif + #if MICROPY_ESP8266_APA102 + { MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_freemem), MP_ROM_PTR(&esp_freemem_obj) }, + { MP_ROM_QSTR(MP_QSTR_meminfo), MP_ROM_PTR(&esp_meminfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_check_fw), MP_ROM_PTR(&esp_check_fw_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_info_obj) }, // TODO delete/rename/move elsewhere + { MP_ROM_QSTR(MP_QSTR_malloc), MP_ROM_PTR(&esp_malloc_obj) }, + { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&esp_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_esf_free_bufs), MP_ROM_PTR(&esp_esf_free_bufs_obj) }, + #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA + { MP_ROM_QSTR(MP_QSTR_set_native_code_location), MP_ROM_PTR(&esp_set_native_code_location_obj) }, + #endif + +#if MODESP_INCLUDE_CONSTANTS + { MP_ROM_QSTR(MP_QSTR_SLEEP_NONE), MP_ROM_INT(NONE_SLEEP_T) }, + { MP_ROM_QSTR(MP_QSTR_SLEEP_LIGHT), MP_ROM_INT(LIGHT_SLEEP_T) }, + { MP_ROM_QSTR(MP_QSTR_SLEEP_MODEM), MP_ROM_INT(MODEM_SLEEP_T) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table); + +const mp_obj_module_t esp_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/modmachine.c b/src/openmv/src/micropython/ports/esp8266/modmachine.c new file mode 100755 index 0000000..1c1d902 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modmachine.c @@ -0,0 +1,330 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" + +// This needs to be set before we include the RTOS headers +#define USE_US_TIMER 1 + +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "modmachine.h" + +#include "xtirq.h" +#include "os_type.h" +#include "osapi.h" +#include "etshal.h" +#include "ets_alt_task.h" +#include "user_interface.h" + +#if MICROPY_PY_MACHINE + +//#define MACHINE_WAKE_IDLE (0x01) +//#define MACHINE_WAKE_SLEEP (0x02) +#define MACHINE_WAKE_DEEPSLEEP (0x04) + +extern const mp_obj_type_t esp_wdt_type; + +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // get + return mp_obj_new_int(system_get_cpu_freq() * 1000000); + } else { + // set + mp_int_t freq = mp_obj_get_int(args[0]) / 1000000; + if (freq != 80 && freq != 160) { + mp_raise_ValueError("frequency can only be either 80Mhz or 160MHz"); + } + system_update_cpu_freq(freq); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); + +STATIC mp_obj_t machine_reset(void) { + system_restart(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_reset_cause(void) { + return MP_OBJ_NEW_SMALL_INT(system_get_rst_info()->reason); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC mp_obj_t machine_unique_id(void) { + uint32_t id = system_get_chip_id(); + return mp_obj_new_bytes((byte*)&id, sizeof(id)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_idle(void) { + uint32_t t = mp_hal_ticks_cpu(); + asm("waiti 0"); + t = mp_hal_ticks_cpu() - t; + return MP_OBJ_NEW_SMALL_INT(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_sleep(void) { + printf("Warning: not yet implemented\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(void) { + // default to sleep forever + uint32_t sleep_us = 0; + + // see if RTC.ALARM0 should wake the device + if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) { + uint64_t t = pyb_rtc_get_us_since_2000(); + if (pyb_rtc_alarm0_expiry <= t) { + sleep_us = 1; // alarm already expired so wake immediately + } else { + uint64_t delta = pyb_rtc_alarm0_expiry - t; + if (delta <= 0xffffffff) { + // sleep for the desired time + sleep_us = delta; + } else { + // overflow, just set to maximum sleep time + sleep_us = 0xffffffff; + } + } + } + + // prepare for RTC reset at wake up + rtc_prepare_deepsleep(sleep_us); + // put the device in a deep-sleep state + system_deep_sleep_set_option(0); // default power down mode; TODO check this + system_deep_sleep(sleep_us); + + for (;;) { + // we must not return + ets_loop_iter(); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); + +typedef struct _esp_timer_obj_t { + mp_obj_base_t base; + os_timer_t timer; + mp_obj_t callback; +} esp_timer_obj_t; + +const mp_obj_type_t esp_timer_type; + +STATIC void esp_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp_timer_obj_t *self = self_in; + mp_printf(print, "Timer(%p)", &self->timer); +} + +STATIC mp_obj_t esp_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + esp_timer_obj_t *tim = m_new_obj(esp_timer_obj_t); + tim->base.type = &esp_timer_type; + return tim; +} + +STATIC void esp_timer_cb(void *arg) { + esp_timer_obj_t *self = arg; + mp_sched_schedule(self->callback, self); +} + +STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_mode, + ARG_callback, + ARG_period, + ARG_tick_hz, + ARG_freq, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, +#if MICROPY_PY_BUILTINS_FLOAT + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +#else + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, +#endif + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self->callback = args[ARG_callback].u_obj; + // Be sure to disarm timer before making any changes + os_timer_disarm(&self->timer); + os_timer_setfn(&self->timer, esp_timer_cb, self); + +#if MICROPY_PY_BUILTINS_FLOAT + if (args[ARG_freq].u_obj != mp_const_none) { + mp_float_t freq = mp_obj_get_float(args[ARG_freq].u_obj); + if (freq < 0.001) { + os_timer_arm(&self->timer, (mp_int_t)(1000 / freq), args[ARG_mode].u_int); + } else { + os_timer_arm_us(&self->timer, (mp_int_t)(1000000 / freq), args[ARG_mode].u_int); + } + } +#else + if (args[ARG_freq].u_int != 0xffffffff) { + os_timer_arm_us(&self->timer, 1000000 / args[ARG_freq].u_int, args[ARG_mode].u_int); + } +#endif + else { + mp_int_t period = args[ARG_period].u_int; + mp_int_t hz = args[ARG_tick_hz].u_int; + if (hz == 1000) { + os_timer_arm(&self->timer, period, args[ARG_mode].u_int); + } else if (hz == 1000000) { + os_timer_arm_us(&self->timer, period, args[ARG_mode].u_int); + } else { + // Use a long long to ensure that we don't either overflow or loose accuracy + uint64_t period_us = (((uint64_t)period) * 1000000) / hz; + if (period_us < 0x80000000ull) { + os_timer_arm_us(&self->timer, (mp_int_t)period_us, args[ARG_mode].u_int); + } else { + os_timer_arm(&self->timer, (mp_int_t)(period_us / 1000), args[ARG_mode].u_int); + } + } + } + + return mp_const_none; +} + +STATIC mp_obj_t esp_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return esp_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_timer_init_obj, 1, esp_timer_init); + +STATIC mp_obj_t esp_timer_deinit(mp_obj_t self_in) { + esp_timer_obj_t *self = self_in; + os_timer_disarm(&self->timer); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_timer_deinit_obj, esp_timer_deinit); + +STATIC const mp_rom_map_elem_t esp_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp_timer_init_obj) }, +// { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&esp_timer_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp_timer_locals_dict, esp_timer_locals_dict_table); + +const mp_obj_type_t esp_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = esp_timer_print, + .make_new = esp_timer_make_new, + .locals_dict = (mp_obj_dict_t*)&esp_timer_locals_dict, +}; + +// this bit is unused in the Xtensa PS register +#define ETS_LOOP_ITER_BIT (12) + +STATIC mp_obj_t machine_disable_irq(void) { + uint32_t state = disable_irq(); + state = (state & ~(1 << ETS_LOOP_ITER_BIT)) | (ets_loop_iter_disable << ETS_LOOP_ITER_BIT); + ets_loop_iter_disable = 1; + return mp_obj_new_int(state); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { + uint32_t state = mp_obj_get_int(state_in); + ets_loop_iter_disable = (state >> ETS_LOOP_ITER_BIT) & 1; + enable_irq(state & ~(1 << ETS_LOOP_ITER_BIT)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + #if MICROPY_PY_MACHINE_I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + #endif + #if MICROPY_PY_MACHINE_SPI + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) }, + #endif + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, + + // reset causes + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(REASON_SOFT_RESTART) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/ports/esp8266/modmachine.h b/src/openmv/src/micropython/ports/esp8266/modmachine.h new file mode 100755 index 0000000..eae351f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modmachine.h @@ -0,0 +1,41 @@ +#ifndef MICROPY_INCLUDED_ESP8266_MODMACHINE_H +#define MICROPY_INCLUDED_ESP8266_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t pyb_pin_type; +extern const mp_obj_type_t pyb_pwm_type; +extern const mp_obj_type_t pyb_adc_type; +extern const mp_obj_type_t pyb_rtc_type; +extern const mp_obj_type_t pyb_uart_type; +extern const mp_obj_type_t pyb_i2c_type; +extern const mp_obj_type_t machine_hspi_type; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj); + +typedef struct _pyb_pin_obj_t { + mp_obj_base_t base; + uint16_t phys_port; + uint16_t func; + uint32_t periph; +} pyb_pin_obj_t; + +const pyb_pin_obj_t pyb_pin_obj[16 + 1]; + +void pin_init0(void); +void pin_intr_handler_iram(void *arg); +void pin_intr_handler(uint32_t); + +uint mp_obj_get_pin(mp_obj_t pin_in); +pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in); +int pin_get(uint pin); +void pin_set(uint pin, int value); + +extern uint32_t pyb_rtc_alarm0_wake; +extern uint64_t pyb_rtc_alarm0_expiry; + +void pyb_rtc_set_us_since_2000(uint64_t nowus); +uint64_t pyb_rtc_get_us_since_2000(); +void rtc_prepare_deepsleep(uint64_t sleep_us); + +#endif // MICROPY_INCLUDED_ESP8266_MODMACHINE_H diff --git a/src/openmv/src/micropython/ports/esp8266/modnetwork.c b/src/openmv/src/micropython/ports/esp8266/modnetwork.c new file mode 100755 index 0000000..c7f3397 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modnetwork.c @@ -0,0 +1,534 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.h" +#include "queue.h" +#include "user_interface.h" +#include "espconn.h" +#include "spi_flash.h" +#include "ets_alt_task.h" +#include "lwip/dns.h" + +#define MODNETWORK_INCLUDE_CONSTANTS (1) + +typedef struct _wlan_if_obj_t { + mp_obj_base_t base; + int if_id; +} wlan_if_obj_t; + +void error_check(bool status, const char *msg); +const mp_obj_type_t wlan_if_type; + +STATIC const wlan_if_obj_t wlan_objs[] = { + {{&wlan_if_type}, STATION_IF}, + {{&wlan_if_type}, SOFTAP_IF}, +}; + +STATIC void require_if(mp_obj_t wlan_if, int if_no) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); + if (self->if_id != if_no) { + error_check(false, if_no == STATION_IF ? "STA required" : "AP required"); + } +} + +STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + int idx = 0; + if (n_args > 0) { + idx = mp_obj_get_int(args[0]); + if (idx < 0 || idx >= sizeof(wlan_objs)) { + mp_raise_ValueError(NULL); + } + } + return MP_OBJ_FROM_PTR(&wlan_objs[idx]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); + +STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t mode = wifi_get_opmode(); + if (n_args > 1) { + int mask = self->if_id == STATION_IF ? STATION_MODE : SOFTAP_MODE; + if (mp_obj_get_int(args[1]) != 0) { + mode |= mask; + } else { + mode &= ~mask; + } + error_check(wifi_set_opmode(mode), "Cannot update i/f status"); + return mp_const_none; + } + + // Get active status + if (self->if_id == STATION_IF) { + return mp_obj_new_bool(mode & STATION_MODE); + } else { + return mp_obj_new_bool(mode & SOFTAP_MODE); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active); + +STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ssid, ARG_password, ARG_bssid }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + require_if(pos_args[0], STATION_IF); + struct station_config config = {{0}}; + size_t len; + const char *p; + bool set_config = false; + + // set parameters based on given args + if (args[ARG_ssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len); + len = MIN(len, sizeof(config.ssid)); + memcpy(config.ssid, p, len); + set_config = true; + } + if (args[ARG_password].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); + len = MIN(len, sizeof(config.password)); + memcpy(config.password, p, len); + set_config = true; + } + if (args[ARG_bssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); + if (len != sizeof(config.bssid)) { + mp_raise_ValueError(NULL); + } + config.bssid_set = 1; + memcpy(config.bssid, p, sizeof(config.bssid)); + set_config = true; + } + + if (set_config) { + error_check(wifi_station_set_config(&config), "Cannot set STA config"); + } + error_check(wifi_station_connect(), "Cannot connect to AP"); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect); + +STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { + require_if(self_in, STATION_IF); + error_check(wifi_station_disconnect(), "Cannot disconnect from AP"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); + +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get link status + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); + } + return MP_OBJ_NEW_SMALL_INT(-1); + } else { + // Get specific status parameter + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi()); + } + } + mp_raise_ValueError("unknown status param"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); + +STATIC mp_obj_t *esp_scan_list = NULL; + +STATIC void esp_scan_cb(void *result, STATUS status) { + if (esp_scan_list == NULL) { + // called unexpectedly + return; + } + if (result && status == 0) { + // we need to catch any memory errors + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + #if 1 + // struct bss_info::ssid_len is not documented in SDK API Guide, + // but is present in SDK headers since 1.4.0 + t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len); + #else + t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid)); + #endif + t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel); + t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode); + t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden); + mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t)); + } + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + // indicate error + *esp_scan_list = MP_OBJ_NULL; + } + } else { + // indicate error + *esp_scan_list = MP_OBJ_NULL; + } + esp_scan_list = NULL; +} + +STATIC mp_obj_t esp_scan(mp_obj_t self_in) { + require_if(self_in, STATION_IF); + if ((wifi_get_opmode() & STATION_MODE) == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "STA must be active")); + } + mp_obj_t list = mp_obj_new_list(0, NULL); + esp_scan_list = &list; + wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb); + while (esp_scan_list != NULL) { + // our esp_scan_cb is called via ets_loop_iter so it's safe to set the + // esp_scan_list variable to NULL without disabling interrupts + if (MP_STATE_VM(mp_pending_exception) != NULL) { + esp_scan_list = NULL; + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + ets_loop_iter(); + } + if (list == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed")); + } + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); + +/// \method isconnected() +/// Return True if connected to an AP and an IP address has been assigned, +/// false otherwise. +STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->if_id == STATION_IF) { + if (wifi_station_get_connect_status() == STATION_GOT_IP) { + return mp_const_true; + } + } else { + if (wifi_softap_get_station_num() > 0) { + return mp_const_true; + } + } + return mp_const_false; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected); + +STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + struct ip_info info; + ip_addr_t dns_addr; + wifi_get_ip_info(self->if_id, &info); + if (n_args == 1) { + // get + dns_addr = dns_getserver(0); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns_addr, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set + mp_obj_t *items; + bool restart_dhcp_server = false; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG); + if (mp_obj_is_integer(items[1])) { + // allow numeric netmask, i.e.: + // 24 -> 255.255.255.0 + // 16 -> 255.255.0.0 + // etc... + uint32_t* m = (uint32_t*)&info.netmask; + *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1]))); + } else { + netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG); + } + netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], (void*)&dns_addr, NETUTILS_BIG); + // To set a static IP we have to disable DHCP first + if (self->if_id == STATION_IF) { + wifi_station_dhcpc_stop(); + } else { + restart_dhcp_server = wifi_softap_dhcps_status(); + wifi_softap_dhcps_stop(); + } + if (!wifi_set_ip_info(self->if_id, &info)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "wifi_set_ip_info() failed")); + } + dns_setserver(0, &dns_addr); + if (restart_dhcp_server) { + wifi_softap_dhcps_start(); + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); + +STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError("either pos or kw args are allowed"); + } + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + union { + struct station_config sta; + struct softap_config ap; + } cfg; + + if (self->if_id == STATION_IF) { + error_check(wifi_station_get_config(&cfg.sta), "can't get STA config"); + } else { + error_check(wifi_softap_get_config(&cfg.ap), "can't get AP config"); + } + + int req_if = -1; + + if (kwargs->used != 0) { + + for (mp_uint_t i = 0; i < kwargs->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)kwargs->table[i].key) { + case QS(MP_QSTR_mac): { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError("invalid buffer length"); + } + wifi_set_macaddr(self->if_id, bufinfo.buf); + break; + } + case QS(MP_QSTR_essid): { + req_if = SOFTAP_IF; + size_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.ssid)); + memcpy(cfg.ap.ssid, s, len); + cfg.ap.ssid_len = len; + break; + } + case QS(MP_QSTR_hidden): { + req_if = SOFTAP_IF; + cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_authmode): { + req_if = SOFTAP_IF; + cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_password): { + req_if = SOFTAP_IF; + size_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.password) - 1); + memcpy(cfg.ap.password, s, len); + cfg.ap.password[len] = 0; + break; + } + case QS(MP_QSTR_channel): { + req_if = SOFTAP_IF; + cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_dhcp_hostname): { + req_if = STATION_IF; + if (self->if_id == STATION_IF) { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + wifi_station_set_hostname((char*)s); + } + break; + } + default: + goto unknown; + } + #undef QS + } + } + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + if (self->if_id == STATION_IF) { + error_check(wifi_station_set_config(&cfg.sta), "can't set STA config"); + } else { + error_check(wifi_softap_set_config(&cfg.ap), "can't set AP config"); + } + + return mp_const_none; + } + + // Get config + + if (n_args != 2) { + mp_raise_TypeError("can query only one param"); + } + + mp_obj_t val; + + qstr key = mp_obj_str_get_qstr(args[1]); + switch (key) { + case MP_QSTR_mac: { + uint8_t mac[6]; + wifi_get_macaddr(self->if_id, mac); + return mp_obj_new_bytes(mac, sizeof(mac)); + } + case MP_QSTR_essid: + if (self->if_id == STATION_IF) { + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + } else { + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + } + break; + case MP_QSTR_hidden: + req_if = SOFTAP_IF; + val = mp_obj_new_bool(cfg.ap.ssid_hidden); + break; + case MP_QSTR_authmode: + req_if = SOFTAP_IF; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); + break; + case MP_QSTR_channel: + req_if = SOFTAP_IF; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); + break; + case MP_QSTR_dhcp_hostname: { + req_if = STATION_IF; + char* s = wifi_station_get_hostname(); + if (s == NULL) { + val = MP_OBJ_NEW_QSTR(MP_QSTR_); + } else { + val = mp_obj_new_str(s, strlen(s)); + } + break; + } + default: + goto unknown; + } + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + return val; + +unknown: + mp_raise_ValueError("unknown config param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); + +STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); + +const mp_obj_type_t wlan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_WLAN, + .locals_dict = (mp_obj_dict_t*)&wlan_if_locals_dict, +}; + +STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return mp_obj_new_int(wifi_get_phy_mode()); + } else { + wifi_set_phy_mode(mp_obj_get_int(args[0])); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); + +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, + { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, + +#if MODNETWORK_INCLUDE_CONSTANTS + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)}, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)}, + + { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)}, + { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)}, + { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)}, + { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)}, + { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)}, + { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)}, + + { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) }, + + { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t network_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/modpyb.c b/src/openmv/src/micropython/ports/esp8266/modpyb.c new file mode 100755 index 0000000..0a23f6f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modpyb.c @@ -0,0 +1,79 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "gccollect.h" +#include "modmachine.h" + +// The pyb module no longer exists since all functionality now appears +// elsewhere, in more standard places (eg time, machine modules). The +// only remaining function is pyb.info() which has been moved to the +// esp module, pending deletion/renaming/moving elsewhere. + +STATIC mp_obj_t pyb_info(size_t n_args, const mp_obj_t *args) { + // print info about memory + { + printf("_text_start=%p\n", &_text_start); + printf("_text_end=%p\n", &_text_end); + printf("_irom0_text_start=%p\n", &_irom0_text_start); + printf("_irom0_text_end=%p\n", &_irom0_text_end); + printf("_data_start=%p\n", &_data_start); + printf("_data_end=%p\n", &_data_end); + printf("_rodata_start=%p\n", &_rodata_start); + printf("_rodata_end=%p\n", &_rodata_end); + printf("_bss_start=%p\n", &_bss_start); + printf("_bss_end=%p\n", &_bss_end); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + } + + // qstr info + { + mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + } + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info); diff --git a/src/openmv/src/micropython/ports/esp8266/modules/_boot.py b/src/openmv/src/micropython/ports/esp8266/modules/_boot.py new file mode 100755 index 0000000..81eb20d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/_boot.py @@ -0,0 +1,13 @@ +import gc +gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4) +import uos +from flashbdev import bdev + +try: + if bdev: + uos.mount(bdev, '/') +except OSError: + import inisetup + inisetup.setup() + +gc.collect() diff --git a/src/openmv/src/micropython/ports/esp8266/modules/apa102.py b/src/openmv/src/micropython/ports/esp8266/modules/apa102.py new file mode 100755 index 0000000..41b7c04 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/apa102.py @@ -0,0 +1,17 @@ +# APA102 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch + +from esp import apa102_write +from neopixel import NeoPixel + + +class APA102(NeoPixel): + ORDER = (0, 1, 2, 3) + + def __init__(self, clock_pin, data_pin, n, bpp=4): + super().__init__(data_pin, n, bpp) + self.clock_pin = clock_pin + self.clock_pin.init(clock_pin.OUT) + + def write(self): + apa102_write(self.clock_pin, self.pin, self.buf) diff --git a/src/openmv/src/micropython/ports/esp8266/modules/dht.py b/src/openmv/src/micropython/ports/esp8266/modules/dht.py new file mode 100755 index 0000000..2aa2f5c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp8266/modules/ds18x20.py b/src/openmv/src/micropython/ports/esp8266/modules/ds18x20.py new file mode 100755 index 0000000..1ec92d1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/ds18x20.py @@ -0,0 +1 @@ +../../../drivers/onewire/ds18x20.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp8266/modules/flashbdev.py b/src/openmv/src/micropython/ports/esp8266/modules/flashbdev.py new file mode 100755 index 0000000..40ba655 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/flashbdev.py @@ -0,0 +1,35 @@ +import esp + +class FlashBdev: + + SEC_SIZE = 4096 + RESERVED_SECS = 1 + START_SEC = esp.flash_user_start() // SEC_SIZE + RESERVED_SECS + NUM_BLK = 0x6b - RESERVED_SECS + + def __init__(self, blocks=NUM_BLK): + self.blocks = blocks + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf) + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + #assert len(buf) <= self.SEC_SIZE, len(buf) + esp.flash_erase(n + self.START_SEC) + esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf) + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return self.blocks + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + +size = esp.flash_size() +if size < 1024*1024: + bdev = None +else: + # 20K at the flash end is reserved for SDK params storage + bdev = FlashBdev((size - 20480) // FlashBdev.SEC_SIZE - FlashBdev.START_SEC) diff --git a/src/openmv/src/micropython/ports/esp8266/modules/inisetup.py b/src/openmv/src/micropython/ports/esp8266/modules/inisetup.py new file mode 100755 index 0000000..9184c6c --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/inisetup.py @@ -0,0 +1,54 @@ +import uos +import network +from flashbdev import bdev + +def wifi(): + import ubinascii + ap_if = network.WLAN(network.AP_IF) + essid = b"MicroPython-%s" % ubinascii.hexlify(ap_if.config("mac")[-3:]) + ap_if.config(essid=essid, authmode=network.AUTH_WPA_WPA2_PSK, password=b"micropythoN") + +def check_bootsec(): + buf = bytearray(bdev.SEC_SIZE) + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xff: + empty = False + break + if empty: + return True + fs_corrupted() + +def fs_corrupted(): + import time + while 1: + print("""\ +The FAT filesystem starting at sector %d with size %d sectors appears to +be corrupted. If you had important data there, you may want to make a flash +snapshot to try to recover it. Otherwise, perform factory reprogramming +of MicroPython firmware (completely erase flash, followed by firmware +programming). +""" % (bdev.START_SEC, bdev.blocks)) + time.sleep(3) + +def setup(): + check_bootsec() + print("Performing initial setup") + wifi() + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/') + with open("boot.py", "w") as f: + f.write("""\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +import uos, machine +uos.dupterm(machine.UART(0, 115200), 1) +import gc +#import webrepl +#webrepl.start() +gc.collect() +""") + return vfs diff --git a/src/openmv/src/micropython/ports/esp8266/modules/neopixel.py b/src/openmv/src/micropython/ports/esp8266/modules/neopixel.py new file mode 100755 index 0000000..b13424d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/neopixel.py @@ -0,0 +1,32 @@ +# NeoPixel driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +from esp import neopixel_write + + +class NeoPixel: + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + + def __setitem__(self, index, val): + offset = index * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = val[i] + + def __getitem__(self, index): + offset = index * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] + for i in range(self.bpp)) + + def fill(self, color): + for i in range(self.n): + self[i] = color + + def write(self): + neopixel_write(self.pin, self.buf, True) diff --git a/src/openmv/src/micropython/ports/esp8266/modules/ntptime.py b/src/openmv/src/micropython/ports/esp8266/modules/ntptime.py new file mode 100755 index 0000000..85c754a --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/ntptime.py @@ -0,0 +1,35 @@ +try: + import usocket as socket +except: + import socket +try: + import ustruct as struct +except: + import struct + +# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 +NTP_DELTA = 3155673600 + +host = "pool.ntp.org" + +def time(): + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1b + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(1) + res = s.sendto(NTP_QUERY, addr) + msg = s.recv(48) + s.close() + val = struct.unpack("!I", msg[40:44])[0] + return val - NTP_DELTA + +# There's currently no timezone support in MicroPython, so +# utime.localtime() will return UTC time (as if it was .gmtime()) +def settime(): + t = time() + import machine + import utime + tm = utime.localtime(t) + tm = tm[0:3] + (0,) + tm[3:6] + (0,) + machine.RTC().datetime(tm) diff --git a/src/openmv/src/micropython/ports/esp8266/modules/onewire.py b/src/openmv/src/micropython/ports/esp8266/modules/onewire.py new file mode 100755 index 0000000..33f30e8 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/onewire.py @@ -0,0 +1 @@ +../../../drivers/onewire/onewire.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp8266/modules/port_diag.py b/src/openmv/src/micropython/ports/esp8266/modules/port_diag.py new file mode 100755 index 0000000..ef88003 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/port_diag.py @@ -0,0 +1,33 @@ +import esp +import uctypes +import network +import lwip + + +def main(): + + ROM = uctypes.bytearray_at(0x40200000, 16) + fid = esp.flash_id() + + print("FlashROM:") + print("Flash ID: %x (Vendor: %x Device: %x)" % (fid, fid & 0xff, fid & 0xff00 | fid >> 16)) + + print("Flash bootloader data:") + SZ_MAP = {0: "512KB", 1: "256KB", 2: "1MB", 3: "2MB", 4: "4MB"} + FREQ_MAP = {0: "40MHZ", 1: "26MHZ", 2: "20MHz", 0xf: "80MHz"} + print("Byte @2: %02x" % ROM[2]) + print("Byte @3: %02x (Flash size: %s Flash freq: %s)" % (ROM[3], SZ_MAP.get(ROM[3] >> 4, "?"), FREQ_MAP.get(ROM[3] & 0xf))) + print("Firmware checksum:") + print(esp.check_fw()) + + print("\nNetworking:") + print("STA ifconfig:", network.WLAN(network.STA_IF).ifconfig()) + print("AP ifconfig:", network.WLAN(network.AP_IF).ifconfig()) + print("Free WiFi driver buffers of type:") + for i, comm in enumerate(("1,2 TX", "4 Mngmt TX(len: 0x41-0x100)", "5 Mngmt TX (len: 0-0x40)", "7", "8 RX")): + print("%d: %d (%s)" % (i, esp.esf_free_bufs(i), comm)) + print("lwIP PCBs:") + lwip.print_pcbs() + + +main() diff --git a/src/openmv/src/micropython/ports/esp8266/modules/upip.py b/src/openmv/src/micropython/ports/esp8266/modules/upip.py new file mode 100755 index 0000000..130eb69 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/upip.py @@ -0,0 +1 @@ +../../../tools/upip.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp8266/modules/upip_utarfile.py b/src/openmv/src/micropython/ports/esp8266/modules/upip_utarfile.py new file mode 100755 index 0000000..d9653d6 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/upip_utarfile.py @@ -0,0 +1 @@ +../../../tools/upip_utarfile.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/esp8266/modules/webrepl.py b/src/openmv/src/micropython/ports/esp8266/modules/webrepl.py new file mode 100755 index 0000000..aa156d1 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/webrepl.py @@ -0,0 +1,79 @@ +# This module should be imported from REPL, not run from command line. +import socket +import uos +import network +import websocket +import websocket_helper +import _webrepl + +listen_s = None +client_s = None + +def setup_conn(port, accept_handler): + global listen_s + listen_s = socket.socket() + listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ai = socket.getaddrinfo("0.0.0.0", port) + addr = ai[0][4] + + listen_s.bind(addr) + listen_s.listen(1) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + for i in (network.AP_IF, network.STA_IF): + iface = network.WLAN(i) + if iface.active(): + print("WebREPL daemon started on ws://%s:%d" % (iface.ifconfig()[0], port)) + return listen_s + + +def accept_conn(listen_sock): + global client_s + cl, remote_addr = listen_sock.accept() + prev = uos.dupterm(None) + uos.dupterm(prev) + if prev: + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return + print("\nWebREPL connection from:", remote_addr) + client_s = cl + websocket_helper.server_handshake(cl) + ws = websocket.websocket(cl, True) + ws = _webrepl._webrepl(ws) + cl.setblocking(False) + # notify REPL on socket incoming data + cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify) + uos.dupterm(ws) + + +def stop(): + global listen_s, client_s + uos.dupterm(None) + if client_s: + client_s.close() + if listen_s: + listen_s.close() + + +def start(port=8266, password=None): + stop() + if password is None: + try: + import webrepl_cfg + _webrepl.password(webrepl_cfg.PASS) + setup_conn(port, accept_conn) + print("Started webrepl in normal mode") + except: + print("WebREPL is not configured, run 'import webrepl_setup'") + else: + _webrepl.password(password) + setup_conn(port, accept_conn) + print("Started webrepl in manual override mode") + + +def start_foreground(port=8266): + stop() + s = setup_conn(port, None) + accept_conn(s) diff --git a/src/openmv/src/micropython/ports/esp8266/modules/webrepl_setup.py b/src/openmv/src/micropython/ports/esp8266/modules/webrepl_setup.py new file mode 100755 index 0000000..129313a --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/webrepl_setup.py @@ -0,0 +1,102 @@ +import sys +#import uos as os +import os +import machine + +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" + +def input_choice(prompt, choices): + while 1: + resp = input(prompt) + if resp in choices: + return resp + +def getpass(prompt): + return input(prompt) + +def input_pass(): + while 1: + passwd1 = getpass("New password (4-9 chars): ") + if len(passwd1) < 4 or len(passwd1) > 9: + print("Invalid password length") + continue + passwd2 = getpass("Confirm password: ") + if passwd1 == passwd2: + return passwd1 + print("Passwords do not match") + + +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False + for l in old_f: + for patt in LINES: + if patt in l: + found = True + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + +main() diff --git a/src/openmv/src/micropython/ports/esp8266/modules/websocket_helper.py b/src/openmv/src/micropython/ports/esp8266/modules/websocket_helper.py new file mode 100755 index 0000000..9c06db5 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modules/websocket_helper.py @@ -0,0 +1,74 @@ +import sys +try: + import ubinascii as binascii +except: + import binascii +try: + import uhashlib as hashlib +except: + import hashlib + +DEBUG = 0 + +def server_handshake(sock): + clr = sock.makefile("rwb", 0) + l = clr.readline() + #sys.stdout.write(repr(l)) + + webkey = None + + while 1: + l = clr.readline() + if not l: + raise OSError("EOF in headers") + if l == b"\r\n": + break + # sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b'Sec-WebSocket-Key': + webkey = v + + if not webkey: + raise OSError("Not a websocket request") + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + d = hashlib.sha1(webkey) + d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + respkey = d.digest() + respkey = binascii.b2a_base64(respkey)[:-1] + if DEBUG: + print("respkey:", respkey) + + sock.send(b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: """) + sock.send(respkey) + sock.send("\r\n\r\n") + + +# Very simplified client handshake, works for MicroPython's +# websocket server implementation, but probably not for other +# servers. +def client_handshake(sock): + cl = sock.makefile("rwb", 0) + cl.write(b"""\ +GET / HTTP/1.1\r +Host: echo.websocket.org\r +Connection: Upgrade\r +Upgrade: websocket\r +Sec-WebSocket-Key: foo\r +\r +""") + l = cl.readline() +# print(l) + while 1: + l = cl.readline() + if l == b"\r\n": + break +# sys.stdout.write(l) diff --git a/src/openmv/src/micropython/ports/esp8266/moduos.c b/src/openmv/src/micropython/ports/esp8266/moduos.c new file mode 100755 index 0000000..7a32c11 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/moduos.c @@ -0,0 +1,129 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objtuple.h" +#include "py/objstr.h" +#include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" +#include "esp_mphal.h" +#include "user_interface.h" + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + +STATIC mp_obj_tuple_t os_uname_info_obj = { + .base = {&mp_type_attrtuple}, + .len = 5, + .items = { + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + NULL, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj, + (void *)os_uname_info_fields, + } +}; + +STATIC mp_obj_t os_uname(void) { + // We must populate the "release" field each time in case it was GC'd since the last call. + const char *ver = system_get_sdk_version(); + os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver)); + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = *WDEV_HWRNG; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +// We wrap the mp_uos_dupterm function to detect if a UART is attached or not +mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + ++uart_attached_to_dupterm; + } + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + --uart_attached_to_dupterm; + } + return prev_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm); + +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + mp_hal_signal_dupterm_input(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, + #endif + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t uos_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/modutime.c b/src/openmv/src/micropython/ports/esp8266/modutime.c new file mode 100755 index 0000000..ab9cb7d --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/modutime.c @@ -0,0 +1,129 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Josef Gajdusek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/smallint.h" +#include "lib/timeutils/timeutils.h" +#include "modmachine.h" +#include "user_interface.h" +#include "extmod/utime_mphal.h" + +/// \module time - time related functions +/// +/// The `time` module provides functions for getting the current time and date, +/// and for sleeping. + +/// \function localtime([secs]) +/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which +/// contains: (year, month, mday, hour, minute, second, weekday, yearday) +/// If secs is not provided or None, then the current time from the RTC is used. +/// year includes the century (for example 2014) +/// month is 1-12 +/// mday is 1-31 +/// hour is 0-23 +/// minute is 0-59 +/// second is 0-59 +/// weekday is 0-6 for Mon-Sun. +/// yearday is 1-366 +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000; + } else { + seconds = mp_obj_get_int(args[0]); + } + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +/// \function mktime() +/// This is inverse function of localtime. It's argument is a full 8-tuple +/// which expresses a time as per localtime. It returns an integer which is +/// the number of seconds since Jan 1, 2000. +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +/// \function time() +/// Returns the number of seconds, as an integer, since 1/1/2000. +STATIC mp_obj_t time_time(void) { + // get date and time + return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t utime_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/esp8266/mpconfigport.h b/src/openmv/src/micropython/ports/esp8266/mpconfigport.h new file mode 100755 index 0000000..890c406 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/mpconfigport.h @@ -0,0 +1,216 @@ +#include + +// options to control how MicroPython is built + +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) +#define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_ALLOC_LEXER_INDENT_INIT (8) +#define MICROPY_ALLOC_PARSE_RULE_INIT (48) +#define MICROPY_ALLOC_PARSE_RULE_INC (8) +#define MICROPY_ALLOC_PARSE_RESULT_INC (8) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTER (&mp_debug_print) +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_REPL_EVENT_DRIVEN (0) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS) +#define MICROPY_PY_UCRYPTOLIB (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_LWIP (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hspi_make_new +#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_WEBREPL_DELAY (20) +#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_OS_DUPTERM (2) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#define MICROPY_WARNINGS (1) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_MODULE_FROZEN_STR (1) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32 +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool + +#define MICROPY_VFS (1) +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_VFS_FAT (1) +#define MICROPY_ESP8266_APA102 (1) +#define MICROPY_ESP8266_NEOPIXEL (1) + +#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();} +#define MICROPY_VM_HOOK_COUNT (10) +#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT; +#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \ + vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \ + extern void ets_loop_iter(void); \ + ets_loop_iter(); \ + } +#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL +#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) + +#define MP_SSIZE_MAX (0x7fffffff) + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; +typedef uint32_t sys_prot_t; // for modlwip +// ssize_t, off_t as required by POSIX-signatured functions in stream.h +#include + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +void *esp_native_code_commit(void*, size_t); +#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) + +// printer for debugging output, goes to UART only +extern const struct _mp_print_t mp_debug_print; + +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t network_module; +extern const struct _mp_obj_module_t utime_module; +extern const struct _mp_obj_module_t uos_module; +extern const struct _mp_obj_module_t mp_module_lwip; +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_onewire; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_esp), MP_ROM_PTR(&esp_module) }, \ + { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, \ + { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&network_module) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&utime_module) }, \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&uos_module) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ + { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ + { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) }, \ + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ + { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib) }, \ + { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io) }, \ + { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&uos_module) }, \ + { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom) }, \ + { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \ + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, \ + { MP_ROM_QSTR(MP_QSTR_ssl), MP_ROM_PTR(&mp_module_ussl) }, \ + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&utime_module) }, \ + { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t pin_irq_handler[16]; \ + +// We need to provide a declaration/definition of alloca() +#include + +// board specifics + +#define MICROPY_MPHALPORT_H "esp_mphal.h" +#define MICROPY_HW_BOARD_NAME "ESP module" +#define MICROPY_HW_MCU_NAME "ESP8266" +#define MICROPY_PY_SYS_PLATFORM "esp8266" + +#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n + +#define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr)) diff --git a/src/openmv/src/micropython/ports/esp8266/mpconfigport_512k.h b/src/openmv/src/micropython/ports/esp8266/mpconfigport_512k.h new file mode 100755 index 0000000..df670d4 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/mpconfigport_512k.h @@ -0,0 +1,43 @@ +#include + +#undef MICROPY_EMIT_XTENSA +#define MICROPY_EMIT_XTENSA (0) +#undef MICROPY_EMIT_INLINE_XTENSA +#define MICROPY_EMIT_INLINE_XTENSA (0) + +#undef MICROPY_DEBUG_PRINTERS +#define MICROPY_DEBUG_PRINTERS (0) + +#undef MICROPY_ERROR_REPORTING +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) + +#undef MICROPY_VFS +#define MICROPY_VFS (0) +#undef MICROPY_VFS_FAT +#define MICROPY_VFS_FAT (0) + +#undef MICROPY_PERSISTENT_CODE_LOAD +#define MICROPY_PERSISTENT_CODE_LOAD (0) + +#undef MICROPY_PY_IO_FILEIO +#define MICROPY_PY_IO_FILEIO (0) + +#undef MICROPY_PY_SYS_STDIO_BUFFER +#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#undef MICROPY_PY_BUILTINS_SLICE_ATTRS +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#undef MICROPY_PY_ALL_SPECIAL_METHODS +#define MICROPY_PY_ALL_SPECIAL_METHODS (0) + +#undef MICROPY_PY_FRAMEBUF +#define MICROPY_PY_FRAMEBUF (0) + +#undef MICROPY_PY_URE_SUB +#define MICROPY_PY_URE_SUB (0) + +#undef MICROPY_PY_UCRYPTOLIB +#define MICROPY_PY_UCRYPTOLIB (0) + +#undef mp_import_stat +#undef mp_builtin_open +#undef mp_builtin_open_obj diff --git a/src/openmv/src/micropython/ports/esp8266/posix_helpers.c b/src/openmv/src/micropython/ports/esp8266/posix_helpers.c new file mode 100755 index 0000000..b72c4ff --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/posix_helpers.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include "py/mphal.h" +#include "py/gc.h" + +// Functions for external libs like axTLS, BerkeleyDB, etc. + +void *malloc(size_t size) { + void *p = gc_alloc(size, false); + if (p == NULL) { + // POSIX requires ENOMEM to be set in case of error + errno = ENOMEM; + } + return p; +} +void free(void *ptr) { + gc_free(ptr); +} +void *calloc(size_t nmemb, size_t size) { + return malloc(nmemb * size); +} +void *realloc(void *ptr, size_t size) { + void *p = gc_realloc(ptr, size, true); + if (p == NULL) { + // POSIX requires ENOMEM to be set in case of error + errno = ENOMEM; + } + return p; +} + +#undef htonl +#undef ntohl +uint32_t ntohl(uint32_t netlong) { + return MP_BE32TOH(netlong); +} +uint32_t htonl(uint32_t netlong) { + return MP_HTOBE32(netlong); +} + +time_t time(time_t *t) { + return mp_hal_ticks_ms() / 1000; +} + +time_t mktime(void *tm) { + return 0; +} diff --git a/src/openmv/src/micropython/ports/esp8266/qstrdefsport.h b/src/openmv/src/micropython/ports/esp8266/qstrdefsport.h new file mode 100755 index 0000000..8f301a6 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/qstrdefsport.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port, only needed if they aren't auto-generated + +// Entries for sys.path +Q(/) +Q(/lib) diff --git a/src/openmv/src/micropython/ports/esp8266/strtoll.c b/src/openmv/src/micropython/ports/esp8266/strtoll.c new file mode 100755 index 0000000..4e8a4d0 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/strtoll.c @@ -0,0 +1,29 @@ +#include + +// assumes endptr != NULL +// doesn't check for sign +// doesn't check for base-prefix +long long int strtoll(const char *nptr, char **endptr, int base) { + long long val = 0; + + for (; *nptr; nptr++) { + int v = *nptr; + if ('0' <= v && v <= '9') { + v -= '0'; + } else if ('A' <= v && v <= 'Z') { + v -= 'A' - 10; + } else if ('a' <= v && v <= 'z') { + v -= 'a' - 10; + } else { + break; + } + if (v >= base) { + break; + } + val = val * base + v; + } + + *endptr = (char*)nptr; + + return val; +} diff --git a/src/openmv/src/micropython/ports/esp8266/uart.c b/src/openmv/src/micropython/ports/esp8266/uart.c new file mode 100755 index 0000000..52707f9 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/uart.c @@ -0,0 +1,309 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: uart.c + * + * Description: Two UART mode configration and interrupt handler. + * Check your hardware connection while use this mode. + * + * Modification history: + * 2014/3/12, v1.0 create this file. +*******************************************************************************/ +#include "ets_sys.h" +#include "osapi.h" +#include "uart.h" +#include "osapi.h" +#include "uart_register.h" +#include "etshal.h" +#include "c_types.h" +#include "user_interface.h" +#include "esp_mphal.h" + +// seems that this is missing in the Espressif SDK +#define FUNC_U0RXD 0 + +#define UART_REPL UART0 + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; + +// the uart to which OS messages go; -1 to disable +static int uart_os = UART_OS; + +#if MICROPY_REPL_EVENT_DRIVEN +static os_event_t uart_evt_queue[16]; +#endif + +// A small, static ring buffer for incoming chars +// This will only be populated if the UART is not attached to dupterm +static byte uart_ringbuf_array[16]; +static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; + +static void uart0_rx_intr_handler(void *para); + +void soft_reset(void); +void mp_keyboard_interrupt(void); + +/****************************************************************************** + * FunctionName : uart_config + * Description : Internal used function + * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled + * UART1 just used for debug output + * Parameters : uart_no, use UART0 or UART1 defined ahead + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) { + if (uart_no == UART1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + } + + uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); + + WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity + | UartDev.parity + | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) + | (UartDev.data_bits << UART_BIT_NUM_S)); + + // clear rx and tx fifo,not ready + SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + + if (uart_no == UART0) { + // set rx fifo trigger + WRITE_PERI_REG(UART_CONF1(uart_no), + ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | + ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | + UART_RX_FLOW_EN | + (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | + UART_RX_TOUT_EN); + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA | + UART_FRM_ERR_INT_ENA); + } else { + WRITE_PERI_REG(UART_CONF1(uart_no), + ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); + } + + // clear all interrupt + WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); + // enable rx_interrupt + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); +} + +/****************************************************************************** + * FunctionName : uart1_tx_one_char + * Description : Internal used function + * Use uart1 interface to transfer one char + * Parameters : uint8 TxChar - character to tx + * Returns : OK +*******************************************************************************/ +void uart_tx_one_char(uint8 uart, uint8 TxChar) { + while (true) { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { + break; + } + } + WRITE_PERI_REG(UART_FIFO(uart), TxChar); +} + +void uart_flush(uint8 uart) { + while (true) { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) { + break; + } + } +} + +/****************************************************************************** + * FunctionName : uart1_write_char + * Description : Internal used function + * Do some special deal while tx char is '\r' or '\n' + * Parameters : char c - character to tx + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +uart_os_write_char(char c) { + if (uart_os == -1) { + return; + } + if (c == '\n') { + uart_tx_one_char(uart_os, '\r'); + uart_tx_one_char(uart_os, '\n'); + } else if (c == '\r') { + } else { + uart_tx_one_char(uart_os, c); + } +} + +void ICACHE_FLASH_ATTR +uart_os_config(int uart) { + uart_os = uart; +} + +/****************************************************************************** + * FunctionName : uart0_rx_intr_handler + * Description : Internal used function + * UART0 interrupt handler, add self handle code inside + * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg + * Returns : NONE +*******************************************************************************/ + +static void uart0_rx_intr_handler(void *para) { + /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents + * uart1 and uart0 respectively + */ + + uint8 uart_no = UART_REPL; + + if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) { + // frame error + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); + } + + if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) { + // fifo full + goto read_chars; + } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { + read_chars: + ETS_UART_INTR_DISABLE(); + + while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { + uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; + // For efficiency, when connected to dupterm we put incoming chars + // directly on stdin_ringbuf, rather than going via uart_ringbuf + if (uart_attached_to_dupterm) { + if (RcvChar == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, RcvChar); + } + } else { + ringbuf_put(&uart_ringbuf, RcvChar); + } + } + + // Clear pending FIFO interrupts + WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); + ETS_UART_INTR_ENABLE(); + + if (uart_attached_to_dupterm) { + mp_hal_signal_input(); + } + } +} + +// Waits at most timeout microseconds for at least 1 char to become ready for reading. +// Returns true if something available, false if not. +bool uart_rx_wait(uint32_t timeout_us) { + uint32_t start = system_get_time(); + for (;;) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { + return true; // have at least 1 char ready for reading + } + if (system_get_time() - start >= timeout_us) { + return false; // timeout + } + ets_event_poll(); + } +} + +int uart_rx_any(uint8 uart) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { + return true; // have at least 1 char ready for reading + } + return false; +} + +int uart_tx_any_room(uint8 uart) { + uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); + if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) >= 126) { + return false; + } + return true; +} + +// Returns char from the input buffer, else -1 if buffer is empty. +int uart_rx_char(void) { + return ringbuf_get(&uart_ringbuf); +} + +int uart_rx_one_char(uint8 uart_no) { + if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { + return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; + } + return -1; +} + +/****************************************************************************** + * FunctionName : uart_init + * Description : user interface for init uart + * Parameters : UartBautRate uart0_br - uart0 bautrate + * UartBautRate uart1_br - uart1 bautrate + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) { + // rom use 74880 baut_rate, here reinitialize + UartDev.baut_rate = uart0_br; + uart_config(UART0); + UartDev.baut_rate = uart1_br; + uart_config(UART1); + ETS_UART_INTR_ENABLE(); + + // install handler for "os" messages + os_install_putc1((void *)uart_os_write_char); +} + +void ICACHE_FLASH_ATTR uart_reattach() { + uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880); +} + +void ICACHE_FLASH_ATTR uart_setup(uint8 uart) { + ETS_UART_INTR_DISABLE(); + uart_config(uart); + ETS_UART_INTR_ENABLE(); +} + +// Task-based UART interface + +#include "py/obj.h" +#include "lib/utils/pyexec.h" + +#if MICROPY_REPL_EVENT_DRIVEN +void uart_task_handler(os_event_t *evt) { + if (pyexec_repl_active) { + // TODO: Just returning here isn't exactly right. + // What really should be done is something like + // enquing delayed event to itself, for another + // chance to feed data to REPL. Otherwise, there + // can be situation when buffer has bunch of data, + // and sits unprocessed, because we consumed all + // processing signals like this. + return; + } + + int c, ret = 0; + while ((c = ringbuf_get(&input_buf)) >= 0) { + if (c == mp_interrupt_char) { + mp_keyboard_interrupt(); + } + ret = pyexec_event_repl_process_char(c); + if (ret & PYEXEC_FORCED_EXIT) { + break; + } + } + + if (ret & PYEXEC_FORCED_EXIT) { + soft_reset(); + } +} + +void uart_task_init() { + system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue)); +} +#endif diff --git a/src/openmv/src/micropython/ports/esp8266/uart.h b/src/openmv/src/micropython/ports/esp8266/uart.h new file mode 100755 index 0000000..684689a --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/uart.h @@ -0,0 +1,106 @@ +#ifndef MICROPY_INCLUDED_ESP8266_UART_H +#define MICROPY_INCLUDED_ESP8266_UART_H + +#include + +#define UART0 (0) +#define UART1 (1) + +typedef enum { + UART_FIVE_BITS = 0x0, + UART_SIX_BITS = 0x1, + UART_SEVEN_BITS = 0x2, + UART_EIGHT_BITS = 0x3 +} UartBitsNum4Char; + +typedef enum { + UART_ONE_STOP_BIT = 0x1, + UART_ONE_HALF_STOP_BIT = 0x2, + UART_TWO_STOP_BIT = 0x3 +} UartStopBitsNum; + +typedef enum { + UART_NONE_BITS = 0, + UART_ODD_BITS = BIT0, + UART_EVEN_BITS = 0 +} UartParityMode; + +typedef enum { + UART_STICK_PARITY_DIS = 0, + UART_STICK_PARITY_EN = BIT1 +} UartExistParity; + +typedef enum { + UART_BIT_RATE_9600 = 9600, + UART_BIT_RATE_19200 = 19200, + UART_BIT_RATE_38400 = 38400, + UART_BIT_RATE_57600 = 57600, + UART_BIT_RATE_74880 = 74880, + UART_BIT_RATE_115200 = 115200, + UART_BIT_RATE_230400 = 230400, + UART_BIT_RATE_256000 = 256000, + UART_BIT_RATE_460800 = 460800, + UART_BIT_RATE_921600 = 921600 +} UartBautRate; + +typedef enum { + UART_NONE_CTRL, + UART_HARDWARE_CTRL, + UART_XON_XOFF_CTRL +} UartFlowCtrl; + +typedef enum { + UART_EMPTY, + UART_UNDER_WRITE, + UART_WRITE_OVER +} RcvMsgBuffState; + +typedef struct { + uint32 RcvBuffSize; + uint8 *pRcvMsgBuff; + uint8 *pWritePos; + uint8 *pReadPos; + uint8 TrigLvl; //JLU: may need to pad + RcvMsgBuffState BuffState; +} RcvMsgBuff; + +typedef struct { + uint32 TrxBuffSize; + uint8 *pTrxBuff; +} TrxMsgBuff; + +typedef enum { + UART_BAUD_RATE_DET, + UART_WAIT_SYNC_FRM, + UART_SRCH_MSG_HEAD, + UART_RCV_MSG_BODY, + UART_RCV_ESC_CHAR, +} RcvMsgState; + +typedef struct { + UartBautRate baut_rate; + UartBitsNum4Char data_bits; + UartExistParity exist_parity; + UartParityMode parity; // chip size in byte + UartStopBitsNum stop_bits; + UartFlowCtrl flow_ctrl; + RcvMsgBuff rcv_buff; + TrxMsgBuff trx_buff; + RcvMsgState rcv_state; + int received; + int buff_uart_no; //indicate which uart use tx/rx buffer +} UartDevice; + +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +int uart0_rx(void); +bool uart_rx_wait(uint32_t timeout_us); +int uart_rx_char(void); +void uart_tx_one_char(uint8 uart, uint8 TxChar); +void uart_flush(uint8 uart); +void uart_os_config(int uart); +void uart_setup(uint8 uart); +// check status of rx/tx +int uart_rx_any(uint8 uart); +int uart_tx_any_room(uint8 uart); + +#endif // MICROPY_INCLUDED_ESP8266_UART_H diff --git a/src/openmv/src/micropython/ports/esp8266/uart_register.h b/src/openmv/src/micropython/ports/esp8266/uart_register.h new file mode 100755 index 0000000..6398879 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/uart_register.h @@ -0,0 +1,128 @@ +//Generated at 2012-07-03 18:44:06 +/* + * Copyright (c) 2010 - 2011 Espressif System + * + */ + +#ifndef UART_REGISTER_H_INCLUDED +#define UART_REGISTER_H_INCLUDED +#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) +//version value:32'h062000 + +#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) +#define UART_RXFIFO_RD_BYTE 0x000000FF +#define UART_RXFIFO_RD_BYTE_S 0 + +#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) +#define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) +#define UART_BRK_DET_INT_RAW (BIT(7)) +#define UART_CTS_CHG_INT_RAW (BIT(6)) +#define UART_DSR_CHG_INT_RAW (BIT(5)) +#define UART_RXFIFO_OVF_INT_RAW (BIT(4)) +#define UART_FRM_ERR_INT_RAW (BIT(3)) +#define UART_PARITY_ERR_INT_RAW (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) +#define UART_RXFIFO_FULL_INT_RAW (BIT(0)) + +#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) +#define UART_RXFIFO_TOUT_INT_ST (BIT(8)) +#define UART_BRK_DET_INT_ST (BIT(7)) +#define UART_CTS_CHG_INT_ST (BIT(6)) +#define UART_DSR_CHG_INT_ST (BIT(5)) +#define UART_RXFIFO_OVF_INT_ST (BIT(4)) +#define UART_FRM_ERR_INT_ST (BIT(3)) +#define UART_PARITY_ERR_INT_ST (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) +#define UART_RXFIFO_FULL_INT_ST (BIT(0)) + +#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) +#define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) +#define UART_BRK_DET_INT_ENA (BIT(7)) +#define UART_CTS_CHG_INT_ENA (BIT(6)) +#define UART_DSR_CHG_INT_ENA (BIT(5)) +#define UART_RXFIFO_OVF_INT_ENA (BIT(4)) +#define UART_FRM_ERR_INT_ENA (BIT(3)) +#define UART_PARITY_ERR_INT_ENA (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) +#define UART_RXFIFO_FULL_INT_ENA (BIT(0)) + +#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) +#define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) +#define UART_BRK_DET_INT_CLR (BIT(7)) +#define UART_CTS_CHG_INT_CLR (BIT(6)) +#define UART_DSR_CHG_INT_CLR (BIT(5)) +#define UART_RXFIFO_OVF_INT_CLR (BIT(4)) +#define UART_FRM_ERR_INT_CLR (BIT(3)) +#define UART_PARITY_ERR_INT_CLR (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) +#define UART_RXFIFO_FULL_INT_CLR (BIT(0)) + +#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) +#define UART_CLKDIV_CNT 0x000FFFFF +#define UART_CLKDIV_S 0 + +#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) +#define UART_GLITCH_FILT 0x000000FF +#define UART_GLITCH_FILT_S 8 +#define UART_AUTOBAUD_EN (BIT(0)) + +#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) +#define UART_TXD (BIT(31)) +#define UART_RTSN (BIT(30)) +#define UART_DTRN (BIT(29)) +#define UART_TXFIFO_CNT 0x000000FF +#define UART_TXFIFO_CNT_S 16 +#define UART_RXD (BIT(15)) +#define UART_CTSN (BIT(14)) +#define UART_DSRN (BIT(13)) +#define UART_RXFIFO_CNT 0x000000FF +#define UART_RXFIFO_CNT_S 0 + +#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) +#define UART_TXFIFO_RST (BIT(18)) +#define UART_RXFIFO_RST (BIT(17)) +#define UART_IRDA_EN (BIT(16)) +#define UART_TX_FLOW_EN (BIT(15)) +#define UART_LOOPBACK (BIT(14)) +#define UART_IRDA_RX_INV (BIT(13)) +#define UART_IRDA_TX_INV (BIT(12)) +#define UART_IRDA_WCTL (BIT(11)) +#define UART_IRDA_TX_EN (BIT(10)) +#define UART_IRDA_DPLX (BIT(9)) +#define UART_TXD_BRK (BIT(8)) +#define UART_SW_DTR (BIT(7)) +#define UART_SW_RTS (BIT(6)) +#define UART_STOP_BIT_NUM 0x00000003 +#define UART_STOP_BIT_NUM_S 4 +#define UART_BIT_NUM 0x00000003 +#define UART_BIT_NUM_S 2 +#define UART_PARITY_EN (BIT(1)) +#define UART_PARITY (BIT(0)) + +#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) +#define UART_RX_TOUT_EN (BIT(31)) +#define UART_RX_TOUT_THRHD 0x0000007F +#define UART_RX_TOUT_THRHD_S 24 +#define UART_RX_FLOW_EN (BIT(23)) +#define UART_RX_FLOW_THRHD 0x0000007F +#define UART_RX_FLOW_THRHD_S 16 +#define UART_TXFIFO_EMPTY_THRHD 0x0000007F +#define UART_TXFIFO_EMPTY_THRHD_S 8 +#define UART_RXFIFO_FULL_THRHD 0x0000007F +#define UART_RXFIFO_FULL_THRHD_S 0 + +#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) +#define UART_LOWPULSE_MIN_CNT 0x000FFFFF +#define UART_LOWPULSE_MIN_CNT_S 0 + +#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) +#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF +#define UART_HIGHPULSE_MIN_CNT_S 0 + +#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) +#define UART_PULSE_NUM_CNT 0x0003FF +#define UART_PULSE_NUM_CNT_S 0 + +#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) +#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) +#endif // UART_REGISTER_H_INCLUDED diff --git a/src/openmv/src/micropython/ports/esp8266/user_config.h b/src/openmv/src/micropython/ports/esp8266/user_config.h new file mode 100755 index 0000000..8b1a393 --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/user_config.h @@ -0,0 +1 @@ +// empty diff --git a/src/openmv/src/micropython/ports/esp8266/xtirq.h b/src/openmv/src/micropython/ports/esp8266/xtirq.h new file mode 100755 index 0000000..595052f --- /dev/null +++ b/src/openmv/src/micropython/ports/esp8266/xtirq.h @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP8266_XTIRQ_H +#define MICROPY_INCLUDED_ESP8266_XTIRQ_H + +#include + +// returns the value of "intlevel" from the PS register +static inline uint32_t query_irq(void) { + uint32_t ps; + __asm__ volatile("rsr %0, ps" : "=a" (ps)); + return ps & 0xf; +} + +// irqs with a priority value lower or equal to "intlevel" will be disabled +// "intlevel" should be between 0 and 15 inclusive, and should be an integer +static inline uint32_t raise_irq_pri(uint32_t intlevel) { + uint32_t old_ps; + __asm__ volatile ("rsil %0, %1" : "=a" (old_ps) : "I" (intlevel)); + return old_ps; +} + +// "ps" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t ps) { + __asm__ volatile ("wsr %0, ps; rsync" :: "a" (ps)); +} + +static inline uint32_t disable_irq(void) { + return raise_irq_pri(15); +} + +static inline void enable_irq(uint32_t irq_state) { + restore_irq_pri(irq_state); +} + +#endif // MICROPY_INCLUDED_ESP8266_XTIRQ_H diff --git a/src/openmv/src/micropython/ports/k210-standalone/Makefile b/src/openmv/src/micropython/ports/k210-standalone/Makefile new file mode 100755 index 0000000..4fb8ce7 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/Makefile @@ -0,0 +1,339 @@ +.PHONY: clean_all build +include ../../py/mkenv.mk + +CROSS_COMPILE=riscv64-unknown-elf- +SDK_PATH ?= ../../../../../.. +MPY_MOD_PATH ?= mpy-mod +FS_PORT_PATH ?= spiffs-port +BOARD_DRIVERS_PATH ?= board-drivers + +#hutu +MPY_ROOT_PATH ?= ../.. +OMV_MOD_PATH ?= ../../../omv + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +FROZEN_MPY_DIR ?= buildin-py + +# include py core make definitionsvers/uarths.c +include $(TOP)/py/py.mk + +# mpy header +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -Iconfig +INC += -Iinclude +INC += -I$(TOP)/lib/timeutils +INC += -I$(SDK_PATH)/lib/bsp/include +INC += -I$(SDK_PATH)/lib/drivers/include +INC += -I$(SDK_PATH)/lib/syslog/include +INC += -I$(SDK_PATH)/lib/math + +# mpy mod header +INC += -I$(MPY_MOD_PATH)/machine/include +INC += -I$(MPY_MOD_PATH)/uos/include + +# board drivers header +INC += -I$(BOARD_DRIVERS_PATH)/include + +# spiffs ports header +INC += -Ispiffs-port/include + +# sdk header +INC += -I$(SDK_PATH)/lib/bsp/include +INC += -I$(SDK_PATH)/lib/drivers/include +INC += -I$(SDK_PATH)/lib/utils/include +INC += -I$(SDK_PATH)/lib/math + +# spiffs header +INC += -Ispiffs/src +INC += -Ispiffs/src/default + +#hutu omv header +INC += -I$(OMV_MOD_PATH) +INC += -I$(OMV_MOD_PATH)/py +INC += -I$(OMV_MOD_PATH)/nn +INC += -I$(OMV_MOD_PATH)/img +INC += -I$(OMV_MOD_PATH)/boards/OPENMV3 + +INC += -I$(MPY_ROOT_PATH)/py +INC += -I$(MPY_ROOT_PATH)//lib/mp-readline +INC += -I$(MPY_ROOT_PATH)//lib/oofatfs + +# compile option +C_DEFINES ?= +C_DEFINES += -DCONFIG_LOG_COLORS \ + -DCONFIG_LOG_ENABLE \ + -DCONFIG_LOG_LEVEL=LOG_VERBOSE \ + -DDEBUG=1 \ + -DFPGA_PLL \ + -DLOG_KERNEL \ + -D__riscv64 + +ARCH_FLAGS = -march=rv64imafdc -mabi=lp64d + +BOTH_FLAGS = -mcmodel=medany \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -fstrict-volatile-bitfields \ + -fno-zero-initialized-in-bss \ + -Os \ + -ggdb \ + -Wall \ + -Werror=all \ + -Wno-error=unused-function \ + -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable \ + -Wno-error=deprecated-declarations \ + -Wextra \ + -Werror=frame-larger-than=65536 \ + -Wno-unused-parameter \ + -Wno-sign-compare \ + -Wno-error=missing-braces \ + -Wno-error=return-type \ + -Wno-error=pointer-sign \ + -Wno-missing-braces \ + -Wno-pointer-to-int-cast \ + -Wno-strict-aliasing \ + -Wno-implicit-fallthrough \ + -Linclude/ + +CFLAGS_RV64_K210 = -lm \ + -mfdiv \ + -mdiv \ + -std=gnu11 \ + -Wno-old-style-declaration \ + -g \ + $(C_DEFINES) \ + $(BOTH_FLAGS) + +CFLAGS = $(INC) \ + -std=gnu11 \ + $(CFLAGS_RV64_K210) \ + -g -Wno-error=unused-label \ + -Wno-error=unused-const-variable= \ + -Wno-error=format= \ + -Wno-error=parentheses + + +CFLAGS_MOD += $(C_DEFINES) +CFLAGS += $(CFLAGS_MOD) + +LDPPFLAGS += \ + -DDUSE_BINUTILS_2_19=1 +LDFLAGS += --gc-sections + +LDFLAGS = -lm $(BOTH_FLAGS) -T $(SDK_PATH)/lds/kendryte.ld \ + -nostartfiles \ + -static \ + -Wl,--gc-sections \ + -Wl,-static \ + -Wl,--start-group \ + -Wl,--whole-archive \ + -Wl,--no-whole-archive \ + -Wl,--end-group \ + -Wl,-EL + +LIBS = + +MODULES_SRC_C= \ + $(MPY_MOD_PATH)/uos/moduos.c \ + $(MPY_MOD_PATH)/machine/modmachine.c \ + $(MPY_MOD_PATH)/machine/machine_uarths.c\ + $(MPY_MOD_PATH)/machine/machine_uart.c \ + $(MPY_MOD_PATH)/machine/machine_pin.c \ + $(MPY_MOD_PATH)/machine/machine_pwm.c \ + $(MPY_MOD_PATH)/machine/machine_timer.c\ + $(MPY_MOD_PATH)/machine/machine_st7789.c\ + $(MPY_MOD_PATH)/machine/machine_ov2640.c\ + $(MPY_MOD_PATH)/machine/machine_burner.c\ + $(MPY_MOD_PATH)/machine/machine_face_detect.c\ + $(MPY_MOD_PATH)/machine/machine_spiflash.c\ + $(MPY_MOD_PATH)/machine/machine_zmodem.c\ + $(MPY_MOD_PATH)/machine/machine_fpioa.c\ + $(MPY_MOD_PATH)/machine/machine_ws2812.c + +LIB_SRC_C ?= +MICROPY_FATFS=1 +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ +lib/oofatfs/ff.c \ +lib/oofatfs/option/unicode.c +endif + +FS_SRC_C = \ + $(FS_PORT_PATH)/spiffs-port.c \ + spiffs/src/spiffs_cache.c \ + spiffs/src/spiffs_check.c \ + spiffs/src/spiffs_gc.c \ + spiffs/src/spiffs_hydrogen.c \ + spiffs/src/spiffs_nucleus.c \ + file_io.c + +BOARD_DRIVERS = $(BOARD_DRIVERS_PATH)/lcd.c\ + $(BOARD_DRIVERS_PATH)/st7789.c\ + $(BOARD_DRIVERS_PATH)/ov2640.c\ + $(BOARD_DRIVERS_PATH)/ov5640.c\ + $(BOARD_DRIVERS_PATH)/w25qxx.c\ + $(BOARD_DRIVERS_PATH)/face_detect.c\ + $(BOARD_DRIVERS_PATH)/region_layer.c\ + $(BOARD_DRIVERS_PATH)/uart_core.c\ + $(BOARD_DRIVERS_PATH)/ws2812b.c + +MPY_LIB_SRC = lib/timeutils/timeutils.c \ + lib/utils/sys_stdio_mphal.c + +#OMV_SRC_C = \ + $(OMV_MOD_PATH)/xalloc.c \ + $(OMV_MOD_PATH)fb_alloc.c \ + $(OMV_MOD_PATH)umm_malloc.c \ + $(OMV_MOD_PATH)ff_wrapper.c \ + $(OMV_MOD_PATH)ini.c \ + $(OMV_MOD_PATH)framebuffer.c \ + $(OMV_MOD_PATH)array.c \ + $(OMV_MOD_PATH)cambus.c \ + $(OMV_MOD_PATH)ov9650.c \ + $(OMV_MOD_PATH)ov2640.c \ + $(OMV_MOD_PATH)ov7725.c \ + $(OMV_MOD_PATH)mt9v034.c \ + $(OMV_MOD_PATH)lepton.c \ + $(OMV_MOD_PATH)sensor.c \ + $(OMV_MOD_PATH)soft_i2c.c \ + $(OMV_MOD_PATH)mutex.c \ + $(OMV_MOD_PATH)trace.c + +OMV_SRC_C += \ + $(OMV_MOD_PATH)/xalloc.c \ + $(OMV_MOD_PATH)/fb_alloc.c \ + $(OMV_MOD_PATH)/umm_malloc.c \ + $(OMV_MOD_PATH)/ff_wrapper.c \ + $(OMV_MOD_PATH)/ini.c \ + $(OMV_MOD_PATH)/framebuffer.c \ + $(OMV_MOD_PATH)/array.c \ + $(OMV_MOD_PATH)/mutex.c \ + $(OMV_MOD_PATH)/trace.c + +OMV_SRC_C += \ + $(OMV_MOD_PATH)/img/binary.c \ + $(OMV_MOD_PATH)/img/blob.c \ + $(OMV_MOD_PATH)/img/clahe.c \ + $(OMV_MOD_PATH)/img/draw.c \ + $(OMV_MOD_PATH)/img/qrcode.c \ + $(OMV_MOD_PATH)/img/apriltag.c \ + $(OMV_MOD_PATH)/img/dmtx.c \ + $(OMV_MOD_PATH)/img/zbar.c \ + $(OMV_MOD_PATH)/img/fmath.c \ + $(OMV_MOD_PATH)/img/fsort.c \ + $(OMV_MOD_PATH)/img/qsort.c \ + $(OMV_MOD_PATH)/img/fft.c \ + $(OMV_MOD_PATH)/img/filter.c \ + $(OMV_MOD_PATH)/img/haar.c \ + $(OMV_MOD_PATH)/img/imlib.c \ + $(OMV_MOD_PATH)/img/collections.c \ + $(OMV_MOD_PATH)/img/stats.c \ + $(OMV_MOD_PATH)/img/integral.c \ + $(OMV_MOD_PATH)/img/integral_mw.c \ + $(OMV_MOD_PATH)/img/kmeans.c \ + $(OMV_MOD_PATH)/img/lab_tab.c \ + $(OMV_MOD_PATH)/img/xyz_tab.c \ + $(OMV_MOD_PATH)/img/yuv_tab.c \ + $(OMV_MOD_PATH)/img/rainbow_tab.c \ + $(OMV_MOD_PATH)/img/rgb2rgb_tab.c \ + $(OMV_MOD_PATH)/img/invariant_tab.c \ + $(OMV_MOD_PATH)/img/mathop.c \ + $(OMV_MOD_PATH)/img/pool.c \ + $(OMV_MOD_PATH)/img/point.c \ + $(OMV_MOD_PATH)/img/rectangle.c \ + $(OMV_MOD_PATH)/img/bmp.c \ + $(OMV_MOD_PATH)/img/ppm.c \ + $(OMV_MOD_PATH)/img/gif.c \ + $(OMV_MOD_PATH)/img/mjpeg.c \ + $(OMV_MOD_PATH)/img/fast.c \ + $(OMV_MOD_PATH)/img/agast.c \ + $(OMV_MOD_PATH)/img/orb.c \ + $(OMV_MOD_PATH)/img/template.c \ + $(OMV_MOD_PATH)/img/phasecorrelation.c \ + $(OMV_MOD_PATH)/img/shadow_removal.c \ + $(OMV_MOD_PATH)/img/font.c \ + $(OMV_MOD_PATH)/img/jpeg.c \ + $(OMV_MOD_PATH)/img/lbp.c \ + $(OMV_MOD_PATH)/img/eye.c \ + $(OMV_MOD_PATH)/img/hough.c \ + $(OMV_MOD_PATH)/img/line.c \ + $(OMV_MOD_PATH)/img/lsd.c \ + $(OMV_MOD_PATH)/img/sincos_tab.c \ + $(OMV_MOD_PATH)/img/edge.c \ + $(OMV_MOD_PATH)/img/hog.c \ + $(OMV_MOD_PATH)/img/selective_search.c + +#OMV_SRC_C += \ + $(OMV_MOD_PATH)/nn/nn.c + + +#OMV_SRC_C += \ + $(OMV_MOD_PATH)/py/py_helper.c \ + $(OMV_MOD_PATH)/py/py_omv.c \ + $(OMV_MOD_PATH)/py/py_sensor.c \ + $(OMV_MOD_PATH)/py/py_image.c \ + $(OMV_MOD_PATH)/py/py_time.c \ + $(OMV_MOD_PATH)/py/py_lcd.c \ + $(OMV_MOD_PATH)/py/py_gif.c \ + $(OMV_MOD_PATH)/py/py_mjpeg.c \ + $(OMV_MOD_PATH)/py/py_cpufreq.c \ + $(OMV_MOD_PATH)/py/py_nn.c + +OMV_SRC_C += \ + $(OMV_MOD_PATH)/py/py_helper.c \ + $(OMV_MOD_PATH)/py/py_omv.c \ + $(OMV_MOD_PATH)/py/py_image.c \ + $(OMV_MOD_PATH)/py/py_gif.c \ + $(OMV_MOD_PATH)/py/py_mjpeg.c +SRC_C = \ + $(MODULES_SRC_C)\ + main.c \ + $(BOARD_DRIVERS) \ + $(MPY_LIB_SRC) \ + $(FS_SRC_C) \ + $(LIB_SRC_C) \ + $(OMV_SRC_C) + +PY_SRC_C = \ + help.c \ + lib/utils/stdout_helpers.c \ + lib/utils/interrupt_char.c \ + lib/utils/pyexec.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c + + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) +# Append any auto-generated sources that are needed by sources listed in SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) $(addprefix $(BUILD)/, $(PY_SRC_C:.c=.o)) + +$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h + $(ECHO) "MISC freezing bytecode" + $(Q)$(TOP)/tools/mpy-tool.py -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=none $< > $@ + +all: micropython + +micropython: $(OBJ) + $(AR) r micropython.a $(OBJ) + + +clean: clean_py + rm -rf *.a + make -C ../../mpy-cross clean + rm -rf ../../mpy-cross/build + rm -rf ../../omv + + + +include $(TOP)/py/mkrules.mk + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/face_detect.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/face_detect.c new file mode 100755 index 0000000..803a9b4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/face_detect.c @@ -0,0 +1,363 @@ +#include +#include +#include +#include "face_detect.h" +#include "platform.h" +#include "sysctl.h" +#include "w25qxx.h" +#include "lcd.h" +#include "dmac.h" +#include "plic.h" +#include "region_layer.h" +// #include "coprocessor.h" + +#define AI_DMA_CHANNEL 1 +#define __AI_DMA_INTERRUPT(x) IRQN_DMA##x##_INTERRUPT +#define _AI_DMA_INTERRUPT(x) __AI_DMA_INTERRUPT(x) +#define AI_DMA_INTERRUPT _AI_DMA_INTERRUPT(AI_DMA_CHANNEL) + +#define AI_CFG_ADDRESS (512 * 1024) +#define AI_CFG_SIZE (4 * 1024) + +struct ai_reg_t { + volatile uint64_t cfg_fifo; + volatile uint64_t intr_status; + volatile uint64_t intr_raw; + volatile uint64_t intr_mask; + volatile uint64_t intr_clear; + volatile uint64_t fifo_threshold; + volatile uint64_t output_fifo; + volatile uint64_t reserve; + volatile uint64_t bit_mode; +} __attribute__((packed, aligned(8))); +volatile struct ai_reg_t *const ai_reg = (volatile struct ai_reg_t *)AI_BASE_ADDR; + +static OBJECT_INFO object_info; + +typedef struct { + uint32_t magic; + uint32_t bit_mode; + uint32_t layer; + uint32_t layer_addr; + uint32_t class; + uint32_t label_addr; + float threshold; + float nms; + uint32_t active_addr; + uint32_t active_len; + uint32_t softmax_addr; + uint32_t softmax_len; + uint32_t biases_addr; + uint32_t biases_len; + uint32_t reserve[2]; +} MODEL_CFG; + +typedef struct { + char name[24]; + uint16_t len; + uint16_t height; + uint16_t width; + uint16_t color; +} LABEL_CFG; + +typedef struct { + char name[24]; + uint16_t len; + uint16_t height; + uint16_t width; + uint16_t color; + uint32_t *ptr; +} LABEL_PARAM; + +typedef struct { + uint32_t reg_addr; + uint32_t reg_len; + uint32_t act_addr; + uint32_t act_len; + uint32_t arg_addr; + uint32_t arg_len; + uint32_t wht_addr; + uint32_t wht_len; +} LAYER_CFG; + +typedef struct { + uint64_t *reg; + uint64_t *act; + uint64_t *arg; + uint64_t *wht; +} LAYER_PARAM; + +typedef struct { + uint32_t bit_mode; + uint32_t layer; + uint32_t class; + LAYER_PARAM *layer_param; + LABEL_PARAM *label_param; + uint32_t input_addr; + uint32_t input_len; + uint32_t output_addr; + uint32_t output_len; +} AI_PARAM;//__attribute__(4); + +static AI_PARAM ai_param; + +static int ai_param_init(uint8_t mode) +{ + void *ptr; + MODEL_CFG model_cfg; + REGION_CFG region_cfg; + LAYER_CFG layer_cfg; + LABEL_CFG label_cfg; + w25qxx_read_data(AI_CFG_ADDRESS + AI_CFG_SIZE * mode, (uint8_t *)&model_cfg, sizeof(MODEL_CFG), W25QXX_QUAD_FAST); + if (model_cfg.magic != 0x12345678) + { + printf("ai param magic is error\n"); + return 1; + } + // region layer init + region_cfg.class = model_cfg.class; + region_cfg.threshold = model_cfg.threshold; + region_cfg.nms = model_cfg.nms; + ptr = malloc(model_cfg.active_len); + if (ptr == NULL) + return 1; + region_cfg.active = (float *)ptr; + ptr = malloc(model_cfg.softmax_len); + if (ptr == NULL) + return 1; + region_cfg.softmax = (float *)ptr; + ptr = malloc(model_cfg.biases_len); + if (ptr == NULL) + return 1; + region_cfg.biases = (float *)ptr; + w25qxx_read_data(model_cfg.active_addr, (uint8_t *)region_cfg.active, model_cfg.active_len, W25QXX_QUAD_FAST); + w25qxx_read_data(model_cfg.softmax_addr, (uint8_t *)region_cfg.softmax, model_cfg.softmax_len, W25QXX_QUAD_FAST); + w25qxx_read_data(model_cfg.biases_addr, (uint8_t *)region_cfg.biases, model_cfg.biases_len, W25QXX_QUAD_FAST); + if (region_layer_init(®ion_cfg)) + return 1; + ai_param.output_addr = (uint32_t)region_cfg.input; + ai_param.output_len = (region_cfg.input_len + 7) / 8; + // layer init + ai_param.layer = model_cfg.layer; + ptr = malloc(sizeof(LAYER_PARAM) * ai_param.layer); + if (ptr == NULL) + return 1; + ai_param.layer_param = (LAYER_PARAM *)ptr; + for (uint32_t layer = 0; layer < ai_param.layer; layer++) { + w25qxx_read_data(model_cfg.layer_addr + sizeof(LAYER_CFG) * layer, (uint8_t *)&layer_cfg, sizeof(LAYER_CFG), W25QXX_QUAD_FAST); + // reg + ptr = malloc(layer_cfg.reg_len); + if (ptr == NULL) + return 1; + ai_param.layer_param[layer].reg = (uint64_t *)ptr; + w25qxx_read_data(layer_cfg.reg_addr, (uint8_t *)ptr, layer_cfg.reg_len, W25QXX_QUAD_FAST); + // act + ptr = malloc(layer_cfg.act_len); + if (ptr == NULL) + return 1; + ai_param.layer_param[layer].act = (uint64_t *)ptr; + w25qxx_read_data(layer_cfg.act_addr, (uint8_t *)ptr, layer_cfg.act_len, W25QXX_QUAD_FAST); + // arg + ptr = malloc(layer_cfg.arg_len); + if (ptr == NULL) + return 1; + ai_param.layer_param[layer].arg = (uint64_t *)ptr; + w25qxx_read_data(layer_cfg.arg_addr, (uint8_t *)ptr, layer_cfg.arg_len, W25QXX_QUAD_FAST); + // wht + ptr = malloc(layer_cfg.wht_len); + if (ptr == NULL) + return 1; + ai_param.layer_param[layer].wht = (uint64_t *)ptr; + w25qxx_read_data(layer_cfg.wht_addr, (uint8_t *)ptr, layer_cfg.wht_len, W25QXX_QUAD_FAST); + } + // label init + ai_param.class = model_cfg.class; + if (ai_param.class > 1) { + ptr = malloc(sizeof(LABEL_PARAM) * ai_param.class); + if (ptr == NULL) + return 1; + ai_param.label_param = (LABEL_PARAM *)ptr; + for (uint32_t class = 0; class < ai_param.class; class++) { + w25qxx_read_data(model_cfg.label_addr + sizeof(LABEL_CFG) * class, (uint8_t *)&label_cfg, sizeof(LABEL_CFG), W25QXX_QUAD_FAST); + + ai_param.label_param[class].len = label_cfg.len; + ai_param.label_param[class].height = label_cfg.height; + ai_param.label_param[class].width = label_cfg.width; + ai_param.label_param[class].color = label_cfg.color; + memcpy(ai_param.label_param[class].name, label_cfg.name, 24); + } + } + ai_param.bit_mode = model_cfg.bit_mode; + return 0; +} + +static int lable_init(void) +{ + if (ai_param.class <= 1) + return 0; + for (uint32_t class = 1; class < ai_param.class; class++) { + ai_param.label_param[class].width *= ai_param.label_param[class].len; + ai_param.label_param[class].ptr = (uint32_t *)malloc(ai_param.label_param[class].width * ai_param.label_param[class].height * 2); + if (ai_param.label_param[class].ptr == NULL) + return 1; + // lcd_draw_string(ai_param.label_param[class].name, ai_param.label_param[class].ptr, BLACK, ai_param.label_param[class].color); + } + return 0; +} + +static int ai_irq(void *ctx) +{ + ai_reg->intr_mask = 0x7; + ai_reg->intr_clear = 0x7; + for (uint32_t layer = 12; layer < ai_param.layer; layer++) { + for (uint32_t index = 0; index < 12; index++) + ai_reg->cfg_fifo = ai_param.layer_param[layer].reg[index]; + } + return 0; +} + +int ai_init(uint8_t mode) +{ + object_info.object_num = 0; + if (ai_param_init(mode)) + return 1; + if (lable_init()) + return 1; + for (uint32_t layer = 0; layer < ai_param.layer; layer++) { + ai_param.layer_param[layer].reg[4] &= 0x00000000FFFFFFFF; + ai_param.layer_param[layer].reg[5] &= 0x00000000FFFFFFFF; + ai_param.layer_param[layer].reg[7] &= 0x00000000FFFFFFFF; + ai_param.layer_param[layer].reg[4] |= (((uint64_t)ai_param.layer_param[layer].arg) << 32); + ai_param.layer_param[layer].reg[5] |= (((uint64_t)ai_param.layer_param[layer].wht) << 32); + ai_param.layer_param[layer].reg[7] |= (((uint64_t)ai_param.layer_param[layer].act) << 32); + } + ai_param.input_addr = AI_IO_BASE_ADDR + (ai_param.layer_param[0].reg[1] & 0x7FFF) * 64; + ai_param.input_len = 320 * 240 * 3 / 8; + sysctl_clock_enable(SYSCTL_CLOCK_AI); + ai_reg->bit_mode = ai_param.bit_mode; + ai_reg->fifo_threshold = 0x10; + ai_reg->intr_mask = 0x07; + ai_reg->intr_clear = 0x07; + dmac->channel[AI_DMA_CHANNEL].intstatus_en = 0x02; + dmac->channel[AI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + if (ai_param.layer > 13) { + plic_irq_enable(IRQN_AI_INTERRUPT); + plic_set_priority(IRQN_AI_INTERRUPT, 1); + plic_irq_register(IRQN_AI_INTERRUPT, ai_irq, NULL); + } + plic_irq_enable(AI_DMA_INTERRUPT); + plic_set_priority(AI_DMA_INTERRUPT, 1); + plic_irq_register(AI_DMA_INTERRUPT, ai_dma_irq, NULL); + return 0; +} + +void ai_cal_start(void) +{ + if (ai_param.layer > 13) { + for (uint32_t layer = 0; layer < 12; layer++) { + for (uint32_t index = 0; index < 12; index++) + ai_reg->cfg_fifo = ai_param.layer_param[layer].reg[index]; + } + ai_reg->intr_mask = 0x05; + } else { + for (uint32_t layer = 0; layer < ai_param.layer; layer++) { + for (uint32_t index = 0; index < 12; index++) + ai_reg->cfg_fifo = ai_param.layer_param[layer].reg[index]; + } + } +} + +void ai_data_input(uint32_t addr) +{ + + dmac->channel[AI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)3 << 11) | ((uint64_t)3 << 8)); + dmac->channel[AI_DMA_CHANNEL].cfg = ((uint64_t)1 << 49); + dmac->channel[AI_DMA_CHANNEL].sar = (uint64_t)addr; + dmac->channel[AI_DMA_CHANNEL].dar = (uint64_t)ai_param.input_addr; + dmac->channel[AI_DMA_CHANNEL].block_ts = ai_param.input_len - 1; + dmac->chen = 0x0101 << AI_DMA_CHANNEL; +} + +void ai_data_output(void) +{ + sysctl_dma_select(AI_DMA_CHANNEL, SYSCTL_DMA_SELECT_AI_RX_REQ); + dmac->channel[AI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)7 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)7 << 39) | + ((uint64_t)2 << 18) | ((uint64_t)2 << 14) | + ((uint64_t)3 << 11) | ((uint64_t)3 << 8) | + ((uint64_t)1 << 4)); + dmac->channel[AI_DMA_CHANNEL].cfg = (((uint64_t)1 << 49) | ((uint64_t)AI_DMA_CHANNEL << 44) | + ((uint64_t)AI_DMA_CHANNEL << 39) | ((uint64_t)2 << 32)); + dmac->channel[AI_DMA_CHANNEL].sar = (uint64_t)(&ai_reg->output_fifo); + dmac->channel[AI_DMA_CHANNEL].dar = (uint64_t)ai_param.output_addr; + dmac->channel[AI_DMA_CHANNEL].block_ts = ai_param.output_len - 1; + dmac->chen = 0x0101 << AI_DMA_CHANNEL; +} +void ai_test(char* str) +{ + printf("[%s]:ai_param.layer_param[0].reg[0] = %ld\n",str,ai_param.layer_param[0].reg[0]); +} + +void ai_cal_first(void) +{ + region_layer_cal_first(); +} + +void ai_cal_second(void) +{ + region_layer_cal_second(); + region_layer_detect_object(&object_info); +} + +// void ai_result_send(void) +// { +// VIDEO_INFO_SEND video_info_send; + +// video_info_send.object_num = object_info.object_num; +// for (uint8_t i = 0; i < object_info.object_num; i++) { +// video_info_send.object[i].x1 = object_info.object[i].x1; +// video_info_send.object[i].x2 = object_info.object[i].x2; +// video_info_send.object[i].y1 = object_info.object[i].y1; +// video_info_send.object[i].y2 = object_info.object[i].y2; +// } +// // coprocessor_send_video_data(&video_info_send); +// } + +void ai_draw_label(uint32_t *ptr) +{ + for (uint8_t i = 0; i < object_info.object_num; i++) { + if (ai_param.class > 1) { + uint8_t class = object_info.object[i].class; + + lcd_draw_rectangle(object_info.object[i].x1, object_info.object[i].y1, + object_info.object[i].x2, object_info.object[i].y2, 2, ai_param.label_param[class].color); + + if ((object_info.object[i].x1 + 1 + ai_param.label_param[class].width < 320) && + (object_info.object[i].y1 + 1 + ai_param.label_param[class].height < 240)) + lcd_draw_picture(object_info.object[i].x1 + 1, + object_info.object[i].y1 + 1, + ai_param.label_param[class].width, + ai_param.label_param[class].height, + ai_param.label_param[class].ptr); + } else{ + // lcd_draw_rectangle(object_info.object[i].x1, object_info.object[i].y1, + // object_info.object[i].x2, object_info.object[i].y2, 2, RED); + uint8_t class = object_info.object[i].class; + /* + printf("(%d,%d)--(%d,%d) >> %d - %d%%\n", object_info.object[i].x1, + object_info.object[i].y1, + object_info.object[i].x2, + object_info.object[i].y2, + class, + (uint8_t)(object_info.object[i].prob * 100)); + */ + lcd_draw_rectangle_cpu(ptr, object_info.object[i].x1, + object_info.object[i].y1, + object_info.object[i].x2, + object_info.object[i].y2, RED); + } + } +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/face_detect.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/face_detect.h new file mode 100755 index 0000000..f8f1639 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/face_detect.h @@ -0,0 +1,18 @@ +#ifndef _AI_H_ +#define _AI_H_ + +#include + +int ai_dma_irq(void *ctx); +int ai_init(uint8_t mode); +void ai_cal_start(void); +void ai_data_input(uint32_t addr); +void ai_data_output(void); +void ai_cal_first(void); +void ai_cal_second(void); +void ai_draw_label(uint32_t *ptr); +void ai_result_send(void); +void ai_test(char* str); + + +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/font.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/font.h new file mode 100755 index 0000000..8894f2b --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/font.h @@ -0,0 +1,449 @@ +#ifndef _FONT_H_ +#define _FONT_H_ + +#include + +uint8_t const ascii0816[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, + 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, + 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, + 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, + 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E, + 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, + 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, + 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, + 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E, + 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, + 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, + 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, + 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, + 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, + 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, + 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, + 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, + 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, + 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, + 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, + 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, + 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, + 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, + 0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, + 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, + 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, + 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 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, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60, + 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, + 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, + 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, + 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, + 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, + 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, + 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, + 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, + 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, + 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, + 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, + 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, + 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C, + 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, + 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, + 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00, + 0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C, + 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC, + 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, + 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, + 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, + 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, + 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C, + 0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, + 0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, + 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36, + 0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, + 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, + 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, + 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, + 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, + 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, + 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +const unsigned char asc2_1608[95][16] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ",0*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xCC, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!",1*/ + {0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x00}, /*""",2*/ + {0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"#",3*/ + {0x00, 0x00, 0x0E, 0x18, 0x11, 0x04, 0x3F, 0xFF, 0x10, 0x84, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00}, /*"$",4*/ + {0x0F, 0x00, 0x10, 0x84, 0x0F, 0x38, 0x00, 0xC0, 0x07, 0x78, 0x18, 0x84, 0x00, 0x78, 0x00, 0x00}, /*"%",5*/ + {0x00, 0x78, 0x0F, 0x84, 0x10, 0xC4, 0x11, 0x24, 0x0E, 0x98, 0x00, 0xE4, 0x00, 0x84, 0x00, 0x08}, /*"&",6*/ + {0x08, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'",7*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x18, 0x18, 0x20, 0x04, 0x40, 0x02, 0x00, 0x00}, /*"(",8*/ + {0x00, 0x00, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*")",9*/ + {0x02, 0x40, 0x02, 0x40, 0x01, 0x80, 0x0F, 0xF0, 0x01, 0x80, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00}, /*"*",10*/ + {0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x0F, 0xF8, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00}, /*"+",11*/ + {0x00, 0x01, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*",",12*/ + {0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80}, /*"-",13*/ + {0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".",14*/ + {0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x18, 0x00, 0x20, 0x00}, /*"/",15*/ + {0x00, 0x00, 0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"0",16*/ + {0x00, 0x00, 0x08, 0x04, 0x08, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"1",17*/ + {0x00, 0x00, 0x0E, 0x0C, 0x10, 0x14, 0x10, 0x24, 0x10, 0x44, 0x11, 0x84, 0x0E, 0x0C, 0x00, 0x00}, /*"2",18*/ + {0x00, 0x00, 0x0C, 0x18, 0x10, 0x04, 0x11, 0x04, 0x11, 0x04, 0x12, 0x88, 0x0C, 0x70, 0x00, 0x00}, /*"3",19*/ + {0x00, 0x00, 0x00, 0xE0, 0x03, 0x20, 0x04, 0x24, 0x08, 0x24, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x00}, /*"4",20*/ + {0x00, 0x00, 0x1F, 0x98, 0x10, 0x84, 0x11, 0x04, 0x11, 0x04, 0x10, 0x88, 0x10, 0x70, 0x00, 0x00}, /*"5",21*/ + {0x00, 0x00, 0x07, 0xF0, 0x08, 0x88, 0x11, 0x04, 0x11, 0x04, 0x18, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"6",22*/ + {0x00, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x10, 0xFC, 0x13, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"7",23*/ + {0x00, 0x00, 0x0E, 0x38, 0x11, 0x44, 0x10, 0x84, 0x10, 0x84, 0x11, 0x44, 0x0E, 0x38, 0x00, 0x00}, /*"8",24*/ + {0x00, 0x00, 0x07, 0x00, 0x08, 0x8C, 0x10, 0x44, 0x10, 0x44, 0x08, 0x88, 0x07, 0xF0, 0x00, 0x00}, /*"9",25*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":",26*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";",27*/ + {0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x00, 0x00}, /*"<",28*/ + {0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"=",29*/ + {0x00, 0x00, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02, 0x20, 0x01, 0x40, 0x00, 0x80, 0x00, 0x00}, /*">",30*/ + {0x00, 0x00, 0x0E, 0x00, 0x12, 0x00, 0x10, 0x0C, 0x10, 0x6C, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"?",31*/ + {0x03, 0xE0, 0x0C, 0x18, 0x13, 0xE4, 0x14, 0x24, 0x17, 0xC4, 0x08, 0x28, 0x07, 0xD0, 0x00, 0x00}, /*"@",32*/ + {0x00, 0x04, 0x00, 0x3C, 0x03, 0xC4, 0x1C, 0x40, 0x07, 0x40, 0x00, 0xE4, 0x00, 0x1C, 0x00, 0x04}, /*"A",33*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x04, 0x0E, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"B",34*/ + {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x10, 0x08, 0x1C, 0x10, 0x00, 0x00}, /*"C",35*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"D",36*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x17, 0xC4, 0x10, 0x04, 0x08, 0x18, 0x00, 0x00}, /*"E",37*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x17, 0xC0, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"F",38*/ + {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x44, 0x1C, 0x78, 0x00, 0x40, 0x00, 0x00}, /*"G",39*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x00, 0x80, 0x00, 0x80, 0x10, 0x84, 0x1F, 0xFC, 0x10, 0x04}, /*"H",40*/ + {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"I",41*/ + {0x00, 0x03, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x1F, 0xFE, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"J",42*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x03, 0x80, 0x14, 0x64, 0x18, 0x1C, 0x10, 0x04, 0x00, 0x00}, /*"K",43*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00}, /*"L",44*/ + {0x10, 0x04, 0x1F, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x00}, /*"M",45*/ + {0x10, 0x04, 0x1F, 0xFC, 0x0C, 0x04, 0x03, 0x00, 0x00, 0xE0, 0x10, 0x18, 0x1F, 0xFC, 0x10, 0x00}, /*"N",46*/ + {0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"O",47*/ + {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"P",48*/ + {0x07, 0xF0, 0x08, 0x18, 0x10, 0x24, 0x10, 0x24, 0x10, 0x1C, 0x08, 0x0A, 0x07, 0xF2, 0x00, 0x00}, /*"Q",49*/ + {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x11, 0xC0, 0x11, 0x30, 0x0E, 0x0C, 0x00, 0x04}, /*"R",50*/ + {0x00, 0x00, 0x0E, 0x1C, 0x11, 0x04, 0x10, 0x84, 0x10, 0x84, 0x10, 0x44, 0x1C, 0x38, 0x00, 0x00}, /*"S",51*/ + {0x18, 0x00, 0x10, 0x00, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"T",52*/ + {0x10, 0x00, 0x1F, 0xF8, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x10, 0x04, 0x1F, 0xF8, 0x10, 0x00}, /*"U",53*/ + {0x10, 0x00, 0x1E, 0x00, 0x11, 0xE0, 0x00, 0x1C, 0x00, 0x70, 0x13, 0x80, 0x1C, 0x00, 0x10, 0x00}, /*"V",54*/ + {0x1F, 0xC0, 0x10, 0x3C, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xE0, 0x10, 0x3C, 0x1F, 0xC0, 0x00, 0x00}, /*"W",55*/ + {0x10, 0x04, 0x18, 0x0C, 0x16, 0x34, 0x01, 0xC0, 0x01, 0xC0, 0x16, 0x34, 0x18, 0x0C, 0x10, 0x04}, /*"X",56*/ + {0x10, 0x00, 0x1C, 0x00, 0x13, 0x04, 0x00, 0xFC, 0x13, 0x04, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"Y",57*/ + {0x08, 0x04, 0x10, 0x1C, 0x10, 0x64, 0x10, 0x84, 0x13, 0x04, 0x1C, 0x04, 0x10, 0x18, 0x00, 0x00}, /*"Z",58*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x00, 0x00}, /*"[",59*/ + {0x00, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00}, /*"\",60*/ + {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"]",61*/ + {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00}, /*"^",62*/ + {0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}, /*"_",63*/ + {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`",64*/ + {0x00, 0x00, 0x00, 0x98, 0x01, 0x24, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xFC, 0x00, 0x04}, /*"a",65*/ + {0x10, 0x00, 0x1F, 0xFC, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"b",66*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x00}, /*"c",67*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x11, 0x08, 0x1F, 0xFC, 0x00, 0x04}, /*"d",68*/ + {0x00, 0x00, 0x00, 0xF8, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xC8, 0x00, 0x00}, /*"e",69*/ + {0x00, 0x00, 0x01, 0x04, 0x01, 0x04, 0x0F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x00, 0x18, 0x00}, /*"f",70*/ + {0x00, 0x00, 0x00, 0xD6, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0xC9, 0x01, 0x06, 0x00, 0x00}, /*"g",71*/ + {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"h",72*/ + {0x00, 0x00, 0x01, 0x04, 0x19, 0x04, 0x19, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"i",73*/ + {0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x01, 0x01, 0x19, 0x01, 0x19, 0xFE, 0x00, 0x00, 0x00, 0x00}, /*"j",74*/ + {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x40, 0x01, 0xB4, 0x01, 0x0C, 0x01, 0x04, 0x00, 0x00}, /*"k",75*/ + {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"l",76*/ + {0x01, 0x04, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x00, 0xFC}, /*"m",77*/ + {0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"n",78*/ + {0x00, 0x00, 0x00, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0xF8, 0x00, 0x00}, /*"o",79*/ + {0x01, 0x01, 0x01, 0xFF, 0x00, 0x85, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"p",80*/ + {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x05, 0x01, 0xFF, 0x00, 0x01}, /*"q",81*/ + {0x01, 0x04, 0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x01, 0x80, 0x00, 0x00}, /*"r",82*/ + {0x00, 0x00, 0x00, 0xCC, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x98, 0x00, 0x00}, /*"s",83*/ + {0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"t",84*/ + {0x01, 0x00, 0x01, 0xF8, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x01, 0x08, 0x01, 0xFC, 0x00, 0x04}, /*"u",85*/ + {0x01, 0x00, 0x01, 0x80, 0x01, 0x70, 0x00, 0x0C, 0x00, 0x10, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"v",86*/ + {0x01, 0xF0, 0x01, 0x0C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x30, 0x01, 0x0C, 0x01, 0xF0, 0x01, 0x00}, /*"w",87*/ + {0x00, 0x00, 0x01, 0x04, 0x01, 0x8C, 0x00, 0x74, 0x01, 0x70, 0x01, 0x8C, 0x01, 0x04, 0x00, 0x00}, /*"x",88*/ + {0x01, 0x01, 0x01, 0x81, 0x01, 0x71, 0x00, 0x0E, 0x00, 0x18, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"y",89*/ + {0x00, 0x00, 0x01, 0x84, 0x01, 0x0C, 0x01, 0x34, 0x01, 0x44, 0x01, 0x84, 0x01, 0x0C, 0x00, 0x00}, /*"z",90*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3E, 0xFC, 0x40, 0x02, 0x40, 0x02}, /*"{",91*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"|",92*/ + {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x3E, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}",93*/ + {0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00}, /*"~",94*/ +}; + +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/lcd.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/lcd.h new file mode 100755 index 0000000..44fb84a --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/lcd.h @@ -0,0 +1,207 @@ +#ifndef _LCD_H_ +#define _LCD_H_ + +#include + +//LCDé‡è¦å‚数集 +typedef struct +{ + uint16_t width; //LCD 宽度 + uint16_t height; //LCD 高度 + uint16_t id; //LCD ID + uint8_t dir; //横å±è¿˜æ˜¯ç«–å±æŽ§åˆ¶ï¼š0,竖å±ï¼›1,横å±ã€‚ + uint8_t wramcmd; //开始写gram指令 + uint8_t setxcmd; //设置xå标指令 + uint8_t setycmd; //设置yå标指令 +}_lcd_dev; + +//LCDå‚æ•° +extern _lcd_dev lcddev; //管ç†LCDé‡è¦å‚æ•° +//LCD的画笔颜色和背景色 +extern uint16_t POINT_COLOR;//默认红色 +extern uint16_t BACK_COLOR; //背景颜色.默认为白色 + +enum lcd_dir_t { + DIR_XY_RLUD = 0x00, + DIR_YX_RLUD = 0x20, + DIR_XY_LRUD = 0x40, + DIR_YX_LRUD = 0x60, + DIR_XY_RLDU = 0x80, + DIR_YX_RLDU = 0xA0, + DIR_XY_LRDU = 0xC0, + DIR_YX_LRDU = 0xE0, + DIR_XY_MASK = 0x20, + DIR_MASK = 0xE0, +}; + +//画笔颜色 +#define WHITE 0xFFFF +#define BLACK 0x0000 +#define BLUE 0x001F +#define BRED 0XF81F +#define GRED 0XFFE0 +#define GBLUE 0X07FF +#define RED 0xF800 +#define MAGENTA 0xF81F +#define GREEN 0x07E0 +#define CYAN 0x7FFF +#define YELLOW 0xFFE0 +#define BROWN 0XBC40 //棕色 +#define BRRED 0XFC07 //棕红色 +#define GRAY 0X8430 //ç°è‰² +//GUI颜色 +#define DARKBLUE 0X01CF //æ·±è“色 +#define LIGHTBLUE 0X7D7C //æµ…è“色 +#define GRAYBLUE 0X5458 //ç°è“色 +//以上三色为PANEL的颜色 +#define LIGHTGREEN 0X841F //浅绿色 +//#define LIGHTGRAY 0XEF5B //æµ…ç°è‰²(PANNEL) +#define LGRAY 0XC618 //æµ…ç°è‰²(PANNEL),窗体背景色 +#define LGRAYBLUE 0XA651 //æµ…ç°è“色(中间层颜色) +#define LBBLUE 0X2B12 //浅棕è“色(选择æ¡ç›®çš„å色) + + +void LCD_DisplayOn(void); //开显示 +void LCD_DisplayOff(void); //关显示 + +void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos); //设置光标 +void LCD_DrawPoint(uint16_t x,uint16_t y); //画点 +void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint16_t color); //快速画点 +uint16_t LCD_ReadPoint(uint16_t x,uint16_t y); //读点 +void Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r); //画圆 +void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); //画线 +void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); //画矩形 +void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color); //å¡«å……å•è‰² +void LCD_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color); //填充指定颜色 +void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint8_t size,uint8_t mode); //显示一个字符 +void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size); //显示一个数字 +void LCD_ShowxNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size,uint8_t mode); //显示 æ•°å­— +void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,uint8_t *p); //显示一个字符串,12/16字体 +void LCD_Set_Window(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height); +void LCD_WR_REG(uint8_t regval); +void LCD_WR_DATA(uint8_t data); +void LCD_WriteReg(uint8_t LCD_Reg, uint8_t LCD_RegValue); +uint16_t LCD_ReadReg(uint8_t LCD_Reg); +void LCD_WriteRAM_Prepare(void); +void LCD_WriteRAM(uint16_t RGB_Code); +void LCD_Display_Dir(uint8_t dir); //设置å±å¹•æ˜¾ç¤ºæ–¹å‘ + +void LCD_Scan_Dir(enum lcd_dir_t dir); +void lcd_init(void); //åˆå§‹åŒ– +void lcd_clear(uint16_t Color); //æ¸…å± +void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color); +void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr); +void lcd_draw_rectangle_cpu(uint32_t *ptr, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); +void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color); + +//9320/9325 LCD寄存器 +#define R0 0x00 +#define R1 0x01 +#define R2 0x02 +#define R3 0x03 +#define R4 0x04 +#define R5 0x05 +#define R6 0x06 +#define R7 0x07 +#define R8 0x08 +#define R9 0x09 +#define R10 0x0A +#define R12 0x0C +#define R13 0x0D +#define R14 0x0E +#define R15 0x0F +#define R16 0x10 +#define R17 0x11 +#define R18 0x12 +#define R19 0x13 +#define R20 0x14 +#define R21 0x15 +#define R22 0x16 +#define R23 0x17 +#define R24 0x18 +#define R25 0x19 +#define R26 0x1A +#define R27 0x1B +#define R28 0x1C +#define R29 0x1D +#define R30 0x1E +#define R31 0x1F +#define R32 0x20 +#define R33 0x21 +#define R34 0x22 +#define R36 0x24 +#define R37 0x25 +#define R40 0x28 +#define R41 0x29 +#define R43 0x2B +#define R45 0x2D +#define R48 0x30 +#define R49 0x31 +#define R50 0x32 +#define R51 0x33 +#define R52 0x34 +#define R53 0x35 +#define R54 0x36 +#define R55 0x37 +#define R56 0x38 +#define R57 0x39 +#define R59 0x3B +#define R60 0x3C +#define R61 0x3D +#define R62 0x3E +#define R63 0x3F +#define R64 0x40 +#define R65 0x41 +#define R66 0x42 +#define R67 0x43 +#define R68 0x44 +#define R69 0x45 +#define R70 0x46 +#define R71 0x47 +#define R72 0x48 +#define R73 0x49 +#define R74 0x4A +#define R75 0x4B +#define R76 0x4C +#define R77 0x4D +#define R78 0x4E +#define R79 0x4F +#define R80 0x50 +#define R81 0x51 +#define R82 0x52 +#define R83 0x53 +#define R96 0x60 +#define R97 0x61 +#define R106 0x6A +#define R118 0x76 +#define R128 0x80 +#define R129 0x81 +#define R130 0x82 +#define R131 0x83 +#define R132 0x84 +#define R133 0x85 +#define R134 0x86 +#define R135 0x87 +#define R136 0x88 +#define R137 0x89 +#define R139 0x8B +#define R140 0x8C +#define R141 0x8D +#define R143 0x8F +#define R144 0x90 +#define R145 0x91 +#define R146 0x92 +#define R147 0x93 +#define R148 0x94 +#define R149 0x95 +#define R150 0x96 +#define R151 0x97 +#define R152 0x98 +#define R153 0x99 +#define R154 0x9A +#define R157 0x9D +#define R192 0xC0 +#define R193 0xC1 +#define R229 0xE5 + +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov2640.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov2640.h new file mode 100755 index 0000000..31e2818 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov2640.h @@ -0,0 +1,14 @@ +/** + * @file ov2640.h + * @brief OV2640 Controller + */ + +#ifndef _OV2640_K210_H +#define _OV2640_K210_H + +#include + +int ov2640_init(void); +int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id); + +#endif /* _OV2640_H */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640.h new file mode 100755 index 0000000..3cb1fe6 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640.h @@ -0,0 +1,73 @@ +#ifndef _OV5640_H +#define _OV5640_H +#include +//#include "stm32f4xx.h" + + + +#define OV5640_PWDN_Pin_RESET HAL_GPIO_WritePin(OV5640_PWDN_GPIO_Port, OV5640_PWDN_Pin, GPIO_PIN_RESET) + + +#define OV5640_ID 0X5640 +#define OV5640_ADDR 0X78 +#define OV5640_CHIPIDH 0X300A +#define OV5640_CHIPIDL 0X300B + +#define USER_KEY_PRESS HAL_GPIO_ReadPin(USER_KEY_GPIO_Port, USER_KEY_Pin) == 0 +#define WAKE_UP_KEY_PRESS HAL_GPIO_ReadPin(WAKE_UP_KEY_GPIO_Port, WAKE_UP_KEY_Pin) == 0 + +#define XSIZE 320 +#define YSIZE 240 +#define LCD_GRAM_ADDRESS 0x60020000 // FSMC Bank1 NOR/PSRM 1 (LCD_RS=1) + + +#define QQVGA_160_120 0 +#define QCIF_176_144 1 +#define QVGA_320_240 2 +#define WQVGA_400_240 3 +#define CIF_352_288 4 + +#define jpeg_buf_size 30*1024 + +uint8_t OV5640_WR_Reg(uint16_t reg,uint8_t data); +uint8_t OV5640_RD_Reg(uint16_t reg); +uint8_t OV5640_Init(void); +void OV5640_JPEG_Mode(void); +void OV5640_RGB565_Mode(void); +void OV5640_Exposure(uint8_t exposure); +void OV5640_Light_Mode(uint8_t mode); +void OV5640_Color_Saturation(uint8_t sat); +void OV5640_Brightness(uint8_t bright); +void OV5640_Contrast(uint8_t contrast); +void OV5640_Sharpness(uint8_t sharp); +void OV5640_Special_Effects(uint8_t eft); +void OV5640_Test_Pattern(uint8_t mode); +void OV5640_Flash_Lamp(uint8_t sw); +uint8_t OV5640_OutSize_Set(uint16_t offx,uint16_t offy,uint16_t width,uint16_t height); +uint8_t OV5640_Focus_Init(void); +uint8_t OV5640_Auto_Focus(void); +void rgb565_test(void); +void jpeg_test(uint8_t jpg_size); + +#endif + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640af.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640af.h new file mode 100755 index 0000000..e4c09fc --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640af.h @@ -0,0 +1,277 @@ +#ifndef _OV5640AF_H +#define _OV5640AF_H + + + // auto focus config +const unsigned char OV5640_AF_Config[] = +{ + 0x02, 0x0f, 0xd6, 0x02, 0x0a, 0x39, 0xc2, 0x01, 0x22, 0x22, 0x00, 0x02, 0x0f, 0xb2, 0xe5, 0x1f, //0x8000, + 0x70, 0x72, 0xf5, 0x1e, 0xd2, 0x35, 0xff, 0xef, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xe4, 0xf6, 0x08, //0x8010, + 0xf6, 0x0f, 0xbf, 0x34, 0xf2, 0x90, 0x0e, 0x93, 0xe4, 0x93, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, //0x8020, + 0x04, 0x7f, 0x05, 0x80, 0x02, 0x7f, 0xfb, 0x78, 0xbd, 0xa6, 0x07, 0x12, 0x0f, 0x04, 0x40, 0x04, //0x8030, + 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x30, 0x78, 0xbc, 0xa6, 0x07, 0xe6, 0x18, 0xf6, 0x08, 0xe6, 0x78, //0x8040, + 0xb9, 0xf6, 0x78, 0xbc, 0xe6, 0x78, 0xba, 0xf6, 0x78, 0xbf, 0x76, 0x33, 0xe4, 0x08, 0xf6, 0x78, //0x8050, + 0xb8, 0x76, 0x01, 0x75, 0x4a, 0x02, 0x78, 0xb6, 0xf6, 0x08, 0xf6, 0x74, 0xff, 0x78, 0xc1, 0xf6, //0x8060, + 0x08, 0xf6, 0x75, 0x1f, 0x01, 0x78, 0xbc, 0xe6, 0x75, 0xf0, 0x05, 0xa4, 0xf5, 0x4b, 0x12, 0x0a, //0x8070, + 0xff, 0xc2, 0x37, 0x22, 0x78, 0xb8, 0xe6, 0xd3, 0x94, 0x00, 0x40, 0x02, 0x16, 0x22, 0xe5, 0x1f, //0x8080, + 0xb4, 0x05, 0x23, 0xe4, 0xf5, 0x1f, 0xc2, 0x01, 0x78, 0xb6, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x78, //0x8090, + 0x4e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, 0x90, 0x30, 0x28, 0xf0, //0x80a0, + 0x75, 0x1e, 0x10, 0xd2, 0x35, 0x22, 0xe5, 0x4b, 0x75, 0xf0, 0x05, 0x84, 0x78, 0xbc, 0xf6, 0x90, //0x80b0, + 0x0e, 0x8c, 0xe4, 0x93, 0xff, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x78, //0x80c0, + 0xbc, 0xe6, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x12, 0x0f, 0x0b, //0x80d0, + 0xd3, 0x78, 0xb7, 0x96, 0xee, 0x18, 0x96, 0x40, 0x0d, 0x78, 0xbc, 0xe6, 0x78, 0xb9, 0xf6, 0x78, //0x80e0, + 0xb6, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x8c, 0xe4, 0x93, 0x12, 0x0f, 0x0b, 0xc3, 0x78, //0x80f0, + 0xc2, 0x96, 0xee, 0x18, 0x96, 0x50, 0x0d, 0x78, 0xbc, 0xe6, 0x78, 0xba, 0xf6, 0x78, 0xc1, 0xa6, //0x8100, + 0x06, 0x08, 0xa6, 0x07, 0x78, 0xb6, 0xe6, 0xfe, 0x08, 0xe6, 0xc3, 0x78, 0xc2, 0x96, 0xff, 0xee, //0x8110, + 0x18, 0x96, 0x78, 0xc3, 0xf6, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x95, 0xe4, 0x18, 0x12, 0x0e, 0xe9, //0x8120, + 0x40, 0x02, 0xd2, 0x37, 0x78, 0xbc, 0xe6, 0x08, 0x26, 0x08, 0xf6, 0xe5, 0x1f, 0x64, 0x01, 0x70, //0x8130, + 0x4a, 0xe6, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xdf, 0x40, 0x05, 0x12, 0x0e, 0xda, 0x40, 0x39, 0x12, //0x8140, + 0x0f, 0x02, 0x40, 0x04, 0x7f, 0xfe, 0x80, 0x02, 0x7f, 0x02, 0x78, 0xbd, 0xa6, 0x07, 0x78, 0xb9, //0x8150, + 0xe6, 0x24, 0x03, 0x78, 0xbf, 0xf6, 0x78, 0xb9, 0xe6, 0x24, 0xfd, 0x78, 0xc0, 0xf6, 0x12, 0x0f, //0x8160, + 0x02, 0x40, 0x06, 0x78, 0xc0, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbf, 0xe6, 0xff, 0x78, 0xbe, 0xa6, //0x8170, + 0x07, 0x75, 0x1f, 0x02, 0x78, 0xb8, 0x76, 0x01, 0x02, 0x02, 0x4a, 0xe5, 0x1f, 0x64, 0x02, 0x60, //0x8180, + 0x03, 0x02, 0x02, 0x2a, 0x78, 0xbe, 0xe6, 0xff, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xe0, 0x40, 0x08, //0x8190, + 0x12, 0x0e, 0xda, 0x50, 0x03, 0x02, 0x02, 0x28, 0x12, 0x0f, 0x02, 0x40, 0x04, 0x7f, 0xff, 0x80, //0x81a0, + 0x02, 0x7f, 0x01, 0x78, 0xbd, 0xa6, 0x07, 0x78, 0xb9, 0xe6, 0x04, 0x78, 0xbf, 0xf6, 0x78, 0xb9, //0x81b0, + 0xe6, 0x14, 0x78, 0xc0, 0xf6, 0x18, 0x12, 0x0f, 0x04, 0x40, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, //0x81c0, + 0x00, 0x78, 0xbf, 0xa6, 0x07, 0xd3, 0x08, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0xe6, 0xff, //0x81d0, + 0x80, 0x02, 0x7f, 0x00, 0x78, 0xc0, 0xa6, 0x07, 0xc3, 0x18, 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, //0x81e0, + 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbf, 0xa6, 0x07, 0xc3, 0x08, 0xe6, 0x64, 0x80, //0x81f0, + 0x94, 0xb3, 0x50, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xc0, 0xa6, 0x07, 0x12, 0x0f, //0x8200, + 0x02, 0x40, 0x06, 0x78, 0xc0, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbf, 0xe6, 0xff, 0x78, 0xbe, 0xa6, //0x8210, + 0x07, 0x75, 0x1f, 0x03, 0x78, 0xb8, 0x76, 0x01, 0x80, 0x20, 0xe5, 0x1f, 0x64, 0x03, 0x70, 0x26, //0x8220, + 0x78, 0xbe, 0xe6, 0xff, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xe0, 0x40, 0x05, 0x12, 0x0e, 0xda, 0x40, //0x8230, + 0x09, 0x78, 0xb9, 0xe6, 0x78, 0xbe, 0xf6, 0x75, 0x1f, 0x04, 0x78, 0xbe, 0xe6, 0x75, 0xf0, 0x05, //0x8240, + 0xa4, 0xf5, 0x4b, 0x02, 0x0a, 0xff, 0xe5, 0x1f, 0xb4, 0x04, 0x10, 0x90, 0x0e, 0x94, 0xe4, 0x78, //0x8250, + 0xc3, 0x12, 0x0e, 0xe9, 0x40, 0x02, 0xd2, 0x37, 0x75, 0x1f, 0x05, 0x22, 0x30, 0x01, 0x03, 0x02, //0x8260, + 0x04, 0xc0, 0x30, 0x02, 0x03, 0x02, 0x04, 0xc0, 0x90, 0x51, 0xa5, 0xe0, 0x78, 0x93, 0xf6, 0xa3, //0x8270, + 0xe0, 0x08, 0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xe5, 0x1f, 0x70, 0x3c, 0x75, 0x1e, 0x20, 0xd2, 0x35, //0x8280, + 0x12, 0x0c, 0x7a, 0x78, 0x7e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8b, 0xa6, 0x09, 0x18, 0x76, //0x8290, + 0x01, 0x12, 0x0c, 0x5b, 0x78, 0x4e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8b, 0xe6, 0x78, 0x6e, //0x82a0, + 0xf6, 0x75, 0x1f, 0x01, 0x78, 0x93, 0xe6, 0x78, 0x90, 0xf6, 0x78, 0x94, 0xe6, 0x78, 0x91, 0xf6, //0x82b0, + 0x78, 0x95, 0xe6, 0x78, 0x92, 0xf6, 0x22, 0x79, 0x90, 0xe7, 0xd3, 0x78, 0x93, 0x96, 0x40, 0x05, //0x82c0, + 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0x93, 0xe7, 0x78, 0x90, 0x96, 0xff, 0x78, 0x88, 0x76, //0x82d0, + 0x00, 0x08, 0xa6, 0x07, 0x79, 0x91, 0xe7, 0xd3, 0x78, 0x94, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, //0x82e0, + 0x80, 0x08, 0xc3, 0x79, 0x94, 0xe7, 0x78, 0x91, 0x96, 0xff, 0x12, 0x0c, 0x8e, 0x79, 0x92, 0xe7, //0x82f0, + 0xd3, 0x78, 0x95, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0x95, 0xe7, 0x78, //0x8300, + 0x92, 0x96, 0xff, 0x12, 0x0c, 0x8e, 0x12, 0x0c, 0x5b, 0x78, 0x8a, 0xe6, 0x25, 0xe0, 0x24, 0x4e, //0x8310, + 0xf8, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8a, 0xe6, 0x24, 0x6e, 0xf8, 0xa6, 0x09, 0x78, 0x8a, //0x8320, + 0xe6, 0x24, 0x01, 0xff, 0xe4, 0x33, 0xfe, 0xd3, 0xef, 0x94, 0x0f, 0xee, 0x64, 0x80, 0x94, 0x80, //0x8330, + 0x40, 0x04, 0x7f, 0x00, 0x80, 0x05, 0x78, 0x8a, 0xe6, 0x04, 0xff, 0x78, 0x8a, 0xa6, 0x07, 0xe5, //0x8340, + 0x1f, 0xb4, 0x01, 0x0a, 0xe6, 0x60, 0x03, 0x02, 0x04, 0xc0, 0x75, 0x1f, 0x02, 0x22, 0x12, 0x0c, //0x8350, + 0x7a, 0x78, 0x80, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x12, 0x0c, 0x7a, 0x78, 0x82, 0xa6, 0x06, 0x08, //0x8360, + 0xa6, 0x07, 0x78, 0x6e, 0xe6, 0x78, 0x8c, 0xf6, 0x78, 0x6e, 0xe6, 0x78, 0x8d, 0xf6, 0x7f, 0x01, //0x8370, + 0xef, 0x25, 0xe0, 0x24, 0x4f, 0xf9, 0xc3, 0x78, 0x81, 0xe6, 0x97, 0x18, 0xe6, 0x19, 0x97, 0x50, //0x8380, + 0x0a, 0x12, 0x0c, 0x82, 0x78, 0x80, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x6e, 0x2f, 0xf9, 0x78, //0x8390, + 0x8c, 0xe6, 0xc3, 0x97, 0x50, 0x08, 0x74, 0x6e, 0x2f, 0xf8, 0xe6, 0x78, 0x8c, 0xf6, 0xef, 0x25, //0x83a0, + 0xe0, 0x24, 0x4f, 0xf9, 0xd3, 0x78, 0x83, 0xe6, 0x97, 0x18, 0xe6, 0x19, 0x97, 0x40, 0x0a, 0x12, //0x83b0, + 0x0c, 0x82, 0x78, 0x82, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x6e, 0x2f, 0xf9, 0x78, 0x8d, 0xe6, //0x83c0, + 0xd3, 0x97, 0x40, 0x08, 0x74, 0x6e, 0x2f, 0xf8, 0xe6, 0x78, 0x8d, 0xf6, 0x0f, 0xef, 0x64, 0x10, //0x83d0, + 0x70, 0x9e, 0xc3, 0x79, 0x81, 0xe7, 0x78, 0x83, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0x78, 0x84, //0x83e0, + 0xf6, 0x08, 0xa6, 0x07, 0xc3, 0x79, 0x8c, 0xe7, 0x78, 0x8d, 0x96, 0x08, 0xf6, 0xd3, 0x79, 0x81, //0x83f0, + 0xe7, 0x78, 0x7f, 0x96, 0x19, 0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, //0x8400, + 0x79, 0x7f, 0xe7, 0x78, 0x81, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0xfe, 0x78, 0x86, 0xa6, 0x06, //0x8410, + 0x08, 0xa6, 0x07, 0x79, 0x8c, 0xe7, 0xd3, 0x78, 0x8b, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, //0x8420, + 0x08, 0xc3, 0x79, 0x8b, 0xe7, 0x78, 0x8c, 0x96, 0xff, 0x78, 0x8f, 0xa6, 0x07, 0xe5, 0x1f, 0x64, //0x8430, + 0x02, 0x70, 0x69, 0x90, 0x0e, 0x91, 0x93, 0xff, 0x18, 0xe6, 0xc3, 0x9f, 0x50, 0x72, 0x12, 0x0c, //0x8440, + 0x4a, 0x12, 0x0c, 0x2f, 0x90, 0x0e, 0x8e, 0x12, 0x0c, 0x38, 0x78, 0x80, 0x12, 0x0c, 0x6b, 0x7b, //0x8450, + 0x04, 0x12, 0x0c, 0x1d, 0xc3, 0x12, 0x06, 0x45, 0x50, 0x56, 0x90, 0x0e, 0x92, 0xe4, 0x93, 0xff, //0x8460, + 0x78, 0x8f, 0xe6, 0x9f, 0x40, 0x02, 0x80, 0x11, 0x90, 0x0e, 0x90, 0xe4, 0x93, 0xff, 0xd3, 0x78, //0x8470, + 0x89, 0xe6, 0x9f, 0x18, 0xe6, 0x94, 0x00, 0x40, 0x03, 0x75, 0x1f, 0x05, 0x12, 0x0c, 0x4a, 0x12, //0x8480, + 0x0c, 0x2f, 0x90, 0x0e, 0x8f, 0x12, 0x0c, 0x38, 0x78, 0x7e, 0x12, 0x0c, 0x6b, 0x7b, 0x40, 0x12, //0x8490, + 0x0c, 0x1d, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x18, 0x75, 0x1f, 0x05, 0x22, 0xe5, 0x1f, 0xb4, 0x05, //0x84a0, + 0x0f, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, 0x33, 0xd2, 0x36, //0x84b0, + 0x22, 0xef, 0x8d, 0xf0, 0xa4, 0xa8, 0xf0, 0xcf, 0x8c, 0xf0, 0xa4, 0x28, 0xce, 0x8d, 0xf0, 0xa4, //0x84c0, + 0x2e, 0xfe, 0x22, 0xbc, 0x00, 0x0b, 0xbe, 0x00, 0x29, 0xef, 0x8d, 0xf0, 0x84, 0xff, 0xad, 0xf0, //0x84d0, + 0x22, 0xe4, 0xcc, 0xf8, 0x75, 0xf0, 0x08, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xec, 0x33, 0xfc, //0x84e0, + 0xee, 0x9d, 0xec, 0x98, 0x40, 0x05, 0xfc, 0xee, 0x9d, 0xfe, 0x0f, 0xd5, 0xf0, 0xe9, 0xe4, 0xce, //0x84f0, + 0xfd, 0x22, 0xed, 0xf8, 0xf5, 0xf0, 0xee, 0x84, 0x20, 0xd2, 0x1c, 0xfe, 0xad, 0xf0, 0x75, 0xf0, //0x8500, + 0x08, 0xef, 0x2f, 0xff, 0xed, 0x33, 0xfd, 0x40, 0x07, 0x98, 0x50, 0x06, 0xd5, 0xf0, 0xf2, 0x22, //0x8510, + 0xc3, 0x98, 0xfd, 0x0f, 0xd5, 0xf0, 0xea, 0x22, 0xe8, 0x8f, 0xf0, 0xa4, 0xcc, 0x8b, 0xf0, 0xa4, //0x8520, + 0x2c, 0xfc, 0xe9, 0x8e, 0xf0, 0xa4, 0x2c, 0xfc, 0x8a, 0xf0, 0xed, 0xa4, 0x2c, 0xfc, 0xea, 0x8e, //0x8530, + 0xf0, 0xa4, 0xcd, 0xa8, 0xf0, 0x8b, 0xf0, 0xa4, 0x2d, 0xcc, 0x38, 0x25, 0xf0, 0xfd, 0xe9, 0x8f, //0x8540, + 0xf0, 0xa4, 0x2c, 0xcd, 0x35, 0xf0, 0xfc, 0xeb, 0x8e, 0xf0, 0xa4, 0xfe, 0xa9, 0xf0, 0xeb, 0x8f, //0x8550, + 0xf0, 0xa4, 0xcf, 0xc5, 0xf0, 0x2e, 0xcd, 0x39, 0xfe, 0xe4, 0x3c, 0xfc, 0xea, 0xa4, 0x2d, 0xce, //0x8560, + 0x35, 0xf0, 0xfd, 0xe4, 0x3c, 0xfc, 0x22, 0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, //0x8570, + 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc, 0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, //0x8580, + 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40, 0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, //0x8590, + 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6, 0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, //0x85a0, + 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9, 0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, //0x85b0, + 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb, 0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, //0x85c0, + 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb, 0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, //0x85d0, + 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9, 0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, //0x85e0, + 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, //0x85f0, + 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a, 0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, //0x8600, + 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, //0x8610, + 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07, 0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, //0x8620, + 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8, 0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, //0x8630, + 0xfa, 0xe4, 0xc8, 0xf9, 0x22, 0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, //0x8640, + 0xf0, 0xe8, 0x9c, 0x45, 0xf0, 0x22, 0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, //0x8650, + 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff, 0xd8, 0xf1, 0x22, 0xe8, 0x60, 0x0f, 0xef, 0xc3, 0x33, 0xff, //0x8660, + 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xd8, 0xf1, 0x22, 0xe4, 0x93, 0xfc, 0x74, //0x8670, + 0x01, 0x93, 0xfd, 0x74, 0x02, 0x93, 0xfe, 0x74, 0x03, 0x93, 0xff, 0x22, 0xe6, 0xfb, 0x08, 0xe6, //0x8680, + 0xf9, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xcb, 0xf8, 0x22, 0xec, 0xf6, 0x08, 0xed, 0xf6, 0x08, 0xee, //0x8690, + 0xf6, 0x08, 0xef, 0xf6, 0x22, 0xa4, 0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, //0x86a0, + 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, //0x86b0, + 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, //0x86c0, + 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x38, 0x04, 0x78, 0x52, 0x12, 0x0b, 0xfd, 0x90, //0x86d0, + 0x38, 0x00, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0b, 0x9e, 0x90, 0x38, 0x10, //0x86e0, + 0x12, 0x0b, 0x92, 0x90, 0x38, 0x06, 0x78, 0x54, 0x12, 0x0b, 0xfd, 0x90, 0x38, 0x02, 0xe0, 0xfe, //0x86f0, + 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0b, 0x9e, 0x90, 0x38, 0x12, 0x12, 0x0b, 0x92, 0xa3, //0x8700, + 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x52, 0x79, 0x52, 0x12, 0x0c, 0x13, 0x90, 0x38, 0x14, 0xe0, 0xb4, //0x8710, + 0x71, 0x15, 0x78, 0x52, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, //0x8720, + 0xf9, 0x79, 0x53, 0xf7, 0xee, 0x19, 0xf7, 0x90, 0x38, 0x15, 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x54, //0x8730, + 0x79, 0x54, 0x12, 0x0c, 0x13, 0x90, 0x38, 0x15, 0xe0, 0xb4, 0x71, 0x15, 0x78, 0x54, 0xe6, 0xfe, //0x8740, + 0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x79, 0x55, 0xf7, 0xee, 0x19, //0x8750, + 0xf7, 0x79, 0x52, 0x12, 0x0b, 0xd9, 0x09, 0x12, 0x0b, 0xd9, 0xaf, 0x47, 0x12, 0x0b, 0xb2, 0xe5, //0x8760, + 0x44, 0xfb, 0x7a, 0x00, 0xfd, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x5a, 0xa6, 0x06, 0x08, 0xa6, //0x8770, + 0x07, 0xaf, 0x45, 0x12, 0x0b, 0xb2, 0xad, 0x03, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x56, 0xa6, //0x8780, + 0x06, 0x08, 0xa6, 0x07, 0xaf, 0x48, 0x78, 0x54, 0x12, 0x0b, 0xb4, 0xe5, 0x43, 0xfb, 0xfd, 0x7c, //0x8790, + 0x00, 0x12, 0x04, 0xd3, 0x78, 0x5c, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xaf, 0x46, 0x7e, 0x00, 0x78, //0x87a0, + 0x54, 0x12, 0x0b, 0xb6, 0xad, 0x03, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x58, 0xa6, 0x06, 0x08, //0x87b0, + 0xa6, 0x07, 0xc3, 0x78, 0x5b, 0xe6, 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, //0x87c0, + 0x08, 0x76, 0x08, 0xc3, 0x78, 0x5d, 0xe6, 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, //0x87d0, + 0x00, 0x08, 0x76, 0x08, 0x78, 0x5a, 0x12, 0x0b, 0xc6, 0xff, 0xd3, 0x78, 0x57, 0xe6, 0x9f, 0x18, //0x87e0, + 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5a, 0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x57, 0x12, 0x0c, 0x08, //0x87f0, + 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x78, 0x5e, 0x12, 0x0b, 0xbe, 0xff, 0xd3, 0x78, 0x59, 0xe6, //0x8800, + 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5c, 0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x59, 0x12, //0x8810, + 0x0c, 0x08, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0xe4, 0xfc, 0xfd, 0x78, 0x62, 0x12, 0x06, 0x99, //0x8820, + 0x78, 0x5a, 0x12, 0x0b, 0xc6, 0x78, 0x57, 0x26, 0xff, 0xee, 0x18, 0x36, 0xfe, 0x78, 0x66, 0x12, //0x8830, + 0x0b, 0xbe, 0x78, 0x59, 0x26, 0xff, 0xee, 0x18, 0x36, 0xfe, 0xe4, 0xfc, 0xfd, 0x78, 0x6a, 0x12, //0x8840, + 0x06, 0x99, 0x12, 0x0b, 0xce, 0x78, 0x66, 0x12, 0x06, 0x8c, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x08, //0x8850, + 0x12, 0x0b, 0xce, 0x78, 0x66, 0x12, 0x06, 0x99, 0x78, 0x54, 0x12, 0x0b, 0xd0, 0x78, 0x6a, 0x12, //0x8860, + 0x06, 0x8c, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x0a, 0x78, 0x54, 0x12, 0x0b, 0xd0, 0x78, 0x6a, 0x12, //0x8870, + 0x06, 0x99, 0x78, 0x61, 0xe6, 0x90, 0x60, 0x01, 0xf0, 0x78, 0x65, 0xe6, 0xa3, 0xf0, 0x78, 0x69, //0x8880, + 0xe6, 0xa3, 0xf0, 0x78, 0x55, 0xe6, 0xa3, 0xf0, 0x7d, 0x01, 0x78, 0x61, 0x12, 0x0b, 0xe9, 0x24, //0x8890, + 0x01, 0x12, 0x0b, 0xa6, 0x78, 0x65, 0x12, 0x0b, 0xe9, 0x24, 0x02, 0x12, 0x0b, 0xa6, 0x78, 0x69, //0x88a0, + 0x12, 0x0b, 0xe9, 0x24, 0x03, 0x12, 0x0b, 0xa6, 0x78, 0x6d, 0x12, 0x0b, 0xe9, 0x24, 0x04, 0x12, //0x88b0, + 0x0b, 0xa6, 0x0d, 0xbd, 0x05, 0xd4, 0xc2, 0x0e, 0xc2, 0x06, 0x22, 0x85, 0x08, 0x41, 0x90, 0x30, //0x88c0, + 0x24, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0xf5, 0x3e, 0xa3, 0xe0, 0xf5, 0x3f, 0xa3, 0xe0, 0xf5, 0x40, //0x88d0, + 0xa3, 0xe0, 0xf5, 0x3c, 0xd2, 0x34, 0xe5, 0x41, 0x12, 0x06, 0xb1, 0x09, 0x31, 0x03, 0x09, 0x35, //0x88e0, + 0x04, 0x09, 0x3b, 0x05, 0x09, 0x3e, 0x06, 0x09, 0x41, 0x07, 0x09, 0x4a, 0x08, 0x09, 0x5b, 0x12, //0x88f0, + 0x09, 0x73, 0x18, 0x09, 0x89, 0x19, 0x09, 0x5e, 0x1a, 0x09, 0x6a, 0x1b, 0x09, 0xad, 0x80, 0x09, //0x8900, + 0xb2, 0x81, 0x0a, 0x1d, 0x8f, 0x0a, 0x09, 0x90, 0x0a, 0x1d, 0x91, 0x0a, 0x1d, 0x92, 0x0a, 0x1d, //0x8910, + 0x93, 0x0a, 0x1d, 0x94, 0x0a, 0x1d, 0x98, 0x0a, 0x17, 0x9f, 0x0a, 0x1a, 0xec, 0x00, 0x00, 0x0a, //0x8920, + 0x38, 0x12, 0x0f, 0x74, 0x22, 0x12, 0x0f, 0x74, 0xd2, 0x03, 0x22, 0xd2, 0x03, 0x22, 0xc2, 0x03, //0x8930, + 0x22, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, 0x02, 0x0a, 0x1d, 0xc2, 0x01, 0xc2, 0x02, 0xc2, 0x03, //0x8940, + 0x12, 0x0d, 0x0d, 0x75, 0x1e, 0x70, 0xd2, 0x35, 0x02, 0x0a, 0x1d, 0x02, 0x0a, 0x04, 0x85, 0x40, //0x8950, + 0x4a, 0x85, 0x3c, 0x4b, 0x12, 0x0a, 0xff, 0x02, 0x0a, 0x1d, 0x85, 0x4a, 0x40, 0x85, 0x4b, 0x3c, //0x8960, + 0x02, 0x0a, 0x1d, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x85, 0x40, 0x31, 0x85, 0x3f, 0x30, 0x85, 0x3e, //0x8970, + 0x2f, 0x85, 0x3d, 0x2e, 0x12, 0x0f, 0x46, 0x80, 0x1f, 0x75, 0x22, 0x00, 0x75, 0x23, 0x01, 0x74, //0x8980, + 0xff, 0xf5, 0x2d, 0xf5, 0x2c, 0xf5, 0x2b, 0xf5, 0x2a, 0x12, 0x0f, 0x46, 0x85, 0x2d, 0x40, 0x85, //0x8990, + 0x2c, 0x3f, 0x85, 0x2b, 0x3e, 0x85, 0x2a, 0x3d, 0xe4, 0xf5, 0x3c, 0x80, 0x70, 0x12, 0x0f, 0x16, //0x89a0, + 0x80, 0x6b, 0x85, 0x3d, 0x45, 0x85, 0x3e, 0x46, 0xe5, 0x47, 0xc3, 0x13, 0xff, 0xe5, 0x45, 0xc3, //0x89b0, + 0x9f, 0x50, 0x02, 0x8f, 0x45, 0xe5, 0x48, 0xc3, 0x13, 0xff, 0xe5, 0x46, 0xc3, 0x9f, 0x50, 0x02, //0x89c0, + 0x8f, 0x46, 0xe5, 0x47, 0xc3, 0x13, 0xff, 0xfd, 0xe5, 0x45, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe5, //0x89d0, + 0x44, 0x12, 0x0f, 0x90, 0x40, 0x05, 0xe5, 0x44, 0x9f, 0xf5, 0x45, 0xe5, 0x48, 0xc3, 0x13, 0xff, //0x89e0, + 0xfd, 0xe5, 0x46, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe5, 0x43, 0x12, 0x0f, 0x90, 0x40, 0x05, 0xe5, //0x89f0, + 0x43, 0x9f, 0xf5, 0x46, 0x12, 0x06, 0xd7, 0x80, 0x14, 0x85, 0x40, 0x48, 0x85, 0x3f, 0x47, 0x85, //0x8a00, + 0x3e, 0x46, 0x85, 0x3d, 0x45, 0x80, 0x06, 0x02, 0x06, 0xd7, 0x12, 0x0d, 0x7e, 0x90, 0x30, 0x24, //0x8a10, + 0xe5, 0x3d, 0xf0, 0xa3, 0xe5, 0x3e, 0xf0, 0xa3, 0xe5, 0x3f, 0xf0, 0xa3, 0xe5, 0x40, 0xf0, 0xa3, //0x8a20, + 0xe5, 0x3c, 0xf0, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, //0x8a30, + 0xd0, 0x90, 0x3f, 0x0c, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x30, 0xe3, 0x74, 0x30, 0x36, 0x66, 0x90, //0x8a40, + 0x60, 0x19, 0xe0, 0xf5, 0x0a, 0xa3, 0xe0, 0xf5, 0x0b, 0x90, 0x60, 0x1d, 0xe0, 0xf5, 0x14, 0xa3, //0x8a50, + 0xe0, 0xf5, 0x15, 0x90, 0x60, 0x21, 0xe0, 0xf5, 0x0c, 0xa3, 0xe0, 0xf5, 0x0d, 0x90, 0x60, 0x29, //0x8a60, + 0xe0, 0xf5, 0x0e, 0xa3, 0xe0, 0xf5, 0x0f, 0x90, 0x60, 0x31, 0xe0, 0xf5, 0x10, 0xa3, 0xe0, 0xf5, //0x8a70, + 0x11, 0x90, 0x60, 0x39, 0xe0, 0xf5, 0x12, 0xa3, 0xe0, 0xf5, 0x13, 0x30, 0x01, 0x06, 0x30, 0x33, //0x8a80, + 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x09, 0x30, 0x02, 0x06, 0x30, 0x33, 0x03, 0xd3, 0x80, 0x01, //0x8a90, + 0xc3, 0x92, 0x0a, 0x30, 0x33, 0x0c, 0x30, 0x03, 0x09, 0x20, 0x02, 0x06, 0x20, 0x01, 0x03, 0xd3, //0x8aa0, + 0x80, 0x01, 0xc3, 0x92, 0x0b, 0x90, 0x30, 0x01, 0xe0, 0x44, 0x40, 0xf0, 0xe0, 0x54, 0xbf, 0xf0, //0x8ab0, + 0xe5, 0x32, 0x30, 0xe1, 0x14, 0x30, 0x34, 0x11, 0x90, 0x30, 0x22, 0xe0, 0xf5, 0x08, 0xe4, 0xf0, //0x8ac0, + 0x30, 0x00, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x08, 0xe5, 0x32, 0x30, 0xe5, 0x12, 0x90, 0x56, //0x8ad0, + 0xa1, 0xe0, 0xf5, 0x09, 0x30, 0x31, 0x09, 0x30, 0x05, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0d, //0x8ae0, + 0x90, 0x3f, 0x0c, 0xe5, 0x32, 0xf0, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, //0x8af0, + 0x0e, 0x7e, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xff, 0xc3, 0x90, 0x0e, 0x7c, 0x74, 0x01, 0x93, //0x8b00, + 0x9f, 0xff, 0xe4, 0x93, 0x9e, 0xfe, 0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0xab, //0x8b10, + 0x3b, 0xaa, 0x3a, 0xa9, 0x39, 0xa8, 0x38, 0xaf, 0x4b, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0x28, 0x12, //0x8b20, + 0x0d, 0xe1, 0xe4, 0x7b, 0xff, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0xb3, 0x12, 0x0d, 0xe1, 0x90, 0x0e, //0x8b30, + 0x69, 0xe4, 0x12, 0x0d, 0xf6, 0x12, 0x0d, 0xe1, 0xe4, 0x85, 0x4a, 0x37, 0xf5, 0x36, 0xf5, 0x35, //0x8b40, + 0xf5, 0x34, 0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0xa3, 0x12, 0x0d, 0xf6, 0x8f, 0x37, //0x8b50, + 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0xe5, 0x3b, 0x45, 0x37, 0xf5, 0x3b, 0xe5, 0x3a, 0x45, 0x36, //0x8b60, + 0xf5, 0x3a, 0xe5, 0x39, 0x45, 0x35, 0xf5, 0x39, 0xe5, 0x38, 0x45, 0x34, 0xf5, 0x38, 0xe4, 0xf5, //0x8b70, + 0x22, 0xf5, 0x23, 0x85, 0x3b, 0x31, 0x85, 0x3a, 0x30, 0x85, 0x39, 0x2f, 0x85, 0x38, 0x2e, 0x02, //0x8b80, + 0x0f, 0x46, 0xe0, 0xa3, 0xe0, 0x75, 0xf0, 0x02, 0xa4, 0xff, 0xae, 0xf0, 0xc3, 0x08, 0xe6, 0x9f, //0x8b90, + 0xf6, 0x18, 0xe6, 0x9e, 0xf6, 0x22, 0xff, 0xe5, 0xf0, 0x34, 0x60, 0x8f, 0x82, 0xf5, 0x83, 0xec, //0x8ba0, + 0xf0, 0x22, 0x78, 0x52, 0x7e, 0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x02, 0x04, 0xc1, 0xe4, 0xfc, //0x8bb0, + 0xfd, 0x12, 0x06, 0x99, 0x78, 0x5c, 0xe6, 0xc3, 0x13, 0xfe, 0x08, 0xe6, 0x13, 0x22, 0x78, 0x52, //0x8bc0, + 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0xfc, 0xfd, 0x22, 0xe7, 0xc4, 0xf8, 0x54, 0xf0, 0xc8, 0x68, //0x8bd0, + 0xf7, 0x09, 0xe7, 0xc4, 0x54, 0x0f, 0x48, 0xf7, 0x22, 0xe6, 0xfc, 0xed, 0x75, 0xf0, 0x04, 0xa4, //0x8be0, + 0x22, 0x12, 0x06, 0x7c, 0x8f, 0x48, 0x8e, 0x47, 0x8d, 0x46, 0x8c, 0x45, 0x22, 0xe0, 0xfe, 0xa3, //0x8bf0, + 0xe0, 0xfd, 0xee, 0xf6, 0xed, 0x08, 0xf6, 0x22, 0x13, 0xff, 0xc3, 0xe6, 0x9f, 0xff, 0x18, 0xe6, //0x8c00, + 0x9e, 0xfe, 0x22, 0xe6, 0xc3, 0x13, 0xf7, 0x08, 0xe6, 0x13, 0x09, 0xf7, 0x22, 0xad, 0x39, 0xac, //0x8c10, + 0x38, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0x28, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39, 0x8c, 0x38, 0xab, //0x8c20, + 0x37, 0xaa, 0x36, 0xa9, 0x35, 0xa8, 0x34, 0x22, 0x93, 0xff, 0xe4, 0xfc, 0xfd, 0xfe, 0x12, 0x05, //0x8c30, + 0x28, 0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x22, 0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, //0x8c40, + 0xff, 0xe4, 0x8f, 0x37, 0x8e, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0x22, 0x90, 0x0e, 0x8c, 0xe4, 0x93, //0x8c50, + 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, //0x8c60, + 0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0x22, 0x78, 0x4e, 0xe6, 0xfe, 0x08, 0xe6, //0x8c70, + 0xff, 0x22, 0xef, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x22, 0x78, 0x89, //0x8c80, + 0xef, 0x26, 0xf6, 0x18, 0xe4, 0x36, 0xf6, 0x22, 0x75, 0x89, 0x03, 0x75, 0xa8, 0x01, 0x75, 0xb8, //0x8c90, + 0x04, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x15, 0x75, 0x37, 0x0d, 0x12, 0x0e, 0x9a, //0x8ca0, + 0x12, 0x00, 0x09, 0x12, 0x0f, 0x16, 0x12, 0x00, 0x06, 0xd2, 0x00, 0xd2, 0x34, 0xd2, 0xaf, 0x75, //0x8cb0, + 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x49, 0x75, 0x37, 0x03, 0x12, 0x0e, 0x9a, 0x30, 0x08, //0x8cc0, + 0x09, 0xc2, 0x34, 0x12, 0x08, 0xcb, 0xc2, 0x08, 0xd2, 0x34, 0x30, 0x0b, 0x09, 0xc2, 0x36, 0x12, //0x8cd0, + 0x02, 0x6c, 0xc2, 0x0b, 0xd2, 0x36, 0x30, 0x09, 0x09, 0xc2, 0x36, 0x12, 0x00, 0x0e, 0xc2, 0x09, //0x8ce0, + 0xd2, 0x36, 0x30, 0x0e, 0x03, 0x12, 0x06, 0xd7, 0x30, 0x35, 0xd3, 0x90, 0x30, 0x29, 0xe5, 0x1e, //0x8cf0, + 0xf0, 0xb4, 0x10, 0x05, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0xc2, 0x35, 0x80, 0xc1, 0xe4, 0xf5, 0x4b, //0x8d00, + 0x90, 0x0e, 0x7a, 0x93, 0xff, 0xe4, 0x8f, 0x37, 0xf5, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0xaf, 0x37, //0x8d10, + 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0x90, 0x0e, 0x6a, 0x12, 0x0d, 0xf6, 0x8f, 0x37, 0x8e, 0x36, //0x8d20, + 0x8d, 0x35, 0x8c, 0x34, 0x90, 0x0e, 0x72, 0x12, 0x06, 0x7c, 0xef, 0x45, 0x37, 0xf5, 0x37, 0xee, //0x8d30, + 0x45, 0x36, 0xf5, 0x36, 0xed, 0x45, 0x35, 0xf5, 0x35, 0xec, 0x45, 0x34, 0xf5, 0x34, 0xe4, 0xf5, //0x8d40, + 0x22, 0xf5, 0x23, 0x85, 0x37, 0x31, 0x85, 0x36, 0x30, 0x85, 0x35, 0x2f, 0x85, 0x34, 0x2e, 0x12, //0x8d50, + 0x0f, 0x46, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x72, 0x12, 0x0d, 0xea, 0x12, 0x0f, 0x46, //0x8d60, + 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x6e, 0x12, 0x0d, 0xea, 0x02, 0x0f, 0x46, 0xe5, 0x40, //0x8d70, + 0x24, 0xf2, 0xf5, 0x37, 0xe5, 0x3f, 0x34, 0x43, 0xf5, 0x36, 0xe5, 0x3e, 0x34, 0xa2, 0xf5, 0x35, //0x8d80, + 0xe5, 0x3d, 0x34, 0x28, 0xf5, 0x34, 0xe5, 0x37, 0xff, 0xe4, 0xfe, 0xfd, 0xfc, 0x78, 0x18, 0x12, //0x8d90, + 0x06, 0x69, 0x8f, 0x40, 0x8e, 0x3f, 0x8d, 0x3e, 0x8c, 0x3d, 0xe5, 0x37, 0x54, 0xa0, 0xff, 0xe5, //0x8da0, + 0x36, 0xfe, 0xe4, 0xfd, 0xfc, 0x78, 0x07, 0x12, 0x06, 0x56, 0x78, 0x10, 0x12, 0x0f, 0x9a, 0xe4, //0x8db0, + 0xff, 0xfe, 0xe5, 0x35, 0xfd, 0xe4, 0xfc, 0x78, 0x0e, 0x12, 0x06, 0x56, 0x12, 0x0f, 0x9d, 0xe4, //0x8dc0, + 0xff, 0xfe, 0xfd, 0xe5, 0x34, 0xfc, 0x78, 0x18, 0x12, 0x06, 0x56, 0x78, 0x08, 0x12, 0x0f, 0x9a, //0x8dd0, + 0x22, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39, 0x8c, 0x38, 0x22, 0x12, 0x06, 0x7c, 0x8f, 0x31, 0x8e, //0x8de0, + 0x30, 0x8d, 0x2f, 0x8c, 0x2e, 0x22, 0x93, 0xf9, 0xf8, 0x02, 0x06, 0x69, 0x00, 0x00, 0x00, 0x00, //0x8df0, + 0x12, 0x01, 0x17, 0x08, 0x31, 0x15, 0x53, 0x54, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20, 0x13, 0x01, //0x8e00, + 0x10, 0x01, 0x56, 0x40, 0x1a, 0x30, 0x29, 0x7e, 0x00, 0x30, 0x04, 0x20, 0xdf, 0x30, 0x05, 0x40, //0x8e10, + 0xbf, 0x50, 0x03, 0x00, 0xfd, 0x50, 0x27, 0x01, 0xfe, 0x60, 0x00, 0x11, 0x00, 0x3f, 0x05, 0x30, //0x8e20, + 0x00, 0x3f, 0x06, 0x22, 0x00, 0x3f, 0x01, 0x2a, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x36, 0x06, 0x07, //0x8e30, + 0x00, 0x3f, 0x0b, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x40, 0xbf, 0x30, 0x01, 0x00, //0x8e40, + 0xbf, 0x30, 0x29, 0x70, 0x00, 0x3a, 0x00, 0x00, 0xff, 0x3a, 0x00, 0x00, 0xff, 0x36, 0x03, 0x36, //0x8e50, + 0x02, 0x41, 0x44, 0x58, 0x20, 0x18, 0x10, 0x0a, 0x04, 0x04, 0x00, 0x03, 0xff, 0x64, 0x00, 0x00, //0x8e60, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x06, 0x00, 0x03, 0x51, 0x00, 0x7a, //0x8e70, + 0x50, 0x3c, 0x28, 0x1e, 0x10, 0x10, 0x50, 0x2d, 0x28, 0x16, 0x10, 0x10, 0x02, 0x00, 0x10, 0x0c, //0x8e80, + 0x10, 0x04, 0x0c, 0x6e, 0x06, 0x05, 0x00, 0xa5, 0x5a, 0x00, 0xae, 0x35, 0xaf, 0x36, 0xe4, 0xfd, //0x8e90, + 0xed, 0xc3, 0x95, 0x37, 0x50, 0x33, 0x12, 0x0f, 0xe2, 0xe4, 0x93, 0xf5, 0x38, 0x74, 0x01, 0x93, //0x8ea0, + 0xf5, 0x39, 0x45, 0x38, 0x60, 0x23, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xe0, 0xfc, 0x12, 0x0f, //0x8eb0, + 0xe2, 0x74, 0x03, 0x93, 0x52, 0x04, 0x12, 0x0f, 0xe2, 0x74, 0x02, 0x93, 0x42, 0x04, 0x85, 0x39, //0x8ec0, + 0x82, 0x85, 0x38, 0x83, 0xec, 0xf0, 0x0d, 0x80, 0xc7, 0x22, 0x78, 0xbe, 0xe6, 0xd3, 0x08, 0xff, //0x8ed0, + 0xe6, 0x64, 0x80, 0xf8, 0xef, 0x64, 0x80, 0x98, 0x22, 0x93, 0xff, 0x7e, 0x00, 0xe6, 0xfc, 0x08, //0x8ee0, + 0xe6, 0xfd, 0x12, 0x04, 0xc1, 0x78, 0xc1, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0xd3, 0xef, 0x9d, 0xee, //0x8ef0, + 0x9c, 0x22, 0x78, 0xbd, 0xd3, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x22, 0x25, 0xe0, 0x24, 0x0a, 0xf8, //0x8f00, + 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xe5, 0x3c, 0xd3, 0x94, 0x00, 0x40, 0x0b, 0x90, 0x0e, 0x88, //0x8f10, + 0x12, 0x0b, 0xf1, 0x90, 0x0e, 0x86, 0x80, 0x09, 0x90, 0x0e, 0x82, 0x12, 0x0b, 0xf1, 0x90, 0x0e, //0x8f20, + 0x80, 0xe4, 0x93, 0xf5, 0x44, 0xa3, 0xe4, 0x93, 0xf5, 0x43, 0xd2, 0x06, 0x30, 0x06, 0x03, 0xd3, //0x8f30, + 0x80, 0x01, 0xc3, 0x92, 0x0e, 0x22, 0xa2, 0xaf, 0x92, 0x32, 0xc2, 0xaf, 0xe5, 0x23, 0x45, 0x22, //0x8f40, + 0x90, 0x0e, 0x5d, 0x60, 0x0e, 0x12, 0x0f, 0xcb, 0xe0, 0xf5, 0x2c, 0x12, 0x0f, 0xc8, 0xe0, 0xf5, //0x8f50, + 0x2d, 0x80, 0x0c, 0x12, 0x0f, 0xcb, 0xe5, 0x30, 0xf0, 0x12, 0x0f, 0xc8, 0xe5, 0x31, 0xf0, 0xa2, //0x8f60, + 0x32, 0x92, 0xaf, 0x22, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, //0x8f70, + 0x33, 0xd2, 0x36, 0xd2, 0x01, 0xc2, 0x02, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, 0x33, 0x22, //0x8f80, + 0xfb, 0xd3, 0xed, 0x9b, 0x74, 0x80, 0xf8, 0x6c, 0x98, 0x22, 0x12, 0x06, 0x69, 0xe5, 0x40, 0x2f, //0x8f90, + 0xf5, 0x40, 0xe5, 0x3f, 0x3e, 0xf5, 0x3f, 0xe5, 0x3e, 0x3d, 0xf5, 0x3e, 0xe5, 0x3d, 0x3c, 0xf5, //0x8fa0, + 0x3d, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x3f, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x33, //0x8fb0, + 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x0e, 0x5f, 0xe4, 0x93, 0xfe, 0x74, 0x01, //0x8fc0, + 0x93, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0xcd, 0x02, //0x8fd0, + 0x0c, 0x98, 0x8f, 0x82, 0x8e, 0x83, 0x75, 0xf0, 0x04, 0xed, 0x02, 0x06, 0xa5, //0x8fe0 +}; + #endif + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640cfg.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640cfg.h new file mode 100755 index 0000000..4673d71 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ov5640cfg.h @@ -0,0 +1,749 @@ +#ifndef _OV5640CFG_H +#define _OV5640CFG_H +#include "ov5640.h" + + +const uint16_t OV5640_jpeg_reg_tbl[][2]= +{ + {0x4300, 0x30}, // YUV 422, YUYV + {0x501f, 0x00}, // YUV 422 + // Input clock = 24Mhz + {0x3035, 0x21}, // PLL + {0x3036, 0x69}, // PLL + {0x3c07, 0x07}, // lightmeter 1 threshold[7:0] + {0x3820, 0x46}, // flip + {0x3821, 0x20}, // mirror + {0x3814, 0x11}, // timing X inc + {0x3815, 0x11}, // timing Y inc + {0x3800, 0x00}, // HS + {0x3801, 0x00}, // HS + {0x3802, 0x00}, // VS + {0x3803, 0x00}, // VS + {0x3804, 0x0a}, // HW (HE) + {0x3805, 0x3f}, // HW (HE) + {0x3806, 0x07}, // VH (VE) + {0x3807, 0x9f}, // VH (VE) + + {0x3808, 0x02}, // DVPHO + {0x3809, 0x80}, // DVPHO + {0x380a, 0x01}, // DVPVO + {0x380b, 0xe0}, // DVPVO + + {0x380c, 0x0b}, // HTS // + {0x380d, 0x1c}, // HTS + {0x380e, 0x07}, // VTS // + {0x380f, 0xb0}, // VTS + {0x3813, 0x04}, // timing V offset 04 + {0x3618, 0x04}, + {0x3612, 0x2b}, + {0x3709, 0x12}, + {0x370c, 0x00}, + + {0x3a02, 0x02}, // 60Hz max exposure + {0x3a03, 0xe0}, // 60Hz max exposure + {0x3a14, 0x02}, // 50Hz max exposure + {0x3a15, 0xe0}, // 50Hz max exposure + + {0x4004, 0x06}, // BLC line number + {0x3002, 0x00}, // enable JFIFO, SFIFO, JPG + {0x3006, 0xff}, // enable clock of JPEG2x, JPEG + {0x4713, 0x03}, // JPEG mode 3 + {0x4407, 0x01}, // Quantization sacle + {0x460b, 0x35}, + {0x460c, 0x22}, + {0x4837, 0x16}, // MIPI global timing + {0x3824, 0x02}, // PCLK manual divider + {0x5001, 0xA3}, // SDE on, Scaling on, CMX on, AWB on + {0x3503, 0x00} // AEC/AGC on +}; + + +const uint16_t ov5640_rgb565_reg_tbl[][2]= +{ + {0x4300, 0x61}, + {0X501F, 0x01}, + // 1280x800,} 15fps + // input clo}ck 24Mhz, PCLK 42Mhz + {0x3035, 0x11},//0x41, // PLL + {0x3036, 0x69}, // PLL + {0x3c07, 0x07}, // lightmeter 1 threshold[7:0] + {0x3820, 0x46}, // flip + {0x3821, 0x00}, // mirror + {0x3814, 0x31}, // timing X inc + {0x3815, 0x31}, // timing Y inc + {0x3800, 0x00}, // HS + {0x3801, 0x00}, // HS + {0x3802, 0x00}, // VS + {0x3803, 0x00}, // VS + {0x3804, 0x0a}, // HW (HE) + {0x3805, 0x3f}, // HW (HE) + {0x3806, 0x06}, // VH (VE) + {0x3807, 0xa9}, // VH (VE) +// {0x3808, 0x05}, // DVPHO +// {0x3809, 0x00}, // DVPHO +// {0x380a, 0x02}, // DVPVO +// {0x380b, 0xd0}, // DVPVO + + {0x3808, (320 >> 8)}, // DVPHO + {0x3809, (320 & 0xff)}, // DVPHO + {0x380a, (240 >> 8)}, // DVPVO + {0x380b, (240 & 0xff)}, // DVPVO + + {0x380c, 0x05}, // HTS + {0x380d, 0xF8}, // HTS + {0x380e, 0x03}, // VTS + {0x380f, 0x84}, // VTS + + {0x3810, (4 >> 8)}, // HTS + {0x3811, (4 & 0xff)}, // HTS + {0x3812, (0 >> 8)}, // VTS + {0x3813, (0 & 0xff)}, // VTS + + + +// {0x3813, 0x04, // timing V offset + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x3a02, 0x02}, // 60Hz max exposure + {0x3a03, 0xe0}, // 60Hz max exposure + + {0x3a14, 0x02}, // 50Hz max exposure + {0x3a15, 0xe0}, // 50Hz max exposure + {0x4004, 0x02}, // BLC line number + {0x3002, 0x1c}, // reset JFIFO, SFIFO, JPG + {0x3006, 0xc3}, // disable clock of JPEG2x, JPEG + {0x4713, 0x03}, // JPEG mode 3 + {0x4407, 0x04}, // Quantization scale + {0x460b, 0x37}, + {0x460c, 0x20}, + {0x4837, 0x16}, // MIPI global timing + {0x3824, 0x04}, // PCLK manual divider + {0x5001, 0xA3}, // SDE on, scale on, UV average off, color matrix on, AWB on + {0x3503, 0x00} // AEC/AGC on +}; + +#if 1 +const uint16_t ov5640_init_reg_tbl[][2]= +{ + // 24MHz input clock, 24MHz PCLK + {0x3008, 0x42}, // software power down, bit[6] + {0x3103, 0x03}, // system clock from PLL, bit[1] + {0x3017, 0xff}, // FREX, Vsync, HREF, PCLK, D[9:6] output enable + {0x3018, 0xff}, // D[5:0], GPIO[1:0] output enable + {0x3034, 0x1a}, // MIPI 10-bit + + {0x3035, 0x41},//0x41, // PLL + {0x3036, 0x40}, // PLL + + {0x3037, 0x13},//0x13, // PLL root divider, bit[4], PLL pre-divider, bit[3:0] + {0x3108, 0x01}, // PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] + + // SCLK root} divider, bit[1:0] + {0x3630, 0x36}, + {0x3631, 0x0e}, + {0x3632, 0xe2}, + {0x3633, 0x12}, + {0x3621, 0xe0}, + {0x3704, 0xa0}, + {0x3703, 0x5a}, + {0x3715, 0x78}, + {0x3717, 0x01}, + {0x370b, 0x60}, + {0x3705, 0x1a}, + {0x3905, 0x02}, + {0x3906, 0x10}, + {0x3901, 0x0a}, + {0x3731, 0x12}, + {0x3600, 0x08}, // VCM control + {0x3601, 0x33}, // VCM control + {0x302d, 0x60}, // system control + {0x3620, 0x52}, + {0x371b, 0x20}, + {0x471c, 0x50}, + {0x3a13, 0x43}, // pre-gain = 1.047x + {0x3a18, 0x00}, // gain ceiling + {0x3a19, 0xf8}, // gain ceiling = 15.5x + {0x3635, 0x13}, + {0x3636, 0x03}, + {0x3634, 0x40}, + {0x3622, 0x01}, + // 50/60Hz d}etection 50/60Hz + {0x3c01, 0x34}, // Band auto, bit[7] + {0x3c04, 0x28}, // threshold low sum + {0x3c05, 0x98}, // threshold high sum + {0x3c06, 0x00}, // light meter 1 threshold[15:8] + {0x3c07, 0x07}, // light meter 1 threshold[7:0] + + {0x3c08, 0x00}, // light meter 2 threshold[15:8] + {0x3c09, 0x1c}, // light meter 2 threshold[7:0] + {0x3c0a, 0x9c}, // sample number[15:8] + {0x3c0b, 0x40}, // sample number[7:0] + {0x3810, 0x00}, // Timing Hoffset[11:8] + {0x3811, 0x10}, // Timing Hoffset[7:0] + {0x3812, 0x00}, // Timing Voffset[10:8] + {0x3708, 0x64}, + {0x4001, 0x02}, // BLC start from line 2 + {0x4005, 0x1a}, // BLC always update + {0x3000, 0x00}, // enable blocks + {0x3004, 0xff}, // enable clocks + {0x300e, 0x58}, // MIPI power down, DVP enable + {0x302e, 0x00}, +#if 1 //RGB565 + {0x4300, 0x61}, + {0X501F, 0x01}, +#else //YUV422 + {0x4300, 0x32}, + {0X501F, 0x00}, +#endif + + {0x3820, 0x46}, // flip + {0x3821, 0x00}, // mirror + +#if 0 + + {0x3800, 0x00}, // HS + {0x3801, 0x00}, // HS + {0x3802, 0x00}, // VS + {0x3803, 0x00}, // VS + + {0x3804, 0x0a}, // HW (HE) + {0x3805, 0x3f}, // HW (HE) + {0x3806, 0x07}, // VH (VE) + {0x3807, 0x9F}, // VH (VE) + + {0x3814, 0x11}, // timing X inc + {0x3815, 0x11}, // timing Y inc + + {0x3808, (1600 >> 8)}, // DVPHO + {0x3809, (1600& 0xff)}, // DVPHO + {0x380a, (1200 >> 8)}, // DVPVO + {0x380b, (1200 & 0xff}), // DVPVO + {0x380c, (0x0b)}, // HTS + {0x380d, (0x1c)}, // HTS + {0x380e, (0x07)}, // VTS + {0x380f, (0xb0)}, // VTS + + + {0x3810, 0x00}, // HTS + {0x3811, 0x80}, // HTS + {0x3812, 0x00}, // VTS + {0x3813, 0x10}, // VTS +#else + {0x3800, 0x00}, // HS + {0x3801, 0x00}, // HS + {0x3802, 0x00}, // VS + {0x3803, 0x00}, // VS + + {0x3804, 0x0a}, // HW (HE) + {0x3805, 0x3f}, // HW (HE) + {0x3806, 0x06}, // VH (VE) + {0x3807, 0xa9}, // VH (VE) + + {0x3814, 0x31}, // timing X inc + {0x3815, 0x31}, // timing Y inc + + {0x3808, (320 >> 8)}, // DVPHO + {0x3809, (320 & 0xff)}, // DVPHO + {0x380a, (240 >> 8)}, // DVPVO + {0x380b, (240 & 0xff)}, // DVPVO + + {0x380c, 0x05}, // HTS + {0x380d, 0xF8}, // HTS + {0x380e, 0x03}, // VTS + {0x380f, 0x84}, // VTS + + {0x3810, 0x00}, // HTS + {0x3811, 0x00}, // HTS + {0x3812, 0x00}, // VTS + {0x3813, 0x00}, // VTS +#endif + + + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x3a02, 0x02}, // 60Hz max exposure + {0x3a03, 0xe0}, // 60Hz max exposure + {0x3a14, 0x02}, // 50Hz max exposure + {0x3a15, 0xe0}, // 50Hz max exposure + + {0x4004, 0x02}, // BLC line number + {0x3002, 0x1c}, // reset JFIFO, SFIFO, JPG + {0x3006, 0xc3}, // disable clock of JPEG2x, JPEG + {0x4713, 0x03}, // JPEG mode 3 + {0x4407, 0x04}, // Quantization scale + {0x460b, 0x37}, + {0x460c, 0x20}, + {0x4837, 0x16}, // MIPI global timing + {0x3824, 0x04}, // PCLK manual divider + {0x5001, 0xA3}, // SDE on, scale on, UV average off, color matrix on, AWB on + {0x3503, 0x00}, // AEC/AGC on + + + {0x440e, 0x00}, + {0x5000, 0xa7}, // Lenc on, raw gamma on, BPC on, WPC on, CIP on + // AEC targe}t + {0x3a0f, 0x30}, // stable range in high + {0x3a10, 0x28}, // stable range in low + {0x3a1b, 0x30}, // stable range out high + {0x3a1e, 0x26}, // stable range out low + {0x3a11, 0x60}, // fast zone high + {0x3a1f, 0x14}, // fast zone low + // Lens corr}ection for ? + {0x5800, 0x23}, + {0x5801, 0x14}, + {0x5802, 0x0f}, + {0x5803, 0x0f}, + {0x5804, 0x12}, + {0x5805, 0x26}, + {0x5806, 0x0c}, + {0x5807, 0x08}, + {0x5808, 0x05}, + {0x5809, 0x05}, + {0x580a, 0x08}, + + {0x580b, 0x0d}, + {0x580c, 0x08}, + {0x580d, 0x03}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x03}, + {0x5811, 0x09}, + {0x5812, 0x07}, + {0x5813, 0x03}, + {0x5814, 0x00}, + {0x5815, 0x01}, + {0x5816, 0x03}, + {0x5817, 0x08}, + {0x5818, 0x0d}, + {0x5819, 0x08}, + {0x581a, 0x05}, + {0x581b, 0x06}, + {0x581c, 0x08}, + {0x581d, 0x0e}, + {0x581e, 0x29}, + {0x581f, 0x17}, + {0x5820, 0x11}, + {0x5821, 0x11}, + {0x5822, 0x15}, + {0x5823, 0x28}, + {0x5824, 0x46}, + {0x5825, 0x26}, + {0x5826, 0x08}, + {0x5827, 0x26}, + {0x5828, 0x64}, + {0x5829, 0x26}, + {0x582a, 0x24}, + {0x582b, 0x22}, + {0x582c, 0x24}, + {0x582d, 0x24}, + {0x582e, 0x06}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x42}, + {0x5832, 0x24}, + {0x5833, 0x26}, + {0x5834, 0x24}, + {0x5835, 0x22}, + {0x5836, 0x22}, + {0x5837, 0x26}, + {0x5838, 0x44}, + {0x5839, 0x24}, + {0x583a, 0x26}, + {0x583b, 0x28}, + {0x583c, 0x42}, + {0x583d, 0xce}, // lenc BR offset + // AWB } + {0x5180, 0xff}, // AWB B block + {0x5181, 0xf2}, // AWB control + {0x5182, 0x00}, // [7:4] max local counter, [3:0] max fast counter + {0x5183, 0x14}, // AWB advanced + {0x5184, 0x25}, + {0x5185, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x75}, + {0x518a, 0x54}, + {0x518b, 0xe0}, + {0x518c, 0xb2}, + {0x518d, 0x42}, + {0x518e, 0x3d}, + {0x518f, 0x56}, + {0x5190, 0x46}, + {0x5191, 0xf8}, // AWB top limit + {0x5192, 0x04}, // AWB bottom limit + {0x5193, 0x70}, // red limit + {0x5194, 0xf0}, // green limit + {0x5195, 0xf0}, // blue limit + {0x5196, 0x03}, // AWB control + {0x5197, 0x01}, // local limit + {0x5198, 0x04}, + {0x5199, 0x12}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x06}, + {0x519d, 0x82}, + {0x519e, 0x38}, // AWB control + // Gamma } + {0x5480, 0x01}, // Gamma bias plus on, bit[0] + {0x5481, 0x08}, + {0x5482, 0x14}, + {0x5483, 0x28}, + {0x5484, 0x51}, + {0x5485, 0x65}, + {0x5486, 0x71}, + {0x5487, 0x7d}, + {0x5488, 0x87}, + {0x5489, 0x91}, + {0x548a, 0x9a}, + {0x548b, 0xaa}, + {0x548c, 0xb8}, + {0x548d, 0xcd}, + {0x548e, 0xdd}, + {0x548f, 0xea}, + {0x5490, 0x1d}, + // color mat}rix + {0x5381, 0x1e}, // CMX1 for Y + {0x5382, 0x5b}, // CMX2 for Y + {0x5383, 0x08}, // CMX3 for Y + {0x5384, 0x0a}, // CMX4 for U + {0x5385, 0x7e}, // CMX5 for U + {0x5386, 0x88}, // CMX6 for U + {0x5387, 0x7c}, // CMX7 for V + {0x5388, 0x6c}, // CMX8 for V + {0x5389, 0x10}, // CMX9 for V + {0x538a, 0x01}, // sign[9] + {0x538b, 0x98}, // sign[8:1] + // UV adjust} UV + {0x5580, 0x06}, // saturation on, bit[1] + {0x5583, 0x40}, + {0x5584, 0x10}, + {0x5589, 0x10}, + {0x558a, 0x00}, + {0x558b, 0xf8}, + {0x501d, 0x40}, // enable manual offset of contrast + // CIP } + {0x5300, 0x08}, // CIP sharpen MT threshold 1 + {0x5301, 0x30}, // CIP sharpen MT threshold 2 + {0x5302, 0x10}, // CIP sharpen MT offset 1 + {0x5303, 0x00}, // CIP sharpen MT offset 2 + {0x5304, 0x08}, // CIP DNS threshold 1 + {0x5305, 0x30}, // CIP DNS threshold 2 + {0x5306, 0x08}, // CIP DNS offset 1 + {0x5307, 0x16}, // CIP DNS offset 2 + {0x5309, 0x08}, // CIP sharpen TH threshold 1 + {0x530a, 0x30}, // CIP sharpen TH threshold 2 + {0x530b, 0x04}, // CIP sharpen TH offset 1 + {0x530c, 0x06}, // CIP sharpen TH offset 2 + {0x5025, 0x00}, + {0x3008, 0x02}, // wake up from standby, bit[6] + + {0x4740, 0X21} //VSYNC active HIGH +}; +#else +const uint16_t ov5640_init_reg_tbl[][2]= +{ + // 24MHz input clock, 24MHz PCLK + {0x3008, 0x42}, // software power down, bit[6] + {0x3103, 0x03}, // system clock from PLL, bit[1] + {0x3017, 0xff}, // FREX, Vsync, HREF, PCLK, D[9:6] output enable + {0x3018, 0xff}, // D[5:0], GPIO[1:0] output enable + {0x3034, 0x1a}, // MIPI 10-bit + + {0x3035, 0x31},//0x41, // PLL + {0x3036, 0x69}, // PLL + + {0x3037, 0x13},//0x13, // PLL root divider, bit[4], PLL pre-divider, bit[3:0] + {0x3108, 0x01}, // PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] + + // SCLK root} divider, bit[1:0] + {0x3630, 0x36}, + {0x3631, 0x0e}, + {0x3632, 0xe2}, + {0x3633, 0x12}, + {0x3621, 0xe0}, + {0x3704, 0xa0}, + {0x3703, 0x5a}, + {0x3715, 0x78}, + {0x3717, 0x01}, + {0x370b, 0x60}, + {0x3705, 0x1a}, + {0x3905, 0x02}, + {0x3906, 0x10}, + {0x3901, 0x0a}, + {0x3731, 0x12}, + {0x3600, 0x08}, // VCM control + {0x3601, 0x33}, // VCM control + {0x302d, 0x60}, // system control + {0x3620, 0x52}, + {0x371b, 0x20}, + {0x471c, 0x50}, + {0x3a13, 0x43}, // pre-gain = 1.047x + {0x3a18, 0x00}, // gain ceiling + {0x3a19, 0xf8}, // gain ceiling = 15.5x + {0x3635, 0x13}, + {0x3636, 0x03}, + {0x3634, 0x40}, + {0x3622, 0x01}, + // 50/60Hz detection 50/60Hz + {0x3c01, 0x34}, // Band auto, bit[7] + {0x3c04, 0x28}, // threshold low sum + {0x3c05, 0x98}, // threshold high sum + {0x3c06, 0x00}, // light meter 1 threshold[15:8] + {0x3c07, 0x07}, // light meter 1 threshold[7:0] + + {0x3c08, 0x00}, // light meter 2 threshold[15:8] + {0x3c09, 0x1c}, // light meter 2 threshold[7:0] + {0x3c0a, 0x9c}, // sample number[15:8] + {0x3c0b, 0x40}, // sample number[7:0] + {0x3810, 0x00}, // Timing Hoffset[11:8] + {0x3811, 0x10}, // Timing Hoffset[7:0] + {0x3812, 0x00}, // Timing Voffset[10:8] + {0x3708, 0x64}, + {0x4001, 0x02}, // BLC start from line 2 + {0x4005, 0x1a}, // BLC always update + {0x3000, 0x00}, // enable blocks + {0x3004, 0xff}, // enable clocks + {0x300e, 0x58}, // MIPI power down, DVP enable + {0x302e, 0x00}, + {0x4300, 0x61}, + {0X501F, 0x01}, + + {0x3820, 0x46}, // flip + {0x3821, 0x00}, // mirror + {0x3814, 0x31}, // timing X inc + {0x3815, 0x31}, // timing Y inc + {0x3800, 0x00}, // HS + {0x3801, 0x00}, // HS + {0x3802, 0x00}, // VS + {0x3803, 0x00}, // VS + {0x3804, 0x0a}, // HW (HE) + {0x3805, 0x3f}, // HW (HE) + {0x3806, 0x06}, // VH (VE) + {0x3807, 0xa9}, // VH (VE) + + {0x3808, (320 >> 8)}, // DVPHO + {0x3809, (320 & 0xff)}, // DVPHO + {0x380a, (240 >> 8)}, // DVPVO + {0x380b, (240 & 0xff)}, // DVPVO + + {0x380c, 0x05}, // HTS + {0x380d, 0xF8}, // HTS + {0x380e, 0x03}, // VTS + {0x380f, 0x84}, // VTS + + {0x3810, (4 >> 8)}, // HTS + {0x3811, (4 & 0xff)}, // HTS + {0x3812, (0 >> 8)}, // VTS + {0x3813, (0 & 0xff)}, // VTS + + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x3a02, 0x02}, // 60Hz max exposure + {0x3a03, 0xe0}, // 60Hz max exposure + {0x3a14, 0x02}, // 50Hz max exposure + {0x3a15, 0xe0}, // 50Hz max exposure + + {0x4004, 0x02}, // BLC line number + {0x3002, 0x1c}, // reset JFIFO, SFIFO, JPG + {0x3006, 0xc3}, // disable clock of JPEG2x, JPEG + {0x4713, 0x03}, // JPEG mode 3 + {0x4407, 0x04}, // Quantization scale + {0x460b, 0x37}, + {0x460c, 0x20}, + {0x4837, 0x16}, // MIPI global timing + {0x3824, 0x04}, // PCLK manual divider + {0x5001, 0xA3}, // SDE on, scale on, UV average off, color matrix on, AWB on + {0x3503, 0x00}, // AEC/AGC on + + + {0x440e, 0x00}, + {0x5000, 0xa7}, // Lenc on, raw gamma on, BPC on, WPC on, CIP on + {// AEC target + {0x3a0f, 0x30}, // stable range in high + {0x3a10, 0x28}, // stable range in low + {0x3a1b, 0x30}, // stable range out high + {0x3a1e, 0x26}, // stable range out low + {0x3a11, 0x60}, // fast zone high + {0x3a1f, 0x14}, // fast zone low + {// Lens correction for ? + {0x5800, 0x23}, + {0x5801, 0x14}, + {0x5802, 0x0f}, + {0x5803, 0x0f}, + {0x5804, 0x12}, + {0x5805, 0x26}, + {0x5806, 0x0c}, + {0x5807, 0x08}, + {0x5808, 0x05}, + {0x5809, 0x05}, + {0x580a, 0x08}, + + {0x580b, 0x0d}, + {0x580c, 0x08}, + {0x580d, 0x03}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x03}, + {0x5811, 0x09}, + {0x5812, 0x07}, + {0x5813, 0x03}, + {0x5814, 0x00}, + {0x5815, 0x01}, + {0x5816, 0x03}, + {0x5817, 0x08}, + {0x5818, 0x0d}, + {0x5819, 0x08}, + {0x581a, 0x05}, + {0x581b, 0x06}, + {0x581c, 0x08}, + {0x581d, 0x0e}, + {0x581e, 0x29}, + {0x581f, 0x17}, + {0x5820, 0x11}, + {0x5821, 0x11}, + {0x5822, 0x15}, + {0x5823, 0x28}, + {0x5824, 0x46}, + {0x5825, 0x26}, + {0x5826, 0x08}, + {0x5827, 0x26}, + {0x5828, 0x64}, + {0x5829, 0x26}, + {0x582a, 0x24}, + {0x582b, 0x22}, + {0x582c, 0x24}, + {0x582d, 0x24}, + {0x582e, 0x06}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x42}, + {0x5832, 0x24}, + {0x5833, 0x26}, + {0x5834, 0x24}, + {0x5835, 0x22}, + {0x5836, 0x22}, + {0x5837, 0x26}, + {0x5838, 0x44}, + {0x5839, 0x24}, + {0x583a, 0x26}, + {0x583b, 0x28}, + {0x583c, 0x42}, + {0x583d, 0xce}, // lenc BR offset + // AWB + {0x5180, 0xff}, // AWB B block + {0x5181, 0xf2}, // AWB control + {0x5182, 0x00}, // [7:4] max local counter, [3:0] max fast counter + {0x5183, 0x14}, // AWB advanced + {0x5184, 0x25}, + {0x5185, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x75}, + {0x518a, 0x54}, + {0x518b, 0xe0}, + {0x518c, 0xb2}, + {0x518d, 0x42}, + {0x518e, 0x3d}, + {0x518f, 0x56}, + {0x5190, 0x46}, + {0x5191, 0xf8}, // AWB top limit + {0x5192, 0x04}, // AWB bottom limit + {0x5193, 0x70}, // red limit + {0x5194, 0xf0}, // green limit + {0x5195, 0xf0}, // blue limit + {0x5196, 0x03}, // AWB control + {0x5197, 0x01}, // local limit + {0x5198, 0x04}, + {0x5199, 0x12}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x06}, + {0x519d, 0x82}, + {0x519e, 0x38}, // AWB control + // Gamma + {0x5480, 0x01}, // Gamma bias plus on, bit[0] + {0x5481, 0x08}, + {0x5482, 0x14}, + {0x5483, 0x28}, + {0x5484, 0x51}, + {0x5485, 0x65}, + {0x5486, 0x71}, + {0x5487, 0x7d}, + {0x5488, 0x87}, + {0x5489, 0x91}, + {0x548a, 0x9a}, + {0x548b, 0xaa}, + {0x548c, 0xb8}, + {0x548d, 0xcd}, + {0x548e, 0xdd}, + {0x548f, 0xea}, + {0x5490, 0x1d}, + // color matrix + {0x5381, 0x1e}, // CMX1 for Y + {0x5382, 0x5b}, // CMX2 for Y + {0x5383, 0x08}, // CMX3 for Y + {0x5384, 0x0a}, // CMX4 for U + {0x5385, 0x7e}, // CMX5 for U + {0x5386, 0x88}, // CMX6 for U + {0x5387, 0x7c}, // CMX7 for V + {0x5388, 0x6c}, // CMX8 for V + {0x5389, 0x10}, // CMX9 for V + {0x538a, 0x01}, // sign[9] + {0x538b, 0x98}, // sign[8:1] + // UV adjust UV + {0x5580, 0x06}, // saturation on, bit[1] + {0x5583, 0x40}, + {0x5584, 0x10}, + {0x5589, 0x10}, + {0x558a, 0x00}, + {0x558b, 0xf8}, + {0x501d, 0x40}, // enable manual offset of contrast + // CIP + {0x5300, 0x08}, // CIP sharpen MT threshold 1 + {0x5301, 0x30}, // CIP sharpen MT threshold 2 + {0x5302, 0x10}, // CIP sharpen MT offset 1 + {0x5303, 0x00}, // CIP sharpen MT offset 2 + {0x5304, 0x08}, // CIP DNS threshold 1 + {0x5305, 0x30}, // CIP DNS threshold 2 + {0x5306, 0x08}, // CIP DNS offset 1 + {0x5307, 0x16}, // CIP DNS offset 2 + {0x5309, 0x08}, // CIP sharpen TH threshold 1 + {0x530a, 0x30}, // CIP sharpen TH threshold 2 + {0x530b, 0x04}, // CIP sharpen TH offset 1 + {0x530c, 0x06}, // CIP sharpen TH offset 2 + {0x5025, 0x00}, + {0x3008, 0x02}, // wake up from standby, bit[6] + + {0x4740, 0X21} //VSYNC active HIGH +}; + +#endif + +#endif + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/region_layer.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/region_layer.h new file mode 100755 index 0000000..612efdc --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/region_layer.h @@ -0,0 +1,34 @@ +#ifndef _REGION_LAYER_ +#define _REGION_LAYER_ + +#include + +typedef struct { + uint32_t class; + float threshold; + float nms; + uint32_t input_len; + uint8_t *input; + float *active; + float *softmax; + float *biases; +} REGION_CFG; + +typedef struct { + uint16_t object_num; + struct { + uint16_t class; + uint16_t prob; + uint16_t x1; + uint16_t x2; + uint16_t y1; + uint16_t y2; + } object[20]; +} OBJECT_INFO; + +int region_layer_init(REGION_CFG *cfg); +void region_layer_cal_first(void); +void region_layer_cal_second(void); +void region_layer_detect_object(OBJECT_INFO *info); + +#endif // _REGION_LAYER diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/st7789.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/st7789.h new file mode 100755 index 0000000..0342ad8 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/st7789.h @@ -0,0 +1,94 @@ +#ifndef _NT35310_H_ +#define _NT35310_H_ + +#include + +/* clang-format off */ +#define NO_OPERATION 0x00 +#define SOFTWARE_RESET 0x01 +#define READ_ID 0x04 +#define READ_STATUS 0x09 +#define READ_POWER_MODE 0x0A +#define READ_MADCTL 0x0B +#define READ_PIXEL_FORMAT 0x0C +#define READ_IMAGE_FORMAT 0x0D +#define READ_SIGNAL_MODE 0x0E +#define READ_SELT_DIAG_RESULT 0x0F +#define SLEEP_ON 0x10 +#define SLEEP_OFF 0x11 +#define PARTIAL_DISPALY_ON 0x12 +#define NORMAL_DISPALY_ON 0x13 +#define INVERSION_DISPALY_OFF 0x20 +#define INVERSION_DISPALY_ON 0x21 +#define GAMMA_SET 0x26 +#define DISPALY_OFF 0x28 +#define DISPALY_ON 0x29 +#define HORIZONTAL_ADDRESS_SET 0x2A +#define VERTICAL_ADDRESS_SET 0x2B +#define MEMORY_WRITE 0x2C +#define COLOR_SET 0x2D +#define MEMORY_READ 0x2E +#define PARTIAL_AREA 0x30 +#define VERTICAL_SCROL_DEFINE 0x33 +#define TEAR_EFFECT_LINE_OFF 0x34 +#define TEAR_EFFECT_LINE_ON 0x35 +#define MEMORY_ACCESS_CTL 0x36 +#define VERTICAL_SCROL_S_ADD 0x37 +#define IDLE_MODE_OFF 0x38 +#define IDLE_MODE_ON 0x39 +#define PIXEL_FORMAT_SET 0x3A +#define WRITE_MEMORY_CONTINUE 0x3C +#define READ_MEMORY_CONTINUE 0x3E +#define SET_TEAR_SCANLINE 0x44 +#define GET_SCANLINE 0x45 +#define WRITE_BRIGHTNESS 0x51 +#define READ_BRIGHTNESS 0x52 +#define WRITE_CTRL_DISPALY 0x53 +#define READ_CTRL_DISPALY 0x54 +#define WRITE_BRIGHTNESS_CTL 0x55 +#define READ_BRIGHTNESS_CTL 0x56 +#define WRITE_MIN_BRIGHTNESS 0x5E +#define READ_MIN_BRIGHTNESS 0x5F +#define READ_ID1 0xDA +#define READ_ID2 0xDB +#define READ_ID3 0xDC +#define RGB_IF_SIGNAL_CTL 0xB0 +#define NORMAL_FRAME_CTL 0xB1 +#define IDLE_FRAME_CTL 0xB2 +#define PARTIAL_FRAME_CTL 0xB3 +#define INVERSION_CTL 0xB4 +#define BLANK_PORCH_CTL 0xB5 +#define DISPALY_FUNCTION_CTL 0xB6 +#define ENTRY_MODE_SET 0xB7 +#define BACKLIGHT_CTL1 0xB8 +#define BACKLIGHT_CTL2 0xB9 +#define BACKLIGHT_CTL3 0xBA +#define BACKLIGHT_CTL4 0xBB +#define BACKLIGHT_CTL5 0xBC +#define BACKLIGHT_CTL7 0xBE +#define BACKLIGHT_CTL8 0xBF +#define POWER_CTL1 0xC0 +#define POWER_CTL2 0xC1 +#define VCOM_CTL1 0xC5 +#define VCOM_CTL2 0xC7 +#define NV_MEMORY_WRITE 0xD0 +#define NV_MEMORY_PROTECT_KEY 0xD1 +#define NV_MEMORY_STATUS_READ 0xD2 +#define READ_ID4 0xD3 +#define POSITIVE_GAMMA_CORRECT 0xE0 +#define NEGATIVE_GAMMA_CORRECT 0xE1 +#define DIGITAL_GAMMA_CTL1 0xE2 +#define DIGITAL_GAMMA_CTL2 0xE3 +#define INTERFACE_CTL 0xF6 +/* clang-format on */ + +void tft_hard_init(void); +void tft_set_datawidth(uint8_t width); +void tft_write_command(uint8_t cmd); +void tft_write_byte_1(uint8_t data); +void tft_write_byte(uint8_t *data_buf, uint32_t length); +void tft_write_half(uint16_t *data_buf, uint32_t length); +void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag); +int tft_busy(void); + +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/w25qxx.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/w25qxx.h new file mode 100755 index 0000000..988f490 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/w25qxx.h @@ -0,0 +1,53 @@ +/** + * @file + * @brief winbond w25qxx series driver + */ +#ifndef _W25QXX_LICHEE_H +#define _W25QXX_LICHEE_H + +#include + +/** + * @brief w25qxx operating status enumerate + */ +enum w25qxx_status_t { + W25QXX_OK = 0, + W25QXX_BUSY, + W25QXX_ERROR, +}; + +/** + * @brief w25qxx read operating enumerate + */ +enum w25qxx_read_t { + W25QXX_STANDARD = 0, + W25QXX_STANDARD_FAST, + W25QXX_DUAL, + W25QXX_DUAL_FAST, + W25QXX_QUAD, + W25QXX_QUAD_FAST, +}; + +extern enum w25qxx_status_t (*w25qxx_page_program_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length); + +enum w25qxx_status_t w25qxx_init(uint8_t spi_index); +enum w25qxx_status_t w25qxx_is_busy(void); +enum w25qxx_status_t w25qxx_chip_erase(void); +enum w25qxx_status_t w25qxx_enable_quad_mode(void); +enum w25qxx_status_t w25qxx_disable_quad_mode(void); +enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr); +enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data); +enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data); +enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data); +enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id); +enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode); +enum w25qxx_status_t w25qxx_enable_xip_mode(void); +enum w25qxx_status_t w25qxx_disable_xip_mode(void); +enum w25qxx_status_t w25qxx_write_data_dma(uint32_t addr, uint32_t *data_buf, uint32_t length); +enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint32_t *data_buf, uint32_t length); + +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ws2812b.h b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ws2812b.h new file mode 100755 index 0000000..660da78 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/include/ws2812b.h @@ -0,0 +1,38 @@ +#ifndef _WS2812B_H +#define _WS2812B_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LED control: + * WS2812B_SetLedRGB(); // First LED (Connected to MCU) + * WS2812B_SetLedRGB(); // Second LED + * WS2812B_SetLedRGB(); // Third LED (If exist) + * WS2812B_TxRes() // Send reset signal + * + * WS2812B's protocol: + * The data is sent in a sequence containing 24 of those bits – 8 bits for each color + * Highest bit first, followed by a low “reset†pulse of at least 50µs. + * 0 is encoded as: T0H = 0.4uS ToL = 0.85uS (Tolerance 0.15uS) + * 1 is encoded as: T1H = 0.85uS T1L = 0.4uS (Tolerance 0.15uS) + * A valid reset: Hold data line low for at least 50µs. + * + * |-->Update color + * _________________ | >50uS | + * START_______IDLE_______________|1st LED|2nd LED|___Reset_______IDLE_____________ + **/ + +void WS2812B_SetLedRGB(uint8_t r, uint8_t g, uint8_t b,int gpio_num); +void WS2812B_TxRes(int gpio_num); +void WS2812B_SetLednRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t num,int gpio_num); +void init_nop_cnt(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _WS2812B_H */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/lcd.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/lcd.c new file mode 100755 index 0000000..c9bb8c0 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/lcd.c @@ -0,0 +1,472 @@ +#include +#include "lcd.h" +#include "st7789.h" +#include "font.h" +// #include "common.h" +#include "sleep.h" +#include "gpiohs.h" +#include "fpioa.h" + +//LCD的画笔颜色和背景色 +uint16_t POINT_COLOR=0x0000; //画笔颜色 +uint16_t BACK_COLOR=0xFFFF; //背景色 + +//管ç†LCDé‡è¦å‚æ•° +//é»˜è®¤ä¸ºç«–å± +_lcd_dev lcddev; + +//写寄存器函数 +//regval:寄存器值 +void LCD_WR_REG(uint8_t regval) +{ + tft_write_command(regval); +} + +//写LCDæ•°æ® +//data:è¦å†™å…¥çš„值 +void LCD_WR_DATA(uint8_t data) +{ + tft_write_byte(&data,1); +} + +//写寄存器 +//LCD_Reg:å¯„å­˜å™¨åœ°å€ +//LCD_RegValue:è¦å†™å…¥çš„æ•°æ® +void LCD_WriteReg(uint8_t LCD_Reg, uint8_t LCD_RegValue) +{ + LCD_WR_REG(LCD_Reg); + LCD_WR_DATA(LCD_RegValue); +} + +//开始写GRAM +void LCD_WriteRAM_Prepare(void) +{ + LCD_WR_REG(lcddev.wramcmd); +} + +//LCD写GRAM +//RGB_Code:颜色值 +void LCD_WriteRAM(uint16_t RGB_Code) +{ + uint8_t buf[2]={0}; + + buf[0] = RGB_Code >> 8; + buf[1] = RGB_Code & 0xff; + tft_write_byte(buf,2); +} + +//设置光标ä½ç½® +//Xpos:横åæ ‡ +//Ypos:纵åæ ‡ +void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos) +{ + LCD_WR_REG(lcddev.setxcmd); + LCD_WR_DATA(Xpos>>8); + LCD_WR_DATA(Xpos&0XFF); + + LCD_WR_REG(lcddev.setycmd); + LCD_WR_DATA(Ypos>>8); + LCD_WR_DATA(Ypos&0XFF); +} +//设置LCD的自动扫ææ–¹å‘ +//注æ„:其他函数å¯èƒ½ä¼šå—到此函数设置的影å“(尤其是9341/6804这两个奇葩), +//所以,一般设置为L2R_U2Då³å¯,如果设置为其他扫ææ–¹å¼,å¯èƒ½å¯¼è‡´æ˜¾ç¤ºä¸æ­£å¸¸. +//dir:0~7,代表8个方å‘(具体定义è§lcd.h) +//9320/9325/9328/4531/4535/1505/b505/8989/5408/9341ç­‰ICå·²ç»å®žé™…测试 +void LCD_Scan_Dir(enum lcd_dir_t dir) +{ + uint16_t temp; + + LCD_WriteReg(0X36,dir); + + if(dir&0X20) + { + if(lcddev.widthlcddev.height)//交æ¢X,Y + { + temp=lcddev.width; + lcddev.width=lcddev.height; + lcddev.height=temp; + } + } + LCD_WR_REG(lcddev.setxcmd); + LCD_WR_DATA(0); + LCD_WR_DATA(0); + LCD_WR_DATA((lcddev.width-1)>>8); + LCD_WR_DATA((lcddev.width-1)&0XFF); + LCD_WR_REG(lcddev.setycmd); + LCD_WR_DATA(0); + LCD_WR_DATA(0); + LCD_WR_DATA((lcddev.height-1)>>8); + LCD_WR_DATA((lcddev.height-1)&0XFF); +} + +//画点 +//x,y:åæ ‡ +//POINT_COLOR:此点的颜色 +void LCD_DrawPoint(uint16_t x,uint16_t y) +{ + LCD_SetCursor(x,y); //设置光标ä½ç½® + LCD_WriteRAM_Prepare(); //开始写入GRAM + LCD_WriteRAM(POINT_COLOR); +} + +//设置LCD显示方å‘(6804ä¸æ”¯æŒæ¨ªå±æ˜¾ç¤ºï¼‰ +//dir:0,ç«–å±ï¼›1,æ¨ªå± +void LCD_Display_Dir(uint8_t dir) +{ + if(lcddev.dir==0)//ç«–å± + { + lcddev.dir=0;//ç«–å± + lcddev.width=240; + lcddev.height=320; + lcddev.wramcmd=0x2C; + lcddev.setxcmd=0x2a; + lcddev.setycmd=0x2b; + }else + { + lcddev.dir=1;//æ¨ªå± + lcddev.width=320; + lcddev.height=240; + lcddev.wramcmd=0x2c; + lcddev.setxcmd=0x2a; + lcddev.setycmd=0x2b; + } + LCD_Scan_Dir(DIR_YX_LRUD); //默认扫ææ–¹å‘ +} +//åˆå§‹åŒ–lcd +//该åˆå§‹åŒ–函数å¯ä»¥åˆå§‹åŒ–å„ç§ILI93XX液晶,但是其他函数是基于ILI9320çš„!!! +//在其他型å·çš„驱动芯片上没有测试! +void lcd_init(void) +{ + tft_hard_init(); + + //************* Start Initial Sequence **********// + LCD_WR_REG(0x11); + msleep(120); //Delay 120ms + //--------------------------------ST7789S Frame rate setting----------------------------------// + LCD_WR_REG(0xb2); + LCD_WR_DATA(0x0c); + LCD_WR_DATA(0x0c); + LCD_WR_DATA(0x00); + LCD_WR_DATA(0x33); + LCD_WR_DATA(0x33); + + LCD_WR_REG(0xb7); + LCD_WR_DATA(0x35); + + //---------------------------------ST7789S Power setting--------------------------------------// + LCD_WR_REG(0xbb); + LCD_WR_DATA(0x2b); + + LCD_WR_REG(0xc0); + LCD_WR_DATA(0x2c); + + LCD_WR_REG(0xc2); + LCD_WR_DATA(0x01); + + LCD_WR_REG(0xc3); + LCD_WR_DATA(0x17); + + LCD_WR_REG(0xc4); + LCD_WR_DATA(0x20); + + LCD_WR_REG(0xc6); + LCD_WR_DATA(0x0f); + + LCD_WR_REG(0xca); + LCD_WR_DATA(0x0f); + + LCD_WR_REG(0xc8); + LCD_WR_DATA(0x08); + + LCD_WR_REG(0x55); + LCD_WR_DATA(0x90); + + LCD_WR_REG(0xd0); + LCD_WR_DATA(0xa4); + LCD_WR_DATA(0xa1); + + LCD_WR_REG(0x3A); + LCD_WR_DATA(0x05); + + LCD_WR_REG(0x36); + LCD_WR_DATA(0x08); + + //--------------------------------ST7789S gamma setting---------------------------------------// + LCD_WR_REG(0xe0); + LCD_WR_DATA(0xF0); + LCD_WR_DATA(0x00); + LCD_WR_DATA(0x0A); + LCD_WR_DATA(0x10); + LCD_WR_DATA(0x12); + + LCD_WR_DATA(0x1b); + LCD_WR_DATA(0x39); + LCD_WR_DATA(0x44); + LCD_WR_DATA(0x47); + LCD_WR_DATA(0x28); + + LCD_WR_DATA(0x12); + LCD_WR_DATA(0x10); + LCD_WR_DATA(0x16); + LCD_WR_DATA(0x1b); + + LCD_WR_REG(0xe1); + LCD_WR_DATA(0xf0); + LCD_WR_DATA(0x00); + LCD_WR_DATA(0x0a); + LCD_WR_DATA(0x10); + LCD_WR_DATA(0x11); + + LCD_WR_DATA(0x1a); + LCD_WR_DATA(0x3b); + LCD_WR_DATA(0x34); + LCD_WR_DATA(0x4e); + LCD_WR_DATA(0x3a); + + LCD_WR_DATA(0x17); + LCD_WR_DATA(0x16); + LCD_WR_DATA(0x21); + LCD_WR_DATA(0x22); + + LCD_WR_REG(0x29); + LCD_WR_REG(0x2c); + + LCD_Display_Dir(1); + lcd_clear(BLACK); +} + +//画线 +//x1,y1:起点åæ ‡ +//x2,y2:终点åæ ‡ +void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + uint16_t t; + int xerr=0,yerr=0,delta_x,delta_y,distance; + int incx,incy,uRow,uCol; + delta_x=x2-x1; //计算åæ ‡å¢žé‡ + delta_y=y2-y1; + uRow=x1; + uCol=y1; + if(delta_x>0)incx=1; //设置å•æ­¥æ–¹å‘ + else if(delta_x==0)incx=0;//垂直线 + else {incx=-1;delta_x=-delta_x;} + if(delta_y>0)incy=1; + else if(delta_y==0)incy=0;//水平线 + else{incy=-1;delta_y=-delta_y;} + if( delta_x>delta_y)distance=delta_x; //选å–基本增é‡å标轴 + else distance=delta_y; + for(t=0;t<=distance+1;t++ )//画线输出 + { + LCD_DrawPoint(uRow,uCol);//画点 + xerr+=delta_x ; + yerr+=delta_y ; + if(xerr>distance) + { + xerr-=distance; + uRow+=incx; + } + if(yerr>distance) + { + yerr-=distance; + uCol+=incy; + } + } +} + +//画矩形 +//(x1,y1),(x2,y2):矩形的对角åæ ‡ +void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + LCD_DrawLine(x1,y1,x2,y1+5); + LCD_DrawLine(x1,y1,x1,y2+5); + LCD_DrawLine(x1,y2,x2,y2+5); + LCD_DrawLine(x2,y1,x2,y2+5); +} + +//è®¾ç½®çª—å£ +void LCD_Set_Window(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height) +{ + width=sx+width-1; + height=sy+height-1; + + LCD_WR_REG(lcddev.setxcmd); + LCD_WR_DATA(sx>>8); + LCD_WR_DATA(sx&0XFF); + LCD_WR_DATA(width>>8); + LCD_WR_DATA(width&0XFF); + + LCD_WR_REG(lcddev.setycmd); + LCD_WR_DATA(sy>>8); + LCD_WR_DATA(sy&0XFF); + LCD_WR_DATA(height>>8); + LCD_WR_DATA(height&0XFF); + LCD_WR_REG(lcddev.wramcmd); +} + +void lcd_draw_char(uint16_t x, uint16_t y, char c, uint16_t color) +{ + uint8_t i, j, data; + uint16_t tmp; + + tmp = POINT_COLOR; + POINT_COLOR = color; + + for (i = 0; i < 16; i++) { + data = ascii0816[c * 16 + i]; + for (j = 0; j < 8; j++) { + if (data & 0x80) + LCD_DrawPoint(x + j, y); + data <<= 1; + } + y++; + } + POINT_COLOR = tmp; +} + +void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color) +{ + while (*str) { + lcd_draw_char(x, y, *str, color); + str++; + x += 8; + } +} + +void ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color) +{ + uint8_t i, j, data, *pdata; + uint16_t width; + uint32_t *pixel; + + width = 4 * strlen(str); + while (*str) { + pdata = (uint8_t *)&ascii0816[(*str) * 16]; + for (i = 0; i < 16; i++) { + data = *pdata++; + pixel = ptr + i * width; + for (j = 0; j < 4; j++) { + switch (data >> 6) { + case 0: + *pixel = ((uint32_t)bg_color << 16) | bg_color; break; + case 1: + *pixel = ((uint32_t)bg_color << 16) | font_color; break; + case 2: + *pixel = ((uint32_t)font_color << 16) | bg_color; break; + case 3: + *pixel = ((uint32_t)font_color << 16) | font_color; break; + default: + *pixel = 0; break; + } + data <<= 2; + pixel++; + } + } + str++; + ptr += 4; + } +} + +void lcd_draw_rectangle_cpu(uint32_t *ptr, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) +{ + uint32_t *addr1, *addr2; + uint16_t i; + uint32_t data = ((uint32_t)color << 16) | (uint32_t)color; + + if (x1 == 319) + x1 = 318; + if (x2 == 0) + x2 = 1; + if (y1 == 239) + y1 = 238; + if (y2 == 0) + y2 = 1; + + addr1 = ptr + (320 * y1 + x1) / 2; + addr2 = ptr + (320 * (y2 - 1) + x1) / 2; + for (i = x1; i < x2; i += 2) { + *addr1 = data; + *(addr1 + 160) = data; + *addr2 = data; + *(addr2 + 160) = data; + addr1++; + addr2++; + } + addr1 = ptr + (320 * y1 + x1) / 2; + addr2 = ptr + (320 * y1 + x2 - 1) / 2; + for (i = y1; i < y2; i++) { + *addr1 = data; + *addr2 = data; + addr1 += 160; + addr2 += 160; + } +} + +void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color) +{ + uint16_t colortemp=POINT_COLOR; + + POINT_COLOR = RED; + LCD_DrawRectangle(x1,y1,x2,y2); + POINT_COLOR = colortemp; +} + +void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr) +{ +#if 1 + LCD_Set_Window(x1, y1, x1 + width, y1 + height); + LCD_SetCursor(0x00,0x0000); //设置光标ä½ç½® + LCD_WriteRAM_Prepare(); //开始写入GRAM + tft_set_datawidth(32); + tft_write_word(ptr, width * height / 2, 0); + tft_set_datawidth(8); +#else + uint32_t index; + uint8_t dat[4]; + + LCD_Set_Window(x1, y1, x1 + width, y1 + height); + LCD_SetCursor(0x00,0x0000); //设置光标ä½ç½® + LCD_WriteRAM_Prepare(); //开始写入GRAM + + for(index=0;index>24&0xff; + dat[1]=*ptr>>16&0xff; + dat[2]=*ptr>>8&0xff; + dat[3]=*ptr&0xff; + tft_write_byte(&dat,4); + ptr++; + } + // msleep(10); +#endif +} + +//清å±å‡½æ•° +//color:è¦æ¸…å±çš„填充色 +void lcd_clear(uint16_t color) +{ + uint8_t data[2]={0}; + uint32_t index=0; + uint32_t totalpoint=lcddev.width; + + totalpoint*=lcddev.height; //得到总点数 + LCD_SetCursor(0x00,0x0000); //设置光标ä½ç½® + LCD_WriteRAM_Prepare(); //开始写入GRAM + + data[0] = color >> 8; + data[1] = color & 0xff; + + for(index=0;index +#include "ov2640.h" +#include "dvp.h" +#include "plic.h" +#include "fpioa.h" + +#define OV2640_ADDR 0x60 + +/* QVGA Window Size */ +static const uint8_t ov2640_config[][2] = { +{0xff, 0x01}, +{0x12, 0x80}, +{0xff, 0x00}, +{0x2c, 0xff}, +{0x2e, 0xdf}, +{0xff, 0x01}, +{0x3c, 0x32}, +{0x11, 0x00}, +{0x09, 0x02}, +{0x04, 0x58}, +{0x13, 0xe5}, +{0x14, 0x48}, +{0x2c, 0x0c}, +{0x33, 0x78}, +{0x3a, 0x33}, +{0x3b, 0xfb}, +{0x3e, 0x00}, +{0x43, 0x11}, +{0x16, 0x10}, +{0x39, 0x92}, +{0x35, 0xda}, +{0x22, 0x1a}, +{0x37, 0xc3}, +{0x23, 0x00}, +{0x34, 0xc0}, +{0x36, 0x1a}, +{0x06, 0x88}, +{0x07, 0xc0}, +{0x0d, 0x87}, +{0x0e, 0x41}, +{0x4c, 0x00}, +{0x48, 0x00}, +{0x5b, 0x00}, +{0x42, 0x03}, +{0x4a, 0x81}, +{0x21, 0x99}, +{0x24, 0x40}, +{0x25, 0x38}, +{0x26, 0x82}, +{0x5c, 0x00}, +{0x63, 0x00}, +{0x46, 0x22}, +{0x0c, 0x3c}, +{0x61, 0x70}, +{0x62, 0x80}, +{0x7c, 0x05}, +{0x20, 0x80}, +{0x28, 0x30}, +{0x6c, 0x00}, +{0x6d, 0x80}, +{0x6e, 0x00}, +{0x70, 0x02}, +{0x71, 0x94}, +{0x73, 0xc1}, +{0x3d, 0x34}, +{0x5a, 0x57}, +{0x12, 0x40}, +{0x17, 0x11}, +{0x18, 0x43}, +{0x19, 0x00}, +{0x1a, 0x4b}, +{0x32, 0x09}, +{0x37, 0xc0}, +{0x4f, 0xca}, +{0x50, 0xa8}, +{0x5a, 0x23}, +{0x6d, 0x00}, +{0x3d, 0x38}, +{0xff, 0x00}, +{0xe5, 0x7f}, +{0xf9, 0xc0}, +{0x41, 0x24}, +{0xe0, 0x14}, +{0x76, 0xff}, +{0x33, 0xa0}, +{0x42, 0x20}, +{0x43, 0x18}, +{0x4c, 0x00}, +{0x87, 0xd5}, +{0x88, 0x3f}, +{0xd7, 0x03}, +{0xd9, 0x10}, +{0xd3, 0x82}, +{0xc8, 0x08}, +{0xc9, 0x80}, +{0x7c, 0x00}, +{0x7d, 0x00}, +{0x7c, 0x03}, +{0x7d, 0x48}, +{0x7d, 0x48}, +{0x7c, 0x08}, +{0x7d, 0x20}, +{0x7d, 0x10}, +{0x7d, 0x0e}, +{0x90, 0x00}, +{0x91, 0x0e}, +{0x91, 0x1a}, +{0x91, 0x31}, +{0x91, 0x5a}, +{0x91, 0x69}, +{0x91, 0x75}, +{0x91, 0x7e}, +{0x91, 0x88}, +{0x91, 0x8f}, +{0x91, 0x96}, +{0x91, 0xa3}, +{0x91, 0xaf}, +{0x91, 0xc4}, +{0x91, 0xd7}, +{0x91, 0xe8}, +{0x91, 0x20}, +{0x92, 0x00}, +{0x93, 0x06}, +{0x93, 0xe3}, +{0x93, 0x05}, +{0x93, 0x05}, +{0x93, 0x00}, +{0x93, 0x04}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x93, 0x00}, +{0x96, 0x00}, +{0x97, 0x08}, +{0x97, 0x19}, +{0x97, 0x02}, +{0x97, 0x0c}, +{0x97, 0x24}, +{0x97, 0x30}, +{0x97, 0x28}, +{0x97, 0x26}, +{0x97, 0x02}, +{0x97, 0x98}, +{0x97, 0x80}, +{0x97, 0x00}, +{0x97, 0x00}, +{0xc3, 0xed}, +{0xa4, 0x00}, +{0xa8, 0x00}, +{0xc5, 0x11}, +{0xc6, 0x51}, +{0xbf, 0x80}, +{0xc7, 0x10}, +{0xb6, 0x66}, +{0xb8, 0xa5}, +{0xb7, 0x64}, +{0xb9, 0x7c}, +{0xb3, 0xaf}, +{0xb4, 0x97}, +{0xb5, 0xff}, +{0xb0, 0xc5}, +{0xb1, 0x94}, +{0xb2, 0x0f}, +{0xc4, 0x5c}, +{0xc0, 0x64}, +{0xc1, 0x4b}, +{0x8c, 0x00}, +{0x86, 0x3d}, +{0x50, 0x00}, +{0x51, 0xc8}, +{0x52, 0x96}, +{0x53, 0x00}, +{0x54, 0x00}, +{0x55, 0x00}, +{0x5a, 0xc8}, +{0x5b, 0x96}, +{0x5c, 0x00}, +{0xd3, 0x02}, +{0xc3, 0xed}, +{0x7f, 0x00}, +{0xda, 0x08}, +{0xe5, 0x1f}, +{0xe1, 0x67}, +{0xe0, 0x00}, +{0xdd, 0x7f}, +{0x05, 0x00}, +//[OV2640_OutSize_Set] width:320 height:240 +{0xff, 0x00}, +{0xe0, 0x04}, +{0x5a, 0x50}, +{0x5b, 0x3c}, +{0x5c, 0x00}, +{0xe0, 0x00}, +#if 0 //color bar + {0xff, 0x01}, + {0x12, 0x02}, +#endif + {0x00, 0x00} +}; + +/** + * dvp_pclk io47 + * dvp_xclk io46 + * dvp_hsync io45 + * dvp_pwdn io44 + * dvp_vsync io43 + * dvp_rst io42 + * dvp_scl io41 + * dvp_sda io40 + * */ + +static void dvp_io_init(void) +{ + /* + fpioa_set_function(47, FUNC_CMOS_PCLK); + fpioa_set_function(46, FUNC_CMOS_XCLK); + fpioa_set_function(45, FUNC_CMOS_HREF); + fpioa_set_function(44, FUNC_CMOS_PWDN); + fpioa_set_function(43, FUNC_CMOS_VSYNC); + fpioa_set_function(42, FUNC_CMOS_RST); + fpioa_set_function(41, FUNC_SCCB_SCLK); + fpioa_set_function(40, FUNC_SCCB_SDA); + */ +} + +int ov2640_init(void) +{ + uint16_t index; + + dvp_init(8); + dvp_io_init(); + dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(1) | DVP_CMOS_CLK_ENABLE; + dvp_reset(); + dvp_enable_burst(); + dvp->dvp_cfg |= (DVP_CFG_AI_OUTPUT_ENABLE | DVP_CFG_DISPLAY_OUTPUT_ENABLE); + printf("Enter the ov2640_init\n"); + for (index = 0; ov2640_config[index][0]; index++) + dvp_sccb_send_data(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]); + dvp_set_image_format(DVP_CFG_RGB_FORMAT); + dvp_set_image_size(320, 240); + + return 0; +} + +int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id) +{ + dvp_sccb_send_data(OV2640_ADDR, 0xFF, 0x01); + *manuf_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x1C) << 8) | + dvp_sccb_receive_data(OV2640_ADDR, 0x1D); + *device_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x0A) << 8) | + dvp_sccb_receive_data(OV2640_ADDR, 0x0B); + return 0; +} + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ov5640.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ov5640.c new file mode 100755 index 0000000..e6bfc4a --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ov5640.c @@ -0,0 +1,504 @@ +#include "ov5640.h" +#include "ov5640cfg.h" +#include "ov5640af.h" +#include +#include "ov2640.h" +#include "dvp.h" +#include "plic.h" + +const uint16_t jpeg_size_tbl[][2]= +{ + {160, 120}, //QQVGA + {176, 144}, //QCIF + {320, 240}, //QVGA + {400, 240}, //WQVGA + {352, 288} //CIF +}; + +static void mdelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25000; i++) + __asm__ __volatile__("nop"); + } +} + + +void HAL_Delay(uint32_t Delay){ + mdelay(Delay); +} + + + + +#if 0 +uint8_t OV5640_WR_Reg(uint16_t reg,uint8_t data) +{ + uint8_t res=0; + SCCB_Start(); + if(SCCB_WR_Byte(OV5640_ADDR))res=1; + if(SCCB_WR_Byte(reg>>8))res=1; + if(SCCB_WR_Byte(reg))res=1; + if(SCCB_WR_Byte(data))res=1; + SCCB_Stop(); + return res; +} + + +uint8_t OV5640_RD_Reg(uint16_t reg) +{ + uint8_t val=0; + SCCB_Start(); + SCCB_WR_Byte(OV5640_ADDR); + SCCB_WR_Byte(reg>>8); + SCCB_WR_Byte(reg); + SCCB_Stop(); + + SCCB_Start(); + SCCB_WR_Byte(OV5640_ADDR|0X01); + val=SCCB_RD_Byte(); + SCCB_No_Ack(); + SCCB_Stop(); + return val; +} +#endif + + +uint8_t OV5640_WR_Reg(uint16_t reg,uint8_t data) +{ +// sccb_dev_write_byte(file_ov2640, reg, data); + dvp_sccb_send_data(OV5640_ADDR, reg, data); + return 0; +} + + +uint8_t OV5640_RD_Reg(uint16_t reg) +{ +// return sccb_dev_read_byte(file_ov2640, reg); + return dvp_sccb_receive_data(OV5640_ADDR,reg); +} + +uint8_t OV5640_Init(void) +{ + uint16_t i=0; + uint16_t reg; + + reg=OV5640_RD_Reg(OV5640_CHIPIDH); + reg<<=8; + reg|=OV5640_RD_Reg(OV5640_CHIPIDL); + printf("ID: %X \r\n",reg); + if(reg!=OV5640_ID) + { + printf("ID: %d \r\n",reg); + return 1; + } + + OV5640_WR_Reg(0x3103,0X11); //system clock from pad, bit[1] + OV5640_WR_Reg(0X3008,0X82); + HAL_Delay(10); + + for(i=0;i>8); + OV5640_WR_Reg(0x3809,width&0xff); + OV5640_WR_Reg(0x380a,height>>8); + OV5640_WR_Reg(0x380b,height&0xff); + + OV5640_WR_Reg(0x3810,offx>>8); + OV5640_WR_Reg(0x3811,offx&0xff); + + OV5640_WR_Reg(0x3812,offy>>8); + OV5640_WR_Reg(0x3813,offy&0xff); + + OV5640_WR_Reg(0X3212,0X13); + OV5640_WR_Reg(0X3212,0Xa3); + + return 0; +} + + +uint8_t OV5640_Focus_Init(void) +{ + uint16_t i; + uint16_t addr=0x8000; + uint8_t state=0x8F; + OV5640_WR_Reg(0x3000, 0x20); //reset + for(i=0;i1000)return 1; + }while(state!=0x70); + return 0; +} + +uint8_t OV5640_Auto_Focus(void) +{ + uint8_t temp=0; + uint16_t retry=0; + OV5640_WR_Reg(0x3023,0x01); + OV5640_WR_Reg(0x3022,0x08); + do + { + temp=OV5640_RD_Reg(0x3023); + retry++; + if(retry>1000)return 2; + HAL_Delay(5); + } while(temp!=0x00); + OV5640_WR_Reg(0x3023,0x01); + OV5640_WR_Reg(0x3022,0x04); + retry=0; + do + { + temp=OV5640_RD_Reg(0x3023); + retry++; + if(retry>1000)return 2; + HAL_Delay(5); + }while(temp!=0x00); + return 0; +} + + +void jpeg_test(uint8_t jpg_size) +{ +// HAL_DCMI_Stop(&hdcmi); + + OV5640_JPEG_Mode(); + OV5640_OutSize_Set(4, 0, jpeg_size_tbl[jpg_size][0],jpeg_size_tbl[jpg_size][1]); + + OV5640_WR_Reg(0x3035,0X41); // slow down OV5640 clocks + OV5640_WR_Reg(0x3036,0x68); +// +// /* DCMI DMA DeInit */ +// HAL_DMA_DeInit(&hdma_dcmi); +// +// /* DCMI DMA Init */ +// /* DCMI Init */ +// hdma_dcmi.Instance = DMA2_Stream1; +// hdma_dcmi.Init.Channel = DMA_CHANNEL_1; +// hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY; +// hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE; +// hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; +// hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; +// hdma_dcmi.Init.Mode = DMA_CIRCULAR; +// hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH; +// hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_ENABLE; +// hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; +// hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE; +// hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE; +// if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK) +// { +// _Error_Handler(__FILE__, __LINE__); +// } +// +// __HAL_LINKDMA(&hdcmi,DMA_Handle,hdma_dcmi); +// +// __HAL_DCMI_ENABLE_IT(&hdcmi,DCMI_IT_FRAME); +// +// /* Start the Camera capture */ +// HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)jpeg_data_buf, jpeg_buf_size/4 ); + +// jpeg_mode = 1; +// + while(1) + { + + } +} + +void rgb565_test(void) +{ +// HAL_DCMI_Stop(&hdcmi); +// +// jpeg_mode = 0; + + OV5640_RGB565_Mode(); +// OV5640_OutSize_Set(4,0, XSIZE , YSIZE); + +// BSP_LCD_Init(); +// BSP_LCD_Clear(LCD_COLOR_BLACK); +// +// /* Set image position */ +// ili9325_SetCursor(0, 0); +// /* Prepare to write GRAM (0x22) */ +// LCD_IO_WriteReg(LCD_REG_34); + +// OV5640_WR_Reg(0x3035,0X51); // slow down OV5640 clocks ,adapt to the refresh rate of the LCD +// OV5640_WR_Reg(0x3036,0X88); +// +// /* DCMI DMA DeInit */ +// HAL_DMA_DeInit(&hdma_dcmi); +// +// /* DCMI DMA Init */ +// /* DCMI Init */ +// hdma_dcmi.Instance = DMA2_Stream1; +// hdma_dcmi.Init.Channel = DMA_CHANNEL_1; +// hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY; +// hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_dcmi.Init.MemInc = DMA_MINC_DISABLE; +// hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; +// hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; +// hdma_dcmi.Init.Mode = DMA_CIRCULAR; +// hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH; +// hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_ENABLE; +// hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; +// hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE; +// hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE; +// if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK) +// { +// _Error_Handler(__FILE__, __LINE__); +// } +// +// __HAL_LINKDMA(&hdcmi,DMA_Handle,hdma_dcmi); +// +// /* Start the Camera capture */ +// HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)LCD_GRAM_ADDRESS, 1); +// +// while(1) +// { + +// } +} + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/region_layer.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/region_layer.c new file mode 100755 index 0000000..44e51f2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/region_layer.c @@ -0,0 +1,361 @@ +#include +#include +#include "fastexp.h" +#include "region_layer.h" + +typedef struct{ + int index; + int class; + float **probs; +} sortable_bbox; + +typedef struct { + volatile float x, y, w, h; +} box; + +typedef struct { + uint32_t class; + uint32_t output_cnt; + float threshold; + float nms; + float *active; + float *softmax; + float *biases; + uint8_t *input_data; + float *output_data; + box *boxes; + float **probs; +} REGION_PARAM; + +#define region_layer_img_w 320 +#define region_layer_img_h 240 +#define region_layer_net_w 320 +#define region_layer_net_h 240 + +#define region_layer_l_h 7 +#define region_layer_l_w 10 + +#define region_layer_l_coords 4 +#define region_layer_l_n 5 +#define region_layer_boxes (region_layer_l_h * region_layer_l_w * region_layer_l_n) // l.w * l.h * l.n + +static volatile REGION_PARAM *region_param; + +static inline void activate_array(float *x, const int n, const uint8_t *input) +{ + for (int i = 0; i < n; ++i) + x[i] = region_param->active[input[i]]; +} + +static inline int entry_index(int location, int entry) +{ + int n = location / (region_layer_l_w * region_layer_l_h); + int loc = location % (region_layer_l_w * region_layer_l_h); + + return n * region_layer_l_w * region_layer_l_h * + (region_layer_l_coords + region_param->class + 1) + + entry * region_layer_l_w * region_layer_l_h + loc; +} + +static inline void softmax(const uint8_t *input, int n, int stride, float *output) +{ + int i; + float e; + float sum = 0; + uint8_t largest_i = input[0]; + int diff; + + for (i = 0; i < n; ++i) { + if (input[i * stride] > largest_i) + largest_i = input[i * stride]; + } + + for (i = 0; i < n; ++i) { + diff = input[i * stride] - largest_i; + e = region_param->softmax[diff + 255]; + sum += e; + output[i * stride] = e; + } + for (i = 0; i < n; ++i) + output[i * stride] /= sum; +} + +static inline void softmax_cpu(const uint8_t *input, int n, int batch, int batch_offset, int groups, int stride, float *output) +{ + int g, b; + + for (b = 0; b < batch; ++b) { + for (g = 0; g < groups; ++g) + softmax(input + b * batch_offset + g, n, stride, output + b * batch_offset + g); + } +} + +static inline void forward_region_layer(const uint8_t *input, float *output) +{ + int n, index; + + for (n = 0; n < region_layer_l_n; ++n) { + index = entry_index(n * region_layer_l_w * region_layer_l_h, 0); + activate_array(output + index, 2 * region_layer_l_w * region_layer_l_h, input + index); + index = entry_index(n * region_layer_l_w * region_layer_l_h, 4); + activate_array(output + index, region_layer_l_w * region_layer_l_h, input + index); + } + + index = entry_index(0, 5); + softmax_cpu(input + index, region_param->class, region_layer_l_n, + region_param->output_cnt / region_layer_l_n, + region_layer_l_w * region_layer_l_h, + region_layer_l_w * region_layer_l_h, output + index); +} + +static inline void correct_region_boxes(box *boxes) +{ + int new_w = 0; + int new_h = 0; + + if (((float)region_layer_net_w / region_layer_img_w) < + ((float)region_layer_net_h / region_layer_img_h)) { + new_w = region_layer_net_w; + new_h = (region_layer_img_h * region_layer_net_w) / region_layer_img_w; + } else { + new_h = region_layer_net_h; + new_w = (region_layer_img_w * region_layer_net_h) / region_layer_img_h; + } + for (int i = 0; i < region_layer_boxes; ++i) { + box b = boxes[i]; + + b.x = (b.x - (region_layer_net_w - new_w) / 2. / region_layer_net_w) / + ((float)new_w / region_layer_net_w); + b.y = (b.y - (region_layer_net_h - new_h) / 2. / region_layer_net_h) / + ((float)new_h / region_layer_net_h); + b.w *= (float)region_layer_net_w / new_w; + b.h *= (float)region_layer_net_h / new_h; + boxes[i] = b; + } +} + +static inline box get_region_box(float *x, const float *biases, int n, int index, int i, int j, int w, int h, int stride) +{ + box b; + + b.x = (i + x[index + 0 * stride]) / w; + b.y = (j + x[index + 1 * stride]) / h; + b.w = expf(x[index + 2 * stride]) * biases[2 * n] / w; + b.h = expf(x[index + 3 * stride]) * biases[2 * n + 1] / h; + return b; +} + +static inline void get_region_boxes(float *predictions, float **probs, box *boxes) +{ + for (int i = 0; i < region_layer_l_w * region_layer_l_h; ++i) { + int row = i / region_layer_l_w; + int col = i % region_layer_l_w; + + for (int n = 0; n < region_layer_l_n; ++n) { + int index = n * region_layer_l_w * region_layer_l_h + i; + + for (int j = 0; j < region_param->class; ++j) + probs[index][j] = 0; + int obj_index = entry_index(n * region_layer_l_w * region_layer_l_h + i, 4); + int box_index = entry_index(n * region_layer_l_w * region_layer_l_h + i, 0); + float scale = predictions[obj_index]; + + boxes[index] = get_region_box( + predictions, region_param->biases, n, box_index, col, row, + region_layer_l_w, region_layer_l_h, + region_layer_l_w * region_layer_l_h); + + float max = 0; + + for (int j = 0; j < region_param->class; ++j) { + int class_index = entry_index(n * region_layer_l_w * region_layer_l_h + i, 5 + j); + float prob = scale * predictions[class_index]; + + probs[index][j] = (prob > region_param->threshold) ? prob : 0; + if (prob > max) + max = prob; + } + probs[index][region_param->class] = max; + } + } + correct_region_boxes(boxes); +} + +static inline int nms_comparator(const void *pa, const void *pb) +{ + sortable_bbox a = *(sortable_bbox *)pa; + sortable_bbox b = *(sortable_bbox *)pb; + float diff = a.probs[a.index][b.class] - b.probs[b.index][b.class]; + + if (diff < 0) + return 1; + else if (diff > 0) + return -1; + return 0; +} + +static inline float overlap(float x1, float w1, float x2, float w2) +{ + float l1 = x1 - w1/2; + float l2 = x2 - w2/2; + float left = l1 > l2 ? l1 : l2; + float r1 = x1 + w1/2; + float r2 = x2 + w2/2; + float right = r1 < r2 ? r1 : r2; + + return right - left; +} + +static inline float box_intersection(box a, box b) +{ + float w = overlap(a.x, a.w, b.x, b.w); + float h = overlap(a.y, a.h, b.y, b.h); + + if (w < 0 || h < 0) + return 0; + return w * h; +} + +static inline float box_union(box a, box b) +{ + float i = box_intersection(a, b); + float u = a.w * a.h + b.w * b.h - i; + + return u; +} + +static inline float box_iou(box a, box b) +{ + return box_intersection(a, b)/box_union(a, b); +} + +static inline void do_nms_sort(box *boxes, float **probs) +{ + int i, j, k; + sortable_bbox s[region_layer_boxes]; + + for (i = 0; i < region_layer_boxes; ++i) { + s[i].index = i; + s[i].class = 0; + s[i].probs = probs; + } + + for (k = 0; k < region_param->class; ++k) { + for (i = 0; i < region_layer_boxes; ++i) + s[i].class = k; + qsort(s, region_layer_boxes, sizeof(sortable_bbox), nms_comparator); + for (i = 0; i < region_layer_boxes; ++i) { + if (probs[s[i].index][k] == 0) + continue; + box a = boxes[s[i].index]; + + for (j = i+1; j < region_layer_boxes; ++j) { + box b = boxes[s[j].index]; + + if (box_iou(a, b) > region_param->nms) + probs[s[j].index][k] = 0; + } + } + } +} + +static inline int max_index(float *a, int n) +{ + int i, max_i = 0; + float max = a[0]; + + for (i = 1; i < n; ++i) { + if (a[i] > max) { + max = a[i]; + max_i = i; + } + } + return max_i; +} + +int region_layer_init(REGION_CFG *cfg) +{ + void *ptr; + + ptr = malloc(sizeof(REGION_PARAM)); + if (ptr == NULL) + return 1; + region_param = (REGION_PARAM *)ptr; + region_param->class = cfg->class; + region_param->threshold = cfg->threshold; + region_param->nms = cfg->nms; + region_param->active = cfg->active; + region_param->softmax = cfg->softmax; + region_param->biases = cfg->biases; + region_param->output_cnt = (region_layer_boxes * (region_param->class + region_layer_l_coords + 1)); + cfg->input_len = region_param->output_cnt; + ptr = malloc(sizeof(uint8_t) * region_param->output_cnt + 63); + if (ptr == NULL) + return 1; + region_param->input_data = (uint8_t *)(((uint32_t)ptr + 63) & 0xFFFFFFC0); + cfg->input = region_param->input_data; + //TODO fix + // ptr = malloc(sizeof(float) * region_param->output_cnt); + // if (ptr == NULL) + // return 1; + // region_param->output_data = (float *)ptr; + ptr = malloc(sizeof(float *) * region_layer_boxes); + if (ptr == NULL) + return 1; + region_param->probs = (float **)ptr; + for (uint32_t i = 0; i < region_layer_boxes; i++) { + ptr = malloc(sizeof(float) * (region_param->class + 1)); + if (ptr == NULL) + return 1; + region_param->probs[i] = (float *)ptr; + } + ptr = malloc(sizeof(box) * region_layer_boxes); + if (ptr == NULL) + return 1; + region_param->boxes = (box *)ptr; + return 0; +} +//TODO fix +static float output[2100]; +void region_layer_cal_first(void) +{ + forward_region_layer(region_param->input_data, output); +} + +void region_layer_cal_second(void) +{ + get_region_boxes(output, region_param->probs, region_param->boxes); + do_nms_sort(region_param->boxes, region_param->probs); +} + +void region_layer_detect_object(OBJECT_INFO *info) +{ + uint16_t index = 0; + + for (int i = 0; i < region_layer_boxes; ++i) { + int class = max_index(region_param->probs[i], region_param->class); + float prob = region_param->probs[i][class]; + + if (prob > region_param->threshold) { + box *b = region_param->boxes + i; + uint32_t x1 = b->x * region_layer_img_w - + (b->w * region_layer_img_w / 2); + uint32_t y1 = b->y * region_layer_img_h - + (b->h * region_layer_img_h / 2); + uint32_t x2 = b->x * region_layer_img_w + + (b->w * region_layer_img_w / 2); + uint32_t y2 = b->y * region_layer_img_h + + (b->h * region_layer_img_h / 2); + info->object[index].class = class; + info->object[index].prob = prob * 100; + info->object[index].x1 = x1 < region_layer_img_w ? x1 : region_layer_img_w -1; + info->object[index].x2 = x2 < region_layer_img_w ? x2 : region_layer_img_w -1; + info->object[index].y1 = y1 < region_layer_img_h ? y1 : region_layer_img_h -1; + info->object[index].y2 = y2 < region_layer_img_h ? y2 : region_layer_img_h -1; + index++; + if (index == 20) + break; + } + } + info->object_num = index; +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/st7789.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/st7789.c new file mode 100755 index 0000000..71da884 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/st7789.c @@ -0,0 +1,236 @@ +#include "st7789.h" +#include "sysctl.h" +#include "fpioa.h" +#include "gpiohs.h" +#include "spi.h" +#include "dmac.h" +#include "plic.h" +#include +#include + +#define SPI_CHANNEL 0 +#define SPI_DMA_CHANNEL 0 +#define SPI_SLAVE_SELECT 3 + +#define __SPI_SYSCTL(x, y) SYSCTL_##x##_SPI##y +#define _SPI_SYSCTL(x, y) __SPI_SYSCTL(x, y) +#define SPI_SYSCTL(x) _SPI_SYSCTL(x, SPI_CHANNEL) +#define __SPI_SS(x, y) FUNC_SPI##x##_SS##y +#define _SPI_SS(x, y) __SPI_SS(x, y) +#define SPI_SS _SPI_SS(SPI_CHANNEL, SPI_SLAVE_SELECT) +#define __SPI(x, y) FUNC_SPI##x##_##y +#define _SPI(x, y) __SPI(x, y) +#define SPI(x) _SPI(SPI_CHANNEL, x) +#define __SPI_HANDSHAKE(x, y) SYSCTL_DMA_SELECT_SSI##x##_##y##_REQ +#define _SPI_HANDSHAKE(x, y) __SPI_HANDSHAKE(x, y) +#define SPI_HANDSHAKE(x) _SPI_HANDSHAKE(SPI_CHANNEL, x) +#define __SPI_DMA_INTERRUPT(x) IRQN_DMA##x##_INTERRUPT +#define _SPI_DMA_INTERRUPT(x) __SPI_DMA_INTERRUPT(x) +#define SPI_DMA_INTERRUPT _SPI_DMA_INTERRUPT(SPI_DMA_CHANNEL) + + +/** + *lcd_cs 36 + *lcd_rst 37 + *lcd_dc 38 + *lcd_wr 39 + * */ + +static int dma_finish_irq(void *ctx); + +static volatile uint8_t tft_status; + +static void init_rst(void) +{ + //fpioa_set_function(37, FUNC_GPIOHS0 + 10);//rst + gpiohs_set_drive_mode(10, GPIO_DM_OUTPUT); + gpiohs_set_pin(10, GPIO_PV_LOW); +} + +void set_rst_value(uint8_t val) +{ + if(val) + gpiohs_set_pin(10, 1); //rst high + else + gpiohs_set_pin(10, 0); //rst low +} + +// init hardware +void tft_hard_init(void) +{ + sysctl->misc.spi_dvp_data_enable = 1; //SPI_D0....D7 output + + //fpioa_set_function(38, FUNC_GPIOHS2);//dc + gpiohs->output_en.u32[0] |= 0x00000004; + + sysctl_reset(SPI_SYSCTL(RESET)); + sysctl_clock_set_threshold(SPI_SYSCTL(THRESHOLD), 0); //pll0/2 + sysctl_clock_enable(SPI_SYSCTL(CLOCK)); + + //fpioa_set_function(36, SPI_SS); + //fpioa_set_function(39, SPI(SCLK)); + + init_rst(); + set_rst_value(0); + msleep(100); + set_rst_value(1); + + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; + spi[SPI_CHANNEL]->endian = 0x00; + spi[SPI_CHANNEL]->ctrlr0 = 0x00670180; + spi[SPI_CHANNEL]->baudr = 10; + spi[SPI_CHANNEL]->imr = 0x00; + spi[SPI_CHANNEL]->spi_ctrlr0 = 0x0202; + spi[SPI_CHANNEL]->dmacr = 0x02; + spi[SPI_CHANNEL]->dmatdlr = 0x0F; + sysctl_dma_select(SPI_DMA_CHANNEL, SPI_HANDSHAKE(TX)); + dmac->channel[SPI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)2 << 11) | ((uint64_t)2 << 8) | + ((uint64_t)1 << 6)); + dmac->channel[SPI_DMA_CHANNEL].cfg = (((uint64_t)4 << 49) | ((uint64_t)SPI_DMA_CHANNEL << 44) | + ((uint64_t)SPI_DMA_CHANNEL << 39) | ((uint64_t)1 << 32)); + dmac->channel[SPI_DMA_CHANNEL].intstatus_en = 0x02; +} + +void tft_set_datawidth(uint8_t width) +{ + if (width == 32) { + spi[SPI_CHANNEL]->ctrlr0 = 0x007F0180; + spi[SPI_CHANNEL]->spi_ctrlr0 = 0x22; + } else if (width == 16) { + spi[SPI_CHANNEL]->ctrlr0 = 0x006F0180; + spi[SPI_CHANNEL]->spi_ctrlr0 = 0x0302; + } else { + spi[SPI_CHANNEL]->ctrlr0 = 0x00670180; + spi[SPI_CHANNEL]->spi_ctrlr0 = 0x0202; + } +} + +// command write +void tft_write_command(uint8_t cmd) +{ + gpiohs->output_val.bits.b2 = 0; + spi[SPI_CHANNEL]->ssienr = 0x01; + spi[SPI_CHANNEL]->dr[0] = cmd; + spi[SPI_CHANNEL]->ser = 0x01 << SPI_SLAVE_SELECT; + while ((spi[SPI_CHANNEL]->sr & 0x05) != 0x04) + ; + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; +} + +// data write +void tft_write_byte(uint8_t *data_buf, uint32_t length) +{ + uint32_t index, fifo_len; + + gpiohs->output_val.bits.b2 = 1; + spi[SPI_CHANNEL]->ssienr = 0x01; + fifo_len = length < 32 ? length : 32; + for (index = 0; index < fifo_len; index++) + spi[SPI_CHANNEL]->dr[0] = *data_buf++; + length -= fifo_len; + spi[SPI_CHANNEL]->ser = 0x01 << SPI_SLAVE_SELECT; + while (length) { + fifo_len = 32 - spi[SPI_CHANNEL]->txflr; + fifo_len = fifo_len < length ? fifo_len : length; + for (index = 0; index < fifo_len; index++) + spi[SPI_CHANNEL]->dr[0] = *data_buf++; + length -= fifo_len; + } + while ((spi[SPI_CHANNEL]->sr & 0x05) != 0x04) + ; + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; +} + +// data write +void tft_write_half(uint16_t *data_buf, uint32_t length) +{ + uint32_t index, fifo_len; + + gpiohs->output_val.bits.b2 = 1; + spi[SPI_CHANNEL]->ssienr = 0x01; + fifo_len = length < 32 ? length : 32; + for (index = 0; index < fifo_len; index++) + spi[SPI_CHANNEL]->dr[0] = *data_buf++; + length -= fifo_len; + spi[SPI_CHANNEL]->ser = 0x01 << SPI_SLAVE_SELECT; + while (length) { + fifo_len = 32 - spi[SPI_CHANNEL]->txflr; + fifo_len = fifo_len < length ? fifo_len : length; + for (index = 0; index < fifo_len; index++) + spi[SPI_CHANNEL]->dr[0] = *data_buf++; + length -= fifo_len; + } + while ((spi[SPI_CHANNEL]->sr & 0x05) != 0x04) + ; + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; +} + +// data write +void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag) +{ + gpiohs->output_val.bits.b2 = 1; + if (flag & 0x01) + dmac->channel[SPI_DMA_CHANNEL].ctl |= (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)2 << 11) | ((uint64_t)2 << 8) | + ((uint64_t)1 << 6) | ((uint64_t)1 << 4)); + else + dmac->channel[SPI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)2 << 11) | ((uint64_t)2 << 8) | + ((uint64_t)1 << 6)); + dmac->channel[SPI_DMA_CHANNEL].sar = (uint64_t)data_buf; + dmac->channel[SPI_DMA_CHANNEL].dar = (uint64_t)(&spi[SPI_CHANNEL]->dr[0]); + dmac->channel[SPI_DMA_CHANNEL].block_ts = length - 1; + dmac->channel[SPI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + spi[SPI_CHANNEL]->ssienr = 0x01; + spi[SPI_CHANNEL]->ser = 0x01 << SPI_SLAVE_SELECT; + if (flag & 0x02) { + plic_irq_deregister(SPI_DMA_INTERRUPT); + plic_irq_enable(SPI_DMA_INTERRUPT); + plic_set_priority(SPI_DMA_INTERRUPT, 3); + plic_irq_register(SPI_DMA_INTERRUPT, dma_finish_irq, 0); + tft_status = 1; + dmac->chen = 0x0101 << SPI_DMA_CHANNEL; + return; + } + dmac->chen = 0x0101 << SPI_DMA_CHANNEL; + while ((dmac->channel[SPI_DMA_CHANNEL].intstatus & 0x02) == 0) + ; + while ((spi[SPI_CHANNEL]->sr & 0x05) != 0x04) + ; + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; +} + +static int dma_finish_irq(void *ctx) +{ + dmac->channel[SPI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + tft_status = 2; + return 0; +} + +int tft_busy(void) +{ + if (tft_status == 2) { + plic_irq_disable(SPI_DMA_INTERRUPT); + tft_status = 3; + } else if (tft_status == 3) { + if ((spi[SPI_CHANNEL]->sr & 0x05) == 0x04) { + tft_status = 0; + spi[SPI_CHANNEL]->ser = 0x00; + spi[SPI_CHANNEL]->ssienr = 0x00; + } + } + return tft_status; +} + diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/uart_core.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/uart_core.c new file mode 100755 index 0000000..5194e50 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/uart_core.c @@ -0,0 +1,48 @@ +#include +#include "py/mpconfig.h" +#include "uarths.h" +#include "sleep.h" + +#include "py/runtime.h" +#include "extmod/misc.h" +#include "lib/utils/pyexec.h" + +#include "uart.h" +#include "uarths.h" + +/* + * Core UART functions to implement for a port + */ + +// Receive single character +int mp_hal_stdin_rx_chr(void) { + unsigned char c = 0xff; + while(c == 0xff) + { + c = (char)uarths_getc(); + } + //uarths_receive_data(&c,1); + return c; +} +void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); +const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + mp_uint_t i; + for(i = 0;i < len; i++) + { + uarths_putchar(*str); + str++; + } + //uarths_send_data(str,len); +} +void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) { + (void)env; + while (len--) { + if (*str == '\n') { + uarths_putchar('\r'); + } + uarths_putchar( *str++); + } +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/w25qxx.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/w25qxx.c new file mode 100755 index 0000000..3ec995c --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/w25qxx.c @@ -0,0 +1,660 @@ +#include "w25qxx.h" +#include "fpioa.h" +#include "spi.h" +#include "sysctl.h" +#include "dmac.h" + +/* clang-format off */ +#define SPI_SLAVE_SELECT (0x01) + +#define w25qxx_FLASH_PAGE_SIZE 256 +#define w25qxx_FLASH_SECTOR_SIZE 4096 +#define w25qxx_FLASH_PAGE_NUM_PER_SECTOR 16 +#define w25qxx_FLASH_CHIP_SIZE (16777216 UL) + +#define WRITE_ENABLE 0x06 +#define WRITE_DISABLE 0x04 +#define READ_REG1 0x05 +#define READ_REG2 0x35 +#define READ_REG3 0x15 +#define WRITE_REG1 0x01 +#define WRITE_REG2 0x31 +#define WRITE_REG3 0x11 +#define READ_DATA 0x03 +#define FAST_READ 0x0B +#define FAST_READ_DUAL_OUTPUT 0x3B +#define FAST_READ_QUAL_OUTPUT 0x6B +#define FAST_READ_DUAL_IO 0xBB +#define FAST_READ_QUAL_IO 0xEB +#define DUAL_READ_RESET 0xFFFF +#define QUAL_READ_RESET 0xFF +#define PAGE_PROGRAM 0x02 +#define QUAD_PAGE_PROGRAM 0x32 +#define SECTOR_ERASE 0x20 +#define BLOCK_32K_ERASE 0x52 +#define BLOCK_64K_ERASE 0xD8 +#define CHIP_ERASE 0x60 +#define READ_ID 0x90 +#define ENABLE_QPI 0x38 +#define EXIT_QPI 0xFF +#define ENABLE_RESET 0x66 +#define RESET_DEVICE 0x99 + +#define REG1_BUSY_MASK 0x01 +#define REG2_QUAL_MASK 0x02 + +#define LETOBE(x) ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24)) +/* clang-format on */ + +#define SPI_DMA_CHANNEL 2 +enum w25qxx_status_t (*w25qxx_page_program_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length); +enum w25qxx_status_t (*w25qxx_read_fun)(uint32_t addr, uint8_t *data_buf, uint32_t length); + +static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length); +static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length); + +static volatile spi_t *spi_handle; +static uint8_t dfs_offset, tmod_offset, frf_offset, dma_tx_line, dma_rx_line; + +static enum w25qxx_status_t w25qxx_receive_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + uint32_t index, fifo_len; + spi_handle->ctrlr0 = (0x07 << dfs_offset) | (0x03 << tmod_offset); + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + spi_handle->ser = SPI_SLAVE_SELECT; + while (rx_len) { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + for (index = 0; index < fifo_len; index++) + *rx_buff++ = spi_handle->dr[0]; + rx_len -= fifo_len; + } + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data(uint8_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + uint32_t index, fifo_len; + + spi_handle->ctrlr0 = (0x07 << dfs_offset) | (0x01 << tmod_offset); + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + spi_handle->ser = SPI_SLAVE_SELECT; + while (tx_len) { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_receive_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *rx_buff, uint32_t rx_len) +{ + uint32_t index, fifo_len; + + spi_handle->ctrlr1 = rx_len - 1; + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + spi_handle->ser = SPI_SLAVE_SELECT; + while (rx_len) { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < rx_len ? fifo_len : rx_len; + for (index = 0; index < fifo_len; index++) + *rx_buff++ = spi_handle->dr[0]; + rx_len -= fifo_len; + } + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_send_data_enhanced(uint32_t *cmd_buff, uint8_t cmd_len, uint8_t *tx_buff, uint32_t tx_len) +{ + uint32_t index, fifo_len; + + spi_handle->ssienr = 0x01; + while (cmd_len--) + spi_handle->dr[0] = *cmd_buff++; + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + spi_handle->ser = SPI_SLAVE_SELECT; + while (tx_len) { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *tx_buff++; + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_init(uint8_t spi_index) +{ + uint8_t data[2] = {0xFF, 0xFF}; + + sysctl_clock_enable(SYSCTL_CLOCK_FPIOA); + if (spi_index == 0) { + sysctl_reset(SYSCTL_RESET_SPI0); + sysctl_clock_enable(SYSCTL_CLOCK_SPI0); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0, 0); + fpioa_set_function(27, FUNC_SPI0_SS0); + fpioa_set_function(24, FUNC_SPI0_SCLK); + fpioa_set_function(26, FUNC_SPI0_D0); + fpioa_set_function(25, FUNC_SPI0_D1); + fpioa_set_function(23, FUNC_SPI0_D2); + fpioa_set_function(22, FUNC_SPI0_D3); + spi_handle = spi[0]; + dfs_offset = 16; + tmod_offset = 8; + frf_offset = 21; + dma_rx_line = 0; + dma_tx_line = 1; + } else if (spi_index == 1) { + sysctl_reset(SYSCTL_RESET_SPI1); + sysctl_clock_enable(SYSCTL_CLOCK_SPI1); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI1, 0); + fpioa_set_function(27, FUNC_SPI1_SS0); + fpioa_set_function(24, FUNC_SPI1_SCLK); + fpioa_set_function(26, FUNC_SPI1_D0); + fpioa_set_function(25, FUNC_SPI1_D1); + fpioa_set_function(23, FUNC_SPI1_D2); + fpioa_set_function(22, FUNC_SPI1_D3); + spi_handle = spi[1]; + dfs_offset = 16; + tmod_offset = 8; + frf_offset = 21; + dma_rx_line = 2; + dma_tx_line = 3; + } else { + sysctl->clk_sel0.spi3_clk_sel = 1; + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI3, 4); + sysctl_clock_enable(SYSCTL_CLOCK_SPI3); + sysctl->peri.spi3_xip_en = 0; + spi_handle = spi[3]; + dfs_offset = 0; + tmod_offset = 10; + frf_offset = 22; + dma_rx_line = 6; + dma_tx_line = 7; + } + + spi_handle->baudr = 0x0A; + spi_handle->imr = 0x00; + spi_handle->dmatdlr = 0x10; + spi_handle->dmardlr = 0x0F; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + + w25qxx_page_program_fun = w25qxx_page_program; + w25qxx_read_fun = w25qxx_stand_read_data; + w25qxx_send_data(data, 2, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id) +{ + uint8_t cmd[4] = {READ_ID, 0x00, 0x00, 0x00}; + uint8_t data[2]; + + w25qxx_receive_data(cmd, 4, data, 2); + *manuf_id = data[0]; + *device_id = data[1]; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_write_enable(void) +{ + uint8_t cmd[1] = {WRITE_ENABLE}; + + w25qxx_send_data(cmd, 1, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_status_reg(uint8_t reg1_data, uint8_t reg2_data) +{ + uint8_t cmd[3] = {WRITE_REG1, reg1_data, reg2_data}; + + w25qxx_write_enable(); + w25qxx_send_data(cmd, 3, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg1(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG1}; + uint8_t data[1]; + + w25qxx_receive_data(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_status_reg2(uint8_t *reg_data) +{ + uint8_t cmd[1] = {READ_REG2}; + uint8_t data[1]; + + w25qxx_receive_data(cmd, 1, data, 1); + *reg_data = data[0]; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_is_busy(void) +{ + uint8_t status; + + w25qxx_read_status_reg1(&status); + if (status & REG1_BUSY_MASK) + return W25QXX_BUSY; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr) +{ + uint8_t cmd[4] = {SECTOR_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_32k_block_erase(uint32_t addr) +{ + uint8_t cmd[4] = {BLOCK_32K_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_64k_block_erase(uint32_t addr) +{ + uint8_t cmd[4] = {BLOCK_64K_ERASE}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_chip_erase(void) +{ + uint8_t cmd[1] = {CHIP_ERASE}; + + w25qxx_write_enable(); + w25qxx_send_data(cmd, 1, 0, 0); + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_enable_quad_mode(void) +{ + uint8_t reg_data; + + w25qxx_read_status_reg2(®_data); + if (!(reg_data & REG2_QUAL_MASK)) { + reg_data |= REG2_QUAL_MASK; + w25qxx_write_status_reg(0x00, reg_data); + } + w25qxx_page_program_fun = w25qxx_quad_page_program; + w25qxx_read_fun = w25qxx_quad_read_data; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_disable_quad_mode(void) +{ + uint8_t reg_data; + + w25qxx_read_status_reg2(®_data); + if (reg_data & REG2_QUAL_MASK) { + reg_data &= (~REG2_QUAL_MASK); + w25qxx_write_status_reg(0x00, reg_data); + } + w25qxx_page_program_fun = w25qxx_page_program; + w25qxx_read_fun = w25qxx_stand_read_data; + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint8_t cmd[4] = {PAGE_PROGRAM}; + + cmd[1] = (uint8_t)(addr >> 16); + cmd[2] = (uint8_t)(addr >> 8); + cmd[3] = (uint8_t)(addr); + w25qxx_write_enable(); + w25qxx_send_data(cmd, 4, data_buf, length); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_quad_page_program(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t cmd[2]; + + cmd[0] = QUAD_PAGE_PROGRAM; + cmd[1] = addr; + w25qxx_write_enable(); + spi_handle->ctrlr0 = (0x01 << tmod_offset) | (0x07 << dfs_offset) | (0x02 << frf_offset); + spi_handle->spi_ctrlr0 = (0x06 << 2) | (0x02 << 8); + w25qxx_send_data_enhanced(cmd, 2, data_buf, length); + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_sector_program(uint32_t addr, uint8_t *data_buf) +{ + uint8_t index; + + for (index = 0; index < w25qxx_FLASH_PAGE_NUM_PER_SECTOR; index++) { + w25qxx_page_program_fun(addr, data_buf, w25qxx_FLASH_PAGE_SIZE); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + addr += w25qxx_FLASH_PAGE_SIZE; + data_buf += w25qxx_FLASH_PAGE_SIZE; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t sector_addr, sector_offset, sector_remain, write_len, index; + uint8_t swap_buf[w25qxx_FLASH_SECTOR_SIZE]; + uint8_t *pread, *pwrite; + + while (length) { + sector_addr = addr & (~(w25qxx_FLASH_SECTOR_SIZE - 1)); + sector_offset = addr & (w25qxx_FLASH_SECTOR_SIZE - 1); + sector_remain = w25qxx_FLASH_SECTOR_SIZE - sector_offset; + write_len = length < sector_remain ? length : sector_remain; + w25qxx_read_fun(sector_addr, swap_buf, w25qxx_FLASH_SECTOR_SIZE); + pread = swap_buf + sector_offset; + pwrite = data_buf; + for (index = 0; index < write_len; index++) { + if ((*pwrite) != ((*pwrite) & (*pread))) { + w25qxx_sector_erase(sector_addr); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + break; + } + pwrite++; + pread++; + } + if (write_len == w25qxx_FLASH_SECTOR_SIZE) + w25qxx_sector_program(sector_addr, data_buf); + else { + pread = swap_buf + sector_offset; + pwrite = data_buf; + for (index = 0; index < write_len; index++) + *pread++ = *pwrite++; + w25qxx_sector_program(sector_addr, swap_buf); + } + length -= write_len; + addr += write_len; + data_buf += write_len; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data_direct(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + uint32_t page_remain, write_len; + + while (length) { + page_remain = w25qxx_FLASH_PAGE_SIZE - (addr & (w25qxx_FLASH_PAGE_SIZE - 1)); + write_len = length < page_remain ? length : page_remain; + w25qxx_page_program_fun(addr, data_buf, write_len); + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + length -= write_len; + addr += write_len; + data_buf += write_len; + } + return W25QXX_OK; +} + +static enum w25qxx_status_t _w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t cmd[2]; + + switch (mode) { + case W25QXX_STANDARD: + *(((uint8_t *)cmd) + 0) = READ_DATA; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + w25qxx_receive_data((uint8_t *)cmd, 4, data_buf, length); + break; + case W25QXX_STANDARD_FAST: + *(((uint8_t *)cmd) + 0) = FAST_READ; + *(((uint8_t *)cmd) + 1) = (uint8_t)(addr >> 16); + *(((uint8_t *)cmd) + 2) = (uint8_t)(addr >> 8); + *(((uint8_t *)cmd) + 3) = (uint8_t)(addr >> 0); + *(((uint8_t *)cmd) + 4) = 0xFF; + w25qxx_receive_data((uint8_t *)cmd, 5, data_buf, length); + break; + case W25QXX_DUAL: + cmd[0] = FAST_READ_DUAL_OUTPUT; + cmd[1] = addr; + spi_handle->ctrlr0 = (0x02 << tmod_offset) | (0x07 << dfs_offset) | (0x01 << frf_offset); + spi_handle->spi_ctrlr0 = (0x06 << 2) | (0x02 << 8) | (0x08 << 11); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_DUAL_FAST: + cmd[0] = FAST_READ_DUAL_IO; + cmd[1] = addr << 8; + spi_handle->ctrlr0 = (0x02 << tmod_offset) | (0x07 << dfs_offset) | (0x01 << frf_offset); + spi_handle->spi_ctrlr0 = (0x08 << 2) | (0x02 << 8) | 0x01; + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_QUAD: + cmd[0] = FAST_READ_QUAL_OUTPUT; + cmd[1] = addr; + spi_handle->ctrlr0 = (0x02 << tmod_offset) | (0x07 << dfs_offset) | (0x02 << frf_offset); + spi_handle->spi_ctrlr0 = (0x06 << 2) | (0x02 << 8) | (0x08 << 11); + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + case W25QXX_QUAD_FAST: + cmd[0] = FAST_READ_QUAL_IO; + cmd[1] = addr << 8; + spi_handle->ctrlr0 = (0x02 << tmod_offset) | (0x07 << dfs_offset) | (0x02 << frf_offset); + spi_handle->spi_ctrlr0 = (0x08 << 2) | (0x02 << 8) | (0x04 << 11) | 0x01; + w25qxx_receive_data_enhanced(cmd, 2, data_buf, length); + break; + } + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length, enum w25qxx_read_t mode) +{ + uint32_t len; + + while (length) { + len = length >= 0x010000 ? 0x010000 : length; + _w25qxx_read_data(addr, data_buf, len, mode); + addr += len; + data_buf += len; + length -= len; + } + return W25QXX_OK; +} + +static enum w25qxx_status_t w25qxx_stand_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + return w25qxx_read_data(addr, data_buf, length, W25QXX_STANDARD_FAST); +} + +static enum w25qxx_status_t w25qxx_quad_read_data(uint32_t addr, uint8_t *data_buf, uint32_t length) +{ + return w25qxx_read_data(addr, data_buf, length, W25QXX_QUAD_FAST); +} + +enum w25qxx_status_t w25qxx_enable_xip_mode(void) +{ + if (spi_handle != spi[3]) + return W25QXX_ERROR; + + spi_handle->xip_ctrl = (0x01 << 29) | (0x02 << 26) | (0x01 << 23) | (0x01 << 22) | (0x04 << 13) | + (0x01 << 12) | (0x02 << 9) | (0x06 << 4) | (0x01 << 2) | 0x02; + spi_handle->xip_incr_inst = 0xEB; + spi_handle->xip_mode_bits = 0x00; + spi_handle->xip_ser = 0x01; + spi_handle->ssienr = 0x01; + sysctl->peri.spi3_xip_en = 1; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_disable_xip_mode(void) +{ + sysctl->peri.spi3_xip_en = 0; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_read_data_dma(uint32_t addr, uint32_t *data_buf, uint32_t length) +{ + uint32_t len; + + if (spi_handle != spi[3]) + spi_handle->endian = 0x01; + spi_handle->baudr = 0x02; + spi_handle->ctrlr0 = (0x02 << tmod_offset) | (0x1F << dfs_offset) | (0x02 << frf_offset); + spi_handle->spi_ctrlr0 = (0x08 << 2) | (0x02 << 8) | (0x04 << 11) | 0x01; + dmac->channel[SPI_DMA_CHANNEL].sar = (uint64_t)(&spi_handle->dr[0]); + dmac->channel[SPI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)2 << 11) | ((uint64_t)2 << 8) | + ((uint64_t)1 << 4)); + dmac->channel[SPI_DMA_CHANNEL].cfg = (((uint64_t)4 << 49) | ((uint64_t)SPI_DMA_CHANNEL << 44) | + ((uint64_t)SPI_DMA_CHANNEL << 39) | ((uint64_t)2 << 32)); + sysctl_dma_select(SPI_DMA_CHANNEL, dma_rx_line); + dmac->channel[SPI_DMA_CHANNEL].intstatus_en = 0xFFFFFFFF; + while (length) { + len = length >= 0x010000 ? 0x010000 : length; + length -= len; + spi_handle->dmacr = 0x01; + spi_handle->ctrlr1 = len - 1; + spi_handle->ssienr = 0x01; + if (spi_handle != spi[3]) { + spi_handle->dr[0] = LETOBE(FAST_READ_QUAL_IO); + spi_handle->dr[0] = LETOBE(addr << 8); + } else { + spi_handle->dr[0] = (FAST_READ_QUAL_IO); + spi_handle->dr[0] = (addr << 8); + } + addr += (len * 4); + if (len > 0x0F) { + dmac->channel[SPI_DMA_CHANNEL].dar = (uint64_t)data_buf; + dmac->channel[SPI_DMA_CHANNEL].block_ts = (len & 0xFFFFFFF0) - 1; + dmac->channel[SPI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + spi_handle->ser = SPI_SLAVE_SELECT; + dmac->chen = 0x0101 << SPI_DMA_CHANNEL; + while ((dmac->channel[SPI_DMA_CHANNEL].intstatus & 0x02) == 0) + ; + data_buf += (len & 0xFFFFFFF0); + len &= 0x0F; + } else + spi_handle->ser = SPI_SLAVE_SELECT; + while ((spi_handle->sr & 0x05) != 0x04) + ; + while (len--) + *data_buf++ = spi_handle->dr[0]; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + spi_handle->dmacr = 0x00; + } + spi_handle->baudr = 0x0A; + if (spi_handle != spi[3]) + spi_handle->endian = 0x00; + return W25QXX_OK; +} + +enum w25qxx_status_t w25qxx_write_data_dma(uint32_t addr, uint32_t *data_buf, uint32_t length) +{ + uint32_t len; + + spi_handle->baudr = 0x02; + dmac->channel[SPI_DMA_CHANNEL].dar = (uint64_t)(&spi_handle->dr[0]); + dmac->channel[SPI_DMA_CHANNEL].ctl = (((uint64_t)1 << 47) | ((uint64_t)15 << 48) | + ((uint64_t)1 << 38) | ((uint64_t)15 << 39) | + ((uint64_t)3 << 18) | ((uint64_t)3 << 14) | + ((uint64_t)2 << 11) | ((uint64_t)2 << 8) | + ((uint64_t)1 << 6)); + dmac->channel[SPI_DMA_CHANNEL].cfg = (((uint64_t)4 << 49) | ((uint64_t)SPI_DMA_CHANNEL << 44) | + ((uint64_t)SPI_DMA_CHANNEL << 39) | ((uint64_t)1 << 32)); + sysctl_dma_select(SPI_DMA_CHANNEL, dma_tx_line); + dmac->channel[SPI_DMA_CHANNEL].intstatus_en = 0xFFFFFFFF; + while (length) { + len = length >= w25qxx_FLASH_PAGE_SIZE / 4 ? w25qxx_FLASH_PAGE_SIZE / 4 : length; + length -= len; + w25qxx_write_enable(); + if (spi_handle != spi[3]) + spi_handle->endian = 0x01; + spi_handle->ctrlr0 = (0x01 << tmod_offset) | (0x1F << dfs_offset) | (0x02 << frf_offset); + spi_handle->spi_ctrlr0 = (0x06 << 2) | (0x02 << 8); + spi_handle->dmacr = 0x02; + spi_handle->ssienr = 0x01; + if (spi_handle != spi[3]) { + spi_handle->dr[0] = LETOBE(QUAD_PAGE_PROGRAM); + spi_handle->dr[0] = LETOBE(addr); + } else { + spi_handle->dr[0] = (QUAD_PAGE_PROGRAM); + spi_handle->dr[0] = (addr); + } + dmac->channel[SPI_DMA_CHANNEL].sar = (uint64_t)data_buf; + dmac->channel[SPI_DMA_CHANNEL].block_ts = len - 1; + dmac->channel[SPI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + dmac->chen = 0x0101 << SPI_DMA_CHANNEL; + addr += (len * 4); + data_buf += len; + len = len >= 16 ? 16 : len; + while (spi_handle->txflr < len) + ; + spi_handle->ser = SPI_SLAVE_SELECT; + while ((dmac->channel[SPI_DMA_CHANNEL].intstatus & 0x02) == 0) + ; + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + spi_handle->dmacr = 0x00; + if (spi_handle != spi[3]) + spi_handle->endian = 0x00; + while (w25qxx_is_busy() == W25QXX_BUSY) + ; + } + spi_handle->baudr = 0x0A; + return W25QXX_OK; +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ws2812b.c b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ws2812b.c new file mode 100755 index 0000000..914c3e5 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/board-drivers/ws2812b.c @@ -0,0 +1,327 @@ +#include +#include "ws2812b.h" +#include "sleep.h" +#include "gpiohs.h" +#include "sysctl.h" +// Change this according to FPIOA, GPIO, and hardware configuration +#define WS2812B_PIN_CLR(gpio_num) gpiohs_set_pin(gpio_num,GPIO_PV_LOW); +#define WS2812B_PIN_SET(gpio_num) gpiohs_set_pin(gpio_num,GPIO_PV_HIGH); + + +volatile static uint16_t ns_300_cnt = 0, ns_800_cnt = 0; + +void init_nop_cnt(void) +{ + uint32_t cpu_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + + float per_nop_ns = 0.0; + + cpu_freq /= 1000000; + per_nop_ns = 1000.0 / cpu_freq; + + printf("per_nop_ns:%f cpu_freq:%dMhz\r\n",per_nop_ns,cpu_freq); + + ns_300_cnt = 300.0 / per_nop_ns; + ns_800_cnt = 800.0 / per_nop_ns; + + printf("ns_300_cnt:%d ns_800_cnt:%d\r\n",ns_300_cnt,ns_800_cnt); +} + + +// The duration / pulse width depends on the CPU clock frequency! +static inline void WS2812B_Tx0(int gpio_num) +{ + WS2812B_PIN_SET(gpio_num); + //13--350ns + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + + + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + + WS2812B_PIN_CLR(gpio_num); + //45--850ns + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); +} + +static inline void WS2812B_Tx1(int gpio_num) +{ + WS2812B_PIN_SET(gpio_num); + //45--850ns + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + + + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + WS2812B_PIN_CLR(gpio_num); + //13--450ns + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); + asm volatile("nop"); +} + +void WS2812B_TxRes(int gpio_num) +{ + WS2812B_PIN_CLR(gpio_num); + usleep(60); +} + + +void WS2812B_SetLedRGB(uint8_t r, uint8_t g, uint8_t b,int gpio_num) +{ + uint64_t frameBuf = (g << 16) | (r << 8) | b; + + for (uint64_t mask = 0x800000; mask > 0; mask >>= 1) { + if (frameBuf & mask) + { + WS2812B_Tx1(gpio_num); + } + else + { + WS2812B_Tx0(gpio_num); + } + } +} + +void WS2812B_SetLednRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t num,int gpio_num) +{ + uint64_t frameBuf = (g << 16) | (r << 8) | b; + uint8_t cnt; + + for(cnt=0;cnt 0; mask >>= 1) + { + if (frameBuf & mask) + WS2812B_Tx1(gpio_num); + else + WS2812B_Tx0(gpio_num); + } + } +} \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/k210-standalone/buildin-py/board_demo.py b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/board_demo.py new file mode 100755 index 0000000..576afc4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/board_demo.py @@ -0,0 +1,8 @@ +import machine + +st7789=machine.st7789() +st7789.init() +ov2640=machine.ov2640() +ov2640.init() +buf=bytearray(320*240*2) +demo=machine.demo_face_detect() diff --git a/src/openmv/src/micropython/ports/k210-standalone/buildin-py/boot.py b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/boot.py new file mode 100755 index 0000000..a90fa11 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/boot.py @@ -0,0 +1,23 @@ +import gc +import platform +import uos +import os +import machine +import common + +# init pin map +pin_init=common.pin_init() +pin_init.init() + +# run usr init.py file +file_list = os.ls() +for i in range(len(file_list)): + if file_list[i] == '/init.py': + import init +ov=machine.ov2640() +ov.init() +st=machine.st7789() +st.init() +demo=machine.demo_face_detect() +demo.init() +buf=bytearray(320*240*2) \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/k210-standalone/buildin-py/common.py b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/common.py new file mode 100755 index 0000000..08a1016 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/common.py @@ -0,0 +1,19 @@ +import machine +class pin_init: + fpioa=machine.fpioa() + def init(self): + self.fpioa.set_function(47,137)#FUNC_CMOS_PCLK + self.fpioa.set_function(46,132)#FUNC_CMOS_XCLK + self.fpioa.set_function(45,136)#FUNC_CMOS_HREF + self.fpioa.set_function(44,134)#FUNC_CMOS_PWDN + self.fpioa.set_function(43,135)#FUNC_CMOS_VSYN + self.fpioa.set_function(42,133)#FUNC_CMOS_RST + self.fpioa.set_function(41,146)#FUNC_SCCB_SCLK + self.fpioa.set_function(40,147)#FUNC_SCCB_SDA + self.fpioa.set_function(37, 34)#FUNC_GPIOHS10 init_rst + self.fpioa.set_function(38, 26)#FUNC_GPIOHS2 tft_hard_init + self.fpioa.set_function(36, 15)#FUNC_SPI0_SS3 tft_hard_init + self.fpioa.set_function(39, 17)#FUNC_SPI0_SCLK tft_hard_init + self.fpioa.set_function(12, 190)#FUNC_TIMER0_TOGGLE1 + self.fpioa.set_function(13, 191)#FUNC_TIMER0_TOGGLE2 + self.fpioa.set_function(14, 192)#FUNC_TIMER0_TOGGLE3 diff --git a/src/openmv/src/micropython/ports/k210-standalone/buildin-py/platform.py b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/platform.py new file mode 100755 index 0000000..08a1016 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/buildin-py/platform.py @@ -0,0 +1,19 @@ +import machine +class pin_init: + fpioa=machine.fpioa() + def init(self): + self.fpioa.set_function(47,137)#FUNC_CMOS_PCLK + self.fpioa.set_function(46,132)#FUNC_CMOS_XCLK + self.fpioa.set_function(45,136)#FUNC_CMOS_HREF + self.fpioa.set_function(44,134)#FUNC_CMOS_PWDN + self.fpioa.set_function(43,135)#FUNC_CMOS_VSYN + self.fpioa.set_function(42,133)#FUNC_CMOS_RST + self.fpioa.set_function(41,146)#FUNC_SCCB_SCLK + self.fpioa.set_function(40,147)#FUNC_SCCB_SDA + self.fpioa.set_function(37, 34)#FUNC_GPIOHS10 init_rst + self.fpioa.set_function(38, 26)#FUNC_GPIOHS2 tft_hard_init + self.fpioa.set_function(36, 15)#FUNC_SPI0_SS3 tft_hard_init + self.fpioa.set_function(39, 17)#FUNC_SPI0_SCLK tft_hard_init + self.fpioa.set_function(12, 190)#FUNC_TIMER0_TOGGLE1 + self.fpioa.set_function(13, 191)#FUNC_TIMER0_TOGGLE2 + self.fpioa.set_function(14, 192)#FUNC_TIMER0_TOGGLE3 diff --git a/src/openmv/src/micropython/ports/k210-standalone/file_io.c b/src/openmv/src/micropython/ports/k210-standalone/file_io.c new file mode 100755 index 0000000..f51b559 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/file_io.c @@ -0,0 +1,343 @@ +#include +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +//#include "extmod/misc.h" +//#include "extmod/vfs.h" +//#include "extmod/vfs_fat.h" +//#include "genhdr/mpversion.h" +#include "py/stream.h" + +#if !MICROPY_VFS +#include "py/lexer.h" +#include "spiffs-port.h" + +const mp_obj_type_t mp_type_vfs_spiffs_textio; +typedef struct _pyb_file_obj_t { + mp_obj_base_t base; + spiffs_file fd; +} pyb_file_obj_t; + +STATIC void file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_printf(print, "", mp_obj_get_type_str(self_in), MP_OBJ_TO_PTR(self_in)); +} + + +STATIC mp_uint_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); + + spiffs_file fd=self->fd; + s32_t ret = SPIFFS_read(&fs, fd, buf, size); + if(ret < 0){ + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + return (mp_uint_t)ret; +} + +STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); + int32_t ret = SPIFFS_write(&fs,self->fd, (uint8_t*)buf, size); + if(ret < 0) + { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + if (ret != size) { + // The FatFS documentation says that this means disk full. + *errcode = MP_ENOSPC; + return MP_STREAM_ERROR; + } + return (mp_uint_t)ret; +} + +STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + pyb_file_obj_t *self = MP_OBJ_TO_PTR(o_in); + + + if (request == MP_STREAM_SEEK) { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)(uintptr_t)arg; + s32_t ret = 0; + + switch (s->whence) { + case 0: // SEEK_SET + ret = SPIFFS_lseek(&fs,self->fd,s->offset,SPIFFS_SEEK_SET); + break; + + case 1: // SEEK_CUR + ret = SPIFFS_lseek(&fs,self->fd,s->offset,SPIFFS_SEEK_CUR); + break; + + case 2: // SEEK_END + ret = SPIFFS_lseek(&fs,self->fd,s->offset,SPIFFS_SEEK_END); + break; + } + + s->offset = ret; + return 0; + + } else if (request == MP_STREAM_FLUSH) { + uint32_t ret = SPIFFS_fflush(&fs,self->fd); + if (ret != 0) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + return 0; + + } else if (request == MP_STREAM_CLOSE) { + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fd > 0) { + int32_t ret = SPIFFS_close(&fs,self->fd); + if (ret != 0) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + } + return 0; + + } else { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + return MP_STREAM_ERROR; +} + + +// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, +// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor +STATIC const mp_arg_t file_open_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, + { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, +}; +#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) + +/*STATIC*/ mp_obj_t file_open(const char* file_name, const mp_obj_type_t *type, mp_arg_val_t *args) { + const char *mode_s = mp_obj_str_get_str(args[1].u_obj); + uint32_t mode = 0; + // TODO make sure only one of r, w, x, a, and b, t are specified + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode |= SPIFFS_O_RDONLY; + break; + case 'w': + mode |= SPIFFS_O_RDWR | SPIFFS_O_CREAT; + break; + case 'x': + mode |= SPIFFS_O_RDWR | SPIFFS_O_CREAT | SPIFFS_O_TRUNC; + break; + case 'a': + mode |= SPIFFS_O_RDWR | SPIFFS_O_APPEND; + break; + case '+': + mode |= SPIFFS_O_RDWR; + break; + #if MICROPY_PY_IO_FILEIO + case 'b': + type = &mp_type_vfs_spiffs_fileio; + break; + #endif + case 't': + type = &mp_type_vfs_spiffs_textio; + break; + } + } + pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t); + o->base.type = type; + uint8_t *temp_obj_patch; + spiffs_file fd; + if(file_name[0]!='/') + { + temp_obj_patch=malloc(strlen(file_name)); + memset(temp_obj_patch,'\0',strlen(file_name)); + strcpy(temp_obj_patch+1,file_name); + temp_obj_patch[0]='/'; + fd = SPIFFS_open(&fs,temp_obj_patch,mode,0); + }else{ + fd = SPIFFS_open(&fs,file_name,mode,0); + } + + if(fd <= 0) + mp_raise_OSError(MP_EIO); + o->fd = fd; + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); + return file_open(NULL, type, arg_vals); +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + // { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + // { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + // { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + // { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + // { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + // { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + // { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +STATIC const mp_stream_p_t fileio_stream_p = { + .read = file_obj_read, + .write = file_obj_write, + .ioctl = file_obj_ioctl, +}; + +const mp_obj_type_t mp_type_vfs_spiffs_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = file_obj_print, + .make_new = file_obj_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +STATIC const mp_stream_p_t textio_stream_p = { + .read = file_obj_read, + .write = file_obj_write, + .ioctl = file_obj_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_vfs_spiffs_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = file_obj_print, + .make_new = file_obj_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +// Note: buffering and encoding args are currently ignored +mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_file, ARG_mode, ARG_encoding }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const char* fileName = mp_obj_str_get_str(args[ARG_file].u_obj); + const mp_obj_type_t* type = &mp_type_vfs_spiffs_textio; + return file_open(fileName,type,args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open); + +/* +// Note: buffering and encoding args are currently ignored +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_file, ARG_mode, ARG_encoding }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const char* fileName = mp_obj_str_get_str(args[ARG_file].u_obj); + const mp_obj_type_t* type = &mp_type_vfs_spiffs_textio; + return file_open(fileName,type,args); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); +*/ + +typedef struct _mp_reader_vfs_t { + mp_obj_t file; + uint16_t len; + uint16_t pos; + byte buf[24]; +} mp_reader_vfs_t; + +STATIC mp_uint_t mp_reader_vfs_readbyte(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; + if (reader->pos >= reader->len) { + if (reader->len < sizeof(reader->buf)) { + return MP_READER_EOF; + } else { + int errcode; + reader->len = mp_stream_rw(reader->file, reader->buf, sizeof(reader->buf), + &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + // TODO handle errors properly + return MP_READER_EOF; + } + if (reader->len == 0) { + return MP_READER_EOF; + } + reader->pos = 0; + } + } + return reader->buf[reader->pos++]; +} + +STATIC void mp_reader_vfs_close(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; + mp_stream_close(reader->file); + m_del_obj(mp_reader_vfs_t, reader); +} + +void mp_reader_new_file(mp_reader_t *reader, const char *filename) { + mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); + rf->file = mp_builtin_open(1, &arg, (mp_map_t*)&mp_const_empty_map); + int errcode; + rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_OSError(errcode); + } + rf->pos = 0; + reader->data = rf; + reader->readbyte = mp_reader_vfs_readbyte; + reader->close = mp_reader_vfs_close; +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_reader_t reader; + mp_reader_new_file(&reader, filename); + return mp_lexer_new(qstr_from_str(filename), reader); +} +/* +mp_import_stat_t mp_import_stat(const char *path) { + uint8_t flag = 0; + //char* path0 = (char*)malloc(FS_PATCH_LENGTH); + //memset(path0,0,FS_PATCH_LENGTH); + //API_FS_RealPath(path,path0); + int32_t fd = SPIFFS_open(&fs,path,SPIFFS_O_RDONLY,0); + if(fd>0) + { + SPIFFS_close(&fs,fd); + return MP_IMPORT_STAT_FILE; + } + spiffs_DIR dir; + if (!SPIFFS_opendir (&fs, path, &dir)) + { + return MP_IMPORT_STAT_DIR; + } + return MP_IMPORT_STAT_NO_EXIST; +} +*/ +#endif //#if !MICROPY_VFS diff --git a/src/openmv/src/micropython/ports/k210-standalone/frozentest.mpy b/src/openmv/src/micropython/ports/k210-standalone/frozentest.mpy new file mode 100755 index 0000000..7c6809b Binary files /dev/null and b/src/openmv/src/micropython/ports/k210-standalone/frozentest.mpy differ diff --git a/src/openmv/src/micropython/ports/k210-standalone/frozentest.py b/src/openmv/src/micropython/ports/k210-standalone/frozentest.py new file mode 100755 index 0000000..0f99b74 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/frozentest.py @@ -0,0 +1,7 @@ +print('uPy') +print('a long string that is not interned') +print('a string that has unicode αβγ chars') +print(b'bytes 1234\x01') +print(123456789) +for i in range(4): + print(i) diff --git a/src/openmv/src/micropython/ports/k210-standalone/help.c b/src/openmv/src/micropython/ports/k210-standalone/help.c new file mode 100755 index 0000000..32c43c4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/help.c @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char kendryte_k210_help_text[] = +"Welcome to MicroPython on the Sipeed Maix One!\n" +"\n" +"For generic online docs please visit http://docs.micropython.org/\n" +"\n" +"Official website : www.sipeed.com\n" +"\n" +"For access to the hardware use the 'machine' module:\n" +"For access to the system use the 'os' module:\n" +"For access to the fpioa use the 'machine.fpioa' module:\n" +"For access to the burner model use the 'machine.burner' module:\n" +"For access to the ov2640 use the 'machine.ov2640' module:\n" +"For access to the pin use the 'machine.pin' module:\n" +"For access to the pwm use the 'machine.pwm' module:\n" +"For access to the spiflash use the 'machine.spiflash' module:\n" +"For access to the st7789 use the 'machine.st7789' module:\n" +"For access to the timer use the 'machine.timer' module:\n" +"For access to the uart use the 'machine.uart' module:\n" +"For access to the uarths use the 'machine.uarths' module:\n" +"For access to the zmodem use the 'machine.zmodem' module:\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +"For a list of available modules, type help('modules')\n" +; diff --git a/src/openmv/src/micropython/ports/k210-standalone/main.c b/src/openmv/src/micropython/ports/k210-standalone/main.c new file mode 100755 index 0000000..9db0b31 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/main.c @@ -0,0 +1,253 @@ +/* Copyright 2018 Canaan Inc. + * + * 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. + */ +//#include +#include +//#include + +#include "sleep.h" +#include "encoding.h" + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "lib/utils/pyexec.h" +#include "fpioa.h" +#include "gpio.h" +#include "lib/mp-readline/readline.h" +#include "timer.h" +#include "sysctl.h" +#include "w25qxx.h" +#include "plic.h" +#include "uarths.h" +#include "lcd.h" +#include "spiffs-port.h" +#include +#define UART_BUF_LENGTH_MAX 269 +#define MPY_HEAP_SIZE 1 * 1024 * 1024 +extern int mp_hal_stdin_rx_chr(void); + + +static char *stack_top; +#if MICROPY_ENABLE_GC +static char heap[MPY_HEAP_SIZE]; +#endif + +void do_str(const char *src, mp_parse_input_kind_t input_kind); +#if 0 +void mpy_main(void) +{ + uint64_t core_id = current_coreid(); + plic_init(); + set_csr(mie, MIP_MEIP); + set_csr(mstatus, MSTATUS_MIE); + if (core_id == 0) + { + sysctl_pll_set_freq(SYSCTL_PLL0,320000000); + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_set_freq(SYSCTL_PLL1,160000000); + uarths_init(); + printf("[lichee]:pll0 freq:%d\r\n",sysctl_clock_get_freq(SYSCTL_CLOCK_PLL0)); + printf("[lichee]:pll1 freq:%d\r\n",sysctl_clock_get_freq(SYSCTL_CLOCK_PLL1)); + sysctl->power_sel.power_mode_sel6 = 1; + sysctl->power_sel.power_mode_sel7 = 1; + //uarths_set_irq(UARTHS_RECEIVE,on_irq_uarths_recv,NULL,1); + //uarths_config(115200,UART_STOP_1); + uarths_init(); + uint8_t manuf_id, device_id; + while (1) { + w25qxx_init(3); + w25qxx_read_id(&manuf_id, &device_id); + if (manuf_id != 0xFF && manuf_id != 0x00 && device_id != 0xFF && device_id != 0x00) + break; + } + w25qxx_enable_quad_mode(); + printf("manuf_id:0x%02x,device_id:0x%02x\n", manuf_id, device_id); + my_spiffs_init(); + int stack_dummy; + stack_top = (char*)&stack_dummy; + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + readline_init0(); + readline_process_char(27); + pyexec_frozen_module("boot.py"); + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + char c = 0; + for (;;) { + //int cnt = read_ringbuff(&c,1); + //if(cnt==0){continue;} + c = (char)uarths_getc(); + if(c == 0xff){continue;} + if(pyexec_event_repl_process_char(c)) { + break; + } + } + #else + pyexec_friendly_repl(); + #endif + mp_deinit(); + msleep(1); + printf("prower off\n"); + return 0; + } + while (1); +} +#else +#define PLL0_OUTPUT_FREQ 600000000UL +#define PLL1_OUTPUT_FREQ 160000000UL +#define PLL2_OUTPUT_FREQ 45158400UL + +static void pll_init() +{ + + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_IN0); + + sysctl_pll_enable(SYSCTL_PLL0); + sysctl_pll_set_freq(SYSCTL_PLL0, PLL0_OUTPUT_FREQ); + //while (sysctl_pll_is_lock(SYSCTL_PLL0) == 0) + // sysctl_pll_clear_slip(SYSCTL_PLL0); + //msdelay(100); + sysctl_clock_enable(SYSCTL_CLOCK_PLL0); + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_ACLK, SYSCTL_SOURCE_PLL0); + //printf("PLL0 output test:(real)%ld (measure)%ld\n", PLL0_OUTPUT_FREQ, PLL0_OUTPUT_FREQ / 16); + + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_set_freq(SYSCTL_PLL1, PLL1_OUTPUT_FREQ); + //while (sysctl_pll_is_lock(SYSCTL_PLL1) == 0) + // sysctl_pll_clear_slip(SYSCTL_PLL1); + + //msdelay(100); + + sysctl_clock_enable(SYSCTL_CLOCK_PLL1); + //printf("PLL1 output test:(real)%ld (measure)%ld\n", PLL1_OUTPUT_FREQ, PLL1_OUTPUT_FREQ / 16); + + sysctl_pll_enable(SYSCTL_PLL2); + sysctl_pll_set_freq(SYSCTL_PLL2, PLL2_OUTPUT_FREQ); + //while (sysctl_pll_is_lock(SYSCTL_PLL2) == 0) + // sysctl_pll_clear_slip(SYSCTL_PLL2); + + //msdelay(100); + sysctl_clock_enable(SYSCTL_CLOCK_PLL2); + //printf("PLL2 output test:(real)%ld (measure)%ld\n", PLL2_OUTPUT_FREQ, PLL2_OUTPUT_FREQ / 16); +} + +void mpy_main(void) +{ + uint64_t core_id = current_coreid(); + if (core_id == 0) + { + /* + sysctl_pll_set_freq(SYSCTL_PLL0,320000000); + sysctl_pll_enable(SYSCTL_PLL1); + sysctl_pll_set_freq(SYSCTL_PLL1,160000000); + printf("[lichee]:pll0 freq:%d\r\n",sysctl_clock_get_freq(SYSCTL_CLOCK_PLL0)); + printf("[lichee]:pll1 freq:%d\r\n",sysctl_clock_get_freq(SYSCTL_CLOCK_PLL1)); + */ + pll_init(); + sysctl->power_sel.power_mode_sel6 = 1; + sysctl->power_sel.power_mode_sel7 = 1; + + uarths_init(); + uint8_t manuf_id, device_id; + while (1) { + w25qxx_init(3); + w25qxx_read_id(&manuf_id, &device_id); + if (manuf_id != 0xFF && manuf_id != 0x00 && device_id != 0xFF && device_id != 0x00) + break; + } + w25qxx_enable_quad_mode(); + printf("manuf_id:0x%02x,device_id:0x%02x\n", manuf_id, device_id); + my_spiffs_init(); + int stack_dummy; + stack_top = (char*)&stack_dummy; + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + readline_init0(); + readline_process_char(27); + pyexec_frozen_module("boot.py"); + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + char c = 0; + for (;;) { + //int cnt = read_ringbuff(&c,1); + //if(cnt==0){continue;} + c = (char)uarths_getc(); + if(c == 0xff){continue;} + if(pyexec_event_repl_process_char(c)) { + break; + } + } + #else + pyexec_friendly_repl(); + #endif + mp_deinit(); + msleep(1); + printf("prower off\n"); + return 0; + } + while (1); +} + +#endif +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + +void nlr_jump_fail(void *val) { + while (1); +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + void *dummy; + gc_collect_start(); + gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_end(); + gc_dump_info(); +} + +#if !MICROPY_DEBUG_PRINTERS +// With MICROPY_DEBUG_PRINTERS disabled DEBUG_printf is not defined but it +// is still needed by esp-open-lwip for debugging output, so define it here. +#include +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); +int DEBUG_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(MICROPY_DEBUG_PRINTER, fmt, ap); + va_end(ap); + return ret; +} +#endif + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpconfigport.h b/src/openmv/src/micropython/ports/k210-standalone/mpconfigport.h new file mode 100755 index 0000000..27b569b --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpconfigport.h @@ -0,0 +1,268 @@ +#include +#include +// options to control how MicroPython is built + +// You can disable the built-in MicroPython compiler by setting the following +// config option to 0. If you do this then you won't get a REPL prompt, but you +// will still be able to execute pre-compiled scripts, compiled with mpy-cross. + +// object representation and NLR handling +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) +#define MICROPY_NLR_SETJMP (1) +#define MICROPY_READER_VFS (0) + +// MCU definition +#define MP_ENDIANNESS_LITTLE (1) +#define MICROPY_NO_ALLOCA (1) + + +// optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_MPZ_BITWISE (1) + + +#define MICROPY_ENABLE_COMPILER (1) + +#define MICROPY_QSTR_BYTES_IN_HASH (1) +#define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) + +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (10) + +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (8) + +#define MICROPY_ENABLE_FINALISER (0) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_HAL_HAS_VT100 (1) + +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_STREAMS_NON_BLOCK (0) +#define MICROPY_STREAMS_POSIX_API (0) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_MODULE_WEAK_LINKS (1) + +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_PERSISTENT_CODE_SAVE (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) + +#define MICROPY_COMP_RETURN_IF_EXPR (1) + +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) + +extern const struct _mp_print_t mp_debug_print; +extern const struct _mp_print_t mp_debug_print; +//#define MICROPY_DEBUG_VERBOSE (1) +#define MICROPY_DEBUG_PRINTER (&mp_debug_print) + + +#define MICROPY_MEM_STATS (1) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_GC_ALLOC_THRESHOLD (1) +#define MICROPY_REPL_EVENT_DRIVEN (1) +#define MICROPY_MALLOC_USES_ALLOCATED_SIZE 200*1024 +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) +#define MICROPY_PY_GC (1) +#define MICROPY_MODULE_FROZEN_STR (0) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT kendryte_k210_help_text +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_BUILTINS_FLOAT (1) + + +// control over Python builtins +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_IO_BYTESIO (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_MODULES (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UTIME_MP_HAL (1) + +//thread todo +//#define MICROPY_PY_THREAD (1) +//#define MICROPY_PY_THREAD_GIL (1) +//#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) + +#define MICROPY_VFS (0) +#define MICROPY_VFS_FAT (0) +#define MP_SSIZE_MAX (0x7fffffff) + +#define _USE_MKFS 1 +#define _FS_READONLY 0 + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj +#define MICROPY_PY_ATTRTUPLE (1) + +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) + + +// extended modules +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UHASHLIB_SHA1 (0) +#define MICROPY_PY_UHASHLIB_SHA256 (0) +#define MICROPY_PY_UCRYPTOLIB (0) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_OS_DUPTERM (0) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_I2C (0) +#define MICROPY_PY_MACHINE_SPI (0) +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (0) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_PY_USSL (0) +#define MICROPY_SSL_MBEDTLS (0) +#define MICROPY_PY_USSL_FINALISER (0) +#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_FRAMEBUF (0) +#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) + +//disable ext str pool +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +// This port is intended to be 32-bit, but unfortunately, int32_t for +// different targets may be defined in different ways - either as int +// or as long. This requires different printf formatting specifiers +// to print such value. So, we avoid int32_t and use int directly. +#define UINT_FMT "%u" +#define INT_FMT "%d" +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size + +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// ext modules +extern const struct _mp_obj_module_t machine_module; +extern const struct _mp_obj_module_t uos_module; +//hutu:omv image module +extern const struct _mp_obj_module_t image_module; +extern const struct _mp_obj_module_t omv_module; + +/*hutu:register omv image module*/ +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module },\ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_image), (mp_obj_t)&image_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_omv), (mp_obj_t)&omv_module }, \ + + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ + + + +// We need to provide a declaration/definition of alloca() +#include + +#define MICROPY_HW_BOARD_NAME "kendryte_demo_board" +#define MICROPY_HW_MCU_NAME "kendryte-k210" +#define MICROPY_PY_SYS_PLATFORM "kendryte_standalone" + +#ifdef __linux__ +#define MICROPY_MIN_USE_STDOUT (1) +#endif + +//#ifdef __thumb__ +//#define MICROPY_MIN_USE_CORTEX_CPU (1) +//#define MICROPY_MIN_USE_STM32_MCU (1) +//#endif + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mphalport.h b/src/openmv/src/micropython/ports/k210-standalone/mphalport.h new file mode 100755 index 0000000..c57e35a --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mphalport.h @@ -0,0 +1,4 @@ +static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; } +static inline void mp_hal_set_interrupt_char(char c) {} + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/modmachine.h b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/modmachine.h new file mode 100755 index 0000000..1039c2d --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/modmachine.h @@ -0,0 +1,23 @@ +#ifndef MICROPY_INCLUDED_K210_MODMACHINE_H +#define MICROPY_INCLUDED_K210_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_uarths_type; +extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_pwm_type; +extern const mp_obj_type_t machine_timer_type; +extern const mp_obj_type_t machine_st7789_type; +extern const mp_obj_type_t machine_ov2640_type; +extern const mp_obj_type_t machine_burner_type; +extern const mp_obj_type_t machine_demo_face_detect_type; +extern const mp_obj_type_t machine_zmodem_type; +extern const mp_obj_type_t machine_spiflash_type; +extern const mp_obj_type_t machine_fpioa_type; +extern const mp_obj_type_t machine_ws2812_type; + +void machine_pins_init(void); +void machine_pins_deinit(void); + +#endif // MICROPY_INCLUDED_K210_MODMACHINE_H diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/rzsz.h b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/rzsz.h new file mode 100755 index 0000000..0bd0312 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/include/rzsz.h @@ -0,0 +1,187 @@ +#pragma once + +/* + * RZSZ . H Manifest constants for ZMODEM + * application to application file transfer protocol + * Copyright 1993 Omen Technology Inc All Rights Reserved + */ + +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator (CRC-16) */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ +#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */ +#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */ +#define ZVHEX 'b' /* HEX frame indicator */ +#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */ +#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */ +#define ZRESC 0176 /* RLE flag/escape character */ +#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */ +#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */ + +/* Frame types (see array "frametypes" in zm.c) */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ZDLE sequences */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* Byte positions within header array */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + + + +/* Parameters for ZRINIT header */ +#define ZRPXWN 8 /* 9th byte in header contains window size/256 */ +#define ZRPXQQ 9 /* 10th to 14th bytes contain quote mask */ +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 01 /* Rx can send and receive true FDX */ +#define CANOVIO 02 /* Rx can receive data during disk I/O */ +#define CANBRK 04 /* Rx can send a break signal */ +#define CANRLE 010 /* Receiver can decode RLE */ +#define CANLZW 020 /* Receiver can uncompress */ +#define CANFC32 040 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0200 /* Receiver expects 8th bit to be escaped */ + +/* Bit Masks for ZRINIT flags byte ZF1 */ +#define CANVHDR 01 /* Variable headers OK */ +#define ZRRQWN 8 /* Receiver specified window size in ZRPXWN */ +#define ZRRQQQ 16 /* Additional control chars to quote in ZRPXQQ */ +#define ZRQNVH (ZRRQWN|ZRRQQQ) /* Variable len hdr reqd to access info */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ +/* Management include options, one of these ored in ZF1 */ +#define ZMSKNOLOC 0200 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZMMASK 037 /* Mask for the choices below */ +#define ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZMCLOB 4 /* Replace existing file */ +#define ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZMPROT 7 /* Protect destination file */ +#define ZMCHNG 8 /* Change filename if destination exists */ +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ +#define ZCANVHDR 01 /* Variable headers OK */ +/* Receiver window size override */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +#define FTOFFSET 4 +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ + +static char *frametypes[] = { + "No Response to Error Correction Request", /* -4 */ + "No Carrier Detect", /* -3 */ + "TIMEOUT", /* -2 */ + "ERROR", /* -1 */ + "ZRQINIT", + "ZRINIT", + "ZSINIT", + "ZACK", + "ZFILE", + "ZSKIP", + "ZNAK", + "ZABORT", + "ZFIN", + "ZRPOS", + "ZDATA", + "ZEOF", + "ZFERR", + "ZCRC", + "ZCHALLENGE", + "ZCOMPL", + "ZCAN", + "ZFREECNT", + "ZCOMMAND", + "ZSTDERR", + "xxxxx" +}; + + + +long rclhdr(); + +/* Globals used by ZMODEM functions */ +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +extern int Rxtype; /* Type of header received */ +extern int Rxcount; /* Count of data bytes received */ +extern int Rxtimeout; /* Tenths of seconds to wait for something */ +extern long Rxpos; /* Received file position */ +extern long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern char *Altcan; /* Alternate canit string */ + +void zinit(); +//int rz(char* fname); +extern int rz(void); +void sz(char* fname); +void zclose(); +void test(); +/* End of rzsz.h */ \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_burner.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_burner.c new file mode 100755 index 0000000..fa85f67 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_burner.c @@ -0,0 +1,198 @@ + +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" + +#include +#include "sysctl.h" +#include "plic.h" +#include "dmac.h" +#include "w25qxx.h" +#include "uarths.h" +#include "fpioa.h" +#include "gpiohs.h" +#include "sleep.h" +#include "lcd.h" + +#define UART_BUF_LENGTH_MAX 269 + +typedef struct _machine_burner_obj_t { + mp_obj_base_t base; + uint32_t burn_uarths_freq; + uint32_t baudrate; +} machine_burner_obj_t; + +typedef struct { + uint8_t *uart_buf; + uint8_t uart_status; + uint8_t flash_status; +} burner_attributes; + +volatile burner_attributes burner_attr; + +const mp_obj_type_t machine_burner_type; + +static int uarths_irq(void *ctx) +{ + static uint16_t cnt, len; + uint8_t *buf = burner_attr.uart_buf; + while (uarths->ip.rxwm == 1) { + buf[cnt++] = uarths->rxdata.data; + if (cnt <= 3) { + if (buf[0] != 0xAA) + cnt = 0; + else if (cnt == 3) { + len = ((uint16_t)buf[1] << 8) | buf[2]; + if (len > UART_BUF_LENGTH_MAX || len < 4) + cnt = 0; + } + } else if (cnt >= len) { + uint8_t sum = 0; + for (cnt = 0; cnt < len - 1; cnt++) + sum += buf[cnt]; + if (buf[len - 1] != sum) { + cnt = 0; + continue; + } else { + uarths->rxctrl.rxen = 0; + burner_attr.uart_status = 1; + cnt = 0; + while (uarths->ip.rxwm == 1) + sum = uarths->rxdata.data; + return 0; + } + } + } + return 0; +} + +void modle_burn(void){ + lcd_draw_string(116, 110, "Burn Model mode", WHITE); + burner_attr.uart_buf = (uint8_t *)malloc(UART_BUF_LENGTH_MAX); + if (burner_attr.uart_buf == NULL) + return; + burner_attr.uart_status = 0; + burner_attr.flash_status = 0; + plic_set_priority(IRQN_UARTHS_INTERRUPT, 1); + plic_irq_register(IRQN_UARTHS_INTERRUPT, uarths_irq, NULL); + plic_irq_enable(IRQN_UARTHS_INTERRUPT); + // system start + //printf("system start\r\n"); + // enable global interrupt + set_csr(mstatus, MSTATUS_MIE); + while (1) { + // wait a valid pack + while (burner_attr.uart_status == 0);//printf("test\n"); + + if (burner_attr.uart_buf[3] == 0x01) { // read status cmd + burner_attr.flash_status = w25qxx_is_busy(); + } else if (burner_attr.uart_buf[3] == 0x02) { // erase cmd + uint32_t addr; + + addr = ((uint32_t)burner_attr.uart_buf[5] << 24) | + ((uint32_t)burner_attr.uart_buf[6] << 16) | + ((uint32_t)burner_attr.uart_buf[7] << 8) | + ((uint32_t)burner_attr.uart_buf[8] << 0); + if (burner_attr.uart_buf[4] == 0x00) + w25qxx_sector_erase(addr); + else if (burner_attr.uart_buf[4] == 0x01) + w25qxx_32k_block_erase(addr); + else + w25qxx_64k_block_erase(addr); + burner_attr.flash_status = 1; + } else if (burner_attr.uart_buf[3] == 0x03) { // write cmd + uint32_t addr, len; + + addr = ((uint32_t)burner_attr.uart_buf[4] << 24) | + ((uint32_t)burner_attr.uart_buf[5] << 16) | + ((uint32_t)burner_attr.uart_buf[6] << 8) | + ((uint32_t)burner_attr.uart_buf[7] << 0); + len = ((uint32_t)burner_attr.uart_buf[8] << 24) | + ((uint32_t)burner_attr.uart_buf[9] << 16) | + ((uint32_t)burner_attr.uart_buf[10] << 8) | + ((uint32_t)burner_attr.uart_buf[11] << 0); + w25qxx_page_program_fun(addr, &burner_attr.uart_buf[12], len); + burner_attr.flash_status = 1; + } else { // invalid cmd + burner_attr.flash_status = 0xFE; + } + burner_attr.uart_buf[0] = 0xAA; + burner_attr.uart_buf[1] = 0x00; + burner_attr.uart_buf[2] = 0x06; + burner_attr.uart_buf[3] = 0x00; + burner_attr.uart_buf[4] = burner_attr.flash_status; + burner_attr.uart_buf[5] = 0x00; + for (uint32_t i = 0; i < 5; i++) + burner_attr.uart_buf[5] += burner_attr.uart_buf[i]; + for (uint32_t i = 0; i < 6; i++) { + while (uarths->txdata.full) + ; + uarths->txdata.data = burner_attr.uart_buf[i]; + } + burner_attr.uart_status = 0; + uarths->rxctrl.rxen = 1; + } +} + +STATIC mp_obj_t machine_burner_start(machine_burner_obj_t *self_in){ + + machine_burner_obj_t* self = self_in; + sysctl_pll_set_freq(SYSCTL_PLL0,self->burn_uarths_freq); + uint32_t freq = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + uint16_t div = freq / self->baudrate - 1; + uarths->div.div = div; + modle_burn(); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_buner_start_obj, machine_burner_start); + +STATIC mp_obj_t machine_burner_init_helper(machine_burner_obj_t *self_in) { + machine_burner_obj_t* self = self_in; + self->burn_uarths_freq = 320000000; + self->baudrate = 1500000; + while (1) { + uint8_t manuf_id, device_id; + w25qxx_init(3); + w25qxx_read_id(&manuf_id, &device_id); + printf("manuf_id:0x%02x,device_id:0x%02x\n", manuf_id, device_id); + if (manuf_id != 0xFF && manuf_id != 0x00 && device_id != 0xFF && device_id != 0x00) + break; + } + w25qxx_enable_quad_mode(); + return mp_const_none; +} + + +STATIC mp_obj_t machine_burner_init(mp_obj_t self_in) { + machine_burner_obj_t* self = self_in; + return machine_burner_init_helper(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_buner_init_obj, machine_burner_init); + + +STATIC mp_obj_t machine_burner_make_new() { + + volatile machine_burner_obj_t *self = m_new_obj(machine_burner_obj_t); + self->base.type = &machine_burner_type; + return self; +} + + +STATIC const mp_rom_map_elem_t pyb_burner_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_buner_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_buner_start_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_burner_locals_dict, pyb_burner_locals_dict_table); + +const mp_obj_type_t machine_burner_type = { + { &mp_type_type }, + .name = MP_QSTR_burner, + .make_new = machine_burner_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_burner_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_face_detect.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_face_detect.c new file mode 100755 index 0000000..a51a0bf --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_face_detect.c @@ -0,0 +1,205 @@ +#include +#include +#include "sysctl.h" +#include "plic.h" +#include "dmac.h" + +#include "py/mphal.h" +#include "py/runtime.h" + +#include "w25qxx.h" +#include "uarths.h" +#include "fpioa.h" +#include "gpiohs.h" +#include "face_detect.h" +#include "sleep.h" + +#define AI_DMA_CHANNEL 1 +#define __AI_DMA_INTERRUPT(x) IRQN_DMA##x##_INTERRUPT +#define _AI_DMA_INTERRUPT(x) __AI_DMA_INTERRUPT(x) +#define AI_DMA_INTERRUPT _AI_DMA_INTERRUPT(AI_DMA_CHANNEL) + +#define K210_DEBUG 0 +#if K210_DEBUG==1 +#define debug_print(x,arg...) printf("[lichee_debug]"x,##arg) +#else +#define debug_print(x,arg...) +#endif + + +typedef struct _machine_ai_obj_t { + mp_obj_base_t base; + uint32_t buf_status; + uint8_t *ai_buf; + uint8_t *image_buf; + uint32_t size; + +} machine_ai_obj_t; + +void ndelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25; i++) + __asm__ __volatile__("nop"); + } +} + +void _mdelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25000; i++) + __asm__ __volatile__("nop"); + } +} + +const mp_obj_type_t machine_demo_face_detect_type; + +static int imge_buf_convert(machine_ai_obj_t* self) +{ + unsigned char* red = NULL; + unsigned char* green = NULL; + unsigned char* blue = NULL; + red = (unsigned char*)self->ai_buf; + green = (unsigned char*)(self->ai_buf+320*240); + blue =(unsigned char*) (self->ai_buf+320*240*2); + int size = self->size; + int i = 0; + uint8_t *src = self->image_buf; + unsigned int twoByte = 0; + for(i = 0; i < size; i += 1) + { + twoByte = (src[1] << 8) + src[0]; + red[i] = (src[1] & 248); + green[i] = (unsigned char)((twoByte & 2016) >> 3); + blue[i] = ((src[0] & 31) * 8); + src += 2; + } + debug_print("imge_buf_convert finish\n"); +} + + +int ai_dma_irq(void *ctx) +{ + machine_ai_obj_t* self = ctx; + //ai_test("ai_dma_irq"); + if (dmac->channel[AI_DMA_CHANNEL].intstatus & 0x02) { + if (self->buf_status == 0) { // convert completed, start ai cal + debug_print("I can enter dma irq self->cal_status == %d\n",self->buf_status); + ai_cal_start(); + self->buf_status = 1; // wait ai cal completed flag + } + else if(self->buf_status == 1){ + debug_print("I can enter dma irq self->cal_status == %d\n",self->buf_status); + self->buf_status = 2; + } + } + dmac->channel[AI_DMA_CHANNEL].intclear = 0xFFFFFFFF; + ndelay(1000); + debug_print("quit ai_dma_irq\n"); + return 0; +} + +STATIC mp_obj_t machine_ai_process_image(mp_obj_t self_in,mp_obj_t buf) { + machine_ai_obj_t* self = self_in; + /*get image buf*/ + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ|MP_BUFFER_WRITE); + self->size = 320*240; + memcpy(self->image_buf,bufinfo.buf, bufinfo.len); + self->buf_status = 0; + /*convert image to rgb888*/ + imge_buf_convert(self); + /*start input dma*/ + ai_data_input((uint32_t)self->ai_buf); + // wait ai cal completed + while(1 != self->buf_status)ndelay(50); + if(1 == self->buf_status) + { + ai_cal_first(); + ai_cal_second(); + ai_data_output(); + } + while(2 != self->buf_status) + { + ndelay(50); + debug_print("whiling\n"); + } + ai_draw_label((uint32_t*)bufinfo.buf); + //memset(bufinfo.buf, 0, bufinfo.len); + debug_print("finish ai_draw_label\n"); + debug_print("finish ai_cal_first\n"); + debug_print("finish process\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_process_image_obj, machine_ai_process_image); + + +STATIC mp_obj_t machine_ai_init_helper(machine_ai_obj_t *self_in) { + machine_ai_obj_t* self = self_in; + void* ptr = NULL; + /*malloc ai buf*/ + ptr = malloc(sizeof(uint8_t) * 320 * 240 * 3 + 127); + if (ptr == NULL) + return; + self->ai_buf = (uint32_t *)(((uint32_t)ptr + 127) & 0xFFFFFF80); + /*malloc image buf*/ + ptr = malloc(sizeof(uint8_t) * 320 * 240 * 2 + 127); + if (ptr == NULL) + return; + self->image_buf = (uint8_t *)(((uint32_t)ptr + 127) & 0xFFFFFF80); + while (1) { + uint8_t manuf_id, device_id; + w25qxx_init(3); + w25qxx_read_id(&manuf_id, &device_id); + printf("manuf_id:0x%02x,device_id:0x%02x\n", manuf_id, device_id); + if (manuf_id != 0xFF && manuf_id != 0x00 && device_id != 0xFF && device_id != 0x00) + break; + } + w25qxx_enable_quad_mode(); + self->buf_status = 0; + if (ai_init(0)) + { + printf("[lichee_error]:ai_init error,please burn a model\n"); + return mp_const_none; + } + plic_irq_register(AI_DMA_INTERRUPT, ai_dma_irq, self); + printf("face detect init!\n"); + return mp_const_none; +} + +STATIC mp_obj_t machine_ai_init(mp_obj_t self_in) { + machine_ai_obj_t* self = self_in; + return machine_ai_init_helper(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_ai_init_obj, machine_ai_init); + + + +STATIC mp_obj_t machine_ai_make_new() { + + volatile machine_ai_obj_t *self = m_new_obj(machine_ai_obj_t); + self->base.type = &machine_demo_face_detect_type; + return self; +} + +STATIC const mp_rom_map_elem_t pyb_ai_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_ai_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_process_image), MP_ROM_PTR(&machine_process_image_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_ai_locals_dict, pyb_ai_locals_dict_table); + +const mp_obj_type_t machine_demo_face_detect_type = { + { &mp_type_type }, + .name = MP_QSTR_face_detect, + .make_new = machine_ai_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_ai_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_fpioa.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_fpioa.c new file mode 100755 index 0000000..ad53a66 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_fpioa.c @@ -0,0 +1,59 @@ + +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/obj.h" +#include "py/objtype.h" +#include "py/objstr.h" +#include "py/objint.h" + +#include "fpioa.h" + +typedef struct _machine_fpioa_obj_t { + mp_obj_base_t base; +} machine_fpioa_obj_t; + +const mp_obj_type_t machine_fpioa_type; + +STATIC mp_obj_t machine_set_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_pin, + ARG_func, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_func, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint16_t pin_num = args[ARG_pin].u_int; + fpioa_function_t func_num = args[ARG_func].u_int; + fpioa_set_function(pin_num,(fpioa_function_t)func_num); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_set_function_obj, 0,machine_set_function); + +STATIC mp_obj_t machine_fpioa_make_new() { + + machine_fpioa_obj_t *self = m_new_obj(machine_fpioa_obj_t); + self->base.type = &machine_fpioa_type; + + return self; +} + +STATIC const mp_rom_map_elem_t pyb_fpioa_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_set_function), MP_ROM_PTR(&machine_set_function_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_fpioa_locals_dict, pyb_fpioa_locals_dict_table); + +const mp_obj_type_t machine_fpioa_type = { + { &mp_type_type }, + .name = MP_QSTR_Fpioa, + .make_new = machine_fpioa_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_fpioa_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ov2640.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ov2640.c new file mode 100755 index 0000000..7e2b62a --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ov2640.c @@ -0,0 +1,266 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "timer.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objtype.h" +#include "mphalport.h" +#include "plic.h" +#include "sysctl.h" +#include "ov2640.h" +#include "ov5640.h" +#include "dvp.h" +#include "fpioa.h" + +#define TIMER_INTR_SEL TIMER_INTR_LEVEL +#define TIMER_DIVIDER 8 + +// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) + +#define TIMER_FLAGS 0 +struct dvp_buf +{ + uint32_t* addr[2]; + uint8_t buf_used[2]; + uint8_t buf_sel; +}; +typedef struct _machine_ov2640_obj_t { + mp_obj_base_t base; + uint32_t active; + uint16_t device_id; + uint16_t manuf_id; + struct dvp_buf buf; + void* ptr; + //mp_uint_t repeat;//timer mode +} machine_ov2640_obj_t; + +const mp_obj_type_t machine_ov2640_type; + +#define K210_DEBUG 0 +#if K210_DEBUG==1 +#define debug_print(x,arg...) printf("[lichee_debug]"x,##arg) +#else +#define debug_print(x,arg...) +#endif +void _ndelay(uint32_t ms) +{ + uint32_t i; + + while (ms && ms--) + { + for (i = 0; i < 25; i++) + __asm__ __volatile__("nop"); + } +} + +static int dvp_irq(void *ctx) +{ + + machine_ov2640_obj_t* self = ctx; + + if (dvp_get_interrupt(DVP_STS_FRAME_FINISH)) { + debug_print("Enter finish dvp_irq\n"); + dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH); + self->buf.buf_used[self->buf.buf_sel] = 1; + self->buf.buf_sel ^= 0x01; + dvp_set_display_addr((uint32_t)self->buf.addr[self->buf.buf_sel]); + } else { + debug_print("Enter start dvp_irq\n"); + dvp_clear_interrupt(DVP_STS_FRAME_START); + if (self->buf.buf_used[self->buf.buf_sel] == 0) + { + dvp_start_convert(); + } + } + debug_print("self->buf.buf_used[0] = %d\n",self->buf.buf_used[0]); + debug_print("self->buf.buf_used[1] = %d\n",self->buf.buf_used[1]); + debug_print("self->buf.buf_sel = %d\n",self->buf.buf_sel); + return 0; +} + +STATIC void machine_ov2640_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_ov2640_obj_t *self = self_in; + + mp_printf(print, "ov2640(%p) ", self); + mp_printf(print, "ov2640 active = %d, ", self->active); + mp_printf(print, "manuf_id=%d, ",self->manuf_id); + mp_printf(print, "device_id=%d", self->device_id); +} + +STATIC mp_obj_t machine_ov2640_make_new() { + + machine_ov2640_obj_t *self = m_new_obj(machine_ov2640_obj_t); + self->base.type = &machine_ov2640_type; + + return self; +} + +STATIC void machine_ov2640_disable(machine_ov2640_obj_t *self) { + sysctl_clock_disable(SYSCTL_CLOCK_DVP); + plic_irq_disable(IRQN_DVP_INTERRUPT); + plic_irq_deregister(IRQN_DVP_INTERRUPT); + dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0); + free(self->ptr); + self->active = 0; +} + +static void dvp_io_init(void) +{ + /* Init DVP IO map and function settings */ + fpioa_set_function(11, FUNC_CMOS_RST);//15 RESET# + fpioa_set_function(13, FUNC_CMOS_PWDN);//17 PWDN + fpioa_set_function(14, FUNC_CMOS_XCLK);//20 XCLK + fpioa_set_function(12, FUNC_CMOS_VSYNC);//18 VSYNC + fpioa_set_function(17, FUNC_CMOS_HREF);//19 HREF + fpioa_set_function(15, FUNC_CMOS_PCLK);//21 PCLK +// fpioa_set_function(24, FUNC_CMOS_D0); +// fpioa_set_function(25, FUNC_CMOS_D1); +// fpioa_set_function(26, FUNC_CMOS_D2); +// fpioa_set_function(27, FUNC_CMOS_D3); +// fpioa_set_function(28, FUNC_CMOS_D4); +// fpioa_set_function(29, FUNC_CMOS_D5); +// fpioa_set_function(33, FUNC_CMOS_D6); +// fpioa_set_function(35, FUNC_CMOS_D7); + fpioa_set_function(10, FUNC_SCCB_SCLK);//22 SIO_C + fpioa_set_function(9, FUNC_SCCB_SDA);//23 SIO_D + +} + + +STATIC mp_obj_t machine_ov2640_init_helper(machine_ov2640_obj_t *self) { +#if 1 + /*init dvp*/ +#if 0 + do { + printf("init ov2640\r\n"); + ov2640_init(); + ov2640_read_id(&self->manuf_id, &self->device_id); + printf("manuf_id:0x%04x,device_id:0x%04x\r\n", self->manuf_id, self->device_id); + } while (self->manuf_id != 0x7FA2 || self->device_id != 0x2642); +#else + dvp_init(16); + dvp_io_init(); + dvp_enable_burst(); + dvp_set_output_enable(0,1); + dvp_set_output_enable(1,1); + dvp_set_image_format(DVP_CFG_RGB_FORMAT); + dvp_set_image_size(320, 240); + do + { + printf("init ov5640\r\n"); + if(0 == OV5640_Init()) + break; + } while(0); +#endif + /*buffer interrupt*/ + void* ptr = NULL; + if(ptr == NULL) + { + ptr = malloc(sizeof(uint8_t) * 320 * 240 * (2 * 2) + 127); + self->ptr = ptr; + } + if (ptr == NULL) + return mp_const_false; + self->buf.addr[0] = (uint32_t *)(((uint32_t)ptr + 127) & 0xFFFFFF80); + self->buf.addr[1] = (uint32_t *)((uint32_t)self->buf.addr[0] + 320 * 240 * 2); + self->buf.buf_used[0] = 0; + self->buf.buf_used[1] = 0; + self->buf.buf_sel = 0; + /*init interrupt*/ + dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0); + dvp_set_display_addr((uint32_t)self->buf.addr[self->buf.buf_sel]); + plic_set_priority(IRQN_DVP_INTERRUPT, 1); + plic_irq_register(IRQN_DVP_INTERRUPT, dvp_irq, self); + plic_irq_enable(IRQN_DVP_INTERRUPT); + /*start interrupt*/ + dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH); + dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1); + + self->active = 1; +#endif + return mp_const_none; +} + + +STATIC mp_obj_t machine_ov2640_deinit(mp_obj_t self_in) { + machine_ov2640_disable(self_in); + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_ov2640_deinit_obj, machine_ov2640_deinit); + + +STATIC mp_obj_t machine_ov2640_get_image(mp_obj_t self_in,mp_obj_t buf) { + machine_ov2640_obj_t* self = self_in; + uint32_t length = 0; + uint8_t* buf_image = 0; + //mp_obj_list_get(buf,&length,&item); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + while(self->buf.buf_used[self->buf.buf_sel] == 0 )_ndelay(50); + memcpy(bufinfo.buf, self->buf.addr[self->buf.buf_sel], bufinfo.len); + self->buf.buf_used[self->buf.buf_sel] = 0; + //printf("[lichee]:get image!\n"); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_ov2640_get_images_obj, machine_ov2640_get_image); + + +STATIC mp_obj_t machine_ov2640_init(mp_obj_t self_in) { + machine_ov2640_obj_t* self = self_in; + return machine_ov2640_init_helper(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_ov2640_init_obj, machine_ov2640_init); + + + +STATIC const mp_rom_map_elem_t machine_ov2640_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_ov2640_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_ov2640_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_ov2640_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_image), MP_ROM_PTR(&machine_ov2640_get_images_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_ov2640_locals_dict, machine_ov2640_locals_dict_table); + +const mp_obj_type_t machine_ov2640_type = { + { &mp_type_type }, + .name = MP_QSTR_ov2640, + .print = machine_ov2640_print, + .make_new = machine_ov2640_make_new, + .locals_dict = (mp_obj_t)&machine_ov2640_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pin.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pin.c new file mode 100755 index 0000000..6162935 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pin.c @@ -0,0 +1,208 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" +#include "gpio.h" + +#define gpio_num_t int +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_obj_t; + +#define GPIO_MAX_PINNO 8 +STATIC const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, 0}, + {{&machine_pin_type}, 1}, + {{&machine_pin_type}, 2}, + {{&machine_pin_type}, 3}, + {{&machine_pin_type}, 4}, + {{&machine_pin_type}, 5}, + {{&machine_pin_type}, 6}, + {{&machine_pin_type}, 7}, +}; + +void machine_pins_init(void) { +} + +void machine_pins_deinit(void) { +} + +gpio_num_t machine_pin_get_id(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &machine_pin_type) { + mp_raise_ValueError("expecting a pin"); + } + machine_pin_obj_t *self = pin_in; + return self->id; +} + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "Pin(%u)", self->id); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // configure the pin for gpio + //gpio_pin_init(size_t pin_num, size_t gpio_pin); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + gpio_set_pin(self->id, mp_obj_is_true(args[ARG_value].u_obj)==0?GPIO_PV_LOW:GPIO_PV_HIGH); + } + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (self->id >= GPIO_MAX_PINNO && (pin_io_mode >GPIO_DM_OUTPUT) && (pin_io_mode id, pin_io_mode); + } + } + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + const machine_pin_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) { + self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin]; + } + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_pin(self->id)); + } else { + // set pin + gpio_set_pin(self->id, mp_obj_is_true(args[0])==0?GPIO_PV_LOW:GPIO_PV_HIGH); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// pin.toggle(pinnum) +STATIC mp_obj_t machine_pin_toggle(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // err + mp_raise_ValueError("please input pin num"); + } else { + // set pin + gpio_set_pin(mp_obj_get_int(args[0]), !gpio_get_pin(mp_obj_get_int(args[0]))); + return MP_OBJ_NEW_SMALL_INT(gpio_get_pin(mp_obj_get_int(args[0]))); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_toggle_obj, 1, 1, machine_pin_toggle); + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) }, +}; + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return gpio_get_pin(self->id); + } + case MP_PIN_WRITE: { + gpio_set_pin(self->id, arg==0?GPIO_PV_LOW:GPIO_PV_HIGH); + return 0; + } + } + return -1; +} + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pwm.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pwm.c new file mode 100755 index 0000000..27a0617 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_pwm.c @@ -0,0 +1,205 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" +#include "pwm.h" +#include "fpioa.h" +#include "mpconfigport.h" +// Forward dec'l +extern const mp_obj_type_t machine_pwm_type; + +typedef struct _k210_pwm_obj_t { + mp_obj_base_t base; + int pin_num; + int tim; + int channel; + uint8_t active; + int freq_hz; + int duty; +} k210_pwm_obj_t; + + +/******************************************************************************/ + +// MicroPython bindings for PWM + +STATIC void k210_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + k210_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(tim:%u channel:%u", self->tim ,self->channel); + if (self->active) { + mp_printf(print, ", freq=%u, duty=%u%", self->freq_hz,self->duty); + } + mp_printf(print, ")"); +} + +STATIC void k210_pwm_init_helper(k210_pwm_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty, ARG_pin_num}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_pin_num, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int channel; + int avail = -1; + + // Find a free PWM channel, also spot if our pin is + // already mentioned. + + if (self->tim > 2) { + mp_raise_ValueError("out of PWM timers"); + } + if (self->channel > 3) { + mp_raise_ValueError("out of PWM channels"); + } + self->pin_num = args[ARG_pin_num].u_int; + printf("PWM:set pin%d to pwm output pin\n",args[ARG_pin_num].u_int); + //fpioa_set_function(args[ARG_pin_num].u_int, FUNC_TIMER0_TOGGLE1 + self->tim * 4 + self->channel); + //Maybe change PWM timer + int tval = args[ARG_freq].u_int; + int dval = args[ARG_duty].u_int; + if (tval != -1 || dval != -1) { + self->freq_hz = tval; + self->duty = dval; + //timer_set_clock_div(self->tim,2); + //timer_set_enable(self->tim, self->channel, 1); + pwm_init(self->tim); + double duty = self->duty/(double)100; + int fre_pwm = pwm_set_frequency(self->tim,self->channel,self->freq_hz,duty); + printf("PWM:frquency = %d,duty = %f\n",fre_pwm,duty); + self->freq_hz = fre_pwm; + pwm_set_enable(self->tim, self->channel,1); + //timer_enable(self->tim,self->channel); + // Set duty cycle? + } + else + { + printf("pwm frequency is invalid!\n"); + } +} + +STATIC mp_obj_t k210_pwm_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + int tim_id = mp_obj_get_int(args[0]); + int channel = mp_obj_get_int(args[1]); + // create PWM object from the given pin + k210_pwm_obj_t *self = m_new_obj(k210_pwm_obj_t); + self->base.type = &machine_pwm_type; + self->tim = tim_id; + self->channel = channel; + self->active = 0; + //self->channel = -1; + + // start the PWM running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + k210_pwm_init_helper(self, n_args - 2, args + 2, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t k210_pwm_init(size_t n_args, + const mp_obj_t *args, mp_map_t *kw_args) { + k210_pwm_init_helper(args[0], n_args - 2, args + 2, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(k210_pwm_init_obj, 1, k210_pwm_init); + +STATIC mp_obj_t k210_pwm_deinit(mp_obj_t self_in) { + k210_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + int chan = self->channel; + + // Valid channel? + if ((chan >= 0) && (chan < 3)) { + // Mark it unused, and tell the hardware to stop routing + self->active = 0; + self->channel = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_pwm_deinit_obj, k210_pwm_deinit); + +STATIC mp_obj_t k210_pwm_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT((*(k210_pwm_obj_t *)(args[0])).freq_hz); + } + + // set + k210_pwm_obj_t *self = (k210_pwm_obj_t *)(args[0]); + self->freq_hz = mp_obj_get_int(args[1]); + pwm_set_frequency(self->tim,self->channel,self->freq_hz,self->duty); + //if (!set_freq(tval)) { + // nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + // "Bad frequency %d", tval)); + //} + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(k210_pwm_freq_obj, 1, 2, k210_pwm_freq); + +STATIC mp_obj_t k210_pwm_duty(size_t n_args, const mp_obj_t *args) { + k210_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int duty; + + if (n_args == 1) { + // get + duty = (*(k210_pwm_obj_t *)(args[0])).duty; + return MP_OBJ_NEW_SMALL_INT(duty); + } + // set + self->duty = mp_obj_get_int(args[1]); + pwm_set_frequency(self->tim,self->channel,self->freq_hz,self->duty/(double)100); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(k210_pwm_duty_obj,1, 2, k210_pwm_duty); + +STATIC const mp_rom_map_elem_t k210_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&k210_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&k210_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&k210_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&k210_pwm_duty_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(k210_pwm_locals_dict,k210_pwm_locals_dict_table); + +const mp_obj_type_t machine_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = k210_pwm_print, + .make_new = k210_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&k210_pwm_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_spiflash.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_spiflash.c new file mode 100755 index 0000000..b093ac2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_spiflash.c @@ -0,0 +1,207 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" +#include "w25qxx.h" + +#define FLASH_CHIP_SIZE 16*1024*1024 +extern const mp_obj_type_t machine_spiflash_type; + +typedef struct _k210_spiflash_obj_t { + mp_obj_base_t base; + int spin; +} k210_spiflash_obj_t; + +STATIC void spiflash_init(void) { + +} + +STATIC void k210_spiflash_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + k210_spiflash_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "SPIFLASH(spi:%u ss:%u)", self->spin); +} + +STATIC mp_obj_t k210_flash_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ + + enum { ARG_offset, ARG_buf}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_offset, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_buf, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args,MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int offset = args[ARG_offset].u_int; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE); + /*new version not have this api*/ + //w25qxx_status_t res = w25qxx_read_data_dma(offset, bufinfo.buf, bufinfo.len,W25QXX_QUAD); + enum w25qxx_status_t res = w25qxx_read_data_dma(offset, bufinfo.buf, bufinfo.len); + if (res != W25QXX_OK) { + mp_raise_ValueError("SPIFLASH read err"); + } + printf("data %d\n",(int)bufinfo.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(k210_flash_read_obj, 1, k210_flash_read); + +STATIC mp_obj_t k210_flash_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum { ARG_offset, ARG_buf}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_offset, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_buf, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args,MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int offset = args[ARG_offset].u_int; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ); + enum w25qxx_status_t res = w25qxx_write_data(offset, bufinfo.buf, bufinfo.len); + if (res != W25QXX_OK) { + mp_raise_ValueError("SPIFLASH write err"); + } + printf("write data len:%d\n",(int)bufinfo.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(k210_flash_write_obj,1, k210_flash_write); + +STATIC mp_obj_t k210_flash_erase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_addr}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_addr, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args,MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int addr = args[ARG_addr].u_int; + enum w25qxx_status_t res = w25qxx_sector_erase(addr); + if (res != W25QXX_OK) { + mp_raise_ValueError("SPIFLASH erase err"); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(k210_flash_erase_obj, 1, k210_flash_erase); + +STATIC mp_obj_t k210_flash_size(void) { + return mp_obj_new_int_from_uint(FLASH_CHIP_SIZE); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_flash_size_obj, k210_flash_size); + +STATIC void k210_spiflash_init_helper(k210_spiflash_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + //enum { ARG_spin, ARG_ss }; + //static const mp_arg_t allowed_args[] = { + //{ MP_QSTR_spin, MP_ARG_INT, {.u_int = -1} }, + //{ MP_QSTR_ss, MP_ARG_INT, {.u_int = -1} }, /*new version not have this parameter*/ + //}; + //mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + //mp_arg_parse_all(n_args, pos_args, kw_args, + //MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // Find a free SPIFLASH channel, also spot if our pin is + // already mentioned. + + + //if (args[ARG_spin].u_int > 3) { + // mp_raise_ValueError("out of SPIFLASH timers"); + // printf(" timern=%u \n",args[ARG_spin].u_int); + // return; + //} + /* new version not have this parameter + if (args[ARG_ss].u_int !=0 && args[ARG_ss].u_int !=1 ) { + mp_raise_ValueError("SPIFLASH ss err"); + printf(" ss=%u\n",args[ARG_ss].u_int); + return; + } + */ + self->spin = 0; + w25qxx_init(0);//args[ARG_ss].u_int); + w25qxx_enable_quad_mode(); + uint8_t status,manuf_id,device_id; + status=w25qxx_read_id(&manuf_id,&device_id); + printf("spiflash:%d m_id: %x , d_id:%x \n",status,manuf_id,device_id); +} + +STATIC mp_obj_t k210_spiflash_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + //mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + //int spin = mp_obj_get_int(args[0]); + //int ss = mp_obj_get_int(args[1]); + // create SPIFLASH object from the given pin + k210_spiflash_obj_t *self = m_new_obj(k210_spiflash_obj_t); + self->base.type = &machine_spiflash_type; + //self->spin = spin; + //self->ss = ss; + + // start the SPIFLASH running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + k210_spiflash_init_helper(self, n_args, args, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t k210_spiflash_init(size_t n_args, + const mp_obj_t *args, mp_map_t *kw_args) { + k210_spiflash_init_helper(args[0], n_args -1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(k210_spiflash_init_obj, 1, k210_spiflash_init); + +STATIC mp_obj_t k210_spiflash_deinit(mp_obj_t self_in) { + k210_spiflash_obj_t *self = MP_OBJ_TO_PTR(self_in); + printf("DEINIT SPIFLASH(spi:%u)", self->spin);//,self->ss); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_spiflash_deinit_obj, k210_spiflash_deinit); + + +STATIC const mp_rom_map_elem_t k210_spiflash_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&k210_spiflash_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&k210_spiflash_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&k210_flash_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&k210_flash_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&k210_flash_erase_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&k210_flash_size_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(k210_spiflash_locals_dict, + k210_spiflash_locals_dict_table); + +const mp_obj_type_t machine_spiflash_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIFLASH, + .print = k210_spiflash_print, + .make_new = k210_spiflash_make_new, + .locals_dict = (mp_obj_dict_t*)&k210_spiflash_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_st7789.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_st7789.c new file mode 100755 index 0000000..ef92237 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_st7789.c @@ -0,0 +1,232 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/obj.h" +#include "py/objtype.h" +#include "py/objstr.h" +#include "py/objint.h" + +#include +#include "lcd.h" +#include "st7789.h" +#include "sleep.h" +#include "gpiohs.h" +#include "fpioa.h" +#include "dmac.h" + +typedef struct _machine_st7789_obj_t { + mp_obj_base_t base; + unsigned short color[14]; + +} machine_st7789_obj_t; + +const mp_obj_type_t machine_st7789_type; + +/* +WHITE 0xFFFF +BLACK 0x0000 +BLUE 0x001F +BRED 0XF81F +GRED 0XFFE0 +GBLUE 0X07FF +RED 0xF800 +MAGENTA 0xF81F +GREEN 0x07E0 +CYAN 0x7FFF +YELLOW 0xFFE0 +BROWN 0XBC40 //棕色 +BRRED 0XFC07 //棕红色 +GRAY 0X8430 //ç°è‰² +*/ + +STATIC mp_obj_t machine_init_helper(machine_st7789_obj_t *self) { + + //需è¦é‡æ–°é…ç½®DMA,LCDæ‰èƒ½ä½¿ç”¨DMAåˆ·å± + dmac->reset = 0x01; + while (dmac->reset); + dmac->cfg = 0x03; + /*init lcd*/ + self->color[0] = 0xFFFF; + self->color[1] = 0x0000; + self->color[2] = 0x001F; + self->color[3] = 0XF81F; + self->color[4] = 0XFFE0; + self->color[5] = 0X07FF; + self->color[6] = 0xF800; + self->color[7] = 0xF81F; + self->color[8] = 0x07E0; + self->color[9] = 0x7FFF; + self->color[10] = 0xFFE0; + self->color[11] = 0XBC40; + self->color[12] = 0XFC07; + self->color[13] = 0X8430; + printf("LCD init\r\n"); + lcd_init(); + lcd_clear(BLUE); + return mp_const_none; +} + +STATIC mp_obj_t machine_draw_picture(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_st7789_obj_t* self = pos_args[0]; + enum { + ARG_x, + ARG_y, + ARG_width, + ARG_height, + ARG_buf + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_buf, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + uint16_t width = args[ARG_width].u_int; + uint16_t height = args[ARG_height].u_int; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ); + uint32_t *ptr = (uint32_t *)bufinfo.buf; + lcd_draw_picture( x, y, width, height, ptr); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_draw_picture_obj, 1,machine_draw_picture); + + +STATIC mp_obj_t machine_draw_picture_default(machine_st7789_obj_t *self_in,mp_obj_t buf) { + machine_st7789_obj_t* self = self_in; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + uint32_t *ptr = (uint32_t *)bufinfo.buf; + lcd_draw_picture( 0, 0, 320, 240 , ptr); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_draw_picture_default_obj,machine_draw_picture_default); + + + +STATIC mp_obj_t machine_draw_string(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_st7789_obj_t* self = pos_args[0]; + enum { + ARG_x, + ARG_y, + ARG_str, + ARG_color + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_str, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_color, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint16_t x = args[ARG_x].u_int; + uint16_t y = args[ARG_y].u_int; + if(args[ARG_str].u_obj == mp_const_none) + { + printf("[lichee error]:please enter a string"); + return mp_const_none; + } + mp_buffer_info_t bufinfo; + mp_obj_str_get_buffer(args[ARG_str].u_obj, &bufinfo, MP_BUFFER_READ); + char *ptr =bufinfo.buf; + uint16_t color = args[ARG_color].u_int; + if(color > 13) + { + printf("[lichee error]:please enter a right color\n"); + return mp_const_none; + } + lcd_draw_string( x, y,ptr,self->color[color]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_draw_string_obj, 1,machine_draw_string); + +STATIC mp_obj_t machine_clear(mp_obj_t self_in,mp_obj_t color) { + machine_st7789_obj_t* self = self_in; + int color_num = 0; + if (MP_OBJ_IS_SMALL_INT(color)) + color_num = MP_OBJ_SMALL_INT_VALUE(color); + else + { + printf("[lichee error]:type error\n"); + return mp_const_none; + } + if(color_num > 13) + { + printf("[lichee error]:please enter a right color\n"); + return mp_const_none; + } + lcd_clear(self->color[color_num]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_clear_obj, machine_clear); + + +STATIC mp_obj_t machine_init(mp_obj_t self_in) { + machine_st7789_obj_t* self = self_in; + return machine_init_helper(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_init_obj, machine_init); + +STATIC mp_obj_t machine_make_new() { + + machine_st7789_obj_t *self = m_new_obj(machine_st7789_obj_t); + self->base.type = &machine_st7789_type; + + return self; +} + +STATIC const mp_rom_map_elem_t pyb_st7789_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_draw_picture), MP_ROM_PTR(&machine_draw_picture_obj) }, + { MP_ROM_QSTR(MP_QSTR_draw_picture_default), MP_ROM_PTR(&machine_draw_picture_default_obj) }, + { MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&machine_draw_string_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&machine_clear_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_st7789_ocals_dict, pyb_st7789_locals_dict_table); + +const mp_obj_type_t machine_st7789_type = { + { &mp_type_type }, + .name = MP_QSTR_St7789, + .make_new = machine_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_st7789_ocals_dict, +}; + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_timer.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_timer.c new file mode 100755 index 0000000..71f8adc --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_timer.c @@ -0,0 +1,375 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "timer.h" +#include "py/obj.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" +#include "plic.h" +#include "sysctl.h" +#include "py/objtype.h" + +#define TIMER_INTR_SEL TIMER_INTR_LEVEL +#define TIMER_DIVIDER 8 + +// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) + +#define TIMER_FLAGS 0 +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + mp_uint_t timer; + mp_uint_t channel; + uint32_t freq; + uint32_t period;//k210 timers are 32-bit + uint32_t div; + uint32_t clk_freq; + mp_obj_t callback; + bool active; + //mp_uint_t repeat;//timer mode +} machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; + +#define K210_DEBUG 0 +#if K210_DEBUG==1 +#define debug_print(x,arg...) printf("[lichee]"x,##arg) +#else +#define debug_print(x,arg...) +#endif + +STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_timer_obj_t *self = self_in; + + mp_printf(print, "Timer(%p) ", self); + + mp_printf(print, "timer freq=%d, ", self->freq); + mp_printf(print, "reload=%d, ", timer_get_reload(self->timer,self->channel)); + mp_printf(print, "counter=%d", timer_get_count(self->timer,self->channel)); +} + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); + self->base.type = &machine_timer_type; + + self->timer = mp_obj_get_int(args[0]); + self->channel = mp_obj_get_int(args[1]); + //mp_map_t kw_args; + //mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + //machine_timer_init_helper(self, n_args - 2, args + 2, &kw_args); + + return self; +} + +STATIC void machine_timer_disable(machine_timer_obj_t *self) { + timer_disable(self->timer, self->channel); + plic_irq_disable(IRQN_TIMER0A_INTERRUPT + self->timer); + plic_irq_deregister(IRQN_TIMER0A_INTERRUPT + self->timer); + self->active = 0; +} + +STATIC int machine_timer_isr(void *self_in) { + int ret = 0; + mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; + machine_timer_obj_t *self = self_in; + debug_print("freq = %d\n",self->freq); + debug_print("enter machine_timer_isr\n"); + timer_channel_clear_interrupt(self->timer,self->channel); + debug_print("self->callback = %p\n",self->callback); + mp_obj_type_t *type = mp_obj_get_type(self->callback); + debug_print("type->call = %p\n",type->call); + if(type != NULL) + { + debug_print("type != NULL\n"); + mp_call_function_1(self->callback,MP_OBJ_FROM_PTR(self)); + } + else + { + debug_print("type == NULL\n"); + + } + debug_print("quit machine_timer_isr\n"); + return 1; +} + +STATIC void machine_timer_enable(machine_timer_obj_t *self) { + debug_print("[lichee]:self->timer=%d,self->channel=%d\n",self->timer,self->channel); + if(self->channel == 0 || 1 == self->channel) + { + debug_print("start init plic timer channel 0 and 1\n"); + plic_set_priority(IRQN_TIMER0A_INTERRUPT + self->timer*2, 1); + plic_irq_enable(IRQN_TIMER0A_INTERRUPT + self->timer*2); + plic_irq_register(IRQN_TIMER0A_INTERRUPT + self->timer*2, machine_timer_isr, (void*)self); + } + else if(self->channel == 2 || 3 == self->channel) + { + debug_print("start init plic timer channel 2 and 3\n"); + plic_set_priority(IRQN_TIMER0B_INTERRUPT + self->timer*2, 1); + plic_irq_enable(IRQN_TIMER0B_INTERRUPT + self->timer*2); + plic_irq_register(IRQN_TIMER0B_INTERRUPT + self->timer*2, machine_timer_isr, (void*)self); + } + //timer_set_mode(self->timer, self->channel, TIMER_CR_USER_MODE); + timer_set_reload(self->timer, self->channel, self->period); + timer_enable_interrupt(self->timer, self->channel); + timer_set_enable(self->timer, self->channel,1); + self->active = 0; + debug_print("[lichee]:quit %s\n",__FUNCTION__); +} + +STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_freq, + ARG_period, + ARG_div, + ARG_callback, + //ARG_tick_hz, + //ARG_mode, + }; + static const mp_arg_t allowed_args[] = { +/* +#if MICROPY_PY_BUILTINS_FLOAT + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +#else +#endif +*/ + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + //{ MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + //{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + + }; + + //machine_timer_disable(self);self->clk_freq + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + self->clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + self->timer); +/* +#if MICROPY_PY_BUILTINS_FLOAT + if (args[ARG_freq].u_obj != mp_const_none) { + self->period = (uint32_t)(clk_freq / mp_obj_get_float(args[ARG_freq].u_obj)); + } +#else +#endif +*/ + /*timer prescale*/ + if(args[ARG_div].u_int == 0) + { + self->div = 1; + } + if(args[ARG_div].u_int - 1 > 0) + { + self->div = args[ARG_div].u_int; + timer_set_clock_div(self->timer,self->div-1); + + } + else + { + printf("[lichee_warn]div must be bigger than 1,use default division parameter\n"); + self->div = 1; + } + + /*set frequency,Frequency takes precedence over period*/ + if (args[ARG_freq].u_int > 0) + { + self->freq = (uint32_t)args[ARG_freq].u_int; + self->clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + self->timer); + self->period = (uint32_t)(self->clk_freq / (uint32_t)args[ARG_freq].u_int); + } + else if(args[ARG_freq].u_int < 0) + { + printf("[lichee_warn]frequency must be bigger than 1,use default frequency parameter\n"); + self->freq = 1; + self->clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + self->timer); + self->period = (uint32_t)(self->clk_freq / (uint32_t)args[ARG_freq].u_int); + } + else if(args[ARG_freq].u_int == 0) + { + if(args[ARG_period].u_int > 0) + { + self->period = args[ARG_period].u_int; + } + else + { + /*no set freq && no set period*/ + printf("[lichee_error]please set freq or period correctly\n"); + printf("[lichee_error] freq > 0 and period > 0\n"); + return mp_const_false; + } + } + + //self->repeat = args[ARG_mode].u_int; + if (mp_obj_is_callable(args[ARG_callback].u_obj)) + { + self->callback = args[ARG_callback].u_obj; + debug_print("callback is normal\n"); + } + else + { + printf("[lichee_error]callback can't work,please give me a callback function\n"); + return mp_const_false; + } + printf("[lichee]clk_freq = %d,self->period = %d\n",self->clk_freq,self->period); + timer_init(self->timer); + machine_timer_enable(self); + self->clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + self->timer); + return mp_const_none; +} + +STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { + machine_timer_disable(self_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init); + + +STATIC mp_obj_t machine_timer_callbcak(mp_obj_t self_in,mp_obj_t func_in) { + machine_timer_obj_t *self = self_in; + + self->callback = func_in; + + return mp_const_none; // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_timer_callback_obj, machine_timer_callbcak); + + + +STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + mp_uint_t result = 0; + + result = timer_get_count(self->timer,self->channel); + + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value); + +STATIC mp_obj_t machine_timer_period(mp_obj_t self_in,mp_obj_t period) { + machine_timer_obj_t *self = self_in; + mp_uint_t result = 0; + if (MP_OBJ_IS_SMALL_INT((period))) + self->period = MP_OBJ_SMALL_INT_VALUE(period); + else + { + printf("[lichee error]:type error\n"); + return mp_const_none; + } + result = self->period; + timer_disable(self->timer, self->channel); + timer_set_reload(self->timer, self->channel, self->period); + timer_set_enable(self->timer, self->channel,1); + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_timer_period_obj, machine_timer_period); + +STATIC mp_obj_t machine_timer_stop(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + + timer_disable(self->timer, self->channel); + self->active = 0; + return mp_const_none; // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_stop_obj, machine_timer_stop); + + +STATIC mp_obj_t machine_timer_restart(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + mp_uint_t result = 0; + timer_disable(self->timer, self->channel); + timer_set_reload(self->timer, self->channel, self->period); + result=self->period; + timer_set_enable(self->timer, self->channel,1); + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_restart_obj, machine_timer_restart); + +STATIC mp_obj_t machine_timer_start(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + if(self->active == 0) + timer_set_enable(self->timer, self->channel,1); + self->active = 1; + return mp_const_none; // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start); + +STATIC mp_obj_t machine_timer_freq(mp_obj_t self_in,mp_obj_t freq) { + machine_timer_obj_t *self = self_in; + mp_uint_t result = 0; + if (MP_OBJ_IS_SMALL_INT((freq))) + self->freq = MP_OBJ_SMALL_INT_VALUE(freq); + else + { + printf("[lichee error]:type error\n"); + return mp_const_none; + } + timer_disable(self->timer, self->channel); + self->period = (uint32_t)(self->clk_freq / self->freq); + timer_set_reload(self->timer, self->channel, self->period); + timer_set_enable(self->timer, self->channel,1); + result = self->freq; + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_timer_freq_obj, machine_timer_freq); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&machine_timer_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&machine_timer_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_timer_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_timer_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&machine_timer_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_timer_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = machine_timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_t)&machine_timer_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uart.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uart.c new file mode 100755 index 0000000..70af3d4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uart.c @@ -0,0 +1,230 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/binary.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +#include "py/parsenum.h" + +#include +#include "py/formatfloat.h" + +#include "uart.h" +#define UART_NUM_MAX 3 +typedef struct _machine_uart_obj_t { + mp_obj_base_t base; + uint16_t baudrate; + uint8_t uart_num; + uint8_t bits; + uart_parity_t parity; + uart_stopbit_t stop; +} machine_uart_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +//QueueHandle_t UART_QUEUE[UART_NUM_MAX] = {}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + //uart_get_baudrate(self->uart_num, &baudrate); + mp_printf(print, "UART%d( baudrate=%u, bits=%u, parity=%s, stop=%u)", + self->uart_num,self->baudrate, self->bits, _parity_name[self->parity], + self->stop); +} + +STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 115200} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set baudrate + if (args[ARG_baudrate].u_int > 0) { + self->baudrate =args[ARG_baudrate].u_int; + } + + // set data bits + if (args[ARG_bits].u_int >=5 && args[ARG_bits].u_int <=8) { + self->bits=args[ARG_bits].u_int; + }else{ + mp_raise_ValueError("invalid data bits"); + return; + } + + // set parity + + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + self->parity = UART_PARITY_NONE; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + if (parity & 1) { + self->parity = UART_PARITY_ODD; + } else { + self->parity = UART_PARITY_EVEN; + } + } + } + + // set stop bits + switch (mp_obj_get_int((mp_obj_t)args[ARG_stop].u_obj)) { + // FIXME: ESP32 also supports 1.5 stop bits + case 0: + self->stop = UART_STOP_1; + break; + case 1: + self->stop = UART_STOP_1; + break; + case 15: + self->stop = UART_STOP_1_5; + break; + default: + mp_raise_ValueError("invalid stop bits"); + break; + } + + uart_init(self->uart_num); + uart_config(self->uart_num, (size_t)self->baudrate, (size_t)self->bits, self->stop, self->parity); +} + +STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get uart id + mp_int_t uart_num = mp_obj_get_int(args[0]); + if (uart_num < 0 || uart_num > UART_NUM_MAX) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); + } + // create instance + machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t); + self->base.type = &machine_uart_type; + self->uart_num = uart_num; + self->baudrate = 0; + self->bits = 8; + self->parity = 0; + self->stop = 1; + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_uart_init_helper(args[0], n_args -1 , args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 0, machine_uart_init); + + +STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); + +STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + int bytes_read = uart_receive_data(self->uart_num, buf_in, size); + + if (bytes_read < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + return bytes_read; +} + +STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int bytes_written=uart_send_data(self->uart_num,buf_in,size); + if (bytes_written < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // return number of bytes written + return bytes_written; +} + +STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + machine_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_uart_read, + .write = machine_uart_write, + .ioctl = machine_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_uart_print, + .make_new = machine_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uarths.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uarths.c new file mode 100755 index 0000000..8c962fa --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_uarths.c @@ -0,0 +1,169 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +#include "uart.h" +#include "uarths.h" + +typedef struct _machine_uarths_obj_t { + mp_obj_base_t base; + uint16_t baudrate; + uint8_t stop; +} machine_uarths_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +//QueueHandle_t UART_QUEUE[UART_NUM_MAX] = {}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void machine_uarths_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_uarths_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "UART( baudrate=%u, stop=%u)", + self->baudrate,self->stop); +} + +STATIC void machine_uarths_init_helper(machine_uarths_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_stop}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 115200} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set baudrate + + if (args[ARG_baudrate].u_int > 0) { + uarths_init(); + //self->baudrate=args[ARG_baudrate].u_int; + //uart_config(args[ARG_baudrate].u_int,args[ARG_stop].u_int==1?UART_STOP_1:UART_STOP_2); + }else{ + mp_raise_ValueError("Please enter the correct baudrate"); + } + +} + +STATIC mp_obj_t machine_uarths_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // create instance + machine_uarths_obj_t *self = m_new_obj(machine_uarths_obj_t); + self->base.type = &machine_uarths_type; + self->stop = 1; + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_uarths_init_helper(self, n_args, args, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_uarths_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_uarths_init_helper(args[0], n_args, args, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_uarths_init_obj, 0, machine_uarths_init); + +STATIC const mp_rom_map_elem_t machine_uarths_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uarths_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_uarths_locals_dict, machine_uarths_locals_dict_table); + +STATIC mp_uint_t machine_uarths_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_uarths_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + int bytes_read = size; + //int bytes_read = uarths_read_bytes(self->uarths_num, buf_in, size, time_to_wait); + + //if (bytes_read < 0) { + // *errcode = MP_EAGAIN; + // return MP_STREAM_ERROR; + //} + while(bytes_read--) + *((char *)(buf_in)++)=uarths_getc(); + + return size; +} + +STATIC mp_uint_t machine_uarths_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_uarths_obj_t *self = MP_OBJ_TO_PTR(self_in); + int bytes_written = size;//uarths_write_bytes(self->uarths_num, buf_in, size); + while(bytes_written--) + uarths_putchar(*((char *)(buf_in)++)); + if (bytes_written < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + // return number of bytes written + return size; +} + +STATIC mp_uint_t machine_uarths_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + machine_uarths_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uarths_stream_p = { + .read = machine_uarths_read, + .write = machine_uarths_write, + .ioctl = machine_uarths_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_uarths_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_uarths_print, + .make_new = machine_uarths_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uarths_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_uarths_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ws2812.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ws2812.c new file mode 100755 index 0000000..6ea8da7 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_ws2812.c @@ -0,0 +1,189 @@ + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" + +#include "ws2812b.h" +#include "sleep.h" +#include "gpiohs.h" +#include "sysctl.h" + + +typedef struct _machine_ws2812_obj_t { + mp_obj_base_t base; + uint32_t gpio_num; + uint32_t pin_num; + +} machine_ws2812_obj_t; + +const mp_obj_type_t machine_ws2812_type; + + + +void WS2812B_TxRes(int gpio_num); + + +void stop_irq_all(void) +{ + volatile uint64_t* irq_threshhoud = (volatile uint64_t *)0x0C200000; + *irq_threshhoud = 0xffffffff; + //printf("stop_irq_all\r\n"); +} +void start_irq_all(void) +{ + volatile uint64_t* irq_threshhoud = (volatile uint64_t *)0x0C200000; + //printf("start_irq_all\r\n"); + *irq_threshhoud = 0x00000000; + +} + + +STATIC void machine_ws2812_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_ws2812_obj_t *self = self_in; + + mp_printf(print, "ws2812(%p) ", self); + + mp_printf(print, "ws2812 gpio_hs: %d ", self->gpio_num); + mp_printf(print, "ws2812 pin: %d ", self->pin_num); +} + +STATIC mp_obj_t machine_ws2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + machine_ws2812_obj_t *self = m_new_obj(machine_ws2812_obj_t); + self->base.type = &machine_ws2812_type; + return self; +} + +STATIC mp_obj_t machine_ws2812_deinit(machine_ws2812_obj_t *self_in) { + machine_ws2812_obj_t* self = self_in; + self->gpio_num = 0; + self->pin_num = 0; + gpiohs_set_drive_mode(self->gpio_num,GPIO_DM_OUTPUT); + gpiohs_set_pin(self->gpio_num,GPIO_PV_LOW); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_deinit_obj,machine_ws2812_deinit); + +STATIC mp_obj_t machine_ws2812_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_ws2812_obj_t* self = pos_args[0]; + enum { + ARG_gpio_num, + ARG_pin_num, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_gpio_num, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pin_num, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + self->gpio_num = args[ARG_gpio_num].u_int; + self->pin_num = args[ARG_pin_num].u_int; + init_nop_cnt(); + gpiohs_set_drive_mode(self->gpio_num,GPIO_DM_INPUT); + gpiohs_set_pin(self->gpio_num,GPIO_PV_LOW); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_init_obj, 1,machine_ws2812_init); + +STATIC mp_obj_t machine_ws2812_set_RGB(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_ws2812_obj_t* self = pos_args[0]; + enum { + ARG_red, + ARG_green, + ARG_blue, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_red, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_green, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_blue, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(args[ARG_red].u_int >255) + { + printf("Error:red value > 255"); + return mp_const_false; + } + if(args[ARG_green].u_int >255) + { + printf("Error:green value > 255"); + return mp_const_false; + } + if(args[ARG_blue].u_int >255) + { + printf("Error:blue value > 255"); + return mp_const_false; + } + stop_irq_all(); + WS2812B_SetLedRGB(args[ARG_red].u_int, args[ARG_green].u_int, args[ARG_blue].u_int, self->gpio_num); + start_irq_all(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_set_RGB_obj, 1,machine_ws2812_set_RGB); + + +STATIC mp_obj_t machine_ws2812_set_RGB_num(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_ws2812_obj_t* self = pos_args[0]; + enum { + ARG_red, + ARG_green, + ARG_blue, + ARG_num, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_red, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_green, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_blue, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_num, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(args[ARG_red].u_int >255) + { + printf("Error:red value > 255"); + return mp_const_false; + } + if(args[ARG_green].u_int >255) + { + printf("Error:green value > 255"); + return mp_const_false; + } + if(args[ARG_blue].u_int >255) + { + printf("Error:blue value > 255"); + return mp_const_false; + } + if(args[ARG_num].u_int <= 0) + { + printf("Error:num value <= 0"); + return mp_const_false; + } + stop_irq_all(); + WS2812B_SetLednRGB(args[ARG_red].u_int, args[ARG_green].u_int, args[ARG_blue].u_int, args[ARG_num].u_int,self->gpio_num); + start_irq_all(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_set_RGB_num_obj, 1,machine_ws2812_set_RGB_num); + +STATIC const mp_rom_map_elem_t machine_ws2812_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_RGB_num), MP_ROM_PTR(&machine_set_RGB_num_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_RGB), MP_ROM_PTR(&machine_set_RGB_obj) }, + +}; +STATIC MP_DEFINE_CONST_DICT(machine_ws2812_locals_dict, machine_ws2812_locals_dict_table); + +const mp_obj_type_t machine_ws2812_type = { + { &mp_type_type }, + .name = MP_QSTR_Ws2812, + .print = machine_ws2812_print, + .make_new = machine_ws2812_make_new, + .locals_dict = (mp_obj_t)&machine_ws2812_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_zmodem.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_zmodem.c new file mode 100755 index 0000000..f539428 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/machine_zmodem.c @@ -0,0 +1,1958 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/binary.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +#include "py/parsenum.h" + +#include +#include "py/formatfloat.h" + +#define zfs_enable +#define uarths_enable +#ifdef uarths_enable +#include "uarths.h" +#else +#include "uart.h" +#endif +#if !MICROPY_VFS +#include "spiffs-port.h" +#include "py/lexer.h" +#endif +#include "sleep.h" + +#include "spiffs-port.h" +spiffs_file fd; + +#include +#include "rzsz.h" + +#define TRUE 1 +#define FALSE 0 +#define OK 0 +#define ERROR (-1) +#define TIMEOUT (-2) +#define RCDO (-3) +#define GCOUNT (-4) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 + +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) + +#define RETRYMAX 5 +#define WCEOT (-10) +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define BUFF_SIZE 512 +#define CPMEOF 032 +#define PATHLEN 257 +#define HOWMANY 96 +#define DEFBYTL 2000000000L /* default rx file size */ +#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ + +#ifdef uarths_enable + #define printf(...) +#endif +/*CRC part*/ +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) + +static unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +static unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +volatile uint64_t zfile_total_size = 0; +int zdlread(); +int zgethex(); +void zputhex(register int c); +int rzfile(char* secbuf); +int tryz(); +void canit(); +int putsec(char *buf, register int n); +int procheader(char *name); +int zm_readline(int timeout); + +static int Zrwindow = 1400; // RX window size(controls garbage count) +static int Zctlesc; // encode control characters +static char Lzconv; //local ZMODEM file conversion request +static char Lzmanag; +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +//static char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; + +int errno; +int Baudrate = 115200; +int errors; +int Crc32t; //controls 32 bit CRC being sent CRC32 == 1 CRC32 +RLE ==2 +int Crc32r; /* Indicates/controls 32 bit CRC being received */ + /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ +int Eofseen; +int Lastrx; +int Rxframeind; //ZBIN ZBIN32 or ZHEX type or frame +int Rxtype; // type of header received +int Rxhlen; //length of header received +//int Zctlesc; +int Firstsec; +int Blklen; +int Rxcount; //count of data bytes received +int Filemode; // unix style mode for incoming file +int Thisbinary; //current file is to be received in bin mode +int Usevhdrs; /* Use variable length headers */ +int Rxbinary = FALSE; //receive all files in bin mode +int Rxascii = FALSE; // receive all files in ascii mode + +int Zmodem = 0; +int Nozmodem = 0; /* If invoked as "rb" */ +int Crcflg = 1; +int tryzhdrtype = ZRINIT; +int Lleft = 0; +int Readnum = HOWMANY; +int Rxtimeout = 10000; + +long rxbytes; +long Filesleft; +long Totalleft; +long Bytesleft; +long Modtime; //unix style mod time for incoming file +long Rxpos; + +char zconv; // ZMODEM file conversion request +char zmanag; //ZMODEM file management request +char ztrans; //MODEM file transport request + +uint16_t btw; +uint16_t* bw; + +char Pathname[PATHLEN]; +char buffer[BUFF_SIZE]; +char Rxhdr[ZMAXHLEN]; //received header +char Txhdr[ZMAXHLEN]; //transmitted header +char linbuf[HOWMANY]; +char Attn[ZATTNLEN+1]; +char secbuf[1025]; +char endmsg[90] = {0}; //possible message to display on exit +static char badcrc[] = "Bad CRC"; + +typedef struct file_s{ + volatile uint64_t size; + volatile uint64_t fsize; + volatile uint64_t ftime; +}file_f; +file_f *f; + +#ifdef mydel + static FIL fout; + FILINFO* f; +#endif +//FILE *fout; +//jmp_buf tohere; + +void _udelay(uint32_t us) +{ + uint32_t i; + + while (us && us--) + { + for (i = 0; i < 25; i++) + __asm__ __volatile__("nop"); + } +} + + +/*��Ҫ����ͨ�ŷ���ָ��*/ +void sendline(char c){ + /*���ڷ���һ���ַ��ĺ���*/ + #ifdef uarths_enable + uarths_putchar(c); + //uarths_send_data(&c,1); + #else + uart_send_data(0,&c,1); + #endif +} + +/*��Ҫ����ͨ�Ž���ָ��*/ +int zm_readline(int timeout){ +#if 0 + register int n; + static char *cdq; //pointer for removing chars from linbuf + int temp_Readnum; + int temp_timeout; + char c; + if(--Lleft >= 0){ + return (*cdq++ & 0377); //��255���� ȡ�Ͱ�λ + } + n = timeout/10; + if(n < 2) + n = 2; + errno = 0; + while( Lleft <1 && timeout--){ + cdq=linbuf; + #ifdef uarths_enable + Lleft = read_ringbuff(cdq, Readnum); + usleep(100); + #else + Lleft = read_ringbuff(0, cdq, Readnum); + usleep(100); + #endif + } + if(Lleft < 1) + return TIMEOUT; + --Lleft; + return (*cdq++ & 0377); //È¡cdq��ֵ�Ͱ�λ cdq��ַ������ +#endif + return 0; +} + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +void zmputs(char *s) +{ + register int c; + + while (*s) { + switch (c = *s++) { + case '\336': + msleep(100); + //sleep(1); + continue; + case '\335': + //sendbrk(); //no break signal available + continue; + default: + sendline(c); + } + } + //flushmo(); +} + +/* send cancel string to get the other end to shut up */ +void canit() +{ + static char canistr[] = { + 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 + }; + + zmputs(canistr); + Lleft=0; /* Do read next time ... */ +} + +long getfree() +{ + return(2147483647); /* many free bytes ... */ +} + +/* + * Putsec writes the n characters of buf to receive file fout. + * If not in binary mode, carriage returns, and all characters + * starting with CPMEOF are discarded. + */ +int putsec(char *buf, register int n)zfs_enable +{ + register char *p; + int ret; + if (n == 0) + return OK; + if (Thisbinary) { + /*for (p=buf; --n>=0; ) + f_putc( *p++, &fout);*/ + /* + printf("f_write\n"); + int temp_i=0; + for(temp_i=0;temp_ifsize += n; + #ifdef mydel + ret = f_write (&fout, buf, (uint16_t)n, bw); + #endif + + } + else { + if (Eofseen) + return OK; + for (p=buf; --n>=0; ++p ) { + if ( *p == '\r' || '\n') + continue; + if (*p == CPMEOF) { + Eofseen = TRUE; + return OK; + } + printf("f_putc\n"); + #ifdef mydel + f_putc(*p ,&fout); + #endif + } + } + return OK; +} + + + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +int zdlread() +{ + register int c; + +again: + /* Quick check for non control characters */ + c = zm_readline(Rxtimeout); + //printf("again c %x \n",c); + if ((c) & 0140) + return c; + switch (c) { + case ZDLE: + break; + case 023: + case 0223: + case 021: + case 0221: + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + c = zm_readline(Rxtimeout); + //printf("again2 c %x \n",c); + if ((c) < 0) + return c; + if (c == CAN && (c = zm_readline(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = zm_readline(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = zm_readline(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case 023: + case 0223: + case 021: + case 0221: + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + return ERROR; + +} + +int zrdat32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; + Rxcount = 0; + end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + printf("crcfooc : %d \n",c); + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; + c &= 0377; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if (crc != 0xDEBB20E3) { + printf("%s\n",badcrc); + //printf(badcrc); + return ERROR; + } + Rxcount = length - (end - buf); + + return d; + case GOTCAN: + printf("Sender Canceled\r\n"); + return ZCAN; + case TIMEOUT: + printf("TIMEOUT\r\n"); + return c; + default: + //garbitch(); + return c; + } + } + *buf++ = c; + crc = UPDC32(c, crc); + } + //zperr1("Data subpacket too long"); + return ERROR; +} + +/* Receive data subpacket RLE encoded with 32 bit FCS */ +int zrdatr32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; + Rxcount = 0; + end = buf + length; + d = 0; /* Use for RLE decoder state */ + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + printf("crcfooc : %d \n",c); + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if (crc != 0xDEBB20E3) { + printf("%s\n", badcrc); + //zperr1(badcrc); + return ERROR; + } + Rxcount = length - (end - buf); + + return d; + case GOTCAN: + //zperr1("Sender Canceled"); + return ZCAN; + case TIMEOUT: + printf("TIMEOUT\n"); + //zperr1("TIMEOUT"); + return c; + default: + printf("Bad data subpacket\n"); + //zperr1("Bad data subpacket"); + return c; + } + } + crc = UPDC32(c, crc); + switch (d) { + case 0: + if (c == ZRESC) { + d = -1; continue; + } + *buf++ = c; continue; + case -1: + if (c >= 040 && c < 0100) { + d = c - 035; c = 040; + goto spaces; + } + if (c == 0100) { + d = 0; + *buf++ = ZRESC; + continue; + } + d = c; + continue; + default: + d -= 0100; + if (d < 1) + goto badpkt; +spaces: + if ((buf + d) > end) + goto badpkt; + while ( --d >= 0) + *buf++ = c; + d = 0; + continue; + } + } +badpkt: + //zperr1("Data subpacket too long"); + return ERROR; +} + + +int zrdata(register char *buf, int length){ + int c; + unsigned short crc; + char *end; + int d; + + switch (Crc32r) { + case 1: + return zrdat32(buf, length); + case 2: + return zrdatr32(buf, length); + } + + crc = Rxcount = 0; + end = buf + length; + printf("after end = buf + length; \n"); + while (buf <= end) { + c = zdlread(); + //printf("c : %x \n",c); + if ((c) & ~0377) { +crcfoo: + printf("crcfooc : %d \n",c); + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + crc = updcrc(((d=c)&0377), crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + //zperr1(badcrc); + #ifdef mydel + return ERROR; + //#else + //goto crcfoo; + #endif + } + Rxcount = length - (end - buf); + + return d; + case GOTCAN: + printf("Sender Canceled\n"); + //zperr1("Sender Canceled"); + return ZCAN; + case TIMEOUT: + printf("TIMEOUT\n"); + //zperr1("TIMEOUT"); + return c; + default: + //garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc(c, crc); + } + return ERROR; +} + +//void alrm(c) { longjmp(tohere, -1); } + + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +int noxrd7() +{ + register int c; + + for (;;) { + if ((c = zm_readline(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + + } +} + +int zgeth1() +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return ERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return ERROR; + c += (n<<4); + return c; +} + +/* Decode two lower case hex digits into an 8 bit byte value */ +int zgethex() +{ + register int c; + + c = zgeth1(); + + return c; +} + + /* NOTREACHED */ +/*void openit(char *name, char *openmode){ + if (strcmp(name, "-")) //�ļ����ֲ�����- ����Ϊѡ�� + //fout = fopen(name, openmode); //substitute with f_open in STM32 + f_open (fout, name, openmode); //name Ӧ��Ϊ�ļ�·�� + else if (isatty(1)) + fout = fopen("stdout", "a"); + else + fout = stdout; +}*/ + +void zputhex(register int c){ + static char digits[] = "0123456789abcdef"; + sendline(digits[(c&0xF0)>>4]); + sendline(digits[(c)&0xF]); +} + + +/*process incoming file information header + returns 0 if success, other codes for errors + or skip conditions*/ +int procheader(char *name){ + register char *openmode, *p; + static int dummy; + //printf("Hello, this is proheader program\r\n"); + /*set default parameters and overrides*/ + openmode = "w"; + Thisbinary = (!Rxascii) || Rxbinary; + if(zconv == ZCBIN && Lzconv != ZCRESUM) + Lzconv = zconv; // remote binary overrides + if(Lzconv) + zconv = Lzconv; + if(Lzmanag) + zmanag = Lzmanag; + + /*process ZMODEM remote file management request*/ + if(!Rxbinary && zconv == ZCNL) + Thisbinary = 0; + if(zconv == ZCBIN) + Thisbinary = TRUE; + else if (zmanag == ZMAPND) + openmode = "a"; + + Bytesleft = DEFBYTL; + Filemode = 0; + Modtime = 0L; + + if(!name || !*name){ + printf("name isn't a NULL pointer\r\n"); + return 0; + } + + //set p address behind the name frame + p = name + 1 + strlen(name); + if (*p) { /* file coming from Unix or DOS system */ + sscanf(p, "%ld%lo%o%lo%d%ld%d%d", + &Bytesleft, (long unsigned int *)&Modtime, (long unsigned int *)&Filemode, + &dummy, &Filesleft, &Totalleft, &dummy, &dummy); + if (Filemode & UNIXFILE) + ++Thisbinary; + } + + + else { /* File coming from CP/M system */ + for (p=name; *p; ++p) /* change / to _ */ + if ( *p == '/') + *p = '_'; + + if ( *--p == '.') /* zap trailing period ȥ����� */ + *p = 0; + } + + strcpy(Pathname, name); +#ifdef mydel + if(*name && f_stat(name, f) == 0){ //replaced with f_stat +#else + if(1){ //replaced with f_stat +#endif + zmanag &= ZMMASK; + #ifdef mydel + if(zmanag == ZMPROT) + #else + if(0) + #endif + goto skipfile; + #ifdef mydel + printf("Current %s is %ld of size %lo of last modified time\r\n", name, f->fsize, f->ftime); + #endif + if(Thisbinary && zconv == ZCRESUM){ + printf("In resuming interrupted file transfer\r\n"); + #ifndef mydel + rxbytes = f->fsize & ~511; //�����9λ + #endif + if (Bytesleft < rxbytes) { + rxbytes = 0; + rxbytes = 0; + goto doopen; + } + else{ + //openit(name, "r+"); + #ifdef mydel + verbose_open(&fout, mkpath(name), FA_READ| FA_WRITE | FA_CREATE_NEW); + #endif + #ifdef mydel + if ( (&fout) == NULL) + #else + if (0) + #endif + { + printf("The file doesn't exist, please check your path\r\n"); + return ZFERR; + } + #ifdef mydel + if (f_lseek(&fout, rxbytes)) { + f_close(&fout); + #else + #ifdef zfs_enable + s32_t ls_res = SPIFFS_lseek(&fs, fd,rxbytes,SPIFFS_SEEK_SET); + if(ls_res != 0){ + printf("lseek err\n"); + mp_raise_OSError(MP_EIO); + } + #endif + #endif + //closeit(); + return ZFERR; + } + printf("Crash recovery at %ld\r\n", rxbytes); + return 0; + } + switch (zmanag & ZMMASK) { + case ZMNEWL: + if (Bytesleft > f->fsize) + goto doopen; + case ZMNEW: + #ifdef mydel + if ((f->ftime+1) >= Modtime) + #else + if(0) + #endif + goto skipfile; + goto doopen; + case ZMCLOB: + case ZMAPND: + goto doopen; + default: + #ifndef mydel + if(0) + #endif + goto skipfile; + } + + } + else if (zmanag & ZMSKNOLOC){ +skipfile: + return ZSKIP;//return 0;// + + } +doopen: + //openit(name, openmode); + #ifdef mydel + verbose_open(&fout, mkpath(name), FA_WRITE | FA_CREATE_NEW); + #endif + //f_open (fout, name, FA_WRITE|FA_CREATE_ALWAYS); + #ifdef mydel + if ( (&fout) == NULL) + #else + if(0) + #endif + { + printf("In doopen branch, the file doesn't exist, please check your path\r\n"); + return ZFERR; + } + //printf("fout pointer is not NULL\r\n"); + return 0; +} + + +/*store long integer pos in Txhdr*/ +void stohdr(long pos){ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; +} + +/* Receive a binary style header (type and position) with 32 bit FCS */ +int zrbhd32(char *hdr) +{ + register int c, n; + register unsigned long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype= c; + crc = 0xFFFFFFFFL; + crc = UPDC32(c, crc); + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); + *hdr = c; + } + + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); + } + + if (crc != 0xDEBB20E3) { + printf("%s\r\n",badcrc); + //zperr1(badcrc); + return ERROR; + } + Zmodem = 1; + return Rxtype; +} + + + +/* Receive a hex style header (type and position) */ +int zrhhdr(char *hdr) +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + printf("%s\n",badcrc); + return ERROR; + } + c = zm_readline(Rxtimeout); + if (c < 0) + return c; + c = zm_readline(Rxtimeout); +#ifdef ZMODEM + Protocol = ZMODEM; +#endif + Zmodem = 1; + if (c < 0) + return c; + return Rxtype; +} + +/* Receive a binary style header (type and position) */ +int zrbhdr(char *hdr) +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=Rxhlen; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + printf("%s\n",badcrc); + return ERROR; + } +#ifdef ZMODEM + Protocol = ZMODEM; +#endif + Zmodem = 1; + return Rxtype; +} + + +/*����ZMODEMЭ���ͷ*/ +void zshhdr(int len, int type, char *hdr){ + register int n; + register unsigned short crc; + + sendline(ZPAD); + sendline(ZPAD); + sendline(ZDLE); + sendline(ZHEX); + zputhex(type); + Crc32t = 0; + + crc = updcrc(type, 0); + for (n=len; --n >= 0; ++hdr) { + zputhex(*hdr); + crc = updcrc((0377 & *hdr), crc); + } + + crc = updcrc(0,updcrc(0,crc)); + zputhex(((int)(crc>>8))); + zputhex(crc); + + /* Make it printable on remote machine */ + sendline(015); + sendline(0212); + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + sendline(021); + printf("Have sent %s frametype\r\n", frametypes[type+FTOFFSET]); + //��һ�����buffer��� +} + + +int zgethdr(char *hdr){ + register int c, n, cancount; + + n = Zrwindow + Baudrate; + Rxframeind = 0; + Rxtype = 0; /* Type of header received */ + +startover: + cancount = 5; +again: + switch(c =zm_readline(Rxtimeout)){ + case 021: //17 + case 0221: //145 + goto again; + case RCDO: + case TIMEOUT: + goto fifi; + case CAN: //030 + +gotcan: + if(--cancount <= 0){ + c = ZCAN; + goto fifi; + } + switch (c = zm_readline(Rxtimeout)) { + case TIMEOUT: + goto again; + case ZCRCW: + switch (zm_readline(Rxtimeout)) { + case TIMEOUT: + c = ERROR; + goto fifi; + case RCDO: + goto fifi; + default: + goto agn2; + } + case RCDO: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; + goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: + if ( --n == 0) { + c = GCOUNT; + goto fifi; + } + goto startover; + case ZPAD: /* This is what we want. */ + { + printf("We get ZPAD\r\n"); + break; + } + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case RCDO: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + { + printf("We get ZDLE\r\n"); + break; + } + } + + + Rxhlen = 4; /* Set default length */ + c = zm_readline(Rxtimeout); + Rxframeind = c; + printf("Got %s\r\n", frametypes[c+FTOFFSET]); + switch (c) { + case ZVBIN32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 1; + c = zrbhd32(hdr); + break; + case ZBIN32: + if (Usevhdrs) + goto agn2; + Crc32r = 1; + c = zrbhd32(hdr); + break; + case ZVBINR32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 2; + c = zrbhd32(hdr); + break; + case ZBINR32: + if (Usevhdrs) + goto agn2; + Crc32r = 2; + c = zrbhd32(hdr); + break; + case RCDO: + case TIMEOUT: + goto fifi; + case ZVBIN: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; + c = zrbhdr(hdr); + break; + case ZBIN://0x41 This is what we want + printf("In ZBIN\r\n"); + if (Usevhdrs) + goto agn2; + Crc32r = 0; + c = zrbhdr(hdr); + + break; + case ZVHEX: + if ((Rxhlen = c = zgethex()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; + c = zrhhdr(hdr); + break; + case ZHEX: + if (Usevhdrs) + goto agn2; + Crc32r = 0; + c = zrhhdr(hdr); + break; + case CAN: + goto gotcan; + default: + goto agn2; + } + for (n = Rxhlen; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */ + hdr[n] = 0; + Rxpos = hdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); +fifi: + printf("In fifi, the received header is %s\r\n", frametypes[c+FTOFFSET] ); + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case ERROR: + case TIMEOUT: + case RCDO: + case GCOUNT: + printf("Got %s\r\n", frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ + default: + if (c >= -4 && c <= FRTYPES) + printf("In fifi,zgethdr: the frametype:%c the received header length:%d\r\n the headertype: %s the received file position: %lx\n", Rxframeind, Rxhlen, frametypes[c+FTOFFSET], Rxpos); + else + printf("In fifi, zgethdr: the frametype:%c the received header length:%d \r\n the received file position: %lx\n", Rxframeind, c, Rxpos); + + } + + /* Use variable length headers if we got one */ + + if (c >= 0 && Rxframeind & 040) + Usevhdrs = 1; + + return c; +} + +long rclhdr(register char *hdr) +{ + register long l; + + l = (hdr[ZP3] & 0377); + l = (l << 8) | (hdr[ZP2] & 0377); + l = (l << 8) | (hdr[ZP1] & 0377); + l = (l << 8) | (hdr[ZP0] & 0377); + return l; +} + + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +int tryz(){ + register int c, n; + register int cmdzack1flg; + uint8_t fname[255]; + //printf("In tryz function \r\n"); + for (n=15; --n>=0; ) { + /* Set buffer length (0) and capability flags */ + + stohdr(0L); + + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; + + if (Zctlesc) + Txhdr[ZF0] |= TESCCTL; + Txhdr[ZF0] |= CANRLE; + Txhdr[ZF1] = CANVHDR; + + /* tryzhdrtype may == ZRINIT */ + zshhdr(4, tryzhdrtype, Txhdr); + + if (tryzhdrtype == ZSKIP) /* Don't skip too far */ + tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ +again: + switch (zgethdr(Rxhdr)) { + case ZRQINIT: + if (Rxhdr[ZF3] & 0x80) + Usevhdrs = 1; /* we can var header */ + continue; + case ZEOF: + continue; + case TIMEOUT: + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + if (Rxhdr[ZF3] & ZCANVHDR) + Usevhdrs = TRUE; + tryzhdrtype = ZRINIT; + c = zrdata(secbuf, 1024); + + char* temp_secbuf_p; + temp_secbuf_p = secbuf; + temp_secbuf_p += 0; + + temp_secbuf_p = secbuf; + printf("name offset %d \n",(int)(temp_secbuf_p-secbuf)); + while(*(temp_secbuf_p++) !=0x00) + { + printf(" %x,",*temp_secbuf_p); + if((temp_secbuf_p-secbuf)%16==0) + printf("\n"); + } + strcpy(fname+1,secbuf); + #ifdef zfs_enable + fname[0]='/'; + fd=SPIFFS_open(&fs,fname, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); + if(fd == -1){ + mp_raise_OSError(MP_EIO); + } + #endif + //uarths_send_data(fname,strlen(fname)+1); + printf("offset %d \n",(int)(temp_secbuf_p-secbuf)); + //temp_secbuf_p++; + while(*(temp_secbuf_p++) !=0x20) + { + zfile_total_size = zfile_total_size*10; + zfile_total_size +=*(temp_secbuf_p-1)-0x30; + printf(" %x,",*(temp_secbuf_p-1)); + if((temp_secbuf_p-secbuf)%16==0) + printf("\n"); + } + printf("again:ZFILE file size %d\n",zfile_total_size); + + if (c == GOTCRCW) + return ZFILE; + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZSINIT: + Zctlesc = TESCCTL & Rxhdr[ZF0]; + if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { + stohdr(1L); + zshhdr(4,ZACK, Txhdr); + goto again; + } + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZFREECNT: + stohdr(getfree()); + zshhdr(4,ZACK, Txhdr); + goto again; + case ZCOMMAND: + + cmdzack1flg = Rxhdr[ZF0]; + if (zrdata(secbuf, 1024) == GOTCRCW) { + //void exec2(); + + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + //stohdr((long)sys2(secbuf)); + //purgeline(); /* dump impatient questions */ + do { + zshhdr(4,ZCOMPL, Txhdr); + } + while (++errors<20 && zgethdr(Rxhdr) != ZFIN); + //ackbibi(); + /*if (cmdzack1flg & ZCACK1) + exec2(secbuf);*/ + return ZCOMPL; + } + zshhdr(4,ZNAK, Txhdr); goto again; + case ZCOMPL: + goto again; + default: + continue; + case ZFIN: + printf("\r\n"); + printf("ZFIN finishe\n"); + sendline(ZPAD); + sendline(ZPAD); + sendline(ZDLE); + sendline(Rxframeind); + sendline(0x30); + sendline(0x38); + sendline(0x30);sendline(0x30);sendline(0x30);sendline(0x30);sendline(0x30);sendline(0x30);sendline(0x30);sendline(0x30); + sendline(0x30);sendline(0x32);sendline(0x32);sendline(0x64); + sendline(0x0D);sendline(0x0A);sendline(0x11); + if(zdlread()==0x4f) + { + if(zdlread()==0x4f) + { + sendline(0x23);sendline(0x20); + } + } + return ZCOMPL; + case ZCAN: + return ERROR; + } + } + return 0; + +} + + +/*receive 1 file with ZMODEM protocol*/ +int rzfile(char* secbuf) +{ + printf("Hello, this is rzfile program\r\n"); + register int c,n; + Eofseen = FALSE; + n = 20; + rxbytes = 0l; + if(c = procheader(secbuf)){ + return (tryzhdrtype = c); + } + printf("c = procheader(secbuf)\n"); + for(;;){ + printf("Send ZRINIT success\r\n"); + stohdr(rxbytes); + zshhdr(4, ZRPOS, Txhdr); + nxthdr: + c = zgethdr(Rxhdr); + printf("In nxthdr, got %s\r\n", frametypes[c+FTOFFSET]); + switch(c){ + default: + //wrong header + if(--n < 0){ + printf("rzfile: Wrong header %d\r\n", c); + return ERROR; + } + continue; + case ZCAN: + printf("Sender CANcelled\r\n"); + return ERROR; + case ZNAK: + if ( --n < 0) { + printf("rzfile: got ZNAK\r\n"); + return ERROR; + } + continue; + case TIMEOUT: + if ( --n < 0) { + printf("rzfile: TIMEOUT\r\n"); + return ERROR; + } + continue; + case ZFILE: + zrdata(secbuf, 1024); + continue; + case ZEOF: + if(rclhdr(Rxhdr) != rxbytes){ + /* + * Ignore eof if it's at wrong place - force + * a timeout because the eof might have gone + * out before we sent our zrpos. + */ + errors = 0; + goto nxthdr; + } + #ifdef mydel + if(f_close(&fout) != 0){ + #else + if(0){ + #endif + tryzhdrtype = ZFERR; + printf("Error closing file\r\n"); + return ERROR; + } + return c; + case ERROR: + if ( --n < 0) { + printf("Persistent CRC or other ERROR\r\n"); + return ERROR; + } + zmputs(Attn); + continue; + case ZSKIP: + Modtime = 1; + #ifdef mydel + f_close(&fout); + #endif + printf("Sender SKIPPED file\r\n"); + return c; + case ZDATA: + printf("i am here--zdata size %d,%d\r\n",rclhdr(Rxhdr),rxbytes); + #ifndef mydel + if (rclhdr(Rxhdr) != rxbytes) { + #else + if (0) { + #endif + #ifndef mydel + if ( --n < 0) { + printf("Data has bad addr\r\n"); + return ERROR; + } + #else + if(1) + #endif + zmputs(Attn); + continue; + printf("continue\r\n"); + } + printf("moredata\r\n"); + moredata: + printf("zrdata zfile_total_size %d \n",zfile_total_size); + printf("zrdata size %d\n",f->fsize); + int size = f->fsize; + int total_size = zfile_total_size; + int Remain_Data = total_size-size; + printf("zrdata Remain_Data %d\n",Remain_Data); + c = zrdata(secbuf, Remain_Data); + //printf("moredata %d %s\r\n",c,frametypes[c+FTOFFSET]); + switch (c){ + case ZCAN: + printf("moredata:Sender CANcelled\r\n"); + return ERROR; + case ERROR: //CRC error + if ( --n < 0) { + printf("Persistent CRC or other ERROR\n"); + return ERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: + if ( --n < 0) { + printf("TIMEOUT\n"); + return ERROR; + } + continue; + case GOTCRCW: + printf("GOTCRCW\n"); + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + sendline(XON); + zshhdr(4,ZACK, Txhdr); + goto nxthdr; + case GOTCRCQ: + printf("GOTCRCQ\n"); + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(4,ZACK, Txhdr); + goto moredata; + case GOTCRCG: + printf("GOTCRCG\n"); + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto moredata; + case GOTCRCE: + printf("GOTCRCE\n"); + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto nxthdr; + } + } + } +} + + +/* + * Receive 1 or more files with ZMODEM protocol + */ +int rzfiles() +{ + register int c; + printf("In rzfiles function\r\n"); + for (;;) { + switch (c = rzfile(secbuf)) { + case ZEOF: + case ZSKIP: + case ZFERR: + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return ERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case ERROR: + return ERROR; + } + } + /* NOTREACHED */ +} + + +/* + * Wcgetsec fetches a Ward Christensen type sector. + * Returns sector number encountered or ERROR if valid sector not received, + * or CAN CAN received + * or WCEOT if eot sector + * time is timeout for first char, set to 4 seconds thereafter + ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** + * (Caller must do that when he is good and ready to get next sector) + */ + +int wcgetsec(char *rxbuf, int maxtime) //��������һ��������setbuf +{ + register int checksum, wcj, firstch; + register unsigned short oldcrc; + register char *p; + int sectcurr; + + for (Lastrx=errors=0; errors=0; ) { + if ((firstch=zm_readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + checksum += (*p++ = firstch); + } + if ((firstch=zm_readline(1)) < 0) + goto bilge; + if (Crcflg) { + oldcrc=updcrc(firstch, oldcrc); + if ((firstch=zm_readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + if (oldcrc & 0xFFFF) + printf( "CRC\r\n"); + else { + Firstsec=FALSE; + return sectcurr; //�������� + } + } + else if (((checksum-firstch)&0377)==0) { + Firstsec=FALSE; + return sectcurr; //�������� + } + else + printf( "Checksum\r\n"); + } + else + printf("Sector number garbled\r\n"); + } + /* make sure eot really is eot and not just mixmash */ + else if (firstch==EOT && Lleft==0) + return WCEOT; + else if (firstch==CAN) { + if (Lastrx==CAN) { + printf( "Sender CANcelled\r\n"); + return ERROR; + } else { + Lastrx=CAN; + continue; + } + } + else if (firstch==TIMEOUT) { + if (Firstsec) + goto humbug; +bilge: + printf( "TIMEOUT\r\n"); + } + else + printf( "Got 0%o sector header\r\n", firstch); + +humbug: + Lastrx=0; + while(zm_readline(1)!=TIMEOUT) + ; + if (Firstsec) { + sendline(Crcflg?WANTCRC:NAK); + //flushmo(); + Lleft=0; /* Do read next time ... */ + } else { + maxtime=40; sendline(NAK); + //flushmo(); + Lleft=0; /* Do read next time ... */ + } + } + /* try to stop the bubble machine. */ + canit(); + return ERROR; +} + + + +/* + * Fetch a pathname from the other end as a C ctyle ASCIZ string. + * Length is indeterminate as long as less than Blklen + * A null string represents no more files (ZMODEM) + */ +int wcrxpn(char *rpn) /* receive a pathname */ +{ + register int c; + + //purgeline(); + +et_tu: + Firstsec = TRUE; + Eofseen = FALSE; + sendline(Crcflg?WANTCRC:NAK); + Lleft=0; /* Do read next time ... */ + switch (c = wcgetsec(rpn, 100)) { + case WCEOT: + printf( "Pathname fetch returned %d\r\n", c); + sendline(ACK); + Lleft=0; /* Do read next time ... */ + zm_readline(1); + goto et_tu; + case 0: + sendline(ACK); + return OK; + default: + return ERROR; + } +} + +/* + * Adapted from CMODEM13.C, written by + * Jack M. Wierda and Roderick W. Hart + */ + +int wcrx() +{ + register int sectnum, sectcurr; + register char sendchar; /*data to be sent*/ + int cblklen; /* bytes to dump this block */ + + Firstsec=TRUE; + sectnum=0; + Eofseen=FALSE; + sendchar=Crcflg?WANTCRC:NAK; /*���CRCflg�� ������sendchar=NAK*/ + + for (;;) { + sendline(sendchar); /* send it now, we're ready! */ + //flushmo(); + Lleft=0; /* Do read next time ... number of characters in linbuf linbufΪʣ���ֽڻ���*/ + sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); //��7λΪ1 + if (sectcurr==(sectnum+1 &0377)) { + sectnum++; + cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; + if (putsec(secbuf, cblklen)==ERROR) + return ERROR; + if ((Bytesleft-=cblklen) < 0) + Bytesleft = 0; + sendchar=ACK; + } + else if (sectcurr==(sectnum&0377)) { + printf( "Received dup Sector\r\n"); + sendchar=ACK; + } + else if (sectcurr==WCEOT) { + #ifdef mydel + if (f_close(&fout) != 0) + return ERROR; + #endif + sendline(ACK); + //flushmo(); + Lleft=0; /* Do read next time ... */ + return OK; //�ɹ����� + } + else if (sectcurr==ERROR) + return ERROR; + else { + printf( "Sync Error\r\n"); + return ERROR; + } + } + /* NOTREACHED */ +} +/************IMPORTANT RZ External Function************/ +//int rz(char* fname) //���ݲ�����û��ȷ�� +int rz(void) +{ + register int c; + printf("In rz function\r\n"); + if (c = tryz()) { + if (c == ZCOMPL) + return OK; + if (c == ERROR) + + goto fubar; + c = rzfiles(); + if (c) + goto fubar; + } else { + for (;;) { + if (wcrxpn(secbuf)== ERROR) + goto fubar; + if (secbuf[0]==0) + return OK; + if (procheader(secbuf)) + goto fubar; + if (wcrx()==ERROR) + goto fubar; + } + } + + return OK; + +fubar: + printf("Error automatically go to fubar\r\n"); + Modtime = 1; + + #ifdef mydel + if ((&fout) == NULL) + f_close(&fout); + #endif + + return ERROR; + + +} + +typedef struct _machine_zmodem_obj_t { + mp_obj_base_t base; +} machine_zmodem_obj_t; + +//QueueHandle_t zmodem_QUEUE[zmodem_NUM_MAX] = {}; + +/******************************************************************************/ +// MicroPython bindings for zmodem + +STATIC void machine_zmodem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_zmodem_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "zmodem(file_patch)"); +} + +STATIC mp_obj_t machine_zmodem_rz(mp_obj_t file_patch_obj) { + //uint8_t *temp_file_patch; + //if (file_patch_obj != MP_OBJ_NULL) { + // temp_file_patch=mp_obj_str_get_str(file_patch_obj); + //}else{ + // mp_raise_ValueError("please input file patch"); + //} +#ifdef uarths_enable + uarths_init(); + //uarths_config(115200,UART_STOP_1); +#else + uart_init(0); + uart_config(UART_DEVICE_1, (size_t)115200, UART_BITWIDTH_8BIT, UART_STOP_1, UART_PARITY_NONE); +#endif + f = malloc(sizeof(file_f)); + f->fsize=0; + rz(); + #ifdef zfs_enable + SPIFFS_close (&fs, fd); + #endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_zmodem_rz_obj, machine_zmodem_rz); + +STATIC void machine_zmodem_init_helper(machine_zmodem_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + /* + enum { ARG_file_patch}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file_patch, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t *temp_file_patch; + if (args[ARG_file_patch].u_obj != MP_OBJ_NULL) { + temp_file_patch=mp_obj_str_get_str(args[ARG_file_patch].u_obj); + }else{ + mp_raise_ValueError("please input file patch"); + } + */ + +} + +STATIC mp_obj_t machine_zmodem_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create instance + machine_zmodem_obj_t *self = m_new_obj(machine_zmodem_obj_t); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_zmodem_init_helper(self, n_args, args, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_zmodem_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_zmodem_init_helper(args[0], n_args , args , kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_zmodem_init_obj, 0, machine_zmodem_init); + + +STATIC const mp_rom_map_elem_t machine_zmodem_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_zmodem_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_rz), MP_ROM_PTR(&machine_zmodem_rz_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_zmodem_locals_dict, machine_zmodem_locals_dict_table); + + + +const mp_obj_type_t machine_zmodem_type = { + { &mp_type_type }, + .name = MP_QSTR_zmodem, + .print = machine_zmodem_print, + .make_new = machine_zmodem_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_zmodem_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/modmachine.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/modmachine.c new file mode 100755 index 0000000..2f5200f --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/machine/modmachine.c @@ -0,0 +1,38 @@ +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/binary.h" +#include + +#include "modmachine.h" + +#if MICROPY_PY_MACHINE + +STATIC const mp_map_elem_t machine_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) }, + { MP_ROM_QSTR(MP_QSTR_uarths), MP_ROM_PTR(&machine_uarths_type) }, + { MP_ROM_QSTR(MP_QSTR_uart), MP_ROM_PTR(&machine_uart_type) }, + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_pwm), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_timer), MP_ROM_PTR(&machine_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_st7789), MP_ROM_PTR(&machine_st7789_type) }, + { MP_ROM_QSTR(MP_QSTR_ov2640), MP_ROM_PTR(&machine_ov2640_type) }, + { MP_ROM_QSTR(MP_QSTR_burner), MP_ROM_PTR(&machine_burner_type) }, + { MP_ROM_QSTR(MP_QSTR_demo_face_detect), MP_ROM_PTR(&machine_demo_face_detect_type) }, + { MP_ROM_QSTR(MP_QSTR_spiflsah), MP_ROM_PTR(&machine_spiflash_type) }, + { MP_ROM_QSTR(MP_QSTR_zmodem), MP_ROM_PTR(&machine_zmodem_type) }, + { MP_ROM_QSTR(MP_QSTR_fpioa), MP_ROM_PTR(&machine_fpioa_type) }, + { MP_ROM_QSTR(MP_QSTR_ws2812), MP_ROM_PTR(&machine_ws2812_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT ( + machine_module_globals, + machine_module_globals_table +); + +const mp_obj_module_t machine_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/uos/moduos.c b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/uos/moduos.c new file mode 100755 index 0000000..c78b0e8 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/mpy-mod/uos/moduos.c @@ -0,0 +1,466 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#if MICROPY_VFS +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +/*hutu*/ +#include "spiffs_configport.h" +#include "spiffs.h" +#endif +#include "genhdr/mpversion.h" +#if !MICROPY_VFS +#include "spiffs-port.h" +#include "py/lexer.h" +#endif + +extern mp_obj_t file_open(const char* file_name, const mp_obj_type_t *type, mp_arg_val_t *args); +extern const mp_obj_type_t mp_type_vfs_spiffs_textio; +static unsigned char current_dir[FS_PATCH_LENGTH]; +extern const mp_obj_type_t mp_fat_vfs_type; + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + uint32_t r = 0; + for (int i = 0; i < n; i++) { + if ((i & 3) == 0) { + //r = esp_random(); // returns 32-bit hardware random number + } + vstr.buf[i] = r; + r >>= 8; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +mp_import_stat_t mp_vfs_import_stat(const char *path) { + + //if (st_mode & MP_S_IFDIR) { + // return MP_IMPORT_STAT_DIR; + //} else { + // return MP_IMPORT_STAT_FILE; + //} + spiffs_stat st; + + //if (SPIFFS_stat(&fs,path, &st) == 0) { + return MP_IMPORT_STAT_FILE; + //}else{ + //return MP_IMPORT_STAT_NO_EXIST; + //} + +} + +#if MICROPY_PY_OS_DUPTERM +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + for (;;) { + int c = mp_uos_dupterm_rx_chr(); + if (c < 0) { + break; + } + ringbuf_put(&stdin_ringbuf, c); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); +#endif + +#if !MICROPY_VFS + +uint32_t API_FS_GetCurDir(uint32_t size,uint8_t *str) +{ + memcpy(str,current_dir,size); + return 0; +} + +mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { + mp_obj_t dir_list = mp_obj_new_list(0, NULL); + char* tmp = (char*)malloc(FS_PATCH_LENGTH); + if(!tmp) + mp_raise_OSError(MP_ENOMEM); + memset(tmp,0,FS_PATCH_LENGTH); + uint32_t ret =API_FS_GetCurDir(FS_PATCH_LENGTH,tmp); + if(ret != 0) + { + free(tmp); + mp_raise_OSError(MP_EIO); + } + char* dirToList = "/"; + if(n_args != 0 ) + dirToList = (char*)mp_obj_str_get_str(args[0]); + else + { + dirToList = tmp; + } + + spiffs_DIR dir; + if (!SPIFFS_opendir (&fs, (const char*)dirToList, &dir)) + mp_raise_OSError(MP_EIO); + struct spiffs_dirent de; + while (SPIFFS_readdir (&dir, &de)) + { + static const char types[] = "?fdhs"; // file, dir, hardlink, softlink + char name[sizeof(de.name)+1] = { 0 }; + char res_str[SPIFFS_OBJ_NAME_LEN+10]={0}; + memcpy (name, de.name, sizeof(de.name)); + sprintf(res_str,"%c %6u %s", types[de.type], de.size, name); + + // Trace(1,"dir name:%s",dirent->d_name); + mp_obj_t dirStr = mp_obj_new_str(res_str,strlen(res_str)); + mp_obj_list_append(dir_list, dirStr); + } + SPIFFS_closedir (&dir); + SPIFFS_opendir(&fs,tmp, &dir); + free(tmp); + return dir_list; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj, 0, 1, mp_vfs_listdir); + +mp_obj_t mp_vfs_ls(size_t n_args, const mp_obj_t *args) { + mp_obj_t dir_list = mp_obj_new_list(0, NULL); + char* tmp = (char*)malloc(FS_PATCH_LENGTH); + if(!tmp) + mp_raise_OSError(MP_ENOMEM); + memset(tmp,0,FS_PATCH_LENGTH); + uint32_t ret =API_FS_GetCurDir(FS_PATCH_LENGTH,tmp); + if(ret != 0) + { + free(tmp); + mp_raise_OSError(MP_EIO); + } + char* dirToList = "/"; + if(n_args != 0 ) + dirToList = (char*)mp_obj_str_get_str(args[0]); + else + { + dirToList = tmp; + } + + spiffs_DIR dir; + if (!SPIFFS_opendir (&fs, (const char*)dirToList, &dir)) + mp_raise_OSError(MP_EIO); + struct spiffs_dirent de; + while (SPIFFS_readdir (&dir, &de)) + { + char name[sizeof(de.name)+1] = { 0 }; + char res_str[SPIFFS_OBJ_NAME_LEN]={0}; + memcpy (name, de.name, sizeof(de.name)); + sprintf(res_str,"%s",name); + + // Trace(1,"dir name:%s",dirent->d_name); + mp_obj_t dirStr = mp_obj_new_str(res_str,strlen(res_str)); + mp_obj_list_append(dir_list, dirStr); + } + SPIFFS_closedir (&dir); + SPIFFS_opendir(&fs,tmp, &dir); + free(tmp); + return dir_list; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_ls_obj, 0, 1, mp_vfs_ls); + +mp_obj_t mp_vfs_formatfs(size_t n_args, const mp_obj_t *args) { + + int res = format_fs(); + printf("spiffs mount %s \n", res?"failed":"successful"); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_formatfs_obj, 0, 1, mp_vfs_formatfs); + + +mp_obj_t mp_vfs_mkdir(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + if(strcmp(path,"/")==0 || strcmp(path,"/t")==0) + { + mp_raise_OSError(MP_EEXIST); + } + spiffs_stat st; + int status = 0; + + if (SPIFFS_stat(&fs,path, &st) != 0) { + /* Directory does not exist. EEXIST for race condition */ + //if (mkdir(&fs,path, 0) != 0 && errno != EEXIST) { + // mp_raise_OSError(MP_EIO); + //} + } else { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj, mp_vfs_mkdir); + +mp_obj_t mp_vfs_remove(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + if(strcmp(path,"/")==0 || strcmp(path,"/t")==0) + { + mp_raise_OSError(MP_EINVAL); + } + s32_t ret = SPIFFS_remove(&fs,path); + if(ret != 0) + mp_raise_OSError(MP_EIO); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_remove_obj, mp_vfs_remove); + +mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { + const char* path_old = mp_obj_str_get_str(old_path_in); + const char* path_new = mp_obj_str_get_str(new_path_in); + s32_t ret = SPIFFS_rename(&fs, path_old, path_new); + if(ret != 0) + mp_raise_OSError(MP_EIO); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_vfs_rename_obj, mp_vfs_rename); + +//#define SPIFFS_SEEK_SET (0) +//#define SPIFFS_SEEK_CUR (1) +//#define SPIFFS_SEEK_END (2) + +mp_obj_t mp_vfs_write(size_t n_args, const mp_obj_t *args) { + + const char* path = mp_obj_str_get_str(args[0]); + s32_t offset = mp_obj_get_int(args[1]); + int mode = mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + spiffs_file fd; + fd=SPIFFS_open(&fs,path, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); + if(fd == -1){ + mp_raise_OSError(MP_EIO); + } + s32_t ls_res = SPIFFS_lseek(&fs, fd,offset,mode); + if(ls_res != 0){ + printf("lseek err\n"); + mp_raise_OSError(MP_EIO); + } + s32_t w_res = SPIFFS_write(&fs, fd, bufinfo.buf, bufinfo.len); + if(w_res <= 0){ + printf("write err\n"); + mp_raise_OSError(MP_EIO); + } + s32_t f_res = SPIFFS_fflush(&fs, fd); + if(f_res != 0){ + printf("fflush err\n"); + mp_raise_OSError(MP_EIO); + } + SPIFFS_close (&fs, fd); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_write_obj, 0, 4, mp_vfs_write); + +mp_obj_t mp_vfs_read(size_t n_args, const mp_obj_t *args) { + + const char* path = mp_obj_str_get_str(args[0]); + s32_t offset = mp_obj_get_int(args[1]); + int mode = mp_obj_get_int(args[2]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_WRITE); + spiffs_file fd; + fd=SPIFFS_open(&fs,path, SPIFFS_RDWR, 0); + if(fd == -1){ + mp_raise_OSError(MP_EIO); + } + + s32_t ls_res = SPIFFS_lseek(&fs, fd,offset,mode); + if(ls_res != 0){ + mp_raise_OSError(MP_EIO); + } + s32_t r_res = SPIFFS_read(&fs, fd, bufinfo.buf, bufinfo.len); + if(r_res < 0){ + printf("read err %d\n",r_res); + mp_raise_OSError(MP_EIO); + } + SPIFFS_close (&fs, fd); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_read_obj, 0, 4, mp_vfs_read); + +/* +mp_obj_t mp_vfs_rmdir(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + if(strcmp(path,"/")==0 || strcmp(path,"/t")==0) + { + mp_raise_OSError(MP_EINVAL); + } + int32_t ret = API_FS_Rmdir(path); + if(ret != 0) + mp_raise_OSError(MP_EIO); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj, mp_vfs_rmdir); + + +mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + int32_t ret = API_FS_ChangeDir(path); + if(ret != 0) + mp_raise_OSError(MP_EIO); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir); + +mp_obj_t mp_vfs_getcwd(void) { + char* tmp = (char*)malloc(200); + if(!tmp) + mp_raise_OSError(MP_ENOMEM); + memset(tmp,0,200); + uint32_t ret =API_FS_GetCurDir(200,tmp); + if(ret != 0) + { + free(tmp); + mp_raise_OSError(MP_EIO); + } + mp_obj_t retVal = mp_obj_new_str(tmp,strlen(tmp)); + free(tmp); + return retVal; +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj, mp_vfs_getcwd); +*/ + +mp_obj_t mp_vfs_stat(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + + u32_t total, used; + s32_t ret = SPIFFS_info(&fs, &total, &used); + + if(ret != 0) + mp_raise_OSError(MP_EIO); + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = mp_obj_new_int(total); + t->items[1] = mp_obj_new_int(used); + return MP_OBJ_FROM_PTR(t); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_stat_obj, mp_vfs_stat); + +mp_obj_t mp_vfs_statvfs(mp_obj_t path_in) { + const char* path = mp_obj_str_get_str(path_in); + + u32_t total, used; + s32_t ret = SPIFFS_info(&fs, &total, &used); + + if(ret != 0) + mp_raise_OSError(MP_EIO); + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = mp_obj_new_int(total); + t->items[1] = mp_obj_new_int(used); + return MP_OBJ_FROM_PTR(t); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs); + +#endif //#if !MICROPY_VFS + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, + #endif + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif + #endif + #if !MICROPY_VFS + //{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_ls), MP_ROM_PTR(&mp_vfs_ls_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_vfs_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_vfs_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_formatfs), MP_ROM_PTR(&mp_vfs_formatfs_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t uos_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/k210-standalone/qstrdefsport.h b/src/openmv/src/micropython/ports/k210-standalone/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/k210-standalone/sdk.patch b/src/openmv/src/micropython/ports/k210-standalone/sdk.patch new file mode 100755 index 0000000..b90d828 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/sdk.patch @@ -0,0 +1,146 @@ +diff -r -u -E kendryte-standalone-sdk/lib/drivers/dvp.c kendryte/lib/drivers/dvp.c +--- kendryte-standalone-sdk/lib/drivers/dvp.c 2018-10-26 13:42:14.109489584 +0800 ++++ kendryte/lib/drivers/dvp.c 2018-10-25 22:22:42.985657618 +0800 +@@ -103,7 +103,7 @@ + return (uint8_t) DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg); + } + +-static void dvp_reset(void) ++void dvp_reset(void) + { + /* First power down */ + dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN; +diff -r -u -E kendryte-standalone-sdk/lib/drivers/include/dvp.h kendryte/lib/drivers/include/dvp.h +--- kendryte-standalone-sdk/lib/drivers/include/dvp.h 2018-10-26 13:42:14.109489584 +0800 ++++ kendryte/lib/drivers/include/dvp.h 2018-10-25 22:22:42.985657618 +0800 +@@ -244,6 +244,9 @@ + */ + void dvp_set_output_enable(dvp_output_mode_t index, int enable); + ++void dvp_reset(void); ++ ++ + #ifdef __cplusplus + } + #endif +diff -r -u -E kendryte-standalone-sdk/lib/drivers/include/timer.h kendryte/lib/drivers/include/timer.h +--- kendryte-standalone-sdk/lib/drivers/include/timer.h 2018-10-26 13:42:14.113489433 +0800 ++++ kendryte/lib/drivers/include/timer.h 2018-10-25 22:22:42.985657618 +0800 +@@ -120,7 +120,26 @@ + * @param[in] enable Enable or disable + * + */ ++ ++void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel); ++void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel); ++ ++void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode); + void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable); ++void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div); ++void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count); ++ ++uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel); ++uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel); ++ ++ ++void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel); ++void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel); ++ ++ ++ ++ ++ + + #ifdef __cplusplus + } +diff -r -u -E kendryte-standalone-sdk/lib/drivers/include/uarths.h kendryte/lib/drivers/include/uarths.h +--- kendryte-standalone-sdk/lib/drivers/include/uarths.h 2018-10-26 13:42:14.113489433 +0800 ++++ kendryte/lib/drivers/include/uarths.h 2018-10-25 22:22:42.985657618 +0800 +@@ -285,6 +285,12 @@ + */ + void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8_t cnt); + ++int on_irq_uarths_recv(void *param); ++ ++int read_ringbuff(char *rdata, size_t len); ++int write_ringbuff(uint8_t rdata); ++ ++ + #ifdef __cplusplus + } + #endif +diff -r -u -E kendryte-standalone-sdk/lib/drivers/uarths.c kendryte/lib/drivers/uarths.c +--- kendryte-standalone-sdk/lib/drivers/uarths.c 2018-10-26 13:42:14.113489433 +0800 ++++ kendryte/lib/drivers/uarths.c 2018-10-25 22:22:42.985657618 +0800 +@@ -18,8 +18,57 @@ + #include "uarths.h" + #include "sysctl.h" + #include "encoding.h" +- ++#include "atomic.h" ++#include "malloc.h" + volatile uarths_t *const uarths = (volatile uarths_t *)UARTHS_BASE_ADDR; ++int pos = 0; ++#define RING_BUFF_LEN 1024U ++ ++typedef struct _ring_buff_t ++{ ++ size_t head; ++ size_t tail; ++ size_t length; ++ char ring_buff[RING_BUFF_LEN]; ++} ring_buff_t; ++ring_buff_t *ring_recv_hs = NULL; ++ ++int write_ringbuff(uint8_t rdata) ++{ ++ ring_buff_t *rb = ring_recv_hs; ++ ++ if (rb->length >= RING_BUFF_LEN) ++ { ++ return -1; ++ } ++ rb->ring_buff[rb->tail] = rdata; ++ rb->tail = (rb->tail + 1) % RING_BUFF_LEN; ++ atomic_add(&rb->length, 1); ++ return ; ++} ++ ++int read_ringbuff(char *rdata, size_t len) ++{ ++ ring_buff_t *rb = ring_recv_hs; ++ size_t cnt = 0; ++ while((len--) && rb->length) ++ { ++ *(rdata++) = rb->ring_buff[rb->head]; ++ rb->head = (rb->head + 1) % RING_BUFF_LEN; ++ atomic_add(&rb->length, -1); ++ cnt++; ++ } ++ return cnt; ++} ++int on_irq_uarths_recv(void *param) ++{ ++ ++ pos++; ++ uarths_rxdata_t recv = uarths->rxdata; ++ while(recv.empty); ++ write_ringbuff(((uint8_t)(recv.data & 0xFF))); ++ return 0; ++} + + typedef struct _uarths_context + { +@@ -164,6 +213,12 @@ + uarths->ip.rxwm = 1; + uarths->ie.txwm = 0; + uarths->ie.rxwm = 1; ++ ++ ring_buff_t *rb = malloc(sizeof(ring_buff_t)); ++ rb->head = 0; ++ rb->tail = 0; ++ rb->length = 0; ++ ring_recv_hs = rb; + } + + void uarths_config(uint32_t baud_rate, uarths_stopbit_t stopbit) diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/params_test.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/params_test.h new file mode 100755 index 0000000..fde9ffc --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/params_test.h @@ -0,0 +1,91 @@ +/* + * params_test.h + * + * Created on: May 26, 2013 + * Author: petera + */ + +#ifndef PARAMS_TEST_H_ +#define PARAMS_TEST_H_ +#include +typedef unsigned int u32; +typedef unsigned short int u16; +typedef unsigned char u8; + +typedef int s32 ; +typedef short int s16; +typedef signed char s8; +//////////////// TEST PARAMS //////////////// + +// default test total emulated spi flash size +#define PHYS_FLASH_SIZE (8*1024*1024) +// default test spiffs file system size +#define SPIFFS_FLASH_SIZE (2*1024*1024) +// default test spiffs file system offset in emulated spi flash +#define SPIFFS_PHYS_ADDR (4*1024*1024) +// default test sector size +#define SECTOR_SIZE 65536 +// default test logical block size +#define LOG_BLOCK (SECTOR_SIZE*2) +// default test logical page size +#define LOG_PAGE (SECTOR_SIZE/256) +// default test number of filedescs +#define DEFAULT_NUM_FD 16 +// default test number of cache pages +#define DEFAULT_NUM_CACHE_PAGES 8 + +// When testing, test bench create reference files for comparison on +// the actual hard drive. By default, put these on ram drive for speed. +#define TEST_PATH "/dev/shm/spiffs/test-data/" + +#define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__); +void real_assert(int c, const char *n, const char *file, int l); + +/////////// SPIFFS BUILD CONFIG //////////// + +// test using filesystem magic +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC 1 +#endif +// test using filesystem magic length +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH 1 +#endif +// test using extra param in callback +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 0 +#endif +// test using filehandle offset +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 1 +// use this offset +#define TEST_SPIFFS_FILEHDL_OFFSET 0x1000 +#endif + +#ifdef NO_TEST +#define SPIFFS_LOCK(fs) +#define SPIFFS_UNLOCK(fs) +#else +struct spiffs_t; +extern void test_lock(struct spiffs_t *fs); +extern void test_unlock(struct spiffs_t *fs); +#define SPIFFS_LOCK(fs) test_lock(fs) +#define SPIFFS_UNLOCK(fs) test_unlock(fs) +#endif + +// dbg output +#define SPIFFS_DBG(_f, ...) //printf("\x1b[32m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_API_DBG(_f, ...) //printf("\n\x1b[1m\x1b[7m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_GC_DBG(_f, ...) //printf("\x1b[36m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CACHE_DBG(_f, ...) //printf("\x1b[33m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CHECK_DBG(_f, ...) //printf("\x1b[31m" _f "\x1b[0m", ## __VA_ARGS__) + +// needed types +typedef signed int s32_t; +typedef unsigned int u32_t; +typedef signed short s16_t; +typedef unsigned short u16_t; +typedef signed char s8_t; +typedef unsigned char u8_t; + +#endif /* PARAMS_TEST_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs-port.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs-port.h new file mode 100755 index 0000000..b1ea360 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs-port.h @@ -0,0 +1,9 @@ +#ifndef MYSPIFFS_H +#define MYSPIFFS_H + +#include +void my_spiffs_mount(); +void my_spiffs_init(); +int format_fs(void); +extern spiffs fs; +#endif// MYSPIFFS_H diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_config.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_config.h new file mode 100755 index 0000000..04d9bd1 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_config.h @@ -0,0 +1,377 @@ +/* + * spiffs_config.h + * + * Created on: Jul 3, 2013 + * Author: petera + */ + +#ifndef SPIFFS_CONFIG_H_ +#define SPIFFS_CONFIG_H_ + +// ----------- 8< ------------ +// Following includes are for the linux test build of spiffs +// These may/should/must be removed/altered/replaced in your target +#include "params_test.h" +#include +#include +#include +#include +#include + +#ifdef _SPIFFS_TEST +#include "testrunner.h" +#endif + +#include "spiffs_configport.h" + +// ----------- >8 ------------ + +// compile time switches + +// Set generic spiffs debug output call. +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for garbage collecting. +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for caching. +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for system consistency checks. +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for all api invocations. +#ifndef SPIFFS_API_DBG +#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif + + + +// Defines spiffs debug print formatters +// some general signed number +#ifndef _SPIPRIi +#define _SPIPRIi "%d" +#endif +// address +#ifndef _SPIPRIad +#define _SPIPRIad "%08x" +#endif +// block +#ifndef _SPIPRIbl +#define _SPIPRIbl "%04x" +#endif +// page +#ifndef _SPIPRIpg +#define _SPIPRIpg "%04x" +#endif +// span index +#ifndef _SPIPRIsp +#define _SPIPRIsp "%04x" +#endif +// file descriptor +#ifndef _SPIPRIfd +#define _SPIPRIfd "%d" +#endif +// file object id +#ifndef _SPIPRIid +#define _SPIPRIid "%04x" +#endif +// file flags +#ifndef _SPIPRIfl +#define _SPIPRIfl "%02x" +#endif + + +// Enable/disable API functions to determine exact number of bytes +// for filedescriptor and cache buffers. Once decided for a configuration, +// this can be disabled to reduce flash. +#ifndef SPIFFS_BUFFER_HELP +#define SPIFFS_BUFFER_HELP 0 +#endif + +// Enables/disable memory read caching of nucleus file system operations. +// If enabled, memory area must be provided for cache in SPIFFS_mount. +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 +#endif +#if SPIFFS_CACHE +// Enables memory write caching for file descriptors in hydrogen +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 +#endif + +// Enable/disable statistics on caching. Debug/test purpose only. +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 1 +#endif +#endif + +// Always check header of each accessed page to ensure consistent state. +// If enabled it will increase number of reads, will increase flash. +#ifndef SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK 1 +#endif + +// Define maximum number of gc runs to perform to reach desired free pages. +#ifndef SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS 5 +#endif + +// Enable/disable statistics on gc. Debug/test purpose only. +#ifndef SPIFFS_GC_STATS +#define SPIFFS_GC_STATS 1 +#endif + +// Garbage collecting examines all pages in a block which and sums up +// to a block score. Deleted pages normally gives positive score and +// used pages normally gives a negative score (as these must be moved). +// To have a fair wear-leveling, the erase age is also included in score, +// whose factor normally is the most positive. +// The larger the score, the more likely it is that the block will +// picked for garbage collection. + +// Garbage collecting heuristics - weight used for deleted pages. +#ifndef SPIFFS_GC_HEUR_W_DELET +#define SPIFFS_GC_HEUR_W_DELET (5) +#endif +// Garbage collecting heuristics - weight used for used pages. +#ifndef SPIFFS_GC_HEUR_W_USED +#define SPIFFS_GC_HEUR_W_USED (-1) +#endif +// Garbage collecting heuristics - weight used for time between +// last erased and erase of this block. +#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#endif + +// Object name maximum length. Note that this length include the +// zero-termination character, meaning maximum string of characters +// can at most be SPIFFS_OBJ_NAME_LEN - 1. +#ifndef SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (32) +#endif + +// Maximum length of the metadata associated with an object. +// Setting to non-zero value enables metadata-related API but also +// changes the on-disk format, so the change is not backward-compatible. +// +// Do note: the meta length must never exceed +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64) +// +// This is derived from following: +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + +// spiffs_object_ix_header fields + at least some LUT entries) +#ifndef SPIFFS_OBJ_META_LEN +#define SPIFFS_OBJ_META_LEN (0) +#endif + +// Size of buffer allocated on stack used when copying data. +// Lower value generates more read/writes. No meaning having it bigger +// than logical page size. +#ifndef SPIFFS_COPY_BUFFER_STACK +#define SPIFFS_COPY_BUFFER_STACK (64) +#endif + +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + +#if SPIFFS_USE_MAGIC +// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is +// enabled, the magic will also be dependent on the length of the filesystem. +// For example, a filesystem configured and formatted for 4 megabytes will not +// be accepted for mounting with a configuration defining the filesystem as 2 +// megabytes. +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (0) +#endif +#endif + +// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level +// These should be defined on a multithreaded system + +// define this to enter a mutex if you're running on a multithreaded system +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) +#endif +// define this to exit a mutex if you're running on a multithreaded system +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) +#endif + +// Enable if only one spiffs instance with constant configuration will exist +// on the target. This will reduce calculations, flash and memory accesses. +// Parts of configuration must be defined below instead of at time of mount. +#ifndef SPIFFS_SINGLETON +#define SPIFFS_SINGLETON 0 +#endif + +#if SPIFFS_SINGLETON +// Instead of giving parameters in config struct, singleton build must +// give parameters in defines below. +#ifndef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2) +#endif +#ifndef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) +#endif +#ifndef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) +#endif +#ifndef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#endif +#ifndef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) +#endif +#endif + +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0 +#endif + +// Enable this if you want the HAL callbacks to be called with the spiffs struct +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 0 +#endif + +// Enable this if you want to add an integer offset to all file handles +// (spiffs_file). This is useful if running multiple instances of spiffs on +// same target, in order to recognise to what spiffs instance a file handle +// belongs. +// NB: This adds config field fh_ix_offset in the configuration struct when +// mounting, which must be defined. +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 0 +#endif + +// Enable this to compile a read only version of spiffs. +// This will reduce binary size of spiffs. All code comprising modification +// of the file system will not be compiled. Some config will be ignored. +// HAL functions for erasing and writing to spi-flash may be null. Cache +// can be disabled for even further binary size reduction (and ram savings). +// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL. +// If the file system cannot be mounted due to aborted erase operation and +// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be +// returned. +// Might be useful for e.g. bootloaders and such. +#ifndef SPIFFS_READ_ONLY +#define SPIFFS_READ_ONLY 0 +#endif + +// Enable this to add a temporal file cache using the fd buffer. +// The effects of the cache is that SPIFFS_open will find the file faster in +// certain cases. It will make it a lot easier for spiffs to find files +// opened frequently, reducing number of readings from the spi flash for +// finding those files. +// This will grow each fd by 6 bytes. If your files are opened in patterns +// with a degree of temporal locality, the system is optimized. +// Examples can be letting spiffs serve web content, where one file is the css. +// The css is accessed for each html file that is opened, meaning it is +// accessed almost every second time a file is opened. Another example could be +// a log file that is often opened, written, and closed. +// The size of the cache is number of given file descriptors, as it piggybacks +// on the fd update mechanism. The cache lives in the closed file descriptors. +// When closed, the fd know the whereabouts of the file. Instead of forgetting +// this, the temporal cache will keep handling updates to that file even if the +// fd is closed. If the file is opened again, the location of the file is found +// directly. If all available descriptors become opened, all cache memory is +// lost. +#ifndef SPIFFS_TEMPORAL_FD_CACHE +#define SPIFFS_TEMPORAL_FD_CACHE 1 +#endif + +// Temporal file cache hit score. Each time a file is opened, all cached files +// will lose one point. If the opened file is found in cache, that entry will +// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this +// value for the specific access patterns of the application. However, it must +// be between 1 (no gain for hitting a cached entry often) and 255. +#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE +#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4 +#endif + +// Enable to be able to map object indices to memory. +// This allows for faster and more deterministic reading if cases of reading +// large files and when changing file offset by seeking around a lot. +// When mapping a file's index, the file system will be scanned for index pages +// and the info will be put in memory provided by user. When reading, the +// memory map can be looked up instead of searching for index pages on the +// medium. This way, user can trade memory against performance. +// Whole, parts of, or future parts not being written yet can be mapped. The +// memory array will be owned by spiffs and updated accordingly during garbage +// collecting or when modifying the indices. The latter is invoked by when the +// file is modified in some way. The index buffer is tied to the file +// descriptor. +#ifndef SPIFFS_IX_MAP +#define SPIFFS_IX_MAP 1 +#endif + +// By default SPIFFS in some cases relies on the property of NOR flash that bits +// cannot be set from 0 to 1 by writing and that controllers will ignore such +// bit changes. This results in fewer reads as SPIFFS can in some cases perform +// blind writes, with all bits set to 1 and only those it needs reset set to 0. +// Most of the chips and controllers allow this behavior, so the default is to +// use this technique. If your controller is one of the rare ones that don't, +// turn this option on and SPIFFS will perform a read-modify-write instead. +#ifndef SPIFFS_NO_BLIND_WRITES +#define SPIFFS_NO_BLIND_WRITES 0 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// in the api. This function will visualize all filesystem using given printf +// function. +#ifndef SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 1 +#endif +#if SPIFFS_TEST_VISUALISATION +#ifndef spiffs_printf +#define spiffs_printf(...) printf(__VA_ARGS__) +#endif +// spiffs_printf argument for a free page +#ifndef SPIFFS_TEST_VIS_FREE_STR +#define SPIFFS_TEST_VIS_FREE_STR "_" +#endif +// spiffs_printf argument for a deleted page +#ifndef SPIFFS_TEST_VIS_DELE_STR +#define SPIFFS_TEST_VIS_DELE_STR "/" +#endif +// spiffs_printf argument for an index page for given object id +#ifndef SPIFFS_TEST_VIS_INDX_STR +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#endif +// spiffs_printf argument for a data page for given object id +#ifndef SPIFFS_TEST_VIS_DATA_STR +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#endif +#endif + +// Types depending on configuration such as the amount of flash bytes +// given to spiffs file system in total (spiffs_file_system_size), +// the logical block size (log_block_size), and the logical page size +// (log_page_size) + +// Block index type. Make sure the size of this type can hold +// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size +typedef u16_t spiffs_block_ix; +// Page index type. Make sure the size of this type can hold +// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size +typedef u16_t spiffs_page_ix; +// Object id type - most significant bit is reserved for index flag. Make sure the +// size of this type can hold the highest object id on a full system, +// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2 +typedef u16_t spiffs_obj_id; +// Object span index type. Make sure the size of this type can +// hold the largest possible span index on the system - +// i.e. (spiffs_file_system_size / log_page_size) - 1 +typedef u16_t spiffs_span_ix; + +#endif /* SPIFFS_CONFIG_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_configport.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_configport.h new file mode 100755 index 0000000..101de58 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/include/spiffs_configport.h @@ -0,0 +1,56 @@ + + +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 + +#define open_fs_debug 0 +#if open_fs_debug + // Set generic spiffs debug output call. + #define SPIFFS_DBG(_f, ...) printf(_f, ## __VA_ARGS__) + + // Set spiffs debug output call for garbage collecting. + #define SPIFFS_GC_DBG(_f, ...) printf(_f, ## __VA_ARGS__) + + // Set spiffs debug output call for caching. + + #define SPIFFS_CACHE_DBG(_f, ...) printf(_f, ## __VA_ARGS__) + + // Set spiffs debug output call for system consistency checks. + #define SPIFFS_CHECK_DBG(_f, ...) printf(_f, ## __VA_ARGS__) + + // Set spiffs debug output call for all api invocations. + #define SPIFFS_API_DBG(_f, ...) printf(_f, ## __VA_ARGS__) +#endif + +#define FS_PATCH_LENGTH (SPIFFS_OBJ_NAME_LEN*20+20) +#define FLASH_CHIP_SIZE (16*1024*1024) + +#define SPIFFS_OBJ_NAME_LEN (255) +#define SPIFFS_SINGLETON(ignore) (1) +#define SPIFFS_CFG_PHYS_SZ(ignore) (6 * 1024 * 1024) +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (32*1024) +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0x600000) + +#define PAGEN_EACH_BLOCK 32 +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (4*32*1024) +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (SPIFFS_CFG_LOG_BLOCK_SZ(ignore)/PAGEN_EACH_BLOCK) + +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (1) +#endif +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (1) +#endif +#define SPIFFS_READ_ONLY 0 + +#define SPIFFS_CACHE(ignore) (1) +#define SPIFFS_CACHE_WR(ignore) (1) +#define SPIFFS_TEMPORAL_FD_CACHE(ignore) (1) + +typedef signed int s32_t; +typedef unsigned int u32_t; +typedef signed short s16_t; +typedef unsigned short u16_t; +typedef signed char s8_t; +typedef unsigned char u8_t; + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/spiffs-port.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/spiffs-port.c new file mode 100755 index 0000000..546f95e --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs-port/spiffs-port.c @@ -0,0 +1,142 @@ +#include "w25qxx.h" +#include "spiffs-port.h" +#include "spiffs_config.h" +#include +#include "sleep.h" + +#define foce_format_fs 0 + +spiffs fs; + +static u8_t spiffs_work_buf[SPIFFS_CFG_LOG_PAGE_SZ(fs)*2]; +static u8_t spiffs_fds[32*4]; +static u8_t spiffs_cache_buf[(SPIFFS_CFG_LOG_PAGE_SZ(fs)+32)*4]; + +s32_t my_spi_read(int addr, int size, char *buf) +{ + int phy_addr=addr; + enum w25qxx_status_t res = w25qxx_read_data(phy_addr, buf, size,W25QXX_QUAD); + #if open_fs_debug + printf("flash read addr:%x size:%d buf_head:%x %x\n",phy_addr,size,buf[0],buf[1]); + #endif + if (res != W25QXX_OK) { + printf("spifalsh read err\n"); + return SPIFFS_ERR_FULL; + } + return SPIFFS_OK; +} +s32_t my_spi_write(int addr, int size, char *buf) +{ + int phy_addr=addr; + + enum w25qxx_status_t res = w25qxx_write_data(phy_addr, buf, size); + #if open_fs_debug + printf("flash write addr:%x size:%d buf_head:%x,%x\n",phy_addr,size,buf[0],buf[1]); + #endif + if (res != W25QXX_OK) { + printf("spifalsh write err\n"); + return SPIFFS_ERR_FULL; + } + return SPIFFS_OK; +} +s32_t my_spi_erase(int addr, int size) +{ + int phy_addr=addr; + unsigned char *temp_pool; + #if open_fs_debug + printf("flash erase addr:%x size:%f\n",phy_addr,size/1024.00); + #endif + enum w25qxx_status_t res = w25qxx_32k_block_erase(phy_addr); + if (res != W25QXX_OK) { + printf("spifalsh erase err\n"); + return SPIFFS_ERR_FULL; + } + return SPIFFS_OK; +} + +void test_lock(spiffs *fs) { +} + +void test_unlock(spiffs *fs) { +} + +void my_spiffs_init(){ + + spiffs_config cfg; + cfg.phys_size = SPIFFS_CFG_PHYS_SZ(fs); // use all spi flash + cfg.phys_addr = SPIFFS_CFG_PHYS_ADDR(fs); // start spiffs at start of spi flash + cfg.phys_erase_block = SPIFFS_CFG_PHYS_ERASE_SZ(fs); // according to datasheet + cfg.log_block_size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); // let us not complicate things + cfg.log_page_size = SPIFFS_CFG_LOG_PAGE_SZ(fs); // as we said + + cfg.hal_read_f = my_spi_read; + cfg.hal_write_f = my_spi_write; + cfg.hal_erase_f = my_spi_erase; + + int res = SPIFFS_mount(&fs, + &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + spiffs_cache_buf, + sizeof(spiffs_cache_buf), + 0); + if(foce_format_fs || res != SPIFFS_OK || res==SPIFFS_ERR_NOT_A_FS) + { + SPIFFS_unmount(&fs);printf("spiffs unmounted...\n"); + printf("spiffs formating...\n"); + s32_t format_res=SPIFFS_format(&fs); + printf("spiffs formated res %d\n",format_res); + res = SPIFFS_mount(&fs, + &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + spiffs_cache_buf, + sizeof(spiffs_cache_buf), + 0); + } + printf("spiffs mount %s \n", res?"failed":"successful"); + return; + +} + +int format_fs(void) +{ + spiffs_config cfg; + cfg.phys_size = SPIFFS_CFG_PHYS_SZ(fs); // use all spi flash + cfg.phys_addr = SPIFFS_CFG_PHYS_ADDR(fs); // start spiffs at start of spi flash + cfg.phys_erase_block = SPIFFS_CFG_PHYS_ERASE_SZ(fs); // according to datasheet + cfg.log_block_size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); // let us not complicate things + cfg.log_page_size = SPIFFS_CFG_LOG_PAGE_SZ(fs); // as we said + + cfg.hal_read_f = my_spi_read; + cfg.hal_write_f = my_spi_write; + cfg.hal_erase_f = my_spi_erase; + + SPIFFS_unmount(&fs);printf("spiffs unmounted...\n"); + printf("spiffs formating...\n"); + s32_t format_res=SPIFFS_format(&fs); + printf("spiffs formated res %d\n",format_res); +// printf("spiffs formated end \n"); +// printf("w25qxx_page_program_fun addr %p\n",w25qxx_page_program_fun); +// printf("spiffs formated \n"); + int res = SPIFFS_mount( &fs, + &cfg, + spiffs_work_buf, + spiffs_fds, + sizeof(spiffs_fds), + spiffs_cache_buf, + sizeof(spiffs_cache_buf), + 0); + + return res; +} + + + + + + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/HEAD b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/HEAD new file mode 100755 index 0000000..cb089cd --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/config b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/config new file mode 100755 index 0000000..2a225f2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = https://github.com/pellepl/spiffs.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/description b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/description new file mode 100755 index 0000000..498b267 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/applypatch-msg.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/applypatch-msg.sample new file mode 100755 index 0000000..a5d7b84 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/commit-msg.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/commit-msg.sample new file mode 100755 index 0000000..b58d118 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/fsmonitor-watchman.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/fsmonitor-watchman.sample new file mode 100755 index 0000000..e673bb3 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/fsmonitor-watchman.sample @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 1) and a time in nanoseconds +# formatted as a string and outputs to stdout all files that have been +# modified since the given time. Paths must be relative to the root of +# the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $time) = @ARGV; + +# Check the hook interface version + +if ($version == 1) { + # convert nanoseconds to seconds + $time = int $time / 1000000000; +} else { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree; +if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $git_work_tree = Win32::GetCwd(); + $git_work_tree =~ tr/\\/\//; +} else { + require Cwd; + $git_work_tree = Cwd::cwd(); +} + +my $retry = 1; + +launch_watchman(); + +sub launch_watchman { + + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $time but were not transient (ie created after + # $time but no longer exist). + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + # + # The category of transient files that we want to ignore will have a + # creation clock (cclock) newer than $time_t value and will also not + # currently exist. + + my $query = <<" END"; + ["query", "$git_work_tree", { + "since": $time, + "fields": ["name"], + "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]] + }] + END + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + my $json_pkg; + eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; + } or do { + require JSON::PP; + $json_pkg = "JSON::PP"; + }; + + my $o = $json_pkg->new->utf8->decode($response); + + if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { + print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; + $retry--; + qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + print "/\0"; + eval { launch_watchman() }; + exit 0; + } + + die "Watchman: $o->{error}.\n" . + "Falling back to scanning...\n" if $o->{error}; + + binmode STDOUT, ":utf8"; + local $, = "\0"; + print @{$o->{files}}; +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/post-update.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/post-update.sample new file mode 100755 index 0000000..ec17ec1 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-applypatch.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-applypatch.sample new file mode 100755 index 0000000..4142082 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-commit.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-commit.sample new file mode 100755 index 0000000..68d62d5 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-push.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-push.sample new file mode 100755 index 0000000..6187dbf --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-rebase.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-rebase.sample new file mode 100755 index 0000000..6cbef5c --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-receive.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-receive.sample new file mode 100755 index 0000000..a1fd29e --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/prepare-commit-msg.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/prepare-commit-msg.sample new file mode 100755 index 0000000..10fa14c --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/update.sample b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/update.sample new file mode 100755 index 0000000..80ba941 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/index b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/index new file mode 100755 index 0000000..0543cfd Binary files /dev/null and b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/index differ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/info/exclude b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/info/exclude new file mode 100755 index 0000000..a5196d1 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/HEAD b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/HEAD new file mode 100755 index 0000000..fa9f2b2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 1350deb54c097fd06133f3c6d39dd3532a229829 xiahui <2535418266@qq.com> 1539275694 +0800 clone: from https://github.com/pellepl/spiffs.git diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/heads/master b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/heads/master new file mode 100755 index 0000000..fa9f2b2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 1350deb54c097fd06133f3c6d39dd3532a229829 xiahui <2535418266@qq.com> 1539275694 +0800 clone: from https://github.com/pellepl/spiffs.git diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/remotes/origin/HEAD b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/remotes/origin/HEAD new file mode 100755 index 0000000..fa9f2b2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 1350deb54c097fd06133f3c6d39dd3532a229829 xiahui <2535418266@qq.com> 1539275694 +0800 clone: from https://github.com/pellepl/spiffs.git diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.idx b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.idx new file mode 100755 index 0000000..0fdb1d2 Binary files /dev/null and b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.idx differ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.pack b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.pack new file mode 100755 index 0000000..f43549f Binary files /dev/null and b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/objects/pack/pack-ebcbfa4b0419424c9d48198a6baeaaae9b71f034.pack differ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/packed-refs b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/packed-refs new file mode 100755 index 0000000..349177d --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/packed-refs @@ -0,0 +1,14 @@ +# pack-refs with: peeled fully-peeled sorted +1350deb54c097fd06133f3c6d39dd3532a229829 refs/remotes/origin/master +3c7bab21c6548d81eb0024b9abe841bebaca229f refs/tags/0.2 +^c6214a14c4eedabf9da0251eeaf6741a571d074d +26e08c093902099e9198dbf4d1302bb567cf0ba8 refs/tags/0.2.1 +658cd679743e0a9d466a3082f972be2982bcae39 refs/tags/0.2.2 +617a1e68e13ebb6d14857641165e711d7014031b refs/tags/0.3.0 +5f57130f93e941781c08b3dc4f0668e8669ec61b refs/tags/0.3.1 +7236147f63134a8e727c6df373d9a1fc1317d23e refs/tags/0.3.2 +a7fa37d1eba13ec38175b71cd7b1caeb6b0536c0 refs/tags/0.3.3 +1d9f6707407ea2c9486d1cf12bbc2ba8a877839c refs/tags/0.3.4 +bdcf008e755ca70c15aa0b49821631aaea353565 refs/tags/0.3.5 +39937743fbbec4b82308ee08332bf9180408d23b refs/tags/0.3.6 +287148c46587089c4543a21eef2d6e9e14b88364 refs/tags/0.3.7 diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/heads/master b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/heads/master new file mode 100755 index 0000000..70ffff3 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/heads/master @@ -0,0 +1 @@ +1350deb54c097fd06133f3c6d39dd3532a229829 diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/remotes/origin/HEAD b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/remotes/origin/HEAD new file mode 100755 index 0000000..6efe28f --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.git.bak/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/.travis.yml b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.travis.yml new file mode 100755 index 0000000..8c36dc5 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/.travis.yml @@ -0,0 +1,8 @@ +language: c + +compiler: + - gcc + +before_script: + +script: make all && make clean && make test && make build-all && make clean test FLAGS=-DSPIFFS_OBJ_META_LEN=8 diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/FUZZING.md b/src/openmv/src/micropython/ports/k210-standalone/spiffs/FUZZING.md new file mode 100755 index 0000000..f517800 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/FUZZING.md @@ -0,0 +1,47 @@ +# Fuzzing SPIFFS + +The SPIFFS test suite includes a test program designed for fuzzing with +[AFL](http://lcamtuf.coredump.cx/afl/). This automatically exercises the +SPIFFS API and verifies that the file system does not crash or interact incorrectly +with the flash chip. + +There are two steps to fuzzing. The first is to build the test suite with +the AFL version of gcc. The CC variable should point to your copy of afl-gcc. + +``` +make clean test CC=/usr/local/bin/afl-gcc +``` + +There is a new test `afl_test` that reads from stdin a list of commands +and arguments. These are interpreted and executed on the API. The `afltests` +directory contains a number of test cases that can be fed to the `afl_test` test. + + +The second is to run this test suite under afl as follows (where findings is +the output directory): + +``` +afl-fuzz -i afltests -o findings ./build/linux_spiffs_test -f afl_test +``` + +This run will take hours (or days) and will (hopefully) not find any crashes. +If a crash (or hang) is found, then the input file that caused the crash is +saved. This allows the specific test case to be debugged. + +## Reducing the size of the file + +AFL comes with `afl-tmin` which can reduce the size of the test input file to +make it easier to debug. + +``` +afl-tmin -i findings/crashes/ -o smalltest -- build/linux_spiffs_test -f afl_test +``` + +This will write a short version of the testcase file to `smalltest`. This can then be +fed into the test program for debugging: + +``` +build/linux_spiffs_test -f afl_test < smalltest +``` + +This should still crash, but allows it to be run under a debugger. diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/LICENSE b/src/openmv/src/micropython/ports/k210-standalone/spiffs/LICENSE new file mode 100755 index 0000000..5fb2427 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/README.md b/src/openmv/src/micropython/ports/k210-standalone/spiffs/README.md new file mode 100755 index 0000000..64ffcc3 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/README.md @@ -0,0 +1,212 @@ +# SPIFFS (SPI Flash File System) +**V0.3.7** + +[![Build Status](https://travis-ci.org/pellepl/spiffs.svg?branch=master)](https://travis-ci.org/pellepl/spiffs) + +Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976 at gmail.com) + +For legal stuff, see [LICENSE](https://github.com/pellepl/spiffs/blob/master/LICENSE). Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won't be held responsible. + +Love to hear feedback though! + + +## INTRODUCTION + +Spiffs is a file system intended for SPI NOR flash devices on embedded targets. + +Spiffs is designed with following characteristics in mind: + - Small (embedded) targets, sparse RAM without heap + - Only big areas of data (blocks) can be erased + - An erase will reset all bits in block to ones + - Writing pulls one to zeroes + - Zeroes can only be pulled to ones by erase + - Wear leveling + + +## BUILDING + +`mkdir build; make` + +Otherwise, configure the `builddir` variable towards the top of `makefile` as something opposed to the default `build`. Sanity check on the host via `make test` and refer to `.travis.yml` for the official in-depth testing procedure. See the wiki for [integrating](https://github.com/pellepl/spiffs/wiki/Integrate-spiffs) spiffs into projects and [spiffsimg](https://github.com/nodemcu/nodemcu-firmware/tree/master/tools/spiffsimg) from [nodemcu](https://github.com/nodemcu) is a good example on the subject. + + +## FEATURES + +What spiffs does: + - Specifically designed for low ram usage + - Uses statically sized ram buffers, independent of number of files + - Posix-like api: open, close, read, write, seek, stat, etc + - It can run on any NOR flash, not only SPI flash - theoretically also on embedded flash of a microprocessor + - Multiple spiffs configurations can run on same target - and even on same SPI flash device + - Implements static wear leveling + - Built in file system consistency checks + - Highly configurable + +What spiffs does not: + - Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path *tmp/myfile.txt* will create a file called *tmp/myfile.txt* instead of a *myfile.txt* under directory *tmp*. + - It is not a realtime stack. One write operation might last much longer than another. + - Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128Mbyte is probably a bad idea. This is a side effect of the design goal to use as little ram as possible. + - Presently, it does not detect or handle bad blocks. + - One configuration, one binary. There's no generic spiffs binary that handles all types of configurations. + + +## MORE INFO + +See the [wiki](https://github.com/pellepl/spiffs/wiki) for [configuring](https://github.com/pellepl/spiffs/wiki/Configure-spiffs), [integrating](https://github.com/pellepl/spiffs/wiki/Integrate-spiffs), [using](https://github.com/pellepl/spiffs/wiki/Using-spiffs), and [optimizing](https://github.com/pellepl/spiffs/wiki/Performance-and-Optimizing) spiffs. + +For design, see [docs/TECH_SPEC](https://github.com/pellepl/spiffs/blob/master/docs/TECH_SPEC). + +For a generic spi flash driver, see [this](https://github.com/pellepl/spiflash_driver). + +## HISTORY + +### 0.3.7 +- fixed prevent seeking to negative offsets #158 +- fixed file descriptor offsets not updated for multiple fds on same file #157 +- fixed cache page not closed for removed files #156 +- fixed a lseek bug when seeking exactly to end of a fully indexed first level LUT #148 +- fixed wear leveling issue #145 +- fixed attempt to write out of bounds in flash #130, +- set file offset when seeking over end #121 (thanks @sensslen) +- fixed seeking in virgin files #120 (thanks @sensslen) +- Optional file metadata #128 (thanks @cesanta) +- AFL testing framework #100 #143 (thanks @pjsg) +- Testframe updates + +New API functions: +- `SPIFFS_update_meta, SPIFFS_fupdate_meta` - updates metadata for a file + +New config defines: +- `SPIFFS_OBJ_META_LEN` - enable possibility to add extra metadata to files + +### 0.3.6 +- Fix range bug in index memory mapping #98 +- Add index memory mapping #97 +- Optimize SPIFFS_read for large files #96 +- Add temporal cache for opening files #95 +- More robust gc #93 (thanks @dismirlian) +- Fixed a double write of same data in certain cache situations +- Fixed an open bug in READ_ONLY builds +- File not visible in SPIFFS_readdir #90 (thanks @benpicco-tmp) +- Cache load code cleanup #92 (thanks @niclash) +- Fixed lock/unlock asymmetry #88 #87 (thanks @JackJefferson, @dpruessner) +- Testframe updates + +New API functions: +- `SPIFFS_ix_map` - map index meta data to memory for a file +- `SPIFFS_ix_unmap` - unmaps index meta data for a file +- `SPIFFS_ix_remap` - changes file offset for index metadata map +- `SPIFFS_bytes_to_ix_map_entries` - utility, get length of needed vector for given amount of bytes +- `SPIFFS_ix_map_entries_to_bytes` - utility, get number of bytes a vector can represent given length + +New config defines: +- `SPIFFS_IX_MAP` - enable possibility to map index meta data to memory for reading faster +- `SPIFFS_TEMPORAL_FD_CACHE` - enable temporal cache for opening files faster +- `SPIFFS_TEMPORAL_CACHE_HIT_SCORE` - for tuning the temporal cache + +### 0.3.5 +- Fixed a bug in fs check +- API returns actual error codes #84) (thanks @Nails) +- Fix compiler warnings for non-gcc #83 #81 (thanks @Nails) +- Unable to recover from full fs #82 (thanks @rojer) +- Define SPIFFS_O_* flags #80 +- Problem with long filenames #79 (thanks @psjg) +- Duplicate file name bug fix #74 (thanks @igrr) +- SPIFFS_eof and SPIFFS_tell return wrong value #72 (thanks @ArtemPisarenko) +- Bunch of testframe updates #77 #78 #86 (thanks @dpreussner, @psjg a.o) + +### 0.3.4 +- Added user callback file func. +- Fixed a stat bug with obj id. +- SPIFFS_probe_fs added +- Add possibility to compile a read-only version of spiffs +- Make magic dependent on fs length, if needed (see #59 & #66) (thanks @hreintke) +- Exposed SPIFFS_open_by_page_function +- Zero-size file cannot be seek #57 (thanks @lishen2) +- Add tell and eof functions #54 (thanks @raburton) +- Make api string params const #53 (thanks @raburton) +- Preserve user_data during mount() #51 (thanks @rojer) + +New API functions: +- `SPIFFS_set_file_callback_func` - register a callback informing about file events +- `SPIFFS_probe_fs` - probe a spi flash trying to figure out size of fs +- `SPIFFS_open_by_page` - open a file by page index +- `SPIFFS_eof` - checks if end of file is reached +- `SPIFFS_tell` - returns current file offset + +New config defines: +- `SPIFFS_READ_ONLY` +- `SPIFFS_USE_MAGIC_LENGTH` + +### 0.3.3 +**Might not be compatible with 0.3.2 structures. See issue #40** +- Possibility to add integer offset to file handles +- Truncate function presumes too few free pages #49 +- Bug in truncate function #48 (thanks @PawelDefee) +- Update spiffs_gc.c - remove unnecessary parameter (thanks @PawelDefee) +- Update INTEGRATION docs (thanks @PawelDefee) +- Fix pointer truncation in 64-bit platforms (thanks @igrr) +- Zero-sized files cannot be read #44 (thanks @rojer) +- (More) correct calculation of max_id in obj_lu_find #42 #41 (thanks @lishen2) +- Check correct error code in obj_lu_find_free #41 (thanks @lishen2) +- Moar comments for SPIFFS_lseek (thanks @igrr) +- Fixed padding in spiffs_page_object_ix #40 (thanks @jmattsson @lishen2) +- Fixed gc_quick test (thanks @jmattsson) +- Add SPIFFS_EXCL flag #36 +- SPIFFS_close may fail silently if cache is enabled #37 +- User data in callbacks #34 +- Ignoring SINGLETON build in cache setup (thanks Luca) +- Compilation error fixed #32 (thanks @chotasanjiv) +- Align cand_scores (thanks @hefloryd) +- Fix build warnings when SPIFFS_CACHE is 0 (thanks @ajaybhargav) + +New config defines: +- `SPIFFS_FILEHDL_OFFSET` + +### 0.3.2 +- Limit cache size if too much cache is given (thanks pgeiem) +- New feature - Controlled erase. #23 +- SPIFFS_rename leaks file descriptors #28 (thanks benpicco) +- moved dbg print defines in test framework to params_test.h +- lseek should return the resulting offset (thanks hefloryd) +- fixed type on dbg ifdefs +- silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco) +- Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela) +- Cache might writethrough too often #16 +- even moar testrunner updates +- Test framework update and some added tests +- Some thoughts for next gen +- Test sigsevs when having too many sectors #13 (thanks alonewolfx2) +- GC might be suboptimal #11 +- Fix eternal readdir when objheader at last block, last entry + +New API functions: +- `SPIFFS_gc_quick` - call a nonintrusive gc +- `SPIFFS_gc` - call a full-scale intrusive gc + +### 0.3.1 +- Removed two return warnings, was too triggerhappy on release + +### 0.3.0 +- Added existing namecheck when creating files +- Lots of static analysis bugs #6 +- Added rename func +- Fix SPIFFS_read length when reading beyond file size +- Added reading beyond file length testcase +- Made build a bit more configurable +- Changed name in spiffs from "errno" to "err_code" due to conflicts compiling in mingw +- Improved GC checks, fixed an append bug, more robust truncate for very special case +- GC checks preempts GC, truncate even less picky +- Struct alignment needed for some targets, define in spiffs config #10 +- Spiffs filesystem magic, definable in config + +New config defines: +- `SPIFFS_USE_MAGIC` - enable or disable magic check upon mount +- `SPIFFS_ALIGNED_OBJECT_INDEX_TABLES` - alignment for certain targets + +New API functions: +- `SPIFFS_rename` - rename files +- `SPIFFS_clearerr` - clears last errno +- `SPIFFS_info` - returns info on used and total bytes in fs +- `SPIFFS_format` - formats the filesystem +- `SPIFFS_mounted` - checks if filesystem is mounted diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/100 b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/100 new file mode 100755 index 0000000..6bb2239 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/100 @@ -0,0 +1,15 @@ +‰5S-C4 +d5rh +OlWkR#C4 +d5rh +O4W4R4O4W4êC4#d5rh +O4d5rh +OlWkRh +O4Y5rh +OlWkR4C44R45ŠË +O4W4ê4C4C4 +O4O4W4R4O4W4êC4#d5rh +O4d5rh +W4R45rË +O4W4ê4#d5rh +rz diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/200 b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/200 new file mode 100755 index 0000000..9014312 Binary files /dev/null and b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/200 differ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/a b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/a new file mode 100755 index 0000000..24e3a21 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/a @@ -0,0 +1,18 @@ + b55 +O4W4R4C4D4 +b45 +d5rh +O4W4R4f4C4 +baaU +d5rh +OaWaRafaCa +cd5rh +OaWaRafaCa +O4S4W4R4C4 +d5rh +O4W4S4R4C4 +d5rh +O4W4R4S4C4 +d5rh +O4W4R4C4 +d5rh diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/b b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/b new file mode 100755 index 0000000..1f95774 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/afltests/b @@ -0,0 +1,15 @@ +b55 +O4 +W?W?W?W?W?f4 +WW:W;f4 +C4 +b45 +d5rh +O4W?R4f4C4 +baa +d5rh +OaWaRafaCa +d5rh +OaWaRafaCa +O4W?R4C4 +d5rh diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TECH_SPEC b/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TECH_SPEC new file mode 100755 index 0000000..b4755a6 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TECH_SPEC @@ -0,0 +1,239 @@ +* USING SPIFFS + +TODO + + +* SPIFFS DESIGN + +Spiffs is inspired by YAFFS. However, YAFFS is designed for NAND flashes, and +for bigger targets with much more ram. Nevertheless, many wise thoughts have +been borrowed from YAFFS when writing spiffs. Kudos! + +The main complication writing spiffs was that it cannot be assumed the target +has a heap. Spiffs must go along only with the work ram buffer given to it. +This forces extra implementation on many areas of spiffs. + + +** SPI flash devices using NOR technology + +Below is a small description of how SPI flashes work internally. This is to +give an understanding of the design choices made in spiffs. + +SPI flash devices are physically divided in blocks. On some SPI flash devices, +blocks are further divided into sectors. Datasheets sometimes name blocks as +sectors and vice versa. + +Common memory capacaties for SPI flashes are 512kB up to 8MB of data, where +blocks may be 64kB. Sectors can be e.g. 4kB, if supported. Many SPI flashes +have uniform block sizes, whereas others have non-uniform - the latter meaning +that e.g. the first 16 blocks are 4kB big, and the rest are 64kB. + +The entire memory is linear and can be read and written in random access. +Erasing can only be done block- or sectorwise; or by mass erase. + +SPI flashes can normally be erased from 100.000 up to 1.000.000 cycles before +they fail. + +A clean SPI flash from factory have all bits in entire memory set to one. A +mass erase will reset the device to this state. Block or sector erasing will +put the all bits in the area given by the sector or block to ones. Writing to a +NOR flash pulls ones to zeroes. Writing 0xFF to an address is simply a no-op. + +Writing 0b10101010 to a flash address holding 0b00001111 will yield 0b00001010. + +This way of "write by nand" is used considerably in spiffs. + +Common characteristics of NOR flashes are quick reads, but slow writes. + +And finally, unlike NAND flashes, NOR flashes seem to not need any error +correction. They always write correctly I gather. + + +** Spiffs logical structure + +Some terminology before proceeding. Physical blocks/sectors means sizes stated +in the datasheet. Logical blocks and pages is something the integrator choose. + + +** Blocks and pages + +Spiffs is allocated to a part or all of the memory of the SPI flash device. +This area is divided into logical blocks, which in turn are divided into +logical pages. The boundary of a logical block must coincide with one or more +physical blocks. The sizes for logical blocks and logical pages always remain +the same, they are uniform. + +Example: non-uniform flash mapped to spiffs with 128kB logical blocks + +PHYSICAL FLASH BLOCKS SPIFFS LOGICAL BLOCKS: 128kB + ++-----------------------+ - - - +-----------------------+ +| Block 1 : 16kB | | Block 1 : 128kB | ++-----------------------+ | | +| Block 2 : 16kB | | | ++-----------------------+ | | +| Block 3 : 16kB | | | ++-----------------------+ | | +| Block 4 : 16kB | | | ++-----------------------+ | | +| Block 5 : 64kB | | | ++-----------------------+ - - - +-----------------------+ +| Block 6 : 64kB | | Block 2 : 128kB | ++-----------------------+ | | +| Block 7 : 64kB | | | ++-----------------------+ - - - +-----------------------+ +| Block 8 : 64kB | | Block 3 : 128kB | ++-----------------------+ | | +| Block 9 : 64kB | | | ++-----------------------+ - - - +-----------------------+ +| ... | | ... | + +A logical block is divided further into a number of logical pages. A page +defines the smallest data holding element known to spiffs. Hence, if a file +is created being one byte big, it will occupy one page for index and one page +for data - it will occupy 2 x size of a logical page on flash. +So it seems it is good to select a small page size. + +Each page has a metadata header being normally 5 to 9 bytes. This said, a very +small page size will make metadata occupy a lot of the memory on the flash. A +page size of 64 bytes will waste 8-14% on metadata, while 256 bytes 2-4%. +So it seems it is good to select a big page size. + +Also, spiffs uses a ram buffer being two times the page size. This ram buffer +is used for loading and manipulating pages, but it is also used for algorithms +to find free file ids, scanning the file system, etc. Having too small a page +size means less work buffer for spiffs, ending up in more reads operations and +eventually gives a slower file system. + +Choosing the page size for the system involves many factors: + - How big is the logical block size + - What is the normal size of most files + - How much ram can be spent + - How much data (vs metadata) must be crammed into the file system + - How fast must spiffs be + - Other things impossible to find out + +So, chosing the Optimal Page Size (tm) seems tricky, to say the least. Don't +fret - there is no optimal page size. This varies from how the target will use +spiffs. Use the golden rule: + + ~~~ Logical Page Size = Logical Block Size / 256 ~~~ + +This is a good starting point. The final page size can then be derived through +heuristical experimenting for us non-analytical minds. + + +** Objects, indices and look-ups + +A file, or an object as called in spiffs, is identified by an object id. +Another YAFFS rip-off. This object id is a part of the page header. So, all +pages know to which object/file they belong - not counting the free pages. + +An object is made up of two types of pages: object index pages and data pages. +Data pages contain the data written by user. Index pages contain metadata about +the object, more specifically what data pages are part of the object. + +The page header also includes something called a span index. Let's say a file +is written covering three data pages. The first data page will then have span +index 0, the second span index 1, and the last data page will have span index +2. Simple as that. + +Finally, each page header contain flags, telling if the page is used, +deleted, finalized, holds index or data, and more. + +Object indices also have span indices, where an object index with span index 0 +is referred to as the object index header. This page does not only contain +references to data pages, but also extra info such as object name, object size +in bytes, flags for file or directory, etc. + +If one were to create a file covering three data pages, named e.g. +"spandex-joke.txt", given object id 12, it could look like this: + +PAGE 0 + +PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA] + + +PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA] + + +PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA] + + +PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA] + + +PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX] + obj ix header: [name:spandex-joke.txt size:600 bytes flags:FILE] + obj ix: [1 2 4] + +Looking in detail at page 5, the object index header page, the object index +array refers to each data page in order, as mentioned before. The index of the +object index array correlates with the data page span index. + + entry ix: 0 1 2 + obj ix: [1 2 4] + | | | + PAGE 1, DATA, SPAN_IX 0 --------/ | | + PAGE 2, DATA, SPAN_IX 1 --------/ | + PAGE 4, DATA, SPAN_IX 2 --------/ + +Things to be unveiled in page 0 - well.. Spiffs is designed for systems low on +ram. We cannot keep a dynamic list on the whereabouts of each object index +header so we can find a file fast. There might not even be a heap! But, we do +not want to scan all page headers on the flash to find the object index header. + +The first page(s) of each block contains the so called object look-up. These +are not normal pages, they do not have a header. Instead, they are arrays +pointing out what object-id the rest of all pages in the block belongs to. + +By this look-up, only the first page(s) in each block must to scanned to find +the actual page which contains the object index header of the desired object. + +The object lookup is redundant metadata. The assumption is that it presents +less overhead reading a full page of data to memory from each block and search +that, instead of reading a small amount of data from each page (i.e. the page +header) in all blocks. Each read operation from SPI flash normally contains +extra data as the read command itself and the flash address. Also, depending on +the underlying implementation, other criterions may need to be passed for each +read transaction, like mutexes and such. + +The veiled example unveiled would look like this, with some extra pages: + +PAGE 0 [ 12 12 545 12 12 34 34 4 0 0 0 0 ...] +PAGE 1 page header: [obj_id:12 span_ix:0 flags:USED|DATA] ... +PAGE 2 page header: [obj_id:12 span_ix:1 flags:USED|DATA] ... +PAGE 3 page header: [obj_id:545 span_ix:13 flags:USED|DATA] ... +PAGE 4 page header: [obj_id:12 span_ix:2 flags:USED|DATA] ... +PAGE 5 page header: [obj_id:12 span_ix:0 flags:USED|INDEX] ... +PAGE 6 page header: [obj_id:34 span_ix:0 flags:USED|DATA] ... +PAGE 7 page header: [obj_id:34 span_ix:1 flags:USED|DATA] ... +PAGE 8 page header: [obj_id:4 span_ix:1 flags:USED|INDEX] ... +PAGE 9 page header: [obj_id:23 span_ix:0 flags:DELETED|INDEX] ... +PAGE 10 page header: [obj_id:23 span_ix:0 flags:DELETED|DATA] ... +PAGE 11 page header: [obj_id:23 span_ix:1 flags:DELETED|DATA] ... +PAGE 12 page header: [obj_id:23 span_ix:2 flags:DELETED|DATA] ... +... + +Ok, so why are page 9 to 12 marked as 0 when they belong to object id 23? These +pages are deleted, so this is marked both in page header flags and in the look +up. This is an example where spiffs uses NOR flashes "nand-way" of writing. + +As a matter of fact, there are two object id's which are special: + +obj id 0 (all bits zeroes) - indicates a deleted page in object look up +obj id 0xff.. (all bits ones) - indicates a free page in object look up + +Actually, the object id's have another quirk: if the most significant bit is +set, this indicates an object index page. If the most significant bit is zero, +this indicates a data page. So to be fully correct, page 0 in above example +would look like this: + +PAGE 0 [ 12 12 545 12 *12 34 34 *4 0 0 0 0 ...] + +where the asterisk means the msb of the object id is set. + +This is another way to speed up the searches when looking for object indices. +By looking on the object id's msb in the object lookup, it is also possible +to find out whether the page is an object index page or a data page. + diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TODO b/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TODO new file mode 100755 index 0000000..c947316 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/docs/TODO @@ -0,0 +1,15 @@ +* When mending lost pages, also see if they fit into length specified in object index header + +SPIFFS2 thoughts + +* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id. + Eg. object id xor:ed with bit-reversed span index. + This should decrease number of actual pages that needs to be visited when looking thru the obj lut. + +* Logical number of each block. When moving stuff in a garbage collected page, the free + page is assigned the same number as the garbage collected. Thus, object index pages do not have to + be rewritten. + +* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit + as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a + check is automatically run. \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/files.mk b/src/openmv/src/micropython/ports/k210-standalone/spiffs/files.mk new file mode 100755 index 0000000..631ec7e --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/files.mk @@ -0,0 +1,12 @@ +ifndef spiffs +$(warn defaulting path to generic spiffs module, spiffs variable not set) +spiffs = ../generic/spiffs +endif +FLAGS += -DCONFIG_BUILD_SPIFFS +INC += -I${spiffs}/src +CPATH += ${spiffs}/src +CFILES += spiffs_nucleus.c +CFILES += spiffs_gc.c +CFILES += spiffs_hydrogen.c +CFILES += spiffs_cache.c +CFILES += spiffs_check.c diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/makefile b/src/openmv/src/micropython/ports/k210-standalone/spiffs/makefile new file mode 100755 index 0000000..355b467 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/makefile @@ -0,0 +1,163 @@ +BINARY = linux_spiffs_test + +############ +# +# Paths +# +############ + +sourcedir = src +builddir = build + + +############# +# +# Build tools +# +############# + +CC ?= gcc +LD ?= ld +GDB ?= gdb +OBJCOPY ?= objcopy +OBJDUMP ?= objdump +MKDIR ?= mkdir -p + +############### +# +# Files and libs +# +############### + +NO_TEST ?= 0 +CFLAGS = $(FLAGS) +ifeq (1, $(strip $(NO_TEST))) +CFILES_TEST = main.c +CFLAGS += -DNO_TEST -Werror +else +CFILES_TEST = main.c \ + test_spiffs.c \ + test_dev.c \ + test_check.c \ + test_hydrogen.c \ + test_bugreports.c \ + testsuites.c \ + testrunner.c +CFLAGS += -D_SPIFFS_TEST +endif +include files.mk +INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default -I./${sourcedir}/test +COMPILEROPTIONS = $(INCLUDE_DIRECTIVES) + +COMPILEROPTIONS_APP = $(INCLUDE_DIRECTIVES) \ +-Wall -Wno-format-y2k -W -Wstrict-prototypes -Wmissing-prototypes \ +-Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch \ +-Wshadow -Wcast-align -Wchar-subscripts -Winline -Wnested-externs\ +-Wredundant-decls + +############ +# +# Tasks +# +############ + +vpath %.c ${sourcedir} ${sourcedir}/default ${sourcedir}/test + +OBJFILES = $(CFILES:%.c=${builddir}/%.o) +OBJFILES_TEST = $(CFILES_TEST:%.c=${builddir}/%.o) + +DEPFILES = $(CFILES:%.c=${builddir}/%.d) $(CFILES_TEST:%.c=${builddir}/%.d) + +ALLOBJFILES += $(OBJFILES) $(OBJFILES_TEST) + +DEPENDENCIES = $(DEPFILES) + +# link object files, create binary +$(BINARY): $(ALLOBJFILES) + @echo "... linking" + @${CC} $(LINKEROPTIONS) -o ${builddir}/$(BINARY) $(ALLOBJFILES) $(LIBS) +ifeq (1, $(strip $(NO_TEST))) + @echo "size: `du -b ${builddir}/${BINARY} | sed 's/\([0-9]*\).*/\1/g '` bytes" +endif + + +-include $(DEPENDENCIES) + +# compile c files +$(OBJFILES) : ${builddir}/%.o:%.c + @echo "... compile $@" + @${CC} $(COMPILEROPTIONS_APP) $(CFLAGS) -g -c -o $@ $< + +$(OBJFILES_TEST) : ${builddir}/%.o:%.c + @echo "... compile $@" + @${CC} ${COMPILEROPTIONS} $(CFLAGS) -g -c -o $@ $< + +# make dependencies +# @echo "... depend $@"; +$(DEPFILES) : ${builddir}/%.d:%.c + @rm -f $@; \ + ${CC} $(COMPILEROPTIONS) -M $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*, ${builddir}/\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +all: mkdirs $(BINARY) + +mkdirs: + -@${MKDIR} ${builddir} + -@${MKDIR} test_data + +FILTER ?= + +test: $(BINARY) +ifdef $(FILTER) + ./build/$(BINARY) +else + ./build/$(BINARY) -f $(FILTER) +endif + +test_failed: $(BINARY) + ./build/$(BINARY) _tests_fail + +clean: + @echo ... removing build files in ${builddir} + @rm -f ${builddir}/*.o + @rm -f ${builddir}/*.d + @rm -f ${builddir}/*.elf + +ONOFF = 1 0 +OFFON = 0 1 +build-all: + @for rdonly in $(ONOFF); do \ + for singleton in $(ONOFF); do \ + for hal_cb_xtra in $(OFFON); do \ + for cache in $(OFFON); do \ + for magic in $(OFFON); do \ + for temporal_cache in $(OFFON); do \ + for ix_map in $(OFFON); do \ + echo; \ + echo ============================================================; \ + echo SPIFFS_READ_ONLY=$$rdonly; \ + echo SPIFFS_SINGLETON=$$singleton; \ + echo SPIFFS_HAL_CALLBACK_EXTRA=$$hal_cb_xtra; \ + echo SPIFFS_CACHE, SPIFFS_CACHE_WR=$$cache; \ + echo SPIFFS_USE_MAGIC, SPIFFS_USE_MAGIC_LENGTH=$$magic; \ + echo SPIFFS_TEMPORAL_FD_CACHE=$$temporal_cache; \ + echo SPIFFS_IX_MAP=$$ix_map; \ + $(MAKE) clean && $(MAKE) FLAGS="\ + -DSPIFFS_HAL_CALLBACK_EXTRA=$$hal_cb_xtra \ + -DSPIFFS_SINGLETON=$$singleton \ + -DSPIFFS_CACHE=$$cache \ + -DSPIFFS_CACHE_WR=$$cache \ + -DSPIFFS_READ_ONLY=$$rdonly \ + -DSPIFFS_USE_MAGIC=$$magic \ + -DSPIFFS_USE_MAGIC_LENGTH=$$magic \ + -DSPIFFS_TEMPORAL_FD_CACHE=$$temporal_cache \ + -DSPIFFS_IX_MAP=$$ix_map \ + " NO_TEST=1; \ + done || exit 1; \ + done \ + done \ + done \ + done \ + done \ + done diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/Makefile b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/Makefile new file mode 100755 index 0000000..9b3f92f --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/Makefile @@ -0,0 +1,18 @@ +SRC = ../src + +SOURCE_FILES = $(SRC)/spiffs_cache.c \ + $(SRC)/spiffs_check.c \ + $(SRC)/spiffs_gc.c \ + $(SRC)/spiffs_hydrogen.c \ + $(SRC)/spiffs_nucleus.c \ + python_ops.c + +INCLUDES = -I . \ + -I $(SRC)/ \ + -I $(SRC)/default + +spiffs_.so: $(SOURCE_FILES) + $(CC) -g3 -fPIC -shared $(INCLUDES) -o $@ $(SOURCE_FILES) -lm + +clean: + rm -rf spiffs_.so *~ *.pyc diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/params_test.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/params_test.h new file mode 100755 index 0000000..e81ff38 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/params_test.h @@ -0,0 +1,8 @@ +#include + +typedef int32_t s32_t; +typedef uint32_t u32_t; +typedef int16_t s16_t; +typedef uint16_t u16_t; +typedef int8_t s8_t; +typedef uint8_t u8_t; diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/python_ops.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/python_ops.c new file mode 100755 index 0000000..8cfab5d --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/python_ops.c @@ -0,0 +1,88 @@ +#include +#include + +#include "spiffs.h" + +void *my_spiffs_mount(int phys_size, + int phys_addr, + int phys_erase_block, + int log_page_size, + int log_block_size, + s32_t (read_cb)(u32_t addr, u32_t size, u8_t *dst), + s32_t (write_cb)(u32_t addr, u32_t size, u8_t *src), + s32_t (erase_cb)(u32_t addr, u32_t size) + ) +{ + +#define WORK_BUF_SIZE (log_page_size*2) +#define SPIFFS_FDS_SIZE (32*4) +#define SPIFFS_CACHE_BUF_SIZE (phys_size) //(log_page_size+32)*128) + + struct alloced { + spiffs fs; + uint8_t spiffs_work_buf[WORK_BUF_SIZE]; + uint8_t spiffs_fds[SPIFFS_FDS_SIZE]; + uint8_t spiffs_cache_buf[SPIFFS_CACHE_BUF_SIZE]; + }; + + struct alloced *d = malloc(sizeof(struct alloced)); + spiffs *pfs = &d->fs; + + spiffs_config cfg; + cfg.phys_size = phys_size; // use all spi flash + cfg.phys_addr = phys_addr; // start spiffs at start of spi flash + cfg.phys_erase_block = phys_erase_block; // according to datasheet + cfg.log_block_size = log_block_size; // let us not complicate things + cfg.log_page_size = log_page_size; // as we said + + cfg.hal_read_f = read_cb; + cfg.hal_write_f = write_cb; + cfg.hal_erase_f = erase_cb; + + int res = SPIFFS_mount(pfs, + &cfg, + d->spiffs_work_buf, + d->spiffs_fds, + SPIFFS_FDS_SIZE, + d->spiffs_cache_buf, + SPIFFS_CACHE_BUF_SIZE, + 0); + + return res?NULL:(void *)pfs; +} + +int my_spiffs_umount(spiffs *fs) +{ + SPIFFS_clearerr(fs); + SPIFFS_unmount(fs); + + int ret = SPIFFS_errno(fs); + free(fs); + + return ret; +} + +int my_dir(spiffs *fs, + void (entry_cb)(char *name, int size, int id)) +{ + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + int ret; + + SPIFFS_clearerr(fs); + + if (NULL==SPIFFS_opendir(fs, "/", &d)) goto done; + + while ((pe = SPIFFS_readdir(&d, pe))) { + entry_cb(pe->name, pe->size, pe->obj_id); + } + + if (SPIFFS_closedir(&d)) goto done; + SPIFFS_clearerr(fs); + + done: + return SPIFFS_errno(fs); +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/sp_test.py b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/sp_test.py new file mode 100755 index 0000000..685c31b --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/py/sp_test.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +"Test spiffs filesystem with a range of parameters" + +import spiffs + +class SpiffsInstr(spiffs.SpiffsCharsBack): + "Keeps count of issued reads / writes / erases" + def __init__(self, *args, **kwargs): + self.reset_counters() + supe = super(SpiffsInstr, self) + + self.super_read = supe.on_read + self.super_write = supe.on_write + self.super_erase = supe.on_erase + + supe.__init__(*args, **kwargs) + + def reset_counters(self): + self.read_requests = [] + self.write_requests = [] + self.erase_requests = [] + + def on_read(self, addr, size): + self.read_requests.append([addr, size]) + return self.super_read(addr, size) + def on_write(self, addr, data): + self.write_requests.append([addr, len(data)]) + return self.super_write(addr, data) + def on_erase(self, addr, size): + self.erase_requests.append([addr, size]) + return self.super_erase(addr, size) + +# Physical parameters +flash_size = 8*1024*1024 +erase_size = 256 + +print "filesystem size =",flash_size + +header = "log_block_size","log_page_size","reads","read_bytes","writes","written_bytes" +print '| %s |'%(' | '.join(header)) +header2 = ['-'*len(x) for x in header] +print '| %s |'%(' | '.join(header2)) + +for log2_log_block_size in range(14,19): + log_block_size = 1<> tf, "Test message",x, + + print s.dir() + print s.open("Testfile").read() + + print s.dir() + s.remove("Testfile") + + print s.dir() + +if __name__=="__main__": + + file('/tmp/back.bin','w').write('\xff'*8*1024*1024) + + with file('/tmp/back.bin','r+wb') as bf: + s = SpiffsFileBack(bf) + _tests(s) + _destructive_tests(s) + + loc=['\xff']*4*1024*1024 + s = SpiffsCharsBack(loc) + _tests(s) + _destructive_tests(s) diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/default/spiffs_config.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/default/spiffs_config.h new file mode 100755 index 0000000..ce562bf --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/default/spiffs_config.h @@ -0,0 +1,362 @@ +/* + * spiffs_config.h + * + * Created on: Jul 3, 2013 + * Author: petera + */ + +#ifndef SPIFFS_CONFIG_H_ +#define SPIFFS_CONFIG_H_ + +// ----------- 8< ------------ +// Following includes are for the linux test build of spiffs +// These may/should/must be removed/altered/replaced in your target +#include "params_test.h" +#include +#include +#include +#include +#include +#ifdef _SPIFFS_TEST +#include "testrunner.h" +#endif +// ----------- >8 ------------ + +// compile time switches + +// Set generic spiffs debug output call. +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for garbage collecting. +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for caching. +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for system consistency checks. +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif +// Set spiffs debug output call for all api invocations. +#ifndef SPIFFS_API_DBG +#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif + + + +// Defines spiffs debug print formatters +// some general signed number +#ifndef _SPIPRIi +#define _SPIPRIi "%d" +#endif +// address +#ifndef _SPIPRIad +#define _SPIPRIad "%08x" +#endif +// block +#ifndef _SPIPRIbl +#define _SPIPRIbl "%04x" +#endif +// page +#ifndef _SPIPRIpg +#define _SPIPRIpg "%04x" +#endif +// span index +#ifndef _SPIPRIsp +#define _SPIPRIsp "%04x" +#endif +// file descriptor +#ifndef _SPIPRIfd +#define _SPIPRIfd "%d" +#endif +// file object id +#ifndef _SPIPRIid +#define _SPIPRIid "%04x" +#endif +// file flags +#ifndef _SPIPRIfl +#define _SPIPRIfl "%02x" +#endif + + +// Enable/disable API functions to determine exact number of bytes +// for filedescriptor and cache buffers. Once decided for a configuration, +// this can be disabled to reduce flash. +#ifndef SPIFFS_BUFFER_HELP +#define SPIFFS_BUFFER_HELP 0 +#endif + +// Enables/disable memory read caching of nucleus file system operations. +// If enabled, memory area must be provided for cache in SPIFFS_mount. +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 +#endif +#if SPIFFS_CACHE +// Enables memory write caching for file descriptors in hydrogen +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 +#endif + +// Enable/disable statistics on caching. Debug/test purpose only. +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 1 +#endif +#endif + +// Always check header of each accessed page to ensure consistent state. +// If enabled it will increase number of reads, will increase flash. +#ifndef SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK 1 +#endif + +// Define maximum number of gc runs to perform to reach desired free pages. +#ifndef SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS 5 +#endif + +// Enable/disable statistics on gc. Debug/test purpose only. +#ifndef SPIFFS_GC_STATS +#define SPIFFS_GC_STATS 1 +#endif + +// Garbage collecting examines all pages in a block which and sums up +// to a block score. Deleted pages normally gives positive score and +// used pages normally gives a negative score (as these must be moved). +// To have a fair wear-leveling, the erase age is also included in score, +// whose factor normally is the most positive. +// The larger the score, the more likely it is that the block will +// picked for garbage collection. + +// Garbage collecting heuristics - weight used for deleted pages. +#ifndef SPIFFS_GC_HEUR_W_DELET +#define SPIFFS_GC_HEUR_W_DELET (5) +#endif +// Garbage collecting heuristics - weight used for used pages. +#ifndef SPIFFS_GC_HEUR_W_USED +#define SPIFFS_GC_HEUR_W_USED (-1) +#endif +// Garbage collecting heuristics - weight used for time between +// last erased and erase of this block. +#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#endif + +// Object name maximum length. Note that this length include the +// zero-termination character, meaning maximum string of characters +// can at most be SPIFFS_OBJ_NAME_LEN - 1. +#ifndef SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (32) +#endif + +// Maximum length of the metadata associated with an object. +// Setting to non-zero value enables metadata-related API but also +// changes the on-disk format, so the change is not backward-compatible. +// +// Do note: the meta length must never exceed +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64) +// +// This is derived from following: +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + +// spiffs_object_ix_header fields + at least some LUT entries) +#ifndef SPIFFS_OBJ_META_LEN +#define SPIFFS_OBJ_META_LEN (0) +#endif + +// Size of buffer allocated on stack used when copying data. +// Lower value generates more read/writes. No meaning having it bigger +// than logical page size. +#ifndef SPIFFS_COPY_BUFFER_STACK +#define SPIFFS_COPY_BUFFER_STACK (64) +#endif + +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + +#if SPIFFS_USE_MAGIC +// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is +// enabled, the magic will also be dependent on the length of the filesystem. +// For example, a filesystem configured and formatted for 4 megabytes will not +// be accepted for mounting with a configuration defining the filesystem as 2 +// megabytes. +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (0) +#endif +#endif + +// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level +// These should be defined on a multithreaded system + +// define this to enter a mutex if you're running on a multithreaded system +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) +#endif +// define this to exit a mutex if you're running on a multithreaded system +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) +#endif + +// Enable if only one spiffs instance with constant configuration will exist +// on the target. This will reduce calculations, flash and memory accesses. +// Parts of configuration must be defined below instead of at time of mount. +#ifndef SPIFFS_SINGLETON +#define SPIFFS_SINGLETON 0 +#endif + +#if SPIFFS_SINGLETON +// Instead of giving parameters in config struct, singleton build must +// give parameters in defines below. +#ifndef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2) +#endif +#ifndef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) +#endif +#ifndef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) +#endif +#ifndef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#endif +#ifndef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) +#endif +#endif + +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0 +#endif + +// Enable this if you want the HAL callbacks to be called with the spiffs struct +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 0 +#endif + +// Enable this if you want to add an integer offset to all file handles +// (spiffs_file). This is useful if running multiple instances of spiffs on +// same target, in order to recognise to what spiffs instance a file handle +// belongs. +// NB: This adds config field fh_ix_offset in the configuration struct when +// mounting, which must be defined. +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 0 +#endif + +// Enable this to compile a read only version of spiffs. +// This will reduce binary size of spiffs. All code comprising modification +// of the file system will not be compiled. Some config will be ignored. +// HAL functions for erasing and writing to spi-flash may be null. Cache +// can be disabled for even further binary size reduction (and ram savings). +// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL. +// If the file system cannot be mounted due to aborted erase operation and +// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be +// returned. +// Might be useful for e.g. bootloaders and such. +#ifndef SPIFFS_READ_ONLY +#define SPIFFS_READ_ONLY 0 +#endif + +// Enable this to add a temporal file cache using the fd buffer. +// The effects of the cache is that SPIFFS_open will find the file faster in +// certain cases. It will make it a lot easier for spiffs to find files +// opened frequently, reducing number of readings from the spi flash for +// finding those files. +// This will grow each fd by 6 bytes. If your files are opened in patterns +// with a degree of temporal locality, the system is optimized. +// Examples can be letting spiffs serve web content, where one file is the css. +// The css is accessed for each html file that is opened, meaning it is +// accessed almost every second time a file is opened. Another example could be +// a log file that is often opened, written, and closed. +// The size of the cache is number of given file descriptors, as it piggybacks +// on the fd update mechanism. The cache lives in the closed file descriptors. +// When closed, the fd know the whereabouts of the file. Instead of forgetting +// this, the temporal cache will keep handling updates to that file even if the +// fd is closed. If the file is opened again, the location of the file is found +// directly. If all available descriptors become opened, all cache memory is +// lost. +#ifndef SPIFFS_TEMPORAL_FD_CACHE +#define SPIFFS_TEMPORAL_FD_CACHE 1 +#endif + +// Temporal file cache hit score. Each time a file is opened, all cached files +// will lose one point. If the opened file is found in cache, that entry will +// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this +// value for the specific access patterns of the application. However, it must +// be between 1 (no gain for hitting a cached entry often) and 255. +#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE +#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4 +#endif + +// Enable to be able to map object indices to memory. +// This allows for faster and more deterministic reading if cases of reading +// large files and when changing file offset by seeking around a lot. +// When mapping a file's index, the file system will be scanned for index pages +// and the info will be put in memory provided by user. When reading, the +// memory map can be looked up instead of searching for index pages on the +// medium. This way, user can trade memory against performance. +// Whole, parts of, or future parts not being written yet can be mapped. The +// memory array will be owned by spiffs and updated accordingly during garbage +// collecting or when modifying the indices. The latter is invoked by when the +// file is modified in some way. The index buffer is tied to the file +// descriptor. +#ifndef SPIFFS_IX_MAP +#define SPIFFS_IX_MAP 1 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// in the api. This function will visualize all filesystem using given printf +// function. +#ifndef SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 1 +#endif +#if SPIFFS_TEST_VISUALISATION +#ifndef spiffs_printf +#define spiffs_printf(...) printf(__VA_ARGS__) +#endif +// spiffs_printf argument for a free page +#ifndef SPIFFS_TEST_VIS_FREE_STR +#define SPIFFS_TEST_VIS_FREE_STR "_" +#endif +// spiffs_printf argument for a deleted page +#ifndef SPIFFS_TEST_VIS_DELE_STR +#define SPIFFS_TEST_VIS_DELE_STR "/" +#endif +// spiffs_printf argument for an index page for given object id +#ifndef SPIFFS_TEST_VIS_INDX_STR +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#endif +// spiffs_printf argument for a data page for given object id +#ifndef SPIFFS_TEST_VIS_DATA_STR +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#endif +#endif + +// Types depending on configuration such as the amount of flash bytes +// given to spiffs file system in total (spiffs_file_system_size), +// the logical block size (log_block_size), and the logical page size +// (log_page_size) + +// Block index type. Make sure the size of this type can hold +// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size +typedef u16_t spiffs_block_ix; +// Page index type. Make sure the size of this type can hold +// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size +typedef u16_t spiffs_page_ix; +// Object id type - most significant bit is reserved for index flag. Make sure the +// size of this type can hold the highest object id on a full system, +// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2 +typedef u16_t spiffs_obj_id; +// Object span index type. Make sure the size of this type can +// hold the largest possible span index on the system - +// i.e. (spiffs_file_system_size / log_page_size) - 1 +typedef u16_t spiffs_span_ix; + +#endif /* SPIFFS_CONFIG_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs.h new file mode 100755 index 0000000..534c3df --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs.h @@ -0,0 +1,816 @@ +/* + * spiffs.h + * + * Created on: May 26, 2013 + * Author: petera + */ + +#ifndef SPIFFS_H_ +#define SPIFFS_H_ +#if defined(__cplusplus) +extern "C" { +#endif + +#include "spiffs_config.h" + +#define SPIFFS_OK 0 +#define SPIFFS_ERR_NOT_MOUNTED -10000 +#define SPIFFS_ERR_FULL -10001 +#define SPIFFS_ERR_NOT_FOUND -10002 +#define SPIFFS_ERR_END_OF_OBJECT -10003 +#define SPIFFS_ERR_DELETED -10004 +#define SPIFFS_ERR_NOT_FINALIZED -10005 +#define SPIFFS_ERR_NOT_INDEX -10006 +#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007 +#define SPIFFS_ERR_FILE_CLOSED -10008 +#define SPIFFS_ERR_FILE_DELETED -10009 +#define SPIFFS_ERR_BAD_DESCRIPTOR -10010 +#define SPIFFS_ERR_IS_INDEX -10011 +#define SPIFFS_ERR_IS_FREE -10012 +#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013 +#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014 +#define SPIFFS_ERR_INDEX_REF_FREE -10015 +#define SPIFFS_ERR_INDEX_REF_LU -10016 +#define SPIFFS_ERR_INDEX_REF_INVALID -10017 +#define SPIFFS_ERR_INDEX_FREE -10018 +#define SPIFFS_ERR_INDEX_LU -10019 +#define SPIFFS_ERR_INDEX_INVALID -10020 +#define SPIFFS_ERR_NOT_WRITABLE -10021 +#define SPIFFS_ERR_NOT_READABLE -10022 +#define SPIFFS_ERR_CONFLICTING_NAME -10023 +#define SPIFFS_ERR_NOT_CONFIGURED -10024 + +#define SPIFFS_ERR_NOT_A_FS -10025 +#define SPIFFS_ERR_MOUNTED -10026 +#define SPIFFS_ERR_ERASE_FAIL -10027 +#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028 + +#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029 + +#define SPIFFS_ERR_FILE_EXISTS -10030 + +#define SPIFFS_ERR_NOT_A_FILE -10031 +#define SPIFFS_ERR_RO_NOT_IMPL -10032 +#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033 +#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034 +#define SPIFFS_ERR_PROBE_NOT_A_FS -10035 +#define SPIFFS_ERR_NAME_TOO_LONG -10036 + +#define SPIFFS_ERR_IX_MAP_UNMAPPED -10037 +#define SPIFFS_ERR_IX_MAP_MAPPED -10038 +#define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039 + +#define SPIFFS_ERR_SEEK_BOUNDS -10040 + + +#define SPIFFS_ERR_INTERNAL -10050 + +#define SPIFFS_ERR_TEST -10100 + + +// spiffs file descriptor index type. must be signed +typedef s16_t spiffs_file; +// spiffs file descriptor flags +typedef u16_t spiffs_flags; +// spiffs file mode +typedef u16_t spiffs_mode; +// object type +typedef u8_t spiffs_obj_type; + +struct spiffs_t; + +#if SPIFFS_HAL_CALLBACK_EXTRA + +/* spi read call function type */ +typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst); +/* spi write call function type */ +typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src); +/* spi erase call function type */ +typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size); + +#else // SPIFFS_HAL_CALLBACK_EXTRA + +/* spi read call function type */ +typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst); +/* spi write call function type */ +typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src); +/* spi erase call function type */ +typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size); +#endif // SPIFFS_HAL_CALLBACK_EXTRA + +/* file system check callback report operation */ +typedef enum { + SPIFFS_CHECK_LOOKUP = 0, + SPIFFS_CHECK_INDEX, + SPIFFS_CHECK_PAGE +} spiffs_check_type; + +/* file system check callback report type */ +typedef enum { + SPIFFS_CHECK_PROGRESS = 0, + SPIFFS_CHECK_ERROR, + SPIFFS_CHECK_FIX_INDEX, + SPIFFS_CHECK_FIX_LOOKUP, + SPIFFS_CHECK_DELETE_ORPHANED_INDEX, + SPIFFS_CHECK_DELETE_PAGE, + SPIFFS_CHECK_DELETE_BAD_FILE +} spiffs_check_report; + +/* file system check callback function */ +#if SPIFFS_HAL_CALLBACK_EXTRA +typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2); +#else // SPIFFS_HAL_CALLBACK_EXTRA +typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2); +#endif // SPIFFS_HAL_CALLBACK_EXTRA + +/* file system listener callback operation */ +typedef enum { + /* the file has been created */ + SPIFFS_CB_CREATED = 0, + /* the file has been updated or moved to another page */ + SPIFFS_CB_UPDATED, + /* the file has been deleted */ + SPIFFS_CB_DELETED +} spiffs_fileop_type; + +/* file system listener callback function */ +typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix); + +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(...) \ + printf(__VA_ARGS__) +#endif +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__) +#endif +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__) +#endif +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__) +#endif + +/* Any write to the filehandle is appended to end of the file */ +#define SPIFFS_APPEND (1<<0) +#define SPIFFS_O_APPEND SPIFFS_APPEND +/* If the opened file exists, it will be truncated to zero length before opened */ +#define SPIFFS_TRUNC (1<<1) +#define SPIFFS_O_TRUNC SPIFFS_TRUNC +/* If the opened file does not exist, it will be created before opened */ +#define SPIFFS_CREAT (1<<2) +#define SPIFFS_O_CREAT SPIFFS_CREAT +/* The opened file may only be read */ +#define SPIFFS_RDONLY (1<<3) +#define SPIFFS_O_RDONLY SPIFFS_RDONLY +/* The opened file may only be written */ +#define SPIFFS_WRONLY (1<<4) +#define SPIFFS_O_WRONLY SPIFFS_WRONLY +/* The opened file may be both read and written */ +#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY) +#define SPIFFS_O_RDWR SPIFFS_RDWR +/* Any writes to the filehandle will never be cached but flushed directly */ +#define SPIFFS_DIRECT (1<<5) +#define SPIFFS_O_DIRECT SPIFFS_DIRECT +/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */ +#define SPIFFS_EXCL (1<<6) +#define SPIFFS_O_EXCL SPIFFS_EXCL + +#define SPIFFS_SEEK_SET (0) +#define SPIFFS_SEEK_CUR (1) +#define SPIFFS_SEEK_END (2) + +#define SPIFFS_TYPE_FILE (1) +#define SPIFFS_TYPE_DIR (2) +#define SPIFFS_TYPE_HARD_LINK (3) +#define SPIFFS_TYPE_SOFT_LINK (4) + +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) +#endif + +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) +#endif + +// phys structs + +// spiffs spi configuration struct +typedef struct { + // physical read function + spiffs_read hal_read_f; + // physical write function + spiffs_write hal_write_f; + // physical erase function + spiffs_erase hal_erase_f; +#if SPIFFS_SINGLETON == 0 + // physical size of the spi flash + u32_t phys_size; + // physical offset in spi flash used for spiffs, + // must be on block boundary + u32_t phys_addr; + // physical size when erasing a block + u32_t phys_erase_block; + + // logical size of a block, must be on physical + // block size boundary and must never be less than + // a physical block + u32_t log_block_size; + // logical size of a page, must be at least + // log_block_size / 8 + u32_t log_page_size; + +#endif +#if SPIFFS_FILEHDL_OFFSET + // an integer offset added to each file handle + u16_t fh_ix_offset; +#endif +} spiffs_config; + +typedef struct spiffs_t { + // file system configuration + spiffs_config cfg; + // number of logical blocks + u32_t block_count; + + // cursor for free blocks, block index + spiffs_block_ix free_cursor_block_ix; + // cursor for free blocks, entry index + int free_cursor_obj_lu_entry; + // cursor when searching, block index + spiffs_block_ix cursor_block_ix; + // cursor when searching, entry index + int cursor_obj_lu_entry; + + // primary work buffer, size of a logical page + u8_t *lu_work; + // secondary work buffer, size of a logical page + u8_t *work; + // file descriptor memory area + u8_t *fd_space; + // available file descriptors + u32_t fd_count; + + // last error + s32_t err_code; + + // current number of free blocks + u32_t free_blocks; + // current number of busy pages + u32_t stats_p_allocated; + // current number of deleted pages + u32_t stats_p_deleted; + // flag indicating that garbage collector is cleaning + u8_t cleaning; + // max erase count amongst all blocks + spiffs_obj_id max_erase_count; + +#if SPIFFS_GC_STATS + u32_t stats_gc_runs; +#endif + +#if SPIFFS_CACHE + // cache memory + void *cache; + // cache size + u32_t cache_size; +#if SPIFFS_CACHE_STATS + u32_t cache_hits; + u32_t cache_misses; +#endif +#endif + + // check callback function + spiffs_check_callback check_cb_f; + // file callback function + spiffs_file_callback file_cb_f; + // mounted flag + u8_t mounted; + // user data + void *user_data; + // config magic + u32_t config_magic; +} spiffs; + +/* spiffs file status struct */ +typedef struct { + spiffs_obj_id obj_id; + u32_t size; + spiffs_obj_type type; + spiffs_page_ix pix; + u8_t name[SPIFFS_OBJ_NAME_LEN]; +#if SPIFFS_OBJ_META_LEN + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif +} spiffs_stat; + +struct spiffs_dirent { + spiffs_obj_id obj_id; + u8_t name[SPIFFS_OBJ_NAME_LEN]; + spiffs_obj_type type; + u32_t size; + spiffs_page_ix pix; +#if SPIFFS_OBJ_META_LEN + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif +}; + +typedef struct { + spiffs *fs; + spiffs_block_ix block; + int entry; +} spiffs_DIR; + +#if SPIFFS_IX_MAP + +typedef struct { + // buffer with looked up data pixes + spiffs_page_ix *map_buf; + // precise file byte offset + u32_t offset; + // start data span index of lookup buffer + spiffs_span_ix start_spix; + // end data span index of lookup buffer + spiffs_span_ix end_spix; +} spiffs_ix_map; + +#endif + +// functions + +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 +/** + * Special function. This takes a spiffs config struct and returns the number + * of blocks this file system was formatted with. This function relies on + * that following info is set correctly in given config struct: + * + * phys_addr, log_page_size, and log_block_size. + * + * Also, hal_read_f must be set in the config struct. + * + * One must be sure of the correct page size and that the physical address is + * correct in the probed file system when calling this function. It is not + * checked if the phys_addr actually points to the start of the file system, + * so one might get a false positive if entering a phys_addr somewhere in the + * middle of the file system at block boundary. In addition, it is not checked + * if the page size is actually correct. If it is not, weird file system sizes + * will be returned. + * + * If this function detects a file system it returns the assumed file system + * size, which can be used to set the phys_size. + * + * Otherwise, it returns an error indicating why it is not regarded as a file + * system. + * + * Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK + * macros. It returns the error code directly, instead of as read by + * SPIFFS_errno. + * + * @param config essential parts of the physical and logical + * configuration of the file system. + */ +s32_t SPIFFS_probe_fs(spiffs_config *config); +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + +/** + * Initializes the file system dynamic parameters and mounts the filesystem. + * If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS + * if the flash does not contain a recognizable file system. + * In this case, SPIFFS_format must be called prior to remounting. + * @param fs the file system struct + * @param config the physical and logical configuration of the file system + * @param work a memory work buffer comprising 2*config->log_page_size + * bytes used throughout all file system operations + * @param fd_space memory for file descriptors + * @param fd_space_size memory size of file descriptors + * @param cache memory for cache, may be null + * @param cache_size memory size of cache + * @param check_cb_f callback function for reporting during consistency checks + */ +s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, + u8_t *fd_space, u32_t fd_space_size, + void *cache, u32_t cache_size, + spiffs_check_callback check_cb_f); + +/** + * Unmounts the file system. All file handles will be flushed of any + * cached writes and closed. + * @param fs the file system struct + */ +void SPIFFS_unmount(spiffs *fs); + +/** + * Creates a new file. + * @param fs the file system struct + * @param path the path of the new file + * @param mode ignored, for posix compliance + */ +s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode); + +/** + * Opens/creates a file. + * @param fs the file system struct + * @param path the path of the new file + * @param flags the flags for the open command, can be combinations of + * SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY, + * SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL + * @param mode ignored, for posix compliance + */ +spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode); + +/** + * Opens a file by given dir entry. + * Optimization purposes, when traversing a file system with SPIFFS_readdir + * a normal SPIFFS_open would need to traverse the filesystem again to find + * the file, whilst SPIFFS_open_by_dirent already knows where the file resides. + * @param fs the file system struct + * @param e the dir entry to the file + * @param flags the flags for the open command, can be combinations of + * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, + * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT. + * SPIFFS_CREAT will have no effect in this case. + * @param mode ignored, for posix compliance + */ +spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode); + +/** + * Opens a file by given page index. + * Optimization purposes, opens a file by directly pointing to the page + * index in the spi flash. + * If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE + * is returned. + * @param fs the file system struct + * @param page_ix the page index + * @param flags the flags for the open command, can be combinations of + * SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY, + * SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT. + * SPIFFS_CREAT will have no effect in this case. + * @param mode ignored, for posix compliance + */ +spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode); + +/** + * Reads from given filehandle. + * @param fs the file system struct + * @param fh the filehandle + * @param buf where to put read data + * @param len how much to read + * @returns number of bytes read, or -1 if error + */ +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len); + +/** + * Writes to given filehandle. + * @param fs the file system struct + * @param fh the filehandle + * @param buf the data to write + * @param len how much to write + * @returns number of bytes written, or -1 if error + */ +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len); + +/** + * Moves the read/write file offset. Resulting offset is returned or negative if error. + * lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset. + * @param fs the file system struct + * @param fh the filehandle + * @param offs how much/where to move the offset + * @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes + * if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset + * if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative + */ +s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence); + +/** + * Removes a file by path + * @param fs the file system struct + * @param path the path of the file to remove + */ +s32_t SPIFFS_remove(spiffs *fs, const char *path); + +/** + * Removes a file by filehandle + * @param fs the file system struct + * @param fh the filehandle of the file to remove + */ +s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh); + +/** + * Gets file status by path + * @param fs the file system struct + * @param path the path of the file to stat + * @param s the stat struct to populate + */ +s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s); + +/** + * Gets file status by filehandle + * @param fs the file system struct + * @param fh the filehandle of the file to stat + * @param s the stat struct to populate + */ +s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s); + +/** + * Flushes all pending write operations from cache for given file + * @param fs the file system struct + * @param fh the filehandle of the file to flush + */ +s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh); + +/** + * Closes a filehandle. If there are pending write operations, these are finalized before closing. + * @param fs the file system struct + * @param fh the filehandle of the file to close + */ +s32_t SPIFFS_close(spiffs *fs, spiffs_file fh); + +/** + * Renames a file + * @param fs the file system struct + * @param old path of file to rename + * @param newPath new path of file + */ +s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath); + +#if SPIFFS_OBJ_META_LEN +/** + * Updates file's metadata + * @param fs the file system struct + * @param path path to the file + * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. + */ +s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta); + +/** + * Updates file's metadata + * @param fs the file system struct + * @param fh file handle of the file + * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. + */ +s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta); +#endif + +/** + * Returns last error of last file operation. + * @param fs the file system struct + */ +s32_t SPIFFS_errno(spiffs *fs); + +/** + * Clears last error. + * @param fs the file system struct + */ +void SPIFFS_clearerr(spiffs *fs); + +/** + * Opens a directory stream corresponding to the given name. + * The stream is positioned at the first entry in the directory. + * On hydrogen builds the name argument is ignored as hydrogen builds always correspond + * to a flat file structure - no directories. + * @param fs the file system struct + * @param name the name of the directory + * @param d pointer the directory stream to be populated + */ +spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d); + +/** + * Closes a directory stream + * @param d the directory stream to close + */ +s32_t SPIFFS_closedir(spiffs_DIR *d); + +/** + * Reads a directory into given spifs_dirent struct. + * @param d pointer to the directory stream + * @param e the dirent struct to be populated + * @returns null if error or end of stream, else given dirent is returned + */ +struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e); + +/** + * Runs a consistency check on given filesystem. + * @param fs the file system struct + */ +s32_t SPIFFS_check(spiffs *fs); + +/** + * Returns number of total bytes available and number of used bytes. + * This is an estimation, and depends on if there a many files with little + * data or few files with much data. + * NB: If used number of bytes exceeds total bytes, a SPIFFS_check should + * run. This indicates a power loss in midst of things. In worst case + * (repeated powerlosses in mending or gc) you might have to delete some files. + * + * @param fs the file system struct + * @param total total number of bytes in filesystem + * @param used used number of bytes in filesystem + */ +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used); + +/** + * Formats the entire file system. All data will be lost. + * The filesystem must not be mounted when calling this. + * + * NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount + * MUST be called prior to formatting in order to configure the filesystem. + * If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling + * SPIFFS_format. + * If SPIFFS_mount fails, SPIFFS_format can be called directly without calling + * SPIFFS_unmount first. + * + * @param fs the file system struct + */ +s32_t SPIFFS_format(spiffs *fs); + +/** + * Returns nonzero if spiffs is mounted, or zero if unmounted. + * @param fs the file system struct + */ +u8_t SPIFFS_mounted(spiffs *fs); + +/** + * Tries to find a block where most or all pages are deleted, and erase that + * block if found. Does not care for wear levelling. Will not move pages + * around. + * If parameter max_free_pages are set to 0, only blocks with only deleted + * pages will be selected. + * + * NB: the garbage collector is automatically called when spiffs needs free + * pages. The reason for this function is to give possibility to do background + * tidying when user knows the system is idle. + * + * Use with care. + * + * Setting max_free_pages to anything larger than zero will eventually wear + * flash more as a block containing free pages can be erased. + * + * Will set err_no to SPIFFS_OK if a block was found and erased, + * SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found, + * or other error. + * + * @param fs the file system struct + * @param max_free_pages maximum number allowed free pages in block + */ +s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages); + +/** + * Will try to make room for given amount of bytes in the filesystem by moving + * pages and erasing blocks. + * If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If + * there already is this amount (or more) of free space, SPIFFS_gc will + * silently return. It is recommended to call SPIFFS_info before invoking + * this method in order to determine what amount of bytes to give. + * + * NB: the garbage collector is automatically called when spiffs needs free + * pages. The reason for this function is to give possibility to do background + * tidying when user knows the system is idle. + * + * Use with care. + * + * @param fs the file system struct + * @param size amount of bytes that should be freed + */ +s32_t SPIFFS_gc(spiffs *fs, u32_t size); + +/** + * Check if EOF reached. + * @param fs the file system struct + * @param fh the filehandle of the file to check + */ +s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh); + +/** + * Get position in file. + * @param fs the file system struct + * @param fh the filehandle of the file to check + */ +s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh); + +/** + * Registers a callback function that keeps track on operations on file + * headers. Do note, that this callback is called from within internal spiffs + * mechanisms. Any operations on the actual file system being callbacked from + * in this callback will mess things up for sure - do not do this. + * This can be used to track where files are and move around during garbage + * collection, which in turn can be used to build location tables in ram. + * Used in conjuction with SPIFFS_open_by_page this may improve performance + * when opening a lot of files. + * Must be invoked after mount. + * + * @param fs the file system struct + * @param cb_func the callback on file operations + */ +s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func); + +#if SPIFFS_IX_MAP + +/** + * Maps the first level index lookup to a given memory map. + * This will make reading big files faster, as the memory map will be used for + * looking up data pages instead of searching for the indices on the physical + * medium. When mapping, all affected indicies are found and the information is + * copied to the array. + * Whole file or only parts of it may be mapped. The index map will cover file + * contents from argument offset until and including arguments (offset+len). + * It is valid to map a longer range than the current file size. The map will + * then be populated when the file grows. + * On garbage collections and file data page movements, the map array will be + * automatically updated. Do not tamper with the map array, as this contains + * the references to the data pages. Modifying it from outside will corrupt any + * future readings using this file descriptor. + * The map will no longer be used when the file descriptor closed or the file + * is unmapped. + * This can be useful to get faster and more deterministic timing when reading + * large files, or when seeking and reading a lot within a file. + * @param fs the file system struct + * @param fh the file handle of the file to map + * @param map a spiffs_ix_map struct, describing the index map + * @param offset absolute file offset where to start the index map + * @param len length of the mapping in actual file bytes + * @param map_buf the array buffer for the look up data - number of required + * elements in the array can be derived from function + * SPIFFS_bytes_to_ix_map_entries given the length + */ +s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map, + u32_t offset, u32_t len, spiffs_page_ix *map_buf); + +/** + * Unmaps the index lookup from this filehandle. All future readings will + * proceed as normal, requiring reading of the first level indices from + * physical media. + * The map and map buffer given in function SPIFFS_ix_map will no longer be + * referenced by spiffs. + * It is not strictly necessary to unmap a file before closing it, as closing + * a file will automatically unmap it. + * @param fs the file system struct + * @param fh the file handle of the file to unmap + */ +s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh); + +/** + * Moves the offset for the index map given in function SPIFFS_ix_map. Parts or + * all of the map buffer will repopulated. + * @param fs the file system struct + * @param fh the mapped file handle of the file to remap + * @param offset new absolute file offset where to start the index map + */ +s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs); + +/** + * Utility function to get number of spiffs_page_ix entries a map buffer must + * contain on order to map given amount of file data in bytes. + * See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes. + * @param fs the file system struct + * @param bytes number of file data bytes to map + * @return needed number of elements in a spiffs_page_ix array needed to + * map given amount of bytes in a file + */ +s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes); + +/** + * Utility function to amount of file data bytes that can be mapped when + * mapping a file with buffer having given number of spiffs_page_ix entries. + * See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries. + * @param fs the file system struct + * @param map_page_ix_entries number of entries in a spiffs_page_ix array + * @return amount of file data in bytes that can be mapped given a map + * buffer having given amount of spiffs_page_ix entries + */ +s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries); + +#endif // SPIFFS_IX_MAP + + +#if SPIFFS_TEST_VISUALISATION +/** + * Prints out a visualization of the filesystem. + * @param fs the file system struct + */ +s32_t SPIFFS_vis(spiffs *fs); +#endif + +#if SPIFFS_BUFFER_HELP +/** + * Returns number of bytes needed for the filedescriptor buffer given + * amount of file descriptors. + */ +u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs); + +#if SPIFFS_CACHE +/** + * Returns number of bytes needed for the cache buffer given + * amount of cache pages. + */ +u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages); +#endif +#endif + +#if SPIFFS_CACHE +#endif +#if defined(__cplusplus) +} +#endif + +#endif /* SPIFFS_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_cache.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_cache.c new file mode 100755 index 0000000..37c9d64 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_cache.c @@ -0,0 +1,317 @@ +/* + * spiffs_cache.c + * + * Created on: Jun 23, 2013 + * Author: petera + */ + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#if SPIFFS_CACHE + +// returns cached page for give page index, or null if no such cached page +static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) { + spiffs_cache *cache = spiffs_get_cache(fs); + if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0; + int i; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && + cp->pix == pix ) { + //SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix); + cp->last_access = cache->last_access; + return cp; + } + } + //SPIFFS_CACHE_DBG("CACHE_GET: no cache for "_SPIPRIpg"\n", pix); + return 0; +} + +// frees cached page +static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) { + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix); + if (cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && + (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) { + u8_t *mem = spiffs_get_cache_page(fs, cache, ix); + SPIFFS_CACHE_DBG("CACHE_FREE: write cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix); + res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem); + } + + + if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) { + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id); + } else { + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix); + } + cache->cpage_use_map &= ~(1 << ix); + cp->flags = 0; + } + + return res; +} + +// removes the oldest accessed cached page +static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) { + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + + if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) { + // at least one free cpage + return SPIFFS_OK; + } + + // all busy, scan thru all to find the cpage which has oldest access + int i; + int cand_ix = -1; + u32_t oldest_val = 0; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->last_access - cp->last_access) > oldest_val && + (cp->flags & flag_mask) == flags) { + oldest_val = cache->last_access - cp->last_access; + cand_ix = i; + } + } + + if (cand_ix >= 0) { + res = spiffs_cache_page_free(fs, cand_ix, 1); + } + + return res; +} + +// allocates a new cached page and returns it, or null if all cache pages are busy +static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) { + spiffs_cache *cache = spiffs_get_cache(fs); + if (cache->cpage_use_map == 0xffffffff) { + // out of cache memory + return 0; + } + int i; + for (i = 0; i < cache->cpage_count; i++) { + if ((cache->cpage_use_map & (1<cpage_use_map |= (1<last_access = cache->last_access; + //SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i); + return cp; + } + } + // out of cache entries + return 0; +} + +// drops the cache page for give page index +void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) { + spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); + if (cp) { + spiffs_cache_page_free(fs, cp->ix, 0); + } +} + +// ------------------------------ + +// reads from spi flash or the cache +s32_t spiffs_phys_rd( + spiffs *fs, + u8_t op, + spiffs_file fh, + u32_t addr, + u32_t len, + u8_t *dst) { + (void)fh; + s32_t res = SPIFFS_OK; + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr)); + cache->last_access++; + if (cp) { + // we've already got one, you see +#if SPIFFS_CACHE_STATS + fs->cache_hits++; +#endif + cp->last_access = cache->last_access; + u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); + _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); + } else { + if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) { + // for second layer lookup functions, we do not cache in order to prevent shredding + return SPIFFS_HAL_READ(fs, addr, len, dst); + } +#if SPIFFS_CACHE_STATS + fs->cache_misses++; +#endif + // this operation will always free one cache page (unless all already free), + // the result code stems from the write operation of the possibly freed cache page + res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); + + cp = spiffs_cache_page_allocate(fs); + if (cp) { + cp->flags = SPIFFS_CACHE_FLAG_WRTHRU; + cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr); + SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for pix "_SPIPRIpg "\n", cp->ix, cp->pix); + + s32_t res2 = SPIFFS_HAL_READ(fs, + addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr), + SPIFFS_CFG_LOG_PAGE_SZ(fs), + spiffs_get_cache_page(fs, cache, cp->ix)); + if (res2 != SPIFFS_OK) { + // honor read failure before possible write failure (bad idea?) + res = res2; + } + u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); + _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); + } else { + // this will never happen, last resort for sake of symmetry + s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst); + if (res2 != SPIFFS_OK) { + // honor read failure before possible write failure (bad idea?) + res = res2; + } + } + } + return res; +} + +// writes to spi flash and/or the cache +s32_t spiffs_phys_wr( + spiffs *fs, + u8_t op, + spiffs_file fh, + u32_t addr, + u32_t len, + u8_t *src) { + (void)fh; + spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr); + spiffs_cache *cache = spiffs_get_cache(fs); + spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix); + + if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) { + // have a cache page + // copy in data to cache page + + if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE && + (op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) { + // page is being deleted, wipe from cache - unless it is a lookup page + spiffs_cache_page_free(fs, cp->ix, 0); + return SPIFFS_HAL_WRITE(fs, addr, len, src); + } + + u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); + _SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len); + + cache->last_access++; + cp->last_access = cache->last_access; + + if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) { + // page is being updated, no write-cache, just pass thru + return SPIFFS_HAL_WRITE(fs, addr, len, src); + } else { + return SPIFFS_OK; + } + } else { + // no cache page, no write cache - just write thru + return SPIFFS_HAL_WRITE(fs, addr, len, src); + } +} + +#if SPIFFS_CACHE_WR +// returns the cache page that this fd refers, or null if no cache page +spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) { + spiffs_cache *cache = spiffs_get_cache(fs); + + if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) { + // all cpages free, no cpage cannot be assigned to obj_id + return 0; + } + + int i; + for (i = 0; i < cache->cpage_count; i++) { + spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); + if ((cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) && + cp->obj_id == fd->obj_id) { + return cp; + } + } + + return 0; +} + +// allocates a new cache page and refers this to given fd - flushes an old cache +// page if all cache is busy +spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) { + // before this function is called, it is ensured that there is no already existing + // cache page with same object id + spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0); + spiffs_cache_page *cp = spiffs_cache_page_allocate(fs); + if (cp == 0) { + // could not get cache page + return 0; + } + + cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR; + cp->obj_id = fd->obj_id; + fd->cache_page = cp; + SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for fd "_SPIPRIfd ":"_SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id); + return cp; +} + +// unrefers all fds that this cache page refers to and releases the cache page +void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) { + if (cp == 0) return; + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) { + cur_fd->cache_page = 0; + } + } + spiffs_cache_page_free(fs, cp->ix, 0); + + cp->obj_id = 0; +} + +#endif + +// initializes the cache +void spiffs_cache_init(spiffs *fs) { + if (fs->cache == 0) return; + u32_t sz = fs->cache_size; + u32_t cache_mask = 0; + int i; + int cache_entries = + (sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs)); + if (cache_entries <= 0) return; + + for (i = 0; i < cache_entries; i++) { + cache_mask <<= 1; + cache_mask |= 1; + } + + spiffs_cache cache; + memset(&cache, 0, sizeof(spiffs_cache)); + cache.cpage_count = cache_entries; + cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache)); + + cache.cpage_use_map = 0xffffffff; + cache.cpage_use_mask = cache_mask; + _SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache)); + + spiffs_cache *c = spiffs_get_cache(fs); + + memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs)); + + c->cpage_use_map &= ~(c->cpage_use_mask); + for (i = 0; i < cache.cpage_count; i++) { + spiffs_get_cache_page_hdr(fs, c, i)->ix = i; + } +} + +#endif // SPIFFS_CACHE diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_check.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_check.c new file mode 100755 index 0000000..dde85ef --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_check.c @@ -0,0 +1,995 @@ +/* + * spiffs_check.c + * + * Contains functionality for checking file system consistency + * and mending problems. + * Three levels of consistency checks are implemented: + * + * Look up consistency + * Checks if indices in lookup pages are coherent with page headers + * Object index consistency + * Checks if there are any orphaned object indices (missing object index headers). + * If an object index is found but not its header, the object index is deleted. + * This is critical for the following page consistency check. + * Page consistency + * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed + * + * + * Created on: Jul 7, 2013 + * Author: petera + */ + + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#if !SPIFFS_READ_ONLY + +#if SPIFFS_HAL_CALLBACK_EXTRA +#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \ + do { \ + if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \ + } while (0) +#else +#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \ + do { \ + if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \ + } while (0) +#endif + +//--------------------------------------- +// Look up consistency + +// searches in the object indices and returns the referenced page index given +// the object id and the data span index +// destroys fs->lu_work +static s32_t spiffs_object_get_data_page_index_reference( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix data_spix, + spiffs_page_ix *pix, + spiffs_page_ix *objix_pix) { + s32_t res; + + // calculate object index span index for given data page span index + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // find obj index for obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix); + SPIFFS_CHECK_RES(res); + + // load obj index entry + u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix); + if (objix_spix == 0) { + // get referenced page from object index header + addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix); + } else { + // get referenced page from object index + addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix); + } + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix); + + return res; +} + +// copies page contents to a new page +static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) { + s32_t res; + res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, + SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + return res; +} + +// rewrites the object index for given object id and replaces the +// data page index to a new page index +static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + spiffs_page_ix free_pix; + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + + // calculate object index span index for given data page span index + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (objix_spix == 0) { + // calc index in index header + entry = data_spix; + } else { + // calc entry in index + entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix); + + } + // load index + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work; + + // be ultra safe, double check header against provided data + if (objix_p_hdr->obj_id != obj_id) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_OBJ_ID_MISM; + } + if (objix_p_hdr->span_ix != objix_spix) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_SPIX_MISM; + } + if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX | + SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) != + (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) { + spiffs_page_delete(fs, free_pix); + return SPIFFS_ERR_CHECK_FLAGS_BAD; + } + + // rewrite in mem + if (objix_spix == 0) { + ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix; + } else { + ((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix; + } + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&obj_id); + SPIFFS_CHECK_RES(res); + res = spiffs_page_delete(fs, objix_pix); + + return res; +} + +// deletes an object just by marking object index header as deleted +static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) { + spiffs_page_ix objix_hdr_pix; + s32_t res; + res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + return SPIFFS_OK; + } + SPIFFS_CHECK_RES(res); + u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&flags); + return res; +} + +// validates the given look up entry +static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr, + spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) { + (void)cur_block; + (void)cur_entry; + u8_t delete_page = 0; + s32_t res = SPIFFS_OK; + spiffs_page_ix objix_pix; + spiffs_page_ix ref_pix; + // check validity, take actions + if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) || + ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) { + // look up entry deleted / free but used in page header + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix); + *reload_lu = 1; + delete_page = 1; + if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) { + // header says data page + // data page can be removed if not referenced by some object index + res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + } else { + SPIFFS_CHECK_RES(res); + if (ref_pix == cur_pix) { + // data page referenced by object index but deleted in lu + // copy page to new place and re-write the object index to new place + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix); + res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); + res = spiffs_page_delete(fs, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0); + } else { + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix); + } + SPIFFS_CHECK_RES(res); + } + } + } else { + // header says index page + // index page can be removed if other index with same obj_id and spanix is found + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no such index page found, check for a data page amongst page headers + // lu cannot be trusted + res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0); + if (res == SPIFFS_OK) { // ignore other errors + // got a data page also, assume lu corruption only, rewrite to new page + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + } + } else { + SPIFFS_CHECK_RES(res); + } + } + } + if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) { + // look up entry used + if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) { + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id); + delete_page = 1; + if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 || + (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) || + (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) { + // page deleted or not finalized, just remove it + } else { + if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) { + // if data page, check for reference to this page + res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + } else { + SPIFFS_CHECK_RES(res); + // if found, rewrite page with object id, update index, and delete current + if (ref_pix == cur_pix) { + spiffs_page_ix new_pix; + res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); + res = spiffs_page_delete(fs, new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); + *reload_lu = 1; + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0); + } + SPIFFS_CHECK_RES(res); + } + } + } else { + // else if index, check for other pages with both obj_id's and spanix + spiffs_page_ix objix_pix_lu, objix_pix_ph; + // see if other object index page exists for lookup obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_lu = 0; + } + SPIFFS_CHECK_RES(res); + // see if other object index exists for page header obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_ph = 0; + } + SPIFFS_CHECK_RES(res); + // if both obj_id's found, just delete current + if (objix_pix_ph == 0 || objix_pix_lu == 0) { + // otherwise try finding first corresponding data pages + spiffs_page_ix data_pix_lu, data_pix_ph; + // see if other data page exists for look up obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_lu = 0; + } + SPIFFS_CHECK_RES(res); + // see if other data page exists for page header obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_ph = 0; + } + SPIFFS_CHECK_RES(res); + + spiffs_page_header new_ph; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL); + new_ph.span_ix = p_hdr->span_ix; + spiffs_page_ix new_pix; + if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) || + (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) { + // got a data page for page header obj id + // rewrite as obj_id_ph + new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG; + res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) || + (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) { + // got a data page for look up obj id + // rewrite as obj_id_lu + new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG; + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); + SPIFFS_CHECK_RES(res); + *reload_lu = 1; + } else { + // cannot safely do anything + SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n"); + } + } + } + } + } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) || + ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) { + SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix); + spiffs_page_ix data_pix, objix_pix_d; + // see if other data page exists for given obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + // see if other object index exists for given obj id and span index + res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + objix_pix_d = 0; + } + SPIFFS_CHECK_RES(res); + + delete_page = 1; + // if other data page exists and object index exists, just delete page + if (data_pix && objix_pix_d) { + SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n"); + } else + // if only data page exists, make this page index + if (data_pix && objix_pix_d == 0) { + SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n"); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix); + spiffs_page_header new_ph; + spiffs_page_ix new_pix; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX); + new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = p_hdr->span_ix; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header)); + SPIFFS_CHECK_RES(res); + } else + // if only index exists, make data page + if (data_pix == 0 && objix_pix_d) { + SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n"); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix); + spiffs_page_header new_ph; + spiffs_page_ix new_pix; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL); + new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = p_hdr->span_ix; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header), + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header)); + SPIFFS_CHECK_RES(res); + } else { + // if nothing exists, we cannot safely make a decision - delete + } + } + else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) { + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix); + delete_page = 1; + } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) { + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix); + // page can be removed if not referenced by object index + *reload_lu = 1; + res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // no object with this id, so remove page safely + res = SPIFFS_OK; + delete_page = 1; + } else { + SPIFFS_CHECK_RES(res); + if (ref_pix != cur_pix) { + SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n"); + delete_page = 1; + } else { + // page referenced by object index but not final + // just finalize + SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n"); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); + u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), (u8_t*)&flags); + } + } + } + } + + if (delete_page) { + SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix); + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + } + + return res; +} + +static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry, + const void *user_const_p, void *user_var_p) { + (void)user_const_p; + (void)user_var_p; + s32_t res = SPIFFS_OK; + spiffs_page_header p_hdr; + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry); + + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, + (cur_block * 256)/fs->block_count, 0); + + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + int reload_lu = 0; + + res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu); + SPIFFS_CHECK_RES(res); + + if (res == SPIFFS_OK) { + return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE; + } + return res; +} + + +// Scans all object look up. For each entry, corresponding page header is checked for validity. +// If an object index header page is found, this is also checked +s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) { + (void)check_all_objects; + s32_t res = SPIFFS_OK; + + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0); + + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + if (res != SPIFFS_OK) { + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0); + } + + CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0); + + return res; +} + +//--------------------------------------- +// Page consistency + +// Scans all pages (except lu pages), reserves 4 bits in working memory for each page +// bit 0: 0 == FREE|DELETED, 1 == USED +// bit 1: 0 == UNREFERENCED, 1 == REFERENCED +// bit 2: 0 == NOT_INDEX, 1 == INDEX +// bit 3: unused +// A consistent file system will have only pages being +// * x000 free, unreferenced, not index +// * x011 used, referenced only once, not index +// * x101 used, unreferenced, index +// The working memory might not fit all pages so several scans might be needed +static s32_t spiffs_page_consistency_check_i(spiffs *fs) { + const u32_t bits = 4; + const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits; + + s32_t res = SPIFFS_OK; + spiffs_page_ix pix_offset = 0; + + // for each range of pages fitting into work memory + while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) { + // set this flag to abort all checks and rescan the page range + u8_t restart = 0; + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + + spiffs_block_ix cur_block = 0; + // build consistency bitmap for id range traversing all blocks + while (!restart && cur_block < fs->block_count) { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, + (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) + + ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count), + 0); + // traverse each page except for lookup pages + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block; + while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) { + //if ((cur_pix & 0xff) == 0) + // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n", + // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count); + + // read header + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan); + const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits); + const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits; + + if (within_range && + (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) { + // used + fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0)); + } + if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) && + (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) && + (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) { + // found non-deleted index + if (within_range) { + fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2)); + } + + // load non-deleted index + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + + // traverse index for referenced pages + spiffs_page_ix *object_page_index; + spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work; + + int entries; + int i; + spiffs_span_ix data_spix_offset; + if (p_hdr.span_ix == 0) { + // object header page index + entries = SPIFFS_OBJ_HDR_IX_LEN(fs); + data_spix_offset = 0; + object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)); + } else { + // object page index + entries = SPIFFS_OBJ_IX_LEN(fs); + data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1); + object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)); + } + + // for all entries in index + for (i = 0; !restart && i < entries; i++) { + spiffs_page_ix rpix = object_page_index[i]; + u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan; + + if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs)) + || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) { + + // bad reference + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n", + rpix, cur_pix); + // check for data page elsewhere + spiffs_page_ix data_pix; + res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, 0, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + if (data_pix == 0) { + // if not, allocate free page + spiffs_page_header new_ph; + new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL); + new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + new_ph.span_ix = data_spix_offset + i; + res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix); + SPIFFS_CHECK_RES(res); + SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix); + } + // remap index + SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix); + res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, data_pix, cur_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0); + // delete file + res = spiffs_page_delete(fs, cur_pix); + } else { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + + } else if (rpix_within_range) { + + // valid reference + // read referenced page header + spiffs_page_header rp_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr); + SPIFFS_CHECK_RES(res); + + // cross reference page header check + if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) || + rp_hdr.span_ix != data_spix_offset + i || + (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) != + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) { + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n", + rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i, + rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags); + // try finding correct page + spiffs_page_ix data_pix; + res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + data_spix_offset + i, rpix, &data_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + data_pix = 0; + } + SPIFFS_CHECK_RES(res); + if (data_pix == 0) { + // not found, this index is badly borked + SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + SPIFFS_CHECK_RES(res); + break; + } else { + // found it, so rewrite index + SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n", + data_pix, cur_pix, p_hdr.obj_id); + res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + } else { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + } + } + else { + // mark rpix as referenced + const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits); + const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits; + if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) { + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n", + rpix, cur_pix); + // Here, we should have fixed all broken references - getting this means there + // must be multiple files with same object id. Only solution is to delete + // the object which is referring to this page + SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n", + p_hdr.obj_id, cur_pix); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + SPIFFS_CHECK_RES(res); + // extra precaution, delete this page also + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + restart = 1; + } + fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1)); + } + } + } // for all index entries + } // found index + + // next page + cur_pix++; + } + // next block + cur_block++; + } + // check consistency bitmap + if (!restart) { + spiffs_page_ix objix_pix; + spiffs_page_ix rpix; + + u32_t byte_ix; + u8_t bit_ix; + for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) { + for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) { + u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7; + spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix; + + // 000 ok - free, unreferenced, not index + + if (bitmask == 0x1) { + + // 001 + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix); + + u8_t rewrite_ix_to_this = 0; + u8_t delete_page = 0; + // check corresponding object index entry + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix, + &rpix, &objix_pix); + if (res == SPIFFS_OK) { + if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) { + // pointing to a bad page altogether, rewrite index to this + rewrite_ix_to_this = 1; + SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix); + } else { + // pointing to something else, check what + spiffs_page_header rp_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr); + SPIFFS_CHECK_RES(res); + if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) && + ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) == + (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) { + // pointing to something else valid, just delete this page then + SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix); + delete_page = 1; + } else { + // pointing to something weird, update index to point to this page instead + if (rpix != cur_pix) { + SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix, + (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ", + (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ", + (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "", + (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "", + cur_pix); + rewrite_ix_to_this = 1; + } else { + // should not happen, destined for fubar + } + } + } + } else if (res == SPIFFS_ERR_NOT_FOUND) { + SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix); + delete_page = 1; + res = SPIFFS_OK; + } + + if (rewrite_ix_to_this) { + // if pointing to invalid page, redirect index to this page + SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n", + p_hdr.obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix); + if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { + // index bad also, cannot mend this file + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); + } else { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix); + } + SPIFFS_CHECK_RES(res); + restart = 1; + continue; + } else if (delete_page) { + SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix); + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); + res = spiffs_page_delete(fs, cur_pix); + } + SPIFFS_CHECK_RES(res); + } + if (bitmask == 0x2) { + + // 010 + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + + // 011 ok - busy, referenced, not index + + if (bitmask == 0x4) { + + // 100 + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix); + + // this should never happen, major fubar + } + + // 101 ok - busy, unreferenced, index + + if (bitmask == 0x6) { + + // 110 + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + if (bitmask == 0x7) { + + // 111 + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix); + + // no op, this should be taken care of when checking valid references + } + } + } + } + + SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart); + // next page range + if (!restart) { + pix_offset += pages_per_scan; + } + } // while page range not reached end + return res; +} + +// Checks consistency amongst all pages and fixes irregularities +s32_t spiffs_page_consistency_check(spiffs *fs) { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0); + s32_t res = spiffs_page_consistency_check_i(fs); + if (res != SPIFFS_OK) { + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0); + } + CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0); + return res; +} + +//--------------------------------------- +// Object index consistency + +// searches for given object id in temporary object id index, +// returns the index or -1 +static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) { + u32_t i; + spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work; + obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) { + if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) { + return i; + } + } + return -1; +} + +static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, + int cur_entry, const void *user_const_p, void *user_var_p) { + (void)user_const_p; + s32_t res_c = SPIFFS_VIS_COUNTINUE; + s32_t res = SPIFFS_OK; + u32_t *log_ix = (u32_t*)user_var_p; + spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work; + + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, + (cur_block * 256)/fs->block_count, 0); + + if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_page_header p_hdr; + spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry); + + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + + if (p_hdr.span_ix == 0 && + (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET)) { + SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n", + cur_pix, obj_id, p_hdr.span_ix); + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + return res_c; + } + + if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + return res_c; + } + + if (p_hdr.span_ix == 0) { + // objix header page, register objid as reachable + int r = spiffs_object_index_search(fs, obj_id); + if (r == -1) { + // not registered, do it + obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + (*log_ix)++; + if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) { + *log_ix = 0; + } + } + } else { // span index + // objix page, see if header can be found + int r = spiffs_object_index_search(fs, obj_id); + u8_t delete = 0; + if (r == -1) { + // not in temporary index, try finding it + spiffs_page_ix objix_hdr_pix; + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix); + res_c = SPIFFS_VIS_COUNTINUE_RELOAD; + if (res == SPIFFS_OK) { + // found, register as reachable + obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + } else if (res == SPIFFS_ERR_NOT_FOUND) { + // not found, register as unreachable + delete = 1; + obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG; + } else { + SPIFFS_CHECK_RES(res); + } + (*log_ix)++; + if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) { + *log_ix = 0; + } + } else { + // in temporary index, check reachable flag + if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) { + // registered as unreachable + delete = 1; + } + } + + if (delete) { + SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n", + cur_pix, obj_id, p_hdr.span_ix); + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + } + } // span index + } // valid object index id + + return res_c; +} + +// Removes orphaned and partially deleted index pages. +// Scans for index pages. When an index page is found, corresponding index header is searched for. +// If no such page exists, the index page cannot be reached as no index header exists and must be +// deleted. +s32_t spiffs_object_index_consistency_check(spiffs *fs) { + s32_t res = SPIFFS_OK; + // impl note: + // fs->work is used for a temporary object index memory, listing found object ids and + // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit. + // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate + // a reachable/unreachable object id. + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + u32_t obj_id_log_ix = 0; + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix, + 0, 0); + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + if (res != SPIFFS_OK) { + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0); + } + CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0); + return res; +} + +#endif // !SPIFFS_READ_ONLY diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_gc.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_gc.c new file mode 100755 index 0000000..db1af4c --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_gc.c @@ -0,0 +1,606 @@ +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#if !SPIFFS_READ_ONLY + +// Erases a logical block and updates the erase counter. +// If cache is enabled, all pages that might be cached in this block +// is dropped. +static s32_t spiffs_gc_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + + SPIFFS_GC_DBG("gc: erase block "_SPIPRIbl"\n", bix); + res = spiffs_erase_block(fs, bix); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_CACHE + { + u32_t i; + for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) { + spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i); + } + } +#endif + return res; +} + +// Searches for blocks where all entries are deleted - if one is found, +// the block is erased. Compared to the non-quick gc, the quick one ensures +// that no updates are needed on existing objects on pages that are erased. +s32_t spiffs_gc_quick( + spiffs *fs, u16_t max_free_pages) { + s32_t res = SPIFFS_OK; + u32_t blocks = fs->block_count; + spiffs_block_ix cur_block = 0; + u32_t cur_block_addr = 0; + int cur_entry = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + + SPIFFS_GC_DBG("gc_quick: running\n"); +#if SPIFFS_GC_STATS + fs->stats_gc_runs++; +#endif + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // find fully deleted blocks + // check each block + while (res == SPIFFS_OK && blocks--) { + u16_t deleted_pages_in_block = 0; + u16_t free_pages_in_block = 0; + + int obj_lookup_page = 0; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && + cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_DELETED) { + deleted_pages_in_block++; + } else if (obj_id == SPIFFS_OBJ_ID_FREE) { + // kill scan, go for next block + free_pages_in_block++; + if (free_pages_in_block > max_free_pages) { + obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); + res = 1; // kill object lu loop + break; + } + } else { + // kill scan, go for next block + obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs); + res = 1; // kill object lu loop + break; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + if (res == 1) res = SPIFFS_OK; + + if (res == SPIFFS_OK && + deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) && + free_pages_in_block <= max_free_pages) { + // found a fully deleted block + fs->stats_p_deleted -= deleted_pages_in_block; + res = spiffs_gc_erase_block(fs, cur_block); + return res; + } + + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + } // per block + + if (res == SPIFFS_OK) { + res = SPIFFS_ERR_NO_DELETED_BLOCKS; + } + return res; +} + +// Checks if garbage collecting is necessary. If so a candidate block is found, +// cleansed and erased +s32_t spiffs_gc_check( + spiffs *fs, + u32_t len) { + s32_t res; + s32_t free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2) + - fs->stats_p_allocated - fs->stats_p_deleted; + int tries = 0; + + if (fs->free_blocks > 3 && + (s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + return SPIFFS_OK; + } + + u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); +// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { +// SPIFFS_GC_DBG("gc: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); +// return SPIFFS_ERR_FULL; +// } + if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) { + SPIFFS_GC_DBG("gc_check: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); + return SPIFFS_ERR_FULL; + } + + do { + SPIFFS_GC_DBG("\ngc_check #"_SPIPRIi": run gc free_blocks:"_SPIPRIi" pfree:"_SPIPRIi" pallo:"_SPIPRIi" pdele:"_SPIPRIi" ["_SPIPRIi"] len:"_SPIPRIi" of "_SPIPRIi"\n", + tries, + fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted), + len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); + + spiffs_block_ix *cands; + int count; + spiffs_block_ix cand; + s32_t prev_free_pages = free_pages; + // if the fs is crammed, ignore block age when selecting candidate - kind of a bad state + res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0); + SPIFFS_CHECK_RES(res); + if (count == 0) { + SPIFFS_GC_DBG("gc_check: no candidates, return\n"); + return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL; + } +#if SPIFFS_GC_STATS + fs->stats_gc_runs++; +#endif + cand = cands[0]; + fs->cleaning = 1; + //SPIFFS_GC_DBG("gcing: cleaning block "_SPIPRIi"\n", cand); + res = spiffs_gc_clean(fs, cand); + fs->cleaning = 0; + if (res < 0) { + SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res); + } else { + SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res); + } + SPIFFS_CHECK_RES(res); + + res = spiffs_gc_erase_page_stats(fs, cand); + SPIFFS_CHECK_RES(res); + + res = spiffs_gc_erase_block(fs, cand); + SPIFFS_CHECK_RES(res); + + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + + if (prev_free_pages <= 0 && prev_free_pages == free_pages) { + // abort early to reduce wear, at least tried once + SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n"); + break; + } + + } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 || + (s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs))); + + free_pages = + (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2) + - fs->stats_p_allocated - fs->stats_p_deleted; + if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) { + res = SPIFFS_ERR_FULL; + } + + SPIFFS_GC_DBG("gc_check: finished, "_SPIPRIi" dirty, blocks "_SPIPRIi" free, "_SPIPRIi" pages free, "_SPIPRIi" tries, res "_SPIPRIi"\n", + fs->stats_p_allocated + fs->stats_p_deleted, + fs->free_blocks, free_pages, tries, res); + + return res; +} + +// Updates page statistics for a block that is about to be erased +s32_t spiffs_gc_erase_page_stats( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res = SPIFFS_OK; + int obj_lookup_page = 0; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = 0; + u32_t dele = 0; + u32_t allo = 0; + + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + dele++; + } else { + allo++; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + SPIFFS_GC_DBG("gc_check: wipe pallo:"_SPIPRIi" pdele:"_SPIPRIi"\n", allo, dele); + fs->stats_p_allocated -= allo; + fs->stats_p_deleted -= dele; + return res; +} + +// Finds block candidates to erase +s32_t spiffs_gc_find_candidate( + spiffs *fs, + spiffs_block_ix **block_candidates, + int *candidate_count, + char fs_crammed) { + s32_t res = SPIFFS_OK; + u32_t blocks = fs->block_count; + spiffs_block_ix cur_block = 0; + u32_t cur_block_addr = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = 0; + + // using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score + int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t))); + *candidate_count = 0; + memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + + // divide up work area into block indices and scores + spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work; + s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix)); + + // align cand_scores on s32_t boundary + cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1)); + + *block_candidates = cand_blocks; + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // check each block + while (res == SPIFFS_OK && blocks--) { + u16_t deleted_pages_in_block = 0; + u16_t used_pages_in_block = 0; + + int obj_lookup_page = 0; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && + cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + // when a free entry is encountered, scan logic ensures that all following entries are free also + res = 1; // kill object lu loop + break; + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + deleted_pages_in_block++; + } else { + used_pages_in_block++; + } + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + if (res == 1) res = SPIFFS_OK; + + // calculate score and insert into candidate table + // stoneage sort, but probably not so many blocks + if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) { + // read erase count + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, cur_block), + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + + spiffs_obj_id erase_age; + if (fs->max_erase_count > erase_count) { + erase_age = fs->max_erase_count - erase_count; + } else { + erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count); + } + + s32_t score = + deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET + + used_pages_in_block * SPIFFS_GC_HEUR_W_USED + + erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); + int cand_ix = 0; + SPIFFS_GC_DBG("gc_check: bix:"_SPIPRIbl" del:"_SPIPRIi" use:"_SPIPRIi" score:"_SPIPRIi"\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); + while (cand_ix < max_candidates) { + if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { + cand_blocks[cand_ix] = cur_block; + cand_scores[cand_ix] = score; + break; + } else if (cand_scores[cand_ix] < score) { + int reorder_cand_ix = max_candidates - 2; + while (reorder_cand_ix >= cand_ix) { + cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix]; + cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix]; + reorder_cand_ix--; + } + cand_blocks[cand_ix] = cur_block; + cand_scores[cand_ix] = score; + break; + } + cand_ix++; + } + (*candidate_count)++; + } + + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + } // per block + + return res; +} + +typedef enum { + FIND_OBJ_DATA, + MOVE_OBJ_DATA, + MOVE_OBJ_IX, + FINISHED +} spiffs_gc_clean_state; + +typedef struct { + spiffs_gc_clean_state state; + spiffs_obj_id cur_obj_id; + spiffs_span_ix cur_objix_spix; + spiffs_page_ix cur_objix_pix; + spiffs_page_ix cur_data_pix; + int stored_scan_entry_index; + u8_t obj_id_found; +} spiffs_gc; + +// Empties given block by moving all data into free pages of another block +// Strategy: +// loop: +// scan object lookup for object data pages +// for first found id, check spix and load corresponding object index page to memory +// push object scan lookup entry index +// rescan object lookup, find data pages with same id and referenced by same object index +// move data page, update object index in memory +// when reached end of lookup, store updated object index +// pop object scan lookup entry index +// repeat loop until end of object lookup +// scan object lookup again for remaining object index pages, move to new page in other block +// +s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { + s32_t res = SPIFFS_OK; + const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + // this is the global localizer being pushed and popped + int cur_entry = 0; + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_gc gc; // our stack frame/state + spiffs_page_ix cur_pix = 0; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + + SPIFFS_GC_DBG("gc_clean: cleaning block "_SPIPRIbl"\n", bix); + + memset(&gc, 0, sizeof(spiffs_gc)); + gc.state = FIND_OBJ_DATA; + + if (fs->free_cursor_block_ix == bix) { + // move free cursor to next block, cannot use free pages from the block we want to clean + fs->free_cursor_block_ix = (bix+1)%fs->block_count; + fs->free_cursor_obj_lu_entry = 0; + SPIFFS_GC_DBG("gc_clean: move free cursor to block "_SPIPRIbl"\n", fs->free_cursor_block_ix); + } + + while (res == SPIFFS_OK && gc.state != FINISHED) { + SPIFFS_GC_DBG("gc_clean: state = "_SPIPRIi" entry:"_SPIPRIi"\n", gc.state, cur_entry); + gc.obj_id_found = 0; // reset (to no found data page) + + // scan through lookup pages + int obj_lookup_page = cur_entry / entries_per_page; + u8_t scan = 1; + // check each object lookup page + while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each object lookup entry + while (scan && res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry); + + // act upon object id depending on gc state + switch (gc.state) { + case FIND_OBJ_DATA: + // find a data page + if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && + ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) { + // found a data page, stop scanning and handle in switch case below + SPIFFS_GC_DBG("gc_clean: FIND_DATA state:"_SPIPRIi" - found obj id "_SPIPRIid"\n", gc.state, obj_id); + gc.obj_id_found = 1; + gc.cur_obj_id = obj_id; + gc.cur_data_pix = cur_pix; + scan = 0; + } + break; + case MOVE_OBJ_DATA: + // evacuate found data pages for corresponding object index we have in memory, + // update memory representation + if (obj_id == gc.cur_obj_id) { + spiffs_page_header p_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page "_SPIPRIid":"_SPIPRIsp" @ "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); + if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) { + SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n"); + } else { + spiffs_page_ix new_data_pix; + if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { + // move page + res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); + SPIFFS_CHECK_RES(res); + // move wipes obj_lu, reload it + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } else { + // page is deleted but not deleted in lookup, scrap it - + // might seem unnecessary as we will erase this block, but + // we might get aborted + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_page_delete(fs, cur_pix); + SPIFFS_CHECK_RES(res); + new_data_pix = SPIFFS_OBJ_ID_FREE; + } + // update memory representation of object index page with new data page + if (gc.cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix; + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix; + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + } + } + } + break; + case MOVE_OBJ_IX: + // find and evacuate object index pages + if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && + (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) { + // found an index object id + spiffs_page_header p_hdr; + spiffs_page_ix new_pix; + // load header + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { + // move page + res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr, + SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0); + // move wipes obj_lu, reload it + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), + SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } else { + // page is deleted but not deleted in lookup, scrap it - + // might seem unnecessary as we will erase this block, but + // we might get aborted + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix); + res = spiffs_page_delete(fs, cur_pix); + if (res == SPIFFS_OK) { + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0, + SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0); + } + } + SPIFFS_CHECK_RES(res); + } + break; + default: + scan = 0; + break; + } // switch gc state + cur_entry++; + } // per entry + obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop + } // per object lookup page + if (res != SPIFFS_OK) break; + + // state finalization and switch + switch (gc.state) { + case FIND_OBJ_DATA: + if (gc.obj_id_found) { + // handle found data page - + // find out corresponding obj ix page and load it to memory + spiffs_page_header p_hdr; + spiffs_page_ix objix_pix; + gc.stored_scan_entry_index = cur_entry; // push cursor + cur_entry = 0; // restart scan from start + gc.state = MOVE_OBJ_DATA; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); + SPIFFS_CHECK_RES(res); + gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix); + SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:"_SPIPRIsp"\n", gc.cur_objix_spix); + res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix); + if (res == SPIFFS_ERR_NOT_FOUND) { + // on borked systems we might get an ERR_NOT_FOUND here - + // this is handled by simply deleting the page as it is not referenced + // from anywhere + SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page "_SPIPRIpg"\n", gc.cur_data_pix); + res = spiffs_page_delete(fs, gc.cur_data_pix); + SPIFFS_CHECK_RES(res); + // then we restore states and continue scanning for data pages + cur_entry = gc.stored_scan_entry_index; // pop cursor + gc.state = FIND_OBJ_DATA; + break; // done + } + SPIFFS_CHECK_RES(res); + SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page "_SPIPRIpg"\n", objix_pix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + // cannot allow a gc if the presumed index in fact is no index, a + // check must run or lot of data may be lost + SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix); + gc.cur_objix_pix = objix_pix; + } else { + // no more data pages found, passed thru all block, start evacuating object indices + gc.state = MOVE_OBJ_IX; + cur_entry = 0; // restart entry scan index + } + break; + case MOVE_OBJ_DATA: { + // store modified objix (hdr) page residing in memory now that all + // data pages belonging to this object index and residing in the block + // we want to evacuate + spiffs_page_ix new_objix_pix; + gc.state = FIND_OBJ_DATA; + cur_entry = gc.stored_scan_entry_index; // pop cursor + if (gc.cur_objix_spix == 0) { + // store object index header page + res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, 0); + SPIFFS_CHECK_RES(res); + } else { + // store object index page + res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, + SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + } + } + break; + case MOVE_OBJ_IX: + // scanned thru all block, no more object indices found - our work here is done + gc.state = FINISHED; + break; + default: + cur_entry = 0; + break; + } // switch gc.state + SPIFFS_GC_DBG("gc_clean: state-> "_SPIPRIi"\n", gc.state); + } // while state != FINISHED + + + return res; +} + +#endif // !SPIFFS_READ_ONLY diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_hydrogen.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_hydrogen.c new file mode 100755 index 0000000..69e0c22 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_hydrogen.c @@ -0,0 +1,1450 @@ +/* + * spiffs_hydrogen.c + * + * Created on: Jun 16, 2013 + * Author: petera + */ + +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#if SPIFFS_CACHE == 1 +static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh); +#endif + +#if SPIFFS_BUFFER_HELP +u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) { + return num_descs * sizeof(spiffs_fd); +} +#if SPIFFS_CACHE +u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) { + return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)); +} +#endif +#endif + +u8_t SPIFFS_mounted(spiffs *fs) { + return SPIFFS_CHECK_MOUNT(fs); +} + +s32_t SPIFFS_format(spiffs *fs) { +#if SPIFFS_READ_ONLY + (void)fs; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + if (SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_MOUNTED; + return -1; + } + + s32_t res; + SPIFFS_LOCK(fs); + + spiffs_block_ix bix = 0; + while (bix < fs->block_count) { + fs->max_erase_count = 0; + res = spiffs_erase_block(fs, bix); + if (res != SPIFFS_OK) { + res = SPIFFS_ERR_ERASE_FAIL; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + bix++; + } + + SPIFFS_UNLOCK(fs); + + return 0; +#endif // SPIFFS_READ_ONLY +} + +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + +s32_t SPIFFS_probe_fs(spiffs_config *config) { + SPIFFS_API_DBG("%s\n", __func__); + s32_t res = spiffs_probe(config); + return res; +} + +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + +s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, + u8_t *fd_space, u32_t fd_space_size, + void *cache, u32_t cache_size, + spiffs_check_callback check_cb_f) { + SPIFFS_API_DBG("%s " + " sz:"_SPIPRIi " logpgsz:"_SPIPRIi " logblksz:"_SPIPRIi " perasz:"_SPIPRIi + " addr:"_SPIPRIad + " fdsz:"_SPIPRIi " cachesz:"_SPIPRIi + "\n", + __func__, + SPIFFS_CFG_PHYS_SZ(fs), SPIFFS_CFG_LOG_PAGE_SZ(fs), SPIFFS_CFG_LOG_BLOCK_SZ(fs), + SPIFFS_CFG_PHYS_ADDR(fs), + SPIFFS_CFG_PHYS_ERASE_SZ(fs), + fd_space_size, cache_size); + void *user_data; + SPIFFS_LOCK(fs); + user_data = fs->user_data; + memset(fs, 0, sizeof(spiffs)); + _SPIFFS_MEMCPY(&fs->cfg, config, sizeof(spiffs_config)); + fs->user_data = user_data; + fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs); + fs->work = &work[0]; + fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)]; + memset(fd_space, 0, fd_space_size); + // align fd_space pointer to pointer size byte boundary + u8_t ptr_size = sizeof(void*); + u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1); + if (addr_lsb) { + fd_space += (ptr_size-addr_lsb); + fd_space_size -= (ptr_size-addr_lsb); + } + fs->fd_space = fd_space; + fs->fd_count = (fd_space_size/sizeof(spiffs_fd)); + + // align cache pointer to 4 byte boundary + addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1); + if (addr_lsb) { + u8_t *cache_8 = (u8_t *)cache; + cache_8 += (ptr_size-addr_lsb); + cache = cache_8; + cache_size -= (ptr_size-addr_lsb); + } + if (cache_size & (ptr_size-1)) { + cache_size -= (cache_size & (ptr_size-1)); + } + +#if SPIFFS_CACHE + fs->cache = cache; + fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size; + spiffs_cache_init(fs); +#endif + + s32_t res; + +#if SPIFFS_USE_MAGIC + res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + fs->config_magic = SPIFFS_CONFIG_MAGIC; + + res = spiffs_obj_lu_scan(fs); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_DBG("page index byte len: "_SPIPRIi"\n", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)); + SPIFFS_DBG("object lookup pages: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs)); + SPIFFS_DBG("page pages per block: "_SPIPRIi"\n", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs)); + SPIFFS_DBG("page header length: "_SPIPRIi"\n", (u32_t)sizeof(spiffs_page_header)); + SPIFFS_DBG("object header index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs)); + SPIFFS_DBG("object index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_IX_LEN(fs)); + SPIFFS_DBG("available file descriptors: "_SPIPRIi"\n", (u32_t)fs->fd_count); + SPIFFS_DBG("free blocks: "_SPIPRIi"\n", (u32_t)fs->free_blocks); + + fs->check_cb_f = check_cb_f; + + fs->mounted = 1; + + SPIFFS_UNLOCK(fs); + + return 0; +} + +void SPIFFS_unmount(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); + if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return; + SPIFFS_LOCK(fs); + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr != 0) { +#if SPIFFS_CACHE + (void)spiffs_fflush_cache(fs, cur_fd->file_nbr); +#endif + spiffs_fd_return(fs, cur_fd->file_nbr); + } + } + fs->mounted = 0; + + SPIFFS_UNLOCK(fs); +} + +s32_t SPIFFS_errno(spiffs *fs) { + return fs->err_code; +} + +void SPIFFS_clearerr(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); + fs->err_code = SPIFFS_OK; +} + +s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); +#if SPIFFS_READ_ONLY + (void)fs; (void)path; (void)mode; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + (void)mode; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } + SPIFFS_LOCK(fs); + spiffs_obj_id obj_id; + s32_t res; + + res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +#endif // SPIFFS_READ_ONLY +} + +spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s' "_SPIPRIfl "\n", __func__, path, flags); + (void)mode; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + spiffs_page_ix pix; + +#if SPIFFS_READ_ONLY + // not valid flags in read only mode + flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC); +#endif // SPIFFS_READ_ONLY + + s32_t res = spiffs_fd_find_new(fs, &fd, path); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); + if ((flags & SPIFFS_O_CREAT) == 0) { + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if (res == SPIFFS_OK && + (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) { + // creat and excl and file exists - fail + res = SPIFFS_ERR_FILE_EXISTS; + spiffs_fd_return(fs, fd->file_nbr); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) { +#if !SPIFFS_READ_ONLY + spiffs_obj_id obj_id; + // no need to enter conflicting name here, already looked for it above + res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + flags &= ~SPIFFS_O_TRUNC; +#endif // !SPIFFS_READ_ONLY + } else { + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + res = spiffs_object_open_by_page(fs, pix, fd, flags, mode); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } +#endif // !SPIFFS_READ_ONLY + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return SPIFFS_FH_OFFS(fs, fd->file_nbr); +} + +spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s':"_SPIPRIid " "_SPIPRIfl "\n", __func__, e->name, e->obj_id, flags); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + + s32_t res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } +#endif // !SPIFFS_READ_ONLY + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return SPIFFS_FH_OFFS(fs, fd->file_nbr); +} + +spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s "_SPIPRIpg " "_SPIPRIfl "\n", __func__, page_ix, flags); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + + s32_t res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) { + res = SPIFFS_ERR_NOT_A_FILE; + spiffs_fd_return(fs, fd->file_nbr); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode); + if (res == SPIFFS_ERR_IS_FREE || + res == SPIFFS_ERR_DELETED || + res == SPIFFS_ERR_NOT_FINALIZED || + res == SPIFFS_ERR_NOT_INDEX || + res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) { + res = SPIFFS_ERR_NOT_A_FILE; + } + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } +#endif // !SPIFFS_READ_ONLY + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return SPIFFS_FH_OFFS(fs, fd->file_nbr); +} + +static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_O_RDONLY) == 0) { + res = SPIFFS_ERR_NOT_READABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) { + // special case for zero sized files + res = SPIFFS_ERR_END_OF_OBJECT; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + if (fd->fdoffset + len >= fd->size) { + // reading beyond file size + s32_t avail = fd->size - fd->fdoffset; + if (avail <= 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT); + } + res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf); + if (res == SPIFFS_ERR_END_OF_OBJECT) { + fd->fdoffset += avail; + SPIFFS_UNLOCK(fs); + return avail; + } else { + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + len = avail; + } + } else { + // reading within file size + res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + fd->fdoffset += len; + + SPIFFS_UNLOCK(fs); + + return len; +} + +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len); + s32_t res = spiffs_hydro_read(fs, fh, buf, len); + if (res == SPIFFS_ERR_END_OF_OBJECT) { + res = 0; + } + return res; +} + + +#if !SPIFFS_READ_ONLY +static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) { + (void)fs; + s32_t res = SPIFFS_OK; + s32_t remaining = len; + if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) { + s32_t m_len = MIN((s32_t)(fd->size - offset), len); + res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len); + SPIFFS_CHECK_RES(res); + remaining -= m_len; + u8_t *buf_8 = (u8_t *)buf; + buf_8 += m_len; + buf = buf_8; + offset += m_len; + } + if (remaining > 0) { + res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining); + SPIFFS_CHECK_RES(res); + } + return len; + +} +#endif // !SPIFFS_READ_ONLY + +s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len); +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; (void)buf; (void)len; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + u32_t offset; + + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if ((fd->flags & SPIFFS_O_APPEND)) { + fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size; + } + + offset = fd->fdoffset; + +#if SPIFFS_CACHE_WR + if (fd->cache_page == 0) { + // see if object id is associated with cache already + fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); + } +#endif + if (fd->flags & SPIFFS_O_APPEND) { + if (fd->size == SPIFFS_UNDEFINED_LEN) { + offset = 0; + } else { + offset = fd->size; + } +#if SPIFFS_CACHE_WR + if (fd->cache_page) { + offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size); + } +#endif + } + +#if SPIFFS_CACHE_WR + if ((fd->flags & SPIFFS_O_DIRECT) == 0) { + if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { + // small write, try to cache it + u8_t alloc_cpage = 1; + if (fd->cache_page) { + // have a cached page for this fd already, check cache page boundaries + if (offset < fd->cache_page->offset || // writing before cache + offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache + offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page + { + // boundary violation, write back cache first and allocate new + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } else { + // writing within cache + alloc_cpage = 0; + } + } + + if (alloc_cpage) { + fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd); + if (fd->cache_page) { + fd->cache_page->offset = offset; + fd->cache_page->size = 0; + SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid"\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id); + } + } + + if (fd->cache_page) { + u32_t offset_in_cpage = offset - fd->cache_page->offset; + SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, + offset, offset_in_cpage, len); + spiffs_cache *cache = spiffs_get_cache(fs); + u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix); +#ifdef _SPIFFS_TEST + { + intptr_t __a1 = (u8_t*)&cpage_data[offset_in_cpage]-(u8_t*)cache; + intptr_t __a2 = (u8_t*)&cpage_data[offset_in_cpage]+len-(u8_t*)cache; + intptr_t __b = sizeof(spiffs_cache) + cache->cpage_count * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)); + if (__a1 > __b || __a2 > __b) { + printf("FATAL OOB: CACHE_WR: memcpy to cache buffer ixs:%4ld..%4ld of %4ld\n", __a1, __a2, __b); + ERREXIT(); + } + } +#endif + _SPIFFS_MEMCPY(&cpage_data[offset_in_cpage], buf, len); + fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len); + fd->fdoffset += len; + SPIFFS_UNLOCK(fs); + return len; + } else { + res = spiffs_hydro_write(fs, fd, buf, offset, len); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + fd->fdoffset += len; + SPIFFS_UNLOCK(fs); + return res; + } + } else { + // big write, no need to cache it - but first check if there is a cached write already + if (fd->cache_page) { + // write back cache first + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + spiffs_cache_fd_release(fs, fd->cache_page); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + // data written below + } + } + } +#endif + + res = spiffs_hydro_write(fs, fd, buf, offset, len); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + fd->fdoffset += len; + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " %s\n", __func__, fh, offs, (const char* []){"SET","CUR","END","???"}[MIN(whence,3)]); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + s32_t file_size = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size; + + switch (whence) { + case SPIFFS_SEEK_CUR: + offs = fd->fdoffset+offs; + break; + case SPIFFS_SEEK_END: + offs = file_size + offs; + break; + } + if (offs < 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_SEEK_BOUNDS); + } + if (offs > file_size) { + fd->fdoffset = file_size; + res = SPIFFS_ERR_END_OF_OBJECT; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + spiffs_span_ix data_spix = (offs > 0 ? (offs-1) : 0) / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (fd->cursor_objix_spix != objix_spix) { + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span( + fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + fd->cursor_objix_spix = objix_spix; + fd->cursor_objix_pix = pix; + } + fd->fdoffset = offs; + + SPIFFS_UNLOCK(fs); + + return offs; +} + +s32_t SPIFFS_remove(spiffs *fs, const char *path) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); +#if SPIFFS_READ_ONLY + (void)fs; (void)path; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + spiffs_page_ix pix; + s32_t res; + + res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix, fd, 0,0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_truncate(fd, 0, 1); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + return 0; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + +#if SPIFFS_CACHE_WR + spiffs_cache_fd_release(fs, fd->cache_page); +#endif + + res = spiffs_object_truncate(fd, 0, 1); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return 0; +#endif // SPIFFS_READ_ONLY +} + +static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) { + (void)fh; + spiffs_page_object_ix_header objix_hdr; + spiffs_obj_id obj_id; + s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh, + SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_API_CHECK_RES(fs, res); + + u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) + + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id); + res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh, + obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id); + SPIFFS_API_CHECK_RES(fs, res); + + s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + s->type = objix_hdr.type; + s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + s->pix = pix; + strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); +#if SPIFFS_OBJ_META_LEN + _SPIFFS_MEMCPY(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN); +#endif + + return res; +} + +s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } + SPIFFS_LOCK(fs); + + s32_t res; + spiffs_page_ix pix; + + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_stat_pix(fs, pix, 0, s); + + SPIFFS_UNLOCK(fs); + + return res; +} + +s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + s32_t res; + + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + spiffs_fflush_cache(fs, fh); +#endif + + res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s); + + SPIFFS_UNLOCK(fs); + + return res; +} + +// Checks if there are any cached writes for the object id associated with +// given filehandle. If so, these writes are flushed. +#if SPIFFS_CACHE == 1 +static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { + (void)fs; + (void)fh; + s32_t res = SPIFFS_OK; +#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES(fs, res); + + if ((fd->flags & SPIFFS_O_DIRECT) == 0) { + if (fd->cache_page == 0) { + // see if object id is associated with cache already + fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); + } + if (fd->cache_page) { + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n", + fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); + res = spiffs_hydro_write(fs, fd, + spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), + fd->cache_page->offset, fd->cache_page->size); + if (res < SPIFFS_OK) { + fs->err_code = res; + } + spiffs_cache_fd_release(fs, fd->cache_page); + } + } +#endif + + return res; +} +#endif + +s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + (void)fh; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + s32_t res = SPIFFS_OK; +#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR + SPIFFS_LOCK(fs); + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs,res); + SPIFFS_UNLOCK(fs); +#endif + + return res; +} + +s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + + s32_t res = SPIFFS_OK; + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); +#if SPIFFS_CACHE + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + res = spiffs_fd_return(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +} + +s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) { + SPIFFS_API_DBG("%s %s %s\n", __func__, old_path, new_path); +#if SPIFFS_READ_ONLY + (void)fs; (void)old_path; (void)new_path; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 || + strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } + SPIFFS_LOCK(fs); + + spiffs_page_ix pix_old, pix_dummy; + spiffs_fd *fd; + + s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy); + if (res == SPIFFS_ERR_NOT_FOUND) { + res = SPIFFS_OK; + } else if (res == SPIFFS_OK) { + res = SPIFFS_ERR_CONFLICTING_NAME; + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path, + 0, 0, &pix_dummy); +#if SPIFFS_TEMPORAL_FD_CACHE + if (res == SPIFFS_OK) { + spiffs_fd_temporal_cache_rehash(fs, old_path, new_path); + } +#endif + + spiffs_fd_return(fs, fd->file_nbr); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} + +#if SPIFFS_OBJ_META_LEN +s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) { +#if SPIFFS_READ_ONLY + (void)fs; (void)name; (void)meta; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_page_ix pix, pix_dummy; + spiffs_fd *fd; + + s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix, fd, 0, 0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta, + 0, &pix_dummy); + + spiffs_fd_return(fs, fd->file_nbr); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) { +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; (void)meta; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + s32_t res; + spiffs_fd *fd; + spiffs_page_ix pix_dummy; + + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta, + 0, &pix_dummy); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} +#endif // SPIFFS_OBJ_META_LEN + +spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) { + SPIFFS_API_DBG("%s\n", __func__); + (void)name; + + if (!SPIFFS_CHECK_CFG((fs))) { + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; + return 0; + } + + if (!SPIFFS_CHECK_MOUNT(fs)) { + fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return 0; + } + + d->fs = fs; + d->block = 0; + d->entry = 0; + return d; +} + +static s32_t spiffs_read_dir_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + const void *user_const_p, + void *user_var_p) { + (void)user_const_p; + s32_t res; + spiffs_page_object_ix_header objix_hdr; + if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED || + (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) { + return SPIFFS_VIS_COUNTINUE; + } + + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + if (res != SPIFFS_OK) return res; + if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && + objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p; + e->obj_id = obj_id; + strcpy((char *)e->name, (char *)objix_hdr.name); + e->type = objix_hdr.type; + e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + e->pix = pix; +#if SPIFFS_OBJ_META_LEN + _SPIFFS_MEMCPY(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN); +#endif + return SPIFFS_OK; + } + return SPIFFS_VIS_COUNTINUE; +} + +struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { + SPIFFS_API_DBG("%s\n", __func__); + if (!SPIFFS_CHECK_MOUNT(d->fs)) { + d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; + return 0; + } + SPIFFS_LOCK(d->fs); + + spiffs_block_ix bix; + int entry; + s32_t res; + struct spiffs_dirent *ret = 0; + + res = spiffs_obj_lu_find_entry_visitor(d->fs, + d->block, + d->entry, + SPIFFS_VIS_NO_WRAP, + 0, + spiffs_read_dir_v, + 0, + e, + &bix, + &entry); + if (res == SPIFFS_OK) { + d->block = bix; + d->entry = entry + 1; + e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + ret = e; + } else { + d->fs->err_code = res; + } + SPIFFS_UNLOCK(d->fs); + return ret; +} + +s32_t SPIFFS_closedir(spiffs_DIR *d) { + SPIFFS_API_DBG("%s\n", __func__); + SPIFFS_API_CHECK_CFG(d->fs); + SPIFFS_API_CHECK_MOUNT(d->fs); + return 0; +} + +s32_t SPIFFS_check(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); +#if SPIFFS_READ_ONLY + (void)fs; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_lookup_consistency_check(fs, 0); + + res = spiffs_object_index_consistency_check(fs); + + res = spiffs_page_consistency_check(fs); + + res = spiffs_obj_lu_scan(fs); + + SPIFFS_UNLOCK(fs); + return res; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { + SPIFFS_API_DBG("%s\n", __func__); + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs); + u32_t blocks = fs->block_count; + u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs); + u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs); + u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page + + if (total) { + *total = total_data_pages * data_page_size; + } + + if (used) { + *used = fs->stats_p_allocated * data_page_size; + } + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { + SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, max_free_pages); +#if SPIFFS_READ_ONLY + (void)fs; (void)max_free_pages; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_gc_quick(fs, max_free_pages); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +#endif // SPIFFS_READ_ONLY +} + + +s32_t SPIFFS_gc(spiffs *fs, u32_t size) { + SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, size); +#if SPIFFS_READ_ONLY + (void)fs; (void)size; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + res = spiffs_gc_check(fs, size); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + SPIFFS_UNLOCK(fs); + return 0; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size)); + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + res = fd->fdoffset; + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) { + SPIFFS_API_DBG("%s\n", __func__); + SPIFFS_LOCK(fs); + fs->file_cb_f = cb_func; + SPIFFS_UNLOCK(fs); + return 0; +} + +#if SPIFFS_IX_MAP + +s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map, + u32_t offset, u32_t len, spiffs_page_ix *map_buf) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " "_SPIPRIi "\n", __func__, fh, offset, len); + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if (fd->ix_map) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED); + } + + map->map_buf = map_buf; + map->offset = offset; + // nb: spix range includes last + map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs); + memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1)); + fd->ix_map = map; + + // scan for pixes + res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if (fd->ix_map == 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED); + } + + fd->ix_map = 0; + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, offset); + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if (fd->ix_map == 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED); + } + + spiffs_ix_map *map = fd->ix_map; + + s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix; + map->offset = offset; + + // move existing pixes if within map offs + if (spix_diff != 0) { + // move vector + int i; + const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last + map->start_spix += spix_diff; + map->end_spix += spix_diff; + if (spix_diff >= vec_len) { + // moving beyond range + memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix)); + // populate_ix_map is inclusive + res = spiffs_populate_ix_map(fs, fd, 0, vec_len-1); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } else if (spix_diff > 0) { + // diff positive + for (i = 0; i < vec_len - spix_diff; i++) { + map->map_buf[i] = map->map_buf[i + spix_diff]; + } + // memset is non-inclusive + memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix)); + // populate_ix_map is inclusive + res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len-1); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } else { + // diff negative + for (i = vec_len - 1; i >= -spix_diff; i--) { + map->map_buf[i] = map->map_buf[i + spix_diff]; + } + // memset is non-inclusive + memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix)); + // populate_ix_map is inclusive + res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + } + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) { + SPIFFS_API_CHECK_CFG(fs); + // always add one extra page, the offset might change to the middle of a page + return (bytes + SPIFFS_DATA_PAGE_SIZE(fs) ) / SPIFFS_DATA_PAGE_SIZE(fs); +} + +s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) { + SPIFFS_API_CHECK_CFG(fs); + return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs); +} + +#endif // SPIFFS_IX_MAP + +#if SPIFFS_TEST_VISUALISATION +s32_t SPIFFS_vis(spiffs *fs) { + s32_t res = SPIFFS_OK; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_block_ix bix = 0; + + while (bix < fs->block_count) { + // check each object lookup page + int obj_lookup_page = 0; + int cur_entry = 0; + + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { + spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; + if (cur_entry == 0) { + spiffs_printf(_SPIPRIbl" ", bix); + } else if ((cur_entry & 0x3f) == 0) { + spiffs_printf(" "); + } + if (obj_id == SPIFFS_OBJ_ID_FREE) { + spiffs_printf(SPIFFS_TEST_VIS_FREE_STR); + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + spiffs_printf(SPIFFS_TEST_VIS_DELE_STR); + } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){ + spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id)); + } else { + spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id)); + } + cur_entry++; + if ((cur_entry & 0x3f) == 0) { + spiffs_printf("\n"); + } + } // per entry + obj_lookup_page++; + } // per object lookup page + + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + + if (erase_count != (spiffs_obj_id)-1) { + spiffs_printf("\tera_cnt: "_SPIPRIi"\n", erase_count); + } else { + spiffs_printf("\tera_cnt: N/A\n"); + } + + bix++; + } // per block + + spiffs_printf("era_cnt_max: "_SPIPRIi"\n", fs->max_erase_count); + spiffs_printf("last_errno: "_SPIPRIi"\n", fs->err_code); + spiffs_printf("blocks: "_SPIPRIi"\n", fs->block_count); + spiffs_printf("free_blocks: "_SPIPRIi"\n", fs->free_blocks); + spiffs_printf("page_alloc: "_SPIPRIi"\n", fs->stats_p_allocated); + spiffs_printf("page_delet: "_SPIPRIi"\n", fs->stats_p_deleted); + SPIFFS_UNLOCK(fs); + u32_t total, used; + SPIFFS_info(fs, &total, &used); + spiffs_printf("used: "_SPIPRIi" of "_SPIPRIi"\n", used, total); + return res; +} +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.c new file mode 100755 index 0000000..12c9de8 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.c @@ -0,0 +1,2350 @@ +#include "spiffs.h" +#include "spiffs_nucleus.h" + +static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { + s32_t res = SPIFFS_OK; + if (pix == (spiffs_page_ix)-1) { + // referring to page 0xffff...., bad object index + return SPIFFS_ERR_INDEX_REF_FREE; + } + if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // referring to an object lookup page, bad object index + return SPIFFS_ERR_INDEX_REF_LU; + } + if (pix > SPIFFS_MAX_PAGES(fs)) { + // referring to a bad page + return SPIFFS_ERR_INDEX_REF_INVALID; + } +#if SPIFFS_PAGE_CHECK + spiffs_page_header ph; + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, pix), + sizeof(spiffs_page_header), + (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix); +#endif + return res; +} + +#if !SPIFFS_READ_ONLY +static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { + s32_t res = SPIFFS_OK; + if (pix == (spiffs_page_ix)-1) { + // referring to page 0xffff...., bad object index + return SPIFFS_ERR_INDEX_FREE; + } + if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // referring to an object lookup page, bad object index + return SPIFFS_ERR_INDEX_LU; + } + if (pix > SPIFFS_MAX_PAGES(fs)) { + // referring to a bad page + return SPIFFS_ERR_INDEX_INVALID; + } +#if SPIFFS_PAGE_CHECK + spiffs_page_header ph; + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, pix), + sizeof(spiffs_page_header), + (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix); +#endif + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_CACHE + +s32_t spiffs_phys_rd( + spiffs *fs, + u32_t addr, + u32_t len, + u8_t *dst) { + return SPIFFS_HAL_READ(fs, addr, len, dst); +} + +s32_t spiffs_phys_wr( + spiffs *fs, + u32_t addr, + u32_t len, + u8_t *src) { + return SPIFFS_HAL_WRITE(fs, addr, len, src); +} + +#endif + +#if !SPIFFS_READ_ONLY +s32_t spiffs_phys_cpy( + spiffs *fs, + spiffs_file fh, + u32_t dst, + u32_t src, + u32_t len) { + (void)fh; + s32_t res; + u8_t b[SPIFFS_COPY_BUFFER_STACK]; + while (len > 0) { + u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD, fh, dst, chunk_size, b); + SPIFFS_CHECK_RES(res); + len -= chunk_size; + src += chunk_size; + dst += chunk_size; + } + return SPIFFS_OK; +} +#endif // !SPIFFS_READ_ONLY + +// Find object lookup entry containing given id with visitor. +// Iterate over object lookup pages in each block until a given object id entry is found. +// When found, the visitor function is called with block index, entry index and user data. +// If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be +// ended and visitor's return code is returned to caller. +// If no visitor is given (0) the search returns on first entry with matching object id. +// If no match is found in all look up, SPIFFS_VIS_END is returned. +// @param fs the file system +// @param starting_block the starting block to start search in +// @param starting_lu_entry the look up index entry to start search in +// @param flags ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH, +// SPIFFS_VIS_NO_WRAP +// @param obj_id argument object id +// @param v visitor callback function +// @param user_const_p any const pointer, passed to the callback visitor function +// @param user_var_p any pointer, passed to the callback visitor function +// @param block_ix reported block index where match was found +// @param lu_entry reported look up index where match was found +s32_t spiffs_obj_lu_find_entry_visitor( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + u8_t flags, + spiffs_obj_id obj_id, + spiffs_visitor_f v, + const void *user_const_p, + void *user_var_p, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res = SPIFFS_OK; + s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs); + spiffs_block_ix cur_block = starting_block; + u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + int cur_entry = starting_lu_entry; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + + // wrap initial + if (cur_entry > (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) { + cur_entry = 0; + cur_block++; + cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs); + if (cur_block >= fs->block_count) { + if (flags & SPIFFS_VIS_NO_WRAP) { + return SPIFFS_VIS_END; + } else { + // block wrap + cur_block = 0; + cur_block_addr = 0; + } + } + } + + // check each block + while (res == SPIFFS_OK && entry_count > 0) { + int obj_lookup_page = cur_entry / entries_per_page; + // check each object lookup page + while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + int entry_offset = obj_lookup_page * entries_per_page; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + // check each entry + while (res == SPIFFS_OK && + cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages + cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page + { + if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry-entry_offset] == obj_id) { + if (block_ix) *block_ix = cur_block; + if (lu_entry) *lu_entry = cur_entry; + if (v) { + res = v( + fs, + (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset], + cur_block, + cur_entry, + user_const_p, + user_var_p); + if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) { + if (res == SPIFFS_VIS_COUNTINUE_RELOAD) { + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work); + SPIFFS_CHECK_RES(res); + } + res = SPIFFS_OK; + cur_entry++; + entry_count--; + continue; + } else { + return res; + } + } else { + return SPIFFS_OK; + } + } + entry_count--; + cur_entry++; + } // per entry + obj_lookup_page++; + } // per object lookup page + cur_entry = 0; + cur_block++; + cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs); + if (cur_block >= fs->block_count) { + if (flags & SPIFFS_VIS_NO_WRAP) { + return SPIFFS_VIS_END; + } else { + // block wrap + cur_block = 0; + cur_block_addr = 0; + } + } + } // per block + + SPIFFS_CHECK_RES(res); + + return SPIFFS_VIS_END; +} + +#if !SPIFFS_READ_ONLY +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix) { + s32_t res; + u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix); + s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs); + + // here we ignore res, just try erasing the block + while (size > 0) { + SPIFFS_DBG("erase "_SPIPRIad":"_SPIPRIi"\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + + addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); + size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); + } + fs->free_blocks++; + + // register erase count for this block + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count); + SPIFFS_CHECK_RES(res); + +#if SPIFFS_USE_MAGIC + // finally, write magic + spiffs_obj_id magic = SPIFFS_MAGIC(fs, bix); + res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_MAGIC_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&magic); + SPIFFS_CHECK_RES(res); +#endif + + fs->max_erase_count++; + if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) { + fs->max_erase_count = 0; + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 +s32_t spiffs_probe( + spiffs_config *cfg) { + s32_t res; + u32_t paddr; + spiffs dummy_fs; // create a dummy fs struct just to be able to use macros + _SPIFFS_MEMCPY(&dummy_fs.cfg, cfg, sizeof(spiffs_config)); + dummy_fs.block_count = 0; + + // Read three magics, as one block may be in an aborted erase state. + // At least two of these must contain magic and be in decreasing order. + spiffs_obj_id magic[3]; + spiffs_obj_id bix_count[3]; + + spiffs_block_ix bix; + for (bix = 0; bix < 3; bix++) { + paddr = SPIFFS_MAGIC_PADDR(&dummy_fs, bix); +#if SPIFFS_HAL_CALLBACK_EXTRA + // not any proper fs to report here, so callback with null + // (cross fingers that no-one gets angry) + res = cfg->hal_read_f((void *)0, paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]); +#else + res = cfg->hal_read_f(paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]); +#endif + bix_count[bix] = magic[bix] ^ SPIFFS_MAGIC(&dummy_fs, 0); + SPIFFS_CHECK_RES(res); + } + + // check that we have sane number of blocks + if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS; + // check that the order is correct, take aborted erases in calculation + // first block aborted erase + if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) { + return (bix_count[1]+1) * cfg->log_block_size; + } + // second block aborted erase + if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) { + return bix_count[0] * cfg->log_block_size; + } + // third block aborted erase + if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) { + return bix_count[0] * cfg->log_block_size; + } + // no block has aborted erase + if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) { + return bix_count[0] * cfg->log_block_size; + } + + return SPIFFS_ERR_PROBE_NOT_A_FS; +} +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + + +static s32_t spiffs_obj_lu_scan_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + const void *user_const_p, + void *user_var_p) { + (void)bix; + (void)user_const_p; + (void)user_var_p; + if (obj_id == SPIFFS_OBJ_ID_FREE) { + if (ix_entry == 0) { + fs->free_blocks++; + // todo optimize further, return SPIFFS_NEXT_BLOCK + } + } else if (obj_id == SPIFFS_OBJ_ID_DELETED) { + fs->stats_p_deleted++; + } else { + fs->stats_p_allocated++; + } + + return SPIFFS_VIS_COUNTINUE; +} + + +// Scans thru all obj lu and counts free, deleted and used pages +// Find the maximum block erase count +// Checks magic if enabled +s32_t spiffs_obj_lu_scan( + spiffs *fs) { + s32_t res; + spiffs_block_ix bix; + int entry; +#if SPIFFS_USE_MAGIC + spiffs_block_ix unerased_bix = (spiffs_block_ix)-1; +#endif + + // find out erase count + // if enabled, check magic + bix = 0; + spiffs_obj_id erase_count_final; + spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE; + spiffs_obj_id erase_count_max = 0; + while (bix < fs->block_count) { +#if SPIFFS_USE_MAGIC + spiffs_obj_id magic; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_MAGIC_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&magic); + + SPIFFS_CHECK_RES(res); + if (magic != SPIFFS_MAGIC(fs, bix)) { + if (unerased_bix == (spiffs_block_ix)-1) { + // allow one unerased block as it might be powered down during an erase + unerased_bix = bix; + } else { + // more than one unerased block, bail out + SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS); + } + } +#endif + spiffs_obj_id erase_count; + res = _spiffs_rd(fs, + SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) , + sizeof(spiffs_obj_id), (u8_t *)&erase_count); + SPIFFS_CHECK_RES(res); + if (erase_count != SPIFFS_OBJ_ID_FREE) { + erase_count_min = MIN(erase_count_min, erase_count); + erase_count_max = MAX(erase_count_max, erase_count); + } + bix++; + } + + if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) { + // clean system, set counter to zero + erase_count_final = 0; + } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) { + // wrap, take min + erase_count_final = erase_count_min+1; + } else { + erase_count_final = erase_count_max+1; + } + + fs->max_erase_count = erase_count_final; + +#if SPIFFS_USE_MAGIC + if (unerased_bix != (spiffs_block_ix)-1) { + // found one unerased block, remedy + SPIFFS_DBG("mount: erase block "_SPIPRIbl"\n", bix); +#if SPIFFS_READ_ONLY + res = SPIFFS_ERR_RO_ABORTED_OPERATION; +#else + res = spiffs_erase_block(fs, unerased_bix); +#endif // SPIFFS_READ_ONLY + SPIFFS_CHECK_RES(res); + } +#endif + + // count blocks + + fs->free_blocks = 0; + fs->stats_p_allocated = 0; + fs->stats_p_deleted = 0; + + res = spiffs_obj_lu_find_entry_visitor(fs, + 0, + 0, + 0, + 0, + spiffs_obj_lu_scan_v, + 0, + 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + SPIFFS_CHECK_RES(res); + + return res; +} + +#if !SPIFFS_READ_ONLY +// Find free object lookup entry +// Iterate over object lookup pages in each block until a free object id entry is found +s32_t spiffs_obj_lu_find_free( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res; + if (!fs->cleaning && fs->free_blocks < 2) { + res = spiffs_gc_quick(fs, 0); + if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) { + res = SPIFFS_OK; + } + SPIFFS_CHECK_RES(res); + if (fs->free_blocks < 2) { + return SPIFFS_ERR_FULL; + } + } + res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry, + SPIFFS_OBJ_ID_FREE, block_ix, lu_entry); + if (res == SPIFFS_OK) { + fs->free_cursor_block_ix = *block_ix; + fs->free_cursor_obj_lu_entry = (*lu_entry) + 1; + if (*lu_entry == 0) { + fs->free_blocks--; + } + } + if (res == SPIFFS_ERR_FULL) { + SPIFFS_DBG("fs full\n"); + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +// Find object lookup entry containing given id +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_obj_id obj_id, + spiffs_block_ix *block_ix, + int *lu_entry) { + s32_t res = spiffs_obj_lu_find_entry_visitor( + fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry); + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + return res; +} + + +static s32_t spiffs_obj_lu_find_id_and_span_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + const void *user_const_p, + void *user_var_p) { + s32_t res; + spiffs_page_header ph; + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph); + SPIFFS_CHECK_RES(res); + if (ph.obj_id == obj_id && + ph.span_ix == *((spiffs_span_ix*)user_var_p) && + (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET && + !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) && + (user_const_p == 0 || *((const spiffs_page_ix*)user_const_p) != pix)) { + return SPIFFS_OK; + } else { + return SPIFFS_VIS_COUNTINUE; + } +} + +// Find object lookup entry containing given id and span index +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id_and_span( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + SPIFFS_VIS_CHECK_ID, + obj_id, + spiffs_obj_lu_find_id_and_span_v, + exclusion_pix ? &exclusion_pix : 0, + &spix, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +// Find object lookup entry containing given id and span index in page headers only +// Iterate over object lookup pages in each block until a given object id entry is found +s32_t spiffs_obj_lu_find_id_and_span_by_phdr( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + SPIFFS_VIS_CHECK_PH, + obj_id, + spiffs_obj_lu_find_id_and_span_v, + exclusion_pix ? &exclusion_pix : 0, + &spix, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +#if SPIFFS_IX_MAP + +// update index map of given fd with given object index data +static void spiffs_update_ix_map(spiffs *fs, + spiffs_fd *fd, spiffs_span_ix objix_spix, spiffs_page_object_ix *objix) { +#if SPIFFS_SINGLETON + (void)fs; +#endif + spiffs_ix_map *map = fd->ix_map; + spiffs_span_ix map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix); + spiffs_span_ix map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->end_spix); + + // check if updated ix is within map range + if (objix_spix < map_objix_start_spix || objix_spix > map_objix_end_spix) { + return; + } + + // update memory mapped page index buffer to new pages + + // get range of updated object index map data span indices + spiffs_span_ix objix_data_spix_start = + SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, objix_spix); + spiffs_span_ix objix_data_spix_end = objix_data_spix_start + + (objix_spix == 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs) : SPIFFS_OBJ_IX_LEN(fs)); + + // calc union of object index range and index map range array + spiffs_span_ix map_spix = MAX(map->start_spix, objix_data_spix_start); + spiffs_span_ix map_spix_end = MIN(map->end_spix + 1, objix_data_spix_end); + + while (map_spix < map_spix_end) { + spiffs_page_ix objix_data_pix; + if (objix_spix == 0) { + // get data page from object index header page + objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix_header)))[map_spix]; + } else { + // get data page from object index page + objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, map_spix)]; + } + + if (objix_data_pix == (spiffs_page_ix)-1) { + // reached end of object, abort + break; + } + + map->map_buf[map_spix - map->start_spix] = objix_data_pix; + SPIFFS_DBG("map "_SPIPRIid":"_SPIPRIsp" ("_SPIPRIsp"--"_SPIPRIsp") objix.spix:"_SPIPRIsp" to pix "_SPIPRIpg"\n", + fd->obj_id, map_spix - map->start_spix, + map->start_spix, map->end_spix, + objix->p_hdr.span_ix, + objix_data_pix); + + map_spix++; + } +} + +typedef struct { + spiffs_fd *fd; + u32_t remaining_objix_pages_to_visit; + spiffs_span_ix map_objix_start_spix; + spiffs_span_ix map_objix_end_spix; +} spiffs_ix_map_populate_state; + +static s32_t spiffs_populate_ix_map_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + const void *user_const_p, + void *user_var_p) { + (void)user_const_p; + s32_t res; + spiffs_ix_map_populate_state *state = (spiffs_ix_map_populate_state *)user_var_p; + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + + // load header to check it + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix), (u8_t *)objix); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix->p_hdr, obj_id, objix->p_hdr.span_ix); + + // check if hdr is ok, and if objix range overlap with ix map range + if ((objix->p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE) && + objix->p_hdr.span_ix >= state->map_objix_start_spix && + objix->p_hdr.span_ix <= state->map_objix_end_spix) { + // ok, load rest of object index + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix) + sizeof(spiffs_page_object_ix), + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix), + (u8_t *)objix + sizeof(spiffs_page_object_ix)); + SPIFFS_CHECK_RES(res); + + spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix); + + state->remaining_objix_pages_to_visit--; + SPIFFS_DBG("map "_SPIPRIid" ("_SPIPRIsp"--"_SPIPRIsp") remaining objix pages "_SPIPRIi"\n", + state->fd->obj_id, + state->fd->ix_map->start_spix, state->fd->ix_map->end_spix, + state->remaining_objix_pages_to_visit); + } + + if (res == SPIFFS_OK) { + res = state->remaining_objix_pages_to_visit ? SPIFFS_VIS_COUNTINUE : SPIFFS_VIS_END; + } + return res; +} + +// populates index map, from vector entry start to vector entry end, inclusive +s32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u32_t vec_entry_end) { + s32_t res; + spiffs_ix_map *map = fd->ix_map; + spiffs_ix_map_populate_state state; + vec_entry_start = MIN((u32_t)(map->end_spix - map->start_spix), vec_entry_start); + vec_entry_end = MAX((u32_t)(map->end_spix - map->start_spix), vec_entry_end); + if (vec_entry_start > vec_entry_end) { + return SPIFFS_ERR_IX_MAP_BAD_RANGE; + } + state.map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_start); + state.map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_end); + state.remaining_objix_pages_to_visit = + state.map_objix_end_spix - state.map_objix_start_spix + 1; + state.fd = fd; + + res = spiffs_obj_lu_find_entry_visitor( + fs, + SPIFFS_BLOCK_FOR_PAGE(fs, fd->objix_hdr_pix), + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, fd->objix_hdr_pix), + SPIFFS_VIS_CHECK_ID, + fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, + spiffs_populate_ix_map_v, + 0, + &state, + 0, + 0); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_OK; + } + + return res; +} + +#endif + + +#if !SPIFFS_READ_ONLY +// Allocates a free defined page with given obj_id +// Occupies object lookup entry and page +// data may be NULL; where only page header is stored, len and page_offs is ignored +s32_t spiffs_page_allocate_data( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_page_header *ph, + u8_t *data, + u32_t len, + u32_t page_offs, + u8_t finalize, + spiffs_page_ix *pix) { + s32_t res = SPIFFS_OK; + spiffs_block_ix bix; + int entry; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + + // occupy page in object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + // write page header + ph->flags &= ~SPIFFS_PH_FLAG_USED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph); + SPIFFS_CHECK_RES(res); + + // write page data + if (data) { + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data); + SPIFFS_CHECK_RES(res); + } + + // finalize header if necessary + if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) { + ph->flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&ph->flags); + SPIFFS_CHECK_RES(res); + } + + // return written page + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_READ_ONLY +// Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page. +// If page data is null, provided header is used for metainfo and page data is physically copied. +s32_t spiffs_page_move( + spiffs *fs, + spiffs_file fh, + u8_t *page_data, + spiffs_obj_id obj_id, + spiffs_page_header *page_hdr, + spiffs_page_ix src_pix, + spiffs_page_ix *dst_pix) { + s32_t res; + u8_t was_final = 0; + spiffs_page_header *p_hdr; + spiffs_block_ix bix; + int entry; + spiffs_page_ix free_pix; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + + if (dst_pix) *dst_pix = free_pix; + + p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr; + if (page_data) { + // got page data + was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0; + // write unfinalized page + p_hdr->flags |= SPIFFS_PH_FLAG_FINAL; + p_hdr->flags &= ~SPIFFS_PH_FLAG_USED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data); + } else { + // copy page data + res = spiffs_phys_cpy(fs, fh, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_PAGE_TO_PADDR(fs, src_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs)); + } + SPIFFS_CHECK_RES(res); + + // mark entry in destination object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + if (was_final) { + // mark finalized in destination page + p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fh, + SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr->flags); + SPIFFS_CHECK_RES(res); + } + // mark source deleted + res = spiffs_page_delete(fs, src_pix); + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_READ_ONLY +// Deletes a page and removes it from object lookup. +s32_t spiffs_page_delete( + spiffs *fs, + spiffs_page_ix pix) { + s32_t res; + spiffs_page_header hdr; + hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED); + // mark deleted entry in source object lookup + spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE, + 0, + SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix), + sizeof(spiffs_obj_id), + (u8_t *)&d_obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_deleted++; + fs->stats_p_allocated--; + + // mark deleted in source page + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE, + 0, + SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&hdr.flags); + + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_READ_ONLY +// Create an object index header page with empty index and undefined length +s32_t spiffs_object_create( + spiffs *fs, + spiffs_obj_id obj_id, + const u8_t name[], + const u8_t meta[], + spiffs_obj_type type, + spiffs_page_ix *objix_hdr_pix) { + s32_t res = SPIFFS_OK; + spiffs_block_ix bix; + spiffs_page_object_ix_header oix_hdr; + int entry; + + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + // find free entry + res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("create: found free page @ "_SPIPRIpg" bix:"_SPIPRIbl" entry:"_SPIPRIsp"\n", (spiffs_page_ix)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry); + + // occupy page in object lookup + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id); + SPIFFS_CHECK_RES(res); + + fs->stats_p_allocated++; + + // write empty object index page + oix_hdr.p_hdr.obj_id = obj_id; + oix_hdr.p_hdr.span_ix = 0; + oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED); + oix_hdr.type = type; + oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page + strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN); +#if SPIFFS_OBJ_META_LEN + if (meta) { + _SPIFFS_MEMCPY(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN); + } else { + memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN); + } +#else + (void) meta; +#endif + + // update page + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr); + + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&oix_hdr, + SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN); + + if (objix_hdr_pix) { + *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_READ_ONLY +// update object index header with any combination of name/size/index +// new_objix_hdr_data may be null, if so the object index header page is loaded +// name may be null, if so name is not changed +// size may be null, if so size is not changed +s32_t spiffs_object_update_index_hdr( + spiffs *fs, + spiffs_fd *fd, + spiffs_obj_id obj_id, + spiffs_page_ix objix_hdr_pix, + u8_t *new_objix_hdr_data, + const u8_t name[], + const u8_t meta[], + u32_t size, + spiffs_page_ix *new_pix) { + s32_t res = SPIFFS_OK; + spiffs_page_object_ix_header *objix_hdr; + spiffs_page_ix new_objix_hdr_pix; + + obj_id |= SPIFFS_OBJ_ID_IX_FLAG; + + if (new_objix_hdr_data) { + // object index header page already given to us, no need to load it + objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data; + } else { + // read object index header page + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + objix_hdr = (spiffs_page_object_ix_header *)fs->work; + } + + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0); + + // change name + if (name) { + strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN); + } +#if SPIFFS_OBJ_META_LEN + if (meta) { + _SPIFFS_MEMCPY(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN); + } +#else + (void) meta; +#endif + if (size) { + objix_hdr->size = size; + } + + // move and update page + res = spiffs_page_move(fs, fd == 0 ? 0 : fd->file_nbr, (u8_t*)objix_hdr, obj_id, 0, objix_hdr_pix, &new_objix_hdr_pix); + + if (res == SPIFFS_OK) { + if (new_pix) { + *new_pix = new_objix_hdr_pix; + } + // callback on object index update + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr, + new_objix_hdr_data ? SPIFFS_EV_IX_UPD : SPIFFS_EV_IX_UPD_HDR, + obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size); + if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +void spiffs_cb_object_event( + spiffs *fs, + spiffs_page_object_ix *objix, + int ev, + spiffs_obj_id obj_id_raw, + spiffs_span_ix spix, + spiffs_page_ix new_pix, + u32_t new_size) { +#if SPIFFS_IX_MAP == 0 + (void)objix; +#endif + // update index caches in all file descriptors + spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG; + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + SPIFFS_DBG(" CALLBACK %s obj_id:"_SPIPRIid" spix:"_SPIPRIsp" npix:"_SPIPRIpg" nsz:"_SPIPRIi"\n", (const char *[]){"UPD", "NEW", "DEL", "MOV", "HUP","???"}[MIN(ev,5)], + obj_id_raw, spix, new_pix, new_size); + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; +#if SPIFFS_TEMPORAL_FD_CACHE + if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; +#else + if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; +#endif + if (spix == 0) { + if (ev != SPIFFS_EV_IX_DEL) { + SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid"(fdoffs:"_SPIPRIi" offs:"_SPIPRIi") objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, cur_fd->fdoffset, cur_fd->offset, new_pix, new_size); + cur_fd->objix_hdr_pix = new_pix; + if (new_size != 0) { + // update size and offsets for fds to this file + cur_fd->size = new_size; + u32_t act_new_size = new_size == SPIFFS_UNDEFINED_LEN ? 0 : new_size; + if (cur_fd->offset > act_new_size) { + cur_fd->offset = act_new_size; + } + if (cur_fd->fdoffset > act_new_size) { + cur_fd->fdoffset = act_new_size; + } +#if SPIFFS_CACHE_WR + if (cur_fd->cache_page && cur_fd->cache_page->offset > act_new_size+1) { + SPIFFS_CACHE_DBG("CACHE_DROP: file trunced, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix); + spiffs_cache_fd_release(fs, cur_fd->cache_page); + } +#endif + } + } else { + // removing file +#if SPIFFS_CACHE_WR + if (cur_fd->file_nbr && cur_fd->cache_page) { + SPIFFS_CACHE_DBG("CACHE_DROP: file deleted, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix); + spiffs_cache_fd_release(fs, cur_fd->cache_page); + } +#endif + cur_fd->file_nbr = 0; + cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED; + } + } + if (cur_fd->cursor_objix_spix == spix) { + if (ev != SPIFFS_EV_IX_DEL) { + SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix); + cur_fd->cursor_objix_pix = new_pix; + } else { + cur_fd->cursor_objix_pix = 0; + } + } + } + +#if SPIFFS_IX_MAP + + // update index maps + if (ev == SPIFFS_EV_IX_UPD || ev == SPIFFS_EV_IX_NEW) { + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + // check fd opened, having ix map, match obj id + if (cur_fd->file_nbr == 0 || + cur_fd->ix_map == 0 || + (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; + SPIFFS_DBG(" callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix); + spiffs_update_ix_map(fs, cur_fd, spix, objix); + } + } + +#endif + + // callback to user if object index header + if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_fileop_type op; + if (ev == SPIFFS_EV_IX_NEW) { + op = SPIFFS_CB_CREATED; + } else if (ev == SPIFFS_EV_IX_UPD || + ev == SPIFFS_EV_IX_MOV || + ev == SPIFFS_EV_IX_UPD_HDR) { + op = SPIFFS_CB_UPDATED; + } else if (ev == SPIFFS_EV_IX_DEL) { + op = SPIFFS_CB_DELETED; + } else { + SPIFFS_DBG(" callback: WARNING unknown callback event "_SPIPRIi"\n", ev); + return; // bail out + } + fs->file_cb_f(fs, op, obj_id, new_pix); + } +} + +// Open object by id +s32_t spiffs_object_open_by_id( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_fd *fd, + spiffs_flags flags, + spiffs_mode mode) { + s32_t res = SPIFFS_OK; + spiffs_page_ix pix; + + res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + SPIFFS_CHECK_RES(res); + + res = spiffs_object_open_by_page(fs, pix, fd, flags, mode); + + return res; +} + +// Open object by page index +s32_t spiffs_object_open_by_page( + spiffs *fs, + spiffs_page_ix pix, + spiffs_fd *fd, + spiffs_flags flags, + spiffs_mode mode) { + (void)mode; + s32_t res = SPIFFS_OK; + spiffs_page_object_ix_header oix_hdr; + spiffs_obj_id obj_id; + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr); + SPIFFS_CHECK_RES(res); + + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix); + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, + 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id); + + fd->fs = fs; + fd->objix_hdr_pix = pix; + fd->size = oix_hdr.size; + fd->offset = 0; + fd->cursor_objix_pix = pix; + fd->cursor_objix_spix = 0; + fd->obj_id = obj_id; + fd->flags = flags; + + SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0); + + SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", SPIFFS_FH_OFFS(fs, fd->file_nbr), fd->obj_id); + + return res; +} + +#if !SPIFFS_READ_ONLY +// Append to object +// keep current object index (header) page in fs->work buffer +s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { + spiffs *fs = fd->fs; + s32_t res = SPIFFS_OK; + u32_t written = 0; + + SPIFFS_DBG("append: "_SPIPRIi" bytes @ offs "_SPIPRIi" of size "_SPIPRIi"\n", len, offset, fd->size); + + if (offset > fd->size) { + SPIFFS_DBG("append: offset reversed to size\n"); + offset = fd->size; + } + + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta + if (res != SPIFFS_OK) { + SPIFFS_DBG("append: gc check fail "_SPIPRIi"\n", res); + } + SPIFFS_CHECK_RES(res); + + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_header p_hdr; + + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix; + spiffs_page_ix new_objix_hdr_page; + + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_page_ix data_page; + u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs); + + // write all data + while (res == SPIFFS_OK && written < len) { + // calculate object index page span index + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // handle storing and loading of object indices + if (cur_objix_spix != prev_objix_spix) { + // new object index page + // within this clause we return directly if something fails, object index mess-up + if (written > 0) { + // store previous object index page, unless first pass + SPIFFS_DBG("append: "_SPIPRIid" store objix "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, + cur_objix_pix, prev_objix_spix, written); + if (prev_objix_spix == 0) { + // this is an update to object index header page + objix_hdr->size = offset+written; + if (offset == 0) { + // was an empty object, update same page (size was 0xffffffff) + res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0); + SPIFFS_CHECK_RES(res); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + } else { + // was a nonempty object, update to new page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("append: "_SPIPRIid" store new objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, + new_objix_hdr_page, 0, written); + } + } else { + // this is an update to an object index page + res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, + SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0); + // update length in object index header page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_CHECK_RES(res); + SPIFFS_DBG("append: "_SPIPRIid" store new size I "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, + offset+written, new_objix_hdr_page, 0, written); + } + fd->size = offset+written; + fd->offset = offset+written; + } + + // create or load new object index page + if (cur_objix_spix == 0) { + // load object index header page, must always exist + SPIFFS_DBG("append: "_SPIPRIid" load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", fd->obj_id, cur_objix_pix, cur_objix_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + } else { + spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs)); + // on subsequent passes, create a new object index page + if (written > 0 || cur_objix_spix > len_objix_spix) { + p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = cur_objix_spix; + p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX); + res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 1, &cur_objix_pix); + SPIFFS_CHECK_RES(res); + // quick "load" of new object index page + memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + _SPIFFS_MEMCPY(fs->work, &p_hdr, sizeof(spiffs_page_header)); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, + SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0); + SPIFFS_DBG("append: "_SPIPRIid" create objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id + , cur_objix_pix, cur_objix_spix, written); + } else { + // on first pass, we load existing object index page + spiffs_page_ix pix; + SPIFFS_DBG("append: "_SPIPRIid" find objix span_ix:"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix); + if (fd->cursor_objix_spix == cur_objix_spix) { + pix = fd->cursor_objix_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); + SPIFFS_CHECK_RES(res); + } + SPIFFS_DBG("append: "_SPIPRIid" found object index at page "_SPIPRIpg" [fd size "_SPIPRIi"]\n", fd->obj_id, pix, fd->size); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + cur_objix_pix = pix; + } + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = offset+written; + fd->size = offset+written; + } + prev_objix_spix = cur_objix_spix; + } + + // write data + u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs); + if (page_offs == 0) { + // at beginning of a page, allocate and write a new page of data + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, &data[written], to_write, page_offs, 1, &data_page); + SPIFFS_DBG("append: "_SPIPRIid" store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id, + data_page, data_spix, page_offs, to_write, written); + } else { + // append to existing page, fill out free data in existing page + if (cur_objix_spix == 0) { + // get data page from object index header page + data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + res = spiffs_page_data_check(fs, fd, data_page, data_spix); + SPIFFS_CHECK_RES(res); + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]); + SPIFFS_DBG("append: "_SPIPRIid" store to existing data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id + , data_page, data_spix, page_offs, to_write, written); + } + + if (res != SPIFFS_OK) break; + + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page; + SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", fd->obj_id + , data_page, data_spix); + objix_hdr->size = offset+written; + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page; + SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", fd->obj_id + , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + + // update internals + page_offs = 0; + data_spix++; + written += to_write; + } // while all data + + fd->size = offset+written; + fd->offset = offset+written; + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + // finalize updated object indices + s32_t res2 = SPIFFS_OK; + if (cur_objix_spix != 0) { + // wrote beyond object index header page + // write last modified object index page, unless object header index page + SPIFFS_DBG("append: "_SPIPRIid" store objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, + cur_objix_pix, cur_objix_spix, written); + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res2); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, + SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0); + + // update size in object header index page + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: "_SPIPRIid" store new size II "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi", res "_SPIPRIi"\n", fd->obj_id + , offset+written, new_objix_hdr_page, 0, written, res2); + SPIFFS_CHECK_RES(res2); + } else { + // wrote within object index header page + if (offset == 0) { + // wrote to empty object - simply update size and write whole page + objix_hdr->size = offset+written; + SPIFFS_DBG("append: "_SPIPRIid" store fresh objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id + , cur_objix_pix, cur_objix_spix, written); + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res2); + // callback on object index update + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, + SPIFFS_EV_IX_UPD_HDR, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size); + } else { + // modifying object index header page, update size and make new copy + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: "_SPIPRIid" store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id + , new_objix_hdr_page, 0, written); + SPIFFS_CHECK_RES(res2); + } + } + + return res; +} // spiffs_object_append +#endif // !SPIFFS_READ_ONLY + +#if !SPIFFS_READ_ONLY +// Modify object +// keep current object index (header) page in fs->work buffer +s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { + spiffs *fs = fd->fs; + s32_t res = SPIFFS_OK; + u32_t written = 0; + + res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_CHECK_RES(res); + + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_header p_hdr; + + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix; + spiffs_page_ix new_objix_hdr_pix; + + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_page_ix data_pix; + u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs); + + + // write all data + while (res == SPIFFS_OK && written < len) { + // calculate object index page span index + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // handle storing and loading of object indices + if (cur_objix_spix != prev_objix_spix) { + // new object index page + // within this clause we return directly if something fails, object index mess-up + if (written > 0) { + // store previous object index (header) page, unless first pass + if (prev_objix_spix == 0) { + // store previous object index header page + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written); + SPIFFS_CHECK_RES(res); + } else { + // store new version of previous object index page + spiffs_page_ix new_objix_pix; + + res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); + SPIFFS_DBG("modify: store previous modified objix page, "_SPIPRIid":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, objix->p_hdr.span_ix, written); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix, + SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + } + } + + // load next object index page + if (cur_objix_spix == 0) { + // load object index header page, must exist + SPIFFS_DBG("modify: load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", cur_objix_pix, cur_objix_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + } else { + // load existing object index page on first pass + spiffs_page_ix pix; + SPIFFS_DBG("modify: find objix span_ix:"_SPIPRIsp"\n", cur_objix_spix); + if (fd->cursor_objix_spix == cur_objix_spix) { + pix = fd->cursor_objix_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); + SPIFFS_CHECK_RES(res); + } + SPIFFS_DBG("modify: found object index at page "_SPIPRIpg"\n", pix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + cur_objix_pix = pix; + } + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = offset+written; + prev_objix_spix = cur_objix_spix; + } + + // write partial data + u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs); + spiffs_page_ix orig_data_pix; + if (cur_objix_spix == 0) { + // get data page from object index header page + orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff; + if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) { + // a full page, allocate and write a new page of data + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, &data[written], to_write, page_offs, 1, &data_pix); + SPIFFS_DBG("modify: store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", data_pix, data_spix, page_offs, to_write, written); + } else { + // write to existing page, allocate new and copy unmodified data + + res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 0, &data_pix); + if (res != SPIFFS_OK) break; + + // copy unmodified data + if (page_offs > 0) { + // before modification + res = spiffs_phys_cpy(fs, fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header), + page_offs); + if (res != SPIFFS_OK) break; + } + if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) { + // after modification + res = spiffs_phys_cpy(fs, fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write, + SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write, + SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write)); + if (res != SPIFFS_OK) break; + } + + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]); + if (res != SPIFFS_OK) break; + p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr.flags); + if (res != SPIFFS_OK) break; + + SPIFFS_DBG("modify: store to existing data page, src:"_SPIPRIpg", dst:"_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written); + } + + // delete original data page + res = spiffs_page_delete(fs, orig_data_pix); + if (res != SPIFFS_OK) break; + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix; + SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", data_pix, data_spix); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix; + SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + + // update internals + page_offs = 0; + data_spix++; + written += to_write; + } // while all data + + fd->offset = offset+written; + fd->cursor_objix_pix = cur_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + // finalize updated object indices + s32_t res2 = SPIFFS_OK; + if (cur_objix_spix != 0) { + // wrote beyond object index header page + // write last modified object index page + // move and update page + spiffs_page_ix new_objix_pix; + + res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res2); + + res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); + SPIFFS_DBG("modify: store modified objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, cur_objix_spix, written); + fd->cursor_objix_pix = new_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + SPIFFS_CHECK_RES(res2); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix, + SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + + } else { + // wrote within object index header page + res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written); + SPIFFS_CHECK_RES(res2); + } + + return res; +} // spiffs_object_modify +#endif // !SPIFFS_READ_ONLY + +static s32_t spiffs_object_find_object_index_header_by_name_v( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_block_ix bix, + int ix_entry, + const void *user_const_p, + void *user_var_p) { + (void)user_var_p; + s32_t res; + spiffs_page_object_ix_header objix_hdr; + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED || + (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) { + return SPIFFS_VIS_COUNTINUE; + } + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_CHECK_RES(res); + if (objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) { + return SPIFFS_OK; + } + } + + return SPIFFS_VIS_COUNTINUE; +} + +// Finds object index header page by name +s32_t spiffs_object_find_object_index_header_by_name( + spiffs *fs, + const u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_page_ix *pix) { + s32_t res; + spiffs_block_ix bix; + int entry; + + res = spiffs_obj_lu_find_entry_visitor(fs, + fs->cursor_block_ix, + fs->cursor_obj_lu_entry, + 0, + 0, + spiffs_object_find_object_index_header_by_name_v, + name, + 0, + &bix, + &entry); + + if (res == SPIFFS_VIS_END) { + res = SPIFFS_ERR_NOT_FOUND; + } + SPIFFS_CHECK_RES(res); + + if (pix) { + *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry); + } + + fs->cursor_block_ix = bix; + fs->cursor_obj_lu_entry = entry; + + return res; +} + +#if !SPIFFS_READ_ONLY +// Truncates object to new size. If new size is null, object may be removed totally +s32_t spiffs_object_truncate( + spiffs_fd *fd, + u32_t new_size, + u8_t remove_full) { + s32_t res = SPIFFS_OK; + spiffs *fs = fd->fs; + + if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove_full) { + // no op + return res; + } + + // need 2 pages if not removing: object index page + possibly chopped data page + if (remove_full == 0) { + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2); + SPIFFS_CHECK_RES(res); + } + + spiffs_page_ix objix_pix = fd->objix_hdr_pix; + spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs); + u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ; + spiffs_span_ix cur_objix_spix = 0; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + spiffs_page_ix data_pix; + spiffs_page_ix new_objix_hdr_pix; + + // before truncating, check if object is to be fully removed and mark this + if (remove_full && new_size == 0) { + u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE); + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&flags); + SPIFFS_CHECK_RES(res); + } + + // delete from end of object until desired len is reached + while (cur_size > new_size) { + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + + // put object index for current data span index in work buffer + if (prev_objix_spix != cur_objix_spix) { + if (prev_objix_spix != (spiffs_span_ix)-1) { + // remove previous object index page + SPIFFS_DBG("truncate: delete objix page "_SPIPRIpg":"_SPIPRIsp"\n", objix_pix, prev_objix_spix); + + res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_delete(fs, objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0, + SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0); + if (prev_objix_spix > 0) { + // Update object index header page, unless we totally want to remove the file. + // If fully removing, we're not keeping consistency as good as when storing the header between chunks, + // would we be aborted. But when removing full files, a crammed system may otherwise + // report ERR_FULL a la windows. We cannot have that. + // Hence, take the risk - if aborted, a file check would free the lost pages and mend things + // as the file is marked as fully deleted in the beginning. + if (remove_full == 0) { + SPIFFS_DBG("truncate: update objix hdr page "_SPIPRIpg":"_SPIPRIsp" to size "_SPIPRIi"\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + fd->size = cur_size; + } + } + // load current object index (header) page + if (cur_objix_spix == 0) { + objix_pix = fd->objix_hdr_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix); + SPIFFS_CHECK_RES(res); + } + + SPIFFS_DBG("truncate: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix); + fd->cursor_objix_pix = objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = cur_size; + + prev_objix_spix = cur_objix_spix; + } + + if (cur_objix_spix == 0) { + // get data page from object index header page + data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE; + } else { + // get data page from object index page + data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; + } + + SPIFFS_DBG("truncate: got data pix "_SPIPRIpg"\n", data_pix); + + if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) { + // delete full data page + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { + SPIFFS_DBG("truncate: err validating data pix "_SPIPRIi"\n", res); + break; + } + + if (res == SPIFFS_OK) { + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) { + SPIFFS_DBG("truncate: err deleting data pix "_SPIPRIi"\n", res); + break; + } + } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) { + res = SPIFFS_OK; + } + + // update current size + if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) { + cur_size -= SPIFFS_DATA_PAGE_SIZE(fs); + } else { + cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs); + } + fd->size = cur_size; + fd->offset = cur_size; + SPIFFS_DBG("truncate: delete data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", data_pix, data_spix, cur_size); + } else { + // delete last page, partially + spiffs_page_header p_hdr; + spiffs_page_ix new_data_pix; + u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs)); + SPIFFS_DBG("truncate: delete "_SPIPRIi" bytes from data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", bytes_to_remove, data_pix, data_spix, cur_size); + + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + if (res != SPIFFS_OK) break; + + p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; + p_hdr.span_ix = data_spix; + p_hdr.flags = 0xff; + // allocate new page and copy unmodified data + res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, + &p_hdr, 0, 0, 0, 0, &new_data_pix); + if (res != SPIFFS_OK) break; + res = spiffs_phys_cpy(fs, 0, + SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header), + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header), + SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove); + if (res != SPIFFS_OK) break; + // delete original data page + res = spiffs_page_delete(fs, data_pix); + if (res != SPIFFS_OK) break; + p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL; + res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags), + sizeof(u8_t), + (u8_t *)&p_hdr.flags); + if (res != SPIFFS_OK) break; + + // update memory representation of object index page with new data page + if (cur_objix_spix == 0) { + // update object index header page + ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix; + SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } else { + // update object index page + ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix; + SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + } + cur_size = new_size; + fd->size = new_size; + fd->offset = cur_size; + break; + } + data_spix--; + } // while all data + + // update object indices + if (cur_objix_spix == 0) { + // update object index header page + if (cur_size == 0) { + if (remove_full) { + // remove object altogether + SPIFFS_DBG("truncate: remove object index header page "_SPIPRIpg"\n", objix_pix); + + res = spiffs_page_index_check(fs, fd, objix_pix, 0); + SPIFFS_CHECK_RES(res); + + res = spiffs_page_delete(fs, objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0, + SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0); + } else { + // make uninitialized object + SPIFFS_DBG("truncate: reset objix_hdr page "_SPIPRIpg"\n", objix_pix); + memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff, + SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header)); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + } else { + // update object index header page + SPIFFS_DBG("truncate: update object index header page with indices and size\n"); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + } else { + // update both current object index page and object index header page + spiffs_page_ix new_objix_pix; + + res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix); + SPIFFS_CHECK_RES(res); + + // move and update object index page + res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix); + SPIFFS_CHECK_RES(res); + spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr, + SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); + SPIFFS_DBG("truncate: store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, cur_objix_spix); + fd->cursor_objix_pix = new_objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + fd->offset = cur_size; + // update object index header page with new size + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } + fd->size = cur_size; + + return res; +} // spiffs_object_truncate +#endif // !SPIFFS_READ_ONLY + +s32_t spiffs_object_read( + spiffs_fd *fd, + u32_t offset, + u32_t len, + u8_t *dst) { + s32_t res = SPIFFS_OK; + spiffs *fs = fd->fs; + spiffs_page_ix objix_pix; + spiffs_page_ix data_pix; + spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs); + u32_t cur_offset = offset; + spiffs_span_ix cur_objix_spix; + spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1; + spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; + spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; + + while (cur_offset < offset + len) { +#if SPIFFS_IX_MAP + // check if we have a memory, index map and if so, if we're within index map's range + // and if so, if the entry is populated + if (fd->ix_map && data_spix >= fd->ix_map->start_spix && data_spix <= fd->ix_map->end_spix + && fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]) { + data_pix = fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]; + } else { +#endif + cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if (prev_objix_spix != cur_objix_spix) { + // load current object index (header) page + if (cur_objix_spix == 0) { + objix_pix = fd->objix_hdr_pix; + } else { + SPIFFS_DBG("read: find objix "_SPIPRIid":"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix); + if (fd->cursor_objix_spix == cur_objix_spix) { + objix_pix = fd->cursor_objix_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix); + SPIFFS_CHECK_RES(res); + } + } + SPIFFS_DBG("read: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix); + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, + fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); + SPIFFS_CHECK_RES(res); + SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix); + + fd->offset = cur_offset; + fd->cursor_objix_pix = objix_pix; + fd->cursor_objix_spix = cur_objix_spix; + + prev_objix_spix = cur_objix_spix; + } + + if (cur_objix_spix == 0) { + // get data page from object index header page + data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + // get data page from object index page + data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } +#if SPIFFS_IX_MAP + } +#endif + // all remaining data + u32_t len_to_read = offset + len - cur_offset; + // remaining data in page + len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))); + // remaining data in file + len_to_read = MIN(len_to_read, fd->size); + SPIFFS_DBG("read: offset:"_SPIPRIi" rd:"_SPIPRIi" data spix:"_SPIPRIsp" is data_pix:"_SPIPRIpg" addr:"_SPIPRIad"\n", cur_offset, len_to_read, data_spix, data_pix, + (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)))); + if (len_to_read <= 0) { + res = SPIFFS_ERR_END_OF_OBJECT; + break; + } + res = spiffs_page_data_check(fs, fd, data_pix, data_spix); + SPIFFS_CHECK_RES(res); + res = _spiffs_rd( + fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ, + fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)), + len_to_read, + dst); + SPIFFS_CHECK_RES(res); + dst += len_to_read; + cur_offset += len_to_read; + fd->offset = cur_offset; + data_spix++; + } + + return res; +} + +#if !SPIFFS_READ_ONLY +typedef struct { + spiffs_obj_id min_obj_id; + spiffs_obj_id max_obj_id; + u32_t compaction; + const u8_t *conflicting_name; +} spiffs_free_obj_id_state; + +static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, + const void *user_const_p, void *user_var_p) { + if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) { + spiffs_obj_id min_obj_id = *((spiffs_obj_id*)user_var_p); + const u8_t *conflicting_name = (const u8_t*)user_const_p; + + // if conflicting name parameter is given, also check if this name is found in object index hdrs + if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); + int res; + spiffs_page_object_ix_header objix_hdr; + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, + 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr); + SPIFFS_CHECK_RES(res); + if (objix_hdr.p_hdr.span_ix == 0 && + (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == + (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { + if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) { + return SPIFFS_ERR_CONFLICTING_NAME; + } + } + } + + id &= ~SPIFFS_OBJ_ID_IX_FLAG; + u32_t bit_ix = (id-min_obj_id) & 7; + int byte_ix = (id-min_obj_id) >> 3; + if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) { + fs->work[byte_ix] |= (1<conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) { + return SPIFFS_ERR_CONFLICTING_NAME; + } + + id &= ~SPIFFS_OBJ_ID_IX_FLAG; + if (id >= state->min_obj_id && id <= state->max_obj_id) { + u8_t *map = (u8_t *)fs->work; + int ix = (id - state->min_obj_id) / state->compaction; + //SPIFFS_DBG("free_obj_id: add ix "_SPIPRIi" for id "_SPIPRIid" min"_SPIPRIid" max"_SPIPRIid" comp:"_SPIPRIi"\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction); + map[ix]++; + } + } + } + return SPIFFS_VIS_COUNTINUE; +} + +// Scans thru all object lookup for object index header pages. If total possible number of +// object ids cannot fit into a work buffer, these are grouped. When a group containing free +// object ids is found, the object lu is again scanned for object ids within group and bitmasked. +// Finally, the bitmask is searched for a free id +s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) { + s32_t res = SPIFFS_OK; + u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2; + spiffs_free_obj_id_state state; + spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE; + state.min_obj_id = 1; + state.max_obj_id = max_objects + 1; + if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) { + state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG; + } + state.compaction = 0; + state.conflicting_name = conflicting_name; + while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) { + if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) { + // possible to represent in bitmap + u32_t i, j; + SPIFFS_DBG("free_obj_id: BITM min:"_SPIPRIid" max:"_SPIPRIid"\n", state.min_obj_id, state.max_obj_id); + + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, + conflicting_name, &state.min_obj_id, 0, 0); + if (res == SPIFFS_VIS_END) res = SPIFFS_OK; + SPIFFS_CHECK_RES(res); + // traverse bitmask until found free obj_id + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) { + u8_t mask = fs->work[i]; + if (mask == 0xff) { + continue; + } + for (j = 0; j < 8; j++) { + if ((mask & (1<work; + u8_t min_count = 0xff; + + for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) { + if (map[i] < min_count) { + min_count = map[i]; + min_i = i; + if (min_count == 0) { + break; + } + } + } + + if (min_count == state.compaction) { + // there are no free objids! + SPIFFS_DBG("free_obj_id: compacted table is full\n"); + return SPIFFS_ERR_FULL; + } + + SPIFFS_DBG("free_obj_id: COMP select index:"_SPIPRIi" min_count:"_SPIPRIi" min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction); + + if (min_count == 0) { + // no id in this range, skip compacting and use directly + *obj_id = min_i * state.compaction + state.min_obj_id; + return SPIFFS_OK; + } else { + SPIFFS_DBG("free_obj_id: COMP SEL chunk:"_SPIPRIi" min:"_SPIPRIid" -> "_SPIPRIid"\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction); + state.min_obj_id += min_i * state.compaction; + state.max_obj_id = state.min_obj_id + state.compaction; + // decrease compaction + } + if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) { + // no need for compacting, use bitmap + continue; + } + } + // in a work memory of log_page_size bytes, we may fit in log_page_size ids + // todo what if compaction is > 255 - then we cannot fit it in a byte + state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t))); + SPIFFS_DBG("free_obj_id: COMP min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", state.min_obj_id, state.max_obj_id, state.compaction); + + memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, &state, 0, 0, 0); + if (res == SPIFFS_VIS_END) res = SPIFFS_OK; + SPIFFS_CHECK_RES(res); + state.conflicting_name = 0; // searched for conflicting name once, no need to do it again + } + } + + return res; +} +#endif // !SPIFFS_READ_ONLY + +#if SPIFFS_TEMPORAL_FD_CACHE +// djb2 hash +static u32_t spiffs_hash(spiffs *fs, const u8_t *name) { + (void)fs; + u32_t hash = 5381; + u8_t c; + int i = 0; + while ((c = name[i++]) && i < SPIFFS_OBJ_NAME_LEN) { + hash = (hash * 33) ^ c; + } + return hash; +} +#endif + +s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) { +#if SPIFFS_TEMPORAL_FD_CACHE + u32_t i; + u16_t min_score = 0xffff; + u32_t cand_ix = (u32_t)-1; + u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + + if (name) { + // first, decrease score of all closed descriptors + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr == 0) { + if (cur_fd->score > 1) { // score == 0 indicates never used fd + cur_fd->score--; + } + } + } + } + + // find the free fd with least score + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr == 0) { + if (name && cur_fd->name_hash == name_hash) { + cand_ix = i; + break; + } + if (cur_fd->score < min_score) { + min_score = cur_fd->score; + cand_ix = i; + } + } + } + + if (cand_ix != (u32_t)-1) { + spiffs_fd *cur_fd = &fds[cand_ix]; + if (name) { + if (cur_fd->name_hash == name_hash && cur_fd->score > 0) { + // opened an fd with same name hash, assume same file + // set search point to saved obj index page and hope we have a correct match directly + // when start searching - if not, we will just keep searching until it is found + fs->cursor_block_ix = SPIFFS_BLOCK_FOR_PAGE(fs, cur_fd->objix_hdr_pix); + fs->cursor_obj_lu_entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, cur_fd->objix_hdr_pix); + // update score + if (cur_fd->score < 0xffff-SPIFFS_TEMPORAL_CACHE_HIT_SCORE) { + cur_fd->score += SPIFFS_TEMPORAL_CACHE_HIT_SCORE; + } else { + cur_fd->score = 0xffff; + } + } else { + // no hash hit, restore this fd to initial state + cur_fd->score = SPIFFS_TEMPORAL_CACHE_HIT_SCORE; + cur_fd->name_hash = name_hash; + } + } + cur_fd->file_nbr = cand_ix+1; + *fd = cur_fd; + return SPIFFS_OK; + } else { + return SPIFFS_ERR_OUT_OF_FILE_DESCS; + } +#else + (void)name; + u32_t i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr == 0) { + cur_fd->file_nbr = i+1; + *fd = cur_fd; + return SPIFFS_OK; + } + } + return SPIFFS_ERR_OUT_OF_FILE_DESCS; +#endif +} + +s32_t spiffs_fd_return(spiffs *fs, spiffs_file f) { + if (f <= 0 || f > (s16_t)fs->fd_count) { + return SPIFFS_ERR_BAD_DESCRIPTOR; + } + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + spiffs_fd *fd = &fds[f-1]; + if (fd->file_nbr == 0) { + return SPIFFS_ERR_FILE_CLOSED; + } + fd->file_nbr = 0; +#if SPIFFS_IX_MAP + fd->ix_map = 0; +#endif + return SPIFFS_OK; +} + +s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) { + if (f <= 0 || f > (s16_t)fs->fd_count) { + return SPIFFS_ERR_BAD_DESCRIPTOR; + } + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + *fd = &fds[f-1]; + if ((*fd)->file_nbr == 0) { + return SPIFFS_ERR_FILE_CLOSED; + } + return SPIFFS_OK; +} + +#if SPIFFS_TEMPORAL_FD_CACHE +void spiffs_fd_temporal_cache_rehash( + spiffs *fs, + const char *old_path, + const char *new_path) { + u32_t i; + u32_t old_hash = spiffs_hash(fs, (const u8_t *)old_path); + u32_t new_hash = spiffs_hash(fs, (const u8_t *)new_path); + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->score > 0 && cur_fd->name_hash == old_hash) { + cur_fd->name_hash = new_hash; + } + } +} +#endif diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.h new file mode 100755 index 0000000..f420978 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/spiffs_nucleus.h @@ -0,0 +1,831 @@ +/* + * spiffs_nucleus.h + * + * Created on: Jun 15, 2013 + * Author: petera + */ + +/* SPIFFS layout + * + * spiffs is designed for following spi flash characteristics: + * - only big areas of data (blocks) can be erased + * - erasing resets all bits in a block to ones + * - writing pulls ones to zeroes + * - zeroes cannot be pulled to ones, without erase + * - wear leveling + * + * spiffs is also meant to be run on embedded, memory constraint devices. + * + * Entire area is divided in blocks. Entire area is also divided in pages. + * Each block contains same number of pages. A page cannot be erased, but a + * block can be erased. + * + * Entire area must be block_size * x + * page_size must be block_size / (2^y) where y > 2 + * + * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes + * + * BLOCK 0 PAGE 0 object lookup 1 + * PAGE 1 object lookup 2 + * ... + * PAGE n-1 object lookup n + * PAGE n object data 1 + * PAGE n+1 object data 2 + * ... + * PAGE n+m-1 object data m + * + * BLOCK 1 PAGE n+m object lookup 1 + * PAGE n+m+1 object lookup 2 + * ... + * PAGE 2n+m-1 object lookup n + * PAGE 2n+m object data 1 + * PAGE 2n+m object data 2 + * ... + * PAGE 2n+2m-1 object data m + * ... + * + * n is number of object lookup pages, which is number of pages needed to index all pages + * in a block by object id + * : block_size / page_size * sizeof(obj_id) / page_size + * m is number data pages, which is number of pages in block minus number of lookup pages + * : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size + * thus, n+m is total number of pages in a block + * : block_size / page_size + * + * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256 + * + * Object lookup pages contain object id entries. Each entry represent the corresponding + * data page. + * Assuming a 16 bit object id, an object id being 0xffff represents a free page. + * An object id being 0x0000 represents a deleted page. + * + * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff .. + * page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff .. + * page 2 : data : data for object id 0008 + * page 3 : data : data for object id 0001 + * page 4 : data : data for object id 0aaa + * ... + * + * + * Object data pages can be either object index pages or object content. + * All object data pages contains a data page header, containing object id and span index. + * The span index denotes the object page ordering amongst data pages with same object id. + * This applies to both object index pages (when index spans more than one page of entries), + * and object data pages. + * An object index page contains page entries pointing to object content page. The entry index + * in a object index page correlates to the span index in the actual object data page. + * The first object index page (span index 0) is called object index header page, and also + * contains object flags (directory/file), size, object name etc. + * + * ex: + * BLOCK 1 + * PAGE 256: objectl lookup page 1 + * [*123] [ 123] [ 123] [ 123] + * [ 123] [*123] [ 123] [ 123] + * [free] [free] [free] [free] ... + * PAGE 257: objectl lookup page 2 + * [free] [free] [free] [free] ... + * PAGE 258: object index page (header) + * obj.id:0123 span.ix:0000 flags:INDEX + * size:1600 name:ex.txt type:file + * [259] [260] [261] [262] + * PAGE 259: object data page + * obj.id:0123 span.ix:0000 flags:DATA + * PAGE 260: object data page + * obj.id:0123 span.ix:0001 flags:DATA + * PAGE 261: object data page + * obj.id:0123 span.ix:0002 flags:DATA + * PAGE 262: object data page + * obj.id:0123 span.ix:0003 flags:DATA + * PAGE 263: object index page + * obj.id:0123 span.ix:0001 flags:INDEX + * [264] [265] [fre] [fre] + * [fre] [fre] [fre] [fre] + * PAGE 264: object data page + * obj.id:0123 span.ix:0004 flags:DATA + * PAGE 265: object data page + * obj.id:0123 span.ix:0005 flags:DATA + * + */ +#ifndef SPIFFS_NUCLEUS_H_ +#define SPIFFS_NUCLEUS_H_ + +#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1) +#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1) +#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2) +#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3) +#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4) + +// visitor result, continue searching +#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20) +// visitor result, continue searching after reloading lu buffer +#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21) +// visitor result, stop searching +#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22) + +// updating an object index contents +#define SPIFFS_EV_IX_UPD (0) +// creating a new object index +#define SPIFFS_EV_IX_NEW (1) +// deleting an object index +#define SPIFFS_EV_IX_DEL (2) +// moving an object index without updating contents +#define SPIFFS_EV_IX_MOV (3) +// updating an object index header data only, not the table itself +#define SPIFFS_EV_IX_UPD_HDR (4) + +#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1))) + +#define SPIFFS_UNDEFINED_LEN (u32_t)(-1) + +#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) +#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) + +#if SPIFFS_USE_MAGIC +#if !SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) +#else // SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix)))) +#endif // SPIFFS_USE_MAGIC_LENGTH +#endif // SPIFFS_USE_MAGIC + +#define SPIFFS_CONFIG_MAGIC (0x20090315) + +#if SPIFFS_SINGLETON == 0 +#undef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \ + ((fs)->cfg.log_page_size) +#undef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \ + ((fs)->cfg.log_block_size) +#undef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(fs) \ + ((fs)->cfg.phys_size) +#undef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \ + ((fs)->cfg.phys_erase_block) +#undef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(fs) \ + ((fs)->cfg.phys_addr) +#endif + +// total number of pages +#define SPIFFS_MAX_PAGES(fs) \ + ( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// total number of pages per block, including object lookup pages +#define SPIFFS_PAGES_PER_BLOCK(fs) \ + ( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// number of object lookup pages per block +#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \ + (MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) ) +// checks if page index belongs to object lookup +#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \ + (((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) +// number of object lookup entries in all object lookup pages +#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \ + (SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) +// converts a block to physical address +#define SPIFFS_BLOCK_TO_PADDR(fs, block) \ + ( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) ) +// converts a object lookup entry to page index +#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \ + ((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry)) +// converts a object lookup entry to physical address of corresponding page +#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \ + (SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// converts a page to physical address +#define SPIFFS_PAGE_TO_PADDR(fs, page) \ + ( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// converts a physical address to page +#define SPIFFS_PADDR_TO_PAGE(fs, addr) \ + ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// gives index in page for a physical address +#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \ + ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) ) +// returns containing block for given page +#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \ + ( (page) / SPIFFS_PAGES_PER_BLOCK(fs) ) +// returns starting page for block +#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \ + ( (block) * SPIFFS_PAGES_PER_BLOCK(fs) ) +// converts page to entry in object lookup page +#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \ + ( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) ) +// returns data size in a data page +#define SPIFFS_DATA_PAGE_SIZE(fs) \ + ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) ) +// returns physical address for block's erase count, +// always in the physical last entry of the last object lookup page +#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) ) +// returns physical address for block's magic, +// always in the physical second last entry of the last object lookup page +#define SPIFFS_MAGIC_PADDR(fs, bix) \ + ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 ) +// checks if there is any room for magic in the object luts +#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \ + ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \ + <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) ) + +// define helpers object + +// entries in an object header page index +#define SPIFFS_OBJ_HDR_IX_LEN(fs) \ + ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix)) +// entries in an object page index +#define SPIFFS_OBJ_IX_LEN(fs) \ + ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix)) +// object index entry for given data span index +#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \ + ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs))) +// object index span index number for given data span index or entry +#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \ + ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs))) +// get data span index for object index span index +#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \ + ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) ) + +#if SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0) +#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0) +#else +#define SPIFFS_FH_OFFS(fs, fh) (fh) +#define SPIFFS_FH_UNOFFS(fs, fh) (fh) +#endif + + +#define SPIFFS_OP_T_OBJ_LU (0<<0) +#define SPIFFS_OP_T_OBJ_LU2 (1<<0) +#define SPIFFS_OP_T_OBJ_IX (2<<0) +#define SPIFFS_OP_T_OBJ_DA (3<<0) +#define SPIFFS_OP_C_DELE (0<<2) +#define SPIFFS_OP_C_UPDT (1<<2) +#define SPIFFS_OP_C_MOVS (2<<2) +#define SPIFFS_OP_C_MOVD (3<<2) +#define SPIFFS_OP_C_FLSH (4<<2) +#define SPIFFS_OP_C_READ (5<<2) +#define SPIFFS_OP_C_WRTHRU (6<<2) + +#define SPIFFS_OP_TYPE_MASK (3<<0) +#define SPIFFS_OP_COM_MASK (7<<2) + + +// if 0, this page is written to, else clean +#define SPIFFS_PH_FLAG_USED (1<<0) +// if 0, writing is finalized, else under modification +#define SPIFFS_PH_FLAG_FINAL (1<<1) +// if 0, this is an index page, else a data page +#define SPIFFS_PH_FLAG_INDEX (1<<2) +// if 0, page is deleted, else valid +#define SPIFFS_PH_FLAG_DELET (1<<7) +// if 0, this index header is being deleted +#define SPIFFS_PH_FLAG_IXDELE (1<<6) + + +#define SPIFFS_CHECK_MOUNT(fs) \ + ((fs)->mounted != 0) + +#define SPIFFS_CHECK_CFG(fs) \ + ((fs)->config_magic == SPIFFS_CONFIG_MAGIC) + +#define SPIFFS_CHECK_RES(res) \ + do { \ + if ((res) < SPIFFS_OK) return (res); \ + } while (0); + +#define SPIFFS_API_CHECK_MOUNT(fs) \ + if (!SPIFFS_CHECK_MOUNT((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \ + return SPIFFS_ERR_NOT_MOUNTED; \ + } + +#define SPIFFS_API_CHECK_CFG(fs) \ + if (!SPIFFS_CHECK_CFG((fs))) { \ + (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \ + return SPIFFS_ERR_NOT_CONFIGURED; \ + } + +#define SPIFFS_API_CHECK_RES(fs, res) \ + if ((res) < SPIFFS_OK) { \ + (fs)->err_code = (res); \ + return (res); \ + } + +#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ + if ((res) < SPIFFS_OK) { \ + (fs)->err_code = (res); \ + SPIFFS_UNLOCK(fs); \ + return (res); \ + } + +#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \ + if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \ + if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \ + if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \ + if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \ + if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \ + if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH; + //if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED; + +#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \ + if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \ + if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \ + if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \ + if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \ + if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \ + if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH; + + +// check id, only visit matching objec ids +#define SPIFFS_VIS_CHECK_ID (1<<0) +// report argument object id to visitor - else object lookup id is reported +#define SPIFFS_VIS_CHECK_PH (1<<1) +// stop searching at end of all look up pages +#define SPIFFS_VIS_NO_WRAP (1<<2) + +#if SPIFFS_HAL_CALLBACK_EXTRA + +#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \ + (_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src)) +#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \ + (_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst)) +#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \ + (_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len)) + +#else // SPIFFS_HAL_CALLBACK_EXTRA + +#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \ + (_fs)->cfg.hal_write_f((_paddr), (_len), (_src)) +#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \ + (_fs)->cfg.hal_read_f((_paddr), (_len), (_dst)) +#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \ + (_fs)->cfg.hal_erase_f((_paddr), (_len)) + +#endif // SPIFFS_HAL_CALLBACK_EXTRA + +#if SPIFFS_CACHE + +#define SPIFFS_CACHE_FLAG_DIRTY (1<<0) +#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1) +#define SPIFFS_CACHE_FLAG_OBJLU (1<<2) +#define SPIFFS_CACHE_FLAG_OBJIX (1<<3) +#define SPIFFS_CACHE_FLAG_DATA (1<<4) +#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7) + +#define SPIFFS_CACHE_PAGE_SIZE(fs) \ + (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)) + +#define spiffs_get_cache(fs) \ + ((spiffs_cache *)((fs)->cache)) + +#define spiffs_get_cache_page_hdr(fs, c, ix) \ + ((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)]))) + +#define spiffs_get_cache_page(fs, c, ix) \ + ((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page)) + +// cache page struct +typedef struct { + // cache flags + u8_t flags; + // cache page index + u8_t ix; + // last access of this cache page + u32_t last_access; + union { + // type read cache + struct { + // read cache page index + spiffs_page_ix pix; + }; +#if SPIFFS_CACHE_WR + // type write cache + struct { + // write cache + spiffs_obj_id obj_id; + // offset in cache page + u32_t offset; + // size of cache page + u16_t size; + }; +#endif + }; +} spiffs_cache_page; + +// cache struct +typedef struct { + u8_t cpage_count; + u32_t last_access; + u32_t cpage_use_map; + u32_t cpage_use_mask; + u8_t *cpages; +} spiffs_cache; + +#endif + + +// spiffs nucleus file descriptor +typedef struct { + // the filesystem of this descriptor + spiffs *fs; + // number of file descriptor - if 0, the file descriptor is closed + spiffs_file file_nbr; + // object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted + spiffs_obj_id obj_id; + // size of the file + u32_t size; + // cached object index header page index + spiffs_page_ix objix_hdr_pix; + // cached offset object index page index + spiffs_page_ix cursor_objix_pix; + // cached offset object index span index + spiffs_span_ix cursor_objix_spix; + // current absolute offset + u32_t offset; + // current file descriptor offset (cached) + u32_t fdoffset; + // fd flags + spiffs_flags flags; +#if SPIFFS_CACHE_WR + spiffs_cache_page *cache_page; +#endif +#if SPIFFS_TEMPORAL_FD_CACHE + // djb2 hash of filename + u32_t name_hash; + // hit score (score == 0 indicates never used fd) + u16_t score; +#endif +#if SPIFFS_IX_MAP + // spiffs index map, if 0 it means unmapped + spiffs_ix_map *ix_map; +#endif +} spiffs_fd; + + +// object structs + +// page header, part of each page except object lookup pages +// NB: this is always aligned when the data page is an object index, +// as in this case struct spiffs_page_object_ix is used +typedef struct __attribute(( packed )) { + // object id + spiffs_obj_id obj_id; + // object span index + spiffs_span_ix span_ix; + // flags + u8_t flags; +} spiffs_page_header; + +// object index header page header +typedef struct __attribute(( packed )) +#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES + __attribute(( aligned(sizeof(spiffs_page_ix)) )) +#endif +{ + // common page header + spiffs_page_header p_hdr; + // alignment + u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; + // size of object + u32_t size; + // type of object + spiffs_obj_type type; + // name of object + u8_t name[SPIFFS_OBJ_NAME_LEN]; +#if SPIFFS_OBJ_META_LEN + // metadata. not interpreted by SPIFFS in any way. + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif +} spiffs_page_object_ix_header; + +// object index page header +typedef struct __attribute(( packed )) { + spiffs_page_header p_hdr; + u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; +} spiffs_page_object_ix; + +// callback func for object lookup visitor +typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, + const void *user_const_p, void *user_var_p); + + +#if SPIFFS_CACHE +#define _spiffs_rd(fs, op, fh, addr, len, dst) \ + spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst)) +#define _spiffs_wr(fs, op, fh, addr, len, src) \ + spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src)) +#else +#define _spiffs_rd(fs, op, fh, addr, len, dst) \ + spiffs_phys_rd((fs), (addr), (len), (dst)) +#define _spiffs_wr(fs, op, fh, addr, len, src) \ + spiffs_phys_wr((fs), (addr), (len), (src)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +// --------------- + +s32_t spiffs_phys_rd( + spiffs *fs, +#if SPIFFS_CACHE + u8_t op, + spiffs_file fh, +#endif + u32_t addr, + u32_t len, + u8_t *dst); + +s32_t spiffs_phys_wr( + spiffs *fs, +#if SPIFFS_CACHE + u8_t op, + spiffs_file fh, +#endif + u32_t addr, + u32_t len, + u8_t *src); + +s32_t spiffs_phys_cpy( + spiffs *fs, + spiffs_file fh, + u32_t dst, + u32_t src, + u32_t len); + +s32_t spiffs_phys_count_free_blocks( + spiffs *fs); + +s32_t spiffs_obj_lu_find_entry_visitor( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + u8_t flags, + spiffs_obj_id obj_id, + spiffs_visitor_f v, + const void *user_const_p, + void *user_var_p, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_erase_block( + spiffs *fs, + spiffs_block_ix bix); + +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH +s32_t spiffs_probe( + spiffs_config *cfg); +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH + +// --------------- + +s32_t spiffs_obj_lu_scan( + spiffs *fs); + +s32_t spiffs_obj_lu_find_free_obj_id( + spiffs *fs, + spiffs_obj_id *obj_id, + const u8_t *conflicting_name); + +s32_t spiffs_obj_lu_find_free( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_obj_lu_find_id( + spiffs *fs, + spiffs_block_ix starting_block, + int starting_lu_entry, + spiffs_obj_id obj_id, + spiffs_block_ix *block_ix, + int *lu_entry); + +s32_t spiffs_obj_lu_find_id_and_span( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix); + +s32_t spiffs_obj_lu_find_id_and_span_by_phdr( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix exclusion_pix, + spiffs_page_ix *pix); + +// --------------- + +s32_t spiffs_page_allocate_data( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_page_header *ph, + u8_t *data, + u32_t len, + u32_t page_offs, + u8_t finalize, + spiffs_page_ix *pix); + +s32_t spiffs_page_move( + spiffs *fs, + spiffs_file fh, + u8_t *page_data, + spiffs_obj_id obj_id, + spiffs_page_header *page_hdr, + spiffs_page_ix src_pix, + spiffs_page_ix *dst_pix); + +s32_t spiffs_page_delete( + spiffs *fs, + spiffs_page_ix pix); + +// --------------- + +s32_t spiffs_object_create( + spiffs *fs, + spiffs_obj_id obj_id, + const u8_t name[], + const u8_t meta[], + spiffs_obj_type type, + spiffs_page_ix *objix_hdr_pix); + +s32_t spiffs_object_update_index_hdr( + spiffs *fs, + spiffs_fd *fd, + spiffs_obj_id obj_id, + spiffs_page_ix objix_hdr_pix, + u8_t *new_objix_hdr_data, + const u8_t name[], + const u8_t meta[], + u32_t size, + spiffs_page_ix *new_pix); + +#if SPIFFS_IX_MAP + +s32_t spiffs_populate_ix_map( + spiffs *fs, + spiffs_fd *fd, + u32_t vec_entry_start, + u32_t vec_entry_end); + +#endif + +void spiffs_cb_object_event( + spiffs *fs, + spiffs_page_object_ix *objix, + int ev, + spiffs_obj_id obj_id, + spiffs_span_ix spix, + spiffs_page_ix new_pix, + u32_t new_size); + +s32_t spiffs_object_open_by_id( + spiffs *fs, + spiffs_obj_id obj_id, + spiffs_fd *f, + spiffs_flags flags, + spiffs_mode mode); + +s32_t spiffs_object_open_by_page( + spiffs *fs, + spiffs_page_ix pix, + spiffs_fd *f, + spiffs_flags flags, + spiffs_mode mode); + +s32_t spiffs_object_append( + spiffs_fd *fd, + u32_t offset, + u8_t *data, + u32_t len); + +s32_t spiffs_object_modify( + spiffs_fd *fd, + u32_t offset, + u8_t *data, + u32_t len); + +s32_t spiffs_object_read( + spiffs_fd *fd, + u32_t offset, + u32_t len, + u8_t *dst); + +s32_t spiffs_object_truncate( + spiffs_fd *fd, + u32_t new_len, + u8_t remove_object); + +s32_t spiffs_object_find_object_index_header_by_name( + spiffs *fs, + const u8_t name[SPIFFS_OBJ_NAME_LEN], + spiffs_page_ix *pix); + +// --------------- + +s32_t spiffs_gc_check( + spiffs *fs, + u32_t len); + +s32_t spiffs_gc_erase_page_stats( + spiffs *fs, + spiffs_block_ix bix); + +s32_t spiffs_gc_find_candidate( + spiffs *fs, + spiffs_block_ix **block_candidate, + int *candidate_count, + char fs_crammed); + +s32_t spiffs_gc_clean( + spiffs *fs, + spiffs_block_ix bix); + +s32_t spiffs_gc_quick( + spiffs *fs, u16_t max_free_pages); + +// --------------- + +s32_t spiffs_fd_find_new( + spiffs *fs, + spiffs_fd **fd, + const char *name); + +s32_t spiffs_fd_return( + spiffs *fs, + spiffs_file f); + +s32_t spiffs_fd_get( + spiffs *fs, + spiffs_file f, + spiffs_fd **fd); + +#if SPIFFS_TEMPORAL_FD_CACHE +void spiffs_fd_temporal_cache_rehash( + spiffs *fs, + const char *old_path, + const char *new_path); +#endif + +#if SPIFFS_CACHE +void spiffs_cache_init( + spiffs *fs); + +void spiffs_cache_drop_page( + spiffs *fs, + spiffs_page_ix pix); + +#if SPIFFS_CACHE_WR +spiffs_cache_page *spiffs_cache_page_allocate_by_fd( + spiffs *fs, + spiffs_fd *fd); + +void spiffs_cache_fd_release( + spiffs *fs, + spiffs_cache_page *cp); + +spiffs_cache_page *spiffs_cache_page_get_by_fd( + spiffs *fs, + spiffs_fd *fd); +#endif +#endif + +s32_t spiffs_lookup_consistency_check( + spiffs *fs, + u8_t check_all_objects); + +s32_t spiffs_page_consistency_check( + spiffs *fs); + +s32_t spiffs_object_index_consistency_check( + spiffs *fs); + +// memcpy macro, +// checked in test builds, otherwise plain memcpy (unless already defined) +#ifdef _SPIFFS_TEST +#define _SPIFFS_MEMCPY(__d, __s, __l) do { \ + intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \ + intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \ + intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \ + intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \ + if (__a1 <= __b2 && __b1 <= __a2) { \ + printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \ + ERREXIT(); \ + } \ + memcpy((__d),(__s),(__l)); \ +} while (0) +#else +#ifndef _SPIFFS_MEMCPY +#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0) +#endif +#endif //_SPIFFS_TEST + +#endif /* SPIFFS_NUCLEUS_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/main.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/main.c new file mode 100755 index 0000000..4d363d5 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/main.c @@ -0,0 +1,12 @@ +#include + +#ifndef NO_TEST +#include "testrunner.h" +#endif + +int main(int argc, char **args) { +#ifndef NO_TEST + run_tests(argc, args); +#endif + exit(EXIT_SUCCESS); +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/params_test.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/params_test.h new file mode 100755 index 0000000..74f553f --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/params_test.h @@ -0,0 +1,84 @@ +/* + * params_test.h + * + * Created on: May 26, 2013 + * Author: petera + */ + +#ifndef PARAMS_TEST_H_ +#define PARAMS_TEST_H_ + +//////////////// TEST PARAMS //////////////// + +// default test total emulated spi flash size +#define PHYS_FLASH_SIZE (16*1024*1024) +// default test spiffs file system size +#define SPIFFS_FLASH_SIZE (2*1024*1024) +// default test spiffs file system offset in emulated spi flash +#define SPIFFS_PHYS_ADDR (4*1024*1024) +// default test sector size +#define SECTOR_SIZE 65536 +// default test logical block size +#define LOG_BLOCK (SECTOR_SIZE*2) +// default test logical page size +#define LOG_PAGE (SECTOR_SIZE/256) +// default test number of filedescs +#define DEFAULT_NUM_FD 16 +// default test number of cache pages +#define DEFAULT_NUM_CACHE_PAGES 8 + +// When testing, test bench create reference files for comparison on +// the actual hard drive. By default, put these on ram drive for speed. +#define TEST_PATH "/dev/shm/spiffs/test-data/" + +#define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__); +void real_assert(int c, const char *n, const char *file, int l); + +/////////// SPIFFS BUILD CONFIG //////////// + +// test using filesystem magic +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC 1 +#endif +// test using filesystem magic length +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH 1 +#endif +// test using extra param in callback +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 1 +#endif +// test using filehandle offset +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 1 +// use this offset +#define TEST_SPIFFS_FILEHDL_OFFSET 0x1000 +#endif + +#ifdef NO_TEST +#define SPIFFS_LOCK(fs) +#define SPIFFS_UNLOCK(fs) +#else +struct spiffs_t; +extern void test_lock(struct spiffs_t *fs); +extern void test_unlock(struct spiffs_t *fs); +#define SPIFFS_LOCK(fs) test_lock(fs) +#define SPIFFS_UNLOCK(fs) test_unlock(fs) +#endif + +// dbg output +#define SPIFFS_DBG(_f, ...) //printf("\x1b[32m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_API_DBG(_f, ...) //printf("\n\x1b[1m\x1b[7m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_GC_DBG(_f, ...) //printf("\x1b[36m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CACHE_DBG(_f, ...) //printf("\x1b[33m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CHECK_DBG(_f, ...) //printf("\x1b[31m" _f "\x1b[0m", ## __VA_ARGS__) + +// needed types +typedef signed int s32_t; +typedef unsigned int u32_t; +typedef signed short s16_t; +typedef unsigned short u16_t; +typedef signed char s8_t; +typedef unsigned char u8_t; + +#endif /* PARAMS_TEST_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_bugreports.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_bugreports.c new file mode 100755 index 0000000..f4d887b --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_bugreports.c @@ -0,0 +1,1209 @@ +/* + * test_bugreports.c + * + * Created on: Mar 8, 2015 + * Author: petera + */ + + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +#include +#include + +/* The follow defines control details of how the fuzzer can exercise the API. If you + * undef any of these, then the fuzzer is less brutal. FOr example, if you undef + * HAVE_REMOVE_OPEN, then the fuzzer will not attempt to remove (or rename) an open file + */ +#define HAVE_REMOVE_OPEN +#define HAVE_MULTIPLE_OPEN +#define NO_FORCE_CHECK + +SUITE(bug_tests) +static void setup() { + _setup_test_only(); +} +static void teardown() { + _teardown(); +} + +TEST(nodemcu_full_fs_1) { + fs_reset_specific(0, 0, 4096*20, 4096, 4096, 256); + + int res; + spiffs_file fd; + + printf(" fill up system by writing one byte a lot\n"); + fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + for (i = 0; i < 100*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + int errno = SPIFFS_errno(FS); + int res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(errno == SPIFFS_ERR_FULL); + SPIFFS_close(FS, fd); + + printf(" remove big file\n"); + res = SPIFFS_remove(FS, "test1.txt"); + + printf("res:%i errno:%i\n",res, SPIFFS_errno(FS)); + + TEST_CHECK(res == SPIFFS_OK); + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res2 = SPIFFS_stat(FS, "test1.txt", &s); + TEST_CHECK(res2 < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + printf(" create small file\n"); + fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_OK; + for (i = 0; res >= 0 && i < 1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + TEST_CHECK(res >= SPIFFS_OK); + + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(s.size == 1000); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; + +} TEST_END + +TEST(nodemcu_full_fs_2) { + fs_reset_specific(0, 0, 4096*22, 4096, 4096, 256); + + int res; + spiffs_file fd; + + printf(" fill up system by writing one byte a lot\n"); + fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + int i; + spiffs_stat s; + res = SPIFFS_OK; + for (i = 0; i < 100*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + int errno = SPIFFS_errno(FS); + int res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + + TEST_CHECK(errno == SPIFFS_ERR_FULL); + SPIFFS_close(FS, fd); + + res2 = SPIFFS_stat(FS, "test1.txt", &s); + TEST_CHECK(res2 == SPIFFS_OK); + + SPIFFS_clearerr(FS); + printf(" create small file\n"); + fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); +#if 0 + // before gc in v3.1 + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL); + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 0); + SPIFFS_clearerr(FS); +#else + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL); + SPIFFS_clearerr(FS); +#endif + printf(" remove files\n"); + res = SPIFFS_remove(FS, "test1.txt"); + TEST_CHECK(res == SPIFFS_OK); +#if 0 + res = SPIFFS_remove(FS, "test2.txt"); + TEST_CHECK(res == SPIFFS_OK); +#endif + + printf(" create medium file\n"); + fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + TEST_CHECK(fd > 0); + + for (i = 0; i < 20*1000; i++) { + u8_t buf = 'x'; + res = SPIFFS_write(FS, fd, &buf, 1); + } + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + + res2 = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res2 == SPIFFS_OK); + printf(" >>> file %s size: %i\n", s.name, s.size); + TEST_CHECK(s.size == 20*1000); + + return TEST_RES_OK; + +} TEST_END + +TEST(magic_test) { + // this test only works on default sizes + TEST_ASSERT(sizeof(spiffs_obj_id) == sizeof(u16_t)); + + // one obj lu page, not full + fs_reset_specific(0, 0, 4096*16, 4096, 4096*1, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // one obj lu page, full + fs_reset_specific(0, 0, 4096*16, 4096, 4096*2, 128); + TEST_CHECK(!SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + // two obj lu pages, not full + fs_reset_specific(0, 0, 4096*16, 4096, 4096*4, 128); + TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS)); + + return TEST_RES_OK; + +} TEST_END + +TEST(nodemcu_309) { + fs_reset_specific(0, 0, 4096*20, 4096, 4096, 256); + + int res; + spiffs_file fd; + int j; + + for (j = 1; j <= 3; j++) { + char fname[32]; + sprintf(fname, "20K%i.txt", j); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0); + TEST_CHECK(fd > 0); + int i; + res = SPIFFS_OK; + u8_t err = 0; + for (i = 1; i <= 1280; i++) { + char *buf = "0123456789ABCDE\n"; + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + if (!err && res < 0) { + printf("err @ %i,%i\n", i, j); + err = 1; + } + } + } + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_ERR_FULL); + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + printf("total:%i\nused:%i\nremain:%i\nerrno:%i\n", total, used, total-used, errno); + //TEST_CHECK(total-used < 11000); // disabled, depends on too many variables + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + int spoon_guard = 0; + while ((pe = SPIFFS_readdir(&d, pe))) { + printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + TEST_CHECK(spoon_guard++ < 3); + } + TEST_CHECK(spoon_guard == 3); + SPIFFS_closedir(&d); + + return TEST_RES_OK; + +} TEST_END + + +TEST(robert) { + // create a clean file system starting at address 0, 2 megabytes big, + // sector size 65536, block size 65536, page size 256 + fs_reset_specific(0, 0, 1024*1024*2, 65536, 65536, 256); + + int res; + spiffs_file fd; + char fname[32]; + + sprintf(fname, "test.txt"); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_OK; + char buf[500]; + memset(buf, 0xaa, 500); + res = SPIFFS_write(FS, fd, buf, 500); + TEST_CHECK(res >= SPIFFS_OK); + SPIFFS_close(FS, fd); + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_OK); + + //SPIFFS_vis(FS); + // unmount + SPIFFS_unmount(FS); + + // remount + res = fs_mount_specific(0, 1024*1024*2, 65536, 65536, 256); + TEST_CHECK(res== SPIFFS_OK); + + //SPIFFS_vis(FS); + + spiffs_stat s; + TEST_CHECK(SPIFFS_stat(FS, fname, &s) == SPIFFS_OK); + printf("file %s stat size %i\n", s.name, s.size); + TEST_CHECK(s.size == 500); + + return TEST_RES_OK; + +} TEST_END + + +TEST(spiffs_12) { + fs_reset_specific(0x4024c000, 0x4024c000 + 0, 192*1024, 4096, 4096*2, 256); + + int res; + spiffs_file fd; + int j = 1; + + while (1) { + char fname[32]; + sprintf(fname, "file%i.txt", j); + fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0); + if (fd <=0) break; + + int i; + res = SPIFFS_OK; + for (i = 1; i <= 100; i++) { + char *buf = "0123456789ABCDE\n"; + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + if (res < 0) break; + } + SPIFFS_close(FS, fd); + j++; + } + + int errno = SPIFFS_errno(FS); + TEST_CHECK(errno == SPIFFS_ERR_FULL); + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + printf("total:%i (%iK)\nused:%i (%iK)\nremain:%i (%iK)\nerrno:%i\n", total, total/1024, used, used/1024, total-used, (total-used)/1024, errno); + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + } + SPIFFS_closedir(&d); + + //SPIFFS_vis(FS); + + //dump_page(FS, 0); + //dump_page(FS, 1); + + return TEST_RES_OK; + +} TEST_END + + +TEST(zero_sized_file_44) { + fs_reset(); + + spiffs_file fd = SPIFFS_open(FS, "zero", SPIFFS_RDWR | SPIFFS_CREAT, 0); + TEST_CHECK_GE(fd, 0); + + int res = SPIFFS_close(FS, fd); + TEST_CHECK_GE(res, 0); + + fd = SPIFFS_open(FS, "zero", SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + + u8_t buf[8]; + res = SPIFFS_read(FS, fd, buf, 8); + TEST_CHECK_EQ(res, 0); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_END_OF_OBJECT); + + res = SPIFFS_read(FS, fd, buf, 0); + TEST_CHECK_GE(res, 0); + + res = SPIFFS_read(FS, fd, buf, 0); + TEST_CHECK_GE(res, 0); + + buf[0] = 1; + buf[1] = 2; + + res = SPIFFS_write(FS, fd, buf, 2); + TEST_CHECK_EQ(res, 2); + + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_SET); + TEST_CHECK_GE(res, 0); + + u8_t b; + res = SPIFFS_read(FS, fd, &b, 1); + TEST_CHECK_EQ(res, 1); + TEST_CHECK_EQ(b, 1); + + res = SPIFFS_read(FS, fd, &b, 1); + TEST_CHECK_EQ(res, 1); + TEST_CHECK_EQ(b, 2); + + res = SPIFFS_read(FS, fd, buf, 8); + TEST_CHECK_EQ(res, 0); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_END_OF_OBJECT); + + return TEST_RES_OK; +} TEST_END + +#if !SPIFFS_READ_ONLY +TEST(truncate_48) { + fs_reset(); + + u32_t len = SPIFFS_DATA_PAGE_SIZE(FS)/2; + + s32_t res = test_create_and_write_file("small", len, len); + TEST_CHECK_GE(res, 0); + + spiffs_file fd = SPIFFS_open(FS, "small", SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + + spiffs_fd *desc; +#if SPIFFS_FILEHDL_OFFSET + res = spiffs_fd_get(FS, fd - TEST_SPIFFS_FILEHDL_OFFSET, &desc); +#else + res = spiffs_fd_get(FS, fd, &desc); +#endif + + TEST_CHECK_GE(res, 0); + + TEST_CHECK_EQ(desc->size, len); + + u32_t new_len = len/2; + res = spiffs_object_truncate(desc, new_len, 0); + TEST_CHECK_GE(res, 0); + + TEST_CHECK_EQ(desc->size, new_len); + + res = SPIFFS_close(FS, fd); + TEST_CHECK_GE(res, 0); + + spiffs_stat s; + res = SPIFFS_stat(FS, "small", &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(s.size, new_len); + + res = SPIFFS_remove(FS, "small"); + TEST_CHECK_GE(res, 0); + + fd = SPIFFS_open(FS, "small", SPIFFS_RDWR, 0); + TEST_CHECK_LT(fd, 0); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} TEST_END +#endif + +TEST(eof_tell_72) { + fs_reset(); + + s32_t res; + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_CREAT | SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 0); + + res = SPIFFS_write(FS, fd, "test", 4); + TEST_CHECK_EQ(res, 4); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 4); + + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 4); + + res = SPIFFS_lseek(FS, fd, 2, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, 2); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 0); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 2); + + res = SPIFFS_write(FS, fd, "test", 4); + TEST_CHECK_EQ(res, 4); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 8); + + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 8); + + res = SPIFFS_close(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + TEST_CHECK_LT(SPIFFS_eof(FS, fd), SPIFFS_OK); + TEST_CHECK_LT(SPIFFS_tell(FS, fd), SPIFFS_OK); + + fd = SPIFFS_open(FS, "file", SPIFFS_RDWR, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 0); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 0); + + res = SPIFFS_lseek(FS, fd, 2, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, 2); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 0); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 2); + + res = SPIFFS_write(FS, fd, "test", 4); + TEST_CHECK_EQ(res, 4); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 0); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 6); + + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 0); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 6); + + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_END); + TEST_CHECK_EQ(res, 8); + TEST_CHECK_EQ(SPIFFS_eof(FS, fd), 1); + TEST_CHECK_EQ(SPIFFS_tell(FS, fd), 8); + + return TEST_RES_OK; +} TEST_END + +TEST(spiffs_dup_file_74) { + fs_reset_specific(0, 0, 64*1024, 4096, 4096*2, 256); + { + spiffs_file fd = SPIFFS_open(FS, "/config", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + char buf[5]; + strncpy(buf, "test", sizeof(buf)); + SPIFFS_write(FS, fd, buf, 4); + SPIFFS_close(FS, fd); + } + { + spiffs_file fd = SPIFFS_open(FS, "/data", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + SPIFFS_close(FS, fd); + } + { + spiffs_file fd = SPIFFS_open(FS, "/config", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + char buf[5]; + int cb = SPIFFS_read(FS, fd, buf, sizeof(buf)); + TEST_CHECK(cb > 0 && cb < sizeof(buf)); + TEST_CHECK(strncmp("test", buf, cb) == 0); + SPIFFS_close(FS, fd); + } + { + spiffs_file fd = SPIFFS_open(FS, "/data", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + spiffs_stat stat; + SPIFFS_fstat(FS, fd, &stat); + if (strcmp((const char*) stat.name, "/data") != 0) { + // oops! lets check the list of files... + spiffs_DIR dir; + SPIFFS_opendir(FS, "/", &dir); + struct spiffs_dirent dirent; + while (SPIFFS_readdir(&dir, &dirent)) { + printf("%s\n", dirent.name); + } + // this will print "/config" two times + TEST_CHECK(0); + } + SPIFFS_close(FS, fd); + } + return TEST_RES_OK; +} TEST_END + +TEST(temporal_fd_cache) { + fs_reset_specific(0, 0, 1024*1024, 4096, 2*4096, 256); + (FS)->fd_count = 4; + + char *fcss = "blaha.css"; + + char *fhtml[] = { + "index.html", "cykel.html", "bloja.html", "drivmedel.html", "smorgasbord.html", + "ombudsman.html", "fubbick.html", "paragrod.html" + }; + + const int hit_probabilities[] = { + 25, 20, 16, 12, 10, 8, 5, 4 + }; + + const int runs = 10000; + + // create our webserver files + TEST_CHECK_EQ(test_create_and_write_file(fcss, 2000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[0], 4000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[1], 3000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[2], 2000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[3], 1000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[4], 1500, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[5], 3000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[6], 2000, 256), SPIFFS_OK); + TEST_CHECK_EQ(test_create_and_write_file(fhtml[7], 3500, 256), SPIFFS_OK); + + clear_flash_ops_log(); + + int run = 0; + do { + // open & read an html + int dice = rand() % 100; + int probability = 0; + int html_ix = 0; + do { + probability += hit_probabilities[html_ix]; + if (dice <= probability) { + break; + } + html_ix++; + } while(probability < 100); + + TEST_CHECK_EQ(read_and_verify(fhtml[html_ix]), SPIFFS_OK); + + // open & read css + TEST_CHECK_EQ(read_and_verify(fcss), SPIFFS_OK); + } while (run ++ < runs); + + return TEST_RES_OK; +} TEST_END + +static int run_fuzz_test(FILE *f, int maxfds, int debuglog) { + // There are a bunch of arbitrary constants in this test case. Changing them will + // almost certainly change the effets of an input file. It *may* be worth + // making some of these constants to come from the input file. + int setup = fgetc(f); + + int page_size = 128 << (setup & 3); + setup >>= 2; + int erase_size = 4096 << (setup & 3); + setup >>= 2; + int block_size = erase_size << (setup & 1); + setup >>= 1; + int blocks = 4 + (setup & 7); + fs_reset_specific(0, 0, blocks * block_size, erase_size, block_size, page_size); + int res; + (FS)->fd_count = 4; + + int c; + + spiffs_file fd[4]; + memset(fd, -1, sizeof(fd)); + int openindex[4]; + memset(openindex, -1, sizeof(openindex)); + char *filename[8]; + + int i; + + for (i = 0; i < 8; i++) { + char buff[128]; + sprintf(buff, "%dfile%d.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxasdasdasdadxxxxxxxxxxxxxxxxxxx", i, i); + buff[9 + 2 * i] = 0; + filename[i] = strdup(buff); + } + + // The list of 8 modes that are chosen. SPIFFS_EXCL is not present -- it probably ought to be. + int modes[8] = {SPIFFS_RDONLY, SPIFFS_RDWR, SPIFFS_RDWR|SPIFFS_TRUNC, SPIFFS_RDWR|SPIFFS_CREAT, SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC, + SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_TRUNC, SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC|SPIFFS_DIRECT, SPIFFS_WRONLY}; + + char buff[2048]; + for (i = 0; i < sizeof(buff); i++) { + buff[i] = i * 19; + } + +#define LOGOP if (debuglog) printf + + while ((c = fgetc(f)) >= 0) { + int add; + char rbuff[2048]; + if (c <= ' ') { + continue; + } + int arg = fgetc(f); + if (arg < 0) { + break; + } + int fdn = ((arg >> 6) & 3) % maxfds; + int rc; + switch(c) { + case 'O': + if (fd[fdn] >= 0) { + LOGOP(" close(%d)\n", fd[fdn]); + SPIFFS_close(FS, fd[fdn]); + openindex[fdn] = -1; + fd[fdn] = -1; + } +#ifndef HAVE_MULTIPLE_OPEN + { + int index = (arg >> 3) & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" open(\"%s\", 0x%x)", filename[(arg>>3) & 7], modes[arg & 7]); + fd[fdn] = SPIFFS_open(FS, filename[(arg>>3) & 7], modes[arg & 7], 0); + if (fd[fdn] >= 0) { + openindex[fdn] = (arg >> 3) & 7; + } + LOGOP(" -> %d\n", fd[fdn]); + break; + + case 'S': + if (fd[fdn] >= 0) { + int offset = (14 << (arg & 7)) + arg; + if (arg & 16) { + offset = -offset; + } + int whence = (arg & 63) % 3; + LOGOP(" lseek(%d, %d, %d)\n", fd[fdn], offset, whence); + SPIFFS_lseek(FS, fd[fdn], offset, whence); + } + break; + + case 'R': + if (fd[fdn] >= 0) { + LOGOP(" read(%d, , %d)", fd[fdn], (15 << (arg & 7)) + (arg & 127)); + int rlen = SPIFFS_read(FS, fd[fdn], rbuff, (15 << (arg & 7)) + (arg & 127)); + LOGOP(" -> %d\n", rlen); + } + break; + + case 'W': + if (fd[fdn] >= 0) { + LOGOP(" write(%d, , %d)", fd[fdn], (15 << (arg & 7)) + (arg & 127)); + rc = SPIFFS_write(FS, fd[fdn], buff, (15 << (arg & 7)) + (arg & 127)); + LOGOP(" -> %d\n", rc); + } + break; + + case 'C': + if (fd[fdn] >= 0) { + LOGOP(" close(%d)\n", fd[fdn]); + SPIFFS_close(FS, fd[fdn]); + } + fd[fdn] = -1; + openindex[fdn] = -1; + break; + + case 'b': + add = fgetc(f); + for (i = 0; i < sizeof(buff); i++) { + buff[i] = add + i * arg; + } + break; + + case 'f': + if (fd[fdn] >= 0) { + LOGOP(" fflush(%d)\n", fd[fdn]); + SPIFFS_fflush(FS, fd[fdn]); + } + break; + +#ifdef HAVE_REMOVE_OPEN + case 'D': + if (fd[fdn] >= 0) { + LOGOP(" fremove(%d)\n", fd[fdn]); + SPIFFS_fremove(FS, fd[fdn]); + } + break; +#endif + + case 'd': +#ifndef HAVE_REMOVE_OPEN + { + int index = arg & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" remove(\"%s\")", filename[arg & 7]); + rc = SPIFFS_remove(FS, filename[arg & 7]); + LOGOP(" -> %d\n", rc); + break; + + case 'r': +#ifndef HAVE_REMOVE_OPEN + { + int index = arg & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" rename(\"%s\", \"%s\")", filename[arg & 7], filename[(arg >> 3) & 7]); + rc = SPIFFS_rename(FS, filename[arg & 7], filename[(arg >> 3) & 7]); + LOGOP(" -> %d\n", rc); + break; + + case 'U': + ungetc(arg, f); + for (i = 0; i < 4; i++) { + fd[i] = -1; + } + { +#ifdef DO_UNMOUNT + LOGOP(" unmount\n"); + SPIFFS_unmount(FS); +#endif + char *tmpfile = strdup("/tmp/fsdump.XXXXXX"); + LOGOP(" cycle and remount\n"); + close(mkstemp(tmpfile)); + fs_store_dump(tmpfile); + fs_mount_dump(tmpfile, 0, 0, blocks * block_size, erase_size, block_size, page_size); + unlink(tmpfile); + free(tmpfile); +#ifndef NO_FORCE_CHECK + LOGOP(" forcecheck()"); + rc = SPIFFS_check(FS); + LOGOP(" -> %d\n", rc); +#endif + } + break; + + case 'c': + { + LOGOP(" check()"); + rc = SPIFFS_check(FS); + LOGOP(" -> %d\n", rc); + ungetc(arg, f); + break; + } + + default: + ungetc(arg, f); + break; + } + } + + for (i = 0; i < 4; i++) { + if (fd[i] >= 0) { + LOGOP(" close(%d)\n", fd[i]); + SPIFFS_close(FS, fd[i]); + } + } + + return TEST_RES_OK; +} + +#define FMEMARGS(x) x, sizeof(x) - 1 + +TEST(fuzzer_found_1) { + return run_fuzz_test(fmemopen(FMEMARGS("\021OlWkd5O4W4W0O5OlWkO5OlW0O5O4W0"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_2) { + return run_fuzz_test(fmemopen(FMEMARGS("bO4W6W0d\036O4W6"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_3) { + return run_fuzz_test(fmemopen(FMEMARGS("\264O4OqWeWWWWW@O4WWW\027"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_4) { + unsigned char smalltest[] = { + 0x62, 0x4f, 0x24, 0x57, 0x3f, 0x57, 0x3f, 0x57, 0x3f, 0x57, 0x3f, 0x57, + 0x3f, 0x4f, 0x34, 0x57, 0x3f, 0x55, 0x4f, 0x61, 0x57, 0x61, 0x4f, 0x61, + 0x57, 0x65, 0x43, 0x61, 0x4f, 0x24, 0x57, 0x30 + }; + unsigned int smalltest_len = 32; + + return run_fuzz_test(fmemopen(smalltest, smalltest_len, "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_single_1) { + return run_fuzz_test(fmemopen(FMEMARGS("\000O\004Odr4d\356Okr0WWUO;WWWWd\035W4"), "r"), 1, 1); +} TEST_END + +TEST(log_afl_test) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 4, 1); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(afl_test) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 4, 0); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(afl_single) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 1, 0); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(small_free_space) { + fs_reset_specific(0, 0, 400*1024, 4096, 2*4096, 256); + spiffs_file fd; + int res; + (FS)->fd_count = 4; + + int tfd = SPIFFS_open(FS, "testfile", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + char *tbuf = "some data"; + res = SPIFFS_write(FS, tfd, tbuf, strlen(tbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + + const int runs = 1000; + + int fileCurrNumber = 0; + int fileDelNumber = 1; + + int run = 0; + do { + u8_t buf[1000]; + + sprintf(buf, "%d", fileCurrNumber); + int i; + for (i = 0; i < 100; i++) { + strcat(buf, " azzaaax"); + } + + int maxFileNr = 500; + char *filename = "awyn"; + char *fileext = ".dat"; + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + + if (total - used < 20000) { + maxFileNr = 1; + } + + fileCurrNumber++; + int fileCntr = fileCurrNumber + 1 - fileDelNumber; + + char fileCurrName[64]; + sprintf(fileCurrName, "%s%d%s", filename, fileCurrNumber, fileext); + + fd = SPIFFS_open(FS, fileCurrName, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + + //printf("About to write to %s\n", fileCurrName); + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + + TEST_CHECK(res == strlen(buf)); + + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + + SPIFFS_close(FS, fd); + + if (fileCntr > maxFileNr) { + char fileDelName[64]; + sprintf(fileDelName, "%s%d%s", filename, fileDelNumber, fileext); + //printf("Deleting %s (free space %d)\n", fileDelName, total - used); + + res = SPIFFS_remove(FS, fileDelName); + + TEST_CHECK(res == SPIFFS_OK); + fileDelNumber++; + } + } while (run ++ < runs); + + tfd = SPIFFS_open(FS, "testfile", SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char rbuf[32]; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + SPIFFS_close(FS, tfd); + + TEST_CHECK(memcmp(rbuf, tbuf, strlen(tbuf)) == 0); + + return TEST_RES_OK; +} TEST_END + +TEST(lots_of_overwrite) { + fs_reset_specific(0, 0, 3000*1024, 4096, 2*4096, 256); + spiffs_file fd; + int res; + (FS)->fd_count = 4; + + int i; + + for (i = 0; i < 5; i++) { + + char filename[64]; + sprintf(filename, "%d-tstfile", i); + int tfd = SPIFFS_open(FS, filename, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + char tbuf[1024]; + memset(tbuf, 'a', 700); + tbuf[700] = 0; + res = SPIFFS_write(FS, tfd, tbuf, strlen(tbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + } + + const int runs = 100000; + + int run = 0; + for (run = 0; run < runs; run++) { + u8_t buf[2000]; + + sprintf(buf, "%d", run); + int i; + for (i = 0; i < 100 + (run % 100); i++) { + strcat(buf, " azzaaax"); + } + + int tfd = SPIFFS_open(FS, "file.dat", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + res = SPIFFS_write(FS, tfd, buf, strlen(buf)); + + TEST_CHECK(res == strlen(buf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + + tfd = SPIFFS_open(FS, "file.dat", SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char rbuf[2000]; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(buf)); + + SPIFFS_close(FS, tfd); + + TEST_CHECK(memcmp(rbuf, buf, strlen(buf)) == 0); + + char filename[64]; + sprintf(filename, "%d-tstfile", run % 5); + tfd = SPIFFS_open(FS, filename, SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char tbuf[1024]; + memset(tbuf, 'a', 700); + tbuf[700] = 0; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + SPIFFS_close(FS, tfd); + TEST_CHECK(memcmp(rbuf, tbuf, strlen(tbuf)) == 0); + } + + return TEST_RES_OK; +} TEST_END + + +#if 0 +TEST(spiffs_hidden_file_90) { + fs_mount_dump("imgs/90.hidden_file.spiffs", 0, 0, 1*1024*1024, 4096, 4096, 128); + + SPIFFS_vis(FS); + + dump_page(FS, 1); + dump_page(FS, 0x8fe); + dump_page(FS, 0x8ff); + + { + spiffs_DIR dir; + SPIFFS_opendir(FS, "/", &dir); + struct spiffs_dirent dirent; + while (SPIFFS_readdir(&dir, &dirent)) { + printf("%-32s sz:%-7i obj_id:%08x pix:%08x\n", dirent.name, dirent.size, dirent.obj_id, dirent.pix); + } + } + + printf("remove cli.bin res %i\n", SPIFFS_remove(FS, "cli.bin")); + + { + spiffs_DIR dir; + SPIFFS_opendir(FS, "/", &dir); + struct spiffs_dirent dirent; + while (SPIFFS_readdir(&dir, &dirent)) { + printf("%-32s sz:%-7i obj_id:%08x pix:%08x\n", dirent.name, dirent.size, dirent.obj_id, dirent.pix); + } + } + return TEST_RES_OK; + +} TEST_END +#endif +#if 0 +TEST(null_deref_check_93) { + fs_mount_dump("imgs/93.dump.bin", 0, 0, 2*1024*1024, 4096, 4096, 256); + + //int res = SPIFFS_open(FS, "d43.fw", SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_WRONLY, 0); + //TEST_CHECK_GE(res, SPIFFS_OK); + + SPIFFS_vis(FS); + + printf("\n\n-------------------------------------------------\n\n"); + + SPIFFS_check(FS); + //fs_store_dump("imgs/93.dump.checked.bin"); + + SPIFFS_vis(FS); + + printf("\n\n-------------------------------------------------\n\n"); + + SPIFFS_check(FS); + + SPIFFS_vis(FS); + printf("\n\n-------------------------------------------------\n\n"); + + + + return TEST_RES_OK; +} TEST_END +#endif + +TEST(spiffs_145) { + int res; + fs_reset_specific(0, 0, 1024*1024, 65536, 65536, 1024); + { + spiffs_file fd = SPIFFS_open(FS, "biggie", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + char buf[1024*512]; + memset(buf, 0xee, sizeof(buf)); + TEST_CHECK_GT(SPIFFS_write(FS, fd, buf, sizeof(buf)), 0); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + } + const int runs = 1000; + int run = 0; + while (run++ < runs) { + spiffs_file fd = SPIFFS_open(FS, "clobber", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + char buf[8192]; + memset(buf, 0xee, sizeof(buf)); + TEST_CHECK_GT(SPIFFS_write(FS, fd, buf, sizeof(buf)), 0); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_remove(FS, "clobber"), SPIFFS_OK); + } + + // below stolen from SPIFFS_vis + spiffs *fs = FS; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_block_ix bix = 0; + + while (bix < fs->block_count) { + // check each object lookup page + spiffs_obj_id erase_count; + TEST_CHECK_EQ(_spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&erase_count), SPIFFS_OK); + TEST_CHECK_NEQ(erase_count, (spiffs_obj_id)-1); + TEST_CHECK_NEQ(erase_count, 0); + bix++; + } // per block + + return TEST_RES_OK; +} TEST_END + + +TEST(seek_bug_148) { + int res; +#define MAGIC_SIZE_THAT_FAILS 26355 // happens to be SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS) + fs_reset_specific(0, 0, 64*1024, 4096, 4096, 256); + u8_t buf[MAGIC_SIZE_THAT_FAILS]; + spiffs_file fd = SPIFFS_open(FS, "EVENT", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_write(FS, fd, &buf, sizeof(buf)), sizeof(buf)); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + fd = SPIFFS_open(FS, "EVENT", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_lseek(FS, fd, 0, SEEK_END), MAGIC_SIZE_THAT_FAILS); + return TEST_RES_OK; +} TEST_END + + +SUITE_TESTS(bug_tests) + ADD_TEST(nodemcu_full_fs_1) + ADD_TEST(nodemcu_full_fs_2) + ADD_TEST(magic_test) + ADD_TEST(nodemcu_309) + ADD_TEST(robert) + ADD_TEST(spiffs_12) + ADD_TEST(zero_sized_file_44) + ADD_TEST(truncate_48) + ADD_TEST(eof_tell_72) + ADD_TEST(spiffs_dup_file_74) + ADD_TEST(temporal_fd_cache) + ADD_TEST(spiffs_145) + ADD_TEST(seek_bug_148) + //ADD_TEST(small_free_space) + ADD_TEST(lots_of_overwrite) + ADD_TEST(fuzzer_found_1) + ADD_TEST(fuzzer_found_2) + ADD_TEST(fuzzer_found_3) + ADD_TEST(fuzzer_found_4) + ADD_TEST_NON_DEFAULT(fuzzer_found_single_1) + ADD_TEST_NON_DEFAULT(log_afl_test) + ADD_TEST_NON_DEFAULT(afl_test) + ADD_TEST_NON_DEFAULT(afl_single) +#if 0 + ADD_TEST(spiffs_hidden_file_90) +#endif +#if 0 + ADD_TEST(null_deref_check_93) +#endif +SUITE_END(bug_tests) diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_check.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_check.c new file mode 100755 index 0000000..15865c4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_check.c @@ -0,0 +1,427 @@ +/* + * test_dev.c + * + * Created on: Jul 14, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +#include +#include + + +SUITE(check_tests) +static void setup() { + _setup(); +} +static void teardown() { + _teardown(); +} + +TEST(evil_write) { + fs_set_validate_flashing(0); + printf("writing corruption to block 1 data range (leaving lu intact)\n"); + u32_t data_range = SPIFFS_CFG_LOG_BLOCK_SZ(FS) - + SPIFFS_CFG_LOG_PAGE_SZ(FS) * (SPIFFS_OBJ_LOOKUP_PAGES(FS)); + u8_t *corruption = malloc(data_range); + memrand(corruption, data_range); + u32_t addr = 0 * SPIFFS_CFG_LOG_PAGE_SZ(FS) * SPIFFS_OBJ_LOOKUP_PAGES(FS); + area_write(addr, corruption, data_range); + free(corruption); + + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + + printf("CHECK1-----------------\n"); + SPIFFS_check(FS); + printf("CHECK2-----------------\n"); + SPIFFS_check(FS); + printf("CHECK3-----------------\n"); + SPIFFS_check(FS); + + res = test_create_and_write_file("file2", size, size); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(lu_check1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index 1 + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix); + TEST_CHECK(res >= 0); + + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry*sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + return TEST_RES_OK; +} TEST_END + + +TEST(page_cons1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 0 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = 0x55; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr + sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(page_cons2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // find data page span index 0 + spiffs_page_ix dpix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &dpix); + TEST_CHECK(res >= 0); + + // set object index entry 1+2 to a data page 0 + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = dpix; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + + +TEST(page_cons3) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 1+2 lookup page + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = SPIFFS_PAGES_PER_BLOCK(FS) * (*FS.block_count - 2); + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(page_cons_final) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify page header, make unfinalized + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix); + TEST_CHECK(res >= 0); + + // set page span ix 1 as unfinalized + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags); + u8_t flags; + area_read(addr, (u8_t*)&flags, 1); + flags |= SPIFFS_PH_FLAG_FINAL; + area_write(addr, (u8_t*)&flags, 1); + + // delete all cache +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(index_cons1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" deleting lu entry pix %04x\n", pix); + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(index_cons2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" writing lu entry for index page, ix %04x, as data page\n", pix); + spiffs_obj_id obj_id = 0x1234; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + + +TEST(index_cons3) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" setting lu entry pix %04x to another index page\n", pix); + // reset lu entry to being erased, but keep page data + spiffs_obj_id obj_id = 1234 | SPIFFS_OBJ_ID_IX_FLAG; + spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix); + int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix); + u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id); + + area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id)); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} TEST_END + +TEST(index_cons4) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS); + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify lu entry data page index header, flags + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + printf(" cue objix hdr deletion in page %04x\n", pix); + // set flags as deleting ix header + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags); + u8_t flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE); + + area_write(addr, (u8_t*)&flags, 1); + +#if SPIFFS_CACHE + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + SPIFFS_check(FS); + + return TEST_RES_OK; +} TEST_END + +SUITE_TESTS(check_tests) + ADD_TEST(evil_write) + ADD_TEST(lu_check1) + ADD_TEST(page_cons1) + ADD_TEST(page_cons2) + ADD_TEST(page_cons3) + ADD_TEST(page_cons_final) + ADD_TEST(index_cons1) + ADD_TEST(index_cons2) + ADD_TEST(index_cons3) + ADD_TEST(index_cons4) +SUITE_END(check_tests) diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_dev.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_dev.c new file mode 100755 index 0000000..552e9d4 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_dev.c @@ -0,0 +1,122 @@ +/* + * test_dev.c + * + * Created on: Jul 14, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +#include +#include + + +SUITE(dev_tests) +static void setup() { + _setup(); +} +static void teardown() { + _teardown(); +} + +TEST(interrupted_write) { + char *name = "interrupt"; + char *name2 = "interrupt2"; + int res; + spiffs_file fd; + + const u32_t sz = SPIFFS_CFG_LOG_PAGE_SZ(FS)*8; + u8_t *buf = malloc(sz); + memrand(buf, sz); + + printf(" create reference file\n"); + fd = SPIFFS_open(FS, name, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + clear_flash_ops_log(); + res = SPIFFS_write(FS, fd, buf, sz); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + u32_t written = get_flash_ops_log_write_bytes(); + printf(" written bytes: %i\n", written); + + + printf(" create error file\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + clear_flash_ops_log(); + invoke_error_after_write_bytes(written/2, 0); + res = SPIFFS_write(FS, fd, buf, sz); + SPIFFS_close(FS, fd); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_TEST); + + clear_flash_ops_log(); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + + printf(" read error file\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + printf(" file size: %i\n", s.size); + + if (s.size > 0) { + u8_t *buf2 = malloc(s.size); + res = SPIFFS_read(FS, fd, buf2, s.size); + TEST_CHECK(res >= 0); + + u32_t ix = 0; + for (ix = 0; ix < s.size; ix += 16) { + int i; + printf(" "); + for (i = 0; i < 16; i++) { + printf("%02x", buf[ix+i]); + } + printf(" "); + for (i = 0; i < 16; i++) { + printf("%02x", buf2[ix+i]); + } + printf("\n"); + } + free(buf2); + } + SPIFFS_close(FS, fd); + + + printf(" FS check\n"); + SPIFFS_check(FS); + + printf(" read error file again\n"); + fd = SPIFFS_open(FS, name2, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + printf(" file size: %i\n", s.size); + printf(" write file\n"); + res = SPIFFS_write(FS, fd, buf, sz); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + free(buf); + + return TEST_RES_OK; + +} TEST_END + +SUITE_TESTS(dev_tests) + ADD_TEST(interrupted_write) +SUITE_END(dev_tests) diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_hydrogen.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_hydrogen.c new file mode 100755 index 0000000..52126b2 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_hydrogen.c @@ -0,0 +1,2507 @@ +/* + * test_suites.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + + +#include "testrunner.h" +#include "test_spiffs.h" +#include "spiffs_nucleus.h" +#include "spiffs.h" +#include +#include +#include +#include +#include + +SUITE(hydrogen_tests) +static void setup() { + _setup(); +} +static void teardown() { + _teardown(); +} + +TEST(info) +{ + u32_t used, total; + int res = SPIFFS_info(FS, &total, &used); + TEST_CHECK(res == SPIFFS_OK); + TEST_CHECK(used == 0); + TEST_CHECK(total < SPIFFS_CFG_PHYS_SZ(&__fs)); + return TEST_RES_OK; +} +TEST_END + +#if SPIFFS_USE_MAGIC +TEST(magic) +{ + fs_reset_specific(0, 0, 65536*16, 65536, 65536, 256); + SPIFFS_unmount(FS); + + TEST_CHECK_EQ(fs_mount_specific(0, 65536*16, 65536, 65536, 256), SPIFFS_OK); + SPIFFS_unmount(FS); + + TEST_CHECK_NEQ(fs_mount_specific(0, 65536*16, 65536, 65536, 128), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + TEST_CHECK_NEQ(fs_mount_specific(4, 65536*16, 65536, 65536, 256), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + return TEST_RES_OK; +} +TEST_END + + +#if SPIFFS_USE_MAGIC_LENGTH +TEST(magic_length) +{ + fs_reset_specific(0, 0, 65536*16, 65536, 65536, 256); + SPIFFS_unmount(FS); + + TEST_CHECK_EQ(fs_mount_specific(0, 65536*16, 65536, 65536, 256), SPIFFS_OK); + SPIFFS_unmount(FS); + + TEST_CHECK_NEQ(fs_mount_specific(0, 65536*8, 65536, 65536, 256), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + TEST_CHECK_NEQ(fs_mount_specific(0, 65536*15, 65536, 65536, 256), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + TEST_CHECK_NEQ(fs_mount_specific(0, 65536*17, 65536, 65536, 256), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + TEST_CHECK_NEQ(fs_mount_specific(0, 65536*256, 65536, 65536, 256), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FS); + + return TEST_RES_OK; +} +TEST_END + +#if SPIFFS_SINGLETON==0 +TEST(magic_length_probe) +{ + fs_reset_specific(0, 0, 65536*16, 65536, 65536, 256); + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 65536*16); + + fs_reset_specific(0, 0, 65536*24, 65536, 65536, 256); + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 65536*24); + + fs_reset_specific(0, 0, 32768*16, 32768, 32768, 128); + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 32768*16); + + fs_reset_specific(0, 0, 16384*37, 16384, 16384, 128); + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 16384*37); + + fs_reset_specific(0, 0, 4096*11, 4096, 4096, 256); + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 4096*11); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + __fs.cfg.log_page_size = 128; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + __fs.cfg.log_page_size = 512; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + __fs.cfg.log_page_size = 256; + __fs.cfg.log_block_size = 8192; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + __fs.cfg.log_block_size = 2048; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + __fs.cfg.log_block_size = 4096; + __fs.cfg.phys_addr += 2; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + __fs.cfg.phys_addr += 4096*6; + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096); // "erase" block 0 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 4096*8); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096); // "erase" block 1 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 4096*8); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096); // "erase" block 2 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), 4096*8); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096*2); // "erase" block 0 & 1 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096*2); // "erase" block 0 + area_set(4096*0, 0xff, 4096); // "erase" block 2 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*1, 0xff, 4096*2); // "erase" block 1 & 2 + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xff, 4096*8); // "erase" all + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + fs_reset_specific(0, 0, 4096*8, 4096, 4096, 256); + area_set(4096*0, 0xdd, 4096*8); // garble all + TEST_CHECK_EQ(SPIFFS_probe_fs(&__fs.cfg), SPIFFS_ERR_PROBE_NOT_A_FS); + + return TEST_RES_OK; +} +TEST_END + +#endif // SPIFFS_SINGLETON==0 + +#endif // SPIFFS_USE_MAGIC_LENGTH + +#endif // SPIFFS_USE_MAGIC + +TEST(missing_file) +{ + spiffs_file fd = SPIFFS_open(FS, "this_wont_exist", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(bad_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd = SPIFFS_open(FS, "this_wont_exist", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); +#if SPIFFS_OBJ_META_LEN + u8_t new_meta[SPIFFS_OBJ_META_LEN] = {0}; + res = SPIFFS_fupdate_meta(FS, fd, new_meta); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); +#endif + return TEST_RES_OK; +} +TEST_END + + +TEST(closed_fd) +{ + int res; + spiffs_stat s; + res = test_create_file("file"); + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + SPIFFS_close(FS, fd); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); +#if SPIFFS_OBJ_META_LEN + u8_t new_meta[SPIFFS_OBJ_META_LEN] = {0}; + res = SPIFFS_fupdate_meta(FS, fd, new_meta); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); +#endif + return TEST_RES_OK; +} +TEST_END + + +TEST(deleted_same_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd; + res = test_create_file("remove"); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + + return TEST_RES_OK; +} +TEST_END + + +TEST(deleted_other_fd) +{ + int res; + spiffs_stat s; + spiffs_file fd, fd_orig; + res = test_create_file("remove"); + fd_orig = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd_orig >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd_orig); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd_orig); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_CUR); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_read(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + res = SPIFFS_write(FS, fd, 0, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); + + return TEST_RES_OK; +} +TEST_END + + +TEST(file_by_open) +{ + int res; + spiffs_stat s; + spiffs_file fd = SPIFFS_open(FS, "filebopen", SPIFFS_CREAT, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp((char*)s.name, "filebopen") == 0); + TEST_CHECK(s.size == 0); + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, "filebopen", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp((char*)s.name, "filebopen") == 0); + TEST_CHECK(s.size == 0); + SPIFFS_close(FS, fd); + return TEST_RES_OK; +} +TEST_END + + +TEST(file_by_creat) +{ + int res; + res = test_create_file("filebcreat"); + TEST_CHECK(res >= 0); + res = SPIFFS_creat(FS, "filebcreat", 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS)==SPIFFS_ERR_CONFLICTING_NAME); + return TEST_RES_OK; +} +TEST_END + +TEST(file_by_open_excl) +{ + int res; + spiffs_stat s; + spiffs_file fd = SPIFFS_open(FS, "filebexcl", SPIFFS_CREAT | SPIFFS_EXCL, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp((char*)s.name, "filebexcl") == 0); + TEST_CHECK(s.size == 0); + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, "filebexcl", SPIFFS_CREAT | SPIFFS_EXCL, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_EXISTS); + + return TEST_RES_OK; +} +TEST_END + +#if SPIFFS_FILEHDL_OFFSET +TEST(open_fh_offs) +{ + spiffs_file fd1, fd2, fd3; + fd1 = SPIFFS_open(FS, "1", SPIFFS_CREAT | SPIFFS_EXCL, 0); + fd2 = SPIFFS_open(FS, "2", SPIFFS_CREAT | SPIFFS_EXCL, 0); + fd3 = SPIFFS_open(FS, "3", SPIFFS_CREAT | SPIFFS_EXCL, 0); + TEST_CHECK(fd1 >= TEST_SPIFFS_FILEHDL_OFFSET); + TEST_CHECK(fd2 >= TEST_SPIFFS_FILEHDL_OFFSET); + TEST_CHECK(fd3 >= TEST_SPIFFS_FILEHDL_OFFSET); + SPIFFS_close(FS, fd1); + fd1 = SPIFFS_open(FS, "2", SPIFFS_RDONLY, 0); + TEST_CHECK(fd1 >= TEST_SPIFFS_FILEHDL_OFFSET); + SPIFFS_close(FS, fd2); + fd2 = SPIFFS_open(FS, "3", SPIFFS_RDONLY, 0); + TEST_CHECK(fd2 >= TEST_SPIFFS_FILEHDL_OFFSET); + SPIFFS_close(FS, fd3); + fd3 = SPIFFS_open(FS, "1", SPIFFS_RDONLY, 0); + TEST_CHECK(fd3 >= TEST_SPIFFS_FILEHDL_OFFSET); + SPIFFS_close(FS, fd1); + SPIFFS_close(FS, fd2); + SPIFFS_close(FS, fd3); + fd1 = SPIFFS_open(FS, "3", SPIFFS_RDONLY, 0); + TEST_CHECK(fd1 >= TEST_SPIFFS_FILEHDL_OFFSET); + SPIFFS_close(FS, fd1); + fd1 = SPIFFS_open(FS, "foo", SPIFFS_RDONLY, 0); + TEST_CHECK(fd1 < TEST_SPIFFS_FILEHDL_OFFSET); + + return TEST_RES_OK; +} +TEST_END + +#endif //SPIFFS_FILEHDL_OFFSET + +TEST(list_dir) +{ + int res; + + char *files[4] = { + "file1", + "file2", + "file3", + "file4" + }; + int file_cnt = sizeof(files)/sizeof(char *); + + int i; + + for (i = 0; i < file_cnt; i++) { + res = test_create_file(files[i]); + TEST_CHECK(res >= 0); + } + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + SPIFFS_opendir(FS, "/", &d); + int found = 0; + while ((pe = SPIFFS_readdir(&d, pe))) { + printf(" %s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size); + for (i = 0; i < file_cnt; i++) { + if (strcmp(files[i], (char *)pe->name) == 0) { + found++; + break; + } + } + { + spiffs_stat s; + TEST_CHECK_EQ(SPIFFS_stat(FS, pe->name, &s), 0); + TEST_CHECK_EQ(pe->obj_id, s.obj_id); + TEST_CHECK_EQ(pe->size, s.size); + TEST_CHECK_EQ(pe->type, s.type); + TEST_CHECK_EQ(pe->pix, s.pix); +#if SPIFFS_OBJ_META_LEN + TEST_CHECK_EQ(memcmp(pe->meta, s.meta, SPIFFS_OBJ_META_LEN), 0); +#endif + } + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == file_cnt); + + return TEST_RES_OK; +} +TEST_END + + +TEST(open_by_dirent) { + int res; + + char *files[4] = { + "file1", + "file2", + "file3", + "file4" + }; + int file_cnt = sizeof(files)/sizeof(char *); + + int i; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + + for (i = 0; i < file_cnt; i++) { + res = test_create_and_write_file(files[i], size, size); + TEST_CHECK(res >= 0); + } + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + int found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + spiffs_file fd = SPIFFS_open_by_dirent(FS, pe, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = read_and_verify_fd(fd, (char *)pe->name); + TEST_CHECK(res == SPIFFS_OK); + fd = SPIFFS_open_by_dirent(FS, pe, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res == SPIFFS_OK); + SPIFFS_close(FS, fd); + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == file_cnt); + + found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == 0); + + return TEST_RES_OK; + +} TEST_END + + +TEST(open_by_page) { + int res; + + char *files[4] = { + "file1", + "file2", + "file3", + "file4" + }; + int file_cnt = sizeof(files)/sizeof(char *); + + int i; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + + for (i = 0; i < file_cnt; i++) { + res = test_create_and_write_file(files[i], size, size); + TEST_CHECK(res >= 0); + } + + spiffs_DIR d; + struct spiffs_dirent e; + struct spiffs_dirent *pe = &e; + + int found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + spiffs_file fd = SPIFFS_open_by_dirent(FS, pe, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = read_and_verify_fd(fd, (char *)pe->name); + TEST_CHECK(res == SPIFFS_OK); + fd = SPIFFS_open_by_page(FS, pe->pix, SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res == SPIFFS_OK); + SPIFFS_close(FS, fd); + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == file_cnt); + + found = 0; + SPIFFS_opendir(FS, "/", &d); + while ((pe = SPIFFS_readdir(&d, pe))) { + found++; + } + SPIFFS_closedir(&d); + + TEST_CHECK(found == 0); + + spiffs_file fd; + // test opening a lookup page + fd = SPIFFS_open_by_page(FS, 0, SPIFFS_RDWR, 0); + TEST_CHECK_LT(fd, 0); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FILE); + // test opening a proper page but not being object index + fd = SPIFFS_open_by_page(FS, SPIFFS_OBJ_LOOKUP_PAGES(FS)+1, SPIFFS_RDWR, 0); + TEST_CHECK_LT(fd, 0); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NOT_A_FILE); + + return TEST_RES_OK; +} TEST_END + + +static struct { + u32_t calls; + spiffs_fileop_type op; + spiffs_obj_id obj_id; + spiffs_page_ix pix; +} ucb; + +void test_cb(spiffs *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix) { + ucb.calls++; + ucb.op = op; + ucb.obj_id = obj_id; + ucb.pix = pix; + //printf("%4i op:%i objid:%04x pix:%04x\n", ucb.calls, ucb.op, ucb.obj_id, ucb.pix); +} + +TEST(user_callback_basic) { + SPIFFS_set_file_callback_func(FS, test_cb); + int res; + memset(&ucb, 0, sizeof(ucb)); + spiffs_file fd = SPIFFS_open(FS, "foo", SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + TEST_CHECK_EQ(ucb.calls, 1); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_CREATED); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_write(FS, fd, "howdy partner", 14); + TEST_CHECK_GE(res, 0); + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 2); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_fremove(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 3); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_DELETED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + return TEST_RES_OK; +} TEST_END + + +TEST(user_callback_gc) { + SPIFFS_set_file_callback_func(FS, test_cb); + + char name[32]; + int f; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + int pages_per_block = SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS); + int files = (pages_per_block-1)/2; + int res; + + // fill block with files + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + memset(&ucb, 0, sizeof(ucb)); + spiffs_file fd = SPIFFS_open(FS, "foo", SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK_GE(fd, 0); + TEST_CHECK_EQ(ucb.calls, 1); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_CREATED); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_write(FS, fd, "howdy partner", 14); + TEST_CHECK_GE(res, 0); + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 2); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + u32_t tot, us; + SPIFFS_info(FS, &tot, &us); + + // do a hard gc, should move our file + res = SPIFFS_gc(FS, tot-us*2); + TEST_CHECK_GE(res, 0); + + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 3); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_UPDATED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_NEQ(ucb.pix, s.pix); + + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.pix, s.pix); + + res = SPIFFS_fremove(FS, fd); + TEST_CHECK_GE(res, 0); + TEST_CHECK_EQ(ucb.calls, 4); + TEST_CHECK_EQ(ucb.op, SPIFFS_CB_DELETED); + TEST_CHECK_EQ(ucb.obj_id, s.obj_id); + TEST_CHECK_EQ(ucb.pix, s.pix); + + return TEST_RES_OK; +} TEST_END + + +TEST(name_too_long) { + char name[SPIFFS_OBJ_NAME_LEN*2]; + memset(name, 0, sizeof(name)); + int i; + for (i = 0; i < SPIFFS_OBJ_NAME_LEN; i++) { + name[i] = 'A'; + } + + TEST_CHECK_LT(SPIFFS_creat(FS, name, 0), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + TEST_CHECK_LT(SPIFFS_open(FS, name, SPIFFS_CREAT | SPIFFS_TRUNC, 0), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + TEST_CHECK_LT(SPIFFS_remove(FS, name), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + spiffs_stat s; + TEST_CHECK_LT(SPIFFS_stat(FS, name, &s), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + TEST_CHECK_LT(SPIFFS_rename(FS, name, "a"), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + TEST_CHECK_LT(SPIFFS_rename(FS, "a", name), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_NAME_TOO_LONG); + + return TEST_RES_OK; +} TEST_END + + +TEST(rename) { + int res; + + char *src_name = "baah"; + char *dst_name = "booh"; + char *dst_name2 = "beeh"; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + + res = test_create_and_write_file(src_name, size, size); + TEST_CHECK(res >= 0); + + res = SPIFFS_rename(FS, src_name, dst_name); + TEST_CHECK(res >= 0); + + res = SPIFFS_rename(FS, dst_name, dst_name); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_CONFLICTING_NAME); + + res = SPIFFS_rename(FS, src_name, dst_name2); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} TEST_END + +#if SPIFFS_OBJ_META_LEN +TEST(update_meta) { + s32_t i, res, fd; + spiffs_stat s; + u8_t new_meta[SPIFFS_OBJ_META_LEN], new_meta2[SPIFFS_OBJ_META_LEN]; + + res = test_create_file("foo"); + TEST_CHECK(res >= 0); + + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + new_meta[i] = 0xaa; + } + res = SPIFFS_update_meta(FS, "foo", new_meta); + TEST_CHECK(res >= 0); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta, SPIFFS_OBJ_META_LEN), 0); + + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + new_meta2[i] = 0xbb; + } + + fd = SPIFFS_open(FS, "foo", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fupdate_meta(FS, fd, new_meta2); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_WRITABLE); + SPIFFS_close(FS, fd); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta, SPIFFS_OBJ_META_LEN), 0); + + fd = SPIFFS_open(FS, "foo", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fupdate_meta(FS, fd, new_meta2); + TEST_CHECK_EQ(res, 0); + SPIFFS_close(FS, fd); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta2, SPIFFS_OBJ_META_LEN), 0); + + return TEST_RES_OK; +} TEST_END +#endif + +TEST(remove_single_by_path) +{ + int res; + spiffs_file fd; + res = test_create_file("remove"); + TEST_CHECK(res >= 0); + res = SPIFFS_remove(FS, "remove"); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END + + +TEST(remove_single_by_fd) +{ + int res; + spiffs_file fd; + res = test_create_file("remove"); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + fd = SPIFFS_open(FS, "remove", SPIFFS_RDONLY, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_cache) +{ + int res; + spiffs_file fd; + u8_t buf[1024*8]; + u8_t fbuf[1024*8]; + res = test_create_file("f"); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, "f", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd, buf, SPIFFS_CFG_LOG_PAGE_SZ(FS)/2); + TEST_CHECK(res >= 0); + res = SPIFFS_write(FS, fd, buf, SPIFFS_CFG_LOG_PAGE_SZ(FS)*2); + TEST_CHECK(res >= 0); + res = SPIFFS_close(FS, fd); + TEST_CHECK(res >= 0); + + fd = SPIFFS_open(FS, "f", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_read(FS, fd, fbuf, SPIFFS_CFG_LOG_PAGE_SZ(FS)/2 + SPIFFS_CFG_LOG_PAGE_SZ(FS)*2); + TEST_CHECK(res >= 0); + TEST_CHECK(0 == memcmp(&buf[0], &fbuf[0], SPIFFS_CFG_LOG_PAGE_SZ(FS)/2)); + TEST_CHECK(0 == memcmp(&buf[0], &fbuf[SPIFFS_CFG_LOG_PAGE_SZ(FS)/2], SPIFFS_CFG_LOG_PAGE_SZ(FS)*2)); + res = SPIFFS_close(FS, fd); + TEST_CHECK(res >= 0); + + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_file_chunks_page) +{ + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS)); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_files_chunks_page) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, SPIFFS_DATA_PAGE_SIZE(FS)); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_file_chunks_index) +{ + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS)); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_files_chunks_index) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS)); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_file_chunks_huge) +{ + int size = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_big_files_chunks_huge) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, size); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END + + +TEST(truncate_big_file) +{ + int size = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + spiffs_file fd = SPIFFS_open(FS, "bigfile", SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_fremove(FS, fd); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, "bigfile", SPIFFS_RDWR, 0); + TEST_CHECK(fd < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND); + + return TEST_RES_OK; +} +TEST_END + + +TEST(simultaneous_write) { + int res = SPIFFS_creat(FS, "simul1", 0); + TEST_CHECK(res >= 0); + + spiffs_file fd1 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd1 > 0); + spiffs_file fd2 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd2 > 0); + spiffs_file fd3 = SPIFFS_open(FS, "simul1", SPIFFS_RDWR, 0); + TEST_CHECK(fd3 > 0); + + u8_t data1 = 1; + u8_t data2 = 2; + u8_t data3 = 3; + + res = SPIFFS_write(FS, fd1, &data1, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd1); + res = SPIFFS_write(FS, fd2, &data2, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd2); + res = SPIFFS_write(FS, fd3, &data3, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd3); + + spiffs_stat s; + res = SPIFFS_stat(FS, "simul1", &s); + TEST_CHECK(res >= 0); + + TEST_CHECK(s.size == 1); + + u8_t rdata; + spiffs_file fd = SPIFFS_open(FS, "simul1", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_read(FS, fd, &rdata, 1); + TEST_CHECK(res >= 0); + + TEST_CHECK(rdata == data3); + + return TEST_RES_OK; +} +TEST_END + + +TEST(simultaneous_write_append) { + int res = SPIFFS_creat(FS, "simul2", 0); + TEST_CHECK(res >= 0); + + spiffs_file fd1 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd1 > 0); + spiffs_file fd2 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd2 > 0); + spiffs_file fd3 = SPIFFS_open(FS, "simul2", SPIFFS_RDWR | SPIFFS_APPEND, 0); + TEST_CHECK(fd3 > 0); + + u8_t data1 = 1; + u8_t data2 = 2; + u8_t data3 = 3; + + res = SPIFFS_write(FS, fd1, &data1, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd1); + res = SPIFFS_write(FS, fd2, &data2, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd2); + res = SPIFFS_write(FS, fd3, &data3, 1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd3); + + spiffs_stat s; + res = SPIFFS_stat(FS, "simul2", &s); + TEST_CHECK(res >= 0); + + TEST_CHECK(s.size == 3); + + u8_t rdata[3]; + spiffs_file fd = SPIFFS_open(FS, "simul2", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + res = SPIFFS_read(FS, fd, &rdata, 3); + TEST_CHECK(res >= 0); + + TEST_CHECK(rdata[0] == data1); + TEST_CHECK(rdata[1] == data2); + TEST_CHECK(rdata[2] == data3); + + return TEST_RES_OK; +} +TEST_END + +TEST(file_uniqueness) +{ + int res; + spiffs_file fd; + char fname[32]; + int files = ((SPIFFS_CFG_PHYS_SZ(FS) * 75) / 100) / 2 / SPIFFS_CFG_LOG_PAGE_SZ(FS); + //(FS_PURE_DATA_PAGES(FS) / 2) - SPIFFS_PAGES_PER_BLOCK(FS)*8; + int i; + printf(" creating %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "%i", i); + res = test_create_file(fname); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, fname, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, content, strlen(content)+1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + } + printf(" checking %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + char ref_content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "%i", i); + fd = SPIFFS_open(FS, fname, SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_read(FS, fd, ref_content, strlen(content)+1); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp(ref_content, content) == 0); + SPIFFS_close(FS, fd); + } + printf(" removing %i files\n", files/2); + for (i = 0; i < files; i += 2) { + sprintf(fname, "file%i", i); + res = SPIFFS_remove(FS, fname); + TEST_CHECK(res >= 0); + } + printf(" creating %i files\n", files/2); + for (i = 0; i < files; i += 2) { + char content[20]; + sprintf(fname, "file%i", i); + sprintf(content, "new%i", i); + res = test_create_file(fname); + TEST_CHECK(res >= 0); + fd = SPIFFS_open(FS, fname, SPIFFS_APPEND | SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, content, strlen(content)+1); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + } + printf(" checking %i files\n", files); + for (i = 0; i < files; i++) { + char content[20]; + char ref_content[20]; + sprintf(fname, "file%i", i); + if ((i & 1) == 0) { + sprintf(content, "new%i", i); + } else { + sprintf(content, "%i", i); + } + fd = SPIFFS_open(FS, fname, SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_read(FS, fd, ref_content, strlen(content)+1); + TEST_CHECK(res >= 0); + TEST_CHECK(strcmp(ref_content, content) == 0); + SPIFFS_close(FS, fd); + } + + return TEST_RES_OK; +} +TEST_END + +int create_and_read_back(int size, int chunk) { + char *name = "file"; + spiffs_file fd; + s32_t res; + + u8_t *buf = malloc(size); + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + + u8_t *rbuf = malloc(size); + int offs = 0; + while (offs < size) { + int len = MIN(size - offs, chunk); + res = SPIFFS_read(FS, fd, &rbuf[offs], len); + CHECK(res >= 0); + CHECK(memcmp(&rbuf[offs], &buf[offs], len) == 0); + + offs += chunk; + } + + CHECK(memcmp(&rbuf[0], &buf[0], size) == 0); + + SPIFFS_close(FS, fd); + + free(rbuf); + free(buf); + + return 0; +} + +TEST(read_chunk_1) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*8, 1) == 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(read_chunk_page) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))*2, + SPIFFS_DATA_PAGE_SIZE(FS)) == 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(read_chunk_index) +{ + TEST_CHECK(create_and_read_back(SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))*4, + SPIFFS_DATA_PAGE_SIZE(FS)*(SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS))) == 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(read_chunk_huge) +{ + int sz = (2*SPIFFS_CFG_PHYS_SZ(FS))/3; + TEST_CHECK(create_and_read_back(sz, sz) == 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(read_beyond) +{ + char *name = "file"; + spiffs_file fd; + s32_t res; + u32_t size = SPIFFS_DATA_PAGE_SIZE(FS)*2; + + u8_t *buf = malloc(size); + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + + u8_t *rbuf = malloc(size+10); + res = SPIFFS_read(FS, fd, rbuf, size+10); + + SPIFFS_close(FS, fd); + + free(rbuf); + free(buf); + + TEST_CHECK(res == size); + + return TEST_RES_OK; +} +TEST_END + +TEST(read_beyond2) +{ + char *name = "file"; + spiffs_file fd; + s32_t res; + const s32_t size = SPIFFS_DATA_PAGE_SIZE(FS); + + u8_t buf[size*2]; + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + int i,j; + for (j = 1; j <= size+1; j++) { + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + SPIFFS_clearerr(FS); + for (i = 0; i < size * 2; i += j) { + u8_t dst; + res = SPIFFS_read(FS, fd, buf, j); + TEST_CHECK_EQ(SPIFFS_errno(FS), i < size ? SPIFFS_OK : SPIFFS_ERR_END_OF_OBJECT); + TEST_CHECK_EQ(res, MIN(j, MAX(0, size - (i + j) + j))); + } + SPIFFS_close(FS, fd); + } + + return TEST_RES_OK; +} +TEST_END + + +TEST(bad_index_1) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page, free + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 2 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = (spiffs_page_ix)-1; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + res = read_and_verify("file"); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_INDEX_REF_FREE); + + return TEST_RES_OK; +} TEST_END + + +TEST(bad_index_2) { + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + int res = test_create_and_write_file("file", size, size); + TEST_CHECK(res >= 0); + res = read_and_verify("file"); + TEST_CHECK(res >= 0); + + spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0); + TEST_CHECK(fd > 0); + spiffs_stat s; + res = SPIFFS_fstat(FS, fd, &s); + TEST_CHECK(res >= 0); + SPIFFS_close(FS, fd); + + // modify object index, find object index header + spiffs_page_ix pix; + res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix); + TEST_CHECK(res >= 0); + + // set object index entry 2 to a bad page, lu + u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 2 * sizeof(spiffs_page_ix); + spiffs_page_ix bad_pix_ref = SPIFFS_OBJ_LOOKUP_PAGES(FS)-1; + area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix)); + +#if SPIFFS_CACHE + // delete all cache + spiffs_cache *cache = spiffs_get_cache(FS); + cache->cpage_use_map = 0; +#endif + + res = read_and_verify("file"); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_INDEX_REF_LU); + + return TEST_RES_OK; +} TEST_END + + +TEST(lseek_simple_modification) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = 4096; + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + res = SPIFFS_lseek(FS, fd, len/2, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + lseek(pfd, len/2, SEEK_SET); + len = len/4; + buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END + + +TEST(lseek_modification_append) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = 4096; + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + res = SPIFFS_lseek(FS, fd, len/2, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + lseek(pfd, len/2, SEEK_SET); + + buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END + + +TEST(lseek_modification_append_multi) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = 1024; + int runs = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS) / (len/2); + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + int pfd = open(make_test_fname(fname), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + u8_t *buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + + while (runs--) { + res = SPIFFS_lseek(FS, fd, -len/2, SPIFFS_SEEK_END); + TEST_CHECK(res >= 0); + lseek(pfd, -len/2, SEEK_END); + + buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + TEST_CHECK(res >= 0); + write(pfd, buf, len); + free(buf); + + res = read_and_verify(fname); + TEST_CHECK(res >= 0); + } + + SPIFFS_close(FS, fd); + close(pfd); + + return TEST_RES_OK; +} +TEST_END + + +TEST(lseek_read) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS); + int runs = 100000; + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + u8_t *refbuf = malloc(len); + memrand(refbuf, len); + res = SPIFFS_write(FS, fd, refbuf, len); + TEST_CHECK(res >= 0); + + int offs = 0; + res = SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + + while (runs--) { + int i; + u8_t buf[64]; + if (offs + 41 + sizeof(buf) >= len) { + offs = (offs + 41 + sizeof(buf)) % len; + res = SPIFFS_lseek(FS, fd, offs, SPIFFS_SEEK_SET); + TEST_CHECK(res >= 0); + } + res = SPIFFS_lseek(FS, fd, 41, SPIFFS_SEEK_CUR); + TEST_CHECK(res >= 0); + offs += 41; + res = SPIFFS_read(FS, fd, buf, sizeof(buf)); + TEST_CHECK(res >= 0); + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != refbuf[offs+i]) { + printf(" mismatch at offs %i\n", offs); + } + TEST_CHECK(buf[i] == refbuf[offs+i]); + } + offs += sizeof(buf); + + res = SPIFFS_lseek(FS, fd, -((u32_t)sizeof(buf)+11), SPIFFS_SEEK_CUR); + TEST_CHECK(res >= 0); + offs -= (sizeof(buf)+11); + res = SPIFFS_read(FS, fd, buf, sizeof(buf)); + TEST_CHECK(res >= 0); + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != refbuf[offs+i]) { + printf(" mismatch at offs %i\n", offs); + } + TEST_CHECK(buf[i] == refbuf[offs+i]); + } + offs += sizeof(buf); + } + + free(refbuf); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; +} +TEST_END + + + +TEST(lseek_oob) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS); + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + u8_t *refbuf = malloc(len); + memrand(refbuf, len); + res = SPIFFS_write(FS, fd, refbuf, len); + TEST_CHECK(res >= 0); + + int offs = 0; + res = SPIFFS_lseek(FS, fd, -1, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, SPIFFS_ERR_SEEK_BOUNDS); + res = SPIFFS_lseek(FS, fd, len+1, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, SPIFFS_ERR_END_OF_OBJECT); + free(refbuf); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; +} +TEST_END + + +TEST(gc_quick) +{ + char name[32]; + int f; + int size = SPIFFS_DATA_PAGE_SIZE(FS); + int pages_per_block=SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS); + int files = (pages_per_block+1)/2; + int res; + + // negative, try quick gc on clean sys + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NO_DELETED_BLOCKS); + + // fill block with files + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block + for (f = 0; f < files; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + // do a quick gc + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res >= 0); + + // fill another block with files but two pages + // We might have one deleted page left over from the previous gc, in case pages_per_block is odd. + int pages_already=2*files-pages_per_block; + int files2=(pages_per_block-pages_already+1)/2; + + for (f = 0; f < files2 - 1; f++) { + sprintf(name, "file%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files2 - 1; f++) { + sprintf(name, "file%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + // remove all files in block leaving two free pages in block + for (f = 0; f < files2 - 1; f++) { + sprintf(name, "file%i", f); + res = SPIFFS_remove(FS, name); + TEST_CHECK(res >= 0); + } + + // negative, try quick gc where no fully deleted blocks exist + res = SPIFFS_gc_quick(FS, 0); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NO_DELETED_BLOCKS); + + // positive, try quick gc where allowing two free pages + res = SPIFFS_gc_quick(FS, 2); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_small_file_chunks_1) +{ + int res = test_create_and_write_file("smallfile", 256, 1); + TEST_CHECK(res >= 0); + res = read_and_verify("smallfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + + +TEST(write_small_files_chunks_1) +{ + char name[32]; + int f; + int size = 512; + int files = ((20*SPIFFS_CFG_PHYS_SZ(FS))/100)/size; + int res; + for (f = 0; f < files; f++) { + sprintf(name, "smallfile%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "smallfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END + +TEST(write_big_file_chunks_1) +{ + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); + printf(" filesize %i\n", size); + int res = test_create_and_write_file("bigfile", size, 1); + TEST_CHECK(res >= 0); + res = read_and_verify("bigfile"); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + +TEST(write_big_files_chunks_1) +{ + char name[32]; + int f; + int files = 10; + int res; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; + printf(" filesize %i\n", size); + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = test_create_and_write_file(name, size, 1); + TEST_CHECK(res >= 0); + } + for (f = 0; f < files; f++) { + sprintf(name, "bigfile%i", f); + res = read_and_verify(name); + TEST_CHECK(res >= 0); + } + + return TEST_RES_OK; +} +TEST_END + + +TEST(long_run_config_many_small_one_long) +{ + tfile_conf cfgs[] = { + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = LONG + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = LONG + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 206, 5, 0); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END + +TEST(long_run_config_many_medium) +{ + tfile_conf cfgs[] = { + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = LARGE, .ttype = MODIFIED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = LONG + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 305, 5, 0); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(long_run_config_many_small) +{ + tfile_conf cfgs[] = { + { .tsize = SMALL, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = LONG + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = UNTAMPERED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = APPENDED, .tlife = SHORT + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = NORMAL + }, + { .tsize = EMPTY, .ttype = UNTAMPERED, .tlife = SHORT + }, + }; + + int res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 115, 6, 0); + TEST_CHECK(res >= 0); + return TEST_RES_OK; +} +TEST_END + + +TEST(long_run) +{ + tfile_conf cfgs[] = { + { .tsize = EMPTY, .ttype = APPENDED, .tlife = NORMAL + }, + { .tsize = SMALL, .ttype = REWRITTEN, .tlife = SHORT + }, + { .tsize = MEDIUM, .ttype = MODIFIED, .tlife = SHORT + }, + { .tsize = MEDIUM, .ttype = APPENDED, .tlife = SHORT + }, + }; + + int macro_runs = 500; + printf(" "); + u32_t clob_size = SPIFFS_CFG_PHYS_SZ(FS)/4; + int res = test_create_and_write_file("long_clobber", clob_size, clob_size); + TEST_CHECK(res >= 0); + + res = read_and_verify("long_clobber"); + TEST_CHECK(res >= 0); + + while (macro_runs--) { + //printf(" ---- run %i ----\n", macro_runs); + if ((macro_runs % 20) == 0) { + printf("."); + fflush(stdout); + } + res = run_file_config(sizeof(cfgs)/sizeof(cfgs[0]), &cfgs[0], 20, 2, 0); + TEST_CHECK(res >= 0); + } + printf("\n"); + + res = read_and_verify("long_clobber"); + TEST_CHECK(res >= 0); + + res = SPIFFS_check(FS); + TEST_CHECK(res >= 0); + + return TEST_RES_OK; +} +TEST_END + +#if SPIFFS_IX_MAP +TEST(ix_map_basic) +{ + // create a scattered file + s32_t res; + spiffs_file fd1, fd2; + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd1, 0); + fd2 = SPIFFS_open(FS, "2", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd2, 0); + + u8_t buf[SPIFFS_DATA_PAGE_SIZE(FS)]; + int i; + for (i = 0; i < SPIFFS_CFG_PHYS_SZ(FS) / 4 / SPIFFS_DATA_PAGE_SIZE(FS); i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd1, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd2, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + res = SPIFFS_close(FS, fd1); + TEST_CHECK_GE(res, SPIFFS_OK); + res = SPIFFS_close(FS, fd2); + TEST_CHECK_GE(res, SPIFFS_OK); + + res = SPIFFS_remove(FS, "2"); + TEST_CHECK_GE(res, SPIFFS_OK); + + spiffs_stat s; + res = SPIFFS_stat(FS, "1", &s); + TEST_CHECK_GE(res, SPIFFS_OK); + u32_t size = s.size; + + printf("file created, size: %i..\n", size); + + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd1, 0); + printf(".. corresponding pix entries: %i\n", SPIFFS_bytes_to_ix_map_entries(FS, size)); + + u8_t rd_buf[SPIFFS_CFG_LOG_PAGE_SZ(FS)]; + + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd1, 0); + + clear_flash_ops_log(); + + printf("reading file without memory mapped index\n"); + while ((res = SPIFFS_read(FS, fd1, rd_buf, sizeof(rd_buf))) == sizeof(rd_buf)); + TEST_CHECK_GT(res, SPIFFS_OK); + + res = SPIFFS_OK; + + u32_t reads_without_ixmap = get_flash_ops_log_read_bytes(); + dump_flash_access_stats(); + + u32_t crc_non_map_ix = get_spiffs_file_crc_by_fd(fd1); + + TEST_CHECK_EQ(SPIFFS_close(FS, fd1), SPIFFS_OK); + + + printf("reading file with memory mapped index\n"); + spiffs_ix_map map; + spiffs_page_ix ixbuf[SPIFFS_bytes_to_ix_map_entries(FS, size)]; + + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd1, 0); + + // map index to memory + res = SPIFFS_ix_map(FS, fd1, &map, 0, size, ixbuf); + TEST_CHECK_GE(res, SPIFFS_OK); + + clear_flash_ops_log(); + + while ((res = SPIFFS_read(FS, fd1, rd_buf, sizeof(rd_buf))) == sizeof(rd_buf)); + TEST_CHECK_GT(res, SPIFFS_OK); + u32_t reads_with_ixmap_pass1 = get_flash_ops_log_read_bytes(); + + dump_flash_access_stats(); + + u32_t crc_map_ix_pass1 = get_spiffs_file_crc_by_fd(fd1); + + TEST_CHECK_LT(reads_with_ixmap_pass1, reads_without_ixmap); + + TEST_CHECK_EQ(crc_non_map_ix, crc_map_ix_pass1); + + spiffs_page_ix ref_ixbuf[SPIFFS_bytes_to_ix_map_entries(FS, size)]; + memcpy(ref_ixbuf, ixbuf, sizeof(ixbuf)); + + // force a gc by creating small files until full, reordering the index + printf("forcing gc, error ERR_FULL %i expected\n", SPIFFS_ERR_FULL); + res = SPIFFS_OK; + u32_t ix = 10; + while (res == SPIFFS_OK) { + char name[32]; + sprintf(name, "%i", ix); + res = test_create_and_write_file(name, SPIFFS_CFG_LOG_BLOCK_SZ(FS), SPIFFS_CFG_LOG_BLOCK_SZ(FS)); + ix++; + } + + TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_FULL); + + // make sure the map array was altered + TEST_CHECK_NEQ(0, memcmp(ref_ixbuf, ixbuf, sizeof(ixbuf))); + + TEST_CHECK_GE(SPIFFS_lseek(FS, fd1, 0, SPIFFS_SEEK_SET), SPIFFS_OK); + + clear_flash_ops_log(); + while ((res = SPIFFS_read(FS, fd1, rd_buf, sizeof(rd_buf))) == sizeof(rd_buf)); + TEST_CHECK_GT(res, SPIFFS_OK); + u32_t reads_with_ixmap_pass2 = get_flash_ops_log_read_bytes(); + + TEST_CHECK_EQ(reads_with_ixmap_pass1, reads_with_ixmap_pass2); + + u32_t crc_map_ix_pass2 = get_spiffs_file_crc_by_fd(fd1); + + TEST_CHECK_EQ(crc_map_ix_pass1, crc_map_ix_pass2); + + TEST_CHECK_EQ(SPIFFS_close(FS, fd1), SPIFFS_OK); + + return TEST_RES_OK; +} +TEST_END + +TEST(ix_map_remap) +{ + // create a file, 10 data pages long + s32_t res; + spiffs_file fd1; + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd1, 0); + + const int size_pages = 10; + + u8_t buf[SPIFFS_DATA_PAGE_SIZE(FS)]; + int i; + for (i = 0; i < size_pages; i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd1, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + res = SPIFFS_close(FS, fd1); + TEST_CHECK_GE(res, SPIFFS_OK); + + spiffs_stat s; + res = SPIFFS_stat(FS, "1", &s); + TEST_CHECK_GE(res, SPIFFS_OK); + u32_t size = s.size; + + printf("file created, size: %i..\n", size); + + fd1 = SPIFFS_open(FS, "1", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd1, 0); + printf(".. corresponding pix entries: %i\n", SPIFFS_bytes_to_ix_map_entries(FS, size) + 1); + TEST_CHECK_EQ(SPIFFS_bytes_to_ix_map_entries(FS, size), size_pages + 1); + + // map index to memory + // move around, check validity + const int entries = SPIFFS_bytes_to_ix_map_entries(FS, size/2); + spiffs_ix_map map; + // add one extra for stack safeguarding + spiffs_page_ix ixbuf[entries+1]; + spiffs_page_ix ixbuf_ref[entries+1]; + const spiffs_page_ix canary = (spiffs_page_ix)0x87654321; + memset(ixbuf, 0xee, sizeof(ixbuf)); + ixbuf[entries] = canary; + + res = SPIFFS_ix_map(FS, fd1, &map, 0, size/2, ixbuf); + TEST_CHECK_GE(res, SPIFFS_OK); + + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + } + printf("\n"); + + memcpy(ixbuf_ref, ixbuf, sizeof(spiffs_page_ix) * entries); + + TEST_CHECK_EQ(SPIFFS_ix_remap(FS, fd1, 0), SPIFFS_OK); + TEST_CHECK_EQ(canary, ixbuf[entries]); + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + } + printf("\n"); + TEST_CHECK_EQ(0, memcmp(ixbuf_ref, ixbuf, sizeof(spiffs_page_ix) * entries)); + + TEST_CHECK_EQ(SPIFFS_ix_remap(FS, fd1, SPIFFS_DATA_PAGE_SIZE(FS)), SPIFFS_OK); + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + } + printf("\n"); + TEST_CHECK_EQ(canary, ixbuf[entries]); + TEST_CHECK_EQ(0, memcmp(&ixbuf_ref[1], ixbuf, sizeof(spiffs_page_ix) * (entries-1))); + + + TEST_CHECK_EQ(SPIFFS_ix_remap(FS, fd1, 0), SPIFFS_OK); + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + } + printf("\n"); + TEST_CHECK_EQ(canary, ixbuf[entries]); + TEST_CHECK_EQ(0, memcmp(ixbuf_ref, ixbuf, sizeof(spiffs_page_ix) * entries)); + + TEST_CHECK_EQ(SPIFFS_ix_remap(FS, fd1, size/2), SPIFFS_OK); + TEST_CHECK_EQ(canary, ixbuf[entries]); + + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf_ref[i]); + } + printf("\n"); + + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + } + printf("\n"); + + int matches = 0; + for (i = 0; i < entries; i++) { + int j; + for (j = 0; j < entries; j++) { + if (ixbuf_ref[i] == ixbuf[i]) { + matches++; + } + } + } + TEST_CHECK_LE(matches, 1); + + return TEST_RES_OK; +} +TEST_END + +TEST(ix_map_partial) +{ + // create a file, 10 data pages long + s32_t res; + spiffs_file fd; + fd = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd, 0); + + const int size_pages = 10; + + u8_t buf[SPIFFS_DATA_PAGE_SIZE(FS)]; + int i; + for (i = 0; i < size_pages; i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + res = SPIFFS_close(FS, fd); + TEST_CHECK_GE(res, SPIFFS_OK); + + spiffs_stat s; + res = SPIFFS_stat(FS, "1", &s); + TEST_CHECK_GE(res, SPIFFS_OK); + u32_t size = s.size; + + printf("file created, size: %i..\n", size); + + const u32_t crc_unmapped = get_spiffs_file_crc("1"); + + fd = SPIFFS_open(FS, "1", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd, 0); + + // map index to memory + const int entries = SPIFFS_bytes_to_ix_map_entries(FS, size/2); + spiffs_ix_map map; + spiffs_page_ix ixbuf[entries]; + + printf("map 0-50%%\n"); + res = SPIFFS_ix_map(FS, fd, &map, 0, size/2, ixbuf); + TEST_CHECK_GE(res, SPIFFS_OK); + + const u32_t crc_mapped_beginning = get_spiffs_file_crc_by_fd(fd); + TEST_CHECK_EQ(crc_mapped_beginning, crc_unmapped); + + printf("map 25-75%%\n"); + res = SPIFFS_ix_remap(FS, fd, size/4); + TEST_CHECK_GE(res, SPIFFS_OK); + + const u32_t crc_mapped_middle = get_spiffs_file_crc_by_fd(fd); + TEST_CHECK_EQ(crc_mapped_middle, crc_unmapped); + + printf("map 50-100%%\n"); + res = SPIFFS_ix_remap(FS, fd, size/2); + TEST_CHECK_GE(res, SPIFFS_OK); + + const u32_t crc_mapped_end = get_spiffs_file_crc_by_fd(fd); + TEST_CHECK_EQ(crc_mapped_end, crc_unmapped); + + return TEST_RES_OK; +} +TEST_END + +TEST(ix_map_beyond) +{ + // create a file, 10 data pages long + s32_t res; + spiffs_file fd; + fd = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd, 0); + + const int size_pages = 10; + + u8_t buf[SPIFFS_DATA_PAGE_SIZE(FS)]; + int i; + for (i = 0; i < size_pages; i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + res = SPIFFS_close(FS, fd); + TEST_CHECK_GE(res, SPIFFS_OK); + + spiffs_stat s; + res = SPIFFS_stat(FS, "1", &s); + TEST_CHECK_GE(res, SPIFFS_OK); + u32_t size = s.size; + + printf("file created, size: %i..\n", size); + + // map index to memory + fd = SPIFFS_open(FS, "1", SPIFFS_O_RDWR | SPIFFS_O_APPEND, 0); + TEST_CHECK_GT(fd, 0); + + const int entries = SPIFFS_bytes_to_ix_map_entries(FS, size); + spiffs_ix_map map; + spiffs_page_ix ixbuf[entries]; + printf("map has %i entries\n", entries); + + printf("map 100-200%%\n"); + res = SPIFFS_ix_map(FS, fd, &map, size, size, ixbuf); + TEST_CHECK_GE(res, SPIFFS_OK); + + printf("make sure map is empty\n"); + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + TEST_CHECK_EQ(ixbuf[i], 0); + } + printf("\n"); + + printf("elongate by 100%%\n"); + for (i = 0; i < size_pages; i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + TEST_CHECK_GE(SPIFFS_fflush(FS, fd), SPIFFS_OK); + + res = SPIFFS_stat(FS, "1", &s); + TEST_CHECK_GE(res, SPIFFS_OK); + size = s.size; + printf("file elongated, size: %i..\n", size); + + printf("make sure map is full but for one element\n"); + int zeroed = 0; + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + if (ixbuf[i] == 0) zeroed++; + } + printf("\n"); + TEST_CHECK_LE(zeroed, 1); + + printf("remap till end\n"); + TEST_CHECK_EQ(SPIFFS_ix_remap(FS, fd, size), SPIFFS_OK); + + printf("make sure map is empty but for one element\n"); + int nonzero = 0; + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + if (ixbuf[i]) nonzero++; + } + printf("\n"); + TEST_CHECK_LE(nonzero, 1); + + printf("elongate again, by other fd\n"); + + spiffs_file fd2 = SPIFFS_open(FS, "1", SPIFFS_O_WRONLY | SPIFFS_O_APPEND, 0); + TEST_CHECK_GT(fd2, 0); + + for (i = 0; i < size_pages; i++) { + memrand(buf, sizeof(buf)); + res = SPIFFS_write(FS, fd2, buf, sizeof(buf)); + TEST_CHECK_GE(res, SPIFFS_OK); + } + TEST_CHECK_GE(SPIFFS_close(FS, fd2), SPIFFS_OK); + + printf("make sure map is full but for one element\n"); + zeroed = 0; + for (i = 0; i < entries; i++) { + printf("%04x ", ixbuf[i]); + if (ixbuf[i] == 0) zeroed++; + } + printf("\n"); + TEST_CHECK_LE(zeroed, 1); + + return TEST_RES_OK; +} +TEST_END + +#endif // SPIFFS_IX_MAP + +SUITE_TESTS(hydrogen_tests) + ADD_TEST(info) +#if SPIFFS_USE_MAGIC + ADD_TEST(magic) +#if SPIFFS_USE_MAGIC_LENGTH + ADD_TEST(magic_length) +#if SPIFFS_SINGLETON==0 + ADD_TEST(magic_length_probe) +#endif +#endif +#endif + ADD_TEST(missing_file) + ADD_TEST(bad_fd) + ADD_TEST(closed_fd) + ADD_TEST(deleted_same_fd) + ADD_TEST(deleted_other_fd) + ADD_TEST(file_by_open) + ADD_TEST(file_by_creat) + ADD_TEST(file_by_open_excl) +#if SPIFFS_FILEHDL_OFFSET + ADD_TEST(open_fh_offs) +#endif + ADD_TEST(list_dir) + ADD_TEST(open_by_dirent) + ADD_TEST(open_by_page) + ADD_TEST(user_callback_basic) + ADD_TEST(user_callback_gc) + ADD_TEST(name_too_long) + ADD_TEST(rename) +#if SPIFFS_OBJ_META_LEN + ADD_TEST(update_meta) +#endif + ADD_TEST(remove_single_by_path) + ADD_TEST(remove_single_by_fd) + ADD_TEST(write_cache) + ADD_TEST(write_big_file_chunks_page) + ADD_TEST(write_big_files_chunks_page) + ADD_TEST(write_big_file_chunks_index) + ADD_TEST(write_big_files_chunks_index) + ADD_TEST(write_big_file_chunks_huge) + ADD_TEST(write_big_files_chunks_huge) + ADD_TEST(truncate_big_file) + ADD_TEST(simultaneous_write) + ADD_TEST(simultaneous_write_append) + ADD_TEST(file_uniqueness) + ADD_TEST(read_chunk_1) + ADD_TEST(read_chunk_page) + ADD_TEST(read_chunk_index) + ADD_TEST(read_chunk_huge) + ADD_TEST(read_beyond) + ADD_TEST(read_beyond2) + ADD_TEST(bad_index_1) + ADD_TEST(bad_index_2) + ADD_TEST(lseek_simple_modification) + ADD_TEST(lseek_modification_append) + ADD_TEST(lseek_modification_append_multi) + ADD_TEST(lseek_read) + ADD_TEST(lseek_oob) + ADD_TEST(gc_quick) + ADD_TEST(write_small_file_chunks_1) + ADD_TEST(write_small_files_chunks_1) + ADD_TEST(write_big_file_chunks_1) + ADD_TEST(write_big_files_chunks_1) + ADD_TEST(long_run_config_many_small_one_long) + ADD_TEST(long_run_config_many_medium) + ADD_TEST(long_run_config_many_small) + ADD_TEST(long_run) +#if SPIFFS_IX_MAP + ADD_TEST(ix_map_basic) + ADD_TEST(ix_map_remap) + ADD_TEST(ix_map_partial) + ADD_TEST(ix_map_beyond) +#endif + +SUITE_END(hydrogen_tests) + diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.c new file mode 100755 index 0000000..374028a --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.c @@ -0,0 +1,1095 @@ +/* + * test_spiffs.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + + +#include +#include +#include + +#include "params_test.h" +#include "spiffs.h" +#include "spiffs_nucleus.h" + +#include "testrunner.h" + +#include "test_spiffs.h" + +#include +#include +#include +#include +#include +#include + +#define AREA(x) _area[(x) - addr_offset] + +static u32_t _area_sz; +static unsigned char *_area = NULL; +static u32_t addr_offset = 0; + +static int *_erases; +static char _path[256]; +static u32_t bytes_rd = 0; +static u32_t bytes_wr = 0; +static u32_t reads = 0; +static u32_t writes = 0; +static u32_t error_after_bytes_written = 0; +static u32_t error_after_bytes_read = 0; +static char error_after_bytes_written_once_only = 0; +static char error_after_bytes_read_once_only = 0; +static char log_flash_ops = 1; +static u32_t fs_check_fixes = 0; +static u32_t _fs_locks; + +spiffs __fs; +static u8_t *_work = NULL; +static u8_t *_fds = NULL; +static u32_t _fds_sz; +static u8_t *_cache = NULL; +static u32_t _cache_sz; + +static int check_valid_flash = 1; + +#ifndef TEST_PATH +#define TEST_PATH "/dev/shm/spiffs/test-data/" +#endif + +// taken from http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux +// thanks Jonathan Leffler + +static int do_mkdir(const char *path, mode_t mode) +{ + struct stat st; + int status = 0; + + if (stat(path, &st) != 0) { + /* Directory does not exist. EEXIST for race condition */ + if (mkdir(path, mode) != 0 && errno != EEXIST) { + status = -1; + } + } else if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + status = -1; + } + + return status; +} + +/** +** mkpath - ensure all directories in path exist +** Algorithm takes the pessimistic view and works top-down to ensure +** each directory in path exists, rather than optimistically creating +** the last element and working backwards. +*/ +static int mkpath(const char *path, mode_t mode) { + char *pp; + char *sp; + int status; + char *copypath = strdup(path); + + status = 0; + pp = copypath; + while (status == 0 && (sp = strchr(pp, '/')) != 0) { + if (sp != pp) { + /* Neither root nor double slash in path */ + *sp = '\0'; + status = do_mkdir(copypath, mode); + *sp = '/'; + } + pp = sp + 1; + } + if (status == 0) { + status = do_mkdir(path, mode); + } + free(copypath); + return status; +} + +// end take +// +// +char *make_test_fname(const char *name) { + sprintf(_path, "%s/%s", TEST_PATH, name); + return _path; +} + +void create_test_path(void) { + if (mkpath(TEST_PATH, 0755)) { + printf("could not create path %s\n", TEST_PATH); + exit(1); + } +} + +void clear_test_path() { + DIR *dp; + struct dirent *ep; + dp = opendir(TEST_PATH); + + if (dp != NULL) { + while ((ep = readdir(dp))) { + if (ep->d_name[0] != '.') { + sprintf(_path, "%s/%s", TEST_PATH, ep->d_name); + remove(_path); + } + } + closedir(dp); + } +} + +static s32_t _read( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size, u8_t *dst) { + //printf("rd @ addr %08x => %p\n", addr, &AREA(addr)); + if (log_flash_ops) { + bytes_rd += size; + reads++; + if (error_after_bytes_read > 0 && bytes_rd >= error_after_bytes_read) { + if (error_after_bytes_read_once_only) { + error_after_bytes_read = 0; + } + return SPIFFS_ERR_TEST; + } + } + if (addr < SPIFFS_CFG_PHYS_ADDR(&__fs)) { + printf("FATAL read addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR); + ERREXIT(); + return -1; + } + if (addr + size > SPIFFS_CFG_PHYS_ADDR(&__fs) + SPIFFS_CFG_PHYS_SZ(&__fs)) { + printf("FATAL read addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE); + ERREXIT(); + return -1; + } + memcpy(dst, &AREA(addr), size); + return 0; +} + +static s32_t _write( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size, u8_t *src) { + int i; + //printf("wr %08x %i\n", addr, size); + if (log_flash_ops) { + bytes_wr += size; + writes++; + if (error_after_bytes_written > 0 && bytes_wr >= error_after_bytes_written) { + if (error_after_bytes_written_once_only) { + error_after_bytes_written = 0; + } + return SPIFFS_ERR_TEST; + } + } + + if (addr < SPIFFS_CFG_PHYS_ADDR(&__fs)) { + printf("FATAL write addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR); + ERREXIT(); + return -1; + } + if (addr + size > SPIFFS_CFG_PHYS_ADDR(&__fs) + SPIFFS_CFG_PHYS_SZ(&__fs)) { + printf("FATAL write addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE); + ERREXIT(); + return -1; + } + + for (i = 0; i < size; i++) { + if (((addr + i) & (SPIFFS_CFG_LOG_PAGE_SZ(&__fs)-1)) != offsetof(spiffs_page_header, flags)) { + if (check_valid_flash && ((AREA(addr + i) ^ src[i]) & src[i])) { + printf("trying to write %02x to %02x at addr %08x (as part of writing %d bytes to addr %08x)\n", src[i], AREA(addr + i), addr+i, size, addr); + spiffs_page_ix pix = (addr + i) / SPIFFS_CFG_LOG_PAGE_SZ(&__fs); + dump_page(&__fs, pix); + ERREXIT(); + return -1; + } + } + AREA(addr + i) &= src[i]; + } + return 0; +} +static s32_t _erase( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size) { + if (addr & (SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)-1)) { + printf("trying to erase at addr %08x, out of boundary\n", addr); + ERREXIT(); + return -1; + } + if (size & (SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)-1)) { + printf("trying to erase at with size %08x, out of boundary\n", size); + ERREXIT(); + return -1; + } + _erases[(addr-SPIFFS_CFG_PHYS_ADDR(&__fs))/SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)]++; + memset(&AREA(addr), 0xff, size); + return 0; +} + +void hexdump_mem(u8_t *b, u32_t len) { + while (len--) { + if ((((intptr_t)b)&0x1f) == 0) { + printf("\n"); + } + printf("%02x", *b++); + } + printf("\n"); +} + +void hexdump(u32_t addr, u32_t len) { + int remainder = (addr % 32) == 0 ? 0 : 32 - (addr % 32); + u32_t a; + for (a = addr - remainder; a < addr+len; a++) { + if ((a & 0x1f) == 0) { + if (a != addr) { + printf(" "); + int j; + for (j = 0; j < 32; j++) { + if (a-32+j < addr) + printf(" "); + else { + printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j)); + } + } + } + printf("%s %08x: ", a<=addr ? "":"\n", a); + } + if (a < addr) { + printf(" "); + } else { + printf("%02x", AREA(a)); + } + } + int j; + printf(" "); + for (j = 0; j < 32; j++) { + if (a-32+j < addr) + printf(" "); + else { + printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j)); + } + } + printf("\n"); +} + +void dump_page(spiffs *fs, spiffs_page_ix p) { + printf("page %04x ", p); + u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, p); + if (p % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) { + // obj lu page + printf("OBJ_LU"); + } else { + u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , p)) + + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, p) * sizeof(spiffs_obj_id); + spiffs_obj_id obj_id = *((spiffs_obj_id *)&AREA(obj_id_addr)); + // data page + spiffs_page_header *ph = (spiffs_page_header *)&AREA(addr); + printf("DATA %04x:%04x ", obj_id, ph->span_ix); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_FINAL) == 0) ? "FIN " : "fin "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_DELET) == 0) ? "DEL " : "del "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_INDEX) == 0) ? "IDX " : "idx "); + printf("%s", ((ph->flags & SPIFFS_PH_FLAG_USED) == 0) ? "USD " : "usd "); + printf("%s ", ((ph->flags & SPIFFS_PH_FLAG_IXDELE) == 0) ? "IDL " : "idl "); + if (obj_id & SPIFFS_OBJ_ID_IX_FLAG) { + // object index + printf("OBJ_IX"); + if (ph->span_ix == 0) { + printf("_HDR "); + spiffs_page_object_ix_header *oix_hdr = (spiffs_page_object_ix_header *)&AREA(addr); + printf("'%s' %i bytes type:%02x", oix_hdr->name, oix_hdr->size, oix_hdr->type); + } + } else { + // data page + printf("CONTENT"); + } + } + printf("\n"); + u32_t len = SPIFFS_CFG_LOG_PAGE_SZ(fs); + hexdump(addr, len); +} + +void area_write(u32_t addr, u8_t *buf, u32_t size) { + int i; + for (i = 0; i < size; i++) { + AREA(addr + i) = *buf++; + } +} + +void area_set(u32_t addr, u8_t d, u32_t size) { + int i; + for (i = 0; i < size; i++) { + AREA(addr + i) = d; + } +} + +void area_read(u32_t addr, u8_t *buf, u32_t size) { + int i; + for (i = 0; i < size; i++) { + *buf++ = AREA(addr + i); + } +} + +void dump_erase_counts(spiffs *fs) { + spiffs_block_ix bix; + spiffs_block_ix bix_offs; + printf(" BLOCK |\n"); + printf(" AGE COUNT|\n"); + for (bix_offs = 0; bix_offs < fs->block_count; bix_offs+=8) { + for (bix = bix_offs; bix < bix_offs+8 && bix < fs->block_count; bix++) { + printf("----%3i ----|", bix); + } + printf("\n"); + for (bix = bix_offs; bix < bix_offs+8 && bix < fs->block_count; bix++) { + spiffs_obj_id erase_mark; + _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_mark); + if (_erases[bix] == 0) { + printf(" |"); + } else { + printf("%7i %4i|", (fs->max_erase_count - erase_mark), _erases[bix]); + } + } + printf("\n"); + } +} + +void dump_flash_access_stats() { + printf(" RD: %10i reads %10i bytes %10i avg bytes/read\n", reads, bytes_rd, reads == 0 ? 0 : (bytes_rd / reads)); + printf(" WR: %10i writes %10i bytes %10i avg bytes/write\n", writes, bytes_wr, writes == 0 ? 0 : (bytes_wr / writes)); +} + + +static int check_cb_count; +// static u32_t old_perc = 999; +static void spiffs_check_cb_f( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + spiffs_check_type type, spiffs_check_report report, + u32_t arg1, u32_t arg2) { +/* if (report == SPIFFS_CHECK_PROGRESS && old_perc != arg1) { + old_perc = arg1; + printf("CHECK REPORT: "); + switch(type) { + case SPIFFS_CHECK_LOOKUP: + printf("LU "); break; + case SPIFFS_CHECK_INDEX: + printf("IX "); break; + case SPIFFS_CHECK_PAGE: + printf("PA "); break; + } + printf("%i%%\n", arg1 * 100 / 256); + }*/ + if (report != SPIFFS_CHECK_PROGRESS) { + check_cb_count++; + if (report != SPIFFS_CHECK_ERROR) fs_check_fixes++; + printf(" check: "); + switch (type) { + case SPIFFS_CHECK_INDEX: + printf("INDEX "); break; + case SPIFFS_CHECK_LOOKUP: + printf("LOOKUP "); break; + case SPIFFS_CHECK_PAGE: + printf("PAGE "); break; + default: + printf("???? "); break; + } + if (report == SPIFFS_CHECK_ERROR) { + printf("ERROR %i", arg1); + } else if (report == SPIFFS_CHECK_DELETE_BAD_FILE) { + printf("DELETE BAD FILE %04x", arg1); + } else if (report == SPIFFS_CHECK_DELETE_ORPHANED_INDEX) { + printf("DELETE ORPHANED INDEX %04x", arg1); + } else if (report == SPIFFS_CHECK_DELETE_PAGE) { + printf("DELETE PAGE %04x", arg1); + } else if (report == SPIFFS_CHECK_FIX_INDEX) { + printf("FIX INDEX %04x:%04x", arg1, arg2); + } else if (report == SPIFFS_CHECK_FIX_LOOKUP) { + printf("FIX INDEX %04x:%04x", arg1, arg2); + } else { + printf("??"); + } + printf("\n"); + } +} + +void fs_set_addr_offset(u32_t offset) { + addr_offset = offset; +} + +void test_lock(spiffs *fs) { + if (_fs_locks != 0) { + printf("FATAL: reentrant locks. Abort.\n"); + ERREXIT(); + exit(-1); + } + _fs_locks++; +} + +void test_unlock(spiffs *fs) { + if (_fs_locks != 1) { + printf("FATAL: unlocking unlocked. Abort.\n"); + ERREXIT(); + exit(-1); + } + _fs_locks--; +} + +s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size) { + spiffs_config c; + c.hal_erase_f = _erase; + c.hal_read_f = _read; + c.hal_write_f = _write; +#if SPIFFS_SINGLETON == 0 + c.log_block_size = log_block_size; + c.log_page_size = log_page_size; + c.phys_addr = phys_addr; + c.phys_erase_block = phys_sector_size; + c.phys_size = phys_size; +#endif +#if SPIFFS_FILEHDL_OFFSET + c.fh_ix_offset = TEST_SPIFFS_FILEHDL_OFFSET; +#endif + return SPIFFS_mount(&__fs, &c, _work, _fds, _fds_sz, _cache, _cache_sz, spiffs_check_cb_f); +} + +static void fs_create(u32_t spiflash_size, + u32_t phys_sector_size, + u32_t log_page_size, + u32_t descriptors, u32_t cache_pages) { + _area_sz = spiflash_size; + _area = malloc(spiflash_size); + ASSERT(_area != NULL, "testbench area could not be malloced"); + + const u32_t erase_sz = sizeof(int) * (spiflash_size / phys_sector_size); + _erases = malloc(erase_sz); + ASSERT(_erases != NULL, "testbench erase log could not be malloced"); + memset(_erases, 0, erase_sz); + + _fds_sz = descriptors * sizeof(spiffs_fd); + _fds = malloc(_fds_sz); + ASSERT(_fds != NULL, "testbench fd buffer could not be malloced"); + memset(_fds, 0, _fds_sz); + +#if SPIFFS_CACHE + _cache_sz = sizeof(spiffs_cache) + cache_pages * (sizeof(spiffs_cache_page) + log_page_size); + _cache = malloc(_cache_sz); + ASSERT(_cache != NULL, "testbench cache could not be malloced"); + memset(_cache, 0, _cache_sz); +#endif + + const u32_t work_sz = log_page_size * 2; + _work = malloc(work_sz); + ASSERT(_work != NULL, "testbench work buffer could not be malloced"); + memset(_work, 0, work_sz); +} + +static void fs_free(void) { + if (_area) free(_area); + _area = NULL; + if (_erases) free(_erases); + _erases = NULL; + if (_fds) free(_fds); + _fds = NULL; + if (_cache) free(_cache); + _cache = NULL; + if (_work) free(_work); + _work = NULL; +} + +/** + * addr_offset + */ +void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size) { + fs_create(phys_size + phys_addr - addr_offset, + phys_sector_size, + log_page_size, + DEFAULT_NUM_FD, + DEFAULT_NUM_CACHE_PAGES); + fs_set_addr_offset(addr_offset); + memset(&AREA(addr_offset), 0xcc, _area_sz); + memset(&AREA(phys_addr), 0xff, phys_size); + memset(&__fs, 0, sizeof(__fs)); + + s32_t res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size); + +#if SPIFFS_USE_MAGIC + if (res == SPIFFS_OK) { + SPIFFS_unmount(&__fs); + } + res = SPIFFS_format(&__fs); + if (res != SPIFFS_OK) { + printf("format failed, %i\n", SPIFFS_errno(&__fs)); + } + res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size); + if (res != SPIFFS_OK) { + printf("mount failed, %i\n", SPIFFS_errno(&__fs)); + } +#endif + + clear_flash_ops_log(); + log_flash_ops = 1; + fs_check_fixes = 0; +} + +void fs_reset() { + fs_reset_specific(0, SPIFFS_PHYS_ADDR, SPIFFS_FLASH_SIZE, SECTOR_SIZE, LOG_BLOCK, LOG_PAGE); +} + +void fs_store_dump(char *fname) { + int pfd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + ASSERT(pfd > 0, "could not open dump file"); + write(pfd, _area, _area_sz); + close(pfd); +} + +void fs_load_dump(char *fname) { + int pfd = open(fname, O_RDONLY, S_IRUSR | S_IWUSR); + ASSERT(pfd > 0, "could not load dump"); + read(pfd, _area, _area_sz); + close(pfd); +} + +void fs_mount_dump(char *fname, + u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size) { + fs_create(phys_size + phys_addr - addr_offset, + phys_sector_size, + log_page_size, + DEFAULT_NUM_FD, + DEFAULT_NUM_CACHE_PAGES); + fs_set_addr_offset(addr_offset); + memset(&AREA(addr_offset), 0xcc, _area_sz); + memset(&AREA(phys_addr), 0xff, phys_size); + memset(&__fs, 0, sizeof(__fs)); + + fs_load_dump(fname); + + s32_t res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size); + + ASSERT(res == SPIFFS_OK, "failed mounting dump, check settings"); + + clear_flash_ops_log(); + log_flash_ops = 1; + fs_check_fixes = 0; +} + +void set_flash_ops_log(int enable) { + log_flash_ops = enable; +} + +void clear_flash_ops_log() { + bytes_rd = 0; + bytes_wr = 0; + reads = 0; + writes = 0; + error_after_bytes_read = 0; + error_after_bytes_written = 0; +} + +u32_t get_flash_ops_log_read_bytes() { + return bytes_rd; +} + +u32_t get_flash_ops_log_write_bytes() { + return bytes_wr; +} + +void invoke_error_after_read_bytes(u32_t b, char once_only) { + error_after_bytes_read = b; + error_after_bytes_read_once_only = once_only; +} +void invoke_error_after_write_bytes(u32_t b, char once_only) { + error_after_bytes_written = b; + error_after_bytes_written_once_only = once_only; +} + +void fs_set_validate_flashing(int i) { + check_valid_flash = i; +} + +void real_assert(int c, const char *n, const char *file, int l) { + if (c == 0) { + printf("ASSERT: %s %s @ %i\n", (n ? n : ""), file, l); + printf("fs errno:%i\n", __fs.err_code); + exit(0); + } +} + +int read_and_verify(char *name) { + int fd = SPIFFS_open(&__fs, name, SPIFFS_RDONLY, 0); + if (fd < 0) { + printf(" read_and_verify: could not open file %s\n", name); + return fd; + } + return read_and_verify_fd(fd, name); +} + +int read_and_verify_fd(spiffs_file fd, char *name) { + s32_t res; + int pfd = open(make_test_fname(name), O_RDONLY); + spiffs_stat s; + res = SPIFFS_fstat(&__fs, fd, &s); + if (res < 0) { + printf(" read_and_verify: could not stat file %s\n", name); + return res; + } + if (s.size == 0) { + SPIFFS_close(&__fs, fd); + close(pfd); + return 0; + } + + //printf("verifying %s, len %i\n", name, s.size); + int offs = 0; + u8_t buf_d[256]; + u8_t buf_v[256]; + while (offs < s.size) { + int read_len = MIN(s.size - offs, sizeof(buf_d)); + res = SPIFFS_read(&__fs, fd, buf_d, read_len); + if (res < 0) { + printf(" read_and_verify: could not read file %s offs:%i len:%i filelen:%i\n", name, offs, read_len, s.size); + return res; + } + int pres = read(pfd, buf_v, read_len); + (void)pres; + //printf("reading offs:%i len:%i spiffs_res:%i posix_res:%i\n", offs, read_len, res, pres); + int i; + int veri_ok = 1; + for (i = 0; veri_ok && i < read_len; i++) { + if (buf_d[i] != buf_v[i]) { + printf("file verification mismatch @ %i, %02x %c != %02x %c\n", offs+i, buf_d[i], buf_d[i], buf_v[i], buf_v[i]); + int j = MAX(0, i-16); + int k = MIN(sizeof(buf_d), i+16); + k = MIN(s.size-offs, k); + int l; + for (l = j; l < k; l++) { + printf("%c", buf_d[l] > 31 ? buf_d[l] : '.'); + } + printf("\n"); + for (l = j; l < k; l++) { + printf("%c", buf_v[l] > 31 ? buf_v[l] : '.'); + } + printf("\n"); + veri_ok = 0; + } + } + if (!veri_ok) { + SPIFFS_close(&__fs, fd); + close(pfd); + printf("data mismatch\n"); + return -1; + } + + offs += read_len; + } + + SPIFFS_close(&__fs, fd); + close(pfd); + + return 0; +} + +static void test_on_stop(test *t) { + printf(" spiffs errno:%i\n", SPIFFS_errno(&__fs)); +#if SPIFFS_TEST_VISUALISATION + if (_area) SPIFFS_vis(FS); +#endif + +} + +void memrand(u8_t *b, int len) { + int i; + for (i = 0; i < len; i++) { + b[i] = rand(); + } +} + +int test_create_file(char *name) { + spiffs_stat s; + spiffs_file fd; + int res = SPIFFS_creat(FS, name, 0); + CHECK_RES(res); + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + res = SPIFFS_fstat(FS, fd, &s); + CHECK_RES(res); + CHECK(strcmp((char*)s.name, name) == 0); + CHECK(s.size == 0); +#if SPIFFS_OBJ_META_LEN + { + int i; + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + CHECK(s.meta[i] == 0xff); + } + } +#endif + SPIFFS_close(FS, fd); + return 0; +} + +int test_create_and_write_file(char *name, int size, int chunk_size) { + int res; + spiffs_file fd; + printf(" create and write %s", name); + res = test_create_file(name); + if (res < 0) { + printf(" failed creation, %i\n",res); + } + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + if (fd < 0) { + printf(" failed open, %i\n",res); + } + CHECK(fd >= 0); + int pfd = open(make_test_fname(name), O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int offset = 0; + int mark = 0; + while (offset < size) { + int len = MIN(size-offset, chunk_size); + if (offset > mark) { + mark += size/16; + printf("."); + fflush(stdout); + } + u8_t *buf = malloc(len); + memrand(buf, len); + res = SPIFFS_write(FS, fd, buf, len); + write(pfd, buf, len); + free(buf); + if (res < 0) { + printf("\n error @ offset %i, res %i\n", offset, res); + } + offset += len; + CHECK(res >= 0); + } + printf("\n"); + close(pfd); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + if (res < 0) { + printf(" failed fstat, %i\n",res); + } + CHECK(res >= 0); + if (stat.size != size) { + printf(" failed size, %i != %i\n", stat.size, size); + } + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + return 0; +} + +static u32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static u32_t crc32(u32_t crc, const void *buf, size_t size) +{ + const u8_t *p; + + p = buf; + crc = crc ^ ~0U; + + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return crc ^ ~0U; +} + +u32_t get_spiffs_file_crc_by_fd(spiffs_file fd) { + s32_t res; + u32_t crc = 0; + u8_t buf[256]; + + ASSERT(SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_SET) >= 0, "could not seek to start of file"); + + while ((res = SPIFFS_read(FS, fd, buf, sizeof(buf))) > SPIFFS_OK) { + crc = crc32(crc, buf, res); + } + ASSERT(SPIFFS_errno(FS) == SPIFFS_ERR_END_OF_OBJECT || SPIFFS_errno(FS) == SPIFFS_OK, "failed reading file"); + + return crc; +} + +u32_t get_spiffs_file_crc(char *name) { + s32_t res; + spiffs_file fd; + fd = SPIFFS_open(FS, name, SPIFFS_O_RDONLY, 0); + ASSERT(fd >= 0, "Could not open file"); + u32_t crc = get_spiffs_file_crc_by_fd(fd); + res = SPIFFS_close(FS, fd); + ASSERT(res >= SPIFFS_OK, "failing closing file"); + return crc; +} + +#if SPIFFS_CACHE +#if SPIFFS_CACHE_STATS +static u32_t chits_tot = 0; +static u32_t cmiss_tot = 0; +#endif +#endif + +void _setup_test_only() { + create_test_path(); + fs_set_validate_flashing(1); + test_init(test_on_stop); +} + +void _setup() { + _fs_locks = 0; + fs_reset(); + _setup_test_only(); +} + +void _teardown() { + printf(" free blocks : %i of %i\n", (FS)->free_blocks, (FS)->block_count); + printf(" pages allocated : %i\n", (FS)->stats_p_allocated); + printf(" pages deleted : %i\n", (FS)->stats_p_deleted); +#if SPIFFS_GC_STATS + printf(" gc runs : %i\n", (FS)->stats_gc_runs); +#endif +#if SPIFFS_CACHE +#if SPIFFS_CACHE_STATS + chits_tot += (FS)->cache_hits; + cmiss_tot += (FS)->cache_misses; + printf(" cache hits : %i (sum %i)\n", (FS)->cache_hits, chits_tot); + printf(" cache misses : %i (sum %i)\n", (FS)->cache_misses, cmiss_tot); + printf(" cache utiliz : %f\n", ((float)chits_tot/(float)(chits_tot + cmiss_tot))); + chits_tot = 0; + cmiss_tot = 0; +#endif +#endif + if (_area) { + dump_flash_access_stats(); + clear_flash_ops_log(); +#if SPIFFS_GC_STATS + if ((FS)->stats_gc_runs > 0) +#endif + dump_erase_counts(FS); + printf(" fs consistency check output begin\n"); + check_cb_count = 0; + SPIFFS_check(FS); + printf(" fs consistency check output end\n"); + if (check_cb_count) { + ERREXIT(); + } + } + clear_test_path(); + fs_free(); + printf(" locks : %i\n", _fs_locks); + if (_fs_locks != 0) { + printf("FATAL: lock asymmetry. Abort.\n"); + ERREXIT(); + exit(-1); + } +} + +u32_t tfile_get_size(tfile_size s) { + switch (s) { + case EMPTY: + return 0; + case SMALL: // half a data page + return SPIFFS_DATA_PAGE_SIZE(FS)/2; + case MEDIUM: // one block + return SPIFFS_DATA_PAGE_SIZE(FS) * (SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS)); + case LARGE: // third of fs + return SPIFFS_DATA_PAGE_SIZE(FS) * (SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS)) * (FS)->block_count/3; + } + return 0; +} + +int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg) { + int res; + tfile *tfiles = malloc(sizeof(tfile) * max_concurrent_files); + memset(tfiles, 0, sizeof(tfile) * max_concurrent_files); + int run = 0; + int cur_config_ix = 0; + char name[32]; + while (run < max_runs) { + if (dbg) printf(" run %i/%i\n", run, max_runs); + int i; + for (i = 0; i < max_concurrent_files; i++) { + sprintf(name, "file%i_%i", (1+run), i); + tfile *tf = &tfiles[i]; + if (tf->state == 0 && cur_config_ix < cfg_count) { +// create a new file + strcpy(tf->name, name); + tf->state = 1; + tf->cfg = cfgs[cur_config_ix]; + int size = tfile_get_size(tf->cfg.tsize); + if (dbg) printf(" create new %s with cfg %i/%i, size %i\n", name, (1+cur_config_ix), cfg_count, size); + + if (tf->cfg.tsize == EMPTY) { + res = SPIFFS_creat(FS, name, 0); + CHECK_RES(res); + int pfd = open(make_test_fname(name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + close(pfd); + int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0; + spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_RDWR, 0); + CHECK(fd > 0); + tf->fd = fd; + } else { + int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0; + spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + CHECK(fd > 0); + extra_flags = tf->cfg.ttype == APPENDED ? O_APPEND : 0; + int pfd = open(make_test_fname(name), extra_flags | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + tf->fd = fd; + u8_t *buf = malloc(size); + memrand(buf, size); + res = SPIFFS_write(FS, fd, buf, size); + CHECK_RES(res); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(name); + CHECK_RES(res); + } + + cur_config_ix++; + } else if (tf->state > 0) { +// hande file lifecycle + switch (tf->cfg.ttype) { + case UNTAMPERED: { + break; + } + case APPENDED: { + if (dbg) printf(" appending %s\n", tf->name); + int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; + u8_t *buf = malloc(size); + memrand(buf, size); + res = SPIFFS_write(FS, tf->fd, buf, size); + CHECK_RES(res); + int pfd = open(make_test_fname(tf->name), O_APPEND | O_RDWR); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + case MODIFIED: { + if (dbg) printf(" modify %s\n", tf->name); + spiffs_stat stat; + res = SPIFFS_fstat(FS, tf->fd, &stat); + CHECK_RES(res); + int size = stat.size / tf->cfg.tlife + SPIFFS_DATA_PAGE_SIZE(FS)/3; + int offs = (stat.size / tf->cfg.tlife) * tf->state; + res = SPIFFS_lseek(FS, tf->fd, offs, SPIFFS_SEEK_SET); + CHECK_RES(res); + u8_t *buf = malloc(size); + memrand(buf, size); + res = SPIFFS_write(FS, tf->fd, buf, size); + CHECK_RES(res); + int pfd = open(make_test_fname(tf->name), O_RDWR); + lseek(pfd, offs, SEEK_SET); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + case REWRITTEN: { + if (tf->fd > 0) { + SPIFFS_close(FS, tf->fd); + } + if (dbg) printf(" rewriting %s\n", tf->name); + spiffs_file fd = SPIFFS_open(FS, tf->name, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + CHECK(fd > 0); + int pfd = open(make_test_fname(tf->name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + tf->fd = fd; + int size = tfile_get_size(tf->cfg.tsize); + u8_t *buf = malloc(size); + memrand(buf, size); + res = SPIFFS_write(FS, fd, buf, size); + CHECK_RES(res); + write(pfd, buf, size); + close(pfd); + free(buf); + res = read_and_verify(tf->name); + CHECK_RES(res); + break; + } + } + tf->state++; + if (tf->state > tf->cfg.tlife) { +// file outlived its time, kill it + if (tf->fd > 0) { + SPIFFS_close(FS, tf->fd); + } + if (dbg) printf(" removing %s\n", tf->name); + res = read_and_verify(tf->name); + CHECK_RES(res); + res = SPIFFS_remove(FS, tf->name); + CHECK_RES(res); + remove(make_test_fname(tf->name)); + memset(tf, 0, sizeof(tfile)); + } + + } + } + + run++; + } + free(tfiles); + return 0; +} + + + diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.h new file mode 100755 index 0000000..568c38b --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/test_spiffs.h @@ -0,0 +1,108 @@ +/* + * test_spiffs.h + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +#ifndef TEST_SPIFFS_H_ +#define TEST_SPIFFS_H_ + +#include "spiffs.h" + +#define FS &__fs + +extern spiffs __fs; + + +#define CHECK(r) if (!(r)) return -1; +#define CHECK_RES(r) if (r < 0) return -1; +#define FS_PURE_DATA_PAGES(fs) \ + (SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_PAGE_SZ(fs)- (fs)->block_count * SPIFFS_OBJ_LOOKUP_PAGES(fs)) +#define FS_PURE_DATA_SIZE(fs) \ + FS_PURE_DATA_PAGES(fs) * SPIFFS_DATA_PAGE_SIZE(fs) + +typedef enum { + EMPTY, + SMALL, + MEDIUM, + LARGE, +} tfile_size; + +typedef enum { + UNTAMPERED, + APPENDED, + MODIFIED, + REWRITTEN, +} tfile_type; + +typedef enum { + SHORT = 3, + NORMAL = 15, + LONG = 100, +} tfile_life; + +typedef struct { + tfile_size tsize; + tfile_type ttype; + tfile_life tlife; +} tfile_conf; + +typedef struct { + int state; + spiffs_file fd; + tfile_conf cfg; + char name[32]; +} tfile; + +void fs_reset(); +void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size); +s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size); +void fs_mount_dump(char *fname, + u32_t addr_offset, u32_t phys_addr, u32_t phys_size, + u32_t phys_sector_size, + u32_t log_block_size, u32_t log_page_size); + +void fs_store_dump(char *fname); +void fs_load_dump(char *fname); + +void fs_set_addr_offset(u32_t offset); +int read_and_verify(char *name); +int read_and_verify_fd(spiffs_file fd, char *name); +void dump_page(spiffs *fs, spiffs_page_ix p); +void hexdump(u32_t addr, u32_t len); +char *make_test_fname(const char *name); +void clear_test_path(); +void area_write(u32_t addr, u8_t *buf, u32_t size); +void area_set(u32_t addr, u8_t d, u32_t size); +void area_read(u32_t addr, u8_t *buf, u32_t size); +void dump_erase_counts(spiffs *fs); +void dump_flash_access_stats(); +void set_flash_ops_log(int enable); +void clear_flash_ops_log(); +u32_t get_flash_ops_log_read_bytes(); +u32_t get_flash_ops_log_write_bytes(); +void invoke_error_after_read_bytes(u32_t b, char once_only); +void invoke_error_after_write_bytes(u32_t b, char once_only); +void fs_set_validate_flashing(int i); +int get_error_count(); + +void memrand(u8_t *b, int len); +int test_create_file(char *name); +int test_create_and_write_file(char *name, int size, int chunk_size); +u32_t get_spiffs_file_crc_by_fd(spiffs_file fd); +u32_t get_spiffs_file_crc(char *name); +void _setup(); +void _setup_test_only(); +void _teardown(); +u32_t tfile_get_size(tfile_size s); +int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg); + +void test_lock(spiffs *fs); +void test_unlock(spiffs *fs); + +#endif /* TEST_SPIFFS_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.c new file mode 100755 index 0000000..27419d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.c @@ -0,0 +1,238 @@ +/* + * testrunner.c + * + * Created on: Jun 18, 2013 + * Author: petera + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "testrunner.h" + +static struct { + test *tests; + test *_last_test; + int test_count; + void (*on_stop)(test *t); + test_res *failed; + test_res *failed_last; + test_res *stopped; + test_res *stopped_last; + FILE *spec; + char incl_filter[256]; + char excl_filter[256]; +} test_main; + +void test_init(void (*on_stop)(test *t)) { + test_main.on_stop = on_stop; +} + +static int abort_on_error = 0; +static int error_count = 0; + +static char check_spec(char *name) { + if (test_main.spec) { + fseek(test_main.spec, 0, SEEK_SET); + char *line = NULL; + size_t sz; + ssize_t read; + while ((read = getline(&line, &sz, test_main.spec)) != -1) { + if (strncmp(line, name, strlen(line)-1) == 0) { + free(line); + return 1; + } + } + free(line); + return 0; + } else { + return 1; + } +} + +static char check_incl_filter(char *name) { + if (strlen(test_main.incl_filter)== 0) return 1; + return strstr(name, test_main.incl_filter) == 0 ? 0 : 2; +} + +static char check_excl_filter(char *name) { + if (strlen(test_main.excl_filter)== 0) return 1; + return strstr(name, test_main.excl_filter) == 0 ? 1 : 0; +} + +void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t), int non_default) { + if (f == 0) return; + if (!check_spec(name)) return; + if (check_incl_filter(name) <= non_default) return; + if (!check_excl_filter(name)) return; + DBGT("adding test %s\n", name); + test *t = malloc(sizeof(test)); + memset(t, 0, sizeof(test)); + t->f = f; + strcpy(t->name, name); + t->setup = setup; + t->teardown = teardown; + if (test_main.tests == 0) { + test_main.tests = t; + } else { + test_main._last_test->_next = t; + } + test_main._last_test = t; + test_main.test_count++; +} + +static void add_res(test *t, test_res **head, test_res **last) { + test_res *tr = malloc(sizeof(test_res)); + memset(tr,0,sizeof(test_res)); + strcpy(tr->name, t->name); + if (*head == 0) { + *head = tr; + } else { + (*last)->_next = tr; + } + *last = tr; +} + +static void dump_res(test_res **head) { + test_res *tr = (*head); + while (tr) { + test_res *next_tr = tr->_next; + printf(" %s\n", tr->name); + free(tr); + tr = next_tr; + } +} + +int get_error_count(void) { + return error_count; +} + +void inc_error_count(void) { + error_count++; +} + +int set_abort_on_error(int val) { + int old_val = abort_on_error; + abort_on_error = val; + + return old_val; +} + +int get_abort_on_error(void) { + return abort_on_error; +} + +int run_tests(int argc, char **args) { + memset(&test_main, 0, sizeof(test_main)); + int arg; + int incl_filter = 0; + int excl_filter = 0; + for (arg = 1; arg < argc; arg++) { + if (strlen(args[arg]) == 0) continue; + if (0 == strcmp("-f", args[arg])) { + incl_filter = 1; + continue; + } + if (0 == strcmp("-e", args[arg])) { + excl_filter = 1; + continue; + } + if (incl_filter) { + strcpy(test_main.incl_filter, args[arg]); + incl_filter = 0; + } else if (excl_filter) { + strcpy(test_main.excl_filter, args[arg]); + excl_filter = 0; + } else { + printf("running tests from %s\n", args[arg]); + FILE *fd = fopen(args[1], "r"); + if (fd == NULL) { + printf("%s not found\n", args[arg]); + return -2; + } + test_main.spec = fd; + } + } + + DBGT("adding suites...\n"); + add_suites(); + DBGT("%i tests added\n", test_main.test_count); + if (test_main.spec) { + fclose(test_main.spec); + } + + if (test_main.test_count == 0) { + printf("No tests to run\n"); + return 0; + } + + int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + DBGT("running tests...\n"); + int ok = 0; + int failed = 0; + int stopped = 0; + test *cur_t = test_main.tests; + int i = 1; + while (cur_t) { + cur_t->setup(cur_t); + test *next_test = cur_t->_next; + DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name); + i++; + int start_error_count = get_error_count(); + int res = cur_t->f(cur_t); + if (res == TEST_RES_OK && get_error_count() != start_error_count) { + res = TEST_RES_FAIL; + } + cur_t->test_result = res; + int fd = res == TEST_RES_OK ? fd_success : fd_bad; + write(fd, cur_t->name, strlen(cur_t->name)); + write(fd, "\n", 1); + switch (res) { + case TEST_RES_OK: + ok++; + printf(" .. ok\n"); + break; + case TEST_RES_FAIL: + failed++; + printf(" .. FAILED\n"); + if (test_main.on_stop) test_main.on_stop(cur_t); + add_res(cur_t, &test_main.failed, &test_main.failed_last); + break; + case TEST_RES_ASSERT: + stopped++; + printf(" .. ABORTED\n"); + if (test_main.on_stop) test_main.on_stop(cur_t); + add_res(cur_t, &test_main.stopped, &test_main.stopped_last); + break; + } + cur_t->teardown(cur_t); + free(cur_t); + cur_t = next_test; + } + close(fd_success); + close(fd_bad); + DBGT("ran %i tests\n", test_main.test_count); + printf("Test report, %i tests\n", test_main.test_count); + printf("%i succeeded\n", ok); + printf("%i failed\n", failed); + dump_res(&test_main.failed); + printf("%i stopped\n", stopped); + dump_res(&test_main.stopped); + if (ok < test_main.test_count) { + printf("\nFAILED\n"); + return -1; + } else { + printf("\nALL TESTS OK\n"); + return 0; + } +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.h b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.h new file mode 100755 index 0000000..697fb09 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testrunner.h @@ -0,0 +1,165 @@ +/* + * testrunner.h + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +/* + +file mysuite.c: + +SUITE(mysuite) + +static void setup(test *t) {} + +static void teardown(test *t) {} + +TEST(mytest) { + printf("mytest runs now..\n"); + return 0; +} TEST_END + +SUITE_TESTS(mysuite) + ADD_TEST(mytest) +SUITE_END(mysuite) + + + +file mysuite2.c: + +SUITE(mysuite2) + +static void setup(test *t) {} + +static void teardown(test *t) {} + +TEST(mytest2a) { + printf("mytest2a runs now..\n"); + return 0; +} TEST_END + +TEST(mytest2b) { + printf("mytest2b runs now..\n"); + return 0; +} TEST_END + +SUITE_TESTS(mysuite2) + ADD_TEST(mytest2a) + ADD_TEST(mytest2b) +SUITE_END(mysuite2) + + +some other file.c: + +void add_suites() { + ADD_SUITE(mysuite); + ADD_SUITE(mysuite2); +} + */ + +#ifndef TESTRUNNER_H_ +#define TESTRUNNER_H_ + +#define TEST_RES_OK 0 +#define TEST_RES_FAIL -1 +#define TEST_RES_ASSERT -2 + +#define ERREXIT() if (get_abort_on_error()) abort(); else inc_error_count() + +struct test_s; + +typedef int (*test_f)(struct test_s *t); + +typedef struct test_s { + test_f f; + char name[256]; + void *data; + void (*setup)(struct test_s *t); + void (*teardown)(struct test_s *t); + struct test_s *_next; + unsigned char test_result; +} test; + +typedef struct test_res_s { + char name[256]; + struct test_res_s *_next; +} test_res; + +#define TEST_CHECK(x) if (!(x)) { \ + printf(" TEST FAIL %s:%d\n", __FILE__, __LINE__); \ + goto __fail_stop; \ +} +#define TEST_CHECK_EQ(x, y) if ((x) != (y)) { \ + printf(" TEST FAIL %s:%d, %d != %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_NEQ(x, y) if ((x) == (y)) { \ + printf(" TEST FAIL %s:%d, %d == %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_GT(x, y) if ((x) <= (y)) { \ + printf(" TEST FAIL %s:%d, %d <= %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_LT(x, y) if ((x) >= (y)) { \ + printf(" TEST FAIL %s:%d, %d >= %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_GE(x, y) if ((x) < (y)) { \ + printf(" TEST FAIL %s:%d, %d < %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_CHECK_LE(x, y) if ((x) > (y)) { \ + printf(" TEST FAIL %s:%d, %d > %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ + goto __fail_stop; \ +} +#define TEST_ASSERT(x) if (!(x)) { \ + printf(" TEST ASSERT %s:%d\n", __FILE__, __LINE__); \ + goto __fail_assert; \ +} + +#define DBGT(...) printf(__VA_ARGS__) + +#define str(s) #s + +#define SUITE(sui) + +#define SUITE_TESTS(sui) \ + void _add_suite_tests_##sui(void) { + +#define SUITE_END(sui) \ + } + +#define ADD_TEST(tf) \ + _add_test(__test_##tf, str(tf), setup, teardown, 0); + +#define ADD_TEST_NON_DEFAULT(tf) \ + _add_test(__test_##tf, str(tf), setup, teardown, 1); + +#define ADD_SUITE(sui) \ + extern void _add_suite_tests_##sui(void); \ + _add_suite_tests_##sui(); + +#define TEST(tf) \ + static int __test_##tf(struct test_s *t) { do + +#define TEST_END \ + while(0); \ + __fail_stop: return TEST_RES_FAIL; \ + __fail_assert: return TEST_RES_ASSERT; \ + } + +int set_abort_on_error(int val); +int get_abort_on_error(void); +int get_error_count(void); +void inc_error_count(void); + +void add_suites(void); +void test_init(void (*on_stop)(test *t)); +// returns 0 if all tests ok, -1 if any test failed, -2 on badness +int run_tests(int argc, char **args); +void _add_suite(const char *suite_name); +void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t), int non_default); + +#endif /* TESTRUNNER_H_ */ diff --git a/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testsuites.c b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testsuites.c new file mode 100755 index 0000000..cce5cd9 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/spiffs/src/test/testsuites.c @@ -0,0 +1,15 @@ +/* + * testsuites.c + * + * Created on: Jun 19, 2013 + * Author: petera + */ + +#include "testrunner.h" + +void add_suites(void) { + //ADD_SUITE(dev_tests); + ADD_SUITE(check_tests); + ADD_SUITE(hydrogen_tests); + ADD_SUITE(bug_tests); +} diff --git a/src/openmv/src/micropython/ports/k210-standalone/todo.md b/src/openmv/src/micropython/ports/k210-standalone/todo.md new file mode 100755 index 0000000..a8038e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/k210-standalone/todo.md @@ -0,0 +1,42 @@ +UART ok +GPIO ok +GPIOHS(上下沿触å‘) pause +PWM test +SYS +---------------------- +I2C +SPI +I2S +RTC + +DVP +WDT + +TIMER +PLIC +FFT +---------------------- + +SHA256 +aes + +FPIOA(首先包å«åœ¨å…¶å®ƒæ¨¡å—çš„åˆå§‹åŒ–中,åŽé¢å†è€ƒè™‘å•ç‹¬å‡ºæ¥) +DMAC (包å«åœ¨å…¶ä»–模å—内) + + + +应用 +文件系统(SPIFFS) +upip +设备抽象 + spi flashæ“作 + tf æ“作 + 按键 + RGB LED + WS2812 + MCU LCD + MIC + Speaker + camera +基础网络 +mqtt diff --git a/src/openmv/src/micropython/ports/minimal/Makefile b/src/openmv/src/micropython/ports/minimal/Makefile new file mode 100755 index 0000000..64ad3cc --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/Makefile @@ -0,0 +1,91 @@ +include ../../py/mkenv.mk + +CROSS = 0 + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +ifeq ($(CROSS), 1) +CROSS_COMPILE = arm-none-eabi- +endif + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +ifeq ($(CROSS), 1) +DFU = $(TOP)/tools/dfu.py +PYDFU = $(TOP)/tools/pydfu.py +CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion +CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) +LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections +else +LD = gcc +CFLAGS = -m32 $(INC) -Wall -Werror -std=c99 $(COPT) +LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections +endif + +# Tune for Debugging or Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -O0 -ggdb +else +CFLAGS += -Os -DNDEBUG +CFLAGS += -fdata-sections -ffunction-sections +endif + +LIBS = + +SRC_C = \ + main.c \ + uart_core.c \ + lib/utils/printf.c \ + lib/utils/stdout_helpers.c \ + lib/utils/pyexec.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ + $(BUILD)/_frozen_mpy.c \ + +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +ifeq ($(CROSS), 1) +all: $(BUILD)/firmware.dfu +else +all: $(BUILD)/firmware.elf +endif + +$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h + $(ECHO) "MISC freezing bytecode" + $(Q)$(TOP)/tools/mpy-tool.py -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=none $< > $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.bin + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/firmware.bin $@ + +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" + $(Q)$(PYTHON) $(PYDFU) -u $< + +# Run emulation build on a POSIX system with suitable terminal settings +run: + stty raw opost -echo + build/firmware.elf + @echo Resetting terminal... +# This sleep is useful to spot segfaults + sleep 1 + reset + +test: $(BUILD)/firmware.elf + $(Q)/bin/echo -e "print('hello world!', list(x+1 for x in range(10)), end='eol\\\\n')\\r\\n\\x04" | $(BUILD)/firmware.elf | tail -n2 | grep "^hello world! \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]eol" + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/minimal/README.md b/src/openmv/src/micropython/ports/minimal/README.md new file mode 100755 index 0000000..356fc4b --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/README.md @@ -0,0 +1,47 @@ +# The minimal port + +This port is intended to be a minimal MicroPython port that actually runs. +It can run under Linux (or similar) and on any STM32F4xx MCU (eg the pyboard). + +## Building and running Linux version + +By default the port will be built for the host machine: + + $ make + +To run the executable and get a basic working REPL do: + + $ make run + +## Building for an STM32 MCU + +The Makefile has the ability to build for a Cortex-M CPU, and by default +includes some start-up code for an STM32F4xx MCU and also enables a UART +for communication. To build: + + $ make CROSS=1 + +If you previously built the Linux version, you will need to first run +`make clean` to get rid of incompatible object files. + +Building will produce the build/firmware.dfu file which can be programmed +to an MCU using: + + $ make CROSS=1 deploy + +This version of the build will work out-of-the-box on a pyboard (and +anything similar), and will give you a MicroPython REPL on UART1 at 9600 +baud. Pin PA13 will also be driven high, and this turns on the red LED on +the pyboard. + +## Building without the built-in MicroPython compiler + +This minimal port can be built with the built-in MicroPython compiler +disabled. This will reduce the firmware by about 20k on a Thumb2 machine, +and by about 40k on 32-bit x86. Without the compiler the REPL will be +disabled, but pre-compiled scripts can still be executed. + +To test out this feature, change the `MICROPY_ENABLE_COMPILER` config +option to "0" in the mpconfigport.h file in this directory. Then +recompile and run the firmware and it will execute the frozentest.py +file. diff --git a/src/openmv/src/micropython/ports/minimal/frozentest.mpy b/src/openmv/src/micropython/ports/minimal/frozentest.mpy new file mode 100755 index 0000000..7c6809b Binary files /dev/null and b/src/openmv/src/micropython/ports/minimal/frozentest.mpy differ diff --git a/src/openmv/src/micropython/ports/minimal/frozentest.py b/src/openmv/src/micropython/ports/minimal/frozentest.py new file mode 100755 index 0000000..0f99b74 --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/frozentest.py @@ -0,0 +1,7 @@ +print('uPy') +print('a long string that is not interned') +print('a string that has unicode αβγ chars') +print(b'bytes 1234\x01') +print(123456789) +for i in range(4): + print(i) diff --git a/src/openmv/src/micropython/ports/minimal/main.c b/src/openmv/src/micropython/ports/minimal/main.c new file mode 100755 index 0000000..5e145dc --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/main.c @@ -0,0 +1,258 @@ +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "lib/utils/pyexec.h" + +#if MICROPY_ENABLE_COMPILER +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} +#endif + +static char *stack_top; +#if MICROPY_ENABLE_GC +static char heap[2048]; +#endif + +int main(int argc, char **argv) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + #if MICROPY_ENABLE_COMPILER + #if MICROPY_REPL_EVENT_DRIVEN + pyexec_event_repl_init(); + for (;;) { + int c = mp_hal_stdin_rx_chr(); + if (pyexec_event_repl_process_char(c)) { + break; + } + } + #else + pyexec_friendly_repl(); + #endif + //do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT); + //do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT); + #else + pyexec_frozen_module("frozentest.py"); + #endif + mp_deinit(); + return 0; +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + void *dummy; + gc_collect_start(); + gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_end(); + gc_dump_info(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + while (1); +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif + +#if MICROPY_MIN_USE_CORTEX_CPU + +// this is a minimal IRQ and reset framework for any Cortex-M CPU + +extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss; + +void Reset_Handler(void) __attribute__((naked)); +void Reset_Handler(void) { + // set stack pointer + __asm volatile ("ldr sp, =_estack"); + // copy .data section from flash to RAM + for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) { + *dest++ = *src++; + } + // zero out .bss section + for (uint32_t *dest = &_sbss; dest < &_ebss;) { + *dest++ = 0; + } + // jump to board initialisation + void _start(void); + _start(); +} + +void Default_Handler(void) { + for (;;) { + } +} + +const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = { + (uint32_t)&_estack, + (uint32_t)&Reset_Handler, + (uint32_t)&Default_Handler, // NMI_Handler + (uint32_t)&Default_Handler, // HardFault_Handler + (uint32_t)&Default_Handler, // MemManage_Handler + (uint32_t)&Default_Handler, // BusFault_Handler + (uint32_t)&Default_Handler, // UsageFault_Handler + 0, + 0, + 0, + 0, + (uint32_t)&Default_Handler, // SVC_Handler + (uint32_t)&Default_Handler, // DebugMon_Handler + 0, + (uint32_t)&Default_Handler, // PendSV_Handler + (uint32_t)&Default_Handler, // SysTick_Handler +}; + +void _start(void) { + // when we get here: stack is initialised, bss is clear, data is copied + + // SCB->CCR: enable 8-byte stack alignment for IRQ handlers, in accord with EABI + *((volatile uint32_t*)0xe000ed14) |= 1 << 9; + + // initialise the cpu and peripherals + #if MICROPY_MIN_USE_STM32_MCU + void stm32_init(void); + stm32_init(); + #endif + + // now that we have a basic system up and running we can call main + main(0, NULL); + + // we must not return + for (;;) { + } +} + +#endif + +#if MICROPY_MIN_USE_STM32_MCU + +// this is minimal set-up code for an STM32 MCU + +typedef struct { + volatile uint32_t CR; + volatile uint32_t PLLCFGR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + uint32_t _1[8]; + volatile uint32_t AHB1ENR; + volatile uint32_t AHB2ENR; + volatile uint32_t AHB3ENR; + uint32_t _2; + volatile uint32_t APB1ENR; + volatile uint32_t APB2ENR; +} periph_rcc_t; + +typedef struct { + volatile uint32_t MODER; + volatile uint32_t OTYPER; + volatile uint32_t OSPEEDR; + volatile uint32_t PUPDR; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile uint16_t BSRRL; + volatile uint16_t BSRRH; + volatile uint32_t LCKR; + volatile uint32_t AFR[2]; +} periph_gpio_t; + +typedef struct { + volatile uint32_t SR; + volatile uint32_t DR; + volatile uint32_t BRR; + volatile uint32_t CR1; +} periph_uart_t; + +#define USART1 ((periph_uart_t*) 0x40011000) +#define GPIOA ((periph_gpio_t*) 0x40020000) +#define GPIOB ((periph_gpio_t*) 0x40020400) +#define RCC ((periph_rcc_t*) 0x40023800) + +// simple GPIO interface +#define GPIO_MODE_IN (0) +#define GPIO_MODE_OUT (1) +#define GPIO_MODE_ALT (2) +#define GPIO_PULL_NONE (0) +#define GPIO_PULL_UP (0) +#define GPIO_PULL_DOWN (1) +void gpio_init(periph_gpio_t *gpio, int pin, int mode, int pull, int alt) { + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | (mode << (2 * pin)); + // OTYPER is left as default push-pull + // OSPEEDR is left as default low speed + gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} +#define gpio_get(gpio, pin) ((gpio->IDR >> (pin)) & 1) +#define gpio_set(gpio, pin, value) do { gpio->ODR = (gpio->ODR & ~(1 << (pin))) | (value << pin); } while (0) +#define gpio_low(gpio, pin) do { gpio->BSRRH = (1 << (pin)); } while (0) +#define gpio_high(gpio, pin) do { gpio->BSRRL = (1 << (pin)); } while (0) + +void stm32_init(void) { + // basic MCU config + RCC->CR |= (uint32_t)0x00000001; // set HSION + RCC->CFGR = 0x00000000; // reset all + RCC->CR &= (uint32_t)0xfef6ffff; // reset HSEON, CSSON, PLLON + RCC->PLLCFGR = 0x24003010; // reset PLLCFGR + RCC->CR &= (uint32_t)0xfffbffff; // reset HSEBYP + RCC->CIR = 0x00000000; // disable IRQs + + // leave the clock as-is (internal 16MHz) + + // enable GPIO clocks + RCC->AHB1ENR |= 0x00000003; // GPIOAEN, GPIOBEN + + // turn on an LED! (on pyboard it's the red one) + gpio_init(GPIOA, 13, GPIO_MODE_OUT, GPIO_PULL_NONE, 0); + gpio_high(GPIOA, 13); + + // enable UART1 at 9600 baud (TX=B6, RX=B7) + gpio_init(GPIOB, 6, GPIO_MODE_ALT, GPIO_PULL_NONE, 7); + gpio_init(GPIOB, 7, GPIO_MODE_ALT, GPIO_PULL_NONE, 7); + RCC->APB2ENR |= 0x00000010; // USART1EN + USART1->BRR = (104 << 4) | 3; // 16MHz/(16*104.1875) = 9598 baud + USART1->CR1 = 0x0000200c; // USART enable, tx enable, rx enable +} + +#endif diff --git a/src/openmv/src/micropython/ports/minimal/mpconfigport.h b/src/openmv/src/micropython/ports/minimal/mpconfigport.h new file mode 100755 index 0000000..13435a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/mpconfigport.h @@ -0,0 +1,99 @@ +#include + +// options to control how MicroPython is built + +// You can disable the built-in MicroPython compiler by setting the following +// config option to 0. If you do this then you won't get a REPL prompt, but you +// will still be able to execute pre-compiled scripts, compiled with mpy-cross. +#define MICROPY_ENABLE_COMPILER (1) + +#define MICROPY_QSTR_BYTES_IN_HASH (1) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_REPL_EVENT_DRIVEN (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (0) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +// This port is intended to be 32-bit, but unfortunately, int32_t for +// different targets may be defined in different ways - either as int +// or as long. This requires different printf formatting specifiers +// to print such value. So, we avoid int32_t and use int directly. +#define UINT_FMT "%u" +#define INT_FMT "%d" +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size + +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// We need to provide a declaration/definition of alloca() +#include + +#define MICROPY_HW_BOARD_NAME "minimal" +#define MICROPY_HW_MCU_NAME "unknown-cpu" + +#ifdef __linux__ +#define MICROPY_MIN_USE_STDOUT (1) +#endif + +#ifdef __thumb__ +#define MICROPY_MIN_USE_CORTEX_CPU (1) +#define MICROPY_MIN_USE_STM32_MCU (1) +#endif + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/src/openmv/src/micropython/ports/minimal/mphalport.h b/src/openmv/src/micropython/ports/minimal/mphalport.h new file mode 100755 index 0000000..60d68bd --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/mphalport.h @@ -0,0 +1,2 @@ +static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; } +static inline void mp_hal_set_interrupt_char(char c) {} diff --git a/src/openmv/src/micropython/ports/minimal/qstrdefsport.h b/src/openmv/src/micropython/ports/minimal/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/minimal/stm32f405.ld b/src/openmv/src/micropython/ports/minimal/stm32f405.ld new file mode 100755 index 0000000..a202294 --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/stm32f405.ld @@ -0,0 +1,63 @@ +/* + GNU linker script for STM32F405 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */ + CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */ +} + +/* top end of the stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* define output sections */ +SECTIONS +{ + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* isr vector table */ + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ + } >FLASH + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code */ + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/minimal/uart_core.c b/src/openmv/src/micropython/ports/minimal/uart_core.c new file mode 100755 index 0000000..d2d17b4 --- /dev/null +++ b/src/openmv/src/micropython/ports/minimal/uart_core.c @@ -0,0 +1,44 @@ +#include +#include "py/mpconfig.h" + +/* + * Core UART functions to implement for a port + */ + +#if MICROPY_MIN_USE_STM32_MCU +typedef struct { + volatile uint32_t SR; + volatile uint32_t DR; +} periph_uart_t; +#define USART1 ((periph_uart_t*)0x40011000) +#endif + +// Receive single character +int mp_hal_stdin_rx_chr(void) { + unsigned char c = 0; +#if MICROPY_MIN_USE_STDOUT + int r = read(0, &c, 1); + (void)r; +#elif MICROPY_MIN_USE_STM32_MCU + // wait for RXNE + while ((USART1->SR & (1 << 5)) == 0) { + } + c = USART1->DR; +#endif + return c; +} + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { +#if MICROPY_MIN_USE_STDOUT + int r = write(1, str, len); + (void)r; +#elif MICROPY_MIN_USE_STM32_MCU + while (len--) { + // wait for TXE + while ((USART1->SR & (1 << 7)) == 0) { + } + USART1->DR = *str++; + } +#endif +} diff --git a/src/openmv/src/micropython/ports/nrf/.gitignore b/src/openmv/src/micropython/ports/nrf/.gitignore new file mode 100755 index 0000000..ace9351 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/.gitignore @@ -0,0 +1,8 @@ +# Nordic files +##################### +drivers/bluetooth/s1*/ + +# Build files +##################### +build-*/ + diff --git a/src/openmv/src/micropython/ports/nrf/Makefile b/src/openmv/src/micropython/ports/nrf/Makefile new file mode 100755 index 0000000..6ca83f1 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/Makefile @@ -0,0 +1,355 @@ +# Select the board to build for: if not given on the command line, +# then default to pca10040. +BOARD ?= pca10040 +ifeq ($(wildcard boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# If SoftDevice is selected, try to use that one. +SD ?= +SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]') + +# TODO: Verify that it is a valid target. + +include boards/$(BOARD)/mpconfigboard.mk + +ifeq ($(SD), ) + # If the build directory is not given, make it reflect the board name. + BUILD ?= build-$(BOARD) + include ../../py/mkenv.mk +else + # If the build directory is not given, make it reflect the board name. + BUILD ?= build-$(BOARD)-$(SD_LOWER) + include ../../py/mkenv.mk + + LD_FILES += boards/$(SD_LOWER)_$(SOFTDEV_VERSION).ld + include drivers/bluetooth/bluetooth_common.mk +endif + +LD_FILES += boards/memory.ld boards/common.ld + +ifneq ($(LD_FILE),) + # Use custom LD file + LD_FILES = $(LD_FILE) +endif + +-include boards/$(BOARD)/modules/boardmodules.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h + +# include py core make definitions +include ../../py/py.mk + +MICROPY_FATFS ?= 0 +FATFS_DIR = lib/oofatfs +MPY_CROSS = ../../mpy-cross/mpy-cross +MPY_TOOL = ../../tools/mpy-tool.py + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I../.. +INC += -I$(BUILD) +INC += -I./../../lib/cmsis/inc +INC += -I./modules/machine +INC += -I./modules/ubluepy +INC += -I./modules/music +INC += -I./modules/random +INC += -I./modules/ble +INC += -I./modules/board +INC += -I../../lib/mp-readline +INC += -I./drivers/bluetooth +INC += -I./drivers +INC += -I../../lib/nrfx/ +INC += -I../../lib/nrfx/drivers +INC += -I../../lib/nrfx/drivers/include +INC += -I../../lib/nrfx/mdk +INC += -I../../lib/nrfx/hal + +MCU_VARIANT_UPPER = $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') +MCU_SUB_VARIANT_UPPER = $(shell echo $(MCU_SUB_VARIANT) | tr '[:lower:]' '[:upper:]') + +# Figure out correct system file to use base on chip sub-variant name. +SYSTEM_C_SRC := +ifeq ($(MCU_SUB_VARIANT),nrf51822) + SYSTEM_C_SRC += $(addprefix lib/nrfx/mdk/, system_nrf51.c) + NRF_DEFINES += -D$(MCU_VARIANT_UPPER) +else ifeq ($(MCU_SUB_VARIANT),nrf52832) + SYSTEM_C_SRC += $(addprefix lib/nrfx/mdk/, system_nrf52.c) + NRF_DEFINES += -D$(MCU_VARIANT_UPPER) +else ifeq ($(MCU_SUB_VARIANT),nrf52840) + SYSTEM_C_SRC += $(addprefix lib/nrfx/mdk/, system_nrf52840.c) + # Do not pass MCU_VARIANT_UPPER flag, as NRF52 defines NRF52832 only. +endif + +NRF_DEFINES += -D$(MCU_SUB_VARIANT_UPPER) +NRF_DEFINES += -DCONFIG_GPIO_AS_PINRESET + +CFLAGS_CORTEX_M = -mthumb -mabi=aapcs -fsingle-precision-constant -Wdouble-promotion + +CFLAGS_MCU_m4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard + +CFLAGS_MCU_m0 = $(CFLAGS_CORTEX_M) -fshort-enums -mtune=cortex-m0 -mcpu=cortex-m0 -mfloat-abi=soft -fno-builtin + +LTO ?= 1 +ifeq ($(LTO),1) +CFLAGS += -flto +else +CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS += -Wl,--gc-sections +endif + + +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(INC) -Wall -Werror -g -ansi -std=c11 -nostdlib $(COPT) $(NRF_DEFINES) $(CFLAGS_MOD) +CFLAGS += -fno-strict-aliasing +CFLAGS += -Iboards/$(BOARD) +CFLAGS += -DNRF5_HAL_H='<$(MCU_VARIANT)_hal.h>' + +LDFLAGS = $(CFLAGS) +LDFLAGS += -Xlinker -Map=$(@:.elf=.map) +LDFLAGS += -mthumb -mabi=aapcs $(addprefix -T,$(LD_FILES)) -L boards/ + +#Debugging/Optimization +ifeq ($(DEBUG), 1) +#ASMFLAGS += -g -gtabs+ +CFLAGS += -O0 -ggdb +LDFLAGS += -O0 +else +CFLAGS += -Os -DNDEBUG +LDFLAGS += -Os +endif + +LIBS = \ + +ifeq ($(MCU_VARIANT), nrf52) +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc + + +SRC_LIB += $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/nearbyintf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + ) + +endif + +SRC_LIB += $(addprefix lib/,\ + libc/string0.c \ + mp-readline/readline.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + timeutils/timeutils.c \ + ) + +ifeq ($(MICROPY_FATFS), 1) +SRC_LIB += $(addprefix lib/,\ + oofatfs/ff.c \ + oofatfs/option/unicode.c \ + ) +endif + + +SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\ + prs/nrfx_prs.c \ + nrfx_uart.c \ + nrfx_adc.c \ + nrfx_saadc.c \ + nrfx_rng.c \ + nrfx_twi.c \ + nrfx_spi.c \ + nrfx_spim.c \ + nrfx_rtc.c \ + nrfx_timer.c \ + nrfx_pwm.c \ + nrfx_gpiote.c \ + ) + +SRC_NRFX_HAL += $(addprefix lib/nrfx/hal/,\ + nrf_nvmc.c \ + ) + +SRC_C += \ + main.c \ + mphalport.c \ + help.c \ + gccollect.c \ + pin_named_pins.c \ + fatfs_port.c \ + drivers/flash.c \ + drivers/softpwm.c \ + drivers/ticker.c \ + drivers/bluetooth/ble_drv.c \ + drivers/bluetooth/ble_uart.c \ + +DRIVERS_SRC_C += $(addprefix modules/,\ + machine/modmachine.c \ + machine/uart.c \ + machine/spi.c \ + machine/i2c.c \ + machine/adc.c \ + machine/pin.c \ + machine/timer.c \ + machine/rtcounter.c \ + machine/pwm.c \ + machine/temp.c \ + uos/moduos.c \ + uos/microbitfs.c \ + utime/modutime.c \ + board/modboard.c \ + board/led.c \ + ubluepy/modubluepy.c \ + ubluepy/ubluepy_peripheral.c \ + ubluepy/ubluepy_service.c \ + ubluepy/ubluepy_characteristic.c \ + ubluepy/ubluepy_uuid.c \ + ubluepy/ubluepy_delegate.c \ + ubluepy/ubluepy_constants.c \ + ubluepy/ubluepy_descriptor.c \ + ubluepy/ubluepy_scanner.c \ + ubluepy/ubluepy_scan_entry.c \ + music/modmusic.c \ + music/musictunes.c \ + ble/modble.c \ + random/modrandom.c \ + ) + +# Custom micropython startup file with smaller interrupt vector table +# than the file provided in nrfx. +SRC_C += \ + device/startup_$(MCU_SUB_VARIANT).c \ + +ifneq ($(FROZEN_MPY_DIR),) +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) +endif + +OBJ += $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX_HAL:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SYSTEM_C_SRC:.c=.o)) +OBJ += $(BUILD)/pins_gen.o + +$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os +$(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os + +.PHONY: all flash sd binary hex + +all: binary hex + +OUTPUT_FILENAME = firmware + +## Create binary .bin file from the .out file +binary: $(BUILD)/$(OUTPUT_FILENAME).bin + +$(BUILD)/$(OUTPUT_FILENAME).bin: $(BUILD)/$(OUTPUT_FILENAME).elf + $(OBJCOPY) -O binary $< $@ + +## Create binary .hex file from the .out file +hex: $(BUILD)/$(OUTPUT_FILENAME).hex + +$(BUILD)/$(OUTPUT_FILENAME).hex: $(BUILD)/$(OUTPUT_FILENAME).elf + $(OBJCOPY) -O ihex $< $@ + +FLASHER ?= + +ifeq ($(FLASHER),) + +flash: $(BUILD)/$(OUTPUT_FILENAME).hex + nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) + nrfjprog --reset -f $(MCU_VARIANT) + +sd: $(BUILD)/$(OUTPUT_FILENAME).hex + nrfjprog --eraseall -f $(MCU_VARIANT) + nrfjprog --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) + nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) + nrfjprog --reset -f $(MCU_VARIANT) + +else ifeq ($(FLASHER), pyocd) + +flash: $(BUILD)/$(OUTPUT_FILENAME).hex + pyocd-flashtool -t $(MCU_VARIANT) $< + +sd: $(BUILD)/$(OUTPUT_FILENAME).hex + pyocd-flashtool -t $(MCU_VARIANT) --chip_erase + pyocd-flashtool -t $(MCU_VARIANT) $(SOFTDEV_HEX) + pyocd-flashtool -t $(MCU_VARIANT) $< + +endif + +$(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + $(Q)$(SIZE) $@ + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(DRIVERS_SRC_C) $(SRC_BOARD_MODULES) + +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +# Making OBJ use an order-only depenedency on the generated pins.h file +# has the side effect of making the pins.h file before we actually compile +# any of the objects. The normal dependency generation will deal with the +# case when pins.h is modified. But when it doesn't exist, we don't know +# which source files might need it. +$(OBJ): | $(HEADER_BUILD)/pins.h + +# Use a pattern rule here so that make will only call make-pins.py once to make +# both pins_gen.c and pins.h +$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) + +$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c + $(call compile_c) + +MAKE_PINS = boards/make-pins.py +BOARD_PINS = boards/$(BOARD)/pins.csv +AF_FILE = $(MCU_VARIANT)_af.csv +PREFIX_FILE = boards/$(MCU_VARIANT)_prefix.c +GEN_PINS_SRC = $(BUILD)/pins_gen.c +GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(BUILD)/pins_qstr.h +GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h +GEN_PINS_AF_PY = $(BUILD)/pins_af.py + +ifneq ($(FROZEN_DIR),) +# To use frozen source modules, put your .py files in a subdirectory (eg scripts/) +# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch). +CFLAGS += -DMICROPY_MODULE_FROZEN_STR +endif + +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +endif + +$(PY_BUILD)/nlr%.o: CFLAGS += -Os -fno-lto + +include ../../py/mkrules.mk + diff --git a/src/openmv/src/micropython/ports/nrf/README.md b/src/openmv/src/micropython/ports/nrf/README.md new file mode 100755 index 0000000..20170e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/README.md @@ -0,0 +1,147 @@ +# MicroPython Port To The Nordic Semiconductor nRF Series + +This is a port of MicroPython to the Nordic Semiconductor nRF series of chips. + +## Supported Features + +* UART +* SPI +* LEDs +* Pins +* ADC +* I2C +* PWM (nRF52 only) +* Temperature +* RTC (Real Time Counter. Low-Power counter) +* BLE support including: + * Peripheral role on nrf51 targets + * Central role and Peripheral role on nrf52 targets + * _REPL over Bluetooth LE_ (optionally using WebBluetooth) + * ubluepy: Bluetooth LE module for MicroPython + * 1 non-connectable advertiser while in connection + +## Tested Hardware + +* nRF51 + * [micro:bit](http://microbit.org/) + * PCA10000 (dongle) + * PCA10001 + * PCA10028 + * PCA10031 (dongle) + * [WT51822-S4AT](http://www.wireless-tag.com/wireless_module/BLE/WT51822-S4AT.html) +* nRF52832 + * [PCA10040](http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52%2Fdita%2Fnrf52%2Fdevelopment%2Fnrf52_dev_kit.html) + * [Adafruit Feather nRF52](https://www.adafruit.com/product/3406) + * [Thingy:52](http://www.nordicsemi.com/eng/Products/Nordic-Thingy-52) + * [Arduino Primo](http://www.arduino.org/products/boards/arduino-primo) +* nRF52840 + * [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK) + +## Compile and Flash + +Prerequisite steps for building the nrf port: + + git clone .git micropython + cd micropython + git submodule update --init + make -C mpy-cross + +By default, the PCA10040 (nrf52832) is used as compile target. To build and flash issue the following command inside the ports/nrf/ folder: + + make + make flash + +Alternatively the target board could be defined: + + make BOARD=pca10040 + make flash + +## Compile and Flash with Bluetooth Stack + +First prepare the bluetooth folder by downloading Bluetooth LE stacks and headers: + + ./drivers/bluetooth/download_ble_stack.sh + +If the Bluetooth stacks has been downloaded, compile the target with the following command: + + make BOARD=pca10040 SD=s132 + +The **make sd** will trigger a flash of the bluetooth stack before that application is flashed. Note that **make sd** will perform a full erase of the chip, which could cause 3rd party bootloaders to also be wiped. + + make BOARD=pca10040 SD=s132 sd + +Note: further tuning of features to include in bluetooth or even setting up the device to use REPL over Bluetooth can be configured in the `bluetooth_conf.h`. + +## Compile with frozen modules + +Frozen modules are Python modules compiled to bytecode and added to the firmware +image, as part of MicroPython. They can be imported as usual, using the `import` +statement. The advantage is that frozen modules use a lot less RAM as the +bytecode is stored in flash, not in RAM like when importing from a filesystem. +Also, frozen modules are available even when no filesystem is present to import +from. + +To use frozen modules, put them in a directory (e.g. `freeze/`) and supply +`make` with the given directory. For example: + + make BOARD=pca10040 FROZEN_MPY_DIR=freeze + +## Enable MICROPY_FATFS +As the `oofatfs` module is not having header guards that can exclude the implementation compile time, this port provides a flag to enable it explicitly. The MICROPY_FATFS is by default set to 0 and has to be set to 1 if `oofatfs` files should be compiled. This will be in addition of setting `MICROPY_VFS` and `MICROPY_VFS_FAT` in mpconfigport.h. + +For example: + + make BOARD=pca10040 MICROPY_FATFS=1 + +## Target Boards and Make Flags + +Target Board (BOARD) | Bluetooth Stack (SD) | Bluetooth Support | Flash Util +---------------------|-------------------------|------------------------|------------------------------- +microbit | s110 | Peripheral | [PyOCD](#pyocdopenocd-targets) +pca10000 | s110 | Peripheral | [Segger](#segger-targets) +pca10001 | s110 | Peripheral | [Segger](#segger-targets) +pca10028 | s110 | Peripheral | [Segger](#segger-targets) +pca10031 | s110 | Peripheral | [Segger](#segger-targets) +wt51822_s4at | s110 | Peripheral | Manual, see [datasheet](https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf) for pinout +pca10040 | s132 | Peripheral and Central | [Segger](#segger-targets) +feather52 | s132 | Peripheral and Central | Manual, SWDIO and SWCLK solder points on the bottom side of the board +arduino_primo | s132 | Peripheral and Central | [PyOCD](#pyocdopenocd-targets) +pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets) + +## Segger Targets + +Install the necessary tools to flash and debug using Segger: + +[JLink Download](https://www.segger.com/downloads/jlink#) + +[nrfjprog linux-32bit Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Linux32/58857) + +[nrfjprog linux-64bit Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Linux64/58852) + +[nrfjprog osx Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-OSX/58855) + +[nrfjprog win32 Download](https://www.nordicsemi.com/eng/nordic/Products/nRF52840/nRF5x-Command-Line-Tools-Win32/58850) + +note: On Linux it might be required to link SEGGER's `libjlinkarm.so` inside nrfjprog's folder. + +## PyOCD/OpenOCD Targets + +Install the necessary tools to flash and debug using OpenOCD: + + sudo apt-get install openocd + sudo pip install pyOCD + +## Bluetooth LE REPL + +The port also implements a BLE REPL driver. This feature is disabled by default, as it will deactivate the UART REPL when activated. As some of the nRF devices only have one UART, using the BLE REPL free's the UART instance such that it can be used as a general UART peripheral not bound to REPL. + +The configuration can be enabled by editing the `bluetooth_conf.h` and set `MICROPY_PY_BLE_NUS` to 1. + +When enabled you have different options to test it: +* [NUS Console for Linux](https://github.com/tralamazza/nus_console) (recommended) +* [WebBluetooth REPL](https://aykevl.nl/apps/nus/) (experimental) + +Other: +* nRF UART application for IPhone/Android + +WebBluetooth mode can also be configured by editing `bluetooth_conf.h` and set `BLUETOOTH_WEBBLUETOOTH_REPL` to 1. This will alternate advertisement between Eddystone URL and regular connectable advertisement. The Eddystone URL will point the phone or PC to download [WebBluetooth REPL](https://aykevl.nl/apps/nus/) (experimental), which subsequently can be used to connect to the Bluetooth REPL from the PC or Phone browser. diff --git a/src/openmv/src/micropython/ports/nrf/bluetooth_conf.h b/src/openmv/src/micropython/ports/nrf/bluetooth_conf.h new file mode 100755 index 0000000..58d47e2 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/bluetooth_conf.h @@ -0,0 +1,46 @@ +#ifndef BLUETOOTH_CONF_H__ +#define BLUETOOTH_CONF_H__ + +// SD specific configurations. + +#if (BLUETOOTH_SD == 110) + +#define MICROPY_PY_BLE (1) +#define MICROPY_PY_BLE_NUS (0) +#define BLUETOOTH_WEBBLUETOOTH_REPL (0) +#define MICROPY_PY_UBLUEPY (1) +#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) + +#elif (BLUETOOTH_SD == 132) + +#define MICROPY_PY_BLE (1) +#define MICROPY_PY_BLE_NUS (0) +#define BLUETOOTH_WEBBLUETOOTH_REPL (0) +#define MICROPY_PY_UBLUEPY (1) +#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) +#define MICROPY_PY_UBLUEPY_CENTRAL (1) + +#elif (BLUETOOTH_SD == 140) + +#define MICROPY_PY_BLE (1) +#define MICROPY_PY_BLE_NUS (0) +#define BLUETOOTH_WEBBLUETOOTH_REPL (0) +#define MICROPY_PY_UBLUEPY (1) +#define MICROPY_PY_UBLUEPY_PERIPHERAL (1) +#define MICROPY_PY_UBLUEPY_CENTRAL (1) + +#else +#error "SD not supported" +#endif + +// Default defines. + +#ifndef MICROPY_PY_BLE +#define MICROPY_PY_BLE (0) +#endif + +#ifndef MICROPY_PY_BLE_NUS +#define MICROPY_PY_BLE_NUS (0) +#endif + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.h new file mode 100755 index 0000000..c34a747 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.h @@ -0,0 +1,68 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "Arduino Primo" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "nrf52" + +#define MICROPY_PY_MACHINE_SOFT_PWM (1) +#define MICROPY_PY_MUSIC (1) + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (1) +#define MICROPY_HW_LED_PULLUP (0) + +#define MICROPY_HW_LED1 (20) // LED1 + +// UART config +#define MICROPY_HW_UART1_RX (11) +#define MICROPY_HW_UART1_TX (12) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (25) // (Arduino D13) +#define MICROPY_HW_SPI0_MOSI (23) // (Arduino D11) +#define MICROPY_HW_SPI0_MISO (24) // (Arduino D12) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +// buzzer pin +#define MICROPY_HW_MUSIC_PIN (8) + +#define HELP_TEXT_BOARD_LED "1" diff --git a/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.mk new file mode 100755 index 0000000..e0be6c6 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.0.0 +LD_FILES += boards/nrf52832_512k_64k.ld +FLASHER = pyocd + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/pins.csv new file mode 100755 index 0000000..90bf84a --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/arduino_primo/pins.csv @@ -0,0 +1,30 @@ +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/boards/common.ld b/src/openmv/src/micropython/ports/nrf/boards/common.ld new file mode 100755 index 0000000..2e1e6f7 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/common.ld @@ -0,0 +1,81 @@ +/* define output sections */ +SECTIONS +{ + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH_TEXT + + /* + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } >FLASH + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + */ + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + _ram_start = .; /* create a global symbol at ram start for garbage collector */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT>FLASH_TEXT + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* Remove information from the standard libraries */ + /* + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + */ + + .ARM.attributes 0 : { *(.ARM.attributes) } +} + +/* Define heap and stack areas */ +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM); diff --git a/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.h new file mode 100755 index 0000000..dee7daf --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.h @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "DVK-BL652" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "bl652" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (2) +#define MICROPY_HW_LED_PULLUP (0) + +#define MICROPY_HW_LED1 (17) // LED1 +#define MICROPY_HW_LED2 (19) // LED2 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_CTS (7) +#define MICROPY_HW_UART1_RTS (5) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (25) +#define MICROPY_HW_SPI0_MOSI (23) +#define MICROPY_HW_SPI0_MISO (24) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2" diff --git a/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.mk new file mode 100755 index 0000000..e293779 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.0.0 +LD_FILES += boards/nrf52832_512k_64k.ld + +NRF_DEFINES += -DNRF52832_XXAA +CFLAGS += -DBLUETOOTH_LFCLK_RC diff --git a/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/pins.csv new file mode 100755 index 0000000..78e249f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/dvk_bl652/pins.csv @@ -0,0 +1,31 @@ +P2,P2 +P3,P3 +P4,P4 +UART_RTS,P5 +UART_TX,P6 +UART_CTS,P7 +UART_RX,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 + diff --git a/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.h new file mode 100755 index 0000000..8ec2b0c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "Bluefruit nRF52 Feather" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "nrf52" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (2) +#define MICROPY_HW_LED_PULLUP (0) + +#define MICROPY_HW_LED1 (17) // LED1 +#define MICROPY_HW_LED2 (19) // LED2 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (12) // (Arduino D13) +#define MICROPY_HW_SPI0_MOSI (13) // (Arduino D11) +#define MICROPY_HW_SPI0_MISO (14) // (Arduino D12) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2" diff --git a/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.mk new file mode 100755 index 0000000..ea4a831 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/feather52/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.0.0 +LD_FILES += boards/nrf52832_512k_64k.ld + +NRF_DEFINES += -DNRF52832_XXAA + diff --git a/src/openmv/src/micropython/ports/nrf/boards/feather52/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/feather52/pins.csv new file mode 100755 index 0000000..be1ab7f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/feather52/pins.csv @@ -0,0 +1,25 @@ +P2,P2,ADC0_IN0 +P3,P3,ADC0_IN1 +P4,P4,ADC0_IN2 +P5,P5,ADC0_IN3 +UART_TX,P6 +P7,P7 +UART_RX,P8 +NFC1,P9 +NFC2,P10 +P11,P11 +SPI_SCK,P12 +SPI_MOSI,P13 +SPI_MISO,P14 +P15,P15 +P16,P16 +LED1,P17 +LED2,P19 +P20,P20 +I2C_SDA,P25 +I2C_SCL,P26 +P27,P27 +P28,P28,ADC0_IN4 +P29,P29,ADC0_IN5 +P30,P30,ADC0_IN6 +P31,P31,ADC0_IN7 diff --git a/src/openmv/src/micropython/ports/nrf/boards/make-pins.py b/src/openmv/src/micropython/ports/nrf/boards/make-pins.py new file mode 100755 index 0000000..023b216 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/make-pins.py @@ -0,0 +1,409 @@ +#!/usr/bin/env python +"""Creates the pin file for the nRF5.""" + +from __future__ import print_function + +import argparse +import sys +import csv + +SUPPORTED_FN = { + 'UART' : ['RX', 'TX', 'CTS', 'RTS'] +} + +def parse_pin(name_str): + """Parses a string and returns a pin-num.""" + if len(name_str) < 1: + raise ValueError("Expecting pin name to be at least 4 charcters.") + if name_str[0] != 'P': + raise ValueError("Expecting pin name to start with P") + pin_str = name_str[1:].split('/')[0] + if not pin_str.isdigit(): + raise ValueError("Expecting numeric pin number.") + return int(pin_str) + +def split_name_num(name_num): + num = None + for num_idx in range(len(name_num) - 1, -1, -1): + if not name_num[num_idx].isdigit(): + name = name_num[0:num_idx + 1] + num_str = name_num[num_idx + 1:] + if len(num_str) > 0: + num = int(num_str) + break + return name, num + + +class AlternateFunction(object): + """Holds the information associated with a pins alternate function.""" + + def __init__(self, idx, af_str): + self.idx = idx + self.af_str = af_str + + self.func = '' + self.fn_num = None + self.pin_type = '' + self.supported = False + + af_words = af_str.split('_', 1) + self.func, self.fn_num = split_name_num(af_words[0]) + if len(af_words) > 1: + self.pin_type = af_words[1] + if self.func in SUPPORTED_FN: + pin_types = SUPPORTED_FN[self.func] + if self.pin_type in pin_types: + self.supported = True + + def is_supported(self): + return self.supported + + def ptr(self): + """Returns the numbered function (i.e. USART6) for this AF.""" + if self.fn_num is None: + return self.func + return '{:s}{:d}'.format(self.func, self.fn_num) + + def mux_name(self): + return 'AF{:d}_{:s}'.format(self.idx, self.ptr()) + + def print(self): + """Prints the C representation of this AF.""" + if self.supported: + print(' AF', end='') + else: + print(' //', end='') + fn_num = self.fn_num + if fn_num is None: + fn_num = 0 + print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, + self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + + def qstr_list(self): + return [self.mux_name()] + + +class Pin(object): + """Holds the information associated with a pin.""" + + def __init__(self, pin): + self.pin = pin + self.alt_fn = [] + self.alt_fn_count = 0 + self.adc_num = 0 + self.adc_channel = 0 + self.board_pin = False + + def cpu_pin_name(self): + return '{:s}{:d}'.format("P", self.pin) + + def is_board_pin(self): + return self.board_pin + + def set_is_board_pin(self): + self.board_pin = True + + def parse_adc(self, adc_str): + if (adc_str[:3] != 'ADC'): + return + (adc,channel) = adc_str.split('_') + for idx in range(3, len(adc)): + self.adc_num = int(adc[idx]) + self.adc_channel = int(channel[2:]) + + def parse_af(self, af_idx, af_strs_in): + if len(af_strs_in) == 0: + return + # If there is a slash, then the slash separates 2 aliases for the + # same alternate function. + af_strs = af_strs_in.split('/') + for af_str in af_strs: + alt_fn = AlternateFunction(af_idx, af_str) + self.alt_fn.append(alt_fn) + if alt_fn.is_supported(): + self.alt_fn_count += 1 + + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return 'NULL' + return 'pin_{:s}_af'.format(self.cpu_pin_name()) + + def adc_num_str(self): + str = '' + for adc_num in range(1,4): + if self.adc_num & (1 << (adc_num - 1)): + if len(str) > 0: + str += ' | ' + str += 'PIN_ADC' + str += chr(ord('0') + adc_num) + if len(str) == 0: + str = '0' + return str + + def print_const_table_entry(self): + print(' PIN({:d}, {:s}, {:s}, {:d}),'.format( + self.pin, + self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) + + def print(self): + if self.alt_fn_count == 0: + print("// ", end='') + print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name())) + for alt_fn in self.alt_fn: + alt_fn.print() + if self.alt_fn_count == 0: + print("// ", end='') + print('};') + print('') + print('const pin_obj_t pin_{:s} = PIN({:d}, {:s}, {:s}, {:d});'.format( + self.cpu_pin_name(), self.pin, + self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) + print('') + + def print_header(self, hdr_file): + hdr_file.write('extern const pin_obj_t pin_{:s};\n'. + format(self.cpu_pin_name())) + if self.alt_fn_count > 0: + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. + format(self.cpu_pin_name())) + + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + +class NamedPin(object): + + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name + + +class Pins(object): + + def __init__(self): + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects + + def find_pin(self, pin_num): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.pin == pin_num: + return pin + + def parse_af_file(self, filename, pinname_col, af_col, af_col_end): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + pin_num = parse_pin(row[pinname_col]) + except: + continue + pin = Pin(pin_num) + for af_idx in range(af_col, len(row)): + if af_idx < af_col_end: + pin.parse_af(af_idx - af_col, row[af_idx]) + elif af_idx == af_col_end: + pin.parse_adc(row[af_idx]) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) + + def parse_board_file(self, filename): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + pin_num = parse_pin(row[1]) + except: + continue + pin = self.find_pin(pin_num) + if pin: + pin.set_is_board_pin() + self.board_pins.append(NamedPin(row[0], pin)) + + def print_named(self, label, named_pins): + print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) + index = 0 + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&machine_pin_obj[{:d}]) }},'.format(named_pin.name(), index)) + index += 1 + print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); + + def print_const_table(self): + print('') + print('const uint8_t machine_pin_num_of_pins = {:d};'.format(len(self.board_pins))) + print('') + print('const pin_obj_t machine_pin_obj[{:d}] = {{'.format(len(self.board_pins))) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_const_table_entry() + print('};'); + + def print(self): + self.print_named('cpu', self.cpu_pins) + print('') + self.print_named('board', self.board_pins) + + def print_adc(self, adc_num): + print(''); + print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) + for channel in range(16): + adc_found = False + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if (pin.is_board_pin() and + (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): + print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) + adc_found = True + break + if not adc_found: + print(' NULL, // {:d}'.format(channel)) + print('};') + + + def print_header(self, hdr_filename): + with open(hdr_filename, 'wt') as hdr_file: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, 'wt') as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + key = 'MP_ROM_QSTR(MP_QSTR_{}),'.format(mux_name) + val = 'MP_ROM_INT(GPIO_{})'.format(mux_name) + print(' { %-*s %s },' % (mux_name_width + 26, key, val), + file=af_const_file) + + def print_af_py(self, af_py_filename): + with open(af_py_filename, 'wt') as af_py_file: + print('PINS_AF = (', file=af_py_file); + for named_pin in self.board_pins: + print(" ('%s', " % named_pin.name(), end='', file=af_py_file) + for af in named_pin.pin().alt_fn: + if af.is_supported(): + print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file) + print('),', file=af_py_file) + print(')', file=af_py_file) + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file" + ) + parser.add_argument( + "-a", "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="nrf.csv" + ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins_af_const.h" + ) + parser.add_argument( + "--af-py", + dest="af_py_filename", + help="Specifies the filename for the python alternate function mappings.", + default="build/pins_af.py" + ) + parser.add_argument( + "-b", "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="nrf52_prefix.c" + ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins_qstr.h" + ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print('// This file was automatically generated by make-pins.py') + print('//') + if args.af_filename: + print('// --af {:s}'.format(args.af_filename)) + pins.parse_af_file(args.af_filename, 1, 2, 2) + + if args.board_filename: + print('// --board {:s}'.format(args.board_filename)) + pins.parse_board_file(args.board_filename) + + if args.prefix_filename: + print('// --prefix {:s}'.format(args.prefix_filename)) + print('') + with open(args.prefix_filename, 'r') as prefix_file: + print(prefix_file.read()) + + pins.print_const_table() + pins.print() + pins.print_header(args.hdr_filename) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) + pins.print_af_py(args.af_py_filename) + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/nrf/boards/memory.ld b/src/openmv/src/micropython/ports/nrf/boards/memory.ld new file mode 100755 index 0000000..c95daf3 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/memory.ld @@ -0,0 +1,24 @@ + +/* Flash layout: softdevice | application | filesystem */ +/* RAM layout: softdevice RAM | application RAM */ +_sd_size = DEFINED(_sd_size) ? _sd_size : 0; +_sd_ram = DEFINED(_sd_ram) ? _sd_ram : 0; +_fs_size = DEFINED(_fs_size) ? _fs_size : 64K; /* TODO: set to 0 if not using the filesystem */ +_app_size = _flash_size - _sd_size - _fs_size; +_app_start = _sd_size; +_fs_start = _sd_size + _app_size; +_fs_end = _fs_start + _fs_size; +_app_ram_start = 0x20000000 + _sd_ram; +_app_ram_size = _ram_size - _sd_ram; +_heap_start = _ebss; +_heap_end = _ram_end - _stack_size; +_heap_size = _heap_end - _heap_start; + +ASSERT(_heap_size >= _minimum_heap_size, "not enough RAM left for heap") + +/* Specify the memory areas */ +MEMORY +{ + FLASH_TEXT (rx) : ORIGIN = _app_start, LENGTH = _app_size /* app */ + RAM (xrw) : ORIGIN = _app_ram_start, LENGTH = _app_ram_size +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/custom_nrf51822_s110_microbit.ld b/src/openmv/src/micropython/ports/nrf/boards/microbit/custom_nrf51822_s110_microbit.ld new file mode 100755 index 0000000..fc286ec --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/custom_nrf51822_s110_microbit.ld @@ -0,0 +1 @@ +_fs_size = 12K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/AUTHORS b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/AUTHORS new file mode 100755 index 0000000..60ed2e5 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/AUTHORS @@ -0,0 +1,9 @@ +Damien P. George (@dpgeorge) +Nicholas H. Tollervey (@ntoll) +Matthew Else (@matthewelse) +Alan M. Jackson (@alanmjackson) +Mark Shannon (@markshannon) +Larry Hastings (@larryhastings) +Mariia Koroliuk (@marichkakorolyuk) +Andrew Mulholland (@gbaman) +Joe Glancy (@JoeGlancy) diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/LICENSE b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/LICENSE new file mode 100755 index 0000000..6212290 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers, as listed +in the accompanying AUTHORS file + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.h new file mode 100755 index 0000000..58df653 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_NRF_BOARD_MICROBIT_BOARD_MODULES_H +#define MICROPY_INCLUDED_NRF_BOARD_MICROBIT_BOARD_MODULES_H + +#include "modmicrobit.h" + +extern const struct _mp_obj_module_t microbit_module; + +#define BOARD_MODULES \ + { MP_ROM_QSTR(MP_QSTR_microbit), MP_ROM_PTR(µbit_module) }, \ + +#endif // MICROPY_INCLUDED_NRF_BOARD_MICROBIT_BOARD_MODULES_H diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.mk b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.mk new file mode 100755 index 0000000..eb8f108 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/boardmodules.mk @@ -0,0 +1,16 @@ +BOARD_MICROBIT_DIR = boards/microbit/modules + +INC += -I./$(BOARD_MICROBIT_DIR) +CFLAGS += -DBOARD_SPECIFIC_MODULES + +SRC_BOARD_MODULES = $(addprefix $(BOARD_MICROBIT_DIR)/,\ + microbitdisplay.c \ + microbitimage.c \ + iters.c \ + microbitconstimage.c \ + microbitconstimagetuples.c \ + modmicrobit.c \ + ) + +OBJ += $(addprefix $(BUILD)/, $(SRC_BOARD_MODULES:.c=.o)) + diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.c new file mode 100755 index 0000000..2c675ff --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.c @@ -0,0 +1,68 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015/6 Mark Shannon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "iters.h" + + +typedef struct _repeat_iterator_t { + mp_obj_base_t base; + mp_obj_t iterable; + mp_int_t index; +} repeat_iterator_t; + +static mp_obj_t microbit_repeat_iter_next(mp_obj_t iter_in) { + repeat_iterator_t *iter = (repeat_iterator_t *)iter_in; + iter->index++; + if (iter->index >= mp_obj_get_int(mp_obj_len(iter->iterable))) { + iter->index = 0; + } + return mp_obj_subscr(iter->iterable, MP_OBJ_NEW_SMALL_INT(iter->index), MP_OBJ_SENTINEL); +} + +const mp_obj_type_t microbit_repeat_iterator_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = NULL, + .binary_op = NULL, + .attr = NULL, + .subscr = NULL, + .getiter = mp_identity_getiter, + .iternext = microbit_repeat_iter_next, + .buffer_p = {NULL}, + MP_OBJ_NULL +}; + +mp_obj_t microbit_repeat_iterator(mp_obj_t iterable) { + repeat_iterator_t *result = m_new_obj(repeat_iterator_t); + result->base.type = µbit_repeat_iterator_type; + result->iterable = iterable; + result->index = -1; + return result; +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.h new file mode 100755 index 0000000..f7f716c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/iters.h @@ -0,0 +1,4 @@ + +#include "py/runtime.h" + +mp_obj_t microbit_repeat_iterator(mp_obj_t iterable); diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.c new file mode 100755 index 0000000..fa07984 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.c @@ -0,0 +1,555 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "microbitimage.h" + + +#define IMAGE_T const monochrome_5by5_t + +IMAGE_T microbit_const_image_heart_obj = SMALL_IMAGE( + 0,1,0,1,0, + 1,1,1,1,1, + 1,1,1,1,1, + 0,1,1,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_heart_small_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,0,1,0, + 0,1,1,1,0, + 0,0,1,0,0, + 0,0,0,0,0 +); + +// smilies + +IMAGE_T microbit_const_image_happy_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,0,1,0, + 0,0,0,0,0, + 1,0,0,0,1, + 0,1,1,1,0 +); + +IMAGE_T microbit_const_image_smile_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,0,0,1, + 0,1,1,1,0 +); + +IMAGE_T microbit_const_image_sad_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,0,1,0, + 0,0,0,0,0, + 0,1,1,1,0, + 1,0,0,0,1 +); + +IMAGE_T microbit_const_image_confused_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,0,1,0, + 0,0,0,0,0, + 0,1,0,1,0, + 1,0,1,0,1 +); + +IMAGE_T microbit_const_image_angry_obj = SMALL_IMAGE( + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,0,1,0,1 +); + +IMAGE_T microbit_const_image_asleep_obj = SMALL_IMAGE( + 0,0,0,0,0, + 1,1,0,1,1, + 0,0,0,0,0, + 0,1,1,1,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_surprised_obj = SMALL_IMAGE( + 0,1,0,1,0, + 0,0,0,0,0, + 0,0,1,0,0, + 0,1,0,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_silly_obj = SMALL_IMAGE( + 1,0,0,0,1, + 0,0,0,0,0, + 1,1,1,1,1, + 0,0,1,0,1, + 0,0,1,1,1 +); + +IMAGE_T microbit_const_image_fabulous_obj = SMALL_IMAGE( + 1,1,1,1,1, + 1,1,0,1,1, + 0,0,0,0,0, + 0,1,0,1,0, + 0,1,1,1,0 +); + +IMAGE_T microbit_const_image_meh_obj = SMALL_IMAGE( + 0,1,0,1,0, + 0,0,0,0,0, + 0,0,0,1,0, + 0,0,1,0,0, + 0,1,0,0,0 +); + +// yes/no + +IMAGE_T microbit_const_image_yes_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,1, + 0,0,0,1,0, + 1,0,1,0,0, + 0,1,0,0,0 +); + +IMAGE_T microbit_const_image_no_obj = SMALL_IMAGE( + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1 +); + +// clock hands + +IMAGE_T microbit_const_image_clock12_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock1_obj = SMALL_IMAGE( + 0,0,0,1,0, + 0,0,0,1,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock2_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,1,1, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock3_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock4_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,0,0, + 0,0,0,1,1, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock5_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,0,0, + 0,0,0,1,0, + 0,0,0,1,0 +); + +IMAGE_T microbit_const_image_clock6_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_clock7_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,0,0, + 0,1,0,0,0, + 0,1,0,0,0 +); + +IMAGE_T microbit_const_image_clock8_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,1,0,0, + 1,1,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock9_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock10_obj = SMALL_IMAGE( + 0,0,0,0,0, + 1,1,0,0,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_clock11_obj = SMALL_IMAGE( + 0,1,0,0,0, + 0,1,0,0,0, + 0,0,1,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +); + +// arrows + +IMAGE_T microbit_const_image_arrow_n_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,1,1,0, + 1,0,1,0,1, + 0,0,1,0,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_arrow_ne_obj = SMALL_IMAGE( + 0,0,1,1,1, + 0,0,0,1,1, + 0,0,1,0,1, + 0,1,0,0,0, + 1,0,0,0,0 +); + +IMAGE_T microbit_const_image_arrow_e_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,0,1,0, + 1,1,1,1,1, + 0,0,0,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_arrow_se_obj = SMALL_IMAGE( + 1,0,0,0,0, + 0,1,0,0,0, + 0,0,1,0,1, + 0,0,0,1,1, + 0,0,1,1,1 +); + +IMAGE_T microbit_const_image_arrow_s_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,1,0,0, + 1,0,1,0,1, + 0,1,1,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_arrow_sw_obj = SMALL_IMAGE( + 0,0,0,0,1, + 0,0,0,1,0, + 1,0,1,0,0, + 1,1,0,0,0, + 1,1,1,0,0 +); + +IMAGE_T microbit_const_image_arrow_w_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,0,0,0, + 1,1,1,1,1, + 0,1,0,0,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_arrow_nw_obj = SMALL_IMAGE( + 1,1,1,0,0, + 1,1,0,0,0, + 1,0,1,0,0, + 0,0,0,1,0, + 0,0,0,0,1 +); + +// geometry + +IMAGE_T microbit_const_image_triangle_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,1,0,0, + 0,1,0,1,0, + 1,1,1,1,1, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_triangle_left_obj = SMALL_IMAGE( + 1,0,0,0,0, + 1,1,0,0,0, + 1,0,1,0,0, + 1,0,0,1,0, + 1,1,1,1,1 +); + +IMAGE_T microbit_const_image_chessboard_obj = SMALL_IMAGE( + 0,1,0,1,0, + 1,0,1,0,1, + 0,1,0,1,0, + 1,0,1,0,1, + 0,1,0,1,0 +); + +IMAGE_T microbit_const_image_diamond_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1, + 0,1,0,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_diamond_small_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,0,1,0,0, + 0,1,0,1,0, + 0,0,1,0,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_square_obj = SMALL_IMAGE( + 1,1,1,1,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,1 +); + +IMAGE_T microbit_const_image_square_small_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,1,1,0, + 0,1,0,1,0, + 0,1,1,1,0, + 0,0,0,0,0 +); + +// animals + +IMAGE_T microbit_const_image_rabbit = SMALL_IMAGE( + 1,0,1,0,0, + 1,0,1,0,0, + 1,1,1,1,0, + 1,1,0,1,0, + 1,1,1,1,0 +); + +IMAGE_T microbit_const_image_cow = SMALL_IMAGE( + 1,0,0,0,1, + 1,0,0,0,1, + 1,1,1,1,1, + 0,1,1,1,0, + 0,0,1,0,0 +); + +// musical notes + +IMAGE_T microbit_const_image_music_crotchet_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0 +); + +IMAGE_T microbit_const_image_music_quaver_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,1,1,0, + 0,0,1,0,1, + 1,1,1,0,0, + 1,1,1,0,0 +); + +IMAGE_T microbit_const_image_music_quavers_obj = SMALL_IMAGE( + 0,1,1,1,1, + 0,1,0,0,1, + 0,1,0,0,1, + 1,1,0,1,1, + 1,1,0,1,1 +); + +// other icons + +IMAGE_T microbit_const_image_pitchfork_obj = SMALL_IMAGE( + 1,0,1,0,1, + 1,0,1,0,1, + 1,1,1,1,1, + 0,0,1,0,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_xmas_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,1,1,0, + 0,0,1,0,0, + 0,1,1,1,0, + 1,1,1,1,1 +); + +IMAGE_T microbit_const_image_pacman_obj = SMALL_IMAGE( + 0,1,1,1,1, + 1,1,0,1,0, + 1,1,1,0,0, + 1,1,1,1,0, + 0,1,1,1,1 +); + +IMAGE_T microbit_const_image_target_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,1,1,0, + 1,1,0,1,1, + 0,1,1,1,0, + 0,0,1,0,0 +); + +/* +The following images were designed by Abbie Brooks. +*/ + +IMAGE_T microbit_const_image_tshirt_obj = SMALL_IMAGE( + 1,1,0,1,1, + 1,1,1,1,1, + 0,1,1,1,0, + 0,1,1,1,0, + 0,1,1,1,0 +); + +IMAGE_T microbit_const_image_rollerskate_obj = SMALL_IMAGE( + 0,0,0,1,1, + 0,0,0,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 0,1,0,1,0 +); + +IMAGE_T microbit_const_image_duck_obj = SMALL_IMAGE( + 0,1,1,0,0, + 1,1,1,0,0, + 0,1,1,1,1, + 0,1,1,1,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_house_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,1,1,1,0, + 1,1,1,1,1, + 0,1,1,1,0, + 0,1,0,1,0 +); + +IMAGE_T microbit_const_image_tortoise_obj = SMALL_IMAGE( + 0,0,0,0,0, + 0,1,1,1,0, + 1,1,1,1,1, + 0,1,0,1,0, + 0,0,0,0,0 +); + +IMAGE_T microbit_const_image_butterfly_obj = SMALL_IMAGE( + 1,1,0,1,1, + 1,1,1,1,1, + 0,0,1,0,0, + 1,1,1,1,1, + 1,1,0,1,1 +); + +IMAGE_T microbit_const_image_stickfigure_obj = SMALL_IMAGE( + 0,0,1,0,0, + 1,1,1,1,1, + 0,0,1,0,0, + 0,1,0,1,0, + 1,0,0,0,1 +); + +IMAGE_T microbit_const_image_ghost_obj = SMALL_IMAGE( + 1,1,1,1,1, + 1,0,1,0,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,0,1,0,1 +); + +IMAGE_T microbit_const_image_sword_obj = SMALL_IMAGE( + 0,0,1,0,0, + 0,0,1,0,0, + 0,0,1,0,0, + 0,1,1,1,0, + 0,0,1,0,0 +); + +IMAGE_T microbit_const_image_giraffe_obj = SMALL_IMAGE( + 1,1,0,0,0, + 0,1,0,0,0, + 0,1,0,0,0, + 0,1,1,1,0, + 0,1,0,1,0 +); + +IMAGE_T microbit_const_image_skull_obj = SMALL_IMAGE( + 0,1,1,1,0, + 1,0,1,0,1, + 1,1,1,1,1, + 0,1,1,1,0, + 0,1,1,1,0 +); + +IMAGE_T microbit_const_image_umbrella_obj = SMALL_IMAGE( + 0,1,1,1,0, + 1,1,1,1,1, + 0,0,1,0,0, + 1,0,1,0,0, + 0,1,1,0,0 +); + +IMAGE_T microbit_const_image_snake_obj = SMALL_IMAGE( + 1,1,0,0,0, + 1,1,0,1,1, + 0,1,0,1,0, + 0,1,1,1,0, + 0,0,0,0,0 +); diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.h new file mode 100755 index 0000000..ca67b5c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimage.h @@ -0,0 +1,109 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_MICROBIT_CONSTIMAGE_H__ +#define __MICROPY_INCLUDED_MICROBIT_CONSTIMAGE_H__ + +typedef struct _image_tuple_12 { + mp_obj_base_t base; + size_t len; + mp_rom_obj_t items[12]; +} image_tuple_12_t; + +typedef struct _image_tuple_8 { + mp_obj_base_t base; + size_t len; + mp_rom_obj_t items[8]; +} image_tuple_8_t; + +extern const image_tuple_12_t microbit_const_image_all_clocks_tuple_obj; +extern const image_tuple_8_t microbit_const_image_all_arrows_tuple_obj; +extern const mp_obj_type_t microbit_const_image_type; +extern const struct _monochrome_5by5_t microbit_const_image_heart_obj; +extern const struct _monochrome_5by5_t microbit_const_image_heart_small_obj; +extern const struct _monochrome_5by5_t microbit_const_image_happy_obj; +extern const struct _monochrome_5by5_t microbit_const_image_smile_obj; +extern const struct _monochrome_5by5_t microbit_const_image_sad_obj; +extern const struct _monochrome_5by5_t microbit_const_image_confused_obj; +extern const struct _monochrome_5by5_t microbit_const_image_angry_obj; +extern const struct _monochrome_5by5_t microbit_const_image_asleep_obj; +extern const struct _monochrome_5by5_t microbit_const_image_surprised_obj; +extern const struct _monochrome_5by5_t microbit_const_image_silly_obj; +extern const struct _monochrome_5by5_t microbit_const_image_fabulous_obj; +extern const struct _monochrome_5by5_t microbit_const_image_meh_obj; +extern const struct _monochrome_5by5_t microbit_const_image_yes_obj; +extern const struct _monochrome_5by5_t microbit_const_image_no_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock12_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock1_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock2_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock3_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock4_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock5_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock6_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock7_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock8_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock9_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock10_obj; +extern const struct _monochrome_5by5_t microbit_const_image_clock11_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_n_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_ne_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_e_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_se_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_s_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_sw_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_w_obj; +extern const struct _monochrome_5by5_t microbit_const_image_arrow_nw_obj; +extern const struct _monochrome_5by5_t microbit_const_image_triangle_obj; +extern const struct _monochrome_5by5_t microbit_const_image_triangle_left_obj; +extern const struct _monochrome_5by5_t microbit_const_image_chessboard_obj; +extern const struct _monochrome_5by5_t microbit_const_image_diamond_obj; +extern const struct _monochrome_5by5_t microbit_const_image_diamond_small_obj; +extern const struct _monochrome_5by5_t microbit_const_image_square_obj; +extern const struct _monochrome_5by5_t microbit_const_image_square_small_obj; +extern const struct _monochrome_5by5_t microbit_const_image_rabbit; +extern const struct _monochrome_5by5_t microbit_const_image_cow; +extern const struct _monochrome_5by5_t microbit_const_image_music_crotchet_obj; +extern const struct _monochrome_5by5_t microbit_const_image_music_quaver_obj; +extern const struct _monochrome_5by5_t microbit_const_image_music_quavers_obj; +extern const struct _monochrome_5by5_t microbit_const_image_pitchfork_obj; +extern const struct _monochrome_5by5_t microbit_const_image_xmas_obj; +extern const struct _monochrome_5by5_t microbit_const_image_pacman_obj; +extern const struct _monochrome_5by5_t microbit_const_image_target_obj; +extern const struct _monochrome_5by5_t microbit_const_image_tshirt_obj; +extern const struct _monochrome_5by5_t microbit_const_image_rollerskate_obj; +extern const struct _monochrome_5by5_t microbit_const_image_duck_obj; +extern const struct _monochrome_5by5_t microbit_const_image_house_obj; +extern const struct _monochrome_5by5_t microbit_const_image_tortoise_obj; +extern const struct _monochrome_5by5_t microbit_const_image_butterfly_obj; +extern const struct _monochrome_5by5_t microbit_const_image_stickfigure_obj; +extern const struct _monochrome_5by5_t microbit_const_image_ghost_obj; +extern const struct _monochrome_5by5_t microbit_const_image_sword_obj; +extern const struct _monochrome_5by5_t microbit_const_image_giraffe_obj; +extern const struct _monochrome_5by5_t microbit_const_image_skull_obj; +extern const struct _monochrome_5by5_t microbit_const_image_umbrella_obj; +extern const struct _monochrome_5by5_t microbit_const_image_snake_obj; + +#endif // __MICROPY_INCLUDED_MICROBIT_CONSTIMAGE_H__ diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c new file mode 100755 index 0000000..3773b1e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitconstimagetuples.c @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Mark Shannon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "microbitconstimage.h" + +const image_tuple_12_t microbit_const_image_all_clocks_tuple_obj = { + {&mp_type_tuple}, + .len = 12, + .items = { + (mp_obj_t)µbit_const_image_clock12_obj, + (mp_obj_t)µbit_const_image_clock1_obj, + (mp_obj_t)µbit_const_image_clock2_obj, + (mp_obj_t)µbit_const_image_clock3_obj, + (mp_obj_t)µbit_const_image_clock4_obj, + (mp_obj_t)µbit_const_image_clock5_obj, + (mp_obj_t)µbit_const_image_clock6_obj, + (mp_obj_t)µbit_const_image_clock7_obj, + (mp_obj_t)µbit_const_image_clock8_obj, + (mp_obj_t)µbit_const_image_clock9_obj, + (mp_obj_t)µbit_const_image_clock10_obj, + (mp_obj_t)µbit_const_image_clock11_obj + } +}; + +const image_tuple_8_t microbit_const_image_all_arrows_tuple_obj = { + {&mp_type_tuple}, + .len = 8, + .items = { + (mp_obj_t)µbit_const_image_arrow_n_obj, + (mp_obj_t)µbit_const_image_arrow_ne_obj, + (mp_obj_t)µbit_const_image_arrow_e_obj, + (mp_obj_t)µbit_const_image_arrow_se_obj, + (mp_obj_t)µbit_const_image_arrow_s_obj, + (mp_obj_t)µbit_const_image_arrow_sw_obj, + (mp_obj_t)µbit_const_image_arrow_w_obj, + (mp_obj_t)µbit_const_image_arrow_nw_obj + } +}; diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.c new file mode 100755 index 0000000..e8e7b2b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.c @@ -0,0 +1,576 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "nrf_gpio.h" +#include "microbitimage.h" +#include "microbitdisplay.h" +#include "iters.h" +#include "ticker.h" + +#define min(a,b) (((a)<(b))?(a):(b)) + +void microbit_display_show(microbit_display_obj_t *display, microbit_image_obj_t *image) { + mp_int_t w = min(imageWidth(image), 5); + mp_int_t h = min(imageHeight(image), 5); + mp_int_t x = 0; + mp_int_t brightnesses = 0; + for (; x < w; ++x) { + mp_int_t y = 0; + for (; y < h; ++y) { + uint8_t pix = imageGetPixelValue(image, x, y); + display->image_buffer[x][y] = pix; + brightnesses |= (1 << pix); + } + for (; y < 5; ++y) { + display->image_buffer[x][y] = 0; + } + } + for (; x < 5; ++x) { + for (mp_int_t y = 0; y < 5; ++y) { + display->image_buffer[x][y] = 0; + } + } + display->brightnesses = brightnesses; +} + +#define DEFAULT_PRINT_SPEED 400 + + +mp_obj_t microbit_display_show_func(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + // Cancel any animations. + MP_STATE_PORT(async_data)[0] = NULL; + MP_STATE_PORT(async_data)[1] = NULL; + + static const mp_arg_t show_allowed_args[] = { + { MP_QSTR_image, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_delay, MP_ARG_INT, {.u_int = DEFAULT_PRINT_SPEED} }, + { MP_QSTR_clear, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_wait, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_loop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // Parse the args. + microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(show_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(show_allowed_args), show_allowed_args, args); + + mp_obj_t image = args[0].u_obj; + mp_int_t delay = args[1].u_int; + bool clear = args[2].u_bool; + bool wait = args[3].u_bool; + bool loop = args[4].u_bool; + + if (MP_OBJ_IS_STR(image)) { + // arg is a string object + mp_uint_t len; + const char *str = mp_obj_str_get_data(image, &len); + if (len == 0) { + // There are no chars; do nothing. + return mp_const_none; + } else if (len == 1) { + if (!clear && !loop) { + // A single char; convert to an image and print that. + image = microbit_image_for_char(str[0]); + goto single_image_immediate; + } + } + image = microbit_string_facade(image); + } else if (mp_obj_get_type(image) == µbit_image_type) { + if (!clear && !loop) { + goto single_image_immediate; + } + image = mp_obj_new_tuple(1, &image); + } + // iterable: + if (args[4].u_bool) { /*loop*/ + image = microbit_repeat_iterator(image); + } + microbit_display_animate(self, image, delay, clear, wait); + return mp_const_none; + +single_image_immediate: + microbit_display_show(self, (microbit_image_obj_t *)image); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_show_obj, 1, microbit_display_show_func); + +static uint8_t async_mode; +static mp_obj_t async_iterator = NULL; +// Record if an error occurs in async animation. Unfortunately there is no way to report this. +static volatile bool wakeup_event = false; +static mp_uint_t async_delay = 1000; +static mp_uint_t async_tick = 0; +static bool async_clear = false; + + +bool microbit_display_active_animation(void) { + return async_mode == ASYNC_MODE_ANIMATION; +} + +STATIC void async_stop(void) { + async_iterator = NULL; + async_mode = ASYNC_MODE_STOPPED; + async_tick = 0; + async_delay = 1000; + async_clear = false; + MP_STATE_PORT(async_data)[0] = NULL; + MP_STATE_PORT(async_data)[1] = NULL; + wakeup_event = true; +} + +STATIC void wait_for_event(void) { + while (!wakeup_event) { + // allow CTRL-C to stop the animation + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + async_stop(); + return; + } + __WFI(); + } + wakeup_event = false; +} + +typedef struct { + uint8_t x; + uint8_t y; +} DisplayPoint; + +#define NO_CONN 0 + +#define ROW_COUNT 3 +#define COLUMN_COUNT 9 + +static const DisplayPoint display_map[COLUMN_COUNT][ROW_COUNT] = { + {{0,0}, {4,2}, {2,4}}, + {{2,0}, {0,2}, {4,4}}, + {{4,0}, {2,2}, {0,4}}, + {{4,3}, {1,0}, {0,1}}, + {{3,3}, {3,0}, {1,1}}, + {{2,3}, {3,4}, {2,1}}, + {{1,3}, {1,4}, {3,1}}, + {{0,3}, {NO_CONN,NO_CONN}, {4,1}}, + {{1,2}, {NO_CONN,NO_CONN}, {3,2}} +}; + +#define MIN_COLUMN_PIN 4 +#define COLUMN_PINS_MASK 0x1ff0 +#define MIN_ROW_PIN 13 +#define MAX_ROW_PIN 15 +#define ROW_PINS_MASK 0xe000 + +static inline void displaySetPinsForRow(microbit_display_obj_t * p_display, uint8_t brightness) { + if (brightness == 0) { + nrf_gpio_port_out_clear(NRF_GPIO, COLUMN_PINS_MASK & ~p_display->pins_for_brightness[brightness]); + } else { + nrf_gpio_pin_set(p_display->pins_for_brightness[brightness]); + } +} + +/* This is the primary PWM driver/display driver. It will operate on one row + * (9 pins) per invocation. It will turn on LEDs with maximum brightness, + * then let the "callback" callback turn off the LEDs as appropriate for the + * required brightness level. + * + * For each row + * Turn off all the LEDs in the previous row + * Set the column bits high (off) + * Set the row strobe low (off) + * Turn on all the LEDs in the current row that have maximum brightness + * Set the row strobe high (on) + * Set some/all column bits low (on) + * Register the PWM callback + * For each callback start with brightness 0 + * If brightness 0 + * Turn off the LEDs specified at this level + * Else + * Turn on the LEDs specified at this level + * If brightness max + * Disable the PWM callback + * Else + * Re-queue the PWM callback after the appropriate delay + */ +static void displayAdvanceRow(microbit_display_obj_t * p_display) { + /* Clear all of the column bits */ + nrf_gpio_port_out_set(NRF_GPIO, COLUMN_PINS_MASK); + /* Clear the strobe bit for this row */ + nrf_gpio_pin_clear(p_display->strobe_row + MIN_ROW_PIN); + + /* Move to the next row. Before this, "this row" refers to the row + * manipulated by the previous invocation of this function. After this, + * "this row" refers to the row manipulated by the current invocation of + * this function. */ + p_display->strobe_row++; + + // Reset the row counts and bit mask when we have hit the max. + if (p_display->strobe_row == ROW_COUNT) { + p_display->strobe_row = 0; + } + + // Set pin for this row. + // Prepare row for rendering. + for (int i = 0; i <= MAX_BRIGHTNESS; i++) { + p_display->pins_for_brightness[i] = 0; + } + for (int i = 0; i < COLUMN_COUNT; i++) { + int x = display_map[i][p_display->strobe_row].x; + int y = display_map[i][p_display->strobe_row].y; + int brightness = microbit_display_obj.image_buffer[x][y]; + p_display->pins_for_brightness[brightness] |= (1<<(i+MIN_COLUMN_PIN)); + (void)brightness; + } + /* Enable the strobe bit for this row */ + nrf_gpio_pin_set(p_display->strobe_row + MIN_ROW_PIN); + /* Enable the column bits for all pins that need to be on. */ + nrf_gpio_port_out_clear(NRF_GPIO, p_display->pins_for_brightness[MAX_BRIGHTNESS]); +} + +static const uint16_t render_timings[] = +// The scale is (approximately) exponential, +// each step is approx x1.9 greater than the previous. +{ 0, // Bright, Ticks Duration, Relative power + 2, // 1, 2, 32µs, inf + 2, // 2, 4, 64µs, 200% + 4, // 3, 8, 128µs, 200% + 7, // 4, 15, 240µs, 187% + 13, // 5, 28, 448µs, 187% + 25, // 6, 53, 848µs, 189% + 49, // 7, 102, 1632µs, 192% + 97, // 8, 199, 3184µs, 195% +// Always on 9, 375, 6000µs, 188% +}; + +#define DISPLAY_TICKER_SLOT 1 + +/* This is the PWM callback. It is registered by the animation callback and + * will unregister itself when all of the brightness steps are complete. */ +static int32_t callback(void) { + microbit_display_obj_t *display = µbit_display_obj; + mp_uint_t brightness = display->previous_brightness; + displaySetPinsForRow(display, brightness); + brightness += 1; + if (brightness == MAX_BRIGHTNESS) { + clear_ticker_callback(DISPLAY_TICKER_SLOT); + return -1; + } + display->previous_brightness = brightness; + // Return interval (in 16µs ticks) until next callback + return render_timings[brightness]; +} + +static void draw_object(mp_obj_t obj) { + microbit_display_obj_t *display = (microbit_display_obj_t*)MP_STATE_PORT(async_data)[0]; + if (obj == MP_OBJ_STOP_ITERATION) { + if (async_clear) { + microbit_display_show(µbit_display_obj, BLANK_IMAGE); + async_clear = false; + } else { + async_stop(); + } + } else if (mp_obj_get_type(obj) == µbit_image_type) { + microbit_display_show(display, (microbit_image_obj_t *)obj); + } else if (MP_OBJ_IS_STR(obj)) { + mp_uint_t len; + const char *str = mp_obj_str_get_data(obj, &len); + if (len == 1) { + microbit_display_show(display, microbit_image_for_char(str[0])); + } else { + async_stop(); + } + } else { + MP_STATE_VM(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, "not an image."); + async_stop(); + } +} + +static void microbit_display_update(void) { + async_tick += MILLISECONDS_PER_MACRO_TICK; + if (async_tick < async_delay) { + return; + } + async_tick = 0; + switch (async_mode) { + case ASYNC_MODE_ANIMATION: + { + if (MP_STATE_PORT(async_data)[0] == NULL || MP_STATE_PORT(async_data)[1] == NULL) { + async_stop(); + break; + } + /* WARNING: We are executing in an interrupt handler. + * If an exception is raised here then we must hand it to the VM. */ + mp_obj_t obj; + nlr_buf_t nlr; + gc_lock(); + if (nlr_push(&nlr) == 0) { + obj = mp_iternext_allow_raise(async_iterator); + nlr_pop(); + gc_unlock(); + } else { + gc_unlock(); + if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + // An exception other than StopIteration, so set it for the VM to raise later + // If memory error, write an appropriate message. + if (mp_obj_get_type(nlr.ret_val) == &mp_type_MemoryError) { + mp_printf(&mp_plat_print, "Allocation in interrupt handler"); + } + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val); + } + obj = MP_OBJ_STOP_ITERATION; + } + draw_object(obj); + break; + } + case ASYNC_MODE_CLEAR: + microbit_display_show(µbit_display_obj, BLANK_IMAGE); + async_stop(); + break; + } +} + +#define GREYSCALE_MASK ((1<active = true; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_on_obj, microbit_display_on_func); + +mp_obj_t microbit_display_off_func(mp_obj_t obj) { + microbit_display_obj_t *self = (microbit_display_obj_t*)obj; + /* Disable the display loop. This will pause any animations in progress. + * It will not prevent a user from attempting to modify the state, but + * modifications will not appear to have any effect until the display loop + * is re-enabled. */ + self->active = false; + /* Disable the row strobes, allowing the columns to be used freely for + * GPIO. */ + nrf_gpio_port_out_clear(0, ROW_PINS_MASK); + /* Free pins for other uses */ +/* + microbit_obj_pin_free(µbit_p3_obj); + microbit_obj_pin_free(µbit_p4_obj); + microbit_obj_pin_free(µbit_p6_obj); + microbit_obj_pin_free(µbit_p7_obj); + microbit_obj_pin_free(µbit_p9_obj); + microbit_obj_pin_free(µbit_p10_obj); +*/ + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_off_obj, microbit_display_off_func); + +mp_obj_t microbit_display_is_on_func(mp_obj_t obj) { + microbit_display_obj_t *self = (microbit_display_obj_t*)obj; + if (self->active) { + return mp_const_true; + } + else { + return mp_const_false; + } +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_is_on_obj, microbit_display_is_on_func); + +void microbit_display_clear(void) { + // Reset repeat state, cancel animation and clear screen. + wakeup_event = false; + async_mode = ASYNC_MODE_CLEAR; + async_tick = async_delay - MILLISECONDS_PER_MACRO_TICK; + wait_for_event(); +} + +mp_obj_t microbit_display_clear_func(mp_obj_t self_in) { + microbit_display_clear(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_clear_obj, microbit_display_clear_func); + +void microbit_display_set_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y, mp_int_t bright) { + if (x < 0 || y < 0 || x > 4 || y > 4) { + mp_raise_ValueError("index out of bounds."); + } + if (bright < 0 || bright > MAX_BRIGHTNESS) { + mp_raise_ValueError("brightness out of bounds."); + } + display->image_buffer[x][y] = bright; + display->brightnesses |= (1 << bright); +} + +STATIC mp_obj_t microbit_display_set_pixel_func(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; + microbit_display_obj_t *self = (microbit_display_obj_t*)args[0]; + microbit_display_set_pixel(self, mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3])); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_set_pixel_obj, 4, 4, microbit_display_set_pixel_func); + +mp_int_t microbit_display_get_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y) { + if (x < 0 || y < 0 || x > 4 || y > 4) { + mp_raise_ValueError("index out of bounds."); + } + return display->image_buffer[x][y]; +} + +STATIC mp_obj_t microbit_display_get_pixel_func(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + microbit_display_obj_t *self = (microbit_display_obj_t*)self_in; + return MP_OBJ_NEW_SMALL_INT(microbit_display_get_pixel(self, mp_obj_get_int(x_in), mp_obj_get_int(y_in))); +} +MP_DEFINE_CONST_FUN_OBJ_3(microbit_display_get_pixel_obj, microbit_display_get_pixel_func); + +STATIC const mp_rom_map_elem_t microbit_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(µbit_display_get_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(µbit_display_set_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(µbit_display_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(µbit_display_scroll_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(µbit_display_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(µbit_display_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(µbit_display_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_on), MP_ROM_PTR(µbit_display_is_on_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(microbit_display_locals_dict, microbit_display_locals_dict_table); + +const mp_obj_type_t microbit_display_type = { + { &mp_type_type }, + .name = MP_QSTR_MicroBitDisplay, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = NULL, + .binary_op = NULL, + .attr = NULL, + .subscr = NULL, + .getiter = NULL, + .iternext = NULL, + .buffer_p = {NULL}, + .locals_dict = (mp_obj_dict_t*)µbit_display_locals_dict, +}; + +microbit_display_obj_t microbit_display_obj = { + {µbit_display_type}, + {{ 0, }}, + .previous_brightness = 0, + .active = 1, + .strobe_row = 0, + .brightnesses = 0, + .pins_for_brightness = { 0 }, +}; + +void microbit_display_init(void) { + // Set pins as output. + for (int i = MIN_COLUMN_PIN; i <= MAX_ROW_PIN; i++) { + nrf_gpio_cfg_output(i); + } +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.h new file mode 100755 index 0000000..2a916a7 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitdisplay.h @@ -0,0 +1,45 @@ + +#ifndef __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__ +#define __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__ + +#include "py/runtime.h" +#include "microbitimage.h" + +typedef struct _microbit_display_obj_t { + mp_obj_base_t base; + uint8_t image_buffer[5][5]; + uint8_t previous_brightness; + bool active; + /* Current row for strobing */ + uint8_t strobe_row; + /* boolean histogram of brightness in buffer */ + uint16_t brightnesses; + uint16_t pins_for_brightness[MAX_BRIGHTNESS+1]; +} microbit_display_obj_t; + +#define ASYNC_MODE_STOPPED 0 +#define ASYNC_MODE_ANIMATION 1 +#define ASYNC_MODE_CLEAR 2 + +extern microbit_display_obj_t microbit_display_obj; +extern const mp_obj_type_t microbit_image_type; + +void microbit_display_show(microbit_display_obj_t *display, microbit_image_obj_t *image); + +void microbit_display_animate(microbit_display_obj_t *display, mp_obj_t iterable, mp_int_t delay, bool clear, bool wait); + +void microbit_display_scroll(microbit_display_obj_t *display, const char* str, bool wait); + +mp_int_t microbit_display_get_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y); + +void microbit_display_set_pixel(microbit_display_obj_t *display, mp_int_t x, mp_int_t y, mp_int_t val); + +void microbit_display_clear(void); + +void microbit_display_init(void); + +void microbit_display_tick(void); + +bool microbit_display_active_animation(void); + +#endif // __MICROPY_INCLUDED_MICROBIT_DISPLAY_H__ diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitfont.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitfont.h new file mode 100755 index 0000000..2ae0c8f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitfont.h @@ -0,0 +1,145 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 British Broadcasting Corporation. +This software is provided by Lancaster University by arrangement with the BBC. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +/** + * A MicroBitFont is 5x5. + * Each Row is represented by a byte in the array. + * + * Row Format: + * ================================================================ + * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | + * ================================================================ + * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | + * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | + * + * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } + * + * The above will produce an exclaimation mark on the second column in form the left. + * + * We could compress further, but the complexity of decode would likely outweigh the gains. + */ + +#ifndef MICROPY_INCLUDED_NRF_BOARD_MICROBIT_MICROBITFONT_H +#define MICROPY_INCLUDED_NRF_BOARD_MICROBIT_MICROBITFONT_H + +const unsigned char font_pendolino3_5x5_pad3msb[475] = { +0x0, 0x0, 0x0, 0x0, 0x0, +0x8, 0x8, 0x8, 0x0, 0x8, +0xa, 0x4a, 0x40, 0x0, 0x0, +0xa, 0x5f, 0xea, 0x5f, 0xea, +0xe, 0xd9, 0x2e, 0xd3, 0x6e, +0x19, 0x32, 0x44, 0x89, 0x33, +0xc, 0x92, 0x4c, 0x92, 0x4d, +0x8, 0x8, 0x0, 0x0, 0x0, +0x4, 0x88, 0x8, 0x8, 0x4, +0x8, 0x4, 0x84, 0x84, 0x88, +0x0, 0xa, 0x44, 0x8a, 0x40, +0x0, 0x4, 0x8e, 0xc4, 0x80, +0x0, 0x0, 0x0, 0x4, 0x88, +0x0, 0x0, 0xe, 0xc0, 0x0, +0x0, 0x0, 0x0, 0x8, 0x0, +0x1, 0x22, 0x44, 0x88, 0x10, +0xc, 0x92, 0x52, 0x52, 0x4c, +0x4, 0x8c, 0x84, 0x84, 0x8e, +0x1c, 0x82, 0x4c, 0x90, 0x1e, +0x1e, 0xc2, 0x44, 0x92, 0x4c, +0x6, 0xca, 0x52, 0x5f, 0xe2, +0x1f, 0xf0, 0x1e, 0xc1, 0x3e, +0x2, 0x44, 0x8e, 0xd1, 0x2e, +0x1f, 0xe2, 0x44, 0x88, 0x10, +0xe, 0xd1, 0x2e, 0xd1, 0x2e, +0xe, 0xd1, 0x2e, 0xc4, 0x88, +0x0, 0x8, 0x0, 0x8, 0x0, +0x0, 0x4, 0x80, 0x4, 0x88, +0x2, 0x44, 0x88, 0x4, 0x82, +0x0, 0xe, 0xc0, 0xe, 0xc0, +0x8, 0x4, 0x82, 0x44, 0x88, +0xe, 0xd1, 0x26, 0xc0, 0x4, +0xe, 0xd1, 0x35, 0xb3, 0x6c, +0xc, 0x92, 0x5e, 0xd2, 0x52, +0x1c, 0x92, 0x5c, 0x92, 0x5c, +0xe, 0xd0, 0x10, 0x10, 0xe, +0x1c, 0x92, 0x52, 0x52, 0x5c, +0x1e, 0xd0, 0x1c, 0x90, 0x1e, +0x1e, 0xd0, 0x1c, 0x90, 0x10, +0xe, 0xd0, 0x13, 0x71, 0x2e, +0x12, 0x52, 0x5e, 0xd2, 0x52, +0x1c, 0x88, 0x8, 0x8, 0x1c, +0x1f, 0xe2, 0x42, 0x52, 0x4c, +0x12, 0x54, 0x98, 0x14, 0x92, +0x10, 0x10, 0x10, 0x10, 0x1e, +0x11, 0x3b, 0x75, 0xb1, 0x31, +0x11, 0x39, 0x35, 0xb3, 0x71, +0xc, 0x92, 0x52, 0x52, 0x4c, +0x1c, 0x92, 0x5c, 0x90, 0x10, +0xc, 0x92, 0x52, 0x4c, 0x86, +0x1c, 0x92, 0x5c, 0x92, 0x51, +0xe, 0xd0, 0xc, 0x82, 0x5c, +0x1f, 0xe4, 0x84, 0x84, 0x84, +0x12, 0x52, 0x52, 0x52, 0x4c, +0x11, 0x31, 0x31, 0x2a, 0x44, +0x11, 0x31, 0x35, 0xbb, 0x71, +0x12, 0x52, 0x4c, 0x92, 0x52, +0x11, 0x2a, 0x44, 0x84, 0x84, +0x1e, 0xc4, 0x88, 0x10, 0x1e, +0xe, 0xc8, 0x8, 0x8, 0xe, +0x10, 0x8, 0x4, 0x82, 0x41, +0xe, 0xc2, 0x42, 0x42, 0x4e, +0x4, 0x8a, 0x40, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x1f, +0x8, 0x4, 0x80, 0x0, 0x0, +0x0, 0xe, 0xd2, 0x52, 0x4f, +0x10, 0x10, 0x1c, 0x92, 0x5c, +0x0, 0xe, 0xd0, 0x10, 0xe, +0x2, 0x42, 0x4e, 0xd2, 0x4e, +0xc, 0x92, 0x5c, 0x90, 0xe, +0x6, 0xc8, 0x1c, 0x88, 0x8, +0xe, 0xd2, 0x4e, 0xc2, 0x4c, +0x10, 0x10, 0x1c, 0x92, 0x52, +0x8, 0x0, 0x8, 0x8, 0x8, +0x2, 0x40, 0x2, 0x42, 0x4c, +0x10, 0x14, 0x98, 0x14, 0x92, +0x8, 0x8, 0x8, 0x8, 0x6, +0x0, 0x1b, 0x75, 0xb1, 0x31, +0x0, 0x1c, 0x92, 0x52, 0x52, +0x0, 0xc, 0x92, 0x52, 0x4c, +0x0, 0x1c, 0x92, 0x5c, 0x90, +0x0, 0xe, 0xd2, 0x4e, 0xc2, +0x0, 0xe, 0xd0, 0x10, 0x10, +0x0, 0x6, 0xc8, 0x4, 0x98, +0x8, 0x8, 0xe, 0xc8, 0x7, +0x0, 0x12, 0x52, 0x52, 0x4f, +0x0, 0x11, 0x31, 0x2a, 0x44, +0x0, 0x11, 0x31, 0x35, 0xbb, +0x0, 0x12, 0x4c, 0x8c, 0x92, +0x0, 0x11, 0x2a, 0x44, 0x98, +0x0, 0x1e, 0xc4, 0x88, 0x1e, +0x6, 0xc4, 0x8c, 0x84, 0x86, +0x8, 0x8, 0x8, 0x8, 0x8, +0x18, 0x8, 0xc, 0x88, 0x18, +0x0, 0x0, 0xc, 0x83, 0x60 +}; + +#endif // MICROPY_INCLUDED_NRF_BOARD_MICROBIT_MICROBITFONT_H diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.c new file mode 100755 index 0000000..046b925 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.c @@ -0,0 +1,973 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien George, Mark Shannon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/runtime.h" +#include "microbitimage.h" +#include "microbitconstimage.h" +#include "py/runtime0.h" +#include "microbitfont.h" + +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +const monochrome_5by5_t microbit_blank_image = { + { µbit_image_type }, + 1, 0, 0, 0, + { 0, 0, 0 } +}; + +STATIC void microbit_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_printf(print, "Image("); + if (kind == PRINT_STR) + mp_printf(print, "\n "); + mp_printf(print, "'"); + for (int y = 0; y < imageHeight(self); ++y) { + for (int x = 0; x < imageWidth(self); ++x) { + mp_printf(print, "%c", "0123456789"[imageGetPixelValue(self, x, y)]); + } + mp_printf(print, ":"); + if (kind == PRINT_STR && y < imageHeight(self)-1) + mp_printf(print, "'\n '"); + } + mp_printf(print, "'"); + if (kind == PRINT_STR) + mp_printf(print, "\n"); + mp_printf(print, ")"); +} + +uint8_t monochromeGetPixelValue(monochrome_5by5_t * p_mono, mp_int_t x, mp_int_t y) { + unsigned int index = y*5+x; + if (index == 24) + return p_mono->pixel44; + return (p_mono->bits24[index>>3] >> (index&7))&1; +} + +uint8_t greyscaleGetPixelValue(greyscale_t * p_greyscale, mp_int_t x, mp_int_t y) { + unsigned int index = y*p_greyscale->width+x; + unsigned int shift = ((index<<2)&4); + return (p_greyscale->byte_data[index>>1] >> shift)&15; +} + +void greyscaleSetPixelValue(greyscale_t * p_greyscale, mp_int_t x, mp_int_t y, mp_int_t val) { + unsigned int index = y*p_greyscale->width+x; + unsigned int shift = ((index<<2)&4); + uint8_t mask = 240 >> shift; + p_greyscale->byte_data[index>>1] = (p_greyscale->byte_data[index>>1] & mask) | (val << shift); +} + +void greyscaleFill(greyscale_t * p_greyscale, mp_int_t val) { + mp_int_t byte = (val<<4) | val; + for (int i = 0; i < ((p_greyscale->width*p_greyscale->height+1)>>1); i++) { + p_greyscale->byte_data[i] = byte; + } +} + +void greyscaleClear(greyscale_t * p_greyscale) { + memset(&p_greyscale->byte_data, 0, (p_greyscale->width*p_greyscale->height+1)>>1); +} + +uint8_t imageGetPixelValue(microbit_image_obj_t * p_image, mp_int_t x, mp_int_t y) { + if (p_image->base.five) + return monochromeGetPixelValue(&p_image->monochrome_5by5, x, y)*MAX_BRIGHTNESS; + else + return greyscaleGetPixelValue(&p_image->greyscale, x, y); +} + +mp_int_t imageWidth(microbit_image_obj_t * p_image) { + if (p_image->base.five) + return 5; + else + return p_image->greyscale.width; +} + +mp_int_t imageHeight(microbit_image_obj_t * p_image) { + if (p_image->base.five) + return 5; + else + return p_image->greyscale.height; +} + +STATIC greyscale_t *greyscale_new(mp_int_t w, mp_int_t h) { + greyscale_t *result = m_new_obj_var(greyscale_t, uint8_t, (w*h+1)>>1); + result->base.type = µbit_image_type; + result->five = 0; + result->width = w; + result->height = h; + return result; +} + +greyscale_t * imageCopy(microbit_image_obj_t * p_image) { + mp_int_t w = imageWidth(p_image); + mp_int_t h = imageHeight(p_image); + greyscale_t *result = greyscale_new(w, h); + for (mp_int_t y = 0; y < h; y++) { + for (mp_int_t x = 0; x < w; ++x) { + greyscaleSetPixelValue(result, x,y, imageGetPixelValue(p_image, x,y)); + } + } + return result; +} + +greyscale_t * imageInvert(microbit_image_obj_t * p_image) { + mp_int_t w = imageWidth(p_image); + mp_int_t h = imageHeight(p_image); + greyscale_t *result = greyscale_new(w, h); + for (mp_int_t y = 0; y < h; y++) { + for (mp_int_t x = 0; x < w; ++x) { + greyscaleSetPixelValue(result, x,y, MAX_BRIGHTNESS - imageGetPixelValue(p_image, x,y)); + } + } + return result; +} + +STATIC microbit_image_obj_t *image_from_parsed_str(const char *s, mp_int_t len) { + mp_int_t w = 0; + mp_int_t h = 0; + mp_int_t line_len = 0; + greyscale_t *result; + /*First pass -- Establish metadata */ + for (int i = 0; i < len; i++) { + char c = s[i]; + if (c == '\n' || c == ':') { + w = max(line_len, w); + line_len = 0; + ++h; + } else if (c == ' ') { + ++line_len; + } else if ('c' >= '0' && c <= '9') { + ++line_len; + } else { + mp_raise_ValueError("Unexpected character in Image definition."); + } + } + if (line_len) { + // Omitted trailing terminator + ++h; + w = max(line_len, w); + } + result = greyscale_new(w, h); + mp_int_t x = 0; + mp_int_t y = 0; + /* Second pass -- Fill in data */ + for (int i = 0; i < len; i++) { + char c = s[i]; + if (c == '\n' || c == ':') { + while (x < w) { + greyscaleSetPixelValue(result, x, y, 0); + x++; + } + ++y; + x = 0; + } else if (c == ' ') { + /* Treat spaces as 0 */ + greyscaleSetPixelValue(result, x, y, 0); + ++x; + } else if ('c' >= '0' && c <= '9') { + greyscaleSetPixelValue(result, x, y, c - '0'); + ++x; + } + } + if (y < h) { + while (x < w) { + greyscaleSetPixelValue(result, x, y, 0); + x++; + } + } + return (microbit_image_obj_t *)result; +} + + +STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 3, false); + + switch (n_args) { + case 0: { + greyscale_t *image = greyscale_new(5, 5); + greyscaleClear(image); + return image; + } + + case 1: { + if (MP_OBJ_IS_STR(args[0])) { + // arg is a string object + mp_uint_t len; + const char *str = mp_obj_str_get_data(args[0], &len); + // make image from string + if (len == 1) { + /* For a single charater, return the font glyph */ + return microbit_image_for_char(str[0]); + } else { + /* Otherwise parse the image description string */ + return image_from_parsed_str(str, len); + } + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, + "Image(s) takes a string.")); + } + } + + case 2: + case 3: { + mp_int_t w = mp_obj_get_int(args[0]); + mp_int_t h = mp_obj_get_int(args[1]); + greyscale_t *image = greyscale_new(w, h); + if (n_args == 2) { + greyscaleClear(image); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + + if (w < 0 || h < 0 || (size_t)(w * h) != bufinfo.len) { + mp_raise_ValueError("image data is incorrect size"); + } + mp_int_t i = 0; + for (mp_int_t y = 0; y < h; y++) { + for (mp_int_t x = 0; x < w; ++x) { + uint8_t val = min(((const uint8_t*)bufinfo.buf)[i], MAX_BRIGHTNESS); + greyscaleSetPixelValue(image, x, y, val); + ++i; + } + } + } + return image; + } + + default: { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, + "Image() takes 0 to 3 arguments")); + } + } +} + +static void clear_rect(greyscale_t *img, mp_int_t x0, mp_int_t y0,mp_int_t x1, mp_int_t y1) { + for (int i = x0; i < x1; ++i) { + for (int j = y0; j < y1; ++j) { + greyscaleSetPixelValue(img, i, j, 0); + } + } +} + +STATIC void image_blit(microbit_image_obj_t *src, greyscale_t *dest, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h, mp_int_t xdest, mp_int_t ydest) { + if (w < 0) + w = 0; + if (h < 0) + h = 0; + mp_int_t intersect_x0 = max(max(0, x), -xdest); + mp_int_t intersect_y0 = max(max(0, y), -ydest); + mp_int_t intersect_x1 = min(min(dest->width+x-xdest, imageWidth(src)), x+w); + mp_int_t intersect_y1 = min(min(dest->height+y-ydest, imageHeight(src)), y+h); + mp_int_t xstart, xend, ystart, yend, xdel, ydel; + mp_int_t clear_x0 = max(0, xdest); + mp_int_t clear_y0 = max(0, ydest); + mp_int_t clear_x1 = min(dest->width, xdest+w); + mp_int_t clear_y1 = min(dest->height, ydest+h); + if (intersect_x0 >= intersect_x1 || intersect_y0 >= intersect_y1) { + // Nothing to copy + clear_rect(dest, clear_x0, clear_y0, clear_x1, clear_y1); + return; + } + if (x > xdest) { + xstart = intersect_x0; xend = intersect_x1; xdel = 1; + } else { + xstart = intersect_x1-1; xend = intersect_x0-1; xdel = -1; + } + if (y > ydest) { + ystart = intersect_y0; yend = intersect_y1; ydel = 1; + } else { + ystart = intersect_y1-1; yend = intersect_y0-1; ydel = -1; + } + for (int i = xstart; i != xend; i += xdel) { + for (int j = ystart; j != yend; j += ydel) { + int val = imageGetPixelValue(src, i, j); + greyscaleSetPixelValue(dest, i+xdest-x, j+ydest-y, val); + } + } + // Adjust intersection rectange to dest + intersect_x0 += xdest-x; + intersect_y0 += ydest-y; + intersect_x1 += xdest-x; + intersect_y1 += ydest-y; + // Clear four rectangles in the cleared area surrounding the copied area. + clear_rect(dest, clear_x0, clear_y0, intersect_x0, intersect_y1); + clear_rect(dest, clear_x0, intersect_y1, intersect_x1, clear_y1); + clear_rect(dest, intersect_x1, intersect_y0, clear_x1, clear_y1); + clear_rect(dest, intersect_x0, clear_y0, clear_x1, intersect_y0); +} + +greyscale_t *image_shift(microbit_image_obj_t *self, mp_int_t x, mp_int_t y) { + greyscale_t *result = greyscale_new(imageWidth(self), imageWidth(self)); + image_blit(self, result, x, y, imageWidth(self), imageWidth(self), 0, 0); + return result; +} + +STATIC microbit_image_obj_t *image_crop(microbit_image_obj_t *img, mp_int_t x, mp_int_t y, mp_int_t w, mp_int_t h) { + if (w < 0) + w = 0; + if (h < 0) + h = 0; + greyscale_t *result = greyscale_new(w, h); + image_blit(img, result, x, y, w, h, 0, 0); + return (microbit_image_obj_t *)result; +} + +mp_obj_t microbit_image_width(mp_obj_t self_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + return MP_OBJ_NEW_SMALL_INT(imageWidth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_width_obj, microbit_image_width); + +mp_obj_t microbit_image_height(mp_obj_t self_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + return MP_OBJ_NEW_SMALL_INT(imageHeight(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_height_obj, microbit_image_height); + +mp_obj_t microbit_image_get_pixel(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_int_t x = mp_obj_get_int(x_in); + mp_int_t y = mp_obj_get_int(y_in); + if (x < 0 || y < 0) { + mp_raise_ValueError("index cannot be negative"); + } + if (x < imageWidth(self) && y < imageHeight(self)) { + return MP_OBJ_NEW_SMALL_INT(imageGetPixelValue(self, x, y)); + } + mp_raise_ValueError("index too large"); +} +MP_DEFINE_CONST_FUN_OBJ_3(microbit_image_get_pixel_obj, microbit_image_get_pixel); + +/* Raise an exception if not mutable */ +static void check_mutability(microbit_image_obj_t *self) { + if (self->base.five) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "image cannot be modified (try copying first)")); + } +} + + +mp_obj_t microbit_image_set_pixel(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; + microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; + check_mutability(self); + mp_int_t x = mp_obj_get_int(args[1]); + mp_int_t y = mp_obj_get_int(args[2]); + if (x < 0 || y < 0) { + mp_raise_ValueError("index cannot be negative"); + } + mp_int_t bright = mp_obj_get_int(args[3]); + if (bright < 0 || bright > MAX_BRIGHTNESS) + mp_raise_ValueError("brightness out of bounds."); + if (x < imageWidth(self) && y < imageHeight(self)) { + greyscaleSetPixelValue(&(self->greyscale), x, y, bright); + return mp_const_none; + } + mp_raise_ValueError("index too large"); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_set_pixel_obj, 4, 4, microbit_image_set_pixel); + +mp_obj_t microbit_image_fill(mp_obj_t self_in, mp_obj_t n_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + check_mutability(self); + mp_int_t n = mp_obj_get_int(n_in); + if (n < 0 || n > MAX_BRIGHTNESS) { + mp_raise_ValueError("brightness out of bounds."); + } + greyscaleFill(&self->greyscale, n); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_fill_obj, microbit_image_fill); + +mp_obj_t microbit_image_blit(mp_uint_t n_args, const mp_obj_t *args) { + microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; + check_mutability(self); + + mp_obj_t src = args[1]; + if (mp_obj_get_type(src) != µbit_image_type) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting an image")); + } + if (n_args == 7) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, + "must specify both offsets")); + } + mp_int_t x = mp_obj_get_int(args[2]); + mp_int_t y = mp_obj_get_int(args[3]); + mp_int_t w = mp_obj_get_int(args[4]); + mp_int_t h = mp_obj_get_int(args[5]); + if (w < 0 || h < 0) { + mp_raise_ValueError("size cannot be negative"); + } + mp_int_t xdest; + mp_int_t ydest; + if (n_args == 6) { + xdest = 0; + ydest = 0; + } else { + xdest = mp_obj_get_int(args[6]); + ydest = mp_obj_get_int(args[7]); + } + image_blit((microbit_image_obj_t *)src, &(self->greyscale), x, y, w, h, xdest, ydest); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_blit_obj, 6, 8, microbit_image_blit); + +mp_obj_t microbit_image_crop(mp_uint_t n_args, const mp_obj_t *args) { + (void)n_args; + microbit_image_obj_t *self = (microbit_image_obj_t*)args[0]; + mp_int_t x0 = mp_obj_get_int(args[1]); + mp_int_t y0 = mp_obj_get_int(args[2]); + mp_int_t x1 = mp_obj_get_int(args[3]); + mp_int_t y1 = mp_obj_get_int(args[4]); + return image_crop(self, x0, y0, x1, y1); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_image_crop_obj, 5, 5, microbit_image_crop); + +mp_obj_t microbit_image_shift_left(mp_obj_t self_in, mp_obj_t n_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_int_t n = mp_obj_get_int(n_in); + return image_shift(self, n, 0); +} +MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_left_obj, microbit_image_shift_left); + +mp_obj_t microbit_image_shift_right(mp_obj_t self_in, mp_obj_t n_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_int_t n = mp_obj_get_int(n_in); + return image_shift(self, -n, 0); +} +MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_right_obj, microbit_image_shift_right); + +mp_obj_t microbit_image_shift_up(mp_obj_t self_in, mp_obj_t n_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_int_t n = mp_obj_get_int(n_in); + return image_shift(self, 0, n); +} +MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_up_obj, microbit_image_shift_up); + +mp_obj_t microbit_image_shift_down(mp_obj_t self_in, mp_obj_t n_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + mp_int_t n = mp_obj_get_int(n_in); + return image_shift(self, 0, -n); +} +MP_DEFINE_CONST_FUN_OBJ_2(microbit_image_shift_down_obj, microbit_image_shift_down); + +mp_obj_t microbit_image_copy(mp_obj_t self_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + return imageCopy(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_copy_obj, microbit_image_copy); + +mp_obj_t microbit_image_invert(mp_obj_t self_in) { + microbit_image_obj_t *self = (microbit_image_obj_t*)self_in; + return imageInvert(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_image_invert_obj, microbit_image_invert); + + +STATIC const mp_rom_map_elem_t microbit_image_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(µbit_image_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(µbit_image_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(µbit_image_get_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(µbit_image_set_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_shift_left), MP_ROM_PTR(µbit_image_shift_left_obj) }, + { MP_ROM_QSTR(MP_QSTR_shift_right), MP_ROM_PTR(µbit_image_shift_right_obj) }, + { MP_ROM_QSTR(MP_QSTR_shift_up), MP_ROM_PTR(µbit_image_shift_up_obj) }, + { MP_ROM_QSTR(MP_QSTR_shift_down), MP_ROM_PTR(µbit_image_shift_down_obj) }, + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(µbit_image_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_crop), MP_ROM_PTR(µbit_image_crop_obj) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(µbit_image_invert_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(µbit_image_fill_obj) }, + { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(µbit_image_blit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_HEART), MP_ROM_PTR(µbit_const_image_heart_obj) }, + { MP_ROM_QSTR(MP_QSTR_HEART_SMALL), MP_ROM_PTR(µbit_const_image_heart_small_obj) }, + { MP_ROM_QSTR(MP_QSTR_HAPPY), MP_ROM_PTR(µbit_const_image_happy_obj) }, + { MP_ROM_QSTR(MP_QSTR_SMILE), MP_ROM_PTR(µbit_const_image_smile_obj) }, + { MP_ROM_QSTR(MP_QSTR_SAD), MP_ROM_PTR(µbit_const_image_sad_obj) }, + { MP_ROM_QSTR(MP_QSTR_CONFUSED), MP_ROM_PTR(µbit_const_image_confused_obj) }, + { MP_ROM_QSTR(MP_QSTR_ANGRY), MP_ROM_PTR(µbit_const_image_angry_obj) }, + { MP_ROM_QSTR(MP_QSTR_ASLEEP), MP_ROM_PTR(µbit_const_image_asleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_SURPRISED), MP_ROM_PTR(µbit_const_image_surprised_obj) }, + { MP_ROM_QSTR(MP_QSTR_SILLY), MP_ROM_PTR(µbit_const_image_silly_obj) }, + { MP_ROM_QSTR(MP_QSTR_FABULOUS), MP_ROM_PTR(µbit_const_image_fabulous_obj) }, + { MP_ROM_QSTR(MP_QSTR_MEH), MP_ROM_PTR(µbit_const_image_meh_obj) }, + { MP_ROM_QSTR(MP_QSTR_YES), MP_ROM_PTR(µbit_const_image_yes_obj) }, + { MP_ROM_QSTR(MP_QSTR_NO), MP_ROM_PTR(µbit_const_image_no_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK12), MP_ROM_PTR(µbit_const_image_clock12_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK1), MP_ROM_PTR(µbit_const_image_clock1_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK2), MP_ROM_PTR(µbit_const_image_clock2_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK3), MP_ROM_PTR(µbit_const_image_clock3_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK4), MP_ROM_PTR(µbit_const_image_clock4_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK5), MP_ROM_PTR(µbit_const_image_clock5_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK6), MP_ROM_PTR(µbit_const_image_clock6_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK7), MP_ROM_PTR(µbit_const_image_clock7_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK8), MP_ROM_PTR(µbit_const_image_clock8_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK9), MP_ROM_PTR(µbit_const_image_clock9_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK10), MP_ROM_PTR(µbit_const_image_clock10_obj) }, + { MP_ROM_QSTR(MP_QSTR_CLOCK11), MP_ROM_PTR(µbit_const_image_clock11_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_N), MP_ROM_PTR(µbit_const_image_arrow_n_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_NE), MP_ROM_PTR(µbit_const_image_arrow_ne_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_E), MP_ROM_PTR(µbit_const_image_arrow_e_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_SE), MP_ROM_PTR(µbit_const_image_arrow_se_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_S), MP_ROM_PTR(µbit_const_image_arrow_s_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_SW), MP_ROM_PTR(µbit_const_image_arrow_sw_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_W), MP_ROM_PTR(µbit_const_image_arrow_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_ARROW_NW), MP_ROM_PTR(µbit_const_image_arrow_nw_obj) }, + { MP_ROM_QSTR(MP_QSTR_TRIANGLE), MP_ROM_PTR(µbit_const_image_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_TRIANGLE_LEFT), MP_ROM_PTR(µbit_const_image_triangle_left_obj) }, + { MP_ROM_QSTR(MP_QSTR_CHESSBOARD), MP_ROM_PTR(µbit_const_image_chessboard_obj) }, + { MP_ROM_QSTR(MP_QSTR_DIAMOND), MP_ROM_PTR(µbit_const_image_diamond_obj) }, + { MP_ROM_QSTR(MP_QSTR_DIAMOND_SMALL), MP_ROM_PTR(µbit_const_image_diamond_small_obj) }, + { MP_ROM_QSTR(MP_QSTR_SQUARE), MP_ROM_PTR(µbit_const_image_square_obj) }, + { MP_ROM_QSTR(MP_QSTR_SQUARE_SMALL), MP_ROM_PTR(µbit_const_image_square_small_obj) }, + { MP_ROM_QSTR(MP_QSTR_RABBIT), MP_ROM_PTR(µbit_const_image_rabbit) }, + { MP_ROM_QSTR(MP_QSTR_COW), MP_ROM_PTR(µbit_const_image_cow) }, + { MP_ROM_QSTR(MP_QSTR_MUSIC_CROTCHET), MP_ROM_PTR(µbit_const_image_music_crotchet_obj) }, + { MP_ROM_QSTR(MP_QSTR_MUSIC_QUAVER), MP_ROM_PTR(µbit_const_image_music_quaver_obj) }, + { MP_ROM_QSTR(MP_QSTR_MUSIC_QUAVERS), MP_ROM_PTR(µbit_const_image_music_quavers_obj) }, + { MP_ROM_QSTR(MP_QSTR_PITCHFORK), MP_ROM_PTR(µbit_const_image_pitchfork_obj) }, + { MP_ROM_QSTR(MP_QSTR_XMAS), MP_ROM_PTR(µbit_const_image_xmas_obj) }, + { MP_ROM_QSTR(MP_QSTR_PACMAN), MP_ROM_PTR(µbit_const_image_pacman_obj) }, + { MP_ROM_QSTR(MP_QSTR_TARGET), MP_ROM_PTR(µbit_const_image_target_obj) }, + { MP_ROM_QSTR(MP_QSTR_ALL_CLOCKS), MP_ROM_PTR(µbit_const_image_all_clocks_tuple_obj) }, + { MP_ROM_QSTR(MP_QSTR_ALL_ARROWS), MP_ROM_PTR(µbit_const_image_all_arrows_tuple_obj) }, + { MP_ROM_QSTR(MP_QSTR_TSHIRT), MP_ROM_PTR(µbit_const_image_tshirt_obj) }, + { MP_ROM_QSTR(MP_QSTR_ROLLERSKATE), MP_ROM_PTR(µbit_const_image_rollerskate_obj) }, + { MP_ROM_QSTR(MP_QSTR_DUCK), MP_ROM_PTR(µbit_const_image_duck_obj) }, + { MP_ROM_QSTR(MP_QSTR_HOUSE), MP_ROM_PTR(µbit_const_image_house_obj) }, + { MP_ROM_QSTR(MP_QSTR_TORTOISE), MP_ROM_PTR(µbit_const_image_tortoise_obj) }, + { MP_ROM_QSTR(MP_QSTR_BUTTERFLY), MP_ROM_PTR(µbit_const_image_butterfly_obj) }, + { MP_ROM_QSTR(MP_QSTR_STICKFIGURE), MP_ROM_PTR(µbit_const_image_stickfigure_obj) }, + { MP_ROM_QSTR(MP_QSTR_GHOST), MP_ROM_PTR(µbit_const_image_ghost_obj) }, + { MP_ROM_QSTR(MP_QSTR_SWORD), MP_ROM_PTR(µbit_const_image_sword_obj) }, + { MP_ROM_QSTR(MP_QSTR_GIRAFFE), MP_ROM_PTR(µbit_const_image_giraffe_obj) }, + { MP_ROM_QSTR(MP_QSTR_SKULL), MP_ROM_PTR(µbit_const_image_skull_obj) }, + { MP_ROM_QSTR(MP_QSTR_UMBRELLA), MP_ROM_PTR(µbit_const_image_umbrella_obj) }, + { MP_ROM_QSTR(MP_QSTR_SNAKE), MP_ROM_PTR(µbit_const_image_snake_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(microbit_image_locals_dict, microbit_image_locals_dict_table); + +#define THE_FONT font_pendolino3_5x5_pad3msb + +#define ASCII_START 32 +#define ASCII_END 126 + +STATIC const unsigned char *get_font_data_from_char(char c) { + if (c < ASCII_START || c > ASCII_END) { + c = '?'; + } + int offset = (c-ASCII_START) * 5; + return THE_FONT + offset; +} + +STATIC mp_int_t get_pixel_from_font_data(const unsigned char *data, int x, int y) { + /* The following logic belongs in MicroBitFont */ + return ((data[y]>>(4-x))&1); +} + +void microbit_image_set_from_char(greyscale_t *img, char c) { + const unsigned char *data = get_font_data_from_char(c); + for (int x = 0; x < 5; ++x) { + for (int y = 0; y < 5; ++y) { + greyscaleSetPixelValue(img, x, y, get_pixel_from_font_data(data, x, y)*MAX_BRIGHTNESS); + } + } +} + + +microbit_image_obj_t *microbit_image_for_char(char c) { + greyscale_t *result = greyscale_new(5,5); + microbit_image_set_from_char(result, c); + return (microbit_image_obj_t *)result; +} + +#if MICROPY_PY_BUILTINS_FLOAT +microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t fval) { +#else +microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_int_t fval) { +#endif + if (fval < 0) + mp_raise_ValueError("Brightness multiplier must not be negative."); + greyscale_t *result = greyscale_new(imageWidth(lhs), imageHeight(lhs)); + for (int x = 0; x < imageWidth(lhs); ++x) { + for (int y = 0; y < imageWidth(lhs); ++y) { +#if MICROPY_PY_BUILTINS_FLOAT + int val = min((int)imageGetPixelValue(lhs, x,y)*fval+0.5, MAX_BRIGHTNESS); +#else + int val = min((int)imageGetPixelValue(lhs, x,y)*fval, MAX_BRIGHTNESS); +#endif + greyscaleSetPixelValue(result, x, y, val); + } + } + return (microbit_image_obj_t *)result; +} + +microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_image_obj_t *rhs, bool add) { + mp_int_t h = imageHeight(lhs); + mp_int_t w = imageWidth(lhs); + if (imageHeight(rhs) != h || imageWidth(lhs) != w) { +// TODO: verify that image width in test above should really test (lhs != w) + mp_raise_ValueError("Images must be the same size."); + } + greyscale_t *result = greyscale_new(w, h); + for (int x = 0; x < w; ++x) { + for (int y = 0; y < h; ++y) { + int val; + int lval = imageGetPixelValue(lhs, x,y); + int rval = imageGetPixelValue(rhs, x,y); + if (add) + val = min(lval + rval, MAX_BRIGHTNESS); + else + val = max(0, lval - rval); + greyscaleSetPixelValue(result, x, y, val); + } + } + return (microbit_image_obj_t *)result; +} + +STATIC mp_obj_t image_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (mp_obj_get_type(lhs_in) != µbit_image_type) { + return MP_OBJ_NULL; // op not supported + } + microbit_image_obj_t *lhs = (microbit_image_obj_t *)lhs_in; + switch(op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_SUBTRACT: + break; + case MP_BINARY_OP_MULTIPLY: +#if MICROPY_PY_BUILTINS_FLOAT + return microbit_image_dim(lhs, mp_obj_get_float(rhs_in)); +#else + return microbit_image_dim(lhs, mp_obj_get_int(rhs_in) * 10); +#endif + case MP_BINARY_OP_TRUE_DIVIDE: +#if MICROPY_PY_BUILTINS_FLOAT + return microbit_image_dim(lhs, 1.0/mp_obj_get_float(rhs_in)); +#else + break; + case MP_BINARY_OP_FLOOR_DIVIDE: + return microbit_image_dim(lhs, (100/mp_obj_get_int(rhs_in) + 5) / 10); +#endif + default: + return MP_OBJ_NULL; // op not supported + } + if (mp_obj_get_type(rhs_in) != µbit_image_type) { + return MP_OBJ_NULL; // op not supported + } + return microbit_image_sum(lhs, (microbit_image_obj_t *)rhs_in, op == MP_BINARY_OP_ADD); +} + + +const mp_obj_type_t microbit_image_type = { + { &mp_type_type }, + .name = MP_QSTR_MicroBitImage, + .print = microbit_image_print, + .make_new = microbit_image_make_new, + .call = NULL, + .unary_op = NULL, + .binary_op = image_binary_op, + .attr = NULL, + .subscr = NULL, + .getiter = NULL, + .iternext = NULL, + .buffer_p = {NULL}, + .locals_dict = (mp_obj_dict_t*)µbit_image_locals_dict, +}; + +typedef struct _scrolling_string_t { + mp_obj_base_t base; + char const *str; + mp_uint_t len; + mp_obj_t ref; + bool monospace; + bool repeat; +} scrolling_string_t; + +typedef struct _scrolling_string_iterator_t { + mp_obj_base_t base; + mp_obj_t ref; + greyscale_t *img; + char const *next_char; + char const *start; + char const *end; + uint8_t offset; + uint8_t offset_limit; + bool monospace; + bool repeat; + char right; +} scrolling_string_iterator_t; + +extern const mp_obj_type_t microbit_scrolling_string_type; +extern const mp_obj_type_t microbit_scrolling_string_iterator_type; + +mp_obj_t scrolling_string_image_iterable(const char* str, mp_uint_t len, mp_obj_t ref, bool monospace, bool repeat) { + scrolling_string_t *result = m_new_obj(scrolling_string_t); + result->base.type = µbit_scrolling_string_type; + result->str = str; + result->len = len; + result->ref = ref; + result->monospace = monospace; + result->repeat = repeat; + return result; +} + +STATIC int font_column_non_blank(const unsigned char *font_data, unsigned int col) { + for (int y = 0; y < 5; ++y) { + if (get_pixel_from_font_data(font_data, col, y)) { + return 1; + } + } + return 0; +} + +/* Not strictly the rightmost non-blank column, but the rightmost in columns 2,3 or 4. */ +STATIC unsigned int rightmost_non_blank_column(const unsigned char *font_data) { + if (font_column_non_blank(font_data, 4)) { + return 4; + } + if (font_column_non_blank(font_data, 3)) { + return 3; + } + return 2; +} + +static void restart(scrolling_string_iterator_t *iter) { + iter->next_char = iter->start; + iter->offset = 0; + if (iter->start < iter->end) { + iter->right = *iter->next_char; + if (iter->monospace) { + iter->offset_limit = 5; + } else { + iter->offset_limit = rightmost_non_blank_column(get_font_data_from_char(iter->right)) + 1; + } + } else { + iter->right = ' '; + iter->offset_limit = 5; + } +} + +STATIC mp_obj_t get_microbit_scrolling_string_iter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + (void)iter_buf; + scrolling_string_t *str = (scrolling_string_t *)o_in; + scrolling_string_iterator_t *result = m_new_obj(scrolling_string_iterator_t); + result->base.type = µbit_scrolling_string_iterator_type; + result->img = greyscale_new(5,5); + result->start = str->str; + result->ref = str->ref; + result->monospace = str->monospace; + result->end = result->start + str->len; + result->repeat = str->repeat; + restart(result); + return result; +} + +STATIC mp_obj_t microbit_scrolling_string_iter_next(mp_obj_t o_in) { + scrolling_string_iterator_t *iter = (scrolling_string_iterator_t *)o_in; + if (iter->next_char == iter->end && iter->offset == 5) { + if (iter->repeat) { + restart(iter); + greyscaleClear(iter->img); + } else { + return MP_OBJ_STOP_ITERATION; + } + } + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 5; y++) { + greyscaleSetPixelValue(iter->img, x, y, greyscaleGetPixelValue(iter->img, x+1, y)); + } + } + for (int y = 0; y < 5; y++) { + greyscaleSetPixelValue(iter->img, 4, y, 0); + } + const unsigned char *font_data; + if (iter->offset < iter->offset_limit) { + font_data = get_font_data_from_char(iter->right); + for (int y = 0; y < 5; ++y) { + int pix = get_pixel_from_font_data(font_data, iter->offset, y)*MAX_BRIGHTNESS; + greyscaleSetPixelValue(iter->img, 4, y, pix); + } + } else if (iter->offset == iter->offset_limit) { + ++iter->next_char; + if (iter->next_char == iter->end) { + iter->right = ' '; + iter->offset_limit = 5; + iter->offset = 0; + } else { + iter->right = *iter->next_char; + font_data = get_font_data_from_char(iter->right); + if (iter->monospace) { + iter->offset = -1; + iter->offset_limit = 5; + } else { + iter->offset = -font_column_non_blank(font_data, 0); + iter->offset_limit = rightmost_non_blank_column(font_data)+1; + } + } + } + ++iter->offset; + return iter->img; +} + +const mp_obj_type_t microbit_scrolling_string_type = { + { &mp_type_type }, + .name = MP_QSTR_ScrollingString, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = NULL, + .binary_op = NULL, + .attr = NULL, + .subscr = NULL, + .getiter = get_microbit_scrolling_string_iter, + .iternext = NULL, + .buffer_p = {NULL}, + .locals_dict = NULL, +}; + +const mp_obj_type_t microbit_scrolling_string_iterator_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = NULL, + .binary_op = NULL, + .attr = NULL, + .subscr = NULL, + .getiter = mp_identity_getiter, + .iternext = microbit_scrolling_string_iter_next, + .buffer_p = {NULL}, + .locals_dict = NULL, +}; + +/** Facade types to present a string as a sequence of images. + * These are necessary to avoid allocation during iteration, + * which may happen in interrupt handlers. + */ + +typedef struct _string_image_facade_t { + mp_obj_base_t base; + mp_obj_t string; + greyscale_t *image; +} string_image_facade_t; + +static mp_obj_t string_image_facade_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { + if (value == MP_OBJ_SENTINEL) { + // Fill in image + string_image_facade_t *self = (string_image_facade_t *)self_in; + mp_uint_t len; + const char *text = mp_obj_str_get_data(self->string, &len); + mp_uint_t index = mp_get_index(self->base.type, len, index_in, false); + microbit_image_set_from_char(self->image, text[index]); + return self->image; + } else { + return MP_OBJ_NULL; // op not supported + } +} + +static mp_obj_t facade_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + string_image_facade_t *self = (string_image_facade_t *)self_in; + switch (op) { + case MP_UNARY_OP_LEN: + return mp_obj_len(self->string); + default: return MP_OBJ_NULL; // op not supported + } +} + +static mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf); + +const mp_obj_type_t string_image_facade_type = { + { &mp_type_type }, + .name = MP_QSTR_Facade, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = facade_unary_op, + .binary_op = NULL, + .attr = NULL, + .subscr = string_image_facade_subscr, + .getiter = microbit_facade_iterator, + .iternext = NULL, + .buffer_p = {NULL}, + NULL +}; + + +typedef struct _facade_iterator_t { + mp_obj_base_t base; + mp_obj_t string; + mp_uint_t index; + greyscale_t *image; +} facade_iterator_t; + +mp_obj_t microbit_string_facade(mp_obj_t string) { + string_image_facade_t *result = m_new_obj(string_image_facade_t); + result->base.type = &string_image_facade_type; + result->string = string; + result->image = greyscale_new(5,5); + return result; +} + +static mp_obj_t microbit_facade_iter_next(mp_obj_t iter_in) { + facade_iterator_t *iter = (facade_iterator_t *)iter_in; + mp_uint_t len; + const char *text = mp_obj_str_get_data(iter->string, &len); + if (iter->index >= len) { + return MP_OBJ_STOP_ITERATION; + } + microbit_image_set_from_char(iter->image, text[iter->index]); + iter->index++; + return iter->image; +} + +const mp_obj_type_t microbit_facade_iterator_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .print = NULL, + .make_new = NULL, + .call = NULL, + .unary_op = NULL, + .binary_op = NULL, + .attr = NULL, + .subscr = NULL, + .getiter = mp_identity_getiter, + .iternext = microbit_facade_iter_next, + .buffer_p = {NULL}, + NULL +}; + +mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf) { + (void)iter_buf; + facade_iterator_t *result = m_new_obj(facade_iterator_t); + string_image_facade_t *iterable = (string_image_facade_t *)iterable_in; + result->base.type = µbit_facade_iterator_type; + result->string = iterable->string; + result->image = iterable->image; + result->index = 0; + return result; +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.h new file mode 100755 index 0000000..23edbd6 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/microbitimage.h @@ -0,0 +1,99 @@ +#ifndef __MICROPY_INCLUDED_MICROBIT_IMAGE_H__ +#define __MICROPY_INCLUDED_MICROBIT_IMAGE_H__ + +#include "py/runtime.h" + +#define MAX_BRIGHTNESS 9 + +/** Monochrome images are immutable, which means that + * we only need one bit per pixel which saves quite a lot + * of memory */ + +/* we reserve a couple of bits, so we won't need to modify the + * layout if we need to add more functionality or subtypes. */ +#define TYPE_AND_FLAGS \ + mp_obj_base_t base; \ + uint8_t five:1; \ + uint8_t reserved1:1; \ + uint8_t reserved2:1 + +typedef struct _image_base_t { + TYPE_AND_FLAGS; +} image_base_t; + +typedef struct _monochrome_5by5_t { + TYPE_AND_FLAGS; + uint8_t pixel44: 1; + uint8_t bits24[3]; +} monochrome_5by5_t; + + +/* This is an internal method it is up to the caller to validate the inputs */ +uint8_t monochromeGetPixelValue(monochrome_5by5_t * p_mono, mp_int_t x, mp_int_t y); + +typedef struct _greyscale_t { + TYPE_AND_FLAGS; + uint8_t height; + uint8_t width; + uint8_t byte_data[]; /* Static initializer for this will have to be C, not C++ */ +} greyscale_t; + +#if 1 +void clear(greyscale_t * p_greyscale); +/* Thiese are internal methods and it is up to the caller to validate the inputs */ +uint8_t greyscaleGetPixelValue(greyscale_t * p_greyscale, mp_int_t x, mp_int_t y); +void greyscaleSetPixelValue(greyscale_t * p_greyscale, mp_int_t x, mp_int_t y, mp_int_t val); +void greyscaleFill(greyscale_t * p_greyscale, mp_int_t val); +#endif + +typedef union _microbit_image_obj_t { + image_base_t base; + monochrome_5by5_t monochrome_5by5; + greyscale_t greyscale; +} microbit_image_obj_t; + +#if 1 +mp_int_t imageHeight(microbit_image_obj_t * p_image_obj); +mp_int_t imageWidth(microbit_image_obj_t * p_image_obj); +greyscale_t * imageCopy(microbit_image_obj_t * p_image_obj); +greyscale_t * imageInvert(microbit_image_obj_t * p_image_obj); +/* This is an internal method it is up to the caller to validate the inputs */ +uint8_t imageGetPixelValue(microbit_image_obj_t * p_image_obj, mp_int_t x, mp_int_t y); +#endif + +/** Return a facade object that presents the string as a sequence of images */ +mp_obj_t microbit_string_facade(mp_obj_t string); + +void microbit_image_set_from_char(greyscale_t *img, char c); +microbit_image_obj_t *microbit_image_for_char(char c); +mp_obj_t microbit_image_slice(microbit_image_obj_t *img, mp_int_t start, mp_int_t width, mp_int_t stride); +/* ref exists so that we can pull a string out of an object and not have it GC'ed while oterating over it */ +mp_obj_t scrolling_string_image_iterable(const char* str, mp_uint_t len, mp_obj_t ref, bool monospace, bool repeat); + +#define SMALL_IMAGE(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p44) \ +{ \ + { µbit_image_type }, \ + 1, 0, 0, (p44), \ + { \ + (p0)|((p1)<<1)|((p2)<<2)|((p3)<<3)|((p4)<<4)|((p5)<<5)|((p6)<<6)|((p7)<<7), \ + (p8)|((p9)<<1)|((p10)<<2)|((p11)<<3)|((p12)<<4)|((p13)<<5)|((p14)<<6)|((p15)<<7), \ + (p16)|((p17)<<1)|((p18)<<2)|((p19)<<3)|((p20)<<4)|((p21)<<5)|((p22)<<6)|((p23)<<7) \ + } \ +} + +extern const monochrome_5by5_t microbit_blank_image; +extern const monochrome_5by5_t microbit_const_image_heart_obj; +extern const mp_obj_type_t microbit_image_type; + +#define BLANK_IMAGE (microbit_image_obj_t *)(µbit_blank_image) +#define HEART_IMAGE (microbit_image_obj_t *)(µbit_const_image_heart_obj) +#define HAPPY_IMAGE (microbit_image_obj_t *)(µbit_const_image_happy_obj) + +#if MICROPY_PY_BUILTINS_FLOAT +microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_float_t fval); +#else +microbit_image_obj_t *microbit_image_dim(microbit_image_obj_t *lhs, mp_int_t val); +#endif +microbit_image_obj_t *microbit_image_sum(microbit_image_obj_t *lhs, microbit_image_obj_t *rhs, bool add); + +#endif // __MICROPY_INCLUDED_MICROBIT_IMAGE_H__ diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.c b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.c new file mode 100755 index 0000000..061e095 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.c @@ -0,0 +1,158 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/mphal.h" +#include "modmicrobit.h" +#include "microbitdisplay.h" +#include "microbitimage.h" +#include "softpwm.h" +#include "ticker.h" +#include "nrf_temp.h" + +extern uint32_t ticks; + +STATIC mp_obj_t microbit_reset_(void) { + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(microbit_reset_obj, microbit_reset_); + +STATIC mp_obj_t microbit_sleep(mp_obj_t ms_in) { + mp_int_t ms = 0; + if (mp_obj_is_integer(ms_in)) { + ms = mp_obj_get_int(ms_in); +#if MICROPY_PY_BUILTINS_FLOAT + } else { + ms = (mp_int_t)mp_obj_get_float(ms_in); +#endif + } + if (ms > 0) { + mp_hal_delay_ms(ms); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(microbit_sleep_obj, microbit_sleep); + +STATIC mp_obj_t microbit_running_time(void) { + return MP_OBJ_NEW_SMALL_INT(ticks); +} +MP_DEFINE_CONST_FUN_OBJ_0(microbit_running_time_obj, microbit_running_time); + +static const monochrome_5by5_t panic = SMALL_IMAGE( + 1,1,0,1,1, + 1,1,0,1,1, + 0,0,0,0,0, + 0,1,1,1,0, + 1,0,0,0,1 +); + +STATIC mp_obj_t microbit_panic(mp_uint_t n_args, const mp_obj_t *args) { + while(true) { + microbit_display_show(µbit_display_obj, (microbit_image_obj_t*)&panic); + mp_hal_delay_ms(1000); + char num[4]; + int code; + if (n_args) { + code = mp_obj_get_int(args[0]); + } else { + code = 0; + } + num[2] = code%10 + '0'; + code /= 10; + num[1] = code%10 + '0'; + code /= 10; + num[0] = code%10 + '0'; + for (int i = 0; i < 3; i++) { + microbit_display_show(µbit_display_obj, microbit_image_for_char(num[i])); + mp_hal_delay_ms(1000); + } + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_panic_obj, 0, 1, microbit_panic); + +STATIC mp_obj_t microbit_temperature(void) { + int temp = nrf_temp_read(); +#if MICROPY_PY_BUILTINS_FLOAT + return mp_obj_new_float(temp / 4); +#else + return mp_obj_new_int(temp / 4); +#endif +} +MP_DEFINE_CONST_FUN_OBJ_0(microbit_temperature_obj, microbit_temperature); + +void board_modules_init0(void) { + ticker_register_low_pri_callback(microbit_display_tick); +} + +STATIC const mp_rom_map_elem_t microbit_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_Image), MP_ROM_PTR(µbit_image_type) }, + + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(µbit_display_obj) }, +/* { MP_OBJ_NEW_QSTR(MP_QSTR_button_a), (mp_obj_t)µbit_button_a_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_button_b), (mp_obj_t)µbit_button_b_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_accelerometer), (mp_obj_t)µbit_accelerometer_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_compass), (mp_obj_t)µbit_compass_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)µbit_i2c_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_uart), (mp_obj_t)µbit_uart_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_spi), (mp_obj_t)µbit_spi_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)µbit_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)µbit_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_running_time), (mp_obj_t)µbit_running_time_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_panic), (mp_obj_t)µbit_panic_obj }, +*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_temperature), (mp_obj_t)µbit_temperature_obj }, +/* + { MP_OBJ_NEW_QSTR(MP_QSTR_pin0), (mp_obj_t)µbit_p0_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin1), (mp_obj_t)µbit_p1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin2), (mp_obj_t)µbit_p2_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin3), (mp_obj_t)µbit_p3_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin4), (mp_obj_t)µbit_p4_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin5), (mp_obj_t)µbit_p5_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin6), (mp_obj_t)µbit_p6_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin7), (mp_obj_t)µbit_p7_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin8), (mp_obj_t)µbit_p8_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin9), (mp_obj_t)µbit_p9_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin10), (mp_obj_t)µbit_p10_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin11), (mp_obj_t)µbit_p11_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin12), (mp_obj_t)µbit_p12_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin13), (mp_obj_t)µbit_p13_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin14), (mp_obj_t)µbit_p14_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin15), (mp_obj_t)µbit_p15_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin16), (mp_obj_t)µbit_p16_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin19), (mp_obj_t)µbit_p19_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pin20), (mp_obj_t)µbit_p20_obj }, +*/ +}; + +STATIC MP_DEFINE_CONST_DICT(microbit_module_globals, microbit_module_globals_table); + +const mp_obj_module_t microbit_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)µbit_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.h new file mode 100755 index 0000000..ba65bd2 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/modules/modmicrobit.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +void board_modules_init0(void); diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.h new file mode 100755 index 0000000..abe138b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.h @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "micro:bit" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MUSIC (1) +#define MICROPY_PY_MACHINE_SOFT_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (0) + +// UART config +#define MICROPY_HW_UART1_RX (25) +#define MICROPY_HW_UART1_TX (24) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (23) +#define MICROPY_HW_SPI0_MOSI (21) +#define MICROPY_HW_SPI0_MISO (22) + +// micro:bit music pin +#define MICROPY_HW_MUSIC_PIN (3) diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.mk new file mode 100755 index 0000000..96f4300 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/mpconfigboard.mk @@ -0,0 +1,11 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +ifneq ($(SD),) +LD_FILES += boards/microbit/custom_nrf51822_s110_microbit.ld +endif +LD_FILES += boards/nrf51x22_256k_16k.ld +FLASHER = pyocd + +CFLAGS += -DBLUETOOTH_LFCLK_RC diff --git a/src/openmv/src/micropython/ports/nrf/boards/microbit/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/microbit/pins.csv new file mode 100755 index 0000000..40413ef --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/microbit/pins.csv @@ -0,0 +1,32 @@ +I2C_SCL,P0 +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +UART_RTS,P8 +UART_TX,P9 +UART_CTS,P10 +UART_RX,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +SPI_MOSI,P21 +SPI_MISO,P22 +SPI_SCK,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +I2C_SDA,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf51_prefix.c b/src/openmv/src/micropython/ports/nrf/boards/nrf51_prefix.c new file mode 100755 index 0000000..b819922 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf51_prefix.c @@ -0,0 +1,29 @@ +// nrf51_prefix.c becomes the initial portion of the generated pins file. + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .af_fn = (af_ptr) \ +} + +#define PIN(p_pin, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_P ## p_pin, \ + .pin = (p_pin), \ + .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_16k.ld b/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_16k.ld new file mode 100755 index 0000000..8a40ae0 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_16k.ld @@ -0,0 +1,12 @@ +/* + GNU linker script for NRF51 AA +*/ +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +_flash_size = 256K; +_ram_size = 16K; + +/* Default stack size when there is no SoftDevice */ +_stack_size = 4K; +_minimum_heap_size = 8K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_32k.ld b/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_32k.ld new file mode 100755 index 0000000..06c0914 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf51x22_256k_32k.ld @@ -0,0 +1,12 @@ +/* + GNU linker script for NRF51 AC +*/ +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +_flash_size = 256K; +_ram_size = 32K; + +/* Default stack size when there is no SoftDevice */ +_stack_size = 4K; +_minimum_heap_size = 24K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf52832_512k_64k.ld b/src/openmv/src/micropython/ports/nrf/boards/nrf52832_512k_64k.ld new file mode 100755 index 0000000..22804df --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf52832_512k_64k.ld @@ -0,0 +1,10 @@ +/* + GNU linker script for NRF52832 +*/ + +_flash_size = 512K; +_ram_size = 64K; + +/* produce a link error if there is not this amount of RAM for these sections */ +_stack_size = 8K; +_minimum_heap_size = 32K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf52840_1M_256k.ld b/src/openmv/src/micropython/ports/nrf/boards/nrf52840_1M_256k.ld new file mode 100755 index 0000000..16d61af --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf52840_1M_256k.ld @@ -0,0 +1,10 @@ +/* + GNU linker script for NRF52840 +*/ + +_flash_size = 1M; +_ram_size = 256K; + +/* produce a link error if there is not this amount of RAM for these sections */ +_stack_size = 8K; +_minimum_heap_size = 128K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/nrf52_prefix.c b/src/openmv/src/micropython/ports/nrf/boards/nrf52_prefix.c new file mode 100755 index 0000000..ede33f2 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/nrf52_prefix.c @@ -0,0 +1,29 @@ +// nrf52_prefix.c becomes the initial portion of the generated pins file. + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .af_fn = (af_ptr) \ +} + +#define PIN(p_pin, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_P ## p_pin, \ + .pin = (p_pin), \ + .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.h new file mode 100755 index 0000000..16ee97b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10000" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51-dongle" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (0) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (0) +#define MICROPY_PY_MACHINE_ADC (0) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_TRICOLOR (1) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED_RED (21) // RED +#define MICROPY_HW_LED_GREEN (22) // GREEN +#define MICROPY_HW_LED_BLUE (23) // BLUE + +// UART config +#define MICROPY_HW_UART1_RX (11) +#define MICROPY_HW_UART1_TX (9) +#define MICROPY_HW_UART1_HWFC (0) + +#define HELP_TEXT_BOARD_LED "1,2,3" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.mk new file mode 100755 index 0000000..c0cef5f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10000/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +LD_FILES += boards/nrf51x22_256k_16k.ld diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10000/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10000/pins.csv new file mode 100755 index 0000000..75fcbac --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10000/pins.csv @@ -0,0 +1,7 @@ +UART_RTS,P8 +UART_TX,P9 +UART_CTS,P10 +UART_RX,P11 +LED_RED,P21 +LED_GREEN,P22 +LED_BLUE,P23 diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.h new file mode 100755 index 0000000..e6a0cec --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10001" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51-DK" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (0) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (2) +#define MICROPY_HW_LED_PULLUP (0) + +#define MICROPY_HW_LED1 (18) // LED1 +#define MICROPY_HW_LED2 (19) // LED2 + +// UART config +#define MICROPY_HW_UART1_RX (11) +#define MICROPY_HW_UART1_TX (9) +#define MICROPY_HW_UART1_CTS (10) +#define MICROPY_HW_UART1_RTS (8) +#define MICROPY_HW_UART1_HWFC (0) + +#define HELP_TEXT_BOARD_LED "1,2" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.mk new file mode 100755 index 0000000..c0cef5f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10001/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +LD_FILES += boards/nrf51x22_256k_16k.ld diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10001/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10001/pins.csv new file mode 100755 index 0000000..659fc87 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10001/pins.csv @@ -0,0 +1,32 @@ +P0,P0 +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +UART_RTS,P8 +UART_TX,P9 +UART_CTS,P10 +UART_RX,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.h new file mode 100755 index 0000000..1061e6b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.h @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10028" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51-DK" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (21) // LED1 +#define MICROPY_HW_LED2 (22) // LED2 +#define MICROPY_HW_LED3 (23) // LED3 +#define MICROPY_HW_LED4 (24) // LED4 + +// UART config +#define MICROPY_HW_UART1_RX (11) +#define MICROPY_HW_UART1_TX (9) +#define MICROPY_HW_UART1_CTS (10) +#define MICROPY_HW_UART1_RTS (8) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (29) +#define MICROPY_HW_SPI0_MOSI (25) +#define MICROPY_HW_SPI0_MISO (28) + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.mk new file mode 100755 index 0000000..b3c8f21 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10028/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +LD_FILES += boards/nrf51x22_256k_32k.ld diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10028/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10028/pins.csv new file mode 100755 index 0000000..33f9b8e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10028/pins.csv @@ -0,0 +1,32 @@ +P0,P0 +P1,P1,ADC0_IN2 +P2,P2,ADC0_IN3 +P3,P3,ADC0_IN4 +P4,P4,ADC0_IN5 +P5,P5,ADC0_IN6 +P6,P6,ADC0_IN7 +P7,P7 +UART_RTS,P8 +UART_TX,P9 +UART_CTS,P10 +UART_RX,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.h new file mode 100755 index 0000000..6bcf215 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10031" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51-dongle" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_TRICOLOR (1) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED_RED (21) // RED +#define MICROPY_HW_LED_GREEN (22) // GREEN +#define MICROPY_HW_LED_BLUE (23) // BLUE + +// UART config +#define MICROPY_HW_UART1_RX (11) +#define MICROPY_HW_UART1_TX (9) +#define MICROPY_HW_UART1_CTS (10) +#define MICROPY_HW_UART1_RTS (8) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (15) +#define MICROPY_HW_SPI0_MOSI (16) +#define MICROPY_HW_SPI0_MISO (17) + +#define HELP_TEXT_BOARD_LED "1,2,3" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.mk new file mode 100755 index 0000000..b3c8f21 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10031/mpconfigboard.mk @@ -0,0 +1,5 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +LD_FILES += boards/nrf51x22_256k_32k.ld diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10031/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10031/pins.csv new file mode 100755 index 0000000..f700898 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10031/pins.csv @@ -0,0 +1,13 @@ +UART_RTS,P8 +UART_TX,P9 +UART_CTS,P10 +UART_RX,P11 +LED_RED,P21 +LED_GREEN,P22 +LED_BLUE,P23 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.h new file mode 100755 index 0000000..82b74d9 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10040" +#define MICROPY_HW_MCU_NAME "NRF52832" +#define MICROPY_PY_SYS_PLATFORM "nrf52-DK" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (17) // LED1 +#define MICROPY_HW_LED2 (18) // LED2 +#define MICROPY_HW_LED3 (19) // LED3 +#define MICROPY_HW_LED4 (20) // LED4 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_CTS (7) +#define MICROPY_HW_UART1_RTS (5) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (25) // (Arduino D13) +#define MICROPY_HW_SPI0_MOSI (23) // (Arduino D11) +#define MICROPY_HW_SPI0_MISO (24) // (Arduino D12) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.mk new file mode 100755 index 0000000..92fbb26 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10040/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52832 +SOFTDEV_VERSION = 6.0.0 +LD_FILES += boards/nrf52832_512k_64k.ld + +NRF_DEFINES += -DNRF52832_XXAA diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10040/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10040/pins.csv new file mode 100755 index 0000000..90bf84a --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10040/pins.csv @@ -0,0 +1,30 @@ +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.h new file mode 100755 index 0000000..e430c38 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.h @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MICROPY_HW_BOARD_NAME "PCA10056" +#define MICROPY_HW_MCU_NAME "NRF52840" +#define MICROPY_PY_SYS_PLATFORM "nrf52840-PDK" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_PWM (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (1) +#define MICROPY_HW_LED_COUNT (4) +#define MICROPY_HW_LED_PULLUP (1) + +#define MICROPY_HW_LED1 (13) // LED1 +#define MICROPY_HW_LED2 (14) // LED2 +#define MICROPY_HW_LED3 (15) // LED3 +#define MICROPY_HW_LED4 (16) // LED4 + +// UART config +#define MICROPY_HW_UART1_RX (8) +#define MICROPY_HW_UART1_TX (6) +#define MICROPY_HW_UART1_CTS (7) +#define MICROPY_HW_UART1_RTS (5) +#define MICROPY_HW_UART1_HWFC (1) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" + +#define MICROPY_HW_SPI0_SCK (47) +#define MICROPY_HW_SPI0_MOSI (45) +#define MICROPY_HW_SPI0_MISO (46) + +#define MICROPY_HW_PWM0_NAME "PWM0" +#define MICROPY_HW_PWM1_NAME "PWM1" +#define MICROPY_HW_PWM2_NAME "PWM2" +#if 0 +#define MICROPY_HW_PWM3_NAME "PWM3" +#endif + +#define HELP_TEXT_BOARD_LED "1,2,3,4" diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.mk new file mode 100755 index 0000000..866698c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10056/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52840 +SOFTDEV_VERSION = 6.0.0 +LD_FILES += boards/nrf52840_1M_256k.ld + +NRF_DEFINES += -DNRF52840_XXAA diff --git a/src/openmv/src/micropython/ports/nrf/boards/pca10056/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/pca10056/pins.csv new file mode 100755 index 0000000..e6190ba --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/pca10056/pins.csv @@ -0,0 +1,48 @@ +P0,P0 +P1,P1 +P2,P2,ADC0_IN0 +P3,P3,ADC0_IN1 +P4,P4,ADC0_IN2 +P5,P5,ADC0_IN3 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28,ADC0_IN4 +P29,P29,ADC0_IN5 +P30,P30,ADC0_IN6 +P31,P31,ADC0_IN7 +P32,P32 +P33,P33 +P34,P34 +P35,P35 +P36,P36 +P37,P37 +P38,P38 +P39,P39 +P40,P40 +P41,P41 +P42,P42 +P43,P43 +P44,P44 +P45,P45 +P46,P46 +P47,P47 diff --git a/src/openmv/src/micropython/ports/nrf/boards/s110_8.0.0.ld b/src/openmv/src/micropython/ports/nrf/boards/s110_8.0.0.ld new file mode 100755 index 0000000..b9cef15 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/s110_8.0.0.ld @@ -0,0 +1,9 @@ + +/* GNU linker script for s110 SoftDevice version 8.0.0 */ + +_sd_size = 0x00018000; +_sd_ram = 0x00002000; +_fs_size = DEFINED(_fs_size) ? _fs_size : 20K; + +_stack_size = _ram_size > 16K ? 4K : 2K; +_minimum_heap_size = 4K; diff --git a/src/openmv/src/micropython/ports/nrf/boards/s132_6.0.0.ld b/src/openmv/src/micropython/ports/nrf/boards/s132_6.0.0.ld new file mode 100755 index 0000000..044af97 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/s132_6.0.0.ld @@ -0,0 +1,4 @@ +/* GNU linker script for s132 SoftDevice version 6.0.0 */ + +_sd_size = 0x00026000; +_sd_ram = 0x000039c0; diff --git a/src/openmv/src/micropython/ports/nrf/boards/s140_6.0.0.ld b/src/openmv/src/micropython/ports/nrf/boards/s140_6.0.0.ld new file mode 100755 index 0000000..044af97 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/s140_6.0.0.ld @@ -0,0 +1,4 @@ +/* GNU linker script for s132 SoftDevice version 6.0.0 */ + +_sd_size = 0x00026000; +_sd_ram = 0x000039c0; diff --git a/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.h b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.h new file mode 100755 index 0000000..4bc2b15 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Datasheet for board: +// https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf +#define MICROPY_HW_BOARD_NAME "WT51822-S4AT" +#define MICROPY_HW_MCU_NAME "NRF51822" +#define MICROPY_PY_SYS_PLATFORM "nrf51" + +#define MICROPY_PY_MACHINE_UART (1) +#define MICROPY_PY_MACHINE_HW_SPI (1) +#define MICROPY_PY_MACHINE_TIMER (1) +#define MICROPY_PY_MACHINE_RTCOUNTER (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_ADC (1) +#define MICROPY_PY_MACHINE_TEMP (1) +#define MICROPY_PY_RANDOM_HW_RNG (1) + +#define MICROPY_HW_HAS_LED (0) + +// UART config +#define MICROPY_HW_UART1_RX (1) +#define MICROPY_HW_UART1_TX (2) +#define MICROPY_HW_UART1_HWFC (0) + +// SPI0 config +#define MICROPY_HW_SPI0_NAME "SPI0" +#define MICROPY_HW_SPI0_SCK (9) +#define MICROPY_HW_SPI0_MOSI (10) +#define MICROPY_HW_SPI0_MISO (13) diff --git a/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk new file mode 100755 index 0000000..515de07 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = m0 +MCU_VARIANT = nrf51 +MCU_SUB_VARIANT = nrf51822 +SOFTDEV_VERSION = 8.0.0 +LD_FILES += boards/nrf51x22_256k_16k.ld + +CFLAGS += -DBLUETOOTH_LFCLK_RC diff --git a/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/pins.csv b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/pins.csv new file mode 100755 index 0000000..ae98cb7 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/boards/wt51822_s4at/pins.csv @@ -0,0 +1,7 @@ +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P9,P9 +P10,P10 +P13,P13 diff --git a/src/openmv/src/micropython/ports/nrf/device/startup_nrf51822.c b/src/openmv/src/micropython/ports/nrf/device/startup_nrf51822.c new file mode 100755 index 0000000..2f15f0f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/device/startup_nrf51822.c @@ -0,0 +1,151 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +extern uint32_t _estack; +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; + +typedef void (*func)(void); + +extern void _start(void) __attribute__((noreturn)); +extern void SystemInit(void); + +void Default_Handler(void) { + while (1); +} + +void Reset_Handler(void) { + uint32_t * ram_on_addr = (uint32_t *)0x40000524; + uint32_t * ram_on_b_addr = (uint32_t *)0x40000554; + // RAM on in on-mode + *ram_on_addr = 3; // block 0 and 1 + *ram_on_b_addr = 3; // block 2 and 3 +#if 0 + // RAM on in off-mode + ram_on_addr = 1 << 16; + ram_on_b_addr = 1 << 17; +#endif + + uint32_t * p_src = &_sidata; + uint32_t * p_dest = &_sdata; + + while (p_dest < &_edata) { + *p_dest++ = *p_src++; + } + + uint32_t * p_bss = &_sbss; + uint32_t * p_bss_end = &_ebss; + while (p_bss < p_bss_end) { + *p_bss++ = 0ul; + } + + SystemInit(); + _start(); +} + +void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void HardFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); + +void POWER_CLOCK_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RADIO_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UART0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPI0_TWI0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPI1_TWI1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void GPIOTE_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void ADC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TEMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RNG_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void ECB_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void CCM_AAR_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void WDT_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void QDEC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void LPCOMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI4_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI5_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); + +const func __Vectors[] __attribute__ ((section(".isr_vector"),used)) = { + (func)&_estack, + Reset_Handler, + NMI_Handler, + HardFault_Handler, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + SVC_Handler, + 0, + 0, + PendSV_Handler, + SysTick_Handler, + + /* External Interrupts */ + POWER_CLOCK_IRQHandler, + RADIO_IRQHandler, + UART0_IRQHandler, + SPI0_TWI0_IRQHandler, + SPI1_TWI1_IRQHandler, + 0, + GPIOTE_IRQHandler, + ADC_IRQHandler, + TIMER0_IRQHandler, + TIMER1_IRQHandler, + TIMER2_IRQHandler, + RTC0_IRQHandler, + TEMP_IRQHandler, + RNG_IRQHandler, + ECB_IRQHandler, + CCM_AAR_IRQHandler, + WDT_IRQHandler, + RTC1_IRQHandler, + QDEC_IRQHandler, + LPCOMP_IRQHandler, + SWI0_IRQHandler, + SWI1_IRQHandler, + SWI2_IRQHandler, + SWI3_IRQHandler, + SWI4_IRQHandler, + SWI5_IRQHandler +}; diff --git a/src/openmv/src/micropython/ports/nrf/device/startup_nrf52832.c b/src/openmv/src/micropython/ports/nrf/device/startup_nrf52832.c new file mode 100755 index 0000000..6eafcc2 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/device/startup_nrf52832.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +extern uint32_t _estack; +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; + +typedef void (*func)(void); + +extern void _start(void) __attribute__((noreturn)); +extern void SystemInit(void); + +void Default_Handler(void) { + while (1); +} + +void Reset_Handler(void) { + uint32_t * p_src = &_sidata; + uint32_t * p_dest = &_sdata; + + while (p_dest < &_edata) { + *p_dest++ = *p_src++; + } + + uint32_t * p_bss = &_sbss; + uint32_t * p_bss_end = &_ebss; + while (p_bss < p_bss_end) { + *p_bss++ = 0ul; + } + + SystemInit(); + _start(); +} + +void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void HardFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void MemoryManagement_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void BusFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UsageFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void DebugMon_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); + +void POWER_CLOCK_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RADIO_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UARTE0_UART0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void NFCT_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void GPIOTE_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SAADC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TEMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RNG_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void ECB_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void CCM_AAR_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void WDT_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void QDEC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void COMP_LPCOMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI0_EGU0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI1_EGU1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI2_EGU2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI3_EGU3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI4_EGU4_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI5_EGU5_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER4_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PDM_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void MWU_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM2_SPIS2_SPI2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void I2S_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); + +const func __Vectors[] __attribute__ ((section(".isr_vector"),used)) = { + (func)&_estack, + Reset_Handler, + NMI_Handler, + HardFault_Handler, + MemoryManagement_Handler, + BusFault_Handler, + UsageFault_Handler, + 0, + 0, + 0, + 0, + SVC_Handler, + DebugMon_Handler, + 0, + PendSV_Handler, + SysTick_Handler, + + /* External Interrupts */ + POWER_CLOCK_IRQHandler, + RADIO_IRQHandler, + UARTE0_UART0_IRQHandler, + SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler, + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler, + NFCT_IRQHandler, + GPIOTE_IRQHandler, + SAADC_IRQHandler, + TIMER0_IRQHandler, + TIMER1_IRQHandler, + TIMER2_IRQHandler, + RTC0_IRQHandler, + TEMP_IRQHandler, + RNG_IRQHandler, + ECB_IRQHandler, + CCM_AAR_IRQHandler, + WDT_IRQHandler, + RTC1_IRQHandler, + QDEC_IRQHandler, + COMP_LPCOMP_IRQHandler, + SWI0_EGU0_IRQHandler, + SWI1_EGU1_IRQHandler, + SWI2_EGU2_IRQHandler, + SWI3_EGU3_IRQHandler, + SWI4_EGU4_IRQHandler, + SWI5_EGU5_IRQHandler, + TIMER3_IRQHandler, + TIMER4_IRQHandler, + PWM0_IRQHandler, + PDM_IRQHandler, + 0, + 0, + MWU_IRQHandler, + PWM1_IRQHandler, + PWM2_IRQHandler, + SPIM2_SPIS2_SPI2_IRQHandler, + RTC2_IRQHandler, + I2S_IRQHandler +}; diff --git a/src/openmv/src/micropython/ports/nrf/device/startup_nrf52840.c b/src/openmv/src/micropython/ports/nrf/device/startup_nrf52840.c new file mode 100755 index 0000000..0935d7d --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/device/startup_nrf52840.c @@ -0,0 +1,182 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +extern uint32_t _estack; +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; + +typedef void (*func)(void); + +extern void _start(void) __attribute__((noreturn)); +extern void SystemInit(void); + +void Default_Handler(void) { + while (1); +} + +void Reset_Handler(void) { + uint32_t * p_src = &_sidata; + uint32_t * p_dest = &_sdata; + + while (p_dest < &_edata) { + *p_dest++ = *p_src++; + } + + uint32_t * p_bss = &_sbss; + uint32_t * p_bss_end = &_ebss; + while (p_bss < p_bss_end) { + *p_bss++ = 0ul; + } + + SystemInit(); + _start(); +} + +void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void HardFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void MemoryManagement_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void BusFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UsageFault_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void DebugMon_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler"))); + +void POWER_CLOCK_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RADIO_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UARTE0_UART0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void NFCT_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void GPIOTE_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SAADC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TEMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RNG_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void ECB_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void CCM_AAR_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void WDT_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void QDEC_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void COMP_LPCOMP_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI0_EGU0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI1_EGU1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI2_EGU2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI3_EGU3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI4_EGU4_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SWI5_EGU5_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void TIMER4_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM0_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PDM_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void MWU_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM2_SPIS2_SPI2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void RTC2_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void I2S_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void FPU_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void USBD_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void UARTE1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void QSPI_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void CRYPTOCELL_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void SPIM3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); +void PWM3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); + +const func __Vectors[] __attribute__ ((section(".isr_vector"),used)) = { + (func)&_estack, + Reset_Handler, + NMI_Handler, + HardFault_Handler, + MemoryManagement_Handler, + BusFault_Handler, + UsageFault_Handler, + 0, + 0, + 0, + 0, + SVC_Handler, + DebugMon_Handler, + 0, + PendSV_Handler, + SysTick_Handler, + + /* External Interrupts */ + POWER_CLOCK_IRQHandler, + RADIO_IRQHandler, + UARTE0_UART0_IRQHandler, + SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler, + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler, + NFCT_IRQHandler, + GPIOTE_IRQHandler, + SAADC_IRQHandler, + TIMER0_IRQHandler, + TIMER1_IRQHandler, + TIMER2_IRQHandler, + RTC0_IRQHandler, + TEMP_IRQHandler, + RNG_IRQHandler, + ECB_IRQHandler, + CCM_AAR_IRQHandler, + WDT_IRQHandler, + RTC1_IRQHandler, + QDEC_IRQHandler, + COMP_LPCOMP_IRQHandler, + SWI0_EGU0_IRQHandler, + SWI1_EGU1_IRQHandler, + SWI2_EGU2_IRQHandler, + SWI3_EGU3_IRQHandler, + SWI4_EGU4_IRQHandler, + SWI5_EGU5_IRQHandler, + TIMER3_IRQHandler, + TIMER4_IRQHandler, + PWM0_IRQHandler, + PDM_IRQHandler, + 0, + 0, + MWU_IRQHandler, + PWM1_IRQHandler, + PWM2_IRQHandler, + SPIM2_SPIS2_SPI2_IRQHandler, + RTC2_IRQHandler, + I2S_IRQHandler, + FPU_IRQHandler, + USBD_IRQHandler, + UARTE1_IRQHandler, + QSPI_IRQHandler, + CRYPTOCELL_IRQHandler, + SPIM3_IRQHandler, + 0, + PWM3_IRQHandler, +}; diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.c b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.c new file mode 100755 index 0000000..f18a571 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.c @@ -0,0 +1,1181 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if BLUETOOTH_SD + +#include +#include +#include + +#include "py/runtime.h" +#include "ble_drv.h" +#include "mpconfigport.h" +#include "nrf_sdm.h" +#include "ble_gap.h" +#include "ble.h" // sd_ble_uuid_encode +#include "drivers/flash.h" +#include "mphalport.h" + + +#define BLE_DRIVER_VERBOSE 0 + +#if BLE_DRIVER_VERBOSE + #define BLE_DRIVER_LOG printf +#else + #define BLE_DRIVER_LOG(...) +#endif + +#define BLE_ADV_LENGTH_FIELD_SIZE 1 +#define BLE_ADV_AD_TYPE_FIELD_SIZE 1 +#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 + +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) +#define UNIT_0_625_MS (625) +#define UNIT_10_MS (10000) +#define APP_CFG_NON_CONN_ADV_TIMEOUT 0 // Disable timeout. +#define NON_CONNECTABLE_ADV_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS) + +#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_0_625_MS) +#define BLE_SLAVE_LATENCY 0 +#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) + +#if (BLUETOOTH_SD == 110) + #define MAX_TX_IN_PROGRESS (6) +#else + #define MAX_TX_IN_PROGRESS (10) +#endif +#if !defined(GATT_MTU_SIZE_DEFAULT) && defined(BLE_GATT_ATT_MTU_DEFAULT) + #define GATT_MTU_SIZE_DEFAULT BLE_GATT_ATT_MTU_DEFAULT +#endif + +#define SD_TEST_OR_ENABLE() \ +if (ble_drv_stack_enabled() == 0) { \ + (void)ble_drv_stack_enable(); \ +} + +static volatile bool m_adv_in_progress; +static volatile uint8_t m_tx_in_progress; + +static ble_drv_gap_evt_callback_t gap_event_handler; +static ble_drv_gatts_evt_callback_t gatts_event_handler; + +static mp_obj_t mp_gap_observer; +static mp_obj_t mp_gatts_observer; + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) +static volatile bool m_primary_service_found; +static volatile bool m_characteristic_found; +static volatile bool m_write_done; + +static volatile ble_drv_adv_evt_callback_t adv_event_handler; +static volatile ble_drv_gattc_evt_callback_t gattc_event_handler; +static volatile ble_drv_disc_add_service_callback_t disc_add_service_handler; +static volatile ble_drv_disc_add_char_callback_t disc_add_char_handler; +static volatile ble_drv_gattc_char_data_callback_t gattc_char_data_handle; + +static mp_obj_t mp_adv_observer; +static mp_obj_t mp_gattc_observer; +static mp_obj_t mp_gattc_disc_service_observer; +static mp_obj_t mp_gattc_disc_char_observer; +static mp_obj_t mp_gattc_char_data_observer; +#endif + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) +#include "nrf_nvic.h" +#define BLE_GAP_ADV_MAX_SIZE 31 +#define BLE_DRV_CONN_CONFIG_TAG 1 + +static uint8_t m_adv_handle; +static uint8_t m_scan_buffer[BLE_GAP_SCAN_BUFFER_MIN]; + +nrf_nvic_state_t nrf_nvic_state = {0}; +#endif + +#if (BLUETOOTH_SD == 110) +void softdevice_assert_handler(uint32_t pc, uint16_t line_number, const uint8_t * p_file_name) { + BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!"); +} +#else +void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { + BLE_DRIVER_LOG("ERROR: SoftDevice assert!!!"); +} +#endif + +uint32_t ble_drv_stack_enable(void) { + m_adv_in_progress = false; + m_tx_in_progress = 0; + +#if (BLUETOOTH_SD == 110) + #if BLUETOOTH_LFCLK_RC + uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION, + softdevice_assert_handler); + #else + uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, + softdevice_assert_handler); + #endif // BLUETOOTH_LFCLK_RC +#endif // (BLUETOOTH_SD == 110) + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + #if BLUETOOTH_LFCLK_RC + nrf_clock_lf_cfg_t clock_config = { + .source = NRF_CLOCK_LF_SRC_RC, + .rc_ctiv = 16, + .rc_temp_ctiv = 2, + .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM + }; + #else + nrf_clock_lf_cfg_t clock_config = { + .source = NRF_CLOCK_LF_SRC_XTAL, + .rc_ctiv = 0, + .rc_temp_ctiv = 0, + .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM + }; + #endif // BLUETOOTH_LFCLK_RC + + uint32_t err_code = sd_softdevice_enable(&clock_config, + softdevice_assert_handler); +#endif // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + + BLE_DRIVER_LOG("SoftDevice enable status: " UINT_FMT "\n", (uint16_t)err_code); + + err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); + + BLE_DRIVER_LOG("IRQ enable status: " UINT_FMT "\n", (uint16_t)err_code); + +#if (BLUETOOTH_SD == 110) + ble_enable_params_t ble_enable_params; + memset(&ble_enable_params, 0x00, sizeof(ble_enable_params)); + ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT; + ble_enable_params.gatts_enable_params.service_changed = 0; +#else + ble_cfg_t ble_conf; + uint32_t app_ram_start_cfg = 0x200039c0; + ble_conf.conn_cfg.conn_cfg_tag = BLE_DRV_CONN_CONFIG_TAG; + ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = 2; + ble_conf.conn_cfg.params.gap_conn_cfg.event_length = 3; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start_cfg); + + BLE_DRIVER_LOG("BLE_CONN_CFG_GAP status: " UINT_FMT "\n", (uint16_t)err_code); + + memset(&ble_conf, 0, sizeof(ble_conf)); + + ble_conf.gap_cfg.role_count_cfg.periph_role_count = 1; + ble_conf.gap_cfg.role_count_cfg.central_role_count = 1; + ble_conf.gap_cfg.role_count_cfg.central_sec_count = 0; + err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start_cfg); + + BLE_DRIVER_LOG("BLE_GAP_CFG_ROLE_COUNT status: " UINT_FMT "\n", (uint16_t)err_code); + + memset(&ble_conf, 0, sizeof(ble_conf)); + ble_conf.conn_cfg.conn_cfg_tag = BLE_DRV_CONN_CONFIG_TAG; + ble_conf.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = MAX_TX_IN_PROGRESS; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &ble_conf, app_ram_start_cfg); + + BLE_DRIVER_LOG("BLE_CONN_CFG_GATTS status: " UINT_FMT "\n", (uint16_t)err_code); +#endif + +#if (BLUETOOTH_SD == 110) + err_code = sd_ble_enable(&ble_enable_params); +#else + uint32_t app_ram_start = 0x200039c0; + err_code = sd_ble_enable(&app_ram_start); // 8K SD headroom from linker script. + BLE_DRIVER_LOG("BLE ram size: " UINT_FMT "\n", (uint16_t)app_ram_start); +#endif + + BLE_DRIVER_LOG("BLE enable status: " UINT_FMT "\n", (uint16_t)err_code); + + // set up security mode + ble_gap_conn_params_t gap_conn_params; + ble_gap_conn_sec_mode_t sec_mode; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + const char device_name[] = "micr"; + + if ((err_code = sd_ble_gap_device_name_set(&sec_mode, + (const uint8_t *)device_name, + strlen(device_name))) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Cannot apply GAP parameters.")); + } + + // set connection parameters + memset(&gap_conn_params, 0, sizeof(gap_conn_params)); + + gap_conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL; + gap_conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL; + gap_conn_params.slave_latency = BLE_SLAVE_LATENCY; + gap_conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT; + + if (sd_ble_gap_ppcp_set(&gap_conn_params) != 0) { + + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Cannot set PPCP parameters.")); + } + + return err_code; +} + +void ble_drv_stack_disable(void) { + sd_softdevice_disable(); +} + +uint8_t ble_drv_stack_enabled(void) { + uint8_t is_enabled; + uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); + (void)err_code; + + BLE_DRIVER_LOG("Is enabled status: " UINT_FMT "\n", (uint16_t)err_code); + + return is_enabled; +} + +void ble_drv_address_get(ble_drv_addr_t * p_addr) { + SD_TEST_OR_ENABLE(); + + ble_gap_addr_t local_ble_addr; +#if (BLUETOOTH_SD == 110) + uint32_t err_code = sd_ble_gap_address_get(&local_ble_addr); +#else + uint32_t err_code = sd_ble_gap_addr_get(&local_ble_addr); +#endif + + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not query for the device address.")); + } + + BLE_DRIVER_LOG("ble address, type: " HEX2_FMT ", " \ + "address: " HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT ":" \ + HEX2_FMT ":" HEX2_FMT ":" HEX2_FMT "\n", \ + local_ble_addr.addr_type, \ + local_ble_addr.addr[5], local_ble_addr.addr[4], local_ble_addr.addr[3], \ + local_ble_addr.addr[2], local_ble_addr.addr[1], local_ble_addr.addr[0]); + + p_addr->addr_type = local_ble_addr.addr_type; + memcpy(p_addr->addr, local_ble_addr.addr, 6); +} + +bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx) { + SD_TEST_OR_ENABLE(); + + if (sd_ble_uuid_vs_add((ble_uuid128_t const *)p_uuid, idx) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not add Vendor Specific 128-bit UUID.")); + } + + return true; +} + +bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj) { + SD_TEST_OR_ENABLE(); + + if (p_service_obj->p_uuid->type > BLE_UUID_TYPE_BLE) { + + ble_uuid_t uuid; + uuid.type = p_service_obj->p_uuid->uuid_vs_idx; + uuid.uuid = p_service_obj->p_uuid->value[0]; + uuid.uuid += p_service_obj->p_uuid->value[1] << 8; + + if (sd_ble_gatts_service_add(p_service_obj->type, + &uuid, + &p_service_obj->handle) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not add Service.")); + } + } else if (p_service_obj->p_uuid->type == BLE_UUID_TYPE_BLE) { + BLE_DRIVER_LOG("adding service\n"); + + ble_uuid_t uuid; + uuid.type = p_service_obj->p_uuid->type; + uuid.uuid = p_service_obj->p_uuid->value[0]; + uuid.uuid += p_service_obj->p_uuid->value[1] << 8; + + if (sd_ble_gatts_service_add(p_service_obj->type, + &uuid, + &p_service_obj->handle) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not add Service.")); + } + } + return true; +} + +bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj) { + ble_gatts_char_md_t char_md; + ble_gatts_attr_md_t cccd_md; + ble_gatts_attr_t attr_char_value; + ble_uuid_t uuid; + ble_gatts_attr_md_t attr_md; + + memset(&char_md, 0, sizeof(char_md)); + + char_md.char_props.broadcast = (p_char_obj->props & UBLUEPY_PROP_BROADCAST) ? 1 : 0; + char_md.char_props.read = (p_char_obj->props & UBLUEPY_PROP_READ) ? 1 : 0; + char_md.char_props.write_wo_resp = (p_char_obj->props & UBLUEPY_PROP_WRITE_WO_RESP) ? 1 : 0; + char_md.char_props.write = (p_char_obj->props & UBLUEPY_PROP_WRITE) ? 1 : 0; + char_md.char_props.notify = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0; + char_md.char_props.indicate = (p_char_obj->props & UBLUEPY_PROP_INDICATE) ? 1 : 0; +#if 0 + char_md.char_props.auth_signed_wr = (p_char_obj->props & UBLUEPY_PROP_NOTIFY) ? 1 : 0; +#endif + + + char_md.p_char_user_desc = NULL; + char_md.p_char_pf = NULL; + char_md.p_user_desc_md = NULL; + char_md.p_sccd_md = NULL; + + // if cccd + if (p_char_obj->attrs & UBLUEPY_ATTR_CCCD) { + memset(&cccd_md, 0, sizeof(cccd_md)); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); + cccd_md.vloc = BLE_GATTS_VLOC_STACK; + char_md.p_cccd_md = &cccd_md; + } else { + char_md.p_cccd_md = NULL; + } + + uuid.type = p_char_obj->p_uuid->type; + uuid.uuid = p_char_obj->p_uuid->value[0]; + uuid.uuid += p_char_obj->p_uuid->value[1] << 8; + + memset(&attr_md, 0, sizeof(attr_md)); + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + + attr_md.vloc = BLE_GATTS_VLOC_STACK; + attr_md.rd_auth = 0; + attr_md.wr_auth = 0; + attr_md.vlen = 1; + + memset(&attr_char_value, 0, sizeof(attr_char_value)); + + attr_char_value.p_uuid = &uuid; + attr_char_value.p_attr_md = &attr_md; + attr_char_value.init_len = sizeof(uint8_t); + attr_char_value.init_offs = 0; + attr_char_value.max_len = (GATT_MTU_SIZE_DEFAULT - 3); + + ble_gatts_char_handles_t handles; + + if (sd_ble_gatts_characteristic_add(p_char_obj->service_handle, + &char_md, + &attr_char_value, + &handles) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not add Characteristic.")); + } + + // apply handles to object instance + p_char_obj->handle = handles.value_handle; + p_char_obj->user_desc_handle = handles.user_desc_handle; + p_char_obj->cccd_handle = handles.cccd_handle; + p_char_obj->sccd_handle = handles.sccd_handle; + + return true; +} + +bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) { + SD_TEST_OR_ENABLE(); + + uint8_t byte_pos = 0; + + uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE]; + + if (p_adv_params->device_name_len > 0) { + ble_gap_conn_sec_mode_t sec_mode; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + if (sd_ble_gap_device_name_set(&sec_mode, + p_adv_params->p_device_name, + p_adv_params->device_name_len) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not apply device name in the stack.")); + } + + BLE_DRIVER_LOG("Device name applied\n"); + + adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + p_adv_params->device_name_len); + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + adv_data[byte_pos] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; + byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; + memcpy(&adv_data[byte_pos], p_adv_params->p_device_name, p_adv_params->device_name_len); + // increment position counter to see if it fits, and in case more content should + // follow in this adv packet. + byte_pos += p_adv_params->device_name_len; + } + + // Add FLAGS only if manually controlled data has not been used. + if (p_adv_params->data_len == 0) { + // set flags, default to disc mode + adv_data[byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + BLE_AD_TYPE_FLAGS_DATA_SIZE); + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + adv_data[byte_pos] = BLE_GAP_AD_TYPE_FLAGS; + byte_pos += BLE_AD_TYPE_FLAGS_DATA_SIZE; + adv_data[byte_pos] = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; + byte_pos += 1; + } + + if (p_adv_params->num_of_services > 0) { + + bool type_16bit_present = false; + bool type_128bit_present = false; + + for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { + ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; + if (p_service->p_uuid->type == UBLUEPY_UUID_16_BIT) { + type_16bit_present = true; + } + + if (p_service->p_uuid->type == UBLUEPY_UUID_128_BIT) { + type_128bit_present = true; + } + } + + if (type_16bit_present) { + uint8_t size_byte_pos = byte_pos; + + // skip length byte for now, apply total length post calculation + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + + adv_data[byte_pos] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE; + byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; + + uint8_t uuid_total_size = 0; + uint8_t encoded_size = 0; + + for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { + ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; + + ble_uuid_t uuid; + uuid.type = p_service->p_uuid->type; + uuid.uuid = p_service->p_uuid->value[0]; + uuid.uuid += p_service->p_uuid->value[1] << 8; + // calculate total size of uuids + if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not encode UUID, to check length.")); + } + + // do encoding into the adv buffer + if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can encode UUID into the advertisment packet.")); + } + + BLE_DRIVER_LOG("encoded uuid for service %u: ", 0); + for (uint8_t j = 0; j < encoded_size; j++) { + BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]); + } + BLE_DRIVER_LOG("\n"); + + uuid_total_size += encoded_size; // size of entry + byte_pos += encoded_size; // relative to adv data packet + BLE_DRIVER_LOG("ADV: uuid size: %u, type: %u, uuid: %x%x, vs_idx: %u\n", + encoded_size, p_service->p_uuid->type, + p_service->p_uuid->value[1], + p_service->p_uuid->value[0], + p_service->p_uuid->uuid_vs_idx); + } + + adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); + } + + if (type_128bit_present) { + uint8_t size_byte_pos = byte_pos; + + // skip length byte for now, apply total length post calculation + byte_pos += BLE_ADV_LENGTH_FIELD_SIZE; + + adv_data[byte_pos] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE; + byte_pos += BLE_ADV_AD_TYPE_FIELD_SIZE; + + uint8_t uuid_total_size = 0; + uint8_t encoded_size = 0; + + for (uint8_t i = 0; i < p_adv_params->num_of_services; i++) { + ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)p_adv_params->p_services[i]; + + ble_uuid_t uuid; + uuid.type = p_service->p_uuid->uuid_vs_idx; + uuid.uuid = p_service->p_uuid->value[0]; + uuid.uuid += p_service->p_uuid->value[1] << 8; + + // calculate total size of uuids + if (sd_ble_uuid_encode(&uuid, &encoded_size, NULL) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not encode UUID, to check length.")); + } + + // do encoding into the adv buffer + if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can encode UUID into the advertisment packet.")); + } + + BLE_DRIVER_LOG("encoded uuid for service %u: ", 0); + for (uint8_t j = 0; j < encoded_size; j++) { + BLE_DRIVER_LOG(HEX2_FMT " ", adv_data[byte_pos + j]); + } + BLE_DRIVER_LOG("\n"); + + uuid_total_size += encoded_size; // size of entry + byte_pos += encoded_size; // relative to adv data packet + BLE_DRIVER_LOG("ADV: uuid size: %u, type: %x%x, uuid: %u, vs_idx: %u\n", + encoded_size, p_service->p_uuid->type, + p_service->p_uuid->value[1], + p_service->p_uuid->value[0], + p_service->p_uuid->uuid_vs_idx); + } + + adv_data[size_byte_pos] = (BLE_ADV_AD_TYPE_FIELD_SIZE + uuid_total_size); + } + } + + if ((p_adv_params->data_len > 0) && (p_adv_params->p_data != NULL)) { + if (p_adv_params->data_len + byte_pos > BLE_GAP_ADV_MAX_SIZE) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not fit data into the advertisment packet.")); + } + + memcpy(adv_data, p_adv_params->p_data, p_adv_params->data_len); + byte_pos += p_adv_params->data_len; + } + + // scan response data not set + uint32_t err_code; +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + const ble_gap_adv_data_t m_adv_data = { + .adv_data.p_data = adv_data, + .adv_data.len = byte_pos, + .scan_rsp_data.p_data = NULL, + .scan_rsp_data.len = 0 + }; +#endif + + static ble_gap_adv_params_t m_adv_params; + memset(&m_adv_params, 0, sizeof(m_adv_params)); + + // initialize advertising params + if (p_adv_params->connectable) { +#if (BLUETOOTH_SD == 110) + m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; +#else + m_adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; +#endif + } else { +#if (BLUETOOTH_SD == 110) + m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; +#else + m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED; +#endif + } + +#if (BLUETOOTH_SD == 110) + m_adv_params.fp = BLE_GAP_ADV_FP_ANY; + m_adv_params.timeout = 0; // infinite advertisment +#else + m_adv_params.properties.anonymous = 0; + m_adv_params.properties.include_tx_power = 0; + m_adv_params.filter_policy = 0; + m_adv_params.max_adv_evts = 0; // infinite advertisment + m_adv_params.primary_phy = BLE_GAP_PHY_AUTO; + m_adv_params.secondary_phy = BLE_GAP_PHY_AUTO; + m_adv_params.scan_req_notification = 0; // Do not raise scan request notifications when scanned. +#endif + m_adv_params.p_peer_addr = NULL; // undirected advertisement + m_adv_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); // approx 8 ms + +#if (BLUETOOTH_SD == 110) + if ((err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not apply advertisment data. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +#else + if ((err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not apply advertisment data. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +#endif + BLE_DRIVER_LOG("Set Adv data size: " UINT_FMT "\n", byte_pos); + + ble_drv_advertise_stop(); + +#if (BLUETOOTH_SD == 110) + err_code = sd_ble_gap_adv_start(&m_adv_params); +#else + uint8_t conf_tag = BLE_DRV_CONN_CONFIG_TAG; // Could also be set to tag from sd_ble_cfg_set + err_code = sd_ble_gap_adv_start(m_adv_handle, conf_tag); +#endif + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not start advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + + m_adv_in_progress = true; + + return true; +} + +void ble_drv_advertise_stop(void) { + if (m_adv_in_progress == true) { + uint32_t err_code; + +#if (BLUETOOTH_SD == 110) + if ((err_code = sd_ble_gap_adv_stop()) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not stop advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +#else + if ((err_code = sd_ble_gap_adv_stop(m_adv_handle)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not stop advertisment. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +#endif + } + m_adv_in_progress = false; +} + +void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { + ble_gatts_value_t gatts_value; + memset(&gatts_value, 0, sizeof(gatts_value)); + + gatts_value.len = len; + gatts_value.offset = 0; + gatts_value.p_value = p_data; + + uint32_t err_code = sd_ble_gatts_value_get(conn_handle, + handle, + &gatts_value); + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + +} + +void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { + ble_gatts_value_t gatts_value; + memset(&gatts_value, 0, sizeof(gatts_value)); + + gatts_value.len = len; + gatts_value.offset = 0; + gatts_value.p_value = p_data; + + uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value); + + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +} + +void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data) { + uint16_t hvx_len = len; + ble_gatts_hvx_params_t hvx_params; + + memset(&hvx_params, 0, sizeof(hvx_params)); + + hvx_params.handle = handle; + hvx_params.type = BLE_GATT_HVX_NOTIFICATION; + hvx_params.offset = 0; + hvx_params.p_len = &hvx_len; + hvx_params.p_data = p_data; + + while (m_tx_in_progress > MAX_TX_IN_PROGRESS) { + ; + } + + BLE_DRIVER_LOG("Request TX, m_tx_in_progress: %u\n", m_tx_in_progress); + uint32_t err_code; + if ((err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not notify attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + m_tx_in_progress++; + BLE_DRIVER_LOG("Queued TX, m_tx_in_progress: %u\n", m_tx_in_progress); +} + +void ble_drv_gap_event_handler_set(mp_obj_t obj, ble_drv_gap_evt_callback_t evt_handler) { + mp_gap_observer = obj; + gap_event_handler = evt_handler; +} + +void ble_drv_gatts_event_handler_set(mp_obj_t obj, ble_drv_gatts_evt_callback_t evt_handler) { + mp_gatts_observer = obj; + gatts_event_handler = evt_handler; +} + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + +void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler) { + mp_gattc_observer = obj; + gattc_event_handler = evt_handler; +} + +void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler) { + mp_adv_observer = obj; + adv_event_handler = evt_handler; +} + + +void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, ble_drv_gattc_char_data_callback_t cb) { + + mp_gattc_char_data_observer = obj; + gattc_char_data_handle = cb; + + uint32_t err_code = sd_ble_gattc_read(conn_handle, + handle, + 0); + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not read attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + + while (gattc_char_data_handle != NULL) { + ; + } +} + +void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response) { + + ble_gattc_write_params_t write_params; + + if (w_response) { + write_params.write_op = BLE_GATT_OP_WRITE_REQ; + } else { + write_params.write_op = BLE_GATT_OP_WRITE_CMD; + } + + write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL; + write_params.handle = handle; + write_params.offset = 0; + write_params.len = len; + write_params.p_value = p_data; + + m_write_done = !w_response; + + uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + + if (err_code != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not write attribute value. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } + + while (m_write_done != true) { + ; + } +} + +void ble_drv_scan_start(bool cont) { + SD_TEST_OR_ENABLE(); + + ble_gap_scan_params_t scan_params; + memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); + scan_params.extended = 0; + scan_params.active = 1; + scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.timeout = 0; // Infinite + + ble_data_t scan_buffer = { + .p_data = m_scan_buffer, + .len = BLE_GAP_SCAN_BUFFER_MIN + }; + + uint32_t err_code; + ble_gap_scan_params_t * p_scan_params = &scan_params; + if (cont) { + p_scan_params = NULL; + } + if ((err_code = sd_ble_gap_scan_start(p_scan_params, &scan_buffer)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not start scanning. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +} + +void ble_drv_scan_stop(void) { + sd_ble_gap_scan_stop(); +} + +void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type) { + SD_TEST_OR_ENABLE(); + + ble_gap_scan_params_t scan_params; + memset(&scan_params, 0, sizeof(ble_gap_scan_params_t)); + scan_params.extended = 0; + scan_params.active = 1; + scan_params.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.window = MSEC_TO_UNITS(100, UNIT_0_625_MS); + scan_params.timeout = 0; // infinite + + ble_gap_addr_t addr; + memset(&addr, 0, sizeof(addr)); + + addr.addr_type = addr_type; + memcpy(addr.addr, p_addr, 6); + + BLE_DRIVER_LOG("GAP CONNECTING: "HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT":"HEX2_FMT", type: %d\n", + addr.addr[0], addr.addr[1], addr.addr[2], addr.addr[3], addr.addr[4], addr.addr[5], addr.addr_type); + + ble_gap_conn_params_t conn_params; + + // set connection parameters + memset(&conn_params, 0, sizeof(conn_params)); + + conn_params.min_conn_interval = BLE_MIN_CONN_INTERVAL; + conn_params.max_conn_interval = BLE_MAX_CONN_INTERVAL; + conn_params.slave_latency = BLE_SLAVE_LATENCY; + conn_params.conn_sup_timeout = BLE_CONN_SUP_TIMEOUT; + + uint8_t conn_tag = BLE_DRV_CONN_CONFIG_TAG; + + uint32_t err_code; + if ((err_code = sd_ble_gap_connect(&addr, + &scan_params, + &conn_params, + conn_tag)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "Can not connect. status: 0x" HEX2_FMT, (uint16_t)err_code)); + } +} + +bool ble_drv_discover_services(mp_obj_t obj, uint16_t conn_handle, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb) { + BLE_DRIVER_LOG("Discover primary services. Conn handle: 0x" HEX2_FMT "\n", + conn_handle); + + mp_gattc_disc_service_observer = obj; + disc_add_service_handler = cb; + + m_primary_service_found = false; + + uint32_t err_code; + err_code = sd_ble_gattc_primary_services_discover(conn_handle, + start_handle, + NULL); + if (err_code != 0) { + return false; + } + + // busy loop until last service has been iterated + while (disc_add_service_handler != NULL) { + ; + } + + if (m_primary_service_found) { + return true; + } else { + return false; + } +} + +bool ble_drv_discover_characteristic(mp_obj_t obj, + uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + ble_drv_disc_add_char_callback_t cb) { + BLE_DRIVER_LOG("Discover characteristicts. Conn handle: 0x" HEX2_FMT "\n", + conn_handle); + + mp_gattc_disc_char_observer = obj; + disc_add_char_handler = cb; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + m_characteristic_found = false; + + uint32_t err_code; + err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + if (err_code != 0) { + return false; + } + + // busy loop until last service has been iterated + while (disc_add_char_handler != NULL) { + ; + } + + if (m_characteristic_found) { + return true; + } else { + return false; + } +} + +void ble_drv_discover_descriptors(void) { + +} + +#endif // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + +static void sd_evt_handler(uint32_t evt_id) { + switch (evt_id) { +#if MICROPY_MBFS + case NRF_EVT_FLASH_OPERATION_SUCCESS: + flash_operation_finished(FLASH_STATE_SUCCESS); + break; + case NRF_EVT_FLASH_OPERATION_ERROR: + flash_operation_finished(FLASH_STATE_ERROR); + break; +#endif + default: + // unhandled event! + break; + } +} + +static void ble_evt_handler(ble_evt_t * p_ble_evt) { +// S132 event ranges. +// Common 0x01 -> 0x0F +// GAP 0x10 -> 0x2F +// GATTC 0x30 -> 0x4F +// GATTS 0x50 -> 0x6F +// L2CAP 0x70 -> 0x8F + switch (p_ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + BLE_DRIVER_LOG("GAP CONNECT\n"); + m_adv_in_progress = false; + gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); + + ble_gap_conn_params_t conn_params; + (void)sd_ble_gap_ppcp_get(&conn_params); + (void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, &conn_params); + break; + + case BLE_GAP_EVT_DISCONNECTED: + BLE_DRIVER_LOG("GAP DISCONNECT\n"); + gap_event_handler(mp_gap_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); + break; + + case BLE_GATTS_EVT_HVC: + gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, p_ble_evt->evt.gatts_evt.params.hvc.handle, p_ble_evt->header.evt_len - (2 * sizeof(uint16_t)), NULL); + break; + + case BLE_GATTS_EVT_WRITE: + BLE_DRIVER_LOG("GATTS write\n"); + + uint16_t handle = p_ble_evt->evt.gatts_evt.params.write.handle; + uint16_t data_len = p_ble_evt->evt.gatts_evt.params.write.len; + uint8_t * p_data = &p_ble_evt->evt.gatts_evt.params.write.data[0]; + + gatts_event_handler(mp_gatts_observer, p_ble_evt->header.evt_id, handle, data_len, p_data); + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE: + BLE_DRIVER_LOG("GAP CONN PARAM UPDATE\n"); + break; + + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + // No system attributes have been stored. + (void)sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0); + break; + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + case BLE_GATTS_EVT_HVN_TX_COMPLETE: +#else + case BLE_EVT_TX_COMPLETE: +#endif + BLE_DRIVER_LOG("BLE EVT TX COMPLETE\n"); +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + BLE_DRIVER_LOG("HVN_TX_COMPLETE, count: %u\n", p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count); + m_tx_in_progress -= p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count; + BLE_DRIVER_LOG("TX_COMPLETE, m_tx_in_progress: %u\n", m_tx_in_progress); +#else + BLE_DRIVER_LOG("TX_COMPLETE, count: %u\n", p_ble_evt->evt.common_evt.params.tx_complete.count); + m_tx_in_progress -= p_ble_evt->evt.common_evt.params.tx_complete.count; + BLE_DRIVER_LOG("TX_COMPLETE, m_tx_in_progress: %u\n", m_tx_in_progress); +#endif + break; + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + BLE_DRIVER_LOG("BLE EVT SEC PARAMS REQUEST\n"); + // pairing not supported + (void)sd_ble_gap_sec_params_reply(p_ble_evt->evt.gatts_evt.conn_handle, + BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, + NULL, NULL); + break; + +#if (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + case BLE_GAP_EVT_ADV_REPORT: + BLE_DRIVER_LOG("BLE EVT ADV REPORT\n"); + ble_drv_adv_data_t adv_data = { + .p_peer_addr = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr, + .addr_type = p_ble_evt->evt.gap_evt.params.adv_report.peer_addr.addr_type, + .is_scan_resp = p_ble_evt->evt.gap_evt.params.adv_report.type.scan_response, + .rssi = p_ble_evt->evt.gap_evt.params.adv_report.rssi, + .data_len = p_ble_evt->evt.gap_evt.params.adv_report.data.len, + .p_data = p_ble_evt->evt.gap_evt.params.adv_report.data.p_data, +// .adv_type = + }; + // TODO: Fix unsafe callback to possible undefined callback... + adv_event_handler(mp_adv_observer, + p_ble_evt->header.evt_id, + &adv_data); + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: + BLE_DRIVER_LOG("BLE EVT CONN PARAM UPDATE REQUEST\n"); + + (void)sd_ble_gap_conn_param_update(p_ble_evt->evt.gap_evt.conn_handle, + &p_ble_evt->evt.gap_evt.params.conn_param_update_request.conn_params); + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + BLE_DRIVER_LOG("BLE EVT PRIMARY SERVICE DISCOVERY RESPONSE\n"); + BLE_DRIVER_LOG(">>> service count: %d\n", p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count); + + for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count; i++) { + ble_gattc_service_t * p_service = &p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i]; + + ble_drv_service_data_t service; + service.uuid_type = p_service->uuid.type; + service.uuid = p_service->uuid.uuid; + service.start_handle = p_service->handle_range.start_handle; + service.end_handle = p_service->handle_range.end_handle; + + disc_add_service_handler(mp_gattc_disc_service_observer, &service); + } + + if (p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count > 0) { + m_primary_service_found = true; + } + + // mark end of service discovery + disc_add_service_handler = NULL; + + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + BLE_DRIVER_LOG("BLE EVT CHAR DISCOVERY RESPONSE\n"); + BLE_DRIVER_LOG(">>> characteristic count: %d\n", p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count); + + for (uint16_t i = 0; i < p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count; i++) { + ble_gattc_char_t * p_char = &p_ble_evt->evt.gattc_evt.params.char_disc_rsp.chars[i]; + + ble_drv_char_data_t char_data; + char_data.uuid_type = p_char->uuid.type; + char_data.uuid = p_char->uuid.uuid; + char_data.decl_handle = p_char->handle_decl; + char_data.value_handle = p_char->handle_value; + + char_data.props |= (p_char->char_props.broadcast) ? UBLUEPY_PROP_BROADCAST : 0; + char_data.props |= (p_char->char_props.read) ? UBLUEPY_PROP_READ : 0; + char_data.props |= (p_char->char_props.write_wo_resp) ? UBLUEPY_PROP_WRITE_WO_RESP : 0; + char_data.props |= (p_char->char_props.write) ? UBLUEPY_PROP_WRITE : 0; + char_data.props |= (p_char->char_props.notify) ? UBLUEPY_PROP_NOTIFY : 0; + char_data.props |= (p_char->char_props.indicate) ? UBLUEPY_PROP_INDICATE : 0; + #if 0 + char_data.props |= (p_char->char_props.auth_signed_wr) ? UBLUEPY_PROP_NOTIFY : 0; + #endif + + disc_add_char_handler(mp_gattc_disc_char_observer, &char_data); + } + + if (p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count > 0) { + m_characteristic_found = true; + } + + // mark end of characteristic discovery + disc_add_char_handler = NULL; + + break; + + case BLE_GATTC_EVT_READ_RSP: + BLE_DRIVER_LOG("BLE EVT READ RESPONSE, offset: 0x"HEX2_FMT", length: 0x"HEX2_FMT"\n", + p_ble_evt->evt.gattc_evt.params.read_rsp.offset, + p_ble_evt->evt.gattc_evt.params.read_rsp.len); + + gattc_char_data_handle(mp_gattc_char_data_observer, + p_ble_evt->evt.gattc_evt.params.read_rsp.len, + p_ble_evt->evt.gattc_evt.params.read_rsp.data); + + // mark end of read + gattc_char_data_handle = NULL; + + break; + + case BLE_GATTC_EVT_WRITE_RSP: + BLE_DRIVER_LOG("BLE EVT WRITE RESPONSE\n"); + m_write_done = true; + break; + + case BLE_GATTC_EVT_HVX: + BLE_DRIVER_LOG("BLE EVT HVX RESPONSE\n"); + break; + + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + BLE_DRIVER_LOG("GATTS EVT EXCHANGE MTU REQUEST\n"); + (void)sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 23); // MAX MTU size + break; +#endif // (BLUETOOTH_SD == 132) || (BLUETOOTH_SD == 140) + + default: + BLE_DRIVER_LOG(">>> unhandled evt: 0x" HEX2_FMT "\n", p_ble_evt->header.evt_id); + break; + } +} + +static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (GATT_MTU_SIZE_DEFAULT)] __attribute__ ((aligned (4))); + +#ifdef NRF51 +void SWI2_IRQHandler(void) { +#else +void SWI2_EGU2_IRQHandler(void) { +#endif + + uint32_t evt_id; + while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) { + sd_evt_handler(evt_id); + } + + while (1) { + uint16_t evt_len = sizeof(m_ble_evt_buf); + uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len); + if (err_code != NRF_SUCCESS) { + // Possible error conditions: + // * NRF_ERROR_NOT_FOUND: no events left, break + // * NRF_ERROR_DATA_SIZE: retry with a bigger data buffer + // (currently not handled, TODO) + // * NRF_ERROR_INVALID_ADDR: pointer is not aligned, should + // not happen. + // In all cases, it's best to simply stop now. + if (err_code == NRF_ERROR_DATA_SIZE) { + BLE_DRIVER_LOG("NRF_ERROR_DATA_SIZE\n"); + } + break; + } + ble_evt_handler((ble_evt_t *)m_ble_evt_buf); + } +} + +#endif // BLUETOOTH_SD diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.h b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.h new file mode 100755 index 0000000..ac68959 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_drv.h @@ -0,0 +1,129 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BLUETOOTH_LE_DRIVER_H__ +#define BLUETOOTH_LE_DRIVER_H__ + +#if BLUETOOTH_SD + +#include +#include + +#include "modubluepy.h" + +typedef struct { + uint8_t addr[6]; + uint8_t addr_type; +} ble_drv_addr_t; + +typedef struct { + uint8_t * p_peer_addr; + uint8_t addr_type; + bool is_scan_resp; + int8_t rssi; + uint8_t data_len; + uint8_t * p_data; + uint8_t adv_type; +} ble_drv_adv_data_t; + +typedef struct { + uint16_t uuid; + uint8_t uuid_type; + uint16_t start_handle; + uint16_t end_handle; +} ble_drv_service_data_t; + +typedef struct { + uint16_t uuid; + uint8_t uuid_type; + uint8_t props; + uint16_t decl_handle; + uint16_t value_handle; +} ble_drv_char_data_t; + +typedef void (*ble_drv_gap_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_gatts_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_gattc_evt_callback_t)(mp_obj_t self, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data); +typedef void (*ble_drv_adv_evt_callback_t)(mp_obj_t self, uint16_t event_id, ble_drv_adv_data_t * data); +typedef void (*ble_drv_disc_add_service_callback_t)(mp_obj_t self, ble_drv_service_data_t * p_service_data); +typedef void (*ble_drv_disc_add_char_callback_t)(mp_obj_t self, ble_drv_char_data_t * p_desc_data); +typedef void (*ble_drv_gattc_char_data_callback_t)(mp_obj_t self, uint16_t length, uint8_t * p_data); + +uint32_t ble_drv_stack_enable(void); + +void ble_drv_stack_disable(void); + +uint8_t ble_drv_stack_enabled(void); + +void ble_drv_address_get(ble_drv_addr_t * p_addr); + +bool ble_drv_uuid_add_vs(uint8_t * p_uuid, uint8_t * idx); + +bool ble_drv_service_add(ubluepy_service_obj_t * p_service_obj); + +bool ble_drv_characteristic_add(ubluepy_characteristic_obj_t * p_char_obj); + +bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params); + +void ble_drv_advertise_stop(void); + +void ble_drv_gap_event_handler_set(mp_obj_t obs, ble_drv_gap_evt_callback_t evt_handler); + +void ble_drv_gatts_event_handler_set(mp_obj_t obj, ble_drv_gatts_evt_callback_t evt_handler); + +void ble_drv_gattc_event_handler_set(mp_obj_t obj, ble_drv_gattc_evt_callback_t evt_handler); + +void ble_drv_attr_s_read(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); + +void ble_drv_attr_c_read(uint16_t conn_handle, uint16_t handle, mp_obj_t obj, ble_drv_gattc_char_data_callback_t cb); + +void ble_drv_attr_s_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); + +void ble_drv_attr_s_notify(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data); + +void ble_drv_attr_c_write(uint16_t conn_handle, uint16_t handle, uint16_t len, uint8_t * p_data, bool w_response); + +void ble_drv_scan_start(bool cont); + +void ble_drv_scan_stop(void); + +void ble_drv_adv_report_handler_set(mp_obj_t obj, ble_drv_adv_evt_callback_t evt_handler); + +void ble_drv_connect(uint8_t * p_addr, uint8_t addr_type); + +bool ble_drv_discover_services(mp_obj_t obj, uint16_t conn_handle, uint16_t start_handle, ble_drv_disc_add_service_callback_t cb); + +bool ble_drv_discover_characteristic(mp_obj_t obj, + uint16_t conn_handle, + uint16_t start_handle, + uint16_t end_handle, + ble_drv_disc_add_char_callback_t cb); + +void ble_drv_discover_descriptors(void); + +#endif // BLUETOOTH_SD + +#endif // BLUETOOTH_LE_DRIVER_H__ diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.c b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.c new file mode 100755 index 0000000..4a23cd6 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.c @@ -0,0 +1,280 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if BLUETOOTH_SD + +#include +#include "ble_uart.h" +#include "ringbuffer.h" +#include "mphalport.h" +#include "lib/utils/interrupt_char.h" + +#if MICROPY_PY_BLE_NUS + +static ubluepy_uuid_obj_t uuid_obj_service = { + .base.type = &ubluepy_uuid_type, + .type = UBLUEPY_UUID_128_BIT, + .value = {0x01, 0x00} +}; + +static ubluepy_uuid_obj_t uuid_obj_char_tx = { + .base.type = &ubluepy_uuid_type, + .type = UBLUEPY_UUID_128_BIT, + .value = {0x03, 0x00} +}; + +static ubluepy_uuid_obj_t uuid_obj_char_rx = { + .base.type = &ubluepy_uuid_type, + .type = UBLUEPY_UUID_128_BIT, + .value = {0x02, 0x00} +}; + +static ubluepy_service_obj_t ble_uart_service = { + .base.type = &ubluepy_service_type, + .p_uuid = &uuid_obj_service, + .type = UBLUEPY_SERVICE_PRIMARY +}; + +static ubluepy_characteristic_obj_t ble_uart_char_rx = { + .base.type = &ubluepy_characteristic_type, + .p_uuid = &uuid_obj_char_rx, + .props = UBLUEPY_PROP_WRITE | UBLUEPY_PROP_WRITE_WO_RESP, + .attrs = 0, +}; + +static ubluepy_characteristic_obj_t ble_uart_char_tx = { + .base.type = &ubluepy_characteristic_type, + .p_uuid = &uuid_obj_char_tx, + .props = UBLUEPY_PROP_NOTIFY, + .attrs = UBLUEPY_ATTR_CCCD, +}; + +static ubluepy_peripheral_obj_t ble_uart_peripheral = { + .base.type = &ubluepy_peripheral_type, + .conn_handle = 0xFFFF, +}; + +static volatile bool m_cccd_enabled; +static volatile bool m_connected; + +ringBuffer_typedef(uint8_t, ringbuffer_t); + +static ringbuffer_t m_rx_ring_buffer; +static ringbuffer_t * mp_rx_ring_buffer = &m_rx_ring_buffer; +static uint8_t m_rx_ring_buffer_data[128]; + +static ubluepy_advertise_data_t m_adv_data_uart_service; + +#if BLUETOOTH_WEBBLUETOOTH_REPL +static ubluepy_advertise_data_t m_adv_data_eddystone_url; +#endif // BLUETOOTH_WEBBLUETOOTH_REPL + +int mp_hal_stdin_rx_chr(void) { + while (!ble_uart_enabled()) { + // wait for connection + } + while (isBufferEmpty(mp_rx_ring_buffer)) { + ; + } + + uint8_t byte; + bufferRead(mp_rx_ring_buffer, byte); + return (int)byte; +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + // Not connected: drop output + if (!ble_uart_enabled()) return; + + uint8_t *buf = (uint8_t *)str; + size_t send_len; + + while (len > 0) { + if (len >= 20) { + send_len = 20; // (GATT_MTU_SIZE_DEFAULT - 3) + } else { + send_len = len; + } + + ubluepy_characteristic_obj_t * p_char = &ble_uart_char_tx; + + ble_drv_attr_s_notify(p_char->p_service->p_periph->conn_handle, + p_char->handle, + send_len, + buf); + + len -= send_len; + buf += send_len; + } +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { + mp_hal_stdout_tx_strn(str, len); +} + +STATIC void gap_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) { + ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); + + if (event_id == 16) { // connect event + self->conn_handle = conn_handle; + m_connected = true; + } else if (event_id == 17) { // disconnect event + self->conn_handle = 0xFFFF; // invalid connection handle + m_connected = false; + m_cccd_enabled = false; + ble_uart_advertise(); + } +} + +STATIC void gatts_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { + ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); + (void)self; + + if (event_id == 80) { // gatts write + if (ble_uart_char_tx.cccd_handle == attr_handle) { + m_cccd_enabled = true; + } else if (ble_uart_char_rx.handle == attr_handle) { + for (uint16_t i = 0; i < length; i++) { + #if MICROPY_KBD_EXCEPTION + if (data[i] == mp_interrupt_char) { + mp_keyboard_interrupt(); + m_rx_ring_buffer.start = 0; + m_rx_ring_buffer.end = 0; + } else + #endif + { + bufferWrite(mp_rx_ring_buffer, data[i]); + } + } + } + } +} + +void ble_uart_init0(void) { + uint8_t base_uuid[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}; + uint8_t uuid_vs_idx; + + (void)ble_drv_uuid_add_vs(base_uuid, &uuid_vs_idx); + + uuid_obj_service.uuid_vs_idx = uuid_vs_idx; + uuid_obj_char_tx.uuid_vs_idx = uuid_vs_idx; + uuid_obj_char_rx.uuid_vs_idx = uuid_vs_idx; + + (void)ble_drv_service_add(&ble_uart_service); + ble_uart_service.char_list = mp_obj_new_list(0, NULL); + + // add TX characteristic + ble_uart_char_tx.service_handle = ble_uart_service.handle; + bool retval = ble_drv_characteristic_add(&ble_uart_char_tx); + if (retval) { + ble_uart_char_tx.p_service = &ble_uart_service; + } + mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_tx)); + + // add RX characteristic + ble_uart_char_rx.service_handle = ble_uart_service.handle; + retval = ble_drv_characteristic_add(&ble_uart_char_rx); + if (retval) { + ble_uart_char_rx.p_service = &ble_uart_service; + } + mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_rx)); + + // setup the peripheral + ble_uart_peripheral.service_list = mp_obj_new_list(0, NULL); + mp_obj_list_append(ble_uart_peripheral.service_list, MP_OBJ_FROM_PTR(&ble_uart_service)); + ble_uart_service.p_periph = &ble_uart_peripheral; + + ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gap_event_handler); + ble_drv_gatts_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gatts_event_handler); + + ble_uart_peripheral.conn_handle = 0xFFFF; + + char device_name[] = "mpus"; + + mp_obj_t service_list = mp_obj_new_list(0, NULL); + mp_obj_list_append(service_list, MP_OBJ_FROM_PTR(&ble_uart_service)); + + mp_obj_t * services = NULL; + mp_uint_t num_services; + mp_obj_get_array(service_list, &num_services, &services); + + m_adv_data_uart_service.p_services = services; + m_adv_data_uart_service.num_of_services = num_services; + m_adv_data_uart_service.p_device_name = (uint8_t *)device_name; + m_adv_data_uart_service.device_name_len = strlen(device_name); + m_adv_data_uart_service.connectable = true; + m_adv_data_uart_service.p_data = NULL; + +#if BLUETOOTH_WEBBLUETOOTH_REPL + // for now point eddystone URL to https://goo.gl/F7fZ69 => https://aykevl.nl/apps/nus/ + static uint8_t eddystone_url_data[27] = {0x2, 0x1, 0x6, + 0x3, 0x3, 0xaa, 0xfe, + 19, 0x16, 0xaa, 0xfe, 0x10, 0xee, 0x3, 'g', 'o', 'o', '.', 'g', 'l', '/', 'F', '7', 'f', 'Z', '6', '9'}; + // eddystone url adv data + m_adv_data_eddystone_url.p_data = eddystone_url_data; + m_adv_data_eddystone_url.data_len = sizeof(eddystone_url_data); + m_adv_data_eddystone_url.connectable = false; +#endif + + m_cccd_enabled = false; + + // initialize ring buffer + m_rx_ring_buffer.size = sizeof(m_rx_ring_buffer_data) + 1; + m_rx_ring_buffer.start = 0; + m_rx_ring_buffer.end = 0; + m_rx_ring_buffer.elems = m_rx_ring_buffer_data; + + m_connected = false; + + ble_uart_advertise(); +} + +void ble_uart_advertise(void) { +#if BLUETOOTH_WEBBLUETOOTH_REPL + while (!m_connected) { + (void)ble_drv_advertise_data(&m_adv_data_uart_service); + mp_hal_delay_ms(500); + (void)ble_drv_advertise_data(&m_adv_data_eddystone_url); + mp_hal_delay_ms(500); + } + + ble_drv_advertise_stop(); +#else + (void)ble_drv_advertise_data(&m_adv_data_uart_service); +#endif // BLUETOOTH_WEBBLUETOOTH_REPL +} + +bool ble_uart_connected(void) { + return (m_connected); +} + +bool ble_uart_enabled(void) { + return (m_cccd_enabled); +} + +#endif // MICROPY_PY_BLE_NUS + +#endif // BLUETOOTH_SD diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.h b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.h new file mode 100755 index 0000000..e67176a --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ble_uart.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BLUETOOTH_LE_UART_H__ +#define BLUETOOTH_LE_UART_H__ + +#if BLUETOOTH_SD + +#include "modubluepy.h" +#include "ble_drv.h" + +void ble_uart_init0(void); +void ble_uart_advertise(void); +bool ble_uart_connected(void); +bool ble_uart_enabled(void); + +#endif // BLUETOOTH_SD + +#endif // BLUETOOTH_LE_UART_H__ diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/bluetooth_common.mk b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/bluetooth_common.mk new file mode 100755 index 0000000..dba0076 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/bluetooth_common.mk @@ -0,0 +1,49 @@ + +SOFTDEV_HEX_NAME ?= +SOFTDEV_HEX_PATH ?= + +ifeq ($(SD), s110) + INC += -Idrivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include + CFLAGS += -DBLUETOOTH_SD_DEBUG=1 + CFLAGS += -DBLUETOOTH_SD=110 + +else ifeq ($(SD), s132) + INC += -Idrivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include + INC += -Idrivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include/$(MCU_VARIANT) + CFLAGS += -DBLUETOOTH_SD_DEBUG=1 + CFLAGS += -DBLUETOOTH_SD=132 + +else ifeq ($(SD), s140) + INC += -Idrivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include + INC += -Idrivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_API/include/$(MCU_VARIANT) + CFLAGS += -DBLUETOOTH_SD_DEBUG=1 + CFLAGS += -DBLUETOOTH_SD=140 +else + $(error Incorrect softdevice set flag) +endif + +SOFTDEV_HEX_NAME = $(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION)_softdevice.hex +SOFTDEV_HEX_PATH = drivers/bluetooth/$(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION) + +define STACK_MISSING_ERROR + + +###### ERROR: Bluetooth LE Stack not found ############ +# # +# The build target requires a Bluetooth LE stack. # +# $(SD)_$(MCU_VARIANT)_$(SOFTDEV_VERSION) Bluetooth LE stack not found. # +# # +# Please run the download script: # +# # +# drivers/bluetooth/download_ble_stack.sh # +# # +####################################################### + +endef + + +SOFTDEV_HEX = $(SOFTDEV_HEX_PATH)/$(SOFTDEV_HEX_NAME) + +ifeq ($(shell test ! -e $(SOFTDEV_HEX) && echo -n no),no) + $(error $(STACK_MISSING_ERROR)) +endif diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/download_ble_stack.sh new file mode 100755 index 0000000..0a542be --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/download_ble_stack.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +function download_s110_nrf51_8_0_0 +{ + echo "" + echo "####################################" + echo "### Downloading s110_nrf51_8.0.0 ###" + echo "####################################" + echo "" + + mkdir -p $1/s110_nrf51_8.0.0 + cd $1/s110_nrf51_8.0.0 + wget https://www.nordicsemi.com/eng/nordic/download_resource/45846/3/78153065/80234 + mv 80234 temp.zip + unzip -u temp.zip + rm temp.zip + cd - +} + + +function download_s132_nrf52_6_0_0 +{ + echo "" + echo "####################################" + echo "### Downloading s132_nrf52_6.0.0 ###" + echo "####################################" + echo "" + + mkdir -p $1/s132_nrf52_6.0.0 + cd $1/s132_nrf52_6.0.0 + + wget http://www.nordicsemi.com/eng/nordic/download_resource/67248/3/62916494/141008 + mv 141008 temp.zip + unzip -u temp.zip + rm temp.zip + cd - +} + + +function download_s140_nrf52_6_0_0 +{ + echo "" + echo "####################################" + echo "### Downloading s140_nrf52_6.0.0 ###" + echo "####################################" + echo "" + + mkdir -p $1/s140_nrf52_6.0.0 + cd $1/s140_nrf52_6.0.0 + + wget http://www.nordicsemi.com/eng/nordic/download_resource/60624/19/81980817/116072 + mv 116072 temp.zip + unzip -u temp.zip + rm temp.zip + cd - +} + + +SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ $# -eq 0 ]; then + echo "No Bluetooth LE stack defined, downloading all." + download_s110_nrf51_8_0_0 ${SCRIPT_DIR} + download_s132_nrf52_6_0_0 ${SCRIPT_DIR} + download_s140_nrf52_6_0_0 ${SCRIPT_DIR} +else + case $1 in + "s110_nrf51" ) + download_s110_nrf51_8_0_0 ${SCRIPT_DIR} ;; + "s132_nrf52_2_0_1" ) + download_s132_nrf52_6_0_0 ${SCRIPT_DIR} ;; + "s132_nrf52_3_0_0" ) + download_s140_nrf52_6_0_0 ${SCRIPT_DIR} ;; + esac +fi + +exit 0 diff --git a/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ringbuffer.h b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ringbuffer.h new file mode 100755 index 0000000..3438b5c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/bluetooth/ringbuffer.h @@ -0,0 +1,99 @@ +/* The MIT License (MIT) + * + * Copyright (c) 2013 Philip Thrasher + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * Philip Thrasher's Crazy Awesome Ring Buffer Macros! + * + * Below you will find some naughty macros for easy owning and manipulating + * generic ring buffers. Yes, they are slightly evil in readability, but they + * are really fast, and they work great. + * + * Example usage: + * + * #include + * + * // So we can use this in any method, this gives us a typedef + * // named 'intBuffer'. + * ringBuffer_typedef(int, intBuffer); + * + * int main() { + * // Declare vars. + * intBuffer myBuffer; + * + * bufferInit(myBuffer,1024,int); + * + * // We must have the pointer. All of the macros deal with the pointer. + * // (except for init.) + * intBuffer* myBuffer_ptr; + * myBuffer_ptr = &myBuffer; + * + * // Write two values. + * bufferWrite(myBuffer_ptr,37); + * bufferWrite(myBuffer_ptr,72); + * + * // Read a value into a local variable. + * int first; + * bufferRead(myBuffer_ptr,first); + * assert(first == 37); // true + * + * int second; + * bufferRead(myBuffer_ptr,second); + * assert(second == 72); // true + * + * return 0; + * } + * + */ + +#ifndef _ringbuffer_h +#define _ringbuffer_h + +#define ringBuffer_typedef(T, NAME) \ + typedef struct { \ + int size; \ + volatile int start; \ + volatile int end; \ + T* elems; \ + } NAME + +#define bufferInit(BUF, S, T) \ + BUF.size = S+1; \ + BUF.start = 0; \ + BUF.end = 0; \ + BUF.elems = (T*)calloc(BUF.size, sizeof(T)) + + +#define bufferDestroy(BUF) free(BUF->elems) +#define nextStartIndex(BUF) ((BUF->start + 1) % BUF->size) +#define nextEndIndex(BUF) ((BUF->end + 1) % BUF->size) +#define isBufferEmpty(BUF) (BUF->end == BUF->start) +#define isBufferFull(BUF) (nextEndIndex(BUF) == BUF->start) + +#define bufferWrite(BUF, ELEM) \ + BUF->elems[BUF->end] = ELEM; \ + BUF->end = (BUF->end + 1) % BUF->size; \ + if (isBufferEmpty(BUF)) { \ + BUF->start = nextStartIndex(BUF); \ + } + +#define bufferRead(BUF, ELEM) \ + ELEM = BUF->elems[BUF->start]; \ + BUF->start = nextStartIndex(BUF); + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/drivers/flash.c b/src/openmv/src/micropython/ports/nrf/drivers/flash.c new file mode 100755 index 0000000..5a7256a --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/flash.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +#if MICROPY_MBFS && BLUETOOTH_SD + +#include "drivers/flash.h" +#include "drivers/bluetooth/ble_drv.h" +#include "nrf_soc.h" + +// Rotates bits in `value` left `shift` times. +STATIC inline uint32_t rotate_left(uint32_t value, uint32_t shift) { + return (value << shift) | (value >> (32 - shift)); +} + +STATIC volatile flash_state_t flash_operation_state = FLASH_STATE_BUSY; + +STATIC void operation_init(void) { + flash_operation_state = FLASH_STATE_BUSY; +} + +void flash_operation_finished(flash_state_t result) { + flash_operation_state = result; +} + +STATIC bool operation_wait(uint32_t result) { + if (ble_drv_stack_enabled() != 1) { + // SoftDevice is not enabled, no event will be generated. + return result == NRF_SUCCESS; + } + + if (result != NRF_SUCCESS) { + // In all other (non-success) cases, the command hasn't been + // started and no event will be generated. + return false; + } + + // Wait until the event has been generated. + while (flash_operation_state == FLASH_STATE_BUSY) { + sd_app_evt_wait(); + } + + // Now we can safely continue, flash operation has completed. + return flash_operation_state == FLASH_STATE_SUCCESS; +} + +void flash_write_byte(uint32_t address, uint8_t b) { + uint32_t address_aligned = address & ~3; + + // Value to write - leave all bits that should not change at 0xff. + uint32_t value = 0xffffff00 | b; + + // Rotate bits in value to an aligned position. + value = rotate_left(value, (address & 3) * 8); + + while (1) { + operation_init(); + uint32_t result = sd_flash_write((uint32_t*)address_aligned, &value, 1); + if (operation_wait(result)) break; + } +} + +void flash_page_erase(uint32_t pageaddr) { + while (1) { + operation_init(); + uint32_t result = sd_flash_page_erase(pageaddr / FLASH_PAGESIZE); + if (operation_wait(result)) break; + } +} + +void flash_write_bytes(uint32_t dst, const uint8_t *src, uint32_t num_bytes) { + const uint8_t *src_end = src + num_bytes; + + // sd_flash_write does not accept unaligned addresses so we have to + // work around that by writing all unaligned addresses byte-by-byte. + + // Write first bytes to align the write address. + while (src != src_end && (dst & 0b11)) { + flash_write_byte(dst, *src); + dst++; + src++; + } + + // Write as many words as possible. + // dst is now aligned, src possibly not. + while (src_end - src >= 4) { + uint8_t buf[4] __attribute__((aligned(4))); + for (int i = 0; i < 4; i++) { + buf[i] = ((uint8_t*)src)[i]; + } + operation_init(); + uint32_t result = sd_flash_write((uint32_t*)dst, (const uint32_t*)&buf, 1); + if (operation_wait(result)) { + // If it is successfully written, go to the next word. + src += 4; + dst += 4; + } + } + + // Write remaining unaligned bytes. + while (src != src_end) { + flash_write_byte(dst, *src); + dst++; + src++; + } +} + +#endif // MICROPY_MBFS diff --git a/src/openmv/src/micropython/ports/nrf/drivers/flash.h b/src/openmv/src/micropython/ports/nrf/drivers/flash.h new file mode 100755 index 0000000..7e6fff3 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/flash.h @@ -0,0 +1,64 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_LIB_FLASH_H__ +#define __MICROPY_INCLUDED_LIB_FLASH_H__ + +#include "nrf_nvmc.h" + +#if defined(NRF51) +#define FLASH_PAGESIZE (1024) + +#elif defined(NRF52_SERIES) +#define FLASH_PAGESIZE (4096) +#else +#error Unknown chip +#endif + +#define FLASH_IS_PAGE_ALIGNED(addr) (((uint32_t)(addr) & (FLASH_PAGESIZE - 1)) == 0) + +#if BLUETOOTH_SD + +typedef enum { + FLASH_STATE_BUSY, + FLASH_STATE_SUCCESS, + FLASH_STATE_ERROR, +} flash_state_t; + +void flash_page_erase(uint32_t address); +void flash_write_byte(uint32_t address, uint8_t value); +void flash_write_bytes(uint32_t address, const uint8_t *src, uint32_t num_bytes); +void flash_operation_finished(flash_state_t result); + +#else + +#define flash_page_erase nrf_nvmc_page_erase +#define flash_write_byte nrf_nvmc_write_byte +#define flash_write_bytes nrf_nvmc_write_bytes + +#endif + +#endif // __MICROPY_INCLUDED_LIB_FLASH_H__ diff --git a/src/openmv/src/micropython/ports/nrf/drivers/softpwm.c b/src/openmv/src/micropython/ports/nrf/drivers/softpwm.c new file mode 100755 index 0000000..517880c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/softpwm.c @@ -0,0 +1,258 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Mark Shannon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_SOFT_PWM + +#include "stddef.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "nrf_timer.h" +#include "nrf_gpio.h" +#include "pin.h" + +#include "ticker.h" + +#define CYCLES_PER_MICROSECONDS 16 + +#define MICROSECONDS_PER_TICK 16 +#define CYCLES_PER_TICK (CYCLES_PER_MICROSECONDS*MICROSECONDS_PER_TICK) +// This must be an integer multiple of MICROSECONDS_PER_TICK +#define MICROSECONDS_PER_MACRO_TICK 6000 +#define MILLISECONDS_PER_MACRO_TICK 6 + +#define PWM_TICKER_INDEX 2 + +// Default period of 20ms +#define DEFAULT_PERIOD ((20*1000)/MICROSECONDS_PER_TICK) + +typedef struct _pwm_event { + uint16_t time; + uint8_t pin; + uint8_t turn_on; +} pwm_event; + +typedef struct _pwm_events { + uint8_t count; + uint16_t period; + uint32_t all_pins; + pwm_event events[1]; +} pwm_events; + +static const pwm_events OFF_EVENTS = { + .count = 1, + .period = DEFAULT_PERIOD, + .all_pins = 0, + .events = { + { + .time = 1024, + .pin = 31, + .turn_on = 0 + } + } +}; + +#define active_events MP_STATE_PORT(pwm_active_events) +#define pending_events MP_STATE_PORT(pwm_pending_events) + +void softpwm_init0(void) { + active_events = &OFF_EVENTS; + pending_events = NULL; +} + +static uint8_t next_event = 0; + +static inline int32_t pwm_get_period_ticks(void) { + const pwm_events *tmp = pending_events; + if (tmp == NULL) + tmp = active_events; + return tmp->period; +} + +#if 0 +void pwm_dump_events(const pwm_events *events) { + printf("Count %d, period %d, all pins %d\r\n", events->count, events->period, events->all_pins); + for (uint32_t i = 0; i < events->count; i++) { + const pwm_event *event = &events->events[i]; + printf("Event. pin: %d, duty cycle: %d, turn_on: %d\r\n", + event->pin, event->time, event->turn_on); + } +} + +void pwm_dump_state(void) { + while(pending_events); + pwm_dump_events(active_events); +} +#endif + +static const pwm_events *swap_pending(const pwm_events *in) { + __disable_irq(); + const pwm_events *result = pending_events; + pending_events = in; + __enable_irq(); + return result; +} + +static pwm_events *copy_events(const pwm_events *orig, uint32_t count) { + pwm_events *events = m_malloc(sizeof(pwm_events) + (count-1)*sizeof(pwm_event)); + events->count = count; + uint32_t copy = count > orig->count ? orig->count : count; + for (uint32_t i = 0; i < copy; i++) { + events->events[i] = orig->events[i]; + } + return events; +} + +static int find_pin_in_events(const pwm_events *events, uint32_t pin) { + for (int i = 0; i < events->count; i++) { + if (events->events[i].pin == pin) + return i; + } + return -1; +} + +static void sort_events(pwm_events *events) { + // Insertion sort + for (int32_t i = 1; i < events->count; i++) { + pwm_event x = events->events[i]; + int32_t j; + for (j = i - 1; j >= 0 && events->events[j].time > x.time; j--) { + events->events[j+1] = events->events[j]; + } + events->events[j+1] = x; + } +} + +int32_t pwm_callback(void) { + int32_t tdiff; + const pwm_events *events = active_events; + const pwm_event *event = &events->events[next_event]; + int32_t tnow = (event->time*events->period)>>10; + do { + if (event->turn_on) { + nrf_gpio_pin_set(event->pin); + next_event++; + } else { + // TODO: Resolve port for nrf52 + nrf_gpio_port_out_clear(NRF_GPIO, events->all_pins); + next_event = 0; + tnow = 0; + if (pending_events) { + events = pending_events; + active_events = events; + pending_events = NULL; + } + } + event = &events->events[next_event]; + tdiff = ((event->time*events->period)>>10) - tnow; + } while (tdiff == 0); + return tdiff; +} + +void pwm_start(void) { + set_ticker_callback(PWM_TICKER_INDEX, pwm_callback, 120); +} + +void pwm_stop(void) { + clear_ticker_callback(PWM_TICKER_INDEX); +} + +static void pwm_set_period_ticks(int32_t ticks) { + const pwm_events *old_events = swap_pending(NULL); + if (old_events == NULL) { + old_events = active_events; + } + pwm_events *events = copy_events(old_events, old_events->count); + events->all_pins = old_events->all_pins; + events->period = ticks; + pending_events = events; +} + +int pwm_set_period_us(int32_t us) { + if ((us < 256) || + (us > 1000000)) { + return -1; + } + pwm_set_period_ticks(us/MICROSECONDS_PER_TICK); + return 0; +} + +int32_t pwm_get_period_us(void) { + return pwm_get_period_ticks()*MICROSECONDS_PER_TICK; +} + +void pwm_set_duty_cycle(int32_t pin, uint32_t value) { + if (value >= (1<<10)) { + value = (1<<10)-1; + } + uint32_t turn_on_time = 1024-value; + const pwm_events *old_events = swap_pending(NULL); + if (old_events == NULL) { + old_events = active_events; + } + if (((1<all_pins) == 0) { + nrf_gpio_cfg_output(pin); + } + int ev = find_pin_in_events(old_events, pin); + pwm_events *events; + if (ev < 0 && value == 0) { + return; + } else if (ev < 0) { + events = copy_events(old_events, old_events->count+1); + events->all_pins = old_events->all_pins | (1<events[old_events->count].time = turn_on_time; + events->events[old_events->count].pin = pin; + events->events[old_events->count].turn_on = 1; + } else if (value == 0) { + events = copy_events(old_events, old_events->count-1); + events->all_pins = old_events->all_pins & ~(1<count-1) { + events->events[ev] = old_events->events[old_events->count-1]; + } + } else { + events = copy_events(old_events, old_events->count); + events->all_pins = old_events->all_pins; + events->events[ev].time = turn_on_time; + } + events->period = old_events->period; + sort_events(events); + pending_events = events; + return; +} + +void pwm_release(int32_t pin) { + pwm_set_duty_cycle(pin, 0); + const pwm_events *ev = active_events; + int i = find_pin_in_events(ev, pin); + if (i < 0) + return; + // If i >= 0 it means that `ev` is in RAM, so it safe to discard the const qualifier + ((pwm_events *)ev)->events[i].pin = 31; + nrf_gpio_pin_clear(pin); +} + +#endif // MICROPY_PY_MACHINE_SOFT_PWM diff --git a/src/openmv/src/micropython/ports/nrf/drivers/softpwm.h b/src/openmv/src/micropython/ports/nrf/drivers/softpwm.h new file mode 100755 index 0000000..0e0979f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/softpwm.h @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers: + * Damien P. George (@dpgeorge) + * Nicholas H. Tollervey (@ntoll) + * Matthew Else (@matthewelse) + * Alan M. Jackson (@alanmjackson) + * Mark Shannon (@markshannon) + * Larry Hastings (@larryhastings) + * Mariia Koroliuk (@marichkakorolyuk) + * Andrew Mulholland (@gbaman) + * Joe Glancy (@JoeGlancy) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_LIB_PWM_H__ +#define __MICROPY_INCLUDED_LIB_PWM_H__ + +void softpwm_init0(void); +void pwm_start(void); +void pwm_stop(void); + +int pwm_set_period_us(int32_t us); +int32_t pwm_get_period_us(void); +void pwm_set_duty_cycle(int32_t pin, int32_t value); +void pwm_release(int32_t pin); + +#endif // __MICROPY_INCLUDED_LIB_PWM_H__ diff --git a/src/openmv/src/micropython/ports/nrf/drivers/ticker.c b/src/openmv/src/micropython/ports/nrf/drivers/ticker.c new file mode 100755 index 0000000..264ed8e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/ticker.c @@ -0,0 +1,170 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Mark Shannon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_SOFT_PWM + +#include "ticker.h" +#include "nrfx_glue.h" + +#define FastTicker NRF_TIMER1 +#define FastTicker_IRQn TIMER1_IRQn +#define FastTicker_IRQHandler TIMER1_IRQHandler + +#define SlowTicker_IRQn SWI0_IRQn +#define SlowTicker_IRQHandler SWI0_IRQHandler + +// Ticker callback function called every MACRO_TICK +static volatile uint8_t m_num_of_slow_tickers = 0; +static volatile callback_ptr m_slow_tickers[2] = {NULL, NULL}; + +void ticker_init0(void) { + NRF_TIMER_Type *ticker = FastTicker; +#ifdef NRF51 + ticker->POWER = 1; +#endif + __NOP(); + ticker_stop(); + ticker->TASKS_CLEAR = 1; + ticker->CC[3] = MICROSECONDS_PER_MACRO_TICK; + ticker->MODE = TIMER_MODE_MODE_Timer; + ticker->BITMODE = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos; + ticker->PRESCALER = 4; // 1 tick == 1 microsecond + ticker->INTENSET = TIMER_INTENSET_COMPARE3_Msk; + ticker->SHORTS = 0; + +#ifdef NRF51 + NRFX_IRQ_PRIORITY_SET(FastTicker_IRQn, 1); +#else + NRFX_IRQ_PRIORITY_SET(FastTicker_IRQn, 2); +#endif + + NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3); + NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3); + + NRFX_IRQ_ENABLE(SlowTicker_IRQn); +} + +void ticker_register_low_pri_callback(callback_ptr slow_ticker_callback) { + m_slow_tickers[m_num_of_slow_tickers++] = slow_ticker_callback; +} + +/* Start and stop timer 1 including workarounds for Anomaly 73 for Timer +* http://www.nordicsemi.com/eng/content/download/29490/494569/file/nRF51822-PAN%20v3.0.pdf +*/ +void ticker_start(void) { + NRFX_IRQ_ENABLE(FastTicker_IRQn); +#ifdef NRF51 + *(uint32_t *)0x40009C0C = 1; // for Timer 1 +#endif + FastTicker->TASKS_START = 1; +} + +void ticker_stop(void) { + NRFX_IRQ_DISABLE(FastTicker_IRQn); + FastTicker->TASKS_STOP = 1; +#ifdef NRF51 + *(uint32_t *)0x40009C0C = 0; // for Timer 1 +#endif +} + +int32_t noop(void) { + return -1; +} + +volatile uint32_t ticks; + +static ticker_callback_ptr callbacks[3] = { noop, noop, noop }; + +void FastTicker_IRQHandler(void) { + NRF_TIMER_Type *ticker = FastTicker; + ticker_callback_ptr *call = callbacks; + if (ticker->EVENTS_COMPARE[0]) { + ticker->EVENTS_COMPARE[0] = 0; + ticker->CC[0] += call[0]()*MICROSECONDS_PER_TICK; + } + if (ticker->EVENTS_COMPARE[1]) { + ticker->EVENTS_COMPARE[1] = 0; + ticker->CC[1] += call[1]()*MICROSECONDS_PER_TICK; + } + if (ticker->EVENTS_COMPARE[2]) { + ticker->EVENTS_COMPARE[2] = 0; + ticker->CC[2] += call[2]()*MICROSECONDS_PER_TICK; + } + if (ticker->EVENTS_COMPARE[3]) { + ticker->EVENTS_COMPARE[3] = 0; + ticker->CC[3] += MICROSECONDS_PER_MACRO_TICK; + ticks += MILLISECONDS_PER_MACRO_TICK; + NRFX_IRQ_PENDING_SET(SlowTicker_IRQn); + } +} + + +static const uint32_t masks[3] = { + TIMER_INTENCLR_COMPARE0_Msk, + TIMER_INTENCLR_COMPARE1_Msk, + TIMER_INTENCLR_COMPARE2_Msk, +}; + +int set_ticker_callback(uint32_t index, ticker_callback_ptr func, int32_t initial_delay_us) { + if (index > 3) + return -1; + NRF_TIMER_Type *ticker = FastTicker; + callbacks[index] = noop; + ticker->INTENCLR = masks[index]; + ticker->TASKS_CAPTURE[index] = 1; + uint32_t t = FastTicker->CC[index]; + // Need to make sure that set tick is aligned to lastest tick + // Use CC[3] as a reference, as that is always up-to-date. + int32_t cc3 = FastTicker->CC[3]; + int32_t delta = t+initial_delay_us-cc3; + delta = (delta/MICROSECONDS_PER_TICK+1)*MICROSECONDS_PER_TICK; + callbacks[index] = func; + ticker->INTENSET = masks[index]; + FastTicker->CC[index] = cc3 + delta; + return 0; +} + +int clear_ticker_callback(uint32_t index) { + if (index > 3) + return -1; + FastTicker->INTENCLR = masks[index]; + callbacks[index] = noop; + return 0; +} + +void SlowTicker_IRQHandler(void) +{ + + for (int i = 0; i < m_num_of_slow_tickers; i++) { + if (m_slow_tickers[i] != NULL) { + m_slow_tickers[i](); + } + } +} + +#endif // MICROPY_PY_MACHINE_SOFT_PWM diff --git a/src/openmv/src/micropython/ports/nrf/drivers/ticker.h b/src/openmv/src/micropython/ports/nrf/drivers/ticker.h new file mode 100755 index 0000000..f6a95a9 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/drivers/ticker.h @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 The MicroPython-on-micro:bit Developers: + * Damien P. George (@dpgeorge) + * Nicholas H. Tollervey (@ntoll) + * Matthew Else (@matthewelse) + * Alan M. Jackson (@alanmjackson) + * Mark Shannon (@markshannon) + * Larry Hastings (@larryhastings) + * Mariia Koroliuk (@marichkakorolyuk) + * Andrew Mulholland (@gbaman) + * Joe Glancy (@JoeGlancy) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_LIB_TICKER_H__ +#define __MICROPY_INCLUDED_LIB_TICKER_H__ + +/************************************* + * 62.5kHz (16µs cycle time) ticker. + ************************************/ + +#include "nrf.h" + +typedef void (*callback_ptr)(void); +typedef int32_t (*ticker_callback_ptr)(void); + +void ticker_init0(void); +void ticker_start(void); +void ticker_stop(void); +int clear_ticker_callback(uint32_t index); +int set_ticker_callback(uint32_t index, ticker_callback_ptr func, int32_t initial_delay_us); + +void ticker_register_low_pri_callback(callback_ptr callback); + +#define CYCLES_PER_MICROSECONDS 16 + +#define MICROSECONDS_PER_TICK 16 +#define CYCLES_PER_TICK (CYCLES_PER_MICROSECONDS*MICROSECONDS_PER_TICK) +// This must be an integer multiple of MICROSECONDS_PER_TICK +#define MICROSECONDS_PER_MACRO_TICK 6000 +#define MILLISECONDS_PER_MACRO_TICK 6 + +#endif // __MICROPY_INCLUDED_LIB_TICKER_H__ diff --git a/src/openmv/src/micropython/ports/nrf/examples/mountsd.py b/src/openmv/src/micropython/ports/nrf/examples/mountsd.py new file mode 100755 index 0000000..64e1c88 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/mountsd.py @@ -0,0 +1,35 @@ +""" + +Example for pca10040 / nrf52832 to show how mount +and list a sdcard connected over SPI. + + +Direct wireing on SD card (SPI): + ______________________________ + | \ + | 9. | NC | \ + | 1. | ~CS | | + | 2. | MOSI | | + | 3. | GND | | + | 4. | VCC3.3| | + | 5. | SCK | | + | 6. | GND | | + | 7. | MISO | | + | 8. | NC | | + | | + --------------------------------- +""" + +import os +from machine import SPI, Pin +from sdcard import SDCard + +def mnt(): + cs = Pin("P22", mode=Pin.OUT) + sd = SDCard(SPI(0), cs) + os.mount(sd, '/') + +def list(): + files = os.listdir() + print(files) + diff --git a/src/openmv/src/micropython/ports/nrf/examples/musictest.py b/src/openmv/src/micropython/ports/nrf/examples/musictest.py new file mode 100755 index 0000000..46276d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/musictest.py @@ -0,0 +1,13 @@ +# +# Example usage where "P3" is the Buzzer pin. +# +# from musictest import play +# play("P3") +# + +from machine import Pin +import music + +def play(pin_str): + p = Pin(pin_str, mode=Pin.OUT) + music.play(music.PRELUDE, pin=p) diff --git a/src/openmv/src/micropython/ports/nrf/examples/nrf52_pwm.py b/src/openmv/src/micropython/ports/nrf/examples/nrf52_pwm.py new file mode 100755 index 0000000..b242ea9 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/nrf52_pwm.py @@ -0,0 +1,15 @@ +import time +from machine import PWM, Pin + +def pulse(): + for i in range(0, 101): + p = PWM(0, Pin("P17", mode=Pin.OUT), freq=PWM.FREQ_16MHZ, duty=i, period=16000) + p.init() + time.sleep_ms(10) + p.deinit() + + for i in range(0, 101): + p = PWM(0, Pin("P17", mode=Pin.OUT), freq=PWM.FREQ_16MHZ, duty=100-i, period=16000) + p.init() + time.sleep_ms(10) + p.deinit() diff --git a/src/openmv/src/micropython/ports/nrf/examples/nrf52_servo.py b/src/openmv/src/micropython/ports/nrf/examples/nrf52_servo.py new file mode 100755 index 0000000..baa8600 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/nrf52_servo.py @@ -0,0 +1,50 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2017 Glenn Ruben Bakke +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE + +import time +from machine import PWM, Pin + +class Servo(): + def __init__(self, pin_name=""): + if pin_name: + self.pin = Pin(pin_name, mode=Pin.OUT, pull=Pin.PULL_DOWN) + else: + self.pin = Pin("P22", mode=Pin.OUT, pull=Pin.PULL_DOWN) + def left(self): + p = PWM(0, self.pin, freq=PWM.FREQ_125KHZ, pulse_width=105, period=2500, mode=PWM.MODE_HIGH_LOW) + p.init() + time.sleep_ms(200) + p.deinit() + + def center(self): + p = PWM(0, self.pin, freq=PWM.FREQ_125KHZ, pulse_width=188, period=2500, mode=PWM.MODE_HIGH_LOW) + p.init() + time.sleep_ms(200) + p.deinit() + + def right(self): + p = PWM(0, self.pin, freq=PWM.FREQ_125KHZ, pulse_width=275, period=2500, mode=PWM.MODE_HIGH_LOW) + p.init() + time.sleep_ms(200) + p.deinit() diff --git a/src/openmv/src/micropython/ports/nrf/examples/powerup.py b/src/openmv/src/micropython/ports/nrf/examples/powerup.py new file mode 100755 index 0000000..6f14309 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/powerup.py @@ -0,0 +1,213 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2017 Glenn Ruben Bakke +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE + +# MicroPython controller for PowerUp 3.0 paper airplane +# https://www.poweruptoys.com/products/powerup-v3 +# +# Examples is written for nrf52832, pca10040 using s132 bluetooth stack. +# +# Joystick shield pin mapping: +# - analog stick x-direction - ADC0 - P0.02/"P2" +# - buttons P0.13 - P0.16 / "P13", "P14", "P15", "P16" +# +# Example usage: +# +# from powerup import PowerUp3 +# p = PowerUp3() + +import time +from machine import ADC +from machine import Pin +from ubluepy import Peripheral, Scanner, constants + +def bytes_to_str(bytes): + string = "" + for b in bytes: + string += chr(b) + return string + +def get_device_names(scan_entries): + dev_names = [] + for e in scan_entries: + scan = e.getScanData() + if scan: + for s in scan: + if s[0] == constants.ad_types.AD_TYPE_COMPLETE_LOCAL_NAME: + dev_names.append((e, bytes_to_str(s[2]))) + return dev_names + +def find_device_by_name(name): + s = Scanner() + scan_res = s.scan(500) + + device_names = get_device_names(scan_res) + for dev in device_names: + if name == dev[1]: + return dev[0] + +class PowerUp3: + def __init__(self): + self.x_adc = ADC(1) + + self.btn_speed_up = Pin("P13", mode=Pin.IN, pull=Pin.PULL_UP) + self.btn_speed_down = Pin("P15", mode=Pin.IN, pull=Pin.PULL_UP) + self.btn_speed_full = Pin("P14", mode=Pin.IN, pull=Pin.PULL_UP) + self.btn_speed_off = Pin("P16", mode=Pin.IN, pull=Pin.PULL_UP) + + self.x_mid = 0 + + self.calibrate() + self.connect() + self.loop() + + def read_stick_x(self): + return self.x_adc.value() + + def button_speed_up(self): + return not bool(self.btn_speed_up.value()) + + def button_speed_down(self): + return not bool(self.btn_speed_down.value()) + + def button_speed_full(self): + return not bool(self.btn_speed_full.value()) + + def button_speed_off(self): + return not bool(self.btn_speed_off.value()) + + def calibrate(self): + self.x_mid = self.read_stick_x() + + def __str__(self): + return "calibration x: %i, y: %i" % (self.x_mid) + + def map_chars(self): + s = self.p.getServices() + + service_batt = s[3] + service_control = s[4] + + self.char_batt_lvl = service_batt.getCharacteristics()[0] + self.char_control_speed = service_control.getCharacteristics()[0] + self.char_control_angle = service_control.getCharacteristics()[2] + + def battery_level(self): + return int(self.char_batt_lvl.read()[0]) + + def speed(self, new_speed=None): + if new_speed == None: + return int(self.char_control_speed.read()[0]) + else: + self.char_control_speed.write(bytearray([new_speed])) + + def angle(self, new_angle=None): + if new_angle == None: + return int(self.char_control_angle.read()[0]) + else: + self.char_control_angle.write(bytearray([new_angle])) + + def connect(self): + dev = None + + # connect to the airplane + while not dev: + dev = find_device_by_name("TailorToys PowerUp") + if dev: + self.p = Peripheral() + self.p.connect(dev.addr()) + + # locate interesting characteristics + self.map_chars() + + def rudder_center(self): + if self.old_angle != 0: + self.old_angle = 0 + self.angle(0) + + def rudder_left(self, angle): + steps = (angle // self.interval_size_left) + new_angle = 60 - steps + + if self.old_angle != new_angle: + self.angle(new_angle) + self.old_angle = new_angle + + def rudder_right(self, angle): + steps = (angle // self.interval_size_right) + new_angle = -steps + + if self.old_angle != new_angle: + self.angle(new_angle) + self.old_angle = new_angle + + def throttle(self, speed): + if (speed > 200): + speed = 200 + elif (speed < 0): + speed = 0 + + if self.old_speed != speed: + self.speed(speed) + self.old_speed = speed + + def loop(self): + adc_threshold = 10 + right_threshold = self.x_mid + adc_threshold + left_threshold = self.x_mid - adc_threshold + + self.interval_size_left = self.x_mid // 60 + self.interval_size_right = (255 - self.x_mid) // 60 + + self.old_angle = 0 + self.old_speed = 0 + + while True: + + time.sleep_ms(100) + + # read out new angle + new_angle = self.read_stick_x() + if (new_angle < 256): + if (new_angle > right_threshold): + self.rudder_right(new_angle - self.x_mid) + elif (new_angle < left_threshold): + self.rudder_left(new_angle) + else: + self.rudder_center() + + # read out new speed + new_speed = self.old_speed + + if self.button_speed_up(): + new_speed += 25 + elif self.button_speed_down(): + new_speed -= 25 + elif self.button_speed_full(): + new_speed = 200 + elif self.button_speed_off(): + new_speed = 0 + else: + pass + + self.throttle(new_speed) diff --git a/src/openmv/src/micropython/ports/nrf/examples/seeed_tft.py b/src/openmv/src/micropython/ports/nrf/examples/seeed_tft.py new file mode 100755 index 0000000..c5cd4cc --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/seeed_tft.py @@ -0,0 +1,210 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Glenn Ruben Bakke +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +""" +MicroPython Seeedstudio TFT Shield V2 driver, SPI interfaces, Analog GPIO +Contains SD-card reader, LCD and Touch sensor + +The pca10040 pin layout is used as reference. + +Example usage of LCD: + + from seeedstudio_tft_shield_v2 import ILI9341 + + lcd = ILI9341(240, 320) + lcd.text("Hello World!, 32, 32) + lcd.show() + +Example usage of SD card reader: + + import os + from seeedstudio_tft_shield_v2 import mount_tf + + tf = mount_tf() + os.listdir() +""" +import os +import time +import framebuf + +from machine import SPI, Pin +from sdcard import SDCard + +def mount_tf(self, mount_point="/"): + sd = SDCard(SPI(0), Pin("P15", mode=Pin.OUT)) + os.mount(sd, mount_point) + +class ILI9341: + def __init__(self, width, height): + self.width = width + self.height = height + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + self.framebuf = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + + self.spi = SPI(0) + # chip select + self.cs = Pin("P16", mode=Pin.OUT, pull=Pin.PULL_UP) + # command + self.dc = Pin("P17", mode=Pin.OUT, pull=Pin.PULL_UP) + + # initialize all pins high + self.cs.high() + self.dc.high() + + self.spi.init(baudrate=8000000, phase=0, polarity=0) + + self.init_display() + + + def init_display(self): + time.sleep_ms(500) + + self.write_cmd(0x01) + + time.sleep_ms(200) + + self.write_cmd(0xCF) + self.write_data(bytearray([0x00, 0x8B, 0x30])) + + self.write_cmd(0xED) + self.write_data(bytearray([0x67, 0x03, 0x12, 0x81])) + + self.write_cmd(0xE8) + self.write_data(bytearray([0x85, 0x10, 0x7A])) + + self.write_cmd(0xCB) + self.write_data(bytearray([0x39, 0x2C, 0x00, 0x34, 0x02])) + + self.write_cmd(0xF7) + self.write_data(bytearray([0x20])) + + self.write_cmd(0xEA) + self.write_data(bytearray([0x00, 0x00])) + + # Power control + self.write_cmd(0xC0) + # VRH[5:0] + self.write_data(bytearray([0x1B])) + + # Power control + self.write_cmd(0xC1) + # SAP[2:0];BT[3:0] + self.write_data(bytearray([0x10])) + + # VCM control + self.write_cmd(0xC5) + self.write_data(bytearray([0x3F, 0x3C])) + + # VCM control2 + self.write_cmd(0xC7) + self.write_data(bytearray([0xB7])) + + # Memory Access Control + self.write_cmd(0x36) + self.write_data(bytearray([0x08])) + + self.write_cmd(0x3A) + self.write_data(bytearray([0x55])) + + self.write_cmd(0xB1) + self.write_data(bytearray([0x00, 0x1B])) + + # Display Function Control + self.write_cmd(0xB6) + self.write_data(bytearray([0x0A, 0xA2])) + + # 3Gamma Function Disable + self.write_cmd(0xF2) + self.write_data(bytearray([0x00])) + + # Gamma curve selected + self.write_cmd(0x26) + self.write_data(bytearray([0x01])) + + # Set Gamma + self.write_cmd(0xE0) + self.write_data(bytearray([0x0F, 0x2A, 0x28, 0x08, 0x0E, 0x08, 0x54, 0XA9, 0x43, 0x0A, 0x0F, 0x00, 0x00, 0x00, 0x00])) + + # Set Gamma + self.write_cmd(0XE1) + self.write_data(bytearray([0x00, 0x15, 0x17, 0x07, 0x11, 0x06, 0x2B, 0x56, 0x3C, 0x05, 0x10, 0x0F, 0x3F, 0x3F, 0x0F])) + + # Exit Sleep + self.write_cmd(0x11) + time.sleep_ms(120) + + # Display on + self.write_cmd(0x29) + time.sleep_ms(500) + self.fill(0) + + def show(self): + # set col + self.write_cmd(0x2A) + self.write_data(bytearray([0x00, 0x00])) + self.write_data(bytearray([0x00, 0xef])) + + # set page + self.write_cmd(0x2B) + self.write_data(bytearray([0x00, 0x00])) + self.write_data(bytearray([0x01, 0x3f])) + + self.write_cmd(0x2c); + + num_of_pixels = self.height * self.width + + for row in range(0, self.pages): + for pixel_pos in range(0, 8): + for col in range(0, self.width): + compressed_pixel = self.buffer[row * 240 + col] + if ((compressed_pixel >> pixel_pos) & 0x1) == 0: + self.write_data(bytearray([0x00, 0x00])) + else: + self.write_data(bytearray([0xFF, 0xFF])) + + def fill(self, col): + self.framebuf.fill(col) + + def pixel(self, x, y, col): + self.framebuf.pixel(x, y, col) + + def scroll(self, dx, dy): + self.framebuf.scroll(dx, dy) + + def text(self, string, x, y, col=1): + self.framebuf.text(string, x, y, col) + + def write_cmd(self, cmd): + self.dc.low() + self.cs.low() + self.spi.write(bytearray([cmd])) + self.cs.high() + + def write_data(self, buf): + self.dc.high() + self.cs.low() + self.spi.write(buf) + self.cs.high() + diff --git a/src/openmv/src/micropython/ports/nrf/examples/ssd1306_mod.py b/src/openmv/src/micropython/ports/nrf/examples/ssd1306_mod.py new file mode 100755 index 0000000..d9614e5 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/ssd1306_mod.py @@ -0,0 +1,54 @@ +# NOTE: Modified version to align with implemented I2C API in nrf port. +# +# Examples usage of SSD1306_SPI on pca10040 +# +# from machine import Pin, SPI +# from ssd1306 import SSD1306_SPI +# spi = SPI(0, baudrate=40000000) +# dc = Pin.board.PA11 +# res = Pin.board.PA12 +# cs = Pin.board.PA13 +# disp = SSD1306_SPI(128, 64, spi, dc, res, cs) +# +# +# Example usage of SSD1306_I2C on pca10040 +# +# from machine import Pin, I2C +# from ssd1306_mod import SSD1306_I2C_Mod +# i2c = I2C(0, Pin.board.PA3, Pin.board.PA4) +# disp = SSD1306_I2C_Mod(128, 64, i2c) + +from ssd1306 import SSD1306_I2C + +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) + +class SSD1306_I2C_Mod(SSD1306_I2C): + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + + chunk_size = 254 # 255, excluding opcode. + num_of_chunks = len(self.buffer) // chunk_size + leftover = len(self.buffer) - (num_of_chunks * chunk_size) + + for i in range(0, num_of_chunks): + self.write_data(self.buffer[chunk_size*i:chunk_size*(i+1)]) + if (leftover > 0): + self.write_data(self.buffer[chunk_size * num_of_chunks:]) + + + def write_data(self, buf): + buffer = bytearray([0x40]) + buf # Co=0, D/C#=1 + self.i2c.writeto(self.addr, buffer) diff --git a/src/openmv/src/micropython/ports/nrf/examples/ubluepy_eddystone.py b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_eddystone.py new file mode 100755 index 0000000..c8abd5a --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_eddystone.py @@ -0,0 +1,58 @@ +from ubluepy import Peripheral, constants + +BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE = const(0x02) +BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED = const(0x04) + +BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE = const(BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) + +EDDYSTONE_FRAME_TYPE_URL = const(0x10) +EDDYSTONE_URL_PREFIX_HTTP_WWW = const(0x00) # "http://www". +EDDYSTONE_URL_SUFFIX_DOT_COM = const(0x01) # ".com" + +def string_to_binarray(text): + b = bytearray([]) + for c in text: + b.append(ord(c)) + return b + +def gen_ad_type_content(ad_type, data): + b = bytearray(1) + b.append(ad_type) + b.extend(data) + b[0] = len(b) - 1 + return b + +def generate_eddystone_adv_packet(url): + # flags + disc_mode = bytearray([BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE]) + packet_flags = gen_ad_type_content(constants.ad_types.AD_TYPE_FLAGS, disc_mode) + + # 16-bit uuid + uuid = bytearray([0xAA, 0xFE]) + packet_uuid16 = gen_ad_type_content(constants.ad_types.AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, uuid) + + # eddystone data + rssi = 0xEE # -18 dB, approx signal strength at 0m. + eddystone_data = bytearray([]) + eddystone_data.append(EDDYSTONE_FRAME_TYPE_URL) + eddystone_data.append(rssi) + eddystone_data.append(EDDYSTONE_URL_PREFIX_HTTP_WWW) + eddystone_data.extend(string_to_binarray(url)) + eddystone_data.append(EDDYSTONE_URL_SUFFIX_DOT_COM) + + # service data + service_data = uuid + eddystone_data + packet_service_data = gen_ad_type_content(constants.ad_types.AD_TYPE_SERVICE_DATA, service_data) + + # generate advertisment packet + packet = bytearray([]) + packet.extend(packet_flags) + packet.extend(packet_uuid16) + packet.extend(packet_service_data) + + return packet + +def start(): + adv_packet = generate_eddystone_adv_packet("micropython") + p = Peripheral() + p.advertise(data=adv_packet, connectable=False) \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/nrf/examples/ubluepy_scan.py b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_scan.py new file mode 100755 index 0000000..ab11661 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_scan.py @@ -0,0 +1,38 @@ +from ubluepy import Scanner, constants + +def bytes_to_str(bytes): + string = "" + for b in bytes: + string += chr(b) + return string + +def get_device_names(scan_entries): + dev_names = [] + for e in scan_entries: + scan = e.getScanData() + if scan: + for s in scan: + if s[0] == constants.ad_types.AD_TYPE_COMPLETE_LOCAL_NAME: + dev_names.append((e, bytes_to_str(s[2]))) + return dev_names + +def find_device_by_name(name): + s = Scanner() + scan_res = s.scan(100) + + device_names = get_device_names(scan_res) + for dev in device_names: + if name == dev[1]: + return dev[0] + +# >>> res = find_device_by_name("micr") +# >>> if res: +# ... print("address:", res.addr()) +# ... print("address type:", res.addr_type()) +# ... print("rssi:", res.rssi()) +# ... +# ... +# ... +# address: c2:73:61:89:24:45 +# address type: 1 +# rssi: -26 diff --git a/src/openmv/src/micropython/ports/nrf/examples/ubluepy_temp.py b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_temp.py new file mode 100755 index 0000000..7df057b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/examples/ubluepy_temp.py @@ -0,0 +1,92 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2017 Glenn Ruben Bakke +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE + +from board import LED +from machine import RTCounter, Temp +from ubluepy import Service, Characteristic, UUID, Peripheral, constants + +def event_handler(id, handle, data): + global rtc + global periph + global serv_env_sense + global notif_enabled + + if id == constants.EVT_GAP_CONNECTED: + # indicated 'connected' + LED(1).on() + + elif id == constants.EVT_GAP_DISCONNECTED: + # stop low power timer + rtc.stop() + # indicate 'disconnected' + LED(1).off() + # restart advertisment + periph.advertise(device_name="micr_temp", services=[serv_env_sense]) + + elif id == constants.EVT_GATTS_WRITE: + # write to this Characteristic is to CCCD + if int(data[0]) == 1: + notif_enabled = True + # start low power timer + rtc.start() + else: + notif_enabled = False + # stop low power timer + rtc.stop() + +def send_temp(timer_id): + global notif_enabled + global char_temp + + if notif_enabled: + # measure chip temperature + temp = Temp.read() + temp = temp * 100 + char_temp.write(bytearray([temp & 0xFF, temp >> 8])) + +# start off with LED(1) off +LED(1).off() + +# use RTC1 as RTC0 is used by bluetooth stack +# set up RTC callback every 5 second +rtc = RTCounter(1, period=50, mode=RTCounter.PERIODIC, callback=send_temp) + +notif_enabled = False + +uuid_env_sense = UUID("0x181A") # Environmental Sensing service +uuid_temp = UUID("0x2A6E") # Temperature characteristic + +serv_env_sense = Service(uuid_env_sense) + +temp_props = Characteristic.PROP_NOTIFY | Characteristic.PROP_READ +temp_attrs = Characteristic.ATTR_CCCD +char_temp = Characteristic(uuid_temp, props = temp_props, attrs = temp_attrs) + +serv_env_sense.addCharacteristic(char_temp) + +periph = Peripheral() +periph.addService(serv_env_sense) +periph.setConnectionHandler(event_handler) +periph.advertise(device_name="micr_temp", services=[serv_env_sense]) + diff --git a/src/openmv/src/micropython/ports/nrf/fatfs_port.c b/src/openmv/src/micropython/ports/nrf/fatfs_port.c new file mode 100755 index 0000000..13ac21f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/fatfs_port.c @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" + +DWORD get_fattime(void) { + // TODO: Implement this function. For now, fake it. + return ((2016 - 1980) << 25) | ((12) << 21) | ((4) << 16) | ((00) << 11) | ((18) << 5) | (23 / 2); +} diff --git a/src/openmv/src/micropython/ports/nrf/freeze/test.py b/src/openmv/src/micropython/ports/nrf/freeze/test.py new file mode 100755 index 0000000..e64bbc9 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/freeze/test.py @@ -0,0 +1,4 @@ +import sys + +def hello(): + print("Hello %s!" % sys.platform) diff --git a/src/openmv/src/micropython/ports/nrf/gccollect.c b/src/openmv/src/micropython/ports/nrf/gccollect.c new file mode 100755 index 0000000..68b8188 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/gccollect.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/gc.h" +#include "gccollect.h" + +static inline uintptr_t get_sp(void) { + uintptr_t result; + __asm__ ("mov %0, sp\n" : "=r" (result) ); + return result; +} + +void gc_collect(void) { + // start the GC + gc_collect_start(); + + // Get stack pointer + uintptr_t sp = get_sp(); + + // trace the stack, including the registers (since they live on the stack in this function) + gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t)); + + // end the GC + gc_collect_end(); +} diff --git a/src/openmv/src/micropython/ports/nrf/gccollect.h b/src/openmv/src/micropython/ports/nrf/gccollect.h new file mode 100755 index 0000000..6a285b0 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/gccollect.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GC_COLLECT_H__ +#define GC_COLLECT_H__ + +extern uint32_t _etext; +extern uint32_t _sidata; +extern uint32_t _ram_start; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern uint32_t _heap_start; +extern uint32_t _heap_end; +extern uint32_t _estack; +extern uint32_t _ram_end; + +void gc_collect(void); + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/help.c b/src/openmv/src/micropython/ports/nrf/help.c new file mode 100755 index 0000000..5856ef6 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/help.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +#if BLUETOOTH_SD +#include "help_sd.h" +#endif + +const char nrf5_help_text[] = +"Welcome to MicroPython!\n" +"\n" +"For online help please visit http://micropython.org/help/.\n" +"\n" +"Quick overview of commands for the board:\n" +#if MICROPY_HW_HAS_LED +" board.LED(n) -- create an LED object for LED n (n=" HELP_TEXT_BOARD_LED ")\n" +"\n" +#endif +#if BLUETOOTH_SD +HELP_TEXT_SD +#endif +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; diff --git a/src/openmv/src/micropython/ports/nrf/main.c b/src/openmv/src/micropython/ports/nrf/main.c new file mode 100755 index 0000000..b9c29e7 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/main.c @@ -0,0 +1,330 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/mperrno.h" +#include "py/lexer.h" +#include "py/parse.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/gc.h" +#include "py/compile.h" +#include "lib/utils/pyexec.h" +#include "readline.h" +#include "gccollect.h" +#include "modmachine.h" +#include "modmusic.h" +#include "modules/uos/microbitfs.h" +#include "led.h" +#include "uart.h" +#include "nrf.h" +#include "pin.h" +#include "spi.h" +#include "i2c.h" +#include "adc.h" +#include "rtcounter.h" +#if MICROPY_PY_MACHINE_HW_PWM +#include "pwm.h" +#endif +#include "timer.h" + +#if BLUETOOTH_SD +#include "nrf_sdm.h" +#endif + +#if (MICROPY_PY_BLE_NUS) +#include "ble_uart.h" +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM +#include "ticker.h" +#include "softpwm.h" +#endif + +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + if (lex == NULL) { + printf("MemoryError: lexer could not allocate memory\n"); + return; + } + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + qstr source_name = lex->source_name; + mp_parse_tree_t pn = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&pn, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + +extern uint32_t _heap_start; +extern uint32_t _heap_end; + +int main(int argc, char **argv) { + +soft_reset: + mp_stack_set_top(&_ram_end); + + // Stack limit should be less than real stack size, so we have a chance + // to recover from limit hit. (Limit is measured in bytes.) + mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 400); + + machine_init(); + + gc_init(&_heap_start, &_heap_end); + + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_init(mp_sys_argv, 0); + + pyb_set_repl_info(MP_OBJ_NEW_SMALL_INT(0)); + + readline_init0(); + +#if MICROPY_PY_MACHINE_HW_SPI + spi_init0(); +#endif + +#if MICROPY_PY_MACHINE_I2C + i2c_init0(); +#endif + +#if MICROPY_PY_MACHINE_ADC + adc_init0(); +#endif + +#if MICROPY_PY_MACHINE_HW_PWM + pwm_init0(); +#endif + +#if MICROPY_PY_MACHINE_RTCOUNTER + rtc_init0(); +#endif + +#if MICROPY_PY_MACHINE_TIMER + timer_init0(); +#endif + +#if MICROPY_PY_MACHINE_UART + uart_init0(); +#endif + +#if (MICROPY_PY_BLE_NUS == 0) + { + mp_obj_t args[2] = { + MP_OBJ_NEW_SMALL_INT(0), + MP_OBJ_NEW_SMALL_INT(115200), + }; + MP_STATE_PORT(board_stdio_uart) = machine_hard_uart_type.make_new((mp_obj_t)&machine_hard_uart_type, MP_ARRAY_SIZE(args), 0, args); + } +#endif + +pin_init0(); + +#if MICROPY_MBFS + microbit_filesystem_init(); +#endif + +#if MICROPY_HW_HAS_SDCARD + // if an SD card is present then mount it on /sd/ + if (sdcard_is_present()) { + // create vfs object + fs_user_mount_t *vfs = m_new_obj_maybe(fs_user_mount_t); + if (vfs == NULL) { + goto no_mem_for_sd; + } + vfs->str = "/sd"; + vfs->len = 3; + vfs->flags = FSUSER_FREE_OBJ; + sdcard_init_vfs(vfs); + + // put the sd device in slot 1 (it will be unused at this point) + MP_STATE_PORT(fs_user_mount)[1] = vfs; + + FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1); + if (res != FR_OK) { + printf("MPY: can't mount SD card\n"); + MP_STATE_PORT(fs_user_mount)[1] = NULL; + m_del_obj(fs_user_mount_t, vfs); + } else { + // TODO these should go before the /flash entries in the path + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib)); + + // use SD card as current directory + f_chdrive("/sd"); + } + no_mem_for_sd:; + } +#endif + +#if (MICROPY_HW_HAS_LED) + led_init(); + + do_str("import board\r\n" \ + "board.LED(1).on()", + MP_PARSE_FILE_INPUT); +#endif + + // Main script is finished, so now go into REPL mode. + // The REPL mode can change, or it can request a soft reset. + int ret_code = 0; + +#if MICROPY_PY_BLE_NUS + ble_uart_init0(); +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM + ticker_init0(); + softpwm_init0(); +#endif + +#if MICROPY_PY_MUSIC + microbit_music_init0(); +#endif +#if BOARD_SPECIFIC_MODULES + board_modules_init0(); +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM + ticker_start(); + pwm_start(); +#endif + +#if MICROPY_VFS || MICROPY_MBFS + // run boot.py and main.py if they exist. + if (mp_import_stat("boot.py") == MP_IMPORT_STAT_FILE) { + pyexec_file("boot.py"); + } + if (mp_import_stat("main.py") == MP_IMPORT_STAT_FILE) { + pyexec_file("main.py"); + } +#endif + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + ret_code = pyexec_friendly_repl(); + if (ret_code != 0) { + break; + } + } + } + + mp_deinit(); + + printf("MPY: soft reboot\n"); + +#if BLUETOOTH_SD + sd_softdevice_disable(); +#endif + + goto soft_reset; + + return 0; +} + +#if !MICROPY_VFS +#if MICROPY_MBFS +// Use micro:bit filesystem +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + return uos_mbfs_new_reader(filename); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return uos_mbfs_import_stat(path); +} + +STATIC mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args) { + return uos_mbfs_open(n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open); + +#else +// use dummy functions - no filesystem available +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + mp_raise_OSError(MP_EPERM); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); +#endif +#endif + +void HardFault_Handler(void) +{ +#if defined(NRF52_SERIES) + static volatile uint32_t reg; + static volatile uint32_t reg2; + static volatile uint32_t bfar; + reg = SCB->HFSR; + reg2 = SCB->CFSR; + bfar = SCB->BFAR; + for (int i = 0; i < 0; i++) + { + (void)reg; + (void)reg2; + (void)bfar; + } +#endif +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)val); + __fatal_error(""); +} + +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} + +void _start(void) {main(0, NULL);} diff --git a/src/openmv/src/micropython/ports/nrf/modules/ble/help_sd.h b/src/openmv/src/micropython/ports/nrf/modules/ble/help_sd.h new file mode 100755 index 0000000..027bbdd --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ble/help_sd.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HELP_SD_H__ +#define HELP_SD_H__ + +#include "bluetooth_conf.h" + +#if MICROPY_PY_BLE + +#define HELP_TEXT_SD \ +"If compiled with SD= the additional commands are\n" \ +"available:\n" \ +" ble.enable() -- enable bluetooth stack\n" \ +" ble.disable() -- disable bluetooth stack\n" \ +" ble.enabled() -- check whether bluetooth stack is enabled\n" \ +" ble.address() -- return device address as text string\n" \ +"\n" + +#else +#define HELP_TEXT_SD +#endif // MICROPY_PY_BLE + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/modules/ble/modble.c b/src/openmv/src/micropython/ports/nrf/modules/ble/modble.c new file mode 100755 index 0000000..2b6dd6e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ble/modble.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/runtime.h" + +#if MICROPY_PY_BLE + +#include "led.h" +#include "mpconfigboard.h" +#include "ble_drv.h" + +/// \method enable() +/// Enable BLE softdevice. +mp_obj_t ble_obj_enable(void) { + printf("SoftDevice enabled\n"); + uint32_t err_code = ble_drv_stack_enable(); + if (err_code < 0) { + // TODO: raise exception. + } + return mp_const_none; +} + +/// \method disable() +/// Disable BLE softdevice. +mp_obj_t ble_obj_disable(void) { + ble_drv_stack_disable(); + return mp_const_none; +} + +/// \method enabled() +/// Get state of whether the softdevice is enabled or not. +mp_obj_t ble_obj_enabled(void) { + uint8_t is_enabled = ble_drv_stack_enabled(); + mp_int_t enabled = is_enabled; + return MP_OBJ_NEW_SMALL_INT(enabled); +} + +/// \method address() +/// Return device address as text string. +mp_obj_t ble_obj_address(void) { + ble_drv_addr_t local_addr; + ble_drv_address_get(&local_addr); + + vstr_t vstr; + vstr_init(&vstr, 17); + + vstr_printf(&vstr, ""HEX2_FMT":"HEX2_FMT":"HEX2_FMT":" \ + HEX2_FMT":"HEX2_FMT":"HEX2_FMT"", + local_addr.addr[5], local_addr.addr[4], local_addr.addr[3], + local_addr.addr[2], local_addr.addr[1], local_addr.addr[0]); + + mp_obj_t mac_str = mp_obj_new_str(vstr.buf, vstr.len); + + vstr_clear(&vstr); + + return mac_str; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_enable_obj, ble_obj_enable); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_disable_obj, ble_obj_disable); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_enabled_obj, ble_obj_enabled); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_obj_address_obj, ble_obj_address); + +STATIC const mp_rom_map_elem_t ble_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ble) }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&ble_obj_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&ble_obj_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&ble_obj_enabled_obj) }, + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&ble_obj_address_obj) }, +}; + + +STATIC MP_DEFINE_CONST_DICT(ble_module_globals, ble_module_globals_table); + +const mp_obj_module_t ble_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&ble_module_globals, +}; + +#endif // MICROPY_PY_BLE diff --git a/src/openmv/src/micropython/ports/nrf/modules/board/led.c b/src/openmv/src/micropython/ports/nrf/modules/board/led.c new file mode 100755 index 0000000..a576b70 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/board/led.c @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2015 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "mphalport.h" +#include "led.h" +#include "mpconfigboard.h" + +#if MICROPY_HW_HAS_LED + +#define LED_OFF(pin) {(MICROPY_HW_LED_PULLUP) ? nrf_gpio_pin_set(pin) : nrf_gpio_pin_clear(pin); } +#define LED_ON(pin) {(MICROPY_HW_LED_PULLUP) ? nrf_gpio_pin_clear(pin) : nrf_gpio_pin_set(pin); } + +typedef struct _board_led_obj_t { + mp_obj_base_t base; + mp_uint_t led_id; + mp_uint_t hw_pin; + uint8_t hw_pin_port; +} board_led_obj_t; + +STATIC const board_led_obj_t board_led_obj[] = { +#if MICROPY_HW_LED_TRICOLOR + {{&board_led_type}, BOARD_LED_RED, MICROPY_HW_LED_RED}, + {{&board_led_type}, BOARD_LED_GREEN, MICROPY_HW_LED_GREEN}, + {{&board_led_type}, BOARD_LED_BLUE, MICROPY_HW_LED_BLUE}, +#elif (MICROPY_HW_LED_COUNT == 1) + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, +#elif (MICROPY_HW_LED_COUNT == 2) + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, + {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2}, +#else + {{&board_led_type}, BOARD_LED1, MICROPY_HW_LED1}, + {{&board_led_type}, BOARD_LED2, MICROPY_HW_LED2}, + {{&board_led_type}, BOARD_LED3, MICROPY_HW_LED3}, + {{&board_led_type}, BOARD_LED4, MICROPY_HW_LED4}, +#endif +}; + +#define NUM_LEDS MP_ARRAY_SIZE(board_led_obj) + +void led_init(void) { + for (uint8_t i = 0; i < NUM_LEDS; i++) { + LED_OFF(board_led_obj[i].hw_pin); + nrf_gpio_cfg_output(board_led_obj[i].hw_pin); + } +} + +void led_state(board_led_obj_t * led_obj, int state) { + if (state == 1) { + LED_ON(led_obj->hw_pin); + } else { + LED_OFF(led_obj->hw_pin); + } +} + +void led_toggle(board_led_obj_t * led_obj) { + nrf_gpio_pin_toggle(led_obj->hw_pin); +} + + + +/******************************************************************************/ +/* MicroPython bindings */ + +void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + board_led_obj_t *self = self_in; + mp_printf(print, "LED(%lu)", self->led_id); +} + +/// \classmethod \constructor(id) +/// Create an LED object associated with the given LED: +/// +/// - `id` is the LED number, 1-4. +STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get led number + mp_int_t led_id = mp_obj_get_int(args[0]); + + // check led number + if (!(1 <= led_id && led_id <= NUM_LEDS)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) does not exist", led_id)); + } + + // return static led object + return (mp_obj_t)&board_led_obj[led_id - 1]; +} + +/// \method on() +/// Turn the LED on. +mp_obj_t led_obj_on(mp_obj_t self_in) { + board_led_obj_t *self = self_in; + led_state(self, 1); + return mp_const_none; +} + +/// \method off() +/// Turn the LED off. +mp_obj_t led_obj_off(mp_obj_t self_in) { + board_led_obj_t *self = self_in; + led_state(self, 0); + return mp_const_none; +} + +/// \method toggle() +/// Toggle the LED between on and off. +mp_obj_t led_obj_toggle(mp_obj_t self_in) { + board_led_obj_t *self = self_in; + led_toggle(self); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle); + +STATIC const mp_rom_map_elem_t led_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table); + +const mp_obj_type_t board_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = led_obj_print, + .make_new = led_obj_make_new, + .locals_dict = (mp_obj_dict_t*)&led_locals_dict, +}; + +#endif // MICROPY_HW_HAS_LED diff --git a/src/openmv/src/micropython/ports/nrf/modules/board/led.h b/src/openmv/src/micropython/ports/nrf/modules/board/led.h new file mode 100755 index 0000000..6210039 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/board/led.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef LED_H +#define LED_H + +typedef enum { +#if MICROPY_HW_LED_TRICOLOR + BOARD_LED_RED = 1, + BOARD_LED_GREEN = 2, + BOARD_LED_BLUE = 3 +#elif (MICROPY_HW_LED_COUNT == 1) + BOARD_LED1 = 1, +#elif (MICROPY_HW_LED_COUNT == 2) + BOARD_LED1 = 1, + BOARD_LED2 = 2, +#else + BOARD_LED1 = 1, + BOARD_LED2 = 2, + BOARD_LED3 = 3, + BOARD_LED4 = 4 +#endif +} board_led_t; + +void led_init(void); + +extern const mp_obj_type_t board_led_type; + +#endif // LED_H diff --git a/src/openmv/src/micropython/ports/nrf/modules/board/modboard.c b/src/openmv/src/micropython/ports/nrf/modules/board/modboard.c new file mode 100755 index 0000000..354a616 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/board/modboard.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" +#include "lib/utils/pyexec.h" +#include "py/runtime.h" +#include "py/obj.h" +#include "led.h" +#include "nrf.h" // TODO: figure out where to put this import +#include "pin.h" + +#if MICROPY_HW_HAS_LED +#define PYB_LED_MODULE { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&board_led_type) }, +#else +#define PYB_LED_MODULE +#endif + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, + { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + PYB_LED_MODULE +}; + + +STATIC MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); + +const mp_obj_module_t board_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&board_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/adc.c b/src/openmv/src/micropython/ports/nrf/modules/machine/adc.c new file mode 100755 index 0000000..ce48056 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/adc.c @@ -0,0 +1,283 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_ADC + +#include "adc.h" + +#if NRF51 + #include "nrfx_adc.h" +#else + #include "nrfx_saadc.h" +#endif + +typedef struct _machine_adc_obj_t { + mp_obj_base_t base; + uint8_t id; +#if NRF51 + uint8_t ain; +#endif +} machine_adc_obj_t; + +STATIC const machine_adc_obj_t machine_adc_obj[] = { +#if NRF51 + {{&machine_adc_type}, .id = 0, .ain = NRF_ADC_CONFIG_INPUT_0}, + {{&machine_adc_type}, .id = 1, .ain = NRF_ADC_CONFIG_INPUT_1}, + {{&machine_adc_type}, .id = 2, .ain = NRF_ADC_CONFIG_INPUT_2}, + {{&machine_adc_type}, .id = 3, .ain = NRF_ADC_CONFIG_INPUT_3}, + {{&machine_adc_type}, .id = 4, .ain = NRF_ADC_CONFIG_INPUT_4}, + {{&machine_adc_type}, .id = 5, .ain = NRF_ADC_CONFIG_INPUT_5}, + {{&machine_adc_type}, .id = 6, .ain = NRF_ADC_CONFIG_INPUT_6}, + {{&machine_adc_type}, .id = 7, .ain = NRF_ADC_CONFIG_INPUT_7}, +#else + {{&machine_adc_type}, .id = 0}, + {{&machine_adc_type}, .id = 1}, + {{&machine_adc_type}, .id = 2}, + {{&machine_adc_type}, .id = 3}, + {{&machine_adc_type}, .id = 4}, + {{&machine_adc_type}, .id = 5}, + {{&machine_adc_type}, .id = 6}, + {{&machine_adc_type}, .id = 7}, +#endif +}; + +#if defined(NRF52_SERIES) +STATIC void saadc_event_handler(nrfx_saadc_evt_t const * p_event) { + (void)p_event; +} +#endif + +void adc_init0(void) { +#if defined(NRF52_SERIES) + const nrfx_saadc_config_t config = { + .resolution = NRF_SAADC_RESOLUTION_8BIT, + .oversample = NRF_SAADC_OVERSAMPLE_DISABLED, + .interrupt_priority = 6, + .low_power_mode = false + }; + + nrfx_saadc_init(&config, saadc_event_handler); +#endif +} + +STATIC int adc_find(mp_obj_t id) { + // given an integer id + int adc_id = mp_obj_get_int(id); + + int adc_idx = adc_id; + + if (adc_idx >= 0 && adc_idx < MP_ARRAY_SIZE(machine_adc_obj) + && machine_adc_obj[adc_idx].id != (uint8_t)-1) { + return adc_idx; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "ADC(%d) does not exist", adc_id)); +} + +/// \method __str__() +/// Return a string describing the ADC object. +STATIC void machine_adc_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_adc_obj_t *self = o; + + mp_printf(print, "ADC(%u)", self->id); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1) } }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int adc_id = adc_find(args[ARG_id].u_obj); + const machine_adc_obj_t *self = &machine_adc_obj[adc_id]; + +#if defined(NRF52_SERIES) + const nrf_saadc_channel_config_t config = { + .resistor_p = NRF_SAADC_RESISTOR_DISABLED, + .resistor_n = NRF_SAADC_RESISTOR_DISABLED, + .gain = NRF_SAADC_GAIN1_4, + .reference = NRF_SAADC_REFERENCE_VDD4, + .acq_time = NRF_SAADC_ACQTIME_3US, + .mode = NRF_SAADC_MODE_SINGLE_ENDED, + .burst = NRF_SAADC_BURST_DISABLED, + .pin_p = self->id, // 0 - 7 + .pin_n = NRF_SAADC_INPUT_DISABLED + }; + + nrfx_saadc_channel_init(self->id, &config); +#endif + + return MP_OBJ_FROM_PTR(self); +} + +int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj) { + +#if NRF51 + nrf_adc_value_t value = 0; + + nrfx_adc_channel_t channel_config = { + .config.resolution = NRF_ADC_CONFIG_RES_8BIT, + .config.input = NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS, + .config.reference = NRF_ADC_CONFIG_REF_VBG, + .config.input = adc_obj->ain, + .config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal. + }; + + nrfx_adc_sample_convert(&channel_config, &value); +#else // NRF52 + nrf_saadc_value_t value = 0; + + nrfx_saadc_sample_convert(adc_obj->id, &value); +#endif + return value; +} + + +/// \method value() +/// Read adc level. +mp_obj_t machine_adc_value(mp_obj_t self_in) { + machine_adc_obj_t *self = self_in; + + int16_t value = machine_adc_value_read(self); + + return MP_OBJ_NEW_SMALL_INT(value); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_machine_adc_value_obj, machine_adc_value); + +#if NRF51 + +#define ADC_REF_VOLTAGE_IN_MILLIVOLT (1200) // Reference voltage in mV (1.2V). +#define ADC_PRE_SCALING_MULTIPLIER (3) // VDD 1/3 prescaling as input. Hence, multiplied by 3 to get the value of the battery voltage. + +#else // NRF52 + +#define ADC_REF_VOLTAGE_IN_MILLIVOLT (600) // Reference voltage in mV (0.6V). +#define ADC_PRE_SCALING_MULTIPLIER (6) // VDD 1/6 prescaling as input. Hence, multiplied by 6 to get the value of the battery voltage. + +#endif + +#define DIODE_VOLT_DROP_MILLIVOLT (270) // Voltage drop over diode. + +#define BATTERY_MILLIVOLT(VALUE) \ + ((((VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLT) / 255) * ADC_PRE_SCALING_MULTIPLIER) + +static uint8_t battery_level_in_percent(const uint16_t mvolts) +{ + uint8_t battery_level; + + if (mvolts >= 3000) { + battery_level = 100; + } else if (mvolts > 2900) { + battery_level = 100 - ((3000 - mvolts) * 58) / 100; + } else if (mvolts > 2740) { + battery_level = 42 - ((2900 - mvolts) * 24) / 160; + } else if (mvolts > 2440) { + battery_level = 18 - ((2740 - mvolts) * 12) / 300; + } else if (mvolts > 2100) { + battery_level = 6 - ((2440 - mvolts) * 6) / 340; + } else { + battery_level = 0; + } + + return battery_level; +} + +/// \method battery_level() +/// Get battery level in percentage. +mp_obj_t machine_adc_battery_level(void) { + +#if NRF51 + nrf_adc_value_t value = 0; + + nrfx_adc_channel_t channel_config = { + .config.resolution = NRF_ADC_CONFIG_RES_8BIT, + .config.input = NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD, + .config.reference = NRF_ADC_CONFIG_REF_VBG, + .config.input = NRF_ADC_CONFIG_INPUT_DISABLED, + .config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal. + }; + + nrfx_adc_sample_convert(&channel_config, &value); +#else // NRF52 + nrf_saadc_value_t value = 0; + + const nrf_saadc_channel_config_t config = { + .resistor_p = NRF_SAADC_RESISTOR_DISABLED, + .resistor_n = NRF_SAADC_RESISTOR_DISABLED, + .gain = NRF_SAADC_GAIN1_6, + .reference = NRF_SAADC_REFERENCE_INTERNAL, + .acq_time = NRF_SAADC_ACQTIME_3US, + .mode = NRF_SAADC_MODE_SINGLE_ENDED, + .burst = NRF_SAADC_BURST_DISABLED, + .pin_p = NRF_SAADC_INPUT_VDD, + .pin_n = NRF_SAADC_INPUT_DISABLED + }; + + nrfx_saadc_channel_init(0, &config); + nrfx_saadc_sample_convert(0, &value); +#endif + + uint16_t batt_lvl_in_milli_volts = BATTERY_MILLIVOLT(value) + DIODE_VOLT_DROP_MILLIVOLT; + uint16_t batt_in_percent = battery_level_in_percent(batt_lvl_in_milli_volts); + + return MP_OBJ_NEW_SMALL_INT(batt_in_percent); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_machine_adc_battery_level_obj, machine_adc_battery_level); + +STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&mp_machine_adc_value_obj) }, + + // class methods + { MP_ROM_QSTR(MP_QSTR_battery_level), MP_ROM_PTR(&mp_machine_adc_battery_level_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .make_new = machine_adc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict, + .print = machine_adc_print, +}; + +#endif // MICROPY_PY_MACHINE_ADC diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/adc.h b/src/openmv/src/micropython/ports/nrf/modules/machine/adc.h new file mode 100755 index 0000000..cefccff --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/adc.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef ADC_H__ +#define ADC_H__ + +typedef struct _machine_adc_obj_t machine_adc_obj_t; + +extern const mp_obj_type_t machine_adc_type; + +void adc_init0(void); + +int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj); + +#endif // ADC_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.c b/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.c new file mode 100755 index 0000000..15f024f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.c @@ -0,0 +1,161 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/machine_i2c.h" +#include "i2c.h" +#include "nrfx_twi.h" + +#if MICROPY_PY_MACHINE_I2C + +STATIC const mp_obj_type_t machine_hard_i2c_type; + +typedef struct _machine_hard_i2c_obj_t { + mp_obj_base_t base; + nrfx_twi_t p_twi; // Driver instance +} machine_hard_i2c_obj_t; + +STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { + {{&machine_hard_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(0)}, + {{&machine_hard_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(1)}, +}; + +void i2c_init0(void) { +} + +STATIC int i2c_find(mp_obj_t id) { + // given an integer id + int i2c_id = mp_obj_get_int(id); + if (i2c_id >= 0 && i2c_id < MP_ARRAY_SIZE(machine_hard_i2c_obj)) { + return i2c_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%d) does not exist", i2c_id)); +} + +STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_i2c_obj_t *self = self_in; + mp_printf(print, "I2C(%u)", self->p_twi.drv_inst_idx); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_scl, ARG_sda }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int i2c_id = i2c_find(args[ARG_id].u_obj); + const machine_hard_i2c_obj_t *self = &machine_hard_i2c_obj[i2c_id]; + + nrfx_twi_config_t config; + config.scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj)->pin; + config.sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj)->pin; + + config.frequency = NRF_TWI_FREQ_400K; + + config.hold_bus_uninit = false; + + // Set context to this object. + nrfx_twi_init(&self->p_twi, &config, NULL, (void *)self); + + return MP_OBJ_FROM_PTR(self); +} + +int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; + + nrfx_twi_enable(&self->p_twi); + + nrfx_err_t err_code = nrfx_twi_rx(&self->p_twi, addr, dest, len); + + if (err_code != NRFX_SUCCESS) { + if (err_code == NRFX_ERROR_DRV_TWI_ERR_ANACK) { + return -MP_ENODEV; + } + else if (err_code == NRFX_ERROR_DRV_TWI_ERR_DNACK) { + return -MP_EIO; + } + return -MP_ETIMEDOUT; + } + + nrfx_twi_disable(&self->p_twi); + + return 0; +} + +int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t *)self_in; + + nrfx_twi_enable(&self->p_twi); + + nrfx_err_t err_code = nrfx_twi_tx(&self->p_twi, addr, src, len, !stop); + + if (err_code != NRFX_SUCCESS) { + if (err_code == NRFX_ERROR_DRV_TWI_ERR_ANACK) { + return -MP_ENODEV; + } + else if (err_code == NRFX_ERROR_DRV_TWI_ERR_DNACK) { + return -MP_EIO; + } + return -MP_ETIMEDOUT; + } + + nrfx_twi_disable(&self->p_twi); + + return len; +} + +STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { + .readfrom = machine_hard_i2c_readfrom, + .writeto = machine_hard_i2c_writeto, +}; + +STATIC const mp_obj_type_t machine_hard_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_hard_i2c_print, + .make_new = machine_hard_i2c_make_new, + .protocol = &machine_hard_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_I2C diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.h b/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.h new file mode 100755 index 0000000..92194ce --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/i2c.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef I2C_H__ +#define I2C_H__ + +extern const mp_obj_type_t machine_i2c_type; + +void i2c_init0(void); + +#endif // I2C_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.c b/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.c new file mode 100755 index 0000000..fca86e8 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.c @@ -0,0 +1,246 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "modmachine.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "lib/utils/pyexec.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "gccollect.h" +#include "pin.h" +#include "uart.h" +#include "spi.h" +#include "i2c.h" +#include "timer.h" +#if MICROPY_PY_MACHINE_HW_PWM +#include "pwm.h" +#endif +#if MICROPY_PY_MACHINE_ADC +#include "adc.h" +#endif +#if MICROPY_PY_MACHINE_TEMP +#include "temp.h" +#endif +#if MICROPY_PY_MACHINE_RTCOUNTER +#include "rtcounter.h" +#endif + +#define PYB_RESET_HARD (0) +#define PYB_RESET_WDT (1) +#define PYB_RESET_SOFT (2) +#define PYB_RESET_LOCKUP (3) +#define PYB_RESET_POWER_ON (16) +#define PYB_RESET_LPCOMP (17) +#define PYB_RESET_DIF (18) +#define PYB_RESET_NFC (19) + +STATIC uint32_t reset_cause; + +void machine_init(void) { + uint32_t state = NRF_POWER->RESETREAS; + if (state & POWER_RESETREAS_RESETPIN_Msk) { + reset_cause = PYB_RESET_HARD; + } else if (state & POWER_RESETREAS_DOG_Msk) { + reset_cause = PYB_RESET_WDT; + } else if (state & POWER_RESETREAS_SREQ_Msk) { + reset_cause = PYB_RESET_SOFT; + } else if (state & POWER_RESETREAS_LOCKUP_Msk) { + reset_cause = PYB_RESET_LOCKUP; + } else if (state & POWER_RESETREAS_OFF_Msk) { + reset_cause = PYB_RESET_POWER_ON; + } else if (state & POWER_RESETREAS_LPCOMP_Msk) { + reset_cause = PYB_RESET_LPCOMP; + } else if (state & POWER_RESETREAS_DIF_Msk) { + reset_cause = PYB_RESET_DIF; +#if defined(NRF52_SERIES) + } else if (state & POWER_RESETREAS_NFC_Msk) { + reset_cause = PYB_RESET_NFC; +#endif + } + + // clear reset reason + NRF_POWER->RESETREAS = (1 << reset_cause); +} + +// machine.info([dump_alloc_table]) +// Print out lots of information about the board. +STATIC mp_obj_t machine_info(mp_uint_t n_args, const mp_obj_t *args) { + // to print info about memory + { + printf("_etext=%p\n", &_etext); + printf("_sidata=%p\n", &_sidata); + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_ram_start=%p\n", &_ram_start); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + printf("_ram_end=%p\n", &_ram_end); + } + + // qstr info + { + mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + } + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info); + +// Resets the board in a manner similar to pushing the external RESET button. +STATIC mp_obj_t machine_reset(void) { + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + +STATIC mp_obj_t machine_sleep(void) { + __WFE(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(void) { + __WFI(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(void) { + return MP_OBJ_NEW_SMALL_INT(reset_cause); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC mp_obj_t machine_enable_irq(void) { +#ifndef BLUETOOTH_SD + __enable_irq(); +#else + +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_enable_irq_obj, machine_enable_irq); + +// Resets the board in a manner similar to pushing the external RESET button. +STATIC mp_obj_t machine_disable_irq(void) { +#ifndef BLUETOOTH_SD + __disable_irq(); +#else + +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&random_module) }, +#endif + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, +#if MICROPY_PY_MACHINE_UART + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_hard_uart_type) }, +#endif +#if MICROPY_PY_MACHINE_HW_SPI + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, +#endif +#if MICROPY_PY_MACHINE_I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, +#endif +#if MICROPY_PY_MACHINE_ADC + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, +#endif +#if MICROPY_PY_MACHINE_RTCOUNTER + { MP_ROM_QSTR(MP_QSTR_RTCounter), MP_ROM_PTR(&machine_rtcounter_type) }, +#endif +#if MICROPY_PY_MACHINE_TIMER + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, +#endif +#if MICROPY_PY_MACHINE_HW_PWM + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_hard_pwm_type) }, +#endif +#if MICROPY_PY_MACHINE_TEMP + { MP_ROM_QSTR(MP_QSTR_Temp), MP_ROM_PTR(&machine_temp_type) }, +#endif + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_RESET_HARD) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_RESET_WDT) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_RESET_SOFT) }, + { MP_ROM_QSTR(MP_QSTR_LOCKUP_RESET), MP_ROM_INT(PYB_RESET_LOCKUP) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) }, + { MP_ROM_QSTR(MP_QSTR_LPCOMP_RESET), MP_ROM_INT(PYB_RESET_LPCOMP) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_IF_RESET), MP_ROM_INT(PYB_RESET_DIF) }, +#if defined(NRF52_SERIES) + { MP_ROM_QSTR(MP_QSTR_NFC_RESET), MP_ROM_INT(PYB_RESET_NFC) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t machine_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.h b/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.h new file mode 100755 index 0000000..76b4ad7 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/modmachine.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ +#define __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ + +#include "py/mpstate.h" +#include "py/nlr.h" +#include "py/obj.h" + +void machine_init(void); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); + +#endif // __MICROPY_INCLUDED_NRF5_MODMACHINE_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/pin.c b/src/openmv/src/micropython/ports/nrf/modules/machine/pin.c new file mode 100755 index 0000000..df4eb47 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/pin.c @@ -0,0 +1,713 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016, 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" +#include "nrf_gpio.h" +#include "nrfx_gpiote.h" + +extern const pin_obj_t machine_pin_obj[]; +extern const uint8_t machine_pin_num_of_pins; + +/// \moduleref machine +/// \class Pin - control I/O pins +/// +/// A pin is the basic object to control I/O pins. It has methods to set +/// the mode of the pin (input, output, etc) and methods to get and set the +/// digital logic level. For analog control of a pin, see the ADC class. +/// +/// Usage Model: +/// +/// All Board Pins are predefined as machine.Pin.board.Name +/// +/// x1_pin = machine.Pin.board.X1 +/// +/// g = machine.Pin(machine.Pin.board.X1, machine.Pin.IN) +/// +/// CPU pins which correspond to the board pins are available +/// as `machine.cpu.Name`. For the CPU pins, the names are the port letter +/// followed by the pin number. On the PYBv1.0, `machine.Pin.board.X1` and +/// `machine.Pin.cpu.B6` are the same pin. +/// +/// You can also use strings: +/// +/// g = machine.Pin('X1', machine.Pin.OUT) +/// +/// Users can add their own names: +/// +/// MyMapperDict = { 'LeftMotorDir' : machine.Pin.cpu.C12 } +/// machine.Pin.dict(MyMapperDict) +/// g = machine.Pin("LeftMotorDir", machine.Pin.OUT) +/// +/// and can query mappings +/// +/// pin = machine.Pin("LeftMotorDir") +/// +/// Users can also add their own mapping function: +/// +/// def MyMapper(pin_name): +/// if pin_name == "LeftMotorDir": +/// return machine.Pin.cpu.A0 +/// +/// machine.Pin.mapper(MyMapper) +/// +/// So, if you were to call: `machine.Pin("LeftMotorDir", machine.Pin.OUT)` +/// then `"LeftMotorDir"` is passed directly to the mapper function. +/// +/// To summarise, the following order determines how things get mapped into +/// an ordinal pin number: +/// +/// 1. Directly specify a pin object +/// 2. User supplied mapping function +/// 3. User supplied mapping (object must be usable as a dictionary key) +/// 4. Supply a string which matches a board pin +/// 5. Supply a string which matches a CPU port/pin +/// +/// You can set `machine.Pin.debug(True)` to get some debug information about +/// how a particular object gets mapped to a pin. + +#define PIN_DEBUG (0) + +// Pin class variables +#if PIN_DEBUG +STATIC bool pin_class_debug; +#else +#define pin_class_debug (0) +#endif + +void pin_init0(void) { + MP_STATE_PORT(pin_class_mapper) = mp_const_none; + MP_STATE_PORT(pin_class_map_dict) = mp_const_none; + for (int i = 0; i < NUM_OF_PINS; i++) { + MP_STATE_PORT(pin_irq_handlers)[i] = mp_const_none; + } + // Initialize GPIOTE if not done yet. + if (!nrfx_gpiote_is_init()) { + nrfx_gpiote_init(); + } + + #if PIN_DEBUG + pin_class_debug = false; + #endif +} + +// C API used to convert a user-supplied pin name into an ordinal pin number. +const pin_obj_t *pin_find(mp_obj_t user_obj) { + const pin_obj_t *pin_obj; + // If pin is SMALL_INT + if (MP_OBJ_IS_SMALL_INT(user_obj)) { + uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj); + for (uint8_t i = 0; i < machine_pin_num_of_pins; i++) { + if (machine_pin_obj[i].pin == value) { + return &machine_pin_obj[i]; + } + } + } + + // If a pin was provided, then use it + if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + pin_obj = user_obj; + if (pin_class_debug) { + printf("Pin map passed pin "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) { + pin_obj = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj); + if (pin_obj != mp_const_none) { + if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + mp_raise_ValueError("Pin.mapper didn't return a Pin object"); + } + if (pin_class_debug) { + printf("Pin.mapper maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + // The pin mapping function returned mp_const_none, fall through to + // other lookup methods. + } + + if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) { + mp_map_t *pin_map_map = mp_obj_dict_get_map(MP_STATE_PORT(pin_class_map_dict)); + mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP); + if (elem != NULL && elem->value != NULL) { + pin_obj = elem->value; + if (pin_class_debug) { + printf("Pin.map_dict maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + } + + // See if the pin name matches a board pin + pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.board maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + // See if the pin name matches a cpu pin + pin_obj = pin_find_named_pin(&pin_cpu_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.cpu maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print((mp_obj_t)pin_obj, PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", mp_obj_str_get_str(user_obj))); +} + +/// \method __str__() +/// Return a string describing the pin object. +STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_obj_t *self = self_in; + + // pin name + mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name); + mp_printf(print, "port=0x%x, ", self->pin / 32); + mp_printf(print, "pin=0x%x, ", self->pin); +/* + uint32_t mode = pin_get_mode(self); + + if (mode == GPIO_MODE_ANALOG) { + // analog + mp_print_str(print, "ANALOG)"); + + } else { + // IO mode + bool af = false; + qstr mode_qst; + if (mode == GPIO_MODE_INPUT) { + mode_qst = MP_QSTR_IN; + } else if (mode == GPIO_MODE_OUTPUT_PP) { + mode_qst = MP_QSTR_OUT; + } else if (mode == GPIO_MODE_OUTPUT_OD) { + mode_qst = MP_QSTR_OPEN_DRAIN; + } else { + af = true; + if (mode == GPIO_MODE_AF_PP) { + mode_qst = MP_QSTR_ALT; + } else { + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; + } + } + mp_print_str(print, qstr_str(mode_qst)); + // pull mode + qstr pull_qst = MP_QSTR_NULL; + uint32_t pull = pin_get_pull(self); + if (pull == GPIO_PULLUP) { + pull_qst = MP_QSTR_PULL_UP; + } else if (pull == GPIO_PULLDOWN) { + pull_qst = MP_QSTR_PULL_DOWN; + } + if (pull_qst != MP_QSTR_NULL) { + mp_printf(print, ", pull=Pin.%q", pull_qst); + } + // AF mode + if (af) { + mp_uint_t af_idx = pin_get_af(self); + const pin_af_obj_t *af_obj = pin_find_af_by_index(self, af_idx); + if (af_obj == NULL) { + mp_printf(print, ", af=%d)", af_idx); + } else { + mp_printf(print, ", af=Pin.%q)", af_obj->name); + } + } else { +*/ + mp_print_str(print, ")"); + /* } + }*/ + +} + +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args); + +/// \classmethod \constructor(id, ...) +/// Create a new Pin object associated with the id. If additional arguments are given, +/// they are used to initialise the pin. See `init`. +STATIC mp_obj_t pin_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + const pin_obj_t *pin = pin_find(args[0]); + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self)); + } else { + // set pin + mp_hal_pin_write(self, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +STATIC mp_obj_t pin_off(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_low(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_off_obj, pin_off); + +STATIC mp_obj_t pin_on(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_high(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on); + +/// \classmethod mapper([fun]) +/// Get or set the pin mapper function. +STATIC mp_obj_t pin_mapper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_mapper) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_mapper); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj); + +/// \classmethod dict([dict]) +/// Get or set the pin mapper dictionary. +STATIC mp_obj_t pin_map_dict(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_map_dict) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_map_dict); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj); + +/// \classmethod af_list() +/// Returns an array of alternate functions available for this pin. +STATIC mp_obj_t pin_af_list(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + + const pin_af_obj_t *af = self->af; + for (mp_uint_t i = 0; i < self->num_af; i++, af++) { + mp_obj_list_append(result, (mp_obj_t)af); + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_list_obj, pin_af_list); + +#if PIN_DEBUG +/// \classmethod debug([state]) +/// Get or set the debugging state (`True` or `False` for on or off). +STATIC mp_obj_t pin_debug(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + pin_class_debug = mp_obj_is_true(args[1]); + return mp_const_none; + } + return mp_obj_new_bool(pin_class_debug); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj); +#endif + +// init(mode, pull=None, af=-1, *, value, alt) +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get pull mode + nrf_gpio_pin_pull_t pull = NRF_GPIO_PIN_NOPULL; + if (args[1].u_obj != mp_const_none) { + pull = (nrf_gpio_pin_pull_t)mp_obj_get_int(args[1].u_obj); + } + + // if given, set the pin value before initialising to prevent glitches + if (args[3].u_obj != MP_OBJ_NULL) { + mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj)); + } + + + // get io mode + nrf_gpio_pin_dir_t mode = (nrf_gpio_pin_dir_t)args[0].u_int; + + // Connect input or not + nrf_gpio_pin_input_t input = (mode == NRF_GPIO_PIN_DIR_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT; + + if (mode == NRF_GPIO_PIN_DIR_OUTPUT || mode == NRF_GPIO_PIN_DIR_INPUT) { + nrf_gpio_cfg(self->pin, + mode, + input, + pull, + NRF_GPIO_PIN_S0S1, + NRF_GPIO_PIN_NOSENSE); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode)); + } + + return mp_const_none; +} + +STATIC mp_obj_t pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); + +/// \method value([value]) +/// Get or set the digital logic level of the pin: +/// +/// - With no argument, return 0 or 1 depending on the logic level of the pin. +/// - With `value` given, set the logic level of the pin. `value` can be +/// anything that converts to a boolean. If it converts to `True`, the pin +/// is set high, otherwise it is set low. +STATIC mp_obj_t pin_value(mp_uint_t n_args, const mp_obj_t *args) { + return pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); + +/// \method low() +/// Set the pin to a low logic level. +STATIC mp_obj_t pin_low(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_low(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); + +/// \method high() +/// Set the pin to a high logic level. +STATIC mp_obj_t pin_high(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_hal_pin_high(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); + +/// \method name() +/// Get the pin name. +STATIC mp_obj_t pin_name(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_QSTR(self->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name); + +/// \method names() +/// Returns the cpu and board names for this pin. +STATIC mp_obj_t pin_names(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + mp_obj_list_append(result, MP_OBJ_NEW_QSTR(self->name)); + + mp_map_t *map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict); + mp_map_elem_t *elem = map->table; + + for (mp_uint_t i = 0; i < map->used; i++, elem++) { + if (elem->value == self) { + mp_obj_list_append(result, elem->key); + } + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_names_obj, pin_names); + +/// \method port() +/// Get the pin port. +STATIC mp_obj_t pin_port(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(self->pin / 32); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port); + +/// \method pin() +/// Get the pin number. +STATIC mp_obj_t pin_pin(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(self->pin); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pin_obj, pin_pin); + +/// \method mode() +/// Returns the currently configured mode of the pin. The integer returned +/// will match one of the allowed constants for the mode argument to the init +/// function. +STATIC mp_obj_t pin_mode(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_mode(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_mode_obj, pin_mode); + +/// \method pull() +/// Returns the currently configured pull of the pin. The integer returned +/// will match one of the allowed constants for the pull argument to the init +/// function. +STATIC mp_obj_t pin_pull(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_pull(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pull_obj, pin_pull); + +/// \method af() +/// Returns the currently configured alternate-function of the pin. The +/// integer returned will match one of the allowed constants for the af +/// argument to the init function. +STATIC mp_obj_t pin_af(mp_obj_t self_in) { + return mp_const_none; // TODO: MP_OBJ_NEW_SMALL_INT(pin_get_af(self_in)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af); + + +STATIC void pin_common_irq_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { + mp_obj_t pin_handler = MP_STATE_PORT(pin_irq_handlers)[pin]; + mp_obj_t pin_number = MP_OBJ_NEW_SMALL_INT(pin); + const pin_obj_t *pin_obj = pin_find(pin_number); + + mp_call_function_1(pin_handler, (mp_obj_t)pin_obj); +} + +STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_handler, ARG_trigger, ARG_wake}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = NRF_GPIOTE_POLARITY_LOTOHI | NRF_GPIOTE_POLARITY_HITOLO} }, + { MP_QSTR_wake, MP_ARG_BOOL, {.u_bool = false} }, + }; + pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + nrfx_gpiote_pin_t pin = self->pin; + + nrfx_gpiote_in_config_t config = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(true); + if (args[ARG_trigger].u_int == NRF_GPIOTE_POLARITY_LOTOHI) { + config.sense = NRF_GPIOTE_POLARITY_LOTOHI; + } else if (args[ARG_trigger].u_int == NRF_GPIOTE_POLARITY_HITOLO) { + config.sense = NRF_GPIOTE_POLARITY_HITOLO; + } + config.pull = NRF_GPIO_PIN_PULLUP; + + nrfx_err_t err_code = nrfx_gpiote_in_init(pin, &config, pin_common_irq_handler); + if (err_code == NRFX_ERROR_INVALID_STATE) { + // Re-init if already configured. + nrfx_gpiote_in_uninit(pin); + nrfx_gpiote_in_init(pin, &config, pin_common_irq_handler); + } + + MP_STATE_PORT(pin_irq_handlers)[pin] = args[ARG_handler].u_obj; + + nrfx_gpiote_in_event_enable(pin, true); + + // return the irq object + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); + +STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_names), MP_ROM_PTR(&pin_names_obj) }, + { MP_ROM_QSTR(MP_QSTR_af_list), MP_ROM_PTR(&pin_af_list_obj) }, + { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&pin_port_obj) }, + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&pin_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&pin_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&pin_pull_obj) }, + { MP_ROM_QSTR(MP_QSTR_af), MP_ROM_PTR(&pin_af_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) }, + + // class methods + { MP_ROM_QSTR(MP_QSTR_mapper), MP_ROM_PTR(&pin_mapper_obj) }, + { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&pin_map_dict_obj) }, + #if PIN_DEBUG + { MP_ROM_QSTR(MP_QSTR_debug), MP_ROM_PTR(&pin_debug_obj) }, + #endif + + // class attributes + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, + { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(NRF_GPIO_PIN_DIR_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(NRF_GPIO_PIN_DIR_OUTPUT) }, +/* + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) }, +*/ + { MP_ROM_QSTR(MP_QSTR_PULL_DISABLED), MP_ROM_INT(NRF_GPIO_PIN_NOPULL) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(NRF_GPIO_PIN_PULLUP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(NRF_GPIO_PIN_PULLDOWN) }, + + // IRQ triggers, can be or'd together + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(NRF_GPIOTE_POLARITY_LOTOHI) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(NRF_GPIOTE_POLARITY_HITOLO) }, +/* + // legacy class constants + { MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) }, + { MP_ROM_QSTR(MP_QSTR_OUT_OD), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) }, +*/ +#include "genhdr/pins_af_const.h" +}; + +STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); + +const mp_obj_type_t pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pin_print, + .make_new = pin_make_new, + .call = pin_call, + .locals_dict = (mp_obj_dict_t*)&pin_locals_dict, +}; + +/// \moduleref machine +/// \class PinAF - Pin Alternate Functions +/// +/// A Pin represents a physical pin on the microcprocessor. Each pin +/// can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF +/// object represents a particular function for a pin. +/// +/// Usage Model: +/// +/// x3 = machine.Pin.board.X3 +/// x3_af = x3.af_list() +/// +/// x3_af will now contain an array of PinAF objects which are availble on +/// pin X3. +/// +/// For the pyboard, x3_af would contain: +/// [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2] +/// +/// Normally, each peripheral would configure the af automatically, but sometimes +/// the same function is available on multiple pins, and having more control +/// is desired. +/// +/// To configure X3 to expose TIM2_CH3, you could use: +/// pin = machine.Pin(machine.Pin.board.X3, mode=machine.Pin.AF_PP, af=machine.Pin.AF1_TIM2) +/// or: +/// pin = machine.Pin(machine.Pin.board.X3, mode=machine.Pin.AF_PP, af=1) + +/// \method __str__() +/// Return a string describing the alternate function. +STATIC void pin_af_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_af_obj_t *self = self_in; + mp_printf(print, "Pin.%q", self->name); +} + +/// \method index() +/// Return the alternate function index. +STATIC mp_obj_t pin_af_index(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT(af->idx); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_index_obj, pin_af_index); + +/// \method name() +/// Return the name of the alternate function. +STATIC mp_obj_t pin_af_name(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_QSTR(af->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_name_obj, pin_af_name); + +/// \method reg() +/// Return the base register associated with the peripheral assigned to this +/// alternate function. +STATIC mp_obj_t pin_af_reg(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)af->reg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_reg_obj, pin_af_reg); + +STATIC const mp_rom_map_elem_t pin_af_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&pin_af_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_af_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pin_af_reg_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pin_af_locals_dict, pin_af_locals_dict_table); + +const mp_obj_type_t pin_af_type = { + { &mp_type_type }, + .name = MP_QSTR_PinAF, + .print = pin_af_obj_print, + .locals_dict = (mp_obj_dict_t*)&pin_af_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/pin.h b/src/openmv/src/micropython/ports/nrf/modules/machine/pin.h new file mode 100755 index 0000000..7004b32 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/pin.h @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_NRF5_PIN_H__ +#define __MICROPY_INCLUDED_NRF5_PIN_H__ + +// This file requires pin_defs_xxx.h (which has port specific enums and +// defines, so we include it here. It should never be included directly + +#include MICROPY_PIN_DEFS_PORT_H +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + qstr name; + uint8_t idx; + uint8_t fn; + uint8_t unit; + uint8_t type; + + union { + void *reg; + + PIN_DEFS_PORT_AF_UNION + }; +} pin_af_obj_t; + +typedef struct { + mp_obj_base_t base; + qstr name; + uint32_t pin : 8; + uint32_t num_af : 4; + uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT + uint32_t adc_num : 3; // 1 bit per ADC + const pin_af_obj_t *af; + uint32_t pull; +} pin_obj_t; + +extern const mp_obj_type_t pin_type; +extern const mp_obj_type_t pin_af_type; + +typedef struct { + const char *name; + const pin_obj_t *pin; +} pin_named_pin_t; + +extern const pin_named_pin_t pin_board_pins[]; +extern const pin_named_pin_t pin_cpu_pins[]; + +//extern pin_map_obj_t pin_map_obj; + +typedef struct { + mp_obj_base_t base; + qstr name; + const pin_named_pin_t *named_pins; +} pin_named_pins_obj_t; + +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_type_t pin_cpu_pins_obj_type; + +extern const mp_obj_dict_t pin_cpu_pins_locals_dict; +extern const mp_obj_dict_t pin_board_pins_locals_dict; + +MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj); + +void pin_init0(void); +uint32_t pin_get_mode(const pin_obj_t *pin); +uint32_t pin_get_pull(const pin_obj_t *pin); +uint32_t pin_get_af(const pin_obj_t *pin); +const pin_obj_t *pin_find(mp_obj_t user_obj); +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); +const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); + +#endif // __MICROPY_INCLUDED_NRF5_PIN_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.c b/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.c new file mode 100755 index 0000000..ed43806 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.c @@ -0,0 +1,354 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_HW_PWM + +#include "pin.h" +#include "genhdr/pins.h" +#include "pwm.h" + +#if defined(NRF52_SERIES) +// Use PWM hardware. +#include "nrfx_pwm.h" +#endif + +typedef enum { + MODE_LOW_HIGH, + MODE_HIGH_LOW +} pwm_mode_t; + +typedef struct { + uint8_t pwm_pin; + uint8_t duty; + uint16_t pulse_width; + uint16_t period; + nrf_pwm_clk_t freq; + pwm_mode_t mode; +} machine_pwm_config_t; + +typedef struct _machine_hard_pwm_obj_t { + mp_obj_base_t base; + const nrfx_pwm_t * p_pwm; + machine_pwm_config_t * p_config; +} machine_hard_pwm_obj_t; + +STATIC const nrfx_pwm_t machine_hard_pwm_instances[] = { +#if defined(NRF52_SERIES) + NRFX_PWM_INSTANCE(0), + NRFX_PWM_INSTANCE(1), + NRFX_PWM_INSTANCE(2), +#if NRF52840 + NRFX_PWM_INSTANCE(3), +#endif +#else + NULL +#endif +}; + +STATIC machine_pwm_config_t hard_configs[MP_ARRAY_SIZE(machine_hard_pwm_instances)]; + +STATIC const machine_hard_pwm_obj_t machine_hard_pwm_obj[] = { +#if defined(NRF52_SERIES) + {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0]}, + {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1]}, + {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2]}, +#if NRF52840 + {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3]}, +#endif +#endif +}; + +void pwm_init0(void) { +} + + +STATIC int hard_pwm_find(mp_obj_t id) { + if (MP_OBJ_IS_INT(id)) { + // given an integer id + int pwm_id = mp_obj_get_int(id); + if (pwm_id >= 0 && pwm_id < MP_ARRAY_SIZE(machine_hard_pwm_obj)) { + return pwm_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM(%d) does not exist", pwm_id)); + } + return -1; +} + +STATIC void machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_pwm_obj_t *self = self_in; + mp_printf(print, "PWM(%u)", self->p_pwm->drv_inst_idx); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args); +STATIC void machine_hard_pwm_init(mp_obj_t self, mp_arg_val_t *args); +STATIC void machine_hard_pwm_deinit(mp_obj_t self); +STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self, mp_arg_val_t *args); + +/* common code for both soft and hard implementations *************************/ + +STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_pin, ARG_freq, ARG_period, ARG_duty, ARG_pulse_width, ARG_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_id].u_obj == MP_OBJ_NEW_SMALL_INT(-1)) { + // TODO: implement soft PWM + // return machine_soft_pwm_make_new(args); + return mp_const_none; + } else { + // hardware peripheral id given + return machine_hard_pwm_make_new(args); + } +} + +STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_INIT_pin }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } + }; + + // parse args + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_init(self, args); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init); + +STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self) { + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_deinit(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit); + +STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_FREQ_freq }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + }; + + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (mp_obj_get_type(self) == &machine_hard_pwm_type) { + machine_hard_pwm_freq(self, args); + } else { + // soft pwm + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_machine_pwm_freq_obj, 1, machine_pwm_freq); + +STATIC mp_obj_t machine_pwm_period(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_period_obj, 1, 2, machine_pwm_period); + +STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_duty_obj, 1, 2, machine_pwm_duty); + +STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&mp_machine_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&mp_machine_pwm_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&mp_machine_pwm_duty_obj) }, + + { MP_ROM_QSTR(MP_QSTR_FREQ_16MHZ), MP_ROM_INT(NRF_PWM_CLK_16MHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_8MHZ), MP_ROM_INT(NRF_PWM_CLK_8MHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_4MHZ), MP_ROM_INT(NRF_PWM_CLK_4MHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_2MHZ), MP_ROM_INT(NRF_PWM_CLK_2MHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_1MHZ), MP_ROM_INT(NRF_PWM_CLK_1MHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_500KHZ), MP_ROM_INT(NRF_PWM_CLK_500kHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_250KHZ), MP_ROM_INT(NRF_PWM_CLK_250kHz) }, + { MP_ROM_QSTR(MP_QSTR_FREQ_125KHZ), MP_ROM_INT(NRF_PWM_CLK_125kHz) }, + + { MP_ROM_QSTR(MP_QSTR_MODE_LOW_HIGH), MP_ROM_INT(MODE_LOW_HIGH) }, + { MP_ROM_QSTR(MP_QSTR_MODE_HIGH_LOW), MP_ROM_INT(MODE_HIGH_LOW) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table); + +/* code for hard implementation ***********************************************/ + +STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args) { + enum { ARG_id, ARG_pin, ARG_freq, ARG_period, ARG_duty, ARG_pulse_width, ARG_mode }; + // get static peripheral object + int pwm_id = hard_pwm_find(args[ARG_id].u_obj); + const machine_hard_pwm_obj_t *self = &machine_hard_pwm_obj[pwm_id]; + + // check if PWM pin is set + if (args[ARG_pin].u_obj != MP_OBJ_NULL) { + self->p_config->pwm_pin = mp_hal_get_pin_obj(args[ARG_pin].u_obj)->pin; + } else { + // TODO: raise exception. + } + + if (args[ARG_freq].u_obj != MP_OBJ_NULL) { + self->p_config->freq = mp_obj_get_int(args[ARG_freq].u_obj); + } else { + self->p_config->freq = 50; // 50 Hz by default. + } + + if (args[ARG_period].u_obj != MP_OBJ_NULL) { + self->p_config->period = mp_obj_get_int(args[ARG_period].u_obj); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM period has to be within 16000 frequence cycles", self->p_config->period)); + } + + if (args[ARG_duty].u_obj != MP_OBJ_NULL) { + self->p_config->duty = mp_obj_get_int(args[ARG_duty].u_obj); + } else { + self->p_config->duty = 50; // 50% by default. + } + + if (args[ARG_pulse_width].u_obj != MP_OBJ_NULL) { + self->p_config->pulse_width = mp_obj_get_int(args[ARG_pulse_width].u_obj); + } else { + self->p_config->pulse_width = 0; + } + + if (args[ARG_mode].u_obj != MP_OBJ_NULL) { + self->p_config->mode = mp_obj_get_int(args[ARG_mode].u_obj); + } else { + self->p_config->mode = MODE_HIGH_LOW; + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void machine_hard_pwm_init(mp_obj_t self_in, mp_arg_val_t *args) { + machine_hard_pwm_obj_t *self = self_in; + + nrfx_pwm_config_t config; + + config.output_pins[0] = self->p_config->pwm_pin; + config.output_pins[1] = NRFX_PWM_PIN_NOT_USED; + config.output_pins[2] = NRFX_PWM_PIN_NOT_USED; + config.output_pins[3] = NRFX_PWM_PIN_NOT_USED; + + config.irq_priority = 6; + config.base_clock = self->p_config->freq; + config.count_mode = NRF_PWM_MODE_UP; + config.top_value = self->p_config->period; + config.load_mode = NRF_PWM_LOAD_INDIVIDUAL; + config.step_mode = NRF_PWM_STEP_AUTO; + + nrfx_pwm_init(self->p_pwm, &config, NULL); + + uint16_t pulse_width = ((self->p_config->period * self->p_config->duty) / 100); + + // If manual period has been set, override duty-cycle. + if (self->p_config->pulse_width > 0) { + pulse_width = self->p_config->pulse_width; + } + + // TODO: Move DMA buffer to global memory. + volatile static uint16_t pwm_seq[4]; + + if (self->p_config->mode == MODE_HIGH_LOW) { + pwm_seq[0] = self->p_config->period - pulse_width; + pwm_seq[1] = self->p_config->period - pulse_width; + } else { + pwm_seq[0] = self->p_config->period - pulse_width; + pwm_seq[1] = self->p_config->period - pulse_width; + } + + pwm_seq[2] = self->p_config->period - pulse_width; + pwm_seq[3] = self->p_config->period - pulse_width; + + const nrf_pwm_sequence_t pwm_sequence = { + .values.p_raw = (const uint16_t *)&pwm_seq, + .length = 4, + .repeats = 0, + .end_delay = 0 + }; + + nrfx_pwm_simple_playback(self->p_pwm, + &pwm_sequence, + 0, // Loop disabled. + 0); +} + +STATIC void machine_hard_pwm_deinit(mp_obj_t self_in) { + machine_hard_pwm_obj_t *self = self_in; + (void)self; + nrfx_pwm_stop(self->p_pwm, true); + nrfx_pwm_uninit(self->p_pwm); +} + +STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self_in, mp_arg_val_t *args) { + machine_hard_pwm_obj_t *self = self_in; + (void)self; + return mp_const_none; +} + +const mp_obj_type_t machine_hard_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = machine_pwm_print, + .make_new = machine_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_pwm_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_HW_PWM diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.h b/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.h new file mode 100755 index 0000000..7a5b72e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/pwm.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +void pwm_init0(void); + +extern const mp_obj_type_t machine_hard_pwm_type; diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.c b/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.c new file mode 100755 index 0000000..ea4a176 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.c @@ -0,0 +1,267 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/nlr.h" +#include "py/runtime.h" +#include "rtcounter.h" +#include "nrfx_rtc.h" +#include "nrf_clock.h" + +#if MICROPY_PY_MACHINE_RTCOUNTER + +// Count every 125ms (~maximum prescaler setting) +#define RTC_FREQUENCY (8UL) + +enum { + RTC_MODE_ONESHOT, + RTC_MODE_PERIODIC, +}; + +// Volatile part of the RTCounter object. +typedef struct { + mp_obj_t callback; + uint32_t period; +} machine_rtc_config_t; + +// Non-volatile part of the RTCounter object. +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; + const nrfx_rtc_t * p_rtc; // Driver instance + nrfx_rtc_handler_t handler; // interrupt callback + machine_rtc_config_t * config; // pointer to volatile part +} machine_rtc_obj_t; + +STATIC const nrfx_rtc_t machine_rtc_instances[] = { + NRFX_RTC_INSTANCE(0), + NRFX_RTC_INSTANCE(1), +#if defined(NRF52_SERIES) + NRFX_RTC_INSTANCE(2), +#endif +}; + +STATIC machine_rtc_config_t configs[MP_ARRAY_SIZE(machine_rtc_instances)]; + +STATIC void interrupt_handler0(nrfx_rtc_int_type_t int_type); +STATIC void interrupt_handler1(nrfx_rtc_int_type_t int_type); +#if defined(NRF52_SERIES) +STATIC void interrupt_handler2(nrfx_rtc_int_type_t int_type); +#endif + +STATIC const machine_rtc_obj_t machine_rtc_obj[] = { + {{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[0], .handler=interrupt_handler0, .config=&configs[0]}, + {{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[1], .handler=interrupt_handler1, .config=&configs[1]}, +#if defined(NRF52_SERIES) + {{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[2], .handler=interrupt_handler2, .config=&configs[2]}, +#endif +}; + +STATIC void interrupt_handler(size_t instance_id) { + const machine_rtc_obj_t * self = &machine_rtc_obj[instance_id]; + machine_rtc_config_t *config = self->config; + if (config->callback != NULL) { + mp_call_function_1((mp_obj_t)config->callback, (mp_obj_t)self); + } + if (config->period == 0) { + nrfx_rtc_cc_disable(self->p_rtc, 0); + } else { // periodic + uint32_t val = nrfx_rtc_counter_get(self->p_rtc) + config->period; + nrfx_rtc_cc_set(self->p_rtc, 0, val, true); + } +} + +STATIC void interrupt_handler0(nrfx_rtc_int_type_t int_type) { + interrupt_handler(0); +} + +STATIC void interrupt_handler1(nrfx_rtc_int_type_t int_type) { + interrupt_handler(1); +} + +#if defined(NRF52_SERIES) +STATIC void interrupt_handler2(nrfx_rtc_int_type_t int_type) { + interrupt_handler(2); +} +#endif + +void rtc_init0(void) { +} + +STATIC int rtc_find(mp_obj_t id) { + // given an integer id + int rtc_id = mp_obj_get_int(id); + if (rtc_id >= 0 && rtc_id < MP_ARRAY_SIZE(machine_rtc_obj)) { + return rtc_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "RTCounter(%d) does not exist", rtc_id)); +} + +STATIC void rtc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_rtc_obj_t *self = self_in; + mp_printf(print, "RTCounter(%u)", self->p_rtc->instance_id); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +const nrfx_rtc_config_t machine_rtc_config = { + .prescaler = RTC_FREQ_TO_PRESCALER(RTC_FREQUENCY), + .reliable = 0, + .tick_latency = 0, // ignored when reliable == 0 + #ifdef NRF51 + .interrupt_priority = 3, + #else + .interrupt_priority = 6, + #endif +}; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_period, ARG_mode, ARG_callback }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = RTC_FREQUENCY} }, // 1 second + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = RTC_MODE_PERIODIC} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int rtc_id = rtc_find(args[ARG_id].u_obj); + + // const and non-const part of the RTC object. + const machine_rtc_obj_t * self = &machine_rtc_obj[rtc_id]; + machine_rtc_config_t *config = self->config; + + if (args[ARG_callback].u_obj == mp_const_none) { + config->callback = NULL; + } else if (MP_OBJ_IS_FUN(args[ARG_callback].u_obj)) { + config->callback = args[ARG_callback].u_obj; + } else { + mp_raise_ValueError("callback must be a function"); + } + + // Periodic or one-shot + if (args[ARG_mode].u_int == RTC_MODE_ONESHOT) { + // One-shot + config->period = 0; + } else { + // Period between the intervals + config->period = args[ARG_period].u_int; + } + + // Start the low-frequency clock (if it hasn't been started already) + if (!nrf_clock_lf_is_running()) { + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART); + } + + // Make sure it's uninitialized. + nrfx_rtc_uninit(self->p_rtc); + nrfx_rtc_counter_clear(self->p_rtc); + + // Initialize and set the correct IRQ. + nrfx_rtc_init(self->p_rtc, &machine_rtc_config, self->handler); + nrfx_rtc_cc_set(self->p_rtc, 0 /*channel*/, args[ARG_period].u_int, true /*enable irq*/); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method start() +/// Start the RTCounter. Timeout occurs after number of periods +/// in the configured frequency has been reached. +/// +STATIC mp_obj_t machine_rtc_start(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_rtc_enable(self->p_rtc); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_start_obj, machine_rtc_start); + +/// \method stop() +/// Stop the RTCounter. +/// +STATIC mp_obj_t machine_rtc_stop(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_rtc_disable(self->p_rtc); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_stop_obj, machine_rtc_stop); + +/// \method counter() +/// Return the current counter value. Wraps around after about 24 days +/// with the current prescaler (2^24 / 8 = 2097152 seconds). +/// +STATIC mp_obj_t machine_rtc_counter(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + uint32_t counter = nrfx_rtc_counter_get(self->p_rtc); + + return MP_OBJ_NEW_SMALL_INT(counter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_counter_obj, machine_rtc_counter); + +/// \method deinit() +/// Free resources associated with this RTC. +/// +STATIC mp_obj_t machine_rtc_deinit(mp_obj_t self_in) { + machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_rtc_uninit(self->p_rtc); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_deinit_obj, machine_rtc_deinit); + + +STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_rtc_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_rtc_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_counter), MP_ROM_PTR(&machine_rtc_counter_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_rtc_deinit_obj) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_ONESHOT), MP_ROM_INT(RTC_MODE_ONESHOT) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(RTC_MODE_PERIODIC) }, + { MP_ROM_QSTR(MP_QSTR_FREQUENCY), MP_ROM_INT(RTC_FREQUENCY) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtcounter_type = { + { &mp_type_type }, + .name = MP_QSTR_RTCounter, + .print = rtc_print, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_rtc_locals_dict +}; + +#endif // MICROPY_PY_MACHINE_RTCOUNTER diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.h b/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.h new file mode 100755 index 0000000..979da12 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/rtcounter.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef RTCOUNTER_H__ +#define RTCOUNTER_H__ + +extern const mp_obj_type_t machine_rtcounter_type; + +void rtc_init0(void); + +#endif // RTCOUNTER_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/spi.c b/src/openmv/src/micropython/ports/nrf/modules/machine/spi.c new file mode 100755 index 0000000..ce75b6c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/spi.c @@ -0,0 +1,441 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 - 2018 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_MACHINE_HW_SPI + +#include "py/nlr.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "pin.h" +#include "genhdr/pins.h" +#include "spi.h" +#if NRFX_SPI_ENABLED +#include "nrfx_spi.h" +#else +#include "nrfx_spim.h" +#endif + +/// \moduleref machine +/// \class SPI - a master-driven serial protocol +/// +/// SPI is a serial protocol that is driven by a master. At the physical level +/// there are 3 lines: SCK, MOSI, MISO. +/// +/// See usage model of I2C; SPI is very similar. Main difference is +/// parameters to init the SPI bus: +/// +/// from machine import SPI +/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) +/// +/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be +/// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1 +/// to sample data on the first or second clock edge respectively. Crc can be +/// None for no CRC, or a polynomial specifier. +/// +/// Additional method for SPI: +/// +/// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes +/// buf = bytearray(4) +/// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf +/// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf + +#if NRFX_SPIM_ENABLED + +#define nrfx_spi_t nrfx_spim_t +#define nrfx_spi_config_t nrfx_spim_config_t +#define nrfx_spi_xfer_desc_t nrfx_spim_xfer_desc_t + +#define NRFX_SPI_PIN_NOT_USED NRFX_SPIM_PIN_NOT_USED +#define NRFX_SPI_INSTANCE NRFX_SPIM_INSTANCE +#define NRF_SPI_BIT_ORDER_LSB_FIRST NRF_SPIM_BIT_ORDER_LSB_FIRST +#define NRF_SPI_BIT_ORDER_MSB_FIRST NRF_SPIM_BIT_ORDER_MSB_FIRST +#define NRF_SPI_MODE_0 NRF_SPIM_MODE_0 +#define NRF_SPI_MODE_1 NRF_SPIM_MODE_1 +#define NRF_SPI_MODE_2 NRF_SPIM_MODE_2 +#define NRF_SPI_MODE_3 NRF_SPIM_MODE_3 +#define NRF_SPI_FREQ_125K NRF_SPIM_FREQ_125K +#define NRF_SPI_FREQ_250K NRF_SPIM_FREQ_250K +#define NRF_SPI_FREQ_500K NRF_SPIM_FREQ_500K +#define NRF_SPI_FREQ_1M NRF_SPIM_FREQ_1M +#define NRF_SPI_FREQ_2M NRF_SPIM_FREQ_2M +#define NRF_SPI_FREQ_4M NRF_SPIM_FREQ_4M +#define NRF_SPI_FREQ_8M NRF_SPIM_FREQ_8M + +#define nrfx_spi_init nrfx_spim_init +#define nrfx_spi_uninit nrfx_spim_uninit +#define nrfx_spi_xfer nrfx_spim_xfer + +#endif // NRFX_SPIM_ENABLED + +typedef struct _machine_hard_spi_obj_t { + mp_obj_base_t base; + const nrfx_spi_t * p_spi; // Driver instance + nrfx_spi_config_t * p_config; // pointer to volatile part +} machine_hard_spi_obj_t; + +STATIC const nrfx_spi_t machine_spi_instances[] = { + NRFX_SPI_INSTANCE(0), + NRFX_SPI_INSTANCE(1), +#if defined(NRF52_SERIES) + NRFX_SPI_INSTANCE(2), +#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED + NRFX_SPI_INSTANCE(3), +#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED +#endif // NRF52_SERIES +}; + +STATIC nrfx_spi_config_t configs[MP_ARRAY_SIZE(machine_spi_instances)]; + +STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = { + {{&machine_hard_spi_type}, .p_spi = &machine_spi_instances[0], .p_config = &configs[0]}, + {{&machine_hard_spi_type}, .p_spi = &machine_spi_instances[1], .p_config = &configs[1]}, +#if defined(NRF52_SERIES) + {{&machine_hard_spi_type}, .p_spi = &machine_spi_instances[2], .p_config = &configs[2]}, +#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED + {{&machine_hard_spi_type}, .p_spi = &machine_spi_instances[3], .p_config = &configs[3]}, +#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED +#endif // NRF52_SERIES +}; + +void spi_init0(void) { +} + +STATIC int spi_find(mp_obj_t id) { + if (MP_OBJ_IS_STR(id)) { + // given a string id + const char *port = mp_obj_str_get_str(id); + if (0) { + #ifdef MICROPY_HW_SPI0_NAME + } else if (strcmp(port, MICROPY_HW_SPI0_NAME) == 0) { + return 1; + #endif + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%s) does not exist", port)); + } else { + // given an integer id + int spi_id = mp_obj_get_int(id); + if (spi_id >= 0 && spi_id < MP_ARRAY_SIZE(machine_hard_spi_obj)) { + return spi_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%d) does not exist", spi_id)); + } +} + +void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) { + nrfx_spi_xfer_desc_t xfer_desc = { + .p_tx_buffer = src, + .tx_length = len, + .p_rx_buffer = dest, + .rx_length = len + }; + + nrfx_spi_xfer(self->p_spi, &xfer_desc, 0); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +// for make_new +enum { + ARG_NEW_id, + ARG_NEW_baudrate, + ARG_NEW_polarity, + ARG_NEW_phase, + ARG_NEW_bits, + ARG_NEW_firstbit, + ARG_NEW_sck, + ARG_NEW_mosi, + ARG_NEW_miso +}; + +// for init +enum { + ARG_INIT_baudrate, + ARG_INIT_polarity, + ARG_INIT_phase, + ARG_INIT_bits, + ARG_INIT_firstbit +}; + +STATIC mp_obj_t machine_hard_spi_make_new(mp_arg_val_t *args); +STATIC void machine_hard_spi_init(mp_obj_t self, mp_arg_val_t *args); +STATIC void machine_hard_spi_deinit(mp_obj_t self); + +/* common code for both soft and hard implementations *************************/ + +STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 1000000} }, + { MP_QSTR_polarity, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_INT, {.u_int = 0 /* SPI_FIRSTBIT_MSB */} }, + { MP_QSTR_sck, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_NEW_id].u_obj == MP_OBJ_NEW_SMALL_INT(-1)) { + // TODO: implement soft SPI + // return machine_soft_spi_make_new(args); + return mp_const_none; + } else { + // hardware peripheral id given + return machine_hard_spi_make_new(args); + } +} + +STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + // parse args + mp_obj_t self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_spi_type) { + machine_hard_spi_init(self, args); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init); + +STATIC mp_obj_t machine_spi_deinit(mp_obj_t self) { + // dispatch to specific implementation + if (mp_obj_get_type(self) == &machine_hard_spi_type) { + machine_hard_spi_deinit(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit); + +STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, + + { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(NRF_SPI_BIT_ORDER_MSB_FIRST) }, + { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(NRF_SPI_BIT_ORDER_LSB_FIRST) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_spi_locals_dict, machine_spi_locals_dict_table); + +/* code for hard implementation ***********************************************/ + +STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_spi_obj_t *self = self_in; + mp_printf(print, "SPI(%u)", self->p_spi->drv_inst_idx); +} + +STATIC mp_obj_t machine_hard_spi_make_new(mp_arg_val_t *args) { + // get static peripheral object + int spi_id = spi_find(args[ARG_NEW_id].u_obj); + const machine_hard_spi_obj_t *self = &machine_hard_spi_obj[spi_id]; + + // here we would check the sck/mosi/miso pins and configure them + if (args[ARG_NEW_sck].u_obj != MP_OBJ_NULL + && args[ARG_NEW_mosi].u_obj != MP_OBJ_NULL + && args[ARG_NEW_miso].u_obj != MP_OBJ_NULL) { + + self->p_config->sck_pin = mp_hal_get_pin_obj(args[ARG_NEW_sck].u_obj)->pin; + self->p_config->mosi_pin = mp_hal_get_pin_obj(args[ARG_NEW_mosi].u_obj)->pin; + self->p_config->miso_pin = mp_hal_get_pin_obj(args[ARG_NEW_miso].u_obj)->pin; + } else { + self->p_config->sck_pin = MICROPY_HW_SPI0_SCK; + self->p_config->mosi_pin = MICROPY_HW_SPI0_MOSI; + self->p_config->miso_pin = MICROPY_HW_SPI0_MISO; + } + + // Manually trigger slave select from upper layer. + self->p_config->ss_pin = NRFX_SPI_PIN_NOT_USED; + +#ifdef NRF51 + self->p_config->irq_priority = 3; +#else + self->p_config->irq_priority = 6; +#endif + + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); + machine_hard_spi_init(self_obj, &args[1]); // Skip instance id param. + + return self_obj; +} + +STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) { + + const machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int baudrate = args[ARG_INIT_baudrate].u_int; + + if (baudrate <= 125000) { + self->p_config->frequency = NRF_SPI_FREQ_125K; + } else if (baudrate <= 250000) { + self->p_config->frequency = NRF_SPI_FREQ_250K; + } else if (baudrate <= 500000) { + self->p_config->frequency = NRF_SPI_FREQ_500K; + } else if (baudrate <= 1000000) { + self->p_config->frequency = NRF_SPI_FREQ_1M; + } else if (baudrate <= 2000000) { + self->p_config->frequency = NRF_SPI_FREQ_2M; + } else if (baudrate <= 4000000) { + self->p_config->frequency = NRF_SPI_FREQ_4M; + } else if (baudrate <= 8000000) { + self->p_config->frequency = NRF_SPI_FREQ_8M; +#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED + } else if (baudrate <= 16000000) { + self->p_config->frequency = NRF_SPIM_FREQ_16M; + } else if (baudrate <= 32000000) { + self->p_config->frequency = NRF_SPIM_FREQ_32M; +#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED + } else { // Default + self->p_config->frequency = NRF_SPI_FREQ_1M; + } + + // Active high + if (args[ARG_INIT_polarity].u_int == 0) { + if (args[ARG_INIT_phase].u_int == 0) { + // First clock edge + self->p_config->mode = NRF_SPI_MODE_0; + } else { + // Second clock edge + self->p_config->mode = NRF_SPI_MODE_1; + } + // Active low + } else { + if (args[ARG_INIT_phase].u_int == 0) { + // First clock edge + self->p_config->mode = NRF_SPI_MODE_2; + } else { + // Second clock edge + self->p_config->mode = NRF_SPI_MODE_3; + } + } + + self->p_config->orc = 0xFF; // Overrun character + self->p_config->bit_order = (args[ARG_INIT_firstbit].u_int == 0) ? NRF_SPI_BIT_ORDER_MSB_FIRST : NRF_SPI_BIT_ORDER_LSB_FIRST; + + // Set context to this instance of SPI + nrfx_err_t err_code = nrfx_spi_init(self->p_spi, self->p_config, NULL, (void *)self); + + if (err_code == NRFX_ERROR_INVALID_STATE) { + // Instance already initialized, deinitialize first. + nrfx_spi_uninit(self->p_spi); + // Initialize again. + nrfx_spi_init(self->p_spi, self->p_config, NULL, (void *)self); + } +} + +STATIC void machine_hard_spi_deinit(mp_obj_t self_in) { + const machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + nrfx_spi_uninit(self->p_spi); +} + +STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + const machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; + spi_transfer(self, len, src, dest); +} + + +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len); + spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len); + spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + mp_raise_ValueError("buffers must be the same length"); + } + spi_transfer(self, src.len, src.buf, dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + + +STATIC const mp_machine_spi_p_t machine_hard_spi_p = { + .transfer = machine_hard_spi_transfer, +}; + +const mp_obj_type_t machine_hard_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hard_spi_print, + .make_new = machine_spi_make_new, + .protocol = &machine_hard_spi_p, + .locals_dict = (mp_obj_dict_t*)&machine_spi_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_HW_SPI diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/spi.h b/src/openmv/src/micropython/ports/nrf/modules/machine/spi.h new file mode 100755 index 0000000..c6f64a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/spi.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "py/obj.h" + +typedef struct _machine_hard_spi_obj_t machine_hard_spi_obj_t; +extern const mp_obj_type_t machine_hard_spi_type; + +void spi_init0(void); +void spi_transfer(const machine_hard_spi_obj_t * self, + size_t len, + const void * src, + void * dest); diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/temp.c b/src/openmv/src/micropython/ports/nrf/modules/machine/temp.c new file mode 100755 index 0000000..361d988 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/temp.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Bander F. Ajba + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "temp.h" +#include "nrf_temp.h" + +#if BLUETOOTH_SD +#include "py/nlr.h" +#include "ble_drv.h" +#include "nrf_soc.h" +#define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) +#endif // BLUETOOTH_SD + +#if MICROPY_PY_MACHINE_TEMP + +typedef struct _machine_temp_obj_t { + mp_obj_base_t base; +} machine_temp_obj_t; + +/// \method __str__() +/// Return a string describing the Temp object. +STATIC void machine_temp_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_temp_obj_t *self = o; + + (void)self; + + mp_printf(print, "Temp"); +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_temp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_temp_obj_t *self = m_new_obj(machine_temp_obj_t); + + self->base.type = &machine_temp_type; + + return MP_OBJ_FROM_PTR(self); +} + +/// \method read() +/// Get temperature. +STATIC mp_obj_t machine_temp_read(mp_uint_t n_args, const mp_obj_t *args) { + +#if BLUETOOTH_SD + if (BLUETOOTH_STACK_ENABLED() == 1) { + int32_t temp; + (void)sd_temp_get(&temp); + return MP_OBJ_NEW_SMALL_INT(temp / 4); // resolution of 0.25 degree celsius + } +#endif // BLUETOOTH_SD + + return MP_OBJ_NEW_SMALL_INT(nrf_temp_read()); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_temp_read_obj, 0, 1, machine_temp_read); + +STATIC const mp_rom_map_elem_t machine_temp_locals_dict_table[] = { + // instance methods + // class methods + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_temp_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_temp_locals_dict, machine_temp_locals_dict_table); + +const mp_obj_type_t machine_temp_type = { + { &mp_type_type }, + .name = MP_QSTR_Temp, + .make_new = machine_temp_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_temp_locals_dict, + .print = machine_temp_print, +}; + +#endif // MICROPY_PY_MACHINE_TEMP diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/temp.h b/src/openmv/src/micropython/ports/nrf/modules/machine/temp.h new file mode 100755 index 0000000..e8f751b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/temp.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Bander F. Ajba + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TEMP_H__ +#define TEMP_H__ + +extern const mp_obj_type_t machine_temp_type; + +int32_t temp_read(void); + +#endif // TEMP_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/timer.c b/src/openmv/src/micropython/ports/nrf/modules/machine/timer.c new file mode 100755 index 0000000..07f1f49 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/timer.c @@ -0,0 +1,246 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/nlr.h" +#include "py/runtime.h" +#include "timer.h" +#include "nrfx_timer.h" + +#if MICROPY_PY_MACHINE_TIMER + +enum { + TIMER_MODE_ONESHOT, + TIMER_MODE_PERIODIC, +}; + +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + nrfx_timer_t p_instance; +} machine_timer_obj_t; + +STATIC mp_obj_t machine_timer_callbacks[] = { + NULL, + NULL, + NULL, +#if defined(NRF52_SERIES) + NULL, + NULL, +#endif +}; + +STATIC const machine_timer_obj_t machine_timer_obj[] = { + {{&machine_timer_type}, NRFX_TIMER_INSTANCE(0)}, +#if !defined(MICROPY_PY_MACHINE_SOFT_PWM) || (MICROPY_PY_MACHINE_SOFT_PWM == 0) + {{&machine_timer_type}, NRFX_TIMER_INSTANCE(1)}, +#endif + {{&machine_timer_type}, NRFX_TIMER_INSTANCE(2)}, +#if defined(NRF52_SERIES) + {{&machine_timer_type}, NRFX_TIMER_INSTANCE(3)}, + {{&machine_timer_type}, NRFX_TIMER_INSTANCE(4)}, +#endif +}; + +void timer_init0(void) { + for (int i = 0; i < MP_ARRAY_SIZE(machine_timer_obj); i++) { + nrfx_timer_uninit(&machine_timer_obj[i].p_instance); + } +} + +STATIC int timer_find(mp_obj_t id) { + // given an integer id + int timer_id = mp_obj_get_int(id); + if (timer_id >= 0 && timer_id < MP_ARRAY_SIZE(machine_timer_obj)) { + return timer_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) does not exist", timer_id)); +} + +STATIC void timer_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + machine_timer_obj_t *self = o; + mp_printf(print, "Timer(%u)", self->p_instance.instance_id); +} + +STATIC void timer_event_handler(nrf_timer_event_t event_type, void *p_context) { + machine_timer_obj_t *self = p_context; + mp_obj_t callback = machine_timer_callbacks[self->p_instance.instance_id]; + if (callback != NULL) { + mp_call_function_1(callback, self); + } +} + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_period, ARG_mode, ARG_callback }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000000} }, // 1 second + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int timer_id = timer_find(args[ARG_id].u_obj); + +#if BLUETOOTH_SD + if (timer_id == 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) reserved by Bluetooth LE stack.", timer_id)); + } +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM + if (timer_id == 1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Timer(%d) reserved by ticker driver.", timer_id)); + } +#endif + + machine_timer_obj_t *self = (machine_timer_obj_t*)&machine_timer_obj[timer_id]; + + if (MP_OBJ_IS_FUN(args[ARG_callback].u_obj)) { + machine_timer_callbacks[timer_id] = args[ARG_callback].u_obj; + } else if (args[ARG_callback].u_obj == mp_const_none) { + machine_timer_callbacks[timer_id] = NULL; + } else { + mp_raise_ValueError("callback must be a function"); + } + + // Timer peripheral usage: + // Every timer instance has a numer of capture/compare (CC) registers. + // These can store either the value to compare against (to trigger an + // interrupt or a shortcut) or store a value returned from a + // capture/compare event. + // We use channel 0 for comparing (to trigger the callback and clear + // shortcut) and channel 1 for capturing the current time. + + const nrfx_timer_config_t config = { + .frequency = NRF_TIMER_FREQ_1MHz, + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_24, + #ifdef NRF51 + .interrupt_priority = 3, + #else + .interrupt_priority = 6, + #endif + .p_context = self, + }; + + // Initialize the drive. + // When it is already initialized, this is a no-op. + nrfx_timer_init(&self->p_instance, &config, timer_event_handler); + + // Configure channel 0. + nrf_timer_short_mask_t short_mask = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK | + ((args[ARG_mode].u_int == TIMER_MODE_ONESHOT) ? NRF_TIMER_SHORT_COMPARE0_STOP_MASK : 0); + bool enable_interrupts = true; + nrfx_timer_extended_compare( + &self->p_instance, + NRF_TIMER_CC_CHANNEL0, + args[ARG_period].u_int, + short_mask, + enable_interrupts); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method period() +/// Return counter value, which is currently in us. +/// +STATIC mp_obj_t machine_timer_period(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + uint32_t period = nrfx_timer_capture(&self->p_instance, NRF_TIMER_CC_CHANNEL1); + + return MP_OBJ_NEW_SMALL_INT(period); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_period_obj, machine_timer_period); + +/// \method start() +/// Start the timer. +/// +STATIC mp_obj_t machine_timer_start(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_timer_enable(&self->p_instance); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start); + +/// \method stop() +/// Stop the timer. +/// +STATIC mp_obj_t machine_timer_stop(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_timer_disable(&self->p_instance); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_stop_obj, machine_timer_stop); + +/// \method deinit() +/// Free resources associated with the timer. +/// +STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { + machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in); + + nrfx_timer_uninit(&self->p_instance); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&machine_timer_period_obj) }, // alias + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&machine_timer_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&machine_timer_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_timer_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_ONESHOT), MP_ROM_INT(TIMER_MODE_ONESHOT) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_timer_locals_dict +}; + +#endif // MICROPY_PY_MACHINE_TIMER diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/timer.h b/src/openmv/src/micropython/ports/nrf/modules/machine/timer.h new file mode 100755 index 0000000..bfbe079 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/timer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TIMER_H__ +#define TIMER_H__ + +extern const mp_obj_type_t machine_timer_type; + +void timer_init0(void); + +#endif // TIMER_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/uart.c b/src/openmv/src/micropython/ports/nrf/modules/machine/uart.c new file mode 100755 index 0000000..c3f8ea9 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/uart.c @@ -0,0 +1,350 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "pin.h" +#include "genhdr/pins.h" + +#include "uart.h" +#include "mpconfigboard.h" +#include "nrf.h" +#include "mphalport.h" +#include "nrfx_uart.h" + + +#if MICROPY_PY_MACHINE_UART + +typedef struct _machine_hard_uart_obj_t { + mp_obj_base_t base; + const nrfx_uart_t * p_uart; // Driver instance +} machine_hard_uart_obj_t; + +static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0); + +STATIC const machine_hard_uart_obj_t machine_hard_uart_obj[] = { + {{&machine_hard_uart_type}, .p_uart = &instance0}, +}; + +void uart_init0(void) { +} + +STATIC int uart_find(mp_obj_t id) { + // given an integer id + int uart_id = mp_obj_get_int(id); + if (uart_id >= 0 && uart_id < MP_ARRAY_SIZE(machine_hard_uart_obj)) { + return uart_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "UART(%d) does not exist", uart_id)); +} + +void uart_irq_handler(mp_uint_t uart_id) { + +} + +bool uart_rx_any(const machine_hard_uart_obj_t *uart_obj) { + // TODO: uart will block for now. + return true; +} + +int uart_rx_char(const machine_hard_uart_obj_t * self) { + uint8_t ch; + nrfx_uart_rx(self->p_uart, &ch, 1); + return (int)ch; +} + +STATIC nrfx_err_t uart_tx_char(const machine_hard_uart_obj_t * self, int c) { + while (nrfx_uart_tx_in_progress(self->p_uart)) { + ; + } + + return nrfx_uart_tx(self->p_uart, (uint8_t *)&c, 1); +} + + +void uart_tx_strn(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + uart_tx_char(uart_obj, *str); + } +} + +void uart_tx_strn_cooked(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + uart_tx_char(uart_obj, '\r'); + } + uart_tx_char(uart_obj, *str); + } +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void machine_hard_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +} + + + +/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64) +/// +/// Initialise the UART bus with the given parameters: +/// - `id`is bus id. +/// - `baudrate` is the clock rate. +/// - `bits` is the number of bits per byte, 7, 8 or 9. +/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). +/// - `stop` is the number of stop bits, 1 or 2. +/// - `timeout` is the timeout in milliseconds to wait for the first character. +/// - `timeout_char` is the timeout in milliseconds to wait between characters. +/// - `read_buf_len` is the character length of the read buffer (0 to disable). +STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_flow, ARG_timeout, ARG_timeout_char, ARG_read_buf_len }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int uart_id = uart_find(args[ARG_id].u_obj); + const machine_hard_uart_obj_t * self = &machine_hard_uart_obj[uart_id]; + + nrfx_uart_config_t config; + + // flow control + config.hwfc = args[ARG_flow].u_int; + +#if MICROPY_HW_UART1_HWFC + config.hwfc = NRF_UART_HWFC_ENABLED; +#else + config.hwfc = NRF_UART_HWFC_DISABLED; +#endif + + config.parity = NRF_UART_PARITY_EXCLUDED; + +#if (BLUETOOTH_SD == 100) + config.interrupt_priority = 3; +#else + config.interrupt_priority = 6; +#endif + + switch (args[ARG_baudrate].u_int) { + case 1200: + config.baudrate = NRF_UART_BAUDRATE_1200; + break; + case 2400: + config.baudrate = NRF_UART_BAUDRATE_2400; + break; + case 4800: + config.baudrate = NRF_UART_BAUDRATE_4800; + break; + case 9600: + config.baudrate = NRF_UART_BAUDRATE_9600; + break; + case 14400: + config.baudrate = NRF_UART_BAUDRATE_14400; + break; + case 19200: + config.baudrate = NRF_UART_BAUDRATE_19200; + break; + case 28800: + config.baudrate = NRF_UART_BAUDRATE_28800; + break; + case 38400: + config.baudrate = NRF_UART_BAUDRATE_38400; + break; + case 57600: + config.baudrate = NRF_UART_BAUDRATE_57600; + break; + case 76800: + config.baudrate = NRF_UART_BAUDRATE_76800; + break; + case 115200: + config.baudrate = NRF_UART_BAUDRATE_115200; + break; + case 230400: + config.baudrate = NRF_UART_BAUDRATE_230400; + break; + case 250000: + config.baudrate = NRF_UART_BAUDRATE_250000; + break; + case 1000000: + config.baudrate = NRF_UART_BAUDRATE_1000000; + break; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "UART baudrate not supported, %u", args[ARG_baudrate].u_int)); + break; + } + + config.pseltxd = MICROPY_HW_UART1_TX; + config.pselrxd = MICROPY_HW_UART1_RX; + +#if MICROPY_HW_UART1_HWFC + config.pselrts = MICROPY_HW_UART1_RTS; + config.pselcts = MICROPY_HW_UART1_CTS; +#endif + + // Set context to this instance of UART + config.p_context = (void *)self; + + // Set NULL as callback function to keep it blocking + nrfx_uart_init(self->p_uart, &config, NULL); + + nrfx_uart_rx_enable(self->p_uart); + + return MP_OBJ_FROM_PTR(self); +} + +/// \method writechar(char) +/// Write a single character on the bus. `char` is an integer to write. +/// Return value: `None`. +STATIC mp_obj_t machine_hard_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) { + machine_hard_uart_obj_t *self = self_in; + + // get the character to write (might be 9 bits) + int data = mp_obj_get_int(char_in); + + nrfx_err_t err = uart_tx_char(self, data); + if (err != NRFX_SUCCESS) { + mp_hal_raise(err); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_hard_uart_writechar_obj, machine_hard_uart_writechar); + +/// \method readchar() +/// Receive a single character on the bus. +/// Return value: The character read, as an integer. Returns -1 on timeout. +STATIC mp_obj_t machine_hard_uart_readchar(mp_obj_t self_in) { + machine_hard_uart_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_readchar_obj, machine_hard_uart_readchar); + +// uart.sendbreak() +STATIC mp_obj_t machine_hard_uart_sendbreak(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_sendbreak_obj, machine_hard_uart_sendbreak); + +STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = { + // instance methods + /// \method read([nbytes]) + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + /// \method readline() + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + /// \method readinto(buf[, nbytes]) + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + /// \method writechar(buf) + { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_hard_uart_writechar_obj) }, + { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_hard_uart_readchar_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_hard_uart_sendbreak_obj) }, + + // class constants +/* + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, +*/ +}; + +STATIC MP_DEFINE_CONST_DICT(machine_hard_uart_locals_dict, machine_hard_uart_locals_dict_table); + +STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + const machine_hard_uart_obj_t *self = self_in; + byte *buf = buf_in; + + // read the data + for (size_t i = 0; i < size; i++) { + buf[i] = uart_rx_char(self); + } + + return size; +} + +STATIC mp_uint_t machine_hard_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_hard_uart_obj_t *self = self_in; + const byte *buf = buf_in; + + nrfx_err_t err = NRFX_SUCCESS; + for (int i = 0; i < size; i++) { + err = uart_tx_char(self, (int)((uint8_t *)buf)[i]); + } + + if (err == NRFX_SUCCESS) { + // return number of bytes written + return size; + } else { + *errcode = mp_hal_status_to_errno_table[err]; + return MP_STREAM_ERROR; + } +} + +STATIC mp_uint_t machine_hard_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + machine_hard_uart_obj_t *self = self_in; + (void)self; + return MP_STREAM_ERROR; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_hard_uart_read, + .write = machine_hard_uart_write, + .ioctl = machine_hard_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_hard_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_hard_uart_print, + .make_new = machine_hard_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_hard_uart_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_UART diff --git a/src/openmv/src/micropython/ports/nrf/modules/machine/uart.h b/src/openmv/src/micropython/ports/nrf/modules/machine/uart.h new file mode 100755 index 0000000..121f83c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/machine/uart.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 - 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UART_H__ +#define UART_H__ + +#include "pin.h" +#include "genhdr/pins.h" + +typedef struct _machine_hard_uart_obj_t machine_hard_uart_obj_t; +extern const mp_obj_type_t machine_hard_uart_type; + +void uart_init0(void); +void uart_deinit(void); +void uart_irq_handler(mp_uint_t uart_id); + +bool uart_rx_any(const machine_hard_uart_obj_t * uart_obj); +int uart_rx_char(const machine_hard_uart_obj_t * uart_obj); +void uart_tx_strn(const machine_hard_uart_obj_t * uart_obj, const char *str, uint len); +void uart_tx_strn_cooked(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len); + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.c b/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.c new file mode 100755 index 0000000..71f6d36 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.c @@ -0,0 +1,512 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_MUSIC + +// #include "microbitobj.h" +// #include "microbitmusic.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "modmusic.h" +#include "musictunes.h" +#include "softpwm.h" +#include "ticker.h" +#include "pin.h" +#include "genhdr/pins.h" + +#define DEFAULT_BPM 120 +#define DEFAULT_TICKS 4 // i.e. 4 ticks per beat +#define DEFAULT_OCTAVE 4 // C4 is middle C +#define DEFAULT_DURATION 4 // Crotchet +#define ARTICULATION_MS 10 // articulation between notes in milliseconds + +typedef struct _music_data_t { + uint16_t bpm; + uint16_t ticks; + + // store these to simplify the writing process + uint8_t last_octave; + uint8_t last_duration; + + // Asynchronous parts. + volatile uint8_t async_state; + bool async_loop; + uint32_t async_wait_ticks; + uint16_t async_notes_len; + uint16_t async_notes_index; + const pin_obj_t *async_pin; + mp_obj_t async_note; +} music_data_t; + +enum { + ASYNC_MUSIC_STATE_IDLE, + ASYNC_MUSIC_STATE_NEXT_NOTE, + ASYNC_MUSIC_STATE_ARTICULATE, +}; + +#define music_data MP_STATE_PORT(music_data) + +extern volatile uint32_t ticks; + +STATIC uint32_t start_note(const char *note_str, size_t note_len, const pin_obj_t *pin); + +void microbit_music_init0(void) { + ticker_register_low_pri_callback(microbit_music_tick); +} + +void microbit_music_tick(void) { + if (music_data == NULL) { + // music module not yet imported + return; + } + + if (music_data->async_state == ASYNC_MUSIC_STATE_IDLE) { + // nothing to do + return; + } + + if (ticks < music_data->async_wait_ticks) { + // need to wait for timeout to expire + return; + } + + if (music_data->async_state == ASYNC_MUSIC_STATE_ARTICULATE) { + // turn off output and rest + pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting. + music_data->async_wait_ticks = ticks + ARTICULATION_MS; + music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; + } else if (music_data->async_state == ASYNC_MUSIC_STATE_NEXT_NOTE) { + // play next note + if (music_data->async_notes_index >= music_data->async_notes_len) { + if (music_data->async_loop) { + music_data->async_notes_index = 0; + } else { + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; +// TODO: microbit_obj_pin_free(music_data->async_pin); + music_data->async_pin = NULL; + return; + } + } + mp_obj_t note; + if (music_data->async_notes_len == 1) { + note = music_data->async_note; + } else { + note = ((mp_obj_t*)music_data->async_note)[music_data->async_notes_index]; + } + if (note == mp_const_none) { + // a rest (is this even used anymore?) + pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting. + music_data->async_wait_ticks = 60000 / music_data->bpm; + music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; + } else { + // a note + mp_uint_t note_len; + const char *note_str = mp_obj_str_get_data(note, ¬e_len); + uint32_t delay_on = start_note(note_str, note_len, music_data->async_pin); + music_data->async_wait_ticks = ticks + delay_on; + music_data->async_notes_index += 1; + music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE; + } + } +} + +STATIC void wait_async_music_idle(void) { + // wait for the async music state to become idle + while (music_data->async_state != ASYNC_MUSIC_STATE_IDLE) { + // allow CTRL-C to stop the music + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; + pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting. + break; + } + } +} + +STATIC uint32_t start_note(const char *note_str, size_t note_len, const pin_obj_t *pin) { + pwm_set_duty_cycle(pin->pin, 128); // TODO: remove pin setting. + + // [NOTE](#|b)(octave)(:length) + // technically, c4 is middle c, so we'll go with that... + // if we define A as 0 and G as 7, then we can use the following + // array of us periods + + // these are the periods of note4 (the octave ascending from middle c) from A->B then C->G + STATIC uint16_t periods_us[] = {2273, 2025, 3822, 3405, 3034, 2863, 2551}; + // A#, -, C#, D#, -, F#, G# + STATIC uint16_t periods_sharps_us[] = {2145, 0, 3608, 3214, 0, 2703, 2408}; + + // we'll represent the note as an integer (A=0, G=6) + // TODO: validate the note + uint8_t note_index = (note_str[0] & 0x1f) - 1; + + // TODO: the duration and bpm should be persistent between notes + uint32_t ms_per_tick = (60000 / music_data->bpm) / music_data->ticks; + + int8_t octave = 0; + bool sharp = false; + + size_t current_position = 1; + + // parse sharp or flat + if (current_position < note_len && (note_str[current_position] == '#' || note_str[current_position] == 'b')) { + if (note_str[current_position] == 'b') { + // make sure we handle wrapping round gracefully + if (note_index == 0) { + note_index = 6; + } else { + note_index--; + } + + // handle the unusual edge case of Cb + if (note_index == 1) { + octave--; + } + } + + sharp = true; + current_position++; + } + + // parse the octave + if (current_position < note_len && note_str[current_position] != ':') { + // currently this will only work with a one digit number + // use +=, since the sharp/flat code changes octave to compensate. + music_data->last_octave = (note_str[current_position] & 0xf); + current_position++; + } + + octave += music_data->last_octave; + + // parse the duration + if (current_position < note_len && note_str[current_position] == ':') { + // I'll make this handle up to two digits for the time being. + current_position++; + + if (current_position < note_len) { + music_data->last_duration = note_str[current_position] & 0xf; + + current_position++; + if (current_position < note_len) { + music_data->last_duration *= 10; + music_data->last_duration += note_str[current_position] & 0xf; + } + } else { + // technically, this should be a syntax error, since this means + // that no duration has been specified. For the time being, + // we'll let you off :D + } + } + // play the note! + + // make the octave relative to octave 4 + octave -= 4; + + // 18 is 'r' or 'R' + if (note_index < 10) { + uint32_t period; + if (sharp) { + if (octave >= 0) { + period = periods_sharps_us[note_index] >> octave; + } + else { + period = periods_sharps_us[note_index] << -octave; + } + } else { + if (octave >= 0) { + period = periods_us[note_index] >> octave; + } + else { + period = periods_us[note_index] << -octave; + } + } + pwm_set_period_us(period); + } else { + pwm_set_duty_cycle(pin->pin, 0); // TODO: remove pin setting. + } + + // Cut off a short time from end of note so we hear articulation. + mp_int_t gap_ms = (ms_per_tick * music_data->last_duration) - ARTICULATION_MS; + if (gap_ms < ARTICULATION_MS) { + gap_ms = ARTICULATION_MS; + } + return gap_ms; +} + +STATIC mp_obj_t microbit_music_reset(void) { + music_data->bpm = DEFAULT_BPM; + music_data->ticks = DEFAULT_TICKS; + music_data->last_octave = DEFAULT_OCTAVE; + music_data->last_duration = DEFAULT_DURATION; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_reset_obj, microbit_music_reset); + +STATIC mp_obj_t microbit_music_get_tempo(void) { + mp_obj_t tempo_tuple[2]; + + tempo_tuple[0] = mp_obj_new_int(music_data->bpm); + tempo_tuple[1] = mp_obj_new_int(music_data->ticks); + + return mp_obj_new_tuple(2, tempo_tuple); +} +MP_DEFINE_CONST_FUN_OBJ_0(microbit_music_get_tempo_obj, microbit_music_get_tempo); + +STATIC mp_obj_t microbit_music_stop(mp_uint_t n_args, const mp_obj_t *args) { + const pin_obj_t *pin; + if (n_args == 0) { +#ifdef MICROPY_HW_MUSIC_PIN + pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN)); +#else + mp_raise_ValueError("pin parameter not given"); +#endif + } else { + pin = (pin_obj_t *)args[0]; + } + (void)pin; + // Raise exception if the pin we are trying to stop is not in a compatible mode. +// TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music); + pwm_set_duty_cycle(pin->pin, 0); // TODO: remove pin setting. +// TODO: microbit_obj_pin_free(pin); + music_data->async_pin = NULL; + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_music_stop_obj, 0, 1, microbit_music_stop); + +STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_music, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_loop, MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // reset octave and duration so tunes always play the same + music_data->last_octave = DEFAULT_OCTAVE; + music_data->last_duration = DEFAULT_DURATION; + + // get either a single note or a list of notes + mp_uint_t len; + mp_obj_t *items; + if (MP_OBJ_IS_STR_OR_BYTES(args[0].u_obj)) { + len = 1; + items = &args[0].u_obj; + } else { + mp_obj_get_array(args[0].u_obj, &len, &items); + } + + // Release the previous pin +// TODO: microbit_obj_pin_free(music_data->async_pin); + music_data->async_pin = NULL; + + // get the pin to play on + const pin_obj_t *pin; + if (args[1].u_obj == MP_OBJ_NULL) { +#ifdef MICROPY_HW_MUSIC_PIN + pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN)); +#else + mp_raise_ValueError("pin parameter not given"); +#endif + } else { + pin = (pin_obj_t *)args[1].u_obj; + } + // TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music); + + // start the tune running in the background + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; + music_data->async_wait_ticks = ticks; + music_data->async_loop = args[3].u_bool; + music_data->async_notes_len = len; + music_data->async_notes_index = 0; + if (len == 1) { + // If a string was passed as a single note then we can't store a pointer + // to args[0].u_obj, so instead store the single string directly (also + // works if a tuple/list of one element was passed). + music_data->async_note = items[0]; + } else { + music_data->async_note = items; + } + music_data->async_pin = pin; + music_data->async_state = ASYNC_MUSIC_STATE_NEXT_NOTE; + + if (args[2].u_bool) { + // wait for tune to finish + wait_async_music_idle(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_play_obj, 0, microbit_music_play); + +STATIC mp_obj_t microbit_music_pitch(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_duration, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_wait, MP_ARG_BOOL, {.u_bool = true} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the parameters + mp_uint_t frequency = args[0].u_int; + mp_int_t duration = args[1].u_int; + + // get the pin to play on + const pin_obj_t *pin; + if (args[2].u_obj == MP_OBJ_NULL) { +#ifdef MICROPY_HW_MUSIC_PIN + pin = mp_hal_get_pin_obj(MP_OBJ_NEW_SMALL_INT(MICROPY_HW_MUSIC_PIN)); +#else + mp_raise_ValueError("pin parameter not given"); +#endif + } else { + pin = (pin_obj_t *)args[2].u_obj; + } + + // Update pin modes +//TODO: microbit_obj_pin_free(music_data->async_pin); + music_data->async_pin = NULL; +//TODO: microbit_obj_pin_acquire(pin, microbit_pin_mode_music); + bool wait = args[3].u_bool; + pwm_set_duty_cycle(pin->pin, 128); // TODO: remove pin setting. + if (frequency == 0) { +//TODO: pwm_release(pin->name); + } else if (pwm_set_period_us(1000000/frequency)) { + pwm_release(pin->pin); // TODO: remove pin setting. + mp_raise_ValueError("invalid pitch"); + } + if (duration >= 0) { + // use async machinery to stop the pitch after the duration + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; + music_data->async_wait_ticks = ticks + duration; + music_data->async_loop = false; + music_data->async_notes_len = 0; + music_data->async_notes_index = 0; + music_data->async_note = NULL; + music_data->async_pin = pin; + music_data->async_state = ASYNC_MUSIC_STATE_ARTICULATE; + + if (wait) { + // wait for the pitch to finish + wait_async_music_idle(); + } + } else { + // don't block here, since there's no reason to leave a pitch forever in a blocking C function + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_pitch_obj, 0, microbit_music_pitch); + +STATIC mp_obj_t microbit_music_set_tempo(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ticks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bpm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[0].u_int != 0) { + // set ticks + music_data->ticks = args[0].u_int; + } + + if (args[1].u_int != 0) { + music_data->bpm = args[1].u_int; + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(microbit_music_set_tempo_obj, 0, microbit_music_set_tempo); + + +static mp_obj_t music_init(void) { + music_data = m_new_obj(music_data_t); + music_data->bpm = DEFAULT_BPM; + music_data->ticks = DEFAULT_TICKS; + music_data->last_octave = DEFAULT_OCTAVE; + music_data->last_duration = DEFAULT_DURATION; + music_data->async_state = ASYNC_MUSIC_STATE_IDLE; + music_data->async_pin = NULL; + music_data->async_note = NULL; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(music___init___obj, music_init); + +STATIC const mp_rom_map_elem_t microbit_music_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&music___init___obj) }, + + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(µbit_music_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_tempo), MP_ROM_PTR(µbit_music_set_tempo_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_tempo), MP_ROM_PTR(µbit_music_get_tempo_obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(µbit_music_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_pitch), MP_ROM_PTR(µbit_music_pitch_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(µbit_music_stop_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DADADADUM), MP_ROM_PTR(µbit_music_tune_dadadadum_obj) }, + { MP_ROM_QSTR(MP_QSTR_ENTERTAINER), MP_ROM_PTR(µbit_music_tune_entertainer_obj) }, + { MP_ROM_QSTR(MP_QSTR_PRELUDE), MP_ROM_PTR(µbit_music_tune_prelude_obj) }, + { MP_ROM_QSTR(MP_QSTR_ODE), MP_ROM_PTR(µbit_music_tune_ode_obj) }, + { MP_ROM_QSTR(MP_QSTR_NYAN), MP_ROM_PTR(µbit_music_tune_nyan_obj) }, + { MP_ROM_QSTR(MP_QSTR_RINGTONE), MP_ROM_PTR(µbit_music_tune_ringtone_obj) }, + { MP_ROM_QSTR(MP_QSTR_FUNK), MP_ROM_PTR(µbit_music_tune_funk_obj) }, + { MP_ROM_QSTR(MP_QSTR_BLUES), MP_ROM_PTR(µbit_music_tune_blues_obj) }, + { MP_ROM_QSTR(MP_QSTR_BIRTHDAY), MP_ROM_PTR(µbit_music_tune_birthday_obj) }, + { MP_ROM_QSTR(MP_QSTR_WEDDING), MP_ROM_PTR(µbit_music_tune_wedding_obj) }, + { MP_ROM_QSTR(MP_QSTR_FUNERAL), MP_ROM_PTR(µbit_music_tune_funeral_obj) }, + { MP_ROM_QSTR(MP_QSTR_PUNCHLINE), MP_ROM_PTR(µbit_music_tune_punchline_obj) }, + { MP_ROM_QSTR(MP_QSTR_PYTHON), MP_ROM_PTR(µbit_music_tune_python_obj) }, + { MP_ROM_QSTR(MP_QSTR_BADDY), MP_ROM_PTR(µbit_music_tune_baddy_obj) }, + { MP_ROM_QSTR(MP_QSTR_CHASE), MP_ROM_PTR(µbit_music_tune_chase_obj) }, + { MP_ROM_QSTR(MP_QSTR_BA_DING), MP_ROM_PTR(µbit_music_tune_ba_ding_obj) }, + { MP_ROM_QSTR(MP_QSTR_WAWAWAWAA), MP_ROM_PTR(µbit_music_tune_wawawawaa_obj) }, + { MP_ROM_QSTR(MP_QSTR_JUMP_UP), MP_ROM_PTR(µbit_music_tune_jump_up_obj) }, + { MP_ROM_QSTR(MP_QSTR_JUMP_DOWN), MP_ROM_PTR(µbit_music_tune_jump_down_obj) }, + { MP_ROM_QSTR(MP_QSTR_POWER_UP), MP_ROM_PTR(µbit_music_tune_power_up_obj) }, + { MP_ROM_QSTR(MP_QSTR_POWER_DOWN), MP_ROM_PTR(µbit_music_tune_power_down_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(microbit_music_locals_dict, microbit_music_locals_dict_table); + +const mp_obj_module_t music_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)µbit_music_locals_dict, +}; + +#endif // MICROPY_PY_MUSIC diff --git a/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.h b/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.h new file mode 100755 index 0000000..8e64f02 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/music/modmusic.h @@ -0,0 +1,7 @@ +#ifndef __MICROPY_INCLUDED_MICROBIT_MUSIC_H__ +#define __MICROPY_INCLUDED_MICROBIT_MUSIC_H__ + +void microbit_music_init0(void); +void microbit_music_tick(void); + +#endif // __MICROPY_INCLUDED_MICROBIT_MUSIC_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.c b/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.c new file mode 100755 index 0000000..77800a4 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.c @@ -0,0 +1,171 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The music encoded herein is either in the public domain, composed by + * Nicholas H.Tollervey or the composer is untraceable and covered by fair + * (educational) use. + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * Copyright (c) 2015 Nicholas H. Tollervey + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "py/objtuple.h" + +#if MICROPY_PY_MUSIC + +#define N(q) MP_ROM_QSTR(MP_QSTR_ ## q) +#define T(name, ...) \ +typedef struct music_tune_ ## name ## _s {\ + mp_obj_base_t base; \ + size_t len; \ + mp_rom_obj_t items[sizeof((mp_obj_t[]){__VA_ARGS__})/sizeof(mp_obj_t)]; \ +} music_tune_ ## name ## _t; \ +\ +const music_tune_ ## name ## _t microbit_music_tune_ ## name ## _obj = {{&mp_type_tuple}, .len = (sizeof((mp_obj_t[]){__VA_ARGS__})/sizeof(mp_obj_t)), .items = {__VA_ARGS__}}; + + +T(dadadadum, + N(r4_colon_2), N(g), N(g), N(g), N(eb_colon_8), N(r_colon_2), N(f), N(f), + N(f), N(d_colon_8)); + +T(entertainer, + N(d4_colon_1), N(d_hash_), N(e), N(c5_colon_2), N(e4_colon_1), + N(c5_colon_2), N(e4_colon_1), N(c5_colon_3), N(c_colon_1), N(d), + N(d_hash_), N(e), N(c), N(d), N(e_colon_2), N(b4_colon_1), N(d5_colon_2), + N(c_colon_4)); + +T(prelude, + N(c4_colon_1), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e), N(c4), N(e), + N(g), N(c5), N(e), N(g4), N(c5), N(e), N(c4), N(d), N(g), N(d5), N(f), + N(g4), N(d5), N(f), N(c4), N(d), N(g), N(d5), N(f), N(g4), N(d5), N(f), + N(b3), N(d4), N(g), N(d5), N(f), N(g4), N(d5), N(f), N(b3), N(d4), N(g), + N(d5), N(f), N(g4), N(d5), N(f), N(c4), N(e), N(g), N(c5), N(e), N(g4), + N(c5), N(e), N(c4), N(e), N(g), N(c5), N(e), N(g4), N(c5), N(e)); + +T(ode, + N(e4), N(e), N(f), N(g), N(g), N(f), N(e), N(d), N(c), N(c), N(d), N(e), + N(e_colon_6), N(d_colon_2), N(d_colon_8), N(e_colon_4), N(e), N(f), N(g), + N(g), N(f), N(e), N(d), N(c), N(c), N(d), N(e), N(d_colon_6), + N(c_colon_2), N(c_colon_8)); + +T(nyan, + N(f_hash_5_colon_2), N(g_hash_), N(c_hash__colon_1), N(d_hash__colon_2), + N(b4_colon_1), N(d5_colon_1), N(c_hash_), N(b4_colon_2), N(b), + N(c_hash_5), N(d), N(d_colon_1), N(c_hash_), N(b4_colon_1), + N(c_hash_5_colon_1), N(d_hash_), N(f_hash_), N(g_hash_), N(d_hash_), + N(f_hash_), N(c_hash_), N(d), N(b4), N(c_hash_5), N(b4), + N(d_hash_5_colon_2), N(f_hash_), N(g_hash__colon_1), N(d_hash_), + N(f_hash_), N(c_hash_), N(d_hash_), N(b4), N(d5), N(d_hash_), N(d), + N(c_hash_), N(b4), N(c_hash_5), N(d_colon_2), N(b4_colon_1), N(c_hash_5), + N(d_hash_), N(f_hash_), N(c_hash_), N(d), N(c_hash_), N(b4), + N(c_hash_5_colon_2), N(b4), N(c_hash_5), N(b4), N(f_hash__colon_1), + N(g_hash_), N(b_colon_2), N(f_hash__colon_1), N(g_hash_), N(b), + N(c_hash_5), N(d_hash_), N(b4), N(e5), N(d_hash_), N(e), N(f_hash_), + N(b4_colon_2), N(b), N(f_hash__colon_1), N(g_hash_), N(b), N(f_hash_), + N(e5), N(d_hash_), N(c_hash_), N(b4), N(f_hash_), N(d_hash_), N(e), + N(f_hash_), N(b_colon_2), N(f_hash__colon_1), N(g_hash_), N(b_colon_2), + N(f_hash__colon_1), N(g_hash_), N(b), N(b), N(c_hash_5), N(d_hash_), + N(b4), N(f_hash_), N(g_hash_), N(f_hash_), N(b_colon_2), N(b_colon_1), + N(a_hash_), N(b), N(f_hash_), N(g_hash_), N(b), N(e5), N(d_hash_), N(e), + N(f_hash_), N(b4_colon_2), N(c_hash_5)); + +T(ringtone, + N(c4_colon_1), N(d), N(e_colon_2), N(g), N(d_colon_1), N(e), N(f_colon_2), + N(a), N(e_colon_1), N(f), N(g_colon_2), N(b), N(c5_colon_4)); + +T(funk, + N(c2_colon_2), N(c), N(d_hash_), N(c_colon_1), N(f_colon_2), N(c_colon_1), + N(f_colon_2), N(f_hash_), N(g), N(c), N(c), N(g), N(c_colon_1), + N(f_hash__colon_2), N(c_colon_1), N(f_hash__colon_2), N(f), N(d_hash_)); + +T(blues, + N(c2_colon_2), N(e), N(g), N(a), N(a_hash_), N(a), N(g), N(e), + N(c2_colon_2), N(e), N(g), N(a), N(a_hash_), N(a), N(g), N(e), N(f), N(a), + N(c3), N(d), N(d_hash_), N(d), N(c), N(a2), N(c2_colon_2), N(e), N(g), + N(a), N(a_hash_), N(a), N(g), N(e), N(g), N(b), N(d3), N(f), N(f2), N(a), + N(c3), N(d_hash_), N(c2_colon_2), N(e), N(g), N(e), N(g), N(f), N(e), + N(d)); + +T(birthday, + N(c4_colon_3), N(c_colon_1), N(d_colon_4), N(c_colon_4), N(f), + N(e_colon_8), N(c_colon_3), N(c_colon_1), N(d_colon_4), N(c_colon_4), + N(g), N(f_colon_8), N(c_colon_3), N(c_colon_1), N(c5_colon_4), N(a4), + N(f), N(e), N(d), N(a_hash__colon_3), N(a_hash__colon_1), N(a_colon_4), + N(f), N(g), N(f_colon_8)); + +T(wedding, + N(c4_colon_4), N(f_colon_3), N(f_colon_1), N(f_colon_8), N(c_colon_4), + N(g_colon_3), N(e_colon_1), N(f_colon_8), N(c_colon_4), N(f_colon_3), + N(a_colon_1), N(c5_colon_4), N(a4_colon_3), N(f_colon_1), N(f_colon_4), + N(e_colon_3), N(f_colon_1), N(g_colon_8)); + +T(funeral, + N(c3_colon_4), N(c_colon_3), N(c_colon_1), N(c_colon_4), + N(d_hash__colon_3), N(d_colon_1), N(d_colon_3), N(c_colon_1), + N(c_colon_3), N(b2_colon_1), N(c3_colon_4)); + +T(punchline, + N(c4_colon_3), N(g3_colon_1), N(f_hash_), N(g), N(g_hash__colon_3), N(g), + N(r), N(b), N(c4)); + +T(python, + N(d5_colon_1), N(b4), N(r), N(b), N(b), N(a_hash_), N(b), N(g5), N(r), + N(d), N(d), N(r), N(b4), N(c5), N(r), N(c), N(c), N(r), N(d), + N(e_colon_5), N(c_colon_1), N(a4), N(r), N(a), N(a), N(g_hash_), N(a), + N(f_hash_5), N(r), N(e), N(e), N(r), N(c), N(b4), N(r), N(b), N(b), N(r), + N(c5), N(d_colon_5), N(d_colon_1), N(b4), N(r), N(b), N(b), N(a_hash_), + N(b), N(b5), N(r), N(g), N(g), N(r), N(d), N(c_hash_), N(r), N(a), N(a), + N(r), N(a), N(a_colon_5), N(g_colon_1), N(f_hash__colon_2), N(a_colon_1), + N(a), N(g_hash_), N(a), N(e_colon_2), N(a_colon_1), N(a), N(g_hash_), + N(a), N(d), N(r), N(c_hash_), N(d), N(r), N(c_hash_), N(d_colon_2), + N(r_colon_3)); + +T(baddy, + N(c3_colon_3), N(r), N(d_colon_2), N(d_hash_), N(r), N(c), N(r), N(f_hash__colon_8), ); + +T(chase, + N(a4_colon_1), N(b), N(c5), N(b4), N(a_colon_2), N(r), N(a_colon_1), N(b), N(c5), N(b4), N(a_colon_2), N(r), N(a_colon_2), N(e5), N(d_hash_), N(e), N(f), N(e), N(d_hash_), N(e), N(b4_colon_1), N(c5), N(d), N(c), N(b4_colon_2), N(r), N(b_colon_1), N(c5), N(d), N(c), N(b4_colon_2), N(r), N(b_colon_2), N(e5), N(d_hash_), N(e), N(f), N(e), N(d_hash_), N(e), ); + +T(ba_ding, + N(b5_colon_1), N(e6_colon_3), ); + +T(wawawawaa, + N(e3_colon_3), N(r_colon_1), N(d_hash__colon_3), N(r_colon_1), N(d_colon_4), N(r_colon_1), N(c_hash__colon_8), ); + +T(jump_up, + N(c5_colon_1), N(d), N(e), N(f), N(g), ); + +T(jump_down, + N(g5_colon_1), N(f), N(e), N(d), N(c), ); + +T(power_up, + N(g4_colon_1), N(c5), N(e), N(g_colon_2), N(e_colon_1), N(g_colon_3), ); + +T(power_down, + N(g5_colon_1), N(d_hash_), N(c), N(g4_colon_2), N(b_colon_1), N(c5_colon_3), ); + +#undef N +#undef T + +#endif // MICROPY_PY_MUSIC diff --git a/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.h b/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.h new file mode 100755 index 0000000..f0444bf --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/music/musictunes.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MUSIC_TUNES_H__ +#define MUSIC_TUNES_H__ + +struct music_tune_dadadum_s; +struct music_tune_entertainer_s; +struct music_tune_prelude_s; +struct music_tune_ode_s; +struct music_tune_nyan_s; +struct music_tune_ringtone_s; +struct music_tune_funk_s; +struct music_tune_blues_s; +struct music_tune_birthday_s; +struct music_tune_wedding_s; +struct music_tune_funeral_s; +struct music_tune_punchline_s; +struct music_tune_python_s; +struct music_tune_baddy_s; +struct music_tune_chase_s; +struct music_tune_ba_ding_s; +struct music_tune_wawawawaa_s; +struct music_tune_jump_up_s; +struct music_tune_jump_down_s; +struct music_tune_power_up_s; +struct music_tune_power_down_s; + +extern const struct music_tune_dadadadum_s microbit_music_tune_dadadadum_obj; +extern const struct music_tune_entertainer_s microbit_music_tune_entertainer_obj; +extern const struct music_tune_prelude_s microbit_music_tune_prelude_obj; +extern const struct music_tune_ode_s microbit_music_tune_ode_obj; +extern const struct music_tune_nyan_s microbit_music_tune_nyan_obj; +extern const struct music_tune_ringtone_s microbit_music_tune_ringtone_obj; +extern const struct music_tune_funk_s microbit_music_tune_funk_obj; +extern const struct music_tune_blues_s microbit_music_tune_blues_obj; +extern const struct music_tune_birthday_s microbit_music_tune_birthday_obj; +extern const struct music_tune_wedding_s microbit_music_tune_wedding_obj; +extern const struct music_tune_funeral_s microbit_music_tune_funeral_obj; +extern const struct music_tune_punchline_s microbit_music_tune_punchline_obj; +extern const struct music_tune_python_s microbit_music_tune_python_obj; +extern const struct music_tune_baddy_s microbit_music_tune_baddy_obj; +extern const struct music_tune_chase_s microbit_music_tune_chase_obj; +extern const struct music_tune_ba_ding_s microbit_music_tune_ba_ding_obj; +extern const struct music_tune_wawawawaa_s microbit_music_tune_wawawawaa_obj; +extern const struct music_tune_jump_up_s microbit_music_tune_jump_up_obj; +extern const struct music_tune_jump_down_s microbit_music_tune_jump_down_obj; +extern const struct music_tune_power_up_s microbit_music_tune_power_up_obj; +extern const struct music_tune_power_down_s microbit_music_tune_power_down_obj; + +#endif // MUSIC_TUNES_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.c b/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.c new file mode 100755 index 0000000..f67bffb --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.c @@ -0,0 +1,223 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_RANDOM_HW_RNG + +#include "nrf_rng.h" +#include "modrandom.h" + +#if BLUETOOTH_SD +#include "nrf_soc.h" +#include "ble_drv.h" +#define BLUETOOTH_STACK_ENABLED() (ble_drv_stack_enabled()) +#endif + +static inline uint32_t generate_hw_random(void) { + uint32_t retval = 0; + uint8_t * p_retval = (uint8_t *)&retval; + + nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY); + nrf_rng_task_trigger(NRF_RNG_TASK_START); + + for (uint16_t i = 0; i < 4; i++) { + while (!nrf_rng_event_get(NRF_RNG_EVENT_VALRDY)) { + ; + } + + nrf_rng_event_clear(NRF_RNG_EVENT_VALRDY); + p_retval[i] = nrf_rng_random_value_get(); + } + + nrf_rng_task_trigger(NRF_RNG_TASK_STOP); + + return retval; +} + +uint32_t machine_rng_generate_random_word(void) { + +#if BLUETOOTH_SD + if (BLUETOOTH_STACK_ENABLED() == 1) { + uint32_t retval = 0; + uint32_t status; + do { + status = sd_rand_application_vector_get((uint8_t *)&retval, 4); // Extract 4 bytes + } while (status != 0); + + return retval; + } +#endif + + return generate_hw_random(); +} + +static inline int rand30(void) { + uint32_t val = machine_rng_generate_random_word(); + return (val & 0x3fffffff); // binary mask b00111111111111111111111111111111 +} + +static inline int randbelow(int n) { + return rand30() % n; +} + +STATIC mp_obj_t mod_random_getrandbits(mp_obj_t num_in) { + int n = mp_obj_get_int(num_in); + if (n > 30 || n == 0) { + mp_raise_ValueError(NULL); + } + uint32_t mask = ~0; + // Beware of C undefined behavior when shifting by >= than bit size + mask >>= (32 - n); + return mp_obj_new_int_from_uint(rand30() & mask); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_getrandbits_obj, mod_random_getrandbits); + +STATIC mp_obj_t mod_random_randrange(size_t n_args, const mp_obj_t *args) { + mp_int_t start = mp_obj_get_int(args[0]); + if (n_args == 1) { + // range(stop) + if (start > 0) { + return mp_obj_new_int(randbelow(start)); + } else { + mp_raise_ValueError(NULL); + } + } else { + mp_int_t stop = mp_obj_get_int(args[1]); + if (n_args == 2) { + // range(start, stop) + if (start < stop) { + return mp_obj_new_int(start + randbelow(stop - start)); + } else { + mp_raise_ValueError(NULL); + } + } else { + // range(start, stop, step) + mp_int_t step = mp_obj_get_int(args[2]); + mp_int_t n; + if (step > 0) { + n = (stop - start + step - 1) / step; + } else if (step < 0) { + n = (stop - start + step + 1) / step; + } else { + mp_raise_ValueError(NULL); + } + if (n > 0) { + return mp_obj_new_int(start + step * randbelow(n)); + } else { + mp_raise_ValueError(NULL); + } + } + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_random_randrange_obj, 1, 3, mod_random_randrange); + +STATIC mp_obj_t mod_random_randint(mp_obj_t a_in, mp_obj_t b_in) { + mp_int_t a = mp_obj_get_int(a_in); + mp_int_t b = mp_obj_get_int(b_in); + if (a <= b) { + return mp_obj_new_int(a + randbelow(b - a + 1)); + } else { + mp_raise_ValueError(NULL); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_randint_obj, mod_random_randint); + +STATIC mp_obj_t mod_random_choice(mp_obj_t seq) { + mp_int_t len = mp_obj_get_int(mp_obj_len(seq)); + if (len > 0) { + return mp_obj_subscr(seq, mp_obj_new_int(randbelow(len)), MP_OBJ_SENTINEL); + } else { + nlr_raise(mp_obj_new_exception(&mp_type_IndexError)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_choice_obj, mod_random_choice); + +#if MICROPY_PY_BUILTINS_FLOAT + +// returns a number in the range [0..1) using RNG to fill in the fraction bits +STATIC mp_float_t randfloat(void) { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + typedef uint64_t mp_float_int_t; + #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + typedef uint32_t mp_float_int_t; + #endif + union { + mp_float_t f; + #if MP_ENDIANNESS_LITTLE + struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; + #else + struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; + #endif + } u; + u.p.sgn = 0; + u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1; + if (MP_FLOAT_FRAC_BITS <= 30) { + u.p.frc = rand30(); + } else { + u.p.frc = ((uint64_t)rand30() << 30) | (uint64_t)rand30(); + } + return u.f - 1; +} + +STATIC mp_obj_t mod_random_random(void) { + return mp_obj_new_float(randfloat()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_random_random_obj, mod_random_random); + +STATIC mp_obj_t mod_random_uniform(mp_obj_t a_in, mp_obj_t b_in) { + mp_float_t a = mp_obj_get_float(a_in); + mp_float_t b = mp_obj_get_float(b_in); + return mp_obj_new_float(a + (b - a) * randfloat()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_uniform_obj, mod_random_uniform); + +#endif + +STATIC const mp_rom_map_elem_t mp_module_random_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) }, + { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_random_getrandbits_obj) }, + { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_random_randrange_obj) }, + { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_random_randint_obj) }, + { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_random_choice_obj) }, +#if MICROPY_PY_BUILTINS_FLOAT + { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_random_random_obj) }, + { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_random_uniform_obj) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_random_globals, mp_module_random_globals_table); + +const mp_obj_module_t random_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_random_globals, +}; + +#endif // MICROPY_PY_RANDOM_HW_RNG diff --git a/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.h b/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.h new file mode 100755 index 0000000..6a6b605 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/random/modrandom.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +uint32_t machine_rng_generate_random_word(void); diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.c new file mode 100755 index 0000000..b306c06 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.c @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#if MICROPY_PY_UBLUEPY + +extern const mp_obj_type_t ubluepy_peripheral_type; +extern const mp_obj_type_t ubluepy_service_type; +extern const mp_obj_type_t ubluepy_uuid_type; +extern const mp_obj_type_t ubluepy_characteristic_type; +extern const mp_obj_type_t ubluepy_delegate_type; +extern const mp_obj_type_t ubluepy_constants_type; +extern const mp_obj_type_t ubluepy_scanner_type; +extern const mp_obj_type_t ubluepy_scan_entry_type; + +STATIC const mp_rom_map_elem_t mp_module_ubluepy_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluepy) }, +#if MICROPY_PY_UBLUEPY_PERIPHERAL + { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&ubluepy_peripheral_type) }, +#endif +#if 0 // MICROPY_PY_UBLUEPY_CENTRAL + { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&ubluepy_central_type) }, +#endif +#if MICROPY_PY_UBLUEPY_CENTRAL + { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&ubluepy_scanner_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&ubluepy_scan_entry_type) }, +#endif + { MP_ROM_QSTR(MP_QSTR_DefaultDelegate), MP_ROM_PTR(&ubluepy_delegate_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&ubluepy_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&ubluepy_service_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&ubluepy_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_constants), MP_ROM_PTR(&ubluepy_constants_type) }, +#if MICROPY_PY_UBLUEPY_DESCRIPTOR + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&ubluepy_descriptor_type) }, +#endif +}; + + +STATIC MP_DEFINE_CONST_DICT(mp_module_ubluepy_globals, mp_module_ubluepy_globals_table); + +const mp_obj_module_t mp_module_ubluepy = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ubluepy_globals, +}; + +#endif // MICROPY_PY_UBLUEPY diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.h b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.h new file mode 100755 index 0000000..fbd07b8 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/modubluepy.h @@ -0,0 +1,200 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UBLUEPY_H__ +#define UBLUEPY_H__ + +/* Examples: + +Advertisment: + +from ubluepy import Peripheral +p = Peripheral() +p.advertise(device_name="MicroPython") + +DB setup: + +from ubluepy import Service, Characteristic, UUID, Peripheral, constants +from board import LED + +def event_handler(id, handle, data): + print("BLE event:", id, "handle:", handle) + print(data) + + if id == constants.EVT_GAP_CONNECTED: + # connected + LED(2).on() + elif id == constants.EVT_GAP_DISCONNECTED: + # disconnect + LED(2).off() + elif id == 80: + print("id 80, data:", data) + +# u0 = UUID("0x180D") # HRM service +# u1 = UUID("0x2A37") # HRM measurement + +u0 = UUID("6e400001-b5a3-f393-e0a9-e50e24dcca9e") +u1 = UUID("6e400002-b5a3-f393-e0a9-e50e24dcca9e") +u2 = UUID("6e400003-b5a3-f393-e0a9-e50e24dcca9e") +s = Service(u0) +c0 = Characteristic(u1, props = Characteristic.PROP_WRITE | Characteristic.PROP_WRITE_WO_RESP) +c1 = Characteristic(u2, props = Characteristic.PROP_NOTIFY, attrs = Characteristic.ATTR_CCCD) +s.addCharacteristic(c0) +s.addCharacteristic(c1) +p = Peripheral() +p.addService(s) +p.setConnectionHandler(event_handler) +p.advertise(device_name="micr", services=[s]) + +*/ + +#include "py/obj.h" + +extern const mp_obj_type_t ubluepy_uuid_type; +extern const mp_obj_type_t ubluepy_service_type; +extern const mp_obj_type_t ubluepy_characteristic_type; +extern const mp_obj_type_t ubluepy_peripheral_type; +extern const mp_obj_type_t ubluepy_scanner_type; +extern const mp_obj_type_t ubluepy_scan_entry_type; +extern const mp_obj_type_t ubluepy_constants_type; +extern const mp_obj_type_t ubluepy_constants_ad_types_type; + +typedef enum { + UBLUEPY_UUID_16_BIT = 1, + UBLUEPY_UUID_128_BIT +} ubluepy_uuid_type_t; + +typedef enum { + UBLUEPY_SERVICE_PRIMARY = 1, + UBLUEPY_SERVICE_SECONDARY = 2 +} ubluepy_service_type_t; + +typedef enum { + UBLUEPY_ADDR_TYPE_PUBLIC = 0, + UBLUEPY_ADDR_TYPE_RANDOM_STATIC = 1, +#if 0 + UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE = 2, + UBLUEPY_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = 3, +#endif +} ubluepy_addr_type_t; + +typedef enum { + UBLUEPY_ROLE_PERIPHERAL, + UBLUEPY_ROLE_CENTRAL +} ubluepy_role_type_t; + +typedef struct _ubluepy_uuid_obj_t { + mp_obj_base_t base; + ubluepy_uuid_type_t type; + uint8_t value[2]; + uint8_t uuid_vs_idx; +} ubluepy_uuid_obj_t; + +typedef struct _ubluepy_peripheral_obj_t { + mp_obj_base_t base; + ubluepy_role_type_t role; + volatile uint16_t conn_handle; + mp_obj_t delegate; + mp_obj_t notif_handler; + mp_obj_t conn_handler; + mp_obj_t service_list; +} ubluepy_peripheral_obj_t; + +typedef struct _ubluepy_service_obj_t { + mp_obj_base_t base; + uint16_t handle; + uint8_t type; + ubluepy_uuid_obj_t * p_uuid; + ubluepy_peripheral_obj_t * p_periph; + mp_obj_t char_list; + uint16_t start_handle; + uint16_t end_handle; +} ubluepy_service_obj_t; + +typedef struct _ubluepy_characteristic_obj_t { + mp_obj_base_t base; + uint16_t handle; + ubluepy_uuid_obj_t * p_uuid; + uint16_t service_handle; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; + uint8_t props; + uint8_t attrs; + ubluepy_service_obj_t * p_service; + mp_obj_t value_data; +} ubluepy_characteristic_obj_t; + +typedef struct _ubluepy_descriptor_obj_t { + mp_obj_base_t base; + uint16_t handle; + ubluepy_uuid_obj_t * p_uuid; +} ubluepy_descriptor_obj_t; + +typedef struct _ubluepy_delegate_obj_t { + mp_obj_base_t base; +} ubluepy_delegate_obj_t; + +typedef struct _ubluepy_advertise_data_t { + uint8_t * p_device_name; + uint8_t device_name_len; + mp_obj_t * p_services; + uint8_t num_of_services; + uint8_t * p_data; + uint8_t data_len; + bool connectable; +} ubluepy_advertise_data_t; + +typedef struct _ubluepy_scanner_obj_t { + mp_obj_base_t base; + mp_obj_t adv_reports; +} ubluepy_scanner_obj_t; + +typedef struct _ubluepy_scan_entry_obj_t { + mp_obj_base_t base; + mp_obj_t addr; + uint8_t addr_type; + bool connectable; + int8_t rssi; + mp_obj_t data; +} ubluepy_scan_entry_obj_t; + +typedef enum _ubluepy_prop_t { + UBLUEPY_PROP_BROADCAST = 0x01, + UBLUEPY_PROP_READ = 0x02, + UBLUEPY_PROP_WRITE_WO_RESP = 0x04, + UBLUEPY_PROP_WRITE = 0x08, + UBLUEPY_PROP_NOTIFY = 0x10, + UBLUEPY_PROP_INDICATE = 0x20, + UBLUEPY_PROP_AUTH_SIGNED_WR = 0x40, +} ubluepy_prop_t; + +typedef enum _ubluepy_attr_t { + UBLUEPY_ATTR_CCCD = 0x01, + UBLUEPY_ATTR_SCCD = 0x02, +} ubluepy_attr_t; + +#endif // UBLUEPY_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_characteristic.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_characteristic.c new file mode 100755 index 0000000..e271132 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_characteristic.c @@ -0,0 +1,221 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" + +#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL + +#include "modubluepy.h" +#include "ble_drv.h" + +STATIC void ubluepy_characteristic_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_characteristic_obj_t * self = (ubluepy_characteristic_obj_t *)o; + + mp_printf(print, "Characteristic(handle: 0x" HEX2_FMT ", conn_handle: " HEX2_FMT ")", + self->handle, self->p_service->p_periph->conn_handle); +} + +STATIC mp_obj_t ubluepy_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_REQUIRED| MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_props, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UBLUEPY_PROP_READ | UBLUEPY_PROP_WRITE} }, + { MP_QSTR_attrs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_characteristic_obj_t *s = m_new_obj(ubluepy_characteristic_obj_t); + s->base.type = type; + + mp_obj_t uuid_obj = args[0].u_obj; + + if (uuid_obj == mp_const_none) { + return MP_OBJ_FROM_PTR(s); + } + + if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); + // (void)sd_characterstic_add(s); + } else { + mp_raise_ValueError("Invalid UUID parameter"); + } + + if (args[1].u_int > 0) { + s->props = (uint8_t)args[1].u_int; + } + + if (args[2].u_int > 0) { + s->attrs = (uint8_t)args[2].u_int; + } + + // clear pointer to service + s->p_service = NULL; + + // clear pointer to char value data + s->value_data = NULL; + + return MP_OBJ_FROM_PTR(s); +} + +void char_data_callback(mp_obj_t self_in, uint16_t length, uint8_t * p_data) { + ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); + self->value_data = mp_obj_new_bytearray(length, p_data); +} + +/// \method read() +/// Read Characteristic value. +/// +STATIC mp_obj_t char_read(mp_obj_t self_in) { + ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); + +#if MICROPY_PY_UBLUEPY_CENTRAL + // TODO: free any previous allocation of value_data + + ble_drv_attr_c_read(self->p_service->p_periph->conn_handle, + self->handle, + self_in, + char_data_callback); + + return self->value_data; +#else + (void)self; + return mp_const_none; +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_read_obj, char_read); + +/// \method write(data, [with_response=False]) +/// Write Characteristic value. +/// +STATIC mp_obj_t char_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + ubluepy_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_obj_t data = pos_args[1]; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_with_response, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false } }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + // figure out mode of the Peripheral + ubluepy_role_type_t role = self->p_service->p_periph->role; + + if (role == UBLUEPY_ROLE_PERIPHERAL) { + if (self->props & UBLUEPY_PROP_NOTIFY) { + ble_drv_attr_s_notify(self->p_service->p_periph->conn_handle, + self->handle, + bufinfo.len, + bufinfo.buf); + } else { + ble_drv_attr_s_write(self->p_service->p_periph->conn_handle, + self->handle, + bufinfo.len, + bufinfo.buf); + } + } else { +#if MICROPY_PY_UBLUEPY_CENTRAL + bool with_response = args[0].u_bool; + + ble_drv_attr_c_write(self->p_service->p_periph->conn_handle, + self->handle, + bufinfo.len, + bufinfo.buf, + with_response); +#endif + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_characteristic_write_obj, 2, char_write); + +/// \method properties() +/// Read Characteristic value properties. +/// +STATIC mp_obj_t char_properties(mp_obj_t self_in) { + ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->props); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_get_properties_obj, char_properties); + +/// \method uuid() +/// Get UUID instance of the characteristic. +/// +STATIC mp_obj_t char_uuid(mp_obj_t self_in) { + ubluepy_characteristic_obj_t * self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(self->p_uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_characteristic_get_uuid_obj, char_uuid); + + +STATIC const mp_rom_map_elem_t ubluepy_characteristic_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&ubluepy_characteristic_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&ubluepy_characteristic_write_obj) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_supportsRead), MP_ROM_PTR(&ubluepy_characteristic_supports_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_propertiesToString), MP_ROM_PTR(&ubluepy_characteristic_properties_to_str_obj) }, + { MP_ROM_QSTR(MP_QSTR_getHandle), MP_ROM_PTR(&ubluepy_characteristic_get_handle_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_characteristic_get_peripheral_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_characteristic_get_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&ubluepy_characteristic_get_properties_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PROP_BROADCAST), MP_ROM_INT(UBLUEPY_PROP_BROADCAST) }, + { MP_ROM_QSTR(MP_QSTR_PROP_READ), MP_ROM_INT(UBLUEPY_PROP_READ) }, + { MP_ROM_QSTR(MP_QSTR_PROP_WRITE_WO_RESP), MP_ROM_INT(UBLUEPY_PROP_WRITE_WO_RESP) }, + { MP_ROM_QSTR(MP_QSTR_PROP_WRITE), MP_ROM_INT(UBLUEPY_PROP_WRITE) }, + { MP_ROM_QSTR(MP_QSTR_PROP_NOTIFY), MP_ROM_INT(UBLUEPY_PROP_NOTIFY) }, + { MP_ROM_QSTR(MP_QSTR_PROP_INDICATE), MP_ROM_INT(UBLUEPY_PROP_INDICATE) }, + { MP_ROM_QSTR(MP_QSTR_PROP_AUTH_SIGNED_WR), MP_ROM_INT(UBLUEPY_PROP_AUTH_SIGNED_WR) }, + +#if MICROPY_PY_UBLUEPY_PERIPHERAL + { MP_ROM_QSTR(MP_QSTR_ATTR_CCCD), MP_ROM_INT(UBLUEPY_ATTR_CCCD) }, +#endif + +#if MICROPY_PY_UBLUEPY_CENTRAL + { MP_ROM_QSTR(MP_QSTR_PROP_AUTH_SIGNED_WR), MP_ROM_INT(UBLUEPY_ATTR_SCCD) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_characteristic_locals_dict, ubluepy_characteristic_locals_dict_table); + +const mp_obj_type_t ubluepy_characteristic_type = { + { &mp_type_type }, + .name = MP_QSTR_Characteristic, + .print = ubluepy_characteristic_print, + .make_new = ubluepy_characteristic_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_characteristic_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_constants.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_constants.c new file mode 100755 index 0000000..14e433e --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_constants.c @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" + +#if MICROPY_PY_UBLUEPY + +#include "modubluepy.h" + +STATIC const mp_rom_map_elem_t ubluepy_constants_ad_types_locals_dict_table[] = { + // GAP AD Types + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_FLAGS), MP_ROM_INT(0x01) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x02) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x03) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x04) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x05) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE), MP_ROM_INT(0x06) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE), MP_ROM_INT(0x07) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SHORT_LOCAL_NAME), MP_ROM_INT(0x08) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_COMPLETE_LOCAL_NAME), MP_ROM_INT(0x09) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_TX_POWER_LEVEL), MP_ROM_INT(0x0A) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_CLASS_OF_DEVICE), MP_ROM_INT(0x0D) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_HASH_C), MP_ROM_INT(0x0E) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R), MP_ROM_INT(0x0F) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SECURITY_MANAGER_TK_VALUE), MP_ROM_INT(0x10) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS), MP_ROM_INT(0x11) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE), MP_ROM_INT(0x12) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT), MP_ROM_INT(0x14) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT), MP_ROM_INT(0x15) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA), MP_ROM_INT(0x16) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_PUBLIC_TARGET_ADDRESS), MP_ROM_INT(0x17) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_RANDOM_TARGET_ADDRESS), MP_ROM_INT(0x18) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_APPEARANCE), MP_ROM_INT(0x19) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_ADVERTISING_INTERVAL), MP_ROM_INT(0x1A) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS), MP_ROM_INT(0x1B) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_LE_ROLE), MP_ROM_INT(0x1C) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_HASH_C256), MP_ROM_INT(0x1D) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256), MP_ROM_INT(0x1E) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA_32BIT_UUID), MP_ROM_INT(0x20) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_SERVICE_DATA_128BIT_UUID), MP_ROM_INT(0x21) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_URI), MP_ROM_INT(0x24) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_3D_INFORMATION_DATA), MP_ROM_INT(0x3D) }, + { MP_ROM_QSTR(MP_QSTR_AD_TYPE_MANUFACTURER_SPECIFIC_DATA), MP_ROM_INT(0xFF) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_constants_ad_types_locals_dict, ubluepy_constants_ad_types_locals_dict_table); + +const mp_obj_type_t ubluepy_constants_ad_types_type = { + { &mp_type_type }, + .name = MP_QSTR_ad_types, + .locals_dict = (mp_obj_dict_t*)&ubluepy_constants_ad_types_locals_dict +}; + +STATIC const mp_rom_map_elem_t ubluepy_constants_locals_dict_table[] = { + // GAP events + { MP_ROM_QSTR(MP_QSTR_EVT_GAP_CONNECTED), MP_ROM_INT(16) }, + { MP_ROM_QSTR(MP_QSTR_EVT_GAP_DISCONNECTED), MP_ROM_INT(17) }, + { MP_ROM_QSTR(MP_QSTR_EVT_GATTS_WRITE), MP_ROM_INT(80) }, + { MP_ROM_QSTR(MP_QSTR_UUID_CCCD), MP_ROM_INT(0x2902) }, + + { MP_ROM_QSTR(MP_QSTR_ADDR_TYPE_PUBLIC), MP_ROM_INT(UBLUEPY_ADDR_TYPE_PUBLIC) }, + { MP_ROM_QSTR(MP_QSTR_ADDR_TYPE_RANDOM_STATIC), MP_ROM_INT(UBLUEPY_ADDR_TYPE_RANDOM_STATIC) }, + + { MP_ROM_QSTR(MP_QSTR_ad_types), MP_ROM_PTR(&ubluepy_constants_ad_types_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_constants_locals_dict, ubluepy_constants_locals_dict_table); + +const mp_obj_type_t ubluepy_constants_type = { + { &mp_type_type }, + .name = MP_QSTR_constants, + .locals_dict = (mp_obj_dict_t*)&ubluepy_constants_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_delegate.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_delegate.c new file mode 100755 index 0000000..07bb7f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_delegate.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" + +#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL + +#include "modubluepy.h" + +STATIC void ubluepy_delegate_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_delegate_obj_t * self = (ubluepy_delegate_obj_t *)o; + (void)self; + mp_printf(print, "DefaultDelegate()"); +} + +STATIC mp_obj_t ubluepy_delegate_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + ubluepy_delegate_obj_t *s = m_new_obj(ubluepy_delegate_obj_t); + s->base.type = type; + + return MP_OBJ_FROM_PTR(s); +} + +/// \method handleConnection() +/// Handle connection events. +/// +STATIC mp_obj_t delegate_handle_conn(mp_obj_t self_in) { + ubluepy_delegate_obj_t *self = MP_OBJ_TO_PTR(self_in); + + (void)self; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_delegate_handle_conn_obj, delegate_handle_conn); + +/// \method handleNotification() +/// Handle notification events. +/// +STATIC mp_obj_t delegate_handle_notif(mp_obj_t self_in) { + ubluepy_delegate_obj_t *self = MP_OBJ_TO_PTR(self_in); + + (void)self; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_delegate_handle_notif_obj, delegate_handle_notif); + +STATIC const mp_rom_map_elem_t ubluepy_delegate_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_handleConnection), MP_ROM_PTR(&ubluepy_delegate_handle_conn_obj) }, + { MP_ROM_QSTR(MP_QSTR_handleNotification), MP_ROM_PTR(&ubluepy_delegate_handle_notif_obj) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_delegate_locals_dict, ubluepy_delegate_locals_dict_table); + +const mp_obj_type_t ubluepy_delegate_type = { + { &mp_type_type }, + .name = MP_QSTR_DefaultDelegate, + .print = ubluepy_delegate_print, + .make_new = ubluepy_delegate_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_delegate_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_descriptor.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_descriptor.c new file mode 100755 index 0000000..b153019 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_descriptor.c @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/misc.h" + +#if MICROPY_PY_UBLUEPY + +#include "modubluepy.h" +#include "ble_drv.h" + +STATIC void ubluepy_descriptor_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_descriptor_obj_t * self = (ubluepy_descriptor_obj_t *)o; + + mp_printf(print, "Descriptor(uuid: 0x" HEX2_FMT HEX2_FMT ")", + self->p_uuid->value[1], self->p_uuid->value[0]); +} + +STATIC mp_obj_t ubluepy_descriptor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + + enum { ARG_NEW_UUID }; + + static const mp_arg_t allowed_args[] = { + { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_descriptor_obj_t * s = m_new_obj(ubluepy_descriptor_obj_t); + s->base.type = type; + + mp_obj_t uuid_obj = args[ARG_NEW_UUID].u_obj; + + (void)uuid_obj; + + return MP_OBJ_FROM_PTR(s); +} + +STATIC const mp_rom_map_elem_t ubluepy_descriptor_locals_dict_table[] = { +#if 0 + { MP_ROM_QSTR(MP_QSTR_binVal), MP_ROM_PTR(&ubluepy_descriptor_bin_val_obj) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_descriptor_locals_dict, ubluepy_descriptor_locals_dict_table); + +const mp_obj_type_t ubluepy_descriptor_type = { + { &mp_type_type }, + .name = MP_QSTR_Descriptor, + .print = ubluepy_descriptor_print, + .make_new = ubluepy_descriptor_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_descriptor_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_peripheral.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_peripheral.c new file mode 100755 index 0000000..48e4673 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_peripheral.c @@ -0,0 +1,498 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/objlist.h" + +#if MICROPY_PY_UBLUEPY + +#include "ble_drv.h" + +STATIC void ubluepy_peripheral_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_peripheral_obj_t * self = (ubluepy_peripheral_obj_t *)o; + (void)self; + mp_printf(print, "Peripheral(conn_handle: " HEX2_FMT ")", + self->conn_handle); +} + +STATIC void gap_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (event_id == 16) { // connect event + self->conn_handle = conn_handle; + } else if (event_id == 17) { // disconnect event + self->conn_handle = 0xFFFF; // invalid connection handle + } + + if (self->conn_handler != mp_const_none) { + mp_obj_t args[3]; + mp_uint_t num_of_args = 3; + args[0] = MP_OBJ_NEW_SMALL_INT(event_id); + args[1] = MP_OBJ_NEW_SMALL_INT(conn_handle); + if (data != NULL) { + args[2] = mp_obj_new_bytearray_by_ref(length, data); + } else { + args[2] = mp_const_none; + } + + // for now hard-code all events to conn_handler + mp_call_function_n_kw(self->conn_handler, num_of_args, 0, args); + } + + (void)self; +} + +STATIC void gatts_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->conn_handler != mp_const_none) { + mp_obj_t args[3]; + mp_uint_t num_of_args = 3; + args[0] = MP_OBJ_NEW_SMALL_INT(event_id); + args[1] = MP_OBJ_NEW_SMALL_INT(attr_handle); + if (data != NULL) { + args[2] = mp_obj_new_bytearray_by_ref(length, data); + } else { + args[2] = mp_const_none; + } + + // for now hard-code all events to conn_handler + mp_call_function_n_kw(self->conn_handler, num_of_args, 0, args); + } + +} + +#if MICROPY_PY_UBLUEPY_CENTRAL + +static volatile bool m_disc_evt_received; + +STATIC void gattc_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + (void)self; + m_disc_evt_received = true; +} +#endif + +STATIC mp_obj_t ubluepy_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { + ARG_NEW_DEVICE_ADDR, + ARG_NEW_ADDR_TYPE + }; + + static const mp_arg_t allowed_args[] = { + { ARG_NEW_DEVICE_ADDR, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { ARG_NEW_ADDR_TYPE, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_peripheral_obj_t *s = m_new_obj(ubluepy_peripheral_obj_t); + s->base.type = type; + + s->delegate = mp_const_none; + s->conn_handler = mp_const_none; + s->notif_handler = mp_const_none; + s->conn_handle = 0xFFFF; + + s->service_list = mp_obj_new_list(0, NULL); + + return MP_OBJ_FROM_PTR(s); +} + +/// \method withDelegate(DefaultDelegate) +/// Set delegate instance for handling Bluetooth LE events. +/// +STATIC mp_obj_t peripheral_with_delegate(mp_obj_t self_in, mp_obj_t delegate) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->delegate = delegate; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_with_delegate_obj, peripheral_with_delegate); + +/// \method setNotificationHandler(func) +/// Set handler for Bluetooth LE notification events. +/// +STATIC mp_obj_t peripheral_set_notif_handler(mp_obj_t self_in, mp_obj_t func) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->notif_handler = func; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_set_notif_handler_obj, peripheral_set_notif_handler); + +/// \method setConnectionHandler(func) +/// Set handler for Bluetooth LE connection events. +/// +STATIC mp_obj_t peripheral_set_conn_handler(mp_obj_t self_in, mp_obj_t func) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->conn_handler = func; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_set_conn_handler_obj, peripheral_set_conn_handler); + +#if MICROPY_PY_UBLUEPY_PERIPHERAL + +/// \method advertise(device_name, [service=[service1, service2, ...]], [data=bytearray], [connectable=True]) +/// Start advertising. Connectable advertisment type by default. +/// +STATIC mp_obj_t peripheral_advertise(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_device_name, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_services, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + self->role = UBLUEPY_ROLE_PERIPHERAL; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_obj_t device_name_obj = args[0].u_obj; + mp_obj_t service_obj = args[1].u_obj; + mp_obj_t data_obj = args[2].u_obj; + mp_obj_t connectable_obj = args[3].u_obj; + + ubluepy_advertise_data_t adv_data; + memset(&adv_data, 0, sizeof(ubluepy_advertise_data_t)); + + if (device_name_obj != mp_const_none && MP_OBJ_IS_STR(device_name_obj)) { + GET_STR_DATA_LEN(device_name_obj, str_data, str_len); + + adv_data.p_device_name = (uint8_t *)str_data; + adv_data.device_name_len = str_len; + } + + if (service_obj != mp_const_none) { + mp_obj_t * services = NULL; + mp_uint_t num_services; + mp_obj_get_array(service_obj, &num_services, &services); + + if (num_services > 0) { + adv_data.p_services = services; + adv_data.num_of_services = num_services; + } + } + + if (data_obj != mp_const_none) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > 0) { + adv_data.p_data = bufinfo.buf; + adv_data.data_len = bufinfo.len; + } + } + + adv_data.connectable = true; + if (connectable_obj != mp_const_none && !(mp_obj_is_true(connectable_obj))) { + adv_data.connectable = false; + } else { + ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(self), gap_event_handler); + ble_drv_gatts_event_handler_set(MP_OBJ_FROM_PTR(self), gatts_event_handler); + } + + (void)ble_drv_advertise_data(&adv_data); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_peripheral_advertise_obj, 0, peripheral_advertise); + +/// \method advertise_stop() +/// Stop advertisment if any onging advertisment. +/// +STATIC mp_obj_t peripheral_advertise_stop(mp_obj_t self_in) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + (void)self; + + ble_drv_advertise_stop(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_advertise_stop_obj, peripheral_advertise_stop); + +#endif // MICROPY_PY_UBLUEPY_PERIPHERAL + +/// \method disconnect() +/// disconnect connection. +/// +STATIC mp_obj_t peripheral_disconnect(mp_obj_t self_in) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + (void)self; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_disconnect_obj, peripheral_disconnect); + +/// \method addService(Service) +/// Add service to the Peripheral. +/// +STATIC mp_obj_t peripheral_add_service(mp_obj_t self_in, mp_obj_t service) { + ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); + ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service); + + p_service->p_periph = self; + + mp_obj_list_append(self->service_list, service); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_peripheral_add_service_obj, peripheral_add_service); + +/// \method getServices() +/// Return list with all service registered in the Peripheral. +/// +STATIC mp_obj_t peripheral_get_services(mp_obj_t self_in) { + ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in); + + return self->service_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_peripheral_get_services_obj, peripheral_get_services); + +#if MICROPY_PY_UBLUEPY_CENTRAL + +void static disc_add_service(mp_obj_t self, ble_drv_service_data_t * p_service_data) { + ubluepy_service_obj_t * p_service = m_new_obj(ubluepy_service_obj_t); + p_service->base.type = &ubluepy_service_type; + + ubluepy_uuid_obj_t * p_uuid = m_new_obj(ubluepy_uuid_obj_t); + p_uuid->base.type = &ubluepy_uuid_type; + + p_service->p_uuid = p_uuid; + + p_uuid->type = p_service_data->uuid_type; + p_uuid->value[0] = p_service_data->uuid & 0xFF; + p_uuid->value[1] = p_service_data->uuid >> 8; + + p_service->handle = p_service_data->start_handle; + p_service->start_handle = p_service_data->start_handle; + p_service->end_handle = p_service_data->end_handle; + + p_service->char_list = mp_obj_new_list(0, NULL); + + peripheral_add_service(self, MP_OBJ_FROM_PTR(p_service)); +} + +void static disc_add_char(mp_obj_t service_in, ble_drv_char_data_t * p_desc_data) { + ubluepy_service_obj_t * p_service = MP_OBJ_TO_PTR(service_in); + ubluepy_characteristic_obj_t * p_char = m_new_obj(ubluepy_characteristic_obj_t); + p_char->base.type = &ubluepy_characteristic_type; + + ubluepy_uuid_obj_t * p_uuid = m_new_obj(ubluepy_uuid_obj_t); + p_uuid->base.type = &ubluepy_uuid_type; + + p_char->p_uuid = p_uuid; + + p_uuid->type = p_desc_data->uuid_type; + p_uuid->value[0] = p_desc_data->uuid & 0xFF; + p_uuid->value[1] = p_desc_data->uuid >> 8; + + // add characteristic specific data from discovery + p_char->props = p_desc_data->props; + p_char->handle = p_desc_data->value_handle; + + // equivalent to ubluepy_service.c - service_add_characteristic() + // except the registration of the characteristic towards the bluetooth stack + p_char->service_handle = p_service->handle; + p_char->p_service = p_service; + + mp_obj_list_append(p_service->char_list, MP_OBJ_FROM_PTR(p_char)); +} + +/// \method connect(device_address [, addr_type=ADDR_TYPE_PUBLIC]) +/// Connect to device peripheral with the given device address. +/// addr_type can be either ADDR_TYPE_PUBLIC (default) or +/// ADDR_TYPE_RANDOM_STATIC. +/// +STATIC mp_obj_t peripheral_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + ubluepy_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_obj_t dev_addr = pos_args[1]; + + self->role = UBLUEPY_ROLE_CENTRAL; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_addr_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UBLUEPY_ADDR_TYPE_PUBLIC } }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t addr_type = args[0].u_int; + + ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(self), gap_event_handler); + + if (MP_OBJ_IS_STR(dev_addr)) { + GET_STR_DATA_LEN(dev_addr, str_data, str_len); + if (str_len == 17) { // Example "11:22:33:aa:bb:cc" + + uint8_t * p_addr = m_new(uint8_t, 6); + + p_addr[0] = unichar_xdigit_value(str_data[16]); + p_addr[0] += unichar_xdigit_value(str_data[15]) << 4; + p_addr[1] = unichar_xdigit_value(str_data[13]); + p_addr[1] += unichar_xdigit_value(str_data[12]) << 4; + p_addr[2] = unichar_xdigit_value(str_data[10]); + p_addr[2] += unichar_xdigit_value(str_data[9]) << 4; + p_addr[3] = unichar_xdigit_value(str_data[7]); + p_addr[3] += unichar_xdigit_value(str_data[6]) << 4; + p_addr[4] = unichar_xdigit_value(str_data[4]); + p_addr[4] += unichar_xdigit_value(str_data[3]) << 4; + p_addr[5] = unichar_xdigit_value(str_data[1]); + p_addr[5] += unichar_xdigit_value(str_data[0]) << 4; + + ble_drv_connect(p_addr, addr_type); + + m_del(uint8_t, p_addr, 6); + } + } + + // block until connected + while (self->conn_handle == 0xFFFF) { + ; + } + + ble_drv_gattc_event_handler_set(MP_OBJ_FROM_PTR(self), gattc_event_handler); + + bool service_disc_retval = ble_drv_discover_services(self, self->conn_handle, 0x0001, disc_add_service); + + // continue discovery of primary services ... + while (service_disc_retval) { + // locate the last added service + mp_obj_t * services = NULL; + mp_uint_t num_services; + mp_obj_get_array(self->service_list, &num_services, &services); + + ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)services[num_services - 1]; + + service_disc_retval = ble_drv_discover_services(self, + self->conn_handle, + p_service->end_handle + 1, + disc_add_service); + } + + // For each service perform a characteristic discovery + mp_obj_t * services = NULL; + mp_uint_t num_services; + mp_obj_get_array(self->service_list, &num_services, &services); + + for (uint16_t s = 0; s < num_services; s++) { + ubluepy_service_obj_t * p_service = (ubluepy_service_obj_t *)services[s]; + bool char_disc_retval = ble_drv_discover_characteristic(p_service, + self->conn_handle, + p_service->start_handle, + p_service->end_handle, + disc_add_char); + // continue discovery of characteristics ... + while (char_disc_retval) { + mp_obj_t * characteristics = NULL; + mp_uint_t num_chars; + mp_obj_get_array(p_service->char_list, &num_chars, &characteristics); + + ubluepy_characteristic_obj_t * p_char = (ubluepy_characteristic_obj_t *)characteristics[num_chars - 1]; + uint16_t next_handle = p_char->handle + 1; + if ((next_handle) < p_service->end_handle) { + char_disc_retval = ble_drv_discover_characteristic(p_service, + self->conn_handle, + next_handle, + p_service->end_handle, + disc_add_char); + } else { + break; + } + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ubluepy_peripheral_connect_obj, 2, peripheral_connect); + +#endif + +STATIC const mp_rom_map_elem_t ubluepy_peripheral_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_withDelegate), MP_ROM_PTR(&ubluepy_peripheral_with_delegate_obj) }, + { MP_ROM_QSTR(MP_QSTR_setNotificationHandler), MP_ROM_PTR(&ubluepy_peripheral_set_notif_handler_obj) }, + { MP_ROM_QSTR(MP_QSTR_setConnectionHandler), MP_ROM_PTR(&ubluepy_peripheral_set_conn_handler_obj) }, + { MP_ROM_QSTR(MP_QSTR_getServices), MP_ROM_PTR(&ubluepy_peripheral_get_services_obj) }, +#if MICROPY_PY_UBLUEPY_CENTRAL + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ubluepy_peripheral_connect_obj) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&ubluepy_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_getServiceByUUID), MP_ROM_PTR(&ubluepy_peripheral_get_service_by_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_peripheral_get_chars_obj) }, + { MP_ROM_QSTR(MP_QSTR_getDescriptors), MP_ROM_PTR(&ubluepy_peripheral_get_descs_obj) }, + { MP_ROM_QSTR(MP_QSTR_waitForNotifications), MP_ROM_PTR(&ubluepy_peripheral_wait_for_notif_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_write_char_obj) }, + { MP_ROM_QSTR(MP_QSTR_readCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_read_char_obj) }, +#endif // 0 +#endif // MICROPY_PY_UBLUEPY_CENTRAL +#if MICROPY_PY_UBLUEPY_PERIPHERAL + { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) }, + { MP_ROM_QSTR(MP_QSTR_advertise_stop), MP_ROM_PTR(&ubluepy_peripheral_advertise_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&ubluepy_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_addService), MP_ROM_PTR(&ubluepy_peripheral_add_service_obj) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_add_char_obj) }, + { MP_ROM_QSTR(MP_QSTR_addDescriptor), MP_ROM_PTR(&ubluepy_peripheral_add_desc_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_write_char_obj) }, + { MP_ROM_QSTR(MP_QSTR_readCharacteristic), MP_ROM_PTR(&ubluepy_peripheral_read_char_obj) }, +#endif +#endif +#if MICROPY_PY_UBLUEPY_BROADCASTER + { MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) }, +#endif +#if MICROPY_PY_UBLUEPY_OBSERVER + // Nothing yet. +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_peripheral_locals_dict, ubluepy_peripheral_locals_dict_table); + +const mp_obj_type_t ubluepy_peripheral_type = { + { &mp_type_type }, + .name = MP_QSTR_Peripheral, + .print = ubluepy_peripheral_print, + .make_new = ubluepy_peripheral_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_peripheral_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c new file mode 100755 index 0000000..773070b --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/objlist.h" +#include "py/objarray.h" +#include "py/objtuple.h" +#include "py/qstr.h" + +#if MICROPY_PY_UBLUEPY_CENTRAL + +#include "ble_drv.h" + +STATIC void ubluepy_scan_entry_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_scan_entry_obj_t * self = (ubluepy_scan_entry_obj_t *)o; + (void)self; + mp_printf(print, "ScanEntry"); +} + +/// \method addr() +/// Return address as text string. +/// +STATIC mp_obj_t scan_entry_get_addr(mp_obj_t self_in) { + ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->addr; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_addr_obj, scan_entry_get_addr); + +/// \method addr_type() +/// Return address type value. +/// +STATIC mp_obj_t scan_entry_get_addr_type(mp_obj_t self_in) { + ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->addr_type); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_addr_type_obj, scan_entry_get_addr_type); + +/// \method rssi() +/// Return RSSI value. +/// +STATIC mp_obj_t scan_entry_get_rssi(mp_obj_t self_in) { + ubluepy_scan_entry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->rssi); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scan_entry_get_rssi_obj, scan_entry_get_rssi); + +/// \method getScanData() +/// Return list of the scan data tupples (ad_type, description, value) +/// +STATIC mp_obj_t scan_entry_get_scan_data(mp_obj_t self_in) { + ubluepy_scan_entry_obj_t * self = MP_OBJ_TO_PTR(self_in); + + mp_obj_t retval_list = mp_obj_new_list(0, NULL); + + // TODO: check if self->data is set + mp_obj_array_t * data = MP_OBJ_TO_PTR(self->data); + + uint16_t byte_index = 0; + + while (byte_index < data->len) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + + uint8_t adv_item_len = ((uint8_t * )data->items)[byte_index]; + uint8_t adv_item_type = ((uint8_t * )data->items)[byte_index + 1]; + + mp_obj_t description = mp_const_none; + + mp_map_t *constant_map = mp_obj_dict_get_map(ubluepy_constants_ad_types_type.locals_dict); + mp_map_elem_t *ad_types_table = MP_OBJ_TO_PTR(constant_map->table); + + uint16_t num_of_elements = constant_map->used; + + for (uint16_t i = 0; i < num_of_elements; i++) { + mp_map_elem_t element = (mp_map_elem_t)*ad_types_table; + ad_types_table++; + uint16_t element_value = mp_obj_get_int(element.value); + + if (adv_item_type == element_value) { + qstr key_qstr = MP_OBJ_QSTR_VALUE(element.key); + const char * text = qstr_str(key_qstr); + size_t len = qstr_len(key_qstr); + + vstr_t vstr; + vstr_init(&vstr, len); + vstr_printf(&vstr, "%s", text); + description = mp_obj_new_str(vstr.buf, vstr.len); + vstr_clear(&vstr); + } + } + + t->items[0] = MP_OBJ_NEW_SMALL_INT(adv_item_type); + t->items[1] = description; + t->items[2] = mp_obj_new_bytearray(adv_item_len - 1, + &((uint8_t * )data->items)[byte_index + 2]); + mp_obj_list_append(retval_list, MP_OBJ_FROM_PTR(t)); + + byte_index += adv_item_len + 1; + } + + return retval_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_scan_entry_get_scan_data_obj, scan_entry_get_scan_data); + +STATIC const mp_rom_map_elem_t ubluepy_scan_entry_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&bluepy_scan_entry_get_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_addr_type), MP_ROM_PTR(&bluepy_scan_entry_get_addr_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bluepy_scan_entry_get_rssi_obj) }, + { MP_ROM_QSTR(MP_QSTR_getScanData), MP_ROM_PTR(&ubluepy_scan_entry_get_scan_data_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_scan_entry_locals_dict, ubluepy_scan_entry_locals_dict_table); + +const mp_obj_type_t ubluepy_scan_entry_type = { + { &mp_type_type }, + .name = MP_QSTR_ScanEntry, + .print = ubluepy_scan_entry_print, + .locals_dict = (mp_obj_dict_t*)&ubluepy_scan_entry_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY_CENTRAL diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scanner.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scanner.c new file mode 100755 index 0000000..f5c9a6d --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_scanner.c @@ -0,0 +1,127 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/objlist.h" + +#if MICROPY_PY_UBLUEPY_CENTRAL + +#include "ble_drv.h" +#include "mphalport.h" + +STATIC void adv_event_handler(mp_obj_t self_in, uint16_t event_id, ble_drv_adv_data_t * data) { + ubluepy_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); + + ubluepy_scan_entry_obj_t * item = m_new_obj(ubluepy_scan_entry_obj_t); + item->base.type = &ubluepy_scan_entry_type; + + vstr_t vstr; + vstr_init(&vstr, 17); + + vstr_printf(&vstr, ""HEX2_FMT":"HEX2_FMT":"HEX2_FMT":" \ + HEX2_FMT":"HEX2_FMT":"HEX2_FMT"", + data->p_peer_addr[5], data->p_peer_addr[4], data->p_peer_addr[3], + data->p_peer_addr[2], data->p_peer_addr[1], data->p_peer_addr[0]); + + item->addr = mp_obj_new_str(vstr.buf, vstr.len); + + vstr_clear(&vstr); + + item->addr_type = data->addr_type; + item->rssi = data->rssi; + item->data = mp_obj_new_bytearray(data->data_len, data->p_data); + + mp_obj_list_append(self->adv_reports, item); + + // Continue scanning + ble_drv_scan_start(true); +} + +STATIC void ubluepy_scanner_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_scanner_obj_t * self = (ubluepy_scanner_obj_t *)o; + (void)self; + mp_printf(print, "Scanner"); +} + +STATIC mp_obj_t ubluepy_scanner_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_scanner_obj_t * s = m_new_obj(ubluepy_scanner_obj_t); + s->base.type = type; + + return MP_OBJ_FROM_PTR(s); +} + +/// \method scan(timeout) +/// Scan for devices. Timeout is in milliseconds and will set the duration +/// of the scanning. +/// +STATIC mp_obj_t scanner_scan(mp_obj_t self_in, mp_obj_t timeout_in) { + ubluepy_scanner_obj_t * self = MP_OBJ_TO_PTR(self_in); + mp_int_t timeout = mp_obj_get_int(timeout_in); + + self->adv_reports = mp_obj_new_list(0, NULL); + + ble_drv_adv_report_handler_set(MP_OBJ_FROM_PTR(self), adv_event_handler); + + // start + ble_drv_scan_start(false); + + // sleep + mp_hal_delay_ms(timeout); + + // stop + ble_drv_scan_stop(); + + return self->adv_reports; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_scanner_scan_obj, scanner_scan); + +STATIC const mp_rom_map_elem_t ubluepy_scanner_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&ubluepy_scanner_scan_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_scanner_locals_dict, ubluepy_scanner_locals_dict_table); + + +const mp_obj_type_t ubluepy_scanner_type = { + { &mp_type_type }, + .name = MP_QSTR_Scanner, + .print = ubluepy_scanner_print, + .make_new = ubluepy_scanner_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_scanner_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY_CENTRAL diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_service.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_service.c new file mode 100755 index 0000000..e83ed1f --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_service.c @@ -0,0 +1,183 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objlist.h" + +#if MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL + +#include "modubluepy.h" +#include "ble_drv.h" + +STATIC void ubluepy_service_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_service_obj_t * self = (ubluepy_service_obj_t *)o; + + mp_printf(print, "Service(handle: 0x" HEX2_FMT ")", self->handle); +} + +STATIC mp_obj_t ubluepy_service_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + + enum { ARG_NEW_UUID, ARG_NEW_TYPE }; + + static const mp_arg_t allowed_args[] = { + { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { ARG_NEW_TYPE, MP_ARG_INT, {.u_int = UBLUEPY_SERVICE_PRIMARY} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_service_obj_t *s = m_new_obj(ubluepy_service_obj_t); + s->base.type = type; + + mp_obj_t uuid_obj = args[ARG_NEW_UUID].u_obj; + + if (uuid_obj == MP_OBJ_NULL) { + return MP_OBJ_FROM_PTR(s); + } + + if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + s->p_uuid = MP_OBJ_TO_PTR(uuid_obj); + + uint8_t type = args[ARG_NEW_TYPE].u_int; + if (type > 0 && type <= UBLUEPY_SERVICE_PRIMARY) { + s->type = type; + } else { + mp_raise_ValueError("Invalid Service type"); + } + + (void)ble_drv_service_add(s); + + } else { + mp_raise_ValueError("Invalid UUID parameter"); + } + + // clear reference to peripheral + s->p_periph = NULL; + s->char_list = mp_obj_new_list(0, NULL); + + return MP_OBJ_FROM_PTR(s); +} + +/// \method addCharacteristic(Characteristic) +/// Add Characteristic to the Service. +/// +STATIC mp_obj_t service_add_characteristic(mp_obj_t self_in, mp_obj_t characteristic) { + ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); + ubluepy_characteristic_obj_t * p_char = MP_OBJ_TO_PTR(characteristic); + + p_char->service_handle = self->handle; + + bool retval = ble_drv_characteristic_add(p_char); + + if (retval) { + p_char->p_service = self; + } + + mp_obj_list_append(self->char_list, characteristic); + + // return mp_obj_new_bool(retval); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_service_add_char_obj, service_add_characteristic); + +/// \method getCharacteristics() +/// Return list with all characteristics registered in the Service. +/// +STATIC mp_obj_t service_get_chars(mp_obj_t self_in) { + ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); + + return self->char_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_service_get_chars_obj, service_get_chars); + +/// \method getCharacteristic(UUID) +/// Return Characteristic with the given UUID. +/// +STATIC mp_obj_t service_get_characteristic(mp_obj_t self_in, mp_obj_t uuid) { + ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); + ubluepy_uuid_obj_t * p_uuid = MP_OBJ_TO_PTR(uuid); + + // validate that there is an UUID object passed in as parameter + if (!(MP_OBJ_IS_TYPE(uuid, &ubluepy_uuid_type))) { + mp_raise_ValueError("Invalid UUID parameter"); + } + + mp_obj_t * chars = NULL; + mp_uint_t num_chars = 0; + mp_obj_get_array(self->char_list, &num_chars, &chars); + + for (uint8_t i = 0; i < num_chars; i++) { + ubluepy_characteristic_obj_t * p_char = (ubluepy_characteristic_obj_t *)chars[i]; + + bool type_match = p_char->p_uuid->type == p_uuid->type; + bool uuid_match = ((uint16_t)(*(uint16_t *)&p_char->p_uuid->value[0]) == + (uint16_t)(*(uint16_t *)&p_uuid->value[0])); + + if (type_match && uuid_match) { + return MP_OBJ_FROM_PTR(p_char); + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ubluepy_service_get_char_obj, service_get_characteristic); + +/// \method uuid() +/// Get UUID instance of the Service. +/// +STATIC mp_obj_t service_uuid(mp_obj_t self_in) { + ubluepy_service_obj_t * self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(self->p_uuid); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_service_get_uuid_obj, service_uuid); + +STATIC const mp_rom_map_elem_t ubluepy_service_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_getCharacteristic), MP_ROM_PTR(&ubluepy_service_get_char_obj) }, + { MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_service_add_char_obj) }, + { MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_service_get_chars_obj) }, +#if 0 + // Properties + { MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_service_get_peripheral_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_service_get_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_PRIMARY), MP_ROM_INT(UBLUEPY_SERVICE_PRIMARY) }, + { MP_ROM_QSTR(MP_QSTR_SECONDARY), MP_ROM_INT(UBLUEPY_SERVICE_SECONDARY) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_service_locals_dict, ubluepy_service_locals_dict_table); + +const mp_obj_type_t ubluepy_service_type = { + { &mp_type_type }, + .name = MP_QSTR_Service, + .print = ubluepy_service_print, + .make_new = ubluepy_service_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_service_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY_PERIPHERAL || MICROPY_PY_UBLUEPY_CENTRAL diff --git a/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_uuid.c b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_uuid.c new file mode 100755 index 0000000..98dba91 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/ubluepy/ubluepy_uuid.c @@ -0,0 +1,171 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/misc.h" + +#if MICROPY_PY_UBLUEPY + +#include "modubluepy.h" +#include "ble_drv.h" + +STATIC void ubluepy_uuid_print(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind) { + ubluepy_uuid_obj_t * self = (ubluepy_uuid_obj_t *)o; + if (self->type == UBLUEPY_UUID_16_BIT) { + mp_printf(print, "UUID(uuid: 0x" HEX2_FMT HEX2_FMT ")", + self->value[1], self->value[0]); + } else { + mp_printf(print, "UUID(uuid: 0x" HEX2_FMT HEX2_FMT ", VS idx: " HEX2_FMT ")", + self->value[1], self->value[0], self->uuid_vs_idx); + } +} + +STATIC mp_obj_t ubluepy_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + + enum { ARG_NEW_UUID }; + + static const mp_arg_t allowed_args[] = { + { ARG_NEW_UUID, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ubluepy_uuid_obj_t *s = m_new_obj(ubluepy_uuid_obj_t); + s->base.type = type; + + mp_obj_t uuid_obj = args[ARG_NEW_UUID].u_obj; + + if (uuid_obj == MP_OBJ_NULL) { + return MP_OBJ_FROM_PTR(s); + } + + if (MP_OBJ_IS_INT(uuid_obj)) { + s->type = UBLUEPY_UUID_16_BIT; + s->value[1] = (((uint16_t)mp_obj_get_int(uuid_obj)) >> 8) & 0xFF; + s->value[0] = ((uint8_t)mp_obj_get_int(uuid_obj)) & 0xFF; + } else if (MP_OBJ_IS_STR(uuid_obj)) { + GET_STR_DATA_LEN(uuid_obj, str_data, str_len); + if (str_len == 6) { // Assume hex digit prefixed with 0x + s->type = UBLUEPY_UUID_16_BIT; + s->value[0] = unichar_xdigit_value(str_data[5]); + s->value[0] += unichar_xdigit_value(str_data[4]) << 4; + s->value[1] = unichar_xdigit_value(str_data[3]); + s->value[1] += unichar_xdigit_value(str_data[2]) << 4; + } else if (str_len == 36) { + s->type = UBLUEPY_UUID_128_BIT; + uint8_t buffer[16]; + buffer[0] = unichar_xdigit_value(str_data[35]); + buffer[0] += unichar_xdigit_value(str_data[34]) << 4; + buffer[1] = unichar_xdigit_value(str_data[33]); + buffer[1] += unichar_xdigit_value(str_data[32]) << 4; + buffer[2] = unichar_xdigit_value(str_data[31]); + buffer[2] += unichar_xdigit_value(str_data[30]) << 4; + buffer[3] = unichar_xdigit_value(str_data[29]); + buffer[3] += unichar_xdigit_value(str_data[28]) << 4; + buffer[4] = unichar_xdigit_value(str_data[27]); + buffer[4] += unichar_xdigit_value(str_data[26]) << 4; + buffer[5] = unichar_xdigit_value(str_data[25]); + buffer[5] += unichar_xdigit_value(str_data[24]) << 4; + // 23 '-' + buffer[6] = unichar_xdigit_value(str_data[22]); + buffer[6] += unichar_xdigit_value(str_data[21]) << 4; + buffer[7] = unichar_xdigit_value(str_data[20]); + buffer[7] += unichar_xdigit_value(str_data[19]) << 4; + // 18 '-' + buffer[8] = unichar_xdigit_value(str_data[17]); + buffer[8] += unichar_xdigit_value(str_data[16]) << 4; + buffer[9] = unichar_xdigit_value(str_data[15]); + buffer[9] += unichar_xdigit_value(str_data[14]) << 4; + // 13 '-' + buffer[10] = unichar_xdigit_value(str_data[12]); + buffer[10] += unichar_xdigit_value(str_data[11]) << 4; + buffer[11] = unichar_xdigit_value(str_data[10]); + buffer[11] += unichar_xdigit_value(str_data[9]) << 4; + // 8 '-' + // 16-bit field + s->value[0] = unichar_xdigit_value(str_data[7]); + s->value[0] += unichar_xdigit_value(str_data[6]) << 4; + s->value[1] = unichar_xdigit_value(str_data[5]); + s->value[1] += unichar_xdigit_value(str_data[4]) << 4; + + buffer[14] = unichar_xdigit_value(str_data[3]); + buffer[14] += unichar_xdigit_value(str_data[2]) << 4; + buffer[15] = unichar_xdigit_value(str_data[1]); + buffer[15] += unichar_xdigit_value(str_data[0]) << 4; + + ble_drv_uuid_add_vs(buffer, &s->uuid_vs_idx); + } else { + mp_raise_ValueError("Invalid UUID string length"); + } + } else if (MP_OBJ_IS_TYPE(uuid_obj, &ubluepy_uuid_type)) { + // deep copy instance + ubluepy_uuid_obj_t * p_old = MP_OBJ_TO_PTR(uuid_obj); + s->type = p_old->type; + s->value[0] = p_old->value[0]; + s->value[1] = p_old->value[1]; + } else { + mp_raise_ValueError("Invalid UUID parameter"); + } + + return MP_OBJ_FROM_PTR(s); +} + +/// \method binVal() +/// Get binary value of the 16 or 128 bit UUID. Returned as bytearray type. +/// +STATIC mp_obj_t uuid_bin_val(mp_obj_t self_in) { + ubluepy_uuid_obj_t * self = MP_OBJ_TO_PTR(self_in); + + // TODO: Extend the uint16 byte value to 16 byte if 128-bit, + // also encapsulate it in a bytearray. For now, return + // the uint16_t field of the UUID. + return MP_OBJ_NEW_SMALL_INT(self->value[0] | self->value[1] << 8); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ubluepy_uuid_bin_val_obj, uuid_bin_val); + +STATIC const mp_rom_map_elem_t ubluepy_uuid_locals_dict_table[] = { +#if 0 + { MP_ROM_QSTR(MP_QSTR_getCommonName), MP_ROM_PTR(&ubluepy_uuid_get_common_name_obj) }, +#endif + // Properties + { MP_ROM_QSTR(MP_QSTR_binVal), MP_ROM_PTR(&ubluepy_uuid_bin_val_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ubluepy_uuid_locals_dict, ubluepy_uuid_locals_dict_table); + +const mp_obj_type_t ubluepy_uuid_type = { + { &mp_type_type }, + .name = MP_QSTR_UUID, + .print = ubluepy_uuid_print, + .make_new = ubluepy_uuid_make_new, + .locals_dict = (mp_obj_dict_t*)&ubluepy_uuid_locals_dict +}; + +#endif // MICROPY_PY_UBLUEPY diff --git a/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.c b/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.c new file mode 100755 index 0000000..d4c5a11 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.c @@ -0,0 +1,709 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Mark Shannon + * Copyright (c) 2017 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "microbitfs.h" +#include "drivers/flash.h" +#include "modrandom.h" +#include "py/obj.h" +#include "py/stream.h" +#include "py/runtime.h" +#include "extmod/vfs.h" +#include "mpconfigport.h" + +#if MICROPY_MBFS + +#define DEBUG_FILE 0 +#if DEBUG_FILE +#define DEBUG(s) printf s +#else +#define DEBUG(s) (void)0 +#endif + +/** How it works: + * The File System consists of up to MAX_CHUNKS_IN_FILE_SYSTEM chunks of CHUNK_SIZE each, + * plus one spare page which holds persistent configuration data and is used. for bulk erasing. + * The spare page is either the first or the last page and will be switched by a bulk erase. + * The exact number of chunks will depend on the amount of flash available. + * + * Each chunk consists of a one byte marker and a one byte tail + * The marker shows whether this chunk is the start of a file, the midst of a file + * (in which case it refers to the previous chunk in the file) or whether it is UNUSED + * (and erased) or FREED (which means it is unused, but not erased). + * Chunks are selected in a randomised round-robin fashion to even out wear on the flash + * memory as much as possible. + * A file consists of a linked list of chunks. The first chunk in a file contains its name + * as well as the end chunk and offset. + * Files are found by linear search of the chunks, this means that no meta-data needs to be stored + * outside of the file, which prevents wear hot-spots. Since there are fewer than 250 chunks, + * the search is fast enough. + * + * Chunks are numbered from 1 as we need to reserve 0 as the FREED marker. + * + * Writing to files relies on the persistent API which is high-level wrapper on top of the Nordic SDK. + */ + +#define CHUNK_SIZE (1<>MBFS_LOG_CHUNK_SIZE; +} + +STATIC void randomise_start_index(void) { + start_index = machine_rng_generate_random_word() % chunks_in_file_system + 1; +} + +void microbit_filesystem_init(void) { + init_limits(); + randomise_start_index(); + file_chunk *base = first_page(); + if (base->marker == PERSISTENT_DATA_MARKER) { + file_system_chunks = &base[(FLASH_PAGESIZE>>MBFS_LOG_CHUNK_SIZE)-1]; + } else if (((file_chunk *)last_page())->marker == PERSISTENT_DATA_MARKER) { + file_system_chunks = &base[-1]; + } else { + flash_write_byte((uint32_t)&((file_chunk *)last_page())->marker, PERSISTENT_DATA_MARKER); + file_system_chunks = &base[-1]; + } +} + +STATIC void copy_page(void *dest, void *src) { + DEBUG(("FILE DEBUG: Copying page from %lx to %lx.\r\n", (uint32_t)src, (uint32_t)dest)); + flash_page_erase((uint32_t)dest); + file_chunk *src_chunk = src; + file_chunk *dest_chunk = dest; + uint32_t chunks = FLASH_PAGESIZE>>MBFS_LOG_CHUNK_SIZE; + for (uint32_t i = 0; i < chunks; i++) { + if (src_chunk[i].marker != FREED_CHUNK) { + flash_write_bytes((uint32_t)&dest_chunk[i], (uint8_t*)&src_chunk[i], CHUNK_SIZE); + } + } +} + +// Move entire file system up or down one page, copying all used chunks +// Freed chunks are not copied, so become erased. +// There should be no erased chunks before the sweep (or it would be unnecessary) +// but if there are this should work correctly. +// +// The direction of the sweep depends on whether the persistent data is in the first or last page +// The persistent data is copied to RAM, leaving its page unused. +// Then all the pages are copied, one by one, into the adjacent newly unused page. +// Finally, the persistent data is saved back to the opposite end of the filesystem from whence it came. +// +STATIC void filesystem_sweep(void) { + persistent_config_t config; + uint8_t *page; + uint8_t *end_page; + int step; + uint32_t page_size = FLASH_PAGESIZE; + DEBUG(("FILE DEBUG: Sweeping file system\r\n")); + if (((file_chunk *)first_page())->marker == PERSISTENT_DATA_MARKER) { + config = *(persistent_config_t *)first_page(); + page = first_page(); + end_page = last_page(); + step = page_size; + } else { + config = *(persistent_config_t *)last_page(); + page = last_page(); + end_page = first_page(); + step = -page_size; + } + while (page != end_page) { + uint8_t *next_page = page+step; + flash_page_erase((uint32_t)page); + copy_page(page, next_page); + page = next_page; + } + flash_page_erase((uint32_t)end_page); + flash_write_bytes((uint32_t)end_page, (uint8_t*)&config, sizeof(config)); + microbit_filesystem_init(); +} + + +STATIC inline byte *seek_address(file_descriptor_obj *self) { + return (byte*)&(file_system_chunks[self->seek_chunk].data[self->seek_offset]); +} + +STATIC uint8_t microbit_find_file(const char *name, int name_len) { + for (uint8_t index = 1; index <= chunks_in_file_system; index++) { + const file_chunk *p = &file_system_chunks[index]; + if (p->marker != FILE_START) + continue; + if (p->header.name_len != name_len) + continue; + if (memcmp(name, &p->header.filename[0], name_len) == 0) { + DEBUG(("FILE DEBUG: File found. index %d\r\n", index)); + return index; + } + } + DEBUG(("FILE DEBUG: File not found.\r\n")); + return FILE_NOT_FOUND; +} + +// Return a free, erased chunk. +// Search the chunks: +// 1 If an UNUSED chunk is found, then return that. +// 2. If an entire page of FREED chunks is found, then erase the page and return the first chunk +// 3. If the number of FREED chunks is >= MIN_CHUNKS_FOR_SWEEP, then +// 3a. Sweep the filesystem and restart. +// 3b. Fail and return FILE_NOT_FOUND +// +STATIC uint8_t find_chunk_and_erase(void) { + // Start search at a random chunk to spread the wear more evenly. + // Search for unused chunk + uint8_t index = start_index; + do { + const file_chunk *p = &file_system_chunks[index]; + if (p->marker == UNUSED_CHUNK) { + DEBUG(("FILE DEBUG: Unused chunk found: %d\r\n", index)); + return index; + } + index++; + if (index == chunks_in_file_system+1) index = 1; + } while (index != start_index); + + // Search for FREED page, and total up FREED chunks + uint32_t freed_chunks = 0; + index = start_index; + uint32_t chunks_per_page = FLASH_PAGESIZE>>MBFS_LOG_CHUNK_SIZE; + do { + const file_chunk *p = &file_system_chunks[index]; + if (p->marker == FREED_CHUNK) { + freed_chunks++; + } + if (FLASH_IS_PAGE_ALIGNED(p)) { + uint32_t i; + for (i = 0; i < chunks_per_page; i++) { + if (p[i].marker != FREED_CHUNK) + break; + } + if (i == chunks_per_page) { + DEBUG(("FILE DEBUG: Found freed page of chunks: %d\r\n", index)); + flash_page_erase((uint32_t)&file_system_chunks[index]); + return index; + } + } + index++; + if (index == chunks_in_file_system+1) index = 1; + } while (index != start_index); + DEBUG(("FILE DEBUG: %lu free chunks\r\n", freed_chunks)); + if (freed_chunks < MIN_CHUNKS_FOR_SWEEP) { + return FILE_NOT_FOUND; + } + // No freed pages, so sweep file system. + filesystem_sweep(); + // This is guaranteed to succeed. + return find_chunk_and_erase(); +} + +STATIC mp_obj_t microbit_file_name(file_descriptor_obj *fd) { + return mp_obj_new_str(&(file_system_chunks[fd->start_chunk].header.filename[0]), file_system_chunks[fd->start_chunk].header.name_len); +} + +STATIC file_descriptor_obj *microbit_file_descriptor_new(uint8_t start_chunk, bool write, bool binary); + +STATIC void clear_file(uint8_t chunk) { + do { + flash_write_byte((uint32_t)&(file_system_chunks[chunk].marker), FREED_CHUNK); + DEBUG(("FILE DEBUG: Freeing chunk %d.\n", chunk)); + chunk = file_system_chunks[chunk].next_chunk; + } while (chunk <= chunks_in_file_system); +} + +STATIC file_descriptor_obj *microbit_file_open(const char *name, size_t name_len, bool write, bool binary) { + if (name_len > MAX_FILENAME_LENGTH) { + return NULL; + } + uint8_t index = microbit_find_file(name, name_len); + if (write) { + if (index != FILE_NOT_FOUND) { + // Free old file + clear_file(index); + } + index = find_chunk_and_erase(); + if (index == FILE_NOT_FOUND) { + mp_raise_OSError(MP_ENOSPC); + } + flash_write_byte((uint32_t)&(file_system_chunks[index].marker), FILE_START); + flash_write_byte((uint32_t)&(file_system_chunks[index].header.name_len), name_len); + flash_write_bytes((uint32_t)&(file_system_chunks[index].header.filename[0]), (uint8_t*)name, name_len); + } else { + if (index == FILE_NOT_FOUND) { + return NULL; + } + } + return microbit_file_descriptor_new(index, write, binary); +} + +STATIC file_descriptor_obj *microbit_file_descriptor_new(uint8_t start_chunk, bool write, bool binary) { + file_descriptor_obj *res = m_new_obj(file_descriptor_obj); + if (binary) { + res->base.type = &uos_mbfs_fileio_type; + } else { + res->base.type = &uos_mbfs_textio_type; + } + res->start_chunk = start_chunk; + res->seek_chunk = start_chunk; + res->seek_offset = file_system_chunks[start_chunk].header.name_len+2; + res->writable = write; + res->open = true; + res->binary = binary; + return res; +} + +STATIC mp_obj_t microbit_remove(mp_obj_t filename) { + mp_uint_t name_len; + const char *name = mp_obj_str_get_data(filename, &name_len); + mp_uint_t index = microbit_find_file(name, name_len); + if (index == 255) { + mp_raise_OSError(MP_ENOENT); + } + clear_file(index); + return mp_const_none; +} + +STATIC void check_file_open(file_descriptor_obj *self) { + if (!self->open) { + mp_raise_ValueError("I/O operation on closed file"); + } +} + +STATIC int advance(file_descriptor_obj *self, uint32_t n, bool write) { + DEBUG(("FILE DEBUG: Advancing from chunk %d, offset %d.\r\n", self->seek_chunk, self->seek_offset)); + self->seek_offset += n; + if (self->seek_offset == DATA_PER_CHUNK) { + self->seek_offset = 0; + if (write) { + uint8_t next_chunk = find_chunk_and_erase(); + if (next_chunk == FILE_NOT_FOUND) { + clear_file(self->start_chunk); + self->open = false; + return MP_ENOSPC; + } + // Link next chunk to this one + flash_write_byte((uint32_t)&(file_system_chunks[self->seek_chunk].next_chunk), next_chunk); + flash_write_byte((uint32_t)&(file_system_chunks[next_chunk].marker), self->seek_chunk); + } + self->seek_chunk = file_system_chunks[self->seek_chunk].next_chunk; + } + DEBUG(("FILE DEBUG: Advanced to chunk %d, offset %d.\r\n", self->seek_chunk, self->seek_offset)); + return 0; +} + +STATIC mp_uint_t microbit_file_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) { + file_descriptor_obj *self = (file_descriptor_obj *)obj; + check_file_open(self); + if (self->writable || file_system_chunks[self->start_chunk].marker == FREED_CHUNK) { + *errcode = MP_EBADF; + return MP_STREAM_ERROR; + } + uint32_t bytes_read = 0; + uint8_t *data = buf; + while (1) { + mp_uint_t to_read = DATA_PER_CHUNK - self->seek_offset; + if (file_system_chunks[self->seek_chunk].next_chunk == UNUSED_CHUNK) { + uint8_t end_offset = file_system_chunks[self->start_chunk].header.end_offset; + if (end_offset == UNUSED_CHUNK) { + to_read = 0; + } else { + to_read = MIN(to_read, (mp_uint_t)end_offset-self->seek_offset); + } + } + to_read = MIN(to_read, size-bytes_read); + if (to_read == 0) { + break; + } + memcpy(data+bytes_read, seek_address(self), to_read); + advance(self, to_read, false); + bytes_read += to_read; + } + return bytes_read; +} + +STATIC mp_uint_t microbit_file_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) { + file_descriptor_obj *self = (file_descriptor_obj *)obj; + check_file_open(self); + if (!self->writable || file_system_chunks[self->start_chunk].marker == FREED_CHUNK) { + *errcode = MP_EBADF; + return MP_STREAM_ERROR; + } + uint32_t len = size; + const uint8_t *data = buf; + while (len) { + uint32_t to_write = MIN(((uint32_t)(DATA_PER_CHUNK - self->seek_offset)), len); + flash_write_bytes((uint32_t)seek_address(self), data, to_write); + int err = advance(self, to_write, true); + if (err) { + *errcode = err; + return MP_STREAM_ERROR; + } + data += to_write; + len -= to_write; + } + return size; +} + +STATIC void microbit_file_close(file_descriptor_obj *fd) { + if (fd->writable) { + flash_write_byte((uint32_t)&(file_system_chunks[fd->start_chunk].header.end_offset), fd->seek_offset); + } + fd->open = false; +} + +STATIC mp_obj_t microbit_file_list(void) { + mp_obj_t res = mp_obj_new_list(0, NULL); + for (uint8_t index = 1; index <= chunks_in_file_system; index++) { + if (file_system_chunks[index].marker == FILE_START) { + mp_obj_t name = mp_obj_new_str(&file_system_chunks[index].header.filename[0], file_system_chunks[index].header.name_len); + mp_obj_list_append(res, name); + } + } + return res; +} + +STATIC mp_obj_t microbit_file_size(mp_obj_t filename) { + mp_uint_t name_len; + const char *name = mp_obj_str_get_data(filename, &name_len); + uint8_t chunk = microbit_find_file(name, name_len); + if (chunk == 255) { + mp_raise_OSError(MP_ENOENT); + } + mp_uint_t len = 0; + uint8_t end_offset = file_system_chunks[chunk].header.end_offset; + uint8_t offset = file_system_chunks[chunk].header.name_len+2; + while (file_system_chunks[chunk].next_chunk != UNUSED_CHUNK) { + len += DATA_PER_CHUNK - offset; + chunk = file_system_chunks[chunk].next_chunk; + offset = 0; + } + len += end_offset - offset; + return mp_obj_new_int(len); +} + +STATIC mp_uint_t file_read_byte(file_descriptor_obj *fd) { + if (file_system_chunks[fd->seek_chunk].next_chunk == UNUSED_CHUNK) { + uint8_t end_offset = file_system_chunks[fd->start_chunk].header.end_offset; + if (end_offset == UNUSED_CHUNK || fd->seek_offset == end_offset) { + return (mp_uint_t)-1; + } + } + mp_uint_t res = file_system_chunks[fd->seek_chunk].data[fd->seek_offset]; + advance(fd, 1, false); + return res; +} + +// Now follows the code to integrate this filesystem into the uos module. + +mp_lexer_t *uos_mbfs_new_reader(const char *filename) { + file_descriptor_obj *fd = microbit_file_open(filename, strlen(filename), false, false); + if (fd == NULL) { + mp_raise_OSError(MP_ENOENT); + } + mp_reader_t reader; + reader.data = fd; + reader.readbyte = (mp_uint_t(*)(void*))file_read_byte; + reader.close = (void(*)(void*))microbit_file_close; // no-op + return mp_lexer_new(qstr_from_str(filename), reader); +} + +mp_import_stat_t uos_mbfs_import_stat(const char *path) { + uint8_t chunk = microbit_find_file(path, strlen(path)); + if (chunk == FILE_NOT_FOUND) { + return MP_IMPORT_STAT_NO_EXIST; + } else { + return MP_IMPORT_STAT_FILE; + } +} + +STATIC mp_obj_t uos_mbfs_file_name(mp_obj_t self) { + file_descriptor_obj *fd = (file_descriptor_obj*)self; + return microbit_file_name(fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uos_mbfs_file_name_obj, uos_mbfs_file_name); + +STATIC mp_obj_t uos_mbfs_file_close(mp_obj_t self) { + file_descriptor_obj *fd = (file_descriptor_obj*)self; + microbit_file_close(fd); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uos_mbfs_file_close_obj, uos_mbfs_file_close); + +STATIC mp_obj_t uos_mbfs_remove(mp_obj_t name) { + return microbit_remove(name); +} +MP_DEFINE_CONST_FUN_OBJ_1(uos_mbfs_remove_obj, uos_mbfs_remove); + +STATIC mp_obj_t uos_mbfs_file___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return uos_mbfs_file_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_mbfs_file___exit___obj, 4, 4, uos_mbfs_file___exit__); + +typedef struct { + mp_obj_base_t base; + mp_fun_1_t iternext; + uint8_t index; +} uos_mbfs_ilistdir_it_t; + +STATIC mp_obj_t uos_mbfs_ilistdir_it_iternext(mp_obj_t self_in) { + uos_mbfs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + // Read until the next FILE_START chunk. + for (; self->index <= chunks_in_file_system; self->index++) { + if (file_system_chunks[self->index].marker != FILE_START) { + continue; + } + + // Get the file name as str object. + mp_obj_t name = mp_obj_new_str(&file_system_chunks[self->index].header.filename[0], file_system_chunks[self->index].header.name_len); + + // make 3-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + t->items[0] = name; + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); // all entries are files + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + + self->index++; + return MP_OBJ_FROM_PTR(t); + } + + return MP_OBJ_STOP_ITERATION; +} + +STATIC mp_obj_t uos_mbfs_ilistdir(void) { + uos_mbfs_ilistdir_it_t *iter = m_new_obj(uos_mbfs_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = uos_mbfs_ilistdir_it_iternext; + iter->index = 1; + + return MP_OBJ_FROM_PTR(iter); +} +MP_DEFINE_CONST_FUN_OBJ_0(uos_mbfs_ilistdir_obj, uos_mbfs_ilistdir); + +MP_DEFINE_CONST_FUN_OBJ_0(uos_mbfs_listdir_obj, microbit_file_list); + +STATIC mp_obj_t microbit_file_writable(mp_obj_t self) { + return mp_obj_new_bool(((file_descriptor_obj *)self)->writable); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(microbit_file_writable_obj, microbit_file_writable); + +STATIC const mp_map_elem_t uos_mbfs_file_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&uos_mbfs_file_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_name), (mp_obj_t)&uos_mbfs_file_name_obj }, + { MP_ROM_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj }, + { MP_ROM_QSTR(MP_QSTR___exit__), (mp_obj_t)&uos_mbfs_file___exit___obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_writable), (mp_obj_t)µbit_file_writable_obj }, + /* Stream methods */ + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj}, +}; +STATIC MP_DEFINE_CONST_DICT(uos_mbfs_file_locals_dict, uos_mbfs_file_locals_dict_table); + + +STATIC const mp_stream_p_t textio_stream_p = { + .read = microbit_file_read, + .write = microbit_file_write, + .is_text = true, +}; + +const mp_obj_type_t uos_mbfs_textio_type = { + { &mp_type_type }, + .name = MP_QSTR_TextIO, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&uos_mbfs_file_locals_dict, +}; + + +STATIC const mp_stream_p_t fileio_stream_p = { + .read = microbit_file_read, + .write = microbit_file_write, +}; + +const mp_obj_type_t uos_mbfs_fileio_type = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&uos_mbfs_file_locals_dict, +}; + +// From micro:bit fileobj.c +mp_obj_t uos_mbfs_open(size_t n_args, const mp_obj_t *args) { + /// -1 means default; 0 explicitly false; 1 explicitly true. + int read = -1; + int text = -1; + if (n_args == 2) { + mp_uint_t len; + const char *mode = mp_obj_str_get_data(args[1], &len); + for (mp_uint_t i = 0; i < len; i++) { + if (mode[i] == 'r' || mode[i] == 'w') { + if (read >= 0) { + goto mode_error; + } + read = (mode[i] == 'r'); + } else if (mode[i] == 'b' || mode[i] == 't') { + if (text >= 0) { + goto mode_error; + } + text = (mode[i] == 't'); + } else { + goto mode_error; + } + } + } + mp_uint_t name_len; + const char *filename = mp_obj_str_get_data(args[0], &name_len); + file_descriptor_obj *res = microbit_file_open(filename, name_len, read == 0, text == 0); + if (res == NULL) { + mp_raise_OSError(MP_ENOENT); + } + return res; +mode_error: + mp_raise_ValueError("illegal mode"); +} + +STATIC mp_obj_t uos_mbfs_stat(mp_obj_t filename) { + mp_obj_t file_size = microbit_file_size(filename); + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); // st_mode + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev + t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink + t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid + t->items[6] = file_size; // st_size + t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime + t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime + t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime + return MP_OBJ_FROM_PTR(t); +} +MP_DEFINE_CONST_FUN_OBJ_1(uos_mbfs_stat_obj, uos_mbfs_stat); + +#endif // MICROPY_MBFS diff --git a/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.h b/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.h new file mode 100755 index 0000000..4157e8c --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/uos/microbitfs.h @@ -0,0 +1,52 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Mark Shannon + * Copyright (c) 2017 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __MICROPY_INCLUDED_FILESYSTEM_H__ +#define __MICROPY_INCLUDED_FILESYSTEM_H__ + +#include "py/obj.h" +#include "py/lexer.h" + +#ifndef MBFS_LOG_CHUNK_SIZE +// This property can be tuned to make the filesystem bigger (while keeping +// the max number of blocks). Note that it cannot (currently) be increased +// beyond 8 or uint8_t integers will overflow. +// 2^7 == 128 bytes +// (128-2) bytes/block * 252 blocks = 31752 usable bytes +#define MBFS_LOG_CHUNK_SIZE 7 +#endif + +mp_obj_t uos_mbfs_open(size_t n_args, const mp_obj_t *args); +void microbit_filesystem_init(void); +mp_lexer_t *uos_mbfs_new_reader(const char *filename); +mp_import_stat_t uos_mbfs_import_stat(const char *path); + +MP_DECLARE_CONST_FUN_OBJ_0(uos_mbfs_listdir_obj); +MP_DECLARE_CONST_FUN_OBJ_0(uos_mbfs_ilistdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(uos_mbfs_remove_obj); +MP_DECLARE_CONST_FUN_OBJ_1(uos_mbfs_stat_obj); + +#endif // __MICROPY_INCLUDED_FILESYSTEM_H__ diff --git a/src/openmv/src/micropython/ports/nrf/modules/uos/moduos.c b/src/openmv/src/micropython/ports/nrf/modules/uos/moduos.c new file mode 100755 index 0000000..03a8dba --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/uos/moduos.c @@ -0,0 +1,188 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpstate.h" +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/objstr.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "modules/uos/microbitfs.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" +//#include "timeutils.h" +#include "uart.h" +//#include "portmodules.h" + +#if MICROPY_HW_ENABLE_RNG +#include "modrandom.h" +#endif // MICROPY_HW_ENABLE_RNG + +/// \module os - basic "operating system" services +/// +/// The `os` module contains functions for filesystem access and `urandom`. +/// +/// The filesystem has `/` as the root directory, and the available physical +/// drives are accessible from here. They are currently: +/// +/// /flash -- the internal flash filesystem +/// /sd -- the SD card (if it exists) +/// +/// On boot up, the current directory is `/flash` if no SD card is inserted, +/// otherwise it is `/sd`. + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "pyboard"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "pyboard"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +#if MICROPY_VFS +/// \function sync() +/// Sync all filesystems. +STATIC mp_obj_t os_sync(void) { + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + // this assumes that vfs->obj is fs_user_mount_t with block device functions + disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync); +#endif + +#if MICROPY_HW_ENABLE_RNG +/// \function urandom(n) +/// Return a bytes object with n random bytes, generated by the hardware +/// random number generator. +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = (uint8_t)(machine_rng_generate_random_word() & 0xFF); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +#endif + +#if MICROPY_PY_MACHINE_UART +// Get or set the UART object that the REPL is repeated on. +// TODO should accept any object with read/write methods. +STATIC mp_obj_t os_dupterm(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_PORT(board_stdio_uart) == NULL) { + return mp_const_none; + } else { + return MP_STATE_PORT(board_stdio_uart); + } + } else { + if (args[0] == mp_const_none) { + MP_STATE_PORT(board_stdio_uart) = NULL; + } else if (mp_obj_get_type(args[0]) == &machine_hard_uart_type) { + MP_STATE_PORT(board_stdio_uart) = args[0]; + } else { + mp_raise_ValueError("need a UART object"); + } + return mp_const_none; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj, 0, 1, os_dupterm); +#endif // MICROPY_PY_MACHINE_UART + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + +#if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + + { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, + +#elif MICROPY_MBFS + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&uos_mbfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&uos_mbfs_ilistdir_obj) }, // uses ~136 bytes + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&uos_mbfs_stat_obj) }, // uses ~228 bytes + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&uos_mbfs_remove_obj) }, +#endif + + /// \constant sep - separation character used in paths + { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, + +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, +#endif + + // these are MicroPython extensions +#if MICROPY_PY_MACHINE_UART + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mod_os_dupterm_obj) }, +#endif +#if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/nrf/modules/utime/modutime.c b/src/openmv/src/micropython/ports/nrf/modules/utime/modutime.c new file mode 100755 index 0000000..60cdbe4 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/modules/utime/modutime.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/nlr.h" +#include "py/smallint.h" +#include "py/obj.h" +#include "extmod/utime_mphal.h" + +/// \module time - time related functions +/// +/// The `time` module provides functions for getting the current time and date, +/// and for sleeping. + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/nrf/mpconfigport.h b/src/openmv/src/micropython/ports/nrf/mpconfigport.h new file mode 100755 index 0000000..a5e1642 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/mpconfigport.h @@ -0,0 +1,344 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NRF5_MPCONFIGPORT_H__ +#define NRF5_MPCONFIGPORT_H__ + +#include + +// options to control how MicroPython is built +#ifndef MICROPY_VFS +#define MICROPY_VFS (0) +#endif +#define MICROPY_VFS_FAT (MICROPY_VFS) +#define MICROPY_ALLOC_PATH_MAX (512) +#define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_READER_VFS (MICROPY_VFS) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (0) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_KBD_EXCEPTION (0) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#if NRF51 +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#else +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#endif +#if NRF51 +#define MICROPY_ALLOC_GC_STACK_SIZE (32) +#endif + +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_OPT_MPZ_BITWISE (0) + +// fatfs configuration used in ffconf.h +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_USE_LABEL (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MULTI_PARTITION (1) + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio fatfs_type_fileio +#define mp_type_textio fatfs_type_textio + +// use vfs's functions for import stat and builtin open +#if MICROPY_VFS +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj +#endif + +// Enable micro:bit filesystem by default. +#ifndef MICROPY_MBFS +#define MICROPY_MBFS (1) +#endif + +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_CENTER (0) +#define MICROPY_PY_BUILTINS_STR_PARTITION (0) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_EXECFILE (0) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT nrf5_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_UERRNO (0) +#define MICROPY_PY_UBINASCII (0) +#define MICROPY_PY_URANDOM (0) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0) +#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_URE (0) +#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (0) +#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new +#define MICROPY_PY_MACHINE_SPI (0) +#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) +#define MICROPY_PY_FRAMEBUF (0) + +#ifndef MICROPY_HW_LED_COUNT +#define MICROPY_HW_LED_COUNT (0) +#endif + +#ifndef MICROPY_HW_LED_PULLUP +#define MICROPY_HW_LED_PULLUP (0) +#endif + +#ifndef MICROPY_PY_MUSIC +#define MICROPY_PY_MUSIC (0) +#endif + +#ifndef MICROPY_PY_MACHINE_ADC +#define MICROPY_PY_MACHINE_ADC (0) +#endif + +#ifndef MICROPY_PY_MACHINE_I2C +#define MICROPY_PY_MACHINE_I2C (0) +#endif + +#ifndef MICROPY_PY_MACHINE_HW_SPI +#define MICROPY_PY_MACHINE_HW_SPI (1) +#endif + +#ifndef MICROPY_PY_MACHINE_HW_PWM +#define MICROPY_PY_MACHINE_HW_PWM (0) +#endif + +#ifndef MICROPY_PY_MACHINE_SOFT_PWM +#define MICROPY_PY_MACHINE_SOFT_PWM (0) +#endif + +#ifndef MICROPY_PY_MACHINE_TIMER +#define MICROPY_PY_MACHINE_TIMER (0) +#endif + +#ifndef MICROPY_PY_MACHINE_RTCOUNTER +#define MICROPY_PY_MACHINE_RTCOUNTER (0) +#endif + +#ifndef MICROPY_PY_RANDOM_HW_RNG +#define MICROPY_PY_RANDOM_HW_RNG (0) +#endif + + +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) + +// if sdk is in use, import configuration +#if BLUETOOTH_SD +#include "bluetooth_conf.h" +#endif + +#ifndef MICROPY_PY_UBLUEPY +#define MICROPY_PY_UBLUEPY (0) +#endif + +#ifndef MICROPY_PY_BLE_NUS +#define MICROPY_PY_BLE_NUS (0) +#endif + +// type definitions for the specific machine + +#define BYTES_PER_WORD (4) + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +#define MP_SSIZE_MAX (0x7fffffff) + +#define UINT_FMT "%u" +#define INT_FMT "%d" +#define HEX2_FMT "%02x" + +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +typedef long mp_off_t; + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t board_module; +extern const struct _mp_obj_module_t machine_module; +extern const struct _mp_obj_module_t mp_module_utime; +extern const struct _mp_obj_module_t mp_module_uos; +extern const struct _mp_obj_module_t mp_module_ubluepy; +extern const struct _mp_obj_module_t music_module; +extern const struct _mp_obj_module_t random_module; + +#if MICROPY_PY_UBLUEPY +#define UBLUEPY_MODULE { MP_ROM_QSTR(MP_QSTR_ubluepy), MP_ROM_PTR(&mp_module_ubluepy) }, +#else +#define UBLUEPY_MODULE +#endif + +#if MICROPY_PY_MUSIC +#define MUSIC_MODULE { MP_ROM_QSTR(MP_QSTR_music), MP_ROM_PTR(&music_module) }, +#else +#define MUSIC_MODULE +#endif + +#if MICROPY_PY_RANDOM_HW_RNG +#define RANDOM_MODULE { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&random_module) }, +#else +#define RANDOM_MODULE +#endif + +#if BOARD_SPECIFIC_MODULES +#include "boardmodules.h" +#define MICROPY_BOARD_BUILTINS BOARD_MODULES +#else +#define MICROPY_BOARD_BUILTINS +#endif // BOARD_SPECIFIC_MODULES + +#if BLUETOOTH_SD + +#if MICROPY_PY_BLE +extern const struct _mp_obj_module_t ble_module; +#define BLE_MODULE { MP_ROM_QSTR(MP_QSTR_ble), MP_ROM_PTR(&ble_module) }, +#else +#define BLE_MODULE +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + BLE_MODULE \ + MUSIC_MODULE \ + UBLUEPY_MODULE \ + RANDOM_MODULE \ + MICROPY_BOARD_BUILTINS \ + + +#else +extern const struct _mp_obj_module_t ble_module; +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + MUSIC_MODULE \ + RANDOM_MODULE \ + MICROPY_BOARD_BUILTINS \ + + +#endif // BLUETOOTH_SD + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&mp_builtin_help_obj) }, \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, \ + +// extra constants +#define MICROPY_PORT_CONSTANTS \ + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&board_module) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + BLE_MODULE \ + +#define MP_STATE_PORT MP_STATE_VM + +#if MICROPY_PY_MUSIC +#define ROOT_POINTERS_MUSIC \ + struct _music_data_t *music_data; +#else +#define ROOT_POINTERS_MUSIC +#endif + +#if MICROPY_PY_MACHINE_SOFT_PWM +#define ROOT_POINTERS_SOFTPWM \ + const struct _pwm_events *pwm_active_events; \ + const struct _pwm_events *pwm_pending_events; +#else +#define ROOT_POINTERS_SOFTPWM +#endif + +#if defined(NRF52840_XXAA) +#define NUM_OF_PINS 48 +#else +#define NUM_OF_PINS 32 +#endif + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t pin_class_mapper; \ + mp_obj_t pin_class_map_dict; \ + mp_obj_t pin_irq_handlers[NUM_OF_PINS]; \ + \ + /* stdio is repeated on this UART object if it's not null */ \ + struct _machine_hard_uart_obj_t *board_stdio_uart; \ + \ + ROOT_POINTERS_MUSIC \ + ROOT_POINTERS_SOFTPWM \ + \ + /* micro:bit root pointers */ \ + void *async_data[2]; \ + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// We need to provide a declaration/definition of alloca() +#include + +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_nrf5.h" + +#endif diff --git a/src/openmv/src/micropython/ports/nrf/mphalport.c b/src/openmv/src/micropython/ports/nrf/mphalport.c new file mode 100755 index 0000000..9ce9045 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/mphalport.c @@ -0,0 +1,222 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpstate.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "uart.h" +#include "nrfx_errors.h" +#include "nrfx_config.h" + +// this table converts from HAL_StatusTypeDef to POSIX errno +const byte mp_hal_status_to_errno_table[4] = { + [HAL_OK] = 0, + [HAL_ERROR] = MP_EIO, + [HAL_BUSY] = MP_EBUSY, + [HAL_TIMEOUT] = MP_ETIMEDOUT, +}; + +NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { + mp_raise_OSError(mp_hal_status_to_errno_table[status]); +} + +#if !MICROPY_KBD_EXCEPTION +void mp_hal_set_interrupt_char(int c) { + +} +#endif + +#if !MICROPY_PY_BLE_NUS +int mp_hal_stdin_rx_chr(void) { + for (;;) { + if (MP_STATE_PORT(board_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(board_stdio_uart))) { + return uart_rx_char(MP_STATE_PORT(board_stdio_uart)); + } + } + + return 0; +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + if (MP_STATE_PORT(board_stdio_uart) != NULL) { + uart_tx_strn(MP_STATE_PORT(board_stdio_uart), str, len); + } +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { + if (MP_STATE_PORT(board_stdio_uart) != NULL) { + uart_tx_strn_cooked(MP_STATE_PORT(board_stdio_uart), str, len); + } +} +#endif + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_delay_us(mp_uint_t us) +{ + if (us == 0) { + return; + } + + register uint32_t delay __ASM ("r0") = us; + __ASM volatile ( +#ifdef NRF51 + ".syntax unified\n" +#endif + "1:\n" + " SUBS %0, %0, #1\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" +#ifdef NRF52 + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" +#endif + " BNE 1b\n" + : "+r" (delay)); +} + +void mp_hal_delay_ms(mp_uint_t ms) +{ + for (mp_uint_t i = 0; i < ms; i++) + { + mp_hal_delay_us(999); + } +} + +#if defined(NRFX_LOG_ENABLED) && (NRFX_LOG_ENABLED == 1) + +static const char nrfx_error_unknown[1] = ""; + +static const char nrfx_error_success[] = "NRFX_SUCCESS"; +static const char nrfx_error_internal[] = "NRFX_ERROR_INTERNAL"; +static const char nrfx_error_no_mem[] = "NRFX_ERROR_NO_MEM"; +static const char nrfx_error_not_supported[] = "NRFX_ERROR_NOT_SUPPORTED"; +static const char nrfx_error_invalid_param[] = "NRFX_ERROR_INVALID_PARAM"; +static const char nrfx_error_invalid_state[] = "NRFX_ERROR_INVALID_STATE"; +static const char nrfx_error_invalid_length[] = "NRFX_ERROR_INVALID_LENGTH"; +static const char nrfx_error_timeout[] = "NRFX_ERROR_TIMEOUT"; +static const char nrfx_error_forbidden[] = "NRFX_ERROR_FORBIDDEN"; +static const char nrfx_error_null[] = "NRFX_ERROR_NULL"; +static const char nrfx_error_invalid_addr[] = "NRFX_ERROR_INVALID_ADDR"; +static const char nrfx_error_busy[] = "NRFX_ERROR_BUSY"; +static const char nrfx_error_already_initalized[] = "NRFX_ERROR_ALREADY_INITIALIZED"; + +static const char * nrfx_error_strings[13] = { + nrfx_error_success, + nrfx_error_internal, + nrfx_error_no_mem, + nrfx_error_not_supported, + nrfx_error_invalid_param, + nrfx_error_invalid_state, + nrfx_error_invalid_length, + nrfx_error_timeout, + nrfx_error_forbidden, + nrfx_error_null, + nrfx_error_invalid_addr, + nrfx_error_busy, + nrfx_error_already_initalized +}; + +static const char nrfx_drv_error_twi_err_overrun[] = "NRFX_ERROR_DRV_TWI_ERR_OVERRUN"; +static const char nrfx_drv_error_twi_err_anack[] = "NRFX_ERROR_DRV_TWI_ERR_ANACK"; +static const char nrfx_drv_error_twi_err_dnack[] = "NRFX_ERROR_DRV_TWI_ERR_DNACK"; + +static const char * nrfx_drv_error_strings[3] = { + nrfx_drv_error_twi_err_overrun, + nrfx_drv_error_twi_err_anack, + nrfx_drv_error_twi_err_dnack +}; + +const char * nrfx_error_code_lookup(uint32_t err_code) { + if (err_code >= NRFX_ERROR_BASE_NUM && err_code <= NRFX_ERROR_BASE_NUM + 13) { + return nrfx_error_strings[err_code - NRFX_ERROR_BASE_NUM]; + } else if (err_code >= NRFX_ERROR_DRIVERS_BASE_NUM && err_code <= NRFX_ERROR_DRIVERS_BASE_NUM + 3) { + return nrfx_drv_error_strings[err_code - NRFX_ERROR_DRIVERS_BASE_NUM]; + } + + return nrfx_error_unknown; +} + +#endif // NRFX_LOG_ENABLED diff --git a/src/openmv/src/micropython/ports/nrf/mphalport.h b/src/openmv/src/micropython/ports/nrf/mphalport.h new file mode 100755 index 0000000..18ff454 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/mphalport.h @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __NRF52_HAL +#define __NRF52_HAL + +#include "py/mpconfig.h" +#include +#include "pin.h" +#include "nrf_gpio.h" +#include "nrfx_config.h" + +typedef enum +{ + HAL_OK = 0x00, + HAL_ERROR = 0x01, + HAL_BUSY = 0x02, + HAL_TIMEOUT = 0x03 +} HAL_StatusTypeDef; + +static inline uint32_t hal_tick_fake(void) { + return 0; +} + +#define mp_hal_ticks_ms hal_tick_fake // TODO: implement. Right now, return 0 always + +extern const unsigned char mp_hal_status_to_errno_table[4]; + +NORETURN void mp_hal_raise(HAL_StatusTypeDef status); +void mp_hal_set_interrupt_char(int c); // -1 to disable + +int mp_hal_stdin_rx_chr(void); +void mp_hal_stdout_tx_str(const char *str); + +void mp_hal_delay_ms(mp_uint_t ms); +void mp_hal_delay_us(mp_uint_t us); + +const char * nrfx_error_code_lookup(uint32_t err_code); + +#define mp_hal_pin_obj_t const pin_obj_t* +#define mp_hal_get_pin_obj(o) pin_find(o) +#define mp_hal_pin_high(p) nrf_gpio_pin_set(p->pin) +#define mp_hal_pin_low(p) nrf_gpio_pin_clear(p->pin) +#define mp_hal_pin_read(p) (nrf_gpio_pin_dir_get(p->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? nrf_gpio_pin_out_read(p->pin) : nrf_gpio_pin_read(p->pin) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_open_drain(p) nrf_gpio_cfg_input(p->pin, NRF_GPIO_PIN_NOPULL) + + +// TODO: empty implementation for now. Used by machine_spi.c:69 +#define mp_hal_delay_us_fast(p) +#define mp_hal_ticks_us() (0) +#define mp_hal_ticks_cpu() (0) + +#endif + diff --git a/src/openmv/src/micropython/ports/nrf/nrf51_af.csv b/src/openmv/src/micropython/ports/nrf/nrf51_af.csv new file mode 100755 index 0000000..0be2770 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/nrf51_af.csv @@ -0,0 +1,32 @@ +P0,P0 +P1,P1,ADC0_IN2 +P2,P2,ADC0_IN3 +P3,P3,ADC0_IN4 +P4,P4,ADC0_IN5 +P5,P5,ADC0_IN6 +P6,P6,ADC0_IN7 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 diff --git a/src/openmv/src/micropython/ports/nrf/nrf52_af.csv b/src/openmv/src/micropython/ports/nrf/nrf52_af.csv new file mode 100755 index 0000000..59686ff --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/nrf52_af.csv @@ -0,0 +1,48 @@ +P0,P0 +P1,P1 +P2,P2 +P3,P3 +P4,P4 +P5,P5 +P6,P6 +P7,P7 +P8,P8 +P9,P9 +P10,P10 +P11,P11 +P12,P12 +P13,P13 +P14,P14 +P15,P15 +P16,P16 +P17,P17 +P18,P18 +P19,P19 +P20,P20 +P21,P21 +P22,P22 +P23,P23 +P24,P24 +P25,P25 +P26,P26 +P27,P27 +P28,P28 +P29,P29 +P30,P30 +P31,P31 +P32,P32 +P33,P33 +P34,P34 +P35,P35 +P36,P36 +P37,P37 +P38,P38 +P39,P39 +P40,P40 +P41,P41 +P42,P42 +P43,P43 +P44,P44 +P45,P45 +P46,P46 +P47,P47 diff --git a/src/openmv/src/micropython/ports/nrf/nrfx_config.h b/src/openmv/src/micropython/ports/nrf/nrfx_config.h new file mode 100755 index 0000000..d8a7d52 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/nrfx_config.h @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Glenn Ruben Bakke + * Copyright (c) 2018 Ayke van Laethem + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NRFX_CONFIG_H +#define NRFX_CONFIG_H + +#include "mpconfigport.h" +#include "nrf.h" + +// Port specific defines +#ifndef NRFX_LOG_ENABLED +#define NRFX_LOG_ENABLED 0 +#endif + +#define NRFX_LOG_UART_DISABLED 1 + + +// NRFX configurations + +#if NRF51 || NRF52832 + #define GPIO_COUNT 1 +#elif NRF52840 || NRF52840_XXAA + #define GPIO_COUNT 2 +#endif + +#define NRFX_GPIOTE_ENABLED 1 +#define NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 1 +#if NRF51 + #define NRFX_GPIOTE_CONFIG_IRQ_PRIORITY 3 +#else + #define NRFX_GPIOTE_CONFIG_IRQ_PRIORITY 6 +#endif + +#define NRFX_UART_ENABLED 1 +#define NRFX_UART0_ENABLED 1 + +#define NRFX_TWI_ENABLED (MICROPY_PY_MACHINE_I2C) +#define NRFX_TWI0_ENABLED 1 +#define NRFX_TWI1_ENABLED 1 + +#if defined(NRF51) || defined(NRF52832) + #define NRFX_SPI_ENABLED (MICROPY_PY_MACHINE_HW_SPI) + #define NRFX_SPI0_ENABLED 1 + #define NRFX_SPI1_ENABLED 1 + + #if defined(NRF52832) + #define NRFX_SPI2_ENABLED 1 + #endif +#elif defined(NRF52840) + #define NRFX_SPIM_ENABLED (MICROPY_PY_MACHINE_HW_SPI) + #define NRFX_SPIM0_ENABLED 1 + #define NRFX_SPIM1_ENABLED 1 + #define NRFX_SPIM2_ENABLED 1 + #define NRFX_SPIM3_ENABLED (NRF52840) +#endif // NRF51 + +// 0 NRF_GPIO_PIN_NOPULL +// 1 NRF_GPIO_PIN_PULLDOWN +// 3 NRF_GPIO_PIN_PULLUP +#define NRFX_SPI_MISO_PULL_CFG 1 +#define NRFX_SPIM_MISO_PULL_CFG 1 + +#define NRFX_RTC_ENABLED (MICROPY_PY_MACHINE_RTCOUNTER) +#define NRFX_RTC0_ENABLED 1 +#define NRFX_RTC1_ENABLED 1 +#define NRFX_RTC2_ENABLED (!NRF51) + +#define NRFX_TIMER_ENABLED (MICROPY_PY_MACHINE_TIMER) +#define NRFX_TIMER0_ENABLED 1 +#define NRFX_TIMER1_ENABLED (!MICROPY_PY_MACHINE_SOFT_PWM) +#define NRFX_TIMER2_ENABLED 1 +#define NRFX_TIMER3_ENABLED (!NRF51) +#define NRFX_TIMER4_ENABLED (!NRF51) + + +#define NRFX_PWM_ENABLED (!NRF51) && MICROPY_PY_MACHINE_HW_PWM +#define NRFX_PWM0_ENABLED 1 +#define NRFX_PWM1_ENABLED 1 +#define NRFX_PWM2_ENABLED 1 +#define NRFX_PWM3_ENABLED (NRF52840) + +// Peripheral Resource Sharing +#if defined(NRF51) || defined(NRF52832) + #define NRFX_PRS_BOX_0_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI0_ENABLED && NRFX_SPI_ENABLED && NRFX_SPI0_ENABLED) + #define NRFX_PRS_BOX_1_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI1_ENABLED && NRFX_SPI_ENABLED && NRFX_SPI1_ENABLED) + + #if defined(NRF52832) + #define NRFX_PRS_BOX_2_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI1_ENABLED && NRFX_SPI_ENABLED && NRFX_SPI1_ENABLED) + #endif +#elif defined(NRF52840) + #define NRFX_PRS_BOX_0_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI0_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM0_ENABLED) + #define NRFX_PRS_BOX_1_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI1_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM1_ENABLED) + #define NRFX_PRS_BOX_2_ENABLED (NRFX_TWI_ENABLED && NRFX_TWI2_ENABLED && NRFX_SPIM_ENABLED && NRFX_SPIM2_ENABLED) +#endif + +#define NRFX_PRS_ENABLED (NRFX_PRS_BOX_0_ENABLED || NRFX_PRS_BOX_1_ENABLED || NRFX_PRS_BOX_2_ENABLED) + +#define NRFX_SAADC_ENABLED !(NRF51) && (MICROPY_PY_MACHINE_ADC) +#define NRFX_ADC_ENABLED (NRF51) && (MICROPY_PY_MACHINE_ADC) + +#endif // NRFX_CONFIG_H diff --git a/src/openmv/src/micropython/ports/nrf/nrfx_glue.h b/src/openmv/src/micropython/ports/nrf/nrfx_glue.h new file mode 100755 index 0000000..0108e32 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/nrfx_glue.h @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NRFX_GLUE_H +#define NRFX_GLUE_H + +#include + +#define NRFX_ASSERT(expression) do { bool res = expression; (void)res; } while (0) +#define NRFX_DELAY_US mp_hal_delay_us + +#if BLUETOOTH_SD + +#if NRF51 +#include "nrf_soc.h" +#else +#include "nrf_nvic.h" +#endif + +#include "ble_drv.h" + +#if (BLUETOOTH_SD == 110) +#define NRFX_IRQ_ENABLE(irq_number) \ + do { \ + if (ble_drv_stack_enabled() == 1) \ + { \ + sd_nvic_EnableIRQ(irq_number); \ + } else { \ + NVIC_EnableIRQ(irq_number); \ + } \ + } while(0) +#else +#define NRFX_IRQ_ENABLE(irq_number) sd_nvic_EnableIRQ(irq_number) +#endif + +#if (BLUETOOTH_SD == 110) +#define NRFX_IRQ_DISABLE(irq_number) \ + do { \ + if (ble_drv_stack_enabled() == 1) \ + { \ + sd_nvic_DisableIRQ(irq_number); \ + } else { \ + NVIC_DisableIRQ(irq_number); \ + } \ + } while(0) +#else +#define NRFX_IRQ_DISABLE(irq_number) sd_nvic_DisableIRQ(irq_number) +#endif + +#if (BLUETOOTH_SD == 110) +#define NRFX_IRQ_PRIORITY_SET(irq_number, priority) \ + do { \ + if (ble_drv_stack_enabled() == 1) \ + { \ + sd_nvic_SetPriority(irq_number, priority); \ + } else { \ + NVIC_SetPriority(irq_number, priority); \ + } \ + } while(0) +#else +#define NRFX_IRQ_PRIORITY_SET(irq_number, priority) sd_nvic_SetPriority(irq_number, priority) +#endif + +#if (BLUETOOTH_SD == 110) +#define NRFX_IRQ_PENDING_SET(irq_number) \ + do { \ + if (ble_drv_stack_enabled() == 1) \ + { \ + sd_nvic_SetPendingIRQ(irq_number); \ + } else { \ + NVIC_SetPendingIRQ(irq_number); \ + } \ + } while(0) +#else +#define NRFX_IRQ_PENDING_SET(irq_number) sd_nvic_SetPendingIRQ(irq_number) +#endif + +#if (BLUETOOTH_SD == 110) +#define NRFX_IRQ_PENDING_CLEAR(irq_number) \ + do { \ + if (ble_drv_stack_enabled() == 1) \ + { \ + sd_nvic_ClearPendingIRQ(irq_number); \ + } else { \ + NVIC_ClearPendingIRQ(irq_number)(irq_number); \ + } \ + } while(0) +#else +#define NRFX_IRQ_PENDING_CLEAR(irq_number) sd_nvic_ClearPendingIRQ(irq_number) +#endif + +#define NRFX_CRITICAL_SECTION_ENTER() \ + { \ + uint8_t _is_nested_critical_region; \ + sd_nvic_critical_region_enter(&_is_nested_critical_region); + +#define NRFX_CRITICAL_SECTION_EXIT() \ + sd_nvic_critical_region_exit(_is_nested_critical_region); \ + } + +#else // BLUETOOTH_SD + +#define NRFX_IRQ_ENABLE(irq_number) NVIC_EnableIRQ(irq_number) +#define NRFX_IRQ_DISABLE(irq_number) NVIC_DisableIRQ(irq_number) +#define NRFX_IRQ_PRIORITY_SET(irq_number, priority) NVIC_SetPriority(irq_number, priority) +#define NRFX_IRQ_PENDING_SET(irq_number) NVIC_SetPendingIRQ(irq_number) +#define NRFX_IRQ_PENDING_CLEAR(irq_number) NVIC_ClearPendingIRQ(irq_number) + +// Source: +// https://devzone.nordicsemi.com/f/nordic-q-a/8572/disable-interrupts-and-enable-interrupts-if-they-where-enabled/31347#31347 +#define NRFX_CRITICAL_SECTION_ENTER() { int _old_primask = __get_PRIMASK(); __disable_irq(); +#define NRFX_CRITICAL_SECTION_EXIT() __set_PRIMASK(_old_primask); } + +#endif // !BLUETOOTH_SD + +#endif // NRFX_GLUE_H diff --git a/src/openmv/src/micropython/ports/nrf/nrfx_log.h b/src/openmv/src/micropython/ports/nrf/nrfx_log.h new file mode 100755 index 0000000..ca2fd58 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/nrfx_log.h @@ -0,0 +1,84 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef NRFX_LOG_H +#define NRFX_LOG_H + +#include +#include "mphalport.h" +#include "nrfx_config.h" + +#define LOG_TEST_UART 1 + +#define TEST_MODULE_IMPL(x, y) LOG_TEST_ ## x == LOG_TEST_ ## y +#define TEST_MODULE(x, y) TEST_MODULE_IMPL(x, y) + +#if (!defined(NRFX_LOG_ENABLED) || (NRFX_LOG_ENABLED == 0)) || \ + (TEST_MODULE(NRFX_LOG_MODULE, UART) && defined(NRFX_LOG_UART_DISABLED) && NRFX_LOG_UART_DISABLED) + + #define NRFX_LOG_DEBUG(fmt, ...) + #define NRFX_LOG_ERROR(fmt, ...) + #define NRFX_LOG_WARNING(fmt, ...) + #define NRFX_LOG_INFO(fmt, ...) + + #define NRFX_LOG_HEXDUMP_ERROR(p_memory, length) + #define NRFX_LOG_HEXDUMP_WARNING(p_memory, length) + #define NRFX_LOG_HEXDUMP_INFO(p_memory, length) + #define NRFX_LOG_HEXDUMP_DEBUG(p_memory, length) + #define NRFX_LOG_ERROR_STRING_GET(error_code) "" + +#else + + #define VALUE_TO_STR(x) #x + #define VALUE(x) VALUE_TO_STR(x) + + #define LOG_PRINTF(fmt, ...) \ + do { \ + printf("%s: ", VALUE(NRFX_LOG_MODULE)); \ + printf(fmt, ##__VA_ARGS__); \ + printf("\n"); \ + } while (0) + + #define NRFX_LOG_DEBUG LOG_PRINTF + #define NRFX_LOG_ERROR LOG_PRINTF + #define NRFX_LOG_WARNING LOG_PRINTF + #define NRFX_LOG_INFO LOG_PRINTF + + + #define NRFX_LOG_HEXDUMP_ERROR(p_memory, length) + + #define NRFX_LOG_HEXDUMP_WARNING(p_memory, length) + + #define NRFX_LOG_HEXDUMP_INFO(p_memory, length) + + #define NRFX_LOG_HEXDUMP_DEBUG(p_memory, length) + + #define NRFX_LOG_ERROR_STRING_GET(error_code) \ + nrfx_error_code_lookup(error_code) + +#endif // NRFX_LOG_ENABLED + +#endif // NRFX_LOG_H diff --git a/src/openmv/src/micropython/ports/nrf/pin_defs_nrf5.h b/src/openmv/src/micropython/ports/nrf/pin_defs_nrf5.h new file mode 100755 index 0000000..c84d048 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/pin_defs_nrf5.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This file contains pin definitions that are specific to the nrf port. +// This file should only ever be #included by pin.h and not directly. + +#include "nrf_gpio.h" + +enum { + PORT_A, + PORT_B, +}; + +enum { + AF_FN_UART, + AF_FN_SPI, +}; + +enum { + AF_PIN_TYPE_UART_TX = 0, + AF_PIN_TYPE_UART_RX, + AF_PIN_TYPE_UART_CTS, + AF_PIN_TYPE_UART_RTS, + + AF_PIN_TYPE_SPI_MOSI = 0, + AF_PIN_TYPE_SPI_MISO, + AF_PIN_TYPE_SPI_SCK, + AF_PIN_TYPE_SPI_NSS, +}; + +#define PIN_DEFS_PORT_AF_UNION \ + NRF_UART_Type *UART; +// NRF_SPI_Type *SPIM; +// NRF_SPIS_Type *SPIS; + + +typedef NRF_GPIO_Type pin_gpio_t; diff --git a/src/openmv/src/micropython/ports/nrf/pin_named_pins.c b/src/openmv/src/micropython/ports/nrf/pin_named_pins.c new file mode 100755 index 0000000..e1d8736 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/pin_named_pins.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" + +STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_named_pins_obj_t *self = self_in; + mp_printf(print, "", self->name); +} + +const mp_obj_type_t pin_cpu_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_cpu, + .print = pin_named_pins_obj_print, + .locals_dict = (mp_obj_t)&pin_cpu_pins_locals_dict, +}; + +const mp_obj_type_t pin_board_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_board, + .print = pin_named_pins_obj_print, + .locals_dict = (mp_obj_t)&pin_board_pins_locals_dict, +}; + +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { + mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins); + mp_map_elem_t *named_elem = mp_map_lookup(named_map, name, MP_MAP_LOOKUP); + if (named_elem != NULL && named_elem->value != NULL) { + return named_elem->value; + } + return NULL; +} + +const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (af->fn == fn && af->unit == unit) { + return af; + } + } + return NULL; +} + +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (af->idx == af_idx) { + return af; + } + } + return NULL; +} + +/* unused +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (strcmp(name, qstr_str(af->name)) == 0) { + return af; + } + } + return NULL; +} +*/ diff --git a/src/openmv/src/micropython/ports/nrf/qstrdefsport.h b/src/openmv/src/micropython/ports/nrf/qstrdefsport.h new file mode 100755 index 0000000..ef398a4 --- /dev/null +++ b/src/openmv/src/micropython/ports/nrf/qstrdefsport.h @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port +Q(a) +Q(a#) +Q(a#:1) +Q(a#:3) +Q(a2) +Q(a4) +Q(a4:1) +Q(a4:3) +Q(a:1) +Q(a:2) +Q(a:4) +Q(a:5) +Q(b) +Q(b2:1) +Q(b3) +Q(b4) +Q(b4:1) +Q(b4:2) +Q(b5) +Q(b5:1) +Q(b:1) +Q(b:2) +Q(c) +Q(c#) +Q(c#5) +Q(c#5:1) +Q(c#5:2) +Q(c#:1) +Q(c#:8) +Q(c2:2) +Q(c3) +Q(c3:3) +Q(c3:4) +Q(c4) +Q(c4:1) +Q(c4:3) +Q(c4:4) +Q(c5) +Q(c5:1) +Q(c5:2) +Q(c5:3) +Q(c5:4) +Q(c:1) +Q(c:2) +Q(c:3) +Q(c:4) +Q(c:8) +Q(d) +Q(d#) +Q(d#5:2) +Q(d#:2) +Q(d#:3) +Q(d3) +Q(d4) +Q(d4:1) +Q(d5) +Q(d5:1) +Q(d5:2) +Q(d:1) +Q(d:2) +Q(d:3) +Q(d:4) +Q(d:5) +Q(d:6) +Q(d:8) +Q(e) +Q(e3:3) +Q(e4) +Q(e4:1) +Q(e5) +Q(e6:3) +Q(e:1) +Q(e:2) +Q(e:3) +Q(e:4) +Q(e:5) +Q(e:6) +Q(e:8) +Q(eb:8) +Q(f) +Q(f#) +Q(f#5) +Q(f#5:2) +Q(f#:1) +Q(f#:2) +Q(f#:8) +Q(f2) +Q(f:1) +Q(f:2) +Q(f:3) +Q(f:4) +Q(f:8) +Q(g) +Q(g#) +Q(g#:1) +Q(g#:3) +Q(g3:1) +Q(g4) +Q(g4:1) +Q(g4:2) +Q(g5) +Q(g5:1) +Q(g:1) +Q(g:2) +Q(g:3) +Q(g:8) +Q(r) +Q(r4:2) +Q(r:1) +Q(r:2) +Q(r:3) + diff --git a/src/openmv/src/micropython/ports/pic16bit/Makefile b/src/openmv/src/micropython/ports/pic16bit/Makefile new file mode 100755 index 0000000..970e75d --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/Makefile @@ -0,0 +1,70 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +XC16 = /opt/microchip/xc16/v1.24 +CROSS_COMPILE = $(XC16)/bin/xc16- + +PARTFAMILY = dsPIC33F +PART = 33FJ256GP506 + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(XC16)/include +INC += -I$(XC16)/support/$(PARTFAMILY)/h + +CFLAGS_PIC16BIT = -mcpu=$(PART) -mlarge-code +CFLAGS = $(INC) -Wall -Werror -std=gnu99 -nostdlib $(CFLAGS_PIC16BIT) $(COPT) + +#Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -O0 -ggdb +else +CFLAGS += -O1 -DNDEBUG +endif + +LDFLAGS = --heap=0 -nostdlib -T $(XC16)/support/$(PARTFAMILY)/gld/p$(PART).gld -Map=$@.map --cref -p$(PART) +LIBS = -L$(XC16)/lib -L$(XC16)/lib/$(PARTFAMILY) -lc -lm -lpic30 -lp$(PART) + +SRC_C = \ + main.c \ + board.c \ + pic16bit_mphal.c \ + modpyb.c \ + modpybled.c \ + modpybswitch.c \ + lib/utils/pyexec.c \ + lib/utils/sys_stdio_mphal.c \ + lib/mp-readline/readline.c \ + +SRC_S = \ +# gchelper.s \ + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +all: $(BUILD)/firmware.hex + +$(BUILD)/firmware.hex: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(CROSS_COMPILE)bin2hex $< + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)size $@ + +$(PY_BUILD)/gc.o: CFLAGS += -O1 +$(PY_BUILD)/vm.o: CFLAGS += -O1 + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/pic16bit/board.c b/src/openmv/src/micropython/ports/pic16bit/board.c new file mode 100755 index 0000000..0321b0e --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/board.c @@ -0,0 +1,153 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "board.h" + +/********************************************************************/ +// CPU + +void cpu_init(void) { + // set oscillator to operate at 40MHz + // Fosc = Fin*M/(N1*N2), Fcy = Fosc/2 + // Fosc = 7.37M*40/(2*2) = 80Mhz for 7.37M input clock + PLLFBD = 41; // M=39 + CLKDIVbits.PLLPOST = 0; // N1=2 + CLKDIVbits.PLLPRE = 0; // N2=2 + OSCTUN = 0; + + // initiate clock switch to FRC with PLL + __builtin_write_OSCCONH(0x01); + __builtin_write_OSCCONL(0x01); + + // wait for clock switch to occur + while (OSCCONbits.COSC != 0x01) { + } + while (!OSCCONbits.LOCK) { + } +} + +/********************************************************************/ +// LEDs + +#define RED_LED_TRIS _TRISC15 +#define YELLOW_LED_TRIS _TRISC13 +#define GREEN_LED_TRIS _TRISC14 + +#define RED_LED _LATC15 +#define YELLOW_LED _LATC13 +#define GREEN_LED _LATC14 + +#define LED_ON (0) +#define LED_OFF (1) + +void led_init(void) { + // set led GPIO as outputs + RED_LED_TRIS = 0; + YELLOW_LED_TRIS = 0; + GREEN_LED_TRIS = 0; + + // turn off the LEDs + RED_LED = LED_OFF; + YELLOW_LED = LED_OFF; + GREEN_LED = LED_OFF; +} + +void led_state(int led, int state) { + int val = state ? LED_ON : LED_OFF; + switch (led) { + case 1: RED_LED = val; break; + case 2: YELLOW_LED = val; break; + case 3: GREEN_LED = val; break; + } +} + +void led_toggle(int led) { + switch (led) { + case 1: RED_LED ^= 1; break; + case 2: YELLOW_LED ^= 1; break; + case 3: GREEN_LED ^= 1; break; + } +} + +/********************************************************************/ +// switches + +#define SWITCH_S1_TRIS _TRISD8 +#define SWITCH_S2_TRIS _TRISD9 + +#define SWITCH_S1 _RD8 +#define SWITCH_S2 _RD9 + +void switch_init(void) { + // set switch GPIO as inputs + SWITCH_S1_TRIS = 1; + SWITCH_S2_TRIS = 1; +} + +int switch_get(int sw) { + int val = 1; + switch (sw) { + case 1: val = SWITCH_S1; break; + case 2: val = SWITCH_S2; break; + } + return val == 0; +} + +/********************************************************************/ +// UART + +/* +// TODO need an irq +void uart_rx_irq(void) { + if (c == interrupt_char) { + MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj); + } +} +*/ + +void uart_init(void) { + // baudrate = F_CY / 16 (uxbrg + 1) + // F_CY = 40MHz for us + UART1.uxbrg = 64; // 38400 baud + UART1.uxmode = 1 << 15; // UARTEN + UART1.uxsta = 1 << 10; // UTXEN +} + +int uart_rx_any(void) { + return UART1.uxsta & 1; // URXDA +} + +int uart_rx_char(void) { + return UART1.uxrxreg; +} + +void uart_tx_char(int chr) { + while (UART1.uxsta & (1 << 9)) { + // tx fifo is full + } + UART1.uxtxreg = chr; +} diff --git a/src/openmv/src/micropython/ports/pic16bit/board.h b/src/openmv/src/micropython/ports/pic16bit/board.h new file mode 100755 index 0000000..f45f875 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/board.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PIC16BIT_BOARD_H +#define MICROPY_INCLUDED_PIC16BIT_BOARD_H + +void cpu_init(void); + +void led_init(void); +void led_state(int led, int state); +void led_toggle(int led); + +void switch_init(void); +int switch_get(int sw); + +void uart_init(void); +int uart_rx_any(void); +int uart_rx_char(void); +void uart_tx_char(int chr); + +#endif // MICROPY_INCLUDED_PIC16BIT_BOARD_H diff --git a/src/openmv/src/micropython/ports/pic16bit/main.c b/src/openmv/src/micropython/ports/pic16bit/main.c new file mode 100755 index 0000000..4a61c5f --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/main.c @@ -0,0 +1,127 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "lib/utils/pyexec.h" +#include "lib/mp-readline/readline.h" +#include "board.h" +#include "modpyb.h" + +_FGS(GWRP_OFF & GCP_OFF); +_FOSCSEL(FNOSC_FRC); +_FOSC(FCKSM_CSECMD & OSCIOFNC_ON & POSCMD_NONE); +_FWDT(FWDTEN_OFF); + +// maximum heap for device with 8k RAM +static char heap[4600]; + +int main(int argc, char **argv) { + // init the CPU and the peripherals + cpu_init(); + led_init(); + switch_init(); + uart_init(); + +soft_reset: + + // flash green led for 150ms to indicate boot + led_state(1, 0); + led_state(2, 0); + led_state(3, 1); + mp_hal_delay_ms(150); + led_state(3, 0); + + // init MicroPython runtime + int stack_dummy; + MP_STATE_THREAD(stack_top) = (char*)&stack_dummy; + gc_init(heap, heap + sizeof(heap)); + mp_init(); + mp_hal_init(); + readline_init0(); + + // REPL loop + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + printf("PYB: soft reboot\n"); + mp_deinit(); + goto soft_reset; +} + +void gc_collect(void) { + // TODO possibly need to trace registers + void *dummy; + gc_collect_start(); + // Node: stack is ascending + gc_collect_root(&dummy, ((mp_uint_t)&dummy - (mp_uint_t)MP_STATE_THREAD(stack_top)) / sizeof(mp_uint_t)); + gc_collect_end(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + while (1); +} + +void NORETURN __fatal_error(const char *msg) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/src/openmv/src/micropython/ports/pic16bit/modpyb.c b/src/openmv/src/micropython/ports/pic16bit/modpyb.c new file mode 100755 index 0000000..6299146 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/modpyb.c @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "modpyb.h" + +STATIC mp_obj_t pyb_millis(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis); + +STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { + uint32_t startMillis = mp_obj_get_int(start); + uint32_t currMillis = mp_hal_ticks_ms(); + return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x1fff); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis); + +STATIC mp_obj_t pyb_delay(mp_obj_t ms_in) { + mp_int_t ms = mp_obj_get_int(ms_in); + if (ms >= 0) { + mp_hal_delay_ms(ms); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay); + +STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) }, + + { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&pyb_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_delay), MP_ROM_PTR(&pyb_delay_obj) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, + { MP_ROM_QSTR(MP_QSTR_Switch), MP_ROM_PTR(&pyb_switch_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table); + +const mp_obj_module_t pyb_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&pyb_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/pic16bit/modpyb.h b/src/openmv/src/micropython/ports/pic16bit/modpyb.h new file mode 100755 index 0000000..ac19fd2 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/modpyb.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PIC16BIT_MODPYB_H +#define MICROPY_INCLUDED_PIC16BIT_MODPYB_H + +extern const mp_obj_type_t pyb_led_type; +extern const mp_obj_type_t pyb_switch_type; +extern const mp_obj_module_t pyb_module; + +#endif // MICROPY_INCLUDED_PIC16BIT_MODPYB_H diff --git a/src/openmv/src/micropython/ports/pic16bit/modpybled.c b/src/openmv/src/micropython/ports/pic16bit/modpybled.c new file mode 100755 index 0000000..0d200c6 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/modpybled.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "board.h" +#include "modpyb.h" + +typedef struct _pyb_led_obj_t { + mp_obj_base_t base; +} pyb_led_obj_t; + +STATIC const pyb_led_obj_t pyb_led_obj[] = { + {{&pyb_led_type}}, + {{&pyb_led_type}}, + {{&pyb_led_type}}, +}; + +#define NUM_LED MP_ARRAY_SIZE(pyb_led_obj) +#define LED_ID(obj) ((obj) - &pyb_led_obj[0] + 1) + +void pyb_led_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_led_obj_t *self = self_in; + mp_printf(print, "LED(%u)", LED_ID(self)); +} + +STATIC mp_obj_t pyb_led_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_int_t led_id = mp_obj_get_int(args[0]); + if (!(1 <= led_id && led_id <= NUM_LED)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED %d does not exist", led_id)); + } + return (mp_obj_t)&pyb_led_obj[led_id - 1]; +} + +mp_obj_t pyb_led_on(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(LED_ID(self), 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_led_on_obj, pyb_led_on); + +mp_obj_t pyb_led_off(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(LED_ID(self), 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_led_off_obj, pyb_led_off); + +mp_obj_t pyb_led_toggle(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_toggle(LED_ID(self)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_led_toggle_obj, pyb_led_toggle); + +STATIC const mp_rom_map_elem_t pyb_led_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pyb_led_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pyb_led_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&pyb_led_toggle_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_led_locals_dict, pyb_led_locals_dict_table); + +const mp_obj_type_t pyb_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = pyb_led_print, + .make_new = pyb_led_make_new, + .locals_dict = (mp_obj_t)&pyb_led_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/pic16bit/modpybswitch.c b/src/openmv/src/micropython/ports/pic16bit/modpybswitch.c new file mode 100755 index 0000000..0799ad9 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/modpybswitch.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "board.h" +#include "modpyb.h" + +typedef struct _pyb_switch_obj_t { + mp_obj_base_t base; +} pyb_switch_obj_t; + +STATIC const pyb_switch_obj_t pyb_switch_obj[] = { + {{&pyb_switch_type}}, + {{&pyb_switch_type}}, +}; + +#define NUM_SWITCH MP_ARRAY_SIZE(pyb_switch_obj) +#define SWITCH_ID(obj) ((obj) - &pyb_switch_obj[0] + 1) + +void pyb_switch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_switch_obj_t *self = self_in; + mp_printf(print, "Switch(%u)", SWITCH_ID(self)); +} + +STATIC mp_obj_t pyb_switch_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_int_t sw_id = mp_obj_get_int(args[0]); + if (!(1 <= sw_id && sw_id <= NUM_SWITCH)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Switch %d does not exist", sw_id)); + } + return (mp_obj_t)&pyb_switch_obj[sw_id - 1]; +} + +mp_obj_t pyb_switch_value(mp_obj_t self_in) { + pyb_switch_obj_t *self = self_in; + return switch_get(SWITCH_ID(self)) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_switch_value_obj, pyb_switch_value); + +mp_obj_t pyb_switch_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return pyb_switch_value(self_in); +} + +STATIC const mp_rom_map_elem_t pyb_switch_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_switch_value_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_switch_locals_dict, pyb_switch_locals_dict_table); + +const mp_obj_type_t pyb_switch_type = { + { &mp_type_type }, + .name = MP_QSTR_Switch, + .print = pyb_switch_print, + .make_new = pyb_switch_make_new, + .call = pyb_switch_call, + .locals_dict = (mp_obj_t)&pyb_switch_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/pic16bit/mpconfigport.h b/src/openmv/src/micropython/ports/pic16bit/mpconfigport.h new file mode 100755 index 0000000..59880dc --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/mpconfigport.h @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +// options to control how MicroPython is built +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_B) +#define MICROPY_ALLOC_PATH_MAX (64) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_REPL_EVENT_DRIVEN (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (0) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_NO_ALLOCA (1) + +// type definitions for the specific machine + +#define MP_ENDIANNESS_LITTLE (1) +#define MPZ_DIG_SIZE (8) + +// The xc16 compiler doesn't seem to respect alignment (!!) so we +// need to use instead an object representation that allows for +// 2-byte aligned pointers (see config setting above). +//#define MICROPY_OBJ_BASE_ALIGNMENT __attribute__((aligned(4))) + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) + +#define UINT_FMT "%u" +#define INT_FMT "%d" +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size + +typedef int mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// extra builtin names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// extra builtin modules to add to the list of known ones +extern const struct _mp_obj_module_t pyb_module; +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + char *readline_hist[8]; \ + mp_obj_t keyboard_interrupt_obj; \ + +#define MICROPY_MPHALPORT_H "pic16bit_mphal.h" +#define MICROPY_HW_BOARD_NAME "dsPICSK" +#define MICROPY_HW_MCU_NAME "dsPIC33" + +// XC16 toolchain doesn't seem to define these +typedef int intptr_t; +typedef unsigned int uintptr_t; diff --git a/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.c b/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.c new file mode 100755 index 0000000..35955f2 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.c @@ -0,0 +1,79 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mphal.h" +#include "board.h" + +static int interrupt_char; + +void mp_hal_init(void) { + MP_STATE_PORT(keyboard_interrupt_obj) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); +} + +mp_uint_t mp_hal_ticks_ms(void) { + // TODO + return 0; +} + +void mp_hal_delay_ms(mp_uint_t ms) { + // tuned for fixed CPU frequency + for (int i = ms; i > 0; i--) { + for (volatile int j = 0; j < 5000; j++) { + } + } +} + +void mp_hal_set_interrupt_char(int c) { + interrupt_char = c; +} + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + if (uart_rx_any()) { + return uart_rx_char(); + } + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + for (; len > 0; --len) { + uart_tx_char(*str++); + } +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + for (; len > 0; --len) { + if (*str == '\n') { + uart_tx_char('\r'); + } + uart_tx_char(*str++); + } +} diff --git a/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.h b/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.h new file mode 100755 index 0000000..f5da6cd --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/pic16bit_mphal.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +void mp_hal_init(void); + +void mp_hal_set_interrupt_char(int c); diff --git a/src/openmv/src/micropython/ports/pic16bit/qstrdefsport.h b/src/openmv/src/micropython/ports/pic16bit/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/pic16bit/unistd.h b/src/openmv/src/micropython/ports/pic16bit/unistd.h new file mode 100755 index 0000000..23c5e54 --- /dev/null +++ b/src/openmv/src/micropython/ports/pic16bit/unistd.h @@ -0,0 +1,11 @@ +#ifndef MICROPY_INCLUDED_PIC16BIT_UNISTD_H +#define MICROPY_INCLUDED_PIC16BIT_UNISTD_H + +// XC16 compiler doesn't seem to have unistd.h file + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +typedef int ssize_t; + +#endif // MICROPY_INCLUDED_PIC16BIT_UNISTD_H diff --git a/src/openmv/src/micropython/ports/qemu-arm/Makefile b/src/openmv/src/micropython/ports/qemu-arm/Makefile new file mode 100755 index 0000000..95f349b --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/Makefile @@ -0,0 +1,99 @@ +include ../../py/mkenv.mk +-include mpconfigport.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +CROSS_COMPILE = arm-none-eabi- + +TINYTEST = $(TOP)/lib/tinytest + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(TINYTEST) + +CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \ + -ffunction-sections -fdata-sections + +#Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g -DPENDSV_DEBUG +COPT = -O0 +else +COPT += -Os -DNDEBUG +endif + +## With CoudeSourcery it's actually a little different, you just need `-T generic-m-hosted.ld`. +## Although for some reason `$(LD)` will not find that linker script, it works with `$(CC)`. +## It turns out that this is specific to CoudeSourcery, and ARM version of GCC ships something +## else instead and according to the following files, this is what we need to pass to `$(CC). +## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/makefile.conf +## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/qemu/Makefile +LDFLAGS= --specs=nano.specs --specs=rdimon.specs -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map) + +SRC_COMMON_C = \ + moduos.c \ + modmachine.c \ + +SRC_RUN_C = \ + main.c \ + +SRC_TEST_C = \ + test_main.c \ + +LIB_SRC_C += $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/nearbyintf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + utils/sys_stdio_mphal.c \ + ) + +OBJ_COMMON = +OBJ_COMMON += $(PY_O) +OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_COMMON_C:.c=.o)) +OBJ_COMMON += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) + +OBJ_RUN = +OBJ_RUN += $(addprefix $(BUILD)/, $(SRC_RUN_C:.c=.o)) + +OBJ_TEST = +OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) +OBJ_TEST += $(BUILD)/tinytest.o + +# All object files, needed to get dependencies correct +OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C) + +all: run + +run: $(BUILD)/firmware.elf + qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf + +## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here. +$(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN) + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/qemu-arm/Makefile.test b/src/openmv/src/micropython/ports/qemu-arm/Makefile.test new file mode 100755 index 0000000..a9aace6 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/Makefile.test @@ -0,0 +1,24 @@ +LIB_SRC_C = lib/upytesthelper/upytesthelper.c + +include Makefile + +CFLAGS += -DTEST + +.PHONY: $(BUILD)/genhdr/tests.h + +$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h +$(BUILD)/genhdr/tests.h: + (cd $(TOP)/tests; ./run-tests --write-exp) + $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ + +$(BUILD)/tinytest.o: + $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c + +$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +test: $(BUILD)/firmware-test.elf + qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out + $(Q)tail -n2 $(BUILD)/console.out + $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0" diff --git a/src/openmv/src/micropython/ports/qemu-arm/README.md b/src/openmv/src/micropython/ports/qemu-arm/README.md new file mode 100755 index 0000000..4f1e79b --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/README.md @@ -0,0 +1,27 @@ +This is experimental, community-supported port for Cortex-M emulation as +provided by QEMU (http://qemu.org). + +The purposes of this port are to enable: + +1. Continuous integration + - run tests against architecture-specific parts of code base +2. Experimentation + - simulation & prototyping of anything that has architecture-specific + code + - exploring instruction set in terms of optimising some part of + MicroPython or a module +3. Streamlined debugging + - no need for JTAG or even an MCU chip itself + - no need to use OpenOCD or anything else that might slow down the + process in terms of plugging things together, pressing buttons, etc. + +This port will only work with with [GCC ARM Embedded](launchpad.net/gcc-arm-embedded) +toolchain and not with CodeSourcery toolchain. You will need to modify +`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`. +The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while +ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be +passed to the linker. + +To build and run image with builtin testsuite: + + make -f Makefile.test test diff --git a/src/openmv/src/micropython/ports/qemu-arm/main.c b/src/openmv/src/micropython/ports/qemu-arm/main.c new file mode 100755 index 0000000..d23ef57 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/main.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +#include "py/obj.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/gc.h" +#include "py/repl.h" +#include "py/mperrno.h" + +void do_str(const char *src, mp_parse_input_kind_t input_kind) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + // uncaught exception + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + +int main(int argc, char **argv) { + mp_stack_ctrl_init(); + mp_stack_set_limit(10240); + void *heap = malloc(16 * 1024); + gc_init(heap, (char*)heap + 16 * 1024); + mp_init(); + do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT); + mp_deinit(); + return 0; +} + +void gc_collect(void) { +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + printf("uncaught NLR\n"); + exit(1); +} diff --git a/src/openmv/src/micropython/ports/qemu-arm/modmachine.c b/src/openmv/src/micropython/ports/qemu-arm/modmachine.c new file mode 100755 index 0000000..0f66349 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/modmachine.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "extmod/machine_mem.h" +#include "extmod/machine_pinbase.h" +#include "extmod/machine_signal.h" + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PinBase), MP_ROM_PTR(&machine_pinbase_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/qemu-arm/moduos.c b/src/openmv/src/micropython/ports/qemu-arm/moduos.c new file mode 100755 index 0000000..a48b51d --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/moduos.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "extmod/vfs.h" + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + + // MicroPython extensions + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/qemu-arm/mpconfigport.h b/src/openmv/src/micropython/ports/qemu-arm/mpconfigport.h new file mode 100755 index 0000000..5d86191 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/mpconfigport.h @@ -0,0 +1,78 @@ +#include + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (512) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB (1) +#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) +#define MICROPY_MEM_STATS (1) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_HELPER_REPL (0) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_WARNINGS (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) +#define MICROPY_VFS (1) + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +#define MP_SSIZE_MAX (0x7fffffff) + +#define UINT_FMT "%lu" +#define INT_FMT "%ld" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#include +#define MP_PLAT_PRINT_STRN(str, len) write(1, str, len) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// extra built-in modules to add to the list of known ones +extern const struct _mp_obj_module_t mp_module_uos; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ + +// We need to provide a declaration/definition of alloca() +#include + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#undef MP_PLAT_PRINT_STRN +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif diff --git a/src/openmv/src/micropython/ports/qemu-arm/mphalport.h b/src/openmv/src/micropython/ports/qemu-arm/mphalport.h new file mode 100755 index 0000000..d996402 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/mphalport.h @@ -0,0 +1,2 @@ +#define mp_hal_stdin_rx_chr() (0) +#define mp_hal_stdout_tx_strn_cooked(s, l) write(1, (s), (l)) diff --git a/src/openmv/src/micropython/ports/qemu-arm/qstrdefsport.h b/src/openmv/src/micropython/ports/qemu-arm/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/qemu-arm/test_main.c b/src/openmv/src/micropython/ports/qemu-arm/test_main.c new file mode 100755 index 0000000..adbdf04 --- /dev/null +++ b/src/openmv/src/micropython/ports/qemu-arm/test_main.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include + +#include "py/obj.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/gc.h" +#include "py/mperrno.h" + +#include "tinytest.h" +#include "tinytest_macros.h" + +#define HEAP_SIZE (128 * 1024) +STATIC void *heap; + +#include "genhdr/tests.h" + +int main() { + mp_stack_ctrl_init(); + mp_stack_set_limit(10240); + heap = malloc(HEAP_SIZE); + upytest_set_heap(heap, (char*)heap + HEAP_SIZE); + int r = tinytest_main(0, NULL, groups); + printf("status: %d\n", r); + return r; +} + +void gc_collect(void) { + gc_collect_start(); + + // get the registers and the sp + jmp_buf env; + setjmp(env); + volatile mp_uint_t dummy; + void *sp = (void*)&dummy; + + // trace the stack, including the registers (since they live on the stack in this function) + gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - (uint32_t)sp) / sizeof(uint32_t)); + + gc_collect_end(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +void nlr_jump_fail(void *val) { + printf("uncaught NLR\n"); + exit(1); +} diff --git a/src/openmv/src/micropython/ports/stm32/.gitignore b/src/openmv/src/micropython/ports/stm32/.gitignore new file mode 100755 index 0000000..414487d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/.gitignore @@ -0,0 +1 @@ +build-*/ diff --git a/src/openmv/src/micropython/ports/stm32/Makefile b/src/openmv/src/micropython/ports/stm32/Makefile new file mode 100755 index 0000000..a5adf03 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/Makefile @@ -0,0 +1,606 @@ +# Select the board to build for: if not given on the command line, +# then default to PYBV10. +BOARD ?= PYBV10 + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +BOARD_DIR ?= boards/$(BOARD) +ifeq ($(wildcard $(BOARD_DIR)/.),) +$(error Invalid BOARD specified: $(BOARD_DIR)) +endif + +include ../../py/mkenv.mk +-include mpconfigport.mk +include $(BOARD_DIR)/mpconfigboard.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h +QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h $(BOARD_DIR)/mpconfigboard.h + +# directory containing scripts to be frozen as bytecode +FROZEN_MPY_DIR ?= modules + +# include py core make definitions +include $(TOP)/py/py.mk + +LD_DIR=boards +CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include +MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver +USBDEV_DIR=usbdev +#USBHOST_DIR=usbhost +FATFS_DIR=lib/oofatfs +DFU=$(TOP)/tools/dfu.py +# may need to prefix dfu-util with sudo +USE_PYDFU ?= 1 +PYDFU ?= $(TOP)/tools/pydfu.py +DFU_UTIL ?= dfu-util +DEVICE=0483:df11 +STFLASH ?= st-flash +OPENOCD ?= openocd +OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg +STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(CMSIS_DIR)/ +INC += -I$(TOP)/$(HAL_DIR)/Inc +INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc +#INC += -I$(USBHOST_DIR) + +# Basic Cortex-M flags +CFLAGS_CORTEX_M = -mthumb + +# Select hardware floating-point support +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx)) +CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard +else +ifeq ($(MCU_SERIES),f0) +CFLAGS_CORTEX_M += -msoft-float +else +CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard +endif +endif + +# Options for particular MCU series +CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0 +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 + +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += -D$(CMSIS_MCU) +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(COPT) +CFLAGS += -I$(BOARD_DIR) +CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) + +ifeq ($(MICROPY_FLOAT_IMPL),double) +CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE +else +CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT +CFLAGS += -fsingle-precision-constant -Wdouble-promotion +endif + +LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Remove uncalled code from the final image. +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += --gc-sections + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g -DPENDSV_DEBUG +COPT = -O0 +else +COPT += -Os -DNDEBUG +endif + +SRC_LIB = $(addprefix lib/,\ + libc/string0.c \ + oofatfs/ff.c \ + oofatfs/option/unicode.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +ifeq ($(MICROPY_FLOAT_IMPL),double) +SRC_LIBM = $(addprefix lib/libm_dbl/,\ + __cos.c \ + __expo2.c \ + __fpclassify.c \ + __rem_pio2.c \ + __rem_pio2_large.c \ + __signbit.c \ + __sin.c \ + __tan.c \ + acos.c \ + acosh.c \ + asin.c \ + asinh.c \ + atan.c \ + atan2.c \ + atanh.c \ + ceil.c \ + cos.c \ + cosh.c \ + copysign.c \ + erf.c \ + exp.c \ + expm1.c \ + floor.c \ + fmod.c \ + frexp.c \ + ldexp.c \ + lgamma.c \ + log.c \ + log10.c \ + log1p.c \ + modf.c \ + nearbyint.c \ + pow.c \ + rint.c \ + scalbn.c \ + sin.c \ + sinh.c \ + sqrt.c \ + tan.c \ + tanh.c \ + tgamma.c \ + trunc.c \ + ) +else +SRC_LIBM = $(addprefix lib/libm/,\ + math.c \ + acoshf.c \ + asinfacosf.c \ + asinhf.c \ + atan2f.c \ + atanf.c \ + atanhf.c \ + ef_rem_pio2.c \ + erf_lgamma.c \ + fmodf.c \ + kf_cos.c \ + kf_rem_pio2.c \ + kf_sin.c \ + kf_tan.c \ + log1pf.c \ + nearbyintf.c \ + sf_cos.c \ + sf_erf.c \ + sf_frexp.c \ + sf_ldexp.c \ + sf_modf.c \ + sf_sin.c \ + sf_tan.c \ + wf_lgamma.c \ + wf_tgamma.c \ + ) +ifeq ($(MCU_SERIES),f0) +SRC_LIBM += lib/libm/ef_sqrt.c +else +SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c +endif +endif + +EXTMOD_SRC_C = $(addprefix extmod/,\ + modlwip.c \ + modonewire.c \ + ) + +DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + bus/softqspi.c \ + memory/spiflash.c \ + dht/dht.c \ + ) + +SRC_C = \ + main.c \ + stm32_it.c \ + usbd_conf.c \ + usbd_desc.c \ + usbd_cdc_interface.c \ + usbd_hid_interface.c \ + usbd_msc_storage.c \ + mphalport.c \ + mpthreadport.c \ + irq.c \ + pendsv.c \ + systick.c \ + powerctrl.c \ + pybthread.c \ + timer.c \ + led.c \ + pin.c \ + pin_defs_stm32.c \ + pin_named_pins.c \ + bufhelper.c \ + dma.c \ + i2c.c \ + pyb_i2c.c \ + spi.c \ + pyb_spi.c \ + qspi.c \ + uart.c \ + can.c \ + usb.c \ + wdt.c \ + gccollect.c \ + help.c \ + machine_i2c.c \ + machine_spi.c \ + modmachine.c \ + modpyb.c \ + modstm.c \ + moduos.c \ + modutime.c \ + modusocket.c \ + modnetwork.c \ + extint.c \ + usrsw.c \ + rng.c \ + rtc.c \ + flash.c \ + flashbdev.c \ + spibdev.c \ + storage.c \ + sdcard.c \ + sdram.c \ + fatfs_port.c \ + lcd.c \ + accel.c \ + servo.c \ + dac.c \ + adc.c \ + $(wildcard $(BOARD_DIR)/*.c) + +ifeq ($(MCU_SERIES),f0) +SRC_O = \ + $(STARTUP_FILE) \ + system_stm32f0.o \ + resethandler_m0.o \ + gchelper_m0.o +else +SRC_O = \ + $(STARTUP_FILE) \ + system_stm32.o \ + resethandler.o \ + gchelper.o +endif + +SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal.c \ + hal_adc.c \ + hal_adc_ex.c \ + hal_cortex.c \ + hal_dac.c \ + hal_dac_ex.c \ + hal_dma.c \ + hal_flash.c \ + hal_flash_ex.c \ + hal_gpio.c \ + hal_i2c.c \ + hal_pcd.c \ + hal_pcd_ex.c \ + hal_pwr.c \ + hal_pwr_ex.c \ + hal_rcc.c \ + hal_rcc_ex.c \ + hal_rtc.c \ + hal_rtc_ex.c \ + hal_spi.c \ + hal_tim.c \ + hal_tim_ex.c \ + hal_uart.c \ + ) + +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4)) +$(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_ll_usb.o: CFLAGS += -Wno-attributes +SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_sd.c \ + ll_sdmmc.c \ + ll_fmc.c \ + ll_usb.c \ + ) +endif + +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7)) +SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_sdram.c \ + hal_dma_ex.c \ + hal_dcmi.c \ + ) +endif + +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) +else + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) +endif + +SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ + core/src/usbd_core.c \ + core/src/usbd_ctlreq.c \ + core/src/usbd_ioreq.c \ + class/src/usbd_cdc_msc_hid.c \ + class/src/usbd_msc_bot.c \ + class/src/usbd_msc_scsi.c \ + class/src/usbd_msc_data.c \ + ) + +ifneq ($(MICROPY_PY_WIZNET5K),0) +WIZNET5K_DIR=drivers/wiznet5k +INC += -I$(TOP)/$(WIZNET5K_DIR) +CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=$(MICROPY_PY_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_WIZNET5K) +SRC_MOD += network_wiznet5k.c modnwwiznet5k.c +SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\ + ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \ + ethernet/wizchip_conf.c \ + ethernet/socket.c \ + internet/dns/dns.c \ + ) +endif + +# for CC3000 module +ifeq ($(MICROPY_PY_CC3K),1) +CC3000_DIR=drivers/cc3000 +INC += -I$(TOP)/$(CC3000_DIR)/inc +CFLAGS_MOD += -DMICROPY_PY_CC3K=1 +SRC_MOD += modnwcc3k.c +SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\ + cc3000_common.c \ + evnt_handler.c \ + hci.c \ + netapp.c \ + nvmem.c \ + security.c \ + socket.c \ + wlan.c \ + ccspi.c \ + inet_ntop.c \ + inet_pton.c \ + patch.c \ + patch_prog.c \ + ) +endif + +LWIP_DIR = lib/lwip/src +INC += -I$(TOP)/$(LWIP_DIR)/include -Ilwip_inc +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address +SRC_MOD += $(addprefix $(LWIP_DIR)/,\ + core/def.c \ + core/dns.c \ + core/inet_chksum.c \ + core/init.c \ + core/ip.c \ + core/mem.c \ + core/memp.c \ + core/netif.c \ + core/pbuf.c \ + core/raw.c \ + core/stats.c \ + core/sys.c \ + core/tcp.c \ + core/tcp_in.c \ + core/tcp_out.c \ + core/timeouts.c \ + core/udp.c \ + core/ipv4/autoip.c \ + core/ipv4/dhcp.c \ + core/ipv4/etharp.c \ + core/ipv4/icmp.c \ + core/ipv4/igmp.c \ + core/ipv4/ip4_addr.c \ + core/ipv4/ip4.c \ + core/ipv4/ip4_frag.c \ + core/ipv6/dhcp6.c \ + core/ipv6/ethip6.c \ + core/ipv6/icmp6.c \ + core/ipv6/inet6.c \ + core/ipv6/ip6_addr.c \ + core/ipv6/ip6.c \ + core/ipv6/ip6_frag.c \ + core/ipv6/mld6.c \ + core/ipv6/nd6.c \ + netif/ethernet.c \ + ) + +OBJ = +OBJ += $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_O)) +OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) +OBJ += $(BUILD)/pins_$(BOARD).o + +# This file contains performance critical functions so turn up the optimisation +# level. It doesn't add much to the code size and improves performance a bit. +# Don't use -O3 with this file because gcc tries to optimise memset in terms of itself. +$(BUILD)/lib/libc/string0.o: COPT += -O2 + +# We put several files into the first 16K section with the ISRs. +# If we compile these using -O0 then it won't fit. So if you really want these +# to be compiled with -O0, then edit boards/common.ld (in the .isr_vector section) +# and comment out the following lines. +$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os +$(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os +$(PY_BUILD)/formatfloat.o: COPT += -Os +$(PY_BUILD)/parsenum.o: COPT += -Os +$(PY_BUILD)/mpprint.o: COPT += -Os + +all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex + +# For convenience, automatically fetch required submodules if they don't exist +$(TOP)/lib/stm32lib/README.md: + $(ECHO) "stm32lib submodule not found, fetching it now..." + (cd $(TOP) && git submodule update --init lib/stm32lib) + +ifneq ($(FROZEN_DIR),) +# To use frozen source modules, put your .py files in a subdirectory (eg scripts/) +# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch). +CFLAGS += -DMICROPY_MODULE_FROZEN_STR +endif + +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +endif + +.PHONY: deploy + +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" +ifeq ($(USE_PYDFU),1) + $(Q)$(PYTHON) $(PYDFU) -u $< +else + $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $< +endif + +# A board should specify TEXT0_ADDR if to use a different location than the +# default for the firmware memory location. A board can also optionally define +# TEXT1_ADDR to split the firmware into two sections; see below for details. +TEXT0_ADDR ?= 0x08000000 + +ifeq ($(TEXT1_ADDR),) +# No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location + +deploy-stlink: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR) + +deploy-openocd: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK using OpenOCD" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware.bin $(TEXT0_ADDR)" + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware.bin $@ + +else +# TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations + +deploy-stlink: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR) + $(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK" + $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT1_ADDR) + +deploy-openocd: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(BUILD)/firmware1.bin $(TEXT1_ADDR)" + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "GEN $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin + $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@ + +endif + +$(BUILD)/firmware.hex: $(BUILD)/firmware.elf + $(ECHO) "GEN $@" + $(Q)$(OBJCOPY) -O ihex $< $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +PLLVALUES = boards/pllvalues.py +MAKE_PINS = boards/make-pins.py +BOARD_PINS = $(BOARD_DIR)/pins.csv +PREFIX_FILE = boards/stm32f4xx_prefix.c +GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c +GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(BUILD)/pins_qstr.h +GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h +GEN_PINS_AF_DEFS = $(HEADER_BUILD)/pins_af_defs.h +GEN_PINS_AF_PY = $(BUILD)/pins_af.py + +INSERT_USB_IDS = $(TOP)/tools/insert-usb-ids.py +FILE2H = $(TOP)/tools/file2h.py + +USB_IDS_FILE = usb.h +CDCINF_TEMPLATE = pybcdc.inf_template +GEN_CDCINF_FILE = $(HEADER_BUILD)/pybcdc.inf +GEN_CDCINF_HEADER = $(HEADER_BUILD)/pybcdc_inf.h + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(SRC_MOD) $(SRC_LIB) $(EXTMOD_SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += $(GEN_CDCINF_HEADER) + +# Making OBJ use an order-only depenedency on the generated pins.h file +# has the side effect of making the pins.h file before we actually compile +# any of the objects. The normal dependency generation will deal with the +# case when pins.h is modified. But when it doesn't exist, we don't know +# which source files might need it. +$(OBJ): | $(GEN_PINS_HDR) + +# With conditional pins, we may need to regenerate qstrdefs.h when config +# options change. +$(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h + +# main.c can't be even preprocessed without $(GEN_CDCINF_HEADER) +main.c: $(GEN_CDCINF_HEADER) + +# Use a pattern rule here so that make will only call make-pins.py once to make +# both pins_$(BOARD).c and pins.h +$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(HEADER_BUILD)/%_af_defs.h $(BUILD)/%_qstr.h: $(BOARD_DIR)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-defs $(GEN_PINS_AF_DEFS) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) + +$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c + $(call compile_c) + +GEN_PLLFREQTABLE_HDR = $(HEADER_BUILD)/pllfreqtable.h +GEN_STMCONST_HDR = $(HEADER_BUILD)/modstm_const.h +GEN_STMCONST_QSTR = $(BUILD)/modstm_qstr.h +GEN_STMCONST_MPZ = $(HEADER_BUILD)/modstm_mpz.h +CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]') +CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h + +modmachine.c: $(GEN_PLLFREQTABLE_HDR) +$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(PLLVALUES) -c $(if $(filter $(MCU_SERIES),f7),--relax-pll48,) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ + +$(BUILD)/modstm.o: $(GEN_STMCONST_HDR) +# Use a pattern rule here so that make will only call make-stmconst.py once to +# make both modstm_const.h and modstm_qstr.h +$(HEADER_BUILD)/%_const.h $(BUILD)/%_qstr.h: $(CMSIS_MCU_HDR) make-stmconst.py | $(HEADER_BUILD) + $(ECHO) "GEN stmconst $@" + $(Q)$(PYTHON) make-stmconst.py --qstr $(GEN_STMCONST_QSTR) --mpz $(GEN_STMCONST_MPZ) $(CMSIS_MCU_HDR) > $(GEN_STMCONST_HDR) + +$(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H) | $(HEADER_BUILD) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(FILE2H) $< > $@ + +$(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD) + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@ + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/stm32/README.md b/src/openmv/src/micropython/ports/stm32/README.md new file mode 100755 index 0000000..a0c3b7f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/README.md @@ -0,0 +1,121 @@ +MicroPython port to STM32 MCUs +============================== + +This directory contains the port of MicroPython to ST's line of STM32 +microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7 and +STM32L4. Parts of the code here utilise the STM32Cube HAL library. + +The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1 +(both with STM32F405), and PYBLITEv1.0 (with STM32F411). See +[micropython.org/pyboard](http://www.micropython.org/pyboard/) for further +details. + +Other boards that are supported include ST Discovery and Nucleo boards. +See the boards/ subdirectory, which contains the configuration files used +to build each individual board. + +The STM32H7 series has preliminary support: there is a working REPL via +USB and UART, as well as very basic peripheral support, but some things do +not work and none of the advanced features of the STM32H7 are yet supported, +such as the clock tree. At this point the STM32H7 should be considered as a +fast version of the STM32F7. + +Build instructions +------------------ + +Before building the firmware for a given board the MicroPython cross-compiler +must be built; it will be used to pre-compile some of the built-in scripts to +bytecode. The cross-compiler is built and run on the host machine, using: +```bash +$ make -C mpy-cross +``` +This command should be executed from the root directory of this repository. +All other commands below should be executed from the ports/stm32/ directory. + +An ARM compiler is required for the build, along with the associated binary +utilities. The default compiler is `arm-none-eabi-gcc`, which is available for +Arch Linux via the package `arm-none-eabi-gcc`, for Ubuntu via instructions +[here](https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa), or +see [here](https://launchpad.net/gcc-arm-embedded) for the main GCC ARM +Embedded page. The compiler can be changed using the `CROSS_COMPILE` variable +when invoking `make`. + +To build for a given board, run: + + $ make BOARD=PYBV11 + +The default board is PYBV10 but any of the names of the subdirectories in the +`boards/` directory can be passed as the argument to `BOARD=`. The above command +should produce binary images in the `build-PYBV11/` subdirectory (or the +equivalent directory for the board specified). + +You must then get your board/microcontroller into DFU mode. On the pyboard +connect the 3V3 pin to the P1/DFU pin with a wire (they are next to each +other on the bottom left of the board, second row from the bottom) and then +reset (by pressing the RST button) or power on the board. Then flash the +firmware using the command: + + $ make BOARD=PYBV11 deploy + +This will use the included `tools/pydfu.py` script. You can use instead the +`dfu-util` program (available [here](http://dfu-util.sourceforge.net/)) by +passing `USE_PYDFU=0`: + + $ make BOARD=PYBV11 USE_PYDFU=0 deploy + +If flashing the firmware does not work it may be because you don't have the +correct permissions. Try then: + + $ sudo make BOARD=PYBV11 deploy + +Or using `dfu-util` directly: + + $ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV11/firmware.dfu + + +### Flashing the Firmware with stlink + +ST Discovery or Nucleo boards have a builtin programmer called ST-LINK. With +these boards and using Linux or OS X, you have the option to upload the +`stm32` firmware using the `st-flash` utility from the +[stlink](https://github.com/texane/stlink) project. To do so, connect the board +with a mini USB cable to its ST-LINK USB port and then use the make target +`deploy-stlink`. For example, if you have the STM32F4DISCOVERY board, you can +run: + + $ make BOARD=STM32F4DISC deploy-stlink + +The `st-flash` program should detect the USB connection to the board +automatically. If not, run `lsusb` to determine its USB bus and device number +and set the `STLINK_DEVICE` environment variable accordingly, using the format +`:`. Example: + + $ lsusb + [...] + Bus 002 Device 035: ID 0483:3748 STMicroelectronics ST-LINK/V2 + $ export STLINK_DEVICE="002:0035" + $ make BOARD=STM32F4DISC deploy-stlink + + +### Flashing the Firmware with OpenOCD + +Another option to deploy the firmware on ST Discovery or Nucleo boards with a +ST-LINK interface uses [OpenOCD](http://openocd.org/). Connect the board with +a mini USB cable to its ST-LINK USB port and then use the make target +`deploy-openocd`. For example, if you have the STM32F4DISCOVERY board: + + $ make BOARD=STM32F4DISC deploy-openocd + +The `openocd` program, which writes the firmware to the target board's flash, +is configured via the file `ports/stm32/boards/openocd_stm32f4.cfg`. This +configuration should work for all boards based on a STM32F4xx MCU with a +ST-LINKv2 interface. You can override the path to this configuration by setting +`OPENOCD_CONFIG` in your Makefile or on the command line. + +Accessing the board +------------------- + +Once built and deployed, access the MicroPython REPL (the Python prompt) via USB +serial or UART, depending on the board. For the pyboard you can try: + + $ picocom /dev/ttyACM0 diff --git a/src/openmv/src/micropython/ports/stm32/accel.c b/src/openmv/src/micropython/ports/stm32/accel.c new file mode 100755 index 0000000..0d7708c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/accel.c @@ -0,0 +1,226 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" +#include "pin.h" +#include "i2c.h" +#include "accel.h" + +#if MICROPY_HW_HAS_MMA7660 + +/// \moduleref pyb +/// \class Accel - accelerometer control +/// +/// Accel is an object that controls the accelerometer. Example usage: +/// +/// accel = pyb.Accel() +/// for i in range(10): +/// print(accel.x(), accel.y(), accel.z()) +/// +/// Raw values are between -32 and 31. + +#define MMA_ADDR (76) +#define MMA_REG_X (0) +#define MMA_REG_Y (1) +#define MMA_REG_Z (2) +#define MMA_REG_TILT (3) +#define MMA_REG_MODE (7) +#define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) + +void accel_init(void) { + // PB5 is connected to AVDD; pull high to enable MMA accel device + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN); +} + +STATIC void accel_start(void) { + // start the I2C bus in master mode + i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000); + + // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off + mp_hal_delay_ms(30); + mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on + mp_hal_delay_ms(30); + + int ret; + for (int i = 0; i < 4; i++) { + ret = i2c_writeto(I2C1, MMA_ADDR, NULL, 0, true); + if (ret == 0) { + break; + } + } + + if (ret != 0) { + mp_raise_msg(&mp_type_OSError, "accelerometer not found"); + } + + // set MMA to active mode + uint8_t data[2] = {MMA_REG_MODE, 1}; // active mode + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); + + // wait for MMA to become active + mp_hal_delay_ms(30); +} + +/******************************************************************************/ +/* MicroPython bindings */ + +#define NUM_AXIS (3) +#define FILT_DEPTH (4) + +typedef struct _pyb_accel_obj_t { + mp_obj_base_t base; + int16_t buf[NUM_AXIS * FILT_DEPTH]; +} pyb_accel_obj_t; + +STATIC pyb_accel_obj_t pyb_accel_obj; + +/// \classmethod \constructor() +/// Create and return an accelerometer object. +/// +/// Note: if you read accelerometer values immediately after creating this object +/// you will get 0. It takes around 20ms for the first sample to be ready, so, +/// unless you have some other code between creating this object and reading its +/// values, you should put a `pyb.delay(20)` after creating it. For example: +/// +/// accel = pyb.Accel() +/// pyb.delay(20) +/// print(accel.x()) +STATIC mp_obj_t pyb_accel_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // init accel object + pyb_accel_obj.base.type = &pyb_accel_type; + accel_start(); + + return MP_OBJ_FROM_PTR(&pyb_accel_obj); +} + +STATIC mp_obj_t read_axis(int axis) { + uint8_t data[1] = { axis }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); + return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0])); +} + +/// \method x() +/// Get the x-axis value. +STATIC mp_obj_t pyb_accel_x(mp_obj_t self_in) { + return read_axis(MMA_REG_X); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_x_obj, pyb_accel_x); + +/// \method y() +/// Get the y-axis value. +STATIC mp_obj_t pyb_accel_y(mp_obj_t self_in) { + return read_axis(MMA_REG_Y); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_y_obj, pyb_accel_y); + +/// \method z() +/// Get the z-axis value. +STATIC mp_obj_t pyb_accel_z(mp_obj_t self_in) { + return read_axis(MMA_REG_Z); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z); + +/// \method tilt() +/// Get the tilt register. +STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) { + uint8_t data[1] = { MMA_REG_TILT }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); + return mp_obj_new_int(data[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt); + +/// \method filtered_xyz() +/// Get a 3-tuple of filtered x, y and z values. +STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { + pyb_accel_obj_t *self = MP_OBJ_TO_PTR(self_in); + + memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t)); + + uint8_t data[NUM_AXIS] = { MMA_REG_X }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 3, true); + + mp_obj_t tuple[NUM_AXIS]; + for (int i = 0; i < NUM_AXIS; i++) { + self->buf[NUM_AXIS * (FILT_DEPTH - 1) + i] = MMA_AXIS_SIGNED_VALUE(data[i]); + int32_t val = 0; + for (int j = 0; j < FILT_DEPTH; j++) { + val += self->buf[i + NUM_AXIS * j]; + } + tuple[i] = mp_obj_new_int(val); + } + + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_xyz); + +STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) { + uint8_t data[1] = { mp_obj_get_int(reg) }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_writeto(I2C1, MMA_ADDR, data, 1, true); + return mp_obj_new_int(data[0]); +} +MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read); + +STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) { + uint8_t data[2] = { mp_obj_get_int(reg), mp_obj_get_int(val) }; + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write); + +STATIC const mp_rom_map_elem_t pyb_accel_locals_dict_table[] = { + // TODO add init, deinit, and perhaps reset methods + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&pyb_accel_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&pyb_accel_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_z), MP_ROM_PTR(&pyb_accel_z_obj) }, + { MP_ROM_QSTR(MP_QSTR_tilt), MP_ROM_PTR(&pyb_accel_tilt_obj) }, + { MP_ROM_QSTR(MP_QSTR_filtered_xyz), MP_ROM_PTR(&pyb_accel_filtered_xyz_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_accel_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_accel_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_accel_locals_dict, pyb_accel_locals_dict_table); + +const mp_obj_type_t pyb_accel_type = { + { &mp_type_type }, + .name = MP_QSTR_Accel, + .make_new = pyb_accel_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_accel_locals_dict, +}; + +#endif // MICROPY_HW_HAS_MMA7660 diff --git a/src/openmv/src/micropython/ports/stm32/accel.h b/src/openmv/src/micropython/ports/stm32/accel.h new file mode 100755 index 0000000..1fea124 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/accel.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_ACCEL_H +#define MICROPY_INCLUDED_STM32_ACCEL_H + +extern const mp_obj_type_t pyb_accel_type; + +void accel_init(void); + +#endif // MICROPY_INCLUDED_STM32_ACCEL_H diff --git a/src/openmv/src/micropython/ports/stm32/adc.c b/src/openmv/src/micropython/ports/stm32/adc.c new file mode 100755 index 0000000..f16159b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/adc.c @@ -0,0 +1,829 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/mphal.h" +#include "adc.h" +#include "pin.h" +#include "timer.h" + +#if MICROPY_HW_ENABLE_ADC + +/// \moduleref pyb +/// \class ADC - analog to digital conversion: read analog values on a pin +/// +/// Usage: +/// +/// adc = pyb.ADC(pin) # create an analog object from a pin +/// val = adc.read() # read an analog value +/// +/// adc = pyb.ADCAll(resolution) # creale an ADCAll object +/// val = adc.read_channel(channel) # read the given channel +/// val = adc.read_core_temp() # read MCU temperature +/// val = adc.read_core_vbat() # read MCU VBAT +/// val = adc.read_core_vref() # read MCU VREF + +/* ADC defintions */ +#if defined(STM32H7) +#define ADCx (ADC3) +#else +#define ADCx (ADC1) +#endif +#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE +#define ADC_NUM_CHANNELS (19) + +#if defined(STM32F0) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#define ADC_SCALE_V (3.3f) +#define ADC_CAL_ADDRESS (0x1ffff7ba) +#define ADC_CAL1 ((uint16_t*)0x1ffff7b8) +#define ADC_CAL2 ((uint16_t*)0x1ffff7c2) + +#elif defined(STM32F4) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#define ADC_SCALE_V (3.3f) +#define ADC_CAL_ADDRESS (0x1fff7a2a) +#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) +#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) + +#elif defined(STM32F7) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#define ADC_SCALE_V (3.3f) +#if defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) +#define ADC_CAL_ADDRESS (0x1ff07a2a) +#else +#define ADC_CAL_ADDRESS (0x1ff0f44a) +#endif + +#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) +#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) + +#elif defined(STM32H7) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (16) +#define ADC_SCALE_V (3.3f) +#define ADC_CAL_ADDRESS (0x1FF1E860) +#define ADC_CAL1 ((uint16_t*)(0x1FF1E820)) +#define ADC_CAL2 ((uint16_t*)(0x1FF1E840)) +#define ADC_CHANNEL_VBAT ADC_CHANNEL_VBAT_DIV4 + +#elif defined(STM32L4) + +#define ADC_FIRST_GPIO_CHANNEL (1) +#define ADC_LAST_GPIO_CHANNEL (16) +#define ADC_SCALE_V (3.0f) +#define ADC_CAL_ADDRESS (0x1fff75aa) +#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS - 2)) +#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 0x20)) + +#else + +#error Unsupported processor + +#endif + +#if defined(STM32F091xC) +#define VBAT_DIV (2) +#elif defined(STM32F405xx) || defined(STM32F415xx) || \ + defined(STM32F407xx) || defined(STM32F417xx) || \ + defined(STM32F401xC) || defined(STM32F401xE) || \ + defined(STM32F411xE) +#define VBAT_DIV (2) +#elif defined(STM32F427xx) || defined(STM32F429xx) || \ + defined(STM32F437xx) || defined(STM32F439xx) || \ + defined(STM32F446xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) || \ + defined(STM32F746xx) || defined(STM32F765xx) || \ + defined(STM32F767xx) || defined(STM32F769xx) +#define VBAT_DIV (4) +#elif defined(STM32H743xx) +#define VBAT_DIV (4) +#elif defined(STM32L475xx) || defined(STM32L476xx) || \ + defined(STM32L496xx) +#define VBAT_DIV (3) +#else +#error Unsupported processor +#endif + +// Timeout for waiting for end-of-conversion, in ms +#define EOC_TIMEOUT (10) + +/* Core temperature sensor definitions */ +#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */ +#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */ + +// scale and calibration values for VBAT and VREF +#define ADC_SCALE (ADC_SCALE_V / 4095) +#define VREFIN_CAL ((uint16_t *)ADC_CAL_ADDRESS) + +typedef struct _pyb_obj_adc_t { + mp_obj_base_t base; + mp_obj_t pin_name; + int channel; + ADC_HandleTypeDef handle; +} pyb_obj_adc_t; + +// convert user-facing channel number into internal channel number +static inline uint32_t adc_get_internal_channel(uint32_t channel) { + #if defined(STM32F4) || defined(STM32F7) + // on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR + // (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't) + if (channel == 16) { + channel = ADC_CHANNEL_TEMPSENSOR; + } + #endif + return channel; +} + +STATIC bool is_adcx_channel(int channel) { +#if defined(STM32F411xE) + // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp + return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; +#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + return IS_ADC_CHANNEL(channel); +#elif defined(STM32L4) + ADC_HandleTypeDef handle; + handle.Instance = ADCx; + return IS_ADC_CHANNEL(&handle, channel); +#else + #error Unsupported processor +#endif +} + +STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { + uint32_t tickstart = HAL_GetTick(); +#if defined(STM32F4) || defined(STM32F7) + while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) + while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { +#else + #error Unsupported processor +#endif + if (((HAL_GetTick() - tickstart ) > timeout)) { + break; // timeout + } + } +} + +STATIC void adcx_clock_enable(void) { +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + ADCx_CLK_ENABLE(); +#elif defined(STM32H7) + __HAL_RCC_ADC3_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); +#elif defined(STM32L4) + __HAL_RCC_ADC_CLK_ENABLE(); +#else + #error Unsupported processor +#endif +} + +STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { + adcx_clock_enable(); + + adch->Instance = ADCx; + adch->Init.Resolution = resolution; + adch->Init.ContinuousConvMode = DISABLE; + adch->Init.DiscontinuousConvMode = DISABLE; + #if !defined(STM32F0) + adch->Init.NbrOfDiscConversion = 0; + adch->Init.NbrOfConversion = 1; + #endif + adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; + adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; + adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; + adch->Init.ScanConvMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + #elif defined(STM32H7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; + adch->Init.BoostMode = ENABLE; + adch->Init.ScanConvMode = DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + adch->Init.OversamplingMode = DISABLE; + adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; + adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; + #elif defined(STM32L4) + adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; + adch->Init.ScanConvMode = ADC_SCAN_DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_PRESERVED; + adch->Init.OversamplingMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + #else + #error Unsupported processor + #endif + + #if defined(STM32F0) + adch->Init.SamplingTimeCommon = ADC_SAMPLETIME_71CYCLES_5; + #endif + + HAL_ADC_Init(adch); + + #if defined(STM32H7) + HAL_ADCEx_Calibration_Start(adch, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); + #endif +} + +STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { + if (!is_adcx_channel(adc_obj->channel)) { + return; + } + + if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) { + // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode. + const pin_obj_t *pin = pin_adc1[adc_obj->channel]; + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); + } + + adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B); + +#if defined(STM32L4) + ADC_MultiModeTypeDef multimode; + multimode.Mode = ADC_MODE_INDEPENDENT; + if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK) + { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel)); + } +#endif +} + +STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) { + ADC_ChannelConfTypeDef sConfig; + + sConfig.Channel = channel; + sConfig.Rank = 1; +#if defined(STM32F0) + sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5; +#elif defined(STM32F4) || defined(STM32F7) + sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; +#elif defined(STM32H7) + sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.OffsetRightShift = DISABLE; + sConfig.OffsetSignedSaturation = DISABLE; +#elif defined(STM32L4) + if (channel == ADC_CHANNEL_VREFINT + || channel == ADC_CHANNEL_TEMPSENSOR + || channel == ADC_CHANNEL_VBAT) { + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; + } else { + sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; + } + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; +#else + #error Unsupported processor +#endif + + #if defined(STM32F0) + // On the STM32F0 we must select only one channel at a time to sample, so clear all + // channels before calling HAL_ADC_ConfigChannel, which will select the desired one. + adc_handle->Instance->CHSELR = 0; + #endif + + HAL_ADC_ConfigChannel(adc_handle, &sConfig); +} + +STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { + HAL_ADC_Start(adcHandle); + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + uint32_t value = ADCx->DR; + HAL_ADC_Stop(adcHandle); + return value; +} + +STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { + adc_config_channel(adcHandle, channel); + uint32_t raw_value = adc_read_channel(adcHandle); + + #if defined(STM32F4) || defined(STM32F7) + // ST docs say that (at least on STM32F42x and STM32F43x), VBATE must + // be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT + // conversions to work. VBATE is enabled by the above call to read + // the channel, and here we disable VBATE so a subsequent call for + // TEMPSENSOR or VREFINT works correctly. + if (channel == ADC_CHANNEL_VBAT) { + ADC->CCR &= ~ADC_CCR_VBATE; + } + #endif + + return raw_value; +} + +/******************************************************************************/ +/* MicroPython bindings : adc object (single channel) */ + +STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_obj_adc_t *self = MP_OBJ_TO_PTR(self_in); + mp_print_str(print, "pin_name, PRINT_STR); + mp_printf(print, " channel=%u>", self->channel); +} + +/// \classmethod \constructor(pin) +/// Create an ADC object associated with the given pin. +/// This allows you to then read analog values on that pin. +STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check number of arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // 1st argument is the pin name + mp_obj_t pin_obj = args[0]; + + uint32_t channel; + + if (MP_OBJ_IS_INT(pin_obj)) { + channel = adc_get_internal_channel(mp_obj_get_int(pin_obj)); + } else { + const pin_obj_t *pin = pin_find(pin_obj); + if ((pin->adc_num & PIN_ADC1) == 0) { + // No ADC1 function on that pin + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name)); + } + channel = pin->adc_channel; + } + + if (!is_adcx_channel(channel)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel)); + } + + + if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) { + // these channels correspond to physical GPIO ports so make sure they exist + if (pin_adc1[channel] == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "channel %d not available on this board", channel)); + } + } + + pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); + memset(o, 0, sizeof(*o)); + o->base.type = &pyb_adc_type; + o->pin_name = pin_obj; + o->channel = channel; + adc_init_single(o); + + return MP_OBJ_FROM_PTR(o); +} + +/// \method read() +/// Read the value on the analog pin and return it. The returned value +/// will be between 0 and 4095. +STATIC mp_obj_t adc_read(mp_obj_t self_in) { + pyb_obj_adc_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); + +/// \method read_timed(buf, timer) +/// +/// Read analog values into `buf` at a rate set by the `timer` object. +/// +/// `buf` can be bytearray or array.array for example. The ADC values have +/// 12-bit resolution and are stored directly into `buf` if its element size is +/// 16 bits or greater. If `buf` has only 8-bit elements (eg a bytearray) then +/// the sample resolution will be reduced to 8 bits. +/// +/// `timer` should be a Timer object, and a sample is read each time the timer +/// triggers. The timer must already be initialised and running at the desired +/// sampling frequency. +/// +/// To support previous behaviour of this function, `timer` can also be an +/// integer which specifies the frequency (in Hz) to sample at. In this case +/// Timer(6) will be automatically configured to run at the given frequency. +/// +/// Example using a Timer object (preferred way): +/// +/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 +/// tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz +/// buf = bytearray(100) # creat a buffer to store the samples +/// adc.read_timed(buf, tim) # sample 100 values, taking 10s +/// +/// Example using an integer for the frequency: +/// +/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 +/// buf = bytearray(100) # create a buffer of 100 bytes +/// adc.read_timed(buf, 10) # read analog values into buf at 10Hz +/// # this will take 10 seconds to finish +/// for val in buf: # loop over all values +/// print(val) # print the value out +/// +/// This function does not allocate any memory. +STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) { + pyb_obj_adc_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + + TIM_HandleTypeDef *tim; + #if defined(TIM6) + if (mp_obj_is_integer(freq_in)) { + // freq in Hz given so init TIM6 (legacy behaviour) + tim = timer_tim6_init(mp_obj_get_int(freq_in)); + HAL_TIM_Base_Start(tim); + } else + #endif + { + // use the supplied timer object as the sampling time base + tim = pyb_timer_get_handle(freq_in); + } + + // configure the ADC channel + adc_config_channel(&self->handle, self->channel); + + // This uses the timer in polling mode to do the sampling + // TODO use DMA + + uint nelems = bufinfo.len / typesize; + for (uint index = 0; index < nelems; index++) { + // Wait for the timer to trigger so we sample at the correct frequency + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + if (index == 0) { + // for the first sample we need to turn the ADC on + HAL_ADC_Start(&self->handle); + } else { + // for subsequent samples we can just set the "start sample" bit +#if defined(STM32F4) || defined(STM32F7) + ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) + SET_BIT(ADCx->CR, ADC_CR_ADSTART); +#else + #error Unsupported processor +#endif + } + + // wait for sample to complete + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + + // read value + uint value = ADCx->DR; + + // store value in buffer + if (typesize == 1) { + value >>= 4; + } + mp_binary_set_val_array_from_int(bufinfo.typecode, bufinfo.buf, index, value); + } + + // turn the ADC off + HAL_ADC_Stop(&self->handle); + + #if defined(TIM6) + if (mp_obj_is_integer(freq_in)) { + // stop timer if we initialised TIM6 in this function (legacy behaviour) + HAL_TIM_Base_Stop(tim); + } + #endif + + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); + +// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) +// +// Read analog values from multiple ADC's into buffers at a rate set by the +// timer. The ADC values have 12-bit resolution and are stored directly into +// the corresponding buffer if its element size is 16 bits or greater, otherwise +// the sample resolution will be reduced to 8 bits. +// +// This function should not allocate any heap memory. +STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) { + size_t nadcs, nbufs; + mp_obj_t *adc_array, *buf_array; + mp_obj_get_array(adc_array_in, &nadcs, &adc_array); + mp_obj_get_array(buf_array_in, &nbufs, &buf_array); + + if (nadcs < 1) { + mp_raise_ValueError("need at least 1 ADC"); + } + if (nadcs != nbufs) { + mp_raise_ValueError("length of ADC and buffer lists differ"); + } + + // Get buf for first ADC, get word size, check other buffers match in type + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); + size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + void *bufptrs[nbufs]; + for (uint array_index = 0; array_index < nbufs; array_index++) { + mp_buffer_info_t bufinfo_curr; + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { + mp_raise_ValueError("size and type of buffers must match"); + } + bufptrs[array_index] = bufinfo_curr.buf; + } + + // Use the supplied timer object as the sampling time base + TIM_HandleTypeDef *tim; + tim = pyb_timer_get_handle(tim_in); + + // Start adc; this is slow so wait for it to start + pyb_obj_adc_t *adc0 = MP_OBJ_TO_PTR(adc_array[0]); + adc_config_channel(&adc0->handle, adc0->channel); + HAL_ADC_Start(&adc0->handle); + // Wait for sample to complete and discard + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + // Read (and discard) value + uint value = ADCx->DR; + + // Ensure first sample is on a timer tick + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + // Overrun check: assume success + bool success = true; + size_t nelems = bufinfo.len / typesize; + for (size_t elem_index = 0; elem_index < nelems; elem_index++) { + if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) { + // Timer has already triggered + success = false; + } else { + // Wait for the timer to trigger so we sample at the correct frequency + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + for (size_t array_index = 0; array_index < nadcs; array_index++) { + pyb_obj_adc_t *adc = MP_OBJ_TO_PTR(adc_array[array_index]); + // configure the ADC channel + adc_config_channel(&adc->handle, adc->channel); + // for the first sample we need to turn the ADC on + // ADC is started: set the "start sample" bit + #if defined(STM32F4) || defined(STM32F7) + ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; + #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) + SET_BIT(ADCx->CR, ADC_CR_ADSTART); + #else + #error Unsupported processor + #endif + // wait for sample to complete + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + + // read value + value = ADCx->DR; + + // store values in buffer + if (typesize == 1) { + value >>= 4; + } + mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value); + } + } + + // Turn the ADC off + adc0 = MP_OBJ_TO_PTR(adc_array[0]); + HAL_ADC_Stop(&adc0->handle); + + return mp_obj_new_bool(success); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj)); + +STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); + +const mp_obj_type_t pyb_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = adc_print, + .make_new = adc_make_new, + .locals_dict = (mp_obj_dict_t*)&adc_locals_dict, +}; + +/******************************************************************************/ +/* adc all object */ + +typedef struct _pyb_adc_all_obj_t { + mp_obj_base_t base; + ADC_HandleTypeDef handle; +} pyb_adc_all_obj_t; + +void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) { + + switch (resolution) { + #if !defined(STM32H7) + case 6: resolution = ADC_RESOLUTION_6B; break; + #endif + case 8: resolution = ADC_RESOLUTION_8B; break; + case 10: resolution = ADC_RESOLUTION_10B; break; + case 12: resolution = ADC_RESOLUTION_12B; break; + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "resolution %d not supported", resolution)); + } + + for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) { + // only initialise those channels that are selected with the en_mask + if (en_mask & (1 << channel)) { + // Channels 0-16 correspond to real pins. Configure the GPIO pin in + // ADC mode. + const pin_obj_t *pin = pin_adc1[channel]; + if (pin) { + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); + } + } + } + + adcx_init_periph(&adc_all->handle, resolution); +} + +int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { + uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); + + switch (res_reg) { + #if !defined(STM32H7) + case ADC_RESOLUTION_6B: return 6; + #endif + case ADC_RESOLUTION_8B: return 8; + case ADC_RESOLUTION_10B: return 10; + } + return 12; +} + +int adc_read_core_temp(ADC_HandleTypeDef *adcHandle) { + int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + return ((raw_value - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25; +} + +#if MICROPY_PY_BUILTINS_FLOAT +// correction factor for reference value +STATIC volatile float adc_refcor = 1.0f; + +float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) { + int32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_TEMPSENSOR); + + // constants assume 12-bit resolution so we scale the raw value to 12-bits + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0; + return (((float)raw_value * adc_refcor - *ADC_CAL1) / core_temp_avg_slope) + 30.0f; +} + +float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) { + uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VBAT); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + return raw_value * VBAT_DIV * ADC_SCALE * adc_refcor; +} + +float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) { + uint32_t raw_value = adc_config_and_read_channel(adcHandle, ADC_CHANNEL_VREFINT); + + // Note: constants assume 12-bit resolution, so we scale the raw value to + // be 12-bits. + raw_value <<= (12 - adc_get_resolution(adcHandle)); + + // update the reference correction factor + adc_refcor = ((float)(*VREFIN_CAL)) / ((float)raw_value); + + return (*VREFIN_CAL) * ADC_SCALE; +} +#endif + +/******************************************************************************/ +/* MicroPython bindings : adc_all object */ + +STATIC mp_obj_t adc_all_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check number of arguments + mp_arg_check_num(n_args, n_kw, 1, 2, false); + + // make ADCAll object + pyb_adc_all_obj_t *o = m_new_obj(pyb_adc_all_obj_t); + o->base.type = &pyb_adc_all_type; + mp_int_t res = mp_obj_get_int(args[0]); + uint32_t en_mask = 0xffffffff; + if (n_args > 1) { + en_mask = mp_obj_get_int(args[1]); + } + adc_init_all(o, res, en_mask); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) { + pyb_adc_all_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t chan = adc_get_internal_channel(mp_obj_get_int(channel)); + uint32_t data = adc_config_and_read_channel(&self->handle, chan); + return mp_obj_new_int(data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel); + +STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) { + pyb_adc_all_obj_t *self = MP_OBJ_TO_PTR(self_in); + #if MICROPY_PY_BUILTINS_FLOAT + float data = adc_read_core_temp_float(&self->handle); + return mp_obj_new_float(data); + #else + int data = adc_read_core_temp(&self->handle); + return mp_obj_new_int(data); + #endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp); + +#if MICROPY_PY_BUILTINS_FLOAT +STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) { + pyb_adc_all_obj_t *self = MP_OBJ_TO_PTR(self_in); + float data = adc_read_core_vbat(&self->handle); + return mp_obj_new_float(data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat); + +STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) { + pyb_adc_all_obj_t *self = MP_OBJ_TO_PTR(self_in); + float data = adc_read_core_vref(&self->handle); + return mp_obj_new_float(data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref); + +STATIC mp_obj_t adc_all_read_vref(mp_obj_t self_in) { + pyb_adc_all_obj_t *self = MP_OBJ_TO_PTR(self_in); + adc_read_core_vref(&self->handle); + return mp_obj_new_float(ADC_SCALE_V * adc_refcor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_vref_obj, adc_all_read_vref); +#endif + +STATIC const mp_rom_map_elem_t adc_all_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read_channel), MP_ROM_PTR(&adc_all_read_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_core_temp), MP_ROM_PTR(&adc_all_read_core_temp_obj) }, +#if MICROPY_PY_BUILTINS_FLOAT + { MP_ROM_QSTR(MP_QSTR_read_core_vbat), MP_ROM_PTR(&adc_all_read_core_vbat_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_core_vref), MP_ROM_PTR(&adc_all_read_core_vref_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_vref), MP_ROM_PTR(&adc_all_read_vref_obj) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table); + +const mp_obj_type_t pyb_adc_all_type = { + { &mp_type_type }, + .name = MP_QSTR_ADCAll, + .make_new = adc_all_make_new, + .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_ADC diff --git a/src/openmv/src/micropython/ports/stm32/adc.h b/src/openmv/src/micropython/ports/stm32/adc.h new file mode 100755 index 0000000..4ae6022 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/adc.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_ADC_H +#define MICROPY_INCLUDED_STM32_ADC_H + +extern const mp_obj_type_t pyb_adc_type; +extern const mp_obj_type_t pyb_adc_all_type; + +#endif // MICROPY_INCLUDED_STM32_ADC_H diff --git a/src/openmv/src/micropython/ports/stm32/autoflash b/src/openmv/src/micropython/ports/stm32/autoflash new file mode 100755 index 0000000..d2240cc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/autoflash @@ -0,0 +1,44 @@ +#!/bin/sh +# +# This script loops doing the following: +# - wait for DFU device +# - flash DFU device +# - wait for DFU to exit +# - wait for serial port to appear +# - run a terminal + +SERIAL=/dev/ttyACM0 +DEVICE=0483:df11 + +while true; do + echo "waiting for DFU device..." + while true; do + if lsusb | grep -q DFU; then + break + fi + sleep 1s + done + + echo "found DFU device, flashing" + dfu-util -a 0 -d $DEVICE -D build/flash.dfu + + echo "waiting for DFU to exit..." + while true; do + if lsusb | grep -q DFU; then + sleep 1s + continue + fi + break + done + + echo "waiting for $SERIAL..." + while true; do + if ls /dev/tty* | grep -q $SERIAL; then + break + fi + sleep 1s + continue + done + sleep 1s + picocom $SERIAL +done diff --git a/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h new file mode 100755 index 0000000..3ab3d5f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h @@ -0,0 +1,71 @@ +#define MICROPY_HW_BOARD_NAME "B-L475E-IOT01A" +#define MICROPY_HW_MCU_NAME "STM32L475" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV4) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART1 config connected to ST-Link +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +// USART2 config connected to PMOD: Flow control is defined and therfore used +#define MICROPY_HW_UART2_CTS (pin_D3) +#define MICROPY_HW_UART2_RTS (pin_D4) +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +// USART3 config for internal use +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +// USART4 config +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +// USART 1 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_1 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) + +#define MICROPY_HW_SPI2_NSS (pin_D0) +#define MICROPY_HW_SPI2_SCK (pin_D1) +#define MICROPY_HW_SPI2_MISO (pin_D3) +#define MICROPY_HW_SPI2_MOSI (pin_D4) + +#define MICROPY_HW_SPI3_NSS (pin_A15) +#define MICROPY_HW_SPI3_SCK (pin_C10) +#define MICROPY_HW_SPI3_MISO (pin_C11) +#define MICROPY_HW_SPI3_MOSI (pin_C12) + +// User and wake-up switch. Pressing the button makes the input go low. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_A5) // green +#define MICROPY_HW_LED2 (pin_B14) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk new file mode 100755 index 0000000..55e443e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -0,0 +1,9 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L475xx +# The stm32l475 does not have a LDC controller which is +# the only diffrence to the stm32l476 - so reuse some files. +AF_FILE = boards/stm32l476_af.csv +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/pins.csv new file mode 100755 index 0000000..afe87b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/pins.csv @@ -0,0 +1,82 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PH0,PH0 +PH1,PH1 diff --git a/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h new file mode 100755 index 0000000..6bfb281 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 25-November-2015 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DFSDM_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_FIREWALL_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LCD_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_OPAMP_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/* #define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ + + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.h new file mode 100755 index 0000000..7c16692 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.h @@ -0,0 +1,65 @@ +#define MICROPY_HW_BOARD_NAME "Cerb40" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// The Cerb40 has No LEDs + +// The Cerb40 has No SDCard + +// USB config +#define MICROPY_HW_USB_FS (1) +//#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +//#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/CERB40/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/CERB40/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/CERB40/pins.csv new file mode 100755 index 0000000..cca0bc0 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/CERB40/pins.csv @@ -0,0 +1,50 @@ +JP1,3.3V +JP2,GND +JP3,PA8 +JP4,PA13 +JP5,PA7 +JP6,PA6 +JP7,PC10 +JP8,PA14 +JP9,PC11 +JP10,PB4 +JP11,PB9 +JP12,PB3 +JP13,PD2 +JP14,PC12 +JP15,VBAT +JP16,PB8 +JP17,Loader +JP18,PB7 +JP19,PB6 +JP20,PB5 +JP21,Reset +JP22,PC0 +JP23,PC1 +JP24,PC2 +JP25,PC3 +JP26,PA0 +JP27,PA1 +JP28,PA2 +JP29,PA3 +JP30,PA4 +JP31,PA5 +JP32,PB10 +JP33,PB11 +JP34,PB14 +JP35,PB15 +JP36,PC6 +JP37,PC7 +JP38,PC8 +JP39,PC9 +JP40,VUSB +UART1_TX,PA9 +UART1_RX,PA10 +UART3_TX,PD8 +UART3_RX,PD9 +UART3_RTS,PD12 +UART3_CTS,PD11 +CAN2_TX,PB13 +CAN2_RX,PB12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..e71ba33 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h new file mode 100755 index 0000000..53c7f3c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h @@ -0,0 +1,68 @@ +#define MICROPY_HW_BOARD_NAME "Espruino Pico" +#define MICROPY_HW_MCU_NAME "STM32F401CD" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_USOCKET (0) +#define MICROPY_PY_NETWORK (0) + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) + +// Pico has an 8 MHz HSE and the F401 does 84 MHz max +#define MICROPY_HW_CLK_PLLM (5) +#define MICROPY_HW_CLK_PLLN (210) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (7) + +// does not have a 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (0) + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART6_TX (pin_A11) +#define MICROPY_HW_UART6_RX (pin_A12) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B3) +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_B4) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// BTN1 has no pullup or pulldown; it is active high and broken out on a header +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// Pico has 2 LEDs +#define MICROPY_HW_LED1 (pin_B2) // red +#define MICROPY_HW_LED2 (pin_B12) // green +#define MICROPY_HW_LED3 (pin_B12) // green +#define MICROPY_HW_LED4 (pin_B12) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk new file mode 100755 index 0000000..16cacc0 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk @@ -0,0 +1,9 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F401xE +AF_FILE = boards/stm32f401_af.csv +LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 + +# Don't include default frozen modules because MCU is tight on flash space +FROZEN_MPY_DIR ?= diff --git a/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/pins.csv new file mode 100755 index 0000000..636eb2c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/pins.csv @@ -0,0 +1,34 @@ +B3,PB3 +B4,PB4 +B5,PB5 +B6,PB6 +B7,PB7 +A8,PA8 +B8,PB8 +B9,PB9 +A10,PA10 +A0,PA0 +A1,PA1 +A2,PA2 +A3,PA3 +A4,PA4 +A5,PA5 +A6,PA6 +A7,PA7 +B1,PB1 +B10,PB10 +B13,PB13 +B14,PB14 +B15,PB15 +B0,PB0 +SW,PC13 +LED_RED,PB2 +LED_GREEN,PB12 +USB_VBUS,PA9 +USB_DM,PA11 +USB_DP,PA12 +OSC32_IN,PC14 +OSC32_OUT,PC15 +NC1,PA13 +NC2,PA14 +NC3,PA15 diff --git a/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..d27e2e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +/* #define HAL_CAN_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +/* #define HAL_SD_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.h new file mode 100755 index 0000000..2e73d3e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -0,0 +1,74 @@ +#define MICROPY_HW_BOARD_NAME "HydraBus1.0" +#define MICROPY_HW_MCU_NAME "STM32F4" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// USRSW/UBTN (Needs Jumper UBTN) is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// The HydraBus has 1 LED (Needs jumper on ULED) +#define MICROPY_HW_LED1 (pin_A4) // green +#define MICROPY_HW_LED2 (pin_A4) // same as LED1 +#define MICROPY_HW_LED3 (pin_A4) // same as LED1 +#define MICROPY_HW_LED4 (pin_A4) // same as LED1 +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch (not used, always on) +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (1) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/pins.csv new file mode 100755 index 0000000..47e1f43 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/pins.csv @@ -0,0 +1,52 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +VUSB,PB13 +USB1D_N,PB14 +USB1D_P,PB15 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PD2,PD2 +BOOT0,BOOT0 +PA15,PA15 +UART3_TX,PD8 +UART3_RX,PD9 +UART3_RTS,PD12 +UART3_CTS,PD11 diff --git a/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..daf9b63 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/board_init.c new file mode 100755 index 0000000..67ccf23 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/board_init.c @@ -0,0 +1,154 @@ +// The code is this file allows the user to enter DFU mode when the board +// starts up, by connecting POS10 on the external connector to GND. +// The code itself is taken from the LimiFrog software repository found at +// https://github.com/LimiFrog/LimiFrog-SW, and the original license header +// is copied below. + +#include STM32_HAL_H + +static void LBF_DFU_If_Needed(void); + +void LIMIFROG_board_early_init(void) { + LBF_DFU_If_Needed(); +} + +/******************************************************************************* + * LBF_DFU_If_Needed.c + * + * (c)2015 LimiFrog / CYMEYA + * This program is licensed under the terms of the MIT License. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. + * Please refer to the License File LICENSE.txt located at the root of this + * project for full licensing conditions, + * or visit https://opensource.org/licenses/MIT. + ******************************************************************************/ + +#define __LIMIFROG_02 + +/* ==== BTLE (excl UART) ======================================== */ +// PC9 = BT_RST (active high) + +#define BT_RST_PIN GPIO_PIN_9 +#define BT_RST_PORT GPIOC + +// Position 10 +#ifdef __LIMIFROG_01 + #define CONN_POS10_PIN GPIO_PIN_9 + #define CONN_POS10_PORT GPIOB +#else + #define CONN_POS10_PIN GPIO_PIN_8 + #define CONN_POS10_PORT GPIOB +#endif + +static inline void GPIO_HIGH(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + GPIOx->BSRR = (uint32_t)GPIO_Pin; +} + +static inline int IS_GPIO_RESET(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + GPIO_PinState bitstatus; + if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) + { + bitstatus = GPIO_PIN_SET; + } + else + { + bitstatus = GPIO_PIN_RESET; + } + return (bitstatus==GPIO_PIN_RESET); +} + +/************************************************************** + RATIONALE FOR THIS FUNCTION : + + - The STM32 embeds in ROM a bootloader that allows to + obtain code and boot from a number of different interfaces, + including USB in a mode called "DFU" (Device Frimware Update) + [see AN3606 from ST for full details] + This bootloader code is executed instead of the regular + application code when pin BOOT0 is pulled-up (which on + LimiFrog0.2 is achieved by pressing the general-purpose + pushbutton switch on the side. + - The bootloader monitors a number of IOs of the STM32 to decide + from which interface it should boot. + - Problem in LimiFrog (up to versions 0.2a at least): upon + power-up the BLE modules generates some activity on UART3, + which is part of the pins monitored by the STM32. + This misleads the bootloader in trying to boot from UART3 + and, as a result, not continuing with booting from USB. + + - This code implements an alternative solution to launch the + bootloader while making sure UART3 remains stable. + - The idea it to start application code with a check, prior to any + other applicative code, of whether USB bootload is required (as + flagged by a GPIO pulled low at reset, in the same way as BOOT0). + The hadware reset pin of BLE is asserted (so that now it won't + generate any acitivity on UART3), and if USB bootload is required : + bootload ROM is remapped at address 0x0, stack pointer is + updated and the code is branched to the start of the bootloader. + - This code is run prior to any applicative configuration of clocks, + IRQs etc. -- the STM32 is therefore still running from MSI + + THIS FUNCTION MAY BE SUPPRESSED IF YOU NEVER NEED TO BOOT DFU MODE + + ********************************************************************/ + +static void LBF_DFU_If_Needed(void) +{ + + + GPIO_InitTypeDef GPIO_InitStruct; + + + // Initialize and assert pin BTLE_RST + // (hw reset to BLE module, so it won't drive UART3) + + __HAL_RCC_GPIOC_CLK_ENABLE(); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Pin = BT_RST_PIN; + HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct); + + GPIO_HIGH(BT_RST_PORT, BT_RST_PIN); // assert BTLE reset + + + /* -- Bootloader will be called if position 10 on the extension port + is actively pulled low -- */ + // Note - this is an arbitrary choice, code could be modified to + // monitor another GPIO of the STM32 and/or decide that active level + // is high rather than low + + + // Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL) + // Use weak pull-up to detect if pin is externally pulled low + + __HAL_RCC_GPIOB_CLK_ENABLE(); + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pin = CONN_POS10_PIN; + HAL_GPIO_Init(CONN_POS10_PORT, &GPIO_InitStruct); + + // If selection pin pulled low... + if ( IS_GPIO_RESET(CONN_POS10_PORT, CONN_POS10_PIN )) + + { + // Remap bootloader ROM (ie System Flash) to address 0x0 + SYSCFG->MEMRMP = 0x00000001; + + // Init stack pointer with value residing at ROM base + asm ( + "LDR R0, =0x00000000\n\t" // load ROM base address" + "LDR SP,[R0, #0]\n\t" // assign main stack pointer" + ); + + // Jump to address pointed by 0x00000004 -- */ + + asm ( + "LDR R0,[R0, #4]\n\t" // load bootloader address + "BX R0\n\t" + ); + + } +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.h new file mode 100755 index 0000000..d27c2e6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.h @@ -0,0 +1,55 @@ +#define MICROPY_HW_BOARD_NAME "LIMIFROG" +#define MICROPY_HW_MCU_NAME "STM32L476" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +#define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init +void LIMIFROG_board_early_init(void); + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART3_TX (pin_C10) +#define MICROPY_HW_UART3_RX (pin_C11) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) + +#define MICROPY_HW_SPI3_NSS (pin_A15) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +#define MICROPY_HW_USRSW_PIN (pin_A15) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_C3) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.mk new file mode 100755 index 0000000..2adc98f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L476xx +AF_FILE = boards/stm32l476_af.csv +LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/pins.csv new file mode 100755 index 0000000..52f96b6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/pins.csv @@ -0,0 +1,114 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 diff --git a/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h new file mode 100755 index 0000000..6bfb281 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 25-November-2015 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DFSDM_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_FIREWALL_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LCD_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_OPAMP_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/* #define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ + + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c new file mode 100755 index 0000000..53df725 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c @@ -0,0 +1,24 @@ +#include STM32_HAL_H + +void NETDUINO_PLUS_2_board_early_init(void) { + + __HAL_RCC_GPIOB_CLK_ENABLE(); + + // Turn off the backlight. LCD_BL_CTRL = PK3 + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + +#if MICROPY_HW_HAS_SDCARD + // Turn on the power enable for the sdcard (PB1) + GPIO_InitStructure.Pin = GPIO_PIN_1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); +#endif + + // Turn on the power for the 5V on the expansion header (PB2) + GPIO_InitStructure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h new file mode 100755 index 0000000..3125767 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -0,0 +1,68 @@ +#define MICROPY_HW_BOARD_NAME "NetduinoPlus2" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) + +#define MICROPY_HW_HAS_FLASH (1) +// On the netuino, the sdcard appears to be wired up as a 1-bit +// SPI, so the driver needs to be converted to support that before +// we can turn this on. +#define MICROPY_HW_HAS_SDCARD (0) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) + +void NETDUINO_PLUS_2_board_early_init(void); +#define MICROPY_BOARD_EARLY_INIT NETDUINO_PLUS_2_board_early_init + +// HSE is 25MHz +#define MICROPY_HW_CLK_PLLM (25) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) + +// SPI busses +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_B11) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_A10) // Blue LED +#define MICROPY_HW_LED2 (pin_C13) // White LED (aka Power) +#define MICROPY_HW_LED3 (pin_A10) // Same as Led(1) +#define MICROPY_HW_LED4 (pin_C13) // Same as Led(2) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv new file mode 100755 index 0000000..53ffa9d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv @@ -0,0 +1,37 @@ +D0,PC7 +D1,PC6 +D2,PA3 +D3,PA2 +D4,PB12 +D5,PB8 +D6,PB9 +D7,PA1 +D8,PA0 +D9,PA6 +D10,PB10 +D11,PB15 +D12,PB14 +D13,PB13 +SDA,PB6 +SCL,PB7 +A0,PC0 +A1,PC1 +A2,PC2 +A3,PC3 +A4,PC4 +A5,PC5 +LED,PA10 +SW,PB11 +PWR_LED,PC13 +PWR_SD,PB1 +PWR_HDR,PB2 +PWR_ETH,PC15 +RST_ETH,PD2 +UART1_TX,PA9 +UART3_TX,PD8 +UART3_RX,PD9 +UART3_RTS,PD12 +UART3_CTS,PD11 +UART5_TX,PC12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..4cb5a83 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h new file mode 100755 index 0000000..5e67916 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -0,0 +1,71 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F091RC" +#define MICROPY_HW_MCU_NAME "STM32F091RCT6" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_USOCKET (0) +#define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_STM (0) +#define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_VFS_FAT (0) + +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_ADC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_HAS_SWITCH (1) + +// For system clock, board uses internal 48MHz, HSI48 + +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART3_TX (pin_C10) +#define MICROPY_HW_UART3_RX (pin_C11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART5_TX (pin_B3) +#define MICROPY_HW_UART5_RX (pin_B4) +#define MICROPY_HW_UART6_TX (pin_C0) +#define MICROPY_HW_UART6_RX (pin_C1) +#define MICROPY_HW_UART7_TX (pin_C6) +#define MICROPY_HW_UART7_RX (pin_C7) +#define MICROPY_HW_UART8_TX (pin_C2) +#define MICROPY_HW_UART8_RX (pin_C3) + +// USART2 is connected to the ST-LINK USB VCP +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B9) // Arduino D14, pin 5 on CN10 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B11) // pin 18 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +// USER B1 has a pull-up and is active low +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (0) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// NUCLEO-64 has one user LED +#define MICROPY_HW_LED1 (pin_A5) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk new file mode 100755 index 0000000..1d66f7e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f0 +CMSIS_MCU = STM32F091xC +AF_FILE = boards/stm32f091_af.csv +LD_FILES = boards/stm32f091xc.ld boards/common_basic.ld + +# Don't include default frozen modules because MCU is tight on flash space +FROZEN_MPY_DIR ?= diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/pins.csv new file mode 100755 index 0000000..36d3141 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/pins.csv @@ -0,0 +1,87 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +RX,PA3 +TX,PA2 +SCL,PB8 +SDA,PB9 +SCK,PA5 +MISO,PA6 +MOSI,PA7 +CS,PB6 +BOOT0,PF11 +SWDIO,PA13 +SWCLK,PA14 +USER_B1,PC13 +LED_GREEN,PA5 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PF0,PF0 +PF1,PF1 +PF11,PF11 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h new file mode 100755 index 0000000..53ea047 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h @@ -0,0 +1,312 @@ +/** + ****************************************************************************** + * @file stm32f0xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f0xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F0xx_HAL_CONF_H +#define __STM32F0xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_TSC_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ######################### Oscillator Values adaptation ################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +/** + * @brief In the following line adjust the External High Speed oscillator (HSE) Startup + * Timeout value + */ +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup + * Timeout value + */ +#if !defined (HSI_STARTUP_TIMEOUT) + #define HSI_STARTUP_TIMEOUT 5000U /*!< Time out for HSI start up */ +#endif /* HSI_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator for ADC (HSI14) value. + */ +#if !defined (HSI14_VALUE) + #define HSI14_VALUE 14000000U /*!< Value of the Internal High Speed oscillator for ADC in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI14_VALUE */ + +/** + * @brief Internal High Speed oscillator for USB (HSI48) value. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE 48000000U /*!< Value of the Internal High Speed oscillator for USB in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE 40000U +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +/** + * @brief Time out for LSE start up value in ms. + */ +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 0U +#define DATA_CACHE_ENABLE 0U +#define USE_SPI_CRC 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/*#define USE_FULL_ASSERT 1*/ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f0xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f0xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f0xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f0xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f0xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f0xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f0xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32f0xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f0xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f0xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f0xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f0xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f0xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f0xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f0xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f0xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f0xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f0xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f0xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32f0xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f0xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f0xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32f0xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f0xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f0xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f0xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(char* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F0xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h new file mode 100755 index 0000000..a843d3c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h @@ -0,0 +1,57 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F401RE" +#define MICROPY_HW_MCU_NAME "STM32F401xE" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) + +// HSE is 8MHz, CPU freq set to 84MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board +// and this is exposed as a USB Serial port. +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B9) // D14, pin 5 on CN10 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10 +#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 + +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7 +#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10 +#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10 + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk new file mode 100755 index 0000000..4c3022f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F401xE +AF_FILE = boards/stm32f401_af.csv +LD_FILES = boards/stm32f401xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/pins.csv new file mode 100755 index 0000000..6fbf91e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/pins.csv @@ -0,0 +1,75 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PH0,PH0 +PH1,PH1 +LED_GREEN,PA5 +LED_ORANGE,PA5 +LED_RED,PA5 +LED_BLUE,PA4 +SW,PC13 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..daf9b63 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h new file mode 100755 index 0000000..26b1e0b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h @@ -0,0 +1,68 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F411RE" +#define MICROPY_HW_MCU_NAME "STM32F411xE" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) + +// HSE is 8MHz, CPU freq set to 96MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (4) + +// UART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board +// and this is exposed as a USB Serial port. +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B9) // D14, pin 5 on CN10 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10 +#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 + +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7 +#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10 +#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10 + +#define MICROPY_HW_SPI4_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI4_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI4_MISO (pin_A1) // pin 30 on CN7 +#define MICROPY_HW_SPI4_MOSI (pin_A11) // pin 14 on CN10 + + +#define MICROPY_HW_SPI5_NSS (pin_B1) // pin 24 on CN10 +#define MICROPY_HW_SPI5_SCK (pin_A10) // pin 33 on CN10 +#define MICROPY_HW_SPI5_MISO (pin_A12) // pin 12 on CN10 +#define MICROPY_HW_SPI5_MOSI (pin_B0) // pin 34 on CN7 + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk new file mode 100755 index 0000000..df95065 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F411xE +AF_FILE = boards/stm32f411_af.csv +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/pins.csv new file mode 100755 index 0000000..6fbf91e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/pins.csv @@ -0,0 +1,75 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PH0,PH0 +PH1,PH1 +LED_GREEN,PA5 +LED_ORANGE,PA5 +LED_RED,PA5 +LED_BLUE,PA4 +SW,PC13 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..8f0b663 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h new file mode 100755 index 0000000..17883a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -0,0 +1,83 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F429ZI" +#define MICROPY_HW_MCU_NAME "STM32F429" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) + +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) + +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) + +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_C11) + +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) + +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) + +#define MICROPY_HW_SPI4_NSS (pin_E4) +#define MICROPY_HW_SPI4_SCK (pin_E2) +#define MICROPY_HW_SPI4_MISO (pin_E5) +#define MICROPY_HW_SPI4_MOSI (pin_E6) + +#define MICROPY_HW_SPI5_NSS (pin_F6) +#define MICROPY_HW_SPI5_SCK (pin_F7) +#define MICROPY_HW_SPI5_MISO (pin_F8) +#define MICROPY_HW_SPI5_MOSI (pin_F9) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk new file mode 100755 index 0000000..d19a35c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F429xx +AF_FILE = boards/stm32f429_af.csv +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/pins.csv new file mode 100755 index 0000000..8a892d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/pins.csv @@ -0,0 +1,117 @@ +PF4,PF4 +PF5,PF5 +PF2,PF2 +PF3,PF3 +PF0,PF0 +PF1,PF1 +PC14,PC14 +PC15,PC15 +PE6,PE6 +PC13,PC13 +PE4,PE4 +PE5,PE5 +PE2,PE2 +PE3,PE3 +PE0,PE0 +PE1,PE1 +PB8,PB8 +PB9,PB9 +PB6,PB6 +PB7,PB7 +PB4,PB4 +PB5,PB5 +PG15,PG15 +PB3,PB3 +PG13,PG13 +PG14,PG14 +PG11,PG11 +PG12,PG12 +PG9,PG9 +PG10,PG10 +PD7,PD7 +PD6,PD6 +PD5,PD5 +PD4,PD4 +PD3,PD3 +PD2,PD2 +PD1,PD1 +PD0,PD0 +PC12,PC12 +PC11,PC11 +PC10,PC10 +PA15,PA15 +PA14,PA14 +PA13,PA13 +PA12,PA12 +PA11,PA11 +PA10,PA10 +PA9,PA9 +PA8,PA8 +PC9,PC9 +PC8,PC8 +PC7,PC7 +PC6,PC6 +PG8,PG8 +PG7,PG7 +PG6,PG6 +PG5,PG5 +PG4,PG4 +PF6,PF6 +PF8,PF8 +PF7,PF7 +PF10,PF10 +PF9,PF9 +PH1,PH1 +PH0,PH0 +PC1,PC1 +PC0,PC0 +PC3,PC3 +PC2,PC2 +PA1,PA1 +PA0,PA0 +PA3,PA3 +PA2,PA2 +PA5,PA5 +PA4,PA4 +PA7,PA7 +PA6,PA6 +PC5,PC5 +PC4,PC4 +PB1,PB1 +PB0,PB0 +PB2,PB2 +PF12,PF12 +PF11,PF11 +PF14,PF14 +PF13,PF13 +PG0,PG0 +PF15,PF15 +PE7,PE7 +PG1,PG1 +PE9,PE9 +PE8,PE8 +PE11,PE11 +PE10,PE10 +PE13,PE13 +PE12,PE12 +PE15,PE15 +PE14,PE14 +PB11,PB11 +PB10,PB10 +PB13,PB13 +PB12,PB12 +PB15,PB15 +PB14,PB14 +PD9,PD9 +PD8,PD8 +PD11,PD11 +PD10,PD10 +PD13,PD13 +PD12,PD12 +PD15,PD15 +PD14,PD14 +PG3,PG3 +PG2,PG2 +SW,PA0 +LED_GREEN,PG13 +LED_RED,PG14 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..5b5a8a3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + + /* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h new file mode 100755 index 0000000..d801fa1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h @@ -0,0 +1,64 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F446RE" +#define MICROPY_HW_MCU_NAME "STM32F446xx" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) + +// HSE is 8MHz, CPU freq set to 168MHz. Using PLLQ for USB this gives a nice +// 48 MHz clock for USB. To goto 180 MHz, I think that USB would need to be +// configured to use PLLSAI +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +// UART 2 connects to the STM32F103 (STLINK) on the Nucleo board +// and this is exposed as a USB Serial port. +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) // Arduino D10, pin 17 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B7) // pin 21 on CN7 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_I2C3_SCL (pin_A8) // Arduino D7, pin 23 on CN10 +#define MICROPY_HW_I2C3_SDA (pin_C9) // pin 1 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 + +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +#define MICROPY_HW_SPI3_NSS (pin_A4) // Arduino A2, pin 32 on CN7 +#define MICROPY_HW_SPI3_SCK (pin_B3) // Arduino D3, pin 31 on CN10 +#define MICROPY_HW_SPI3_MISO (pin_B4) // Arduino D5, pin 27 on CN10 +#define MICROPY_HW_SPI3_MOSI (pin_B5) // Arduino D4, pin 29 on CN10 + +#define MICROPY_HW_SPI4_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI4_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI4_MISO (pin_A1) // pin 30 on CN7 +#define MICROPY_HW_SPI4_MOSI (pin_A11) // pin 14 on CN10 + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk new file mode 100755 index 0000000..64a80e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F446xx +AF_FILE = boards/stm32f429_af.csv +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/pins.csv new file mode 100755 index 0000000..5b09bcc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/pins.csv @@ -0,0 +1,72 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PH0,PH0 +PH1,PH1 +LED,PA5 +SW,PC13 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..245fb9a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +/* #define HAL_RNG_MODULE_ENABLED */ +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h new file mode 100755 index 0000000..a9fbea5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -0,0 +1,77 @@ +// This board is only confirmed to operate using DFU mode and openocd. +// DFU mode can be accessed by setting BOOT0 (see schematics) +// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in +// the make command. + +#define MICROPY_HW_BOARD_NAME "NUCLEO-F746ZG" +#define MICROPY_HW_MCU_NAME "STM32F746" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +// VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (216) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (9) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states + +// UART config +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART2_RTS (pin_D4) +#define MICROPY_HW_UART2_CTS (pin_D3) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk new file mode 100755 index 0000000..160218f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F746xx +AF_FILE = boards/stm32f746_af.csv +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/pins.csv new file mode 100755 index 0000000..aa5143e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/pins.csv @@ -0,0 +1,68 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PF3 +A4,PF5 +A5,PF10 +D0,PG9 +D1,PG14 +D2,PF15 +D3,PE13 +D4,PF14 +D5,PE11 +D6,PE9 +D7,PF13 +D8,PF12 +D9,PD15 +D10,PD14 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 +D22,PB5 +D23,PB3 +D24,PA4 +D25,PB4 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_SW,PC13 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +VCP_TX,PD8 +VCP_RX,PD9 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 +UART6_TX,PG14 +UART6_RX,PG9 +SPI_B_NSS,PA4 +SPI_B_SCK,PB3 +SPI_B_MOSI,PB5 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h new file mode 100755 index 0000000..a019ee4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/board_init.c new file mode 100755 index 0000000..7d25a44 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void NUCLEO_F767ZI_board_early_init(void) { + // Turn off the USB switch + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h new file mode 100755 index 0000000..3f23d77 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -0,0 +1,80 @@ +// This board is only confirmed to operate using DFU mode and openocd. +// DFU mode can be accessed by setting BOOT0 (see schematics) +// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in +// the make command. + +#define MICROPY_HW_BOARD_NAME "NUCLEO-F767ZI" +#define MICROPY_HW_MCU_NAME "STM32F767" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +#define MICROPY_BOARD_EARLY_INIT NUCLEO_F767ZI_board_early_init +void NUCLEO_F767ZI_board_early_init(void); + +// HSE is 25MHz +// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (216) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (9) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states + +// UART config +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART2_RTS (pin_D4) +#define MICROPY_HW_UART2_CTS (pin_D3) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk new file mode 100755 index 0000000..b79ee7d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F767xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32f767_af.csv +LD_FILES = boards/stm32f767.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/pins.csv new file mode 100755 index 0000000..3cae615 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -0,0 +1,72 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PF3 +A4,PF5 +A5,PF10 +A6,PB1 +A7,PC2 +A8,PF4 +D0,PG9 +D1,PG14 +D2,PF15 +D3,PE13 +D4,PF14 +D5,PE11 +D6,PE9 +D7,PF13 +D8,PF12 +D9,PD15 +D10,PD14 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 +D22,PB5 +D23,PB3 +D24,PA4 +D25,PB4 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_SW,PC13 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +USB_POWER,PG6 +VCP_TX,PD8 +VCP_RX,PD9 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 +UART6_TX,PG14 +UART6_RX,PG9 +SPI_B_NSS,PA4 +SPI_B_SCK,PB3 +SPI_B_MOSI,PB5 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h new file mode 100755 index 0000000..a019ee4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/board_init.c new file mode 100755 index 0000000..04149c3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void NUCLEO_H743ZI_board_early_init(void) { + // Turn off the USB switch + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h new file mode 100755 index 0000000..117e7f3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -0,0 +1,65 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI" +#define MICROPY_HW_MCU_NAME "STM32H743" + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_ADC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) + +#define MICROPY_BOARD_EARLY_INIT NUCLEO_H743ZI_board_early_init +void NUCLEO_H743ZI_board_early_init(void); + +// The board has an 8MHz HSE, the following gives 400MHz CPU speed +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (400) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLR (2) + +// 4 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// UART config +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_F1) +#define MICROPY_HW_I2C2_SDA (pin_F0) + +// SPI +//#define MICROPY_HW_SPI2_NSS (pin_I0) +//#define MICROPY_HW_SPI2_SCK (pin_I1) +//#define MICROPY_HW_SPI2_MISO (pin_B14) +//#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_G2) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk new file mode 100755 index 0000000..4d34554 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = h7 +CMSIS_MCU = STM32H743xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32h743_af.csv +LD_FILES = boards/stm32h743.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08040000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/pins.csv new file mode 100755 index 0000000..30910c4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -0,0 +1,63 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +DAC1,PA4 +DAC2,PA5 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 +EXT_RST,PG3 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PG2 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA8 +USB_DM,PA11 +USB_DP,PA12 +UART1_TX,PA9 +UART1_RX,PA10 +UART5_TX,PC12 +UART5_RX,PD2 +UART3_TX,PD8 +UART3_RX,PD9 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h new file mode 100755 index 0000000..97b141d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -0,0 +1,434 @@ +/** + ****************************************************************************** + * @file stm32h7xx_hal_conf_template.h + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32h7xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32H7xx_HAL_CONF_H +#define __STM32H7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_CRYP_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DFSDM_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_ETH_MODULE_ENABLED +#define HAL_FDCAN_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_HRTIM_MODULE_ENABLED +#define HAL_HSEM_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_JPEG_MODULE_ENABLED +#define HAL_LPTIM_MODULE_ENABLED +#define HAL_LTDC_MODULE_ENABLED +#define HAL_MDIOS_MODULE_ENABLED +#define HAL_MDMA_MODULE_ENABLED +#define HAL_MMC_MODULE_ENABLED +#define HAL_NAND_MODULE_ENABLED +#define HAL_NOR_MODULE_ENABLED +#define HAL_OPAMP_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_QSPI_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SAI_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPDIFRX_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_SRAM_MODULE_ENABLED +#define HAL_SWPMI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal oscillator (CSI) default value. + * This value is the default CSI value after Reset. + */ +#if !defined (CSI_VALUE) + #define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ + +/* ########################### Ethernet Configuration ######################### */ +#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */ +#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */ + +#define ETH_MAC_ADDR0 ((uint8_t)0x02) +#define ETH_MAC_ADDR1 ((uint8_t)0x00) +#define ETH_MAC_ADDR2 ((uint8_t)0x00) +#define ETH_MAC_ADDR3 ((uint8_t)0x00) +#define ETH_MAC_ADDR4 ((uint8_t)0x00) +#define ETH_MAC_ADDR5 ((uint8_t)0x00) + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## SPI peripheral configuration ########################## */ +/** + * @brief Used to activate CRC feature inside HAL SPI Driver + * Activated (1U): CRC code is compiled within HAL SPI driver + * Deactivated (0U): CRC code excluded from HAL SPI driver + */ + +#define USE_SPI_CRC 1U + + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32h7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32h7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32h7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32h7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32h7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32h7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32h7xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32h7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32h7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32h7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED + #include "stm32h7xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32h7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32h7xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32h7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32h7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32h7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32h7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HRTIM_MODULE_ENABLED + #include "stm32h7xx_hal_hrtim.h" +#endif /* HAL_HRTIM_MODULE_ENABLED */ + +#ifdef HAL_HSEM_MODULE_ENABLED + #include "stm32h7xx_hal_hsem.h" +#endif /* HAL_HSEM_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32h7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32h7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32h7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32h7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32h7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_JPEG_MODULE_ENABLED + #include "stm32h7xx_hal_jpeg.h" +#endif /* HAL_JPEG_MODULE_ENABLED */ + +#ifdef HAL_MDIOS_MODULE_ENABLED + #include "stm32h7xx_hal_mdios.h" +#endif /* HAL_MDIOS_MODULE_ENABLED */ + +#ifdef HAL_MDMA_MODULE_ENABLED + #include "stm32h7xx_hal_mdma.h" +#endif /* HAL_MDMA_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32h7xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32h7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32h7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32h7xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32h7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32h7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32h7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32h7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32h7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32h7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32h7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32h7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32h7xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32h7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32h7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32h7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32h7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32h7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32h7xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32h7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32h7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32h7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h new file mode 100755 index 0000000..0d5dab3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -0,0 +1,55 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-L476RG" +#define MICROPY_HW_MCU_NAME "STM32L476RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLR (2) +#define MICROPY_HW_CLK_PLLP (7) +#define MICROPY_HW_CLK_PLLQ (4) + +// UART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) + +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_C0) +#define MICROPY_HW_I2C3_SDA (pin_C1) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk new file mode 100755 index 0000000..38ae5af --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L476xx +AF_FILE = boards/stm32l476_af.csv +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/pins.csv new file mode 100755 index 0000000..035d933 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/pins.csv @@ -0,0 +1,76 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PH0,PH0 +PH1,PH1 +LED_GREEN,PA5 +LED_ORANGE,PA5 +LED_RED,PA5 +LED_BLUE,PA4 +SW,PC13 diff --git a/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h new file mode 100755 index 0000000..6bfb281 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 25-November-2015 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DFSDM_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_FIREWALL_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LCD_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_OPAMP_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/* #define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ + + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h new file mode 100755 index 0000000..a56f6f7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -0,0 +1,80 @@ +#define MICROPY_HW_BOARD_NAME "OLIMEX STM32-E407" +#define MICROPY_HW_MCU_NAME "STM32F407" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#if MICROPY_HW_HAS_SWITCH == 0 +// NOTE: A0 also connects to the user switch. To use UART4 you should +// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back +// of the board near the USER switch). +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#endif +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_C13) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C11) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk new file mode 100755 index 0000000..b154dcf --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F407xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/pins.csv new file mode 100755 index 0000000..81a9bcb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/pins.csv @@ -0,0 +1,86 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PC4,PC4 +PC5,PC5 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +LED_GREEN,PC13 +PC14,PC14 +PC15,PC15 +PH0,PH0 +PH1,PH1 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PA0,PA0 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..24cc922 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.h new file mode 100755 index 0000000..60a6980 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.h @@ -0,0 +1,84 @@ +#define MICROPY_HW_BOARD_NAME "PYBLITEv1.0" +#define MICROPY_HW_MCU_NAME "STM32F411RE" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// Pyboard lite has an optional 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_NAME "XA" +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C3_NAME "Y" +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_B8) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_B3) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The pyboard has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_B5) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk new file mode 100755 index 0000000..df95065 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F411xE +AF_FILE = boards/stm32f411_af.csv +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/pins.csv new file mode 100755 index 0000000..838587c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/pins.csv @@ -0,0 +1,60 @@ +X1,PA2 +X2,PA3 +X3,PA0 +X4,PA1 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +X13,Reset +X14,GND +X15,3.3V +X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +X23,A3.3V +X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB10 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PA8 +Y10,PB8 +Y11,PB0 +Y12,PB1 +Y13,Reset +Y14,GND +Y15,3.3V +Y16,VIN +SW,PB3 +LED_BLUE,PB4 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +MMA_AVDD,PA10 +MMA_INT,PB2 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PB5 +USB_VBUS,PA9 +USB_DM,PA11 +USB_DP,PA12 +USB_ID,PA10 +OSC32_IN,PC14 +OSC32_OUT,PC15 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..4e96f78 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.h new file mode 100755 index 0000000..3439f5a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -0,0 +1,102 @@ +#define MICROPY_HW_BOARD_NAME "PYBv1.0" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The pyboard has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// CAN busses +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_B3) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The pyboard has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_B5) diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV10/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/pins.csv new file mode 100755 index 0000000..cee80a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/pins.csv @@ -0,0 +1,59 @@ +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +X13,Reset +X14,GND +X15,3.3V +X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +X23,A3.3V +X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB8 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y12,PB1 +Y13,Reset +Y14,GND +Y15,3.3V +Y16,VIN +SW,PB3 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +LED_BLUE,PB4 +MMA_INT,PB2 +MMA_AVDD,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD,PA8 +SD_SW,PA8 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..4f18ac8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.h new file mode 100755 index 0000000..2c75d0e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -0,0 +1,102 @@ +#define MICROPY_HW_BOARD_NAME "PYBv1.1" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The pyboard has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// CAN busses +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_B3) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The pyboard has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_B5) diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV11/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/pins.csv new file mode 100755 index 0000000..cee80a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/pins.csv @@ -0,0 +1,59 @@ +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +X13,Reset +X14,GND +X15,3.3V +X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +X23,A3.3V +X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB8 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y12,PB1 +Y13,Reset +Y14,GND +Y15,3.3V +Y16,VIN +SW,PB3 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +LED_BLUE,PB4 +MMA_INT,PB2 +MMA_AVDD,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD,PA8 +SD_SW,PA8 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..24cc922 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.h new file mode 100755 index 0000000..3e457c5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -0,0 +1,92 @@ +#define MICROPY_HW_BOARD_NAME "PYBv3" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// The pyboard has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) +#define MICROPY_HW_UART3_RTS (pin_B14) +#define MICROPY_HW_UART3_CTS (pin_B13) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// X-skin: X9=PB6=SCL, X10=PB7=SDA +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) + +// Y-skin: Y9=PB10=SCL, Y10=PB11=SDA +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_A13) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// LEDs +#define MICROPY_HW_LED_INVERTED (1) // LEDs are on when pin is driven low +#define MICROPY_HW_LED1 (pin_A8) // R1 - red +#define MICROPY_HW_LED2 (pin_A10) // R2 - red +#define MICROPY_HW_LED3 (pin_C4) // G1 - green +#define MICROPY_HW_LED4 (pin_C5) // G2 - green +#define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 } +#define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) + +// USB VBUS detect pin +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_B5) diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV3/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/pins.csv new file mode 100755 index 0000000..1ddc3f5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/pins.csv @@ -0,0 +1,48 @@ +B13,PB13 +B14,PB14 +B15,PB15 +C6,PC6 +C7,PC7 +A13,PA13 +A14,PA14 +A15,PA15 +B3,PB3 +B4,PB4 +B6,PB6 +B7,PB7 +B8,PB8 +B9,PB9 +C0,PC0 +C1,PC1 +C2,PC2 +C3,PC3 +A0,PA0 +A1,PA1 +A2,PA2 +A3,PA3 +A4,PA4 +A5,PA5 +A6,PA6 +A7,PA7 +B0,PB0 +B1,PB1 +B10,PB10 +B11,PB11 +B12,PB12 +LED_R1,PA8 +LED_R2,PA10 +LED_G1,PC4 +LED_G2,PC5 +SW,PA13 +SD,PC13 +MMA_INT,PB2 +MMA_AVDD,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CK,PC12 +SD_CMD,PD2 +UART1_TX,PA9 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..daf9b63 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.h new file mode 100755 index 0000000..8c05644 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -0,0 +1,99 @@ +#define MICROPY_HW_BOARD_NAME "PYBv4" +#define MICROPY_HW_MCU_NAME "STM32F405RG" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_HAS_MMA7660 (1) +#define MICROPY_HW_HAS_LCD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_SERVO (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// The pyboard has a 32kHz crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (1) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_PORT (GPIOB) +#define MICROPY_HW_UART1_PINS (GPIO_PIN_6 | GPIO_PIN_7) +#define MICROPY_HW_UART2_PORT (GPIOA) +#define MICROPY_HW_UART2_PINS (GPIO_PIN_2 | GPIO_PIN_3) +#define MICROPY_HW_UART2_RTS (GPIO_PIN_1) +#define MICROPY_HW_UART2_CTS (GPIO_PIN_0) +#define MICROPY_HW_UART3_NAME "YB" +#define MICROPY_HW_UART3_PORT (GPIOB) +#define MICROPY_HW_UART3_PINS (GPIO_PIN_10 | GPIO_PIN_11) +#define MICROPY_HW_UART3_RTS (GPIO_PIN_14) +#define MICROPY_HW_UART3_CTS (GPIO_PIN_13) +#define MICROPY_HW_UART4_NAME "XA" +#define MICROPY_HW_UART4_PORT (GPIOA) +#define MICROPY_HW_UART4_PINS (GPIO_PIN_0 | GPIO_PIN_1) +#define MICROPY_HW_UART6_NAME "YA" +#define MICROPY_HW_UART6_PORT (GPIOC) +#define MICROPY_HW_UART6_PINS (GPIO_PIN_6 | GPIO_PIN_7) + +// I2C busses +#define MICROPY_HW_I2C1_NAME "X" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // X5 +#define MICROPY_HW_SPI1_SCK (pin_A5) // X6 +#define MICROPY_HW_SPI1_MISO (pin_A6) // X7 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // X8 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // Y5 +#define MICROPY_HW_SPI2_SCK (pin_B13) // Y6 +#define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 + +// CAN busses +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_B3) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// The pyboard has 4 LEDs +#define MICROPY_HW_LED1 (pin_A13) // red +#define MICROPY_HW_LED2 (pin_A14) // green +#define MICROPY_HW_LED3 (pin_A15) // yellow +#define MICROPY_HW_LED4 (pin_B4) // blue +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// MMA accelerometer config +#define MICROPY_HW_MMA_AVDD_PIN (pin_B5) diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.mk new file mode 100755 index 0000000..40972b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F405xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV4/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/pins.csv new file mode 100755 index 0000000..cee80a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/pins.csv @@ -0,0 +1,59 @@ +X1,PA0 +X2,PA1 +X3,PA2 +X4,PA3 +X5,PA4 +X6,PA5 +X7,PA6 +X8,PA7 +X9,PB6 +X10,PB7 +X11,PC4 +X12,PC5 +X13,Reset +X14,GND +X15,3.3V +X16,VIN +X17,PB3 +X18,PC13 +X19,PC0 +X20,PC1 +X21,PC2 +X22,PC3 +X23,A3.3V +X24,AGND +Y1,PC6 +Y2,PC7 +Y3,PB8 +Y4,PB9 +Y5,PB12 +Y6,PB13 +Y7,PB14 +Y8,PB15 +Y9,PB10 +Y10,PB11 +Y11,PB0 +Y12,PB1 +Y13,Reset +Y14,GND +Y15,3.3V +Y16,VIN +SW,PB3 +LED_RED,PA13 +LED_GREEN,PA14 +LED_YELLOW,PA15 +LED_BLUE,PB4 +MMA_INT,PB2 +MMA_AVDD,PB5 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD,PA8 +SD_SW,PA8 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..daf9b63 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.h new file mode 100755 index 0000000..1317233 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.h @@ -0,0 +1,64 @@ +#define MICROPY_HW_BOARD_NAME "F411DISC" +#define MICROPY_HW_MCU_NAME "STM32F411" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (5) +#define MICROPY_HW_CLK_PLLN (210) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (7) + +// does not have a 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (0) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B9) +//#define MICROPY_HW_I2C2_SCL (pin_B10) +//#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_A9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_D14) // red +#define MICROPY_HW_LED2 (pin_D12) // green +#define MICROPY_HW_LED3 (pin_D13) // orange +#define MICROPY_HW_LED4 (pin_D15) // blue +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk new file mode 100755 index 0000000..df95065 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F411xE +AF_FILE = boards/stm32f411_af.csv +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/pins.csv new file mode 100755 index 0000000..a747aef --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/pins.csv @@ -0,0 +1,86 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PC4,PC4 +PC5,PC5 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PH0,PH0 +PH1,PH1 +LED_GREEN,PD12 +LED_ORANGE,PD13 +LED_RED,PD14 +LED_BLUE,PD15 +SW,PA0 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..8f0b663 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.h new file mode 100755 index 0000000..3d04f65 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -0,0 +1,141 @@ +#define MICROPY_HW_BOARD_NAME "F429I-DISCO" +#define MICROPY_HW_MCU_NAME "STM32F429" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_D8) +#define MICROPY_HW_UART2_RX (pin_D9) + +// I2C busses +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI busses +//#define MICROPY_HW_SPI1_NSS (pin_A4) +//#define MICROPY_HW_SPI1_SCK (pin_A5) +//#define MICROPY_HW_SPI1_MISO (pin_A6) +//#define MICROPY_HW_SPI1_MOSI (pin_A7) +#if defined(USE_USB_HS_IN_FS) +// The HS USB uses B14 & B15 for D- and D+ +#else +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) +#endif +//#define MICROPY_HW_SPI4_NSS (pin_E11) +//#define MICROPY_HW_SPI4_SCK (pin_E12) +//#define MICROPY_HW_SPI4_MISO (pin_E13) +//#define MICROPY_HW_SPI4_MOSI (pin_E14) +#define MICROPY_HW_SPI5_NSS (pin_F6) +#define MICROPY_HW_SPI5_SCK (pin_F7) +#define MICROPY_HW_SPI5_MISO (pin_F8) +#define MICROPY_HW_SPI5_MOSI (pin_F9) +//#define MICROPY_HW_SPI6_NSS (pin_G8) +//#define MICROPY_HW_SPI6_SCK (pin_G13) +//#define MICROPY_HW_SPI6_MISO (pin_G12) +//#define MICROPY_HW_SPI6_MOSI (pin_G14) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_G14) // red +#define MICROPY_HW_LED2 (pin_G13) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_B12) + +// SDRAM +#define MICROPY_HW_SDRAM_SIZE (64 / 8 * 1024 * 1024) // 64 Mbit +#define MICROPY_HW_SDRAM_STARTUP_TEST (1) +#define MICROPY_HEAP_START sdram_start() +#define MICROPY_HEAP_END sdram_end() + +// Timing configuration for 90 Mhz (11.90ns) of SD clock frequency (180Mhz/2) +#define MICROPY_HW_SDRAM_TIMING_TMRD (2) +#define MICROPY_HW_SDRAM_TIMING_TXSR (7) +#define MICROPY_HW_SDRAM_TIMING_TRAS (4) +#define MICROPY_HW_SDRAM_TIMING_TRC (7) +#define MICROPY_HW_SDRAM_TIMING_TWR (2) +#define MICROPY_HW_SDRAM_TIMING_TRP (2) +#define MICROPY_HW_SDRAM_TIMING_TRCD (2) +#define MICROPY_HW_SDRAM_REFRESH_RATE (64) // ms + +#define MICROPY_HW_SDRAM_BURST_LENGTH 2 +#define MICROPY_HW_SDRAM_CAS_LATENCY 3 +#define MICROPY_HW_SDRAM_COLUMN_BITS_NUM 8 +#define MICROPY_HW_SDRAM_ROW_BITS_NUM 12 +#define MICROPY_HW_SDRAM_MEM_BUS_WIDTH 16 +#define MICROPY_HW_SDRAM_INTERN_BANKS_NUM 4 +#define MICROPY_HW_SDRAM_CLOCK_PERIOD 2 +#define MICROPY_HW_SDRAM_RPIPE_DELAY 1 +#define MICROPY_HW_SDRAM_RBURST (0) +#define MICROPY_HW_SDRAM_WRITE_PROTECTION (0) +#define MICROPY_HW_SDRAM_AUTOREFRESH_NUM (4) + +#define MICROPY_HW_FMC_SDCKE1 (pin_B5) +#define MICROPY_HW_FMC_SDNE1 (pin_B6) +#define MICROPY_HW_FMC_SDCLK (pin_G8) +#define MICROPY_HW_FMC_SDNCAS (pin_G15) +#define MICROPY_HW_FMC_SDNRAS (pin_F11) +#define MICROPY_HW_FMC_SDNWE (pin_C0) +#define MICROPY_HW_FMC_BA0 (pin_G4) +#define MICROPY_HW_FMC_BA1 (pin_G5) +#define MICROPY_HW_FMC_NBL0 (pin_E0) +#define MICROPY_HW_FMC_NBL1 (pin_E1) +#define MICROPY_HW_FMC_A0 (pin_F0) +#define MICROPY_HW_FMC_A1 (pin_F1) +#define MICROPY_HW_FMC_A2 (pin_F2) +#define MICROPY_HW_FMC_A3 (pin_F3) +#define MICROPY_HW_FMC_A4 (pin_F4) +#define MICROPY_HW_FMC_A5 (pin_F5) +#define MICROPY_HW_FMC_A6 (pin_F12) +#define MICROPY_HW_FMC_A7 (pin_F13) +#define MICROPY_HW_FMC_A8 (pin_F14) +#define MICROPY_HW_FMC_A9 (pin_F15) +#define MICROPY_HW_FMC_A10 (pin_G0) +#define MICROPY_HW_FMC_A11 (pin_G1) +#define MICROPY_HW_FMC_D0 (pin_D14) +#define MICROPY_HW_FMC_D1 (pin_D15) +#define MICROPY_HW_FMC_D2 (pin_D0) +#define MICROPY_HW_FMC_D3 (pin_D1) +#define MICROPY_HW_FMC_D4 (pin_E7) +#define MICROPY_HW_FMC_D5 (pin_E8) +#define MICROPY_HW_FMC_D6 (pin_E9) +#define MICROPY_HW_FMC_D7 (pin_E10) +#define MICROPY_HW_FMC_D8 (pin_E11) +#define MICROPY_HW_FMC_D9 (pin_E12) +#define MICROPY_HW_FMC_D10 (pin_E13) +#define MICROPY_HW_FMC_D11 (pin_E14) +#define MICROPY_HW_FMC_D12 (pin_E15) +#define MICROPY_HW_FMC_D13 (pin_D8) +#define MICROPY_HW_FMC_D14 (pin_D9) +#define MICROPY_HW_FMC_D15 (pin_D10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk new file mode 100755 index 0000000..d19a35c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F429xx +AF_FILE = boards/stm32f429_af.csv +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/pins.csv new file mode 100755 index 0000000..8a892d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/pins.csv @@ -0,0 +1,117 @@ +PF4,PF4 +PF5,PF5 +PF2,PF2 +PF3,PF3 +PF0,PF0 +PF1,PF1 +PC14,PC14 +PC15,PC15 +PE6,PE6 +PC13,PC13 +PE4,PE4 +PE5,PE5 +PE2,PE2 +PE3,PE3 +PE0,PE0 +PE1,PE1 +PB8,PB8 +PB9,PB9 +PB6,PB6 +PB7,PB7 +PB4,PB4 +PB5,PB5 +PG15,PG15 +PB3,PB3 +PG13,PG13 +PG14,PG14 +PG11,PG11 +PG12,PG12 +PG9,PG9 +PG10,PG10 +PD7,PD7 +PD6,PD6 +PD5,PD5 +PD4,PD4 +PD3,PD3 +PD2,PD2 +PD1,PD1 +PD0,PD0 +PC12,PC12 +PC11,PC11 +PC10,PC10 +PA15,PA15 +PA14,PA14 +PA13,PA13 +PA12,PA12 +PA11,PA11 +PA10,PA10 +PA9,PA9 +PA8,PA8 +PC9,PC9 +PC8,PC8 +PC7,PC7 +PC6,PC6 +PG8,PG8 +PG7,PG7 +PG6,PG6 +PG5,PG5 +PG4,PG4 +PF6,PF6 +PF8,PF8 +PF7,PF7 +PF10,PF10 +PF9,PF9 +PH1,PH1 +PH0,PH0 +PC1,PC1 +PC0,PC0 +PC3,PC3 +PC2,PC2 +PA1,PA1 +PA0,PA0 +PA3,PA3 +PA2,PA2 +PA5,PA5 +PA4,PA4 +PA7,PA7 +PA6,PA6 +PC5,PC5 +PC4,PC4 +PB1,PB1 +PB0,PB0 +PB2,PB2 +PF12,PF12 +PF11,PF11 +PF14,PF14 +PF13,PF13 +PG0,PG0 +PF15,PF15 +PE7,PE7 +PG1,PG1 +PE9,PE9 +PE8,PE8 +PE11,PE11 +PE10,PE10 +PE13,PE13 +PE12,PE12 +PE15,PE15 +PE14,PE14 +PB11,PB11 +PB10,PB10 +PB13,PB13 +PB12,PB12 +PB15,PB15 +PB14,PB14 +PD9,PD9 +PD8,PD8 +PD11,PD11 +PD10,PD10 +PD13,PD13 +PD12,PD12 +PD15,PD15 +PD14,PD14 +PG3,PG3 +PG2,PG2 +SW,PA0 +LED_GREEN,PG13 +LED_RED,PG14 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..ec70793 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + + /* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_SDRAM_MODULE_ENABLED +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.h new file mode 100755 index 0000000..4ac5b32 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -0,0 +1,88 @@ +#define MICROPY_HW_BOARD_NAME "CustomPCB" +#define MICROPY_HW_MCU_NAME "STM32F439" + +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) //works with no SD card too +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// SD card detect switch +#if MICROPY_HW_HAS_SDCARD +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (1) +#endif + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) //divide external clock by this to get 1MHz +#define MICROPY_HW_CLK_PLLN (384) //this number is the PLL clock in MHz +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) //divide PLL clock by this to get core clock +#define MICROPY_HW_CLK_PLLQ (8) //divide core clock by this to get 48MHz + +// USB config +#define MICROPY_HW_USB_FS (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART2_RTS (pin_D1) +#define MICROPY_HW_UART2_CTS (pin_D0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_A8) +#define MICROPY_HW_I2C1_SDA (pin_C9) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#if MICROPY_HW_USB_HS_IN_FS +// The HS USB uses B14 & B15 for D- and D+ +#else +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) +#endif +#define MICROPY_HW_SPI3_NSS (pin_E11) +#define MICROPY_HW_SPI3_SCK (pin_E12) +#define MICROPY_HW_SPI3_MISO (pin_E13) +#define MICROPY_HW_SPI3_MOSI (pin_E14) +//#define MICROPY_HW_SPI4_NSS (pin_E11) +//#define MICROPY_HW_SPI4_SCK (pin_E12) +//#define MICROPY_HW_SPI4_MISO (pin_E13) +//#define MICROPY_HW_SPI4_MOSI (pin_E14) +//#define MICROPY_HW_SPI5_NSS (pin_F6) +//#define MICROPY_HW_SPI5_SCK (pin_F7) +//#define MICROPY_HW_SPI5_MISO (pin_F8) +//#define MICROPY_HW_SPI5_MOSI (pin_F9) +//#define MICROPY_HW_SPI6_NSS (pin_G8) +//#define MICROPY_HW_SPI6_SCK (pin_G13) +//#define MICROPY_HW_SPI6_MISO (pin_G12) +//#define MICROPY_HW_SPI6_MOSI (pin_G14) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.mk new file mode 100755 index 0000000..ca97acb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F439xx +AF_FILE = boards/stm32f439_af.csv +LD_FILES = boards/stm32f439.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F439/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/pins.csv new file mode 100755 index 0000000..cc9443d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/pins.csv @@ -0,0 +1,85 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +VUSB,PB13 +USB1D_N,PB14 +USB1D_P,PB15 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PD2,PD2 +BOOT0,BOOT0 +PA15,PA15 +PA13,PA13 +PA14,PA14 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..5b5a8a3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + + /* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.h new file mode 100755 index 0000000..3e4c826 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -0,0 +1,85 @@ +#define MICROPY_HW_BOARD_NAME "F4DISC" +#define MICROPY_HW_MCU_NAME "STM32F407" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +#define MICROPY_HW_CLK_PLLM (8) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (7) + +// UART config +#if 0 +// A9 is used for USB VBUS detect, and A10 is used for USB_FS_ID. +// UART1 is also on PB6/7 but PB6 is tied to the Audio SCL line. +// Without board modifications, this makes UART1 unusable on this board. +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#endif +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) +#define MICROPY_HW_UART2_RTS (pin_A1) +#define MICROPY_HW_UART2_CTS (pin_A0) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) +#if MICROPY_HW_HAS_SWITCH == 0 +// NOTE: A0 also connects to the user switch. To use UART4 you should +// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back +// of the board near the USER switch). +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#endif +// NOTE: PC7 is connected to MCLK on the Audio chip. This is an input signal +// so I think as long as you're not using the audio chip then it should +// be fine to use as a UART pin. +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) +#define MICROPY_HW_SPI2_NSS (pin_B12) +#define MICROPY_HW_SPI2_SCK (pin_B13) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_D14) // red +#define MICROPY_HW_LED2 (pin_D12) // green +#define MICROPY_HW_LED3 (pin_D13) // orange +#define MICROPY_HW_LED4 (pin_D15) // blue +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk new file mode 100755 index 0000000..b154dcf --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F407xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/pins.csv new file mode 100755 index 0000000..a747aef --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/pins.csv @@ -0,0 +1,86 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PC4,PC4 +PC5,PC5 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PH0,PH0 +PH1,PH1 +LED_GREEN,PD12 +LED_ORANGE,PD13 +LED_RED,PD14 +LED_BLUE,PD15 +SW,PA0 +USB_DM,PA11 +USB_DP,PA12 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/staccel.py b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/staccel.py new file mode 100755 index 0000000..2f2561d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/staccel.py @@ -0,0 +1,98 @@ +""" +Driver for accelerometer on STM32F4 Discover board. + +Sets accelerometer range at +-2g. +Returns list containing X,Y,Z axis acceleration values in 'g' units (9.8m/s^2). + +See: + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/Components/lis302dl/lis302dl.h + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/Components/lis302dl/lis302dl.c + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery.c + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery.h + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery_accelerometer.c + STM32Cube_FW_F4_V1.1.0/Drivers/BSP/STM32F4-Discovery/stm32f4_discovery_accelerometer.h + STM32Cube_FW_F4_V1.1.0/Projects/STM32F4-Discovery/Demonstrations/Src/main.c +""" + +from micropython import const +from pyb import Pin +from pyb import SPI + +READWRITE_CMD = const(0x80) +MULTIPLEBYTE_CMD = const(0x40) +WHO_AM_I_ADDR = const(0x0f) +OUT_X_ADDR = const(0x29) +OUT_Y_ADDR = const(0x2b) +OUT_Z_ADDR = const(0x2d) +OUT_T_ADDR = const(0x0c) + +LIS302DL_WHO_AM_I_VAL = const(0x3b) +LIS302DL_CTRL_REG1_ADDR = const(0x20) +# Configuration for 100Hz sampling rate, +-2g range +LIS302DL_CONF = const(0b01000111) + +LIS3DSH_WHO_AM_I_VAL = const(0x3f) +LIS3DSH_CTRL_REG4_ADDR = const(0x20) +LIS3DSH_CTRL_REG5_ADDR = const(0x24) +# Configuration for 100Hz sampling rate, +-2g range +LIS3DSH_CTRL_REG4_CONF = const(0b01100111) +LIS3DSH_CTRL_REG5_CONF = const(0b00000000) + +class STAccel: + def __init__(self): + self.cs_pin = Pin('PE3', Pin.OUT_PP, Pin.PULL_NONE) + self.cs_pin.high() + self.spi = SPI(1, SPI.MASTER, baudrate=328125, polarity=0, phase=1, bits=8) + + self.who_am_i = self.read_id() + + if self.who_am_i == LIS302DL_WHO_AM_I_VAL: + self.write_bytes(LIS302DL_CTRL_REG1_ADDR, bytearray([LIS302DL_CONF])) + self.sensitivity = 18 + elif self.who_am_i == LIS3DSH_WHO_AM_I_VAL: + self.write_bytes(LIS3DSH_CTRL_REG4_ADDR, bytearray([LIS3DSH_CTRL_REG4_CONF])) + self.write_bytes(LIS3DSH_CTRL_REG5_ADDR, bytearray([LIS3DSH_CTRL_REG5_CONF])) + self.sensitivity = 0.06 * 256 + else: + raise Exception('LIS302DL or LIS3DSH accelerometer not present') + + def convert_raw_to_g(self, x): + if x & 0x80: + x = x - 256 + return x * self.sensitivity / 1000 + + def read_bytes(self, addr, nbytes): + if nbytes > 1: + addr |= READWRITE_CMD | MULTIPLEBYTE_CMD + else: + addr |= READWRITE_CMD + self.cs_pin.low() + self.spi.send(addr) + #buf = self.spi.send_recv(bytearray(nbytes * [0])) # read data, MSB first + buf = self.spi.recv(nbytes) + self.cs_pin.high() + return buf + + def write_bytes(self, addr, buf): + if len(buf) > 1: + addr |= MULTIPLEBYTE_CMD + self.cs_pin.low() + self.spi.send(addr) + for b in buf: + self.spi.send(b) + self.cs_pin.high() + + def read_id(self): + return self.read_bytes(WHO_AM_I_ADDR, 1)[0] + + def x(self): + return self.convert_raw_to_g(self.read_bytes(OUT_X_ADDR, 1)[0]) + + def y(self): + return self.convert_raw_to_g(self.read_bytes(OUT_Y_ADDR, 1)[0]) + + def z(self): + return self.convert_raw_to_g(self.read_bytes(OUT_Z_ADDR, 1)[0]) + + def xyz(self): + return (self.x(), self.y(), self.z()) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h new file mode 100755 index 0000000..daf9b63 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h @@ -0,0 +1,409 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf.h + * @author MCD Application Team + * @version V1.1.0 + * @date 19-June-2014 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 0 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.h new file mode 100755 index 0000000..d31a22b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -0,0 +1,169 @@ +// This board is confirmed to operate using stlink and openocd. +// REPL is on UART(1) and is available through the stlink USB-UART device. +// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in +// the make command. +#define MICROPY_HW_BOARD_NAME "F769DISC" +#define MICROPY_HW_MCU_NAME "STM32F769" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 25MHz +// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +#define MICROPY_HW_CLK_PLLM (25) +#define MICROPY_HW_CLK_PLLN (432) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (9) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART5_TX (pin_C12) +#define MICROPY_HW_UART5_RX (pin_D2) +#define MICROPY_HW_UART_REPL PYB_UART_1 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI2_NSS (pin_A11) +#define MICROPY_HW_SPI2_SCK (pin_A12) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_J13) // red +#define MICROPY_HW_LED2 (pin_J5) // green +#define MICROPY_HW_LED3 (pin_A12) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDMMC2_CK (pin_D6) +#define MICROPY_HW_SDMMC2_CMD (pin_D7) +#define MICROPY_HW_SDMMC2_D0 (pin_G9) +#define MICROPY_HW_SDMMC2_D1 (pin_G10) +#define MICROPY_HW_SDMMC2_D2 (pin_B3) +#define MICROPY_HW_SDMMC2_D3 (pin_B4) +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_I15) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) +/*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ +#define MICROPY_HW_USB_OTG_ID_PIN (pin_J12) + +#if 0 +// Optional SDRAM configuration; requires SYSCLK <= 200MHz +#define MICROPY_HW_SDRAM_SIZE (128 * 1024 * 1024 / 8) // 128 Mbit +#define MICROPY_HW_SDRAM_STARTUP_TEST (0) +#define MICROPY_HEAP_START sdram_start() +#define MICROPY_HEAP_END sdram_end() + +// Timing configuration for 90 Mhz (11.90ns) of SD clock frequency (180Mhz/2) +#define MICROPY_HW_SDRAM_TIMING_TMRD (2) +#define MICROPY_HW_SDRAM_TIMING_TXSR (7) +#define MICROPY_HW_SDRAM_TIMING_TRAS (4) +#define MICROPY_HW_SDRAM_TIMING_TRC (7) +#define MICROPY_HW_SDRAM_TIMING_TWR (2) +#define MICROPY_HW_SDRAM_TIMING_TRP (2) +#define MICROPY_HW_SDRAM_TIMING_TRCD (2) +#define MICROPY_HW_SDRAM_REFRESH_RATE (64) // ms + +#define MICROPY_HW_SDRAM_BURST_LENGTH 1 +#define MICROPY_HW_SDRAM_CAS_LATENCY 2 +#define MICROPY_HW_SDRAM_COLUMN_BITS_NUM 8 +#define MICROPY_HW_SDRAM_ROW_BITS_NUM 13 +#define MICROPY_HW_SDRAM_MEM_BUS_WIDTH 32 +#define MICROPY_HW_SDRAM_INTERN_BANKS_NUM 4 +#define MICROPY_HW_SDRAM_CLOCK_PERIOD 2 +#define MICROPY_HW_SDRAM_RPIPE_DELAY 0 +#define MICROPY_HW_SDRAM_RBURST (1) +#define MICROPY_HW_SDRAM_WRITE_PROTECTION (0) +#define MICROPY_HW_SDRAM_AUTOREFRESH_NUM (8) + +// See pins.csv for CPU pin mapping +#define MICROPY_HW_FMC_SDCKE0 (pyb_pin_FMC_SDCKE0) +#define MICROPY_HW_FMC_SDNE0 (pyb_pin_FMC_SDNE0) +#define MICROPY_HW_FMC_SDCLK (pyb_pin_FMC_SDCLK) +#define MICROPY_HW_FMC_SDNCAS (pyb_pin_FMC_SDNCAS) +#define MICROPY_HW_FMC_SDNRAS (pyb_pin_FMC_SDNRAS) +#define MICROPY_HW_FMC_SDNWE (pyb_pin_FMC_SDNWE) +#define MICROPY_HW_FMC_BA0 (pyb_pin_FMC_BA0) +#define MICROPY_HW_FMC_BA1 (pyb_pin_FMC_BA1) +#define MICROPY_HW_FMC_NBL0 (pyb_pin_FMC_NBL0) +#define MICROPY_HW_FMC_NBL1 (pyb_pin_FMC_NBL1) +#define MICROPY_HW_FMC_NBL2 (pyb_pin_FMC_NBL2) +#define MICROPY_HW_FMC_NBL3 (pyb_pin_FMC_NBL3) +#define MICROPY_HW_FMC_A0 (pyb_pin_FMC_A0) +#define MICROPY_HW_FMC_A1 (pyb_pin_FMC_A1) +#define MICROPY_HW_FMC_A2 (pyb_pin_FMC_A2) +#define MICROPY_HW_FMC_A3 (pyb_pin_FMC_A3) +#define MICROPY_HW_FMC_A4 (pyb_pin_FMC_A4) +#define MICROPY_HW_FMC_A5 (pyb_pin_FMC_A5) +#define MICROPY_HW_FMC_A6 (pyb_pin_FMC_A6) +#define MICROPY_HW_FMC_A7 (pyb_pin_FMC_A7) +#define MICROPY_HW_FMC_A8 (pyb_pin_FMC_A8) +#define MICROPY_HW_FMC_A9 (pyb_pin_FMC_A9) +#define MICROPY_HW_FMC_A10 (pyb_pin_FMC_A10) +#define MICROPY_HW_FMC_A11 (pyb_pin_FMC_A11) +#define MICROPY_HW_FMC_A12 (pyb_pin_FMC_A12) +#define MICROPY_HW_FMC_D0 (pyb_pin_FMC_D0) +#define MICROPY_HW_FMC_D1 (pyb_pin_FMC_D1) +#define MICROPY_HW_FMC_D2 (pyb_pin_FMC_D2) +#define MICROPY_HW_FMC_D3 (pyb_pin_FMC_D3) +#define MICROPY_HW_FMC_D4 (pyb_pin_FMC_D4) +#define MICROPY_HW_FMC_D5 (pyb_pin_FMC_D5) +#define MICROPY_HW_FMC_D6 (pyb_pin_FMC_D6) +#define MICROPY_HW_FMC_D7 (pyb_pin_FMC_D7) +#define MICROPY_HW_FMC_D8 (pyb_pin_FMC_D8) +#define MICROPY_HW_FMC_D9 (pyb_pin_FMC_D9) +#define MICROPY_HW_FMC_D10 (pyb_pin_FMC_D10) +#define MICROPY_HW_FMC_D11 (pyb_pin_FMC_D11) +#define MICROPY_HW_FMC_D12 (pyb_pin_FMC_D12) +#define MICROPY_HW_FMC_D13 (pyb_pin_FMC_D13) +#define MICROPY_HW_FMC_D14 (pyb_pin_FMC_D14) +#define MICROPY_HW_FMC_D15 (pyb_pin_FMC_D15) +#define MICROPY_HW_FMC_D16 (pyb_pin_FMC_D16) +#define MICROPY_HW_FMC_D17 (pyb_pin_FMC_D17) +#define MICROPY_HW_FMC_D18 (pyb_pin_FMC_D18) +#define MICROPY_HW_FMC_D19 (pyb_pin_FMC_D19) +#define MICROPY_HW_FMC_D20 (pyb_pin_FMC_D20) +#define MICROPY_HW_FMC_D21 (pyb_pin_FMC_D21) +#define MICROPY_HW_FMC_D22 (pyb_pin_FMC_D22) +#define MICROPY_HW_FMC_D23 (pyb_pin_FMC_D23) +#define MICROPY_HW_FMC_D24 (pyb_pin_FMC_D24) +#define MICROPY_HW_FMC_D25 (pyb_pin_FMC_D25) +#define MICROPY_HW_FMC_D26 (pyb_pin_FMC_D26) +#define MICROPY_HW_FMC_D27 (pyb_pin_FMC_D27) +#define MICROPY_HW_FMC_D28 (pyb_pin_FMC_D28) +#define MICROPY_HW_FMC_D29 (pyb_pin_FMC_D29) +#define MICROPY_HW_FMC_D30 (pyb_pin_FMC_D30) +#define MICROPY_HW_FMC_D31 (pyb_pin_FMC_D31) +#endif diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk new file mode 100755 index 0000000..873368c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F769xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32f767_af.csv +LD_FILES = boards/stm32f769.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/pins.csv new file mode 100755 index 0000000..6b6308c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/pins.csv @@ -0,0 +1,116 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +LED1,PJ13 +LED2,PJ5 +LED3,PA12 +SW,PI11 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_D0,PG9 +SD_D1,PG10 +SD_D2,PB3 +SD_D3,PB4 +SD_CK,PD6 +SD_CMD,PD7 +SD_SW,PI15 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA8 +USB_DM,PA11 +USB_DP,PA12 +UART1_TX,PA9 +UART1_RX,PA10 +UART5_TX,PC12 +UART5_RX,PD2 +CAN2_TX,PB13 +CAN2_RX,PB12 +FMC_SDCKE0,PH2 +FMC_SDNE0,PH3 +FMC_SDCLK,PG8 +FMC_SDNCAS,PG15 +FMC_SDNRAS,PF11 +FMC_SDNWE,PH5 +FMC_BA0,PG4 +FMC_BA1,PG5 +FMC_NBL0,PE0 +FMC_NBL1,PE1 +FMC_NBL2,PI4 +FMC_NBL3,PI5 +FMC_A0,PF0 +FMC_A1,PF1 +FMC_A2,PF2 +FMC_A3,PF3 +FMC_A4,PF4 +FMC_A5,PF5 +FMC_A6,PF12 +FMC_A7,PF13 +FMC_A8,PF14 +FMC_A9,PF15 +FMC_A10,PG0 +FMC_A11,PG1 +FMC_A12,PG2 +FMC_D0,PD14 +FMC_D1,PD15 +FMC_D2,PD0 +FMC_D3,PD1 +FMC_D4,PE7 +FMC_D5,PE8 +FMC_D6,PE9 +FMC_D7,PE10 +FMC_D8,PE11 +FMC_D9,PE12 +FMC_D10,PE13 +FMC_D11,PE14 +FMC_D12,PE15 +FMC_D13,PD8 +FMC_D14,PD9 +FMC_D15,PD10 +FMC_D16,PH8 +FMC_D17,PH9 +FMC_D18,PH10 +FMC_D19,PH11 +FMC_D20,PH12 +FMC_D21,PH13 +FMC_D22,PH14 +FMC_D23,PH15 +FMC_D24,PI0 +FMC_D25,PI1 +FMC_D26,PI2 +FMC_D27,PI3 +FMC_D28,PI6 +FMC_D29,PI7 +FMC_D30,PI9 +FMC_D31,PI10 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h new file mode 100755 index 0000000..1593390 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_SDRAM_MODULE_ENABLED +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/board_init.c new file mode 100755 index 0000000..dd268fb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/board_init.c @@ -0,0 +1,15 @@ +#include STM32_HAL_H + +void STM32F7DISC_board_early_init(void) { + GPIO_InitTypeDef GPIO_InitStructure; + + __HAL_RCC_GPIOK_CLK_ENABLE(); + + // Turn off the backlight. LCD_BL_CTRL = PK3 + GPIO_InitStructure.Pin = GPIO_PIN_3; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOK, &GPIO_InitStructure); + HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET); +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.h new file mode 100755 index 0000000..792206c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -0,0 +1,149 @@ +#define MICROPY_HW_BOARD_NAME "F7DISC" +#define MICROPY_HW_MCU_NAME "STM32F746" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +#define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init +void STM32F7DISC_board_early_init(void); + +// HSE is 25MHz +// VCOClock = HSE * PLLN / PLLM = 25 MHz * 384 / 25 = 384 MHz +// SYSCLK = VCOClock / PLLP = 384 MHz / 2 = 192 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 384 MHz / 8 = 48 MHz +// Note: SDRAM requires SYSCLK <= 200MHz +// SYSCLK can be increased to 216MHz if SDRAM is disabled +#define MICROPY_HW_CLK_PLLM (25) +#define MICROPY_HW_CLK_PLLN (384) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (8) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 // 181-210 MHz => 6 wait states + +// UART config +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +#define MICROPY_HW_UART7_TX (pin_F6) +#define MICROPY_HW_UART7_RX (pin_F7) +#define MICROPY_HW_UART_REPL PYB_UART_1 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) + +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI2_NSS (pin_I0) +#define MICROPY_HW_SPI2_SCK (pin_I1) +#define MICROPY_HW_SPI2_MISO (pin_B14) +#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_I11) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_I1) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +// USB config (CN13 - USB OTG FS) +// The Hardware VBUS detect only works on pin PA9. The STM32F7 Discovery uses +// PA9 for VCP_TX functionality and connects the VBUS to pin J12 (so software +// only detect). So we don't define the VBUS detect pin since that requires PA9. +#define MICROPY_HW_USB_FS (1) +/*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// SDRAM +#define MICROPY_HW_SDRAM_SIZE (64 / 8 * 1024 * 1024) // 64 Mbit +#define MICROPY_HW_SDRAM_STARTUP_TEST (1) +#define MICROPY_HEAP_START sdram_start() +#define MICROPY_HEAP_END sdram_end() + +// Timing configuration for 90 Mhz (11.90ns) of SD clock frequency (180Mhz/2) +#define MICROPY_HW_SDRAM_TIMING_TMRD (2) +#define MICROPY_HW_SDRAM_TIMING_TXSR (7) +#define MICROPY_HW_SDRAM_TIMING_TRAS (4) +#define MICROPY_HW_SDRAM_TIMING_TRC (7) +#define MICROPY_HW_SDRAM_TIMING_TWR (2) +#define MICROPY_HW_SDRAM_TIMING_TRP (2) +#define MICROPY_HW_SDRAM_TIMING_TRCD (2) +#define MICROPY_HW_SDRAM_REFRESH_RATE (64) // ms + +#define MICROPY_HW_SDRAM_BURST_LENGTH 1 +#define MICROPY_HW_SDRAM_CAS_LATENCY 2 +#define MICROPY_HW_SDRAM_COLUMN_BITS_NUM 8 +#define MICROPY_HW_SDRAM_ROW_BITS_NUM 12 +#define MICROPY_HW_SDRAM_MEM_BUS_WIDTH 16 +#define MICROPY_HW_SDRAM_INTERN_BANKS_NUM 4 +#define MICROPY_HW_SDRAM_CLOCK_PERIOD 2 +#define MICROPY_HW_SDRAM_RPIPE_DELAY 0 +#define MICROPY_HW_SDRAM_RBURST (1) +#define MICROPY_HW_SDRAM_WRITE_PROTECTION (0) +#define MICROPY_HW_SDRAM_AUTOREFRESH_NUM (8) + +#define MICROPY_HW_FMC_SDCKE0 (pin_C3) +#define MICROPY_HW_FMC_SDNE0 (pin_H3) +#define MICROPY_HW_FMC_SDCLK (pin_G8) +#define MICROPY_HW_FMC_SDNCAS (pin_G15) +#define MICROPY_HW_FMC_SDNRAS (pin_F11) +#define MICROPY_HW_FMC_SDNWE (pin_H5) +#define MICROPY_HW_FMC_BA0 (pin_G4) +#define MICROPY_HW_FMC_BA1 (pin_G5) +#define MICROPY_HW_FMC_NBL0 (pin_E0) +#define MICROPY_HW_FMC_NBL1 (pin_E1) +#define MICROPY_HW_FMC_A0 (pin_F0) +#define MICROPY_HW_FMC_A1 (pin_F1) +#define MICROPY_HW_FMC_A2 (pin_F2) +#define MICROPY_HW_FMC_A3 (pin_F3) +#define MICROPY_HW_FMC_A4 (pin_F4) +#define MICROPY_HW_FMC_A5 (pin_F5) +#define MICROPY_HW_FMC_A6 (pin_F12) +#define MICROPY_HW_FMC_A7 (pin_F13) +#define MICROPY_HW_FMC_A8 (pin_F14) +#define MICROPY_HW_FMC_A9 (pin_F15) +#define MICROPY_HW_FMC_A10 (pin_G0) +#define MICROPY_HW_FMC_A11 (pin_G1) +#define MICROPY_HW_FMC_D0 (pin_D14) +#define MICROPY_HW_FMC_D1 (pin_D15) +#define MICROPY_HW_FMC_D2 (pin_D0) +#define MICROPY_HW_FMC_D3 (pin_D1) +#define MICROPY_HW_FMC_D4 (pin_E7) +#define MICROPY_HW_FMC_D5 (pin_E8) +#define MICROPY_HW_FMC_D6 (pin_E9) +#define MICROPY_HW_FMC_D7 (pin_E10) +#define MICROPY_HW_FMC_D8 (pin_E11) +#define MICROPY_HW_FMC_D9 (pin_E12) +#define MICROPY_HW_FMC_D10 (pin_E13) +#define MICROPY_HW_FMC_D11 (pin_E14) +#define MICROPY_HW_FMC_D12 (pin_E15) +#define MICROPY_HW_FMC_D13 (pin_D8) +#define MICROPY_HW_FMC_D14 (pin_D9) +#define MICROPY_HW_FMC_D15 (pin_D10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk new file mode 100755 index 0000000..160218f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F746xx +AF_FILE = boards/stm32f746_af.csv +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/pins.csv new file mode 100755 index 0000000..dfafe67 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/pins.csv @@ -0,0 +1,93 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +LED,PI1 +SW,PI11 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CK,PC12 +SD_CMD,PD2 +SD_SW,PC13 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +VCP_TX,PA9 +VCP_RX,PB7 +CAN_TX,PB13 +CAN_RX,PB12 +SDRAM_SDCKE0,PC3 +SDRAM_SDNE0,PH3 +SDRAM_SDCLK,PG8 +SDRAM_SDNCAS,PG15 +SDRAM_SDNRAS,PF11 +SDRAM_SDNWE,PH5 +SDRAM_BA0,PG4 +SDRAM_BA1,PG5 +SDRAM_NBL0,PE0 +SDRAM_NBL1,PE1 +SDRAM_A0,PF0 +SDRAM_A1,PF1 +SDRAM_A2,PF2 +SDRAM_A3,PF3 +SDRAM_A4,PF4 +SDRAM_A5,PF5 +SDRAM_A6,PF12 +SDRAM_A7,PF13 +SDRAM_A8,PF14 +SDRAM_A9,PF15 +SDRAM_A10,PG0 +SDRAM_A11,PG1 +SDRAM_D0,PD14 +SDRAM_D1,PD15 +SDRAM_D2,PD0 +SDRAM_D3,PD1 +SDRAM_D4,PE7 +SDRAM_D5,PE8 +SDRAM_D6,PE9 +SDRAM_D7,PE10 +SDRAM_D8,PE11 +SDRAM_D9,PE12 +SDRAM_D10,PE13 +SDRAM_D11,PE14 +SDRAM_D12,PE15 +SDRAM_D13,PD8 +SDRAM_D14,PD9 +SDRAM_D15,PD10 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h new file mode 100755 index 0000000..1593390 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_SDRAM_MODULE_ENABLED +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/bdev.c b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/bdev.c new file mode 100755 index 0000000..01f06b8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/bdev.c @@ -0,0 +1,24 @@ +#include "storage.h" + +// External SPI flash uses standard SPI interface + +STATIC const mp_soft_spi_obj_t soft_spi_bus = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = MICROPY_HW_SPIFLASH_SCK, + .mosi = MICROPY_HW_SPIFLASH_MOSI, + .miso = MICROPY_HW_SPIFLASH_MISO, +}; + +STATIC mp_spiflash_cache_t spi_bdev_cache; + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, + .cache = &spi_bdev_cache, +}; + +spi_bdev_t spi_bdev; diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/board_init.c b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/board_init.c new file mode 100755 index 0000000..eb44f32 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/board_init.c @@ -0,0 +1,9 @@ +#include "py/mphal.h" + +void STM32L476DISC_board_early_init(void) { + // set SPI flash WP and HOLD pins high + mp_hal_pin_output(pin_E14); + mp_hal_pin_output(pin_E15); + mp_hal_pin_write(pin_E14, 1); + mp_hal_pin_write(pin_E15, 1); +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.h new file mode 100755 index 0000000..2653ebb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -0,0 +1,81 @@ +#define MICROPY_BOARD_EARLY_INIT STM32L476DISC_board_early_init +void STM32L476DISC_board_early_init(void); + +#define MICROPY_HW_BOARD_NAME "L476-DISCO" +#define MICROPY_HW_MCU_NAME "STM32L476" + +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// use external SPI flash for storage +#define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) +#define MICROPY_HW_SPIFLASH_CS (pin_E11) +#define MICROPY_HW_SPIFLASH_SCK (pin_E10) +#define MICROPY_HW_SPIFLASH_MOSI (pin_E12) +#define MICROPY_HW_SPIFLASH_MISO (pin_E13) + +// block device config for SPI flash +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ + (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ + (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ + spi_bdev_ioctl(&spi_bdev, (op), (arg)) \ +) +#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n)) +#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n)) + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +// USART 2 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI busses +#define MICROPY_HW_SPI2_NSS (pin_D0) +#define MICROPY_HW_SPI2_SCK (pin_D1) +#define MICROPY_HW_SPI2_MISO (pin_D3) +#define MICROPY_HW_SPI2_MOSI (pin_D4) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + +// Joystick is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B2) // red +#define MICROPY_HW_LED2 (pin_E8) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk new file mode 100755 index 0000000..2cad9e2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L476xx +AF_FILE = boards/stm32l476_af.csv +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/pins.csv new file mode 100755 index 0000000..52f96b6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/pins.csv @@ -0,0 +1,114 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h new file mode 100755 index 0000000..6bfb281 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 25-November-2015 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DFSDM_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_FIREWALL_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LCD_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_OPAMP_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/* #define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ + + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h new file mode 100755 index 0000000..6a17d74 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h @@ -0,0 +1,52 @@ +#define MICROPY_HW_BOARD_NAME "L496G-DISCO" +#define MICROPY_HW_MCU_NAME "STM32L496" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) + +// MSI is used and is 4MHz, +// Resulting core frequency is 80MHz: +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_D6) +// USART 2 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_G14) +#define MICROPY_HW_I2C1_SDA (pin_G13) +#define MICROPY_HW_I2C2_SCL (pin_H4) +#define MICROPY_HW_I2C2_SDA (pin_B14) + +// SPI busses +// -> To the arduino connector +#define MICROPY_HW_SPI1_NSS (pin_A15) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) + +// Use Sel from joystick. Joystick is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LED (The orange LED is controlled over MFX) +#define MICROPY_HW_LED1 (pin_B13) // Green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk new file mode 100755 index 0000000..3a61746 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L496xx +AF_FILE = boards/stm32l496_af.csv +LD_FILES = boards/stm32l496xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/pins.csv b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/pins.csv new file mode 100755 index 0000000..2ee0540 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/pins.csv @@ -0,0 +1,140 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 +PH2,PH2 +PH3,PH3 +PH4,PH4 +PH5,PH5 +PH6,PH6 +PH7,PH7 +PH8,PH8 +PH9,PH9 +PH10,PH10 +PH11,PH11 +PH12,PH12 +PH13,PH13 +PH14,PH14 +PH15,PH15 +PI0,PI0 +PI1,PI1 +PI2,PI2 +PI3,PI3 +PI4,PI4 +PI5,PI5 +PI6,PI6 +PI7,PI7 +PI8,PI8 +PI9,PI9 +PI10,PI10 +PI11,PI11 diff --git a/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h new file mode 100755 index 0000000..884db5e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h @@ -0,0 +1,421 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2018 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +/*#define HAL_CRYP_MODULE_ENABLED */ +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_DFSDM_MODULE_ENABLED */ +/*#define HAL_DSI_MODULE_ENABLED */ +/*#define HAL_FIREWALL_MODULE_ENABLED */ +/*#define HAL_GFXMMU_MODULE_ENABLED */ +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LTDC_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMBUS_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + + /** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ + #if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ + #endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0 + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" + #include "stm32l4xx_hal_rcc_ex.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32l4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32l4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32l4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32l4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32l4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED + #include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED + #include "stm32l4xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED + #include "stm32l4xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/common_basic.ld b/src/openmv/src/micropython/ports/stm32/boards/common_basic.ld new file mode 100755 index 0000000..2e428aa --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/common_basic.ld @@ -0,0 +1,86 @@ +/* Memory layout for basic configuration: + + FLASH .isr_vector + FLASH .text + FLASH .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/common_bl.ld b/src/openmv/src/micropython/ports/stm32/boards/common_bl.ld new file mode 100755 index 0000000..52b2a67 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/common_bl.ld @@ -0,0 +1,86 @@ +/* Memory layout for bootloader configuration (this here describes the app part): + + FLASH_APP .isr_vector + FLASH_APP .text + FLASH_APP .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH_APP + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH_APP + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH_APP + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/common_ifs.ld b/src/openmv/src/micropython/ports/stm32/boards/common_ifs.ld new file mode 100755 index 0000000..74b2ffb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/common_ifs.ld @@ -0,0 +1,103 @@ +/* Memory layout for internal flash storage configuration: + + FLASH_ISR .isr_vector + + FLASH_TEXT .text + FLASH_TEXT .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + /* This first flash block is 16K annd the isr vectors only take up + about 400 bytes. So we pull in a couple of object files to pad it + out. */ + + . = ALIGN(4); + + /* NOTE: If you update the list of files contained in .isr_vector, + then be sure to also update smhal/Makefile where it forcibly + builds each of these files with -Os */ + + */ff.o(.text*) + */vfs_fat_*.o(.text*) + */py/formatfloat.o(.text*) + */py/parsenum.o(.text*) + */py/mpprint.o(.text*) + + . = ALIGN(4); + } >FLASH_ISR + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH_TEXT + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH_TEXT + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/make-pins.py b/src/openmv/src/micropython/ports/stm32/boards/make-pins.py new file mode 100755 index 0000000..a7051b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/make-pins.py @@ -0,0 +1,500 @@ +#!/usr/bin/env python +"""Creates the pin file for the STM32F4xx.""" + +from __future__ import print_function + +import argparse +import sys +import csv + +# Must have matching entries in AF_FN_* enum in ../pin_defs_stm32.h +SUPPORTED_FN = { + 'TIM' : ['CH1', 'CH2', 'CH3', 'CH4', + 'CH1N', 'CH2N', 'CH3N', 'CH1_ETR', 'ETR', 'BKIN'], + 'I2C' : ['SDA', 'SCL'], + 'I2S' : ['CK', 'MCK', 'SD', 'WS', 'EXTSD'], + 'USART' : ['RX', 'TX', 'CTS', 'RTS', 'CK'], + 'UART' : ['RX', 'TX', 'CTS', 'RTS'], + 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'], + 'SDMMC' : ['CK', 'CMD', 'D0', 'D1', 'D2', 'D3'], + 'CAN' : ['TX', 'RX'], +} + +CONDITIONAL_VAR = { + 'I2C' : 'MICROPY_HW_I2C{num}_SCL', + 'I2S' : 'MICROPY_HW_ENABLE_I2S{num}', + 'SPI' : 'MICROPY_HW_SPI{num}_SCK', + 'UART' : 'MICROPY_HW_UART{num}_TX', + 'USART' : 'MICROPY_HW_UART{num}_TX', + 'SDMMC' : 'MICROPY_HW_SDMMC{num}_CK', + 'CAN' : 'MICROPY_HW_CAN{num}_TX', +} + +def parse_port_pin(name_str): + """Parses a string and returns a (port-num, pin-num) tuple.""" + if len(name_str) < 3: + raise ValueError("Expecting pin name to be at least 3 charcters.") + if name_str[0] != 'P': + raise ValueError("Expecting pin name to start with P") + if name_str[1] < 'A' or name_str[1] > 'K': + raise ValueError("Expecting pin port to be between A and K") + port = ord(name_str[1]) - ord('A') + pin_str = name_str[2:] + if not pin_str.isdigit(): + raise ValueError("Expecting numeric pin number.") + return (port, int(pin_str)) + +def split_name_num(name_num): + num = None + for num_idx in range(len(name_num) - 1, -1, -1): + if not name_num[num_idx].isdigit(): + name = name_num[0:num_idx + 1] + num_str = name_num[num_idx + 1:] + if len(num_str) > 0: + num = int(num_str) + break + return name, num + +def conditional_var(name_num): + # Try the specific instance first. For example, if name_num is UART4_RX + # then try UART4 first, and then try UART second. + name, num = split_name_num(name_num) + var = [] + if name in CONDITIONAL_VAR: + var.append(CONDITIONAL_VAR[name].format(num=num)) + if name_num in CONDITIONAL_VAR: + var.append(CONDITIONAL_VAR[name_num]) + return var + +def print_conditional_if(cond_var, file=None): + if cond_var: + cond_str = [] + for var in cond_var: + if var.find('ENABLE') >= 0: + cond_str.append('(defined({0}) && {0})'.format(var)) + else: + cond_str.append('defined({0})'.format(var)) + print('#if ' + ' || '.join(cond_str), file=file) + +def print_conditional_endif(cond_var, file=None): + if cond_var: + print('#endif', file=file) + + +class AlternateFunction(object): + """Holds the information associated with a pins alternate function.""" + + def __init__(self, idx, af_str): + self.idx = idx + # Special case. We change I2S2ext_SD into I2S2_EXTSD so that it parses + # the same way the other peripherals do. + af_str = af_str.replace('ext_', '_EXT') + + self.af_str = af_str + + self.func = '' + self.fn_num = None + self.pin_type = '' + self.supported = False + + af_words = af_str.split('_', 1) + self.func, self.fn_num = split_name_num(af_words[0]) + if len(af_words) > 1: + self.pin_type = af_words[1] + if self.func in SUPPORTED_FN: + pin_types = SUPPORTED_FN[self.func] + if self.pin_type in pin_types: + self.supported = True + + def is_supported(self): + return self.supported + + def ptr(self): + """Returns the numbered function (i.e. USART6) for this AF.""" + if self.fn_num is None: + return self.func + return '{:s}{:d}'.format(self.func, self.fn_num) + + def mux_name(self): + return 'AF{:d}_{:s}'.format(self.idx, self.ptr()) + + def print(self): + """Prints the C representation of this AF.""" + cond_var = None + if self.supported: + cond_var = conditional_var('{}{}'.format(self.func, self.fn_num)) + print_conditional_if(cond_var) + print(' AF', end='') + else: + print(' //', end='') + fn_num = self.fn_num + if fn_num is None: + fn_num = 0 + print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, + self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + print_conditional_endif(cond_var) + + def qstr_list(self): + return [self.mux_name()] + + +class Pin(object): + """Holds the information associated with a pin.""" + + def __init__(self, port, pin): + self.port = port + self.pin = pin + self.alt_fn = [] + self.alt_fn_count = 0 + self.adc_num = 0 + self.adc_channel = 0 + self.board_pin = False + + def port_letter(self): + return chr(self.port + ord('A')) + + def cpu_pin_name(self): + return '{:s}{:d}'.format(self.port_letter(), self.pin) + + def is_board_pin(self): + return self.board_pin + + def set_is_board_pin(self): + self.board_pin = True + + def parse_adc(self, adc_str): + if (adc_str[:3] != 'ADC'): + return + (adc,channel) = adc_str.split('_') + for idx in range(3, len(adc)): + adc_num = int(adc[idx]) # 1, 2, or 3 + self.adc_num |= (1 << (adc_num - 1)) + self.adc_channel = int(channel[2:]) + + def parse_af(self, af_idx, af_strs_in): + if len(af_strs_in) == 0: + return + # If there is a slash, then the slash separates 2 aliases for the + # same alternate function. + af_strs = af_strs_in.split('/') + for af_str in af_strs: + alt_fn = AlternateFunction(af_idx, af_str) + self.alt_fn.append(alt_fn) + if alt_fn.is_supported(): + self.alt_fn_count += 1 + + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return 'NULL' + return 'pin_{:s}_af'.format(self.cpu_pin_name()) + + def adc_num_str(self): + str = '' + for adc_num in range(1,4): + if self.adc_num & (1 << (adc_num - 1)): + if len(str) > 0: + str += ' | ' + str += 'PIN_ADC' + str += chr(ord('0') + adc_num) + if len(str) == 0: + str = '0' + return str + + def print(self): + if self.alt_fn_count == 0: + print("// ", end='') + print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name())) + for alt_fn in self.alt_fn: + alt_fn.print() + if self.alt_fn_count == 0: + print("// ", end='') + print('};') + print('') + print('const pin_obj_t pin_{:s}_obj = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( + self.cpu_pin_name(), self.port_letter(), self.pin, + self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) + print('') + + def print_header(self, hdr_file): + n = self.cpu_pin_name() + hdr_file.write('extern const pin_obj_t pin_{:s}_obj;\n'.format(n)) + hdr_file.write('#define pin_{:s} (&pin_{:s}_obj)\n'.format(n, n)) + if self.alt_fn_count > 0: + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.format(n)) + + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + +class NamedPin(object): + + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name + + +class Pins(object): + + def __init__(self): + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects + + def find_pin(self, port_num, pin_num): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.port == port_num and pin.pin == pin_num: + return pin + + def parse_af_file(self, filename, pinname_col, af_col): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[pinname_col]) + except: + continue + pin = Pin(port_num, pin_num) + for af_idx in range(af_col, len(row)): + if af_idx < af_col + 16: + pin.parse_af(af_idx - af_col, row[af_idx]) + elif af_idx == af_col + 16: + pin.parse_adc(row[af_idx]) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) + + def parse_board_file(self, filename): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[1]) + except: + continue + pin = self.find_pin(port_num, pin_num) + if pin: + pin.set_is_board_pin() + self.board_pins.append(NamedPin(row[0], pin)) + + def print_named(self, label, named_pins): + print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}_obj) }},'.format(named_pin.name(), pin.cpu_pin_name())) + print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)) + + def print(self): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print() + self.print_named('cpu', self.cpu_pins) + print('') + self.print_named('board', self.board_pins) + + def print_adc(self, adc_num): + print('') + print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) + for channel in range(17): + if channel == 16: + print('#if defined(STM32L4)') + adc_found = False + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if (pin.is_board_pin() and + (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): + print(' &pin_{:s}_obj, // {:d}'.format(pin.cpu_pin_name(), channel)) + adc_found = True + break + if not adc_found: + print(' NULL, // {:d}'.format(channel)) + if channel == 16: + print('#endif') + print('};') + + + def print_header(self, hdr_filename): + with open(hdr_filename, 'wt') as hdr_file: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + # provide #define's mapping board to cpu name + for named_pin in self.board_pins: + hdr_file.write("#define pyb_pin_{:s} pin_{:s}\n".format(named_pin.name(), named_pin.pin().cpu_pin_name())) + + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + cond_var = None + if qstr.startswith('AF'): + af_words = qstr.split('_') + cond_var = conditional_var(af_words[1]) + print_conditional_if(cond_var, file=qstr_file) + print('Q({})'.format(qstr), file=qstr_file) + print_conditional_endif(cond_var, file=qstr_file) + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, 'wt') as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + af_words = mux_name.split('_') # ex mux_name: AF9_I2C2 + cond_var = conditional_var(af_words[1]) + print_conditional_if(cond_var, file=af_const_file) + key = 'MP_ROM_QSTR(MP_QSTR_{}),'.format(mux_name) + val = 'MP_ROM_INT(GPIO_{})'.format(mux_name) + print(' { %-*s %s },' % (mux_name_width + 26, key, val), + file=af_const_file) + print_conditional_endif(cond_var, file=af_const_file) + + def print_af_defs(self, af_defs_filename): + with open(af_defs_filename, 'wt') as af_defs_file: + + STATIC_AF_TOKENS = {} + for named_pin in self.board_pins: + for af in named_pin.pin().alt_fn: + func = "%s%d" % (af.func, af.fn_num) if af.fn_num else af.func + pin_type = (af.pin_type or "NULL").split('(')[0] + tok = "#define STATIC_AF_%s_%s(pin_obj) ( \\" % (func, pin_type) + if tok not in STATIC_AF_TOKENS: + STATIC_AF_TOKENS[tok] = [] + STATIC_AF_TOKENS[tok].append( + ' ((strcmp( #pin_obj , "(&pin_%s_obj)") & strcmp( #pin_obj , "((&pin_%s_obj))")) == 0) ? (%d) : \\' % ( + named_pin.pin().cpu_pin_name(), named_pin.pin().cpu_pin_name(), af.idx + ) + ) + + for tok, pins in STATIC_AF_TOKENS.items(): + print(tok, file=af_defs_file) + print("\n".join(sorted(pins)), file=af_defs_file) + print(" (0xffffffffffffffffULL))\n", file=af_defs_file) + + def print_af_py(self, af_py_filename): + with open(af_py_filename, 'wt') as af_py_file: + print('PINS_AF = (', file=af_py_file) + for named_pin in self.board_pins: + print(" ('%s', " % named_pin.name(), end='', file=af_py_file) + for af in named_pin.pin().alt_fn: + if af.is_supported(): + print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file) + print('),', file=af_py_file) + print(')', file=af_py_file) + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file" + ) + parser.add_argument( + "-a", "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="stm32f4xx_af.csv" + ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins_af_const.h" + ) + parser.add_argument( + "--af-py", + dest="af_py_filename", + help="Specifies the filename for the python alternate function mappings.", + default="build/pins_af.py" + ) + parser.add_argument( + "--af-defs", + dest="af_defs_filename", + help="Specifies the filename for the alternate function defines.", + default="build/pins_af_defs.h" + ) + parser.add_argument( + "-b", "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="stm32f4xx_prefix.c" + ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins_qstr.h" + ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print('// This file was automatically generated by make-pins.py') + print('//') + if args.af_filename: + print('// --af {:s}'.format(args.af_filename)) + pins.parse_af_file(args.af_filename, 1, 2) + + if args.board_filename: + print('// --board {:s}'.format(args.board_filename)) + pins.parse_board_file(args.board_filename) + + if args.prefix_filename: + print('// --prefix {:s}'.format(args.prefix_filename)) + print('') + with open(args.prefix_filename, 'r') as prefix_file: + print(prefix_file.read()) + pins.print() + pins.print_adc(1) + pins.print_adc(2) + pins.print_adc(3) + pins.print_header(args.hdr_filename) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) + pins.print_af_py(args.af_py_filename) + pins.print_af_defs(args.af_defs_filename) + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f4.cfg b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f4.cfg new file mode 100755 index 0000000..ee96b91 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f4.cfg @@ -0,0 +1,42 @@ +# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger +# and an STM32F4 target microcontroller. +# +# To flash your firmware: +# +# $ openocd -f openocd_stm32f4.cfg \ +# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08020000" +# +# For a gdb server on port 3333: +# +# $ openocd -f openocd_stm32f4.cfg + + +source [find interface/stlink-v2.cfg] +transport select hla_swd +source [find target/stm32f4x.cfg] +reset_config srst_only +init + +proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } { + reset halt + sleep 100 + wait_halt 2 + flash write_image erase $BIN0 $ADDR0 + sleep 100 + verify_image $BIN0 $ADDR0 + sleep 100 + flash write_image erase $BIN1 $ADDR1 + sleep 100 + verify_image $BIN1 $ADDR1 + sleep 100 + reset run + shutdown +} + +proc stm_erase {} { + reset halt + sleep 100 + stm32f4x mass_erase 0 + sleep 100 + shutdown +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f7.cfg b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f7.cfg new file mode 100755 index 0000000..55b6326 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32f7.cfg @@ -0,0 +1,42 @@ +# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger +# and an STM32F7 target microcontroller. +# +# To flash your firmware: +# +# $ openocd -f openocd_stm32f7.cfg \ +# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08020000" +# +# For a gdb server on port 3333: +# +# $ openocd -f openocd_stm32f7.cfg + + +source [find interface/stlink-v2-1.cfg] +transport select hla_swd +source [find target/stm32f7x.cfg] +reset_config srst_only +init + +proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } { + reset halt + sleep 100 + wait_halt 2 + flash write_image erase $BIN0 $ADDR0 + sleep 100 + verify_image $BIN0 $ADDR0 + sleep 100 + flash write_image erase $BIN1 $ADDR1 + sleep 100 + verify_image $BIN1 $ADDR1 + sleep 100 + reset run + shutdown +} + +proc stm_erase {} { + reset halt + sleep 100 + stm32f7x mass_erase 0 + sleep 100 + shutdown +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32l4.cfg b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32l4.cfg new file mode 100755 index 0000000..59e98de --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/openocd_stm32l4.cfg @@ -0,0 +1,42 @@ +# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger +# and an STM32L4 target microcontroller. +# +# To flash your firmware: +# +# $ openocd -f openocd_stm32l4.cfg \ +# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08004000" +# +# For a gdb server on port 3333: +# +# $ openocd -f openocd_stm32l4.cfg + + +source [find interface/stlink-v2-1.cfg] +transport select hla_swd +source [find target/stm32l4x.cfg] +reset_config srst_only +init + +proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } { + reset halt + sleep 100 + wait_halt 2 + flash write_image erase $BIN0 $ADDR0 + sleep 100 + verify_image $BIN0 $ADDR0 + sleep 100 + flash write_image erase $BIN1 $ADDR1 + sleep 100 + verify_image $BIN1 $ADDR1 + sleep 100 + reset run + shutdown +} + +proc stm_erase {} { + reset halt + sleep 100 + stm32l4x mass_erase 0 + sleep 100 + shutdown +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/pllvalues.py b/src/openmv/src/micropython/ports/stm32/boards/pllvalues.py new file mode 100755 index 0000000..4b090c4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/pllvalues.py @@ -0,0 +1,184 @@ +""" +This is an auxiliary script that is used to compute valid PLL values to set +the CPU frequency to a given value. The algorithm here appears as C code +for the machine.freq() function. +""" + +from __future__ import print_function + +def close_int(x): + return abs(x - round(x)) < 0.01 + +# original version that requires N/M to be an integer (for simplicity) +def compute_pll(hse, sys): + for P in (2, 4, 6, 8): # allowed values of P + Q = sys * P / 48 + NbyM = sys * P / hse + # N/M and Q must be integers + if not (close_int(NbyM) and close_int(Q)): + continue + # VCO_OUT must be between 192MHz and 432MHz + if not (192 <= hse * NbyM <= 432): + continue + # compute M + M = int(192 // NbyM) + while hse > 2 * M or NbyM * M < 192: + M += 1 + # VCO_IN must be between 1MHz and 2MHz (2MHz recommended) + if not (M <= hse): + continue + # compute N + N = NbyM * M + # N and Q are restricted + if not (192 <= N <= 432 and 2 <= Q <= 15): + continue + # found valid values + assert NbyM == N // M + return (M, N, P, Q) + # no valid values found + return None + +# improved version that doesn't require N/M to be an integer +def compute_pll2(hse, sys, relax_pll48): + # Loop over the allowed values of P, looking for a valid PLL configuration + # that gives the desired "sys" frequency. We use floats for P to force + # floating point arithmetic on Python 2. + fallback = None + for P in (2.0, 4.0, 6.0, 8.0): + NbyM = sys * P / hse + # VCO_OUT must be between 192MHz and 432MHz + if not (192 <= hse * NbyM <= 432): + continue + # scan M + M = int(192 // NbyM) # starting value + while 2 * M < hse: + M += 1 + # VCO_IN must be between 1MHz and 2MHz (2MHz recommended) + for M in range(M, hse + 1): + if NbyM * M < 191.99 or not close_int(NbyM * M): + continue + # compute N + N = NbyM * M + # N must be an integer + if not close_int(N): + continue + # N is restricted + if not (192 <= N <= 432): + continue + Q = (sys * P / 48) + # Q must be an integer in a set range + if not (2 <= Q <= 15): + continue + if not close_int(Q): + if int(M) == int(hse) and fallback is None: + # the values don't give 48MHz on PLL48 but are otherwise OK + fallback = M, N, P, int(Q) + continue + # found valid values + return (M, N, P, Q) + if relax_pll48: + # might have found values which don't give 48MHz on PLL48 + return fallback + else: + # no valid values found which give 48MHz on PLL48 + return None + +def compute_derived(hse, pll): + M, N, P, Q = pll + vco_in = hse / M + vco_out = hse * N / M + pllck = hse / M * N / P + pll48ck = hse / M * N / Q + return (vco_in, vco_out, pllck, pll48ck) + +def verify_pll(hse, pll): + M, N, P, Q = pll + vco_in, vco_out, pllck, pll48ck = compute_derived(hse, pll) + + # verify ints + assert close_int(M) + assert close_int(N) + assert close_int(P) + assert close_int(Q) + + # verify range + assert 2 <= M <= 63 + assert 192 <= N <= 432 + assert P in (2, 4, 6, 8) + assert 2 <= Q <= 15 + assert 1 <= vco_in <= 2 + assert 192 <= vco_out <= 432 + +def generate_c_table(hse, valid_plls): + valid_plls = valid_plls + [(16, (0, 0, 2, 0))] + if hse < 16: + valid_plls.append((hse, (1, 0, 2, 0))) + valid_plls.sort() + print("// (M, P/2-1, SYS) values for %u MHz HSE" % hse) + print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls)) + for sys, (M, N, P, Q) in valid_plls: + print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys)) + print("};") + +def print_table(hse, valid_plls): + print("HSE =", hse, "MHz") + print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK") + out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f" + for sys, pll in valid_plls: + print(out_format % ((sys,) + pll + compute_derived(hse, pll))) + print("found %u valid configurations" % len(valid_plls)) + +def main(): + global out_format + + # parse input args + import sys + argv = sys.argv[1:] + + c_table = False + relax_pll48 = False + + while True: + if argv[0] == '-c': + c_table = True + argv.pop(0) + elif argv[0] == '--relax-pll48': + relax_pll48 = True + argv.pop(0) + else: + break + + if len(argv) != 1: + print("usage: pllvalues.py [-c] ") + sys.exit(1) + + if argv[0].startswith("file:"): + # extract HSE_VALUE from header file + with open(argv[0][5:]) as f: + for line in f: + line = line.strip() + if line.startswith("#define") and line.find("HSE_VALUE") != -1: + idx_start = line.find("((uint32_t)") + 11 + idx_end = line.find(")", idx_start) + hse = int(line[idx_start:idx_end]) // 1000000 + break + else: + raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0]) + else: + # HSE given directly as an integer + hse = int(argv[0]) + + valid_plls = [] + for sysclk in range(2, 217, 2): + pll = compute_pll2(hse, sysclk, relax_pll48) + if pll is not None: + verify_pll(hse, pll) + valid_plls.append((sysclk, pll)) + + if c_table: + generate_c_table(hse, valid_plls) + else: + print_table(hse, valid_plls) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f0.s b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f0.s new file mode 100755 index 0000000..eb5c496 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f0.s @@ -0,0 +1,303 @@ +/** + ****************************************************************************** + * @file startup_stm32f091xc.s + * @author MCD Application Team + * @brief STM32F091xC devices vector table for GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M0 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m0 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill the bss segment. */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + +LoopForever: + b LoopForever + + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M0. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word 0 + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_VDDIO2_IRQHandler /* PVD and VDDIO2 through EXTI Line detect */ + .word RTC_IRQHandler /* RTC through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_CRS_IRQHandler /* RCC and CRS */ + .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */ + .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */ + .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */ + .word TSC_IRQHandler /* TSC */ + .word DMA1_Ch1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler /* DMA1 Channel 2 and 3 & DMA2 Channel 1 and 2 */ + .word DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler /* DMA1 Channel 4 to 7 & DMA2 Channel 3 to 5 */ + .word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */ + .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC */ + .word TIM7_IRQHandler /* TIM7 */ + .word TIM14_IRQHandler /* TIM14 */ + .word TIM15_IRQHandler /* TIM15 */ + .word TIM16_IRQHandler /* TIM16 */ + .word TIM17_IRQHandler /* TIM17 */ + .word I2C1_IRQHandler /* I2C1 */ + .word I2C2_IRQHandler /* I2C2 */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_8_IRQHandler /* USART3, USART4, USART5, USART6, USART7, USART8 */ + .word CEC_CAN_IRQHandler /* CEC and CAN */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_VDDIO2_IRQHandler + .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler + + .weak RTC_IRQHandler + .thumb_set RTC_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_CRS_IRQHandler + .thumb_set RCC_CRS_IRQHandler,Default_Handler + + .weak EXTI0_1_IRQHandler + .thumb_set EXTI0_1_IRQHandler,Default_Handler + + .weak EXTI2_3_IRQHandler + .thumb_set EXTI2_3_IRQHandler,Default_Handler + + .weak EXTI4_15_IRQHandler + .thumb_set EXTI4_15_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak DMA1_Ch1_IRQHandler + .thumb_set DMA1_Ch1_IRQHandler,Default_Handler + + .weak DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler + .thumb_set DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler,Default_Handler + + .weak DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler + .thumb_set DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler,Default_Handler + + .weak ADC1_COMP_IRQHandler + .thumb_set ADC1_COMP_IRQHandler,Default_Handler + + .weak TIM1_BRK_UP_TRG_COM_IRQHandler + .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak TIM14_IRQHandler + .thumb_set TIM14_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak I2C1_IRQHandler + .thumb_set I2C1_IRQHandler,Default_Handler + + .weak I2C2_IRQHandler + .thumb_set I2C2_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_8_IRQHandler + .thumb_set USART3_8_IRQHandler,Default_Handler + + .weak CEC_CAN_IRQHandler + .thumb_set CEC_CAN_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f4.s b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f4.s new file mode 100755 index 0000000..3e29a79 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f4.s @@ -0,0 +1,530 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f7.s b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f7.s new file mode 100755 index 0000000..633ba01 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32f7.s @@ -0,0 +1,604 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m7 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMA2D_IRQHandler /* DMA2D */ + .word SAI2_IRQHandler /* SAI2 */ + .word QUADSPI_IRQHandler /* QUADSPI */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word CEC_IRQHandler /* HDMI_CEC */ + .word I2C4_EV_IRQHandler /* I2C4 Event */ + .word I2C4_ER_IRQHandler /* I2C4 Error */ + .word SPDIF_RX_IRQHandler /* SPDIF_RX */ + .word DSIHOST_IRQHandler /* DSI host */ + .word DFSDM1_FLT0_IRQHandler /* DFSDM1 filter 0 */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM1 filter 1 */ + .word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */ + .word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */ + .word SDMMC2_IRQHandler /* SDMMC2 */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak CEC_IRQHandler + .thumb_set CEC_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak SPDIF_RX_IRQHandler + .thumb_set SPDIF_RX_IRQHandler,Default_Handler + + .weak DSIHOST_IRQHandler + .thumb_set DSIHOST_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/startup_stm32h7.s b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32h7.s new file mode 100755 index 0000000..53d4620 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32h7.s @@ -0,0 +1,763 @@ +/** + ****************************************************************************** + * @file startup_stm32h743xx.s + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief STM32H743xx Devices vector table for GCC based toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2017 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m7 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ +/* bl __libc_init_array */ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_AVD_IRQHandler /* PVD/AVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */ + .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */ + .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */ + .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */ + .word TIM1_UP_IRQHandler /* TIM1 Update interrupt */ + .word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word 0 /* Reserved */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* Reserved */ + .word RNG_IRQHandler /* Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word LTDC_IRQHandler /* LTDC */ + .word LTDC_ER_IRQHandler /* LTDC error */ + .word DMA2D_IRQHandler /* DMA2D */ + .word SAI2_IRQHandler /* SAI2 */ + .word QUADSPI_IRQHandler /* QUADSPI */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word CEC_IRQHandler /* HDMI_CEC */ + .word I2C4_EV_IRQHandler /* I2C4 Event */ + .word I2C4_ER_IRQHandler /* I2C4 Error */ + .word SPDIF_RX_IRQHandler /* SPDIF_RX */ + .word OTG_FS_EP1_OUT_IRQHandler /* USB OTG FS End Point 1 Out */ + .word OTG_FS_EP1_IN_IRQHandler /* USB OTG FS End Point 1 In */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */ + .word HRTIM1_Master_IRQHandler /* HRTIM Master Timer global Interrupt */ + .word HRTIM1_TIMA_IRQHandler /* HRTIM Timer A global Interrupt */ + .word HRTIM1_TIMB_IRQHandler /* HRTIM Timer B global Interrupt */ + .word HRTIM1_TIMC_IRQHandler /* HRTIM Timer C global Interrupt */ + .word HRTIM1_TIMD_IRQHandler /* HRTIM Timer D global Interrupt */ + .word HRTIM1_TIME_IRQHandler /* HRTIM Timer E global Interrupt */ + .word HRTIM1_FLT_IRQHandler /* HRTIM Fault global Interrupt */ + .word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */ + .word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */ + .word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */ + .word SAI3_IRQHandler /* SAI3 global Interrupt */ + .word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */ + .word TIM15_IRQHandler /* TIM15 global Interrupt */ + .word TIM16_IRQHandler /* TIM16 global Interrupt */ + .word TIM17_IRQHandler /* TIM17 global Interrupt */ + .word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */ + .word MDIOS_IRQHandler /* MDIOS global Interrupt */ + .word JPEG_IRQHandler /* JPEG global Interrupt */ + .word MDMA_IRQHandler /* MDMA global Interrupt */ + .word 0 /* Reserved */ + .word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */ + .word HSEM1_IRQHandler /* HSEM1 global Interrupt */ + .word 0 /* Reserved */ + .word ADC3_IRQHandler /* ADC3 global Interrupt */ + .word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */ + .word BDMA_Channel0_IRQHandler /* BDMA Channel 0 global Interrupt */ + .word BDMA_Channel1_IRQHandler /* BDMA Channel 1 global Interrupt */ + .word BDMA_Channel2_IRQHandler /* BDMA Channel 2 global Interrupt */ + .word BDMA_Channel3_IRQHandler /* BDMA Channel 3 global Interrupt */ + .word BDMA_Channel4_IRQHandler /* BDMA Channel 4 global Interrupt */ + .word BDMA_Channel5_IRQHandler /* BDMA Channel 5 global Interrupt */ + .word BDMA_Channel6_IRQHandler /* BDMA Channel 6 global Interrupt */ + .word BDMA_Channel7_IRQHandler /* BDMA Channel 7 global Interrupt */ + .word COMP1_IRQHandler /* COMP1 global Interrupt */ + .word LPTIM2_IRQHandler /* LP TIM2 global interrupt */ + .word LPTIM3_IRQHandler /* LP TIM3 global interrupt */ + .word LPTIM4_IRQHandler /* LP TIM4 global interrupt */ + .word LPTIM5_IRQHandler /* LP TIM5 global interrupt */ + .word LPUART1_IRQHandler /* LP UART1 interrupt */ + .word 0 /* Reserved */ + .word CRS_IRQHandler /* Clock Recovery Global Interrupt */ + .word 0 /* Reserved */ + .word SAI4_IRQHandler /* SAI4 global interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_AVD_IRQHandler + .thumb_set PVD_AVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak FDCAN1_IT0_IRQHandler + .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler + + .weak FDCAN2_IT0_IRQHandler + .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler + + .weak FDCAN1_IT1_IRQHandler + .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler + + .weak FDCAN2_IT1_IRQHandler + .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_IRQHandler + .thumb_set TIM1_UP_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_IRQHandler + .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak FDCAN_CAL_IRQHandler + .thumb_set FDCAN_CAL_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak LTDC_IRQHandler + .thumb_set LTDC_IRQHandler,Default_Handler + + .weak LTDC_ER_IRQHandler + .thumb_set LTDC_ER_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak CEC_IRQHandler + .thumb_set CEC_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak SPDIF_RX_IRQHandler + .thumb_set SPDIF_RX_IRQHandler,Default_Handler + + .weak OTG_FS_EP1_OUT_IRQHandler + .thumb_set OTG_FS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_FS_EP1_IN_IRQHandler + .thumb_set OTG_FS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + + .weak HRTIM1_Master_IRQHandler + .thumb_set HRTIM1_Master_IRQHandler,Default_Handler + + .weak HRTIM1_TIMA_IRQHandler + .thumb_set HRTIM1_TIMA_IRQHandler,Default_Handler + + .weak HRTIM1_TIMB_IRQHandler + .thumb_set HRTIM1_TIMB_IRQHandler,Default_Handler + + .weak HRTIM1_TIMC_IRQHandler + .thumb_set HRTIM1_TIMC_IRQHandler,Default_Handler + + .weak HRTIM1_TIMD_IRQHandler + .thumb_set HRTIM1_TIMD_IRQHandler,Default_Handler + + .weak HRTIM1_TIME_IRQHandler + .thumb_set HRTIM1_TIME_IRQHandler,Default_Handler + + .weak HRTIM1_FLT_IRQHandler + .thumb_set HRTIM1_FLT_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak SAI3_IRQHandler + .thumb_set SAI3_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak MDIOS_WKUP_IRQHandler + .thumb_set MDIOS_WKUP_IRQHandler,Default_Handler + + .weak MDIOS_IRQHandler + .thumb_set MDIOS_IRQHandler,Default_Handler + + .weak JPEG_IRQHandler + .thumb_set JPEG_IRQHandler,Default_Handler + + .weak MDMA_IRQHandler + .thumb_set MDMA_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + + .weak HSEM1_IRQHandler + .thumb_set HSEM1_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak DMAMUX2_OVR_IRQHandler + .thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler + + .weak BDMA_Channel0_IRQHandler + .thumb_set BDMA_Channel0_IRQHandler,Default_Handler + + .weak BDMA_Channel1_IRQHandler + .thumb_set BDMA_Channel1_IRQHandler,Default_Handler + + .weak BDMA_Channel2_IRQHandler + .thumb_set BDMA_Channel2_IRQHandler,Default_Handler + + .weak BDMA_Channel3_IRQHandler + .thumb_set BDMA_Channel3_IRQHandler,Default_Handler + + .weak BDMA_Channel4_IRQHandler + .thumb_set BDMA_Channel4_IRQHandler,Default_Handler + + .weak BDMA_Channel5_IRQHandler + .thumb_set BDMA_Channel5_IRQHandler,Default_Handler + + .weak BDMA_Channel6_IRQHandler + .thumb_set BDMA_Channel6_IRQHandler,Default_Handler + + .weak BDMA_Channel7_IRQHandler + .thumb_set BDMA_Channel7_IRQHandler,Default_Handler + + .weak COMP1_IRQHandler + .thumb_set COMP1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LPTIM3_IRQHandler + .thumb_set LPTIM3_IRQHandler,Default_Handler + + .weak LPTIM4_IRQHandler + .thumb_set LPTIM4_IRQHandler,Default_Handler + + .weak LPTIM5_IRQHandler + .thumb_set LPTIM5_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak SAI4_IRQHandler + .thumb_set SAI4_IRQHandler,Default_Handler + + .weak WAKEUP_PIN_IRQHandler + .thumb_set WAKEUP_PIN_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/boards/startup_stm32l4.s b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32l4.s new file mode 100755 index 0000000..3225723 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/startup_stm32l4.s @@ -0,0 +1,549 @@ +/** + ****************************************************************************** + * @file startup_stm32l496xx.s + * @author MCD Application Team + * @brief STM32L496xx devices vector table GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address, + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + * Taken from STM32L4 template code for stm32l496 in STM32Cube_FW_L4_V1.11.0 + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2017 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +.equ BootRAM, 0xF1E0F85F +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ + .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ + .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ + .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ + .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ + .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ + .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ + .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ + .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word DFSDM1_FLT3_IRQHandler /* Digital filter 3 for sigma delta modulator */ + .word TIM8_BRK_IRQHandler /* TIM8 Break */ + .word TIM8_UP_IRQHandler /* TIM8 Update */ + .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word ADC3_IRQHandler /* ADC3 global interrupt */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ + .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ + .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ + .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ + .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ + .word DFSDM1_FLT0_IRQHandler /* Digital filter 0 for sigma delta modulator */ + .word DFSDM1_FLT1_IRQHandler /* Digital filter 1 for sigma delta modulator */ + .word DFSDM1_FLT2_IRQHandler /* Digital filter 2 for sigma delta modulator */ + .word COMP_IRQHandler /* Comporator thru EXTI line */ + .word LPTIM1_IRQHandler /* Low power timer 1 */ + .word LPTIM2_IRQHandler /* Low power timer 2 */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ + .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ + .word LPUART1_IRQHandler /* Low power UART */ + .word QUADSPI_IRQHandler /* Quad SPI */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word SAI1_IRQHandler /* Serial audio interface 1 */ + .word SAI2_IRQHandler /* Serial audio interface 2 */ + .word SWPMI1_IRQHandler /* Single wire protocole 1 */ + .word TSC_IRQHandler /* Touch sensig controller */ + .word LCD_IRQHandler /* LCD */ + .word 0 /* CRYP crypto */ + .word RNG_IRQHandler /* Random number generator */ + .word FPU_IRQHandler /* FPU */ + /* Following Handlers are only used on L496/4A6xx devices */ + .word CRS_IRQHandler /* HASH and CRS interrupt */ + .word I2C4_EV_IRQHandler /* I2C4 event interrupt */ + .word I2C4_ER_IRQHandler /* I2C4 error interrupt */ + .word DCMI_IRQHandler /* DCMI global interrupt */ + .word CAN2_TX_IRQHandler /* CAN2 TX interrupt */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 interrupt */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 interrupt */ + .word CAN2_SCE_IRQHandler /* CAN SCE interrupt */ + .word DMA2D_IRQHandler /* DMA2D global interrupt */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak TIM8_BRK_IRQHandler + .thumb_set TIM8_BRK_IRQHandler,Default_Handler + + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_IRQHandler + .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f091_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f091_af.csv new file mode 100755 index 0000000..38e134f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f091_af.csv @@ -0,0 +1,89 @@ +Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,, +,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,,ADC +PortA,PA0,,USART2_CTS,TIM2_CH1_ETR,TSC_G1_IO1,USART4_TX,,,COMP1_OUT,,,,,,,,,ADC1_IN0 +PortA,PA1,EVENTOUT,USART2_RTS,TIM2_CH2,TSC_G1_IO2,USART4_RX,TIM15_CH1N,,,,,,,,,,,ADC1_IN1 +PortA,PA2,TIM15_CH1,USART2_TX,TIM2_CH3,TSC_G1_IO3,,,,COMP2_OUT,,,,,,,,,ADC1_IN2 +PortA,PA3,TIM15_CH2,USART2_RX,TIM2_CH4,TSC_G1_IO4,,,,,,,,,,,,,ADC1_IN3 +PortA,PA4,SPI1_NSS/I2S1_WS,USART2_CK,,TSC_G2_IO1,TIM14_CH1,USART6_TX,,,,,,,,,,,ADC1_IN4 +PortA,PA5,SPI1_SCK/I2S1_CK,CEC,TIM2_CH1_ETR,TSC_G2_IO2,,USART6_RX,,,,,,,,,,,ADC1_IN5 +PortA,PA6,SPI1_MISO/I2S1_MCK,TIM3_CH1,TIM1_BKIN,TSC_G2_IO3,USART3_CTS,TIM16_CH1,EVENTOUT,COMP1_OUT,,,,,,,,,ADC1_IN6 +PortA,PA7,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM1_CH1N,TSC_G2_IO4,TIM14_CH1,TIM17_CH1,EVENTOUT,COMP2_OUT,,,,,,,,,ADC1_IN7 +PortA,PA8,MCO,USART1_CK,TIM1_CH1,EVENTOUT,CRS_SYNC,,,,,,,,,,,, +PortA,PA9,TIM15_BKIN,USART1_TX,TIM1_CH2,TSC_G4_IO1,I2C1_SCL,MCO,,,,,,,,,,, +PortA,PA10,TIM17_BKIN,USART1_RX,TIM1_CH3,TSC_G4_IO2,I2C1_SDA,,,,,,,,,,,, +PortA,PA11,EVENTOUT,USART1_CTS,TIM1_CH4,TSC_G4_IO3,CAN1_RX,I2C2_SCL,,COMP1_OUT,,,,,,,,, +PortA,PA12,EVENTOUT,USART1_RTS,TIM1_ETR,TSC_G4_IO4,CAN1_TX,I2C2_SDA,,COMP2_OUT,,,,,,,,, +PortA,PA13,SWDIO,IR_OUT,,,,,,,,,,,,,,, +PortA,PA14,SWCLK,USART2_TX,,,,,,,,,,,,,,, +PortA,PA15,SPI1_NSS/I2S1_WS,USART2_RX,TIM2_CH1_ETR,EVENTOUT,USART4_RTS,,,,,,,,,,,, +PortB,PB0,EVENTOUT,TIM3_CH3,TIM1_CH2N,TSC_G3_IO2,USART3_CK,,,,,,,,,,,,ADC1_IN8 +PortB,PB1,TIM14_CH1,TIM3_CH4,TIM1_CH3N,TSC_G3_IO3,USART3_RTS,,,,,,,,,,,,ADC1_IN9 +PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,,,, +PortB,PB3,SPI1_SCK/I2S1_CK,EVENTOUT,TIM2_CH2,TSC_G5_IO1,USART5_TX,,,,,,,,,, +PortB,PB4,SPI1_MISO/I2S1_MCK,TIM3_CH1,EVENTOUT,TSC_G5_IO2,USART5_RX,TIM17_BKIN,,,,,,,,, +PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK/USART5_RTS,,,,,,,,,, +PortB,PB6,USART1_TX,I2C1_SCL,TIM16_CH1N,TSC_G5_IO3,,,,,,,,,,, +PortB,PB7,USART1_RX,I2C1_SDA,TIM17_CH1N,TSC_G5_IO4,USART4_CTS,,,,,,,,,, +PortB,PB8,CEC,I2C1_SCL,TIM16_CH1,TSC_SYNC,CAN1_RX,,,,,,,,,, +PortB,PB9,IR_OUT,I2C1_SDA,TIM17_CH1,EVENTOUT,CAN1_TX,SPI2_NSS/I2S2_WS,,,,,,,,, +PortB,PB10,CEC,I2C2_SCL,TIM2_CH3,TSC_SYNC,USART3_TX,SPI2_SCK/I2S2_CK,,,,,,,,, +PortB,PB11,EVENTOUT,I2C2_SDA,TIM2_CH4,TSC_G6_IO1,USART3_RX,,,,,,,,,, +PortB,PB12,SPI2_NSS/I2S2_WS,EVENTOUT,TIM1_BKIN,TSC_G6_IO2,USART3_CK,TIM15_BKIN,,,,,,,,, +PortB,PB13,SPI2_SCK/I2S2_CK,,TIM1_CH1N,TSC_G6_IO3,USART3_CTS,I2C2_SCL,,,,,,,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,TIM15_CH1,TIM1_CH2N,TSC_G6_IO4,USART3_RTS,I2C2_SDA,,,,,,,,, +PortB,PB15,SPI2_MOSI/I2S2_SD,TIM15_CH2,TIM1_CH3N,TIM15_CH1N,,,,,,,,,,, +PortC,PC0,EVENTOUT,USART7_TX,USART6_TX,,,,,,,,,,,,,,ADC1_IN10 +PortC,PC1,EVENTOUT,USART7_RX,USART6_RX,,,,,,,,,,,,,,ADC1_IN11 +PortC,PC2,EVENTOUT,SPI2_MISO/I2S2_MCK,USART8_TX,,,,,,,,,,,,,,ADC1_IN12 +PortC,PC3,EVENTOUT,SPI2_MOSI/I2S2_SD,USART8_RX,,,,,,,,,,,,,,ADC1_IN13 +PortC,PC4,EVENTOUT,USART3_TX,,,,,,,,,,,,,,,ADC1_IN14 +PortC,PC5,TSC_G3_IO1,USART3_RX,,,,,,,,,,,,,,,ADC1_IN15 +PortC,PC6,TIM3_CH1,USART7_TX,,,,,,,,,,,,,,, +PortC,PC7,TIM3_CH2,USART7_RX,,,,,,,,,,,,,,, +PortC,PC8,TIM3_CH3,USART8_TX,,,,,,,,,,,,,,, +PortC,PC9,TIM3_CH4,USART8_RX,,,,,,,,,,,,,,, +PortC,PC10,USART4_TX,USART3_TX,,,,,,,,,,,,,,, +PortC,PC11,USART4_RX,USART3_RX,,,,,,,,,,,,,,, +PortC,PC12,USART4_CK,USART3_CK,USART5_TX,,,,,,,,,,,,,, +PortC,PC13,,,,,,,,,,,,,,,,, +PortC,PC14,,,,,,,,,,,,,,,,, +PortC,PC15,,,,,,,,,,,,,,,,, +PortD,PD0,CAN1_RX,SPI2_NSS/I2S2_WS,,,,,,,,,,,,,,, +PortD,PD1,CAN1_TX,SPI2_SCK/I2S2_CK,,,,,,,,,,,,,,, +PortD,PD2,TIM3_ETR,USART3_RTS,USART5_RX,,,,,,,,,,,,,, +PortD,PD3,USART2_CTS,SPI2_MISO/I2S2_MCK,,,,,,,,,,,,,,, +PortD,PD4,USART2_RTS,SPI2_MOSI/I2S2_SD,,,,,,,,,,,,,,, +PortD,PD5,USART2_TX,,,,,,,,,,,,,,,, +PortD,PD6,USART2_RX,,,,,,,,,,,,,,,, +PortD,PD7,USART2_CK,,,,,,,,,,,,,,,, +PortD,PD8,USART3_TX,,,,,,,,,,,,,,,, +PortD,PD9,USART3_RX,,,,,,,,,,,,,,,, +PortD,PD10,USART3_CK,,,,,,,,,,,,,,,, +PortD,PD11,USART3_CTS,,,,,,,,,,,,,,,, +PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK/USART8_RTS,,,,,,,,,,,,,, +PortD,PD13,USART8_TX,TSC_G8_IO2,,,,,,,,,,,,,,, +PortD,PD14,USART8_RX,TSC_G8_IO3,,,,,,,,,,,,,,, +PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK/USART7_RTS,,,,,,,,,,,,,, +PortE,PE0,TIM16_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE1,TIM17_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE2,TIM3_ETR,TSC_G7_IO1,,,,,,,,,,,,,,, +PortE,PE3,TIM3_CH1,TSC_G7_IO2,,,,,,,,,,,,,,, +PortE,PE4,TIM3_CH2,TSC_G7_IO3,,,,,,,,,,,,,,, +PortE,PE5,TIM3_CH3,TSC_G7_IO4,,,,,,,,,,,,,,, +PortE,PE6,TIM3_CH4,,,,,,,,,,,,,,,, +PortE,PE7,TIM1_ETR,USART5_CK/USART5_RTS,,,,,,,,,,,,,,, +PortE,PE8,TIM1_CH1N,USART4_TX,,,,,,,,,,,,,,, +PortE,PE9,TIM1_CH1,USART4_RX,,,,,,,,,,,,,,, +PortE,PE10,TIM1_CH2N,USART5_TX,,,,,,,,,,,,,,, +PortE,PE11,TIM1_CH2,USART5_RX,,,,,,,,,,,,,,, +PortE,PE12,TIM1_CH3N,SPI1_NSS/I2S1_WS,,,,,,,,,,,,,,, +PortE,PE13,TIM1_CH3,SPI1_SCK/I2S1_CK,,,,,,,,,,,,,,, +PortE,PE14,TIM1_CH4,SPI1_MISO/I2S1_MCK,,,,,,,,,,,,,,, +PortE,PE15,TIM1_BKIN,SPI1_MOSI/I2S1_SD,,,,,,,,,,,,,,, +PortF,PF0,CRS_SYNC,I2C1_SDA,,,,,,,,,,,,,,, +PortF,PF1,,I2C1_SCL,,,,,,,,,,,,,,, +PortF,PF2,EVENTOUT,USART7_TX,USART7_CK/USART7_RTS,,,,,,,,,,,,,, +PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,, +PortF,PF6,,,,,,,,,,,,,,,,, +PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,, +PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f091xc.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f091xc.ld new file mode 100755 index 0000000..73b8442 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f091xc.ld @@ -0,0 +1,26 @@ +/* + GNU linker script for STM32F091xC +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K + FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 256K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20006800; /* room for a 6k stack */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f401_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f401_af.csv new file mode 100755 index 0000000..1acb8e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f401_af.csv @@ -0,0 +1,83 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS_AF,TIM1/TIM2,TIM3/TIM4/TIM5,TIM9/TIM10/TIM11,I2C1/I2C2/I2C3,SPI1/SPI2/I2S2/SPI3/I2S3/SPI4,SPI2/I2S2/SPI3/I2S3,SPI3/I2S3/USART1/USART2,USART6,I2C2/I2C3,OTG1_FS,,SDIO,,,,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,,,,,USART2_CTS,,,,,,,,EVENTOUT,ADC1_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,,,,,,,,EVENTOUT,ADC1_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,,,,,EVENTOUT,ADC1_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,,,,,,EVENTOUT,ADC1_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,,,,EVENTOUT,ADC1_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,,,SPI1_SCK,,,,,,,,,,EVENTOUT,ADC1_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,,,SPI1_MISO,,,,,,,,,,EVENTOUT,ADC1_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,,,SPI1_MOSI,,,,,,,,,,EVENTOUT,ADC1_IN7 +PortA,PA8,MCO_1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,OTG_FS_VBUS,,,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,USART6_TX,,OTG_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,USART6_RX,,OTG_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,,,,,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,,,,SDIO_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,,,,SDIO_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,,,,,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,,,,,,,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,,,,,,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN10 +PortC,PC1,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT,ADC1_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,ADC1_IN13 +PortC,PC4,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN14 +PortC,PC5,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN15 +PortC,PC6,,,TIM3_CH1,,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,,,EVENTOUT, +PortC,PC8,,,TIM3_CH3,,,,,,USART6_CK,,,,SDIO_D0,,,EVENTOUT, +PortC,PC9,MCO_2,,TIM3_CH4,,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,,,,,,SDIO_D2,,,EVENTOUT, +PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,,,,,,SDIO_D3,,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,,,,,,SDIO_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD1,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,,,,,SDIO_CMD,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,,USART2_RX,,,,,,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,,,,,EVENTOUT, +PortD,PD8,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD9,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD10,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD11,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,,,,,,,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,,,,,,,,EVENTOUT, +PortE,PE1,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,,,,,,,,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,,,,,,,,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,,,,,,,,,,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,,,,,,,,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,,,,,,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,,,,,,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,,,,,,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f401xd.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f401xd.ld new file mode 100755 index 0000000..7c0e790 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f401xd.ld @@ -0,0 +1,28 @@ +/* + GNU linker script for STM32F401xD +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3 are 16K, 4 is 64K */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 256K /* sectors 5,6 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20014000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f401xe.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f401xe.ld new file mode 100755 index 0000000..e76bbad --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f401xe.ld @@ -0,0 +1,28 @@ +/* + GNU linker script for STM32F401xE +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3 are 16K, 4 is 64K */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 384K /* sectors 5,6,7 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20014000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f405.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f405.ld new file mode 100755 index 0000000..0375491 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f405.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32F405 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3,4 are for filesystem */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5,6,7,8,9,10,11 */ + CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001c000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f405_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f405_af.csv new file mode 100755 index 0000000..e6d8fcc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f405_af.csv @@ -0,0 +1,142 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,,,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCK,,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,,DCMI_D10,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FSMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,,,,EVENTOUT,ADC123_IN10 +PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC123_IN14 +PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC123_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,,EVENTOUT, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,,EVENTOUT, +PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FSMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FSMC_D3,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,,,,,USART2_CTS,,,,,FSMC_CLK,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FSMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FSMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,,,USART2_RX,,,,,FSMC_NWAIT,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,,FSMC_NE1/FSMC_NCE2,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FSMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FSMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FSMC_D15,,,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,,,,FSMC_A16,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FSMC_A17,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,FSMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,FSMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,FSMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,,,,,FSMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,,,,,,,,,,FSMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,,,,,,,ETH_MII_TXD3,FSMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,,,,,,,FSMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,,,,,,,,FSMC_A20,DCMI_D4,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,,,,,,,,FSMC_A21,DCMI_D6,,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,,,,,,,,FSMC_A22,DCMI_D7,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,,,,,FSMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,,,,,FSMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,,,,,FSMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FSMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,,,,,,,,FSMC_D8,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,,,,,,,,FSMC_D9,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,,,,,,,,FSMC_D10,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,,,,,,,,FSMC_D11,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FSMC_D12,,,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FSMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FSMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FSMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FSMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FSMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FSMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,,,,,,,,FSMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,,,,,,,,FSMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,,,,,TIM13_CH1,,,FSMC_NIOWR,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,,,,,TIM14_CH1,,,FSMC_CD,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,FSMC_INTR,,,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,,,,,,,,,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FSMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FSMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FSMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FSMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FSMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FSMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FSMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FSMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FSMC_A14,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FSMC_A15,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FSMC_INT2,,,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FSMC_INT3,,,EVENTOUT, +PortG,PG8,,,,,,,,,USART6_RTS,,,ETH_PPS_OUT,,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,,,,FSMC_NE2/FSMC_NCE3,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,,,FSMC_NCE4_1/FSMC_NE3,,,EVENTOUT, +PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FSMC_NCE4_2,,,EVENTOUT, +PortG,PG12,,,,,,,,,USART6_RTS,,,,FSMC_NE4,,,EVENTOUT, +PortG,PG13,,,,,,,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FSMC_A24,,,EVENTOUT, +PortG,PG14,,,,,,,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FSMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,,,,EVENTOUT, +PortH,PH3,,,,,,,,,,,,ETH_MII_COL,,,,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,,,,,,,,,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,,,,,TIM12_CH1,,ETH_MII_RXD2,,,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,,,,,,,ETH_MII_RXD3,,,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,,DCMI_HSYNC,,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,,DCMI_D0,,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,,DCMI_D1,,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,,DCMI_D2,,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,,DCMI_D3,,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,,,,,,DCMI_D4,,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,,DCMI_D11,,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,,DCMI_D13,,EVENTOUT, +PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,,DCMI_D8,,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,,DCMI_D9,,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,,,,DCMI_D5,,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,,,,DCMI_VSYNC,,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,,,,DCMI_D6,,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,,,,DCMI_D7,,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,,,,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f411.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f411.ld new file mode 100755 index 0000000..9e3e6bc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f411.ld @@ -0,0 +1,28 @@ +/* + GNU linker script for STM32F411 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1,2,3 are 16K, 4 is 64K */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 384K /* sectors 5,6,7 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001c000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f411_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f411_af.csv new file mode 100755 index 0000000..d5b7a61 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f411_af.csv @@ -0,0 +1,84 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS_AF,TIM1/TIM2,TIM3/TIM4/TIM5,TIM9/TIM10/TIM11,I2C1/I2C2/I2C3,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3,SPI2/I2S2/SPI3/I2S3/SPI4/I2S4/SPI5/I2S5,SPI3/I2S3/USART1/USART2,USART6,I2C2/I2C3,,,SDIO,,,,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,,,,,USART2_CTS,,,,,,,,EVENTOUT,ADC1_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,SPI4_MOSI/I2S4_SD,,USART2_RTS,,,,,,,,EVENTOUT,ADC1_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,I2S2_CKIN,,USART2_TX,,,,,,,,EVENTOUT,ADC1_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,I2S2_MCK,,USART2_RX,,,,,,,,EVENTOUT,ADC1_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,,,,EVENTOUT,ADC1_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,,,SPI1_SCK/I2S1_CK,,,,,,,,,,EVENTOUT,ADC1_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,,,SPI1_MISO,I2S2_MCK,,,,,,SDIO_CMD,,,EVENTOUT,ADC1_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,,,SPI1_MOSI/I2S1_SD,,,,,,,,,,EVENTOUT,ADC1_IN7 +PortA,PA8,MCO_1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,USB_FS_SOF,,SDIO_D1,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,USB_FS_VBUS,,SDIO_D2,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,SPI5_MOSI/I2S5_SD,USART1_RX,,,USB_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,SPI4_MISO,USART1_CTS,USART6_TX,,USB_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,SPI5_MISO,USART1_RTS,USART6_RX,,USB_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART1_TX,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,ADC1_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,SDIO_D0,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,,,SDIO_D3,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,SDIO_D0,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,SPI5_MOSI/I2S5_SD,,,I2C3_SDA,,,SDIO_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,I2C2_SDA,,,SDIO_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,I2S3_MCK,,,,,,SDIO_D7,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,I2S2_CKIN,,,,,,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,SPI4_NSS/I2S4_WS,SPI3_SCK/I2S3_CK,,,,,,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,SPI4_SCK/I2S4_CK,,,,,,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,,,SPI2_MISO,I2S2ext_SD,,,,,,SDIO_D6,,,EVENTOUT, +PortB,PB15,RTC_50Hz,TIM1_CH3N,,,,SPI2_MOSI/I2S2_SD,,,,,,,SDIO_CK,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN10 +PortC,PC1,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,,,,,,EVENTOUT,ADC1_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,ADC1_IN13 +PortC,PC4,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN14 +PortC,PC5,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN15 +PortC,PC6,,,TIM3_CH1,,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,,,SPI2_SCK/I2S2_CK,I2S3_MCK,,USART6_RX,,,,SDIO_D7,,,EVENTOUT, +PortC,PC8,,,TIM3_CH3,,,,,,USART6_CK,,,,SDIO_D0,,,EVENTOUT, +PortC,PC9,MCO_2,,TIM3_CH4,,I2C3_SDA,I2S2_CKIN,,,,,,,SDIO_D1,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,,,,,,SDIO_D2,,,EVENTOUT, +PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,,,,,,SDIO_D3,,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,,,,,,SDIO_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD1,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,,,,,SDIO_CMD,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,,USART2_RX,,,,,,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,,,,,EVENTOUT, +PortD,PD8,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD9,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD10,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD11,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,,,,,,,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,,,,,,,,EVENTOUT, +PortE,PE1,,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SPI5_MISO,,,,,,,,,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,,,,,,,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,,,,,,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,,,,,,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,,,,,,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,,,,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS/I2S4_WS,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK/I2S4_CK,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,SPI5_MISO,,,,,,,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI/I2S4_SD,SPI5_MOSI/I2S5_SD,,,,,,,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f429.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f429.ld new file mode 100755 index 0000000..d80f7f5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f429.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32F429i-Discovery kit with external 8MByte SDRam +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0, 16 KiB */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1-4: 3*16K+64K */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5-11 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K + SDRAM(xrw) : ORIGIN = 0xC0000000, LENGTH = 8192K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001c000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f429_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f429_af.csv new file mode 100755 index 0000000..4ee8edd --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f429_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/2/3/4/5/6,SPI2/3/SAI1,SPI3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/LCD,OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI,LCD,SYS, +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10 +PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,,FMC_NE1/FMC_NCE2,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,,,,FMC_A16,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FMC_A17,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,UART8_Rx,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,,,,,,UART8_Tx,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_Rx,,,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_Tx,,,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_Rx,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_Tx,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,,,FMC_NIOWR,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,,,FMC_CD,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,FMC_INTR,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_INT2,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT3,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,,,,FMC_NE2/FMC_NCE3,DCMI_VSYNC(1),,EVENTOUT, +PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NCE4_1/FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FMC_NCE4_2,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,,EVENTOUT, +PortG,PG14,,,,,,SPI6_MOSI,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,,,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,DCMI_D8,,, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f439.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f439.ld new file mode 100755 index 0000000..16c606e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f439.ld @@ -0,0 +1,28 @@ +/* + GNU linker script for STM32F439 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5-11 are 128K */ + FLASH_FS (rx) : ORIGIN = 0x08100000, LENGTH = 256K /* sectors 12-17 are 4*16K+64K+128K */ + FLASH_FS2 (rx) : ORIGIN = 0x08140000, LENGTH = 128K /* sector 18 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K + CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* top end of the stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2002c000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f439_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f439_af.csv new file mode 100755 index 0000000..4fc1f11 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f439_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/2/3/4/5/6,SPI2/3/SAI1,SPI3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/LCD,OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI,LCD,SYS, +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10 +PortC,PC1,,,,,,,,,,,,ETH_MDC,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,I2S2ext_SD,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,,,,SDIO_D1,DCMI_D3,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,,,I2S3ext_SD,SPI3_MISO,USART3_RX,UART4_RX,,,,SDIO_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,UART5_RX,,,,SDIO_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,,FMC_NE1/FMC_NCE2,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,,,,FMC_A16,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FMC_A17,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,UART8_RX,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,SPI3_NSS,,,,,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,SPI3_SCK,,,,,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,SPI3_MISO,,,,,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,SP3_MOSI,,,,,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,,,FMC_NIOWR,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,,,FMC_CD,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,FMC_INTR,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_INT2,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT3,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,,,,FMC_NE2/FMC_NCE3,DCMI_VSYNC(1),,EVENTOUT, +PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NCE4_1/FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,FMC_NCE4_2,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,,EVENTOUT, +PortG,PG14,,,,,,SPI6_MOSI,,,USART6_TX,,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,,,,,,,,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,,,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,DCMI_D8,,, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f4xx_prefix.c b/src/openmv/src/micropython/ports/stm32/boards/stm32f4xx_prefix.c new file mode 100755 index 0000000..3bcd6e6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f4xx_prefix.c @@ -0,0 +1,32 @@ +// stm32f4xx_prefix.c becomes the initial portion of the generated pins file. + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .reg = (af_ptr) \ +} + +#define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_ ## p_port ## p_pin, \ + .port = PORT_ ## p_port, \ + .pin = (p_pin), \ + .num_af = (sizeof(p_af) / sizeof(pin_af_obj_t)), \ + .pin_mask = (1 << ((p_pin) & 0x0f)), \ + .gpio = GPIO ## p_port, \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f722.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f722.ld new file mode 100755 index 0000000..f2a1d85 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f722.ld @@ -0,0 +1,27 @@ +/* + GNU linker script for STM32F722, STM32F723, STM32F732, STM32F733 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sectors 0,1 */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* sectors 2-7 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* DTCM+SRAM1+SRAM2 */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20038000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f722_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f722_af.csv new file mode 100755 index 0000000..24500f5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f722_af.csv @@ -0,0 +1,146 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1,I2C1/2/3/USART1,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5,SPI2/I2S2/SPI3/I2S3/SPI3/I2S3/SAI1/UART4,SPI2/I2S2/SPI3/I2S3/USART1/2/3/UART5,SAI2/USART6/UART4/5/7/8/OTG1_FS,CAN1/TIM12/13/14/QUADSPI/FMC/OTG2_HS,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2,UART7/FMC/SDMMC1/OTG2_FS,,,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,,,,,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,,,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,,,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,,OTG_HS_ULPI_D1,,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,OTG_HS_ULPI_D7,,FMC_SDCKE1,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,QUADSPI_BK1_NCS,,FMC_SDNE1,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,,SDMMC1_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,,,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,,OTG_HS_ULPI_D5,,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,,OTG_HS_ULPI_D6,,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,I2S1_MCK,,,,,,,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,,,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,,,EVENTOUT, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,,,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,,,,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,,,EVENTOUT, +PortG,PG8,,,,,,,,,USART6_RTS,,,,FMC_SDCLK,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,SAI2_SD_B,SDMMC2_D1,FMC_NE3,,,EVENTOUT, +PortG,PG11,,,,,,,,,,,SDMMC2_D2,,,,,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,,,,USART6_RTS,,,SDMMC2_D3,FMC_NE4,,,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,,,,USART6_CTS,,,,FMC_A24,,,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,,,,USART6_TX,QUADSPI_BK2_IO3,,,FMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,,FMC_SDCKE0,,,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,,FMC_SDNE0,,,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,,,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,,,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,,,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,,,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,,,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,,,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,,,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,,,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,,,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,,,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,,,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,,,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,,,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,,,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,,EVENTOUT, +PortI,PI10,,,,,,,,,,,,,FMC_D31,,,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f746.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f746.ld new file mode 100755 index 0000000..b586445 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f746.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32F405 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */ + FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x20010000, LENGTH = 256K /* SRAM1 = 240K, SRAM2 = 16K */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2004c000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f746_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f746_af.csv new file mode 100755 index 0000000..8069edc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f746_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/CEC,I2C1/2/3/4/CEC,SPI1/2/3/4/5/6,SPI3/SAI1,SPI2/3/USART1/2/3/UART5/SPDIFRX,SAI2/USART6/UART4/5/7/8/SPDIFRX,CAN1/2/TIM12/13/14/QUADSPI/LCD,SAI2/QUADSPI/OTG2_HS/OTG1_FS,ETH/OTG1_FS,FMC/SDMMC1/OTG2_FS,DCMI,LCD,SYS +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,,,,,,EVENTOUT +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT +PortB,PB6,,,TIM4_CH1,HDMI_CEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT +PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT +PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT +PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT +PortC,PC4,,,,,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT +PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,DCMI_D2,,EVENTOUT +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT +PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,,FMC_NE1,,,EVENTOUT +PortD,PD8,,,,,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT +PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT +PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT +PortF,PF10,,,,,,,,,,,,,,DCMI_D11,LCD_DE,EVENTOUT +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT +PortF,PF13,,,,,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT +PortF,PF14,,,,,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT +PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT +PortG,PG9,,,,,,,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT +PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT +PortG,PG11,,,,,,,,SPDIFRX_IN0,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT +PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT +PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT +PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT +PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT +PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT +PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT +PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT +PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT +PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f767.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f767.ld new file mode 100755 index 0000000..c05fd80 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f767.ld @@ -0,0 +1,30 @@ +/* + GNU linker script for STM32F767 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ + FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20078000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f767_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32f767_af.csv new file mode 100755 index 0000000..0c8069e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f767_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT, +PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32f769.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32f769.ld new file mode 100755 index 0000000..d6da439 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32f769.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32F769 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */ + FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 384K /* SRAM1 = 368K, SRAM2 = 16K */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20078000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32h743.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32h743.ld new file mode 100755 index 0000000..ca429ed --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32h743.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32H743 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */ + FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */ + FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2407C000; /* tunable */ diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32h743_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32h743_af.csv new file mode 100755 index 0000000..d008ba6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32h743_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT, +PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT, +PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT, +PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT, +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO/I2S1_SDI,,,SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP12,MDIOS_MDC,TIM1_BKIN_COMP12,DCMI_PIXCLK,LCD_G2,EVENTOUT, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT, +PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS/USART1_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,HRTIM_FLT1,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,UART7_TX,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT, +PortB,PB2,,,SAI1_D1,,DFSDM_CKIN1,,SAI1_SD_A,SPI3_MOSI/I2S3_SDO,SAI4_SD_A,QUADSPI_CLK,SAI4_D1,ETH_TX_ER,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,HRTIM_FLT4,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,SDMMC2_D2,,UART7_RX,,,,EVENTOUT, +PortB,PB4,NJTRST,TIM16_BKIN,TIM3_CH1,HRTIM_EEV6,,SPI1_MISO/I2S1_SDI,SPI3_MISO/I2S3_SDI,SPI2_NSS/I2S2_WS,SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT, +PortB,PB5,,TIM17_BKIN,TIM3_CH2,HRTIM_EEV7,I2C1_SMBA,SPI1_MOSI/I2S1_SDO,I2C4_SMBA,SPI3_MOSI/I2S3_SDO,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,UART5_RX,EVENTOUT, +PortB,PB6,,TIM16_CH1N,TIM4_CH1,HRTIM_EEV8,I2C1_SCL,HDMI_CEC,I2C4_SCL,USART1_TX,LPUART1_TX,CAN2_TX,QUADSPI_BK1_NCS,DFSDM_DATIN5,FMC_SDNE1,DCMI_D5,UART5_TX,EVENTOUT, +PortB,PB7,,TIM17_CH1N,TIM4_CH2,HRTIM_EEV9,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,CAN2_TXFD,,DFSDM_CKIN5,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS/USART3_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, +PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT, +PortC,PC1,TRACED0,,SAI1_D1,DFSDM_DATIN0,DFSDM_CKIN4,SPI2_MOSI/I2S2_SDO,SAI1_SD_A,,SAI4_SD_A,SDMMC2_CK,SAI4_D1,ETH_MDC,MDIOS_MDC,,,EVENTOUT, +PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT, +PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT, +PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT, +PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT, +PortC,PC6,,HRTIM_CHA1,TIM3_CH1,TIM8_CH1,DFSDM_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,TRGIO,HRTIM_CHA2,TIM3_CH2,TIM8_CH2,DFSDM_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI_TX,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,HRTIM_CHB1,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_RTS,FMC_NE2/FMC_NCE,,SWPMI_RX,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,QUADSPI_BK1_IO0,LCD_G3,SWPMI_SUSPEND,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,HRTIM_EEV1,DFSDM_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,HRTIM_FLT2,DFSDM_DATIN5,,,SPI3_MISO/I2S3_SDI,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,HRTIM_EEV2,,,,SPI3_MOSI/I2S3_SDO,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT, +PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT, +PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT, +PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, +PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT, +PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,SAI3_MCLK_A,,UART8_RTS,,,,FMC_D1/FMC_DA1,,,EVENTOUT, +PortE,PE0,,LPTIM1_ETR,TIM4_ETR,HRTIM_SCIN,LPTIM2_ETR,,,,UART8_RX,CAN1_RXFD,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,LPTIM1_IN2,,HRTIM_SCOUT,,,,,UART8_TX,CAN1_TXFD,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,SAI4_MCLK_A,QUADSPI_BK1_IO2,SAI4_CK1,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,SAI4_SD_B,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,SAI1_D2,DFSDM_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,SAI4_FS_A,,SAI4_D2,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,SAI1_CK2,DFSDM_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,SAI4_SCK_A,,SAI4_CK2,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,SAI4_SD_A,SAI4_D1,SAI2_MCK_B,TIM1_BKIN2_COMP12,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,DFSDM_DATIN2,,,,UART7_RX,,,QUADSPI_BK2_IO0,,FMC_D4/FMC_DA4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,DFSDM_CKIN2,,,,UART7_TX,,,QUADSPI_BK2_IO1,,FMC_D5/FMC_DA5,COMP_2_OUT,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,DFSDM_CKOUT,,,,UART7_RTS,,,QUADSPI_BK2_IO2,,FMC_D6/FMC_DA6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,DFSDM_DATIN4,,,,UART7_CTS,,,QUADSPI_BK2_IO3,,FMC_D7/FMC_DA7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,DFSDM_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8/FMC_DA8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,DFSDM_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP_1_OUT,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,DFSDM_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP_2_OUT,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11/FMC_DA11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT, +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT, +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT, +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT, +PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT, +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP12,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP12,FMC_A13,,,EVENTOUT, +PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP12,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,TIM17_BKIN,HRTIM_CHE1,,,,,,,,QUADSPI_BK1_NCS,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,HRTIM_CHE2,,,,SAI1_MCLK_A,USART6_CK,,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,TIM8_ETR,,SPI6_NSS,,USART6_RTS,SPDIFRX_IN2,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS/USART6_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,CAN1_TXFD,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,CAN1_RXFD,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,TIM8_BKIN2_COMP12,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO/I2S2_SDI,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SDO,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,TIM8_BKIN_COMP12,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,CAN1_RXFD,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,ETH_TX_ER,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,TRGIN,,,TIM8_CH2N,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,TRGOUT,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_B4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP12,TIM1_BKIN_COMP12,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32l476_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32l476_af.csv new file mode 100755 index 0000000..01db895 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32l476_af.csv @@ -0,0 +1,116 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,, +,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP +PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7, +PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9, +PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,USART3_CTS,,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12, +PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOUT,, +PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM +PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,, +PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, +PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1, +PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN3, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4, +PortC,PC4,,,,,,,,USART3_TX,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM +PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM_CKIN3,,,TSC_G4_IO1,,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM_DATIN3,,,TSC_G4_IO2,,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,, +PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,,,,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,, +PortC,PC10,,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,, +PortC,PC12,,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,, +PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,, +PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,, +PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, +PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,,,FMC_NOE,,,EVENTOUT,, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,, +PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,, +PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,, +PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,, +PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,, +PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, +PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,, +PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,, +PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,, +PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,, +PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,FMC_A22,SAI1_SD_A,,EVENTOUT,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,, +PortE,PE11,,TIM1_CH2,,,,,DFSDM_CKIN4,,,TSC_G5_IO2,QUADSPI_NCS,,FMC_D8,,,EVENTOUT,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8, +PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9, +PortF,PF7,,,TIM5_CH2,,,,,,,,,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10, +PortF,PF8,,,TIM5_CH3,,,,,,,,,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11, +PortF,PF9,,,TIM5_CH4,,,,,,,,,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12, +PortF,PF10,,,,,,,,,,,,,,,TIM15_CH2,EVENTOUT,ADC3_IN13, +PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT,, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,, +PortF,PF13,,,,,,,DFSDM_DATIN6,,,,,,FMC_A7,,,EVENTOUT,, +PortF,PF14,,,,,,,DFSDM_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,, +PortF,PF15,,,,,,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,, +PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,, +PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,, +PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,, +PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,, +PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,, +PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,, +PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,, +PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,, +PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, +PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,, +PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, +PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,, +PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,, +PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32l476xe.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32l476xe.ld new file mode 100755 index 0000000..3192951 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32l476xe.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32L476XE +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ + FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 368K /* sectors 8-191 */ + FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 128K /* sectors 192-255 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20014000; /* tunable */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32l476xg.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32l476xg.ld new file mode 100755 index 0000000..59c5d90 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32l476xg.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32L476XG +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ + FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 496K /* sectors 8-255 */ + FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 512K /* sectors 256-511 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20014000; /* tunable */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32l496_af.csv b/src/openmv/src/micropython/ports/stm32/boards/stm32l496_af.csv new file mode 100755 index 0000000..311770a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32l496_af.csv @@ -0,0 +1,142 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,, +,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP,DAC +PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,, +PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,DCMI_HSYNC,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,,DAC1_OUT1 +PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,,DAC1_OUT2 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,DCMI_PIXCLK,SPI1_MISO,,USART3_CTS,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11,, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,, +PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,SWPMI1_IO,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,,, +PortA,PA9,,TIM1_CH2,,SPI2_SCK,I2C1_SCL,DCMI_D0,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, +PortA,PA10,,TIM1_CH3,,,I2C1_SDA,DCMI_D1,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT,,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,SWPMI1_TX,SAI1_SD_B,,EVENTOUT,,, +PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,OTG_FS_SOF,,SWPMI1_RX,SAI1_FS_B,,EVENTOUT,,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS/USART3_DE,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,SPI1_NSS,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS/USART3_DE,LPUART1_RTS/LPUART1_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM, +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM1_CKIN0,,,,,LCD_VLCD,,,,EVENTOUT,,COMP1_INP, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, +PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP, +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN2_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,DCMI_D10,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,I2C4_SCL,DFSDM1_DATIN5,USART1_TX,CAN2_TX,TSC_G2_IO3,DCMI_D5,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP, +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,I2C4_SDA,DFSDM1_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,DCMI_VSYNC,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM, +PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM1_DATIN6,,,CAN1_RX,DCMI_D6,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,, +PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM1_CKIN6,,,CAN1_TX,DCMI_D7,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,, +PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,DFSDM1_DATIN7,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,, +PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM1_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN2_TX,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM1_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,, +PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,DFSDM1_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, +PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,SPI2_MOSI,I2C3_SDA,,DFSDM1_CKIN4,,LPUART1_TX,,QUADSPI_BK2_IO0,LCD_SEG19,,SAI1_SD_A,,EVENTOUT,ADC123_IN2,, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM1_CKOUT,,,,QUADSPI_BK2_IO1,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,QUADSPI_BK2_IO2,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,, +PortC,PC4,,,,,,,,USART3_TX,,,QUADSPI_BK2_IO3,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM, +PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP, +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM1_CKIN3,,,TSC_G4_IO1,DCMI_D0,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM1_DATIN3,,,TSC_G4_IO2,DCMI_D1,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,DCMI_D2,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,, +PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,DCMI_D3,,I2C3_SDA,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,, +PortC,PC10,TRACED1,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,DCMI_D8,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,, +PortC,PC11,,,,,,QUADSPI_BK2_NCS,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,DCMI_D4,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,DCMI_D9,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, +PortD,PD0,,,,,,SPI2_NSS,DFSDM1_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,, +PortD,PD1,,,,,,SPI2_SCK,DFSDM1_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,, +PortD,PD3,,,,SPI2_SCK,DCMI_D5,SPI2_MISO,DFSDM1_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,FMC_CLK,,,EVENTOUT,,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS/USART2_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,, +PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,FMC_NWE,,,EVENTOUT,,, +PortD,PD6,,,,,DCMI_D10,QUADSPI_BK2_IO1,DFSDM1_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,, +PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,FMC_NE1,,,EVENTOUT,,, +PortD,PD8,,,,,,,,USART3_TX,,,DCMI_HSYNC,LCD_SEG28,FMC_D13,,,EVENTOUT,,, +PortD,PD9,,,,,,,,USART3_RX,,,DCMI_PIXCLK,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,, +PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,, +PortD,PD13,,,TIM4_CH2,,I2C4_SDA,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,, +PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,, +PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,, +PortE,PE0,,,TIM4_ETR,,,,,,,,DCMI_D2,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,, +PortE,PE1,,,,,,,,,,,DCMI_D3,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM1_DATIN3,,,TSC_G7_IO3,DCMI_D4,,FMC_A20,SAI1_FS_A,,EVENTOUT,,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM1_CKIN3,,,TSC_G7_IO4,DCMI_D6,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,DCMI_D7,,FMC_A22,SAI1_SD_A,,EVENTOUT,,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,, +PortE,PE11,,TIM1_CH2,,,,,DFSDM1_CKIN4,,,TSC_G5_IO2,QUADSPI_BK1_NCS,,FMC_D8,,,EVENTOUT,,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM1_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM1_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,,, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,,, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,,, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,,, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6,, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7,, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8,, +PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,QUADSPI_BK1_IO3,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,, +PortF,PF7,,,TIM5_CH2,,,,,,,,QUADSPI_BK1_IO2,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,, +PortF,PF8,,,TIM5_CH3,,,,,,,,QUADSPI_BK1_IO0,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,, +PortF,PF9,,,TIM5_CH4,,,,,,,,QUADSPI_BK1_IO1,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,, +PortF,PF10,,,,QUADSPI_CLK,,,,,,,DCMI_D11,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,, +PortF,PF11,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,, +PortF,PF15,,,,,I2C4_SDA,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,,, +PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,,, +PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,,, +PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,, +PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,, +PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,, +PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,, +PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT,SAI1_MCLK_A,,EVENTOUT,,, +PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,, +PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,, +PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,, +PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,, +PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,, +PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH2,,,,QUADSPI_BK2_IO0,,,,,,,,,,,,EVENTOUT,,, +PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH4,,,,,I2C2_SCL,,,,,,,,,,,EVENTOUT,,, +PortH,PH5,,,,,I2C2_SDA,,,,,,DCMI_PIXCLK,,,,,EVENTOUT,,, +PortH,PH6,,,,,I2C2_SMBA,,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortH,PH7,,,,,I2C3_SCL,,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortH,PH8,,,,,I2C3_SDA,,,,,,DCMI_HSYNC,,,,,EVENTOUT,,, +PortH,PH9,,,,,I2C3_SMBA,,,,,,DCMI_D0,,,,,EVENTOUT,,, +PortH,PH10,,,TIM5_CH1,,,,,,,,DCMI_D1,,,,,EVENTOUT,,, +PortH,PH11,,,TIM5_CH2,,,,,,,,DCMI_D2,,,,,EVENTOUT,,, +PortH,PH12,,,TIM5_CH3,,,,,,,,DCMI_D3,,,,,EVENTOUT,,, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT,,, +PortH,PH14,,,,TIM8_CH2N,,,,,,,DCMI_D4,,,,,EVENTOUT,,, +PortH,PH15,,,,TIM8_CH3N,,,,,,,DCMI_D11,,,,,EVENTOUT,,, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortI,PI1,,,,,,SPI2_SCK,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI,,,,,DCMI_D10,,,,,EVENTOUT,,, +PortI,PI4,,,,TIM8_BKIN,,,,,,,DCMI_D5,,,,,EVENTOUT,,, +PortI,PI5,,,,TIM8_CH1,,,,,,,DCMI_VSYNC,,,,,EVENTOUT,,, +PortI,PI6,,,,TIM8_CH2,,,,,,,DCMI_D6,,,,,EVENTOUT,,, +PortI,PI7,,,,TIM8_CH3,,,,,,,DCMI_D7,,,,,EVENTOUT,,, +PortI,PI8,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT,,, +PortI,PI10,,,,,,,,,,,,,,,,EVENTOUT,,, +PortI,PI11,,,,,,,,,,,,,,,,EVENTOUT,,, diff --git a/src/openmv/src/micropython/ports/stm32/boards/stm32l496xg.ld b/src/openmv/src/micropython/ports/stm32/boards/stm32l496xg.ld new file mode 100755 index 0000000..b420873 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/boards/stm32l496xg.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32L496XG +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ + FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 596K /* sectors 8-305 */ + FLASH_FS (r) : ORIGIN = 0x08099000, LENGTH = 412K /* sectors 306-511 412 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K + SRAM2 (xrw) : ORIGIN = 0x20040000, LENGTH = 62K /* leave 2K for flash fs cache */ + FS_CACHE(xrw) : ORIGIN = 0x2004f800, LENGTH = 2K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); + +/* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001C000; /* tunable */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/src/openmv/src/micropython/ports/stm32/bufhelper.c b/src/openmv/src/micropython/ports/stm32/bufhelper.c new file mode 100755 index 0000000..7951196 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/bufhelper.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "bufhelper.h" + +void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data) { + if (MP_OBJ_IS_INT(o)) { + tmp_data[0] = mp_obj_get_int(o); + bufinfo->buf = tmp_data; + bufinfo->len = 1; + bufinfo->typecode = 'B'; + } else { + mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ); + } +} + +mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr) { + if (MP_OBJ_IS_INT(o)) { + // allocate a new bytearray of given length + vstr_init_len(vstr, mp_obj_get_int(o)); + return MP_OBJ_NULL; + } else { + // get the existing buffer + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_WRITE); + vstr->buf = bufinfo.buf; + vstr->len = bufinfo.len; + return o; + } +} diff --git a/src/openmv/src/micropython/ports/stm32/bufhelper.h b/src/openmv/src/micropython/ports/stm32/bufhelper.h new file mode 100755 index 0000000..12c79c2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/bufhelper.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_BUFHELPER_H +#define MICROPY_INCLUDED_STM32_BUFHELPER_H + +void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data); +mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr); + +#endif // MICROPY_INCLUDED_STM32_BUFHELPER_H diff --git a/src/openmv/src/micropython/ports/stm32/can.c b/src/openmv/src/micropython/ports/stm32/can.c new file mode 100755 index 0000000..b92389a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/can.c @@ -0,0 +1,1093 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objtuple.h" +#include "py/objarray.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/binary.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "bufhelper.h" +#include "can.h" +#include "irq.h" + +#if MICROPY_HW_ENABLE_CAN + +#define MASK16 (0) +#define LIST16 (1) +#define MASK32 (2) +#define LIST32 (3) + +enum { + CAN_STATE_STOPPED, + CAN_STATE_ERROR_ACTIVE, + CAN_STATE_ERROR_WARNING, + CAN_STATE_ERROR_PASSIVE, + CAN_STATE_BUS_OFF, +}; + +/// \moduleref pyb +/// \class CAN - controller area network communication bus +/// +/// CAN implements the standard CAN communications protocol. At +/// the physical level it consists of 2 lines: RX and TX. Note that +/// to connect the pyboard to a CAN bus you must use a CAN transceiver +/// to convert the CAN logic signals from the pyboard to the correct +/// voltage levels on the bus. +/// +/// Note that this driver does not yet support filter configuration +/// (it defaults to a single filter that lets through all messages), +/// or bus timing configuration (except for setting the prescaler). +/// +/// Example usage (works without anything connected): +/// +/// from pyb import CAN +/// can = pyb.CAN(1, pyb.CAN.LOOPBACK) +/// can.send('message!', 123) # send message with id 123 +/// can.recv(0) # receive message on FIFO 0 + +typedef enum _rx_state_t { + RX_STATE_FIFO_EMPTY = 0, + RX_STATE_MESSAGE_PENDING, + RX_STATE_FIFO_FULL, + RX_STATE_FIFO_OVERFLOW, +} rx_state_t; + +typedef struct _pyb_can_obj_t { + mp_obj_base_t base; + mp_obj_t rxcallback0; + mp_obj_t rxcallback1; + mp_uint_t can_id : 8; + bool is_enabled : 1; + bool extframe : 1; + byte rx_state0; + byte rx_state1; + uint16_t num_error_warning; + uint16_t num_error_passive; + uint16_t num_bus_off; + CAN_HandleTypeDef can; +} pyb_can_obj_t; + +STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in); + +STATIC uint8_t can2_start_bank = 14; + +// assumes Init parameters have been set up correctly +STATIC bool can_init(pyb_can_obj_t *can_obj) { + CAN_TypeDef *CANx = NULL; + uint32_t sce_irq = 0; + const pin_obj_t *pins[2]; + + switch (can_obj->can_id) { + #if defined(MICROPY_HW_CAN1_TX) + case PYB_CAN_1: + CANx = CAN1; + sce_irq = CAN1_SCE_IRQn; + pins[0] = MICROPY_HW_CAN1_TX; + pins[1] = MICROPY_HW_CAN1_RX; + __CAN1_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_CAN2_TX) + case PYB_CAN_2: + CANx = CAN2; + sce_irq = CAN2_SCE_IRQn; + pins[0] = MICROPY_HW_CAN2_TX; + pins[1] = MICROPY_HW_CAN2_RX; + __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well + __CAN2_CLK_ENABLE(); + break; + #endif + + default: + return false; + } + + // init GPIO + uint32_t mode = MP_HAL_PIN_MODE_ALT; + uint32_t pull = MP_HAL_PIN_PULL_UP; + for (int i = 0; i < 2; i++) { + if (!mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_CAN, can_obj->can_id)) { + return false; + } + } + + // init CANx + can_obj->can.Instance = CANx; + HAL_CAN_Init(&can_obj->can); + + can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + NVIC_SetPriority(sce_irq, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); + + return true; +} + +void can_init0(void) { + for (uint i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) { + MP_STATE_PORT(pyb_can_obj_all)[i] = NULL; + } +} + +void can_deinit(void) { + for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) { + pyb_can_obj_t *can_obj = MP_STATE_PORT(pyb_can_obj_all)[i]; + if (can_obj != NULL) { + pyb_can_deinit(MP_OBJ_FROM_PTR(can_obj)); + } + } +} + +STATIC void can_clearfilter(uint32_t f) { + CAN_FilterConfTypeDef filter; + + filter.FilterIdHigh = 0; + filter.FilterIdLow = 0; + filter.FilterMaskIdHigh = 0; + filter.FilterMaskIdLow = 0; + filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; + filter.FilterNumber = f; + filter.FilterMode = CAN_FILTERMODE_IDMASK; + filter.FilterScale = CAN_FILTERSCALE_16BIT; + filter.FilterActivation = DISABLE; + filter.BankNumber = can2_start_bank; + + HAL_CAN_ConfigFilter(NULL, &filter); +} + +STATIC int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms) { + volatile uint32_t *rfr; + if (fifo == CAN_FIFO0) { + rfr = &can->RF0R; + } else { + rfr = &can->RF1R; + } + + // Wait for a message to become available, with timeout + uint32_t start = HAL_GetTick(); + while ((*rfr & 3) == 0) { + MICROPY_EVENT_POLL_HOOK + if (HAL_GetTick() - start >= timeout_ms) { + return -MP_ETIMEDOUT; + } + } + + // Read message data + CAN_FIFOMailBox_TypeDef *box = &can->sFIFOMailBox[fifo]; + msg->IDE = box->RIR & 4; + if (msg->IDE == CAN_ID_STD) { + msg->StdId = box->RIR >> 21; + } else { + msg->ExtId = box->RIR >> 3; + } + msg->RTR = box->RIR & 2; + msg->DLC = box->RDTR & 0xf; + msg->FMI = box->RDTR >> 8 & 0xff; + uint32_t rdlr = box->RDLR; + msg->Data[0] = rdlr; + msg->Data[1] = rdlr >> 8; + msg->Data[2] = rdlr >> 16; + msg->Data[3] = rdlr >> 24; + uint32_t rdhr = box->RDHR; + msg->Data[4] = rdhr; + msg->Data[5] = rdhr >> 8; + msg->Data[6] = rdhr >> 16; + msg->Data[7] = rdhr >> 24; + + // Release (free) message from FIFO + *rfr |= CAN_RF0R_RFOM0; + + return 0; // success +} + +// We have our own version of CAN transmit so we can handle Timeout=0 correctly. +STATIC HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) { + uint32_t transmitmailbox; + uint32_t tickstart; + uint32_t rqcpflag; + uint32_t txokflag; + + // Check the parameters + assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE)); + assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR)); + assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC)); + + // Select one empty transmit mailbox + if ((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) { + transmitmailbox = CAN_TXMAILBOX_0; + rqcpflag = CAN_FLAG_RQCP0; + txokflag = CAN_FLAG_TXOK0; + } else if ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) { + transmitmailbox = CAN_TXMAILBOX_1; + rqcpflag = CAN_FLAG_RQCP1; + txokflag = CAN_FLAG_TXOK1; + } else if ((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2) { + transmitmailbox = CAN_TXMAILBOX_2; + rqcpflag = CAN_FLAG_RQCP2; + txokflag = CAN_FLAG_TXOK2; + } else { + transmitmailbox = CAN_TXSTATUS_NOMAILBOX; + } + + if (transmitmailbox != CAN_TXSTATUS_NOMAILBOX) { + // Set up the Id + hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ; + if (hcan->pTxMsg->IDE == CAN_ID_STD) { + assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId)); + hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21) | \ + hcan->pTxMsg->RTR); + } else { + assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId)); + hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3) | \ + hcan->pTxMsg->IDE | \ + hcan->pTxMsg->RTR); + } + + // Set up the DLC + hcan->pTxMsg->DLC &= (uint8_t)0x0000000F; + hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0; + hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC; + + // Set up the data field + hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3] << 24) | + ((uint32_t)hcan->pTxMsg->Data[2] << 16) | + ((uint32_t)hcan->pTxMsg->Data[1] << 8) | + ((uint32_t)hcan->pTxMsg->Data[0])); + hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7] << 24) | + ((uint32_t)hcan->pTxMsg->Data[6] << 16) | + ((uint32_t)hcan->pTxMsg->Data[5] << 8) | + ((uint32_t)hcan->pTxMsg->Data[4])); + // Request transmission + hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ; + + if (Timeout == 0) { + return HAL_OK; + } + + // Get tick + tickstart = HAL_GetTick(); + // Check End of transmission flag + while (!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox))) { + // Check for the Timeout + if (Timeout != HAL_MAX_DELAY) { + if ((HAL_GetTick() - tickstart) > Timeout) { + // When the timeout expires, we try to abort the transmission of the packet + __HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox); + while (!__HAL_CAN_GET_FLAG(hcan, rqcpflag)) { + } + if (__HAL_CAN_GET_FLAG(hcan, txokflag)) { + // The abort attempt failed and the message was sent properly + return HAL_OK; + } else { + return HAL_TIMEOUT; + } + } + } + } + return HAL_OK; + } else { + return HAL_BUSY; + } +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_printf(print, "CAN(%u)", self->can_id); + } else { + qstr mode; + switch (self->can.Init.Mode) { + case CAN_MODE_NORMAL: mode = MP_QSTR_NORMAL; break; + case CAN_MODE_LOOPBACK: mode = MP_QSTR_LOOPBACK; break; + case CAN_MODE_SILENT: mode = MP_QSTR_SILENT; break; + case CAN_MODE_SILENT_LOOPBACK: default: mode = MP_QSTR_SILENT_LOOPBACK; break; + } + mp_printf(print, "CAN(%u, CAN.%q, extframe=%q, auto_restart=%q)", + self->can_id, + mode, + self->extframe ? MP_QSTR_True : MP_QSTR_False, + (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False); + } +} + +// init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8) +STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_auto_restart }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, + { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_prescaler, MP_ARG_INT, {.u_int = 100} }, + { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} }, + { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + self->extframe = args[ARG_extframe].u_bool; + + // set the CAN configuration values + memset(&self->can, 0, sizeof(self->can)); + CAN_InitTypeDef *init = &self->can.Init; + init->Mode = args[ARG_mode].u_int << 4; // shift-left so modes fit in a small-int + init->Prescaler = args[ARG_prescaler].u_int; + init->SJW = ((args[ARG_sjw].u_int - 1) & 3) << 24; + init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16; + init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20; + init->TTCM = DISABLE; + init->ABOM = args[ARG_auto_restart].u_bool ? ENABLE : DISABLE; + init->AWUM = DISABLE; + init->NART = DISABLE; + init->RFLM = DISABLE; + init->TXFP = DISABLE; + + // init CAN (if it fails, it's because the port doesn't exist) + if (!can_init(self)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%d) doesn't exist", self->can_id)); + } + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct a CAN object on the given bus. `bus` can be 1-2, or 'YA' or 'YB'. +/// With no additional parameters, the CAN object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the CAN busses are: +/// +/// - `CAN(1)` is on `YA`: `(RX, TX) = (Y3, Y4) = (PB8, PB9)` +/// - `CAN(2)` is on `YB`: `(RX, TX) = (Y5, Y6) = (PB12, PB13)` +STATIC mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // work out port + mp_uint_t can_idx; + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { + #ifdef MICROPY_HW_CAN1_NAME + } else if (strcmp(port, MICROPY_HW_CAN1_NAME) == 0) { + can_idx = PYB_CAN_1; + #endif + #ifdef MICROPY_HW_CAN2_NAME + } else if (strcmp(port, MICROPY_HW_CAN2_NAME) == 0) { + can_idx = PYB_CAN_2; + #endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%s) doesn't exist", port)); + } + } else { + can_idx = mp_obj_get_int(args[0]); + } + if (can_idx < 1 || can_idx > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all))) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%d) doesn't exist", can_idx)); + } + + pyb_can_obj_t *self; + if (MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] == NULL) { + self = m_new_obj(pyb_can_obj_t); + self->base.type = &pyb_can_type; + self->can_id = can_idx; + self->is_enabled = false; + MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] = self; + } else { + self = MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1]; + } + + if (!self->is_enabled || n_args > 1) { + if (self->is_enabled) { + // The caller is requesting a reconfiguration of the hardware + // this can only be done if the hardware is in init mode + pyb_can_deinit(MP_OBJ_FROM_PTR(self)); + } + + self->rxcallback0 = mp_const_none; + self->rxcallback1 = mp_const_none; + self->rx_state0 = RX_STATE_FIFO_EMPTY; + self->rx_state1 = RX_STATE_FIFO_EMPTY; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_can_init_helper(self, n_args - 1, args + 1, &kw_args); + } + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_can_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_can_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_init_obj, 1, pyb_can_init); + +/// \method deinit() +/// Turn off the CAN bus. +STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->is_enabled = false; + HAL_CAN_DeInit(&self->can); + if (self->can.Instance == CAN1) { + HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); + HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn); + __CAN1_FORCE_RESET(); + __CAN1_RELEASE_RESET(); + __CAN1_CLK_DISABLE(); + #if defined(CAN2) + } else if (self->can.Instance == CAN2) { + HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); + HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn); + __CAN2_FORCE_RESET(); + __CAN2_RELEASE_RESET(); + __CAN2_CLK_DISABLE(); + #endif + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit); + +// Force a software restart of the controller, to allow transmission after a bus error +STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_raise_ValueError(NULL); + } + CAN_TypeDef *can = self->can.Instance; + can->MCR |= CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK) == 0) { + } + can->MCR &= ~CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK)) { + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); + +// Get the state of the controller +STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t state = CAN_STATE_STOPPED; + if (self->is_enabled) { + CAN_TypeDef *can = self->can.Instance; + if (can->ESR & CAN_ESR_BOFF) { + state = CAN_STATE_BUS_OFF; + } else if (can->ESR & CAN_ESR_EPVF) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (can->ESR & CAN_ESR_EWGF) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + } + return MP_OBJ_NEW_SMALL_INT(state); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); + +// Get info about error states and TX/RX buffers +STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_list_t *list; + if (n_args == 1) { + list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL)); + } else { + if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_raise_TypeError(NULL); + } + list = MP_OBJ_TO_PTR(args[1]); + if (list->len < 8) { + mp_raise_ValueError(NULL); + } + } + CAN_TypeDef *can = self->can.Instance; + uint32_t esr = can->ESR; + list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); + list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf; + list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); + list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); + list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); + return MP_OBJ_FROM_PTR(list); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); + +/// \method any(fifo) +/// Return `True` if any message waiting on the FIFO, else `False`. +STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t fifo = mp_obj_get_int(fifo_in); + if (fifo == 0) { + if (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO0) != 0) { + return mp_const_true; + } + } else { + if (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO1) != 0) { + return mp_const_true; + } + } + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any); + +/// \method send(send, addr, *, timeout=5000) +/// Send a message on the bus: +/// +/// - `send` is the data to send (an integer to send, or a buffer object). +/// - `addr` is the address to send to +/// - `timeout` is the timeout in milliseconds to wait for the send. +/// +/// Return value: `None`. +STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_data, ARG_id, ARG_timeout, ARG_rtr }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + pyb_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[ARG_data].u_obj, &bufinfo, data); + + if (bufinfo.len > 8) { + mp_raise_ValueError("CAN data field too long"); + } + + // send the data + CanTxMsgTypeDef tx_msg; + if (self->extframe) { + tx_msg.ExtId = args[ARG_id].u_int & 0x1FFFFFFF; + tx_msg.IDE = CAN_ID_EXT; + } else { + tx_msg.StdId = args[ARG_id].u_int & 0x7FF; + tx_msg.IDE = CAN_ID_STD; + } + if (args[ARG_rtr].u_bool == false) { + tx_msg.RTR = CAN_RTR_DATA; + } else { + tx_msg.RTR = CAN_RTR_REMOTE; + } + tx_msg.DLC = bufinfo.len; + for (mp_uint_t i = 0; i < bufinfo.len; i++) { + tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte + } + + self->can.pTxMsg = &tx_msg; + HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[ARG_timeout].u_int); + + if (status != HAL_OK) { + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); + +/// \method recv(fifo, list=None, *, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `fifo` is an integer, which is the FIFO to receive on +/// - `list` if not None is a list with at least 4 elements +/// - `timeout` is the timeout in milliseconds to wait for the receive. +/// +/// Return value: buffer of data bytes. +STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_fifo, ARG_list, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_list, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // receive the data + CanRxMsgTypeDef rx_msg; + int ret = can_receive(self->can.Instance, args[ARG_fifo].u_int, &rx_msg, args[ARG_timeout].u_int); + if (ret < 0) { + mp_raise_OSError(-ret); + } + + // Manage the rx state machine + mp_int_t fifo = args[ARG_fifo].u_int; + if ((fifo == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || + (fifo == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { + byte *state = (fifo == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; + + switch (*state) { + case RX_STATE_FIFO_EMPTY: + break; + case RX_STATE_MESSAGE_PENDING: + if (__HAL_CAN_MSG_PENDING(&self->can, fifo) == 0) { + // Fifo is empty + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + *state = RX_STATE_FIFO_EMPTY; + } + break; + case RX_STATE_FIFO_FULL: + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + *state = RX_STATE_MESSAGE_PENDING; + break; + case RX_STATE_FIFO_OVERFLOW: + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + *state = RX_STATE_MESSAGE_PENDING; + break; + } + } + + // Create the tuple, or get the list, that will hold the return values + // Also populate the fourth element, either a new bytes or reuse existing memoryview + mp_obj_t ret_obj = args[ARG_list].u_obj; + mp_obj_t *items; + if (ret_obj == mp_const_none) { + ret_obj = mp_obj_new_tuple(4, NULL); + items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; + items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); + } else { + // User should provide a list of length at least 4 to hold the values + if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { + mp_raise_TypeError(NULL); + } + mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj); + if (list->len < 4) { + mp_raise_ValueError(NULL); + } + items = list->items; + // Fourth element must be a memoryview which we assume points to a + // byte-like array which is large enough, and then we resize it inplace + if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) { + mp_raise_TypeError(NULL); + } + mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); + if (!(mv->typecode == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | 'b'))) { + mp_raise_ValueError(NULL); + } + mv->len = rx_msg.DLC; + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); + } + + // Populate the first 3 values of the tuple/list + if (rx_msg.IDE == CAN_ID_STD) { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + } else { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); + } + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + + // Return the result + return ret_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); + +/// \class method initfilterbanks +/// +/// Set up the filterbanks. All filter will be disabled and set to their reset states. +/// +/// - `banks` is an integer that sets how many filter banks that are reserved for CAN1. +/// 0 -> no filters assigned for CAN1 +/// 28 -> all filters are assigned to CAN1 +/// CAN2 will get the rest of the 28 available. +/// +/// Return value: none. +STATIC mp_obj_t pyb_can_initfilterbanks(mp_obj_t self, mp_obj_t bank_in) { + can2_start_bank = mp_obj_get_int(bank_in); + + for (int f = 0; f < 28; f++) { + can_clearfilter(f); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_initfilterbanks_fun_obj, pyb_can_initfilterbanks); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pyb_can_initfilterbanks_obj, MP_ROM_PTR(&pyb_can_initfilterbanks_fun_obj)); + +STATIC mp_obj_t pyb_can_clearfilter(mp_obj_t self_in, mp_obj_t bank_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t f = mp_obj_get_int(bank_in); + if (self->can_id == 2) { + f += can2_start_bank; + } + can_clearfilter(f); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter); + +/// Configures a filterbank +/// Return value: `None`. +#define EXTENDED_ID_TO_16BIT_FILTER(id) (((id & 0xC00000) >> 13) | ((id & 0x38000) >> 15)) | 8 +STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bank, ARG_mode, ARG_fifo, ARG_params, ARG_rtr }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bank, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_FILTER_FIFO0} }, + { MP_QSTR_params, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + pyb_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t len; + size_t rtr_len; + mp_uint_t rtr_masks[4] = {0, 0, 0, 0}; + mp_obj_t *rtr_flags; + mp_obj_t *params; + mp_obj_get_array(args[ARG_params].u_obj, &len, ¶ms); + if (args[ARG_rtr].u_obj != MP_OBJ_NULL){ + mp_obj_get_array(args[ARG_rtr].u_obj, &rtr_len, &rtr_flags); + } + + CAN_FilterConfTypeDef filter; + if (args[ARG_mode].u_int == MASK16 || args[ARG_mode].u_int == LIST16) { + if (len != 4) { + goto error; + } + filter.FilterScale = CAN_FILTERSCALE_16BIT; + if (self->extframe) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = 0x02; + rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + rtr_masks[3] = 0x02; + } else { // LIST16 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x02 : 0; + rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x02 : 0; + } + } + filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])) | rtr_masks[0]; // id1 + filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])) | rtr_masks[1]; // mask1 + filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2 + filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2 + } else { // Basic frames + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; + rtr_masks[1] = 0x10; + rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; + rtr_masks[3] = 0x10; + } else { // LIST16 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; + rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x10 : 0; + rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x10 : 0; + } + } + filter.FilterIdLow = (mp_obj_get_int(params[0]) << 5) | rtr_masks[0]; // id1 + filter.FilterMaskIdLow = (mp_obj_get_int(params[1]) << 5) | rtr_masks[1]; // mask1 + filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2 + filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2 + } + if (args[ARG_mode].u_int == MASK16) { + filter.FilterMode = CAN_FILTERMODE_IDMASK; + } + if (args[ARG_mode].u_int == LIST16) { + filter.FilterMode = CAN_FILTERMODE_IDLIST; + } + } + else if (args[ARG_mode].u_int == MASK32 || args[ARG_mode].u_int == LIST32) { + if (len != 2) { + goto error; + } + filter.FilterScale = CAN_FILTERSCALE_32BIT; + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK32) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = 0x02; + } else { // LIST32 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + } + } + filter.FilterIdHigh = (mp_obj_get_int(params[0]) & 0x1FFFE000) >> 13; + filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00001FFF) << 3) | 4) | rtr_masks[0]; + filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0x1FFFE000 ) >> 13; + filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00001FFF) << 3) | 4) | rtr_masks[1]; + if (args[ARG_mode].u_int == MASK32) { + filter.FilterMode = CAN_FILTERMODE_IDMASK; + } + if (args[ARG_mode].u_int == LIST32) { + filter.FilterMode = CAN_FILTERMODE_IDLIST; + } + } else { + goto error; + } + + filter.FilterFIFOAssignment = args[ARG_fifo].u_int; + filter.FilterNumber = args[ARG_bank].u_int; + if (self->can_id == 1) { + if (filter.FilterNumber >= can2_start_bank) { + goto error; + } + } else { + filter.FilterNumber = filter.FilterNumber + can2_start_bank; + if (filter.FilterNumber > 27) { + goto error; + } + } + filter.FilterActivation = ENABLE; + filter.BankNumber = can2_start_bank; + HAL_CAN_ConfigFilter(&self->can, &filter); + + return mp_const_none; + +error: + mp_raise_ValueError("CAN filter parameter error"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_setfilter_obj, 1, pyb_can_setfilter); + +STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t callback_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t fifo = mp_obj_get_int(fifo_in); + mp_obj_t *callback; + + callback = (fifo == 0) ? &self->rxcallback0 : &self->rxcallback1; + if (callback_in == mp_const_none) { + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1); + *callback = mp_const_none; + } else if (*callback != mp_const_none) { + // Rx call backs has already been initialized + // only the callback function should be changed + *callback = callback_in; + } else if (mp_obj_is_callable(callback_in)) { + *callback = callback_in; + uint32_t irq = 0; + if (self->can_id == PYB_CAN_1) { + irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn; + #if defined(CAN2) + } else { + irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; + #endif + } + NVIC_SetPriority(irq, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(irq); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_can_rxcallback_obj, pyb_can_rxcallback); + +STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_initfilterbanks), MP_ROM_PTR(&pyb_can_initfilterbanks_obj) }, + { MP_ROM_QSTR(MP_QSTR_setfilter), MP_ROM_PTR(&pyb_can_setfilter_obj) }, + { MP_ROM_QSTR(MP_QSTR_clearfilter), MP_ROM_PTR(&pyb_can_clearfilter_obj) }, + { MP_ROM_QSTR(MP_QSTR_rxcallback), MP_ROM_PTR(&pyb_can_rxcallback_obj) }, + + // class constants + // Note: we use the ST constants >> 4 so they fit in a small-int. The + // right-shift is undone when the constants are used in the init function. + { MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(CAN_MODE_NORMAL >> 4) }, + { MP_ROM_QSTR(MP_QSTR_LOOPBACK), MP_ROM_INT(CAN_MODE_LOOPBACK >> 4) }, + { MP_ROM_QSTR(MP_QSTR_SILENT), MP_ROM_INT(CAN_MODE_SILENT >> 4) }, + { MP_ROM_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_ROM_INT(CAN_MODE_SILENT_LOOPBACK >> 4) }, + { MP_ROM_QSTR(MP_QSTR_MASK16), MP_ROM_INT(MASK16) }, + { MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) }, + { MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) }, + { MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) }, + + // values for CAN.state() + { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_ACTIVE), MP_ROM_INT(CAN_STATE_ERROR_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_WARNING), MP_ROM_INT(CAN_STATE_ERROR_WARNING) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_PASSIVE), MP_ROM_INT(CAN_STATE_ERROR_PASSIVE) }, + { MP_ROM_QSTR(MP_QSTR_BUS_OFF), MP_ROM_INT(CAN_STATE_BUS_OFF) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table); + +mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + uintptr_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) + && ((__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO0) != 0) + || (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO1) != 0))) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && (self->can.Instance->TSR & CAN_TSR_TME)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = -1; + } + return ret; +} + +void can_rx_irq_handler(uint can_id, uint fifo_id) { + mp_obj_t callback; + pyb_can_obj_t *self; + mp_obj_t irq_reason = MP_OBJ_NEW_SMALL_INT(0); + byte *state; + + self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + + if (fifo_id == CAN_FIFO0) { + callback = self->rxcallback0; + state = &self->rx_state0; + } else { + callback = self->rxcallback1; + state = &self->rx_state1; + } + + switch (*state) { + case RX_STATE_FIFO_EMPTY: + __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + irq_reason = MP_OBJ_NEW_SMALL_INT(0); + *state = RX_STATE_MESSAGE_PENDING; + break; + case RX_STATE_MESSAGE_PENDING: + __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1); + irq_reason = MP_OBJ_NEW_SMALL_INT(1); + *state = RX_STATE_FIFO_FULL; + break; + case RX_STATE_FIFO_FULL: + __HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1); + irq_reason = MP_OBJ_NEW_SMALL_INT(2); + *state = RX_STATE_FIFO_OVERFLOW; + break; + case RX_STATE_FIFO_OVERFLOW: + // This should never happen + break; + } + + if (callback != mp_const_none) { + mp_sched_lock(); + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_2(callback, MP_OBJ_FROM_PTR(self), irq_reason); + nlr_pop(); + } else { + // Uncaught exception; disable the callback so it doesn't run again. + pyb_can_rxcallback(MP_OBJ_FROM_PTR(self), MP_OBJ_NEW_SMALL_INT(fifo_id), mp_const_none); + printf("uncaught exception in CAN(%u) rx interrupt handler\n", self->can_id); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + gc_unlock(); + mp_sched_unlock(); + } +} + +void can_sce_irq_handler(uint can_id) { + pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + if (self) { + self->can.Instance->MSR = CAN_MSR_ERRI; + uint32_t esr = self->can.Instance->ESR; + if (esr & CAN_ESR_BOFF) { + ++self->num_bus_off; + } else if (esr & CAN_ESR_EPVF) { + ++self->num_error_passive; + } else if (esr & CAN_ESR_EWGF) { + ++self->num_error_warning; + } + } +} + +STATIC const mp_stream_p_t can_stream_p = { + //.read = can_read, // is read sensible for CAN? + //.write = can_write, // is write sensible for CAN? + .ioctl = can_ioctl, + .is_text = false, +}; + +const mp_obj_type_t pyb_can_type = { + { &mp_type_type }, + .name = MP_QSTR_CAN, + .print = pyb_can_print, + .make_new = pyb_can_make_new, + .protocol = &can_stream_p, + .locals_dict = (mp_obj_dict_t*)&pyb_can_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_CAN diff --git a/src/openmv/src/micropython/ports/stm32/can.h b/src/openmv/src/micropython/ports/stm32/can.h new file mode 100755 index 0000000..54e7dea --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/can.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_CAN_H +#define MICROPY_INCLUDED_STM32_CAN_H + +#define PYB_CAN_1 (1) +#define PYB_CAN_2 (2) + +extern const mp_obj_type_t pyb_can_type; + +void can_init0(void); +void can_deinit(void); +void can_rx_irq_handler(uint can_id, uint fifo_id); +void can_sce_irq_handler(uint can_id); + +#endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/src/openmv/src/micropython/ports/stm32/dac.c b/src/openmv/src/micropython/ports/stm32/dac.c new file mode 100755 index 0000000..808e4d1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/dac.c @@ -0,0 +1,544 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "timer.h" +#include "dac.h" +#include "dma.h" +#include "pin.h" + +/// \moduleref pyb +/// \class DAC - digital to analog conversion +/// +/// The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6. +/// The voltage will be between 0 and 3.3V. +/// +/// *This module will undergo changes to the API.* +/// +/// Example usage: +/// +/// from pyb import DAC +/// +/// dac = DAC(1) # create DAC 1 on pin X5 +/// dac.write(128) # write a value to the DAC (makes X5 1.65V) +/// +/// To output a continuous sine-wave: +/// +/// import math +/// from pyb import DAC +/// +/// # create a buffer containing a sine-wave +/// buf = bytearray(100) +/// for i in range(len(buf)): +/// buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf))) +/// +/// # output the sine-wave at 400Hz +/// dac = DAC(1) +/// dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) + +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC + +#if defined(STM32H7) +#define DAC DAC1 +#endif + +STATIC DAC_HandleTypeDef DAC_Handle; + +void dac_init(void) { + memset(&DAC_Handle, 0, sizeof DAC_Handle); + DAC_Handle.Instance = DAC; + DAC_Handle.State = HAL_DAC_STATE_RESET; + HAL_DAC_Init(&DAC_Handle); +} + +#if defined(TIM6) +STATIC void TIM6_Config(uint freq) { + // Init TIM6 at the required frequency (in Hz) + TIM_HandleTypeDef *tim = timer_tim6_init(freq); + + // TIM6 TRGO selection + TIM_MasterConfigTypeDef config; + config.MasterOutputTrigger = TIM_TRGO_UPDATE; + config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(tim, &config); + + // TIM6 start counter + HAL_TIM_Base_Start(tim); +} +#endif + +STATIC uint32_t TIMx_Config(mp_obj_t timer) { + // TRGO selection to trigger DAC + TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer); + TIM_MasterConfigTypeDef config; + config.MasterOutputTrigger = TIM_TRGO_UPDATE; + config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(tim, &config); + + // work out the trigger channel (only certain ones are supported) + if (tim->Instance == TIM2) { + return DAC_TRIGGER_T2_TRGO; + #if defined(TIM4) + } else if (tim->Instance == TIM4) { + return DAC_TRIGGER_T4_TRGO; + #endif + #if defined(TIM5) + } else if (tim->Instance == TIM5) { + return DAC_TRIGGER_T5_TRGO; + #endif + #if defined(TIM6) + } else if (tim->Instance == TIM6) { + return DAC_TRIGGER_T6_TRGO; + #endif + #if defined(TIM7) + } else if (tim->Instance == TIM7) { + return DAC_TRIGGER_T7_TRGO; + #endif + #if defined(TIM8) + } else if (tim->Instance == TIM8) { + return DAC_TRIGGER_T8_TRGO; + #endif + } else { + mp_raise_ValueError("Timer does not support DAC triggering"); + } +} + +/******************************************************************************/ +// MicroPython bindings + +typedef enum { + DAC_STATE_RESET, + DAC_STATE_WRITE_SINGLE, + DAC_STATE_BUILTIN_WAVEFORM, + DAC_STATE_DMA_WAVEFORM, // should be last enum since we use space beyond it +} pyb_dac_state_t; + +typedef struct _pyb_dac_obj_t { + mp_obj_base_t base; + uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 + const dma_descr_t *tx_dma_descr; + mp_hal_pin_obj_t pin; // pin_A4 or pin_A5 + uint8_t bits; // 8 or 12 + uint8_t state; + uint8_t outbuf_single; + uint8_t outbuf_waveform; +} pyb_dac_obj_t; + +STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "DAC(%u, bits=%u)", + self->dac_channel == DAC_CHANNEL_1 ? 1 : 2, + self->bits); +} + +STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // GPIO configuration + mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); + + // DAC peripheral clock + #if defined(STM32F4) || defined(STM32F7) + __DAC_CLK_ENABLE(); + #elif defined(STM32H7) + __HAL_RCC_DAC12_CLK_ENABLE(); + #elif defined(STM32F0) || defined(STM32L4) + __HAL_RCC_DAC1_CLK_ENABLE(); + #else + #error Unsupported Processor + #endif + + // stop anything already going on + __HAL_RCC_DMA1_CLK_ENABLE(); + DMA_HandleTypeDef DMA_Handle; + /* Get currently configured dma */ + dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL); + // Need to deinit DMA first + DMA_Handle.State = HAL_DMA_STATE_READY; + HAL_DMA_DeInit(&DMA_Handle); + + HAL_DAC_Stop(&DAC_Handle, self->dac_channel); + if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL) + || (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) { + HAL_DAC_Stop_DMA(&DAC_Handle, self->dac_channel); + } + + // set bit resolution + if (args[0].u_int == 8 || args[0].u_int == 12) { + self->bits = args[0].u_int; + } else { + mp_raise_ValueError("unsupported bits"); + } + + // set output buffer config + if (args[1].u_obj == mp_const_none) { + // due to legacy, default values differ for single and waveform outputs + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else if (mp_obj_is_true(args[1].u_obj)) { + self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else { + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; + } + + // reset state of DAC + self->state = DAC_STATE_RESET; + + return mp_const_none; +} + +// create the dac object +// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2) + +/// \classmethod \constructor(port) +/// Construct a new DAC object. +/// +/// `port` can be a pin object, or an integer (1 or 2). +/// DAC(1) is on pin X5 and DAC(2) is on pin X6. +STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get pin/channel to output on + mp_int_t dac_id; + if (MP_OBJ_IS_INT(args[0])) { + dac_id = mp_obj_get_int(args[0]); + } else { + const pin_obj_t *pin = pin_find(args[0]); + if (pin == pin_A4) { + dac_id = 1; + } else if (pin == pin_A5) { + dac_id = 2; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have DAC capabilities", pin->name)); + } + } + + pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t); + dac->base.type = &pyb_dac_type; + + if (dac_id == 1) { + dac->pin = pin_A4; + dac->dac_channel = DAC_CHANNEL_1; + dac->tx_dma_descr = &dma_DAC_1_TX; + } else if (dac_id == 2) { + dac->pin = pin_A5; + dac->dac_channel = DAC_CHANNEL_2; + dac->tx_dma_descr = &dma_DAC_2_TX; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC(%d) doesn't exist", dac_id)); + } + + // configure the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_dac_init_helper(dac, n_args - 1, args + 1, &kw_args); + + // return object + return MP_OBJ_FROM_PTR(dac); +} + +STATIC mp_obj_t pyb_dac_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_dac_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init); + +/// \method deinit() +/// Turn off the DAC, enable other use of pin. +STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->dac_channel == DAC_CHANNEL_1) { + DAC_Handle.Instance->CR &= ~DAC_CR_EN1; + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE1_Pos)) | 2 << DAC_MCR_MODE1_Pos; + #else + DAC_Handle.Instance->CR |= DAC_CR_BOFF1; + #endif + } else { + DAC_Handle.Instance->CR &= ~DAC_CR_EN2; + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE2_Pos)) | 2 << DAC_MCR_MODE2_Pos; + #else + DAC_Handle.Instance->CR |= DAC_CR_BOFF2; + #endif + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_dac_deinit_obj, pyb_dac_deinit); + +#if defined(TIM6) +/// \method noise(freq) +/// Generate a pseudo-random noise signal. A new random sample is written +/// to the DAC output at the given frequency. +STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(freq)); + + if (self->state != DAC_STATE_BUILTIN_WAVEFORM) { + // configure DAC to trigger via TIM6 + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = self->outbuf_waveform; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = DAC_STATE_BUILTIN_WAVEFORM; + } + + // set noise wave generation + HAL_DACEx_NoiseWaveGenerate(&DAC_Handle, self->dac_channel, DAC_LFSRUNMASK_BITS10_0); + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_L, 0x7ff0); + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_noise_obj, pyb_dac_noise); +#endif + +#if defined(TIM6) +/// \method triangle(freq) +/// Generate a triangle wave. The value on the DAC output changes at +/// the given frequency, and the frequence of the repeating triangle wave +/// itself is 256 (or 1024, need to check) times smaller. +STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(freq)); + + if (self->state != DAC_STATE_BUILTIN_WAVEFORM) { + // configure DAC to trigger via TIM6 + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = self->outbuf_waveform; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = DAC_STATE_BUILTIN_WAVEFORM; + } + + // set triangle wave generation + HAL_DACEx_TriangleWaveGenerate(&DAC_Handle, self->dac_channel, DAC_TRIANGLEAMPLITUDE_1023); + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, 0x100); + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle); +#endif + +/// \method write(value) +/// Direct access to the DAC output (8 bit only at the moment). +STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->state != DAC_STATE_WRITE_SINGLE) { + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_NONE; + config.DAC_OutputBuffer = self->outbuf_single; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = DAC_STATE_WRITE_SINGLE; + } + + // DAC output is always 12-bit at the hardware level, and we provide support + // for multiple bit "resolutions" simply by shifting the input value. + HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R, + mp_obj_get_int(val) << (12 - self->bits)); + + HAL_DAC_Start(&DAC_Handle, self->dac_channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write); + +#if defined(TIM6) +/// \method write_timed(data, freq, *, mode=DAC.NORMAL) +/// Initiates a burst of RAM to DAC using a DMA transfer. +/// The input data is treated as an array of bytes (8 bit data). +/// +/// `freq` can be an integer specifying the frequency to write the DAC +/// samples at, using Timer(6). Or it can be an already-initialised +/// Timer object which is used to trigger the DAC sample. Valid timers +/// are 2, 4, 5, 6, 7 and 8. +/// +/// `mode` can be `DAC.NORMAL` or `DAC.CIRCULAR`. +/// +// TODO add callback argument, to call when transfer is finished +// TODO add double buffer argument +// +// TODO reconsider API, eg: write_trig(data, *, trig=None, loop=False) +// Then trigger can be timer (preinitialised with desired freq) or pin (extint9), +// and we can reuse the same timer for both DACs (and maybe also ADC) without +// setting the freq twice. +// Can still do 1-liner: dac.write_trig(buf, trig=Timer(6, freq=100), loop=True) +mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_NORMAL} }, + }; + + // parse args + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the data to write + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0].u_obj, &bufinfo, MP_BUFFER_READ); + + uint32_t dac_trigger; + if (mp_obj_is_integer(args[1].u_obj)) { + // set TIM6 to trigger the DAC at the given frequency + TIM6_Config(mp_obj_get_int(args[1].u_obj)); + dac_trigger = DAC_TRIGGER_T6_TRGO; + } else { + // set the supplied timer to trigger the DAC (timer should be initialised) + dac_trigger = TIMx_Config(args[1].u_obj); + } + + __HAL_RCC_DMA1_CLK_ENABLE(); + + DMA_HandleTypeDef DMA_Handle; + /* Get currently configured dma */ + dma_init_handle(&DMA_Handle, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, (void*)NULL); + /* + DMA_Cmd(DMA_Handle->Instance, DISABLE); + while (DMA_GetCmdStatus(DMA_Handle->Instance) != DISABLE) { + } + + DAC_Cmd(self->dac_channel, DISABLE); + */ + + /* + // DAC channel configuration + DAC_InitTypeDef DAC_InitStructure; + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(self->dac_channel, &DAC_InitStructure); + */ + + // Need to deinit DMA first + DMA_Handle.State = HAL_DMA_STATE_READY; + HAL_DMA_DeInit(&DMA_Handle); + + if (self->bits == 8) { + DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + } else { + DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + } + DMA_Handle.Init.Mode = args[2].u_int; + HAL_DMA_Init(&DMA_Handle); + + if (self->dac_channel == DAC_CHANNEL_1) { + __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + } else { + __HAL_LINKDMA(&DAC_Handle, DMA_Handle2, DMA_Handle); + } + + DAC_Handle.Instance = DAC; + DAC_Handle.State = HAL_DAC_STATE_RESET; + HAL_DAC_Init(&DAC_Handle); + + if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = dac_trigger; + config.DAC_OutputBuffer = self->outbuf_waveform; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; + } + + if (self->bits == 8) { + HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, + (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R); + } else { + HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, + (uint32_t*)bufinfo.buf, bufinfo.len / 2, DAC_ALIGN_12B_R); + } + + /* + // enable DMA stream + DMA_Cmd(DMA_Handle->Instance, ENABLE); + while (DMA_GetCmdStatus(DMA_Handle->Instance) == DISABLE) { + } + + // enable DAC channel + DAC_Cmd(self->dac_channel, ENABLE); + + // enable DMA for DAC channel + DAC_DMACmd(self->dac_channel, ENABLE); + */ + + //printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_write_timed_obj, 1, pyb_dac_write_timed); +#endif + +STATIC const mp_rom_map_elem_t pyb_dac_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_dac_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_dac_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_dac_write_obj) }, + #if defined(TIM6) + { MP_ROM_QSTR(MP_QSTR_noise), MP_ROM_PTR(&pyb_dac_noise_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&pyb_dac_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_timed), MP_ROM_PTR(&pyb_dac_write_timed_obj) }, + #endif + + // class constants + { MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(DMA_NORMAL) }, + { MP_ROM_QSTR(MP_QSTR_CIRCULAR), MP_ROM_INT(DMA_CIRCULAR) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table); + +const mp_obj_type_t pyb_dac_type = { + { &mp_type_type }, + .name = MP_QSTR_DAC, + .print = pyb_dac_print, + .make_new = pyb_dac_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_dac_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_DAC diff --git a/src/openmv/src/micropython/ports/stm32/dac.h b/src/openmv/src/micropython/ports/stm32/dac.h new file mode 100755 index 0000000..1d8f0ab --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/dac.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_DAC_H +#define MICROPY_INCLUDED_STM32_DAC_H + +void dac_init(void); + +extern const mp_obj_type_t pyb_dac_type; + +#endif // MICROPY_INCLUDED_STM32_DAC_H diff --git a/src/openmv/src/micropython/ports/stm32/dma.c b/src/openmv/src/micropython/ports/stm32/dma.c new file mode 100755 index 0000000..9817bf6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/dma.c @@ -0,0 +1,710 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/obj.h" +#include "dma.h" +#include "irq.h" + +typedef enum { + dma_id_not_defined=-1, + dma_id_0, + dma_id_1, + dma_id_2, + dma_id_3, + dma_id_4, + dma_id_5, + dma_id_6, + dma_id_7, + dma_id_8, + dma_id_9, + dma_id_10, + dma_id_11, + dma_id_12, + dma_id_13, + dma_id_14, + dma_id_15, +} dma_id_t; + +struct _dma_descr_t { + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + DMA_Stream_TypeDef *instance; + #elif defined(STM32F0) || defined(STM32L4) + DMA_Channel_TypeDef *instance; + #else + #error "Unsupported Processor" + #endif + uint32_t sub_instance; + dma_id_t id; + const DMA_InitTypeDef *init; +}; + +// Default parameters to dma_init() shared by spi and i2c; Channel and Direction +// vary depending on the peripheral instance so they get passed separately +static const DMA_InitTypeDef dma_init_struct_spi_i2c = { + #if defined(STM32F4) || defined(STM32F7) + .Channel = 0, + #elif defined(STM32L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Mode = DMA_NORMAL, + .Priority = DMA_PRIORITY_LOW, + #if defined(STM32F4) || defined(STM32F7) + .FIFOMode = DMA_FIFOMODE_DISABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, + .MemBurst = DMA_MBURST_INC4, + .PeriphBurst = DMA_PBURST_INC4 + #endif +}; + +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD && !defined(STM32H7) +// Parameters to dma_init() for SDIO tx and rx. +static const DMA_InitTypeDef dma_init_struct_sdio = { + #if defined(STM32F4) || defined(STM32F7) + .Channel = 0, + #elif defined(STM32L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_WORD, + .MemDataAlignment = DMA_MDATAALIGN_WORD, + #if defined(STM32F4) || defined(STM32F7) + .Mode = DMA_PFCTRL, + #elif defined(STM32L4) + .Mode = DMA_NORMAL, + #endif + .Priority = DMA_PRIORITY_VERY_HIGH, + #if defined(STM32F4) || defined(STM32F7) + .FIFOMode = DMA_FIFOMODE_ENABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, + .MemBurst = DMA_MBURST_INC4, + .PeriphBurst = DMA_PBURST_INC4, + #endif +}; +#endif + +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +// Default parameters to dma_init() for DAC tx +static const DMA_InitTypeDef dma_init_struct_dac = { + #if defined(STM32F4) || defined(STM32F7) + .Channel = 0, + #elif defined(STM32L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Mode = DMA_NORMAL, + .Priority = DMA_PRIORITY_HIGH, + #if defined(STM32F4) || defined(STM32F7) + .FIFOMode = DMA_FIFOMODE_DISABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL, + .MemBurst = DMA_MBURST_SINGLE, + .PeriphBurst = DMA_PBURST_SINGLE, + #endif +}; +#endif + +#if MICROPY_HW_ENABLE_DCMI +static const DMA_InitTypeDef dma_init_struct_dcmi = { + #if defined(STM32H7) + .Request = DMA_REQUEST_DCMI, + #else + .Channel = DMA_CHANNEL_1, + #endif + .Direction = DMA_PERIPH_TO_MEMORY, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_WORD, + .MemDataAlignment = DMA_MDATAALIGN_WORD, + .Mode = DMA_NORMAL, + .Priority = DMA_PRIORITY_HIGH, + .FIFOMode = DMA_FIFOMODE_ENABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, + .MemBurst = DMA_MBURST_INC4, + .PeriphBurst = DMA_PBURST_SINGLE +}; +#endif + +#if defined(STM32F0) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) ((dma_channel) >> ((dma_channel >> 28) * 4)) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponding to DMA1 (7 channels) +#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 (only 5 channels) + +// DMA1 streams +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, HAL_DMA1_CH3_DAC_CH1, dma_id_2, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, HAL_DMA1_CH4_DAC_CH2, dma_id_3, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, HAL_DMA1_CH5_SPI2_TX, dma_id_4, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel6, HAL_DMA1_CH6_SPI2_RX, dma_id_5, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, HAL_DMA2_CH3_SPI1_RX, dma_id_9, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, HAL_DMA2_CH4_SPI1_TX, dma_id_10, &dma_init_struct_spi_i2c}; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Ch1_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + 0, + 0, +}; + +#elif defined(STM32F4) || defined(STM32F7) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (8) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 25) + +#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Stream number, and within a stream by channel +// number. The duplicate streams are ok as long as they aren't used at the same time. +// +// Currently I2C and SPI are synchronous and they call dma_init/dma_deinit +// around each transfer. + +// DMA1 streams +const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_CHANNEL_1, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_CHANNEL_0, dma_id_2, &dma_init_struct_spi_i2c }; +#if defined(STM32F7) +const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, DMA_CHANNEL_2, dma_id_2, &dma_init_struct_spi_i2c }; +#endif +const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, dma_id_4, &dma_init_struct_spi_i2c }; +#if defined(STM32F7) +const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, dma_id_5, &dma_init_struct_spi_i2c }; +#endif +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_CHANNEL_7, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_CHANNEL_7, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_CHANNEL_0, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_CHANNEL_1, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_CHANNEL_7, dma_id_7, &dma_init_struct_spi_i2c }; +/* not preferred streams +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream0, DMA_CHANNEL_0, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, dma_id_6, &dma_init_struct_spi_i2c }; +*/ + +// DMA2 streams +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDMMC_2 = { DMA2_Stream0, DMA_CHANNEL_11, dma_id_8, &dma_init_struct_sdio }; +#endif +#if MICROPY_HW_ENABLE_DCMI +const dma_descr_t dma_DCMI_0 = { DMA2_Stream1, DMA_CHANNEL_1, dma_id_9, &dma_init_struct_dcmi }; +#endif +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio }; +#endif +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, dma_id_13, &dma_init_struct_spi_i2c }; +//#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +//const dma_descr_t dma_SDMMC_2 = { DMA2_Stream5, DMA_CHANNEL_11, dma_id_13, &dma_init_struct_sdio }; +//#endif +const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, dma_id_14, &dma_init_struct_spi_i2c }; +//#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +//const dma_descr_t dma_SDIO_0 = { DMA2_Stream6, DMA_CHANNEL_4, dma_id_14, &dma_init_struct_sdio }; +//#endif +/* not preferred streams +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream3, DMA_CHANNEL_3, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream0, DMA_CHANNEL_3, dma_id_8, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream0, DMA_CHANNEL_4, dma_id_8, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream1, DMA_CHANNEL_4, dma_id_9, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream5, DMA_CHANNEL_7, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream6, DMA_CHANNEL_7, dma_id_14, &dma_init_struct_spi_i2c }; +*/ + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Stream0_IRQn, + DMA1_Stream1_IRQn, + DMA1_Stream2_IRQn, + DMA1_Stream3_IRQn, + DMA1_Stream4_IRQn, + DMA1_Stream5_IRQn, + DMA1_Stream6_IRQn, + DMA1_Stream7_IRQn, + DMA2_Stream0_IRQn, + DMA2_Stream1_IRQn, + DMA2_Stream2_IRQn, + DMA2_Stream3_IRQn, + DMA2_Stream4_IRQn, + DMA2_Stream5_IRQn, + DMA2_Stream6_IRQn, + DMA2_Stream7_IRQn, +}; + +#elif defined(STM32L4) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_request) (dma_request) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0x3f80) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Channel number, and within a channel by request +// number. The duplicate streams are ok as long as they aren't used at the same time. + +// DMA1 streams +//const dma_descr_t dma_ADC_1_RX = { DMA1_Channel1, DMA_REQUEST_0, dma_id_0, NULL }; // unused +//const dma_descr_t dma_ADC_2_RX = { DMA1_Channel2, DMA_REQUEST_0, dma_id_1, NULL }; // unused +const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, dma_id_1, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, dma_id_1, &dma_init_struct_spi_i2c }; +//const dma_descr_t dma_ADC_3_RX = { DMA1_Channel3, DMA_REQUEST_0, dma_id_2, NULL }; // unused +const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, dma_id_2, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, dma_id_2, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, dma_id_3, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, dma_id_3, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, dma_id_5, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, dma_id_6, &dma_init_struct_spi_i2c }; + +// DMA2 streams +const dma_descr_t dma_SPI_3_RX = { DMA2_Channel1, DMA_REQUEST_3, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_TX = { DMA2_Channel2, DMA_REQUEST_3, dma_id_8, &dma_init_struct_spi_i2c }; +/* not preferred streams +const dma_descr_t dma_ADC_1_RX = { DMA2_Channel3, DMA_REQUEST_0, dma_id_9, NULL }; +const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, DMA_REQUEST_4, dma_id_9, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, dma_id_10, NULL }; +const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, dma_id_10, &dma_init_struct_dac }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, dma_id_10, &dma_init_struct_spi_i2c }; +*/ +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0 = { DMA2_Channel4, DMA_REQUEST_7, dma_id_10, &dma_init_struct_sdio }; +#endif +/* not preferred streams +const dma_descr_t dma_ADC_3_RX = { DMA2_Channel5, DMA_REQUEST_0, dma_id_11, NULL }; +const dma_descr_t dma_DAC_2_TX = { DMA2_Channel5, DMA_REQUEST_3, dma_id_11, &dma_init_struct_dac }; +const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel5, DMA_REQUEST_7, dma_id_11, &dma_init_struct_sdio }; +const dma_descr_t dma_I2C_1_RX = { DMA2_Channel6, DMA_REQUEST_5, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA2_Channel7, DMA_REQUEST_5, dma_id_13, &dma_init_struct_spi_i2c }; +*/ + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Channel1_IRQn, + DMA1_Channel2_IRQn, + DMA1_Channel3_IRQn, + DMA1_Channel4_IRQn, + DMA1_Channel5_IRQn, + DMA1_Channel6_IRQn, + DMA1_Channel7_IRQn, + DMA2_Channel1_IRQn, + DMA2_Channel2_IRQn, + DMA2_Channel3_IRQn, + DMA2_Channel4_IRQn, + DMA2_Channel5_IRQn, + DMA2_Channel6_IRQn, + DMA2_Channel7_IRQn, +}; + +#elif defined(STM32H7) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (8) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel) + +#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Stream number, and within a stream by channel +// number. The duplicate streams are ok as long as they aren't used at the same time. +// +// Currently I2C and SPI are synchronous and they call dma_init/dma_deinit +// around each transfer. + +// DMA1 streams +const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_REQUEST_I2C1_RX, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_REQUEST_SPI3_RX, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, BDMA_REQUEST_I2C4_RX, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_REQUEST_I2C3_RX, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_REQUEST_I2C2_RX, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_REQUEST_SPI2_RX, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_REQUEST_SPI2_TX, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_REQUEST_I2C3_TX, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, BDMA_REQUEST_I2C4_TX, dma_id_5, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_CH1, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC1_CH2, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, dma_id_7, &dma_init_struct_spi_i2c }; + +// DMA2 streams +#if MICROPY_HW_ENABLE_DCMI +const dma_descr_t dma_DCMI_0 = { DMA2_Stream1, DMA_REQUEST_DCMI, dma_id_9, &dma_init_struct_dcmi }; +#endif +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_REQUEST_SPI1_RX, dma_id_10, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_REQUEST_SPI5_RX, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_REQUEST_SPI4_RX, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_REQUEST_SPI5_TX, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_REQUEST_SPI4_TX, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, BDMA_REQUEST_SPI6_TX, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_REQUEST_SPI1_TX, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, BDMA_REQUEST_SPI6_RX, dma_id_14, &dma_init_struct_spi_i2c }; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Stream0_IRQn, + DMA1_Stream1_IRQn, + DMA1_Stream2_IRQn, + DMA1_Stream3_IRQn, + DMA1_Stream4_IRQn, + DMA1_Stream5_IRQn, + DMA1_Stream6_IRQn, + DMA1_Stream7_IRQn, + DMA2_Stream0_IRQn, + DMA2_Stream1_IRQn, + DMA2_Stream2_IRQn, + DMA2_Stream3_IRQn, + DMA2_Stream4_IRQn, + DMA2_Stream5_IRQn, + DMA2_Stream6_IRQn, + DMA2_Stream7_IRQn, +}; + +#endif + +static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL}; +static uint8_t dma_last_sub_instance[NSTREAM]; +static volatile uint32_t dma_enable_mask = 0; +volatile dma_idle_count_t dma_idle; + +#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid + +#if defined(STM32F0) +#define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0) +#define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0) +#else +#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) +#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) +#endif + +#if defined(STM32F0) + +void DMA1_Ch1_IRQHandler(void) { + IRQ_ENTER(DMA1_Ch1_IRQn); + if (dma_handle[dma_id_0] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_0]); + } +} + +void DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler(void) { + IRQ_ENTER(DMA1_Ch2_3_DMA2_Ch1_2_IRQn); + if (dma_handle[dma_id_1] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_1]); + } + if (dma_handle[dma_id_2] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_2]); + } + if (dma_handle[dma_id_7] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_7]); + } + if (dma_handle[dma_id_8] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_8]); + } + IRQ_EXIT(DMA1_Ch2_3_DMA2_Ch1_2_IRQn); +} + +void DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler(void) { + IRQ_ENTER(DMA1_Ch4_7_DMA2_Ch3_5_IRQn); + for (unsigned int i = 0; i < 4; ++i) { + if (dma_handle[dma_id_3 + i] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_3 + i]); + } + // When i==3 this will check an invalid handle, but it will always be NULL + if (dma_handle[dma_id_9 + i] != NULL) { + HAL_DMA_IRQHandler(dma_handle[dma_id_9 + i]); + } + } + IRQ_EXIT(DMA1_Ch4_7_DMA2_Ch3_5_IRQn); +} + +#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + +void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } +void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } +void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Stream2_IRQn); } +void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Stream3_IRQn); } +void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Stream4_IRQn); } +void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Stream5_IRQn); } +void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Stream6_IRQn); } +void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA1_Stream7_IRQn); } +void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Stream0_IRQn); } +void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Stream1_IRQn); } +void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]); } IRQ_EXIT(DMA2_Stream2_IRQn); } +void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]); } IRQ_EXIT(DMA2_Stream3_IRQn); } +void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]); } IRQ_EXIT(DMA2_Stream4_IRQn); } +void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]); } IRQ_EXIT(DMA2_Stream5_IRQn); } +void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); } +void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); } + +#elif defined(STM32L4) + +void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Channel1_IRQn); } +void DMA1_Channel2_IRQHandler(void) { IRQ_ENTER(DMA1_Channel2_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Channel2_IRQn); } +void DMA1_Channel3_IRQHandler(void) { IRQ_ENTER(DMA1_Channel3_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Channel3_IRQn); } +void DMA1_Channel4_IRQHandler(void) { IRQ_ENTER(DMA1_Channel4_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Channel4_IRQn); } +void DMA1_Channel5_IRQHandler(void) { IRQ_ENTER(DMA1_Channel5_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Channel5_IRQn); } +void DMA1_Channel6_IRQHandler(void) { IRQ_ENTER(DMA1_Channel6_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Channel6_IRQn); } +void DMA1_Channel7_IRQHandler(void) { IRQ_ENTER(DMA1_Channel7_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Channel7_IRQn); } +void DMA2_Channel1_IRQHandler(void) { IRQ_ENTER(DMA2_Channel1_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA2_Channel1_IRQn); } +void DMA2_Channel2_IRQHandler(void) { IRQ_ENTER(DMA2_Channel2_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Channel2_IRQn); } +void DMA2_Channel3_IRQHandler(void) { IRQ_ENTER(DMA2_Channel3_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Channel3_IRQn); } +void DMA2_Channel4_IRQHandler(void) { IRQ_ENTER(DMA2_Channel4_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]);} IRQ_EXIT(DMA2_Channel4_IRQn); } +void DMA2_Channel5_IRQHandler(void) { IRQ_ENTER(DMA2_Channel5_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]);} IRQ_EXIT(DMA2_Channel5_IRQn); } +void DMA2_Channel6_IRQHandler(void) { IRQ_ENTER(DMA2_Channel6_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]);} IRQ_EXIT(DMA2_Channel6_IRQn); } +void DMA2_Channel7_IRQHandler(void) { IRQ_ENTER(DMA2_Channel7_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]);} IRQ_EXIT(DMA2_Channel7_IRQn); } + +#endif + +// Resets the idle counter for the DMA controller associated with dma_id. +static void dma_tickle(dma_id_t dma_id) { + dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1; +} + +static void dma_enable_clock(dma_id_t dma_id) { + // We don't want dma_tick_handler() to turn off the clock right after we + // enable it, so we need to mark the channel in use in an atomic fashion. + mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION(); + uint32_t old_enable_mask = dma_enable_mask; + dma_enable_mask |= (1 << dma_id); + MICROPY_END_ATOMIC_SECTION(irq_state); + + if (dma_id < NSTREAMS_PER_CONTROLLER) { + if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { + __HAL_RCC_DMA1_CLK_ENABLE(); + + // We just turned on the clock. This means that anything stored + // in dma_last_channel (for DMA1) needs to be invalidated. + + for (int channel = 0; channel < NSTREAMS_PER_CONTROLLER; channel++) { + dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; + } + } + } else { + if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { + __HAL_RCC_DMA2_CLK_ENABLE(); + + // We just turned on the clock. This means that anything stored + // in dma_last_channel (for DMA1) needs to be invalidated. + + for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) { + dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; + } + } + } +} + +static void dma_disable_clock(dma_id_t dma_id) { + // We just mark the clock as disabled here, but we don't actually disable it. + // We wait for the timer to expire first, which means that back-to-back + // transfers don't have to initialize as much. + dma_tickle(dma_id); + dma_enable_mask &= ~(1 << dma_id); +} + +void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data) { + // initialise parameters + dma->Instance = dma_descr->instance; + dma->Init = *dma_descr->init; + dma->Init.Direction = dir; + #if defined(STM32L4) || defined(STM32H7) + dma->Init.Request = dma_descr->sub_instance; + #else + #if !defined(STM32F0) + dma->Init.Channel = dma_descr->sub_instance; + #endif + #endif + // half of __HAL_LINKDMA(data, xxx, *dma) + // caller must implement other half by doing: data->xxx = dma + dma->Parent = data; +} + +void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data){ + // Some drivers allocate the DMA_HandleTypeDef from the stack + // (i.e. dac, i2c, spi) and for those cases we need to clear the + // structure so we don't get random values from the stack) + memset(dma, 0, sizeof(*dma)); + + if (dma_descr != NULL) { + dma_id_t dma_id = dma_descr->id; + + dma_init_handle(dma, dma_descr, dir, data); + // set global pointer for IRQ handler + dma_handle[dma_id] = dma; + + dma_enable_clock(dma_id); + + #if defined(STM32L4) + // Always reset and configure the L4 DMA peripheral + // (dma->State is set to HAL_DMA_STATE_RESET by memset above) + // TODO: understand how L4 DMA works so this is not needed + HAL_DMA_DeInit(dma); + HAL_DMA_Init(dma); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); + #else + // if this stream was previously configured for this channel/request and direction then we + // can skip most of the initialisation + uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) | (dir == DMA_PERIPH_TO_MEMORY) << 7; + if (dma_last_sub_instance[dma_id] != sub_inst) { + dma_last_sub_instance[dma_id] = sub_inst; + + // reset and configure DMA peripheral + // (dma->State is set to HAL_DMA_STATE_RESET by memset above) + HAL_DMA_DeInit(dma); + HAL_DMA_Init(dma); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); + #if defined(STM32F0) + if (dma->Instance < DMA2_Channel1) { + __HAL_DMA1_REMAP(dma_descr->sub_instance); + } else { + __HAL_DMA2_REMAP(dma_descr->sub_instance); + } + #endif + } else { + // only necessary initialization + dma->State = HAL_DMA_STATE_READY; + #if defined(STM32F0) + // These variables are used to access the relevant 4 bits in ISR and IFCR + if (dma_id < NSTREAMS_PER_CONTROLLER) { + dma->DmaBaseAddress = DMA1; + dma->ChannelIndex = dma_id * 4; + } else { + dma->DmaBaseAddress = DMA2; + dma->ChannelIndex = (dma_id - NSTREAMS_PER_CONTROLLER) * 4; + } + #elif defined(STM32F4) || defined(STM32F7) + // calculate DMA base address and bitshift to be used in IRQ handler + extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma); + DMA_CalcBaseAndBitshift(dma); + #endif + } + #endif + + HAL_NVIC_EnableIRQ(dma_irqn[dma_id]); + } +} + +void dma_deinit(const dma_descr_t *dma_descr) { + if (dma_descr != NULL) { + #if !defined(STM32F0) + HAL_NVIC_DisableIRQ(dma_irqn[dma_descr->id]); + #endif + dma_handle[dma_descr->id] = NULL; + + dma_disable_clock(dma_descr->id); + } +} + +void dma_invalidate_channel(const dma_descr_t *dma_descr) { + if (dma_descr != NULL) { + dma_id_t dma_id = dma_descr->id; + // Only compare the sub-instance, not the direction bit (MSB) + if ((dma_last_sub_instance[dma_id] & 0x7f) == DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) ) { + dma_last_sub_instance[dma_id] = DMA_INVALID_CHANNEL; + } + } +} + +// Called from the SysTick handler +// We use LSB of tick to select which controller to process +void dma_idle_handler(int tick) { + static const uint32_t controller_mask[] = { + DMA1_ENABLE_MASK, DMA2_ENABLE_MASK + }; + { + int controller = tick & 1; + if (dma_idle.counter[controller] == 0) { + return; + } + if (++dma_idle.counter[controller] > DMA_IDLE_TICK_MAX) { + if ((dma_enable_mask & controller_mask[controller]) == 0) { + // Nothing is active and we've reached our idle timeout, + // Now we'll really disable the clock. + dma_idle.counter[controller] = 0; + if (controller == 0) { + __HAL_RCC_DMA1_CLK_DISABLE(); + } else { + __HAL_RCC_DMA2_CLK_DISABLE(); + } + } else { + // Something is still active, but the counter never got + // reset, so we'll reset the counter here. + dma_idle.counter[controller] = 1; + } + } + } +} diff --git a/src/openmv/src/micropython/ports/stm32/dma.h b/src/openmv/src/micropython/ports/stm32/dma.h new file mode 100755 index 0000000..8487537 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/dma.h @@ -0,0 +1,103 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_DMA_H +#define MICROPY_INCLUDED_STM32_DMA_H + +typedef struct _dma_descr_t dma_descr_t; + +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + +extern const dma_descr_t dma_I2C_1_RX; +extern const dma_descr_t dma_SPI_3_RX; +extern const dma_descr_t dma_I2C_4_RX; +extern const dma_descr_t dma_I2C_3_RX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_3_TX; +extern const dma_descr_t dma_I2C_4_TX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_3_TX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_SDMMC_2; +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_SPI_5_RX; +extern const dma_descr_t dma_SDIO_0; +extern const dma_descr_t dma_SPI_4_RX; +extern const dma_descr_t dma_SPI_5_TX; +extern const dma_descr_t dma_SPI_4_TX; +extern const dma_descr_t dma_SPI_6_TX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_SDMMC_2; +extern const dma_descr_t dma_SPI_6_RX; +extern const dma_descr_t dma_SDIO_0; +extern const dma_descr_t dma_DCMI_0; + +#elif defined(STM32L4) + +extern const dma_descr_t dma_ADC_1_RX; +extern const dma_descr_t dma_ADC_2_RX; +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_I2C_3_TX; +extern const dma_descr_t dma_ADC_3_RX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_I2C_3_RX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_1_RX; +extern const dma_descr_t dma_SPI_3_RX; +extern const dma_descr_t dma_SPI_3_TX; +extern const dma_descr_t dma_SDIO_0; + +#endif + +typedef union { + uint16_t enabled; // Used to test if both counters are == 0 + uint8_t counter[2]; +} dma_idle_count_t; +extern volatile dma_idle_count_t dma_idle; +#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0) + +#define DMA_SYSTICK_MASK 0x0e +#define DMA_MSECS_PER_SYSTICK (DMA_SYSTICK_MASK + 1) +#define DMA_IDLE_TICK_MAX (8) // 128 msec +#define DMA_IDLE_TICK(tick) (((tick) & DMA_SYSTICK_MASK) == 0) + + +void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); +void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data); +void dma_deinit(const dma_descr_t *dma_descr); +void dma_invalidate_channel(const dma_descr_t *dma_descr); +void dma_idle_handler(int controller); + +#endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/src/openmv/src/micropython/ports/stm32/extint.c b/src/openmv/src/micropython/ports/stm32/extint.c new file mode 100755 index 0000000..b6e9801 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/extint.c @@ -0,0 +1,552 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "pin.h" +#include "extint.h" +#include "irq.h" + +/// \moduleref pyb +/// \class ExtInt - configure I/O pins to interrupt on external events +/// +/// There are a total of 22 interrupt lines. 16 of these can come from GPIO pins +/// and the remaining 6 are from internal sources. +/// +/// For lines 0 thru 15, a given line can map to the corresponding line from an +/// arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and +/// line 1 can map to Px1 where x is A, B, C, ... +/// +/// def callback(line): +/// print("line =", line) +/// +/// Note: ExtInt will automatically configure the gpio line as an input. +/// +/// extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback) +/// +/// Now every time a falling edge is seen on the X1 pin, the callback will be +/// called. Caution: mechanical pushbuttons have "bounce" and pushing or +/// releasing a switch will often generate multiple edges. +/// See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed +/// explanation, along with various techniques for debouncing. +/// +/// Trying to register 2 callbacks onto the same pin will throw an exception. +/// +/// If pin is passed as an integer, then it is assumed to map to one of the +/// internal interrupt sources, and must be in the range 16 thru 22. +/// +/// All other pin objects go through the pin mapper to come up with one of the +/// gpio pins. +/// +/// extint = pyb.ExtInt(pin, mode, pull, callback) +/// +/// Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING, +/// pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING, +/// pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING. +/// +/// Only the IRQ_xxx modes have been tested. The EVT_xxx modes have +/// something to do with sleep mode and the WFE instruction. +/// +/// Valid pull values are pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN, pyb.Pin.PULL_NONE. +/// +/// There is also a C API, so that drivers which require EXTI interrupt lines +/// can also use this code. See extint.h for the available functions and +/// usrsw.h for an example of using this. + +// TODO Add python method to change callback object. + +#define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE) + +// Macro used to set/clear the bit corresponding to the line in the IMR/EMR +// register in an atomic fashion by using bitband addressing. +#define EXTI_MODE_BB(mode, line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (mode)) * 32) + ((line) * 4))) + +#if defined(STM32L4) +// The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct. +// Here we only support configurable line types. Details, see page 330 of RM0351, Rev 1. +// The USB_FS_WAKUP event is a direct type and there is no support for it. +#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1) +#define EXTI_RTSR EXTI->RTSR1 +#define EXTI_FTSR EXTI->FTSR1 +#elif defined(STM32H7) +#define EXTI_Mode_Interrupt offsetof(EXTI_Core_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_Core_TypeDef, EMR1) +#define EXTI_RTSR EXTI->RTSR1 +#define EXTI_FTSR EXTI->FTSR1 +#else +#define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR) +#define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR) +#define EXTI_RTSR EXTI->RTSR +#define EXTI_FTSR EXTI->FTSR +#endif + +#define EXTI_SWIER_BB(line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + offsetof(EXTI_TypeDef, SWIER)) * 32) + ((line) * 4))) + +typedef struct { + mp_obj_base_t base; + mp_int_t line; +} extint_obj_t; + +STATIC uint8_t pyb_extint_mode[EXTI_NUM_VECTORS]; +STATIC bool pyb_extint_hard_irq[EXTI_NUM_VECTORS]; + +// The callback arg is a small-int or a ROM Pin object, so no need to scan by GC +STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS]; + +#if !defined(ETH) +#define ETH_WKUP_IRQn 62 // Some MCUs don't have ETH, but we want a value to put in our table +#endif +#if !defined(OTG_HS_WKUP_IRQn) +#define OTG_HS_WKUP_IRQn 76 // Some MCUs don't have HS, but we want a value to put in our table +#endif +#if !defined(OTG_FS_WKUP_IRQn) +#define OTG_FS_WKUP_IRQn 42 // Some MCUs don't have FS IRQ, but we want a value to put in our table +#endif + +STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { + #if defined(STM32F0) + EXTI0_1_IRQn, EXTI0_1_IRQn, EXTI2_3_IRQn, EXTI2_3_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + #else + EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, + EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, + EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, + EXTI15_10_IRQn, + #if defined(STM32L4) + PVD_PVM_IRQn, + #else + PVD_IRQn, + #endif + RTC_Alarm_IRQn, + OTG_FS_WKUP_IRQn, + ETH_WKUP_IRQn, + OTG_HS_WKUP_IRQn, + TAMP_STAMP_IRQn, + RTC_WKUP_IRQn, + #endif +}; + +// Set override_callback_obj to true if you want to unconditionally set the +// callback function. +uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj) { + const pin_obj_t *pin = NULL; + uint v_line; + + if (MP_OBJ_IS_INT(pin_obj)) { + // If an integer is passed in, then use it to identify lines 16 thru 22 + // We expect lines 0 thru 15 to be passed in as a pin, so that we can + // get both the port number and line number. + v_line = mp_obj_get_int(pin_obj); + if (v_line < 16) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d < 16, use a Pin object", v_line)); + } + if (v_line >= EXTI_NUM_VECTORS) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); + } + } else { + pin = pin_find(pin_obj); + v_line = pin->pin; + } + if (mode != GPIO_MODE_IT_RISING && + mode != GPIO_MODE_IT_FALLING && + mode != GPIO_MODE_IT_RISING_FALLING && + mode != GPIO_MODE_EVT_RISING && + mode != GPIO_MODE_EVT_FALLING && + mode != GPIO_MODE_EVT_RISING_FALLING) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Mode: %d", mode)); + } + if (pull != GPIO_NOPULL && + pull != GPIO_PULLUP && + pull != GPIO_PULLDOWN) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Pull: %d", pull)); + } + + mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[v_line]; + if (!override_callback_obj && *cb != mp_const_none && callback_obj != mp_const_none) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d is already in use", v_line)); + } + + // We need to update callback atomically, so we disable the line + // before we update anything. + + extint_disable(v_line); + + *cb = callback_obj; + pyb_extint_mode[v_line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000 + EXTI_Mode_Interrupt : EXTI_Mode_Event; + + if (*cb != mp_const_none) { + pyb_extint_hard_irq[v_line] = true; + pyb_extint_callback_arg[v_line] = MP_OBJ_NEW_SMALL_INT(v_line); + + mp_hal_gpio_clock_enable(pin->gpio); + GPIO_InitTypeDef exti; + exti.Pin = pin->pin_mask; + exti.Mode = mode; + exti.Pull = pull; + exti.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(pin->gpio, &exti); + + // Calling HAL_GPIO_Init does an implicit extint_enable + + /* Enable and set NVIC Interrupt to the lowest priority */ + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[v_line]), IRQ_PRI_EXTINT); + HAL_NVIC_EnableIRQ(nvic_irq_channel[v_line]); + } + return v_line; +} + +// This function is intended to be used by the Pin.irq() method +void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj) { + uint32_t line = pin->pin; + + // Check if the ExtInt line is already in use by another Pin/ExtInt + mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line]; + if (*cb != mp_const_none && MP_OBJ_FROM_PTR(pin) != pyb_extint_callback_arg[line]) { + if (MP_OBJ_IS_SMALL_INT(pyb_extint_callback_arg[line])) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "ExtInt vector %d is already in use", line)); + } else { + const pin_obj_t *other_pin = MP_OBJ_TO_PTR(pyb_extint_callback_arg[line]); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, + "IRQ resource already taken by Pin('%q')", other_pin->name)); + } + } + + extint_disable(line); + + *cb = callback_obj; + pyb_extint_mode[line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000 + EXTI_Mode_Interrupt : EXTI_Mode_Event; + + if (*cb != mp_const_none) { + // Configure and enable the callback + + pyb_extint_hard_irq[line] = hard_irq; + pyb_extint_callback_arg[line] = MP_OBJ_FROM_PTR(pin); + + // Route the GPIO to EXTI + __HAL_RCC_SYSCFG_CLK_ENABLE(); + SYSCFG->EXTICR[line >> 2] = + (SYSCFG->EXTICR[line >> 2] & ~(0x0f << (4 * (line & 0x03)))) + | ((uint32_t)(GPIO_GET_INDEX(pin->gpio)) << (4 * (line & 0x03))); + + // Enable or disable the rising detector + if ((mode & GPIO_MODE_IT_RISING) == GPIO_MODE_IT_RISING) { + EXTI_RTSR |= 1 << line; + } else { + EXTI_RTSR &= ~(1 << line); + } + + // Enable or disable the falling detector + if ((mode & GPIO_MODE_IT_FALLING) == GPIO_MODE_IT_FALLING) { + EXTI_FTSR |= 1 << line; + } else { + EXTI_FTSR &= ~(1 << line); + } + + // Configure the NVIC + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT); + HAL_NVIC_EnableIRQ(nvic_irq_channel[line]); + + // Enable the interrupt + extint_enable(line); + } +} + +void extint_enable(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) + // The Cortex-M7 doesn't have bitband support. + mp_uint_t irq_state = disable_irq(); + if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { + #if defined(STM32H7) + EXTI_D1->IMR1 |= (1 << line); + #else + EXTI->IMR |= (1 << line); + #endif + } else { + #if defined(STM32H7) + EXTI_D1->EMR1 |= (1 << line); + #else + EXTI->EMR |= (1 << line); + #endif + } + enable_irq(irq_state); + #else + // Since manipulating IMR/EMR is a read-modify-write, and we want this to + // be atomic, we use the bit-band area to just affect the bit we're + // interested in. + EXTI_MODE_BB(pyb_extint_mode[line], line) = 1; + #endif +} + +void extint_disable(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) + // The Cortex-M7 doesn't have bitband support. + mp_uint_t irq_state = disable_irq(); + #if defined(STM32H7) + EXTI_D1->IMR1 &= ~(1 << line); + EXTI_D1->EMR1 &= ~(1 << line); + #else + EXTI->IMR &= ~(1 << line); + EXTI->EMR &= ~(1 << line); + #endif + enable_irq(irq_state); + #else + // Since manipulating IMR/EMR is a read-modify-write, and we want this to + // be atomic, we use the bit-band area to just affect the bit we're + // interested in. + EXTI_MODE_BB(EXTI_Mode_Interrupt, line) = 0; + EXTI_MODE_BB(EXTI_Mode_Event, line) = 0; + #endif +} + +void extint_swint(uint line) { + if (line >= EXTI_NUM_VECTORS) { + return; + } + // we need 0 to 1 transition to trigger the interrupt +#if defined(STM32L4) || defined(STM32H7) + EXTI->SWIER1 &= ~(1 << line); + EXTI->SWIER1 |= (1 << line); +#else + EXTI->SWIER &= ~(1 << line); + EXTI->SWIER |= (1 << line); +#endif +} + +/// \method line() +/// Return the line number that the pin is mapped to. +STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) { + extint_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->line); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj, extint_obj_line); + +/// \method enable() +/// Enable a disabled interrupt. +STATIC mp_obj_t extint_obj_enable(mp_obj_t self_in) { + extint_obj_t *self = MP_OBJ_TO_PTR(self_in); + extint_enable(self->line); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj, extint_obj_enable); + +/// \method disable() +/// Disable the interrupt associated with the ExtInt object. +/// This could be useful for debouncing. +STATIC mp_obj_t extint_obj_disable(mp_obj_t self_in) { + extint_obj_t *self = MP_OBJ_TO_PTR(self_in); + extint_disable(self->line); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable); + +/// \method swint() +/// Trigger the callback from software. +STATIC mp_obj_t extint_obj_swint(mp_obj_t self_in) { + extint_obj_t *self = MP_OBJ_TO_PTR(self_in); + extint_swint(self->line); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); + +// TODO document as a staticmethod +/// \classmethod regs() +/// Dump the values of the EXTI registers. +STATIC mp_obj_t extint_regs(void) { + #if defined(STM32L4) + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI->IMR2); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI->EMR2); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI->PR2); + #elif defined(STM32H7) + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI_D1->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI_D1->IMR2); + printf("EXTI_IMR3 %08x\n", (unsigned int)EXTI_D1->IMR3); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI_D1->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI_D1->EMR2); + printf("EXTI_EMR3 %08x\n", (unsigned int)EXTI_D1->EMR3); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_RTSR3 %08x\n", (unsigned int)EXTI->RTSR3); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_FTSR3 %08x\n", (unsigned int)EXTI->FTSR3); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_SWIER3 %08x\n", (unsigned int)EXTI->SWIER3); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI_D1->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI_D1->PR2); + printf("EXTI_PR3 %08x\n", (unsigned int)EXTI_D1->PR3); + #else + printf("EXTI_IMR %08x\n", (unsigned int)EXTI->IMR); + printf("EXTI_EMR %08x\n", (unsigned int)EXTI->EMR); + printf("EXTI_RTSR %08x\n", (unsigned int)EXTI->RTSR); + printf("EXTI_FTSR %08x\n", (unsigned int)EXTI->FTSR); + printf("EXTI_SWIER %08x\n", (unsigned int)EXTI->SWIER); + printf("EXTI_PR %08x\n", (unsigned int)EXTI->PR); + #endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj, extint_regs); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, MP_ROM_PTR(&extint_regs_fun_obj)); + +/// \classmethod \constructor(pin, mode, pull, callback) +/// Create an ExtInt object: +/// +/// - `pin` is the pin on which to enable the interrupt (can be a pin object or any valid pin name). +/// - `mode` can be one of: +/// - `ExtInt.IRQ_RISING` - trigger on a rising edge; +/// - `ExtInt.IRQ_FALLING` - trigger on a falling edge; +/// - `ExtInt.IRQ_RISING_FALLING` - trigger on a rising or falling edge. +/// - `pull` can be one of: +/// - `pyb.Pin.PULL_NONE` - no pull up or down resistors; +/// - `pyb.Pin.PULL_UP` - enable the pull-up resistor; +/// - `pyb.Pin.PULL_DOWN` - enable the pull-down resistor. +/// - `callback` is the function to call when the interrupt triggers. The +/// callback function must accept exactly 1 argument, which is the line that +/// triggered the interrupt. +STATIC const mp_arg_t pyb_extint_make_new_args[] = { + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pull, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, +}; +#define PYB_EXTINT_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(pyb_extint_make_new_args) + +STATIC mp_obj_t extint_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // type_in == extint_obj_type + + // parse args + mp_arg_val_t vals[PYB_EXTINT_MAKE_NEW_NUM_ARGS]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, PYB_EXTINT_MAKE_NEW_NUM_ARGS, pyb_extint_make_new_args, vals); + + extint_obj_t *self = m_new_obj(extint_obj_t); + self->base.type = type; + self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void extint_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + extint_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->line); +} + +STATIC const mp_rom_map_elem_t extint_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&extint_obj_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&extint_obj_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&extint_obj_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_swint), MP_ROM_PTR(&extint_obj_swint_obj) }, + { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&extint_regs_obj) }, + + // class constants + /// \constant IRQ_RISING - interrupt on a rising edge + /// \constant IRQ_FALLING - interrupt on a falling edge + /// \constant IRQ_RISING_FALLING - interrupt on a rising or falling edge + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_ROM_INT(GPIO_MODE_IT_RISING_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_EVT_RISING), MP_ROM_INT(GPIO_MODE_EVT_RISING) }, + { MP_ROM_QSTR(MP_QSTR_EVT_FALLING), MP_ROM_INT(GPIO_MODE_EVT_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_EVT_RISING_FALLING), MP_ROM_INT(GPIO_MODE_EVT_RISING_FALLING) }, +}; + +STATIC MP_DEFINE_CONST_DICT(extint_locals_dict, extint_locals_dict_table); + +const mp_obj_type_t extint_type = { + { &mp_type_type }, + .name = MP_QSTR_ExtInt, + .print = extint_obj_print, + .make_new = extint_make_new, + .locals_dict = (mp_obj_dict_t*)&extint_locals_dict, +}; + +void extint_init0(void) { + for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) { + MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none; + pyb_extint_mode[i] = EXTI_Mode_Interrupt; + } +} + +// Interrupt handler +void Handle_EXTI_Irq(uint32_t line) { + if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) { + __HAL_GPIO_EXTI_CLEAR_FLAG(1 << line); + if (line < EXTI_NUM_VECTORS) { + mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line]; + if (*cb != mp_const_none) { + // If it's a soft IRQ handler then just schedule callback for later + if (!pyb_extint_hard_irq[line]) { + mp_sched_schedule(*cb, pyb_extint_callback_arg[line]); + return; + } + + mp_sched_lock(); + // When executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(*cb, pyb_extint_callback_arg[line]); + nlr_pop(); + } else { + // Uncaught exception; disable the callback so it doesn't run again. + *cb = mp_const_none; + extint_disable(line); + printf("Uncaught exception in ExtInt interrupt handler line %u\n", (unsigned int)line); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + gc_unlock(); + mp_sched_unlock(); + } + } + } +} diff --git a/src/openmv/src/micropython/ports/stm32/extint.h b/src/openmv/src/micropython/ports/stm32/extint.h new file mode 100755 index 0000000..792eda1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/extint.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_EXTINT_H +#define MICROPY_INCLUDED_STM32_EXTINT_H + +#include "py/mphal.h" + +// Vectors 0-15 are for regular pins +// Vectors 16-22 are for internal sources. +// +// Use the following constants for the internal sources: + +#define EXTI_PVD_OUTPUT (16) +#define EXTI_RTC_ALARM (17) +#define EXTI_USB_OTG_FS_WAKEUP (18) +#define EXTI_ETH_WAKEUP (19) +#define EXTI_USB_OTG_HS_WAKEUP (20) +#if defined(STM32F0) || defined(STM32L4) +#define EXTI_RTC_TIMESTAMP (19) +#define EXTI_RTC_WAKEUP (20) +#else +#define EXTI_RTC_TIMESTAMP (21) +#define EXTI_RTC_WAKEUP (22) +#endif +#if defined(STM32F7) +#define EXTI_LPTIM1_ASYNC_EVENT (23) +#endif + +#define EXTI_NUM_VECTORS (PYB_EXTI_NUM_VECTORS) + +#define EXTI_MODE_INTERRUPT (offsetof(EXTI_TypeDef, IMR)) +#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR)) + +#define EXTI_TRIGGER_RISING (offsetof(EXTI_TypeDef, RTSR)) +#define EXTI_TRIGGER_FALLING (offsetof(EXTI_TypeDef, FTSR)) +#define EXTI_TRIGGER_RISING_FALLING (EXTI_TRIGGER_RISING + EXTI_TRIGGER_FALLING) // just different from RISING or FALLING + +void extint_init0(void); + +uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj); +void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_obj_t callback_obj); + +void extint_enable(uint line); +void extint_disable(uint line); +void extint_swint(uint line); + +void Handle_EXTI_Irq(uint32_t line); + +extern const mp_obj_type_t extint_type; + +#endif // MICROPY_INCLUDED_STM32_EXTINT_H diff --git a/src/openmv/src/micropython/ports/stm32/fatfs_port.c b/src/openmv/src/micropython/ports/stm32/fatfs_port.c new file mode 100755 index 0000000..3feeab2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/fatfs_port.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "lib/oofatfs/ff.h" +#include "rtc.h" + +MP_WEAK DWORD get_fattime(void) { + #if MICROPY_HW_ENABLE_RTC + rtc_init_finalise(); + RTC_TimeTypeDef time; + RTC_DateTypeDef date; + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); + return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2); + #else + // Jan 1st, 2018 at midnight. Not sure what timezone. + return ((2018 - 1980) << 25) | ((1) << 21) | ((1) << 16) | ((0) << 11) | ((0) << 5) | (0 / 2); + #endif +} diff --git a/src/openmv/src/micropython/ports/stm32/flash.c b/src/openmv/src/micropython/ports/stm32/flash.c new file mode 100755 index 0000000..26f76a1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/flash.c @@ -0,0 +1,331 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "flash.h" + +typedef struct { + uint32_t base_address; + uint32_t sector_size; + uint32_t sector_count; +} flash_layout_t; + +#if defined(STM32F0) + +static const flash_layout_t flash_layout[] = { + { FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE }, +}; + +#elif defined(STM32F4) + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x04000, 4 }, + { 0x08010000, 0x10000, 1 }, + { 0x08020000, 0x20000, 3 }, + #if defined(FLASH_SECTOR_8) + { 0x08080000, 0x20000, 4 }, + #endif + #if defined(FLASH_SECTOR_12) + { 0x08100000, 0x04000, 4 }, + { 0x08110000, 0x10000, 1 }, + { 0x08120000, 0x20000, 7 }, + #endif +}; + +#elif defined(STM32F7) + +// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to +// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 +#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x08000, 4 }, + { 0x08020000, 0x20000, 1 }, + { 0x08040000, 0x40000, 3 }, +}; + +#elif defined(STM32L4) + +static const flash_layout_t flash_layout[] = { + { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, +}; + +#elif defined(STM32H7) + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x20000, 16 }, +}; + +#else +#error Unsupported processor +#endif + +#if defined(STM32L4) || defined(STM32H7) + +// get the bank of a given flash address +static uint32_t get_bank(uint32_t addr) { + #if defined(STM32H7) + if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) { + #else + if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) { + #endif + // no bank swap + if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + return FLASH_BANK_1; + } else { + return FLASH_BANK_2; + } + } else { + // bank swap + if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + return FLASH_BANK_2; + } else { + return FLASH_BANK_1; + } + } +} + +#if defined(STM32L4) +// get the page of a given flash address +static uint32_t get_page(uint32_t addr) { + if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + // bank 1 + return (addr - FLASH_BASE) / FLASH_PAGE_SIZE; + } else { + // bank 2 + return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; + } +} +#endif + +#endif + +uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size) { + if (addr >= flash_layout[0].base_address) { + uint32_t sector_index = 0; + for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) { + for (int j = 0; j < flash_layout[i].sector_count; ++j) { + uint32_t sector_start_next = flash_layout[i].base_address + + (j + 1) * flash_layout[i].sector_size; + if (addr < sector_start_next) { + if (start_addr != NULL) { + *start_addr = flash_layout[i].base_address + + j * flash_layout[i].sector_size; + } + if (size != NULL) { + *size = flash_layout[i].sector_size; + } + return sector_index; + } + ++sector_index; + } + } + } + return 0; +} + +void flash_erase(uint32_t flash_dest, uint32_t num_word32) { + // check there is something to write + if (num_word32 == 0) { + return; + } + + // unlock + HAL_FLASH_Unlock(); + + FLASH_EraseInitTypeDef EraseInitStruct; + + #if defined(STM32F0) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.PageAddress = flash_dest; + EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; + #elif defined(STM32L4) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); + + // erase the sector(s) + // The sector returned by flash_get_sector_info can not be used + // as the flash has on each bank 0/1 pages 0..255 + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.Banks = get_bank(flash_dest); + EraseInitStruct.Page = get_page(flash_dest); + EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;; + #else + // Clear pending flags (if any) + #if defined(STM32H7) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2); + #else + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + #endif + + // erase the sector(s) + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + #if defined(STM32H7) + EraseInitStruct.Banks = get_bank(flash_dest); + #endif + EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); + EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; + #endif + + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash + return; + } +} + +/* +// erase the sector using an interrupt +void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) { + // check there is something to write + if (num_word32 == 0) { + return; + } + + // unlock + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); + EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; + if (HAL_FLASHEx_Erase_IT(&EraseInitStruct) != HAL_OK) { + // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash + return; + } +} +*/ + +void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + #if defined(STM32L4) + + // program the flash uint64 by uint64 + for (int i = 0; i < num_word32 / 2; i++) { + uint64_t val = *(uint64_t*)src; + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 8; + src += 2; + } + if ((num_word32 & 0x01) == 1) { + uint64_t val = *(uint64_t*)flash_dest; + val = (val & 0xffffffff00000000uL) | (*src); + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flash_dest, val) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + } + + #elif defined(STM32H7) + + // program the flash 256 bits at a time + for (int i = 0; i < num_word32 / 8; i++) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_dest, (uint64_t)(uint32_t)src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 32; + src += 8; + } + + #else + + // program the flash word by word + for (int i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 4; + src += 1; + } + + #endif + + // lock the flash + HAL_FLASH_Lock(); +} + +/* + use erase, then write +void flash_erase_and_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + // check there is something to write + if (num_word32 == 0) { + return; + } + + // unlock + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); + EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash + return; + } + + // program the flash word by word + for (int i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 4; + src += 1; + } + + // lock the flash + HAL_FLASH_Lock(); +} +*/ diff --git a/src/openmv/src/micropython/ports/stm32/flash.h b/src/openmv/src/micropython/ports/stm32/flash.h new file mode 100755 index 0000000..b9edf61 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/flash.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_FLASH_H +#define MICROPY_INCLUDED_STM32_FLASH_H + +uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); +void flash_erase(uint32_t flash_dest, uint32_t num_word32); +void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); + +#endif // MICROPY_INCLUDED_STM32_FLASH_H diff --git a/src/openmv/src/micropython/ports/stm32/flashbdev.c b/src/openmv/src/micropython/ports/stm32/flashbdev.c new file mode 100755 index 0000000..181ee64 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/flashbdev.c @@ -0,0 +1,275 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/mperrno.h" +#include "led.h" +#include "flash.h" +#include "storage.h" + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE + +// Here we try to automatically configure the location and size of the flash +// pages to use for the internal storage. We also configure the location of the +// cache used for writing. + +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +// enable this to get an extra 64k of storage (uses the last sector of the flash) +#if 0 +#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k +#endif + +#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) + +STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k +#define CACHE_MEM_START_ADDR (&flash_cache_mem[0]) +#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k + +#elif defined(STM32F429xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +#elif defined(STM32F439xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 +#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k +#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) + +#elif defined(STM32F746xx) || defined(STM32F765xx) || defined(STM32F767xx) || defined(STM32F769xx) + +// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. + +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max +#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k + +#elif defined(STM32H743xx) + +// The STM32H743 flash sectors are 128K +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k +#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max +#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks + +#elif defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) + +// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this, although +// actual location and size is defined by the linker script. +extern uint8_t _flash_fs_start; +extern uint8_t _flash_fs_end; +extern uint8_t _ram_fs_cache_start[]; // size determined by linker file +extern uint8_t _ram_fs_cache_end[]; + +#define CACHE_MEM_START_ADDR ((uintptr_t)&_ram_fs_cache_start[0]) +#define FLASH_SECTOR_SIZE_MAX (&_ram_fs_cache_end[0] - &_ram_fs_cache_start[0]) // 2k max +#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) +#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) + +#else +#error "no internal flash storage support for this MCU" +#endif + +#if !defined(FLASH_MEM_SEG2_START_ADDR) +#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment +#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment +#endif + +#define FLASH_FLAG_DIRTY (1) +#define FLASH_FLAG_FORCE_WRITE (2) +#define FLASH_FLAG_ERASED (4) +static __IO uint8_t flash_flags = 0; +static uint32_t flash_cache_sector_id; +static uint32_t flash_cache_sector_start; +static uint32_t flash_cache_sector_size; +static uint32_t flash_tick_counter_last_write; + +static void flash_bdev_irq_handler(void); + +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) { + (void)arg; + switch (op) { + case BDEV_IOCTL_INIT: + flash_flags = 0; + flash_cache_sector_id = 0; + flash_tick_counter_last_write = 0; + return 0; + + case BDEV_IOCTL_NUM_BLOCKS: + return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS; + + case BDEV_IOCTL_IRQ_HANDLER: + flash_bdev_irq_handler(); + return 0; + + case BDEV_IOCTL_SYNC: { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + if (flash_flags & FLASH_FLAG_DIRTY) { + flash_flags |= FLASH_FLAG_FORCE_WRITE; + while (flash_flags & FLASH_FLAG_DIRTY) { + flash_bdev_irq_handler(); + } + } + restore_irq_pri(basepri); + return 0; + } + } + return -MP_EINVAL; +} + +static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) { + flash_sector_size = FLASH_SECTOR_SIZE_MAX; + } + if (flash_cache_sector_id != flash_sector_id) { + flash_bdev_ioctl(BDEV_IOCTL_SYNC, 0); + memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); + flash_cache_sector_id = flash_sector_id; + flash_cache_sector_start = flash_sector_start; + flash_cache_sector_size = flash_sector_size; + } + flash_flags |= FLASH_FLAG_DIRTY; + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + flash_tick_counter_last_write = HAL_GetTick(); + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; +} + +static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_cache_sector_id == flash_sector_id) { + // in cache, copy from there + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; + } + // not in cache, copy straight from flash + return (uint8_t*)flash_addr; +} + +static uint32_t convert_block_to_flash_addr(uint32_t block) { + if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { + return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; + } + if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { + return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; + } + // can add more flash segments here if needed, following above pattern + + // bad block + return -1; +} + +static void flash_bdev_irq_handler(void) { + if (!(flash_flags & FLASH_FLAG_DIRTY)) { + return; + } + + // This code uses interrupts to erase the flash + /* + if (flash_erase_state == 0) { + flash_erase_it(flash_cache_sector_start, flash_cache_sector_size / 4); + flash_erase_state = 1; + return; + } + + if (flash_erase_state == 1) { + // wait for erase + // TODO add timeout + #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) + if (!flash_erase_done()) { + return; + } + flash_erase_state = 2; + } + */ + + // This code erases the flash directly, waiting for it to finish + if (!(flash_flags & FLASH_FLAG_ERASED)) { + flash_erase(flash_cache_sector_start, flash_cache_sector_size / 4); + flash_flags |= FLASH_FLAG_ERASED; + return; + } + + // If not a forced write, wait at least 5 seconds after last write to flush + // On file close and flash unmount we get a forced write, so we can afford to wait a while + if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || HAL_GetTick() - flash_tick_counter_last_write >= 5000) { + // sync the cache RAM buffer by writing it to the flash page + flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + // clear the flash flags now that we have a clean cache + flash_flags = 0; + // indicate a clean cache with LED off + led_state(PYB_LED_RED, 0); + } +} + +bool flash_bdev_readblock(uint8_t *dest, uint32_t block) { + // non-MBR block, get data from flash memory, possibly via cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint8_t *src = flash_cache_get_addr_for_read(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + return true; +} + +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) { + // non-MBR block, copy to cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + restore_irq_pri(basepri); + return true; +} + +#endif // MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/src/openmv/src/micropython/ports/stm32/font_petme128_8x8.h b/src/openmv/src/micropython/ports/stm32/font_petme128_8x8.h new file mode 100755 index 0000000..cdc4e73 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/font_petme128_8x8.h @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H +#define MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H + +static const uint8_t font_petme128_8x8[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32= + 0x00,0x00,0x00,0x4f,0x4f,0x00,0x00,0x00, // 33=! + 0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, // 34=" + 0x14,0x7f,0x7f,0x14,0x14,0x7f,0x7f,0x14, // 35=# + 0x00,0x24,0x2e,0x6b,0x6b,0x3a,0x12,0x00, // 36=$ + 0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00, // 37=% + 0x00,0x32,0x7f,0x4d,0x4d,0x77,0x72,0x50, // 38=& + 0x00,0x00,0x00,0x04,0x06,0x03,0x01,0x00, // 39=' + 0x00,0x00,0x1c,0x3e,0x63,0x41,0x00,0x00, // 40=( + 0x00,0x00,0x41,0x63,0x3e,0x1c,0x00,0x00, // 41=) + 0x08,0x2a,0x3e,0x1c,0x1c,0x3e,0x2a,0x08, // 42=* + 0x00,0x08,0x08,0x3e,0x3e,0x08,0x08,0x00, // 43=+ + 0x00,0x00,0x80,0xe0,0x60,0x00,0x00,0x00, // 44=, + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, // 45=- + 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, // 46=. + 0x00,0x40,0x60,0x30,0x18,0x0c,0x06,0x02, // 47=/ + 0x00,0x3e,0x7f,0x49,0x45,0x7f,0x3e,0x00, // 48=0 + 0x00,0x40,0x44,0x7f,0x7f,0x40,0x40,0x00, // 49=1 + 0x00,0x62,0x73,0x51,0x49,0x4f,0x46,0x00, // 50=2 + 0x00,0x22,0x63,0x49,0x49,0x7f,0x36,0x00, // 51=3 + 0x00,0x18,0x18,0x14,0x16,0x7f,0x7f,0x10, // 52=4 + 0x00,0x27,0x67,0x45,0x45,0x7d,0x39,0x00, // 53=5 + 0x00,0x3e,0x7f,0x49,0x49,0x7b,0x32,0x00, // 54=6 + 0x00,0x03,0x03,0x79,0x7d,0x07,0x03,0x00, // 55=7 + 0x00,0x36,0x7f,0x49,0x49,0x7f,0x36,0x00, // 56=8 + 0x00,0x26,0x6f,0x49,0x49,0x7f,0x3e,0x00, // 57=9 + 0x00,0x00,0x00,0x24,0x24,0x00,0x00,0x00, // 58=: + 0x00,0x00,0x80,0xe4,0x64,0x00,0x00,0x00, // 59=; + 0x00,0x08,0x1c,0x36,0x63,0x41,0x41,0x00, // 60=< + 0x00,0x14,0x14,0x14,0x14,0x14,0x14,0x00, // 61== + 0x00,0x41,0x41,0x63,0x36,0x1c,0x08,0x00, // 62=> + 0x00,0x02,0x03,0x51,0x59,0x0f,0x06,0x00, // 63=? + 0x00,0x3e,0x7f,0x41,0x4d,0x4f,0x2e,0x00, // 64=@ + 0x00,0x7c,0x7e,0x0b,0x0b,0x7e,0x7c,0x00, // 65=A + 0x00,0x7f,0x7f,0x49,0x49,0x7f,0x36,0x00, // 66=B + 0x00,0x3e,0x7f,0x41,0x41,0x63,0x22,0x00, // 67=C + 0x00,0x7f,0x7f,0x41,0x63,0x3e,0x1c,0x00, // 68=D + 0x00,0x7f,0x7f,0x49,0x49,0x41,0x41,0x00, // 69=E + 0x00,0x7f,0x7f,0x09,0x09,0x01,0x01,0x00, // 70=F + 0x00,0x3e,0x7f,0x41,0x49,0x7b,0x3a,0x00, // 71=G + 0x00,0x7f,0x7f,0x08,0x08,0x7f,0x7f,0x00, // 72=H + 0x00,0x00,0x41,0x7f,0x7f,0x41,0x00,0x00, // 73=I + 0x00,0x20,0x60,0x41,0x7f,0x3f,0x01,0x00, // 74=J + 0x00,0x7f,0x7f,0x1c,0x36,0x63,0x41,0x00, // 75=K + 0x00,0x7f,0x7f,0x40,0x40,0x40,0x40,0x00, // 76=L + 0x00,0x7f,0x7f,0x06,0x0c,0x06,0x7f,0x7f, // 77=M + 0x00,0x7f,0x7f,0x0e,0x1c,0x7f,0x7f,0x00, // 78=N + 0x00,0x3e,0x7f,0x41,0x41,0x7f,0x3e,0x00, // 79=O + 0x00,0x7f,0x7f,0x09,0x09,0x0f,0x06,0x00, // 80=P + 0x00,0x1e,0x3f,0x21,0x61,0x7f,0x5e,0x00, // 81=Q + 0x00,0x7f,0x7f,0x19,0x39,0x6f,0x46,0x00, // 82=R + 0x00,0x26,0x6f,0x49,0x49,0x7b,0x32,0x00, // 83=S + 0x00,0x01,0x01,0x7f,0x7f,0x01,0x01,0x00, // 84=T + 0x00,0x3f,0x7f,0x40,0x40,0x7f,0x3f,0x00, // 85=U + 0x00,0x1f,0x3f,0x60,0x60,0x3f,0x1f,0x00, // 86=V + 0x00,0x7f,0x7f,0x30,0x18,0x30,0x7f,0x7f, // 87=W + 0x00,0x63,0x77,0x1c,0x1c,0x77,0x63,0x00, // 88=X + 0x00,0x07,0x0f,0x78,0x78,0x0f,0x07,0x00, // 89=Y + 0x00,0x61,0x71,0x59,0x4d,0x47,0x43,0x00, // 90=Z + 0x00,0x00,0x7f,0x7f,0x41,0x41,0x00,0x00, // 91=[ + 0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0x40, // 92='\' + 0x00,0x00,0x41,0x41,0x7f,0x7f,0x00,0x00, // 93=] + 0x00,0x08,0x0c,0x06,0x06,0x0c,0x08,0x00, // 94=^ + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, // 95=_ + 0x00,0x00,0x01,0x03,0x06,0x04,0x00,0x00, // 96=` + 0x00,0x20,0x74,0x54,0x54,0x7c,0x78,0x00, // 97=a + 0x00,0x7f,0x7f,0x44,0x44,0x7c,0x38,0x00, // 98=b + 0x00,0x38,0x7c,0x44,0x44,0x6c,0x28,0x00, // 99=c + 0x00,0x38,0x7c,0x44,0x44,0x7f,0x7f,0x00, // 100=d + 0x00,0x38,0x7c,0x54,0x54,0x5c,0x58,0x00, // 101=e + 0x00,0x08,0x7e,0x7f,0x09,0x03,0x02,0x00, // 102=f + 0x00,0x98,0xbc,0xa4,0xa4,0xfc,0x7c,0x00, // 103=g + 0x00,0x7f,0x7f,0x04,0x04,0x7c,0x78,0x00, // 104=h + 0x00,0x00,0x00,0x7d,0x7d,0x00,0x00,0x00, // 105=i + 0x00,0x40,0xc0,0x80,0x80,0xfd,0x7d,0x00, // 106=j + 0x00,0x7f,0x7f,0x30,0x38,0x6c,0x44,0x00, // 107=k + 0x00,0x00,0x41,0x7f,0x7f,0x40,0x00,0x00, // 108=l + 0x00,0x7c,0x7c,0x18,0x30,0x18,0x7c,0x7c, // 109=m + 0x00,0x7c,0x7c,0x04,0x04,0x7c,0x78,0x00, // 110=n + 0x00,0x38,0x7c,0x44,0x44,0x7c,0x38,0x00, // 111=o + 0x00,0xfc,0xfc,0x24,0x24,0x3c,0x18,0x00, // 112=p + 0x00,0x18,0x3c,0x24,0x24,0xfc,0xfc,0x00, // 113=q + 0x00,0x7c,0x7c,0x04,0x04,0x0c,0x08,0x00, // 114=r + 0x00,0x48,0x5c,0x54,0x54,0x74,0x20,0x00, // 115=s + 0x04,0x04,0x3f,0x7f,0x44,0x64,0x20,0x00, // 116=t + 0x00,0x3c,0x7c,0x40,0x40,0x7c,0x3c,0x00, // 117=u + 0x00,0x1c,0x3c,0x60,0x60,0x3c,0x1c,0x00, // 118=v + 0x00,0x1c,0x7c,0x30,0x18,0x30,0x7c,0x1c, // 119=w + 0x00,0x44,0x6c,0x38,0x38,0x6c,0x44,0x00, // 120=x + 0x00,0x9c,0xbc,0xa0,0xa0,0xfc,0x7c,0x00, // 121=y + 0x00,0x44,0x64,0x74,0x5c,0x4c,0x44,0x00, // 122=z + 0x00,0x08,0x08,0x3e,0x77,0x41,0x41,0x00, // 123={ + 0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00, // 124=| + 0x00,0x41,0x41,0x77,0x3e,0x08,0x08,0x00, // 125=} + 0x00,0x02,0x03,0x01,0x03,0x02,0x03,0x01, // 126=~ + 0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55, // 127 +}; + +#endif // MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H diff --git a/src/openmv/src/micropython/ports/stm32/gccollect.c b/src/openmv/src/micropython/ports/stm32/gccollect.c new file mode 100755 index 0000000..50880e2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/gccollect.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" +#include "systick.h" + +uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs); + +void gc_collect(void) { + // get current time, in case we want to time the GC + #if 0 + uint32_t start = mp_hal_ticks_us(); + #endif + + // start the GC + gc_collect_start(); + + // get the registers and the sp + uintptr_t regs[10]; + uintptr_t sp = gc_helper_get_regs_and_sp(regs); + + // trace the stack, including the registers (since they live on the stack in this function) + #if MICROPY_PY_THREAD + gc_collect_root((void**)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + #else + gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t)); + #endif + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + + // end the GC + gc_collect_end(); + + #if 0 + // print GC info + uint32_t ticks = mp_hal_ticks_us() - start; + gc_info_t info; + gc_info(&info); + printf("GC@%lu %lums\n", start, ticks); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + #endif +} diff --git a/src/openmv/src/micropython/ports/stm32/gccollect.h b/src/openmv/src/micropython/ports/stm32/gccollect.h new file mode 100755 index 0000000..25a74a3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/gccollect.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H +#define MICROPY_INCLUDED_STM32_GCCOLLECT_H + +// variables defining memory layout +// (these probably belong somewhere else...) +extern uint32_t _etext; +extern uint32_t _sidata; +extern uint32_t _ram_start; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern uint32_t _heap_start; +extern uint32_t _heap_end; +extern uint32_t _estack; +extern uint32_t _ram_end; + +#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H diff --git a/src/openmv/src/micropython/ports/stm32/gchelper.s b/src/openmv/src/micropython/ports/stm32/gchelper.s new file mode 100755 index 0000000..6baedcd --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/gchelper.s @@ -0,0 +1,62 @@ + .syntax unified + .cpu cortex-m4 + .thumb + .text + .align 2 + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) + .global gc_helper_get_regs_and_sp + .thumb + .thumb_func + .type gc_helper_get_regs_and_sp, %function +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0], #4 + str r5, [r0], #4 + str r6, [r0], #4 + str r7, [r0], #4 + str r8, [r0], #4 + str r9, [r0], #4 + str r10, [r0], #4 + str r11, [r0], #4 + str r12, [r0], #4 + str r13, [r0], #4 + + @ return the sp + mov r0, sp + bx lr + + +@ this next function is now obsolete + + .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack +@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end) + .global gc_helper_get_regs_and_clean_stack + .thumb + .thumb_func + .type gc_helper_get_regs_and_clean_stack, %function +gc_helper_get_regs_and_clean_stack: + @ store registers into given array + str r4, [r0], #4 + str r5, [r0], #4 + str r6, [r0], #4 + str r7, [r0], #4 + str r8, [r0], #4 + str r9, [r0], #4 + str r10, [r0], #4 + str r11, [r0], #4 + str r12, [r0], #4 + str r13, [r0], #4 + + @ clean the stack from given pointer up to current sp + movs r0, #0 + mov r2, sp + b.n .entry +.loop: + str r0, [r1], #4 +.entry: + cmp r1, r2 + bcc.n .loop + bx lr + + .size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack diff --git a/src/openmv/src/micropython/ports/stm32/gchelper_m0.s b/src/openmv/src/micropython/ports/stm32/gchelper_m0.s new file mode 100755 index 0000000..db0d973 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/gchelper_m0.s @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text + .align 2 + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, %function + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0, #0] + str r5, [r0, #4] + str r6, [r0, #8] + str r7, [r0, #12] + mov r1, r8 + str r1, [r0, #16] + mov r1, r9 + str r1, [r0, #20] + mov r1, r10 + str r1, [r0, #24] + mov r1, r11 + str r1, [r0, #28] + mov r1, r12 + str r1, [r0, #32] + mov r1, r13 + str r1, [r0, #36] + + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/src/openmv/src/micropython/ports/stm32/help.c b/src/openmv/src/micropython/ports/stm32/help.c new file mode 100755 index 0000000..f9d97b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/help.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char stm32_help_text[] = +"Welcome to MicroPython!\n" +"\n" +"For online help please visit http://micropython.org/help/.\n" +"\n" +"Quick overview of commands for the board:\n" +" pyb.info() -- print some general information\n" +" pyb.delay(n) -- wait for n milliseconds\n" +" pyb.millis() -- get number of milliseconds since hard reset\n" +" pyb.Switch() -- create a switch object\n" +" Switch methods: (), callback(f)\n" +" pyb.LED(n) -- create an LED object for LED n (n=1,2,3,4)\n" +" LED methods: on(), off(), toggle(), intensity()\n" +" pyb.Pin(pin) -- get a pin, eg pyb.Pin('X1')\n" +" pyb.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n" +" Pin methods: init(..), value([v]), high(), low()\n" +" pyb.ExtInt(pin, m, p, callback) -- create an external interrupt object\n" +" pyb.ADC(pin) -- make an analog object from a pin\n" +" ADC methods: read(), read_timed(buf, freq)\n" +" pyb.DAC(port) -- make a DAC object\n" +" DAC methods: triangle(freq), write(n), write_timed(buf, freq)\n" +" pyb.RTC() -- make an RTC object; methods: datetime([val])\n" +" pyb.rng() -- get a 30-bit hardware random number\n" +" pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4)\n" +" Servo methods: calibration(..), angle([x, [t]]), speed([x, [t]])\n" +" pyb.Accel() -- create an Accelerometer object\n" +" Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz()\n" +"\n" +"Pins are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name\n" +"Pin IO modes are: pyb.Pin.IN, pyb.Pin.OUT_PP, pyb.Pin.OUT_OD\n" +"Pin pull modes are: pyb.Pin.PULL_NONE, pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN\n" +"Additional serial bus objects: pyb.I2C(n), pyb.SPI(n), pyb.UART(n)\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +"For a list of available modules, type help('modules')\n" +; diff --git a/src/openmv/src/micropython/ports/stm32/i2c.c b/src/openmv/src/micropython/ports/stm32/i2c.c new file mode 100755 index 0000000..109b941 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/i2c.c @@ -0,0 +1,474 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "i2c.h" + +#if MICROPY_HW_ENABLE_HW_I2C + +#define I2C_POLL_TIMEOUT_MS (50) + +#if defined(STM32F4) + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + + // Force reset I2C peripheral + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + uint32_t PCLK1 = HAL_RCC_GetPCLK1Freq(); + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = PCLK1 / 1000000; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + freq = MIN(freq, 400000); + + // SM: MAX(4, PCLK1 / (F * 2)) + // FM, 16:9 duty: 0xc000 | MAX(1, (PCLK1 / (F * (16 + 9)))) + if (freq <= 100000) { + i2c->CCR = MAX(4, PCLK1 / (freq * 2)); + } else { + i2c->CCR = 0xc000 | MAX(1, PCLK1 / (freq * 25)); + } + + // SM: 1000ns / (1/PCLK1) + 1 = PCLK1 * 1e-6 + 1 + // FM: 300ns / (1/PCLK1) + 1 = 300e-3 * PCLK1 * 1e-6 + 1 + if (freq <= 100000) { + i2c->TRISE = PCLK1 / 1000000 + 1; // 1000ns rise time in SM + } else { + i2c->TRISE = PCLK1 / 1000000 * 3 / 10 + 1; // 300ns rise time in FM + } + + #if defined(I2C_FLTR_ANOFF) + i2c->FLTR = 0; // analog filter on, digital filter off + #endif + + return 0; +} + +STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->SR1 & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +STATIC int i2c_wait_stop(i2c_t *i2c) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR1 & I2C_CR1_STOP) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + i2c->CR1 &= ~I2C_CR1_PE; + return 0; +} + +// For write: len = 0, 1 or N +// For read: len = 1, 2 or N; stop = true +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t next_len, bool stop) { + if (!(i2c->CR1 & I2C_CR1_PE) && (i2c->SR2 & I2C_SR2_MSL)) { + // The F4 I2C peripheral can sometimes get into a bad state where it's disabled + // (PE low) but still an active master (MSL high). It seems the best way to get + // out of this is a full reset. + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + } + + // It looks like it's possible to terminate the reading by sending a + // START condition instead of STOP condition but we don't support that. + if (rd_wrn) { + if (!stop) { + return -MP_EINVAL; + } + } + + // Repurpose OAR1 to hold stop flag + i2c->OAR1 = stop; + + // Enable peripheral and send START condition + i2c->CR1 |= I2C_CR1_PE; + i2c->CR1 |= I2C_CR1_START; + + // Wait for START to be sent + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_SB))) { + return ret; + } + + // Send the 7-bit address with read/write bit + i2c->DR = addr << 1 | rd_wrn; + + // Wait for address to be sent + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_ADDR))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->SR1 & I2C_SR1_AF) { + // Got a NACK + i2c->CR1 |= I2C_CR1_STOP; + i2c_wait_stop(i2c); // Don't leak errors from this call + return -MP_ENODEV; + } + + if (rd_wrn) { + // For reading, set up ACK/NACK control based on number of bytes to read (at least 1 byte) + if (next_len <= 1) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } else if (next_len <= 2) { + // NACK second received byte + i2c->CR1 |= I2C_CR1_POS; + i2c->CR1 &= ~I2C_CR1_ACK; + } else { + // ACK next received byte + i2c->CR1 |= I2C_CR1_ACK; + } + } + + // Read SR2 to clear SR1_ADDR + uint32_t sr2 = i2c->SR2; + (void)sr2; + + return 0; +} + +// next_len = 0 or N (>=2) +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (len == 0) { + return -MP_EINVAL; + } + if (next_len == 1) { + return -MP_EINVAL; + } + + size_t remain = len + next_len; + if (remain == 1) { + // Special case + i2c->CR1 |= I2C_CR1_STOP; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_RXNE))) { + return ret; + } + *dest = i2c->DR; + } else { + for (; len; --len) { + remain = len + next_len; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_BTF))) { + return ret; + } + if (remain == 2) { + // In this case next_len == 0 (it's not allowed to be 1) + i2c->CR1 |= I2C_CR1_STOP; + *dest++ = i2c->DR; + *dest = i2c->DR; + break; + } else if (remain == 3) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } + *dest++ = i2c->DR; + } + } + + if (!next_len) { + // We sent a stop above, just wait for it to be finished + return i2c_wait_stop(i2c); + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_TXE))) { + return ret; + } + + // Write out the data + int num_acks = 0; + while (len--) { + i2c->DR = *src++; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_BTF))) { + return ret; + } + if (i2c->SR1 & I2C_SR1_AF) { + // Slave did not respond to byte so stop sending + break; + } + ++num_acks; + } + + if (!next_len) { + if (i2c->OAR1) { + // Send a STOP and wait for it to finish + i2c->CR1 |= I2C_CR1_STOP; + if ((ret = i2c_wait_stop(i2c))) { + return ret; + } + } + } + + return num_acks; +} + +#elif defined(STM32F0) || defined(STM32F7) + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = 0; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + // These timing values are for f_I2CCLK=54MHz and are only approximate + if (freq >= 1000000) { + i2c->TIMINGR = 0x50100103; + } else if (freq >= 400000) { + i2c->TIMINGR = 0x70330309; + } else if (freq >= 100000) { + i2c->TIMINGR = 0xb0420f13; + } else { + return -MP_EINVAL; + } + + i2c->TIMEOUTR = 0; + + return 0; +} + +STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR2 & mask) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->ISR & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +// len = 0, 1 or N +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) { + // Enable the peripheral and send the START condition with slave address + i2c->CR1 |= I2C_CR1_PE; + i2c->CR2 = stop << I2C_CR2_AUTOEND_Pos + | (len > 1) << I2C_CR2_RELOAD_Pos + | (len > 0) << I2C_CR2_NBYTES_Pos + | rd_wrn << I2C_CR2_RD_WRN_Pos + | (addr & 0x7f) << 1; + i2c->CR2 |= I2C_CR2_START; + + // Wait for address to be sent + int ret; + if ((ret = i2c_wait_cr2_clear(i2c, I2C_CR2_START))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->ISR & I2C_ISR_NACKF) { + // If we get a NACK then I2C periph unconditionally sends a STOP + i2c_wait_isr_set(i2c, I2C_ISR_STOPF); // Don't leak errors from this call + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ENODEV; + } + + // Repurpose OAR1 to indicate that we loaded CR2 + i2c->OAR1 = 1; + + return 0; +} + +STATIC int i2c_check_stop(i2c_t *i2c) { + if (i2c->CR2 & I2C_CR2_AUTOEND) { + // Wait for the STOP condition and then disable the peripheral + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_STOPF))) { + return ret; + } + i2c->CR1 &= ~I2C_CR1_PE; + } + + return 0; +} + +// next_len = 0 or N +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Read in the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_RXNE))) { + return ret; + } + *dest++ = i2c->RXDR; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int num_acks = 0; + + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Write out the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TXE))) { + return ret; + } + i2c->TXDR = *src++; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF))) { + return ret; + } + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_NACKF) { + // Slave did not respond to byte so stop sending + if (!(isr & I2C_ISR_TXE)) { + // The TXDR is still full so the byte previous to that wasn't actually ACK'd + --num_acks; + } + break; + } + ++num_acks; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return num_acks; +} + +#endif + +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 1, addr, len, stop))) { + return ret; + } + return i2c_read(i2c, dest, len, 0); +} + +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 0, addr, len, stop))) { + return ret; + } + return i2c_write(i2c, src, len, 0); +} + +#endif + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/src/openmv/src/micropython/ports/stm32/i2c.h b/src/openmv/src/micropython/ports/stm32/i2c.h new file mode 100755 index 0000000..5599f41 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/i2c.h @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_I2C_H +#define MICROPY_INCLUDED_STM32_I2C_H + +#include "dma.h" + +// use this for OwnAddress1 to configure I2C in master mode +#define PYB_I2C_MASTER_ADDRESS (0xfe) + +typedef struct _pyb_i2c_obj_t { + mp_obj_base_t base; + I2C_HandleTypeDef *i2c; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; + bool *use_dma; +} pyb_i2c_obj_t; + +extern I2C_HandleTypeDef I2CHandle1; +extern I2C_HandleTypeDef I2CHandle2; +extern I2C_HandleTypeDef I2CHandle3; +extern I2C_HandleTypeDef I2CHandle4; +extern const mp_obj_type_t pyb_i2c_type; +extern const pyb_i2c_obj_t pyb_i2c_obj[4]; + +void i2c_init0(void); +void pyb_i2c_init(I2C_HandleTypeDef *i2c); +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c); +void i2c_ev_irq_handler(mp_uint_t i2c_id); +void i2c_er_irq_handler(mp_uint_t i2c_id); + +typedef I2C_TypeDef i2c_t; + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq); +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop); +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len); +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len); +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop); +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop); + +#endif // MICROPY_INCLUDED_STM32_I2C_H diff --git a/src/openmv/src/micropython/ports/stm32/i2cslave.c b/src/openmv/src/micropython/ports/stm32/i2cslave.c new file mode 100755 index 0000000..473f0c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/i2cslave.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "i2cslave.h" + +#if defined(STM32F4) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR2 = I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN | 4 << I2C_CR2_FREQ_Pos; + i2c->OAR1 = 1 << 14 | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 = I2C_CR1_ACK | I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t sr1 = i2c->SR1; + if (sr1 & I2C_SR1_ADDR) { + // Address matched + // Read of SR1, SR2 needed to clear ADDR bit + sr1 = i2c->SR1; + uint32_t sr2 = i2c->SR2; + i2c_slave_process_addr_match((sr2 >> I2C_SR2_TRA_Pos) & 1); + } + if (sr1 & I2C_SR1_TXE) { + i2c->DR = i2c_slave_process_tx_byte(); + } + if (sr1 & I2C_SR1_RXNE) { + i2c_slave_process_rx_byte(i2c->DR); + } + if (sr1 & I2C_SR1_STOPF) { + // STOPF only set at end of RX mode (in TX mode AF is set on NACK) + // Read of SR1, write CR1 needed to clear STOPF bit + sr1 = i2c->SR1; + i2c->CR1 &= ~I2C_CR1_ACK; + i2c_slave_process_rx_end(); + i2c->CR1 |= I2C_CR1_ACK; + } +} + +#elif defined(STM32F7) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR1 = I2C_CR1_STOPIE | I2C_CR1_ADDRIE | I2C_CR1_RXIE | I2C_CR1_TXIE; + i2c->CR2 = 0; + i2c->OAR1 = I2C_OAR1_OA1EN | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 |= I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_ADDR) { + // Address matched + // Set TXE so that TXDR is flushed and ready for the first byte + i2c->ISR = I2C_ISR_TXE; + i2c->ICR = I2C_ICR_ADDRCF; + i2c_slave_process_addr_match(0); + } + if (isr & I2C_ISR_TXIS) { + i2c->TXDR = i2c_slave_process_tx_byte(); + } + if (isr & I2C_ISR_RXNE) { + i2c_slave_process_rx_byte(i2c->RXDR); + } + if (isr & I2C_ISR_STOPF) { + // STOPF only set for STOP condition, not a repeated START + i2c->ICR = I2C_ICR_STOPCF; + i2c->OAR1 &= ~I2C_OAR1_OA1EN; + if (i2c->ISR & I2C_ISR_DIR) { + //i2c_slave_process_tx_end(); + } else { + i2c_slave_process_rx_end(); + } + i2c->OAR1 |= I2C_OAR1_OA1EN; + } +} + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/i2cslave.h b/src/openmv/src/micropython/ports/stm32/i2cslave.h new file mode 100755 index 0000000..ac35c0c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/i2cslave.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_I2CSLAVE_H +#define MICROPY_INCLUDED_STM32_I2CSLAVE_H + +#include STM32_HAL_H + +typedef I2C_TypeDef i2c_slave_t; + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr); + +static inline void i2c_slave_init(i2c_slave_t *i2c, int irqn, int irq_pri, int addr) { + int en_bit = RCC_APB1ENR_I2C1EN_Pos + ((uintptr_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->APB1ENR; // Delay after enabling clock + (void)tmp; + + i2c_slave_init_helper(i2c, addr); + + NVIC_SetPriority(irqn, irq_pri); + NVIC_EnableIRQ(irqn); +} + +static inline void i2c_slave_shutdown(i2c_slave_t *i2c, int irqn) { + i2c->CR1 = 0; + NVIC_DisableIRQ(irqn); +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c); + +// These should be provided externally +int i2c_slave_process_addr_match(int rw); +int i2c_slave_process_rx_byte(uint8_t val); +void i2c_slave_process_rx_end(void); +uint8_t i2c_slave_process_tx_byte(void); + +#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H diff --git a/src/openmv/src/micropython/ports/stm32/irq.c b/src/openmv/src/micropython/ports/stm32/irq.c new file mode 100755 index 0000000..7298a4b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/irq.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/mphal.h" +#include "irq.h" + +/// \moduleref pyb + +#if IRQ_ENABLE_STATS +uint32_t irq_stats[FPU_IRQn + 1] = {0}; +#endif + +/// \function wfi() +/// Wait for an interrupt. +/// This executies a `wfi` instruction which reduces power consumption +/// of the MCU until an interrupt occurs, at which point execution continues. +STATIC mp_obj_t pyb_wfi(void) { + __WFI(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi); + +/// \function disable_irq() +/// Disable interrupt requests. +/// Returns the previous IRQ state: `False`/`True` for disabled/enabled IRQs +/// respectively. This return value can be passed to enable_irq to restore +/// the IRQ to its original state. +STATIC mp_obj_t pyb_disable_irq(void) { + return mp_obj_new_bool(disable_irq() == IRQ_STATE_ENABLED); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq); + +/// \function enable_irq(state=True) +/// Enable interrupt requests. +/// If `state` is `True` (the default value) then IRQs are enabled. +/// If `state` is `False` then IRQs are disabled. The most common use of +/// this function is to pass it the value returned by `disable_irq` to +/// exit a critical section. +STATIC mp_obj_t pyb_enable_irq(uint n_args, const mp_obj_t *arg) { + enable_irq((n_args == 0 || mp_obj_is_true(arg[0])) ? IRQ_STATE_ENABLED : IRQ_STATE_DISABLED); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj, 0, 1, pyb_enable_irq); + +#if IRQ_ENABLE_STATS +// return a memoryview of the irq statistics array +STATIC mp_obj_t pyb_irq_stats(void) { + return mp_obj_new_memoryview(0x80 | 'I', MP_ARRAY_SIZE(irq_stats), &irq_stats[0]); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_irq_stats_obj, pyb_irq_stats); +#endif diff --git a/src/openmv/src/micropython/ports/stm32/irq.h b/src/openmv/src/micropython/ports/stm32/irq.h new file mode 100755 index 0000000..9919013 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/irq.h @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_IRQ_H +#define MICROPY_INCLUDED_STM32_IRQ_H + +// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative, +// which helps the compiler optimise the resulting inline function. +#define IRQn_NONNEG(pri) ((pri) & 0x7f) + +// these states correspond to values from query_irq, enable_irq and disable_irq +#define IRQ_STATE_DISABLED (0x00000001) +#define IRQ_STATE_ENABLED (0x00000000) + +// Enable this to get a count for the number of times each irq handler is called, +// accessible via pyb.irq_stats(). +#define IRQ_ENABLE_STATS (0) + +#if IRQ_ENABLE_STATS +extern uint32_t irq_stats[FPU_IRQn + 1]; +#define IRQ_ENTER(irq) ++irq_stats[irq] +#define IRQ_EXIT(irq) +#else +#define IRQ_ENTER(irq) +#define IRQ_EXIT(irq) +#endif + +static inline mp_uint_t query_irq(void) { + return __get_PRIMASK(); +} + +// enable_irq and disable_irq are defined inline in mpconfigport.h + +#if __CORTEX_M >= 0x03 + +// irqs with a priority value greater or equal to "pri" will be disabled +// "pri" should be between 1 and 15 inclusive +static inline uint32_t raise_irq_pri(uint32_t pri) { + uint32_t basepri = __get_BASEPRI(); + // If non-zero, the processor does not process any exception with a + // priority value greater than or equal to BASEPRI. + // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: + // - Rn is non-zero and the current BASEPRI value is 0 + // - Rn is non-zero and less than the current BASEPRI value + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + return basepri; +} + +// "basepri" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t basepri) { + __set_BASEPRI(basepri); +} + +#endif + +MP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_disable_irq_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); + +// IRQ priority definitions. +// +// Lower number implies higher interrupt priority. +// +// The default priority grouping is set to NVIC_PRIORITYGROUP_4 in the +// HAL_Init function. This corresponds to 4 bits for the priority field +// and 0 bits for the sub-priority field (which means that for all intensive +// purposes that the sub-priorities below are ignored). +// +// While a given interrupt is being processed, only higher priority (lower number) +// interrupts will preempt a given interrupt. If sub-priorities are active +// then the sub-priority determines the order that pending interrupts of +// a given priority are executed. This is only meaningful if 2 or more +// interrupts of the same priority are pending at the same time. +// +// The priority of the SysTick timer is determined from the TICK_INT_PRIORITY +// value which is normally set to 0 in the stm32f4xx_hal_conf.h file. +// +// The following interrupts are arranged from highest priority to lowest +// priority to make it a bit easier to figure out. + +#if __CORTEX_M == 0 + +//#def IRQ_PRI_SYSTICK 0 +#define IRQ_PRI_UART 1 +#define IRQ_PRI_SDIO 1 +#define IRQ_PRI_DMA 1 +#define IRQ_PRI_FLASH 2 +#define IRQ_PRI_OTG_FS 2 +#define IRQ_PRI_OTG_HS 2 +#define IRQ_PRI_TIM5 2 +#define IRQ_PRI_CAN 2 +#define IRQ_PRI_TIMX 2 +#define IRQ_PRI_EXTINT 2 +#define IRQ_PRI_PENDSV 3 +#define IRQ_PRI_RTC_WKUP 3 + +#else + +//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) + +// The UARTs have no FIFOs, so if they don't get serviced quickly then characters +// get dropped. The handling for each character only consumes about 0.5 usec +#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0) + +// SDIO must be higher priority than DMA for SDIO DMA transfers to work. +#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0) + +// DMA should be higher priority than USB, since USB Mass Storage calls +// into the sdcard driver which waits for the DMA to complete. +#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0) + +// Flash IRQ (used for flushing storage cache) must be at the same priority as +// the USB IRQs, so that the IRQ priority can be raised to this level to disable +// both the USB and cache flushing, when storage transfers are in progress. +#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) + +#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) + +#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) + +// Interrupt priority for non-special timers. +#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0) + +#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) + +// PENDSV should be at the lowst priority so that other interrupts complete +// before exception is raised. +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + +#endif + +#endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/src/openmv/src/micropython/ports/stm32/lcd.c b/src/openmv/src/micropython/ports/stm32/lcd.c new file mode 100755 index 0000000..b35bd3b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/lcd.c @@ -0,0 +1,527 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" + +#if MICROPY_HW_HAS_LCD + +#include "pin.h" +#include "bufhelper.h" +#include "spi.h" +#include "font_petme128_8x8.h" +#include "lcd.h" + +/// \moduleref pyb +/// \class LCD - LCD control for the LCD touch-sensor pyskin +/// +/// The LCD class is used to control the LCD on the LCD touch-sensor pyskin, +/// LCD32MKv1.0. The LCD is a 128x32 pixel monochrome screen, part NHD-C12832A1Z. +/// +/// The pyskin must be connected in either the X or Y positions, and then +/// an LCD object is made using: +/// +/// lcd = pyb.LCD('X') # if pyskin is in the X position +/// lcd = pyb.LCD('Y') # if pyskin is in the Y position +/// +/// Then you can use: +/// +/// lcd.light(True) # turn the backlight on +/// lcd.write('Hello world!\n') # print text to the screen +/// +/// This driver implements a double buffer for setting/getting pixels. +/// For example, to make a bouncing dot, try: +/// +/// x = y = 0 +/// dx = dy = 1 +/// while True: +/// # update the dot's position +/// x += dx +/// y += dy +/// +/// # make the dot bounce of the edges of the screen +/// if x <= 0 or x >= 127: dx = -dx +/// if y <= 0 or y >= 31: dy = -dy +/// +/// lcd.fill(0) # clear the buffer +/// lcd.pixel(x, y, 1) # draw the dot +/// lcd.show() # show the buffer +/// pyb.delay(50) # pause for 50ms + +#define LCD_INSTR (0) +#define LCD_DATA (1) + +#define LCD_CHAR_BUF_W (16) +#define LCD_CHAR_BUF_H (4) + +#define LCD_PIX_BUF_W (128) +#define LCD_PIX_BUF_H (32) +#define LCD_PIX_BUF_BYTE_SIZE (LCD_PIX_BUF_W * LCD_PIX_BUF_H / 8) + +typedef struct _pyb_lcd_obj_t { + mp_obj_base_t base; + + // hardware control for the LCD + const spi_t *spi; + const pin_obj_t *pin_cs1; + const pin_obj_t *pin_rst; + const pin_obj_t *pin_a0; + const pin_obj_t *pin_bl; + + // character buffer for stdout-like output + char char_buffer[LCD_CHAR_BUF_W * LCD_CHAR_BUF_H]; + int line; + int column; + int next_line; + + // double buffering for pixel buffer + byte pix_buf[LCD_PIX_BUF_BYTE_SIZE]; + byte pix_buf2[LCD_PIX_BUF_BYTE_SIZE]; +} pyb_lcd_obj_t; + +STATIC void lcd_delay(void) { + __asm volatile ("nop\nnop"); +} + +STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) { + lcd_delay(); + mp_hal_pin_low(lcd->pin_cs1); // CS=0; enable + if (instr_data == LCD_INSTR) { + mp_hal_pin_low(lcd->pin_a0); // A0=0; select instr reg + } else { + mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg + } + lcd_delay(); + HAL_SPI_Transmit(lcd->spi->spi, &i, 1, 1000); + lcd_delay(); + mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable +} + +// write a string to the LCD at the current cursor location +// output it straight away (doesn't use the pixel buffer) +STATIC void lcd_write_strn(pyb_lcd_obj_t *lcd, const char *str, unsigned int len) { + int redraw_min = lcd->line * LCD_CHAR_BUF_W + lcd->column; + int redraw_max = redraw_min; + for (; len > 0; len--, str++) { + // move to next line if needed + if (lcd->next_line) { + if (lcd->line + 1 < LCD_CHAR_BUF_H) { + lcd->line += 1; + } else { + lcd->line = LCD_CHAR_BUF_H - 1; + for (int i = 0; i < LCD_CHAR_BUF_W * (LCD_CHAR_BUF_H - 1); i++) { + lcd->char_buffer[i] = lcd->char_buffer[i + LCD_CHAR_BUF_W]; + } + for (int i = 0; i < LCD_CHAR_BUF_W; i++) { + lcd->char_buffer[LCD_CHAR_BUF_W * (LCD_CHAR_BUF_H - 1) + i] = ' '; + } + redraw_min = 0; + redraw_max = LCD_CHAR_BUF_W * LCD_CHAR_BUF_H; + } + lcd->next_line = 0; + lcd->column = 0; + } + if (*str == '\n') { + lcd->next_line = 1; + } else if (*str == '\r') { + lcd->column = 0; + } else if (*str == '\b') { + if (lcd->column > 0) { + lcd->column--; + redraw_min = 0; // could optimise this to not redraw everything + } + } else if (lcd->column >= LCD_CHAR_BUF_W) { + lcd->next_line = 1; + str -= 1; + len += 1; + } else { + lcd->char_buffer[lcd->line * LCD_CHAR_BUF_W + lcd->column] = *str; + lcd->column += 1; + int max = lcd->line * LCD_CHAR_BUF_W + lcd->column; + if (max > redraw_max) { + redraw_max = max; + } + } + } + + // we must draw upside down, because the LCD is upside down + for (int i = redraw_min; i < redraw_max; i++) { + uint page = i / LCD_CHAR_BUF_W; + uint offset = 8 * (LCD_CHAR_BUF_W - 1 - (i - (page * LCD_CHAR_BUF_W))); + lcd_out(lcd, LCD_INSTR, 0xb0 | page); // page address set + lcd_out(lcd, LCD_INSTR, 0x10 | ((offset >> 4) & 0x0f)); // column address set upper + lcd_out(lcd, LCD_INSTR, 0x00 | (offset & 0x0f)); // column address set lower + int chr = lcd->char_buffer[i]; + if (chr < 32 || chr > 126) { + chr = 127; + } + const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8]; + for (int j = 7; j >= 0; j--) { + lcd_out(lcd, LCD_DATA, chr_data[j]); + } + } +} + +/// \classmethod \constructor(skin_position) +/// +/// Construct an LCD object in the given skin position. `skin_position` can be 'X' or 'Y', and +/// should match the position where the LCD pyskin is plugged in. +STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get LCD position + const char *lcd_id = mp_obj_str_get_str(args[0]); + + // create lcd object + pyb_lcd_obj_t *lcd = m_new_obj(pyb_lcd_obj_t); + lcd->base.type = &pyb_lcd_type; + + // configure pins + // TODO accept an SPI object and pin objects for full customisation + if ((lcd_id[0] | 0x20) == 'x' && lcd_id[1] == '\0') { + lcd->spi = &spi_obj[0]; + lcd->pin_cs1 = pyb_pin_X3; + lcd->pin_rst = pyb_pin_X4; + lcd->pin_a0 = pyb_pin_X5; + lcd->pin_bl = pyb_pin_X12; + } else if ((lcd_id[0] | 0x20) == 'y' && lcd_id[1] == '\0') { + lcd->spi = &spi_obj[1]; + lcd->pin_cs1 = pyb_pin_Y3; + lcd->pin_rst = pyb_pin_Y4; + lcd->pin_a0 = pyb_pin_Y5; + lcd->pin_bl = pyb_pin_Y12; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LCD(%s) doesn't exist", lcd_id)); + } + + // init the SPI bus + SPI_InitTypeDef *init = &lcd->spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + + // compute the baudrate prescaler from the desired baudrate + // select a prescaler that yields at most the desired baudrate + uint spi_clock; + if (lcd->spi->spi->Instance == SPI1) { + // SPI1 is on APB2 + spi_clock = HAL_RCC_GetPCLK2Freq(); + } else { + // SPI2 and SPI3 are on APB1 + spi_clock = HAL_RCC_GetPCLK1Freq(); + } + uint br_prescale = spi_clock / 16000000; // datasheet says LCD can run at 20MHz, but we go for 16MHz + if (br_prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } + else if (br_prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; } + else if (br_prescale <= 8) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; } + else if (br_prescale <= 16) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; } + else if (br_prescale <= 32) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; } + else if (br_prescale <= 64) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; } + else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; } + else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; } + + // data is sent bigendian, latches on rising clock + init->CLKPolarity = SPI_POLARITY_HIGH; + init->CLKPhase = SPI_PHASE_2EDGE; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->NSS = SPI_NSS_SOFT; + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 0; + + // init the SPI bus + spi_init(lcd->spi, false); + + // set the pins to default values + mp_hal_pin_high(lcd->pin_cs1); + mp_hal_pin_high(lcd->pin_rst); + mp_hal_pin_high(lcd->pin_a0); + mp_hal_pin_low(lcd->pin_bl); + + // init the pins to be push/pull outputs + mp_hal_pin_output(lcd->pin_cs1); + mp_hal_pin_output(lcd->pin_rst); + mp_hal_pin_output(lcd->pin_a0); + mp_hal_pin_output(lcd->pin_bl); + + // init the LCD + mp_hal_delay_ms(1); // wait a bit + mp_hal_pin_low(lcd->pin_rst); // RST=0; reset + mp_hal_delay_ms(1); // wait for reset; 2us min + mp_hal_pin_high(lcd->pin_rst); // RST=1; enable + mp_hal_delay_ms(1); // wait for reset; 2us min + lcd_out(lcd, LCD_INSTR, 0xa0); // ADC select, normal + lcd_out(lcd, LCD_INSTR, 0xc0); // common output mode select, normal (this flips the display) + lcd_out(lcd, LCD_INSTR, 0xa2); // LCD bias set, 1/9 bias + lcd_out(lcd, LCD_INSTR, 0x2f); // power control set, 0b111=(booster on, vreg on, vfollow on) + lcd_out(lcd, LCD_INSTR, 0x21); // v0 voltage regulator internal resistor ratio set, 0b001=small + lcd_out(lcd, LCD_INSTR, 0x81); // electronic volume mode set + lcd_out(lcd, LCD_INSTR, 0x28); // electronic volume register set + lcd_out(lcd, LCD_INSTR, 0x40); // display start line set, 0 + lcd_out(lcd, LCD_INSTR, 0xaf); // LCD display, on + + // clear LCD RAM + for (int page = 0; page < 4; page++) { + lcd_out(lcd, LCD_INSTR, 0xb0 | page); // page address set + lcd_out(lcd, LCD_INSTR, 0x10); // column address set upper + lcd_out(lcd, LCD_INSTR, 0x00); // column address set lower + for (int i = 0; i < 128; i++) { + lcd_out(lcd, LCD_DATA, 0x00); + } + } + + // clear local char buffer + memset(lcd->char_buffer, ' ', LCD_CHAR_BUF_H * LCD_CHAR_BUF_W); + lcd->line = 0; + lcd->column = 0; + lcd->next_line = 0; + + // clear local pixel buffer + memset(lcd->pix_buf, 0, LCD_PIX_BUF_BYTE_SIZE); + memset(lcd->pix_buf2, 0, LCD_PIX_BUF_BYTE_SIZE); + + return MP_OBJ_FROM_PTR(lcd); +} + +/// \method command(instr_data, buf) +/// +/// Send an arbitrary command to the LCD. Pass 0 for `instr_data` to send an +/// instruction, otherwise pass 1 to send data. `buf` is a buffer with the +/// instructions/data to send. +STATIC mp_obj_t pyb_lcd_command(mp_obj_t self_in, mp_obj_t instr_data_in, mp_obj_t val) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get whether instr or data + int instr_data = mp_obj_get_int(instr_data_in); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(val, &bufinfo, data); + + // send the data + for (uint i = 0; i < bufinfo.len; i++) { + lcd_out(self, instr_data, ((byte*)bufinfo.buf)[i]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_lcd_command_obj, pyb_lcd_command); + +/// \method contrast(value) +/// +/// Set the contrast of the LCD. Valid values are between 0 and 47. +STATIC mp_obj_t pyb_lcd_contrast(mp_obj_t self_in, mp_obj_t contrast_in) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + int contrast = mp_obj_get_int(contrast_in); + if (contrast < 0) { + contrast = 0; + } else if (contrast > 0x2f) { + contrast = 0x2f; + } + lcd_out(self, LCD_INSTR, 0x81); // electronic volume mode set + lcd_out(self, LCD_INSTR, contrast); // electronic volume register set + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_contrast_obj, pyb_lcd_contrast); + +/// \method light(value) +/// +/// Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off. +STATIC mp_obj_t pyb_lcd_light(mp_obj_t self_in, mp_obj_t value) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_obj_is_true(value)) { + mp_hal_pin_high(self->pin_bl); // set pin high to turn backlight on + } else { + mp_hal_pin_low(self->pin_bl); // set pin low to turn backlight off + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_light_obj, pyb_lcd_light); + +/// \method write(str) +/// +/// Write the string `str` to the screen. It will appear immediately. +STATIC mp_obj_t pyb_lcd_write(mp_obj_t self_in, mp_obj_t str) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t len; + const char *data = mp_obj_str_get_data(str, &len); + lcd_write_strn(self, data, len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_write_obj, pyb_lcd_write); + +/// \method fill(colour) +/// +/// Fill the screen with the given colour (0 or 1 for white or black). +/// +/// This method writes to the hidden buffer. Use `show()` to show the buffer. +STATIC mp_obj_t pyb_lcd_fill(mp_obj_t self_in, mp_obj_t col_in) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + int col = mp_obj_get_int(col_in); + if (col) { + col = 0xff; + } + memset(self->pix_buf, col, LCD_PIX_BUF_BYTE_SIZE); + memset(self->pix_buf2, col, LCD_PIX_BUF_BYTE_SIZE); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_fill_obj, pyb_lcd_fill); + +/// \method get(x, y) +/// +/// Get the pixel at the position `(x, y)`. Returns 0 or 1. +/// +/// This method reads from the visible buffer. +STATIC mp_obj_t pyb_lcd_get(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + int x = mp_obj_get_int(x_in); + int y = mp_obj_get_int(y_in); + if (0 <= x && x <= 127 && 0 <= y && y <= 31) { + uint byte_pos = x + 128 * ((uint)y >> 3); + if (self->pix_buf[byte_pos] & (1 << (y & 7))) { + return mp_obj_new_int(1); + } + } + return mp_obj_new_int(0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_lcd_get_obj, pyb_lcd_get); + +/// \method pixel(x, y, colour) +/// +/// Set the pixel at `(x, y)` to the given colour (0 or 1). +/// +/// This method writes to the hidden buffer. Use `show()` to show the buffer. +STATIC mp_obj_t pyb_lcd_pixel(size_t n_args, const mp_obj_t *args) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + if (0 <= x && x <= 127 && 0 <= y && y <= 31) { + uint byte_pos = x + 128 * ((uint)y >> 3); + if (mp_obj_get_int(args[3]) == 0) { + self->pix_buf2[byte_pos] &= ~(1 << (y & 7)); + } else { + self->pix_buf2[byte_pos] |= 1 << (y & 7); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_lcd_pixel_obj, 4, 4, pyb_lcd_pixel); + +/// \method text(str, x, y, colour) +/// +/// Draw the given text to the position `(x, y)` using the given colour (0 or 1). +/// +/// This method writes to the hidden buffer. Use `show()` to show the buffer. +STATIC mp_obj_t pyb_lcd_text(size_t n_args, const mp_obj_t *args) { + // extract arguments + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + size_t len; + const char *data = mp_obj_str_get_data(args[1], &len); + int x0 = mp_obj_get_int(args[2]); + int y0 = mp_obj_get_int(args[3]); + int col = mp_obj_get_int(args[4]); + + // loop over chars + for (const char *top = data + len; data < top; data++) { + // get char and make sure its in range of font + uint chr = *(byte*)data; + if (chr < 32 || chr > 127) { + chr = 127; + } + // get char data + const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8]; + // loop over char data + for (uint j = 0; j < 8; j++, x0++) { + if (0 <= x0 && x0 < LCD_PIX_BUF_W) { // clip x + uint vline_data = chr_data[j]; // each byte of char data is a vertical column of 8 pixels, LSB at top + for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column + if (vline_data & 1) { // only draw if pixel set + if (0 <= y && y < LCD_PIX_BUF_H) { // clip y + uint byte_pos = x0 + LCD_PIX_BUF_W * ((uint)y >> 3); + if (col == 0) { + // clear pixel + self->pix_buf2[byte_pos] &= ~(1 << (y & 7)); + } else { + // set pixel + self->pix_buf2[byte_pos] |= 1 << (y & 7); + } + } + } + } + } + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_lcd_text_obj, 5, 5, pyb_lcd_text); + +/// \method show() +/// +/// Show the hidden buffer on the screen. +STATIC mp_obj_t pyb_lcd_show(mp_obj_t self_in) { + pyb_lcd_obj_t *self = MP_OBJ_TO_PTR(self_in); + memcpy(self->pix_buf, self->pix_buf2, LCD_PIX_BUF_BYTE_SIZE); + for (uint page = 0; page < 4; page++) { + lcd_out(self, LCD_INSTR, 0xb0 | page); // page address set + lcd_out(self, LCD_INSTR, 0x10); // column address set upper; 0 + lcd_out(self, LCD_INSTR, 0x00); // column address set lower; 0 + for (uint i = 0; i < 128; i++) { + lcd_out(self, LCD_DATA, self->pix_buf[128 * page + 127 - i]); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_lcd_show_obj, pyb_lcd_show); + +STATIC const mp_rom_map_elem_t pyb_lcd_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_command), MP_ROM_PTR(&pyb_lcd_command_obj) }, + { MP_ROM_QSTR(MP_QSTR_contrast), MP_ROM_PTR(&pyb_lcd_contrast_obj) }, + { MP_ROM_QSTR(MP_QSTR_light), MP_ROM_PTR(&pyb_lcd_light_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_lcd_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&pyb_lcd_fill_obj) }, + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&pyb_lcd_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&pyb_lcd_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&pyb_lcd_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&pyb_lcd_show_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_lcd_locals_dict, pyb_lcd_locals_dict_table); + +const mp_obj_type_t pyb_lcd_type = { + { &mp_type_type }, + .name = MP_QSTR_LCD, + .make_new = pyb_lcd_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_lcd_locals_dict, +}; + +#endif // MICROPY_HW_HAS_LCD diff --git a/src/openmv/src/micropython/ports/stm32/lcd.h b/src/openmv/src/micropython/ports/stm32/lcd.h new file mode 100755 index 0000000..98f9048 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/lcd.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_LCD_H +#define MICROPY_INCLUDED_STM32_LCD_H + +extern const mp_obj_type_t pyb_lcd_type; + +#endif // MICROPY_INCLUDED_STM32_LCD_H diff --git a/src/openmv/src/micropython/ports/stm32/led.c b/src/openmv/src/micropython/ports/stm32/led.c new file mode 100755 index 0000000..be7d196 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/led.c @@ -0,0 +1,376 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "timer.h" +#include "led.h" +#include "pin.h" + +#if defined(MICROPY_HW_LED1) + +/// \moduleref pyb +/// \class LED - LED object +/// +/// The LED object controls an individual LED (Light Emitting Diode). + +// the default is that LEDs are not inverted, and pin driven high turns them on +#ifndef MICROPY_HW_LED_INVERTED +#define MICROPY_HW_LED_INVERTED (0) +#endif + +typedef struct _pyb_led_obj_t { + mp_obj_base_t base; + mp_uint_t led_id; + const pin_obj_t *led_pin; +} pyb_led_obj_t; + +STATIC const pyb_led_obj_t pyb_led_obj[] = { + {{&pyb_led_type}, 1, MICROPY_HW_LED1}, +#if defined(MICROPY_HW_LED2) + {{&pyb_led_type}, 2, MICROPY_HW_LED2}, +#if defined(MICROPY_HW_LED3) + {{&pyb_led_type}, 3, MICROPY_HW_LED3}, +#if defined(MICROPY_HW_LED4) + {{&pyb_led_type}, 4, MICROPY_HW_LED4}, +#endif +#endif +#endif +}; +#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) + +void led_init(void) { + /* Turn off LEDs and initialize */ + for (int led = 0; led < NUM_LEDS; led++) { + const pin_obj_t *led_pin = pyb_led_obj[led].led_pin; + mp_hal_gpio_clock_enable(led_pin->gpio); + MICROPY_HW_LED_OFF(led_pin); + mp_hal_pin_output(led_pin); + } +} + +#if defined(MICROPY_HW_LED1_PWM) \ + || defined(MICROPY_HW_LED2_PWM) \ + || defined(MICROPY_HW_LED3_PWM) \ + || defined(MICROPY_HW_LED4_PWM) + +// The following is semi-generic code to control LEDs using PWM. +// It currently supports TIM1, TIM2 and TIM3, channels 1-4. +// Configure by defining the relevant MICROPY_HW_LEDx_PWM macros in mpconfigboard.h. +// If they are not defined then PWM will not be available for that LED. + +#define LED_PWM_ENABLED (1) + +#ifndef MICROPY_HW_LED1_PWM +#define MICROPY_HW_LED1_PWM { NULL, 0, 0, 0 } +#endif +#ifndef MICROPY_HW_LED2_PWM +#define MICROPY_HW_LED2_PWM { NULL, 0, 0, 0 } +#endif +#ifndef MICROPY_HW_LED3_PWM +#define MICROPY_HW_LED3_PWM { NULL, 0, 0, 0 } +#endif +#ifndef MICROPY_HW_LED4_PWM +#define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 } +#endif + +#define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms + +// this gives the address of the CCR register for channels 1-4 +#define LED_PWM_CCR(pwm_cfg) ((volatile uint32_t*)&(pwm_cfg)->tim->CCR1 + ((pwm_cfg)->tim_channel >> 2)) + +typedef struct _led_pwm_config_t { + TIM_TypeDef *tim; + uint8_t tim_id; + uint8_t tim_channel; + uint8_t alt_func; +} led_pwm_config_t; + +STATIC const led_pwm_config_t led_pwm_config[] = { + MICROPY_HW_LED1_PWM, + MICROPY_HW_LED2_PWM, + MICROPY_HW_LED3_PWM, + MICROPY_HW_LED4_PWM, +}; + +STATIC uint8_t led_pwm_state = 0; + +static inline bool led_pwm_is_enabled(int led) { + return (led_pwm_state & (1 << led)) != 0; +} + +// this function has a large stack so it should not be inlined +STATIC void led_pwm_init(int led) __attribute__((noinline)); +STATIC void led_pwm_init(int led) { + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1]; + + // GPIO configuration + mp_hal_pin_config(led_pin, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, pwm_cfg->alt_func); + + // TIM configuration + switch (pwm_cfg->tim_id) { + case 1: __TIM1_CLK_ENABLE(); break; + case 2: __TIM2_CLK_ENABLE(); break; + case 3: __TIM3_CLK_ENABLE(); break; + default: assert(0); + } + TIM_HandleTypeDef tim = {0}; + tim.Instance = pwm_cfg->tim; + tim.Init.Period = LED_PWM_TIM_PERIOD - 1; + tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz + tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + tim.Init.CounterMode = TIM_COUNTERMODE_UP; + tim.Init.RepetitionCounter = 0; + HAL_TIM_PWM_Init(&tim); + + // PWM configuration + TIM_OC_InitTypeDef oc_init; + oc_init.OCMode = TIM_OCMODE_PWM1; + oc_init.Pulse = 0; // off + oc_init.OCPolarity = MICROPY_HW_LED_INVERTED ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH; + oc_init.OCFastMode = TIM_OCFAST_DISABLE; + oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; // needed for TIM1 and TIM8 + oc_init.OCIdleState = TIM_OCIDLESTATE_SET; // needed for TIM1 and TIM8 + oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; // needed for TIM1 and TIM8 + HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, pwm_cfg->tim_channel); + HAL_TIM_PWM_Start(&tim, pwm_cfg->tim_channel); + + // indicate that this LED is using PWM + led_pwm_state |= 1 << led; +} + +STATIC void led_pwm_deinit(int led) { + // make the LED's pin a standard GPIO output pin + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + GPIO_TypeDef *g = led_pin->gpio; + uint32_t pin = led_pin->pin; + static const int mode = 1; // output + static const int alt = 0; // no alt func + g->MODER = (g->MODER & ~(3 << (2 * pin))) | (mode << (2 * pin)); + g->AFR[pin >> 3] = (g->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); + led_pwm_state &= ~(1 << led); +} + +#else +#define LED_PWM_ENABLED (0) +#endif + +void led_state(pyb_led_t led, int state) { + if (led < 1 || led > NUM_LEDS) { + return; + } + + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + //printf("led_state(%d,%d)\n", led, state); + if (state == 0) { + // turn LED off + MICROPY_HW_LED_OFF(led_pin); + } else { + // turn LED on + MICROPY_HW_LED_ON(led_pin); + } + + #if LED_PWM_ENABLED + if (led_pwm_is_enabled(led)) { + led_pwm_deinit(led); + } + #endif +} + +void led_toggle(pyb_led_t led) { + if (led < 1 || led > NUM_LEDS) { + return; + } + + #if LED_PWM_ENABLED + if (led_pwm_is_enabled(led)) { + // if PWM is enabled then LED has non-zero intensity, so turn it off + led_state(led, 0); + return; + } + #endif + + // toggle the output data register to toggle the LED state + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + led_pin->gpio->ODR ^= led_pin->pin_mask; +} + +int led_get_intensity(pyb_led_t led) { + if (led < 1 || led > NUM_LEDS) { + return 0; + } + + #if LED_PWM_ENABLED + if (led_pwm_is_enabled(led)) { + const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1]; + mp_uint_t i = (*LED_PWM_CCR(pwm_cfg) * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1); + if (i > 255) { + i = 255; + } + return i; + } + #endif + + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + GPIO_TypeDef *gpio = led_pin->gpio; + + if (gpio->ODR & led_pin->pin_mask) { + // pin is high + return MICROPY_HW_LED_INVERTED ? 0 : 255; + } else { + // pin is low + return MICROPY_HW_LED_INVERTED ? 255 : 0; + } +} + +void led_set_intensity(pyb_led_t led, mp_int_t intensity) { + #if LED_PWM_ENABLED + if (intensity > 0 && intensity < 255) { + const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1]; + if (pwm_cfg->tim != NULL) { + // set intensity using PWM pulse width + if (!led_pwm_is_enabled(led)) { + led_pwm_init(led); + } + *LED_PWM_CCR(pwm_cfg) = intensity * (LED_PWM_TIM_PERIOD - 1) / 255; + return; + } + } + #endif + + // intensity not supported for this LED; just turn it on/off + led_state(led, intensity > 0); +} + +void led_debug(int n, int delay) { + led_state(1, n & 1); + led_state(2, n & 2); + led_state(3, n & 4); + led_state(4, n & 8); + mp_hal_delay_ms(delay); +} + +/******************************************************************************/ +/* MicroPython bindings */ + +void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "LED(%u)", self->led_id); +} + +/// \classmethod \constructor(id) +/// Create an LED object associated with the given LED: +/// +/// - `id` is the LED number, 1-4. +STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get led number + mp_int_t led_id = mp_obj_get_int(args[0]); + + // check led number + if (!(1 <= led_id && led_id <= NUM_LEDS)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED(%d) doesn't exist", led_id)); + } + + // return static led object + return MP_OBJ_FROM_PTR(&pyb_led_obj[led_id - 1]); +} + +/// \method on() +/// Turn the LED on. +mp_obj_t led_obj_on(mp_obj_t self_in) { + pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + led_state(self->led_id, 1); + return mp_const_none; +} + +/// \method off() +/// Turn the LED off. +mp_obj_t led_obj_off(mp_obj_t self_in) { + pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + led_state(self->led_id, 0); + return mp_const_none; +} + +/// \method toggle() +/// Toggle the LED between on and off. +mp_obj_t led_obj_toggle(mp_obj_t self_in) { + pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + led_toggle(self->led_id); + return mp_const_none; +} + +/// \method intensity([value]) +/// Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on). +/// If no argument is given, return the LED intensity. +/// If an argument is given, set the LED intensity and return `None`. +mp_obj_t led_obj_intensity(size_t n_args, const mp_obj_t *args) { + pyb_led_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_int(led_get_intensity(self->led_id)); + } else { + led_set_intensity(self->led_id, mp_obj_get_int(args[1])); + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(led_obj_intensity_obj, 1, 2, led_obj_intensity); + +STATIC const mp_rom_map_elem_t led_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) }, + { MP_ROM_QSTR(MP_QSTR_intensity), MP_ROM_PTR(&led_obj_intensity_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table); + +const mp_obj_type_t pyb_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = led_obj_print, + .make_new = led_obj_make_new, + .locals_dict = (mp_obj_dict_t*)&led_locals_dict, +}; + +#else +// For boards with no LEDs, we leave an empty function here so that we don't +// have to put conditionals everywhere. +void led_init(void) { +} +void led_state(pyb_led_t led, int state) { +} +void led_toggle(pyb_led_t led) { +} +#endif // defined(MICROPY_HW_LED1) diff --git a/src/openmv/src/micropython/ports/stm32/led.h b/src/openmv/src/micropython/ports/stm32/led.h new file mode 100755 index 0000000..1cc96b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/led.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_LED_H +#define MICROPY_INCLUDED_STM32_LED_H + +typedef enum { + PYB_LED_RED = 1, + PYB_LED_GREEN = 2, + PYB_LED_YELLOW = 3, + PYB_LED_BLUE = 4, +} pyb_led_t; + +void led_init(void); +void led_state(pyb_led_t led, int state); +void led_toggle(pyb_led_t led); +void led_debug(int value, int delay); + +extern const mp_obj_type_t pyb_led_type; + +#endif // MICROPY_INCLUDED_STM32_LED_H diff --git a/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/cc.h b/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/cc.h new file mode 100755 index 0000000..635b1c8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/cc.h @@ -0,0 +1,8 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H +#define MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H + +#include +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) { assert(1); } + +#endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H diff --git a/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/sys_arch.h b/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/sys_arch.h new file mode 100755 index 0000000..8b1a393 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/lwip_inc/arch/sys_arch.h @@ -0,0 +1 @@ +// empty diff --git a/src/openmv/src/micropython/ports/stm32/lwip_inc/lwipopts.h b/src/openmv/src/micropython/ports/stm32/lwip_inc/lwipopts.h new file mode 100755 index 0000000..b8ab8a2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/lwip_inc/lwipopts.h @@ -0,0 +1,61 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H +#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H + +#include + +#define NO_SYS 1 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_ALIGNMENT 4 + +#define LWIP_CHKSUM_ALGORITHM 3 + +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 +#define LWIP_STATS 0 +#define LWIP_NETIF_HOSTNAME 1 + +#define LWIP_IPV6 0 +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 1 +#define LWIP_DNS 1 +#define LWIP_IGMP 1 + +#define SO_REUSE 1 + +extern uint32_t rng_get(void); +#define LWIP_RAND() rng_get() + +// default +// lwip takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote +// TCP u/l is very slow + +#if 0 +// lwip takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network +#define MEM_SIZE (5000) +#define TCP_WND (4 * TCP_MSS) +#define TCP_SND_BUF (4 * TCP_MSS) +#endif + +#if 1 +// lwip takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network +#define MEM_SIZE (8000) +#define TCP_MSS (800) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +#if 0 +// lwip takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network +#define MEM_SIZE (16000) +#define TCP_MSS (1460) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +typedef uint32_t sys_prot_t; + +#endif // MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H diff --git a/src/openmv/src/micropython/ports/stm32/machine_i2c.c b/src/openmv/src/micropython/ports/stm32/machine_i2c.c new file mode 100755 index 0000000..b7a9ea6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/machine_i2c.c @@ -0,0 +1,256 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "extmod/machine_i2c.h" +#include "i2c.h" + +#if MICROPY_HW_ENABLE_HW_I2C + +STATIC const mp_obj_type_t machine_hard_i2c_type; + +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + +typedef struct _machine_hard_i2c_obj_t { + mp_obj_base_t base; + i2c_t *i2c; + mp_hal_pin_obj_t scl; + mp_hal_pin_obj_t sda; +} machine_hard_i2c_obj_t; + +STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { + #if defined(MICROPY_HW_I2C1_SCL) + {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&machine_hard_i2c_type}, I2C2, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&machine_hard_i2c_type}, I2C3, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&machine_hard_i2c_type}, I2C4, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif +}; + +STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + #if defined(STM32F4) + + uint32_t freq = self->i2c->CR2 & 0x3f; + uint32_t ccr = self->i2c->CCR; + if (ccr & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + freq = freq * 40000 / (ccr & 0xfff); + } else { + // Standard mode + freq = freq * 500000 / (ccr & 0xfff); + } + + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq); + + #else + + uint32_t timingr = self->i2c->TIMINGR; + uint32_t presc = timingr >> 28; + uint32_t sclh = timingr >> 8 & 0xff; + uint32_t scll = timingr & 0xff; + uint32_t freq = HAL_RCC_GetPCLK1Freq() / (presc + 1) / (sclh + scll + 2); + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u, timingr=0x%08x)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq, timingr); + + #endif +} + +void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { + (void)timeout; + i2c_init(self->i2c, self->scl, self->sda, freq); +} + +int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_readfrom(self->i2c, addr, dest, len, stop); +} + +int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_writeto(self->i2c, addr, src, len, stop); +} + +#else + +// No hardware I2C driver for this MCU so use the software implementation + +typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t; + +STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { + #if defined(MICROPY_HW_I2C1_SCL) + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, + #else + {{NULL}, 0, 0, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, + #else + {{NULL}, 0, 0, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, + #else + {{NULL}, 0, 0, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, + #else + {{NULL}, 0, 0, NULL, NULL}, + #endif +}; + +STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u, timeout=%u)", + self - &machine_hard_i2c_obj[0] + 1, + self->scl->name, self->sda->name, 500000 / self->us_delay, self->us_timeout); +} + +STATIC void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { + // set parameters + if (freq >= 1000000) { + // allow fastest possible bit-bang rate + self->us_delay = 0; + } else { + self->us_delay = 500000 / freq; + if (self->us_delay == 0) { + self->us_delay = 1; + } + } + + self->us_timeout = timeout; + + // init pins + mp_hal_pin_open_drain(self->scl); + mp_hal_pin_open_drain(self->sda); +} + +#define machine_hard_i2c_readfrom mp_machine_soft_i2c_readfrom +#define machine_hard_i2c_writeto mp_machine_soft_i2c_writeto + +#endif + +/******************************************************************************/ +/* MicroPython bindings for machine API */ + +mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse args + enum { ARG_id, ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // work out i2c bus + int i2c_id = 0; + if (MP_OBJ_IS_STR(args[ARG_id].u_obj)) { + const char *port = mp_obj_str_get_str(args[ARG_id].u_obj); + if (0) { + #ifdef MICROPY_HW_I2C1_NAME + } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) { + i2c_id = 1; + #endif + #ifdef MICROPY_HW_I2C2_NAME + } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) { + i2c_id = 2; + #endif + #ifdef MICROPY_HW_I2C3_NAME + } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) { + i2c_id = 3; + #endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%s) doesn't exist", port)); + } + } else { + i2c_id = mp_obj_get_int(args[ARG_id].u_obj); + if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(machine_hard_i2c_obj) + || machine_hard_i2c_obj[i2c_id - 1].base.type == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%d) doesn't exist", i2c_id)); + } + } + + // get static peripheral object + machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)&machine_hard_i2c_obj[i2c_id - 1]; + + // here we would check the scl/sda pins and configure them, but it's not implemented + if (args[ARG_scl].u_obj != MP_OBJ_NULL || args[ARG_sda].u_obj != MP_OBJ_NULL) { + mp_raise_ValueError("explicit choice of scl/sda is not implemented"); + } + + // initialise the I2C peripheral + machine_hard_i2c_init(self, args[ARG_freq].u_int, args[ARG_timeout].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = { + .readfrom = machine_hard_i2c_readfrom, + .writeto = machine_hard_i2c_writeto, +}; + +STATIC const mp_obj_type_t machine_hard_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = machine_hard_i2c_print, + .make_new = machine_hard_i2c_make_new, + .protocol = &machine_hard_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/src/openmv/src/micropython/ports/stm32/machine_spi.c b/src/openmv/src/micropython/ports/stm32/machine_spi.c new file mode 100755 index 0000000..dedcafc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/machine_spi.c @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "extmod/machine_spi.h" +#include "spi.h" + +/******************************************************************************/ +// Implementation of hard SPI for machine module + +STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = { + {{&machine_hard_spi_type}, &spi_obj[0]}, + {{&machine_hard_spi_type}, &spi_obj[1]}, + {{&machine_hard_spi_type}, &spi_obj[2]}, + {{&machine_hard_spi_type}, &spi_obj[3]}, + {{&machine_hard_spi_type}, &spi_obj[4]}, + {{&machine_hard_spi_type}, &spi_obj[5]}, +}; + +STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + spi_print(print, self->spi, false); +} + +mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_FIRSTBIT_MSB} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get static peripheral object + int spi_id = spi_find_index(args[ARG_id].u_obj); + const machine_hard_spi_obj_t *self = &machine_hard_spi_obj[spi_id - 1]; + + // here we would check the sck/mosi/miso pins and configure them, but it's not implemented + if (args[ARG_sck].u_obj != MP_OBJ_NULL + || args[ARG_mosi].u_obj != MP_OBJ_NULL + || args[ARG_miso].u_obj != MP_OBJ_NULL) { + mp_raise_ValueError("explicit choice of sck/mosi/miso is not implemented"); + } + + // set the SPI configuration values + SPI_InitTypeDef *init = &self->spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + + // these parameters are not currently configurable + init->Direction = SPI_DIRECTION_2LINES; + init->NSS = SPI_NSS_SOFT; + init->TIMode = SPI_TIMODE_DISABLE; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; + init->CRCPolynomial = 0; + + // set configurable paramaters + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, + args[ARG_firstbit].u_int); + + // init the SPI bus + spi_init(self->spi, false); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; + + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set the SPI configuration values + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, + args[ARG_firstbit].u_int); + + // re-init the SPI bus + spi_init(self->spi, false); +} + +STATIC void machine_hard_spi_deinit(mp_obj_base_t *self_in) { + machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; + spi_deinit(self->spi); +} + +STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); +} + +STATIC const mp_machine_spi_p_t machine_hard_spi_p = { + .init = machine_hard_spi_init, + .deinit = machine_hard_spi_deinit, + .transfer = machine_hard_spi_transfer, +}; + +const mp_obj_type_t machine_hard_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hard_spi_print, + .make_new = mp_machine_spi_make_new, // delegate to master constructor + .protocol = &machine_hard_spi_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/main.c b/src/openmv/src/micropython/ports/stm32/main.c new file mode 100755 index 0000000..7656569 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/main.c @@ -0,0 +1,769 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "lib/oofatfs/ff.h" +#include "lwip/init.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" + +#include "systick.h" +#include "pendsv.h" +#include "pybthread.h" +#include "gccollect.h" +#include "modmachine.h" +#include "i2c.h" +#include "spi.h" +#include "uart.h" +#include "timer.h" +#include "led.h" +#include "pin.h" +#include "extint.h" +#include "usrsw.h" +#include "usb.h" +#include "rtc.h" +#include "storage.h" +#include "sdcard.h" +#include "sdram.h" +#include "rng.h" +#include "accel.h" +#include "servo.h" +#include "dac.h" +#include "can.h" +#include "modnetwork.h" + +void SystemClock_Config(void); + +pyb_thread_t pyb_thread_main; +fs_user_mount_t fs_user_mount_flash; + +void flash_error(int n) { + for (int i = 0; i < n; i++) { + led_state(PYB_LED_RED, 1); + led_state(PYB_LED_GREEN, 0); + mp_hal_delay_ms(250); + led_state(PYB_LED_RED, 0); + led_state(PYB_LED_GREEN, 1); + mp_hal_delay_ms(250); + } + led_state(PYB_LED_GREEN, 0); +} + +void NORETURN __fatal_error(const char *msg) { + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + led_state(1, 1); + led_state(2, 1); + led_state(3, 1); + led_state(4, 1); + mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14); + mp_hal_stdout_tx_strn(msg, strlen(msg)); + for (uint i = 0;;) { + led_toggle(((i++) & 3) + 1); + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + if (i >= 16) { + // to conserve power + __WFI(); + } + } +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val)); + __fatal_error(""); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + (void)func; + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error(""); +} +#endif + +STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_opt, MP_ARG_INT, {.u_int = 0} } + }; + + if (MP_OBJ_IS_STR(pos_args[0])) { + MP_STATE_PORT(pyb_config_main) = pos_args[0]; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + MP_STATE_VM(mp_optimise_value) = args[0].u_int; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main); + +#if MICROPY_HW_ENABLE_STORAGE +static const char fresh_boot_py[] = +"# boot.py -- run on boot-up\r\n" +"# can run arbitrary Python, but best to keep it minimal\r\n" +"\r\n" +"import machine\r\n" +"import pyb\r\n" +"#pyb.main('main.py') # main script to run after this one\r\n" +#if MICROPY_HW_ENABLE_USB +"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n" +"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n" +#endif +; + +static const char fresh_main_py[] = +"# main.py -- put your code here!\r\n" +; + +static const char fresh_pybcdc_inf[] = +#include "genhdr/pybcdc_inf.h" +; + +static const char fresh_readme_txt[] = +"This is a MicroPython board\r\n" +"\r\n" +"You can get started right away by writing your Python code in 'main.py'.\r\n" +"\r\n" +"For a serial prompt:\r\n" +" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n" +" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n" +" Then use a terminal program like Hyperterminal or putty.\r\n" +" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n" +" - Linux: use the command: screen /dev/ttyACM0\r\n" +"\r\n" +"Please visit http://micropython.org/help/ for further help.\r\n" +; + +// avoid inlining to avoid stack usage within main() +MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { + // init the vfs object + fs_user_mount_t *vfs_fat = &fs_user_mount_flash; + vfs_fat->flags = 0; + pyb_flash_init_vfs(vfs_fat); + + // try to mount the flash + FRESULT res = f_mount(&vfs_fat->fatfs); + + if (reset_mode == 3 || res == FR_NO_FILESYSTEM) { + // no filesystem, or asked to reset it, so create a fresh one + + // LED on to indicate creation of LFS + led_state(PYB_LED_GREEN, 1); + uint32_t start_tick = HAL_GetTick(); + + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)); + if (res == FR_OK) { + // success creating fresh LFS + } else { + printf("PYB: can't create flash filesystem\n"); + return false; + } + + // set label + f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL); + + // create empty main.py + FIL fp; + f_open(&vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS); + UINT n; + f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n); + // TODO check we could write n bytes + f_close(&fp); + + // create .inf driver file + f_open(&vfs_fat->fatfs, &fp, "/pybcdc.inf", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n); + f_close(&fp); + + // create readme file + f_open(&vfs_fat->fatfs, &fp, "/README.txt", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n); + f_close(&fp); + + // keep LED on for at least 200ms + sys_tick_wait_at_least(start_tick, 200); + led_state(PYB_LED_GREEN, 0); + } else if (res == FR_OK) { + // mount sucessful + } else { + fail: + printf("PYB: can't mount flash\n"); + return false; + } + + // mount the flash device (there should be no other devices mounted at this point) + // we allocate this structure on the heap because vfs->next is a root pointer + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL) { + goto fail; + } + vfs->str = "/flash"; + vfs->len = 6; + vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); + vfs->next = NULL; + MP_STATE_VM(vfs_mount_table) = vfs; + + // The current directory is used as the boot up directory. + // It is set to the internal flash filesystem by default. + MP_STATE_PORT(vfs_cur) = vfs; + + // Make sure we have a /flash/boot.py. Create it if needed. + FILINFO fno; + res = f_stat(&vfs_fat->fatfs, "/boot.py", &fno); + if (res != FR_OK) { + // doesn't exist, create fresh file + + // LED on to indicate creation of boot.py + led_state(PYB_LED_GREEN, 1); + uint32_t start_tick = HAL_GetTick(); + + FIL fp; + f_open(&vfs_fat->fatfs, &fp, "/boot.py", FA_WRITE | FA_CREATE_ALWAYS); + UINT n; + f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n); + // TODO check we could write n bytes + f_close(&fp); + + // keep LED on for at least 200ms + sys_tick_wait_at_least(start_tick, 200); + led_state(PYB_LED_GREEN, 0); + } + + return true; +} +#endif + +#if MICROPY_HW_HAS_SDCARD +STATIC bool init_sdcard_fs(void) { + bool first_part = true; + for (int part_num = 1; part_num <= 4; ++part_num) { + // create vfs object + fs_user_mount_t *vfs_fat = m_new_obj_maybe(fs_user_mount_t); + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL || vfs_fat == NULL) { + break; + } + vfs_fat->flags = FSUSER_FREE_OBJ; + sdcard_init_vfs(vfs_fat, part_num); + + // try to mount the partition + FRESULT res = f_mount(&vfs_fat->fatfs); + + if (res != FR_OK) { + // couldn't mount + m_del_obj(fs_user_mount_t, vfs_fat); + m_del_obj(mp_vfs_mount_t, vfs); + } else { + // mounted via FatFs, now mount the SD partition in the VFS + if (first_part) { + // the first available partition is traditionally called "sd" for simplicity + vfs->str = "/sd"; + vfs->len = 3; + } else { + // subsequent partitions are numbered by their index in the partition table + if (part_num == 2) { + vfs->str = "/sd2"; + } else if (part_num == 2) { + vfs->str = "/sd3"; + } else { + vfs->str = "/sd4"; + } + vfs->len = 4; + } + vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); + vfs->next = NULL; + for (mp_vfs_mount_t **m = &MP_STATE_VM(vfs_mount_table);; m = &(*m)->next) { + if (*m == NULL) { + *m = vfs; + break; + } + } + + #if MICROPY_HW_ENABLE_USB + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + // if no USB MSC medium is selected then use the SD card + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; + } + #endif + + #if MICROPY_HW_ENABLE_USB + // only use SD card as current directory if that's what the USB medium is + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD) + #endif + { + if (first_part) { + // use SD card as current directory + MP_STATE_PORT(vfs_cur) = vfs; + } + } + first_part = false; + } + } + + if (first_part) { + printf("PYB: can't mount SD card\n"); + return false; + } else { + return true; + } +} +#endif + +#if !MICROPY_HW_USES_BOOTLOADER +STATIC uint update_reset_mode(uint reset_mode) { + #if MICROPY_HW_HAS_SWITCH + if (switch_get()) { + + // The original method used on the pyboard is appropriate if you have 2 + // or more LEDs. + #if defined(MICROPY_HW_LED2) + for (uint i = 0; i < 3000; i++) { + if (!switch_get()) { + break; + } + mp_hal_delay_ms(20); + if (i % 30 == 29) { + if (++reset_mode > 3) { + reset_mode = 1; + } + led_state(2, reset_mode & 1); + led_state(3, reset_mode & 2); + led_state(4, reset_mode & 4); + } + } + // flash the selected reset mode + for (uint i = 0; i < 6; i++) { + led_state(2, 0); + led_state(3, 0); + led_state(4, 0); + mp_hal_delay_ms(50); + led_state(2, reset_mode & 1); + led_state(3, reset_mode & 2); + led_state(4, reset_mode & 4); + mp_hal_delay_ms(50); + } + mp_hal_delay_ms(400); + + #elif defined(MICROPY_HW_LED1) + + // For boards with only a single LED, we'll flash that LED the + // appropriate number of times, with a pause between each one + for (uint i = 0; i < 10; i++) { + led_state(1, 0); + for (uint j = 0; j < reset_mode; j++) { + if (!switch_get()) { + break; + } + led_state(1, 1); + mp_hal_delay_ms(100); + led_state(1, 0); + mp_hal_delay_ms(200); + } + mp_hal_delay_ms(400); + if (!switch_get()) { + break; + } + if (++reset_mode > 3) { + reset_mode = 1; + } + } + // Flash the selected reset mode + for (uint i = 0; i < 2; i++) { + for (uint j = 0; j < reset_mode; j++) { + led_state(1, 1); + mp_hal_delay_ms(100); + led_state(1, 0); + mp_hal_delay_ms(200); + } + mp_hal_delay_ms(400); + } + #else + #error Need a reset mode update method + #endif + } + #endif + return reset_mode; +} +#endif + +void stm32_main(uint32_t reset_mode) { + // Enable caches and prefetch buffers + + #if defined(STM32F4) + + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #elif defined(STM32F7) || defined(STM32H7) + + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + + SCB_EnableICache(); + SCB_EnableDCache(); + + #elif defined(STM32L4) + + #if !INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); + #endif + #if !DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_DISABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #endif + + #if __CORTEX_M >= 0x03 + // Set the priority grouping + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + #endif + + // SysTick is needed by HAL_RCC_ClockConfig (called in SystemClock_Config) + HAL_InitTick(TICK_INT_PRIORITY); + + // set the system clock to be HSE + SystemClock_Config(); + + // enable GPIO clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + #if defined(STM32F4) || defined(STM32F7) + #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE) + // The STM32F746 doesn't really have CCM memory, but it does have DTCM, + // which behaves more or less like normal SRAM. + __HAL_RCC_DTCMRAMEN_CLK_ENABLE(); + #elif defined(CCMDATARAM_BASE) + // enable the CCM RAM + __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); + #endif + #elif defined(STM32H7) + // Enable D2 SRAM1/2/3 clocks. + __HAL_RCC_D2SRAM1_CLK_ENABLE(); + __HAL_RCC_D2SRAM2_CLK_ENABLE(); + __HAL_RCC_D2SRAM3_CLK_ENABLE(); + #endif + + + #if defined(MICROPY_BOARD_EARLY_INIT) + MICROPY_BOARD_EARLY_INIT(); + #endif + + // basic sub-system init + #if MICROPY_HW_SDRAM_SIZE + sdram_init(); + #if MICROPY_HW_SDRAM_STARTUP_TEST + sdram_test(true); + #endif + #endif + #if MICROPY_PY_THREAD + pyb_thread_init(&pyb_thread_main); + #endif + pendsv_init(); + led_init(); + #if MICROPY_HW_HAS_SWITCH + switch_init0(); + #endif + machine_init(); + #if MICROPY_HW_ENABLE_RTC + rtc_init_start(false); + #endif + spi_init0(); + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C + i2c_init0(); + #endif + #if MICROPY_HW_HAS_SDCARD + sdcard_init(); + #endif + #if MICROPY_HW_ENABLE_STORAGE + storage_init(); + #endif + #if MICROPY_PY_LWIP + // lwIP doesn't allow to reinitialise itself by subsequent calls to this function + // because the system timeout list (next_timeout) is only ever reset by BSS clearing. + // So for now we only init the lwIP stack once on power-up. + lwip_init(); + #endif + +soft_reset: + + #if defined(MICROPY_HW_LED2) + led_state(1, 0); + led_state(2, 1); + #else + led_state(1, 1); + led_state(2, 0); + #endif + led_state(3, 0); + led_state(4, 0); + + #if !MICROPY_HW_USES_BOOTLOADER + // check if user switch held to select the reset mode + reset_mode = update_reset_mode(1); + #endif + + // Python threading init + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif + + // Stack limit should be less than real stack size, so we have a chance + // to recover from limit hit. (Limit is measured in bytes.) + // Note: stack control relies on main thread being initialised above + mp_stack_set_top(&_estack); + mp_stack_set_limit((char*)&_estack - (char*)&_heap_end - 1024); + + // GC init + gc_init(MICROPY_HEAP_START, MICROPY_HEAP_END); + + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[384]; + mp_pystack_init(pystack, &pystack[384]); + #endif + + // MicroPython init + mp_init(); + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + + // Initialise low-level sub-systems. Here we need to very basic things like + // zeroing out memory and resetting any of the sub-systems. Following this + // we can run Python scripts (eg boot.py), but anything that is configurable + // by boot.py must be set after boot.py is run. + + readline_init0(); + pin_init0(); + extint_init0(); + timer_init0(); + uart_init0(); + + // Define MICROPY_HW_UART_REPL to be PYB_UART_6 and define + // MICROPY_HW_UART_REPL_BAUD in your mpconfigboard.h file if you want a + // REPL on a hardware UART as well as on USB VCP + #if defined(MICROPY_HW_UART_REPL) + { + mp_obj_t args[2] = { + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL), + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL_BAUD), + }; + MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); + } + #else + MP_STATE_PORT(pyb_stdio_uart) = NULL; + #endif + + #if MICROPY_HW_ENABLE_CAN + can_init0(); + #endif + + #if MICROPY_HW_ENABLE_USB + pyb_usb_init0(); + #endif + + // Initialise the local flash filesystem. + // Create it if needed, mount in on /flash, and set it as current dir. + bool mounted_flash = false; + #if MICROPY_HW_ENABLE_STORAGE + mounted_flash = init_flash_fs(reset_mode); + #endif + + bool mounted_sdcard = false; + #if MICROPY_HW_HAS_SDCARD + // if an SD card is present then mount it on /sd/ + if (sdcard_is_present()) { + // if there is a file in the flash called "SKIPSD", then we don't mount the SD card + if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) { + mounted_sdcard = init_sdcard_fs(); + } + } + #endif + + #if MICROPY_HW_ENABLE_USB + // if the SD card isn't used as the USB MSC medium then use the internal flash + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; + } + #endif + + // set sys.path based on mounted filesystems (/sd is first so it can override /flash) + if (mounted_sdcard) { + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib)); + } + if (mounted_flash) { + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); + } + + // reset config variables; they should be set by boot.py + MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; + + // run boot.py, if it exists + // TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py + if (reset_mode == 1 || reset_mode == 3) { + const char *boot_py = "boot.py"; + mp_import_stat_t stat = mp_import_stat(boot_py); + if (stat == MP_IMPORT_STAT_FILE) { + int ret = pyexec_file(boot_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + flash_error(4); + } + } + } + + // turn boot-up LEDs off + #if !defined(MICROPY_HW_LED2) + // If there is only one LED on the board then it's used to signal boot-up + // and so we turn it off here. Otherwise LED(1) is used to indicate dirty + // flash cache and so we shouldn't change its state. + led_state(1, 0); + #endif + led_state(2, 0); + led_state(3, 0); + led_state(4, 0); + + // Now we initialise sub-systems that need configuration from boot.py, + // or whose initialisation can be safely deferred until after running + // boot.py. + + #if MICROPY_HW_ENABLE_USB + // init USB device to default setting if it was not already configured + if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { + pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); + } + #endif + + #if MICROPY_HW_HAS_MMA7660 + // MMA accel: init and reset + accel_init(); + #endif + + #if MICROPY_HW_ENABLE_SERVO + servo_init(); + #endif + + #if MICROPY_HW_ENABLE_DAC + dac_init(); + #endif + + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif + + // At this point everything is fully configured and initialised. + + // Run the main script from the current directory. + if ((reset_mode == 1 || reset_mode == 3) && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + const char *main_py; + if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) { + main_py = "main.py"; + } else { + main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main)); + } + mp_import_stat_t stat = mp_import_stat(main_py); + if (stat == MP_IMPORT_STAT_FILE) { + int ret = pyexec_file(main_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { + flash_error(3); + } + } + } + + // Main script is finished, so now go into REPL mode. + // The REPL mode can change, or it can request a soft reset. + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + +soft_reset_exit: + + // soft reset + + #if MICROPY_HW_ENABLE_STORAGE + printf("PYB: sync filesystems\n"); + storage_flush(); + #endif + + printf("PYB: soft reboot\n"); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif + timer_deinit(); + uart_deinit(); + #if MICROPY_HW_ENABLE_CAN + can_deinit(); + #endif + machine_deinit(); + + #if MICROPY_PY_THREAD + pyb_thread_deinit(); + #endif + + gc_sweep_all(); + + goto soft_reset; +} diff --git a/src/openmv/src/micropython/ports/stm32/make-stmconst.py b/src/openmv/src/micropython/ports/stm32/make-stmconst.py new file mode 100755 index 0000000..d509d00 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/make-stmconst.py @@ -0,0 +1,260 @@ +""" +This script reads in the given CMSIS device include file (eg stm32f405xx.h), +extracts relevant peripheral constants, and creates qstrs, mpz's and constants +for the stm module. +""" + +from __future__ import print_function + +import argparse +import re + +# Python 2/3 compatibility +import platform +if platform.python_version_tuple()[0] == '2': + def convert_bytes_to_str(b): + return b +elif platform.python_version_tuple()[0] == '3': + def convert_bytes_to_str(b): + try: + return str(b, 'utf8') + except ValueError: + # some files have invalid utf8 bytes, so filter them out + return ''.join(chr(l) for l in b if l <= 126) +# end compatibility code + +# given a list of (name,regex) pairs, find the first one that matches the given line +def re_match_first(regexs, line): + for name, regex in regexs: + match = re.match(regex, line) + if match: + return name, match + return None, None + +class LexerError(Exception): + def __init__(self, line): + self.line = line + +class Lexer: + re_io_reg = r'__IO uint(?P8|16|32)_t +(?P[A-Z0-9]+)' + re_comment = r'(?P[A-Za-z0-9 \-/_()&]+)' + re_addr_offset = r'Address offset: (?P0x[0-9A-Z]{2,3})' + regexs = ( + ('#define hex', re.compile(r'#define +(?P[A-Z0-9_]+) +(?:\(\(uint32_t\))?(?P0x[0-9A-F]+)U?(?:\))?($| +/\*)')), + ('#define X', re.compile(r'#define +(?P[A-Z0-9_]+) +(?P[A-Z0-9_]+)($| +/\*)')), + ('#define X+hex', re.compile(r'#define +(?P[A-Za-z0-9_]+) +\((?P[A-Z0-9_]+) \+ (?P0x[0-9A-F]+)U?\)($| +/\*)')), + ('#define typedef', re.compile(r'#define +(?P[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P[A-Za-z0-9_]+)\)($| +/\*)')), + ('typedef struct', re.compile(r'typedef struct$')), + ('{', re.compile(r'{$')), + ('}', re.compile(r'}$')), + ('} TypeDef', re.compile(r'} *(?P[A-Z][A-Za-z0-9_]+)_(?P([A-Za-z0-9_]+)?)TypeDef;$')), + ('IO reg', re.compile(re_io_reg + r'; +/\*!< ' + re_comment + r', +' + re_addr_offset + r' *\*/')), + ('IO reg array', re.compile(re_io_reg + r'\[(?P[2-8])\]; +/\*!< ' + re_comment + r', +' + re_addr_offset + r'-(0x[0-9A-Z]{2,3}) *\*/')), + ) + + def __init__(self, filename): + self.file = open(filename, 'rb') + self.line_number = 0 + + def next_match(self, strictly_next=False): + while True: + line = self.file.readline() + line = convert_bytes_to_str(line) + self.line_number += 1 + if len(line) == 0: + return ('EOF', None) + match = re_match_first(Lexer.regexs, line.strip()) + if strictly_next or match[0] is not None: + return match + + def must_match(self, kind): + match = self.next_match(strictly_next=True) + if match[0] != kind: + raise LexerError(self.line_number) + return match + +def parse_file(filename): + lexer = Lexer(filename) + + reg_defs = {} + consts = {} + periphs = [] + while True: + m = lexer.next_match() + if m[0] == 'EOF': + break + elif m[0] == '#define hex': + d = m[1].groupdict() + consts[d['id']] = int(d['hex'], base=16) + elif m[0] == '#define X': + d = m[1].groupdict() + if d['id2'] in consts: + consts[d['id']] = consts[d['id2']] + elif m[0] == '#define X+hex': + d = m[1].groupdict() + if d['id2'] in consts: + consts[d['id']] = consts[d['id2']] + int(d['hex'], base=16) + elif m[0] == '#define typedef': + d = m[1].groupdict() + if d['id2'] in consts: + periphs.append((d['id'], consts[d['id2']])) + elif m[0] == 'typedef struct': + lexer.must_match('{') + m = lexer.next_match() + regs = [] + while m[0] in ('IO reg', 'IO reg array'): + d = m[1].groupdict() + reg = d['reg'] + offset = int(d['offset'], base=16) + bits = int(d['bits']) + comment = d['comment'] + if m[0] == 'IO reg': + regs.append((reg, offset, bits, comment)) + else: + for i in range(int(d['array'])): + regs.append((reg + str(i), offset + i * bits // 8, bits, comment)) + m = lexer.next_match() + if m[0] == '}': + pass + elif m[0] == '} TypeDef': + reg_defs[m[1].groupdict()['id']] = regs + else: + raise LexerError(lexer.line_number) + + return periphs, reg_defs + +def print_int_obj(val, needed_mpzs): + if -0x40000000 <= val < 0x40000000: + print('MP_ROM_INT(%#x)' % val, end='') + else: + print('MP_ROM_PTR(&mpz_%08x)' % val, end='') + needed_mpzs.add(val) + +def print_periph(periph_name, periph_val, needed_qstrs, needed_mpzs): + qstr = periph_name.upper() + print('{ MP_ROM_QSTR(MP_QSTR_%s), ' % qstr, end='') + print_int_obj(periph_val, needed_mpzs) + print(' },') + needed_qstrs.add(qstr) + +def print_regs(reg_name, reg_defs, needed_qstrs, needed_mpzs): + reg_name = reg_name.upper() + for r in reg_defs: + qstr = reg_name + '_' + r[0] + print('{ MP_ROM_QSTR(MP_QSTR_%s), ' % qstr, end='') + print_int_obj(r[1], needed_mpzs) + print(' }, // %s-bits, %s' % (r[2], r[3])) + needed_qstrs.add(qstr) + +# This version of print regs groups registers together into submodules (eg GPIO submodule). +# This makes the qstrs shorter, and makes the list of constants more manageable (since +# they are not all in one big module) but it is then harder to compile the constants, and +# is more cumbersome to access. +# As such, we don't use this version. +# And for the number of constants we have, this function seems to use about the same amount +# of ROM as print_regs. +def print_regs_as_submodules(reg_name, reg_defs, modules, needed_qstrs): + mod_name_lower = reg_name.lower() + '_' + mod_name_upper = mod_name_lower.upper() + modules.append((mod_name_lower, mod_name_upper)) + + print(""" +STATIC const mp_rom_map_elem_t stm_%s_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_%s) }, +""" % (mod_name_lower, mod_name_upper)) + needed_qstrs.add(mod_name_upper) + + for r in reg_defs: + print(' { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_INT(%#x) }, // %s-bits, %s' % (r[0], r[1], r[2], r[3])) + needed_qstrs.add(r[0]) + + print("""}; + +STATIC MP_DEFINE_CONST_DICT(stm_%s_globals, stm_%s_globals_table); + +const mp_obj_module_t stm_%s_obj = { + .base = { &mp_type_module }, + .name = MP_QSTR_%s, + .globals = (mp_obj_dict_t*)&stm_%s_globals, +}; +""" % (mod_name_lower, mod_name_lower, mod_name_lower, mod_name_upper, mod_name_lower)) + +def main(): + cmd_parser = argparse.ArgumentParser(description='Extract ST constants from a C header file.') + cmd_parser.add_argument('file', nargs=1, help='input file') + cmd_parser.add_argument('-q', '--qstr', dest='qstr_filename', default='build/stmconst_qstr.h', + help='Specified the name of the generated qstr header file') + cmd_parser.add_argument('--mpz', dest='mpz_filename', default='build/stmconst_mpz.h', + help='the destination file of the generated mpz header') + args = cmd_parser.parse_args() + + periphs, reg_defs = parse_file(args.file[0]) + + # add legacy GPIO constants that were removed when upgrading CMSIS + if 'GPIO' in reg_defs and 'stm32f4' in args.file[0]: + reg_defs['GPIO'].append(['BSRRL', 0x18, 16, 'legacy register']) + reg_defs['GPIO'].append(['BSRRH', 0x1a, 16, 'legacy register']) + + modules = [] + needed_qstrs = set() + needed_mpzs = set() + + print("// Automatically generated from %s by make-stmconst.py" % args.file[0]) + print("") + + for periph_name, periph_val in periphs: + print_periph(periph_name, periph_val, needed_qstrs, needed_mpzs) + + for reg in ( + 'ADC', + #'ADC_Common', + #'CAN_TxMailBox', + #'CAN_FIFOMailBox', + #'CAN_FilterRegister', + #'CAN', + 'CRC', + 'DAC', + 'DBGMCU', + 'DMA_Stream', + 'DMA', + 'EXTI', + 'FLASH', + 'GPIO', + 'SYSCFG', + 'I2C', + 'IWDG', + 'PWR', + 'RCC', + 'RTC', + #'SDIO', + 'SPI', + 'TIM', + 'USART', + 'WWDG', + 'RNG', + ): + if reg in reg_defs: + print_regs(reg, reg_defs[reg], needed_qstrs, needed_mpzs) + #print_regs_as_submodules(reg, reg_defs[reg], modules, needed_qstrs) + + #print("#define MOD_STM_CONST_MODULES \\") + #for mod_lower, mod_upper in modules: + # print(" { MP_ROM_QSTR(MP_QSTR_%s), MP_ROM_PTR(&stm_%s_obj) }, \\" % (mod_upper, mod_lower)) + + print("") + + with open(args.qstr_filename, 'wt') as qstr_file: + print('#if MICROPY_PY_STM', file=qstr_file) + for qstr in sorted(needed_qstrs): + print('Q({})'.format(qstr), file=qstr_file) + print('#endif // MICROPY_PY_STM', file=qstr_file) + + with open(args.mpz_filename, 'wt') as mpz_file: + for mpz in sorted(needed_mpzs): + assert 0 <= mpz <= 0xffffffff + print('STATIC const mp_obj_int_t mpz_%08x = {{&mp_type_int}, ' + '{.neg=0, .fixed_dig=1, .alloc=2, .len=2, ' '.dig=(uint16_t*)(const uint16_t[]){%#x, %#x}}};' + % (mpz, mpz & 0xffff, (mpz >> 16) & 0xffff), file=mpz_file) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/stm32/mboot/Makefile b/src/openmv/src/micropython/ports/stm32/mboot/Makefile new file mode 100755 index 0000000..e892f91 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mboot/Makefile @@ -0,0 +1,190 @@ +# Select the board to build for: if not given on the command line, +# then default to PYBV10. +BOARD ?= PYBV10 +ifeq ($(wildcard ../boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +include ../../../py/mkenv.mk +include ../boards/$(BOARD)/mpconfigboard.mk + +CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include +MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver +USBDEV_DIR=usbdev +DFU=$(TOP)/tools/dfu.py +PYDFU ?= $(TOP)/tools/pydfu.py +DEVICE=0483:df11 +STFLASH ?= st-flash +OPENOCD ?= openocd +OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I.. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(CMSIS_DIR)/ +INC += -I$(TOP)/$(HAL_DIR)/Inc +INC += -I../$(USBDEV_DIR)/core/inc -I../$(USBDEV_DIR)/class/inc + +# Basic Cortex-M flags +CFLAGS_CORTEX_M = -mthumb + +# Options for particular MCU series +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 + +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += -D$(CMSIS_MCU) +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(COPT) +CFLAGS += -I../boards/$(BOARD) +CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DBOARD_$(BOARD) +CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) + +LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Remove uncalled code from the final image. +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += --gc-sections + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g -DPENDSV_DEBUG +COPT = -O0 +else +COPT += -Os -DNDEBUG +endif + +SRC_LIB = $(addprefix lib/,\ + libc/string0.c \ + ) + +SRC_C = \ + main.c \ + drivers/bus/softspi.c \ + drivers/bus/softqspi.c \ + drivers/memory/spiflash.c \ + ports/stm32/i2cslave.c \ + ports/stm32/qspi.c \ + ports/stm32/flashbdev.c \ + ports/stm32/spibdev.c \ + ports/stm32/usbd_conf.c \ + $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c)) + +SRC_O = \ + ports/stm32/boards/startup_stm32$(MCU_SERIES).o \ + ports/stm32/resethandler.o \ + +$(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_ll_usb.o: CFLAGS += -Wno-attributes +SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_cortex.c \ + hal_flash.c \ + hal_flash_ex.c \ + hal_pcd.c \ + hal_pcd_ex.c \ + ll_usb.c \ + ) + +SRC_USBDEV = $(addprefix ports/stm32/$(USBDEV_DIR)/,\ + core/src/usbd_core.c \ + core/src/usbd_ctlreq.c \ + core/src/usbd_ioreq.c \ + ) + +OBJ = +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_O)) +OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) + +all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex + +# For convenience, automatically fetch required submodules if they don't exist +$(TOP)/lib/stm32lib/README.md: + $(ECHO) "stm32lib submodule not found, fetching it now..." + (cd $(TOP) && git submodule update --init lib/stm32lib) + +.PHONY: deploy + +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" + $(Q)$(PYTHON) $(PYDFU) -u $< + +FLASH_ADDR = 0x08000000 + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware.bin $@ + +$(BUILD)/firmware.hex: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O ihex $< $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +######################################### + +vpath %.S . $(TOP) +$(BUILD)/%.o: %.S + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS) -c -o $@ $< + +vpath %.s . $(TOP) +$(BUILD)/%.o: %.s + $(ECHO) "AS $<" + $(Q)$(AS) -o $@ $< + +define compile_c +$(ECHO) "CC $<" +$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.c . $(TOP) +$(BUILD)/%.o: %.c + $(call compile_c) + +# $(sort $(var)) removes duplicates +# +# The net effect of this, is it causes the objects to depend on the +# object directories (but only for existence), and the object directories +# will be created if they don't exist. +OBJ_DIRS = $(sort $(dir $(OBJ))) +$(OBJ): | $(OBJ_DIRS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +clean: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) +.PHONY: clean + +########################################### + +$(BUILD)/main.o: $(BUILD)/genhdr/qstrdefs.generated.h + +$(BUILD)/genhdr/qstrdefs.generated.h: + $(MKDIR) -p $(BUILD)/genhdr + $(Q)echo "// empty" > $@ + +-include $(OBJ:.o=.P) diff --git a/src/openmv/src/micropython/ports/stm32/mboot/README.md b/src/openmv/src/micropython/ports/stm32/mboot/README.md new file mode 100755 index 0000000..2ff6101 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mboot/README.md @@ -0,0 +1,78 @@ +Mboot - MicroPython boot loader +=============================== + +Mboot is a custom bootloader for STM32 MCUs, and currently supports the +STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface +on either the FS or HS peripherals, as well as a sophisticated, custom I2C +interface. It fits in 16k of flash space. + +How to use +---------- + +1. Configure your board to use a boot loader by editing the mpconfigboard.mk + and mpconfigboard.h files. For example, for an F767 be sure to have these + lines in mpconfigboard.mk: + + LD_FILES = boards/stm32f767.ld boards/common_bl.ld + TEXT0_ADDR = 0x08008000 + + And this in mpconfigboard.h (recommended to put at the end of the file): + + // Bootloader configuration + #define MBOOT_I2C_PERIPH_ID 1 + #define MBOOT_I2C_SCL (pin_B8) + #define MBOOT_I2C_SDA (pin_B9) + #define MBOOT_I2C_ALTFUNC (4) + + To configure a pin to force entry into the boot loader the following + options can be used (with example configuration): + + #define MBOOT_BOOTPIN_PIN (pin_A0) + #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP) + #define MBOOT_BOOTPIN_ACTIVE (0) + + Mboot supports programming external SPI flash via the DFU and I2C + interfaces. SPI flash will be mapped to an address range. To + configure it use the following options (edit as needed): + + #define MBOOT_SPIFLASH_ADDR (0x80000000) + #define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024) + #define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg" + #define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4) + #define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash) + #define MBOOT_SPIFLASH_CONFIG (&spiflash_config) + + This assumes that the board declares and defines the relevant SPI flash + configuration structs, eg in the board-specific bdev.c file. The + `MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and + must describe the SPI flash layout. Note that the number of pages in + this layout description (the `64` above) cannot be larger than 99 (it + must fit in two digits) so the reported page size (the `32Kg` above) + must be made large enough so the number of pages fits in two digits. + Alternatively the layout can specify multiple sections like + `32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE` + must be changed to `16 / 4` to match tho `16Kg` value. + + Mboot supports up to two external SPI flash devices. To configure the + second one use the same configuration names as above but with + `SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc. + +2. Build the board's main application firmware as usual. + +3. Build mboot via: + + $ cd mboot + $ make BOARD= + + That should produce a DFU file for mboot. It can be deployed using + USB DFU programming via (it will be placed at location 0x08000000): + + $ make BOARD= deploy + +4. Reset the board while holding USR until all 3 LEDs are lit (the 4th option in + the cycle) and then release USR. LED0 will then blink once per second to + indicate that it's in mboot + +5. Use either USB DFU or I2C to download firmware. The script mboot.py shows how + to communicate with the I2C boot loader interface. It should be run on a + pyboard connected via I2C to the target board. diff --git a/src/openmv/src/micropython/ports/stm32/mboot/main.c b/src/openmv/src/micropython/ports/stm32/mboot/main.c new file mode 100755 index 0000000..0f042c9 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mboot/main.c @@ -0,0 +1,1336 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "extmod/crypto-algorithms/sha256.c" +#include "usbd_core.h" +#include "storage.h" +#include "i2cslave.h" + +// Using polling is about 10% faster than not using it (and using IRQ instead) +// This DFU code with polling runs in about 70% of the time of the ST bootloader +#define USE_USB_POLLING (1) + +// Using cache probably won't make it faster because we run at 48MHz, and best +// to keep the MCU config as minimal as possible. +#define USE_CACHE (0) + +// IRQ priorities (encoded values suitable for NVIC_SetPriority) +#define IRQ_PRI_SYSTICK (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)) +#define IRQ_PRI_I2C (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)) + +// Configure PLL to give a 48MHz CPU freq +#define CORE_PLL_FREQ (48000000) +#undef MICROPY_HW_CLK_PLLM +#undef MICROPY_HW_CLK_PLLN +#undef MICROPY_HW_CLK_PLLP +#undef MICROPY_HW_CLK_PLLQ +#undef MICROPY_HW_FLASH_LATENCY +#define MICROPY_HW_CLK_PLLM (HSE_VALUE / 1000000) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1 + +// Work out which USB device to use for the USB DFU interface +#if !defined(MICROPY_HW_USB_MAIN_DEV) +#if MICROPY_HW_USB_FS +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) +#elif MICROPY_HW_USB_HS && MICROPY_HW_USB_HS_IN_FS +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +#else +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif +#endif + +// These bits are used to detect valid application firmware at APPLICATION_ADDR +#define APP_VALIDITY_BITS (0x00000003) + +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static void do_reset(void); + +static uint32_t get_le32(const uint8_t *b) { + return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; +} + +void mp_hal_delay_us(mp_uint_t usec) { + // use a busy loop for the delay + // sys freq is always a multiple of 2MHz, so division here won't lose precision + const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2; + for (uint32_t count = 0; ++count <= ucount;) { + } +} + +static volatile uint32_t systick_ms; + +void mp_hal_delay_ms(mp_uint_t ms) { + if (__get_PRIMASK() == 0) { + // IRQs enabled, use systick + if (ms != 0 && ms != (mp_uint_t)-1) { + ++ms; // account for the fact that systick_ms may roll over immediately + } + uint32_t start = systick_ms; + while (systick_ms - start < ms) { + __WFI(); + } + } else { + // IRQs disabled, so need to use a busy loop for the delay. + // To prevent possible overflow of the counter we use a double loop. + const uint32_t count_1ms = 16000000 / 8000; + for (uint32_t i = 0; i < ms; i++) { + for (volatile uint32_t count = 0; ++count <= count_1ms;) { + } + } + } +} + +// Needed by parts of the HAL +uint32_t HAL_GetTick(void) { + return systick_ms; +} + +// Needed by parts of the HAL +void HAL_Delay(uint32_t ms) { + mp_hal_delay_ms(ms); +} + +static void __fatal_error(const char *msg) { + NVIC_SystemReset(); + for (;;) { + } +} + +/******************************************************************************/ +// CLOCK + +#if defined(STM32F4) || defined(STM32F7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x24003010) + +#else +#error Unknown processor +#endif + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= CONFIG_RCC_CR_1ST; + + // Reset CFGR register + RCC->CFGR = 0x00000000; + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= ~CONFIG_RCC_CR_2ND; + + // Reset PLLCFGR register + RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFF; + + // Disable all interrupts + RCC->CIR = 0x00000000; + + // Set location of vector table + SCB->VTOR = FLASH_BASE; + + // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void systick_init(void) { + // Configure SysTick as 1ms ticker + SysTick_Config(SystemCoreClock / 1000); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); +} + +void SystemClock_Config(void) { + // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits) + + // Enable Power Control clock + __HAL_RCC_PWR_CLK_ENABLE(); + + // Reduce power consumption + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Turn HSE on + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) { + } + + // Disable PLL + __HAL_RCC_PLL_DISABLE(); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) { + } + + // Configure PLL factors and source + RCC->PLLCFGR = + 1 << RCC_PLLCFGR_PLLSRC_Pos // HSE selected as PLL source + | MICROPY_HW_CLK_PLLM << RCC_PLLCFGR_PLLM_Pos + | MICROPY_HW_CLK_PLLN << RCC_PLLCFGR_PLLN_Pos + | ((MICROPY_HW_CLK_PLLP >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos + | MICROPY_HW_CLK_PLLQ << RCC_PLLCFGR_PLLQ_Pos + #ifdef RCC_PLLCFGR_PLLR + | 2 << RCC_PLLCFGR_PLLR_Pos // default PLLR value of 2 + #endif + ; + + // Enable PLL + __HAL_RCC_PLL_ENABLE(); + while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) { + } + + // Increase latency before changing clock + if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Configure AHB divider + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + + // Configure SYSCLK source from PLL + __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK); + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) { + } + + // Decrease latency after changing clock + if (MICROPY_HW_FLASH_LATENCY < (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Set APB clock dividers + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV4); + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV2 << 3); + + // Update clock value and reconfigure systick now that the frequency changed + SystemCoreClock = CORE_PLL_FREQ; + systick_init(); + + #if defined(STM32F7) + // The DFU bootloader changes the clocksource register from its default power + // on reset value, so we set it back here, so the clocksources are the same + // whether we were started from DFU or from a power on reset. + RCC->DCKCFGR2 = 0; + #endif +} + +// Needed by HAL_PCD_IRQHandler +uint32_t HAL_RCC_GetHCLKFreq(void) { + return SystemCoreClock; +} + +/******************************************************************************/ +// GPIO + +void mp_hal_pin_config(mp_hal_pin_obj_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + + // Enable the GPIO peripheral clock + uint32_t en_bit = RCC_AHB1ENR_GPIOAEN_Pos + ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->AHB1ENR; // Delay after enabling clock + (void)tmp; + + // Configure the pin + uint32_t pin = port_pin & 0xf; + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed + gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} + +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + uint32_t pin = port_pin & 0xf; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} + +/******************************************************************************/ +// LED + +#define LED0 MICROPY_HW_LED1 +#define LED1 MICROPY_HW_LED2 +#define LED2 MICROPY_HW_LED3 + +void led_init(void) { + mp_hal_pin_output(LED0); + mp_hal_pin_output(LED1); + mp_hal_pin_output(LED2); +} + +void led_state(int led, int val) { + if (led == 1) { + led = LED0; + } + if (val) { + MICROPY_HW_LED_ON(led); + } else { + MICROPY_HW_LED_OFF(led); + } +} + +/******************************************************************************/ +// USR BUTTON + +static void usrbtn_init(void) { + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); +} + +static int usrbtn_state(void) { + return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED; +} + +/******************************************************************************/ +// FLASH + +#ifndef MBOOT_SPIFLASH_LAYOUT +#define MBOOT_SPIFLASH_LAYOUT "" +#endif + +#ifndef MBOOT_SPIFLASH2_LAYOUT +#define MBOOT_SPIFLASH2_LAYOUT "" +#endif + +typedef struct { + uint32_t base_address; + uint32_t sector_size; + uint32_t sector_count; +} flash_layout_t; + +#if defined(STM32F7) +// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to +// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 +#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR +#endif + +#if defined(STM32F4) \ + || defined(STM32F722xx) \ + || defined(STM32F723xx) \ + || defined(STM32F732xx) \ + || defined(STM32F733xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x04000, 4 }, + { 0x08010000, 0x10000, 1 }, + { 0x08020000, 0x20000, 3 }, + #if defined(FLASH_SECTOR_8) + { 0x08080000, 0x20000, 4 }, + #endif + #if defined(FLASH_SECTOR_12) + { 0x08100000, 0x04000, 4 }, + { 0x08110000, 0x10000, 1 }, + { 0x08120000, 0x20000, 7 }, + #endif +}; + +#elif defined(STM32F765xx) || defined(STM32F767xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT + +// This is for dual-bank mode disabled +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x08000, 4 }, + { 0x08020000, 0x20000, 1 }, + { 0x08040000, 0x40000, 7 }, +}; + +#endif + +static uint32_t flash_get_sector_index(uint32_t addr) { + if (addr >= flash_layout[0].base_address) { + uint32_t sector_index = 0; + for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) { + for (int j = 0; j < flash_layout[i].sector_count; ++j) { + uint32_t sector_start_next = flash_layout[i].base_address + + (j + 1) * flash_layout[i].sector_size; + if (addr < sector_start_next) { + return sector_index; + } + ++sector_index; + } + } + } + return 0; +} + +static int flash_mass_erase(void) { + // TODO + return -1; +} + +static int flash_page_erase(uint32_t addr) { + uint32_t sector = flash_get_sector_index(addr); + if (sector == 0) { + // Don't allow to erase the sector with this bootloader in it + return -1; + } + + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = sector; + EraseInitStruct.NbSectors = 1; + + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + return -1; + } + + // Check the erase set bits to 1, at least for the first 256 bytes + for (int i = 0; i < 64; ++i) { + if (((volatile uint32_t*)addr)[i] != 0xffffffff) { + return -2; + } + } + + return 0; +} + +static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) { + if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) { + // Don't allow to write the sector with this bootloader in it + return -1; + } + + const uint32_t *src = (const uint32_t*)src8; + size_t num_word32 = (len + 3) / 4; + HAL_FLASH_Unlock(); + // program the flash word by word + for (size_t i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, addr, *src) != HAL_OK) { + return -1; + } + addr += 4; + src += 1; + } + + // TODO verify data + + return 0; +} + +/******************************************************************************/ +// Writable address space interface + +static int do_mass_erase(void) { + // TODO + return flash_mass_erase(); +} + +#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR) +static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) { + for (int i = 0; i < n_blocks; ++i) { + int ret = mp_spiflash_erase_block(spif, addr); + if (ret != 0) { + return ret; + } + addr += MP_SPIFLASH_ERASE_BLOCK_SIZE; + } + return 0; +} +#endif + +static int do_page_erase(uint32_t addr) { + led_state(LED0, 1); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH, + addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH, + addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE); + } + #endif + + return flash_page_erase(addr); +} + +static void do_read(uint32_t addr, int len, uint8_t *buf) { + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf); + return; + } + #endif + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf); + return; + } + #endif + + // Other addresses, just read directly from memory + memcpy(buf, (void*)addr, len); +} + +static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { + static uint32_t led_tog = 0; + led_state(LED0, (led_tog++) & 4); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8); + } + #endif + + return flash_write(addr, src8, len); +} + +/******************************************************************************/ +// I2C slave interface + +#if defined(MBOOT_I2C_SCL) + +#define PASTE2(a, b) a ## b +#define PASTE3(a, b, c) a ## b ## c +#define EVAL_PASTE2(a, b) PASTE2(a, b) +#define EVAL_PASTE3(a, b, c) PASTE3(a, b, c) + +#define MBOOT_I2Cx EVAL_PASTE2(I2C, MBOOT_I2C_PERIPH_ID) +#define I2Cx_EV_IRQn EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQn) +#define I2Cx_EV_IRQHandler EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQHandler) + +#define I2C_CMD_BUF_LEN (129) + +enum { + I2C_CMD_ECHO = 1, + I2C_CMD_GETID, // () -> u8*12 unique id, ASCIIZ mcu name, ASCIIZ board name + I2C_CMD_GETCAPS, // not implemented + I2C_CMD_RESET, // () -> () + I2C_CMD_CONFIG, // not implemented + I2C_CMD_GETLAYOUT, // () -> ASCII string + I2C_CMD_MASSERASE, // () -> () + I2C_CMD_PAGEERASE, // le32 -> () + I2C_CMD_SETRDADDR, // le32 -> () + I2C_CMD_SETWRADDR, // le32 -> () + I2C_CMD_READ, // u8 -> bytes + I2C_CMD_WRITE, // bytes -> () + I2C_CMD_COPY, // not implemented + I2C_CMD_CALCHASH, // le32 -> u8*32 + I2C_CMD_MARKVALID, // () -> () +}; + +typedef struct _i2c_obj_t { + volatile bool cmd_send_arg; + volatile bool cmd_arg_sent; + volatile int cmd_arg; + volatile uint32_t cmd_rdaddr; + volatile uint32_t cmd_wraddr; + volatile uint16_t cmd_buf_pos; + uint8_t cmd_buf[I2C_CMD_BUF_LEN]; +} i2c_obj_t; + +static i2c_obj_t i2c_obj; + +void i2c_init(int addr) { + i2c_obj.cmd_send_arg = false; + + mp_hal_pin_config(MBOOT_I2C_SCL, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + mp_hal_pin_config(MBOOT_I2C_SDA, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + + i2c_slave_init(MBOOT_I2Cx, I2Cx_EV_IRQn, IRQ_PRI_I2C, addr); +} + +int i2c_slave_process_addr_match(int rw) { + if (i2c_obj.cmd_arg_sent) { + i2c_obj.cmd_send_arg = false; + } + i2c_obj.cmd_buf_pos = 0; + return 0; // ACK +} + +int i2c_slave_process_rx_byte(uint8_t val) { + if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = val; + } + return 0; // ACK +} + +void i2c_slave_process_rx_end(void) { + if (i2c_obj.cmd_buf_pos == 0) { + return; + } + + int len = i2c_obj.cmd_buf_pos - 1; + uint8_t *buf = i2c_obj.cmd_buf; + + if (buf[0] == I2C_CMD_ECHO) { + ++len; + } else if (buf[0] == I2C_CMD_GETID && len == 0) { + memcpy(buf, (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS, 12); + memcpy(buf + 12, MICROPY_HW_MCU_NAME, sizeof(MICROPY_HW_MCU_NAME)); + memcpy(buf + 12 + sizeof(MICROPY_HW_MCU_NAME), MICROPY_HW_BOARD_NAME, sizeof(MICROPY_HW_BOARD_NAME) - 1); + len = 12 + sizeof(MICROPY_HW_MCU_NAME) + sizeof(MICROPY_HW_BOARD_NAME) - 1; + } else if (buf[0] == I2C_CMD_RESET && len == 0) { + do_reset(); + } else if (buf[0] == I2C_CMD_GETLAYOUT && len == 0) { + len = strlen(FLASH_LAYOUT_STR); + memcpy(buf, FLASH_LAYOUT_STR, len); + } else if (buf[0] == I2C_CMD_MASSERASE && len == 0) { + len = do_mass_erase(); + } else if (buf[0] == I2C_CMD_PAGEERASE && len == 4) { + len = do_page_erase(get_le32(buf + 1)); + } else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) { + i2c_obj.cmd_rdaddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_SETWRADDR && len == 4) { + i2c_obj.cmd_wraddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_READ && len == 1) { + len = buf[1]; + if (len > I2C_CMD_BUF_LEN) { + len = I2C_CMD_BUF_LEN; + } + do_read(i2c_obj.cmd_rdaddr, len, buf); + i2c_obj.cmd_rdaddr += len; + } else if (buf[0] == I2C_CMD_WRITE) { + if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) { + // Mark the 2 lower bits to indicate invalid app firmware + buf[1] |= APP_VALIDITY_BITS; + } + int ret = do_write(i2c_obj.cmd_wraddr, buf + 1, len); + if (ret < 0) { + len = ret; + } else { + i2c_obj.cmd_wraddr += len; + len = 0; + } + } else if (buf[0] == I2C_CMD_CALCHASH && len == 4) { + uint32_t hashlen = get_le32(buf + 1); + static CRYAL_SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, (const void*)i2c_obj.cmd_rdaddr, hashlen); + i2c_obj.cmd_rdaddr += hashlen; + sha256_final(&ctx, buf); + len = 32; + } else if (buf[0] == I2C_CMD_MARKVALID && len == 0) { + uint32_t buf; + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != APP_VALIDITY_BITS) { + len = -1; + } else { + buf &= ~APP_VALIDITY_BITS; + int ret = do_write(APPLICATION_ADDR, (void*)&buf, 4); + if (ret < 0) { + len = ret; + } else { + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != 0) { + len = -2; + } else { + len = 0; + } + } + } + } else { + len = -127; + } + i2c_obj.cmd_arg = len; + i2c_obj.cmd_send_arg = true; + i2c_obj.cmd_arg_sent = false; +} + +uint8_t i2c_slave_process_tx_byte(void) { + if (i2c_obj.cmd_send_arg) { + i2c_obj.cmd_arg_sent = true; + return i2c_obj.cmd_arg; + } else if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + return i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++]; + } else { + return 0; + } +} + +#endif // defined(MBOOT_I2C_SCL) + +/******************************************************************************/ +// DFU + +#define DFU_XFER_SIZE (2048) + +enum { + DFU_DNLOAD = 1, + DFU_UPLOAD = 2, + DFU_GETSTATUS = 3, + DFU_CLRSTATUS = 4, + DFU_ABORT = 6, +}; + +enum { + DFU_STATUS_IDLE = 2, + DFU_STATUS_BUSY = 4, + DFU_STATUS_DNLOAD_IDLE = 5, + DFU_STATUS_MANIFEST = 7, + DFU_STATUS_UPLOAD_IDLE = 9, + DFU_STATUS_ERROR = 0xa, +}; + +enum { + DFU_CMD_NONE = 0, + DFU_CMD_EXIT = 1, + DFU_CMD_UPLOAD = 7, + DFU_CMD_DNLOAD = 8, +}; + +typedef struct _dfu_state_t { + int status; + int cmd; + uint16_t wBlockNum; + uint16_t wLength; + uint32_t addr; + uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4))); +} dfu_state_t; + +static dfu_state_t dfu_state; + +static void dfu_init(void) { + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.addr = 0x08000000; +} + +static int dfu_process_dnload(void) { + int ret = -1; + if (dfu_state.wBlockNum == 0) { + // download control commands + if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x41) { + if (dfu_state.wLength == 1) { + // mass erase + ret = do_mass_erase(); + } else if (dfu_state.wLength == 5) { + // erase page + ret = do_page_erase(get_le32(&dfu_state.buf[1])); + } + } else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) { + if (dfu_state.wLength == 5) { + // set address + dfu_state.addr = get_le32(&dfu_state.buf[1]); + ret = 0; + } + } + } else if (dfu_state.wBlockNum > 1) { + // write data to memory + uint32_t addr = (dfu_state.wBlockNum - 2) * DFU_XFER_SIZE + dfu_state.addr; + ret = do_write(addr, dfu_state.buf, dfu_state.wLength); + } + if (ret == 0) { + return DFU_STATUS_DNLOAD_IDLE; + } else { + return DFU_STATUS_ERROR; + } +} + +static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) { + if (cmd == DFU_CLRSTATUS) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_ABORT) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_DNLOAD) { + if (len == 0) { + // exit DFU + dfu_state.cmd = DFU_CMD_EXIT; + } else { + // download + dfu_state.cmd = DFU_CMD_DNLOAD; + dfu_state.wBlockNum = arg; + dfu_state.wLength = len; + memcpy(dfu_state.buf, buf, len); + } + } +} + +static void dfu_process(void) { + if (dfu_state.status == DFU_STATUS_MANIFEST) { + do_reset(); + } + + if (dfu_state.status == DFU_STATUS_BUSY) { + if (dfu_state.cmd == DFU_CMD_DNLOAD) { + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.status = dfu_process_dnload(); + } + } +} + +static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) { + if (cmd == DFU_UPLOAD) { + if (arg >= 2) { + dfu_state.cmd = DFU_CMD_UPLOAD; + uint32_t addr = (arg - 2) * max_len + dfu_state.addr; + do_read(addr, len, buf); + return len; + } + } else if (cmd == DFU_GETSTATUS && len == 6) { + // execute command and get status + switch (dfu_state.cmd) { + case DFU_CMD_NONE: + break; + case DFU_CMD_EXIT: + dfu_state.status = DFU_STATUS_MANIFEST; + break; + case DFU_CMD_UPLOAD: + dfu_state.status = DFU_STATUS_UPLOAD_IDLE; + break; + case DFU_CMD_DNLOAD: + dfu_state.status = DFU_STATUS_BUSY; + break; + } + buf[0] = 0; + buf[1] = dfu_state.cmd; // TODO is this correct? + buf[2] = 0; + buf[3] = 0; + buf[4] = dfu_state.status; + buf[5] = 0; + return 6; + } + return -1; +} + +/******************************************************************************/ +// USB + +#define USB_XFER_SIZE (DFU_XFER_SIZE) + +#define USB_PHY_FS_ID (0) +#define USB_PHY_HS_ID (1) + +typedef struct _pyb_usbdd_obj_t { + bool started; + bool tx_pending; + USBD_HandleTypeDef hUSBDDevice; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wLength; + __ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END; + __ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END; + + // RAM to hold the current descriptors, which we configure on the fly + __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; + __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; +} pyb_usbdd_obj_t; + +#define USBD_LANGID_STRING (0x409) + +__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +static const uint8_t dev_descr[0x12] = "\x12\x01\x00\x01\x00\x00\x00\x40\x83\x04\x11\xdf\x00\x22\x01\x02\x03\x01"; + +// This may be modified by USBD_GetDescriptor +static uint8_t cfg_descr[9 + 9 + 9] = + "\x09\x02\x1b\x00\x01\x01\x00\xc0\x32" + "\x09\x04\x00\x00\x00\xfe\x01\x02\x04" + "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE +; + +static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = USB_LEN_DEV_DESC; + return (uint8_t*)dev_descr; +} + +static char get_hex_char(int val) { + val &= 0xf; + if (val <= 9) { + return '0' + val; + } else { + return 'A' + val - 10; + } +} + +static void format_hex(char *buf, int val) { + buf[0] = get_hex_char(val >> 4); + buf[1] = get_hex_char(val); +} + +static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + uint8_t *str_desc = self->usbd_str_desc; + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + USBD_GetString((uint8_t*)"USBDevice Manuf", str_desc, length); + return str_desc; + + case USBD_IDX_PRODUCT_STR: + USBD_GetString((uint8_t*)"USBDevice Product", str_desc, length); + return str_desc; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you do: + // + // dfu-util -l + // + // See: https://my.st.com/52d187b7 for the algorithim used. + uint8_t *id = (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS; + char serial_buf[16]; + format_hex(&serial_buf[0], id[11]); + format_hex(&serial_buf[2], id[10] + id[2]); + format_hex(&serial_buf[4], id[9]); + format_hex(&serial_buf[6], id[8] + id[0]); + format_hex(&serial_buf[8], id[7]); + format_hex(&serial_buf[10], id[6]); + serial_buf[12] = '\0'; + + USBD_GetString((uint8_t*)serial_buf, str_desc, length); + return str_desc; + } + + case USBD_IDX_CONFIG_STR: + USBD_GetString((uint8_t*)FLASH_LAYOUT_STR, str_desc, length); + return str_desc; + + default: + return NULL; + } +} + +static const USBD_DescriptorsTypeDef pyb_usbdd_descriptors = { + pyb_usbdd_DeviceDescriptor, + pyb_usbdd_StrDescriptor, +}; + +static uint8_t pyb_usbdd_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + self->bRequest = req->bRequest; + self->wValue = req->wValue; + self->wLength = req->wLength; + if (req->bmRequest == 0x21) { + // host-to-device request + if (req->wLength == 0) { + // no data, process command straightaway + dfu_handle_rx(self->bRequest, self->wValue, 0, NULL); + } else { + // have data, prepare to receive it + USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength); + } + } else if (req->bmRequest == 0xa1) { + // device-to-host request + int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE); + if (len >= 0) { + self->tx_pending = true; + USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len); + } + } + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_TxSent(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + self->tx_pending = false; + #if !USE_USB_POLLING + // Process now that we have sent a response + dfu_process(); + #endif + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_RxReady(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + dfu_handle_rx(self->bRequest, self->wValue, self->wLength, self->rx_buf); + return USBD_OK; +} + +static uint8_t *pyb_usbdd_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = sizeof(cfg_descr); + return (uint8_t*)cfg_descr; +} + +// this is used only in high-speed mode, which we don't support +static uint8_t *pyb_usbdd_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + /* + *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); + return USBD_CDC_MSC_HID_DeviceQualifierDesc; + */ + *length = 0; + return NULL; +} + +static const USBD_ClassTypeDef pyb_usbdd_class = { + pyb_usbdd_Init, + pyb_usbdd_DeInit, + pyb_usbdd_Setup, + pyb_usbdd_EP0_TxSent, + pyb_usbdd_EP0_RxReady, + NULL, // pyb_usbdd_DataIn, + NULL, // pyb_usbdd_DataOut, + NULL, // SOF + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetDeviceQualifierDescriptor, +}; + +static pyb_usbdd_obj_t pyb_usbdd; + +static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { + self->started = false; + USBD_HandleTypeDef *usbd = &self->hUSBDDevice; + usbd->id = phy_id; + usbd->dev_state = USBD_STATE_DEFAULT; + usbd->pDesc = (USBD_DescriptorsTypeDef*)&pyb_usbdd_descriptors; + usbd->pClass = &pyb_usbdd_class; + usbd->pClassData = self; +} + +static void pyb_usbdd_start(pyb_usbdd_obj_t *self) { + if (!self->started) { + USBD_LL_Init(&self->hUSBDDevice, 0); + USBD_LL_Start(&self->hUSBDDevice); + self->started = true; + } +} + +static void pyb_usbdd_stop(pyb_usbdd_obj_t *self) { + if (self->started) { + USBD_Stop(&self->hUSBDDevice); + self->started = false; + } +} + +static int pyb_usbdd_shutdown(void) { + pyb_usbdd_stop(&pyb_usbdd); + return 0; +} + +/******************************************************************************/ +// main + +#define RESET_MODE_NUM_STATES (4) +#define RESET_MODE_TIMEOUT_CYCLES (8) +#define RESET_MODE_LED_STATES 0x7421 + +static int get_reset_mode(void) { + usrbtn_init(); + int reset_mode = 1; + if (usrbtn_state()) { + // Cycle through reset modes while USR is held + // Timeout is roughly 20s, where reset_mode=1 + systick_init(); + led_init(); + reset_mode = 0; + for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) { + if (i % 32 == 0) { + if (++reset_mode > RESET_MODE_NUM_STATES) { + reset_mode = 1; + } + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + } + if (!usrbtn_state()) { + break; + } + mp_hal_delay_ms(19); + } + // Flash the selected reset mode + for (int i = 0; i < 6; i++) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + mp_hal_delay_ms(50); + } + mp_hal_delay_ms(300); + } + return reset_mode; +} + +static void do_reset(void) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + pyb_usbdd_shutdown(); + #if defined(MBOOT_I2C_SCL) + i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn); + #endif + mp_hal_delay_ms(50); + NVIC_SystemReset(); +} + +uint32_t SystemCoreClock; + +extern PCD_HandleTypeDef pcd_fs_handle; +extern PCD_HandleTypeDef pcd_hs_handle; + +void stm32_main(int initial_r0) { + #if defined(STM32F4) + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + #elif defined(STM32F7) + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + #endif + + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + + #if USE_CACHE && defined(STM32F7) + SCB_EnableICache(); + SCB_EnableDCache(); + #endif + + #ifdef MBOOT_BOOTPIN_PIN + mp_hal_pin_config(MBOOT_BOOTPIN_PIN, MP_HAL_PIN_MODE_INPUT, MBOOT_BOOTPIN_PULL, 0); + if (mp_hal_pin_read(MBOOT_BOOTPIN_PIN) == MBOOT_BOOTPIN_ACTIVE) { + goto enter_bootloader; + } + #endif + + if ((initial_r0 & 0xffffff00) == 0x70ad0000) { + goto enter_bootloader; + } + + // MCU starts up with 16MHz HSI + SystemCoreClock = 16000000; + + int reset_mode = get_reset_mode(); + uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR; + if (reset_mode != 4 && (msp & APP_VALIDITY_BITS) == 0) { + // not DFU mode so jump to application, passing through reset_mode + // undo our DFU settings + // TODO probably should disable all IRQ sources first + #if USE_CACHE && defined(STM32F7) + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + __set_MSP(msp); + ((void (*)(uint32_t)) *((volatile uint32_t*)(APPLICATION_ADDR + 4)))(reset_mode); + } + +enter_bootloader: + + // Init subsystems (get_reset_mode() may call these, calling them again is ok) + led_init(); + + // set the system clock to be HSE + SystemClock_Config(); + + #if USE_USB_POLLING + // irqs with a priority value greater or equal to "pri" will be disabled + // "pri" should be between 1 and 15 inclusive + uint32_t pri = 2; + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + #endif + + #if defined(MBOOT_SPIFLASH_ADDR) + MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH); + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH); + #endif + + dfu_init(); + + pyb_usbdd_init(&pyb_usbdd, MICROPY_HW_USB_MAIN_DEV); + pyb_usbdd_start(&pyb_usbdd); + + #if defined(MBOOT_I2C_SCL) + initial_r0 &= 0x7f; + if (initial_r0 == 0) { + initial_r0 = 0x23; // Default I2C address + } + i2c_init(initial_r0); + #endif + + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + + #if USE_USB_POLLING + uint32_t ss = systick_ms; + int ss2 = -1; + #endif + for (;;) { + #if USE_USB_POLLING + #if MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID + if (USB_OTG_FS->GINTSTS & USB_OTG_FS->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_fs_handle); + } + #else + if (USB_OTG_HS->GINTSTS & USB_OTG_HS->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_hs_handle); + } + #endif + if (!pyb_usbdd.tx_pending) { + dfu_process(); + } + #endif + + #if USE_USB_POLLING + //__WFI(); // slows it down way too much; might work with 10x faster systick + if (systick_ms - ss > 50) { + ss += 50; + ss2 = (ss2 + 1) % 20; + switch (ss2) { + case 0: led_state(LED0, 1); break; + case 1: led_state(LED0, 0); break; + } + } + #else + led_state(LED0, 1); + mp_hal_delay_ms(50); + led_state(LED0, 0); + mp_hal_delay_ms(950); + #endif + } +} + +void NMI_Handler(void) { +} + +void MemManage_Handler(void) { + while (1) { + __fatal_error("MemManage"); + } +} + +void BusFault_Handler(void) { + while (1) { + __fatal_error("BusFault"); + } +} + +void UsageFault_Handler(void) { + while (1) { + __fatal_error("UsageFault"); + } +} + +void SVC_Handler(void) { +} + +void DebugMon_Handler(void) { +} + +void PendSV_Handler(void) { +} + +void SysTick_Handler(void) { + systick_ms += 1; + + // Read the systick control regster. This has the side effect of clearing + // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us + // work properly. + SysTick->CTRL; +} + +#if defined(MBOOT_I2C_SCL) +void I2Cx_EV_IRQHandler(void) { + i2c_slave_ev_irq_handler(MBOOT_I2Cx); +} +#endif + +#if !USE_USB_POLLING +#if MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID +void OTG_FS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_fs_handle); +} +#else +void OTG_HS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_hs_handle); +} +#endif +#endif diff --git a/src/openmv/src/micropython/ports/stm32/mboot/mboot.py b/src/openmv/src/micropython/ports/stm32/mboot/mboot.py new file mode 100755 index 0000000..39ae0f6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mboot/mboot.py @@ -0,0 +1,177 @@ +# Driver for Mboot, the MicroPython boot loader +# MIT license; Copyright (c) 2018 Damien P. George + +import struct, time, os, hashlib + + +I2C_CMD_ECHO = 1 +I2C_CMD_GETID = 2 +I2C_CMD_GETCAPS = 3 +I2C_CMD_RESET = 4 +I2C_CMD_CONFIG = 5 +I2C_CMD_GETLAYOUT = 6 +I2C_CMD_MASSERASE = 7 +I2C_CMD_PAGEERASE = 8 +I2C_CMD_SETRDADDR = 9 +I2C_CMD_SETWRADDR = 10 +I2C_CMD_READ = 11 +I2C_CMD_WRITE = 12 +I2C_CMD_COPY = 13 +I2C_CMD_CALCHASH = 14 +I2C_CMD_MARKVALID = 15 + + +class Bootloader: + def __init__(self, i2c, addr): + self.i2c = i2c + self.addr = addr + self.buf1 = bytearray(1) + try: + self.i2c.writeto(addr, b'') + except OSError: + raise Exception('no I2C mboot device found') + + def wait_response(self): + start = time.ticks_ms() + while 1: + try: + self.i2c.readfrom_into(self.addr, self.buf1) + n = self.buf1[0] + break + except OSError as er: + time.sleep_us(500) + if time.ticks_diff(time.ticks_ms(), start) > 5000: + raise Exception('timeout') + if n >= 129: + raise Exception(n) + if n == 0: + return b'' + else: + return self.i2c.readfrom(self.addr, n) + + def wait_empty_response(self): + ret = self.wait_response() + if ret: + raise Exception('expected empty response got %r' % ret) + else: + return None + + def echo(self, data): + self.i2c.writeto(self.addr, struct.pack(' + +#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) + +#define MP_HAL_PIN_MODE_INPUT (0) +#define MP_HAL_PIN_MODE_OUTPUT (1) +#define MP_HAL_PIN_MODE_ALT (2) +#define MP_HAL_PIN_MODE_ANALOG (3) +#define MP_HAL_PIN_MODE_OPEN_DRAIN (5) +#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) +#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) +#define MP_HAL_PIN_PULL_UP (GPIO_PULLUP) +#define MP_HAL_PIN_PULL_DOWN (GPIO_PULLDOWN) + +#define mp_hal_pin_obj_t uint32_t +#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 0x10000 << ((p) & 0xf)) +#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 1 << ((p) & 0xf)) +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_pin_config(uint32_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt); +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed); + +#define pin_A0 (GPIOA_BASE | 0) +#define pin_A1 (GPIOA_BASE | 1) +#define pin_A2 (GPIOA_BASE | 2) +#define pin_A3 (GPIOA_BASE | 3) +#define pin_A4 (GPIOA_BASE | 4) +#define pin_A5 (GPIOA_BASE | 5) +#define pin_A6 (GPIOA_BASE | 6) +#define pin_A7 (GPIOA_BASE | 7) +#define pin_A8 (GPIOA_BASE | 8) +#define pin_A9 (GPIOA_BASE | 9) +#define pin_A10 (GPIOA_BASE | 10) +#define pin_A11 (GPIOA_BASE | 11) +#define pin_A12 (GPIOA_BASE | 12) +#define pin_A13 (GPIOA_BASE | 13) +#define pin_A14 (GPIOA_BASE | 14) +#define pin_A15 (GPIOA_BASE | 15) + +#define pin_B0 (GPIOB_BASE | 0) +#define pin_B1 (GPIOB_BASE | 1) +#define pin_B2 (GPIOB_BASE | 2) +#define pin_B3 (GPIOB_BASE | 3) +#define pin_B4 (GPIOB_BASE | 4) +#define pin_B5 (GPIOB_BASE | 5) +#define pin_B6 (GPIOB_BASE | 6) +#define pin_B7 (GPIOB_BASE | 7) +#define pin_B8 (GPIOB_BASE | 8) +#define pin_B9 (GPIOB_BASE | 9) +#define pin_B10 (GPIOB_BASE | 10) +#define pin_B11 (GPIOB_BASE | 11) +#define pin_B12 (GPIOB_BASE | 12) +#define pin_B13 (GPIOB_BASE | 13) +#define pin_B14 (GPIOB_BASE | 14) +#define pin_B15 (GPIOB_BASE | 15) + +#define pin_C0 (GPIOC_BASE | 0) +#define pin_C1 (GPIOC_BASE | 1) +#define pin_C2 (GPIOC_BASE | 2) +#define pin_C3 (GPIOC_BASE | 3) +#define pin_C4 (GPIOC_BASE | 4) +#define pin_C5 (GPIOC_BASE | 5) +#define pin_C6 (GPIOC_BASE | 6) +#define pin_C7 (GPIOC_BASE | 7) +#define pin_C8 (GPIOC_BASE | 8) +#define pin_C9 (GPIOC_BASE | 9) +#define pin_C10 (GPIOC_BASE | 10) +#define pin_C11 (GPIOC_BASE | 11) +#define pin_C12 (GPIOC_BASE | 12) +#define pin_C13 (GPIOC_BASE | 13) +#define pin_C14 (GPIOC_BASE | 14) +#define pin_C15 (GPIOC_BASE | 15) + +#define pin_D0 (GPIOD_BASE | 0) +#define pin_D1 (GPIOD_BASE | 1) +#define pin_D2 (GPIOD_BASE | 2) +#define pin_D3 (GPIOD_BASE | 3) +#define pin_D4 (GPIOD_BASE | 4) +#define pin_D5 (GPIOD_BASE | 5) +#define pin_D6 (GPIOD_BASE | 6) +#define pin_D7 (GPIOD_BASE | 7) +#define pin_D8 (GPIOD_BASE | 8) +#define pin_D9 (GPIOD_BASE | 9) +#define pin_D10 (GPIOD_BASE | 10) +#define pin_D11 (GPIOD_BASE | 11) +#define pin_D12 (GPIOD_BASE | 12) +#define pin_D13 (GPIOD_BASE | 13) +#define pin_D14 (GPIOD_BASE | 14) +#define pin_D15 (GPIOD_BASE | 15) + +#define pin_E0 (GPIOE_BASE | 0) +#define pin_E1 (GPIOE_BASE | 1) +#define pin_E2 (GPIOE_BASE | 2) +#define pin_E3 (GPIOE_BASE | 3) +#define pin_E4 (GPIOE_BASE | 4) +#define pin_E5 (GPIOE_BASE | 5) +#define pin_E6 (GPIOE_BASE | 6) +#define pin_E7 (GPIOE_BASE | 7) +#define pin_E8 (GPIOE_BASE | 8) +#define pin_E9 (GPIOE_BASE | 9) +#define pin_E10 (GPIOE_BASE | 10) +#define pin_E11 (GPIOE_BASE | 11) +#define pin_E12 (GPIOE_BASE | 12) +#define pin_E13 (GPIOE_BASE | 13) +#define pin_E14 (GPIOE_BASE | 14) +#define pin_E15 (GPIOE_BASE | 15) + +#define pin_F0 (GPIOF_BASE | 0) +#define pin_F1 (GPIOF_BASE | 1) +#define pin_F2 (GPIOF_BASE | 2) +#define pin_F3 (GPIOF_BASE | 3) +#define pin_F4 (GPIOF_BASE | 4) +#define pin_F5 (GPIOF_BASE | 5) +#define pin_F6 (GPIOF_BASE | 6) +#define pin_F7 (GPIOF_BASE | 7) +#define pin_F8 (GPIOF_BASE | 8) +#define pin_F9 (GPIOF_BASE | 9) +#define pin_F10 (GPIOF_BASE | 10) +#define pin_F11 (GPIOF_BASE | 11) +#define pin_F12 (GPIOF_BASE | 12) +#define pin_F13 (GPIOF_BASE | 13) +#define pin_F14 (GPIOF_BASE | 14) +#define pin_F15 (GPIOF_BASE | 15) diff --git a/src/openmv/src/micropython/ports/stm32/mboot/stm32_generic.ld b/src/openmv/src/micropython/ports/stm32/mboot/stm32_generic.ld new file mode 100755 index 0000000..8585c68 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mboot/stm32_generic.ld @@ -0,0 +1,77 @@ +/* + GNU linker script for generic STM32xxx MCU +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +ENTRY(Reset_Handler) + +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH_BL + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_BL + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data section */ + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_BL + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/openmv/src/micropython/ports/stm32/modmachine.c b/src/openmv/src/micropython/ports/stm32/modmachine.c new file mode 100755 index 0000000..e0d9afb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modmachine.c @@ -0,0 +1,530 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "modmachine.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "lib/utils/pyexec.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "gccollect.h" +#include "irq.h" +#include "powerctrl.h" +#include "pybthread.h" +#include "rng.h" +#include "storage.h" +#include "pin.h" +#include "timer.h" +#include "usb.h" +#include "rtc.h" +#include "i2c.h" +#include "spi.h" +#include "uart.h" +#include "wdt.h" + +#if defined(STM32L4) +// L4 does not have a POR, so use BOR instead +#define RCC_CSR_PORRSTF RCC_CSR_BORRSTF +#endif + +#if defined(STM32H7) +#define RCC_SR RSR +#define RCC_SR_IWDGRSTF RCC_RSR_IWDG1RSTF +#define RCC_SR_WWDGRSTF RCC_RSR_WWDG1RSTF +#define RCC_SR_PORRSTF RCC_RSR_PORRSTF +#define RCC_SR_BORRSTF RCC_RSR_BORRSTF +#define RCC_SR_PINRSTF RCC_RSR_PINRSTF +#define RCC_SR_RMVF RCC_RSR_RMVF +#else +#define RCC_SR CSR +#define RCC_SR_IWDGRSTF RCC_CSR_IWDGRSTF +#define RCC_SR_WWDGRSTF RCC_CSR_WWDGRSTF +#define RCC_SR_PORRSTF RCC_CSR_PORRSTF +#define RCC_SR_BORRSTF RCC_CSR_BORRSTF +#define RCC_SR_PINRSTF RCC_CSR_PINRSTF +#define RCC_SR_RMVF RCC_CSR_RMVF +#endif + +#define PYB_RESET_SOFT (0) +#define PYB_RESET_POWER_ON (1) +#define PYB_RESET_HARD (2) +#define PYB_RESET_WDT (3) +#define PYB_RESET_DEEPSLEEP (4) + +STATIC uint32_t reset_cause; + +void machine_init(void) { + #if defined(STM32F4) + if (PWR->CSR & PWR_CSR_SBF) { + // came out of standby + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CR |= PWR_CR_CSBF; + } else + #elif defined(STM32F7) + if (PWR->CSR1 & PWR_CSR1_SBF) { + // came out of standby + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CR1 |= PWR_CR1_CSBF; + } else + #elif defined(STM32H7) + if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) { + // came out of standby or stop mode + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CPUCR |= PWR_CPUCR_CSSF; + } else + #endif + { + // get reset cause from RCC flags + uint32_t state = RCC->RCC_SR; + if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) { + reset_cause = PYB_RESET_WDT; + } else if (state & RCC_SR_PORRSTF + #if !defined(STM32F0) + || state & RCC_SR_BORRSTF + #endif + ) { + reset_cause = PYB_RESET_POWER_ON; + } else if (state & RCC_SR_PINRSTF) { + reset_cause = PYB_RESET_HARD; + } else { + // default is soft reset + reset_cause = PYB_RESET_SOFT; + } + } + // clear RCC reset flags + RCC->RCC_SR |= RCC_SR_RMVF; +} + +void machine_deinit(void) { + // we are doing a soft-reset so change the reset_cause + reset_cause = PYB_RESET_SOFT; +} + +// machine.info([dump_alloc_table]) +// Print out lots of information about the board. +STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { + // get and print unique id; 96 bits + { + byte *id = (byte*)MP_HAL_UNIQUE_ID_ADDRESS; + printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]); + } + + // get and print clock speeds + // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz + { + #if defined(STM32F0) + printf("S=%u\nH=%u\nP1=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq()); + #else + printf("S=%u\nH=%u\nP1=%u\nP2=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq(), + (unsigned int)HAL_RCC_GetPCLK2Freq()); + #endif + } + + // to print info about memory + { + printf("_etext=%p\n", &_etext); + printf("_sidata=%p\n", &_sidata); + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_ram_start=%p\n", &_ram_start); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + printf("_ram_end=%p\n", &_ram_end); + } + + // qstr info + { + size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" %u total\n", info.total); + printf(" %u : %u\n", info.used, info.free); + printf(" 1=%u 2=%u m=%u\n", info.num_1block, info.num_2block, info.max_block); + } + + // free space on flash + { + #if MICROPY_VFS_FAT + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + if (strncmp("/flash", vfs->str, vfs->len) == 0) { + // assumes that it's a FatFs filesystem + fs_user_mount_t *vfs_fat = MP_OBJ_TO_PTR(vfs->obj); + DWORD nclst; + f_getfree(&vfs_fat->fatfs, &nclst); + printf("LFS free: %u bytes\n", (uint)(nclst * vfs_fat->fatfs.csize * 512)); + break; + } + } + #endif + } + + #if MICROPY_PY_THREAD + pyb_thread_dump(); + #endif + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info); + +// Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU. +STATIC mp_obj_t machine_unique_id(void) { + byte *id = (byte*)MP_HAL_UNIQUE_ID_ADDRESS; + return mp_obj_new_bytes(id, 12); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +// Resets the pyboard in a manner similar to pushing the external RESET button. +STATIC mp_obj_t machine_reset(void) { + NVIC_SystemReset(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + +// Activate the bootloader without BOOT* pins. +STATIC NORETURN mp_obj_t machine_bootloader(void) { + #if MICROPY_HW_ENABLE_USB + pyb_usb_dev_deinit(); + #endif + #if MICROPY_HW_ENABLE_STORAGE + storage_flush(); + #endif + + HAL_RCC_DeInit(); + HAL_DeInit(); + + #if (__MPU_PRESENT == 1) + // MPU must be disabled for bootloader to function correctly + HAL_MPU_Disable(); + #endif + +#if defined(STM32F7) || defined(STM32H7) + // arm-none-eabi-gcc 4.9.0 does not correctly inline this + // MSP function, so we write it out explicitly here. + //__set_MSP(*((uint32_t*) 0x1FF00000)); + __ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); + + ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); +#else + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + + // arm-none-eabi-gcc 4.9.0 does not correctly inline this + // MSP function, so we write it out explicitly here. + //__set_MSP(*((uint32_t*) 0x00000000)); + __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); + + ((void (*)(void)) *((uint32_t*) 0x00000004))(); +#endif + + while (1); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); + +// get or set the MCU frequencies +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // get + mp_obj_t tuple[] = { + mp_obj_new_int(HAL_RCC_GetSysClockFreq()), + mp_obj_new_int(HAL_RCC_GetHCLKFreq()), + mp_obj_new_int(HAL_RCC_GetPCLK1Freq()), + #if !defined(STM32F0) + mp_obj_new_int(HAL_RCC_GetPCLK2Freq()), + #endif + }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); + } else { + // set + #if defined(STM32F0) || defined(STM32L4) + mp_raise_NotImplementedError("machine.freq set not supported yet"); + #else + mp_int_t sysclk = mp_obj_get_int(args[0]); + mp_int_t ahb = sysclk; + mp_int_t apb1 = ahb / 4; + mp_int_t apb2 = ahb / 2; + if (n_args > 1) { + ahb = mp_obj_get_int(args[1]); + if (n_args > 2) { + apb1 = mp_obj_get_int(args[2]); + if (n_args > 3) { + apb2 = mp_obj_get_int(args[3]); + } + } + } + int ret = powerctrl_set_sysclk(sysclk, ahb, apb1, apb2); + if (ret == -MP_EINVAL) { + mp_raise_ValueError("invalid freq"); + } else if (ret < 0) { + void NORETURN __fatal_error(const char *msg); + __fatal_error("can't change freq"); + } + return mp_const_none; + #endif + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq); + +STATIC mp_obj_t machine_sleep(void) { + #if defined(STM32L4) + // Configure the MSI as the clock source after waking up + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); + #endif + + #if !defined(STM32F0) && !defined(STM32L4) + // takes longer to wake but reduces stop current + HAL_PWREx_EnableFlashPowerDown(); + #endif + + # if defined(STM32F7) + HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI); + # else + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + #endif + + // reconfigure the system clock after waking up + + #if defined(STM32F0) + + // Enable HSI48 + __HAL_RCC_HSI48_ENABLE(); + while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSI48RDY)) { + } + + // Select HSI48 as system clock source + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_HSI48); + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_HSI48) { + } + + #else + + #if !defined(STM32L4) + // enable HSE + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); + while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) { + } + #endif + + // enable PLL + __HAL_RCC_PLL_ENABLE(); + while (!__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)) { + } + + // select PLL as system clock source + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { + #else + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { + #endif + } + + #if defined(STM32F7) + if (RCC->DCKCFGR2 & RCC_DCKCFGR2_CK48MSEL) { + // Enable PLLSAI if it is selected as 48MHz source + RCC->CR |= RCC_CR_PLLSAION; + while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + } + } + #endif + + #if defined(STM32L4) + // Enable PLLSAI1 for peripherals that use it + RCC->CR |= RCC_CR_PLLSAI1ON; + while (!(RCC->CR & RCC_CR_PLLSAI1RDY)) { + } + #endif + + #endif + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(void) { + rtc_init_finalise(); + +#if defined(STM32L4) + printf("machine.deepsleep not supported yet\n"); +#else + // We need to clear the PWR wake-up-flag before entering standby, since + // the flag may have been set by a previous wake-up event. Furthermore, + // we need to disable the wake-up sources while clearing this flag, so + // that if a source is active it does actually wake the device. + // See section 5.3.7 of RM0090. + + // Note: we only support RTC ALRA, ALRB, WUT and TS. + // TODO support TAMP and WKUP (PA0 external pin). + #if defined(STM32F0) + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF) + #else + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF) + #endif + + // save RTC interrupts + uint32_t save_irq_bits = RTC->CR & CR_BITS; + + // disable RTC interrupts + RTC->CR &= ~CR_BITS; + + // clear RTC wake-up flags + RTC->ISR &= ~ISR_BITS; + + #if defined(STM32F7) + // disable wake-up flags + PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); + // clear global wake-up flag + PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1; + #elif defined(STM32H7) + // TODO + #else + // clear global wake-up flag + PWR->CR |= PWR_CR_CWUF; + #endif + + // enable previously-enabled RTC interrupts + RTC->CR |= save_irq_bits; + + // enter standby mode + HAL_PWR_EnterSTANDBYMode(); + // we never return; MCU is reset on exit from standby +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(void) { + return MP_OBJ_NEW_SMALL_INT(reset_cause); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&pyb_wfi_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, +#endif + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + +#if 0 + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, +#endif +#if MICROPY_PY_MACHINE_I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, +#endif + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_HeartBeat), MP_ROM_PTR(&pyb_heartbeat_type) }, + { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sd_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IDLE), MP_ROM_INT(PYB_PWR_MODE_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(PYB_PWR_MODE_LPDS) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(PYB_PWR_MODE_HIBERNATE) }, +#endif + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(PYB_RESET_POWER_ON) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(PYB_RESET_HARD) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(PYB_RESET_WDT) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(PYB_RESET_DEEPSLEEP) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(PYB_RESET_SOFT) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_WLAN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_WLAN) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_GPIO) }, + { MP_ROM_QSTR(MP_QSTR_RTC_WAKE), MP_ROM_INT(PYB_SLP_WAKED_BY_RTC) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t machine_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + diff --git a/src/openmv/src/micropython/ports/stm32/modmachine.h b/src/openmv/src/micropython/ports/stm32/modmachine.h new file mode 100755 index 0000000..88fe236 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modmachine.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_MODMACHINE_H +#define MICROPY_INCLUDED_STM32_MODMACHINE_H + +#include "py/obj.h" + +void machine_init(void); +void machine_deinit(void); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); + +#endif // MICROPY_INCLUDED_STM32_MODMACHINE_H diff --git a/src/openmv/src/micropython/ports/stm32/modnetwork.c b/src/openmv/src/micropython/ports/stm32/modnetwork.c new file mode 100755 index 0000000..dea23b4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modnetwork.c @@ -0,0 +1,177 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" + +#if MICROPY_PY_NETWORK + +#if MICROPY_PY_LWIP + +#include "lwip/netif.h" +#include "lwip/timeouts.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" + +u32_t sys_now(void) { + return mp_hal_ticks_ms(); +} + +void pyb_lwip_poll(void) { + // Poll all the NICs for incoming data + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif->flags & NETIF_FLAG_LINK_UP) { + mod_network_nic_type_t *nic = netif->state; + nic->poll_callback(nic, netif); + } + } + // Run the lwIP internal updates + sys_check_timeouts(); +} + +#endif + +/// \module network - network configuration +/// +/// This module provides network drivers and routing configuration. + +void mod_network_init(void) { + mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0); +} + +void mod_network_deinit(void) { +} + +void mod_network_register_nic(mp_obj_t nic) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { + if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) { + // nic already registered + return; + } + } + // nic not registered so add to list + mp_obj_list_append(MP_OBJ_FROM_PTR(&MP_STATE_PORT(mod_network_nic_list)), nic); +} + +mp_obj_t mod_network_find_nic(const uint8_t *ip) { + // find a NIC that is suited to given IP address + for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { + mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i]; + // TODO check IP suitability here + //mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + return nic; + } + + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); +} + +STATIC mp_obj_t network_route(void) { + return MP_OBJ_FROM_PTR(&MP_STATE_PORT(mod_network_nic_list)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route); + +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + + #if MICROPY_PY_WIZNET5K + { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, + #endif + #if MICROPY_PY_CC3K + { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) }, + #endif + + { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; + +/*******************************************************************************/ +// Implementations of network methods that can be used by any interface + +#if MICROPY_PY_LWIP + +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Get IP addresses + const ip_addr_t *dns = dns_getserver(0); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&netif->ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)dns, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) { + // Start the DHCP client + if (dhcp_supplied_address(netif)) { + dhcp_renew(netif); + } else { + dhcp_stop(netif); + dhcp_start(netif); + } + + // Wait for DHCP to get IP address + uint32_t start = mp_hal_ticks_ms(); + while (!dhcp_supplied_address(netif)) { + if (mp_hal_ticks_ms() - start > 10000) { + mp_raise_msg(&mp_type_OSError, "timeout waiting for DHCP to get IP address"); + } + mp_hal_delay_ms(100); + } + + return mp_const_none; + } else { + // Release and stop any existing DHCP + dhcp_release(netif); + dhcp_stop(netif); + // Set static IP addresses + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[0], 4, &items); + netutils_parse_ipv4_addr(items[0], (uint8_t*)&netif->ip_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], (uint8_t*)&netif->netmask, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], (uint8_t*)&netif->gw, NETUTILS_BIG); + ip_addr_t dns; + netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG); + dns_setserver(0, &dns); + return mp_const_none; + } +} + +#endif + +#endif // MICROPY_PY_NETWORK diff --git a/src/openmv/src/micropython/ports/stm32/modnetwork.h b/src/openmv/src/micropython/ports/stm32/modnetwork.h new file mode 100755 index 0000000..f45e00f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modnetwork.h @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H +#define MICROPY_INCLUDED_STM32_MODNETWORK_H + +#define MOD_NETWORK_IPADDR_BUF_SIZE (4) + +#define MOD_NETWORK_AF_INET (2) +#define MOD_NETWORK_AF_INET6 (10) + +#define MOD_NETWORK_SOCK_STREAM (1) +#define MOD_NETWORK_SOCK_DGRAM (2) +#define MOD_NETWORK_SOCK_RAW (3) + +#if MICROPY_PY_LWIP + +struct netif; + +typedef struct _mod_network_nic_type_t { + mp_obj_base_t base; + void (*poll_callback)(void *data, struct netif *netif); +} mod_network_nic_type_t; + +extern const mp_obj_type_t mod_network_nic_type_wiznet5k; + +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args); + +#else + +struct _mod_network_socket_obj_t; + +typedef struct _mod_network_nic_type_t { + mp_obj_type_t base; + + // API for non-socket operations + int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out); + + // API for socket operations; return -1 on error + int (*socket)(struct _mod_network_socket_obj_t *socket, int *_errno); + void (*close)(struct _mod_network_socket_obj_t *socket); + int (*bind)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno); + int (*listen)(struct _mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno); + int (*accept)(struct _mod_network_socket_obj_t *socket, struct _mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno); + int (*connect)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno); + mp_uint_t (*send)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno); + mp_uint_t (*recv)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno); + mp_uint_t (*sendto)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno); + mp_uint_t (*recvfrom)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno); + int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno); + int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno); + int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno); +} mod_network_nic_type_t; + +typedef struct _mod_network_socket_obj_t { + mp_obj_base_t base; + mp_obj_t nic; + mod_network_nic_type_t *nic_type; + union { + struct { + uint8_t domain; + uint8_t type; + int8_t fileno; + } u_param; + mp_uint_t u_state; + }; +} mod_network_socket_obj_t; + +extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k; +extern const mod_network_nic_type_t mod_network_nic_type_cc3k; + +#endif + +void mod_network_init(void); +void mod_network_deinit(void); +void mod_network_register_nic(mp_obj_t nic); +mp_obj_t mod_network_find_nic(const uint8_t *ip); + +#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H diff --git a/src/openmv/src/micropython/ports/stm32/modnwcc3k.c b/src/openmv/src/micropython/ports/stm32/modnwcc3k.c new file mode 100755 index 0000000..8723994 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modnwcc3k.c @@ -0,0 +1,600 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +// CC3000 defines its own ENOBUFS (different to standard one!) +#undef ENOBUFS + +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/stream.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" +#include "pin.h" +#include "spi.h" + +#include "hci.h" +#include "socket.h" +#include "inet_ntop.h" +#include "inet_pton.h" +#include "ccspi.h" +#include "wlan.h" +#include "nvmem.h" +#include "netapp.h" +#include "patch_prog.h" + +#define MAX_ADDRSTRLEN (128) +#define MAX_RX_PACKET (CC3000_RX_BUFFER_SIZE-CC3000_MINIMAL_RX_SIZE-1) +#define MAX_TX_PACKET (CC3000_TX_BUFFER_SIZE-CC3000_MINIMAL_TX_SIZE-1) + +#define MAKE_SOCKADDR(addr, ip, port) \ + sockaddr addr; \ + addr.sa_family = AF_INET; \ + addr.sa_data[0] = port >> 8; \ + addr.sa_data[1] = port; \ + addr.sa_data[2] = ip[0]; \ + addr.sa_data[3] = ip[1]; \ + addr.sa_data[4] = ip[2]; \ + addr.sa_data[5] = ip[3]; + +#define UNPACK_SOCKADDR(addr, ip, port) \ + port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \ + ip[0] = addr.sa_data[2]; \ + ip[1] = addr.sa_data[3]; \ + ip[2] = addr.sa_data[4]; \ + ip[3] = addr.sa_data[5]; + +STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno); + +int CC3000_EXPORT(errno); // for cc3000 driver + +STATIC volatile uint32_t fd_closed_state = 0; +STATIC volatile bool wlan_connected = false; +STATIC volatile bool ip_obtained = false; + +STATIC int cc3k_get_fd_closed_state(int fd) { + return fd_closed_state & (1 << fd); +} + +STATIC void cc3k_set_fd_closed_state(int fd) { + fd_closed_state |= 1 << fd; +} + +STATIC void cc3k_reset_fd_closed_state(int fd) { + fd_closed_state &= ~(1 << fd); +} + +STATIC void cc3k_callback(long event_type, char *data, unsigned char length) { + switch (event_type) { + case HCI_EVNT_WLAN_UNSOL_CONNECT: + wlan_connected = true; + break; + case HCI_EVNT_WLAN_UNSOL_DISCONNECT: + // link down + wlan_connected = false; + ip_obtained = false; + break; + case HCI_EVNT_WLAN_UNSOL_DHCP: + ip_obtained = true; + break; + case HCI_EVNT_BSD_TCP_CLOSE_WAIT: + // mark socket for closure + cc3k_set_fd_closed_state(data[0]); + break; + } +} + +STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + uint32_t ip; + // CC3000 gethostbyname is unreliable and usually returns -95 on first call + for (int retry = 5; CC3000_EXPORT(gethostbyname)((char*)name, len, &ip) < 0; retry--) { + if (retry == 0 || CC3000_EXPORT(errno) != -95) { + return CC3000_EXPORT(errno); + } + mp_hal_delay_ms(50); + } + + if (ip == 0) { + // unknown host + return -2; + } + + out_ip[0] = ip >> 24; + out_ip[1] = ip >> 16; + out_ip[2] = ip >> 8; + out_ip[3] = ip; + + return 0; +} + +STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { + if (socket->u_param.domain != MOD_NETWORK_AF_INET) { + *_errno = MP_EAFNOSUPPORT; + return -1; + } + + mp_uint_t type; + switch (socket->u_param.type) { + case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break; + case MOD_NETWORK_SOCK_DGRAM: type = SOCK_DGRAM; break; + case MOD_NETWORK_SOCK_RAW: type = SOCK_RAW; break; + default: *_errno = MP_EINVAL; return -1; + } + + // open socket + int fd = CC3000_EXPORT(socket)(AF_INET, type, 0); + if (fd < 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + + // clear socket state + cc3k_reset_fd_closed_state(fd); + + // store state of this socket + socket->u_state = fd; + + // make accept blocking by default + int optval = SOCK_OFF; + socklen_t optlen = sizeof(optval); + CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); + + return 0; +} + +STATIC void cc3k_socket_close(mod_network_socket_obj_t *socket) { + CC3000_EXPORT(closesocket)(socket->u_state); +} + +STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = CC3000_EXPORT(bind)(socket->u_state, &addr, sizeof(addr)); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int cc3k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { + int ret = CC3000_EXPORT(listen)(socket->u_state, backlog); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) { + // accept incoming connection + int fd; + sockaddr addr; + socklen_t addr_len = sizeof(addr); + if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) { + if (fd == SOC_IN_PROGRESS) { + *_errno = MP_EAGAIN; + } else { + *_errno = -fd; + } + return -1; + } + + // clear socket state + cc3k_reset_fd_closed_state(fd); + + // store state in new socket object + socket2->u_state = fd; + + // return ip and port + // it seems CC3000 returns little endian for accept?? + //UNPACK_SOCKADDR(addr, ip, *port); + *port = (addr.sa_data[1] << 8) | addr.sa_data[0]; + ip[3] = addr.sa_data[2]; + ip[2] = addr.sa_data[3]; + ip[1] = addr.sa_data[4]; + ip[0] = addr.sa_data[5]; + + return 0; +} + +STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = CC3000_EXPORT(connect)(socket->u_state, &addr, sizeof(addr)); + if (ret != 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + return 0; +} + +STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + if (cc3k_get_fd_closed_state(socket->u_state)) { + CC3000_EXPORT(closesocket)(socket->u_state); + *_errno = MP_EPIPE; + return -1; + } + + // CC3K does not handle fragmentation, and will overflow, + // split the packet into smaller ones and send them out. + mp_int_t bytes = 0; + while (bytes < len) { + int n = MIN((len - bytes), MAX_TX_PACKET); + n = CC3000_EXPORT(send)(socket->u_state, (uint8_t*)buf + bytes, n, 0); + if (n <= 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + bytes += n; + } + + return bytes; +} + +STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + // check the socket is open + if (cc3k_get_fd_closed_state(socket->u_state)) { + // socket is closed, but CC3000 may have some data remaining in buffer, so check + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(socket->u_state, &rfds); + cc3000_timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1; + int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv); + if (nfds == -1 || !FD_ISSET(socket->u_state, &rfds)) { + // no data waiting, so close socket and return 0 data + CC3000_EXPORT(closesocket)(socket->u_state); + return 0; + } + } + + // cap length at MAX_RX_PACKET + len = MIN(len, MAX_RX_PACKET); + + // do the recv + int ret = CC3000_EXPORT(recv)(socket->u_state, buf, len, 0); + if (ret < 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + + return ret; +} + +STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = CC3000_EXPORT(sendto)(socket->u_state, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr)); + if (ret < 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + return ret; +} + +STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + sockaddr addr; + socklen_t addr_len = sizeof(addr); + mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->u_state, buf, len, 0, &addr, &addr_len); + if (ret < 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + UNPACK_SOCKADDR(addr, ip, *port); + return ret; +} + +STATIC int cc3k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + int ret = CC3000_EXPORT(setsockopt)(socket->u_state, level, opt, optval, optlen); + if (ret < 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + return 0; +} + +STATIC int cc3k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { + int ret; + if (timeout_ms == 0 || timeout_ms == -1) { + int optval; + socklen_t optlen = sizeof(optval); + if (timeout_ms == 0) { + // set non-blocking mode + optval = SOCK_ON; + } else { + // set blocking mode + optval = SOCK_OFF; + } + ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen); + if (ret == 0) { + ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); + } + } else { + // set timeout + socklen_t optlen = sizeof(timeout_ms); + ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen); + } + + if (ret != 0) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + + return 0; +} + +STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + int fd = socket->u_state; + + // init fds + fd_set rfds, wfds, xfds; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + + // set fds if needed + if (flags & MP_STREAM_POLL_RD) { + FD_SET(fd, &rfds); + + // A socked that just closed is available for reading. A call to + // recv() returns 0 which is consistent with BSD. + if (cc3k_get_fd_closed_state(fd)) { + ret |= MP_STREAM_POLL_RD; + } + } + if (flags & MP_STREAM_POLL_WR) { + FD_SET(fd, &wfds); + } + if (flags & MP_STREAM_POLL_HUP) { + FD_SET(fd, &xfds); + } + + // call cc3000 select with minimum timeout + cc3000_timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1; + int nfds = CC3000_EXPORT(select)(fd + 1, &rfds, &wfds, &xfds, &tv); + + // check for error + if (nfds == -1) { + *_errno = CC3000_EXPORT(errno); + return -1; + } + + // check return of select + if (FD_ISSET(fd, &rfds)) { + ret |= MP_STREAM_POLL_RD; + } + if (FD_ISSET(fd, &wfds)) { + ret |= MP_STREAM_POLL_WR; + } + if (FD_ISSET(fd, &xfds)) { + ret |= MP_STREAM_POLL_HUP; + } + } else { + *_errno = MP_EINVAL; + ret = -1; + } + return ret; +} + +/******************************************************************************/ +// MicroPython bindings; CC3K class + +typedef struct _cc3k_obj_t { + mp_obj_base_t base; +} cc3k_obj_t; + +STATIC const cc3k_obj_t cc3k_obj = {{(mp_obj_type_t*)&mod_network_nic_type_cc3k}}; + +// \classmethod \constructor(spi, pin_cs, pin_en, pin_irq) +// Initialise the CC3000 using the given SPI bus and pins and return a CC3K object. +// +// Note: pins were originally hard-coded to: +// PYBv1.0: init(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3) +// [SPI on Y position; Y6=B13=SCK, Y7=B14=MISO, Y8=B15=MOSI] +// +// STM32F4DISC: init(pyb.SPI(2), pyb.Pin.cpu.A15, pyb.Pin.cpu.B10, pyb.Pin.cpu.B11) +STATIC mp_obj_t cc3k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 4, 4, false); + + // set the pins to use + SpiInit( + spi_from_mp_obj(args[0])->spi, + pin_find(args[1]), + pin_find(args[2]), + pin_find(args[3]) + ); + + // initialize and start the module + wlan_init(cc3k_callback, NULL, NULL, NULL, + ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin); + + if (wlan_start(0) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "failed to init CC3000 module")); + } + + // set connection policy. this should be called explicitly by the user + // wlan_ioctl_set_connection_policy(0, 0, 0); + + // Mask out all non-required events from the CC3000 + wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE| + HCI_EVNT_WLAN_UNSOL_INIT| + HCI_EVNT_WLAN_ASYNC_PING_REPORT| + HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE); + + // register with network module + mod_network_register_nic((mp_obj_t)&cc3k_obj); + + return (mp_obj_t)&cc3k_obj; +} + +// method connect(ssid, key=None, *, security=WPA2, bssid=None) +STATIC mp_obj_t cc3k_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = WLAN_SEC_WPA2} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get ssid + size_t ssid_len; + const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len); + + // get key and sec + size_t key_len = 0; + const char *key = NULL; + mp_uint_t sec = WLAN_SEC_UNSEC; + if (args[1].u_obj != mp_const_none) { + key = mp_obj_str_get_data(args[1].u_obj, &key_len); + sec = args[2].u_int; + } + + // get bssid + const char *bssid = NULL; + if (args[3].u_obj != mp_const_none) { + bssid = mp_obj_str_get_str(args[3].u_obj); + } + + // connect to AP + if (wlan_connect(sec, (char*)ssid, ssid_len, (uint8_t*)bssid, (uint8_t*)key, key_len) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "could not connect to ssid=%s, sec=%d, key=%s\n", ssid, sec, key)); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_connect_obj, 1, cc3k_connect); + +STATIC mp_obj_t cc3k_disconnect(mp_obj_t self_in) { + // should we check return value? + wlan_disconnect(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_disconnect_obj, cc3k_disconnect); + +STATIC mp_obj_t cc3k_isconnected(mp_obj_t self_in) { + return mp_obj_new_bool(wlan_connected && ip_obtained); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_isconnected_obj, cc3k_isconnected); + +STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) { + tNetappIpconfigRetArgs ipconfig; + netapp_ipconfig(&ipconfig); + + // render MAC address + VSTR_FIXED(mac_vstr, 18); + const uint8_t *mac = ipconfig.uaMacAddr; + vstr_printf(&mac_vstr, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + + // create and return tuple with ifconfig info + mp_obj_t tuple[7] = { + netutils_format_ipv4_addr(ipconfig.aucIP, NETUTILS_LITTLE), + netutils_format_ipv4_addr(ipconfig.aucSubnetMask, NETUTILS_LITTLE), + netutils_format_ipv4_addr(ipconfig.aucDefaultGateway, NETUTILS_LITTLE), + netutils_format_ipv4_addr(ipconfig.aucDNSServer, NETUTILS_LITTLE), + netutils_format_ipv4_addr(ipconfig.aucDHCPServer, NETUTILS_LITTLE), + mp_obj_new_str(mac_vstr.buf, mac_vstr.len), + mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID)), + }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_ifconfig_obj, cc3k_ifconfig); + +STATIC mp_obj_t cc3k_patch_version(mp_obj_t self_in) { + uint8_t pver[2]; + mp_obj_tuple_t *t_pver; + + nvmem_read_sp_version(pver); + t_pver = mp_obj_new_tuple(2, NULL); + t_pver->items[0] = mp_obj_new_int(pver[0]); + t_pver->items[1] = mp_obj_new_int(pver[1]); + return t_pver; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_version_obj, cc3k_patch_version); + +STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in, mp_obj_t key_in) { + const char *key = mp_obj_str_get_str(key_in); + if (key[0] == 'p' && key[1] == 'g' && key[2] == 'm' && key[3] == '\0') { + patch_prog_start(); + } else { + mp_print_str(&mp_plat_print, "pass 'pgm' as argument in order to program\n"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_patch_program_obj, cc3k_patch_program); + +STATIC const mp_rom_map_elem_t cc3k_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&cc3k_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&cc3k_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&cc3k_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&cc3k_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_patch_version), MP_ROM_PTR(&cc3k_patch_version_obj) }, + { MP_ROM_QSTR(MP_QSTR_patch_program), MP_ROM_PTR(&cc3k_patch_program_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(WLAN_SEC_WEP) }, + { MP_ROM_QSTR(MP_QSTR_WPA), MP_ROM_INT(WLAN_SEC_WPA) }, + { MP_ROM_QSTR(MP_QSTR_WPA2), MP_ROM_INT(WLAN_SEC_WPA2) }, +}; + +STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table); + +const mod_network_nic_type_t mod_network_nic_type_cc3k = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_CC3K, + .make_new = cc3k_make_new, + .locals_dict = (mp_obj_dict_t*)&cc3k_locals_dict, + }, + .gethostbyname = cc3k_gethostbyname, + .socket = cc3k_socket_socket, + .close = cc3k_socket_close, + .bind = cc3k_socket_bind, + .listen = cc3k_socket_listen, + .accept = cc3k_socket_accept, + .connect = cc3k_socket_connect, + .send = cc3k_socket_send, + .recv = cc3k_socket_recv, + .sendto = cc3k_socket_sendto, + .recvfrom = cc3k_socket_recvfrom, + .setsockopt = cc3k_socket_setsockopt, + .settimeout = cc3k_socket_settimeout, + .ioctl = cc3k_socket_ioctl, +}; diff --git a/src/openmv/src/micropython/ports/stm32/modnwwiznet5k.c b/src/openmv/src/micropython/ports/stm32/modnwwiznet5k.c new file mode 100755 index 0000000..bf4b72f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modnwwiznet5k.c @@ -0,0 +1,505 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" +#include "pin.h" +#include "spi.h" + +#if MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP + +#include "ethernet/wizchip_conf.h" +#include "ethernet/socket.h" +#include "internet/dns/dns.h" + +/// \moduleref network + +typedef struct _wiznet5k_obj_t { + mp_obj_base_t base; + mp_uint_t cris_state; + const spi_t *spi; + const pin_obj_t *cs; + const pin_obj_t *rst; + uint8_t socket_used; +} wiznet5k_obj_t; + +STATIC wiznet5k_obj_t wiznet5k_obj; + +STATIC void wiz_cris_enter(void) { + wiznet5k_obj.cris_state = MICROPY_BEGIN_ATOMIC_SECTION(); +} + +STATIC void wiz_cris_exit(void) { + MICROPY_END_ATOMIC_SECTION(wiznet5k_obj.cris_state); +} + +STATIC void wiz_cs_select(void) { + mp_hal_pin_low(wiznet5k_obj.cs); +} + +STATIC void wiz_cs_deselect(void) { + mp_hal_pin_high(wiznet5k_obj.cs); +} + +STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); + (void)status; +} + +STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); + (void)status; +} + +STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + uint8_t dns_ip[MOD_NETWORK_IPADDR_BUF_SIZE] = {8, 8, 8, 8}; + uint8_t *buf = m_new(uint8_t, MAX_DNS_BUF_SIZE); + DNS_init(0, buf); + mp_int_t ret = DNS_run(dns_ip, (uint8_t*)name, out_ip); + m_del(uint8_t, buf, MAX_DNS_BUF_SIZE); + if (ret == 1) { + // success + return 0; + } else { + // failure + return -2; + } +} + +STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { + if (socket->u_param.domain != MOD_NETWORK_AF_INET) { + *_errno = MP_EAFNOSUPPORT; + return -1; + } + + switch (socket->u_param.type) { + case MOD_NETWORK_SOCK_STREAM: socket->u_param.type = Sn_MR_TCP; break; + case MOD_NETWORK_SOCK_DGRAM: socket->u_param.type = Sn_MR_UDP; break; + default: *_errno = MP_EINVAL; return -1; + } + + if (socket->u_param.fileno == -1) { + // get first unused socket number + for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { + if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { + wiznet5k_obj.socket_used |= (1 << sn); + socket->u_param.fileno = sn; + break; + } + } + if (socket->u_param.fileno == -1) { + // too many open sockets + *_errno = MP_EMFILE; + return -1; + } + } + + // WIZNET does not have a concept of pure "open socket". You need to know + // if it's a server or client at the time of creation of the socket. + // So, we defer the open until we know what kind of socket we want. + + // use "domain" to indicate that this socket has not yet been opened + socket->u_param.domain = 0; + + return 0; +} + +STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { + uint8_t sn = (uint8_t)socket->u_param.fileno; + if (sn < _WIZCHIP_SOCK_NUM_) { + wiznet5k_obj.socket_used &= ~(1 << sn); + WIZCHIP_EXPORT(close)(sn); + } +} + +STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + // open the socket in server mode (if port != 0) + mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->u_param.fileno, socket->u_param.type, port, 0); + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + + // indicate that this socket has been opened + socket->u_param.domain = 1; + + // success + return 0; +} + +STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { + mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->u_param.fileno); + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + return 0; +} + +STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) { + for (;;) { + int sr = getSn_SR((uint8_t)socket->u_param.fileno); + if (sr == SOCK_ESTABLISHED) { + socket2->u_param = socket->u_param; + getSn_DIPR((uint8_t)socket2->u_param.fileno, ip); + *port = getSn_PORT(socket2->u_param.fileno); + + // WIZnet turns the listening socket into the client socket, so we + // need to re-bind and re-listen on another socket for the server. + // TODO handle errors, especially no-more-sockets error + socket->u_param.domain = MOD_NETWORK_AF_INET; + socket->u_param.fileno = -1; + int _errno2; + if (wiznet5k_socket_socket(socket, &_errno2) != 0) { + //printf("(bad resocket %d)\n", _errno2); + } else if (wiznet5k_socket_bind(socket, NULL, *port, &_errno2) != 0) { + //printf("(bad rebind %d)\n", _errno2); + } else if (wiznet5k_socket_listen(socket, 0, &_errno2) != 0) { + //printf("(bad relisten %d)\n", _errno2); + } + + return 0; + } + if (sr == SOCK_CLOSED || sr == SOCK_CLOSE_WAIT) { + wiznet5k_socket_close(socket); + *_errno = MP_ENOTCONN; // ?? + return -1; + } + mp_hal_delay_ms(1); + } +} + +STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + // use "bind" function to open the socket in client mode + if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) { + return -1; + } + + // now connect + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->u_param.fileno, ip, port); + MP_THREAD_GIL_ENTER(); + + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + + // success + return 0; +} + +STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(send)(socket->u_param.fileno, (byte*)buf, len); + MP_THREAD_GIL_ENTER(); + + // TODO convert Wiz errno's to POSIX ones + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + return ret; +} + +STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->u_param.fileno, buf, len); + MP_THREAD_GIL_ENTER(); + + // TODO convert Wiz errno's to POSIX ones + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + return ret; +} + +STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + if (socket->u_param.domain == 0) { + // socket not opened; use "bind" function to open the socket in client mode + if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) { + return -1; + } + } + + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->u_param.fileno, (byte*)buf, len, ip, port); + MP_THREAD_GIL_ENTER(); + + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + return ret; +} + +STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + uint16_t port2; + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->u_param.fileno, buf, len, ip, &port2); + MP_THREAD_GIL_ENTER(); + *port = port2; + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + return ret; +} + +STATIC int wiznet5k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + // TODO + *_errno = MP_EINVAL; + return -1; +} + +STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { + // TODO + *_errno = MP_EINVAL; + return -1; + + /* + if (timeout_ms == 0) { + // set non-blocking mode + uint8_t arg = SOCK_IO_NONBLOCK; + WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg); + } + */ +} + +STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { + if (request == MP_STREAM_POLL) { + int ret = 0; + if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->u_param.fileno) != 0) { + ret |= MP_STREAM_POLL_RD; + } + if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->u_param.fileno) != 0) { + ret |= MP_STREAM_POLL_WR; + } + return ret; + } else { + *_errno = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +#if 0 +STATIC void wiznet5k_socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + wiznet5k_socket_obj_t *self = self_in; + print(env, "", self->sn, getSn_MR(self->sn)); +} + +STATIC mp_obj_t wiznet5k_socket_disconnect(mp_obj_t self_in) { + mp_int_t ret = WIZCHIP_EXPORT(disconnect)(self->sn); + return 0; +} +#endif + +/******************************************************************************/ +// MicroPython bindings + +/// \classmethod \constructor(spi, pin_cs, pin_rst) +/// Create and return a WIZNET5K object. +STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 3, 3, false); + + // init the wiznet5k object + wiznet5k_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wiznet5k; + wiznet5k_obj.cris_state = 0; + wiznet5k_obj.spi = spi_from_mp_obj(args[0]); + wiznet5k_obj.cs = pin_find(args[1]); + wiznet5k_obj.rst = pin_find(args[2]); + wiznet5k_obj.socket_used = 0; + + /*!< SPI configuration */ + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused + spi_init(wiznet5k_obj.spi, false); + + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); + + mp_hal_pin_low(wiznet5k_obj.rst); + mp_hal_delay_ms(1); // datasheet says 2us + mp_hal_pin_high(wiznet5k_obj.rst); + mp_hal_delay_ms(160); // datasheet says 150ms + + reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); + reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect); + reg_wizchip_spi_cbfunc(wiz_spi_read, wiz_spi_write); + + uint8_t sn_size[16] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 2k buffer for each socket + ctlwizchip(CW_INIT_WIZCHIP, sn_size); + + // set some sensible default values; they are configurable using ifconfig method + wiz_NetInfo netinfo = { + .mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef}, + .ip = {192, 168, 0, 18}, + .sn = {255, 255, 255, 0}, + .gw = {192, 168, 0, 1}, + .dns = {8, 8, 8, 8}, // Google public DNS + .dhcp = NETINFO_STATIC, + }; + ctlnetwork(CN_SET_NETINFO, (void*)&netinfo); + + // seems we need a small delay after init + mp_hal_delay_ms(250); + + // register with network module + mod_network_register_nic(&wiznet5k_obj); + + // return wiznet5k object + return &wiznet5k_obj; +} + +/// \method regs() +/// Dump WIZNET5K registers. +STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) { + //wiznet5k_obj_t *self = self_in; + printf("Wiz CREG:"); + for (int i = 0; i < 0x50; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = i; + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + for (int sn = 0; sn < 4; ++sn) { + printf("\nWiz SREG[%d]:", sn); + for (int i = 0; i < 0x30; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = WIZCHIP_SREG_ADDR(sn, i); + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + } + printf("\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs); + +STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) { + (void)self_in; + return mp_obj_new_bool(wizphy_getphylink() == PHY_LINK_ON); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected); + +/// \method ifconfig([(ip, subnet, gateway, dns)]) +/// Get/set IP address, subnet mask, gateway and DNS. +STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { + wiz_NetInfo netinfo; + ctlnetwork(CN_GET_NETINFO, &netinfo); + if (n_args == 1) { + // get + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr(netinfo.ip, NETUTILS_BIG), + netutils_format_ipv4_addr(netinfo.sn, NETUTILS_BIG), + netutils_format_ipv4_addr(netinfo.gw, NETUTILS_BIG), + netutils_format_ipv4_addr(netinfo.dns, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], netinfo.ip, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], netinfo.sn, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], netinfo.gw, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], netinfo.dns, NETUTILS_BIG); + ctlnetwork(CN_SET_NETINFO, &netinfo); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig); + +STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table); + +const mod_network_nic_type_t mod_network_nic_type_wiznet5k = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_WIZNET5K, + .make_new = wiznet5k_make_new, + .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict, + }, + .gethostbyname = wiznet5k_gethostbyname, + .socket = wiznet5k_socket_socket, + .close = wiznet5k_socket_close, + .bind = wiznet5k_socket_bind, + .listen = wiznet5k_socket_listen, + .accept = wiznet5k_socket_accept, + .connect = wiznet5k_socket_connect, + .send = wiznet5k_socket_send, + .recv = wiznet5k_socket_recv, + .sendto = wiznet5k_socket_sendto, + .recvfrom = wiznet5k_socket_recvfrom, + .setsockopt = wiznet5k_socket_setsockopt, + .settimeout = wiznet5k_socket_settimeout, + .ioctl = wiznet5k_socket_ioctl, +}; + +#endif // MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP diff --git a/src/openmv/src/micropython/ports/stm32/modpyb.c b/src/openmv/src/micropython/ports/stm32/modpyb.c new file mode 100755 index 0000000..0e8313d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modpyb.c @@ -0,0 +1,239 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "lib/utils/pyexec.h" +#include "drivers/dht/dht.h" +#include "stm32_it.h" +#include "irq.h" +#include "led.h" +#include "timer.h" +#include "extint.h" +#include "usrsw.h" +#include "rng.h" +#include "rtc.h" +#include "i2c.h" +#include "spi.h" +#include "uart.h" +#include "can.h" +#include "adc.h" +#include "storage.h" +#include "sdcard.h" +#include "accel.h" +#include "servo.h" +#include "dac.h" +#include "lcd.h" +#include "usb.h" +#include "portmodules.h" +#include "modmachine.h" +#include "extmod/vfs.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) { + pyb_hard_fault_debug = mp_obj_is_true(value); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug); + +#if MICROPY_PY_PYB_LEGACY + +// Returns the number of milliseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. +STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { + uint32_t startMillis = mp_obj_get_int(start); + uint32_t currMillis = mp_hal_ticks_ms(); + return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x3fffffff); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis); + +// Returns the number of microseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. +STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { + uint32_t startMicros = mp_obj_get_int(start); + uint32_t currMicros = mp_hal_ticks_us(); + return MP_OBJ_NEW_SMALL_INT((currMicros - startMicros) & 0x3fffffff); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros); + +#endif + +MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c + +// Get or set the UART object that the REPL is repeated on. +// This is a legacy function, use of uos.dupterm is preferred. +STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_PORT(pyb_stdio_uart) == NULL) { + return mp_const_none; + } else { + return MP_OBJ_FROM_PTR(MP_STATE_PORT(pyb_stdio_uart)); + } + } else { + if (args[0] == mp_const_none) { + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), false); + MP_STATE_PORT(pyb_stdio_uart) = NULL; + } + } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + MP_STATE_PORT(pyb_stdio_uart) = MP_OBJ_TO_PTR(args[0]); + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); + } else { + mp_raise_ValueError("need a UART object"); + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart); + +STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) }, + + { MP_ROM_QSTR(MP_QSTR_fault_debug), MP_ROM_PTR(&pyb_fault_debug_obj) }, + + #if MICROPY_PY_PYB_LEGACY + { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, + { MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + + { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) }, + #if IRQ_ENABLE_STATS + { MP_ROM_QSTR(MP_QSTR_irq_stats), MP_ROM_PTR(&pyb_irq_stats_obj) }, + #endif + + #if MICROPY_PY_PYB_LEGACY + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, + { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) }, + + #if MICROPY_HW_ENABLE_USB + { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) }, + { MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) }, + { MP_ROM_QSTR(MP_QSTR_USB_VCP), MP_ROM_PTR(&pyb_usb_vcp_type) }, + { MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&pyb_usb_hid_type) }, + #if MICROPY_PY_PYB_LEGACY + // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead + { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, + { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, + #endif + #endif + + #if MICROPY_PY_PYB_LEGACY + { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_elapsed_micros), MP_ROM_PTR(&pyb_elapsed_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_delay), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + #endif + + // This function is not intended to be public and may be moved elsewhere + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, + +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) }, +#endif + +#if MICROPY_HW_ENABLE_RTC + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, +#endif + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, + { MP_ROM_QSTR(MP_QSTR_ExtInt), MP_ROM_PTR(&extint_type) }, + +#if MICROPY_HW_ENABLE_SERVO + { MP_ROM_QSTR(MP_QSTR_pwm), MP_ROM_PTR(&pyb_pwm_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_servo), MP_ROM_PTR(&pyb_servo_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_Servo), MP_ROM_PTR(&pyb_servo_type) }, +#endif + +#if MICROPY_HW_HAS_SWITCH + { MP_ROM_QSTR(MP_QSTR_Switch), MP_ROM_PTR(&pyb_switch_type) }, +#endif + +#if MICROPY_HW_HAS_FLASH + { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&pyb_flash_type) }, +#endif + +#if MICROPY_HW_HAS_SDCARD + #if MICROPY_PY_PYB_LEGACY + { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete + #endif + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) }, +#endif + +#if defined(MICROPY_HW_LED1) + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, +#endif + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, + #endif + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, +#if MICROPY_HW_ENABLE_CAN + { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) }, +#endif + + #if MICROPY_HW_ENABLE_ADC + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) }, + #endif + +#if MICROPY_HW_ENABLE_DAC + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, +#endif + +#if MICROPY_HW_HAS_MMA7660 + { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) }, +#endif + +#if MICROPY_HW_HAS_LCD + { MP_ROM_QSTR(MP_QSTR_LCD), MP_ROM_PTR(&pyb_lcd_type) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table); + +const mp_obj_module_t pyb_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&pyb_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/stm32/modstm.c b/src/openmv/src/micropython/ports/stm32/modstm.c new file mode 100755 index 0000000..3fae3a5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modstm.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/objint.h" +#include "extmod/machine_mem.h" +#include "portmodules.h" + +#if MICROPY_PY_STM + +#include "genhdr/modstm_mpz.h" + +STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stm) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + +#include "genhdr/modstm_const.h" +}; + +STATIC MP_DEFINE_CONST_DICT(stm_module_globals, stm_module_globals_table); + +const mp_obj_module_t stm_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&stm_module_globals, +}; + +#endif // MICROPY_PY_STM diff --git a/src/openmv/src/micropython/ports/stm32/modules/dht.py b/src/openmv/src/micropython/ports/stm32/modules/dht.py new file mode 100755 index 0000000..2aa2f5c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/stm32/modules/lcd160cr.py b/src/openmv/src/micropython/ports/stm32/modules/lcd160cr.py new file mode 100755 index 0000000..9e63f1d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modules/lcd160cr.py @@ -0,0 +1 @@ +../../../drivers/display/lcd160cr.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/stm32/modules/lcd160cr_test.py b/src/openmv/src/micropython/ports/stm32/modules/lcd160cr_test.py new file mode 100755 index 0000000..5f5bcc1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modules/lcd160cr_test.py @@ -0,0 +1 @@ +../../../drivers/display/lcd160cr_test.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/stm32/modules/onewire.py b/src/openmv/src/micropython/ports/stm32/modules/onewire.py new file mode 100755 index 0000000..33f30e8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modules/onewire.py @@ -0,0 +1 @@ +../../../drivers/onewire/onewire.py \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/stm32/moduos.c b/src/openmv/src/micropython/ports/stm32/moduos.c new file mode 100755 index 0000000..f492b0b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/moduos.c @@ -0,0 +1,163 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/objstr.h" +#include "lib/timeutils/timeutils.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" +#include "rng.h" +#include "uart.h" +#include "portmodules.h" + +/// \module os - basic "operating system" services +/// +/// The `os` module contains functions for filesystem access and `urandom`. +/// +/// The filesystem has `/` as the root directory, and the available physical +/// drives are accessible from here. They are currently: +/// +/// /flash -- the internal flash filesystem +/// /sd -- the SD card (if it exists) +/// +/// On boot up, the current directory is `/flash` if no SD card is inserted, +/// otherwise it is `/sd`. + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, "pyboard"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, "pyboard"); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + MP_ROM_PTR(&os_uname_info_sysname_obj), + MP_ROM_PTR(&os_uname_info_nodename_obj), + MP_ROM_PTR(&os_uname_info_release_obj), + MP_ROM_PTR(&os_uname_info_version_obj), + MP_ROM_PTR(&os_uname_info_machine_obj) +); + +STATIC mp_obj_t os_uname(void) { + return MP_OBJ_FROM_PTR(&os_uname_info_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +/// \function sync() +/// Sync all filesystems. +STATIC mp_obj_t os_sync(void) { + #if MICROPY_VFS_FAT + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + // this assumes that vfs->obj is fs_user_mount_t with block device functions + disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL); + } + #endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync); + +#if MICROPY_HW_ENABLE_RNG +/// \function urandom(n) +/// Return a bytes object with n random bytes, generated by the hardware +/// random number generator. +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + for (int i = 0; i < n; i++) { + vstr.buf[i] = rng_get(); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +#endif + +STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false); + } + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true); + } + return prev_obj; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_dupterm_obj, 1, 2, uos_dupterm); + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename),MP_ROM_PTR(&mp_vfs_rename_obj)}, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + + { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, + + /// \constant sep - separation character used in paths + { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, + +#if MICROPY_HW_ENABLE_RNG + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, +#endif + + // these are MicroPython extensions + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/stm32/modusocket.c b/src/openmv/src/micropython/ports/stm32/modusocket.c new file mode 100755 index 0000000..7503ecb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modusocket.c @@ -0,0 +1,468 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" +#include "modnetwork.h" + +#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP + +/******************************************************************************/ +// socket class + +STATIC const mp_obj_type_t socket_type; + +// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + // create socket object (not bound to any NIC yet) + mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t); + s->base.type = &socket_type; + s->nic = MP_OBJ_NULL; + s->nic_type = NULL; + s->u_param.domain = MOD_NETWORK_AF_INET; + s->u_param.type = MOD_NETWORK_SOCK_STREAM; + s->u_param.fileno = -1; + if (n_args >= 1) { + s->u_param.domain = mp_obj_get_int(args[0]); + if (n_args >= 2) { + s->u_param.type = mp_obj_get_int(args[1]); + if (n_args >= 4) { + s->u_param.fileno = mp_obj_get_int(args[3]); + } + } + } + + return MP_OBJ_FROM_PTR(s); +} + +STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { + if (self->nic == MP_OBJ_NULL) { + // select NIC based on IP + self->nic = mod_network_find_nic(ip); + self->nic_type = (mod_network_nic_type_t*)mp_obj_get_type(self->nic); + + // call the NIC to open the socket + int _errno; + if (self->nic_type->socket(self, &_errno) != 0) { + mp_raise_OSError(_errno); + } + } +} + +// method socket.bind(address) +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to bind the socket + int _errno; + if (self->nic_type->bind(self, ip, port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +// method socket.listen(backlog) +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->nic == MP_OBJ_NULL) { + // not connected + // TODO I think we can listen even if not bound... + mp_raise_OSError(MP_ENOTCONN); + } + + int _errno; + if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +// method socket.accept() +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // create new socket object + // starts with empty NIC so that finaliser doesn't run close() method if accept() fails + mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); + socket2->base.type = &socket_type; + socket2->nic = MP_OBJ_NULL; + socket2->nic_type = NULL; + + // accept incoming connection + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port; + int _errno; + if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + // new socket has valid state, so set the NIC to the same as parent + socket2->nic = self->nic; + socket2->nic_type = self->nic_type; + + // make the return value + mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + client->items[0] = MP_OBJ_FROM_PTR(socket2); + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return MP_OBJ_FROM_PTR(client); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +// method socket.connect(address) +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to connect the socket + int _errno; + if (self->nic_type->connect(self, ip, port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +// method socket.send(bytes) +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_EPIPE); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int _errno; + mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +// method socket.recv(bufsize) +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + int _errno; + mp_uint_t ret = self->nic_type->recv(self, (byte*)vstr.buf, len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + if (ret == 0) { + return mp_const_empty_bytes; + } + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +// method socket.sendto(bytes, address) +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the data + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to sendto + int _errno; + mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + + return mp_obj_new_int(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +// method socket.recvfrom(bufsize) +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(len_in)); + byte ip[4]; + mp_uint_t port; + int _errno; + mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + mp_obj_t tuple[2]; + if (ret == 0) { + tuple[0] = mp_const_empty_bytes; + } else { + vstr.len = ret; + tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +// method socket.setsockopt(level, optname, value) +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + mp_int_t level = mp_obj_get_int(args[1]); + mp_int_t opt = mp_obj_get_int(args[2]); + + const void *optval; + mp_uint_t optlen; + mp_int_t val; + if (mp_obj_is_integer(args[3])) { + val = mp_obj_get_int_truncated(args[3]); + optval = &val; + optlen = sizeof(val); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + optval = bufinfo.buf; + optlen = bufinfo.len; + } + + int _errno; + if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +// method socket.settimeout(value) +// timeout=0 means non-blocking +// timeout=None means blocking +// otherwise, timeout is in seconds +STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_uint_t timeout; + if (timeout_in == mp_const_none) { + timeout = -1; + } else { + #if MICROPY_PY_BUILTINS_FLOAT + timeout = 1000 * mp_obj_get_float(timeout_in); + #else + timeout = 1000 * mp_obj_get_int(timeout_in); + #endif + } + int _errno; + if (self->nic_type->settimeout(self, timeout, &_errno) != 0) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +// method socket.setblocking(flag) +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { + if (mp_obj_is_true(blocking)) { + return socket_settimeout(self_in, mp_const_none); + } else { + return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (request == MP_STREAM_CLOSE) { + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + self->nic = MP_OBJ_NULL; + } + return 0; + } + return self->nic_type->ioctl(self, request, arg, errcode); +} + +STATIC const mp_stream_p_t socket_stream_p = { + .ioctl = socket_ioctl, + .is_text = false, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .make_new = socket_make_new, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_dict_t*)&socket_locals_dict, +}; + +/******************************************************************************/ +// usocket module + +// function usocket.getaddrinfo(host, port) +STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { + size_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + mp_int_t port = mp_obj_get_int(port_in); + uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + bool have_ip = false; + + if (hlen > 0) { + // check if host is already in IP form + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + netutils_parse_ipv4_addr(host_in, out_ip, NETUTILS_BIG); + have_ip = true; + nlr_pop(); + } else { + // swallow exception: host was not in IP form so need to do DNS lookup + } + } + + if (!have_ip) { + // find a NIC that can do a name lookup + for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { + mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i]; + mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + if (nic_type->gethostbyname != NULL) { + int ret = nic_type->gethostbyname(nic, host, hlen, out_ip); + if (ret != 0) { + mp_raise_OSError(ret); + } + have_ip = true; + break; + } + } + } + + if (!have_ip) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); + } + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo); + +STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) }, + + /* + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(MOD_NETWORK_IPPROTO_IP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_ICMP), MP_ROM_INT(MOD_NETWORK_IPPROTO_ICMP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV4), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV4) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(MOD_NETWORK_IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(MOD_NETWORK_IPPROTO_UDP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV6), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV6) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_RAW), MP_ROM_INT(MOD_NETWORK_IPPROTO_RAW) }, + */ +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; + +#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP diff --git a/src/openmv/src/micropython/ports/stm32/modutime.c b/src/openmv/src/micropython/ports/stm32/modutime.c new file mode 100755 index 0000000..6b5c841 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/modutime.c @@ -0,0 +1,153 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/obj.h" +#include "lib/timeutils/timeutils.h" +#include "extmod/utime_mphal.h" +#include "systick.h" +#include "portmodules.h" +#include "rtc.h" + +/// \module time - time related functions +/// +/// The `time` module provides functions for getting the current time and date, +/// and for sleeping. + +/// \function localtime([secs]) +/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which +/// contains: (year, month, mday, hour, minute, second, weekday, yearday) +/// If secs is not provided or None, then the current time from the RTC is used. +/// year includes the century (for example 2014) +/// month is 1-12 +/// mday is 1-31 +/// hour is 0-23 +/// minute is 0-59 +/// second is 0-59 +/// weekday is 0-6 for Mon-Sun. +/// yearday is 1-366 +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + if (n_args == 0 || args[0] == mp_const_none) { + // get current date and time + // note: need to call get time then get date to correctly access the registers + rtc_init_finalise(); + RTC_DateTypeDef date; + RTC_TimeTypeDef time; + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); + mp_obj_t tuple[8] = { + mp_obj_new_int(2000 + date.Year), + mp_obj_new_int(date.Month), + mp_obj_new_int(date.Date), + mp_obj_new_int(time.Hours), + mp_obj_new_int(time.Minutes), + mp_obj_new_int(time.Seconds), + mp_obj_new_int(date.WeekDay - 1), + mp_obj_new_int(timeutils_year_day(2000 + date.Year, date.Month, date.Date)), + }; + return mp_obj_new_tuple(8, tuple); + } else { + mp_int_t seconds = mp_obj_get_int(args[0]); + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + + +/// \function mktime() +/// This is inverse function of localtime. It's argument is a full 8-tuple +/// which expresses a time as per localtime. It returns an integer which is +/// the number of seconds since Jan 1, 2000. +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + + size_t len; + mp_obj_t *elem; + + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +/// \function time() +/// Returns the number of seconds, as an integer, since 1/1/2000. +STATIC mp_obj_t time_time(void) { + // get date and time + // note: need to call get time then get date to correctly access the registers + rtc_init_finalise(); + RTC_DateTypeDef date; + RTC_TimeTypeDef time; + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); + return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/stm32/mpconfigboard_common.h b/src/openmv/src/micropython/ports/stm32/mpconfigboard_common.h new file mode 100755 index 0000000..2acdcc2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mpconfigboard_common.h @@ -0,0 +1,231 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Common settings and defaults for board configuration. +// The defaults here should be overridden in mpconfigboard.h. + +#include STM32_HAL_H + +/*****************************************************************************/ +// Feature settings with defaults + +// Whether to include the stm module, with peripheral register constants +#ifndef MICROPY_PY_STM +#define MICROPY_PY_STM (1) +#endif + +// Whether to include legacy functions and classes in the pyb module +#ifndef MICROPY_PY_PYB_LEGACY +#define MICROPY_PY_PYB_LEGACY (1) +#endif + +// Whether to enable storage on the internal flash of the MCU +#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) +#endif + +// Whether to enable the RTC, exposed as pyb.RTC +#ifndef MICROPY_HW_ENABLE_RTC +#define MICROPY_HW_ENABLE_RTC (0) +#endif + +// Whether to enable the hardware RNG peripheral, exposed as pyb.rng() +#ifndef MICROPY_HW_ENABLE_RNG +#define MICROPY_HW_ENABLE_RNG (0) +#endif + +// Whether to enable the ADC peripheral, exposed as pyb.ADC and pyb.ADCAll +#ifndef MICROPY_HW_ENABLE_ADC +#define MICROPY_HW_ENABLE_ADC (1) +#endif + +// Whether to enable the DAC peripheral, exposed as pyb.DAC +#ifndef MICROPY_HW_ENABLE_DAC +#define MICROPY_HW_ENABLE_DAC (0) +#endif + +// Whether to enable the DCMI peripheral +#ifndef MICROPY_HW_ENABLE_DCMI +#define MICROPY_HW_ENABLE_DCMI (0) +#endif + +// Whether to enable USB support +#ifndef MICROPY_HW_ENABLE_USB +#define MICROPY_HW_ENABLE_USB (0) +#endif + +// Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo +#ifndef MICROPY_HW_ENABLE_SERVO +#define MICROPY_HW_ENABLE_SERVO (0) +#endif + +// Whether to enable a USR switch, exposed as pyb.Switch +#ifndef MICROPY_HW_HAS_SWITCH +#define MICROPY_HW_HAS_SWITCH (0) +#endif + +// Whether to expose internal flash storage as pyb.Flash +#ifndef MICROPY_HW_HAS_FLASH +#define MICROPY_HW_HAS_FLASH (0) +#endif + +// Whether to enable the SD card interface, exposed as pyb.SDCard +#ifndef MICROPY_HW_HAS_SDCARD +#define MICROPY_HW_HAS_SDCARD (0) +#endif + +// Whether to enable the MMA7660 driver, exposed as pyb.Accel +#ifndef MICROPY_HW_HAS_MMA7660 +#define MICROPY_HW_HAS_MMA7660 (0) +#endif + +// Whether to enable the LCD32MK driver, exposed as pyb.LCD +#ifndef MICROPY_HW_HAS_LCD +#define MICROPY_HW_HAS_LCD (0) +#endif + +// The volume label used when creating the flash filesystem +#ifndef MICROPY_HW_FLASH_FS_LABEL +#define MICROPY_HW_FLASH_FS_LABEL "pybflash" +#endif + +/*****************************************************************************/ +// General configuration + +// Heap start / end definitions +#ifndef MICROPY_HEAP_START +#define MICROPY_HEAP_START &_heap_start +#endif +#ifndef MICROPY_HEAP_END +#define MICROPY_HEAP_END &_heap_end +#endif + +// Configuration for STM32F0 series +#if defined(STM32F0) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32F4 series +#elif defined(STM32F4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (14) +#ifdef UART8 +#define MICROPY_HW_MAX_UART (8) +#else +#define MICROPY_HW_MAX_UART (6) +#endif + +// Configuration for STM32F7 series +#elif defined(STM32F7) + +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) +#else +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) +#endif + +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32H7 series +#elif defined(STM32H7) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff1e800) +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32L4 series +#elif defined(STM32L4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (6) + +#else +#error Unsupported MCU series +#endif + +// Configure HSE for bypass or oscillator +#if MICROPY_HW_CLK_USE_BYPASS +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_BYPASS) +#else +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_ON) +#endif + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +// Provide block device macros if internal flash storage is enabled +#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl +#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock +#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock +#endif + +// Enable the storage sub-system if a block device is defined +#if defined(MICROPY_HW_BDEV_IOCTL) +#define MICROPY_HW_ENABLE_STORAGE (1) +#else +#define MICROPY_HW_ENABLE_STORAGE (0) +#endif + +// Enable hardware I2C if there are any peripherals defined +#if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ + || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) +#define MICROPY_HW_ENABLE_HW_I2C (1) +#else +#define MICROPY_HW_ENABLE_HW_I2C (0) +#endif + +// Enable CAN if there are any peripherals defined +#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) +#define MICROPY_HW_ENABLE_CAN (1) +#else +#define MICROPY_HW_ENABLE_CAN (0) +#endif + +// Pin definition header file +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" + +// D-cache clean/invalidate helpers +#if __DCACHE_PRESENT == 1 +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \ + (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#define MP_HAL_CLEAN_DCACHE(addr, size) \ + (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#else +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) +#define MP_HAL_CLEAN_DCACHE(addr, size) +#endif + +#define MICROPY_HW_USES_BOOTLOADER (MICROPY_HW_VTOR != 0x08000000) diff --git a/src/openmv/src/micropython/ports/stm32/mpconfigport.h b/src/openmv/src/micropython/ports/stm32/mpconfigport.h new file mode 100755 index 0000000..2c052d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mpconfigport.h @@ -0,0 +1,370 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. + +// board specific definitions +#include "mpconfigboard.h" +#include "mpconfigboard_common.h" + +// memory allocation policies +#define MICROPY_ALLOC_PATH_MAX (128) + +// emitters +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#ifndef MICROPY_EMIT_THUMB +#define MICROPY_EMIT_THUMB (1) +#endif +#ifndef MICROPY_EMIT_INLINE_THUMB +#define MICROPY_EMIT_INLINE_THUMB (1) +#endif + +// compiler configuration +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_RETURN_IF_EXPR (1) + +// optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_OPT_MPZ_BITWISE (1) +#define MICROPY_OPT_MATH_FACTORIAL (1) + +// Python internal features +#define MICROPY_READER_VFS (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#ifndef MICROPY_FLOAT_IMPL // can be configured by each board via mpconfigboard.mk +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#endif +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_VFS (1) +#ifndef MICROPY_VFS_FAT +#define MICROPY_VFS_FAT (1) +#endif + +// control over Python builtins +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_DELATTR_SETATTR (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT stm32_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_MATH_FACTORIAL (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT) // because mp_type_fileio/textio point to fatfs impl +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#ifndef MICROPY_PY_SYS_PLATFORM // let boards override it if they want +#define MICROPY_PY_SYS_PLATFORM "pyboard" +#endif +#define MICROPY_PY_UERRNO (1) +#ifndef MICROPY_PY_THREAD +#define MICROPY_PY_THREAD (0) +#endif + +// extended modules +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_I2C (1) +#if MICROPY_HW_ENABLE_HW_I2C +#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new +#endif +#define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) +#define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) +#define MICROPY_PY_FRAMEBUF (1) +#ifndef MICROPY_PY_USOCKET +#define MICROPY_PY_USOCKET (1) +#endif +#ifndef MICROPY_PY_NETWORK +#define MICROPY_PY_NETWORK (1) +#endif + +// fatfs configuration used in ffconf.h +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_FATFS_USE_LABEL (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MULTI_PARTITION (1) + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t machine_module; +extern const struct _mp_obj_module_t pyb_module; +extern const struct _mp_obj_module_t stm_module; +extern const struct _mp_obj_module_t mp_module_ubinascii; +extern const struct _mp_obj_module_t mp_module_ure; +extern const struct _mp_obj_module_t mp_module_uzlib; +extern const struct _mp_obj_module_t mp_module_ujson; +extern const struct _mp_obj_module_t mp_module_uheapq; +extern const struct _mp_obj_module_t mp_module_uhashlib; +extern const struct _mp_obj_module_t mp_module_uos; +extern const struct _mp_obj_module_t mp_module_utime; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_onewire; + +#if MICROPY_PY_STM +#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, +#else +#define STM_BUILTIN_MODULE +#endif + +#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP +// usocket implementation provided by lwIP +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_POLL extern void pyb_lwip_poll(void); pyb_lwip_poll(); +#elif MICROPY_PY_USOCKET +// usocket implementation provided by skeleton wrapper +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, +#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, +#define SOCKET_POLL +#else +// no usocket module +#define SOCKET_BUILTIN_MODULE +#define SOCKET_BUILTIN_MODULE_WEAK_LINKS +#define SOCKET_POLL +#endif + +#if MICROPY_PY_NETWORK +#define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) }, +#else +#define NETWORK_BUILTIN_MODULE +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + STM_BUILTIN_MODULE \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ + SOCKET_BUILTIN_MODULE \ + NETWORK_BUILTIN_MODULE \ + { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_binascii), MP_ROM_PTR(&mp_module_ubinascii) }, \ + { MP_ROM_QSTR(MP_QSTR_collections), MP_ROM_PTR(&mp_module_collections) }, \ + { MP_ROM_QSTR(MP_QSTR_re), MP_ROM_PTR(&mp_module_ure) }, \ + { MP_ROM_QSTR(MP_QSTR_zlib), MP_ROM_PTR(&mp_module_uzlib) }, \ + { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \ + { MP_ROM_QSTR(MP_QSTR_heapq), MP_ROM_PTR(&mp_module_uheapq) }, \ + { MP_ROM_QSTR(MP_QSTR_hashlib), MP_ROM_PTR(&mp_module_uhashlib) }, \ + { MP_ROM_QSTR(MP_QSTR_io), MP_ROM_PTR(&mp_module_io) }, \ + { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&mp_module_uos) }, \ + { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mp_module_urandom) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, \ + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \ + SOCKET_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&mp_module_ustruct) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \ + +// extra constants +#define MICROPY_PORT_CONSTANTS \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ + { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + STM_BUILTIN_MODULE \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + \ + mp_obj_t pyb_hid_report_desc; \ + \ + mp_obj_t pyb_config_main; \ + \ + mp_obj_t pyb_switch_callback; \ + \ + mp_obj_t pin_class_mapper; \ + mp_obj_t pin_class_map_dict; \ + \ + mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \ + \ + /* pointers to all Timer objects (if they have been created) */ \ + struct _pyb_timer_obj_t *pyb_timer_obj_all[MICROPY_HW_MAX_TIMER]; \ + \ + /* stdio is repeated on this UART object if it's not null */ \ + struct _pyb_uart_obj_t *pyb_stdio_uart; \ + \ + /* pointers to all UART objects (if they have been created) */ \ + struct _pyb_uart_obj_t *pyb_uart_obj_all[MICROPY_HW_MAX_UART]; \ + \ + /* pointers to all CAN objects (if they have been created) */ \ + struct _pyb_can_obj_t *pyb_can_obj_all[2]; \ + \ + /* list of registered NICs */ \ + mp_obj_list_t mod_network_nic_list; \ + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +#define MP_SSIZE_MAX (0x7fffffff) + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// We have inlined IRQ functions for efficiency (they are generally +// 1 machine instruction). +// +// Note on IRQ state: you should not need to know the specific +// value of the state variable, but rather just pass the return +// value from disable_irq back to enable_irq. If you really need +// to know the machine-specific values, see irq.h. + +static inline void enable_irq(mp_uint_t state) { + __set_PRIMASK(state); +} + +static inline mp_uint_t disable_irq(void) { + mp_uint_t state = __get_PRIMASK(); + __disable_irq(); + return state; +} + +#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() +#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) + +#if MICROPY_PY_THREAD +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + SOCKET_POLL \ + if (pyb_thread_enabled) { \ + MP_THREAD_GIL_EXIT(); \ + pyb_thread_yield(); \ + MP_THREAD_GIL_ENTER(); \ + } else { \ + __WFI(); \ + } \ + } while (0); + +#define MICROPY_THREAD_YIELD() pyb_thread_yield() +#else +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + SOCKET_POLL \ + __WFI(); \ + } while (0); + +#define MICROPY_THREAD_YIELD() +#endif + +// We need an implementation of the log2 function which is not a macro +#define MP_NEED_LOG2 (1) + +// There is no classical C heap in bare-metal ports, only Python +// garbage-collected heap. For completeness, emulate C heap via +// GC heap. Note that MicroPython core never uses malloc() and friends, +// so these defines are mostly to help extension module writers. +#define malloc(n) m_malloc(n) +#define free(p) m_free(p) +#define realloc(p, n) m_realloc(p, n) + +// We need to provide a declaration/definition of alloca() +#include diff --git a/src/openmv/src/micropython/ports/stm32/mpconfigport.mk b/src/openmv/src/micropython/ports/stm32/mpconfigport.mk new file mode 100755 index 0000000..e708de6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mpconfigport.mk @@ -0,0 +1,10 @@ +# Enable/disable extra modules + +# wiznet5k module for ethernet support; valid values are: +# 0 : no Wiznet support +# 5200 : support for W5200 module +# 5500 : support for W5500 module +MICROPY_PY_WIZNET5K ?= 0 + +# cc3k module for wifi support +MICROPY_PY_CC3K ?= 0 diff --git a/src/openmv/src/micropython/ports/stm32/mphalport.c b/src/openmv/src/micropython/ports/stm32/mphalport.c new file mode 100755 index 0000000..2062217 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mphalport.c @@ -0,0 +1,164 @@ +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "usb.h" +#include "uart.h" + +// this table converts from HAL_StatusTypeDef to POSIX errno +const byte mp_hal_status_to_errno_table[4] = { + [HAL_OK] = 0, + [HAL_ERROR] = MP_EIO, + [HAL_BUSY] = MP_EBUSY, + [HAL_TIMEOUT] = MP_ETIMEDOUT, +}; + +NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { + mp_raise_OSError(mp_hal_status_to_errno_table[status]); +} + +MP_WEAK int mp_hal_stdin_rx_chr(void) { + for (;;) { +#if 0 +#ifdef USE_HOST_MODE + pyb_usb_host_process(); + int c = pyb_usb_host_get_keyboard(); + if (c != 0) { + return c; + } +#endif +#endif + + #if MICROPY_HW_ENABLE_USB + byte c; + if (usb_vcp_recv_byte(&c) != 0) { + return c; + } + #endif + if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { + return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart)); + } + int dupterm_c = mp_uos_dupterm_rx_chr(); + if (dupterm_c >= 0) { + return dupterm_c; + } + MICROPY_EVENT_POLL_HOOK + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +MP_WEAK void mp_hal_stdout_tx_strn(const char *str, size_t len) { + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len); + } +#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD + lcd_print_strn(str, len); +#endif + #if MICROPY_HW_ENABLE_USB + if (usb_vcp_is_enabled()) { + usb_vcp_send_strn(str, len); + } + #endif + mp_uos_dupterm_tx_strn(str, len); +} + +// Efficiently convert "\n" to "\r\n" +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + const char *last = str; + while (len--) { + if (*str == '\n') { + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } + mp_hal_stdout_tx_strn("\r\n", 2); + ++str; + last = str; + } else { + ++str; + } + } + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } +} + +#if __CORTEX_M >= 0x03 +void mp_hal_ticks_cpu_enable(void) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + #if defined(__CORTEX_M) && __CORTEX_M == 7 + // on Cortex-M7 we must unlock the DWT before writing to its registers + DWT->LAR = 0xc5acce55; + #endif + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + } +} +#endif + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { + #if defined(STM32L476xx) || defined(STM32L496xx) + if (gpio == GPIOG) { + // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. + HAL_PWREx_EnableVddIO2(); + } + #endif + + // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register + + #if defined(STM32F0) + #define AHBxENR AHBENR + #define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos + #elif defined(STM32F4) || defined(STM32F7) + #define AHBxENR AHB1ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos + #elif defined(STM32H7) + #define AHBxENR AHB4ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos + #elif defined(STM32L4) + #define AHBxENR AHB2ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos + #endif + + uint32_t gpio_idx = ((uint32_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx); + volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock + (void)tmp; +} + +void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; + mp_hal_gpio_clock_enable(gpio); + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + #if defined(GPIO_ASCR_ASC0) + // The L4 has a special analog switch to connect the GPIO to the ADC + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (((mode >> 2) & 1) << pin); + gpio->ASCR = (gpio->ASCR & ~(1 << pin)) | ((mode >> 3) & 1) << pin; + #else + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + #endif + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed + gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} + +bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit) { + const pin_af_obj_t *af = pin_find_af(pin, fn, unit); + if (af == NULL) { + return false; + } + mp_hal_pin_config(pin, mode, pull, af->idx); + return true; +} + +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} diff --git a/src/openmv/src/micropython/ports/stm32/mphalport.h b/src/openmv/src/micropython/ports/stm32/mphalport.h new file mode 100755 index 0000000..72413c0 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mphalport.h @@ -0,0 +1,77 @@ +// We use the ST Cube HAL library for most hardware peripherals +#include STM32_HAL_H +#include "pin.h" + +extern const unsigned char mp_hal_status_to_errno_table[4]; + +NORETURN void mp_hal_raise(HAL_StatusTypeDef status); +void mp_hal_set_interrupt_char(int c); // -1 to disable + +// timing functions + +#include "irq.h" + +#if __CORTEX_M == 0 +// Don't have raise_irq_pri on Cortex-M0 so keep IRQs enabled to have SysTick timing +#define mp_hal_quiet_timing_enter() (1) +#define mp_hal_quiet_timing_exit(irq_state) (void)(irq_state) +#else +#define mp_hal_quiet_timing_enter() raise_irq_pri(1) +#define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) +#endif +#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) + +void mp_hal_ticks_cpu_enable(void); +static inline mp_uint_t mp_hal_ticks_cpu(void) { + #if __CORTEX_M == 0 + return 0; + #else + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { + mp_hal_ticks_cpu_enable(); + } + return DWT->CYCCNT; + #endif +} + +// C-level pin HAL + +#include "pin.h" + +#define MP_HAL_PIN_FMT "%q" +#define MP_HAL_PIN_MODE_INPUT (0) +#define MP_HAL_PIN_MODE_OUTPUT (1) +#define MP_HAL_PIN_MODE_ALT (2) +#define MP_HAL_PIN_MODE_ANALOG (3) +#if defined(GPIO_ASCR_ASC0) +#define MP_HAL_PIN_MODE_ADC (11) +#else +#define MP_HAL_PIN_MODE_ADC (3) +#endif +#define MP_HAL_PIN_MODE_OPEN_DRAIN (5) +#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) +#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) +#define MP_HAL_PIN_PULL_UP (GPIO_PULLUP) +#define MP_HAL_PIN_PULL_DOWN (GPIO_PULLDOWN) + +#define mp_hal_pin_obj_t const pin_obj_t* +#define mp_hal_get_pin_obj(o) pin_find(o) +#define mp_hal_pin_name(p) ((p)->name) +#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#if defined(STM32H7) +#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask) +#else +#define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16)) +#endif +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); +void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt); +bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit); +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed); diff --git a/src/openmv/src/micropython/ports/stm32/mpthreadport.c b/src/openmv/src/micropython/ports/stm32/mpthreadport.c new file mode 100755 index 0000000..11653b2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mpthreadport.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" + +#if MICROPY_PY_THREAD + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; + +void mp_thread_init(void) { + mp_thread_mutex_init(&thread_mutex); + mp_thread_set_state(&mp_state_ctx.thread); +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); + gc_collect_root(&th->stack, 1); + if (th != pyb_thread_cur) { + gc_collect_root(th->stack, th->stack_len); + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + if (*stack_size == 0) { + *stack_size = 4096; // default stack size + } else if (*stack_size < 2048) { + *stack_size = 2048; // minimum stack size + } + + // round stack size to a multiple of the word size + size_t stack_len = *stack_size / sizeof(uint32_t); + *stack_size = stack_len * sizeof(uint32_t); + + // allocate stack and linked-list node (must be done outside thread_mutex lock) + uint32_t *stack = m_new(uint32_t, stack_len); + pyb_thread_t *th = m_new_obj(pyb_thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + uint32_t id = pyb_thread_new(th, stack, stack_len, entry, arg); + if (id == 0) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + } + + mp_thread_mutex_unlock(&thread_mutex); + + // adjust stack_size to provide room to recover from hitting the limit + *stack_size -= 1024; +} + +void mp_thread_start(void) { +} + +void mp_thread_finish(void) { +} + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/ports/stm32/mpthreadport.h b/src/openmv/src/micropython/ports/stm32/mpthreadport.h new file mode 100755 index 0000000..8e2372d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/mpthreadport.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpthread.h" +#include "pybthread.h" + +typedef pyb_mutex_t mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); + +static inline void mp_thread_set_state(void *state) { + pyb_thread_set_local(state); +} + +static inline struct _mp_state_thread_t *mp_thread_get_state(void) { + return pyb_thread_get_local(); +} + +static inline void mp_thread_mutex_init(mp_thread_mutex_t *m) { + pyb_mutex_init(m); +} + +static inline int mp_thread_mutex_lock(mp_thread_mutex_t *m, int wait) { + return pyb_mutex_lock(m, wait); +} + +static inline void mp_thread_mutex_unlock(mp_thread_mutex_t *m) { + pyb_mutex_unlock(m); +} diff --git a/src/openmv/src/micropython/ports/stm32/network_wiznet5k.c b/src/openmv/src/micropython/ports/stm32/network_wiznet5k.c new file mode 100755 index 0000000..9db42b7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/network_wiznet5k.c @@ -0,0 +1,417 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/runtime.h" +#include "py/mphal.h" +#include "spi.h" +#include "modnetwork.h" + +#if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP + +#include "drivers/wiznet5k/ethernet/socket.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/etharp.h" + +/*******************************************************************************/ +// Wiznet5k Ethernet driver in MACRAW mode + +typedef struct _wiznet5k_obj_t { + mod_network_nic_type_t base; + mp_uint_t cris_state; + const spi_t *spi; + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t rst; + uint8_t eth_frame[1514]; + struct netif netif; + struct dhcp dhcp_struct; +} wiznet5k_obj_t; + +// Global object holding the Wiznet5k state +STATIC wiznet5k_obj_t wiznet5k_obj; + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self); +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif); + +STATIC void wiz_cris_enter(void) { + wiznet5k_obj.cris_state = MICROPY_BEGIN_ATOMIC_SECTION(); +} + +STATIC void wiz_cris_exit(void) { + MICROPY_END_ATOMIC_SECTION(wiznet5k_obj.cris_state); +} + +STATIC void wiz_cs_select(void) { + mp_hal_pin_low(wiznet5k_obj.cs); +} + +STATIC void wiz_cs_deselect(void) { + mp_hal_pin_high(wiznet5k_obj.cs); +} + +STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); + (void)status; +} + +STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); + (void)status; +} + +STATIC void wiznet5k_init(void) { + // SPI configuration + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused + spi_init(wiznet5k_obj.spi, false); + + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); + + // Reset the chip + mp_hal_pin_low(wiznet5k_obj.rst); + mp_hal_delay_ms(1); // datasheet says 2us + mp_hal_pin_high(wiznet5k_obj.rst); + mp_hal_delay_ms(150); // datasheet says 150ms + + // Set physical interface callbacks + reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); + reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect); + reg_wizchip_spi_cbfunc(wiz_spi_read, wiz_spi_write); + + // Configure 16k buffers for fast MACRAW + uint8_t sn_size[16] = {16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0}; + ctlwizchip(CW_INIT_WIZCHIP, sn_size); + + // Seems we need a small delay after init + mp_hal_delay_ms(250); + + // Hook the Wiznet into lwIP + wiznet5k_lwip_init(&wiznet5k_obj); +} + +STATIC void wiznet5k_deinit(void) { + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif == &wiznet5k_obj.netif) { + netif_remove(netif); + netif->flags = 0; + break; + } + } +} + +STATIC void wiznet5k_get_mac_address(wiznet5k_obj_t *self, uint8_t mac[6]) { + (void)self; + getSHAR(mac); +} + +STATIC void wiznet5k_send_ethernet(wiznet5k_obj_t *self, size_t len, const uint8_t *buf) { + uint8_t ip[4] = {1, 1, 1, 1}; // dummy + int ret = WIZCHIP_EXPORT(sendto)(0, (byte*)buf, len, ip, 11); // dummy port + if (ret != len) { + printf("wiznet5k_send_ethernet: fatal error %d\n", ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + } +} + +// Stores the frame in self->eth_frame and returns number of bytes in the frame, 0 for no frame +STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) { + uint16_t len = getSn_RX_RSR(0); + if (len == 0) { + return 0; + } + + byte ip[4]; + uint16_t port; + int ret = WIZCHIP_EXPORT(recvfrom)(0, self->eth_frame, 1514, ip, &port); + if (ret <= 0) { + printf("wiznet5k_lwip_poll: fatal error len=%u ret=%d\n", len, ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + return 0; + } + + return ret; +} + +/*******************************************************************************/ +// Wiznet5k lwIP interface + +STATIC err_t wiznet5k_netif_output(struct netif *netif, struct pbuf *p) { + wiznet5k_obj_t *self = netif->state; + pbuf_copy_partial(p, self->eth_frame, p->tot_len, 0); + wiznet5k_send_ethernet(self, p->tot_len, self->eth_frame); + return ERR_OK; +} + +STATIC err_t wiznet5k_netif_init(struct netif *netif) { + netif->linkoutput = wiznet5k_netif_output; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + wiznet5k_get_mac_address(netif->state, netif->hwaddr); + netif->hwaddr_len = sizeof(netif->hwaddr); + int ret = WIZCHIP_EXPORT(socket)(0, Sn_MR_MACRAW, 0, 0); + if (ret != 0) { + printf("WIZNET fatal error in netifinit: %d\n", ret); + return ERR_IF; + } + + // Enable MAC filtering so we only get frames destined for us, to reduce load on lwIP + setSn_MR(0, getSn_MR(0) | Sn_MR_MFEN); + + return ERR_OK; +} + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self) { + ip_addr_t ipconfig[4]; + ipconfig[0].addr = 0; + ipconfig[1].addr = 0; + ipconfig[2].addr = 0; + ipconfig[3].addr = 0; + netif_add(&self->netif, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, wiznet5k_netif_init, ethernet_input); + self->netif.name[0] = 'e'; + self->netif.name[1] = '0'; + netif_set_default(&self->netif); + dns_setserver(0, &ipconfig[3]); + dhcp_set_struct(&self->netif, &self->dhcp_struct); + // Setting NETIF_FLAG_UP then clearing it is a workaround for dhcp_start and the + // LWIP_DHCP_CHECK_LINK_UP option, so that the DHCP client schedules itself to + // automatically start when the interface later goes up. + self->netif.flags |= NETIF_FLAG_UP; + dhcp_start(&self->netif); + self->netif.flags &= ~NETIF_FLAG_UP; +} + +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif) { + wiznet5k_obj_t *self = self_in; + uint16_t len; + while ((len = wiznet5k_recv_ethernet(self)) > 0) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, self->eth_frame, len); + if (self->netif.input(p, &self->netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +/*******************************************************************************/ +// MicroPython bindings + +// WIZNET5K([spi, pin_cs, pin_rst]) +STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 3, 3, false); + + const spi_t *spi = spi_from_mp_obj(args[0]); + mp_hal_pin_obj_t cs = pin_find(args[1]); + mp_hal_pin_obj_t rst = pin_find(args[2]); + + // Access the existing object, if it has been constructed with the same hardware interface + if (wiznet5k_obj.base.base.type == &mod_network_nic_type_wiznet5k) { + if (!(wiznet5k_obj.spi == spi && wiznet5k_obj.cs == cs && wiznet5k_obj.rst == rst + && wiznet5k_obj.netif.flags != 0)) { + wiznet5k_deinit(); + } + } + + // Init the wiznet5k object + wiznet5k_obj.base.base.type = &mod_network_nic_type_wiznet5k; + wiznet5k_obj.base.poll_callback = wiznet5k_lwip_poll; + wiznet5k_obj.cris_state = 0; + wiznet5k_obj.spi = spi; + wiznet5k_obj.cs = cs; + wiznet5k_obj.rst = rst; + + // Return wiznet5k object + return MP_OBJ_FROM_PTR(&wiznet5k_obj); +} + +STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) { + (void)self_in; + printf("Wiz CREG:"); + for (int i = 0; i < 0x50; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = i; + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + for (int sn = 0; sn < 4; ++sn) { + printf("\nWiz SREG[%d]:", sn); + for (int i = 0; i < 0x30; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = WIZCHIP_SREG_ADDR(sn, i); + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + } + printf("\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs); + +STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool( + wizphy_getphylink() == PHY_LINK_ON + && (self->netif.flags & NETIF_FLAG_UP) + && self->netif.ip_addr.addr != 0 + ); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected); + +STATIC mp_obj_t wiznet5k_active(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_bool(self->netif.flags & NETIF_FLAG_UP); + } else { + if (mp_obj_is_true(args[1])) { + if (!(self->netif.flags & NETIF_FLAG_UP)) { + wiznet5k_init(); + netif_set_link_up(&self->netif); + netif_set_up(&self->netif); + } + } else { + if (self->netif.flags & NETIF_FLAG_UP) { + netif_set_down(&self->netif); + netif_set_link_down(&self->netif); + wiznet5k_deinit(); + } + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_active_obj, 1, 2, wiznet5k_active); + +STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + return mod_network_nic_ifconfig(&self->netif, n_args - 1, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig); + +STATIC mp_obj_t wiznet5k_status(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // No arguments: return link status + if (self->netif.flags && wizphy_getphylink() == PHY_LINK_ON) { + if ((self->netif.flags & NETIF_FLAG_UP) && self->netif.ip_addr.addr != 0) { + return MP_OBJ_NEW_SMALL_INT(2); + } else { + return MP_OBJ_NEW_SMALL_INT(1); + } + } else { + return MP_OBJ_NEW_SMALL_INT(0); + } + } + + mp_raise_ValueError("unknown config param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_status_obj, 1, 2, wiznet5k_status); + +STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (kwargs->used == 0) { + // Get config value + if (n_args != 2) { + mp_raise_TypeError("must query one param"); + } + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_mac: { + uint8_t buf[6]; + wiznet5k_get_mac_address(self, buf); + return mp_obj_new_bytes(buf, 6); + } + default: + mp_raise_ValueError("unknown config param"); + } + } else { + // Set config value(s) + if (n_args != 1) { + mp_raise_TypeError("can't specify pos and kw args"); + } + mp_raise_ValueError("unknown config param"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_config_obj, 1, wiznet5k_config); + +STATIC mp_obj_t send_ethernet_wrapper(mp_obj_t self_in, mp_obj_t buf_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf; + mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ); + wiznet5k_send_ethernet(self, buf.len, buf.buf); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(send_ethernet_obj, send_ethernet_wrapper); + +STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wiznet5k_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wiznet5k_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wiznet5k_config_obj) }, + + { MP_ROM_QSTR(MP_QSTR_send_ethernet), MP_ROM_PTR(&send_ethernet_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table); + +const mp_obj_type_t mod_network_nic_type_wiznet5k = { + { &mp_type_type }, + .name = MP_QSTR_WIZNET5K, + .make_new = wiznet5k_make_new, + .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict, +}; + +#endif // MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP diff --git a/src/openmv/src/micropython/ports/stm32/pendsv.c b/src/openmv/src/micropython/ports/stm32/pendsv.c new file mode 100755 index 0000000..b5fe42f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pendsv.c @@ -0,0 +1,151 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "lib/utils/interrupt_char.h" +#include "pendsv.h" +#include "irq.h" + +// This variable is used to save the exception object between a ctrl-C and the +// PENDSV call that actually raises the exception. It must be non-static +// otherwise gcc-5 optimises it away. It can point to the heap but is not +// traced by GC. This is okay because we only ever set it to +// mp_kbd_exception which is in the root-pointer set. +void *pendsv_object; + +void pendsv_init(void) { + // set PendSV interrupt at lowest priority + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); +} + +// Call this function to raise a pending exception during an interrupt. +// It will first try to raise the exception "softly" by setting the +// mp_pending_exception variable and hoping that the VM will notice it. +// If this function is called a second time (ie with the mp_pending_exception +// variable already set) then it will force the exception by using the hardware +// PENDSV feature. This will wait until all interrupts are finished then raise +// the given exception object using nlr_jump in the context of the top-level +// thread. +void pendsv_kbd_intr(void) { + if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_NULL) { + mp_keyboard_interrupt(); + } else { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + pendsv_object = &MP_STATE_VM(mp_kbd_exception); + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } +} + +void pendsv_isr_handler(void) { + // re-jig the stack so that when we return from this interrupt handler + // it returns instead to nlr_jump with argument pendsv_object + // note that stack has a different layout if DEBUG is enabled + // + // on entry to this (naked) function, stack has the following layout: + // + // stack layout with DEBUG disabled: + // sp[6]: pc=r15 + // sp[5]: lr=r14 + // sp[4]: r12 + // sp[3]: r3 + // sp[2]: r2 + // sp[1]: r1 + // sp[0]: r0 + // + // stack layout with DEBUG enabled: + // sp[8]: pc=r15 + // sp[7]: lr=r14 + // sp[6]: r12 + // sp[5]: r3 + // sp[4]: r2 + // sp[3]: r1 + // sp[2]: r0 + // sp[1]: 0xfffffff9 + // sp[0]: ? + +#if MICROPY_PY_THREAD + __asm volatile ( + "ldr r1, pendsv_object_ptr\n" + "ldr r0, [r1]\n" + "cmp r0, 0\n" + "beq .no_obj\n" + "str r0, [sp, #0]\n" // store to r0 on stack + "mov r0, #0\n" + "str r0, [r1]\n" // clear pendsv_object + "ldr r0, nlr_jump_ptr\n" + "str r0, [sp, #24]\n" // store to pc on stack + "bx lr\n" // return from interrupt; will return to nlr_jump + + ".no_obj:\n" // pendsv_object==NULL + "push {r4-r11, lr}\n" + "vpush {s16-s31}\n" + "mrs r5, primask\n" // save PRIMASK in r5 + "cpsid i\n" // disable interrupts while we change stacks + "mov r0, sp\n" // pass sp to save + "mov r4, lr\n" // save lr because we are making a call + "bl pyb_thread_next\n" // get next thread to execute + "mov lr, r4\n" // restore lr + "mov sp, r0\n" // switch stacks + "msr primask, r5\n" // reenable interrupts + "vpop {s16-s31}\n" + "pop {r4-r11, lr}\n" + "bx lr\n" // return from interrupt; will return to new thread + ".align 2\n" + "pendsv_object_ptr: .word pendsv_object\n" + "nlr_jump_ptr: .word nlr_jump\n" + ); +#else + __asm volatile ( + "ldr r0, pendsv_object_ptr\n" + "ldr r0, [r0]\n" +#if defined(PENDSV_DEBUG) + "str r0, [sp, #8]\n" +#else + "str r0, [sp, #0]\n" +#endif + "ldr r0, nlr_jump_ptr\n" +#if defined(PENDSV_DEBUG) + "str r0, [sp, #32]\n" +#else + "str r0, [sp, #24]\n" +#endif + "bx lr\n" + ".align 2\n" + "pendsv_object_ptr: .word pendsv_object\n" + "nlr_jump_ptr: .word nlr_jump\n" + ); +#endif + + /* + uint32_t x[2] = {0x424242, 0xdeaddead}; + printf("PendSV: %p\n", x); + for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) { + printf(" %p: %08x %08x %08x %08x\n", p, (uint)p[0], (uint)p[1], (uint)p[2], (uint)p[3]); + } + */ +} diff --git a/src/openmv/src/micropython/ports/stm32/pendsv.h b/src/openmv/src/micropython/ports/stm32/pendsv.h new file mode 100755 index 0000000..0d9fde6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pendsv.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_PENDSV_H +#define MICROPY_INCLUDED_STM32_PENDSV_H + +void pendsv_init(void); +void pendsv_kbd_intr(void); + +// since we play tricks with the stack, the compiler must not generate a +// prelude for this function +void pendsv_isr_handler(void) __attribute__((naked)); + +#endif // MICROPY_INCLUDED_STM32_PENDSV_H diff --git a/src/openmv/src/micropython/ports/stm32/pin.c b/src/openmv/src/micropython/ports/stm32/pin.c new file mode 100755 index 0000000..58c01e2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin.c @@ -0,0 +1,674 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/virtpin.h" +#include "pin.h" +#include "extint.h" + +/// \moduleref pyb +/// \class Pin - control I/O pins +/// +/// A pin is the basic object to control I/O pins. It has methods to set +/// the mode of the pin (input, output, etc) and methods to get and set the +/// digital logic level. For analog control of a pin, see the ADC class. +/// +/// Usage Model: +/// +/// All Board Pins are predefined as pyb.Pin.board.Name +/// +/// x1_pin = pyb.Pin.board.X1 +/// +/// g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN) +/// +/// CPU pins which correspond to the board pins are available +/// as `pyb.cpu.Name`. For the CPU pins, the names are the port letter +/// followed by the pin number. On the PYBv1.0, `pyb.Pin.board.X1` and +/// `pyb.Pin.cpu.B6` are the same pin. +/// +/// You can also use strings: +/// +/// g = pyb.Pin('X1', pyb.Pin.OUT_PP) +/// +/// Users can add their own names: +/// +/// MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 } +/// pyb.Pin.dict(MyMapperDict) +/// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD) +/// +/// and can query mappings +/// +/// pin = pyb.Pin("LeftMotorDir") +/// +/// Users can also add their own mapping function: +/// +/// def MyMapper(pin_name): +/// if pin_name == "LeftMotorDir": +/// return pyb.Pin.cpu.A0 +/// +/// pyb.Pin.mapper(MyMapper) +/// +/// So, if you were to call: `pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)` +/// then `"LeftMotorDir"` is passed directly to the mapper function. +/// +/// To summarise, the following order determines how things get mapped into +/// an ordinal pin number: +/// +/// 1. Directly specify a pin object +/// 2. User supplied mapping function +/// 3. User supplied mapping (object must be usable as a dictionary key) +/// 4. Supply a string which matches a board pin +/// 5. Supply a string which matches a CPU port/pin +/// +/// You can set `pyb.Pin.debug(True)` to get some debug information about +/// how a particular object gets mapped to a pin. + +// Pin class variables +STATIC bool pin_class_debug; + +void pin_init0(void) { + MP_STATE_PORT(pin_class_mapper) = mp_const_none; + MP_STATE_PORT(pin_class_map_dict) = mp_const_none; + pin_class_debug = false; +} + +// C API used to convert a user-supplied pin name into an ordinal pin number. +const pin_obj_t *pin_find(mp_obj_t user_obj) { + const pin_obj_t *pin_obj; + + // If a pin was provided, then use it + if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) { + pin_obj = MP_OBJ_TO_PTR(user_obj); + if (pin_class_debug) { + printf("Pin map passed pin "); + mp_obj_print(MP_OBJ_FROM_PTR(pin_obj), PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + if (MP_STATE_PORT(pin_class_mapper) != mp_const_none) { + mp_obj_t o = mp_call_function_1(MP_STATE_PORT(pin_class_mapper), user_obj); + if (o != mp_const_none) { + if (!MP_OBJ_IS_TYPE(o, &pin_type)) { + mp_raise_ValueError("Pin.mapper didn't return a Pin object"); + } + if (pin_class_debug) { + printf("Pin.mapper maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print(o, PRINT_STR); + printf("\n"); + } + return MP_OBJ_TO_PTR(o); + } + // The pin mapping function returned mp_const_none, fall through to + // other lookup methods. + } + + if (MP_STATE_PORT(pin_class_map_dict) != mp_const_none) { + mp_map_t *pin_map_map = mp_obj_dict_get_map(MP_STATE_PORT(pin_class_map_dict)); + mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP); + if (elem != NULL && elem->value != MP_OBJ_NULL) { + mp_obj_t o = elem->value; + if (pin_class_debug) { + printf("Pin.map_dict maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print(o, PRINT_STR); + printf("\n"); + } + return MP_OBJ_TO_PTR(o); + } + } + + // See if the pin name matches a board pin + pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.board maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print(MP_OBJ_FROM_PTR(pin_obj), PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + // See if the pin name matches a cpu pin + pin_obj = pin_find_named_pin(&pin_cpu_pins_locals_dict, user_obj); + if (pin_obj) { + if (pin_class_debug) { + printf("Pin.cpu maps "); + mp_obj_print(user_obj, PRINT_REPR); + printf(" to "); + mp_obj_print(MP_OBJ_FROM_PTR(pin_obj), PRINT_STR); + printf("\n"); + } + return pin_obj; + } + + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%s) doesn't exist", mp_obj_str_get_str(user_obj))); +} + +/// \method __str__() +/// Return a string describing the pin object. +STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // pin name + mp_printf(print, "Pin(Pin.cpu.%q, mode=Pin.", self->name); + + uint32_t mode = pin_get_mode(self); + + if (mode == GPIO_MODE_ANALOG) { + // analog + mp_print_str(print, "ANALOG)"); + + } else { + // IO mode + bool af = false; + qstr mode_qst; + if (mode == GPIO_MODE_INPUT) { + mode_qst = MP_QSTR_IN; + } else if (mode == GPIO_MODE_OUTPUT_PP) { + mode_qst = MP_QSTR_OUT; + } else if (mode == GPIO_MODE_OUTPUT_OD) { + mode_qst = MP_QSTR_OPEN_DRAIN; + } else { + af = true; + if (mode == GPIO_MODE_AF_PP) { + mode_qst = MP_QSTR_ALT; + } else { + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; + } + } + mp_print_str(print, qstr_str(mode_qst)); + + // pull mode + qstr pull_qst = MP_QSTR_NULL; + uint32_t pull = pin_get_pull(self); + if (pull == GPIO_PULLUP) { + pull_qst = MP_QSTR_PULL_UP; + } else if (pull == GPIO_PULLDOWN) { + pull_qst = MP_QSTR_PULL_DOWN; + } + if (pull_qst != MP_QSTR_NULL) { + mp_printf(print, ", pull=Pin.%q", pull_qst); + } + + // AF mode + if (af) { + mp_uint_t af_idx = pin_get_af(self); + const pin_af_obj_t *af_obj = pin_find_af_by_index(self, af_idx); + if (af_obj == NULL) { + mp_printf(print, ", af=%d)", af_idx); + } else { + mp_printf(print, ", af=Pin.%q)", af_obj->name); + } + } else { + mp_print_str(print, ")"); + } + } +} + +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args); + +/// \classmethod \constructor(id, ...) +/// Create a new Pin object associated with the id. If additional arguments are given, +/// they are used to initialise the pin. See `init`. +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + const pin_obj_t *pin = pin_find(args[0]); + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(pin); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self)); + } else { + // set pin + mp_hal_pin_write(self, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +/// \classmethod mapper([fun]) +/// Get or set the pin mapper function. +STATIC mp_obj_t pin_mapper(size_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_mapper) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_mapper); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, MP_ROM_PTR(&pin_mapper_fun_obj)); + +/// \classmethod dict([dict]) +/// Get or set the pin mapper dictionary. +STATIC mp_obj_t pin_map_dict(size_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + MP_STATE_PORT(pin_class_map_dict) = args[1]; + return mp_const_none; + } + return MP_STATE_PORT(pin_class_map_dict); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, MP_ROM_PTR(&pin_map_dict_fun_obj)); + +/// \classmethod af_list() +/// Returns an array of alternate functions available for this pin. +STATIC mp_obj_t pin_af_list(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t result = mp_obj_new_list(0, NULL); + + const pin_af_obj_t *af = self->af; + for (mp_uint_t i = 0; i < self->num_af; i++, af++) { + mp_obj_list_append(result, MP_OBJ_FROM_PTR(af)); + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_list_obj, pin_af_list); + +/// \classmethod debug([state]) +/// Get or set the debugging state (`True` or `False` for on or off). +STATIC mp_obj_t pin_debug(size_t n_args, const mp_obj_t *args) { + if (n_args > 1) { + pin_class_debug = mp_obj_is_true(args[1]); + return mp_const_none; + } + return mp_obj_new_bool(pin_class_debug); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, MP_ROM_PTR(&pin_debug_fun_obj)); + +// init(mode, pull=None, af=-1, *, value, alt) +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)}}, + { MP_QSTR_af, MP_ARG_INT, {.u_int = -1}}, // legacy + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + { MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get io mode + uint mode = args[0].u_int; + if (!IS_GPIO_MODE(mode)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode)); + } + + // get pull mode + uint pull = GPIO_NOPULL; + if (args[1].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[1].u_obj); + } + if (!IS_GPIO_PULL(pull)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin pull: %d", pull)); + } + + // get af (alternate function); alt-arg overrides af-arg + mp_int_t af = args[4].u_int; + if (af == -1) { + af = args[2].u_int; + } + if ((mode == GPIO_MODE_AF_PP || mode == GPIO_MODE_AF_OD) && !IS_GPIO_AF(af)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin af: %d", af)); + } + + // enable the peripheral clock for the port of this pin + mp_hal_gpio_clock_enable(self->gpio); + + // if given, set the pin value before initialising to prevent glitches + if (args[3].u_obj != MP_OBJ_NULL) { + mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj)); + } + + // configure the GPIO as requested + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = self->pin_mask; + GPIO_InitStructure.Mode = mode; + GPIO_InitStructure.Pull = pull; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStructure.Alternate = af; + HAL_GPIO_Init(self->gpio, &GPIO_InitStructure); + + return mp_const_none; +} + +STATIC mp_obj_t pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); + +/// \method value([value]) +/// Get or set the digital logic level of the pin: +/// +/// - With no argument, return 0 or 1 depending on the logic level of the pin. +/// - With `value` given, set the logic level of the pin. `value` can be +/// anything that converts to a boolean. If it converts to `True`, the pin +/// is set high, otherwise it is set low. +STATIC mp_obj_t pin_value(size_t n_args, const mp_obj_t *args) { + return pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); + +STATIC mp_obj_t pin_off(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_pin_low(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_off_obj, pin_off); + +STATIC mp_obj_t pin_on(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_hal_pin_high(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False) +STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_hard }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_MODE_IT_RISING | GPIO_MODE_IT_FALLING} }, + { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, + }; + pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (n_args > 1 || kw_args->used != 0) { + // configure irq + extint_register_pin(self, args[ARG_trigger].u_int, + args[ARG_hard].u_bool, args[ARG_handler].u_obj); + } + + // TODO should return an IRQ object + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); + +/// \method name() +/// Get the pin name. +STATIC mp_obj_t pin_name(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_QSTR(self->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name); + +/// \method names() +/// Returns the cpu and board names for this pin. +STATIC mp_obj_t pin_names(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t result = mp_obj_new_list(0, NULL); + mp_obj_list_append(result, MP_OBJ_NEW_QSTR(self->name)); + + const mp_map_t *map = &pin_board_pins_locals_dict.map; + mp_map_elem_t *elem = map->table; + + for (mp_uint_t i = 0; i < map->used; i++, elem++) { + if (elem->value == self_in) { + mp_obj_list_append(result, elem->key); + } + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_names_obj, pin_names); + +/// \method port() +/// Get the pin port. +STATIC mp_obj_t pin_port(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->port); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port); + +/// \method pin() +/// Get the pin number. +STATIC mp_obj_t pin_pin(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->pin); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pin_obj, pin_pin); + +/// \method gpio() +/// Returns the base address of the GPIO block associated with this pin. +STATIC mp_obj_t pin_gpio(mp_obj_t self_in) { + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((intptr_t)self->gpio); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_gpio_obj, pin_gpio); + +/// \method mode() +/// Returns the currently configured mode of the pin. The integer returned +/// will match one of the allowed constants for the mode argument to the init +/// function. +STATIC mp_obj_t pin_mode(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(pin_get_mode(MP_OBJ_TO_PTR(self_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_mode_obj, pin_mode); + +/// \method pull() +/// Returns the currently configured pull of the pin. The integer returned +/// will match one of the allowed constants for the pull argument to the init +/// function. +STATIC mp_obj_t pin_pull(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(pin_get_pull(MP_OBJ_TO_PTR(self_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pull_obj, pin_pull); + +/// \method af() +/// Returns the currently configured alternate-function of the pin. The +/// integer returned will match one of the allowed constants for the af +/// argument to the init function. +STATIC mp_obj_t pin_af(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(pin_get_af(MP_OBJ_TO_PTR(self_in))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af); + +STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pin_irq_obj) }, + + // Legacy names as used by pyb.Pin + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_names), MP_ROM_PTR(&pin_names_obj) }, + { MP_ROM_QSTR(MP_QSTR_af_list), MP_ROM_PTR(&pin_af_list_obj) }, + { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&pin_port_obj) }, + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&pin_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_gpio), MP_ROM_PTR(&pin_gpio_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&pin_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&pin_pull_obj) }, + { MP_ROM_QSTR(MP_QSTR_af), MP_ROM_PTR(&pin_af_obj) }, + + // class methods + { MP_ROM_QSTR(MP_QSTR_mapper), MP_ROM_PTR(&pin_mapper_obj) }, + { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&pin_map_dict_obj) }, + { MP_ROM_QSTR(MP_QSTR_debug), MP_ROM_PTR(&pin_debug_obj) }, + + // class attributes + { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, + { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_ALT_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_ANALOG), MP_ROM_INT(GPIO_MODE_ANALOG) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_MODE_IT_RISING) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_MODE_IT_FALLING) }, + + // legacy class constants + { MP_ROM_QSTR(MP_QSTR_OUT_PP), MP_ROM_INT(GPIO_MODE_OUTPUT_PP) }, + { MP_ROM_QSTR(MP_QSTR_OUT_OD), MP_ROM_INT(GPIO_MODE_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP), MP_ROM_INT(GPIO_MODE_AF_PP) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) }, + +#include "genhdr/pins_af_const.h" +}; + +STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + + switch (request) { + case MP_PIN_READ: { + return mp_hal_pin_read(self); + } + case MP_PIN_WRITE: { + mp_hal_pin_write(self, arg); + return 0; + } + } + return -1; +} + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pin_print, + .make_new = mp_pin_make_new, + .call = pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_dict_t*)&pin_locals_dict, +}; + +/// \moduleref pyb +/// \class PinAF - Pin Alternate Functions +/// +/// A Pin represents a physical pin on the microcprocessor. Each pin +/// can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF +/// object represents a particular function for a pin. +/// +/// Usage Model: +/// +/// x3 = pyb.Pin.board.X3 +/// x3_af = x3.af_list() +/// +/// x3_af will now contain an array of PinAF objects which are availble on +/// pin X3. +/// +/// For the pyboard, x3_af would contain: +/// [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2] +/// +/// Normally, each peripheral would configure the af automatically, but sometimes +/// the same function is available on multiple pins, and having more control +/// is desired. +/// +/// To configure X3 to expose TIM2_CH3, you could use: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2) +/// or: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1) + +/// \method __str__() +/// Return a string describing the alternate function. +STATIC void pin_af_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pin_af_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "Pin.%q", self->name); +} + +/// \method index() +/// Return the alternate function index. +STATIC mp_obj_t pin_af_index(mp_obj_t self_in) { + pin_af_obj_t *af = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(af->idx); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_index_obj, pin_af_index); + +/// \method name() +/// Return the name of the alternate function. +STATIC mp_obj_t pin_af_name(mp_obj_t self_in) { + pin_af_obj_t *af = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_QSTR(af->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_name_obj, pin_af_name); + +/// \method reg() +/// Return the base register associated with the peripheral assigned to this +/// alternate function. For example, if the alternate function were TIM2_CH3 +/// this would return stm.TIM2 +STATIC mp_obj_t pin_af_reg(mp_obj_t self_in) { + pin_af_obj_t *af = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((uintptr_t)af->reg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_reg_obj, pin_af_reg); + +STATIC const mp_rom_map_elem_t pin_af_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&pin_af_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&pin_af_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pin_af_reg_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pin_af_locals_dict, pin_af_locals_dict_table); + +const mp_obj_type_t pin_af_type = { + { &mp_type_type }, + .name = MP_QSTR_PinAF, + .print = pin_af_obj_print, + .locals_dict = (mp_obj_dict_t*)&pin_af_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/pin.h b/src/openmv/src/micropython/ports/stm32/pin.h new file mode 100755 index 0000000..ea57b0a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin.h @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_PIN_H +#define MICROPY_INCLUDED_STM32_PIN_H + +// This file requires pin_defs_xxx.h (which has port specific enums and +// defines, so we include it here. It should never be included directly + +#include MICROPY_PIN_DEFS_PORT_H +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + qstr name; + uint8_t idx; + uint8_t fn; + uint8_t unit; + uint8_t type; + void *reg; // The peripheral associated with this AF +} pin_af_obj_t; + +typedef struct { + mp_obj_base_t base; + qstr name; + uint32_t port : 4; + uint32_t pin : 5; // Some ARM processors use 32 bits/PORT + uint32_t num_af : 4; + uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT + uint32_t adc_num : 3; // 1 bit per ADC + uint32_t pin_mask; + pin_gpio_t *gpio; + const pin_af_obj_t *af; +} pin_obj_t; + +extern const mp_obj_type_t pin_type; +extern const mp_obj_type_t pin_af_type; + +// Include all of the individual pin objects +#include "genhdr/pins.h" + +typedef struct { + const char *name; + const pin_obj_t *pin; +} pin_named_pin_t; + +extern const pin_named_pin_t pin_board_pins[]; +extern const pin_named_pin_t pin_cpu_pins[]; + +//extern pin_map_obj_t pin_map_obj; + +typedef struct { + mp_obj_base_t base; + qstr name; + const pin_named_pin_t *named_pins; +} pin_named_pins_obj_t; + +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_type_t pin_cpu_pins_obj_type; + +extern const mp_obj_dict_t pin_cpu_pins_locals_dict; +extern const mp_obj_dict_t pin_board_pins_locals_dict; + +MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj); + +void pin_init0(void); +uint32_t pin_get_mode(const pin_obj_t *pin); +uint32_t pin_get_pull(const pin_obj_t *pin); +uint32_t pin_get_af(const pin_obj_t *pin); +const pin_obj_t *pin_find(mp_obj_t user_obj); +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); +const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); + +#endif // MICROPY_INCLUDED_STM32_PIN_H diff --git a/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.c b/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.c new file mode 100755 index 0000000..0aef5f9 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.c @@ -0,0 +1,31 @@ +#include "py/obj.h" +#include "pin.h" + +// Returns the pin mode. This value returned by this macro should be one of: +// GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP, GPIO_MODE_OUTPUT_OD, +// GPIO_MODE_AF_PP, GPIO_MODE_AF_OD, or GPIO_MODE_ANALOG. + +uint32_t pin_get_mode(const pin_obj_t *pin) { + GPIO_TypeDef *gpio = pin->gpio; + uint32_t mode = (gpio->MODER >> (pin->pin * 2)) & 3; + if (mode != GPIO_MODE_ANALOG) { + if (gpio->OTYPER & pin->pin_mask) { + mode |= 1 << 4; + } + } + return mode; +} + +// Returns the pin pullup/pulldown. The value returned by this macro should +// be one of GPIO_NOPULL, GPIO_PULLUP, or GPIO_PULLDOWN. + +uint32_t pin_get_pull(const pin_obj_t *pin) { + return (pin->gpio->PUPDR >> (pin->pin * 2)) & 3; +} + +// Returns the af (alternate function) index currently set for a pin. + +uint32_t pin_get_af(const pin_obj_t *pin) { + return (pin->gpio->AFR[pin->pin >> 3] >> ((pin->pin & 7) * 4)) & 0xf; +} + diff --git a/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.h b/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.h new file mode 100755 index 0000000..89b659d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin_defs_stm32.h @@ -0,0 +1,124 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This file contains pin definitions that are specific to the stm32 port. +// This file should only ever be #included by pin.h and not directly. + +enum { + PORT_A, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + PORT_F, + PORT_G, + PORT_H, + PORT_I, + PORT_J, + PORT_K, +}; + +// Must have matching entries in SUPPORTED_FN in boards/make-pins.py +enum { + AF_FN_TIM, + AF_FN_I2C, + AF_FN_USART, + AF_FN_UART = AF_FN_USART, + AF_FN_SPI, + AF_FN_I2S, + AF_FN_SDMMC, + AF_FN_CAN, +}; + +enum { + AF_PIN_TYPE_TIM_CH1 = 0, + AF_PIN_TYPE_TIM_CH2, + AF_PIN_TYPE_TIM_CH3, + AF_PIN_TYPE_TIM_CH4, + AF_PIN_TYPE_TIM_CH1N, + AF_PIN_TYPE_TIM_CH2N, + AF_PIN_TYPE_TIM_CH3N, + AF_PIN_TYPE_TIM_CH1_ETR, + AF_PIN_TYPE_TIM_ETR, + AF_PIN_TYPE_TIM_BKIN, + + AF_PIN_TYPE_I2C_SDA = 0, + AF_PIN_TYPE_I2C_SCL, + + AF_PIN_TYPE_USART_TX = 0, + AF_PIN_TYPE_USART_RX, + AF_PIN_TYPE_USART_CTS, + AF_PIN_TYPE_USART_RTS, + AF_PIN_TYPE_USART_CK, + AF_PIN_TYPE_UART_TX = AF_PIN_TYPE_USART_TX, + AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX, + AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS, + AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS, + + AF_PIN_TYPE_SPI_MOSI = 0, + AF_PIN_TYPE_SPI_MISO, + AF_PIN_TYPE_SPI_SCK, + AF_PIN_TYPE_SPI_NSS, + + AF_PIN_TYPE_I2S_CK = 0, + AF_PIN_TYPE_I2S_MCK, + AF_PIN_TYPE_I2S_SD, + AF_PIN_TYPE_I2S_WS, + AF_PIN_TYPE_I2S_EXTSD, + + AF_PIN_TYPE_SDMMC_CK = 0, + AF_PIN_TYPE_SDMMC_CMD, + AF_PIN_TYPE_SDMMC_D0, + AF_PIN_TYPE_SDMMC_D1, + AF_PIN_TYPE_SDMMC_D2, + AF_PIN_TYPE_SDMMC_D3, + + AF_PIN_TYPE_CAN_TX = 0, + AF_PIN_TYPE_CAN_RX, +}; + +// The HAL uses a slightly different naming than we chose, so we provide +// some #defines to massage things. Also I2S and SPI share the same +// peripheral. + +#define GPIO_AF5_I2S2 GPIO_AF5_SPI2 +#define GPIO_AF5_I2S3 GPIO_AF5_I2S3ext +#define GPIO_AF6_I2S2 GPIO_AF6_I2S2ext +#define GPIO_AF6_I2S3 GPIO_AF6_SPI3 +#define GPIO_AF7_I2S2 GPIO_AF7_SPI2 +#define GPIO_AF7_I2S3 GPIO_AF7_I2S3ext + +#define I2S2 SPI2 +#define I2S3 SPI3 + +enum { + PIN_ADC1 = (1 << 0), + PIN_ADC2 = (1 << 1), + PIN_ADC3 = (1 << 2), +}; + +typedef GPIO_TypeDef pin_gpio_t; + diff --git a/src/openmv/src/micropython/ports/stm32/pin_named_pins.c b/src/openmv/src/micropython/ports/stm32/pin_named_pins.c new file mode 100755 index 0000000..1c7e643 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin_named_pins.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" + +const mp_obj_type_t pin_cpu_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_cpu, + .locals_dict = (mp_obj_dict_t*)&pin_cpu_pins_locals_dict, +}; + +const mp_obj_type_t pin_board_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_board, + .locals_dict = (mp_obj_dict_t*)&pin_board_pins_locals_dict, +}; + +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { + const mp_map_t *named_map = &named_pins->map; + mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t*)named_map, name, MP_MAP_LOOKUP); + if (named_elem != NULL && named_elem->value != MP_OBJ_NULL) { + return MP_OBJ_TO_PTR(named_elem->value); + } + return NULL; +} + +const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (af->fn == fn && af->unit == unit) { + return af; + } + } + return NULL; +} + +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (af->idx == af_idx) { + return af; + } + } + return NULL; +} + +/* unused +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (strcmp(name, qstr_str(af->name)) == 0) { + return af; + } + } + return NULL; +} +*/ diff --git a/src/openmv/src/micropython/ports/stm32/pin_static_af.h b/src/openmv/src/micropython/ports/stm32/pin_static_af.h new file mode 100755 index 0000000..b73944d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pin_static_af.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_PIN_STATIC_AF_H +#define MICROPY_INCLUDED_STM32_PIN_STATIC_AF_H + +#include "py/mphal.h" +#include "genhdr/pins.h" +#include "genhdr/pins_af_defs.h" + +#if 0 // Enable to test if AF's are statically compiled +#define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn_type) \ + mp_hal_pin_config(pin_obj, mode, pull, fn_type(pin_obj)); \ + _Static_assert(fn_type(pin_obj) != -1, ""); \ + _Static_assert(__builtin_constant_p(fn_type(pin_obj)) == 1, "") + +#else + +#define mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn_type) \ + mp_hal_pin_config(pin_obj, mode, pull, fn_type(pin_obj)) /* Overflow Error => alt func not found */ + +#endif + +#endif // MICROPY_INCLUDED_STM32_PIN_STATIC_AF_H diff --git a/src/openmv/src/micropython/ports/stm32/portmodules.h b/src/openmv/src/micropython/ports/stm32/portmodules.h new file mode 100755 index 0000000..81cb7fd --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/portmodules.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_PORTMODULES_H +#define MICROPY_INCLUDED_STM32_PORTMODULES_H + +extern const mp_obj_module_t pyb_module; +extern const mp_obj_module_t stm_module; +extern const mp_obj_module_t mp_module_uos; +extern const mp_obj_module_t mp_module_utime; +extern const mp_obj_module_t mp_module_usocket; + +// additional helper functions exported by the modules + +MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj); + +MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj); + +#endif // MICROPY_INCLUDED_STM32_PORTMODULES_H diff --git a/src/openmv/src/micropython/ports/stm32/powerctrl.c b/src/openmv/src/micropython/ports/stm32/powerctrl.c new file mode 100755 index 0000000..4199cf6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/powerctrl.c @@ -0,0 +1,259 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "powerctrl.h" +#include "genhdr/pllfreqtable.h" + +#if !defined(STM32F0) + +// Assumes that PLL is used as the SYSCLK source +int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) { + uint32_t flash_latency; + + #if defined(STM32F7) + + if (need_pllsai) { + // Configure PLLSAI at 48MHz for those peripherals that need this freq + const uint32_t pllsain = 192; + const uint32_t pllsaip = 4; + const uint32_t pllsaiq = 2; + RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos + | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos + | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos; + RCC->CR |= RCC_CR_PLLSAION; + uint32_t ticks = mp_hal_ticks_ms(); + while (!(RCC->CR & RCC_CR_PLLSAIRDY)) { + if (mp_hal_ticks_ms() - ticks > 200) { + return -MP_ETIMEDOUT; + } + } + RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; + } else { + RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL; + } + + // If possible, scale down the internal voltage regulator to save power + uint32_t volt_scale; + if (sysclk_mhz <= 151) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + } else if (sysclk_mhz <= 180) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2; + } else { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + } + if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) { + return -MP_EIO; + } + + // These flash_latency values assume a supply voltage between 2.7V and 3.6V + if (sysclk_mhz <= 30) { + flash_latency = FLASH_LATENCY_0; + } else if (sysclk_mhz <= 60) { + flash_latency = FLASH_LATENCY_1; + } else if (sysclk_mhz <= 90) { + flash_latency = FLASH_LATENCY_2; + } else if (sysclk_mhz <= 120) { + flash_latency = FLASH_LATENCY_3; + } else if (sysclk_mhz <= 150) { + flash_latency = FLASH_LATENCY_4; + } else if (sysclk_mhz <= 180) { + flash_latency = FLASH_LATENCY_5; + } else if (sysclk_mhz <= 210) { + flash_latency = FLASH_LATENCY_6; + } else { + flash_latency = FLASH_LATENCY_7; + } + + #elif defined(MICROPY_HW_FLASH_LATENCY) + flash_latency = MICROPY_HW_FLASH_LATENCY; + #else + flash_latency = FLASH_LATENCY_5; + #endif + + rcc_init->SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + if (HAL_RCC_ClockConfig(rcc_init, flash_latency) != HAL_OK) { + return -MP_EIO; + } + + return 0; +} + +#endif + +#if !(defined(STM32F0) || defined(STM32L4)) + +STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { + if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } + else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; } + else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; } + else if (wanted_div <= 8) { return RCC_SYSCLK_DIV8; } + else if (wanted_div <= 16) { return RCC_SYSCLK_DIV16; } + else if (wanted_div <= 64) { return RCC_SYSCLK_DIV64; } + else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; } + else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; } + else { return RCC_SYSCLK_DIV512; } +} + +STATIC uint32_t calc_apb_div(uint32_t wanted_div) { + if (wanted_div <= 1) { return RCC_HCLK_DIV1; } + else if (wanted_div <= 2) { return RCC_HCLK_DIV2; } + else if (wanted_div <= 4) { return RCC_HCLK_DIV4; } + else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } + else { return RCC_SYSCLK_DIV16; } +} + +int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2) { + // Return straightaway if the clocks are already at the desired frequency + if (sysclk == HAL_RCC_GetSysClockFreq() + && ahb == HAL_RCC_GetHCLKFreq() + && apb1 == HAL_RCC_GetPCLK1Freq() + && apb2 == HAL_RCC_GetPCLK2Freq()) { + return 0; + } + + // Default PLL parameters that give 48MHz on PLL48CK + uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7; + uint32_t sysclk_source; + bool need_pllsai = false; + + // Search for a valid PLL configuration that keeps USB at 48MHz + uint32_t sysclk_mhz = sysclk / 1000000; + for (const uint16_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) { + uint32_t sys = *pll & 0xff; + if (sys <= sysclk_mhz) { + m = (*pll >> 10) & 0x3f; + p = ((*pll >> 7) & 0x6) + 2; + if (m == 0) { + // special entry for using HSI directly + sysclk_source = RCC_SYSCLKSOURCE_HSI; + } else if (m == 1) { + // special entry for using HSE directly + sysclk_source = RCC_SYSCLKSOURCE_HSE; + } else { + // use PLL + sysclk_source = RCC_SYSCLKSOURCE_PLLCLK; + uint32_t vco_out = sys * p; + n = vco_out * m / (HSE_VALUE / 1000000); + q = vco_out / 48; + #if defined(STM32F7) + need_pllsai = vco_out % 48 != 0; + #endif + } + goto set_clk; + } + } + return -MP_EINVAL; + +set_clk: + // Let the USB CDC have a chance to process before we change the clock + mp_hal_delay_ms(5); + + // Desired system clock source is in sysclk_source + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { + // Set HSE as system clock source to allow modification of the PLL configuration + // We then change to PLL after re-configuring PLL + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; + } else { + // Directly set the system clock source as desired + RCC_ClkInitStruct.SYSCLKSource = sysclk_source; + } + + // Determine the bus clock dividers + // Note: AHB freq required to be >= 14.2MHz for USB operation + RCC_ClkInitStruct.AHBCLKDivider = calc_ahb_div(sysclk / ahb); + #if !defined(STM32H7) + ahb = sysclk >> AHBPrescTable[RCC_ClkInitStruct.AHBCLKDivider >> RCC_CFGR_HPRE_Pos]; + #endif + RCC_ClkInitStruct.APB1CLKDivider = calc_apb_div(ahb / apb1); + RCC_ClkInitStruct.APB2CLKDivider = calc_apb_div(ahb / apb2); + + #if MICROPY_HW_CLK_LAST_FREQ + // Save the bus dividers for use later + uint32_t h = RCC_ClkInitStruct.AHBCLKDivider >> 4; + uint32_t b1 = RCC_ClkInitStruct.APB1CLKDivider >> 10; + uint32_t b2 = RCC_ClkInitStruct.APB2CLKDivider >> 10; + #endif + + // Configure clock + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { + return -MP_EIO; + } + + #if defined(STM32F7) + // Turn PLLSAI off because we are changing PLLM (which drives PLLSAI) + RCC->CR &= ~RCC_CR_PLLSAION; + #endif + + // Re-configure PLL + // Even if we don't use the PLL for the system clock, we still need it for USB, RNG and SDIO + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = m; + RCC_OscInitStruct.PLL.PLLN = n; + RCC_OscInitStruct.PLL.PLLP = p; + RCC_OscInitStruct.PLL.PLLQ = q; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + return -MP_EIO; + } + + // Set PLL as system clock source if wanted + if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; + int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai); + if (ret != 0) { + return ret; + } + } + + #if MICROPY_HW_CLK_LAST_FREQ + // Save settings in RTC backup register to reconfigure clocks on hard-reset + #if defined(STM32F7) + #define FREQ_BKP BKP31R + #else + #define FREQ_BKP BKP19R + #endif + // qqqqqqqq pppppppp nnnnnnnn nnmmmmmm + // qqqqQQQQ ppppppPP nNNNNNNN NNMMMMMM + // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM + p = (p / 2) - 1; + RTC->FREQ_BKP = m + | (n << 6) | (p << 16) | (q << 18) + | (h << 22) + | (b1 << 26) + | (b2 << 29); + #endif + + return 0; +} + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/powerctrl.h b/src/openmv/src/micropython/ports/stm32/powerctrl.h new file mode 100755 index 0000000..b9de324 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/powerctrl.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_POWERCTRL_H +#define MICROPY_INCLUDED_STM32_POWERCTRL_H + +#include + +int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai); +int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2); + +#endif // MICROPY_INCLUDED_STM32_POWERCTRL_H diff --git a/src/openmv/src/micropython/ports/stm32/pyb_i2c.c b/src/openmv/src/micropython/ports/stm32/pyb_i2c.c new file mode 100755 index 0000000..d6b9ec6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pyb_i2c.c @@ -0,0 +1,1069 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "irq.h" +#include "pin.h" +#include "bufhelper.h" +#include "dma.h" +#include "i2c.h" + +#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C + +/// \moduleref pyb +/// \class I2C - a two-wire serial protocol +/// +/// I2C is a two-wire protocol for communicating between devices. At the physical +/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively. +/// +/// I2C objects are created attached to a specific bus. They can be initialised +/// when created, or initialised later on: +/// +/// from pyb import I2C +/// +/// i2c = I2C(1) # create on bus 1 +/// i2c = I2C(1, I2C.MASTER) # create and init as a master +/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master +/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address +/// i2c.deinit() # turn off the peripheral +/// +/// Printing the i2c object gives you information about its configuration. +/// +/// Basic methods for slave are send and recv: +/// +/// i2c.send('abc') # send 3 bytes +/// i2c.send(0x42) # send a single byte, given by the number +/// data = i2c.recv(3) # receive 3 bytes +/// +/// To receive inplace, first create a bytearray: +/// +/// data = bytearray(3) # create a buffer +/// i2c.recv(data) # receive 3 bytes, writing them into data +/// +/// You can specify a timeout (in ms): +/// +/// i2c.send(b'123', timeout=2000) # timout after 2 seconds +/// +/// A master must specify the recipient's address: +/// +/// i2c.init(I2C.MASTER) +/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42 +/// i2c.send(b'456', addr=0x42) # keyword for address +/// +/// Master also has other methods: +/// +/// i2c.is_ready(0x42) # check if slave 0x42 is ready +/// i2c.scan() # scan for slaves on the bus, returning +/// # a list of valid addresses +/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42, +/// # starting at address 2 in the slave +/// i2c.mem_write('abc', 0x42, 2, timeout=1000) +#define PYB_I2C_MASTER (0) +#define PYB_I2C_SLAVE (1) + +#define PYB_I2C_SPEED_STANDARD (100000L) +#define PYB_I2C_SPEED_FULL (400000L) +#define PYB_I2C_SPEED_FAST (1000000L) + +#if defined(MICROPY_HW_I2C1_SCL) +I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C2_SCL) +I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C3_SCL) +I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C4_SCL) +I2C_HandleTypeDef I2CHandle4 = {.Instance = NULL}; +#endif + +STATIC bool pyb_i2c_use_dma[4]; + +const pyb_i2c_obj_t pyb_i2c_obj[] = { + #if defined(MICROPY_HW_I2C1_SCL) + {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&pyb_i2c_type}, &I2CHandle4, &dma_I2C_4_TX, &dma_I2C_4_RX, &pyb_i2c_use_dma[3]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif +}; + +#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + +// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and +// DutyCycle. + +#if defined(STM32F746xx) + +// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant +// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0x40912732}, \ + {PYB_I2C_SPEED_FULL, 0x10911823}, \ + {PYB_I2C_SPEED_FAST, 0x00611116}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32F722xx) || defined(STM32F723xx) \ + || defined(STM32F732xx) || defined(STM32F733xx) \ + || defined(STM32F765xx) || defined(STM32F767xx) \ + || defined(STM32F769xx) + +// These timing values are for f_I2CCLK=54MHz and are only approximate +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0xb0420f13}, \ + {PYB_I2C_SPEED_FULL, 0x70330309}, \ + {PYB_I2C_SPEED_FAST, 0x50100103}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32H7) + +// I2C TIMINGs obtained from the STHAL examples. +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0x40604E73}, \ + {PYB_I2C_SPEED_FULL, 0x00901954}, \ + {PYB_I2C_SPEED_FAST, 0x10810915}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32L4) + +// The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant +// defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h +#define MICROPY_HW_I2C_BAUDRATE_TIMING {{PYB_I2C_SPEED_STANDARD, 0x90112626}} +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_STANDARD) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_STANDARD) + +#else +#error "no I2C timings for this MCU" +#endif + +STATIC const struct { + uint32_t baudrate; + uint32_t timing; +} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING; + +#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing) + +STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { + for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { + if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) { + init->Timing = pyb_i2c_baudrate_timing[i].timing; + return; + } + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Unsupported I2C baudrate: %u", baudrate)); +} + +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { + if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) { + return pyb_i2c_baudrate_timing[i].baudrate; + } + } + return 0; +} + +#else + +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL) + +STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { + init->ClockSpeed = baudrate; + init->DutyCycle = I2C_DUTYCYCLE_16_9; +} + +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + uint32_t pfreq = i2c->Instance->CR2 & 0x3f; + uint32_t ccr = i2c->Instance->CCR & 0xfff; + if (i2c->Instance->CCR & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + return pfreq * 40000 / ccr; + } else { + // Standard mode + return pfreq * 500000 / ccr; + } +} + +#endif + +void i2c_init0(void) { + // Initialise the I2C handles. + // The structs live on the BSS so all other fields will be zero after a reset. + #if defined(MICROPY_HW_I2C1_SCL) + I2CHandle1.Instance = I2C1; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + I2CHandle2.Instance = I2C2; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + I2CHandle3.Instance = I2C3; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + I2CHandle4.Instance = I2C4; + #endif +} + +void pyb_i2c_init(I2C_HandleTypeDef *i2c) { + int i2c_unit; + const pin_obj_t *scl_pin; + const pin_obj_t *sda_pin; + + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c == &I2CHandle1) { + i2c_unit = 1; + scl_pin = MICROPY_HW_I2C1_SCL; + sda_pin = MICROPY_HW_I2C1_SDA; + __HAL_RCC_I2C1_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c == &I2CHandle2) { + i2c_unit = 2; + scl_pin = MICROPY_HW_I2C2_SCL; + sda_pin = MICROPY_HW_I2C2_SDA; + __HAL_RCC_I2C2_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c == &I2CHandle3) { + i2c_unit = 3; + scl_pin = MICROPY_HW_I2C3_SCL; + sda_pin = MICROPY_HW_I2C3_SDA; + __HAL_RCC_I2C3_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c == &I2CHandle4) { + i2c_unit = 4; + scl_pin = MICROPY_HW_I2C4_SCL; + sda_pin = MICROPY_HW_I2C4_SDA; + __HAL_RCC_I2C4_CLK_ENABLE(); + #endif + } else { + // I2C does not exist for this board (shouldn't get here, should be checked by caller) + return; + } + + // init the GPIO lines + uint32_t mode = MP_HAL_PIN_MODE_ALT_OPEN_DRAIN; + uint32_t pull = MP_HAL_PIN_PULL_NONE; // have external pull-up resistors on both lines + mp_hal_pin_config_alt(scl_pin, mode, pull, AF_FN_I2C, i2c_unit); + mp_hal_pin_config_alt(sda_pin, mode, pull, AF_FN_I2C, i2c_unit); + + // init the I2C device + if (HAL_I2C_Init(i2c) != HAL_OK) { + // init error + // TODO should raise an exception, but this function is not necessarily going to be + // called via Python, so may not be properly wrapped in an NLR handler + printf("OSError: HAL_I2C_Init failed\n"); + return; + } + + // invalidate the DMA channels so they are initialised on first use + const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1]; + dma_invalidate_channel(self->tx_dma_descr); + dma_invalidate_channel(self->rx_dma_descr); + + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c->Instance == I2C1) { + HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C1_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c->Instance == I2C2) { + HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c->Instance == I2C3) { + HAL_NVIC_EnableIRQ(I2C3_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C3_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c->Instance == I2C4) { + HAL_NVIC_EnableIRQ(I2C4_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C4_ER_IRQn); + #endif + } +} + +void i2c_deinit(I2C_HandleTypeDef *i2c) { + HAL_I2C_DeInit(i2c); + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c->Instance == I2C1) { + __HAL_RCC_I2C1_FORCE_RESET(); + __HAL_RCC_I2C1_RELEASE_RESET(); + __HAL_RCC_I2C1_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c->Instance == I2C2) { + __HAL_RCC_I2C2_FORCE_RESET(); + __HAL_RCC_I2C2_RELEASE_RESET(); + __HAL_RCC_I2C2_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c->Instance == I2C3) { + __HAL_RCC_I2C3_FORCE_RESET(); + __HAL_RCC_I2C3_RELEASE_RESET(); + __HAL_RCC_I2C3_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C3_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C3_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c->Instance == I2C4) { + __HAL_RCC_I2C4_FORCE_RESET(); + __HAL_RCC_I2C4_RELEASE_RESET(); + __HAL_RCC_I2C4_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C4_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C4_ER_IRQn); + #endif + } +} + +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { + I2C_InitTypeDef *init = &self->i2c->Init; + + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; + init->DualAddressMode = I2C_DUALADDRESS_DISABLED; + init->GeneralCallMode = I2C_GENERALCALL_DISABLED; + init->NoStretchMode = I2C_NOSTRETCH_DISABLE; + init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + init->OwnAddress2 = 0; // unused + if (freq != -1) { + i2c_set_baudrate(init, MIN(freq, MICROPY_HW_I2C_BAUDRATE_MAX)); + } + + *self->use_dma = false; + + // init the I2C bus + i2c_deinit(self->i2c); + pyb_i2c_init(self->i2c); +} + +STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) { + // wait for bus-busy flag to be cleared, with a timeout + for (int timeout = 50; timeout > 0; --timeout) { + if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) { + // stop bit was generated and bus is back to normal + return; + } + mp_hal_delay_ms(1); + } + // bus was/is busy, need to reset the peripheral to get it to work again + i2c_deinit(i2c); + pyb_i2c_init(i2c); +} + +void i2c_ev_irq_handler(mp_uint_t i2c_id) { + I2C_HandleTypeDef *hi2c; + + switch (i2c_id) { + #if defined(MICROPY_HW_I2C1_SCL) + case 1: + hi2c = &I2CHandle1; + break; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + case 2: + hi2c = &I2CHandle2; + break; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + case 3: + hi2c = &I2CHandle3; + break; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + case 4: + hi2c = &I2CHandle4; + break; + #endif + default: + return; + } + + #if defined(STM32F4) + + if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) { + if (hi2c->XferCount != 0U) { + hi2c->Instance->DR = *hi2c->pBuffPtr++; + hi2c->XferCount--; + } else { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + if (hi2c->XferOptions != I2C_FIRST_FRAME) { + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + } + } + + #else + + // if not an F4 MCU, use the HAL's IRQ handler + HAL_I2C_EV_IRQHandler(hi2c); + + #endif +} + +void i2c_er_irq_handler(mp_uint_t i2c_id) { + I2C_HandleTypeDef *hi2c; + + switch (i2c_id) { + #if defined(MICROPY_HW_I2C1_SCL) + case 1: + hi2c = &I2CHandle1; + break; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + case 2: + hi2c = &I2CHandle2; + break; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + case 3: + hi2c = &I2CHandle3; + break; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + case 4: + hi2c = &I2CHandle4; + break; + #endif + default: + return; + } + + #if defined(STM32F4) + + uint32_t sr1 = hi2c->Instance->SR1; + + // I2C Bus error + if (sr1 & I2C_FLAG_BERR) { + hi2c->ErrorCode |= HAL_I2C_ERROR_BERR; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); + } + + // I2C Arbitration Loss error + if (sr1 & I2C_FLAG_ARLO) { + hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); + } + + // I2C Acknowledge failure + if (sr1 & I2C_FLAG_AF) { + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP); + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + } + + // I2C Over-Run/Under-Run + if (sr1 & I2C_FLAG_OVR) { + hi2c->ErrorCode |= HAL_I2C_ERROR_OVR; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); + } + + #else + + // if not an F4 MCU, use the HAL's IRQ handler + HAL_I2C_ER_IRQHandler(hi2c); + + #endif +} + +STATIC HAL_StatusTypeDef i2c_wait_dma_finished(I2C_HandleTypeDef *i2c, uint32_t timeout) { + // Note: we can't use WFI to idle in this loop because the DMA completion + // interrupt may occur before the WFI. Hence we miss it and have to wait + // until the next sys-tick (up to 1ms). + uint32_t start = HAL_GetTick(); + while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) { + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +/******************************************************************************/ +/* MicroPython bindings */ + +static inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; } + +STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + uint i2c_num = 0; + if (0) { } + #if defined(MICROPY_HW_I2C1_SCL) + else if (self->i2c->Instance == I2C1) { i2c_num = 1; } + #endif + #if defined(MICROPY_HW_I2C2_SCL) + else if (self->i2c->Instance == I2C2) { i2c_num = 2; } + #endif + #if defined(MICROPY_HW_I2C3_SCL) + else if (self->i2c->Instance == I2C3) { i2c_num = 3; } + #endif + #if defined(MICROPY_HW_I2C4_SCL) + else if (self->i2c->Instance == I2C4) { i2c_num = 4; } + #endif + + if (self->i2c->State == HAL_I2C_STATE_RESET) { + mp_printf(print, "I2C(%u)", i2c_num); + } else { + if (in_master_mode(self)) { + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, pyb_i2c_get_baudrate(self->i2c)); + } else { + mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); + } + } +} + +/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False) +/// +/// Initialise the I2C bus with the given parameters: +/// +/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE` +/// - `addr` is the 7-bit address (only sensible for a slave) +/// - `baudrate` is the SCL clock rate (only sensible for a master) +/// - `gencall` is whether to support general call mode +STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_INT, {.u_int = PYB_I2C_MASTER} }, + { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} }, + { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set the I2C configuration values + I2C_InitTypeDef *init = &self->i2c->Init; + + if (args[0].u_int == PYB_I2C_MASTER) { + // use a special address to indicate we are a master + init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + } else { + init->OwnAddress1 = (args[1].u_int << 1) & 0xfe; + } + + i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX)); + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; + init->DualAddressMode = I2C_DUALADDRESS_DISABLED; + init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED; + init->OwnAddress2 = 0; // unused + init->NoStretchMode = I2C_NOSTRETCH_DISABLE; + + *self->use_dma = args[4].u_bool; + + // init the I2C bus + i2c_deinit(self->i2c); + pyb_i2c_init(self->i2c); + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct an I2C object on the given bus. `bus` can be 1 or 2. +/// With no additional parameters, the I2C object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the I2C busses are: +/// +/// - `I2C(1)` is on the X position: `(SCL, SDA) = (X9, X10) = (PB6, PB7)` +/// - `I2C(2)` is on the Y position: `(SCL, SDA) = (Y9, Y10) = (PB10, PB11)` +STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // work out i2c bus + int i2c_id = 0; + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { + #ifdef MICROPY_HW_I2C1_NAME + } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) { + i2c_id = 1; + #endif + #ifdef MICROPY_HW_I2C2_NAME + } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) { + i2c_id = 2; + #endif + #ifdef MICROPY_HW_I2C3_NAME + } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) { + i2c_id = 3; + #endif + #ifdef MICROPY_HW_I2C4_NAME + } else if (strcmp(port, MICROPY_HW_I2C4_NAME) == 0) { + i2c_id = 4; + #endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%s) doesn't exist", port)); + } + } else { + i2c_id = mp_obj_get_int(args[0]); + if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(pyb_i2c_obj) + || pyb_i2c_obj[i2c_id - 1].i2c == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%d) doesn't exist", i2c_id)); + } + } + + // get I2C object + const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id - 1]; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(i2c_obj); +} + +STATIC mp_obj_t pyb_i2c_init_(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_i2c_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init_); + +/// \method deinit() +/// Turn off the I2C bus. +STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) { + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + i2c_deinit(self->i2c); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit); + +/// \method is_ready(addr) +/// Check if an I2C device responds to the given address. Only valid when in master mode. +STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1; + + for (int i = 0; i < 10; i++) { + HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, i2c_addr, 10, 200); + if (status == HAL_OK) { + return mp_const_true; + } + } + + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready); + +/// \method scan() +/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond. +/// Only valid when in master mode. +STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + + for (uint addr = 0x08; addr <= 0x77; addr++) { + HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 1, 200); + if (status == HAL_OK) { + mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); + } + } + + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan); + +/// \method send(send, addr=0x00, timeout=5000) +/// Send data on the bus: +/// +/// - `send` is the data to send (an integer to send, or a buffer object) +/// - `addr` is the address to send to (only required in master mode) +/// - `timeout` is the timeout in milliseconds to wait for the send +/// +/// Return value: `None`. +STATIC mp_obj_t pyb_i2c_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + DMA_HandleTypeDef tx_dma; + if (use_dma) { + dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->i2c); + self->i2c->hdmatx = &tx_dma; + self->i2c->hdmarx = NULL; + } + + // send the data + HAL_StatusTypeDef status; + if (in_master_mode(self)) { + if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { + if (use_dma) { + dma_deinit(self->tx_dma_descr); + } + mp_raise_TypeError("addr argument required"); + } + mp_uint_t i2c_addr = args[1].u_int << 1; + if (!use_dma) { + status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int); + } else { + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len); + } + } else { + if (!use_dma) { + status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int); + } else { + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len); + } + } + + // if we used DMA, wait for it to finish + if (use_dma) { + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[2].u_int); + } + dma_deinit(self->tx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send); + +/// \method recv(recv, addr=0x00, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `recv` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes +/// - `addr` is the address to receive from (only required in master mode) +/// - `timeout` is the timeout in milliseconds to wait for the receive +/// +/// Return value: if `recv` is an integer then a new buffer of the bytes received, +/// otherwise the same buffer that was passed in to `recv`. +STATIC mp_obj_t pyb_i2c_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to receive into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + DMA_HandleTypeDef rx_dma; + if (use_dma) { + dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->i2c); + self->i2c->hdmatx = NULL; + self->i2c->hdmarx = &rx_dma; + } + + // receive the data + HAL_StatusTypeDef status; + if (in_master_mode(self)) { + if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { + mp_raise_TypeError("addr argument required"); + } + mp_uint_t i2c_addr = args[1].u_int << 1; + if (!use_dma) { + status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); + } else { + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len); + } + } else { + if (!use_dma) { + status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); + } else { + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len); + } + } + + // if we used DMA, wait for it to finish + if (use_dma) { + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[2].u_int); + } + dma_deinit(self->rx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv); + +/// \method mem_read(data, addr, memaddr, timeout=5000, addr_size=8) +/// +/// Read from the memory of an I2C device: +/// +/// - `data` can be an integer or a buffer to read into +/// - `addr` is the I2C device address +/// - `memaddr` is the memory location within the I2C device +/// - `timeout` is the timeout in milliseconds to wait for the read +/// - `addr_size` selects width of memaddr: 8 or 16 bits +/// +/// Returns the read data. +/// This is only valid in master mode. +STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + { MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, +}; + +STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + // get the buffer to read into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // get the addresses + mp_uint_t i2c_addr = args[1].u_int << 1; + mp_uint_t mem_addr = args[2].u_int; + // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width + mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; + if (args[4].u_int != 8) { + mem_addr_size = I2C_MEMADD_SIZE_16BIT; + } + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + HAL_StatusTypeDef status; + if (!use_dma) { + status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int); + } else { + DMA_HandleTypeDef rx_dma; + dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->i2c); + self->i2c->hdmatx = NULL; + self->i2c->hdmarx = &rx_dma; + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len); + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[3].u_int); + } + dma_deinit(self->rx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + // return the read data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read); + +/// \method mem_write(data, addr, memaddr, timeout=5000, addr_size=8) +/// +/// Write to the memory of an I2C device: +/// +/// - `data` can be an integer or a buffer to write from +/// - `addr` is the I2C device address +/// - `memaddr` is the memory location within the I2C device +/// - `timeout` is the timeout in milliseconds to wait for the write +/// - `addr_size` selects width of memaddr: 8 or 16 bits +/// +/// Returns `None`. +/// This is only valid in master mode. +STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args (same as mem_read) + pyb_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + // get the buffer to write from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + + // get the addresses + mp_uint_t i2c_addr = args[1].u_int << 1; + mp_uint_t mem_addr = args[2].u_int; + // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width + mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; + if (args[4].u_int != 8) { + mem_addr_size = I2C_MEMADD_SIZE_16BIT; + } + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + HAL_StatusTypeDef status; + if (!use_dma) { + status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int); + } else { + DMA_HandleTypeDef tx_dma; + dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->i2c); + self->i2c->hdmatx = &tx_dma; + self->i2c->hdmarx = NULL; + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len); + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[3].u_int); + } + dma_deinit(self->tx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write); + +STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_ready), MP_ROM_PTR(&pyb_i2c_is_ready_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_i2c_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_i2c_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_read), MP_ROM_PTR(&pyb_i2c_mem_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) }, + + // class constants + /// \constant MASTER - for initialising the bus to master mode + /// \constant SLAVE - for initialising the bus to slave mode + { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); + +const mp_obj_type_t pyb_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = pyb_i2c_print, + .make_new = pyb_i2c_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, +}; + +#endif // MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C diff --git a/src/openmv/src/micropython/ports/stm32/pyb_spi.c b/src/openmv/src/micropython/ports/stm32/pyb_spi.c new file mode 100755 index 0000000..e763699 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pyb_spi.c @@ -0,0 +1,357 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "extmod/machine_spi.h" +#include "bufhelper.h" +#include "spi.h" + +/******************************************************************************/ +// MicroPython bindings for legacy pyb API + +// class pyb.SPI - a master-driven serial protocol +// +// SPI is a serial protocol that is driven by a master. At the physical level +// there are 3 lines: SCK, MOSI, MISO. +// +// See usage model of I2C; SPI is very similar. Main difference is +// parameters to init the SPI bus: +// +// from pyb import SPI +// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7) +// +// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be +// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1 +// to sample data on the first or second clock edge respectively. Crc can be +// None for no CRC, or a polynomial specifier. +// +// Additional method for SPI: +// +// data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes +// buf = bytearray(4) +// spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf +// spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf + +STATIC const pyb_spi_obj_t pyb_spi_obj[] = { + {{&pyb_spi_type}, &spi_obj[0]}, + {{&pyb_spi_type}, &spi_obj[1]}, + {{&pyb_spi_type}, &spi_obj[2]}, + {{&pyb_spi_type}, &spi_obj[3]}, + {{&pyb_spi_type}, &spi_obj[4]}, + {{&pyb_spi_type}, &spi_obj[5]}, +}; + +STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + spi_print(print, self->spi, true); +} + +// init(mode, baudrate=328125, *, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) +// +// Initialise the SPI bus with the given parameters: +// - `mode` must be either `SPI.MASTER` or `SPI.SLAVE`. +// - `baudrate` is the SCK clock rate (only sensible for a master). +STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} }, + { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_dir, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DIRECTION_2LINES} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_nss, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_NSS_SOFT} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_FIRSTBIT_MSB} }, + { MP_QSTR_ti, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set the SPI configuration values + SPI_InitTypeDef *init = &self->spi->spi->Init; + init->Mode = args[0].u_int; + + spi_set_params(self->spi, args[2].u_int, args[1].u_int, args[3].u_int, args[4].u_int, + args[6].u_int, args[8].u_int); + + init->Direction = args[5].u_int; + init->NSS = args[7].u_int; + init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLE : SPI_TIMODE_DISABLE; + if (args[10].u_obj == mp_const_none) { + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; + init->CRCPolynomial = 0; + } else { + init->CRCCalculation = SPI_CRCCALCULATION_ENABLE; + init->CRCPolynomial = mp_obj_get_int(args[10].u_obj); + } + + // init the SPI bus + spi_init(self->spi, init->NSS != SPI_NSS_SOFT); + + return mp_const_none; +} + +// constructor(bus, ...) +// +// Construct an SPI object on the given bus. `bus` can be 1 or 2. +// With no additional parameters, the SPI object is created but not +// initialised (it has the settings from the last initialisation of +// the bus, if any). If extra arguments are given, the bus is initialised. +// See `init` for parameters of initialisation. +// +// The physical pins of the SPI busses are: +// - `SPI(1)` is on the X position: `(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)` +// - `SPI(2)` is on the Y position: `(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)` +// +// At the moment, the NSS pin is not used by the SPI driver and is free +// for other use. +STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // work out SPI bus + int spi_id = spi_find_index(args[0]); + + // get SPI object + const pyb_spi_obj_t *spi_obj = &pyb_spi_obj[spi_id - 1]; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_spi_init_helper(spi_obj, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(spi_obj); +} + +STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_spi_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init); + +// deinit() +// Turn off the SPI bus. +STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) { + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + spi_deinit(self->spi); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit); + +// send(send, *, timeout=5000) +// Send data on the bus: +// - `send` is the data to send (an integer to send, or a buffer object). +// - `timeout` is the timeout in milliseconds to wait for the send. +// +// Return value: `None`. +STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + + // send the data + spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send); + +// recv(recv, *, timeout=5000) +// +// Receive data on the bus: +// - `recv` can be an integer, which is the number of bytes to receive, +// or a mutable buffer, which will be filled with received bytes. +// - `timeout` is the timeout in milliseconds to wait for the receive. +// +// Return value: if `recv` is an integer then a new buffer of the bytes received, +// otherwise the same buffer that was passed in to `recv`. +STATIC mp_obj_t pyb_spi_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to receive into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // receive the data + spi_transfer(self->spi, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int); + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_recv_obj, 1, pyb_spi_recv); + +// send_recv(send, recv=None, *, timeout=5000) +// +// Send and receive data on the bus at the same time: +// - `send` is the data to send (an integer to send, or a buffer object). +// - `recv` is a mutable buffer which will be filled with received bytes. +// It can be the same as `send`, or omitted. If omitted, a new buffer will +// be created. +// - `timeout` is the timeout in milliseconds to wait for the receive. +// +// Return value: the buffer with the received bytes. +STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_recv, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get buffers to send from/receive to + mp_buffer_info_t bufinfo_send; + uint8_t data_send[1]; + mp_buffer_info_t bufinfo_recv; + vstr_t vstr_recv; + mp_obj_t o_ret; + + if (args[0].u_obj == args[1].u_obj) { + // same object for send and receive, it must be a r/w buffer + mp_get_buffer_raise(args[0].u_obj, &bufinfo_send, MP_BUFFER_RW); + bufinfo_recv = bufinfo_send; + o_ret = args[0].u_obj; + } else { + // get the buffer to send from + pyb_buf_get_for_send(args[0].u_obj, &bufinfo_send, data_send); + + // get the buffer to receive into + if (args[1].u_obj == MP_OBJ_NULL) { + // only send argument given, so create a fresh buffer of the send length + vstr_init_len(&vstr_recv, bufinfo_send.len); + bufinfo_recv.len = vstr_recv.len; + bufinfo_recv.buf = vstr_recv.buf; + o_ret = MP_OBJ_NULL; + } else { + // recv argument given + mp_get_buffer_raise(args[1].u_obj, &bufinfo_recv, MP_BUFFER_WRITE); + if (bufinfo_recv.len != bufinfo_send.len) { + mp_raise_ValueError("recv must be same length as send"); + } + o_ret = args[1].u_obj; + } + } + + // do the transfer + spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int); + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr_recv); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_recv_obj, 1, pyb_spi_send_recv); + +STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_spi_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, + + // legacy methods + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_spi_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_spi_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_send_recv), MP_ROM_PTR(&pyb_spi_send_recv_obj) }, + + // class constants + /// \constant MASTER - for initialising the bus to master mode + /// \constant SLAVE - for initialising the bus to slave mode + /// \constant MSB - set the first bit to MSB + /// \constant LSB - set the first bit to LSB + { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(SPI_MODE_MASTER) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(SPI_MODE_SLAVE) }, + { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(SPI_FIRSTBIT_MSB) }, + { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(SPI_FIRSTBIT_LSB) }, + /* TODO + { MP_ROM_QSTR(MP_QSTR_DIRECTION_2LINES ((uint32_t)0x00000000) + { MP_ROM_QSTR(MP_QSTR_DIRECTION_2LINES_RXONLY SPI_CR1_RXONLY + { MP_ROM_QSTR(MP_QSTR_DIRECTION_1LINE SPI_CR1_BIDIMODE + { MP_ROM_QSTR(MP_QSTR_NSS_SOFT SPI_CR1_SSM + { MP_ROM_QSTR(MP_QSTR_NSS_HARD_INPUT ((uint32_t)0x00000000) + { MP_ROM_QSTR(MP_QSTR_NSS_HARD_OUTPUT ((uint32_t)0x00040000) + */ +}; +STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); + +STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); +} + +STATIC const mp_machine_spi_p_t pyb_spi_p = { + .transfer = spi_transfer_machine, +}; + +const mp_obj_type_t pyb_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = pyb_spi_print, + .make_new = pyb_spi_make_new, + .protocol = &pyb_spi_p, + .locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/pybcdc.inf_template b/src/openmv/src/micropython/ports/stm32/pybcdc.inf_template new file mode 100755 index 0000000..85279ad --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pybcdc.inf_template @@ -0,0 +1,92 @@ +; Windows USB CDC ACM Setup File +; Based on INF files which were: +; Copyright (c) 2000 Microsoft Corporation +; Copyright (C) 2007 Microchip Technology Inc. +; Likely to be covered by the MLPL as found at: +; . + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MFGNAME% +LayoutFile=layout.inf +DriverVer=03/11/2010,5.1.2600.3 + +[Manufacturer] +%MFGNAME%=DeviceList, NTamd64 + +[DestinationDirs] +DefaultDestDir=12 + +;--------------------------------------------------------------------- +; Windows 2000/XP/Server2003/Vista/Server2008/7 - 32bit Sections + +[DriverInstall.nt] +include=mdmcpq.inf +CopyFiles=DriverCopyFiles.nt +AddReg=DriverInstall.nt.AddReg + +[DriverCopyFiles.nt] +usbser.sys,,,0x20 + +[DriverInstall.nt.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.nt.Services] +AddService=usbser, 0x00000002, DriverService.nt + +[DriverService.nt] +DisplayName=%SERVICE% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;--------------------------------------------------------------------- +; Windows XP/Server2003/Vista/Server2008/7 - 64bit Sections + +[DriverInstall.NTamd64] +include=mdmcpq.inf +CopyFiles=DriverCopyFiles.NTamd64 +AddReg=DriverInstall.NTamd64.AddReg + +[DriverCopyFiles.NTamd64] +usbser.sys,,,0x20 + +[DriverInstall.NTamd64.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.NTamd64.Services] +AddService=usbser, 0x00000002, DriverService.NTamd64 + +[DriverService.NTamd64] +DisplayName=%SERVICE% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys + +;--------------------------------------------------------------------- +; Vendor and Product ID Definitions + +[SourceDisksFiles] +[SourceDisksNames] +[DeviceList] +%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC} + +[DeviceList.NTamd64] +%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_MSC}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID_CDC_HID}&MI_01, USB\VID_${USB_VID}&PID_${USB_PID_CDC} + +;--------------------------------------------------------------------- +; String Definitions + +[Strings] +MFGFILENAME="pybcdc" +MFGNAME="MicroPython" +DESCRIPTION="Pyboard USB Comm Port" +SERVICE="USB Serial Driver" diff --git a/src/openmv/src/micropython/ports/stm32/pybthread.c b/src/openmv/src/micropython/ports/stm32/pybthread.c new file mode 100755 index 0000000..6baf88f --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pybthread.c @@ -0,0 +1,237 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "gccollect.h" +#include "irq.h" +#include "pybthread.h" + +#if MICROPY_PY_THREAD + +#define PYB_MUTEX_UNLOCKED ((void*)0) +#define PYB_MUTEX_LOCKED ((void*)1) + +// These macros are used when we only need to protect against a thread +// switch; other interrupts are still allowed to proceed. +#define RAISE_IRQ_PRI() raise_irq_pri(IRQ_PRI_PENDSV) +#define RESTORE_IRQ_PRI(state) restore_irq_pri(state) + +extern void __fatal_error(const char*); + +volatile int pyb_thread_enabled; +pyb_thread_t *volatile pyb_thread_all; +pyb_thread_t *volatile pyb_thread_cur; + +static inline void pyb_thread_add_to_runable(pyb_thread_t *thread) { + thread->run_prev = pyb_thread_cur->run_prev; + thread->run_next = pyb_thread_cur; + pyb_thread_cur->run_prev->run_next = thread; + pyb_thread_cur->run_prev = thread; +} + +static inline void pyb_thread_remove_from_runable(pyb_thread_t *thread) { + if (thread->run_next == thread) { + __fatal_error("deadlock"); + } + thread->run_prev->run_next = thread->run_next; + thread->run_next->run_prev = thread->run_prev; +} + +void pyb_thread_init(pyb_thread_t *thread) { + pyb_thread_enabled = 0; + pyb_thread_all = thread; + pyb_thread_cur = thread; + thread->sp = NULL; // will be set when this thread switches out + thread->local_state = 0; // will be set by mp_thread_init + thread->arg = NULL; + thread->stack = &_heap_end; + thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_heap_end) / sizeof(uint32_t); + thread->all_next = NULL; + thread->run_prev = thread; + thread->run_next = thread; + thread->queue_next = NULL; +} + +void pyb_thread_deinit() { + uint32_t irq_state = disable_irq(); + pyb_thread_enabled = 0; + pyb_thread_all = pyb_thread_cur; + pyb_thread_cur->all_next = NULL; + pyb_thread_cur->run_prev = pyb_thread_cur; + pyb_thread_cur->run_next = pyb_thread_cur; + enable_irq(irq_state); +} + +STATIC void pyb_thread_terminate(void) { + uint32_t irq_state = disable_irq(); + pyb_thread_t *thread = pyb_thread_cur; + // take current thread off the run list + pyb_thread_remove_from_runable(thread); + // take current thread off the list of all threads + for (pyb_thread_t **n = (pyb_thread_t**)&pyb_thread_all;; n = &(*n)->all_next) { + if (*n == thread) { + *n = thread->all_next; + break; + } + } + // clean pointers as much as possible to help GC + thread->all_next = NULL; + thread->queue_next = NULL; + thread->stack = NULL; + if (pyb_thread_all->all_next == NULL) { + // only 1 thread left + pyb_thread_enabled = 0; + } + // thread switch will occur after we enable irqs + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + enable_irq(irq_state); + // should not return + __fatal_error("could not terminate"); +} + +uint32_t pyb_thread_new(pyb_thread_t *thread, void *stack, size_t stack_len, void *entry, void *arg) { + uint32_t *stack_top = (uint32_t*)stack + stack_len; // stack is full descending + *--stack_top = 0x01000000; // xPSR (thumb bit set) + *--stack_top = (uint32_t)entry & 0xfffffffe; // pc (must have bit 0 cleared, even for thumb code) + *--stack_top = (uint32_t)pyb_thread_terminate; // lr + *--stack_top = 0; // r12 + *--stack_top = 0; // r3 + *--stack_top = 0; // r2 + *--stack_top = 0; // r1 + *--stack_top = (uint32_t)arg; // r0 + *--stack_top = 0xfffffff9; // lr (return to thread mode, non-FP, use MSP) + stack_top -= 8; // r4-r11 + stack_top -= 16; // s16-s31 (we assume all threads use FP registers) + thread->sp = stack_top; + thread->local_state = 0; + thread->arg = arg; + thread->stack = stack; + thread->stack_len = stack_len; + thread->queue_next = NULL; + uint32_t irq_state = disable_irq(); + pyb_thread_enabled = 1; + thread->all_next = pyb_thread_all; + pyb_thread_all = thread; + pyb_thread_add_to_runable(thread); + enable_irq(irq_state); + return (uint32_t)thread; // success +} + +void pyb_thread_dump(void) { + if (!pyb_thread_enabled) { + printf("THREAD: only main thread\n"); + } else { + printf("THREAD:\n"); + for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) { + bool runable = false; + for (pyb_thread_t *th2 = pyb_thread_cur;; th2 = th2->run_next) { + if (th == th2) { + runable = true; + break; + } + if (th2->run_next == pyb_thread_cur) { + break; + } + } + printf(" id=%p sp=%p sz=%u", th, th->stack, th->stack_len); + if (runable) { + printf(" (runable)"); + } + printf("\n"); + } + } +} + +// should only be called from pendsv_isr_handler +void *pyb_thread_next(void *sp) { + pyb_thread_cur->sp = sp; + pyb_thread_cur = pyb_thread_cur->run_next; + pyb_thread_cur->timeslice = 4; // in milliseconds + return pyb_thread_cur->sp; +} + +void pyb_mutex_init(pyb_mutex_t *m) { + *m = PYB_MUTEX_UNLOCKED; +} + +int pyb_mutex_lock(pyb_mutex_t *m, int wait) { + uint32_t irq_state = RAISE_IRQ_PRI(); + if (*m == PYB_MUTEX_UNLOCKED) { + // mutex is available + *m = PYB_MUTEX_LOCKED; + RESTORE_IRQ_PRI(irq_state); + } else { + // mutex is locked + if (!wait) { + RESTORE_IRQ_PRI(irq_state); + return 0; // failed to lock mutex + } + if (*m == PYB_MUTEX_LOCKED) { + *m = pyb_thread_cur; + } else { + for (pyb_thread_t *n = *m;; n = n->queue_next) { + if (n->queue_next == NULL) { + n->queue_next = pyb_thread_cur; + break; + } + } + } + pyb_thread_cur->queue_next = NULL; + // take current thread off the run list + pyb_thread_remove_from_runable(pyb_thread_cur); + // thread switch will occur after we enable irqs + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + RESTORE_IRQ_PRI(irq_state); + // when we come back we have the mutex + } + return 1; // have mutex +} + +void pyb_mutex_unlock(pyb_mutex_t *m) { + uint32_t irq_state = RAISE_IRQ_PRI(); + if (*m == PYB_MUTEX_LOCKED) { + // no threads are blocked on the mutex + *m = PYB_MUTEX_UNLOCKED; + } else { + // at least one thread is blocked on this mutex + pyb_thread_t *th = *m; + if (th->queue_next == NULL) { + // no other threads are blocked + *m = PYB_MUTEX_LOCKED; + } else { + // at least one other thread is still blocked + *m = th->queue_next; + } + // put unblocked thread on runable list + pyb_thread_add_to_runable(th); + } + RESTORE_IRQ_PRI(irq_state); +} + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/ports/stm32/pybthread.h b/src/openmv/src/micropython/ports/stm32/pybthread.h new file mode 100755 index 0000000..4230050 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/pybthread.h @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_PYBTHREAD_H +#define MICROPY_INCLUDED_STM32_PYBTHREAD_H + +typedef struct _pyb_thread_t { + void *sp; + uint32_t local_state; + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + size_t stack_len; // number of words in the stack + uint32_t timeslice; + struct _pyb_thread_t *all_next; + struct _pyb_thread_t *run_prev; + struct _pyb_thread_t *run_next; + struct _pyb_thread_t *queue_next; +} pyb_thread_t; + +typedef pyb_thread_t *pyb_mutex_t; + +extern volatile int pyb_thread_enabled; +extern pyb_thread_t *volatile pyb_thread_all; +extern pyb_thread_t *volatile pyb_thread_cur; + +void pyb_thread_init(pyb_thread_t *th); +void pyb_thread_deinit(); +uint32_t pyb_thread_new(pyb_thread_t *th, void *stack, size_t stack_len, void *entry, void *arg); +void pyb_thread_dump(void); + +static inline uint32_t pyb_thread_get_id(void) { + return (uint32_t)pyb_thread_cur; +} + +static inline void pyb_thread_set_local(void *value) { + pyb_thread_cur->local_state = (uint32_t)value; +} + +static inline void *pyb_thread_get_local(void) { + return (void*)pyb_thread_cur->local_state; +} + +static inline void pyb_thread_yield(void) { + if (pyb_thread_cur->run_next == pyb_thread_cur) { + __WFI(); + } else { + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } +} + +void pyb_mutex_init(pyb_mutex_t *m); +int pyb_mutex_lock(pyb_mutex_t *m, int wait); +void pyb_mutex_unlock(pyb_mutex_t *m); + +#endif // MICROPY_INCLUDED_STM32_PYBTHREAD_H diff --git a/src/openmv/src/micropython/ports/stm32/qspi.c b/src/openmv/src/micropython/ports/stm32/qspi.c new file mode 100755 index 0000000..a7cbbde --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/qspi.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "qspi.h" + +#if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) + +void qspi_init(void) { + // Configure pins + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + + // Bring up the QSPI peripheral + + __HAL_RCC_QSPI_CLK_ENABLE(); + + QUADSPI->CR = + 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) + | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write + #if defined(QUADSPI_CR_FSEL_Pos) + | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected + #endif + #if defined(QUADSPI_CR_DFM_Pos) + | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled + #endif + | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift + | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled + | 1 << QUADSPI_CR_EN_Pos // enable the peripheral + ; + + QUADSPI->DCR = + (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos + | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles + | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state + ; +} + +void qspi_memory_map(void) { + // Enable memory-mapped mode + + QUADSPI->ABR = 0; // disable continuous read mode + QUADSPI->LPTR = 100; // to tune + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; +} + +STATIC int qspi_ioctl(void *self_in, uint32_t cmd) { + (void)self_in; + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + qspi_init(); + break; + case MP_QSPI_IOCTL_BUS_RELEASE: + // Switch to memory-map mode when bus is idle + qspi_memory_map(); + break; + } + return 0; // success +} + +STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + // This assumes len==2 + *(uint16_t*)&QUADSPI->DR = data; + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + + // Write out the data 1 byte at a time + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(volatile uint8_t*)&QUADSPI->DR = *src++; + --len; + } + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode + ; + + // Wait for read to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + // Read result + return QUADSPI->DR; +} + +STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + (void)self_in; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; + + QUADSPI->ABR = 0; // alternate byte: disable continuous read mode + QUADSPI->AR = addr; // addres to read from + + // Read in the data 4 bytes at a time if dest is aligned + if (((uintptr_t)dest & 3) == 0) { + while (len >= 4) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(uint32_t*)dest = QUADSPI->DR; + dest += 4; + len -= 4; + } + } + + // Read in remaining data 1 byte at a time + while (len) { + while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) { + } + *dest++ = *(volatile uint8_t*)&QUADSPI->DR; + --len; + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +const mp_qspi_proto_t qspi_proto = { + .ioctl = qspi_ioctl, + .write_cmd_data = qspi_write_cmd_data, + .write_cmd_addr_data = qspi_write_cmd_addr_data, + .read_cmd = qspi_read_cmd, + .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata, +}; + +#endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) diff --git a/src/openmv/src/micropython/ports/stm32/qspi.h b/src/openmv/src/micropython/ports/stm32/qspi.h new file mode 100755 index 0000000..c774b12 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/qspi.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_QSPI_H +#define MICROPY_INCLUDED_STM32_QSPI_H + +#include "drivers/bus/qspi.h" + +extern const mp_qspi_proto_t qspi_proto; + +void qspi_init(void); +void qspi_memory_map(void); + +#endif // MICROPY_INCLUDED_STM32_QSPI_H diff --git a/src/openmv/src/micropython/ports/stm32/qstrdefsport.h b/src/openmv/src/micropython/ports/stm32/qstrdefsport.h new file mode 100755 index 0000000..31220c5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/qstrdefsport.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port + +Q(boot.py) +Q(main.py) +// Entries for sys.path +Q(/flash) +Q(/flash/lib) +Q(/sd) +Q(/sd/lib) +// for usb modes +Q(MSC+HID) +Q(VCP+MSC) +Q(VCP+HID) +Q(CDC+MSC) +Q(CDC+HID) +Q(/) + + +// The following qstrings not referenced from anywhere in the sources +Q(CDC) +Q(flash) diff --git a/src/openmv/src/micropython/ports/stm32/resethandler.s b/src/openmv/src/micropython/ports/stm32/resethandler.s new file mode 100755 index 0000000..7f09733 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/resethandler.s @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m4 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr sp, =_estack + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ + str r0, [r2], #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + b stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/src/openmv/src/micropython/ports/stm32/resethandler_m0.s b/src/openmv/src/micropython/ports/stm32/resethandler_m0.s new file mode 100755 index 0000000..bb88e8d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/resethandler_m0.s @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr r0, =_estack + mov sp, r0 + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1] + adds r1, #4 + str r0, [r2] + adds r2, #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1] + adds r1, #4 +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + bl stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/src/openmv/src/micropython/ports/stm32/rng.c b/src/openmv/src/micropython/ports/stm32/rng.c new file mode 100755 index 0000000..b239419 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/rng.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "rng.h" + +#if MICROPY_HW_ENABLE_RNG + +#define RNG_TIMEOUT_MS (10) + +uint32_t rng_get(void) { + // Enable the RNG peripheral if it's not already enabled + if (!(RNG->CR & RNG_CR_RNGEN)) { + #if defined(STM32H7) + // Set RNG Clock source + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); + __HAL_RCC_RNG_CONFIG(RCC_RNGCLKSOURCE_PLL); + #endif + __HAL_RCC_RNG_CLK_ENABLE(); + RNG->CR |= RNG_CR_RNGEN; + } + + // Wait for a new random number to be ready, takes on the order of 10us + uint32_t start = HAL_GetTick(); + while (!(RNG->SR & RNG_SR_DRDY)) { + if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { + return 0; + } + } + + // Get and return the new random number + return RNG->DR; +} + +// Return a 30-bit hardware generated random number. +STATIC mp_obj_t pyb_rng_get(void) { + return mp_obj_new_int(rng_get() >> 2); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); + +#else // MICROPY_HW_ENABLE_RNG + +// For MCUs that don't have an RNG we still need to provide a rng_get() function, +// eg for lwIP. A pseudo-RNG is not really ideal but we go with it for now. We +// don't want to use urandom's pRNG because then the user won't see a reproducible +// random stream. + +// Yasmarang random number generator by Ilya Levin +// http://www.literatecode.com/yasmarang +STATIC uint32_t pyb_rng_yasmarang(void) { + static uint32_t pad = 0xeda4baba, n = 69, d = 233; + static uint8_t dat = 0; + + pad += dat + d * n; + pad = (pad << 3) + (pad >> 29); + n = pad | 2; + d ^= (pad << 31) + (pad >> 1); + dat ^= (char)pad ^ (d >> 8) ^ 1; + + return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1); +} + +uint32_t rng_get(void) { + return pyb_rng_yasmarang(); +} + +#endif // MICROPY_HW_ENABLE_RNG diff --git a/src/openmv/src/micropython/ports/stm32/rng.h b/src/openmv/src/micropython/ports/stm32/rng.h new file mode 100755 index 0000000..ed9cc80 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/rng.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_RNG_H +#define MICROPY_INCLUDED_STM32_RNG_H + +#include "py/obj.h" + +uint32_t rng_get(void); + +MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); + +#endif // MICROPY_INCLUDED_STM32_RNG_H diff --git a/src/openmv/src/micropython/ports/stm32/rtc.c b/src/openmv/src/micropython/ports/stm32/rtc.c new file mode 100755 index 0000000..1999dfb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/rtc.c @@ -0,0 +1,753 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "extint.h" +#include "rtc.h" +#include "irq.h" + +/// \moduleref pyb +/// \class RTC - real time clock +/// +/// The RTC is and independent clock that keeps track of the date +/// and time. +/// +/// Example usage: +/// +/// rtc = pyb.RTC() +/// rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0)) +/// print(rtc.datetime()) + +RTC_HandleTypeDef RTCHandle; + +// rtc_info indicates various things about RTC startup +// it's a bit of a hack at the moment +static mp_uint_t rtc_info; + +// Note: LSI is around (32KHz), these dividers should work either way +// ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1) +// modify RTC_ASYNCH_PREDIV & RTC_SYNCH_PREDIV in board//mpconfigport.h to change sub-second ticks +// default is 3906.25 µs, min is ~30.52 µs (will increas Ivbat by ~500nA) +#ifndef RTC_ASYNCH_PREDIV +#define RTC_ASYNCH_PREDIV (0x7f) +#endif +#ifndef RTC_SYNCH_PREDIV +#define RTC_SYNCH_PREDIV (0x00ff) +#endif + +STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc); +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse); +STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc); +STATIC void RTC_CalendarConfig(void); + +#if defined(MICROPY_HW_RTC_USE_LSE) && MICROPY_HW_RTC_USE_LSE +STATIC bool rtc_use_lse = true; +#else +STATIC bool rtc_use_lse = false; +#endif +STATIC uint32_t rtc_startup_tick; +STATIC bool rtc_need_init_finalise = false; + +// check if LSE exists +// not well tested, should probably be removed +STATIC bool lse_magic(void) { +#if 0 + uint32_t mode_in = GPIOC->MODER & 0x3fffffff; + uint32_t mode_out = mode_in | 0x40000000; + GPIOC->MODER = mode_out; + GPIOC->OTYPER &= 0x7fff; + GPIOC->BSRRH = 0x8000; + GPIOC->OSPEEDR &= 0x3fffffff; + GPIOC->PUPDR &= 0x3fffffff; + int i = 0xff0; + __IO int d = 0; + uint32_t tc = 0; + __IO uint32_t j; + while (i) { + GPIOC->MODER = mode_out; + GPIOC->MODER = mode_in; + for (j = 0; j < d; j++) ; + i--; + if ((GPIOC->IDR & 0x8000) == 0) { + tc++; + } + } + return (tc < 0xff0)?true:false; +#else + return false; +#endif +} + +void rtc_init_start(bool force_init) { + RTCHandle.Instance = RTC; + + /* Configure RTC prescaler and RTC data registers */ + /* RTC configured as follow: + - Hour Format = Format 24 + - Asynch Prediv = Value according to source clock + - Synch Prediv = Value according to source clock + - OutPut = Output Disable + - OutPutPolarity = High Polarity + - OutPutType = Open Drain */ + RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24; + RTCHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV; + RTCHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV; + RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE; + RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + + rtc_need_init_finalise = false; + + if (!force_init) { + if ((RCC->BDCR & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) == (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { + // LSE is enabled & ready --> no need to (re-)init RTC + // remove Backup Domain write protection + HAL_PWR_EnableBkUpAccess(); + // Clear source Reset Flag + __HAL_RCC_CLEAR_RESET_FLAGS(); + // provide some status information + rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; + return; + } else if ((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) { + // LSI configured as the RTC clock source --> no need to (re-)init RTC + // remove Backup Domain write protection + HAL_PWR_EnableBkUpAccess(); + // Clear source Reset Flag + __HAL_RCC_CLEAR_RESET_FLAGS(); + // Turn the LSI on (it may need this even if the RTC is running) + RCC->CSR |= RCC_CSR_LSION; + // provide some status information + rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; + return; + } + } + + rtc_startup_tick = HAL_GetTick(); + rtc_info = 0x3f000000 | (rtc_startup_tick & 0xffffff); + if (rtc_use_lse) { + if (lse_magic()) { + // don't even try LSE + rtc_use_lse = false; + rtc_info &= ~0x01000000; + } + } + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); +} + +void rtc_init_finalise() { + if (!rtc_need_init_finalise) { + return; + } + + rtc_info = 0x20000000; + if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { + if (rtc_use_lse) { + // fall back to LSI... + rtc_use_lse = false; + rtc_startup_tick = HAL_GetTick(); + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); + HAL_PWR_EnableBkUpAccess(); + RTCHandle.State = HAL_RTC_STATE_RESET; + if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { + rtc_info = 0x0100ffff; // indicate error + return; + } + } else { + // init error + rtc_info = 0xffff; // indicate error + return; + } + } + + // record if LSE or LSI is used + rtc_info |= (rtc_use_lse << 28); + + // record how long it took for the RTC to start up + rtc_info |= (HAL_GetTick() - rtc_startup_tick) & 0xffff; + + // fresh reset; configure RTC Calendar + RTC_CalendarConfig(); + #if defined(STM32L4) + if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) { + #else + if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { + #endif + // power on reset occurred + rtc_info |= 0x10000; + } + if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET) { + // external reset occurred + rtc_info |= 0x20000; + } + // Clear source Reset Flag + __HAL_RCC_CLEAR_RESET_FLAGS(); + rtc_need_init_finalise = false; +} + +STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct) { + /*------------------------------ LSI Configuration -------------------------*/ + if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) { + // Check the LSI State + if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF) { + // Enable the Internal Low Speed oscillator (LSI). + __HAL_RCC_LSI_ENABLE(); + } else { + // Disable the Internal Low Speed oscillator (LSI). + __HAL_RCC_LSI_DISABLE(); + } + } + + /*------------------------------ LSE Configuration -------------------------*/ + if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) { + #if !defined(STM32H7) + // Enable Power Clock + __HAL_RCC_PWR_CLK_ENABLE(); + #endif + + // Enable access to the backup domain + HAL_PWR_EnableBkUpAccess(); + uint32_t tickstart = HAL_GetTick(); + + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + //__HAL_RCC_PWR_CLK_ENABLE(); + // Enable write access to Backup domain + //PWR->CR1 |= PWR_CR1_DBP; + // Wait for Backup domain Write protection disable + while ((PWR->CR1 & PWR_CR1_DBP) == RESET) { + if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + #else + // Enable write access to Backup domain + //PWR->CR |= PWR_CR_DBP; + // Wait for Backup domain Write protection disable + while ((PWR->CR & PWR_CR_DBP) == RESET) { + if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + #endif + + // Set the new LSE configuration + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + } + + return HAL_OK; +} + +STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { + // Check the RTC peripheral state + if (hrtc == NULL) { + return HAL_ERROR; + } + if (hrtc->State == HAL_RTC_STATE_RESET) { + // Allocate lock resource and initialize it + hrtc->Lock = HAL_UNLOCKED; + // Initialize RTC MSP + if (PYB_RTC_MspInit_Finalise(hrtc) != HAL_OK) { + return HAL_ERROR; + } + } + + // Set RTC state + hrtc->State = HAL_RTC_STATE_BUSY; + + // Disable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc); + + // Set Initialization mode + if (RTC_EnterInitMode(hrtc) != HAL_OK) { + // Enable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); + + // Set RTC state + hrtc->State = HAL_RTC_STATE_ERROR; + + return HAL_ERROR; + } else { + // Clear RTC_CR FMT, OSEL and POL Bits + hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL)); + // Set RTC_CR register + hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity); + + // Configure the RTC PRER + hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv); + hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16); + + // Exit Initialization mode + hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; + + #if defined(STM32L4) || defined(STM32H7) + hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; + hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); + #elif defined(STM32F7) + hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE; + hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); + #else + hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE; + hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType); + #endif + + // Enable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); + + // Set RTC state + hrtc->State = HAL_RTC_STATE_READY; + + return HAL_OK; + } +} + +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { + /* To change the source clock of the RTC feature (LSE, LSI), You have to: + - Enable the power clock using __PWR_CLK_ENABLE() + - Enable write access using HAL_PWR_EnableBkUpAccess() function before to + configure the RTC clock source (to be done once after reset). + - Reset the Back up Domain using __HAL_RCC_BACKUPRESET_FORCE() and + __HAL_RCC_BACKUPRESET_RELEASE(). + - Configure the needed RTc clock source */ + + // RTC clock source uses LSE (external crystal) only if relevant + // configuration variable is set. Otherwise it uses LSI (internal osc). + + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (rtc_use_lse) { + #if MICROPY_HW_RTC_USE_BYPASS + RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS; + #else + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + #endif + RCC_OscInitStruct.LSIState = RCC_LSI_OFF; + } else { + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; + } + PYB_RCC_OscConfig(&RCC_OscInitStruct); + + // now ramp up osc. in background and flag calendear init needed + rtc_need_init_finalise = true; +} + +#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic +#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms + +STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) { + // we already had a kick so now wait for the corresponding ready state... + if (rtc_use_lse) { + // we now have to wait for LSE ready or timeout + uint32_t tickstart = rtc_startup_tick; + while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) { + if ((HAL_GetTick() - tickstart ) > PYB_LSE_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + } else { + // we now have to wait for LSI ready or timeout + uint32_t tickstart = rtc_startup_tick; + while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) { + if ((HAL_GetTick() - tickstart ) > PYB_LSI_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + } + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; + if (rtc_use_lse) { + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + } else { + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + } + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + //Error_Handler(); + return HAL_ERROR; + } + + // enable RTC peripheral clock + __HAL_RCC_RTC_ENABLE(); + return HAL_OK; +} + +STATIC void RTC_CalendarConfig(void) { + // set the date to 1st Jan 2015 + RTC_DateTypeDef date; + date.Year = 15; + date.Month = 1; + date.Date = 1; + date.WeekDay = RTC_WEEKDAY_THURSDAY; + + if(HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN) != HAL_OK) { + // init error + return; + } + + // set the time to 00:00:00 + RTC_TimeTypeDef time; + time.Hours = 0; + time.Minutes = 0; + time.Seconds = 0; + time.TimeFormat = RTC_HOURFORMAT12_AM; + time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; + time.StoreOperation = RTC_STOREOPERATION_RESET; + + if (HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN) != HAL_OK) { + // init error + return; + } +} + +/******************************************************************************/ +// MicroPython bindings + +typedef struct _pyb_rtc_obj_t { + mp_obj_base_t base; +} pyb_rtc_obj_t; + +STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; + +/// \classmethod \constructor() +/// Create an RTC object. +STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return MP_OBJ_FROM_PTR(&pyb_rtc_obj); +} + +// force rtc to re-initialise +mp_obj_t pyb_rtc_init(mp_obj_t self_in) { + rtc_init_start(true); + rtc_init_finalise(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_init_obj, pyb_rtc_init); + +/// \method info() +/// Get information about the startup time and reset source. +/// +/// - The lower 0xffff are the number of milliseconds the RTC took to +/// start up. +/// - Bit 0x10000 is set if a power-on reset occurred. +/// - Bit 0x20000 is set if an external reset occurred +mp_obj_t pyb_rtc_info(mp_obj_t self_in) { + return mp_obj_new_int(rtc_info); +} +MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_info_obj, pyb_rtc_info); + +/// \method datetime([datetimetuple]) +/// Get or set the date and time of the RTC. +/// +/// With no arguments, this method returns an 8-tuple with the current +/// date and time. With 1 argument (being an 8-tuple) it sets the date +/// and time. +/// +/// The 8-tuple has the following format: +/// +/// (year, month, day, weekday, hours, minutes, seconds, subseconds) +/// +/// `weekday` is 1-7 for Monday through Sunday. +/// +/// `subseconds` counts down from 255 to 0 + +#define MEG_DIV_64 (1000000 / 64) +#define MEG_DIV_SCALE ((RTC_SYNCH_PREDIV + 1) / 64) + +#if defined(MICROPY_HW_RTC_USE_US) && MICROPY_HW_RTC_USE_US +uint32_t rtc_subsec_to_us(uint32_t ss) { + return ((RTC_SYNCH_PREDIV - ss) * MEG_DIV_64) / MEG_DIV_SCALE; +} + +uint32_t rtc_us_to_subsec(uint32_t us) { + return RTC_SYNCH_PREDIV - (us * MEG_DIV_SCALE / MEG_DIV_64); +} +#else +#define rtc_us_to_subsec +#define rtc_subsec_to_us +#endif + +mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { + rtc_init_finalise(); + if (n_args == 1) { + // get date and time + // note: need to call get time then get date to correctly access the registers + RTC_DateTypeDef date; + RTC_TimeTypeDef time; + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); + mp_obj_t tuple[8] = { + mp_obj_new_int(2000 + date.Year), + mp_obj_new_int(date.Month), + mp_obj_new_int(date.Date), + mp_obj_new_int(date.WeekDay), + mp_obj_new_int(time.Hours), + mp_obj_new_int(time.Minutes), + mp_obj_new_int(time.Seconds), + mp_obj_new_int(rtc_subsec_to_us(time.SubSeconds)), + }; + return mp_obj_new_tuple(8, tuple); + } else { + // set date and time + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + RTC_DateTypeDef date; + date.Year = mp_obj_get_int(items[0]) - 2000; + date.Month = mp_obj_get_int(items[1]); + date.Date = mp_obj_get_int(items[2]); + date.WeekDay = mp_obj_get_int(items[3]); + HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN); + + RTC_TimeTypeDef time; + time.Hours = mp_obj_get_int(items[4]); + time.Minutes = mp_obj_get_int(items[5]); + time.Seconds = mp_obj_get_int(items[6]); + time.TimeFormat = RTC_HOURFORMAT12_AM; + time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; + time.StoreOperation = RTC_STOREOPERATION_SET; + HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + + return mp_const_none; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime); + +#if defined(STM32F0) +#define RTC_WKUP_IRQn RTC_IRQn +#endif + +// wakeup(None) +// wakeup(ms, callback=None) +// wakeup(wucksel, wut, callback) +mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { + // wut is wakeup counter start value, wucksel is clock source + // counter is decremented at wucksel rate, and wakes the MCU when it gets to 0 + // wucksel=0b000 is RTC/16 (RTC runs at 32768Hz) + // wucksel=0b001 is RTC/8 + // wucksel=0b010 is RTC/4 + // wucksel=0b011 is RTC/2 + // wucksel=0b100 is 1Hz clock + // wucksel=0b110 is 1Hz clock with 0x10000 added to wut + // so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc + + rtc_init_finalise(); + + // disable wakeup IRQ while we configure it + HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn); + + bool enable = false; + mp_int_t wucksel; + mp_int_t wut; + mp_obj_t callback = mp_const_none; + if (n_args <= 3) { + if (args[1] == mp_const_none) { + // disable wakeup + } else { + // time given in ms + mp_int_t ms = mp_obj_get_int(args[1]); + mp_int_t div = 2; + wucksel = 3; + while (div <= 16 && ms > 2000 * div) { + div *= 2; + wucksel -= 1; + } + if (div <= 16) { + wut = 32768 / div * ms / 1000; + } else { + // use 1Hz clock + wucksel = 4; + wut = ms / 1000; + if (wut > 0x10000) { + // wut too large for 16-bit register, try to offset by 0x10000 + wucksel = 6; + wut -= 0x10000; + if (wut > 0x10000) { + // wut still too large + mp_raise_ValueError("wakeup value too large"); + } + } + } + // wut register should be 1 less than desired value, but guard against wut=0 + if (wut > 0) { + wut -= 1; + } + enable = true; + } + if (n_args == 3) { + callback = args[2]; + } + } else { + // config values given directly + wucksel = mp_obj_get_int(args[1]); + wut = mp_obj_get_int(args[2]); + callback = args[3]; + enable = true; + } + + // set the callback + MP_STATE_PORT(pyb_extint_callback)[EXTI_RTC_WAKEUP] = callback; + + // disable register write protection + RTC->WPR = 0xca; + RTC->WPR = 0x53; + + // clear WUTE + RTC->CR &= ~RTC_CR_WUTE; + + // wait until WUTWF is set + while (!(RTC->ISR & RTC_ISR_WUTWF)) { + } + + if (enable) { + // program WUT + RTC->WUTR = wut; + + // set WUTIE to enable wakeup interrupts + // set WUTE to enable wakeup + // program WUCKSEL + RTC->CR = (RTC->CR & ~7) | (1 << 14) | (1 << 10) | (wucksel & 7); + + // enable register write protection + RTC->WPR = 0xff; + + // enable external interrupts on line EXTI_RTC_WAKEUP + #if defined(STM32L4) + EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP; + EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP; + EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; + #else + EXTI->IMR |= 1 << EXTI_RTC_WAKEUP; + EXTI->RTSR |= 1 << EXTI_RTC_WAKEUP; + #endif + + // clear interrupt flags + RTC->ISR &= ~RTC_ISR_WUTF; + #if defined(STM32L4) + EXTI->PR1 = 1 << EXTI_RTC_WAKEUP; + #elif defined(STM32H7) + EXTI_D1->PR1 = 1 << EXTI_RTC_WAKEUP; + #else + EXTI->PR = 1 << EXTI_RTC_WAKEUP; + #endif + + NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP); + HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); + + //printf("wut=%d wucksel=%d\n", wut, wucksel); + } else { + // clear WUTIE to disable interrupts + RTC->CR &= ~RTC_CR_WUTIE; + + // enable register write protection + RTC->WPR = 0xff; + + // disable external interrupts on line EXTI_RTC_WAKEUP + #if defined(STM32L4) + EXTI->IMR1 &= ~(1 << EXTI_RTC_WAKEUP); + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP; + #else + EXTI->IMR &= ~(1 << EXTI_RTC_WAKEUP); + #endif + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_wakeup_obj, 2, 4, pyb_rtc_wakeup); + +// calibration(None) +// calibration(cal) +// When an integer argument is provided, check that it falls in the range [-511 to 512] +// and set the calibration value; otherwise return calibration value +mp_obj_t pyb_rtc_calibration(size_t n_args, const mp_obj_t *args) { + rtc_init_finalise(); + mp_int_t cal; + if (n_args == 2) { + cal = mp_obj_get_int(args[1]); + mp_uint_t cal_p, cal_m; + if (cal < -511 || cal > 512) { +#if defined(MICROPY_HW_RTC_USE_CALOUT) && MICROPY_HW_RTC_USE_CALOUT + if ((cal & 0xfffe) == 0x0ffe) { + // turn on/off X18 (PC13) 512Hz output + // Note: + // Output will stay active even in VBAT mode (and inrease current) + if (cal & 1) { + HAL_RTCEx_SetCalibrationOutPut(&RTCHandle, RTC_CALIBOUTPUT_512HZ); + } else { + HAL_RTCEx_DeactivateCalibrationOutPut(&RTCHandle); + } + return mp_obj_new_int(cal & 1); + } else { + mp_raise_ValueError("calibration value out of range"); + } +#else + mp_raise_ValueError("calibration value out of range"); +#endif + } + if (cal > 0) { + cal_p = RTC_SMOOTHCALIB_PLUSPULSES_SET; + cal_m = 512 - cal; + } else { + cal_p = RTC_SMOOTHCALIB_PLUSPULSES_RESET; + cal_m = -cal; + } + HAL_RTCEx_SetSmoothCalib(&RTCHandle, RTC_SMOOTHCALIB_PERIOD_32SEC, cal_p, cal_m); + return mp_const_none; + } else { + // printf("CALR = 0x%x\n", (mp_uint_t) RTCHandle.Instance->CALR); // DEBUG + // Test if CALP bit is set in CALR: + if (RTCHandle.Instance->CALR & 0x8000) { + cal = 512 - (RTCHandle.Instance->CALR & 0x1ff); + } else { + cal = -(RTCHandle.Instance->CALR & 0x1ff); + } + return mp_obj_new_int(cal); + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_calibration_obj, 1, 2, pyb_rtc_calibration); + +STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_rtc_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_rtc_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&pyb_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_wakeup), MP_ROM_PTR(&pyb_rtc_wakeup_obj) }, + { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&pyb_rtc_calibration_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table); + +const mp_obj_type_t pyb_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = pyb_rtc_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_rtc_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/rtc.h b/src/openmv/src/micropython/ports/stm32/rtc.h new file mode 100755 index 0000000..307f888 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/rtc.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_RTC_H +#define MICROPY_INCLUDED_STM32_RTC_H + +extern RTC_HandleTypeDef RTCHandle; +extern const mp_obj_type_t pyb_rtc_type; + +void rtc_init_start(bool force_init); +void rtc_init_finalise(void); + +#endif // MICROPY_INCLUDED_STM32_RTC_H diff --git a/src/openmv/src/micropython/ports/stm32/sdcard.c b/src/openmv/src/micropython/ports/stm32/sdcard.c new file mode 100755 index 0000000..bb972be --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/sdcard.c @@ -0,0 +1,604 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" + +#include "sdcard.h" +#include "pin.h" +#include "pin_static_af.h" +#include "bufhelper.h" +#include "dma.h" +#include "irq.h" + +#if MICROPY_HW_HAS_SDCARD + +#if defined(STM32F7) || defined(STM32H7) || defined(STM32L4) + +// The F7 has 2 SDMMC units but at the moment we only support using one of them in +// a given build. If a boards config file defines MICROPY_HW_SDMMC2_CK then SDMMC2 +// is used, otherwise SDMMC1 is used. + +#if defined(MICROPY_HW_SDMMC2_CK) +#define SDIO SDMMC2 +#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC2_CLK_ENABLE() +#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC2_CLK_DISABLE() +#define SDMMC_IRQn SDMMC2_IRQn +#define SDMMC_DMA dma_SDMMC_2 +#else +#define SDIO SDMMC1 +#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE() +#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE() +#define SDMMC_IRQn SDMMC1_IRQn +#define SDMMC_DMA dma_SDIO_0 +#define STATIC_AF_SDMMC_CK STATIC_AF_SDMMC1_CK +#define STATIC_AF_SDMMC_CMD STATIC_AF_SDMMC1_CMD +#define STATIC_AF_SDMMC_D0 STATIC_AF_SDMMC1_D0 +#define STATIC_AF_SDMMC_D1 STATIC_AF_SDMMC1_D1 +#define STATIC_AF_SDMMC_D2 STATIC_AF_SDMMC1_D2 +#define STATIC_AF_SDMMC_D3 STATIC_AF_SDMMC1_D3 +#endif + +// The F7 & L4 series calls the peripheral SDMMC rather than SDIO, so provide some +// #defines for backwards compatability. + +#define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING +#define SDIO_CLOCK_EDGE_FALLING SDMMC_CLOCK_EDGE_FALLING + +#define SDIO_CLOCK_BYPASS_DISABLE SDMMC_CLOCK_BYPASS_DISABLE +#define SDIO_CLOCK_BYPASS_ENABLE SDMMC_CLOCK_BYPASS_ENABLE + +#define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE +#define SDIO_CLOCK_POWER_SAVE_ENABLE SDMMC_CLOCK_POWER_SAVE_ENABLE + +#define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B +#define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B +#define SDIO_BUS_WIDE_8B SDMMC_BUS_WIDE_8B + +#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE +#define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE + +#if defined(STM32H7) +#define GPIO_AF12_SDIO GPIO_AF12_SDIO1 +#define SDIO_IRQHandler SDMMC1_IRQHandler +#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV +#define SDIO_USE_GPDMA 0 +#else +#define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV +#define SDIO_USE_GPDMA 1 +#endif + +#else + +// These are definitions for F4 MCUs so there is a common macro across all MCUs. + +#define SDMMC_CLK_ENABLE() __SDIO_CLK_ENABLE() +#define SDMMC_CLK_DISABLE() __SDIO_CLK_DISABLE() +#define SDMMC_IRQn SDIO_IRQn +#define SDMMC_DMA dma_SDIO_0 +#define SDIO_USE_GPDMA 1 +#define STATIC_AF_SDMMC_CK STATIC_AF_SDIO_CK +#define STATIC_AF_SDMMC_CMD STATIC_AF_SDIO_CMD +#define STATIC_AF_SDMMC_D0 STATIC_AF_SDIO_D0 +#define STATIC_AF_SDMMC_D1 STATIC_AF_SDIO_D1 +#define STATIC_AF_SDMMC_D2 STATIC_AF_SDIO_D2 +#define STATIC_AF_SDMMC_D3 STATIC_AF_SDIO_D3 + +#endif + +// If no custom SDIO pins defined, use the default ones +#ifndef MICROPY_HW_SDMMC_CK + +#define MICROPY_HW_SDMMC_D0 (pin_C8) +#define MICROPY_HW_SDMMC_D1 (pin_C9) +#define MICROPY_HW_SDMMC_D2 (pin_C10) +#define MICROPY_HW_SDMMC_D3 (pin_C11) +#define MICROPY_HW_SDMMC_CK (pin_C12) +#define MICROPY_HW_SDMMC_CMD (pin_D2) + +#endif + +// TODO: I think that as an optimization, we can allocate these dynamically +// if an sd card is detected. This will save approx 260 bytes of RAM +// when no sdcard was being used. +static SD_HandleTypeDef sd_handle; + +void sdcard_init(void) { + // invalidate the sd_handle + sd_handle.Instance = NULL; + + // configure SD GPIO + // we do this here an not in HAL_SD_MspInit because it apparently + // makes it more robust to have the pins always pulled high + // Note: the mp_hal_pin_config function will configure the GPIO in + // fast mode which can do up to 50MHz. This should be plenty for SDIO + // which clocks up to 25MHz maximum. + #if defined(MICROPY_HW_SDMMC2_CK) + // Use SDMMC2 peripheral with pins provided by the board's config + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CK); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_CMD); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D0); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D1); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D2); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC2_D3); + #else + // Default SDIO/SDMMC1 config + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D0); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D1); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D2); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_D3); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CK); + mp_hal_pin_config_alt_static(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDMMC_CMD); + #endif + + // configure the SD card detect pin + // we do this here so we can detect if the SD card is inserted before powering it on + mp_hal_pin_config(MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); +} + +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { + // enable SDIO clock + SDMMC_CLK_ENABLE(); + + #if defined(STM32H7) + // Reset SDMMC + __HAL_RCC_SDMMC1_FORCE_RESET(); + __HAL_RCC_SDMMC1_RELEASE_RESET(); + #endif + + // NVIC configuration for SDIO interrupts + NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO); + HAL_NVIC_EnableIRQ(SDMMC_IRQn); + + // GPIO have already been initialised by sdcard_init +} + +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { + HAL_NVIC_DisableIRQ(SDMMC_IRQn); + SDMMC_CLK_DISABLE(); +} + +bool sdcard_is_present(void) { + return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN->gpio, MICROPY_HW_SDCARD_DETECT_PIN->pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; +} + +bool sdcard_power_on(void) { + if (!sdcard_is_present()) { + return false; + } + if (sd_handle.Instance) { + return true; + } + + // SD device interface configuration + sd_handle.Instance = SDIO; + sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + #ifndef STM32H7 + sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + #endif + sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; + sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B; + sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; + + // init the SD interface, with retry if it's not ready yet + for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) { + if (retry == 0) { + goto error; + } + mp_hal_delay_ms(50); + } + + // configure the SD bus width for wide operation + #if defined(STM32F7) + // use maximum SDMMC clock speed on F7 MCUs + sd_handle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE; + #endif + if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) { + HAL_SD_DeInit(&sd_handle); + goto error; + } + + return true; + +error: + sd_handle.Instance = NULL; + return false; +} + +void sdcard_power_off(void) { + if (!sd_handle.Instance) { + return; + } + HAL_SD_DeInit(&sd_handle); + sd_handle.Instance = NULL; +} + +uint64_t sdcard_get_capacity_in_bytes(void) { + if (sd_handle.Instance == NULL) { + return 0; + } + HAL_SD_CardInfoTypeDef cardinfo; + HAL_SD_GetCardInfo(&sd_handle, &cardinfo); + return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; +} + +#if !defined(MICROPY_HW_SDMMC2_CK) +void SDIO_IRQHandler(void) { + IRQ_ENTER(SDIO_IRQn); + HAL_SD_IRQHandler(&sd_handle); + IRQ_EXIT(SDIO_IRQn); +} +#endif + +#if defined(STM32F7) +void SDMMC2_IRQHandler(void) { + IRQ_ENTER(SDMMC2_IRQn); + HAL_SD_IRQHandler(&sd_handle); + IRQ_EXIT(SDMMC2_IRQn); +} +#endif + +STATIC void sdcard_reset_periph(void) { + // Fully reset the SDMMC peripheral before calling HAL SD DMA functions. + // (There could be an outstanding DTIMEOUT event from a previous call and the + // HAL function enables IRQs before fully configuring the SDMMC peripheral.) + sd_handle.Instance->DTIMER = 0; + sd_handle.Instance->DLEN = 0; + sd_handle.Instance->DCTRL = 0; + sd_handle.Instance->ICR = SDMMC_STATIC_FLAGS; +} + +STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) { + // Wait for HAL driver to be ready (eg for DMA to finish) + uint32_t start = HAL_GetTick(); + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (sd->State != HAL_SD_STATE_BUSY) { + enable_irq(irq_state); + break; + } + __WFI(); + enable_irq(irq_state); + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + } + + // Wait for SD card to complete the operation + for (;;) { + HAL_SD_CardStateTypedef state = HAL_SD_GetCardState(sd); + if (state == HAL_SD_CARD_TRANSFER) { + return HAL_OK; + } + if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING || state == HAL_SD_CARD_PROGRAMMING)) { + return HAL_ERROR; + } + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + __WFI(); + } + return HAL_OK; +} + +mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return HAL_ERROR; + } + + HAL_StatusTypeDef err = HAL_OK; + + // check that dest pointer is aligned on a 4-byte boundary + uint8_t *orig_dest = NULL; + uint32_t saved_word; + if (((uint32_t)dest & 3) != 0) { + // Pointer is not aligned so it needs fixing. + // We could allocate a temporary block of RAM (as sdcard_write_blocks + // does) but instead we are going to use the dest buffer inplace. We + // are going to align the pointer, save the initial word at the aligned + // location, read into the aligned memory, move the memory back to the + // unaligned location, then restore the initial bytes at the aligned + // location. We should have no trouble doing this as those initial + // bytes at the aligned location should be able to be changed for the + // duration of this function call. + orig_dest = dest; + dest = (uint8_t*)((uint32_t)dest & ~3); + saved_word = *(uint32_t*)dest; + } + + if (query_irq() == IRQ_STATE_ENABLED) { + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + #if SDIO_USE_GPDMA + DMA_HandleTypeDef sd_dma; + dma_init(&sd_dma, &SDMMC_DMA, DMA_PERIPH_TO_MEMORY, &sd_handle); + sd_handle.hdmarx = &sd_dma; + #endif + + // make sure cache is flushed and invalidated so when DMA updates the RAM + // from reading the peripheral the CPU then reads the new data + MP_HAL_CLEANINVALIDATE_DCACHE(dest, num_blocks * SDCARD_BLOCK_SIZE); + + sdcard_reset_periph(); + err = HAL_SD_ReadBlocks_DMA(&sd_handle, dest, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 60000); + } + + #if SDIO_USE_GPDMA + dma_deinit(&SDMMC_DMA); + sd_handle.hdmarx = NULL; + #endif + + restore_irq_pri(basepri); + } else { + err = HAL_SD_ReadBlocks(&sd_handle, dest, block_num, num_blocks, 60000); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 60000); + } + } + + if (orig_dest != NULL) { + // move the read data to the non-aligned position, and restore the initial bytes + memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE); + memcpy(dest, &saved_word, orig_dest - dest); + } + + return err; +} + +mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return HAL_ERROR; + } + + HAL_StatusTypeDef err = HAL_OK; + + // check that src pointer is aligned on a 4-byte boundary + if (((uint32_t)src & 3) != 0) { + // pointer is not aligned, so allocate a temporary block to do the write + uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE); + if (src_aligned == NULL) { + return HAL_ERROR; + } + for (size_t i = 0; i < num_blocks; ++i) { + memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE); + err = sdcard_write_blocks(src_aligned, block_num + i, 1); + if (err != HAL_OK) { + break; + } + } + m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE); + return err; + } + + if (query_irq() == IRQ_STATE_ENABLED) { + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + #if SDIO_USE_GPDMA + DMA_HandleTypeDef sd_dma; + dma_init(&sd_dma, &SDMMC_DMA, DMA_MEMORY_TO_PERIPH, &sd_handle); + sd_handle.hdmatx = &sd_dma; + #endif + + // make sure cache is flushed to RAM so the DMA can read the correct data + MP_HAL_CLEAN_DCACHE(src, num_blocks * SDCARD_BLOCK_SIZE); + + sdcard_reset_periph(); + err = HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t*)src, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 60000); + } + + #if SDIO_USE_GPDMA + dma_deinit(&SDMMC_DMA); + sd_handle.hdmatx = NULL; + #endif + + restore_irq_pri(basepri); + } else { + err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t*)src, block_num, num_blocks, 60000); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 60000); + } + } + + return err; +} + +/******************************************************************************/ +// MicroPython bindings +// +// Expose the SD card as an object with the block protocol. + +// there is a singleton SDCard object +const mp_obj_base_t pyb_sdcard_obj = {&pyb_sdcard_type}; + +STATIC mp_obj_t pyb_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return singleton object + return MP_OBJ_FROM_PTR(&pyb_sdcard_obj); +} + +STATIC mp_obj_t sd_present(mp_obj_t self) { + return mp_obj_new_bool(sdcard_is_present()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_present_obj, sd_present); + +STATIC mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) { + bool result; + if (mp_obj_is_true(state)) { + result = sdcard_power_on(); + } else { + sdcard_power_off(); + result = true; + } + return mp_obj_new_bool(result); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power); + +STATIC mp_obj_t sd_info(mp_obj_t self) { + if (sd_handle.Instance == NULL) { + return mp_const_none; + } + HAL_SD_CardInfoTypeDef cardinfo; + HAL_SD_GetCardInfo(&sd_handle, &cardinfo); + // cardinfo.SD_csd and cardinfo.SD_cid have lots of info but we don't use them + mp_obj_t tuple[3] = { + mp_obj_new_int_from_ull((uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize), + mp_obj_new_int_from_uint(cardinfo.LogBlockSize), + mp_obj_new_int(cardinfo.CardType), + }; + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info); + +// now obsolete, kept for backwards compatibility +STATIC mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) { + uint8_t *dest = m_new(uint8_t, SDCARD_BLOCK_SIZE); + mp_uint_t ret = sdcard_read_blocks(dest, mp_obj_get_int(block_num), 1); + + if (ret != 0) { + m_del(uint8_t, dest, SDCARD_BLOCK_SIZE); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_read_blocks failed [%u]", ret)); + } + + return mp_obj_new_bytearray_by_ref(SDCARD_BLOCK_SIZE, dest); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read); + +// now obsolete, kept for backwards compatibility +STATIC mp_obj_t sd_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len % SDCARD_BLOCK_SIZE != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writes must be a multiple of %d bytes", SDCARD_BLOCK_SIZE)); + } + + mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE); + + if (ret != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_write_blocks failed [%u]", ret)); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(sd_write_obj, sd_write); + +STATIC mp_obj_t pyb_sdcard_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + mp_uint_t ret = sdcard_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE); + return mp_obj_new_bool(ret == 0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_readblocks_obj, pyb_sdcard_readblocks); + +STATIC mp_obj_t pyb_sdcard_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE); + return mp_obj_new_bool(ret == 0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_writeblocks_obj, pyb_sdcard_writeblocks); + +STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: + if (!sdcard_power_on()) { + return MP_OBJ_NEW_SMALL_INT(-1); // error + } + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_DEINIT: + sdcard_power_off(); + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SYNC: + // nothing to do + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SEC_COUNT: + return MP_OBJ_NEW_SMALL_INT(sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE); + + case BP_IOCTL_SEC_SIZE: + return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE); + + default: // unknown command + return MP_OBJ_NEW_SMALL_INT(-1); // error + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_sdcard_ioctl_obj, pyb_sdcard_ioctl); + +STATIC const mp_rom_map_elem_t pyb_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_present), MP_ROM_PTR(&sd_present_obj) }, + { MP_ROM_QSTR(MP_QSTR_power), MP_ROM_PTR(&sd_power_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&sd_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&sd_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&sd_write_obj) }, + // block device protocol + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_sdcard_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_sdcard_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_sdcard_locals_dict, pyb_sdcard_locals_dict_table); + +const mp_obj_type_t pyb_sdcard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = pyb_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_sdcard_locals_dict, +}; + +void sdcard_init_vfs(fs_user_mount_t *vfs, int part) { + vfs->base.type = &mp_fat_vfs_type; + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->fatfs.drv = vfs; + vfs->fatfs.part = part; + vfs->readblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_readblocks_obj); + vfs->readblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); + vfs->readblocks[2] = MP_OBJ_FROM_PTR(sdcard_read_blocks); // native version + vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_writeblocks_obj); + vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); + vfs->writeblocks[2] = MP_OBJ_FROM_PTR(sdcard_write_blocks); // native version + vfs->u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_sdcard_ioctl_obj); + vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_sdcard_obj); +} + +#endif // MICROPY_HW_HAS_SDCARD diff --git a/src/openmv/src/micropython/ports/stm32/sdcard.h b/src/openmv/src/micropython/ports/stm32/sdcard.h new file mode 100755 index 0000000..4afc258 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/sdcard.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_SDCARD_H +#define MICROPY_INCLUDED_STM32_SDCARD_H + +// this is a fixed size and should not be changed +#define SDCARD_BLOCK_SIZE (512) + +void sdcard_init(void); +bool sdcard_is_present(void); +bool sdcard_power_on(void); +void sdcard_power_off(void); +uint64_t sdcard_get_capacity_in_bytes(void); + +// these return 0 on success, non-zero on error +mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); + +extern const struct _mp_obj_type_t pyb_sdcard_type; +extern const struct _mp_obj_base_t pyb_sdcard_obj; + +struct _fs_user_mount_t; +void sdcard_init_vfs(struct _fs_user_mount_t *vfs, int part); + +#endif // MICROPY_INCLUDED_STM32_SDCARD_H diff --git a/src/openmv/src/micropython/ports/stm32/sdram.c b/src/openmv/src/micropython/ports/stm32/sdram.c new file mode 100755 index 0000000..6350b1d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/sdram.c @@ -0,0 +1,315 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SDRAM Driver. + * + */ +#include +#include +#include +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" +#include "pin_static_af.h" +#include "systick.h" +#include "sdram.h" + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +#if defined(MICROPY_HW_FMC_SDCKE0) && defined(MICROPY_HW_FMC_SDNE0) +#define FMC_SDRAM_BANK FMC_SDRAM_BANK1 +#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK1 +#define SDRAM_START_ADDRESS 0xC0000000 +#elif defined(MICROPY_HW_FMC_SDCKE1) && defined(MICROPY_HW_FMC_SDNE1) +#define FMC_SDRAM_BANK FMC_SDRAM_BANK2 +#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK2 +#define SDRAM_START_ADDRESS 0xD0000000 +#endif + +#ifdef FMC_SDRAM_BANK + +static void sdram_init_seq(SDRAM_HandleTypeDef + *hsdram, FMC_SDRAM_CommandTypeDef *command); +extern void __fatal_error(const char *msg); + +bool sdram_init(void) { + SDRAM_HandleTypeDef hsdram; + FMC_SDRAM_TimingTypeDef SDRAM_Timing; + FMC_SDRAM_CommandTypeDef command; + + __HAL_RCC_FMC_CLK_ENABLE(); + + #if defined(MICROPY_HW_FMC_SDCKE0) + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCKE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCKE0); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNE0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNE0); + + #elif defined(MICROPY_HW_FMC_SDCKE1) + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCKE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCKE1); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNE1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNE1); + #endif + + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDCLK); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNCAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNCAS); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNRAS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNRAS); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDNWE, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_SDNWE); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_BA0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_BA0); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_BA1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_BA1); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL0); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL1); + #ifdef MICROPY_HW_FMC_NBL2 + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL2); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_NBL3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_NBL3); + #endif + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A0); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A1); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A2); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A3); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A4); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A5); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A6); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A7); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A8); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A9); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A10); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A11); + #ifdef MICROPY_HW_FMC_A12 + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_A12); + #endif + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D0); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D1); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D2); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D3); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D4); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D5); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D6); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D7); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D8, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D8); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D9, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D9); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D10, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D10); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D11); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D12); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D13, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D13); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D14); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D15); + #ifdef MICROPY_HW_FMC_D16 + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D16, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D16); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D17, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D17); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D18, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D18); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D19, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D19); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D20, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D20); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D21, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D21); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D22, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D22); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D23, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D23); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D24, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D24); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D25, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D25); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D26, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D26); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D27, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D27); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D28, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D28); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D29, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D29); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D30, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D30); + mp_hal_pin_config_alt_static(MICROPY_HW_FMC_D31, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_FMC_D31); + #endif + + /* SDRAM device configuration */ + hsdram.Instance = FMC_SDRAM_DEVICE; + /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ + /* TMRD: 2 Clock cycles */ + SDRAM_Timing.LoadToActiveDelay = MICROPY_HW_SDRAM_TIMING_TMRD; + /* TXSR: min=70ns (6x11.90ns) */ + SDRAM_Timing.ExitSelfRefreshDelay = MICROPY_HW_SDRAM_TIMING_TXSR; + /* TRAS */ + SDRAM_Timing.SelfRefreshTime = MICROPY_HW_SDRAM_TIMING_TRAS; + /* TRC */ + SDRAM_Timing.RowCycleDelay = MICROPY_HW_SDRAM_TIMING_TRC; + /* TWR */ + SDRAM_Timing.WriteRecoveryTime = MICROPY_HW_SDRAM_TIMING_TWR; + /* TRP */ + SDRAM_Timing.RPDelay = MICROPY_HW_SDRAM_TIMING_TRP; + /* TRCD */ + SDRAM_Timing.RCDDelay = MICROPY_HW_SDRAM_TIMING_TRCD; + + #define _FMC_INIT(x, n) x ## _ ## n + #define FMC_INIT(x, n) _FMC_INIT(x, n) + + hsdram.Init.SDBank = FMC_SDRAM_BANK; + hsdram.Init.ColumnBitsNumber = FMC_INIT(FMC_SDRAM_COLUMN_BITS_NUM, MICROPY_HW_SDRAM_COLUMN_BITS_NUM); + hsdram.Init.RowBitsNumber = FMC_INIT(FMC_SDRAM_ROW_BITS_NUM, MICROPY_HW_SDRAM_ROW_BITS_NUM); + hsdram.Init.MemoryDataWidth = FMC_INIT(FMC_SDRAM_MEM_BUS_WIDTH, MICROPY_HW_SDRAM_MEM_BUS_WIDTH); + hsdram.Init.InternalBankNumber = FMC_INIT(FMC_SDRAM_INTERN_BANKS_NUM, MICROPY_HW_SDRAM_INTERN_BANKS_NUM); + hsdram.Init.CASLatency = FMC_INIT(FMC_SDRAM_CAS_LATENCY, MICROPY_HW_SDRAM_CAS_LATENCY); + hsdram.Init.SDClockPeriod = FMC_INIT(FMC_SDRAM_CLOCK_PERIOD, MICROPY_HW_SDRAM_CLOCK_PERIOD); + hsdram.Init.ReadPipeDelay = FMC_INIT(FMC_SDRAM_RPIPE_DELAY, MICROPY_HW_SDRAM_RPIPE_DELAY); + hsdram.Init.ReadBurst = (MICROPY_HW_SDRAM_RBURST) ? FMC_SDRAM_RBURST_ENABLE : FMC_SDRAM_RBURST_DISABLE; + hsdram.Init.WriteProtection = (MICROPY_HW_SDRAM_WRITE_PROTECTION) ? FMC_SDRAM_WRITE_PROTECTION_ENABLE : FMC_SDRAM_WRITE_PROTECTION_DISABLE; + + /* Initialize the SDRAM controller */ + if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { + return false; + } + + sdram_init_seq(&hsdram, &command); + return true; +} + +void *sdram_start(void) { + return (void*)SDRAM_START_ADDRESS; +} + +void *sdram_end(void) { + return (void*)(SDRAM_START_ADDRESS + MICROPY_HW_SDRAM_SIZE); +} + +static void sdram_init_seq(SDRAM_HandleTypeDef + *hsdram, FMC_SDRAM_CommandTypeDef *command) +{ + /* Program the SDRAM external device */ + __IO uint32_t tmpmrd =0; + + /* Step 3: Configure a clock configuration enable command */ + command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 4: Insert 100 ms delay */ + HAL_Delay(100); + + /* Step 5: Configure a PALL (precharge all) command */ + command->CommandMode = FMC_SDRAM_CMD_PALL; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 6 : Configure a Auto-Refresh command */ + command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command->AutoRefreshNumber = MICROPY_HW_SDRAM_AUTOREFRESH_NUM; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 7: Program the external memory mode register */ + tmpmrd = (uint32_t)FMC_INIT(SDRAM_MODEREG_BURST_LENGTH, MICROPY_HW_SDRAM_BURST_LENGTH) | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + FMC_INIT(SDRAM_MODEREG_CAS_LATENCY, MICROPY_HW_SDRAM_CAS_LATENCY) | + SDRAM_MODEREG_OPERATING_MODE_STANDARD | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 8: Set the refresh rate counter + RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc + + RefreshCycles = 7.8125 us * 90 MHz = 703 + According to the formula on p.1665 of the reference manual, + we also need to subtract 20 from the value, so the target + refresh rate is 703 - 20 = 683. + */ + #define REFRESH_COUNT (MICROPY_HW_SDRAM_REFRESH_RATE * 90000 / 8192 - 20) + HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); + + #if defined(STM32F7) + /* Enable MPU for the SDRAM Memory Region to allow non-aligned + accesses (hard-fault otherwise) + */ + + MPU_Region_InitTypeDef MPU_InitStruct; + + /* Disable the MPU */ + HAL_MPU_Disable(); + + /* Configure the MPU attributes as Write-Through for External SDRAM */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; + MPU_InitStruct.Size = MPU_REGION_SIZE_256MB; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.SubRegionDisable = 0x00; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + /* Enable the MPU */ + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + #endif +} + +bool __attribute__((optimize("O0"))) sdram_test(bool fast) { + uint8_t const pattern = 0xaa; + uint8_t const antipattern = 0x55; + uint8_t *const mem_base = (uint8_t*)sdram_start(); + + /* test data bus */ + for (uint8_t i = 1; i; i <<= 1) { + *mem_base = i; + if (*mem_base != i) { + printf("data bus lines test failed! data (%d)\n", i); + __asm__ volatile ("BKPT"); + } + } + + /* test address bus */ + /* Check individual address lines */ + for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { + mem_base[i] = pattern; + if (mem_base[i] != pattern) { + printf("address bus lines test failed! address (%p)\n", &mem_base[i]); + __asm__ volatile ("BKPT"); + } + } + + /* Check for aliasing (overlaping addresses) */ + mem_base[0] = antipattern; + for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { + if (mem_base[i] != pattern) { + printf("address bus overlap %p\n", &mem_base[i]); + __asm__ volatile ("BKPT"); + } + } + + /* test all ram cells */ + if (!fast) { + for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; ++i) { + mem_base[i] = pattern; + if (mem_base[i] != pattern) { + printf("address bus test failed! address (%p)\n", &mem_base[i]); + __asm__ volatile ("BKPT"); + } + } + } else { + memset(mem_base, pattern, MICROPY_HW_SDRAM_SIZE); + } + + return true; +} + +#endif // FMC_SDRAM_BANK diff --git a/src/openmv/src/micropython/ports/stm32/sdram.h b/src/openmv/src/micropython/ports/stm32/sdram.h new file mode 100755 index 0000000..9b4b4fb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/sdram.h @@ -0,0 +1,15 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SDRAM Driver. + * + */ +#ifndef __SDRAM_H__ +#define __SDRAM_H__ +bool sdram_init(void); +void *sdram_start(void); +void *sdram_end(void); +bool sdram_test(bool fast); +#endif // __SDRAM_H__ diff --git a/src/openmv/src/micropython/ports/stm32/servo.c b/src/openmv/src/micropython/ports/stm32/servo.c new file mode 100755 index 0000000..4eb5b32 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/servo.c @@ -0,0 +1,333 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" +#include "timer.h" +#include "servo.h" + +#if MICROPY_HW_ENABLE_SERVO + +// This file implements the pyb.Servo class which controls standard hobby servo +// motors that have 3-wires (ground, power, signal). +// +// The driver uses hardware PWM to drive servos on pins X1, X2, X3, X4 which are +// assumed to be on PA0, PA1, PA2, PA3 but not necessarily in that order (the +// pins PA0-PA3 are used directly if the X pins are not defined). +// +// TIM2 and TIM5 have CH1-CH4 on PA0-PA3 respectively. They are both 32-bit +// counters with 16-bit prescaler. TIM5 is used by this driver. + +#define PYB_SERVO_NUM (4) + +typedef struct _pyb_servo_obj_t { + mp_obj_base_t base; + const pin_obj_t *pin; + uint8_t pulse_min; // units of 10us + uint8_t pulse_max; // units of 10us + uint8_t pulse_centre; // units of 10us + uint8_t pulse_angle_90; // units of 10us; pulse at 90 degrees, minus pulse_centre + uint8_t pulse_speed_100; // units of 10us; pulse at 100% forward speed, minus pulse_centre + uint16_t pulse_cur; // units of 10us + uint16_t pulse_dest; // units of 10us + int16_t pulse_accum; + uint16_t time_left; +} pyb_servo_obj_t; + +STATIC pyb_servo_obj_t pyb_servo_obj[PYB_SERVO_NUM]; + +void servo_init(void) { + timer_tim5_init(); + + // reset servo objects + for (int i = 0; i < PYB_SERVO_NUM; i++) { + pyb_servo_obj[i].base.type = &pyb_servo_type; + pyb_servo_obj[i].pulse_min = 64; + pyb_servo_obj[i].pulse_max = 242; + pyb_servo_obj[i].pulse_centre = 150; + pyb_servo_obj[i].pulse_angle_90 = 97; + pyb_servo_obj[i].pulse_speed_100 = 70; + pyb_servo_obj[i].pulse_cur = 150; + pyb_servo_obj[i].pulse_dest = 0; + pyb_servo_obj[i].time_left = 0; + } + + // assign servo objects to specific pins (must be some permutation of PA0-PA3) + #ifdef pyb_pin_X1 + pyb_servo_obj[0].pin = pyb_pin_X1; + pyb_servo_obj[1].pin = pyb_pin_X2; + pyb_servo_obj[2].pin = pyb_pin_X3; + pyb_servo_obj[3].pin = pyb_pin_X4; + #else + pyb_servo_obj[0].pin = pin_A0; + pyb_servo_obj[1].pin = pin_A1; + pyb_servo_obj[2].pin = pin_A2; + pyb_servo_obj[3].pin = pin_A3; + #endif +} + +void servo_timer_irq_callback(void) { + bool need_it = false; + for (int i = 0; i < PYB_SERVO_NUM; i++) { + pyb_servo_obj_t *s = &pyb_servo_obj[i]; + if (s->pulse_cur != s->pulse_dest) { + // clamp pulse to within min/max + if (s->pulse_dest < s->pulse_min) { + s->pulse_dest = s->pulse_min; + } else if (s->pulse_dest > s->pulse_max) { + s->pulse_dest = s->pulse_max; + } + // adjust cur to get closer to dest + if (s->time_left <= 1) { + s->pulse_cur = s->pulse_dest; + s->time_left = 0; + } else { + s->pulse_accum += s->pulse_dest - s->pulse_cur; + s->pulse_cur += s->pulse_accum / s->time_left; + s->pulse_accum %= s->time_left; + s->time_left--; + need_it = true; + } + // set the pulse width + *(&TIM5->CCR1 + s->pin->pin) = s->pulse_cur; + } + } + if (need_it) { + __HAL_TIM_ENABLE_IT(&TIM5_Handle, TIM_IT_UPDATE); + } else { + __HAL_TIM_DISABLE_IT(&TIM5_Handle, TIM_IT_UPDATE); + } +} + +STATIC void servo_init_channel(pyb_servo_obj_t *s) { + static const uint8_t channel_table[4] = + {TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4}; + uint32_t channel = channel_table[s->pin->pin]; + + // GPIO configuration + mp_hal_pin_config(s->pin, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF2_TIM5); + + // PWM mode configuration + TIM_OC_InitTypeDef oc_init; + oc_init.OCMode = TIM_OCMODE_PWM1; + oc_init.Pulse = s->pulse_cur; // units of 10us + oc_init.OCPolarity = TIM_OCPOLARITY_HIGH; + oc_init.OCFastMode = TIM_OCFAST_DISABLE; + HAL_TIM_PWM_ConfigChannel(&TIM5_Handle, &oc_init, channel); + + // start PWM + HAL_TIM_PWM_Start(&TIM5_Handle, channel); +} + +/******************************************************************************/ +// MicroPython bindings + +STATIC mp_obj_t pyb_servo_set(mp_obj_t port, mp_obj_t value) { + int p = mp_obj_get_int(port); + int v = mp_obj_get_int(value); + if (v < 50) { v = 50; } + if (v > 250) { v = 250; } + switch (p) { + case 1: TIM5->CCR1 = v; break; + case 2: TIM5->CCR2 = v; break; + case 3: TIM5->CCR3 = v; break; + case 4: TIM5->CCR4 = v; break; + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_2(pyb_servo_set_obj, pyb_servo_set); + +STATIC mp_obj_t pyb_pwm_set(mp_obj_t period, mp_obj_t pulse) { + int pe = mp_obj_get_int(period); + int pu = mp_obj_get_int(pulse); + TIM5->ARR = pe; + TIM5->CCR3 = pu; + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set); + +STATIC void pyb_servo_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_servo_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur); +} + +/// \classmethod \constructor(id) +/// Create a servo object. `id` is 1-4. +STATIC mp_obj_t pyb_servo_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get servo number + mp_int_t servo_id = mp_obj_get_int(args[0]) - 1; + + // check servo number + if (!(0 <= servo_id && servo_id < PYB_SERVO_NUM)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo(%d) doesn't exist", servo_id + 1)); + } + + // get and init servo object + pyb_servo_obj_t *s = &pyb_servo_obj[servo_id]; + s->pulse_dest = s->pulse_cur; + s->time_left = 0; + servo_init_channel(s); + + return MP_OBJ_FROM_PTR(s); +} + +/// \method pulse_width([value]) +/// Get or set the pulse width in milliseconds. +STATIC mp_obj_t pyb_servo_pulse_width(size_t n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get pulse width, in us + return mp_obj_new_int(10 * self->pulse_cur); + } else { + // set pulse width, in us + self->pulse_dest = mp_obj_get_int(args[1]) / 10; + self->time_left = 0; + servo_timer_irq_callback(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_pulse_width_obj, 1, 2, pyb_servo_pulse_width); + +/// \method calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]]) +/// Get or set the calibration of the servo timing. +// TODO should accept 1 arg, a 5-tuple of values to set +STATIC mp_obj_t pyb_servo_calibration(size_t n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get calibration values + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_int(10 * self->pulse_min); + tuple[1] = mp_obj_new_int(10 * self->pulse_max); + tuple[2] = mp_obj_new_int(10 * self->pulse_centre); + tuple[3] = mp_obj_new_int(10 * (self->pulse_angle_90 + self->pulse_centre)); + tuple[4] = mp_obj_new_int(10 * (self->pulse_speed_100 + self->pulse_centre)); + return mp_obj_new_tuple(5, tuple); + } else if (n_args >= 4) { + // set min, max, centre + self->pulse_min = mp_obj_get_int(args[1]) / 10; + self->pulse_max = mp_obj_get_int(args[2]) / 10; + self->pulse_centre = mp_obj_get_int(args[3]) / 10; + if (n_args == 4) { + return mp_const_none; + } else if (n_args == 6) { + self->pulse_angle_90 = mp_obj_get_int(args[4]) / 10 - self->pulse_centre; + self->pulse_speed_100 = mp_obj_get_int(args[5]) / 10 - self->pulse_centre; + return mp_const_none; + } + } + + // bad number of arguments + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "calibration expecting 1, 4 or 6 arguments, got %d", n_args)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_calibration_obj, 1, 6, pyb_servo_calibration); + +/// \method angle([angle, time=0]) +/// Get or set the angle of the servo. +/// +/// - `angle` is the angle to move to in degrees. +/// - `time` is the number of milliseconds to take to get to the specified angle. +STATIC mp_obj_t pyb_servo_angle(size_t n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get angle + return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 90 / self->pulse_angle_90); + } else { +#if MICROPY_PY_BUILTINS_FLOAT + self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_float(args[1]) / 90.0; +#else + self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_int(args[1]) / 90; +#endif + if (n_args == 2) { + // set angle immediately + self->time_left = 0; + } else { + // set angle over a given time (given in milli seconds) + self->time_left = mp_obj_get_int(args[2]) / 20; + self->pulse_accum = 0; + } + servo_timer_irq_callback(); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle); + +/// \method speed([speed, time=0]) +/// Get or set the speed of a continuous rotation servo. +/// +/// - `speed` is the speed to move to change to, between -100 and 100. +/// - `time` is the number of milliseconds to take to get to the specified speed. +STATIC mp_obj_t pyb_servo_speed(size_t n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get speed + return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 100 / self->pulse_speed_100); + } else { +#if MICROPY_PY_BUILTINS_FLOAT + self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_float(args[1]) / 100.0; +#else + self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_int(args[1]) / 100; +#endif + if (n_args == 2) { + // set speed immediately + self->time_left = 0; + } else { + // set speed over a given time (given in milli seconds) + self->time_left = mp_obj_get_int(args[2]) / 20; + self->pulse_accum = 0; + } + servo_timer_irq_callback(); + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_speed_obj, 1, 3, pyb_servo_speed); + +STATIC const mp_rom_map_elem_t pyb_servo_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_servo_pulse_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&pyb_servo_calibration_obj) }, + { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&pyb_servo_angle_obj) }, + { MP_ROM_QSTR(MP_QSTR_speed), MP_ROM_PTR(&pyb_servo_speed_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_servo_locals_dict, pyb_servo_locals_dict_table); + +const mp_obj_type_t pyb_servo_type = { + { &mp_type_type }, + .name = MP_QSTR_Servo, + .print = pyb_servo_print, + .make_new = pyb_servo_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_servo_locals_dict, +}; + +#endif // MICROPY_HW_ENABLE_SERVO diff --git a/src/openmv/src/micropython/ports/stm32/servo.h b/src/openmv/src/micropython/ports/stm32/servo.h new file mode 100755 index 0000000..0160568 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/servo.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_SERVO_H +#define MICROPY_INCLUDED_STM32_SERVO_H + +void servo_init(void); +void servo_timer_irq_callback(void); + +extern const mp_obj_type_t pyb_servo_type; + +MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); + +#endif // MICROPY_INCLUDED_STM32_SERVO_H diff --git a/src/openmv/src/micropython/ports/stm32/spi.c b/src/openmv/src/micropython/ports/stm32/spi.c new file mode 100755 index 0000000..06c6bce --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/spi.c @@ -0,0 +1,617 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "spi.h" + +// Possible DMA configurations for SPI busses: +// SPI1_TX: DMA2_Stream3.CHANNEL_3 or DMA2_Stream5.CHANNEL_3 +// SPI1_RX: DMA2_Stream0.CHANNEL_3 or DMA2_Stream2.CHANNEL_3 +// SPI2_TX: DMA1_Stream4.CHANNEL_0 +// SPI2_RX: DMA1_Stream3.CHANNEL_0 +// SPI3_TX: DMA1_Stream5.CHANNEL_0 or DMA1_Stream7.CHANNEL_0 +// SPI3_RX: DMA1_Stream0.CHANNEL_0 or DMA1_Stream2.CHANNEL_0 +// SPI4_TX: DMA2_Stream4.CHANNEL_5 or DMA2_Stream1.CHANNEL_4 +// SPI4_RX: DMA2_Stream3.CHANNEL_5 or DMA2_Stream0.CHANNEL_4 +// SPI5_TX: DMA2_Stream4.CHANNEL_2 or DMA2_Stream6.CHANNEL_7 +// SPI5_RX: DMA2_Stream3.CHANNEL_2 or DMA2_Stream5.CHANNEL_7 +// SPI6_TX: DMA2_Stream5.CHANNEL_1 +// SPI6_RX: DMA2_Stream6.CHANNEL_1 + +#if defined(MICROPY_HW_SPI1_SCK) +SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_SPI2_SCK) +SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_SPI3_SCK) +SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_SPI4_SCK) +SPI_HandleTypeDef SPIHandle4 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_SPI5_SCK) +SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_SPI6_SCK) +SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL}; +#endif + +const spi_t spi_obj[6] = { + #if defined(MICROPY_HW_SPI1_SCK) + {&SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, + #else + {NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_SPI2_SCK) + {&SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, + #else + {NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_SPI3_SCK) + {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, + #else + {NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_SPI4_SCK) + {&SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, + #else + {NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_SPI5_SCK) + {&SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, + #else + {NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_SPI6_SCK) + {&SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, + #else + {NULL, NULL, NULL}, + #endif +}; + +void spi_init0(void) { + // Initialise the SPI handles. + // The structs live on the BSS so all other fields will be zero after a reset. + #if defined(MICROPY_HW_SPI1_SCK) + SPIHandle1.Instance = SPI1; + #endif + #if defined(MICROPY_HW_SPI2_SCK) + SPIHandle2.Instance = SPI2; + #endif + #if defined(MICROPY_HW_SPI3_SCK) + SPIHandle3.Instance = SPI3; + #endif + #if defined(MICROPY_HW_SPI4_SCK) + SPIHandle4.Instance = SPI4; + #endif + #if defined(MICROPY_HW_SPI5_SCK) + SPIHandle5.Instance = SPI5; + #endif + #if defined(MICROPY_HW_SPI6_SCK) + SPIHandle6.Instance = SPI6; + #endif +} + +int spi_find_index(mp_obj_t id) { + if (MP_OBJ_IS_STR(id)) { + // given a string id + const char *port = mp_obj_str_get_str(id); + if (0) { + #ifdef MICROPY_HW_SPI1_NAME + } else if (strcmp(port, MICROPY_HW_SPI1_NAME) == 0) { + return 1; + #endif + #ifdef MICROPY_HW_SPI2_NAME + } else if (strcmp(port, MICROPY_HW_SPI2_NAME) == 0) { + return 2; + #endif + #ifdef MICROPY_HW_SPI3_NAME + } else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) { + return 3; + #endif + #ifdef MICROPY_HW_SPI4_NAME + } else if (strcmp(port, MICROPY_HW_SPI4_NAME) == 0) { + return 4; + #endif + #ifdef MICROPY_HW_SPI5_NAME + } else if (strcmp(port, MICROPY_HW_SPI5_NAME) == 0) { + return 5; + #endif + #ifdef MICROPY_HW_SPI6_NAME + } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) { + return 6; + #endif + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%s) doesn't exist", port)); + } else { + // given an integer id + int spi_id = mp_obj_get_int(id); + if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(spi_obj) + && spi_obj[spi_id - 1].spi != NULL) { + return spi_id; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "SPI(%d) doesn't exist", spi_id)); + } +} + +// sets the parameters in the SPI_InitTypeDef struct +// if an argument is -1 then the corresponding parameter is not changed +void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, + int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) { + SPI_HandleTypeDef *spi = spi_obj->spi; + SPI_InitTypeDef *init = &spi->Init; + + if (prescale != 0xffffffff || baudrate != -1) { + if (prescale == 0xffffffff) { + // prescaler not given, so select one that yields at most the requested baudrate + mp_uint_t spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32H7) + if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); + } else if (spi->Instance == SPI4 || spi->Instance == SPI5) { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); + } else { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); + } + #else + if (spi->Instance == SPI2 || spi->Instance == SPI3) { + // SPI2 and SPI3 are on APB1 + spi_clock = HAL_RCC_GetPCLK1Freq(); + } else { + // SPI1, SPI4, SPI5 and SPI6 are on APB2 + spi_clock = HAL_RCC_GetPCLK2Freq(); + } + #endif + prescale = (spi_clock + baudrate - 1) / baudrate; + } + if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } + else if (prescale <= 4) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; } + else if (prescale <= 8) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; } + else if (prescale <= 16) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; } + else if (prescale <= 32) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; } + else if (prescale <= 64) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; } + else if (prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; } + else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; } + } + + if (polarity != -1) { + init->CLKPolarity = polarity == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; + } + + if (phase != -1) { + init->CLKPhase = phase == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; + } + + if (bits != -1) { + init->DataSize = (bits == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; + } + + if (firstbit != -1) { + init->FirstBit = firstbit; + } +} + +// TODO allow to take a list of pins to use +void spi_init(const spi_t *self, bool enable_nss_pin) { + SPI_HandleTypeDef *spi = self->spi; + const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL }; + + if (0) { + #if defined(MICROPY_HW_SPI1_SCK) + } else if (spi->Instance == SPI1) { + #if defined(MICROPY_HW_SPI1_NSS) + pins[0] = MICROPY_HW_SPI1_NSS; + #endif + pins[1] = MICROPY_HW_SPI1_SCK; + #if defined(MICROPY_HW_SPI1_MISO) + pins[2] = MICROPY_HW_SPI1_MISO; + #endif + pins[3] = MICROPY_HW_SPI1_MOSI; + // enable the SPI clock + __HAL_RCC_SPI1_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_SPI2_SCK) + } else if (spi->Instance == SPI2) { + #if defined(MICROPY_HW_SPI2_NSS) + pins[0] = MICROPY_HW_SPI2_NSS; + #endif + pins[1] = MICROPY_HW_SPI2_SCK; + #if defined(MICROPY_HW_SPI2_MISO) + pins[2] = MICROPY_HW_SPI2_MISO; + #endif + pins[3] = MICROPY_HW_SPI2_MOSI; + // enable the SPI clock + __HAL_RCC_SPI2_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_SPI3_SCK) + } else if (spi->Instance == SPI3) { + #if defined(MICROPY_HW_SPI3_NSS) + pins[0] = MICROPY_HW_SPI3_NSS; + #endif + pins[1] = MICROPY_HW_SPI3_SCK; + #if defined(MICROPY_HW_SPI3_MISO) + pins[2] = MICROPY_HW_SPI3_MISO; + #endif + pins[3] = MICROPY_HW_SPI3_MOSI; + // enable the SPI clock + __HAL_RCC_SPI3_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_SPI4_SCK) + } else if (spi->Instance == SPI4) { + #if defined(MICROPY_HW_SPI4_NSS) + pins[0] = MICROPY_HW_SPI4_NSS; + #endif + pins[1] = MICROPY_HW_SPI4_SCK; + #if defined(MICROPY_HW_SPI4_MISO) + pins[2] = MICROPY_HW_SPI4_MISO; + #endif + pins[3] = MICROPY_HW_SPI4_MOSI; + // enable the SPI clock + __HAL_RCC_SPI4_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_SPI5_SCK) + } else if (spi->Instance == SPI5) { + #if defined(MICROPY_HW_SPI5_NSS) + pins[0] = MICROPY_HW_SPI5_NSS; + #endif + pins[1] = MICROPY_HW_SPI5_SCK; + #if defined(MICROPY_HW_SPI5_MISO) + pins[2] = MICROPY_HW_SPI5_MISO; + #endif + pins[3] = MICROPY_HW_SPI5_MOSI; + // enable the SPI clock + __HAL_RCC_SPI5_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_SPI6_SCK) + } else if (spi->Instance == SPI6) { + #if defined(MICROPY_HW_SPI6_NSS) + pins[0] = MICROPY_HW_SPI6_NSS; + #endif + pins[1] = MICROPY_HW_SPI6_SCK; + #if defined(MICROPY_HW_SPI6_MISO) + pins[2] = MICROPY_HW_SPI6_MISO; + #endif + pins[3] = MICROPY_HW_SPI6_MOSI; + // enable the SPI clock + __HAL_RCC_SPI6_CLK_ENABLE(); + #endif + } else { + // SPI does not exist for this board (shouldn't get here, should be checked by caller) + return; + } + + // init the GPIO lines + uint32_t mode = MP_HAL_PIN_MODE_ALT; + uint32_t pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? MP_HAL_PIN_PULL_DOWN : MP_HAL_PIN_PULL_UP; + for (uint i = (enable_nss_pin ? 0 : 1); i < 4; i++) { + if (pins[i] == NULL) { + continue; + } + mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &spi_obj[0]) + 1); + } + + // init the SPI device + if (HAL_SPI_Init(spi) != HAL_OK) { + // init error + // TODO should raise an exception, but this function is not necessarily going to be + // called via Python, so may not be properly wrapped in an NLR handler + printf("OSError: HAL_SPI_Init failed\n"); + return; + } + + // After calling HAL_SPI_Init() it seems that the DMA gets disconnected if + // it was previously configured. So we invalidate the DMA channel to force + // an initialisation the next time we use it. + dma_invalidate_channel(self->tx_dma_descr); + dma_invalidate_channel(self->rx_dma_descr); +} + +void spi_deinit(const spi_t *spi_obj) { + SPI_HandleTypeDef *spi = spi_obj->spi; + HAL_SPI_DeInit(spi); + if (0) { + #if defined(MICROPY_HW_SPI1_SCK) + } else if (spi->Instance == SPI1) { + __HAL_RCC_SPI1_FORCE_RESET(); + __HAL_RCC_SPI1_RELEASE_RESET(); + __HAL_RCC_SPI1_CLK_DISABLE(); + #endif + #if defined(MICROPY_HW_SPI2_SCK) + } else if (spi->Instance == SPI2) { + __HAL_RCC_SPI2_FORCE_RESET(); + __HAL_RCC_SPI2_RELEASE_RESET(); + __HAL_RCC_SPI2_CLK_DISABLE(); + #endif + #if defined(MICROPY_HW_SPI3_SCK) + } else if (spi->Instance == SPI3) { + __HAL_RCC_SPI3_FORCE_RESET(); + __HAL_RCC_SPI3_RELEASE_RESET(); + __HAL_RCC_SPI3_CLK_DISABLE(); + #endif + #if defined(MICROPY_HW_SPI4_SCK) + } else if (spi->Instance == SPI4) { + __HAL_RCC_SPI4_FORCE_RESET(); + __HAL_RCC_SPI4_RELEASE_RESET(); + __HAL_RCC_SPI4_CLK_DISABLE(); + #endif + #if defined(MICROPY_HW_SPI5_SCK) + } else if (spi->Instance == SPI5) { + __HAL_RCC_SPI5_FORCE_RESET(); + __HAL_RCC_SPI5_RELEASE_RESET(); + __HAL_RCC_SPI5_CLK_DISABLE(); + #endif + #if defined(MICROPY_HW_SPI6_SCK) + } else if (spi->Instance == SPI6) { + __HAL_RCC_SPI6_FORCE_RESET(); + __HAL_RCC_SPI6_RELEASE_RESET(); + __HAL_RCC_SPI6_CLK_DISABLE(); + #endif + } +} + +STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) { + volatile HAL_SPI_StateTypeDef *state = &spi->spi->State; + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (*state == HAL_SPI_STATE_READY) { + enable_irq(irq_state); + return HAL_OK; + } + __WFI(); + enable_irq(irq_state); + if (HAL_GetTick() - t_start >= timeout) { + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { + // Note: there seems to be a problem sending 1 byte using DMA the first + // time directly after the SPI/DMA is initialised. The cause of this is + // unknown but we sidestep the issue by using polling for 1 byte transfer. + + // Note: DMA transfers are limited to 65535 bytes at a time. + + HAL_StatusTypeDef status; + + if (dest == NULL) { + // send only + if (len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Transmit(self->spi, (uint8_t*)src, len, timeout); + } else { + DMA_HandleTypeDef tx_dma; + dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi); + self->spi->hdmatx = &tx_dma; + self->spi->hdmarx = NULL; + MP_HAL_CLEAN_DCACHE(src, len); + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + } while (len); + dma_deinit(self->tx_dma_descr); + } + } else if (src == NULL) { + // receive only + if (len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Receive(self->spi, dest, len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + if (self->spi->Init.Mode == SPI_MODE_MASTER) { + // in master mode the HAL actually does a TransmitReceive call + dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi); + self->spi->hdmatx = &tx_dma; + } else { + self->spi->hdmatx = NULL; + } + dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->spi); + self->spi->hdmarx = &rx_dma; + MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Receive_DMA(self->spi, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + dest += l; + } while (len); + if (self->spi->hdmatx != NULL) { + dma_deinit(self->tx_dma_descr); + } + dma_deinit(self->rx_dma_descr); + } + } else { + // send and receive + if (len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_TransmitReceive(self->spi, (uint8_t*)src, dest, len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + dma_init(&tx_dma, self->tx_dma_descr, DMA_MEMORY_TO_PERIPH, self->spi); + self->spi->hdmatx = &tx_dma; + dma_init(&rx_dma, self->rx_dma_descr, DMA_PERIPH_TO_MEMORY, self->spi); + self->spi->hdmarx = &rx_dma; + MP_HAL_CLEAN_DCACHE(src, len); + MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + dest += l; + } while (len); + dma_deinit(self->tx_dma_descr); + dma_deinit(self->rx_dma_descr); + } + } + + if (status != HAL_OK) { + mp_hal_raise(status); + } +} + +void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { + SPI_HandleTypeDef *spi = spi_obj->spi; + + uint spi_num = 1; // default to SPI1 + if (spi->Instance == SPI2) { spi_num = 2; } + #if defined(SPI3) + else if (spi->Instance == SPI3) { spi_num = 3; } + #endif + #if defined(SPI4) + else if (spi->Instance == SPI4) { spi_num = 4; } + #endif + #if defined(SPI5) + else if (spi->Instance == SPI5) { spi_num = 5; } + #endif + #if defined(SPI6) + else if (spi->Instance == SPI6) { spi_num = 6; } + #endif + + mp_printf(print, "SPI(%u", spi_num); + if (spi->State != HAL_SPI_STATE_RESET) { + if (spi->Init.Mode == SPI_MODE_MASTER) { + // compute baudrate + uint spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32H7) + if (spi->Instance == SPI1 || spi->Instance == SPI2 || spi->Instance == SPI3) { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123); + } else if (spi->Instance == SPI4 || spi->Instance == SPI5) { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45); + } else { + spi_clock = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6); + } + #else + if (spi->Instance == SPI2 || spi->Instance == SPI3) { + // SPI2 and SPI3 are on APB1 + spi_clock = HAL_RCC_GetPCLK1Freq(); + } else { + // SPI1, SPI4, SPI5 and SPI6 are on APB2 + spi_clock = HAL_RCC_GetPCLK2Freq(); + } + #endif + uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1; + uint baudrate = spi_clock >> log_prescaler; + if (legacy) { + mp_printf(print, ", SPI.MASTER"); + } + mp_printf(print, ", baudrate=%u", baudrate); + if (legacy) { + mp_printf(print, ", prescaler=%u", 1 << log_prescaler); + } + } else { + mp_printf(print, ", SPI.SLAVE"); + } + mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16); + if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) { + mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial); + } + } + mp_print_str(print, ")"); +} + +const spi_t *spi_from_mp_obj(mp_obj_t o) { + if (MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { + pyb_spi_obj_t *self = MP_OBJ_TO_PTR(o); + return self->spi; + } else if (MP_OBJ_IS_TYPE(o, &machine_hard_spi_type)) { + machine_hard_spi_obj_t *self = MP_OBJ_TO_PTR(o); + return self->spi; + } else { + mp_raise_TypeError("expecting an SPI object"); + } +} + +/******************************************************************************/ +// Implementation of low-level SPI C protocol + +STATIC int spi_proto_ioctl(void *self_in, uint32_t cmd) { + spi_proto_cfg_t *self = (spi_proto_cfg_t*)self_in; + + switch (cmd) { + case MP_SPI_IOCTL_INIT: + self->spi->spi->Init.Mode = SPI_MODE_MASTER; + self->spi->spi->Init.Direction = SPI_DIRECTION_2LINES; + self->spi->spi->Init.NSS = SPI_NSS_SOFT; + self->spi->spi->Init.TIMode = SPI_TIMODE_DISABLE; + self->spi->spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + spi_set_params(self->spi, 0xffffffff, self->baudrate, + self->polarity, self->phase, self->bits, self->firstbit); + spi_init(self->spi, false); + break; + + case MP_SPI_IOCTL_DEINIT: + spi_deinit(self->spi); + break; + } + + return 0; +} + +STATIC void spi_proto_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + spi_proto_cfg_t *self = (spi_proto_cfg_t*)self_in; + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); +} + +const mp_spi_proto_t spi_proto = { + .ioctl = spi_proto_ioctl, + .transfer = spi_proto_transfer, +}; diff --git a/src/openmv/src/micropython/ports/stm32/spi.h b/src/openmv/src/micropython/ports/stm32/spi.h new file mode 100755 index 0000000..885fb0b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/spi.h @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_SPI_H +#define MICROPY_INCLUDED_STM32_SPI_H + +#include "drivers/bus/spi.h" +#include "dma.h" + +typedef struct _spi_t { + SPI_HandleTypeDef *spi; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; +} spi_t; + +typedef struct _spi_proto_cfg_t { + const spi_t *spi; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + uint8_t firstbit; +} spi_proto_cfg_t; + +typedef struct _pyb_spi_obj_t { + mp_obj_base_t base; + const spi_t *spi; +} pyb_spi_obj_t; + +typedef struct _machine_hard_spi_obj_t { + mp_obj_base_t base; + const spi_t *spi; +} machine_hard_spi_obj_t; + +extern SPI_HandleTypeDef SPIHandle1; +extern SPI_HandleTypeDef SPIHandle2; +extern SPI_HandleTypeDef SPIHandle3; +extern SPI_HandleTypeDef SPIHandle4; +extern SPI_HandleTypeDef SPIHandle5; +extern SPI_HandleTypeDef SPIHandle6; + +extern const spi_t spi_obj[6]; + +extern const mp_spi_proto_t spi_proto; +extern const mp_obj_type_t pyb_spi_type; +extern const mp_obj_type_t machine_soft_spi_type; +extern const mp_obj_type_t machine_hard_spi_type; + +// A transfer of "len" bytes should take len*8*1000/baudrate milliseconds. +// To simplify the calculation we assume the baudrate is never less than 8kHz +// and use that value for the baudrate in the formula, plus a small constant. +#define SPI_TRANSFER_TIMEOUT(len) ((len) + 100) + +void spi_init0(void); +void spi_init(const spi_t *spi, bool enable_nss_pin); +void spi_deinit(const spi_t *spi_obj); +int spi_find_index(mp_obj_t id); +void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, + int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit); +void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout); +void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy); +const spi_t *spi_from_mp_obj(mp_obj_t o); + +#endif // MICROPY_INCLUDED_STM32_SPI_H diff --git a/src/openmv/src/micropython/ports/stm32/spibdev.c b/src/openmv/src/micropython/ports/stm32/spibdev.c new file mode 100755 index 0000000..9b5a10b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/spibdev.c @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/mperrno.h" +#include "irq.h" +#include "led.h" +#include "storage.h" + +#if MICROPY_HW_ENABLE_STORAGE + +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { + switch (op) { + case BDEV_IOCTL_INIT: + bdev->spiflash.config = (const mp_spiflash_config_t*)arg; + mp_spiflash_init(&bdev->spiflash); + bdev->flash_tick_counter_last_write = 0; + return 0; + + case BDEV_IOCTL_IRQ_HANDLER: + if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { + mp_spiflash_cache_flush(&bdev->spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + } + return 0; + + case BDEV_IOCTL_SYNC: + if (bdev->spiflash.flags & 1) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + mp_spiflash_cache_flush(&bdev->spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + restore_irq_pri(basepri); + } + return 0; + } + return -MP_EINVAL; +} + +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); + restore_irq_pri(basepri); + + return 0; +} + +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access + int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); + if (bdev->spiflash.flags & 1) { + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + bdev->flash_tick_counter_last_write = HAL_GetTick(); + } + restore_irq_pri(basepri); + + return ret; +} + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/stm32_it.c b/src/openmv/src/micropython/ports/stm32/stm32_it.c new file mode 100755 index 0000000..026082e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/stm32_it.c @@ -0,0 +1,915 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Original template from ST Cube library. See below for header. + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + ****************************************************************************** + * @file Templates/Src/stm32f4xx_it.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief Main Interrupt Service Routines. + * This file provides template for all exceptions handler and + * peripherals interrupt service routine. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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 "py/obj.h" +#include "py/mphal.h" +#include "stm32_it.h" +#include "pendsv.h" +#include "irq.h" +#include "pybthread.h" +#include "gccollect.h" +#include "extint.h" +#include "timer.h" +#include "uart.h" +#include "storage.h" +#include "can.h" +#include "dma.h" +#include "i2c.h" +#include "usb.h" + +extern void __fatal_error(const char*); +#if defined(MICROPY_HW_USB_FS) +extern PCD_HandleTypeDef pcd_fs_handle; +#endif +#if defined(MICROPY_HW_USB_HS) +extern PCD_HandleTypeDef pcd_hs_handle; +#endif + +/******************************************************************************/ +/* Cortex-M4 Processor Exceptions Handlers */ +/******************************************************************************/ + +// Set the following to 1 to get some more information on the Hard Fault +// More information about decoding the fault registers can be found here: +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646a/Cihdjcfc.html + +STATIC char *fmt_hex(uint32_t val, char *buf) { + const char *hexDig = "0123456789abcdef"; + + buf[0] = hexDig[(val >> 28) & 0x0f]; + buf[1] = hexDig[(val >> 24) & 0x0f]; + buf[2] = hexDig[(val >> 20) & 0x0f]; + buf[3] = hexDig[(val >> 16) & 0x0f]; + buf[4] = hexDig[(val >> 12) & 0x0f]; + buf[5] = hexDig[(val >> 8) & 0x0f]; + buf[6] = hexDig[(val >> 4) & 0x0f]; + buf[7] = hexDig[(val >> 0) & 0x0f]; + buf[8] = '\0'; + + return buf; +} + +STATIC void print_reg(const char *label, uint32_t val) { + char hexStr[9]; + + mp_hal_stdout_tx_str(label); + mp_hal_stdout_tx_str(fmt_hex(val, hexStr)); + mp_hal_stdout_tx_str("\r\n"); +} + +STATIC void print_hex_hex(const char *label, uint32_t val1, uint32_t val2) { + char hex_str[9]; + mp_hal_stdout_tx_str(label); + mp_hal_stdout_tx_str(fmt_hex(val1, hex_str)); + mp_hal_stdout_tx_str(" "); + mp_hal_stdout_tx_str(fmt_hex(val2, hex_str)); + mp_hal_stdout_tx_str("\r\n"); +} + +// The ARMv7M Architecture manual (section B.1.5.6) says that upon entry +// to an exception, that the registers will be in the following order on the +// // stack: R0, R1, R2, R3, R12, LR, PC, XPSR + +typedef struct { + uint32_t r0, r1, r2, r3, r12, lr, pc, xpsr; +} ExceptionRegisters_t; + +int pyb_hard_fault_debug = 0; + +void HardFault_C_Handler(ExceptionRegisters_t *regs) { + if (!pyb_hard_fault_debug) { + NVIC_SystemReset(); + } + + #if MICROPY_HW_ENABLE_USB + // We need to disable the USB so it doesn't try to write data out on + // the VCP and then block indefinitely waiting for the buffer to drain. + pyb_usb_flags = 0; + #endif + + mp_hal_stdout_tx_str("HardFault\r\n"); + + print_reg("R0 ", regs->r0); + print_reg("R1 ", regs->r1); + print_reg("R2 ", regs->r2); + print_reg("R3 ", regs->r3); + print_reg("R12 ", regs->r12); + print_reg("SP ", (uint32_t)regs); + print_reg("LR ", regs->lr); + print_reg("PC ", regs->pc); + print_reg("XPSR ", regs->xpsr); + + #if __CORTEX_M >= 3 + uint32_t cfsr = SCB->CFSR; + + print_reg("HFSR ", SCB->HFSR); + print_reg("CFSR ", cfsr); + if (cfsr & 0x80) { + print_reg("MMFAR ", SCB->MMFAR); + } + if (cfsr & 0x8000) { + print_reg("BFAR ", SCB->BFAR); + } + #endif + + if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) { + mp_hal_stdout_tx_str("Stack:\r\n"); + uint32_t *stack_top = &_estack; + if ((void*)regs < (void*)&_heap_end) { + // stack not in static stack area so limit the amount we print + stack_top = (uint32_t*)regs + 32; + } + for (uint32_t *sp = (uint32_t*)regs; sp < stack_top; ++sp) { + print_hex_hex(" ", (uint32_t)sp, *sp); + } + } + + /* Go to infinite loop when Hard Fault exception occurs */ + while (1) { + __fatal_error("HardFault"); + } +} + +// Naked functions have no compiler generated gunk, so are the best thing to +// use for asm functions. +__attribute__((naked)) +void HardFault_Handler(void) { + + // From the ARMv7M Architecture Reference Manual, section B.1.5.6 + // on entry to the Exception, the LR register contains, amongst other + // things, the value of CONTROL.SPSEL. This can be found in bit 3. + // + // If CONTROL.SPSEL is 0, then the exception was stacked up using the + // main stack pointer (aka MSP). If CONTROL.SPSEL is 1, then the exception + // was stacked up using the process stack pointer (aka PSP). + + #if __CORTEX_M == 0 + __asm volatile( + " mov r0, lr \n" + " lsr r0, r0, #3 \n" // Shift Bit 3 into carry to see which stack pointer we should use. + " mrs r0, msp \n" // Make R0 point to main stack pointer + " bcc .use_msp \n" // Keep MSP in R0 if SPSEL (carry) is 0 + " mrs r0, psp \n" // Make R0 point to process stack pointer + " .use_msp: \n" + " b HardFault_C_Handler \n" // Off to C land + ); + #else + __asm volatile( + " tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should use. + " ite eq \n" // Tell the assembler that the nest 2 instructions are if-then-else + " mrseq r0, msp \n" // Make R0 point to main stack pointer + " mrsne r0, psp \n" // Make R0 point to process stack pointer + " b HardFault_C_Handler \n" // Off to C land + ); + #endif +} + +/** + * @brief This function handles NMI exception. + * @param None + * @retval None + */ +void NMI_Handler(void) { +} + +/** + * @brief This function handles Memory Manage exception. + * @param None + * @retval None + */ +void MemManage_Handler(void) { + /* Go to infinite loop when Memory Manage exception occurs */ + while (1) { + __fatal_error("MemManage"); + } +} + +/** + * @brief This function handles Bus Fault exception. + * @param None + * @retval None + */ +void BusFault_Handler(void) { + /* Go to infinite loop when Bus Fault exception occurs */ + while (1) { + __fatal_error("BusFault"); + } +} + +/** + * @brief This function handles Usage Fault exception. + * @param None + * @retval None + */ +void UsageFault_Handler(void) { + /* Go to infinite loop when Usage Fault exception occurs */ + while (1) { + __fatal_error("UsageFault"); + } +} + +/** + * @brief This function handles SVCall exception. + * @param None + * @retval None + */ +void SVC_Handler(void) { +} + +/** + * @brief This function handles Debug Monitor exception. + * @param None + * @retval None + */ +void DebugMon_Handler(void) { +} + +/** + * @brief This function handles PendSVC exception. + * @param None + * @retval None + */ +void PendSV_Handler(void) { + pendsv_isr_handler(); +} + +/** + * @brief This function handles SysTick Handler. + * @param None + * @retval None + */ +void SysTick_Handler(void) { + // Instead of calling HAL_IncTick we do the increment here of the counter. + // This is purely for efficiency, since SysTick is called 1000 times per + // second at the highest interrupt priority. + // Note: we don't need uwTick to be declared volatile here because this is + // the only place where it can be modified, and the code is more efficient + // without the volatile specifier. + extern uint32_t uwTick; + uwTick += 1; + + // Read the systick control regster. This has the side effect of clearing + // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us + // work properly. + SysTick->CTRL; + + // Right now we have the storage and DMA controllers to process during + // this interrupt and we use custom dispatch handlers. If this needs to + // be generalised in the future then a dispatch table can be used as + // follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))(); + + #if MICROPY_HW_ENABLE_STORAGE + if (STORAGE_IDLE_TICK(uwTick)) { + NVIC->STIR = FLASH_IRQn; + } + #endif + + if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) { + dma_idle_handler(uwTick); + } + + #if MICROPY_PY_THREAD + if (pyb_thread_enabled) { + if (pyb_thread_cur->timeslice == 0) { + if (pyb_thread_cur->run_next != pyb_thread_cur) { + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } + } else { + --pyb_thread_cur->timeslice; + } + } + #endif +} + +/******************************************************************************/ +/* STM32F4xx Peripherals Interrupt Handlers */ +/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ +/* available peripheral interrupt handler's name please refer to the startup */ +/* file (startup_stm32f4xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles USB-On-The-Go FS global interrupt request. + * @param None + * @retval None + */ +#if MICROPY_HW_USB_FS +void OTG_FS_IRQHandler(void) { + IRQ_ENTER(OTG_FS_IRQn); + HAL_PCD_IRQHandler(&pcd_fs_handle); + IRQ_EXIT(OTG_FS_IRQn); +} +#endif +#if MICROPY_HW_USB_HS +void OTG_HS_IRQHandler(void) { + IRQ_ENTER(OTG_HS_IRQn); + HAL_PCD_IRQHandler(&pcd_hs_handle); + IRQ_EXIT(OTG_HS_IRQn); +} +#endif + +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS +/** + * @brief This function handles USB OTG Common FS/HS Wakeup functions. + * @param *pcd_handle for FS or HS + * @retval None + */ +STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { + + if (pcd_handle->Init.low_power_enable) { + /* Reset SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); + + /* Configures system clock after wake-up from STOP: enable HSE, PLL and select + PLL as system clock source (HSE and PLL are disabled in STOP mode) */ + + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); + + /* Wait till HSE is ready */ + while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) + {} + + /* Enable the main PLL. */ + __HAL_RCC_PLL_ENABLE(); + + /* Wait till PLL is ready */ + while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) + {} + + /* Select PLL as SYSCLK */ + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) + {} + #else + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) + {} + #endif + + /* ungate PHY clock */ + __HAL_PCD_UNGATE_PHYCLOCK(pcd_handle); + } + +} +#endif + +#if MICROPY_HW_USB_FS +/** + * @brief This function handles USB OTG FS Wakeup IRQ Handler. + * @param None + * @retval None + */ +void OTG_FS_WKUP_IRQHandler(void) { + IRQ_ENTER(OTG_FS_WKUP_IRQn); + + OTG_CMD_WKUP_Handler(&pcd_fs_handle); + + /* Clear EXTI pending Bit*/ + __HAL_USB_FS_EXTI_CLEAR_FLAG(); + + IRQ_EXIT(OTG_FS_WKUP_IRQn); +} +#endif + +#if MICROPY_HW_USB_HS +/** + * @brief This function handles USB OTG HS Wakeup IRQ Handler. + * @param None + * @retval None + */ +void OTG_HS_WKUP_IRQHandler(void) { + IRQ_ENTER(OTG_HS_WKUP_IRQn); + + OTG_CMD_WKUP_Handler(&pcd_hs_handle); + + /* Clear EXTI pending Bit*/ + __HAL_USB_HS_EXTI_CLEAR_FLAG(); + + IRQ_EXIT(OTG_HS_WKUP_IRQn); +} +#endif + +/** + * @brief This function handles PPP interrupt request. + * @param None + * @retval None + */ +/*void PPP_IRQHandler(void) +{ +}*/ + +// Handle a flash (erase/program) interrupt. +void FLASH_IRQHandler(void) { + IRQ_ENTER(FLASH_IRQn); + // This calls the real flash IRQ handler, if needed + /* + uint32_t flash_cr = FLASH->CR; + if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) { + HAL_FLASH_IRQHandler(); + } + */ + #if MICROPY_HW_ENABLE_STORAGE + // This call the storage IRQ handler, to check if the flash cache needs flushing + storage_irq_handler(); + #endif + IRQ_EXIT(FLASH_IRQn); +} + +/** + * @brief These functions handle the EXTI interrupt requests. + * @param None + * @retval None + */ +void EXTI0_IRQHandler(void) { + IRQ_ENTER(EXTI0_IRQn); + Handle_EXTI_Irq(0); + IRQ_EXIT(EXTI0_IRQn); +} + +void EXTI1_IRQHandler(void) { + IRQ_ENTER(EXTI1_IRQn); + Handle_EXTI_Irq(1); + IRQ_EXIT(EXTI1_IRQn); +} + +void EXTI2_IRQHandler(void) { + IRQ_ENTER(EXTI2_IRQn); + Handle_EXTI_Irq(2); + IRQ_EXIT(EXTI2_IRQn); +} + +void EXTI3_IRQHandler(void) { + IRQ_ENTER(EXTI3_IRQn); + Handle_EXTI_Irq(3); + IRQ_EXIT(EXTI3_IRQn); +} + +void EXTI4_IRQHandler(void) { + IRQ_ENTER(EXTI4_IRQn); + Handle_EXTI_Irq(4); + IRQ_EXIT(EXTI4_IRQn); +} + +void EXTI9_5_IRQHandler(void) { + IRQ_ENTER(EXTI9_5_IRQn); + Handle_EXTI_Irq(5); + Handle_EXTI_Irq(6); + Handle_EXTI_Irq(7); + Handle_EXTI_Irq(8); + Handle_EXTI_Irq(9); + IRQ_EXIT(EXTI9_5_IRQn); +} + +void EXTI15_10_IRQHandler(void) { + IRQ_ENTER(EXTI15_10_IRQn); + Handle_EXTI_Irq(10); + Handle_EXTI_Irq(11); + Handle_EXTI_Irq(12); + Handle_EXTI_Irq(13); + Handle_EXTI_Irq(14); + Handle_EXTI_Irq(15); + IRQ_EXIT(EXTI15_10_IRQn); +} + +void PVD_IRQHandler(void) { + IRQ_ENTER(PVD_IRQn); + Handle_EXTI_Irq(EXTI_PVD_OUTPUT); + IRQ_EXIT(PVD_IRQn); +} + +#if defined(STM32L4) +void PVD_PVM_IRQHandler(void) { + IRQ_ENTER(PVD_PVM_IRQn); + Handle_EXTI_Irq(EXTI_PVD_OUTPUT); + IRQ_EXIT(PVD_PVM_IRQn); +} +#endif + +void RTC_Alarm_IRQHandler(void) { + IRQ_ENTER(RTC_Alarm_IRQn); + Handle_EXTI_Irq(EXTI_RTC_ALARM); + IRQ_EXIT(RTC_Alarm_IRQn); +} + +#if defined(ETH) // The 407 has ETH, the 405 doesn't +void ETH_WKUP_IRQHandler(void) { + IRQ_ENTER(ETH_WKUP_IRQn); + Handle_EXTI_Irq(EXTI_ETH_WAKEUP); + IRQ_EXIT(ETH_WKUP_IRQn); +} +#endif + +void TAMP_STAMP_IRQHandler(void) { + IRQ_ENTER(TAMP_STAMP_IRQn); + Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP); + IRQ_EXIT(TAMP_STAMP_IRQn); +} + +void RTC_WKUP_IRQHandler(void) { + IRQ_ENTER(RTC_WKUP_IRQn); + RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag + Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + IRQ_EXIT(RTC_WKUP_IRQn); +} + +#if defined(STM32F0) + +void RTC_IRQHandler(void) { + IRQ_ENTER(RTC_IRQn); + RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag + Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + IRQ_EXIT(RTC_IRQn); +} + +void EXTI0_1_IRQHandler(void) { + IRQ_ENTER(EXTI0_1_IRQn); + Handle_EXTI_Irq(0); + Handle_EXTI_Irq(1); + IRQ_EXIT(EXTI0_1_IRQn); +} + +void EXTI2_3_IRQHandler(void) { + IRQ_ENTER(EXTI2_3_IRQn); + Handle_EXTI_Irq(2); + Handle_EXTI_Irq(3); + IRQ_EXIT(EXTI2_3_IRQn); +} + +void EXTI4_15_IRQHandler(void) { + IRQ_ENTER(EXTI4_15_IRQn); + for (int i = 4; i <= 15; ++i) { + Handle_EXTI_Irq(i); + } + IRQ_EXIT(EXTI4_15_IRQn); +} + +void TIM1_BRK_UP_TRG_COM_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_UP_TRG_COM_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_BRK_UP_TRG_COM_IRQn); +} + +#endif + +void TIM1_BRK_TIM9_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_TIM9_IRQn); + timer_irq_handler(9); + IRQ_EXIT(TIM1_BRK_TIM9_IRQn); +} + +#if defined(STM32L4) +void TIM1_BRK_TIM15_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_TIM15_IRQn); + timer_irq_handler(15); + IRQ_EXIT(TIM1_BRK_TIM15_IRQn); +} +#endif + +void TIM1_UP_TIM10_IRQHandler(void) { + IRQ_ENTER(TIM1_UP_TIM10_IRQn); + timer_irq_handler(1); + timer_irq_handler(10); + IRQ_EXIT(TIM1_UP_TIM10_IRQn); +} + +#if defined(STM32L4) +void TIM1_UP_TIM16_IRQHandler(void) { + IRQ_ENTER(TIM1_UP_TIM16_IRQn); + timer_irq_handler(1); + timer_irq_handler(16); + IRQ_EXIT(TIM1_UP_TIM16_IRQn); +} +#endif + +void TIM1_TRG_COM_TIM11_IRQHandler(void) { + IRQ_ENTER(TIM1_TRG_COM_TIM11_IRQn); + timer_irq_handler(11); + IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn); +} + +#if defined(STM32L4) +void TIM1_TRG_COM_TIM17_IRQHandler(void) { + IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn); + timer_irq_handler(17); + IRQ_EXIT(TIM1_TRG_COM_TIM17_IRQn); +} +#endif + +void TIM1_CC_IRQHandler(void) { + IRQ_ENTER(TIM1_CC_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_CC_IRQn); +} + +void TIM2_IRQHandler(void) { + IRQ_ENTER(TIM2_IRQn); + timer_irq_handler(2); + IRQ_EXIT(TIM2_IRQn); +} + +void TIM3_IRQHandler(void) { + IRQ_ENTER(TIM3_IRQn); + timer_irq_handler(3); + IRQ_EXIT(TIM3_IRQn); +} + +void TIM4_IRQHandler(void) { + IRQ_ENTER(TIM4_IRQn); + timer_irq_handler(4); + IRQ_EXIT(TIM4_IRQn); +} + +void TIM5_IRQHandler(void) { + IRQ_ENTER(TIM5_IRQn); + timer_irq_handler(5); + HAL_TIM_IRQHandler(&TIM5_Handle); + IRQ_EXIT(TIM5_IRQn); +} + +#if defined(TIM6) // STM32F401 doesn't have TIM6 +void TIM6_DAC_IRQHandler(void) { + IRQ_ENTER(TIM6_DAC_IRQn); + timer_irq_handler(6); + IRQ_EXIT(TIM6_DAC_IRQn); +} +#endif + +#if defined(TIM7) // STM32F401 doesn't have TIM7 +void TIM7_IRQHandler(void) { + IRQ_ENTER(TIM7_IRQn); + timer_irq_handler(7); + IRQ_EXIT(TIM7_IRQn); +} +#endif + +#if defined(TIM8) // STM32F401 doesn't have TIM8 +void TIM8_BRK_TIM12_IRQHandler(void) { + IRQ_ENTER(TIM8_BRK_TIM12_IRQn); + timer_irq_handler(12); + IRQ_EXIT(TIM8_BRK_TIM12_IRQn); +} + +void TIM8_UP_TIM13_IRQHandler(void) { + IRQ_ENTER(TIM8_UP_TIM13_IRQn); + timer_irq_handler(8); + timer_irq_handler(13); + IRQ_EXIT(TIM8_UP_TIM13_IRQn); +} + +#if defined(STM32L4) +void TIM8_UP_IRQHandler(void) { + IRQ_ENTER(TIM8_UP_IRQn); + timer_irq_handler(8); + IRQ_EXIT(TIM8_UP_IRQn); +} +#endif + +void TIM8_CC_IRQHandler(void) { + IRQ_ENTER(TIM8_CC_IRQn); + timer_irq_handler(8); + IRQ_EXIT(TIM8_CC_IRQn); +} + +void TIM8_TRG_COM_TIM14_IRQHandler(void) { + IRQ_ENTER(TIM8_TRG_COM_TIM14_IRQn); + timer_irq_handler(14); + IRQ_EXIT(TIM8_TRG_COM_TIM14_IRQn); +} +#endif + +// UART/USART IRQ handlers +void USART1_IRQHandler(void) { + IRQ_ENTER(USART1_IRQn); + uart_irq_handler(1); + IRQ_EXIT(USART1_IRQn); +} + +void USART2_IRQHandler(void) { + IRQ_ENTER(USART2_IRQn); + uart_irq_handler(2); + IRQ_EXIT(USART2_IRQn); +} + +#if defined(STM32F0) + +void USART3_8_IRQHandler(void) { + IRQ_ENTER(USART3_8_IRQn); + uart_irq_handler(3); + uart_irq_handler(4); + uart_irq_handler(5); + uart_irq_handler(6); + uart_irq_handler(7); + uart_irq_handler(8); + IRQ_EXIT(USART3_8_IRQn); +} + +#else + +void USART3_IRQHandler(void) { + IRQ_ENTER(USART3_IRQn); + uart_irq_handler(3); + IRQ_EXIT(USART3_IRQn); +} + +void UART4_IRQHandler(void) { + IRQ_ENTER(UART4_IRQn); + uart_irq_handler(4); + IRQ_EXIT(UART4_IRQn); +} + +void UART5_IRQHandler(void) { + IRQ_ENTER(UART5_IRQn); + uart_irq_handler(5); + IRQ_EXIT(UART5_IRQn); +} + +void USART6_IRQHandler(void) { + IRQ_ENTER(USART6_IRQn); + uart_irq_handler(6); + IRQ_EXIT(USART6_IRQn); +} + +#if defined(UART8) +void UART7_IRQHandler(void) { + IRQ_ENTER(UART7_IRQn); + uart_irq_handler(7); + IRQ_EXIT(UART7_IRQn); +} +#endif + +#if defined(UART8) +void UART8_IRQHandler(void) { + IRQ_ENTER(UART8_IRQn); + uart_irq_handler(8); + IRQ_EXIT(UART8_IRQn); +} +#endif + +#endif + +#if defined(MICROPY_HW_CAN1_TX) +void CAN1_RX0_IRQHandler(void) { + IRQ_ENTER(CAN1_RX0_IRQn); + can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0); + IRQ_EXIT(CAN1_RX0_IRQn); +} + +void CAN1_RX1_IRQHandler(void) { + IRQ_ENTER(CAN1_RX1_IRQn); + can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1); + IRQ_EXIT(CAN1_RX1_IRQn); +} + +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} +#endif + +#if defined(MICROPY_HW_CAN2_TX) +void CAN2_RX0_IRQHandler(void) { + IRQ_ENTER(CAN2_RX0_IRQn); + can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); + IRQ_EXIT(CAN2_RX0_IRQn); +} + +void CAN2_RX1_IRQHandler(void) { + IRQ_ENTER(CAN2_RX1_IRQn); + can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); + IRQ_EXIT(CAN2_RX1_IRQn); +} + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} +#endif + +#if MICROPY_PY_PYB_LEGACY + +#if defined(MICROPY_HW_I2C1_SCL) +void I2C1_EV_IRQHandler(void) { + IRQ_ENTER(I2C1_EV_IRQn); + i2c_ev_irq_handler(1); + IRQ_EXIT(I2C1_EV_IRQn); +} + +void I2C1_ER_IRQHandler(void) { + IRQ_ENTER(I2C1_ER_IRQn); + i2c_er_irq_handler(1); + IRQ_EXIT(I2C1_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C1_SCL) + +#if defined(MICROPY_HW_I2C2_SCL) +void I2C2_EV_IRQHandler(void) { + IRQ_ENTER(I2C2_EV_IRQn); + i2c_ev_irq_handler(2); + IRQ_EXIT(I2C2_EV_IRQn); +} + +void I2C2_ER_IRQHandler(void) { + IRQ_ENTER(I2C2_ER_IRQn); + i2c_er_irq_handler(2); + IRQ_EXIT(I2C2_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C2_SCL) + +#if defined(MICROPY_HW_I2C3_SCL) +void I2C3_EV_IRQHandler(void) { + IRQ_ENTER(I2C3_EV_IRQn); + i2c_ev_irq_handler(3); + IRQ_EXIT(I2C3_EV_IRQn); +} + +void I2C3_ER_IRQHandler(void) { + IRQ_ENTER(I2C3_ER_IRQn); + i2c_er_irq_handler(3); + IRQ_EXIT(I2C3_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C3_SCL) + +#if defined(MICROPY_HW_I2C4_SCL) +void I2C4_EV_IRQHandler(void) { + IRQ_ENTER(I2C4_EV_IRQn); + i2c_ev_irq_handler(4); + IRQ_EXIT(I2C4_EV_IRQn); +} + +void I2C4_ER_IRQHandler(void) { + IRQ_ENTER(I2C4_ER_IRQn); + i2c_er_irq_handler(4); + IRQ_EXIT(I2C4_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C4_SCL) + +#endif // MICROPY_PY_PYB_LEGACY diff --git a/src/openmv/src/micropython/ports/stm32/stm32_it.h b/src/openmv/src/micropython/ports/stm32/stm32_it.h new file mode 100755 index 0000000..46523e5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/stm32_it.h @@ -0,0 +1,82 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Original template from ST Cube library. See below for header. + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_STM32_IT_H +#define MICROPY_INCLUDED_STM32_STM32_IT_H + +/** + ****************************************************************************** + * @file Templates/Inc/stm32f4xx_it.h + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +extern int pyb_hard_fault_debug; + +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +void OTG_FS_IRQHandler(void); +void OTG_HS_IRQHandler(void); + +#endif // MICROPY_INCLUDED_STM32_STM32_IT_H diff --git a/src/openmv/src/micropython/ports/stm32/storage.c b/src/openmv/src/micropython/ports/stm32/storage.c new file mode 100755 index 0000000..7724ae0 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/storage.c @@ -0,0 +1,289 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "extmod/vfs_fat.h" + +#include "led.h" +#include "storage.h" +#include "irq.h" + +#if MICROPY_HW_ENABLE_STORAGE + +#define FLASH_PART1_START_BLOCK (0x100) + +#if defined(MICROPY_HW_BDEV2_IOCTL) +#define FLASH_PART2_START_BLOCK (FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) +#endif + +static bool storage_is_initialised = false; + +void storage_init(void) { + if (!storage_is_initialised) { + storage_is_initialised = true; + + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0); + #endif + + // Enable the flash IRQ, which is used to also call our storage IRQ handler + // It must go at the same priority as USB (see comment in irq.h). + NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH); + HAL_NVIC_EnableIRQ(FLASH_IRQn); + } +} + +uint32_t storage_get_block_size(void) { + return FLASH_BLOCK_SIZE; +} + +uint32_t storage_get_block_count(void) { + #if defined(MICROPY_HW_BDEV2_IOCTL) + return FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #else + return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #endif +} + +void storage_irq_handler(void) { + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + #endif +} + +void storage_flush(void) { + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_SYNC, 0); + #endif +} + +static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) { + buf[0] = boot; + + if (num_blocks == 0) { + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + } else { + buf[1] = 0xff; + buf[2] = 0xff; + buf[3] = 0xff; + } + + buf[4] = type; + + if (num_blocks == 0) { + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + } else { + buf[5] = 0xff; + buf[6] = 0xff; + buf[7] = 0xff; + } + + buf[8] = start_block; + buf[9] = start_block >> 8; + buf[10] = start_block >> 16; + buf[11] = start_block >> 24; + + buf[12] = num_blocks; + buf[13] = num_blocks >> 8; + buf[14] = num_blocks >> 16; + buf[15] = num_blocks >> 24; +} + +bool storage_read_block(uint8_t *dest, uint32_t block) { + //printf("RD %u\n", block); + if (block == 0) { + // fake the MBR so we can decide on our own partition table + + for (int i = 0; i < 446; i++) { + dest[i] = 0; + } + + build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #if defined(MICROPY_HW_BDEV2_IOCTL) + build_partition(dest + 462, 0, 0x01 /* FAT12 */, FLASH_PART2_START_BLOCK, MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #else + build_partition(dest + 462, 0, 0, 0, 0); + #endif + build_partition(dest + 478, 0, 0, 0, 0); + build_partition(dest + 494, 0, 0, 0, 0); + + dest[510] = 0x55; + dest[511] = 0xaa; + + return true; + + #if defined(MICROPY_HW_BDEV_READBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); + #endif + } else { + return false; + } +} + +bool storage_write_block(const uint8_t *src, uint32_t block) { + //printf("WR %u\n", block); + if (block == 0) { + // can't write MBR, but pretend we did + return true; + #if defined(MICROPY_HW_BDEV_WRITEBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); + #endif + } else { + return false; + } +} + +mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + #if defined(MICROPY_HW_BDEV_READBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + + #if defined(MICROPY_HW_BDEV2_READBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_READBLOCKS(dest, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + + for (size_t i = 0; i < num_blocks; i++) { + if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) { + return 1; // error + } + } + return 0; // success +} + +mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + #if defined(MICROPY_HW_BDEV_WRITEBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + + #if defined(MICROPY_HW_BDEV2_WRITEBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_WRITEBLOCKS(src, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + + for (size_t i = 0; i < num_blocks; i++) { + if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) { + return 1; // error + } + } + return 0; // success +} + +/******************************************************************************/ +// MicroPython bindings +// +// Expose the flash as an object with the block protocol. + +// there is a singleton Flash object +STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type}; + +STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return singleton object + return MP_OBJ_FROM_PTR(&pyb_flash_obj); +} + +STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + mp_uint_t ret = storage_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE); + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks); + +STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + mp_uint_t ret = storage_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FLASH_BLOCK_SIZE); + return MP_OBJ_NEW_SMALL_INT(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks); + +STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) { + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: storage_init(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_DEINIT: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly + case BP_IOCTL_SYNC: storage_flush(); return MP_OBJ_NEW_SMALL_INT(0); + case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(storage_get_block_count()); + case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(storage_get_block_size()); + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl); + +STATIC const mp_rom_map_elem_t pyb_flash_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&pyb_flash_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&pyb_flash_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&pyb_flash_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table); + +const mp_obj_type_t pyb_flash_type = { + { &mp_type_type }, + .name = MP_QSTR_Flash, + .make_new = pyb_flash_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_flash_locals_dict, +}; + +void pyb_flash_init_vfs(fs_user_mount_t *vfs) { + vfs->base.type = &mp_fat_vfs_type; + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->fatfs.drv = vfs; + vfs->fatfs.part = 1; // flash filesystem lives on first partition + vfs->readblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_readblocks_obj); + vfs->readblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); + vfs->readblocks[2] = MP_OBJ_FROM_PTR(storage_read_blocks); // native version + vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_writeblocks_obj); + vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); + vfs->writeblocks[2] = MP_OBJ_FROM_PTR(storage_write_blocks); // native version + vfs->u.ioctl[0] = MP_OBJ_FROM_PTR(&pyb_flash_ioctl_obj); + vfs->u.ioctl[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj); +} + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/storage.h b/src/openmv/src/micropython/ports/stm32/storage.h new file mode 100755 index 0000000..7250b6d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/storage.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_STORAGE_H +#define MICROPY_INCLUDED_STM32_STORAGE_H + +#include "drivers/memory/spiflash.h" + +#define FLASH_BLOCK_SIZE (512) + +#define STORAGE_SYSTICK_MASK (0x1ff) // 512ms +#define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2) + +// Try to match Python-level VFS block protocol where possible for these constants +enum { + BDEV_IOCTL_INIT = 1, + BDEV_IOCTL_SYNC = 3, + BDEV_IOCTL_NUM_BLOCKS = 4, + BDEV_IOCTL_IRQ_HANDLER = 6, +}; + +void storage_init(void); +uint32_t storage_get_block_size(void); +uint32_t storage_get_block_count(void); +void storage_irq_handler(void); +void storage_flush(void); +bool storage_read_block(uint8_t *dest, uint32_t block); +bool storage_write_block(const uint8_t *src, uint32_t block); + +// these return 0 on success, non-zero on error +mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); + +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg); +bool flash_bdev_readblock(uint8_t *dest, uint32_t block); +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); + +typedef struct _spi_bdev_t { + mp_spiflash_t spiflash; + uint32_t flash_tick_counter_last_write; +} spi_bdev_t; + +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg); +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks); + +extern const struct _mp_obj_type_t pyb_flash_type; + +struct _fs_user_mount_t; +void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs); + +#endif // MICROPY_INCLUDED_STM32_STORAGE_H diff --git a/src/openmv/src/micropython/ports/stm32/system_stm32.c b/src/openmv/src/micropython/ports/stm32/system_stm32.c new file mode 100755 index 0000000..b57b8e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/system_stm32.c @@ -0,0 +1,602 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and modified. See below for original header. + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + ****************************************************************************** + * @file system_stm32.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief CMSIS Cortex-M4/M7 Device Peripheral Access Layer System Source File. + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32fxxx_system + * @{ + */ + +/** @addtogroup STM32Fxxx_System_Private_Includes + * @{ + */ + +#include "py/mphal.h" +#include "powerctrl.h" + +void __fatal_error(const char *msg); + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_Defines + * @{ + */ + +#if defined(STM32F4) || defined(STM32F7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x24003010) + +#if defined(STM32F4) +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +#elif defined(STM32F7) +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +#endif + +#elif defined(STM32L4) + +#define CONFIG_RCC_CR_1ST (RCC_CR_MSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_HSION | RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x00001000) +/* + * FIXME Do not know why I have to define these arrays here! they should be defined in the + * hal_rcc-file!! + * + */ +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +#elif defined(STM32H7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (~0xEAF6ED7F) +#define CONFIG_RCC_PLLCFGR (0x00000000) + +#define SRAM_BASE D1_AXISRAM_BASE +#define FLASH_BASE FLASH_BANK1_BASE +uint32_t SystemD2Clock = 64000000; +const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9}; + +#else +#error Unknown processor +#endif + +/************************* Miscellaneous Configuration ************************/ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/******************************************************************************/ + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_Variables + * @{ + */ + /* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 16000000; + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32Fxxx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the FPU setting, vector table location and External memory + * configuration. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ + #endif + /* Reset the RCC clock configuration to the default reset state ------------*/ + + /* Set configured startup clk source */ + RCC->CR |= CONFIG_RCC_CR_1ST; + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= ~ CONFIG_RCC_CR_2ND; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + + #if defined(STM32H7) + /* Reset D1CFGR register */ + RCC->D1CFGR = 0x00000000; + + /* Reset D2CFGR register */ + RCC->D2CFGR = 0x00000000; + + /* Reset D3CFGR register */ + RCC->D3CFGR = 0x00000000; + + /* Reset PLLCKSELR register */ + RCC->PLLCKSELR = 0x00000000; + + /* Reset PLL1DIVR register */ + RCC->PLL1DIVR = 0x00000000; + + /* Reset PLL1FRACR register */ + RCC->PLL1FRACR = 0x00000000; + + /* Reset PLL2DIVR register */ + RCC->PLL2DIVR = 0x00000000; + + /* Reset PLL2FRACR register */ + RCC->PLL2FRACR = 0x00000000; + + /* Reset PLL3DIVR register */ + RCC->PLL3DIVR = 0x00000000; + + /* Reset PLL3FRACR register */ + RCC->PLL3FRACR = 0x00000000; + #endif + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Disable all interrupts */ + #if defined(STM32F4) || defined(STM32F7) + RCC->CIR = 0x00000000; + #elif defined(STM32L4) || defined(STM32H7) + RCC->CIER = 0x00000000; + #endif + + #if defined(STM32H7) + /* Change the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */ + *((__IO uint32_t*)0x51008108) = 0x00000001; + #endif + + /* Configure the Vector Table location add offset address ------------------*/ +#ifdef MICROPY_HW_VTOR + SCB->VTOR = MICROPY_HW_VTOR; +#else +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif +#endif + + /* dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI */ + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + + +/** + * @brief System Clock Configuration + * + * The system Clock is configured for F4/F7 as follows: + * System Clock source = PLL (HSE) + * SYSCLK(Hz) = 168000000 + * HCLK(Hz) = 168000000 + * AHB Prescaler = 1 + * APB1 Prescaler = 4 + * APB2 Prescaler = 2 + * HSE Frequency(Hz) = HSE_VALUE + * PLL_M = HSE_VALUE/1000000 + * PLL_N = 336 + * PLL_P = 2 + * PLL_Q = 7 + * VDD(V) = 3.3 + * Main regulator output voltage = Scale1 mode + * Flash Latency(WS) = 5 + * + * The system Clock is configured for L4 as follows: + * System Clock source = PLL (MSI) + * SYSCLK(Hz) = 80000000 + * HCLK(Hz) = 80000000 + * AHB Prescaler = 1 + * APB1 Prescaler = 1 + * APB2 Prescaler = 1 + * MSI Frequency(Hz) = MSI_VALUE (4000000) + * LSE Frequency(Hz) = 32768 + * PLL_M = 1 + * PLL_N = 40 + * PLL_P = 7 + * PLL_Q = 2 + * PLL_R = 2 <= This is the source for SysClk, not as on F4/7 PLL_P + * Flash Latency(WS) = 4 + * @param None + * @retval None + * + * PLL is configured as follows: + * + * VCO_IN + * F4/F7 = HSE / M + * L4 = MSI / M + * VCO_OUT + * F4/F7 = HSE / M * N + * L4 = MSI / M * N + * PLLCLK + * F4/F7 = HSE / M * N / P + * L4 = MSI / M * N / R + * PLL48CK + * F4/F7 = HSE / M * N / Q + * L4 = MSI / M * N / Q USB Clock is obtained over PLLSAI1 + * + * SYSCLK = PLLCLK + * HCLK = SYSCLK / AHB_PRESC + * PCLKx = HCLK / APBx_PRESC + * + * Constraints on parameters: + * + * VCO_IN between 1MHz and 2MHz (2MHz recommended) + * VCO_OUT between 192MHz and 432MHz + * HSE = 8MHz + * M = 2 .. 63 (inclusive) + * N = 192 ... 432 (inclusive) + * P = 2, 4, 6, 8 + * Q = 2 .. 15 (inclusive) + * + * AHB_PRESC=1,2,4,8,16,64,128,256,512 + * APBx_PRESC=1,2,4,8,16 + * + * Output clocks: + * + * CPU SYSCLK max 168MHz + * USB,RNG,SDIO PLL48CK must be 48MHz for USB + * AHB HCLK max 168MHz + * APB1 PCLK1 max 42MHz + * APB2 PCLK2 max 84MHz + * + * Timers run from APBx if APBx_PRESC=1, else 2x APBx + */ +void SystemClock_Config(void) +{ + #if defined(STM32F7) + // The DFU bootloader changes the clocksource register from its default power + // on reset value, so we set it back here, so the clocksources are the same + // whether we were started from DFU or from a power on reset. + RCC->DCKCFGR2 = 0; + #endif + + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_OscInitTypeDef RCC_OscInitStruct; + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + #endif + + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + + /* Enable Power Control clock */ + #if defined(STM32H7) + MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0); + #else + __PWR_CLK_ENABLE(); + #endif + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + #elif defined(STM32L4) + // Configure LSE Drive Capability + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + #endif + + #if defined(STM32H7) + // Wait for PWR_FLAG_VOSRDY + while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) { + } + #endif + + /* Enable HSE Oscillator and activate PLL with HSE as source */ + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; + RCC_OscInitStruct.HSIState = RCC_HSI_OFF; + #if defined(STM32H7) + RCC_OscInitStruct.CSIState = RCC_CSI_OFF; + #endif + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + #elif defined(STM32L4) + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.MSIState = RCC_MSI_ON; + RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; + RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + #endif + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 + clocks dividers */ + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + #if defined(STM32H7) + RCC_ClkInitStruct.ClockType |= (RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1); + #endif + +#if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ + #if defined(STM32F7) + #define FREQ_BKP BKP31R + #elif defined(STM32L4) + #error Unsupported Processor + #else + #define FREQ_BKP BKP19R + #endif + uint32_t m = RTC->FREQ_BKP; + uint32_t n; + uint32_t p; + uint32_t q; + + // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM + uint32_t h = (m >> 22) & 0xf; + uint32_t b1 = (m >> 26) & 0x7; + uint32_t b2 = (m >> 29) & 0x7; + q = (m >> 18) & 0xf; + p = (((m >> 16) & 0x03)+1)*2; + n = (m >> 6) & 0x3ff; + m &= 0x3f; + if ((q < 2) || (q > 15) || (p > 8) || (p < 2) || (n < 192) || (n >= 433) || (m < 2)) { + m = MICROPY_HW_CLK_PLLM; + n = MICROPY_HW_CLK_PLLN; + p = MICROPY_HW_CLK_PLLP; + q = MICROPY_HW_CLK_PLLQ; + h = RCC_SYSCLK_DIV1; + b1 = RCC_HCLK_DIV4; + b2 = RCC_HCLK_DIV2; + } else { + h <<= 4; + b1 <<= 10; + b2 <<= 10; + } + RCC_OscInitStruct.PLL.PLLM = m; //MICROPY_HW_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = n; //MICROPY_HW_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = p; //MICROPY_HW_CLK_PLLP; + RCC_OscInitStruct.PLL.PLLQ = q; //MICROPY_HW_CLK_PLLQ; + + RCC_ClkInitStruct.AHBCLKDivider = h; //RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = b1; //RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = b2; //RCC_HCLK_DIV2; +#else // defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ + RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; + RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; + #if defined(STM32L4) || defined(STM32H7) + RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; + #endif + + #if defined(STM32H7) + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + #endif + + #if defined(STM32F4) || defined(STM32F7) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + #elif defined(STM32L4) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + #elif defined(STM32H7) + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; + #endif +#endif + + if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + __fatal_error("HAL_RCC_OscConfig"); + } + +#if defined(STM32H7) + /* PLL3 for USB Clock */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3; + PeriphClkInitStruct.PLL3.PLL3M = 4; + PeriphClkInitStruct.PLL3.PLL3N = 120; + PeriphClkInitStruct.PLL3.PLL3P = 2; + PeriphClkInitStruct.PLL3.PLL3Q = 5; + PeriphClkInitStruct.PLL3.PLL3R = 2; + PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1; + PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE; + PeriphClkInitStruct.PLL3.PLL3FRACN = 0; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } +#endif + +#if defined(STM32F7) + /* Activate the OverDrive to reach the 200 MHz Frequency */ + if (HAL_PWREx_EnableOverDrive() != HAL_OK) + { + __fatal_error("HAL_PWREx_EnableOverDrive"); + } +#endif + + uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (HSE_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM; + uint32_t sysclk_mhz = vco_out / RCC_OscInitStruct.PLL.PLLP; + bool need_pllsai = vco_out % 48 != 0; + if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai) != 0) { + __fatal_error("HAL_RCC_ClockConfig"); + } + +#if defined(STM32H7) + /* Activate CSI clock mandatory for I/O Compensation Cell*/ + __HAL_RCC_CSI_ENABLE() ; + + /* Enable SYSCFG clock mandatory for I/O Compensation Cell */ + __HAL_RCC_SYSCFG_CLK_ENABLE() ; + + /* Enable the I/O Compensation Cell */ + HAL_EnableCompensationCell(); + + /* Enable the USB voltage level detector */ + HAL_PWREx_EnableUSBVoltageDetector(); +#endif + +#if defined(STM32L4) + // Enable MSI-Hardware auto calibration mode with LSE + HAL_RCCEx_EnableMSIPLLMode(); + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_I2C1 + |RCC_PERIPHCLK_USB |RCC_PERIPHCLK_ADC + |RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is + MSI(4MHz)/PLLM(1)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx + application or the reference manual. */ + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI; + PeriphClkInitStruct.PLLSAI1.PLLSAI1M = 1; + PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24; + PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; + PeriphClkInitStruct.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + |RCC_PLLSAI1_48M2CLK + |RCC_PLLSAI1_ADC1CLK; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + + __PWR_CLK_ENABLE(); + + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0)); +#endif +} diff --git a/src/openmv/src/micropython/ports/stm32/system_stm32f0.c b/src/openmv/src/micropython/ports/stm32/system_stm32f0.c new file mode 100755 index 0000000..9d4b06e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/system_stm32f0.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and modified. See below for original header. + */ + +/** + ****************************************************************************** + * @file system_stm32f0xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File. + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * 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 STMicroelectronics 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 STM32_HAL_H + +#ifndef HSE_VALUE +#define HSE_VALUE (8000000) +#endif + +#ifndef HSI_VALUE +#define HSI_VALUE (8000000) +#endif + +#ifndef HSI48_VALUE +#define HSI48_VALUE (48000000) +#endif + +/* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock there is no need to + call the 2 first functions listed above, since SystemCoreClock variable is + updated automatically. +*/ +uint32_t SystemCoreClock = 8000000; + +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= (uint32_t)0x00000001U; + + #if defined(STM32F051x8) || defined(STM32F058x8) + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits + RCC->CFGR &= (uint32_t)0xF8FFB80CU; + #else + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits + RCC->CFGR &= (uint32_t)0x08FFB80CU; + #endif + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= (uint32_t)0xFEF6FFFFU; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFFU; + + // Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits + RCC->CFGR &= (uint32_t)0xFFC0FFFFU; + + // Reset PREDIV[3:0] bits + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U; + + #if defined(STM32F072xB) || defined(STM32F078xx) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU; + #elif defined(STM32F071xB) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFCEACU; + #elif defined(STM32F091xC) || defined(STM32F098xx) + // Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFF0FEACU; + #elif defined(STM32F030x6) || defined(STM32F030x8) || defined(STM32F031x6) || defined(STM32F038xx) || defined(STM32F030xC) + // Reset USART1SW[1:0], I2C1SW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEECU; + #elif defined(STM32F051x8) || defined(STM32F058xx) + // Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEACU; + #elif defined(STM32F042x6) || defined(STM32F048xx) + // Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU; + #elif defined(STM32F070x6) || defined(STM32F070xB) + // Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU; + // Set default USB clock to PLLCLK, since there is no HSI48 + RCC->CFGR3 |= (uint32_t)0x00000080U; + #else + #warning "No target selected" + #endif + + // Reset HSI14 bit + RCC->CR2 &= (uint32_t)0xFFFFFFFEU; + + // Disable all interrupts + RCC->CIR = 0x00000000U; + + // dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void SystemClock_Config(void) { + // Set flash latency to 1 because SYSCLK > 24MHz + FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; + + // Use the 48MHz internal oscillator + RCC->CR2 |= RCC_CR2_HSI48ON; + while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) { + } + RCC->CFGR |= 3 << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x03) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + +void SystemCoreClockUpdate(void) { + // Get SYSCLK source + uint32_t tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case RCC_CFGR_SWS_HSI: + SystemCoreClock = HSI_VALUE; + break; + case RCC_CFGR_SWS_HSE: + SystemCoreClock = HSE_VALUE; + break; + case RCC_CFGR_SWS_PLL: { + /* Get PLL clock source and multiplication factor */ + uint32_t pllmull = RCC->CFGR & RCC_CFGR_PLLMUL; + uint32_t pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = (pllmull >> 18) + 2; + uint32_t predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1; + + if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) { + /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */ + SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull; + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) \ + || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx) + } else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) { + /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */ + SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull; + #endif + } else { + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \ + || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \ + || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC) + /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */ + SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull; + #else + /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + #endif + } + break; + } + case RCC_CFGR_SWS_HSI48: + SystemCoreClock = HSI48_VALUE; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + + // Compute HCLK clock frequency + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + SystemCoreClock >>= tmp; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/systick.c b/src/openmv/src/micropython/ports/stm32/systick.c new file mode 100755 index 0000000..c07d0fa --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/systick.c @@ -0,0 +1,140 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "irq.h" +#include "systick.h" +#include "pybthread.h" + +extern __IO uint32_t uwTick; + +// We provide our own version of HAL_Delay that calls __WFI while waiting, +// and works when interrupts are disabled. This function is intended to be +// used only by the ST HAL functions. +void HAL_Delay(uint32_t Delay) { + if (query_irq() == IRQ_STATE_ENABLED) { + // IRQs enabled, so can use systick counter to do the delay + uint32_t start = uwTick; + // Wraparound of tick is taken care of by 2's complement arithmetic. + while (uwTick - start < Delay) { + // Enter sleep mode, waiting for (at least) the SysTick interrupt. + __WFI(); + } + } else { + // IRQs disabled, use mp_hal_delay_ms routine. + mp_hal_delay_ms(Delay); + } +} + +// Core delay function that does an efficient sleep and may switch thread context. +// If IRQs are enabled then we must have the GIL. +void mp_hal_delay_ms(mp_uint_t Delay) { + if (query_irq() == IRQ_STATE_ENABLED) { + // IRQs enabled, so can use systick counter to do the delay + uint32_t start = uwTick; + // Wraparound of tick is taken care of by 2's complement arithmetic. + while (uwTick - start < Delay) { + // This macro will execute the necessary idle behaviour. It may + // raise an exception, switch threads or enter sleep mode (waiting for + // (at least) the SysTick interrupt). + MICROPY_EVENT_POLL_HOOK + } + } else { + // IRQs disabled, so need to use a busy loop for the delay. + // To prevent possible overflow of the counter we use a double loop. + const uint32_t count_1ms = HAL_RCC_GetSysClockFreq() / 4000; + for (int i = 0; i < Delay; i++) { + for (uint32_t count = 0; ++count <= count_1ms;) { + } + } + } +} + +// delay for given number of microseconds +void mp_hal_delay_us(mp_uint_t usec) { + if (query_irq() == IRQ_STATE_ENABLED) { + // IRQs enabled, so can use systick counter to do the delay + uint32_t start = mp_hal_ticks_us(); + while (mp_hal_ticks_us() - start < usec) { + } + } else { + // IRQs disabled, so need to use a busy loop for the delay + // sys freq is always a multiple of 2MHz, so division here won't lose precision + const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2; + for (uint32_t count = 0; ++count <= ucount;) { + } + } +} + +bool sys_tick_has_passed(uint32_t start_tick, uint32_t delay_ms) { + return HAL_GetTick() - start_tick >= delay_ms; +} + +// waits until at least delay_ms milliseconds have passed from the sampling of +// startTick. Handles overflow properly. Assumes stc was taken from +// HAL_GetTick() some time before calling this function. +void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) { + while (!sys_tick_has_passed(start_tick, delay_ms)) { + __WFI(); // enter sleep mode, waiting for interrupt + } +} + +mp_uint_t mp_hal_ticks_ms(void) { + return uwTick; +} + +// The SysTick timer counts down at 168 MHz, so we can use that knowledge +// to grab a microsecond counter. +// +// We assume that HAL_GetTickis returns milliseconds. +mp_uint_t mp_hal_ticks_us(void) { + mp_uint_t irq_state = disable_irq(); + uint32_t counter = SysTick->VAL; + uint32_t milliseconds = HAL_GetTick(); + uint32_t status = SysTick->CTRL; + enable_irq(irq_state); + + // It's still possible for the countflag bit to get set if the counter was + // reloaded between reading VAL and reading CTRL. With interrupts disabled + // it definitely takes less than 50 HCLK cycles between reading VAL and + // reading CTRL, so the test (counter > 50) is to cover the case where VAL + // is +ve and very close to zero, and the COUNTFLAG bit is also set. + if ((status & SysTick_CTRL_COUNTFLAG_Msk) && counter > 50) { + // This means that the HW reloaded VAL between the time we read VAL and the + // time we read CTRL, which implies that there is an interrupt pending + // to increment the tick counter. + milliseconds++; + } + uint32_t load = SysTick->LOAD; + counter = load - counter; // Convert from decrementing to incrementing + + // ((load + 1) / 1000) is the number of counts per microsecond. + // + // counter / ((load + 1) / 1000) scales from the systick clock to microseconds + // and is the same thing as (counter * 1000) / (load + 1) + return milliseconds * 1000 + (counter * 1000) / (load + 1); +} diff --git a/src/openmv/src/micropython/ports/stm32/systick.h b/src/openmv/src/micropython/ports/stm32/systick.h new file mode 100755 index 0000000..256a500 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/systick.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H +#define MICROPY_INCLUDED_STM32_SYSTICK_H + +void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms); +bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms); + +#endif // MICROPY_INCLUDED_STM32_SYSTICK_H diff --git a/src/openmv/src/micropython/ports/stm32/timer.c b/src/openmv/src/micropython/ports/stm32/timer.c new file mode 100755 index 0000000..0aa3c47 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/timer.c @@ -0,0 +1,1516 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "timer.h" +#include "servo.h" +#include "pin.h" +#include "irq.h" + +/// \moduleref pyb +/// \class Timer - periodically call a function +/// +/// Timers can be used for a great variety of tasks. At the moment, only +/// the simplest case is implemented: that of calling a function periodically. +/// +/// Each timer consists of a counter that counts up at a certain rate. The rate +/// at which it counts is the peripheral clock frequency (in Hz) divided by the +/// timer prescaler. When the counter reaches the timer period it triggers an +/// event, and the counter resets back to zero. By using the callback method, +/// the timer event can call a Python function. +/// +/// Example usage to toggle an LED at a fixed frequency: +/// +/// tim = pyb.Timer(4) # create a timer object using timer 4 +/// tim.init(freq=2) # trigger at 2Hz +/// tim.callback(lambda t:pyb.LED(1).toggle()) +/// +/// Further examples: +/// +/// tim = pyb.Timer(4, freq=100) # freq in Hz +/// tim = pyb.Timer(4, prescaler=0, period=99) +/// tim.counter() # get counter (can also set) +/// tim.prescaler(2) # set prescaler (can also get) +/// tim.period(199) # set period (can also get) +/// tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance) +/// tim.callback(None) # clear callback +/// +/// *Note:* Timer 3 is used for fading the blue LED. Timer 5 controls +/// the servo driver, and Timer 6 is used for timed ADC/DAC reading/writing. +/// It is recommended to use the other timers in your programs. + +// The timers can be used by multiple drivers, and need a common point for +// the interrupts to be dispatched, so they are all collected here. +// +// TIM3: +// - LED 4, PWM to set the LED intensity +// +// TIM5: +// - servo controller, PWM +// +// TIM6: +// - ADC, DAC for read_timed and write_timed + +typedef enum { + CHANNEL_MODE_PWM_NORMAL, + CHANNEL_MODE_PWM_INVERTED, + CHANNEL_MODE_OC_TIMING, + CHANNEL_MODE_OC_ACTIVE, + CHANNEL_MODE_OC_INACTIVE, + CHANNEL_MODE_OC_TOGGLE, + CHANNEL_MODE_OC_FORCED_ACTIVE, + CHANNEL_MODE_OC_FORCED_INACTIVE, + CHANNEL_MODE_IC, + CHANNEL_MODE_ENC_A, + CHANNEL_MODE_ENC_B, + CHANNEL_MODE_ENC_AB, +} pyb_channel_mode; + +STATIC const struct { + qstr name; + uint32_t oc_mode; +} channel_mode_info[] = { + { MP_QSTR_PWM, TIM_OCMODE_PWM1 }, + { MP_QSTR_PWM_INVERTED, TIM_OCMODE_PWM2 }, + { MP_QSTR_OC_TIMING, TIM_OCMODE_TIMING }, + { MP_QSTR_OC_ACTIVE, TIM_OCMODE_ACTIVE }, + { MP_QSTR_OC_INACTIVE, TIM_OCMODE_INACTIVE }, + { MP_QSTR_OC_TOGGLE, TIM_OCMODE_TOGGLE }, + { MP_QSTR_OC_FORCED_ACTIVE, TIM_OCMODE_FORCED_ACTIVE }, + { MP_QSTR_OC_FORCED_INACTIVE, TIM_OCMODE_FORCED_INACTIVE }, + { MP_QSTR_IC, 0 }, + { MP_QSTR_ENC_A, TIM_ENCODERMODE_TI1 }, + { MP_QSTR_ENC_B, TIM_ENCODERMODE_TI2 }, + { MP_QSTR_ENC_AB, TIM_ENCODERMODE_TI12 }, +}; + +typedef struct _pyb_timer_channel_obj_t { + mp_obj_base_t base; + struct _pyb_timer_obj_t *timer; + uint8_t channel; + uint8_t mode; + mp_obj_t callback; + struct _pyb_timer_channel_obj_t *next; +} pyb_timer_channel_obj_t; + +typedef struct _pyb_timer_obj_t { + mp_obj_base_t base; + uint8_t tim_id; + uint8_t is_32bit; + mp_obj_t callback; + TIM_HandleTypeDef tim; + IRQn_Type irqn; + pyb_timer_channel_obj_t *channel; +} pyb_timer_obj_t; + +// The following yields TIM_IT_UPDATE when channel is zero and +// TIM_IT_CC1..TIM_IT_CC4 when channel is 1..4 +#define TIMER_IRQ_MASK(channel) (1 << (channel)) +#define TIMER_CNT_MASK(self) ((self)->is_32bit ? 0xffffffff : 0xffff) +#define TIMER_CHANNEL(self) ((((self)->channel) - 1) << 2) + +TIM_HandleTypeDef TIM5_Handle; +TIM_HandleTypeDef TIM6_Handle; + +#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(MP_STATE_PORT(pyb_timer_obj_all)) + +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in); +STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback); +STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback); + +void timer_init0(void) { + for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { + MP_STATE_PORT(pyb_timer_obj_all)[i] = NULL; + } +} + +// unregister all interrupt sources +void timer_deinit(void) { + for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { + pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[i]; + if (tim != NULL) { + pyb_timer_deinit(MP_OBJ_FROM_PTR(tim)); + } + } +} + +#if defined(TIM5) +// TIM5 is set-up for the servo controller +// This function inits but does not start the timer +void timer_tim5_init(void) { + // TIM5 clock enable + __HAL_RCC_TIM5_CLK_ENABLE(); + + // set up and enable interrupt + NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5); + HAL_NVIC_EnableIRQ(TIM5_IRQn); + + // PWM clock configuration + TIM5_Handle.Instance = TIM5; + TIM5_Handle.Init.Period = 2000 - 1; // timer cycles at 50Hz + TIM5_Handle.Init.Prescaler = (timer_get_source_freq(5) / 100000) - 1; // timer runs at 100kHz + TIM5_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + TIM5_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; + + HAL_TIM_PWM_Init(&TIM5_Handle); +} +#endif + +#if defined(TIM6) +// Init TIM6 with a counter-overflow at the given frequency (given in Hz) +// TIM6 is used by the DAC and ADC for auto sampling at a given frequency +// This function inits but does not start the timer +TIM_HandleTypeDef *timer_tim6_init(uint freq) { + // TIM6 clock enable + __HAL_RCC_TIM6_CLK_ENABLE(); + + // Timer runs at SystemCoreClock / 2 + // Compute the prescaler value so TIM6 triggers at freq-Hz + uint32_t period = MAX(1, timer_get_source_freq(6) / freq); + uint32_t prescaler = 1; + while (period > 0xffff) { + period >>= 1; + prescaler <<= 1; + } + + // Time base clock configuration + TIM6_Handle.Instance = TIM6; + TIM6_Handle.Init.Period = period - 1; + TIM6_Handle.Init.Prescaler = prescaler - 1; + TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6 + TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 + HAL_TIM_Base_Init(&TIM6_Handle); + + return &TIM6_Handle; +} +#endif + +// Interrupt dispatch +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { + #if MICROPY_HW_ENABLE_SERVO + if (htim == &TIM5_Handle) { + servo_timer_irq_callback(); + } + #endif +} + +// Get the frequency (in Hz) of the source clock for the given timer. +// On STM32F405/407/415/417 there are 2 cases for how the clock freq is set. +// If the APB prescaler is 1, then the timer clock is equal to its respective +// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its +// respective APB clock. See DM00031020 Rev 4, page 115. +uint32_t timer_get_source_freq(uint32_t tim_id) { + uint32_t source, clk_div; + if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { + // TIM{1,8,9,10,11} are on APB2 + #if defined(STM32F0) + source = HAL_RCC_GetPCLK1Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) + source = HAL_RCC_GetPCLK2Freq(); + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2; + #else + source = HAL_RCC_GetPCLK2Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE2; + #endif + } else { + // TIM{2,3,4,5,6,7,12,13,14} are on APB1 + source = HAL_RCC_GetPCLK1Freq(); + #if defined(STM32F0) + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1; + #else + clk_div = RCC->CFGR & RCC_CFGR_PPRE1; + #endif + } + if (clk_div != 0) { + // APB prescaler for this timer is > 1 + source *= 2; + } + return source; +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC const mp_obj_type_t pyb_timer_channel_type; + +// This is the largest value that we can multiply by 100 and have the result +// fit in a uint32_t. +#define MAX_PERIOD_DIV_100 42949672 + +// computes prescaler and period so TIM triggers at freq-Hz +STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj_t freq_in, uint32_t *period_out) { + uint32_t source_freq = timer_get_source_freq(self->tim_id); + uint32_t prescaler = 1; + uint32_t period; + if (0) { + #if MICROPY_PY_BUILTINS_FLOAT + } else if (MP_OBJ_IS_TYPE(freq_in, &mp_type_float)) { + float freq = mp_obj_get_float(freq_in); + if (freq <= 0) { + goto bad_freq; + } + while (freq < 1 && prescaler < 6553) { + prescaler *= 10; + freq *= 10; + } + period = (float)source_freq / freq; + #endif + } else { + mp_int_t freq = mp_obj_get_int(freq_in); + if (freq <= 0) { + goto bad_freq; + bad_freq: + mp_raise_ValueError("must have positive freq"); + } + period = source_freq / freq; + } + period = MAX(1, period); + while (period > TIMER_CNT_MASK(self)) { + // if we can divide exactly, do that first + if (period % 5 == 0) { + prescaler *= 5; + period /= 5; + } else if (period % 3 == 0) { + prescaler *= 3; + period /= 3; + } else { + // may not divide exactly, but loses minimal precision + prescaler <<= 1; + period >>= 1; + } + } + *period_out = (period - 1) & TIMER_CNT_MASK(self); + return (prescaler - 1) & 0xffff; +} + +// computes prescaler and period so TIM triggers with a period of t_num/t_den seconds +STATIC uint32_t compute_prescaler_period_from_t(pyb_timer_obj_t *self, int32_t t_num, int32_t t_den, uint32_t *period_out) { + uint32_t source_freq = timer_get_source_freq(self->tim_id); + if (t_num <= 0 || t_den <= 0) { + mp_raise_ValueError("must have positive freq"); + } + uint64_t period = (uint64_t)source_freq * (uint64_t)t_num / (uint64_t)t_den; + uint32_t prescaler = 1; + while (period > TIMER_CNT_MASK(self)) { + // if we can divide exactly, and without prescaler overflow, do that first + if (prescaler <= 13107 && period % 5 == 0) { + prescaler *= 5; + period /= 5; + } else if (prescaler <= 21845 && period % 3 == 0) { + prescaler *= 3; + period /= 3; + } else { + // may not divide exactly, but loses minimal precision + uint32_t period_lsb = period & 1; + prescaler <<= 1; + period >>= 1; + if (period < prescaler) { + // round division up + prescaler |= period_lsb; + } + if (prescaler > 0x10000) { + mp_raise_ValueError("period too large"); + } + } + } + *period_out = (period - 1) & TIMER_CNT_MASK(self); + return (prescaler - 1) & 0xffff; +} + +// Helper function for determining the period used for calculating percent +STATIC uint32_t compute_period(pyb_timer_obj_t *self) { + // In center mode, compare == period corresponds to 100% + // In edge mode, compare == (period + 1) corresponds to 100% + uint32_t period = (__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); + if (period != 0xffffffff) { + if (self->tim.Init.CounterMode == TIM_COUNTERMODE_UP || + self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN) { + // Edge mode + period++; + } + } + return period; +} + +// Helper function to compute PWM value from timer period and percent value. +// 'percent_in' can be an int or a float between 0 and 100 (out of range +// values are clamped). +STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent_in) { + uint32_t cmp; + if (0) { + #if MICROPY_PY_BUILTINS_FLOAT + } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) { + mp_float_t percent = mp_obj_get_float(percent_in); + if (percent <= 0.0) { + cmp = 0; + } else if (percent >= 100.0) { + cmp = period; + } else { + cmp = percent / 100.0 * ((mp_float_t)period); + } + #endif + } else { + // For integer arithmetic, if period is large and 100*period will + // overflow, then divide period before multiplying by cmp. Otherwise + // do it the other way round to retain precision. + mp_int_t percent = mp_obj_get_int(percent_in); + if (percent <= 0) { + cmp = 0; + } else if (percent >= 100) { + cmp = period; + } else if (period > MAX_PERIOD_DIV_100) { + cmp = (uint32_t)percent * (period / 100); + } else { + cmp = ((uint32_t)percent * period) / 100; + } + } + return cmp; +} + +// Helper function to compute percentage from timer perion and PWM value. +STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) { + #if MICROPY_PY_BUILTINS_FLOAT + mp_float_t percent; + if (cmp >= period) { + percent = 100.0; + } else { + percent = (mp_float_t)cmp * 100.0 / ((mp_float_t)period); + } + return mp_obj_new_float(percent); + #else + mp_int_t percent; + if (cmp >= period) { + percent = 100; + } else if (cmp > MAX_PERIOD_DIV_100) { + percent = cmp / (period / 100); + } else { + percent = cmp * 100 / period; + } + return mp_obj_new_int(percent); + #endif +} + +// Computes the 8-bit value for the DTG field in the BDTR register. +// +// 1 tick = 1 count of the timer's clock (source_freq) divided by div. +// 0-128 ticks in inrements of 1 +// 128-256 ticks in increments of 2 +// 256-512 ticks in increments of 8 +// 512-1008 ticks in increments of 16 +STATIC uint32_t compute_dtg_from_ticks(mp_int_t ticks) { + if (ticks <= 0) { + return 0; + } + if (ticks < 128) { + return ticks; + } + if (ticks < 256) { + return 0x80 | ((ticks - 128) / 2); + } + if (ticks < 512) { + return 0xC0 | ((ticks - 256) / 8); + } + if (ticks < 1008) { + return 0xE0 | ((ticks - 512) / 16); + } + return 0xFF; +} + +// Given the 8-bit value stored in the DTG field of the BDTR register, compute +// the number of ticks. +STATIC mp_int_t compute_ticks_from_dtg(uint32_t dtg) { + if ((dtg & 0x80) == 0) { + return dtg & 0x7F; + } + if ((dtg & 0xC0) == 0x80) { + return 128 + ((dtg & 0x3F) * 2); + } + if ((dtg & 0xE0) == 0xC0) { + return 256 + ((dtg & 0x1F) * 8); + } + return 512 + ((dtg & 0x1F) * 16); +} + +STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) { + TIM_BreakDeadTimeConfigTypeDef deadTimeConfig; + deadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + deadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + deadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + deadTimeConfig.DeadTime = compute_dtg_from_ticks(ticks); + deadTimeConfig.BreakState = TIM_BREAK_DISABLE; + deadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW; + deadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig); +} + +TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) { + if (mp_obj_get_type(timer) != &pyb_timer_type) { + mp_raise_ValueError("need a Timer object"); + } + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(timer); + return &self->tim; +} + +STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->tim.State == HAL_TIM_STATE_RESET) { + mp_printf(print, "Timer(%u)", self->tim_id); + } else { + uint32_t prescaler = self->tim.Instance->PSC & 0xffff; + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); + // for efficiency, we compute and print freq as an int (not a float) + uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1)); + mp_printf(print, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u", + self->tim_id, + freq, + prescaler, + period, + self->tim.Init.CounterMode == TIM_COUNTERMODE_UP ? "UP" : + self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER", + self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 : + self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV2 ? 2 : 1); + + #if defined(IS_TIM_ADVANCED_INSTANCE) + if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) + #elif defined(IS_TIM_BREAK_INSTANCE) + if (IS_TIM_BREAK_INSTANCE(self->tim.Instance)) + #else + if (0) + #endif + { + mp_printf(print, ", deadtime=%u", + compute_ticks_from_dtg(self->tim.Instance->BDTR & TIM_BDTR_DTG)); + } + mp_print_str(print, ")"); + } +} + +/// \method init(*, freq, prescaler, period) +/// Initialise the timer. Initialisation must be either by frequency (in Hz) +/// or by prescaler and period: +/// +/// tim.init(freq=100) # set the timer to trigger at 100Hz +/// tim.init(prescaler=83, period=999) # set the prescaler and period directly +/// +/// Keyword arguments: +/// +/// - `freq` - specifies the periodic frequency of the timer. You migh also +/// view this as the frequency with which the timer goes through +/// one complete cycle. +/// +/// - `prescaler` [0-0xffff] - specifies the value to be loaded into the +/// timer's Prescaler Register (PSC). The timer clock source is divided by +/// (`prescaler + 1`) to arrive at the timer clock. Timers 2-7 and 12-14 +/// have a clock source of 84 MHz (pyb.freq()[2] * 2), and Timers 1, and 8-11 +/// have a clock source of 168 MHz (pyb.freq()[3] * 2). +/// +/// - `period` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5. +/// Specifies the value to be loaded into the timer's AutoReload +/// Register (ARR). This determines the period of the timer (i.e. when the +/// counter cycles). The timer counter will roll-over after `period + 1` +/// timer clock cycles. +/// +/// - `mode` can be one of: +/// - `Timer.UP` - configures the timer to count from 0 to ARR (default) +/// - `Timer.DOWN` - configures the timer to count from ARR down to 0. +/// - `Timer.CENTER` - confgures the timer to count from 0 to ARR and +/// then back down to 0. +/// +/// - `div` can be one of 1, 2, or 4. Divides the timer clock to determine +/// the sampling clock used by the digital filters. +/// +/// - `callback` - as per Timer.callback() +/// +/// - `deadtime` - specifies the amount of "dead" or inactive time between +/// transitions on complimentary channels (both channels will be inactive) +/// for this time). `deadtime` may be an integer between 0 and 1008, with +/// the following restrictions: 0-128 in steps of 1. 128-256 in steps of +/// 2, 256-512 in steps of 8, and 512-1008 in steps of 16. `deadime` +/// measures ticks of `source_freq` divided by `div` clock ticks. +/// `deadtime` is only available on timers 1 and 8. +/// +/// You must either specify freq or both of period and prescaler. +STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_prescaler, ARG_period, ARG_tick_hz, ARG_mode, ARG_div, ARG_callback, ARG_deadtime }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_COUNTERMODE_UP} }, + { MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // set the TIM configuration values + TIM_Base_InitTypeDef *init = &self->tim.Init; + + if (args[ARG_freq].u_obj != mp_const_none) { + // set prescaler and period from desired frequency + init->Prescaler = compute_prescaler_period_from_freq(self, args[ARG_freq].u_obj, &init->Period); + } else if (args[ARG_prescaler].u_int != 0xffffffff && args[ARG_period].u_int != 0xffffffff) { + // set prescaler and period directly + init->Prescaler = args[ARG_prescaler].u_int; + init->Period = args[ARG_period].u_int; + } else if (args[ARG_period].u_int != 0xffffffff) { + // set prescaler and period from desired period and tick_hz scale + init->Prescaler = compute_prescaler_period_from_t(self, args[ARG_period].u_int, args[ARG_tick_hz].u_int, &init->Period); + } else { + mp_raise_TypeError("must specify either freq, period, or prescaler and period"); + } + + init->CounterMode = args[ARG_mode].u_int; + if (!IS_TIM_COUNTER_MODE(init->CounterMode)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid mode (%d)", init->CounterMode)); + } + + init->ClockDivision = args[ARG_div].u_int == 2 ? TIM_CLOCKDIVISION_DIV2 : + args[ARG_div].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 : + TIM_CLOCKDIVISION_DIV1; + + init->RepetitionCounter = 0; + + // enable TIM clock + switch (self->tim_id) { + case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break; + case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break; + case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break; + #if defined(TIM4) + case 4: __HAL_RCC_TIM4_CLK_ENABLE(); break; + #endif + #if defined(TIM5) + case 5: __HAL_RCC_TIM5_CLK_ENABLE(); break; + #endif + #if defined(TIM6) + case 6: __HAL_RCC_TIM6_CLK_ENABLE(); break; + #endif + #if defined(TIM7) + case 7: __HAL_RCC_TIM7_CLK_ENABLE(); break; + #endif + #if defined(TIM8) + case 8: __HAL_RCC_TIM8_CLK_ENABLE(); break; + #endif + #if defined(TIM9) + case 9: __HAL_RCC_TIM9_CLK_ENABLE(); break; + #endif + #if defined(TIM10) + case 10: __HAL_RCC_TIM10_CLK_ENABLE(); break; + #endif + #if defined(TIM11) + case 11: __HAL_RCC_TIM11_CLK_ENABLE(); break; + #endif + #if defined(TIM12) + case 12: __HAL_RCC_TIM12_CLK_ENABLE(); break; + #endif + #if defined(TIM13) + case 13: __HAL_RCC_TIM13_CLK_ENABLE(); break; + #endif + #if defined(TIM14) + case 14: __HAL_RCC_TIM14_CLK_ENABLE(); break; + #endif + #if defined(TIM15) + case 15: __HAL_RCC_TIM15_CLK_ENABLE(); break; + #endif + #if defined(TIM16) + case 16: __HAL_RCC_TIM16_CLK_ENABLE(); break; + #endif + #if defined(TIM17) + case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break; + #endif + } + + // set IRQ priority (if not a special timer) + if (self->tim_id != 5) { + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX); + if (self->tim_id == 1) { + NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX); + #if defined(TIM8) + } else if (self->tim_id == 8) { + NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX); + #endif + } + } + + // init TIM + HAL_TIM_Base_Init(&self->tim); + #if defined(IS_TIM_ADVANCED_INSTANCE) + if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) { + #elif defined(IS_TIM_BREAK_INSTANCE) + if (IS_TIM_BREAK_INSTANCE(self->tim.Instance)) { + #else + if (0) { + #endif + config_deadtime(self, args[ARG_deadtime].u_int); + } + + // Enable ARPE so that the auto-reload register is buffered. + // This allows to smoothly change the frequency of the timer. + self->tim.Instance->CR1 |= TIM_CR1_ARPE; + + // Start the timer running + if (args[ARG_callback].u_obj == mp_const_none) { + HAL_TIM_Base_Start(&self->tim); + } else { + pyb_timer_callback(MP_OBJ_FROM_PTR(self), args[ARG_callback].u_obj); + } + + return mp_const_none; +} + +// This table encodes the timer instance and irq number (for the update irq). +// It assumes that timer instance pointer has the lower 8 bits cleared. +#define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq +STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { + #if defined(STM32F0) + TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn), + #elif defined(STM32F4) || defined(STM32F7) + TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), + #elif defined(STM32L4) + TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), + #endif + TIM_ENTRY(2, TIM2_IRQn), + TIM_ENTRY(3, TIM3_IRQn), + #if defined(TIM4) + TIM_ENTRY(4, TIM4_IRQn), + #endif + #if defined(TIM5) + TIM_ENTRY(5, TIM5_IRQn), + #endif + #if defined(TIM6) + TIM_ENTRY(6, TIM6_DAC_IRQn), + #endif + #if defined(TIM7) + TIM_ENTRY(7, TIM7_IRQn), + #endif + #if defined(TIM8) + #if defined(STM32F4) || defined(STM32F7) + TIM_ENTRY(8, TIM8_UP_TIM13_IRQn), + #elif defined(STM32L4) + TIM_ENTRY(8, TIM8_UP_IRQn), + #endif + #endif + #if defined(TIM9) + TIM_ENTRY(9, TIM1_BRK_TIM9_IRQn), + #endif + #if defined(TIM10) + TIM_ENTRY(10, TIM1_UP_TIM10_IRQn), + #endif + #if defined(TIM11) + TIM_ENTRY(11, TIM1_TRG_COM_TIM11_IRQn), + #endif + #if defined(TIM12) + TIM_ENTRY(12, TIM8_BRK_TIM12_IRQn), + #endif + #if defined(TIM13) + TIM_ENTRY(13, TIM8_UP_TIM13_IRQn), + #endif + #if defined(STM32F0) + TIM_ENTRY(14, TIM14_IRQn), + #elif defined(TIM14) + TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn), + #endif + #if defined(TIM15) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(15, TIM15_IRQn), + #else + TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn), + #endif + #endif + #if defined(TIM16) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(16, TIM16_IRQn), + #else + TIM_ENTRY(16, TIM1_UP_TIM16_IRQn), + #endif + #endif + #if defined(TIM17) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(17, TIM17_IRQn), + #else + TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn), + #endif + #endif +}; +#undef TIM_ENTRY + +/// \classmethod \constructor(id, ...) +/// Construct a new timer object of the given id. If additional +/// arguments are given, then the timer is initialised by `init(...)`. +/// `id` can be 1 to 14, excluding 3. +STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the timer id + mp_int_t tim_id = mp_obj_get_int(args[0]); + + // check if the timer exists + if (tim_id <= 0 || tim_id > MICROPY_HW_MAX_TIMER || tim_instance_table[tim_id - 1] == 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer(%d) doesn't exist", tim_id)); + } + + pyb_timer_obj_t *tim; + if (MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1] == NULL) { + // create new Timer object + tim = m_new_obj(pyb_timer_obj_t); + memset(tim, 0, sizeof(*tim)); + tim->base.type = &pyb_timer_type; + tim->tim_id = tim_id; + tim->is_32bit = tim_id == 2 || tim_id == 5; + tim->callback = mp_const_none; + uint32_t ti = tim_instance_table[tim_id - 1]; + tim->tim.Instance = (TIM_TypeDef*)(ti & 0xffffff00); + tim->irqn = ti & 0xff; + MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1] = tim; + } else { + // reference existing Timer object + tim = MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1]; + } + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(tim); +} + +STATIC mp_obj_t pyb_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_timer_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); + +// timer.deinit() +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Disable the base interrupt + pyb_timer_callback(self_in, mp_const_none); + + pyb_timer_channel_obj_t *chan = self->channel; + self->channel = NULL; + + // Disable the channel interrupts + while (chan != NULL) { + pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), mp_const_none); + pyb_timer_channel_obj_t *prev_chan = chan; + chan = chan->next; + prev_chan->next = NULL; + } + + self->tim.State = HAL_TIM_STATE_RESET; + self->tim.Instance->CCER = 0x0000; // disable all capture/compare outputs + self->tim.Instance->CR1 = 0x0000; // disable the timer and reset its state + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); + +/// \method channel(channel, mode, ...) +/// +/// If only a channel number is passed, then a previously initialized channel +/// object is returned (or `None` if there is no previous channel). +/// +/// Othwerwise, a TimerChannel object is initialized and returned. +/// +/// Each channel can be configured to perform pwm, output compare, or +/// input capture. All channels share the same underlying timer, which means +/// that they share the same timer clock. +/// +/// Keyword arguments: +/// +/// - `mode` can be one of: +/// - `Timer.PWM` - configure the timer in PWM mode (active high). +/// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low). +/// - `Timer.OC_TIMING` - indicates that no pin is driven. +/// - `Timer.OC_ACTIVE` - the pin will be made active when a compare +/// match occurs (active is determined by polarity) +/// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare +/// match occurs. +/// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs. +/// - `Timer.OC_FORCED_ACTIVE` - the pin is forced active (compare match is ignored). +/// - `Timer.OC_FORCED_INACTIVE` - the pin is forced inactive (compare match is ignored). +/// - `Timer.IC` - configure the timer in Input Capture mode. +/// - `Timer.ENC_A` --- configure the timer in Encoder mode. The counter only changes when CH1 changes. +/// - `Timer.ENC_B` --- configure the timer in Encoder mode. The counter only changes when CH2 changes. +/// - `Timer.ENC_AB` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes. +/// +/// - `callback` - as per TimerChannel.callback() +/// +/// - `pin` None (the default) or a Pin object. If specified (and not None) +/// this will cause the alternate function of the the indicated pin +/// to be configured for this timer channel. An error will be raised if +/// the pin doesn't support any alternate functions for this timer channel. +/// +/// Keyword arguments for Timer.PWM modes: +/// +/// - `pulse_width` - determines the initial pulse width value to use. +/// - `pulse_width_percent` - determines the initial pulse width percentage to use. +/// +/// Keyword arguments for Timer.OC modes: +/// +/// - `compare` - determines the initial value of the compare register. +/// +/// - `polarity` can be one of: +/// - `Timer.HIGH` - output is active high +/// - `Timer.LOW` - output is acive low +/// +/// Optional keyword arguments for Timer.IC modes: +/// +/// - `polarity` can be one of: +/// - `Timer.RISING` - captures on rising edge. +/// - `Timer.FALLING` - captures on falling edge. +/// - `Timer.BOTH` - captures on both edges. +/// +/// Note that capture only works on the primary channel, and not on the +/// complimentary channels. +/// +/// Notes for Timer.ENC modes: +/// +/// - Requires 2 pins, so one or both pins will need to be configured to use +/// the appropriate timer AF using the Pin API. +/// - Read the encoder value using the timer.counter() method. +/// - Only works on CH1 and CH2 (and not on CH1N or CH2N) +/// - The channel number is ignored when setting the encoder mode. +/// +/// PWM Example: +/// +/// timer = pyb.Timer(2, freq=1000) +/// ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=210000) +/// ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=420000) +STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + }; + + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_int_t channel = mp_obj_get_int(pos_args[1]); + + if (channel < 1 || channel > 4) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid channel (%d)", channel)); + } + + pyb_timer_channel_obj_t *chan = self->channel; + pyb_timer_channel_obj_t *prev_chan = NULL; + + while (chan != NULL) { + if (chan->channel == channel) { + break; + } + prev_chan = chan; + chan = chan->next; + } + + // If only the channel number is given return the previously allocated + // channel (or None if no previous channel). + if (n_args == 2 && kw_args->used == 0) { + if (chan) { + return MP_OBJ_FROM_PTR(chan); + } + return mp_const_none; + } + + // If there was already a channel, then remove it from the list. Note that + // the order we do things here is important so as to appear atomic to + // the IRQ handler. + if (chan) { + // Turn off any IRQ associated with the channel. + pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), mp_const_none); + + // Unlink the channel from the list. + if (prev_chan) { + prev_chan->next = chan->next; + } + self->channel = chan->next; + chan->next = NULL; + } + + // Allocate and initialize a new channel + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + chan = m_new_obj(pyb_timer_channel_obj_t); + memset(chan, 0, sizeof(*chan)); + chan->base.type = &pyb_timer_channel_type; + chan->timer = self; + chan->channel = channel; + chan->mode = args[0].u_int; + chan->callback = args[1].u_obj; + + mp_obj_t pin_obj = args[2].u_obj; + if (pin_obj != mp_const_none) { + if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + mp_raise_ValueError("pin argument needs to be be a Pin type"); + } + const pin_obj_t *pin = MP_OBJ_TO_PTR(pin_obj); + const pin_af_obj_t *af = pin_find_af(pin, AF_FN_TIM, self->tim_id); + if (af == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have an af for Timer(%d)", pin->name, self->tim_id)); + } + // pin.init(mode=AF_PP, af=idx) + const mp_obj_t args2[6] = { + MP_OBJ_FROM_PTR(&pin_init_obj), + pin_obj, + MP_OBJ_NEW_QSTR(MP_QSTR_mode), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP), + MP_OBJ_NEW_QSTR(MP_QSTR_af), MP_OBJ_NEW_SMALL_INT(af->idx) + }; + mp_call_method_n_kw(0, 2, args2); + } + + // Link the channel to the timer before we turn the channel on. + // Note that this needs to appear atomic to the IRQ handler (the write + // to self->channel is atomic, so we're good, but I thought I'd mention + // in case this was ever changed in the future). + chan->next = self->channel; + self->channel = chan; + + switch (chan->mode) { + + case CHANNEL_MODE_PWM_NORMAL: + case CHANNEL_MODE_PWM_INVERTED: { + TIM_OC_InitTypeDef oc_config; + oc_config.OCMode = channel_mode_info[chan->mode].oc_mode; + if (args[4].u_obj != mp_const_none) { + // pulse width percent given + uint32_t period = compute_period(self); + oc_config.Pulse = compute_pwm_value_from_percent(period, args[4].u_obj); + } else { + // use absolute pulse width value (defaults to 0 if nothing given) + oc_config.Pulse = args[3].u_int; + } + oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; + oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; + oc_config.OCFastMode = TIM_OCFAST_DISABLE; + oc_config.OCIdleState = TIM_OCIDLESTATE_SET; + oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; + + HAL_TIM_PWM_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan)); + if (chan->callback == mp_const_none) { + HAL_TIM_PWM_Start(&self->tim, TIMER_CHANNEL(chan)); + } else { + pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); + } + // Start the complimentary channel too (if its supported) + if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { + HAL_TIMEx_PWMN_Start(&self->tim, TIMER_CHANNEL(chan)); + } + break; + } + + case CHANNEL_MODE_OC_TIMING: + case CHANNEL_MODE_OC_ACTIVE: + case CHANNEL_MODE_OC_INACTIVE: + case CHANNEL_MODE_OC_TOGGLE: + case CHANNEL_MODE_OC_FORCED_ACTIVE: + case CHANNEL_MODE_OC_FORCED_INACTIVE: { + TIM_OC_InitTypeDef oc_config; + oc_config.OCMode = channel_mode_info[chan->mode].oc_mode; + oc_config.Pulse = args[5].u_int; + oc_config.OCPolarity = args[6].u_int; + if (oc_config.OCPolarity == 0xffffffff) { + oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; + } + if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) { + oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; + } else { + oc_config.OCNPolarity = TIM_OCNPOLARITY_LOW; + } + oc_config.OCFastMode = TIM_OCFAST_DISABLE; + oc_config.OCIdleState = TIM_OCIDLESTATE_SET; + oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; + + if (!IS_TIM_OC_POLARITY(oc_config.OCPolarity)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", oc_config.OCPolarity)); + } + HAL_TIM_OC_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan)); + if (chan->callback == mp_const_none) { + HAL_TIM_OC_Start(&self->tim, TIMER_CHANNEL(chan)); + } else { + pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); + } + // Start the complimentary channel too (if its supported) + if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { + HAL_TIMEx_OCN_Start(&self->tim, TIMER_CHANNEL(chan)); + } + break; + } + + case CHANNEL_MODE_IC: { + TIM_IC_InitTypeDef ic_config; + + ic_config.ICPolarity = args[6].u_int; + if (ic_config.ICPolarity == 0xffffffff) { + ic_config.ICPolarity = TIM_ICPOLARITY_RISING; + } + ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI; + ic_config.ICPrescaler = TIM_ICPSC_DIV1; + ic_config.ICFilter = 0; + + if (!IS_TIM_IC_POLARITY(ic_config.ICPolarity)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", ic_config.ICPolarity)); + } + HAL_TIM_IC_ConfigChannel(&self->tim, &ic_config, TIMER_CHANNEL(chan)); + if (chan->callback == mp_const_none) { + HAL_TIM_IC_Start(&self->tim, TIMER_CHANNEL(chan)); + } else { + pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); + } + break; + } + + case CHANNEL_MODE_ENC_A: + case CHANNEL_MODE_ENC_B: + case CHANNEL_MODE_ENC_AB: { + TIM_Encoder_InitTypeDef enc_config; + + enc_config.EncoderMode = channel_mode_info[chan->mode].oc_mode; + enc_config.IC1Polarity = args[6].u_int; + if (enc_config.IC1Polarity == 0xffffffff) { + enc_config.IC1Polarity = TIM_ICPOLARITY_RISING; + } + enc_config.IC2Polarity = enc_config.IC1Polarity; + enc_config.IC1Selection = TIM_ICSELECTION_DIRECTTI; + enc_config.IC2Selection = TIM_ICSELECTION_DIRECTTI; + enc_config.IC1Prescaler = TIM_ICPSC_DIV1; + enc_config.IC2Prescaler = TIM_ICPSC_DIV1; + enc_config.IC1Filter = 0; + enc_config.IC2Filter = 0; + + if (!IS_TIM_IC_POLARITY(enc_config.IC1Polarity)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", enc_config.IC1Polarity)); + } + // Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode + if (self->tim.Instance != TIM1 + && self->tim.Instance != TIM2 + && self->tim.Instance != TIM3 + #if defined(TIM4) + && self->tim.Instance != TIM4 + #endif + #if defined(TIM5) + && self->tim.Instance != TIM5 + #endif + #if defined(TIM8) + && self->tim.Instance != TIM8 + #endif + ) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "encoder not supported on timer %d", self->tim_id)); + } + + // Disable & clear the timer interrupt so that we don't trigger + // an interrupt by initializing the timer. + __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE); + HAL_TIM_Encoder_Init(&self->tim, &enc_config); + __HAL_TIM_SET_COUNTER(&self->tim, 0); + if (self->callback != mp_const_none) { + __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE); + __HAL_TIM_ENABLE_IT(&self->tim, TIM_IT_UPDATE); + } + HAL_TIM_Encoder_Start(&self->tim, TIM_CHANNEL_ALL); + break; + } + + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid mode (%d)", chan->mode)); + } + + return MP_OBJ_FROM_PTR(chan); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); + +/// \method counter([value]) +/// Get or set the timer counter. +STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + return mp_obj_new_int(self->tim.Instance->CNT); + } else { + // set + __HAL_TIM_SET_COUNTER(&self->tim, mp_obj_get_int(args[1])); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter); + +/// \method source_freq() +/// Get the frequency of the source of the timer. +STATIC mp_obj_t pyb_timer_source_freq(mp_obj_t self_in) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t source_freq = timer_get_source_freq(self->tim_id); + return mp_obj_new_int(source_freq); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_source_freq_obj, pyb_timer_source_freq); + +/// \method freq([value]) +/// Get or set the frequency for the timer (changes prescaler and period if set). +STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + uint32_t prescaler = self->tim.Instance->PSC & 0xffff; + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); + uint32_t source_freq = timer_get_source_freq(self->tim_id); + uint32_t divide = ((prescaler + 1) * (period + 1)); + #if MICROPY_PY_BUILTINS_FLOAT + if (source_freq % divide != 0) { + return mp_obj_new_float((float)source_freq / (float)divide); + } else + #endif + { + return mp_obj_new_int(source_freq / divide); + } + } else { + // set + uint32_t period; + uint32_t prescaler = compute_prescaler_period_from_freq(self, args[1], &period); + self->tim.Instance->PSC = prescaler; + __HAL_TIM_SET_AUTORELOAD(&self->tim, period); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_freq_obj, 1, 2, pyb_timer_freq); + +/// \method prescaler([value]) +/// Get or set the prescaler for the timer. +STATIC mp_obj_t pyb_timer_prescaler(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + return mp_obj_new_int(self->tim.Instance->PSC & 0xffff); + } else { + // set + self->tim.Instance->PSC = mp_obj_get_int(args[1]) & 0xffff; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler); + +/// \method period([value]) +/// Get or set the period of the timer. +STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + return mp_obj_new_int(__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); + } else { + // set + __HAL_TIM_SET_AUTORELOAD(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self)); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period); + +/// \method callback(fun) +/// Set the function to be called when the timer triggers. +/// `fun` is passed 1 argument, the timer object. +/// If `fun` is `None` then the callback will be disabled. +STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) { + pyb_timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (callback == mp_const_none) { + // stop interrupt (but not timer) + __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE); + self->callback = mp_const_none; + } else if (mp_obj_is_callable(callback)) { + __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE); + self->callback = callback; + // start timer, so that it interrupts on overflow, but clear any + // pending interrupts which may have been set by initializing it. + __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE); + HAL_TIM_Base_Start_IT(&self->tim); // This will re-enable the IRQ + HAL_NVIC_EnableIRQ(self->irqn); + } else { + mp_raise_ValueError("callback must be None or a callable object"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback); + +STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&pyb_timer_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_counter), MP_ROM_PTR(&pyb_timer_counter_obj) }, + { MP_ROM_QSTR(MP_QSTR_source_freq), MP_ROM_PTR(&pyb_timer_source_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_timer_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_prescaler), MP_ROM_PTR(&pyb_timer_prescaler_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&pyb_timer_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(TIM_COUNTERMODE_UP) }, + { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(TIM_COUNTERMODE_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(TIM_COUNTERMODE_CENTERALIGNED1) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_INT(CHANNEL_MODE_PWM_NORMAL) }, + { MP_ROM_QSTR(MP_QSTR_PWM_INVERTED), MP_ROM_INT(CHANNEL_MODE_PWM_INVERTED) }, + { MP_ROM_QSTR(MP_QSTR_OC_TIMING), MP_ROM_INT(CHANNEL_MODE_OC_TIMING) }, + { MP_ROM_QSTR(MP_QSTR_OC_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_OC_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_INACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_OC_TOGGLE), MP_ROM_INT(CHANNEL_MODE_OC_TOGGLE) }, + { MP_ROM_QSTR(MP_QSTR_OC_FORCED_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_FORCED_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_OC_FORCED_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_FORCED_INACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_IC), MP_ROM_INT(CHANNEL_MODE_IC) }, + { MP_ROM_QSTR(MP_QSTR_ENC_A), MP_ROM_INT(CHANNEL_MODE_ENC_A) }, + { MP_ROM_QSTR(MP_QSTR_ENC_B), MP_ROM_INT(CHANNEL_MODE_ENC_B) }, + { MP_ROM_QSTR(MP_QSTR_ENC_AB), MP_ROM_INT(CHANNEL_MODE_ENC_AB) }, + { MP_ROM_QSTR(MP_QSTR_HIGH), MP_ROM_INT(TIM_OCPOLARITY_HIGH) }, + { MP_ROM_QSTR(MP_QSTR_LOW), MP_ROM_INT(TIM_OCPOLARITY_LOW) }, + { MP_ROM_QSTR(MP_QSTR_RISING), MP_ROM_INT(TIM_ICPOLARITY_RISING) }, + { MP_ROM_QSTR(MP_QSTR_FALLING), MP_ROM_INT(TIM_ICPOLARITY_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(TIM_ICPOLARITY_BOTHEDGE) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); + +const mp_obj_type_t pyb_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = pyb_timer_print, + .make_new = pyb_timer_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_timer_locals_dict, +}; + +/// \moduleref pyb +/// \class TimerChannel - setup a channel for a timer. +/// +/// Timer channels are used to generate/capture a signal using a timer. +/// +/// TimerChannel objects are created using the Timer.channel() method. +STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_channel_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_printf(print, "TimerChannel(timer=%u, channel=%u, mode=%s)", + self->timer->tim_id, + self->channel, + qstr_str(channel_mode_info[self->mode].name)); +} + +/// \method capture([value]) +/// Get or set the capture value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// capture is the logical name to use when the channel is in input capture mode. + +/// \method compare([value]) +/// Get or set the compare value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// compare is the logical name to use when the channel is in output compare mode. + +/// \method pulse_width([value]) +/// Get or set the pulse width value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// pulse_width is the logical name to use when the channel is in PWM mode. +/// +/// In edge aligned mode, a pulse_width of `period + 1` corresponds to a duty cycle of 100% +/// In center aligned mode, a pulse width of `period` corresponds to a duty cycle of 100% +STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // get + return mp_obj_new_int(__HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer)); + } else { + // set + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer)); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare); + +/// \method pulse_width_percent([value]) +/// Get or set the pulse width percentage associated with a channel. The value +/// is a number between 0 and 100 and sets the percentage of the timer period +/// for which the pulse is active. The value can be an integer or +/// floating-point number for more accuracy. For example, a value of 25 gives +/// a duty cycle of 25%. +STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t period = compute_period(self->timer); + if (n_args == 1) { + // get + uint32_t cmp = __HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer); + return compute_percent_from_pwm_value(period, cmp); + } else { + // set + uint32_t cmp = compute_pwm_value_from_percent(period, args[1]); + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer)); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent); + +/// \method callback(fun) +/// Set the function to be called when the timer channel triggers. +/// `fun` is passed 1 argument, the timer object. +/// If `fun` is `None` then the callback will be disabled. +STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) { + pyb_timer_channel_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (callback == mp_const_none) { + // stop interrupt (but not timer) + __HAL_TIM_DISABLE_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel)); + self->callback = mp_const_none; + } else if (mp_obj_is_callable(callback)) { + self->callback = callback; + uint8_t tim_id = self->timer->tim_id; + __HAL_TIM_CLEAR_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel)); + if (tim_id == 1) { + HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); + #if defined(TIM8) // STM32F401 doesn't have a TIM8 + } else if (tim_id == 8) { + HAL_NVIC_EnableIRQ(TIM8_CC_IRQn); + #endif + } else { + HAL_NVIC_EnableIRQ(self->timer->irqn); + } + // start timer, so that it interrupts on overflow + switch (self->mode) { + case CHANNEL_MODE_PWM_NORMAL: + case CHANNEL_MODE_PWM_INVERTED: + HAL_TIM_PWM_Start_IT(&self->timer->tim, TIMER_CHANNEL(self)); + break; + case CHANNEL_MODE_OC_TIMING: + case CHANNEL_MODE_OC_ACTIVE: + case CHANNEL_MODE_OC_INACTIVE: + case CHANNEL_MODE_OC_TOGGLE: + case CHANNEL_MODE_OC_FORCED_ACTIVE: + case CHANNEL_MODE_OC_FORCED_INACTIVE: + HAL_TIM_OC_Start_IT(&self->timer->tim, TIMER_CHANNEL(self)); + break; + case CHANNEL_MODE_IC: + HAL_TIM_IC_Start_IT(&self->timer->tim, TIMER_CHANNEL(self)); + break; + } + } else { + mp_raise_ValueError("callback must be None or a callable object"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_channel_callback_obj, pyb_timer_channel_callback); + +STATIC const mp_rom_map_elem_t pyb_timer_channel_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_channel_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, + { MP_ROM_QSTR(MP_QSTR_pulse_width_percent), MP_ROM_PTR(&pyb_timer_channel_pulse_width_percent_obj) }, + { MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, + { MP_ROM_QSTR(MP_QSTR_compare), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_timer_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_TimerChannel, + .print = pyb_timer_channel_print, + .locals_dict = (mp_obj_dict_t*)&pyb_timer_channel_locals_dict, +}; + +STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_obj_t callback) { + uint32_t irq_mask = TIMER_IRQ_MASK(channel); + + if (__HAL_TIM_GET_FLAG(&tim->tim, irq_mask) != RESET) { + if (__HAL_TIM_GET_IT_SOURCE(&tim->tim, irq_mask) != RESET) { + // clear the interrupt + __HAL_TIM_CLEAR_IT(&tim->tim, irq_mask); + + // execute callback if it's set + if (callback != mp_const_none) { + mp_sched_lock(); + // When executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(callback, MP_OBJ_FROM_PTR(tim)); + nlr_pop(); + } else { + // Uncaught exception; disable the callback so it doesn't run again. + tim->callback = mp_const_none; + __HAL_TIM_DISABLE_IT(&tim->tim, irq_mask); + if (channel == 0) { + printf("uncaught exception in Timer(%u) interrupt handler\n", tim->tim_id); + } else { + printf("uncaught exception in Timer(%u) channel %u interrupt handler\n", tim->tim_id, channel); + } + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + gc_unlock(); + mp_sched_unlock(); + } + } + } +} + +void timer_irq_handler(uint tim_id) { + if (tim_id - 1 < PYB_TIMER_OBJ_ALL_NUM) { + // get the timer object + pyb_timer_obj_t *tim = MP_STATE_PORT(pyb_timer_obj_all)[tim_id - 1]; + + if (tim == NULL) { + // Timer object has not been set, so we can't do anything. + // This can happen under normal circumstances for timers like + // 1 & 10 which use the same IRQ. + return; + } + + // Check for timer (versus timer channel) interrupt. + timer_handle_irq_channel(tim, 0, tim->callback); + uint32_t handled = TIMER_IRQ_MASK(0); + + // Check to see if a timer channel interrupt was pending + pyb_timer_channel_obj_t *chan = tim->channel; + while (chan != NULL) { + timer_handle_irq_channel(tim, chan->channel, chan->callback); + handled |= TIMER_IRQ_MASK(chan->channel); + chan = chan->next; + } + + // Finally, clear any remaining interrupt sources. Otherwise we'll + // just get called continuously. + uint32_t unhandled = tim->tim.Instance->DIER & 0xff & ~handled; + if (unhandled != 0) { + __HAL_TIM_DISABLE_IT(&tim->tim, unhandled); + __HAL_TIM_CLEAR_IT(&tim->tim, unhandled); + printf("Unhandled interrupt SR=0x%02x (now disabled)\n", (unsigned int)unhandled); + } + } +} diff --git a/src/openmv/src/micropython/ports/stm32/timer.h b/src/openmv/src/micropython/ports/stm32/timer.h new file mode 100755 index 0000000..2ba91cf --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/timer.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_TIMER_H +#define MICROPY_INCLUDED_STM32_TIMER_H + +extern TIM_HandleTypeDef TIM5_Handle; + +extern const mp_obj_type_t pyb_timer_type; + +void timer_init0(void); +void timer_tim5_init(void); +TIM_HandleTypeDef *timer_tim6_init(uint freq); +void timer_deinit(void); +uint32_t timer_get_source_freq(uint32_t tim_id); +void timer_irq_handler(uint tim_id); + +TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer); + +#endif // MICROPY_INCLUDED_STM32_TIMER_H diff --git a/src/openmv/src/micropython/ports/stm32/uart.c b/src/openmv/src/micropython/ports/stm32/uart.c new file mode 100755 index 0000000..775d868 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/uart.c @@ -0,0 +1,1160 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "lib/utils/interrupt_char.h" +#include "uart.h" +#include "irq.h" +#include "pendsv.h" + +/// \moduleref pyb +/// \class UART - duplex serial communication bus +/// +/// UART implements the standard UART/USART duplex serial communications protocol. At +/// the physical level it consists of 2 lines: RX and TX. The unit of communication +/// is a character (not to be confused with a string character) which can be 8 or 9 +/// bits wide. +/// +/// UART objects can be created and initialised using: +/// +/// from pyb import UART +/// +/// uart = UART(1, 9600) # init with given baudrate +/// uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters +/// +/// Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2. +/// +/// A UART object acts like a stream object and reading and writing is done +/// using the standard stream methods: +/// +/// uart.read(10) # read 10 characters, returns a bytes object +/// uart.read() # read all available characters +/// uart.readline() # read a line +/// uart.readinto(buf) # read and store into the given buffer +/// uart.write('abc') # write the 3 characters +/// +/// Individual characters can be read/written using: +/// +/// uart.readchar() # read 1 character and returns it as an integer +/// uart.writechar(42) # write 1 character +/// +/// To check if there is anything to be read, use: +/// +/// uart.any() # returns True if any characters waiting + +#define CHAR_WIDTH_8BIT (0) +#define CHAR_WIDTH_9BIT (1) + +struct _pyb_uart_obj_t { + mp_obj_base_t base; + UART_HandleTypeDef uart; // this is 17 words big + IRQn_Type irqn; + pyb_uart_t uart_id : 8; + bool is_enabled : 1; + bool attached_to_repl; // whether the UART is attached to REPL + byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars + uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit + uint16_t timeout; // timeout waiting for first char + uint16_t timeout_char; // timeout waiting between chars + uint16_t read_buf_len; // len in chars; buf can hold len-1 chars + volatile uint16_t read_buf_head; // indexes first empty slot + uint16_t read_buf_tail; // indexes first full slot (not full if equals head) + byte *read_buf; // byte or uint16_t, depending on char size +}; + +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in); +extern void NORETURN __fatal_error(const char *msg); + +void uart_init0(void) { + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0}; + // Configure USART1/6 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + + // Configure USART2/3/4/5/7/8 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + #endif + + for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) { + MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL; + } +} + +// unregister all interrupt sources +void uart_deinit(void) { + for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) { + pyb_uart_obj_t *uart_obj = MP_STATE_PORT(pyb_uart_obj_all)[i]; + if (uart_obj != NULL) { + pyb_uart_deinit(MP_OBJ_FROM_PTR(uart_obj)); + } + } +} + +STATIC bool uart_exists(int uart_id) { + if (uart_id > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all))) { + // safeguard against pyb_uart_obj_all array being configured too small + return false; + } + switch (uart_id) { + #if defined(MICROPY_HW_UART1_TX) && defined(MICROPY_HW_UART1_RX) + case PYB_UART_1: return true; + #endif + + #if defined(MICROPY_HW_UART2_TX) && defined(MICROPY_HW_UART2_RX) + case PYB_UART_2: return true; + #endif + + #if defined(MICROPY_HW_UART3_TX) && defined(MICROPY_HW_UART3_RX) + case PYB_UART_3: return true; + #endif + + #if defined(MICROPY_HW_UART4_TX) && defined(MICROPY_HW_UART4_RX) + case PYB_UART_4: return true; + #endif + + #if defined(MICROPY_HW_UART5_TX) && defined(MICROPY_HW_UART5_RX) + case PYB_UART_5: return true; + #endif + + #if defined(MICROPY_HW_UART6_TX) && defined(MICROPY_HW_UART6_RX) + case PYB_UART_6: return true; + #endif + + #if defined(MICROPY_HW_UART7_TX) && defined(MICROPY_HW_UART7_RX) + case PYB_UART_7: return true; + #endif + + #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX) + case PYB_UART_8: return true; + #endif + + default: return false; + } +} + +// assumes Init parameters have been set up correctly +STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { + USART_TypeDef *UARTx; + IRQn_Type irqn; + int uart_unit; + + const pin_obj_t *pins[4] = {0}; + + switch (uart_obj->uart_id) { + #if defined(MICROPY_HW_UART1_TX) && defined(MICROPY_HW_UART1_RX) + case PYB_UART_1: + uart_unit = 1; + UARTx = USART1; + irqn = USART1_IRQn; + pins[0] = MICROPY_HW_UART1_TX; + pins[1] = MICROPY_HW_UART1_RX; + __HAL_RCC_USART1_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_UART2_TX) && defined(MICROPY_HW_UART2_RX) + case PYB_UART_2: + uart_unit = 2; + UARTx = USART2; + irqn = USART2_IRQn; + pins[0] = MICROPY_HW_UART2_TX; + pins[1] = MICROPY_HW_UART2_RX; + #if defined(MICROPY_HW_UART2_RTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + pins[2] = MICROPY_HW_UART2_RTS; + } + #endif + #if defined(MICROPY_HW_UART2_CTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + pins[3] = MICROPY_HW_UART2_CTS; + } + #endif + __HAL_RCC_USART2_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_UART3_TX) && defined(MICROPY_HW_UART3_RX) + case PYB_UART_3: + uart_unit = 3; + UARTx = USART3; + #if defined(STM32F0) + irqn = USART3_8_IRQn; + #else + irqn = USART3_IRQn; + #endif + pins[0] = MICROPY_HW_UART3_TX; + pins[1] = MICROPY_HW_UART3_RX; + #if defined(MICROPY_HW_UART3_RTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + pins[2] = MICROPY_HW_UART3_RTS; + } + #endif + #if defined(MICROPY_HW_UART3_CTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + pins[3] = MICROPY_HW_UART3_CTS; + } + #endif + __HAL_RCC_USART3_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_UART4_TX) && defined(MICROPY_HW_UART4_RX) + case PYB_UART_4: + uart_unit = 4; + #if defined(STM32F0) + UARTx = USART4; + irqn = USART3_8_IRQn; + __HAL_RCC_USART4_CLK_ENABLE(); + #else + UARTx = UART4; + irqn = UART4_IRQn; + __HAL_RCC_UART4_CLK_ENABLE(); + #endif + pins[0] = MICROPY_HW_UART4_TX; + pins[1] = MICROPY_HW_UART4_RX; + break; + #endif + + #if defined(MICROPY_HW_UART5_TX) && defined(MICROPY_HW_UART5_RX) + case PYB_UART_5: + uart_unit = 5; + #if defined(STM32F0) + UARTx = USART5; + irqn = USART3_8_IRQn; + __HAL_RCC_USART5_CLK_ENABLE(); + #else + UARTx = UART5; + irqn = UART5_IRQn; + __HAL_RCC_UART5_CLK_ENABLE(); + #endif + pins[0] = MICROPY_HW_UART5_TX; + pins[1] = MICROPY_HW_UART5_RX; + break; + #endif + + #if defined(MICROPY_HW_UART6_TX) && defined(MICROPY_HW_UART6_RX) + case PYB_UART_6: + uart_unit = 6; + UARTx = USART6; + #if defined(STM32F0) + irqn = USART3_8_IRQn; + #else + irqn = USART6_IRQn; + #endif + pins[0] = MICROPY_HW_UART6_TX; + pins[1] = MICROPY_HW_UART6_RX; + #if defined(MICROPY_HW_UART6_RTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + pins[2] = MICROPY_HW_UART6_RTS; + } + #endif + #if defined(MICROPY_HW_UART6_CTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + pins[3] = MICROPY_HW_UART6_CTS; + } + #endif + __HAL_RCC_USART6_CLK_ENABLE(); + break; + #endif + + #if defined(MICROPY_HW_UART7_TX) && defined(MICROPY_HW_UART7_RX) + case PYB_UART_7: + uart_unit = 7; + #if defined(STM32F0) + UARTx = USART7; + irqn = USART3_8_IRQn; + __HAL_RCC_USART7_CLK_ENABLE(); + #else + UARTx = UART7; + irqn = UART7_IRQn; + __HAL_RCC_UART7_CLK_ENABLE(); + #endif + pins[0] = MICROPY_HW_UART7_TX; + pins[1] = MICROPY_HW_UART7_RX; + break; + #endif + + #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX) + case PYB_UART_8: + uart_unit = 8; + #if defined(STM32F0) + UARTx = USART8; + irqn = USART3_8_IRQn; + __HAL_RCC_USART8_CLK_ENABLE(); + #else + UARTx = UART8; + irqn = UART8_IRQn; + __HAL_RCC_UART8_CLK_ENABLE(); + #endif + pins[0] = MICROPY_HW_UART8_TX; + pins[1] = MICROPY_HW_UART8_RX; + break; + #endif + + default: + // UART does not exist or is not configured for this board + return false; + } + + uint32_t mode = MP_HAL_PIN_MODE_ALT; + uint32_t pull = MP_HAL_PIN_PULL_UP; + + for (uint i = 0; i < 4; i++) { + if (pins[i] != NULL) { + bool ret = mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_UART, uart_unit); + if (!ret) { + return false; + } + } + } + + uart_obj->irqn = irqn; + uart_obj->uart.Instance = UARTx; + + // init UARTx + HAL_UART_Init(&uart_obj->uart); + + uart_obj->is_enabled = true; + uart_obj->attached_to_repl = false; + + return true; +} + +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached) { + self->attached_to_repl = attached; +} + +/* obsolete and unused +bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) { + UART_HandleTypeDef *uh = &uart_obj->uart; + memset(uh, 0, sizeof(*uh)); + uh->Init.BaudRate = baudrate; + uh->Init.WordLength = UART_WORDLENGTH_8B; + uh->Init.StopBits = UART_STOPBITS_1; + uh->Init.Parity = UART_PARITY_NONE; + uh->Init.Mode = UART_MODE_TX_RX; + uh->Init.HwFlowCtl = UART_HWCONTROL_NONE; + uh->Init.OverSampling = UART_OVERSAMPLING_16; + return uart_init2(uart_obj); +} +*/ + +mp_uint_t uart_rx_any(pyb_uart_obj_t *self) { + int buffer_bytes = self->read_buf_head - self->read_buf_tail; + if (buffer_bytes < 0) { + return buffer_bytes + self->read_buf_len; + } else if (buffer_bytes > 0) { + return buffer_bytes; + } else { + return __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET; + } +} + +// Waits at most timeout milliseconds for at least 1 char to become ready for +// reading (from buf or for direct reading). +// Returns true if something available, false if not. +STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout) { + uint32_t start = HAL_GetTick(); + for (;;) { + if (self->read_buf_tail != self->read_buf_head || __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) { + return true; // have at least 1 char ready for reading + } + if (HAL_GetTick() - start >= timeout) { + return false; // timeout + } + MICROPY_EVENT_POLL_HOOK + } +} + +// assumes there is a character available +int uart_rx_char(pyb_uart_obj_t *self) { + if (self->read_buf_tail != self->read_buf_head) { + // buffering via IRQ + int data; + if (self->char_width == CHAR_WIDTH_9BIT) { + data = ((uint16_t*)self->read_buf)[self->read_buf_tail]; + } else { + data = self->read_buf[self->read_buf_tail]; + } + self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len; + if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) { + // UART was stalled by flow ctrl: re-enable IRQ now we have room in buffer + __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE); + } + return data; + } else { + // no buffering + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + return self->uart.Instance->RDR & self->char_mask; + #else + return self->uart.Instance->DR & self->char_mask; + #endif + } +} + +// Waits at most timeout milliseconds for TX register to become empty. +// Returns true if can write, false if can't. +STATIC bool uart_tx_wait(pyb_uart_obj_t *self, uint32_t timeout) { + uint32_t start = HAL_GetTick(); + for (;;) { + if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) { + return true; // tx register is empty + } + if (HAL_GetTick() - start >= timeout) { + return false; // timeout + } + MICROPY_EVENT_POLL_HOOK + } +} + +// Waits at most timeout milliseconds for UART flag to be set. +// Returns true if flag is/was set, false on timeout. +STATIC bool uart_wait_flag_set(pyb_uart_obj_t *self, uint32_t flag, uint32_t timeout) { + // Note: we don't use WFI to idle in this loop because UART tx doesn't generate + // an interrupt and the flag can be set quickly if the baudrate is large. + uint32_t start = HAL_GetTick(); + for (;;) { + if (__HAL_UART_GET_FLAG(&self->uart, flag)) { + return true; + } + if (timeout == 0 || HAL_GetTick() - start >= timeout) { + return false; // timeout + } + } +} + +// src - a pointer to the data to send (16-bit aligned for 9-bit chars) +// num_chars - number of characters to send (9-bit chars count for 2 bytes from src) +// *errcode - returns 0 for success, MP_Exxx on error +// returns the number of characters sent (valid even if there was an error) +STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_chars, int *errcode) { + if (num_chars == 0) { + *errcode = 0; + return 0; + } + + uint32_t timeout; + if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + // CTS can hold off transmission for an arbitrarily long time. Apply + // the overall timeout rather than the character timeout. + timeout = self->timeout; + } else { + // The timeout specified here is for waiting for the TX data register to + // become empty (ie between chars), as well as for the final char to be + // completely transferred. The default value for timeout_char is long + // enough for 1 char, but we need to double it to wait for the last char + // to be transferred to the data register, and then to be transmitted. + timeout = 2 * self->timeout_char; + } + + const uint8_t *src = (const uint8_t*)src_in; + size_t num_tx = 0; + USART_TypeDef *uart = self->uart.Instance; + + while (num_tx < num_chars) { + if (!uart_wait_flag_set(self, UART_FLAG_TXE, timeout)) { + *errcode = MP_ETIMEDOUT; + return num_tx; + } + uint32_t data; + if (self->char_width == CHAR_WIDTH_9BIT) { + data = *((uint16_t*)src) & 0x1ff; + src += 2; + } else { + data = *src++; + } + #if defined(STM32F4) + uart->DR = data; + #else + uart->TDR = data; + #endif + ++num_tx; + } + + // wait for the UART frame to complete + if (!uart_wait_flag_set(self, UART_FLAG_TC, timeout)) { + *errcode = MP_ETIMEDOUT; + return num_tx; + } + + *errcode = 0; + return num_tx; +} + +void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) { + int errcode; + uart_tx_data(uart_obj, str, len, &errcode); +} + +// this IRQ handler is set up to handle RXNE interrupts only +void uart_irq_handler(mp_uint_t uart_id) { + // get the uart object + pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1]; + + if (self == NULL) { + // UART object has not been set, so we can't do anything, not + // even disable the IRQ. This should never happen. + return; + } + + if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) { + if (self->read_buf_len != 0) { + uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; + if (next_head != self->read_buf_tail) { + // only read data if room in buf + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE + #else + int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE + #endif + data &= self->char_mask; + // Handle interrupt coming in on a UART REPL + if (self->attached_to_repl && data == mp_interrupt_char) { + pendsv_kbd_intr(); + return; + } + if (self->char_width == CHAR_WIDTH_9BIT) { + ((uint16_t*)self->read_buf)[self->read_buf_head] = data; + } else { + self->read_buf[self->read_buf_head] = data; + } + self->read_buf_head = next_head; + } else { // No room: leave char in buf, disable interrupt + __HAL_UART_DISABLE_IT(&self->uart, UART_IT_RXNE); + } + } + } +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_printf(print, "UART(%u)", self->uart_id); + } else { + mp_int_t bits; + switch (self->uart.Init.WordLength) { + #ifdef UART_WORDLENGTH_7B + case UART_WORDLENGTH_7B: bits = 7; break; + #endif + case UART_WORDLENGTH_8B: bits = 8; break; + case UART_WORDLENGTH_9B: default: bits = 9; break; + } + if (self->uart.Init.Parity != UART_PARITY_NONE) { + bits -= 1; + } + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=", + self->uart_id, self->uart.Init.BaudRate, bits); + if (self->uart.Init.Parity == UART_PARITY_NONE) { + mp_print_str(print, "None"); + } else { + mp_printf(print, "%u", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1); + } + if (self->uart.Init.HwFlowCtl) { + mp_printf(print, ", flow="); + if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + mp_printf(print, "RTS%s", self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS ? "|" : ""); + } + if (self->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + mp_printf(print, "CTS"); + } + } + mp_printf(print, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u)", + self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2, + self->timeout, self->timeout_char, + self->read_buf_len == 0 ? 0 : self->read_buf_len - 1); // -1 to adjust for usable length of buffer + } +} + +/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, flow=0, read_buf_len=64) +/// +/// Initialise the UART bus with the given parameters: +/// +/// - `baudrate` is the clock rate. +/// - `bits` is the number of bits per byte, 7, 8 or 9. +/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). +/// - `stop` is the number of stop bits, 1 or 2. +/// - `timeout` is the timeout in milliseconds to wait for the first character. +/// - `timeout_char` is the timeout in milliseconds to wait between characters. +/// - `flow` is RTS | CTS where RTS == 256, CTS == 512 +/// - `read_buf_len` is the character length of the read buffer (0 to disable). +STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + + // parse args + struct { + mp_arg_val_t baudrate, bits, parity, stop, flow, timeout, timeout_char, read_buf_len; + } args; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + // set the UART configuration values + memset(&self->uart, 0, sizeof(self->uart)); + UART_InitTypeDef *init = &self->uart.Init; + + // baudrate + init->BaudRate = args.baudrate.u_int; + + // parity + mp_int_t bits = args.bits.u_int; + if (args.parity.u_obj == mp_const_none) { + init->Parity = UART_PARITY_NONE; + } else { + mp_int_t parity = mp_obj_get_int(args.parity.u_obj); + init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; + bits += 1; // STs convention has bits including parity + } + + // number of bits + if (bits == 8) { + init->WordLength = UART_WORDLENGTH_8B; + } else if (bits == 9) { + init->WordLength = UART_WORDLENGTH_9B; + #ifdef UART_WORDLENGTH_7B + } else if (bits == 7) { + init->WordLength = UART_WORDLENGTH_7B; + #endif + } else { + mp_raise_ValueError("unsupported combination of bits and parity"); + } + + // stop bits + switch (args.stop.u_int) { + case 1: init->StopBits = UART_STOPBITS_1; break; + default: init->StopBits = UART_STOPBITS_2; break; + } + + // flow control + init->HwFlowCtl = args.flow.u_int; + + // extra config (not yet configurable) + init->Mode = UART_MODE_TX_RX; + init->OverSampling = UART_OVERSAMPLING_16; + + // init UART (if it fails, it's because the port doesn't exist) + if (!uart_init2(self)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) doesn't exist", self->uart_id)); + } + + // set timeout + self->timeout = args.timeout.u_int; + + // set timeout_char + // make sure it is at least as long as a whole character (13 bits to be safe) + // minimum value is 2ms because sys-tick has a resolution of only 1ms + self->timeout_char = args.timeout_char.u_int; + uint32_t min_timeout_char = 13000 / init->BaudRate + 2; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } + + // setup the read buffer + m_del(byte, self->read_buf, self->read_buf_len << self->char_width); + if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) { + self->char_mask = 0x1ff; + self->char_width = CHAR_WIDTH_9BIT; + } else { + if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) { + self->char_mask = 0xff; + } else { + self->char_mask = 0x7f; + } + self->char_width = CHAR_WIDTH_8BIT; + } + self->read_buf_head = 0; + self->read_buf_tail = 0; + if (args.read_buf_len.u_int <= 0) { + // no read buffer + self->read_buf_len = 0; + self->read_buf = NULL; + HAL_NVIC_DisableIRQ(self->irqn); + __HAL_UART_DISABLE_IT(&self->uart, UART_IT_RXNE); + } else { + // read buffer using interrupts + self->read_buf_len = args.read_buf_len.u_int + 1; // +1 to adjust for usable length of buffer + self->read_buf = m_new(byte, self->read_buf_len << self->char_width); + __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE); + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_UART); + HAL_NVIC_EnableIRQ(self->irqn); + } + + // compute actual baudrate that was configured + // (this formula assumes UART_OVERSAMPLING_16) + uint32_t actual_baudrate = 0; + #if defined(STM32F0) + actual_baudrate = HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32F7) || defined(STM32H7) + UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED; + UART_GETCLOCKSOURCE(&self->uart, clocksource); + switch (clocksource) { + #if defined(STM32H7) + case UART_CLOCKSOURCE_D2PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D3PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D2PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; + #else + case UART_CLOCKSOURCE_PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; + case UART_CLOCKSOURCE_SYSCLK: actual_baudrate = HAL_RCC_GetSysClockFreq(); break; + #endif + #if defined(STM32H7) + case UART_CLOCKSOURCE_CSI: actual_baudrate = CSI_VALUE; break; + #endif + case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break; + case UART_CLOCKSOURCE_LSE: actual_baudrate = LSE_VALUE; break; + #if defined(STM32H7) + case UART_CLOCKSOURCE_PLL2: + case UART_CLOCKSOURCE_PLL3: + #endif + case UART_CLOCKSOURCE_UNDEFINED: break; + } + #else + if (self->uart.Instance == USART1 + #if defined(USART6) + || self->uart.Instance == USART6 + #endif + ) { + actual_baudrate = HAL_RCC_GetPCLK2Freq(); + } else { + actual_baudrate = HAL_RCC_GetPCLK1Freq(); + } + #endif + actual_baudrate /= self->uart.Instance->BRR; + + // check we could set the baudrate within 5% + uint32_t baudrate_diff; + if (actual_baudrate > init->BaudRate) { + baudrate_diff = actual_baudrate - init->BaudRate; + } else { + baudrate_diff = init->BaudRate - actual_baudrate; + } + init->BaudRate = actual_baudrate; // remember actual baudrate for printing + if (20 * baudrate_diff > init->BaudRate) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "set baudrate %d is not within 5%% of desired value", actual_baudrate)); + } + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct a UART object on the given bus. `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'. +/// With no additional parameters, the UART object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the UART busses are: +/// +/// - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)` +/// - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)` +/// - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)` +/// - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)` +/// - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)` +STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // work out port + int uart_id = 0; + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { + #ifdef MICROPY_HW_UART1_NAME + } else if (strcmp(port, MICROPY_HW_UART1_NAME) == 0) { + uart_id = PYB_UART_1; + #endif + #ifdef MICROPY_HW_UART2_NAME + } else if (strcmp(port, MICROPY_HW_UART2_NAME) == 0) { + uart_id = PYB_UART_2; + #endif + #ifdef MICROPY_HW_UART3_NAME + } else if (strcmp(port, MICROPY_HW_UART3_NAME) == 0) { + uart_id = PYB_UART_3; + #endif + #ifdef MICROPY_HW_UART4_NAME + } else if (strcmp(port, MICROPY_HW_UART4_NAME) == 0) { + uart_id = PYB_UART_4; + #endif + #ifdef MICROPY_HW_UART5_NAME + } else if (strcmp(port, MICROPY_HW_UART5_NAME) == 0) { + uart_id = PYB_UART_5; + #endif + #ifdef MICROPY_HW_UART6_NAME + } else if (strcmp(port, MICROPY_HW_UART6_NAME) == 0) { + uart_id = PYB_UART_6; + #endif + #ifdef MICROPY_HW_UART7_NAME + } else if (strcmp(port, MICROPY_HW_UART7_NAME) == 0) { + uart_id = PYB_UART_7; + #endif + #ifdef MICROPY_HW_UART8_NAME + } else if (strcmp(port, MICROPY_HW_UART8_NAME) == 0) { + uart_id = PYB_UART_8; + #endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%s) doesn't exist", port)); + } + } else { + uart_id = mp_obj_get_int(args[0]); + if (!uart_exists(uart_id)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) doesn't exist", uart_id)); + } + } + + pyb_uart_obj_t *self; + if (MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] == NULL) { + // create new UART object + self = m_new0(pyb_uart_obj_t, 1); + self->base.type = &pyb_uart_type; + self->uart_id = uart_id; + MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] = self; + } else { + // reference existing UART object + self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1]; + } + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_uart_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); + +/// \method deinit() +/// Turn off the UART bus. +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->is_enabled = false; + UART_HandleTypeDef *uart = &self->uart; + HAL_UART_DeInit(uart); + if (uart->Instance == USART1) { + HAL_NVIC_DisableIRQ(USART1_IRQn); + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + __HAL_RCC_USART1_CLK_DISABLE(); + } else if (uart->Instance == USART2) { + HAL_NVIC_DisableIRQ(USART2_IRQn); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + __HAL_RCC_USART2_CLK_DISABLE(); + #if defined(USART3) + } else if (uart->Instance == USART3) { + #if !defined(STM32F0) + HAL_NVIC_DisableIRQ(USART3_IRQn); + #endif + __HAL_RCC_USART3_FORCE_RESET(); + __HAL_RCC_USART3_RELEASE_RESET(); + __HAL_RCC_USART3_CLK_DISABLE(); + #endif + #if defined(UART4) + } else if (uart->Instance == UART4) { + HAL_NVIC_DisableIRQ(UART4_IRQn); + __HAL_RCC_UART4_FORCE_RESET(); + __HAL_RCC_UART4_RELEASE_RESET(); + __HAL_RCC_UART4_CLK_DISABLE(); + #endif + #if defined(USART4) + } else if (uart->Instance == USART4) { + __HAL_RCC_USART4_FORCE_RESET(); + __HAL_RCC_USART4_RELEASE_RESET(); + __HAL_RCC_USART4_CLK_DISABLE(); + #endif + #if defined(UART5) + } else if (uart->Instance == UART5) { + HAL_NVIC_DisableIRQ(UART5_IRQn); + __HAL_RCC_UART5_FORCE_RESET(); + __HAL_RCC_UART5_RELEASE_RESET(); + __HAL_RCC_UART5_CLK_DISABLE(); + #endif + #if defined(USART5) + } else if (uart->Instance == USART5) { + __HAL_RCC_USART5_FORCE_RESET(); + __HAL_RCC_USART5_RELEASE_RESET(); + __HAL_RCC_USART5_CLK_DISABLE(); + #endif + #if defined(UART6) + } else if (uart->Instance == USART6) { + HAL_NVIC_DisableIRQ(USART6_IRQn); + __HAL_RCC_USART6_FORCE_RESET(); + __HAL_RCC_USART6_RELEASE_RESET(); + __HAL_RCC_USART6_CLK_DISABLE(); + #endif + #if defined(UART7) + } else if (uart->Instance == UART7) { + HAL_NVIC_DisableIRQ(UART7_IRQn); + __HAL_RCC_UART7_FORCE_RESET(); + __HAL_RCC_UART7_RELEASE_RESET(); + __HAL_RCC_UART7_CLK_DISABLE(); + #endif + #if defined(USART7) + } else if (uart->Instance == USART7) { + __HAL_RCC_USART7_FORCE_RESET(); + __HAL_RCC_USART7_RELEASE_RESET(); + __HAL_RCC_USART7_CLK_DISABLE(); + #endif + #if defined(UART8) + } else if (uart->Instance == UART8) { + HAL_NVIC_DisableIRQ(UART8_IRQn); + __HAL_RCC_UART8_FORCE_RESET(); + __HAL_RCC_UART8_RELEASE_RESET(); + __HAL_RCC_UART8_CLK_DISABLE(); + #endif + #if defined(USART8) + } else if (uart->Instance == USART8) { + __HAL_RCC_USART8_FORCE_RESET(); + __HAL_RCC_USART8_RELEASE_RESET(); + __HAL_RCC_USART8_CLK_DISABLE(); + #endif + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit); + +/// \method any() +/// Return `True` if any characters waiting, else `False`. +STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any); + +/// \method writechar(char) +/// Write a single character on the bus. `char` is an integer to write. +/// Return value: `None`. +STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the character to write (might be 9 bits) + uint16_t data = mp_obj_get_int(char_in); + + // write the character + int errcode; + if (uart_tx_wait(self, self->timeout)) { + uart_tx_data(self, &data, 1, &errcode); + } else { + errcode = MP_ETIMEDOUT; + } + + if (errcode != 0) { + mp_raise_OSError(errcode); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar); + +/// \method readchar() +/// Receive a single character on the bus. +/// Return value: The character read, as an integer. Returns -1 on timeout. +STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (uart_rx_wait(self, self->timeout)) { + return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self)); + } else { + // return -1 on timeout + return MP_OBJ_NEW_SMALL_INT(-1); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar); + +// uart.sendbreak() +STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register + #else + self->uart.Instance->CR1 |= USART_CR1_SBK; + #endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak); + +STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = { + // instance methods + + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_uart_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) }, + + /// \method read([nbytes]) + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + /// \method readline() + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + /// \method readinto(buf[, nbytes]) + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + /// \method write(buf) + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + + { MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&pyb_uart_writechar_obj) }, + { MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&pyb_uart_readchar_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&pyb_uart_sendbreak_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); + +STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + byte *buf = buf_in; + + // check that size is a multiple of character width + if (size & self->char_width) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + // convert byte size to char size + size >>= self->char_width; + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + // wait for first char to become available + if (!uart_rx_wait(self, self->timeout)) { + // return EAGAIN error to indicate non-blocking (then read() method returns None) + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // read the data + byte *orig_buf = buf; + for (;;) { + int data = uart_rx_char(self); + if (self->char_width == CHAR_WIDTH_9BIT) { + *(uint16_t*)buf = data; + buf += 2; + } else { + *buf++ = data; + } + if (--size == 0 || !uart_rx_wait(self, self->timeout_char)) { + // return number of bytes read + return buf - orig_buf; + } + } +} + +STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + const byte *buf = buf_in; + + // check that size is a multiple of character width + if (size & self->char_width) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + // wait to be able to write the first character. EAGAIN causes write to return None + if (!uart_tx_wait(self, self->timeout)) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // write the data + size_t num_tx = uart_tx_data(self, buf, size >> self->char_width, errcode); + + if (*errcode == 0 || *errcode == MP_ETIMEDOUT) { + // return number of bytes written, even if there was a timeout + return num_tx << self->char_width; + } else { + return MP_STREAM_ERROR; + } +} + +STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + uintptr_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self)) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = pyb_uart_read, + .write = pyb_uart_write, + .ioctl = pyb_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t pyb_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = pyb_uart_print, + .make_new = pyb_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/uart.h b/src/openmv/src/micropython/ports/stm32/uart.h new file mode 100755 index 0000000..4ab18ff --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/uart.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_UART_H +#define MICROPY_INCLUDED_STM32_UART_H + +typedef enum { + PYB_UART_NONE = 0, + PYB_UART_1 = 1, + PYB_UART_2 = 2, + PYB_UART_3 = 3, + PYB_UART_4 = 4, + PYB_UART_5 = 5, + PYB_UART_6 = 6, + PYB_UART_7 = 7, + PYB_UART_8 = 8, +} pyb_uart_t; + +typedef struct _pyb_uart_obj_t pyb_uart_obj_t; +extern const mp_obj_type_t pyb_uart_type; + +void uart_init0(void); +void uart_deinit(void); +void uart_irq_handler(mp_uint_t uart_id); + +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached); +mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); +int uart_rx_char(pyb_uart_obj_t *uart_obj); +void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); + +#endif // MICROPY_INCLUDED_STM32_UART_H diff --git a/src/openmv/src/micropython/ports/stm32/usb.c b/src/openmv/src/micropython/ports/stm32/usb.c new file mode 100755 index 0000000..defb2d8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usb.c @@ -0,0 +1,784 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_cdc_msc_hid.h" +#include "usbd_cdc_interface.h" +#include "usbd_msc_storage.h" +#include "usbd_hid_interface.h" + +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "bufhelper.h" +#include "usb.h" + +#if MICROPY_HW_ENABLE_USB + +// Work out which USB device to use as the main one (the one with the REPL) +#if !defined(MICROPY_HW_USB_MAIN_DEV) +#if defined(MICROPY_HW_USB_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) +#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +#else +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif +#endif + +// this will be persistent across a soft-reset +mp_uint_t pyb_usb_flags = 0; + +typedef struct _usb_device_t { + uint32_t enabled; + USBD_HandleTypeDef hUSBDDevice; + usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state; + usbd_cdc_itf_t usbd_cdc_itf; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_itf_t usbd_cdc2_itf; + #endif + usbd_hid_itf_t usbd_hid_itf; +} usb_device_t; + +usb_device_t usb_device; +pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; + +// predefined hid mouse data +STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { + {&mp_type_bytes}, + 0, // hash not valid + USBD_HID_MOUSE_REPORT_DESC_SIZE, + USBD_HID_MOUSE_ReportDesc, +}; +const mp_rom_obj_tuple_t pyb_usb_hid_mouse_obj = { + {&mp_type_tuple}, + 5, + { + MP_ROM_INT(1), // subclass: boot + MP_ROM_INT(2), // protocol: mouse + MP_ROM_INT(USBD_HID_MOUSE_MAX_PACKET), + MP_ROM_INT(8), // polling interval: 8ms + MP_ROM_PTR(&pyb_usb_hid_mouse_desc_obj), + }, +}; + +// predefined hid keyboard data +STATIC const mp_obj_str_t pyb_usb_hid_keyboard_desc_obj = { + {&mp_type_bytes}, + 0, // hash not valid + USBD_HID_KEYBOARD_REPORT_DESC_SIZE, + USBD_HID_KEYBOARD_ReportDesc, +}; +const mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj = { + {&mp_type_tuple}, + 5, + { + MP_ROM_INT(1), // subclass: boot + MP_ROM_INT(1), // protocol: keyboard + MP_ROM_INT(USBD_HID_KEYBOARD_MAX_PACKET), + MP_ROM_INT(8), // polling interval: 8ms + MP_ROM_PTR(&pyb_usb_hid_keyboard_desc_obj), + }, +}; + +void pyb_usb_init0(void) { + mp_hal_set_interrupt_char(-1); + MP_STATE_PORT(pyb_hid_report_desc) = MP_OBJ_NULL; +} + +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { + bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; + mode &= 0x7f; + usb_device_t *usb_dev = &usb_device; + if (!usb_dev->enabled) { + // only init USB once in the device's power-lifetime + + // set up the USBD state + USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; + usbd->id = MICROPY_HW_USB_MAIN_DEV; + usbd->dev_state = USBD_STATE_DEFAULT; + usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; + usbd->pClass = &USBD_CDC_MSC_HID; + usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; + usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; + #endif + usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; + usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; + + // configure the VID, PID and the USBD mode (interfaces it will expose) + USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC); + if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { + return false; + } + + switch (pyb_usb_storage_medium) { +#if MICROPY_HW_HAS_SDCARD + case PYB_USB_STORAGE_MEDIUM_SDCARD: + USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops); + break; +#endif + default: + USBD_MSC_RegisterStorage(&usb_dev->usbd_cdc_msc_hid_state, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops); + break; + } + + // start the USB device + USBD_LL_Init(usbd, high_speed); + USBD_LL_Start(usbd); + usb_dev->enabled = true; + } + + return true; +} + +void pyb_usb_dev_deinit(void) { + usb_device_t *usb_dev = &usb_device; + if (usb_dev->enabled) { + USBD_Stop(&usb_dev->hUSBDDevice); + usb_dev->enabled = false; + } +} + +bool usb_vcp_is_enabled(void) { + return usb_device.enabled; +} + +int usb_vcp_recv_byte(uint8_t *c) { + return usbd_cdc_rx(&usb_device.usbd_cdc_itf, c, 1, 0); +} + +void usb_vcp_send_strn(const char *str, int len) { + if (usb_device.enabled) { + usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len); + } +} + +usbd_cdc_itf_t *usb_vcp_get(int idx) { + #if MICROPY_HW_USB_ENABLE_CDC2 + if (idx == 1) { + return &usb_device.usbd_cdc2_itf; + } + #endif + return &usb_device.usbd_cdc_itf; +} + +/******************************************************************************/ +// MicroPython bindings for USB + +/* + Philosophy of USB driver and Python API: pyb.usb_mode(...) configures the USB + on the board. The USB itself is not an entity, rather the interfaces are, and + can be accessed by creating objects, such as pyb.USB_VCP() and pyb.USB_HID(). + + We have: + + pyb.usb_mode() # return the current usb mode + pyb.usb_mode(None) # disable USB + pyb.usb_mode('VCP') # enable with VCP interface + pyb.usb_mode('VCP+MSC') # enable with VCP and MSC interfaces + pyb.usb_mode('VCP+HID') # enable with VCP and HID, defaulting to mouse protocol + pyb.usb_mode('VCP+HID', vid=0xf055, pid=0x9800) # specify VID and PID + pyb.usb_mode('VCP+HID', hid=pyb.hid_mouse) + pyb.usb_mode('VCP+HID', hid=pyb.hid_keyboard) + pyb.usb_mode('VCP+HID', pid=0x1234, hid=(subclass, protocol, max_packet_len, polling_interval, report_desc)) + + vcp = pyb.USB_VCP() # get the VCP device for read/write + hid = pyb.USB_HID() # get the HID device for write/poll + + Possible extensions: + pyb.usb_mode('host', ...) + pyb.usb_mode('OTG', ...) + pyb.usb_mode(..., port=2) # for second USB port +*/ + +STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} }, + { MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&pyb_usb_hid_mouse_obj)} }, + #if USBD_SUPPORT_HS_MODE + { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + #endif + }; + + // fetch the current usb mode -> pyb.usb_mode() + if (n_args == 0) { + #if defined(USE_HOST_MODE) + return MP_OBJ_NEW_QSTR(MP_QSTR_host); + #else + uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state); + switch (mode) { + case USBD_MODE_CDC: + return MP_OBJ_NEW_QSTR(MP_QSTR_VCP); + case USBD_MODE_MSC: + return MP_OBJ_NEW_QSTR(MP_QSTR_MSC); + case USBD_MODE_HID: + return MP_OBJ_NEW_QSTR(MP_QSTR_HID); + case USBD_MODE_CDC_MSC: + return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_MSC); + case USBD_MODE_CDC_HID: + return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_HID); + case USBD_MODE_MSC_HID: + return MP_OBJ_NEW_QSTR(MP_QSTR_MSC_plus_HID); + default: + return mp_const_none; + } + #endif + } + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // record the fact that the usb has been explicitly configured + pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED; + + // check if user wants to disable the USB + if (args[0].u_obj == mp_const_none) { + // disable usb + pyb_usb_dev_deinit(); + return mp_const_none; + } + + // get mode string + const char *mode_str = mp_obj_str_get_str(args[0].u_obj); + +#if defined(USE_HOST_MODE) + + // hardware configured for USB host mode + + if (strcmp(mode_str, "host") == 0) { + pyb_usb_host_init(); + } else { + goto bad_mode; + } + +#else + + // hardware configured for USB device mode + + // get the VID, PID and USB mode + // note: PID=-1 means select PID based on mode + // note: we support CDC as a synonym for VCP for backward compatibility + uint16_t vid = args[1].u_int; + uint16_t pid = args[2].u_int; + usb_device_mode_t mode; + if (strcmp(mode_str, "CDC+MSC") == 0 || strcmp(mode_str, "VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC_MSC; + } + mode = USBD_MODE_CDC_MSC; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2_MSC; + } + mode = USBD_MODE_CDC2_MSC; + #endif + } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC_HID; + } + mode = USBD_MODE_CDC_HID; + } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC; + } + mode = USBD_MODE_CDC; + } else if (strcmp(mode_str, "MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_MSC; + } + mode = USBD_MODE_MSC; + } else { + goto bad_mode; + } + + // get hid info if user selected such a mode + USBD_HID_ModeInfoTypeDef hid_info; + if (mode & USBD_MODE_HID) { + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[3].u_obj, 5, &items); + hid_info.subclass = mp_obj_get_int(items[0]); + hid_info.protocol = mp_obj_get_int(items[1]); + hid_info.max_packet_len = mp_obj_get_int(items[2]); + hid_info.polling_interval = mp_obj_get_int(items[3]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(items[4], &bufinfo, MP_BUFFER_READ); + hid_info.report_desc = bufinfo.buf; + hid_info.report_desc_len = bufinfo.len; + + // need to keep a copy of this so report_desc does not get GC'd + MP_STATE_PORT(pyb_hid_report_desc) = items[4]; + } + + #if USBD_SUPPORT_HS_MODE + if (args[4].u_bool) { + mode |= USBD_MODE_HIGH_SPEED; + } + #endif + + // init the USB device + if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) { + goto bad_mode; + } + +#endif + + return mp_const_none; + +bad_mode: + mp_raise_ValueError("bad USB mode"); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 0, pyb_usb_mode); + +/******************************************************************************/ +// MicroPython bindings for USB VCP + +/// \moduleref pyb +/// \class USB_VCP - USB virtual comm port +/// +/// The USB_VCP class allows creation of an object representing the USB +/// virtual comm port. It can be used to read and write data over USB to +/// the connected host. + +typedef struct _pyb_usb_vcp_obj_t { + mp_obj_base_t base; + usbd_cdc_itf_t *cdc_itf; +} pyb_usb_vcp_obj_t; + +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; +#if MICROPY_HW_USB_ENABLE_CDC2 +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf}; +#endif + +STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + int id = ((pyb_usb_vcp_obj_t*)MP_OBJ_TO_PTR(self_in))->cdc_itf - &usb_device.usbd_cdc_itf; + mp_printf(print, "USB_VCP(%u)", id); +} + +/// \classmethod \constructor() +/// Create a new USB_VCP object. +STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + // TODO raise exception if USB is not configured for VCP + + int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]); + if (id == 0) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (id == 1) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj); + #endif + } else { + mp_raise_ValueError(NULL); + } +} + +STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { + mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setinterrupt); + +STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) { + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(usbd_cdc_is_connected(self->cdc_itf)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconnected); + +// deprecated in favour of USB_VCP.isconnected +STATIC mp_obj_t pyb_have_cdc(void) { + return pyb_usb_vcp_isconnected(MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj)); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); + +/// \method any() +/// Return `True` if any characters waiting, else `False`. +STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) { + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (usbd_cdc_rx_num(self->cdc_itf) > 0) { + return mp_const_true; + } else { + return mp_const_false; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_any_obj, pyb_usb_vcp_any); + +/// \method send(data, *, timeout=5000) +/// Send data over the USB VCP: +/// +/// - `data` is the data to send (an integer to send, or a buffer object). +/// - `timeout` is the timeout in milliseconds to wait for the send. +/// +/// Return value: number of bytes sent. +STATIC const mp_arg_t pyb_usb_vcp_send_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, +}; +#define PYB_USB_VCP_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_usb_vcp_send_args) + +STATIC mp_obj_t pyb_usb_vcp_send(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_arg_val_t vals[PYB_USB_VCP_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USB_VCP_SEND_NUM_ARGS, pyb_usb_vcp_send_args, vals); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // send the data + int ret = usbd_cdc_tx(self->cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int); + + return mp_obj_new_int(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_send_obj, 1, pyb_usb_vcp_send); + +/// \method recv(data, *, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `data` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes. +/// - `timeout` is the timeout in milliseconds to wait for the receive. +/// +/// Return value: if `data` is an integer then a new buffer of the bytes received, +/// otherwise the number of bytes read into `data` is returned. +STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_arg_val_t vals[PYB_USB_VCP_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USB_VCP_SEND_NUM_ARGS, pyb_usb_vcp_send_args, vals); + + // get the buffer to receive into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr); + + // receive the data + int ret = usbd_cdc_rx(self->cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int); + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return mp_obj_new_int(ret); // number of bytes read into given buffer + } else { + vstr.len = ret; // set actual number of bytes read + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_vcp_recv_obj, 1, pyb_usb_vcp_recv); + +mp_obj_t pyb_usb_vcp___exit__(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_usb_vcp___exit___obj, 4, 4, pyb_usb_vcp___exit__); + +STATIC const mp_rom_map_elem_t pyb_usb_vcp_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_setinterrupt), MP_ROM_PTR(&pyb_usb_vcp_setinterrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&pyb_usb_vcp_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_usb_vcp_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_usb_vcp_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_usb_vcp_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)}, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pyb_usb_vcp___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_table); + +STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + int ret = usbd_cdc_rx(self->cdc_itf, (byte*)buf, size, 0); + if (ret == 0) { + // return EAGAIN error to indicate non-blocking + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + return ret; +} + +STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + int ret = usbd_cdc_tx(self->cdc_itf, (const byte*)buf, size, 0); + if (ret == 0) { + // return EAGAIN error to indicate non-blocking + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + return ret; +} + +STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_uint_t ret; + pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (request == MP_STREAM_POLL) { + uintptr_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(self->cdc_itf) > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(self->cdc_itf)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t pyb_usb_vcp_stream_p = { + .read = pyb_usb_vcp_read, + .write = pyb_usb_vcp_write, + .ioctl = pyb_usb_vcp_ioctl, +}; + +const mp_obj_type_t pyb_usb_vcp_type = { + { &mp_type_type }, + .name = MP_QSTR_USB_VCP, + .print = pyb_usb_vcp_print, + .make_new = pyb_usb_vcp_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &pyb_usb_vcp_stream_p, + .locals_dict = (mp_obj_dict_t*)&pyb_usb_vcp_locals_dict, +}; + +/******************************************************************************/ +// MicroPython bindings for USB HID + +typedef struct _pyb_usb_hid_obj_t { + mp_obj_base_t base; + usb_device_t *usb_dev; +} pyb_usb_hid_obj_t; + +STATIC const pyb_usb_hid_obj_t pyb_usb_hid_obj = {{&pyb_usb_hid_type}, &usb_device}; + +STATIC mp_obj_t pyb_usb_hid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // TODO raise exception if USB is not configured for HID + + // return the USB HID object + return MP_OBJ_FROM_PTR(&pyb_usb_hid_obj); +} + +/// \method recv(data, *, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `data` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes. +/// - `timeout` is the timeout in milliseconds to wait for the receive. +/// +/// Return value: if `data` is an integer then a new buffer of the bytes received, +/// otherwise the number of bytes read into `data` is returned. +STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); + + // get the buffer to receive into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr); + + // receive the data + int ret = usbd_hid_rx(&self->usb_dev->usbd_hid_itf, vstr.len, (uint8_t*)vstr.buf, vals[1].u_int); + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return mp_obj_new_int(ret); // number of bytes read into given buffer + } else { + vstr.len = ret; // set actual number of bytes read + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv); + +STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + byte temp_buf[8]; + // get the buffer to send from + // we accept either a byte array, or a tuple/list of integers + if (!mp_get_buffer(report_in, &bufinfo, MP_BUFFER_READ)) { + mp_obj_t *items; + mp_obj_get_array(report_in, &bufinfo.len, &items); + if (bufinfo.len > sizeof(temp_buf)) { + mp_raise_ValueError("tuple/list too large for HID report; use bytearray instead"); + } + for (int i = 0; i < bufinfo.len; i++) { + temp_buf[i] = mp_obj_get_int(items[i]); + } + bufinfo.buf = temp_buf; + } + + // send the data + if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_hid_itf.base, bufinfo.buf, bufinfo.len)) { + return mp_obj_new_int(bufinfo.len); + } else { + return mp_obj_new_int(0); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_hid_send_obj, pyb_usb_hid_send); + +// deprecated in favour of USB_HID.send +STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { + return pyb_usb_hid_send(MP_OBJ_FROM_PTR(&pyb_usb_hid_obj), arg); +} +MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); + +STATIC const mp_rom_map_elem_t pyb_usb_hid_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_usb_hid_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_usb_hid_recv_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table); + +STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + uintptr_t flags = arg; + ret = 0; + if ((flags & MP_STREAM_POLL_RD) && usbd_hid_rx_num(&self->usb_dev->usbd_hid_itf) > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_hid_itf.base)) { + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t pyb_usb_hid_stream_p = { + .ioctl = pyb_usb_hid_ioctl, +}; + +const mp_obj_type_t pyb_usb_hid_type = { + { &mp_type_type }, + .name = MP_QSTR_USB_HID, + .make_new = pyb_usb_hid_make_new, + .protocol = &pyb_usb_hid_stream_p, + .locals_dict = (mp_obj_dict_t*)&pyb_usb_hid_locals_dict, +}; + +/******************************************************************************/ +// code for experimental USB OTG support + +#ifdef USE_HOST_MODE + +#include "led.h" +#include "usbh_core.h" +#include "usbh_usr.h" +#include "usbh_hid_core.h" +#include "usbh_hid_keybd.h" +#include "usbh_hid_mouse.h" + +__ALIGN_BEGIN USBH_HOST USB_Host __ALIGN_END ; + +static int host_is_enabled = 0; + +void pyb_usb_host_init(void) { + if (!host_is_enabled) { + // only init USBH once in the device's power-lifetime + /* Init Host Library */ + USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &HID_cb, &USR_Callbacks); + } + host_is_enabled = 1; +} + +void pyb_usb_host_process(void) { + USBH_Process(&USB_OTG_Core, &USB_Host); +} + +uint8_t usb_keyboard_key = 0; + +// TODO this is an ugly hack to get key presses +uint pyb_usb_host_get_keyboard(void) { + uint key = usb_keyboard_key; + usb_keyboard_key = 0; + return key; +} + +void USR_MOUSE_Init(void) { + led_state(4, 1); + USB_OTG_BSP_mDelay(100); + led_state(4, 0); +} + +void USR_MOUSE_ProcessData(HID_MOUSE_Data_TypeDef *data) { + led_state(4, 1); + USB_OTG_BSP_mDelay(50); + led_state(4, 0); +} + +void USR_KEYBRD_Init(void) { + led_state(4, 1); + USB_OTG_BSP_mDelay(100); + led_state(4, 0); +} + +void USR_KEYBRD_ProcessData(uint8_t pbuf) { + led_state(4, 1); + USB_OTG_BSP_mDelay(50); + led_state(4, 0); + usb_keyboard_key = pbuf; +} + +#endif // USE_HOST_MODE + +#endif // MICROPY_HW_ENABLE_USB diff --git a/src/openmv/src/micropython/ports/stm32/usb.h b/src/openmv/src/micropython/ports/stm32/usb.h new file mode 100755 index 0000000..45a0588 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usb.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_USB_H +#define MICROPY_INCLUDED_STM32_USB_H + +#include "usbd_cdc_msc_hid0.h" + +#define PYB_USB_FLAG_USB_MODE_CALLED (0x0002) + +// Windows needs a different PID to distinguish different device configurations +#define USBD_VID (0xf055) +#define USBD_PID_CDC_MSC (0x9800) +#define USBD_PID_CDC_HID (0x9801) +#define USBD_PID_CDC (0x9802) +#define USBD_PID_MSC (0x9803) +#define USBD_PID_CDC2_MSC (0x9804) + +typedef enum { + PYB_USB_STORAGE_MEDIUM_NONE = 0, + PYB_USB_STORAGE_MEDIUM_FLASH, + PYB_USB_STORAGE_MEDIUM_SDCARD, +} pyb_usb_storage_medium_t; + +typedef enum { + USB_PHY_FS_ID = 0, + USB_PHY_HS_ID = 1, +} USB_PHY_ID; + +extern mp_uint_t pyb_usb_flags; +extern pyb_usb_storage_medium_t pyb_usb_storage_medium; +extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_mouse_obj; +extern const struct _mp_rom_obj_tuple_t pyb_usb_hid_keyboard_obj; +extern const mp_obj_type_t pyb_usb_vcp_type; +extern const mp_obj_type_t pyb_usb_hid_type; +MP_DECLARE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated +MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated + +void pyb_usb_init0(void); +bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +void pyb_usb_dev_deinit(void); +bool usb_vcp_is_enabled(void); +int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0 +void usb_vcp_send_strn(const char* str, int len); + +void pyb_usb_host_init(void); +void pyb_usb_host_process(void); +uint pyb_usb_host_get_keyboard(void); + +#endif // MICROPY_INCLUDED_STM32_USB_H diff --git a/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.c b/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.c new file mode 100755 index 0000000..149971b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.c @@ -0,0 +1,374 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and heavily modified. See below for original + * copyright header. + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief Source file for USBD CDC interface + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include + +#include "usbd_cdc_msc_hid.h" +#include "usbd_cdc_interface.h" +#include "pendsv.h" + +#include "py/obj.h" +#include "lib/utils/interrupt_char.h" +#include "irq.h" + +#if MICROPY_HW_ENABLE_USB + +// CDC control commands +#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define CDC_SET_COMM_FEATURE 0x02 +#define CDC_GET_COMM_FEATURE 0x03 +#define CDC_CLEAR_COMM_FEATURE 0x04 +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 + +// Used to control the connect_state variable when USB host opens the serial port +static uint8_t usbd_cdc_connect_tx_timer; + +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + + // Reset all the CDC state + // Note: we don't reset tx_buf_ptr_in in order to allow the output buffer to + // be filled (by usbd_cdc_tx_always) before the USB device is connected. + cdc->rx_buf_put = 0; + cdc->rx_buf_get = 0; + cdc->tx_buf_ptr_out = 0; + cdc->tx_buf_ptr_out_shadow = 0; + cdc->tx_need_empty_packet = 0; + cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc; + #else + cdc->attached_to_repl = 1; + #endif + + // Return the buffer to place the first USB OUT packet + return cdc->rx_packet_buf; +} + +void usbd_cdc_deinit(usbd_cdc_state_t *cdc_in) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; +} + +// Manage the CDC class requests +// cmd: command code +// pbuf: buffer containing command data (request parameters) +// length: number of data to be sent (in bytes) +// Returns USBD_OK if all operations are OK else USBD_FAIL +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, uint16_t length) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + + switch (cmd) { + case CDC_SEND_ENCAPSULATED_COMMAND: + /* Add your code here */ + break; + + case CDC_GET_ENCAPSULATED_RESPONSE: + /* Add your code here */ + break; + + case CDC_SET_COMM_FEATURE: + /* Add your code here */ + break; + + case CDC_GET_COMM_FEATURE: + /* Add your code here */ + break; + + case CDC_CLEAR_COMM_FEATURE: + /* Add your code here */ + break; + + case CDC_SET_LINE_CODING: + #if 0 + LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\ + (pbuf[2] << 16) | (pbuf[3] << 24)); + LineCoding.format = pbuf[4]; + LineCoding.paritytype = pbuf[5]; + LineCoding.datatype = pbuf[6]; + /* Set the new configuration */ + #endif + break; + + case CDC_GET_LINE_CODING: + /* Add your code here */ + pbuf[0] = (uint8_t)(115200); + pbuf[1] = (uint8_t)(115200 >> 8); + pbuf[2] = (uint8_t)(115200 >> 16); + pbuf[3] = (uint8_t)(115200 >> 24); + pbuf[4] = 0; // stop bits (1) + pbuf[5] = 0; // parity (none) + pbuf[6] = 8; // number of bits (8) + break; + + case CDC_SET_CONTROL_LINE_STATE: { + // wValue, indicating the state, is passed in length (bit of a hack) + if (length & 1) { + // The actual connection state is delayed to give the host a chance to + // configure its serial port (in most cases to disable local echo) + PCD_HandleTypeDef *hpcd = cdc->base.usbd->pdev->pData; + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTING; + usbd_cdc_connect_tx_timer = 8; // wait for 8 SOF IRQs + USBx->GINTMSK |= USB_OTG_GINTMSK_SOFM; + } else { + cdc->connect_state = USBD_CDC_CONNECT_STATE_DISCONNECTED; + } + break; + } + + case CDC_SEND_BREAK: + /* Add your code here */ + break; + + default: + break; + } + + return USBD_OK; +} + +// Called when the USB IN endpoint is ready to receive more data +// (cdc.base.tx_in_progress must be 0) +void usbd_cdc_tx_ready(usbd_cdc_state_t *cdc_in) { + + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + cdc->tx_buf_ptr_out = cdc->tx_buf_ptr_out_shadow; + + if (cdc->tx_buf_ptr_out == cdc->tx_buf_ptr_in && !cdc->tx_need_empty_packet) { + // No outstanding data to send + return; + } + + uint32_t len; + if (cdc->tx_buf_ptr_out > cdc->tx_buf_ptr_in) { // rollback + len = USBD_CDC_TX_DATA_SIZE - cdc->tx_buf_ptr_out; + } else { + len = cdc->tx_buf_ptr_in - cdc->tx_buf_ptr_out; + } + + // Should always succeed because cdc.base.tx_in_progress==0 + USBD_CDC_TransmitPacket(&cdc->base, len, &cdc->tx_buf[cdc->tx_buf_ptr_out]); + + cdc->tx_buf_ptr_out_shadow += len; + if (cdc->tx_buf_ptr_out_shadow == USBD_CDC_TX_DATA_SIZE) { + cdc->tx_buf_ptr_out_shadow = 0; + } + + // According to the USB specification, a packet size of 64 bytes (CDC_DATA_FS_MAX_PACKET_SIZE) + // gets held at the USB host until the next packet is sent. This is because a + // packet of maximum size is considered to be part of a longer chunk of data, and + // the host waits for all data to arrive (ie, waits for a packet < max packet size). + // To flush a packet of exactly max packet size, we need to send a zero-size packet. + // See eg http://www.cypress.com/?id=4&rID=92719 + cdc->tx_need_empty_packet = (len > 0 && len % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); +} + +// Attempt to queue data on the USB IN endpoint +static void usbd_cdc_try_tx(usbd_cdc_itf_t *cdc) { + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + if (cdc == NULL || cdc->connect_state == USBD_CDC_CONNECT_STATE_DISCONNECTED) { + // CDC device is not connected to a host, so we are unable to send any data + } else if (cdc->base.tx_in_progress) { + // USB driver will call callback when ready + } else { + usbd_cdc_tx_ready(&cdc->base); + } + restore_irq_pri(basepri); +} + +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + if (usbd_cdc_connect_tx_timer > 0) { + --usbd_cdc_connect_tx_timer; + } else { + usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + hpcd->Instance->GINTMSK &= ~USB_OTG_GINTMSK_SOFM; + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc; + if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { + cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED; + usbd_cdc_try_tx(cdc); + } + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc = (usbd_cdc_itf_t*)usbd->cdc2; + if (cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTING) { + cdc->connect_state = USBD_CDC_CONNECT_STATE_CONNECTED; + usbd_cdc_try_tx(cdc); + } + #endif + } +} + +// Data received over USB OUT endpoint is processed here. +// len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket +// Returns USBD_OK if all operations are OK else USBD_FAIL +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + + // copy the incoming data into the circular buffer + for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { + if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) { + pendsv_kbd_intr(); + } else { + uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1); + if (next_put == cdc->rx_buf_get) { + // overflow, we just discard the rest of the chars + break; + } + cdc->rx_user_buf[cdc->rx_buf_put] = *src; + cdc->rx_buf_put = next_put; + } + } + + // initiate next USB packet transfer + USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); + + return USBD_OK; +} + +int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc) { + int32_t tx_waiting = (int32_t)cdc->tx_buf_ptr_in - (int32_t)cdc->tx_buf_ptr_out; + if (tx_waiting < 0) { + tx_waiting += USBD_CDC_TX_DATA_SIZE; + } + return tx_waiting <= USBD_CDC_TX_DATA_SIZE / 2; +} + +// timout in milliseconds. +// Returns number of bytes written to the device. +int usbd_cdc_tx(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len, uint32_t timeout) { + for (uint32_t i = 0; i < len; i++) { + // Wait until the device is connected and the buffer has space, with a given timeout + uint32_t start = HAL_GetTick(); + while (cdc->connect_state == USBD_CDC_CONNECT_STATE_DISCONNECTED + || ((cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1)) == cdc->tx_buf_ptr_out) { + usbd_cdc_try_tx(cdc); + // Wraparound of tick is taken care of by 2's complement arithmetic. + if (HAL_GetTick() - start >= timeout) { + // timeout + return i; + } + if (query_irq() == IRQ_STATE_DISABLED) { + // IRQs disabled so buffer will never be drained; return immediately + return i; + } + __WFI(); // enter sleep mode, waiting for interrupt + } + + // Write data to device buffer + cdc->tx_buf[cdc->tx_buf_ptr_in] = buf[i]; + cdc->tx_buf_ptr_in = (cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1); + } + + usbd_cdc_try_tx(cdc); + + // Success, return number of bytes read + return len; +} + +// Always write all of the data to the device tx buffer, even if the +// device is not connected, or if the buffer is full. Has a small timeout +// to wait for the buffer to be drained, in the case the device is connected. +void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) { + for (int i = 0; i < len; i++) { + // If the CDC device is not connected to the host then we don't have anyone to receive our data. + // The device may become connected in the future, so we should at least try to fill the buffer + // and hope that it doesn't overflow by the time the device connects. + // If the device is not connected then we should go ahead and fill the buffer straight away, + // ignoring overflow. Otherwise, we should make sure that we have enough room in the buffer. + if (cdc->connect_state != USBD_CDC_CONNECT_STATE_DISCONNECTED) { + // If the buffer is full, wait until it gets drained, with a timeout of 500ms + // (wraparound of tick is taken care of by 2's complement arithmetic). + uint32_t start = HAL_GetTick(); + while (((cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1)) == cdc->tx_buf_ptr_out && HAL_GetTick() - start <= 500) { + usbd_cdc_try_tx(cdc); + if (query_irq() == IRQ_STATE_DISABLED) { + // IRQs disabled so buffer will never be drained; exit loop + break; + } + __WFI(); // enter sleep mode, waiting for interrupt + } + } + + cdc->tx_buf[cdc->tx_buf_ptr_in] = buf[i]; + cdc->tx_buf_ptr_in = (cdc->tx_buf_ptr_in + 1) & (USBD_CDC_TX_DATA_SIZE - 1); + } + usbd_cdc_try_tx(cdc); +} + +// Returns number of bytes in the rx buffer. +int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc) { + int32_t rx_waiting = (int32_t)cdc->rx_buf_put - (int32_t)cdc->rx_buf_get; + if (rx_waiting < 0) { + rx_waiting += USBD_CDC_RX_DATA_SIZE; + } + return rx_waiting; +} + +// timout in milliseconds. +// Returns number of bytes read from the device. +int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout) { + // loop to read bytes + for (uint32_t i = 0; i < len; i++) { + // Wait until we have at least 1 byte to read + uint32_t start = HAL_GetTick(); + while (cdc->rx_buf_put == cdc->rx_buf_get) { + // Wraparound of tick is taken care of by 2's complement arithmetic. + if (HAL_GetTick() - start >= timeout) { + // timeout + return i; + } + if (query_irq() == IRQ_STATE_DISABLED) { + // IRQs disabled so buffer will never be filled; return immediately + return i; + } + __WFI(); // enter sleep mode, waiting for interrupt + } + + // Copy byte from device to user buffer + buf[i] = cdc->rx_user_buf[cdc->rx_buf_get]; + cdc->rx_buf_get = (cdc->rx_buf_get + 1) & (USBD_CDC_RX_DATA_SIZE - 1); + } + + // Success, return number of bytes read + return len; +} + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.h b/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.h new file mode 100755 index 0000000..fd69222 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_cdc_interface.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ +#ifndef MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_cdc_interface.h + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief Header for usbd_cdc_interface.c file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 USBD_CDC_RX_DATA_SIZE (1024) // this must be 2 or greater, and a power of 2 +#define USBD_CDC_TX_DATA_SIZE (1024) // I think this can be any value (was 2048) + +// Values for connect_state +#define USBD_CDC_CONNECT_STATE_DISCONNECTED (0) +#define USBD_CDC_CONNECT_STATE_CONNECTING (1) +#define USBD_CDC_CONNECT_STATE_CONNECTED (2) + +typedef struct _usbd_cdc_itf_t { + usbd_cdc_state_t base; // state for the base CDC layer + + uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer + uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it + volatile uint16_t rx_buf_put; // circular buffer index + uint16_t rx_buf_get; // circular buffer index + + uint8_t tx_buf[USBD_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer + uint16_t tx_buf_ptr_in; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when new data is available + volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when data is drained + uint16_t tx_buf_ptr_out_shadow; // shadow of above + uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size + + volatile uint8_t connect_state; // indicates if we are connected + uint8_t attached_to_repl; // indicates if interface is connected to REPL +} usbd_cdc_itf_t; + +// This is implemented in usb.c +usbd_cdc_itf_t *usb_vcp_get(int idx); + +static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) { + return cdc->connect_state == USBD_CDC_CONNECT_STATE_CONNECTED; +} + +int usbd_cdc_tx_half_empty(usbd_cdc_itf_t *cdc); +int usbd_cdc_tx(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len, uint32_t timeout); +void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len); + +int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc); +int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout); + +#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H diff --git a/src/openmv/src/micropython/ports/stm32/usbd_conf.c b/src/openmv/src/micropython/ports/stm32/usbd_conf.c new file mode 100755 index 0000000..3068a82 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_conf.c @@ -0,0 +1,670 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_conf.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief This file implements the USB Device library callbacks and MSP + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +#include "usbd_core.h" +#include "py/obj.h" +#include "py/mphal.h" +#include "irq.h" +#include "usb.h" + +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS + +#if MICROPY_HW_USB_FS +PCD_HandleTypeDef pcd_fs_handle; +#endif +#if MICROPY_HW_USB_HS +PCD_HandleTypeDef pcd_hs_handle; +#endif + +/******************************************************************************* + PCD BSP Routines +*******************************************************************************/ + +/** + * @brief Initializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { + if (hpcd->Instance == USB_OTG_FS) { + #if defined(STM32H7) + const uint32_t otg_alt = GPIO_AF10_OTG1_FS; + #else + const uint32_t otg_alt = GPIO_AF10_OTG_FS; + #endif + + mp_hal_pin_config(pin_A11, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A11, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_A12, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, otg_alt); + mp_hal_pin_config_speed(pin_A12, GPIO_SPEED_FREQ_VERY_HIGH); + + #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + // USB VBUS detect pin is always A9 + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + #endif + + #if defined(MICROPY_HW_USB_OTG_ID_PIN) + // USB ID pin is always A10 + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, otg_alt); + #endif + + #if defined(STM32H7) + // Keep USB clock running during sleep or else __WFI() will disable the USB + __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); + #endif + + // Enable USB FS Clocks + __USB_OTG_FS_CLK_ENABLE(); + + #if defined(STM32L4) + // Enable VDDUSB + if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + __HAL_RCC_PWR_CLK_DISABLE(); + } else { + HAL_PWREx_EnableVddUSB(); + } + #endif + + // Configure and enable USB FS interrupt + NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + #if MICROPY_HW_USB_HS + else if (hpcd->Instance == USB_OTG_HS) { + #if MICROPY_HW_USB_HS_IN_FS + + // Configure USB FS GPIOs + mp_hal_pin_config(pin_B14, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B14, GPIO_SPEED_FREQ_VERY_HIGH); + mp_hal_pin_config(pin_B15, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, GPIO_AF12_OTG_HS_FS); + mp_hal_pin_config_speed(pin_B15, GPIO_SPEED_FREQ_VERY_HIGH); + + #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + // Configure VBUS Pin + mp_hal_pin_config(MICROPY_HW_USB_VBUS_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0); + #endif + + #if defined(MICROPY_HW_USB_OTG_ID_PIN) + // Configure ID pin + mp_hal_pin_config(MICROPY_HW_USB_OTG_ID_PIN, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, GPIO_AF12_OTG_HS_FS); + #endif + + // Enable calling WFI and correct function of the embedded USB_FS_IN_HS phy + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE(); + __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); + + // Enable USB HS Clocks + + #if defined(STM32F723xx) || defined(STM32F733xx) + // Needs to remain awake during sleep or else __WFI() will disable the USB + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_ENABLE(); + __HAL_RCC_OTGPHYC_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + #endif + + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + + #else // !MICROPY_HW_USB_HS_IN_FS + + GPIO_InitTypeDef GPIO_InitStruct; + + // Configure USB HS GPIOs + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + // CLK + GPIO_InitStruct.Pin = GPIO_PIN_5; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // D0 + GPIO_InitStruct.Pin = GPIO_PIN_3; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // D1 D2 D3 D4 D5 D6 D7 + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // STP + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + // NXT + GPIO_InitStruct.Pin = GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + // DIR + GPIO_InitStruct.Pin = GPIO_PIN_11; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); + + // Enable USB HS Clocks + __USB_OTG_HS_CLK_ENABLE(); + __USB_OTG_HS_ULPI_CLK_ENABLE(); + + #endif // !MICROPY_HW_USB_HS_IN_FS + + // Configure and enable USB HS interrupt + NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS); + HAL_NVIC_EnableIRQ(OTG_HS_IRQn); + } + #endif // MICROPY_HW_USB_HS +} + +/** + * @brief DeInitializes the PCD MSP. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { + if (hpcd->Instance == USB_OTG_FS) { + /* Disable USB FS Clocks */ + __USB_OTG_FS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #if MICROPY_HW_USB_HS + else if (hpcd->Instance == USB_OTG_HS) { + /* Disable USB FS Clocks */ + __USB_OTG_HS_CLK_DISABLE(); + __SYSCFG_CLK_DISABLE(); + } + #endif +} + +/******************************************************************************* + LL Driver Callbacks (PCD -> USB Device Library) +*******************************************************************************/ + +/** + * @brief Setup stage callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_SetupStage(hpcd->pData, (uint8_t *)hpcd->Setup); +} + +/** + * @brief Data Out stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataOutStage(hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff); +} + +/** + * @brief Data In stage callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_DataInStage(hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff); +} + +/** + * @brief SOF callback. + * @param hpcd: PCD handle + * @retval None + */ +/* +This is now handled by the USB CDC interface. +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +{ + USBD_LL_SOF(hpcd->pData); +} +*/ + +/** + * @brief Reset callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) { + USBD_SpeedTypeDef speed = USBD_SPEED_FULL; + + // Set USB Current Speed + switch (hpcd->Init.speed) { + #if defined(PCD_SPEED_HIGH) + case PCD_SPEED_HIGH: + speed = USBD_SPEED_HIGH; + break; + #endif + + case PCD_SPEED_FULL: + speed = USBD_SPEED_FULL; + break; + + default: + speed = USBD_SPEED_FULL; + break; + } + USBD_LL_SetSpeed(hpcd->pData, speed); + + // Reset Device + USBD_LL_Reset(hpcd->pData); +} + +/** + * @brief Suspend callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_Suspend(hpcd->pData); +} + +/** + * @brief Resume callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_Resume(hpcd->pData); +} + +/** + * @brief ISOC Out Incomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoOUTIncomplete(hpcd->pData, epnum); +} + +/** + * @brief ISOC In Incomplete callback. + * @param hpcd: PCD handle + * @param epnum: Endpoint Number + * @retval None + */ +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) { + USBD_LL_IsoINIncomplete(hpcd->pData, epnum); +} + +/** + * @brief Connect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevConnected(hpcd->pData); +} + +/** + * @brief Disconnect callback. + * @param hpcd: PCD handle + * @retval None + */ +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) { + USBD_LL_DevDisconnected(hpcd->pData); +} + +/******************************************************************************* + LL Driver Interface (USB Device Library --> PCD) +*******************************************************************************/ + +/** + * @brief Initializes the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) { + #if MICROPY_HW_USB_FS + if (pdev->id == USB_PHY_FS_ID) { + // Set LL Driver parameters + pcd_fs_handle.Instance = USB_OTG_FS; + #if MICROPY_HW_USB_ENABLE_CDC2 + pcd_fs_handle.Init.dev_endpoints = 6; + #else + pcd_fs_handle.Init.dev_endpoints = 4; + #endif + pcd_fs_handle.Init.use_dedicated_ep1 = 0; + pcd_fs_handle.Init.ep0_mps = 0x40; + pcd_fs_handle.Init.dma_enable = 0; + pcd_fs_handle.Init.low_power_enable = 0; + pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + pcd_fs_handle.Init.Sof_enable = 0; + pcd_fs_handle.Init.speed = PCD_SPEED_FULL; + #if defined(STM32L4) + pcd_fs_handle.Init.lpm_enable = DISABLE; + pcd_fs_handle.Init.battery_charging_enable = DISABLE; + #endif + #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + pcd_fs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 + #else + pcd_fs_handle.Init.vbus_sensing_enable = 1; + #endif + + // Link The driver to the stack + pcd_fs_handle.pData = pdev; + pdev->pData = &pcd_fs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_fs_handle); + + // We have 320 32-bit words in total to use here + #if MICROPY_HW_USB_ENABLE_CDC2 + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA + #else + HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128); + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA + #endif + } + #endif + #if MICROPY_HW_USB_HS + if (pdev->id == USB_PHY_HS_ID) { + #if MICROPY_HW_USB_HS_IN_FS + + // Set LL Driver parameters + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 6; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + pcd_hs_handle.Init.dma_enable = 0; + pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.lpm_enable = DISABLE; + pcd_hs_handle.Init.battery_charging_enable = DISABLE; + #if defined(STM32F723xx) || defined(STM32F733xx) + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + #else + pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + #endif + pcd_hs_handle.Init.Sof_enable = 0; + if (high_speed) { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + } else { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + } + #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) + pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 + #else + pcd_hs_handle.Init.vbus_sensing_enable = 1; + #endif + pcd_hs_handle.Init.use_external_vbus = 0; + + // Link The driver to the stack + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_hs_handle); + + // We have 1024 32-bit words in total to use here + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 464); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0 + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 8); // CDC CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 128); // CDC DATA + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 8); // CDC2 CMD + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 128); // CDC2 DATA + + #else // !MICROPY_HW_USB_HS_IN_FS + + // Set LL Driver parameters + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 6; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + + /* Be aware that enabling USB-DMA mode will result in data being sent only by + multiple of 4 packet sizes. This is due to the fact that USB-DMA does + not allow sending data from non word-aligned addresses. + For this specific application, it is advised to not enable this option + unless required. */ + pcd_hs_handle.Init.dma_enable = 0; + + pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.phy_itface = PCD_PHY_ULPI; + pcd_hs_handle.Init.Sof_enable = 0; + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + pcd_hs_handle.Init.vbus_sensing_enable = 1; + + // Link The driver to the stack + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + + // Initialize LL Driver + HAL_PCD_Init(&pcd_hs_handle); + + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174); + + #endif // !MICROPY_HW_USB_HS_IN_FS + } + #endif // MICROPY_HW_USB_HS + + return USBD_OK; +} + +/** + * @brief De-Initializes the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) { + HAL_PCD_DeInit(pdev->pData); + return USBD_OK; +} + +/** + * @brief Starts the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) { + HAL_PCD_Start(pdev->pData); + return USBD_OK; +} + +/** + * @brief Stops the Low Level portion of the Device driver. + * @param pdev: Device handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) { + HAL_PCD_Stop(pdev->pData); + return USBD_OK; +} + +/** + * @brief Opens an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param ep_type: Endpoint Type + * @param ep_mps: Endpoint Max Packet Size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps) { + HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type); + return USBD_OK; +} + +/** + * @brief Closes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_Close(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Flushes an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_Flush(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Sets a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_SetStall(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Clears a Stall condition on an endpoint of the Low Level Driver. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + HAL_PCD_EP_ClrStall(pdev->pData, ep_addr); + return USBD_OK; +} + +/** + * @brief Returns Stall condition. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval Stall (1: yes, 0: No) + */ +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + PCD_HandleTypeDef *hpcd = pdev->pData; + + if ((ep_addr & 0x80) == 0x80) { + return hpcd->IN_ep[ep_addr & 0x7F].is_stall; + } else { + return hpcd->OUT_ep[ep_addr & 0x7F].is_stall; + } +} + +/** + * @brief Assigns an USB address to the device + * @param pdev: Device handle + * @param dev_addr: USB address + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) { + HAL_PCD_SetAddress(pdev->pData, dev_addr); + return USBD_OK; +} + +/** + * @brief Transmits data over an endpoint + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param pbuf: Pointer to data to be sent + * @param size: Data size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { + HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size); + return USBD_OK; +} + +/** + * @brief Prepares an endpoint for reception + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @param pbuf:pointer to data to be received + * @param size: data size + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, uint8_t *pbuf, uint16_t size) { + HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size); + return USBD_OK; +} + +/** + * @brief Returns the last transfered packet size. + * @param pdev: Device handle + * @param ep_addr: Endpoint Number + * @retval Recived Data Size + */ +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) { + return HAL_PCD_EP_GetRxCount(pdev->pData, ep_addr); +} + +/** + * @brief Delay routine for the USB Device Library + * @param Delay: Delay in ms + * @retval None + */ +void USBD_LL_Delay(uint32_t Delay) { + HAL_Delay(Delay); +} + +#endif // MICROPY_HW_USB_FS || MICROPY_HW_USB_HS + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbd_conf.h b/src/openmv/src/micropython/ports/stm32/usbd_conf.h new file mode 100755 index 0000000..1f8e754 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_conf.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +#ifndef MICROPY_INCLUDED_STM32_USBD_CONF_H +#define MICROPY_INCLUDED_STM32_USBD_CONF_H + +#include +#include +#include +#include + +#define USBD_MAX_NUM_INTERFACES 4 +#define USBD_MAX_NUM_CONFIGURATION 1 +#define USBD_MAX_STR_DESC_SIZ 0x100 +#define USBD_SELF_POWERED 0 +#define USBD_DEBUG_LEVEL 0 + +#endif // MICROPY_INCLUDED_STM32_USBD_CONF_H + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbd_desc.c b/src/openmv/src/micropython/ports/stm32/usbd_desc.c new file mode 100755 index 0000000..4babebf --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_desc.c @@ -0,0 +1,184 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_desc.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief This file provides the USBD descriptors and string formating method. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_conf.h" + +// need this header just for MP_HAL_UNIQUE_ID_ADDRESS +#include "py/mphal.h" + +// So we don't clash with existing ST boards, we use the unofficial FOSS VID. +// This needs a proper solution. +#define USBD_VID 0xf055 +#define USBD_PID 0x9800 +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "MicroPython" +#define USBD_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode" +#define USBD_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode" +#define USBD_CONFIGURATION_HS_STRING "Pyboard Config" +#define USBD_INTERFACE_HS_STRING "Pyboard Interface" +#define USBD_CONFIGURATION_FS_STRING "Pyboard Config" +#define USBD_INTERFACE_FS_STRING "Pyboard Interface" + +__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +// set the VID, PID and device release number +void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only) { + uint8_t *dev_desc = &usbd->usbd_device_desc[0]; + + dev_desc[0] = USB_LEN_DEV_DESC; // bLength + dev_desc[1] = USB_DESC_TYPE_DEVICE; // bDescriptorType + dev_desc[2] = 0x00; // bcdUSB + dev_desc[3] = 0x02; // bcdUSB + if (cdc_only) { + // Make it look like a Communications device if we're only + // using CDC. Otherwise, windows gets confused when we tell it that + // its a composite device with only a cdc serial interface. + dev_desc[4] = 0x02; // bDeviceClass + dev_desc[5] = 0x00; // bDeviceSubClass + dev_desc[6] = 0x00; // bDeviceProtocol + } else { + // For the other modes, we make this look like a composite device. + dev_desc[4] = 0xef; // bDeviceClass: Miscellaneous Device Class + dev_desc[5] = 0x02; // bDeviceSubClass: Common Class + dev_desc[6] = 0x01; // bDeviceProtocol: Interface Association Descriptor + } + dev_desc[7] = USB_MAX_EP0_SIZE; // bMaxPacketSize + dev_desc[8] = LOBYTE(vid); // idVendor + dev_desc[9] = HIBYTE(vid); // idVendor + dev_desc[10] = LOBYTE(pid); // idVendor + dev_desc[11] = HIBYTE(pid); // idVendor + dev_desc[12] = LOBYTE(device_release_num); // bcdDevice + dev_desc[13] = HIBYTE(device_release_num); // bcdDevice + dev_desc[14] = USBD_IDX_MFC_STR; // Index of manufacturer string + dev_desc[15] = USBD_IDX_PRODUCT_STR; // Index of product string + dev_desc[16] = USBD_IDX_SERIAL_STR; // Index of serial number string + dev_desc[17] = USBD_MAX_NUM_CONFIGURATION; // bNumConfigurations +} + +/** + * @brief Returns the device descriptor. + * @param speed: Current device speed + * @param length: Pointer to data length variable + * @retval Pointer to descriptor buffer + */ +STATIC uint8_t *USBD_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + uint8_t *dev_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_device_desc; + *length = USB_LEN_DEV_DESC; + return dev_desc; +} + +/** + * @brief Returns a string descriptor + * @param idx: Index of the string descriptor to retrieve + * @param length: Pointer to data length variable + * @retval Pointer to descriptor buffer, or NULL if idx is invalid + */ +STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + char str_buf[16]; + const char *str = NULL; + + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + str = USBD_MANUFACTURER_STRING; + break; + + case USBD_IDX_PRODUCT_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_PRODUCT_HS_STRING; + } else { + str = USBD_PRODUCT_FS_STRING; + } + break; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you use: lsusb -v + // + // See: https://my.st.com/52d187b7 for the algorithim used. + + uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; + snprintf(str_buf, sizeof(str_buf), + "%02X%02X%02X%02X%02X%02X", + id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]); + + str = str_buf; + break; + } + + case USBD_IDX_CONFIG_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_CONFIGURATION_HS_STRING; + } else { + str = USBD_CONFIGURATION_FS_STRING; + } + break; + + case USBD_IDX_INTERFACE_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_INTERFACE_HS_STRING; + } else { + str = USBD_INTERFACE_FS_STRING; + } + break; + + default: + // invalid string index + return NULL; + } + + uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; + USBD_GetString((uint8_t*)str, str_desc, length); + return str_desc; +} + +const USBD_DescriptorsTypeDef USBD_Descriptors = { + USBD_DeviceDescriptor, + USBD_StrDescriptor, +}; + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbd_desc.h b/src/openmv/src/micropython/ports/stm32/usbd_desc.h new file mode 100755 index 0000000..0307def --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_desc.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_USBD_DESC_H +#define MICROPY_INCLUDED_STM32_USBD_DESC_H + +#include "usbd_cdc_msc_hid.h" + +extern const USBD_DescriptorsTypeDef USBD_Descriptors; + +void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only); + +#endif // MICROPY_INCLUDED_STM32_USBD_DESC_H diff --git a/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.c b/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.c new file mode 100755 index 0000000..3ffc0b4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.c @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and heavily modified. See below for original + * copyright header. + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief Source file for USBD CDC interface + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ + +#include + +#include "usbd_hid_interface.h" + +#include "py/obj.h" +#include "irq.h" +#include "usb.h" + +uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + + hid->current_read_buffer = 0; + hid->last_read_len = 0; + hid->current_write_buffer = 0; + + // Return the buffer to place the first USB OUT packet + return hid->buffer[hid->current_write_buffer]; +} + +// Data received over USB OUT endpoint is processed here. +// len: number of bytes received into the buffer we passed to USBD_HID_ReceivePacket +// Returns USBD_OK if all operations are OK else USBD_FAIL +int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + + hid->current_write_buffer = !hid->current_write_buffer; + hid->last_read_len = len; + // initiate next USB packet transfer, to append to existing data in buffer + USBD_HID_ReceivePacket(&hid->base, hid->buffer[hid->current_write_buffer]); + // Set NAK to indicate we need to process read buffer + USBD_HID_SetNAK(&hid->base); + return USBD_OK; +} + +// Returns number of ready rx buffers. +int usbd_hid_rx_num(usbd_hid_itf_t *hid) { + return hid->current_read_buffer != hid->current_write_buffer; +} + +// timout in milliseconds. +// Returns number of bytes read from the device. +int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) { + // Wait until we have buffer to read + uint32_t start = HAL_GetTick(); + while (hid->current_read_buffer == hid->current_write_buffer) { + // Wraparound of tick is taken care of by 2's complement arithmetic. + if (HAL_GetTick() - start >= timeout) { + // timeout + return 0; + } + if (query_irq() == IRQ_STATE_DISABLED) { + // IRQs disabled so buffer will never be filled; return immediately + return 0; + } + __WFI(); // enter sleep mode, waiting for interrupt + } + + // There is not enough space in buffer + if (len < hid->last_read_len) { + return 0; + } + + // Copy bytes from device to user buffer + int read_len = hid->last_read_len; + memcpy(buf, hid->buffer[hid->current_read_buffer], read_len); + hid->current_read_buffer = !hid->current_read_buffer; + + // Clear NAK to indicate we are ready to read more data + USBD_HID_ClearNAK(&hid->base); + + // Success, return number of bytes read + return read_len; +} diff --git a/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.h b/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.h new file mode 100755 index 0000000..777fa93 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_hid_interface.h @@ -0,0 +1,21 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ +#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H + +#include "usbd_cdc_msc_hid.h" + +typedef struct _usbd_hid_itf_t { + usbd_hid_state_t base; // state for the base HID layer + + uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into + int8_t current_read_buffer; // which buffer to read from + uint32_t last_read_len; // length of last read + int8_t current_write_buffer; // which buffer to write to +} usbd_hid_itf_t; + +int usbd_hid_rx_num(usbd_hid_itf_t *hid); +int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout); + +#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H diff --git a/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.c b/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.c new file mode 100755 index 0000000..7d6c19e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.c @@ -0,0 +1,306 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file usbd_storage_msd.c + * @author MCD application Team + * @version V1.1.0 + * @date 19-March-2012 + * @brief This file provides the disk operations functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + * Heavily modified by dpgeorge for MicroPython. + * + ****************************************************************************** + */ + +#include + +#include "usbd_cdc_msc_hid.h" +#include "usbd_msc_storage.h" + +#include "py/mpstate.h" +#include "storage.h" +#include "sdcard.h" + +// These are needed to support removal of the medium, so that the USB drive +// can be unmounted, and won't be remounted automatically. +static uint8_t flash_started = 0; + +#if MICROPY_HW_HAS_SDCARD +static uint8_t sdcard_started = 0; +#endif + +/******************************************************************************/ +// Callback functions for when the internal flash is the mass storage device + +static const int8_t FLASH_STORAGE_Inquirydata[] = { // 36 bytes + // LUN 0 + 0x00, + 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive + 0x02, + 0x02, + (STANDARD_INQUIRY_DATA_LEN - 5), + 0x00, + 0x00, + 0x00, + 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes + 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes + 'F', 'l', 'a', 's', 'h', ' ', ' ', ' ', + '1', '.', '0' ,'0', // Version : 4 Bytes +}; + +/** + * @brief Initialize the storage medium + * @param lun : logical unit number + * @retval Status + */ +int8_t FLASH_STORAGE_Init(uint8_t lun) { + storage_init(); + flash_started = 1; + return 0; +} + +/** + * @brief return medium capacity and block size + * @param lun : logical unit number + * @param block_num : number of physical block + * @param block_size : size of a physical block + * @retval Status + */ +int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { + *block_size = storage_get_block_size(); + *block_num = storage_get_block_count(); + return 0; +} + +/** + * @brief check whether the medium is ready + * @param lun : logical unit number + * @retval Status + */ +int8_t FLASH_STORAGE_IsReady(uint8_t lun) { + if (flash_started) { + return 0; + } + return -1; +} + +/** + * @brief check whether the medium is write-protected + * @param lun : logical unit number + * @retval Status + */ +int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) { + return 0; +} + +// Remove the lun +int8_t FLASH_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) { + flash_started = started; + return 0; +} + +int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { + // sync the flash so that the cache is cleared and the device can be unplugged/turned off + storage_flush(); + return 0; +} + +/** + * @brief Read data from the medium + * @param lun : logical unit number + * @param buf : Pointer to the buffer to save data + * @param blk_addr : address of 1st block to be read + * @param blk_len : nmber of blocks to be read + * @retval Status + */ +int8_t FLASH_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + storage_read_blocks(buf, blk_addr, blk_len); + return 0; +} + +/** + * @brief Write data to the medium + * @param lun : logical unit number + * @param buf : Pointer to the buffer to write from + * @param blk_addr : address of 1st block to be written + * @param blk_len : nmber of blocks to be read + * @retval Status + */ +int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + storage_write_blocks(buf, blk_addr, blk_len); + return 0; +} + +/** + * @brief Return number of supported logical unit + * @param None + * @retval number of logical unit + */ +int8_t FLASH_STORAGE_GetMaxLun(void) { + return 0; +} + +const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = { + FLASH_STORAGE_Init, + FLASH_STORAGE_GetCapacity, + FLASH_STORAGE_IsReady, + FLASH_STORAGE_IsWriteProtected, + FLASH_STORAGE_StartStopUnit, + FLASH_STORAGE_PreventAllowMediumRemoval, + FLASH_STORAGE_Read, + FLASH_STORAGE_Write, + FLASH_STORAGE_GetMaxLun, + (int8_t *)FLASH_STORAGE_Inquirydata, +}; + +/******************************************************************************/ +// Callback functions for when the SD card is the mass storage device + +#if MICROPY_HW_HAS_SDCARD + +static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes + // LUN 0 + 0x00, + 0x80, // 0x00 for a fixed drive, 0x80 for a removable drive + 0x02, + 0x02, + (STANDARD_INQUIRY_DATA_LEN - 5), + 0x00, + 0x00, + 0x00, + 'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes + 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product : 16 Bytes + 'S', 'D', ' ', 'c', 'a', 'r', 'd', ' ', + '1', '.', '0' ,'0', // Version : 4 Bytes +}; + +/** + * @brief Initialize the storage medium + * @param lun : logical unit number + * @retval Status + */ +int8_t SDCARD_STORAGE_Init(uint8_t lun) { + if (!sdcard_power_on()) { + return -1; + } + sdcard_started = 1; + return 0; + +} + +/** + * @brief return medium capacity and block size + * @param lun : logical unit number + * @param block_num : number of physical block + * @param block_size : size of a physical block + * @retval Status + */ +int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) { + *block_size = SDCARD_BLOCK_SIZE; + *block_num = sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE; + return 0; +} + +/** + * @brief check whether the medium is ready + * @param lun : logical unit number + * @retval Status + */ +int8_t SDCARD_STORAGE_IsReady(uint8_t lun) { + if (sdcard_started) { + return 0; + } + return -1; +} + +/** + * @brief check whether the medium is write-protected + * @param lun : logical unit number + * @retval Status + */ +int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) { + return 0; +} + +// Remove the lun +int8_t SDCARD_STORAGE_StartStopUnit(uint8_t lun, uint8_t started) { + sdcard_started = started; + return 0; +} + +int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { + return 0; +} + +/** + * @brief Read data from the medium + * @param lun : logical unit number + * @param buf : Pointer to the buffer to save data + * @param blk_addr : address of 1st block to be read + * @param blk_len : nmber of blocks to be read + * @retval Status + */ +int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + if (sdcard_read_blocks(buf, blk_addr, blk_len) != 0) { + return -1; + } + return 0; +} + +/** + * @brief Write data to the medium + * @param lun : logical unit number + * @param buf : Pointer to the buffer to write from + * @param blk_addr : address of 1st block to be written + * @param blk_len : nmber of blocks to be read + * @retval Status + */ +int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { + if (sdcard_write_blocks(buf, blk_addr, blk_len) != 0) { + return -1; + } + return 0; +} + +/** + * @brief Return number of supported logical unit + * @param None + * @retval number of logical unit + */ +int8_t SDCARD_STORAGE_GetMaxLun(void) { + return 0; +} + +const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = { + SDCARD_STORAGE_Init, + SDCARD_STORAGE_GetCapacity, + SDCARD_STORAGE_IsReady, + SDCARD_STORAGE_IsWriteProtected, + SDCARD_STORAGE_StartStopUnit, + SDCARD_STORAGE_PreventAllowMediumRemoval, + SDCARD_STORAGE_Read, + SDCARD_STORAGE_Write, + SDCARD_STORAGE_GetMaxLun, + (int8_t *)SDCARD_STORAGE_Inquirydata, +}; + +#endif // MICROPY_HW_HAS_SDCARD diff --git a/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.h b/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.h new file mode 100755 index 0000000..669f7df --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbd_msc_storage.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H + +extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops; +extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops; + +#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h new file mode 100755 index 0000000..1857273 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -0,0 +1,197 @@ +#ifndef _USB_CDC_MSC_CORE_H_ +#define _USB_CDC_MSC_CORE_H_ + +#include "usbd_cdc_msc_hid0.h" +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_ioreq.h" + +// These are included to get direct access the MICROPY_HW_USB_xxx config +#include "mpconfigboard.h" +#include "mpconfigboard_common.h" + +// Work out if we should support USB high-speed device mode +#if MICROPY_HW_USB_HS \ + && (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx)) +#define USBD_SUPPORT_HS_MODE (1) +#else +#define USBD_SUPPORT_HS_MODE (0) +#endif + +// Needed for the CDC+MSC+HID state and should be maximum of all template +// config descriptors defined in usbd_cdc_msc_hid.c +#if MICROPY_HW_USB_ENABLE_CDC2 +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#else +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +#endif + +// CDC, MSC and HID packet sizes +#define MSC_FS_MAX_PACKET (64) +#define MSC_HS_MAX_PACKET (512) +#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size +#define CDC_DATA_HS_MAX_PACKET_SIZE (512) // endpoint IN & OUT packet size +#if USBD_SUPPORT_HS_MODE +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#else +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE +#endif +#define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working? +#define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size + +// Need to define here for BOT and SCSI layers +#define MSC_IN_EP (0x81) +#define MSC_OUT_EP (0x01) + +struct _usbd_cdc_msc_hid_state_t; + +typedef struct { + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment + uint8_t iface_num; + uint8_t in_ep; + uint8_t out_ep; + uint8_t cur_request; + uint8_t cur_length; + volatile uint8_t tx_in_progress; +} usbd_cdc_state_t; + +typedef struct _USBD_STORAGE { + int8_t (* Init) (uint8_t lun); + int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size); + int8_t (* IsReady) (uint8_t lun); + int8_t (* IsWriteProtected) (uint8_t lun); + int8_t (* StartStopUnit)(uint8_t lun, uint8_t started); + int8_t (* PreventAllowMediumRemoval)(uint8_t lun, uint8_t param0); + int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); + int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); + int8_t (* GetMaxLun)(void); + int8_t *pInquiry; +} USBD_StorageTypeDef; + +typedef struct { + uint32_t max_lun; + uint32_t interface; + uint8_t bot_state; + uint8_t bot_status; + uint16_t bot_data_length; + uint8_t bot_data[MSC_MEDIA_PACKET]; + USBD_MSC_BOT_CBWTypeDef cbw; + USBD_MSC_BOT_CSWTypeDef csw; + + USBD_SCSI_SenseTypeDef scsi_sense [SENSE_LIST_DEEPTH]; + uint8_t scsi_sense_head; + uint8_t scsi_sense_tail; + + uint16_t scsi_blk_size; + uint32_t scsi_blk_nbr; + + uint32_t scsi_blk_addr_in_blks; + uint32_t scsi_blk_len; + + // operations of the underlying block device + USBD_StorageTypeDef *bdev_ops; +} USBD_MSC_BOT_HandleTypeDef; + +typedef enum { + HID_IDLE = 0, + HID_BUSY, +} HID_StateTypeDef; + +typedef struct { + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint8_t iface_num; + uint8_t in_ep; + uint8_t out_ep; + uint8_t state; + uint8_t ctl_protocol; + uint8_t ctl_idle_state; + uint8_t ctl_alt_setting; + uint8_t *desc; + const uint8_t *report_desc; +} usbd_hid_state_t; + +typedef struct _usbd_cdc_msc_hid_state_t { + USBD_HandleTypeDef *pdev; + + uint8_t usbd_mode; + uint8_t usbd_config_desc_size; + + USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; + + // RAM to hold the current descriptors, which we configure on the fly + __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; + __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; + __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; + + usbd_cdc_state_t *cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_state_t *cdc2; + #endif + usbd_hid_state_t *hid; +} usbd_cdc_msc_hid_state_t; + +#define USBD_HID_MOUSE_MAX_PACKET (4) +#define USBD_HID_MOUSE_REPORT_DESC_SIZE (74) + +extern const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE]; + +#define USBD_HID_KEYBOARD_MAX_PACKET (8) +#define USBD_HID_KEYBOARD_REPORT_DESC_SIZE (63) + +extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE]; + +extern const USBD_ClassTypeDef USBD_CDC_MSC_HID; + +static inline uint32_t usbd_msc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return MSC_HS_MAX_PACKET; + } else + #endif + { + return MSC_FS_MAX_PACKET; + } +} + +static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return CDC_DATA_HS_MAX_PACKET_SIZE; + } else + #endif + { + return CDC_DATA_FS_MAX_PACKET_SIZE; + } +} + +// returns 0 on success, -1 on failure +int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); +// returns the current usb mode +uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd); + +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf); +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf); + +static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD_StorageTypeDef *fops) { + usbd->MSC_BOT_ClassData.bdev_ops = fops; +} + +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *usbd, uint8_t *buf); +int USBD_HID_CanSendReport(usbd_hid_state_t *usbd); +uint8_t USBD_HID_SendReport(usbd_hid_state_t *usbd, uint8_t *report, uint16_t len); +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *usbd); +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *usbd); + +// These are provided externally to implement the CDC interface +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc); +void usbd_cdc_deinit(usbd_cdc_state_t *cdc); +void usbd_cdc_tx_ready(usbd_cdc_state_t *cdc); +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length); +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc, size_t len); + +// These are provided externally to implement the HID interface +uint8_t *usbd_hid_init(usbd_hid_state_t *hid); +int8_t usbd_hid_receive(usbd_hid_state_t *hid, size_t len); + +#endif // _USB_CDC_MSC_CORE_H_ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h new file mode 100755 index 0000000..c876dcf --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#define MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H + +// these are exports for the CDC/MSC/HID interface that are independent +// from any other definitions/declarations + +// only CDC_MSC and CDC_HID are available +typedef enum { + USBD_MODE_CDC = 0x01, + USBD_MODE_MSC = 0x02, + USBD_MODE_HID = 0x04, + USBD_MODE_CDC2 = 0x08, + USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC, + USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID, + USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID, + USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2, + USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above +} usb_device_mode_t; + +typedef struct _USBD_HID_ModeInfoTypeDef { + uint8_t subclass; // 0=no sub class, 1=boot + uint8_t protocol; // 0=none, 1=keyboard, 2=mouse + uint8_t max_packet_len; // only support up to 255 + uint8_t polling_interval; // in units of 1ms + uint8_t report_desc_len; + const uint8_t *report_desc; +} USBD_HID_ModeInfoTypeDef; + +#endif // MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_bot.h b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_bot.h new file mode 100755 index 0000000..4edc912 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_bot.h @@ -0,0 +1,151 @@ +/** + ****************************************************************************** + * @file usbd_msc_bot.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_bot.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ + +#include "usbd_core.h" + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_BOT_H +#define __USBD_MSC_BOT_H + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup MSC_BOT + * @brief This file is the Header file for usbd_bot.c + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ +#define USBD_BOT_IDLE 0 /* Idle state */ +#define USBD_BOT_DATA_OUT 1 /* Data Out state */ +#define USBD_BOT_DATA_IN 2 /* Data In state */ +#define USBD_BOT_LAST_DATA_IN 3 /* Last Data In Last */ +#define USBD_BOT_SEND_DATA 4 /* Send Immediate data */ +#define USBD_BOT_NO_DATA 5 /* No data Stage */ + +#define USBD_BOT_CBW_SIGNATURE 0x43425355 +#define USBD_BOT_CSW_SIGNATURE 0x53425355 +#define USBD_BOT_CBW_LENGTH 31 +#define USBD_BOT_CSW_LENGTH 13 +#define USBD_BOT_MAX_DATA 256 + +/* CSW Status Definitions */ +#define USBD_CSW_CMD_PASSED 0x00 +#define USBD_CSW_CMD_FAILED 0x01 +#define USBD_CSW_PHASE_ERROR 0x02 + +/* BOT Status */ +#define USBD_BOT_STATUS_NORMAL 0 +#define USBD_BOT_STATUS_RECOVERY 1 +#define USBD_BOT_STATUS_ERROR 2 + + +#define USBD_DIR_IN 0 +#define USBD_DIR_OUT 1 +#define USBD_BOTH_DIR 2 + +/** + * @} + */ + +/** @defgroup MSC_CORE_Private_TypesDefinitions + * @{ + */ + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataLength; + uint8_t bmFlags; + uint8_t bLUN; + uint8_t bCBLength; + uint8_t CB[16]; + uint8_t ReservedForAlign; +} +USBD_MSC_BOT_CBWTypeDef; + + +typedef struct +{ + uint32_t dSignature; + uint32_t dTag; + uint32_t dDataResidue; + uint8_t bStatus; + uint8_t ReservedForAlign[3]; +} +USBD_MSC_BOT_CSWTypeDef; + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_Types + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_CORE_Exported_FunctionsPrototypes + * @{ + */ +void MSC_BOT_Init (USBD_HandleTypeDef *pdev); +void MSC_BOT_Reset (USBD_HandleTypeDef *pdev); +void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev); +void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, + uint8_t epnum); + +void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, + uint8_t CSW_Status); + +void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, + uint8_t epnum); +/** + * @} + */ + +#endif /* __USBD_MSC_BOT_H */ +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_data.h b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_data.h new file mode 100755 index 0000000..afd39e4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_data.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * @file usbd_msc_data.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_data.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ + +#ifndef _USBD_MSC_DATA_H_ +#define _USBD_MSC_DATA_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_INFO + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_INFO_Exported_Defines + * @{ + */ +#define MODE_SENSE6_LEN 8 +#define MODE_SENSE10_LEN 8 +#define LENGTH_INQUIRY_PAGE00 7 +#define LENGTH_FORMAT_CAPACITIES 20 + +/** + * @} + */ + + +/** @defgroup USBD_INFO_Exported_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_INFO_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_Variables + * @{ + */ +extern const uint8_t MSC_Page00_Inquiry_Data[]; +extern const uint8_t MSC_Mode_Sense6_data[]; +extern const uint8_t MSC_Mode_Sense10_data[] ; + +/** + * @} + */ + +/** @defgroup USBD_INFO_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* _USBD_MSC_DATA_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h new file mode 100755 index 0000000..b657cea --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/inc/usbd_msc_scsi.h @@ -0,0 +1,195 @@ +/** + ****************************************************************************** + * @file usbd_msc_scsi.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header for the usbd_msc_scsi.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_SCSI_H +#define __USBD_MSC_SCSI_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_SCSI + * @brief header file for the storage disk file + * @{ + */ + +/** @defgroup USBD_SCSI_Exported_Defines + * @{ + */ + +#define SENSE_LIST_DEEPTH 4 + +/* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT6 0x15 +#define SCSI_MODE_SELECT10 0x55 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_MODE_SENSE10 0x5A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_SYNCHRONIZE_CACHE10 0x35 +#define SCSI_SYNCHRONIZE_CACHE16 0x91 +#define SCSI_READ6 0x08 +#define SCSI_READ10 0x28 +#define SCSI_READ12 0xA8 +#define SCSI_READ16 0x88 + +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_READ_CAPACITY16 0x9E + +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE6 0x0A +#define SCSI_WRITE10 0x2A +#define SCSI_WRITE12 0xAA +#define SCSI_WRITE16 0x8A + +#define SCSI_VERIFY10 0x2F +#define SCSI_VERIFY12 0xAF +#define SCSI_VERIFY16 0x8F + +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define NO_SENSE 0 +#define RECOVERED_ERROR 1 +#define NOT_READY 2 +#define MEDIUM_ERROR 3 +#define HARDWARE_ERROR 4 +#define ILLEGAL_REQUEST 5 +#define UNIT_ATTENTION 6 +#define DATA_PROTECT 7 +#define BLANK_CHECK 8 +#define VENDOR_SPECIFIC 9 +#define COPY_ABORTED 10 +#define ABORTED_COMMAND 11 +#define VOLUME_OVERFLOW 13 +#define MISCOMPARE 14 + + +#define INVALID_CDB 0x20 +#define INVALID_FIELED_IN_COMMAND 0x24 +#define PARAMETER_LIST_LENGTH_ERROR 0x1A +#define INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define ADDRESS_OUT_OF_RANGE 0x21 +#define MEDIUM_NOT_PRESENT 0x3A +#define MEDIUM_HAVE_CHANGED 0x28 +#define WRITE_PROTECTED 0x27 +#define UNRECOVERED_READ_ERROR 0x11 +#define WRITE_FAULT 0x03 + +#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define READ_CAPACITY10_DATA_LEN 0x08 +#define MODE_SENSE10_DATA_LEN 0x08 +#define MODE_SENSE6_DATA_LEN 0x04 +#define REQUEST_SENSE_DATA_LEN 0x12 +#define STANDARD_INQUIRY_DATA_LEN 0x24 +#define BLKVFY 0x04 + +extern uint8_t Page00_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data2[]; +extern uint8_t Mode_Sense6_data[]; +extern uint8_t Mode_Sense10_data[]; +extern uint8_t Scsi_Sense_Data[]; +extern uint8_t ReadCapacity10_Data[]; +extern uint8_t ReadFormatCapacity_Data []; +/** + * @} + */ + + +/** @defgroup USBD_SCSI_Exported_TypesDefinitions + * @{ + */ + +typedef struct _SENSE_ITEM { + char Skey; + union { + struct _ASCs { + char ASC; + char ASCQ; + }b; + unsigned int ASC; + char *pData; + } w; +} USBD_SCSI_SenseTypeDef; +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Variables + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_SCSI_Exported_FunctionsPrototype + * @{ + */ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t *cmd); + +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t sKey, + uint8_t ASC); + +/** + * @} + */ + +#endif /* __USBD_MSC_SCSI_H */ +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c new file mode 100755 index 0000000..809e0d4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -0,0 +1,1324 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include STM32_HAL_H +#include "usbd_ioreq.h" +#include "usbd_cdc_msc_hid.h" + +#if MICROPY_HW_ENABLE_USB + +#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) +#define MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) +#define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) +#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) +#define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) +#define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) +#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) +#define CDC_TEMPLATE_CDC_DESC_OFFSET (9) +#define CDC_DESC_OFFSET_INTR_INTERVAL (34) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_LO (48) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_HI (49) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_LO (55) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_HI (56) +#define HID_DESC_OFFSET_SUBCLASS (6) +#define HID_DESC_OFFSET_PROTOCOL (7) +#define HID_DESC_OFFSET_SUBDESC (9) +#define HID_DESC_OFFSET_REPORT_DESC_LEN (16) +#define HID_DESC_OFFSET_MAX_PACKET_LO (22) +#define HID_DESC_OFFSET_MAX_PACKET_HI (23) +#define HID_DESC_OFFSET_POLLING_INTERVAL (24) +#define HID_DESC_OFFSET_MAX_PACKET_OUT_LO (29) +#define HID_DESC_OFFSET_MAX_PACKET_OUT_HI (30) +#define HID_DESC_OFFSET_POLLING_INTERVAL_OUT (31) +#define HID_SUBDESC_LEN (9) + +#define CDC_IFACE_NUM_ALONE (0) +#define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_MSC (3) +#define CDC_IFACE_NUM_WITH_HID (1) +#define MSC_IFACE_NUM_WITH_CDC (0) +#define HID_IFACE_NUM_WITH_CDC (0) +#define HID_IFACE_NUM_WITH_MSC (1) + +#define CDC_IN_EP (0x83) +#define CDC_OUT_EP (0x03) +#define CDC_CMD_EP (0x82) + +#define CDC2_IN_EP (0x85) +#define CDC2_OUT_EP (0x05) +#define CDC2_CMD_EP (0x84) + +#define HID_IN_EP_WITH_CDC (0x81) +#define HID_OUT_EP_WITH_CDC (0x01) +#define HID_IN_EP_WITH_MSC (0x83) +#define HID_OUT_EP_WITH_MSC (0x03) + +#define USB_DESC_TYPE_ASSOCIATION (0x0b) + +#define CDC_CMD_PACKET_SIZE (8) // Control Endpoint Packet size + +#define BOT_GET_MAX_LUN (0xfe) +#define BOT_RESET (0xff) + +#define HID_DESCRIPTOR_TYPE (0x21) +#define HID_REPORT_DESC (0x22) +#define HID_REQ_SET_PROTOCOL (0x0b) +#define HID_REQ_GET_PROTOCOL (0x03) +#define HID_REQ_SET_IDLE (0x0a) +#define HID_REQ_GET_IDLE (0x02) + +#if USBD_SUPPORT_HS_MODE +// USB Standard Device Descriptor +__ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, // same for CDC and MSC (latter being MSC_FS_MAX_PACKET), HID is 0x04 + 0x01, + 0x00, +}; +#endif + +// USB MSC device Configuration Descriptor +static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), + 0x01, // bNumInterfaces: 1 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // MSC only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor + MSC_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints + 0x08, // bInterfaceClass: MSC Class + 0x06, // bInterfaceSubClass : SCSI transparent + 0x50, // nInterfaceProtocol + 0x00, // iInterface: + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_IN_EP, // bEndpointAddress: IN, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_OUT_EP, // bEndpointAddress: OUT, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer +}; + +// USB CDC MSC device Configuration Descriptor +static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE), + 0x03, // bNumInterfaces: 3 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // MSC only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor + MSC_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints + 0x08, // bInterfaceClass: MSC Class + 0x06, // bInterfaceSubClass : SCSI transparent + 0x50, // nInterfaceProtocol + 0x00, // iInterface: + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_IN_EP, // bEndpointAddress: IN, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_OUT_EP, // bEndpointAddress: OUT, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + //========================================================================== + // Interface Association for CDC VCP + 0x08, // bLength: 8 bytes + USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD + CDC_IFACE_NUM_WITH_MSC, // bFirstInterface: first interface for this association + 0x02, // bInterfaceCount: nummber of interfaces for this association + 0x02, // bFunctionClass: Communication Interface Class + 0x02, // bFunctionSubClass: Abstract Control Model + 0x01, // bFunctionProtocol: Common AT commands + 0x00, // iFunction: index of string for this function + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface + CDC_IFACE_NUM_WITH_MSC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x01, // bNumEndpoints: One endpoints used + 0x02, // bInterfaceClass: Communication Interface Class + 0x02, // bInterfaceSubClass: Abstract Control Model + 0x01, // bInterfaceProtocol: Common AT commands + 0x00, // iInterface: + + // Header Functional Descriptor + 0x05, // bLength: Endpoint Descriptor size + 0x24, // bDescriptorType: CS_INTERFACE + 0x00, // bDescriptorSubtype: Header Func Desc + 0x10, // bcdCDC: spec release number + 0x01, // ? + + // Call Management Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x01, // bDescriptorSubtype: Call Management Func Desc + 0x00, // bmCapabilities: D0+D1 + CDC_IFACE_NUM_WITH_MSC + 1, // bDataInterface: 1 + + // ACM Functional Descriptor + 0x04, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x02, // bDescriptorSubtype: Abstract Control Management desc + 0x02, // bmCapabilities + + // Union Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptorSubtype: Union func desc + CDC_IFACE_NUM_WITH_MSC + 0, // bMasterInterface: Communication class interface + CDC_IFACE_NUM_WITH_MSC + 1, // bSlaveInterface0: Data Class Interface + + // Endpoint 2 Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_CMD_EP, // bEndpointAddress + 0x03, // bmAttributes: Interrupt + LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: + HIBYTE(CDC_CMD_PACKET_SIZE), + 0x20, // bInterval: polling interval in frames of 1ms + + //-------------------------------------------------------------------------- + // Data class interface descriptor + 0x09, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface + CDC_IFACE_NUM_WITH_MSC + 1, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints: Two endpoints used + 0x0A, // bInterfaceClass: CDC + 0x00, // bInterfaceSubClass: ? + 0x00, // bInterfaceProtocol: ? + 0x00, // iInterface: + + // Endpoint OUT Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint IN Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_IN_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer +}; + +// USB CDC HID device Configuration Descriptor +static const uint8_t cdc_hid_template_config_desc[CDC_HID_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(CDC_HID_TEMPLATE_CONFIG_DESC_SIZE), + 0x03, // bNumInterfaces: 3 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // HID only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor + HID_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints + 0x03, // bInterfaceClass: HID Class + 0x01, // bInterfaceSubClass: 0=no sub class, 1=boot + 0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse + 0x00, // iInterface: + + // HID descriptor + 0x09, // bLength: HID Descriptor size + HID_DESCRIPTOR_TYPE, // bDescriptorType: HID + 0x11, // bcdHID: HID Class Spec release number + 0x01, + 0x00, // bCountryCode: Hardware target country + 0x01, // bNumDescriptors: Number of HID class descriptors to follow + 0x22, // bDescriptorType + USBD_HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor + 0x00, + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + HID_IN_EP_WITH_CDC, // bEndpointAddress: IN + 0x03, // bmAttributes: Interrupt endpoint type + LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize + HIBYTE(USBD_HID_MOUSE_MAX_PACKET), + 0x08, // bInterval: Polling interval + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + HID_OUT_EP_WITH_CDC, // bEndpointAddress: OUT + 0x03, // bmAttributes: Interrupt endpoint type + LOBYTE(USBD_HID_MOUSE_MAX_PACKET), // wMaxPacketSize + HIBYTE(USBD_HID_MOUSE_MAX_PACKET), + 0x08, // bInterval: Polling interval + + //========================================================================== + // Interface Association for CDC VCP + 0x08, // bLength: 8 bytes + USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD + CDC_IFACE_NUM_WITH_HID, // bFirstInterface: first interface for this association + 0x02, // bInterfaceCount: nummber of interfaces for this association + 0x02, // bFunctionClass: Communication Interface Class + 0x02, // bFunctionSubClass: Abstract Control Model + 0x01, // bFunctionProtocol: Common AT commands + 0x00, // iFunction: index of string for this function + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface + CDC_IFACE_NUM_WITH_HID, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x01, // bNumEndpoints: One endpoints used + 0x02, // bInterfaceClass: Communication Interface Class + 0x02, // bInterfaceSubClass: Abstract Control Model + 0x01, // bInterfaceProtocol: Common AT commands + 0x00, // iInterface: + + // Header Functional Descriptor + 0x05, // bLength: Endpoint Descriptor size + 0x24, // bDescriptorType: CS_INTERFACE + 0x00, // bDescriptorSubtype: Header Func Desc + 0x10, // bcdCDC: spec release number + 0x01, // ? + + // Call Management Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x01, // bDescriptorSubtype: Call Management Func Desc + 0x00, // bmCapabilities: D0+D1 + CDC_IFACE_NUM_WITH_HID + 1, // bDataInterface: 1 + + // ACM Functional Descriptor + 0x04, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x02, // bDescriptorSubtype: Abstract Control Management desc + 0x02, // bmCapabilities + + // Union Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptorSubtype: Union func desc + CDC_IFACE_NUM_WITH_HID + 0, // bMasterInterface: Communication class interface + CDC_IFACE_NUM_WITH_HID + 1, // bSlaveInterface0: Data Class Interface + + // Endpoint 2 Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_CMD_EP, // bEndpointAddress + 0x03, // bmAttributes: Interrupt + LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: + HIBYTE(CDC_CMD_PACKET_SIZE), + 0x20, // bInterval: polling interval in frames of 1ms + + //-------------------------------------------------------------------------- + // Data class interface descriptor + 0x09, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface + CDC_IFACE_NUM_WITH_HID + 1, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints: Two endpoints used + 0x0A, // bInterfaceClass: CDC + 0x00, // bInterfaceSubClass: ? + 0x00, // bInterfaceProtocol: ? + 0x00, // iInterface: + + // Endpoint OUT Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint IN Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_IN_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer +}; + +static const uint8_t cdc_template_config_desc[CDC_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength:no of returned bytes + HIBYTE(CDC_TEMPLATE_CONFIG_DESC_SIZE), + 0x02, // bNumInterfaces: 2 interface + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: Interface + CDC_IFACE_NUM_ALONE, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x01, // bNumEndpoints: One endpoints used + 0x02, // bInterfaceClass: Communication Interface Class + 0x02, // bInterfaceSubClass: Abstract Control Model + 0x01, // bInterfaceProtocol: Common AT commands + 0x00, // iInterface: + + // Header Functional Descriptor + 0x05, // bLength: Endpoint Descriptor size + 0x24, // bDescriptorType: CS_INTERFACE + 0x00, // bDescriptorSubtype: Header Func Desc + 0x10, // bcdCDC: spec release number + 0x01, // ? + + // Call Management Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x01, // bDescriptorSubtype: Call Management Func Desc + 0x00, // bmCapabilities: D0+D1 + CDC_IFACE_NUM_ALONE + 1, // bDataInterface: 1 + + // ACM Functional Descriptor + 0x04, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x02, // bDescriptorSubtype: Abstract Control Management desc + 0x02, // bmCapabilities + + // Union Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptorSubtype: Union func desc + CDC_IFACE_NUM_ALONE + 0, // bMasterInterface: Communication class interface + CDC_IFACE_NUM_ALONE + 1, // bSlaveInterface0: Data Class Interface + + // Endpoint 2 Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_CMD_EP, // bEndpointAddress + 0x03, // bmAttributes: Interrupt + LOBYTE(CDC_CMD_PACKET_SIZE), // wMaxPacketSize: + HIBYTE(CDC_CMD_PACKET_SIZE), + 0x20, // bInterval: polling interval in frames of 1ms + + //-------------------------------------------------------------------------- + // Data class interface descriptor + 0x09, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: + CDC_IFACE_NUM_ALONE + 1, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints: Two endpoints used + 0x0a, // bInterfaceClass: CDC + 0x00, // bInterfaceSubClass: ? + 0x00, // bInterfaceProtocol: ? + 0x00, // iInterface: + + // Endpoint OUT Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint IN Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint + CDC_IN_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),// wMaxPacketSize: + HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), + 0x00 // bInterval: ignore for Bulk transfer +}; + +__ALIGN_BEGIN const uint8_t USBD_HID_MOUSE_ReportDesc[USBD_HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = { + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x02, // Usage (Mouse), + 0xA1, 0x01, // Collection (Application), + 0x09, 0x01, // Usage (Pointer), + 0xA1, 0x00, // Collection (Physical), + 0x05, 0x09, // Usage Page (Buttons), + 0x19, 0x01, // Usage Minimum (01), + 0x29, 0x03, // Usage Maximum (03), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x95, 0x03, // Report Count (3), + 0x75, 0x01, // Report Size (1), + 0x81, 0x02, // Input(Data, Variable, Absolute), -- 3 button bits + 0x95, 0x01, // Report Count(1), + 0x75, 0x05, // Report Size(5), + 0x81, 0x01, // Input(Constant), -- 5 bit padding + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x30, // Usage (X), + 0x09, 0x31, // Usage (Y), + 0x09, 0x38, // Usage (Wheel), + 0x15, 0x81, // Logical Minimum (-127), + 0x25, 0x7F, // Logical Maximum (127), + 0x75, 0x08, // Report Size (8), + 0x95, 0x03, // Report Count (3), + 0x81, 0x06, // Input(Data, Variable, Relative), -- 3 position bytes (X,Y,Wheel) + 0xC0, // End Collection, + 0x09, 0x3c, // Usage (Motion Wakeup), + 0x05, 0xff, // Usage Page (?), + 0x09, 0x01, // Usage (?), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x75, 0x01, // Report Size(1), + 0x95, 0x02, // Report Count(2), + 0xb1, 0x22, // ? + 0x75, 0x06, // Report Size(6), + 0x95, 0x01, // Report Count(1), + 0xb1, 0x01, // ? + 0xc0 // End Collection +}; + +__ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { + // From p69 of http://www.usb.org/developers/devclass_docs/HID1_11.pdf + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application), + 0x05, 0x07, // Usage Page (Key Codes); + 0x19, 0xE0, // Usage Minimum (224), + 0x29, 0xE7, // Usage Maximum (231), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x75, 0x01, // Report Size (1), + 0x95, 0x08, // Report Count (8), + 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte + 0x95, 0x01, // Report Count (1), + 0x75, 0x08, // Report Size (8), + 0x81, 0x01, // Input (Constant), ;Reserved byte + 0x95, 0x05, // Report Count (5), + 0x75, 0x01, // Report Size (1), + 0x05, 0x08, // Usage Page (Page# for LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report + 0x95, 0x01, // Report Count (1), + 0x75, 0x03, // Report Size (3), + 0x91, 0x01, // Output (Constant), ;LED report padding + 0x95, 0x06, // Report Count (6), + 0x75, 0x08, // Report Size (8), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x65, // Logical Maximum(101), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0x00, // Usage Minimum (0), + 0x29, 0x65, // Usage Maximum (101), + 0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes) + 0xC0 // End Collection +}; + +// return the saved usb mode +uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd) { + return usbd->usbd_mode; +} + +int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { + // save mode + usbd->usbd_mode = mode; + + // construct config desc + switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + usbd->usbd_config_desc_size = sizeof(msc_template_config_desc); + memcpy(usbd->usbd_config_desc, msc_template_config_desc, sizeof(msc_template_config_desc)); + break; + + case USBD_MODE_CDC_MSC: + usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc); + memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + break; + + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: { + usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength + d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); + d[4] = 5; // bNumInterfaces + memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58); + d += 9 + 23 + (8 + 58); + d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface + d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber + d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface + d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface + d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface + d[38] = CDC2_CMD_EP; // bEndpointAddress + d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber + d[54] = CDC2_OUT_EP; // bEndpointAddress + d[61] = CDC2_IN_EP; // bEndpointAddress + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + break; + } + #endif + + case USBD_MODE_CDC_HID: + usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); + memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC; + usbd->hid->desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; + break; + + case USBD_MODE_CDC: + usbd->usbd_config_desc_size = sizeof(cdc_template_config_desc); + memcpy(usbd->usbd_config_desc, cdc_template_config_desc, sizeof(cdc_template_config_desc)); + usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; + break; + + /* + // not implemented + case USBD_MODE_MSC_HID: + hid_in_ep = HID_IN_EP_WITH_MSC; + hid_out_ep = HID_OUT_EP_WITH_MSC; + hid_iface_num = HID_IFACE_NUM_WITH_MSC; + break; + */ + + default: + // mode not supported + return -1; + } + + if (usbd->usbd_mode & USBD_MODE_CDC) { + usbd->cdc->in_ep = CDC_IN_EP; + usbd->cdc->out_ep = CDC_OUT_EP; + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + usbd->cdc2->in_ep = CDC2_IN_EP; + usbd->cdc2->out_ep = CDC2_OUT_EP; + } + #endif + + // configure the HID descriptor, if needed + if (usbd->usbd_mode & USBD_MODE_HID) { + uint8_t *hid_desc = usbd->hid->desc; + hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; + hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; + hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; + hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO] = hid_info->max_packet_len; + hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] = 0; + hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL] = hid_info->polling_interval; + hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] = hid_info->max_packet_len; + hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] = 0; + hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; + usbd->hid->report_desc = hid_info->report_desc; + } + + return 0; +} + +static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) { + int mp = usbd_cdc_max_packet(pdev); + + // Open endpoints + USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); + + // Init state + cdc->usbd = usbd; + cdc->cur_request = 0xff; + cdc->tx_in_progress = 0; + + // Init interface + uint8_t *buf = usbd_cdc_init(cdc); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp); +} + +static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + #if !USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + // can't handle high speed + return 1; + } + #endif + + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + if (usbd->usbd_mode & USBD_MODE_CDC) { + // CDC VCP component + usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + // CDC VCP #2 component + usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP); + } + #endif + + if (usbd->usbd_mode & USBD_MODE_MSC) { + // MSC component + + int mp = usbd_msc_max_packet(pdev); + + // Open EP OUT + USBD_LL_OpenEP(pdev, + MSC_OUT_EP, + USBD_EP_TYPE_BULK, + mp); + + // Open EP IN + USBD_LL_OpenEP(pdev, + MSC_IN_EP, + USBD_EP_TYPE_BULK, + mp); + + // Init the BOT layer + MSC_BOT_Init(pdev); + } + + if (usbd->usbd_mode & USBD_MODE_HID) { + // HID component + + // get max packet lengths from descriptor + uint16_t mps_in = + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8); + uint16_t mps_out = + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + + // Open EP IN + USBD_LL_OpenEP(pdev, usbd->hid->in_ep, USBD_EP_TYPE_INTR, mps_in); + + // Open EP OUT + USBD_LL_OpenEP(pdev, usbd->hid->out_ep, USBD_EP_TYPE_INTR, mps_out); + + + usbd->hid->usbd = usbd; + uint8_t *buf = usbd_hid_init(usbd->hid); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, usbd->hid->out_ep, buf, mps_out); + + usbd->hid->state = HID_IDLE; + } + + return 0; +} + +static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + if ((usbd->usbd_mode & USBD_MODE_CDC) && usbd->cdc) { + // CDC VCP component + + usbd_cdc_deinit(usbd->cdc); + + // close endpoints + USBD_LL_CloseEP(pdev, CDC_IN_EP); + USBD_LL_CloseEP(pdev, CDC_OUT_EP); + USBD_LL_CloseEP(pdev, CDC_CMD_EP); + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { + // CDC VCP #2 component + + usbd_cdc_deinit(usbd->cdc2); + + // close endpoints + USBD_LL_CloseEP(pdev, CDC2_IN_EP); + USBD_LL_CloseEP(pdev, CDC2_OUT_EP); + USBD_LL_CloseEP(pdev, CDC2_CMD_EP); + } + #endif + + if (usbd->usbd_mode & USBD_MODE_MSC) { + // MSC component + + // close endpoints + USBD_LL_CloseEP(pdev, MSC_OUT_EP); + USBD_LL_CloseEP(pdev, MSC_IN_EP); + + // DeInit the BOT layer + MSC_BOT_DeInit(pdev); + } + + if (usbd->usbd_mode & USBD_MODE_HID) { + // HID component + + // close endpoints + USBD_LL_CloseEP(pdev, usbd->hid->in_ep); + USBD_LL_CloseEP(pdev, usbd->hid->out_ep); + } + + return 0; +} + +static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { + + /* + printf("SU: %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex); + + This is what we get when MSC is IFACE=0 and CDC is IFACE=1,2: + SU: 21 22 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE + SU: 21 20 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_LINE_CODING + SU: a1 fe 0 0 -- 0x80 | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; BOT_GET_MAX_LUN; 0; 0 + SU: 21 22 3 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE + + On a Mac OS X, with MSC then CDC: + SU: a1 fe 0 0 + SU: 21 22 2 1 + SU: 21 22 3 1 + SU: 21 20 0 1 + */ + + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + // Work out the recipient of the setup request + uint8_t mode = usbd->usbd_mode; + uint8_t recipient = 0; + usbd_cdc_state_t *cdc = NULL; + switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { + case USB_REQ_RECIPIENT_INTERFACE: { + uint16_t iface = req->wIndex; + if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif + } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { + recipient = USBD_MODE_HID; + } + break; + } + case USB_REQ_RECIPIENT_ENDPOINT: { + uint8_t ep = req->wIndex & 0x7f; + if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif + } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { + recipient = USBD_MODE_HID; + } + break; + } + } + + // Fail the request if we didn't have a valid recipient + if (recipient == 0) { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + + switch (req->bmRequest & USB_REQ_TYPE_MASK) { + + // Class request + case USB_REQ_TYPE_CLASS: + if (recipient == USBD_MODE_CDC) { + if (req->wLength) { + if (req->bmRequest & 0x80) { + // device-to-host request + usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + } else { + // host-to-device request + cdc->cur_request = req->bRequest; + cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + } + } else { + // Not a Data request + // Transfer the command to the interface layer + return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); + } + } else if (recipient == USBD_MODE_MSC) { + switch (req->bRequest) { + case BOT_GET_MAX_LUN: + if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { + usbd->MSC_BOT_ClassData.max_lun = usbd->MSC_BOT_ClassData.bdev_ops->GetMaxLun(); + USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.max_lun, 1); + } else { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + break; + + case BOT_RESET: + if ((req->wValue == 0) && (req->wLength == 0) && ((req->bmRequest & 0x80) != 0x80)) { + MSC_BOT_Reset(pdev); + } else { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + break; + + default: + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + } else if (recipient == USBD_MODE_HID) { + switch (req->bRequest) { + case HID_REQ_SET_PROTOCOL: + usbd->hid->ctl_protocol = (uint8_t)(req->wValue); + break; + + case HID_REQ_GET_PROTOCOL: + USBD_CtlSendData(pdev, &usbd->hid->ctl_protocol, 1); + break; + + case HID_REQ_SET_IDLE: + usbd->hid->ctl_idle_state = (uint8_t)(req->wValue >> 8); + break; + + case HID_REQ_GET_IDLE: + USBD_CtlSendData(pdev, &usbd->hid->ctl_idle_state, 1); + break; + + default: + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + } + break; + + case USB_REQ_TYPE_STANDARD: + if (recipient == USBD_MODE_MSC) { + switch (req->bRequest) { + case USB_REQ_GET_INTERFACE : + USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.interface, 1); + break; + + case USB_REQ_SET_INTERFACE : + usbd->MSC_BOT_ClassData.interface = (uint8_t)(req->wValue); + break; + + case USB_REQ_CLEAR_FEATURE: + // Flush the FIFO and Clear the stall status + USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex); + + // Re-activate the EP + USBD_LL_CloseEP(pdev, (uint8_t)req->wIndex); + if((((uint8_t)req->wIndex) & 0x80) == 0x80) { + // Open EP IN + USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); + } else { + // Open EP OUT + USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); + } + // Handle BOT error + MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); + break; + } + } else if (recipient == USBD_MODE_HID) { + switch (req->bRequest) { + case USB_REQ_GET_DESCRIPTOR: { + uint16_t len = 0; + const uint8_t *pbuf = NULL; + if (req->wValue >> 8 == HID_REPORT_DESC) { + len = usbd->hid->desc[HID_DESC_OFFSET_REPORT_DESC_LEN]; + len = MIN(len, req->wLength); + pbuf = usbd->hid->report_desc; + } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { + len = MIN(HID_SUBDESC_LEN, req->wLength); + pbuf = usbd->hid->desc + HID_DESC_OFFSET_SUBDESC; + } + USBD_CtlSendData(pdev, (uint8_t*)pbuf, len); + break; + } + + case USB_REQ_GET_INTERFACE: + USBD_CtlSendData(pdev, &usbd->hid->ctl_alt_setting, 1); + break; + + case USB_REQ_SET_INTERFACE: + usbd->hid->ctl_alt_setting = (uint8_t)(req->wValue); + break; + } + } + break; + } + return USBD_OK; +} + +/* unused +static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) { +} +*/ + +static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + if (usbd->cdc != NULL && usbd->cdc->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); + usbd->cdc->cur_request = 0xff; + } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length); + usbd->cdc2->cur_request = 0xff; + } + #endif + + return USBD_OK; +} + +static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { + usbd->cdc->tx_in_progress = 0; + usbd_cdc_tx_ready(usbd->cdc); + return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) { + usbd->cdc2->tx_in_progress = 0; + usbd_cdc_tx_ready(usbd->cdc2); + return USBD_OK; + #endif + } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { + MSC_BOT_DataIn(pdev, epnum); + return USBD_OK; + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->in_ep & 0x7f)) { + /* Ensure that the FIFO is empty before a new transfer, this condition could + be caused by a new transfer before the end of the previous transfer */ + usbd->hid->state = HID_IDLE; + return USBD_OK; + } + + return USBD_OK; +} + +static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) { + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + if ((usbd->usbd_mode & USBD_MODE_CDC) && epnum == (CDC_OUT_EP & 0x7f)) { + /* Get the received data length */ + size_t len = USBD_LL_GetRxDataSize (pdev, epnum); + + /* USB data will be immediately processed, this allow next USB traffic being + NAKed till the end of the application Xfer */ + usbd_cdc_receive(usbd->cdc, len); + + return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_cdc_receive(usbd->cdc2, len); + return USBD_OK; + #endif + } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { + MSC_BOT_DataOut(pdev, epnum); + return USBD_OK; + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_hid_receive(usbd->hid, len); + } + + return USBD_OK; +} + +#if USBD_SUPPORT_HS_MODE +static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; +} +#endif + +static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { + usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + #if USBD_SUPPORT_HS_MODE + uint8_t *cdc_desc = NULL; + #if MICROPY_HW_USB_ENABLE_CDC2 + uint8_t *cdc2_desc = NULL; + #endif + uint8_t *msc_desc = NULL; + switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_MSC: + cdc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: + cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + + case USBD_MODE_CDC_HID: + cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; + break; + + case USBD_MODE_CDC: + cdc_desc = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; + break; + } + + // configure CDC descriptors, if needed + if (cdc_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc_desc); + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if (cdc2_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc2_desc); + } + #endif + + if (msc_desc != NULL) { + uint32_t mp = usbd_msc_max_packet(pdev); + msc_desc[13] = LOBYTE(mp); + msc_desc[14] = HIBYTE(mp); + msc_desc[20] = LOBYTE(mp); + msc_desc[21] = HIBYTE(mp); + } + #endif + + *length = usbd->usbd_config_desc_size; + return usbd->usbd_config_desc; +} + +uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + #if USBD_SUPPORT_HS_MODE + *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); + return USBD_CDC_MSC_HID_DeviceQualifierDesc; + #else + *length = 0; + return NULL; + #endif +} + +// data received on non-control OUT endpoint +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf) { + if (cdc->tx_in_progress == 0) { + // transmit next packet + USBD_LL_Transmit(cdc->usbd->pdev, cdc->in_ep, (uint8_t*)buf, len); + + // Tx transfer in progress + cdc->tx_in_progress = 1; + return USBD_OK; + } else { + return USBD_BUSY; + } +} + +// prepare OUT endpoint for reception +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { + // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE + if (cdc->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + return USBD_FAIL; + } + #endif + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); + + return USBD_OK; +} + +// prepare OUT endpoint for reception +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *hid, uint8_t *buf) { + // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE + if (hid->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + return USBD_FAIL; + } + #endif + + // Prepare Out endpoint to receive next packet + uint16_t mps_out = + hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + USBD_LL_PrepareReceive(hid->usbd->pdev, hid->out_ep, buf, mps_out); + + return USBD_OK; +} + +int USBD_HID_CanSendReport(usbd_hid_state_t *hid) { + return hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED && hid->state == HID_IDLE; +} + +uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len) { + if (hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { + if (hid->state == HID_IDLE) { + hid->state = HID_BUSY; + USBD_LL_Transmit(hid->usbd->pdev, hid->in_ep, report, len); + return USBD_OK; + } + } + return USBD_FAIL; +} + +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) { + // get USBx object from pdev (needed for USBx_OUTEP macro below) + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + // set NAK on HID OUT endpoint + USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; + return USBD_OK; +} + +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) { + // get USBx object from pdev (needed for USBx_OUTEP macro below) + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + // clear NAK on HID OUT endpoint + USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; + return USBD_OK; +} + +// CDC/MSC/HID interface class callback structure +const USBD_ClassTypeDef USBD_CDC_MSC_HID = { + USBD_CDC_MSC_HID_Init, + USBD_CDC_MSC_HID_DeInit, + USBD_CDC_MSC_HID_Setup, + NULL, // EP0_TxSent + USBD_CDC_MSC_HID_EP0_RxReady, + USBD_CDC_MSC_HID_DataIn, + USBD_CDC_MSC_HID_DataOut, + NULL, // SOF + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete + USBD_CDC_MSC_HID_GetCfgDesc, + USBD_CDC_MSC_HID_GetCfgDesc, + USBD_CDC_MSC_HID_GetCfgDesc, + USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor, +}; + +#endif diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_bot.c new file mode 100755 index 0000000..d20f7a8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_bot.c @@ -0,0 +1,407 @@ +/** + ****************************************************************************** + * @file usbd_msc_bot.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the BOT protocol core functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_cdc_msc_hid.h" +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_BOT + * @brief BOT protocol module + * @{ + */ + +/** @defgroup MSC_BOT_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_FunctionPrototypes + * @{ + */ +static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev); + +static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev, + uint8_t* pbuf, + uint16_t len); + +static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev); +/** + * @} + */ + + +/** @defgroup MSC_BOT_Private_Functions + * @{ + */ + + + +/** +* @brief MSC_BOT_Init +* Initialize the BOT Process +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_Init (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_NORMAL; + + hmsc->scsi_sense_tail = 0; + hmsc->scsi_sense_head = 0; + + hmsc->bdev_ops->Init(0); + + USBD_LL_FlushEP(pdev, MSC_OUT_EP); + USBD_LL_FlushEP(pdev, MSC_IN_EP); + + /* Prapare EP to Receive First BOT Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** +* @brief MSC_BOT_Reset +* Reset the BOT Machine +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_Reset (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_state = USBD_BOT_IDLE; + hmsc->bot_status = USBD_BOT_STATUS_RECOVERY; + + /* Prapare EP to Receive First BOT Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); +} + +/** +* @brief MSC_BOT_DeInit +* Uninitialize the BOT Machine +* @param pdev: device instance +* @retval None +*/ +void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_state = USBD_BOT_IDLE; +} + +/** +* @brief MSC_BOT_DataIn +* Handle BOT IN data stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ +void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, + uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + switch (hmsc->bot_state) + { + case USBD_BOT_DATA_IN: + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + break; + + case USBD_BOT_SEND_DATA: + case USBD_BOT_LAST_DATA_IN: + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); + + break; + + default: + break; + } +} +/** +* @brief MSC_BOT_DataOut +* Proccess MSC OUT data +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ +void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, + uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + switch (hmsc->bot_state) + { + case USBD_BOT_IDLE: + MSC_BOT_CBW_Decode(pdev); + break; + + case USBD_BOT_DATA_OUT: + + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + + break; + + default: + break; + } +} + +/** +* @brief MSC_BOT_CBW_Decode +* Decode the CBW command and set the BOT state machine accordingtly +* @param pdev: device instance +* @retval None +*/ +static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->csw.dTag = hmsc->cbw.dTag; + hmsc->csw.dDataResidue = hmsc->cbw.dDataLength; + + if ((USBD_LL_GetRxDataSize (pdev ,MSC_OUT_EP) != USBD_BOT_CBW_LENGTH) || + (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)|| + (hmsc->cbw.bLUN > 1) || + (hmsc->cbw.bCBLength < 1) || + (hmsc->cbw.bCBLength > 16)) + { + + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + + hmsc->bot_status = USBD_BOT_STATUS_ERROR; + MSC_BOT_Abort(pdev); + + } + else + { + if(SCSI_ProcessCmd(pdev, + hmsc->cbw.bLUN, + &hmsc->cbw.CB[0]) < 0) + { + if(hmsc->bot_state == USBD_BOT_NO_DATA) + { + MSC_BOT_SendCSW (pdev, + USBD_CSW_CMD_FAILED); + } + else + { + MSC_BOT_Abort(pdev); + } + } + /*Burst xfer handled internally*/ + else if ((hmsc->bot_state != USBD_BOT_DATA_IN) && + (hmsc->bot_state != USBD_BOT_DATA_OUT) && + (hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) + { + if (hmsc->bot_data_length > 0) + { + MSC_BOT_SendData(pdev, + hmsc->bot_data, + hmsc->bot_data_length); + } + else if (hmsc->bot_data_length == 0) + { + MSC_BOT_SendCSW (pdev, + USBD_CSW_CMD_PASSED); + } + } + } +} + +/** +* @brief MSC_BOT_SendData +* Send the requested data +* @param pdev: device instance +* @param buf: pointer to data buffer +* @param len: Data Length +* @retval None +*/ +static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, + uint8_t* buf, + uint16_t len) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + len = MIN (hmsc->cbw.dDataLength, len); + hmsc->csw.dDataResidue -= len; + hmsc->csw.bStatus = USBD_CSW_CMD_PASSED; + hmsc->bot_state = USBD_BOT_SEND_DATA; + + USBD_LL_Transmit (pdev, MSC_IN_EP, buf, len); +} + +/** +* @brief MSC_BOT_SendCSW +* Send the Command Status Wrapper +* @param pdev: device instance +* @param status : CSW status +* @retval None +*/ +void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, + uint8_t CSW_Status) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE; + hmsc->csw.bStatus = CSW_Status; + hmsc->bot_state = USBD_BOT_IDLE; + + USBD_LL_Transmit (pdev, + MSC_IN_EP, + (uint8_t *)&hmsc->csw, + USBD_BOT_CSW_LENGTH); + + /* Prapare EP to Receive next Cmd */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); + +} + +/** +* @brief MSC_BOT_Abort +* Abort the current transfer +* @param pdev: device instance +* @retval status +*/ + +static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((hmsc->cbw.bmFlags == 0) && + (hmsc->cbw.dDataLength != 0) && + (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) ) + { + USBD_LL_StallEP(pdev, MSC_OUT_EP ); + } + USBD_LL_StallEP(pdev, MSC_IN_EP); + + if(hmsc->bot_status == USBD_BOT_STATUS_ERROR) + { + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + (uint8_t *)&hmsc->cbw, + USBD_BOT_CBW_LENGTH); + } +} + +/** +* @brief MSC_BOT_CplClrFeature +* Complete the clear feature request +* @param pdev: device instance +* @param epnum: endpoint index +* @retval None +*/ + +void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */ + { + USBD_LL_StallEP(pdev, MSC_IN_EP); + hmsc->bot_status = USBD_BOT_STATUS_NORMAL; + } + else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); + } + +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_data.c b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_data.c new file mode 100755 index 0000000..96740a3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_data.c @@ -0,0 +1,134 @@ +/** + ****************************************************************************** + * @file usbd_msc_data.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the vital inquiry pages and sense data. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_data.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_DATA + * @brief Mass storage info/data module + * @{ + */ + +/** @defgroup MSC_DATA_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Variables + * @{ + */ + + +/* USB Mass storage Page 0 Inquiry Data */ +const uint8_t MSC_Page00_Inquiry_Data[] = {//7 + 0x00, + 0x00, + 0x00, + (LENGTH_INQUIRY_PAGE00 - 4), + 0x00, + 0x80, + 0x83 +}; +/* USB Mass storage sense 6 Data */ +const uint8_t MSC_Mode_Sense6_data[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; +/* USB Mass storage sense 10 Data */ +const uint8_t MSC_Mode_Sense10_data[] = { + 0x00, + 0x06, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_DATA_Private_Functions + * @{ + */ + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_scsi.c b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_scsi.c new file mode 100755 index 0000000..9da9033 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/class/src/usbd_msc_scsi.c @@ -0,0 +1,811 @@ +/** + ****************************************************************************** + * @file usbd_msc_scsi.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the USBD SCSI layer functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_msc_bot.h" +#include "usbd_msc_scsi.h" +#include "usbd_msc_data.h" +#include "usbd_cdc_msc_hid.h" + + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup MSC_SCSI + * @brief Mass storage SCSI layer module + * @{ + */ + +/** @defgroup MSC_SCSI_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_FunctionPrototypes + * @{ + */ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params); +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params); +static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, + uint8_t lun , + uint32_t blk_offset , + uint16_t blk_nbr); +static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, + uint8_t lun); + +static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, + uint8_t lun); +/** + * @} + */ + + +/** @defgroup MSC_SCSI_Private_Functions + * @{ + */ + + +/** +* @brief SCSI_ProcessCmd +* Process SCSI commands +* @param pdev: device instance +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t *params) +{ + /* + if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) { + printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]); + } + */ + + switch (params[0]) + { + case SCSI_TEST_UNIT_READY: + return SCSI_TestUnitReady(pdev, lun, params); + + case SCSI_REQUEST_SENSE: + return SCSI_RequestSense (pdev, lun, params); + case SCSI_INQUIRY: + return SCSI_Inquiry(pdev, lun, params); + + case SCSI_START_STOP_UNIT: + return SCSI_StartStopUnit(pdev, lun, params); + + case SCSI_ALLOW_MEDIUM_REMOVAL: + return SCSI_AllowMediumRemoval(pdev, lun, params); + + case SCSI_MODE_SENSE6: + return SCSI_ModeSense6 (pdev, lun, params); + + case SCSI_MODE_SENSE10: + return SCSI_ModeSense10 (pdev, lun, params); + + case SCSI_SYNCHRONIZE_CACHE10: + case SCSI_SYNCHRONIZE_CACHE16: + return SCSI_SynchronizeCache(pdev, lun, params); + + case SCSI_READ_FORMAT_CAPACITIES: + return SCSI_ReadFormatCapacity(pdev, lun, params); + + case SCSI_READ_CAPACITY10: + return SCSI_ReadCapacity10(pdev, lun, params); + + case SCSI_READ10: + return SCSI_Read10(pdev, lun, params); + + case SCSI_WRITE10: + return SCSI_Write10(pdev, lun, params); + + case SCSI_VERIFY10: + return SCSI_Verify10(pdev, lun, params); + + default: + SCSI_SenseCode(pdev, + lun, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } +} + + +/** +* @brief SCSI_TestUnitReady +* Process SCSI Test Unit Ready Command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + /* case 9 : Hi > D0 */ + if (hmsc->cbw.dDataLength != 0) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + + hmsc->bot_state = USBD_BOT_NO_DATA; + return -1; + } + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_Inquiry +* Process Inquiry command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint8_t* pPage; + uint16_t len; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if (params[1] & 0x01)/*Evpd is set*/ + { + pPage = (uint8_t *)MSC_Page00_Inquiry_Data; + len = LENGTH_INQUIRY_PAGE00; + } + else + { + + pPage = (uint8_t *)&hmsc->bdev_ops->pInquiry[lun * STANDARD_INQUIRY_DATA_LEN]; + len = pPage[4] + 5; + + if (params[4] <= len) + { + len = params[4]; + } + } + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = pPage[len]; + } + return 0; +} + +/** +* @brief SCSI_ReadCapacity10 +* Process Read Capacity 10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bdev_ops->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + else + { + + hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24); + hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16); + hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8); + hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1); + + hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24); + hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16); + hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8); + hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size); + + hmsc->bot_data_length = 8; + return 0; + } +} +/** +* @brief SCSI_ReadFormatCapacity +* Process Read Format Capacity command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + uint16_t blk_size; + uint32_t blk_nbr; + uint16_t i; + + for(i=0 ; i < 12 ; i++) + { + hmsc->bot_data[i] = 0; + } + + if(hmsc->bdev_ops->GetCapacity(lun, &blk_nbr, &blk_size) != 0) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + else + { + hmsc->bot_data[3] = 0x08; + hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24); + hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16); + hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8); + hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1); + + hmsc->bot_data[8] = 0x02; + hmsc->bot_data[9] = (uint8_t)(blk_size >> 16); + hmsc->bot_data[10] = (uint8_t)(blk_size >> 8); + hmsc->bot_data[11] = (uint8_t)(blk_size); + + hmsc->bot_data_length = 12; + return 0; + } +} +/** +* @brief SCSI_ModeSense6 +* Process Mode Sense6 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + uint16_t len = 8 ; + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = MSC_Mode_Sense6_data[len]; + } + return 0; +} + +/** +* @brief SCSI_ModeSense10 +* Process Mode Sense10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint16_t len = 8; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->bot_data_length = len; + + while (len) + { + len--; + hmsc->bot_data[len] = MSC_Mode_Sense10_data[len]; + } + return 0; +} + +static int8_t SCSI_SynchronizeCache(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) { + // nothing to synchronize, so just return "success" + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_RequestSense +* Process Request Sense command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + uint8_t i; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) + { + hmsc->bot_data[i] = 0; + } + + hmsc->bot_data[0] = 0x70; + hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6; + + if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) { + + hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey; + hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ; + hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC; + hmsc->scsi_sense_head++; + + if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_head = 0; + } + } + hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN; + + if (params[4] <= REQUEST_SENSE_DATA_LEN) + { + hmsc->bot_data_length = params[4]; + } + return 0; +} + +/** +* @brief SCSI_SenseCode +* Load the last error code in the error list +* @param lun: Logical unit number +* @param sKey: Sense Key +* @param ASC: Additional Sense Key +* @retval none + +*/ +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey; + hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8; + hmsc->scsi_sense_tail++; + if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH) + { + hmsc->scsi_sense_tail = 0; + } +} +/** +* @brief SCSI_StartStopUnit +* Process Start Stop Unit command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + + // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent. + // Bit 0 of params[4] is the START bit. + // If we get a stop, we must really stop the device so that the Mac does not + // automatically remount it. + hmsc->bdev_ops->StartStopUnit(lun, params[4] & 1); + + return 0; +} + +/** +* @brief SCSI_AllowMediumRemoval +* Process Allow Medium Removal command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + hmsc->bot_data_length = 0; + hmsc->bdev_ops->PreventAllowMediumRemoval(lun, params[4]); + return 0; +} + +/** +* @brief SCSI_Read10 +* Process Read10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ +static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + + /* case 10 : Ho <> Di */ + + if ((hmsc->cbw.bmFlags & 0x80) != 0x80) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ + (params[3] << 16) | \ + (params[4] << 8) | \ + params[5]; + + hmsc->scsi_blk_len = (params[7] << 8) | \ + params[8]; + + + + if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr_in_blks, hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + + hmsc->bot_state = USBD_BOT_DATA_IN; + hmsc->scsi_blk_len *= hmsc->scsi_blk_size; + + /* cases 4,5 : Hi <> Dn */ + if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + } + hmsc->bot_data_length = MSC_MEDIA_PACKET; + + return SCSI_ProcessRead(pdev, lun); +} + +/** +* @brief SCSI_Write10 +* Process Write10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */ + { + + /* case 8 : Hi <> Do */ + + if ((hmsc->cbw.bmFlags & 0x80) == 0x80) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + /* Check whether Media is ready */ + if(hmsc->bdev_ops->IsReady(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + MEDIUM_NOT_PRESENT); + return -1; + } + + /* Check If media is write-protected */ + if(hmsc->bdev_ops->IsWriteProtected(lun) !=0 ) + { + SCSI_SenseCode(pdev, + lun, + NOT_READY, + WRITE_PROTECTED); + return -1; + } + + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | \ + (params[3] << 16) | \ + (params[4] << 8) | \ + params[5]; + hmsc->scsi_blk_len = (params[7] << 8) | \ + params[8]; + + /* check if LBA address is in the right range */ + if(SCSI_CheckAddressRange(pdev, + lun, + hmsc->scsi_blk_addr_in_blks, + hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + + hmsc->scsi_blk_len *= hmsc->scsi_blk_size; + + /* cases 3,11,13 : Hn,Ho <> D0 */ + if (hmsc->cbw.dDataLength != hmsc->scsi_blk_len) + { + SCSI_SenseCode(pdev, + hmsc->cbw.bLUN, + ILLEGAL_REQUEST, + INVALID_CDB); + return -1; + } + + /* Prepare EP to receive first data packet */ + hmsc->bot_state = USBD_BOT_DATA_OUT; + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + hmsc->bot_data, + MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); + } + else /* Write Process ongoing */ + { + return SCSI_ProcessWrite(pdev, lun); + } + return 0; +} + + +/** +* @brief SCSI_Verify10 +* Process Verify10 command +* @param lun: Logical unit number +* @param params: Command parameters +* @retval status +*/ + +static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((params[1]& 0x02) == 0x02) + { + SCSI_SenseCode (pdev, + lun, + ILLEGAL_REQUEST, + INVALID_FIELED_IN_COMMAND); + return -1; /* Error, Verify Mode Not supported*/ + } + + hmsc->scsi_blk_addr_in_blks = (params[2] << 24) | (params[3] << 16) | (params[4] << 8) | params[5]; + hmsc->scsi_blk_len = (params[7] << 8) | params[8]; + + if(SCSI_CheckAddressRange(pdev, + lun, + hmsc->scsi_blk_addr_in_blks, + hmsc->scsi_blk_len) < 0) + { + return -1; /* error */ + } + hmsc->bot_data_length = 0; + return 0; +} + +/** +* @brief SCSI_CheckAddressRange +* Check address range +* @param lun: Logical unit number +* @param blk_offset: first block address +* @param blk_nbr: number of block to be processed +* @retval status +*/ +static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr ) + { + SCSI_SenseCode(pdev, + lun, + ILLEGAL_REQUEST, + ADDRESS_OUT_OF_RANGE); + return -1; + } + return 0; +} + +/** +* @brief SCSI_ProcessRead +* Handle Read Process +* @param lun: Logical unit number +* @retval status +*/ +static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun) +{ + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + uint32_t len; + + len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); + + if( hmsc->bdev_ops->Read(lun , + hmsc->bot_data, + hmsc->scsi_blk_addr_in_blks, + len / hmsc->scsi_blk_size) < 0) + { + + SCSI_SenseCode(pdev, + lun, + HARDWARE_ERROR, + UNRECOVERED_READ_ERROR); + return -1; + } + + + USBD_LL_Transmit (pdev, + MSC_IN_EP, + hmsc->bot_data, + len); + + + hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; + hmsc->scsi_blk_len -= len; + + /* case 6 : Hi = Di */ + hmsc->csw.dDataResidue -= len; + + if (hmsc->scsi_blk_len == 0) + { + hmsc->bot_state = USBD_BOT_LAST_DATA_IN; + } + return 0; +} + +/** +* @brief SCSI_ProcessWrite +* Handle Write Process +* @param lun: Logical unit number +* @retval status +*/ + +static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun) +{ + uint32_t len; + USBD_MSC_BOT_HandleTypeDef *hmsc = &((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->MSC_BOT_ClassData; + + len = MIN(hmsc->scsi_blk_len , MSC_MEDIA_PACKET); + + if(hmsc->bdev_ops->Write(lun , + hmsc->bot_data, + hmsc->scsi_blk_addr_in_blks, + len / hmsc->scsi_blk_size) < 0) + { + SCSI_SenseCode(pdev, + lun, + HARDWARE_ERROR, + WRITE_FAULT); + return -1; + } + + + hmsc->scsi_blk_addr_in_blks += len / hmsc->scsi_blk_size; + hmsc->scsi_blk_len -= len; + + /* case 12 : Ho = Do */ + hmsc->csw.dDataResidue -= len; + + if (hmsc->scsi_blk_len == 0) + { + MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); + } + else + { + /* Prapare EP to Receive next packet */ + USBD_LL_PrepareReceive (pdev, + MSC_OUT_EP, + hmsc->bot_data, + MIN (hmsc->scsi_blk_len, MSC_MEDIA_PACKET)); + } + + return 0; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_core.h b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_core.h new file mode 100755 index 0000000..5494be3 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_core.h @@ -0,0 +1,159 @@ +/** + ****************************************************************************** + * @file usbd_core.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief Header file for usbd_core.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_CORE_H +#define __USBD_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" +#include "usbd_def.h" +#include "usbd_ioreq.h" +#include "usbd_ctlreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_CORE + * @brief This file is the Header file for usbd_core.c file + * @{ + */ + + +/** @defgroup USBD_CORE_Exported_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_CORE_Exported_TypesDefinitions + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_Variables + * @{ + */ +#define USBD_SOF USBD_LL_SOF +/** + * @} + */ + +/** @defgroup USBD_CORE_Exported_FunctionsPrototype + * @{ + */ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id); +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass); + +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx); + +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup); +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata); + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed); +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); + +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); + +/* USBD Low Level Driver */ +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed); +USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_OpenEP (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t ep_type, + uint16_t ep_mps); + +USBD_StatusTypeDef USBD_LL_CloseEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_FlushEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_StallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_ClearStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +uint8_t USBD_LL_IsStallEP (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +USBD_StatusTypeDef USBD_LL_SetUSBAddress (USBD_HandleTypeDef *pdev, uint8_t dev_addr); +USBD_StatusTypeDef USBD_LL_Transmit (USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, + uint8_t ep_addr, + uint8_t *pbuf, + uint16_t size); + +uint32_t USBD_LL_GetRxDataSize (USBD_HandleTypeDef *pdev, uint8_t ep_addr); +void USBD_LL_Delay (uint32_t Delay); + +/** + * @} + */ + +#endif /* __USBD_CORE_H */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ctlreq.h b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ctlreq.h new file mode 100755 index 0000000..8c26884 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ctlreq.h @@ -0,0 +1,106 @@ +/** + ****************************************************************************** + * @file usbd_req.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_req.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USB_REQUEST_H_ +#define __USB_REQUEST_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_REQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_REQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Exported_Types + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBD_REQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBD_REQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + + +void USBD_CtlError (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); + +void USBD_ParseSetupRequest (USBD_SetupReqTypedef *req, uint8_t *pdata); + +void USBD_GetString (uint8_t *desc, uint8_t *unicode, uint16_t *len); +/** + * @} + */ + +#endif /* __USB_REQUEST_H_ */ + +/** + * @} + */ + +/** +* @} +*/ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_def.h b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_def.h new file mode 100755 index 0000000..e0d1c37 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_def.h @@ -0,0 +1,313 @@ +/** + ****************************************************************************** + * @file usbd_def.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief general defines for the usb device library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_DEF_H +#define __USBD_DEF_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_conf.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USB_DEF + * @brief general defines for the usb device library file + * @{ + */ + +/** @defgroup USB_DEF_Exported_Defines + * @{ + */ + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#define USB_LEN_DEV_QUALIFIER_DESC 0x0A +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 +#define USB_LEN_LANGID_STR_DESC 0x04 +#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 + +#define USBD_IDX_LANGID_STR 0x00 +#define USBD_IDX_MFC_STR 0x01 +#define USBD_IDX_PRODUCT_STR 0x02 +#define USBD_IDX_SERIAL_STR 0x03 +#define USBD_IDX_CONFIG_STR 0x04 +#define USBD_IDX_INTERFACE_STR 0x05 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_MASK 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 1 +#define USB_DESC_TYPE_CONFIGURATION 2 +#define USB_DESC_TYPE_STRING 3 +#define USB_DESC_TYPE_INTERFACE 4 +#define USB_DESC_TYPE_ENDPOINT 5 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 + + +#define USB_CONFIG_REMOTE_WAKEUP 2 +#define USB_CONFIG_SELF_POWERED 1 + +#define USB_FEATURE_EP_HALT 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 +#define USB_FEATURE_TEST_MODE 2 + + +#define USB_HS_MAX_PACKET_SIZE 512 +#define USB_FS_MAX_PACKET_SIZE 64 +#define USB_MAX_EP0_SIZE 64 + +/* Device Status */ +#define USBD_STATE_DEFAULT 1 +#define USBD_STATE_ADDRESSED 2 +#define USBD_STATE_CONFIGURED 3 +#define USBD_STATE_SUSPENDED 4 + + +/* EP0 State */ +#define USBD_EP0_IDLE 0 +#define USBD_EP0_SETUP 1 +#define USBD_EP0_DATA_IN 2 +#define USBD_EP0_DATA_OUT 3 +#define USBD_EP0_STATUS_IN 4 +#define USBD_EP0_STATUS_OUT 5 +#define USBD_EP0_STALL 6 + +#define USBD_EP_TYPE_CTRL 0 +#define USBD_EP_TYPE_ISOC 1 +#define USBD_EP_TYPE_BULK 2 +#define USBD_EP_TYPE_INTR 3 + + +/** + * @} + */ + + +/** @defgroup USBD_DEF_Exported_TypesDefinitions + * @{ + */ + +typedef struct usb_setup_req +{ + + uint8_t bmRequest; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}USBD_SetupReqTypedef; + +struct _USBD_HandleTypeDef; + +typedef struct _Device_cb +{ + uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); + /* Control Endpoints*/ + uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req); + uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev ); + uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev ); + /* Class Specific Endpoints*/ + uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev); + uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); + + uint8_t *(*GetHSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + +} USBD_ClassTypeDef; + +/* Following USB Device Speed */ +typedef enum +{ + USBD_SPEED_HIGH = 0, + USBD_SPEED_FULL = 1, + USBD_SPEED_LOW = 2, +}USBD_SpeedTypeDef; + +/* Following USB Device status */ +typedef enum { + USBD_OK = 0, + USBD_BUSY, + USBD_FAIL, +}USBD_StatusTypeDef; + +struct _USBD_HandleTypeDef; + +/* USB Device descriptors structure */ +typedef struct +{ + uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length); +} USBD_DescriptorsTypeDef; + +/* USB Device handle structure */ +typedef struct +{ + uint32_t status; + uint32_t total_length; + uint32_t rem_length; + uint32_t maxpacket; +} USBD_EndpointTypeDef; + +/* USB Device handle structure */ +typedef struct _USBD_HandleTypeDef +{ + uint8_t id; + uint32_t dev_config; + uint32_t dev_default_config; + uint32_t dev_config_status; + USBD_SpeedTypeDef dev_speed; + USBD_EndpointTypeDef ep_in[15]; + USBD_EndpointTypeDef ep_out[15]; + uint32_t ep0_state; + uint32_t ep0_data_len; + uint8_t dev_state; + uint8_t dev_old_state; + uint8_t dev_address; + uint8_t dev_connection_status; + uint8_t dev_test_mode; + uint32_t dev_remote_wakeup; + + USBD_SetupReqTypedef request; + USBD_DescriptorsTypeDef *pDesc; + const USBD_ClassTypeDef *pClass; + void *pClassData; + void *pUserData; + void *pData; +} USBD_HandleTypeDef; + +/** + * @} + */ + + + +/** @defgroup USBD_DEF_Exported_Macros + * @{ + */ +#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LOBYTE(x) ((uint8_t)(x & 0x00FF)) +#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + + +#if defined ( __GNUC__ ) + #ifndef __weak + #define __weak __attribute__((weak)) + #endif /* __weak */ + #ifndef __packed + #define __packed __attribute__((__packed__)) + #endif /* __packed */ +#endif /* __GNUC__ */ + + +/* In HS mode and when the DMA is used, all variables and data structures dealing + with the DMA during the transaction process should be 4-bytes aligned */ + +#if defined (__GNUC__) /* GNU Compiler */ + #define __ALIGN_END __attribute__ ((aligned (4))) + #define __ALIGN_BEGIN +#else + #define __ALIGN_END + #if defined (__CC_ARM) /* ARM Compiler */ + #define __ALIGN_BEGIN __align(4) + #elif defined (__ICCARM__) /* IAR Compiler */ + #define __ALIGN_BEGIN + #elif defined (__TASKING__) /* TASKING Compiler */ + #define __ALIGN_BEGIN __align(4) + #endif /* __CC_ARM */ +#endif /* __GNUC__ */ + + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_DEF_Exported_FunctionsPrototype + * @{ + */ + +/** + * @} + */ + +#endif /* __USBD_DEF_H */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ioreq.h b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ioreq.h new file mode 100755 index 0000000..c964f0a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/inc/usbd_ioreq.h @@ -0,0 +1,121 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.h + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief header file for the usbd_ioreq.c file + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ + +#ifndef __USBD_IOREQ_H_ +#define __USBD_IOREQ_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" +#include "usbd_core.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_IOREQ + * @brief header file for the usbd_ioreq.c file + * @{ + */ + +/** @defgroup USBD_IOREQ_Exported_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Exported_Types + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup USBD_IOREQ_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_IOREQ_Exported_FunctionsPrototype + * @{ + */ + +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *buf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len); + +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev); + +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev); + +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , + uint8_t epnum); + +/** + * @} + */ + +#endif /* __USBD_IOREQ_H_ */ + +/** + * @} + */ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_core.c b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_core.c new file mode 100755 index 0000000..f235b24 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_core.c @@ -0,0 +1,552 @@ +/** + ****************************************************************************** + * @file usbd_core.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides all the USBD core functions. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_core.h" + +/** @addtogroup STM32_USBD_DEVICE_LIBRARY +* @{ +*/ + + +/** @defgroup USBD_CORE +* @brief usbd core module +* @{ +*/ + +/** @defgroup USBD_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Defines +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBD_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + + + +/** @defgroup USBD_CORE_Private_FunctionPrototypes +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Variables +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBD_CORE_Private_Functions +* @{ +*/ + +/** +* @brief USBD_Init +* Initailizes the device stack and load the class driver +* @param pdev: device instance +* @param core_address: USB OTG core ID +* @param pdesc: Descriptor structure address +* @param id: Low level core index +* @retval None +*/ +USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id) +{ + /* Check whether the USB Host handle is valid */ + if(pdev == NULL) + { + return USBD_FAIL; + } + + /* Unlink previous class*/ + if(pdev->pClass != NULL) + { + pdev->pClass = NULL; + } + + /* Assign USBD Descriptors */ + if(pdesc != NULL) + { + pdev->pDesc = pdesc; + } + + /* Set Device initial State */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->id = id; + /* Initialize low level driver */ + USBD_LL_Init(pdev, 0); + + return USBD_OK; +} + +/** +* @brief USBD_DeInit +* Re-Initialize th device library +* @param pdev: device instance +* @retval status: status +*/ +USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev) +{ + /* Set Default State */ + pdev->dev_state = USBD_STATE_DEFAULT; + + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + /* Initialize low level driver */ + USBD_LL_DeInit(pdev); + + return USBD_OK; +} + + +/** + * @brief USBD_RegisterClass + * Link class driver to Device Core. + * @param pDevice : Device Handle + * @param pclass: Class handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, const USBD_ClassTypeDef *pclass) +{ + USBD_StatusTypeDef status = USBD_OK; + if(pclass != 0) + { + /* link the class tgo the USB Device handle */ + pdev->pClass = pclass; + status = USBD_OK; + } + else + { + status = USBD_FAIL; + } + + return status; +} + +/** + * @brief USBD_Start + * Start the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev) +{ + + /* Start the low level driver */ + USBD_LL_Start(pdev); + + return USBD_OK; +} + +/** + * @brief USBD_Stop + * Stop the USB Device Core. + * @param pdev: Device Handle + * @retval USBD Status + */ +USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->pClass->DeInit(pdev, pdev->dev_config); + + /* Stop the low level driver */ + USBD_LL_Stop(pdev); + + return USBD_OK; +} + +/** +* @brief USBD_RunTestMode +* Launch test mode process +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + + +/** +* @brief USBD_SetClassConfig +* Configure device and start the interface +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status +*/ + +USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + USBD_StatusTypeDef ret = USBD_FAIL; + + if(pdev->pClass != NULL) + { + /* Set configuration and Start the Class*/ + if(pdev->pClass->Init(pdev, cfgidx) == 0) + { + ret = USBD_OK; + } + } + return ret; +} + +/** +* @brief USBD_ClrClassConfig +* Clear current configuration +* @param pdev: device instance +* @param cfgidx: configuration index +* @retval status: USBD_StatusTypeDef +*/ +USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) +{ + /* Clear configuration and Deinitialize the Class process*/ + pdev->pClass->DeInit(pdev, cfgidx); + return USBD_OK; +} + + +/** +* @brief USBD_SetupStage +* Handle the setup stage +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup) +{ + + USBD_ParseSetupRequest(&pdev->request, psetup); + + pdev->ep0_state = USBD_EP0_SETUP; + pdev->ep0_data_len = pdev->request.wLength; + + switch (pdev->request.bmRequest & 0x1F) + { + case USB_REQ_RECIPIENT_DEVICE: + USBD_StdDevReq (pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_INTERFACE: + USBD_StdItfReq(pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_ENDPOINT: + USBD_StdEPReq(pdev, &pdev->request); + break; + + default: + USBD_LL_StallEP(pdev , pdev->request.bmRequest & 0x80); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_DataOutStage +* Handle data OUT stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_out[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_OUT) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueRx (pdev, + pdata, + MIN(pep->rem_length ,pep->maxpacket)); + } + else + { + if((pdev->pClass->EP0_RxReady != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_RxReady(pdev); + } + USBD_CtlSendStatus(pdev); + } + } + } + else if((pdev->pClass->DataOut != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataOut(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_DataInStage +* Handle data in stage +* @param pdev: device instance +* @param epnum: endpoint index +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata) +{ + USBD_EndpointTypeDef *pep; + + if(epnum == 0) + { + pep = &pdev->ep_in[0]; + + if ( pdev->ep0_state == USBD_EP0_DATA_IN) + { + if(pep->rem_length > pep->maxpacket) + { + pep->rem_length -= pep->maxpacket; + + USBD_CtlContinueSendData (pdev, + pdata, + pep->rem_length); + } + else + { /* last packet is MPS multiple, so send ZLP packet */ + if((pep->total_length % pep->maxpacket == 0) && + (pep->total_length >= pep->maxpacket) && + (pep->total_length < pdev->ep0_data_len )) + { + + USBD_CtlContinueSendData(pdev , NULL, 0); + pdev->ep0_data_len = 0; + } + else + { + if((pdev->pClass->EP0_TxSent != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->EP0_TxSent(pdev); + } + USBD_CtlReceiveStatus(pdev); + } + } + } + if (pdev->dev_test_mode == 1) + { + USBD_RunTestMode(pdev); + pdev->dev_test_mode = 0; + } + } + else if((pdev->pClass->DataIn != NULL)&& + (pdev->dev_state == USBD_STATE_CONFIGURED)) + { + pdev->pClass->DataIn(pdev, epnum); + } + return USBD_OK; +} + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) +{ + /* Open EP0 OUT */ + USBD_LL_OpenEP(pdev, + 0x00, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE; + + /* Open EP0 IN */ + USBD_LL_OpenEP(pdev, + 0x80, + USBD_EP_TYPE_CTRL, + USB_MAX_EP0_SIZE); + + pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE; + /* Upon Reset call usr call back */ + pdev->dev_state = USBD_STATE_DEFAULT; + + if (pdev->pClassData) + pdev->pClass->DeInit(pdev, pdev->dev_config); + + + return USBD_OK; +} + + + + +/** +* @brief USBD_LL_Reset +* Handle Reset event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed) +{ + pdev->dev_speed = speed; + return USBD_OK; +} + +/** +* @brief USBD_Suspend +* Handle Suspend event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev) +{ + pdev->dev_old_state = pdev->dev_state; + pdev->dev_state = USBD_STATE_SUSPENDED; + return USBD_OK; +} + +/** +* @brief USBD_Resume +* Handle Resume event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev) +{ + pdev->dev_state = pdev->dev_old_state; + return USBD_OK; +} + +/** +* @brief USBD_SOF +* Handle SOF event +* @param pdev: device instance +* @retval status +*/ + +USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev) +{ + if(pdev->dev_state == USBD_STATE_CONFIGURED) + { + if(pdev->pClass->SOF != NULL) + { + pdev->pClass->SOF(pdev); + } + } + return USBD_OK; +} + +/** +* @brief USBD_IsoINIncomplete +* Handle iso in incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_IsoOUTIncomplete +* Handle iso out incomplete event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevConnected +* Handle device connection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev) +{ + return USBD_OK; +} + +/** +* @brief USBD_DevDisconnected +* Handle device disconnection event +* @param pdev: device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev) +{ + /* Free Class Resources */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->pClass->DeInit(pdev, pdev->dev_config); + + return USBD_OK; +} +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ctlreq.c new file mode 100755 index 0000000..f25f252 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ctlreq.c @@ -0,0 +1,740 @@ +/** + ****************************************************************************** + * @file usbd_req.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the standard USB requests following chapter 9. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ctlreq.h" +#include "usbd_ioreq.h" + + +/** @addtogroup STM32_USBD_STATE_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_REQ + * @brief USB standard requests module + * @{ + */ + +/** @defgroup USBD_REQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_FunctionPrototypes + * @{ + */ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req); + +static uint8_t USBD_GetLen(uint8_t *buf); + +/** + * @} + */ + + +/** @defgroup USBD_REQ_Private_Functions + * @{ + */ + + +/** +* @brief USBD_StdDevReq +* Handle standard usb device requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (req->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + + USBD_GetDescriptor (pdev, req) ; + break; + + case USB_REQ_SET_ADDRESS: + USBD_SetAddress(pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + USBD_SetConfig (pdev , req); + break; + + case USB_REQ_GET_CONFIGURATION: + USBD_GetConfig (pdev , req); + break; + + case USB_REQ_GET_STATUS: + USBD_GetStatus (pdev , req); + break; + + + case USB_REQ_SET_FEATURE: + USBD_SetFeature (pdev , req); + break; + + case USB_REQ_CLEAR_FEATURE: + USBD_ClrFeature (pdev , req); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + + return ret; +} + +/** +* @brief USBD_StdItfReq +* Handle standard usb interface requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdItfReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + USBD_StatusTypeDef ret = USBD_OK; + + switch (pdev->dev_state) + { + case USBD_STATE_CONFIGURED: + + if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) + { + pdev->pClass->Setup (pdev, req); + + if((req->wLength == 0)&& (ret == USBD_OK)) + { + USBD_CtlSendStatus(pdev); + } + } + else + { + USBD_CtlError(pdev , req); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + return USBD_OK; +} + +/** +* @brief USBD_StdEPReq +* Handle standard usb endpoint requests +* @param pdev: USB OTG device instance +* @param req: usb request +* @retval status +*/ +USBD_StatusTypeDef USBD_StdEPReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) +{ + + uint8_t ep_addr; + USBD_StatusTypeDef ret = USBD_OK; + USBD_EndpointTypeDef *pep; + ep_addr = LOBYTE(req->wIndex); + + switch (req->bRequest) + { + + case USB_REQ_SET_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + + } + } + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_CLEAR_FEATURE : + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr != 0x00) && (ep_addr != 0x80)) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_EP_HALT) + { + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_ClearStallEP(pdev , ep_addr); + pdev->pClass->Setup (pdev, req); + } + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + case USB_REQ_GET_STATUS: + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if ((ep_addr & 0x7F) != 0x00) + { + USBD_LL_StallEP(pdev , ep_addr); + } + break; + + case USBD_STATE_CONFIGURED: + pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\ + &pdev->ep_out[ep_addr & 0x7F]; + if(USBD_LL_IsStallEP(pdev, ep_addr)) + { + pep->status = 0x0001; + } + else + { + pep->status = 0x0000; + } + + USBD_CtlSendData (pdev, + (uint8_t *)&pep->status, + 2); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + break; + + default: + break; + } + return ret; +} +/** +* @brief USBD_GetDescriptor +* Handle Get Descriptor requests +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint16_t len; + uint8_t *pbuf; + + + switch (req->wValue >> 8) + { + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->pDesc->GetDeviceDescriptor(pdev, &len); + break; + + case USB_DESC_TYPE_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + else + { + pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + } + break; + + case USB_DESC_TYPE_STRING: + pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len); + if (pbuf == NULL) { + USBD_CtlError(pdev, req); + return; + } + break; + + case USB_DESC_TYPE_DEVICE_QUALIFIER: + + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(pdev, &len); + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: + if(pdev->dev_speed == USBD_SPEED_HIGH ) + { + pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(pdev, &len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + } + else + { + USBD_CtlError(pdev , req); + return; + } + + default: + USBD_CtlError(pdev , req); + return; + } + + if((len != 0)&& (req->wLength != 0)) + { + + len = MIN(len , req->wLength); + + USBD_CtlSendData (pdev, + pbuf, + len); + } + +} + +/** +* @brief USBD_SetAddress +* Set device address +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetAddress(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + uint8_t dev_addr; + + if ((req->wIndex == 0) && (req->wLength == 0)) + { + dev_addr = (uint8_t)(req->wValue) & 0x7F; + + if (pdev->dev_state == USBD_STATE_CONFIGURED) + { + USBD_CtlError(pdev , req); + } + else + { + pdev->dev_address = dev_addr; + USBD_LL_SetUSBAddress(pdev, dev_addr); + USBD_CtlSendStatus(pdev); + + if (dev_addr != 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + } + else + { + pdev->dev_state = USBD_STATE_DEFAULT; + } + } + } + else + { + USBD_CtlError(pdev , req); + } +} + +/** +* @brief USBD_SetConfig +* Handle Set device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + uint8_t cfgidx; + + cfgidx = (uint8_t)(req->wValue); + + if (cfgidx > USBD_MAX_NUM_CONFIGURATION ) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + if (cfgidx) + { + pdev->dev_config = cfgidx; + pdev->dev_state = USBD_STATE_CONFIGURED; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + case USBD_STATE_CONFIGURED: + if (cfgidx == 0) + { + pdev->dev_state = USBD_STATE_ADDRESSED; + pdev->dev_config = cfgidx; + USBD_ClrClassConfig(pdev , cfgidx); + USBD_CtlSendStatus(pdev); + + } + else if (cfgidx != pdev->dev_config) + { + /* Clear old configuration */ + USBD_ClrClassConfig(pdev , pdev->dev_config); + + /* set new configuration */ + pdev->dev_config = cfgidx; + if(USBD_SetClassConfig(pdev , cfgidx) == USBD_FAIL) + { + USBD_CtlError(pdev , req); + return; + } + USBD_CtlSendStatus(pdev); + } + else + { + USBD_CtlSendStatus(pdev); + } + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetConfig +* Handle Get device configuration request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetConfig(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wLength != 1) + { + USBD_CtlError(pdev , req); + } + else + { + switch (pdev->dev_state ) + { + case USBD_STATE_ADDRESSED: + pdev->dev_default_config = 0; + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_default_config, + 1); + break; + + case USBD_STATE_CONFIGURED: + + USBD_CtlSendData (pdev, + (uint8_t *)&pdev->dev_config, + 1); + break; + + default: + USBD_CtlError(pdev , req); + break; + } + } +} + +/** +* @brief USBD_GetStatus +* Handle Get Status request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_GetStatus(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + +#if ( USBD_SELF_POWERED == 1) + pdev->dev_config_status = USB_CONFIG_SELF_POWERED; +#else + pdev->dev_config_status = 0; +#endif + + if (pdev->dev_remote_wakeup) + { + pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; + } + + USBD_CtlSendData (pdev, + (uint8_t *)& pdev->dev_config_status, + 2); + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + + +/** +* @brief USBD_SetFeature +* Handle Set device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_SetFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 1; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + +} + + +/** +* @brief USBD_ClrFeature +* Handle clear device feature request +* @param pdev: device instance +* @param req: usb request +* @retval status +*/ +static void USBD_ClrFeature(USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + switch (pdev->dev_state) + { + case USBD_STATE_ADDRESSED: + case USBD_STATE_CONFIGURED: + if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + pdev->dev_remote_wakeup = 0; + pdev->pClass->Setup (pdev, req); + USBD_CtlSendStatus(pdev); + } + break; + + default : + USBD_CtlError(pdev , req); + break; + } +} + +/** +* @brief USBD_ParseSetupRequest +* Copy buffer into setup structure +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata) +{ + req->bmRequest = *(uint8_t *) (pdata); + req->bRequest = *(uint8_t *) (pdata + 1); + req->wValue = SWAPBYTE (pdata + 2); + req->wIndex = SWAPBYTE (pdata + 4); + req->wLength = SWAPBYTE (pdata + 6); + +} + +/** +* @brief USBD_CtlError +* Handle USB low level Error +* @param pdev: device instance +* @param req: usb request +* @retval None +*/ + +void USBD_CtlError( USBD_HandleTypeDef *pdev , + USBD_SetupReqTypedef *req) +{ + USBD_LL_StallEP(pdev , 0x80); + USBD_LL_StallEP(pdev , 0); +} + + +/** + * @brief USBD_GetString + * Convert Ascii string into unicode one + * @param desc : descriptor buffer + * @param unicode : Formatted string buffer (unicode) + * @param len : descriptor length + * @retval None + */ +void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0; + + if (desc != NULL) + { + *len = USBD_GetLen(desc) * 2 + 2; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') + { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00; + } + } +} + +/** + * @brief USBD_GetLen + * return the string length + * @param buf : pointer to the ascii string buffer + * @retval string length + */ +static uint8_t USBD_GetLen(uint8_t *buf) +{ + uint8_t len = 0; + + while (*buf != '\0') + { + len++; + buf++; + } + + return len; +} +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ioreq.c b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ioreq.c new file mode 100755 index 0000000..aab59fc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbdev/core/src/usbd_ioreq.c @@ -0,0 +1,236 @@ +/** + ****************************************************************************** + * @file usbd_ioreq.c + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief This file provides the IO requests APIs for control endpoints. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_ioreq.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + + +/** @defgroup USBD_IOREQ + * @brief control I/O requests module + * @{ + */ + +/** @defgroup USBD_IOREQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBD_IOREQ_Private_Functions + * @{ + */ + +/** +* @brief USBD_CtlSendData +* send data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = len; + pdev->ep_in[0].rem_length = len; + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueSendData +* continue sending data on the ctl pipe +* @param pdev: device instance +* @param buff: pointer to data buffer +* @param len: length of data to be sent +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueSendData (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Start the next transfer */ + USBD_LL_Transmit (pdev, 0x00, pbuf, len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlPrepareRx +* receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlPrepareRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_OUT; + pdev->ep_out[0].total_length = len; + pdev->ep_out[0].rem_length = len; + /* Start the transfer */ + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + + return USBD_OK; +} + +/** +* @brief USBD_CtlContinueRx +* continue receive data on the ctl pipe +* @param pdev: USB OTG device instance +* @param buff: pointer to data buffer +* @param len: length of data to be received +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlContinueRx (USBD_HandleTypeDef *pdev, + uint8_t *pbuf, + uint16_t len) +{ + + USBD_LL_PrepareReceive (pdev, + 0, + pbuf, + len); + return USBD_OK; +} +/** +* @brief USBD_CtlSendStatus +* send zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlSendStatus (USBD_HandleTypeDef *pdev) +{ + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + /* Start the transfer */ + USBD_LL_Transmit (pdev, 0x00, NULL, 0); + + return USBD_OK; +} + +/** +* @brief USBD_CtlReceiveStatus +* receive zero lzngth packet on the ctl pipe +* @param pdev: USB OTG device instance +* @retval status +*/ +USBD_StatusTypeDef USBD_CtlReceiveStatus (USBD_HandleTypeDef *pdev) +{ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_OUT; + + /* Start the transfer */ + USBD_LL_PrepareReceive ( pdev, + 0, + NULL, + 0); + + return USBD_OK; +} + + +/** +* @brief USBD_GetRxCount +* returns the received data length +* @param pdev: USB OTG device instance +* epnum: endpoint index +* @retval Rx Data blength +*/ +uint16_t USBD_GetRxCount (USBD_HandleTypeDef *pdev , uint8_t ep_addr) +{ + return USBD_LL_GetRxDataSize(pdev, ep_addr); +} + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h new file mode 100755 index 0000000..8cee530 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Inc/usbh_audio.h @@ -0,0 +1,581 @@ +/** + ****************************************************************************** + * @file usbh_audio.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_audio.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_AUDIO_H +#define __USBH_AUDIO_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_AUDIO_CLASS + * @{ + */ + +/** @defgroup USBH_AUDIO_CORE + * @brief This file is the Header file for usbh_audio.c + * @{ + */ + + +/** @defgroup USBH_AUDIO_CORE_Exported_Types + * @{ + */ + +/* States for AUDIO State Machine */ +typedef enum +{ + AUDIO_INIT = 0, + AUDIO_IDLE, + AUDIO_CS_REQUESTS, + AUDIO_SET_DEFAULT_FEATURE_UNIT, + AUDIO_SET_INTERFACE, + AUDIO_SET_STREAMING_INTERFACE, + AUDIO_SET_CUR1, + AUDIO_GET_MIN, + AUDIO_GET_MAX, + AUDIO_GET_RES, + AUDIO_GET_CUR1, + AUDIO_SET_CUR2, + AUDIO_GET_CUR2, + AUDIO_SET_CUR3, + AUDIO_SET_INTERFACE0, + AUDIO_SET_INTERFACE1, + AUDIO_SET_INTERFACE2, + AUDIO_ISOC_OUT, + AUDIO_ISOC_IN, + AUDIO_ISOC_POLL, + AUDIO_ERROR, +} +AUDIO_StateTypeDef; + +typedef enum +{ + AUDIO_REQ_INIT = 1, + AUDIO_REQ_IDLE, + AUDIO_REQ_SET_DEFAULT_IN_INTERFACE, + AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE, + AUDIO_REQ_SET_IN_INTERFACE, + AUDIO_REQ_SET_OUT_INTERFACE, + AUDIO_REQ_CS_REQUESTS, +} +AUDIO_ReqStateTypeDef; + +typedef enum +{ + AUDIO_REQ_SET_VOLUME = 1, + AUDIO_REQ_SET_MUTE, + AUDIO_REQ_GET_CURR_VOLUME, + AUDIO_REQ_GET_MIN_VOLUME, + AUDIO_REQ_GET_MAX_VOLUME, + AUDIO_REQ_GET_VOLUME, + AUDIO_REQ_GET_RESOLUTION, + AUDIO_REQ_CS_IDLE, +} +AUDIO_CSReqStateTypeDef; + +typedef enum +{ + AUDIO_PLAYBACK_INIT = 1, + AUDIO_PLAYBACK_SET_EP, + AUDIO_PLAYBACK_SET_EP_FREQ, + AUDIO_PLAYBACK_PLAY, + AUDIO_PLAYBACK_IDLE, +} +AUDIO_PlayStateTypeDef; + +typedef enum +{ + VOLUME_UP = 1, + VOLUME_DOWN = 2, +} +AUDIO_VolumeCtrlTypeDef; + +typedef enum +{ + AUDIO_CONTROL_INIT = 1, + AUDIO_CONTROL_CHANGE, + AUDIO_CONTROL_IDLE, + AUDIO_CONTROL_VOLUME_UP, + AUDIO_CONTROL_VOLUME_DOWN, +} +AUDIO_ControlStateTypeDef; + + +typedef enum +{ + AUDIO_DATA_START_OUT = 1, + AUDIO_DATA_OUT, +} +AUDIO_ProcessingTypeDef; + +/* Structure for AUDIO process */ +typedef struct +{ + uint8_t Channels; + uint8_t Bits; + uint32_t SampleRate; +} +AUDIO_FormatTypeDef; + +typedef struct +{ + uint8_t Ep; + uint16_t EpSize; + uint8_t AltSettings; + uint8_t interface; + uint8_t valid; + uint16_t Poll; +} +AUDIO_STREAMING_IN_HandleTypeDef; + +typedef struct +{ + uint8_t Ep; + uint16_t EpSize; + uint8_t AltSettings; + uint8_t interface; + uint8_t valid; + uint16_t Poll; +} +AUDIO_STREAMING_OUT_HandleTypeDef; + + +typedef struct +{ + uint8_t mute; + uint32_t volumeMin; + uint32_t volumeMax; + uint32_t volume; + uint32_t resolution; +} +AUDIO_ControlAttributeTypeDef; + +typedef struct +{ + + uint8_t Ep; + uint16_t EpSize; + uint8_t interface; + uint8_t AltSettings; + uint8_t supported; + + uint8_t Pipe; + uint8_t Poll; + uint32_t timer ; + + uint8_t asociated_as; + uint8_t asociated_mixer; + uint8_t asociated_selector; + uint8_t asociated_feature; + uint8_t asociated_terminal; + uint8_t asociated_channels; + + uint32_t frequency; + uint8_t *buf; + uint8_t *cbuf; + uint32_t partial_ptr; + + uint32_t global_ptr; + uint16_t frame_length; + uint32_t total_length; + + AUDIO_ControlAttributeTypeDef attribute; +} +AUDIO_InterfaceStreamPropTypeDef; + +typedef struct +{ + + uint8_t Ep; + uint16_t EpSize; + uint8_t interface; + uint8_t supported; + + uint8_t Pipe; + uint8_t Poll; + uint32_t timer ; +} +AUDIO_InterfaceControlPropTypeDef; + + +#define AUDIO_MAX_AUDIO_STD_INTERFACE 0x05 +#define AUDIO_MAX_FREQ_SUPPORTED 0x05 +#define AUDIO_MAX_STREAMING_INTERFACE 0x05 +#define AUDIO_MAX_NUM_IN_TERMINAL 0x04 +#define AUDIO_MAX_NUM_OUT_TERMINAL 0x04 +#define AUDIO_MAX_NUM_FEATURE_UNIT 0x04 +#define AUDIO_MAX_NUM_MIXER_UNIT 0x04 +#define AUDIO_MAX_NUM_SELECTOR_UNIT 0x04 + +#define HEADPHONE_SUPPORTED 0x01 +#define MICROPHONE_SUPPORTED 0x02 +#define HEADSET_SUPPORTED 0x03 + + +/*Class-Specific AS(Audio Streaming) Interface Descriptor*/ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalLink; + uint8_t bDelay; + uint8_t wFormatTag[2]; +} +AUDIO_ASGeneralDescTypeDef; + +/*Class-Specific AS(Audio Streaming) Format Type Descriptor*/ +typedef struct +{ + uint8_t bLength; /*At to be deside*/ + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bFormatType; + uint8_t bNrChannels; + uint8_t bSubframeSize; + uint8_t bBitResolution; + uint8_t bSamFreqType; + uint8_t tSamFreq[][3]; +} +AUDIO_ASFormatTypeDescTypeDef; + +/*Class-Specific AS(Audio Streaming) Interface Descriptor*/ +typedef struct +{ + AUDIO_ASGeneralDescTypeDef *GeneralDesc; + AUDIO_ASFormatTypeDescTypeDef *FormatTypeDesc; +} +AUDIO_ASDescTypeDef; + +/* 4.3.2 Class-Specific AC Interface Descriptor */ + +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bcdADC[2]; + uint8_t wTotalLength[2]; + uint8_t bInCollection; + uint8_t baInterfaceNr[]; +} +AUDIO_HeaderDescTypeDef; + +/* 4.3.2.1 Input Terminal Descriptor */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalID; + uint8_t wTerminalType[2]; + uint8_t bAssocTerminal; + uint8_t bNrChannels; + uint8_t wChannelConfig[2]; + uint8_t iChannelNames; + uint8_t iTerminal; +} +AUDIO_ITDescTypeDef; + +/* 4.3.2.2 Output Terminal Descriptor */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalID; + uint8_t wTerminalType[2]; + uint8_t bAssocTerminal; + uint8_t bSourceID; + uint8_t iTerminal; +} +AUDIO_OTDescTypeDef; + +/* 4.3.2.3 Feature Descriptor */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bUnitID; + uint8_t bSourceID; + uint8_t bControlSize; + uint8_t bmaControls[][2]; +} +AUDIO_FeatureDescTypeDef; + + +/* 4.3.2.3 Feature Descriptor */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bUnitID; + uint8_t bNrInPins; + uint8_t bSourceID0; + uint8_t bSourceID1; + uint8_t bNrChannels; + uint8_t bmChannelsConfig[2]; + uint8_t iChannelsNames; + uint8_t bmaControls; + uint8_t iMixer; +} +AUDIO_MixerDescTypeDef; + + + +/* 4.3.2.3 Feature Descriptor */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bUnitID; + uint8_t bNrInPins; + uint8_t bSourceID0; + uint8_t iSelector; +} +AUDIO_SelectorDescTypeDef; + +/*Class-Specific AC(Audio Control) Interface Descriptor*/ +typedef struct +{ + AUDIO_HeaderDescTypeDef *HeaderDesc; + AUDIO_ITDescTypeDef *InputTerminalDesc [AUDIO_MAX_NUM_IN_TERMINAL]; + AUDIO_OTDescTypeDef *OutputTerminalDesc[AUDIO_MAX_NUM_OUT_TERMINAL]; + AUDIO_FeatureDescTypeDef *FeatureUnitDesc [AUDIO_MAX_NUM_FEATURE_UNIT]; + AUDIO_MixerDescTypeDef *MixerUnitDesc [AUDIO_MAX_NUM_MIXER_UNIT]; + AUDIO_SelectorDescTypeDef *SelectorUnitDesc [AUDIO_MAX_NUM_SELECTOR_UNIT]; +} +AUDIO_ACDescTypeDef; + +/*Class-Specific AC : Global descriptor*/ + +typedef struct +{ + AUDIO_ACDescTypeDef cs_desc; /* Only one control descriptor*/ + AUDIO_ASDescTypeDef as_desc[AUDIO_MAX_STREAMING_INTERFACE]; + + uint16_t ASNum; + uint16_t InputTerminalNum; + uint16_t OutputTerminalNum; + uint16_t FeatureUnitNum; + uint16_t SelectorUnitNum; + uint16_t MixerUnitNum; +} +AUDIO_ClassSpecificDescTypedef; + + +typedef struct _AUDIO_Process +{ + AUDIO_ReqStateTypeDef req_state; + AUDIO_CSReqStateTypeDef cs_req_state; + AUDIO_PlayStateTypeDef play_state; + AUDIO_ControlStateTypeDef control_state; + AUDIO_ProcessingTypeDef processing_state; + + AUDIO_STREAMING_IN_HandleTypeDef stream_in[AUDIO_MAX_AUDIO_STD_INTERFACE]; + AUDIO_STREAMING_OUT_HandleTypeDef stream_out[AUDIO_MAX_AUDIO_STD_INTERFACE]; + AUDIO_ClassSpecificDescTypedef class_desc; + + AUDIO_InterfaceStreamPropTypeDef headphone; + AUDIO_InterfaceStreamPropTypeDef microphone; + AUDIO_InterfaceControlPropTypeDef control; + uint16_t mem [8]; + uint8_t temp_feature; + uint8_t temp_channels; +} +AUDIO_HandleTypeDef; + +/** + * @} + */ + +/** @defgroup USBH_AUDIO_CORE_Exported_Defines + * @{ + */ + + +/*Audio Interface Subclass Codes*/ +#define AC_CLASS 0x01 + +/* A.2 Audio Interface Subclass Codes */ +#define USB_SUBCLASS_AUDIOCONTROL 0x01 +#define USB_SUBCLASS_AUDIOSTREAMING 0x02 +#define USB_SUBCLASS_MIDISTREAMING 0x03 + +#define USB_DESC_TYPE_CS_INTERFACE 0x24 +#define USB_DESC_TYPE_CS_ENDPOINT 0x25 + +/* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */ +#define UAC_HEADER 0x01 +#define UAC_INPUT_TERMINAL 0x02 +#define UAC_OUTPUT_TERMINAL 0x03 +#define UAC_MIXER_UNIT 0x04 +#define UAC_SELECTOR_UNIT 0x05 +#define UAC_FEATURE_UNIT 0x06 +#define UAC_PROCESSING_UNIT 0x07 +#define UAC_EXTENSION_UNIT 0x08 + +/*Audio Class-Specific Endpoint Descriptor Subtypes*/ +#define EP_CONTROL_UNDEFINED 0x00 +#define SAMPLING_FREQ_CONTROL 0x01 +#define PITCH_CONTROL 0x02 + +/*Feature unit control selector*/ +#define FU_CONTROL_UNDEFINED 0x00 +#define MUTE_CONTROL 0x01 +#define VOLUME_CONTROL 0x02 +#define BASS_CONTROL 0x03 +#define MID_CONTROL 0x04 +#define TREBLE_CONTROL 0x05 +#define GRAPHIC_EQUALIZER_CONTROL 0x06 +#define AUTOMATIC_GAIN_CONTROL 0x07 +#define DELAY_CONTROL 0x08 +#define BASS_BOOST_CONTROL 0x09 +#define LOUDNESS_CONTROL 0x0A + +/*Terminal control selector*/ +#define TE_CONTROL_UNDEFINED 0x00 +#define COPY_PROTECT_CONTROL 0x01 + + +/* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ +#define UAC_AS_GENERAL 0x01 +#define UAC_FORMAT_TYPE 0x02 +#define UAC_FORMAT_SPECIFIC 0x03 + +/* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ +#define UAC_EP_GENERAL 0x01 + +/* A.9 Audio Class-Specific Request Codes */ +#define UAC_SET_ 0x00 +#define UAC_GET_ 0x80 + +#define UAC__CUR 0x1 +#define UAC__MIN 0x2 +#define UAC__MAX 0x3 +#define UAC__RES 0x4 +#define UAC__MEM 0x5 + +#define UAC_SET_CUR (UAC_SET_ | UAC__CUR) +#define UAC_GET_CUR (UAC_GET_ | UAC__CUR) +#define UAC_SET_MIN (UAC_SET_ | UAC__MIN) +#define UAC_GET_MIN (UAC_GET_ | UAC__MIN) +#define UAC_SET_MAX (UAC_SET_ | UAC__MAX) +#define UAC_GET_MAX (UAC_GET_ | UAC__MAX) +#define UAC_SET_RES (UAC_SET_ | UAC__RES) +#define UAC_GET_RES (UAC_GET_ | UAC__RES) +#define UAC_SET_MEM (UAC_SET_ | UAC__MEM) +#define UAC_GET_MEM (UAC_GET_ | UAC__MEM) + +#define UAC_GET_STAT 0xff + +/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ +#define UAC_MS_HEADER 0x01 +#define UAC_MIDI_IN_JACK 0x02 +#define UAC_MIDI_OUT_JACK 0x03 + +/* MIDI - A.1 MS Class-Specific Endpoint Descriptor Subtypes */ +#define UAC_MS_GENERAL 0x01 + +/* Terminals - 2.1 USB Terminal Types */ +#define UAC_TERMINAL_UNDEFINED 0x100 +#define UAC_TERMINAL_STREAMING 0x101 +#define UAC_TERMINAL_VENDOR_SPEC 0x1FF + +/** + * @} + */ + +/** @defgroup USBH_AUDIO_CORE_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_AUDIO_CORE_Exported_Variables + * @{ + */ +extern USBH_ClassTypeDef AUDIO_Class; +#define USBH_AUDIO_CLASS &AUDIO_Class +/** + * @} + */ + +/** @defgroup USBH_AUDIO_CORE_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_AUDIO_SetFrequency (USBH_HandleTypeDef *phost, + uint16_t sample_rate, + uint8_t channel_num, + uint8_t data_width); + +USBH_StatusTypeDef USBH_AUDIO_Play (USBH_HandleTypeDef *phost, uint8_t *buf, uint32_t length); +USBH_StatusTypeDef USBH_AUDIO_Stop (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_AUDIO_Suspend (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_AUDIO_Resume (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_AUDIO_SetVolume (USBH_HandleTypeDef *phost, AUDIO_VolumeCtrlTypeDef volume_ctl); +USBH_StatusTypeDef USBH_AUDIO_ChangeOutBuffer (USBH_HandleTypeDef *phost, uint8_t *buf); +int32_t USBH_AUDIO_GetOutOffset (USBH_HandleTypeDef *phost); + +void USBH_AUDIO_FrequencySet(USBH_HandleTypeDef *phost); +/** + * @} + */ + + +#endif /* __USBH_AUDIO_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c new file mode 100755 index 0000000..b9677b6 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/AUDIO/Src/usbh_audio.c @@ -0,0 +1,1994 @@ +/** + ****************************************************************************** + * @file usbh_audio.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the AC Layer Handlers for USB Host AC class. + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_audio.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_AUDIO_CLASS + * @{ + */ + +/** @defgroup USBH_AUDIO_CORE + * @brief This file includes HID Layer Handlers for USB Host HID class. + * @{ + */ + +/** @defgroup USBH_AUDIO_CORE_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_AUDIO_CORE_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_AUDIO_CORE_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_AUDIO_CORE_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_AUDIO_CORE_Private_FunctionPrototypes + * @{ + */ + +static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_Process(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_SOFProcess(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost, + uint8_t feature, + uint8_t channel); + +static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost); +int32_t USBH_AUDIO_FindLinkedUnitIN(USBH_HandleTypeDef *phost, uint8_t UnitID); +int32_t USBH_AUDIO_FindLinkedUnitOUT(USBH_HandleTypeDef *phost, uint8_t UnitID); + + + +static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc, + uint8_t ac_subclass, + uint8_t *pdesc); + + +static USBH_StatusTypeDef USBH_AUDIO_Transmit (USBH_HandleTypeDef *phost); + + +static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length); + +static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length); + +static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length); + +static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length); + +static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length); + +static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost, + uint8_t Ep, + uint8_t *buff); + +static USBH_StatusTypeDef AUDIO_SetVolume (USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume); + +static USBH_StatusTypeDef USBH_AUDIO_InputStream (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_OutputStream (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_Control (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute (USBH_HandleTypeDef *phost, uint8_t attrib); +static int32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID); + +USBH_ClassTypeDef AUDIO_Class = +{ + "AUDIO", + AC_CLASS, + USBH_AUDIO_InterfaceInit, + USBH_AUDIO_InterfaceDeInit, + USBH_AUDIO_ClassRequest, + USBH_AUDIO_Process, + USBH_AUDIO_SOFProcess, + NULL, +}; + +/** + * @} + */ + +/** @defgroup USBH_AUDIO_CORE_Private_Functions + * @{ + */ + +/** + * @brief USBH_AUDIO_InterfaceInit + * The function init the Audio class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_FAIL ; + USBH_StatusTypeDef out_status, in_status ; + AUDIO_HandleTypeDef *AUDIO_Handle; + uint8_t interface, index; + uint16_t ep_size_out = 0; + uint16_t ep_size_in = 0; + + interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0x00); + + if(interface == 0xFF) /* Not Valid Interface */ + { + USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name); + status = USBH_FAIL; + } + else + { + + + phost->pActiveClass->pData = (AUDIO_HandleTypeDef *)USBH_malloc (sizeof(AUDIO_HandleTypeDef)); + AUDIO_Handle = phost->pActiveClass->pData; + USBH_memset(AUDIO_Handle, 0, sizeof(AUDIO_HandleTypeDef)); + + + /* 1st Step: Find Audio Interfaces */ + out_status = USBH_AUDIO_FindAudioStreamingIN (phost); + + in_status = USBH_AUDIO_FindAudioStreamingOUT(phost); + + if((out_status == USBH_FAIL) && (in_status == USBH_FAIL)) + { + USBH_DbgLog ("%s class configuration not supported.", phost->pActiveClass->Name); + } + else + { + /* 2nd Step: Select Audio Streaming Interfaces with largest endpoint size : default behavior*/ + for (index = 0; index < AUDIO_MAX_AUDIO_STD_INTERFACE; index ++) + { + if( AUDIO_Handle->stream_out[index].valid == 1) + { + if(ep_size_out < AUDIO_Handle->stream_out[index].EpSize) + { + ep_size_out = AUDIO_Handle->stream_out[index].EpSize; + AUDIO_Handle->headphone.interface = AUDIO_Handle->stream_out[index].interface; + AUDIO_Handle->headphone.AltSettings = AUDIO_Handle->stream_out[index].AltSettings; + AUDIO_Handle->headphone.Ep = AUDIO_Handle->stream_out[index].Ep; + AUDIO_Handle->headphone.EpSize = AUDIO_Handle->stream_out[index].EpSize; + AUDIO_Handle->headphone.Poll = AUDIO_Handle->stream_out[index].Poll; + AUDIO_Handle->headphone.supported = 1; + } + } + + if( AUDIO_Handle->stream_in[index].valid == 1) + { + if(ep_size_in < AUDIO_Handle->stream_in[index].EpSize) + { + ep_size_in = AUDIO_Handle->stream_in[index].EpSize; + AUDIO_Handle->microphone.interface = AUDIO_Handle->stream_in[index].interface; + AUDIO_Handle->microphone.AltSettings = AUDIO_Handle->stream_in[index].AltSettings; + AUDIO_Handle->microphone.Ep = AUDIO_Handle->stream_in[index].Ep; + AUDIO_Handle->microphone.EpSize = AUDIO_Handle->stream_in[index].EpSize; + AUDIO_Handle->microphone.Poll = AUDIO_Handle->stream_out[index].Poll; + AUDIO_Handle->microphone.supported = 1; + } + } + } + + if(USBH_AUDIO_FindHIDControl(phost) == USBH_OK) + { + AUDIO_Handle->control.supported = 1; + } + + /* 3rd Step: Find and Parse Audio interfaces */ + USBH_AUDIO_ParseCSDescriptors (phost); + + + /* 4th Step: Open the Audio streaming pipes*/ + if(AUDIO_Handle->headphone.supported == 1) + { + USBH_AUDIO_BuildHeadphonePath (phost); + + AUDIO_Handle->headphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->headphone.Ep); + + /* Open pipe for IN endpoint */ + USBH_OpenPipe (phost, + AUDIO_Handle->headphone.Pipe, + AUDIO_Handle->headphone.Ep, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_ISOC, + AUDIO_Handle->headphone.EpSize); + + USBH_LL_SetToggle (phost, AUDIO_Handle->headphone.Pipe, 0); + + } + + if(AUDIO_Handle->microphone.supported == 1) + { + USBH_AUDIO_BuildMicrophonePath (phost); + AUDIO_Handle->microphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->microphone.Ep); + + /* Open pipe for IN endpoint */ + USBH_OpenPipe (phost, + AUDIO_Handle->microphone.Pipe, + AUDIO_Handle->microphone.Ep, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_ISOC, + AUDIO_Handle->microphone.EpSize); + + USBH_LL_SetToggle (phost, AUDIO_Handle->microphone.Pipe, 0); + } + + if(AUDIO_Handle->control.supported == 1) + { + AUDIO_Handle->control.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->control.Ep); + + /* Open pipe for IN endpoint */ + USBH_OpenPipe (phost, + AUDIO_Handle->control.Pipe, + AUDIO_Handle->control.Ep, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_INTR, + AUDIO_Handle->control.EpSize); + + USBH_LL_SetToggle (phost, AUDIO_Handle->control.Pipe, 0); + + } + + AUDIO_Handle->req_state = AUDIO_REQ_INIT; + AUDIO_Handle->control_state = AUDIO_CONTROL_INIT; + + status = USBH_OK; + } + } + return status; +} + + + +/** + * @brief USBH_AUDIO_InterfaceDeInit + * The function DeInit the Pipes used for the Audio class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit (USBH_HandleTypeDef *phost) +{ + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + + if(AUDIO_Handle->microphone.Pipe != 0x00) + { + USBH_ClosePipe (phost, AUDIO_Handle->microphone.Pipe); + USBH_FreePipe (phost, AUDIO_Handle->microphone.Pipe); + AUDIO_Handle->microphone.Pipe = 0; /* Reset the pipe as Free */ + } + + if( AUDIO_Handle->headphone.Pipe != 0x00) + { + USBH_ClosePipe(phost, AUDIO_Handle->headphone.Pipe); + USBH_FreePipe (phost, AUDIO_Handle->headphone.Pipe); + AUDIO_Handle->headphone.Pipe = 0; /* Reset the pipe as Free */ + } + + if( AUDIO_Handle->control.Pipe != 0x00) + { + USBH_ClosePipe(phost, AUDIO_Handle->control.Pipe); + USBH_FreePipe (phost, AUDIO_Handle->control.Pipe); + AUDIO_Handle->control.Pipe = 0; /* Reset the pipe as Free */ + } + + if(phost->pActiveClass->pData) + { + USBH_free (phost->pActiveClass->pData); + phost->pActiveClass->pData = 0; + } + return USBH_OK ; +} + +/** + * @brief USBH_AUDIO_ClassRequest + * The function is responsible for handling Standard requests + * for Audio class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost) +{ + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef req_status = USBH_BUSY; + + /* Switch AUDIO REQ state machine */ + switch (AUDIO_Handle->req_state) + { + case AUDIO_REQ_INIT: + case AUDIO_REQ_SET_DEFAULT_IN_INTERFACE: + if(AUDIO_Handle->microphone.supported == 1) + { + req_status = USBH_SetInterface(phost, + AUDIO_Handle->microphone.interface, + 0); + + if(req_status == USBH_OK) + { + AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE; + } + + } + else + { + AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE: + if(AUDIO_Handle->headphone.supported == 1) + { + req_status = USBH_SetInterface(phost, + AUDIO_Handle->headphone.interface, + 0); + + if(req_status == USBH_OK) + { + AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS; + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME; + + AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature; + AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels; + } + } + else + { + AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS; + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case AUDIO_REQ_CS_REQUESTS: + if(USBH_AUDIO_HandleCSRequest (phost) == USBH_OK) + { + AUDIO_Handle->req_state = AUDIO_REQ_SET_IN_INTERFACE; + } + break; + + case AUDIO_REQ_SET_IN_INTERFACE: + if(AUDIO_Handle->microphone.supported == 1) + { + req_status = USBH_SetInterface(phost, + AUDIO_Handle->microphone.interface, + AUDIO_Handle->microphone.AltSettings); + + if(req_status == USBH_OK) + { + AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE; + } + } + else + { + AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + case AUDIO_REQ_SET_OUT_INTERFACE: + if(AUDIO_Handle->headphone.supported == 1) + { + req_status = USBH_SetInterface(phost, + AUDIO_Handle->headphone.interface, + AUDIO_Handle->headphone.AltSettings); + + if(req_status == USBH_OK) + { + AUDIO_Handle->req_state = AUDIO_REQ_IDLE; + } + + } + else + { + AUDIO_Handle->req_state = AUDIO_REQ_IDLE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + case AUDIO_REQ_IDLE: + AUDIO_Handle->play_state = AUDIO_PLAYBACK_INIT; + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + status = USBH_OK; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + default: + break; + } + return status; +} + +/** + * @brief USBH_AUDIO_CSRequest + * The function is responsible for handling AC Specific requests for a specific feature and channel + * for Audio class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel) +{ + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef req_status = USBH_BUSY; + + /* Switch AUDIO REQ state machine */ + switch (AUDIO_Handle->cs_req_state) + { + case AUDIO_REQ_GET_VOLUME: + req_status = USBH_AC_GetCur(phost, + UAC_FEATURE_UNIT, /* subtype */ + feature, /* feature */ + VOLUME_CONTROL, /* Selector */ + channel, /* channel */ + 0x02); /* length */ + if(req_status != USBH_BUSY) + { + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MIN_VOLUME; + AUDIO_Handle->headphone.attribute.volume = LE16(&(AUDIO_Handle->mem[0])); + } + break; + + case AUDIO_REQ_GET_MIN_VOLUME: + req_status = USBH_AC_GetMin(phost, + UAC_FEATURE_UNIT, /* subtype */ + feature, /* feature */ + VOLUME_CONTROL, /* Selector */ + channel, /* channel */ + 0x02); /* length */ + if(req_status != USBH_BUSY) + { + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MAX_VOLUME; + AUDIO_Handle->headphone.attribute.volumeMin = LE16(&AUDIO_Handle->mem[0]); + } + break; + + case AUDIO_REQ_GET_MAX_VOLUME: + req_status = USBH_AC_GetMax(phost, + UAC_FEATURE_UNIT, /* subtype */ + feature, /* feature */ + VOLUME_CONTROL, /* Selector */ + channel, /* channel */ + 0x02); /* length */ + if(req_status != USBH_BUSY) + { + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_RESOLUTION; + AUDIO_Handle->headphone.attribute.volumeMax = LE16(&AUDIO_Handle->mem[0]); + + if (AUDIO_Handle->headphone.attribute.volumeMax < AUDIO_Handle->headphone.attribute.volumeMin) + { + AUDIO_Handle->headphone.attribute.volumeMax = 0xFF00; + } + } + break; + + case AUDIO_REQ_GET_RESOLUTION: + req_status = USBH_AC_GetRes(phost, + UAC_FEATURE_UNIT, /* subtype */ + feature, /* feature */ + VOLUME_CONTROL, /* Selector */ + channel, /* channel */ + 0x02); /* length */ + if(req_status != USBH_BUSY) + { + AUDIO_Handle->cs_req_state = AUDIO_REQ_CS_IDLE; + AUDIO_Handle->headphone.attribute.resolution = LE16(&AUDIO_Handle->mem[0]); + } + break; + + + case AUDIO_REQ_CS_IDLE: + status = USBH_OK; + default: + break; + } + return status; +} + +/** + * @brief USBH_AUDIO_HandleCSRequest + * The function is responsible for handling AC Specific requests for a all features + * and associated channels for Audio class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost) +{ + + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef cs_status = USBH_BUSY; + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + + cs_status = USBH_AUDIO_CSRequest(phost, + AUDIO_Handle->temp_feature, + AUDIO_Handle->temp_channels); + + if(cs_status != USBH_BUSY) + { + + if(AUDIO_Handle->temp_channels == 1) + { + AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature; + AUDIO_Handle->temp_channels = 0; + status = USBH_OK; + } + else + { + AUDIO_Handle->temp_channels--; + } + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + + return status; +} + +/** + * @brief USBH_AUDIO_Process + * The function is for managing state machine for Audio data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_Process (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY; + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + + if(AUDIO_Handle->headphone.supported == 1) + { + USBH_AUDIO_OutputStream (phost); + } + + if(AUDIO_Handle->microphone.supported == 1) + { + USBH_AUDIO_InputStream (phost); + } + + return status; +} + +/** + * @brief USBH_AUDIO_SOFProcess + * The function is for managing the SOF callback + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_SOFProcess (USBH_HandleTypeDef *phost) +{ + return USBH_OK; +} +/** + * @brief Find IN Audio Streaming interfaces + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost) +{ + uint8_t interface, alt_settings; + USBH_StatusTypeDef status = USBH_FAIL ; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /* Look For AUDIOSTREAMING IN interface */ + alt_settings = 0; + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS)&& + (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING)) + { + if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80)&& + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0)) + { + AUDIO_Handle->stream_in[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + AUDIO_Handle->stream_in[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + AUDIO_Handle->stream_in[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber; + AUDIO_Handle->stream_in[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting; + AUDIO_Handle->stream_in[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval; + AUDIO_Handle->stream_in[alt_settings].valid = 1; + alt_settings++; + } + } + } + + if(alt_settings > 0) + { + status = USBH_OK; + } + + return status; +} + +/** + * @brief Find OUT Audio Streaming interfaces + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost) +{ + uint8_t interface, alt_settings; + USBH_StatusTypeDef status = USBH_FAIL ; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /* Look For AUDIOSTREAMING IN interface */ + alt_settings = 0; + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS)&& + (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING)) + { + if(((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) == 0x00)&& + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0)) + { + AUDIO_Handle->stream_out[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + AUDIO_Handle->stream_out[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + AUDIO_Handle->stream_out[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber; + AUDIO_Handle->stream_out[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting; + AUDIO_Handle->stream_out[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval; + AUDIO_Handle->stream_out[alt_settings].valid = 1; + alt_settings++; + } + } + } + + if(alt_settings > 0) + { + status = USBH_OK; + } + + return status; +} + +/** + * @brief Find HID Control interfaces + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost) +{ + uint8_t interface; + USBH_StatusTypeDef status = USBH_FAIL ; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /* Look For AUDIOCONTROL interface */ + interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0xFF); + if(interface != 0xFF) + { + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == 0x03)&& /*HID*/ + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0)) + { + if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) == 0x80) + { + AUDIO_Handle->control.Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + AUDIO_Handle->control.EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + AUDIO_Handle->control.interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber; + AUDIO_Handle->control.Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval; + AUDIO_Handle->control.supported = 1; + status = USBH_OK; + break; + } + } + } + } + return status; +} + +/** + * @brief Parse AC and interfaces Descriptors + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost) +{ + USBH_DescHeader_t *pdesc ; + uint16_t ptr; + int8_t itf_index = 0; + int8_t itf_number = 0; + int8_t alt_setting; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + pdesc = (USBH_DescHeader_t *)(phost->device.CfgDesc_Raw); + ptr = USB_LEN_CFG_DESC; + + AUDIO_Handle->class_desc.FeatureUnitNum = 0; + AUDIO_Handle->class_desc.InputTerminalNum = 0; + AUDIO_Handle->class_desc.OutputTerminalNum = 0; + AUDIO_Handle->class_desc.ASNum = 0; + + while(ptr < phost->device.CfgDesc.wTotalLength) + { + pdesc = USBH_GetNextDesc((void *)pdesc, &ptr); + + switch (pdesc->bDescriptorType) + { + + case USB_DESC_TYPE_INTERFACE: + itf_number = *((uint8_t *)pdesc + 2); + alt_setting = *((uint8_t *)pdesc + 3); + itf_index = USBH_FindInterfaceIndex (phost, itf_number, alt_setting); + break; + + case USB_DESC_TYPE_CS_INTERFACE: + if(itf_number <= phost->device.CfgDesc.bNumInterfaces) + { + + ParseCSDescriptors(&AUDIO_Handle->class_desc, + phost->device.CfgDesc.Itf_Desc[itf_index].bInterfaceSubClass, + (uint8_t *)pdesc); + } + break; + + default: + break; + } + } + return USBH_OK; +} + +/** + * @brief Parse AC interfaces + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc, + uint8_t ac_subclass, + uint8_t *pdesc) +{ + if(ac_subclass == USB_SUBCLASS_AUDIOCONTROL) + { + switch(pdesc[2]) + { + case UAC_HEADER: + class_desc->cs_desc.HeaderDesc = (AUDIO_HeaderDescTypeDef *)pdesc; + break; + + case UAC_INPUT_TERMINAL: + class_desc->cs_desc.InputTerminalDesc[class_desc->InputTerminalNum++] = (AUDIO_ITDescTypeDef*) pdesc; + break; + + case UAC_OUTPUT_TERMINAL: + class_desc->cs_desc.OutputTerminalDesc[class_desc->OutputTerminalNum++] = (AUDIO_OTDescTypeDef*) pdesc; + break; + + case UAC_FEATURE_UNIT: + class_desc->cs_desc.FeatureUnitDesc[class_desc->FeatureUnitNum++] = (AUDIO_FeatureDescTypeDef*) pdesc; + break; + + case UAC_SELECTOR_UNIT: + class_desc->cs_desc.SelectorUnitDesc[class_desc->SelectorUnitNum++] = (AUDIO_SelectorDescTypeDef*) pdesc; + break; + + case UAC_MIXER_UNIT: + class_desc->cs_desc.MixerUnitDesc[class_desc->MixerUnitNum++] = (AUDIO_MixerDescTypeDef*) pdesc; + break; + + default: + break; + } + } + else if(ac_subclass == USB_SUBCLASS_AUDIOSTREAMING) + { + switch(pdesc[2]) + { + case UAC_AS_GENERAL: + class_desc->as_desc[class_desc->ASNum].GeneralDesc = (AUDIO_ASGeneralDescTypeDef*) pdesc; + break; + case UAC_FORMAT_TYPE: + class_desc->as_desc[class_desc->ASNum++].FormatTypeDesc = (AUDIO_ASFormatTypeDescTypeDef*) pdesc; + break; + default: + break; + } + } + + return USBH_OK; +} + + +/** + * @brief Link a Unit to next associated one + * @param phost: Host handle + * @param UnitID: Unit identifer + * @retval UnitID, Index and Type of the assicated Unit + */ +static int32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID) +{ + uint8_t Index; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /* Find Feature Unit */ + for(Index = 0; Index < AUDIO_Handle->class_desc.FeatureUnitNum; Index ++) + { + if(AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bSourceID == UnitID) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bUnitID; + + return ((UnitID << 16) | (UAC_FEATURE_UNIT << 8) | Index); + } + } + + /* Find Mixer Unit */ + for(Index = 0; Index < AUDIO_Handle->class_desc.MixerUnitNum; Index ++) + { + if((AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID0 == UnitID)|| + (AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID1 == UnitID)) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bUnitID; + + return ((UnitID << 16) | (UAC_MIXER_UNIT << 8) | Index); + } + } + + + /* Find Selector Unit */ + for(Index = 0; Index < AUDIO_Handle->class_desc.SelectorUnitNum; Index ++) + { + if(AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bSourceID0 == UnitID) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bUnitID; + + return ((UnitID << 16) | (UAC_SELECTOR_UNIT << 8) | Index); + } + } + + + /* Find OT Unit */ + for(Index = 0; Index < AUDIO_Handle->class_desc.OutputTerminalNum; Index ++) + { + if(AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bSourceID == UnitID) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bTerminalID; + + return ((UnitID << 16) | (UAC_OUTPUT_TERMINAL << 8) | Index); + } + } + + /* No associated Unit found */ + return -1; +} + +/** + * @brief Build full path for Microphone device + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost) +{ + uint8_t UnitID = 0, Type, Index; + uint32_t value; + uint8_t terminalIndex; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /*Find microphone IT*/ + for(terminalIndex = 0; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++) + { + if(LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x201) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID; + AUDIO_Handle->microphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels; + break; + } + } + + do + { + value = USBH_AUDIO_FindLinkedUnit(phost, UnitID); + Index = value & 0xFF; + Type = (value >> 8) & 0xFF; + UnitID = (value >> 16) & 0xFF; + + switch (Type) + { + case UAC_FEATURE_UNIT: + AUDIO_Handle->microphone.asociated_feature = Index; + break; + + case UAC_MIXER_UNIT: + AUDIO_Handle->microphone.asociated_mixer = Index; + break; + + case UAC_SELECTOR_UNIT: + AUDIO_Handle->microphone.asociated_selector = Index; + break; + + case UAC_OUTPUT_TERMINAL: + AUDIO_Handle->microphone.asociated_terminal = Index; + break; + } + } + while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0)); + + + + return USBH_OK; +} + +/** + * @brief Build full path for Headphone device + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost) +{ + uint8_t UnitID = 0, Type, Index; + uint32_t value; + uint8_t terminalIndex; + AUDIO_HandleTypeDef *AUDIO_Handle; + + AUDIO_Handle = phost->pActiveClass->pData; + + /*Find association betwen audio streaming and microphone*/ + for(terminalIndex = 0; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++) + { + if(LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x101) + { + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID; + AUDIO_Handle->headphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels; + break; + } + } + + for(Index = 0; Index < AUDIO_Handle->class_desc.ASNum; Index++) + { + if(AUDIO_Handle->class_desc.as_desc[Index].GeneralDesc->bTerminalLink == UnitID) + { + AUDIO_Handle->headphone.asociated_as = Index; + break; + } + } + + do + { + value = USBH_AUDIO_FindLinkedUnit(phost, UnitID); + Index = value & 0xFF; + Type = (value >> 8) & 0xFF; + UnitID = (value >> 16) & 0xFF; + + switch (Type) + { + case UAC_FEATURE_UNIT: + AUDIO_Handle->headphone.asociated_feature = Index; + break; + + case UAC_MIXER_UNIT: + AUDIO_Handle->headphone.asociated_mixer = Index; + break; + + case UAC_SELECTOR_UNIT: + AUDIO_Handle->headphone.asociated_selector = Index; + break; + + case UAC_OUTPUT_TERMINAL: + AUDIO_Handle->headphone.asociated_terminal = Index; + if(LE16(AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->wTerminalType) != 0x103) + { + return USBH_OK; + } + break; + } + } + while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0)); + + return USBH_FAIL; +} + + +/** + * @brief Handle Set Cur request + * @param phost: Host handle + * @param subtype: subtype index + * @param feature: feature index + * @param controlSelector: control code + * @param channel: channel index + * @param length: Command length + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length) +{ + uint16_t wValue,wIndex,wLength; + uint8_t UnitID,InterfaceNum; + AUDIO_HandleTypeDef *AUDIO_Handle; + AUDIO_Handle = phost->pActiveClass->pData; + + switch(subtype) + { + case UAC_INPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + AUDIO_Handle->mem[0] = 0x00; + + wLength = 1; + break; + case UAC_FEATURE_UNIT: + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + /*holds the CS(control selector ) and CN (channel number)*/ + wValue = (controlSelector << 8) | channel; + wLength = length; + break; + } + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_SET_CUR; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength )); + +} + +/** + * @brief Handle Get Cur request + * @param phost: Host handle + * @param subtype: subtype index + * @param feature: feature index + * @param controlSelector: control code + * @param channel: channel index + * @param length: Command length + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length) +{ + uint16_t wValue = 0, wIndex = 0,wLength = 0; + uint8_t UnitID = 0, InterfaceNum = 0; + AUDIO_HandleTypeDef *AUDIO_Handle; + AUDIO_Handle = phost->pActiveClass->pData; + + switch(subtype) + { + case UAC_INPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + AUDIO_Handle->mem[0] = 0x00; + + wLength = 1; + break; + case UAC_FEATURE_UNIT: + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + /*holds the CS(control selector ) and CN (channel number)*/ + wValue = (controlSelector << 8) | channel; + wLength = length; + break; + + case UAC_OUTPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + wLength = 1; + break; + } + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_GET_CUR; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength )); + +} + + +/** + * @brief Handle Get Max request + * @param phost: Host handle + * @param subtype: subtype index + * @param feature: feature index + * @param controlSelector: control code + * @param channel: channel index + * @param length: Command length + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length) +{ + uint16_t wValue = 0, wIndex = 0, wLength = 0; + uint8_t UnitID = 0, InterfaceNum = 0; + AUDIO_HandleTypeDef *AUDIO_Handle; + AUDIO_Handle = phost->pActiveClass->pData; + + switch(subtype) + { + case UAC_INPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + AUDIO_Handle->mem[0] = 0x00; + + wLength = 1; + break; + case UAC_FEATURE_UNIT: + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + /*holds the CS(control selector ) and CN (channel number)*/ + wValue = (controlSelector << 8) | channel; + wLength = length; + break; + + case UAC_OUTPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + wLength = 1; + break; + } + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_GET_MAX; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength )); + +} + + + +/** + * @brief Handle Get Res request + * @param phost: Host handle + * @param subtype: subtype index + * @param feature: feature index + * @param controlSelector: control code + * @param channel: channel index + * @param length: Command length + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length) +{ + uint16_t wValue = 0, wIndex = 0, wLength = 0; + uint8_t UnitID = 0, InterfaceNum = 0; + AUDIO_HandleTypeDef *AUDIO_Handle; + AUDIO_Handle = phost->pActiveClass->pData; + + switch(subtype) + { + case UAC_INPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + AUDIO_Handle->mem[0] = 0x00; + + wLength = 1; + break; + case UAC_FEATURE_UNIT: + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + /*holds the CS(control selector ) and CN (channel number)*/ + wValue = (controlSelector << 8) | channel; + wLength = length; + break; + + case UAC_OUTPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + wLength = 1; + break; + } + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_GET_RES; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength )); + +} + +/** + * @brief Handle Get Min request + * @param phost: Host handle + * @param subtype: subtype index + * @param feature: feature index + * @param controlSelector: control code + * @param channel: channel index + * @param length: Command length + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost, + uint8_t subtype, + uint8_t feature, + uint8_t controlSelector, + uint8_t channel, + uint16_t length) +{ + uint16_t wValue = 0, wIndex = 0, wLength = 0; + uint8_t UnitID = 0, InterfaceNum = 0; + AUDIO_HandleTypeDef *AUDIO_Handle; + AUDIO_Handle = phost->pActiveClass->pData; + + switch(subtype) + { + case UAC_INPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + AUDIO_Handle->mem[0] = 0x00; + + wLength = 1; + break; + case UAC_FEATURE_UNIT: + UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + /*holds the CS(control selector ) and CN (channel number)*/ + wValue = (controlSelector << 8) | channel; + wLength = length; + break; + + case UAC_OUTPUT_TERMINAL: + UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID; + InterfaceNum = 0; /*Always zero Control Interface */ + wIndex = ( UnitID << 8 ) | InterfaceNum ; + wValue = (COPY_PROTECT_CONTROL << 8 ) ; + wLength = 1; + break; + } + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_GET_MIN; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)(AUDIO_Handle->mem) , wLength )); + +} + +/** + * @brief Handle Set Endpoint Controls Request + * @param phost: Host handle + * @param Ep: Endpoint address + * @param buf: pointer to data + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost, + uint8_t Ep, + uint8_t *buff) +{ + uint16_t wValue, wIndex, wLength; + + + wValue = SAMPLING_FREQ_CONTROL << 8; + wIndex = Ep; + wLength = 3; /*length of the frequency parameter*/ + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | \ + USB_REQ_TYPE_CLASS; + + phost->Control.setup.b.bRequest = UAC_SET_CUR; + phost->Control.setup.b.wValue.w = wValue; + phost->Control.setup.b.wIndex.w = wIndex; + phost->Control.setup.b.wLength.w = wLength; + + return(USBH_CtlReq(phost, (uint8_t *)buff, wLength )); + +} + +/** + * @brief Handle Input stream process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_InputStream (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + + return status; +} + +/** + * @brief Handle HID Control process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_Control (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + uint16_t attribute = 0; + + + switch(AUDIO_Handle->control_state) + { + case AUDIO_CONTROL_INIT: + if((phost->Timer & 1) == 0) + { + AUDIO_Handle->control.timer = phost->Timer; + USBH_InterruptReceiveData(phost, + (uint8_t *)(AUDIO_Handle->mem), + AUDIO_Handle->control.EpSize, + AUDIO_Handle->control.Pipe); + + AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature; + AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels; + + AUDIO_Handle->control_state = AUDIO_CONTROL_CHANGE ; + } + break; + case AUDIO_CONTROL_CHANGE: + if(USBH_LL_GetURBState(phost , AUDIO_Handle->control.Pipe) == USBH_URB_DONE) + { + attribute = LE16(&AUDIO_Handle->mem[0]); + if(USBH_AUDIO_SetControlAttribute (phost, attribute) == USBH_BUSY) + { + break; + } + } + + if(( phost->Timer - AUDIO_Handle->control.timer) >= AUDIO_Handle->control.Poll) + { + AUDIO_Handle->control.timer = phost->Timer; + + USBH_InterruptReceiveData(phost, + (uint8_t *)(AUDIO_Handle->mem), + AUDIO_Handle->control.EpSize, + AUDIO_Handle->control.Pipe); + + } + break; + + case AUDIO_CONTROL_VOLUME_UP: + if( USBH_AUDIO_SetControlAttribute (phost, 1) == USBH_OK) + { + AUDIO_Handle->control_state = AUDIO_CONTROL_INIT; + status = USBH_OK; + } + break; + + case AUDIO_CONTROL_VOLUME_DOWN: + if( USBH_AUDIO_SetControlAttribute (phost, 2) == USBH_OK) + { + AUDIO_Handle->control_state = AUDIO_CONTROL_INIT; + status = USBH_OK; + } + break; + + case AUDIO_CONTROL_IDLE: + default: + break; + } + + return status; +} + +/** + * @brief Handle Output stream process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_OutputStream (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + uint8_t *buff; + + + switch(AUDIO_Handle->play_state) + { + case AUDIO_PLAYBACK_INIT: + + if( AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0) + { + AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP_FREQ; + } + else + { + AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + break; + + case AUDIO_PLAYBACK_SET_EP_FREQ: + + buff = (uint8_t*)AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0]; + + status = USBH_AUDIO_SetEndpointControls(phost, AUDIO_Handle->headphone.Ep, buff); + if(status == USBH_OK) + { + AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE; + } + break; + + case AUDIO_PLAYBACK_SET_EP: + buff = (uint8_t *)&AUDIO_Handle->headphone.frequency; + status = USBH_AUDIO_SetEndpointControls(phost,AUDIO_Handle->headphone.Ep, buff); + if(status == USBH_OK) + { + AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE; + USBH_AUDIO_FrequencySet(phost); + } + break; + case AUDIO_PLAYBACK_IDLE: +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + status = USBH_OK; + break; + + case AUDIO_PLAYBACK_PLAY: + USBH_AUDIO_Transmit(phost); + status = USBH_OK; + break; + + default: + break; + } + + return status; +} + +/** + * @brief Handle Transmission process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_Transmit (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + + switch(AUDIO_Handle->processing_state) + { + case AUDIO_DATA_START_OUT: + /* Sync with start of Even Frame */ + if((phost->Timer & 1) == 0) + { + AUDIO_Handle->headphone.timer = phost->Timer; + AUDIO_Handle->processing_state = AUDIO_DATA_OUT; + USBH_IsocSendData(phost, + AUDIO_Handle->headphone.buf, + AUDIO_Handle->headphone.frame_length, + AUDIO_Handle->headphone.Pipe); + + AUDIO_Handle->headphone.partial_ptr = AUDIO_Handle->headphone.frame_length; + AUDIO_Handle->headphone.global_ptr = AUDIO_Handle->headphone.frame_length; + AUDIO_Handle->headphone.cbuf = AUDIO_Handle->headphone.buf; + + } + break; + + case AUDIO_DATA_OUT: + if((USBH_LL_GetURBState(phost , AUDIO_Handle->headphone.Pipe) == USBH_URB_DONE)&& + (( phost->Timer - AUDIO_Handle->headphone.timer) >= AUDIO_Handle->headphone.Poll)) + { + AUDIO_Handle->headphone.timer = phost->Timer; + + if(AUDIO_Handle->control.supported == 1) + { + USBH_AUDIO_Control (phost); + } + + if(AUDIO_Handle->headphone.global_ptr <= AUDIO_Handle->headphone.total_length) + { + USBH_IsocSendData(phost, + AUDIO_Handle->headphone.cbuf, + AUDIO_Handle->headphone.frame_length, + AUDIO_Handle->headphone.Pipe); + + AUDIO_Handle->headphone.cbuf += AUDIO_Handle->headphone.frame_length; + AUDIO_Handle->headphone.partial_ptr += AUDIO_Handle->headphone.frame_length; + AUDIO_Handle->headphone.global_ptr += AUDIO_Handle->headphone.frame_length; + } + else + { + AUDIO_Handle->headphone.partial_ptr = 0xFFFFFFFF; + AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE; + } + } + break; + } + return status; +} + +/** + * @brief USBH_AUDIO_SetFrequency + * Set Audio sampling parameters + * @param phost: Host handle + * @param SampleRate: Sample Rate + * @param NbrChannels: Number of Channels + * @param BitPerSample: Bit Per Sample + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_SetFrequency (USBH_HandleTypeDef *phost, + uint16_t SampleRate, + uint8_t NbrChannels, + uint8_t BitPerSample) +{ + USBH_StatusTypeDef Status = USBH_BUSY; + AUDIO_HandleTypeDef *AUDIO_Handle; + uint8_t index; + uint8_t change_freq = FALSE; + uint32_t freq_min, freq_max; + uint8_t num_supported_freq; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE) + { + + if(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0) + { + freq_min = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0]); + freq_max = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[1]); + + if(( SampleRate >= freq_min)&& (SampleRate <= freq_max)) + { + change_freq = TRUE; + } + } + else + { + + num_supported_freq = (AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bLength - 8)/3; + + + for(index = 0; index < num_supported_freq; index++) + { + if(SampleRate == LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[index])) + { + change_freq = TRUE; + break; + } + } + } + + if(change_freq == TRUE) + { + AUDIO_Handle->headphone.frequency = SampleRate; + AUDIO_Handle->headphone.frame_length = (SampleRate * BitPerSample * NbrChannels) / 8000; + AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP; + Status = USBH_OK; + + } + } + } + return Status; +} + +/** + * @brief USBH_AUDIO_Play + * Start playback process + * @param phost: Host handle + * @param buf: pointer to raw audio data + * @param length: total length of the audio data + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_Play (USBH_HandleTypeDef *phost, uint8_t *buf, uint32_t length) +{ + USBH_StatusTypeDef Status = USBH_FAIL; + AUDIO_HandleTypeDef *AUDIO_Handle; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE) + { + AUDIO_Handle->headphone.buf = buf; + AUDIO_Handle->headphone.total_length = length; + AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY; + AUDIO_Handle->control_state = AUDIO_CONTROL_INIT; + AUDIO_Handle->processing_state = AUDIO_DATA_START_OUT; + Status = USBH_OK; + } + } + return Status; +} + +/** + * @brief USBH_AUDIO_Pause + * Stop the playback process + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_Stop (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef Status = USBH_FAIL; + Status = USBH_AUDIO_Suspend(phost); + return Status; +} + +/** + * @brief USBH_AUDIO_Suspend + * Suspend the playback process + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_Suspend (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef Status = USBH_FAIL; + AUDIO_HandleTypeDef *AUDIO_Handle; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY) + { + AUDIO_Handle->control_state = AUDIO_CONTROL_IDLE; + AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE; + Status = USBH_OK; + } + } + return Status; +} +/** + * @brief USBH_AUDIO_Resume + * Resume the playback process + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_Resume (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef Status = USBH_FAIL; + AUDIO_HandleTypeDef *AUDIO_Handle; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE) + { + AUDIO_Handle->control_state = AUDIO_CONTROL_INIT; + AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY; + } + } + return Status; +} +/** + * @brief USBH_AUDIO_GetOutOffset + * return the current buffer pointer for OUT proces + * @param phost: Host handle + * @retval USBH Status + */ +int32_t USBH_AUDIO_GetOutOffset (USBH_HandleTypeDef *phost) +{ + AUDIO_HandleTypeDef *AUDIO_Handle; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY) + { + return AUDIO_Handle->headphone.partial_ptr; + } + } + return -1; +} + +/** + * @brief USBH_AUDIO_ChangeOutBuffer + * Change audio data buffer address + * @param phost: Host handle + * @param buf: buffer address + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_ChangeOutBuffer (USBH_HandleTypeDef *phost, uint8_t *buf) +{ + USBH_StatusTypeDef Status = USBH_FAIL; + AUDIO_HandleTypeDef *AUDIO_Handle; + + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY) + { + if(AUDIO_Handle->headphone.buf <= buf) + { + AUDIO_Handle->headphone.cbuf = buf; + if ( AUDIO_Handle->headphone.buf == buf) + { + AUDIO_Handle->headphone.partial_ptr = 0; + } + Status = USBH_OK; + } + } + } + return Status; +} + +/** + * @brief USBH_AUDIO_SetControlAttribute + * Set Control Attribute + * @param phost: Host handle + * @param attrib: control attribute + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute (USBH_HandleTypeDef *phost, uint8_t attrib) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + AUDIO_HandleTypeDef *AUDIO_Handle; + + + AUDIO_Handle = phost->pActiveClass->pData; + + switch (attrib) + { + case 0x01: + AUDIO_Handle->headphone.attribute.volume += AUDIO_Handle->headphone.attribute.resolution; + break; + + case 0x02: + AUDIO_Handle->headphone.attribute.volume -= AUDIO_Handle->headphone.attribute.resolution; + break; + + } + + if(AUDIO_Handle->headphone.attribute.volume > AUDIO_Handle->headphone.attribute.volumeMax) + { + AUDIO_Handle->headphone.attribute.volume =AUDIO_Handle->headphone.attribute.volumeMax; + } + + if(AUDIO_Handle->headphone.attribute.volume < AUDIO_Handle->headphone.attribute.volumeMin) + { + AUDIO_Handle->headphone.attribute.volume =AUDIO_Handle->headphone.attribute.volumeMin; + } + + if(AUDIO_SetVolume (phost, + AUDIO_Handle->temp_feature, + AUDIO_Handle->temp_channels, + AUDIO_Handle->headphone.attribute.volume) != USBH_BUSY) + { + + if(AUDIO_Handle->temp_channels == 1) + { + AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature; + AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels; + status = USBH_OK; + } + else + { + AUDIO_Handle->temp_channels--; + } + AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME; + } + + + return status; +} + + +/** + * @brief USBH_AUDIO_SetVolume + * Set Volume + * @param phost: Host handle + * @param volume: VOLUME_UP/ VOLUME_DOWN + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_AUDIO_SetVolume (USBH_HandleTypeDef *phost, AUDIO_VolumeCtrlTypeDef volume_ctl) +{ + AUDIO_HandleTypeDef *AUDIO_Handle = phost->pActiveClass->pData; + + if((volume_ctl == VOLUME_UP) || (volume_ctl == VOLUME_DOWN)) + { + if(phost->gState == HOST_CLASS) + { + AUDIO_Handle = phost->pActiveClass->pData; + if(AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY) + { + AUDIO_Handle->control_state = (volume_ctl == VOLUME_UP)? AUDIO_CONTROL_VOLUME_UP : AUDIO_CONTROL_VOLUME_DOWN; + return USBH_OK; + } + } + } + return USBH_FAIL; +} +/** + * @brief AUDIO_SetVolume + * Set Volume + * @param phost: Host handle + * @param feature: feature Unit index + * @param channel: channel index + * @param volume: new volume + * @retval USBH Status + */ +static USBH_StatusTypeDef AUDIO_SetVolume (USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + AUDIO_HandleTypeDef *AUDIO_Handle; + + + AUDIO_Handle = phost->pActiveClass->pData; + + AUDIO_Handle->mem[0] = volume; + + status = USBH_AC_SetCur(phost, + UAC_FEATURE_UNIT, + feature, + VOLUME_CONTROL, + channel, + 2); + + return status; +} + +/** + * @brief The function informs user that Settings have been changed + * @param pdev: Selected device + * @retval None + */ +__weak void USBH_AUDIO_FrequencySet(USBH_HandleTypeDef *phost) +{ + +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h new file mode 100755 index 0000000..df11bfd --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Inc/usbh_cdc.h @@ -0,0 +1,449 @@ +/** + ****************************************************************************** + * @file usbh_cdc.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_cdc.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_CDC_CORE_H +#define __USBH_CDC_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_CDC_CLASS +* @{ +*/ + +/** @defgroup USBH_CDC_CORE +* @brief This file is the Header file for USBH_CDC_CORE.c +* @{ +*/ + + + + +/*Communication Class codes*/ +#define USB_CDC_CLASS 0x02 +#define COMMUNICATION_INTERFACE_CLASS_CODE 0x02 + +/*Data Interface Class Codes*/ +#define DATA_INTERFACE_CLASS_CODE 0x0A + +/*Communcation sub class codes*/ +#define RESERVED 0x00 +#define DIRECT_LINE_CONTROL_MODEL 0x01 +#define ABSTRACT_CONTROL_MODEL 0x02 +#define TELEPHONE_CONTROL_MODEL 0x03 +#define MULTICHANNEL_CONTROL_MODEL 0x04 +#define CAPI_CONTROL_MODEL 0x05 +#define ETHERNET_NETWORKING_CONTROL_MODEL 0x06 +#define ATM_NETWORKING_CONTROL_MODEL 0x07 + + +/*Communication Interface Class Control Protocol Codes*/ +#define NO_CLASS_SPECIFIC_PROTOCOL_CODE 0x00 +#define COMMON_AT_COMMAND 0x01 +#define VENDOR_SPECIFIC 0xFF + + +#define CS_INTERFACE 0x24 +#define CDC_PAGE_SIZE_64 0x40 + +/*Class-Specific Request Codes*/ +#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 +#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 +#define CDC_SET_COMM_FEATURE 0x02 +#define CDC_GET_COMM_FEATURE 0x03 +#define CDC_CLEAR_COMM_FEATURE 0x04 + +#define CDC_SET_AUX_LINE_STATE 0x10 +#define CDC_SET_HOOK_STATE 0x11 +#define CDC_PULSE_SETUP 0x12 +#define CDC_SEND_PULSE 0x13 +#define CDC_SET_PULSE_TIME 0x14 +#define CDC_RING_AUX_JACK 0x15 + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 + +#define CDC_SET_RINGER_PARMS 0x30 +#define CDC_GET_RINGER_PARMS 0x31 +#define CDC_SET_OPERATION_PARMS 0x32 +#define CDC_GET_OPERATION_PARMS 0x33 +#define CDC_SET_LINE_PARMS 0x34 +#define CDC_GET_LINE_PARMS 0x35 +#define CDC_DIAL_DIGITS 0x36 +#define CDC_SET_UNIT_PARAMETER 0x37 +#define CDC_GET_UNIT_PARAMETER 0x38 +#define CDC_CLEAR_UNIT_PARAMETER 0x39 +#define CDC_GET_PROFILE 0x3A + +#define CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN FILTER 0x41 +#define CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN FILTER 0x42 +#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 +#define CDC_GET_ETHERNET_STATISTIC 0x44 + +#define CDC_SET_ATM_DATA_FORMAT 0x50 +#define CDC_GET_ATM_DEVICE_STATISTICS 0x51 +#define CDC_SET_ATM_DEFAULT_VC 0x52 +#define CDC_GET_ATM_VC_STATISTICS 0x53 + + +/* wValue for SetControlLineState*/ +#define CDC_ACTIVATE_CARRIER_SIGNAL_RTS 0x0002 +#define CDC_DEACTIVATE_CARRIER_SIGNAL_RTS 0x0000 +#define CDC_ACTIVATE_SIGNAL_DTR 0x0001 +#define CDC_DEACTIVATE_SIGNAL_DTR 0x0000 + +#define LINE_CODING_STRUCTURE_SIZE 0x07 +/** + * @} + */ + +/** @defgroup USBH_CDC_CORE_Exported_Types +* @{ +*/ + +/* States for CDC State Machine */ +typedef enum +{ + CDC_IDLE= 0, + CDC_SEND_DATA, + CDC_SEND_DATA_WAIT, + CDC_RECEIVE_DATA, + CDC_RECEIVE_DATA_WAIT, +} +CDC_DataStateTypeDef; + +typedef enum +{ + CDC_IDLE_STATE= 0, + CDC_SET_LINE_CODING_STATE, + CDC_GET_LAST_LINE_CODING_STATE, + CDC_TRANSFER_DATA, + CDC_ERROR_STATE, +} +CDC_StateTypeDef; + + +/*Line coding structure*/ +typedef union _CDC_LineCodingStructure +{ + uint8_t Array[LINE_CODING_STRUCTURE_SIZE]; + + struct + { + + uint32_t dwDTERate; /*Data terminal rate, in bits per second*/ + uint8_t bCharFormat; /*Stop bits + 0 - 1 Stop bit + 1 - 1.5 Stop bits + 2 - 2 Stop bits*/ + uint8_t bParityType; /* Parity + 0 - None + 1 - Odd + 2 - Even + 3 - Mark + 4 - Space*/ + uint8_t bDataBits; /* Data bits (5, 6, 7, 8 or 16). */ + }b; +} +CDC_LineCodingTypeDef; + + + +/* Header Functional Descriptor +-------------------------------------------------------------------------------- +Offset| field | Size | Value | Description +------|---------------------|-------|------------|------------------------------ +0 | bFunctionLength | 1 | number | Size of this descriptor. +1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24) +2 | bDescriptorSubtype | 1 | Constant | Identifier (ID) of functional + | | | | descriptor. +3 | bcdCDC | 2 | | + | | | Number | USB Class Definitions for + | | | | Communication Devices Specification + | | | | release number in binary-coded + | | | | decimal +------|---------------------|-------|------------|------------------------------ +*/ +typedef struct _FunctionalDescriptorHeader +{ + uint8_t bLength; /*Size of this descriptor.*/ + uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/ + uint8_t bDescriptorSubType; /* Header functional descriptor subtype as*/ + uint16_t bcdCDC; /* USB Class Definitions for Communication + Devices Specification release number in + binary-coded decimal. */ +} +CDC_HeaderFuncDesc_TypeDef; +/* Call Management Functional Descriptor +-------------------------------------------------------------------------------- +Offset| field | Size | Value | Description +------|---------------------|-------|------------|------------------------------ +0 | bFunctionLength | 1 | number | Size of this descriptor. +1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24) +2 | bDescriptorSubtype | 1 | Constant | Call Management functional + | | | | descriptor subtype. +3 | bmCapabilities | 1 | Bitmap | The capabilities that this configuration + | | | | supports: + | | | | D7..D2: RESERVED (Reset to zero) + | | | | D1: 0 - Device sends/receives call + | | | | management information only over + | | | | the Communication Class + | | | | interface. + | | | | 1 - Device can send/receive call + | \ | | management information over a + | | | | Data Class interface. + | | | | D0: 0 - Device does not handle call + | | | | management itself. + | | | | 1 - Device handles call + | | | | management itself. + | | | | The previous bits, in combination, identify + | | | | which call management scenario is used. If bit + | | | | D0 is reset to 0, then the value of bit D1 is + | | | | ignored. In this case, bit D1 is reset to zero for + | | | | future compatibility. +4 | bDataInterface | 1 | Number | Interface number of Data Class interface + | | | | optionally used for call management. +------|---------------------|-------|------------|------------------------------ +*/ +typedef struct _CallMgmtFunctionalDescriptor +{ + uint8_t bLength; /*Size of this functional descriptor, in bytes.*/ + uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/ + uint8_t bDescriptorSubType; /* Call Management functional descriptor subtype*/ + uint8_t bmCapabilities; /* bmCapabilities: D0+D1 */ + uint8_t bDataInterface; /*bDataInterface: 1*/ +} +CDC_CallMgmtFuncDesc_TypeDef; +/* Abstract Control Management Functional Descriptor +-------------------------------------------------------------------------------- +Offset| field | Size | Value | Description +------|---------------------|-------|------------|------------------------------ +0 | bFunctionLength | 1 | number | Size of functional descriptor, in bytes. +1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24) +2 | bDescriptorSubtype | 1 | Constant | Abstract Control Management + | | | | functional descriptor subtype. +3 | bmCapabilities | 1 | Bitmap | The capabilities that this configuration + | | | | supports ((A bit value of zero means that the + | | | | request is not supported.) ) + D7..D4: RESERVED (Reset to zero) + | | | | D3: 1 - Device supports the notification + | | | | Network_Connection. + | | | | D2: 1 - Device supports the request + | | | | Send_Break + | | | | D1: 1 - Device supports the request + | \ | | combination of Set_Line_Coding, + | | | | Set_Control_Line_State, Get_Line_Coding, and the + notification Serial_State. + | | | | D0: 1 - Device supports the request + | | | | combination of Set_Comm_Feature, + | | | | Clear_Comm_Feature, and Get_Comm_Feature. + | | | | The previous bits, in combination, identify + | | | | which requests/notifications are supported by + | | | | a Communication Class interface with the + | | | | SubClass code of Abstract Control Model. +------|---------------------|-------|------------|------------------------------ +*/ +typedef struct _AbstractCntrlMgmtFunctionalDescriptor +{ + uint8_t bLength; /*Size of this functional descriptor, in bytes.*/ + uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/ + uint8_t bDescriptorSubType; /* Abstract Control Management functional + descriptor subtype*/ + uint8_t bmCapabilities; /* The capabilities that this configuration supports */ +} +CDC_AbstCntrlMgmtFuncDesc_TypeDef; +/* Union Functional Descriptor +-------------------------------------------------------------------------------- +Offset| field | Size | Value | Description +------|---------------------|-------|------------|------------------------------ +0 | bFunctionLength | 1 | number | Size of this descriptor. +1 | bDescriptorType | 1 | Constant | CS_INTERFACE (0x24) +2 | bDescriptorSubtype | 1 | Constant | Union functional + | | | | descriptor subtype. +3 | bMasterInterface | 1 | Constant | The interface number of the + | | | | Communication or Data Class interface +4 | bSlaveInterface0 | 1 | Number | nterface number of first slave or associated + | | | | interface in the union. +------|---------------------|-------|------------|------------------------------ +*/ +typedef struct _UnionFunctionalDescriptor +{ + uint8_t bLength; /*Size of this functional descriptor, in bytes*/ + uint8_t bDescriptorType; /*CS_INTERFACE (0x24)*/ + uint8_t bDescriptorSubType; /* Union functional descriptor SubType*/ + uint8_t bMasterInterface; /* The interface number of the Communication or + Data Class interface,*/ + uint8_t bSlaveInterface0; /*Interface number of first slave*/ +} +CDC_UnionFuncDesc_TypeDef; + +typedef struct _USBH_CDCInterfaceDesc +{ + CDC_HeaderFuncDesc_TypeDef CDC_HeaderFuncDesc; + CDC_CallMgmtFuncDesc_TypeDef CDC_CallMgmtFuncDesc; + CDC_AbstCntrlMgmtFuncDesc_TypeDef CDC_AbstCntrlMgmtFuncDesc; + CDC_UnionFuncDesc_TypeDef CDC_UnionFuncDesc; +} +CDC_InterfaceDesc_Typedef; + + +/* Structure for CDC process */ +typedef struct +{ + uint8_t NotifPipe; + uint8_t NotifEp; + uint8_t buff[8]; + uint16_t NotifEpSize; +} +CDC_CommItfTypedef ; + +typedef struct +{ + uint8_t InPipe; + uint8_t OutPipe; + uint8_t OutEp; + uint8_t InEp; + uint8_t buff[8]; + uint16_t OutEpSize; + uint16_t InEpSize; +} +CDC_DataItfTypedef ; + +/* Structure for CDC process */ +typedef struct _CDC_Process +{ + CDC_CommItfTypedef CommItf; + CDC_DataItfTypedef DataItf; + uint8_t *pTxData; + uint8_t *pRxData; + uint32_t TxDataLength; + uint32_t RxDataLength; + CDC_InterfaceDesc_Typedef CDC_Desc; + CDC_LineCodingTypeDef LineCoding; + CDC_LineCodingTypeDef *pUserLineCoding; + CDC_StateTypeDef state; + CDC_DataStateTypeDef data_tx_state; + CDC_DataStateTypeDef data_rx_state; + uint8_t Rx_Poll; +} +CDC_HandleTypeDef; + +/** +* @} +*/ + +/** @defgroup USBH_CDC_CORE_Exported_Defines +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBH_CDC_CORE_Exported_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_CDC_CORE_Exported_Variables +* @{ +*/ +extern USBH_ClassTypeDef CDC_Class; +#define USBH_CDC_CLASS &CDC_Class + +/** +* @} +*/ + +/** @defgroup USBH_CDC_CORE_Exported_FunctionsPrototype +* @{ +*/ + +USBH_StatusTypeDef USBH_CDC_SetLineCoding(USBH_HandleTypeDef *phost, + CDC_LineCodingTypeDef *linecoding); + +USBH_StatusTypeDef USBH_CDC_GetLineCoding(USBH_HandleTypeDef *phost, + CDC_LineCodingTypeDef *linecoding); + +USBH_StatusTypeDef USBH_CDC_Transmit(USBH_HandleTypeDef *phost, + uint8_t *pbuff, + uint32_t length); + +USBH_StatusTypeDef USBH_CDC_Receive(USBH_HandleTypeDef *phost, + uint8_t *pbuff, + uint32_t length); + + +uint16_t USBH_CDC_GetLastReceivedDataSize(USBH_HandleTypeDef *phost); + +USBH_StatusTypeDef USBH_CDC_Stop(USBH_HandleTypeDef *phost); + +void USBH_CDC_LineCodingChanged(USBH_HandleTypeDef *phost); + +void USBH_CDC_TransmitCallback(USBH_HandleTypeDef *phost); + +void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost); + +/** +* @} +*/ + + +#endif /* __USBH_CDC_CORE_H */ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c new file mode 100755 index 0000000..250e1fc --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/CDC/Src/usbh_cdc.c @@ -0,0 +1,755 @@ +/** + ****************************************************************************** + * @file usbh_cdc.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the CDC Layer Handlers for USB Host CDC class. + * + * @verbatim + * + * =================================================================== + * CDC Class Description + * =================================================================== + * This module manages the MSC class V1.11 following the "Device Class Definition + * for Human Interface Devices (CDC) Version 1.11 Jun 27, 2001". + * This driver implements the following aspects of the specification: + * - The Boot Interface Subclass + * - The Mouse and Keyboard protocols + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_cdc.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_CDC_CLASS +* @{ +*/ + +/** @defgroup USBH_CDC_CORE +* @brief This file includes CDC Layer Handlers for USB Host CDC class. +* @{ +*/ + +/** @defgroup USBH_CDC_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_CDC_CORE_Private_Defines +* @{ +*/ +#define USBH_CDC_BUFFER_SIZE 1024 +/** +* @} +*/ + + +/** @defgroup USBH_CDC_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_CDC_CORE_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_CDC_CORE_Private_FunctionPrototypes +* @{ +*/ + +static USBH_StatusTypeDef USBH_CDC_InterfaceInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_CDC_InterfaceDeInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_CDC_Process(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_CDC_SOFProcess(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_CDC_ClassRequest (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef GetLineCoding(USBH_HandleTypeDef *phost, + CDC_LineCodingTypeDef *linecoding); + +static USBH_StatusTypeDef SetLineCoding(USBH_HandleTypeDef *phost, + CDC_LineCodingTypeDef *linecoding); + +static void CDC_ProcessTransmission(USBH_HandleTypeDef *phost); + +static void CDC_ProcessReception(USBH_HandleTypeDef *phost); + +USBH_ClassTypeDef CDC_Class = +{ + "CDC", + USB_CDC_CLASS, + USBH_CDC_InterfaceInit, + USBH_CDC_InterfaceDeInit, + USBH_CDC_ClassRequest, + USBH_CDC_Process, + USBH_CDC_SOFProcess, + NULL, +}; +/** +* @} +*/ + + +/** @defgroup USBH_CDC_CORE_Private_Functions +* @{ +*/ + +/** + * @brief USBH_CDC_InterfaceInit + * The function init the CDC class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_CDC_InterfaceInit (USBH_HandleTypeDef *phost) +{ + + USBH_StatusTypeDef status = USBH_FAIL ; + uint8_t interface; + CDC_HandleTypeDef *CDC_Handle; + + interface = USBH_FindInterface(phost, + COMMUNICATION_INTERFACE_CLASS_CODE, + ABSTRACT_CONTROL_MODEL, + COMMON_AT_COMMAND); + + if(interface == 0xFF) /* No Valid Interface */ + { + USBH_DbgLog ("Cannot Find the interface for Communication Interface Class.", phost->pActiveClass->Name); + } + else + { + USBH_SelectInterface (phost, interface); + phost->pActiveClass->pData = (CDC_HandleTypeDef *)USBH_malloc (sizeof(CDC_HandleTypeDef)); + CDC_Handle = phost->pActiveClass->pData; + + /*Collect the notification endpoint address and length*/ + if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) + { + CDC_Handle->CommItf.NotifEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + CDC_Handle->CommItf.NotifEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + } + + /*Allocate the length for host channel number in*/ + CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost, CDC_Handle->CommItf.NotifEp); + + /* Open pipe for Notification endpoint */ + USBH_OpenPipe (phost, + CDC_Handle->CommItf.NotifPipe, + CDC_Handle->CommItf.NotifEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_INTR, + CDC_Handle->CommItf.NotifEpSize); + + USBH_LL_SetToggle (phost, CDC_Handle->CommItf.NotifPipe, 0); + + interface = USBH_FindInterface(phost, + DATA_INTERFACE_CLASS_CODE, + RESERVED, + NO_CLASS_SPECIFIC_PROTOCOL_CODE); + + if(interface == 0xFF) /* No Valid Interface */ + { + USBH_DbgLog ("Cannot Find the interface for Data Interface Class.", phost->pActiveClass->Name); + } + else + { + /*Collect the class specific endpoint address and length*/ + if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80) + { + CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + } + else + { + CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; + CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; + } + + if(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80) + { + CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress; + CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize; + } + else + { + CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress; + CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize; + } + + /*Allocate the length for host channel number out*/ + CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.OutEp); + + /*Allocate the length for host channel number in*/ + CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.InEp); + + /* Open channel for OUT endpoint */ + USBH_OpenPipe (phost, + CDC_Handle->DataItf.OutPipe, + CDC_Handle->DataItf.OutEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + CDC_Handle->DataItf.OutEpSize); + /* Open channel for IN endpoint */ + USBH_OpenPipe (phost, + CDC_Handle->DataItf.InPipe, + CDC_Handle->DataItf.InEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + CDC_Handle->DataItf.InEpSize); + + CDC_Handle->state = CDC_IDLE_STATE; + + USBH_LL_SetToggle (phost, CDC_Handle->DataItf.OutPipe,0); + USBH_LL_SetToggle (phost, CDC_Handle->DataItf.InPipe,0); + status = USBH_OK; + } + } + return status; +} + + + +/** + * @brief USBH_CDC_InterfaceDeInit + * The function DeInit the Pipes used for the CDC class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_CDC_InterfaceDeInit (USBH_HandleTypeDef *phost) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if ( CDC_Handle->CommItf.NotifPipe) + { + USBH_ClosePipe(phost, CDC_Handle->CommItf.NotifPipe); + USBH_FreePipe (phost, CDC_Handle->CommItf.NotifPipe); + CDC_Handle->CommItf.NotifPipe = 0; /* Reset the Channel as Free */ + } + + if ( CDC_Handle->DataItf.InPipe) + { + USBH_ClosePipe(phost, CDC_Handle->DataItf.InPipe); + USBH_FreePipe (phost, CDC_Handle->DataItf.InPipe); + CDC_Handle->DataItf.InPipe = 0; /* Reset the Channel as Free */ + } + + if ( CDC_Handle->DataItf.OutPipe) + { + USBH_ClosePipe(phost, CDC_Handle->DataItf.OutPipe); + USBH_FreePipe (phost, CDC_Handle->DataItf.OutPipe); + CDC_Handle->DataItf.OutPipe = 0; /* Reset the Channel as Free */ + } + + if(phost->pActiveClass->pData) + { + USBH_free (phost->pActiveClass->pData); + phost->pActiveClass->pData = 0; + } + + return USBH_OK; +} + +/** + * @brief USBH_CDC_ClassRequest + * The function is responsible for handling Standard requests + * for CDC class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_CDC_ClassRequest (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_FAIL ; + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + /*Issue the get line coding request*/ + status = GetLineCoding(phost, &CDC_Handle->LineCoding); + if(status == USBH_OK) + { + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + } + return status; +} + + +/** + * @brief USBH_CDC_Process + * The function is for managing state machine for CDC data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_CDC_Process (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef req_status = USBH_OK; + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + switch(CDC_Handle->state) + { + + case CDC_IDLE_STATE: + status = USBH_OK; + break; + + case CDC_SET_LINE_CODING_STATE: + req_status = SetLineCoding(phost, CDC_Handle->pUserLineCoding); + + if(req_status == USBH_OK) + { + CDC_Handle->state = CDC_GET_LAST_LINE_CODING_STATE; + } + + else if(req_status != USBH_BUSY) + { + CDC_Handle->state = CDC_ERROR_STATE; + } + break; + + + case CDC_GET_LAST_LINE_CODING_STATE: + req_status = GetLineCoding(phost, &(CDC_Handle->LineCoding)); + + if(req_status == USBH_OK) + { + CDC_Handle->state = CDC_IDLE_STATE; + + if((CDC_Handle->LineCoding.b.bCharFormat == CDC_Handle->pUserLineCoding->b.bCharFormat) && + (CDC_Handle->LineCoding.b.bDataBits == CDC_Handle->pUserLineCoding->b.bDataBits) && + (CDC_Handle->LineCoding.b.bParityType == CDC_Handle->pUserLineCoding->b.bParityType) && + (CDC_Handle->LineCoding.b.dwDTERate == CDC_Handle->pUserLineCoding->b.dwDTERate)) + { + USBH_CDC_LineCodingChanged(phost); + } + } + + else if(req_status != USBH_BUSY) + { + CDC_Handle->state = CDC_ERROR_STATE; + } + + break; + + case CDC_TRANSFER_DATA: + CDC_ProcessTransmission(phost); + CDC_ProcessReception(phost); + break; + + case CDC_ERROR_STATE: + req_status = USBH_ClrFeature(phost, 0x00); + + if(req_status == USBH_OK ) + { + /*Change the state to waiting*/ + CDC_Handle->state = CDC_IDLE_STATE ; + } + break; + + default: + break; + + } + + return status; +} + +/** + * @brief USBH_CDC_SOFProcess + * The function is for managing SOF callback + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_CDC_SOFProcess (USBH_HandleTypeDef *phost) +{ + return USBH_OK; +} + + + /** + * @brief USBH_CDC_Stop + * Stop current CDC Transmission + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_CDC_Stop(USBH_HandleTypeDef *phost) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if(phost->gState == HOST_CLASS) + { + CDC_Handle->state = CDC_IDLE_STATE; + + USBH_ClosePipe(phost, CDC_Handle->CommItf.NotifPipe); + USBH_ClosePipe(phost, CDC_Handle->DataItf.InPipe); + USBH_ClosePipe(phost, CDC_Handle->DataItf.OutPipe); + } + return USBH_OK; +} +/** + * @brief This request allows the host to find out the currently + * configured line coding. + * @param pdev: Selected device + * @retval USBH_StatusTypeDef : USB ctl xfer status + */ +static USBH_StatusTypeDef GetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecoding) +{ + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ + USB_REQ_RECIPIENT_INTERFACE; + + phost->Control.setup.b.bRequest = CDC_GET_LINE_CODING; + phost->Control.setup.b.wValue.w = 0; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = LINE_CODING_STRUCTURE_SIZE; + + return USBH_CtlReq(phost, linecoding->Array, LINE_CODING_STRUCTURE_SIZE); +} + + +/** + * @brief This request allows the host to specify typical asynchronous + * line-character formatting properties + * This request applies to asynchronous byte stream data class interfaces + * and endpoints + * @param pdev: Selected device + * @retval USBH_StatusTypeDef : USB ctl xfer status + */ +static USBH_StatusTypeDef SetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin) +{ + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \ + USB_REQ_RECIPIENT_INTERFACE; + + phost->Control.setup.b.bRequest = CDC_SET_LINE_CODING; + phost->Control.setup.b.wValue.w = 0; + + phost->Control.setup.b.wIndex.w = 0; + + phost->Control.setup.b.wLength.w = LINE_CODING_STRUCTURE_SIZE; + + return USBH_CtlReq(phost, linecodin->Array , LINE_CODING_STRUCTURE_SIZE ); +} + +/** +* @brief This function prepares the state before issuing the class specific commands +* @param None +* @retval None +*/ +USBH_StatusTypeDef USBH_CDC_SetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + if(phost->gState == HOST_CLASS) + { + CDC_Handle->state = CDC_SET_LINE_CODING_STATE; + CDC_Handle->pUserLineCoding = linecodin; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + } + return USBH_OK; +} + +/** +* @brief This function prepares the state before issuing the class specific commands +* @param None +* @retval None +*/ +USBH_StatusTypeDef USBH_CDC_GetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecodin) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if((phost->gState == HOST_CLASS) ||(phost->gState == HOST_CLASS_REQUEST)) + { + *linecodin = CDC_Handle->LineCoding; + return USBH_OK; + } + else + { + return USBH_FAIL; + } +} + +/** + * @brief This function return last recieved data size + * @param None + * @retval None + */ +uint16_t USBH_CDC_GetLastReceivedDataSize(USBH_HandleTypeDef *phost) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if(phost->gState == HOST_CLASS) + { + return USBH_LL_GetLastXferSize(phost, CDC_Handle->DataItf.InPipe);; + } + else + { + return 0; + } +} + +/** + * @brief This function prepares the state before issuing the class specific commands + * @param None + * @retval None + */ +USBH_StatusTypeDef USBH_CDC_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length) +{ + USBH_StatusTypeDef Status = USBH_BUSY; + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if((CDC_Handle->state == CDC_IDLE_STATE) || (CDC_Handle->state == CDC_TRANSFER_DATA)) + { + CDC_Handle->pTxData = pbuff; + CDC_Handle->TxDataLength = length; + CDC_Handle->state = CDC_TRANSFER_DATA; + CDC_Handle->data_tx_state = CDC_SEND_DATA; + Status = USBH_OK; + } + return Status; +} + + +/** +* @brief This function prepares the state before issuing the class specific commands +* @param None +* @retval None +*/ +USBH_StatusTypeDef USBH_CDC_Receive(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length) +{ + USBH_StatusTypeDef Status = USBH_BUSY; + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + + if((CDC_Handle->state == CDC_IDLE_STATE) || (CDC_Handle->state == CDC_TRANSFER_DATA)) + { + CDC_Handle->pRxData = pbuff; + CDC_Handle->RxDataLength = length; + CDC_Handle->state = CDC_TRANSFER_DATA; + CDC_Handle->data_rx_state = CDC_RECEIVE_DATA; + Status = USBH_OK; + } + return Status; +} + +/** +* @brief The function is responsible for sending data to the device +* @param pdev: Selected device +* @retval None +*/ +static void CDC_ProcessTransmission(USBH_HandleTypeDef *phost) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; + + switch(CDC_Handle->data_tx_state) + { + + case CDC_SEND_DATA: + if(CDC_Handle->TxDataLength > CDC_Handle->DataItf.OutEpSize) + { + USBH_BulkSendData (phost, + CDC_Handle->pTxData, + CDC_Handle->DataItf.OutEpSize, + CDC_Handle->DataItf.OutPipe, + 1); + } + else + { + USBH_BulkSendData (phost, + CDC_Handle->pTxData, + CDC_Handle->TxDataLength, + CDC_Handle->DataItf.OutPipe, + 1); + } + + CDC_Handle->data_tx_state = CDC_SEND_DATA_WAIT; + + break; + + case CDC_SEND_DATA_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.OutPipe); + + /*Check the status done for transmssion*/ + if(URB_Status == USBH_URB_DONE ) + { + if(CDC_Handle->TxDataLength > CDC_Handle->DataItf.OutEpSize) + { + CDC_Handle->TxDataLength -= CDC_Handle->DataItf.OutEpSize ; + CDC_Handle->pTxData += CDC_Handle->DataItf.OutEpSize; + } + else + { + CDC_Handle->TxDataLength = 0; + } + + if( CDC_Handle->TxDataLength > 0) + { + CDC_Handle->data_tx_state = CDC_SEND_DATA; + } + else + { + CDC_Handle->data_tx_state = CDC_IDLE; + USBH_CDC_TransmitCallback(phost); + + } + } + else if( URB_Status == USBH_URB_NOTREADY ) + { + CDC_Handle->data_tx_state = CDC_SEND_DATA; + } + break; + default: + break; + } +} +/** +* @brief This function responsible for reception of data from the device +* @param pdev: Selected device +* @retval None +*/ + +static void CDC_ProcessReception(USBH_HandleTypeDef *phost) +{ + CDC_HandleTypeDef *CDC_Handle = phost->pActiveClass->pData; + USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; + uint16_t length; + + switch(CDC_Handle->data_rx_state) + { + + case CDC_RECEIVE_DATA: + + USBH_BulkReceiveData (phost, + CDC_Handle->pRxData, + CDC_Handle->DataItf.InEpSize, + CDC_Handle->DataItf.InPipe); + + CDC_Handle->data_rx_state = CDC_RECEIVE_DATA_WAIT; + + break; + + case CDC_RECEIVE_DATA_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.InPipe); + + /*Check the status done for reception*/ + if(URB_Status == USBH_URB_DONE ) + { + length = USBH_LL_GetLastXferSize(phost, CDC_Handle->DataItf.InPipe); + + if(((CDC_Handle->RxDataLength - length) > 0) && (length > CDC_Handle->DataItf.InEpSize)) + { + CDC_Handle->RxDataLength -= length ; + CDC_Handle->pRxData += length; + CDC_Handle->data_rx_state = CDC_RECEIVE_DATA; + } + else + { + CDC_Handle->data_rx_state = CDC_IDLE; + USBH_CDC_ReceiveCallback(phost); + } + } + break; + + default: + break; + } +} + +/** +* @brief The function informs user that data have been received +* @param pdev: Selected device +* @retval None +*/ +__weak void USBH_CDC_TransmitCallback(USBH_HandleTypeDef *phost) +{ + +} + + /** +* @brief The function informs user that data have been sent +* @param pdev: Selected device +* @retval None +*/ +__weak void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost) +{ + +} + + /** +* @brief The function informs user that Settings have been changed +* @param pdev: Selected device +* @retval None +*/ +__weak void USBH_CDC_LineCodingChanged(USBH_HandleTypeDef *phost) +{ + +} + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h new file mode 100755 index 0000000..38302ad --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid.h @@ -0,0 +1,341 @@ +/** + ****************************************************************************** + * @file usbh_hid.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_hid.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_HID_H +#define __USBH_HID_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" +#include "usbh_hid_mouse.h" +#include "usbh_hid_keybd.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_CORE + * @brief This file is the Header file for USBH_HID_CORE.c + * @{ + */ + + +/** @defgroup USBH_HID_CORE_Exported_Types + * @{ + */ + +#define HID_MIN_POLL 10 +#define HID_REPORT_SIZE 16 +#define HID_MAX_USAGE 10 +#define HID_MAX_NBR_REPORT_FMT 10 +#define HID_QUEUE_SIZE 10 + +#define HID_ITEM_LONG 0xFE + +#define HID_ITEM_TYPE_MAIN 0x00 +#define HID_ITEM_TYPE_GLOBAL 0x01 +#define HID_ITEM_TYPE_LOCAL 0x02 +#define HID_ITEM_TYPE_RESERVED 0x03 + + +#define HID_MAIN_ITEM_TAG_INPUT 0x08 +#define HID_MAIN_ITEM_TAG_OUTPUT 0x09 +#define HID_MAIN_ITEM_TAG_COLLECTION 0x0A +#define HID_MAIN_ITEM_TAG_FEATURE 0x0B +#define HID_MAIN_ITEM_TAG_ENDCOLLECTION 0x0C + + +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0x00 +#define HID_GLOBAL_ITEM_TAG_LOG_MIN 0x01 +#define HID_GLOBAL_ITEM_TAG_LOG_MAX 0x02 +#define HID_GLOBAL_ITEM_TAG_PHY_MIN 0x03 +#define HID_GLOBAL_ITEM_TAG_PHY_MAX 0x04 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 0x05 +#define HID_GLOBAL_ITEM_TAG_UNIT 0x06 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 0x07 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 0x08 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 0x09 +#define HID_GLOBAL_ITEM_TAG_PUSH 0x0A +#define HID_GLOBAL_ITEM_TAG_POP 0x0B + + +#define HID_LOCAL_ITEM_TAG_USAGE 0x00 +#define HID_LOCAL_ITEM_TAG_USAGE_MIN 0x01 +#define HID_LOCAL_ITEM_TAG_USAGE_MAX 0x02 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 0x03 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MIN 0x04 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAX 0x05 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 0x07 +#define HID_LOCAL_ITEM_TAG_STRING_MIN 0x08 +#define HID_LOCAL_ITEM_TAG_STRING_MAX 0x09 +#define HID_LOCAL_ITEM_TAG_DELIMITER 0x0A + + +/* States for HID State Machine */ +typedef enum +{ + HID_INIT= 0, + HID_IDLE, + HID_SEND_DATA, + HID_BUSY, + HID_GET_DATA, + HID_SYNC, + HID_POLL, + HID_ERROR, +} +HID_StateTypeDef; + +typedef enum +{ + HID_REQ_INIT = 0, + HID_REQ_IDLE, + HID_REQ_GET_REPORT_DESC, + HID_REQ_GET_HID_DESC, + HID_REQ_SET_IDLE, + HID_REQ_SET_PROTOCOL, + HID_REQ_SET_REPORT, + +} +HID_CtlStateTypeDef; + +typedef enum +{ + HID_MOUSE = 0x01, + HID_KEYBOARD = 0x02, + HID_UNKNOWN = 0xFF, +} +HID_TypeTypeDef; + + +typedef struct _HID_ReportData +{ + uint8_t ReportID; + uint8_t ReportType; + uint16_t UsagePage; + uint32_t Usage[HID_MAX_USAGE]; + uint32_t NbrUsage; + uint32_t UsageMin; + uint32_t UsageMax; + int32_t LogMin; + int32_t LogMax; + int32_t PhyMin; + int32_t PhyMax; + int32_t UnitExp; + uint32_t Unit; + uint32_t ReportSize; + uint32_t ReportCnt; + uint32_t Flag; + uint32_t PhyUsage; + uint32_t AppUsage; + uint32_t LogUsage; +} +HID_ReportDataTypeDef; + +typedef struct _HID_ReportIDTypeDef { + uint8_t Size; /* Report size return by the device id */ + uint8_t ReportID; /* Report Id */ + uint8_t Type; /* Report Type (INPUT/OUTPUT/FEATURE) */ +} HID_ReportIDTypeDef; + +typedef struct _HID_CollectionTypeDef +{ + uint32_t Usage; + uint8_t Type; + struct _HID_CollectionTypeDef *NextPtr; +} HID_CollectionTypeDef; + + +typedef struct _HID_AppCollectionTypeDef { + uint32_t Usage; + uint8_t Type; + uint8_t NbrReportFmt; + HID_ReportDataTypeDef ReportData[HID_MAX_NBR_REPORT_FMT]; +} HID_AppCollectionTypeDef; + + +typedef struct _HIDDescriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; /* indicates what endpoint this descriptor is describing */ + uint8_t bCountryCode; /* specifies the transfer type. */ + uint8_t bNumDescriptors; /* specifies the transfer type. */ + uint8_t bReportDescriptorType; /* Maximum Packet Size this endpoint is capable of sending or receiving */ + uint16_t wItemLength; /* is used to specify the polling interval of certain transfers. */ +} +HID_DescTypeDef; + + +typedef struct +{ + uint8_t *buf; + uint16_t head; + uint16_t tail; + uint16_t size; + uint8_t lock; +} FIFO_TypeDef; + + +/* Structure for HID process */ +typedef struct _HID_Process +{ + uint8_t OutPipe; + uint8_t InPipe; + HID_StateTypeDef state; + uint8_t OutEp; + uint8_t InEp; + HID_CtlStateTypeDef ctl_state; + FIFO_TypeDef fifo; + uint8_t *pData; + uint16_t length; + uint8_t ep_addr; + uint16_t poll; + uint16_t timer; + uint8_t DataReady; + HID_DescTypeDef HID_Desc; + USBH_StatusTypeDef ( * Init)(USBH_HandleTypeDef *phost); +} +HID_HandleTypeDef; + +/** + * @} + */ + +/** @defgroup USBH_HID_CORE_Exported_Defines + * @{ + */ + +#define USB_HID_GET_REPORT 0x01 +#define USB_HID_GET_IDLE 0x02 +#define USB_HID_GET_PROTOCOL 0x03 +#define USB_HID_SET_REPORT 0x09 +#define USB_HID_SET_IDLE 0x0A +#define USB_HID_SET_PROTOCOL 0x0B + + + + +/* HID Class Codes */ +#define USB_HID_CLASS 0x03 + +/* Interface Descriptor field values for HID Boot Protocol */ +#define HID_BOOT_CODE 0x01 +#define HID_KEYBRD_BOOT_CODE 0x01 +#define HID_MOUSE_BOOT_CODE 0x02 + + +/** + * @} + */ + +/** @defgroup USBH_HID_CORE_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_CORE_Exported_Variables + * @{ + */ +extern USBH_ClassTypeDef HID_Class; +#define USBH_HID_CLASS &HID_Class +/** + * @} + */ + +/** @defgroup USBH_HID_CORE_Exported_FunctionsPrototype + * @{ + */ + +USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost, + uint8_t reportType, + uint8_t reportId, + uint8_t* reportBuff, + uint8_t reportLen); + +USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost, + uint8_t reportType, + uint8_t reportId, + uint8_t* reportBuff, + uint8_t reportLen); + +USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost, + uint16_t length); + +USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost, + uint16_t length); + +USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost, + uint8_t duration, + uint8_t reportId); + +USBH_StatusTypeDef USBH_HID_SetProtocol (USBH_HandleTypeDef *phost, + uint8_t protocol); + +void USBH_HID_EventCallback(USBH_HandleTypeDef *phost); + +HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost); + +void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size); + +uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes); + +uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes); + +/** + * @} + */ + + +#endif /* __USBH_HID_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h new file mode 100755 index 0000000..dc72ebb --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_keybd.h @@ -0,0 +1,318 @@ +/** + ****************************************************************************** + * @file usbh_hid_keybd.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_hid_keybd.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive -----------------------------------------------*/ +#ifndef __USBH_HID_KEYBD_H +#define __USBH_HID_KEYBD_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid.h" +#include "usbh_hid_keybd.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_KEYBD + * @brief This file is the Header file for USBH_HID_KEYBD.c + * @{ + */ + + +/** @defgroup USBH_HID_KEYBD_Exported_Types + * @{ + */ +#define KEY_NONE 0x00 +#define KEY_ERRORROLLOVER 0x01 +#define KEY_POSTFAIL 0x02 +#define KEY_ERRORUNDEFINED 0x03 +#define KEY_A 0x04 +#define KEY_B 0x05 +#define KEY_C 0x06 +#define KEY_D 0x07 +#define KEY_E 0x08 +#define KEY_F 0x09 +#define KEY_G 0x0A +#define KEY_H 0x0B +#define KEY_I 0x0C +#define KEY_J 0x0D +#define KEY_K 0x0E +#define KEY_L 0x0F +#define KEY_M 0x10 +#define KEY_N 0x11 +#define KEY_O 0x12 +#define KEY_P 0x13 +#define KEY_Q 0x14 +#define KEY_R 0x15 +#define KEY_S 0x16 +#define KEY_T 0x17 +#define KEY_U 0x18 +#define KEY_V 0x19 +#define KEY_W 0x1A +#define KEY_X 0x1B +#define KEY_Y 0x1C +#define KEY_Z 0x1D +#define KEY_1_EXCLAMATION_MARK 0x1E +#define KEY_2_AT 0x1F +#define KEY_3_NUMBER_SIGN 0x20 +#define KEY_4_DOLLAR 0x21 +#define KEY_5_PERCENT 0x22 +#define KEY_6_CARET 0x23 +#define KEY_7_AMPERSAND 0x24 +#define KEY_8_ASTERISK 0x25 +#define KEY_9_OPARENTHESIS 0x26 +#define KEY_0_CPARENTHESIS 0x27 +#define KEY_ENTER 0x28 +#define KEY_ESCAPE 0x29 +#define KEY_BACKSPACE 0x2A +#define KEY_TAB 0x2B +#define KEY_SPACEBAR 0x2C +#define KEY_MINUS_UNDERSCORE 0x2D +#define KEY_EQUAL_PLUS 0x2E +#define KEY_OBRACKET_AND_OBRACE 0x2F +#define KEY_CBRACKET_AND_CBRACE 0x30 +#define KEY_BACKSLASH_VERTICAL_BAR 0x31 +#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32 +#define KEY_SEMICOLON_COLON 0x33 +#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34 +#define KEY_GRAVE ACCENT AND TILDE 0x35 +#define KEY_COMMA_AND_LESS 0x36 +#define KEY_DOT_GREATER 0x37 +#define KEY_SLASH_QUESTION 0x38 +#define KEY_CAPS LOCK 0x39 +#define KEY_F1 0x3A +#define KEY_F2 0x3B +#define KEY_F3 0x3C +#define KEY_F4 0x3D +#define KEY_F5 0x3E +#define KEY_F6 0x3F +#define KEY_F7 0x40 +#define KEY_F8 0x41 +#define KEY_F9 0x42 +#define KEY_F10 0x43 +#define KEY_F11 0x44 +#define KEY_F12 0x45 +#define KEY_PRINTSCREEN 0x46 +#define KEY_SCROLL LOCK 0x47 +#define KEY_PAUSE 0x48 +#define KEY_INSERT 0x49 +#define KEY_HOME 0x4A +#define KEY_PAGEUP 0x4B +#define KEY_DELETE 0x4C +#define KEY_END1 0x4D +#define KEY_PAGEDOWN 0x4E +#define KEY_RIGHTARROW 0x4F +#define KEY_LEFTARROW 0x50 +#define KEY_DOWNARROW 0x51 +#define KEY_UPARROW 0x52 +#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53 +#define KEY_KEYPAD_SLASH 0x54 +#define KEY_KEYPAD_ASTERIKS 0x55 +#define KEY_KEYPAD_MINUS 0x56 +#define KEY_KEYPAD_PLUS 0x57 +#define KEY_KEYPAD_ENTER 0x58 +#define KEY_KEYPAD_1_END 0x59 +#define KEY_KEYPAD_2_DOWN_ARROW 0x5A +#define KEY_KEYPAD_3_PAGEDN 0x5B +#define KEY_KEYPAD_4_LEFT_ARROW 0x5C +#define KEY_KEYPAD_5 0x5D +#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E +#define KEY_KEYPAD_7_HOME 0x5F +#define KEY_KEYPAD_8_UP_ARROW 0x60 +#define KEY_KEYPAD_9_PAGEUP 0x61 +#define KEY_KEYPAD_0_INSERT 0x62 +#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63 +#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64 +#define KEY_APPLICATION 0x65 +#define KEY_POWER 0x66 +#define KEY_KEYPAD_EQUAL 0x67 +#define KEY_F13 0x68 +#define KEY_F14 0x69 +#define KEY_F15 0x6A +#define KEY_F16 0x6B +#define KEY_F17 0x6C +#define KEY_F18 0x6D +#define KEY_F19 0x6E +#define KEY_F20 0x6F +#define KEY_F21 0x70 +#define KEY_F22 0x71 +#define KEY_F23 0x72 +#define KEY_F24 0x73 +#define KEY_EXECUTE 0x74 +#define KEY_HELP 0x75 +#define KEY_MENU 0x76 +#define KEY_SELECT 0x77 +#define KEY_STOP 0x78 +#define KEY_AGAIN 0x79 +#define KEY_UNDO 0x7A +#define KEY_CUT 0x7B +#define KEY_COPY 0x7C +#define KEY_PASTE 0x7D +#define KEY_FIND 0x7E +#define KEY_MUTE 0x7F +#define KEY_VOLUME_UP 0x80 +#define KEY_VOLUME_DOWN 0x81 +#define KEY_LOCKING_CAPS_LOCK 0x82 +#define KEY_LOCKING_NUM_LOCK 0x83 +#define KEY_LOCKING_SCROLL_LOCK 0x84 +#define KEY_KEYPAD_COMMA 0x85 +#define KEY_KEYPAD_EQUAL_SIGN 0x86 +#define KEY_INTERNATIONAL1 0x87 +#define KEY_INTERNATIONAL2 0x88 +#define KEY_INTERNATIONAL3 0x89 +#define KEY_INTERNATIONAL4 0x8A +#define KEY_INTERNATIONAL5 0x8B +#define KEY_INTERNATIONAL6 0x8C +#define KEY_INTERNATIONAL7 0x8D +#define KEY_INTERNATIONAL8 0x8E +#define KEY_INTERNATIONAL9 0x8F +#define KEY_LANG1 0x90 +#define KEY_LANG2 0x91 +#define KEY_LANG3 0x92 +#define KEY_LANG4 0x93 +#define KEY_LANG5 0x94 +#define KEY_LANG6 0x95 +#define KEY_LANG7 0x96 +#define KEY_LANG8 0x97 +#define KEY_LANG9 0x98 +#define KEY_ALTERNATE_ERASE 0x99 +#define KEY_SYSREQ 0x9A +#define KEY_CANCEL 0x9B +#define KEY_CLEAR 0x9C +#define KEY_PRIOR 0x9D +#define KEY_RETURN 0x9E +#define KEY_SEPARATOR 0x9F +#define KEY_OUT 0xA0 +#define KEY_OPER 0xA1 +#define KEY_CLEAR_AGAIN 0xA2 +#define KEY_CRSEL 0xA3 +#define KEY_EXSEL 0xA4 +#define KEY_KEYPAD_00 0xB0 +#define KEY_KEYPAD_000 0xB1 +#define KEY_THOUSANDS_SEPARATOR 0xB2 +#define KEY_DECIMAL_SEPARATOR 0xB3 +#define KEY_CURRENCY_UNIT 0xB4 +#define KEY_CURRENCY_SUB_UNIT 0xB5 +#define KEY_KEYPAD_OPARENTHESIS 0xB6 +#define KEY_KEYPAD_CPARENTHESIS 0xB7 +#define KEY_KEYPAD_OBRACE 0xB8 +#define KEY_KEYPAD_CBRACE 0xB9 +#define KEY_KEYPAD_TAB 0xBA +#define KEY_KEYPAD_BACKSPACE 0xBB +#define KEY_KEYPAD_A 0xBC +#define KEY_KEYPAD_B 0xBD +#define KEY_KEYPAD_C 0xBE +#define KEY_KEYPAD_D 0xBF +#define KEY_KEYPAD_E 0xC0 +#define KEY_KEYPAD_F 0xC1 +#define KEY_KEYPAD_XOR 0xC2 +#define KEY_KEYPAD_CARET 0xC3 +#define KEY_KEYPAD_PERCENT 0xC4 +#define KEY_KEYPAD_LESS 0xC5 +#define KEY_KEYPAD_GREATER 0xC6 +#define KEY_KEYPAD_AMPERSAND 0xC7 +#define KEY_KEYPAD_LOGICAL_AND 0xC8 +#define KEY_KEYPAD_VERTICAL_BAR 0xC9 +#define KEY_KEYPAD_LOGIACL_OR 0xCA +#define KEY_KEYPAD_COLON 0xCB +#define KEY_KEYPAD_NUMBER_SIGN 0xCC +#define KEY_KEYPAD_SPACE 0xCD +#define KEY_KEYPAD_AT 0xCE +#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF +#define KEY_KEYPAD_MEMORY_STORE 0xD0 +#define KEY_KEYPAD_MEMORY_RECALL 0xD1 +#define KEY_KEYPAD_MEMORY_CLEAR 0xD2 +#define KEY_KEYPAD_MEMORY_ADD 0xD3 +#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4 +#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5 +#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6 +#define KEY_KEYPAD_PLUSMINUS 0xD7 +#define KEY_KEYPAD_CLEAR 0xD8 +#define KEY_KEYPAD_CLEAR_ENTRY 0xD9 +#define KEY_KEYPAD_BINARY 0xDA +#define KEY_KEYPAD_OCTAL 0xDB +#define KEY_KEYPAD_DECIMAL 0xDC +#define KEY_KEYPAD_HEXADECIMAL 0xDD +#define KEY_LEFTCONTROL 0xE0 +#define KEY_LEFTSHIFT 0xE1 +#define KEY_LEFTALT 0xE2 +#define KEY_LEFT_GUI 0xE3 +#define KEY_RIGHTCONTROL 0xE4 +#define KEY_RIGHTSHIFT 0xE5 +#define KEY_RIGHTALT 0xE6 +#define KEY_RIGHT_GUI 0xE7 + +typedef struct +{ + uint8_t state; + uint8_t lctrl; + uint8_t lshift; + uint8_t lalt; + uint8_t lgui; + uint8_t rctrl; + uint8_t rshift; + uint8_t ralt; + uint8_t rgui; + uint8_t keys[6]; +} +HID_KEYBD_Info_TypeDef; + +USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost); +HID_KEYBD_Info_TypeDef *USBH_HID_GetKeybdInfo(USBH_HandleTypeDef *phost); +uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info); + +/** + * @} + */ + +#endif /* __USBH_HID_KEYBD_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h new file mode 100755 index 0000000..3a87d1a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_mouse.h @@ -0,0 +1,118 @@ +/** + ****************************************************************************** + * @file usbh_hid_mouse.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_hid_mouse.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_HID_MOUSE_H +#define __USBH_HID_MOUSE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_MOUSE + * @brief This file is the Header file for USBH_HID_MOUSE.c + * @{ + */ + + +/** @defgroup USBH_HID_MOUSE_Exported_Types + * @{ + */ + +typedef struct _HID_MOUSE_Info +{ + uint8_t x; + uint8_t y; + uint8_t buttons[3]; +} +HID_MOUSE_Info_TypeDef; + +/** + * @} + */ + +/** @defgroup USBH_HID_MOUSE_Exported_Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_MOUSE_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_MOUSE_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_MOUSE_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost); +HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost); + +/** + * @} + */ + +#endif /* __USBH_HID_MOUSE_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h new file mode 100755 index 0000000..0bf5739 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_parser.h @@ -0,0 +1,96 @@ +/** + ****************************************************************************** + * @file usbh_hid_parser.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the header file of the usbh_hid_parser.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +#ifndef _HID_PARSER_H_ +#define _HID_PARSER_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid.h" +#include "usbh_hid_usage.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_PARSER + * @brief This file is the Header file for USBH_HID_PARSER.c + * @{ + */ + + +/** @defgroup USBH_HID_PARSER_Exported_Types + * @{ + */ +typedef struct +{ + uint8_t *data; + uint32_t size; + uint8_t shift; + uint8_t count; + uint8_t sign; + uint32_t logical_min; /*min value device can return*/ + uint32_t logical_max; /*max value device can return*/ + uint32_t physical_min; /*min vale read can report*/ + uint32_t physical_max; /*max value read can report*/ + uint32_t resolution; +} +HID_Report_ItemTypedef; + + +uint32_t HID_ReadItem (HID_Report_ItemTypedef *ri, uint8_t ndx); +uint32_t HID_WriteItem(HID_Report_ItemTypedef *ri, uint32_t value, uint8_t ndx); + + +/** + * @} + */ + +#endif /* _HID_PARSER_H_ */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h new file mode 100755 index 0000000..e1f7762 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Inc/usbh_hid_usage.h @@ -0,0 +1,191 @@ +/** + ****************************************************************************** + * @file usbh_hid_keybd.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contain the USAGE page codes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +#ifndef _HID_USAGE_H_ +#define _HID_USAGE_H_ + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_USAGE + * @brief This file is the Header file for USBH_HID_USAGE.c + * @{ + */ + + +/** @defgroup USBH_HID_USAGE_Exported_Types + * @{ + */ + +/****************************************************/ +/* HID 1.11 usage pages */ +/****************************************************/ + +#define HID_USAGE_PAGE_UNDEFINED uint16_t (0x00) /* Undefined */ +/**** Top level pages */ +#define HID_USAGE_PAGE_GEN_DES uint16_t (0x01) /* Generic Desktop Controls*/ +#define HID_USAGE_PAGE_SIM_CTR uint16_t (0x02) /* Simulation Controls */ +#define HID_USAGE_PAGE_VR_CTR uint16_t (0x03) /* VR Controls */ +#define HID_USAGE_PAGE_SPORT_CTR uint16_t (0x04) /* Sport Controls */ +#define HID_USAGE_PAGE_GAME_CTR uint16_t (0x05) /* Game Controls */ +#define HID_USAGE_PAGE_GEN_DEV uint16_t (0x06) /* Generic Device Controls */ +#define HID_USAGE_PAGE_KEYB uint16_t (0x07) /* Keyboard/Keypad */ +#define HID_USAGE_PAGE_LED uint16_t (0x08) /* LEDs */ +#define HID_USAGE_PAGE_BUTTON uint16_t (0x09) /* Button */ +#define HID_USAGE_PAGE_ORDINAL uint16_t (0x0A) /* Ordinal */ +#define HID_USAGE_PAGE_PHONE uint16_t (0x0B) /* Telephony */ +#define HID_USAGE_PAGE_CONSUMER uint16_t (0x0C) /* Consumer */ +#define HID_USAGE_PAGE_DIGITIZER uint16_t (0x0D) /* Digitizer*/ +/* 0E Reserved */ +#define HID_USAGE_PAGE_PID uint16_t (0x0F) /* PID Page (force feedback and related devices) */ +#define HID_USAGE_PAGE_UNICODE uint16_t (0x10) /* Unicode */ +/* 11-13 Reserved */ +#define HID_USAGE_PAGE_ALNUM_DISP uint16_t (0x14) /* Alphanumeric Display */ +/* 15-1f Reserved */ +/**** END of top level pages */ +/* 25-3f Reserved */ +#define HID_USAGE_PAGE_MEDICAL uint16_t (0x40) /* Medical Instruments */ +/* 41-7F Reserved */ +/*80-83 Monitor pages USB Device Class Definition for Monitor Devices + 84-87 Power pages USB Device Class Definition for Power Devices */ +/* 88-8B Reserved */ +#define HID_USAGE_PAGE_BARCODE uint16_t (0x8C) /* Bar Code Scanner page */ +#define HID_USAGE_PAGE_SCALE uint16_t (0x8D) /* Scale page */ +#define HID_USAGE_PAGE_MSR uint16_t (0x8E) /* Magnetic Stripe Reading (MSR) Devices */ +#define HID_USAGE_PAGE_POS uint16_t (0x8F) /* Reserved Point of Sale pages */ +#define HID_USAGE_PAGE_CAMERA_CTR uint16_t (0x90) /* Camera Control Page */ +#define HID_USAGE_PAGE_ARCADE uint16_t (0x91) /* Arcade Page */ + +/****************************************************/ +/* Usage definitions for the "Generic Decktop" page */ +/****************************************************/ +#define HID_USAGE_UNDEFINED uint16_t (0x00) /* Undefined */ +#define HID_USAGE_POINTER uint16_t (0x01) /* Pointer (Physical Collection) */ +#define HID_USAGE_MOUSE uint16_t (0x02) /* Mouse (Application Collection) */ +/* 03 Reserved */ +#define HID_USAGE_JOYSTICK uint16_t (0x04) /* Joystick (Application Collection) */ +#define HID_USAGE_GAMEPAD uint16_t (0x05) /* Game Pad (Application Collection) */ +#define HID_USAGE_KBD uint16_t (0x06) /* Keyboard (Application Collection) */ +#define HID_USAGE_KEYPAD uint16_t (0x07) /* Keypad (Application Collection) */ +#define HID_USAGE_MAX_CTR uint16_t (0x08) /* Multi-axis Controller (Application Collection) */ +/* 09-2F Reserved */ +#define HID_USAGE_X uint16_t (0x30) /* X (Dynamic Value) */ +#define HID_USAGE_Y uint16_t (0x31) /* Y (Dynamic Value) */ +#define HID_USAGE_Z uint16_t (0x32) /* Z (Dynamic Value) */ +#define HID_USAGE_RX uint16_t (0x33) /* Rx (Dynamic Value) */ +#define HID_USAGE_RY uint16_t (0x34) /* Ry (Dynamic Value) */ +#define HID_USAGE_RZ uint16_t (0x35) /* Rz (Dynamic Value) */ +#define HID_USAGE_SLIDER uint16_t (0x36) /* Slider (Dynamic Value) */ +#define HID_USAGE_DIAL uint16_t (0x37) /* Dial (Dynamic Value) */ +#define HID_USAGE_WHEEL uint16_t (0x38) /* Wheel (Dynamic Value) */ +#define HID_USAGE_HATSW uint16_t (0x39) /* Hat switch (Dynamic Value) */ +#define HID_USAGE_COUNTEDBUF uint16_t (0x3A) /* Counted Buffer (Logical Collection) */ +#define HID_USAGE_BYTECOUNT uint16_t (0x3B) /* Byte Count (Dynamic Value) */ +#define HID_USAGE_MOTIONWAKE uint16_t (0x3C) /* Motion Wakeup (One Shot Control) */ +#define HID_USAGE_START uint16_t (0x3D) /* Start (On/Off Control) */ +#define HID_USAGE_SELECT uint16_t (0x3E) /* Select (On/Off Control) */ +/* 3F Reserved */ +#define HID_USAGE_VX uint16_t (0x40) /* Vx (Dynamic Value) */ +#define HID_USAGE_VY uint16_t (0x41) /* Vy (Dynamic Value) */ +#define HID_USAGE_VZ uint16_t (0x42) /* Vz (Dynamic Value) */ +#define HID_USAGE_VBRX uint16_t (0x43) /* Vbrx (Dynamic Value) */ +#define HID_USAGE_VBRY uint16_t (0x44) /* Vbry (Dynamic Value) */ +#define HID_USAGE_VBRZ uint16_t (0x45) /* Vbrz (Dynamic Value) */ +#define HID_USAGE_VNO uint16_t (0x46) /* Vno (Dynamic Value) */ +#define HID_USAGE_FEATNOTIF uint16_t (0x47) /* Feature Notification (Dynamic Value),(Dynamic Flag) */ +/* 48-7F Reserved */ +#define HID_USAGE_SYSCTL uint16_t (0x80) /* System Control (Application Collection) */ +#define HID_USAGE_PWDOWN uint16_t (0x81) /* System Power Down (One Shot Control) */ +#define HID_USAGE_SLEEP uint16_t (0x82) /* System Sleep (One Shot Control) */ +#define HID_USAGE_WAKEUP uint16_t (0x83) /* System Wake Up (One Shot Control) */ +#define HID_USAGE_CONTEXTM uint16_t (0x84) /* System Context Menu (One Shot Control) */ +#define HID_USAGE_MAINM uint16_t (0x85) /* System Main Menu (One Shot Control) */ +#define HID_USAGE_APPM uint16_t (0x86) /* System App Menu (One Shot Control) */ +#define HID_USAGE_MENUHELP uint16_t (0x87) /* System Menu Help (One Shot Control) */ +#define HID_USAGE_MENUEXIT uint16_t (0x88) /* System Menu Exit (One Shot Control) */ +#define HID_USAGE_MENUSELECT uint16_t (0x89) /* System Menu Select (One Shot Control) */ +#define HID_USAGE_SYSM_RIGHT uint16_t (0x8A) /* System Menu Right (Re-Trigger Control) */ +#define HID_USAGE_SYSM_LEFT uint16_t (0x8B) /* System Menu Left (Re-Trigger Control) */ +#define HID_USAGE_SYSM_UP uint16_t (0x8C) /* System Menu Up (Re-Trigger Control) */ +#define HID_USAGE_SYSM_DOWN uint16_t (0x8D) /* System Menu Down (Re-Trigger Control) */ +#define HID_USAGE_COLDRESET uint16_t (0x8E) /* System Cold Restart (One Shot Control) */ +#define HID_USAGE_WARMRESET uint16_t (0x8F) /* System Warm Restart (One Shot Control) */ +#define HID_USAGE_DUP uint16_t (0x90) /* D-pad Up (On/Off Control) */ +#define HID_USAGE_DDOWN uint16_t (0x91) /* D-pad Down (On/Off Control) */ +#define HID_USAGE_DRIGHT uint16_t (0x92) /* D-pad Right (On/Off Control) */ +#define HID_USAGE_DLEFT uint16_t (0x93) /* D-pad Left (On/Off Control) */ +/* 94-9F Reserved */ +#define HID_USAGE_SYS_DOCK uint16_t (0xA0) /* System Dock (One Shot Control) */ +#define HID_USAGE_SYS_UNDOCK uint16_t (0xA1) /* System Undock (One Shot Control) */ +#define HID_USAGE_SYS_SETUP uint16_t (0xA2) /* System Setup (One Shot Control) */ +#define HID_USAGE_SYS_BREAK uint16_t (0xA3) /* System Break (One Shot Control) */ +#define HID_USAGE_SYS_DBGBRK uint16_t (0xA4) /* System Debugger Break (One Shot Control) */ +#define HID_USAGE_APP_BRK uint16_t (0xA5) /* Application Break (One Shot Control) */ +#define HID_USAGE_APP_DBGBRK uint16_t (0xA6) /* Application Debugger Break (One Shot Control) */ +#define HID_USAGE_SYS_SPKMUTE uint16_t (0xA7) /* System Speaker Mute (One Shot Control) */ +#define HID_USAGE_SYS_HIBERN uint16_t (0xA8) /* System Hibernate (One Shot Control) */ +/* A9-AF Reserved */ +#define HID_USAGE_SYS_SIDPINV uint16_t (0xB0) /* System Display Invert (One Shot Control) */ +#define HID_USAGE_SYS_DISPINT uint16_t (0xB1) /* System Display Internal (One Shot Control) */ +#define HID_USAGE_SYS_DISPEXT uint16_t (0xB2) /* System Display External (One Shot Control) */ +#define HID_USAGE_SYS_DISPBOTH uint16_t (0xB3) /* System Display Both (One Shot Control) */ +#define HID_USAGE_SYS_DISPDUAL uint16_t (0xB4) /* System Display Dual (One Shot Control) */ +#define HID_USAGE_SYS_DISPTGLIE uint16_t (0xB5) /* System Display Toggle Int/Ext (One Shot Control) */ +#define HID_USAGE_SYS_DISP_SWAP uint16_t (0xB6) /* System Display Swap Primary/Secondary (One Shot Control) */ +#define HID_USAGE_SYS_DIPS_LCDA uint16_t (0xB7) /* System Display LCD Autoscale (One Shot Control) */ +/* B8-FFFF Reserved */ + +/** + * @} + */ + +#endif /* _HID_USAGE_H_ */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c new file mode 100755 index 0000000..a56f45c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid.c @@ -0,0 +1,800 @@ +/** + ****************************************************************************** + * @file usbh_hid.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the HID Layer Handlers for USB Host HID class. + * + * @verbatim + * + * =================================================================== + * HID Class Description + * =================================================================== + * This module manages the MSC class V1.11 following the "Device Class Definition + * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001". + * This driver implements the following aspects of the specification: + * - The Boot Interface Subclass + * - The Mouse and Keyboard protocols + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid.h" +#include "usbh_hid_parser.h" + + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_HID_CLASS +* @{ +*/ + +/** @defgroup USBH_HID_CORE +* @brief This file includes HID Layer Handlers for USB Host HID class. +* @{ +*/ + +/** @defgroup USBH_HID_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_HID_CORE_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_HID_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_HID_CORE_Private_Variables +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBH_HID_CORE_Private_FunctionPrototypes +* @{ +*/ + +static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost); +static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf); + +extern USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost); +extern USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost); + +USBH_ClassTypeDef HID_Class = +{ + "HID", + USB_HID_CLASS, + USBH_HID_InterfaceInit, + USBH_HID_InterfaceDeInit, + USBH_HID_ClassRequest, + USBH_HID_Process, + USBH_HID_SOFProcess, + NULL, +}; +/** +* @} +*/ + + +/** @defgroup USBH_HID_CORE_Private_Functions +* @{ +*/ + + +/** + * @brief USBH_HID_InterfaceInit + * The function init the HID class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_InterfaceInit (USBH_HandleTypeDef *phost) +{ + uint8_t max_ep; + uint8_t num = 0; + uint8_t interface; + + USBH_StatusTypeDef status = USBH_FAIL ; + HID_HandleTypeDef *HID_Handle; + + interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, 0xFF); + + if(interface == 0xFF) /* No Valid Interface */ + { + status = USBH_FAIL; + USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name); + } + else + { + USBH_SelectInterface (phost, interface); + phost->pActiveClass->pData = (HID_HandleTypeDef *)USBH_malloc (sizeof(HID_HandleTypeDef)); + HID_Handle = phost->pActiveClass->pData; + HID_Handle->state = HID_ERROR; + + /*Decode Bootclass Protocl: Mouse or Keyboard*/ + if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE) + { + USBH_UsrLog ("KeyBoard device found!"); + HID_Handle->Init = USBH_HID_KeybdInit; + } + else if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol == HID_MOUSE_BOOT_CODE) + { + USBH_UsrLog ("Mouse device found!"); + HID_Handle->Init = USBH_HID_MouseInit; + } + else + { + USBH_UsrLog ("Protocol not supported."); + return USBH_FAIL; + } + + HID_Handle->state = HID_INIT; + HID_Handle->ctl_state = HID_REQ_INIT; + HID_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress; + HID_Handle->length = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize; + HID_Handle->poll = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bInterval ; + + if (HID_Handle->poll < HID_MIN_POLL) + { + HID_Handle->poll = HID_MIN_POLL; + } + + /* Check fo available number of endpoints */ + /* Find the number of EPs in the Interface Descriptor */ + /* Choose the lower number in order not to overrun the buffer allocated */ + max_ep = ( (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ? + phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bNumEndpoints : + USBH_MAX_NUM_ENDPOINTS); + + + /* Decode endpoint IN and OUT address from interface descriptor */ + for ( ;num < max_ep; num++) + { + if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress & 0x80) + { + HID_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress); + HID_Handle->InPipe =\ + USBH_AllocPipe(phost, HID_Handle->InEp); + + /* Open pipe for IN endpoint */ + USBH_OpenPipe (phost, + HID_Handle->InPipe, + HID_Handle->InEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_INTR, + HID_Handle->length); + + USBH_LL_SetToggle (phost, HID_Handle->InPipe, 0); + + } + else + { + HID_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[num].bEndpointAddress); + HID_Handle->OutPipe =\ + USBH_AllocPipe(phost, HID_Handle->OutEp); + + /* Open pipe for OUT endpoint */ + USBH_OpenPipe (phost, + HID_Handle->OutPipe, + HID_Handle->OutEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_INTR, + HID_Handle->length); + + USBH_LL_SetToggle (phost, HID_Handle->OutPipe, 0); + } + + } + status = USBH_OK; + } + return status; +} + +/** + * @brief USBH_HID_InterfaceDeInit + * The function DeInit the Pipes used for the HID class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_InterfaceDeInit (USBH_HandleTypeDef *phost ) +{ + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + if(HID_Handle->InPipe != 0x00) + { + USBH_ClosePipe (phost, HID_Handle->InPipe); + USBH_FreePipe (phost, HID_Handle->InPipe); + HID_Handle->InPipe = 0; /* Reset the pipe as Free */ + } + + if(HID_Handle->OutPipe != 0x00) + { + USBH_ClosePipe(phost, HID_Handle->OutPipe); + USBH_FreePipe (phost, HID_Handle->OutPipe); + HID_Handle->OutPipe = 0; /* Reset the pipe as Free */ + } + + if(phost->pActiveClass->pData) + { + USBH_free (phost->pActiveClass->pData); + } + + return USBH_OK; +} + +/** + * @brief USBH_HID_ClassRequest + * The function is responsible for handling Standard requests + * for HID class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost) +{ + + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef classReqStatus = USBH_BUSY; + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + /* Switch HID state machine */ + switch (HID_Handle->ctl_state) + { + case HID_REQ_INIT: + case HID_REQ_GET_HID_DESC: + + /* Get HID Desc */ + if (USBH_HID_GetHIDDescriptor (phost, USB_HID_DESC_SIZE)== USBH_OK) + { + + USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.Data); + HID_Handle->ctl_state = HID_REQ_GET_REPORT_DESC; + } + + break; + case HID_REQ_GET_REPORT_DESC: + + + /* Get Report Desc */ + if (USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength) == USBH_OK) + { + /* The decriptor is available in phost->device.Data */ + + HID_Handle->ctl_state = HID_REQ_SET_IDLE; + } + + break; + + case HID_REQ_SET_IDLE: + + classReqStatus = USBH_HID_SetIdle (phost, 0, 0); + + /* set Idle */ + if (classReqStatus == USBH_OK) + { + HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL; + } + else if(classReqStatus == USBH_NOT_SUPPORTED) + { + HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL; + } + break; + + case HID_REQ_SET_PROTOCOL: + /* set protocol */ + if (USBH_HID_SetProtocol (phost, 0) == USBH_OK) + { + HID_Handle->ctl_state = HID_REQ_IDLE; + + /* all requests performed*/ + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + status = USBH_OK; + } + break; + + case HID_REQ_IDLE: + default: + break; + } + + return status; +} + +/** + * @brief USBH_HID_Process + * The function is for managing state machine for HID data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_OK; + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + switch (HID_Handle->state) + { + case HID_INIT: + HID_Handle->Init(phost); + case HID_IDLE: + if(USBH_HID_GetReport (phost, + 0x01, + 0, + HID_Handle->pData, + HID_Handle->length) == USBH_OK) + { + + fifo_write(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length); + HID_Handle->state = HID_SYNC; + } + + break; + + case HID_SYNC: + + /* Sync with start of Even Frame */ + if(phost->Timer & 1) + { + HID_Handle->state = HID_GET_DATA; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + break; + + case HID_GET_DATA: + + USBH_InterruptReceiveData(phost, + HID_Handle->pData, + HID_Handle->length, + HID_Handle->InPipe); + + HID_Handle->state = HID_POLL; + HID_Handle->timer = phost->Timer; + HID_Handle->DataReady = 0; + break; + + case HID_POLL: + + if(USBH_LL_GetURBState(phost , HID_Handle->InPipe) == USBH_URB_DONE) + { + if(HID_Handle->DataReady == 0) + { + fifo_write(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length); + HID_Handle->DataReady = 1; + USBH_HID_EventCallback(phost); +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + } + else if(USBH_LL_GetURBState(phost , HID_Handle->InPipe) == USBH_URB_STALL) /* IN Endpoint Stalled */ + { + + /* Issue Clear Feature on interrupt IN endpoint */ + if(USBH_ClrFeature(phost, + HID_Handle->ep_addr) == USBH_OK) + { + /* Change state to issue next IN token */ + HID_Handle->state = HID_GET_DATA; + } + } + + + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_HID_SOFProcess + * The function is for managing the SOF Process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost) +{ + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + if(HID_Handle->state == HID_POLL) + { + if(( phost->Timer - HID_Handle->timer) >= HID_Handle->poll) + { + HID_Handle->state = HID_GET_DATA; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + } + return USBH_OK; +} + +/** +* @brief USBH_Get_HID_ReportDescriptor + * Issue report Descriptor command to the device. Once the response + * received, parse the report descriptor and update the status. + * @param phost: Host handle + * @param Length : HID Report Descriptor Length + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor (USBH_HandleTypeDef *phost, + uint16_t length) +{ + + USBH_StatusTypeDef status; + + status = USBH_GetDescriptor(phost, + USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, + USB_DESC_HID_REPORT, + phost->device.Data, + length); + + /* HID report descriptor is available in phost->device.Data. + In case of USB Boot Mode devices for In report handling , + HID report descriptor parsing is not required. + In case, for supporting Non-Boot Protocol devices and output reports, + user may parse the report descriptor*/ + + + return status; +} + +/** + * @brief USBH_Get_HID_Descriptor + * Issue HID Descriptor command to the device. Once the response + * received, parse the report descriptor and update the status. + * @param phost: Host handle + * @param Length : HID Descriptor Length + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_GetHIDDescriptor (USBH_HandleTypeDef *phost, + uint16_t length) +{ + + USBH_StatusTypeDef status; + + status = USBH_GetDescriptor( phost, + USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, + USB_DESC_HID, + phost->device.Data, + length); + + return status; +} + +/** + * @brief USBH_Set_Idle + * Set Idle State. + * @param phost: Host handle + * @param duration: Duration for HID Idle request + * @param reportId : Targetted report ID for Set Idle request + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost, + uint8_t duration, + uint8_t reportId) +{ + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ + USB_REQ_TYPE_CLASS; + + + phost->Control.setup.b.bRequest = USB_HID_SET_IDLE; + phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId; + + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 0; + + return USBH_CtlReq(phost, 0 , 0 ); +} + + +/** + * @brief USBH_HID_Set_Report + * Issues Set Report + * @param phost: Host handle + * @param reportType : Report type to be sent + * @param reportId : Targetted report ID for Set Report request + * @param reportBuff : Report Buffer + * @param reportLen : Length of data report to be send + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_SetReport (USBH_HandleTypeDef *phost, + uint8_t reportType, + uint8_t reportId, + uint8_t* reportBuff, + uint8_t reportLen) +{ + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ + USB_REQ_TYPE_CLASS; + + + phost->Control.setup.b.bRequest = USB_HID_SET_REPORT; + phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId; + + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = reportLen; + + return USBH_CtlReq(phost, reportBuff , reportLen ); +} + + +/** + * @brief USBH_HID_GetReport + * retreive Set Report + * @param phost: Host handle + * @param reportType : Report type to be sent + * @param reportId : Targetted report ID for Set Report request + * @param reportBuff : Report Buffer + * @param reportLen : Length of data report to be send + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost, + uint8_t reportType, + uint8_t reportId, + uint8_t* reportBuff, + uint8_t reportLen) +{ + + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE |\ + USB_REQ_TYPE_CLASS; + + + phost->Control.setup.b.bRequest = USB_HID_GET_REPORT; + phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId; + + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = reportLen; + + return USBH_CtlReq(phost, reportBuff , reportLen ); +} + +/** + * @brief USBH_Set_Protocol + * Set protocol State. + * @param phost: Host handle + * @param protocol : Set Protocol for HID : boot/report protocol + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_SetProtocol(USBH_HandleTypeDef *phost, + uint8_t protocol) +{ + + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ + USB_REQ_TYPE_CLASS; + + + phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL; + phost->Control.setup.b.wValue.w = protocol != 0 ? 0 : 1; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 0; + + return USBH_CtlReq(phost, 0 , 0 ); + +} + +/** + * @brief USBH_ParseHIDDesc + * This function Parse the HID descriptor + * @param desc: HID Descriptor + * @param buf: Buffer where the source descriptor is available + * @retval None + */ +static void USBH_HID_ParseHIDDesc (HID_DescTypeDef *desc, uint8_t *buf) +{ + + desc->bLength = *(uint8_t *) (buf + 0); + desc->bDescriptorType = *(uint8_t *) (buf + 1); + desc->bcdHID = LE16 (buf + 2); + desc->bCountryCode = *(uint8_t *) (buf + 4); + desc->bNumDescriptors = *(uint8_t *) (buf + 5); + desc->bReportDescriptorType = *(uint8_t *) (buf + 6); + desc->wItemLength = LE16 (buf + 7); +} + +/** + * @brief USBH_HID_GetDeviceType + * Return Device function. + * @param phost: Host handle + * @retval HID function: HID_MOUSE / HID_KEYBOARD + */ +HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost) +{ + HID_TypeTypeDef type = HID_UNKNOWN; + + if(phost->gState == HOST_CLASS) + { + + if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \ + == HID_KEYBRD_BOOT_CODE) + { + type = HID_KEYBOARD; + } + else if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol \ + == HID_MOUSE_BOOT_CODE) + { + type= HID_MOUSE; + } + } + return type; +} + +/** + * @brief fifo_init + * Initialize FIFO. + * @param f: Fifo address + * @param buf: Fifo buffer + * @param size: Fifo Size + * @retval none + */ +void fifo_init(FIFO_TypeDef * f, uint8_t * buf, uint16_t size) +{ + f->head = 0; + f->tail = 0; + f->lock = 0; + f->size = size; + f->buf = buf; +} + +/** + * @brief fifo_read + * Read from FIFO. + * @param f: Fifo address + * @param buf: read buffer + * @param nbytes: number of item to read + * @retval number of read items + */ +uint16_t fifo_read(FIFO_TypeDef * f, void * buf, uint16_t nbytes) +{ + uint16_t i; + uint8_t * p; + p = buf; + + if(f->lock == 0) + { + f->lock = 1; + for(i=0; i < nbytes; i++) + { + if( f->tail != f->head ) + { + *p++ = f->buf[f->tail]; + f->tail++; + if( f->tail == f->size ) + { + f->tail = 0; + } + } else + { + f->lock = 0; + return i; + } + } + } + f->lock = 0; + return nbytes; +} + +/** + * @brief fifo_write + * Read from FIFO. + * @param f: Fifo address + * @param buf: read buffer + * @param nbytes: number of item to write + * @retval number of written items + */ +uint16_t fifo_write(FIFO_TypeDef * f, const void * buf, uint16_t nbytes) +{ + uint16_t i; + const uint8_t * p; + p = buf; + if(f->lock == 0) + { + f->lock = 1; + for(i=0; i < nbytes; i++) + { + if( (f->head + 1 == f->tail) || + ( (f->head + 1 == f->size) && (f->tail == 0)) ) + { + f->lock = 0; + return i; + } + else + { + f->buf[f->head] = *p++; + f->head++; + if( f->head == f->size ) + { + f->head = 0; + } + } + } + } + f->lock = 0; + return nbytes; +} + + +/** +* @brief The function is a callback about HID Data events +* @param phost: Selected device +* @retval None +*/ +__weak void USBH_HID_EventCallback(USBH_HandleTypeDef *phost) +{ + +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c new file mode 100755 index 0000000..7910476 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_keybd.c @@ -0,0 +1,418 @@ +/** + ****************************************************************************** + * @file usbh_hid_keybd.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the application layer for USB Host HID Keyboard handling + * QWERTY and AZERTY Keyboard are supported as per the selection in + * usbh_hid_keybd.h + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid_keybd.h" +#include "usbh_hid_parser.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_HID_CLASS +* @{ +*/ + +/** @defgroup USBH_HID_KEYBD +* @brief This file includes HID Layer Handlers for USB Host HID class. +* @{ +*/ + +/** @defgroup USBH_HID_KEYBD_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_HID_KEYBD_Private_Defines +* @{ +*/ +/** +* @} +*/ +#ifndef AZERTY_KEYBOARD + #define QWERTY_KEYBOARD +#endif +#define KBD_LEFT_CTRL 0x01 +#define KBD_LEFT_SHIFT 0x02 +#define KBD_LEFT_ALT 0x04 +#define KBD_LEFT_GUI 0x08 +#define KBD_RIGHT_CTRL 0x10 +#define KBD_RIGHT_SHIFT 0x20 +#define KBD_RIGHT_ALT 0x40 +#define KBD_RIGHT_GUI 0x80 +#define KBR_MAX_NBR_PRESSED 6 + +/** @defgroup USBH_HID_KEYBD_Private_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_HID_KEYBD_Private_FunctionPrototypes +* @{ +*/ +static USBH_StatusTypeDef USBH_HID_KeybdDecode(USBH_HandleTypeDef *phost); +/** +* @} +*/ + +/** @defgroup USBH_HID_KEYBD_Private_Variables +* @{ +*/ + +HID_KEYBD_Info_TypeDef keybd_info; +uint32_t keybd_report_data[2]; + +static const HID_Report_ItemTypedef imp_0_lctrl={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 0, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_lshift={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 1, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_lalt={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 2, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_lgui={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 3, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_rctrl={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 4, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_rshift={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 5, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_ralt={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 6, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; +static const HID_Report_ItemTypedef imp_0_rgui={ + (uint8_t*)keybd_report_data+0, /*data*/ + 1, /*size*/ + 7, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; + +static const HID_Report_ItemTypedef imp_0_key_array={ + (uint8_t*)keybd_report_data+2, /*data*/ + 8, /*size*/ + 0, /*shift*/ + 6, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 101, /*max value read can return*/ + 0, /*min vale device can report*/ + 101, /*max value device can report*/ + 1 /*resolution*/ +}; + +#ifdef QWERTY_KEYBOARD +static const int8_t HID_KEYBRD_Key[] = { + '\0', '`', '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', '\0', '\r', + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', + 'i', 'o', 'p', '[', ']', '\\', + '\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', + 'k', 'l', ';', '\'', '\0', '\n', + '\0', '\0', 'z', 'x', 'c', 'v', 'b', 'n', + 'm', ',', '.', '/', '\0', '\0', + '\0', '\0', '\0', ' ', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\r', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '7', '4', '1', + '\0', '/', '8', '5', '2', + '0', '*', '9', '6', '3', + '.', '-', '+', '\0', '\n', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0' +}; + +static const int8_t HID_KEYBRD_ShiftKey[] = { + '\0', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '_', '+', '\0', '\0', '\0', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', + 'I', 'O', 'P', '{', '}', '|', '\0', 'A', 'S', 'D', 'F', 'G', + 'H', 'J', 'K', 'L', ':', '"', '\0', '\n', '\0', '\0', 'Z', 'X', + 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' +}; + +#else + +static const int8_t HID_KEYBRD_Key[] = { + '\0', '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '-', '=', '\0', '\r', '\t', 'a', 'z', 'e', 'r', 't', 'y', 'u', + 'i', 'o', 'p', '[', ']', '\\', '\0', 'q', 's', 'd', 'f', 'g', + 'h', 'j', 'k', 'l', 'm', '\0', '\0', '\n', '\0', '\0', 'w', 'x', + 'c', 'v', 'b', 'n', ',', ';', ':', '!', '\0', '\0', '\0', '\0', + '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\r', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '4', '1','\0', '/', + '8', '5', '2', '0', '*', '9', '6', '3', '.', '-', '+', '\0', + '\n', '\0', '\0', '\0', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' +}; + +static const int8_t HID_KEYBRD_ShiftKey[] = { + '\0', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', + '+', '\0', '\0', '\0', 'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', + 'P', '{', '}', '*', '\0', 'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', + 'L', 'M', '%', '\0', '\n', '\0', '\0', 'W', 'X', 'C', 'V', 'B', 'N', + '?', '.', '/', '\0', '\0', '\0','\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' +}; +#endif + +static const uint8_t HID_KEYBRD_Codes[] = { + 0, 0, 0, 0, 31, 50, 48, 33, + 19, 34, 35, 36, 24, 37, 38, 39, /* 0x00 - 0x0F */ + 52, 51, 25, 26, 17, 20, 32, 21, + 23, 49, 18, 47, 22, 46, 2, 3, /* 0x10 - 0x1F */ + 4, 5, 6, 7, 8, 9, 10, 11, + 43, 110, 15, 16, 61, 12, 13, 27, /* 0x20 - 0x2F */ + 28, 29, 42, 40, 41, 1, 53, 54, + 55, 30, 112, 113, 114, 115, 116, 117, /* 0x30 - 0x3F */ + 118, 119, 120, 121, 122, 123, 124, 125, + 126, 75, 80, 85, 76, 81, 86, 89, /* 0x40 - 0x4F */ + 79, 84, 83, 90, 95, 100, 105, 106, + 108, 93, 98, 103, 92, 97, 102, 91, /* 0x50 - 0x5F */ + 96, 101, 99, 104, 45, 129, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 107, 0, 56, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 - 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ + 58, 44, 60, 127, 64, 57, 62, 128 /* 0xE0 - 0xE7 */ +}; + +/** + * @brief USBH_HID_KeybdInit + * The function init the HID keyboard. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost) +{ + uint32_t x; + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + keybd_info.lctrl=keybd_info.lshift= 0; + keybd_info.lalt=keybd_info.lgui= 0; + keybd_info.rctrl=keybd_info.rshift= 0; + keybd_info.ralt=keybd_info.rgui=0; + + + for(x=0; x< (sizeof(keybd_report_data)/sizeof(uint32_t)); x++) + { + keybd_report_data[x]=0; + } + + if(HID_Handle->length > (sizeof(keybd_report_data)/sizeof(uint32_t))) + { + HID_Handle->length = (sizeof(keybd_report_data)/sizeof(uint32_t)); + } + HID_Handle->pData = (uint8_t*)keybd_report_data; + fifo_init(&HID_Handle->fifo, phost->device.Data, HID_QUEUE_SIZE * sizeof(keybd_report_data)); + + return USBH_OK; +} + +/** + * @brief USBH_HID_GetKeybdInfo + * The function return keyboard information. + * @param phost: Host handle + * @retval keyboard information + */ +HID_KEYBD_Info_TypeDef *USBH_HID_GetKeybdInfo(USBH_HandleTypeDef *phost) +{ + if(USBH_HID_KeybdDecode(phost) == USBH_OK) + { + return &keybd_info; + } + else + { + return NULL; + } +} + +/** + * @brief USBH_HID_KeybdDecode + * The function decode keyboard data. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_KeybdDecode(USBH_HandleTypeDef *phost) +{ + uint8_t x; + + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + if(HID_Handle->length == 0) + { + return USBH_FAIL; + } + /*Fill report */ + if(fifo_read(&HID_Handle->fifo, &keybd_report_data, HID_Handle->length) == HID_Handle->length) + { + + keybd_info.lctrl=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lctrl, 0); + keybd_info.lshift=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lshift, 0); + keybd_info.lalt=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lalt, 0); + keybd_info.lgui=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_lgui, 0); + keybd_info.rctrl=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rctrl, 0); + keybd_info.rshift=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rshift, 0); + keybd_info.ralt=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_ralt, 0); + keybd_info.rgui=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_rgui, 0); + + for(x=0; x < sizeof(keybd_info.keys); x++) + { + keybd_info.keys[x]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &imp_0_key_array, x); + } + + return USBH_OK; + } + return USBH_FAIL; +} + +/** + * @brief USBH_HID_GetASCIICode + * The function decode keyboard data into ASCII characters. + * @param phost: Host handle + * @param info: Keyboard information + * @retval ASCII code + */ +uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info) +{ + uint8_t output; + if((info->lshift == 1) || (info->rshift)) + { + output = HID_KEYBRD_ShiftKey[HID_KEYBRD_Codes[info->keys[0]]]; + } + else + { + output = HID_KEYBRD_Key[HID_KEYBRD_Codes[info->keys[0]]]; + } + return output; +} +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c new file mode 100755 index 0000000..0851714 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_mouse.c @@ -0,0 +1,267 @@ +/** + ****************************************************************************** + * @file usbh_hid_mouse.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the application layer for USB Host HID Mouse Handling. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid_mouse.h" +#include "usbh_hid_parser.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_MOUSE + * @brief This file includes HID Layer Handlers for USB Host HID class. + * @{ + */ + +/** @defgroup USBH_HID_MOUSE_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_HID_MOUSE_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_HID_MOUSE_Private_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_MOUSE_Private_FunctionPrototypes + * @{ + */ +static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost); + +/** + * @} + */ + + +/** @defgroup USBH_HID_MOUSE_Private_Variables + * @{ + */ +HID_MOUSE_Info_TypeDef mouse_info; +uint32_t mouse_report_data[1]; + +/* Structures defining how to access items in a HID mouse report */ +/* Access button 1 state. */ +static const HID_Report_ItemTypedef prop_b1={ + (uint8_t *)mouse_report_data+0, /*data*/ + 1, /*size*/ + 0, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min value device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; + +/* Access button 2 state. */ +static const HID_Report_ItemTypedef prop_b2={ + (uint8_t *)mouse_report_data+0, /*data*/ + 1, /*size*/ + 1, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min value device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; + +/* Access button 3 state. */ +static const HID_Report_ItemTypedef prop_b3={ + (uint8_t *)mouse_report_data+0, /*data*/ + 1, /*size*/ + 2, /*shift*/ + 0, /*count (only for array items)*/ + 0, /*signed?*/ + 0, /*min value read can return*/ + 1, /*max value read can return*/ + 0, /*min vale device can report*/ + 1, /*max value device can report*/ + 1 /*resolution*/ +}; + +/* Access x coordinate change. */ +static const HID_Report_ItemTypedef prop_x={ + (uint8_t *)mouse_report_data+1, /*data*/ + 8, /*size*/ + 0, /*shift*/ + 0, /*count (only for array items)*/ + 1, /*signed?*/ + 0, /*min value read can return*/ + 0xFFFF,/*max value read can return*/ + 0, /*min vale device can report*/ + 0xFFFF,/*max value device can report*/ + 1 /*resolution*/ +}; + +/* Access y coordinate change. */ +static const HID_Report_ItemTypedef prop_y={ + (uint8_t *)mouse_report_data+2, /*data*/ + 8, /*size*/ + 0, /*shift*/ + 0, /*count (only for array items)*/ + 1, /*signed?*/ + 0, /*min value read can return*/ + 0xFFFF,/*max value read can return*/ + 0, /*min vale device can report*/ + 0xFFFF,/*max value device can report*/ + 1 /*resolution*/ +}; + + +/** + * @} + */ + + +/** @defgroup USBH_HID_MOUSE_Private_Functions + * @{ + */ + +/** + * @brief USBH_HID_MouseInit + * The function init the HID mouse. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost) +{ + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + mouse_info.x=0; + mouse_info.y=0; + mouse_info.buttons[0]=0; + mouse_info.buttons[1]=0; + mouse_info.buttons[2]=0; + + mouse_report_data[0]=0; + + if(HID_Handle->length > sizeof(mouse_report_data)) + { + HID_Handle->length = sizeof(mouse_report_data); + } + HID_Handle->pData = (uint8_t *)mouse_report_data; + fifo_init(&HID_Handle->fifo, phost->device.Data, HID_QUEUE_SIZE * sizeof(mouse_report_data)); + + return USBH_OK; +} + +/** + * @brief USBH_HID_GetMouseInfo + * The function return mouse information. + * @param phost: Host handle + * @retval mouse information + */ +HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost) +{ + if(USBH_HID_MouseDecode(phost)== USBH_OK) + { + return &mouse_info; + } + else + { + return NULL; + } +} + +/** + * @brief USBH_HID_MouseDecode + * The function decode mouse data. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost) +{ + HID_HandleTypeDef *HID_Handle = phost->pActiveClass->pData; + + if(HID_Handle->length == 0) + { + return USBH_FAIL; + } + /*Fill report */ + if(fifo_read(&HID_Handle->fifo, &mouse_report_data, HID_Handle->length) == HID_Handle->length) + { + + /*Decode report */ + mouse_info.x = (int16_t )HID_ReadItem((HID_Report_ItemTypedef *) &prop_x, 0); + mouse_info.y = (int16_t )HID_ReadItem((HID_Report_ItemTypedef *) &prop_y, 0); + + mouse_info.buttons[0]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b1, 0); + mouse_info.buttons[1]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b2, 0); + mouse_info.buttons[2]=(uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b3, 0); + + return USBH_OK; + } + return USBH_FAIL; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c new file mode 100755 index 0000000..a050f95 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/HID/Src/usbh_hid_parser.c @@ -0,0 +1,235 @@ +/** + ****************************************************************************** + * @file usbh_hid_parser.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the HID Layer Handlers for USB Host HID class. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ +#include "usbh_hid_parser.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_HID_CLASS + * @{ + */ + +/** @defgroup USBH_HID_PARSER + * @brief This file includes HID parsers for USB Host HID class. + * @{ + */ + +/** @defgroup USBH_HID_PARSER_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_HID_PARSER_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_HID_PARSER_Private_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_HID_PARSER_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_HID_PARSER_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_HID_PARSER_Private_Functions + * @{ + */ + +/** + * @brief HID_ReadItem + * The function read a report item. + * @param ri: report item + * @param ndx: report index +* @retval status (0 : fail / otherwise: item value) + */ +uint32_t HID_ReadItem(HID_Report_ItemTypedef *ri, uint8_t ndx) +{ + uint32_t val=0; + uint32_t x=0; + uint32_t bofs; + uint8_t *data=ri->data; + uint8_t shift=ri->shift; + + /* get the logical value of the item */ + + /* if this is an array, wee may need to offset ri->data.*/ + if (ri->count > 0) + { + /* If app tries to read outside of the array. */ + if (ri->count <= ndx) + { + return(0); + } + + /* calculate bit offset */ + bofs = ndx*ri->size; + bofs += shift; + /* calculate byte offset + shift pair from bit offset. */ + data+=bofs/8; + shift=(uint8_t)(bofs%8); + } + /* read data bytes in little endian order */ + for(x=0; x < ((ri->size & 0x7) ? (ri->size/8)+1 : (ri->size/8)); x++) + { + val=(uint32_t)(*data << (x*8)); + } + val=(val >> shift) & ((1<size)-1); + + if (val < ri->logical_min || val > ri->logical_max) + { + return(0); + } + + /* convert logical value to physical value */ + /* See if the number is negative or not. */ + if ((ri->sign) && (val & (1<<(ri->size-1)))) + { + /* yes, so sign extend value to 32 bits. */ + int vs=(int)((-1 & ~((1<<(ri->size))-1)) | val); + + if(ri->resolution == 1) + { + return((uint32_t)vs); + } + return((uint32_t)(vs*ri->resolution)); + } + else + { + if(ri->resolution == 1) + { + return(val); + } + return(val*ri->resolution); + } +} + +/** + * @brief HID_WriteItem + * The function write a report item. + * @param ri: report item + * @param ndx: report index + * @retval status (1: fail/ 0 : Ok) + */ +uint32_t HID_WriteItem(HID_Report_ItemTypedef *ri, uint32_t value, uint8_t ndx) +{ + uint32_t x; + uint32_t mask; + uint32_t bofs; + uint8_t *data=ri->data; + uint8_t shift=ri->shift; + + if (value < ri->physical_min || value > ri->physical_max) + { + return(1); + } + + /* if this is an array, wee may need to offset ri->data.*/ + if (ri->count > 0) + { + /* If app tries to read outside of the array. */ + if (ri->count >= ndx) + { + return(0); + } + /* calculate bit offset */ + bofs = ndx*ri->size; + bofs += shift; + /* calculate byte offset + shift pair from bit offset. */ + data+=bofs/8; + shift=(uint8_t)(bofs%8); + + } + + /* Convert physical value to logical value. */ + if (ri->resolution != 1) + { + value=value/ri->resolution; + } + + /* Write logical value to report in little endian order. */ + mask=(uint32_t)((1<size)-1); + value = (value & mask) << shift; + + for(x=0; x < ((ri->size & 0x7) ? (ri->size/8)+1 : (ri->size/8)); x++) + { + *(ri->data+x)=(uint8_t)((*(ri->data+x) & ~(mask>>(x*8))) | ((value>>(x*8)) & (mask>>(x*8)))); + } + return(0); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h new file mode 100755 index 0000000..ea173a7 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc.h @@ -0,0 +1,222 @@ +/** + ****************************************************************************** + * @file usbh_msc.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_msc_core.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MSC_H +#define __USBH_MSC_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" +#include "usbh_msc_bot.h" +#include "usbh_msc_scsi.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MSC_CLASS + * @{ + */ + +/** @defgroup USBH_MSC_CORE + * @brief This file is the Header file for usbh_msc_core.c + * @{ + */ + + +/** @defgroup USBH_MSC_CORE_Exported_Types + * @{ + */ + +typedef enum +{ + MSC_INIT = 0, + MSC_IDLE, + MSC_TEST_UNIT_READY, + MSC_READ_CAPACITY10, + MSC_READ_INQUIRY, + MSC_REQUEST_SENSE, + MSC_READ, + MSC_WRITE, + MSC_UNRECOVERED_ERROR, + MSC_PERIODIC_CHECK, +} +MSC_StateTypeDef; + +typedef enum +{ + MSC_OK, + MSC_NOT_READY, + MSC_ERROR, + +} +MSC_ErrorTypeDef; + +typedef enum +{ + MSC_REQ_IDLE = 0, + MSC_REQ_RESET, + MSC_REQ_GET_MAX_LUN, + MSC_REQ_ERROR, +} +MSC_ReqStateTypeDef; + +#define MAX_SUPPORTED_LUN 2 + +/* Structure for LUN */ +typedef struct +{ + MSC_StateTypeDef state; + MSC_ErrorTypeDef error; + USBH_StatusTypeDef prev_ready_state; + SCSI_CapacityTypeDef capacity; + SCSI_SenseTypeDef sense; + SCSI_StdInquiryDataTypeDef inquiry; + uint8_t state_changed; + +} +MSC_LUNTypeDef; + +/* Structure for MSC process */ +typedef struct _MSC_Process +{ + uint32_t max_lun; + uint8_t InPipe; + uint8_t OutPipe; + uint8_t OutEp; + uint8_t InEp; + uint16_t OutEpSize; + uint16_t InEpSize; + MSC_StateTypeDef state; + MSC_ErrorTypeDef error; + MSC_ReqStateTypeDef req_state; + MSC_ReqStateTypeDef prev_req_state; + BOT_HandleTypeDef hbot; + MSC_LUNTypeDef unit[MAX_SUPPORTED_LUN]; + uint16_t current_lun; + uint16_t rw_lun; + uint32_t timer; +} +MSC_HandleTypeDef; + + +/** + * @} + */ + + + +/** @defgroup USBH_MSC_CORE_Exported_Defines + * @{ + */ + +#define USB_REQ_BOT_RESET 0xFF +#define USB_REQ_GET_MAX_LUN 0xFE + + +/* MSC Class Codes */ +#define USB_MSC_CLASS 0x08 + +/* Interface Descriptor field values for HID Boot Protocol */ +#define MSC_BOT 0x50 +#define MSC_TRANSPARENT 0x06 +/** + * @} + */ + +/** @defgroup USBH_MSC_CORE_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MSC_CORE_Exported_Variables + * @{ + */ +extern USBH_ClassTypeDef USBH_msc; +#define USBH_MSC_CLASS &USBH_msc + +/** + * @} + */ + +/** @defgroup USBH_MSC_CORE_Exported_FunctionsPrototype + * @{ + */ + +/* Common APIs */ +uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost); + +/* APIs for LUN */ +int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost); + +uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun); + +USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info); + +USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length); + +USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length); +/** + * @} + */ + +#endif /* __USBH_MSC_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h new file mode 100755 index 0000000..5422c80 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_bot.h @@ -0,0 +1,233 @@ +/** + ****************************************************************************** + * @file usbh_msc_bot.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_msc_bot.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MSC_BOT_H__ +#define __USBH_MSC_BOT_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" +#include "usbh_msc_bot.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MSC_CLASS + * @{ + */ + +/** @defgroup USBH_MSC_BOT + * @brief This file is the Header file for usbh_msc_core.c + * @{ + */ + + +/** @defgroup USBH_MSC_BOT_Exported_Types + * @{ + */ + +typedef enum { + BOT_OK = 0, + BOT_FAIL = 1, + BOT_PHASE_ERROR = 2, + BOT_BUSY = 3 +} +BOT_StatusTypeDef; + +typedef enum { + BOT_CMD_IDLE = 0, + BOT_CMD_SEND, + BOT_CMD_WAIT, +} +BOT_CMDStateTypeDef; + +/* CSW Status Definitions */ +typedef enum +{ + + BOT_CSW_CMD_PASSED = 0x00, + BOT_CSW_CMD_FAILED = 0x01, + BOT_CSW_PHASE_ERROR = 0x02, +} +BOT_CSWStatusTypeDef; + +typedef enum { + BOT_SEND_CBW = 1, + BOT_SEND_CBW_WAIT, + BOT_DATA_IN, + BOT_DATA_IN_WAIT, + BOT_DATA_OUT, + BOT_DATA_OUT_WAIT, + BOT_RECEIVE_CSW, + BOT_RECEIVE_CSW_WAIT, + BOT_ERROR_IN, + BOT_ERROR_OUT, + BOT_UNRECOVERED_ERROR +} +BOT_StateTypeDef; + +typedef union +{ + struct __CBW + { + uint32_t Signature; + uint32_t Tag; + uint32_t DataTransferLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; + }field; + uint8_t data[31]; +} +BOT_CBWTypeDef; + +typedef union +{ + struct __CSW + { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; + }field; + uint8_t data[13]; +} +BOT_CSWTypeDef; + +typedef struct +{ + uint32_t data[16]; + BOT_StateTypeDef state; + BOT_StateTypeDef prev_state; + BOT_CMDStateTypeDef cmd_state; + BOT_CBWTypeDef cbw; + uint8_t Reserved1; + BOT_CSWTypeDef csw; + uint8_t Reserved2[3]; + uint8_t *pbuf; +} +BOT_HandleTypeDef; + +/** + * @} + */ + + + +/** @defgroup USBH_MSC_BOT_Exported_Defines + * @{ + */ +#define BOT_CBW_SIGNATURE 0x43425355 +#define BOT_CBW_TAG 0x20304050 +#define BOT_CSW_SIGNATURE 0x53425355 +#define BOT_CBW_LENGTH 31 +#define BOT_CSW_LENGTH 13 + + + +#define BOT_SEND_CSW_DISABLE 0 +#define BOT_SEND_CSW_ENABLE 1 + +#define BOT_DIR_IN 0 +#define BOT_DIR_OUT 1 +#define BOT_DIR_BOTH 2 + +#define BOT_PAGE_LENGTH 512 + + +#define BOT_CBW_CB_LENGTH 16 + + +#define USB_REQ_BOT_RESET 0xFF +#define USB_REQ_GET_MAX_LUN 0xFE + +#define MAX_BULK_STALL_COUNT_LIMIT 0x04 /* If STALL is seen on Bulk + Endpoint continously, this means + that device and Host has phase error + Hence a Reset is needed */ + +/** + * @} + */ + +/** @defgroup USBH_MSC_BOT_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MSC_BOT_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_MSC_BOT_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun); + +USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun); +USBH_StatusTypeDef USBH_MSC_BOT_Error(USBH_HandleTypeDef *phost, uint8_t lun); + + + +/** + * @} + */ + +#endif //__USBH_MSC_BOT_H__ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h new file mode 100755 index 0000000..76b5190 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Inc/usbh_msc_scsi.h @@ -0,0 +1,218 @@ +/** + ****************************************************************************** + * @file usbh_msc_scsi.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_msc_scsi.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MSC_SCSI_H__ +#define __USBH_MSC_SCSI_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MSC_CLASS + * @{ + */ + +/** @defgroup USBH_MSC_SCSI + * @brief This file is the Header file for usbh_msc_scsi.c + * @{ + */ + + +// Capacity data. +typedef struct +{ + uint32_t block_nbr; + uint16_t block_size; +} SCSI_CapacityTypeDef; + + +// Sense data. +typedef struct +{ + uint8_t key; + uint8_t asc; + uint8_t ascq; +} SCSI_SenseTypeDef; + +// INQUIRY data. +typedef struct +{ + uint8_t PeripheralQualifier; + uint8_t DeviceType; + uint8_t RemovableMedia; + uint8_t vendor_id[9]; + uint8_t product_id[17]; + uint8_t revision_id[5]; +}SCSI_StdInquiryDataTypeDef; + +/** @defgroup USBH_MSC_SCSI_Exported_Defines + * @{ + */ +#define OPCODE_TEST_UNIT_READY 0x00 +#define OPCODE_READ_CAPACITY10 0x25 +#define OPCODE_READ10 0x28 +#define OPCODE_WRITE10 0x2A +#define OPCODE_REQUEST_SENSE 0x03 +#define OPCODE_INQUIRY 0x12 + +#define DATA_LEN_MODE_TEST_UNIT_READY 0 +#define DATA_LEN_READ_CAPACITY10 8 +#define DATA_LEN_INQUIRY 36 +#define DATA_LEN_REQUEST_SENSE 14 + +#define CBW_CB_LENGTH 16 +#define CBW_LENGTH 10 + +/** @defgroup USBH_MSC_SCSI_Exported_Defines + * @{ + */ +#define SCSI_SENSE_KEY_NO_SENSE 0x00 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_KEY_NOT_READY 0x02 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E +/** + * @} + */ + + +/** @defgroup USBH_MSC_SCSI_Exported_Defines + * @{ + */ +#define SCSI_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00 +#define SCSI_ASC_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASC_WRITE_PROTECTED 0x27 +#define SCSI_ASC_FORMAT_ERROR 0x31 +#define SCSI_ASC_INVALID_COMMAND_OPERATION_CODE 0x20 +#define SCSI_ASC_NOT_READY_TO_READY_CHANGE 0x28 +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A +/** + * @} + */ + + +/** @defgroup USBH_MSC_SCSI_Exported_Defines + * @{ + */ +#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01 +#define SCSI_ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07 + +/** + * @} + */ + +/** @defgroup USBH_MSC_SCSI_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup _Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_MSC_SCSI_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost, + uint8_t lun); + +USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_CapacityTypeDef *capacity); + +USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_StdInquiryDataTypeDef *inquiry); + +USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_SenseTypeDef *sense_data); + +USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length); + +USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length); + + +/** + * @} + */ + +#endif //__USBH_MSC_SCSI_H__ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c new file mode 100755 index 0000000..53a2cd8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc.c @@ -0,0 +1,795 @@ +/** + ****************************************************************************** + * @file usbh_msc.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements the MSC class driver functions + * =================================================================== + * MSC Class Description + * =================================================================== + * This module manages the MSC class V1.0 following the "Universal + * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0 + * Sep. 31, 1999". + * This driver implements the following aspects of the specification: + * - Bulk-Only Transport protocol + * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3)) + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ + +#include "usbh_msc.h" +#include "usbh_msc_bot.h" +#include "usbh_msc_scsi.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MSC_CLASS + * @{ + */ + +/** @defgroup USBH_MSC_CORE + * @brief This file includes the mass storage related functions + * @{ + */ + + +/** @defgroup USBH_MSC_CORE_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MSC_CORE_Private_Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MSC_CORE_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_MSC_CORE_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes + * @{ + */ + +static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun); + +USBH_ClassTypeDef USBH_msc = +{ + "MSC", + USB_MSC_CLASS, + USBH_MSC_InterfaceInit, + USBH_MSC_InterfaceDeInit, + USBH_MSC_ClassRequest, + USBH_MSC_Process, + USBH_MSC_SOFProcess, + NULL, +}; + + +/** + * @} + */ + + +/** @defgroup USBH_MSC_CORE_Exported_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_MSC_CORE_Private_Functions + * @{ + */ + + +/** + * @brief USBH_MSC_InterfaceInit + * The function init the MSC class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost) +{ + uint8_t interface = 0; + USBH_StatusTypeDef status = USBH_FAIL ; + MSC_HandleTypeDef *MSC_Handle; + + interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, MSC_TRANSPARENT, MSC_BOT); + + if(interface == 0xFF) /* Not Valid Interface */ + { + USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name); + status = USBH_FAIL; + } + else + { + USBH_SelectInterface (phost, interface); + + phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc (sizeof(MSC_HandleTypeDef)); + MSC_Handle = phost->pActiveClass->pData; + + if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80) + { + MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress); + MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize; + } + else + { + MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress); + MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize; + } + + if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80) + { + MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress); + MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize; + } + else + { + MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress); + MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize; + } + + MSC_Handle->current_lun = 0; + MSC_Handle->rw_lun = 0; + MSC_Handle->state = MSC_INIT; + MSC_Handle->error = MSC_OK; + MSC_Handle->req_state = MSC_REQ_IDLE; + MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp); + MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp); + + USBH_MSC_BOT_Init(phost); + + /* De-Initialize LUNs information */ + USBH_memset(MSC_Handle->unit, 0, sizeof(MSC_Handle->unit)); + + /* Open the new channels */ + USBH_OpenPipe (phost, + MSC_Handle->OutPipe, + MSC_Handle->OutEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + MSC_Handle->OutEpSize); + + USBH_OpenPipe (phost, + MSC_Handle->InPipe, + MSC_Handle->InEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + MSC_Handle->InEpSize); + + + USBH_LL_SetToggle (phost, MSC_Handle->InPipe,0); + USBH_LL_SetToggle (phost, MSC_Handle->OutPipe,0); + status = USBH_OK; + } + return status; +} + +/** + * @brief USBH_MSC_InterfaceDeInit + * The function DeInit the Pipes used for the MSC class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if ( MSC_Handle->OutPipe) + { + USBH_ClosePipe(phost, MSC_Handle->OutPipe); + USBH_FreePipe (phost, MSC_Handle->OutPipe); + MSC_Handle->OutPipe = 0; /* Reset the Channel as Free */ + } + + if ( MSC_Handle->InPipe) + { + USBH_ClosePipe(phost, MSC_Handle->InPipe); + USBH_FreePipe (phost, MSC_Handle->InPipe); + MSC_Handle->InPipe = 0; /* Reset the Channel as Free */ + } + + if(phost->pActiveClass->pData) + { + USBH_free (phost->pActiveClass->pData); + phost->pActiveClass->pData = 0; + } + + return USBH_OK; +} + +/** + * @brief USBH_MSC_ClassRequest + * The function is responsible for handling Standard requests + * for MSC class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + USBH_StatusTypeDef status = USBH_BUSY; + uint8_t i; + + /* Switch MSC REQ state machine */ + switch (MSC_Handle->req_state) + { + case MSC_REQ_IDLE: + case MSC_REQ_GET_MAX_LUN: + /* Issue GetMaxLUN request */ + if(USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun) == USBH_OK ) + { + MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1; + USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun)); + + for(i = 0; i < MSC_Handle->max_lun; i++) + { + MSC_Handle->unit[i].prev_ready_state = USBH_FAIL; + MSC_Handle->unit[i].state_changed = 0; + } + status = USBH_OK; + } + break; + + case MSC_REQ_ERROR : + /* a Clear Feature should be issued here */ + if(USBH_ClrFeature(phost, 0x00) == USBH_OK) + { + MSC_Handle->req_state = MSC_Handle->prev_req_state; + } + break; + + default: + break; + } + + return status; +} + +/** + * @brief USBH_MSC_Process + * The function is for managing state machine for MSC data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + USBH_StatusTypeDef error = USBH_BUSY ; + USBH_StatusTypeDef scsi_status = USBH_BUSY ; + USBH_StatusTypeDef ready_status = USBH_BUSY ; + + switch (MSC_Handle->state) + { + case MSC_INIT: + + if(MSC_Handle->current_lun < MSC_Handle->max_lun) + { + + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY; + /* Switch MSC REQ state machine */ + switch (MSC_Handle->unit[MSC_Handle->current_lun].state) + { + case MSC_INIT: + USBH_UsrLog ("LUN #%d: ", MSC_Handle->current_lun); + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY; + MSC_Handle->timer = phost->Timer + 10000; + + case MSC_READ_INQUIRY: + scsi_status = USBH_MSC_SCSI_Inquiry(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry); + + if( scsi_status == USBH_OK) + { + USBH_UsrLog ("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id); + USBH_UsrLog ("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id); + USBH_UsrLog ("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id); + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY; + } + if( scsi_status == USBH_FAIL) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; + } + break; + + case MSC_TEST_UNIT_READY: + ready_status = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->current_lun); + + if( ready_status == USBH_OK) + { + if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK) + { + MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1; + USBH_UsrLog ("Mass Storage Device ready"); + } + else + { + MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0; + } + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK; + MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK; + } + if( ready_status == USBH_FAIL) + { + /* Media not ready, so try to check again during 10s */ + if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL) + { + MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1; + USBH_UsrLog ("Mass Storage Device NOT ready"); + } + else + { + MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0; + } + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY; + MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL; + } + else if(ready_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; + } + break; + + case MSC_READ_CAPACITY10: + scsi_status = USBH_MSC_SCSI_ReadCapacity(phost,MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ; + + if(scsi_status == USBH_OK) + { + if(MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1) + { + USBH_UsrLog ("Mass Storage Device capacity : %lu MB", \ + (int32_t)((MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size)/1024/1024)); + USBH_UsrLog ("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr)); + USBH_UsrLog ("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size)); + } + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK; + MSC_Handle->current_lun++; + } + else if( scsi_status == USBH_FAIL) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; + } + break; + + case MSC_REQUEST_SENSE: + scsi_status = USBH_MSC_SCSI_RequestSense(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense); + + if( scsi_status == USBH_OK) + { + if((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) || + (MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY) ) + { + + if(phost->Timer <= MSC_Handle->timer) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY; + break; + } + } + + USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key); + USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc); + USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq); + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->current_lun++; + } + if( scsi_status == USBH_FAIL) + { + USBH_UsrLog ("Mass Storage Device NOT ready"); + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR; + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; + MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; + } + break; + + case MSC_UNRECOVERED_ERROR: + MSC_Handle->current_lun++; + break; + + default: + break; + } + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + } + else + { + MSC_Handle->current_lun = 0; + MSC_Handle->state = MSC_IDLE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + } + break; + + case MSC_IDLE: + error = USBH_OK; + break; + + default: + break; + } + return error; +} + + +/** + * @brief USBH_MSC_SOFProcess + * The function is for SOF state + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} +/** + * @brief USBH_MSC_RdWrProcess + * The function is for managing state machine for MSC I/O Process + * @param phost: Host handle + * @param lun: logical Unit Number + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + USBH_StatusTypeDef error = USBH_BUSY ; + USBH_StatusTypeDef scsi_status = USBH_BUSY ; + + /* Switch MSC REQ state machine */ + switch (MSC_Handle->unit[lun].state) + { + + case MSC_READ: + scsi_status = USBH_MSC_SCSI_Read(phost,lun, 0, NULL, 0) ; + + if(scsi_status == USBH_OK) + { + MSC_Handle->unit[lun].state = MSC_IDLE; + error = USBH_OK; + } + else if( scsi_status == USBH_FAIL) + { + MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE; + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; + error = USBH_FAIL; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + break; + + case MSC_WRITE: + scsi_status = USBH_MSC_SCSI_Write(phost,lun, 0, NULL, 0) ; + + if(scsi_status == USBH_OK) + { + MSC_Handle->unit[lun].state = MSC_IDLE; + error = USBH_OK; + } + else if( scsi_status == USBH_FAIL) + { + MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE; + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; + error = USBH_FAIL; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + break; + + case MSC_REQUEST_SENSE: + scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense); + + if( scsi_status == USBH_OK) + { + USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[lun].sense.key); + USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc); + USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq); + MSC_Handle->unit[lun].state = MSC_IDLE; + MSC_Handle->unit[lun].error = MSC_ERROR; + + error = USBH_FAIL; + } + if( scsi_status == USBH_FAIL) + { + USBH_UsrLog ("Mass Storage Device NOT ready"); + } + else if(scsi_status == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; + error = USBH_FAIL; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); +#endif + break; + + default: + break; + + } + return error; +} + +/** + * @brief USBH_MSC_IsReady + * The function check if the MSC function is ready + * @param phost: Host handle + * @retval USBH Status + */ +uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if(phost->gState == HOST_CLASS) + { + return (MSC_Handle->state == MSC_IDLE); + } + else + { + return 0; + } +} + +/** + * @brief USBH_MSC_GetMaxLUN + * The function return the Max LUN supported + * @param phost: Host handle + * @retval logical Unit Number supported + */ +int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if ((phost->gState != HOST_CLASS) && (MSC_Handle->state == MSC_IDLE)) + { + return MSC_Handle->max_lun; + } + return 0xFF; +} + +/** + * @brief USBH_MSC_UnitIsReady + * The function check whether a LUN is ready + * @param phost: Host handle + * @param lun: logical Unit Number + * @retval Lun status (0: not ready / 1: ready) + */ +uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if(phost->gState == HOST_CLASS) + { + return (MSC_Handle->unit[lun].error == MSC_OK); + } + else + { + return 0; + } +} + +/** + * @brief USBH_MSC_GetLUNInfo + * The function return a LUN information + * @param phost: Host handle + * @param lun: logical Unit Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + if(phost->gState == HOST_CLASS) + { + USBH_memcpy(info,&MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef)); + return USBH_OK; + } + else + { + return USBH_FAIL; + } +} + +/** + * @brief USBH_MSC_Read + * The function performs a Read operation + * @param phost: Host handle + * @param lun: logical Unit Number + * @param address: sector address + * @param pbuf: pointer to data + * @param length: number of sector to read + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length) +{ + uint32_t timeout; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if ((phost->device.is_connected == 0) || + (phost->gState != HOST_CLASS) || + (MSC_Handle->unit[lun].state != MSC_IDLE)) + { + return USBH_FAIL; + } + MSC_Handle->state = MSC_READ; + MSC_Handle->unit[lun].state = MSC_READ; + MSC_Handle->rw_lun = lun; + USBH_MSC_SCSI_Read(phost, + lun, + address, + pbuf, + length); + + timeout = phost->Timer + (10000 * length); + while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + MSC_Handle->state = MSC_IDLE; + return USBH_FAIL; + } + } + MSC_Handle->state = MSC_IDLE; + return USBH_OK; +} + +/** + * @brief USBH_MSC_Write + * The function performs a Write operation + * @param phost: Host handle + * @param lun: logical Unit Number + * @param address: sector address + * @param pbuf: pointer to data + * @param length: number of sector to write + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length) +{ + uint32_t timeout; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + if ((phost->device.is_connected == 0) || + (phost->gState != HOST_CLASS) || + (MSC_Handle->unit[lun].state != MSC_IDLE)) + { + return USBH_FAIL; + } + MSC_Handle->state = MSC_WRITE; + MSC_Handle->unit[lun].state = MSC_WRITE; + MSC_Handle->rw_lun = lun; + USBH_MSC_SCSI_Write(phost, + lun, + address, + pbuf, + length); + + timeout = phost->Timer + (10000 * length); + while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + MSC_Handle->state = MSC_IDLE; + return USBH_FAIL; + } + } + MSC_Handle->state = MSC_IDLE; + return USBH_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c new file mode 100755 index 0000000..5489ce2 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_bot.c @@ -0,0 +1,633 @@ +/** + ****************************************************************************** + * @file usbh_msc_bot.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file includes the BOT protocol related functions + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_msc_bot.h" +#include "usbh_msc.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_MSC_CLASS +* @{ +*/ + +/** @defgroup USBH_MSC_BOT +* @brief This file includes the mass storage related functions +* @{ +*/ + + +/** @defgroup USBH_MSC_BOT_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_MSC_BOT_Private_Defines +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_MSC_BOT_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MSC_BOT_Private_Variables +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBH_MSC_BOT_Private_FunctionPrototypes +* @{ +*/ +static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir); +static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost); +/** +* @} +*/ + + +/** @defgroup USBH_MSC_BOT_Exported_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MSC_BOT_Private_Functions +* @{ +*/ + +/** + * @brief USBH_MSC_BOT_REQ_Reset + * The function the MSC BOT Reset request. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost) +{ + + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \ + USB_REQ_RECIPIENT_INTERFACE; + + phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET; + phost->Control.setup.b.wValue.w = 0; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 0; + + return USBH_CtlReq(phost, 0 , 0 ); +} + +/** + * @brief USBH_MSC_BOT_REQ_GetMaxLUN + * The function the MSC BOT GetMaxLUN request. + * @param phost: Host handle + * @param Maxlun: pointer to Maxlun variable + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun) +{ + phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ + USB_REQ_RECIPIENT_INTERFACE; + + phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN; + phost->Control.setup.b.wValue.w = 0; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 1; + + return USBH_CtlReq(phost, Maxlun , 1 ); +} + + + +/** + * @brief USBH_MSC_BOT_Init + * The function Initializes the BOT protocol. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_BOT_Init(USBH_HandleTypeDef *phost) +{ + + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + MSC_Handle->hbot.cbw.field.Signature = BOT_CBW_SIGNATURE; + MSC_Handle->hbot.cbw.field.Tag = BOT_CBW_TAG; + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_SEND; + + return USBH_OK; +} + + + +/** + * @brief USBH_MSC_BOT_Process + * The function handle the BOT protocol. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun) +{ + USBH_StatusTypeDef status = USBH_BUSY; + USBH_StatusTypeDef error = USBH_BUSY; + BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED; + USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + uint8_t toggle = 0; + + switch (MSC_Handle->hbot.state) + { + case BOT_SEND_CBW: + MSC_Handle->hbot.cbw.field.LUN = lun; + MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT; + USBH_BulkSendData (phost, + MSC_Handle->hbot.cbw.data, + BOT_CBW_LENGTH, + MSC_Handle->OutPipe, + 1); + + break; + + case BOT_SEND_CBW_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe); + + if(URB_Status == USBH_URB_DONE) + { + if ( MSC_Handle->hbot.cbw.field.DataTransferLength != 0 ) + { + /* If there is Data Transfer Stage */ + if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H) + { + /* Data Direction is IN */ + MSC_Handle->hbot.state = BOT_DATA_IN; + } + else + { + /* Data Direction is OUT */ + MSC_Handle->hbot.state = BOT_DATA_OUT; + } + } + + else + {/* If there is NO Data Transfer Stage */ + MSC_Handle->hbot.state = BOT_RECEIVE_CSW; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + + } + else if(URB_Status == USBH_URB_NOTREADY) + { + /* Re-send CBW */ + MSC_Handle->hbot.state = BOT_SEND_CBW; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_STALL) + { + MSC_Handle->hbot.state = BOT_ERROR_OUT; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case BOT_DATA_IN: + /* Send first packet */ + USBH_BulkReceiveData (phost, + MSC_Handle->hbot.pbuf, + MSC_Handle->InEpSize , + MSC_Handle->InPipe); + + MSC_Handle->hbot.state = BOT_DATA_IN_WAIT; + + break; + + case BOT_DATA_IN_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe); + + if(URB_Status == USBH_URB_DONE) + { + /* Adjudt Data pointer and data length */ + if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->InEpSize) + { + MSC_Handle->hbot.pbuf += MSC_Handle->InEpSize; + MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->InEpSize; + } + else + { + MSC_Handle->hbot.cbw.field.DataTransferLength = 0; + } + + /* More Data To be Received */ + if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0) + { + /* Send next packet */ + USBH_BulkReceiveData (phost, + MSC_Handle->hbot.pbuf, + MSC_Handle->InEpSize , + MSC_Handle->InPipe); + + } + else + { + /* If value was 0, and successful transfer, then change the state */ + MSC_Handle->hbot.state = BOT_RECEIVE_CSW; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + } + else if(URB_Status == USBH_URB_STALL) + { + /* This is Data IN Stage STALL Condition */ + MSC_Handle->hbot.state = BOT_ERROR_IN; + + /* Refer to USB Mass-Storage Class : BOT (www.usb.org) + 6.7.2 Host expects to receive data from the device + 3. On a STALL condition receiving data, then: + The host shall accept the data received. + The host shall clear the Bulk-In pipe. + 4. The host shall attempt to receive a CSW.*/ + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case BOT_DATA_OUT: + + USBH_BulkSendData (phost, + MSC_Handle->hbot.pbuf, + MSC_Handle->OutEpSize , + MSC_Handle->OutPipe, + 1); + + + MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT; + break; + + case BOT_DATA_OUT_WAIT: + URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe); + + if(URB_Status == USBH_URB_DONE) + { + /* Adjudt Data pointer and data length */ + if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->OutEpSize) + { + MSC_Handle->hbot.pbuf += MSC_Handle->OutEpSize; + MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->OutEpSize; + } + else + { + MSC_Handle->hbot.cbw.field.DataTransferLength = 0; + } + + /* More Data To be Sent */ + if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0) + { + USBH_BulkSendData (phost, + MSC_Handle->hbot.pbuf, + MSC_Handle->OutEpSize , + MSC_Handle->OutPipe, + 1); + } + else + { + /* If value was 0, and successful transfer, then change the state */ + MSC_Handle->hbot.state = BOT_RECEIVE_CSW; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + + else if(URB_Status == USBH_URB_NOTREADY) + { + /* Re-send same data */ + MSC_Handle->hbot.state = BOT_DATA_OUT; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + + else if(URB_Status == USBH_URB_STALL) + { + MSC_Handle->hbot.state = BOT_ERROR_OUT; + + /* Refer to USB Mass-Storage Class : BOT (www.usb.org) + 6.7.3 Ho - Host expects to send data to the device + 3. On a STALL condition sending data, then: + " The host shall clear the Bulk-Out pipe. + 4. The host shall attempt to receive a CSW. + */ +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case BOT_RECEIVE_CSW: + + USBH_BulkReceiveData (phost, + MSC_Handle->hbot.csw.data, + BOT_CSW_LENGTH , + MSC_Handle->InPipe); + + MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT; + break; + + case BOT_RECEIVE_CSW_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe); + + /* Decode CSW */ + if(URB_Status == USBH_URB_DONE) + { + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_SEND; + CSW_Status = USBH_MSC_DecodeCSW(phost); + + if(CSW_Status == BOT_CSW_CMD_PASSED) + { + status = USBH_OK; + } + else + { + status = USBH_FAIL; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_STALL) + { + MSC_Handle->hbot.state = BOT_ERROR_IN; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case BOT_ERROR_IN: + error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN); + + if (error == USBH_OK) + { + MSC_Handle->hbot.state = BOT_RECEIVE_CSW; + } + else if (error == USBH_UNRECOVERED_ERROR) + { + /* This means that there is a STALL Error limit, Do Reset Recovery */ + MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR; + } + break; + + case BOT_ERROR_OUT: + error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT); + + if ( error == USBH_OK) + { + + toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe); + USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1- toggle); + USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0); + MSC_Handle->hbot.state = BOT_ERROR_IN; + } + else if (error == USBH_UNRECOVERED_ERROR) + { + MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR; + } + break; + + + case BOT_UNRECOVERED_ERROR: + status = USBH_MSC_BOT_REQ_Reset(phost); + if ( status == USBH_OK) + { + MSC_Handle->hbot.state = BOT_SEND_CBW; + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_MSC_BOT_Abort + * The function handle the BOT Abort process. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param dir: direction (0: out / 1 : in) + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MSC_BOT_Abort(USBH_HandleTypeDef *phost, uint8_t lun, uint8_t dir) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch (dir) + { + case BOT_DIR_IN : + /* send ClrFeture on Bulk IN endpoint */ + status = USBH_ClrFeature(phost, MSC_Handle->InEp); + + break; + + case BOT_DIR_OUT : + /*send ClrFeature on Bulk OUT endpoint */ + status = USBH_ClrFeature(phost, MSC_Handle->OutEp); + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_MSC_BOT_DecodeCSW + * This function decodes the CSW received by the device and updates the + * same to upper layer. + * @param phost: Host handle + * @retval USBH Status + * @notes + * Refer to USB Mass-Storage Class : BOT (www.usb.org) + * 6.3.1 Valid CSW Conditions : + * The host shall consider the CSW valid when: + * 1. dCSWSignature is equal to 53425355h + * 2. the CSW is 13 (Dh) bytes in length, + * 3. dCSWTag matches the dCBWTag from the corresponding CBW. + */ + +static BOT_CSWStatusTypeDef USBH_MSC_DecodeCSW(USBH_HandleTypeDef *phost) +{ + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + BOT_CSWStatusTypeDef status = BOT_CSW_CMD_FAILED; + + /*Checking if the transfer length is diffrent than 13*/ + if(USBH_LL_GetLastXferSize(phost, MSC_Handle->InPipe) != BOT_CSW_LENGTH) + { + /*(4) Hi > Dn (Host expects to receive data from the device, + Device intends to transfer no data) + (5) Hi > Di (Host expects to receive data from the device, + Device intends to send data to the host) + (9) Ho > Dn (Host expects to send data to the device, + Device intends to transfer no data) + (11) Ho > Do (Host expects to send data to the device, + Device intends to receive data from the host)*/ + + + status = BOT_CSW_PHASE_ERROR; + } + else + { /* CSW length is Correct */ + + /* Check validity of the CSW Signature and CSWStatus */ + if(MSC_Handle->hbot.csw.field.Signature == BOT_CSW_SIGNATURE) + {/* Check Condition 1. dCSWSignature is equal to 53425355h */ + + if(MSC_Handle->hbot.csw.field.Tag == MSC_Handle->hbot.cbw.field.Tag) + { + /* Check Condition 3. dCSWTag matches the dCBWTag from the + corresponding CBW */ + + if(MSC_Handle->hbot.csw.field.Status == 0) + { + /* Refer to USB Mass-Storage Class : BOT (www.usb.org) + + Hn Host expects no data transfers + Hi Host expects to receive data from the device + Ho Host expects to send data to the device + + Dn Device intends to transfer no data + Di Device intends to send data to the host + Do Device intends to receive data from the host + + Section 6.7 + (1) Hn = Dn (Host expects no data transfers, + Device intends to transfer no data) + (6) Hi = Di (Host expects to receive data from the device, + Device intends to send data to the host) + (12) Ho = Do (Host expects to send data to the device, + Device intends to receive data from the host) + + */ + + status = BOT_CSW_CMD_PASSED; + } + else if(MSC_Handle->hbot.csw.field.Status == 1) + { + status = BOT_CSW_CMD_FAILED; + } + + else if(MSC_Handle->hbot.csw.field.Status == 2) + { + /* Refer to USB Mass-Storage Class : BOT (www.usb.org) + Section 6.7 + (2) Hn < Di ( Host expects no data transfers, + Device intends to send data to the host) + (3) Hn < Do ( Host expects no data transfers, + Device intends to receive data from the host) + (7) Hi < Di ( Host expects to receive data from the device, + Device intends to send data to the host) + (8) Hi <> Do ( Host expects to receive data from the device, + Device intends to receive data from the host) + (10) Ho <> Di (Host expects to send data to the device, + Di Device intends to send data to the host) + (13) Ho < Do (Host expects to send data to the device, + Device intends to receive data from the host) + */ + + status = BOT_CSW_PHASE_ERROR; + } + } /* CSW Tag Matching is Checked */ + } /* CSW Signature Correct Checking */ + else + { + /* If the CSW Signature is not valid, We sall return the Phase Error to + Upper Layers for Reset Recovery */ + + status = BOT_CSW_PHASE_ERROR; + } + } /* CSW Length Check*/ + + return status; +} + + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c new file mode 100755 index 0000000..5d069b4 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MSC/Src/usbh_msc_scsi.c @@ -0,0 +1,458 @@ +/** + ****************************************************************************** + * @file usbh_msc_scsi.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements the SCSI commands + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_msc.h" +#include "usbh_msc_scsi.h" +#include "usbh_msc_bot.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MSC_CLASS + * @{ + */ + +/** @defgroup USBH_MSC_SCSI + * @brief This file includes the mass storage related functions + * @{ + */ + + +/** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_MSC_SCSI_Private_Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MSC_SCSI_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_MSC_SCSI_Exported_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_MSC_SCSI_Private_Functions + * @{ + */ + + +/** + * @brief USBH_MSC_SCSI_TestUnitReady + * Issue TestUnitReady command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_TestUnitReady (USBH_HandleTypeDef *phost, + uint8_t lun) +{ + USBH_StatusTypeDef error = USBH_FAIL ; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_MODE_TEST_UNIT_READY; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_TEST_UNIT_READY; + + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + error = USBH_MSC_BOT_Process(phost, lun); + break; + + default: + break; + } + + return error; +} + +/** + * @brief USBH_MSC_SCSI_ReadCapacity + * Issue Read Capacity command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param capacity: pointer to the capacity structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_ReadCapacity (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_CapacityTypeDef *capacity) +{ + USBH_StatusTypeDef error = USBH_BUSY ; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_READ_CAPACITY10; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ_CAPACITY10; + + MSC_Handle->hbot.state = BOT_SEND_CBW; + + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + + error = USBH_MSC_BOT_Process(phost, lun); + + if(error == USBH_OK) + { + /*assign the capacity*/ + capacity->block_nbr = MSC_Handle->hbot.pbuf[3] | (MSC_Handle->hbot.pbuf[2] << 8) |\ + (MSC_Handle->hbot.pbuf[1] << 16) | (MSC_Handle->hbot.pbuf[0] << 24); + + /*assign the page length*/ + capacity->block_size = MSC_Handle->hbot.pbuf[7] | (MSC_Handle->hbot.pbuf[6] << 8); + } + break; + + default: + break; + } + + return error; +} + +/** + * @brief USBH_MSC_SCSI_Inquiry + * Issue Inquiry command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param capacity: pointer to the inquiry structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_Inquiry (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_StdInquiryDataTypeDef *inquiry) +{ + USBH_StatusTypeDef error = USBH_FAIL ; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_INQUIRY; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_INQUIRY; + MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5); + MSC_Handle->hbot.cbw.field.CB[2] = 0; + MSC_Handle->hbot.cbw.field.CB[3] = 0; + MSC_Handle->hbot.cbw.field.CB[4] = 0x24; + MSC_Handle->hbot.cbw.field.CB[5] = 0; + + MSC_Handle->hbot.state = BOT_SEND_CBW; + + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + + error = USBH_MSC_BOT_Process(phost, lun); + + if(error == USBH_OK) + { + USBH_memset(inquiry, 0, sizeof(SCSI_StdInquiryDataTypeDef)); + /*assign Inquiry Data */ + inquiry->DeviceType = MSC_Handle->hbot.pbuf[0] & 0x1F; + inquiry->PeripheralQualifier = MSC_Handle->hbot.pbuf[0] >> 5; + inquiry->RemovableMedia = (MSC_Handle->hbot.pbuf[1] & 0x80)== 0x80; + USBH_memcpy (inquiry->vendor_id, &MSC_Handle->hbot.pbuf[8], 8); + USBH_memcpy (inquiry->product_id, &MSC_Handle->hbot.pbuf[16], 16); + USBH_memcpy (inquiry->revision_id, &MSC_Handle->hbot.pbuf[32], 4); + } + break; + + default: + break; + } + + return error; +} + +/** + * @brief USBH_MSC_SCSI_RequestSense + * Issue RequestSense command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param capacity: pointer to the sense data structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_RequestSense (USBH_HandleTypeDef *phost, + uint8_t lun, + SCSI_SenseTypeDef *sense_data) +{ + USBH_StatusTypeDef error = USBH_FAIL ; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = DATA_LEN_REQUEST_SENSE; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_REQUEST_SENSE; + MSC_Handle->hbot.cbw.field.CB[1] = (lun << 5); + MSC_Handle->hbot.cbw.field.CB[2] = 0; + MSC_Handle->hbot.cbw.field.CB[3] = 0; + MSC_Handle->hbot.cbw.field.CB[4] = DATA_LEN_REQUEST_SENSE; + MSC_Handle->hbot.cbw.field.CB[5] = 0; + + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + MSC_Handle->hbot.pbuf = (uint8_t *)MSC_Handle->hbot.data; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + + error = USBH_MSC_BOT_Process(phost, lun); + + if(error == USBH_OK) + { + sense_data->key = MSC_Handle->hbot.pbuf[2] & 0x0F; + sense_data->asc = MSC_Handle->hbot.pbuf[12]; + sense_data->ascq = MSC_Handle->hbot.pbuf[13]; + } + break; + + default: + break; + } + + return error; +} + +/** + * @brief USBH_MSC_SCSI_Write + * Issue write10 command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param address: sector address + * @param pbuf: pointer to data + * @param length: number of sector to write + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_Write(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length) +{ + USBH_StatusTypeDef error = USBH_FAIL ; + + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_OUT; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_WRITE10; + + /*logical block address*/ + MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]); + MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]); + MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]); + MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]); + + + /*Tranfer length */ + MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ; + MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ; + + + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + MSC_Handle->hbot.pbuf = pbuf; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + error = USBH_MSC_BOT_Process(phost, lun); + break; + + default: + break; + } + + return error; +} + +/** + * @brief USBH_MSC_SCSI_Read + * Issue Read10 command. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @param address: sector address + * @param pbuf: pointer to data + * @param length: number of sector to read + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MSC_SCSI_Read(USBH_HandleTypeDef *phost, + uint8_t lun, + uint32_t address, + uint8_t *pbuf, + uint32_t length) +{ + USBH_StatusTypeDef error = USBH_FAIL ; + MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; + + switch(MSC_Handle->hbot.cmd_state) + { + case BOT_CMD_SEND: + + /*Prepare the CBW and relevent field*/ + MSC_Handle->hbot.cbw.field.DataTransferLength = length * 512; + MSC_Handle->hbot.cbw.field.Flags = USB_EP_DIR_IN; + MSC_Handle->hbot.cbw.field.CBLength = CBW_LENGTH; + + USBH_memset(MSC_Handle->hbot.cbw.field.CB, 0, CBW_CB_LENGTH); + MSC_Handle->hbot.cbw.field.CB[0] = OPCODE_READ10; + + /*logical block address*/ + MSC_Handle->hbot.cbw.field.CB[2] = (((uint8_t*)&address)[3]); + MSC_Handle->hbot.cbw.field.CB[3] = (((uint8_t*)&address)[2]); + MSC_Handle->hbot.cbw.field.CB[4] = (((uint8_t*)&address)[1]); + MSC_Handle->hbot.cbw.field.CB[5] = (((uint8_t*)&address)[0]); + + + /*Tranfer length */ + MSC_Handle->hbot.cbw.field.CB[7] = (((uint8_t *)&length)[1]) ; + MSC_Handle->hbot.cbw.field.CB[8] = (((uint8_t *)&length)[0]) ; + + + MSC_Handle->hbot.state = BOT_SEND_CBW; + MSC_Handle->hbot.cmd_state = BOT_CMD_WAIT; + MSC_Handle->hbot.pbuf = pbuf; + error = USBH_BUSY; + break; + + case BOT_CMD_WAIT: + error = USBH_MSC_BOT_Process(phost, lun); + break; + + default: + break; + } + + return error; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h new file mode 100755 index 0000000..704a410 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp.h @@ -0,0 +1,263 @@ +/** + ****************************************************************************** + * @file usbh_mtp.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_mtp.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MTP_CORE_H +#define __USBH_MTP_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_mtp_ptp.h" +#include "usbh_core.h" + + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_MTP_CLASS +* @{ +*/ + +/** @defgroup USBH_MTP_CORE +* @brief This file is the Header file for USBH_MTP_CORE.c +* @{ +*/ + + + + +/*Communication Class codes*/ +#define USB_MTP_CLASS 0x06 /* Still Image Class)*/ +#define MTP_MAX_STORAGE_UNITS_NBR PTP_MAX_STORAGE_UNITS_NBR + +/** + * @} + */ + +/** @defgroup USBH_MTP_CORE_Exported_Types +* @{ +*/ +typedef enum +{ + MTP_IDLE = 0, + MTP_GETDEVICEINFO , + MTP_OPENSESSION , + MTP_CLOSESESSION , + MTP_GETSTORAGEIDS , + MTP_GETSTORAGEINFO , +} +MTP_StateTypeDef; + + +typedef enum +{ + MTP_EVENTS_INIT = 0, + MTP_EVENTS_GETDATA , +} +MTP_EventsStateTypeDef; + + +typedef struct +{ + MTP_EventsStateTypeDef state; + uint32_t timer; + uint16_t poll; + PTP_EventContainerTypedef container; +} +MTP_EventHandleTypedef; + +typedef struct +{ + + uint32_t CurrentStorageId; + uint32_t ObjectFormatCode; + uint32_t CurrentObjectHandler; + uint8_t ObjectHandlerNbr; + uint32_t Objdepth; +} +MTP_ParamsTypedef; + + +typedef struct +{ + PTP_DeviceInfoTypedef devinfo; + PTP_StorageIDsTypedef storids; + PTP_StorageInfoTypedef storinfo[MTP_MAX_STORAGE_UNITS_NBR]; + PTP_ObjectHandlesTypedef Handles; +} +MTP_InfoTypedef; + +/* Structure for MTP process */ +typedef struct _MTP_Process +{ + MTP_InfoTypedef info; + MTP_ParamsTypedef params; + + uint8_t DataInPipe; + uint8_t DataOutPipe; + uint8_t NotificationPipe; + + uint8_t DataOutEp; + uint8_t DataInEp; + uint8_t NotificationEp; + + uint16_t DataOutEpSize; + uint16_t DataInEpSize; + uint16_t NotificationEpSize; + MTP_StateTypeDef state; + MTP_EventHandleTypedef events; + PTP_HandleTypeDef ptp; + uint32_t current_storage_unit; + uint32_t is_ready; +} +MTP_HandleTypeDef; + +#define MTP_StorageInfoTypedef PTP_StorageInfoTypedef +#define MTP_ObjectHandlesTypedef PTP_ObjectHandlesTypedef +#define MTP_ObjectInfoTypedef PTP_ObjectInfoTypedef +/** +* @} +*/ + +/** @defgroup USBH_MTP_CORE_Exported_Defines +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBH_MTP_CORE_Exported_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_MTP_CORE_Exported_Variables +* @{ +*/ +extern USBH_ClassTypeDef MTP_Class; +#define USBH_MTP_CLASS &MTP_Class + +/** +* @} +*/ + +/** @defgroup USBH_MTP_CORE_Exported_FunctionsPrototype +* @{ +*/ +uint8_t USBH_MTP_IsReady (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_MTP_SelectStorage (USBH_HandleTypeDef *phost, uint8_t storage_idx); +USBH_StatusTypeDef USBH_MTP_GetNumStorage (USBH_HandleTypeDef *phost, uint8_t *storage_num); +USBH_StatusTypeDef USBH_MTP_GetNumObjects (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + uint32_t* numobs); +USBH_StatusTypeDef USBH_MTP_GetStorageInfo (USBH_HandleTypeDef *phost, + uint8_t storage_idx, + MTP_StorageInfoTypedef *info); + +USBH_StatusTypeDef USBH_MTP_GetObjectHandles (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + PTP_ObjectHandlesTypedef* objecthandles); + +USBH_StatusTypeDef USBH_MTP_GetObjectInfo (USBH_HandleTypeDef *phost, + uint32_t handle, + PTP_ObjectInfoTypedef* objectinfo); + +USBH_StatusTypeDef USBH_MTP_DeleteObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t objectformatcode); + +USBH_StatusTypeDef USBH_MTP_GetObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object); + +USBH_StatusTypeDef USBH_MTP_GetPartialObject(USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t offset, + uint32_t maxbytes, + uint8_t *object, + uint32_t *len); + +USBH_StatusTypeDef USBH_MTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost, + uint16_t ofc, + uint32_t *propnum, + uint16_t *props); + +USBH_StatusTypeDef USBH_MTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, + uint16_t opc, + uint16_t ofc, + PTP_ObjectPropDescTypeDef *opd); + +USBH_StatusTypeDef USBH_MTP_GetObjectPropList (USBH_HandleTypeDef *phost, + uint32_t handle, + MTP_PropertiesTypedef *pprops, + uint32_t *nrofprops); + +USBH_StatusTypeDef USBH_MTP_SendObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object, + uint32_t size); + +USBH_StatusTypeDef USBH_MTP_GetDevicePropDesc (USBH_HandleTypeDef *phost, + uint16_t propcode, + PTP_DevicePropDescTypdef* devicepropertydesc); + +void USBH_MTP_EventsCallback(USBH_HandleTypeDef *phost, uint32_t event, uint32_t param); +/** +* @} +*/ + + +#endif /* __USBH_MTP_CORE_H */ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h new file mode 100755 index 0000000..3fbddd8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Inc/usbh_mtp_ptp.h @@ -0,0 +1,1038 @@ +/** + ****************************************************************************** + * @file usbh_mtp_ptp.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_mtp_ptp.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MTP_PTP_H__ +#define __USBH_MTP_PTP_H__ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_CLASS + * @{ + */ + +/** @addtogroup USBH_MTP_PTP_CLASS + * @{ + */ + +/** @defgroup USBH_MTP_PTP + * @brief This file is the Header file for usbh_mtp_ptp.c + * @{ + */ + + +/* Operation Codes */ + +/* PTP v1.0 operation codes */ +#define PTP_OC_Undefined 0x1000 +#define PTP_OC_GetDeviceInfo 0x1001 +#define PTP_OC_OpenSession 0x1002 +#define PTP_OC_CloseSession 0x1003 +#define PTP_OC_GetStorageIDs 0x1004 +#define PTP_OC_GetStorageInfo 0x1005 +#define PTP_OC_GetNumObjects 0x1006 +#define PTP_OC_GetObjectHandles 0x1007 +#define PTP_OC_GetObjectInfo 0x1008 +#define PTP_OC_GetObject 0x1009 +#define PTP_OC_GetThumb 0x100A +#define PTP_OC_DeleteObject 0x100B +#define PTP_OC_SendObjectInfo 0x100C +#define PTP_OC_SendObject 0x100D +#define PTP_OC_InitiateCapture 0x100E +#define PTP_OC_FormatStore 0x100F +#define PTP_OC_ResetDevice 0x1010 +#define PTP_OC_SelfTest 0x1011 +#define PTP_OC_SetObjectProtection 0x1012 +#define PTP_OC_PowerDown 0x1013 +#define PTP_OC_GetDevicePropDesc 0x1014 +#define PTP_OC_GetDevicePropValue 0x1015 +#define PTP_OC_SetDevicePropValue 0x1016 +#define PTP_OC_ResetDevicePropValue 0x1017 +#define PTP_OC_TerminateOpenCapture 0x1018 +#define PTP_OC_MoveObject 0x1019 +#define PTP_OC_CopyObject 0x101A +#define PTP_OC_GetPartialObject 0x101B +#define PTP_OC_InitiateOpenCapture 0x101C + +/* PTP v1.1 operation codes */ +#define PTP_OC_StartEnumHandles 0x101D +#define PTP_OC_EnumHandles 0x101E +#define PTP_OC_StopEnumHandles 0x101F +#define PTP_OC_GetVendorExtensionMaps 0x1020 +#define PTP_OC_GetVendorDeviceInfo 0x1021 +#define PTP_OC_GetResizedImageObject 0x1022 +#define PTP_OC_GetFilesystemManifest 0x1023 +#define PTP_OC_GetStreamInfo 0x1024 +#define PTP_OC_GetStream 0x1025 + + /* Microsoft / MTP extension codes */ +#define PTP_OC_GetObjectPropsSupported 0x9801 +#define PTP_OC_GetObjectPropDesc 0x9802 +#define PTP_OC_GetObjectPropValue 0x9803 +#define PTP_OC_SetObjectPropValue 0x9804 +#define PTP_OC_GetObjPropList 0x9805 +#define PTP_OC_SetObjPropList 0x9806 +#define PTP_OC_GetInterdependendPropdesc 0x9807 +#define PTP_OC_SendObjectPropList 0x9808 +#define PTP_OC_GetObjectReferences 0x9810 +#define PTP_OC_SetObjectReferences 0x9811 +#define PTP_OC_UpdateDeviceFirmware 0x9812 +#define PTP_OC_Skip 0x9820 + + +/* Response Codes */ + +/* PTP v1.0 response codes */ +#define PTP_RC_Undefined 0x2000 +#define PTP_RC_OK 0x2001 +#define PTP_RC_GeneralError 0x2002 +#define PTP_RC_SessionNotOpen 0x2003 +#define PTP_RC_InvalidTransactionID 0x2004 +#define PTP_RC_OperationNotSupported 0x2005 +#define PTP_RC_ParameterNotSupported 0x2006 +#define PTP_RC_IncompleteTransfer 0x2007 +#define PTP_RC_InvalidStorageId 0x2008 +#define PTP_RC_InvalidObjectHandle 0x2009 +#define PTP_RC_DevicePropNotSupported 0x200A +#define PTP_RC_InvalidObjectFormatCode 0x200B +#define PTP_RC_StoreFull 0x200C +#define PTP_RC_ObjectWriteProtected 0x200D +#define PTP_RC_StoreReadOnly 0x200E +#define PTP_RC_AccessDenied 0x200F +#define PTP_RC_NoThumbnailPresent 0x2010 +#define PTP_RC_SelfTestFailed 0x2011 +#define PTP_RC_PartialDeletion 0x2012 +#define PTP_RC_StoreNotAvailable 0x2013 +#define PTP_RC_SpecificationByFormatUnsupported 0x2014 +#define PTP_RC_NoValidObjectInfo 0x2015 +#define PTP_RC_InvalidCodeFormat 0x2016 +#define PTP_RC_UnknownVendorCode 0x2017 +#define PTP_RC_CaptureAlreadyTerminated 0x2018 +#define PTP_RC_DeviceBusy 0x2019 +#define PTP_RC_InvalidParentObject 0x201A +#define PTP_RC_InvalidDevicePropFormat 0x201B +#define PTP_RC_InvalidDevicePropValue 0x201C +#define PTP_RC_InvalidParameter 0x201D +#define PTP_RC_SessionAlreadyOpened 0x201E +#define PTP_RC_TransactionCanceled 0x201F +#define PTP_RC_SpecificationOfDestinationUnsupported 0x2020 +/* PTP v1.1 response codes */ +#define PTP_RC_InvalidEnumHandle 0x2021 +#define PTP_RC_NoStreamEnabled 0x2022 +#define PTP_RC_InvalidDataSet 0x2023 + +/* USB container types */ + +#define PTP_USB_CONTAINER_UNDEFINED 0x0000 +#define PTP_USB_CONTAINER_COMMAND 0x0001 +#define PTP_USB_CONTAINER_DATA 0x0002 +#define PTP_USB_CONTAINER_RESPONSE 0x0003 +#define PTP_USB_CONTAINER_EVENT 0x0004 + +/* PTP/IP definitions */ +#define PTPIP_INIT_COMMAND_REQUEST 1 +#define PTPIP_INIT_COMMAND_ACK 2 +#define PTPIP_INIT_EVENT_REQUEST 3 +#define PTPIP_INIT_EVENT_ACK 4 +#define PTPIP_INIT_FAIL 5 +#define PTPIP_CMD_REQUEST 6 +#define PTPIP_CMD_RESPONSE 7 +#define PTPIP_EVENT 8 +#define PTPIP_START_DATA_PACKET 9 +#define PTPIP_DATA_PACKET 10 +#define PTPIP_CANCEL_TRANSACTION 11 +#define PTPIP_END_DATA_PACKET 12 +#define PTPIP_PING 13 +#define PTPIP_PONG 14 + +/* Transaction data phase description */ +#define PTP_DP_NODATA 0x0000 /* no data phase */ +#define PTP_DP_SENDDATA 0x0001 /* sending data */ +#define PTP_DP_GETDATA 0x0002 /* receiving data */ +#define PTP_DP_DATA_MASK 0x00ff /* data phase mask */ + +/** @defgroup USBH_MTP_PTP_Exported_Types + * @{ + */ + +typedef enum +{ + PTP_REQ_IDLE = 0, + PTP_REQ_SEND = 1, + PTP_REQ_WAIT, + PTP_REQ_ERROR, +} +PTP_RequestStateTypeDef; + +typedef enum +{ + PTP_IDLE = 0, + PTP_OP_REQUEST_STATE, + PTP_OP_REQUEST_WAIT_STATE, + PTP_DATA_OUT_PHASE_STATE, + PTP_DATA_OUT_PHASE_WAIT_STATE, + PTP_DATA_IN_PHASE_STATE, + PTP_DATA_IN_PHASE_WAIT_STATE, + PTP_RESPONSE_STATE, + PTP_RESPONSE_WAIT_STATE, + PTP_ERROR, +} +PTP_ProcessStateTypeDef; + +/* PTP request/response/event general PTP container (transport independent) */ +typedef struct +{ + uint16_t Code; + uint32_t SessionID; + uint32_t Transaction_ID; + /* params may be of any type of size less or equal to uint32_t */ + uint32_t Param1; + uint32_t Param2; + uint32_t Param3; + /* events can only have three parameters */ + uint32_t Param4; + uint32_t Param5; + /* the number of meaningfull parameters */ + uint8_t Nparam; +} +PTP_ContainerTypedef; + +#define PTP_USB_BULK_HS_MAX_PACKET_LEN_WRITE 1024 +#define PTP_USB_BULK_HS_MAX_PACKET_LEN_READ 1024 +#define PTP_USB_BULK_HDR_LEN (2*sizeof(uint32_t)+2*sizeof(uint16_t)) +#define PTP_USB_BULK_PAYLOAD_LEN_WRITE (PTP_USB_BULK_HS_MAX_PACKET_LEN_WRITE-PTP_USB_BULK_HDR_LEN) +#define PTP_USB_BULK_PAYLOAD_LEN_READ (PTP_USB_BULK_HS_MAX_PACKET_LEN_READ-PTP_USB_BULK_HDR_LEN) +#define PTP_USB_BULK_REQ_LEN (PTP_USB_BULK_HDR_LEN+5*sizeof(uint32_t)) +#define PTP_USB_BULK_REQ_RESP_MAX_LEN 63 + +typedef struct +{ + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + uint32_t param1; + uint32_t param2; + uint32_t param3; + uint32_t param4; + uint32_t param5; +} +PTP_RespContainerTypedef; + + +typedef struct +{ + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + uint32_t param1; + uint32_t param2; + uint32_t param3; + uint32_t param4; + uint32_t param5; +} +PTP_OpContainerTypedef; + +typedef struct +{ + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + union { + struct { + uint32_t param1; + uint32_t param2; + uint32_t param3; + uint32_t param4; + uint32_t param5; + } params; + uint8_t data[PTP_USB_BULK_PAYLOAD_LEN_READ]; + }payload; +} +PTP_DataContainerTypedef; + +/* PTP USB Asynchronous Event Interrupt Data Format */ +typedef struct +{ + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + uint32_t param1; + uint32_t param2; + uint32_t param3; +} +PTP_EventContainerTypedef; + +/* Structure for PTP Transport process */ +typedef struct +{ + PTP_ProcessStateTypeDef state; + PTP_RequestStateTypeDef req_state; + PTP_OpContainerTypedef op_container; + PTP_DataContainerTypedef data_container; + PTP_RespContainerTypedef resp_container; + + /* ptp transaction ID */ + uint32_t transaction_id; + + /* ptp session ID */ + uint32_t session_id; + + /* device flags */ + uint32_t flags; + + /****** PTP transfer control *******/ + + /* Data pointer */ + uint8_t *data_ptr; + + /* Data length */ + int32_t data_length; + + /* Data length */ + uint32_t data_packet; + + /* Data length */ + uint32_t iteration; + + /* Packet Index */ + uint32_t data_packet_counter; + + /****** Object transfer control *******/ + + /* object pointer */ + uint8_t *object_ptr; + +} +PTP_HandleTypeDef; + +/* DeviceInfo data offset */ +#define PTP_di_StandardVersion 0 +#define PTP_di_VendorExtensionID 2 +#define PTP_di_VendorExtensionVersion 6 +#define PTP_di_VendorExtensionDesc 8 +#define PTP_di_FunctionalMode 8 +#define PTP_di_OperationsSupported 10 + +/* Max info items size */ +#define PTP_SUPPORTED_OPERATIONS_NBR 100 +#define PTP_SUPPORTED_EVENTS_NBR 100 +#define PTP_SUPPORTED_PROPRIETIES_NBR 100 +#define PTP_CAPTURE_FORMATS_NBR 100 +#define PTP_IMAGE_FORMATS_NBR 100 +#define PTP_MAX_STR_SIZE 255 +/* PTP device info structure */ +typedef struct +{ + uint16_t StandardVersion; + uint32_t VendorExtensionID; + uint16_t VendorExtensionVersion; + uint8_t VendorExtensionDesc[PTP_MAX_STR_SIZE]; + uint16_t FunctionalMode; + uint32_t OperationsSupported_len; + uint16_t OperationsSupported[PTP_SUPPORTED_OPERATIONS_NBR]; + uint32_t EventsSupported_len; + uint16_t EventsSupported[PTP_SUPPORTED_EVENTS_NBR]; + uint32_t DevicePropertiesSupported_len; + uint16_t DevicePropertiesSupported[PTP_SUPPORTED_PROPRIETIES_NBR]; + uint32_t CaptureFormats_len; + uint16_t CaptureFormats[PTP_CAPTURE_FORMATS_NBR]; + uint32_t ImageFormats_len; + uint16_t ImageFormats[PTP_IMAGE_FORMATS_NBR]; + uint8_t Manufacturer[PTP_MAX_STR_SIZE]; + uint8_t Model[PTP_MAX_STR_SIZE]; + uint8_t DeviceVersion[PTP_MAX_STR_SIZE]; + uint8_t SerialNumber[PTP_MAX_STR_SIZE]; +} +PTP_DeviceInfoTypedef; + +#define PTP_MAX_STORAGE_UNITS_NBR 5 +/* PTP storageIDs structute (returned by GetStorageIDs) */ +typedef struct +{ + uint32_t n; + uint32_t Storage [PTP_MAX_STORAGE_UNITS_NBR]; +} +PTP_StorageIDsTypedef; + +/* PTP StorageInfo structure (returned by GetStorageInfo) */ + +#define PTP_si_StorageType 0 +#define PTP_si_FilesystemType 2 +#define PTP_si_AccessCapability 4 +#define PTP_si_MaxCapability 6 +#define PTP_si_FreeSpaceInBytes 14 +#define PTP_si_FreeSpaceInImages 22 +#define PTP_si_StorageDescription 26 + + +/* PTP Storage Types */ + +#define PTP_ST_Undefined 0x0000 +#define PTP_ST_FixedROM 0x0001 +#define PTP_ST_RemovableROM 0x0002 +#define PTP_ST_FixedRAM 0x0003 +#define PTP_ST_RemovableRAM 0x0004 + +/* PTP FilesystemType Values */ + +#define PTP_FST_Undefined 0x0000 +#define PTP_FST_GenericFlat 0x0001 +#define PTP_FST_GenericHierarchical 0x0002 +#define PTP_FST_DCF 0x0003 + +/* PTP StorageInfo AccessCapability Values */ + +#define PTP_AC_ReadWrite 0x0000 +#define PTP_AC_ReadOnly 0x0001 +#define PTP_AC_ReadOnly_with_Object_Deletion 0x0002 + +typedef struct +{ + uint16_t StorageType; + uint16_t FilesystemType; + uint16_t AccessCapability; + uint64_t MaxCapability; + uint64_t FreeSpaceInBytes; + uint32_t FreeSpaceInImages; + uint8_t StorageDescription[PTP_MAX_STR_SIZE]; + uint8_t VolumeLabel[PTP_MAX_STR_SIZE]; +} +PTP_StorageInfoTypedef; + +/* PTP Object Format Codes */ + +/* ancillary formats */ +#define PTP_OFC_Undefined 0x3000 +#define PTP_OFC_Defined 0x3800 +#define PTP_OFC_Association 0x3001 +#define PTP_OFC_Script 0x3002 +#define PTP_OFC_Executable 0x3003 +#define PTP_OFC_Text 0x3004 +#define PTP_OFC_HTML 0x3005 +#define PTP_OFC_DPOF 0x3006 +#define PTP_OFC_AIFF 0x3007 +#define PTP_OFC_WAV 0x3008 +#define PTP_OFC_MP3 0x3009 +#define PTP_OFC_AVI 0x300A +#define PTP_OFC_MPEG 0x300B +#define PTP_OFC_ASF 0x300C +#define PTP_OFC_QT 0x300D /* guessing */ +/* image formats */ +#define PTP_OFC_EXIF_JPEG 0x3801 +#define PTP_OFC_TIFF_EP 0x3802 +#define PTP_OFC_FlashPix 0x3803 +#define PTP_OFC_BMP 0x3804 +#define PTP_OFC_CIFF 0x3805 +#define PTP_OFC_Undefined_0x3806 0x3806 +#define PTP_OFC_GIF 0x3807 +#define PTP_OFC_JFIF 0x3808 +#define PTP_OFC_PCD 0x3809 +#define PTP_OFC_PICT 0x380A +#define PTP_OFC_PNG 0x380B +#define PTP_OFC_Undefined_0x380C 0x380C +#define PTP_OFC_TIFF 0x380D +#define PTP_OFC_TIFF_IT 0x380E +#define PTP_OFC_JP2 0x380F +#define PTP_OFC_JPX 0x3810 +/* ptp v1.1 has only DNG new */ +#define PTP_OFC_DNG 0x3811 + +/* MTP extensions */ +#define PTP_OFC_MTP_MediaCard 0xb211 +#define PTP_OFC_MTP_MediaCardGroup 0xb212 +#define PTP_OFC_MTP_Encounter 0xb213 +#define PTP_OFC_MTP_EncounterBox 0xb214 +#define PTP_OFC_MTP_M4A 0xb215 +#define PTP_OFC_MTP_ZUNEUNDEFINED 0xb217 /* Unknown file type */ +#define PTP_OFC_MTP_Firmware 0xb802 +#define PTP_OFC_MTP_WindowsImageFormat 0xb881 +#define PTP_OFC_MTP_UndefinedAudio 0xb900 +#define PTP_OFC_MTP_WMA 0xb901 +#define PTP_OFC_MTP_OGG 0xb902 +#define PTP_OFC_MTP_AAC 0xb903 +#define PTP_OFC_MTP_AudibleCodec 0xb904 +#define PTP_OFC_MTP_FLAC 0xb906 +#define PTP_OFC_MTP_SamsungPlaylist 0xb909 +#define PTP_OFC_MTP_UndefinedVideo 0xb980 +#define PTP_OFC_MTP_WMV 0xb981 +#define PTP_OFC_MTP_MP4 0xb982 +#define PTP_OFC_MTP_MP2 0xb983 +#define PTP_OFC_MTP_3GP 0xb984 +#define PTP_OFC_MTP_UndefinedCollection 0xba00 +#define PTP_OFC_MTP_AbstractMultimediaAlbum 0xba01 +#define PTP_OFC_MTP_AbstractImageAlbum 0xba02 +#define PTP_OFC_MTP_AbstractAudioAlbum 0xba03 +#define PTP_OFC_MTP_AbstractVideoAlbum 0xba04 +#define PTP_OFC_MTP_AbstractAudioVideoPlaylist 0xba05 +#define PTP_OFC_MTP_AbstractContactGroup 0xba06 +#define PTP_OFC_MTP_AbstractMessageFolder 0xba07 +#define PTP_OFC_MTP_AbstractChapteredProduction 0xba08 +#define PTP_OFC_MTP_AbstractAudioPlaylist 0xba09 +#define PTP_OFC_MTP_AbstractVideoPlaylist 0xba0a +#define PTP_OFC_MTP_AbstractMediacast 0xba0b +#define PTP_OFC_MTP_WPLPlaylist 0xba10 +#define PTP_OFC_MTP_M3UPlaylist 0xba11 +#define PTP_OFC_MTP_MPLPlaylist 0xba12 +#define PTP_OFC_MTP_ASXPlaylist 0xba13 +#define PTP_OFC_MTP_PLSPlaylist 0xba14 +#define PTP_OFC_MTP_UndefinedDocument 0xba80 +#define PTP_OFC_MTP_AbstractDocument 0xba81 +#define PTP_OFC_MTP_XMLDocument 0xba82 +#define PTP_OFC_MTP_MSWordDocument 0xba83 +#define PTP_OFC_MTP_MHTCompiledHTMLDocument 0xba84 +#define PTP_OFC_MTP_MSExcelSpreadsheetXLS 0xba85 +#define PTP_OFC_MTP_MSPowerpointPresentationPPT 0xba86 +#define PTP_OFC_MTP_UndefinedMessage 0xbb00 +#define PTP_OFC_MTP_AbstractMessage 0xbb01 +#define PTP_OFC_MTP_UndefinedContact 0xbb80 +#define PTP_OFC_MTP_AbstractContact 0xbb81 +#define PTP_OFC_MTP_vCard2 0xbb82 +#define PTP_OFC_MTP_vCard3 0xbb83 +#define PTP_OFC_MTP_UndefinedCalendarItem 0xbe00 +#define PTP_OFC_MTP_AbstractCalendarItem 0xbe01 +#define PTP_OFC_MTP_vCalendar1 0xbe02 +#define PTP_OFC_MTP_vCalendar2 0xbe03 +#define PTP_OFC_MTP_UndefinedWindowsExecutable 0xbe80 +#define PTP_OFC_MTP_MediaCast 0xbe81 +#define PTP_OFC_MTP_Section 0xbe82 + +/* MTP specific Object Properties */ +#define PTP_OPC_StorageID 0xDC01 +#define PTP_OPC_ObjectFormat 0xDC02 +#define PTP_OPC_ProtectionStatus 0xDC03 +#define PTP_OPC_ObjectSize 0xDC04 +#define PTP_OPC_AssociationType 0xDC05 +#define PTP_OPC_AssociationDesc 0xDC06 +#define PTP_OPC_ObjectFileName 0xDC07 +#define PTP_OPC_DateCreated 0xDC08 +#define PTP_OPC_DateModified 0xDC09 +#define PTP_OPC_Keywords 0xDC0A +#define PTP_OPC_ParentObject 0xDC0B +#define PTP_OPC_AllowedFolderContents 0xDC0C +#define PTP_OPC_Hidden 0xDC0D +#define PTP_OPC_SystemObject 0xDC0E +#define PTP_OPC_PersistantUniqueObjectIdentifier 0xDC41 +#define PTP_OPC_SyncID 0xDC42 +#define PTP_OPC_PropertyBag 0xDC43 +#define PTP_OPC_Name 0xDC44 +#define PTP_OPC_CreatedBy 0xDC45 +#define PTP_OPC_Artist 0xDC46 +#define PTP_OPC_DateAuthored 0xDC47 +#define PTP_OPC_Description 0xDC48 +#define PTP_OPC_URLReference 0xDC49 +#define PTP_OPC_LanguageLocale 0xDC4A +#define PTP_OPC_CopyrightInformation 0xDC4B +#define PTP_OPC_Source 0xDC4C +#define PTP_OPC_OriginLocation 0xDC4D +#define PTP_OPC_DateAdded 0xDC4E +#define PTP_OPC_NonConsumable 0xDC4F +#define PTP_OPC_CorruptOrUnplayable 0xDC50 +#define PTP_OPC_ProducerSerialNumber 0xDC51 +#define PTP_OPC_RepresentativeSampleFormat 0xDC81 +#define PTP_OPC_RepresentativeSampleSize 0xDC82 +#define PTP_OPC_RepresentativeSampleHeight 0xDC83 +#define PTP_OPC_RepresentativeSampleWidth 0xDC84 +#define PTP_OPC_RepresentativeSampleDuration 0xDC85 +#define PTP_OPC_RepresentativeSampleData 0xDC86 +#define PTP_OPC_Width 0xDC87 +#define PTP_OPC_Height 0xDC88 +#define PTP_OPC_Duration 0xDC89 +#define PTP_OPC_Rating 0xDC8A +#define PTP_OPC_Track 0xDC8B +#define PTP_OPC_Genre 0xDC8C +#define PTP_OPC_Credits 0xDC8D +#define PTP_OPC_Lyrics 0xDC8E +#define PTP_OPC_SubscriptionContentID 0xDC8F +#define PTP_OPC_ProducedBy 0xDC90 +#define PTP_OPC_UseCount 0xDC91 +#define PTP_OPC_SkipCount 0xDC92 +#define PTP_OPC_LastAccessed 0xDC93 +#define PTP_OPC_ParentalRating 0xDC94 +#define PTP_OPC_MetaGenre 0xDC95 +#define PTP_OPC_Composer 0xDC96 +#define PTP_OPC_EffectiveRating 0xDC97 +#define PTP_OPC_Subtitle 0xDC98 +#define PTP_OPC_OriginalReleaseDate 0xDC99 +#define PTP_OPC_AlbumName 0xDC9A +#define PTP_OPC_AlbumArtist 0xDC9B +#define PTP_OPC_Mood 0xDC9C +#define PTP_OPC_DRMStatus 0xDC9D +#define PTP_OPC_SubDescription 0xDC9E +#define PTP_OPC_IsCropped 0xDCD1 +#define PTP_OPC_IsColorCorrected 0xDCD2 +#define PTP_OPC_ImageBitDepth 0xDCD3 +#define PTP_OPC_Fnumber 0xDCD4 +#define PTP_OPC_ExposureTime 0xDCD5 +#define PTP_OPC_ExposureIndex 0xDCD6 +#define PTP_OPC_DisplayName 0xDCE0 +#define PTP_OPC_BodyText 0xDCE1 +#define PTP_OPC_Subject 0xDCE2 +#define PTP_OPC_Priority 0xDCE3 +#define PTP_OPC_GivenName 0xDD00 +#define PTP_OPC_MiddleNames 0xDD01 +#define PTP_OPC_FamilyName 0xDD02 +#define PTP_OPC_Prefix 0xDD03 +#define PTP_OPC_Suffix 0xDD04 +#define PTP_OPC_PhoneticGivenName 0xDD05 +#define PTP_OPC_PhoneticFamilyName 0xDD06 +#define PTP_OPC_EmailPrimary 0xDD07 +#define PTP_OPC_EmailPersonal1 0xDD08 +#define PTP_OPC_EmailPersonal2 0xDD09 +#define PTP_OPC_EmailBusiness1 0xDD0A +#define PTP_OPC_EmailBusiness2 0xDD0B +#define PTP_OPC_EmailOthers 0xDD0C +#define PTP_OPC_PhoneNumberPrimary 0xDD0D +#define PTP_OPC_PhoneNumberPersonal 0xDD0E +#define PTP_OPC_PhoneNumberPersonal2 0xDD0F +#define PTP_OPC_PhoneNumberBusiness 0xDD10 +#define PTP_OPC_PhoneNumberBusiness2 0xDD11 +#define PTP_OPC_PhoneNumberMobile 0xDD12 +#define PTP_OPC_PhoneNumberMobile2 0xDD13 +#define PTP_OPC_FaxNumberPrimary 0xDD14 +#define PTP_OPC_FaxNumberPersonal 0xDD15 +#define PTP_OPC_FaxNumberBusiness 0xDD16 +#define PTP_OPC_PagerNumber 0xDD17 +#define PTP_OPC_PhoneNumberOthers 0xDD18 +#define PTP_OPC_PrimaryWebAddress 0xDD19 +#define PTP_OPC_PersonalWebAddress 0xDD1A +#define PTP_OPC_BusinessWebAddress 0xDD1B +#define PTP_OPC_InstantMessengerAddress 0xDD1C +#define PTP_OPC_InstantMessengerAddress2 0xDD1D +#define PTP_OPC_InstantMessengerAddress3 0xDD1E +#define PTP_OPC_PostalAddressPersonalFull 0xDD1F +#define PTP_OPC_PostalAddressPersonalFullLine1 0xDD20 +#define PTP_OPC_PostalAddressPersonalFullLine2 0xDD21 +#define PTP_OPC_PostalAddressPersonalFullCity 0xDD22 +#define PTP_OPC_PostalAddressPersonalFullRegion 0xDD23 +#define PTP_OPC_PostalAddressPersonalFullPostalCode 0xDD24 +#define PTP_OPC_PostalAddressPersonalFullCountry 0xDD25 +#define PTP_OPC_PostalAddressBusinessFull 0xDD26 +#define PTP_OPC_PostalAddressBusinessLine1 0xDD27 +#define PTP_OPC_PostalAddressBusinessLine2 0xDD28 +#define PTP_OPC_PostalAddressBusinessCity 0xDD29 +#define PTP_OPC_PostalAddressBusinessRegion 0xDD2A +#define PTP_OPC_PostalAddressBusinessPostalCode 0xDD2B +#define PTP_OPC_PostalAddressBusinessCountry 0xDD2C +#define PTP_OPC_PostalAddressOtherFull 0xDD2D +#define PTP_OPC_PostalAddressOtherLine1 0xDD2E +#define PTP_OPC_PostalAddressOtherLine2 0xDD2F +#define PTP_OPC_PostalAddressOtherCity 0xDD30 +#define PTP_OPC_PostalAddressOtherRegion 0xDD31 +#define PTP_OPC_PostalAddressOtherPostalCode 0xDD32 +#define PTP_OPC_PostalAddressOtherCountry 0xDD33 +#define PTP_OPC_OrganizationName 0xDD34 +#define PTP_OPC_PhoneticOrganizationName 0xDD35 +#define PTP_OPC_Role 0xDD36 +#define PTP_OPC_Birthdate 0xDD37 +#define PTP_OPC_MessageTo 0xDD40 +#define PTP_OPC_MessageCC 0xDD41 +#define PTP_OPC_MessageBCC 0xDD42 +#define PTP_OPC_MessageRead 0xDD43 +#define PTP_OPC_MessageReceivedTime 0xDD44 +#define PTP_OPC_MessageSender 0xDD45 +#define PTP_OPC_ActivityBeginTime 0xDD50 +#define PTP_OPC_ActivityEndTime 0xDD51 +#define PTP_OPC_ActivityLocation 0xDD52 +#define PTP_OPC_ActivityRequiredAttendees 0xDD54 +#define PTP_OPC_ActivityOptionalAttendees 0xDD55 +#define PTP_OPC_ActivityResources 0xDD56 +#define PTP_OPC_ActivityAccepted 0xDD57 +#define PTP_OPC_Owner 0xDD5D +#define PTP_OPC_Editor 0xDD5E +#define PTP_OPC_Webmaster 0xDD5F +#define PTP_OPC_URLSource 0xDD60 +#define PTP_OPC_URLDestination 0xDD61 +#define PTP_OPC_TimeBookmark 0xDD62 +#define PTP_OPC_ObjectBookmark 0xDD63 +#define PTP_OPC_ByteBookmark 0xDD64 +#define PTP_OPC_LastBuildDate 0xDD70 +#define PTP_OPC_TimetoLive 0xDD71 +#define PTP_OPC_MediaGUID 0xDD72 +#define PTP_OPC_TotalBitRate 0xDE91 +#define PTP_OPC_BitRateType 0xDE92 +#define PTP_OPC_SampleRate 0xDE93 +#define PTP_OPC_NumberOfChannels 0xDE94 +#define PTP_OPC_AudioBitDepth 0xDE95 +#define PTP_OPC_ScanDepth 0xDE97 +#define PTP_OPC_AudioWAVECodec 0xDE99 +#define PTP_OPC_AudioBitRate 0xDE9A +#define PTP_OPC_VideoFourCCCodec 0xDE9B +#define PTP_OPC_VideoBitRate 0xDE9C +#define PTP_OPC_FramesPerThousandSeconds 0xDE9D +#define PTP_OPC_KeyFrameDistance 0xDE9E +#define PTP_OPC_BufferSize 0xDE9F +#define PTP_OPC_EncodingQuality 0xDEA0 +#define PTP_OPC_EncodingProfile 0xDEA1 +#define PTP_OPC_BuyFlag 0xD901 + +/* WiFi Provisioning MTP Extension property codes */ +#define PTP_OPC_WirelessConfigurationFile 0xB104 + + +/* PTP Association Types */ +#define PTP_AT_Undefined 0x0000 +#define PTP_AT_GenericFolder 0x0001 +#define PTP_AT_Album 0x0002 +#define PTP_AT_TimeSequence 0x0003 +#define PTP_AT_HorizontalPanoramic 0x0004 +#define PTP_AT_VerticalPanoramic 0x0005 +#define PTP_AT_2DPanoramic 0x0006 +#define PTP_AT_AncillaryData 0x0007 + +#define PTP_MAX_HANDLER_NBR 0x255 +typedef struct +{ + uint32_t n; + uint32_t Handler[PTP_MAX_HANDLER_NBR]; +} +PTP_ObjectHandlesTypedef; + + +#define PTP_oi_StorageID 0 +#define PTP_oi_ObjectFormat 4 +#define PTP_oi_ProtectionStatus 6 +#define PTP_oi_ObjectCompressedSize 8 +#define PTP_oi_ThumbFormat 12 +#define PTP_oi_ThumbCompressedSize 14 +#define PTP_oi_ThumbPixWidth 18 +#define PTP_oi_ThumbPixHeight 22 +#define PTP_oi_ImagePixWidth 26 +#define PTP_oi_ImagePixHeight 30 +#define PTP_oi_ImageBitDepth 34 +#define PTP_oi_ParentObject 38 +#define PTP_oi_AssociationType 42 +#define PTP_oi_AssociationDesc 44 +#define PTP_oi_SequenceNumber 48 +#define PTP_oi_filenamelen 52 +#define PTP_oi_Filename 53 + +typedef struct +{ + uint32_t StorageID; + uint16_t ObjectFormat; + uint16_t ProtectionStatus; + /* In the regular objectinfo this is 32bit, but we keep the general object size here + that also arrives via other methods and so use 64bit */ + uint64_t ObjectCompressedSize; + uint16_t ThumbFormat; + uint32_t ThumbCompressedSize; + uint32_t ThumbPixWidth; + uint32_t ThumbPixHeight; + uint32_t ImagePixWidth; + uint32_t ImagePixHeight; + uint32_t ImageBitDepth; + uint32_t ParentObject; + uint16_t AssociationType; + uint32_t AssociationDesc; + uint32_t SequenceNumber; + uint8_t Filename[PTP_MAX_STR_SIZE]; + uint32_t CaptureDate; + uint32_t ModificationDate; + uint8_t Keywords[PTP_MAX_STR_SIZE]; +} +PTP_ObjectInfoTypedef; + +/* Object Property Describing Dataset (DevicePropDesc) */ + +typedef union _PTP_PropertyValueTypedef +{ + char str[PTP_MAX_STR_SIZE]; + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + + struct array { + uint32_t count; + union _PTP_PropertyValueTypedef *v; + } a; +}PTP_PropertyValueTypedef; + +typedef struct +{ + PTP_PropertyValueTypedef MinimumValue; + PTP_PropertyValueTypedef MaximumValue; + PTP_PropertyValueTypedef StepSize; +} +PTP_PropDescRangeFormTypedef; + +/* Property Describing Dataset, Enum Form */ + +typedef struct +{ + uint16_t NumberOfValues; + PTP_PropertyValueTypedef SupportedValue[PTP_SUPPORTED_PROPRIETIES_NBR]; +} +PTP_PropDescEnumFormTypedef; + +/* (MTP) Object Property pack/unpack */ +#define PTP_opd_ObjectPropertyCode 0 +#define PTP_opd_DataType 2 +#define PTP_opd_GetSet 4 +#define PTP_opd_FactoryDefaultValue 5 + +typedef struct +{ + uint16_t ObjectPropertyCode; + uint16_t DataType; + uint8_t GetSet; + PTP_PropertyValueTypedef FactoryDefaultValue; + uint32_t GroupCode; + uint8_t FormFlag; + union { + PTP_PropDescEnumFormTypedef Enum; + PTP_PropDescRangeFormTypedef Range; + } FORM; +} +PTP_ObjectPropDescTypeDef; + +/* Metadata lists for MTP operations */ +typedef struct +{ + uint16_t property; + uint16_t datatype; + uint32_t ObjectHandle; + PTP_PropertyValueTypedef propval; +} +MTP_PropertiesTypedef; + + +/* Device Property Form Flag */ + +#define PTP_DPFF_None 0x00 +#define PTP_DPFF_Range 0x01 +#define PTP_DPFF_Enumeration 0x02 + +/* Object Property Codes used by MTP (first 3 are same as DPFF codes) */ +#define PTP_OPFF_None 0x00 +#define PTP_OPFF_Range 0x01 +#define PTP_OPFF_Enumeration 0x02 +#define PTP_OPFF_DateTime 0x03 +#define PTP_OPFF_FixedLengthArray 0x04 +#define PTP_OPFF_RegularExpression 0x05 +#define PTP_OPFF_ByteArray 0x06 +#define PTP_OPFF_LongString 0xFF + +/* Device Property pack/unpack */ + +#define PTP_dpd_DevicePropertyCode 0 +#define PTP_dpd_DataType 2 +#define PTP_dpd_GetSet 4 +#define PTP_dpd_FactoryDefaultValue 5 + +/* Device Property Describing Dataset (DevicePropDesc) */ + +typedef struct +{ + uint16_t DevicePropertyCode; + uint16_t DataType; + uint8_t GetSet; + PTP_PropertyValueTypedef FactoryDefaultValue; + PTP_PropertyValueTypedef CurrentValue; + uint8_t FormFlag; + union { + PTP_PropDescEnumFormTypedef Enum; + PTP_PropDescRangeFormTypedef Range; + } FORM; +} +PTP_DevicePropDescTypdef; + +/* DataType Codes */ + +#define PTP_DTC_UNDEF 0x0000 +#define PTP_DTC_INT8 0x0001 +#define PTP_DTC_UINT8 0x0002 +#define PTP_DTC_INT16 0x0003 +#define PTP_DTC_UINT16 0x0004 +#define PTP_DTC_INT32 0x0005 +#define PTP_DTC_UINT32 0x0006 +#define PTP_DTC_INT64 0x0007 +#define PTP_DTC_UINT64 0x0008 +#define PTP_DTC_INT128 0x0009 +#define PTP_DTC_UINT128 0x000A + +#define PTP_DTC_ARRAY_MASK 0x4000 + +#define PTP_DTC_AINT8 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT8) +#define PTP_DTC_AUINT8 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT8) +#define PTP_DTC_AINT16 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT16) +#define PTP_DTC_AUINT16 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT16) +#define PTP_DTC_AINT32 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT32) +#define PTP_DTC_AUINT32 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT32) +#define PTP_DTC_AINT64 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT64) +#define PTP_DTC_AUINT64 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT64) +#define PTP_DTC_AINT128 (PTP_DTC_ARRAY_MASK | PTP_DTC_INT128) +#define PTP_DTC_AUINT128 (PTP_DTC_ARRAY_MASK | PTP_DTC_UINT128) + +#define PTP_DTC_STR 0xFFFF + +/* PTP Event Codes */ + +#define PTP_EC_Undefined 0x4000 +#define PTP_EC_CancelTransaction 0x4001 +#define PTP_EC_ObjectAdded 0x4002 +#define PTP_EC_ObjectRemoved 0x4003 +#define PTP_EC_StoreAdded 0x4004 +#define PTP_EC_StoreRemoved 0x4005 +#define PTP_EC_DevicePropChanged 0x4006 +#define PTP_EC_ObjectInfoChanged 0x4007 +#define PTP_EC_DeviceInfoChanged 0x4008 +#define PTP_EC_RequestObjectTransfer 0x4009 +#define PTP_EC_StoreFull 0x400A +#define PTP_EC_DeviceReset 0x400B +#define PTP_EC_StorageInfoChanged 0x400C +#define PTP_EC_CaptureComplete 0x400D +#define PTP_EC_UnreportedStatus 0x400E + + +/** + * @} + */ + +/** @defgroup USBH_MTP_PTP_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_MTP_PTP_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_MTP_PTP_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_PTP_Init(USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_PTP_Process (USBH_HandleTypeDef *phost); + +USBH_StatusTypeDef USBH_PTP_SendRequest (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req); +USBH_StatusTypeDef USBH_PTP_GetResponse (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req); + +USBH_StatusTypeDef USBH_PTP_OpenSession (USBH_HandleTypeDef *phost, uint32_t session); +USBH_StatusTypeDef USBH_PTP_GetDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info); +USBH_StatusTypeDef USBH_PTP_GetStorageIds (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *storage_ids); + +USBH_StatusTypeDef USBH_PTP_GetStorageInfo (USBH_HandleTypeDef *phost, + uint32_t storage_id, + PTP_StorageInfoTypedef *storage_info); + +USBH_StatusTypeDef USBH_PTP_GetNumObjects (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + uint32_t* numobs); + +USBH_StatusTypeDef USBH_PTP_GetObjectHandles (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + PTP_ObjectHandlesTypedef* objecthandles); + +USBH_StatusTypeDef USBH_PTP_GetObjectInfo (USBH_HandleTypeDef *phost, + uint32_t handle, + PTP_ObjectInfoTypedef* objectinfo); + +USBH_StatusTypeDef USBH_PTP_DeleteObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t objectformatcode); + +USBH_StatusTypeDef USBH_PTP_GetObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object); + +USBH_StatusTypeDef USBH_PTP_GetPartialObject(USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t offset, + uint32_t maxbytes, uint8_t *object, + uint32_t *len); + +USBH_StatusTypeDef USBH_PTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost, + uint16_t ofc, + uint32_t *propnum, + uint16_t *props); + +USBH_StatusTypeDef USBH_PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, + uint16_t opc, + uint16_t ofc, + PTP_ObjectPropDescTypeDef *opd); + +USBH_StatusTypeDef USBH_PTP_GetObjectPropList (USBH_HandleTypeDef *phost, + uint32_t handle, + MTP_PropertiesTypedef *pprops, + uint32_t *nrofprops); + +USBH_StatusTypeDef USBH_PTP_SendObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object, + uint32_t size); + +USBH_StatusTypeDef USBH_PTP_GetDevicePropDesc (USBH_HandleTypeDef *phost, + uint16_t propcode, + PTP_DevicePropDescTypdef* devicepropertydesc); + +/** + * @} + */ + +#endif //__USBH_MTP_PTP_H__ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c new file mode 100755 index 0000000..d93aa42 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp.c @@ -0,0 +1,1065 @@ +/** + ****************************************************************************** + * @file usbh_mtp.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the MTP Layer Handlers for USB Host MTP class. + * + * @verbatim + * + * =================================================================== + * MTP Class Description + * =================================================================== + * This module manages the MSC class V1.11 following the "Device Class Definition + * for Human Interface Devices (MTP) Version 1.11 Jun 27, 2001". + * This driver implements the following aspects of the specification: + * - The Boot Interface Subclass + * - The Mouse and Keyboard protocols + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_mtp.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_MTP_CLASS +* @{ +*/ + +/** @defgroup USBH_MTP_CORE +* @brief This file includes MTP Layer Handlers for USB Host MTP class. +* @{ +*/ + +/** @defgroup USBH_MTP_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_CORE_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_CORE_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_CORE_Private_FunctionPrototypes +* @{ +*/ + +static USBH_StatusTypeDef USBH_MTP_InterfaceInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MTP_InterfaceDeInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MTP_Process(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MTP_ClassRequest (USBH_HandleTypeDef *phost); + +static uint8_t MTP_FindCtlEndpoint(USBH_HandleTypeDef *phost); + +static uint8_t MTP_FindDataOutEndpoint(USBH_HandleTypeDef *phost); + +static uint8_t MTP_FindDataInEndpoint(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MTP_SOFProcess (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_MTP_Events (USBH_HandleTypeDef *phost); + +static void MTP_DecodeEvent (USBH_HandleTypeDef *phost) ; + +USBH_ClassTypeDef MTP_Class = +{ + "MTP", + USB_MTP_CLASS, + USBH_MTP_InterfaceInit, + USBH_MTP_InterfaceDeInit, + USBH_MTP_ClassRequest, + USBH_MTP_Process, + USBH_MTP_SOFProcess, + NULL, +}; +/** +* @} +*/ + + +/** @defgroup USBH_MTP_CORE_Private_Functions +* @{ +*/ + +/** + * @brief USBH_MTP_InterfaceInit + * The function init the MTP class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MTP_InterfaceInit (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_OK ; + uint8_t interface, endpoint; + + MTP_HandleTypeDef *MTP_Handle; + + interface = USBH_FindInterface(phost, + USB_MTP_CLASS, + 1, + 1); + + if(interface == 0xFF) /* No Valid Interface */ + { + status = USBH_FAIL; + USBH_DbgLog ("Cannot Find the interface for Still Image Class."); + } + else + { + USBH_SelectInterface (phost, interface); + + endpoint = MTP_FindCtlEndpoint(phost); + + phost->pActiveClass->pData = (MTP_HandleTypeDef *)USBH_malloc (sizeof(MTP_HandleTypeDef)); + MTP_Handle = phost->pActiveClass->pData; + + if( MTP_Handle == NULL) + { + status = USBH_FAIL; + USBH_DbgLog ("Cannot allocate RAM for MTP Handle"); + } + + /*Collect the control endpoint address and length*/ + MTP_Handle->NotificationEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress; + MTP_Handle->NotificationEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize; + MTP_Handle->NotificationPipe = USBH_AllocPipe(phost, MTP_Handle->NotificationEp); + MTP_Handle->events.poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bInterval; + + /* Open pipe for Notification endpoint */ + USBH_OpenPipe (phost, + MTP_Handle->NotificationPipe, + MTP_Handle->NotificationEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_INTR, + MTP_Handle->NotificationEpSize); + + USBH_LL_SetToggle (phost, MTP_Handle->NotificationPipe, 0); + + + endpoint = MTP_FindDataInEndpoint(phost); + + /*Collect the control endpoint address and length*/ + MTP_Handle->DataInEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress; + MTP_Handle->DataInEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize; + MTP_Handle->DataInPipe = USBH_AllocPipe(phost, MTP_Handle->DataInEp); + + /* Open pipe for DATA IN endpoint */ + USBH_OpenPipe (phost, + MTP_Handle->DataInPipe, + MTP_Handle->DataInEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + MTP_Handle->DataInEpSize); + + USBH_LL_SetToggle (phost, MTP_Handle->DataInPipe, 0); + + endpoint = MTP_FindDataOutEndpoint(phost); + + /*Collect the DATA OUT endpoint address and length*/ + MTP_Handle->DataOutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress; + MTP_Handle->DataOutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize; + MTP_Handle->DataOutPipe = USBH_AllocPipe(phost, MTP_Handle->DataOutEp); + + /* Open pipe for DATA OUT endpoint */ + USBH_OpenPipe (phost, + MTP_Handle->DataOutPipe, + MTP_Handle->DataOutEp, + phost->device.address, + phost->device.speed, + USB_EP_TYPE_BULK, + MTP_Handle->DataOutEpSize); + + USBH_LL_SetToggle (phost, MTP_Handle->DataOutPipe, 0); + + + MTP_Handle->state = MTP_OPENSESSION; + MTP_Handle->is_ready = 0; + MTP_Handle->events.state = MTP_EVENTS_INIT; + return USBH_PTP_Init(phost); + + } + return status; +} + +/** + * @brief Find MTP Ctl interface + * @param phost: Host handle + * @retval USBH Status + */ +static uint8_t MTP_FindCtlEndpoint(USBH_HandleTypeDef *phost) +{ + uint8_t interface, endpoint; + + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS) + { + for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ ) + { + if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80)&& + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&& + ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_INTERRUPT) == USBH_EP_INTERRUPT)) + { + return endpoint; + } + } + } + } + + return 0xFF; /* Invalid Endpoint */ +} + + +/** + * @brief Find MTP DATA OUT interface + * @param phost: Host handle + * @retval USBH Status + */ +static uint8_t MTP_FindDataOutEndpoint(USBH_HandleTypeDef *phost) +{ + uint8_t interface, endpoint; + + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS) + { + for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ ) + { + + if(((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80) == 0)&& + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&& + ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_BULK) == USBH_EP_BULK)) + { + return endpoint; + } + } + } + } + + return 0xFF; /* Invalid Endpoint */ +} + +/** + * @brief Find MTP DATA IN interface + * @param phost: Host handle + * @retval USBH Status + */ +static uint8_t MTP_FindDataInEndpoint(USBH_HandleTypeDef *phost) +{ + uint8_t interface, endpoint; + + for (interface = 0; interface < USBH_MAX_NUM_INTERFACES ; interface ++ ) + { + if(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == USB_MTP_CLASS) + { + for (endpoint = 0; endpoint < USBH_MAX_NUM_ENDPOINTS ; endpoint ++ ) + { + + if((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bEndpointAddress & 0x80)&& + (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].wMaxPacketSize > 0)&& + ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[endpoint].bmAttributes & USBH_EP_BULK) == USBH_EP_BULK)) + { + return endpoint; + } + } + } + } + + return 0xFF; /* Invalid Endpoint */ +} + + +/** + * @brief USBH_MTP_InterfaceDeInit + * The function DeInit the Pipes used for the MTP class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_InterfaceDeInit (USBH_HandleTypeDef *phost) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + if (MTP_Handle->DataOutPipe) + { + USBH_ClosePipe(phost, MTP_Handle->DataOutPipe); + USBH_FreePipe (phost, MTP_Handle->DataOutPipe); + MTP_Handle->DataOutPipe = 0; /* Reset the Channel as Free */ + } + + if (MTP_Handle->DataInPipe) + { + USBH_ClosePipe(phost, MTP_Handle->DataInPipe); + USBH_FreePipe (phost, MTP_Handle->DataInPipe); + MTP_Handle->DataInPipe = 0; /* Reset the Channel as Free */ + } + + if (MTP_Handle->NotificationPipe) + { + USBH_ClosePipe(phost, MTP_Handle->NotificationPipe); + USBH_FreePipe (phost, MTP_Handle->NotificationPipe); + MTP_Handle->NotificationPipe = 0; /* Reset the Channel as Free */ + } + + if(phost->pActiveClass->pData) + { + USBH_free (phost->pActiveClass->pData); + phost->pActiveClass->pData = 0; + } + return USBH_OK; +} + +/** + * @brief USBH_MTP_ClassRequest + * The function is responsible for handling Standard requests + * for MTP class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MTP_ClassRequest (USBH_HandleTypeDef *phost) +{ + return USBH_OK;; +} + + +/** + * @brief USBH_MTP_Process + * The function is for managing state machine for MTP data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MTP_Process (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t idx = 0; + + switch(MTP_Handle->state) + { + case MTP_OPENSESSION: + + status = USBH_PTP_OpenSession (phost, 1); /* Session '0' is not valid */ + + if(status == USBH_OK) + { + USBH_UsrLog("MTP Session #0 Opened"); + MTP_Handle->state = MTP_GETDEVICEINFO; + } + break; + + case MTP_GETDEVICEINFO: + status = USBH_PTP_GetDeviceInfo (phost, &(MTP_Handle->info.devinfo)); + + if(status == USBH_OK) + { + USBH_DbgLog(">>>>> MTP Device Information"); + USBH_DbgLog("Standard version : %x", MTP_Handle->info.devinfo.StandardVersion); + USBH_DbgLog("Vendor ExtID : %s", (MTP_Handle->info.devinfo.VendorExtensionID == 6)?"MTP": "NOT SUPPORTED"); + USBH_DbgLog("Functional mode : %s", (MTP_Handle->info.devinfo.FunctionalMode == 0) ? "Standard" : "Vendor"); + USBH_DbgLog("Number of Supported Operation(s) : %d", MTP_Handle->info.devinfo.OperationsSupported_len); + USBH_DbgLog("Number of Supported Events(s) : %d", MTP_Handle->info.devinfo.EventsSupported_len); + USBH_DbgLog("Number of Supported Proprieties : %d", MTP_Handle->info.devinfo.DevicePropertiesSupported_len); + USBH_DbgLog("Manufacturer : %s", MTP_Handle->info.devinfo.Manufacturer); + USBH_DbgLog("Model : %s", MTP_Handle->info.devinfo.Model); + USBH_DbgLog("Device version : %s", MTP_Handle->info.devinfo.DeviceVersion); + USBH_DbgLog("Serial number : %s", MTP_Handle->info.devinfo.SerialNumber); + + MTP_Handle->state = MTP_GETSTORAGEIDS; + } + break; + + case MTP_GETSTORAGEIDS: + status = USBH_PTP_GetStorageIds (phost, &(MTP_Handle->info.storids)); + + if(status == USBH_OK) + { + USBH_DbgLog("Number of storage ID items : %d", MTP_Handle->info.storids.n); + for (idx = 0; idx < MTP_Handle->info.storids.n; idx ++) + { + USBH_DbgLog("storage#%d ID : %x", idx, MTP_Handle->info.storids.Storage[idx]); + } + + MTP_Handle->current_storage_unit = 0; + MTP_Handle->state = MTP_GETSTORAGEINFO; + } + break; + + case MTP_GETSTORAGEINFO: + status = USBH_PTP_GetStorageInfo (phost, + MTP_Handle->info.storids.Storage[MTP_Handle->current_storage_unit], + &((MTP_Handle->info.storinfo)[MTP_Handle->current_storage_unit])); + + if(status == USBH_OK) + { + USBH_UsrLog("Volume#%lu: %s [%s]", MTP_Handle->current_storage_unit, + MTP_Handle->info.storinfo[MTP_Handle->current_storage_unit].StorageDescription, + MTP_Handle->info.storinfo[MTP_Handle->current_storage_unit].VolumeLabel); + if(++MTP_Handle->current_storage_unit >= MTP_Handle->info.storids.n) + { + MTP_Handle->state = MTP_IDLE; + MTP_Handle->is_ready = 1; + MTP_Handle->current_storage_unit = 0; + MTP_Handle->params.CurrentStorageId = MTP_Handle->info.storids.Storage[0]; + + USBH_UsrLog( "MTP Class initialized."); + USBH_UsrLog("%s is default storage unit", MTP_Handle->info.storinfo[0].StorageDescription); + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + } + } + break; + + case MTP_IDLE: + USBH_MTP_Events(phost); + default: + status = USBH_OK; + break; + } + return status; +} + +/** + * @brief USBH_MTP_SOFProcess + * The function is for managing SOF callback + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MTP_SOFProcess (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_OK; + + return status; +} + +/** + * @brief USBH_MTP_IsReady + * Select the storage Unit to be used + * @param phost: Host handle + * @retval USBH Status + */ +uint8_t USBH_MTP_IsReady (USBH_HandleTypeDef *phost) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + return (MTP_Handle->is_ready); +} + +/** + * @brief USBH_MTP_GetNumStorage + * Select the storage Unit to be used + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetNumStorage (USBH_HandleTypeDef *phost, uint8_t *storage_num) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + if(MTP_Handle->is_ready > 0) + { + *storage_num = MTP_Handle->info.storids.n; + status = USBH_OK; + } + + return status; +} + +/** + * @brief USBH_MTP_SelectStorage + * Select the storage Unit to be used + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_SelectStorage (USBH_HandleTypeDef *phost, uint8_t storage_idx) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready)) + { + MTP_Handle->params.CurrentStorageId = MTP_Handle->info.storids.Storage[storage_idx]; + status = USBH_OK; + } + + return status; +} + +/** + * @brief USBH_MTP_GetStorageInfo + * Get the storage Unit info + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint8_t storage_idx, MTP_StorageInfoTypedef *info) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready)) + { + *info = MTP_Handle->info.storinfo[storage_idx]; + status = USBH_OK; + } + return status; +} + +/** + * @brief USBH_MTP_GetStorageInfo + * Get the storage Unit info + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetNumObjects (USBH_HandleTypeDef *phost, + uint32_t storage_idx, + uint32_t objectformatcode, + uint32_t associationOH, + uint32_t* numobs) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready)) + { + while ((status = USBH_PTP_GetNumObjects (phost, + MTP_Handle->info.storids.Storage[storage_idx], + objectformatcode, + associationOH, + numobs)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + + +/** + * @brief USBH_MTP_GetStorageInfo + * Get the storage Unit info + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObjectHandles (USBH_HandleTypeDef *phost, + uint32_t storage_idx, + uint32_t objectformatcode, + uint32_t associationOH, + PTP_ObjectHandlesTypedef* objecthandles) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if((storage_idx < MTP_Handle->info.storids.n) && (MTP_Handle->is_ready)) + { + while ((status = USBH_PTP_GetObjectHandles (phost, + MTP_Handle->info.storids.Storage[storage_idx], + objectformatcode, + associationOH, + objecthandles)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectInfo + * Gets objert info + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObjectInfo (USBH_HandleTypeDef *phost, + uint32_t handle, + PTP_ObjectInfoTypedef* objectinfo) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetObjectInfo (phost, handle, objectinfo)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} +/** + * @brief USBH_MTP_DeleteObject + * Delete an object. + * @param phost: Host handle + * @param handle : Object Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_DeleteObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t objectformatcode) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_DeleteObject (phost, handle, objectformatcode)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_GetObject + * Gets object + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetObject (phost, handle, object)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_GetPartialObject + * Gets object + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetPartialObject(USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t offset, + uint32_t maxbytes, + uint8_t *object, + uint32_t *len) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetPartialObject(phost, + handle, + offset, + maxbytes, + object, + len)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_GetObjectPropsSupported + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost, + uint16_t ofc, + uint32_t *propnum, + uint16_t *props) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetObjectPropsSupported (phost, + ofc, + propnum, + props)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_GetObjectPropDesc + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, + uint16_t opc, + uint16_t ofc, + PTP_ObjectPropDescTypeDef *opd) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetObjectPropDesc (phost, + opc, + ofc, + opd)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_GetObjectPropList + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetObjectPropList (USBH_HandleTypeDef *phost, + uint32_t handle, + MTP_PropertiesTypedef *pprops, + uint32_t *nrofprops) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetObjectPropList (phost, + handle, + pprops, + nrofprops)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + +/** + * @brief USBH_MTP_SendObject + * Send an object + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_SendObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object, + uint32_t size) +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_SendObject (phost, handle, object, size)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} + + /** + * @brief Handle HID Control process + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MTP_Events (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY ; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + + switch(MTP_Handle->events.state) + { + case MTP_EVENTS_INIT: + if((phost->Timer & 1) == 0) + { + MTP_Handle->events.timer = phost->Timer; + USBH_InterruptReceiveData(phost, + (uint8_t *)&(MTP_Handle->events.container), + MTP_Handle->NotificationEpSize, + MTP_Handle->NotificationPipe); + + + MTP_Handle->events.state = MTP_EVENTS_GETDATA ; + } + break; + case MTP_EVENTS_GETDATA: + if(USBH_LL_GetURBState(phost , MTP_Handle->NotificationPipe) == USBH_URB_DONE) + { + MTP_DecodeEvent(phost); + } + + if(( phost->Timer - MTP_Handle->events.timer) >= MTP_Handle->events.poll) + { + MTP_Handle->events.timer = phost->Timer; + + USBH_InterruptReceiveData(phost, + (uint8_t *)&(MTP_Handle->events.container), + MTP_Handle->NotificationEpSize, + MTP_Handle->NotificationPipe); + + } + break; + + default: + break; + } + + return status; +} + +/** + * @brief MTP_DecodeEvent + * Decode device event sent by responder + * @param phost: Host handle + * @retval None + */ +static void MTP_DecodeEvent (USBH_HandleTypeDef *phost) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + uint16_t code; + uint32_t param1; + + /* Process the event */ + code = MTP_Handle->events.container.code; + param1 = MTP_Handle->events.container.param1; + + switch(code) + { + case PTP_EC_Undefined: + USBH_DbgLog("EVT: PTP_EC_Undefined in session %u", MTP_Handle->ptp.session_id); + break; + case PTP_EC_CancelTransaction: + USBH_DbgLog("EVT: PTP_EC_CancelTransaction in session %u", MTP_Handle->ptp.session_id); + break; + case PTP_EC_ObjectAdded: + USBH_DbgLog("EVT: PTP_EC_ObjectAdded in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_ObjectRemoved: + USBH_DbgLog("EVT: PTP_EC_ObjectRemoved in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_StoreAdded: + USBH_DbgLog("EVT: PTP_EC_StoreAdded in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_StoreRemoved: + USBH_DbgLog("EVT: PTP_EC_StoreRemoved in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_DevicePropChanged: + USBH_DbgLog("EVT: PTP_EC_DevicePropChanged in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_ObjectInfoChanged: + USBH_DbgLog("EVT: PTP_EC_ObjectInfoChanged in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_DeviceInfoChanged: + USBH_DbgLog("EVT: PTP_EC_DeviceInfoChanged in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_RequestObjectTransfer: + USBH_DbgLog("EVT: PTP_EC_RequestObjectTransfer in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_StoreFull: + USBH_DbgLog("EVT: PTP_EC_StoreFull in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_DeviceReset: + USBH_DbgLog("EVT: PTP_EC_DeviceReset in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_StorageInfoChanged : + USBH_DbgLog( "EVT: PTP_EC_StorageInfoChanged in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_CaptureComplete : + USBH_DbgLog( "EVT: PTP_EC_CaptureComplete in session %u", MTP_Handle->ptp.session_id); + break; + + case PTP_EC_UnreportedStatus : + USBH_DbgLog( "EVT: PTP_EC_UnreportedStatus in session %u", MTP_Handle->ptp.session_id); + break; + + default : + USBH_DbgLog( "Received unknown event in session %u", MTP_Handle->ptp.session_id); + break; + } + + USBH_MTP_EventsCallback(phost, code, param1); +} + +/** + * @brief USBH_MTP_GetDevicePropDesc + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_MTP_GetDevicePropDesc (USBH_HandleTypeDef *phost, + uint16_t propcode, + PTP_DevicePropDescTypdef* devicepropertydesc) + +{ + USBH_StatusTypeDef status = USBH_FAIL; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint32_t timeout = phost->Timer + 5000; + + if(MTP_Handle->is_ready) + { + while ((status = USBH_PTP_GetDevicePropDesc (phost, propcode, devicepropertydesc)) == USBH_BUSY) + { + if((phost->Timer > timeout) || (phost->device.is_connected == 0)) + { + return USBH_FAIL; + } + } + } + return status; +} +/** + * @brief The function informs that host has rceived an event + * @param pdev: Selected device + * @retval None + */ +__weak void USBH_MTP_EventsCallback(USBH_HandleTypeDef *phost, uint32_t event, uint32_t param) +{ + +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c new file mode 100755 index 0000000..dd5a293 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/MTP/Src/usbh_mtp_ptp.c @@ -0,0 +1,1769 @@ +/** + ****************************************************************************** + * @file usbh_mtp_ptp.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file includes the PTP operations layer + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_mtp_ptp.h" +#include "usbh_mtp.h" +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_MTP_CLASS +* @{ +*/ + +/** @defgroup USBH_MTP_PTP +* @brief This file includes the mass storage related functions +* @{ +*/ + + +/** @defgroup USBH_MTP_PTP_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_MTP_PTP_Private_Defines +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_MTP_PTP_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_PTP_Private_Variables +* @{ +*/ + +/** +* @} +*/ + + +/** @defgroup USBH_MTP_PTP_Private_FunctionPrototypes +* @{ +*/ +static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info); +static void PTP_GetStorageIDs (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids); +static void PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info); +static void PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen); +static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info); +static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost, + uint32_t *offset, + uint32_t total, + PTP_PropertyValueTypedef* value, + uint16_t datatype); + +static uint32_t PTP_GetObjectPropList (USBH_HandleTypeDef *phost, + MTP_PropertiesTypedef *props, + uint32_t len); + + +static void PTP_BufferFullCallback(USBH_HandleTypeDef *phost); +static void PTP_GetString(uint8_t *str, uint8_t* data, uint16_t *len); +static uint32_t PTP_GetArray16 (uint16_t *array, uint8_t *data, uint32_t offset); +static uint32_t PTP_GetArray32 (uint32_t *array, uint8_t *data, uint32_t offset); +/** +* @} +*/ + + +/** @defgroup USBH_MTP_PTP_Exported_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_MTP_PTP_Private_Functions +* @{ +*/ +/** + * @brief USBH_PTP_Init + * The function Initializes the BOT protocol. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_Init(USBH_HandleTypeDef *phost) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + /* Set state to idle to be ready for operations */ + MTP_Handle->ptp.state = PTP_IDLE; + MTP_Handle->ptp.req_state = PTP_REQ_SEND; + + return USBH_OK; +} + +/** + * @brief USBH_PTP_Process + * The function handle the BOT protocol. + * @param phost: Host handle + * @param lun: Logical Unit Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_Process (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status = USBH_BUSY; + USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + uint32_t len; + + switch (MTP_Handle->ptp.state) + { + case PTP_IDLE: + /*Do Nothing */ + break; + + case PTP_OP_REQUEST_STATE: + USBH_BulkSendData (phost, + (uint8_t*)&(MTP_Handle->ptp.op_container), + MTP_Handle->ptp.op_container.length, + MTP_Handle->DataOutPipe, + 1); + MTP_Handle->ptp.state = PTP_OP_REQUEST_WAIT_STATE; + break; + + case PTP_OP_REQUEST_WAIT_STATE: + URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe); + + if(URB_Status == USBH_URB_DONE) + { + if(MTP_Handle->ptp.flags == PTP_DP_NODATA) + { + MTP_Handle->ptp.state = PTP_RESPONSE_STATE; + } + else if(MTP_Handle->ptp.flags == PTP_DP_SENDDATA) + { + MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE; + } + else if(MTP_Handle->ptp.flags == PTP_DP_GETDATA) + { + MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_STATE; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_NOTREADY) + { + /* Re-send Request */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_STALL) + { + MTP_Handle->ptp.state = PTP_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case PTP_DATA_OUT_PHASE_STATE: + + USBH_BulkSendData (phost, + MTP_Handle->ptp.data_ptr, + MTP_Handle->DataOutEpSize , + MTP_Handle->DataOutPipe, + 1); + + + MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_WAIT_STATE; + break; + + case PTP_DATA_OUT_PHASE_WAIT_STATE: + URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataOutPipe); + + if(URB_Status == USBH_URB_DONE) + { + /* Adjudt Data pointer and data length */ + if(MTP_Handle->ptp.data_length > MTP_Handle->DataOutEpSize) + { + MTP_Handle->ptp.data_ptr += MTP_Handle->DataOutEpSize; + MTP_Handle->ptp.data_length -= MTP_Handle->DataOutEpSize; + MTP_Handle->ptp.data_packet += MTP_Handle->DataOutEpSize; + + if(MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ) + { + PTP_BufferFullCallback (phost); + MTP_Handle->ptp.data_packet = 0; + MTP_Handle->ptp.iteration++; + } + + } + else + { + MTP_Handle->ptp.data_length = 0; + } + + /* More Data To be Sent */ + if(MTP_Handle->ptp.data_length > 0) + { + USBH_BulkSendData (phost, + MTP_Handle->ptp.data_ptr, + MTP_Handle->DataOutEpSize , + MTP_Handle->DataOutPipe, + 1); + } + else + { + /* If value was 0, and successful transfer, then change the state */ + MTP_Handle->ptp.state = PTP_RESPONSE_STATE; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + + else if(URB_Status == USBH_URB_NOTREADY) + { + /* Re-send same data */ + MTP_Handle->ptp.state = PTP_DATA_OUT_PHASE_STATE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + + else if(URB_Status == USBH_URB_STALL) + { + MTP_Handle->ptp.state = PTP_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case PTP_DATA_IN_PHASE_STATE: + /* Send first packet */ + USBH_BulkReceiveData (phost, + MTP_Handle->ptp.data_ptr, + MTP_Handle->DataInEpSize, + MTP_Handle->DataInPipe); + + MTP_Handle->ptp.state = PTP_DATA_IN_PHASE_WAIT_STATE; + break; + + case PTP_DATA_IN_PHASE_WAIT_STATE: + URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe); + + if(URB_Status == USBH_URB_DONE) + { + len = USBH_LL_GetLastXferSize (phost, MTP_Handle->DataInPipe); + + if( MTP_Handle->ptp.data_packet_counter++ == 0) + { + /* This is the first packet; so retrieve exact data length from payload */ + MTP_Handle->ptp.data_length = *(uint32_t*)(MTP_Handle->ptp.data_ptr); + MTP_Handle->ptp.iteration = 0; + } + + if((len >= MTP_Handle->DataInEpSize) && (MTP_Handle->ptp.data_length > 0)) + { + MTP_Handle->ptp.data_ptr += len; + MTP_Handle->ptp.data_length -= len; + MTP_Handle->ptp.data_packet += len; + + if(MTP_Handle->ptp.data_packet >= PTP_USB_BULK_PAYLOAD_LEN_READ) + { + PTP_BufferFullCallback (phost); + MTP_Handle->ptp.data_packet = 0; + MTP_Handle->ptp.iteration++; + } + + /* Continue receiving data*/ + USBH_BulkReceiveData (phost, + MTP_Handle->ptp.data_ptr, + MTP_Handle->DataInEpSize, + MTP_Handle->DataInPipe); + } + else + { + MTP_Handle->ptp.data_length -= len; + MTP_Handle->ptp.state = PTP_RESPONSE_STATE; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + } + else if(URB_Status == USBH_URB_STALL) + { + MTP_Handle->ptp.state = PTP_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case PTP_RESPONSE_STATE: + + USBH_BulkReceiveData (phost, + (uint8_t*)&(MTP_Handle->ptp.resp_container), + PTP_USB_BULK_REQ_RESP_MAX_LEN , + MTP_Handle->DataInPipe); + + MTP_Handle->ptp.state = PTP_RESPONSE_WAIT_STATE; + break; + + case PTP_RESPONSE_WAIT_STATE: + URB_Status = USBH_LL_GetURBState(phost, MTP_Handle->DataInPipe); + + if(URB_Status == USBH_URB_DONE) + { + USBH_PTP_GetResponse (phost, &ptp_container); + + if(ptp_container.Code == PTP_RC_OK) + { + status = USBH_OK; + } + else + { + status = USBH_FAIL; + } + MTP_Handle->ptp.req_state = PTP_REQ_SEND; + } + else if(URB_Status == USBH_URB_STALL) + { + MTP_Handle->ptp.state = PTP_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); +#endif + } + break; + + case PTP_ERROR: + MTP_Handle->ptp.req_state = PTP_REQ_SEND; + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_OpenSession + * Open a new session + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_SendRequest (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *req) +{ + USBH_StatusTypeDef status = USBH_OK; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + /* Clear PTP Data container*/ + USBH_memset(&(MTP_Handle->ptp.op_container), 0, sizeof(PTP_OpContainerTypedef)); + + /* build appropriate USB container */ + MTP_Handle->ptp.op_container.length = PTP_USB_BULK_REQ_LEN- (sizeof(uint32_t)*(5-req->Nparam)); + MTP_Handle->ptp.op_container.type = PTP_USB_CONTAINER_COMMAND; + MTP_Handle->ptp.op_container.code = req->Code; + MTP_Handle->ptp.op_container.trans_id = req->Transaction_ID; + MTP_Handle->ptp.op_container.param1 = req->Param1; + MTP_Handle->ptp.op_container.param2 = req->Param2; + MTP_Handle->ptp.op_container.param3 = req->Param3; + MTP_Handle->ptp.op_container.param4 = req->Param4; + MTP_Handle->ptp.op_container.param5 = req->Param5; + + return status; +} + +/** + * @brief USBH_PTP_OpenSession + * Open a new session + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetResponse (USBH_HandleTypeDef *phost, PTP_ContainerTypedef *resp) +{ + USBH_StatusTypeDef status = USBH_OK; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + /* build an appropriate PTPContainer */ + resp->Code = MTP_Handle->ptp.resp_container.code; + resp->SessionID = MTP_Handle->ptp.session_id; + resp->Transaction_ID = MTP_Handle->ptp.resp_container.trans_id; + resp->Param1 = MTP_Handle->ptp.resp_container.param1; + resp->Param2 = MTP_Handle->ptp.resp_container.param2; + resp->Param3 = MTP_Handle->ptp.resp_container.param3; + resp->Param4 = MTP_Handle->ptp.resp_container.param4; + resp->Param5 = MTP_Handle->ptp.resp_container.param5; + + return status; +} + +/** + * @brief The function informs user that data buffer is full + * @param phost: host handle + * @retval None + */ +void PTP_BufferFullCallback(USBH_HandleTypeDef *phost) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + + switch (MTP_Handle->ptp.data_container.code) + { + case PTP_OC_GetDeviceInfo: + PTP_DecodeDeviceInfo (phost, &(MTP_Handle->info.devinfo)); + break; + + case PTP_OC_GetPartialObject: + case PTP_OC_GetObject: + + /* first packet is in the PTP data payload buffer */ + if(MTP_Handle->ptp.iteration == 0) + { + /* copy it to object */ + USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, PTP_USB_BULK_PAYLOAD_LEN_READ); + + /* next packet should be directly copied to object */ + MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ); + } + break; + + case PTP_OC_SendObject: + /* first packet is in the PTP data payload buffer */ + if(MTP_Handle->ptp.iteration == 0) + { + /* next packet should be directly copied to object */ + MTP_Handle->ptp.data_ptr = (MTP_Handle->ptp.object_ptr + PTP_USB_BULK_PAYLOAD_LEN_READ); + } + break; + + default: + break; + + + } +} + +/** + * @brief PTP_GetDeviceInfo + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval None + */ +static void PTP_DecodeDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + uint32_t totallen; + uint16_t len; + + /* Max device info is PTP_USB_BULK_HS_MAX_PACKET_LEN_READ */ + USBH_DbgLog (" MTP device info size exceeds internal buffer size.\ + only available data are decoded."); + + if(MTP_Handle->ptp.iteration == 0) + { + dev_info->StandardVersion = LE16(&data[PTP_di_StandardVersion]); + dev_info->VendorExtensionID = LE32(&data[PTP_di_VendorExtensionID]); + dev_info->VendorExtensionVersion = LE16(&data[PTP_di_VendorExtensionVersion]); + PTP_GetString(dev_info->VendorExtensionDesc, &data[PTP_di_VendorExtensionDesc], &len); + + totallen=len*2+1; + dev_info->FunctionalMode = LE16(&data[PTP_di_FunctionalMode+totallen]); + dev_info->OperationsSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->OperationsSupported, + data, + PTP_di_OperationsSupported+totallen); + + totallen=totallen+dev_info->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + dev_info->EventsSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->EventsSupported, + data, + PTP_di_OperationsSupported+totallen); + + totallen=totallen+dev_info->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + dev_info->DevicePropertiesSupported_len = PTP_GetArray16 ((uint16_t *)&dev_info->DevicePropertiesSupported, + data, + PTP_di_OperationsSupported+totallen); + + totallen=totallen+dev_info->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + + dev_info->CaptureFormats_len = PTP_GetArray16 ((uint16_t *)&dev_info->CaptureFormats, + data, + PTP_di_OperationsSupported+totallen); + + totallen=totallen+dev_info->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + dev_info->ImageFormats_len = PTP_GetArray16 ((uint16_t *)&dev_info->ImageFormats, + data, + PTP_di_OperationsSupported+totallen); + + totallen=totallen+dev_info->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + PTP_GetString(dev_info->Manufacturer, &data[PTP_di_OperationsSupported+totallen], &len); + + totallen+=len*2+1; + PTP_GetString(dev_info->Model, &data[PTP_di_OperationsSupported+totallen], &len); + + totallen+=len*2+1; + PTP_GetString(dev_info->DeviceVersion, &data[PTP_di_OperationsSupported+totallen], &len); + + totallen+=len*2+1; + PTP_GetString(dev_info->SerialNumber, &data[PTP_di_OperationsSupported+totallen], &len); + } +} + +/** + * @brief PTP_GetStorageIDs + * Gets Storage Ids and fills stor_ids structure. + * @param phost: Host handle + * @param stor_ids: Storage IDsstructure + * @retval None + */ +static void PTP_GetStorageIDs (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *stor_ids) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + + stor_ids->n = PTP_GetArray32 (stor_ids->Storage, data, 0); +} + + +/** + * @brief PTP_GetStorageInfo + * Gets Storage Info and fills stor_info structure. + * @param phost: Host handle + * @param stor_ids: Storage IDsstructure + * @retval None + */ +static void PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *stor_info) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + + uint16_t len; + + stor_info->StorageType=LE16(&data[PTP_si_StorageType]); + stor_info->FilesystemType=LE16(&data[PTP_si_FilesystemType]); + stor_info->AccessCapability=LE16(&data[PTP_si_AccessCapability]); + stor_info->MaxCapability=LE64(&data[PTP_si_MaxCapability]); + stor_info->FreeSpaceInBytes=LE64(&data[PTP_si_FreeSpaceInBytes]); + stor_info->FreeSpaceInImages=LE32(&data[PTP_si_FreeSpaceInImages]); + + PTP_GetString(stor_info->StorageDescription, &data[PTP_si_StorageDescription], &len); + PTP_GetString(stor_info->VolumeLabel, &data[PTP_si_StorageDescription+len*2+1], &len); +} + +/** + * @brief PTP_GetObjectInfo + * Gets objectInfo and fills object_info structure. + * @param phost: Host handle + * @param object_info: object info structure + * @retval None + */ +static void PTP_GetObjectInfo (USBH_HandleTypeDef *phost, PTP_ObjectInfoTypedef *object_info) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + uint16_t filenamelen; + + object_info->StorageID=LE32(&data[PTP_oi_StorageID]); + object_info->ObjectFormat=LE16(&data[PTP_oi_ObjectFormat]); + object_info->ProtectionStatus=LE16(&data[PTP_oi_ProtectionStatus]); + object_info->ObjectCompressedSize=LE32(&data[PTP_oi_ObjectCompressedSize]); + + /* For Samsung Galaxy */ + if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0)) + { + data += 4; + } + object_info->ThumbFormat=LE16(&data[PTP_oi_ThumbFormat]); + object_info->ThumbCompressedSize=LE32(&data[PTP_oi_ThumbCompressedSize]); + object_info->ThumbPixWidth=LE32(&data[PTP_oi_ThumbPixWidth]); + object_info->ThumbPixHeight=LE32(&data[PTP_oi_ThumbPixHeight]); + object_info->ImagePixWidth=LE32(&data[PTP_oi_ImagePixWidth]); + object_info->ImagePixHeight=LE32(&data[PTP_oi_ImagePixHeight]); + object_info->ImageBitDepth=LE32(&data[PTP_oi_ImageBitDepth]); + object_info->ParentObject=LE32(&data[PTP_oi_ParentObject]); + object_info->AssociationType=LE16(&data[PTP_oi_AssociationType]); + object_info->AssociationDesc=LE32(&data[PTP_oi_AssociationDesc]); + object_info->SequenceNumber=LE32(&data[PTP_oi_SequenceNumber]); + PTP_GetString(object_info->Filename, &data[PTP_oi_filenamelen], &filenamelen); +} + + +/** + * @brief PTP_GetObjectPropDesc + * Gets objectInfo and fills object_info structure. + * @param phost: Host handle + * @param opd: object prop descriptor structure + * @retval None + */ +static void PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, PTP_ObjectPropDescTypeDef *opd, uint32_t opdlen) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + uint32_t offset = 0, i; + + opd->ObjectPropertyCode=LE16(&data[PTP_opd_ObjectPropertyCode]); + opd->DataType=LE16(&data[PTP_opd_DataType]); + opd->GetSet=*(uint8_t *)(&data[PTP_opd_GetSet]); + + offset = PTP_opd_FactoryDefaultValue; + PTP_GetDevicePropValue (phost, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType); + + opd->GroupCode=LE32(&data[offset]); + offset+=sizeof(uint32_t); + + opd->FormFlag=*(uint8_t *)(&data[offset]); + offset+=sizeof(uint8_t); + + switch (opd->FormFlag) + { + case PTP_OPFF_Range: + PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType); + PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType); + PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType); + break; + + case PTP_OPFF_Enumeration: + + opd->FORM.Enum.NumberOfValues = LE16(&data[offset]); + offset+=sizeof(uint16_t); + + for (i=0 ; i < opd->FORM.Enum.NumberOfValues ; i++) + { + PTP_GetDevicePropValue(phost, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType); + } + break; + default: + break; + } +} + +/** + * @brief PTP_GetDevicePropValue + * Gets objectInfo and fills object_info structure. + * @param phost: Host handle + * @param opd: object prop descriptor structure + * @retval None + */ +static void PTP_GetDevicePropValue(USBH_HandleTypeDef *phost, + uint32_t *offset, + uint32_t total, + PTP_PropertyValueTypedef* value, + uint16_t datatype) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + uint16_t len; + switch (datatype) + { + case PTP_DTC_INT8: + value->i8 = *(uint8_t *)&(data[*offset]); + *offset += 1; + break; + case PTP_DTC_UINT8: + value->u8 = *(uint8_t *)&(data[*offset]); + *offset += 1; + break; + case PTP_DTC_INT16: + + value->i16 = LE16(&(data[*offset])); + *offset += 2; + break; + case PTP_DTC_UINT16: + value->u16 = LE16(&(data[*offset])); + *offset += 2; + break; + case PTP_DTC_INT32: + value->i32 = LE32(&(data[*offset])); + *offset += 4; + break; + case PTP_DTC_UINT32: + value->u32 = LE32(&(data[*offset])); + *offset += 4; + break; + case PTP_DTC_INT64: + value->i64 = LE64(&(data[*offset])); + *offset += 8; + break; + case PTP_DTC_UINT64: + value->u64 = LE64(&(data[*offset])); + *offset += 8; + break; + + case PTP_DTC_UINT128: + *offset += 16; + break; + case PTP_DTC_INT128: + *offset += 16; + break; + + case PTP_DTC_STR: + + PTP_GetString((uint8_t *)value->str, (uint8_t *)&(data[*offset]), &len); + *offset += len*2+1; + break; + default: + break; + } +} + + +/** + * @brief PTP_GetDevicePropValue + * Gets objectInfo and fills object_info structure. + * @param phost: Host handle + * @param opd: object prop descriptor structure + * @retval None + */ +static uint32_t PTP_GetObjectPropList (USBH_HandleTypeDef *phost, + MTP_PropertiesTypedef *props, + uint32_t len) +{ + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + uint32_t prop_count; + uint32_t offset = 0, i; + + prop_count = LE32(data); + + + if (prop_count == 0) + { + return 0; + } + + data += sizeof(uint32_t); + len -= sizeof(uint32_t); + + for (i = 0; i < prop_count; i++) + { + if (len <= 0) + { + return 0; + } + + props[i].ObjectHandle = LE32(data); + data += sizeof(uint32_t); + len -= sizeof(uint32_t); + + props[i].property = LE16(data); + data += sizeof(uint16_t); + len -= sizeof(uint16_t); + + props[i].datatype = LE16(data); + data += sizeof(uint16_t); + len -= sizeof(uint16_t); + + offset = 0; + + PTP_GetDevicePropValue(phost, &offset, len, &props[i].propval, props[i].datatype); + + data += offset; + len -= offset; + } + + return prop_count; +} + +/** + * @brief PTP_GetString + * Gets SCII String from. + * @param str: ascii string + * @param data: Device info structure + * @retval None + */ +static void PTP_GetString (uint8_t *str, uint8_t* data, uint16_t *len) +{ + uint16_t strlength; + uint16_t idx; + + *len = data[0]; + strlength = 2 * data[0]; + data ++; /* Adjust the offset ignoring the String Len */ + + for (idx = 0; idx < strlength; idx+=2 ) + { + /* Copy Only the string and ignore the UNICODE ID, hence add the src */ + *str = data[idx]; + str++; + } + *str = 0; /* mark end of string */ +} + +/** + * @brief PTP_GetString + * Gets SCII String from. + * @param str: ascii string + * @param data: Device info structure + * @retval None + */ + +static uint32_t PTP_GetArray16 (uint16_t *array, uint8_t *data, uint32_t offset) +{ + uint32_t size, idx = 0; + + size=LE32(&data[offset]); + while (size > idx) + { + array[idx] = LE16(&data[offset+(sizeof(uint16_t)*(idx+2))]); + idx++; + } + return size; +} + +/** + * @brief PTP_GetString + * Gets SCII String from. + * @param str: ascii string + * @param data: Device info structure + * @retval None + */ + +static uint32_t PTP_GetArray32 (uint32_t *array, uint8_t *data, uint32_t offset) +{ + uint32_t size, idx = 0; + + size=LE32(&data[offset]); + while (size > idx) + { + array[idx] = LE32(&data[offset+(sizeof(uint32_t)*(idx+1))]); + idx++; + } + return size; +} + +/******************************************************************************* + + PTP Requests + +*******************************************************************************/ +/** + * @brief USBH_PTP_OpenSession + * Open a new session + * @param phost: Host handle + * @param session: Session ID (MUST BE > 0) + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_OpenSession (USBH_HandleTypeDef *phost, uint32_t session) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Init session params */ + MTP_Handle->ptp.transaction_id = 0x00000000; + MTP_Handle->ptp.session_id = session; + MTP_Handle->ptp.flags = PTP_DP_NODATA; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_OpenSession; + ptp_container.SessionID = session; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = session; + ptp_container.Nparam = 1; + + /* convert request packet inti USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetDevicePropDesc + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetDevicePropDesc (USBH_HandleTypeDef *phost, + uint16_t propcode, + PTP_DevicePropDescTypdef* devicepropertydesc) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + uint8_t *data = MTP_Handle->ptp.data_container.payload.data; + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetDevicePropDesc; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = propcode; + ptp_container.Nparam = 1; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + devicepropertydesc->DevicePropertyCode = LE16(&data[PTP_dpd_DevicePropertyCode]); + devicepropertydesc->DataType = LE16(&data[PTP_dpd_DataType]); + devicepropertydesc->GetSet = *(uint8_t *)(&data[PTP_dpd_GetSet]); + devicepropertydesc->FormFlag = PTP_DPFF_None; + } + break; + + default: + break; + } + return status; +} +/** + * @brief USBH_PTP_GetDeviceInfo + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetDeviceInfo (USBH_HandleTypeDef *phost, PTP_DeviceInfoTypedef *dev_info) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetDeviceInfo; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Nparam = 0; + + /* convert request packet inti USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_DecodeDeviceInfo (phost, dev_info); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetStorageIds + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetStorageIds (USBH_HandleTypeDef *phost, PTP_StorageIDsTypedef *storage_ids) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetStorageIDs; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Nparam = 0; + + /* convert request packet inti USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_GetStorageIDs (phost, storage_ids); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetDeviceInfo + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetStorageInfo (USBH_HandleTypeDef *phost, uint32_t storage_id, PTP_StorageInfoTypedef *storage_info) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetStorageInfo; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = storage_id; + ptp_container.Nparam = 1; + + /* convert request packet inti USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_GetStorageInfo (phost, storage_id, storage_info); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetNumObjects + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetNumObjects (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + uint32_t* numobs) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_NODATA; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetNumObjects; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = storage_id; + ptp_container.Param2 = objectformatcode; + ptp_container.Param3 = associationOH; + ptp_container.Nparam = 3; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + *numobs = MTP_Handle->ptp.resp_container.param1; + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectHandles + * Gets device info dataset and fills deviceinfo structure. + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObjectHandles (USBH_HandleTypeDef *phost, + uint32_t storage_id, + uint32_t objectformatcode, + uint32_t associationOH, + PTP_ObjectHandlesTypedef* objecthandles) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObjectHandles; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = storage_id; + ptp_container.Param2 = objectformatcode; + ptp_container.Param3 = associationOH; + ptp_container.Nparam = 3; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + objecthandles->n = PTP_GetArray32 (objecthandles->Handler, + MTP_Handle->ptp.data_container.payload.data, + 0); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectInfo + * Gets objert info + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObjectInfo (USBH_HandleTypeDef *phost, + uint32_t handle, + PTP_ObjectInfoTypedef* object_info) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObjectInfo; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = handle; + ptp_container.Nparam = 1; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_GetObjectInfo (phost, object_info); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_DeleteObject + * Delete an object. + * @param phost: Host handle + * @param handle : Object Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_DeleteObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t objectformatcode) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_NODATA; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_DeleteObject; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = handle; + ptp_container.Param2 = objectformatcode; + ptp_container.Nparam = 2; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObject + * Gets object + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* set object control params */ + MTP_Handle->ptp.object_ptr = object; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObject; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = handle; + ptp_container.Nparam = 1; + + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + /* first packet is in the PTP data payload buffer */ + if(MTP_Handle->ptp.iteration == 0) + { + /* copy it to object */ + USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, PTP_USB_BULK_PAYLOAD_LEN_READ); + } + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetPartialObject + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetPartialObject(USBH_HandleTypeDef *phost, + uint32_t handle, + uint32_t offset, + uint32_t maxbytes, + uint8_t *object, + uint32_t *len) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* set object control params */ + MTP_Handle->ptp.object_ptr = object; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetPartialObject; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = handle; + ptp_container.Param2 = offset; + ptp_container.Param3 = maxbytes; + ptp_container.Nparam = 3; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + *len = MTP_Handle->ptp.resp_container.param1; + /* first packet is in the PTP data payload buffer */ + if(MTP_Handle->ptp.iteration == 0) + { + /* copy it to object */ + USBH_memcpy(MTP_Handle->ptp.object_ptr, MTP_Handle->ptp.data_container.payload.data, *len); + } + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectPropsSupported + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObjectPropsSupported (USBH_HandleTypeDef *phost, + uint16_t ofc, + uint32_t *propnum, + uint16_t *props) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObjectPropsSupported; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = ofc; + ptp_container.Nparam = 1; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + *propnum = PTP_GetArray16 (props, MTP_Handle->ptp.data_container.payload.data, 0); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectPropDesc + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObjectPropDesc (USBH_HandleTypeDef *phost, + uint16_t opc, + uint16_t ofc, + PTP_ObjectPropDescTypeDef *opd) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObjectPropDesc; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = opc; + ptp_container.Param2 = ofc; + ptp_container.Nparam = 2; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_GetObjectPropDesc(phost, opd, MTP_Handle->ptp.data_length); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_GetObjectPropList + * Gets object partially + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_GetObjectPropList (USBH_HandleTypeDef *phost, + uint32_t handle, + MTP_PropertiesTypedef *pprops, + uint32_t *nrofprops) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_GETDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_length = 0; + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + + /* copy first packet of the object into data container */ + USBH_memcpy(MTP_Handle->ptp.data_container.payload.data, MTP_Handle->ptp.object_ptr, PTP_USB_BULK_PAYLOAD_LEN_READ); + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_GetObjPropList; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Param1 = handle; + ptp_container.Param2 = 0x00000000U; /* 0x00000000U should be "all formats" */ + ptp_container.Param3 = 0xFFFFFFFFU; /* 0xFFFFFFFFU should be "all properties" */ + ptp_container.Param4 = 0x00000000U; + ptp_container.Param5 = 0xFFFFFFFFU; /* Return full tree below the Param1 handle */ + ptp_container.Nparam = 5; + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + + if(status == USBH_OK) + { + PTP_GetObjectPropList (phost, pprops, MTP_Handle->ptp.data_length); + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_PTP_SendObject + * Send an object + * @param phost: Host handle + * @param dev_info: Device info structure + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_PTP_SendObject (USBH_HandleTypeDef *phost, + uint32_t handle, + uint8_t *object, + uint32_t size) +{ + USBH_StatusTypeDef status = USBH_BUSY; + MTP_HandleTypeDef *MTP_Handle = phost->pActiveClass->pData; + PTP_ContainerTypedef ptp_container; + + switch(MTP_Handle->ptp.req_state) + { + case PTP_REQ_SEND: + + /* Set operation request type */ + MTP_Handle->ptp.flags = PTP_DP_SENDDATA; + MTP_Handle->ptp.data_ptr = (uint8_t *)&(MTP_Handle->ptp.data_container); + MTP_Handle->ptp.data_packet_counter = 0; + MTP_Handle->ptp.data_packet = 0; + MTP_Handle->ptp.iteration = 0; + + /* set object control params */ + MTP_Handle->ptp.object_ptr = object; + MTP_Handle->ptp.data_length = size; + + /* Fill operation request params */ + ptp_container.Code = PTP_OC_SendObject; + ptp_container.SessionID = MTP_Handle->ptp.session_id; + ptp_container.Transaction_ID = MTP_Handle->ptp.transaction_id ++; + ptp_container.Nparam = 0; + + + /* convert request packet into USB raw packet*/ + USBH_PTP_SendRequest (phost, &ptp_container); + + /* Setup State machine and start transfer */ + MTP_Handle->ptp.state = PTP_OP_REQUEST_STATE; + MTP_Handle->ptp.req_state = PTP_REQ_WAIT; + status = USBH_BUSY; + break; + + case PTP_REQ_WAIT: + status = USBH_PTP_Process(phost); + break; + + default: + break; + } + return status; +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h b/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h new file mode 100755 index 0000000..728a36c --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Inc/usbh_template.h @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * @file usbh_mtp.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file contains all the prototypes for the usbh_template.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_TEMPLATE_CORE_H +#define __USBH_TEMPLATE_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_TEMPLATE_CLASS +* @{ +*/ + +/** @defgroup USBH_TEMPLATE_CORE +* @brief This file is the Header file for USBH_TEMPLATE_CORE.c +* @{ +*/ + + +/** + * @} + */ + +/** @defgroup USBH_TEMPLATE_CORE_Exported_Types +* @{ +*/ + +/* States for TEMPLATE State Machine */ + + +/** +* @} +*/ + +/** @defgroup USBH_TEMPLATE_CORE_Exported_Defines +* @{ +*/ + +/** +* @} +*/ + +/** @defgroup USBH_TEMPLATE_CORE_Exported_Macros +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_TEMPLATE_CORE_Exported_Variables +* @{ +*/ +extern USBH_ClassTypeDef TEMPLATE_Class; +#define USBH_TEMPLATE_CLASS &TEMPLATE_Class + +/** +* @} +*/ + +/** @defgroup USBH_TEMPLATE_CORE_Exported_FunctionsPrototype +* @{ +*/ +USBH_StatusTypeDef USBH_TEMPLATE_IOProcess (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_TEMPLATE_Init (USBH_HandleTypeDef *phost); +/** +* @} +*/ + + +#endif /* __USBH_TEMPLATE_CORE_H */ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Src/usbh_template.c b/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Src/usbh_template.c new file mode 100755 index 0000000..2ea14a8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Class/Template/Src/usbh_template.c @@ -0,0 +1,240 @@ +/** + ****************************************************************************** + * @file usbh_mtp.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file is the MTP Layer Handlers for USB Host MTP class. + * + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_template.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_CLASS +* @{ +*/ + +/** @addtogroup USBH_TEMPLATE_CLASS +* @{ +*/ + +/** @defgroup USBH_TEMPLATE_CORE +* @brief This file includes TEMPLATE Layer Handlers for USB Host TEMPLATE class. +* @{ +*/ + +/** @defgroup USBH_TEMPLATE_CORE_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_TEMPLATE_CORE_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_TEMPLATE_CORE_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_TEMPLATE_CORE_Private_Variables +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_TEMPLATE_CORE_Private_FunctionPrototypes +* @{ +*/ + +static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceDeInit (USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_TEMPLATE_Process(USBH_HandleTypeDef *phost); + +static USBH_StatusTypeDef USBH_TEMPLATE_ClassRequest (USBH_HandleTypeDef *phost); + + +USBH_ClassTypeDef TEMPLATE_Class = +{ + "TEMPLATE", + USB_TEMPLATE_CLASS, + USBH_TEMPLATE_InterfaceInit, + USBH_TEMPLATE_InterfaceDeInit, + USBH_TEMPLATE_ClassRequest, + USBH_TEMPLATE_Process +}; +/** +* @} +*/ + + +/** @defgroup USBH_TEMPLATE_CORE_Private_Functions +* @{ +*/ + +/** + * @brief USBH_TEMPLATE_InterfaceInit + * The function init the TEMPLATE class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_TEMPLATE_InterfaceInit (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + + + +/** + * @brief USBH_TEMPLATE_InterfaceDeInit + * The function DeInit the Pipes used for the TEMPLATE class. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_TEMPLATE_InterfaceDeInit (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_TEMPLATE_ClassRequest + * The function is responsible for handling Standard requests + * for TEMPLATE class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_TEMPLATE_ClassRequest (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + + +/** + * @brief USBH_TEMPLATE_Process + * The function is for managing state machine for TEMPLATE data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_TEMPLATE_Process (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + + +/** + * @brief USBH_TEMPLATE_Init + * The function Initialize the TEMPLATE function + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_TEMPLATE_Init (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef Status = USBH_BUSY; +#if (USBH_USE_OS == 1) + osEvent event; + + event = osMessageGet( phost->class_ready_event, osWaitForever ); + + if( event.status == osEventMessage ) + { + if(event.value.v == USBH_CLASS_EVENT) + { +#else + + while ((Status == USBH_BUSY) || (Status == USBH_FAIL)) + { + /* Host background process */ + USBH_Process(phost); + if(phost->gState == HOST_CLASS) + { +#endif + Status = USBH_OK; + } + } + return Status; +} + +/** + * @brief USBH_TEMPLATE_IOProcess + * TEMPLATE TEMPLATE process + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_TEMPLATE_IOProcess (USBH_HandleTypeDef *phost) +{ + if (phost->device.is_connected == 1) + { + if(phost->gState == HOST_CLASS) + { + USBH_TEMPLATE_Process(phost); + } + } + + return USBH_OK; +} + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h new file mode 100755 index 0000000..8f85e13 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_conf_template.h @@ -0,0 +1,151 @@ +/** + ****************************************************************************** + * @file USBH_conf.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBH_CONF__H__ +#define __USBH_CONF__H__ + +#include "stm32f4xx.h" +#include +#include +#include + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup USBH_OTG_DRIVER + * @{ + */ + +/** @defgroup USBH_CONF + * @brief usb otg low level driver configuration file + * @{ + */ + +/** @defgroup USBH_CONF_Exported_Defines + * @{ + */ + +#define USBH_MAX_NUM_ENDPOINTS 2 +#define USBH_MAX_NUM_INTERFACES 2 +#define USBH_MAX_NUM_CONFIGURATION 1 +#define USBH_KEEP_CFG_DESCRIPTOR 1 +#define USBH_MAX_NUM_SUPPORTED_CLASS 1 +#define USBH_MAX_SIZE_CONFIGURATION 0x200 +#define USBH_MAX_DATA_BUFFER 0x200 +#define USBH_DEBUG_LEVEL 2 +#define USBH_USE_OS 1 + +/** @defgroup USBH_Exported_Macros + * @{ + */ + + /* Memory management macros */ +#define USBH_malloc malloc +#define USBH_free free +#define USBH_memset memset +#define USBH_memcpy memcpy + + /* DEBUG macros */ + + +#if (USBH_DEBUG_LEVEL > 0) +#define USBH_UsrLog(...) printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBH_UsrLog(...) +#endif + + +#if (USBH_DEBUG_LEVEL > 1) + +#define USBH_ErrLog(...) printf("ERROR: ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBH_ErrLog(...) +#endif + + +#if (USBH_DEBUG_LEVEL > 2) +#define USBH_DbgLog(...) printf("DEBUG : ") ;\ + printf(__VA_ARGS__);\ + printf("\n"); +#else +#define USBH_DbgLog(...) +#endif + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup USBH_CONF_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_CONF_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_CONF_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_CONF_Exported_FunctionsPrototype + * @{ + */ +/** + * @} + */ + + +#endif //__USBH_CONF__H__ + + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_core.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_core.h new file mode 100755 index 0000000..bc3da6d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_core.h @@ -0,0 +1,161 @@ +/** + ****************************************************************************** + * @file usbh_core.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_core.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_CORE_H +#define __USBH_CORE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_conf.h" +#include "usbh_def.h" +#include "usbh_ioreq.h" +#include "usbh_pipes.h" +#include "usbh_ctlreq.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_CORE + * @brief This file is the Header file for usbh_core.c + * @{ + */ + + +/** @defgroup USBH_CORE_Exported_Defines + * @{ + */ + +/** + * @} + */ +#define HOST_USER_SELECT_CONFIGURATION 1 +#define HOST_USER_CLASS_ACTIVE 2 +#define HOST_USER_CLASS_SELECTED 3 +#define HOST_USER_CONNECTION 4 +#define HOST_USER_DISCONNECTION 5 + + + +/** + * @} + */ + + + +/** @defgroup USBH_CORE_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_CORE_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBH_CORE_Exported_FunctionsPrototype + * @{ + */ + + +USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id); +USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass); +USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface); +uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, + uint8_t Class, + uint8_t SubClass, + uint8_t Protocol); +uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost); + +uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, + uint8_t interface_number, + uint8_t alt_settings); + +USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_Process (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost); + +/* USBH Low Level Driver */ +USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_LL_Start (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost); + +USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost); +USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost); +USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost); +uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t ); +USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t ); + +USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost, uint8_t, uint8_t, uint8_t, uint8_t , uint8_t, uint16_t ); +USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t ); +USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost, uint8_t, uint8_t,uint8_t, uint8_t, uint8_t*, uint16_t, uint8_t ); +USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t ); +#if (USBH_USE_OS == 1) +USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost); +#endif +USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t , uint8_t ); +uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t ); + +/* USBH Time base */ +void USBH_Delay (uint32_t Delay); +void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t ); +void USBH_LL_IncTimer (USBH_HandleTypeDef *phost); +/** + * @} + */ + +#endif /* __CORE_H */ +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h new file mode 100755 index 0000000..cd61755 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ctlreq.h @@ -0,0 +1,147 @@ +/** + ****************************************************************************** + * @file usbh_ctlreq.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_ctlreq.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_CTLREQ_H +#define __USBH_CTLREQ_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_CTLREQ + * @brief This file is the + * @{ + */ + + +/** @defgroup USBH_CTLREQ_Exported_Defines + * @{ + */ +/*Standard Feature Selector for clear feature command*/ +#define FEATURE_SELECTOR_ENDPOINT 0X00 +#define FEATURE_SELECTOR_DEVICE 0X01 + + +#define INTERFACE_DESC_TYPE 0x04 +#define ENDPOINT_DESC_TYPE 0x05 +#define INTERFACE_DESC_SIZE 0x09 + +/** + * @} + */ + + +/** @defgroup USBH_CTLREQ_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_CTLREQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_CTLREQ_Exported_Variables + * @{ + */ +extern uint8_t USBH_CfgDesc[512]; +/** + * @} + */ + +/** @defgroup USBH_CTLREQ_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length); + +USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost, + uint8_t req_type, + uint16_t value_idx, + uint8_t* buff, + uint16_t length ); + +USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, + uint8_t length); + +USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost, + uint8_t string_index, + uint8_t *buff, + uint16_t length); + +USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, + uint16_t configuration_value); + +USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost, + uint16_t length); + +USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost, + uint8_t DeviceAddress); + +USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, + uint8_t ep_num, uint8_t altSetting); + +USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, + uint8_t ep_num); + +USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, + uint16_t *ptr); +/** + * @} + */ + +#endif /* __USBH_CTLREQ_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_def.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_def.h new file mode 100755 index 0000000..cf24d69 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_def.h @@ -0,0 +1,480 @@ +/** + ****************************************************************************** + * @file usbh_def.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Definitions used in the USB host library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_DEF + * @brief This file is includes USB descriptors + * @{ + */ + +#ifndef USBH_DEF_H +#define USBH_DEF_H + +#include "usbh_conf.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + + +#define ValBit(VAR,POS) (VAR & (1 << POS)) +#define SetBit(VAR,POS) (VAR |= (1 << POS)) +#define ClrBit(VAR,POS) (VAR &= ((1 << POS)^255)) + +#define LE16(addr) (((uint16_t)(*((uint8_t *)(addr))))\ + + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LE16S(addr) (uint16_t)(LE16((addr))) + +#define LE32(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \ + (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \ + (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16) + \ + (((uint32_t)(*(((uint8_t *)(addr)) + 3))) << 24))) + +#define LE64(addr) ((((uint64_t)(*(((uint8_t *)(addr)) + 0))) + \ + (((uint64_t)(*(((uint8_t *)(addr)) + 1))) << 8) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 2))) << 16) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 3))) << 24) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 4))) << 32) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 5))) << 40) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 6))) << 48) +\ + (((uint64_t)(*(((uint8_t *)(addr)) + 7))) << 56))) + + +#define LE24(addr) ((((uint32_t)(*(((uint8_t *)(addr)) + 0))) + \ + (((uint32_t)(*(((uint8_t *)(addr)) + 1))) << 8) + \ + (((uint32_t)(*(((uint8_t *)(addr)) + 2))) << 16))) + + +#define LE32S(addr) (int32_t)(LE32((addr))) + + + +#define USB_LEN_DESC_HDR 0x02 +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 +#define USB_LEN_SETUP_PKT 0x08 + +/* bmRequestType :D7 Data Phase Transfer Direction */ +#define USB_REQ_DIR_MASK 0x80 +#define USB_H2D 0x00 +#define USB_D2H 0x80 + +/* bmRequestType D6..5 Type */ +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_RESERVED 0x60 + +/* bmRequestType D4..0 Recipient */ +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_OTHER 0x03 + +/* Table 9-4. Standard Request Codes */ +/* bRequest , Value */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +/* Table 9-5. Descriptor Types of USB Specifications */ +#define USB_DESC_TYPE_DEVICE 1 +#define USB_DESC_TYPE_CONFIGURATION 2 +#define USB_DESC_TYPE_STRING 3 +#define USB_DESC_TYPE_INTERFACE 4 +#define USB_DESC_TYPE_ENDPOINT 5 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 6 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7 +#define USB_DESC_TYPE_INTERFACE_POWER 8 +#define USB_DESC_TYPE_HID 0x21 +#define USB_DESC_TYPE_HID_REPORT 0x22 + + +#define USB_DEVICE_DESC_SIZE 18 +#define USB_CONFIGURATION_DESC_SIZE 9 +#define USB_HID_DESC_SIZE 9 +#define USB_INTERFACE_DESC_SIZE 9 +#define USB_ENDPOINT_DESC_SIZE 7 + +/* Descriptor Type and Descriptor Index */ +/* Use the following values when calling the function USBH_GetDescriptor */ +#define USB_DESC_DEVICE ((USB_DESC_TYPE_DEVICE << 8) & 0xFF00) +#define USB_DESC_CONFIGURATION ((USB_DESC_TYPE_CONFIGURATION << 8) & 0xFF00) +#define USB_DESC_STRING ((USB_DESC_TYPE_STRING << 8) & 0xFF00) +#define USB_DESC_INTERFACE ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00) +#define USB_DESC_ENDPOINT ((USB_DESC_TYPE_INTERFACE << 8) & 0xFF00) +#define USB_DESC_DEVICE_QUALIFIER ((USB_DESC_TYPE_DEVICE_QUALIFIER << 8) & 0xFF00) +#define USB_DESC_OTHER_SPEED_CONFIGURATION ((USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION << 8) & 0xFF00) +#define USB_DESC_INTERFACE_POWER ((USB_DESC_TYPE_INTERFACE_POWER << 8) & 0xFF00) +#define USB_DESC_HID_REPORT ((USB_DESC_TYPE_HID_REPORT << 8) & 0xFF00) +#define USB_DESC_HID ((USB_DESC_TYPE_HID << 8) & 0xFF00) + + +#define USB_EP_TYPE_CTRL 0x00 +#define USB_EP_TYPE_ISOC 0x01 +#define USB_EP_TYPE_BULK 0x02 +#define USB_EP_TYPE_INTR 0x03 + +#define USB_EP_DIR_OUT 0x00 +#define USB_EP_DIR_IN 0x80 +#define USB_EP_DIR_MSK 0x80 + +#define USBH_MAX_PIPES_NBR 15 + + + +#define USBH_DEVICE_ADDRESS_DEFAULT 0 +#define USBH_MAX_ERROR_COUNT 2 +#define USBH_DEVICE_ADDRESS 1 + + +/** + * @} + */ + + +#define USBH_CONFIGURATION_DESCRIPTOR_SIZE (USB_CONFIGURATION_DESC_SIZE \ + + USB_INTERFACE_DESC_SIZE\ + + (USBH_MAX_NUM_ENDPOINTS * USB_ENDPOINT_DESC_SIZE)) + + +#define CONFIG_DESC_wTOTAL_LENGTH (ConfigurationDescriptorData.ConfigDescfield.\ + ConfigurationDescriptor.wTotalLength) + + +typedef union +{ + uint16_t w; + struct BW + { + uint8_t msb; + uint8_t lsb; + } + bw; +} +uint16_t_uint8_t; + + +typedef union _USB_Setup +{ + uint32_t d8[2]; + + struct _SetupPkt_Struc + { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t_uint8_t wValue; + uint16_t_uint8_t wIndex; + uint16_t_uint8_t wLength; + } b; +} +USB_Setup_TypeDef; + +typedef struct _DescHeader +{ + uint8_t bLength; + uint8_t bDescriptorType; +} +USBH_DescHeader_t; + +typedef struct _DeviceDescriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; /* USB Specification Number which device complies too */ + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + /* If equal to Zero, each interface specifies its own class + code if equal to 0xFF, the class code is vendor specified. + Otherwise field is valid Class Code.*/ + uint8_t bMaxPacketSize; + uint16_t idVendor; /* Vendor ID (Assigned by USB Org) */ + uint16_t idProduct; /* Product ID (Assigned by Manufacturer) */ + uint16_t bcdDevice; /* Device Release Number */ + uint8_t iManufacturer; /* Index of Manufacturer String Descriptor */ + uint8_t iProduct; /* Index of Product String Descriptor */ + uint8_t iSerialNumber; /* Index of Serial Number String Descriptor */ + uint8_t bNumConfigurations; /* Number of Possible Configurations */ +} +USBH_DevDescTypeDef; + +typedef struct _EndpointDescriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; /* indicates what endpoint this descriptor is describing */ + uint8_t bmAttributes; /* specifies the transfer type. */ + uint16_t wMaxPacketSize; /* Maximum Packet Size this endpoint is capable of sending or receiving */ + uint8_t bInterval; /* is used to specify the polling interval of certain transfers. */ +} +USBH_EpDescTypeDef; + +typedef struct _InterfaceDescriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; /* Value used to select alternative setting */ + uint8_t bNumEndpoints; /* Number of Endpoints used for this interface */ + uint8_t bInterfaceClass; /* Class Code (Assigned by USB Org) */ + uint8_t bInterfaceSubClass; /* Subclass Code (Assigned by USB Org) */ + uint8_t bInterfaceProtocol; /* Protocol Code */ + uint8_t iInterface; /* Index of String Descriptor Describing this interface */ + USBH_EpDescTypeDef Ep_Desc[USBH_MAX_NUM_ENDPOINTS]; +} +USBH_InterfaceDescTypeDef; + + +typedef struct _ConfigurationDescriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; /* Total Length of Data Returned */ + uint8_t bNumInterfaces; /* Number of Interfaces */ + uint8_t bConfigurationValue; /* Value to use as an argument to select this configuration*/ + uint8_t iConfiguration; /*Index of String Descriptor Describing this configuration */ + uint8_t bmAttributes; /* D7 Bus Powered , D6 Self Powered, D5 Remote Wakeup , D4..0 Reserved (0)*/ + uint8_t bMaxPower; /*Maximum Power Consumption */ + USBH_InterfaceDescTypeDef Itf_Desc[USBH_MAX_NUM_INTERFACES]; +} +USBH_CfgDescTypeDef; + + +/* Following USB Host status */ +typedef enum +{ + USBH_OK = 0, + USBH_BUSY, + USBH_FAIL, + USBH_NOT_SUPPORTED, + USBH_UNRECOVERED_ERROR, + USBH_ERROR_SPEED_UNKNOWN, +}USBH_StatusTypeDef; + + +/** @defgroup USBH_CORE_Exported_Types + * @{ + */ + +typedef enum +{ + USBH_SPEED_HIGH = 0, + USBH_SPEED_FULL = 1, + USBH_SPEED_LOW = 2, + +}USBH_SpeedTypeDef; + +/* Following states are used for gState */ +typedef enum +{ + HOST_IDLE =0, + HOST_DEV_WAIT_FOR_ATTACHMENT, + HOST_DEV_ATTACHED, + HOST_DEV_DISCONNECTED, + HOST_DETECT_DEVICE_SPEED, + HOST_ENUMERATION, + HOST_CLASS_REQUEST, + HOST_INPUT, + HOST_SET_CONFIGURATION, + HOST_CHECK_CLASS, + HOST_CLASS, + HOST_SUSPENDED, + HOST_ABORT_STATE, +}HOST_StateTypeDef; + +/* Following states are used for EnumerationState */ +typedef enum +{ + ENUM_IDLE = 0, + ENUM_GET_FULL_DEV_DESC, + ENUM_SET_ADDR, + ENUM_GET_CFG_DESC, + ENUM_GET_FULL_CFG_DESC, + ENUM_GET_MFC_STRING_DESC, + ENUM_GET_PRODUCT_STRING_DESC, + ENUM_GET_SERIALNUM_STRING_DESC, +} ENUM_StateTypeDef; + +/* Following states are used for CtrlXferStateMachine */ +typedef enum +{ + CTRL_IDLE =0, + CTRL_SETUP, + CTRL_SETUP_WAIT, + CTRL_DATA_IN, + CTRL_DATA_IN_WAIT, + CTRL_DATA_OUT, + CTRL_DATA_OUT_WAIT, + CTRL_STATUS_IN, + CTRL_STATUS_IN_WAIT, + CTRL_STATUS_OUT, + CTRL_STATUS_OUT_WAIT, + CTRL_ERROR, + CTRL_STALLED, + CTRL_COMPLETE +}CTRL_StateTypeDef; + + +/* Following states are used for RequestState */ +typedef enum +{ + CMD_IDLE =0, + CMD_SEND, + CMD_WAIT +} CMD_StateTypeDef; + +typedef enum { + USBH_URB_IDLE = 0, + USBH_URB_DONE, + USBH_URB_NOTREADY, + USBH_URB_NYET, + USBH_URB_ERROR, + USBH_URB_STALL +}USBH_URBStateTypeDef; + +typedef enum +{ + USBH_PORT_EVENT = 1, + USBH_URB_EVENT, + USBH_CONTROL_EVENT, + USBH_CLASS_EVENT, + USBH_STATE_CHANGED_EVENT, +} +USBH_OSEventTypeDef; + +/* Control request structure */ +typedef struct +{ + uint8_t pipe_in; + uint8_t pipe_out; + uint8_t pipe_size; + uint8_t *buff; + uint16_t length; + uint16_t timer; + USB_Setup_TypeDef setup; + CTRL_StateTypeDef state; + uint8_t errorcount; + +} USBH_CtrlTypeDef; + +/* Attached device structure */ +typedef struct +{ +#if (USBH_KEEP_CFG_DESCRIPTOR == 1) + uint8_t CfgDesc_Raw[USBH_MAX_SIZE_CONFIGURATION]; +#endif + uint8_t Data[USBH_MAX_DATA_BUFFER]; + uint8_t address; + uint8_t speed; + __IO uint8_t is_connected; + uint8_t current_interface; + USBH_DevDescTypeDef DevDesc; + USBH_CfgDescTypeDef CfgDesc; + +}USBH_DeviceTypeDef; + +struct _USBH_HandleTypeDef; + +/* USB Host Class structure */ +typedef struct +{ + const char *Name; + uint8_t ClassCode; + USBH_StatusTypeDef (*Init) (struct _USBH_HandleTypeDef *phost); + USBH_StatusTypeDef (*DeInit) (struct _USBH_HandleTypeDef *phost); + USBH_StatusTypeDef (*Requests) (struct _USBH_HandleTypeDef *phost); + USBH_StatusTypeDef (*BgndProcess) (struct _USBH_HandleTypeDef *phost); + USBH_StatusTypeDef (*SOFProcess) (struct _USBH_HandleTypeDef *phost); + void* pData; +} USBH_ClassTypeDef; + +/* USB Host handle structure */ +typedef struct _USBH_HandleTypeDef +{ + __IO HOST_StateTypeDef gState; /* Host State Machine Value */ + ENUM_StateTypeDef EnumState; /* Enumeration state Machine */ + CMD_StateTypeDef RequestState; + USBH_CtrlTypeDef Control; + USBH_DeviceTypeDef device; + USBH_ClassTypeDef* pClass[USBH_MAX_NUM_SUPPORTED_CLASS]; + USBH_ClassTypeDef* pActiveClass; + uint32_t ClassNumber; + uint32_t Pipes[15]; + __IO uint32_t Timer; + uint8_t id; + void* pData; + void (* pUser )(struct _USBH_HandleTypeDef *pHandle, uint8_t id); + +#if (USBH_USE_OS == 1) + osMessageQId os_event; + osThreadId thread; +#endif + +} USBH_HandleTypeDef; + + +#if defined ( __GNUC__ ) + #ifndef __weak + #define __weak __attribute__((weak)) + #endif /* __weak */ + #ifndef __packed + #define __packed __attribute__((__packed__)) + #endif /* __packed */ +#endif /* __GNUC__ */ + +#endif + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h new file mode 100755 index 0000000..463d4ea --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_ioreq.h @@ -0,0 +1,159 @@ +/** + ****************************************************************************** + * @file usbh_ioreq.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_ioreq.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_IOREQ_H +#define __USBH_IOREQ_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_conf.h" +#include "usbh_core.h" +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_IOREQ + * @brief This file is the header file for usbh_ioreq.c + * @{ + */ + + +/** @defgroup USBH_IOREQ_Exported_Defines + * @{ + */ + +#define USBH_PID_SETUP 0 +#define USBH_PID_DATA 1 + +#define USBH_EP_CONTROL 0 +#define USBH_EP_ISO 1 +#define USBH_EP_BULK 2 +#define USBH_EP_INTERRUPT 3 + +#define USBH_SETUP_PKT_SIZE 8 +/** + * @} + */ + + +/** @defgroup USBH_IOREQ_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_IOREQ_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_IOREQ_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_IOREQ_Exported_FunctionsPrototype + * @{ + */ +USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t hc_num); + +USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t hc_num, + uint8_t do_ping ); + +USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t hc_num); + +USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t hc_num); + +USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t hc_num, + uint8_t do_ping ); + +USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t length, + uint8_t hc_num); + +USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t length, + uint8_t hc_num); + + +USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint32_t length, + uint8_t hc_num); + + +USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint32_t length, + uint8_t hc_num); +/** + * @} + */ + +#endif /* __USBH_IOREQ_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_pipes.h b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_pipes.h new file mode 100755 index 0000000..d72cd53 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Inc/usbh_pipes.h @@ -0,0 +1,124 @@ +/** + ****************************************************************************** + * @file usbh_PIPES.h + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief Header file for usbh_pipes.c + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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 to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_PIPES_H +#define __USBH_PIPES_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_PIPES + * @brief This file is the header file for usbh_PIPES.c + * @{ + */ + +/** @defgroup USBH_PIPES_Exported_Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_PIPES_Exported_Types + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_PIPES_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_PIPES_Exported_Variables + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_PIPES_Exported_FunctionsPrototype + * @{ + */ + +USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost, + uint8_t ch_num, + uint8_t epnum, + uint8_t dev_address, + uint8_t speed, + uint8_t ep_type, + uint16_t mps); + +USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost, + uint8_t pipe_num); + +uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost, + uint8_t ep_addr); + +USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost, + uint8_t idx); + + + + +/** + * @} + */ + + + +#endif /* __USBH_PIPES_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_conf_template.c b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_conf_template.c new file mode 100755 index 0000000..1c25f7b --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_conf_template.c @@ -0,0 +1,270 @@ +/** + ****************************************************************************** + * @file usb_bsp.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements the board support package for the USB host library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +/** + * @brief USBH_LL_Init + * Initialize the Low Level portion of the Host driver. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_Init (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_DeInit + * De-Initialize the Low Level portion of the Host driver. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_DeInit (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_Start + * Start the Low Level portion of the Host driver. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_Stop + * Stop the Low Level portion of the Host driver. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_Stop (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_GetSpeed + * Return the USB Host Speed from the Low Level Driver. + * @param phost: Host handle + * @retval USBH Speeds + */ +USBH_SpeedTypeDef USBH_LL_GetSpeed (USBH_HandleTypeDef *phost) +{ + USBH_SpeedTypeDef speed = 0; + + + return speed; +} + +/** + * @brief USBH_LL_ResetPort + * Reset the Host Port of the Low Level Driver. + * @param phost: Host handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_ResetPort (USBH_HandleTypeDef *phost) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_GetLastXferSize + * Return the last transfered packet size. + * @param phost: Host handle + * @param pipe: Pipe index + * @retval Packet Size + */ +uint32_t USBH_LL_GetLastXferSize (USBH_HandleTypeDef *phost, uint8_t pipe) +{ + +} + +/** + * @brief USBH_LL_OpenPipe + * Open a pipe of the Low Level Driver. + * @param phost: Host handle + * @param pipe_num: Pipe index + * @param epnum: Endpoint Number + * @param dev_address: Device USB address + * @param speed: Device Speed + * @param ep_type: Endpoint Type + * @param mps: Endpoint Max Packet Size + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_OpenPipe (USBH_HandleTypeDef *phost, + uint8_t pipe_num, + uint8_t epnum, + uint8_t dev_address, + uint8_t speed, + uint8_t ep_type, + uint16_t mps) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_ClosePipe + * Close a pipe of the Low Level Driver. + * @param phost: Host handle + * @param pipe_num: Pipe index + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_LL_ClosePipe (USBH_HandleTypeDef *phost, uint8_t pipe) +{ + +} +/** + * @brief USBH_LL_SubmitURB + * Submit a new URB to the low level driver. + * @param phost: Host handle + * @param pipe: Pipe index + * This parameter can be a value from 1 to 15 + * @param direction : Channel number + * This parameter can be one of the these values: + * 0 : Output + * 1 : Input + * @param ep_type : Endpoint Type + * This parameter can be one of the these values: + * @arg EP_TYPE_CTRL: Control type + * @arg EP_TYPE_ISOC: Isochrounous type + * @arg EP_TYPE_BULK: Bulk type + * @arg EP_TYPE_INTR: Interrupt type + * @param token : Endpoint Type + * This parameter can be one of the these values: + * @arg 0: PID_SETUP + * @arg 1: PID_DATA + * @param pbuff : pointer to URB data + * @param length : Length of URB data + * @param do_ping : activate do ping protocol (for high speed only) + * This parameter can be one of the these values: + * 0 : do ping inactive + * 1 : do ping active + * @retval Status + */ + +USBH_StatusTypeDef USBH_LL_SubmitURB (USBH_HandleTypeDef *phost, + uint8_t pipe, + uint8_t direction , + uint8_t ep_type, + uint8_t token, + uint8_t* pbuff, + uint16_t length, + uint8_t do_ping ) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_GetURBState + * Get a URB state from the low level driver. + * @param phost: Host handle + * @param pipe: Pipe index + * This parameter can be a value from 1 to 15 + * @retval URB state + * This parameter can be one of the these values: + * @arg URB_IDLE + * @arg URB_DONE + * @arg URB_NOTREADY + * @arg URB_NYET + * @arg URB_ERROR + * @arg URB_STALL + */ +USBH_URBStateTypeDef USBH_LL_GetURBState (USBH_HandleTypeDef *phost, uint8_t pipe) +{ + +} + +/** + * @brief USBH_LL_DriverVBUS + * Drive VBUS. + * @param phost: Host handle + * @param state : VBUS state + * This parameter can be one of the these values: + * 0 : VBUS Active + * 1 : VBUS Inactive + * @retval Status + */ + +USBH_StatusTypeDef USBH_LL_DriverVBUS (USBH_HandleTypeDef *phost, uint8_t state) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_SetToggle + * Set toggle for a pipe. + * @param phost: Host handle + * @param pipe: Pipe index + * @param pipe_num: Pipe index + * @param toggle: toggle (0/1) + * @retval Status + */ +USBH_StatusTypeDef USBH_LL_SetToggle (USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle) +{ + + return USBH_OK; +} + +/** + * @brief USBH_LL_GetToggle + * Return the current toggle of a pipe. + * @param phost: Host handle + * @param pipe: Pipe index + * @retval toggle (0/1) + */ +uint8_t USBH_LL_GetToggle (USBH_HandleTypeDef *phost, uint8_t pipe) +{ + uint8_t toggle = 0; + + + return toggle; +} +/** + * @brief USBH_Delay + * Delay routine for the USB Host Library + * @param Delay: Delay in ms + * @retval None + */ +void USBH_Delay (uint32_t Delay) +{ + +} +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_core.c b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_core.c new file mode 100755 index 0000000..9d2727a --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_core.c @@ -0,0 +1,936 @@ +/** + ****************************************************************************** + * @file usbh_core.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements the functions for the core state machine process + * the enumeration and the control transfer process + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ + +#include "usbh_core.h" + + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE + * @{ + */ + +/** @defgroup USBH_CORE + * @brief TThis file handles the basic enumaration when a device is connected + * to the host. + * @{ + */ + + +/** @defgroup USBH_CORE_Private_Defines + * @{ + */ +#define USBH_ADDRESS_DEFAULT 0 +#define USBH_ADDRESS_ASSIGNED 1 +#define USBH_MPS_DEFAULT 0x40 +/** + * @} + */ + +/** @defgroup USBH_CORE_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_CORE_Private_Variables + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_CORE_Private_Functions + * @{ + */ +static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost); +static void USBH_HandleSof (USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost); + +#if (USBH_USE_OS == 1) +static void USBH_Process_OS(void const * argument); +#endif + +/** + * @brief HCD_Init + * Initialize the HOST Core. + * @param phost: Host Handle + * @param pUsrFunc: User Callback + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Init(USBH_HandleTypeDef *phost, void (*pUsrFunc)(USBH_HandleTypeDef *phost, uint8_t ), uint8_t id) +{ + /* Check whether the USB Host handle is valid */ + if(phost == NULL) + { + USBH_ErrLog("Invalid Host handle"); + return USBH_FAIL; + } + + /* Set DRiver ID */ + phost->id = id; + + /* Unlink class*/ + phost->pActiveClass = NULL; + phost->ClassNumber = 0; + + /* Restore default states and prepare EP0 */ + DeInitStateMachine(phost); + + /* Assign User process */ + if(pUsrFunc != NULL) + { + phost->pUser = pUsrFunc; + } + +#if (USBH_USE_OS == 1) + + /* Create USB Host Queue */ + osMessageQDef(USBH_Queue, 10, uint16_t); + phost->os_event = osMessageCreate (osMessageQ(USBH_Queue), NULL); + + /*Create USB Host Task */ + osThreadDef(USBH_Thread, USBH_Process_OS, USBH_PROCESS_PRIO, 0, 8 * configMINIMAL_STACK_SIZE); + phost->thread = osThreadCreate (osThread(USBH_Thread), phost); +#endif + + /* Initialize low level driver */ + USBH_LL_Init(phost); + return USBH_OK; +} + +/** + * @brief HCD_Init + * De-Initialize the Host portion of the driver. + * @param phost: Host Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost) +{ + DeInitStateMachine(phost); + + if(phost->pData != NULL) + { + phost->pActiveClass->pData = NULL; + USBH_LL_Stop(phost); + } + + return USBH_OK; +} + +/** + * @brief DeInitStateMachine + * De-Initialize the Host state machine. + * @param phost: Host Handle + * @retval USBH Status + */ +static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost) +{ + uint32_t i = 0; + + /* Clear Pipes flags*/ + for ( ; i < USBH_MAX_PIPES_NBR; i++) + { + phost->Pipes[i] = 0; + } + + for(i = 0; i< USBH_MAX_DATA_BUFFER; i++) + { + phost->device.Data[i] = 0; + } + + phost->gState = HOST_IDLE; + phost->EnumState = ENUM_IDLE; + phost->RequestState = CMD_SEND; + phost->Timer = 0; + + phost->Control.state = CTRL_SETUP; + phost->Control.pipe_size = USBH_MPS_DEFAULT; + phost->Control.errorcount = 0; + + phost->device.address = USBH_ADDRESS_DEFAULT; + phost->device.speed = USBH_SPEED_FULL; + + return USBH_OK; +} + +/** + * @brief USBH_RegisterClass + * Link class driver to Host Core. + * @param phost : Host Handle + * @param pclass: Class handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_RegisterClass(USBH_HandleTypeDef *phost, USBH_ClassTypeDef *pclass) +{ + USBH_StatusTypeDef status = USBH_OK; + + if(pclass != 0) + { + if(phost->ClassNumber < USBH_MAX_NUM_SUPPORTED_CLASS) + { + /* link the class tgo the USB Host handle */ + phost->pClass[phost->ClassNumber++] = pclass; + status = USBH_OK; + } + else + { + USBH_ErrLog("Max Class Number reached"); + status = USBH_FAIL; + } + } + else + { + USBH_ErrLog("Invalid Class handle"); + status = USBH_FAIL; + } + + return status; +} + +/** + * @brief USBH_SelectInterface + * Select current interface. + * @param phost: Host Handle + * @param interface: Interface number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_SelectInterface(USBH_HandleTypeDef *phost, uint8_t interface) +{ + USBH_StatusTypeDef status = USBH_OK; + + if(interface < phost->device.CfgDesc.bNumInterfaces) + { + phost->device.current_interface = interface; + USBH_UsrLog ("Switching to Interface (#%d)", interface); + USBH_UsrLog ("Class : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass ); + USBH_UsrLog ("SubClass : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass ); + USBH_UsrLog ("Protocol : %xh", phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol ); + } + else + { + USBH_ErrLog ("Cannot Select This Interface."); + status = USBH_FAIL; + } + return status; +} + +/** + * @brief USBH_GetActiveClass + * Return Device Class. + * @param phost: Host Handle + * @param interface: Interface index + * @retval Class Code + */ +uint8_t USBH_GetActiveClass(USBH_HandleTypeDef *phost) +{ + return (phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass); +} +/** + * @brief USBH_FindInterface + * Find the interface index for a specific class. + * @param phost: Host Handle + * @param Class: Class code + * @param SubClass: SubClass code + * @param Protocol: Protocol code + * @retval interface index in the configuration structure + * @note : (1)interface index 0xFF means interface index not found + */ +uint8_t USBH_FindInterface(USBH_HandleTypeDef *phost, uint8_t Class, uint8_t SubClass, uint8_t Protocol) +{ + USBH_InterfaceDescTypeDef *pif ; + USBH_CfgDescTypeDef *pcfg ; + int8_t if_ix = 0; + + pif = (USBH_InterfaceDescTypeDef *)0; + pcfg = &phost->device.CfgDesc; + + if((pif->bInterfaceClass == 0xFF) &&(pif->bInterfaceSubClass == 0xFF) && (pif->bInterfaceProtocol == 0xFF)) + { + return 0xFF; + } + + while (if_ix < USBH_MAX_NUM_INTERFACES) + { + pif = &pcfg->Itf_Desc[if_ix]; + if(((pif->bInterfaceClass == Class) || (Class == 0xFF))&& + ((pif->bInterfaceSubClass == SubClass) || (SubClass == 0xFF))&& + ((pif->bInterfaceProtocol == Protocol) || (Protocol == 0xFF))) + { + return if_ix; + } + if_ix++; + } + return 0xFF; +} + +/** + * @brief USBH_FindInterfaceIndex + * Find the interface index for a specific class interface and alternate setting number. + * @param phost: Host Handle + * @param interface_number: interface number + * @param alt_settings : alaternate setting number + * @retval interface index in the configuration structure + * @note : (1)interface index 0xFF means interface index not found + */ +uint8_t USBH_FindInterfaceIndex(USBH_HandleTypeDef *phost, uint8_t interface_number, uint8_t alt_settings) +{ + USBH_InterfaceDescTypeDef *pif ; + USBH_CfgDescTypeDef *pcfg ; + int8_t if_ix = 0; + + pif = (USBH_InterfaceDescTypeDef *)0; + pcfg = &phost->device.CfgDesc; + + while (if_ix < USBH_MAX_NUM_INTERFACES) + { + pif = &pcfg->Itf_Desc[if_ix]; + if((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings)) + { + return if_ix; + } + if_ix++; + } + return 0xFF; +} + +/** + * @brief USBH_Start + * Start the USB Host Core. + * @param phost: Host Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Start (USBH_HandleTypeDef *phost) +{ + /* Start the low level driver */ + USBH_LL_Start(phost); + + /* Activate VBUS on the port */ + USBH_LL_DriverVBUS (phost, TRUE); + + return USBH_OK; +} + +/** + * @brief USBH_Stop + * Stop the USB Host Core. + * @param phost: Host Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Stop (USBH_HandleTypeDef *phost) +{ + /* Stop and cleanup the low level driver */ + USBH_LL_Stop(phost); + + /* DeActivate VBUS on the port */ + USBH_LL_DriverVBUS (phost, FALSE); + + /* FRee Control Pipes */ + USBH_FreePipe (phost, phost->Control.pipe_in); + USBH_FreePipe (phost, phost->Control.pipe_out); + + return USBH_OK; +} + +/** + * @brief HCD_ReEnumerate + * Perform a new Enumeration phase. + * @param phost: Host Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_ReEnumerate (USBH_HandleTypeDef *phost) +{ + /*Stop Host */ + USBH_Stop(phost); + + /*Device has disconnected, so wait for 200 ms */ + USBH_Delay(200); + + /* Set State machines in default state */ + DeInitStateMachine(phost); + + /* Start again the host */ + USBH_Start(phost); + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); +#endif + return USBH_OK; +} + +/** + * @brief USBH_Process + * Background process of the USB Core. + * @param phost: Host Handle + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) +{ + __IO USBH_StatusTypeDef status = USBH_FAIL; + uint8_t idx = 0; + + switch (phost->gState) + { + case HOST_IDLE : + + if (phost->device.is_connected) + { + /* Wait for 200 ms after connection */ + phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; + USBH_Delay(200); + USBH_LL_ResetPort(phost); +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); +#endif + } + break; + + case HOST_DEV_WAIT_FOR_ATTACHMENT: + break; + + case HOST_DEV_ATTACHED : + + USBH_UsrLog("USB Device Attached"); + + /* Wait for 100 ms after Reset */ + USBH_Delay(100); + + phost->device.speed = USBH_LL_GetSpeed(phost); + + phost->gState = HOST_ENUMERATION; + + phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00); + phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80); + + + /* Open Control pipes */ + USBH_OpenPipe (phost, + phost->Control.pipe_in, + 0x80, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + + /* Open Control pipes */ + USBH_OpenPipe (phost, + phost->Control.pipe_out, + 0x00, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); +#endif + + break; + + case HOST_ENUMERATION: + /* Check for enumeration status */ + if ( USBH_HandleEnum(phost) == USBH_OK) + { + /* The function shall return USBH_OK when full enumeration is complete */ + USBH_UsrLog ("Enumeration done."); + phost->device.current_interface = 0; + if(phost->device.DevDesc.bNumConfigurations == 1) + { + USBH_UsrLog ("This device has only 1 configuration."); + phost->gState = HOST_SET_CONFIGURATION; + + } + else + { + phost->gState = HOST_INPUT; + } + + } + break; + + case HOST_INPUT: + { + /* user callback for end of device basic enumeration */ + if(phost->pUser != NULL) + { + phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION); + phost->gState = HOST_SET_CONFIGURATION; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + } + break; + + case HOST_SET_CONFIGURATION: + /* set configuration */ + if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK) + { + phost->gState = HOST_CHECK_CLASS; + USBH_UsrLog ("Default configuration set."); + + } + + break; + + case HOST_CHECK_CLASS: + + if(phost->ClassNumber == 0) + { + USBH_UsrLog ("No Class has been registered."); + } + else + { + phost->pActiveClass = NULL; + + for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++) + { + if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass) + { + phost->pActiveClass = phost->pClass[idx]; + } + } + + if(phost->pActiveClass != NULL) + { + if(phost->pActiveClass->Init(phost)== USBH_OK) + { + phost->gState = HOST_CLASS_REQUEST; + USBH_UsrLog ("%s class started.", phost->pActiveClass->Name); + + /* Inform user that a class has been activated */ + phost->pUser(phost, HOST_USER_CLASS_SELECTED); + } + else + { + phost->gState = HOST_ABORT_STATE; + USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name); + } + } + else + { + phost->gState = HOST_ABORT_STATE; + USBH_UsrLog ("No registered class for this device."); + } + } + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + break; + + case HOST_CLASS_REQUEST: + /* process class standard contol requests state machine */ + + if(phost->pActiveClass != NULL) + { + status = phost->pActiveClass->Requests(phost); + + if(status == USBH_OK) + { + phost->gState = HOST_CLASS; + } + } + else + { + phost->gState = HOST_ABORT_STATE; + USBH_ErrLog ("Invalid Class Driver."); + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + + break; + case HOST_CLASS: + /* process class state machine */ + if(phost->pActiveClass != NULL) + { + phost->pActiveClass->BgndProcess(phost); + } + break; + + case HOST_DEV_DISCONNECTED : + + DeInitStateMachine(phost); + + /* Re-Initilaize Host for new Enumeration */ + if(phost->pActiveClass != NULL) + { + phost->pActiveClass->DeInit(phost); + phost->pActiveClass = NULL; + } + break; + + case HOST_ABORT_STATE: + default : + break; + } + return USBH_OK; +} + + +/** + * @brief USBH_HandleEnum + * This function includes the complete enumeration process + * @param phost: Host Handle + * @retval USBH_Status + */ +static USBH_StatusTypeDef USBH_HandleEnum (USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef Status = USBH_BUSY; + + switch (phost->EnumState) + { + case ENUM_IDLE: + /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */ + if ( USBH_Get_DevDesc(phost, 8) == USBH_OK) + { + phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize; + + phost->EnumState = ENUM_GET_FULL_DEV_DESC; + + /* modify control channels configuration for MaxPacket size */ + USBH_OpenPipe (phost, + phost->Control.pipe_in, + 0x80, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + + /* Open Control pipes */ + USBH_OpenPipe (phost, + phost->Control.pipe_out, + 0x00, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + + } + break; + + case ENUM_GET_FULL_DEV_DESC: + /* Get FULL Device Desc */ + if ( USBH_Get_DevDesc(phost, USB_DEVICE_DESC_SIZE)== USBH_OK) + { + USBH_UsrLog("PID: %xh", phost->device.DevDesc.idProduct ); + USBH_UsrLog("VID: %xh", phost->device.DevDesc.idVendor ); + + phost->EnumState = ENUM_SET_ADDR; + + } + break; + + case ENUM_SET_ADDR: + /* set address */ + if ( USBH_SetAddress(phost, USBH_DEVICE_ADDRESS) == USBH_OK) + { + USBH_Delay(2); + phost->device.address = USBH_DEVICE_ADDRESS; + + /* user callback for device address assigned */ + USBH_UsrLog("Address (#%d) assigned.", phost->device.address); + phost->EnumState = ENUM_GET_CFG_DESC; + + /* modify control channels to update device address */ + USBH_OpenPipe (phost, + phost->Control.pipe_in, + 0x80, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + + /* Open Control pipes */ + USBH_OpenPipe (phost, + phost->Control.pipe_out, + 0x00, + phost->device.address, + phost->device.speed, + USBH_EP_CONTROL, + phost->Control.pipe_size); + } + break; + + case ENUM_GET_CFG_DESC: + /* get standard configuration descriptor */ + if ( USBH_Get_CfgDesc(phost, + USB_CONFIGURATION_DESC_SIZE) == USBH_OK) + { + phost->EnumState = ENUM_GET_FULL_CFG_DESC; + } + break; + + case ENUM_GET_FULL_CFG_DESC: + /* get FULL config descriptor (config, interface, endpoints) */ + if (USBH_Get_CfgDesc(phost, + phost->device.CfgDesc.wTotalLength) == USBH_OK) + { + phost->EnumState = ENUM_GET_MFC_STRING_DESC; + } + break; + + case ENUM_GET_MFC_STRING_DESC: + if (phost->device.DevDesc.iManufacturer != 0) + { /* Check that Manufacturer String is available */ + + if ( USBH_Get_StringDesc(phost, + phost->device.DevDesc.iManufacturer, + phost->device.Data , + 0xff) == USBH_OK) + { + /* User callback for Manufacturing string */ + USBH_UsrLog("Manufacturer : %s", (char *)phost->device.Data); + phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + } + else + { + USBH_UsrLog("Manufacturer : N/A"); + phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + break; + + case ENUM_GET_PRODUCT_STRING_DESC: + if (phost->device.DevDesc.iProduct != 0) + { /* Check that Product string is available */ + if ( USBH_Get_StringDesc(phost, + phost->device.DevDesc.iProduct, + phost->device.Data, + 0xff) == USBH_OK) + { + /* User callback for Product string */ + USBH_UsrLog("Product : %s", (char *)phost->device.Data); + phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC; + } + } + else + { + USBH_UsrLog("Product : N/A"); + phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + break; + + case ENUM_GET_SERIALNUM_STRING_DESC: + if (phost->device.DevDesc.iSerialNumber != 0) + { /* Check that Serial number string is available */ + if ( USBH_Get_StringDesc(phost, + phost->device.DevDesc.iSerialNumber, + phost->device.Data, + 0xff) == USBH_OK) + { + /* User callback for Serial number string */ + USBH_UsrLog("Serial Number : %s", (char *)phost->device.Data); + Status = USBH_OK; + } + } + else + { + USBH_UsrLog("Serial Number : N/A"); + Status = USBH_OK; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); +#endif + } + break; + + default: + break; + } + return Status; +} + +/** + * @brief USBH_LL_SetTimer + * Set the initial Host Timer tick + * @param phost: Host Handle + * @retval None + */ +void USBH_LL_SetTimer (USBH_HandleTypeDef *phost, uint32_t time) +{ + phost->Timer = time; +} +/** + * @brief USBH_LL_IncTimer + * Increment Host Timer tick + * @param phost: Host Handle + * @retval None + */ +void USBH_LL_IncTimer (USBH_HandleTypeDef *phost) +{ + phost->Timer ++; + USBH_HandleSof(phost); +} + +/** + * @brief USBH_HandleSof + * Call SOF process + * @param phost: Host Handle + * @retval None + */ +void USBH_HandleSof (USBH_HandleTypeDef *phost) +{ + if((phost->gState == HOST_CLASS)&&(phost->pActiveClass != NULL)) + { + phost->pActiveClass->SOFProcess(phost); + } +} +/** + * @brief USBH_LL_Connect + * Handle USB Host connexion event + * @param phost: Host Handle + * @retval USBH_Status + */ +USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost) +{ + if(phost->gState == HOST_IDLE ) + { + phost->device.is_connected = 1; + phost->gState = HOST_IDLE ; + + if(phost->pUser != NULL) + { + phost->pUser(phost, HOST_USER_CONNECTION); + } + } + else if(phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT ) + { + phost->gState = HOST_DEV_ATTACHED ; + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); +#endif + + return USBH_OK; +} + +/** + * @brief USBH_LL_Disconnect + * Handle USB Host disconnexion event + * @param phost: Host Handle + * @retval USBH_Status + */ +USBH_StatusTypeDef USBH_LL_Disconnect (USBH_HandleTypeDef *phost) +{ + /*Stop Host */ + USBH_LL_Stop(phost); + + /* FRee Control Pipes */ + USBH_FreePipe (phost, phost->Control.pipe_in); + USBH_FreePipe (phost, phost->Control.pipe_out); + + phost->device.is_connected = 0; + + if(phost->pUser != NULL) + { + phost->pUser(phost, HOST_USER_DISCONNECTION); + } + USBH_UsrLog("USB Device disconnected"); + + /* Start the low level driver */ + USBH_LL_Start(phost); + + phost->gState = HOST_DEV_DISCONNECTED; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); +#endif + + return USBH_OK; +} + + +#if (USBH_USE_OS == 1) +/** + * @brief USB Host Thread task + * @param pvParameters not used + * @retval None + */ +static void USBH_Process_OS(void const * argument) +{ + osEvent event; + + for(;;) + { + event = osMessageGet(((USBH_HandleTypeDef *)argument)->os_event, osWaitForever ); + + if( event.status == osEventMessage ) + { + USBH_Process((USBH_HandleTypeDef *)argument); + } + } +} + +/** +* @brief USBH_LL_NotifyURBChange +* Notify URB state Change +* @param phost: Host handle +* @retval USBH Status +*/ +USBH_StatusTypeDef USBH_LL_NotifyURBChange (USBH_HandleTypeDef *phost) +{ + osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); + return USBH_OK; +} +#endif +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c new file mode 100755 index 0000000..58bc34d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ctlreq.c @@ -0,0 +1,881 @@ +/** + ****************************************************************************** + * @file usbh_ctlreq.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements the control requests for device enumeration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ + +#include "usbh_ctlreq.h" + +/** @addtogroup USBH_LIB +* @{ +*/ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_CTLREQ +* @brief This file implements the standard requests for device enumeration +* @{ +*/ + + +/** @defgroup USBH_CTLREQ_Private_Defines +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_CTLREQ_Private_TypesDefinitions +* @{ +*/ +/** +* @} +*/ + + + +/** @defgroup USBH_CTLREQ_Private_Macros +* @{ +*/ +/** +* @} +*/ + + +/** @defgroup USBH_CTLREQ_Private_Variables +* @{ +*/ +/** +* @} +*/ + +/** @defgroup USBH_CTLREQ_Private_FunctionPrototypes +* @{ +*/ +static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost); + +static void USBH_ParseDevDesc (USBH_DevDescTypeDef* , uint8_t *buf, uint16_t length); + +static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc, + uint8_t *buf, + uint16_t length); + + +static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf); +static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length); +static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf); + + +/** +* @} +*/ + + +/** @defgroup USBH_CTLREQ_Private_Functions +* @{ +*/ + + +/** + * @brief USBH_Get_DevDesc + * Issue Get Device Descriptor command to the device. Once the response + * received, it parses the device descriptor and updates the status. + * @param phost: Host Handle + * @param length: Length of the descriptor + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length) +{ + USBH_StatusTypeDef status; + + if((status = USBH_GetDescriptor(phost, + USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, + USB_DESC_DEVICE, + phost->device.Data, + length)) == USBH_OK) + { + /* Commands successfully sent and Response Received */ + USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data, length); + } + return status; +} + +/** + * @brief USBH_Get_CfgDesc + * Issues Configuration Descriptor to the device. Once the response + * received, it parses the configuartion descriptor and updates the + * status. + * @param phost: Host Handle + * @param length: Length of the descriptor + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost, + uint16_t length) + +{ + USBH_StatusTypeDef status; + uint8_t *pData; +#if (USBH_KEEP_CFG_DESCRIPTOR == 1) + pData = phost->device.CfgDesc_Raw; +#else + pData = phost->device.Data; +#endif + if((status = USBH_GetDescriptor(phost, + USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, + USB_DESC_CONFIGURATION, + pData, + length)) == USBH_OK) + { + + /* Commands successfully sent and Response Received */ + USBH_ParseCfgDesc (&phost->device.CfgDesc, + pData, + length); + + } + return status; +} + + +/** + * @brief USBH_Get_StringDesc + * Issues string Descriptor command to the device. Once the response + * received, it parses the string descriptor and updates the status. + * @param phost: Host Handle + * @param string_index: String index for the descriptor + * @param buff: Buffer address for the descriptor + * @param length: Length of the descriptor + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost, + uint8_t string_index, + uint8_t *buff, + uint16_t length) +{ + USBH_StatusTypeDef status; + if((status = USBH_GetDescriptor(phost, + USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, + USB_DESC_STRING | string_index, + phost->device.Data, + length)) == USBH_OK) + { + /* Commands successfully sent and Response Received */ + USBH_ParseStringDesc(phost->device.Data,buff, length); + } + return status; +} + +/** + * @brief USBH_GetDescriptor + * Issues Descriptor command to the device. Once the response received, + * it parses the descriptor and updates the status. + * @param phost: Host Handle + * @param req_type: Descriptor type + * @param value_idx: wValue for the GetDescriptr request + * @param buff: Buffer to store the descriptor + * @param length: Length of the descriptor + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost, + uint8_t req_type, + uint16_t value_idx, + uint8_t* buff, + uint16_t length ) +{ + if(phost->RequestState == CMD_SEND) + { + phost->Control.setup.b.bmRequestType = USB_D2H | req_type; + phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; + phost->Control.setup.b.wValue.w = value_idx; + + if ((value_idx & 0xff00) == USB_DESC_STRING) + { + phost->Control.setup.b.wIndex.w = 0x0409; + } + else + { + phost->Control.setup.b.wIndex.w = 0; + } + phost->Control.setup.b.wLength.w = length; + } + return USBH_CtlReq(phost, buff , length ); +} + +/** + * @brief USBH_SetAddress + * This command sets the address to the connected device + * @param phost: Host Handle + * @param DeviceAddress: Device address to assign + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost, + uint8_t DeviceAddress) +{ + if(phost->RequestState == CMD_SEND) + { + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \ + USB_REQ_TYPE_STANDARD; + + phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS; + + phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 0; + } + return USBH_CtlReq(phost, 0 , 0 ); +} + +/** + * @brief USBH_SetCfg + * The command sets the configuration value to the connected device + * @param phost: Host Handle + * @param cfg_idx: Configuration value + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, + uint16_t cfg_idx) +{ + if(phost->RequestState == CMD_SEND) + { + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\ + USB_REQ_TYPE_STANDARD; + phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION; + phost->Control.setup.b.wValue.w = cfg_idx; + phost->Control.setup.b.wIndex.w = 0; + phost->Control.setup.b.wLength.w = 0; + } + + return USBH_CtlReq(phost, 0 , 0 ); +} + +/** + * @brief USBH_SetInterface + * The command sets the Interface value to the connected device + * @param phost: Host Handle + * @param altSetting: Interface value + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, + uint8_t ep_num, uint8_t altSetting) +{ + + if(phost->RequestState == CMD_SEND) + { + phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ + USB_REQ_TYPE_STANDARD; + + phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE; + phost->Control.setup.b.wValue.w = altSetting; + phost->Control.setup.b.wIndex.w = ep_num; + phost->Control.setup.b.wLength.w = 0; + } + return USBH_CtlReq(phost, 0 , 0 ); +} + +/** + * @brief USBH_ClrFeature + * This request is used to clear or disable a specific feature. + * @param phost: Host Handle + * @param ep_num: endpoint number + * @param hc_num: Host channel number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, + uint8_t ep_num) +{ + if(phost->RequestState == CMD_SEND) + { + phost->Control.setup.b.bmRequestType = USB_H2D | + USB_REQ_RECIPIENT_ENDPOINT | + USB_REQ_TYPE_STANDARD; + + phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE; + phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT; + phost->Control.setup.b.wIndex.w = ep_num; + phost->Control.setup.b.wLength.w = 0; + } + return USBH_CtlReq(phost, 0 , 0 ); +} + +/** + * @brief USBH_ParseDevDesc + * This function Parses the device descriptor + * @param dev_desc: device_descriptor destinaton address + * @param buf: Buffer where the source descriptor is available + * @param length: Length of the descriptor + * @retval None + */ +static void USBH_ParseDevDesc (USBH_DevDescTypeDef* dev_desc, + uint8_t *buf, + uint16_t length) +{ + dev_desc->bLength = *(uint8_t *) (buf + 0); + dev_desc->bDescriptorType = *(uint8_t *) (buf + 1); + dev_desc->bcdUSB = LE16 (buf + 2); + dev_desc->bDeviceClass = *(uint8_t *) (buf + 4); + dev_desc->bDeviceSubClass = *(uint8_t *) (buf + 5); + dev_desc->bDeviceProtocol = *(uint8_t *) (buf + 6); + dev_desc->bMaxPacketSize = *(uint8_t *) (buf + 7); + + if (length > 8) + { /* For 1st time after device connection, Host may issue only 8 bytes for + Device Descriptor Length */ + dev_desc->idVendor = LE16 (buf + 8); + dev_desc->idProduct = LE16 (buf + 10); + dev_desc->bcdDevice = LE16 (buf + 12); + dev_desc->iManufacturer = *(uint8_t *) (buf + 14); + dev_desc->iProduct = *(uint8_t *) (buf + 15); + dev_desc->iSerialNumber = *(uint8_t *) (buf + 16); + dev_desc->bNumConfigurations = *(uint8_t *) (buf + 17); + } +} + +/** + * @brief USBH_ParseCfgDesc + * This function Parses the configuration descriptor + * @param cfg_desc: Configuration Descriptor address + * @param buf: Buffer where the source descriptor is available + * @param length: Length of the descriptor + * @retval None + */ +static void USBH_ParseCfgDesc (USBH_CfgDescTypeDef* cfg_desc, + uint8_t *buf, + uint16_t length) +{ + USBH_InterfaceDescTypeDef *pif ; + USBH_EpDescTypeDef *pep; + USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf; + uint16_t ptr; + int8_t if_ix = 0; + int8_t ep_ix = 0; + + pdesc = (USBH_DescHeader_t *)buf; + + /* Parse configuration descriptor */ + cfg_desc->bLength = *(uint8_t *) (buf + 0); + cfg_desc->bDescriptorType = *(uint8_t *) (buf + 1); + cfg_desc->wTotalLength = LE16 (buf + 2); + cfg_desc->bNumInterfaces = *(uint8_t *) (buf + 4); + cfg_desc->bConfigurationValue = *(uint8_t *) (buf + 5); + cfg_desc->iConfiguration = *(uint8_t *) (buf + 6); + cfg_desc->bmAttributes = *(uint8_t *) (buf + 7); + cfg_desc->bMaxPower = *(uint8_t *) (buf + 8); + + + if (length > USB_CONFIGURATION_DESC_SIZE) + { + ptr = USB_LEN_CFG_DESC; + pif = (USBH_InterfaceDescTypeDef *)0; + + + while ((if_ix < USBH_MAX_NUM_INTERFACES ) && (ptr < cfg_desc->wTotalLength)) + { + pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr); + if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE) + { + pif = &cfg_desc->Itf_Desc[if_ix]; + USBH_ParseInterfaceDesc (pif, (uint8_t *)pdesc); + + ep_ix = 0; + pep = (USBH_EpDescTypeDef *)0; + while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength)) + { + pdesc = USBH_GetNextDesc((void* )pdesc, &ptr); + if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT) + { + pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix]; + USBH_ParseEPDesc (pep, (uint8_t *)pdesc); + ep_ix++; + } + } + if_ix++; + } + } + } +} + + + +/** + * @brief USBH_ParseInterfaceDesc + * This function Parses the interface descriptor + * @param if_descriptor : Interface descriptor destination + * @param buf: Buffer where the descriptor data is available + * @retval None + */ +static void USBH_ParseInterfaceDesc (USBH_InterfaceDescTypeDef *if_descriptor, + uint8_t *buf) +{ + if_descriptor->bLength = *(uint8_t *) (buf + 0); + if_descriptor->bDescriptorType = *(uint8_t *) (buf + 1); + if_descriptor->bInterfaceNumber = *(uint8_t *) (buf + 2); + if_descriptor->bAlternateSetting = *(uint8_t *) (buf + 3); + if_descriptor->bNumEndpoints = *(uint8_t *) (buf + 4); + if_descriptor->bInterfaceClass = *(uint8_t *) (buf + 5); + if_descriptor->bInterfaceSubClass = *(uint8_t *) (buf + 6); + if_descriptor->bInterfaceProtocol = *(uint8_t *) (buf + 7); + if_descriptor->iInterface = *(uint8_t *) (buf + 8); +} + +/** + * @brief USBH_ParseEPDesc + * This function Parses the endpoint descriptor + * @param ep_descriptor: Endpoint descriptor destination address + * @param buf: Buffer where the parsed descriptor stored + * @retval None + */ +static void USBH_ParseEPDesc (USBH_EpDescTypeDef *ep_descriptor, + uint8_t *buf) +{ + + ep_descriptor->bLength = *(uint8_t *) (buf + 0); + ep_descriptor->bDescriptorType = *(uint8_t *) (buf + 1); + ep_descriptor->bEndpointAddress = *(uint8_t *) (buf + 2); + ep_descriptor->bmAttributes = *(uint8_t *) (buf + 3); + ep_descriptor->wMaxPacketSize = LE16 (buf + 4); + ep_descriptor->bInterval = *(uint8_t *) (buf + 6); +} + +/** + * @brief USBH_ParseStringDesc + * This function Parses the string descriptor + * @param psrc: Source pointer containing the descriptor data + * @param pdest: Destination address pointer + * @param length: Length of the descriptor + * @retval None + */ +static void USBH_ParseStringDesc (uint8_t* psrc, + uint8_t* pdest, + uint16_t length) +{ + uint16_t strlength; + uint16_t idx; + + /* The UNICODE string descriptor is not NULL-terminated. The string length is + computed by substracting two from the value of the first byte of the descriptor. + */ + + /* Check which is lower size, the Size of string or the length of bytes read + from the device */ + + if ( psrc[1] == USB_DESC_TYPE_STRING) + { /* Make sure the Descriptor is String Type */ + + /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */ + strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length); + psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */ + + for (idx = 0; idx < strlength; idx+=2 ) + {/* Copy Only the string and ignore the UNICODE ID, hence add the src */ + *pdest = psrc[idx]; + pdest++; + } + *pdest = 0; /* mark end of string */ + } +} + +/** + * @brief USBH_GetNextDesc + * This function return the next descriptor header + * @param buf: Buffer where the cfg descriptor is available + * @param ptr: data popinter inside the cfg descriptor + * @retval next header + */ +USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, uint16_t *ptr) +{ + USBH_DescHeader_t *pnext; + + *ptr += ((USBH_DescHeader_t *)pbuf)->bLength; + pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \ + ((USBH_DescHeader_t *)pbuf)->bLength); + + return(pnext); +} + + +/** + * @brief USBH_CtlReq + * USBH_CtlReq sends a control request and provide the status after + * completion of the request + * @param phost: Host Handle + * @param req: Setup Request Structure + * @param buff: data buffer address to store the response + * @param length: length of the response + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_CtlReq (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length) +{ + USBH_StatusTypeDef status; + status = USBH_BUSY; + + switch (phost->RequestState) + { + case CMD_SEND: + /* Start a SETUP transfer */ + phost->Control.buff = buff; + phost->Control.length = length; + phost->Control.state = CTRL_SETUP; + phost->RequestState = CMD_WAIT; + status = USBH_BUSY; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + break; + + case CMD_WAIT: + status = USBH_HandleControl(phost); + if (status == USBH_OK) + { + /* Commands successfully sent and Response Received */ + phost->RequestState = CMD_SEND; + phost->Control.state =CTRL_IDLE; + status = USBH_OK; + } + else if (status == USBH_FAIL) + { + /* Failure Mode */ + phost->RequestState = CMD_SEND; + status = USBH_FAIL; + } + break; + + default: + break; + } + return status; +} + +/** + * @brief USBH_HandleControl + * Handles the USB control transfer state machine + * @param phost: Host Handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost) +{ + uint8_t direction; + USBH_StatusTypeDef status = USBH_BUSY; + USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; + + switch (phost->Control.state) + { + case CTRL_SETUP: + /* send a SETUP packet */ + USBH_CtlSendSetup (phost, + (uint8_t *)phost->Control.setup.d8 , + phost->Control.pipe_out); + + phost->Control.state = CTRL_SETUP_WAIT; + break; + + case CTRL_SETUP_WAIT: + + URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out); + /* case SETUP packet sent successfully */ + if(URB_Status == USBH_URB_DONE) + { + direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK); + + /* check if there is a data stage */ + if (phost->Control.setup.b.wLength.w != 0 ) + { + if (direction == USB_D2H) + { + /* Data Direction is IN */ + phost->Control.state = CTRL_DATA_IN; + } + else + { + /* Data Direction is OUT */ + phost->Control.state = CTRL_DATA_OUT; + } + } + /* No DATA stage */ + else + { + /* If there is No Data Transfer Stage */ + if (direction == USB_D2H) + { + /* Data Direction is IN */ + phost->Control.state = CTRL_STATUS_OUT; + } + else + { + /* Data Direction is OUT */ + phost->Control.state = CTRL_STATUS_IN; + } + } +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_ERROR) + { + phost->Control.state = CTRL_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + break; + + case CTRL_DATA_IN: + /* Issue an IN token */ + phost->Control.timer = phost->Timer; + USBH_CtlReceiveData(phost, + phost->Control.buff, + phost->Control.length, + phost->Control.pipe_in); + + phost->Control.state = CTRL_DATA_IN_WAIT; + break; + + case CTRL_DATA_IN_WAIT: + + URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); + + /* check is DATA packet transfered successfully */ + if (URB_Status == USBH_URB_DONE) + { + phost->Control.state = CTRL_STATUS_OUT; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + + /* manage error cases*/ + if (URB_Status == USBH_URB_STALL) + { + /* In stall case, return to previous machine state*/ + status = USBH_NOT_SUPPORTED; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if (URB_Status == USBH_URB_ERROR) + { + /* Device error */ + phost->Control.state = CTRL_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + break; + + case CTRL_DATA_OUT: + + USBH_CtlSendData (phost, + phost->Control.buff, + phost->Control.length , + phost->Control.pipe_out, + 1); + phost->Control.timer = phost->Timer; + phost->Control.state = CTRL_DATA_OUT_WAIT; + break; + + case CTRL_DATA_OUT_WAIT: + + URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); + + if (URB_Status == USBH_URB_DONE) + { /* If the Setup Pkt is sent successful, then change the state */ + phost->Control.state = CTRL_STATUS_IN; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + + /* handle error cases */ + else if (URB_Status == USBH_URB_STALL) + { + /* In stall case, return to previous machine state*/ + phost->Control.state = CTRL_STALLED; + status = USBH_NOT_SUPPORTED; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if (URB_Status == USBH_URB_NOTREADY) + { + /* Nack received from device */ + phost->Control.state = CTRL_DATA_OUT; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if (URB_Status == USBH_URB_ERROR) + { + /* device error */ + phost->Control.state = CTRL_ERROR; + status = USBH_FAIL; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + break; + + + case CTRL_STATUS_IN: + /* Send 0 bytes out packet */ + USBH_CtlReceiveData (phost, + 0, + 0, + phost->Control.pipe_in); + phost->Control.timer = phost->Timer; + phost->Control.state = CTRL_STATUS_IN_WAIT; + + break; + + case CTRL_STATUS_IN_WAIT: + + URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in); + + if ( URB_Status == USBH_URB_DONE) + { /* Control transfers completed, Exit the State Machine */ + phost->Control.state = CTRL_COMPLETE; + status = USBH_OK; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + + else if (URB_Status == USBH_URB_ERROR) + { + phost->Control.state = CTRL_ERROR; +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if(URB_Status == USBH_URB_STALL) + { + /* Control transfers completed, Exit the State Machine */ + status = USBH_NOT_SUPPORTED; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + break; + + case CTRL_STATUS_OUT: + USBH_CtlSendData (phost, + 0, + 0, + phost->Control.pipe_out, + 1); + phost->Control.timer = phost->Timer; + phost->Control.state = CTRL_STATUS_OUT_WAIT; + break; + + case CTRL_STATUS_OUT_WAIT: + + URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out); + if (URB_Status == USBH_URB_DONE) + { + status = USBH_OK; + phost->Control.state = CTRL_COMPLETE; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if (URB_Status == USBH_URB_NOTREADY) + { + phost->Control.state = CTRL_STATUS_OUT; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + else if (URB_Status == USBH_URB_ERROR) + { + phost->Control.state = CTRL_ERROR; + +#if (USBH_USE_OS == 1) + osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0); +#endif + } + break; + + case CTRL_ERROR: + /* + After a halt condition is encountered or an error is detected by the + host, a control endpoint is allowed to recover by accepting the next Setup + PID; i.e., recovery actions via some other pipe are not required for control + endpoints. For the Default Control Pipe, a device reset will ultimately be + required to clear the halt or error condition if the next Setup PID is not + accepted. + */ + if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT) + { + /* try to recover control */ + USBH_LL_Stop(phost); + + /* Do the transmission again, starting from SETUP Packet */ + phost->Control.state = CTRL_SETUP; + phost->RequestState = CMD_SEND; + } + else + { + phost->Control.errorcount = 0; + USBH_ErrLog("Control error"); + status = USBH_FAIL; + + } + break; + + default: + break; + } + return status; +} + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ioreq.c b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ioreq.c new file mode 100755 index 0000000..2800203 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_ioreq.c @@ -0,0 +1,358 @@ +/** + ****************************************************************************** + * @file usbh_ioreq.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file handles the issuing of the USB transactions + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ + +#include "usbh_ioreq.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_IOREQ + * @brief This file handles the standard protocol processing (USB v2.0) + * @{ + */ + + +/** @defgroup USBH_IOREQ_Private_Defines + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_IOREQ_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + + +/** @defgroup USBH_IOREQ_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_IOREQ_Private_Variables + * @{ + */ +/** + * @} + */ +/** @defgroup USBH_IOREQ_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_IOREQ_Private_Functions + * @{ + */ + + + +/** + * @brief USBH_CtlSendSetup + * Sends the Setup Packet to the Device + * @param phost: Host Handle + * @param buff: Buffer pointer from which the Data will be send to Device + * @param pipe_num: Pipe Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_CtlSendSetup (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t pipe_num) +{ + + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 0, /* Direction : OUT */ + USBH_EP_CONTROL, /* EP type */ + USBH_PID_SETUP, /* Type setup */ + buff, /* data buffer */ + USBH_SETUP_PKT_SIZE, /* data length */ + 0); + return USBH_OK; +} + + +/** + * @brief USBH_CtlSendData + * Sends a data Packet to the Device + * @param phost: Host Handle + * @param buff: Buffer pointer from which the Data will be sent to Device + * @param length: Length of the data to be sent + * @param pipe_num: Pipe Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_CtlSendData (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t pipe_num, + uint8_t do_ping ) +{ + if(phost->device.speed != USBH_SPEED_HIGH) + { + do_ping = 0; + } + + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 0, /* Direction : OUT */ + USBH_EP_CONTROL, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + do_ping); /* do ping (HS Only)*/ + + return USBH_OK; +} + + +/** + * @brief USBH_CtlReceiveData + * Receives the Device Response to the Setup Packet + * @param phost: Host Handle + * @param buff: Buffer pointer in which the response needs to be copied + * @param length: Length of the data to be received + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_CtlReceiveData(USBH_HandleTypeDef *phost, + uint8_t* buff, + uint16_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 1, /* Direction : IN */ + USBH_EP_CONTROL, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + return USBH_OK; + +} + + +/** + * @brief USBH_BulkSendData + * Sends the Bulk Packet to the device + * @param phost: Host Handle + * @param buff: Buffer pointer from which the Data will be sent to Device + * @param length: Length of the data to be sent + * @param pipe_num: Pipe Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_BulkSendData (USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t pipe_num, + uint8_t do_ping ) +{ + if(phost->device.speed != USBH_SPEED_HIGH) + { + do_ping = 0; + } + + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 0, /* Direction : IN */ + USBH_EP_BULK, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + do_ping); /* do ping (HS Only)*/ + return USBH_OK; +} + + +/** + * @brief USBH_BulkReceiveData + * Receives IN bulk packet from device + * @param phost: Host Handle + * @param buff: Buffer pointer in which the received data packet to be copied + * @param length: Length of the data to be received + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_BulkReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint16_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 1, /* Direction : IN */ + USBH_EP_BULK, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + return USBH_OK; +} + + +/** + * @brief USBH_InterruptReceiveData + * Receives the Device Response to the Interrupt IN token + * @param phost: Host Handle + * @param buff: Buffer pointer in which the response needs to be copied + * @param length: Length of the data to be received + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_InterruptReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 1, /* Direction : IN */ + USBH_EP_INTERRUPT, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + + return USBH_OK; +} + +/** + * @brief USBH_InterruptSendData + * Sends the data on Interrupt OUT Endpoint + * @param phost: Host Handle + * @param buff: Buffer pointer from where the data needs to be copied + * @param length: Length of the data to be sent + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_InterruptSendData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint8_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 0, /* Direction : OUT */ + USBH_EP_INTERRUPT, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + + return USBH_OK; +} + +/** + * @brief USBH_IsocReceiveData + * Receives the Device Response to the Isochronous IN token + * @param phost: Host Handle + * @param buff: Buffer pointer in which the response needs to be copied + * @param length: Length of the data to be received + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_IsocReceiveData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint32_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 1, /* Direction : IN */ + USBH_EP_ISO, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + + + return USBH_OK; +} + +/** + * @brief USBH_IsocSendData + * Sends the data on Isochronous OUT Endpoint + * @param phost: Host Handle + * @param buff: Buffer pointer from where the data needs to be copied + * @param length: Length of the data to be sent + * @param pipe_num: Pipe Number + * @retval USBH Status. + */ +USBH_StatusTypeDef USBH_IsocSendData(USBH_HandleTypeDef *phost, + uint8_t *buff, + uint32_t length, + uint8_t pipe_num) +{ + USBH_LL_SubmitURB (phost, /* Driver handle */ + pipe_num, /* Pipe index */ + 0, /* Direction : OUT */ + USBH_EP_ISO, /* EP type */ + USBH_PID_DATA, /* Type Data */ + buff, /* data buffer */ + length, /* data length */ + 0); + + return USBH_OK; +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_pipes.c b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_pipes.c new file mode 100755 index 0000000..9dcc4c5 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usbhost/Core/Src/usbh_pipes.c @@ -0,0 +1,204 @@ +/** + ****************************************************************************** + * @file usbh_pipes.c + * @author MCD Application Team + * @version V3.0.0 + * @date 18-February-2014 + * @brief This file implements functions for opening and closing Pipes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_pipes.h" + +/** @addtogroup USBH_LIB + * @{ + */ + +/** @addtogroup USBH_LIB_CORE +* @{ +*/ + +/** @defgroup USBH_PIPES + * @brief This file includes opening and closing Pipes + * @{ + */ + +/** @defgroup USBH_PIPES_Private_Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup USBH_PIPES_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_PIPES_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup USBH_PIPES_Private_Variables + * @{ + */ + +/** + * @} + */ + + +/** @defgroup USBH_PIPES_Private_Functions + * @{ + */ +static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost); + + +/** + * @brief USBH_Open_Pipe + * Open a pipe + * @param phost: Host Handle + * @param pipe_num: Pipe Number + * @param dev_address: USB Device address allocated to attached device + * @param speed : USB device speed (Full/Low) + * @param ep_type: end point type (Bulk/int/ctl) + * @param mps: max pkt size + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_OpenPipe (USBH_HandleTypeDef *phost, + uint8_t pipe_num, + uint8_t epnum, + uint8_t dev_address, + uint8_t speed, + uint8_t ep_type, + uint16_t mps) +{ + + USBH_LL_OpenPipe(phost, + pipe_num, + epnum, + dev_address, + speed, + ep_type, + mps); + + return USBH_OK; + +} + +/** + * @brief USBH_ClosePipe + * Close a pipe + * @param phost: Host Handle + * @param pipe_num: Pipe Number + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_ClosePipe (USBH_HandleTypeDef *phost, + uint8_t pipe_num) +{ + + USBH_LL_ClosePipe(phost, pipe_num); + + return USBH_OK; + +} + +/** + * @brief USBH_Alloc_Pipe + * Allocate a new Pipe + * @param phost: Host Handle + * @param ep_addr: End point for which the Pipe to be allocated + * @retval Pipe number + */ +uint8_t USBH_AllocPipe (USBH_HandleTypeDef *phost, uint8_t ep_addr) +{ + uint16_t pipe; + + pipe = USBH_GetFreePipe(phost); + + if (pipe != 0xFFFF) + { + phost->Pipes[pipe] = 0x8000 | ep_addr; + } + return pipe; +} + +/** + * @brief USBH_Free_Pipe + * Free the USB Pipe + * @param phost: Host Handle + * @param idx: Pipe number to be freed + * @retval USBH Status + */ +USBH_StatusTypeDef USBH_FreePipe (USBH_HandleTypeDef *phost, uint8_t idx) +{ + if(idx < 11) + { + phost->Pipes[idx] &= 0x7FFF; + } + return USBH_OK; +} + +/** + * @brief USBH_GetFreePipe + * @param phost: Host Handle + * Get a free Pipe number for allocation to a device endpoint + * @retval idx: Free Pipe number + */ +static uint16_t USBH_GetFreePipe (USBH_HandleTypeDef *phost) +{ + uint8_t idx = 0; + + for (idx = 0 ; idx < 11 ; idx++) + { + if ((phost->Pipes[idx] & 0x8000) == 0) + { + return idx; + } + } + return 0xFFFF; +} +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + diff --git a/src/openmv/src/micropython/ports/stm32/usrsw.c b/src/openmv/src/micropython/ports/stm32/usrsw.c new file mode 100755 index 0000000..4519f80 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usrsw.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "extint.h" +#include "pin.h" +#include "usrsw.h" + +#if MICROPY_HW_HAS_SWITCH + +/// \moduleref pyb +/// \class Switch - switch object +/// +/// A Switch object is used to control a push-button switch. +/// +/// Usage: +/// +/// sw = pyb.Switch() # create a switch object +/// sw() # get state (True if pressed, False otherwise) +/// sw.callback(f) # register a callback to be called when the +/// # switch is pressed down +/// sw.callback(None) # remove the callback +/// +/// Example: +/// +/// pyb.Switch().callback(lambda: pyb.LED(1).toggle()) + +// this function inits the switch GPIO so that it can be used +void switch_init0(void) { + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); +} + +int switch_get(void) { + int val = ((MICROPY_HW_USRSW_PIN->gpio->IDR & MICROPY_HW_USRSW_PIN->pin_mask) != 0); + return val == MICROPY_HW_USRSW_PRESSED; +} + +/******************************************************************************/ +// MicroPython bindings + +typedef struct _pyb_switch_obj_t { + mp_obj_base_t base; +} pyb_switch_obj_t; + +STATIC const pyb_switch_obj_t pyb_switch_obj = {{&pyb_switch_type}}; + +void pyb_switch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_print_str(print, "Switch()"); +} + +/// \classmethod \constructor() +/// Create and return a switch object. +STATIC mp_obj_t pyb_switch_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // No need to clear the callback member: if it's already been set and registered + // with extint then we don't want to reset that behaviour. If it hasn't been set, + // then no extint will be called until it is set via the callback method. + + // return static switch object + return MP_OBJ_FROM_PTR(&pyb_switch_obj); +} + +/// \method \call() +/// Return the switch state: `True` if pressed down, `False` otherwise. +mp_obj_t pyb_switch_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // get switch state + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return switch_get() ? mp_const_true : mp_const_false; +} + +mp_obj_t pyb_switch_value(mp_obj_t self_in) { + (void)self_in; + return mp_obj_new_bool(switch_get()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_switch_value_obj, pyb_switch_value); + +STATIC mp_obj_t switch_callback(mp_obj_t line) { + if (MP_STATE_PORT(pyb_switch_callback) != mp_const_none) { + mp_call_function_0(MP_STATE_PORT(pyb_switch_callback)); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(switch_callback_obj, switch_callback); + +/// \method callback(fun) +/// Register the given function to be called when the switch is pressed down. +/// If `fun` is `None`, then it disables the callback. +mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) { + MP_STATE_PORT(pyb_switch_callback) = callback; + // Init the EXTI each time this function is called, since the EXTI + // may have been disabled by an exception in the interrupt, or the + // user disabling the line explicitly. + extint_register(MP_OBJ_FROM_PTR(MICROPY_HW_USRSW_PIN), + MICROPY_HW_USRSW_EXTI_MODE, + MICROPY_HW_USRSW_PULL, + callback == mp_const_none ? mp_const_none : MP_OBJ_FROM_PTR(&switch_callback_obj), + true); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_switch_callback_obj, pyb_switch_callback); + +STATIC const mp_rom_map_elem_t pyb_switch_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_switch_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_switch_callback_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_switch_locals_dict, pyb_switch_locals_dict_table); + +const mp_obj_type_t pyb_switch_type = { + { &mp_type_type }, + .name = MP_QSTR_Switch, + .print = pyb_switch_print, + .make_new = pyb_switch_make_new, + .call = pyb_switch_call, + .locals_dict = (mp_obj_dict_t*)&pyb_switch_locals_dict, +}; + +#endif // MICROPY_HW_HAS_SWITCH diff --git a/src/openmv/src/micropython/ports/stm32/usrsw.h b/src/openmv/src/micropython/ports/stm32/usrsw.h new file mode 100755 index 0000000..a8a087d --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/usrsw.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_USRSW_H +#define MICROPY_INCLUDED_STM32_USRSW_H + +void switch_init0(void); +int switch_get(void); + +extern const mp_obj_type_t pyb_switch_type; + +#endif // MICROPY_INCLUDED_STM32_USRSW_H diff --git a/src/openmv/src/micropython/ports/stm32/wdt.c b/src/openmv/src/micropython/ports/stm32/wdt.c new file mode 100755 index 0000000..0759ed8 --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/wdt.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "wdt.h" + +#if defined(STM32H7) +#define IWDG (IWDG1) +#endif + +typedef struct _pyb_wdt_obj_t { + mp_obj_base_t base; +} pyb_wdt_obj_t; + +STATIC pyb_wdt_obj_t pyb_wdt = {{&pyb_wdt_type}}; + +STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse arguments + enum { ARG_id, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t id = args[ARG_id].u_int; + if (id != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "WDT(%d) doesn't exist", id)); + } + + // timeout is in milliseconds + mp_int_t timeout = args[ARG_timeout].u_int; + + // compute prescaler + uint32_t prescaler; + for (prescaler = 0; prescaler < 6 && timeout >= 512; ++prescaler, timeout /= 2) { + } + + // convert milliseconds to ticks + timeout *= 8; // 32kHz / 4 = 8 ticks per millisecond (approx) + if (timeout <= 0) { + mp_raise_ValueError("WDT timeout too short"); + } else if (timeout > 0xfff) { + mp_raise_ValueError("WDT timeout too long"); + } + timeout -= 1; + + // set the reload register + while (IWDG->SR & 2) { + } + IWDG->KR = 0x5555; + IWDG->RLR = timeout; + + // set the prescaler + while (IWDG->SR & 1) { + } + IWDG->KR = 0x5555; + IWDG->PR = prescaler; + + // start the watch dog + IWDG->KR = 0xcccc; + + return MP_OBJ_FROM_PTR(&pyb_wdt); +} + +STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) { + (void)self_in; + IWDG->KR = 0xaaaa; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed); + +STATIC const mp_rom_map_elem_t pyb_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&pyb_wdt_feed_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_wdt_locals_dict, pyb_wdt_locals_dict_table); + +const mp_obj_type_t pyb_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = pyb_wdt_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_wdt_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/stm32/wdt.h b/src/openmv/src/micropython/ports/stm32/wdt.h new file mode 100755 index 0000000..d60bb7e --- /dev/null +++ b/src/openmv/src/micropython/ports/stm32/wdt.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_WDT_H +#define MICROPY_INCLUDED_STM32_WDT_H + +extern const mp_obj_type_t pyb_wdt_type; + +#endif // MICROPY_INCLUDED_STM32_WDT_H diff --git a/src/openmv/src/micropython/ports/teensy/Makefile b/src/openmv/src/micropython/ports/teensy/Makefile new file mode 100755 index 0000000..08ecf0f --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/Makefile @@ -0,0 +1,235 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h + +# include py core make definitions +include $(TOP)/py/py.mk + +# If you set USE_ARDUINO_TOOLCHAIN=1 then this makefile will attempt to use +# the toolchain that comes with Teensyduino +ifeq ($(USE_ARDUINO_TOOLCHAIN),) +USE_ARDUINO_TOOLCHAIN = 0 +endif + +ifeq ($(USE_ARDUINO_TOOLCHAIN),1) +ifeq ($(ARDUINO),) +$(error USE_ARDUINO_TOOLCHAIN requires that ARDUINO be set) +endif +endif + +ifeq ($(USE_ARDUINO_TOOLCHAIN),1) +$(info Using ARDUINO toolchain) +CROSS_COMPILE = $(ARDUINO)/hardware/tools/arm-none-eabi/bin/arm-none-eabi- +else +$(info Using toolchain from PATH) +CROSS_COMPILE = arm-none-eabi- +endif + +CFLAGS_TEENSY = -DF_CPU=96000000 -DUSB_SERIAL -D__MK20DX256__ +CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion $(CFLAGS_TEENSY) + +INC += -I. +INC += -I$(TOP) +INC += -I$(TOP)/ports/stm32 +INC += -I$(BUILD) +INC += -Icore + +CFLAGS = $(INC) -Wall -Wpointer-arith -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) +LDFLAGS = -nostdlib -T mk20dx256.ld -msoft-float -mfloat-abi=soft + +ifeq ($(USE_ARDUINO_TOOLCHAIN),1) + +LIBGCC_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/lib/gcc/arm-none-eabi/4.7.2/thumb2/libgcc.a +LIBM_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/arm-none-eabi/lib/thumb2/libm.a +LIBC_FILE_NAME = $(ARDUINO)/hardware/tools/arm-none-eabi/arm-none-eabi/lib/thumb2/libc.a + +else + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBM_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-file-name=libm.a) +LIBC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-file-name=libc.a) + +endif + +#$(info %%%%% LIBGCC_FILE_NAME = $(LIBGCC_FILE_NAME)) +#$(info %%%%% LIBM_FILE_NAME = $(LIBM_FILE_NAME)) +#$(info %%%%% LIBC_FILE_NAME = $(LIBC_FILE_NAME)) + +#$(info %%%%% dirname LIBGCC_FILE_NAME = $(dir $(LIBGCC_FILE_NAME))) +#$(info %%%%% dirname LIBM_FILE_NAME = $(dir $(LIBM_FILE_NAME))) +#$(info %%%%% dirname LIBC_FILE_NAME = $(dir $(LIBC_FILE_NAME))) + +LIBS = -L $(dir $(LIBM_FILE_NAME)) -lm +LIBS += -L $(dir $(LIBC_FILE_NAME)) -lc +LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc + +#Debugging/Optimization +ifdef DEBUG +CFLAGS += -Og -ggdb +else +CFLAGS += -Os #-DNDEBUG +endif +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += -Wl,--gc-sections + +USE_FROZEN = 1 +USE_MEMZIP = 0 + +SRC_C = \ + hal_ftm.c \ + hal_gpio.c \ + help.c \ + main.c \ + lcd.c \ + led.c \ + modpyb.c \ + pin_defs_teensy.c \ + reg.c \ + teensy_hal.c \ + timer.c \ + uart.c \ + usb.c \ + +STM_SRC_C = $(addprefix ports/stm32/,\ + gccollect.c \ + irq.c \ + pin.c \ + pin_named_pins.c \ + ) + +STM_SRC_S = $(addprefix ports/stm32/,\ + gchelper.s \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + libc/string0.c \ + mp-readline/readline.c \ + utils/pyexec.c \ + utils/sys_stdio_mphal.c \ + ) + +SRC_TEENSY = $(addprefix core/,\ + mk20dx128.c \ + pins_teensy.c \ + analog.c \ + usb_desc.c \ + usb_dev.c \ + usb_mem.c \ + usb_serial.c \ + yield.c \ + ) + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(STM_SRC_S:.s=.o) $(SRC_TEENSY:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ += $(BUILD)/pins_gen.o + +all: hex +hex: $(BUILD)/micropython.hex + +ifeq ($(USE_MEMZIP),1) +SRC_C += \ + lib/memzip/import.c \ + lib/memzip/lexermemzip.c \ + lib/memzip/memzip.c \ + +OBJ += $(BUILD)/memzip-files.o + +MAKE_MEMZIP = $(TOP)/lib/memzip/make-memzip.py +ifeq ($(MEMZIP_DIR),) +MEMZIP_DIR = memzip_files +endif + +$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c + $(call compile_c) + +$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f) + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR) + +endif # USE_MEMZIP + +ifeq ($(USE_FROZEN),1) + +ifeq ($(FROZEN_DIR),) +FROZEN_DIR = memzip_files +endif + +CFLAGS += -DMICROPY_MODULE_FROZEN_STR + +SRC_C += \ + lexerfrozen.c \ + $(BUILD)/frozen.c + +endif # USE_FROZEN + +ifeq ($(ARDUINO),) +post_compile: $(BUILD)/micropython.hex + $(ECHO) "Please define ARDUINO (where TeensyDuino is installed)" + exit 1 + +reboot: + $(ECHO) "Please define ARDUINO (where TeensyDuino is installed)" + exit 1 + +else +TOOLS_PATH = $(ARDUINO)/hardware/tools + +post_compile: $(BUILD)/micropython.hex + $(ECHO) "Preparing $@ for upload" + $(Q)$(TOOLS_PATH)/teensy_post_compile -file="$(basename $( $(GEN_PINS_SRC) + +$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c + $(call compile_c) + +$(BUILD)/%.pp: $(BUILD)/%.c + $(ECHO) "PreProcess $<" + $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/teensy/README.md b/src/openmv/src/micropython/ports/teensy/README.md new file mode 100755 index 0000000..c586853 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/README.md @@ -0,0 +1,72 @@ +# Build Instructions for Teensy 3.1 + +Currently the Teensy 3.1 port of MicroPython builds under Linux and not under Windows. + +The tool chain required for the build can be found at . + +Download the current Linux *.tar.bz2 file. Instructions regarding unpacking the file and moving it to the correct location +as well as adding the extracted folders to the enviroment variable can be found at + + +In order to download the firmware image to the teensy, you'll need to use the +downloader included with TeensyDuino. The following assumes that you have +TeensyDuino installed and set the ARDUINO environment variable pointing to the +where Arduino with TeensyDuino is installed. + +```bash +cd teensy +ARDUINO=~/arduino-1.0.5 make +``` + +To upload MicroPython to the Teensy 3.1. + +Press the Program button on the Teensy 3.1 +```bash +sudo ARDUINO=~/arduino-1.0.5/ make deploy +``` + +Currently, the Python prompt is through the USB serial interface, i.e. + +```bash +minicom -D /dev/ttyACM0 +``` + +## TIPS + +### Install 49-teensy.rules into /etc/udev/rules.d +If you install the 49-teensy.rules file from http://www.pjrc.com/teensy/49-teensy.rules +into your ```/etc/udev/rules.d``` folder then you won't need to use sudo: +```bash +sudo cp ~/Downloads/49-teensy.rules /etc/udev/rules.d +sudo udevadm control --reload-rules +``` +Unplug and replug the teensy board, and then you can use: ```ARDUINO=~/arduino-1.0.5/ make deploy``` + +### Create a GNUmakefile to hold your ARDUINO setting. +Create a file call GNUmakefile (note the lowercase m) in the teensy folder +with the following contents: +```make +$(info Executing GNUmakefile) + +ARDUINO=${HOME}/arduino-1.0.5 +$(info ARDUINO=${ARDUINO}) + +include Makefile +``` +GNUmakefile is not checked into the source code control system, so it will +retain your settings when updating your source tree. You can also add +additional Makefile customizations this way. + +### Tips for OSX + +Set the ARDUINO environment variable to the location where Arduino with TeensyDuino is installed. +```bash +export ARDUINO=~/Downloads/Arduino.app/Contents/Java/ +``` + +Search /dev/ for USB port name, which will be cu.usbmodem followed by a few numbers. The name of the port maybe different depending on the version of OSX. +To access the Python prompt type: + +```bash +screen 115200 +``` diff --git a/src/openmv/src/micropython/ports/teensy/add-memzip.sh b/src/openmv/src/micropython/ports/teensy/add-memzip.sh new file mode 100755 index 0000000..a00489e --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/add-memzip.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +if [ "$#" != 3 ]; then + echo "Usage: add-memzip.sh input.hex output.hex file-directory" + exit 1 +fi + +#set -x + +input_hex=$1 +output_hex=$2 +memzip_src_dir=$3 + +input_bin=${input_hex}.bin +output_bin=${output_hex}.bin +zip_file=${output_hex}.zip +zip_base=$(basename ${zip_file}) +zip_dir=$(dirname ${zip_file}) +abs_zip_dir=$(realpath ${zip_dir}) + +rm -f ${zip_file} +(cd ${memzip_src_dir}; zip -0 -r -D ${abs_zip_dir}/${zip_base} .) +objcopy -I ihex -O binary ${input_hex} ${input_bin} +cat ${input_bin} ${zip_file} > ${output_bin} +objcopy -I binary -O ihex ${output_bin} ${output_hex} +echo "Added ${memzip_src_dir} to ${input_hex} creating ${output_hex}" + diff --git a/src/openmv/src/micropython/ports/teensy/core/Arduino.h b/src/openmv/src/micropython/ports/teensy/core/Arduino.h new file mode 100755 index 0000000..1b053f0 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/Arduino.h @@ -0,0 +1,3 @@ +//#include "WProgram.h" +#include "core_pins.h" +#include "pins_arduino.h" diff --git a/src/openmv/src/micropython/ports/teensy/core/HardwareSerial.h b/src/openmv/src/micropython/ports/teensy/core/HardwareSerial.h new file mode 100755 index 0000000..439e0f7 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/HardwareSerial.h @@ -0,0 +1,227 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include "mk20dx128.h" +#include + +// uncomment to enable 9 bit formats +//#define SERIAL_9BIT_SUPPORT + + +#define SERIAL_7E1 0x02 +#define SERIAL_7O1 0x03 +#define SERIAL_8N1 0x00 +#define SERIAL_8N2 0x04 +#define SERIAL_8E1 0x06 +#define SERIAL_8O1 0x07 +#define SERIAL_7E1_RXINV 0x12 +#define SERIAL_7O1_RXINV 0x13 +#define SERIAL_8N1_RXINV 0x10 +#define SERIAL_8N2_RXINV 0x14 +#define SERIAL_8E1_RXINV 0x16 +#define SERIAL_8O1_RXINV 0x17 +#define SERIAL_7E1_TXINV 0x22 +#define SERIAL_7O1_TXINV 0x23 +#define SERIAL_8N1_TXINV 0x20 +#define SERIAL_8N2_TXINV 0x24 +#define SERIAL_8E1_TXINV 0x26 +#define SERIAL_8O1_TXINV 0x27 +#define SERIAL_7E1_RXINV_TXINV 0x32 +#define SERIAL_7O1_RXINV_TXINV 0x33 +#define SERIAL_8N1_RXINV_TXINV 0x30 +#define SERIAL_8N2_RXINV_TXINV 0x34 +#define SERIAL_8E1_RXINV_TXINV 0x36 +#define SERIAL_8O1_RXINV_TXINV 0x37 +#ifdef SERIAL_9BIT_SUPPORT +#define SERIAL_9N1 0x84 +#define SERIAL_9E1 0x8E +#define SERIAL_9O1 0x8F +#define SERIAL_9N1_RXINV 0x94 +#define SERIAL_9E1_RXINV 0x9E +#define SERIAL_9O1_RXINV 0x9F +#define SERIAL_9N1_TXINV 0xA4 +#define SERIAL_9E1_TXINV 0xAE +#define SERIAL_9O1_TXINV 0xAF +#define SERIAL_9N1_RXINV_TXINV 0xB4 +#define SERIAL_9E1_RXINV_TXINV 0xBE +#define SERIAL_9O1_RXINV_TXINV 0xBF +#endif +// bit0: parity, 0=even, 1=odd +// bit1: parity, 0=disable, 1=enable +// bit2: mode, 1=9bit, 0=8bit +// bit3: mode10: 1=10bit, 0=8bit +// bit4: rxinv, 0=normal, 1=inverted +// bit5: txinv, 0=normal, 1=inverted +// bit6: unused +// bit7: actual data goes into 9th bit + + +#define BAUD2DIV(baud) (((F_CPU * 2) + ((baud) >> 1)) / (baud)) +#define BAUD2DIV3(baud) (((F_BUS * 2) + ((baud) >> 1)) / (baud)) + +// C language implementation +// +#ifdef __cplusplus +extern "C" { +#endif +void serial_begin(uint32_t divisor); +void serial_format(uint32_t format); +void serial_end(void); +void serial_set_transmit_pin(uint8_t pin); +void serial_putchar(uint32_t c); +void serial_write(const void *buf, unsigned int count); +void serial_flush(void); +int serial_available(void); +int serial_getchar(void); +int serial_peek(void); +void serial_clear(void); +void serial_print(const char *p); +void serial_phex(uint32_t n); +void serial_phex16(uint32_t n); +void serial_phex32(uint32_t n); + +void serial2_begin(uint32_t divisor); +void serial2_format(uint32_t format); +void serial2_end(void); +void serial2_putchar(uint32_t c); +void serial2_write(const void *buf, unsigned int count); +void serial2_flush(void); +int serial2_available(void); +int serial2_getchar(void); +int serial2_peek(void); +void serial2_clear(void); + +void serial3_begin(uint32_t divisor); +void serial3_format(uint32_t format); +void serial3_end(void); +void serial3_putchar(uint32_t c); +void serial3_write(const void *buf, unsigned int count); +void serial3_flush(void); +int serial3_available(void); +int serial3_getchar(void); +int serial3_peek(void); +void serial3_clear(void); + +#ifdef __cplusplus +} +#endif + + +// C++ interface +// +#ifdef __cplusplus +#include "Stream.h" +class HardwareSerial : public Stream +{ +public: + virtual void begin(uint32_t baud) { serial_begin(BAUD2DIV(baud)); } + virtual void begin(uint32_t baud, uint32_t format) { + serial_begin(BAUD2DIV(baud)); + serial_format(format); } + virtual void end(void) { serial_end(); } + virtual void transmitterEnable(uint8_t pin) { serial_set_transmit_pin(pin); } + virtual int available(void) { return serial_available(); } + virtual int peek(void) { return serial_peek(); } + virtual int read(void) { return serial_getchar(); } + virtual void flush(void) { serial_flush(); } + virtual void clear(void) { serial_clear(); } + virtual size_t write(uint8_t c) { serial_putchar(c); return 1; } + virtual size_t write(unsigned long n) { return write((uint8_t)n); } + virtual size_t write(long n) { return write((uint8_t)n); } + virtual size_t write(unsigned int n) { return write((uint8_t)n); } + virtual size_t write(int n) { return write((uint8_t)n); } + virtual size_t write(const uint8_t *buffer, size_t size) + { serial_write(buffer, size); return size; } + virtual size_t write(const char *str) { size_t len = strlen(str); + serial_write((const uint8_t *)str, len); + return len; } + virtual size_t write9bit(uint32_t c) { serial_putchar(c); return 1; } +}; +extern HardwareSerial Serial1; + +class HardwareSerial2 : public HardwareSerial +{ +public: + virtual void begin(uint32_t baud) { serial2_begin(BAUD2DIV(baud)); } + virtual void begin(uint32_t baud, uint32_t format) { + serial2_begin(BAUD2DIV(baud)); + serial2_format(format); } + virtual void end(void) { serial2_end(); } + virtual int available(void) { return serial2_available(); } + virtual int peek(void) { return serial2_peek(); } + virtual int read(void) { return serial2_getchar(); } + virtual void flush(void) { serial2_flush(); } + virtual void clear(void) { serial2_clear(); } + virtual size_t write(uint8_t c) { serial2_putchar(c); return 1; } + virtual size_t write(unsigned long n) { return write((uint8_t)n); } + virtual size_t write(long n) { return write((uint8_t)n); } + virtual size_t write(unsigned int n) { return write((uint8_t)n); } + virtual size_t write(int n) { return write((uint8_t)n); } + virtual size_t write(const uint8_t *buffer, size_t size) + { serial2_write(buffer, size); return size; } + virtual size_t write(const char *str) { size_t len = strlen(str); + serial2_write((const uint8_t *)str, len); + return len; } + virtual size_t write9bit(uint32_t c) { serial2_putchar(c); return 1; } +}; +extern HardwareSerial2 Serial2; + +class HardwareSerial3 : public HardwareSerial +{ +public: + virtual void begin(uint32_t baud) { serial3_begin(BAUD2DIV3(baud)); } + virtual void begin(uint32_t baud, uint32_t format) { + serial3_begin(BAUD2DIV3(baud)); + serial3_format(format); } + virtual void end(void) { serial3_end(); } + virtual int available(void) { return serial3_available(); } + virtual int peek(void) { return serial3_peek(); } + virtual int read(void) { return serial3_getchar(); } + virtual void flush(void) { serial3_flush(); } + virtual void clear(void) { serial3_clear(); } + virtual size_t write(uint8_t c) { serial3_putchar(c); return 1; } + virtual size_t write(unsigned long n) { return write((uint8_t)n); } + virtual size_t write(long n) { return write((uint8_t)n); } + virtual size_t write(unsigned int n) { return write((uint8_t)n); } + virtual size_t write(int n) { return write((uint8_t)n); } + virtual size_t write(const uint8_t *buffer, size_t size) + { serial3_write(buffer, size); return size; } + virtual size_t write(const char *str) { size_t len = strlen(str); + serial3_write((const uint8_t *)str, len); + return len; } + virtual size_t write9bit(uint32_t c) { serial3_putchar(c); return 1; } +}; +extern HardwareSerial3 Serial3; + +#endif +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/analog.c b/src/openmv/src/micropython/ports/teensy/core/analog.c new file mode 100755 index 0000000..f408ec9 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/analog.c @@ -0,0 +1,463 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "core_pins.h" +//#include "HardwareSerial.h" + +static uint8_t calibrating; +static uint8_t analog_right_shift = 0; +static uint8_t analog_config_bits = 10; +static uint8_t analog_num_average = 4; +static uint8_t analog_reference_internal = 0; + +// the alternate clock is connected to OSCERCLK (16 MHz). +// datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode +// datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode + +#if F_BUS == 60000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7.5 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 15 MHz +#elif F_BUS == 56000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1) // 7 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 14 MHz +#elif F_BUS == 48000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 12 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 24 MHz +#elif F_BUS == 40000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 10 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 20 MHz +#elif F_BUS == 36000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1) // 9 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1) // 18 MHz +#elif F_BUS == 24000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0) // 12 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 24 MHz +#elif F_BUS == 16000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 16 MHz +#elif F_BUS == 8000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 8 MHz +#elif F_BUS == 4000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 4 MHz +#elif F_BUS == 2000000 + #define ADC_CFG1_16BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz + #define ADC_CFG1_12BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz + #define ADC_CFG1_10BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz + #define ADC_CFG1_8BIT ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0) // 2 MHz +#else +#error "F_BUS must be 60, 56, 48, 40, 36, 24, 4 or 2 MHz" +#endif + +void analog_init(void) +{ + uint32_t num; + + VREF_TRM = 0x60; + VREF_SC = 0xE1; // enable 1.2 volt ref + + if (analog_config_bits == 8) { + ADC0_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); + ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); + #if defined(__MK20DX256__) + ADC1_CFG1 = ADC_CFG1_8BIT + ADC_CFG1_MODE(0); + ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); + #endif + } else if (analog_config_bits == 10) { + ADC0_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; + ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); + #if defined(__MK20DX256__) + ADC1_CFG1 = ADC_CFG1_10BIT + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP; + ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3); + #endif + } else if (analog_config_bits == 12) { + ADC0_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; + ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); + #if defined(__MK20DX256__) + ADC1_CFG1 = ADC_CFG1_12BIT + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP; + ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); + #endif + } else { + ADC0_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; + ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); + #if defined(__MK20DX256__) + ADC1_CFG1 = ADC_CFG1_16BIT + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP; + ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2); + #endif + } + + if (analog_reference_internal) { + ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref + #if defined(__MK20DX256__) + ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref + #endif + } else { + ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref + #if defined(__MK20DX256__) + ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref + #endif + } + + num = analog_num_average; + if (num <= 1) { + ADC0_SC3 = ADC_SC3_CAL; // begin cal + #if defined(__MK20DX256__) + ADC1_SC3 = ADC_SC3_CAL; // begin cal + #endif + } else if (num <= 4) { + ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); + #if defined(__MK20DX256__) + ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0); + #endif + } else if (num <= 8) { + ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); + #if defined(__MK20DX256__) + ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1); + #endif + } else if (num <= 16) { + ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); + #if defined(__MK20DX256__) + ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2); + #endif + } else { + ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); + #if defined(__MK20DX256__) + ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3); + #endif + } + calibrating = 1; +} + +static void wait_for_cal(void) +{ + uint16_t sum; + + //serial_print("wait_for_cal\n"); +#if defined(__MK20DX128__) + while (ADC0_SC3 & ADC_SC3_CAL) { + // wait + } +#elif defined(__MK20DX256__) + while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) { + // wait + } +#endif + __disable_irq(); + if (calibrating) { + //serial_print("\n"); + sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0; + sum = (sum / 2) | 0x8000; + ADC0_PG = sum; + //serial_print("ADC0_PG = "); + //serial_phex16(sum); + //serial_print("\n"); + sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0; + sum = (sum / 2) | 0x8000; + ADC0_MG = sum; + //serial_print("ADC0_MG = "); + //serial_phex16(sum); + //serial_print("\n"); +#if defined(__MK20DX256__) + sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; + sum = (sum / 2) | 0x8000; + ADC1_PG = sum; + sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0; + sum = (sum / 2) | 0x8000; + ADC1_MG = sum; +#endif + calibrating = 0; + } + __enable_irq(); +} + +// ADCx_SC2[REFSEL] bit selects the voltage reference sources for ADC. +// VREFH/VREFL - connected as the primary reference option +// 1.2 V VREF_OUT - connected as the VALT reference option + + +#define DEFAULT 0 +#define INTERNAL 2 +#define INTERNAL1V2 2 +#define INTERNAL1V1 2 +#define EXTERNAL 0 + +void analogReference(uint8_t type) +{ + if (type) { + // internal reference requested + if (!analog_reference_internal) { + analog_reference_internal = 1; + if (calibrating) { + ADC0_SC3 = 0; // cancel cal +#if defined(__MK20DX256__) + ADC1_SC3 = 0; // cancel cal +#endif + } + analog_init(); + } + } else { + // vcc or external reference requested + if (analog_reference_internal) { + analog_reference_internal = 0; + if (calibrating) { + ADC0_SC3 = 0; // cancel cal +#if defined(__MK20DX256__) + ADC1_SC3 = 0; // cancel cal +#endif + } + analog_init(); + } + } +} + + +void analogReadRes(unsigned int bits) +{ + unsigned int config; + + if (bits >= 13) { + if (bits > 16) bits = 16; + config = 16; + } else if (bits >= 11) { + config = 12; + } else if (bits >= 9) { + config = 10; + } else { + config = 8; + } + analog_right_shift = config - bits; + if (config != analog_config_bits) { + analog_config_bits = config; + if (calibrating) ADC0_SC3 = 0; // cancel cal + analog_init(); + } +} + +void analogReadAveraging(unsigned int num) +{ + + if (calibrating) wait_for_cal(); + if (num <= 1) { + num = 0; + ADC0_SC3 = 0; + } else if (num <= 4) { + num = 4; + ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); + } else if (num <= 8) { + num = 8; + ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); + } else if (num <= 16) { + num = 16; + ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); + } else { + num = 32; + ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); + } + analog_num_average = num; +} + +// The SC1A register is used for both software and hardware trigger modes of operation. + +#if defined(__MK20DX128__) +static const uint8_t channel2sc1a[] = { + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, + 0, 19, 3, 21, 26, 22, 23 +}; +#elif defined(__MK20DX256__) +static const uint8_t channel2sc1a[] = { + 5, 14, 8, 9, 13, 12, 6, 7, 15, 4, + 0, 19, 3, 19+128, 26, 18+128, 23, + 5+192, 5+128, 4+128, 6+128, 7+128, 4+192 +// A15 26 E1 ADC1_SE5a 5+64 +// A16 27 C9 ADC1_SE5b 5 +// A17 28 C8 ADC1_SE4b 4 +// A18 29 C10 ADC1_SE6b 6 +// A19 30 C11 ADC1_SE7b 7 +// A20 31 E0 ADC1_SE4a 4+64 +}; +#endif + + + +// TODO: perhaps this should store the NVIC priority, so it works recursively? +static volatile uint8_t analogReadBusyADC0 = 0; +#if defined(__MK20DX256__) +static volatile uint8_t analogReadBusyADC1 = 0; +#endif + +int analogRead(uint8_t pin) +{ + int result; + uint8_t index, channel; + + //serial_phex(pin); + //serial_print(" "); + + if (pin <= 13) { + index = pin; // 0-13 refer to A0-A13 + } else if (pin <= 23) { + index = pin - 14; // 14-23 are A0-A9 +#if defined(__MK20DX256__) + } else if (pin >= 26 && pin <= 31) { + index = pin - 9; // 26-31 are A15-A20 +#endif + } else if (pin >= 34 && pin <= 40) { + index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, + // 39 is vref, 40 is unused (A14 on Teensy 3.1) + } else { + return 0; // all others are invalid + } + + //serial_phex(index); + //serial_print(" "); + + channel = channel2sc1a[index]; + //serial_phex(channel); + //serial_print(" "); + + //serial_print("analogRead"); + //return 0; + if (calibrating) wait_for_cal(); + //pin = 5; // PTD1/SE5b, pin 14, analog 0 + +#if defined(__MK20DX256__) + if (channel & 0x80) goto beginADC1; +#endif + + __disable_irq(); +startADC0: + //serial_print("startADC0\n"); + ADC0_SC1A = channel; + analogReadBusyADC0 = 1; + __enable_irq(); + while (1) { + __disable_irq(); + if ((ADC0_SC1A & ADC_SC1_COCO)) { + result = ADC0_RA; + analogReadBusyADC0 = 0; + __enable_irq(); + result >>= analog_right_shift; + return result; + } + // detect if analogRead was used from an interrupt + // if so, our analogRead got canceled, so it must + // be restarted. + if (!analogReadBusyADC0) goto startADC0; + __enable_irq(); + yield(); + } + +#if defined(__MK20DX256__) +beginADC1: + __disable_irq(); +startADC1: + //serial_print("startADC0\n"); + // ADC1_CFG2[MUXSEL] bit selects between ADCx_SEn channels a and b. + if (channel & 0x40) { + ADC1_CFG2 &= ~ADC_CFG2_MUXSEL; + } else { + ADC1_CFG2 |= ADC_CFG2_MUXSEL; + } + ADC1_SC1A = channel & 0x3F; + analogReadBusyADC1 = 1; + __enable_irq(); + while (1) { + __disable_irq(); + if ((ADC1_SC1A & ADC_SC1_COCO)) { + result = ADC1_RA; + analogReadBusyADC1 = 0; + __enable_irq(); + result >>= analog_right_shift; + return result; + } + // detect if analogRead was used from an interrupt + // if so, our analogRead got canceled, so it must + // be restarted. + if (!analogReadBusyADC1) goto startADC1; + __enable_irq(); + yield(); + } +#endif +} + + + +void analogWriteDAC0(int val) +{ +#if defined(__MK20DX256__) + SIM_SCGC2 |= SIM_SCGC2_DAC0; + if (analog_reference_internal) { + DAC0_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1 + } else { + DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 + } + if (val < 0) val = 0; // TODO: saturate instruction? + else if (val > 4095) val = 4095; + *(int16_t *)&(DAC0_DAT0L) = val; +#endif +} + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/teensy/core/avr_functions.h b/src/openmv/src/micropython/ports/teensy/core/avr_functions.h new file mode 100755 index 0000000..fe99f26 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/avr_functions.h @@ -0,0 +1,107 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _avr_functions_h_ +#define _avr_functions_h_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void eeprom_initialize(void); +uint8_t eeprom_read_byte(const uint8_t *addr) __attribute__ ((pure)); +uint16_t eeprom_read_word(const uint16_t *addr) __attribute__ ((pure)); +uint32_t eeprom_read_dword(const uint32_t *addr) __attribute__ ((pure)); +void eeprom_read_block(void *buf, const void *addr, uint32_t len); +void eeprom_write_byte(uint8_t *addr, uint8_t value); +void eeprom_write_word(uint16_t *addr, uint16_t value); +void eeprom_write_dword(uint32_t *addr, uint32_t value); +void eeprom_write_block(const void *buf, void *addr, uint32_t len); +int eeprom_is_ready(void); +#define eeprom_busy_wait() do {} while (!eeprom_is_ready()) + +static inline float eeprom_read_float(const float *addr) __attribute__((pure, always_inline, unused)); +static inline float eeprom_read_float(const float *addr) +{ + union {float f; uint32_t u32;} u; + u.u32 = eeprom_read_dword((const uint32_t *)addr); + return u.f; +} +static inline void eeprom_write_float(float *addr, float value) __attribute__((always_inline, unused)); +static inline void eeprom_write_float(float *addr, float value) +{ + union {float f; uint32_t u32;} u; + u.f = value; + eeprom_write_dword((uint32_t *)addr, u.u32); +} +static inline void eeprom_update_byte(uint8_t *addr, uint8_t value) __attribute__((always_inline, unused)); +static inline void eeprom_update_byte(uint8_t *addr, uint8_t value) +{ + eeprom_write_byte(addr, value); +} +static inline void eeprom_update_word(uint16_t *addr, uint16_t value) __attribute__((always_inline, unused)); +static inline void eeprom_update_word(uint16_t *addr, uint16_t value) +{ + eeprom_write_word(addr, value); +} +static inline void eeprom_update_dword(uint32_t *addr, uint32_t value) __attribute__((always_inline, unused)); +static inline void eeprom_update_dword(uint32_t *addr, uint32_t value) +{ + eeprom_write_dword(addr, value); +} +static inline void eeprom_update_float(float *addr, float value) __attribute__((always_inline, unused)); +static inline void eeprom_update_float(float *addr, float value) +{ + union {float f; uint32_t u32;} u; + u.f = value; + eeprom_write_dword((uint32_t *)addr, u.u32); +} +static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len) __attribute__((always_inline, unused)); +static inline void eeprom_update_block(const void *buf, void *addr, uint32_t len) +{ + eeprom_write_block(buf, addr, len); +} + + +char * ultoa(unsigned long val, char *buf, int radix); +char * ltoa(long val, char *buf, int radix); +static inline char * utoa(unsigned int val, char *buf, int radix) __attribute__((always_inline, unused)); +static inline char * utoa(unsigned int val, char *buf, int radix) { return ultoa(val, buf, radix); } +static inline char * itoa(int val, char *buf, int radix) __attribute__((always_inline, unused)); +static inline char * itoa(int val, char *buf, int radix) { return ltoa(val, buf, radix); } +char * dtostrf(float val, int width, unsigned int precision, char *buf); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/core_pins.h b/src/openmv/src/micropython/ports/teensy/core/core_pins.h new file mode 100755 index 0000000..169bf3c --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/core_pins.h @@ -0,0 +1,841 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _core_pins_h_ +#define _core_pins_h_ + +#include "mk20dx128.h" +#include "pins_arduino.h" + + +#define HIGH 1 +#define LOW 0 +#define INPUT 0 +#define OUTPUT 1 +#define INPUT_PULLUP 2 +#define LSBFIRST 0 +#define MSBFIRST 1 +#define _BV(n) (1<<(n)) +#define CHANGE 4 +#define FALLING 2 +#define RISING 3 + +// Pin Arduino +// 0 B16 RXD +// 1 B17 TXD +// 2 D0 +// 3 A12 FTM1_CH0 +// 4 A13 FTM1_CH1 +// 5 D7 FTM0_CH7 OC0B/T1 +// 6 D4 FTM0_CH4 OC0A +// 7 D2 +// 8 D3 ICP1 +// 9 C3 FTM0_CH2 OC1A +// 10 C4 FTM0_CH3 SS/OC1B +// 11 C6 MOSI/OC2A +// 12 C7 MISO +// 13 C5 SCK +// 14 D1 +// 15 C0 +// 16 B0 (FTM1_CH0) +// 17 B1 (FTM1_CH1) +// 18 B3 SDA +// 19 B2 SCL +// 20 D5 FTM0_CH5 +// 21 D6 FTM0_CH6 +// 22 C1 FTM0_CH0 +// 23 C2 FTM0_CH1 +// 24 A5 (FTM0_CH2) +// 25 B19 +// 26 E1 +// 27 C9 +// 28 C8 +// 29 C10 +// 30 C11 +// 31 E0 +// 32 B18 +// 33 A4 (FTM0_CH1) +// (34) analog only +// (35) analog only +// (36) analog only +// (37) analog only + +// not available to user: +// A0 FTM0_CH5 SWD Clock +// A1 FTM0_CH6 USB ID +// A2 FTM0_CH7 SWD Trace +// A3 FTM0_CH0 SWD Data + +#define CORE_NUM_TOTAL_PINS 34 +#define CORE_NUM_DIGITAL 34 +#define CORE_NUM_INTERRUPT 34 +#if defined(__MK20DX128__) +#define CORE_NUM_ANALOG 14 +#define CORE_NUM_PWM 10 +#elif defined(__MK20DX256__) +#define CORE_NUM_ANALOG 21 +#define CORE_NUM_PWM 12 +#endif + +#define CORE_PIN0_BIT 16 +#define CORE_PIN1_BIT 17 +#define CORE_PIN2_BIT 0 +#define CORE_PIN3_BIT 12 +#define CORE_PIN4_BIT 13 +#define CORE_PIN5_BIT 7 +#define CORE_PIN6_BIT 4 +#define CORE_PIN7_BIT 2 +#define CORE_PIN8_BIT 3 +#define CORE_PIN9_BIT 3 +#define CORE_PIN10_BIT 4 +#define CORE_PIN11_BIT 6 +#define CORE_PIN12_BIT 7 +#define CORE_PIN13_BIT 5 +#define CORE_PIN14_BIT 1 +#define CORE_PIN15_BIT 0 +#define CORE_PIN16_BIT 0 +#define CORE_PIN17_BIT 1 +#define CORE_PIN18_BIT 3 +#define CORE_PIN19_BIT 2 +#define CORE_PIN20_BIT 5 +#define CORE_PIN21_BIT 6 +#define CORE_PIN22_BIT 1 +#define CORE_PIN23_BIT 2 +#define CORE_PIN24_BIT 5 +#define CORE_PIN25_BIT 19 +#define CORE_PIN26_BIT 1 +#define CORE_PIN27_BIT 9 +#define CORE_PIN28_BIT 8 +#define CORE_PIN29_BIT 10 +#define CORE_PIN30_BIT 11 +#define CORE_PIN31_BIT 0 +#define CORE_PIN32_BIT 18 +#define CORE_PIN33_BIT 4 + +#define CORE_PIN0_BITMASK (1<<(CORE_PIN0_BIT)) +#define CORE_PIN1_BITMASK (1<<(CORE_PIN1_BIT)) +#define CORE_PIN2_BITMASK (1<<(CORE_PIN2_BIT)) +#define CORE_PIN3_BITMASK (1<<(CORE_PIN3_BIT)) +#define CORE_PIN4_BITMASK (1<<(CORE_PIN4_BIT)) +#define CORE_PIN5_BITMASK (1<<(CORE_PIN5_BIT)) +#define CORE_PIN6_BITMASK (1<<(CORE_PIN6_BIT)) +#define CORE_PIN7_BITMASK (1<<(CORE_PIN7_BIT)) +#define CORE_PIN8_BITMASK (1<<(CORE_PIN8_BIT)) +#define CORE_PIN9_BITMASK (1<<(CORE_PIN9_BIT)) +#define CORE_PIN10_BITMASK (1<<(CORE_PIN10_BIT)) +#define CORE_PIN11_BITMASK (1<<(CORE_PIN11_BIT)) +#define CORE_PIN12_BITMASK (1<<(CORE_PIN12_BIT)) +#define CORE_PIN13_BITMASK (1<<(CORE_PIN13_BIT)) +#define CORE_PIN14_BITMASK (1<<(CORE_PIN14_BIT)) +#define CORE_PIN15_BITMASK (1<<(CORE_PIN15_BIT)) +#define CORE_PIN16_BITMASK (1<<(CORE_PIN16_BIT)) +#define CORE_PIN17_BITMASK (1<<(CORE_PIN17_BIT)) +#define CORE_PIN18_BITMASK (1<<(CORE_PIN18_BIT)) +#define CORE_PIN19_BITMASK (1<<(CORE_PIN19_BIT)) +#define CORE_PIN20_BITMASK (1<<(CORE_PIN20_BIT)) +#define CORE_PIN21_BITMASK (1<<(CORE_PIN21_BIT)) +#define CORE_PIN22_BITMASK (1<<(CORE_PIN22_BIT)) +#define CORE_PIN23_BITMASK (1<<(CORE_PIN23_BIT)) +#define CORE_PIN24_BITMASK (1<<(CORE_PIN24_BIT)) +#define CORE_PIN25_BITMASK (1<<(CORE_PIN25_BIT)) +#define CORE_PIN26_BITMASK (1<<(CORE_PIN26_BIT)) +#define CORE_PIN27_BITMASK (1<<(CORE_PIN27_BIT)) +#define CORE_PIN28_BITMASK (1<<(CORE_PIN28_BIT)) +#define CORE_PIN29_BITMASK (1<<(CORE_PIN29_BIT)) +#define CORE_PIN30_BITMASK (1<<(CORE_PIN30_BIT)) +#define CORE_PIN31_BITMASK (1<<(CORE_PIN31_BIT)) +#define CORE_PIN32_BITMASK (1<<(CORE_PIN32_BIT)) +#define CORE_PIN33_BITMASK (1<<(CORE_PIN33_BIT)) + +#define CORE_PIN0_PORTREG GPIOB_PDOR +#define CORE_PIN1_PORTREG GPIOB_PDOR +#define CORE_PIN2_PORTREG GPIOD_PDOR +#define CORE_PIN3_PORTREG GPIOA_PDOR +#define CORE_PIN4_PORTREG GPIOA_PDOR +#define CORE_PIN5_PORTREG GPIOD_PDOR +#define CORE_PIN6_PORTREG GPIOD_PDOR +#define CORE_PIN7_PORTREG GPIOD_PDOR +#define CORE_PIN8_PORTREG GPIOD_PDOR +#define CORE_PIN9_PORTREG GPIOC_PDOR +#define CORE_PIN10_PORTREG GPIOC_PDOR +#define CORE_PIN11_PORTREG GPIOC_PDOR +#define CORE_PIN12_PORTREG GPIOC_PDOR +#define CORE_PIN13_PORTREG GPIOC_PDOR +#define CORE_PIN14_PORTREG GPIOD_PDOR +#define CORE_PIN15_PORTREG GPIOC_PDOR +#define CORE_PIN16_PORTREG GPIOB_PDOR +#define CORE_PIN17_PORTREG GPIOB_PDOR +#define CORE_PIN18_PORTREG GPIOB_PDOR +#define CORE_PIN19_PORTREG GPIOB_PDOR +#define CORE_PIN20_PORTREG GPIOD_PDOR +#define CORE_PIN21_PORTREG GPIOD_PDOR +#define CORE_PIN22_PORTREG GPIOC_PDOR +#define CORE_PIN23_PORTREG GPIOC_PDOR +#define CORE_PIN24_PORTREG GPIOA_PDOR +#define CORE_PIN25_PORTREG GPIOB_PDOR +#define CORE_PIN26_PORTREG GPIOE_PDOR +#define CORE_PIN27_PORTREG GPIOC_PDOR +#define CORE_PIN28_PORTREG GPIOC_PDOR +#define CORE_PIN29_PORTREG GPIOC_PDOR +#define CORE_PIN30_PORTREG GPIOC_PDOR +#define CORE_PIN31_PORTREG GPIOE_PDOR +#define CORE_PIN32_PORTREG GPIOB_PDOR +#define CORE_PIN33_PORTREG GPIOA_PDOR + +#define CORE_PIN0_PORTSET GPIOB_PSOR +#define CORE_PIN1_PORTSET GPIOB_PSOR +#define CORE_PIN2_PORTSET GPIOD_PSOR +#define CORE_PIN3_PORTSET GPIOA_PSOR +#define CORE_PIN4_PORTSET GPIOA_PSOR +#define CORE_PIN5_PORTSET GPIOD_PSOR +#define CORE_PIN6_PORTSET GPIOD_PSOR +#define CORE_PIN7_PORTSET GPIOD_PSOR +#define CORE_PIN8_PORTSET GPIOD_PSOR +#define CORE_PIN9_PORTSET GPIOC_PSOR +#define CORE_PIN10_PORTSET GPIOC_PSOR +#define CORE_PIN11_PORTSET GPIOC_PSOR +#define CORE_PIN12_PORTSET GPIOC_PSOR +#define CORE_PIN13_PORTSET GPIOC_PSOR +#define CORE_PIN14_PORTSET GPIOD_PSOR +#define CORE_PIN15_PORTSET GPIOC_PSOR +#define CORE_PIN16_PORTSET GPIOB_PSOR +#define CORE_PIN17_PORTSET GPIOB_PSOR +#define CORE_PIN18_PORTSET GPIOB_PSOR +#define CORE_PIN19_PORTSET GPIOB_PSOR +#define CORE_PIN20_PORTSET GPIOD_PSOR +#define CORE_PIN21_PORTSET GPIOD_PSOR +#define CORE_PIN22_PORTSET GPIOC_PSOR +#define CORE_PIN23_PORTSET GPIOC_PSOR +#define CORE_PIN24_PORTSET GPIOA_PSOR +#define CORE_PIN25_PORTSET GPIOB_PSOR +#define CORE_PIN26_PORTSET GPIOE_PSOR +#define CORE_PIN27_PORTSET GPIOC_PSOR +#define CORE_PIN28_PORTSET GPIOC_PSOR +#define CORE_PIN29_PORTSET GPIOC_PSOR +#define CORE_PIN30_PORTSET GPIOC_PSOR +#define CORE_PIN31_PORTSET GPIOE_PSOR +#define CORE_PIN32_PORTSET GPIOB_PSOR +#define CORE_PIN33_PORTSET GPIOA_PSOR + +#define CORE_PIN0_PORTCLEAR GPIOB_PCOR +#define CORE_PIN1_PORTCLEAR GPIOB_PCOR +#define CORE_PIN2_PORTCLEAR GPIOD_PCOR +#define CORE_PIN3_PORTCLEAR GPIOA_PCOR +#define CORE_PIN4_PORTCLEAR GPIOA_PCOR +#define CORE_PIN5_PORTCLEAR GPIOD_PCOR +#define CORE_PIN6_PORTCLEAR GPIOD_PCOR +#define CORE_PIN7_PORTCLEAR GPIOD_PCOR +#define CORE_PIN8_PORTCLEAR GPIOD_PCOR +#define CORE_PIN9_PORTCLEAR GPIOC_PCOR +#define CORE_PIN10_PORTCLEAR GPIOC_PCOR +#define CORE_PIN11_PORTCLEAR GPIOC_PCOR +#define CORE_PIN12_PORTCLEAR GPIOC_PCOR +#define CORE_PIN13_PORTCLEAR GPIOC_PCOR +#define CORE_PIN14_PORTCLEAR GPIOD_PCOR +#define CORE_PIN15_PORTCLEAR GPIOC_PCOR +#define CORE_PIN16_PORTCLEAR GPIOB_PCOR +#define CORE_PIN17_PORTCLEAR GPIOB_PCOR +#define CORE_PIN18_PORTCLEAR GPIOB_PCOR +#define CORE_PIN19_PORTCLEAR GPIOB_PCOR +#define CORE_PIN20_PORTCLEAR GPIOD_PCOR +#define CORE_PIN21_PORTCLEAR GPIOD_PCOR +#define CORE_PIN22_PORTCLEAR GPIOC_PCOR +#define CORE_PIN23_PORTCLEAR GPIOC_PCOR +#define CORE_PIN24_PORTCLEAR GPIOA_PCOR +#define CORE_PIN25_PORTCLEAR GPIOB_PCOR +#define CORE_PIN26_PORTCLEAR GPIOE_PCOR +#define CORE_PIN27_PORTCLEAR GPIOC_PCOR +#define CORE_PIN28_PORTCLEAR GPIOC_PCOR +#define CORE_PIN29_PORTCLEAR GPIOC_PCOR +#define CORE_PIN30_PORTCLEAR GPIOC_PCOR +#define CORE_PIN31_PORTCLEAR GPIOE_PCOR +#define CORE_PIN32_PORTCLEAR GPIOB_PCOR +#define CORE_PIN33_PORTCLEAR GPIOA_PCOR + +#define CORE_PIN0_DDRREG GPIOB_PDDR +#define CORE_PIN1_DDRREG GPIOB_PDDR +#define CORE_PIN2_DDRREG GPIOD_PDDR +#define CORE_PIN3_DDRREG GPIOA_PDDR +#define CORE_PIN4_DDRREG GPIOA_PDDR +#define CORE_PIN5_DDRREG GPIOD_PDDR +#define CORE_PIN6_DDRREG GPIOD_PDDR +#define CORE_PIN7_DDRREG GPIOD_PDDR +#define CORE_PIN8_DDRREG GPIOD_PDDR +#define CORE_PIN9_DDRREG GPIOC_PDDR +#define CORE_PIN10_DDRREG GPIOC_PDDR +#define CORE_PIN11_DDRREG GPIOC_PDDR +#define CORE_PIN12_DDRREG GPIOC_PDDR +#define CORE_PIN13_DDRREG GPIOC_PDDR +#define CORE_PIN14_DDRREG GPIOD_PDDR +#define CORE_PIN15_DDRREG GPIOC_PDDR +#define CORE_PIN16_DDRREG GPIOB_PDDR +#define CORE_PIN17_DDRREG GPIOB_PDDR +#define CORE_PIN18_DDRREG GPIOB_PDDR +#define CORE_PIN19_DDRREG GPIOB_PDDR +#define CORE_PIN20_DDRREG GPIOD_PDDR +#define CORE_PIN21_DDRREG GPIOD_PDDR +#define CORE_PIN22_DDRREG GPIOC_PDDR +#define CORE_PIN23_DDRREG GPIOC_PDDR +#define CORE_PIN24_DDRREG GPIOA_PDDR +#define CORE_PIN25_DDRREG GPIOB_PDDR +#define CORE_PIN26_DDRREG GPIOE_PDDR +#define CORE_PIN27_DDRREG GPIOC_PDDR +#define CORE_PIN28_DDRREG GPIOC_PDDR +#define CORE_PIN29_DDRREG GPIOC_PDDR +#define CORE_PIN30_DDRREG GPIOC_PDDR +#define CORE_PIN31_DDRREG GPIOE_PDDR +#define CORE_PIN32_DDRREG GPIOB_PDDR +#define CORE_PIN33_DDRREG GPIOA_PDDR + +#define CORE_PIN0_PINREG GPIOB_PDIR +#define CORE_PIN1_PINREG GPIOB_PDIR +#define CORE_PIN2_PINREG GPIOD_PDIR +#define CORE_PIN3_PINREG GPIOA_PDIR +#define CORE_PIN4_PINREG GPIOA_PDIR +#define CORE_PIN5_PINREG GPIOD_PDIR +#define CORE_PIN6_PINREG GPIOD_PDIR +#define CORE_PIN7_PINREG GPIOD_PDIR +#define CORE_PIN8_PINREG GPIOD_PDIR +#define CORE_PIN9_PINREG GPIOC_PDIR +#define CORE_PIN10_PINREG GPIOC_PDIR +#define CORE_PIN11_PINREG GPIOC_PDIR +#define CORE_PIN12_PINREG GPIOC_PDIR +#define CORE_PIN13_PINREG GPIOC_PDIR +#define CORE_PIN14_PINREG GPIOD_PDIR +#define CORE_PIN15_PINREG GPIOC_PDIR +#define CORE_PIN16_PINREG GPIOB_PDIR +#define CORE_PIN17_PINREG GPIOB_PDIR +#define CORE_PIN18_PINREG GPIOB_PDIR +#define CORE_PIN19_PINREG GPIOB_PDIR +#define CORE_PIN20_PINREG GPIOD_PDIR +#define CORE_PIN21_PINREG GPIOD_PDIR +#define CORE_PIN22_PINREG GPIOC_PDIR +#define CORE_PIN23_PINREG GPIOC_PDIR +#define CORE_PIN24_PINREG GPIOA_PDIR +#define CORE_PIN25_PINREG GPIOB_PDIR +#define CORE_PIN26_PINREG GPIOE_PDIR +#define CORE_PIN27_PINREG GPIOC_PDIR +#define CORE_PIN28_PINREG GPIOC_PDIR +#define CORE_PIN29_PINREG GPIOC_PDIR +#define CORE_PIN30_PINREG GPIOC_PDIR +#define CORE_PIN31_PINREG GPIOE_PDIR +#define CORE_PIN32_PINREG GPIOB_PDIR +#define CORE_PIN33_PINREG GPIOA_PDIR + +#define CORE_PIN0_CONFIG PORTB_PCR16 +#define CORE_PIN1_CONFIG PORTB_PCR17 +#define CORE_PIN2_CONFIG PORTD_PCR0 +#define CORE_PIN3_CONFIG PORTA_PCR12 +#define CORE_PIN4_CONFIG PORTA_PCR13 +#define CORE_PIN5_CONFIG PORTD_PCR7 +#define CORE_PIN6_CONFIG PORTD_PCR4 +#define CORE_PIN7_CONFIG PORTD_PCR2 +#define CORE_PIN8_CONFIG PORTD_PCR3 +#define CORE_PIN9_CONFIG PORTC_PCR3 +#define CORE_PIN10_CONFIG PORTC_PCR4 +#define CORE_PIN11_CONFIG PORTC_PCR6 +#define CORE_PIN12_CONFIG PORTC_PCR7 +#define CORE_PIN13_CONFIG PORTC_PCR5 +#define CORE_PIN14_CONFIG PORTD_PCR1 +#define CORE_PIN15_CONFIG PORTC_PCR0 +#define CORE_PIN16_CONFIG PORTB_PCR0 +#define CORE_PIN17_CONFIG PORTB_PCR1 +#define CORE_PIN18_CONFIG PORTB_PCR3 +#define CORE_PIN19_CONFIG PORTB_PCR2 +#define CORE_PIN20_CONFIG PORTD_PCR5 +#define CORE_PIN21_CONFIG PORTD_PCR6 +#define CORE_PIN22_CONFIG PORTC_PCR1 +#define CORE_PIN23_CONFIG PORTC_PCR2 +#define CORE_PIN24_CONFIG PORTA_PCR5 +#define CORE_PIN25_CONFIG PORTB_PCR19 +#define CORE_PIN26_CONFIG PORTE_PCR1 +#define CORE_PIN27_CONFIG PORTC_PCR9 +#define CORE_PIN28_CONFIG PORTC_PCR8 +#define CORE_PIN29_CONFIG PORTC_PCR10 +#define CORE_PIN30_CONFIG PORTC_PCR11 +#define CORE_PIN31_CONFIG PORTE_PCR0 +#define CORE_PIN32_CONFIG PORTB_PCR18 +#define CORE_PIN33_CONFIG PORTA_PCR4 + +#define CORE_ADC0_PIN 14 +#define CORE_ADC1_PIN 15 +#define CORE_ADC2_PIN 16 +#define CORE_ADC3_PIN 17 +#define CORE_ADC4_PIN 18 +#define CORE_ADC5_PIN 19 +#define CORE_ADC6_PIN 20 +#define CORE_ADC7_PIN 21 +#define CORE_ADC8_PIN 22 +#define CORE_ADC9_PIN 23 +#define CORE_ADC10_PIN 34 +#define CORE_ADC11_PIN 35 +#define CORE_ADC12_PIN 36 +#define CORE_ADC13_PIN 37 + +#define CORE_RXD0_PIN 0 +#define CORE_TXD0_PIN 1 +#define CORE_RXD1_PIN 9 +#define CORE_TXD1_PIN 10 +#define CORE_RXD2_PIN 7 +#define CORE_TXD2_PIN 8 + +#define CORE_INT0_PIN 0 +#define CORE_INT1_PIN 1 +#define CORE_INT2_PIN 2 +#define CORE_INT3_PIN 3 +#define CORE_INT4_PIN 4 +#define CORE_INT5_PIN 5 +#define CORE_INT6_PIN 6 +#define CORE_INT7_PIN 7 +#define CORE_INT8_PIN 8 +#define CORE_INT9_PIN 9 +#define CORE_INT10_PIN 10 +#define CORE_INT11_PIN 11 +#define CORE_INT12_PIN 12 +#define CORE_INT13_PIN 13 +#define CORE_INT14_PIN 14 +#define CORE_INT15_PIN 15 +#define CORE_INT16_PIN 16 +#define CORE_INT17_PIN 17 +#define CORE_INT18_PIN 18 +#define CORE_INT19_PIN 19 +#define CORE_INT20_PIN 20 +#define CORE_INT21_PIN 21 +#define CORE_INT22_PIN 22 +#define CORE_INT23_PIN 23 +#define CORE_INT24_PIN 24 +#define CORE_INT25_PIN 25 +#define CORE_INT26_PIN 26 +#define CORE_INT27_PIN 27 +#define CORE_INT28_PIN 28 +#define CORE_INT29_PIN 29 +#define CORE_INT30_PIN 30 +#define CORE_INT31_PIN 31 +#define CORE_INT32_PIN 32 +#define CORE_INT33_PIN 33 +#define CORE_INT_EVERY_PIN 1 + + + + +#ifdef __cplusplus +extern "C" { +#endif + +void digitalWrite(uint8_t pin, uint8_t val); +static inline void digitalWriteFast(uint8_t pin, uint8_t val) __attribute__((always_inline, unused)); +static inline void digitalWriteFast(uint8_t pin, uint8_t val) +{ + if (__builtin_constant_p(pin)) { + if (val) { + if (pin == 0) { + CORE_PIN0_PORTSET = CORE_PIN0_BITMASK; + } else if (pin == 1) { + CORE_PIN1_PORTSET = CORE_PIN1_BITMASK; + } else if (pin == 2) { + CORE_PIN2_PORTSET = CORE_PIN2_BITMASK; + } else if (pin == 3) { + CORE_PIN3_PORTSET = CORE_PIN3_BITMASK; + } else if (pin == 4) { + CORE_PIN4_PORTSET = CORE_PIN4_BITMASK; + } else if (pin == 5) { + CORE_PIN5_PORTSET = CORE_PIN5_BITMASK; + } else if (pin == 6) { + CORE_PIN6_PORTSET = CORE_PIN6_BITMASK; + } else if (pin == 7) { + CORE_PIN7_PORTSET = CORE_PIN7_BITMASK; + } else if (pin == 8) { + CORE_PIN8_PORTSET = CORE_PIN8_BITMASK; + } else if (pin == 9) { + CORE_PIN9_PORTSET = CORE_PIN9_BITMASK; + } else if (pin == 10) { + CORE_PIN10_PORTSET = CORE_PIN10_BITMASK; + } else if (pin == 11) { + CORE_PIN11_PORTSET = CORE_PIN11_BITMASK; + } else if (pin == 12) { + CORE_PIN12_PORTSET = CORE_PIN12_BITMASK; + } else if (pin == 13) { + CORE_PIN13_PORTSET = CORE_PIN13_BITMASK; + } else if (pin == 14) { + CORE_PIN14_PORTSET = CORE_PIN14_BITMASK; + } else if (pin == 15) { + CORE_PIN15_PORTSET = CORE_PIN15_BITMASK; + } else if (pin == 16) { + CORE_PIN16_PORTSET = CORE_PIN16_BITMASK; + } else if (pin == 17) { + CORE_PIN17_PORTSET = CORE_PIN17_BITMASK; + } else if (pin == 18) { + CORE_PIN18_PORTSET = CORE_PIN18_BITMASK; + } else if (pin == 19) { + CORE_PIN19_PORTSET = CORE_PIN19_BITMASK; + } else if (pin == 20) { + CORE_PIN20_PORTSET = CORE_PIN20_BITMASK; + } else if (pin == 21) { + CORE_PIN21_PORTSET = CORE_PIN21_BITMASK; + } else if (pin == 22) { + CORE_PIN22_PORTSET = CORE_PIN22_BITMASK; + } else if (pin == 23) { + CORE_PIN23_PORTSET = CORE_PIN23_BITMASK; + } else if (pin == 24) { + CORE_PIN24_PORTSET = CORE_PIN24_BITMASK; + } else if (pin == 25) { + CORE_PIN25_PORTSET = CORE_PIN25_BITMASK; + } else if (pin == 26) { + CORE_PIN26_PORTSET = CORE_PIN26_BITMASK; + } else if (pin == 27) { + CORE_PIN27_PORTSET = CORE_PIN27_BITMASK; + } else if (pin == 28) { + CORE_PIN28_PORTSET = CORE_PIN28_BITMASK; + } else if (pin == 29) { + CORE_PIN29_PORTSET = CORE_PIN29_BITMASK; + } else if (pin == 30) { + CORE_PIN30_PORTSET = CORE_PIN30_BITMASK; + } else if (pin == 31) { + CORE_PIN31_PORTSET = CORE_PIN31_BITMASK; + } else if (pin == 32) { + CORE_PIN32_PORTSET = CORE_PIN32_BITMASK; + } else if (pin == 33) { + CORE_PIN33_PORTSET = CORE_PIN33_BITMASK; + } + } else { + if (pin == 0) { + CORE_PIN0_PORTCLEAR = CORE_PIN0_BITMASK; + } else if (pin == 1) { + CORE_PIN1_PORTCLEAR = CORE_PIN1_BITMASK; + } else if (pin == 2) { + CORE_PIN2_PORTCLEAR = CORE_PIN2_BITMASK; + } else if (pin == 3) { + CORE_PIN3_PORTCLEAR = CORE_PIN3_BITMASK; + } else if (pin == 4) { + CORE_PIN4_PORTCLEAR = CORE_PIN4_BITMASK; + } else if (pin == 5) { + CORE_PIN5_PORTCLEAR = CORE_PIN5_BITMASK; + } else if (pin == 6) { + CORE_PIN6_PORTCLEAR = CORE_PIN6_BITMASK; + } else if (pin == 7) { + CORE_PIN7_PORTCLEAR = CORE_PIN7_BITMASK; + } else if (pin == 8) { + CORE_PIN8_PORTCLEAR = CORE_PIN8_BITMASK; + } else if (pin == 9) { + CORE_PIN9_PORTCLEAR = CORE_PIN9_BITMASK; + } else if (pin == 10) { + CORE_PIN10_PORTCLEAR = CORE_PIN10_BITMASK; + } else if (pin == 11) { + CORE_PIN11_PORTCLEAR = CORE_PIN11_BITMASK; + } else if (pin == 12) { + CORE_PIN12_PORTCLEAR = CORE_PIN12_BITMASK; + } else if (pin == 13) { + CORE_PIN13_PORTCLEAR = CORE_PIN13_BITMASK; + } else if (pin == 14) { + CORE_PIN14_PORTCLEAR = CORE_PIN14_BITMASK; + } else if (pin == 15) { + CORE_PIN15_PORTCLEAR = CORE_PIN15_BITMASK; + } else if (pin == 16) { + CORE_PIN16_PORTCLEAR = CORE_PIN16_BITMASK; + } else if (pin == 17) { + CORE_PIN17_PORTCLEAR = CORE_PIN17_BITMASK; + } else if (pin == 18) { + CORE_PIN18_PORTCLEAR = CORE_PIN18_BITMASK; + } else if (pin == 19) { + CORE_PIN19_PORTCLEAR = CORE_PIN19_BITMASK; + } else if (pin == 20) { + CORE_PIN20_PORTCLEAR = CORE_PIN20_BITMASK; + } else if (pin == 21) { + CORE_PIN21_PORTCLEAR = CORE_PIN21_BITMASK; + } else if (pin == 22) { + CORE_PIN22_PORTCLEAR = CORE_PIN22_BITMASK; + } else if (pin == 23) { + CORE_PIN23_PORTCLEAR = CORE_PIN23_BITMASK; + } else if (pin == 24) { + CORE_PIN24_PORTCLEAR = CORE_PIN24_BITMASK; + } else if (pin == 25) { + CORE_PIN25_PORTCLEAR = CORE_PIN25_BITMASK; + } else if (pin == 26) { + CORE_PIN26_PORTCLEAR = CORE_PIN26_BITMASK; + } else if (pin == 27) { + CORE_PIN27_PORTCLEAR = CORE_PIN27_BITMASK; + } else if (pin == 28) { + CORE_PIN28_PORTCLEAR = CORE_PIN28_BITMASK; + } else if (pin == 29) { + CORE_PIN29_PORTCLEAR = CORE_PIN29_BITMASK; + } else if (pin == 30) { + CORE_PIN30_PORTCLEAR = CORE_PIN30_BITMASK; + } else if (pin == 31) { + CORE_PIN31_PORTCLEAR = CORE_PIN31_BITMASK; + } else if (pin == 32) { + CORE_PIN32_PORTCLEAR = CORE_PIN32_BITMASK; + } else if (pin == 33) { + CORE_PIN33_PORTCLEAR = CORE_PIN33_BITMASK; + } + } + } else { + if (val) { + *portSetRegister(pin) = 1; + } else { + *portClearRegister(pin) = 1; + } + } +} + +uint8_t digitalRead(uint8_t pin); +static inline uint8_t digitalReadFast(uint8_t pin) __attribute__((always_inline, unused)); +static inline uint8_t digitalReadFast(uint8_t pin) +{ + if (__builtin_constant_p(pin)) { + if (pin == 0) { + return (CORE_PIN0_PINREG & CORE_PIN0_BITMASK) ? 1 : 0; + } else if (pin == 1) { + return (CORE_PIN1_PINREG & CORE_PIN1_BITMASK) ? 1 : 0; + } else if (pin == 2) { + return (CORE_PIN2_PINREG & CORE_PIN2_BITMASK) ? 1 : 0; + } else if (pin == 3) { + return (CORE_PIN3_PINREG & CORE_PIN3_BITMASK) ? 1 : 0; + } else if (pin == 4) { + return (CORE_PIN4_PINREG & CORE_PIN4_BITMASK) ? 1 : 0; + } else if (pin == 5) { + return (CORE_PIN5_PINREG & CORE_PIN5_BITMASK) ? 1 : 0; + } else if (pin == 6) { + return (CORE_PIN6_PINREG & CORE_PIN6_BITMASK) ? 1 : 0; + } else if (pin == 7) { + return (CORE_PIN7_PINREG & CORE_PIN7_BITMASK) ? 1 : 0; + } else if (pin == 8) { + return (CORE_PIN8_PINREG & CORE_PIN8_BITMASK) ? 1 : 0; + } else if (pin == 9) { + return (CORE_PIN9_PINREG & CORE_PIN9_BITMASK) ? 1 : 0; + } else if (pin == 10) { + return (CORE_PIN10_PINREG & CORE_PIN10_BITMASK) ? 1 : 0; + } else if (pin == 11) { + return (CORE_PIN11_PINREG & CORE_PIN11_BITMASK) ? 1 : 0; + } else if (pin == 12) { + return (CORE_PIN12_PINREG & CORE_PIN12_BITMASK) ? 1 : 0; + } else if (pin == 13) { + return (CORE_PIN13_PINREG & CORE_PIN13_BITMASK) ? 1 : 0; + } else if (pin == 14) { + return (CORE_PIN14_PINREG & CORE_PIN14_BITMASK) ? 1 : 0; + } else if (pin == 15) { + return (CORE_PIN15_PINREG & CORE_PIN15_BITMASK) ? 1 : 0; + } else if (pin == 16) { + return (CORE_PIN16_PINREG & CORE_PIN16_BITMASK) ? 1 : 0; + } else if (pin == 17) { + return (CORE_PIN17_PINREG & CORE_PIN17_BITMASK) ? 1 : 0; + } else if (pin == 18) { + return (CORE_PIN18_PINREG & CORE_PIN18_BITMASK) ? 1 : 0; + } else if (pin == 19) { + return (CORE_PIN19_PINREG & CORE_PIN19_BITMASK) ? 1 : 0; + } else if (pin == 20) { + return (CORE_PIN20_PINREG & CORE_PIN20_BITMASK) ? 1 : 0; + } else if (pin == 21) { + return (CORE_PIN21_PINREG & CORE_PIN21_BITMASK) ? 1 : 0; + } else if (pin == 22) { + return (CORE_PIN22_PINREG & CORE_PIN22_BITMASK) ? 1 : 0; + } else if (pin == 23) { + return (CORE_PIN23_PINREG & CORE_PIN23_BITMASK) ? 1 : 0; + } else if (pin == 24) { + return (CORE_PIN24_PINREG & CORE_PIN24_BITMASK) ? 1 : 0; + } else if (pin == 25) { + return (CORE_PIN25_PINREG & CORE_PIN25_BITMASK) ? 1 : 0; + } else if (pin == 26) { + return (CORE_PIN26_PINREG & CORE_PIN26_BITMASK) ? 1 : 0; + } else if (pin == 27) { + return (CORE_PIN27_PINREG & CORE_PIN27_BITMASK) ? 1 : 0; + } else if (pin == 28) { + return (CORE_PIN28_PINREG & CORE_PIN28_BITMASK) ? 1 : 0; + } else if (pin == 29) { + return (CORE_PIN29_PINREG & CORE_PIN29_BITMASK) ? 1 : 0; + } else if (pin == 30) { + return (CORE_PIN30_PINREG & CORE_PIN30_BITMASK) ? 1 : 0; + } else if (pin == 31) { + return (CORE_PIN31_PINREG & CORE_PIN31_BITMASK) ? 1 : 0; + } else if (pin == 32) { + return (CORE_PIN32_PINREG & CORE_PIN32_BITMASK) ? 1 : 0; + } else if (pin == 33) { + return (CORE_PIN33_PINREG & CORE_PIN33_BITMASK) ? 1 : 0; + } else { + return 0; + } + } else { + return *portInputRegister(pin); + } +} + + +void pinMode(uint8_t pin, uint8_t mode); +void init_pins(void); +void analogWrite(uint8_t pin, int val); +void analogWriteRes(uint32_t bits); +static inline void analogWriteResolution(uint32_t bits) { analogWriteRes(bits); } +void analogWriteFrequency(uint8_t pin, uint32_t frequency); +void analogWriteDAC0(int val); +void attachInterrupt(uint8_t pin, void (*function)(void), int mode); +void detachInterrupt(uint8_t pin); +void _init_Teensyduino_internal_(void); + +int analogRead(uint8_t pin); +void analogReference(uint8_t type); +void analogReadRes(unsigned int bits); +static inline void analogReadResolution(unsigned int bits) { analogReadRes(bits); } +void analogReadAveraging(unsigned int num); +void analog_init(void); + +#define DEFAULT 0 +#define INTERNAL 2 +#define INTERNAL1V2 2 +#define INTERNAL1V1 2 +#define EXTERNAL 0 + +int touchRead(uint8_t pin); + + +static inline void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t) __attribute__((always_inline, unused)); +extern void _shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value) __attribute__((noinline)); +extern void shiftOut_lsbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) __attribute__((noinline)); +extern void shiftOut_msbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) __attribute__((noinline)); + +static inline void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value) +{ + if (__builtin_constant_p(bitOrder)) { + if (bitOrder == LSBFIRST) { + shiftOut_lsbFirst(dataPin, clockPin, value); + } else { + shiftOut_msbFirst(dataPin, clockPin, value); + } + } else { + _shiftOut(dataPin, clockPin, bitOrder, value); + } +} + +static inline uint8_t shiftIn(uint8_t, uint8_t, uint8_t) __attribute__((always_inline, unused)); +extern uint8_t _shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) __attribute__((noinline)); +extern uint8_t shiftIn_lsbFirst(uint8_t dataPin, uint8_t clockPin) __attribute__((noinline)); +extern uint8_t shiftIn_msbFirst(uint8_t dataPin, uint8_t clockPin) __attribute__((noinline)); + +static inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) +{ + if (__builtin_constant_p(bitOrder)) { + if (bitOrder == LSBFIRST) { + return shiftIn_lsbFirst(dataPin, clockPin); + } else { + return shiftIn_msbFirst(dataPin, clockPin); + } + } else { + return _shiftIn(dataPin, clockPin, bitOrder); + } +} + +void _reboot_Teensyduino_(void) __attribute__((noreturn)); +void _restart_Teensyduino_(void) __attribute__((noreturn)); + +void yield(void); + +void delay(uint32_t msec); + +extern volatile uint32_t systick_millis_count; + +static inline uint32_t millis(void) __attribute__((always_inline, unused)); +static inline uint32_t millis(void) +{ + volatile uint32_t ret = systick_millis_count; // single aligned 32 bit is atomic; + return ret; +} + +uint32_t micros(void); + +static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); +static inline void delayMicroseconds(uint32_t usec) +{ +#if F_CPU == 168000000 + uint32_t n = usec * 56; +#elif F_CPU == 144000000 + uint32_t n = usec * 48; +#elif F_CPU == 120000000 + uint32_t n = usec * 40; +#elif F_CPU == 96000000 + uint32_t n = usec << 5; +#elif F_CPU == 72000000 + uint32_t n = usec * 24; +#elif F_CPU == 48000000 + uint32_t n = usec << 4; +#elif F_CPU == 24000000 + uint32_t n = usec << 3; +#elif F_CPU == 16000000 + uint32_t n = usec << 2; +#elif F_CPU == 8000000 + uint32_t n = usec << 1; +#elif F_CPU == 4000000 + uint32_t n = usec; +#elif F_CPU == 2000000 + uint32_t n = usec >> 1; +#endif + // changed because a delay of 1 micro Sec @ 2MHz will be 0 + if (n == 0) return; + __asm__ volatile( + "L_%=_delayMicroseconds:" "\n\t" +#if F_CPU < 24000000 + "nop" "\n\t" +#endif + "subs %0, #1" "\n\t" + "bne L_%=_delayMicroseconds" "\n" + : "+r" (n) : + ); +} + +#ifdef __cplusplus +} +#endif + + + + + + + + +#ifdef __cplusplus +extern "C" { +#endif +unsigned long rtc_get(void); +void rtc_set(unsigned long t); +void rtc_compensate(int adjust); +#ifdef __cplusplus +} +class teensy3_clock_class +{ +public: + static unsigned long get(void) __attribute__((always_inline)) { return rtc_get(); } + static void set(unsigned long t) __attribute__((always_inline)) { rtc_set(t); } + static void compensate(int adj) __attribute__((always_inline)) { rtc_compensate(adj); } +}; +extern teensy3_clock_class Teensy3Clock; +#endif + + + + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/mk20dx128.c b/src/openmv/src/micropython/ports/teensy/core/mk20dx128.c new file mode 100755 index 0000000..0f5f1e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/mk20dx128.c @@ -0,0 +1,662 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mk20dx128.h" + + +extern unsigned long _stext; +extern unsigned long _etext; +extern unsigned long _sdata; +extern unsigned long _edata; +extern unsigned long _sbss; +extern unsigned long _ebss; +extern unsigned long _estack; +//extern void __init_array_start(void); +//extern void __init_array_end(void); + + + +extern int main (void); +void ResetHandler(void); +void _init_Teensyduino_internal_(void); +void __libc_init_array(void); + + +void fault_isr(void) +{ + while (1) { + // keep polling some communication while in fault + // mode, so we don't completely die. + if (SIM_SCGC4 & SIM_SCGC4_USBOTG) usb_isr(); + if (SIM_SCGC4 & SIM_SCGC4_UART0) uart0_status_isr(); + if (SIM_SCGC4 & SIM_SCGC4_UART1) uart1_status_isr(); + if (SIM_SCGC4 & SIM_SCGC4_UART2) uart2_status_isr(); + } +} + +void unused_isr(void) +{ + fault_isr(); +} + +extern volatile uint32_t systick_millis_count; +void systick_default_isr(void) +{ + systick_millis_count++; +} + +void nmi_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void hard_fault_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void memmanage_fault_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void bus_fault_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void usage_fault_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void svcall_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void debugmonitor_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pendablesrvreq_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void systick_isr(void) __attribute__ ((weak, alias("systick_default_isr"))); + +void dma_ch0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch3_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch4_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch5_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch6_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch7_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch8_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch9_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch10_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch11_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch12_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch13_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch14_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_ch15_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dma_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void mcm_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void flash_cmd_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void flash_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void low_voltage_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void wakeup_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void watchdog_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void i2c0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void i2c1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void i2c2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void spi0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void spi1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void spi2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void sdhc_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_message_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_bus_off_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_tx_warn_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_rx_warn_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void can0_wakeup_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void i2s0_tx_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void i2s0_rx_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart0_lon_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart0_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart0_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart1_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart1_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart2_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart2_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart3_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart3_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart4_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart4_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart5_status_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void uart5_error_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void adc0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void adc1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void cmp0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void cmp1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void cmp2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void ftm0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void ftm1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void ftm2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void ftm3_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void cmt_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void rtc_alarm_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void rtc_seconds_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pit0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pit1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pit2_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pit3_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void pdb_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void usb_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void usb_charge_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dac0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void dac1_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void tsi0_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void mcg_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void lptmr_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void porta_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void portb_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void portc_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void portd_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void porte_isr(void) __attribute__ ((weak, alias("unused_isr"))); +void software_isr(void) __attribute__ ((weak, alias("unused_isr"))); + + +// TODO: create AVR-stype ISR() macro, with default linkage to undefined handler +// +__attribute__ ((section(".vectors"), used)) +void (* const gVectors[])(void) = +{ + (void (*)(void))((unsigned long)&_estack), // 0 ARM: Initial Stack Pointer + ResetHandler, // 1 ARM: Initial Program Counter + nmi_isr, // 2 ARM: Non-maskable Interrupt (NMI) + hard_fault_isr, // 3 ARM: Hard Fault + memmanage_fault_isr, // 4 ARM: MemManage Fault + bus_fault_isr, // 5 ARM: Bus Fault + usage_fault_isr, // 6 ARM: Usage Fault + fault_isr, // 7 -- + fault_isr, // 8 -- + fault_isr, // 9 -- + fault_isr, // 10 -- + svcall_isr, // 11 ARM: Supervisor call (SVCall) + debugmonitor_isr, // 12 ARM: Debug Monitor + fault_isr, // 13 -- + pendablesrvreq_isr, // 14 ARM: Pendable req serv(PendableSrvReq) + systick_isr, // 15 ARM: System tick timer (SysTick) +#if defined(__MK20DX128__) + dma_ch0_isr, // 16 DMA channel 0 transfer complete + dma_ch1_isr, // 17 DMA channel 1 transfer complete + dma_ch2_isr, // 18 DMA channel 2 transfer complete + dma_ch3_isr, // 19 DMA channel 3 transfer complete + dma_error_isr, // 20 DMA error interrupt channel + unused_isr, // 21 DMA -- + flash_cmd_isr, // 22 Flash Memory Command complete + flash_error_isr, // 23 Flash Read collision + low_voltage_isr, // 24 Low-voltage detect/warning + wakeup_isr, // 25 Low Leakage Wakeup + watchdog_isr, // 26 Both EWM and WDOG interrupt + i2c0_isr, // 27 I2C0 + spi0_isr, // 28 SPI0 + i2s0_tx_isr, // 29 I2S0 Transmit + i2s0_rx_isr, // 30 I2S0 Receive + uart0_lon_isr, // 31 UART0 CEA709.1-B (LON) status + uart0_status_isr, // 32 UART0 status + uart0_error_isr, // 33 UART0 error + uart1_status_isr, // 34 UART1 status + uart1_error_isr, // 35 UART1 error + uart2_status_isr, // 36 UART2 status + uart2_error_isr, // 37 UART2 error + adc0_isr, // 38 ADC0 + cmp0_isr, // 39 CMP0 + cmp1_isr, // 40 CMP1 + ftm0_isr, // 41 FTM0 + ftm1_isr, // 42 FTM1 + cmt_isr, // 43 CMT + rtc_alarm_isr, // 44 RTC Alarm interrupt + rtc_seconds_isr, // 45 RTC Seconds interrupt + pit0_isr, // 46 PIT Channel 0 + pit1_isr, // 47 PIT Channel 1 + pit2_isr, // 48 PIT Channel 2 + pit3_isr, // 49 PIT Channel 3 + pdb_isr, // 50 PDB Programmable Delay Block + usb_isr, // 51 USB OTG + usb_charge_isr, // 52 USB Charger Detect + tsi0_isr, // 53 TSI0 + mcg_isr, // 54 MCG + lptmr_isr, // 55 Low Power Timer + porta_isr, // 56 Pin detect (Port A) + portb_isr, // 57 Pin detect (Port B) + portc_isr, // 58 Pin detect (Port C) + portd_isr, // 59 Pin detect (Port D) + porte_isr, // 60 Pin detect (Port E) + software_isr, // 61 Software interrupt +#elif defined(__MK20DX256__) + dma_ch0_isr, // 16 DMA channel 0 transfer complete + dma_ch1_isr, // 17 DMA channel 1 transfer complete + dma_ch2_isr, // 18 DMA channel 2 transfer complete + dma_ch3_isr, // 19 DMA channel 3 transfer complete + dma_ch4_isr, // 20 DMA channel 4 transfer complete + dma_ch5_isr, // 21 DMA channel 5 transfer complete + dma_ch6_isr, // 22 DMA channel 6 transfer complete + dma_ch7_isr, // 23 DMA channel 7 transfer complete + dma_ch8_isr, // 24 DMA channel 8 transfer complete + dma_ch9_isr, // 25 DMA channel 9 transfer complete + dma_ch10_isr, // 26 DMA channel 10 transfer complete + dma_ch11_isr, // 27 DMA channel 10 transfer complete + dma_ch12_isr, // 28 DMA channel 10 transfer complete + dma_ch13_isr, // 29 DMA channel 10 transfer complete + dma_ch14_isr, // 30 DMA channel 10 transfer complete + dma_ch15_isr, // 31 DMA channel 10 transfer complete + dma_error_isr, // 32 DMA error interrupt channel + unused_isr, // 33 -- + flash_cmd_isr, // 34 Flash Memory Command complete + flash_error_isr, // 35 Flash Read collision + low_voltage_isr, // 36 Low-voltage detect/warning + wakeup_isr, // 37 Low Leakage Wakeup + watchdog_isr, // 38 Both EWM and WDOG interrupt + unused_isr, // 39 -- + i2c0_isr, // 40 I2C0 + i2c1_isr, // 41 I2C1 + spi0_isr, // 42 SPI0 + spi1_isr, // 43 SPI1 + unused_isr, // 44 -- + can0_message_isr, // 45 CAN OR'ed Message buffer (0-15) + can0_bus_off_isr, // 46 CAN Bus Off + can0_error_isr, // 47 CAN Error + can0_tx_warn_isr, // 48 CAN Transmit Warning + can0_rx_warn_isr, // 49 CAN Receive Warning + can0_wakeup_isr, // 50 CAN Wake Up + i2s0_tx_isr, // 51 I2S0 Transmit + i2s0_rx_isr, // 52 I2S0 Receive + unused_isr, // 53 -- + unused_isr, // 54 -- + unused_isr, // 55 -- + unused_isr, // 56 -- + unused_isr, // 57 -- + unused_isr, // 58 -- + unused_isr, // 59 -- + uart0_lon_isr, // 60 UART0 CEA709.1-B (LON) status + uart0_status_isr, // 61 UART0 status + uart0_error_isr, // 62 UART0 error + uart1_status_isr, // 63 UART1 status + uart1_error_isr, // 64 UART1 error + uart2_status_isr, // 65 UART2 status + uart2_error_isr, // 66 UART2 error + unused_isr, // 67 -- + unused_isr, // 68 -- + unused_isr, // 69 -- + unused_isr, // 70 -- + unused_isr, // 71 -- + unused_isr, // 72 -- + adc0_isr, // 73 ADC0 + adc1_isr, // 74 ADC1 + cmp0_isr, // 75 CMP0 + cmp1_isr, // 76 CMP1 + cmp2_isr, // 77 CMP2 + ftm0_isr, // 78 FTM0 + ftm1_isr, // 79 FTM1 + ftm2_isr, // 80 FTM2 + cmt_isr, // 81 CMT + rtc_alarm_isr, // 82 RTC Alarm interrupt + rtc_seconds_isr, // 83 RTC Seconds interrupt + pit0_isr, // 84 PIT Channel 0 + pit1_isr, // 85 PIT Channel 1 + pit2_isr, // 86 PIT Channel 2 + pit3_isr, // 87 PIT Channel 3 + pdb_isr, // 88 PDB Programmable Delay Block + usb_isr, // 89 USB OTG + usb_charge_isr, // 90 USB Charger Detect + unused_isr, // 91 -- + unused_isr, // 92 -- + unused_isr, // 93 -- + unused_isr, // 94 -- + unused_isr, // 95 -- + unused_isr, // 96 -- + dac0_isr, // 97 DAC0 + unused_isr, // 98 -- + tsi0_isr, // 99 TSI0 + mcg_isr, // 100 MCG + lptmr_isr, // 101 Low Power Timer + unused_isr, // 102 -- + porta_isr, // 103 Pin detect (Port A) + portb_isr, // 104 Pin detect (Port B) + portc_isr, // 105 Pin detect (Port C) + portd_isr, // 106 Pin detect (Port D) + porte_isr, // 107 Pin detect (Port E) + unused_isr, // 108 -- + unused_isr, // 109 -- + software_isr, // 110 Software interrupt +#endif +}; + +//void usb_isr(void) +//{ +//} + +__attribute__ ((section(".flashconfig"), used)) +const uint8_t flashconfigbytes[16] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF +}; + + +// Automatically initialize the RTC. When the build defines the compile +// time, and the user has added a crystal, the RTC will automatically +// begin at the time of the first upload. +#ifndef TIME_T +#define TIME_T 1349049600 // default 1 Oct 2012 (never used, Arduino sets this) +#endif +extern void rtc_set(unsigned long t); + + +static void startup_default_early_hook(void) { WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE; } +static void startup_default_late_hook(void) {} +void startup_early_hook(void) __attribute__ ((weak, alias("startup_default_early_hook"))); +void startup_late_hook(void) __attribute__ ((weak, alias("startup_default_late_hook"))); + +__attribute__ ((section(".startup"))) +void ResetHandler(void) +{ + uint32_t *src = &_etext; + uint32_t *dest = &_sdata; + unsigned int i; +#if F_CPU <= 2000000 + volatile int n; +#endif + + WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; + WDOG_UNLOCK = WDOG_UNLOCK_SEQ2; + __asm__ volatile ("nop"); + __asm__ volatile ("nop"); + // programs using the watchdog timer or needing to initialize hardware as + // early as possible can implement startup_early_hook() + startup_early_hook(); + + // enable clocks to always-used peripherals +#if defined(__MK20DX128__) + SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO + SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; +#elif defined(__MK20DX256__) + SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2; + SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO + SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTFL; +#endif + // if the RTC oscillator isn't enabled, get it started early + if (!(RTC_CR & RTC_CR_OSCE)) { + RTC_SR = 0; + RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; + } + + // release I/O pins hold, if we woke up from VLLS mode + if (PMC_REGSC & PMC_REGSC_ACKISO) PMC_REGSC |= PMC_REGSC_ACKISO; + + // since this is a write once register, make it visible to all F_CPU's + // so we can into other sleep modes in the future at any speed + SMC_PMPROT = SMC_PMPROT_AVLP | SMC_PMPROT_ALLS | SMC_PMPROT_AVLLS; + + // TODO: do this while the PLL is waiting to lock.... + while (dest < &_edata) *dest++ = *src++; + dest = &_sbss; + while (dest < &_ebss) *dest++ = 0; + SCB_VTOR = 0; // use vector table in flash + + // default all interrupts to medium priority level + for (i=0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_PRIORITY(i, 128); + + // hardware always starts in FEI mode + // C1[CLKS] bits are written to 00 + // C1[IREFS] bit is written to 1 + // C6[PLLS] bit is written to 0 +// MCG_SC[FCDIV] defaults to divide by two for internal ref clock +// I tried changing MSG_SC to divide by 1, it didn't work for me +#if F_CPU <= 2000000 + // use the internal oscillator + MCG_C1 = MCG_C1_CLKS(1) | MCG_C1_IREFS; + // wait for MCGOUT to use oscillator + while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(1)) ; + for (n=0; n<10; n++) ; // TODO: why do we get 2 mA extra without this delay? + MCG_C2 = MCG_C2_IRCS; + while (!(MCG_S & MCG_S_IRCST)) ; + // now in FBI mode: + // C1[CLKS] bits are written to 01 + // C1[IREFS] bit is written to 1 + // C6[PLLS] is written to 0 + // C2[LP] is written to 0 + MCG_C2 = MCG_C2_IRCS | MCG_C2_LP; + // now in BLPI mode: + // C1[CLKS] bits are written to 01 + // C1[IREFS] bit is written to 1 + // C6[PLLS] bit is written to 0 + // C2[LP] bit is written to 1 +#else + // enable capacitors for crystal + OSC0_CR = OSC_SC8P | OSC_SC2P; + // enable osc, 8-32 MHz range, low power mode + MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS; + // switch to crystal as clock source, FLL input = 16 MHz / 512 + MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(4); + // wait for crystal oscillator to begin + while ((MCG_S & MCG_S_OSCINIT0) == 0) ; + // wait for FLL to use oscillator + while ((MCG_S & MCG_S_IREFST) != 0) ; + // wait for MCGOUT to use oscillator + while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(2)) ; + // now in FBE mode + // C1[CLKS] bits are written to 10 + // C1[IREFS] bit is written to 0 + // C1[FRDIV] must be written to divide xtal to 31.25-39 kHz + // C6[PLLS] bit is written to 0 + // C2[LP] is written to 0 + #if F_CPU <= 16000000 + // if the crystal is fast enough, use it directly (no FLL or PLL) + MCG_C2 = MCG_C2_RANGE0(2) | MCG_C2_EREFS | MCG_C2_LP; + // BLPE mode: + // C1[CLKS] bits are written to 10 + // C1[IREFS] bit is written to 0 + // C2[LP] bit is written to 1 + #else + // if we need faster than the crystal, turn on the PLL + #if F_CPU == 72000000 + MCG_C5 = MCG_C5_PRDIV0(5); // config PLL input for 16 MHz Crystal / 6 = 2.667 Hz + #else + MCG_C5 = MCG_C5_PRDIV0(3); // config PLL input for 16 MHz Crystal / 4 = 4 MHz + #endif + #if F_CPU == 168000000 + MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(18); // config PLL for 168 MHz output + #elif F_CPU == 144000000 + MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(12); // config PLL for 144 MHz output + #elif F_CPU == 120000000 + MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(6); // config PLL for 120 MHz output + #elif F_CPU == 72000000 + MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(3); // config PLL for 72 MHz output + #else + MCG_C6 = MCG_C6_PLLS | MCG_C6_VDIV0(0); // config PLL for 96 MHz output + #endif + // wait for PLL to start using xtal as its input + while (!(MCG_S & MCG_S_PLLST)) ; + // wait for PLL to lock + while (!(MCG_S & MCG_S_LOCK0)) ; + // now we're in PBE mode + #endif +#endif + + // now program the clock dividers +#if F_CPU == 168000000 + // config divisors: 168 MHz core, 56 MHz bus, 33.6 MHz flash, USB = 168 * 2 / 7 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(6) | SIM_CLKDIV2_USBFRAC; +#elif F_CPU == 144000000 + // config divisors: 144 MHz core, 48 MHz bus, 28.8 MHz flash, USB = 144 / 3 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(2) | SIM_CLKDIV1_OUTDIV4(4); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2); +#elif F_CPU == 120000000 + // config divisors: 120 MHz core, 60 MHz bus, 24 MHz flash, USB = 128 * 2 / 5 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(4); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC; +#elif F_CPU == 96000000 + // config divisors: 96 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); +#elif F_CPU == 72000000 + // config divisors: 72 MHz core, 36 MHz bus, 24 MHz flash, USB = 72 * 2 / 3 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(2); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC; +#elif F_CPU == 48000000 + // config divisors: 48 MHz core, 48 MHz bus, 24 MHz flash, USB = 96 / 2 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(3); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); +#elif F_CPU == 24000000 + // config divisors: 24 MHz core, 24 MHz bus, 24 MHz flash, USB = 96 / 2 + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3); + SIM_CLKDIV2 = SIM_CLKDIV2_USBDIV(1); +#elif F_CPU == 16000000 + // config divisors: 16 MHz core, 16 MHz bus, 16 MHz flash + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(0); +#elif F_CPU == 8000000 + // config divisors: 8 MHz core, 8 MHz bus, 8 MHz flash + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(1) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV4(1); +#elif F_CPU == 4000000 + // config divisors: 4 MHz core, 4 MHz bus, 2 MHz flash + // since we are running from external clock 16MHz + // fix outdiv too -> cpu 16/4, bus 16/4, flash 16/4 + // here we can go into vlpr? + // config divisors: 4 MHz core, 4 MHz bus, 4 MHz flash + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(3) | SIM_CLKDIV1_OUTDIV2(3) | SIM_CLKDIV1_OUTDIV4(3); +#elif F_CPU == 2000000 + // since we are running from the fast internal reference clock 4MHz + // but is divided down by 2 so we actually have a 2MHz, MCG_SC[FCDIV] default is 2 + // fix outdiv -> cpu 2/1, bus 2/1, flash 2/2 + // config divisors: 2 MHz core, 2 MHz bus, 1 MHz flash + SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV4(1); +#else +#error "Error, F_CPU must be 168, 144, 120, 96, 72, 48, 24, 16, 8, 4, or 2 MHz" +#endif + +#if F_CPU > 16000000 + // switch to PLL as clock source, FLL input = 16 MHz / 512 + MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4); + // wait for PLL clock to be used + while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST(3)) ; + // now we're in PEE mode + // USB uses PLL clock, trace is CPU clock, CLKOUT=OSCERCLK0 + SIM_SOPT2 = SIM_SOPT2_USBSRC | SIM_SOPT2_PLLFLLSEL | SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(6); +#else + SIM_SOPT2 = SIM_SOPT2_TRACECLKSEL | SIM_SOPT2_CLKOUTSEL(3); +#endif + +#if F_CPU <= 2000000 + // since we are not going into "stop mode" i removed it + SMC_PMCTRL = SMC_PMCTRL_RUNM(2); // VLPR mode :-) +#endif + + // initialize the SysTick counter + SYST_RVR = (F_CPU / 1000) - 1; + SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_TICKINT | SYST_CSR_ENABLE; + + //init_pins(); + __enable_irq(); + + _init_Teensyduino_internal_(); + if (RTC_SR & RTC_SR_TIF) { + // TODO: this should probably set the time more agressively, if + // we could reliably detect the first reboot after programming. + rtc_set(TIME_T); + } + + __libc_init_array(); + + startup_late_hook(); + main(); + while (1) ; +} + +char *__brkval = (char *)&_ebss; + +void * _sbrk(int incr) +{ + char *prev = __brkval; + __brkval += incr; + return prev; +} + +__attribute__((weak)) +int _read(int file, char *ptr, int len) +{ + return 0; +} + +__attribute__((weak)) +int _close(int fd) +{ + return -1; +} + +#include + +__attribute__((weak)) +int _fstat(int fd, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; +} + +__attribute__((weak)) +int _isatty(int fd) +{ + return 1; +} + +__attribute__((weak)) +int _lseek(int fd, long long offset, int whence) +{ + return -1; +} + +__attribute__((weak)) +void _exit(int status) +{ + while (1); +} + +__attribute__((weak)) +void __cxa_pure_virtual() +{ + while (1); +} + +__attribute__((weak)) +int __cxa_guard_acquire (char *g) +{ + return !(*g); +} + +__attribute__((weak)) +void __cxa_guard_release(char *g) +{ + *g = 1; +} + +int nvic_execution_priority(void) +{ + int priority=256; + uint32_t primask, faultmask, basepri, ipsr; + + // full algorithm in ARM DDI0403D, page B1-639 + // this isn't quite complete, but hopefully good enough + __asm__ volatile("mrs %0, faultmask\n" : "=r" (faultmask)::); + if (faultmask) return -1; + __asm__ volatile("mrs %0, primask\n" : "=r" (primask)::); + if (primask) return 0; + __asm__ volatile("mrs %0, ipsr\n" : "=r" (ipsr)::); + if (ipsr) { + if (ipsr < 16) priority = 0; // could be non-zero + else priority = NVIC_GET_PRIORITY(ipsr - 16); + } + __asm__ volatile("mrs %0, basepri\n" : "=r" (basepri)::); + if (basepri > 0 && basepri < priority) priority = basepri; + return priority; +} + diff --git a/src/openmv/src/micropython/ports/teensy/core/mk20dx128.h b/src/openmv/src/micropython/ports/teensy/core/mk20dx128.h new file mode 100755 index 0000000..ab13760 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/mk20dx128.h @@ -0,0 +1,2385 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _mk20dx128_h_ +#define _mk20dx128_h_ + +//#ifdef F_CPU +//#undef F_CPU +//#endif +//#define F_CPU 168000000 +//#define F_CPU 144000000 +//#define F_CPU 120000000 +//#define F_CPU 96000000 +//#define F_CPU 72000000 +//#define F_CPU 48000000 +//#define F_CPU 24000000 + +#if (F_CPU == 168000000) + #define F_BUS 56000000 + #define F_MEM 33600000 +#elif (F_CPU == 144000000) + #define F_BUS 48000000 + #define F_MEM 28800000 +#elif (F_CPU == 120000000) + #define F_BUS 60000000 + #define F_MEM 24000000 +#elif (F_CPU == 96000000) + #define F_BUS 48000000 + #define F_MEM 24000000 +#elif (F_CPU == 72000000) + #define F_BUS 36000000 + #define F_MEM 24000000 +#elif (F_CPU == 48000000) + #define F_BUS 48000000 + #define F_MEM 24000000 +#elif (F_CPU == 24000000) + #define F_BUS 24000000 + #define F_MEM 24000000 +#elif (F_CPU == 16000000) + #define F_BUS 16000000 + #define F_MEM 16000000 +#elif (F_CPU == 8000000) + #define F_BUS 8000000 + #define F_MEM 8000000 +#elif (F_CPU == 4000000) + #define F_BUS 4000000 + #define F_MEM 4000000 +#elif (F_CPU == 2000000) + #define F_BUS 2000000 + #define F_MEM 1000000 +#endif + + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif + +// chapter 11: Port control and interrupts (PORT) +#define PORTA_PCR0 *(volatile uint32_t *)0x40049000 // Pin Control Register n +#define PORT_PCR_ISF (uint32_t)0x01000000 // Interrupt Status Flag +#define PORT_PCR_IRQC(n) (uint32_t)(((n) & 15) << 16) // Interrupt Configuration +#define PORT_PCR_IRQC_MASK (uint32_t)0x000F0000 +#define PORT_PCR_LK (uint32_t)0x00008000 // Lock Register +#define PORT_PCR_MUX(n) (uint32_t)(((n) & 7) << 8) // Pin Mux Control +#define PORT_PCR_MUX_MASK (uint32_t)0x00000700 +#define PORT_PCR_DSE (uint32_t)0x00000040 // Drive Strength Enable +#define PORT_PCR_ODE (uint32_t)0x00000020 // Open Drain Enable +#define PORT_PCR_PFE (uint32_t)0x00000010 // Passive Filter Enable +#define PORT_PCR_SRE (uint32_t)0x00000004 // Slew Rate Enable +#define PORT_PCR_PE (uint32_t)0x00000002 // Pull Enable +#define PORT_PCR_PS (uint32_t)0x00000001 // Pull Select +#define PORTA_PCR1 *(volatile uint32_t *)0x40049004 // Pin Control Register n +#define PORTA_PCR2 *(volatile uint32_t *)0x40049008 // Pin Control Register n +#define PORTA_PCR3 *(volatile uint32_t *)0x4004900C // Pin Control Register n +#define PORTA_PCR4 *(volatile uint32_t *)0x40049010 // Pin Control Register n +#define PORTA_PCR5 *(volatile uint32_t *)0x40049014 // Pin Control Register n +#define PORTA_PCR6 *(volatile uint32_t *)0x40049018 // Pin Control Register n +#define PORTA_PCR7 *(volatile uint32_t *)0x4004901C // Pin Control Register n +#define PORTA_PCR8 *(volatile uint32_t *)0x40049020 // Pin Control Register n +#define PORTA_PCR9 *(volatile uint32_t *)0x40049024 // Pin Control Register n +#define PORTA_PCR10 *(volatile uint32_t *)0x40049028 // Pin Control Register n +#define PORTA_PCR11 *(volatile uint32_t *)0x4004902C // Pin Control Register n +#define PORTA_PCR12 *(volatile uint32_t *)0x40049030 // Pin Control Register n +#define PORTA_PCR13 *(volatile uint32_t *)0x40049034 // Pin Control Register n +#define PORTA_PCR14 *(volatile uint32_t *)0x40049038 // Pin Control Register n +#define PORTA_PCR15 *(volatile uint32_t *)0x4004903C // Pin Control Register n +#define PORTA_PCR16 *(volatile uint32_t *)0x40049040 // Pin Control Register n +#define PORTA_PCR17 *(volatile uint32_t *)0x40049044 // Pin Control Register n +#define PORTA_PCR18 *(volatile uint32_t *)0x40049048 // Pin Control Register n +#define PORTA_PCR19 *(volatile uint32_t *)0x4004904C // Pin Control Register n +#define PORTA_PCR20 *(volatile uint32_t *)0x40049050 // Pin Control Register n +#define PORTA_PCR21 *(volatile uint32_t *)0x40049054 // Pin Control Register n +#define PORTA_PCR22 *(volatile uint32_t *)0x40049058 // Pin Control Register n +#define PORTA_PCR23 *(volatile uint32_t *)0x4004905C // Pin Control Register n +#define PORTA_PCR24 *(volatile uint32_t *)0x40049060 // Pin Control Register n +#define PORTA_PCR25 *(volatile uint32_t *)0x40049064 // Pin Control Register n +#define PORTA_PCR26 *(volatile uint32_t *)0x40049068 // Pin Control Register n +#define PORTA_PCR27 *(volatile uint32_t *)0x4004906C // Pin Control Register n +#define PORTA_PCR28 *(volatile uint32_t *)0x40049070 // Pin Control Register n +#define PORTA_PCR29 *(volatile uint32_t *)0x40049074 // Pin Control Register n +#define PORTA_PCR30 *(volatile uint32_t *)0x40049078 // Pin Control Register n +#define PORTA_PCR31 *(volatile uint32_t *)0x4004907C // Pin Control Register n +#define PORTA_GPCLR *(volatile uint32_t *)0x40049080 // Global Pin Control Low Register +#define PORTA_GPCHR *(volatile uint32_t *)0x40049084 // Global Pin Control High Register +#define PORTA_ISFR *(volatile uint32_t *)0x400490A0 // Interrupt Status Flag Register +#define PORTB_PCR0 *(volatile uint32_t *)0x4004A000 // Pin Control Register n +#define PORTB_PCR1 *(volatile uint32_t *)0x4004A004 // Pin Control Register n +#define PORTB_PCR2 *(volatile uint32_t *)0x4004A008 // Pin Control Register n +#define PORTB_PCR3 *(volatile uint32_t *)0x4004A00C // Pin Control Register n +#define PORTB_PCR4 *(volatile uint32_t *)0x4004A010 // Pin Control Register n +#define PORTB_PCR5 *(volatile uint32_t *)0x4004A014 // Pin Control Register n +#define PORTB_PCR6 *(volatile uint32_t *)0x4004A018 // Pin Control Register n +#define PORTB_PCR7 *(volatile uint32_t *)0x4004A01C // Pin Control Register n +#define PORTB_PCR8 *(volatile uint32_t *)0x4004A020 // Pin Control Register n +#define PORTB_PCR9 *(volatile uint32_t *)0x4004A024 // Pin Control Register n +#define PORTB_PCR10 *(volatile uint32_t *)0x4004A028 // Pin Control Register n +#define PORTB_PCR11 *(volatile uint32_t *)0x4004A02C // Pin Control Register n +#define PORTB_PCR12 *(volatile uint32_t *)0x4004A030 // Pin Control Register n +#define PORTB_PCR13 *(volatile uint32_t *)0x4004A034 // Pin Control Register n +#define PORTB_PCR14 *(volatile uint32_t *)0x4004A038 // Pin Control Register n +#define PORTB_PCR15 *(volatile uint32_t *)0x4004A03C // Pin Control Register n +#define PORTB_PCR16 *(volatile uint32_t *)0x4004A040 // Pin Control Register n +#define PORTB_PCR17 *(volatile uint32_t *)0x4004A044 // Pin Control Register n +#define PORTB_PCR18 *(volatile uint32_t *)0x4004A048 // Pin Control Register n +#define PORTB_PCR19 *(volatile uint32_t *)0x4004A04C // Pin Control Register n +#define PORTB_PCR20 *(volatile uint32_t *)0x4004A050 // Pin Control Register n +#define PORTB_PCR21 *(volatile uint32_t *)0x4004A054 // Pin Control Register n +#define PORTB_PCR22 *(volatile uint32_t *)0x4004A058 // Pin Control Register n +#define PORTB_PCR23 *(volatile uint32_t *)0x4004A05C // Pin Control Register n +#define PORTB_PCR24 *(volatile uint32_t *)0x4004A060 // Pin Control Register n +#define PORTB_PCR25 *(volatile uint32_t *)0x4004A064 // Pin Control Register n +#define PORTB_PCR26 *(volatile uint32_t *)0x4004A068 // Pin Control Register n +#define PORTB_PCR27 *(volatile uint32_t *)0x4004A06C // Pin Control Register n +#define PORTB_PCR28 *(volatile uint32_t *)0x4004A070 // Pin Control Register n +#define PORTB_PCR29 *(volatile uint32_t *)0x4004A074 // Pin Control Register n +#define PORTB_PCR30 *(volatile uint32_t *)0x4004A078 // Pin Control Register n +#define PORTB_PCR31 *(volatile uint32_t *)0x4004A07C // Pin Control Register n +#define PORTB_GPCLR *(volatile uint32_t *)0x4004A080 // Global Pin Control Low Register +#define PORTB_GPCHR *(volatile uint32_t *)0x4004A084 // Global Pin Control High Register +#define PORTB_ISFR *(volatile uint32_t *)0x4004A0A0 // Interrupt Status Flag Register +#define PORTC_PCR0 *(volatile uint32_t *)0x4004B000 // Pin Control Register n +#define PORTC_PCR1 *(volatile uint32_t *)0x4004B004 // Pin Control Register n +#define PORTC_PCR2 *(volatile uint32_t *)0x4004B008 // Pin Control Register n +#define PORTC_PCR3 *(volatile uint32_t *)0x4004B00C // Pin Control Register n +#define PORTC_PCR4 *(volatile uint32_t *)0x4004B010 // Pin Control Register n +#define PORTC_PCR5 *(volatile uint32_t *)0x4004B014 // Pin Control Register n +#define PORTC_PCR6 *(volatile uint32_t *)0x4004B018 // Pin Control Register n +#define PORTC_PCR7 *(volatile uint32_t *)0x4004B01C // Pin Control Register n +#define PORTC_PCR8 *(volatile uint32_t *)0x4004B020 // Pin Control Register n +#define PORTC_PCR9 *(volatile uint32_t *)0x4004B024 // Pin Control Register n +#define PORTC_PCR10 *(volatile uint32_t *)0x4004B028 // Pin Control Register n +#define PORTC_PCR11 *(volatile uint32_t *)0x4004B02C // Pin Control Register n +#define PORTC_PCR12 *(volatile uint32_t *)0x4004B030 // Pin Control Register n +#define PORTC_PCR13 *(volatile uint32_t *)0x4004B034 // Pin Control Register n +#define PORTC_PCR14 *(volatile uint32_t *)0x4004B038 // Pin Control Register n +#define PORTC_PCR15 *(volatile uint32_t *)0x4004B03C // Pin Control Register n +#define PORTC_PCR16 *(volatile uint32_t *)0x4004B040 // Pin Control Register n +#define PORTC_PCR17 *(volatile uint32_t *)0x4004B044 // Pin Control Register n +#define PORTC_PCR18 *(volatile uint32_t *)0x4004B048 // Pin Control Register n +#define PORTC_PCR19 *(volatile uint32_t *)0x4004B04C // Pin Control Register n +#define PORTC_PCR20 *(volatile uint32_t *)0x4004B050 // Pin Control Register n +#define PORTC_PCR21 *(volatile uint32_t *)0x4004B054 // Pin Control Register n +#define PORTC_PCR22 *(volatile uint32_t *)0x4004B058 // Pin Control Register n +#define PORTC_PCR23 *(volatile uint32_t *)0x4004B05C // Pin Control Register n +#define PORTC_PCR24 *(volatile uint32_t *)0x4004B060 // Pin Control Register n +#define PORTC_PCR25 *(volatile uint32_t *)0x4004B064 // Pin Control Register n +#define PORTC_PCR26 *(volatile uint32_t *)0x4004B068 // Pin Control Register n +#define PORTC_PCR27 *(volatile uint32_t *)0x4004B06C // Pin Control Register n +#define PORTC_PCR28 *(volatile uint32_t *)0x4004B070 // Pin Control Register n +#define PORTC_PCR29 *(volatile uint32_t *)0x4004B074 // Pin Control Register n +#define PORTC_PCR30 *(volatile uint32_t *)0x4004B078 // Pin Control Register n +#define PORTC_PCR31 *(volatile uint32_t *)0x4004B07C // Pin Control Register n +#define PORTC_GPCLR *(volatile uint32_t *)0x4004B080 // Global Pin Control Low Register +#define PORTC_GPCHR *(volatile uint32_t *)0x4004B084 // Global Pin Control High Register +#define PORTC_ISFR *(volatile uint32_t *)0x4004B0A0 // Interrupt Status Flag Register +#define PORTD_PCR0 *(volatile uint32_t *)0x4004C000 // Pin Control Register n +#define PORTD_PCR1 *(volatile uint32_t *)0x4004C004 // Pin Control Register n +#define PORTD_PCR2 *(volatile uint32_t *)0x4004C008 // Pin Control Register n +#define PORTD_PCR3 *(volatile uint32_t *)0x4004C00C // Pin Control Register n +#define PORTD_PCR4 *(volatile uint32_t *)0x4004C010 // Pin Control Register n +#define PORTD_PCR5 *(volatile uint32_t *)0x4004C014 // Pin Control Register n +#define PORTD_PCR6 *(volatile uint32_t *)0x4004C018 // Pin Control Register n +#define PORTD_PCR7 *(volatile uint32_t *)0x4004C01C // Pin Control Register n +#define PORTD_PCR8 *(volatile uint32_t *)0x4004C020 // Pin Control Register n +#define PORTD_PCR9 *(volatile uint32_t *)0x4004C024 // Pin Control Register n +#define PORTD_PCR10 *(volatile uint32_t *)0x4004C028 // Pin Control Register n +#define PORTD_PCR11 *(volatile uint32_t *)0x4004C02C // Pin Control Register n +#define PORTD_PCR12 *(volatile uint32_t *)0x4004C030 // Pin Control Register n +#define PORTD_PCR13 *(volatile uint32_t *)0x4004C034 // Pin Control Register n +#define PORTD_PCR14 *(volatile uint32_t *)0x4004C038 // Pin Control Register n +#define PORTD_PCR15 *(volatile uint32_t *)0x4004C03C // Pin Control Register n +#define PORTD_PCR16 *(volatile uint32_t *)0x4004C040 // Pin Control Register n +#define PORTD_PCR17 *(volatile uint32_t *)0x4004C044 // Pin Control Register n +#define PORTD_PCR18 *(volatile uint32_t *)0x4004C048 // Pin Control Register n +#define PORTD_PCR19 *(volatile uint32_t *)0x4004C04C // Pin Control Register n +#define PORTD_PCR20 *(volatile uint32_t *)0x4004C050 // Pin Control Register n +#define PORTD_PCR21 *(volatile uint32_t *)0x4004C054 // Pin Control Register n +#define PORTD_PCR22 *(volatile uint32_t *)0x4004C058 // Pin Control Register n +#define PORTD_PCR23 *(volatile uint32_t *)0x4004C05C // Pin Control Register n +#define PORTD_PCR24 *(volatile uint32_t *)0x4004C060 // Pin Control Register n +#define PORTD_PCR25 *(volatile uint32_t *)0x4004C064 // Pin Control Register n +#define PORTD_PCR26 *(volatile uint32_t *)0x4004C068 // Pin Control Register n +#define PORTD_PCR27 *(volatile uint32_t *)0x4004C06C // Pin Control Register n +#define PORTD_PCR28 *(volatile uint32_t *)0x4004C070 // Pin Control Register n +#define PORTD_PCR29 *(volatile uint32_t *)0x4004C074 // Pin Control Register n +#define PORTD_PCR30 *(volatile uint32_t *)0x4004C078 // Pin Control Register n +#define PORTD_PCR31 *(volatile uint32_t *)0x4004C07C // Pin Control Register n +#define PORTD_GPCLR *(volatile uint32_t *)0x4004C080 // Global Pin Control Low Register +#define PORTD_GPCHR *(volatile uint32_t *)0x4004C084 // Global Pin Control High Register +#define PORTD_ISFR *(volatile uint32_t *)0x4004C0A0 // Interrupt Status Flag Register +#define PORTE_PCR0 *(volatile uint32_t *)0x4004D000 // Pin Control Register n +#define PORTE_PCR1 *(volatile uint32_t *)0x4004D004 // Pin Control Register n +#define PORTE_PCR2 *(volatile uint32_t *)0x4004D008 // Pin Control Register n +#define PORTE_PCR3 *(volatile uint32_t *)0x4004D00C // Pin Control Register n +#define PORTE_PCR4 *(volatile uint32_t *)0x4004D010 // Pin Control Register n +#define PORTE_PCR5 *(volatile uint32_t *)0x4004D014 // Pin Control Register n +#define PORTE_PCR6 *(volatile uint32_t *)0x4004D018 // Pin Control Register n +#define PORTE_PCR7 *(volatile uint32_t *)0x4004D01C // Pin Control Register n +#define PORTE_PCR8 *(volatile uint32_t *)0x4004D020 // Pin Control Register n +#define PORTE_PCR9 *(volatile uint32_t *)0x4004D024 // Pin Control Register n +#define PORTE_PCR10 *(volatile uint32_t *)0x4004D028 // Pin Control Register n +#define PORTE_PCR11 *(volatile uint32_t *)0x4004D02C // Pin Control Register n +#define PORTE_PCR12 *(volatile uint32_t *)0x4004D030 // Pin Control Register n +#define PORTE_PCR13 *(volatile uint32_t *)0x4004D034 // Pin Control Register n +#define PORTE_PCR14 *(volatile uint32_t *)0x4004D038 // Pin Control Register n +#define PORTE_PCR15 *(volatile uint32_t *)0x4004D03C // Pin Control Register n +#define PORTE_PCR16 *(volatile uint32_t *)0x4004D040 // Pin Control Register n +#define PORTE_PCR17 *(volatile uint32_t *)0x4004D044 // Pin Control Register n +#define PORTE_PCR18 *(volatile uint32_t *)0x4004D048 // Pin Control Register n +#define PORTE_PCR19 *(volatile uint32_t *)0x4004D04C // Pin Control Register n +#define PORTE_PCR20 *(volatile uint32_t *)0x4004D050 // Pin Control Register n +#define PORTE_PCR21 *(volatile uint32_t *)0x4004D054 // Pin Control Register n +#define PORTE_PCR22 *(volatile uint32_t *)0x4004D058 // Pin Control Register n +#define PORTE_PCR23 *(volatile uint32_t *)0x4004D05C // Pin Control Register n +#define PORTE_PCR24 *(volatile uint32_t *)0x4004D060 // Pin Control Register n +#define PORTE_PCR25 *(volatile uint32_t *)0x4004D064 // Pin Control Register n +#define PORTE_PCR26 *(volatile uint32_t *)0x4004D068 // Pin Control Register n +#define PORTE_PCR27 *(volatile uint32_t *)0x4004D06C // Pin Control Register n +#define PORTE_PCR28 *(volatile uint32_t *)0x4004D070 // Pin Control Register n +#define PORTE_PCR29 *(volatile uint32_t *)0x4004D074 // Pin Control Register n +#define PORTE_PCR30 *(volatile uint32_t *)0x4004D078 // Pin Control Register n +#define PORTE_PCR31 *(volatile uint32_t *)0x4004D07C // Pin Control Register n +#define PORTE_GPCLR *(volatile uint32_t *)0x4004D080 // Global Pin Control Low Register +#define PORTE_GPCHR *(volatile uint32_t *)0x4004D084 // Global Pin Control High Register +#define PORTE_ISFR *(volatile uint32_t *)0x4004D0A0 // Interrupt Status Flag Register + +// Chapter 12: System Integration Module (SIM) +#define SIM_SOPT1 *(volatile uint32_t *)0x40047000 // System Options Register 1 +#define SIM_SOPT1CFG *(volatile uint32_t *)0x40047004 // SOPT1 Configuration Register +#define SIM_SOPT2 *(volatile uint32_t *)0x40048004 // System Options Register 2 +#define SIM_SOPT2_USBSRC (uint32_t)0x00040000 // 0=USB_CLKIN, 1=FFL/PLL +#define SIM_SOPT2_PLLFLLSEL (uint32_t)0x00010000 // 0=FLL, 1=PLL +#define SIM_SOPT2_TRACECLKSEL (uint32_t)0x00001000 // 0=MCGOUTCLK, 1=CPU +#define SIM_SOPT2_PTD7PAD (uint32_t)0x00000800 // 0=normal, 1=double drive PTD7 +#define SIM_SOPT2_CLKOUTSEL(n) (uint32_t)(((n) & 7) << 5) // Selects the clock to output on the CLKOUT pin. +#define SIM_SOPT2_RTCCLKOUTSEL (uint32_t)0x00000010 // RTC clock out select +#define SIM_SOPT4 *(volatile uint32_t *)0x4004800C // System Options Register 4 +#define SIM_SOPT5 *(volatile uint32_t *)0x40048010 // System Options Register 5 +#define SIM_SOPT7 *(volatile uint32_t *)0x40048018 // System Options Register 7 +#define SIM_SDID *(const uint32_t *)0x40048024 // System Device Identification Register +#define SIM_SCGC2 *(volatile uint32_t *)0x4004802C // System Clock Gating Control Register 2 +#define SIM_SCGC2_DAC0 (uint32_t)0x00001000 // DAC0 Clock Gate Control +#define SIM_SCGC3 *(volatile uint32_t *)0x40048030 // System Clock Gating Control Register 3 +#define SIM_SCGC3_ADC1 (uint32_t)0x08000000 // ADC1 Clock Gate Control +#define SIM_SCGC3_FTM2 (uint32_t)0x01000000 // FTM2 Clock Gate Control +#define SIM_SCGC4 *(volatile uint32_t *)0x40048034 // System Clock Gating Control Register 4 +#define SIM_SCGC4_VREF (uint32_t)0x00100000 // VREF Clock Gate Control +#define SIM_SCGC4_CMP (uint32_t)0x00080000 // Comparator Clock Gate Control +#define SIM_SCGC4_USBOTG (uint32_t)0x00040000 // USB Clock Gate Control +#define SIM_SCGC4_UART2 (uint32_t)0x00001000 // UART2 Clock Gate Control +#define SIM_SCGC4_UART1 (uint32_t)0x00000800 // UART1 Clock Gate Control +#define SIM_SCGC4_UART0 (uint32_t)0x00000400 // UART0 Clock Gate Control +#define SIM_SCGC4_I2C1 (uint32_t)0x00000080 // I2C1 Clock Gate Control +#define SIM_SCGC4_I2C0 (uint32_t)0x00000040 // I2C0 Clock Gate Control +#define SIM_SCGC4_CMT (uint32_t)0x00000004 // CMT Clock Gate Control +#define SIM_SCGC4_EWM (uint32_t)0x00000002 // EWM Clock Gate Control +#define SIM_SCGC5 *(volatile uint32_t *)0x40048038 // System Clock Gating Control Register 5 +#define SIM_SCGC5_PORTE (uint32_t)0x00002000 // Port E Clock Gate Control +#define SIM_SCGC5_PORTD (uint32_t)0x00001000 // Port D Clock Gate Control +#define SIM_SCGC5_PORTC (uint32_t)0x00000800 // Port C Clock Gate Control +#define SIM_SCGC5_PORTB (uint32_t)0x00000400 // Port B Clock Gate Control +#define SIM_SCGC5_PORTA (uint32_t)0x00000200 // Port A Clock Gate Control +#define SIM_SCGC5_TSI (uint32_t)0x00000020 // Touch Sense Input TSI Clock Gate Control +#define SIM_SCGC5_LPTIMER (uint32_t)0x00000001 // Low Power Timer Access Control +#define SIM_SCGC6 *(volatile uint32_t *)0x4004803C // System Clock Gating Control Register 6 +#define SIM_SCGC6_RTC (uint32_t)0x20000000 // RTC Access +#define SIM_SCGC6_ADC0 (uint32_t)0x08000000 // ADC0 Clock Gate Control +#define SIM_SCGC6_FTM1 (uint32_t)0x02000000 // FTM1 Clock Gate Control +#define SIM_SCGC6_FTM0 (uint32_t)0x01000000 // FTM0 Clock Gate Control +#define SIM_SCGC6_PIT (uint32_t)0x00800000 // PIT Clock Gate Control +#define SIM_SCGC6_PDB (uint32_t)0x00400000 // PDB Clock Gate Control +#define SIM_SCGC6_USBDCD (uint32_t)0x00200000 // USB DCD Clock Gate Control +#define SIM_SCGC6_CRC (uint32_t)0x00040000 // CRC Clock Gate Control +#define SIM_SCGC6_I2S (uint32_t)0x00008000 // I2S Clock Gate Control +#define SIM_SCGC6_SPI1 (uint32_t)0x00002000 // SPI1 Clock Gate Control +#define SIM_SCGC6_SPI0 (uint32_t)0x00001000 // SPI0 Clock Gate Control +#define SIM_SCGC6_FLEXCAN0 (uint32_t)0x00000010 // FlexCAN0 Clock Gate Control +#define SIM_SCGC6_DMAMUX (uint32_t)0x00000002 // DMA Mux Clock Gate Control +#define SIM_SCGC6_FTFL (uint32_t)0x00000001 // Flash Memory Clock Gate Control +#define SIM_SCGC7 *(volatile uint32_t *)0x40048040 // System Clock Gating Control Register 7 +#define SIM_SCGC7_DMA (uint32_t)0x00000002 // DMA Clock Gate Control +#define SIM_CLKDIV1 *(volatile uint32_t *)0x40048044 // System Clock Divider Register 1 +#define SIM_CLKDIV1_OUTDIV1(n) (uint32_t)(((n) & 0x0F) << 28) // divide value for the core/system clock +#define SIM_CLKDIV1_OUTDIV2(n) (uint32_t)(((n) & 0x0F) << 24) // divide value for the peripheral clock +#define SIM_CLKDIV1_OUTDIV4(n) (uint32_t)(((n) & 0x0F) << 16) // divide value for the flash clock +#define SIM_CLKDIV2 *(volatile uint32_t *)0x40048048 // System Clock Divider Register 2 +#define SIM_CLKDIV2_USBDIV(n) (uint32_t)(((n) & 0x07) << 1) +#define SIM_CLKDIV2_USBFRAC (uint32_t)0x01 +#define SIM_FCFG1 *(const uint32_t *)0x4004804C // Flash Configuration Register 1 +#define SIM_FCFG2 *(const uint32_t *)0x40048050 // Flash Configuration Register 2 +#define SIM_UIDH *(const uint32_t *)0x40048054 // Unique Identification Register High +#define SIM_UIDMH *(const uint32_t *)0x40048058 // Unique Identification Register Mid-High +#define SIM_UIDML *(const uint32_t *)0x4004805C // Unique Identification Register Mid Low +#define SIM_UIDL *(const uint32_t *)0x40048060 // Unique Identification Register Low + +// Chapter 13: Reset Control Module (RCM) +#define RCM_SRS0 *(volatile uint8_t *)0x4007F000 // System Reset Status Register 0 +#define RCM_SRS1 *(volatile uint8_t *)0x4007F001 // System Reset Status Register 1 +#define RCM_RPFC *(volatile uint8_t *)0x4007F004 // Reset Pin Filter Control Register +#define RCM_RPFW *(volatile uint8_t *)0x4007F005 // Reset Pin Filter Width Register +#define RCM_MR *(volatile uint8_t *)0x4007F007 // Mode Register + +// Chapter 14: System Mode Controller +#define SMC_PMPROT *(volatile uint8_t *)0x4007E000 // Power Mode Protection Register +#define SMC_PMPROT_AVLP (uint8_t)0x20 // Allow very low power modes +#define SMC_PMPROT_ALLS (uint8_t)0x08 // Allow low leakage stop mode +#define SMC_PMPROT_AVLLS (uint8_t)0x02 // Allow very low leakage stop mode +#define SMC_PMCTRL *(volatile uint8_t *)0x4007E001 // Power Mode Control Register +#define SMC_PMCTRL_LPWUI (uint8_t)0x80 // Low Power Wake Up on Interrupt +#define SMC_PMCTRL_RUNM(n) (uint8_t)(((n) & 0x03) << 5) // Run Mode Control +#define SMC_PMCTRL_STOPA (uint8_t)0x08 // Stop Aborted +#define SMC_PMCTRL_STOPM(n) (uint8_t)((n) & 0x07) // Stop Mode Control +#define SMC_VLLSCTRL *(volatile uint8_t *)0x4007E002 // VLLS Control Register +#define SMC_VLLSCTRL_PORPO (uint8_t)0x20 // POR Power Option +#define SMC_VLLSCTRL_VLLSM(n) (uint8_t)((n) & 0x07) // VLLS Mode Control +#define SMC_PMSTAT *(volatile uint8_t *)0x4007E003 // Power Mode Status Register +#define SMC_PMSTAT_RUN (uint8_t)0x01 // Current power mode is RUN +#define SMC_PMSTAT_STOP (uint8_t)0x02 // Current power mode is STOP +#define SMC_PMSTAT_VLPR (uint8_t)0x04 // Current power mode is VLPR +#define SMC_PMSTAT_VLPW (uint8_t)0x08 // Current power mode is VLPW +#define SMC_PMSTAT_VLPS (uint8_t)0x10 // Current power mode is VLPS +#define SMC_PMSTAT_LLS (uint8_t)0x20 // Current power mode is LLS +#define SMC_PMSTAT_VLLS (uint8_t)0x40 // Current power mode is VLLS + +// Chapter 15: Power Management Controller +#define PMC_LVDSC1 *(volatile uint8_t *)0x4007D000 // Low Voltage Detect Status And Control 1 register +#define PMC_LVDSC1_LVDF (uint8_t)0x80 // Low-Voltage Detect Flag +#define PMC_LVDSC1_LVDACK (uint8_t)0x40 // Low-Voltage Detect Acknowledge +#define PMC_LVDSC1_LVDIE (uint8_t)0x20 // Low-Voltage Detect Interrupt Enable +#define PMC_LVDSC1_LVDRE (uint8_t)0x10 // Low-Voltage Detect Reset Enable +#define PMC_LVDSC1_LVDV(n) (uint8_t)((n) & 0x03) // Low-Voltage Detect Voltage Select +#define PMC_LVDSC2 *(volatile uint8_t *)0x4007D001 // Low Voltage Detect Status And Control 2 register +#define PMC_LVDSC2_LVWF (uint8_t)0x80 // Low-Voltage Warning Flag +#define PMC_LVDSC2_LVWACK (uint8_t)0x40 // Low-Voltage Warning Acknowledge +#define PMC_LVDSC2_LVWIE (uint8_t)0x20 // Low-Voltage Warning Interrupt Enable +#define PMC_LVDSC2_LVWV(n) (uint8_t)((n) & 0x03) // Low-Voltage Warning Voltage Select +#define PMC_REGSC *(volatile uint8_t *)0x4007D002 // Regulator Status And Control register +#define PMC_REGSC_BGEN (uint8_t)0x10 // Bandgap Enable In VLPx Operation +#define PMC_REGSC_ACKISO (uint8_t)0x08 // Acknowledge Isolation +#define PMC_REGSC_REGONS (uint8_t)0x04 // Regulator In Run Regulation Status +#define PMC_REGSC_BGBE (uint8_t)0x01 // Bandgap Buffer Enable + +// Chapter 16: Low-Leakage Wakeup Unit (LLWU) +#define LLWU_PE1 *(volatile uint8_t *)0x4007C000 // LLWU Pin Enable 1 register +#define LLWU_PE2 *(volatile uint8_t *)0x4007C001 // LLWU Pin Enable 2 register +#define LLWU_PE3 *(volatile uint8_t *)0x4007C002 // LLWU Pin Enable 3 register +#define LLWU_PE4 *(volatile uint8_t *)0x4007C003 // LLWU Pin Enable 4 register +#define LLWU_ME *(volatile uint8_t *)0x4007C004 // LLWU Module Enable register +#define LLWU_F1 *(volatile uint8_t *)0x4007C005 // LLWU Flag 1 register +#define LLWU_F2 *(volatile uint8_t *)0x4007C006 // LLWU Flag 2 register +#define LLWU_F3 *(volatile uint8_t *)0x4007C007 // LLWU Flag 3 register +#define LLWU_FILT1 *(volatile uint8_t *)0x4007C008 // LLWU Pin Filter 1 register +#define LLWU_FILT2 *(volatile uint8_t *)0x4007C009 // LLWU Pin Filter 2 register +#define LLWU_RST *(volatile uint8_t *)0x4007C00A // LLWU Reset Enable register + +// Chapter 17: Miscellaneous Control Module (MCM) +#define MCM_PLASC *(volatile uint16_t *)0xE0080008 // Crossbar Switch (AXBS) Slave Configuration +#define MCM_PLAMC *(volatile uint16_t *)0xE008000A // Crossbar Switch (AXBS) Master Configuration +#define MCM_PLACR *(volatile uint32_t *)0xE008000C // Crossbar Switch (AXBS) Control Register (MK20DX128) +#define MCM_PLACR_ARG (uint32_t)0x00000200 // Arbitration select, 0=fixed, 1=round-robin +#define MCM_CR *(volatile uint32_t *)0xE008000C // RAM arbitration control register (MK20DX256) +#define MCM_CR_SRAMLWP (uint32_t)0x40000000 // SRAM_L write protect +#define MCM_CR_SRAMLAP(n) (uint32_t)(((n) & 0x03) << 28) // SRAM_L priority, 0=RR, 1=favor DMA, 2=CPU, 3=DMA +#define MCM_CR_SRAMUWP (uint32_t)0x04000000 // SRAM_U write protect +#define MCM_CR_SRAMUAP(n) (uint32_t)(((n) & 0x03) << 24) // SRAM_U priority, 0=RR, 1=favor DMA, 2=CPU, 3=DMA + +// Crossbar Switch (AXBS) - only programmable on MK20DX256 +#define AXBS_PRS0 *(volatile uint32_t *)0x40004000 // Priority Registers Slave 0 +#define AXBS_CRS0 *(volatile uint32_t *)0x40004010 // Control Register 0 +#define AXBS_PRS1 *(volatile uint32_t *)0x40004100 // Priority Registers Slave 1 +#define AXBS_CRS1 *(volatile uint32_t *)0x40004110 // Control Register 1 +#define AXBS_PRS2 *(volatile uint32_t *)0x40004200 // Priority Registers Slave 2 +#define AXBS_CRS2 *(volatile uint32_t *)0x40004210 // Control Register 2 +#define AXBS_PRS3 *(volatile uint32_t *)0x40004300 // Priority Registers Slave 3 +#define AXBS_CRS3 *(volatile uint32_t *)0x40004310 // Control Register 3 +#define AXBS_PRS4 *(volatile uint32_t *)0x40004400 // Priority Registers Slave 4 +#define AXBS_CRS4 *(volatile uint32_t *)0x40004410 // Control Register 4 +#define AXBS_PRS5 *(volatile uint32_t *)0x40004500 // Priority Registers Slave 5 +#define AXBS_CRS5 *(volatile uint32_t *)0x40004510 // Control Register 5 +#define AXBS_PRS6 *(volatile uint32_t *)0x40004600 // Priority Registers Slave 6 +#define AXBS_CRS6 *(volatile uint32_t *)0x40004610 // Control Register 6 +#define AXBS_PRS7 *(volatile uint32_t *)0x40004700 // Priority Registers Slave 7 +#define AXBS_CRS7 *(volatile uint32_t *)0x40004710 // Control Register 7 +#define AXBS_MGPCR0 *(volatile uint32_t *)0x40004800 // Master 0 General Purpose Control Register +#define AXBS_MGPCR1 *(volatile uint32_t *)0x40004900 // Master 1 General Purpose Control Register +#define AXBS_MGPCR2 *(volatile uint32_t *)0x40004A00 // Master 2 General Purpose Control Register +#define AXBS_MGPCR3 *(volatile uint32_t *)0x40004B00 // Master 3 General Purpose Control Register +#define AXBS_MGPCR4 *(volatile uint32_t *)0x40004C00 // Master 4 General Purpose Control Register +#define AXBS_MGPCR5 *(volatile uint32_t *)0x40004D00 // Master 5 General Purpose Control Register +#define AXBS_MGPCR6 *(volatile uint32_t *)0x40004E00 // Master 6 General Purpose Control Register +#define AXBS_MGPCR7 *(volatile uint32_t *)0x40004F00 // Master 7 General Purpose Control Register +#define AXBS_CRS_READONLY (uint32_t)0x80000000 +#define AXBS_CRS_HALTLOWPRIORITY (uint32_t)0x40000000 +#define AXBS_CRS_ARB_FIXED (uint32_t)0x00000000 +#define AXBS_CRS_ARB_ROUNDROBIN (uint32_t)0x00010000 +#define AXBS_CRS_PARK_FIXED (uint32_t)0x00000000 +#define AXBS_CRS_PARK_PREVIOUS (uint32_t)0x00000010 +#define AXBS_CRS_PARK_NONE (uint32_t)0x00000020 +#define AXBS_CRS_PARK(n) (uint32_t)(((n) & 7) << 0) + + + +// Chapter 20: Direct Memory Access Multiplexer (DMAMUX) +#define DMAMUX0_CHCFG0 *(volatile uint8_t *)0x40021000 // Channel Configuration register +#define DMAMUX0_CHCFG1 *(volatile uint8_t *)0x40021001 // Channel Configuration register +#define DMAMUX0_CHCFG2 *(volatile uint8_t *)0x40021002 // Channel Configuration register +#define DMAMUX0_CHCFG3 *(volatile uint8_t *)0x40021003 // Channel Configuration register +#define DMAMUX0_CHCFG4 *(volatile uint8_t *)0x40021004 // Channel Configuration register +#define DMAMUX0_CHCFG5 *(volatile uint8_t *)0x40021005 // Channel Configuration register +#define DMAMUX0_CHCFG6 *(volatile uint8_t *)0x40021006 // Channel Configuration register +#define DMAMUX0_CHCFG7 *(volatile uint8_t *)0x40021007 // Channel Configuration register +#define DMAMUX0_CHCFG8 *(volatile uint8_t *)0x40021008 // Channel Configuration register +#define DMAMUX0_CHCFG9 *(volatile uint8_t *)0x40021009 // Channel Configuration register +#define DMAMUX0_CHCFG10 *(volatile uint8_t *)0x4002100A // Channel Configuration register +#define DMAMUX0_CHCFG11 *(volatile uint8_t *)0x4002100B // Channel Configuration register +#define DMAMUX0_CHCFG12 *(volatile uint8_t *)0x4002100C // Channel Configuration register +#define DMAMUX0_CHCFG13 *(volatile uint8_t *)0x4002100D // Channel Configuration register +#define DMAMUX0_CHCFG14 *(volatile uint8_t *)0x4002100E // Channel Configuration register +#define DMAMUX0_CHCFG15 *(volatile uint8_t *)0x4002100F // Channel Configuration register +#define DMAMUX_DISABLE 0 +#define DMAMUX_TRIG 64 +#define DMAMUX_ENABLE 128 +#define DMAMUX_SOURCE_UART0_RX 2 +#define DMAMUX_SOURCE_UART0_TX 3 +#define DMAMUX_SOURCE_UART1_RX 4 +#define DMAMUX_SOURCE_UART1_TX 5 +#define DMAMUX_SOURCE_UART2_RX 6 +#define DMAMUX_SOURCE_UART2_TX 7 +#define DMAMUX_SOURCE_I2S0_RX 14 +#define DMAMUX_SOURCE_I2S0_TX 15 +#define DMAMUX_SOURCE_SPI0_RX 16 +#define DMAMUX_SOURCE_SPI0_TX 17 +#define DMAMUX_SOURCE_I2C0 22 +#define DMAMUX_SOURCE_I2C1 23 +#define DMAMUX_SOURCE_FTM0_CH0 24 +#define DMAMUX_SOURCE_FTM0_CH1 25 +#define DMAMUX_SOURCE_FTM0_CH2 26 +#define DMAMUX_SOURCE_FTM0_CH3 27 +#define DMAMUX_SOURCE_FTM0_CH4 28 +#define DMAMUX_SOURCE_FTM0_CH5 29 +#define DMAMUX_SOURCE_FTM0_CH6 30 +#define DMAMUX_SOURCE_FTM0_CH7 31 +#define DMAMUX_SOURCE_FTM1_CH0 32 +#define DMAMUX_SOURCE_FTM1_CH1 33 +#define DMAMUX_SOURCE_FTM2_CH0 34 +#define DMAMUX_SOURCE_FTM2_CH1 35 +#define DMAMUX_SOURCE_ADC0 40 +#define DMAMUX_SOURCE_ADC1 41 +#define DMAMUX_SOURCE_CMP0 42 +#define DMAMUX_SOURCE_CMP1 43 +#define DMAMUX_SOURCE_CMP2 44 +#define DMAMUX_SOURCE_DAC0 45 +#define DMAMUX_SOURCE_CMT 47 +#define DMAMUX_SOURCE_PDB 48 +#define DMAMUX_SOURCE_PORTA 49 +#define DMAMUX_SOURCE_PORTB 50 +#define DMAMUX_SOURCE_PORTC 51 +#define DMAMUX_SOURCE_PORTD 52 +#define DMAMUX_SOURCE_PORTE 53 +#define DMAMUX_SOURCE_ALWAYS0 54 +#define DMAMUX_SOURCE_ALWAYS1 55 +#define DMAMUX_SOURCE_ALWAYS2 56 +#define DMAMUX_SOURCE_ALWAYS3 57 +#define DMAMUX_SOURCE_ALWAYS4 58 +#define DMAMUX_SOURCE_ALWAYS5 59 +#define DMAMUX_SOURCE_ALWAYS6 60 +#define DMAMUX_SOURCE_ALWAYS7 61 +#define DMAMUX_SOURCE_ALWAYS8 62 +#define DMAMUX_SOURCE_ALWAYS9 63 + +// Chapter 21: Direct Memory Access Controller (eDMA) +#define DMA_CR *(volatile uint32_t *)0x40008000 // Control Register +#define DMA_CR_CX ((uint32_t)(1<<17)) // Cancel Transfer +#define DMA_CR_ECX ((uint32_t)(1<<16)) // Error Cancel Transfer +#define DMA_CR_EMLM ((uint32_t)0x80) // Enable Minor Loop Mapping +#define DMA_CR_CLM ((uint32_t)0x40) // Continuous Link Mode +#define DMA_CR_HALT ((uint32_t)0x20) // Halt DMA Operations +#define DMA_CR_HOE ((uint32_t)0x10) // Halt On Error +#define DMA_CR_ERCA ((uint32_t)0x04) // Enable Round Robin Channel Arbitration +#define DMA_CR_EDBG ((uint32_t)0x02) // Enable Debug +#define DMA_ES *(volatile uint32_t *)0x40008004 // Error Status Register +#define DMA_ERQ *(volatile uint32_t *)0x4000800C // Enable Request Register +#define DMA_ERQ_ERQ0 ((uint32_t)1<<0) // Enable DMA Request 0 +#define DMA_ERQ_ERQ1 ((uint32_t)1<<1) // Enable DMA Request 1 +#define DMA_ERQ_ERQ2 ((uint32_t)1<<2) // Enable DMA Request 2 +#define DMA_ERQ_ERQ3 ((uint32_t)1<<3) // Enable DMA Request 3 +#define DMA_ERQ_ERQ4 ((uint32_t)1<<4) // Enable DMA Request 4 +#define DMA_ERQ_ERQ5 ((uint32_t)1<<5) // Enable DMA Request 5 +#define DMA_ERQ_ERQ6 ((uint32_t)1<<6) // Enable DMA Request 6 +#define DMA_ERQ_ERQ7 ((uint32_t)1<<7) // Enable DMA Request 7 +#define DMA_ERQ_ERQ8 ((uint32_t)1<<8) // Enable DMA Request 8 +#define DMA_ERQ_ERQ9 ((uint32_t)1<<9) // Enable DMA Request 9 +#define DMA_ERQ_ERQ10 ((uint32_t)1<<10) // Enable DMA Request 10 +#define DMA_ERQ_ERQ11 ((uint32_t)1<<11) // Enable DMA Request 11 +#define DMA_ERQ_ERQ12 ((uint32_t)1<<12) // Enable DMA Request 12 +#define DMA_ERQ_ERQ13 ((uint32_t)1<<13) // Enable DMA Request 13 +#define DMA_ERQ_ERQ14 ((uint32_t)1<<14) // Enable DMA Request 14 +#define DMA_ERQ_ERQ15 ((uint32_t)1<<15) // Enable DMA Request 15 +#define DMA_EEI *(volatile uint32_t *)0x40008014 // Enable Error Interrupt Register +#define DMA_EEI_EEI0 ((uint32_t)1<<0) // Enable Error Interrupt 0 +#define DMA_EEI_EEI1 ((uint32_t)1<<1) // Enable Error Interrupt 1 +#define DMA_EEI_EEI2 ((uint32_t)1<<2) // Enable Error Interrupt 2 +#define DMA_EEI_EEI3 ((uint32_t)1<<3) // Enable Error Interrupt 3 +#define DMA_EEI_EEI4 ((uint32_t)1<<4) // Enable Error Interrupt 4 +#define DMA_EEI_EEI5 ((uint32_t)1<<5) // Enable Error Interrupt 5 +#define DMA_EEI_EEI6 ((uint32_t)1<<6) // Enable Error Interrupt 6 +#define DMA_EEI_EEI7 ((uint32_t)1<<7) // Enable Error Interrupt 7 +#define DMA_EEI_EEI8 ((uint32_t)1<<8) // Enable Error Interrupt 8 +#define DMA_EEI_EEI9 ((uint32_t)1<<9) // Enable Error Interrupt 9 +#define DMA_EEI_EEI10 ((uint32_t)1<<10) // Enable Error Interrupt 10 +#define DMA_EEI_EEI11 ((uint32_t)1<<11) // Enable Error Interrupt 11 +#define DMA_EEI_EEI12 ((uint32_t)1<<12) // Enable Error Interrupt 12 +#define DMA_EEI_EEI13 ((uint32_t)1<<13) // Enable Error Interrupt 13 +#define DMA_EEI_EEI14 ((uint32_t)1<<14) // Enable Error Interrupt 14 +#define DMA_EEI_EEI15 ((uint32_t)1<<15) // Enable Error Interrupt 15 +#define DMA_CEEI *(volatile uint8_t *)0x40008018 // Clear Enable Error Interrupt Register +#define DMA_CEEI_CEEI(n) ((uint8_t)(n & 15)<<0) // Clear Enable Error Interrupt +#define DMA_CEEI_CAEE ((uint8_t)1<<6) // Clear All Enable Error Interrupts +#define DMA_CEEI_NOP ((uint8_t)1<<7) // NOP +#define DMA_SEEI *(volatile uint8_t *)0x40008019 // Set Enable Error Interrupt Register +#define DMA_SEEI_SEEI(n) ((uint8_t)(n & 15)<<0) // Set Enable Error Interrupt +#define DMA_SEEI_SAEE ((uint8_t)1<<6) // Set All Enable Error Interrupts +#define DMA_SEEI_NOP ((uint8_t)1<<7) // NOP +#define DMA_CERQ *(volatile uint8_t *)0x4000801A // Clear Enable Request Register +#define DMA_CERQ_CERQ(n) ((uint8_t)(n & 15)<<0) // Clear Enable Request +#define DMA_CERQ_CAER ((uint8_t)1<<6) // Clear All Enable Requests +#define DMA_CERQ_NOP ((uint8_t)1<<7) // NOP +#define DMA_SERQ *(volatile uint8_t *)0x4000801B // Set Enable Request Register +#define DMA_SERQ_SERQ(n) ((uint8_t)(n & 15)<<0) // Set Enable Request +#define DMA_SERQ_SAER ((uint8_t)1<<6) // Set All Enable Requests +#define DMA_SERQ_NOP ((uint8_t)1<<7) // NOP +#define DMA_CDNE *(volatile uint8_t *)0x4000801C // Clear DONE Status Bit Register +#define DMA_CDNE_CDNE(n) ((uint8_t)(n & 15)<<0) // Clear Done Bit +#define DMA_CDNE_CADN ((uint8_t)1<<6) // Clear All Done Bits +#define DMA_CDNE_NOP ((uint8_t)1<<7) // NOP +#define DMA_SSRT *(volatile uint8_t *)0x4000801D // Set START Bit Register +#define DMA_SSRT_SSRT(n) ((uint8_t)(n & 15)<<0) // Set Start Bit +#define DMA_SSRT_SAST ((uint8_t)1<<6) // Set All Start Bits +#define DMA_SSRT_NOP ((uint8_t)1<<7) // NOP +#define DMA_CERR *(volatile uint8_t *)0x4000801E // Clear Error Register +#define DMA_CERR_CERR(n) ((uint8_t)(n & 15)<<0) // Clear Error Indicator +#define DMA_CERR_CAEI ((uint8_t)1<<6) // Clear All Error Indicators +#define DMA_CERR_NOP ((uint8_t)1<<7) // NOP +#define DMA_CINT *(volatile uint8_t *)0x4000801F // Clear Interrupt Request Register +#define DMA_CINT_CINT(n) ((uint8_t)(n & 15)<<0) // Clear Interrupt Request +#define DMA_CINT_CAIR ((uint8_t)1<<6) // Clear All Interrupt Requests +#define DMA_CINT_NOP ((uint8_t)1<<7) // NOP +#define DMA_INT *(volatile uint32_t *)0x40008024 // Interrupt Request Register +#define DMA_INT_INT0 ((uint32_t)1<<0) // Interrupt Request 0 +#define DMA_INT_INT1 ((uint32_t)1<<1) // Interrupt Request 1 +#define DMA_INT_INT2 ((uint32_t)1<<2) // Interrupt Request 2 +#define DMA_INT_INT3 ((uint32_t)1<<3) // Interrupt Request 3 +#define DMA_INT_INT4 ((uint32_t)1<<4) // Interrupt Request 4 +#define DMA_INT_INT5 ((uint32_t)1<<5) // Interrupt Request 5 +#define DMA_INT_INT6 ((uint32_t)1<<6) // Interrupt Request 6 +#define DMA_INT_INT7 ((uint32_t)1<<7) // Interrupt Request 7 +#define DMA_INT_INT8 ((uint32_t)1<<8) // Interrupt Request 8 +#define DMA_INT_INT9 ((uint32_t)1<<9) // Interrupt Request 9 +#define DMA_INT_INT10 ((uint32_t)1<<10) // Interrupt Request 10 +#define DMA_INT_INT11 ((uint32_t)1<<11) // Interrupt Request 11 +#define DMA_INT_INT12 ((uint32_t)1<<12) // Interrupt Request 12 +#define DMA_INT_INT13 ((uint32_t)1<<13) // Interrupt Request 13 +#define DMA_INT_INT14 ((uint32_t)1<<14) // Interrupt Request 14 +#define DMA_INT_INT15 ((uint32_t)1<<15) // Interrupt Request 15 +#define DMA_ERR *(volatile uint32_t *)0x4000802C // Error Register +#define DMA_ERR_ERR0 ((uint32_t)1<<0) // Error in Channel 0 +#define DMA_ERR_ERR1 ((uint32_t)1<<1) // Error in Channel 1 +#define DMA_ERR_ERR2 ((uint32_t)1<<2) // Error in Channel 2 +#define DMA_ERR_ERR3 ((uint32_t)1<<3) // Error in Channel 3 +#define DMA_ERR_ERR4 ((uint32_t)1<<4) // Error in Channel 4 +#define DMA_ERR_ERR5 ((uint32_t)1<<5) // Error in Channel 5 +#define DMA_ERR_ERR6 ((uint32_t)1<<6) // Error in Channel 6 +#define DMA_ERR_ERR7 ((uint32_t)1<<7) // Error in Channel 7 +#define DMA_ERR_ERR8 ((uint32_t)1<<8) // Error in Channel 8 +#define DMA_ERR_ERR9 ((uint32_t)1<<9) // Error in Channel 9 +#define DMA_ERR_ERR10 ((uint32_t)1<<10) // Error in Channel 10 +#define DMA_ERR_ERR11 ((uint32_t)1<<11) // Error in Channel 11 +#define DMA_ERR_ERR12 ((uint32_t)1<<12) // Error in Channel 12 +#define DMA_ERR_ERR13 ((uint32_t)1<<13) // Error in Channel 13 +#define DMA_ERR_ERR14 ((uint32_t)1<<14) // Error in Channel 14 +#define DMA_ERR_ERR15 ((uint32_t)1<<15) // Error in Channel 15 +#define DMA_HRS *(volatile uint32_t *)0x40008034 // Hardware Request Status Register +#define DMA_HRS_HRS0 ((uint32_t)1<<0) // Hardware Request Status Channel 0 +#define DMA_HRS_HRS1 ((uint32_t)1<<1) // Hardware Request Status Channel 1 +#define DMA_HRS_HRS2 ((uint32_t)1<<2) // Hardware Request Status Channel 2 +#define DMA_HRS_HRS3 ((uint32_t)1<<3) // Hardware Request Status Channel 3 +#define DMA_HRS_HRS4 ((uint32_t)1<<4) // Hardware Request Status Channel 4 +#define DMA_HRS_HRS5 ((uint32_t)1<<5) // Hardware Request Status Channel 5 +#define DMA_HRS_HRS6 ((uint32_t)1<<6) // Hardware Request Status Channel 6 +#define DMA_HRS_HRS7 ((uint32_t)1<<7) // Hardware Request Status Channel 7 +#define DMA_HRS_HRS8 ((uint32_t)1<<8) // Hardware Request Status Channel 8 +#define DMA_HRS_HRS9 ((uint32_t)1<<9) // Hardware Request Status Channel 9 +#define DMA_HRS_HRS10 ((uint32_t)1<<10) // Hardware Request Status Channel 10 +#define DMA_HRS_HRS11 ((uint32_t)1<<11) // Hardware Request Status Channel 11 +#define DMA_HRS_HRS12 ((uint32_t)1<<12) // Hardware Request Status Channel 12 +#define DMA_HRS_HRS13 ((uint32_t)1<<13) // Hardware Request Status Channel 13 +#define DMA_HRS_HRS14 ((uint32_t)1<<14) // Hardware Request Status Channel 14 +#define DMA_HRS_HRS15 ((uint32_t)1<<15) // Hardware Request Status Channel 15 +#define DMA_DCHPRI3 *(volatile uint8_t *)0x40008100 // Channel n Priority Register +#define DMA_DCHPRI2 *(volatile uint8_t *)0x40008101 // Channel n Priority Register +#define DMA_DCHPRI1 *(volatile uint8_t *)0x40008102 // Channel n Priority Register +#define DMA_DCHPRI0 *(volatile uint8_t *)0x40008103 // Channel n Priority Register +#define DMA_DCHPRI_CHPRI(n) ((uint8_t)(n & 15)<<0) // Channel Arbitration Priority +#define DMA_DCHPRI_DPA ((uint8_t)1<<6) // Disable PreEmpt Ability +#define DMA_DCHPRI_ECP ((uint8_t)1<<7) // Enable PreEmption +#define DMA_DCHPRI7 *(volatile uint8_t *)0x40008104 // Channel n Priority Register +#define DMA_DCHPRI6 *(volatile uint8_t *)0x40008105 // Channel n Priority Register +#define DMA_DCHPRI5 *(volatile uint8_t *)0x40008106 // Channel n Priority Register +#define DMA_DCHPRI4 *(volatile uint8_t *)0x40008107 // Channel n Priority Register +#define DMA_DCHPRI11 *(volatile uint8_t *)0x40008108 // Channel n Priority Register +#define DMA_DCHPRI10 *(volatile uint8_t *)0x40008109 // Channel n Priority Register +#define DMA_DCHPRI9 *(volatile uint8_t *)0x4000810A // Channel n Priority Register +#define DMA_DCHPRI8 *(volatile uint8_t *)0x4000810B // Channel n Priority Register +#define DMA_DCHPRI15 *(volatile uint8_t *)0x4000810C // Channel n Priority Register +#define DMA_DCHPRI14 *(volatile uint8_t *)0x4000810D // Channel n Priority Register +#define DMA_DCHPRI13 *(volatile uint8_t *)0x4000810E // Channel n Priority Register +#define DMA_DCHPRI12 *(volatile uint8_t *)0x4000810F // Channel n Priority Register + + +#define DMA_TCD_ATTR_SMOD(n) (((n) & 0x1F) << 11) +#define DMA_TCD_ATTR_SSIZE(n) (((n) & 0x7) << 8) +#define DMA_TCD_ATTR_DMOD(n) (((n) & 0x1F) << 3) +#define DMA_TCD_ATTR_DSIZE(n) (((n) & 0x7) << 0) +#define DMA_TCD_ATTR_SIZE_8BIT 0 +#define DMA_TCD_ATTR_SIZE_16BIT 1 +#define DMA_TCD_ATTR_SIZE_32BIT 2 +#define DMA_TCD_ATTR_SIZE_16BYTE 4 +#define DMA_TCD_ATTR_SIZE_32BYTE 5 +#define DMA_TCD_CSR_BWC(n) (((n) & 0x3) << 14) +#define DMA_TCD_CSR_MAJORLINKCH(n) (((n) & 0x3) << 8) +#define DMA_TCD_CSR_DONE 0x0080 +#define DMA_TCD_CSR_ACTIVE 0x0040 +#define DMA_TCD_CSR_MAJORELINK 0x0020 +#define DMA_TCD_CSR_ESG 0x0010 +#define DMA_TCD_CSR_DREQ 0x0008 +#define DMA_TCD_CSR_INTHALF 0x0004 +#define DMA_TCD_CSR_INTMAJOR 0x0002 +#define DMA_TCD_CSR_START 0x0001 +#define DMA_TCD_CITER_MASK ((uint16_t)0x7FFF) // Loop count mask +#define DMA_TCD_CITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete +#define DMA_TCD_BITER_MASK ((uint16_t)0x7FFF) // Loop count mask +#define DMA_TCD_BITER_ELINK ((uint16_t)1<<15) // Enable channel linking on minor-loop complete +#define DMA_TCD_NBYTES_SMLOE ((uint32_t)1<<31) // Source Minor Loop Offset Enable +#define DMA_TCD_NBYTES_DMLOE ((uint32_t)1<<30) // Destination Minor Loop Offset Enable +#define DMA_TCD_NBYTES_MLOFFNO_NBYTES(n) ((uint32_t)(n)) // NBytes transfer count when minor loop disabled +#define DMA_TCD_NBYTES_MLOFFYES_NBYTES(n) ((uint32_t)(n & 0x1F)) // NBytes transfer count when minor loop enabled +#define DMA_TCD_NBYTES_MLOFFYES_MLOFF(n) ((uint32_t)(n & 0xFFFFF)<<10) // Offset + +#define DMA_TCD0_SADDR *(volatile const void * volatile *)0x40009000 // TCD Source Address +#define DMA_TCD0_SOFF *(volatile int16_t *)0x40009004 // TCD Signed Source Address Offset +#define DMA_TCD0_ATTR *(volatile uint16_t *)0x40009006 // TCD Transfer Attributes +#define DMA_TCD0_NBYTES_MLNO *(volatile uint32_t *)0x40009008 // TCD Minor Byte Count (Minor Loop Disabled) +#define DMA_TCD0_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009008 // TCD Signed Minor Loop Offset (Minor Loop Enabled and Offset Disabled) +#define DMA_TCD0_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009008 // TCD Signed Minor Loop Offset (Minor Loop and Offset Enabled) +#define DMA_TCD0_SLAST *(volatile int32_t *)0x4000900C // TCD Last Source Address Adjustment +#define DMA_TCD0_DADDR *(volatile void * volatile *)0x40009010 // TCD Destination Address +#define DMA_TCD0_DOFF *(volatile int16_t *)0x40009014 // TCD Signed Destination Address Offset +#define DMA_TCD0_CITER_ELINKYES *(volatile uint16_t *)0x40009016 // TCD Current Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD0_CITER_ELINKNO *(volatile uint16_t *)0x40009016 // ?? +#define DMA_TCD0_DLASTSGA *(volatile int32_t *)0x40009018 // TCD Last Destination Address Adjustment/Scatter Gather Address +#define DMA_TCD0_CSR *(volatile uint16_t *)0x4000901C // TCD Control and Status +#define DMA_TCD0_BITER_ELINKYES *(volatile uint16_t *)0x4000901E // TCD Beginning Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD0_BITER_ELINKNO *(volatile uint16_t *)0x4000901E // TCD Beginning Minor Loop Link, Major Loop Count, Channel Linking Disabled + +#define DMA_TCD1_SADDR *(volatile const void * volatile *)0x40009020 // TCD Source Address +#define DMA_TCD1_SOFF *(volatile int16_t *)0x40009024 // TCD Signed Source Address Offset +#define DMA_TCD1_ATTR *(volatile uint16_t *)0x40009026 // TCD Transfer Attributes +#define DMA_TCD1_NBYTES_MLNO *(volatile uint32_t *)0x40009028 // TCD Minor Byte Count, Minor Loop Disabled +#define DMA_TCD1_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009028 // TCD Signed Minor Loop Offset, Minor Loop Enabled and Offset Disabled +#define DMA_TCD1_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009028 // TCD Signed Minor Loop Offset, Minor Loop and Offset Enabled +#define DMA_TCD1_SLAST *(volatile int32_t *)0x4000902C // TCD Last Source Address Adjustment +#define DMA_TCD1_DADDR *(volatile void * volatile *)0x40009030 // TCD Destination Address +#define DMA_TCD1_DOFF *(volatile int16_t *)0x40009034 // TCD Signed Destination Address Offset +#define DMA_TCD1_CITER_ELINKYES *(volatile uint16_t *)0x40009036 // TCD Current Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD1_CITER_ELINKNO *(volatile uint16_t *)0x40009036 // ?? +#define DMA_TCD1_DLASTSGA *(volatile int32_t *)0x40009038 // TCD Last Destination Address Adjustment/Scatter Gather Address +#define DMA_TCD1_CSR *(volatile uint16_t *)0x4000903C // TCD Control and Status +#define DMA_TCD1_BITER_ELINKYES *(volatile uint16_t *)0x4000903E // TCD Beginning Minor Loop Link, Major Loop Count Channel Linking Enabled +#define DMA_TCD1_BITER_ELINKNO *(volatile uint16_t *)0x4000903E // TCD Beginning Minor Loop Link, Major Loop Count, Channel Linking Disabled + +#define DMA_TCD2_SADDR *(volatile const void * volatile *)0x40009040 // TCD Source Address +#define DMA_TCD2_SOFF *(volatile int16_t *)0x40009044 // TCD Signed Source Address Offset +#define DMA_TCD2_ATTR *(volatile uint16_t *)0x40009046 // TCD Transfer Attributes +#define DMA_TCD2_NBYTES_MLNO *(volatile uint32_t *)0x40009048 // TCD Minor Byte Count, Minor Loop Disabled +#define DMA_TCD2_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009048 // TCD Signed Minor Loop Offset, Minor Loop Enabled and Offset Disabled +#define DMA_TCD2_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009048 // TCD Signed Minor Loop Offset, Minor Loop and Offset Enabled +#define DMA_TCD2_SLAST *(volatile int32_t *)0x4000904C // TCD Last Source Address Adjustment +#define DMA_TCD2_DADDR *(volatile void * volatile *)0x40009050 // TCD Destination Address +#define DMA_TCD2_DOFF *(volatile int16_t *)0x40009054 // TCD Signed Destination Address Offset +#define DMA_TCD2_CITER_ELINKYES *(volatile uint16_t *)0x40009056 // TCD Current Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD2_CITER_ELINKNO *(volatile uint16_t *)0x40009056 // ?? +#define DMA_TCD2_DLASTSGA *(volatile int32_t *)0x40009058 // TCD Last Destination Address Adjustment/Scatter Gather Address +#define DMA_TCD2_CSR *(volatile uint16_t *)0x4000905C // TCD Control and Status +#define DMA_TCD2_BITER_ELINKYES *(volatile uint16_t *)0x4000905E // TCD Beginning Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD2_BITER_ELINKNO *(volatile uint16_t *)0x4000905E // TCD Beginning Minor Loop Link, Major Loop Count, Channel Linking Disabled + +#define DMA_TCD3_SADDR *(volatile const void * volatile *)0x40009060 // TCD Source Address +#define DMA_TCD3_SOFF *(volatile int16_t *)0x40009064 // TCD Signed Source Address Offset +#define DMA_TCD3_ATTR *(volatile uint16_t *)0x40009066 // TCD Transfer Attributes +#define DMA_TCD3_NBYTES_MLNO *(volatile uint32_t *)0x40009068 // TCD Minor Byte Count, Minor Loop Disabled +#define DMA_TCD3_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009068 // TCD Signed Minor Loop Offset, Minor Loop Enabled and Offset Disabled +#define DMA_TCD3_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009068 // TCD Signed Minor Loop Offset, Minor Loop and Offset Enabled +#define DMA_TCD3_SLAST *(volatile int32_t *)0x4000906C // TCD Last Source Address Adjustment +#define DMA_TCD3_DADDR *(volatile void * volatile *)0x40009070 // TCD Destination Address +#define DMA_TCD3_DOFF *(volatile int16_t *)0x40009074 // TCD Signed Destination Address Offset +#define DMA_TCD3_CITER_ELINKYES *(volatile uint16_t *)0x40009076 // TCD Current Minor Loop Link, Major Loop Count, Channel Linking Enabled +#define DMA_TCD3_CITER_ELINKNO *(volatile uint16_t *)0x40009076 // ?? +#define DMA_TCD3_DLASTSGA *(volatile int32_t *)0x40009078 // TCD Last Destination Address Adjustment/Scatter Gather Address +#define DMA_TCD3_CSR *(volatile uint16_t *)0x4000907C // TCD Control and Status +#define DMA_TCD3_BITER_ELINKYES *(volatile uint16_t *)0x4000907E // TCD Beginning Minor Loop Link, Major Loop Count ,Channel Linking Enabled +#define DMA_TCD3_BITER_ELINKNO *(volatile uint16_t *)0x4000907E // TCD Beginning Minor Loop Link, Major Loop Count ,Channel Linking Disabled + +#define DMA_TCD4_SADDR *(volatile const void * volatile *)0x40009080 // TCD Source Addr +#define DMA_TCD4_SOFF *(volatile int16_t *)0x40009084 // TCD Signed Source Address Offset +#define DMA_TCD4_ATTR *(volatile uint16_t *)0x40009086 // TCD Transfer Attributes +#define DMA_TCD4_NBYTES_MLNO *(volatile uint32_t *)0x40009088 // TCD Minor Byte Count +#define DMA_TCD4_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009088 // TCD Signed Minor Loop Offset +#define DMA_TCD4_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009088 // TCD Signed Minor Loop Offset +#define DMA_TCD4_SLAST *(volatile int32_t *)0x4000908C // TCD Last Source Addr Adj. +#define DMA_TCD4_DADDR *(volatile void * volatile *)0x40009090 // TCD Destination Address +#define DMA_TCD4_DOFF *(volatile int16_t *)0x40009094 // TCD Signed Dest Address Offset +#define DMA_TCD4_CITER_ELINKYES *(volatile uint16_t *)0x40009096 // TCD Current Minor Loop Link +#define DMA_TCD4_CITER_ELINKNO *(volatile uint16_t *)0x40009096 // ?? +#define DMA_TCD4_DLASTSGA *(volatile int32_t *)0x40009098 // TCD Last Destination Addr Adj +#define DMA_TCD4_CSR *(volatile uint16_t *)0x4000909C // TCD Control and Status +#define DMA_TCD4_BITER_ELINKYES *(volatile uint16_t *)0x4000909E // TCD Beginning Minor Loop Link +#define DMA_TCD4_BITER_ELINKNO *(volatile uint16_t *)0x4000909E // TCD Beginning Minor Loop Link + +#define DMA_TCD5_SADDR *(volatile const void * volatile *)0x400090A0 // TCD Source Addr +#define DMA_TCD5_SOFF *(volatile int16_t *)0x400090A4 // TCD Signed Source Address Offset +#define DMA_TCD5_ATTR *(volatile uint16_t *)0x400090A6 // TCD Transfer Attributes +#define DMA_TCD5_NBYTES_MLNO *(volatile uint32_t *)0x400090A8 // TCD Minor Byte Count +#define DMA_TCD5_NBYTES_MLOFFNO *(volatile uint32_t *)0x400090A8 // TCD Signed Minor Loop Offset +#define DMA_TCD5_NBYTES_MLOFFYES *(volatile uint32_t *)0x400090A8 // TCD Signed Minor Loop Offset +#define DMA_TCD5_SLAST *(volatile int32_t *)0x400090AC // TCD Last Source Addr Adj. +#define DMA_TCD5_DADDR *(volatile void * volatile *)0x400090B0 // TCD Destination Address +#define DMA_TCD5_DOFF *(volatile int16_t *)0x400090B4 // TCD Signed Dest Address Offset +#define DMA_TCD5_CITER_ELINKYES *(volatile uint16_t *)0x400090B6 // TCD Current Minor Loop Link +#define DMA_TCD5_CITER_ELINKNO *(volatile uint16_t *)0x400090B6 // ?? +#define DMA_TCD5_DLASTSGA *(volatile int32_t *)0x400090B8 // TCD Last Destination Addr Adj +#define DMA_TCD5_CSR *(volatile uint16_t *)0x400090BC // TCD Control and Status +#define DMA_TCD5_BITER_ELINKYES *(volatile uint16_t *)0x400090BE // TCD Beginning Minor Loop Link +#define DMA_TCD5_BITER_ELINKNO *(volatile uint16_t *)0x400090BE // TCD Beginning Minor Loop Link + +#define DMA_TCD6_SADDR *(volatile const void * volatile *)0x400090C0 // TCD Source Addr +#define DMA_TCD6_SOFF *(volatile int16_t *)0x400090C4 // TCD Signed Source Address Offset +#define DMA_TCD6_ATTR *(volatile uint16_t *)0x400090C6 // TCD Transfer Attributes +#define DMA_TCD6_NBYTES_MLNO *(volatile uint32_t *)0x400090C8 // TCD Minor Byte Count +#define DMA_TCD6_NBYTES_MLOFFNO *(volatile uint32_t *)0x400090C8 // TCD Signed Minor Loop Offset +#define DMA_TCD6_NBYTES_MLOFFYES *(volatile uint32_t *)0x400090C8 // TCD Signed Minor Loop Offset +#define DMA_TCD6_SLAST *(volatile int32_t *)0x400090CC // TCD Last Source Addr Adj. +#define DMA_TCD6_DADDR *(volatile void * volatile *)0x400090D0 // TCD Destination Address +#define DMA_TCD6_DOFF *(volatile int16_t *)0x400090D4 // TCD Signed Dest Address Offset +#define DMA_TCD6_CITER_ELINKYES *(volatile uint16_t *)0x400090D6 // TCD Current Minor Loop Link +#define DMA_TCD6_CITER_ELINKNO *(volatile uint16_t *)0x400090D6 // ?? +#define DMA_TCD6_DLASTSGA *(volatile int32_t *)0x400090D8 // TCD Last Destination Addr Adj +#define DMA_TCD6_CSR *(volatile uint16_t *)0x400090DC // TCD Control and Status +#define DMA_TCD6_BITER_ELINKYES *(volatile uint16_t *)0x400090DE // TCD Beginning Minor Loop Link +#define DMA_TCD6_BITER_ELINKNO *(volatile uint16_t *)0x400090DE // TCD Beginning Minor Loop Link + +#define DMA_TCD7_SADDR *(volatile const void * volatile *)0x400090E0 // TCD Source Addr +#define DMA_TCD7_SOFF *(volatile int16_t *)0x400090E4 // TCD Signed Source Address Offset +#define DMA_TCD7_ATTR *(volatile uint16_t *)0x400090E6 // TCD Transfer Attributes +#define DMA_TCD7_NBYTES_MLNO *(volatile uint32_t *)0x400090E8 // TCD Minor Byte Count +#define DMA_TCD7_NBYTES_MLOFFNO *(volatile uint32_t *)0x400090E8 // TCD Signed Minor Loop Offset +#define DMA_TCD7_NBYTES_MLOFFYES *(volatile uint32_t *)0x400090E8 // TCD Signed Minor Loop Offset +#define DMA_TCD7_SLAST *(volatile int32_t *)0x400090EC // TCD Last Source Addr Adj. +#define DMA_TCD7_DADDR *(volatile void * volatile *)0x400090F0 // TCD Destination Address +#define DMA_TCD7_DOFF *(volatile int16_t *)0x400090F4 // TCD Signed Dest Address Offset +#define DMA_TCD7_CITER_ELINKYES *(volatile uint16_t *)0x400090F6 // TCD Current Minor Loop Link +#define DMA_TCD7_CITER_ELINKNO *(volatile uint16_t *)0x400090F6 // ?? +#define DMA_TCD7_DLASTSGA *(volatile int32_t *)0x400090F8 // TCD Last Destination Addr Adj +#define DMA_TCD7_CSR *(volatile uint16_t *)0x400090FC // TCD Control and Status +#define DMA_TCD7_BITER_ELINKYES *(volatile uint16_t *)0x400090FE // TCD Beginning Minor Loop Link +#define DMA_TCD7_BITER_ELINKNO *(volatile uint16_t *)0x400090FE // TCD Beginning Minor Loop Link + +#define DMA_TCD8_SADDR *(volatile const void * volatile *)0x40009100 // TCD Source Addr +#define DMA_TCD8_SOFF *(volatile int16_t *)0x40009104 // TCD Signed Source Address Offset +#define DMA_TCD8_ATTR *(volatile uint16_t *)0x40009106 // TCD Transfer Attributes +#define DMA_TCD8_NBYTES_MLNO *(volatile uint32_t *)0x40009108 // TCD Minor Byte Count +#define DMA_TCD8_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009108 // TCD Signed Minor Loop Offset +#define DMA_TCD8_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009108 // TCD Signed Minor Loop Offset +#define DMA_TCD8_SLAST *(volatile int32_t *)0x4000910C // TCD Last Source Addr Adj. +#define DMA_TCD8_DADDR *(volatile void * volatile *)0x40009110 // TCD Destination Address +#define DMA_TCD8_DOFF *(volatile int16_t *)0x40009114 // TCD Signed Dest Address Offset +#define DMA_TCD8_CITER_ELINKYES *(volatile uint16_t *)0x40009116 // TCD Current Minor Loop Link +#define DMA_TCD8_CITER_ELINKNO *(volatile uint16_t *)0x40009116 // ?? +#define DMA_TCD8_DLASTSGA *(volatile int32_t *)0x40009118 // TCD Last Destination Addr Adj +#define DMA_TCD8_CSR *(volatile uint16_t *)0x4000911C // TCD Control and Status +#define DMA_TCD8_BITER_ELINKYES *(volatile uint16_t *)0x4000911E // TCD Beginning Minor Loop Link +#define DMA_TCD8_BITER_ELINKNO *(volatile uint16_t *)0x4000911E // TCD Beginning Minor Loop Link + +#define DMA_TCD9_SADDR *(volatile const void * volatile *)0x40009120 // TCD Source Addr +#define DMA_TCD9_SOFF *(volatile int16_t *)0x40009124 // TCD Signed Source Address Offset +#define DMA_TCD9_ATTR *(volatile uint16_t *)0x40009126 // TCD Transfer Attributes +#define DMA_TCD9_NBYTES_MLNO *(volatile uint32_t *)0x40009128 // TCD Minor Byte Count +#define DMA_TCD9_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009128 // TCD Signed Minor Loop Offset +#define DMA_TCD9_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009128 // TCD Signed Minor Loop Offset +#define DMA_TCD9_SLAST *(volatile int32_t *)0x4000912C // TCD Last Source Addr Adj. +#define DMA_TCD9_DADDR *(volatile void * volatile *)0x40009130 // TCD Destination Address +#define DMA_TCD9_DOFF *(volatile int16_t *)0x40009134 // TCD Signed Dest Address Offset +#define DMA_TCD9_CITER_ELINKYES *(volatile uint16_t *)0x40009136 // TCD Current Minor Loop Link +#define DMA_TCD9_CITER_ELINKNO *(volatile uint16_t *)0x40009136 // ?? +#define DMA_TCD9_DLASTSGA *(volatile int32_t *)0x40009138 // TCD Last Destination Addr Adj +#define DMA_TCD9_CSR *(volatile uint16_t *)0x4000913C // TCD Control and Status +#define DMA_TCD9_BITER_ELINKYES *(volatile uint16_t *)0x4000913E // TCD Beginning Minor Loop Link +#define DMA_TCD9_BITER_ELINKNO *(volatile uint16_t *)0x4000913E // TCD Beginning Minor Loop Link + +#define DMA_TCD10_SADDR *(volatile const void * volatile *)0x40009140 // TCD Source Addr +#define DMA_TCD10_SOFF *(volatile int16_t *)0x40009144 // TCD Signed Source Address Offset +#define DMA_TCD10_ATTR *(volatile uint16_t *)0x40009146 // TCD Transfer Attributes +#define DMA_TCD10_NBYTES_MLNO *(volatile uint32_t *)0x40009148 // TCD Minor Byte Count +#define DMA_TCD10_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009148 // TCD Signed Minor Loop Offset +#define DMA_TCD10_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009148 // TCD Signed Minor Loop Offset +#define DMA_TCD10_SLAST *(volatile int32_t *)0x4000914C // TCD Last Source Addr Adj. +#define DMA_TCD10_DADDR *(volatile void * volatile *)0x40009150 // TCD Destination Address +#define DMA_TCD10_DOFF *(volatile int16_t *)0x40009154 // TCD Signed Dest Address Offset +#define DMA_TCD10_CITER_ELINKYES *(volatile uint16_t *)0x40009156 // TCD Current Minor Loop Link +#define DMA_TCD10_CITER_ELINKNO *(volatile uint16_t *)0x40009156 // ?? +#define DMA_TCD10_DLASTSGA *(volatile int32_t *)0x40009158 // TCD Last Destination Addr Adj +#define DMA_TCD10_CSR *(volatile uint16_t *)0x4000915C // TCD Control and Status +#define DMA_TCD10_BITER_ELINKYES *(volatile uint16_t *)0x4000915E // TCD Beginning Minor Loop Link +#define DMA_TCD10_BITER_ELINKNO *(volatile uint16_t *)0x4000915E // TCD Beginning Minor Loop Link + +#define DMA_TCD11_SADDR *(volatile const void * volatile *)0x40009160 // TCD Source Addr +#define DMA_TCD11_SOFF *(volatile int16_t *)0x40009164 // TCD Signed Source Address Offset +#define DMA_TCD11_ATTR *(volatile uint16_t *)0x40009166 // TCD Transfer Attributes +#define DMA_TCD11_NBYTES_MLNO *(volatile uint32_t *)0x40009168 // TCD Minor Byte Count +#define DMA_TCD11_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009168 // TCD Signed Minor Loop Offset +#define DMA_TCD11_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009168 // TCD Signed Minor Loop Offset +#define DMA_TCD11_SLAST *(volatile int32_t *)0x4000916C // TCD Last Source Addr Adj. +#define DMA_TCD11_DADDR *(volatile void * volatile *)0x40009170 // TCD Destination Address +#define DMA_TCD11_DOFF *(volatile int16_t *)0x40009174 // TCD Signed Dest Address Offset +#define DMA_TCD11_CITER_ELINKYES *(volatile uint16_t *)0x40009176 // TCD Current Minor Loop Link +#define DMA_TCD11_CITER_ELINKNO *(volatile uint16_t *)0x40009176 // ?? +#define DMA_TCD11_DLASTSGA *(volatile int32_t *)0x40009178 // TCD Last Destination Addr Adj +#define DMA_TCD11_CSR *(volatile uint16_t *)0x4000917C // TCD Control and Status +#define DMA_TCD11_BITER_ELINKYES *(volatile uint16_t *)0x4000917E // TCD Beginning Minor Loop Link +#define DMA_TCD11_BITER_ELINKNO *(volatile uint16_t *)0x4000917E // TCD Beginning Minor Loop Link + +#define DMA_TCD12_SADDR *(volatile const void * volatile *)0x40009180 // TCD Source Addr +#define DMA_TCD12_SOFF *(volatile int16_t *)0x40009184 // TCD Signed Source Address Offset +#define DMA_TCD12_ATTR *(volatile uint16_t *)0x40009186 // TCD Transfer Attributes +#define DMA_TCD12_NBYTES_MLNO *(volatile uint32_t *)0x40009188 // TCD Minor Byte Count +#define DMA_TCD12_NBYTES_MLOFFNO *(volatile uint32_t *)0x40009188 // TCD Signed Minor Loop Offset +#define DMA_TCD12_NBYTES_MLOFFYES *(volatile uint32_t *)0x40009188 // TCD Signed Minor Loop Offset +#define DMA_TCD12_SLAST *(volatile int32_t *)0x4000918C // TCD Last Source Addr Adj. +#define DMA_TCD12_DADDR *(volatile void * volatile *)0x40009190 // TCD Destination Address +#define DMA_TCD12_DOFF *(volatile int16_t *)0x40009194 // TCD Signed Dest Address Offset +#define DMA_TCD12_CITER_ELINKYES *(volatile uint16_t *)0x40009196 // TCD Current Minor Loop Link +#define DMA_TCD12_CITER_ELINKNO *(volatile uint16_t *)0x40009196 // ?? +#define DMA_TCD12_DLASTSGA *(volatile int32_t *)0x40009198 // TCD Last Destination Addr Adj +#define DMA_TCD12_CSR *(volatile uint16_t *)0x4000919C // TCD Control and Status +#define DMA_TCD12_BITER_ELINKYES *(volatile uint16_t *)0x4000919E // TCD Beginning Minor Loop Link +#define DMA_TCD12_BITER_ELINKNO *(volatile uint16_t *)0x4000919E // TCD Beginning Minor Loop Link + +#define DMA_TCD13_SADDR *(volatile const void * volatile *)0x400091A0 // TCD Source Addr +#define DMA_TCD13_SOFF *(volatile int16_t *)0x400091A4 // TCD Signed Source Address Offset +#define DMA_TCD13_ATTR *(volatile uint16_t *)0x400091A6 // TCD Transfer Attributes +#define DMA_TCD13_NBYTES_MLNO *(volatile uint32_t *)0x400091A8 // TCD Minor Byte Count +#define DMA_TCD13_NBYTES_MLOFFNO *(volatile uint32_t *)0x400091A8 // TCD Signed Minor Loop Offset +#define DMA_TCD13_NBYTES_MLOFFYES *(volatile uint32_t *)0x400091A8 // TCD Signed Minor Loop Offset +#define DMA_TCD13_SLAST *(volatile int32_t *)0x400091AC // TCD Last Source Addr Adj. +#define DMA_TCD13_DADDR *(volatile void * volatile *)0x400091B0 // TCD Destination Address +#define DMA_TCD13_DOFF *(volatile int16_t *)0x400091B4 // TCD Signed Dest Address Offset +#define DMA_TCD13_CITER_ELINKYES *(volatile uint16_t *)0x400091B6 // TCD Current Minor Loop Link +#define DMA_TCD13_CITER_ELINKNO *(volatile uint16_t *)0x400091B6 // ?? +#define DMA_TCD13_DLASTSGA *(volatile int32_t *)0x400091B8 // TCD Last Destination Addr Adj +#define DMA_TCD13_CSR *(volatile uint16_t *)0x400091BC // TCD Control and Status +#define DMA_TCD13_BITER_ELINKYES *(volatile uint16_t *)0x400091BE // TCD Beginning Minor Loop Link +#define DMA_TCD13_BITER_ELINKNO *(volatile uint16_t *)0x400091BE // TCD Beginning Minor Loop Link + +#define DMA_TCD14_SADDR *(volatile const void * volatile *)0x400091C0 // TCD Source Addr +#define DMA_TCD14_SOFF *(volatile int16_t *)0x400091C4 // TCD Signed Source Address Offset +#define DMA_TCD14_ATTR *(volatile uint16_t *)0x400091C6 // TCD Transfer Attributes +#define DMA_TCD14_NBYTES_MLNO *(volatile uint32_t *)0x400091C8 // TCD Minor Byte Count +#define DMA_TCD14_NBYTES_MLOFFNO *(volatile uint32_t *)0x400091C8 // TCD Signed Minor Loop Offset +#define DMA_TCD14_NBYTES_MLOFFYES *(volatile uint32_t *)0x400091C8 // TCD Signed Minor Loop Offset +#define DMA_TCD14_SLAST *(volatile int32_t *)0x400091CC // TCD Last Source Addr Adj. +#define DMA_TCD14_DADDR *(volatile void * volatile *)0x400091D0 // TCD Destination Address +#define DMA_TCD14_DOFF *(volatile int16_t *)0x400091D4 // TCD Signed Dest Address Offset +#define DMA_TCD14_CITER_ELINKYES *(volatile uint16_t *)0x400091D6 // TCD Current Minor Loop Link +#define DMA_TCD14_CITER_ELINKNO *(volatile uint16_t *)0x400091D6 // ?? +#define DMA_TCD14_DLASTSGA *(volatile int32_t *)0x400091D8 // TCD Last Destination Addr Adj +#define DMA_TCD14_CSR *(volatile uint16_t *)0x400091DC // TCD Control and Status +#define DMA_TCD14_BITER_ELINKYES *(volatile uint16_t *)0x400091DE // TCD Beginning Minor Loop Link +#define DMA_TCD14_BITER_ELINKNO *(volatile uint16_t *)0x400091DE // TCD Beginning Minor Loop Link + +#define DMA_TCD15_SADDR *(volatile const void * volatile *)0x400091E0 // TCD Source Addr +#define DMA_TCD15_SOFF *(volatile int16_t *)0x400091E4 // TCD Signed Source Address Offset +#define DMA_TCD15_ATTR *(volatile uint16_t *)0x400091E6 // TCD Transfer Attributes +#define DMA_TCD15_NBYTES_MLNO *(volatile uint32_t *)0x400091E8 // TCD Minor Byte Count +#define DMA_TCD15_NBYTES_MLOFFNO *(volatile uint32_t *)0x400091E8 // TCD Signed Minor Loop Offset +#define DMA_TCD15_NBYTES_MLOFFYES *(volatile uint32_t *)0x400091E8 // TCD Signed Minor Loop Offset +#define DMA_TCD15_SLAST *(volatile int32_t *)0x400091EC // TCD Last Source Addr Adj. +#define DMA_TCD15_DADDR *(volatile void * volatile *)0x400091F0 // TCD Destination Address +#define DMA_TCD15_DOFF *(volatile int16_t *)0x400091F4 // TCD Signed Dest Address Offset +#define DMA_TCD15_CITER_ELINKYES *(volatile uint16_t *)0x400091F6 // TCD Current Minor Loop Link +#define DMA_TCD15_CITER_ELINKNO *(volatile uint16_t *)0x400091F6 // ?? +#define DMA_TCD15_DLASTSGA *(volatile int32_t *)0x400091F8 // TCD Last Destination Addr Adj +#define DMA_TCD15_CSR *(volatile uint16_t *)0x400091FC // TCD Control and Status +#define DMA_TCD15_BITER_ELINKYES *(volatile uint16_t *)0x400091FE // TCD Beginning Minor Loop Link +#define DMA_TCD15_BITER_ELINKNO *(volatile uint16_t *)0x400091FE // TCD Beginning Minor Loop Link + + +// Chapter 22: External Watchdog Monitor (EWM) +#define EWM_CTRL *(volatile uint8_t *)0x40061000 // Control Register +#define EWM_SERV *(volatile uint8_t *)0x40061001 // Service Register +#define EWM_CMPL *(volatile uint8_t *)0x40061002 // Compare Low Register +#define EWM_CMPH *(volatile uint8_t *)0x40061003 // Compare High Register + +// Chapter 23: Watchdog Timer (WDOG) +#define WDOG_STCTRLH *(volatile uint16_t *)0x40052000 // Watchdog Status and Control Register High +#define WDOG_STCTRLH_DISTESTWDOG (uint16_t)0x4000 // Allows the WDOG's functional test mode to be disabled permanently. +#define WDOG_STCTRLH_BYTESEL(n) (uint16_t)(((n) & 3) << 12) // selects the byte to be tested when the watchdog is in the byte test mode. +#define WDOG_STCTRLH_TESTSEL (uint16_t)0x0800 +#define WDOG_STCTRLH_TESTWDOG (uint16_t)0x0400 +#define WDOG_STCTRLH_WAITEN (uint16_t)0x0080 +#define WDOG_STCTRLH_STOPEN (uint16_t)0x0040 +#define WDOG_STCTRLH_DBGEN (uint16_t)0x0020 +#define WDOG_STCTRLH_ALLOWUPDATE (uint16_t)0x0010 +#define WDOG_STCTRLH_WINEN (uint16_t)0x0008 +#define WDOG_STCTRLH_IRQRSTEN (uint16_t)0x0004 +#define WDOG_STCTRLH_CLKSRC (uint16_t)0x0002 +#define WDOG_STCTRLH_WDOGEN (uint16_t)0x0001 +#define WDOG_STCTRLL *(volatile uint16_t *)0x40052002 // Watchdog Status and Control Register Low +#define WDOG_TOVALH *(volatile uint16_t *)0x40052004 // Watchdog Time-out Value Register High +#define WDOG_TOVALL *(volatile uint16_t *)0x40052006 // Watchdog Time-out Value Register Low +#define WDOG_WINH *(volatile uint16_t *)0x40052008 // Watchdog Window Register High +#define WDOG_WINL *(volatile uint16_t *)0x4005200A // Watchdog Window Register Low +#define WDOG_REFRESH *(volatile uint16_t *)0x4005200C // Watchdog Refresh register +#define WDOG_UNLOCK *(volatile uint16_t *)0x4005200E // Watchdog Unlock register +#define WDOG_UNLOCK_SEQ1 (uint16_t)0xC520 +#define WDOG_UNLOCK_SEQ2 (uint16_t)0xD928 +#define WDOG_TMROUTH *(volatile uint16_t *)0x40052010 // Watchdog Timer Output Register High +#define WDOG_TMROUTL *(volatile uint16_t *)0x40052012 // Watchdog Timer Output Register Low +#define WDOG_RSTCNT *(volatile uint16_t *)0x40052014 // Watchdog Reset Count register +#define WDOG_PRESC *(volatile uint16_t *)0x40052016 // Watchdog Prescaler register + +// Chapter 24: Multipurpose Clock Generator (MCG) +#define MCG_C1 *(volatile uint8_t *)0x40064000 // MCG Control 1 Register +#define MCG_C1_IREFSTEN (uint8_t)0x01 // Internal Reference Stop Enable, Controls whether or not the internal reference clock remains enabled when the MCG enters Stop mode. +#define MCG_C1_IRCLKEN (uint8_t)0x02 // Internal Reference Clock Enable, Enables the internal reference clock for use as MCGIRCLK. +#define MCG_C1_IREFS (uint8_t)0x04 // Internal Reference Select, Selects the reference clock source for the FLL. +#define MCG_C1_FRDIV(n) (uint8_t)(((n) & 0x07) << 3) // FLL External Reference Divider, Selects the amount to divide down the external reference clock for the FLL +#define MCG_C1_CLKS(n) (uint8_t)(((n) & 0x03) << 6) // Clock Source Select, Selects the clock source for MCGOUTCLK +#define MCG_C2 *(volatile uint8_t *)0x40064001 // MCG Control 2 Register +#define MCG_C2_IRCS (uint8_t)0x01 // Internal Reference Clock Select, Selects between the fast or slow internal reference clock source. +#define MCG_C2_LP (uint8_t)0x02 // Low Power Select, Controls whether the FLL or PLL is disabled in BLPI and BLPE modes. +#define MCG_C2_EREFS (uint8_t)0x04 // External Reference Select, Selects the source for the external reference clock. +#define MCG_C2_HGO0 (uint8_t)0x08 // High Gain Oscillator Select, Controls the crystal oscillator mode of operation +#define MCG_C2_RANGE0(n) (uint8_t)(((n) & 0x03) << 4) // Frequency Range Select, Selects the frequency range for the crystal oscillator +#define MCG_C2_LOCRE0 (uint8_t)0x80 // Loss of Clock Reset Enable, Determines whether an interrupt or a reset request is made following a loss of OSC0 +#define MCG_C3 *(volatile uint8_t *)0x40064002 // MCG Control 3 Register +#define MCG_C3_SCTRIM(n) (uint8_t)(n) // Slow Internal Reference Clock Trim Setting +#define MCG_C4 *(volatile uint8_t *)0x40064003 // MCG Control 4 Register +#define MCG_C4_SCFTRIM (uint8_t)0x01 // Slow Internal Reference Clock Fine Trim +#define MCG_C4_FCTRIM(n) (uint8_t)(((n) & 0x0F) << 1) // Fast Internal Reference Clock Trim Setting +#define MCG_C4_DRST_DRS(n) (uint8_t)(((n) & 0x03) << 5) // DCO Range Select +#define MCG_C4_DMX32 (uint8_t)0x80 // DCO Maximum Frequency with 32.768 kHz Reference, controls whether the DCO frequency range is narrowed +#define MCG_C5 *(volatile uint8_t *)0x40064004 // MCG Control 5 Register +#define MCG_C5_PRDIV0(n) (uint8_t)((n) & 0x1F) // PLL External Reference Divider +#define MCG_C5_PLLSTEN0 (uint8_t)0x20 // PLL Stop Enable +#define MCG_C5_PLLCLKEN0 (uint8_t)0x40 // PLL Clock Enable +#define MCG_C6 *(volatile uint8_t *)0x40064005 // MCG Control 6 Register +#define MCG_C6_VDIV0(n) (uint8_t)((n) & 0x1F) // VCO 0 Divider +#define MCG_C6_CME0 (uint8_t)0x20 // Clock Monitor Enable +#define MCG_C6_PLLS (uint8_t)0x40 // PLL Select, Controls whether the PLL or FLL output is selected as the MCG source when CLKS[1:0]=00. +#define MCG_C6_LOLIE0 (uint8_t)0x80 // Loss of Lock Interrrupt Enable +#define MCG_S *(volatile uint8_t *)0x40064006 // MCG Status Register +#define MCG_S_IRCST (uint8_t)0x01 // Internal Reference Clock Status +#define MCG_S_OSCINIT0 (uint8_t)0x02 // OSC Initialization, resets to 0, is set to 1 after the initialization cycles of the crystal oscillator +#define MCG_S_CLKST(n) (uint8_t)(((n) & 0x03) << 2) // Clock Mode Status, 0=FLL is selected, 1= Internal ref, 2=External ref, 3=PLL +#define MCG_S_CLKST_MASK (uint8_t)0x0C +#define MCG_S_IREFST (uint8_t)0x10 // Internal Reference Status +#define MCG_S_PLLST (uint8_t)0x20 // PLL Select Status +#define MCG_S_LOCK0 (uint8_t)0x40 // Lock Status, 0=PLL Unlocked, 1=PLL Locked +#define MCG_S_LOLS0 (uint8_t)0x80 // Loss of Lock Status +#define MCG_SC *(volatile uint8_t *)0x40064008 // MCG Status and Control Register +#define MCG_SC_LOCS0 (uint8_t)0x01 // OSC0 Loss of Clock Status +#define MCG_SC_FCRDIV(n) (uint8_t)(((n) & 0x07) << 1) // Fast Clock Internal Reference Divider +#define MCG_SC_FLTPRSRV (uint8_t)0x10 // FLL Filter Preserve Enable +#define MCG_SC_ATMF (uint8_t)0x20 // Automatic Trim Machine Fail Flag +#define MCG_SC_ATMS (uint8_t)0x40 // Automatic Trim Machine Select +#define MCG_SC_ATME (uint8_t)0x80 // Automatic Trim Machine Enable +#define MCG_ATCVH *(volatile uint8_t *)0x4006400A // MCG Auto Trim Compare Value High Register +#define MCG_ATCVL *(volatile uint8_t *)0x4006400B // MCG Auto Trim Compare Value Low Register +#define MCG_C7 *(volatile uint8_t *)0x4006400C // MCG Control 7 Register +#define MCG_C8 *(volatile uint8_t *)0x4006400D // MCG Control 8 Register + +// Chapter 25: Oscillator (OSC) +#define OSC0_CR *(volatile uint8_t *)0x40065000 // OSC Control Register +#define OSC_SC16P (uint8_t)0x01 // Oscillator 16 pF Capacitor Load Configure +#define OSC_SC8P (uint8_t)0x02 // Oscillator 8 pF Capacitor Load Configure +#define OSC_SC4P (uint8_t)0x04 // Oscillator 4 pF Capacitor Load Configure +#define OSC_SC2P (uint8_t)0x08 // Oscillator 2 pF Capacitor Load Configure +#define OSC_EREFSTEN (uint8_t)0x20 // External Reference Stop Enable, Controls whether or not the external reference clock (OSCERCLK) remains enabled when MCU enters Stop mode. +#define OSC_ERCLKEN (uint8_t)0x80 // External Reference Enable, Enables external reference clock (OSCERCLK). + +// Chapter 27: Flash Memory Controller (FMC) +#define FMC_PFAPR *(volatile uint32_t *)0x4001F000 // Flash Access Protection +#define FMC_PFB0CR *(volatile uint32_t *)0x4001F004 // Flash Control +#define FMC_TAGVDW0S0 *(volatile uint32_t *)0x4001F100 // Cache Tag Storage +#define FMC_TAGVDW0S1 *(volatile uint32_t *)0x4001F104 // Cache Tag Storage +#define FMC_TAGVDW1S0 *(volatile uint32_t *)0x4001F108 // Cache Tag Storage +#define FMC_TAGVDW1S1 *(volatile uint32_t *)0x4001F10C // Cache Tag Storage +#define FMC_TAGVDW2S0 *(volatile uint32_t *)0x4001F110 // Cache Tag Storage +#define FMC_TAGVDW2S1 *(volatile uint32_t *)0x4001F114 // Cache Tag Storage +#define FMC_TAGVDW3S0 *(volatile uint32_t *)0x4001F118 // Cache Tag Storage +#define FMC_TAGVDW3S1 *(volatile uint32_t *)0x4001F11C // Cache Tag Storage +#define FMC_DATAW0S0 *(volatile uint32_t *)0x4001F200 // Cache Data Storage +#define FMC_DATAW0S1 *(volatile uint32_t *)0x4001F204 // Cache Data Storage +#define FMC_DATAW1S0 *(volatile uint32_t *)0x4001F208 // Cache Data Storage +#define FMC_DATAW1S1 *(volatile uint32_t *)0x4001F20C // Cache Data Storage +#define FMC_DATAW2S0 *(volatile uint32_t *)0x4001F210 // Cache Data Storage +#define FMC_DATAW2S1 *(volatile uint32_t *)0x4001F214 // Cache Data Storage +#define FMC_DATAW3S0 *(volatile uint32_t *)0x4001F218 // Cache Data Storage +#define FMC_DATAW3S1 *(volatile uint32_t *)0x4001F21C // Cache Data Storage + +// Chapter 28: Flash Memory Module (FTFL) +#define FTFL_FSTAT *(volatile uint8_t *)0x40020000 // Flash Status Register +#define FTFL_FSTAT_CCIF (uint8_t)0x80 // Command Complete Interrupt Flag +#define FTFL_FSTAT_RDCOLERR (uint8_t)0x40 // Flash Read Collision Error Flag +#define FTFL_FSTAT_ACCERR (uint8_t)0x20 // Flash Access Error Flag +#define FTFL_FSTAT_FPVIOL (uint8_t)0x10 // Flash Protection Violation Flag +#define FTFL_FSTAT_MGSTAT0 (uint8_t)0x01 // Memory Controller Command Completion Status Flag +#define FTFL_FCNFG *(volatile uint8_t *)0x40020001 // Flash Configuration Register +#define FTFL_FCNFG_CCIE (uint8_t)0x80 // Command Complete Interrupt Enable +#define FTFL_FCNFG_RDCOLLIE (uint8_t)0x40 // Read Collision Error Interrupt Enable +#define FTFL_FCNFG_ERSAREQ (uint8_t)0x20 // Erase All Request +#define FTFL_FCNFG_ERSSUSP (uint8_t)0x10 // Erase Suspend +#define FTFL_FCNFG_PFLSH (uint8_t)0x04 // Flash memory configuration +#define FTFL_FCNFG_RAMRDY (uint8_t)0x02 // RAM Ready +#define FTFL_FCNFG_EEERDY (uint8_t)0x01 // EEPROM Ready +#define FTFL_FSEC *(const uint8_t *)0x40020002 // Flash Security Register +#define FTFL_FOPT *(const uint8_t *)0x40020003 // Flash Option Register +#define FTFL_FCCOB3 *(volatile uint8_t *)0x40020004 // Flash Common Command Object Registers +#define FTFL_FCCOB2 *(volatile uint8_t *)0x40020005 +#define FTFL_FCCOB1 *(volatile uint8_t *)0x40020006 +#define FTFL_FCCOB0 *(volatile uint8_t *)0x40020007 +#define FTFL_FCCOB7 *(volatile uint8_t *)0x40020008 +#define FTFL_FCCOB6 *(volatile uint8_t *)0x40020009 +#define FTFL_FCCOB5 *(volatile uint8_t *)0x4002000A +#define FTFL_FCCOB4 *(volatile uint8_t *)0x4002000B +#define FTFL_FCCOBB *(volatile uint8_t *)0x4002000C +#define FTFL_FCCOBA *(volatile uint8_t *)0x4002000D +#define FTFL_FCCOB9 *(volatile uint8_t *)0x4002000E +#define FTFL_FCCOB8 *(volatile uint8_t *)0x4002000F +#define FTFL_FPROT3 *(volatile uint8_t *)0x40020010 // Program Flash Protection Registers +#define FTFL_FPROT2 *(volatile uint8_t *)0x40020011 // Program Flash Protection Registers +#define FTFL_FPROT1 *(volatile uint8_t *)0x40020012 // Program Flash Protection Registers +#define FTFL_FPROT0 *(volatile uint8_t *)0x40020013 // Program Flash Protection Registers +#define FTFL_FEPROT *(volatile uint8_t *)0x40020016 // EEPROM Protection Register +#define FTFL_FDPROT *(volatile uint8_t *)0x40020017 // Data Flash Protection Register + +// Chapter 30: Cyclic Redundancy Check (CRC) +#define CRC_CRC *(volatile uint32_t *)0x40032000 // CRC Data register +#define CRC_GPOLY *(volatile uint32_t *)0x40032004 // CRC Polynomial register +#define CRC_CTRL *(volatile uint32_t *)0x40032008 // CRC Control register + +// Chapter 31: Analog-to-Digital Converter (ADC) +#define ADC0_SC1A *(volatile uint32_t *)0x4003B000 // ADC status and control registers 1 +#define ADC0_SC1B *(volatile uint32_t *)0x4003B004 // ADC status and control registers 1 +#define ADC_SC1_COCO (uint32_t)0x80 // Conversion complete flag +#define ADC_SC1_AIEN (uint32_t)0x40 // Interrupt enable +#define ADC_SC1_DIFF (uint32_t)0x20 // Differential mode enable +#define ADC_SC1_ADCH(n) (uint32_t)((n) & 0x1F) // Input channel select +#define ADC0_CFG1 *(volatile uint32_t *)0x4003B008 // ADC configuration register 1 +#define ADC_CFG1_ADLPC (uint32_t)0x80 // Low-power configuration +#define ADC_CFG1_ADIV(n) (uint32_t)(((n) & 3) << 5) // Clock divide select, 0=direct, 1=div2, 2=div4, 3=div8 +#define ADC_CFG1_ADLSMP (uint32_t)0x10 // Sample time configuration, 0=Short, 1=Long +#define ADC_CFG1_MODE(n) (uint32_t)(((n) & 3) << 2) // Conversion mode, 0=8 bit, 1=12 bit, 2=10 bit, 3=16 bit +#define ADC_CFG1_ADICLK(n) (uint32_t)(((n) & 3) << 0) // Input clock, 0=bus, 1=bus/2, 2=OSCERCLK, 3=async +#define ADC0_CFG2 *(volatile uint32_t *)0x4003B00C // Configuration register 2 +#define ADC_CFG2_MUXSEL (uint32_t)0x10 // 0=a channels, 1=b channels +#define ADC_CFG2_ADACKEN (uint32_t)0x08 // async clock enable +#define ADC_CFG2_ADHSC (uint32_t)0x04 // High speed configuration +#define ADC_CFG2_ADLSTS(n) (uint32_t)(((n) & 3) << 0) // Sample time, 0=24 cycles, 1=12 cycles, 2=6 cycles, 3=2 cycles +#define ADC0_RA *(volatile uint32_t *)0x4003B010 // ADC data result register +#define ADC0_RB *(volatile uint32_t *)0x4003B014 // ADC data result register +#define ADC0_CV1 *(volatile uint32_t *)0x4003B018 // Compare value registers +#define ADC0_CV2 *(volatile uint32_t *)0x4003B01C // Compare value registers +#define ADC0_SC2 *(volatile uint32_t *)0x4003B020 // Status and control register 2 +#define ADC_SC2_ADACT (uint32_t)0x80 // Conversion active +#define ADC_SC2_ADTRG (uint32_t)0x40 // Conversion trigger select, 0=software, 1=hardware +#define ADC_SC2_ACFE (uint32_t)0x20 // Compare function enable +#define ADC_SC2_ACFGT (uint32_t)0x10 // Compare function greater than enable +#define ADC_SC2_ACREN (uint32_t)0x08 // Compare function range enable +#define ADC_SC2_DMAEN (uint32_t)0x04 // DMA enable +#define ADC_SC2_REFSEL(n) (uint32_t)(((n) & 3) << 0) // Voltage reference, 0=vcc/external, 1=1.2 volts +#define ADC0_SC3 *(volatile uint32_t *)0x4003B024 // Status and control register 3 +#define ADC_SC3_CAL (uint32_t)0x80 // Calibration, 1=begin, stays set while cal in progress +#define ADC_SC3_CALF (uint32_t)0x40 // Calibration failed flag +#define ADC_SC3_ADCO (uint32_t)0x08 // Continuous conversion enable +#define ADC_SC3_AVGE (uint32_t)0x04 // Hardware average enable +#define ADC_SC3_AVGS(n) (uint32_t)(((n) & 3) << 0) // avg select, 0=4 samples, 1=8 samples, 2=16 samples, 3=32 samples +#define ADC0_OFS *(volatile uint32_t *)0x4003B028 // ADC offset correction register +#define ADC0_PG *(volatile uint32_t *)0x4003B02C // ADC plus-side gain register +#define ADC0_MG *(volatile uint32_t *)0x4003B030 // ADC minus-side gain register +#define ADC0_CLPD *(volatile uint32_t *)0x4003B034 // ADC plus-side general calibration value register +#define ADC0_CLPS *(volatile uint32_t *)0x4003B038 // ADC plus-side general calibration value register +#define ADC0_CLP4 *(volatile uint32_t *)0x4003B03C // ADC plus-side general calibration value register +#define ADC0_CLP3 *(volatile uint32_t *)0x4003B040 // ADC plus-side general calibration value register +#define ADC0_CLP2 *(volatile uint32_t *)0x4003B044 // ADC plus-side general calibration value register +#define ADC0_CLP1 *(volatile uint32_t *)0x4003B048 // ADC plus-side general calibration value register +#define ADC0_CLP0 *(volatile uint32_t *)0x4003B04C // ADC plus-side general calibration value register +#define ADC0_PGA *(volatile uint32_t *)0x4003B050 // ADC Programmable Gain Amplifier +#define ADC_PGA_PGAEN (uint32_t)0x00800000 // Enable +#define ADC_PGA_PGALPB (uint32_t)0x00100000 // Low-Power Mode Control, 0=low power, 1=normal +#define ADC_PGA_PGAG(n) (uint32_t)(((n) & 15) << 16) // Gain, 0=1X, 1=2X, 2=4X, 3=8X, 4=16X, 5=32X, 6=64X +#define ADC0_CLMD *(volatile uint32_t *)0x4003B054 // ADC minus-side general calibration value register +#define ADC0_CLMS *(volatile uint32_t *)0x4003B058 // ADC minus-side general calibration value register +#define ADC0_CLM4 *(volatile uint32_t *)0x4003B05C // ADC minus-side general calibration value register +#define ADC0_CLM3 *(volatile uint32_t *)0x4003B060 // ADC minus-side general calibration value register +#define ADC0_CLM2 *(volatile uint32_t *)0x4003B064 // ADC minus-side general calibration value register +#define ADC0_CLM1 *(volatile uint32_t *)0x4003B068 // ADC minus-side general calibration value register +#define ADC0_CLM0 *(volatile uint32_t *)0x4003B06C // ADC minus-side general calibration value register + +#define ADC1_SC1A *(volatile uint32_t *)0x400BB000 // ADC status and control registers 1 +#define ADC1_SC1B *(volatile uint32_t *)0x400BB004 // ADC status and control registers 1 +#define ADC1_CFG1 *(volatile uint32_t *)0x400BB008 // ADC configuration register 1 +#define ADC1_CFG2 *(volatile uint32_t *)0x400BB00C // Configuration register 2 +#define ADC1_RA *(volatile uint32_t *)0x400BB010 // ADC data result register +#define ADC1_RB *(volatile uint32_t *)0x400BB014 // ADC data result register +#define ADC1_CV1 *(volatile uint32_t *)0x400BB018 // Compare value registers +#define ADC1_CV2 *(volatile uint32_t *)0x400BB01C // Compare value registers +#define ADC1_SC2 *(volatile uint32_t *)0x400BB020 // Status and control register 2 +#define ADC1_SC3 *(volatile uint32_t *)0x400BB024 // Status and control register 3 +#define ADC1_OFS *(volatile uint32_t *)0x400BB028 // ADC offset correction register +#define ADC1_PG *(volatile uint32_t *)0x400BB02C // ADC plus-side gain register +#define ADC1_MG *(volatile uint32_t *)0x400BB030 // ADC minus-side gain register +#define ADC1_CLPD *(volatile uint32_t *)0x400BB034 // ADC plus-side general calibration value register +#define ADC1_CLPS *(volatile uint32_t *)0x400BB038 // ADC plus-side general calibration value register +#define ADC1_CLP4 *(volatile uint32_t *)0x400BB03C // ADC plus-side general calibration value register +#define ADC1_CLP3 *(volatile uint32_t *)0x400BB040 // ADC plus-side general calibration value register +#define ADC1_CLP2 *(volatile uint32_t *)0x400BB044 // ADC plus-side general calibration value register +#define ADC1_CLP1 *(volatile uint32_t *)0x400BB048 // ADC plus-side general calibration value register +#define ADC1_CLP0 *(volatile uint32_t *)0x400BB04C // ADC plus-side general calibration value register +#define ADC1_PGA *(volatile uint32_t *)0x400BB050 // ADC Programmable Gain Amplifier +#define ADC1_CLMD *(volatile uint32_t *)0x400BB054 // ADC minus-side general calibration value register +#define ADC1_CLMS *(volatile uint32_t *)0x400BB058 // ADC minus-side general calibration value register +#define ADC1_CLM4 *(volatile uint32_t *)0x400BB05C // ADC minus-side general calibration value register +#define ADC1_CLM3 *(volatile uint32_t *)0x400BB060 // ADC minus-side general calibration value register +#define ADC1_CLM2 *(volatile uint32_t *)0x400BB064 // ADC minus-side general calibration value register +#define ADC1_CLM1 *(volatile uint32_t *)0x400BB068 // ADC minus-side general calibration value register +#define ADC1_CLM0 *(volatile uint32_t *)0x400BB06C // ADC minus-side general calibration value register + +#define DAC0_DAT0L *(volatile uint8_t *)0x400CC000 // DAC Data Low Register +#define DAC0_DATH *(volatile uint8_t *)0x400CC001 // DAC Data High Register +#define DAC0_DAT1L *(volatile uint8_t *)0x400CC002 // DAC Data Low Register +#define DAC0_DAT2L *(volatile uint8_t *)0x400CC004 // DAC Data Low Register +#define DAC0_DAT3L *(volatile uint8_t *)0x400CC006 // DAC Data Low Register +#define DAC0_DAT4L *(volatile uint8_t *)0x400CC008 // DAC Data Low Register +#define DAC0_DAT5L *(volatile uint8_t *)0x400CC00A // DAC Data Low Register +#define DAC0_DAT6L *(volatile uint8_t *)0x400CC00C // DAC Data Low Register +#define DAC0_DAT7L *(volatile uint8_t *)0x400CC00E // DAC Data Low Register +#define DAC0_DAT8L *(volatile uint8_t *)0x400CC010 // DAC Data Low Register +#define DAC0_DAT9L *(volatile uint8_t *)0x400CC012 // DAC Data Low Register +#define DAC0_DAT10L *(volatile uint8_t *)0x400CC014 // DAC Data Low Register +#define DAC0_DAT11L *(volatile uint8_t *)0x400CC016 // DAC Data Low Register +#define DAC0_DAT12L *(volatile uint8_t *)0x400CC018 // DAC Data Low Register +#define DAC0_DAT13L *(volatile uint8_t *)0x400CC01A // DAC Data Low Register +#define DAC0_DAT14L *(volatile uint8_t *)0x400CC01C // DAC Data Low Register +#define DAC0_DAT15L *(volatile uint8_t *)0x400CC01E // DAC Data Low Register +#define DAC0_SR *(volatile uint8_t *)0x400CC020 // DAC Status Register +#define DAC0_C0 *(volatile uint8_t *)0x400CC021 // DAC Control Register +#define DAC_C0_DACEN 0x80 // DAC Enable +#define DAC_C0_DACRFS 0x40 // DAC Reference Select +#define DAC_C0_DACTRGSEL 0x20 // DAC Trigger Select +#define DAC_C0_DACSWTRG 0x10 // DAC Software Trigger +#define DAC_C0_LPEN 0x08 // DAC Low Power Control +#define DAC_C0_DACBWIEN 0x04 // DAC Buffer Watermark Interrupt Enable +#define DAC_C0_DACBTIEN 0x02 // DAC Buffer Read Pointer Top Flag Interrupt Enable +#define DAC_C0_DACBBIEN 0x01 // DAC Buffer Read Pointer Bottom Flag Interrupt Enable +#define DAC0_C1 *(volatile uint8_t *)0x400CC022 // DAC Control Register 1 +#define DAC_C1_DMAEN 0x80 // DMA Enable Select +#define DAC_C1_DACBFWM(n) (((n) & 3) << 3) // DAC Buffer Watermark Select +#define DAC_C1_DACBFMD(n) (((n) & 3) << 0) // DAC Buffer Work Mode Select +#define DAC_C1_DACBFEN 0x00 // DAC Buffer Enable + +#define DAC0_C2 *(volatile uint8_t *)0x400CC023 // DAC Control Register 2 +#define DAC_C2_DACBFRP(n) (((n) & 15) << 4) // DAC Buffer Read Pointer +#define DAC_C2_DACBFUP(n) (((n) & 15) << 0) // DAC Buffer Upper Limit + + +//#define MCG_C2_RANGE0(n) (uint8_t)(((n) & 0x03) << 4) // Frequency Range Select, Selects the frequency range for the crystal oscillator +//#define MCG_C2_LOCRE0 (uint8_t)0x80 // Loss of Clock Reset Enable, Determines whether an interrupt or a reset request is made following a loss of OSC0 + +// Chapter 32: Comparator (CMP) +#define CMP0_CR0 *(volatile uint8_t *)0x40073000 // CMP Control Register 0 +#define CMP0_CR1 *(volatile uint8_t *)0x40073001 // CMP Control Register 1 +#define CMP0_FPR *(volatile uint8_t *)0x40073002 // CMP Filter Period Register +#define CMP0_SCR *(volatile uint8_t *)0x40073003 // CMP Status and Control Register +#define CMP0_DACCR *(volatile uint8_t *)0x40073004 // DAC Control Register +#define CMP0_MUXCR *(volatile uint8_t *)0x40073005 // MUX Control Register +#define CMP1_CR0 *(volatile uint8_t *)0x40073008 // CMP Control Register 0 +#define CMP1_CR1 *(volatile uint8_t *)0x40073009 // CMP Control Register 1 +#define CMP1_FPR *(volatile uint8_t *)0x4007300A // CMP Filter Period Register +#define CMP1_SCR *(volatile uint8_t *)0x4007300B // CMP Status and Control Register +#define CMP1_DACCR *(volatile uint8_t *)0x4007300C // DAC Control Register +#define CMP1_MUXCR *(volatile uint8_t *)0x4007300D // MUX Control Register + +// Chapter 33: Voltage Reference (VREFV1) +#define VREF_TRM *(volatile uint8_t *)0x40074000 // VREF Trim Register +#define VREF_TRM_CHOPEN (uint8_t)0x40 // Chop oscillator enable +#define VREF_TRM_TRIM(n) ((n) & 0x3F) // Trim bits +#define VREF_SC *(volatile uint8_t *)0x40074001 // VREF Status and Control Register +#define VREF_SC_VREFEN (uint8_t)0x80 // Internal Voltage Reference enable +#define VREF_SC_REGEN (uint8_t)0x40 // Regulator enable +#define VREF_SC_ICOMPEN (uint8_t)0x20 // Second order curvature compensation enable +#define VREF_SC_VREFST (uint8_t)0x04 // Internal Voltage Reference stable flag +#define VREF_SC_MODE_LV(n) (uint8_t)(((n) & 3) << 0) // Buffer Mode selection: 0=Bandgap on only + // 1=High power buffer mode, + // 2=Low-power buffer mode + +// Chapter 34: Programmable Delay Block (PDB) +#define PDB0_SC *(volatile uint32_t *)0x40036000 // Status and Control Register +#define PDB_SC_LDMOD(n) (((n) & 3) << 18) // Load Mode Select +#define PDB_SC_PDBEIE 0x00020000 // Sequence Error Interrupt Enable +#define PDB_SC_SWTRIG 0x00010000 // Software Trigger +#define PDB_SC_DMAEN 0x00008000 // DMA Enable +#define PDB_SC_PRESCALER(n) (((n) & 7) << 12) // Prescaler Divider Select +#define PDB_SC_TRGSEL(n) (((n) & 15) << 8) // Trigger Input Source Select +#define PDB_SC_PDBEN 0x00000080 // PDB Enable +#define PDB_SC_PDBIF 0x00000040 // PDB Interrupt Flag +#define PDB_SC_PDBIE 0x00000020 // PDB Interrupt Enable. +#define PDB_SC_MULT(n) (((n) & 3) << 2) // Multiplication Factor +#define PDB_SC_CONT 0x00000002 // Continuous Mode Enable +#define PDB_SC_LDOK 0x00000001 // Load OK +#define PDB0_MOD *(volatile uint32_t *)0x40036004 // Modulus Register +#define PDB0_CNT *(volatile uint32_t *)0x40036008 // Counter Register +#define PDB0_IDLY *(volatile uint32_t *)0x4003600C // Interrupt Delay Register +#define PDB0_CH0C1 *(volatile uint32_t *)0x40036010 // Channel n Control Register 1 +#define PDB0_CH0S *(volatile uint32_t *)0x40036014 // Channel n Status Register +#define PDB0_CH0DLY0 *(volatile uint32_t *)0x40036018 // Channel n Delay 0 Register +#define PDB0_CH0DLY1 *(volatile uint32_t *)0x4003601C // Channel n Delay 1 Register +#define PDB0_POEN *(volatile uint32_t *)0x40036190 // Pulse-Out n Enable Register +#define PDB0_PO0DLY *(volatile uint32_t *)0x40036194 // Pulse-Out n Delay Register +#define PDB0_PO1DLY *(volatile uint32_t *)0x40036198 // Pulse-Out n Delay Register + +// Chapter 35: FlexTimer Module (FTM) +#define FTM0_SC *(volatile uint32_t *)0x40038000 // Status And Control +#define FTM_SC_TOF 0x80 // Timer Overflow Flag +#define FTM_SC_TOIE 0x40 // Timer Overflow Interrupt Enable +#define FTM_SC_CPWMS 0x20 // Center-Aligned PWM Select +#define FTM_SC_CLKS(n) (((n) & 3) << 3) // Clock Source Selection +#define FTM_SC_PS(n) (((n) & 7) << 0) // Prescale Factor Selection +#define FTM0_CNT *(volatile uint32_t *)0x40038004 // Counter +#define FTM0_MOD *(volatile uint32_t *)0x40038008 // Modulo +#define FTM0_C0SC *(volatile uint32_t *)0x4003800C // Channel 0 Status And Control +#define FTM0_C0V *(volatile uint32_t *)0x40038010 // Channel 0 Value +#define FTM0_C1SC *(volatile uint32_t *)0x40038014 // Channel 1 Status And Control +#define FTM0_C1V *(volatile uint32_t *)0x40038018 // Channel 1 Value +#define FTM0_C2SC *(volatile uint32_t *)0x4003801C // Channel 2 Status And Control +#define FTM0_C2V *(volatile uint32_t *)0x40038020 // Channel 2 Value +#define FTM0_C3SC *(volatile uint32_t *)0x40038024 // Channel 3 Status And Control +#define FTM0_C3V *(volatile uint32_t *)0x40038028 // Channel 3 Value +#define FTM0_C4SC *(volatile uint32_t *)0x4003802C // Channel 4 Status And Control +#define FTM0_C4V *(volatile uint32_t *)0x40038030 // Channel 4 Value +#define FTM0_C5SC *(volatile uint32_t *)0x40038034 // Channel 5 Status And Control +#define FTM0_C5V *(volatile uint32_t *)0x40038038 // Channel 5 Value +#define FTM0_C6SC *(volatile uint32_t *)0x4003803C // Channel 6 Status And Control +#define FTM0_C6V *(volatile uint32_t *)0x40038040 // Channel 6 Value +#define FTM0_C7SC *(volatile uint32_t *)0x40038044 // Channel 7 Status And Control +#define FTM0_C7V *(volatile uint32_t *)0x40038048 // Channel 7 Value +#define FTM0_CNTIN *(volatile uint32_t *)0x4003804C // Counter Initial Value +#define FTM0_STATUS *(volatile uint32_t *)0x40038050 // Capture And Compare Status +#define FTM0_MODE *(volatile uint32_t *)0x40038054 // Features Mode Selection +#define FTM_MODE_FAULTIE 0x80 // Fault Interrupt Enable +#define FTM_MODE_FAULTM(n) (((n) & 3) << 5) // Fault Control Mode +#define FTM_MODE_CAPTEST 0x10 // Capture Test Mode Enable +#define FTM_MODE_PWMSYNC 0x08 // PWM Synchronization Mode +#define FTM_MODE_WPDIS 0x04 // Write Protection Disable +#define FTM_MODE_INIT 0x02 // Initialize The Channels Output +#define FTM_MODE_FTMEN 0x01 // FTM Enable +#define FTM0_SYNC *(volatile uint32_t *)0x40038058 // Synchronization +#define FTM_SYNC_SWSYNC 0x80 // +#define FTM_SYNC_TRIG2 0x40 // +#define FTM_SYNC_TRIG1 0x20 // +#define FTM_SYNC_TRIG0 0x10 // +#define FTM_SYNC_SYNCHOM 0x08 // +#define FTM_SYNC_REINIT 0x04 // +#define FTM_SYNC_CNTMAX 0x02 // +#define FTM_SYNC_CNTMIN 0x01 // +#define FTM0_OUTINIT *(volatile uint32_t *)0x4003805C // Initial State For Channels Output +#define FTM0_OUTMASK *(volatile uint32_t *)0x40038060 // Output Mask +#define FTM0_COMBINE *(volatile uint32_t *)0x40038064 // Function For Linked Channels +#define FTM0_DEADTIME *(volatile uint32_t *)0x40038068 // Deadtime Insertion Control +#define FTM0_EXTTRIG *(volatile uint32_t *)0x4003806C // FTM External Trigger +#define FTM0_POL *(volatile uint32_t *)0x40038070 // Channels Polarity +#define FTM0_FMS *(volatile uint32_t *)0x40038074 // Fault Mode Status +#define FTM0_FILTER *(volatile uint32_t *)0x40038078 // Input Capture Filter Control +#define FTM0_FLTCTRL *(volatile uint32_t *)0x4003807C // Fault Control +#define FTM0_QDCTRL *(volatile uint32_t *)0x40038080 // Quadrature Decoder Control And Status +#define FTM0_CONF *(volatile uint32_t *)0x40038084 // Configuration +#define FTM0_FLTPOL *(volatile uint32_t *)0x40038088 // FTM Fault Input Polarity +#define FTM0_SYNCONF *(volatile uint32_t *)0x4003808C // Synchronization Configuration +#define FTM0_INVCTRL *(volatile uint32_t *)0x40038090 // FTM Inverting Control +#define FTM0_SWOCTRL *(volatile uint32_t *)0x40038094 // FTM Software Output Control +#define FTM0_PWMLOAD *(volatile uint32_t *)0x40038098 // FTM PWM Load +#define FTM1_SC *(volatile uint32_t *)0x40039000 // Status And Control +#define FTM1_CNT *(volatile uint32_t *)0x40039004 // Counter +#define FTM1_MOD *(volatile uint32_t *)0x40039008 // Modulo +#define FTM1_C0SC *(volatile uint32_t *)0x4003900C // Channel 0 Status And Control +#define FTM1_C0V *(volatile uint32_t *)0x40039010 // Channel 0 Value +#define FTM1_C1SC *(volatile uint32_t *)0x40039014 // Channel 1 Status And Control +#define FTM1_C1V *(volatile uint32_t *)0x40039018 // Channel 1 Value +#define FTM1_CNTIN *(volatile uint32_t *)0x4003904C // Counter Initial Value +#define FTM1_STATUS *(volatile uint32_t *)0x40039050 // Capture And Compare Status +#define FTM1_MODE *(volatile uint32_t *)0x40039054 // Features Mode Selection +#define FTM1_SYNC *(volatile uint32_t *)0x40039058 // Synchronization +#define FTM1_OUTINIT *(volatile uint32_t *)0x4003905C // Initial State For Channels Output +#define FTM1_OUTMASK *(volatile uint32_t *)0x40039060 // Output Mask +#define FTM1_COMBINE *(volatile uint32_t *)0x40039064 // Function For Linked Channels +#define FTM1_DEADTIME *(volatile uint32_t *)0x40039068 // Deadtime Insertion Control +#define FTM1_EXTTRIG *(volatile uint32_t *)0x4003906C // FTM External Trigger +#define FTM1_POL *(volatile uint32_t *)0x40039070 // Channels Polarity +#define FTM1_FMS *(volatile uint32_t *)0x40039074 // Fault Mode Status +#define FTM1_FILTER *(volatile uint32_t *)0x40039078 // Input Capture Filter Control +#define FTM1_FLTCTRL *(volatile uint32_t *)0x4003907C // Fault Control +#define FTM1_QDCTRL *(volatile uint32_t *)0x40039080 // Quadrature Decoder Control And Status +#define FTM1_CONF *(volatile uint32_t *)0x40039084 // Configuration +#define FTM1_FLTPOL *(volatile uint32_t *)0x40039088 // FTM Fault Input Polarity +#define FTM1_SYNCONF *(volatile uint32_t *)0x4003908C // Synchronization Configuration +#define FTM1_INVCTRL *(volatile uint32_t *)0x40039090 // FTM Inverting Control +#define FTM1_SWOCTRL *(volatile uint32_t *)0x40039094 // FTM Software Output Control +#define FTM1_PWMLOAD *(volatile uint32_t *)0x40039098 // FTM PWM Load +#define FTM2_SC *(volatile uint32_t *)0x400B8000 // Status And Control +#define FTM2_CNT *(volatile uint32_t *)0x400B8004 // Counter +#define FTM2_MOD *(volatile uint32_t *)0x400B8008 // Modulo +#define FTM2_C0SC *(volatile uint32_t *)0x400B800C // Channel 0 Status And Control +#define FTM2_C0V *(volatile uint32_t *)0x400B8010 // Channel 0 Value +#define FTM2_C1SC *(volatile uint32_t *)0x400B8014 // Channel 1 Status And Control +#define FTM2_C1V *(volatile uint32_t *)0x400B8018 // Channel 1 Value +#define FTM2_CNTIN *(volatile uint32_t *)0x400B804C // Counter Initial Value +#define FTM2_STATUS *(volatile uint32_t *)0x400B8050 // Capture And Compare Status +#define FTM2_MODE *(volatile uint32_t *)0x400B8054 // Features Mode Selection +#define FTM2_SYNC *(volatile uint32_t *)0x400B8058 // Synchronization +#define FTM2_OUTINIT *(volatile uint32_t *)0x400B805C // Initial State For Channels Output +#define FTM2_OUTMASK *(volatile uint32_t *)0x400B8060 // Output Mask +#define FTM2_COMBINE *(volatile uint32_t *)0x400B8064 // Function For Linked Channels +#define FTM2_DEADTIME *(volatile uint32_t *)0x400B8068 // Deadtime Insertion Control +#define FTM2_EXTTRIG *(volatile uint32_t *)0x400B806C // FTM External Trigger +#define FTM2_POL *(volatile uint32_t *)0x400B8070 // Channels Polarity +#define FTM2_FMS *(volatile uint32_t *)0x400B8074 // Fault Mode Status +#define FTM2_FILTER *(volatile uint32_t *)0x400B8078 // Input Capture Filter Control +#define FTM2_FLTCTRL *(volatile uint32_t *)0x400B807C // Fault Control +#define FTM2_QDCTRL *(volatile uint32_t *)0x400B8080 // Quadrature Decoder Control And Status +#define FTM2_CONF *(volatile uint32_t *)0x400B8084 // Configuration +#define FTM2_FLTPOL *(volatile uint32_t *)0x400B8088 // FTM Fault Input Polarity +#define FTM2_SYNCONF *(volatile uint32_t *)0x400B808C // Synchronization Configuration +#define FTM2_INVCTRL *(volatile uint32_t *)0x400B8090 // FTM Inverting Control +#define FTM2_SWOCTRL *(volatile uint32_t *)0x400B8094 // FTM Software Output Control +#define FTM2_PWMLOAD *(volatile uint32_t *)0x400B8098 // FTM PWM Load + +// Chapter 36: Periodic Interrupt Timer (PIT) +#define PIT_MCR *(volatile uint32_t *)0x40037000 // PIT Module Control Register +#define PIT_LDVAL0 *(volatile uint32_t *)0x40037100 // Timer Load Value Register +#define PIT_CVAL0 *(volatile uint32_t *)0x40037104 // Current Timer Value Register +#define PIT_TCTRL0 *(volatile uint32_t *)0x40037108 // Timer Control Register +#define PIT_TFLG0 *(volatile uint32_t *)0x4003710C // Timer Flag Register +#define PIT_LDVAL1 *(volatile uint32_t *)0x40037110 // Timer Load Value Register +#define PIT_CVAL1 *(volatile uint32_t *)0x40037114 // Current Timer Value Register +#define PIT_TCTRL1 *(volatile uint32_t *)0x40037118 // Timer Control Register +#define PIT_TFLG1 *(volatile uint32_t *)0x4003711C // Timer Flag Register +#define PIT_LDVAL2 *(volatile uint32_t *)0x40037120 // Timer Load Value Register +#define PIT_CVAL2 *(volatile uint32_t *)0x40037124 // Current Timer Value Register +#define PIT_TCTRL2 *(volatile uint32_t *)0x40037128 // Timer Control Register +#define PIT_TFLG2 *(volatile uint32_t *)0x4003712C // Timer Flag Register +#define PIT_LDVAL3 *(volatile uint32_t *)0x40037130 // Timer Load Value Register +#define PIT_CVAL3 *(volatile uint32_t *)0x40037134 // Current Timer Value Register +#define PIT_TCTRL3 *(volatile uint32_t *)0x40037138 // Timer Control Register +#define PIT_TFLG3 *(volatile uint32_t *)0x4003713C // Timer Flag Register + +// Chapter 37: Low-Power Timer (LPTMR) +#define LPTMR0_CSR *(volatile uint32_t *)0x40040000 // Low Power Timer Control Status Register +#define LPTMR0_PSR *(volatile uint32_t *)0x40040004 // Low Power Timer Prescale Register +#define LPTMR0_CMR *(volatile uint32_t *)0x40040008 // Low Power Timer Compare Register +#define LPTMR0_CNR *(volatile uint32_t *)0x4004000C // Low Power Timer Counter Register + +// Chapter 38: Carrier Modulator Transmitter (CMT) +#define CMT_CGH1 *(volatile uint8_t *)0x40062000 // CMT Carrier Generator High Data Register 1 +#define CMT_CGL1 *(volatile uint8_t *)0x40062001 // CMT Carrier Generator Low Data Register 1 +#define CMT_CGH2 *(volatile uint8_t *)0x40062002 // CMT Carrier Generator High Data Register 2 +#define CMT_CGL2 *(volatile uint8_t *)0x40062003 // CMT Carrier Generator Low Data Register 2 +#define CMT_OC *(volatile uint8_t *)0x40062004 // CMT Output Control Register +#define CMT_MSC *(volatile uint8_t *)0x40062005 // CMT Modulator Status and Control Register +#define CMT_CMD1 *(volatile uint8_t *)0x40062006 // CMT Modulator Data Register Mark High +#define CMT_CMD2 *(volatile uint8_t *)0x40062007 // CMT Modulator Data Register Mark Low +#define CMT_CMD3 *(volatile uint8_t *)0x40062008 // CMT Modulator Data Register Space High +#define CMT_CMD4 *(volatile uint8_t *)0x40062009 // CMT Modulator Data Register Space Low +#define CMT_PPS *(volatile uint8_t *)0x4006200A // CMT Primary Prescaler Register +#define CMT_DMA *(volatile uint8_t *)0x4006200B // CMT Direct Memory Access Register + +// Chapter 39: Real Time Clock (RTC) +#define RTC_TSR *(volatile uint32_t *)0x4003D000 // RTC Time Seconds Register +#define RTC_TPR *(volatile uint32_t *)0x4003D004 // RTC Time Prescaler Register +#define RTC_TAR *(volatile uint32_t *)0x4003D008 // RTC Time Alarm Register +#define RTC_TCR *(volatile uint32_t *)0x4003D00C // RTC Time Compensation Register +#define RTC_TCR_CIC(n) (((n) & 255) << 24) // Compensation Interval Counter +#define RTC_TCR_TCV(n) (((n) & 255) << 16) // Time Compensation Value +#define RTC_TCR_CIR(n) (((n) & 255) << 8) // Compensation Interval Register +#define RTC_TCR_TCR(n) (((n) & 255) << 0) // Time Compensation Register +#define RTC_CR *(volatile uint32_t *)0x4003D010 // RTC Control Register +#define RTC_CR_SC2P (uint32_t)0x00002000 // +#define RTC_CR_SC4P (uint32_t)0x00001000 // +#define RTC_CR_SC8P (uint32_t)0x00000800 // +#define RTC_CR_SC16P (uint32_t)0x00000400 // +#define RTC_CR_CLKO (uint32_t)0x00000200 // +#define RTC_CR_OSCE (uint32_t)0x00000100 // +#define RTC_CR_UM (uint32_t)0x00000008 // +#define RTC_CR_SUP (uint32_t)0x00000004 // +#define RTC_CR_WPE (uint32_t)0x00000002 // +#define RTC_CR_SWR (uint32_t)0x00000001 // +#define RTC_SR *(volatile uint32_t *)0x4003D014 // RTC Status Register +#define RTC_SR_TCE (uint32_t)0x00000010 // +#define RTC_SR_TAF (uint32_t)0x00000004 // +#define RTC_SR_TOF (uint32_t)0x00000002 // +#define RTC_SR_TIF (uint32_t)0x00000001 // +#define RTC_LR *(volatile uint32_t *)0x4003D018 // RTC Lock Register +#define RTC_IER *(volatile uint32_t *)0x4003D01C // RTC Interrupt Enable Register +#define RTC_WAR *(volatile uint32_t *)0x4003D800 // RTC Write Access Register +#define RTC_RAR *(volatile uint32_t *)0x4003D804 // RTC Read Access Register + +// Chapter 40: Universal Serial Bus OTG Controller (USBOTG) +#define USB0_PERID *(const uint8_t *)0x40072000 // Peripheral ID register +#define USB0_IDCOMP *(const uint8_t *)0x40072004 // Peripheral ID Complement register +#define USB0_REV *(const uint8_t *)0x40072008 // Peripheral Revision register +#define USB0_ADDINFO *(volatile uint8_t *)0x4007200C // Peripheral Additional Info register +#define USB0_OTGISTAT *(volatile uint8_t *)0x40072010 // OTG Interrupt Status register +#define USB_OTGISTAT_IDCHG (uint8_t)0x80 // +#define USB_OTGISTAT_ONEMSEC (uint8_t)0x40 // +#define USB_OTGISTAT_LINE_STATE_CHG (uint8_t)0x20 // +#define USB_OTGISTAT_SESSVLDCHG (uint8_t)0x08 // +#define USB_OTGISTAT_B_SESS_CHG (uint8_t)0x04 // +#define USB_OTGISTAT_AVBUSCHG (uint8_t)0x01 // +#define USB0_OTGICR *(volatile uint8_t *)0x40072014 // OTG Interrupt Control Register +#define USB_OTGICR_IDEN (uint8_t)0x80 // +#define USB_OTGICR_ONEMSECEN (uint8_t)0x40 // +#define USB_OTGICR_LINESTATEEN (uint8_t)0x20 // +#define USB_OTGICR_SESSVLDEN (uint8_t)0x08 // +#define USB_OTGICR_BSESSEN (uint8_t)0x04 // +#define USB_OTGICR_AVBUSEN (uint8_t)0x01 // +#define USB0_OTGSTAT *(volatile uint8_t *)0x40072018 // OTG Status register +#define USB_OTGSTAT_ID (uint8_t)0x80 // +#define USB_OTGSTAT_ONEMSECEN (uint8_t)0x40 // +#define USB_OTGSTAT_LINESTATESTABLE (uint8_t)0x20 // +#define USB_OTGSTAT_SESS_VLD (uint8_t)0x08 // +#define USB_OTGSTAT_BSESSEND (uint8_t)0x04 // +#define USB_OTGSTAT_AVBUSVLD (uint8_t)0x01 // +#define USB0_OTGCTL *(volatile uint8_t *)0x4007201C // OTG Control Register +#define USB_OTGCTL_DPHIGH (uint8_t)0x80 // +#define USB_OTGCTL_DPLOW (uint8_t)0x20 // +#define USB_OTGCTL_DMLOW (uint8_t)0x10 // +#define USB_OTGCTL_OTGEN (uint8_t)0x04 // +#define USB0_ISTAT *(volatile uint8_t *)0x40072080 // Interrupt Status Register +#define USB_ISTAT_STALL (uint8_t)0x80 // +#define USB_ISTAT_ATTACH (uint8_t)0x40 // +#define USB_ISTAT_RESUME (uint8_t)0x20 // +#define USB_ISTAT_SLEEP (uint8_t)0x10 // +#define USB_ISTAT_TOKDNE (uint8_t)0x08 // +#define USB_ISTAT_SOFTOK (uint8_t)0x04 // +#define USB_ISTAT_ERROR (uint8_t)0x02 // +#define USB_ISTAT_USBRST (uint8_t)0x01 // +#define USB0_INTEN *(volatile uint8_t *)0x40072084 // Interrupt Enable Register +#define USB_INTEN_STALLEN (uint8_t)0x80 // +#define USB_INTEN_ATTACHEN (uint8_t)0x40 // +#define USB_INTEN_RESUMEEN (uint8_t)0x20 // +#define USB_INTEN_SLEEPEN (uint8_t)0x10 // +#define USB_INTEN_TOKDNEEN (uint8_t)0x08 // +#define USB_INTEN_SOFTOKEN (uint8_t)0x04 // +#define USB_INTEN_ERROREN (uint8_t)0x02 // +#define USB_INTEN_USBRSTEN (uint8_t)0x01 // +#define USB0_ERRSTAT *(volatile uint8_t *)0x40072088 // Error Interrupt Status Register +#define USB_ERRSTAT_BTSERR (uint8_t)0x80 // +#define USB_ERRSTAT_DMAERR (uint8_t)0x20 // +#define USB_ERRSTAT_BTOERR (uint8_t)0x10 // +#define USB_ERRSTAT_DFN8 (uint8_t)0x08 // +#define USB_ERRSTAT_CRC16 (uint8_t)0x04 // +#define USB_ERRSTAT_CRC5EOF (uint8_t)0x02 // +#define USB_ERRSTAT_PIDERR (uint8_t)0x01 // +#define USB0_ERREN *(volatile uint8_t *)0x4007208C // Error Interrupt Enable Register +#define USB_ERREN_BTSERREN (uint8_t)0x80 // +#define USB_ERREN_DMAERREN (uint8_t)0x20 // +#define USB_ERREN_BTOERREN (uint8_t)0x10 // +#define USB_ERREN_DFN8EN (uint8_t)0x08 // +#define USB_ERREN_CRC16EN (uint8_t)0x04 // +#define USB_ERREN_CRC5EOFEN (uint8_t)0x02 // +#define USB_ERREN_PIDERREN (uint8_t)0x01 // +#define USB0_STAT *(volatile uint8_t *)0x40072090 // Status Register +#define USB_STAT_TX (uint8_t)0x08 // +#define USB_STAT_ODD (uint8_t)0x04 // +#define USB_STAT_ENDP(n) (uint8_t)((n) >> 4) // +#define USB0_CTL *(volatile uint8_t *)0x40072094 // Control Register +#define USB_CTL_JSTATE (uint8_t)0x80 // +#define USB_CTL_SE0 (uint8_t)0x40 // +#define USB_CTL_TXSUSPENDTOKENBUSY (uint8_t)0x20 // +#define USB_CTL_RESET (uint8_t)0x10 // +#define USB_CTL_HOSTMODEEN (uint8_t)0x08 // +#define USB_CTL_RESUME (uint8_t)0x04 // +#define USB_CTL_ODDRST (uint8_t)0x02 // +#define USB_CTL_USBENSOFEN (uint8_t)0x01 // +#define USB0_ADDR *(volatile uint8_t *)0x40072098 // Address Register +#define USB0_BDTPAGE1 *(volatile uint8_t *)0x4007209C // BDT Page Register 1 +#define USB0_FRMNUML *(volatile uint8_t *)0x400720A0 // Frame Number Register Low +#define USB0_FRMNUMH *(volatile uint8_t *)0x400720A4 // Frame Number Register High +#define USB0_TOKEN *(volatile uint8_t *)0x400720A8 // Token Register +#define USB0_SOFTHLD *(volatile uint8_t *)0x400720AC // SOF Threshold Register +#define USB0_BDTPAGE2 *(volatile uint8_t *)0x400720B0 // BDT Page Register 2 +#define USB0_BDTPAGE3 *(volatile uint8_t *)0x400720B4 // BDT Page Register 3 +#define USB0_ENDPT0 *(volatile uint8_t *)0x400720C0 // Endpoint Control Register +#define USB_ENDPT_HOSTWOHUB (uint8_t)0x80 // host only, enable low speed +#define USB_ENDPT_RETRYDIS (uint8_t)0x40 // host only, set to disable NAK retry +#define USB_ENDPT_EPCTLDIS (uint8_t)0x10 // 0=control, 1=bulk, interrupt, isync +#define USB_ENDPT_EPRXEN (uint8_t)0x08 // enables the endpoint for RX transfers. +#define USB_ENDPT_EPTXEN (uint8_t)0x04 // enables the endpoint for TX transfers. +#define USB_ENDPT_EPSTALL (uint8_t)0x02 // set to stall endpoint +#define USB_ENDPT_EPHSHK (uint8_t)0x01 // enable handshaking during a transaction, generally set unless Isochronous +#define USB0_ENDPT1 *(volatile uint8_t *)0x400720C4 // Endpoint Control Register +#define USB0_ENDPT2 *(volatile uint8_t *)0x400720C8 // Endpoint Control Register +#define USB0_ENDPT3 *(volatile uint8_t *)0x400720CC // Endpoint Control Register +#define USB0_ENDPT4 *(volatile uint8_t *)0x400720D0 // Endpoint Control Register +#define USB0_ENDPT5 *(volatile uint8_t *)0x400720D4 // Endpoint Control Register +#define USB0_ENDPT6 *(volatile uint8_t *)0x400720D8 // Endpoint Control Register +#define USB0_ENDPT7 *(volatile uint8_t *)0x400720DC // Endpoint Control Register +#define USB0_ENDPT8 *(volatile uint8_t *)0x400720E0 // Endpoint Control Register +#define USB0_ENDPT9 *(volatile uint8_t *)0x400720E4 // Endpoint Control Register +#define USB0_ENDPT10 *(volatile uint8_t *)0x400720E8 // Endpoint Control Register +#define USB0_ENDPT11 *(volatile uint8_t *)0x400720EC // Endpoint Control Register +#define USB0_ENDPT12 *(volatile uint8_t *)0x400720F0 // Endpoint Control Register +#define USB0_ENDPT13 *(volatile uint8_t *)0x400720F4 // Endpoint Control Register +#define USB0_ENDPT14 *(volatile uint8_t *)0x400720F8 // Endpoint Control Register +#define USB0_ENDPT15 *(volatile uint8_t *)0x400720FC // Endpoint Control Register +#define USB0_USBCTRL *(volatile uint8_t *)0x40072100 // USB Control Register +#define USB_USBCTRL_SUSP (uint8_t)0x80 // Places the USB transceiver into the suspend state. +#define USB_USBCTRL_PDE (uint8_t)0x40 // Enables the weak pulldowns on the USB transceiver. +#define USB0_OBSERVE *(volatile uint8_t *)0x40072104 // USB OTG Observe Register +#define USB_OBSERVE_DPPU (uint8_t)0x80 // +#define USB_OBSERVE_DPPD (uint8_t)0x40 // +#define USB_OBSERVE_DMPD (uint8_t)0x10 // +#define USB0_CONTROL *(volatile uint8_t *)0x40072108 // USB OTG Control Register +#define USB_CONTROL_DPPULLUPNONOTG (uint8_t)0x10 // Provides control of the DP PULLUP in the USB OTG module, if USB is configured in non-OTG device mode. +#define USB0_USBTRC0 *(volatile uint8_t *)0x4007210C // USB Transceiver Control Register 0 +#define USB_USBTRC_USBRESET (uint8_t)0x80 // +#define USB_USBTRC_USBRESMEN (uint8_t)0x20 // +#define USB_USBTRC_SYNC_DET (uint8_t)0x02 // +#define USB_USBTRC_USB_RESUME_INT (uint8_t)0x01 // +#define USB0_USBFRMADJUST *(volatile uint8_t *)0x40072114 // Frame Adjust Register + +// Chapter 41: USB Device Charger Detection Module (USBDCD) +#define USBDCD_CONTROL *(volatile uint32_t *)0x40035000 // Control register +#define USBDCD_CLOCK *(volatile uint32_t *)0x40035004 // Clock register +#define USBDCD_STATUS *(volatile uint32_t *)0x40035008 // Status register +#define USBDCD_TIMER0 *(volatile uint32_t *)0x40035010 // TIMER0 register +#define USBDCD_TIMER1 *(volatile uint32_t *)0x40035014 // TIMER1 register +#define USBDCD_TIMER2 *(volatile uint32_t *)0x40035018 // TIMER2 register + +// Chapter 43: SPI (DSPI) +#define SPI0_MCR *(volatile uint32_t *)0x4002C000 // DSPI Module Configuration Register +#define SPI_MCR_MSTR (uint32_t)0x80000000 // Master/Slave Mode Select +#define SPI_MCR_CONT_SCKE (uint32_t)0x40000000 // +#define SPI_MCR_DCONF(n) (((n) & 3) << 28) // +#define SPI_MCR_FRZ (uint32_t)0x08000000 // +#define SPI_MCR_MTFE (uint32_t)0x04000000 // +#define SPI_MCR_ROOE (uint32_t)0x01000000 // +#define SPI_MCR_PCSIS(n) (((n) & 0x1F) << 16) // +#define SPI_MCR_DOZE (uint32_t)0x00008000 // +#define SPI_MCR_MDIS (uint32_t)0x00004000 // +#define SPI_MCR_DIS_TXF (uint32_t)0x00002000 // +#define SPI_MCR_DIS_RXF (uint32_t)0x00001000 // +#define SPI_MCR_CLR_TXF (uint32_t)0x00000800 // +#define SPI_MCR_CLR_RXF (uint32_t)0x00000400 // +#define SPI_MCR_SMPL_PT(n) (((n) & 3) << 8) // +#define SPI_MCR_HALT (uint32_t)0x00000001 // +#define SPI0_TCR *(volatile uint32_t *)0x4002C008 // DSPI Transfer Count Register +#define SPI0_CTAR0 *(volatile uint32_t *)0x4002C00C // DSPI Clock and Transfer Attributes Register, In Master Mode +#define SPI_CTAR_DBR (uint32_t)0x80000000 // Double Baud Rate +#define SPI_CTAR_FMSZ(n) (((n) & 15) << 27) // Frame Size (+1) +#define SPI_CTAR_CPOL (uint32_t)0x04000000 // Clock Polarity +#define SPI_CTAR_CPHA (uint32_t)0x02000000 // Clock Phase +#define SPI_CTAR_LSBFE (uint32_t)0x01000000 // LSB First +#define SPI_CTAR_PCSSCK(n) (((n) & 3) << 22) // PCS to SCK Delay Prescaler +#define SPI_CTAR_PASC(n) (((n) & 3) << 20) // After SCK Delay Prescaler +#define SPI_CTAR_PDT(n) (((n) & 3) << 18) // Delay after Transfer Prescaler +#define SPI_CTAR_PBR(n) (((n) & 3) << 16) // Baud Rate Prescaler +#define SPI_CTAR_CSSCK(n) (((n) & 15) << 12) // PCS to SCK Delay Scaler +#define SPI_CTAR_ASC(n) (((n) & 15) << 8) // After SCK Delay Scaler +#define SPI_CTAR_DT(n) (((n) & 15) << 4) // Delay After Transfer Scaler +#define SPI_CTAR_BR(n) (((n) & 15) << 0) // Baud Rate Scaler +#define SPI0_CTAR0_SLAVE *(volatile uint32_t *)0x4002C00C // DSPI Clock and Transfer Attributes Register, In Slave Mode +#define SPI0_CTAR1 *(volatile uint32_t *)0x4002C010 // DSPI Clock and Transfer Attributes Register, In Master Mode +#define SPI0_SR *(volatile uint32_t *)0x4002C02C // DSPI Status Register +#define SPI_SR_TCF (uint32_t)0x80000000 // Transfer Complete Flag +#define SPI_SR_TXRXS (uint32_t)0x40000000 // TX and RX Status +#define SPI_SR_EOQF (uint32_t)0x10000000 // End of Queue Flag +#define SPI_SR_TFUF (uint32_t)0x08000000 // Transmit FIFO Underflow Flag +#define SPI_SR_TFFF (uint32_t)0x02000000 // Transmit FIFO Fill Flag +#define SPI_SR_RFOF (uint32_t)0x00080000 // Receive FIFO Overflow Flag +#define SPI_SR_RFDF (uint32_t)0x00020000 // Receive FIFO Drain Flag +#define SPI0_RSER *(volatile uint32_t *)0x4002C030 // DSPI DMA/Interrupt Request Select and Enable Register +#define SPI_RSER_TCF_RE (uint32_t)0x80000000 // Transmission Complete Request Enable +#define SPI_RSER_EOQF_RE (uint32_t)0x10000000 // DSPI Finished Request Request Enable +#define SPI_RSER_TFUF_RE (uint32_t)0x08000000 // Transmit FIFO Underflow Request Enable +#define SPI_RSER_TFFF_RE (uint32_t)0x02000000 // Transmit FIFO Fill Request Enable +#define SPI_RSER_TFFF_DIRS (uint32_t)0x01000000 // Transmit FIFO FIll Dma or Interrupt Request Select +#define SPI_RSER_RFOF_RE (uint32_t)0x00080000 // Receive FIFO Overflow Request Enable +#define SPI_RSER_RFDF_RE (uint32_t)0x00020000 // Receive FIFO Drain Request Enable +#define SPI_RSER_RFDF_DIRS (uint32_t)0x00010000 // Receive FIFO Drain DMA or Interrupt Request Select +#define SPI0_PUSHR *(volatile uint32_t *)0x4002C034 // DSPI PUSH TX FIFO Register In Master Mode +#define SPI_PUSHR_CONT (uint32_t)0x80000000 // +#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28) // +#define SPI_PUSHR_EOQ (uint32_t)0x08000000 // +#define SPI_PUSHR_CTCNT (uint32_t)0x04000000 // +#define SPI_PUSHR_PCS(n) (((n) & 31) << 16) // +#define SPI0_PUSHR_SLAVE *(volatile uint32_t *)0x4002C034 // DSPI PUSH TX FIFO Register In Slave Mode +#define SPI0_POPR *(volatile uint32_t *)0x4002C038 // DSPI POP RX FIFO Register +#define SPI0_TXFR0 *(volatile uint32_t *)0x4002C03C // DSPI Transmit FIFO Registers +#define SPI0_TXFR1 *(volatile uint32_t *)0x4002C040 // DSPI Transmit FIFO Registers +#define SPI0_TXFR2 *(volatile uint32_t *)0x4002C044 // DSPI Transmit FIFO Registers +#define SPI0_TXFR3 *(volatile uint32_t *)0x4002C048 // DSPI Transmit FIFO Registers +#define SPI0_RXFR0 *(volatile uint32_t *)0x4002C07C // DSPI Receive FIFO Registers +#define SPI0_RXFR1 *(volatile uint32_t *)0x4002C080 // DSPI Receive FIFO Registers +#define SPI0_RXFR2 *(volatile uint32_t *)0x4002C084 // DSPI Receive FIFO Registers +#define SPI0_RXFR3 *(volatile uint32_t *)0x4002C088 // DSPI Receive FIFO Registers +typedef struct { + volatile uint32_t MCR; // 0 + volatile uint32_t unused1;// 4 + volatile uint32_t TCR; // 8 + volatile uint32_t CTAR0; // c + volatile uint32_t CTAR1; // 10 + volatile uint32_t CTAR2; // 14 + volatile uint32_t CTAR3; // 18 + volatile uint32_t CTAR4; // 1c + volatile uint32_t CTAR5; // 20 + volatile uint32_t CTAR6; // 24 + volatile uint32_t CTAR7; // 28 + volatile uint32_t SR; // 2c + volatile uint32_t RSER; // 30 + volatile uint32_t PUSHR; // 34 + volatile uint32_t POPR; // 38 + volatile uint32_t TXFR[16]; // 3c + volatile uint32_t RXFR[16]; // 7c +} SPI_t; +#define SPI0 (*(SPI_t *)0x4002C000) + +// Chapter 44: Inter-Integrated Circuit (I2C) +#define I2C0_A1 *(volatile uint8_t *)0x40066000 // I2C Address Register 1 +#define I2C0_F *(volatile uint8_t *)0x40066001 // I2C Frequency Divider register +#define I2C0_C1 *(volatile uint8_t *)0x40066002 // I2C Control Register 1 +#define I2C_C1_IICEN (uint8_t)0x80 // I2C Enable +#define I2C_C1_IICIE (uint8_t)0x40 // I2C Interrupt Enable +#define I2C_C1_MST (uint8_t)0x20 // Master Mode Select +#define I2C_C1_TX (uint8_t)0x10 // Transmit Mode Select +#define I2C_C1_TXAK (uint8_t)0x08 // Transmit Acknowledge Enable +#define I2C_C1_RSTA (uint8_t)0x04 // Repeat START +#define I2C_C1_WUEN (uint8_t)0x02 // Wakeup Enable +#define I2C_C1_DMAEN (uint8_t)0x01 // DMA Enable +#define I2C0_S *(volatile uint8_t *)0x40066003 // I2C Status register +#define I2C_S_TCF (uint8_t)0x80 // Transfer Complete Flag +#define I2C_S_IAAS (uint8_t)0x40 // Addressed As A Slave +#define I2C_S_BUSY (uint8_t)0x20 // Bus Busy +#define I2C_S_ARBL (uint8_t)0x10 // Arbitration Lost +#define I2C_S_RAM (uint8_t)0x08 // Range Address Match +#define I2C_S_SRW (uint8_t)0x04 // Slave Read/Write +#define I2C_S_IICIF (uint8_t)0x02 // Interrupt Flag +#define I2C_S_RXAK (uint8_t)0x01 // Receive Acknowledge +#define I2C0_D *(volatile uint8_t *)0x40066004 // I2C Data I/O register +#define I2C0_C2 *(volatile uint8_t *)0x40066005 // I2C Control Register 2 +#define I2C_C2_GCAEN (uint8_t)0x80 // General Call Address Enable +#define I2C_C2_ADEXT (uint8_t)0x40 // Address Extension +#define I2C_C2_HDRS (uint8_t)0x20 // High Drive Select +#define I2C_C2_SBRC (uint8_t)0x10 // Slave Baud Rate Control +#define I2C_C2_RMEN (uint8_t)0x08 // Range Address Matching Enable +#define I2C_C2_AD(n) ((n) & 7) // Slave Address, upper 3 bits +#define I2C0_FLT *(volatile uint8_t *)0x40066006 // I2C Programmable Input Glitch Filter register +#define I2C0_RA *(volatile uint8_t *)0x40066007 // I2C Range Address register +#define I2C0_SMB *(volatile uint8_t *)0x40066008 // I2C SMBus Control and Status register +#define I2C0_A2 *(volatile uint8_t *)0x40066009 // I2C Address Register 2 +#define I2C0_SLTH *(volatile uint8_t *)0x4006600A // I2C SCL Low Timeout Register High +#define I2C0_SLTL *(volatile uint8_t *)0x4006600B // I2C SCL Low Timeout Register Low + +#define I2C1_A1 *(volatile uint8_t *)0x40067000 // I2C Address Register 1 +#define I2C1_F *(volatile uint8_t *)0x40067001 // I2C Frequency Divider register +#define I2C1_C1 *(volatile uint8_t *)0x40067002 // I2C Control Register 1 +#define I2C1_S *(volatile uint8_t *)0x40067003 // I2C Status register +#define I2C1_D *(volatile uint8_t *)0x40067004 // I2C Data I/O register +#define I2C1_C2 *(volatile uint8_t *)0x40067005 // I2C Control Register 2 +#define I2C1_FLT *(volatile uint8_t *)0x40067006 // I2C Programmable Input Glitch Filter register +#define I2C1_RA *(volatile uint8_t *)0x40067007 // I2C Range Address register +#define I2C1_SMB *(volatile uint8_t *)0x40067008 // I2C SMBus Control and Status register +#define I2C1_A2 *(volatile uint8_t *)0x40067009 // I2C Address Register 2 +#define I2C1_SLTH *(volatile uint8_t *)0x4006700A // I2C SCL Low Timeout Register High +#define I2C1_SLTL *(volatile uint8_t *)0x4006700B // I2C SCL Low Timeout Register Low + +// Chapter 45: Universal Asynchronous Receiver/Transmitter (UART) +#define UART0_BDH *(volatile uint8_t *)0x4006A000 // UART Baud Rate Registers: High +#define UART0_BDL *(volatile uint8_t *)0x4006A001 // UART Baud Rate Registers: Low +#define UART0_C1 *(volatile uint8_t *)0x4006A002 // UART Control Register 1 +#define UART_C1_LOOPS (uint8_t)0x80 // When LOOPS is set, the RxD pin is disconnected from the UART and the transmitter output is internally connected to the receiver input +#define UART_C1_UARTSWAI (uint8_t)0x40 // UART Stops in Wait Mode +#define UART_C1_RSRC (uint8_t)0x20 // When LOOPS is set, the RSRC field determines the source for the receiver shift register input +#define UART_C1_M (uint8_t)0x10 // 9-bit or 8-bit Mode Select +#define UART_C1_WAKE (uint8_t)0x08 // Determines which condition wakes the UART +#define UART_C1_ILT (uint8_t)0x04 // Idle Line Type Select +#define UART_C1_PE (uint8_t)0x02 // Parity Enable +#define UART_C1_PT (uint8_t)0x01 // Parity Type, 0=even, 1=odd +#define UART0_C2 *(volatile uint8_t *)0x4006A003 // UART Control Register 2 +#define UART_C2_TIE (uint8_t)0x80 // Transmitter Interrupt or DMA Transfer Enable. +#define UART_C2_TCIE (uint8_t)0x40 // Transmission Complete Interrupt Enable +#define UART_C2_RIE (uint8_t)0x20 // Receiver Full Interrupt or DMA Transfer Enable +#define UART_C2_ILIE (uint8_t)0x10 // Idle Line Interrupt Enable +#define UART_C2_TE (uint8_t)0x08 // Transmitter Enable +#define UART_C2_RE (uint8_t)0x04 // Receiver Enable +#define UART_C2_RWU (uint8_t)0x02 // Receiver Wakeup Control +#define UART_C2_SBK (uint8_t)0x01 // Send Break +#define UART0_S1 *(volatile uint8_t *)0x4006A004 // UART Status Register 1 +#define UART_S1_TDRE (uint8_t)0x80 // Transmit Data Register Empty Flag +#define UART_S1_TC (uint8_t)0x40 // Transmit Complete Flag +#define UART_S1_RDRF (uint8_t)0x20 // Receive Data Register Full Flag +#define UART_S1_IDLE (uint8_t)0x10 // Idle Line Flag +#define UART_S1_OR (uint8_t)0x08 // Receiver Overrun Flag +#define UART_S1_NF (uint8_t)0x04 // Noise Flag +#define UART_S1_FE (uint8_t)0x02 // Framing Error Flag +#define UART_S1_PF (uint8_t)0x01 // Parity Error Flag +#define UART0_S2 *(volatile uint8_t *)0x4006A005 // UART Status Register 2 +#define UART0_C3 *(volatile uint8_t *)0x4006A006 // UART Control Register 3 +#define UART0_D *(volatile uint8_t *)0x4006A007 // UART Data Register +#define UART0_MA1 *(volatile uint8_t *)0x4006A008 // UART Match Address Registers 1 +#define UART0_MA2 *(volatile uint8_t *)0x4006A009 // UART Match Address Registers 2 +#define UART0_C4 *(volatile uint8_t *)0x4006A00A // UART Control Register 4 +#define UART0_C5 *(volatile uint8_t *)0x4006A00B // UART Control Register 5 +#define UART0_ED *(volatile uint8_t *)0x4006A00C // UART Extended Data Register +#define UART0_MODEM *(volatile uint8_t *)0x4006A00D // UART Modem Register +#define UART0_IR *(volatile uint8_t *)0x4006A00E // UART Infrared Register +#define UART0_PFIFO *(volatile uint8_t *)0x4006A010 // UART FIFO Parameters +#define UART_PFIFO_TXFE (uint8_t)0x80 +#define UART_PFIFO_RXFE (uint8_t)0x08 +#define UART0_CFIFO *(volatile uint8_t *)0x4006A011 // UART FIFO Control Register +#define UART_CFIFO_TXFLUSH (uint8_t)0x80 // +#define UART_CFIFO_RXFLUSH (uint8_t)0x40 // +#define UART_CFIFO_RXOFE (uint8_t)0x04 // +#define UART_CFIFO_TXOFE (uint8_t)0x02 // +#define UART_CFIFO_RXUFE (uint8_t)0x01 // +#define UART0_SFIFO *(volatile uint8_t *)0x4006A012 // UART FIFO Status Register +#define UART_SFIFO_TXEMPT (uint8_t)0x80 +#define UART_SFIFO_RXEMPT (uint8_t)0x40 +#define UART_SFIFO_RXOF (uint8_t)0x04 +#define UART_SFIFO_TXOF (uint8_t)0x02 +#define UART_SFIFO_RXUF (uint8_t)0x01 +#define UART0_TWFIFO *(volatile uint8_t *)0x4006A013 // UART FIFO Transmit Watermark +#define UART0_TCFIFO *(volatile uint8_t *)0x4006A014 // UART FIFO Transmit Count +#define UART0_RWFIFO *(volatile uint8_t *)0x4006A015 // UART FIFO Receive Watermark +#define UART0_RCFIFO *(volatile uint8_t *)0x4006A016 // UART FIFO Receive Count +#define UART0_C7816 *(volatile uint8_t *)0x4006A018 // UART 7816 Control Register +#define UART0_IE7816 *(volatile uint8_t *)0x4006A019 // UART 7816 Interrupt Enable Register +#define UART0_IS7816 *(volatile uint8_t *)0x4006A01A // UART 7816 Interrupt Status Register +#define UART0_WP7816T0 *(volatile uint8_t *)0x4006A01B // UART 7816 Wait Parameter Register +#define UART0_WP7816T1 *(volatile uint8_t *)0x4006A01B // UART 7816 Wait Parameter Register +#define UART0_WN7816 *(volatile uint8_t *)0x4006A01C // UART 7816 Wait N Register +#define UART0_WF7816 *(volatile uint8_t *)0x4006A01D // UART 7816 Wait FD Register +#define UART0_ET7816 *(volatile uint8_t *)0x4006A01E // UART 7816 Error Threshold Register +#define UART0_TL7816 *(volatile uint8_t *)0x4006A01F // UART 7816 Transmit Length Register +#define UART0_C6 *(volatile uint8_t *)0x4006A021 // UART CEA709.1-B Control Register 6 +#define UART0_PCTH *(volatile uint8_t *)0x4006A022 // UART CEA709.1-B Packet Cycle Time Counter High +#define UART0_PCTL *(volatile uint8_t *)0x4006A023 // UART CEA709.1-B Packet Cycle Time Counter Low +#define UART0_B1T *(volatile uint8_t *)0x4006A024 // UART CEA709.1-B Beta1 Timer +#define UART0_SDTH *(volatile uint8_t *)0x4006A025 // UART CEA709.1-B Secondary Delay Timer High +#define UART0_SDTL *(volatile uint8_t *)0x4006A026 // UART CEA709.1-B Secondary Delay Timer Low +#define UART0_PRE *(volatile uint8_t *)0x4006A027 // UART CEA709.1-B Preamble +#define UART0_TPL *(volatile uint8_t *)0x4006A028 // UART CEA709.1-B Transmit Packet Length +#define UART0_IE *(volatile uint8_t *)0x4006A029 // UART CEA709.1-B Interrupt Enable Register +#define UART0_WB *(volatile uint8_t *)0x4006A02A // UART CEA709.1-B WBASE +#define UART0_S3 *(volatile uint8_t *)0x4006A02B // UART CEA709.1-B Status Register +#define UART0_S4 *(volatile uint8_t *)0x4006A02C // UART CEA709.1-B Status Register +#define UART0_RPL *(volatile uint8_t *)0x4006A02D // UART CEA709.1-B Received Packet Length +#define UART0_RPREL *(volatile uint8_t *)0x4006A02E // UART CEA709.1-B Received Preamble Length +#define UART0_CPW *(volatile uint8_t *)0x4006A02F // UART CEA709.1-B Collision Pulse Width +#define UART0_RIDT *(volatile uint8_t *)0x4006A030 // UART CEA709.1-B Receive Indeterminate Time +#define UART0_TIDT *(volatile uint8_t *)0x4006A031 // UART CEA709.1-B Transmit Indeterminate Time +#define UART1_BDH *(volatile uint8_t *)0x4006B000 // UART Baud Rate Registers: High +#define UART1_BDL *(volatile uint8_t *)0x4006B001 // UART Baud Rate Registers: Low +#define UART1_C1 *(volatile uint8_t *)0x4006B002 // UART Control Register 1 +#define UART1_C2 *(volatile uint8_t *)0x4006B003 // UART Control Register 2 +#define UART1_S1 *(volatile uint8_t *)0x4006B004 // UART Status Register 1 +#define UART1_S2 *(volatile uint8_t *)0x4006B005 // UART Status Register 2 +#define UART1_C3 *(volatile uint8_t *)0x4006B006 // UART Control Register 3 +#define UART1_D *(volatile uint8_t *)0x4006B007 // UART Data Register +#define UART1_MA1 *(volatile uint8_t *)0x4006B008 // UART Match Address Registers 1 +#define UART1_MA2 *(volatile uint8_t *)0x4006B009 // UART Match Address Registers 2 +#define UART1_C4 *(volatile uint8_t *)0x4006B00A // UART Control Register 4 +#define UART1_C5 *(volatile uint8_t *)0x4006B00B // UART Control Register 5 +#define UART1_ED *(volatile uint8_t *)0x4006B00C // UART Extended Data Register +#define UART1_MODEM *(volatile uint8_t *)0x4006B00D // UART Modem Register +#define UART1_IR *(volatile uint8_t *)0x4006B00E // UART Infrared Register +#define UART1_PFIFO *(volatile uint8_t *)0x4006B010 // UART FIFO Parameters +#define UART1_CFIFO *(volatile uint8_t *)0x4006B011 // UART FIFO Control Register +#define UART1_SFIFO *(volatile uint8_t *)0x4006B012 // UART FIFO Status Register +#define UART1_TWFIFO *(volatile uint8_t *)0x4006B013 // UART FIFO Transmit Watermark +#define UART1_TCFIFO *(volatile uint8_t *)0x4006B014 // UART FIFO Transmit Count +#define UART1_RWFIFO *(volatile uint8_t *)0x4006B015 // UART FIFO Receive Watermark +#define UART1_RCFIFO *(volatile uint8_t *)0x4006B016 // UART FIFO Receive Count +#define UART1_C7816 *(volatile uint8_t *)0x4006B018 // UART 7816 Control Register +#define UART1_IE7816 *(volatile uint8_t *)0x4006B019 // UART 7816 Interrupt Enable Register +#define UART1_IS7816 *(volatile uint8_t *)0x4006B01A // UART 7816 Interrupt Status Register +#define UART1_WP7816T0 *(volatile uint8_t *)0x4006B01B // UART 7816 Wait Parameter Register +#define UART1_WP7816T1 *(volatile uint8_t *)0x4006B01B // UART 7816 Wait Parameter Register +#define UART1_WN7816 *(volatile uint8_t *)0x4006B01C // UART 7816 Wait N Register +#define UART1_WF7816 *(volatile uint8_t *)0x4006B01D // UART 7816 Wait FD Register +#define UART1_ET7816 *(volatile uint8_t *)0x4006B01E // UART 7816 Error Threshold Register +#define UART1_TL7816 *(volatile uint8_t *)0x4006B01F // UART 7816 Transmit Length Register +#define UART1_C6 *(volatile uint8_t *)0x4006B021 // UART CEA709.1-B Control Register 6 +#define UART1_PCTH *(volatile uint8_t *)0x4006B022 // UART CEA709.1-B Packet Cycle Time Counter High +#define UART1_PCTL *(volatile uint8_t *)0x4006B023 // UART CEA709.1-B Packet Cycle Time Counter Low +#define UART1_B1T *(volatile uint8_t *)0x4006B024 // UART CEA709.1-B Beta1 Timer +#define UART1_SDTH *(volatile uint8_t *)0x4006B025 // UART CEA709.1-B Secondary Delay Timer High +#define UART1_SDTL *(volatile uint8_t *)0x4006B026 // UART CEA709.1-B Secondary Delay Timer Low +#define UART1_PRE *(volatile uint8_t *)0x4006B027 // UART CEA709.1-B Preamble +#define UART1_TPL *(volatile uint8_t *)0x4006B028 // UART CEA709.1-B Transmit Packet Length +#define UART1_IE *(volatile uint8_t *)0x4006B029 // UART CEA709.1-B Interrupt Enable Register +#define UART1_WB *(volatile uint8_t *)0x4006B02A // UART CEA709.1-B WBASE +#define UART1_S3 *(volatile uint8_t *)0x4006B02B // UART CEA709.1-B Status Register +#define UART1_S4 *(volatile uint8_t *)0x4006B02C // UART CEA709.1-B Status Register +#define UART1_RPL *(volatile uint8_t *)0x4006B02D // UART CEA709.1-B Received Packet Length +#define UART1_RPREL *(volatile uint8_t *)0x4006B02E // UART CEA709.1-B Received Preamble Length +#define UART1_CPW *(volatile uint8_t *)0x4006B02F // UART CEA709.1-B Collision Pulse Width +#define UART1_RIDT *(volatile uint8_t *)0x4006B030 // UART CEA709.1-B Receive Indeterminate Time +#define UART1_TIDT *(volatile uint8_t *)0x4006B031 // UART CEA709.1-B Transmit Indeterminate Time +#define UART2_BDH *(volatile uint8_t *)0x4006C000 // UART Baud Rate Registers: High +#define UART2_BDL *(volatile uint8_t *)0x4006C001 // UART Baud Rate Registers: Low +#define UART2_C1 *(volatile uint8_t *)0x4006C002 // UART Control Register 1 +#define UART2_C2 *(volatile uint8_t *)0x4006C003 // UART Control Register 2 +#define UART2_S1 *(volatile uint8_t *)0x4006C004 // UART Status Register 1 +#define UART2_S2 *(volatile uint8_t *)0x4006C005 // UART Status Register 2 +#define UART2_C3 *(volatile uint8_t *)0x4006C006 // UART Control Register 3 +#define UART2_D *(volatile uint8_t *)0x4006C007 // UART Data Register +#define UART2_MA1 *(volatile uint8_t *)0x4006C008 // UART Match Address Registers 1 +#define UART2_MA2 *(volatile uint8_t *)0x4006C009 // UART Match Address Registers 2 +#define UART2_C4 *(volatile uint8_t *)0x4006C00A // UART Control Register 4 +#define UART2_C5 *(volatile uint8_t *)0x4006C00B // UART Control Register 5 +#define UART2_ED *(volatile uint8_t *)0x4006C00C // UART Extended Data Register +#define UART2_MODEM *(volatile uint8_t *)0x4006C00D // UART Modem Register +#define UART2_IR *(volatile uint8_t *)0x4006C00E // UART Infrared Register +#define UART2_PFIFO *(volatile uint8_t *)0x4006C010 // UART FIFO Parameters +#define UART2_CFIFO *(volatile uint8_t *)0x4006C011 // UART FIFO Control Register +#define UART2_SFIFO *(volatile uint8_t *)0x4006C012 // UART FIFO Status Register +#define UART2_TWFIFO *(volatile uint8_t *)0x4006C013 // UART FIFO Transmit Watermark +#define UART2_TCFIFO *(volatile uint8_t *)0x4006C014 // UART FIFO Transmit Count +#define UART2_RWFIFO *(volatile uint8_t *)0x4006C015 // UART FIFO Receive Watermark +#define UART2_RCFIFO *(volatile uint8_t *)0x4006C016 // UART FIFO Receive Count +#define UART2_C7816 *(volatile uint8_t *)0x4006C018 // UART 7816 Control Register +#define UART2_IE7816 *(volatile uint8_t *)0x4006C019 // UART 7816 Interrupt Enable Register +#define UART2_IS7816 *(volatile uint8_t *)0x4006C01A // UART 7816 Interrupt Status Register +#define UART2_WP7816T0 *(volatile uint8_t *)0x4006C01B // UART 7816 Wait Parameter Register +#define UART2_WP7816T1 *(volatile uint8_t *)0x4006C01B // UART 7816 Wait Parameter Register +#define UART2_WN7816 *(volatile uint8_t *)0x4006C01C // UART 7816 Wait N Register +#define UART2_WF7816 *(volatile uint8_t *)0x4006C01D // UART 7816 Wait FD Register +#define UART2_ET7816 *(volatile uint8_t *)0x4006C01E // UART 7816 Error Threshold Register +#define UART2_TL7816 *(volatile uint8_t *)0x4006C01F // UART 7816 Transmit Length Register +#define UART2_C6 *(volatile uint8_t *)0x4006C021 // UART CEA709.1-B Control Register 6 +#define UART2_PCTH *(volatile uint8_t *)0x4006C022 // UART CEA709.1-B Packet Cycle Time Counter High +#define UART2_PCTL *(volatile uint8_t *)0x4006C023 // UART CEA709.1-B Packet Cycle Time Counter Low +#define UART2_B1T *(volatile uint8_t *)0x4006C024 // UART CEA709.1-B Beta1 Timer +#define UART2_SDTH *(volatile uint8_t *)0x4006C025 // UART CEA709.1-B Secondary Delay Timer High +#define UART2_SDTL *(volatile uint8_t *)0x4006C026 // UART CEA709.1-B Secondary Delay Timer Low +#define UART2_PRE *(volatile uint8_t *)0x4006C027 // UART CEA709.1-B Preamble +#define UART2_TPL *(volatile uint8_t *)0x4006C028 // UART CEA709.1-B Transmit Packet Length +#define UART2_IE *(volatile uint8_t *)0x4006C029 // UART CEA709.1-B Interrupt Enable Register +#define UART2_WB *(volatile uint8_t *)0x4006C02A // UART CEA709.1-B WBASE +#define UART2_S3 *(volatile uint8_t *)0x4006C02B // UART CEA709.1-B Status Register +#define UART2_S4 *(volatile uint8_t *)0x4006C02C // UART CEA709.1-B Status Register +#define UART2_RPL *(volatile uint8_t *)0x4006C02D // UART CEA709.1-B Received Packet Length +#define UART2_RPREL *(volatile uint8_t *)0x4006C02E // UART CEA709.1-B Received Preamble Length +#define UART2_CPW *(volatile uint8_t *)0x4006C02F // UART CEA709.1-B Collision Pulse Width +#define UART2_RIDT *(volatile uint8_t *)0x4006C030 // UART CEA709.1-B Receive Indeterminate Time +#define UART2_TIDT *(volatile uint8_t *)0x4006C031 // UART CEA709.1-B Transmit Indeterminate Time + +// Chapter 46: Synchronous Audio Interface (SAI) +#define I2S0_TCSR *(volatile uint32_t *)0x4002F000 // SAI Transmit Control Register +#define I2S_TCSR_TE (uint32_t)0x80000000 // Transmitter Enable +#define I2S_TCSR_STOPE (uint32_t)0x40000000 // Transmitter Enable in Stop mode +#define I2S_TCSR_DBGE (uint32_t)0x20000000 // Transmitter Enable in Debug mode +#define I2S_TCSR_BCE (uint32_t)0x10000000 // Bit Clock Enable +#define I2S_TCSR_FR (uint32_t)0x02000000 // FIFO Reset +#define I2S_TCSR_SR (uint32_t)0x01000000 // Software Reset +#define I2S_TCSR_WSF (uint32_t)0x00100000 // Word Start Flag +#define I2S_TCSR_SEF (uint32_t)0x00080000 // Sync Error Flag +#define I2S_TCSR_FEF (uint32_t)0x00040000 // FIFO Error Flag (underrun) +#define I2S_TCSR_FWF (uint32_t)0x00020000 // FIFO Warning Flag (empty) +#define I2S_TCSR_FRF (uint32_t)0x00010000 // FIFO Request Flag (Data Ready) +#define I2S_TCSR_WSIE (uint32_t)0x00001000 // Word Start Interrupt Enable +#define I2S_TCSR_SEIE (uint32_t)0x00000800 // Sync Error Interrupt Enable +#define I2S_TCSR_FEIE (uint32_t)0x00000400 // FIFO Error Interrupt Enable +#define I2S_TCSR_FWIE (uint32_t)0x00000200 // FIFO Warning Interrupt Enable +#define I2S_TCSR_FRIE (uint32_t)0x00000100 // FIFO Request Interrupt Enable +#define I2S_TCSR_FWDE (uint32_t)0x00000002 // FIFO Warning DMA Enable +#define I2S_TCSR_FRDE (uint32_t)0x00000001 // FIFO Request DMA Enable +#define I2S0_TCR1 *(volatile uint32_t *)0x4002F004 // SAI Transmit Configuration 1 Register +#define I2S_TCR1_TFW(n) ((uint32_t)n & 0x03) // Transmit FIFO watermark +#define I2S0_TCR2 *(volatile uint32_t *)0x4002F008 // SAI Transmit Configuration 2 Register +#define I2S_TCR2_DIV(n) ((uint32_t)n & 0xff) // Bit clock divide by (DIV+1)*2 +#define I2S_TCR2_BCD ((uint32_t)1<<24) // Bit clock direction +#define I2S_TCR2_BCP ((uint32_t)1<<25) // Bit clock polarity +#define I2S_TCR2_MSEL(n) ((uint32_t)(n & 3)<<26) // MCLK select, 0=bus clock, 1=I2S0_MCLK +#define I2S_TCR2_BCI ((uint32_t)1<<28) // Bit clock input +#define I2S_TCR2_BCS ((uint32_t)1<<29) // Bit clock swap +#define I2S_TCR2_SYNC(n) ((uint32_t)(n & 3)<<30) // 0=async 1=sync with receiver +#define I2S0_TCR3 *(volatile uint32_t *)0x4002F00C // SAI Transmit Configuration 3 Register +#define I2S_TCR3_WDFL(n) ((uint32_t)n & 0x0f) // word flag configuration +#define I2S_TCR3_TCE ((uint32_t)0x10000) // transmit channel enable +#define I2S0_TCR4 *(volatile uint32_t *)0x4002F010 // SAI Transmit Configuration 4 Register +#define I2S_TCR4_FSD ((uint32_t)1) // Frame Sync Direction +#define I2S_TCR4_FSP ((uint32_t)2) // Frame Sync Polarity +#define I2S_TCR4_FSE ((uint32_t)8) // Frame Sync Early +#define I2S_TCR4_MF ((uint32_t)0x10) // MSB First +#define I2S_TCR4_SYWD(n) ((uint32_t)(n & 0x1f)<<8) // Sync Width +#define I2S_TCR4_FRSZ(n) ((uint32_t)(n & 0x0f)<<16) // Frame Size +#define I2S0_TCR5 *(volatile uint32_t *)0x4002F014 // SAI Transmit Configuration 5 Register +#define I2S_TCR5_FBT(n) ((uint32_t)(n & 0x1f)<<8) // First Bit Shifted +#define I2S_TCR5_W0W(n) ((uint32_t)(n & 0x1f)<<16) // Word 0 Width +#define I2S_TCR5_WNW(n) ((uint32_t)(n & 0x1f)<<24) // Word N Width +#define I2S0_TDR0 *(volatile uint32_t *)0x4002F020 // SAI Transmit Data Register +#define I2S0_TDR1 *(volatile uint32_t *)0x4002F024 // SAI Transmit Data Register +#define I2S0_TFR0 *(volatile uint32_t *)0x4002F040 // SAI Transmit FIFO Register +#define I2S0_TFR1 *(volatile uint32_t *)0x4002F044 // SAI Transmit FIFO Register +#define I2S_TFR_RFP(n) ((uint32_t)n & 7) // read FIFO pointer +#define I2S_TFR_WFP(n) ((uint32_t)(n & 7)<<16) // write FIFO pointer +#define I2S0_TMR *(volatile uint32_t *)0x4002F060 // SAI Transmit Mask Register +#define I2S_TMR_TWM(n) ((uint32_t)n & 0xFFFFFFFF) +#define I2S0_RCSR *(volatile uint32_t *)0x4002F080 // SAI Receive Control Register +#define I2S_RCSR_RE (uint32_t)0x80000000 // Receiver Enable +#define I2S_RCSR_STOPE (uint32_t)0x40000000 // Receiver Enable in Stop mode +#define I2S_RCSR_DBGE (uint32_t)0x20000000 // Receiver Enable in Debug mode +#define I2S_RCSR_BCE (uint32_t)0x10000000 // Bit Clock Enable +#define I2S_RCSR_FR (uint32_t)0x02000000 // FIFO Reset +#define I2S_RCSR_SR (uint32_t)0x01000000 // Software Reset +#define I2S_RCSR_WSF (uint32_t)0x00100000 // Word Start Flag +#define I2S_RCSR_SEF (uint32_t)0x00080000 // Sync Error Flag +#define I2S_RCSR_FEF (uint32_t)0x00040000 // FIFO Error Flag (underrun) +#define I2S_RCSR_FWF (uint32_t)0x00020000 // FIFO Warning Flag (empty) +#define I2S_RCSR_FRF (uint32_t)0x00010000 // FIFO Request Flag (Data Ready) +#define I2S_RCSR_WSIE (uint32_t)0x00001000 // Word Start Interrupt Enable +#define I2S_RCSR_SEIE (uint32_t)0x00000800 // Sync Error Interrupt Enable +#define I2S_RCSR_FEIE (uint32_t)0x00000400 // FIFO Error Interrupt Enable +#define I2S_RCSR_FWIE (uint32_t)0x00000200 // FIFO Warning Interrupt Enable +#define I2S_RCSR_FRIE (uint32_t)0x00000100 // FIFO Request Interrupt Enable +#define I2S_RCSR_FWDE (uint32_t)0x00000002 // FIFO Warning DMA Enable +#define I2S_RCSR_FRDE (uint32_t)0x00000001 // FIFO Request DMA Enable +#define I2S0_RCR1 *(volatile uint32_t *)0x4002F084 // SAI Receive Configuration 1 Register +#define I2S_RCR1_RFW(n) ((uint32_t)n & 0x03) // Receive FIFO watermark +#define I2S0_RCR2 *(volatile uint32_t *)0x4002F088 // SAI Receive Configuration 2 Register +#define I2S_RCR2_DIV(n) ((uint32_t)n & 0xff) // Bit clock divide by (DIV+1)*2 +#define I2S_RCR2_BCD ((uint32_t)1<<24) // Bit clock direction +#define I2S_RCR2_BCP ((uint32_t)1<<25) // Bit clock polarity +#define I2S_RCR2_MSEL(n) ((uint32_t)(n & 3)<<26) // MCLK select, 0=bus clock, 1=I2S0_MCLK +#define I2S_RCR2_BCI ((uint32_t)1<<28) // Bit clock input +#define I2S_RCR2_BCS ((uint32_t)1<<29) // Bit clock swap +#define I2S_RCR2_SYNC(n) ((uint32_t)(n & 3)<<30) // 0=async 1=sync with receiver +#define I2S0_RCR3 *(volatile uint32_t *)0x4002F08C // SAI Receive Configuration 3 Register +#define I2S_RCR3_WDFL(n) ((uint32_t)n & 0x0f) // word flag configuration +#define I2S_RCR3_RCE ((uint32_t)0x10000) // receive channel enable +#define I2S0_RCR4 *(volatile uint32_t *)0x4002F090 // SAI Receive Configuration 4 Register +#define I2S_RCR4_FSD ((uint32_t)1) // Frame Sync Direction +#define I2S_RCR4_FSP ((uint32_t)2) // Frame Sync Polarity +#define I2S_RCR4_FSE ((uint32_t)8) // Frame Sync Early +#define I2S_RCR4_MF ((uint32_t)0x10) // MSB First +#define I2S_RCR4_SYWD(n) ((uint32_t)(n & 0x1f)<<8) // Sync Width +#define I2S_RCR4_FRSZ(n) ((uint32_t)(n & 0x0f)<<16) // Frame Size +#define I2S0_RCR5 *(volatile uint32_t *)0x4002F094 // SAI Receive Configuration 5 Register +#define I2S_RCR5_FBT(n) ((uint32_t)(n & 0x1f)<<8) // First Bit Shifted +#define I2S_RCR5_W0W(n) ((uint32_t)(n & 0x1f)<<16) // Word 0 Width +#define I2S_RCR5_WNW(n) ((uint32_t)(n & 0x1f)<<24) // Word N Width +#define I2S0_RDR0 *(volatile uint32_t *)0x4002F0A0 // SAI Receive Data Register +#define I2S0_RDR1 *(volatile uint32_t *)0x4002F0A4 // SAI Receive Data Register +#define I2S0_RFR0 *(volatile uint32_t *)0x4002F0C0 // SAI Receive FIFO Register +#define I2S0_RFR1 *(volatile uint32_t *)0x4002F0C4 // SAI Receive FIFO Register +#define I2S_RFR_RFP(n) ((uint32_t)n & 7) // read FIFO pointer +#define I2S_RFR_WFP(n) ((uint32_t)(n & 7)<<16) // write FIFO pointer +#define I2S0_RMR *(volatile uint32_t *)0x4002F0E0 // SAI Receive Mask Register +#define I2S_RMR_RWM(n) ((uint32_t)n & 0xFFFFFFFF) +#define I2S0_MCR *(volatile uint32_t *)0x4002F100 // SAI MCLK Control Register +#define I2S_MCR_DUF ((uint32_t)1<<31) // Divider Update Flag +#define I2S_MCR_MOE ((uint32_t)1<<30) // MCLK Output Enable +#define I2S_MCR_MICS(n) ((uint32_t)(n & 3)<<24) // MCLK Input Clock Select +#define I2S0_MDR *(volatile uint32_t *)0x4002F104 // SAI MCLK Divide Register +#define I2S_MDR_FRACT(n) ((uint32_t)(n & 0xff)<<12) // MCLK Fraction +#define I2S_MDR_DIVIDE(n) ((uint32_t)(n & 0xfff)) // MCLK Divide + +// Chapter 47: General-Purpose Input/Output (GPIO) +#define GPIOA_PDOR *(volatile uint32_t *)0x400FF000 // Port Data Output Register +#define GPIOA_PSOR *(volatile uint32_t *)0x400FF004 // Port Set Output Register +#define GPIOA_PCOR *(volatile uint32_t *)0x400FF008 // Port Clear Output Register +#define GPIOA_PTOR *(volatile uint32_t *)0x400FF00C // Port Toggle Output Register +#define GPIOA_PDIR *(volatile uint32_t *)0x400FF010 // Port Data Input Register +#define GPIOA_PDDR *(volatile uint32_t *)0x400FF014 // Port Data Direction Register +#define GPIOB_PDOR *(volatile uint32_t *)0x400FF040 // Port Data Output Register +#define GPIOB_PSOR *(volatile uint32_t *)0x400FF044 // Port Set Output Register +#define GPIOB_PCOR *(volatile uint32_t *)0x400FF048 // Port Clear Output Register +#define GPIOB_PTOR *(volatile uint32_t *)0x400FF04C // Port Toggle Output Register +#define GPIOB_PDIR *(volatile uint32_t *)0x400FF050 // Port Data Input Register +#define GPIOB_PDDR *(volatile uint32_t *)0x400FF054 // Port Data Direction Register +#define GPIOC_PDOR *(volatile uint32_t *)0x400FF080 // Port Data Output Register +#define GPIOC_PSOR *(volatile uint32_t *)0x400FF084 // Port Set Output Register +#define GPIOC_PCOR *(volatile uint32_t *)0x400FF088 // Port Clear Output Register +#define GPIOC_PTOR *(volatile uint32_t *)0x400FF08C // Port Toggle Output Register +#define GPIOC_PDIR *(volatile uint32_t *)0x400FF090 // Port Data Input Register +#define GPIOC_PDDR *(volatile uint32_t *)0x400FF094 // Port Data Direction Register +#define GPIOD_PDOR *(volatile uint32_t *)0x400FF0C0 // Port Data Output Register +#define GPIOD_PSOR *(volatile uint32_t *)0x400FF0C4 // Port Set Output Register +#define GPIOD_PCOR *(volatile uint32_t *)0x400FF0C8 // Port Clear Output Register +#define GPIOD_PTOR *(volatile uint32_t *)0x400FF0CC // Port Toggle Output Register +#define GPIOD_PDIR *(volatile uint32_t *)0x400FF0D0 // Port Data Input Register +#define GPIOD_PDDR *(volatile uint32_t *)0x400FF0D4 // Port Data Direction Register +#define GPIOE_PDOR *(volatile uint32_t *)0x400FF100 // Port Data Output Register +#define GPIOE_PSOR *(volatile uint32_t *)0x400FF104 // Port Set Output Register +#define GPIOE_PCOR *(volatile uint32_t *)0x400FF108 // Port Clear Output Register +#define GPIOE_PTOR *(volatile uint32_t *)0x400FF10C // Port Toggle Output Register +#define GPIOE_PDIR *(volatile uint32_t *)0x400FF110 // Port Data Input Register +#define GPIOE_PDDR *(volatile uint32_t *)0x400FF114 // Port Data Direction Register + +// Chapter 48: Touch sense input (TSI) +#define TSI0_GENCS *(volatile uint32_t *)0x40045000 // General Control and Status Register +#define TSI_GENCS_LPCLKS (uint32_t)0x10000000 // +#define TSI_GENCS_LPSCNITV(n) (((n) & 15) << 24) // +#define TSI_GENCS_NSCN(n) (((n) & 31) << 19) // +#define TSI_GENCS_PS(n) (((n) & 7) << 16) // +#define TSI_GENCS_EOSF (uint32_t)0x00008000 // +#define TSI_GENCS_OUTRGF (uint32_t)0x00004000 // +#define TSI_GENCS_EXTERF (uint32_t)0x00002000 // +#define TSI_GENCS_OVRF (uint32_t)0x00001000 // +#define TSI_GENCS_SCNIP (uint32_t)0x00000200 // +#define TSI_GENCS_SWTS (uint32_t)0x00000100 // +#define TSI_GENCS_TSIEN (uint32_t)0x00000080 // +#define TSI_GENCS_TSIIE (uint32_t)0x00000040 // +#define TSI_GENCS_ERIE (uint32_t)0x00000020 // +#define TSI_GENCS_ESOR (uint32_t)0x00000010 // +#define TSI_GENCS_STM (uint32_t)0x00000002 // +#define TSI_GENCS_STPE (uint32_t)0x00000001 // +#define TSI0_SCANC *(volatile uint32_t *)0x40045004 // SCAN Control Register +#define TSI_SCANC_REFCHRG(n) (((n) & 15) << 24) // +#define TSI_SCANC_EXTCHRG(n) (((n) & 7) << 16) // +#define TSI_SCANC_SMOD(n) (((n) & 255) << 8) // +#define TSI_SCANC_AMCLKS(n) (((n) & 3) << 3) // +#define TSI_SCANC_AMPSC(n) (((n) & 7) << 0) // +#define TSI0_PEN *(volatile uint32_t *)0x40045008 // Pin Enable Register +#define TSI0_WUCNTR *(volatile uint32_t *)0x4004500C // Wake-Up Channel Counter Register +#define TSI0_CNTR1 *(volatile uint32_t *)0x40045100 // Counter Register +#define TSI0_CNTR3 *(volatile uint32_t *)0x40045104 // Counter Register +#define TSI0_CNTR5 *(volatile uint32_t *)0x40045108 // Counter Register +#define TSI0_CNTR7 *(volatile uint32_t *)0x4004510C // Counter Register +#define TSI0_CNTR9 *(volatile uint32_t *)0x40045110 // Counter Register +#define TSI0_CNTR11 *(volatile uint32_t *)0x40045114 // Counter Register +#define TSI0_CNTR13 *(volatile uint32_t *)0x40045118 // Counter Register +#define TSI0_CNTR15 *(volatile uint32_t *)0x4004511C // Counter Register +#define TSI0_THRESHOLD *(volatile uint32_t *)0x40045120 // Low Power Channel Threshold Register + +// Nested Vectored Interrupt Controller, Table 3-4 & ARMv7 ref, appendix B3.4 (page 750) +#define NVIC_ENABLE_IRQ(n) (*((volatile uint32_t *)0xE000E100 + (n >> 5)) = (1 << (n & 31))) +#define NVIC_DISABLE_IRQ(n) (*((volatile uint32_t *)0xE000E180 + (n >> 5)) = (1 << (n & 31))) +#define NVIC_SET_PENDING(n) (*((volatile uint32_t *)0xE000E200 + (n >> 5)) = (1 << (n & 31))) +#define NVIC_CLEAR_PENDING(n) (*((volatile uint32_t *)0xE000E280 + (n >> 5)) = (1 << (n & 31))) + +#define NVIC_ISER0 *(volatile uint32_t *)0xE000E100 +#define NVIC_ISER1 *(volatile uint32_t *)0xE000E104 +#define NVIC_ICER0 *(volatile uint32_t *)0xE000E180 +#define NVIC_ICER1 *(volatile uint32_t *)0xE000E184 + +// 0 = highest priority +// Cortex-M4: 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240 +// Cortex-M0: 0,64,128,192 +#define NVIC_SET_PRIORITY(irqnum, priority) (*((volatile uint8_t *)0xE000E400 + (irqnum)) = (uint8_t)(priority)) +#define NVIC_GET_PRIORITY(irqnum) (*((uint8_t *)0xE000E400 + (irqnum))) + +#if defined(__MK20DX128__) +#define IRQ_DMA_CH0 0 +#define IRQ_DMA_CH1 1 +#define IRQ_DMA_CH2 2 +#define IRQ_DMA_CH3 3 +#define IRQ_DMA_ERROR 4 +#define IRQ_FTFL_COMPLETE 6 +#define IRQ_FTFL_COLLISION 7 +#define IRQ_LOW_VOLTAGE 8 +#define IRQ_LLWU 9 +#define IRQ_WDOG 10 +#define IRQ_I2C0 11 +#define IRQ_SPI0 12 +#define IRQ_I2S0_TX 13 +#define IRQ_I2S0_RX 14 +#define IRQ_UART0_LON 15 +#define IRQ_UART0_STATUS 16 +#define IRQ_UART0_ERROR 17 +#define IRQ_UART1_STATUS 18 +#define IRQ_UART1_ERROR 19 +#define IRQ_UART2_STATUS 20 +#define IRQ_UART2_ERROR 21 +#define IRQ_ADC0 22 +#define IRQ_CMP0 23 +#define IRQ_CMP1 24 +#define IRQ_FTM0 25 +#define IRQ_FTM1 26 +#define IRQ_CMT 27 +#define IRQ_RTC_ALARM 28 +#define IRQ_RTC_SECOND 29 +#define IRQ_PIT_CH0 30 +#define IRQ_PIT_CH1 31 +#define IRQ_PIT_CH2 32 +#define IRQ_PIT_CH3 33 +#define IRQ_PDB 34 +#define IRQ_USBOTG 35 +#define IRQ_USBDCD 36 +#define IRQ_TSI 37 +#define IRQ_MCG 38 +#define IRQ_LPTMR 39 +#define IRQ_PORTA 40 +#define IRQ_PORTB 41 +#define IRQ_PORTC 42 +#define IRQ_PORTD 43 +#define IRQ_PORTE 44 +#define IRQ_SOFTWARE 45 +#define NVIC_NUM_INTERRUPTS 46 + +#elif defined(__MK20DX256__) +#define IRQ_DMA_CH0 0 +#define IRQ_DMA_CH1 1 +#define IRQ_DMA_CH2 2 +#define IRQ_DMA_CH3 3 +#define IRQ_DMA_CH4 4 +#define IRQ_DMA_CH5 5 +#define IRQ_DMA_CH6 6 +#define IRQ_DMA_CH7 7 +#define IRQ_DMA_CH8 8 +#define IRQ_DMA_CH9 9 +#define IRQ_DMA_CH10 10 +#define IRQ_DMA_CH11 11 +#define IRQ_DMA_CH12 12 +#define IRQ_DMA_CH13 13 +#define IRQ_DMA_CH14 14 +#define IRQ_DMA_CH15 15 +#define IRQ_DMA_ERROR 16 +#define IRQ_FTFL_COMPLETE 18 +#define IRQ_FTFL_COLLISION 19 +#define IRQ_LOW_VOLTAGE 20 +#define IRQ_LLWU 21 +#define IRQ_WDOG 22 +#define IRQ_I2C0 24 +#define IRQ_I2C1 25 +#define IRQ_SPI0 26 +#define IRQ_SPI1 27 +#define IRQ_CAN_MESSAGE 29 +#define IRQ_CAN_BUS_OFF 30 +#define IRQ_CAN_ERROR 31 +#define IRQ_CAN_TX_WARN 32 +#define IRQ_CAN_RX_WARN 33 +#define IRQ_CAN_WAKEUP 34 +#define IRQ_I2S0_TX 35 +#define IRQ_I2S0_RX 36 +#define IRQ_UART0_LON 44 +#define IRQ_UART0_STATUS 45 +#define IRQ_UART0_ERROR 46 +#define IRQ_UART1_STATUS 47 +#define IRQ_UART1_ERROR 48 +#define IRQ_UART2_STATUS 49 +#define IRQ_UART2_ERROR 50 +#define IRQ_ADC0 57 +#define IRQ_ADC1 58 +#define IRQ_CMP0 59 +#define IRQ_CMP1 60 +#define IRQ_CMP2 61 +#define IRQ_FTM0 62 +#define IRQ_FTM1 63 +#define IRQ_FTM2 64 +#define IRQ_CMT 65 +#define IRQ_RTC_ALARM 66 +#define IRQ_RTC_SECOND 67 +#define IRQ_PIT_CH0 68 +#define IRQ_PIT_CH1 69 +#define IRQ_PIT_CH2 70 +#define IRQ_PIT_CH3 71 +#define IRQ_PDB 72 +#define IRQ_USBOTG 73 +#define IRQ_USBDCD 74 +#define IRQ_DAC0 81 +#define IRQ_TSI 83 +#define IRQ_MCG 84 +#define IRQ_LPTMR 85 +#define IRQ_PORTA 87 +#define IRQ_PORTB 88 +#define IRQ_PORTC 89 +#define IRQ_PORTD 90 +#define IRQ_PORTE 91 +#define IRQ_SOFTWARE 94 +#define NVIC_NUM_INTERRUPTS 95 + +#endif + + + + + +#define __disable_irq() __asm__ volatile("CPSID i"); +#define __enable_irq() __asm__ volatile("CPSIE i"); + +// System Control Space (SCS), ARMv7 ref manual, B3.2, page 708 +#define SCB_CPUID *(const uint32_t *)0xE000ED00 // CPUID Base Register +#define SCB_ICSR *(volatile uint32_t *)0xE000ED04 // Interrupt Control and State +#define SCB_ICSR_PENDSTSET (uint32_t)0x04000000 +#define SCB_VTOR *(volatile uint32_t *)0xE000ED08 // Vector Table Offset +#define SCB_AIRCR *(volatile uint32_t *)0xE000ED0C // Application Interrupt and Reset Control +#define SCB_SCR *(volatile uint32_t *)0xE000ED10 // System Control Register +#define SCB_CCR *(volatile uint32_t *)0xE000ED14 // Configuration and Control +#define SCB_SHPR1 *(volatile uint32_t *)0xE000ED18 // System Handler Priority Register 1 +#define SCB_SHPR2 *(volatile uint32_t *)0xE000ED1C // System Handler Priority Register 2 +#define SCB_SHPR3 *(volatile uint32_t *)0xE000ED20 // System Handler Priority Register 3 +#define SCB_SHCSR *(volatile uint32_t *)0xE000ED24 // System Handler Control and State +#define SCB_CFSR *(volatile uint32_t *)0xE000ED28 // Configurable Fault Status Register +#define SCB_HFSR *(volatile uint32_t *)0xE000ED2C // HardFault Status +#define SCB_DFSR *(volatile uint32_t *)0xE000ED30 // Debug Fault Status +#define SCB_MMFAR *(volatile uint32_t *)0xE000ED34 // MemManage Fault Address + +#define SYST_CSR *(volatile uint32_t *)0xE000E010 // SysTick Control and Status +#define SYST_CSR_COUNTFLAG (uint32_t)0x00010000 +#define SYST_CSR_CLKSOURCE (uint32_t)0x00000004 +#define SYST_CSR_TICKINT (uint32_t)0x00000002 +#define SYST_CSR_ENABLE (uint32_t)0x00000001 +#define SYST_RVR *(volatile uint32_t *)0xE000E014 // SysTick Reload Value Register +#define SYST_CVR *(volatile uint32_t *)0xE000E018 // SysTick Current Value Register +#define SYST_CALIB *(const uint32_t *)0xE000E01C // SysTick Calibration Value + + +#define ARM_DEMCR *(volatile uint32_t *)0xE000EDFC // Debug Exception and Monitor Control +#define ARM_DEMCR_TRCENA (1 << 24) // Enable debugging & monitoring blocks +#define ARM_DWT_CTRL *(volatile uint32_t *)0xE0001000 // DWT control register +#define ARM_DWT_CTRL_CYCCNTENA (1 << 0) // Enable cycle count +#define ARM_DWT_CYCCNT *(volatile uint32_t *)0xE0001004 // Cycle count register + +extern int nvic_execution_priority(void); + +extern void nmi_isr(void); +extern void hard_fault_isr(void); +extern void memmanage_fault_isr(void); +extern void bus_fault_isr(void); +extern void usage_fault_isr(void); +extern void svcall_isr(void); +extern void debugmonitor_isr(void); +extern void pendablesrvreq_isr(void); +extern void systick_isr(void); +extern void dma_ch0_isr(void); +extern void dma_ch1_isr(void); +extern void dma_ch2_isr(void); +extern void dma_ch3_isr(void); +extern void dma_ch4_isr(void); +extern void dma_ch5_isr(void); +extern void dma_ch6_isr(void); +extern void dma_ch7_isr(void); +extern void dma_ch8_isr(void); +extern void dma_ch9_isr(void); +extern void dma_ch10_isr(void); +extern void dma_ch11_isr(void); +extern void dma_ch12_isr(void); +extern void dma_ch13_isr(void); +extern void dma_ch14_isr(void); +extern void dma_ch15_isr(void); +extern void dma_error_isr(void); +extern void mcm_isr(void); +extern void flash_cmd_isr(void); +extern void flash_error_isr(void); +extern void low_voltage_isr(void); +extern void wakeup_isr(void); +extern void watchdog_isr(void); +extern void i2c0_isr(void); +extern void i2c1_isr(void); +extern void i2c2_isr(void); +extern void spi0_isr(void); +extern void spi1_isr(void); +extern void spi2_isr(void); +extern void sdhc_isr(void); +extern void can0_message_isr(void); +extern void can0_bus_off_isr(void); +extern void can0_error_isr(void); +extern void can0_tx_warn_isr(void); +extern void can0_rx_warn_isr(void); +extern void can0_wakeup_isr(void); +extern void i2s0_tx_isr(void); +extern void i2s0_rx_isr(void); +extern void uart0_lon_isr(void); +extern void uart0_status_isr(void); +extern void uart0_error_isr(void); +extern void uart1_status_isr(void); +extern void uart1_error_isr(void); +extern void uart2_status_isr(void); +extern void uart2_error_isr(void); +extern void uart3_status_isr(void); +extern void uart3_error_isr(void); +extern void uart4_status_isr(void); +extern void uart4_error_isr(void); +extern void uart5_status_isr(void); +extern void uart5_error_isr(void); +extern void adc0_isr(void); +extern void adc1_isr(void); +extern void cmp0_isr(void); +extern void cmp1_isr(void); +extern void cmp2_isr(void); +extern void ftm0_isr(void); +extern void ftm1_isr(void); +extern void ftm2_isr(void); +extern void ftm3_isr(void); +extern void cmt_isr(void); +extern void rtc_alarm_isr(void); +extern void rtc_seconds_isr(void); +extern void pit0_isr(void); +extern void pit1_isr(void); +extern void pit2_isr(void); +extern void pit3_isr(void); +extern void pdb_isr(void); +extern void usb_isr(void); +extern void usb_charge_isr(void); +extern void dac0_isr(void); +extern void dac1_isr(void); +extern void tsi0_isr(void); +extern void mcg_isr(void); +extern void lptmr_isr(void); +extern void porta_isr(void); +extern void portb_isr(void); +extern void portc_isr(void); +extern void portd_isr(void); +extern void porte_isr(void); +extern void software_isr(void); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/pins_arduino.h b/src/openmv/src/micropython/ports/teensy/core/pins_arduino.h new file mode 100755 index 0000000..0367493 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/pins_arduino.h @@ -0,0 +1,113 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef pins_macros_for_arduino_compatibility_h +#define pins_macros_for_arduino_compatibility_h + +#include + +const static uint8_t A0 = 14; +const static uint8_t A1 = 15; +const static uint8_t A2 = 16; +const static uint8_t A3 = 17; +const static uint8_t A4 = 18; +const static uint8_t A5 = 19; +const static uint8_t A6 = 20; +const static uint8_t A7 = 21; +const static uint8_t A8 = 22; +const static uint8_t A9 = 23; +const static uint8_t A10 = 34; +const static uint8_t A11 = 35; +const static uint8_t A12 = 36; +const static uint8_t A13 = 37; +const static uint8_t A14 = 40; + +const static uint8_t A15 = 26; +const static uint8_t A16 = 27; +const static uint8_t A17 = 28; +const static uint8_t A18 = 29; +const static uint8_t A19 = 30; +const static uint8_t A20 = 31; + +const static uint8_t SS = 10; +const static uint8_t MOSI = 11; +const static uint8_t MISO = 12; +const static uint8_t SCK = 13; +const static uint8_t LED_BUILTIN = 13; +const static uint8_t SDA = 18; +const static uint8_t SCL = 19; + + +#define NUM_DIGITAL_PINS 34 +#define NUM_ANALOG_INPUTS 14 + +#define analogInputToDigitalPin(p) (((p) < 10) ? (p) + 14 : -1) +#define digitalPinHasPWM(p) (((p) >= 3 && (p) <= 6) || (p) == 9 || (p) == 10 || ((p) >= 20 && (p) <= 23)) + +#define NOT_AN_INTERRUPT -1 +#define digitalPinToInterrupt(p) ((p) < NUM_DIGITAL_PINS ? (p) : -1) + + +struct digital_pin_bitband_and_config_table_struct { + volatile uint32_t *reg; + volatile uint32_t *config; +}; +extern const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[]; + +// compatibility macros +#define digitalPinToPort(pin) (pin) +#define digitalPinToBitMask(pin) (1) +#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0)) +#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32)) +#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64)) +#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96)) +#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128)) +#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160)) +#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config)) + + +#define digitalPinToPortReg(pin) (portOutputRegister(pin)) +#define digitalPinToBit(pin) (1) + + +#define NOT_ON_TIMER 0 +static inline uint8_t digitalPinToTimer(uint8_t) __attribute__((always_inline, unused)); +static inline uint8_t digitalPinToTimer(uint8_t pin) +{ + if (pin >= 3 && pin <= 6) return pin - 2; + if (pin >= 9 && pin <= 10) return pin - 4; + if (pin >= 20 && pin <= 23) return pin - 13; + return NOT_ON_TIMER; +} + + + + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/pins_teensy.c b/src/openmv/src/micropython/ports/teensy/core/pins_teensy.c new file mode 100755 index 0000000..b28f94a --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/pins_teensy.c @@ -0,0 +1,817 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "core_pins.h" +#include "pins_arduino.h" +#include "HardwareSerial.h" + +#if 0 +// moved to pins_arduino.h +struct digital_pin_bitband_and_config_table_struct { + volatile uint32_t *reg; + volatile uint32_t *config; +}; +const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[]; + +// compatibility macros +#define digitalPinToPort(pin) (pin) +#define digitalPinToBitMask(pin) (1) +#define portOutputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 0)) +#define portSetRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 32)) +#define portClearRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 64)) +#define portToggleRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 96)) +#define portInputRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 128)) +#define portModeRegister(pin) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pin)].reg + 160)) +#define portConfigRegister(pin) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pin)].config)) +#endif + +//#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +//#define analogInPinToBit(P) (P) + +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +//#define GPIO_SET_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 1) +//#define GPIO_CLR_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 0) + +const struct digital_pin_bitband_and_config_table_struct digital_pin_to_info_PGM[] = { + {GPIO_BITBAND_PTR(CORE_PIN0_PORTREG, CORE_PIN0_BIT), &CORE_PIN0_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN1_PORTREG, CORE_PIN1_BIT), &CORE_PIN1_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN2_PORTREG, CORE_PIN2_BIT), &CORE_PIN2_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN3_PORTREG, CORE_PIN3_BIT), &CORE_PIN3_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN4_PORTREG, CORE_PIN4_BIT), &CORE_PIN4_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN5_PORTREG, CORE_PIN5_BIT), &CORE_PIN5_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN6_PORTREG, CORE_PIN6_BIT), &CORE_PIN6_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN7_PORTREG, CORE_PIN7_BIT), &CORE_PIN7_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN8_PORTREG, CORE_PIN8_BIT), &CORE_PIN8_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN9_PORTREG, CORE_PIN9_BIT), &CORE_PIN9_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN10_PORTREG, CORE_PIN10_BIT), &CORE_PIN10_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN11_PORTREG, CORE_PIN11_BIT), &CORE_PIN11_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN12_PORTREG, CORE_PIN12_BIT), &CORE_PIN12_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN13_PORTREG, CORE_PIN13_BIT), &CORE_PIN13_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN14_PORTREG, CORE_PIN14_BIT), &CORE_PIN14_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN15_PORTREG, CORE_PIN15_BIT), &CORE_PIN15_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN16_PORTREG, CORE_PIN16_BIT), &CORE_PIN16_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN17_PORTREG, CORE_PIN17_BIT), &CORE_PIN17_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN18_PORTREG, CORE_PIN18_BIT), &CORE_PIN18_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN19_PORTREG, CORE_PIN19_BIT), &CORE_PIN19_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN20_PORTREG, CORE_PIN20_BIT), &CORE_PIN20_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN21_PORTREG, CORE_PIN21_BIT), &CORE_PIN21_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN22_PORTREG, CORE_PIN22_BIT), &CORE_PIN22_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN23_PORTREG, CORE_PIN23_BIT), &CORE_PIN23_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN24_PORTREG, CORE_PIN24_BIT), &CORE_PIN24_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN25_PORTREG, CORE_PIN25_BIT), &CORE_PIN25_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN26_PORTREG, CORE_PIN26_BIT), &CORE_PIN26_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN27_PORTREG, CORE_PIN27_BIT), &CORE_PIN27_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN28_PORTREG, CORE_PIN28_BIT), &CORE_PIN28_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN29_PORTREG, CORE_PIN29_BIT), &CORE_PIN29_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN30_PORTREG, CORE_PIN30_BIT), &CORE_PIN30_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN31_PORTREG, CORE_PIN31_BIT), &CORE_PIN31_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN32_PORTREG, CORE_PIN32_BIT), &CORE_PIN32_CONFIG}, + {GPIO_BITBAND_PTR(CORE_PIN33_PORTREG, CORE_PIN33_BIT), &CORE_PIN33_CONFIG} +}; + + + + +typedef void (*voidFuncPtr)(void); +volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL]; + +void init_pin_interrupts(void) +{ + //SIM_SCGC5 = 0x00043F82; // clocks active to all GPIO + NVIC_ENABLE_IRQ(IRQ_PORTA); + NVIC_ENABLE_IRQ(IRQ_PORTB); + NVIC_ENABLE_IRQ(IRQ_PORTC); + NVIC_ENABLE_IRQ(IRQ_PORTD); + NVIC_ENABLE_IRQ(IRQ_PORTE); + // TODO: maybe these should be set to a lower priority + // so if the user puts lots of slow code on attachInterrupt + // fast interrupts will still be serviced quickly? +} + +void attachInterrupt(uint8_t pin, void (*function)(void), int mode) +{ + volatile uint32_t *config; + uint32_t cfg, mask; + + if (pin >= CORE_NUM_DIGITAL) return; + switch (mode) { + case CHANGE: mask = 0x0B; break; + case RISING: mask = 0x09; break; + case FALLING: mask = 0x0A; break; + case LOW: mask = 0x08; break; + case HIGH: mask = 0x0C; break; + default: return; + } + mask = (mask << 16) | 0x01000000; + config = portConfigRegister(pin); + + __disable_irq(); + cfg = *config; + cfg &= ~0x000F0000; // disable any previous interrupt + *config = cfg; + intFunc[pin] = function; // set the function pointer + cfg |= mask; + *config = cfg; // enable the new interrupt + __enable_irq(); +} + +void detachInterrupt(uint8_t pin) +{ + volatile uint32_t *config; + + config = portConfigRegister(pin); + __disable_irq(); + *config = ((*config & ~0x000F0000) | 0x01000000); + intFunc[pin] = NULL; + __enable_irq(); +} + + +void porta_isr(void) +{ + uint32_t isfr = PORTA_ISFR; + PORTA_ISFR = isfr; + if ((isfr & CORE_PIN3_BITMASK) && intFunc[3]) intFunc[3](); + if ((isfr & CORE_PIN4_BITMASK) && intFunc[4]) intFunc[4](); + if ((isfr & CORE_PIN24_BITMASK) && intFunc[24]) intFunc[24](); + if ((isfr & CORE_PIN33_BITMASK) && intFunc[33]) intFunc[33](); +} + +void portb_isr(void) +{ + uint32_t isfr = PORTB_ISFR; + PORTB_ISFR = isfr; + if ((isfr & CORE_PIN0_BITMASK) && intFunc[0]) intFunc[0](); + if ((isfr & CORE_PIN1_BITMASK) && intFunc[1]) intFunc[1](); + if ((isfr & CORE_PIN16_BITMASK) && intFunc[16]) intFunc[16](); + if ((isfr & CORE_PIN17_BITMASK) && intFunc[17]) intFunc[17](); + if ((isfr & CORE_PIN18_BITMASK) && intFunc[18]) intFunc[18](); + if ((isfr & CORE_PIN19_BITMASK) && intFunc[19]) intFunc[19](); + if ((isfr & CORE_PIN25_BITMASK) && intFunc[25]) intFunc[25](); + if ((isfr & CORE_PIN32_BITMASK) && intFunc[32]) intFunc[32](); +} + +void portc_isr(void) +{ + // TODO: these are inefficent. Use CLZ somehow.... + uint32_t isfr = PORTC_ISFR; + PORTC_ISFR = isfr; + if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9](); + if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10](); + if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11](); + if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12](); + if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13](); + if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15](); + if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22](); + if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23](); + if ((isfr & CORE_PIN27_BITMASK) && intFunc[27]) intFunc[27](); + if ((isfr & CORE_PIN28_BITMASK) && intFunc[28]) intFunc[28](); + if ((isfr & CORE_PIN29_BITMASK) && intFunc[29]) intFunc[29](); + if ((isfr & CORE_PIN30_BITMASK) && intFunc[30]) intFunc[30](); +} + +void portd_isr(void) +{ + uint32_t isfr = PORTD_ISFR; + PORTD_ISFR = isfr; + if ((isfr & CORE_PIN2_BITMASK) && intFunc[2]) intFunc[2](); + if ((isfr & CORE_PIN5_BITMASK) && intFunc[5]) intFunc[5](); + if ((isfr & CORE_PIN6_BITMASK) && intFunc[6]) intFunc[6](); + if ((isfr & CORE_PIN7_BITMASK) && intFunc[7]) intFunc[7](); + if ((isfr & CORE_PIN8_BITMASK) && intFunc[8]) intFunc[8](); + if ((isfr & CORE_PIN14_BITMASK) && intFunc[14]) intFunc[14](); + if ((isfr & CORE_PIN20_BITMASK) && intFunc[20]) intFunc[20](); + if ((isfr & CORE_PIN21_BITMASK) && intFunc[21]) intFunc[21](); +} + +void porte_isr(void) +{ + uint32_t isfr = PORTE_ISFR; + PORTE_ISFR = isfr; + if ((isfr & CORE_PIN26_BITMASK) && intFunc[26]) intFunc[26](); + if ((isfr & CORE_PIN31_BITMASK) && intFunc[31]) intFunc[31](); +} + + + + +unsigned long rtc_get(void) +{ + return RTC_TSR; +} + +void rtc_set(unsigned long t) +{ + RTC_SR = 0; + RTC_TPR = 0; + RTC_TSR = t; + RTC_SR = RTC_SR_TCE; +} + + +// adjust is the amount of crystal error to compensate, 1 = 0.1192 ppm +// For example, adjust = -100 is slows the clock by 11.92 ppm +// +void rtc_compensate(int adjust) +{ + uint32_t comp, interval, tcr; + + // This simple approach tries to maximize the interval. + // Perhaps minimizing TCR would be better, so the + // compensation is distributed more evenly across + // many seconds, rather than saving it all up and then + // altering one second up to +/- 0.38% + if (adjust >= 0) { + comp = adjust; + interval = 256; + while (1) { + tcr = comp * interval; + if (tcr < 128*256) break; + if (--interval == 1) break; + } + tcr = tcr >> 8; + } else { + comp = -adjust; + interval = 256; + while (1) { + tcr = comp * interval; + if (tcr < 129*256) break; + if (--interval == 1) break; + } + tcr = tcr >> 8; + tcr = 256 - tcr; + } + RTC_TCR = ((interval - 1) << 8) | tcr; +} + +#if 0 +// TODO: build system should define this +// so RTC is automatically initialized to approx correct time +// at least when the program begins running right after upload +#ifndef TIME_T +#define TIME_T 1350160272 +#endif + +void init_rtc(void) +{ + serial_print("init_rtc\n"); + //SIM_SCGC6 |= SIM_SCGC6_RTC; + + // enable the RTC crystal oscillator, for approx 12pf crystal + if (!(RTC_CR & RTC_CR_OSCE)) { + serial_print("start RTC oscillator\n"); + RTC_SR = 0; + RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE; + } + // should wait for crystal to stabilize..... + + serial_print("SR="); + serial_phex32(RTC_SR); + serial_print("\n"); + serial_print("CR="); + serial_phex32(RTC_CR); + serial_print("\n"); + serial_print("TSR="); + serial_phex32(RTC_TSR); + serial_print("\n"); + serial_print("TCR="); + serial_phex32(RTC_TCR); + serial_print("\n"); + + if (RTC_SR & RTC_SR_TIF) { + // enable the RTC + RTC_SR = 0; + RTC_TPR = 0; + RTC_TSR = TIME_T; + RTC_SR = RTC_SR_TCE; + } +} +#endif + +extern void usb_init(void); + + +// create a default PWM at the same 488.28 Hz as Arduino Uno + +#if F_BUS == 60000000 +#define DEFAULT_FTM_MOD (61440 - 1) +#define DEFAULT_FTM_PRESCALE 1 +#elif F_BUS == 56000000 +#define DEFAULT_FTM_MOD (57344 - 1) +#define DEFAULT_FTM_PRESCALE 1 +#elif F_BUS == 48000000 +#define DEFAULT_FTM_MOD (49152 - 1) +#define DEFAULT_FTM_PRESCALE 1 +#elif F_BUS == 40000000 +#define DEFAULT_FTM_MOD (40960 - 1) +#define DEFAULT_FTM_PRESCALE 1 +#elif F_BUS == 36000000 +#define DEFAULT_FTM_MOD (36864 - 1) +#define DEFAULT_FTM_PRESCALE 1 +#elif F_BUS == 24000000 +#define DEFAULT_FTM_MOD (49152 - 1) +#define DEFAULT_FTM_PRESCALE 0 +#elif F_BUS == 16000000 +#define DEFAULT_FTM_MOD (32768 - 1) +#define DEFAULT_FTM_PRESCALE 0 +#elif F_BUS == 8000000 +#define DEFAULT_FTM_MOD (16384 - 1) +#define DEFAULT_FTM_PRESCALE 0 +#elif F_BUS == 4000000 +#define DEFAULT_FTM_MOD (8192 - 1) +#define DEFAULT_FTM_PRESCALE 0 +#elif F_BUS == 2000000 +#define DEFAULT_FTM_MOD (4096 - 1) +#define DEFAULT_FTM_PRESCALE 0 +#endif + +//void init_pins(void) +void _init_Teensyduino_internal_(void) +{ + init_pin_interrupts(); + + //SIM_SCGC6 |= SIM_SCGC6_FTM0; // TODO: use bitband for atomic read-mod-write + //SIM_SCGC6 |= SIM_SCGC6_FTM1; + FTM0_CNT = 0; + FTM0_MOD = DEFAULT_FTM_MOD; + FTM0_C0SC = 0x28; // MSnB:MSnA = 10, ELSnB:ELSnA = 10 + FTM0_C1SC = 0x28; + FTM0_C2SC = 0x28; + FTM0_C3SC = 0x28; + FTM0_C4SC = 0x28; + FTM0_C5SC = 0x28; + FTM0_C6SC = 0x28; + FTM0_C7SC = 0x28; + FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE); + FTM1_CNT = 0; + FTM1_MOD = DEFAULT_FTM_MOD; + FTM1_C0SC = 0x28; + FTM1_C1SC = 0x28; + FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE); +#if defined(__MK20DX256__) + FTM2_CNT = 0; + FTM2_MOD = DEFAULT_FTM_MOD; + FTM2_C0SC = 0x28; + FTM2_C1SC = 0x28; + FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(DEFAULT_FTM_PRESCALE); +#endif + + analog_init(); + //delay(100); // TODO: this is not necessary, right? + delay(4); + usb_init(); +} + + + +static uint8_t analog_write_res = 8; + +// SOPT4 is SIM select clocks? +// FTM is clocked by the bus clock, either 24 or 48 MHz +// input capture can be FTM1_CH0, CMP0 or CMP1 or USB start of frame +// 24 MHz with reload 49152 to match Arduino's speed = 488.28125 Hz + +void analogWrite(uint8_t pin, int val) +{ + uint32_t cval, max; + +#if defined(__MK20DX256__) + if (pin == A14) { + uint8_t res = analog_write_res; + if (res < 12) { + val <<= 12 - res; + } else if (res > 12) { + val >>= res - 12; + } + analogWriteDAC0(val); + return; + } +#endif + + max = 1 << analog_write_res; + if (val <= 0) { + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); // TODO: implement OUTPUT_LOW + return; + } else if (val >= max) { + digitalWrite(pin, HIGH); + pinMode(pin, OUTPUT); // TODO: implement OUTPUT_HIGH + return; + } + + //serial_print("analogWrite\n"); + //serial_print("val = "); + //serial_phex32(val); + //serial_print("\n"); + //serial_print("analog_write_res = "); + //serial_phex(analog_write_res); + //serial_print("\n"); + if (pin == 3 || pin == 4) { + cval = ((uint32_t)val * (uint32_t)(FTM1_MOD + 1)) >> analog_write_res; +#if defined(__MK20DX256__) + } else if (pin == 25 || pin == 32) { + cval = ((uint32_t)val * (uint32_t)(FTM2_MOD + 1)) >> analog_write_res; +#endif + } else { + cval = ((uint32_t)val * (uint32_t)(FTM0_MOD + 1)) >> analog_write_res; + } + //serial_print("cval = "); + //serial_phex32(cval); + //serial_print("\n"); + switch (pin) { + case 3: // PTA12, FTM1_CH0 + FTM1_C0V = cval; + CORE_PIN3_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 4: // PTA13, FTM1_CH1 + FTM1_C1V = cval; + CORE_PIN4_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 5: // PTD7, FTM0_CH7 + FTM0_C7V = cval; + CORE_PIN5_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 6: // PTD4, FTM0_CH4 + FTM0_C4V = cval; + CORE_PIN6_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 9: // PTC3, FTM0_CH2 + FTM0_C2V = cval; + CORE_PIN9_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 10: // PTC4, FTM0_CH3 + FTM0_C3V = cval; + CORE_PIN10_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 20: // PTD5, FTM0_CH5 + FTM0_C5V = cval; + CORE_PIN20_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 21: // PTD6, FTM0_CH6 + FTM0_C6V = cval; + CORE_PIN21_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 22: // PTC1, FTM0_CH0 + FTM0_C0V = cval; + CORE_PIN22_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 23: // PTC2, FTM0_CH1 + FTM0_C1V = cval; + CORE_PIN23_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE; + break; +#if defined(__MK20DX256__) + case 32: // PTB18, FTM2_CH0 + FTM2_C0V = cval; + CORE_PIN32_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; + break; + case 25: // PTB19, FTM1_CH1 + FTM2_C1V = cval; + CORE_PIN25_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE; + break; +#endif + default: + digitalWrite(pin, (val > 127) ? HIGH : LOW); + pinMode(pin, OUTPUT); + } +} + +void analogWriteRes(uint32_t bits) +{ + if (bits < 1) { + bits = 1; + } else if (bits > 16) { + bits = 16; + } + analog_write_res = bits; +} + +void analogWriteFrequency(uint8_t pin, uint32_t frequency) +{ + uint32_t minfreq, prescale, mod; + + //serial_print("analogWriteFrequency: pin = "); + //serial_phex(pin); + //serial_print(", freq = "); + //serial_phex32(frequency); + //serial_print("\n"); + for (prescale = 0; prescale < 7; prescale++) { + minfreq = (F_BUS >> 16) >> prescale; + if (frequency > minfreq) break; + } + //serial_print("F_BUS = "); + //serial_phex32(F_BUS >> prescale); + //serial_print("\n"); + //serial_print("prescale = "); + //serial_phex(prescale); + //serial_print("\n"); + //mod = ((F_BUS >> prescale) / frequency) - 1; + mod = (((F_BUS >> prescale) + (frequency >> 1)) / frequency) - 1; + if (mod > 65535) mod = 65535; + //serial_print("mod = "); + //serial_phex32(mod); + //serial_print("\n"); + if (pin == 3 || pin == 4) { + FTM1_SC = 0; + FTM1_CNT = 0; + FTM1_MOD = mod; + FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale); + } else if (pin == 5 || pin == 6 || pin == 9 || pin == 10 || + (pin >= 20 && pin <= 23)) { + FTM0_SC = 0; + FTM0_CNT = 0; + FTM0_MOD = mod; + FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale); + } +} + + + + +// TODO: startup code needs to initialize all pins to GPIO mode, input by default + +void digitalWrite(uint8_t pin, uint8_t val) +{ + if (pin >= CORE_NUM_DIGITAL) return; + if (*portModeRegister(pin)) { + if (val) { + *portSetRegister(pin) = 1; + } else { + *portClearRegister(pin) = 1; + } + } else { + volatile uint32_t *config = portConfigRegister(pin); + if (val) { + // TODO use bitband for atomic read-mod-write + *config |= (PORT_PCR_PE | PORT_PCR_PS); + //*config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; + } else { + // TODO use bitband for atomic read-mod-write + *config &= ~(PORT_PCR_PE); + //*config = PORT_PCR_MUX(1); + } + } + +} + +uint8_t digitalRead(uint8_t pin) +{ + if (pin >= CORE_NUM_DIGITAL) return 0; + return *portInputRegister(pin); +} + + + +void pinMode(uint8_t pin, uint8_t mode) +{ + volatile uint32_t *config; + + if (pin >= CORE_NUM_DIGITAL) return; + config = portConfigRegister(pin); + + if (mode == OUTPUT) { + *portModeRegister(pin) = 1; + *config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + } else { + *portModeRegister(pin) = 0; + if (mode == INPUT) { + *config = PORT_PCR_MUX(1); + } else { + *config = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; // pullup + } + } +} + + +void _shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value) +{ + if (bitOrder == LSBFIRST) { + shiftOut_lsbFirst(dataPin, clockPin, value); + } else { + shiftOut_msbFirst(dataPin, clockPin, value); + } +} + +void shiftOut_lsbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) +{ + uint8_t mask; + for (mask=0x01; mask; mask <<= 1) { + digitalWrite(dataPin, value & mask); + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} + +void shiftOut_msbFirst(uint8_t dataPin, uint8_t clockPin, uint8_t value) +{ + uint8_t mask; + for (mask=0x80; mask; mask >>= 1) { + digitalWrite(dataPin, value & mask); + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} + +uint8_t _shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) +{ + if (bitOrder == LSBFIRST) { + return shiftIn_lsbFirst(dataPin, clockPin); + } else { + return shiftIn_msbFirst(dataPin, clockPin); + } +} + +uint8_t shiftIn_lsbFirst(uint8_t dataPin, uint8_t clockPin) +{ + uint8_t mask, value=0; + for (mask=0x01; mask; mask <<= 1) { + digitalWrite(clockPin, HIGH); + if (digitalRead(dataPin)) value |= mask; + digitalWrite(clockPin, LOW); + } + return value; +} + +uint8_t shiftIn_msbFirst(uint8_t dataPin, uint8_t clockPin) +{ + uint8_t mask, value=0; + for (mask=0x80; mask; mask >>= 1) { + digitalWrite(clockPin, HIGH); + if (digitalRead(dataPin)) value |= mask; + digitalWrite(clockPin, LOW); + } + return value; +} + + + +// the systick interrupt is supposed to increment this at 1 kHz rate +volatile uint32_t systick_millis_count = 0; + +//uint32_t systick_current, systick_count, systick_istatus; // testing only + +uint32_t micros(void) +{ + uint32_t count, current, istatus; + + __disable_irq(); + current = SYST_CVR; + count = systick_millis_count; + istatus = SCB_ICSR; // bit 26 indicates if systick exception pending + __enable_irq(); + //systick_current = current; + //systick_count = count; + //systick_istatus = istatus & SCB_ICSR_PENDSTSET ? 1 : 0; + if ((istatus & SCB_ICSR_PENDSTSET) && current > 50) count++; + current = ((F_CPU / 1000) - 1) - current; + return count * 1000 + current / (F_CPU / 1000000); +} + +void delay(uint32_t ms) +{ + uint32_t start = micros(); + + if (ms > 0) { + while (1) { + if ((micros() - start) >= 1000) { + ms--; + if (ms == 0) return; + start += 1000; + } + yield(); + } + } +} + +// TODO: verify these result in correct timeouts... +#if F_CPU == 168000000 +#define PULSEIN_LOOPS_PER_USEC 25 +#elif F_CPU == 144000000 +#define PULSEIN_LOOPS_PER_USEC 21 +#elif F_CPU == 120000000 +#define PULSEIN_LOOPS_PER_USEC 18 +#elif F_CPU == 96000000 +#define PULSEIN_LOOPS_PER_USEC 14 +#elif F_CPU == 72000000 +#define PULSEIN_LOOPS_PER_USEC 10 +#elif F_CPU == 48000000 +#define PULSEIN_LOOPS_PER_USEC 7 +#elif F_CPU == 24000000 +#define PULSEIN_LOOPS_PER_USEC 4 +#elif F_CPU == 16000000 +#define PULSEIN_LOOPS_PER_USEC 1 +#elif F_CPU == 8000000 +#define PULSEIN_LOOPS_PER_USEC 1 +#elif F_CPU == 4000000 +#define PULSEIN_LOOPS_PER_USEC 1 +#elif F_CPU == 2000000 +#define PULSEIN_LOOPS_PER_USEC 1 +#endif + + +uint32_t pulseIn_high(volatile uint8_t *reg, uint32_t timeout) +{ + uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; + uint32_t usec_start, usec_stop; + + // wait for any previous pulse to end + while (*reg) { + if (--timeout_count == 0) return 0; + } + // wait for the pulse to start + while (!*reg) { + if (--timeout_count == 0) return 0; + } + usec_start = micros(); + // wait for the pulse to stop + while (*reg) { + if (--timeout_count == 0) return 0; + } + usec_stop = micros(); + return usec_stop - usec_start; +} + +uint32_t pulseIn_low(volatile uint8_t *reg, uint32_t timeout) +{ + uint32_t timeout_count = timeout * PULSEIN_LOOPS_PER_USEC; + uint32_t usec_start, usec_stop; + + // wait for any previous pulse to end + while (!*reg) { + if (--timeout_count == 0) return 0; + } + // wait for the pulse to start + while (*reg) { + if (--timeout_count == 0) return 0; + } + usec_start = micros(); + // wait for the pulse to stop + while (!*reg) { + if (--timeout_count == 0) return 0; + } + usec_stop = micros(); + return usec_stop - usec_start; +} + +// TODO: an inline version should handle the common case where state is const +uint32_t pulseIn(uint8_t pin, uint8_t state, uint32_t timeout) +{ + if (pin >= CORE_NUM_DIGITAL) return 0; + if (state) return pulseIn_high(portInputRegister(pin), timeout); + return pulseIn_low(portInputRegister(pin), timeout);; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_desc.c b/src/openmv/src/micropython/ports/teensy/core/usb_desc.c new file mode 100755 index 0000000..828a619 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_desc.c @@ -0,0 +1,895 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if F_CPU >= 20000000 + +#include "usb_desc.h" +#include "usb_names.h" +#include "mk20dx128.h" +#include "avr_functions.h" + +// USB Descriptors are binary data which the USB host reads to +// automatically detect a USB device's capabilities. The format +// and meaning of every field is documented in numerous USB +// standards. When working with USB descriptors, despite the +// complexity of the standards and poor writing quality in many +// of those documents, remember descriptors are nothing more +// than constant binary data that tells the USB host what the +// device can do. Computers will load drivers based on this data. +// Those drivers then communicate on the endpoints specified by +// the descriptors. + +// To configure a new combination of interfaces or make minor +// changes to existing configuration (eg, change the name or ID +// numbers), usually you would edit "usb_desc.h". This file +// is meant to be configured by the header, so generally it is +// only edited to add completely new USB interfaces or features. + + + +// ************************************************************** +// USB Device +// ************************************************************** + +#define LSB(n) ((n) & 255) +#define MSB(n) (((n) >> 8) & 255) + +// USB Device Descriptor. The USB host reads this first, to learn +// what type of device is connected. +static uint8_t device_descriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB +#ifdef DEVICE_CLASS + DEVICE_CLASS, // bDeviceClass +#else + 0, +#endif +#ifdef DEVICE_SUBCLASS + DEVICE_SUBCLASS, // bDeviceSubClass +#else + 0, +#endif +#ifdef DEVICE_PROTOCOL + DEVICE_PROTOCOL, // bDeviceProtocol +#else + 0, +#endif + EP0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 3, // iSerialNumber + 1 // bNumConfigurations +}; + +// These descriptors must NOT be "const", because the USB DMA +// has trouble accessing flash memory with enough bandwidth +// while the processor is executing from flash. + + + +// ************************************************************** +// HID Report Descriptors +// ************************************************************** + +// Each HID interface needs a special report descriptor that tells +// the meaning and format of the data. + +#ifdef KEYBOARD_INTERFACE +// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 +static uint8_t keyboard_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop), + 0x09, 0x06, // Usage (Keyboard), + 0xA1, 0x01, // Collection (Application), + 0x75, 0x01, // Report Size (1), + 0x95, 0x08, // Report Count (8), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0xE0, // Usage Minimum (224), + 0x29, 0xE7, // Usage Maximum (231), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte + 0x95, 0x08, // Report Count (8), + 0x75, 0x01, // Report Size (1), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x01, // Logical Maximum (1), + 0x05, 0x0C, // Usage Page (Consumer), + 0x09, 0xE9, // Usage (Volume Increment), + 0x09, 0xEA, // Usage (Volume Decrement), + 0x09, 0xE2, // Usage (Mute), + 0x09, 0xCD, // Usage (Play/Pause), + 0x09, 0xB5, // Usage (Scan Next Track), + 0x09, 0xB6, // Usage (Scan Previous Track), + 0x09, 0xB7, // Usage (Stop), + 0x09, 0xB8, // Usage (Eject), + 0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys + 0x95, 0x05, // Report Count (5), + 0x75, 0x01, // Report Size (1), + 0x05, 0x08, // Usage Page (LEDs), + 0x19, 0x01, // Usage Minimum (1), + 0x29, 0x05, // Usage Maximum (5), + 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report + 0x95, 0x01, // Report Count (1), + 0x75, 0x03, // Report Size (3), + 0x91, 0x03, // Output (Constant), ;LED report padding + 0x95, 0x06, // Report Count (6), + 0x75, 0x08, // Report Size (8), + 0x15, 0x00, // Logical Minimum (0), + 0x25, 0x7F, // Logical Maximum(104), + 0x05, 0x07, // Usage Page (Key Codes), + 0x19, 0x00, // Usage Minimum (0), + 0x29, 0x7F, // Usage Maximum (104), + 0x81, 0x00, // Input (Data, Array), ;Normal keys + 0xc0 // End Collection +}; +#endif + +#ifdef MOUSE_INTERFACE +// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension +static uint8_t mouse_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // REPORT_ID (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button #1) + 0x29, 0x08, // Usage Maximum (Button #8) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x08, // Report Count (8) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8), + 0x95, 0x03, // Report Count (3), + 0x81, 0x06, // Input (Data, Variable, Relative) + 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x02, // REPORT_ID (2) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16), + 0x95, 0x02, // Report Count (2), + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0xC0 // End Collection +}; +#endif + +#ifdef JOYSTICK_INTERFACE +static uint8_t joystick_report_desc[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x20, // Report Count (32) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (Button #1) + 0x29, 0x20, // Usage Maximum (Button #32) + 0x81, 0x02, // Input (variable,absolute) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (20) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (variable,absolute,null_state) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection () + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x04, // Report Count (4) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (variable,absolute) + 0xC0, // End Collection + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x03, // Logical Maximum (1023) + 0x75, 0x0A, // Report Size (10) + 0x95, 0x02, // Report Count (2) + 0x09, 0x36, // Usage (Slider) + 0x09, 0x36, // Usage (Slider) + 0x81, 0x02, // Input (variable,absolute) + 0xC0 // End Collection +}; +#endif + +#ifdef SEREMU_INTERFACE +static uint8_t seremu_report_desc[] = { + 0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined) + 0x09, 0x04, // Usage 0x04 + 0xA1, 0x5C, // Collection 0x5C + 0x75, 0x08, // report size = 8 bits (global) + 0x15, 0x00, // logical minimum = 0 (global) + 0x26, 0xFF, 0x00, // logical maximum = 255 (global) + 0x95, SEREMU_TX_SIZE, // report count (global) + 0x09, 0x75, // usage (local) + 0x81, 0x02, // Input + 0x95, SEREMU_RX_SIZE, // report count (global) + 0x09, 0x76, // usage (local) + 0x91, 0x02, // Output + 0x95, 0x04, // report count (global) + 0x09, 0x76, // usage (local) + 0xB1, 0x02, // Feature + 0xC0 // end collection +}; +#endif + +#ifdef RAWHID_INTERFACE +static uint8_t rawhid_report_desc[] = { + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), + 0xA1, 0x01, // Collection 0x01 + 0x75, 0x08, // report size = 8 bits + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 + 0x95, RAWHID_TX_SIZE, // report count + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) + 0x95, RAWHID_RX_SIZE, // report count + 0x09, 0x02, // usage + 0x91, 0x02, // Output (array) + 0xC0 // end collection +}; +#endif + +#ifdef FLIGHTSIM_INTERFACE +static uint8_t flightsim_report_desc[] = { + 0x06, 0x1C, 0xFF, // Usage page = 0xFF1C + 0x0A, 0x39, 0xA7, // Usage = 0xA739 + 0xA1, 0x01, // Collection 0x01 + 0x75, 0x08, // report size = 8 bits + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 + 0x95, FLIGHTSIM_TX_SIZE, // report count + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) + 0x95, FLIGHTSIM_RX_SIZE, // report count + 0x09, 0x02, // usage + 0x91, 0x02, // Output (array) + 0xC0 // end collection +}; +#endif + + + +// ************************************************************** +// USB Configuration +// ************************************************************** + +// USB Configuration Descriptor. This huge descriptor tells all +// of the devices capbilities. +static uint8_t config_descriptor[CONFIG_DESC_SIZE] = { + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + 9, // bLength; + 2, // bDescriptorType; + LSB(CONFIG_DESC_SIZE), // wTotalLength + MSB(CONFIG_DESC_SIZE), + NUM_INTERFACE, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0xC0, // bmAttributes + 50, // bMaxPower + +#ifdef CDC_IAD_DESCRIPTOR + // interface association descriptor, USB ECN, Table 9-Z + 8, // bLength + 11, // bDescriptorType + CDC_STATUS_INTERFACE, // bFirstInterface + 2, // bInterfaceCount + 0x02, // bFunctionClass + 0x02, // bFunctionSubClass + 0x01, // bFunctionProtocol + 4, // iFunction +#endif + +#ifdef CDC_DATA_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + CDC_STATUS_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0, // iInterface + // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x00, // bDescriptorSubtype + 0x10, 0x01, // bcdCDC + // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x01, // bDescriptorSubtype + 0x01, // bmCapabilities + 1, // bDataInterface + // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 + 4, // bFunctionLength + 0x24, // bDescriptorType + 0x02, // bDescriptorSubtype + 0x06, // bmCapabilities + // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 + 5, // bFunctionLength + 0x24, // bDescriptorType + 0x06, // bDescriptorSubtype + CDC_STATUS_INTERFACE, // bMasterInterface + CDC_DATA_INTERFACE, // bSlaveInterface0 + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_ACM_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + CDC_ACM_SIZE, 0, // wMaxPacketSize + 64, // bInterval + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + CDC_DATA_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x0A, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_RX_ENDPOINT, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_RX_SIZE, 0, // wMaxPacketSize + 0, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + CDC_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + CDC_TX_SIZE, 0, // wMaxPacketSize + 0, // bInterval +#endif // CDC_DATA_INTERFACE + +#ifdef MIDI_INTERFACE + // Standard MS Interface Descriptor, + 9, // bLength + 4, // bDescriptorType + MIDI_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x01, // bInterfaceClass (0x01 = Audio) + 0x03, // bInterfaceSubClass (0x03 = MIDI) + 0x00, // bInterfaceProtocol (unused for MIDI) + 0, // iInterface + // MIDI MS Interface Header, USB MIDI 6.1.2.1, page 21, Table 6-2 + 7, // bLength + 0x24, // bDescriptorType = CS_INTERFACE + 0x01, // bDescriptorSubtype = MS_HEADER + 0x00, 0x01, // bcdMSC = revision 01.00 + 0x41, 0x00, // wTotalLength + // MIDI IN Jack Descriptor, B.4.3, Table B-7 (embedded), page 40 + 6, // bLength + 0x24, // bDescriptorType = CS_INTERFACE + 0x02, // bDescriptorSubtype = MIDI_IN_JACK + 0x01, // bJackType = EMBEDDED + 1, // bJackID, ID = 1 + 0, // iJack + // MIDI IN Jack Descriptor, B.4.3, Table B-8 (external), page 40 + 6, // bLength + 0x24, // bDescriptorType = CS_INTERFACE + 0x02, // bDescriptorSubtype = MIDI_IN_JACK + 0x02, // bJackType = EXTERNAL + 2, // bJackID, ID = 2 + 0, // iJack + // MIDI OUT Jack Descriptor, B.4.4, Table B-9, page 41 + 9, + 0x24, // bDescriptorType = CS_INTERFACE + 0x03, // bDescriptorSubtype = MIDI_OUT_JACK + 0x01, // bJackType = EMBEDDED + 3, // bJackID, ID = 3 + 1, // bNrInputPins = 1 pin + 2, // BaSourceID(1) = 2 + 1, // BaSourcePin(1) = first pin + 0, // iJack + // MIDI OUT Jack Descriptor, B.4.4, Table B-10, page 41 + 9, + 0x24, // bDescriptorType = CS_INTERFACE + 0x03, // bDescriptorSubtype = MIDI_OUT_JACK + 0x02, // bJackType = EXTERNAL + 4, // bJackID, ID = 4 + 1, // bNrInputPins = 1 pin + 1, // BaSourceID(1) = 1 + 1, // BaSourcePin(1) = first pin + 0, // iJack + // Standard Bulk OUT Endpoint Descriptor, B.5.1, Table B-11, pae 42 + 9, // bLength + 5, // bDescriptorType = ENDPOINT + MIDI_RX_ENDPOINT, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + MIDI_RX_SIZE, 0, // wMaxPacketSize + 0, // bInterval + 0, // bRefresh + 0, // bSynchAddress + // Class-specific MS Bulk OUT Endpoint Descriptor, B.5.2, Table B-12, page 42 + 5, // bLength + 0x25, // bDescriptorSubtype = CS_ENDPOINT + 0x01, // bJackType = MS_GENERAL + 1, // bNumEmbMIDIJack = 1 jack + 1, // BaAssocJackID(1) = jack ID #1 + // Standard Bulk IN Endpoint Descriptor, B.5.1, Table B-11, pae 42 + 9, // bLength + 5, // bDescriptorType = ENDPOINT + MIDI_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + MIDI_TX_SIZE, 0, // wMaxPacketSize + 0, // bInterval + 0, // bRefresh + 0, // bSynchAddress + // Class-specific MS Bulk IN Endpoint Descriptor, B.5.2, Table B-12, page 42 + 5, // bLength + 0x25, // bDescriptorSubtype = CS_ENDPOINT + 0x01, // bJackType = MS_GENERAL + 1, // bNumEmbMIDIJack = 1 jack + 3, // BaAssocJackID(1) = jack ID #3 +#endif // MIDI_INTERFACE + +#ifdef KEYBOARD_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + KEYBOARD_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x01, // bInterfaceSubClass (0x01 = Boot) + 0x01, // bInterfaceProtocol (0x01 = Keyboard) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(keyboard_report_desc)), // wDescriptorLength + MSB(sizeof(keyboard_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + KEYBOARD_SIZE, 0, // wMaxPacketSize + KEYBOARD_INTERVAL, // bInterval +#endif // KEYBOARD_INTERFACE + +#ifdef MOUSE_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + MOUSE_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x01 = Boot) + 0x00, // bInterfaceProtocol (0x02 = Mouse) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(mouse_report_desc)), // wDescriptorLength + MSB(sizeof(mouse_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + MOUSE_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + MOUSE_SIZE, 0, // wMaxPacketSize + MOUSE_INTERVAL, // bInterval +#endif // MOUSE_INTERFACE + +#ifdef RAWHID_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + RAWHID_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(rawhid_report_desc)), // wDescriptorLength + MSB(sizeof(rawhid_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWHID_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + RAWHID_TX_SIZE, 0, // wMaxPacketSize + RAWHID_TX_INTERVAL, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWHID_RX_ENDPOINT, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + RAWHID_RX_SIZE, 0, // wMaxPacketSize + RAWHID_RX_INTERVAL, // bInterval +#endif // RAWHID_INTERFACE + +#ifdef FLIGHTSIM_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + FLIGHTSIM_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(flightsim_report_desc)), // wDescriptorLength + MSB(sizeof(flightsim_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + FLIGHTSIM_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + FLIGHTSIM_TX_SIZE, 0, // wMaxPacketSize + FLIGHTSIM_TX_INTERVAL, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + FLIGHTSIM_RX_ENDPOINT, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + FLIGHTSIM_RX_SIZE, 0, // wMaxPacketSize + FLIGHTSIM_RX_INTERVAL, // bInterval +#endif // FLIGHTSIM_INTERFACE + +#ifdef SEREMU_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + SEREMU_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(seremu_report_desc)), // wDescriptorLength + MSB(sizeof(seremu_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + SEREMU_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + SEREMU_TX_SIZE, 0, // wMaxPacketSize + SEREMU_TX_INTERVAL, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + SEREMU_RX_ENDPOINT, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + SEREMU_RX_SIZE, 0, // wMaxPacketSize + SEREMU_RX_INTERVAL, // bInterval +#endif // SEREMU_INTERFACE + +#ifdef JOYSTICK_INTERFACE + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + JOYSTICK_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 1, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + LSB(sizeof(joystick_report_desc)), // wDescriptorLength + MSB(sizeof(joystick_report_desc)), + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + JOYSTICK_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + JOYSTICK_SIZE, 0, // wMaxPacketSize + JOYSTICK_INTERVAL, // bInterval +#endif // JOYSTICK_INTERFACE + +}; + + +// ************************************************************** +// String Descriptors +// ************************************************************** + +// The descriptors above can provide human readable strings, +// referenced by index numbers. These descriptors are the +// actual string data + +/* defined in usb_names.h +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wString[]; +}; +*/ + +extern struct usb_string_descriptor_struct usb_string_manufacturer_name + __attribute__ ((weak, alias("usb_string_manufacturer_name_default"))); +extern struct usb_string_descriptor_struct usb_string_product_name + __attribute__ ((weak, alias("usb_string_product_name_default"))); +extern struct usb_string_descriptor_struct usb_string_serial_number + __attribute__ ((weak, alias("usb_string_serial_number_default"))); + +struct usb_string_descriptor_struct string0 = { + 4, + 3, + {0x0409} +}; + +struct usb_string_descriptor_struct usb_string_manufacturer_name_default = { + 2 + MANUFACTURER_NAME_LEN * 2, + 3, + MANUFACTURER_NAME +}; +struct usb_string_descriptor_struct usb_string_product_name_default = { + 2 + PRODUCT_NAME_LEN * 2, + 3, + PRODUCT_NAME +}; +struct usb_string_descriptor_struct usb_string_serial_number_default = { + 12, + 3, + {0,0,0,0,0,0,0,0,0,0} +}; + +void usb_init_serialnumber(void) +{ + char buf[11]; + uint32_t i, num; + + __disable_irq(); + FTFL_FSTAT = FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL; + FTFL_FCCOB0 = 0x41; + FTFL_FCCOB1 = 15; + FTFL_FSTAT = FTFL_FSTAT_CCIF; + while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF)) ; // wait + num = *(uint32_t *)&FTFL_FCCOB7; + __enable_irq(); + // add extra zero to work around OS-X CDC-ACM driver bug + if (num < 10000000) num = num * 10; + ultoa(num, buf, 10); + for (i=0; i<10; i++) { + char c = buf[i]; + if (!c) break; + usb_string_serial_number_default.wString[i] = c; + } + usb_string_serial_number_default.bLength = i * 2 + 2; +} + + +// ************************************************************** +// Descriptors List +// ************************************************************** + +// This table provides access to all the descriptor data above. + +const usb_descriptor_list_t usb_descriptor_list[] = { + //wValue, wIndex, address, length + {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, + {0x0200, 0x0000, config_descriptor, sizeof(config_descriptor)}, +#ifdef SEREMU_INTERFACE + {0x2200, SEREMU_INTERFACE, seremu_report_desc, sizeof(seremu_report_desc)}, + {0x2100, SEREMU_INTERFACE, config_descriptor+SEREMU_DESC_OFFSET, 9}, +#endif +#ifdef KEYBOARD_INTERFACE + {0x2200, KEYBOARD_INTERFACE, keyboard_report_desc, sizeof(keyboard_report_desc)}, + {0x2100, KEYBOARD_INTERFACE, config_descriptor+KEYBOARD_DESC_OFFSET, 9}, +#endif +#ifdef MOUSE_INTERFACE + {0x2200, MOUSE_INTERFACE, mouse_report_desc, sizeof(mouse_report_desc)}, + {0x2100, MOUSE_INTERFACE, config_descriptor+MOUSE_DESC_OFFSET, 9}, +#endif +#ifdef JOYSTICK_INTERFACE + {0x2200, JOYSTICK_INTERFACE, joystick_report_desc, sizeof(joystick_report_desc)}, + {0x2100, JOYSTICK_INTERFACE, config_descriptor+JOYSTICK_DESC_OFFSET, 9}, +#endif +#ifdef RAWHID_INTERFACE + {0x2200, RAWHID_INTERFACE, rawhid_report_desc, sizeof(rawhid_report_desc)}, + {0x2100, RAWHID_INTERFACE, config_descriptor+RAWHID_DESC_OFFSET, 9}, +#endif +#ifdef FLIGHTSIM_INTERFACE + {0x2200, FLIGHTSIM_INTERFACE, flightsim_report_desc, sizeof(flightsim_report_desc)}, + {0x2100, FLIGHTSIM_INTERFACE, config_descriptor+FLIGHTSIM_DESC_OFFSET, 9}, +#endif + {0x0300, 0x0000, (const uint8_t *)&string0, 0}, + {0x0301, 0x0409, (const uint8_t *)&usb_string_manufacturer_name, 0}, + {0x0302, 0x0409, (const uint8_t *)&usb_string_product_name, 0}, + {0x0303, 0x0409, (const uint8_t *)&usb_string_serial_number, 0}, + //{0x0301, 0x0409, (const uint8_t *)&string1, 0}, + //{0x0302, 0x0409, (const uint8_t *)&string2, 0}, + //{0x0303, 0x0409, (const uint8_t *)&string3, 0}, + {0, 0, NULL, 0} +}; + + +// ************************************************************** +// Endpoint Configuration +// ************************************************************** + +#if 0 +// 0x00 = not used +// 0x19 = Recieve only +// 0x15 = Transmit only +// 0x1D = Transmit & Recieve +// +const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = +{ + 0x00, 0x15, 0x19, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +#endif + + +const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS] = +{ +#if (defined(ENDPOINT1_CONFIG) && NUM_ENDPOINTS >= 1) + ENDPOINT1_CONFIG, +#elif (NUM_ENDPOINTS >= 1) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT2_CONFIG) && NUM_ENDPOINTS >= 2) + ENDPOINT2_CONFIG, +#elif (NUM_ENDPOINTS >= 2) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT3_CONFIG) && NUM_ENDPOINTS >= 3) + ENDPOINT3_CONFIG, +#elif (NUM_ENDPOINTS >= 3) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT4_CONFIG) && NUM_ENDPOINTS >= 4) + ENDPOINT4_CONFIG, +#elif (NUM_ENDPOINTS >= 4) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT5_CONFIG) && NUM_ENDPOINTS >= 5) + ENDPOINT5_CONFIG, +#elif (NUM_ENDPOINTS >= 5) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT6_CONFIG) && NUM_ENDPOINTS >= 6) + ENDPOINT6_CONFIG, +#elif (NUM_ENDPOINTS >= 6) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT7_CONFIG) && NUM_ENDPOINTS >= 7) + ENDPOINT7_CONFIG, +#elif (NUM_ENDPOINTS >= 7) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT8_CONFIG) && NUM_ENDPOINTS >= 8) + ENDPOINT8_CONFIG, +#elif (NUM_ENDPOINTS >= 8) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT9_CONFIG) && NUM_ENDPOINTS >= 9) + ENDPOINT9_CONFIG, +#elif (NUM_ENDPOINTS >= 9) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT10_CONFIG) && NUM_ENDPOINTS >= 10) + ENDPOINT10_CONFIG, +#elif (NUM_ENDPOINTS >= 10) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT11_CONFIG) && NUM_ENDPOINTS >= 11) + ENDPOINT11_CONFIG, +#elif (NUM_ENDPOINTS >= 11) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT12_CONFIG) && NUM_ENDPOINTS >= 12) + ENDPOINT12_CONFIG, +#elif (NUM_ENDPOINTS >= 12) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT13_CONFIG) && NUM_ENDPOINTS >= 13) + ENDPOINT13_CONFIG, +#elif (NUM_ENDPOINTS >= 13) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT14_CONFIG) && NUM_ENDPOINTS >= 14) + ENDPOINT14_CONFIG, +#elif (NUM_ENDPOINTS >= 14) + ENDPOINT_UNUSED, +#endif +#if (defined(ENDPOINT15_CONFIG) && NUM_ENDPOINTS >= 15) + ENDPOINT15_CONFIG, +#elif (NUM_ENDPOINTS >= 15) + ENDPOINT_UNUSED, +#endif +}; + + + +#endif // F_CPU >= 20 MHz diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_desc.h b/src/openmv/src/micropython/ports/teensy/core/usb_desc.h new file mode 100755 index 0000000..a951e03 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_desc.h @@ -0,0 +1,313 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _usb_desc_h_ +#define _usb_desc_h_ + +#if F_CPU >= 20000000 + +// This header is NOT meant to be included when compiling +// user sketches in Arduino. The low-level functions +// provided by usb_dev.c are meant to be called only by +// code which provides higher-level interfaces to the user. + +#include +#include + +#define ENDPOINT_UNUSED 0x00 +#define ENDPOINT_TRANSIMIT_ONLY 0x15 +#define ENDPOINT_RECEIVE_ONLY 0x19 +#define ENDPOINT_TRANSMIT_AND_RECEIVE 0x1D + +/* +To modify a USB Type to have different interfaces, start in this +file. Delete the XYZ_INTERFACE lines for any interfaces you +wish to remove, and copy them from another USB Type for any you +want to add. + +Give each interface a unique number, and edit NUM_INTERFACE to +reflect the number of interfaces. + +Within each interface, make sure it uses a unique set of endpoints. +Edit NUM_ENDPOINTS to be at least the largest endpoint number used. +Then edit the ENDPOINT*_CONFIG lines so each endpoint is configured +the proper way (transmit, receive, or both). + +The CONFIG_DESC_SIZE and any XYZ_DESC_OFFSET numbers must be +edited to the correct sizes. See usb_desc.c for the giant array +of bytes. Someday these may be done automatically..... (but how?) + +If you are using existing interfaces, the code in each file should +automatically adapt to the changes you specify. If you need to +create a new type of interface, you'll need to write the code which +sends and receives packets, and presents an API to the user. + +Finally, edit usb_inst.cpp, which creats instances of the C++ +objects for each combination. + +Some operating systems, especially Windows, may cache USB device +info. Changes to the device name may not update on the same +computer unless the vendor or product ID numbers change, or the +"bcdDevice" revision code is increased. + +If these instructions are missing steps or could be improved, please +let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports +*/ + + + +#if defined(USB_SERIAL) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0483 + #define DEVICE_CLASS 2 // 2 = Communication Class + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'U','S','B',' ','S','e','r','i','a','l'} + #define PRODUCT_NAME_LEN 10 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 4 + #define NUM_USB_BUFFERS 12 + #define NUM_INTERFACE 2 + #define CDC_STATUS_INTERFACE 0 + #define CDC_DATA_INTERFACE 1 + #define CDC_ACM_ENDPOINT 2 + #define CDC_RX_ENDPOINT 3 + #define CDC_TX_ENDPOINT 4 + #define CDC_ACM_SIZE 16 + #define CDC_RX_SIZE 64 + #define CDC_TX_SIZE 64 + #define CONFIG_DESC_SIZE (9+9+5+5+4+5+7+9+7+7) + #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY + +#elif defined(USB_HID) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0482 + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'} + #define PRODUCT_NAME_LEN 23 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 5 + #define NUM_USB_BUFFERS 24 + #define NUM_INTERFACE 4 + #define SEREMU_INTERFACE 2 // Serial emulation + #define SEREMU_TX_ENDPOINT 1 + #define SEREMU_TX_SIZE 64 + #define SEREMU_TX_INTERVAL 1 + #define SEREMU_RX_ENDPOINT 2 + #define SEREMU_RX_SIZE 32 + #define SEREMU_RX_INTERVAL 2 + #define KEYBOARD_INTERFACE 0 // Keyboard + #define KEYBOARD_ENDPOINT 3 + #define KEYBOARD_SIZE 8 + #define KEYBOARD_INTERVAL 1 + #define MOUSE_INTERFACE 1 // Mouse + #define MOUSE_ENDPOINT 5 + #define MOUSE_SIZE 8 + #define MOUSE_INTERVAL 1 + #define JOYSTICK_INTERFACE 3 // Joystick + #define JOYSTICK_ENDPOINT 4 + #define JOYSTICK_SIZE 16 + #define JOYSTICK_INTERVAL 2 + #define KEYBOARD_DESC_OFFSET (9 + 9) + #define MOUSE_DESC_OFFSET (9 + 9+9+7 + 9) + #define SEREMU_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 9) + #define JOYSTICK_DESC_OFFSET (9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9) + #define CONFIG_DESC_SIZE (9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY + +#elif defined(USB_SERIAL_HID) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0487 + #define DEVICE_CLASS 0xEF + #define DEVICE_SUBCLASS 0x02 + #define DEVICE_PROTOCOL 0x01 + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'} + #define PRODUCT_NAME_LEN 30 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 6 + #define NUM_USB_BUFFERS 30 + #define NUM_INTERFACE 5 + #define CDC_IAD_DESCRIPTOR 1 + #define CDC_STATUS_INTERFACE 0 + #define CDC_DATA_INTERFACE 1 // Serial + #define CDC_ACM_ENDPOINT 2 + #define CDC_RX_ENDPOINT 3 + #define CDC_TX_ENDPOINT 4 + #define CDC_ACM_SIZE 16 + #define CDC_RX_SIZE 64 + #define CDC_TX_SIZE 64 + #define KEYBOARD_INTERFACE 2 // Keyboard + #define KEYBOARD_ENDPOINT 1 + #define KEYBOARD_SIZE 8 + #define KEYBOARD_INTERVAL 1 + #define MOUSE_INTERFACE 3 // Mouse + #define MOUSE_ENDPOINT 5 + #define MOUSE_SIZE 8 + #define MOUSE_INTERVAL 2 + #define JOYSTICK_INTERFACE 4 // Joystick + #define JOYSTICK_ENDPOINT 6 + #define JOYSTICK_SIZE 16 + #define JOYSTICK_INTERVAL 1 + #define KEYBOARD_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9) + #define MOUSE_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9) + #define JOYSTICK_DESC_OFFSET (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9) + #define CONFIG_DESC_SIZE (9+8 + 9+5+5+4+5+7+9+7+7 + 9+9+7 + 9+9+7 + 9+9+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT2_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT5_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT6_CONFIG ENDPOINT_TRANSIMIT_ONLY + +#elif defined(USB_MIDI) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0485 + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'T','e','e','n','s','y',' ','M','I','D','I'} + #define PRODUCT_NAME_LEN 11 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 4 + #define NUM_USB_BUFFERS 16 + #define NUM_INTERFACE 2 + #define SEREMU_INTERFACE 1 // Serial emulation + #define SEREMU_TX_ENDPOINT 1 + #define SEREMU_TX_SIZE 64 + #define SEREMU_TX_INTERVAL 1 + #define SEREMU_RX_ENDPOINT 2 + #define SEREMU_RX_SIZE 32 + #define SEREMU_RX_INTERVAL 2 + #define MIDI_INTERFACE 0 // MIDI + #define MIDI_TX_ENDPOINT 3 + #define MIDI_TX_SIZE 64 + #define MIDI_RX_ENDPOINT 4 + #define MIDI_RX_SIZE 64 + #define SEREMU_DESC_OFFSET (9 + 9+7+6+6+9+9+9+5+9+5 + 9) + #define CONFIG_DESC_SIZE (9 + 9+7+6+6+9+9+9+5+9+5 + 9+9+7+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY + +#elif defined(USB_RAWHID) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0486 + #define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF + #define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'T','e','e','n','s','y','d','u','i','n','o',' ','R','a','w','H','I','D'} + #define PRODUCT_NAME_LEN 18 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 6 + #define NUM_USB_BUFFERS 12 + #define NUM_INTERFACE 2 + #define RAWHID_INTERFACE 0 // RawHID + #define RAWHID_TX_ENDPOINT 3 + #define RAWHID_TX_SIZE 64 + #define RAWHID_TX_INTERVAL 1 + #define RAWHID_RX_ENDPOINT 4 + #define RAWHID_RX_SIZE 64 + #define RAWHID_RX_INTERVAL 1 + #define SEREMU_INTERFACE 1 // Serial emulation + #define SEREMU_TX_ENDPOINT 1 + #define SEREMU_TX_SIZE 64 + #define SEREMU_TX_INTERVAL 1 + #define SEREMU_RX_ENDPOINT 2 + #define SEREMU_RX_SIZE 32 + #define SEREMU_RX_INTERVAL 2 + #define RAWHID_DESC_OFFSET (9 + 9) + #define SEREMU_DESC_OFFSET (9 + 9+9+7+7 + 9) + #define CONFIG_DESC_SIZE (9 + 9+9+7+7 + 9+9+7+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY + +#elif defined(USB_FLIGHTSIM) + #define VENDOR_ID 0x16C0 + #define PRODUCT_ID 0x0488 + #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'} + #define MANUFACTURER_NAME_LEN 11 + #define PRODUCT_NAME {'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'} + #define PRODUCT_NAME_LEN 26 + #define EP0_SIZE 64 + #define NUM_ENDPOINTS 4 + #define NUM_USB_BUFFERS 20 + #define NUM_INTERFACE 2 + #define FLIGHTSIM_INTERFACE 0 // Flight Sim Control + #define FLIGHTSIM_TX_ENDPOINT 3 + #define FLIGHTSIM_TX_SIZE 64 + #define FLIGHTSIM_TX_INTERVAL 1 + #define FLIGHTSIM_RX_ENDPOINT 4 + #define FLIGHTSIM_RX_SIZE 64 + #define FLIGHTSIM_RX_INTERVAL 1 + #define SEREMU_INTERFACE 1 // Serial emulation + #define SEREMU_TX_ENDPOINT 1 + #define SEREMU_TX_SIZE 64 + #define SEREMU_TX_INTERVAL 1 + #define SEREMU_RX_ENDPOINT 2 + #define SEREMU_RX_SIZE 32 + #define SEREMU_RX_INTERVAL 2 + #define FLIGHTSIM_DESC_OFFSET (9 + 9) + #define SEREMU_DESC_OFFSET (9 + 9+9+7+7 + 9) + #define CONFIG_DESC_SIZE (9 + 9+9+7+7 + 9+9+7+7) + #define ENDPOINT1_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY + #define ENDPOINT3_CONFIG ENDPOINT_TRANSIMIT_ONLY + #define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ONLY + +#endif + +// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15) +extern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS]; + +typedef struct { + uint16_t wValue; + uint16_t wIndex; + const uint8_t *addr; + uint16_t length; +} usb_descriptor_list_t; + +extern const usb_descriptor_list_t usb_descriptor_list[]; + + +#endif // F_CPU >= 20 MHz + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_dev.c b/src/openmv/src/micropython/ports/teensy/core/usb_dev.c new file mode 100755 index 0000000..6cf85d3 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_dev.c @@ -0,0 +1,980 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if F_CPU >= 20000000 + +#include "mk20dx128.h" +//#include "HardwareSerial.h" +#include "usb_dev.h" +#include "usb_mem.h" + +// buffer descriptor table + +typedef struct { + uint32_t desc; + void * addr; +} bdt_t; + +__attribute__ ((section(".usbdescriptortable"), used)) +static bdt_t table[(NUM_ENDPOINTS+1)*4]; + +static usb_packet_t *rx_first[NUM_ENDPOINTS]; +static usb_packet_t *rx_last[NUM_ENDPOINTS]; +static usb_packet_t *tx_first[NUM_ENDPOINTS]; +static usb_packet_t *tx_last[NUM_ENDPOINTS]; +uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; + +static uint8_t tx_state[NUM_ENDPOINTS]; +#define TX_STATE_BOTH_FREE_EVEN_FIRST 0 +#define TX_STATE_BOTH_FREE_ODD_FIRST 1 +#define TX_STATE_EVEN_FREE 2 +#define TX_STATE_ODD_FREE 3 +#define TX_STATE_NONE_FREE_EVEN_FIRST 4 +#define TX_STATE_NONE_FREE_ODD_FIRST 5 + +#define BDT_OWN 0x80 +#define BDT_DATA1 0x40 +#define BDT_DATA0 0x00 +#define BDT_DTS 0x08 +#define BDT_STALL 0x04 +#define BDT_PID(n) (((n) >> 2) & 15) + +#define BDT_DESC(count, data) (BDT_OWN | BDT_DTS \ + | ((data) ? BDT_DATA1 : BDT_DATA0) \ + | ((count) << 16)) + +#define TX 1 +#define RX 0 +#define ODD 1 +#define EVEN 0 +#define DATA0 0 +#define DATA1 1 +#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) +#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) + + +static union { + struct { + union { + struct { + uint8_t bmRequestType; + uint8_t bRequest; + }; + uint16_t wRequestAndType; + }; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + }; + struct { + uint32_t word1; + uint32_t word2; + }; +} setup; + + +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 12 + +// SETUP always uses a DATA0 PID for the data field of the SETUP transaction. +// transactions in the data phase start with DATA1 and toggle (figure 8-12, USB1.1) +// Status stage uses a DATA1 PID. + +static uint8_t ep0_rx0_buf[EP0_SIZE] __attribute__ ((aligned (4))); +static uint8_t ep0_rx1_buf[EP0_SIZE] __attribute__ ((aligned (4))); +static const uint8_t *ep0_tx_ptr = NULL; +static uint16_t ep0_tx_len; +static uint8_t ep0_tx_bdt_bank = 0; +static uint8_t ep0_tx_data_toggle = 0; +uint8_t usb_rx_memory_needed = 0; + +volatile uint8_t usb_configuration = 0; +volatile uint8_t usb_reboot_timer = 0; + + +static void endpoint0_stall(void) +{ + USB0_ENDPT0 = USB_ENDPT_EPSTALL | USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; +} + + +static void endpoint0_transmit(const void *data, uint32_t len) +{ +#if 0 + serial_print("tx0:"); + serial_phex32((uint32_t)data); + serial_print(","); + serial_phex16(len); + serial_print(ep0_tx_bdt_bank ? ", odd" : ", even"); + serial_print(ep0_tx_data_toggle ? ", d1\n" : ", d0\n"); +#endif + table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; + table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); + ep0_tx_data_toggle ^= 1; + ep0_tx_bdt_bank ^= 1; +} + +static uint8_t reply_buffer[8]; + +static void usb_setup(void) +{ + const uint8_t *data = NULL; + uint32_t datalen = 0; + const usb_descriptor_list_t *list; + uint32_t size; + volatile uint8_t *reg; + uint8_t epconf; + const uint8_t *cfg; + int i; + + switch (setup.wRequestAndType) { + case 0x0500: // SET_ADDRESS + break; + case 0x0900: // SET_CONFIGURATION + //serial_print("configure\n"); + usb_configuration = setup.wValue; + reg = &USB0_ENDPT1; + cfg = usb_endpoint_config_table; + // clear all BDT entries, free any allocated memory... + for (i=4; i < (NUM_ENDPOINTS+1)*4; i++) { + if (table[i].desc & BDT_OWN) { + usb_free((usb_packet_t *)((uint8_t *)(table[i].addr) - 8)); + } + } + // free all queued packets + for (i=0; i < NUM_ENDPOINTS; i++) { + usb_packet_t *p, *n; + p = rx_first[i]; + while (p) { + n = p->next; + usb_free(p); + p = n; + } + rx_first[i] = NULL; + rx_last[i] = NULL; + p = tx_first[i]; + while (p) { + n = p->next; + usb_free(p); + p = n; + } + tx_first[i] = NULL; + tx_last[i] = NULL; + usb_rx_byte_count_data[i] = 0; + switch (tx_state[i]) { + case TX_STATE_EVEN_FREE: + case TX_STATE_NONE_FREE_EVEN_FIRST: + tx_state[i] = TX_STATE_BOTH_FREE_EVEN_FIRST; + break; + case TX_STATE_ODD_FREE: + case TX_STATE_NONE_FREE_ODD_FIRST: + tx_state[i] = TX_STATE_BOTH_FREE_ODD_FIRST; + break; + default: + break; + } + } + usb_rx_memory_needed = 0; + for (i=1; i <= NUM_ENDPOINTS; i++) { + epconf = *cfg++; + *reg = epconf; + reg += 4; + if (epconf & USB_ENDPT_EPRXEN) { + usb_packet_t *p; + p = usb_malloc(); + if (p) { + table[index(i, RX, EVEN)].addr = p->buf; + table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); + } else { + table[index(i, RX, EVEN)].desc = 0; + usb_rx_memory_needed++; + } + p = usb_malloc(); + if (p) { + table[index(i, RX, ODD)].addr = p->buf; + table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); + } else { + table[index(i, RX, ODD)].desc = 0; + usb_rx_memory_needed++; + } + } + table[index(i, TX, EVEN)].desc = 0; + table[index(i, TX, ODD)].desc = 0; + } + break; + case 0x0880: // GET_CONFIGURATION + reply_buffer[0] = usb_configuration; + datalen = 1; + data = reply_buffer; + break; + case 0x0080: // GET_STATUS (device) + reply_buffer[0] = 0; + reply_buffer[1] = 0; + datalen = 2; + data = reply_buffer; + break; + case 0x0082: // GET_STATUS (endpoint) + if (setup.wIndex > NUM_ENDPOINTS) { + // TODO: do we need to handle IN vs OUT here? + endpoint0_stall(); + return; + } + reply_buffer[0] = 0; + reply_buffer[1] = 0; + if (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4) & 0x02) reply_buffer[0] = 1; + data = reply_buffer; + datalen = 2; + break; + case 0x0102: // CLEAR_FEATURE (endpoint) + i = setup.wIndex & 0x7F; + if (i > NUM_ENDPOINTS || setup.wValue != 0) { + // TODO: do we need to handle IN vs OUT here? + endpoint0_stall(); + return; + } + (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; + // TODO: do we need to clear the data toggle here? + break; + case 0x0302: // SET_FEATURE (endpoint) + i = setup.wIndex & 0x7F; + if (i > NUM_ENDPOINTS || setup.wValue != 0) { + // TODO: do we need to handle IN vs OUT here? + endpoint0_stall(); + return; + } + (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) |= 0x02; + // TODO: do we need to clear the data toggle here? + break; + case 0x0680: // GET_DESCRIPTOR + case 0x0681: + //serial_print("desc:"); + //serial_phex16(setup.wValue); + //serial_print("\n"); + for (list = usb_descriptor_list; 1; list++) { + if (list->addr == NULL) break; + //if (setup.wValue == list->wValue && + //(setup.wIndex == list->wIndex) || ((setup.wValue >> 8) == 3)) { + if (setup.wValue == list->wValue && setup.wIndex == list->wIndex) { + data = list->addr; + if ((setup.wValue >> 8) == 3) { + // for string descriptors, use the descriptor's + // length field, allowing runtime configured + // length. + datalen = *(list->addr); + } else { + datalen = list->length; + } +#if 0 + serial_print("Desc found, "); + serial_phex32((uint32_t)data); + serial_print(","); + serial_phex16(datalen); + serial_print(","); + serial_phex(data[0]); + serial_phex(data[1]); + serial_phex(data[2]); + serial_phex(data[3]); + serial_phex(data[4]); + serial_phex(data[5]); + serial_print("\n"); +#endif + goto send; + } + } + //serial_print("desc: not found\n"); + endpoint0_stall(); + return; +#if defined(CDC_STATUS_INTERFACE) + case 0x2221: // CDC_SET_CONTROL_LINE_STATE + usb_cdc_line_rtsdtr = setup.wValue; + //serial_print("set control line state\n"); + break; + case 0x2321: // CDC_SEND_BREAK + break; + case 0x2021: // CDC_SET_LINE_CODING + //serial_print("set coding, waiting...\n"); + return; +#endif + +// TODO: this does not work... why? +#if defined(SEREMU_INTERFACE) || defined(KEYBOARD_INTERFACE) + case 0x0921: // HID SET_REPORT + //serial_print(":)\n"); + return; + case 0x0A21: // HID SET_IDLE + break; + // case 0xC940: +#endif + default: + endpoint0_stall(); + return; + } + send: + //serial_print("setup send "); + //serial_phex32(data); + //serial_print(","); + //serial_phex16(datalen); + //serial_print("\n"); + + if (datalen > setup.wLength) datalen = setup.wLength; + size = datalen; + if (size > EP0_SIZE) size = EP0_SIZE; + endpoint0_transmit(data, size); + data += size; + datalen -= size; + if (datalen == 0 && size < EP0_SIZE) return; + + size = datalen; + if (size > EP0_SIZE) size = EP0_SIZE; + endpoint0_transmit(data, size); + data += size; + datalen -= size; + if (datalen == 0 && size < EP0_SIZE) return; + + ep0_tx_ptr = data; + ep0_tx_len = datalen; +} + + + +//A bulk endpoint's toggle sequence is initialized to DATA0 when the endpoint +//experiences any configuration event (configuration events are explained in +//Sections 9.1.1.5 and 9.4.5). + +//Configuring a device or changing an alternate setting causes all of the status +//and configuration values associated with endpoints in the affected interfaces +//to be set to their default values. This includes setting the data toggle of +//any endpoint using data toggles to the value DATA0. + +//For endpoints using data toggle, regardless of whether an endpoint has the +//Halt feature set, a ClearFeature(ENDPOINT_HALT) request always results in the +//data toggle being reinitialized to DATA0. + + + +// #define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) + +static void usb_control(uint32_t stat) +{ + bdt_t *b; + uint32_t pid, size; + uint8_t *buf; + const uint8_t *data; + + b = stat2bufferdescriptor(stat); + pid = BDT_PID(b->desc); + //count = b->desc >> 16; + buf = b->addr; + //serial_print("pid:"); + //serial_phex(pid); + //serial_print(", count:"); + //serial_phex(count); + //serial_print("\n"); + + switch (pid) { + case 0x0D: // Setup received from host + //serial_print("PID=Setup\n"); + //if (count != 8) ; // panic? + // grab the 8 byte setup info + setup.word1 = *(uint32_t *)(buf); + setup.word2 = *(uint32_t *)(buf + 4); + + // give the buffer back + b->desc = BDT_DESC(EP0_SIZE, DATA1); + //table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 1); + //table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 1); + + // clear any leftover pending IN transactions + ep0_tx_ptr = NULL; + if (ep0_tx_data_toggle) { + } + //if (table[index(0, TX, EVEN)].desc & 0x80) { + //serial_print("leftover tx even\n"); + //} + //if (table[index(0, TX, ODD)].desc & 0x80) { + //serial_print("leftover tx odd\n"); + //} + table[index(0, TX, EVEN)].desc = 0; + table[index(0, TX, ODD)].desc = 0; + // first IN after Setup is always DATA1 + ep0_tx_data_toggle = 1; + +#if 0 + serial_print("bmRequestType:"); + serial_phex(setup.bmRequestType); + serial_print(", bRequest:"); + serial_phex(setup.bRequest); + serial_print(", wValue:"); + serial_phex16(setup.wValue); + serial_print(", wIndex:"); + serial_phex16(setup.wIndex); + serial_print(", len:"); + serial_phex16(setup.wLength); + serial_print("\n"); +#endif + // actually "do" the setup request + usb_setup(); + // unfreeze the USB, now that we're ready + USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit + break; + case 0x01: // OUT transaction received from host + case 0x02: + //serial_print("PID=OUT\n"); +#ifdef CDC_STATUS_INTERFACE + if (setup.wRequestAndType == 0x2021 /*CDC_SET_LINE_CODING*/) { + int i; + uint8_t *dst = (uint8_t *)usb_cdc_line_coding; + //serial_print("set line coding "); + for (i=0; i<7; i++) { + //serial_phex(*buf); + *dst++ = *buf++; + } + //serial_phex32(usb_cdc_line_coding[0]); + //serial_print("\n"); + if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15; + endpoint0_transmit(NULL, 0); + } +#endif +#ifdef KEYBOARD_INTERFACE + if (setup.word1 == 0x02000921 && setup.word2 == ((1<<16)|KEYBOARD_INTERFACE)) { + keyboard_leds = buf[0]; + endpoint0_transmit(NULL, 0); + } +#endif +#ifdef SEREMU_INTERFACE + if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE) + && buf[0] == 0xA9 && buf[1] == 0x45 && buf[2] == 0xC2 && buf[3] == 0x6B) { + usb_reboot_timer = 5; + endpoint0_transmit(NULL, 0); + } +#endif + // give the buffer back + b->desc = BDT_DESC(EP0_SIZE, DATA1); + break; + + case 0x09: // IN transaction completed to host + //serial_print("PID=IN:"); + //serial_phex(stat); + //serial_print("\n"); + + // send remaining data, if any... + data = ep0_tx_ptr; + if (data) { + size = ep0_tx_len; + if (size > EP0_SIZE) size = EP0_SIZE; + endpoint0_transmit(data, size); + data += size; + ep0_tx_len -= size; + ep0_tx_ptr = (ep0_tx_len > 0 || size == EP0_SIZE) ? data : NULL; + } + + if (setup.bRequest == 5 && setup.bmRequestType == 0) { + setup.bRequest = 0; + //serial_print("set address: "); + //serial_phex16(setup.wValue); + //serial_print("\n"); + USB0_ADDR = setup.wValue; + } + + break; + //default: + //serial_print("PID=unknown:"); + //serial_phex(pid); + //serial_print("\n"); + } + USB0_CTL = USB_CTL_USBENSOFEN; // clear TXSUSPENDTOKENBUSY bit +} + + + + + + +usb_packet_t *usb_rx(uint32_t endpoint) +{ + usb_packet_t *ret; + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return NULL; + __disable_irq(); + ret = rx_first[endpoint]; + if (ret) { + rx_first[endpoint] = ret->next; + usb_rx_byte_count_data[endpoint] -= ret->len; + } + __enable_irq(); + //serial_print("rx, epidx="); + //serial_phex(endpoint); + //serial_print(", packet="); + //serial_phex32(ret); + //serial_print("\n"); + return ret; +} + +static uint32_t usb_queue_byte_count(const usb_packet_t *p) +{ + uint32_t count=0; + + __disable_irq(); + for ( ; p; p = p->next) { + count += p->len; + } + __enable_irq(); + return count; +} + +// TODO: make this an inline function... +/* +uint32_t usb_rx_byte_count(uint32_t endpoint) +{ + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return 0; + return usb_rx_byte_count_data[endpoint]; + //return usb_queue_byte_count(rx_first[endpoint]); +} +*/ + +uint32_t usb_tx_byte_count(uint32_t endpoint) +{ + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return 0; + return usb_queue_byte_count(tx_first[endpoint]); +} + +uint32_t usb_tx_packet_count(uint32_t endpoint) +{ + const usb_packet_t *p; + uint32_t count=0; + + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return 0; + __disable_irq(); + for (p = tx_first[endpoint]; p; p = p->next) count++; + __enable_irq(); + return count; +} + + +// Called from usb_free, but only when usb_rx_memory_needed > 0, indicating +// receive endpoints are starving for memory. The intention is to give +// endpoints needing receive memory priority over the user's code, which is +// likely calling usb_malloc to obtain memory for transmitting. When the +// user is creating data very quickly, their consumption could starve reception +// without this prioritization. The packet buffer (input) is assigned to the +// first endpoint needing memory. +// +void usb_rx_memory(usb_packet_t *packet) +{ + unsigned int i; + const uint8_t *cfg; + + cfg = usb_endpoint_config_table; + //serial_print("rx_mem:"); + __disable_irq(); + for (i=1; i <= NUM_ENDPOINTS; i++) { + if (*cfg++ & USB_ENDPT_EPRXEN) { + if (table[index(i, RX, EVEN)].desc == 0) { + table[index(i, RX, EVEN)].addr = packet->buf; + table[index(i, RX, EVEN)].desc = BDT_DESC(64, 0); + usb_rx_memory_needed--; + __enable_irq(); + //serial_phex(i); + //serial_print(",even\n"); + return; + } + if (table[index(i, RX, ODD)].desc == 0) { + table[index(i, RX, ODD)].addr = packet->buf; + table[index(i, RX, ODD)].desc = BDT_DESC(64, 1); + usb_rx_memory_needed--; + __enable_irq(); + //serial_phex(i); + //serial_print(",odd\n"); + return; + } + } + } + __enable_irq(); + // we should never reach this point. If we get here, it means + // usb_rx_memory_needed was set greater than zero, but no memory + // was actually needed. + usb_rx_memory_needed = 0; + usb_free(packet); + return; +} + +//#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) +//#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) + +void usb_tx(uint32_t endpoint, usb_packet_t *packet) +{ + bdt_t *b = &table[index(endpoint, TX, EVEN)]; + uint8_t next; + + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return; + __disable_irq(); + //serial_print("txstate="); + //serial_phex(tx_state[endpoint]); + //serial_print("\n"); + switch (tx_state[endpoint]) { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + next = TX_STATE_ODD_FREE; + break; + case TX_STATE_BOTH_FREE_ODD_FIRST: + b++; + next = TX_STATE_EVEN_FREE; + break; + case TX_STATE_EVEN_FREE: + next = TX_STATE_NONE_FREE_ODD_FIRST; + break; + case TX_STATE_ODD_FREE: + b++; + next = TX_STATE_NONE_FREE_EVEN_FIRST; + break; + default: + if (tx_first[endpoint] == NULL) { + tx_first[endpoint] = packet; + } else { + tx_last[endpoint]->next = packet; + } + tx_last[endpoint] = packet; + __enable_irq(); + return; + } + tx_state[endpoint] = next; + b->addr = packet->buf; + b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + __enable_irq(); +} + + + + + + +void _reboot_Teensyduino_(void) +{ + // TODO: initialize R0 with a code.... + __asm__ volatile("bkpt"); +} + + + +void usb_isr(void) +{ + uint8_t status, stat, t; + + //serial_print("isr"); + //status = USB0_ISTAT; + //serial_phex(status); + //serial_print("\n"); + restart: + status = USB0_ISTAT; + + if ((status & USB_INTEN_SOFTOKEN /* 04 */ )) { + if (usb_configuration) { + t = usb_reboot_timer; + if (t) { + usb_reboot_timer = --t; + if (!t) _reboot_Teensyduino_(); + } +#ifdef CDC_DATA_INTERFACE + t = usb_cdc_transmit_flush_timer; + if (t) { + usb_cdc_transmit_flush_timer = --t; + if (t == 0) usb_serial_flush_callback(); + } +#endif +#ifdef SEREMU_INTERFACE + t = usb_seremu_transmit_flush_timer; + if (t) { + usb_seremu_transmit_flush_timer = --t; + if (t == 0) usb_seremu_flush_callback(); + } +#endif +#ifdef MIDI_INTERFACE + usb_midi_flush_output(); +#endif +#ifdef FLIGHTSIM_INTERFACE + usb_flightsim_flush_callback(); +#endif + } + USB0_ISTAT = USB_INTEN_SOFTOKEN; + } + + if ((status & USB_ISTAT_TOKDNE /* 08 */ )) { + uint8_t endpoint; + stat = USB0_STAT; + //serial_print("token: ep="); + //serial_phex(stat >> 4); + //serial_print(stat & 0x08 ? ",tx" : ",rx"); + //serial_print(stat & 0x04 ? ",odd\n" : ",even\n"); + endpoint = stat >> 4; + if (endpoint == 0) { + usb_control(stat); + } else { + bdt_t *b = stat2bufferdescriptor(stat); + usb_packet_t *packet = (usb_packet_t *)((uint8_t *)(b->addr) - 8); +#if 0 + serial_print("ep:"); + serial_phex(endpoint); + serial_print(", pid:"); + serial_phex(BDT_PID(b->desc)); + serial_print(((uint32_t)b & 8) ? ", odd" : ", even"); + serial_print(", count:"); + serial_phex(b->desc >> 16); + serial_print("\n"); +#endif + endpoint--; // endpoint is index to zero-based arrays + + if (stat & 0x08) { // transmit + usb_free(packet); + packet = tx_first[endpoint]; + if (packet) { + //serial_print("tx packet\n"); + tx_first[endpoint] = packet->next; + b->addr = packet->buf; + switch (tx_state[endpoint]) { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + tx_state[endpoint] = TX_STATE_ODD_FREE; + break; + case TX_STATE_BOTH_FREE_ODD_FIRST: + tx_state[endpoint] = TX_STATE_EVEN_FREE; + break; + case TX_STATE_EVEN_FREE: + tx_state[endpoint] = TX_STATE_NONE_FREE_ODD_FIRST; + break; + case TX_STATE_ODD_FREE: + tx_state[endpoint] = TX_STATE_NONE_FREE_EVEN_FIRST; + break; + default: + break; + } + b->desc = BDT_DESC(packet->len, ((uint32_t)b & 8) ? DATA1 : DATA0); + } else { + //serial_print("tx no packet\n"); + switch (tx_state[endpoint]) { + case TX_STATE_BOTH_FREE_EVEN_FIRST: + case TX_STATE_BOTH_FREE_ODD_FIRST: + break; + case TX_STATE_EVEN_FREE: + tx_state[endpoint] = TX_STATE_BOTH_FREE_EVEN_FIRST; + break; + case TX_STATE_ODD_FREE: + tx_state[endpoint] = TX_STATE_BOTH_FREE_ODD_FIRST; + break; + default: + tx_state[endpoint] = ((uint32_t)b & 8) ? + TX_STATE_ODD_FREE : TX_STATE_EVEN_FREE; + break; + } + } + } else { // receive + packet->len = b->desc >> 16; + if (packet->len > 0) { + packet->index = 0; + packet->next = NULL; + if (rx_first[endpoint] == NULL) { + //serial_print("rx 1st, epidx="); + //serial_phex(endpoint); + //serial_print(", packet="); + //serial_phex32((uint32_t)packet); + //serial_print("\n"); + rx_first[endpoint] = packet; + } else { + //serial_print("rx Nth, epidx="); + //serial_phex(endpoint); + //serial_print(", packet="); + //serial_phex32((uint32_t)packet); + //serial_print("\n"); + rx_last[endpoint]->next = packet; + } + rx_last[endpoint] = packet; + usb_rx_byte_count_data[endpoint] += packet->len; + // TODO: implement a per-endpoint maximum # of allocated packets + // so a flood of incoming data on 1 endpoint doesn't starve + // the others if the user isn't reading it regularly + packet = usb_malloc(); + if (packet) { + b->addr = packet->buf; + b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); + } else { + //serial_print("starving "); + //serial_phex(endpoint + 1); + //serial_print(((uint32_t)b & 8) ? ",odd\n" : ",even\n"); + b->desc = 0; + usb_rx_memory_needed++; + } + } else { + b->desc = BDT_DESC(64, ((uint32_t)b & 8) ? DATA1 : DATA0); + } + } + + + + + } + USB0_ISTAT = USB_ISTAT_TOKDNE; + goto restart; + } + + + + if (status & USB_ISTAT_USBRST /* 01 */ ) { + //serial_print("reset\n"); + + // initialize BDT toggle bits + USB0_CTL = USB_CTL_ODDRST; + ep0_tx_bdt_bank = 0; + + // set up buffers to receive Setup and OUT packets + table[index(0, RX, EVEN)].desc = BDT_DESC(EP0_SIZE, 0); + table[index(0, RX, EVEN)].addr = ep0_rx0_buf; + table[index(0, RX, ODD)].desc = BDT_DESC(EP0_SIZE, 0); + table[index(0, RX, ODD)].addr = ep0_rx1_buf; + table[index(0, TX, EVEN)].desc = 0; + table[index(0, TX, ODD)].desc = 0; + + // activate endpoint 0 + USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; + + // clear all ending interrupts + USB0_ERRSTAT = 0xFF; + USB0_ISTAT = 0xFF; + + // set the address to zero during enumeration + USB0_ADDR = 0; + + // enable other interrupts + USB0_ERREN = 0xFF; + USB0_INTEN = USB_INTEN_TOKDNEEN | + USB_INTEN_SOFTOKEN | + USB_INTEN_STALLEN | + USB_INTEN_ERROREN | + USB_INTEN_USBRSTEN | + USB_INTEN_SLEEPEN; + + // is this necessary? + USB0_CTL = USB_CTL_USBENSOFEN; + return; + } + + + if ((status & USB_ISTAT_STALL /* 80 */ )) { + //serial_print("stall:\n"); + USB0_ENDPT0 = USB_ENDPT_EPRXEN | USB_ENDPT_EPTXEN | USB_ENDPT_EPHSHK; + USB0_ISTAT = USB_ISTAT_STALL; + } + if ((status & USB_ISTAT_ERROR /* 02 */ )) { + uint8_t err = USB0_ERRSTAT; + USB0_ERRSTAT = err; + //serial_print("err:"); + //serial_phex(err); + //serial_print("\n"); + USB0_ISTAT = USB_ISTAT_ERROR; + } + + if ((status & USB_ISTAT_SLEEP /* 10 */ )) { + //serial_print("sleep\n"); + USB0_ISTAT = USB_ISTAT_SLEEP; + } + +} + + + +void usb_init(void) +{ + int i; + + //serial_begin(BAUD2DIV(115200)); + //serial_print("usb_init\n"); + + usb_init_serialnumber(); + + for (i=0; i <= NUM_ENDPOINTS*4; i++) { + table[i].desc = 0; + table[i].addr = 0; + } + + // this basically follows the flowchart in the Kinetis + // Quick Reference User Guide, Rev. 1, 03/2012, page 141 + + // assume 48 MHz clock already running + // SIM - enable clock + SIM_SCGC4 |= SIM_SCGC4_USBOTG; + + // reset USB module + USB0_USBTRC0 = USB_USBTRC_USBRESET; + while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end + + // set desc table base addr + USB0_BDTPAGE1 = ((uint32_t)table) >> 8; + USB0_BDTPAGE2 = ((uint32_t)table) >> 16; + USB0_BDTPAGE3 = ((uint32_t)table) >> 24; + + // clear all ISR flags + USB0_ISTAT = 0xFF; + USB0_ERRSTAT = 0xFF; + USB0_OTGISTAT = 0xFF; + + USB0_USBTRC0 |= 0x40; // undocumented bit + + // enable USB + USB0_CTL = USB_CTL_USBENSOFEN; + USB0_USBCTRL = 0; + + // enable reset interrupt + USB0_INTEN = USB_INTEN_USBRSTEN; + + // enable interrupt in NVIC... + NVIC_SET_PRIORITY(IRQ_USBOTG, 112); + NVIC_ENABLE_IRQ(IRQ_USBOTG); + + // enable d+ pullup + USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG; +} + + +#else // F_CPU < 20 MHz + +void usb_init(void) +{ +} + +#endif // F_CPU >= 20 MHz diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_dev.h b/src/openmv/src/micropython/ports/teensy/core/usb_dev.h new file mode 100755 index 0000000..211cebe --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_dev.h @@ -0,0 +1,108 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _usb_dev_h_ +#define _usb_dev_h_ + +#if F_CPU >= 20000000 + +// This header is NOT meant to be included when compiling +// user sketches in Arduino. The low-level functions +// provided by usb_dev.c are meant to be called only by +// code which provides higher-level interfaces to the user. + +#include "usb_mem.h" +#include "usb_desc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void usb_init(void); +void usb_init_serialnumber(void); +void usb_isr(void); +usb_packet_t *usb_rx(uint32_t endpoint); +uint32_t usb_tx_byte_count(uint32_t endpoint); +uint32_t usb_tx_packet_count(uint32_t endpoint); +void usb_tx(uint32_t endpoint, usb_packet_t *packet); +void usb_tx_isr(uint32_t endpoint, usb_packet_t *packet); + +extern volatile uint8_t usb_configuration; + +extern uint16_t usb_rx_byte_count_data[NUM_ENDPOINTS]; +static inline uint32_t usb_rx_byte_count(uint32_t endpoint) __attribute__((always_inline)); +static inline uint32_t usb_rx_byte_count(uint32_t endpoint) +{ + endpoint--; + if (endpoint >= NUM_ENDPOINTS) return 0; + return usb_rx_byte_count_data[endpoint]; +} + +#ifdef CDC_DATA_INTERFACE +extern uint32_t usb_cdc_line_coding[2]; +extern volatile uint8_t usb_cdc_line_rtsdtr; +extern volatile uint8_t usb_cdc_transmit_flush_timer; +extern void usb_serial_flush_callback(void); +#endif + +#ifdef SEREMU_INTERFACE +extern volatile uint8_t usb_seremu_transmit_flush_timer; +extern void usb_seremu_flush_callback(void); +#endif + +#ifdef KEYBOARD_INTERFACE +extern uint8_t keyboard_modifier_keys; +extern uint8_t keyboard_keys[6]; +extern uint8_t keyboard_protocol; +extern uint8_t keyboard_idle_config; +extern uint8_t keyboard_idle_count; +extern volatile uint8_t keyboard_leds; +#endif + +#ifdef MIDI_INTERFACE +extern void usb_midi_flush_output(void); +#endif + +#ifdef FLIGHTSIM_INTERFACE +extern void usb_flightsim_flush_callback(void); +#endif + + + + + +#ifdef __cplusplus +} +#endif + + +#endif // F_CPU >= 20 MHz + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_mem.c b/src/openmv/src/micropython/ports/teensy/core/usb_mem.c new file mode 100755 index 0000000..2424327 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_mem.c @@ -0,0 +1,109 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if F_CPU >= 20000000 + +#include "mk20dx128.h" +//#include "HardwareSerial.h" +#include "usb_dev.h" +#include "usb_mem.h" + +__attribute__ ((section(".usbbuffers"), used)) +unsigned char usb_buffer_memory[NUM_USB_BUFFERS * sizeof(usb_packet_t)]; + +static uint32_t usb_buffer_available = 0xFFFFFFFF; + +// use bitmask and CLZ instruction to implement fast free list +// http://www.archivum.info/gnu.gcc.help/2006-08/00148/Re-GCC-Inline-Assembly.html +// http://gcc.gnu.org/ml/gcc/2012-06/msg00015.html +// __builtin_clz() + +usb_packet_t * usb_malloc(void) +{ + unsigned int n, avail; + uint8_t *p; + + __disable_irq(); + avail = usb_buffer_available; + n = __builtin_clz(avail); // clz = count leading zeros + if (n >= NUM_USB_BUFFERS) { + __enable_irq(); + return NULL; + } + //serial_print("malloc:"); + //serial_phex(n); + //serial_print("\n"); + + usb_buffer_available = avail & ~(0x80000000 >> n); + __enable_irq(); + p = usb_buffer_memory + (n * sizeof(usb_packet_t)); + //serial_print("malloc:"); + //serial_phex32((int)p); + //serial_print("\n"); + *(uint32_t *)p = 0; + *(uint32_t *)(p + 4) = 0; + return (usb_packet_t *)p; +} + +// for the receive endpoints to request memory +extern uint8_t usb_rx_memory_needed; +extern void usb_rx_memory(usb_packet_t *packet); + +void usb_free(usb_packet_t *p) +{ + unsigned int n, mask; + + //serial_print("free:"); + n = ((uint8_t *)p - usb_buffer_memory) / sizeof(usb_packet_t); + if (n >= NUM_USB_BUFFERS) return; + //serial_phex(n); + //serial_print("\n"); + + // if any endpoints are starving for memory to receive + // packets, give this memory to them immediately! + if (usb_rx_memory_needed && usb_configuration) { + //serial_print("give to rx:"); + //serial_phex32((int)p); + //serial_print("\n"); + usb_rx_memory(p); + return; + } + + mask = (0x80000000 >> n); + __disable_irq(); + usb_buffer_available |= mask; + __enable_irq(); + + //serial_print("free:"); + //serial_phex32((int)p); + //serial_print("\n"); +} + +#endif // F_CPU >= 20 MHz diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_mem.h b/src/openmv/src/micropython/ports/teensy/core/usb_mem.h new file mode 100755 index 0000000..94d1eb4 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_mem.h @@ -0,0 +1,55 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _usb_mem_h_ +#define _usb_mem_h_ + +#include + +typedef struct usb_packet_struct { + uint16_t len; + uint16_t index; + struct usb_packet_struct *next; + uint8_t buf[64]; +} usb_packet_t; + +#ifdef __cplusplus +extern "C" { +#endif + +usb_packet_t * usb_malloc(void); +void usb_free(usb_packet_t *p); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_names.h b/src/openmv/src/micropython/ports/teensy/core/usb_names.h new file mode 100755 index 0000000..067cb95 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_names.h @@ -0,0 +1,57 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _usb_names_h_ +#define _usb_names_h_ + +// These definitions are intended to allow users to override the default +// USB manufacturer, product and serial number strings. + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wString[]; +}; + +extern struct usb_string_descriptor_struct usb_string_manufacturer_name; +extern struct usb_string_descriptor_struct usb_string_product_name; +extern struct usb_string_descriptor_struct usb_string_serial_number; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_serial.c b/src/openmv/src/micropython/ports/teensy/core/usb_serial.c new file mode 100755 index 0000000..3b38ec8 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_serial.c @@ -0,0 +1,273 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "usb_dev.h" +#include "usb_serial.h" +#include "core_pins.h" // for yield() +//#include "HardwareSerial.h" +#include // for memcpy() + +// defined by usb_dev.h -> usb_desc.h +#if defined(CDC_STATUS_INTERFACE) && defined(CDC_DATA_INTERFACE) + +uint32_t usb_cdc_line_coding[2]; +volatile uint8_t usb_cdc_line_rtsdtr=0; +volatile uint8_t usb_cdc_transmit_flush_timer=0; + +static usb_packet_t *rx_packet=NULL; +static usb_packet_t *tx_packet=NULL; +static volatile uint8_t tx_noautoflush=0; + +#define TRANSMIT_FLUSH_TIMEOUT 5 /* in milliseconds */ + +// get the next character, or -1 if nothing received +int usb_serial_getchar(void) +{ + unsigned int i; + int c; + + if (!rx_packet) { + if (!usb_configuration) return -1; + rx_packet = usb_rx(CDC_RX_ENDPOINT); + if (!rx_packet) return -1; + } + i = rx_packet->index; + c = rx_packet->buf[i++]; + if (i >= rx_packet->len) { + usb_free(rx_packet); + rx_packet = NULL; + } else { + rx_packet->index = i; + } + return c; +} + +// peek at the next character, or -1 if nothing received +int usb_serial_peekchar(void) +{ + if (!rx_packet) { + if (!usb_configuration) return -1; + rx_packet = usb_rx(CDC_RX_ENDPOINT); + if (!rx_packet) return -1; + } + if (!rx_packet) return -1; + return rx_packet->buf[rx_packet->index]; +} + +// number of bytes available in the receive buffer +int usb_serial_available(void) +{ + int count; + count = usb_rx_byte_count(CDC_RX_ENDPOINT); + if (rx_packet) count += rx_packet->len - rx_packet->index; + return count; +} + +// read a block of bytes to a buffer +int usb_serial_read(void *buffer, uint32_t size) +{ + uint8_t *p = (uint8_t *)buffer; + uint32_t qty, count=0; + + while (size) { + if (!usb_configuration) break; + if (!rx_packet) { + rx: + rx_packet = usb_rx(CDC_RX_ENDPOINT); + if (!rx_packet) break; + if (rx_packet->len == 0) { + usb_free(rx_packet); + goto rx; + } + } + qty = rx_packet->len - rx_packet->index; + if (qty > size) qty = size; + memcpy(p, rx_packet->buf + rx_packet->index, qty); + p += qty; + count += qty; + size -= qty; + rx_packet->index += qty; + if (rx_packet->index >= rx_packet->len) { + usb_free(rx_packet); + rx_packet = NULL; + } + } + return count; +} + +// discard any buffered input +void usb_serial_flush_input(void) +{ + usb_packet_t *rx; + + if (!usb_configuration) return; + if (rx_packet) { + usb_free(rx_packet); + rx_packet = NULL; + } + while (1) { + rx = usb_rx(CDC_RX_ENDPOINT); + if (!rx) break; + usb_free(rx); + } +} + +// Maximum number of transmit packets to queue so we don't starve other endpoints for memory +#define TX_PACKET_LIMIT 8 + +// When the PC isn't listening, how long do we wait before discarding data? If this is +// too short, we risk losing data during the stalls that are common with ordinary desktop +// software. If it's too long, we stall the user's program when no software is running. +#define TX_TIMEOUT_MSEC 70 + +#if F_CPU == 168000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100) +#elif F_CPU == 144000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932) +#elif F_CPU == 120000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764) +#elif F_CPU == 96000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596) +#elif F_CPU == 72000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512) +#elif F_CPU == 48000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428) +#elif F_CPU == 24000000 + #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262) +#endif + +// When we've suffered the transmit timeout, don't wait again until the computer +// begins accepting data. If no software is running to receive, we'll just discard +// data as rapidly as Serial.print() can generate it, until there's something to +// actually receive it. +static uint8_t transmit_previous_timeout=0; + + +// transmit a character. 0 returned on success, -1 on error +int usb_serial_putchar(uint8_t c) +{ + return usb_serial_write(&c, 1); +} + + +int usb_serial_write(const void *buffer, uint32_t size) +{ + uint32_t len; + uint32_t wait_count; + const uint8_t *src = (const uint8_t *)buffer; + uint8_t *dest; + + tx_noautoflush = 1; + while (size > 0) { + if (!tx_packet) { + wait_count = 0; + while (1) { + if (!usb_configuration) { + tx_noautoflush = 0; + return -1; + } + if (usb_tx_packet_count(CDC_TX_ENDPOINT) < TX_PACKET_LIMIT) { + tx_noautoflush = 1; + tx_packet = usb_malloc(); + if (tx_packet) break; + tx_noautoflush = 0; + } + if (++wait_count > TX_TIMEOUT || transmit_previous_timeout) { + transmit_previous_timeout = 1; + return -1; + } + yield(); + } + } + transmit_previous_timeout = 0; + len = CDC_TX_SIZE - tx_packet->index; + if (len > size) len = size; + dest = tx_packet->buf + tx_packet->index; + tx_packet->index += len; + size -= len; + while (len-- > 0) *dest++ = *src++; + if (tx_packet->index >= CDC_TX_SIZE) { + tx_packet->len = CDC_TX_SIZE; + usb_tx(CDC_TX_ENDPOINT, tx_packet); + tx_packet = NULL; + } + usb_cdc_transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT; + } + tx_noautoflush = 0; + return 0; +} + +void usb_serial_flush_output(void) +{ + if (!usb_configuration) return; + tx_noautoflush = 1; + if (tx_packet) { + usb_cdc_transmit_flush_timer = 0; + tx_packet->len = tx_packet->index; + usb_tx(CDC_TX_ENDPOINT, tx_packet); + tx_packet = NULL; + } else { + usb_packet_t *tx = usb_malloc(); + if (tx) { + usb_cdc_transmit_flush_timer = 0; + usb_tx(CDC_TX_ENDPOINT, tx); + } else { + usb_cdc_transmit_flush_timer = 1; + } + } + tx_noautoflush = 0; +} + +void usb_serial_flush_callback(void) +{ + if (tx_noautoflush) return; + if (tx_packet) { + tx_packet->len = tx_packet->index; + usb_tx(CDC_TX_ENDPOINT, tx_packet); + tx_packet = NULL; + } else { + usb_packet_t *tx = usb_malloc(); + if (tx) { + usb_tx(CDC_TX_ENDPOINT, tx); + } else { + usb_cdc_transmit_flush_timer = 1; + } + } +} + + + + + + + + + +#endif // CDC_STATUS_INTERFACE && CDC_DATA_INTERFACE diff --git a/src/openmv/src/micropython/ports/teensy/core/usb_serial.h b/src/openmv/src/micropython/ports/teensy/core/usb_serial.h new file mode 100755 index 0000000..9c0429d --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/usb_serial.h @@ -0,0 +1,144 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef USBserial_h_ +#define USBserial_h_ + +#if defined(USB_SERIAL) || defined(USB_SERIAL_HID) + +#include + +#if F_CPU >= 20000000 + +// C language implementation +#ifdef __cplusplus +extern "C" { +#endif +int usb_serial_getchar(void); +int usb_serial_peekchar(void); +int usb_serial_available(void); +int usb_serial_read(void *buffer, uint32_t size); +void usb_serial_flush_input(void); +int usb_serial_putchar(uint8_t c); +int usb_serial_write(const void *buffer, uint32_t size); +void usb_serial_flush_output(void); +extern uint32_t usb_cdc_line_coding[2]; +extern volatile uint8_t usb_cdc_line_rtsdtr; +extern volatile uint8_t usb_cdc_transmit_flush_timer; +extern volatile uint8_t usb_configuration; +#ifdef __cplusplus +} +#endif + +#define USB_SERIAL_DTR 0x01 +#define USB_SERIAL_RTS 0x02 + +// C++ interface +#ifdef __cplusplus +#include "Stream.h" +class usb_serial_class : public Stream +{ +public: + void begin(long) { /* TODO: call a function that tries to wait for enumeration */ }; + void end() { /* TODO: flush output and shut down USB port */ }; + virtual int available() { return usb_serial_available(); } + virtual int read() { return usb_serial_getchar(); } + virtual int peek() { return usb_serial_peekchar(); } + virtual void flush() { usb_serial_flush_output(); } // TODO: actually wait for data to leave USB... + virtual size_t write(uint8_t c) { return usb_serial_putchar(c); } + virtual size_t write(const uint8_t *buffer, size_t size) { return usb_serial_write(buffer, size); } + size_t write(unsigned long n) { return write((uint8_t)n); } + size_t write(long n) { return write((uint8_t)n); } + size_t write(unsigned int n) { return write((uint8_t)n); } + size_t write(int n) { return write((uint8_t)n); } + using Print::write; + void send_now(void) { usb_serial_flush_output(); } + uint32_t baud(void) { return usb_cdc_line_coding[0]; } + uint8_t stopbits(void) { uint8_t b = usb_cdc_line_coding[1]; if (!b) b = 1; return b; } + uint8_t paritytype(void) { return usb_cdc_line_coding[1] >> 8; } // 0=none, 1=odd, 2=even + uint8_t numbits(void) { return usb_cdc_line_coding[1] >> 16; } + uint8_t dtr(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) ? 1 : 0; } + uint8_t rts(void) { return (usb_cdc_line_rtsdtr & USB_SERIAL_RTS) ? 1 : 0; } + operator bool() { return usb_configuration && (usb_cdc_line_rtsdtr & (USB_SERIAL_DTR | USB_SERIAL_RTS)); } + size_t readBytes(char *buffer, size_t length) { + size_t count=0; + unsigned long startMillis = millis(); + do { + count += usb_serial_read(buffer + count, length - count); + if (count >= length) return count; + } while(millis() - startMillis < _timeout); + setReadError(); + return count; + } + +}; +extern usb_serial_class Serial; +#endif // __cplusplus + + +#else // F_CPU < 20 MHz + +// Allow Arduino programs using Serial to compile, but Serial will do nothing. +#ifdef __cplusplus +#include "Stream.h" +class usb_serial_class : public Stream +{ +public: + void begin(long) { }; + void end() { }; + virtual int available() { return 0; } + virtual int read() { return -1; } + virtual int peek() { return -1; } + virtual void flush() { } + virtual size_t write(uint8_t c) { return 1; } + virtual size_t write(const uint8_t *buffer, size_t size) { return size; } + size_t write(unsigned long n) { return 1; } + size_t write(long n) { return 1; } + size_t write(unsigned int n) { return 1; } + size_t write(int n) { return 1; } + using Print::write; + void send_now(void) { } + uint32_t baud(void) { return 0; } + uint8_t stopbits(void) { return 1; } + uint8_t paritytype(void) { return 0; } + uint8_t numbits(void) { return 8; } + uint8_t dtr(void) { return 1; } + uint8_t rts(void) { return 1; } + operator bool() { return true; } +}; + +extern usb_serial_class Serial; +#endif // __cplusplus + +#endif // F_CPU + +#endif // USB_SERIAL || USB_SERIAL_HID + +#endif // USBserial_h_ diff --git a/src/openmv/src/micropython/ports/teensy/core/yield.c b/src/openmv/src/micropython/ports/teensy/core/yield.c new file mode 100755 index 0000000..06c741a --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/core/yield.c @@ -0,0 +1,32 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +void yield(void) __attribute__ ((weak)); +void yield(void) {}; diff --git a/src/openmv/src/micropython/ports/teensy/hal_ftm.c b/src/openmv/src/micropython/ports/teensy/hal_ftm.c new file mode 100755 index 0000000..3c031bf --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/hal_ftm.c @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "teensy_hal.h" + +void HAL_FTM_Base_Init(FTM_HandleTypeDef *hftm) { + /* Check the parameters */ + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + assert_param(IS_FTM_PRESCALERSHIFT(hftm->Init.PrescalerShift)); + assert_param(IS_FTM_COUNTERMODE(hftm->Init.CounterMode)); + assert_param(IS_FTM_PERIOD(hftm->Init.Period)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->MODE = FTM_MODE_WPDIS; + FTMx->SC = 0; + FTMx->MOD = hftm->Init.Period; + uint32_t sc = FTM_SC_PS(hftm->Init.PrescalerShift); + if (hftm->Init.CounterMode == FTM_COUNTERMODE_CENTER) { + sc |= FTM_SC_CPWMS; + } + FTMx->SC = sc; + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_Base_Start(FTM_HandleTypeDef *hftm) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->CNT = 0; + FTMx->SC &= ~FTM_SC_CLKS(3); + FTMx->SC |= FTM_SC_CLKS(1); + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_Base_Start_IT(FTM_HandleTypeDef *hftm) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->CNT = 0; + FTMx->SC |= FTM_SC_CLKS(1) | FTM_SC_TOIE; + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_Base_DeInit(FTM_HandleTypeDef *hftm) { + assert_param(IS_FTM_INSTANCE(hftm->Instance)); + + hftm->State = HAL_FTM_STATE_BUSY; + + __HAL_FTM_DISABLE_TOF_IT(hftm); + + hftm->State = HAL_FTM_STATE_RESET; +} + +void HAL_FTM_OC_Init(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_Init(hftm); +} + +void HAL_FTM_OC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + assert_param(IS_FTM_CHANNEL(channel)); + assert_param(IS_FTM_OC_MODE(sConfig->OCMode)); + assert_param(IS_FTM_OC_PULSE(sConfig->Pulse)); + assert_param(IS_FTM_OC_POLARITY(sConfig->OCPolarity)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->channel[channel].CSC = sConfig->OCMode; + FTMx->channel[channel].CV = sConfig->Pulse; + if (sConfig->OCPolarity & 1) { + FTMx->POL |= (1 << channel); + } else { + FTMx->POL &= ~(1 << channel); + } + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_OC_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { + // Nothing else to do +} + +void HAL_FTM_OC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + + FTMx->channel[channel].CSC |= FTM_CSC_CHIE; +} + +void HAL_FTM_OC_DeInit(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_DeInit(hftm); +} + +void HAL_FTM_PWM_Init(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_Init(hftm); +} + +void HAL_FTM_PWM_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + assert_param(IS_FTM_CHANNEL(channel)); + assert_param(IS_FTM_PWM_MODE(sConfig->OCMode)); + assert_param(IS_FTM_OC_PULSE(sConfig->Pulse)); + assert_param(IS_FTM_OC_POLARITY(sConfig->OCPolarity)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->channel[channel].CSC = sConfig->OCMode; + FTMx->channel[channel].CV = sConfig->Pulse; + if (sConfig->OCPolarity & 1) { + FTMx->POL |= (1 << channel); + } else { + FTMx->POL &= ~(1 << channel); + } + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_PWM_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { + // Nothing else to do +} + +void HAL_FTM_PWM_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + + FTMx->channel[channel].CSC |= FTM_CSC_CHIE; +} + +void HAL_FTM_PWM_DeInit(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_DeInit(hftm); +} + +void HAL_FTM_IC_Init(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_Init(hftm); +} + +void HAL_FTM_IC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_IC_InitTypeDef* sConfig, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + assert_param(IS_FTM_CHANNEL(channel)); + assert_param(IS_FTM_IC_POLARITY(sConfig->ICPolarity)); + + hftm->State = HAL_FTM_STATE_BUSY; + + FTMx->channel[channel].CSC = sConfig->ICPolarity; + + hftm->State = HAL_FTM_STATE_READY; +} + +void HAL_FTM_IC_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { + //FTM_TypeDef *FTMx = hftm->Instance; + //assert_param(IS_FTM_INSTANCE(FTMx)); + + // Nothing else to do +} + +void HAL_FTM_IC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { + FTM_TypeDef *FTMx = hftm->Instance; + assert_param(IS_FTM_INSTANCE(FTMx)); + + FTMx->channel[channel].CSC |= FTM_CSC_CHIE; +} + +void HAL_FTM_IC_DeInit(FTM_HandleTypeDef *hftm) { + HAL_FTM_Base_DeInit(hftm); +} diff --git a/src/openmv/src/micropython/ports/teensy/hal_ftm.h b/src/openmv/src/micropython/ports/teensy/hal_ftm.h new file mode 100755 index 0000000..84fae83 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/hal_ftm.h @@ -0,0 +1,186 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_TEENSY_HAL_FTM_H +#define MICROPY_INCLUDED_TEENSY_HAL_FTM_H + +#define FTM0 ((FTM_TypeDef *)&FTM0_SC) +#define FTM1 ((FTM_TypeDef *)&FTM1_SC) +#define FTM2 ((FTM_TypeDef *)&FTM2_SC) + +typedef struct { + volatile uint32_t CSC; // Channel x Status And Control + volatile uint32_t CV; // Channel x Value +} FTM_ChannelTypeDef; + +typedef struct { + volatile uint32_t SC; // Status And Control + volatile uint32_t CNT; // Counter + volatile uint32_t MOD; // Modulo + FTM_ChannelTypeDef channel[8]; + volatile uint32_t CNTIN; // Counter Initial Value + volatile uint32_t STATUS; // Capture And Compare Status + volatile uint32_t MODE; // Features Mode Selection + volatile uint32_t SYNC; // Synchronization + volatile uint32_t OUTINIT; // Initial State For Channels Output + volatile uint32_t OUTMASK; // Output Mask + volatile uint32_t COMBINE; // Function For Linked Channels + volatile uint32_t DEADTIME; // Deadtime Insertion Control + volatile uint32_t EXTTRIG; // FTM External Trigger + volatile uint32_t POL; // Channels Polarity + volatile uint32_t FMS; // Fault Mode Status + volatile uint32_t FILTER; // Input Capture Filter Control + volatile uint32_t FLTCTRL; // Fault Control + volatile uint32_t QDCTRL; // Quadrature Decoder Control And Status + volatile uint32_t CONF; // Configuration + volatile uint32_t FLTPOL; // FTM Fault Input Polarity + volatile uint32_t SYNCONF; // Synchronization Configuration + volatile uint32_t INVCTRL; // FTM Inverting Control + volatile uint32_t SWOCTRL; // FTM Software Output Control + volatile uint32_t PWMLOAD; // FTM PWM Load +} FTM_TypeDef; + +typedef struct { + uint32_t PrescalerShift; // Sets the prescaler to 1 << PrescalerShift + uint32_t CounterMode; // One of FTM_COUNTERMODE_xxx + uint32_t Period; // Specifies the Period for determining timer overflow +} FTM_Base_InitTypeDef; + +typedef struct { + uint32_t OCMode; // One of FTM_OCMODE_xxx + uint32_t Pulse; // Specifies initial pulse width (0-0xffff) + uint32_t OCPolarity; // One of FTM_OCPOLRITY_xxx +} FTM_OC_InitTypeDef; + +typedef struct { + uint32_t ICPolarity; // Specifies Rising/Falling/Both +} FTM_IC_InitTypeDef; + +#define IS_FTM_INSTANCE(INSTANCE) (((INSTANCE) == FTM0) || \ + ((INSTANCE) == FTM1) || \ + ((INSTANCE) == FTM2)) + +#define IS_FTM_PRESCALERSHIFT(PRESCALERSHIFT) (((PRESCALERSHIFT) & ~7) == 0) + +#define FTM_COUNTERMODE_UP (0) +#define FTM_COUNTERMODE_CENTER (FTM_SC_CPWMS) + +#define IS_FTM_COUNTERMODE(MODE) (((MODE) == FTM_COUNTERMODE_UP) ||\ + ((MODE) == FTM_COUNTERMODE_CENTER)) + +#define IS_FTM_PERIOD(PERIOD) (((PERIOD) & 0xFFFF0000) == 0) + +#define FTM_CSC_CHF 0x80 +#define FTM_CSC_CHIE 0x40 +#define FTM_CSC_MSB 0x20 +#define FTM_CSC_MSA 0x10 +#define FTM_CSC_ELSB 0x08 +#define FTM_CSC_ELSA 0x04 +#define FTM_CSC_DMA 0x01 + +#define FTM_OCMODE_TIMING (0) +#define FTM_OCMODE_ACTIVE (FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA) +#define FTM_OCMODE_INACTIVE (FTM_CSC_MSA | FTM_CSC_ELSB) +#define FTM_OCMODE_TOGGLE (FTM_CSC_MSA | FTM_CSC_ELSA) +#define FTM_OCMODE_PWM1 (FTM_CSC_MSB | FTM_CSC_ELSB) +#define FTM_OCMODE_PWM2 (FTM_CSC_MSB | FTM_CSC_ELSA) + +#define IS_FTM_OC_MODE(mode) ((mode) == FTM_OCMODE_TIMING || \ + (mode) == FTM_OCMODE_ACTIVE || \ + (mode) == FTM_OCMODE_INACTIVE || \ + (mode) == FTM_OCMODE_TOGGLE ) + +#define IS_FTM_PWM_MODE(mode) ((mode) == FTM_OCMODE_PWM1 || \ + (mode) == FTM_OCMODE_PWM2) + +#define IS_FTM_CHANNEL(channel) (((channel) & ~7) == 0) + +#define IS_FTM_PULSE(pulse) (((pulse) & ~0xffff) == 0) + +#define FTM_OCPOLARITY_HIGH (0) +#define FTM_OCPOLARITY_LOW (1) + +#define IS_FTM_OC_POLARITY(polarity) ((polarity) == FTM_OCPOLARITY_HIGH || \ + (polarity) == FTM_OCPOLARITY_LOW) + +#define FTM_ICPOLARITY_RISING (FTM_CSC_ELSA) +#define FTM_ICPOLARITY_FALLING (FTM_CSC_ELSB) +#define FTM_ICPOLARITY_BOTH (FTM_CSC_ELSA | FTM_CSC_ELSB) + +#define IS_FTM_IC_POLARITY(polarity) ((polarity) == FTM_ICPOLARITY_RISING || \ + (polarity) == FTM_ICPOLARITY_FALLING || \ + (polarity) == FTM_ICPOLARITY_BOTH) + +typedef enum { + HAL_FTM_STATE_RESET = 0x00, + HAL_FTM_STATE_READY = 0x01, + HAL_FTM_STATE_BUSY = 0x02, +} HAL_FTM_State; + +typedef struct { + FTM_TypeDef *Instance; + FTM_Base_InitTypeDef Init; + HAL_FTM_State State; + +} FTM_HandleTypeDef; + +#define __HAL_FTM_GET_TOF_FLAG(HANDLE) (((HANDLE)->Instance->SC & FTM_SC_TOF) != 0) +#define __HAL_FTM_CLEAR_TOF_FLAG(HANDLE) ((HANDLE)->Instance->SC &= ~FTM_SC_TOF) + +#define __HAL_FTM_GET_TOF_IT(HANDLE) (((HANDLE)->Instance->SC & FTM_SC_TOIE) != 0) +#define __HAL_FTM_ENABLE_TOF_IT(HANDLE) ((HANDLE)->Instance->SC |= FTM_SC_TOIE) +#define __HAL_FTM_DISABLE_TOF_IT(HANDLE) ((HANDLE)->Instance->SC &= ~FTM_SC_TOIE) + +#define __HAL_FTM_GET_CH_FLAG(HANDLE, CH) (((HANDLE)->Instance->channel[CH].CSC & FTM_CSC_CHF) != 0) +#define __HAL_FTM_CLEAR_CH_FLAG(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC &= ~FTM_CSC_CHF) + +#define __HAL_FTM_GET_CH_IT(HANDLE, CH) (((HANDLE)->Instance->channel[CH].CSC & FTM_CSC_CHIE) != 0) +#define __HAL_FTM_ENABLE_CH_IT(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC |= FTM_CSC_CHIE) +#define __HAL_FTM_DISABLE_CH_IT(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC &= ~FTM_CSC_CHIE) + +void HAL_FTM_Base_Init(FTM_HandleTypeDef *hftm); +void HAL_FTM_Base_Start(FTM_HandleTypeDef *hftm); +void HAL_FTM_Base_Start_IT(FTM_HandleTypeDef *hftm); +void HAL_FTM_Base_DeInit(FTM_HandleTypeDef *hftm); + +void HAL_FTM_OC_Init(FTM_HandleTypeDef *hftm); +void HAL_FTM_OC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel); +void HAL_FTM_OC_Start(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_OC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_OC_DeInit(FTM_HandleTypeDef *hftm); + +void HAL_FTM_PWM_Init(FTM_HandleTypeDef *hftm); +void HAL_FTM_PWM_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel); +void HAL_FTM_PWM_Start(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_PWM_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_PWM_DeInit(FTM_HandleTypeDef *hftm); + +void HAL_FTM_IC_Init(FTM_HandleTypeDef *hftm); +void HAL_FTM_IC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_IC_InitTypeDef* sConfig, uint32_t channel); +void HAL_FTM_IC_Start(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_IC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); +void HAL_FTM_IC_DeInit(FTM_HandleTypeDef *hftm); + +#endif // MICROPY_INCLUDED_TEENSY_HAL_FTM_H diff --git a/src/openmv/src/micropython/ports/teensy/hal_gpio.c b/src/openmv/src/micropython/ports/teensy/hal_gpio.c new file mode 100755 index 0000000..f9e1376 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/hal_gpio.c @@ -0,0 +1,123 @@ +#include +#include +#include "teensy_hal.h" + +#define GPIO_NUMBER 32 + +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Init->Pin)); + assert_param(IS_GPIO_MODE(GPIO_Init->Mode)); + assert_param(IS_GPIO_PULL(GPIO_Init->Pull)); + + /* Configure the port pins */ + for (uint32_t position = 0; position < GPIO_NUMBER; position++) { + uint32_t bitmask = 1 << position; + if ((GPIO_Init->Pin & bitmask) == 0) { + continue; + } + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(GPIOx, position); + + /*--------------------- GPIO Mode Configuration ------------------------*/ + /* In case of Alternate function mode selection */ + if ((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) { + /* Check the Alternate function parameter */ + assert_param(IS_GPIO_AF(GPIO_Init->Alternate)); + } + else if (GPIO_Init->Mode == GPIO_MODE_ANALOG) { + GPIO_Init->Alternate = 0; + } + else { + GPIO_Init->Alternate = 1; + } + + /* Configure Alternate function mapped with the current IO */ + *port_pcr &= ~PORT_PCR_MUX_MASK; + *port_pcr |= PORT_PCR_MUX(GPIO_Init->Alternate); + + /* Configure IO Direction mode (Input, Output, Alternate or Analog) */ + if (GPIO_Init->Mode == GPIO_MODE_INPUT || GPIO_Init->Mode == GPIO_MODE_ANALOG) { + GPIOx->PDDR &= ~bitmask; + } else { + GPIOx->PDDR |= bitmask; + } + + /* In case of Output or Alternate function mode selection */ + if ((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + (GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) { + /* Check the Speed parameter */ + assert_param(IS_GPIO_SPEED(GPIO_Init->Speed)); + + *port_pcr |= PORT_PCR_DSE; + + /* Configure the IO Speed */ + if (GPIO_Init->Speed > GPIO_SPEED_FREQ_MEDIUM) { + *port_pcr &= ~PORT_PCR_SRE; + } else { + *port_pcr |= PORT_PCR_SRE; + } + + /* Configure the IO Output Type */ + if (GPIO_Init->Mode & GPIO_OUTPUT_TYPE) { + *port_pcr |= PORT_PCR_ODE; // OD + } else { + *port_pcr &= ~PORT_PCR_ODE; // PP + } + } else { + *port_pcr &= ~PORT_PCR_DSE; + } + + /* Activate the Pull-up or Pull down resistor for the current IO */ + if (GPIO_Init->Pull == GPIO_NOPULL) { + *port_pcr &= ~PORT_PCR_PE; + } else { + *port_pcr |= PORT_PCR_PE; + if (GPIO_Init->Pull == GPIO_PULLDOWN) { + *port_pcr &= ~PORT_PCR_PS; + } else { + *port_pcr |= PORT_PCR_PS; + } + } + +#if 0 + /*--------------------- EXTI Mode Configuration ------------------------*/ + /* Configure the External Interrupt or event for the current IO */ + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + { + /* Enable SYSCFG Clock */ + __SYSCFG_CLK_ENABLE(); + + temp = ((uint32_t)0x0F) << (4 * (position & 0x03)); + SYSCFG->EXTICR[position >> 2] &= ~temp; + SYSCFG->EXTICR[position >> 2] |= ((uint32_t)(__HAL_GET_GPIO_SOURCE(GPIOx)) << (4 * (position & 0x03))); + + /* Clear EXTI line configuration */ + EXTI->IMR &= ~((uint32_t)iocurrent); + EXTI->EMR &= ~((uint32_t)iocurrent); + + if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT) + { + EXTI->IMR |= iocurrent; + } + if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT) + { + EXTI->EMR |= iocurrent; + } + + /* Clear Rising Falling edge configuration */ + EXTI->RTSR &= ~((uint32_t)iocurrent); + EXTI->FTSR &= ~((uint32_t)iocurrent); + + if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE) + { + EXTI->RTSR |= iocurrent; + } + if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE) + { + EXTI->FTSR |= iocurrent; + } + } +#endif + } +} diff --git a/src/openmv/src/micropython/ports/teensy/help.c b/src/openmv/src/micropython/ports/teensy/help.c new file mode 100755 index 0000000..a2370c0 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/help.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char teensy_help_text[] = +"Welcome to MicroPython!\n" +"\n" +"For online help please visit http://micropython.org/help/.\n" +"\n" +"Quick overview of commands for the board:\n" +" pyb.info() -- print some general information\n" +" pyb.gc() -- run the garbage collector\n" +" pyb.delay(n) -- wait for n milliseconds\n" +" pyb.Switch() -- create a switch object\n" +" Switch methods: (), callback(f)\n" +" pyb.LED(n) -- create an LED object for LED n (n=1,2,3,4)\n" +" LED methods: on(), off(), toggle(), intensity()\n" +" pyb.Pin(pin) -- get a pin, eg pyb.Pin('X1')\n" +" pyb.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n" +" Pin methods: init(..), value([v]), high(), low()\n" +" pyb.ExtInt(pin, m, p, callback) -- create an external interrupt object\n" +" pyb.ADC(pin) -- make an analog object from a pin\n" +" ADC methods: read(), read_timed(buf, freq)\n" +" pyb.DAC(port) -- make a DAC object\n" +" DAC methods: triangle(freq), write(n), write_timed(buf, freq)\n" +" pyb.RTC() -- make an RTC object; methods: datetime([val])\n" +" pyb.rng() -- get a 30-bit hardware random number\n" +" pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4)\n" +" Servo methods: calibration(..), angle([x, [t]]), speed([x, [t]])\n" +" pyb.Accel() -- create an Accelerometer object\n" +" Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz()\n" +"\n" +"Pins are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name\n" +"Pin IO modes are: pyb.Pin.IN, pyb.Pin.OUT_PP, pyb.Pin.OUT_OD\n" +"Pin pull modes are: pyb.Pin.PULL_NONE, pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN\n" +"Additional serial bus objects: pyb.I2C(n), pyb.SPI(n), pyb.UART(n)\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; diff --git a/src/openmv/src/micropython/ports/teensy/lcd.c b/src/openmv/src/micropython/ports/teensy/lcd.c new file mode 100755 index 0000000..e5d6115 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/lcd.c @@ -0,0 +1,14 @@ +#include "py/obj.h" +#include "../stm32/lcd.h" + +void lcd_init(void) { +} + +void lcd_print_str(const char *str) { + (void)str; +} + +void lcd_print_strn(const char *str, unsigned int len) { + (void)str; + (void)len; +} diff --git a/src/openmv/src/micropython/ports/teensy/led.c b/src/openmv/src/micropython/ports/teensy/led.c new file mode 100755 index 0000000..cf59dbd --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/led.c @@ -0,0 +1,143 @@ +#include + +#include "Arduino.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "led.h" +#include "pin.h" +#include "genhdr/pins.h" + +typedef struct _pyb_led_obj_t { + mp_obj_base_t base; + mp_uint_t led_id; + const pin_obj_t *led_pin; +} pyb_led_obj_t; + +STATIC const pyb_led_obj_t pyb_led_obj[] = { + {{&pyb_led_type}, 1, &MICROPY_HW_LED1}, +#if defined(MICROPY_HW_LED2) + {{&pyb_led_type}, 2, &MICROPY_HW_LED2}, +#if defined(MICROPY_HW_LED3) + {{&pyb_led_type}, 3, &MICROPY_HW_LED3}, +#if defined(MICROPY_HW_LED4) + {{&pyb_led_type}, 4, &MICROPY_HW_LED4}, +#endif +#endif +#endif +}; +#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) + +void led_init(void) { + /* GPIO structure */ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Configure I/O speed, mode, output type and pull */ + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; + GPIO_InitStructure.Pull = GPIO_NOPULL; + + /* Turn off LEDs and initialize */ + for (int led = 0; led < NUM_LEDS; led++) { + const pin_obj_t *led_pin = pyb_led_obj[led].led_pin; + MICROPY_HW_LED_OFF(led_pin); + GPIO_InitStructure.Pin = led_pin->pin_mask; + HAL_GPIO_Init(led_pin->gpio, &GPIO_InitStructure); + } +} + +void led_state(pyb_led_t led, int state) { + if (led < 1 || led > NUM_LEDS) { + return; + } + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + //printf("led_state(%d,%d)\n", led, state); + if (state == 0) { + // turn LED off + MICROPY_HW_LED_OFF(led_pin); + } else { + // turn LED on + MICROPY_HW_LED_ON(led_pin); + } +} + +void led_toggle(pyb_led_t led) { + if (led < 1 || led > NUM_LEDS) { + return; + } + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + GPIO_TypeDef *gpio = led_pin->gpio; + + // We don't know if we're turning the LED on or off, but we don't really + // care. Just invert the state. + if (gpio->PDOR & led_pin->pin_mask) { + // pin is high, make it low + gpio->PCOR = led_pin->pin_mask; + } else { + // pin is low, make it high + gpio->PSOR = led_pin->pin_mask; + } +} + +/******************************************************************************/ +/* MicroPython bindings */ + +void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_led_obj_t *self = self_in; + (void)kind; + mp_printf(print, "", self->led_id); +} + +STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get led number + mp_int_t led_id = mp_obj_get_int(args[0]); + + // check led number + if (!(1 <= led_id && led_id <= NUM_LEDS)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED %d does not exist", led_id)); + } + + // return static led object + return (mp_obj_t)&pyb_led_obj[led_id - 1]; +} + +mp_obj_t led_obj_on(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(self->led_id, 1); + return mp_const_none; +} + +mp_obj_t led_obj_off(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_state(self->led_id, 0); + return mp_const_none; +} + +mp_obj_t led_obj_toggle(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_toggle(self->led_id); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle); + +STATIC const mp_rom_map_elem_t led_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table); + +const mp_obj_type_t pyb_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = led_obj_print, + .make_new = led_obj_make_new, + .locals_dict = (mp_obj_t)&led_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/teensy/led.h b/src/openmv/src/micropython/ports/teensy/led.h new file mode 100755 index 0000000..5c45166 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/led.h @@ -0,0 +1,14 @@ +#ifndef MICROPY_INCLUDED_TEENSY_LED_H +#define MICROPY_INCLUDED_TEENSY_LED_H + +typedef enum { + PYB_LED_BUILTIN = 1, +} pyb_led_t; + +void led_init(void); +void led_state(pyb_led_t led, int state); +void led_toggle(pyb_led_t led); + +extern const mp_obj_type_t pyb_led_type; + +#endif // MICROPY_INCLUDED_TEENSY_LED_H diff --git a/src/openmv/src/micropython/ports/teensy/lexerfrozen.c b/src/openmv/src/micropython/ports/teensy/lexerfrozen.c new file mode 100755 index 0000000..21e978d --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/lexerfrozen.c @@ -0,0 +1,13 @@ +#include + +#include "py/lexer.h" +#include "py/runtime.h" +#include "py/mperrno.h" + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(MP_ENOENT); +} diff --git a/src/openmv/src/micropython/ports/teensy/lexermemzip.h b/src/openmv/src/micropython/ports/teensy/lexermemzip.h new file mode 100755 index 0000000..cd7326a --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/lexermemzip.h @@ -0,0 +1,6 @@ +#ifndef MICROPY_INCLUDED_TEENSY_LEXERMEMZIP_H +#define MICROPY_INCLUDED_TEENSY_LEXERMEMZIP_H + +mp_lexer_t *mp_lexer_new_from_memzip_file(const char *filename); + +#endif // MICROPY_INCLUDED_TEENSY_LEXERMEMZIP_H diff --git a/src/openmv/src/micropython/ports/teensy/main.c b/src/openmv/src/micropython/ports/teensy/main.c new file mode 100755 index 0000000..3edaa28 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/main.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include + +#include "py/lexer.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "gccollect.h" +#include "lib/utils/pyexec.h" +#include "lib/mp-readline/readline.h" +#include "lexermemzip.h" + +#include "Arduino.h" + +#include "servo.h" +#include "led.h" +#include "uart.h" +#include "pin.h" + +extern uint32_t _heap_start; + +void flash_error(int n) { + for (int i = 0; i < n; i++) { + led_state(PYB_LED_BUILTIN, 1); + delay(250); + led_state(PYB_LED_BUILTIN, 0); + delay(250); + } +} + +void NORETURN __fatal_error(const char *msg) { + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + led_state(1, 1); + led_state(2, 1); + led_state(3, 1); + led_state(4, 1); + mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14); + mp_hal_stdout_tx_strn(msg, strlen(msg)); + for (uint i = 0;;) { + led_toggle(((i++) & 3) + 1); + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + if (i >= 16) { + // to conserve power + __WFI(); + } + } +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + __fatal_error(""); +} + +void __assert_func(const char *file, int line, const char *func, const char *expr) { + + printf("Assertion failed: %s, file %s, line %d\n", expr, file, line); + __fatal_error(""); +} + +mp_obj_t pyb_analog_read(mp_obj_t pin_obj) { + uint pin = mp_obj_get_int(pin_obj); + int val = analogRead(pin); + return MP_OBJ_NEW_SMALL_INT(val); +} + +mp_obj_t pyb_analog_write(mp_obj_t pin_obj, mp_obj_t val_obj) { + uint pin = mp_obj_get_int(pin_obj); + int val = mp_obj_get_int(val_obj); + analogWrite(pin, val); + return mp_const_none; +} + +mp_obj_t pyb_analog_write_resolution(mp_obj_t res_obj) { + int res = mp_obj_get_int(res_obj); + analogWriteResolution(res); + return mp_const_none; +} + +mp_obj_t pyb_analog_write_frequency(mp_obj_t pin_obj, mp_obj_t freq_obj) { + uint pin = mp_obj_get_int(pin_obj); + int freq = mp_obj_get_int(freq_obj); + analogWriteFrequency(pin, freq); + return mp_const_none; +} + +#if 0 +// get lots of info about the board +static mp_obj_t pyb_info(void) { + // get and print unique id; 96 bits + { + byte *id = (byte*)0x40048058; + printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]); + } + + // get and print clock speeds + printf("CPU=%u\nBUS=%u\nMEM=%u\n", F_CPU, F_BUS, F_MEM); + + // to print info about memory + { + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_etext=%p\n", &_etext); + printf("_heap_start=%p\n", &_heap_start); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" %u total\n", info.total); + printf(" %u used %u free\n", info.used, info.free); + printf(" 1=%u 2=%u m=%u\n", info.num_1block, info.num_2block, info.max_block); + } + +#if 0 + // free space on flash + { + DWORD nclst; + FATFS *fatfs; + f_getfree("0:", &nclst, &fatfs); + printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512)); + } +#endif + + return mp_const_none; +} + +#endif + +#define RAM_START (0x1FFF8000) // fixed for chip +#define HEAP_END (0x20006000) // tunable +#define RAM_END (0x20008000) // fixed for chip + +#if 0 + +void gc_helper_get_regs_and_clean_stack(mp_uint_t *regs, mp_uint_t heap_end); + +mp_obj_t pyb_gc(void) { + gc_collect(); + return mp_const_none; +} + +mp_obj_t pyb_gpio(int n_args, mp_obj_t *args) { + //assert(1 <= n_args && n_args <= 2); + + uint pin = mp_obj_get_int(args[0]); + if (pin > CORE_NUM_DIGITAL) { + goto pin_error; + } + + if (n_args == 1) { + // get pin + pinMode(pin, INPUT); + return MP_OBJ_NEW_SMALL_INT(digitalRead(pin)); + } + + // set pin + pinMode(pin, OUTPUT); + digitalWrite(pin, mp_obj_is_true(args[1])); + return mp_const_none; + +pin_error: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %d does not exist", pin)); +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio); + +#if 0 +mp_obj_t pyb_hid_send_report(mp_obj_t arg) { + mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4); + uint8_t data[4]; + data[0] = mp_obj_get_int(items[0]); + data[1] = mp_obj_get_int(items[1]); + data[2] = mp_obj_get_int(items[2]); + data[3] = mp_obj_get_int(items[3]); + usb_hid_send_report(data); + return mp_const_none; +} +#endif + +#endif // 0 + +STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL; +STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL; +STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL; + +mp_obj_t pyb_source_dir(mp_obj_t source_dir) { + if (MP_OBJ_IS_STR(source_dir)) { + pyb_config_source_dir = source_dir; + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_source_dir_obj, pyb_source_dir); + +mp_obj_t pyb_main(mp_obj_t main) { + if (MP_OBJ_IS_STR(main)) { + pyb_config_main = main; + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main); + +STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) { + if (MP_OBJ_IS_STR(usb_mode)) { + pyb_config_usb_mode = usb_mode; + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_mode_obj, pyb_usb_mode); + +#if 0 + +mp_obj_t pyb_delay(mp_obj_t count) { + delay(mp_obj_get_int(count)); + return mp_const_none; +} + +mp_obj_t pyb_led(mp_obj_t state) { + led_state(PYB_LED_BUILTIN, mp_obj_is_true(state)); + return state; +} + +#endif // 0 + +#if 0 +char *strdup(const char *str) { + uint32_t len = strlen(str); + char *s2 = m_new(char, len + 1); + memcpy(s2, str, len); + s2[len] = 0; + return s2; +} +#endif + +int main(void) { + // TODO: Put this in a more common initialization function. + // Turn on STKALIGN which keeps the stack 8-byte aligned for interrupts + // (per EABI) + #define SCB_CCR_STKALIGN (1 << 9) + SCB_CCR |= SCB_CCR_STKALIGN; + + mp_stack_ctrl_init(); + mp_stack_set_limit(10240); + + pinMode(LED_BUILTIN, OUTPUT); + led_init(); + +// int first_soft_reset = true; + +soft_reset: + + led_state(PYB_LED_BUILTIN, 1); + + // GC init + gc_init(&_heap_start, (void*)HEAP_END); + + // MicroPython init + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_init(mp_sys_argv, 0); + + readline_init0(); + + pin_init0(); + +#if 0 + // add some functions to the python namespace + { + mp_store_name(MP_QSTR_help, mp_make_function_n(0, pyb_help)); + mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb); + mp_store_attr(m, MP_QSTR_info, mp_make_function_n(0, pyb_info)); + mp_store_attr(m, MP_QSTR_source_dir, mp_make_function_n(1, pyb_source_dir)); + mp_store_attr(m, MP_QSTR_main, mp_make_function_n(1, pyb_main)); + mp_store_attr(m, MP_QSTR_gc, mp_make_function_n(0, pyb_gc)); + mp_store_attr(m, MP_QSTR_delay, mp_make_function_n(1, pyb_delay)); + mp_store_attr(m, MP_QSTR_led, mp_make_function_n(1, pyb_led)); + mp_store_attr(m, MP_QSTR_LED, (mp_obj_t)&pyb_led_type); + mp_store_attr(m, MP_QSTR_analogRead, mp_make_function_n(1, pyb_analog_read)); + mp_store_attr(m, MP_QSTR_analogWrite, mp_make_function_n(2, pyb_analog_write)); + mp_store_attr(m, MP_QSTR_analogWriteResolution, mp_make_function_n(1, pyb_analog_write_resolution)); + mp_store_attr(m, MP_QSTR_analogWriteFrequency, mp_make_function_n(2, pyb_analog_write_frequency)); + + mp_store_attr(m, MP_QSTR_gpio, (mp_obj_t)&pyb_gpio_obj); + mp_store_attr(m, MP_QSTR_Servo, mp_make_function_n(0, pyb_Servo)); + mp_store_name(MP_QSTR_pyb, m); + } +#endif + +#if MICROPY_MODULE_FROZEN + pyexec_frozen_module("boot.py"); +#else + if (!pyexec_file("/boot.py")) { + flash_error(4); + } +#endif + + // Turn bootup LED off + led_state(PYB_LED_BUILTIN, 0); + + // run main script +#if MICROPY_MODULE_FROZEN + pyexec_frozen_module("main.py"); +#else + { + vstr_t *vstr = vstr_new(16); + vstr_add_str(vstr, "/"); + if (pyb_config_main == MP_OBJ_NULL) { + vstr_add_str(vstr, "main.py"); + } else { + vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main)); + } + if (!pyexec_file(vstr_null_terminated_str(vstr))) { + flash_error(3); + } + vstr_free(vstr); + } +#endif + + // enter REPL + // REPL mode can change, or it can request a soft reset + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + printf("PYB: soft reboot\n"); + +// first_soft_reset = false; + goto soft_reset; +} + +// stub out __libc_init_array. It's called by mk20dx128.c and is used to call +// global C++ constructors. Since this is a C-only projects, we don't need to +// call constructors. +void __libc_init_array(void) { +} + +// ultoa is used by usb_init_serialnumber. Normally ultoa would be provided +// by nonstd.c from the teensy core, but it conflicts with some of the +// MicroPython functions in string0.c, so we provide ultoa here. +char * ultoa(unsigned long val, char *buf, int radix) +{ + unsigned digit; + int i=0, j; + char t; + + while (1) { + digit = val % radix; + buf[i] = ((digit < 10) ? '0' + digit : 'A' + digit - 10); + val /= radix; + if (val == 0) break; + i++; + } + buf[i + 1] = 0; + for (j=0; j < i; j++, i--) { + t = buf[j]; + buf[j] = buf[i]; + buf[i] = t; + } + return buf; +} diff --git a/src/openmv/src/micropython/ports/teensy/make-pins.py b/src/openmv/src/micropython/ports/teensy/make-pins.py new file mode 100755 index 0000000..0f6c5f2 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/make-pins.py @@ -0,0 +1,405 @@ +#!/usr/bin/env python +"""Creates the pin file for the Teensy.""" + +from __future__ import print_function + +import argparse +import sys +import csv + +SUPPORTED_FN = { + 'FTM' : ['CH0', 'CH1', 'CH2', 'CH3', 'CH4', 'CH5', 'CH6', 'CH7', + 'QD_PHA', 'QD_PHB'], + 'I2C' : ['SDA', 'SCL'], + 'UART' : ['RX', 'TX', 'CTS', 'RTS'], + 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'] +} + +def parse_port_pin(name_str): + """Parses a string and returns a (port-num, pin-num) tuple.""" + if len(name_str) < 4: + raise ValueError("Expecting pin name to be at least 4 charcters.") + if name_str[0:2] != 'PT': + raise ValueError("Expecting pin name to start with PT") + if name_str[2] not in ('A', 'B', 'C', 'D', 'E', 'Z'): + raise ValueError("Expecting pin port to be between A and E or Z") + port = ord(name_str[2]) - ord('A') + pin_str = name_str[3:].split('/')[0] + if not pin_str.isdigit(): + raise ValueError("Expecting numeric pin number.") + return (port, int(pin_str)) + +def split_name_num(name_num): + num = None + for num_idx in range(len(name_num) - 1, -1, -1): + if not name_num[num_idx].isdigit(): + name = name_num[0:num_idx + 1] + num_str = name_num[num_idx + 1:] + if len(num_str) > 0: + num = int(num_str) + break + return name, num + + +class AlternateFunction(object): + """Holds the information associated with a pins alternate function.""" + + def __init__(self, idx, af_str): + self.idx = idx + self.af_str = af_str + + self.func = '' + self.fn_num = None + self.pin_type = '' + self.supported = False + + af_words = af_str.split('_', 1) + self.func, self.fn_num = split_name_num(af_words[0]) + if len(af_words) > 1: + self.pin_type = af_words[1] + if self.func in SUPPORTED_FN: + pin_types = SUPPORTED_FN[self.func] + if self.pin_type in pin_types: + self.supported = True + + def is_supported(self): + return self.supported + + def ptr(self): + """Returns the numbered function (i.e. USART6) for this AF.""" + if self.fn_num is None: + return self.func + return '{:s}{:d}'.format(self.func, self.fn_num) + + def mux_name(self): + return 'AF{:d}_{:s}'.format(self.idx, self.ptr()) + + def print(self): + """Prints the C representation of this AF.""" + if self.supported: + print(' AF', end='') + else: + print(' //', end='') + fn_num = self.fn_num + if fn_num is None: + fn_num = 0 + print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, + self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + + def qstr_list(self): + return [self.mux_name()] + + +class Pin(object): + """Holds the information associated with a pin.""" + + def __init__(self, port, pin): + self.port = port + self.pin = pin + self.alt_fn = [] + self.alt_fn_count = 0 + self.adc_num = 0 + self.adc_channel = 0 + self.board_pin = False + + def port_letter(self): + return chr(self.port + ord('A')) + + def cpu_pin_name(self): + return '{:s}{:d}'.format(self.port_letter(), self.pin) + + def is_board_pin(self): + return self.board_pin + + def set_is_board_pin(self): + self.board_pin = True + + def parse_adc(self, adc_str): + if (adc_str[:3] != 'ADC'): + return + (adc,channel) = adc_str.split('_') + for idx in range(3, len(adc)): + adc_num = int(adc[idx]) # 1, 2, or 3 + self.adc_num |= (1 << (adc_num - 1)) + self.adc_channel = int(channel[2:]) + + def parse_af(self, af_idx, af_strs_in): + if len(af_strs_in) == 0: + return + # If there is a slash, then the slash separates 2 aliases for the + # same alternate function. + af_strs = af_strs_in.split('/') + for af_str in af_strs: + alt_fn = AlternateFunction(af_idx, af_str) + self.alt_fn.append(alt_fn) + if alt_fn.is_supported(): + self.alt_fn_count += 1 + + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return 'NULL' + return 'pin_{:s}_af'.format(self.cpu_pin_name()) + + def adc_num_str(self): + str = '' + for adc_num in range(1,4): + if self.adc_num & (1 << (adc_num - 1)): + if len(str) > 0: + str += ' | ' + str += 'PIN_ADC' + str += chr(ord('0') + adc_num) + if len(str) == 0: + str = '0' + return str + + def print(self): + if self.alt_fn_count == 0: + print("// ", end='') + print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name())) + for alt_fn in self.alt_fn: + alt_fn.print() + if self.alt_fn_count == 0: + print("// ", end='') + print('};') + print('') + print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s}, {:s}, {:d});'.format( + self.cpu_pin_name(), self.port_letter(), self.pin, + self.alt_fn_count, self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) + print('') + + def print_header(self, hdr_file): + hdr_file.write('extern const pin_obj_t pin_{:s};\n'. + format(self.cpu_pin_name())) + if self.alt_fn_count > 0: + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. + format(self.cpu_pin_name())) + + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + +class NamedPin(object): + + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name + + +class Pins(object): + + def __init__(self): + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects + + def find_pin(self, port_num, pin_num): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.port == port_num and pin.pin == pin_num: + return pin + + def parse_af_file(self, filename, pinname_col, af_col): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[pinname_col]) + except: + continue + pin = Pin(port_num, pin_num) + for af_idx in range(af_col, len(row)): + if af_idx >= af_col: + pin.parse_af(af_idx - af_col, row[af_idx]) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) + + def parse_board_file(self, filename): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[1]) + except: + continue + pin = self.find_pin(port_num, pin_num) + if pin: + pin.set_is_board_pin() + self.board_pins.append(NamedPin(row[0], pin)) + + def print_named(self, label, named_pins): + print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) + print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); + + def print(self): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print() + self.print_named('cpu', self.cpu_pins) + print('') + self.print_named('board', self.board_pins) + + def print_adc(self, adc_num): + print(''); + print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) + for channel in range(16): + adc_found = False + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if (pin.is_board_pin() and + (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): + print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) + adc_found = True + break + if not adc_found: + print(' NULL, // {:d}'.format(channel)) + print('};') + + + def print_header(self, hdr_filename): + with open(hdr_filename, 'wt') as hdr_file: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, 'wt') as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + key = 'MP_OBJ_NEW_QSTR(MP_QSTR_{}),'.format(mux_name) + val = 'MP_OBJ_NEW_SMALL_INT(GPIO_{})'.format(mux_name) + print(' { %-*s %s },' % (mux_name_width + 26, key, val), + file=af_const_file) + + def print_af_py(self, af_py_filename): + with open(af_py_filename, 'wt') as af_py_file: + print('PINS_AF = (', file=af_py_file); + for named_pin in self.board_pins: + print(" ('%s', " % named_pin.name(), end='', file=af_py_file) + for af in named_pin.pin().alt_fn: + if af.is_supported(): + print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file) + print('),', file=af_py_file) + print(')', file=af_py_file) + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file" + ) + parser.add_argument( + "-a", "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="mk20dx256_af.csv" + ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins_af_const.h" + ) + parser.add_argument( + "--af-py", + dest="af_py_filename", + help="Specifies the filename for the python alternate function mappings.", + default="build/pins_af.py" + ) + parser.add_argument( + "-b", "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="mk20dx256_prefix.c" + ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins_qstr.h" + ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print('// This file was automatically generated by make-pins.py') + print('//') + if args.af_filename: + print('// --af {:s}'.format(args.af_filename)) + pins.parse_af_file(args.af_filename, 4, 3) + + if args.board_filename: + print('// --board {:s}'.format(args.board_filename)) + pins.parse_board_file(args.board_filename) + + if args.prefix_filename: + print('// --prefix {:s}'.format(args.prefix_filename)) + print('') + with open(args.prefix_filename, 'r') as prefix_file: + print(prefix_file.read()) + pins.print() + pins.print_adc(1) + pins.print_adc(2) + pins.print_adc(3) + pins.print_header(args.hdr_filename) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) + pins.print_af_py(args.af_py_filename) + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/ports/teensy/memzip_files/boot.py b/src/openmv/src/micropython/ports/teensy/memzip_files/boot.py new file mode 100755 index 0000000..6dd5516 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/memzip_files/boot.py @@ -0,0 +1,12 @@ +import pyb +print("Executing boot.py") + +def pins(): + for pin_name in dir(pyb.Pin.board): + pin = pyb.Pin(pin_name) + print('{:10s} {:s}'.format(pin_name, str(pin))) + +def af(): + for pin_name in dir(pyb.Pin.board): + pin = pyb.Pin(pin_name) + print('{:10s} {:s}'.format(pin_name, str(pin.af_list()))) diff --git a/src/openmv/src/micropython/ports/teensy/memzip_files/main.py b/src/openmv/src/micropython/ports/teensy/memzip_files/main.py new file mode 100755 index 0000000..b652377 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/memzip_files/main.py @@ -0,0 +1,15 @@ +import pyb + +print("Executing main.py") + +led = pyb.LED(1) + +led.on() +pyb.delay(100) +led.off() +pyb.delay(100) +led.on() +pyb.delay(100) +led.off() + + diff --git a/src/openmv/src/micropython/ports/teensy/mk20dx256.ld b/src/openmv/src/micropython/ports/teensy/mk20dx256.ld new file mode 100755 index 0000000..bff0a8c --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/mk20dx256.ld @@ -0,0 +1,176 @@ +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K + RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* INCLUDE common.ld */ + +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + + +SECTIONS +{ + .text : { + . = 0; + KEEP(*(.vectors)) + *(.startup*) + /* TODO: does linker detect startup overflow onto flashconfig? */ + . = 0x400; + KEEP(*(.flashconfig*)) + *(.text*) + *(.rodata*) + . = ALIGN(4); + KEEP(*(.init)) + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } > FLASH = 0xFF + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + _etext = .; + + .usbdescriptortable (NOLOAD) : { + /* . = ORIGIN(RAM); */ + . = ALIGN(512); + *(.usbdescriptortable*) + } > RAM + + .dmabuffers (NOLOAD) : { + . = ALIGN(4); + *(.dmabuffers*) + } > RAM + + .usbbuffers (NOLOAD) : { + . = ALIGN(4); + *(.usbbuffers*) + } > RAM + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + .data : AT (_etext) { + . = ALIGN(4); + _sdata = .; + _ram_start = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } > RAM + + /* + * _staticfs is the place in flash where the static filesystem which + * is concatenated to the .hex file will wind up. + */ + _staticfs = LOADADDR(.data) + SIZEOF(.data); + + .noinit (NOLOAD) : { + *(.noinit*) + } > RAM + + .bss : { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + __bss_end = .; + } > RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + _heap_start = .; /* define a global symbol at heap start */ + . = . + _minimum_heap_size; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + _estack = ORIGIN(RAM) + LENGTH(RAM); + _ram_end = ORIGIN(RAM) + LENGTH(RAM); + _heap_end = ORIGIN(RAM) + 0xe000; +} + + + + diff --git a/src/openmv/src/micropython/ports/teensy/mk20dx256_af.csv b/src/openmv/src/micropython/ports/teensy/mk20dx256_af.csv new file mode 100755 index 0000000..571587d --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/mk20dx256_af.csv @@ -0,0 +1,65 @@ +Pin,Name,Default,ALT0,ALT1,ALT2,ALT3,ALT4,ALT5,ALT6,ALT7,EzPort +1,PTE0,ADC1_SE4a,ADC1_SE4a,PTE0,SPI1_PCS1,UART1_TX,,,I2C1_SDA,RTC_CLKOUT, +2,PTE1/LLWU_P0,ADC1_SE5a,ADC1_SE5a,PTE1/LLWU_P0,SPI1_SOUT,UART1_RX,,,I2C1_SCL,SPI1_SIN, +3,VDD,VDD,VDD,,,,,,,, +4,VSS,VSS,VSS,,,,,,,, +5,USB0_DP,USB0_DP,USB0_DP,,,,,,,, +6,USB0_DM,USB0_DM,USB0_DM,,,,,,,, +7,VOUT33,VOUT33,VOUT33,,,,,,,, +8,VREGIN,VREGIN,VREGIN,,,,,,,, +9,PGA0_DP/ADC0_DP0/ADC1_DP3,PGA0_DP/ADC0_DP0/ADC1_DP3,PGA0_DP/ADC0_DP0/ADC1_DP3,PTZ0,,,,,,, +10,PGA0_DM/ADC0_DM0/ADC1_DM3,PGA0_DM/ADC0_DM0/ADC1_DM3,PGA0_DM/ADC0_DM0/ADC1_DM3,PTZ1,,,,,,, +11,PGA1_DP/ADC1_DP0/ADC0_DP3,PGA1_DP/ADC1_DP0/ADC0_DP3,PGA1_DP/ADC1_DP0/ADC0_DP3,PTZ2,,,,,,, +12,PGA1_DM/ADC1_DM0/ADC0_DM3,PGA1_DM/ADC1_DM0/ADC0_DM3,PGA1_DM/ADC1_DM0/ADC0_DM3,PTZ3,,,,,,, +13,VDDA,VDDA,VDDA,,,,,,,, +14,VREFH,VREFH,VREFH,,,,,,,, +15,VREFL,VREFL,VREFL,,,,,,,, +16,VSSA,VSSA,VSSA,,,,,,,, +17,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,PTZ4,,,,,,, +18,DAC0_OUT/CMP1_IN3/ADC0_SE23,DAC0_OUT/CMP1_IN3/ADC0_SE23,DAC0_OUT/CMP1_IN3/ADC0_SE23,PTZ5,,,,,,, +19,XTAL32,XTAL32,XTAL32,,,,,,,, +20,EXTAL32,EXTAL32,EXTAL32,,,,,,,, +21,VBAT,VBAT,VBAT,,,,,,,, +22,PTA0,JTAG_TCLK/SWD_CLK/EZP_CLK,TSI0_CH1,PTA0,UART0_CTS_b/UART0_COL_b,FTM0_CH5,,,,JTAG_TCLK/SWD_CLK,EZP_CLK +23,PTA1,JTAG_TDI/EZP_DI,TSI0_CH2,PTA1,UART0_RX,FTM0_CH6,,,,JTAG_TDI,EZP_DI +24,PTA2,JTAG_TDO/TRACE_SWO/EZP_DO,TSI0_CH3,PTA2,UART0_TX,FTM0_CH7,,,,JTAG_TDO/TRACE_SWO,EZP_DO +25,PTA3,JTAG_TMS/SWD_DIO,TSI0_CH4,PTA3,UART0_RTS_b,FTM0_CH0,,,,JTAG_TMS/SWD_DIO, +26,PTA4/LLWU_P3,NMI_b/EZP_CS_b,TSI0_CH5,PTA4/LLWU_P3,,FTM0_CH1,,,NMI_b,EZP_CS_b, +27,PTA5,DISABLED,,PTA5,USB_CLKIN,FTM0_CH2,,CMP2_OUT,I2S0_TX_BCLK,JTAG_TRST_b, +28,PTA12,CMP2_IN0,CMP2_IN0,PTA12,CAN0_TX,FTM1_CH0,,,I2S0_TXD0,FTM1_QD_PHA, +29,PTA13/LLWU_P4,CMP2_IN1,CMP2_IN1,PTA13/LLWU_P4,CAN0_RX,FTM1_CH1,,,I2S0_TX_FS,FTM1_QD_PHB, +30,VDD,VDD,VDD,,,,,,,, +31,VSS,VSS,VSS,,,,,,,, +32,PTA18,EXTAL0,EXTAL0,PTA18,,FTM0_FLT2,FTM_CLKIN0,,,, +33,PTA19,XTAL0,XTAL0,PTA19,,FTM1_FLT0,FTM_CLKIN1,,LPTMR0_ALT1,, +34,RESET_b,RESET_b,RESET_b,,,,,,,, +35,PTB0/LLWU_P5,ADC0_SE8/ADC1_SE8/TSI0_CH0,ADC0_SE8/ADC1_SE8/TSI0_CH0,PTB0/LLWU_P5,I2C0_SCL,FTM1_CH0,,,FTM1_QD_PHA,, +36,PTB1,ADC0_SE9/ADC1_SE9/TSI0_CH6,ADC0_SE9/ADC1_SE9/TSI0_CH6,PTB1,I2C0_SDA,FTM1_CH1,,,FTM1_QD_PHB,, +37,PTB2,ADC0_SE12/TSI0_CH7,ADC0_SE12/TSI0_CH7,PTB2,I2C0_SCL,UART0_RTS_b,,,FTM0_FLT3,, +38,PTB3,ADC0_SE13/TSI0_CH8,ADC0_SE13/TSI0_CH8,PTB3,I2C0_SDA,UART0_CTS_b/UART0_COL_b,,,FTM0_FLT0,, +39,PTB16,TSI0_CH9,TSI0_CH9,PTB16,SPI1_SOUT,UART0_RX,,FB_AD17,EWM_IN,, +40,PTB17,TSI0_CH10,TSI0_CH10,PTB17,SPI1_SIN,UART0_TX,,FB_AD16,EWM_OUT_b,, +41,PTB18,TSI0_CH11,TSI0_CH11,PTB18,CAN0_TX,FTM2_CH0,I2S0_TX_BCLK,FB_AD15,FTM2_QD_PHA,, +42,PTB19,TSI0_CH12,TSI0_CH12,PTB19,CAN0_RX,FTM2_CH1,I2S0_TX_FS,FB_OE_b,FTM2_QD_PHB,, +43,PTC0,ADC0_SE14/TSI0_CH13,ADC0_SE14/TSI0_CH13,PTC0,SPI0_PCS4,PDB0_EXTRG,,FB_AD14,I2S0_TXD1,, +44,PTC1/LLWU_P6,ADC0_SE15/TSI0_CH14,ADC0_SE15/TSI0_CH14,PTC1/LLWU_P6,SPI0_PCS3,UART1_RTS_b,FTM0_CH0,FB_AD13,I2S0_TXD0,, +45,PTC2,ADC0_SE4b/CMP1_IN0/TSI0_CH15,ADC0_SE4b/CMP1_IN0/TSI0_CH15,PTC2,SPI0_PCS2,UART1_CTS_b,FTM0_CH1,FB_AD12,I2S0_TX_FS,, +46,PTC3/LLWU_P7,CMP1_IN1,CMP1_IN1,PTC3/LLWU_P7,SPI0_PCS1,UART1_RX,FTM0_CH2,CLKOUT,I2S0_TX_BCLK,, +47,VSS,VSS,VSS,,,,,,,, +48,VDD,VDD,VDD,,,,,,,, +49,PTC4/LLWU_P8,DISABLED,,PTC4/LLWU_P8,SPI0_PCS0,UART1_TX,FTM0_CH3,FB_AD11,CMP1_OUT,, +50,PTC5/LLWU_P9,DISABLED,,PTC5/LLWU_P9,SPI0_SCK,LPTMR0_ALT2,I2S0_RXD0,FB_AD10,CMP0_OUT,, +51,PTC6/LLWU_P10,CMP0_IN0,CMP0_IN0,PTC6/LLWU_P10,SPI0_SOUT,PDB0_EXTRG,I2S0_RX_BCLK,FB_AD9,I2S0_MCLK,, +52,PTC7,CMP0_IN1,CMP0_IN1,PTC7,SPI0_SIN,USB_SOF_OUT,I2S0_RX_FS,FB_AD8,,, +53,PTC8,ADC1_SE4b/CMP0_IN2,ADC1_SE4b/CMP0_IN2,PTC8,,,I2S0_MCLK,FB_AD7,,, +54,PTC9,ADC1_SE5b/CMP0_IN3,ADC1_SE5b/CMP0_IN3,PTC9,,,I2S0_RX_BCLK,FB_AD6,FTM2_FLT0,, +55,PTC10,ADC1_SE6b,ADC1_SE6b,PTC10,I2C1_SCL,,I2S0_RX_FS,FB_AD5,,, +56,PTC11/LLWU_P11,ADC1_SE7b,ADC1_SE7b,PTC11/LLWU_P11,I2C1_SDA,,I2S0_RXD1,FB_RW_b,,, +57,PTD0/LLWU_P12,DISABLED,,PTD0/LLWU_P12,SPI0_PCS0,UART2_RTS_b,,FB_ALE/FB_CS1_b/FB_TS_b,,, +58,PTD1,ADC0_SE5b,ADC0_SE5b,PTD1,SPI0_SCK,UART2_CTS_b,,FB_CS0_b,,, +59,PTD2/LLWU_P13,DISABLED,,PTD2/LLWU_P13,SPI0_SOUT,UART2_RX,,FB_AD4,,, +60,PTD3,DISABLED,,PTD3,SPI0_SIN,UART2_TX,,FB_AD3,,, +61,PTD4/LLWU_P14,DISABLED,,PTD4/LLWU_P14,SPI0_PCS1,UART0_RTS_b,FTM0_CH4,FB_AD2,EWM_IN,, +62,PTD5,ADC0_SE6b,ADC0_SE6b,PTD5,SPI0_PCS2,UART0_CTS_b/UART0_COL_b,FTM0_CH5,FB_AD1,EWM_OUT_b,, +63,PTD6/LLWU_P15,ADC0_SE7b,ADC0_SE7b,PTD6/LLWU_P15,SPI0_PCS3,UART0_RX,FTM0_CH6,FB_AD0,FTM0_FLT0f,, +64,PTD7,DISABLED,,PTD7,CMT_IRO,UART0_TX,FTM0_CH7,,FTM0_FLT1,, diff --git a/src/openmv/src/micropython/ports/teensy/mk20dx256_prefix.c b/src/openmv/src/micropython/ports/teensy/mk20dx256_prefix.c new file mode 100755 index 0000000..58ab07d --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/mk20dx256_prefix.c @@ -0,0 +1,33 @@ +// stm32fxx-prefix.c becomes the initial portion of the generated pins file. + +#include +#include + +#include "py/obj.h" +#include "teensy_hal.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .reg = (af_ptr) \ +} + +#define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = MP_QSTR_ ## p_port ## p_pin, \ + .port = PORT_ ## p_port, \ + .pin = (p_pin), \ + .num_af = (p_num_af), \ + .pin_mask = (1 << (p_pin)), \ + .gpio = GPIO ## p_port, \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/src/openmv/src/micropython/ports/teensy/modpyb.c b/src/openmv/src/micropython/ports/teensy/modpyb.c new file mode 100755 index 0000000..e4c399f --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/modpyb.c @@ -0,0 +1,358 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include "Arduino.h" + +#include "py/obj.h" +#include "py/gc.h" +#include "py/mphal.h" + +#include "lib/utils/pyexec.h" + +#include "gccollect.h" +#include "irq.h" +#include "systick.h" +#include "led.h" +#include "pin.h" +#include "timer.h" +#include "extint.h" +#include "usrsw.h" +#include "rng.h" +//#include "rtc.h" +//#include "i2c.h" +//#include "spi.h" +#include "uart.h" +#include "adc.h" +#include "storage.h" +#include "sdcard.h" +#include "accel.h" +#include "servo.h" +#include "dac.h" +#include "usb.h" +#include "portmodules.h" + +/// \module pyb - functions related to the pyboard +/// +/// The `pyb` module contains specific functions related to the pyboard. + +/// \function bootloader() +/// Activate the bootloader without BOOT* pins. +STATIC mp_obj_t pyb_bootloader(void) { + printf("bootloader command not current supported\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_bootloader_obj, pyb_bootloader); + +/// \function info([dump_alloc_table]) +/// Print out lots of information about the board. +STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) { + // get and print unique id; 96 bits + { + byte *id = (byte*)0x40048058; + printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]); + } + + // get and print clock speeds + printf("CPU=%u\nBUS=%u\nMEM=%u\n", F_CPU, F_BUS, F_MEM); + + // to print info about memory + { + printf("_etext=%p\n", &_etext); + printf("_sidata=%p\n", &_sidata); + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_ram_start=%p\n", &_ram_start); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + printf("_ram_end=%p\n", &_ram_end); + } + + // qstr info + { + uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + } + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info); + +/// \function unique_id() +/// Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU. +STATIC mp_obj_t pyb_unique_id(void) { + byte *id = (byte*)0x40048058; + return mp_obj_new_bytes(id, 12); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id); + +/// \function freq() +/// Return a tuple of clock frequencies: (SYSCLK, HCLK, PCLK1, PCLK2). +// TODO should also be able to set frequency via this function +STATIC mp_obj_t pyb_freq(void) { + mp_obj_t tuple[3] = { + mp_obj_new_int(F_CPU), + mp_obj_new_int(F_BUS), + mp_obj_new_int(F_MEM), + }; + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq); + +/// \function sync() +/// Sync all file systems. +STATIC mp_obj_t pyb_sync(void) { + printf("sync not currently implemented\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync); + +/// \function millis() +/// Returns the number of milliseconds since the board was last reset. +/// +/// The result is always a MicroPython smallint (31-bit signed number), so +/// after 2^30 milliseconds (about 12.4 days) this will start to return +/// negative numbers. +STATIC mp_obj_t pyb_millis(void) { + // We want to "cast" the 32 bit unsigned into a small-int. This means + // copying the MSB down 1 bit (extending the sign down), which is + // equivalent to just using the MP_OBJ_NEW_SMALL_INT macro. + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis); + +/// \function elapsed_millis(start) +/// Returns the number of milliseconds which have elapsed since `start`. +/// +/// This function takes care of counter wrap, and always returns a positive +/// number. This means it can be used to measure periods upto about 12.4 days. +/// +/// Example: +/// start = pyb.millis() +/// while pyb.elapsed_millis(start) < 1000: +/// # Perform some operation +STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { + uint32_t startMillis = mp_obj_get_int(start); + uint32_t currMillis = mp_hal_ticks_ms(); + return MP_OBJ_NEW_SMALL_INT((currMillis - startMillis) & 0x3fffffff); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis); + +/// \function micros() +/// Returns the number of microseconds since the board was last reset. +/// +/// The result is always a MicroPython smallint (31-bit signed number), so +/// after 2^30 microseconds (about 17.8 minutes) this will start to return +/// negative numbers. +STATIC mp_obj_t pyb_micros(void) { + // We want to "cast" the 32 bit unsigned into a small-int. This means + // copying the MSB down 1 bit (extending the sign down), which is + // equivalent to just using the MP_OBJ_NEW_SMALL_INT macro. + return MP_OBJ_NEW_SMALL_INT(micros()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_micros_obj, pyb_micros); + +/// \function elapsed_micros(start) +/// Returns the number of microseconds which have elapsed since `start`. +/// +/// This function takes care of counter wrap, and always returns a positive +/// number. This means it can be used to measure periods upto about 17.8 minutes. +/// +/// Example: +/// start = pyb.micros() +/// while pyb.elapsed_micros(start) < 1000: +/// # Perform some operation +STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { + uint32_t startMicros = mp_obj_get_int(start); + uint32_t currMicros = micros(); + return MP_OBJ_NEW_SMALL_INT((currMicros - startMicros) & 0x3fffffff); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros); + +/// \function delay(ms) +/// Delay for the given number of milliseconds. +STATIC mp_obj_t pyb_delay(mp_obj_t ms_in) { + mp_int_t ms = mp_obj_get_int(ms_in); + if (ms >= 0) { + mp_hal_delay_ms(ms); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay); + +/// \function udelay(us) +/// Delay for the given number of microseconds. +STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) { + mp_int_t usec = mp_obj_get_int(usec_in); + delayMicroseconds(usec); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay); + +STATIC mp_obj_t pyb_stop(void) { + printf("stop not currently implemented\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_stop_obj, pyb_stop); + +STATIC mp_obj_t pyb_standby(void) { + printf("standby not currently implemented\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby); + +/// \function have_cdc() +/// Return True if USB is connected as a serial device, False otherwise. +STATIC mp_obj_t pyb_have_cdc(void ) { + return mp_obj_new_bool(usb_vcp_is_connected()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); + +/// \function hid((buttons, x, y, z)) +/// Takes a 4-tuple (or list) and sends it to the USB host (the PC) to +/// signal a HID mouse-motion event. +STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { +#if 1 + printf("hid_send_report not currently implemented\n"); +#else + mp_obj_t *items; + mp_obj_get_array_fixed_n(arg, 4, &items); + uint8_t data[4]; + data[0] = mp_obj_get_int(items[0]); + data[1] = mp_obj_get_int(items[1]); + data[2] = mp_obj_get_int(items[2]); + data[3] = mp_obj_get_int(items[3]); + usb_hid_send_report(data); +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); + +MP_DECLARE_CONST_FUN_OBJ_1(pyb_source_dir_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_1(pyb_main_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_1(pyb_usb_mode_obj); // defined in main.c + +STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) }, + + { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&pyb_bootloader_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&pyb_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, + + { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&pyb_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&pyb_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&pyb_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&pyb_standby_obj) }, + { MP_ROM_QSTR(MP_QSTR_source_dir), MP_ROM_PTR(&pyb_source_dir_obj) }, + { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, + { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, + + { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, + { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, + + { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&pyb_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&pyb_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_elapsed_micros), MP_ROM_PTR(&pyb_elapsed_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_delay), MP_ROM_PTR(&pyb_delay_obj) }, + { MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&pyb_udelay_obj) }, + { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&pyb_sync_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, + +//#if MICROPY_HW_ENABLE_RNG +// { MP_ROM_QSTR(MP_QSTR_rng), MP_ROM_PTR(&pyb_rng_get_obj) }, +//#endif + +//#if MICROPY_HW_ENABLE_RTC +// { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, +//#endif + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, +// { MP_ROM_QSTR(MP_QSTR_ExtInt), MP_ROM_PTR(&extint_type) }, + +#if MICROPY_HW_ENABLE_SERVO + { MP_ROM_QSTR(MP_QSTR_pwm), MP_ROM_PTR(&pyb_pwm_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_servo), MP_ROM_PTR(&pyb_servo_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_Servo), MP_ROM_PTR(&pyb_servo_type) }, +#endif + +#if MICROPY_HW_HAS_SWITCH + { MP_ROM_QSTR(MP_QSTR_Switch), MP_ROM_PTR(&pyb_switch_type) }, +#endif + +//#if MICROPY_HW_HAS_SDCARD +// { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, +//#endif + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, +// { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, +// { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + +// { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, +// { MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) }, + +//#if MICROPY_HW_ENABLE_DAC +// { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, +//#endif + +//#if MICROPY_HW_HAS_MMA7660 +// { MP_ROM_QSTR(MP_QSTR_Accel), MP_ROM_PTR(&pyb_accel_type) }, +//#endif +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table); + +const mp_obj_module_t pyb_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&pyb_module_globals, +}; diff --git a/src/openmv/src/micropython/ports/teensy/mpconfigport.h b/src/openmv/src/micropython/ports/teensy/mpconfigport.h new file mode 100755 index 0000000..b45b5ad --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/mpconfigport.h @@ -0,0 +1,139 @@ +#include + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_EMIT_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_OPT_COMPUTED_GOTO (1) + +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT teensy_help_text + +#define MICROPY_PY_IO (0) +#define MICROPY_PY_FROZENSET (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_CMATH (1) + +#define MICROPY_TIMER_REG (0) +#define MICROPY_REG (MICROPY_TIMER_REG) + +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t os_module; +extern const struct _mp_obj_module_t pyb_module; +extern const struct _mp_obj_module_t time_module; +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + +// extra constants +#define MICROPY_PORT_CONSTANTS \ + { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t pin_class_mapper; \ + mp_obj_t pin_class_map_dict; \ + struct _pyb_uart_obj_t *pyb_stdio_uart; \ + +// type definitions for the specific machine + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) + +// We have inlined IRQ functions for efficiency (they are generally +// 1 machine instruction). +// +// Note on IRQ state: you should not need to know the specific +// value of the state variable, but rather just pass the return +// value from disable_irq back to enable_irq. If you really need +// to know the machine-specific values, see irq.h. + +#ifndef __disable_irq +#define __disable_irq() __asm__ volatile("CPSID i"); +#endif + +__attribute__(( always_inline )) static inline uint32_t __get_PRIMASK(void) { + uint32_t result; + __asm volatile ("MRS %0, primask" : "=r" (result)); + return(result); +} + +__attribute__(( always_inline )) static inline void __set_PRIMASK(uint32_t priMask) { + __asm volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + +__attribute__(( always_inline )) static inline void enable_irq(mp_uint_t state) { + __set_PRIMASK(state); +} + +__attribute__(( always_inline )) static inline mp_uint_t disable_irq(void) { + mp_uint_t state = __get_PRIMASK(); + __disable_irq(); + return state; +} + +#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() +#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) + +// We need to provide a declaration/definition of alloca() +#include + +// The following would be from a board specific file, if one existed + +#define MICROPY_HW_BOARD_NAME "Teensy-3.1" +#define MICROPY_HW_MCU_NAME "MK20DX256" + +#define MICROPY_HW_HAS_SWITCH (0) +#define MICROPY_HW_HAS_SDCARD (0) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LIS3DSH (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (0) +#define MICROPY_HW_ENABLE_RTC (0) +#define MICROPY_HW_ENABLE_TIMER (0) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_I2C1 (0) +#define MICROPY_HW_ENABLE_SPI1 (0) +#define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) + +#define MICROPY_HW_LED1 (pin_C5) +#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) +#define MICROPY_HW_LED_ON(pin) (pin->gpio->PSOR = pin->pin_mask) +#define MICROPY_HW_LED_OFF(pin) (pin->gpio->PCOR = pin->pin_mask) + +#if 0 +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) +#endif + +#define MICROPY_MATH_SQRT_ASM (1) + +#define MICROPY_MPHALPORT_H "teensy_hal.h" +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_teensy.h" diff --git a/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.c b/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.c new file mode 100755 index 0000000..e7af1e9 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.c @@ -0,0 +1,71 @@ +#include +#include +#include "py/runtime.h" +#include "py/mphal.h" +#include "pin.h" + +// Returns the pin mode. This value returned by this macro should be one of: +// GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP, GPIO_MODE_OUTPUT_OD, +// GPIO_MODE_AF_PP, GPIO_MODE_AF_OD, or GPIO_MODE_ANALOG. + +uint32_t pin_get_mode(const pin_obj_t *pin) { + if (pin->gpio == NULL) { + // Analog only pin + return GPIO_MODE_ANALOG; + } + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + uint32_t pcr = *port_pcr; + uint32_t af = (pcr & PORT_PCR_MUX_MASK) >> 8; + if (af == 0) { + return GPIO_MODE_ANALOG; + } + if (af == 1) { + if (pin->gpio->PDDR & (1 << pin->pin)) { + if (pcr & PORT_PCR_ODE) { + return GPIO_MODE_OUTPUT_OD; + } + return GPIO_MODE_OUTPUT_PP; + } + return GPIO_MODE_INPUT; + } + + if (pcr & PORT_PCR_ODE) { + return GPIO_MODE_AF_OD; + } + return GPIO_MODE_AF_PP; +} + +// Returns the pin pullup/pulldown. The value returned by this macro should +// be one of GPIO_NOPULL, GPIO_PULLUP, or GPIO_PULLDOWN. + +uint32_t pin_get_pull(const pin_obj_t *pin) { + if (pin->gpio == NULL) { + // Analog only pin + return GPIO_NOPULL; + } + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + + uint32_t pcr = *port_pcr; + uint32_t af = (pcr & PORT_PCR_MUX_MASK) >> 8; + + // pull is only valid for digital modes (hence the af > 0 test) + + if (af > 0 && (pcr & PORT_PCR_PE) != 0) { + if (pcr & PORT_PCR_PS) { + return GPIO_PULLUP; + } + return GPIO_PULLDOWN; + } + return GPIO_NOPULL; +} + +// Returns the af (alternate function) index currently set for a pin. + +uint32_t pin_get_af(const pin_obj_t *pin) { + if (pin->gpio == NULL) { + // Analog only pin + return 0; + } + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + return (*port_pcr & PORT_PCR_MUX_MASK) >> 8; +} diff --git a/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.h b/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.h new file mode 100755 index 0000000..d3a700b --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/pin_defs_teensy.h @@ -0,0 +1,43 @@ +enum { + PORT_A, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + PORT_Z, +}; + +enum { + AF_FN_FTM, + AF_FN_I2C, + AF_FN_UART, + AF_FN_SPI +}; + +enum { + AF_PIN_TYPE_FTM_CH0 = 0, + AF_PIN_TYPE_FTM_CH1, + AF_PIN_TYPE_FTM_CH2, + AF_PIN_TYPE_FTM_CH3, + AF_PIN_TYPE_FTM_CH4, + AF_PIN_TYPE_FTM_CH5, + AF_PIN_TYPE_FTM_CH6, + AF_PIN_TYPE_FTM_CH7, + AF_PIN_TYPE_FTM_QD_PHA, + AF_PIN_TYPE_FTM_QD_PHB, + + AF_PIN_TYPE_I2C_SDA = 0, + AF_PIN_TYPE_I2C_SCL, + + AF_PIN_TYPE_SPI_MOSI = 0, + AF_PIN_TYPE_SPI_MISO, + AF_PIN_TYPE_SPI_SCK, + AF_PIN_TYPE_SPI_NSS, + + AF_PIN_TYPE_UART_TX = 0, + AF_PIN_TYPE_UART_RX, + AF_PIN_TYPE_UART_CTS, + AF_PIN_TYPE_UART_RTS, +}; + +typedef GPIO_TypeDef pin_gpio_t; diff --git a/src/openmv/src/micropython/ports/teensy/qstrdefsport.h b/src/openmv/src/micropython/ports/teensy/qstrdefsport.h new file mode 100755 index 0000000..3ba8970 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/src/openmv/src/micropython/ports/teensy/reg.c b/src/openmv/src/micropython/ports/teensy/reg.c new file mode 100755 index 0000000..cbc427d --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/reg.c @@ -0,0 +1,47 @@ +#include +#include +#include "py/runtime.h" +#include "reg.h" + +#if MICROPY_REG + +mp_obj_t reg_cmd(void *base, reg_t *reg, mp_uint_t num_regs, uint n_args, const mp_obj_t *args) { + if (n_args == 0) { + // dump all regs + + for (mp_uint_t reg_idx = 0; reg_idx < num_regs; reg_idx++, reg++) { + printf(" %-8s @0x%08x = 0x%08lx\n", + reg->name, (mp_uint_t)base + reg->offset, *(uint32_t *)((uint8_t *)base + reg->offset)); + } + return mp_const_none; + } + + mp_uint_t addr = 0; + + if (MP_OBJ_IS_STR(args[0])) { + const char *name = mp_obj_str_get_str(args[0]); + mp_uint_t reg_idx; + for (reg_idx = 0; reg_idx < num_regs; reg_idx++, reg++) { + if (strcmp(name, reg->name) == 0) { + break; + } + } + if (reg_idx >= num_regs) { + printf("Unknown register: '%s'\n", name); + return mp_const_none; + } + addr = (mp_uint_t)base + reg->offset; + } else { + addr = (mp_uint_t)base + mp_obj_get_int(args[0]); + } + + if (n_args < 2) { + // get + printf("0x%08lx\n", *(uint32_t *)addr); + } else { + *(uint32_t *)addr = mp_obj_get_int(args[1]); + } + return mp_const_none; +} + +#endif diff --git a/src/openmv/src/micropython/ports/teensy/reg.h b/src/openmv/src/micropython/ports/teensy/reg.h new file mode 100755 index 0000000..0da6378 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/reg.h @@ -0,0 +1,13 @@ +#ifndef MICROPY_INCLUDED_TEENSY_REG_H +#define MICROPY_INCLUDED_TEENSY_REG_H + +typedef struct { + const char *name; + mp_uint_t offset; +} reg_t; + +#define REG_ENTRY(st, name) { #name, offsetof(st, name) } + +mp_obj_t reg_cmd(void *base, reg_t *reg, mp_uint_t num_reg, uint n_args, const mp_obj_t *args); + +#endif // MICROPY_INCLUDED_TEENSY_REG_H diff --git a/src/openmv/src/micropython/ports/teensy/servo.c b/src/openmv/src/micropython/ports/teensy/servo.c new file mode 100755 index 0000000..262daae --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/servo.c @@ -0,0 +1,265 @@ +#include +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "nlr.h" +#include "obj.h" +#include "servo.h" + +#include "Arduino.h" + +#define MAX_SERVOS 12 +#define INVALID_SERVO -1 + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds + +#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE \ + | PDB_SC_CONT | PDB_SC_PRESCALER(2) | PDB_SC_MULT(0)) +#define PDB_PRESCALE 4 +#define usToTicks(us) ((us) * (F_BUS / 1000) / PDB_PRESCALE / 1000) +#define ticksToUs(ticks) ((ticks) * PDB_PRESCALE * 1000 / (F_BUS / 1000)) + +static uint16_t servo_active_mask = 0; +static uint16_t servo_allocated_mask = 0; +static uint8_t servo_pin[MAX_SERVOS]; +static uint16_t servo_ticks[MAX_SERVOS]; + +typedef struct _pyb_servo_obj_t { + mp_obj_base_t base; + uint servo_id; + uint min_usecs; + uint max_usecs; +} pyb_servo_obj_t; + +#define clamp(v, min_val, max_val) ((v) < (min_val) ? (min_val) : (v) > (max_val) ? (max_val) : (v)) + +static float map_uint_to_float(uint x, uint in_min, uint in_max, float out_min, float out_max) +{ + return (float)(x - in_min) * (out_max - out_min) / (float)(in_max - in_min) + (float)out_min; +} + +static uint map_float_to_uint(float x, float in_min, float in_max, uint out_min, uint out_max) +{ + return (int)((x - in_min) * (float)(out_max - out_min) / (in_max - in_min) + (float)out_min); +} + +static mp_obj_t servo_obj_attach(mp_obj_t self_in, mp_obj_t pin_obj) { + pyb_servo_obj_t *self = self_in; + uint pin = mp_obj_get_int(pin_obj); + if (pin > CORE_NUM_DIGITAL) { + goto pin_error; + } + + pinMode(pin, OUTPUT); + servo_pin[self->servo_id] = pin; + servo_active_mask |= (1 << self->servo_id); + if (!(SIM_SCGC6 & SIM_SCGC6_PDB)) { + SIM_SCGC6 |= SIM_SCGC6_PDB; // TODO: use bitband for atomic bitset + PDB0_MOD = 0xFFFF; + PDB0_CNT = 0; + PDB0_IDLY = 0; + PDB0_SC = PDB_CONFIG; + // TODO: maybe this should be a higher priority than most + // other interrupts (init all to some default?) + PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; + } + NVIC_ENABLE_IRQ(IRQ_PDB); + return mp_const_none; + +pin_error: + nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); +} + +static mp_obj_t servo_obj_detach(mp_obj_t self_in) { + //pyb_servo_obj_t *self = self_in; + return mp_const_none; +} + +static mp_obj_t servo_obj_pin(mp_obj_t self_in) { + pyb_servo_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(servo_pin[self->servo_id]); +} + +static mp_obj_t servo_obj_min_usecs(int n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get min + return MP_OBJ_NEW_SMALL_INT(self->min_usecs); + } + // Set min + self->min_usecs = mp_obj_get_int(args[1]); + return mp_const_none; +} + +static mp_obj_t servo_obj_max_usecs(int n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get max + return MP_OBJ_NEW_SMALL_INT(self->max_usecs); + } + // Set max + self->max_usecs = mp_obj_get_int(args[1]); + return mp_const_none; +} + +static mp_obj_t servo_obj_angle(int n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get + float angle = map_uint_to_float(servo_ticks[self->servo_id], + usToTicks(self->min_usecs), + usToTicks(self->max_usecs), + 0.0, 180.0); + return mp_obj_new_float(angle); + } + // Set + float angle = mp_obj_get_float(args[1]); + if (angle < 0.0F) { + angle = 0.0F; + } + if (angle > 180.0F) { + angle = 180.0F; + } + servo_ticks[self->servo_id] = map_float_to_uint(angle, + 0.0F, 180.0F, + usToTicks(self->min_usecs), + usToTicks(self->max_usecs)); + return mp_const_none; +} + +static mp_obj_t servo_obj_usecs(int n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + uint usecs; + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(ticksToUs(servo_ticks[self->servo_id])); + } + // Set + usecs = mp_obj_get_int(args[1]); + + if (self->min_usecs < self->max_usecs) { + usecs = clamp(usecs, self->min_usecs, self->max_usecs); + } else { + usecs = clamp(usecs, self->max_usecs, self->min_usecs); + } + servo_ticks[self->servo_id] = usToTicks(usecs); + return mp_const_none; +} + +static mp_obj_t servo_obj_attached(mp_obj_t self_in) { + pyb_servo_obj_t *self = self_in; + uint attached = (servo_active_mask & (1 << self->servo_id)) != 0; + return MP_OBJ_NEW_SMALL_INT(attached); +} + +static void servo_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_servo_obj_t *self = self_in; + (void)kind; + print(env, "", self->servo_id); +} + +static MP_DEFINE_CONST_FUN_OBJ_2(servo_obj_attach_obj, servo_obj_attach); +static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_detach_obj, servo_obj_detach); +static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_pin_obj, servo_obj_pin); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_min_usecs_obj, 1, 2, servo_obj_min_usecs); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_max_usecs_obj, 1, 2, servo_obj_max_usecs); +static MP_DEFINE_CONST_FUN_OBJ_1(servo_obj_attached_obj, servo_obj_attached); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_angle_obj, 1, 2, servo_obj_angle); +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(servo_obj_usecs_obj, 1, 2, servo_obj_usecs); + +static const mp_method_t servo_methods[] = { + { "attach", &servo_obj_attach_obj }, + { "detach", &servo_obj_detach_obj }, + { "pin", &servo_obj_pin_obj }, + { "min_usecs", &servo_obj_min_usecs_obj }, + { "max_usecs", &servo_obj_max_usecs_obj }, + { "attached", &servo_obj_attached_obj }, + { "angle", &servo_obj_angle_obj }, + { "usecs", &servo_obj_usecs_obj }, + { NULL, NULL }, +}; + +/* + * Notes: + * + * ISR needs to know pin #, ticks + */ + +static const mp_obj_type_t servo_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_Servo, + .print = servo_obj_print, + .methods = servo_methods, +}; + +/* servo = pyb.Servo(pin, [min_uecs, [max_usecs]]) */ + +mp_obj_t pyb_Servo(void) { + uint16_t mask; + pyb_servo_obj_t *self = m_new_obj(pyb_servo_obj_t); + self->base.type = &servo_obj_type; + self->min_usecs = MIN_PULSE_WIDTH; + self->max_usecs = MAX_PULSE_WIDTH; + + /* Find an unallocated servo id */ + + self->servo_id = 0; + for (mask=1; mask < (1<servo_id] = usToTicks(DEFAULT_PULSE_WIDTH); + return self; + } + self->servo_id++; + } + m_del_obj(pyb_servo_obj_t, self); + mp_raise_ValueError("No available servo ids"); + return mp_const_none; +} + +void pdb_isr(void) +{ + static int8_t channel = 0, channel_high = MAX_SERVOS; + static uint32_t tick_accum = 0; + uint32_t ticks; + int32_t wait_ticks; + + // first, if any channel was left high from the previous + // run, now is the time to shut it off + if (servo_active_mask & (1 << channel_high)) { + digitalWrite(servo_pin[channel_high], LOW); + channel_high = MAX_SERVOS; + } + // search for the next channel to turn on + while (channel < MAX_SERVOS) { + if (servo_active_mask & (1 << channel)) { + digitalWrite(servo_pin[channel], HIGH); + channel_high = channel; + ticks = servo_ticks[channel]; + tick_accum += ticks; + PDB0_IDLY += ticks; + PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; + channel++; + return; + } + channel++; + } + // when all channels have output, wait for the + // minimum refresh interval + wait_ticks = usToTicks(REFRESH_INTERVAL) - tick_accum; + if (wait_ticks < usToTicks(100)) wait_ticks = usToTicks(100); + else if (wait_ticks > 60000) wait_ticks = 60000; + tick_accum += wait_ticks; + PDB0_IDLY += wait_ticks; + PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; + // if this wait is enough to satisfy the refresh + // interval, next time begin again at channel zero + if (tick_accum >= usToTicks(REFRESH_INTERVAL)) { + tick_accum = 0; + channel = 0; + } +} diff --git a/src/openmv/src/micropython/ports/teensy/servo.h b/src/openmv/src/micropython/ports/teensy/servo.h new file mode 100755 index 0000000..1ad3435 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/servo.h @@ -0,0 +1,11 @@ +#ifndef MICROPY_INCLUDED_TEENSY_SERVO_H +#define MICROPY_INCLUDED_TEENSY_SERVO_H + +void servo_init(void); + +extern const mp_obj_type_t pyb_servo_type; + +MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); + +#endif // MICROPY_INCLUDED_TEENSY_SERVO_H diff --git a/src/openmv/src/micropython/ports/teensy/std.h b/src/openmv/src/micropython/ports/teensy/std.h new file mode 100755 index 0000000..ef55d22 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/std.h @@ -0,0 +1,25 @@ +#ifndef MICROPY_INCLUDED_TEENSY_STD_H +#define MICROPY_INCLUDED_TEENSY_STD_H + +typedef unsigned int size_t; + +void __assert_func(void); + +void *malloc(size_t n); +void free(void *ptr); +void *realloc(void *ptr, size_t n); + +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); + +size_t strlen(const char *str); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); + +int printf(const char *fmt, ...); +int snprintf(char *str, size_t size, const char *fmt, ...); + +#endif // MICROPY_INCLUDED_TEENSY_STD_H diff --git a/src/openmv/src/micropython/ports/teensy/teensy_hal.c b/src/openmv/src/micropython/ports/teensy/teensy_hal.c new file mode 100755 index 0000000..7ce82f1 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/teensy_hal.c @@ -0,0 +1,65 @@ +#include +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "usb.h" +#include "uart.h" +#include "Arduino.h" + +mp_uint_t mp_hal_ticks_ms(void) { + return millis(); +} + +void mp_hal_delay_ms(mp_uint_t ms) { + delay(ms); +} + +void mp_hal_set_interrupt_char(int c) { + // The teensy 3.1 usb stack doesn't currently have the notion of generating + // an exception when a certain character is received. That just means that + // you can't press Control-C and get your python script to stop. +} + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + byte c; + if (usb_vcp_recv_byte(&c) != 0) { + return c; + } else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { + return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart)); + } + __WFI(); + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len); + } + if (usb_vcp_is_enabled()) { + usb_vcp_send_strn(str, len); + } +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + // send stdout to UART and USB CDC VCP + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len); + uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len); + } + if (usb_vcp_is_enabled()) { + usb_vcp_send_strn_cooked(str, len); + } +} + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { +} + +void extint_register_pin(const void *pin, uint32_t mode, int hard_irq, mp_obj_t callback_obj) { + mp_raise_NotImplementedError(NULL); +} diff --git a/src/openmv/src/micropython/ports/teensy/teensy_hal.h b/src/openmv/src/micropython/ports/teensy/teensy_hal.h new file mode 100755 index 0000000..aef38a2 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/teensy_hal.h @@ -0,0 +1,128 @@ +#include +#include "hal_ftm.h" + +#ifdef USE_FULL_ASSERT + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#define HAL_NVIC_EnableIRQ(irq) NVIC_ENABLE_IRQ(irq) + +#define GPIOA ((GPIO_TypeDef *)&GPIOA_PDOR) +#define GPIOB ((GPIO_TypeDef *)&GPIOB_PDOR) +#define GPIOC ((GPIO_TypeDef *)&GPIOC_PDOR) +#define GPIOD ((GPIO_TypeDef *)&GPIOD_PDOR) +#define GPIOE ((GPIO_TypeDef *)&GPIOE_PDOR) +#define GPIOZ ((GPIO_TypeDef *)NULL) + +#define I2C0 ((I2C_TypeDef *)0x40066000) +#define I2C1 ((I2C_TypeDef *)0x40067000) + +#undef SPI0 +#define SPI0 ((SPI_TypeDef *)0x4002C000) +#define SPI1 ((SPI_TypeDef *)0x4002D000) + +#define UART0 ((UART_TypeDef *)&UART0_BDH) +#define UART1 ((UART_TypeDef *)&UART1_BDH) +#define UART2 ((UART_TypeDef *)&UART2_BDH) + +typedef struct { + uint32_t dummy; +} I2C_TypeDef; + +typedef struct { + uint32_t dummy; +} UART_TypeDef; + +typedef struct { + uint32_t dummy; +} SPI_TypeDef; + +typedef struct { + volatile uint32_t PDOR; // Output register + volatile uint32_t PSOR; // Set output register + volatile uint32_t PCOR; // Clear output register + volatile uint32_t PTOR; // Toggle output register + volatile uint32_t PDIR; // Data Input register + volatile uint32_t PDDR; // Data Direction register +} GPIO_TypeDef; + +#define GPIO_OUTPUT_TYPE ((uint32_t)0x00000010) // Indicates OD + +#define GPIO_MODE_INPUT ((uint32_t)0x00000000) +#define GPIO_MODE_OUTPUT_PP ((uint32_t)0x00000001) +#define GPIO_MODE_OUTPUT_OD ((uint32_t)0x00000011) +#define GPIO_MODE_AF_PP ((uint32_t)0x00000002) +#define GPIO_MODE_AF_OD ((uint32_t)0x00000012) +#define GPIO_MODE_ANALOG ((uint32_t)0x00000003) +#define GPIO_MODE_IT_RISING ((uint32_t)1) +#define GPIO_MODE_IT_FALLING ((uint32_t)2) + +#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_MODE_INPUT) ||\ + ((MODE) == GPIO_MODE_OUTPUT_PP) ||\ + ((MODE) == GPIO_MODE_OUTPUT_OD) ||\ + ((MODE) == GPIO_MODE_AF_PP) ||\ + ((MODE) == GPIO_MODE_AF_OD) ||\ + ((MODE) == GPIO_MODE_ANALOG)) + +#define GPIO_NOPULL ((uint32_t)0) +#define GPIO_PULLUP ((uint32_t)1) +#define GPIO_PULLDOWN ((uint32_t)2) + +#define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ + ((PULL) == GPIO_PULLDOWN)) + +#define GPIO_SPEED_FREQ_LOW ((uint32_t)0) +#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)1) +#define GPIO_SPEED_FREQ_HIGH ((uint32_t)2) +#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)3) + +#define IS_GPIO_AF(af) ((af) >= 0 && (af) <= 7) + +typedef struct { + uint32_t Pin; + uint32_t Mode; + uint32_t Pull; + uint32_t Speed; + uint32_t Alternate; +} GPIO_InitTypeDef; + +#define GPIO_PORT_TO_PORT_NUM(GPIOx) \ + ((&GPIOx->PDOR - &GPIOA_PDOR) / (&GPIOB_PDOR - &GPIOA_PDOR)) + +#define GPIO_PIN_TO_PORT_PCR(GPIOx, pin) \ + (&PORTA_PCR0 + (GPIO_PORT_TO_PORT_NUM(GPIOx) * 0x400) + (pin)) + +#define GPIO_AF2_I2C0 2 +#define GPIO_AF2_I2C1 2 +#define GPIO_AF2_SPI0 2 +#define GPIO_AF3_FTM0 3 +#define GPIO_AF3_FTM1 3 +#define GPIO_AF3_FTM2 3 +#define GPIO_AF3_UART0 3 +#define GPIO_AF3_UART1 3 +#define GPIO_AF3_UART2 3 +#define GPIO_AF4_FTM0 4 +#define GPIO_AF6_FTM1 6 +#define GPIO_AF6_FTM2 6 +#define GPIO_AF6_I2C1 6 +#define GPIO_AF7_FTM1 7 + +__attribute__(( always_inline )) static inline void __WFI(void) { + __asm volatile ("wfi"); +} + +void mp_hal_set_interrupt_char(int c); + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); + +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *init); + +struct _pin_obj_t; +#define mp_hal_pin_obj_t const struct _pin_obj_t* +#define mp_hal_pin_high(p) (((p)->gpio->PSOR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->PCOR) = (p)->pin_mask) +#define mp_hal_pin_read(p) (((p)->gpio->PDIR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) diff --git a/src/openmv/src/micropython/ports/teensy/teensy_pins.csv b/src/openmv/src/micropython/ports/teensy/teensy_pins.csv new file mode 100755 index 0000000..10887e2 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/teensy_pins.csv @@ -0,0 +1,56 @@ +D0,PTB16 +D1,PTB17 +D2,PTD0 +D3,PTA12 +D4,PTA13 +D5,PTD7 +D6,PTD4 +D7,PTD2 +D8,PTD3 +D9,PTC3 +D10,PTC4 +D11,PTC6 +D12,PTC7 +D13,PTC5 +D14,PTD1 +D15,PTC0 +D16,PTB0 +D17,PTB1 +D18,PTB3 +D19,PTB2 +D20,PTD5 +D21,PTD6 +D22,PTC1 +D23,PTC2 +D24,PTA5 +D25,PTB19 +D26,PTE1 +D27,PTC9 +D28,PTC8 +D29,PTC10 +D30,PTC11 +D31,PTE0 +D32,PTB18 +D33,PTA4 +A0,PTD1 +A1,PTC0 +A2,PTB0 +A3,PTB1 +A4,PTB3 +A5,PTB2 +A6,PTD5 +A7,PTD6 +A8,PTC1 +A9,PTC2 +A10,PTZ0 +A11,PTZ1 +A12,PTZ2 +A13,PTZ3 +A14,PTZ5 +A15,PTE1 +A16,PTC9 +A17,PTC8 +A18,PTC10 +A19,PTC11 +A20,PTE0 +LED,PTC5 diff --git a/src/openmv/src/micropython/ports/teensy/timer.c b/src/openmv/src/micropython/ports/teensy/timer.c new file mode 100755 index 0000000..b823e6c --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/timer.c @@ -0,0 +1,991 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "pin.h" +#include "reg.h" +#include "timer.h" + +typedef enum { + CHANNEL_MODE_PWM_NORMAL, + CHANNEL_MODE_PWM_INVERTED, + CHANNEL_MODE_OC_TIMING, + CHANNEL_MODE_OC_ACTIVE, + CHANNEL_MODE_OC_INACTIVE, + CHANNEL_MODE_OC_TOGGLE, +// CHANNEL_MODE_OC_FORCED_ACTIVE, +// CHANNEL_MODE_OC_FORCED_INACTIVE, + CHANNEL_MODE_IC, +} pyb_channel_mode; + +STATIC const struct { + qstr name; + uint32_t oc_mode; +} channel_mode_info[] = { + { MP_QSTR_PWM, FTM_OCMODE_PWM1 }, + { MP_QSTR_PWM_INVERTED, FTM_OCMODE_PWM2 }, + { MP_QSTR_OC_TIMING, FTM_OCMODE_TIMING }, + { MP_QSTR_OC_ACTIVE, FTM_OCMODE_ACTIVE }, + { MP_QSTR_OC_INACTIVE, FTM_OCMODE_INACTIVE }, + { MP_QSTR_OC_TOGGLE, FTM_OCMODE_TOGGLE }, +// { MP_QSTR_OC_FORCED_ACTIVE, FTM_OCMODE_FORCED_ACTIVE }, +// { MP_QSTR_OC_FORCED_INACTIVE, FTM_OCMODE_FORCED_INACTIVE }, + { MP_QSTR_IC, 0 }, +}; + +struct _pyb_timer_obj_t; + +typedef struct _pyb_timer_channel_obj_t { + mp_obj_base_t base; + struct _pyb_timer_obj_t *timer; + uint8_t channel; + uint8_t mode; + mp_obj_t callback; + struct _pyb_timer_channel_obj_t *next; +} pyb_timer_channel_obj_t; + +typedef struct _pyb_timer_obj_t { + mp_obj_base_t base; + uint8_t tim_id; + uint8_t irqn; + mp_obj_t callback; + FTM_HandleTypeDef ftm; + pyb_timer_channel_obj_t *channel; +} pyb_timer_obj_t; + +// Used to do callbacks to Python code on interrupt +STATIC pyb_timer_obj_t *pyb_timer_obj_all[3]; +#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all) + +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in); +STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback); +STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback); + +void timer_init0(void) { + for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { + pyb_timer_obj_all[i] = NULL; + } +} + +// unregister all interrupt sources +void timer_deinit(void) { + for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { + pyb_timer_obj_t *tim = pyb_timer_obj_all[i]; + if (tim != NULL) { + pyb_timer_deinit(tim); + } + } +} + +mp_uint_t get_prescaler_shift(mp_int_t prescaler) { + mp_uint_t prescaler_shift; + for (prescaler_shift = 0; prescaler_shift < 8; prescaler_shift++) { + if (prescaler == (1 << prescaler_shift)) { + return prescaler_shift; + } + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "prescaler must be a power of 2 between 1 and 128, not %d", prescaler)); +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC const mp_obj_type_t pyb_timer_channel_type; + +// Helper function for determining the period used for calculating percent +STATIC uint32_t compute_period(pyb_timer_obj_t *self) { + // In center mode, compare == period corresponds to 100% + // In edge mode, compare == (period + 1) corresponds to 100% + FTM_TypeDef *FTMx = self->ftm.Instance; + uint32_t period = (FTMx->MOD & 0xffff); + if ((FTMx->SC & FTM_SC_CPWMS) == 0) { + // Edge mode + period++; + } + return period; +} + +// Helper function to compute PWM value from timer period and percent value. +// 'val' can be an int or a float between 0 and 100 (out of range values are +// clamped). +STATIC uint32_t compute_pwm_value_from_percent(uint32_t period, mp_obj_t percent_in) { + uint32_t cmp; + if (0) { + #if MICROPY_PY_BUILTINS_FLOAT + } else if (MP_OBJ_IS_TYPE(percent_in, &mp_type_float)) { + float percent = mp_obj_get_float(percent_in); + if (percent <= 0.0) { + cmp = 0; + } else if (percent >= 100.0) { + cmp = period; + } else { + cmp = percent / 100.0 * ((float)period); + } + #endif + } else { + mp_int_t percent = mp_obj_get_int(percent_in); + if (percent <= 0) { + cmp = 0; + } else if (percent >= 100) { + cmp = period; + } else { + cmp = ((uint32_t)percent * period) / 100; + } + } + return cmp; +} + +// Helper function to compute percentage from timer perion and PWM value. +STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) { + #if MICROPY_PY_BUILTINS_FLOAT + float percent = (float)cmp * 100.0 / (float)period; + if (cmp >= period) { + percent = 100.0; + } else { + percent = (float)cmp * 100.0 / (float)period; + } + return mp_obj_new_float(percent); + #else + mp_int_t percent; + if (cmp >= period) { + percent = 100; + } else { + percent = cmp * 100 / period; + } + return mp_obj_new_int(percent); + #endif +} + +STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_obj_t *self = self_in; + + if (self->ftm.State == HAL_FTM_STATE_RESET) { + mp_printf(print, "Timer(%u)", self->tim_id); + } else { + mp_printf(print, "Timer(%u, prescaler=%u, period=%u, mode=%s)", + self->tim_id, + 1 << (self->ftm.Instance->SC & 7), + self->ftm.Instance->MOD & 0xffff, + self->ftm.Init.CounterMode == FTM_COUNTERMODE_UP ? "UP" : "CENTER"); + } +} + +/// \method init(*, freq, prescaler, period) +/// Initialise the timer. Initialisation must be either by frequency (in Hz) +/// or by prescaler and period: +/// +/// tim.init(freq=100) # set the timer to trigger at 100Hz +/// tim.init(prescaler=83, period=999) # set the prescaler and period directly +/// +/// Keyword arguments: +/// +/// - `freq` - specifies the periodic frequency of the timer. You migh also +/// view this as the frequency with which the timer goes through +/// one complete cycle. +/// +/// - `prescaler` 1, 2, 4, 8 16 32, 64 or 128 - specifies the value to be loaded into the +/// timer's prescaler. The timer clock source is divided by +/// (`prescaler`) to arrive at the timer clock. +/// +/// - `period` [0-0xffff] - Specifies the value to be loaded into the timer's +/// Modulo Register (MOD). This determines the period of the timer (i.e. +/// when the counter cycles). The timer counter will roll-over after +/// `period` timer clock cycles. In center mode, a compare register > 0x7fff +/// doesn't seem to work properly, so keep this in mind. +/// +/// - `mode` can be one of: +/// - `Timer.UP` - configures the timer to count from 0 to MOD (default) +/// - `Timer.CENTER` - confgures the timer to count from 0 to MOD and +/// then back down to 0. +/// +/// - `callback` - as per Timer.callback() +/// +/// You must either specify freq or both of period and prescaler. +STATIC const mp_arg_t pyb_timer_init_args[] = { + { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = FTM_COUNTERMODE_UP} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +}; +#define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args) + +STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t vals[PYB_TIMER_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PYB_TIMER_INIT_NUM_ARGS, pyb_timer_init_args, vals); + + FTM_HandleTypeDef *ftm = &self->ftm; + + // set the TIM configuration values + FTM_Base_InitTypeDef *init = &ftm->Init; + + if (vals[0].u_int != 0xffffffff) { + // set prescaler and period from frequency + + if (vals[0].u_int == 0) { + mp_raise_ValueError("can't have 0 frequency"); + } + + uint32_t period = MAX(1, F_BUS / vals[0].u_int); + uint32_t prescaler_shift = 0; + while (period > 0xffff && prescaler_shift < 7) { + period >>= 1; + prescaler_shift++; + } + if (period > 0xffff) { + period = 0xffff; + } + init->PrescalerShift = prescaler_shift; + init->Period = period; + } else if (vals[1].u_int != 0xffffffff && vals[2].u_int != 0xffffffff) { + // set prescaler and period directly + init->PrescalerShift = get_prescaler_shift(vals[1].u_int); + init->Period = vals[2].u_int; + if (!IS_FTM_PERIOD(init->Period)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "period must be between 0 and 65535, not %d", init->Period)); + } + } else { + mp_raise_TypeError("must specify either freq, or prescaler and period"); + } + + init->CounterMode = vals[3].u_int; + if (!IS_FTM_COUNTERMODE(init->CounterMode)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "invalid counter mode: %d", init->CounterMode)); + } + + // Currently core/mk20dx128.c sets SIM_SCGC6_FTM0, SIM_SCGC6_FTM1, SIM_SCGC3_FTM2 + // so we don't need to do it here. + + NVIC_SET_PRIORITY(self->irqn, 0xe); // next-to lowest priority + + HAL_FTM_Base_Init(ftm); + if (vals[4].u_obj == mp_const_none) { + HAL_FTM_Base_Start(ftm); + } else { + pyb_timer_callback(self, vals[4].u_obj); + } + + return mp_const_none; +} + +/// \classmethod \constructor(id, ...) +/// Construct a new timer object of the given id. If additional +/// arguments are given, then the timer is initialised by `init(...)`. +/// `id` can be 1 to 14, excluding 3. +STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create new Timer object + pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t); + memset(tim, 0, sizeof(*tim)); + + tim->base.type = &pyb_timer_type; + tim->callback = mp_const_none; + tim->channel = NULL; + + // get FTM number + tim->tim_id = mp_obj_get_int(args[0]); + + switch (tim->tim_id) { + case 0: tim->ftm.Instance = FTM0; tim->irqn = IRQ_FTM0; break; + case 1: tim->ftm.Instance = FTM1; tim->irqn = IRQ_FTM1; break; + case 2: tim->ftm.Instance = FTM2; tim->irqn = IRQ_FTM2; break; + default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d does not exist", tim->tim_id)); + } + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args); + } + + // set the global variable for interrupt callbacks + if (tim->tim_id < PYB_TIMER_OBJ_ALL_NUM) { + pyb_timer_obj_all[tim->tim_id] = tim; + } + + return (mp_obj_t)tim; +} + +STATIC mp_obj_t pyb_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); + +/// \method deinit() +/// Deinitialises the timer. +/// +/// Disables the callback (and the associated irq). +/// Disables any channel callbacks (and the associated irq). +/// Stops the timer, and disables the timer peripheral. +STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { + pyb_timer_obj_t *self = self_in; + + // Disable the base interrupt + pyb_timer_callback(self_in, mp_const_none); + + pyb_timer_channel_obj_t *chan = self->channel; + self->channel = NULL; + + // Disable the channel interrupts + while (chan != NULL) { + pyb_timer_channel_callback(chan, mp_const_none); + pyb_timer_channel_obj_t *prev_chan = chan; + chan = chan->next; + prev_chan->next = NULL; + } + + HAL_FTM_Base_DeInit(&self->ftm); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); + +/// \method channel(channel, mode, ...) +/// +/// If only a channel number is passed, then a previously initialized channel +/// object is returned (or `None` if there is no previous channel). +/// +/// Othwerwise, a TimerChannel object is initialized and returned. +/// +/// Each channel can be configured to perform pwm, output compare, or +/// input capture. All channels share the same underlying timer, which means +/// that they share the same timer clock. +/// +/// Keyword arguments: +/// +/// - `mode` can be one of: +/// - `Timer.PWM` - configure the timer in PWM mode (active high). +/// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low). +/// - `Timer.OC_TIMING` - indicates that no pin is driven. +/// - `Timer.OC_ACTIVE` - the pin will be made active when a compare +/// match occurs (active is determined by polarity) +/// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare +/// match occurs. +/// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs. +/// - `Timer.IC` - configure the timer in Input Capture mode. +/// +/// - `callback` - as per TimerChannel.callback() +/// +/// - `pin` None (the default) or a Pin object. If specified (and not None) +/// this will cause the alternate function of the the indicated pin +/// to be configured for this timer channel. An error will be raised if +/// the pin doesn't support any alternate functions for this timer channel. +/// +/// Keyword arguments for Timer.PWM modes: +/// +/// - `pulse_width` - determines the initial pulse width value to use. +/// - `pulse_width_percent` - determines the initial pulse width percentage to use. +/// +/// Keyword arguments for Timer.OC modes: +/// +/// - `compare` - determines the initial value of the compare register. +/// +/// - `polarity` can be one of: +/// - `Timer.HIGH` - output is active high +/// - `Timer.LOW` - output is acive low +/// +/// Optional keyword arguments for Timer.IC modes: +/// +/// - `polarity` can be one of: +/// - `Timer.RISING` - captures on rising edge. +/// - `Timer.FALLING` - captures on falling edge. +/// - `Timer.BOTH` - captures on both edges. +/// +/// PWM Example: +/// +/// timer = pyb.Timer(0, prescaler=128, period=37500, counter_mode=pyb.Timer.COUNTER_MODE_CENTER) +/// ch0 = t0.channel(0, pyb.Timer.PWM, pin=pyb.Pin.board.D22, pulse_width=(t0.period() + 1) // 4) +/// ch1 = t0.channel(1, pyb.Timer.PWM, pin=pyb.Pin.board.D23, pulse_width=(t0.period() + 1) // 2) +STATIC const mp_arg_t pyb_timer_channel_args[] = { + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pulse_width_percent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, +}; +#define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args) + +STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_timer_obj_t *self = args[0]; + mp_int_t channel = mp_obj_get_int(args[1]); + + if (channel < 0 || channel > 7) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid channel (%d)", channel)); + } + + pyb_timer_channel_obj_t *chan = self->channel; + pyb_timer_channel_obj_t *prev_chan = NULL; + + while (chan != NULL) { + if (chan->channel == channel) { + break; + } + prev_chan = chan; + chan = chan->next; + } + + // If only the channel number is given return the previously allocated + // channel (or None if no previous channel). + if (n_args == 2) { + if (chan) { + return chan; + } + return mp_const_none; + } + + // If there was already a channel, then remove it from the list. Note that + // the order we do things here is important so as to appear atomic to + // the IRQ handler. + if (chan) { + // Turn off any IRQ associated with the channel. + pyb_timer_channel_callback(chan, mp_const_none); + + // Unlink the channel from the list. + if (prev_chan) { + prev_chan->next = chan->next; + } + self->channel = chan->next; + chan->next = NULL; + } + + // Allocate and initialize a new channel + mp_arg_val_t vals[PYB_TIMER_CHANNEL_NUM_ARGS]; + mp_arg_parse_all(n_args - 3, args + 3, kw_args, PYB_TIMER_CHANNEL_NUM_ARGS, pyb_timer_channel_args, vals); + + chan = m_new_obj(pyb_timer_channel_obj_t); + memset(chan, 0, sizeof(*chan)); + chan->base.type = &pyb_timer_channel_type; + chan->timer = self; + chan->channel = channel; + chan->mode = mp_obj_get_int(args[2]); + chan->callback = vals[0].u_obj; + + mp_obj_t pin_obj = vals[1].u_obj; + if (pin_obj != mp_const_none) { + if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { + mp_raise_ValueError("pin argument needs to be be a Pin type"); + } + const pin_obj_t *pin = pin_obj; + const pin_af_obj_t *af = pin_find_af(pin, AF_FN_FTM, self->tim_id); + if (af == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s doesn't have an af for TIM%d", qstr_str(pin->name), self->tim_id)); + } + // pin.init(mode=AF_PP, af=idx) + const mp_obj_t args[6] = { + (mp_obj_t)&pin_init_obj, + pin_obj, + MP_OBJ_NEW_QSTR(MP_QSTR_mode), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP), + MP_OBJ_NEW_QSTR(MP_QSTR_af), MP_OBJ_NEW_SMALL_INT(af->idx) + }; + mp_call_method_n_kw(0, 2, args); + } + + // Link the channel to the timer before we turn the channel on. + // Note that this needs to appear atomic to the IRQ handler (the write + // to self->channel is atomic, so we're good, but I thought I'd mention + // in case this was ever changed in the future). + chan->next = self->channel; + self->channel = chan; + + switch (chan->mode) { + + case CHANNEL_MODE_PWM_NORMAL: + case CHANNEL_MODE_PWM_INVERTED: { + FTM_OC_InitTypeDef oc_config; + oc_config.OCMode = channel_mode_info[chan->mode].oc_mode; + if (vals[3].u_obj != mp_const_none) { + // pulse width ratio given + uint32_t period = compute_period(self); + oc_config.Pulse = compute_pwm_value_from_percent(period, vals[3].u_obj); + } else { + // use absolute pulse width value (defaults to 0 if nothing given) + oc_config.Pulse = vals[2].u_int; + } + oc_config.OCPolarity = FTM_OCPOLARITY_HIGH; + + HAL_FTM_PWM_ConfigChannel(&self->ftm, &oc_config, channel); + if (chan->callback == mp_const_none) { + HAL_FTM_PWM_Start(&self->ftm, channel); + } else { + HAL_FTM_PWM_Start_IT(&self->ftm, channel); + } + break; + } + + case CHANNEL_MODE_OC_TIMING: + case CHANNEL_MODE_OC_ACTIVE: + case CHANNEL_MODE_OC_INACTIVE: + case CHANNEL_MODE_OC_TOGGLE: { + FTM_OC_InitTypeDef oc_config; + oc_config.OCMode = channel_mode_info[chan->mode].oc_mode; + oc_config.Pulse = vals[4].u_int; + oc_config.OCPolarity = vals[5].u_int; + if (oc_config.OCPolarity == 0xffffffff) { + oc_config.OCPolarity = FTM_OCPOLARITY_HIGH; + } + + if (!IS_FTM_OC_POLARITY(oc_config.OCPolarity)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", oc_config.OCPolarity)); + } + HAL_FTM_OC_ConfigChannel(&self->ftm, &oc_config, channel); + if (chan->callback == mp_const_none) { + HAL_FTM_OC_Start(&self->ftm, channel); + } else { + HAL_FTM_OC_Start_IT(&self->ftm, channel); + } + break; + } + + case CHANNEL_MODE_IC: { + FTM_IC_InitTypeDef ic_config; + + ic_config.ICPolarity = vals[5].u_int; + if (ic_config.ICPolarity == 0xffffffff) { + ic_config.ICPolarity = FTM_ICPOLARITY_RISING; + } + + if (!IS_FTM_IC_POLARITY(ic_config.ICPolarity)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", ic_config.ICPolarity)); + } + HAL_FTM_IC_ConfigChannel(&self->ftm, &ic_config, chan->channel); + if (chan->callback == mp_const_none) { + HAL_FTM_IC_Start(&self->ftm, channel); + } else { + HAL_FTM_IC_Start_IT(&self->ftm, channel); + } + break; + } + + default: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid mode (%d)", chan->mode)); + } + + return chan; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); + +/// \method counter([value]) +/// Get or set the timer counter. +STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(self->ftm.Instance->CNT); + } + // set - In order to write to CNT we need to set CNTIN + self->ftm.Instance->CNTIN = mp_obj_get_int(args[1]); + self->ftm.Instance->CNT = 0; // write any value to load CNTIN into CNT + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter); + +/// \method prescaler([value]) +/// Get or set the prescaler for the timer. +STATIC mp_obj_t pyb_timer_prescaler(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(1 << (self->ftm.Instance->SC & 7)); + } + + // set + mp_uint_t prescaler_shift = get_prescaler_shift(mp_obj_get_int(args[1])); + + mp_uint_t sc = self->ftm.Instance->SC; + sc &= ~7; + sc |= FTM_SC_PS(prescaler_shift); + self->ftm.Instance->SC = sc; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler); + +/// \method period([value]) +/// Get or set the period of the timer. +STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = args[0]; + if (n_args == 1) { + // get + return mp_obj_new_int(self->ftm.Instance->MOD & 0xffff); + } + + // set + mp_int_t period = mp_obj_get_int(args[1]) & 0xffff; + self->ftm.Instance->CNT = 0; + self->ftm.Instance->MOD = period; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period); + +/// \method callback(fun) +/// Set the function to be called when the timer triggers. +/// `fun` is passed 1 argument, the timer object. +/// If `fun` is `None` then the callback will be disabled. +STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) { + pyb_timer_obj_t *self = self_in; + if (callback == mp_const_none) { + // stop interrupt (but not timer) + __HAL_FTM_DISABLE_TOF_IT(&self->ftm); + self->callback = mp_const_none; + } else if (mp_obj_is_callable(callback)) { + self->callback = callback; + HAL_NVIC_EnableIRQ(self->irqn); + // start timer, so that it interrupts on overflow + HAL_FTM_Base_Start_IT(&self->ftm); + } else { + mp_raise_ValueError("callback must be None or a callable object"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback); + +#if MICROPY_TIMER_REG +reg_t timer_reg[] = { + REG_ENTRY(FTM_TypeDef, SC), + REG_ENTRY(FTM_TypeDef, CNT), + REG_ENTRY(FTM_TypeDef, MOD), + REG_ENTRY(FTM_TypeDef, CNTIN), + REG_ENTRY(FTM_TypeDef, STATUS), + REG_ENTRY(FTM_TypeDef, MODE), + REG_ENTRY(FTM_TypeDef, SYNC), + REG_ENTRY(FTM_TypeDef, OUTINIT), + REG_ENTRY(FTM_TypeDef, OUTMASK), + REG_ENTRY(FTM_TypeDef, COMBINE), + REG_ENTRY(FTM_TypeDef, DEADTIME), + REG_ENTRY(FTM_TypeDef, EXTTRIG), + REG_ENTRY(FTM_TypeDef, POL), + REG_ENTRY(FTM_TypeDef, FMS), + REG_ENTRY(FTM_TypeDef, FILTER), + REG_ENTRY(FTM_TypeDef, FLTCTRL), + REG_ENTRY(FTM_TypeDef, QDCTRL), + REG_ENTRY(FTM_TypeDef, CONF), + REG_ENTRY(FTM_TypeDef, FLTPOL), + REG_ENTRY(FTM_TypeDef, SYNCONF), + REG_ENTRY(FTM_TypeDef, INVCTRL), + REG_ENTRY(FTM_TypeDef, SWOCTRL), + REG_ENTRY(FTM_TypeDef, PWMLOAD), +}; + +mp_obj_t pyb_timer_reg(uint n_args, const mp_obj_t *args) { + pyb_timer_obj_t *self = args[0]; + return reg_cmd(self->ftm.Instance, timer_reg, MP_ARRAY_SIZE(timer_reg), n_args - 1, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_reg_obj, 1, 3, pyb_timer_reg); +#endif // MICROPY_TIMER_REG + +STATIC const mp_rom_map_elem_t pyb_timer_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&pyb_timer_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_counter), MP_ROM_PTR(&pyb_timer_counter_obj) }, + { MP_ROM_QSTR(MP_QSTR_prescaler), MP_ROM_PTR(&pyb_timer_prescaler_obj) }, + { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&pyb_timer_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_callback_obj) }, +#if MICROPY_TIMER_REG + { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pyb_timer_reg_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(FTM_COUNTERMODE_UP) }, + { MP_ROM_QSTR(MP_QSTR_CENTER), MP_ROM_INT(FTM_COUNTERMODE_CENTER) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_INT(CHANNEL_MODE_PWM_NORMAL) }, + { MP_ROM_QSTR(MP_QSTR_PWM_INVERTED), MP_ROM_INT(CHANNEL_MODE_PWM_INVERTED) }, + { MP_ROM_QSTR(MP_QSTR_OC_TIMING), MP_ROM_INT(CHANNEL_MODE_OC_TIMING) }, + { MP_ROM_QSTR(MP_QSTR_OC_ACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_OC_INACTIVE), MP_ROM_INT(CHANNEL_MODE_OC_INACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_OC_TOGGLE), MP_ROM_INT(CHANNEL_MODE_OC_TOGGLE) }, + { MP_ROM_QSTR(MP_QSTR_IC), MP_ROM_INT(CHANNEL_MODE_IC) }, + { MP_ROM_QSTR(MP_QSTR_HIGH), MP_ROM_INT(FTM_OCPOLARITY_HIGH) }, + { MP_ROM_QSTR(MP_QSTR_LOW), MP_ROM_INT(FTM_OCPOLARITY_LOW) }, + { MP_ROM_QSTR(MP_QSTR_RISING), MP_ROM_INT(FTM_ICPOLARITY_RISING) }, + { MP_ROM_QSTR(MP_QSTR_FALLING), MP_ROM_INT(FTM_ICPOLARITY_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_BOTH), MP_ROM_INT(FTM_ICPOLARITY_BOTH) }, +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); + +const mp_obj_type_t pyb_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = pyb_timer_print, + .make_new = pyb_timer_make_new, + .locals_dict = (mp_obj_t)&pyb_timer_locals_dict, +}; + +/// \moduleref pyb +/// \class TimerChannel - setup a channel for a timer. +/// +/// Timer channels are used to generate/capture a signal using a timer. +/// +/// TimerChannel objects are created using the Timer.channel() method. +STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_timer_channel_obj_t *self = self_in; + + mp_printf(print, "TimerChannel(timer=%u, channel=%u, mode=%s)", + self->timer->tim_id, + self->channel, + qstr_str(channel_mode_info[self->mode].name)); +} + +/// \method capture([value]) +/// Get or set the capture value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// capture is the logical name to use when the channel is in input capture mode. + +/// \method compare([value]) +/// Get or set the compare value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// compare is the logical name to use when the channel is in output compare mode. + +/// \method pulse_width([value]) +/// Get or set the pulse width value associated with a channel. +/// capture, compare, and pulse_width are all aliases for the same function. +/// pulse_width is the logical name to use when the channel is in PWM mode. +/// +/// In edge aligned mode, a pulse_width of `period + 1` corresponds to a duty cycle of 100% +/// In center aligned mode, a pulse width of `period` corresponds to a duty cycle of 100% +STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *self = args[0]; + FTM_TypeDef *FTMx = self->timer->ftm.Instance; + if (n_args == 1) { + // get + return mp_obj_new_int(FTMx->channel[self->channel].CV & 0xffff); + } + + mp_int_t pw = mp_obj_get_int(args[1]); + + // set + FTMx->channel[self->channel].CV = pw & 0xffff; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare); + +/// \method pulse_width_percent([value]) +/// Get or set the pulse width percentage associated with a channel. The value +/// is a number between 0 and 100 and sets the percentage of the timer period +/// for which the pulse is active. The value can be an integer or +/// floating-point number for more accuracy. For example, a value of 25 gives +/// a duty cycle of 25%. +STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *self = args[0]; + FTM_TypeDef *FTMx = self->timer->ftm.Instance; + uint32_t period = compute_period(self->timer); + if (n_args == 1) { + // get + uint32_t cmp = FTMx->channel[self->channel].CV & 0xffff; + return compute_percent_from_pwm_value(period, cmp); + } else { + // set + uint32_t cmp = compute_pwm_value_from_percent(period, args[1]); + FTMx->channel[self->channel].CV = cmp & 0xffff; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_pulse_width_percent_obj, 1, 2, pyb_timer_channel_pulse_width_percent); + +/// \method callback(fun) +/// Set the function to be called when the timer channel triggers. +/// `fun` is passed 1 argument, the timer object. +/// If `fun` is `None` then the callback will be disabled. +STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) { + pyb_timer_channel_obj_t *self = self_in; + if (callback == mp_const_none) { + // stop interrupt (but not timer) + __HAL_FTM_DISABLE_CH_IT(&self->timer->ftm, self->channel); + self->callback = mp_const_none; + } else if (mp_obj_is_callable(callback)) { + self->callback = callback; + HAL_NVIC_EnableIRQ(self->timer->irqn); + // start timer, so that it interrupts on overflow + switch (self->mode) { + case CHANNEL_MODE_PWM_NORMAL: + case CHANNEL_MODE_PWM_INVERTED: + HAL_FTM_PWM_Start_IT(&self->timer->ftm, self->channel); + break; + case CHANNEL_MODE_OC_TIMING: + case CHANNEL_MODE_OC_ACTIVE: + case CHANNEL_MODE_OC_INACTIVE: + case CHANNEL_MODE_OC_TOGGLE: + HAL_FTM_OC_Start_IT(&self->timer->ftm, self->channel); + break; + case CHANNEL_MODE_IC: + HAL_FTM_IC_Start_IT(&self->timer->ftm, self->channel); + break; + } + } else { + mp_raise_ValueError("callback must be None or a callable object"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_channel_callback_obj, pyb_timer_channel_callback); + +#if MICROPY_TIMER_REG +reg_t timer_channel_reg[] = { + REG_ENTRY(FTM_ChannelTypeDef, CSC), + REG_ENTRY(FTM_ChannelTypeDef, CV), +}; + +mp_obj_t pyb_timer_channel_reg(uint n_args, const mp_obj_t *args) { + pyb_timer_channel_obj_t *self = args[0]; + return reg_cmd(&self->timer->ftm.Instance->channel[self->channel], + timer_channel_reg, MP_ARRAY_SIZE(timer_channel_reg), + n_args - 1, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_reg_obj, 1, 3, pyb_timer_channel_reg); +#endif + +STATIC const mp_rom_map_elem_t pyb_timer_channel_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&pyb_timer_channel_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_pulse_width), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, + { MP_ROM_QSTR(MP_QSTR_pulse_width_percent), MP_ROM_PTR(&pyb_timer_channel_pulse_width_percent_obj) }, + { MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, + { MP_ROM_QSTR(MP_QSTR_compare), MP_ROM_PTR(&pyb_timer_channel_capture_compare_obj) }, +#if MICROPY_TIMER_REG + { MP_ROM_QSTR(MP_QSTR_reg), MP_ROM_PTR(&pyb_timer_channel_reg_obj) }, +#endif +}; +STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_timer_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_TimerChannel, + .print = pyb_timer_channel_print, + .locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict, +}; + +STATIC bool ftm_handle_irq_callback(pyb_timer_obj_t *self, mp_uint_t channel, mp_obj_t callback) { + // execute callback if it's set + if (callback == mp_const_none) { + return false; + } + bool handled = false; + + // When executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_1(callback, self); + nlr_pop(); + handled = true; + } else { + // Uncaught exception; disable the callback so it doesn't run again. + self->callback = mp_const_none; + if (channel == 0xffffffff) { + printf("Uncaught exception in Timer(" UINT_FMT + ") interrupt handler\n", self->tim_id); + } else { + printf("Uncaught exception in Timer(" UINT_FMT ") channel " + UINT_FMT " interrupt handler\n", self->tim_id, channel); + } + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + gc_unlock(); + return handled; +} + +STATIC void ftm_irq_handler(uint tim_id) { + if (tim_id >= PYB_TIMER_OBJ_ALL_NUM) { + return; + } + // get the timer object + pyb_timer_obj_t *self = pyb_timer_obj_all[tim_id]; + if (self == NULL) { + // timer object has not been set, so we can't do anything + printf("No timer object for id=%d\n", tim_id); + return; + } + FTM_HandleTypeDef *hftm = &self->ftm; + + bool handled = false; + + // Check for timer (versus timer channel) interrupt. + if (__HAL_FTM_GET_TOF_IT(hftm) && __HAL_FTM_GET_TOF_FLAG(hftm)) { + __HAL_FTM_CLEAR_TOF_FLAG(hftm); + if (ftm_handle_irq_callback(self, 0xffffffff, self->callback)) { + handled = true; + } else { + __HAL_FTM_DISABLE_TOF_IT(&self->ftm); + printf("No callback for Timer %d TOF (now disabled)\n", tim_id); + } + } + + uint32_t processed = 0; + + // Check to see if a timer channel interrupt is pending + pyb_timer_channel_obj_t *chan = self->channel; + while (chan != NULL) { + processed |= (1 << chan->channel); + if (__HAL_FTM_GET_CH_IT(&self->ftm, chan->channel) && __HAL_FTM_GET_CH_FLAG(&self->ftm, chan->channel)) { + __HAL_FTM_CLEAR_CH_FLAG(&self->ftm, chan->channel); + if (ftm_handle_irq_callback(self, chan->channel, chan->callback)) { + handled = true; + } else { + __HAL_FTM_DISABLE_CH_IT(&self->ftm, chan->channel); + printf("No callback for Timer %d channel %u (now disabled)\n", + self->tim_id, chan->channel); + } + } + chan = chan->next; + } + + if (!handled) { + // An interrupt occurred for a channel we didn't process. Find it and + // turn it off. + for (mp_uint_t channel = 0; channel < 8; channel++) { + if ((processed & (1 << channel)) == 0) { + if (__HAL_FTM_GET_CH_FLAG(&self->ftm, channel) != 0) { + __HAL_FTM_CLEAR_CH_FLAG(&self->ftm, channel); + __HAL_FTM_DISABLE_CH_IT(&self->ftm, channel); + printf("Unhandled interrupt Timer %d channel %u (now disabled)\n", + tim_id, channel); + } + } + } + } +} + +void ftm0_isr(void) { + ftm_irq_handler(0); +} + +void ftm1_isr(void) { + ftm_irq_handler(1); +} + +void ftm2_isr(void) { + ftm_irq_handler(2); +} diff --git a/src/openmv/src/micropython/ports/teensy/timer.h b/src/openmv/src/micropython/ports/teensy/timer.h new file mode 100755 index 0000000..75c2e65 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/timer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_TEENSY_TIMER_H +#define MICROPY_INCLUDED_TEENSY_TIMER_H + +extern const mp_obj_type_t pyb_timer_type; + +void timer_init0(void); +void timer_deinit(void); + +#endif // MICROPY_INCLUDED_TEENSY_TIMER_H diff --git a/src/openmv/src/micropython/ports/teensy/uart.c b/src/openmv/src/micropython/ports/teensy/uart.c new file mode 100755 index 0000000..a8cfd63 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/uart.c @@ -0,0 +1,489 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "bufhelper.h" +#include "uart.h" + +/// \moduleref pyb +/// \class UART - duplex serial communication bus +/// +/// UART implements the standard UART/USART duplex serial communications protocol. At +/// the physical level it consists of 2 lines: RX and TX. +/// +/// See usage model of I2C. UART is very similar. Main difference is +/// parameters to init the UART bus: +/// +/// from pyb import UART +/// +/// uart = UART(1, 9600) # init with given baudrate +/// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters +/// +/// Bits can be 8 or 9, stop can be 1 or 2, parity can be None, 0 (even), 1 (odd). +/// +/// Extra method: +/// +/// uart.any() # returns True if any characters waiting + +struct _pyb_uart_obj_t { + mp_obj_base_t base; + pyb_uart_t uart_id; + bool is_enabled; +// UART_HandleTypeDef uart; +}; + +pyb_uart_obj_t *pyb_uart_global_debug = NULL; + +// assumes Init parameters have been set up correctly +bool uart_init2(pyb_uart_obj_t *uart_obj) { +#if 0 + USART_TypeDef *UARTx = NULL; + + uint32_t GPIO_Pin = 0; + uint8_t GPIO_AF_UARTx = 0; + GPIO_TypeDef* GPIO_Port = NULL; + + switch (uart_obj->uart_id) { + // USART1 is on PA9/PA10 (CK on PA8), PB6/PB7 + case PYB_UART_1: + UARTx = USART1; + GPIO_AF_UARTx = GPIO_AF7_USART1; + +#if defined (PYBV4) || defined(PYBV10) + GPIO_Port = GPIOB; + GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; +#else + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10; +#endif + + __USART1_CLK_ENABLE(); + break; + + // USART2 is on PA2/PA3 (CK on PA4), PD5/PD6 (CK on PD7) + case PYB_UART_2: + UARTx = USART2; + GPIO_AF_UARTx = GPIO_AF7_USART2; + + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_2 | GPIO_PIN_3; + + __USART2_CLK_ENABLE(); + break; + + // USART3 is on PB10/PB11 (CK on PB12), PC10/PC11 (CK on PC12), PD8/PD9 (CK on PD10) + case PYB_UART_3: + UARTx = USART3; + GPIO_AF_UARTx = GPIO_AF7_USART3; + +#if defined(PYBV3) || defined(PYBV4) | defined(PYBV10) + GPIO_Port = GPIOB; + GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11; +#else + GPIO_Port = GPIOD; + GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; +#endif + __USART3_CLK_ENABLE(); + break; + + // UART4 is on PA0/PA1, PC10/PC11 + case PYB_UART_4: + UARTx = UART4; + GPIO_AF_UARTx = GPIO_AF8_UART4; + + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1; + + __UART4_CLK_ENABLE(); + break; + + // USART6 is on PC6/PC7 (CK on PC8) + case PYB_UART_6: + UARTx = USART6; + GPIO_AF_UARTx = GPIO_AF8_USART6; + + GPIO_Port = GPIOC; + GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; + + __USART6_CLK_ENABLE(); + break; + + default: + return false; + } + + // init GPIO + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = GPIO_Pin; + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Alternate = GPIO_AF_UARTx; + HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure); + + // init UARTx + uart_obj->uart.Instance = UARTx; + HAL_UART_Init(&uart_obj->uart); + + uart_obj->is_enabled = true; +#endif + return true; +} + +bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) { +#if 0 + UART_HandleTypeDef *uh = &uart_obj->uart; + memset(uh, 0, sizeof(*uh)); + uh->Init.BaudRate = baudrate; + uh->Init.WordLength = UART_WORDLENGTH_8B; + uh->Init.StopBits = UART_STOPBITS_1; + uh->Init.Parity = UART_PARITY_NONE; + uh->Init.Mode = UART_MODE_TX_RX; + uh->Init.HwFlowCtl = UART_HWCONTROL_NONE; + uh->Init.OverSampling = UART_OVERSAMPLING_16; +#endif + return uart_init2(uart_obj); +} + +mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj) { +#if 0 + return __HAL_UART_GET_FLAG(&uart_obj->uart, UART_FLAG_RXNE); +#else + return 0; +#endif +} + +int uart_rx_char(pyb_uart_obj_t *uart_obj) { + uint8_t ch; +#if 0 + if (HAL_UART_Receive(&uart_obj->uart, &ch, 1, 0) != HAL_OK) { + ch = 0; + } +#else + ch = 'A'; +#endif + return ch; +} + +void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) { +#if 0 + uint8_t ch = c; + HAL_UART_Transmit(&uart_obj->uart, &ch, 1, 100000); +#endif +} + +void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str) { +#if 0 + HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, strlen(str), 100000); +#endif +} + +void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) { +#if 0 + HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, 100000); +#endif +} + +void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + uart_tx_char(uart_obj, '\r'); + } + uart_tx_char(uart_obj, *str); + } +} + +/******************************************************************************/ +/* MicroPython bindings */ + +STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_uart_obj_t *self = self_in; + if (!self->is_enabled) { + mp_printf(print, "UART(%lu)", self->uart_id); + } else { +#if 0 + mp_printf(print, "UART(%lu, baudrate=%u, bits=%u, stop=%u", + self->uart_id, self->uart.Init.BaudRate, + self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9, + self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2); + if (self->uart.Init.Parity == UART_PARITY_NONE) { + mp_print_str(print, ", parity=None)"); + } else { + mp_printf(print, ", parity=%u)", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1); + } +#endif + } +} + +/// \method init(baudrate, *, bits=8, stop=1, parity=None) +/// +/// Initialise the SPI bus with the given parameters: +/// +/// - `baudrate` is the clock rate. +/// - `bits` is the number of bits per byte, 8 or 9. +/// - `stop` is the number of stop bits, 1 or 2. +/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). +STATIC const mp_arg_t pyb_uart_init_args[] = { + { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +}; +#define PYB_UART_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_init_args) + +STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t vals[PYB_UART_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PYB_UART_INIT_NUM_ARGS, pyb_uart_init_args, vals); +#if 0 + // set the UART configuration values + memset(&self->uart, 0, sizeof(self->uart)); + UART_InitTypeDef *init = &self->uart.Init; + init->BaudRate = vals[0].u_int; + init->WordLength = vals[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B; + switch (vals[2].u_int) { + case 1: init->StopBits = UART_STOPBITS_1; break; + default: init->StopBits = UART_STOPBITS_2; break; + } + if (vals[3].u_obj == mp_const_none) { + init->Parity = UART_PARITY_NONE; + } else { + mp_int_t parity = mp_obj_get_int(vals[3].u_obj); + init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; + } + init->Mode = UART_MODE_TX_RX; + init->HwFlowCtl = UART_HWCONTROL_NONE; + init->OverSampling = UART_OVERSAMPLING_16; + + // init UART (if it fails, it's because the port doesn't exist) + if (!uart_init2(self)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART port %d does not exist", self->uart_id)); + } +#endif + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct a UART object on the given bus. `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'. +/// With no additional parameters, the UART object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the UART busses are: +/// +/// - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)` +/// - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)` +/// - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)` +/// - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)` +/// - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)` +STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create object + pyb_uart_obj_t *o = m_new_obj(pyb_uart_obj_t); + o->base.type = &pyb_uart_type; + + // work out port + o->uart_id = 0; +#if 0 + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { +#if defined(PYBV10) + } else if (strcmp(port, "XA") == 0) { + o->uart_id = PYB_UART_XA; + } else if (strcmp(port, "XB") == 0) { + o->uart_id = PYB_UART_XB; + } else if (strcmp(port, "YA") == 0) { + o->uart_id = PYB_UART_YA; + } else if (strcmp(port, "YB") == 0) { + o->uart_id = PYB_UART_YB; +#endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART port %s does not exist", port)); + } + } else { + o->uart_id = mp_obj_get_int(args[0]); + } +#endif + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_uart_init_helper(o, n_args - 1, args + 1, &kw_args); + } + + return o; +} + +STATIC mp_obj_t pyb_uart_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); + +/// \method deinit() +/// Turn off the UART bus. +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { + //pyb_uart_obj_t *self = self_in; + // TODO + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit); + +/// \method any() +/// Return `True` if any characters waiting, else `False`. +STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + if (uart_rx_any(self)) { + return mp_const_true; + } else { + return mp_const_false; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any); + +/// \method send(send, *, timeout=5000) +/// Send data on the bus: +/// +/// - `send` is the data to send (an integer to send, or a buffer object). +/// - `timeout` is the timeout in milliseconds to wait for the send. +/// +/// Return value: `None`. +STATIC const mp_arg_t pyb_uart_send_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, +}; +#define PYB_UART_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_send_args) + +STATIC mp_obj_t pyb_uart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + pyb_uart_obj_t *self = args[0]; + + // parse args + mp_arg_val_t vals[PYB_UART_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_UART_SEND_NUM_ARGS, pyb_uart_send_args, vals); + +#if 0 + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // send the data + HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Transmit failed with code %d", status)); + } +#else + (void)self; +#endif + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_send_obj, 1, pyb_uart_send); + +/// \method recv(recv, *, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `recv` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes. +/// - `timeout` is the timeout in milliseconds to wait for the receive. +/// +/// Return value: if `recv` is an integer then a new buffer of the bytes received, +/// otherwise the same buffer that was passed in to `recv`. +#if 0 +STATIC const mp_arg_t pyb_uart_recv_args[] = { + { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, +}; +#define PYB_UART_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_recv_args) +#endif + +STATIC mp_obj_t pyb_uart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + pyb_uart_obj_t *self = args[0]; + +#if 0 + // parse args + mp_arg_val_t vals[PYB_UART_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_UART_RECV_NUM_ARGS, pyb_uart_recv_args, vals); + + // get the buffer to receive into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); + + // receive the data + HAL_StatusTypeDef status = HAL_UART_Receive(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Receive failed with code %d", status)); + } + + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } +#else + (void)self; + return mp_const_none; +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_recv_obj, 1, pyb_uart_recv); + +STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_uart_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_uart_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_uart_recv_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); + +const mp_obj_type_t pyb_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = pyb_uart_print, + .make_new = pyb_uart_make_new, + .locals_dict = (mp_obj_t)&pyb_uart_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/teensy/usb.c b/src/openmv/src/micropython/ports/teensy/usb.c new file mode 100755 index 0000000..ed96826 --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/usb.c @@ -0,0 +1,52 @@ +#include + +#include "py/runtime.h" + +#include "Arduino.h" + +#include "usb.h" +#include "usb_serial.h" + +bool usb_vcp_is_connected(void) +{ + return usb_configuration && (usb_cdc_line_rtsdtr & (USB_SERIAL_DTR | USB_SERIAL_RTS)); +} + +bool usb_vcp_is_enabled(void) +{ + return true; +} + +int usb_vcp_rx_num(void) { + return usb_serial_available(); +} + +int usb_vcp_recv_byte(uint8_t *ptr) +{ + int ch = usb_serial_getchar(); + if (ch < 0) { + return 0; + } + *ptr = ch; + return 1; +} + +void usb_vcp_send_str(const char* str) +{ + usb_vcp_send_strn(str, strlen(str)); +} + +void usb_vcp_send_strn(const char* str, int len) +{ + usb_serial_write(str, len); +} + +void usb_vcp_send_strn_cooked(const char *str, int len) +{ + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + usb_serial_putchar('\r'); + } + usb_serial_putchar(*str); + } +} diff --git a/src/openmv/src/micropython/ports/teensy/usb.h b/src/openmv/src/micropython/ports/teensy/usb.h new file mode 100755 index 0000000..50fb3ff --- /dev/null +++ b/src/openmv/src/micropython/ports/teensy/usb.h @@ -0,0 +1,12 @@ +#ifndef MICROPY_INCLUDED_TEENSY_USB_H +#define MICROPY_INCLUDED_TEENSY_USB_H + +bool usb_vcp_is_connected(void); +bool usb_vcp_is_enabled(void); +int usb_vcp_rx_num(void); +int usb_vcp_recv_byte(uint8_t *ptr); +void usb_vcp_send_str(const char* str); +void usb_vcp_send_strn(const char* str, int len); +void usb_vcp_send_strn_cooked(const char *str, int len); + +#endif // MICROPY_INCLUDED_TEENSY_USB_H diff --git a/src/openmv/src/micropython/ports/unix/.gitignore b/src/openmv/src/micropython/ports/unix/.gitignore new file mode 100755 index 0000000..706b773 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/.gitignore @@ -0,0 +1,14 @@ +build +build-fast +build-minimal +build-coverage +build-nanbox +build-freedos +micropython +micropython_fast +micropython_minimal +micropython_coverage +micropython_nanbox +micropython_freedos* +*.py +*.gcov diff --git a/src/openmv/src/micropython/ports/unix/Makefile b/src/openmv/src/micropython/ports/unix/Makefile new file mode 100755 index 0000000..badfac7 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/Makefile @@ -0,0 +1,292 @@ +-include mpconfigport.mk +include ../../py/mkenv.mk + +FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + +# define main target +PROG = micropython + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +# OS name, for simple autoconfig +UNAME_S := $(shell uname -s) + +# include py core make definitions +include $(TOP)/py/py.mk + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +# compiler settings +CWARN = -Wall -Werror +CWARN += -Wpointer-arith -Wuninitialized +CFLAGS = $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) + +# Debugging/Optimization +ifdef DEBUG +CFLAGS += -g +COPT = -O0 +else +COPT = -Os -fdata-sections -ffunction-sections -DNDEBUG +# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra +# security for detecting buffer overflows. Some distros (Ubuntu at the very least) +# have it enabled by default. +# +# gcc already optimizes some printf calls to call puts and/or putchar. When +# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some +# printf calls will also be optimized to call __printf_chk (in glibc). Any +# printfs which get redirected to __printf_chk are then no longer synchronized +# with printfs that go through mp_printf. +# +# In MicroPython, we don't want to use the runtime library's printf but rather +# go through mp_printf, so that stdout is properly tied into streams, etc. +# This means that we either need to turn off _FORTIFY_SOURCE or provide our +# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE. +# It should also be noted that the use of printf in MicroPython is typically +# quite limited anyways (primarily for debug and some error reporting, etc +# in the unix version). +# +# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could +# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/ +# Original patchset was introduced by +# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html . +# +# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater +CFLAGS += -U _FORTIFY_SOURCE +endif + +# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. +# The unix port of MicroPython on OSX must be compiled with clang, +# while cross-compile ports require gcc, so we test here for OSX and +# if necessary override the value of 'CC' set in py/mkenv.mk +ifeq ($(UNAME_S),Darwin) +ifeq ($(MICROPY_FORCE_32BIT),1) +CC = clang -m32 +else +CC = clang +endif +# Use clang syntax for map file +LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip +else +# Use gcc syntax for map file +LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections +endif +LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) + +# Flags to link with pthread library +LIBPTHREAD = -lpthread + +ifeq ($(MICROPY_FORCE_32BIT),1) +# Note: you may need to install i386 versions of dependency packages, +# starting with linux-libc-dev:i386 +ifeq ($(MICROPY_PY_FFI),1) +ifeq ($(UNAME_S),Linux) +CFLAGS_MOD += -I/usr/include/i686-linux-gnu +endif +endif +endif + +ifeq ($(MICROPY_USE_READLINE),1) +INC += -I$(TOP)/lib/mp-readline +CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +LIB_SRC_C_EXTRA += mp-readline/readline.c +endif +ifeq ($(MICROPY_PY_TERMIOS),1) +CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1 +SRC_MOD += modtermios.c +endif +ifeq ($(MICROPY_PY_SOCKET),1) +CFLAGS_MOD += -DMICROPY_PY_SOCKET=1 +SRC_MOD += modusocket.c +endif +ifeq ($(MICROPY_PY_THREAD),1) +CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0 +LDFLAGS_MOD += $(LIBPTHREAD) +endif + +ifeq ($(MICROPY_PY_FFI),1) + +ifeq ($(MICROPY_STANDALONE),1) +LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(BUILD)/lib/libffi/out/lib/libffi-*/include) + ifeq ($(MICROPY_FORCE_32BIT),1) + LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib32/libffi.a + else + LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib/libffi.a + endif +else +LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) +LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi) +endif + +ifeq ($(UNAME_S),Linux) +LIBFFI_LDFLAGS_MOD += -ldl +endif + +CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1 +LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD) +SRC_MOD += modffi.c +endif + +ifeq ($(MICROPY_PY_JNI),1) +# Path for 64-bit OpenJDK, should be adjusted for other JDKs +CFLAGS_MOD += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1 +SRC_MOD += modjni.c +endif + +# source files +SRC_C = \ + main.c \ + gccollect.c \ + unix_mphal.c \ + mpthreadport.c \ + input.c \ + file.c \ + modmachine.c \ + modos.c \ + moduos_vfs.c \ + modtime.c \ + moduselect.c \ + alloc.c \ + coverage.c \ + fatfs_port.c \ + $(SRC_MOD) + +LIB_SRC_C = $(addprefix lib/,\ + $(LIB_SRC_C_EXTRA) \ + timeutils/timeutils.c \ + ) + +# FatFS VFS support +LIB_SRC_C += $(addprefix lib/,\ + oofatfs/ff.c \ + oofatfs/option/unicode.c \ + ) + +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(LIB_SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs +MPY_CROSS_FLAGS += -mcache-lookup-bc +endif + + +include $(TOP)/py/mkrules.mk + +.PHONY: test + +test: $(PROG) $(TOP)/tests/run-tests + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests + +# install micropython in /usr/local/bin +TARGET = micropython +PREFIX = $(DESTDIR)/usr/local +BINDIR = $(PREFIX)/bin + +install: micropython + install -d $(BINDIR) + install $(TARGET) $(BINDIR)/$(TARGET) + +# uninstall micropython +uninstall: + -rm $(BINDIR)/$(TARGET) + +# build synthetically fast interpreter for benchmarking +fast: + $(MAKE) COPT="-O2 -DNDEBUG -fno-crossjumping" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' BUILD=build-fast PROG=micropython_fast + +# build a minimal interpreter +minimal: + $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ + BUILD=build-minimal PROG=micropython_minimal FROZEN_DIR= FROZEN_MPY_DIR= \ + MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_SOCKET=0 MICROPY_PY_THREAD=0 \ + MICROPY_PY_TERMIOS=0 MICROPY_PY_USSL=0 \ + MICROPY_USE_READLINE=0 + +# build interpreter with nan-boxing as object model +nanbox: + $(MAKE) \ + CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ + BUILD=build-nanbox \ + PROG=micropython_nanbox \ + MICROPY_FORCE_32BIT=1 + +freedos: + $(MAKE) \ + CC=i586-pc-msdosdjgpp-gcc \ + STRIP=i586-pc-msdosdjgpp-strip \ + SIZE=i586-pc-msdosdjgpp-size \ + CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DMICROPY_NLR_SETJMP -Dtgamma=gamma -DMICROPY_EMIT_X86=0 -DMICROPY_NO_ALLOCA=1 -DMICROPY_PY_USELECT_POSIX=0' \ + BUILD=build-freedos \ + PROG=micropython_freedos \ + MICROPY_PY_SOCKET=0 \ + MICROPY_PY_FFI=0 \ + MICROPY_PY_JNI=0 \ + MICROPY_PY_BTREE=0 \ + MICROPY_PY_THREAD=0 \ + MICROPY_PY_USSL=0 + +# build an interpreter for coverage testing and do the testing +coverage: + $(MAKE) \ + COPT="-O0" CFLAGS_EXTRA='$(CFLAGS_EXTRA) -DMP_CONFIGFILE="" \ + -fprofile-arcs -ftest-coverage \ + -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \ + -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ + -DMICROPY_UNIX_COVERAGE' \ + LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' \ + FROZEN_DIR=coverage-frzstr FROZEN_MPY_DIR=coverage-frzmpy \ + BUILD=build-coverage PROG=micropython_coverage + +coverage_test: coverage + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -d thread + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --emit native + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy -d basics float + cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc' + gcov -o build-coverage/py $(TOP)/py/*.c + gcov -o build-coverage/extmod $(TOP)/extmod/*.c + +# Value of configure's --host= option (required for cross-compilation). +# Deduce it from CROSS_COMPILE by default, but can be overridden. +ifneq ($(CROSS_COMPILE),) +CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE)) +else +CROSS_COMPILE_HOST = +endif + +deplibs: libffi axtls + +libffi: $(BUILD)/lib/libffi/include/ffi.h + +$(TOP)/lib/libffi/configure: $(TOP)/lib/libffi/autogen.sh + cd $(TOP)/lib/libffi; ./autogen.sh + +# install-exec-recursive & install-data-am targets are used to avoid building +# docs and depending on makeinfo +$(BUILD)/lib/libffi/include/ffi.h: $(TOP)/lib/libffi/configure + mkdir -p $(BUILD)/lib/libffi; cd $(BUILD)/lib/libffi; \ + $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \ + $(MAKE) install-exec-recursive; $(MAKE) -C include install-data-am + +axtls: $(TOP)/lib/axtls/README + +$(TOP)/lib/axtls/README: + @echo "You cloned without --recursive, fetching submodules for you." + (cd $(TOP); git submodule update --init --recursive) diff --git a/src/openmv/src/micropython/ports/unix/alloc.c b/src/openmv/src/micropython/ports/unix/alloc.c new file mode 100755 index 0000000..ca12d02 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/alloc.c @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Fabian Vogt + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/mpstate.h" +#include "py/gc.h" + +#if MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) + +#if defined(__OpenBSD__) || defined(__MACH__) +#define MAP_ANONYMOUS MAP_ANON +#endif + +// The memory allocated here is not on the GC heap (and it may contain pointers +// that need to be GC'd) so we must somehow trace this memory. We do it by +// keeping a linked list of all mmap'd regions, and tracing them explicitly. + +typedef struct _mmap_region_t { + void *ptr; + size_t len; + struct _mmap_region_t *next; +} mmap_region_t; + +void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size) { + // size needs to be a multiple of the page size + *size = (min_size + 0xfff) & (~0xfff); + *ptr = mmap(NULL, *size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (*ptr == MAP_FAILED) { + *ptr = NULL; + } + + // add new link to the list of mmap'd regions + mmap_region_t *rg = m_new_obj(mmap_region_t); + rg->ptr = *ptr; + rg->len = min_size; + rg->next = MP_STATE_VM(mmap_region_head); + MP_STATE_VM(mmap_region_head) = rg; +} + +void mp_unix_free_exec(void *ptr, size_t size) { + munmap(ptr, size); + + // unlink the mmap'd region from the list + for (mmap_region_t **rg = (mmap_region_t**)&MP_STATE_VM(mmap_region_head); *rg != NULL; *rg = (*rg)->next) { + if ((*rg)->ptr == ptr) { + mmap_region_t *next = (*rg)->next; + m_del_obj(mmap_region_t, *rg); + *rg = next; + return; + } + } +} + +void mp_unix_mark_exec(void) { + for (mmap_region_t *rg = MP_STATE_VM(mmap_region_head); rg != NULL; rg = rg->next) { + gc_collect_root(rg->ptr, rg->len / sizeof(mp_uint_t)); + } +} + +#if MICROPY_FORCE_PLAT_ALLOC_EXEC +// Provide implementation of libffi ffi_closure_* functions in terms +// of the functions above. On a normal Linux system, this save a lot +// of code size. +void *ffi_closure_alloc(size_t size, void **code); +void ffi_closure_free(void *ptr); + +void *ffi_closure_alloc(size_t size, void **code) { + size_t dummy; + mp_unix_alloc_exec(size, code, &dummy); + return *code; +} + +void ffi_closure_free(void *ptr) { + (void)ptr; + // TODO +} +#endif + +#endif // MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) diff --git a/src/openmv/src/micropython/ports/unix/coverage.c b/src/openmv/src/micropython/ports/unix/coverage.c new file mode 100755 index 0000000..7820f6d --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/coverage.c @@ -0,0 +1,436 @@ +#include +#include + +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/repl.h" +#include "py/mpz.h" +#include "py/builtin.h" +#include "py/emit.h" +#include "py/formatfloat.h" +#include "py/stream.h" +#include "py/binary.h" +#include "py/bc.h" + +#if defined(MICROPY_UNIX_COVERAGE) + +// stream testing object +typedef struct _mp_obj_streamtest_t { + mp_obj_base_t base; + uint8_t *buf; + size_t len; + size_t pos; + int error_code; +} mp_obj_streamtest_t; + +STATIC mp_obj_t stest_set_buf(mp_obj_t o_in, mp_obj_t buf_in) { + mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + o->buf = m_new(uint8_t, bufinfo.len); + memcpy(o->buf, bufinfo.buf, bufinfo.len); + o->len = bufinfo.len; + o->pos = 0; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(stest_set_buf_obj, stest_set_buf); + +STATIC mp_obj_t stest_set_error(mp_obj_t o_in, mp_obj_t err_in) { + mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in); + o->error_code = mp_obj_get_int(err_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(stest_set_error_obj, stest_set_error); + +STATIC mp_uint_t stest_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in); + if (o->pos < o->len) { + if (size > o->len - o->pos) { + size = o->len - o->pos; + } + memcpy(buf, o->buf + o->pos, size); + o->pos += size; + return size; + } else if (o->error_code == 0) { + return 0; + } else { + *errcode = o->error_code; + return MP_STREAM_ERROR; + } +} + +STATIC mp_uint_t stest_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in); + (void)buf; + (void)size; + *errcode = o->error_code; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t stest_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_streamtest_t *o = MP_OBJ_TO_PTR(o_in); + (void)arg; + (void)request; + (void)errcode; + if (o->error_code != 0) { + *errcode = o->error_code; + return MP_STREAM_ERROR; + } + return 0; +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_buf), MP_ROM_PTR(&stest_set_buf_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_error), MP_ROM_PTR(&stest_set_error_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_read1), MP_ROM_PTR(&mp_stream_read1_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write1), MP_ROM_PTR(&mp_stream_write1_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +STATIC const mp_stream_p_t fileio_stream_p = { + .read = stest_read, + .write = stest_write, + .ioctl = stest_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_stest_fileio = { + { &mp_type_type }, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +// stream read returns non-blocking error +STATIC mp_uint_t stest_read2(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + (void)o_in; + (void)buf; + (void)size; + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table2[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict2, rawfile_locals_dict_table2); + +STATIC const mp_stream_p_t textio_stream_p2 = { + .read = stest_read2, + .write = NULL, + .is_text = true, +}; + +STATIC const mp_obj_type_t mp_type_stest_textio2 = { + { &mp_type_type }, + .protocol = &textio_stream_p2, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict2, +}; + +// str/bytes objects without a valid hash +STATIC const mp_obj_str_t str_no_hash_obj = {{&mp_type_str}, 0, 10, (const byte*)"0123456789"}; +STATIC const mp_obj_str_t bytes_no_hash_obj = {{&mp_type_bytes}, 0, 10, (const byte*)"0123456789"}; + +// function to run extra tests for things that can't be checked by scripts +STATIC mp_obj_t extra_coverage(void) { + // mp_printf (used by ports that don't have a native printf) + { + mp_printf(&mp_plat_print, "# mp_printf\n"); + mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign + mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding + mp_printf(&mp_plat_print, "%ld\n", 123); // long + mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex + mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex + mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision + mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision + mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools + #ifndef NDEBUG + mp_printf(&mp_plat_print, "%s\n", NULL); // null string + #else + mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null + #endif + mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed + mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned + mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned + mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned + mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier + } + + // GC + { + mp_printf(&mp_plat_print, "# GC\n"); + + // calling gc_free while GC is locked + gc_lock(); + gc_free(NULL); + gc_unlock(); + + // using gc_realloc to resize to 0, which means free the memory + void *p = gc_alloc(4, false); + mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); + + // calling gc_nbytes with a non-heap pointer + mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); + } + + // vstr + { + mp_printf(&mp_plat_print, "# vstr\n"); + vstr_t *vstr = vstr_new(16); + vstr_hint_size(vstr, 32); + vstr_add_str(vstr, "ts"); + vstr_ins_byte(vstr, 1, 'e'); + vstr_ins_char(vstr, 3, 't'); + vstr_ins_char(vstr, 10, 's'); + mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); + + vstr_cut_head_bytes(vstr, 2); + mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); + + vstr_cut_tail_bytes(vstr, 10); + mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); + + vstr_printf(vstr, "t%cst", 'e'); + mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); + + vstr_cut_out_bytes(vstr, 3, 10); + mp_printf(&mp_plat_print, "%.*s\n", (int)vstr->len, vstr->buf); + + VSTR_FIXED(fix, 4); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + vstr_add_str(&fix, "large"); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + fix.len = fix.alloc; + if (nlr_push(&nlr) == 0) { + vstr_null_terminated_str(&fix); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } + + // repl autocomplete + { + mp_printf(&mp_plat_print, "# repl\n"); + + const char *str; + size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str); + mp_printf(&mp_plat_print, "%.*s\n", (int)len, str); + + mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0))); + mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str); + len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str); + mp_printf(&mp_plat_print, "%.*s\n", (int)len, str); + } + + // attrtuple + { + mp_printf(&mp_plat_print, "# attrtuple\n"); + + static const qstr fields[] = {MP_QSTR_start, MP_QSTR_stop, MP_QSTR_step}; + static const mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(2), MP_OBJ_NEW_SMALL_INT(3)}; + mp_obj_print_helper(&mp_plat_print, mp_obj_new_attrtuple(fields, 3, items), PRINT_REPR); + mp_printf(&mp_plat_print, "\n"); + } + + // str + { + mp_printf(&mp_plat_print, "# str\n"); + + // intern string + mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); + } + + // bytearray + { + mp_printf(&mp_plat_print, "# bytearray\n"); + + // create a bytearray via mp_obj_new_bytearray + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); + mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); + } + + // mpz + { + mp_printf(&mp_plat_print, "# mpz\n"); + + mp_uint_t value; + mpz_t mpz; + mpz_init_zero(&mpz); + + // mpz_as_uint_checked, with success + mpz_set_from_int(&mpz, 12345678); + mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_as_uint_checked, with negative arg + mpz_set_from_int(&mpz, -1); + mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); + + // mpz_as_uint_checked, with overflowing arg + mpz_set_from_int(&mpz, 1); + mpz_shl_inpl(&mpz, &mpz, 70); + mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); + + // mpz_set_from_float with inf as argument + mpz_set_from_float(&mpz, 1.0 / 0.0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0 as argument + mpz_set_from_float(&mpz, 0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0fun_bc = &fun_bc; + code_state->ip = (const byte*)"\x00"; // just needed for an invalid opcode + code_state->sp = &code_state->state[0]; + code_state->exc_sp = NULL; + code_state->old_globals = NULL; + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); + mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); + } + + // scheduler + { + mp_printf(&mp_plat_print, "# scheduler\n"); + + // lock scheduler + mp_sched_lock(); + + // schedule multiple callbacks; last one should fail + for (int i = 0; i < 5; ++i) { + mp_printf(&mp_plat_print, "sched(%d)=%d\n", i, mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(i))); + } + + // test nested locking/unlocking + mp_sched_lock(); + mp_sched_unlock(); + + // shouldn't do anything while scheduler is locked + mp_handle_pending(); + + // unlock scheduler + mp_sched_unlock(); + mp_printf(&mp_plat_print, "unlocked\n"); + + // drain pending callbacks + while (mp_sched_num_pending()) { + mp_handle_pending(); + } + } + + mp_obj_streamtest_t *s = m_new_obj(mp_obj_streamtest_t); + s->base.type = &mp_type_stest_fileio; + s->buf = NULL; + s->len = 0; + s->pos = 0; + s->error_code = 0; + mp_obj_streamtest_t *s2 = m_new_obj(mp_obj_streamtest_t); + s2->base.type = &mp_type_stest_textio2; + + // return a tuple of data for testing on the Python side + mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj, MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)}; + return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items); +} +MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage); + +#endif diff --git a/src/openmv/src/micropython/ports/unix/fatfs_port.c b/src/openmv/src/micropython/ports/unix/fatfs_port.c new file mode 100755 index 0000000..30f1959 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/fatfs_port.c @@ -0,0 +1,5 @@ +#include "lib/oofatfs/ff.h" + +DWORD get_fattime(void) { + return 0; +} diff --git a/src/openmv/src/micropython/ports/unix/fdfile.h b/src/openmv/src/micropython/ports/unix/fdfile.h new file mode 100755 index 0000000..69a9b6b --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/fdfile.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_UNIX_FDFILE_H +#define MICROPY_INCLUDED_UNIX_FDFILE_H + +#include "py/obj.h" + +typedef struct _mp_obj_fdfile_t { + mp_obj_base_t base; + int fd; +} mp_obj_fdfile_t; + +extern const mp_obj_type_t mp_type_fileio; +extern const mp_obj_type_t mp_type_textio; + +#endif // MICROPY_INCLUDED_UNIX_FDFILE_H diff --git a/src/openmv/src/micropython/ports/unix/file.c b/src/openmv/src/micropython/ports/unix/file.c new file mode 100755 index 0000000..a54d1d0 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/file.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/builtin.h" +#include "py/mphal.h" +#include "fdfile.h" + +#if MICROPY_PY_IO && !MICROPY_VFS + +#ifdef _WIN32 +#define fsync _commit +#endif + +#ifdef MICROPY_CPYTHON_COMPAT +STATIC void check_fd_is_open(const mp_obj_fdfile_t *o) { + if (o->fd < 0) { + mp_raise_ValueError("I/O operation on closed file"); + } +} +#else +#define check_fd_is_open(o) +#endif + +extern const mp_obj_type_t mp_type_fileio; +extern const mp_obj_type_t mp_type_textio; + +STATIC void fdfile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", mp_obj_get_type_str(self_in), self->fd); +} + +STATIC mp_uint_t fdfile_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + mp_int_t r = read(o->fd, buf, size); + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + #if MICROPY_PY_OS_DUPTERM + if (o->fd <= STDERR_FILENO) { + mp_hal_stdout_tx_strn(buf, size); + return size; + } + #endif + mp_int_t r = write(o->fd, buf, size); + while (r == -1 && errno == EINTR) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + r = write(o->fd, buf, size); + } + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_fdfile_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + switch (request) { + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + off_t off = lseek(o->fd, s->offset, s->whence); + if (off == (off_t)-1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + s->offset = off; + return 0; + } + case MP_STREAM_FLUSH: + if (fsync(o->fd) < 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return 0; + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; + case MP_STREAM_GET_FILENO: + return o->fd; + default: + *errcode = EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__); + +STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) { + mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); + check_fd_is_open(self); + return MP_OBJ_NEW_SMALL_INT(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); + +// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, +// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor +STATIC const mp_arg_t file_open_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, + { MP_QSTR_buffering, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, +}; +#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) + +STATIC mp_obj_t fdfile_open(const mp_obj_type_t *type, mp_arg_val_t *args) { + mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); + const char *mode_s = mp_obj_str_get_str(args[1].u_obj); + + int mode_rw = 0, mode_x = 0; + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode_rw = O_RDONLY; + break; + case 'w': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_TRUNC; + break; + case 'a': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_APPEND; + break; + case '+': + mode_rw = O_RDWR; + break; + #if MICROPY_PY_IO_FILEIO + // If we don't have io.FileIO, then files are in text mode implicitly + case 'b': + type = &mp_type_fileio; + break; + case 't': + type = &mp_type_textio; + break; + #endif + } + } + + o->base.type = type; + + mp_obj_t fid = args[0].u_obj; + + if (MP_OBJ_IS_SMALL_INT(fid)) { + o->fd = MP_OBJ_SMALL_INT_VALUE(fid); + return MP_OBJ_FROM_PTR(o); + } + + const char *fname = mp_obj_str_get_str(fid); + int fd = open(fname, mode_x | mode_rw, 0644); + if (fd == -1) { + mp_raise_OSError(errno); + } + o->fd = fd; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t fdfile_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); + return fdfile_open(type, arg_vals); +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&fdfile_fileno_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { + .read = fdfile_read, + .write = fdfile_write, + .ioctl = fdfile_ioctl, +}; + +const mp_obj_type_t mp_type_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = fdfile_print, + .make_new = fdfile_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = fdfile_read, + .write = fdfile_write, + .ioctl = fdfile_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = fdfile_print, + .make_new = fdfile_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +// Factory function for I/O stream classes +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + // TODO: analyze buffering args and instantiate appropriate type + mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); + return fdfile_open(&mp_type_textio, arg_vals); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STDIN_FILENO }; +const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO }; +const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO }; + +#endif // MICROPY_PY_IO && !MICROPY_VFS diff --git a/src/openmv/src/micropython/ports/unix/gccollect.c b/src/openmv/src/micropython/ports/unix/gccollect.c new file mode 100755 index 0000000..02f6fc9 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/gccollect.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpstate.h" +#include "py/gc.h" + +#if MICROPY_ENABLE_GC + +// Even if we have specific support for an architecture, it is +// possible to force use of setjmp-based implementation. +#if !MICROPY_GCREGS_SETJMP + +// We capture here callee-save registers, i.e. ones which may contain +// interesting values held there by our callers. It doesn't make sense +// to capture caller-saved registers, because they, well, put on the +// stack already by the caller. +#if defined(__x86_64__) +typedef mp_uint_t regs_t[6]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long rbx asm ("rbx"); + register long rbp asm ("rbp"); + register long r12 asm ("r12"); + register long r13 asm ("r13"); + register long r14 asm ("r14"); + register long r15 asm ("r15"); +#ifdef __clang__ + // TODO: + // This is dirty workaround for Clang. It tries to get around + // uncompliant (wrt to GCC) behavior of handling register variables. + // Application of this patch here is random, and done only to unbreak + // MacOS build. Better, cross-arch ways to deal with Clang issues should + // be found. + asm("" : "=r"(rbx)); + asm("" : "=r"(rbp)); + asm("" : "=r"(r12)); + asm("" : "=r"(r13)); + asm("" : "=r"(r14)); + asm("" : "=r"(r15)); +#endif + arr[0] = rbx; + arr[1] = rbp; + arr[2] = r12; + arr[3] = r13; + arr[4] = r14; + arr[5] = r15; +} + +#elif defined(__i386__) + +typedef mp_uint_t regs_t[4]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long ebx asm ("ebx"); + register long esi asm ("esi"); + register long edi asm ("edi"); + register long ebp asm ("ebp"); +#ifdef __clang__ + // TODO: + // This is dirty workaround for Clang. It tries to get around + // uncompliant (wrt to GCC) behavior of handling register variables. + // Application of this patch here is random, and done only to unbreak + // MacOS build. Better, cross-arch ways to deal with Clang issues should + // be found. + asm("" : "=r"(ebx)); + asm("" : "=r"(esi)); + asm("" : "=r"(edi)); + asm("" : "=r"(ebp)); +#endif + arr[0] = ebx; + arr[1] = esi; + arr[2] = edi; + arr[3] = ebp; +} + +#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) + +typedef mp_uint_t regs_t[10]; + +STATIC void gc_helper_get_regs(regs_t arr) { + register long r4 asm ("r4"); + register long r5 asm ("r5"); + register long r6 asm ("r6"); + register long r7 asm ("r7"); + register long r8 asm ("r8"); + register long r9 asm ("r9"); + register long r10 asm ("r10"); + register long r11 asm ("r11"); + register long r12 asm ("r12"); + register long r13 asm ("r13"); + arr[0] = r4; + arr[1] = r5; + arr[2] = r6; + arr[3] = r7; + arr[4] = r8; + arr[5] = r9; + arr[6] = r10; + arr[7] = r11; + arr[8] = r12; + arr[9] = r13; +} + +#else + +// If we don't have architecture-specific optimized support, +// just fall back to setjmp-based implementation. +#undef MICROPY_GCREGS_SETJMP +#define MICROPY_GCREGS_SETJMP (1) + +#endif // Arch-specific selection +#endif // !MICROPY_GCREGS_SETJMP + +// If MICROPY_GCREGS_SETJMP was requested explicitly, or if +// we enabled it as a fallback above. +#if MICROPY_GCREGS_SETJMP +#include + +typedef jmp_buf regs_t; + +STATIC void gc_helper_get_regs(regs_t arr) { + setjmp(arr); +} + +#endif // MICROPY_GCREGS_SETJMP + +// this function is used by mpthreadport.c +void gc_collect_regs_and_stack(void); + +void gc_collect_regs_and_stack(void) { + regs_t regs; + gc_helper_get_regs(regs); + // GC stack (and regs because we captured them) + void **regs_ptr = (void**)(void*)®s; + gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)®s) / sizeof(uintptr_t)); +} + +void gc_collect(void) { + //gc_dump_info(); + + gc_collect_start(); + gc_collect_regs_and_stack(); + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + #if MICROPY_EMIT_NATIVE + mp_unix_mark_exec(); + #endif + gc_collect_end(); + + //printf("-----\n"); + //gc_dump_info(); +} + +#endif //MICROPY_ENABLE_GC diff --git a/src/openmv/src/micropython/ports/unix/input.c b/src/openmv/src/micropython/ports/unix/input.c new file mode 100755 index 0000000..7d60b46 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/input.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mpstate.h" +#include "py/mphal.h" +#include "input.h" + +#if MICROPY_USE_READLINE == 1 +#include "lib/mp-readline/readline.h" +#endif + +#if MICROPY_USE_READLINE == 0 +char *prompt(char *p) { + // simple read string + static char buf[256]; + fputs(p, stdout); + char *s = fgets(buf, sizeof(buf), stdin); + if (!s) { + return NULL; + } + int l = strlen(buf); + if (buf[l - 1] == '\n') { + buf[l - 1] = 0; + } else { + l++; + } + char *line = malloc(l); + memcpy(line, buf, l); + return line; +} +#endif + +void prompt_read_history(void) { +#if MICROPY_USE_READLINE_HISTORY + #if MICROPY_USE_READLINE == 1 + readline_init0(); // will clear history pointers + char *home = getenv("HOME"); + if (home != NULL) { + vstr_t vstr; + vstr_init(&vstr, 50); + vstr_printf(&vstr, "%s/.micropython.history", home); + int fd = open(vstr_null_terminated_str(&vstr), O_RDONLY); + if (fd != -1) { + vstr_reset(&vstr); + for (;;) { + char c; + int sz = read(fd, &c, 1); + if (sz < 0) { + break; + } + if (sz == 0 || c == '\n') { + readline_push_history(vstr_null_terminated_str(&vstr)); + if (sz == 0) { + break; + } + vstr_reset(&vstr); + } else { + vstr_add_byte(&vstr, c); + } + } + close(fd); + } + vstr_clear(&vstr); + } + #endif +#endif +} + +void prompt_write_history(void) { +#if MICROPY_USE_READLINE_HISTORY + #if MICROPY_USE_READLINE == 1 + char *home = getenv("HOME"); + if (home != NULL) { + vstr_t vstr; + vstr_init(&vstr, 50); + vstr_printf(&vstr, "%s/.micropython.history", home); + int fd = open(vstr_null_terminated_str(&vstr), O_CREAT | O_TRUNC | O_WRONLY, 0644); + if (fd != -1) { + for (int i = MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)) - 1; i >= 0; i--) { + const char *line = MP_STATE_PORT(readline_hist)[i]; + if (line != NULL) { + int res; + res = write(fd, line, strlen(line)); + res = write(fd, "\n", 1); + (void)res; + } + } + close(fd); + } + } + #endif +#endif +} diff --git a/src/openmv/src/micropython/ports/unix/input.h b/src/openmv/src/micropython/ports/unix/input.h new file mode 100755 index 0000000..a76b87e --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/input.h @@ -0,0 +1,8 @@ +#ifndef MICROPY_INCLUDED_UNIX_INPUT_H +#define MICROPY_INCLUDED_UNIX_INPUT_H + +char *prompt(char *p); +void prompt_read_history(void); +void prompt_write_history(void); + +#endif // MICROPY_INCLUDED_UNIX_INPUT_H diff --git a/src/openmv/src/micropython/ports/unix/main.c b/src/openmv/src/micropython/ports/unix/main.c new file mode 100755 index 0000000..1cf237a --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/main.c @@ -0,0 +1,683 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/stackctrl.h" +#include "py/mphal.h" +#include "py/mpthread.h" +#include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" +#include "genhdr/mpversion.h" +#include "input.h" + +// Command line options, with their defaults +STATIC bool compile_only = false; +STATIC uint emit_opt = MP_EMIT_OPT_NONE; + +#if MICROPY_ENABLE_GC +// Heap size of GC heap (if enabled) +// Make it larger on a 64 bit machine, because pointers are larger. +long heap_size = 1024*1024 * (sizeof(mp_uint_t) / 4); +#endif + +STATIC void stderr_print_strn(void *env, const char *str, size_t len) { + (void)env; + ssize_t dummy = write(STDERR_FILENO, str, len); + mp_uos_dupterm_tx_strn(str, len); + (void)dummy; +} + +const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; + +#define FORCED_EXIT (0x100) +// If exc is SystemExit, return value where FORCED_EXIT bit set, +// and lower 8 bits are SystemExit value. For all other exceptions, +// return 1. +STATIC int handle_uncaught_exception(mp_obj_base_t *exc) { + // check for SystemExit + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + // None is an exit value of 0; an int is its value; anything else is 1 + mp_obj_t exit_val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc)); + mp_int_t val = 0; + if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) { + val = 1; + } + return FORCED_EXIT | (val & 255); + } + + // Report all other exceptions + mp_obj_print_exception(&mp_stderr_print, MP_OBJ_FROM_PTR(exc)); + return 1; +} + +#define LEX_SRC_STR (1) +#define LEX_SRC_VSTR (2) +#define LEX_SRC_FILENAME (3) +#define LEX_SRC_STDIN (4) + +// Returns standard error codes: 0 for success, 1 for all other errors, +// except if FORCED_EXIT bit is set then script raised SystemExit and the +// value of the exit is in the lower 8 bits of the return value +STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) { + mp_hal_set_interrupt_char(CHAR_CTRL_C); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // create lexer based on source kind + mp_lexer_t *lex; + if (source_kind == LEX_SRC_STR) { + const char *line = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); + } else if (source_kind == LEX_SRC_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false); + } else if (source_kind == LEX_SRC_FILENAME) { + lex = mp_lexer_new_from_file((const char*)source); + } else { // LEX_SRC_STDIN + lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); + } + + qstr source_name = lex->source_name; + + #if MICROPY_PY___FILE__ + if (input_kind == MP_PARSE_FILE_INPUT) { + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + } + #endif + + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + + #if defined(MICROPY_UNIX_COVERAGE) + // allow to print the parse tree in the coverage build + if (mp_verbose_flag >= 3) { + printf("----------------\n"); + mp_parse_node_print(parse_tree.root, 0); + printf("----------------\n"); + } + #endif + + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, emit_opt, is_repl); + + if (!compile_only) { + // execute it + mp_call_function_0(module_fun); + // check for pending exception + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + } + + mp_hal_set_interrupt_char(-1); + nlr_pop(); + return 0; + + } else { + // uncaught exception + mp_hal_set_interrupt_char(-1); + return handle_uncaught_exception(nlr.ret_val); + } +} + +#if MICROPY_USE_READLINE == 1 +#include "lib/mp-readline/readline.h" +#else +STATIC char *strjoin(const char *s1, int sep_char, const char *s2) { + int l1 = strlen(s1); + int l2 = strlen(s2); + char *s = malloc(l1 + l2 + 2); + memcpy(s, s1, l1); + if (sep_char != 0) { + s[l1] = sep_char; + l1 += 1; + } + memcpy(s + l1, s2, l2); + s[l1 + l2] = 0; + return s; +} +#endif + +STATIC int do_repl(void) { + mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " + MICROPY_PY_SYS_PLATFORM " version\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); + + #if MICROPY_USE_READLINE == 1 + + // use MicroPython supplied readline + + vstr_t line; + vstr_init(&line, 16); + for (;;) { + mp_hal_stdio_mode_raw(); + + input_restart: + vstr_reset(&line); + int ret = readline(&line, ">>> "); + mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; + + if (ret == CHAR_CTRL_C) { + // cancel input + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // EOF + printf("\n"); + mp_hal_stdio_mode_orig(); + vstr_clear(&line); + return 0; + } else if (ret == CHAR_CTRL_E) { + // paste mode + mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== "); + vstr_reset(&line); + for (;;) { + char c = mp_hal_stdin_rx_chr(); + if (c == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\n"); + goto input_restart; + } else if (c == CHAR_CTRL_D) { + // end of input + mp_hal_stdout_tx_str("\n"); + break; + } else { + // add char to buffer and echo + vstr_add_byte(&line, c); + if (c == '\r') { + mp_hal_stdout_tx_str("\n=== "); + } else { + mp_hal_stdout_tx_strn(&c, 1); + } + } + } + parse_input_kind = MP_PARSE_FILE_INPUT; + } else if (line.len == 0) { + if (ret != 0) { + printf("\n"); + } + goto input_restart; + } else { + // got a line with non-zero length, see if it needs continuing + while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { + vstr_add_byte(&line, '\n'); + ret = readline(&line, "... "); + if (ret == CHAR_CTRL_C) { + // cancel everything + printf("\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // stop entering compound statement + break; + } + } + } + + mp_hal_stdio_mode_orig(); + + ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); + if (ret & FORCED_EXIT) { + return ret; + } + } + + #else + + // use simple readline + + for (;;) { + char *line = prompt(">>> "); + if (line == NULL) { + // EOF + return 0; + } + while (mp_repl_continue_with_input(line)) { + char *line2 = prompt("... "); + if (line2 == NULL) { + break; + } + char *line3 = strjoin(line, '\n', line2); + free(line); + free(line2); + line = line3; + } + + int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); + if (ret & FORCED_EXIT) { + return ret; + } + free(line); + } + + #endif +} + +STATIC int do_file(const char *file) { + return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); +} + +STATIC int do_str(const char *str) { + return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false); +} + +STATIC int usage(char **argv) { + printf( +"usage: %s [] [-X ] [-c ] []\n" +"Options:\n" +"-v : verbose (trace various operations); can be multiple\n" +"-O[N] : apply bytecode optimizations of level N\n" +"\n" +"Implementation specific options (-X):\n", argv[0] +); + int impl_opts_cnt = 0; + printf( +" compile-only -- parse and compile only\n" +" emit={bytecode,native,viper} -- set the default code emitter\n" +); + impl_opts_cnt++; +#if MICROPY_ENABLE_GC + printf( +" heapsize=[w][K|M] -- set the heap size for the GC (default %ld)\n" +, heap_size); + impl_opts_cnt++; +#endif + + if (impl_opts_cnt == 0) { + printf(" (none)\n"); + } + + return 1; +} + +// Process options which set interpreter init options +STATIC void pre_process_options(int argc, char **argv) { + for (int a = 1; a < argc; a++) { + if (argv[a][0] == '-') { + if (strcmp(argv[a], "-X") == 0) { + if (a + 1 >= argc) { + exit(usage(argv)); + } + if (0) { + } else if (strcmp(argv[a + 1], "compile-only") == 0) { + compile_only = true; + } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { + emit_opt = MP_EMIT_OPT_BYTECODE; + } else if (strcmp(argv[a + 1], "emit=native") == 0) { + emit_opt = MP_EMIT_OPT_NATIVE_PYTHON; + } else if (strcmp(argv[a + 1], "emit=viper") == 0) { + emit_opt = MP_EMIT_OPT_VIPER; +#if MICROPY_ENABLE_GC + } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) { + char *end; + heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0); + // Don't bring unneeded libc dependencies like tolower() + // If there's 'w' immediately after number, adjust it for + // target word size. Note that it should be *before* size + // suffix like K or M, to avoid confusion with kilowords, + // etc. the size is still in bytes, just can be adjusted + // for word size (taking 32bit as baseline). + bool word_adjust = false; + if ((*end | 0x20) == 'w') { + word_adjust = true; + end++; + } + if ((*end | 0x20) == 'k') { + heap_size *= 1024; + } else if ((*end | 0x20) == 'm') { + heap_size *= 1024 * 1024; + } else { + // Compensate for ++ below + --end; + } + if (*++end != 0) { + goto invalid_arg; + } + if (word_adjust) { + heap_size = heap_size * BYTES_PER_WORD / 4; + } + // If requested size too small, we'll crash anyway + if (heap_size < 700) { + goto invalid_arg; + } +#endif + } else { +invalid_arg: + printf("Invalid option\n"); + exit(usage(argv)); + } + a++; + } + } + } +} + +STATIC void set_sys_argv(char *argv[], int argc, int start_arg) { + for (int i = start_arg; i < argc; i++) { + mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i]))); + } +} + +#ifdef _WIN32 +#define PATHLIST_SEP_CHAR ';' +#else +#define PATHLIST_SEP_CHAR ':' +#endif + +MP_NOINLINE int main_(int argc, char **argv); + +int main(int argc, char **argv) { + #if MICROPY_PY_THREAD + mp_thread_init(); + #endif + // We should capture stack top ASAP after start, and it should be + // captured guaranteedly before any other stack variables are allocated. + // For this, actual main (renamed main_) should not be inlined into + // this function. main_() itself may have other functions inlined (with + // their own stack variables), that's why we need this main/main_ split. + mp_stack_ctrl_init(); + return main_(argc, argv); +} + +MP_NOINLINE int main_(int argc, char **argv) { + #ifdef SIGPIPE + // Do not raise SIGPIPE, instead return EPIPE. Otherwise, e.g. writing + // to peer-closed socket will lead to sudden termination of MicroPython + // process. SIGPIPE is particularly nasty, because unix shell doesn't + // print anything for it, so the above looks like completely sudden and + // silent termination for unknown reason. Ignoring SIGPIPE is also what + // CPython does. Note that this may lead to problems using MicroPython + // scripts as pipe filters, but again, that's what CPython does. So, + // scripts which want to follow unix shell pipe semantics (where SIGPIPE + // means "pipe was requested to terminate, it's not an error"), should + // catch EPIPE themselves. + signal(SIGPIPE, SIG_IGN); + #endif + + mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); + + pre_process_options(argc, argv); + +#if MICROPY_ENABLE_GC + char *heap = malloc(heap_size); + gc_init(heap, heap + heap_size); +#endif + + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[1024]; + mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]); + #endif + + mp_init(); + + #if MICROPY_VFS_POSIX + { + // Mount the host FS at the root of our internal VFS + mp_obj_t args[2] = { + mp_type_vfs_posix.make_new(&mp_type_vfs_posix, 0, 0, NULL), + MP_OBJ_NEW_QSTR(MP_QSTR__slash_), + }; + mp_vfs_mount(2, args, (mp_map_t*)&mp_const_empty_map); + MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table); + } + #endif + + char *home = getenv("HOME"); + char *path = getenv("MICROPYPATH"); + if (path == NULL) { + #ifdef MICROPY_PY_SYS_PATH_DEFAULT + path = MICROPY_PY_SYS_PATH_DEFAULT; + #else + path = "~/.micropython/lib:/usr/lib/micropython"; + #endif + } + size_t path_num = 1; // [0] is for current dir (or base dir of the script) + if (*path == ':') { + path_num++; + } + for (char *p = path; p != NULL; p = strchr(p, PATHLIST_SEP_CHAR)) { + path_num++; + if (p != NULL) { + p++; + } + } + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), path_num); + mp_obj_t *path_items; + mp_obj_list_get(mp_sys_path, &path_num, &path_items); + path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_); + { + char *p = path; + for (mp_uint_t i = 1; i < path_num; i++) { + char *p1 = strchr(p, PATHLIST_SEP_CHAR); + if (p1 == NULL) { + p1 = p + strlen(p); + } + if (p[0] == '~' && p[1] == '/' && home != NULL) { + // Expand standalone ~ to $HOME + int home_l = strlen(home); + vstr_t vstr; + vstr_init(&vstr, home_l + (p1 - p - 1) + 1); + vstr_add_strn(&vstr, home, home_l); + vstr_add_strn(&vstr, p + 1, p1 - p - 1); + path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); + } else { + path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p); + } + p = p1 + 1; + } + } + + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + + #if defined(MICROPY_UNIX_COVERAGE) + { + MP_DECLARE_CONST_FUN_OBJ_0(extra_coverage_obj); + mp_store_global(QSTR_FROM_STR_STATIC("extra_coverage"), MP_OBJ_FROM_PTR(&extra_coverage_obj)); + } + #endif + + // Here is some example code to create a class and instance of that class. + // First is the Python, then the C code. + // + // class TestClass: + // pass + // test_obj = TestClass() + // test_obj.attr = 42 + // + // mp_obj_t test_class_type, test_class_instance; + // test_class_type = mp_obj_new_type(QSTR_FROM_STR_STATIC("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0)); + // mp_store_name(QSTR_FROM_STR_STATIC("test_obj"), test_class_instance = mp_call_function_0(test_class_type)); + // mp_store_attr(test_class_instance, QSTR_FROM_STR_STATIC("attr"), mp_obj_new_int(42)); + + /* + printf("bytes:\n"); + printf(" total %d\n", m_get_total_bytes_allocated()); + printf(" cur %d\n", m_get_current_bytes_allocated()); + printf(" peak %d\n", m_get_peak_bytes_allocated()); + */ + + const int NOTHING_EXECUTED = -2; + int ret = NOTHING_EXECUTED; + bool inspect = false; + for (int a = 1; a < argc; a++) { + if (argv[a][0] == '-') { + if (strcmp(argv[a], "-i") == 0) { + inspect = true; + } else if (strcmp(argv[a], "-c") == 0) { + if (a + 1 >= argc) { + return usage(argv); + } + ret = do_str(argv[a + 1]); + if (ret & FORCED_EXIT) { + break; + } + a += 1; + } else if (strcmp(argv[a], "-m") == 0) { + if (a + 1 >= argc) { + return usage(argv); + } + mp_obj_t import_args[4]; + import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1])); + import_args[1] = import_args[2] = mp_const_none; + // Ask __import__ to handle imported module specially - set its __name__ + // to __main__, and also return this leaf module, not top-level package + // containing it. + import_args[3] = mp_const_false; + // TODO: https://docs.python.org/3/using/cmdline.html#cmdoption-m : + // "the first element of sys.argv will be the full path to + // the module file (while the module file is being located, + // the first element will be set to "-m")." + set_sys_argv(argv, argc, a + 1); + + mp_obj_t mod; + nlr_buf_t nlr; + bool subpkg_tried = false; + + reimport: + if (nlr_push(&nlr) == 0) { + mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); + nlr_pop(); + } else { + // uncaught exception + return handle_uncaught_exception(nlr.ret_val) & 0xff; + } + + if (mp_obj_is_package(mod) && !subpkg_tried) { + subpkg_tried = true; + vstr_t vstr; + int len = strlen(argv[a + 1]); + vstr_init(&vstr, len + sizeof(".__main__")); + vstr_add_strn(&vstr, argv[a + 1], len); + vstr_add_strn(&vstr, ".__main__", sizeof(".__main__") - 1); + import_args[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); + goto reimport; + } + + ret = 0; + break; + } else if (strcmp(argv[a], "-X") == 0) { + a += 1; + #if MICROPY_DEBUG_PRINTERS + } else if (strcmp(argv[a], "-v") == 0) { + mp_verbose_flag++; + #endif + } else if (strncmp(argv[a], "-O", 2) == 0) { + if (unichar_isdigit(argv[a][2])) { + MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf; + } else { + MP_STATE_VM(mp_optimise_value) = 0; + for (char *p = argv[a] + 1; *p && *p == 'O'; p++, MP_STATE_VM(mp_optimise_value)++); + } + } else { + return usage(argv); + } + } else { + char *pathbuf = malloc(PATH_MAX); + char *basedir = realpath(argv[a], pathbuf); + if (basedir == NULL) { + mp_printf(&mp_stderr_print, "%s: can't open file '%s': [Errno %d] %s\n", argv[0], argv[a], errno, strerror(errno)); + // CPython exits with 2 in such case + ret = 2; + break; + } + + // Set base dir of the script as first entry in sys.path + char *p = strrchr(basedir, '/'); + path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir); + free(pathbuf); + + set_sys_argv(argv, argc, a); + ret = do_file(argv[a]); + break; + } + } + + if (ret == NOTHING_EXECUTED || inspect) { + if (isatty(0)) { + prompt_read_history(); + ret = do_repl(); + prompt_write_history(); + } else { + ret = execute_from_lexer(LEX_SRC_STDIN, NULL, MP_PARSE_FILE_INPUT, false); + } + } + + #if MICROPY_PY_MICROPYTHON_MEM_INFO + if (mp_verbose_flag) { + mp_micropython_mem_info(0, NULL); + } + #endif + + #if defined(MICROPY_UNIX_COVERAGE) + gc_sweep_all(); + #endif + + mp_deinit(); + +#if MICROPY_ENABLE_GC && !defined(NDEBUG) + // We don't really need to free memory since we are about to exit the + // process, but doing so helps to find memory leaks. + free(heap); +#endif + + //printf("total bytes = %d\n", m_get_total_bytes_allocated()); + return ret & 0xff; +} + +#if !MICROPY_VFS +uint mp_import_stat(const char *path) { + struct stat st; + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return MP_IMPORT_STAT_DIR; + } else if (S_ISREG(st.st_mode)) { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} +#endif + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught NLR %p\n", val); + exit(1); +} diff --git a/src/openmv/src/micropython/ports/unix/modffi.c b/src/openmv/src/micropython/ports/unix/modffi.c new file mode 100755 index 0000000..c262721 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modffi.c @@ -0,0 +1,506 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/mperrno.h" + +/* + * modffi uses character codes to encode a value type, based on "struct" + * module type codes, with some extensions and overridings. + * + * Extra/overridden typecodes: + * v - void, can be used only as return type + * P - const void*, pointer to read-only memory + * p - void*, meaning pointer to a writable memory (note that this + * clashes with struct's "p" as "Pascal string"). + * s - as argument, the same as "p", as return value, causes string + * to be allocated and returned, instead of pointer value. + * O - mp_obj_t, passed as is (mostly useful as a callback param) + * + * TODO: + * C - callback function + * + * Note: all constraint specified by typecode can be not enforced at this time, + * but may be later. + */ + +typedef struct _mp_obj_opaque_t { + mp_obj_base_t base; + void *val; +} mp_obj_opaque_t; + +typedef struct _mp_obj_ffimod_t { + mp_obj_base_t base; + void *handle; +} mp_obj_ffimod_t; + +typedef struct _mp_obj_ffivar_t { + mp_obj_base_t base; + void *var; + char type; +// ffi_type *type; +} mp_obj_ffivar_t; + +typedef struct _mp_obj_ffifunc_t { + mp_obj_base_t base; + void *func; + char rettype; + const char *argtypes; + ffi_cif cif; + ffi_type *params[]; +} mp_obj_ffifunc_t; + +typedef struct _mp_obj_fficallback_t { + mp_obj_base_t base; + void *func; + ffi_closure *clo; + char rettype; + ffi_cif cif; + ffi_type *params[]; +} mp_obj_fficallback_t; + +//STATIC const mp_obj_type_t opaque_type; +STATIC const mp_obj_type_t ffimod_type; +STATIC const mp_obj_type_t ffifunc_type; +STATIC const mp_obj_type_t fficallback_type; +STATIC const mp_obj_type_t ffivar_type; + +STATIC ffi_type *char2ffi_type(char c) +{ + switch (c) { + case 'b': return &ffi_type_schar; + case 'B': return &ffi_type_uchar; + case 'h': return &ffi_type_sshort; + case 'H': return &ffi_type_ushort; + case 'i': return &ffi_type_sint; + case 'I': return &ffi_type_uint; + case 'l': return &ffi_type_slong; + case 'L': return &ffi_type_ulong; + case 'q': return &ffi_type_sint64; + case 'Q': return &ffi_type_uint64; + #if MICROPY_PY_BUILTINS_FLOAT + case 'f': return &ffi_type_float; + case 'd': return &ffi_type_double; + #endif + case 'O': // mp_obj_t + case 'C': // (*)() + case 'P': // const void* + case 'p': // void* + case 's': return &ffi_type_pointer; + case 'v': return &ffi_type_void; + default: return NULL; + } +} + +STATIC ffi_type *get_ffi_type(mp_obj_t o_in) +{ + if (MP_OBJ_IS_STR(o_in)) { + const char *s = mp_obj_str_get_str(o_in); + ffi_type *t = char2ffi_type(*s); + if (t != NULL) { + return t; + } + } + // TODO: Support actual libffi type objects + + mp_raise_TypeError("Unknown type"); +} + +STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) +{ + switch (type) { + case 's': { + const char *s = (const char *)(intptr_t)val; + if (!s) { + return mp_const_none; + } + return mp_obj_new_str(s, strlen(s)); + } + case 'v': + return mp_const_none; + #if MICROPY_PY_BUILTINS_FLOAT + case 'f': { + union { ffi_arg ffi; float flt; } val_union = { .ffi = val }; + return mp_obj_new_float(val_union.flt); + } + case 'd': { + double *p = (double*)&val; + return mp_obj_new_float(*p); + } + #endif + case 'O': + return (mp_obj_t)(intptr_t)val; + default: + return mp_obj_new_int(val); + } +} + +// FFI module + +STATIC void ffimod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->handle); +} + +STATIC mp_obj_t ffimod_close(mp_obj_t self_in) { + mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in); + dlclose(self->handle); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close); + +STATIC mp_obj_t make_func(mp_obj_t rettype_in, void *func, mp_obj_t argtypes_in) { + const char *rettype = mp_obj_str_get_str(rettype_in); + const char *argtypes = mp_obj_str_get_str(argtypes_in); + + mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(argtypes_in)); + mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type*, nparams); + o->base.type = &ffifunc_type; + + o->func = func; + o->rettype = *rettype; + o->argtypes = argtypes; + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(argtypes_in, &iter_buf); + mp_obj_t item; + int i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + o->params[i++] = get_ffi_type(item); + } + + int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); + if (res != FFI_OK) { + mp_raise_ValueError("Error in ffi_prep_cif"); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t ffimod_func(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(args[0]); + const char *symname = mp_obj_str_get_str(args[2]); + + void *sym = dlsym(self->handle, symname); + if (sym == NULL) { + mp_raise_OSError(MP_ENOENT); + } + return make_func(args[1], sym, args[3]); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func); + +STATIC mp_obj_t mod_ffi_func(mp_obj_t rettype, mp_obj_t addr_in, mp_obj_t argtypes) { + void *addr = (void*)MP_OBJ_TO_PTR(mp_obj_int_get_truncated(addr_in)); + return make_func(rettype, addr, argtypes); +} +MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_func_obj, mod_ffi_func); + +STATIC void call_py_func(ffi_cif *cif, void *ret, void** args, void *func) { + mp_obj_t pyargs[cif->nargs]; + for (uint i = 0; i < cif->nargs; i++) { + pyargs[i] = mp_obj_new_int(*(mp_int_t*)args[i]); + } + mp_obj_t res = mp_call_function_n_kw(MP_OBJ_FROM_PTR(func), cif->nargs, 0, pyargs); + + if (res != mp_const_none) { + *(ffi_arg*)ret = mp_obj_int_get_truncated(res); + } +} + +STATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t paramtypes_in) { + const char *rettype = mp_obj_str_get_str(rettype_in); + + mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in)); + mp_obj_fficallback_t *o = m_new_obj_var(mp_obj_fficallback_t, ffi_type*, nparams); + o->base.type = &fficallback_type; + + o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func); + + o->rettype = *rettype; + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(paramtypes_in, &iter_buf); + mp_obj_t item; + int i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + o->params[i++] = get_ffi_type(item); + } + + int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); + if (res != FFI_OK) { + mp_raise_ValueError("Error in ffi_prep_cif"); + } + + res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, MP_OBJ_TO_PTR(func_in), o->func); + if (res != FFI_OK) { + mp_raise_ValueError("ffi_prep_closure_loc"); + } + + return MP_OBJ_FROM_PTR(o); +} +MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_callback_obj, mod_ffi_callback); + +STATIC mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) { + mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in); + const char *rettype = mp_obj_str_get_str(vartype_in); + const char *symname = mp_obj_str_get_str(symname_in); + + void *sym = dlsym(self->handle, symname); + if (sym == NULL) { + mp_raise_OSError(MP_ENOENT); + } + mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t); + o->base.type = &ffivar_type; + + o->var = sym; + o->type = *rettype; + return MP_OBJ_FROM_PTR(o); +} +MP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var); + +STATIC mp_obj_t ffimod_addr(mp_obj_t self_in, mp_obj_t symname_in) { + mp_obj_ffimod_t *self = MP_OBJ_TO_PTR(self_in); + const char *symname = mp_obj_str_get_str(symname_in); + + void *sym = dlsym(self->handle, symname); + if (sym == NULL) { + mp_raise_OSError(MP_ENOENT); + } + return mp_obj_new_int((uintptr_t)sym); +} +MP_DEFINE_CONST_FUN_OBJ_2(ffimod_addr_obj, ffimod_addr); + +STATIC mp_obj_t ffimod_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)n_args; + (void)n_kw; + + const char *fname = NULL; + if (args[0] != mp_const_none) { + fname = mp_obj_str_get_str(args[0]); + } + void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL); + + if (mod == NULL) { + mp_raise_OSError(errno); + } + mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t); + o->base.type = type; + o->handle = mod; + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_rom_map_elem_t ffimod_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&ffimod_func_obj) }, + { MP_ROM_QSTR(MP_QSTR_var), MP_ROM_PTR(&ffimod_var_obj) }, + { MP_ROM_QSTR(MP_QSTR_addr), MP_ROM_PTR(&ffimod_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&ffimod_close_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ffimod_locals_dict, ffimod_locals_dict_table); + +STATIC const mp_obj_type_t ffimod_type = { + { &mp_type_type }, + .name = MP_QSTR_ffimod, + .print = ffimod_print, + .make_new = ffimod_make_new, + .locals_dict = (mp_obj_dict_t*)&ffimod_locals_dict, +}; + +// FFI function + +STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->func); +} + +STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in); + assert(n_kw == 0); + assert(n_args == self->cif.nargs); + + ffi_arg values[n_args]; + void *valueptrs[n_args]; + const char *argtype = self->argtypes; + for (uint i = 0; i < n_args; i++, argtype++) { + mp_obj_t a = args[i]; + if (*argtype == 'O') { + values[i] = (ffi_arg)(intptr_t)a; + #if MICROPY_PY_BUILTINS_FLOAT + } else if (*argtype == 'f') { + float *p = (float*)&values[i]; + *p = mp_obj_get_float(a); + } else if (*argtype == 'd') { + double *p = (double*)&values[i]; + *p = mp_obj_get_float(a); + #endif + } else if (a == mp_const_none) { + values[i] = 0; + } else if (MP_OBJ_IS_INT(a)) { + values[i] = mp_obj_int_get_truncated(a); + } else if (MP_OBJ_IS_STR(a)) { + const char *s = mp_obj_str_get_str(a); + values[i] = (ffi_arg)(intptr_t)s; + } else if (((mp_obj_base_t*)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) { + mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(a); + mp_buffer_info_t bufinfo; + int ret = o->type->buffer_p.get_buffer(MP_OBJ_FROM_PTR(o), &bufinfo, MP_BUFFER_READ); // TODO: MP_BUFFER_READ? + if (ret != 0) { + goto error; + } + values[i] = (ffi_arg)(intptr_t)bufinfo.buf; + } else if (MP_OBJ_IS_TYPE(a, &fficallback_type)) { + mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a); + values[i] = (ffi_arg)(intptr_t)p->func; + } else { + goto error; + } + valueptrs[i] = &values[i]; + } + + // If ffi_arg is not big enough to hold a double, then we must pass along a + // pointer to a memory location of the correct size. + // TODO check if this needs to be done for other types which don't fit into + // ffi_arg. + #if MICROPY_PY_BUILTINS_FLOAT + if (sizeof(ffi_arg) == 4 && self->rettype == 'd') { + double retval; + ffi_call(&self->cif, self->func, &retval, valueptrs); + return mp_obj_new_float(retval); + } else + #endif + { + ffi_arg retval; + ffi_call(&self->cif, self->func, &retval, valueptrs); + return return_ffi_value(retval, self->rettype); + } + +error: + mp_raise_TypeError("Don't know how to pass object to native function"); +} + +STATIC const mp_obj_type_t ffifunc_type = { + { &mp_type_type }, + .name = MP_QSTR_ffifunc, + .print = ffifunc_print, + .call = ffifunc_call, +}; + +// FFI callback for Python function + +STATIC void fficallback_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_fficallback_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->func); +} + +STATIC const mp_obj_type_t fficallback_type = { + { &mp_type_type }, + .name = MP_QSTR_fficallback, + .print = fficallback_print, +}; + +// FFI variable + +STATIC void ffivar_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in); + // Variable value printed as cast to int + mp_printf(print, "", self->var, *(int*)self->var); +} + +STATIC mp_obj_t ffivar_get(mp_obj_t self_in) { + mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in); + return mp_binary_get_val_array(self->type, self->var, 0); +} +MP_DEFINE_CONST_FUN_OBJ_1(ffivar_get_obj, ffivar_get); + +STATIC mp_obj_t ffivar_set(mp_obj_t self_in, mp_obj_t val_in) { + mp_obj_ffivar_t *self = MP_OBJ_TO_PTR(self_in); + mp_binary_set_val_array(self->type, self->var, 0, val_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(ffivar_set_obj, ffivar_set); + +STATIC const mp_rom_map_elem_t ffivar_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ffivar_locals_dict, ffivar_locals_dict_table); + +STATIC const mp_obj_type_t ffivar_type = { + { &mp_type_type }, + .name = MP_QSTR_ffivar, + .print = ffivar_print, + .locals_dict = (mp_obj_dict_t*)&ffivar_locals_dict, +}; + +// Generic opaque storage object (unused) + +/* +STATIC const mp_obj_type_t opaque_type = { + { &mp_type_type }, + .name = MP_QSTR_opaqueval, +// .print = opaque_print, +}; +*/ + +STATIC mp_obj_t mod_ffi_open(size_t n_args, const mp_obj_t *args) { + return ffimod_make_new(&ffimod_type, n_args, 0, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open); + +STATIC mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) { + return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void*)(uintptr_t)mp_obj_int_get_truncated(ptr)); +} +MP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray); + +STATIC const mp_rom_map_elem_t mp_module_ffi_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ffi) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_ffi_open_obj) }, + { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_ffi_callback_obj) }, + { MP_ROM_QSTR(MP_QSTR_func), MP_ROM_PTR(&mod_ffi_func_obj) }, + { MP_ROM_QSTR(MP_QSTR_as_bytearray), MP_ROM_PTR(&mod_ffi_as_bytearray_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ffi_globals, mp_module_ffi_globals_table); + +const mp_obj_module_t mp_module_ffi = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ffi_globals, +}; diff --git a/src/openmv/src/micropython/ports/unix/modjni.c b/src/openmv/src/micropython/ports/unix/modjni.c new file mode 100755 index 0000000..9e8c232 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modjni.c @@ -0,0 +1,719 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" + +#include + +#define JJ(call, ...) (*env)->call(env, __VA_ARGS__) +#define JJ1(call) (*env)->call(env) +#define MATCH(s, static) (!strncmp(s, static, sizeof(static) - 1)) + +static JavaVM *jvm; +static JNIEnv *env; +static jclass Class_class; +static jclass String_class; +static jmethodID Class_getName_mid; +static jmethodID Class_getField_mid; +static jmethodID Class_getMethods_mid; +static jmethodID Class_getConstructors_mid; +static jmethodID Method_getName_mid; +static jmethodID Object_toString_mid; + +static jclass List_class; +static jmethodID List_get_mid; +static jmethodID List_set_mid; +static jmethodID List_size_mid; + +static jclass IndexException_class; + +STATIC const mp_obj_type_t jobject_type; +STATIC const mp_obj_type_t jmethod_type; + +STATIC mp_obj_t new_jobject(jobject jo); +STATIC mp_obj_t new_jclass(jclass jc); +STATIC mp_obj_t call_method(jobject obj, const char *name, jarray methods, bool is_constr, size_t n_args, const mp_obj_t *args); +STATIC bool py2jvalue(const char **jtypesig, mp_obj_t arg, jvalue *out); + +typedef struct _mp_obj_jclass_t { + mp_obj_base_t base; + jclass cls; +} mp_obj_jclass_t; + +typedef struct _mp_obj_jobject_t { + mp_obj_base_t base; + jobject obj; +} mp_obj_jobject_t; + +typedef struct _mp_obj_jmethod_t { + mp_obj_base_t base; + jobject obj; + jmethodID meth; + qstr name; + bool is_static; +} mp_obj_jmethod_t; + +// Utility functions + +STATIC bool is_object_type(const char *jtypesig) { + while (*jtypesig != ' ' && *jtypesig) { + if (*jtypesig == '.') { + return true; + } + jtypesig++; + } + return false; +} + +STATIC void check_exception(void) { + jobject exc = JJ1(ExceptionOccurred); + if (exc) { + //JJ1(ExceptionDescribe); + mp_obj_t py_e = new_jobject(exc); + JJ1(ExceptionClear); + if (JJ(IsInstanceOf, exc, IndexException_class)) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, py_e)); + } + nlr_raise(mp_obj_new_exception_arg1(&mp_type_Exception, py_e)); + } +} + +STATIC void print_jobject(const mp_print_t *print, jobject obj) { + jobject str_o = JJ(CallObjectMethod, obj, Object_toString_mid); + const char *str = JJ(GetStringUTFChars, str_o, NULL); + mp_printf(print, str); + JJ(ReleaseStringUTFChars, str_o, str); +} + +// jclass + +STATIC void jclass_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_jclass_t *self = MP_OBJ_TO_PTR(self_in); + if (kind == PRINT_REPR) { + mp_printf(print, "cls); + } + print_jobject(print, self->cls); + if (kind == PRINT_REPR) { + mp_printf(print, "\">"); + } +} + +STATIC void jclass_attr(mp_obj_t self_in, qstr attr_in, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_jclass_t *self = MP_OBJ_TO_PTR(self_in); + const char *attr = qstr_str(attr_in); + + jstring field_name = JJ(NewStringUTF, attr); + jobject field = JJ(CallObjectMethod, self->cls, Class_getField_mid, field_name); + if (!JJ1(ExceptionCheck)) { + jfieldID field_id = JJ(FromReflectedField, field); + jobject obj = JJ(GetStaticObjectField, self->cls, field_id); + dest[0] = new_jobject(obj); + return; + } + //JJ1(ExceptionDescribe); + JJ1(ExceptionClear); + + mp_obj_jmethod_t *o = m_new_obj(mp_obj_jmethod_t); + o->base.type = &jmethod_type; + o->name = attr_in; + o->meth = NULL; + o->obj = self->cls; + o->is_static = true; + dest[0] = MP_OBJ_FROM_PTR(o); + } +} + +STATIC mp_obj_t jclass_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + if (n_kw != 0) { + mp_raise_TypeError("kwargs not supported"); + } + mp_obj_jclass_t *self = MP_OBJ_TO_PTR(self_in); + + jarray methods = JJ(CallObjectMethod, self->cls, Class_getConstructors_mid); + + return call_method(self->cls, NULL, methods, true, n_args, args); +} + +STATIC const mp_rom_map_elem_t jclass_locals_dict_table[] = { +// { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ffivar_get_obj) }, +// { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&ffivar_set_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(jclass_locals_dict, jclass_locals_dict_table); + +STATIC const mp_obj_type_t jclass_type = { + { &mp_type_type }, + .name = MP_QSTR_jclass, + .print = jclass_print, + .attr = jclass_attr, + .call = jclass_call, + .locals_dict = (mp_obj_dict_t*)&jclass_locals_dict, +}; + +STATIC mp_obj_t new_jclass(jclass jc) { + mp_obj_jclass_t *o = m_new_obj(mp_obj_jclass_t); + o->base.type = &jclass_type; + o->cls = jc; + return MP_OBJ_FROM_PTR(o); +} + +// jobject + +STATIC void jobject_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_jobject_t *self = MP_OBJ_TO_PTR(self_in); + if (kind == PRINT_REPR) { + mp_printf(print, "obj); + } + print_jobject(print, self->obj); + if (kind == PRINT_REPR) { + mp_printf(print, "\">"); + } +} + +STATIC void jobject_attr(mp_obj_t self_in, qstr attr_in, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_jobject_t *self = MP_OBJ_TO_PTR(self_in); + + const char *attr = qstr_str(attr_in); + jclass obj_class = JJ(GetObjectClass, self->obj); + jstring field_name = JJ(NewStringUTF, attr); + jobject field = JJ(CallObjectMethod, obj_class, Class_getField_mid, field_name); + JJ(DeleteLocalRef, field_name); + JJ(DeleteLocalRef, obj_class); + if (!JJ1(ExceptionCheck)) { + jfieldID field_id = JJ(FromReflectedField, field); + JJ(DeleteLocalRef, field); + jobject obj = JJ(GetObjectField, self->obj, field_id); + dest[0] = new_jobject(obj); + return; + } + //JJ1(ExceptionDescribe); + JJ1(ExceptionClear); + + mp_obj_jmethod_t *o = m_new_obj(mp_obj_jmethod_t); + o->base.type = &jmethod_type; + o->name = attr_in; + o->meth = NULL; + o->obj = self->obj; + o->is_static = false; + dest[0] = MP_OBJ_FROM_PTR(o); + } +} + +STATIC void get_jclass_name(jobject obj, char *buf) { + jclass obj_class = JJ(GetObjectClass, obj); + jstring name = JJ(CallObjectMethod, obj_class, Class_getName_mid); + jint len = JJ(GetStringLength, name); + JJ(GetStringUTFRegion, name, 0, len, buf); + check_exception(); +} + +STATIC mp_obj_t jobject_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_jobject_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t idx = mp_obj_get_int(index); + char class_name[64]; + get_jclass_name(self->obj, class_name); + //printf("class: %s\n", class_name); + + if (class_name[0] == '[') { + if (class_name[1] == 'L' || class_name[1] == '[') { + if (value == MP_OBJ_NULL) { + // delete + assert(0); + } else if (value == MP_OBJ_SENTINEL) { + // load + jobject el = JJ(GetObjectArrayElement, self->obj, idx); + return new_jobject(el); + } else { + // store + jvalue jval; + const char *t = class_name + 1; + py2jvalue(&t, value, &jval); + JJ(SetObjectArrayElement, self->obj, idx, jval.l); + return mp_const_none; + } + } + mp_raise_NotImplementedError(NULL); + } + + if (!JJ(IsInstanceOf, self->obj, List_class)) { + return MP_OBJ_NULL; + } + + + if (value == MP_OBJ_NULL) { + // delete + assert(0); + } else if (value == MP_OBJ_SENTINEL) { + // load + jobject el = JJ(CallObjectMethod, self->obj, List_get_mid, idx); + check_exception(); + return new_jobject(el); + } else { + // store + assert(0); + } + + +return MP_OBJ_NULL; +} + +STATIC mp_obj_t jobject_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_jobject_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: + case MP_UNARY_OP_LEN: { + jint len = JJ(CallIntMethod, self->obj, List_size_mid); + if (op == MP_UNARY_OP_BOOL) { + return mp_obj_new_bool(len != 0); + } + return MP_OBJ_NEW_SMALL_INT(len); + } + default: + return MP_OBJ_NULL; // op not supported + } +} + +// TODO: subscr_load_adaptor & subscr_getiter convenience functions +// should be moved to common location for reuse. +STATIC mp_obj_t subscr_load_adaptor(mp_obj_t self_in, mp_obj_t index_in) { + return mp_obj_subscr(self_in, index_in, MP_OBJ_SENTINEL); +} +MP_DEFINE_CONST_FUN_OBJ_2(subscr_load_adaptor_obj, subscr_load_adaptor); + +// .getiter special method which returns iterator which works in terms +// of object subscription. +STATIC mp_obj_t subscr_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + mp_obj_t dest[2] = {MP_OBJ_FROM_PTR(&subscr_load_adaptor_obj), self_in}; + return mp_obj_new_getitem_iter(dest, iter_buf); +} + +STATIC const mp_obj_type_t jobject_type = { + { &mp_type_type }, + .name = MP_QSTR_jobject, + .print = jobject_print, + .unary_op = jobject_unary_op, + .attr = jobject_attr, + .subscr = jobject_subscr, + .getiter = subscr_getiter, +// .locals_dict = (mp_obj_dict_t*)&jobject_locals_dict, +}; + +STATIC mp_obj_t new_jobject(jobject jo) { + if (jo == NULL) { + return mp_const_none; + } else if (JJ(IsInstanceOf, jo, String_class)) { + const char *s = JJ(GetStringUTFChars, jo, NULL); + mp_obj_t ret = mp_obj_new_str(s, strlen(s)); + JJ(ReleaseStringUTFChars, jo, s); + return ret; + } else if (JJ(IsInstanceOf, jo, Class_class)) { + return new_jclass(jo); + } else { + mp_obj_jobject_t *o = m_new_obj(mp_obj_jobject_t); + o->base.type = &jobject_type; + o->obj = jo; + return MP_OBJ_FROM_PTR(o); + } + +} + + +// jmethod + +STATIC void jmethod_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_jmethod_t *self = MP_OBJ_TO_PTR(self_in); + // Variable value printed as cast to int + mp_printf(print, "", qstr_str(self->name)); +} + +#define IMATCH(s, static) ((!strncmp(s, static, sizeof(static) - 1)) && (s += sizeof(static) - 1)) + +#define CHECK_TYPE(java_type_name) \ + if (strncmp(arg_type, java_type_name, sizeof(java_type_name) - 1) != 0) { \ + return false; \ + } \ + arg_type += sizeof(java_type_name) - 1; + +STATIC const char *strprev(const char *s, char c) { + while (*s != c) { + s--; + } + return s; +} + +STATIC bool py2jvalue(const char **jtypesig, mp_obj_t arg, jvalue *out) { + const char *arg_type = *jtypesig; + mp_obj_type_t *type = mp_obj_get_type(arg); + + if (type == &mp_type_str) { + if (IMATCH(arg_type, "java.lang.String") || IMATCH(arg_type, "java.lang.Object")) { + out->l = JJ(NewStringUTF, mp_obj_str_get_str(arg)); + } else { + return false; + } + } else if (type == &mp_type_int) { + if (IMATCH(arg_type, "int") || IMATCH(arg_type, "long")) { + // TODO: Java long is 64-bit actually + out->j = mp_obj_get_int(arg); + } else { + return false; + } + } else if (type == &jobject_type) { + bool is_object = false; + const char *expected_type = arg_type; + while (1) { + if (isalpha(*arg_type)) { + } else if (*arg_type == '.') { + is_object = true; + } else { + break; + } + arg_type++; + } + if (!is_object) { + return false; + } + mp_obj_jobject_t *jo = MP_OBJ_TO_PTR(arg); + if (!MATCH(expected_type, "java.lang.Object")) { + char class_name[64]; + get_jclass_name(jo->obj, class_name); + //printf("Arg class: %s\n", class_name); + if (strcmp(class_name, expected_type) != 0) { + return false; + } + } + out->l = jo->obj; + } else if (type == &mp_type_bool) { + if (IMATCH(arg_type, "boolean")) { + out->z = arg == mp_const_true; + } else { + return false; + } + } else if (arg == mp_const_none) { + //printf("TODO: Check java arg type!!\n"); + while (isalpha(*arg_type) || *arg_type == '.') { + arg_type++; + } + out->l = NULL; + } else { + mp_raise_TypeError("arg type not supported"); + } + + *jtypesig = arg_type; + return true; +} + +#if 0 +// jvalue is known to be union of jobject and friends. And yet from C's +// perspective, it's aggregate object which may require passing via stack +// instead of registers. Work that around by passing jobject and typecasting +// it. +STATIC mp_obj_t jvalue2py(const char *jtypesig, jobject arg) { + if (arg == NULL || MATCH(jtypesig, "void")) { + return mp_const_none; + } else if (MATCH(jtypesig, "boolean")) { + return mp_obj_new_bool((bool)arg); + } else if (MATCH(jtypesig, "int")) { + return mp_obj_new_int((mp_int_t)arg); + } else if (is_object_type(jtypesig)) { + // Non-primitive, object type + return new_jobject(arg); + } + + printf("Unknown return type: %s\n", jtypesig); + + return MP_OBJ_NULL; +} +#endif + +STATIC mp_obj_t call_method(jobject obj, const char *name, jarray methods, bool is_constr, size_t n_args, const mp_obj_t *args) { + jvalue jargs[n_args]; +// printf("methods=%p\n", methods); + jsize num_methods = JJ(GetArrayLength, methods); + for (int i = 0; i < num_methods; i++) { + jobject meth = JJ(GetObjectArrayElement, methods, i); + jobject name_o = JJ(CallObjectMethod, meth, Object_toString_mid); + const char *decl = JJ(GetStringUTFChars, name_o, NULL); + const char *arg_types = strchr(decl, '(') + 1; + //const char *arg_types_end = strchr(arg_types, ')'); +// printf("method[%d]=%p %s\n", i, meth, decl); + + const char *meth_name = NULL; + const char *ret_type = NULL; + if (!is_constr) { + meth_name = strprev(arg_types, '.') + 1; + ret_type = strprev(meth_name, ' ') - 1; + ret_type = strprev(ret_type, ' ') + 1; + + int name_len = strlen(name); + if (strncmp(name, meth_name, name_len/*arg_types - meth_name - 1*/) || meth_name[name_len] != '('/*(*/) { + goto next_method; + } + } +// printf("method[%d]=%p %s\n", i, meth, decl); +// printf("!!!%s\n", arg_types); +// printf("name=%p meth_name=%s\n", name, meth_name); + + bool found = true; + for (size_t j = 0; j < n_args && *arg_types != ')'; j++) { + if (!py2jvalue(&arg_types, args[j], &jargs[j])) { + goto next_method; + } + + if (*arg_types == ',') { + arg_types++; + } + } + + if (*arg_types != ')') { + goto next_method; + } + + if (found) { +// printf("found!\n"); + jmethodID method_id = JJ(FromReflectedMethod, meth); + if (is_constr) { + JJ(ReleaseStringUTFChars, name_o, decl); + jobject res = JJ(NewObjectA, obj, method_id, jargs); + return new_jobject(res); + } else { + mp_obj_t ret; + if (MATCH(ret_type, "void")) { + JJ(CallVoidMethodA, obj, method_id, jargs); + check_exception(); + ret = mp_const_none; + } else if (MATCH(ret_type, "int")) { + jint res = JJ(CallIntMethodA, obj, method_id, jargs); + check_exception(); + ret = mp_obj_new_int(res); + } else if (MATCH(ret_type, "boolean")) { + jboolean res = JJ(CallBooleanMethodA, obj, method_id, jargs); + check_exception(); + ret = mp_obj_new_bool(res); + } else if (is_object_type(ret_type)) { + jobject res = JJ(CallObjectMethodA, obj, method_id, jargs); + check_exception(); + ret = new_jobject(res); + } else { + JJ(ReleaseStringUTFChars, name_o, decl); + mp_raise_TypeError("cannot handle return type"); + } + + JJ(ReleaseStringUTFChars, name_o, decl); + JJ(DeleteLocalRef, name_o); + JJ(DeleteLocalRef, meth); + return ret; + } + } + +next_method: + JJ(ReleaseStringUTFChars, name_o, decl); + JJ(DeleteLocalRef, name_o); + JJ(DeleteLocalRef, meth); + } + + mp_raise_TypeError("method not found"); +} + + +STATIC mp_obj_t jmethod_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + if (n_kw != 0) { + mp_raise_TypeError("kwargs not supported"); + } + mp_obj_jmethod_t *self = MP_OBJ_TO_PTR(self_in); + + const char *name = qstr_str(self->name); +// jstring meth_name = JJ(NewStringUTF, name); + + jclass obj_class = self->obj; + if (!self->is_static) { + obj_class = JJ(GetObjectClass, self->obj); + } + jarray methods = JJ(CallObjectMethod, obj_class, Class_getMethods_mid); + + return call_method(self->obj, name, methods, false, n_args, args); +} + +STATIC const mp_obj_type_t jmethod_type = { + { &mp_type_type }, + .name = MP_QSTR_jmethod, + .print = jmethod_print, + .call = jmethod_call, +// .attr = jobject_attr, +// .locals_dict = (mp_obj_dict_t*)&jobject_locals_dict, +}; + +#ifdef __ANDROID__ +#define LIBJVM_SO "libdvm.so" +#else +#define LIBJVM_SO "libjvm.so" +#endif + +STATIC void create_jvm(void) { + JavaVMInitArgs args; + JavaVMOption options; + options.optionString = "-Djava.class.path=."; + args.version = JNI_VERSION_1_6; + args.nOptions = 1; + args.options = &options; + args.ignoreUnrecognized = 0; + + if (env) { + return; + } + + void *libjvm = dlopen(LIBJVM_SO, RTLD_NOW | RTLD_GLOBAL); + if (!libjvm) { + mp_raise_msg(&mp_type_OSError, "unable to load libjvm.so, use LD_LIBRARY_PATH"); + } + int (*_JNI_CreateJavaVM)(void*, void**, void*) = dlsym(libjvm, "JNI_CreateJavaVM"); + + int st = _JNI_CreateJavaVM(&jvm, (void**)&env, &args); + if (st < 0 || !env) { + mp_raise_msg(&mp_type_OSError, "unable to create JVM"); + } + + Class_class = JJ(FindClass, "java/lang/Class"); + jclass method_class = JJ(FindClass, "java/lang/reflect/Method"); + String_class = JJ(FindClass, "java/lang/String"); + + jclass Object_class = JJ(FindClass, "java/lang/Object"); + Object_toString_mid = JJ(GetMethodID, Object_class, "toString", + "()Ljava/lang/String;"); + + Class_getName_mid = (*env)->GetMethodID(env, Class_class, "getName", + "()Ljava/lang/String;"); + Class_getField_mid = (*env)->GetMethodID(env, Class_class, "getField", + "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); + Class_getMethods_mid = (*env)->GetMethodID(env, Class_class, "getMethods", + "()[Ljava/lang/reflect/Method;"); + Class_getConstructors_mid = (*env)->GetMethodID(env, Class_class, "getConstructors", + "()[Ljava/lang/reflect/Constructor;"); + Method_getName_mid = (*env)->GetMethodID(env, method_class, "getName", + "()Ljava/lang/String;"); + + List_class = JJ(FindClass, "java/util/List"); + List_get_mid = JJ(GetMethodID, List_class, "get", + "(I)Ljava/lang/Object;"); + List_set_mid = JJ(GetMethodID, List_class, "set", + "(ILjava/lang/Object;)Ljava/lang/Object;"); + List_size_mid = JJ(GetMethodID, List_class, "size", + "()I"); + IndexException_class = JJ(FindClass, "java/lang/IndexOutOfBoundsException"); +} + +STATIC mp_obj_t mod_jni_cls(mp_obj_t cls_name_in) { + const char *cls_name = mp_obj_str_get_str(cls_name_in); + if (!env) { + create_jvm(); + } + jclass cls = JJ(FindClass, cls_name); + + mp_obj_jclass_t *o = m_new_obj(mp_obj_jclass_t); + o->base.type = &jclass_type; + o->cls = cls; + return MP_OBJ_FROM_PTR(o); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_jni_cls_obj, mod_jni_cls); + +STATIC mp_obj_t mod_jni_array(mp_obj_t type_in, mp_obj_t size_in) { + if (!env) { + create_jvm(); + } + mp_int_t size = mp_obj_get_int(size_in); + jobject res = NULL; + + if (MP_OBJ_IS_TYPE(type_in, &jclass_type)) { + + mp_obj_jclass_t *jcls = MP_OBJ_TO_PTR(type_in); + res = JJ(NewObjectArray, size, jcls->cls, NULL); + + } else if (MP_OBJ_IS_STR(type_in)) { + const char *type = mp_obj_str_get_str(type_in); + switch (*type) { + case 'Z': + res = JJ(NewBooleanArray, size); + break; + case 'B': + res = JJ(NewByteArray, size); + break; + case 'C': + res = JJ(NewCharArray, size); + break; + case 'S': + res = JJ(NewShortArray, size); + break; + case 'I': + res = JJ(NewIntArray, size); + break; + case 'J': + res = JJ(NewLongArray, size); + break; + case 'F': + res = JJ(NewFloatArray, size); + break; + case 'D': + res = JJ(NewDoubleArray, size); + break; + } + + } + + return new_jobject(res); +} +MP_DEFINE_CONST_FUN_OBJ_2(mod_jni_array_obj, mod_jni_array); + + +STATIC mp_obj_t mod_jni_env(void) { + return mp_obj_new_int((mp_int_t)(uintptr_t)env); +} +MP_DEFINE_CONST_FUN_OBJ_0(mod_jni_env_obj, mod_jni_env); + +STATIC const mp_rom_map_elem_t mp_module_jni_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jni) }, + { MP_ROM_QSTR(MP_QSTR_cls), MP_ROM_PTR(&mod_jni_cls_obj) }, + { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mod_jni_array_obj) }, + { MP_ROM_QSTR(MP_QSTR_env), MP_ROM_PTR(&mod_jni_env_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_jni_globals, mp_module_jni_globals_table); + +const mp_obj_module_t mp_module_jni = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_jni_globals, +}; diff --git a/src/openmv/src/micropython/ports/unix/modmachine.c b/src/openmv/src/micropython/ports/unix/modmachine.c new file mode 100755 index 0000000..48dddec --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modmachine.c @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/obj.h" + +#include "extmod/machine_mem.h" +#include "extmod/machine_pinbase.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" + +#if MICROPY_PLAT_DEV_MEM +#include +#include +#include +#define MICROPY_PAGE_SIZE 4096 +#define MICROPY_PAGE_MASK (MICROPY_PAGE_SIZE - 1) +#endif + +#if MICROPY_PY_MACHINE + +uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { + uintptr_t addr = mp_obj_int_get_truncated(addr_o); + if ((addr & (align - 1)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + } + #if MICROPY_PLAT_DEV_MEM + { + // Not thread-safe + static int fd; + static uintptr_t last_base = (uintptr_t)-1; + static uintptr_t map_page; + if (!fd) { + fd = open("/dev/mem", O_RDWR | O_SYNC); + if (fd == -1) { + mp_raise_OSError(errno); + } + } + + uintptr_t cur_base = addr & ~MICROPY_PAGE_MASK; + if (cur_base != last_base) { + map_page = (uintptr_t)mmap(NULL, MICROPY_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, cur_base); + last_base = cur_base; + } + addr = map_page + (addr & MICROPY_PAGE_MASK); + } + #endif + + return addr; +} + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_PinBase), MP_ROM_PTR(&machine_pinbase_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + #if MICROPY_PY_MACHINE_PULSE + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/ports/unix/modos.c b/src/openmv/src/micropython/ports/unix/modos.c new file mode 100755 index 0000000..98bca94 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modos.c @@ -0,0 +1,247 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "py/mpconfig.h" + +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/mphal.h" +#include "extmod/vfs.h" +#include "extmod/misc.h" + +#ifdef __ANDROID__ +#define USE_STATFS 1 +#endif + +STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) { + struct stat sb; + const char *path = mp_obj_str_get_str(path_in); + + int res = stat(path, &sb); + RAISE_ERRNO(res, errno); + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid); + t->items[6] = mp_obj_new_int_from_uint(sb.st_size); + t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); + t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); + t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_stat_obj, mod_os_stat); + +#if MICROPY_PY_OS_STATVFS + +#if USE_STATFS +#include +#define STRUCT_STATVFS struct statfs +#define STATVFS statfs +#define F_FAVAIL sb.f_ffree +#define F_NAMEMAX sb.f_namelen +#define F_FLAG sb.f_flags +#else +#include +#define STRUCT_STATVFS struct statvfs +#define STATVFS statvfs +#define F_FAVAIL sb.f_favail +#define F_NAMEMAX sb.f_namemax +#define F_FLAG sb.f_flag +#endif + +STATIC mp_obj_t mod_os_statvfs(mp_obj_t path_in) { + STRUCT_STATVFS sb; + const char *path = mp_obj_str_get_str(path_in); + + int res = STATVFS(path, &sb); + RAISE_ERRNO(res, errno); + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree); + t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL); + t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG); + t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_statvfs_obj, mod_os_statvfs); +#endif + +STATIC mp_obj_t mod_os_unlink(mp_obj_t path_in) { + const char *path = mp_obj_str_get_str(path_in); + + int r = unlink(path); + + RAISE_ERRNO(r, errno); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_unlink_obj, mod_os_unlink); + +STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { + const char *cmd = mp_obj_str_get_str(cmd_in); + + int r = system(cmd); + + RAISE_ERRNO(r, errno); + + return MP_OBJ_NEW_SMALL_INT(r); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system); + +STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { + const char *s = getenv(mp_obj_str_get_str(var_in)); + if (s == NULL) { + return mp_const_none; + } + return mp_obj_new_str(s, strlen(s)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); + +STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) { + // TODO: Accept mode param + const char *path = mp_obj_str_get_str(path_in); + #ifdef _WIN32 + int r = mkdir(path); + #else + int r = mkdir(path, 0777); + #endif + RAISE_ERRNO(r, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_mkdir_obj, mod_os_mkdir); + +typedef struct _mp_obj_listdir_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + DIR *dir; +} mp_obj_listdir_t; + +STATIC mp_obj_t listdir_next(mp_obj_t self_in) { + mp_obj_listdir_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->dir == NULL) { + goto done; + } + struct dirent *dirent = readdir(self->dir); + if (dirent == NULL) { + closedir(self->dir); + self->dir = NULL; + done: + return MP_OBJ_STOP_ITERATION; + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name)); + + #ifdef _DIRENT_HAVE_D_TYPE + #ifdef DTTOIF + t->items[1] = MP_OBJ_NEW_SMALL_INT(DTTOIF(dirent->d_type)); + #else + if (dirent->d_type == DT_DIR) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else if (dirent->d_type == DT_REG) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } else { + t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); + } + #endif + #else + // DT_UNKNOWN should have 0 value on any reasonable system + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); + #endif + + #ifdef _DIRENT_HAVE_D_INO + t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino); + #else + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); + #endif + return MP_OBJ_FROM_PTR(t); +} + +STATIC mp_obj_t mod_os_ilistdir(size_t n_args, const mp_obj_t *args) { + const char *path = "."; + if (n_args > 0) { + path = mp_obj_str_get_str(args[0]); + } + mp_obj_listdir_t *o = m_new_obj(mp_obj_listdir_t); + o->base.type = &mp_type_polymorph_iter; + o->dir = opendir(path); + o->iternext = listdir_next; + return MP_OBJ_FROM_PTR(o); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_ilistdir_obj, 0, 1, mod_os_ilistdir); + +STATIC mp_obj_t mod_os_errno(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return MP_OBJ_NEW_SMALL_INT(errno); + } + + errno = mp_obj_get_int(args[0]); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno); + +STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) }, + #if MICROPY_PY_OS_STATVFS + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mod_os_unlink_obj) }, + { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mod_os_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mod_os_ilistdir_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_os_globals, mp_module_os_globals_table); + +const mp_obj_module_t mp_module_os = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_os_globals, +}; diff --git a/src/openmv/src/micropython/ports/unix/modtermios.c b/src/openmv/src/micropython/ports/unix/modtermios.c new file mode 100755 index 0000000..fe19aac --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modtermios.c @@ -0,0 +1,150 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" + +STATIC mp_obj_t mod_termios_tcgetattr(mp_obj_t fd_in) { + struct termios term; + int fd = mp_obj_get_int(fd_in); + + int res = tcgetattr(fd, &term); + RAISE_ERRNO(res, errno); + + mp_obj_list_t *r = MP_OBJ_TO_PTR(mp_obj_new_list(7, NULL)); + r->items[0] = MP_OBJ_NEW_SMALL_INT(term.c_iflag); + r->items[1] = MP_OBJ_NEW_SMALL_INT(term.c_oflag); + r->items[2] = MP_OBJ_NEW_SMALL_INT(term.c_cflag); + r->items[3] = MP_OBJ_NEW_SMALL_INT(term.c_lflag); + r->items[4] = MP_OBJ_NEW_SMALL_INT(cfgetispeed(&term)); + r->items[5] = MP_OBJ_NEW_SMALL_INT(cfgetospeed(&term)); + + mp_obj_list_t *cc = MP_OBJ_TO_PTR(mp_obj_new_list(NCCS, NULL)); + r->items[6] = MP_OBJ_FROM_PTR(cc); + for (int i = 0; i < NCCS; i++) { + if (i == VMIN || i == VTIME) { + cc->items[i] = MP_OBJ_NEW_SMALL_INT(term.c_cc[i]); + } else { + // https://docs.python.org/3/library/termios.html says value is *string*, + // but no way unicode chars could be there, if c_cc is defined to be a + // a "char". But it's type is actually cc_t, which can be anything. + // TODO: For now, we still deal with it like that. + cc->items[i] = mp_obj_new_bytes((byte*)&term.c_cc[i], 1); + } + } + return MP_OBJ_FROM_PTR(r); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_termios_tcgetattr_obj, mod_termios_tcgetattr); + +STATIC mp_obj_t mod_termios_tcsetattr(mp_obj_t fd_in, mp_obj_t when_in, mp_obj_t attrs_in) { + struct termios term; + int fd = mp_obj_get_int(fd_in); + int when = mp_obj_get_int(when_in); + if (when == 0) { + // We don't export TCSANOW and friends to save on code space. Then + // common lazy sense says that passing 0 should be godo enough, and + // it is e.g. for glibc. But for other libc's it's not, so set just + // treat 0 as defauling to TCSANOW. + when = TCSANOW; + } + + assert(MP_OBJ_IS_TYPE(attrs_in, &mp_type_list)); + mp_obj_list_t *attrs = MP_OBJ_TO_PTR(attrs_in); + + term.c_iflag = mp_obj_get_int(attrs->items[0]); + term.c_oflag = mp_obj_get_int(attrs->items[1]); + term.c_cflag = mp_obj_get_int(attrs->items[2]); + term.c_lflag = mp_obj_get_int(attrs->items[3]); + + mp_obj_list_t *cc = MP_OBJ_TO_PTR(attrs->items[6]); + for (int i = 0; i < NCCS; i++) { + if (i == VMIN || i == VTIME) { + term.c_cc[i] = mp_obj_get_int(cc->items[i]); + } else { + term.c_cc[i] = *mp_obj_str_get_str(cc->items[i]); + } + } + + int res = cfsetispeed(&term, mp_obj_get_int(attrs->items[4])); + RAISE_ERRNO(res, errno); + res = cfsetispeed(&term, mp_obj_get_int(attrs->items[5])); + RAISE_ERRNO(res, errno); + + res = tcsetattr(fd, when, &term); + RAISE_ERRNO(res, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_termios_tcsetattr_obj, mod_termios_tcsetattr); + +STATIC mp_obj_t mod_termios_setraw(mp_obj_t fd_in) { + struct termios term; + int fd = mp_obj_get_int(fd_in); + int res = tcgetattr(fd, &term); + RAISE_ERRNO(res, errno); + + term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + term.c_oflag = 0; + term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8; + term.c_lflag = 0; + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + res = tcsetattr(fd, TCSAFLUSH, &term); + RAISE_ERRNO(res, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_termios_setraw_obj, mod_termios_setraw); + +STATIC const mp_rom_map_elem_t mp_module_termios_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_termios) }, + { MP_ROM_QSTR(MP_QSTR_tcgetattr), MP_ROM_PTR(&mod_termios_tcgetattr_obj) }, + { MP_ROM_QSTR(MP_QSTR_tcsetattr), MP_ROM_PTR(&mod_termios_tcsetattr_obj) }, + { MP_ROM_QSTR(MP_QSTR_setraw), MP_ROM_PTR(&mod_termios_setraw_obj) }, + +#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(name) } + C(TCSANOW), + + C(B9600), + #ifdef B57600 + C(B57600), + #endif + #ifdef B115200 + C(B115200), + #endif +#undef C +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_termios_globals, mp_module_termios_globals_table); + +const mp_obj_module_t mp_module_termios = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_termios_globals, +}; diff --git a/src/openmv/src/micropython/ports/unix/modtime.c b/src/openmv/src/micropython/ports/unix/modtime.c new file mode 100755 index 0000000..a74b81f --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modtime.c @@ -0,0 +1,185 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME + +#include +#include +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "extmod/utime_mphal.h" + +#ifdef _WIN32 +static inline int msec_sleep_tv(struct timeval *tv) { + msec_sleep(tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0); + return 0; +} +#define sleep_select(a,b,c,d,e) msec_sleep_tv((e)) +#else +#define sleep_select select +#endif + +// mingw32 defines CLOCKS_PER_SEC as ((clock_t)) but preprocessor does not handle casts +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#define MP_REMOVE_BRACKETSA(x) +#define MP_REMOVE_BRACKETSB(x) MP_REMOVE_BRACKETSA x +#define MP_REMOVE_BRACKETSC(x) MP_REMOVE_BRACKETSB x +#define MP_CLOCKS_PER_SEC MP_REMOVE_BRACKETSC(CLOCKS_PER_SEC) +#else +#define MP_CLOCKS_PER_SEC CLOCKS_PER_SEC +#endif + +#if defined(MP_CLOCKS_PER_SEC) +#define CLOCK_DIV (MP_CLOCKS_PER_SEC / 1000.0F) +#else +#error Unsupported clock() implementation +#endif + +STATIC mp_obj_t mod_time_time(void) { +#if MICROPY_PY_BUILTINS_FLOAT + struct timeval tv; + gettimeofday(&tv, NULL); + mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000; + return mp_obj_new_float(val); +#else + return mp_obj_new_int((mp_int_t)time(NULL)); +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); + +// Note: this is deprecated since CPy3.3, but pystone still uses it. +STATIC mp_obj_t mod_time_clock(void) { +#if MICROPY_PY_BUILTINS_FLOAT + // float cannot represent full range of int32 precisely, so we pre-divide + // int to reduce resolution, and then actually do float division hoping + // to preserve integer part resolution. + return mp_obj_new_float((float)(clock() / 1000) / CLOCK_DIV); +#else + return mp_obj_new_int((mp_int_t)clock()); +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock); + +STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { +#if MICROPY_PY_BUILTINS_FLOAT + struct timeval tv; + mp_float_t val = mp_obj_get_float(arg); + double ipart; + tv.tv_usec = round(modf(val, &ipart) * 1000000); + tv.tv_sec = ipart; + int res; + while (1) { + MP_THREAD_GIL_EXIT(); + res = sleep_select(0, NULL, NULL, NULL, &tv); + MP_THREAD_GIL_ENTER(); + #if MICROPY_SELECT_REMAINING_TIME + // TODO: This assumes Linux behavior of modifying tv to the remaining + // time. + if (res != -1 || errno != EINTR) { + break; + } + mp_handle_pending(); + //printf("select: EINTR: %ld:%ld\n", tv.tv_sec, tv.tv_usec); + #else + break; + #endif + } + RAISE_ERRNO(res, errno); +#else + // TODO: Handle EINTR + MP_THREAD_GIL_EXIT(); + sleep(mp_obj_get_int(arg)); + MP_THREAD_GIL_ENTER(); +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); + +STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) { + time_t t; + if (n_args == 0) { + t = time(NULL); + } else { + #if MICROPY_PY_BUILTINS_FLOAT + mp_float_t val = mp_obj_get_float(args[0]); + t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); + #else + t = mp_obj_get_int(args[0]); + #endif + } + struct tm *tm = localtime(&t); + + mp_obj_t ret = mp_obj_new_tuple(9, NULL); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(ret); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(tm->tm_year + 1900); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(tm->tm_mon + 1); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(tm->tm_mday); + tuple->items[3] = MP_OBJ_NEW_SMALL_INT(tm->tm_hour); + tuple->items[4] = MP_OBJ_NEW_SMALL_INT(tm->tm_min); + tuple->items[5] = MP_OBJ_NEW_SMALL_INT(tm->tm_sec); + int wday = tm->tm_wday - 1; + if (wday < 0) { + wday = 6; + } + tuple->items[6] = MP_OBJ_NEW_SMALL_INT(wday); + tuple->items[7] = MP_OBJ_NEW_SMALL_INT(tm->tm_yday + 1); + tuple->items[8] = MP_OBJ_NEW_SMALL_INT(tm->tm_isdst); + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, mod_time_localtime); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&mod_time_clock_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mod_time_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_UTIME diff --git a/src/openmv/src/micropython/ports/unix/moduos_vfs.c b/src/openmv/src/micropython/ports/unix/moduos_vfs.c new file mode 100755 index 0000000..e9ac8e1 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/moduos_vfs.c @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" +#include "extmod/vfs_fat.h" + +#if MICROPY_VFS + +// These are defined in modos.c +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_getenv_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_system_obj); + +STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos_vfs) }, + { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, + + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) }, + { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) }, + { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) }, + + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename),MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + #endif + + #if MICROPY_VFS_POSIX + { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) }, + #endif + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(uos_vfs_module_globals, uos_vfs_module_globals_table); + +const mp_obj_module_t mp_module_uos_vfs = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&uos_vfs_module_globals, +}; + +#endif // MICROPY_VFS diff --git a/src/openmv/src/micropython/ports/unix/moduselect.c b/src/openmv/src/micropython/ports/unix/moduselect.c new file mode 100755 index 0000000..a95663e --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/moduselect.c @@ -0,0 +1,351 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2015-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +#if MICROPY_PY_USELECT_POSIX + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/obj.h" +#include "py/objlist.h" +#include "py/objtuple.h" +#include "py/mphal.h" +#include "fdfile.h" + +#define DEBUG 0 + +#if MICROPY_PY_SOCKET +extern const mp_obj_type_t mp_type_socket; +#endif + +// Flags for poll() +#define FLAG_ONESHOT (1) + +/// \class Poll - poll class + +typedef struct _mp_obj_poll_t { + mp_obj_base_t base; + unsigned short alloc; + unsigned short len; + struct pollfd *entries; + mp_obj_t *obj_map; + short iter_cnt; + short iter_idx; + int flags; + // callee-owned tuple + mp_obj_t ret_tuple; +} mp_obj_poll_t; + +STATIC int get_fd(mp_obj_t fdlike) { + if (MP_OBJ_IS_OBJ(fdlike)) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(fdlike, MP_STREAM_OP_IOCTL); + int err; + mp_uint_t res = stream_p->ioctl(fdlike, MP_STREAM_GET_FILENO, 0, &err); + if (res != MP_STREAM_ERROR) { + return res; + } + } + return mp_obj_get_int(fdlike); +} + +/// \method register(obj[, eventmask]) +STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + bool is_fd = MP_OBJ_IS_INT(args[1]); + int fd = get_fd(args[1]); + + mp_uint_t flags; + if (n_args == 3) { + flags = mp_obj_get_int(args[2]); + } else { + flags = POLLIN | POLLOUT; + } + + struct pollfd *free_slot = NULL; + + struct pollfd *entry = self->entries; + for (int i = 0; i < self->len; i++, entry++) { + int entry_fd = entry->fd; + if (entry_fd == fd) { + entry->events = flags; + return mp_const_false; + } + if (entry_fd == -1) { + free_slot = entry; + } + } + + if (free_slot == NULL) { + if (self->len >= self->alloc) { + self->entries = m_renew(struct pollfd, self->entries, self->alloc, self->alloc + 4); + if (self->obj_map) { + self->obj_map = m_renew(mp_obj_t, self->obj_map, self->alloc, self->alloc + 4); + } + self->alloc += 4; + } + free_slot = &self->entries[self->len++]; + } + + if (!is_fd) { + if (self->obj_map == NULL) { + self->obj_map = m_new0(mp_obj_t, self->alloc); + } + self->obj_map[free_slot - self->entries] = args[1]; + } + + free_slot->fd = fd; + free_slot->events = flags; + free_slot->revents = 0; + return mp_const_true; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); + +/// \method unregister(obj) +STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + struct pollfd *entries = self->entries; + int fd = get_fd(obj_in); + for (int i = self->len - 1; i >= 0; i--) { + if (entries->fd == fd) { + entries->fd = -1; + if (self->obj_map) { + self->obj_map[entries - self->entries] = MP_OBJ_NULL; + } + break; + } + entries++; + } + + // TODO raise KeyError if obj didn't exist in map + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister); + +/// \method modify(obj, eventmask) +STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + struct pollfd *entries = self->entries; + int fd = get_fd(obj_in); + for (int i = self->len - 1; i >= 0; i--) { + if (entries->fd == fd) { + entries->events = mp_obj_get_int(eventmask_in); + return mp_const_none; + } + entries++; + } + + // obj doesn't exist in poller + mp_raise_OSError(MP_ENOENT); +} +MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify); + +STATIC int poll_poll_internal(size_t n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + + // work out timeout (it's given already in ms) + int timeout = -1; + int flags = 0; + if (n_args >= 2) { + if (args[1] != mp_const_none) { + mp_int_t timeout_i = mp_obj_get_int(args[1]); + if (timeout_i >= 0) { + timeout = timeout_i; + } + } + if (n_args >= 3) { + flags = mp_obj_get_int(args[2]); + } + } + + self->flags = flags; + + int n_ready = poll(self->entries, self->len, timeout); + RAISE_ERRNO(n_ready, errno); + return n_ready; +} + +/// \method poll([timeout]) +/// Timeout is in milliseconds. +STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) { + int n_ready = poll_poll_internal(n_args, args); + + if (n_ready == 0) { + return mp_const_empty_tuple; + } + + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + + mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL)); + int ret_i = 0; + struct pollfd *entries = self->entries; + for (int i = 0; i < self->len; i++, entries++) { + if (entries->revents != 0) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + // If there's an object stored, return it, otherwise raw fd + if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) { + t->items[0] = self->obj_map[i]; + } else { + t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd); + } + t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents); + ret_list->items[ret_i++] = MP_OBJ_FROM_PTR(t); + if (self->flags & FLAG_ONESHOT) { + entries->events = 0; + } + } + } + + return MP_OBJ_FROM_PTR(ret_list); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll); + +STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); + + if (self->ret_tuple == MP_OBJ_NULL) { + self->ret_tuple = mp_obj_new_tuple(2, NULL); + } + + int n_ready = poll_poll_internal(n_args, args); + self->iter_cnt = n_ready; + self->iter_idx = 0; + + return args[0]; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll); + +STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->iter_cnt == 0) { + return MP_OBJ_STOP_ITERATION; + } + + self->iter_cnt--; + + struct pollfd *entries = self->entries + self->iter_idx; + for (int i = self->iter_idx; i < self->len; i++, entries++) { + self->iter_idx++; + if (entries->revents != 0) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple); + // If there's an object stored, return it, otherwise raw fd + if (self->obj_map && self->obj_map[i] != MP_OBJ_NULL) { + t->items[0] = self->obj_map[i]; + } else { + t->items[0] = MP_OBJ_NEW_SMALL_INT(entries->fd); + } + t->items[1] = MP_OBJ_NEW_SMALL_INT(entries->revents); + if (self->flags & FLAG_ONESHOT) { + entries->events = 0; + } + return MP_OBJ_FROM_PTR(t); + } + } + + assert(!"inconsistent number of poll active entries"); + self->iter_cnt = 0; + return MP_OBJ_STOP_ITERATION; +} + +#if DEBUG +STATIC mp_obj_t poll_dump(mp_obj_t self_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + + struct pollfd *entries = self->entries; + for (int i = self->len - 1; i >= 0; i--) { + printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents); + if (self->obj_map) { + printf(" obj: %p", self->obj_map[entries - self->entries]); + } + printf("\n"); + entries++; + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump); +#endif + +STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, + { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) }, + { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, + { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, + { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, + #if DEBUG + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, + #endif +}; +STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); + +STATIC const mp_obj_type_t mp_type_poll = { + { &mp_type_type }, + .name = MP_QSTR_poll, + .getiter = mp_identity_getiter, + .iternext = poll_iternext, + .locals_dict = (void*)&poll_locals_dict, +}; + +STATIC mp_obj_t select_poll(size_t n_args, const mp_obj_t *args) { + int alloc = 4; + if (n_args > 0) { + alloc = mp_obj_get_int(args[0]); + } + mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t); + poll->base.type = &mp_type_poll; + poll->entries = m_new(struct pollfd, alloc); + poll->alloc = alloc; + poll->len = 0; + poll->obj_map = NULL; + poll->iter_cnt = 0; + poll->ret_tuple = MP_OBJ_NULL; + return MP_OBJ_FROM_PTR(poll); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_poll_obj, 0, 1, select_poll); + +STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) }, + { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) }, + { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(POLLIN) }, + { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(POLLOUT) }, + { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(POLLERR) }, + { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(POLLHUP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table); + +const mp_obj_module_t mp_module_uselect = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_select_globals, +}; + +#endif // MICROPY_PY_USELECT_POSIX diff --git a/src/openmv/src/micropython/ports/unix/modusocket.c b/src/openmv/src/micropython/ports/unix/modusocket.c new file mode 100755 index 0000000..61402e0 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/modusocket.c @@ -0,0 +1,624 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/builtin.h" +#include "py/mphal.h" + +/* + The idea of this module is to implement reasonable minimum of + socket-related functions to write typical clients and servers. + The module named "usocket" on purpose, to allow to make + Python-level module more (or fully) compatible with CPython + "socket", e.g.: + ---- socket.py ---- + from usocket import * + from socket_more_funcs import * + from socket_more_funcs2 import * + ------------------- + I.e. this module should stay lean, and more functions (if needed) + should be add to separate modules (C or Python level). + */ + +// This type must "inherit" from mp_obj_fdfile_t, i.e. matching subset of +// fields should have the same layout. +typedef struct _mp_obj_socket_t { + mp_obj_base_t base; + int fd; + bool blocking; +} mp_obj_socket_t; + +const mp_obj_type_t mp_type_socket; + +// Helper functions +static inline mp_obj_t mp_obj_from_sockaddr(const struct sockaddr *addr, socklen_t len) { + return mp_obj_new_bytes((const byte *)addr, len); +} + +STATIC mp_obj_socket_t *socket_new(int fd) { + mp_obj_socket_t *o = m_new_obj(mp_obj_socket_t); + o->base.type = &mp_type_socket; + o->fd = fd; + o->blocking = true; + return o; +} + + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<_socket %d>", self->fd); +} + +STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in); + mp_int_t r = read(o->fd, buf, size); + if (r == -1) { + int err = errno; + // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO + // timed out, and need to convert that to ETIMEDOUT. + if (err == EAGAIN && o->blocking) { + err = MP_ETIMEDOUT; + } + + *errcode = err; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in); + mp_int_t r = write(o->fd, buf, size); + if (r == -1) { + int err = errno; + // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO + // timed out, and need to convert that to ETIMEDOUT. + if (err == EAGAIN && o->blocking) { + err = MP_ETIMEDOUT; + } + + *errcode = err; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // There's a POSIX drama regarding return value of close in general, + // and EINTR error in particular. See e.g. + // http://lwn.net/Articles/576478/ + // http://austingroupbugs.net/view.php?id=529 + // The rationale MicroPython follows is that close() just releases + // file descriptor. If you're interested to catch I/O errors before + // closing fd, fsync() it. + close(self->fd); + return 0; + + case MP_STREAM_GET_FILENO: + return self->fd; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t socket_fileno(mp_obj_t self_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); + +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); + int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); + RAISE_ERRNO(r, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ); + int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); + RAISE_ERRNO(r, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + int r = listen(self->fd, MP_OBJ_SMALL_INT_VALUE(backlog_in)); + RAISE_ERRNO(r, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + // sockaddr_storage isn't stack-friendly (129 bytes or so) + //struct sockaddr_storage addr; + byte addr[32]; + socklen_t addr_len = sizeof(addr); + int fd = accept(self->fd, (struct sockaddr*)&addr, &addr_len); + RAISE_ERRNO(fd, errno); + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + t->items[0] = MP_OBJ_FROM_PTR(socket_new(fd)); + t->items[1] = mp_obj_new_bytearray(addr_len, &addr); + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +// Note: besides flag param, this differs from read() in that +// this does not swallow blocking errors (EAGAIN, EWOULDBLOCK) - +// these would be thrown as exceptions. +STATIC mp_obj_t socket_recv(size_t n_args, const mp_obj_t *args) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + int sz = MP_OBJ_SMALL_INT_VALUE(args[1]); + int flags = 0; + + if (n_args > 2) { + flags = MP_OBJ_SMALL_INT_VALUE(args[2]); + } + + byte *buf = m_new(byte, sz); + int out_sz = recv(self->fd, buf, sz, flags); + RAISE_ERRNO(out_sz, errno); + + mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); + m_del(char, buf, sz); + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_obj, 2, 3, socket_recv); + +STATIC mp_obj_t socket_recvfrom(size_t n_args, const mp_obj_t *args) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + int sz = MP_OBJ_SMALL_INT_VALUE(args[1]); + int flags = 0; + + if (n_args > 2) { + flags = MP_OBJ_SMALL_INT_VALUE(args[2]); + } + + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + + byte *buf = m_new(byte, sz); + int out_sz = recvfrom(self->fd, buf, sz, flags, (struct sockaddr*)&addr, &addr_len); + RAISE_ERRNO(out_sz, errno); + + mp_obj_t buf_o = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz); + m_del(char, buf, sz); + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + t->items[0] = buf_o; + t->items[1] = mp_obj_from_sockaddr((struct sockaddr*)&addr, addr_len); + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recvfrom_obj, 2, 3, socket_recvfrom); + +// Note: besides flag param, this differs from write() in that +// this does not swallow blocking errors (EAGAIN, EWOULDBLOCK) - +// these would be thrown as exceptions. +STATIC mp_obj_t socket_send(size_t n_args, const mp_obj_t *args) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + int flags = 0; + + if (n_args > 2) { + flags = MP_OBJ_SMALL_INT_VALUE(args[2]); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + int out_sz = send(self->fd, bufinfo.buf, bufinfo.len, flags); + RAISE_ERRNO(out_sz, errno); + + return MP_OBJ_NEW_SMALL_INT(out_sz); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_send_obj, 2, 3, socket_send); + +STATIC mp_obj_t socket_sendto(size_t n_args, const mp_obj_t *args) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + int flags = 0; + + mp_obj_t dst_addr = args[2]; + if (n_args > 3) { + flags = MP_OBJ_SMALL_INT_VALUE(args[2]); + dst_addr = args[3]; + } + + mp_buffer_info_t bufinfo, addr_bi; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(dst_addr, &addr_bi, MP_BUFFER_READ); + int out_sz = sendto(self->fd, bufinfo.buf, bufinfo.len, flags, + (struct sockaddr *)addr_bi.buf, addr_bi.len); + RAISE_ERRNO(out_sz, errno); + + return MP_OBJ_NEW_SMALL_INT(out_sz); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_sendto_obj, 3, 4, socket_sendto); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + int level = MP_OBJ_SMALL_INT_VALUE(args[1]); + int option = mp_obj_get_int(args[2]); + + const void *optval; + socklen_t optlen; + int val; + if (MP_OBJ_IS_INT(args[3])) { + val = mp_obj_int_get_truncated(args[3]); + optval = &val; + optlen = sizeof(val); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + optval = bufinfo.buf; + optlen = bufinfo.len; + } + int r = setsockopt(self->fd, level, option, optval, optlen); + RAISE_ERRNO(r, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + int val = mp_obj_is_true(flag_in); + int flags = fcntl(self->fd, F_GETFL, 0); + RAISE_ERRNO(flags, errno); + if (val) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + flags = fcntl(self->fd, F_SETFL, flags); + RAISE_ERRNO(flags, errno); + self->blocking = val; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); + struct timeval tv = {0,}; + bool new_blocking = true; + + if (timeout_in == mp_const_none) { + setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, NULL, 0); + setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, NULL, 0); + } else { + #if MICROPY_PY_BUILTINS_FLOAT + mp_float_t val = mp_obj_get_float(timeout_in); + double ipart; + tv.tv_usec = round(modf(val, &ipart) * 1000000); + tv.tv_sec = ipart; + #else + tv.tv_sec = mp_obj_get_int(timeout_in); + #endif + + // For SO_RCVTIMEO/SO_SNDTIMEO, zero timeout means infinity, but + // for Python API it means non-blocking. + if (tv.tv_sec == 0 && tv.tv_usec == 0) { + new_blocking = false; + } else { + setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, + &tv, sizeof(struct timeval)); + setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, + &tv, sizeof(struct timeval)); + } + } + + if (self->blocking != new_blocking) { + socket_setblocking(self_in, mp_obj_new_bool(new_blocking)); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + // TODO: CPython explicitly says that closing returned object doesn't close + // the original socket (Python2 at all says that fd is dup()ed). But we + // save on the bloat. + mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_t *new_args = alloca(n_args * sizeof(mp_obj_t)); + memcpy(new_args + 1, args + 1, (n_args - 1) * sizeof(mp_obj_t)); + new_args[0] = MP_OBJ_NEW_SMALL_INT(self->fd); + return mp_builtin_open(n_args, new_args, (mp_map_t*)&mp_const_empty_map); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + (void)n_kw; + + int family = AF_INET; + int type = SOCK_STREAM; + int proto = 0; + + if (n_args > 0) { + assert(MP_OBJ_IS_SMALL_INT(args[0])); + family = MP_OBJ_SMALL_INT_VALUE(args[0]); + if (n_args > 1) { + assert(MP_OBJ_IS_SMALL_INT(args[1])); + type = MP_OBJ_SMALL_INT_VALUE(args[1]); + if (n_args > 2) { + assert(MP_OBJ_IS_SMALL_INT(args[2])); + proto = MP_OBJ_SMALL_INT_VALUE(args[2]); + } + } + } + + int fd = socket(family, type, proto); + RAISE_ERRNO(fd, errno); + return MP_OBJ_FROM_PTR(socket_new(fd)); +} + +STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); + +STATIC const mp_stream_p_t usocket_stream_p = { + .read = socket_read, + .write = socket_write, + .ioctl = socket_ioctl, +}; + +const mp_obj_type_t mp_type_socket = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .print = socket_print, + .make_new = socket_make_new, + .getiter = NULL, + .iternext = NULL, + .protocol = &usocket_stream_p, + .locals_dict = (mp_obj_dict_t*)&usocket_locals_dict, +}; + +#define BINADDR_MAX_LEN sizeof(struct in6_addr) +STATIC mp_obj_t mod_socket_inet_pton(mp_obj_t family_in, mp_obj_t addr_in) { + int family = mp_obj_get_int(family_in); + byte binaddr[BINADDR_MAX_LEN]; + int r = inet_pton(family, mp_obj_str_get_str(addr_in), binaddr); + RAISE_ERRNO(r, errno); + if (r == 0) { + mp_raise_OSError(MP_EINVAL); + } + int binaddr_len = 0; + switch (family) { + case AF_INET: + binaddr_len = sizeof(struct in_addr); + break; + case AF_INET6: + binaddr_len = sizeof(struct in6_addr); + break; + } + return mp_obj_new_bytes(binaddr, binaddr_len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_socket_inet_pton_obj, mod_socket_inet_pton); + +STATIC mp_obj_t mod_socket_inet_ntop(mp_obj_t family_in, mp_obj_t binaddr_in) { + int family = mp_obj_get_int(family_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(binaddr_in, &bufinfo, MP_BUFFER_READ); + vstr_t vstr; + vstr_init_len(&vstr, family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN); + if (inet_ntop(family, bufinfo.buf, vstr.buf, vstr.len) == NULL) { + mp_raise_OSError(errno); + } + vstr.len = strlen(vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_socket_inet_ntop_obj, mod_socket_inet_ntop); + +STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { + // TODO: Implement 5th and 6th args + + const char *host = mp_obj_str_get_str(args[0]); + const char *serv = NULL; + struct addrinfo hints; + char buf[6]; + memset(&hints, 0, sizeof(hints)); + // getaddrinfo accepts port in string notation, so however + // it may seem stupid, we need to convert int to str + if (MP_OBJ_IS_SMALL_INT(args[1])) { + unsigned port = (unsigned short)MP_OBJ_SMALL_INT_VALUE(args[1]); + snprintf(buf, sizeof(buf), "%u", port); + serv = buf; + hints.ai_flags = AI_NUMERICSERV; +#ifdef __UCLIBC_MAJOR__ +#if __UCLIBC_MAJOR__ == 0 && (__UCLIBC_MINOR__ < 9 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ <= 32)) +// "warning" requires -Wno-cpp which is a relatively new gcc option, so we choose not to use it. +//#warning Working around uClibc bug with numeric service name + // Older versions og uClibc have bugs when numeric ports in service + // arg require also hints.ai_socktype (or hints.ai_protocol) != 0 + // This actually was fixed in 0.9.32.1, but uClibc doesn't allow to + // test for that. + // http://git.uclibc.org/uClibc/commit/libc/inet/getaddrinfo.c?id=bc3be18145e4d5 + // Note that this is crude workaround, precluding UDP socket addresses + // to be returned. TODO: set only if not set by Python args. + hints.ai_socktype = SOCK_STREAM; +#endif +#endif + } else { + serv = mp_obj_str_get_str(args[1]); + } + + if (n_args > 2) { + hints.ai_family = MP_OBJ_SMALL_INT_VALUE(args[2]); + if (n_args > 3) { + hints.ai_socktype = MP_OBJ_SMALL_INT_VALUE(args[3]); + } + } + + struct addrinfo *addr_list; + int res = getaddrinfo(host, serv, &hints, &addr_list); + + if (res != 0) { + // CPython: socket.gaierror + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); + } + assert(addr_list); + + mp_obj_t list = mp_obj_new_list(0, NULL); + for (struct addrinfo *addr = addr_list; addr; addr = addr->ai_next) { + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(addr->ai_family); + t->items[1] = MP_OBJ_NEW_SMALL_INT(addr->ai_socktype); + t->items[2] = MP_OBJ_NEW_SMALL_INT(addr->ai_protocol); + // "canonname will be a string representing the canonical name of the host + // if AI_CANONNAME is part of the flags argument; else canonname will be empty." ?? + if (addr->ai_canonname) { + t->items[3] = MP_OBJ_NEW_QSTR(qstr_from_str(addr->ai_canonname)); + } else { + t->items[3] = mp_const_none; + } + t->items[4] = mp_obj_new_bytearray(addr->ai_addrlen, addr->ai_addr); + mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); + } + freeaddrinfo(addr_list); + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 4, mod_socket_getaddrinfo); + +STATIC mp_obj_t mod_socket_sockaddr(mp_obj_t sockaddr_in) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(sockaddr_in, &bufinfo, MP_BUFFER_READ); + switch (((struct sockaddr*)bufinfo.buf)->sa_family) { + case AF_INET: { + struct sockaddr_in *sa = (struct sockaddr_in*)bufinfo.buf; + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET); + t->items[1] = mp_obj_new_bytes((byte*)&sa->sin_addr, sizeof(sa->sin_addr)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(ntohs(sa->sin_port)); + return MP_OBJ_FROM_PTR(t); + } + case AF_INET6: { + struct sockaddr_in6 *sa = (struct sockaddr_in6*)bufinfo.buf; + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET6); + t->items[1] = mp_obj_new_bytes((byte*)&sa->sin6_addr, sizeof(sa->sin6_addr)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(ntohs(sa->sin6_port)); + t->items[3] = MP_OBJ_NEW_SMALL_INT(ntohl(sa->sin6_flowinfo)); + t->items[4] = MP_OBJ_NEW_SMALL_INT(ntohl(sa->sin6_scope_id)); + return MP_OBJ_FROM_PTR(t); + } + default: { + struct sockaddr *sa = (struct sockaddr*)bufinfo.buf; + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sa->sa_family); + t->items[1] = mp_obj_new_bytes((byte*)sa->sa_data, bufinfo.len - offsetof(struct sockaddr, sa_data)); + return MP_OBJ_FROM_PTR(t); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_sockaddr_obj, mod_socket_sockaddr); + +STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_type_socket) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_socket_getaddrinfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_inet_pton), MP_ROM_PTR(&mod_socket_inet_pton_obj) }, + { MP_ROM_QSTR(MP_QSTR_inet_ntop), MP_ROM_PTR(&mod_socket_inet_ntop_obj) }, + { MP_ROM_QSTR(MP_QSTR_sockaddr), MP_ROM_PTR(&mod_socket_sockaddr_obj) }, + +#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(name) } + C(AF_UNIX), + C(AF_INET), + C(AF_INET6), + C(SOCK_STREAM), + C(SOCK_DGRAM), + C(SOCK_RAW), + + C(MSG_DONTROUTE), + C(MSG_DONTWAIT), + + C(SOL_SOCKET), + C(SO_BROADCAST), + C(SO_ERROR), + C(SO_KEEPALIVE), + C(SO_LINGER), + C(SO_REUSEADDR), +#undef C +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); + +const mp_obj_module_t mp_module_socket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_socket_globals, +}; diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport.h b/src/openmv/src/micropython/ports/unix/mpconfigport.h new file mode 100755 index 0000000..d0cc9e3 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport.h @@ -0,0 +1,327 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#if !defined(MICROPY_EMIT_X64) && defined(__x86_64__) + #define MICROPY_EMIT_X64 (1) +#endif +#if !defined(MICROPY_EMIT_X86) && defined(__i386__) + #define MICROPY_EMIT_X86 (1) +#endif +#if !defined(MICROPY_EMIT_THUMB) && defined(__thumb2__) + #define MICROPY_EMIT_THUMB (1) + #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) +#endif +// Some compilers define __thumb2__ and __arm__ at the same time, let +// autodetected thumb2 emitter have priority. +#if !defined(MICROPY_EMIT_ARM) && defined(__arm__) && !defined(__thumb2__) + #define MICROPY_EMIT_ARM (1) +#endif +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_RETURN_IF_EXPR (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) +#define MICROPY_MEM_STATS (1) +#define MICROPY_DEBUG_PRINTERS (1) +// Printing debug to stderr may give tests which +// check stdout a chance to pass, etc. +#define MICROPY_DEBUG_PRINTER (&mp_stderr_print) +#define MICROPY_READER_POSIX (1) +#define MICROPY_USE_READLINE_HISTORY (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_OPT_COMPUTED_GOTO (1) +#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) +#endif +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_SYS_EXIT (1) +#if defined(__APPLE__) && defined(__MACH__) + #define MICROPY_PY_SYS_PLATFORM "darwin" +#else + #define MICROPY_PY_SYS_PLATFORM "linux" +#endif +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#endif +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_GC_COLLECT_RETVAL (1) +#define MICROPY_MODULE_FROZEN_STR (1) + +#ifndef MICROPY_STACKLESS +#define MICROPY_STACKLESS (0) +#define MICROPY_STACKLESS_STRICT (0) +#endif + +#define MICROPY_PY_OS_STATVFS (1) +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (1) +#if MICROPY_PY_USSL +#define MICROPY_PY_UHASHLIB_MD5 (1) +#define MICROPY_PY_UHASHLIB_SHA1 (1) +#define MICROPY_PY_UCRYPTOLIB (1) +#endif +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#ifndef MICROPY_PY_USELECT_POSIX +#define MICROPY_PY_USELECT_POSIX (1) +#endif +#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr +#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr + +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_VFS_FAT (0) + +// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. +// names in exception messages (may require more RAM). +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_WARNINGS (1) +#define MICROPY_ERROR_PRINTER (&mp_stderr_print) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) + +extern const struct _mp_print_t mp_stderr_print; + +// Define to 1 to use undertested inefficient GC helper implementation +// (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP + #ifdef __mips__ + #define MICROPY_GCREGS_SETJMP (1) + #else + #define MICROPY_GCREGS_SETJMP (0) + #endif +#endif + +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_ASYNC_KBD_INTR (1) + +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_os; +extern const struct _mp_obj_module_t mp_module_uos_vfs; +extern const struct _mp_obj_module_t mp_module_uselect; +extern const struct _mp_obj_module_t mp_module_time; +extern const struct _mp_obj_module_t mp_module_termios; +extern const struct _mp_obj_module_t mp_module_socket; +extern const struct _mp_obj_module_t mp_module_ffi; +extern const struct _mp_obj_module_t mp_module_jni; + +#if MICROPY_PY_UOS_VFS +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos_vfs) }, +#else +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, +#endif +#if MICROPY_PY_FFI +#define MICROPY_PY_FFI_DEF { MP_ROM_QSTR(MP_QSTR_ffi), MP_ROM_PTR(&mp_module_ffi) }, +#else +#define MICROPY_PY_FFI_DEF +#endif +#if MICROPY_PY_JNI +#define MICROPY_PY_JNI_DEF { MP_ROM_QSTR(MP_QSTR_jni), MP_ROM_PTR(&mp_module_jni) }, +#else +#define MICROPY_PY_JNI_DEF +#endif +#if MICROPY_PY_UTIME +#define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, +#else +#define MICROPY_PY_UTIME_DEF +#endif +#if MICROPY_PY_TERMIOS +#define MICROPY_PY_TERMIOS_DEF { MP_ROM_QSTR(MP_QSTR_termios), MP_ROM_PTR(&mp_module_termios) }, +#else +#define MICROPY_PY_TERMIOS_DEF +#endif +#if MICROPY_PY_SOCKET +#define MICROPY_PY_SOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_socket) }, +#else +#define MICROPY_PY_SOCKET_DEF +#endif +#if MICROPY_PY_USELECT_POSIX +#define MICROPY_PY_USELECT_DEF { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, +#else +#define MICROPY_PY_USELECT_DEF +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + MICROPY_PY_FFI_DEF \ + MICROPY_PY_JNI_DEF \ + MICROPY_PY_UTIME_DEF \ + MICROPY_PY_SOCKET_DEF \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ + MICROPY_PY_UOS_DEF \ + MICROPY_PY_USELECT_DEF \ + MICROPY_PY_TERMIOS_DEF \ + +// type definitions for the specific machine + +// For size_t and ssize_t +#include + +// assume that if we already defined the obj repr then we also defined types +#ifndef MICROPY_OBJ_REPR +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless of actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif +#endif + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +void mp_unix_alloc_exec(size_t min_size, void** ptr, size_t *size); +void mp_unix_free_exec(void *ptr, size_t size); +void mp_unix_mark_exec(void); +#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size) +#define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size) +#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC +// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI +// (overriding libffi own implementation) +#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1) +#endif + +#if MICROPY_PY_OS_DUPTERM +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#else +#define MP_PLAT_PRINT_STRN(str, len) do { ssize_t ret = write(1, str, len); (void)ret; } while (0) +#endif + +#ifdef __linux__ +// Can access physical memory using /dev/mem +#define MICROPY_PLAT_DEV_MEM (1) +#endif + +// Assume that select() call, interrupted with a signal, and erroring +// with EINTR, updates remaining timeout value. +#define MICROPY_SELECT_REMAINING_TIME (1) + +#ifdef __ANDROID__ +#include +#if __ANDROID_API__ < 4 +// Bionic libc in Android 1.5 misses these 2 functions +#define MP_NEED_LOG2 (1) +#define nan(x) NAN +#endif +#endif + +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[50]; \ + void *mmap_region_head; \ + +// We need to provide a declaration/definition of alloca() +// unless support for it is disabled. +#if !defined(MICROPY_NO_ALLOCA) || MICROPY_NO_ALLOCA == 0 +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#endif + +// From "man readdir": "Under glibc, programs can check for the availability +// of the fields [in struct dirent] not defined in POSIX.1 by testing whether +// the macros [...], _DIRENT_HAVE_D_TYPE are defined." +// Other libc's don't define it, but proactively assume that dirent->d_type +// is available on a modern *nix system. +#ifndef _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_TYPE (1) +#endif +// This macro is not provided by glibc but we need it so ports that don't have +// dirent->d_ino can disable the use of this field. +#ifndef _DIRENT_HAVE_D_INO +#define _DIRENT_HAVE_D_INO (1) +#endif + +#ifndef __APPLE__ +// For debugging purposes, make printf() available to any source file. +#include +#endif diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport.mk b/src/openmv/src/micropython/ports/unix/mpconfigport.mk new file mode 100755 index 0000000..f0aa955 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport.mk @@ -0,0 +1,42 @@ +# Enable/disable modules and 3rd-party libs to be included in interpreter + +# Build 32-bit binaries on a 64-bit host +MICROPY_FORCE_32BIT = 0 + +# This variable can take the following values: +# 0 - no readline, just simple stdin input +# 1 - use MicroPython version of readline +MICROPY_USE_READLINE = 1 + +# btree module using Berkeley DB 1.xx +MICROPY_PY_BTREE = 1 + +# _thread module using pthreads +MICROPY_PY_THREAD = 1 + +# Subset of CPython termios module +MICROPY_PY_TERMIOS = 1 + +# Subset of CPython socket module +MICROPY_PY_SOCKET = 1 + +# ffi module requires libffi (libffi-dev Debian package) +MICROPY_PY_FFI = 1 + +# ussl module requires one of the TLS libraries below +MICROPY_PY_USSL = 1 +# axTLS has minimal size and fully integrated with MicroPython, but +# implements only a subset of modern TLS functionality, so may have +# problems with some servers. +MICROPY_SSL_AXTLS = 1 +# mbedTLS is more up to date and complete implementation, but also +# more bloated. Configuring and building of mbedTLS should be done +# outside of MicroPython, it can just link with mbedTLS library. +MICROPY_SSL_MBEDTLS = 0 + +# jni module requires JVM/JNI +MICROPY_PY_JNI = 0 + +# Avoid using system libraries, use copies bundled with MicroPython +# as submodules (currently affects only libffi). +MICROPY_STANDALONE = 0 diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport_coverage.h b/src/openmv/src/micropython/ports/unix/mpconfigport_coverage.h new file mode 100755 index 0000000..9ab442f --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport_coverage.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Default unix config while intended to be comprehensive, may still not enable +// all the features, this config should enable more (testable) options. + +#define MICROPY_VFS (1) +#define MICROPY_PY_UOS_VFS (1) + +#include + +#define MICROPY_OPT_MATH_FACTORIAL (1) +#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_READER_VFS (1) +#define MICROPY_MODULE_GETATTR (1) +#define MICROPY_PY_DELATTR_SETATTR (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_RANGE_BINOP (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY_SYS_GETSIZEOF (1) +#define MICROPY_PY_MATH_FACTORIAL (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_IO_RESOURCE_STREAM (1) +#define MICROPY_PY_URE_MATCH_GROUPS (1) +#define MICROPY_PY_URE_MATCH_SPAN_START_END (1) +#define MICROPY_PY_URE_SUB (1) +#define MICROPY_VFS_POSIX (1) +#undef MICROPY_VFS_FAT +#define MICROPY_VFS_FAT (1) +#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) +#define MICROPY_PY_UCRYPTOLIB (1) + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio mp_type_vfs_posix_fileio +#define mp_type_textio mp_type_vfs_posix_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport_fast.h b/src/openmv/src/micropython/ports/unix/mpconfigport_fast.h new file mode 100755 index 0000000..442159e --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport_fast.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This config file is intended to configure artificially fast uPy build for +// synthetic benchmarking, at the expense of features supported and memory +// usage. This config is not intended to be used in production. + +#include +#define MICROPY_PY___FILE__ (0) +// 91 is a magic number proposed by @dpgeorge, which make pystone run ~ at tie +// with CPython 3.4. +#define MICROPY_MODULE_DICT_SIZE (91) + +// Don't include builtin upip, as this build is again intended just for +// synthetic benchmarking +#undef MICROPY_MODULE_FROZEN_STR +#define MICROPY_MODULE_FROZEN_STR (0) diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport_freedos.h b/src/openmv/src/micropython/ports/unix/mpconfigport_freedos.h new file mode 100755 index 0000000..09c85ab --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport_freedos.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#include + +#undef MICROPY_STREAMS_NON_BLOCK +#define MICROPY_STREAMS_NON_BLOCK (0) + +#undef MICROPY_PY_SYS_PLATFORM +#define MICROPY_PY_SYS_PLATFORM "freedos" + +// djgpp dirent struct does not have d_ino field +#undef _DIRENT_HAVE_D_INO + +#define MICROPY_USE_INTERNAL_ERRNO (1) diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport_minimal.h b/src/openmv/src/micropython/ports/unix/mpconfigport_minimal.h new file mode 100755 index 0000000..c49819e --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport_minimal.h @@ -0,0 +1,144 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_QSTR_CHUNK_INIT (64) +#define MICROPY_ALLOC_PARSE_RULE_INIT (8) +#define MICROPY_ALLOC_PARSE_RULE_INC (8) +#define MICROPY_ALLOC_PARSE_RESULT_INIT (8) +#define MICROPY_ALLOC_PARSE_RESULT_INC (8) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_ENABLE_FINALISER (0) +#define MICROPY_STACK_CHECK (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_MEM_STATS (0) +#define MICROPY_DEBUG_PRINTERS (0) +#define MICROPY_READER_POSIX (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#define MICROPY_WARNINGS (0) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#define MICROPY_STREAMS_NON_BLOCK (0) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_CAN_OVERRIDE_BUILTINS (0) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_COMPILE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_GC_COLLECT_RETVAL (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_EXIT (0) +#define MICROPY_PY_SYS_PLATFORM "linux" +#define MICROPY_PY_SYS_MAXSIZE (0) +#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UTIME (0) +#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_URE (0) +#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UBINASCII (0) + +extern const struct _mp_obj_module_t mp_module_os; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ + +#define MICROPY_PORT_ROOT_POINTERS \ + +////////////////////////////////////////// +// Do not change anything beyond this line +////////////////////////////////////////// + +// Define to 1 to use undertested inefficient GC helper implementation +// (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP + #ifdef __mips__ + #define MICROPY_GCREGS_SETJMP (1) + #else + #define MICROPY_GCREGS_SETJMP (0) + #endif +#endif + +// type definitions for the specific machine + +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +// We need to provide a declaration/definition of alloca() +#ifdef __FreeBSD__ +#include +#else +#include +#endif diff --git a/src/openmv/src/micropython/ports/unix/mpconfigport_nanbox.h b/src/openmv/src/micropython/ports/unix/mpconfigport_nanbox.h new file mode 100755 index 0000000..7da2cf7 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpconfigport_nanbox.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// select nan-boxing object model +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D) + +// native emitters don't work with nan-boxing +#define MICROPY_EMIT_X86 (0) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_ARM (0) + +#include + +typedef int64_t mp_int_t; +typedef uint64_t mp_uint_t; +#define UINT_FMT "%llu" +#define INT_FMT "%lld" + +#include diff --git a/src/openmv/src/micropython/ports/unix/mphalport.h b/src/openmv/src/micropython/ports/unix/mphalport.h new file mode 100755 index 0000000..ff7a515 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mphalport.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#ifndef CHAR_CTRL_C +#define CHAR_CTRL_C (3) +#endif + +void mp_hal_set_interrupt_char(char c); + +void mp_hal_stdio_mode_raw(void); +void mp_hal_stdio_mode_orig(void); + +#if MICROPY_USE_READLINE == 1 && MICROPY_PY_BUILTINS_INPUT +#include "py/misc.h" +#include "lib/mp-readline/readline.h" +// For built-in input() we need to wrap the standard readline() to enable raw mode +#define mp_hal_readline mp_hal_readline +static inline int mp_hal_readline(vstr_t *vstr, const char *p) { + mp_hal_stdio_mode_raw(); + int ret = readline(vstr, p); + mp_hal_stdio_mode_orig(); + return ret; +} +#endif + +// TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep: +// "The useconds argument shall be less than one million." +static inline void mp_hal_delay_ms(mp_uint_t ms) { usleep((ms) * 1000); } +static inline void mp_hal_delay_us(mp_uint_t us) { usleep(us); } +#define mp_hal_ticks_cpu() 0 + +#define RAISE_ERRNO(err_flag, error_val) \ + { if (err_flag == -1) \ + { mp_raise_OSError(error_val); } } diff --git a/src/openmv/src/micropython/ports/unix/mpthreadport.c b/src/openmv/src/micropython/ports/unix/mpthreadport.c new file mode 100755 index 0000000..baca0a2 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpthreadport.c @@ -0,0 +1,231 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/mpthread.h" +#include "py/gc.h" + +#if MICROPY_PY_THREAD + +#include +#include + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + pthread_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + struct _thread_t *next; +} thread_t; + +STATIC pthread_key_t tls_key; + +// the mutex controls access to the linked list +STATIC pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; +STATIC thread_t *thread; + +// this is used to synchronise the signal handler of the thread +// it's needed because we can't use any pthread calls in a signal handler +STATIC volatile int thread_signal_done; + +// this signal handler is used to scan the regs and stack of a thread +STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { + (void)info; // unused + (void)context; // unused + if (signo == SIGUSR1) { + void gc_collect_regs_and_stack(void); + gc_collect_regs_and_stack(); + // We have access to the context (regs, stack) of the thread but it seems + // that we don't need the extra information, enough is captured by the + // gc_collect_regs_and_stack function above + //gc_collect_root((void**)context, sizeof(ucontext_t) / sizeof(uintptr_t)); + #if MICROPY_ENABLE_PYSTACK + void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif + thread_signal_done = 1; + } +} + +void mp_thread_init(void) { + pthread_key_create(&tls_key, NULL); + pthread_setspecific(tls_key, &mp_state_ctx.thread); + + // create first entry in linked list of all threads + thread = malloc(sizeof(thread_t)); + thread->id = pthread_self(); + thread->ready = 1; + thread->arg = NULL; + thread->next = NULL; + + // enable signal handler for garbage collection + struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = mp_thread_gc; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR1, &sa, NULL); +} + +// This function scans all pointers that are external to the current thread. +// It does this by signalling all other threads and getting them to scan their +// own registers and stack. Note that there may still be some edge cases left +// with race conditions and root-pointer scanning: a given thread may manipulate +// the global root pointers (in mp_state_ctx) while another thread is doing a +// garbage collection and tracing these pointers. +void mp_thread_gc_others(void) { + pthread_mutex_lock(&thread_mutex); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root(&th->arg, 1); + if (th->id == pthread_self()) { + continue; + } + if (!th->ready) { + continue; + } + thread_signal_done = 0; + pthread_kill(th->id, SIGUSR1); + while (thread_signal_done == 0) { + sched_yield(); + } + } + pthread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return (mp_state_thread_t*)pthread_getspecific(tls_key); +} + +void mp_thread_set_state(void *state) { + pthread_setspecific(tls_key, state); +} + +void mp_thread_start(void) { + pthread_mutex_lock(&thread_mutex); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == pthread_self()) { + th->ready = 1; + break; + } + } + pthread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + // default stack size is 8k machine-words + if (*stack_size == 0) { + *stack_size = 8192 * BYTES_PER_WORD; + } + + // minimum stack size is set by pthreads + if (*stack_size < PTHREAD_STACK_MIN) { + *stack_size = PTHREAD_STACK_MIN; + } + + // set thread attributes + pthread_attr_t attr; + int ret = pthread_attr_init(&attr); + if (ret != 0) { + goto er; + } + ret = pthread_attr_setstacksize(&attr, *stack_size); + if (ret != 0) { + goto er; + } + + pthread_mutex_lock(&thread_mutex); + + // create thread + pthread_t id; + ret = pthread_create(&id, &attr, entry, arg); + if (ret != 0) { + pthread_mutex_unlock(&thread_mutex); + goto er; + } + + // adjust stack_size to provide room to recover from hitting the limit + // this value seems to be about right for both 32-bit and 64-bit builds + *stack_size -= 8192; + + // add thread to linked list of all threads + thread_t *th = malloc(sizeof(thread_t)); + th->id = id; + th->ready = 0; + th->arg = arg; + th->next = thread; + thread = th; + + pthread_mutex_unlock(&thread_mutex); + + return; + +er: + mp_raise_OSError(ret); +} + +void mp_thread_finish(void) { + pthread_mutex_lock(&thread_mutex); + // TODO unlink from list + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == pthread_self()) { + th->ready = 0; + break; + } + } + pthread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + pthread_mutex_init(mutex, NULL); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + int ret; + if (wait) { + ret = pthread_mutex_lock(mutex); + if (ret == 0) { + return 1; + } + } else { + ret = pthread_mutex_trylock(mutex); + if (ret == 0) { + return 1; + } else if (ret == EBUSY) { + return 0; + } + } + return -ret; +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + pthread_mutex_unlock(mutex); + // TODO check return value +} + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/ports/unix/mpthreadport.h b/src/openmv/src/micropython/ports/unix/mpthreadport.h new file mode 100755 index 0000000..b158ed5 --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/mpthreadport.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +typedef pthread_mutex_t mp_thread_mutex_t; + +void mp_thread_init(void); +void mp_thread_gc_others(void); diff --git a/src/openmv/src/micropython/ports/unix/qstrdefsport.h b/src/openmv/src/micropython/ports/unix/qstrdefsport.h new file mode 100755 index 0000000..ebfaa6c --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/qstrdefsport.h @@ -0,0 +1,25 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/src/openmv/src/micropython/ports/unix/unix_mphal.c b/src/openmv/src/micropython/ports/unix/unix_mphal.c new file mode 100755 index 0000000..f27c62f --- /dev/null +++ b/src/openmv/src/micropython/ports/unix/unix_mphal.c @@ -0,0 +1,199 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" +#include "extmod/misc.h" + +#ifndef _WIN32 +#include + +STATIC void sighandler(int signum) { + if (signum == SIGINT) { + #if MICROPY_ASYNC_KBD_INTR + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + sigset_t mask; + sigemptyset(&mask); + // On entry to handler, its signal is blocked, and unblocked on + // normal exit. As we instead perform longjmp, unblock it manually. + sigprocmask(SIG_SETMASK, &mask, NULL); + nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + #else + if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) { + // this is the second time we are called, so die straight away + exit(1); + } + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + #endif + } +} +#endif + +void mp_hal_set_interrupt_char(char c) { + // configure terminal settings to (not) let ctrl-C through + if (c == CHAR_CTRL_C) { + #ifndef _WIN32 + // enable signal handler + struct sigaction sa; + sa.sa_flags = 0; + sa.sa_handler = sighandler; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + #endif + } else { + #ifndef _WIN32 + // disable signal handler + struct sigaction sa; + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + #endif + } +} + +#if MICROPY_USE_READLINE == 1 + +#include + +static struct termios orig_termios; + +void mp_hal_stdio_mode_raw(void) { + // save and set terminal settings + tcgetattr(0, &orig_termios); + static struct termios termios; + termios = orig_termios; + termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8; + termios.c_lflag = 0; + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSAFLUSH, &termios); +} + +void mp_hal_stdio_mode_orig(void) { + // restore terminal settings + tcsetattr(0, TCSAFLUSH, &orig_termios); +} + +#endif + +#if MICROPY_PY_OS_DUPTERM +static int call_dupterm_read(size_t idx) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t read_m[3]; + mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_read, read_m); + read_m[2] = MP_OBJ_NEW_SMALL_INT(1); + mp_obj_t res = mp_call_method_n_kw(1, 0, read_m); + if (res == mp_const_none) { + return -2; + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len == 0) { + mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n"); + MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; + return -1; + } + nlr_pop(); + return *(byte*)bufinfo.buf; + } else { + // Temporarily disable dupterm to avoid infinite recursion + mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]); + MP_STATE_VM(dupterm_objs[idx]) = NULL; + mp_printf(&mp_plat_print, "dupterm: "); + mp_obj_print_exception(&mp_plat_print, nlr.ret_val); + MP_STATE_VM(dupterm_objs[idx]) = save_term; + } + + return -1; +} +#endif + +int mp_hal_stdin_rx_chr(void) { + unsigned char c; +#if MICROPY_PY_OS_DUPTERM + // TODO only support dupterm one slot at the moment + if (MP_STATE_VM(dupterm_objs[0]) != MP_OBJ_NULL) { + int c; + do { + c = call_dupterm_read(0); + } while (c == -2); + if (c == -1) { + goto main_term; + } + if (c == '\n') { + c = '\r'; + } + return c; + } else { + main_term:; +#endif + int ret = read(0, &c, 1); + if (ret == 0) { + c = 4; // EOF, ctrl-D + } else if (c == '\n') { + c = '\r'; + } + return c; +#if MICROPY_PY_OS_DUPTERM + } +#endif +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + int ret = write(1, str, len); + mp_uos_dupterm_tx_strn(str, len); + (void)ret; // to suppress compiler warning +} + +// cooked is same as uncooked because the terminal does some postprocessing +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + mp_hal_stdout_tx_strn(str, len); +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +mp_uint_t mp_hal_ticks_ms(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +mp_uint_t mp_hal_ticks_us(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} diff --git a/src/openmv/src/micropython/ports/windows/.appveyor.yml b/src/openmv/src/micropython/ports/windows/.appveyor.yml new file mode 100755 index 0000000..795330e --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/.appveyor.yml @@ -0,0 +1,52 @@ +environment: + # Python version used + MICROPY_CPYTHON3: c:/python34/python.exe + +init: + # Set build version number to commit to be travis-like +- ps: Update-AppveyorBuild -Version $env:appveyor_repo_commit.substring(0,8) + +configuration: +- Debug +- Release + +platform: +- x86 +- x64 + +build: + project: ports/windows/micropython.vcxproj + verbosity: normal + +test_script: +- cmd: >- + cd tests + + %MICROPY_CPYTHON3% run-tests + +# After the build/test phase for the MSVC build completes, +# build and test with mingw-w64, release versions only. +after_test: +- ps: | + if ($env:configuration -eq 'Debug') { + return + } + $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'} + $env:CHERE_INVOKING = 'enabled_from_arguments' + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows') + C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1" + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM build exited with code $LASTEXITCODE" + } + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') + & $env:MICROPY_CPYTHON3 run-tests -e math_fun -e float2int_double -e float_parse -e math_domain_special + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM tests exited with code $LASTEXITCODE" + } + +skip_tags: true + +deploy: off + +nuget: + disable_publish_on_pr: true diff --git a/src/openmv/src/micropython/ports/windows/.gitignore b/src/openmv/src/micropython/ports/windows/.gitignore new file mode 100755 index 0000000..12235e7 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/.gitignore @@ -0,0 +1,11 @@ +*.user +*.*sdf +*.suo +*.sln +*.exe +*.pdb +*.ilk +*.filters +/build/* +.vs/* +*.VC.*db diff --git a/src/openmv/src/micropython/ports/windows/Makefile b/src/openmv/src/micropython/ports/windows/Makefile new file mode 100755 index 0000000..61a6b28 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/Makefile @@ -0,0 +1,62 @@ +include ../../py/mkenv.mk +-include mpconfigport.mk + +# define main target +PROG = micropython.exe + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = ../unix/qstrdefsport.h + +# include py core make definitions +include $(TOP)/py/py.mk + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +# compiler settings +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -DUNIX -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS_MOD) $(COPT) +LDFLAGS = $(LDFLAGS_MOD) -lm + +# Debugging/Optimization +ifdef DEBUG +CFLAGS += -g +COPT = -O0 +else +COPT = -Os #-DNDEBUG +endif + +# source files +SRC_C = \ + lib/utils/printf.c \ + ports/unix/main.c \ + ports/unix/file.c \ + ports/unix/input.c \ + ports/unix/modos.c \ + ports/unix/modmachine.c \ + ports/unix/modtime.c \ + ports/unix/gccollect.c \ + windows_mphal.c \ + realpath.c \ + init.c \ + sleep.c \ + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +ifeq ($(MICROPY_USE_READLINE),1) +CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +SRC_C += lib/mp-readline/readline.c +else ifeq ($(MICROPY_USE_READLINE),2) +CFLAGS_MOD += -DMICROPY_USE_READLINE=2 +LDFLAGS_MOD += -lreadline +endif + +LIB += -lws2_32 + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) +# Append any auto-generated sources that are needed by sources listed in +# SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +include $(TOP)/py/mkrules.mk diff --git a/src/openmv/src/micropython/ports/windows/README.md b/src/openmv/src/micropython/ports/windows/README.md new file mode 100755 index 0000000..f1bd405 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/README.md @@ -0,0 +1,74 @@ +This is the experimental, community-supported Windows port of MicroPython. +It is based on Unix port, and expected to remain so. +The port requires additional testing, debugging, and patches. Please +consider to contribute. + + +Building on Debian/Ubuntu Linux system +--------------------------------------- + + sudo apt-get install gcc-mingw-w64 + make CROSS_COMPILE=i686-w64-mingw32- + +If for some reason the mingw-w64 crosscompiler is not available, you can try +mingw32 instead, but it comes with a really old gcc which may produce some +spurious errors (you may need to disable -Werror): + + sudo apt-get install mingw32 mingw32-binutils mingw32-runtime + make CROSS_COMPILE=i586-mingw32msvc- + + +Building under Cygwin +--------------------- + +Install following packages using cygwin's setup.exe: + +* mingw64-i686-gcc-core +* mingw64-x86_64-gcc-core +* make + +Build using: + + make CROSS_COMPILE=i686-w64-mingw32- + +Or for 64bit: + + make CROSS_COMPILE=x86_64-w64-mingw32- + + +Building using MS Visual Studio 2013 (or higher) +------------------------------------------------ + +In the IDE, open `micropython.vcxproj` and build. + +To build from the command line: + + msbuild micropython.vcxproj + +__Stack usage__ + +The msvc compiler is quite stack-hungry which might result in a "maximum recursion depth exceeded" +RuntimeError for code with lots of nested function calls. +There are several ways to deal with this: +- increase the threshold used for detection by altering the argument to `mp_stack_set_limit` in `ports/unix/main.c` +- disable detection all together by setting `MICROPY_STACK_CHECK` to "0" in `ports/windows/mpconfigport.h` +- disable the /GL compiler flag by setting `WholeProgramOptimization` to "false" + +See [issue 2927](https://github.com/micropython/micropython/issues/2927) for more information. + + +Running on Linux using Wine +--------------------------- + +The default build (MICROPY_USE_READLINE=1) uses extended Windows console +functions and thus should be ran using the `wineconsole` tool. Depending +on the Wine build configuration, you may also want to select the curses +backend which has the look&feel of a standard Unix console: + + wineconsole --backend=curses ./micropython.exe + +For more info, see https://www.winehq.org/docs/wineusr-guide/cui-programs . + +If built without line editing and history capabilities +(MICROPY_USE_READLINE=0), the resulting binary can be run using the standard +`wine` tool. diff --git a/src/openmv/src/micropython/ports/windows/fmode.c b/src/openmv/src/micropython/ports/windows/fmode.c new file mode 100755 index 0000000..33ba24e --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/fmode.c @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "fmode.h" +#include "py/mpconfig.h" +#include +#include + +// Workaround for setting file translation mode: we must distinguish toolsets +// since mingw has no _set_fmode, and altering msvc's _fmode directly has no effect +STATIC int set_fmode_impl(int mode) { +#ifndef _MSC_VER + _fmode = mode; + return 0; +#else + return _set_fmode(mode); +#endif +} + +void set_fmode_binary(void) { + set_fmode_impl(O_BINARY); +} + +void set_fmode_text(void) { + set_fmode_impl(O_TEXT); +} diff --git a/src/openmv/src/micropython/ports/windows/fmode.h b/src/openmv/src/micropython/ports/windows/fmode.h new file mode 100755 index 0000000..c661c84 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/fmode.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WINDOWS_FMODE_H +#define MICROPY_INCLUDED_WINDOWS_FMODE_H + +// Treat files opened by open() as binary. No line ending translation is done. +void set_fmode_binary(void); + +// Treat files opened by open() as text. +// When reading from the file \r\n will be converted to \n. +// When writing to the file \n will be converted into \r\n. +void set_fmode_text(void); + +#endif // MICROPY_INCLUDED_WINDOWS_FMODE_H diff --git a/src/openmv/src/micropython/ports/windows/init.c b/src/openmv/src/micropython/ports/windows/init.c new file mode 100755 index 0000000..09fa104 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/init.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#ifdef _MSC_VER +#include +#endif +#include "sleep.h" + +extern BOOL WINAPI console_sighandler(DWORD evt); + +#ifdef _MSC_VER +void invalid_param_handler(const wchar_t *expr, const wchar_t *fun, const wchar_t *file, unsigned int line, uintptr_t p) { +} +#endif + +void init() { +#ifdef _MSC_VER + // Disable the 'Debug Error!' dialog for assertions failures and the likes, + // instead write messages to the debugger output and terminate. + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); + + // Disable 'invalid parameter handling' which is for instance invoked when + // passing invalid file descriptors to functions like lseek() and make the + // functions called behave properly by setting errno to EBADF/EINVAL/.. + _set_invalid_parameter_handler(invalid_param_handler); +#endif + SetConsoleCtrlHandler(console_sighandler, TRUE); + init_sleep(); +#ifdef __MINGW32__ + putenv("PRINTF_EXPONENT_DIGITS=2"); +#elif _MSC_VER < 1900 + // This is only necessary for Visual Studio versions 2013 and below: + // https://msdn.microsoft.com/en-us/library/bb531344(v=vs.140).aspx + _set_output_format(_TWO_DIGIT_EXPONENT); +#endif +} + +void deinit() { + SetConsoleCtrlHandler(console_sighandler, FALSE); + deinit_sleep(); +} diff --git a/src/openmv/src/micropython/ports/windows/init.h b/src/openmv/src/micropython/ports/windows/init.h new file mode 100755 index 0000000..c6fddb2 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/init.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WINDOWS_INIT_H +#define MICROPY_INCLUDED_WINDOWS_INIT_H + +void init(void); +void deinit(void); + +#endif // MICROPY_INCLUDED_WINDOWS_INIT_H diff --git a/src/openmv/src/micropython/ports/windows/micropython.vcxproj b/src/openmv/src/micropython/ports/windows/micropython.vcxproj new file mode 100755 index 0000000..27d6257 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/micropython.vcxproj @@ -0,0 +1,104 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {740F3C30-EB6C-4B59-9C50-AE4D5A4A9D12} + micropython + + + + Application + true + $(DefaultPlatformToolset) + MultiByte + + + Application + false + $(DefaultPlatformToolset) + true + MultiByte + + + Application + true + $(DefaultPlatformToolset) + MultiByte + + + Application + false + $(DefaultPlatformToolset) + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + msvc/user.props + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/windows/mpconfigport.h b/src/openmv/src/micropython/ports/windows/mpconfigport.h new file mode 100755 index 0000000..03af97b --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/mpconfigport.h @@ -0,0 +1,260 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +// Linking with GNU readline (MICROPY_USE_READLINE == 2) causes binary to be licensed under GPL +#ifndef MICROPY_USE_READLINE +#define MICROPY_USE_READLINE (1) +#endif + +#define MICROPY_ALLOC_PATH_MAX (260) //see minwindef.h for msvc or limits.h for mingw +#define MICROPY_PERSISTENT_CODE_LOAD (1) +#define MICROPY_EMIT_X64 (0) +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_RETURN_IF_EXPR (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_ENABLE_PYSTACK (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) +#define MICROPY_MEM_STATS (1) +#define MICROPY_DEBUG_PRINTER (&mp_stderr_print) +#define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_READER_POSIX (1) +#define MICROPY_USE_READLINE_HISTORY (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_PLATFORM "win32" +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_GC_COLLECT_RETVAL (1) +#define MICROPY_MODULE_FROZEN_STR (0) + +#define MICROPY_STACKLESS (0) +#define MICROPY_STACKLESS_STRICT (0) + +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr +#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr + +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_ERROR_PRINTER (&mp_stderr_print) +#define MICROPY_WARNINGS (1) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) + +extern const struct _mp_print_t mp_stderr_print; + +#ifdef _MSC_VER +#define MICROPY_GCREGS_SETJMP (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) +#endif + +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256) +#define MICROPY_KBD_EXCEPTION (1) + +#define MICROPY_PORT_INIT_FUNC init() +#define MICROPY_PORT_DEINIT_FUNC deinit() + +// type definitions for the specific machine + +#if defined( __MINGW32__ ) && defined( __LP64__ ) +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#elif defined ( __MINGW32__ ) && defined( _WIN64 ) +#include +typedef __int64 mp_int_t; +typedef unsigned __int64 mp_uint_t; +#define MP_SSIZE_MAX __INT64_MAX__ +#elif defined ( _MSC_VER ) && defined( _WIN64 ) +typedef __int64 mp_int_t; +typedef unsigned __int64 mp_uint_t; +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +// Just assume Windows is little-endian - mingw32 gcc doesn't +// define standard endianness macros. +#define MP_ENDIANNESS_LITTLE (1) + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +#if MICROPY_PY_OS_DUPTERM +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +void mp_hal_dupterm_tx_strn(const char *str, size_t len); +#else +#include +#define MP_PLAT_PRINT_STRN(str, len) do { int ret = write(1, str, len); (void)ret; } while (0) +#define mp_hal_dupterm_tx_strn(s, l) +#endif + +#define MICROPY_PORT_BUILTINS \ + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +extern const struct _mp_obj_module_t mp_module_os; +extern const struct _mp_obj_module_t mp_module_time; +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, \ + { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ + { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ + +#if MICROPY_USE_READLINE == 1 +#define MICROPY_PORT_ROOT_POINTERS \ + char *readline_hist[50]; +#endif + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_MPHALPORT_H "windows_mphal.h" + +// We need to provide a declaration/definition of alloca() +#include + +#include "realpath.h" +#include "init.h" +#include "sleep.h" + +#ifdef __GNUC__ +#define MP_NOINLINE __attribute__((noinline)) +#endif + +// MSVC specifics +#ifdef _MSC_VER + +// Sanity check + +#if ( _MSC_VER < 1800 ) + #error Can only build with Visual Studio 2013 toolset +#endif + + +// CL specific overrides from mpconfig + +#define NORETURN __declspec(noreturn) +#define MP_NOINLINE __declspec(noinline) +#define MP_LIKELY(x) (x) +#define MP_UNLIKELY(x) (x) +#define MICROPY_PORT_CONSTANTS { "dummy", 0 } //can't have zero-sized array +#ifdef _WIN64 +#define MP_SSIZE_MAX _I64_MAX +#else +#define MP_SSIZE_MAX _I32_MAX +#endif + + +// CL specific definitions + +#define restrict +#define inline __inline +#define alignof(t) __alignof(t) +#define PATH_MAX MICROPY_ALLOC_PATH_MAX +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#ifdef _WIN64 +#define SSIZE_MAX _I64_MAX +typedef __int64 ssize_t; +#else +#define SSIZE_MAX _I32_MAX +typedef int ssize_t; +#endif +typedef mp_off_t off_t; + + +// Put static/global variables in sections with a known name +// This used to be required for GC, not the case anymore but keep it as it makes the map file easier to inspect +// For this to work this header must be included by all sources, which is the case normally +#define MICROPY_PORT_DATASECTION "upydata" +#define MICROPY_PORT_BSSSECTION "upybss" +#pragma data_seg(MICROPY_PORT_DATASECTION) +#pragma bss_seg(MICROPY_PORT_BSSSECTION) + + +// System headers (needed e.g. for nlr.h) + +#include //for NULL +#include //for assert + +#endif diff --git a/src/openmv/src/micropython/ports/windows/mpconfigport.mk b/src/openmv/src/micropython/ports/windows/mpconfigport.mk new file mode 100755 index 0000000..87001d4 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/mpconfigport.mk @@ -0,0 +1,10 @@ +# Enable/disable modules and 3rd-party libs to be included in interpreter + +# Build 32-bit binaries on a 64-bit host +MICROPY_FORCE_32BIT = 0 + +# Linking with GNU readline causes binary to be licensed under GPL +MICROPY_USE_READLINE = 1 + +# ffi module requires libffi (libffi-dev Debian package) +MICROPY_PY_FFI = 0 diff --git a/src/openmv/src/micropython/ports/windows/msvc/common.props b/src/openmv/src/micropython/ports/windows/msvc/common.props new file mode 100755 index 0000000..ae481e8 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/common.props @@ -0,0 +1,47 @@ + + + + + + + + $(PyOutDir) + $(PyIntDir) + $(PyBuildDir)copycookie$(Configuration)$(Platform) + + + + $(PyIncDirs);%(AdditionalIncludeDirectories) + _USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) + false + Level1 + false + true + false + + + true + true + + + + + $(PyWinDir)%(FileName)%(Extension) + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/windows/msvc/debug.props b/src/openmv/src/micropython/ports/windows/msvc/debug.props new file mode 100755 index 0000000..219f854 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/debug.props @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/openmv/src/micropython/ports/windows/msvc/dirent.c b/src/openmv/src/micropython/ports/windows/msvc/dirent.c new file mode 100755 index 0000000..053a3cd --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/dirent.c @@ -0,0 +1,118 @@ +/* +* This file is part of the MicroPython project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2015 Damien P. George +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include "dirent.h" +#include "extmod/vfs.h" +#include +#include + +typedef struct DIR { + HANDLE findHandle; + WIN32_FIND_DATA findData; + struct dirent result; +} DIR; + +DIR *opendir(const char *name) { + if (!name || !*name) { + errno = ENOENT; + return NULL; + } + + DIR *dir = malloc(sizeof(DIR)); + if (!dir) { + errno = ENOMEM; + return NULL; + } + dir->result.d_ino = 0; + dir->result.d_name = NULL; + dir->findHandle = INVALID_HANDLE_VALUE; + + const size_t nameLen = strlen(name); + char *path = malloc(nameLen + 3); // allocate enough for adding "/*" + if (!path) { + free(dir); + errno = ENOMEM; + return NULL; + } + strcpy(path, name); + + // assure path ends with wildcard + const char lastChar = path[nameLen - 1]; + if (lastChar != '*') { + const char *appendWC = (lastChar != '/' && lastChar != '\\') ? "/*" : "*"; + strcat(path, appendWC); + } + + // init + dir->findHandle = FindFirstFile(path, &dir->findData); + free(path); + if (dir->findHandle == INVALID_HANDLE_VALUE) { + free(dir); + errno = ENOENT; + return NULL; + } + return dir; +} + +int closedir(DIR *dir) { + if (dir) { + FindClose(dir->findHandle); + free(dir); + return 0; + } else { + errno = EBADF; + return -1; + } +} + +struct dirent *readdir(DIR *dir) { + if (!dir) { + errno = EBADF; + return NULL; + } + + // first pass d_name is NULL so use result from FindFirstFile in opendir, else use FindNextFile + if (!dir->result.d_name || FindNextFile(dir->findHandle, &dir->findData)) { + dir->result.d_name = dir->findData.cFileName; + dir->result.d_type = dir->findData.dwFileAttributes; + return &dir->result; + } + + return NULL; +} + +int dttoif(int d_type) { + if (d_type == INVALID_FILE_ATTRIBUTES) { + return 0; + } + // Could be a couple of things (symlink, junction, ...) and non-trivial to + // figure out so just report it as unknown. Should we ever want this then + // the proper code can be found in msvc's std::filesystem implementation. + if (d_type & FILE_ATTRIBUTE_REPARSE_POINT) { + return 0; + } + return (d_type & FILE_ATTRIBUTE_DIRECTORY) ? MP_S_IFDIR : MP_S_IFREG; +} diff --git a/src/openmv/src/micropython/ports/windows/msvc/dirent.h b/src/openmv/src/micropython/ports/windows/msvc/dirent.h new file mode 100755 index 0000000..2ad88b3 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/dirent.h @@ -0,0 +1,54 @@ +/* +* This file is part of the MicroPython project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2015 Damien P. George +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ +#ifndef MICROPY_INCLUDED_WINDOWS_MSVC_DIRENT_H +#define MICROPY_INCLUDED_WINDOWS_MSVC_DIRENT_H + +// dirent.h implementation for msvc + +// for ino_t +#include + +#define _DIRENT_HAVE_D_TYPE (1) +#define DTTOIF dttoif + +// opaque DIR structure +typedef struct DIR DIR; + +// the dirent structure +// d_ino is always 0 - if ever needed use GetFileInformationByHandle +// d_type can be converted using DTTOIF, into 0 (unknown) or MP_S_IFDIR or MP_S_IFREG +typedef struct dirent { + ino_t d_ino; + int d_type; + char *d_name; +} dirent; + +DIR *opendir(const char *name); +int closedir(DIR *dir); +struct dirent *readdir(DIR *dir); +int dttoif(int d_type); + +#endif // MICROPY_INCLUDED_WINDOWS_MSVC_DIRENT_H diff --git a/src/openmv/src/micropython/ports/windows/msvc/genhdr.targets b/src/openmv/src/micropython/ports/windows/msvc/genhdr.targets new file mode 100755 index 0000000..fa3e95e --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/genhdr.targets @@ -0,0 +1,119 @@ + + + + + + + + + + + $(PyBuildDir)genhdr\ + $(PyBaseDir)py\ + $(PyBaseDir)ports\unix\qstrdefsport.h + $(PySrcDir)qstrdefs.h + $(DestDir)qstrdefscollected.h + $(DestDir)qstrdefs.generated.h + python + cl.exe + $([System.IO.Path]::Combine(`$(CLToolPath)`, `$(CLToolExe)`)) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '$(DestDir)qstr\')) + + + $([System.IO.Path]::ChangeExtension('%(OutFile)', '.pp')) + $([System.IO.Path]::GetDirectoryName('%(OutFile)')) + + + True + + + True + + + + @(QstrDependencies->AnyHaveMetadataValue('Changed', 'True')) + @(PyQstrSourceFiles->AnyHaveMetadataValue('Changed', 'True')) + + + + + + + + + + + + $(QstrGen).tmp + + + + + + + + + $(DestDir)mpversion.h + $(DestFile).tmp + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/windows/msvc/gettimeofday.c b/src/openmv/src/micropython/ports/windows/msvc/gettimeofday.c new file mode 100755 index 0000000..5f816df --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/gettimeofday.c @@ -0,0 +1,58 @@ +/* +* This file is part of the MicroPython project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2013, 2014 Damien P. George +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include + +typedef union { + unsigned __int64 tm; // time in 100 nanoseconds interval + FILETIME ft; +} FT; + +int gettimeofday(struct timeval *tp, struct timezone *tz) { + if (tp == NULL) { + return 0; + } + + // UTC time + FT ft; + ZeroMemory(&ft, sizeof(ft)); + GetSystemTimeAsFileTime(&ft.ft); + + // to microseconds + ft.tm /= 10; + + // convert to unix format + // number of microseconds intervals between the 1st january 1601 and the 1st january 1970 (369 years + 89 leap days) + const unsigned __int64 deltaEpoch = 11644473600000000ull; + const unsigned __int64 microSecondsToSeconds = 1000000ull; + tp->tv_usec = ft.tm % microSecondsToSeconds; + tp->tv_sec = (ft.tm - deltaEpoch) / microSecondsToSeconds; + + // see man gettimeofday: timezone is deprecated and expected to be NULL + (void)tz; + + return 0; +} diff --git a/src/openmv/src/micropython/ports/windows/msvc/paths.props b/src/openmv/src/micropython/ports/windows/msvc/paths.props new file mode 100755 index 0000000..3d1b401 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/paths.props @@ -0,0 +1,45 @@ + + + + True + + + + + $([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..\..`))\ + $(PyBaseDir)ports\windows\ + $(PyWinDir)build\ + + + $(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc + + + $(Platform) + $(Configuration) + + + $(PyBuildDir)$(PyConfiguration)$(PyPlatform)\ + $(PyOutDir)obj\ + + diff --git a/src/openmv/src/micropython/ports/windows/msvc/release.props b/src/openmv/src/micropython/ports/windows/msvc/release.props new file mode 100755 index 0000000..c1d0c02 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/release.props @@ -0,0 +1,16 @@ + + + + + + + + true + true + + + true + + + + diff --git a/src/openmv/src/micropython/ports/windows/msvc/sources.props b/src/openmv/src/micropython/ports/windows/msvc/sources.props new file mode 100755 index 0000000..0f04d0c --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/sources.props @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/openmv/src/micropython/ports/windows/msvc/sys/time.h b/src/openmv/src/micropython/ports/windows/msvc/sys/time.h new file mode 100755 index 0000000..7c95d40 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/sys/time.h @@ -0,0 +1,32 @@ +/* +* This file is part of the MicroPython project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2013, 2014 Damien P. George +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ +#ifndef MICROPY_INCLUDED_WINDOWS_MSVC_SYS_TIME_H +#define MICROPY_INCLUDED_WINDOWS_MSVC_SYS_TIME_H + +// Get the definitions for timeval etc +#include + +#endif // MICROPY_INCLUDED_WINDOWS_MSVC_SYS_TIME_H diff --git a/src/openmv/src/micropython/ports/windows/msvc/unistd.h b/src/openmv/src/micropython/ports/windows/msvc/unistd.h new file mode 100755 index 0000000..1a1629b --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/msvc/unistd.h @@ -0,0 +1,44 @@ +/* +* This file is part of the MicroPython project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2013, 2014 Damien P. George +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ +#ifndef MICROPY_INCLUDED_WINDOWS_MSVC_UNISTD_H +#define MICROPY_INCLUDED_WINDOWS_MSVC_UNISTD_H + +// There's no unistd.h, but this is the equivalent +#include + +#define F_OK 0 +#define W_OK 2 +#define R_OK 4 + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 0 + +#endif // MICROPY_INCLUDED_WINDOWS_MSVC_UNISTD_H diff --git a/src/openmv/src/micropython/ports/windows/realpath.c b/src/openmv/src/micropython/ports/windows/realpath.c new file mode 100755 index 0000000..ac9adf8 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/realpath.c @@ -0,0 +1,64 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +// Make sure a path only has forward slashes. +char *to_unix_path(char *p) { + if (p != NULL) { + char *pp = p; + while (*pp != 0) { + if (*pp == '\\') + *pp = '/'; + ++pp; + } + } + return p; +} + +// Implement realpath() using _fullpath and make it use the same error codes as realpath() on unix. +// Also have it return a path with forward slashes only as some code relies on this, +// but _fullpath() returns backward slashes no matter what. +char *realpath(const char *path, char *resolved_path) { + char *ret = NULL; + if (path == NULL) { + errno = EINVAL; + } else if (access(path, R_OK) == 0) { + ret = resolved_path; + if (ret == NULL) + ret = malloc(_MAX_PATH); + if (ret == NULL) { + errno = ENOMEM; + } else { + ret = _fullpath(ret, path, _MAX_PATH); + if (ret == NULL) + errno = EIO; + } + } + return to_unix_path(ret); +} diff --git a/src/openmv/src/micropython/ports/windows/realpath.h b/src/openmv/src/micropython/ports/windows/realpath.h new file mode 100755 index 0000000..869fe80 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/realpath.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WINDOWS_REALPATH_H +#define MICROPY_INCLUDED_WINDOWS_REALPATH_H + +extern char *realpath(const char *path, char *resolved_path); + +#endif // MICROPY_INCLUDED_WINDOWS_REALPATH_H diff --git a/src/openmv/src/micropython/ports/windows/sleep.c b/src/openmv/src/micropython/ports/windows/sleep.c new file mode 100755 index 0000000..6043ec7 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/sleep.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +HANDLE waitTimer = NULL; + +void init_sleep(void) { + waitTimer = CreateWaitableTimer(NULL, TRUE, NULL); +} + +void deinit_sleep(void) { + if (waitTimer != NULL) { + CloseHandle(waitTimer); + waitTimer = NULL; + } +} + +int usleep_impl(__int64 usec) { + if (waitTimer == NULL) { + errno = EAGAIN; + return -1; + } + if (usec < 0 || usec > LLONG_MAX / 10) { + errno = EINVAL; + return -1; + } + + LARGE_INTEGER ft; + ft.QuadPart = -10 * usec; // 100 nanosecond interval, negative value = relative time + if (SetWaitableTimer(waitTimer, &ft, 0, NULL, NULL, 0) == 0) { + errno = EINVAL; + return -1; + } + if (WaitForSingleObject(waitTimer, INFINITE) != WAIT_OBJECT_0) { + errno = EAGAIN; + return -1; + } + return 0; +} + +#ifdef _MSC_VER // mingw and the likes provide their own usleep() +int usleep(__int64 usec) { + return usleep_impl(usec); +} +#endif + +void msec_sleep(double msec) { + const double usec = msec * 1000.0; + usleep_impl(usec > (double)LLONG_MAX ? LLONG_MAX : (__int64)usec); +} diff --git a/src/openmv/src/micropython/ports/windows/sleep.h b/src/openmv/src/micropython/ports/windows/sleep.h new file mode 100755 index 0000000..430ec3a --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/sleep.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_WINDOWS_SLEEP_H +#define MICROPY_INCLUDED_WINDOWS_SLEEP_H + +void init_sleep(void); +void deinit_sleep(void); +void msec_sleep(double msec); +#ifdef _MSC_VER +int usleep(__int64 usec); +#endif + +#endif // MICROPY_INCLUDED_WINDOWS_SLEEP_H diff --git a/src/openmv/src/micropython/ports/windows/windows_mphal.c b/src/openmv/src/micropython/ports/windows/windows_mphal.c new file mode 100755 index 0000000..153b044 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/windows_mphal.c @@ -0,0 +1,229 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "py/mpstate.h" +#include "py/mphal.h" + +#include +#include +#include + +HANDLE std_in = NULL; +HANDLE con_out = NULL; +DWORD orig_mode = 0; + +STATIC void assure_stdin_handle() { + if (!std_in) { + std_in = GetStdHandle(STD_INPUT_HANDLE); + assert(std_in != INVALID_HANDLE_VALUE); + } +} + +STATIC void assure_conout_handle() { + if (!con_out) { + con_out = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0); + assert(con_out != INVALID_HANDLE_VALUE); + } +} + +void mp_hal_stdio_mode_raw(void) { + assure_stdin_handle(); + GetConsoleMode(std_in, &orig_mode); + DWORD mode = orig_mode; + mode &= ~ENABLE_ECHO_INPUT; + mode &= ~ENABLE_LINE_INPUT; + mode &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); +} + +void mp_hal_stdio_mode_orig(void) { + assure_stdin_handle(); + SetConsoleMode(std_in, orig_mode); +} + +// Handler to be installed by SetConsoleCtrlHandler, currently used only to handle Ctrl-C. +// This handler has to be installed just once (this has to be done elswhere in init code). +// Previous versions of the mp_hal code would install a handler whenever Ctrl-C input is +// allowed and remove the handler again when it is not. That is not necessary though (1), +// and it might introduce problems (2) because console notifications are delivered to the +// application in a separate thread. +// (1) mp_hal_set_interrupt_char effectively enables/disables processing of Ctrl-C via the +// ENABLE_PROCESSED_INPUT flag so in raw mode console_sighandler won't be called. +// (2) if mp_hal_set_interrupt_char would remove the handler while Ctrl-C was issued earlier, +// the thread created for handling it might not be running yet so we'd miss the notification. +BOOL WINAPI console_sighandler(DWORD evt) { + if (evt == CTRL_C_EVENT) { + if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) { + // this is the second time we are called, so die straight away + exit(1); + } + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + return TRUE; + } + return FALSE; +} + +void mp_hal_set_interrupt_char(char c) { + assure_stdin_handle(); + if (c == CHAR_CTRL_C) { + DWORD mode; + GetConsoleMode(std_in, &mode); + mode |= ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); + } else { + DWORD mode; + GetConsoleMode(std_in, &mode); + mode &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); + } +} + +void mp_hal_move_cursor_back(uint pos) { + assure_conout_handle(); + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(con_out, &info); + info.dwCursorPosition.X -= (short)pos; + if (info.dwCursorPosition.X < 0) { + info.dwCursorPosition.X = 0; + } + SetConsoleCursorPosition(con_out, info.dwCursorPosition); +} + +void mp_hal_erase_line_from_cursor(uint n_chars_to_erase) { + assure_conout_handle(); + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(con_out, &info); + DWORD written; + FillConsoleOutputCharacter(con_out, ' ', n_chars_to_erase, info.dwCursorPosition, &written); + FillConsoleOutputAttribute(con_out, info.wAttributes, n_chars_to_erase, info.dwCursorPosition, &written); +} + +typedef struct item_t { + WORD vkey; + const char *seq; +} item_t; + +// map virtual key codes to VT100 escape sequences +STATIC item_t keyCodeMap[] = { + {VK_UP, "[A"}, + {VK_DOWN, "[B"}, + {VK_RIGHT, "[C"}, + {VK_LEFT, "[D"}, + {VK_HOME, "[H"}, + {VK_END, "[F"}, + {VK_DELETE, "[3~"}, + {0, ""} //sentinel +}; + +STATIC const char *cur_esc_seq = NULL; + +STATIC int esc_seq_process_vk(int vk) { + for (item_t *p = keyCodeMap; p->vkey != 0; ++p) { + if (p->vkey == vk) { + cur_esc_seq = p->seq; + return 27; // ESC, start of escape sequence + } + } + return 0; // nothing found +} + +STATIC int esc_seq_chr() { + if (cur_esc_seq) { + const char c = *cur_esc_seq++; + if (c) { + return c; + } + cur_esc_seq = NULL; + } + return 0; +} + +int mp_hal_stdin_rx_chr(void) { + // currently processing escape seq? + const int ret = esc_seq_chr(); + if (ret) { + return ret; + } + + // poll until key which we handle is pressed + assure_stdin_handle(); + DWORD num_read; + INPUT_RECORD rec; + for (;;) { + if (!ReadConsoleInput(std_in, &rec, 1, &num_read) || !num_read) { + return CHAR_CTRL_C; // EOF, ctrl-D + } + if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) { // only want key down events + continue; + } + const char c = rec.Event.KeyEvent.uChar.AsciiChar; + if (c) { // plain ascii char, return it + return c; + } + const int ret = esc_seq_process_vk(rec.Event.KeyEvent.wVirtualKeyCode); + if (ret) { + return ret; + } + } +} + +void mp_hal_stdout_tx_strn(const char *str, size_t len) { + write(1, str, len); +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + mp_hal_stdout_tx_strn(str, len); +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +mp_uint_t mp_hal_ticks_ms(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +mp_uint_t mp_hal_ticks_us(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} + +mp_uint_t mp_hal_ticks_cpu(void) { + LARGE_INTEGER value; + QueryPerformanceCounter(&value); +#ifdef _WIN64 + return value.QuadPart; +#else + return value.LowPart; +#endif +} diff --git a/src/openmv/src/micropython/ports/windows/windows_mphal.h b/src/openmv/src/micropython/ports/windows/windows_mphal.h new file mode 100755 index 0000000..2b7aab4 --- /dev/null +++ b/src/openmv/src/micropython/ports/windows/windows_mphal.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sleep.h" +#include "ports/unix/mphalport.h" + +#define MICROPY_HAL_HAS_VT100 (0) + +void mp_hal_move_cursor_back(unsigned int pos); +void mp_hal_erase_line_from_cursor(unsigned int n_chars_to_erase); + +#undef mp_hal_ticks_cpu +mp_uint_t mp_hal_ticks_cpu(void); diff --git a/src/openmv/src/micropython/ports/zephyr/.gitignore b/src/openmv/src/micropython/ports/zephyr/.gitignore new file mode 100755 index 0000000..00ca089 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/.gitignore @@ -0,0 +1 @@ +outdir/ diff --git a/src/openmv/src/micropython/ports/zephyr/CMakeLists.txt b/src/openmv/src/micropython/ports/zephyr/CMakeLists.txt new file mode 100755 index 0000000..8e01624 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.8) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c) + +add_library(libmicropython STATIC IMPORTED) +set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) +target_link_libraries(app PUBLIC libmicropython) + +zephyr_get_include_directories_for_lang_as_string(C includes) +zephyr_get_system_include_directories_for_lang_as_string(C system_includes) +zephyr_get_compile_definitions_for_lang_as_string(C definitions) +zephyr_get_compile_options_for_lang_as_string(C options) + +add_custom_target( + outputexports + COMMAND echo CC="${CMAKE_C_COMPILER}" + COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} + VERBATIM + USES_TERMINAL +) diff --git a/src/openmv/src/micropython/ports/zephyr/Kbuild b/src/openmv/src/micropython/ports/zephyr/Kbuild new file mode 100755 index 0000000..9e656d5 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/Kbuild @@ -0,0 +1,3 @@ +#subdir-ccflags-y += -I$(SOURCE_DIR)/../mylib/include + +obj-y += src/ diff --git a/src/openmv/src/micropython/ports/zephyr/Makefile b/src/openmv/src/micropython/ports/zephyr/Makefile new file mode 100755 index 0000000..8cb4c12 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/Makefile @@ -0,0 +1,109 @@ +# +# This is the main Makefile, which uses MicroPython build system, +# but Zephyr arch-specific toolchain and target-specific flags. +# This Makefile builds MicroPython as a library, and then calls +# recursively Makefile.zephyr to build complete application binary +# using Zephyr build system. +# +# To build a "minimal" configuration, use "make-minimal" wrapper. + +BOARD ?= qemu_x86 +CONF_FILE = prj_$(BOARD)_merged.conf +OUTDIR_PREFIX = $(BOARD) + +# Default heap size is 16KB, which is on conservative side, to let +# it build for smaller boards, but it won't be enough for larger +# applications, and will need to be increased. +MICROPY_HEAP_SIZE = 16384 +FROZEN_DIR = scripts + +# Default target +all: + +include ../../py/mkenv.mk +include $(TOP)/py/py.mk + +# Zephyr (generated) config files - must be defined before include below +Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export +ifneq ($(MAKECMDGOALS), clean) +include $(Z_EXPORTS) +endif + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(ZEPHYR_BASE)/net/ip +INC += -I$(ZEPHYR_BASE)/net/ip/contiki +INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os + +SRC_C = main.c \ + help.c \ + modusocket.c \ + modutime.c \ + modzephyr.c \ + modzsensor.c \ + modmachine.c \ + machine_pin.c \ + uart_core.c \ + lib/utils/stdout_helpers.c \ + lib/utils/printf.c \ + lib/utils/pyexec.c \ + lib/utils/interrupt_char.c \ + lib/mp-readline/readline.c \ + $(SRC_MOD) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) + +OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) + +CFLAGS = $(Z_CFLAGS) \ + -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) + +include $(TOP)/py/mkrules.mk + +GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver +KCONFIG_TARGETS = \ + initconfig config nconfig menuconfig xconfig gconfig \ + oldconfig silentoldconfig defconfig savedefconfig \ + allnoconfig allyesconfig alldefconfig randconfig \ + listnewconfig olddefconfig +CLEAN_TARGETS = pristine mrproper + +$(GENERIC_TARGETS): $(LIBMICROPYTHON) +$(CLEAN_TARGETS): clean + +$(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): + $(MAKE) -C outdir/$(BOARD) $@ + +$(LIBMICROPYTHON): | $(Z_EXPORTS) +build/genhdr/qstr.i.last: | $(Z_EXPORTS) + +# If we recreate libmicropython, also cause zephyr.bin relink +LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk + +# MicroPython's global clean cleans everything, fast +CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf + +# Clean Zephyr things in Zephyr way +z_clean: + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean + +# This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which +# can be overriden. +# prj_$(BOARD).conf is optional, that's why it's resolved with $(wildcard) +# function. +prj_$(BOARD)_merged.conf: prj_base.conf $(wildcard prj_$(BOARD).conf) + $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ + +test: + cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../ports/zephyr run BOARD=$(BOARD) QEMU_PTY=1" + +cmake: outdir/$(BOARD)/Makefile + +outdir/$(BOARD)/Makefile: $(CONF_FILE) + mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) -DCONF_FILE=$(CONF_FILE) -Boutdir/$(BOARD) -H. + +$(Z_EXPORTS): outdir/$(BOARD)/Makefile + make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ + make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target kobj_types_h_target diff --git a/src/openmv/src/micropython/ports/zephyr/Makefile.zephyr b/src/openmv/src/micropython/ports/zephyr/Makefile.zephyr new file mode 100755 index 0000000..16f0a94 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/Makefile.zephyr @@ -0,0 +1,30 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# 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. +# + +KERNEL_TYPE = micro +# BOARD must be passed on command line from main Makefile +#BOARD = +CONF_FILE = prj.conf +QEMU_NET = 1 + +#export SOURCE_DIR = $(ZEPHYR_BASE)/samples/static_lib/hello_world +export LDFLAGS_zephyr += -L$(CURDIR) +export ALL_LIBS += micropython + +include ${ZEPHYR_BASE}/Makefile.inc +ifeq ($(QEMU_NET), 1) +include ${ZEPHYR_BASE}/samples/net/common/Makefile.ipstack +endif diff --git a/src/openmv/src/micropython/ports/zephyr/README.md b/src/openmv/src/micropython/ports/zephyr/README.md new file mode 100755 index 0000000..f7001af --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/README.md @@ -0,0 +1,113 @@ +MicroPython port to Zephyr RTOS +=============================== + +This is an work-in-progress port of MicroPython to Zephyr RTOS +(http://zephyrproject.org). + +This port requires Zephyr version 1.8 or higher. All boards supported +by Zephyr (with standard level of features support, like UART console) +should work with MicroPython (but not all were tested). + +Features supported at this time: + +* REPL (interactive prompt) over Zephyr UART console. +* `utime` module for time measurements and delays. +* `machine.Pin` class for GPIO control. +* `usocket` module for networking (IPv4/IPv6). +* "Frozen modules" support to allow to bundle Python modules together + with firmware. Including complete applications, including with + run-on-boot capability. + +Over time, bindings for various Zephyr subsystems may be added. + + +Building +-------- + +Follow to Zephyr web site for Getting Started instruction of installing +Zephyr SDK, getting Zephyr source code, and setting up development +environment. (Direct link: +https://www.zephyrproject.org/doc/getting_started/getting_started.html). +You may want to build Zephyr's own sample applications to make sure your +setup is correct. + +To build MicroPython port, in the port subdirectory (zephyr/), run: + + make BOARD= + +If you don't specify BOARD, the default is `qemu_x86` (x86 target running +in QEMU emulator). Consult Zephyr documentation above for the list of +supported boards. + + +Running +------- + +To run the resulting firmware in QEMU (for BOARDs like qemu_x86, +qemu_cortex_m3): + + make run + +With the default configuration, networking is now enabled, so you need to +follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu +to setup host side of TAP/SLIP networking. If you get error like: + + could not connect serial device to character backend 'unix:/tmp/slip.sock' + +it's a sign that you didn't followed instructions above. If you would like +to just run it quickly without extra setup, see "minimal" build below. + +For deploying/flashing a firmware on a real board, follow Zephyr +documentation for a given board, including known issues for that board +(if any). (Mind again that networking is enabled for the default build, +so you should know if there're any special requirements in that regard, +cf. for example QEMU networking requirements above; real hardware boards +generally should not have any special requirements, unless there're known +issues). + + +Quick example +------------- + +To blink an LED: + + import time + from machine import Pin + + LED = Pin(("GPIO_1", 21), Pin.OUT) + while True: + LED.value(1) + time.sleep(0.5) + LED.value(0) + time.sleep(0.5) + +The above code uses an LED location for a FRDM-K64F board (port B, pin 21; +following Zephyr conventions port are identified by "GPIO_x", where *x* +starts from 0). You will need to adjust it for another board (using board's +reference materials). To execute the above sample, copy it to clipboard, in +MicroPython REPL enter "paste mode" using Ctrl+E, paste clipboard, press +Ctrl+D to finish paste mode and start execution. + + +Minimal build +------------- + +MicroPython is committed to maintain minimal binary size for Zephyr port +below 128KB, as long as Zephyr project is committed to maintain stable +minimal size of their kernel (which they appear to be). Note that at such +size, there is no support for any Zephyr features beyond REPL over UART, +and only very minimal set of builtin Python modules is available. Thus, +this build is more suitable for code size control and quick demonstrations +on smaller systems. It's also suitable for careful enabling of features +one by one to achieve needed functionality and code size. This is in the +contrast to the "default" build, which may get more and more features +enabled over time. + +To make a minimal build: + + ./make-minimal BOARD= + +To run a minimal build in QEMU without requiring TAP networking setup +run the following after you built image with the previous command: + + ./make-minimal BOARD= run diff --git a/src/openmv/src/micropython/ports/zephyr/help.c b/src/openmv/src/micropython/ports/zephyr/help.c new file mode 100755 index 0000000..becc203 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/help.c @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char zephyr_help_text[] = +"Welcome to MicroPython!\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; diff --git a/src/openmv/src/micropython/ports/zephyr/machine_pin.c b/src/openmv/src/micropython/ports/zephyr/machine_pin.c new file mode 100755 index 0000000..4dcd956 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/machine_pin.c @@ -0,0 +1,200 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "modmachine.h" + +const mp_obj_base_t machine_pin_obj_template = {&machine_pin_type}; + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "", self->port, self->pin); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get io mode + uint mode = args[ARG_mode].u_int; + + // get pull mode + uint pull = GPIO_PUD_NORMAL; + if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + } + + int ret = gpio_pin_configure(self->port, self->pin, mode | pull); + if (ret) { + mp_raise_ValueError("invalid pin"); + } + + // get initial value + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[ARG_value].u_obj)); + } + + return mp_const_none; +} + +// constructor(drv_name, pin, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted port + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + mp_raise_ValueError("Pin id must be tuple of (\"GPIO_x\", pin#)"); + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[0], 2, &items); + const char *drv_name = mp_obj_str_get_str(items[0]); + int wanted_pin = mp_obj_get_int(items[1]); + struct device *wanted_port = device_get_binding(drv_name); + if (!wanted_port) { + mp_raise_ValueError("invalid port"); + } + + machine_pin_obj_t *pin = m_new_obj(machine_pin_obj_t); + pin->base = machine_pin_obj_template; + pin->port = wanted_port; + pin->pin = wanted_pin; + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + u32_t pin_val; + (void)gpio_pin_read(self->port, self->pin, &pin_val); + return MP_OBJ_NEW_SMALL_INT(pin_val); + } else { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off); + +STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on); + +STATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + u32_t pin_val; + gpio_pin_read(self->port, self->pin, &pin_val); + return pin_val; + } + case MP_PIN_WRITE: { + gpio_pin_write(self->port, self->pin, arg); + return 0; + } + } + return -1; +} + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DIR_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DIR_OUT) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PUD_PULL_UP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PUD_PULL_DOWN) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t machine_pin_pin_p = { + .ioctl = machine_pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &machine_pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; diff --git a/src/openmv/src/micropython/ports/zephyr/main.c b/src/openmv/src/micropython/ports/zephyr/main.c new file mode 100755 index 0000000..a28fb37 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/main.c @@ -0,0 +1,160 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016-2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include +#ifdef CONFIG_NETWORKING +#include +#endif + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/stackctrl.h" +#include "lib/utils/pyexec.h" +#include "lib/mp-readline/readline.h" + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#include "lib/tinytest/tinytest.c" +#include "lib/upytesthelper/upytesthelper.c" +#include TEST +#endif + +static char *stack_top; +static char heap[MICROPY_HEAP_SIZE]; + +void init_zephyr(void) { + // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap + // network addresses. +#if 0 + #ifdef CONFIG_NETWORKING + if (net_if_get_default() == NULL) { + // If there's no default networking interface, + // there's nothing to configure. + return; + } + #endif + #ifdef CONFIG_NET_IPV4 + static struct in_addr in4addr_my = {{{192, 0, 2, 1}}}; + net_if_ipv4_addr_add(net_if_get_default(), &in4addr_my, NET_ADDR_MANUAL, 0); + static struct in_addr in4netmask_my = {{{255, 255, 255, 0}}}; + net_if_ipv4_set_netmask(net_if_get_default(), &in4netmask_my); + static struct in_addr in4gw_my = {{{192, 0, 2, 2}}}; + net_if_ipv4_set_gw(net_if_get_default(), &in4gw_my); + #endif + #ifdef CONFIG_NET_IPV6 + // 2001:db8::1 + static struct in6_addr in6addr_my = {{{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}; + net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, NET_ADDR_MANUAL, 0); + #endif +#endif +} + +int real_main(void) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + mp_stack_set_top(stack_top); + // Make MicroPython's stack limit somewhat smaller than full stack available + mp_stack_set_limit(CONFIG_MAIN_STACK_SIZE - 512); + + init_zephyr(); + + #ifdef TEST + static const char *argv[] = {"test"}; + upytest_set_heap(heap, heap + sizeof(heap)); + int r = tinytest_main(1, argv, groups); + printf("status: %d\n", r); + #endif + +soft_reset: + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) + mp_obj_list_init(mp_sys_argv, 0); + + #if MICROPY_MODULE_FROZEN + pyexec_frozen_module("main.py"); + #endif + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + printf("soft reboot\n"); + goto soft_reset; + + return 0; +} + +void gc_collect(void) { + // WARNING: This gc_collect implementation doesn't try to get root + // pointers from CPU registers, and thus may function incorrectly. + void *dummy; + gc_collect_start(); + gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); + gc_collect_end(); + //gc_dump_info(); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_raise_OSError(ENOENT); +} + +mp_import_stat_t mp_import_stat(const char *path) { + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); + +NORETURN void nlr_jump_fail(void *val) { + while (1); +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error("Assertion failed"); +} +#endif diff --git a/src/openmv/src/micropython/ports/zephyr/make-bin-testsuite b/src/openmv/src/micropython/ports/zephyr/make-bin-testsuite new file mode 100755 index 0000000..f6aeb83 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/make-bin-testsuite @@ -0,0 +1,20 @@ +#!/bin/sh +# +# This is a wrapper for make to build a binary with builtin testsuite. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-bin-testsuite BOARD=qemu_cortex_m3 +# ./make-bin-testsuite BOARD=qemu_cortex_m3 run +# + +(cd ../../tests; ./run-tests --write-exp) +(cd ../../tests; ./run-tests --list-tests --target=minimal \ + -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \ + -e /set -e frozenset -e complex -e const -e native -e viper \ + -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \ + | ../tools/tinytest-codegen.py --stdin) > bin-testsuite.c + +make \ + CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DTEST=\"bin-testsuite.c\" -DNO_FORKING' \ + "$@" diff --git a/src/openmv/src/micropython/ports/zephyr/make-minimal b/src/openmv/src/micropython/ports/zephyr/make-minimal new file mode 100755 index 0000000..1fc143e --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/make-minimal @@ -0,0 +1,16 @@ +#!/bin/sh +# +# This is a wrapper for make to build a "minimal" Zephyr port. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-minimal BOARD=qemu_cortex_m3 +# ./make-minimal BOARD=qemu_cortex_m3 run +# + +make \ + CONF_FILE=prj_minimal.conf \ + CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ + FROZEN_DIR= \ + QEMU_NET=0 \ + "$@" diff --git a/src/openmv/src/micropython/ports/zephyr/makeprj.py b/src/openmv/src/micropython/ports/zephyr/makeprj.py new file mode 100755 index 0000000..239c877 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/makeprj.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import sys +import os +import hashlib + + +def hash_file(fname): + if not os.path.exists(fname): + return b"" + hasher = hashlib.md5() + with open(fname, "rb") as f: + hasher.update(f.read()) + return hasher.digest() + + +old_digest = hash_file(sys.argv[3]) + +with open(sys.argv[3] + ".tmp", "wb") as f: + f.write(open(sys.argv[1], "rb").read()) + if os.path.exists(sys.argv[2]): + f.write(open(sys.argv[2], "rb").read()) + +new_digest = hash_file(sys.argv[3] + ".tmp") + +if new_digest != old_digest: + print("Replacing") + os.rename(sys.argv[3] + ".tmp", sys.argv[3]) +else: + os.remove(sys.argv[3] + ".tmp") diff --git a/src/openmv/src/micropython/ports/zephyr/modmachine.c b/src/openmv/src/micropython/ports/zephyr/modmachine.c new file mode 100755 index 0000000..5909c37 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modmachine.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "modmachine.h" + +#if MICROPY_PY_MACHINE + +STATIC mp_obj_t machine_reset(void) { + sys_reboot(SYS_REBOOT_COLD); + // Won't get here, Zephyr has infiniloop on its side + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_reset_cause(void) { + printf("Warning: %s is not implemented\n", __func__); + return MP_OBJ_NEW_SMALL_INT(42); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + #ifdef CONFIG_REBOOT + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + + // reset causes + /*{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },*/ +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/src/openmv/src/micropython/ports/zephyr/modmachine.h b/src/openmv/src/micropython/ports/zephyr/modmachine.h new file mode 100755 index 0000000..84e4d10 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modmachine.h @@ -0,0 +1,16 @@ +#ifndef MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H +#define MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pin_type; + +MP_DECLARE_CONST_FUN_OBJ_0(machine_info_obj); + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + struct device *port; + uint32_t pin; +} machine_pin_obj_t; + +#endif // MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H diff --git a/src/openmv/src/micropython/ports/zephyr/modusocket.c b/src/openmv/src/micropython/ports/zephyr/modusocket.c new file mode 100755 index 0000000..84d6fa7 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modusocket.c @@ -0,0 +1,468 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#ifdef MICROPY_PY_USOCKET + +#include "py/runtime.h" +#include "py/stream.h" + +#include +#include +// Zephyr's generated version header +#include +#include +#include +#include +#ifdef CONFIG_NET_SOCKETS +#include +#endif + +#define DEBUG_PRINT 0 +#if DEBUG_PRINT // print debugging info +#define DEBUG_printf printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +typedef struct _socket_obj_t { + mp_obj_base_t base; + int ctx; + + #define STATE_NEW 0 + #define STATE_CONNECTING 1 + #define STATE_CONNECTED 2 + #define STATE_PEER_CLOSED 3 + int8_t state; +} socket_obj_t; + +STATIC const mp_obj_type_t socket_type; + +// Helper functions + +#define RAISE_ERRNO(x) { int _err = x; if (_err < 0) mp_raise_OSError(-_err); } +#define RAISE_SOCK_ERRNO(x) { if ((int)(x) == -1) mp_raise_OSError(errno); } + +STATIC void socket_check_closed(socket_obj_t *socket) { + if (socket->ctx == -1) { + // already closed + mp_raise_OSError(EBADF); + } +} + +STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct sockaddr *sockaddr) { + // We employ the fact that port and address offsets are the same for IPv4 & IPv6 + struct sockaddr_in *sockaddr_in = (struct sockaddr_in*)sockaddr; + + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); + sockaddr_in->sin_family = net_context_get_family((void*)socket->ctx); + RAISE_ERRNO(net_addr_pton(sockaddr_in->sin_family, mp_obj_str_get_str(addr_items[0]), &sockaddr_in->sin_addr)); + sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1])); +} + +STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { + // We employ the fact that port and address offsets are the same for IPv4 & IPv6 + struct sockaddr_in6 *sockaddr_in6 = (struct sockaddr_in6*)addr; + char buf[40]; + net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); + mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); + + tuple->items[0] = mp_obj_new_str(buf, strlen(buf)); + // We employ the fact that port offset is the same for IPv4 & IPv6 + // not filled in + //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); + tuple->items[1] = port; + + if (addr->sa_family == AF_INET6) { + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); // flow_info + tuple->items[3] = MP_OBJ_NEW_SMALL_INT(sockaddr_in6->sin6_scope_id); + } + + return MP_OBJ_FROM_PTR(tuple); +} + +socket_obj_t *socket_new(void) { + socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t); + socket->base.type = (mp_obj_t)&socket_type; + socket->state = STATE_NEW; + return socket; +} + +// Methods + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + socket_obj_t *self = self_in; + if (self->ctx == -1) { + mp_printf(print, ""); + } else { + struct net_context *ctx = (void*)self->ctx; + mp_printf(print, "", ctx, net_context_get_type(ctx)); + } +} + +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + socket_obj_t *socket = socket_new(); + + int family = AF_INET; + int socktype = SOCK_STREAM; + int proto = -1; + + if (n_args >= 1) { + family = mp_obj_get_int(args[0]); + if (n_args >= 2) { + socktype = mp_obj_get_int(args[1]); + if (n_args >= 3) { + proto = mp_obj_get_int(args[2]); + } + } + } + + if (proto == -1) { + proto = IPPROTO_TCP; + if (socktype != SOCK_STREAM) { + proto = IPPROTO_UDP; + } + } + + socket->ctx = zsock_socket(family, socktype, proto); + RAISE_SOCK_ERRNO(socket->ctx); + + return MP_OBJ_FROM_PTR(socket); +} + +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + parse_inet_addr(socket, addr_in, &sockaddr); + + int res = zsock_bind(socket->ctx, &sockaddr, sizeof(sockaddr)); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + parse_inet_addr(socket, addr_in, &sockaddr); + + int res = zsock_connect(socket->ctx, &sockaddr, sizeof(sockaddr)); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + mp_int_t backlog = mp_obj_get_int(backlog_in); + int res = zsock_listen(socket->ctx, backlog); + RAISE_SOCK_ERRNO(res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + socket_obj_t *socket = self_in; + socket_check_closed(socket); + + struct sockaddr sockaddr; + socklen_t addrlen = sizeof(sockaddr); + int ctx = zsock_accept(socket->ctx, &sockaddr, &addrlen); + + socket_obj_t *socket2 = socket_new(); + socket2->ctx = ctx; + + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = MP_OBJ_FROM_PTR(socket2); + // TODO + client->items[1] = mp_const_none; + + return MP_OBJ_FROM_PTR(client); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *socket = self_in; + if (socket->ctx == -1) { + // already closed + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + ssize_t len = zsock_send(socket->ctx, buf, size, 0); + if (len == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + + return len; +} + +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int err = 0; + mp_uint_t len = sock_write(self_in, bufinfo.buf, bufinfo.len, &err); + if (len == MP_STREAM_ERROR) { + mp_raise_OSError(err); + } + return mp_obj_new_int_from_uint(len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +STATIC mp_uint_t sock_read(mp_obj_t self_in, void *buf, mp_uint_t max_len, int *errcode) { + socket_obj_t *socket = self_in; + if (socket->ctx == -1) { + // already closed + *errcode = EBADF; + return MP_STREAM_ERROR; + } + + ssize_t recv_len = zsock_recv(socket->ctx, buf, max_len, 0); + if (recv_len == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + + return recv_len; +} + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mp_int_t max_len = mp_obj_get_int(len_in); + vstr_t vstr; + // +1 to accommodate for trailing \0 + vstr_init_len(&vstr, max_len + 1); + + int err; + mp_uint_t len = sock_read(self_in, vstr.buf, max_len, &err); + + if (len == MP_STREAM_ERROR) { + vstr_clear(&vstr); + mp_raise_OSError(err); + } + + if (len == 0) { + vstr_clear(&vstr); + return mp_const_empty_bytes; + } + + vstr.len = len; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + mp_warning("setsockopt() not implemented"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + +STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t *socket = o_in; + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (socket->ctx != -1) { + int res = zsock_close(socket->ctx); + RAISE_SOCK_ERRNO(res); + if (res == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->ctx = -1; + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +STATIC const mp_stream_p_t socket_stream_p = { + .read = sock_read, + .write = sock_write, + .ioctl = sock_ioctl, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .print = socket_print, + .make_new = socket_make_new, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +// +// getaddrinfo() implementation +// + +typedef struct _getaddrinfo_state_t { + mp_obj_t result; + struct k_sem sem; + mp_obj_t port; + int status; +} getaddrinfo_state_t; + +void dns_resolve_cb(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { + getaddrinfo_state_t *state = user_data; + DEBUG_printf("dns status: %d\n", status); + + if (info == NULL) { + if (status == DNS_EAI_ALLDONE) { + status = 0; + } + state->status = status; + k_sem_give(&state->sem); + return; + } + + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(info->ai_family); + // info->ai_socktype not filled + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM); + // info->ai_protocol not filled + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = format_inet_addr(&info->ai_addr, state->port); + mp_obj_list_append(state->result, MP_OBJ_FROM_PTR(tuple)); +} + +STATIC mp_obj_t mod_getaddrinfo(size_t n_args, const mp_obj_t *args) { + mp_obj_t host_in = args[0], port_in = args[1]; + const char *host = mp_obj_str_get_str(host_in); + mp_int_t family = 0; + if (n_args > 2) { + family = mp_obj_get_int(args[2]); + } + + getaddrinfo_state_t state; + // Just validate that it's int + (void)mp_obj_get_int(port_in); + state.port = port_in; + state.result = mp_obj_new_list(0, NULL); + k_sem_init(&state.sem, 0, UINT_MAX); + + for (int i = 2; i--;) { + int type = (family != AF_INET6 ? DNS_QUERY_TYPE_A : DNS_QUERY_TYPE_AAAA); + RAISE_ERRNO(dns_get_addr_info(host, type, NULL, dns_resolve_cb, &state, 3000)); + k_sem_take(&state.sem, K_FOREVER); + if (family != 0) { + break; + } + family = AF_INET6; + } + + // Raise error only if there's nothing to return, otherwise + // it may be IPv4 vs IPv6 differences. + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(state.result)); + if (state.status != 0 && len == 0) { + mp_raise_OSError(state.status); + } + + return state.result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_getaddrinfo_obj, 2, 3, mod_getaddrinfo); + + +STATIC mp_obj_t pkt_get_info(void) { + struct k_mem_slab *rx, *tx; + struct net_buf_pool *rx_data, *tx_data; + net_pkt_get_info(&rx, &tx, &rx_data, &tx_data); + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(rx)); + t->items[1] = MP_OBJ_NEW_SMALL_INT(k_mem_slab_num_free_get(tx)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(rx_data->avail_count); + t->items[3] = MP_OBJ_NEW_SMALL_INT(tx_data->avail_count); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pkt_get_info_obj, pkt_get_info); + +STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + // objects + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, + + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(2) }, + + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_getaddrinfo_obj) }, + { MP_ROM_QSTR(MP_QSTR_pkt_get_info), MP_ROM_PTR(&pkt_get_info_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; + +#endif // MICROPY_PY_USOCKET diff --git a/src/openmv/src/micropython/ports/zephyr/modutime.c b/src/openmv/src/micropython/ports/zephyr/modutime.c new file mode 100755 index 0000000..a5d32fe --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modutime.c @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME + +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t mod_time_time(void) { + /* The absence of FP support is deliberate. The Zephyr port uses + * single precision floats so the fraction component will start to + * lose precision on devices with a long uptime. + */ + return mp_obj_new_int(k_uptime_get() / 1000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_UTIME diff --git a/src/openmv/src/micropython/ports/zephyr/modzephyr.c b/src/openmv/src/micropython/ports/zephyr/modzephyr.c new file mode 100755 index 0000000..265fc88 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modzephyr.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_ZEPHYR + +#include +#include + +#include "py/runtime.h" + +STATIC mp_obj_t mod_is_preempt_thread(void) { + return mp_obj_new_bool(k_is_preempt_thread()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_is_preempt_thread_obj, mod_is_preempt_thread); + +STATIC mp_obj_t mod_current_tid(void) { + return MP_OBJ_NEW_SMALL_INT(k_current_get()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_current_tid_obj, mod_current_tid); + +STATIC mp_obj_t mod_stacks_analyze(void) { + k_call_stacks_analyze(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_stacks_analyze_obj, mod_stacks_analyze); + +#ifdef CONFIG_NET_SHELL + +//int net_shell_cmd_iface(int argc, char *argv[]); + +STATIC mp_obj_t mod_shell_net_iface(void) { + net_shell_cmd_iface(0, NULL); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_shell_net_iface_obj, mod_shell_net_iface); + +#endif // CONFIG_NET_SHELL + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr) }, + { MP_ROM_QSTR(MP_QSTR_is_preempt_thread), MP_ROM_PTR(&mod_is_preempt_thread_obj) }, + { MP_ROM_QSTR(MP_QSTR_current_tid), MP_ROM_PTR(&mod_current_tid_obj) }, + { MP_ROM_QSTR(MP_QSTR_stacks_analyze), MP_ROM_PTR(&mod_stacks_analyze_obj) }, + + #ifdef CONFIG_NET_SHELL + { MP_ROM_QSTR(MP_QSTR_shell_net_iface), MP_ROM_PTR(&mod_shell_net_iface_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_zephyr = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_ZEPHYR diff --git a/src/openmv/src/micropython/ports/zephyr/modzsensor.c b/src/openmv/src/micropython/ports/zephyr/modzsensor.c new file mode 100755 index 0000000..74c909d --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/modzsensor.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#include +#include + +#if MICROPY_PY_ZSENSOR + +typedef struct _mp_obj_sensor_t { + mp_obj_base_t base; + struct device *dev; +} mp_obj_sensor_t; + +STATIC mp_obj_t sensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_obj_sensor_t *o = m_new_obj(mp_obj_sensor_t); + o->base.type = type; + o->dev = device_get_binding(mp_obj_str_get_str(args[0])); + if (o->dev == NULL) { + mp_raise_ValueError("dev not found"); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t sensor_measure(mp_obj_t self_in) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + int st = sensor_sample_fetch(self->dev); + if (st != 0) { + mp_raise_OSError(-st); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sensor_measure_obj, sensor_measure); + +STATIC void sensor_get_internal(mp_obj_t self_in, mp_obj_t channel_in, struct sensor_value *res) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + + int st = sensor_channel_get(self->dev, mp_obj_get_int(channel_in), res); + if (st != 0) { + mp_raise_OSError(-st); + } +} + +STATIC mp_obj_t sensor_get_float(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_float_obj, sensor_get_float); + +STATIC mp_obj_t sensor_get_micros(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_micros_obj, sensor_get_micros); + +STATIC mp_obj_t sensor_get_millis(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_millis_obj, sensor_get_millis); + +STATIC mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int); + +STATIC const mp_rom_map_elem_t sensor_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table); + +STATIC const mp_obj_type_t sensor_type = { + { &mp_type_type }, + .name = MP_QSTR_Sensor, + .make_new = sensor_make_new, + .locals_dict = (void*)&sensor_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zsensor) }, + { MP_ROM_QSTR(MP_QSTR_Sensor), MP_ROM_PTR(&sensor_type) }, + +#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(SENSOR_CHAN_ ## name) } + C(ACCEL_X), + C(ACCEL_Y), + C(ACCEL_Z), + C(GYRO_X), + C(GYRO_Y), + C(GYRO_Z), + C(MAGN_X), + C(MAGN_Y), + C(MAGN_Z), + C(TEMP), + C(PRESS), + C(PROX), + C(HUMIDITY), + C(LIGHT), + C(ALTITUDE), +#undef C +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table); + +const mp_obj_module_t mp_module_zsensor = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_zsensor_globals, +}; + +#endif //MICROPY_PY_UHASHLIB diff --git a/src/openmv/src/micropython/ports/zephyr/mpconfigport.h b/src/openmv/src/micropython/ports/zephyr/mpconfigport.h new file mode 100755 index 0000000..ab55601 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/mpconfigport.h @@ -0,0 +1,157 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" +// Included here to get basic Zephyr environment (macros, etc.) +#include + +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif + +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_STR_COUNT (0) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT zephyr_help_text +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_PY_STRUCT (0) +#ifdef CONFIG_NETWORKING +// If we have networking, we likely want errno comfort +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_USOCKET (1) +#endif +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_ZEPHYR (1) +#define MICROPY_PY_ZSENSOR (1) +#define MICROPY_PY_SYS_MODULES (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#define MICROPY_PY_SYS_PLATFORM "zephyr" + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else +#define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else +#define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + +#define MICROPY_MODULE_FROZEN_STR (1) + +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; + +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_time; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_zephyr; +extern const struct _mp_obj_module_t mp_module_zsensor; + +#if MICROPY_PY_USOCKET +#define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, +#define MICROPY_PY_USOCKET_WEAK_DEF { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, +#else +#define MICROPY_PY_USOCKET_DEF +#define MICROPY_PY_USOCKET_WEAK_DEF +#endif + +#if MICROPY_PY_UTIME +#define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, +#else +#define MICROPY_PY_UTIME_DEF +#endif + +#if MICROPY_PY_ZEPHYR +#define MICROPY_PY_ZEPHYR_DEF { MP_ROM_QSTR(MP_QSTR_zephyr), MP_ROM_PTR(&mp_module_zephyr) }, +#else +#define MICROPY_PY_ZEPHYR_DEF +#endif + +#if MICROPY_PY_ZSENSOR +#define MICROPY_PY_ZSENSOR_DEF { MP_ROM_QSTR(MP_QSTR_zsensor), MP_ROM_PTR(&mp_module_zsensor) }, +#else +#define MICROPY_PY_ZSENSOR_DEF +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ + MICROPY_PY_USOCKET_DEF \ + MICROPY_PY_UTIME_DEF \ + MICROPY_PY_ZEPHYR_DEF \ + MICROPY_PY_ZSENSOR_DEF \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ + MICROPY_PY_USOCKET_WEAK_DEF \ + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + diff --git a/src/openmv/src/micropython/ports/zephyr/mpconfigport_bin_testsuite.h b/src/openmv/src/micropython/ports/zephyr/mpconfigport_bin_testsuite.h new file mode 100755 index 0000000..684b4f4 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/mpconfigport_bin_testsuite.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "mpconfigport.h" + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif diff --git a/src/openmv/src/micropython/ports/zephyr/mpconfigport_minimal.h b/src/openmv/src/micropython/ports/zephyr/mpconfigport_minimal.h new file mode 100755 index 0000000..f0e57d7 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/mpconfigport_minimal.h @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" +// Included here to get basic Zephyr environment (macros, etc.) +#include + +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif + +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS_MODULES (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else +#define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else +#define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_uint_t; // must be pointer size +typedef long mp_off_t; + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/src/openmv/src/micropython/ports/zephyr/mphalport.h b/src/openmv/src/micropython/ports/zephyr/mphalport.h new file mode 100755 index 0000000..e3cca8d --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/mphalport.h @@ -0,0 +1,25 @@ +#include +#include "lib/utils/interrupt_char.h" + +static inline mp_uint_t mp_hal_ticks_us(void) { + return SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32()) / 1000; +} + +static inline mp_uint_t mp_hal_ticks_ms(void) { + return k_uptime_get(); +} + +static inline mp_uint_t mp_hal_ticks_cpu(void) { + // ticks_cpu() is defined as using the highest-resolution timing source + // in the system. This is usually a CPU clock, but doesn't have to be, + // here we just use Zephyr hi-res timer. + return k_cycle_get_32(); +} + +static inline void mp_hal_delay_us(mp_uint_t delay) { + k_busy_wait(delay); +} + +static inline void mp_hal_delay_ms(mp_uint_t delay) { + k_sleep(delay); +} diff --git a/src/openmv/src/micropython/ports/zephyr/prj_96b_carbon.conf b/src/openmv/src/micropython/ports/zephyr/prj_96b_carbon.conf new file mode 100755 index 0000000..40b57e6 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_96b_carbon.conf @@ -0,0 +1,2 @@ +# TODO: Enable networking +CONFIG_NETWORKING=y diff --git a/src/openmv/src/micropython/ports/zephyr/prj_base.conf b/src/openmv/src/micropython/ports/zephyr/prj_base.conf new file mode 100755 index 0000000..34124dd --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_base.conf @@ -0,0 +1,65 @@ +CONFIG_BUILD_OUTPUT_BIN=y +CONFIG_REBOOT=y + +CONFIG_STDOUT_CONSOLE=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y + +CONFIG_CONSOLE_SUBSYS=y +CONFIG_CONSOLE_GETCHAR=y +CONFIG_CONSOLE_GETCHAR_BUFSIZE=128 +CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128 + +CONFIG_NEWLIB_LIBC=y +CONFIG_FLOAT=y +CONFIG_MAIN_STACK_SIZE=4736 + +# Enable sensor subsystem (doesn't add code if not used). +# Specific sensors should be enabled per-board. +CONFIG_SENSOR=y + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_TEST_RANDOM_GENERATOR=y + +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_INIT_TIMEOUT=3 +CONFIG_NET_CONFIG_NEED_IPV6=y +CONFIG_NET_CONFIG_NEED_IPV4=y + +# DNS +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2 +CONFIG_DNS_SERVER_IP_ADDRESSES=y + +# Static IP addresses +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" +CONFIG_DNS_SERVER1="192.0.2.2" + +# DHCP configuration. Until DHCP address is assigned, +# static configuration above is used instead. +CONFIG_NET_DHCPV4=y + +# Diagnostics and debugging + +# Required for zephyr.stack_analyze() +CONFIG_INIT_STACKS=y + +# Required for usocket.pkt_get_info() +CONFIG_NET_BUF_POOL_USAGE=y + +# Required for usocket.shell_*() +#CONFIG_NET_SHELL=y + +# Uncomment to enable "INFO" level net_buf logging +#CONFIG_NET_LOG=y +#CONFIG_NET_DEBUG_NET_BUF=y +# Change to 4 for "DEBUG" level +#CONFIG_SYS_LOG_NET_LEVEL=3 diff --git a/src/openmv/src/micropython/ports/zephyr/prj_disco_l475_iot1.conf b/src/openmv/src/micropython/ports/zephyr/prj_disco_l475_iot1.conf new file mode 100755 index 0000000..36c8b99 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_disco_l475_iot1.conf @@ -0,0 +1,5 @@ +# Sensors +CONFIG_HTS221=y +CONFIG_LIS3MDL=y +CONFIG_LPS22HB=y +CONFIG_LSM6DSL=y diff --git a/src/openmv/src/micropython/ports/zephyr/prj_frdm_k64f.conf b/src/openmv/src/micropython/ports/zephyr/prj_frdm_k64f.conf new file mode 100755 index 0000000..611d6bc --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_frdm_k64f.conf @@ -0,0 +1,2 @@ +# Networking drivers +CONFIG_NET_L2_ETHERNET=y diff --git a/src/openmv/src/micropython/ports/zephyr/prj_minimal.conf b/src/openmv/src/micropython/ports/zephyr/prj_minimal.conf new file mode 100755 index 0000000..5d6b353 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_minimal.conf @@ -0,0 +1,6 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y +CONFIG_NEWLIB_LIBC=y +CONFIG_FLOAT=y +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/src/openmv/src/micropython/ports/zephyr/prj_qemu_cortex_m3.conf b/src/openmv/src/micropython/ports/zephyr/prj_qemu_cortex_m3.conf new file mode 100755 index 0000000..dac0c35 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_qemu_cortex_m3.conf @@ -0,0 +1,7 @@ +# Interrupt-driven UART console has emulation artifacts under QEMU, +# disable it +CONFIG_CONSOLE_SUBSYS=n + +# Networking drivers +# SLIP driver for QEMU +CONFIG_NET_SLIP_TAP=y diff --git a/src/openmv/src/micropython/ports/zephyr/prj_qemu_x86.conf b/src/openmv/src/micropython/ports/zephyr/prj_qemu_x86.conf new file mode 100755 index 0000000..dac0c35 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/prj_qemu_x86.conf @@ -0,0 +1,7 @@ +# Interrupt-driven UART console has emulation artifacts under QEMU, +# disable it +CONFIG_CONSOLE_SUBSYS=n + +# Networking drivers +# SLIP driver for QEMU +CONFIG_NET_SLIP_TAP=y diff --git a/src/openmv/src/micropython/ports/zephyr/src/Makefile b/src/openmv/src/micropython/ports/zephyr/src/Makefile new file mode 100755 index 0000000..36dd8c6 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/src/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# 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. +# + +obj-y += zephyr_start.o zephyr_getchar.o diff --git a/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.c b/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.c new file mode 100755 index 0000000..52b3394 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Linaro + * + * 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. + */ + +#include +#include +#include +#include +#include "zephyr_getchar.h" + +extern int mp_interrupt_char; +void mp_keyboard_interrupt(void); + +static struct k_sem uart_sem; +#define UART_BUFSIZE 256 +static uint8_t uart_ringbuf[UART_BUFSIZE]; +static uint8_t i_get, i_put; + +static int console_irq_input_hook(uint8_t ch) +{ + int i_next = (i_put + 1) & (UART_BUFSIZE - 1); + if (i_next == i_get) { + printk("UART buffer overflow - char dropped\n"); + return 1; + } + if (ch == mp_interrupt_char) { + mp_keyboard_interrupt(); + return 1; + } else { + uart_ringbuf[i_put] = ch; + i_put = i_next; + } + //printk("%x\n", ch); + k_sem_give(&uart_sem); + k_yield(); + return 1; +} + +uint8_t zephyr_getchar(void) { + k_sem_take(&uart_sem, K_FOREVER); + unsigned int key = irq_lock(); + uint8_t c = uart_ringbuf[i_get++]; + i_get &= UART_BUFSIZE - 1; + irq_unlock(key); + return c; +} + +void zephyr_getchar_init(void) { + k_sem_init(&uart_sem, 0, UINT_MAX); + uart_console_in_debug_hook_install(console_irq_input_hook); + // All NULLs because we're interested only in the callback above + uart_register_input(NULL, NULL, NULL); +} diff --git a/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.h b/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.h new file mode 100755 index 0000000..fb5f19a --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/src/zephyr_getchar.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 Linaro + * + * 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. + */ + +#include + +void zephyr_getchar_init(void); +uint8_t zephyr_getchar(void); diff --git a/src/openmv/src/micropython/ports/zephyr/src/zephyr_start.c b/src/openmv/src/micropython/ports/zephyr/src/zephyr_start.c new file mode 100755 index 0000000..591eec7 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/src/zephyr_start.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include "zephyr_getchar.h" + +int real_main(void); + +void main(void) { +#ifdef CONFIG_CONSOLE_SUBSYS + console_init(); +#else + zephyr_getchar_init(); +#endif + real_main(); +} diff --git a/src/openmv/src/micropython/ports/zephyr/uart_core.c b/src/openmv/src/micropython/ports/zephyr/uart_core.c new file mode 100755 index 0000000..325e437 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/uart_core.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "py/mpconfig.h" +#include "src/zephyr_getchar.h" +// Zephyr headers +#include +#include + +/* + * Core UART functions to implement for a port + */ + +// Receive single character +int mp_hal_stdin_rx_chr(void) { +#ifdef CONFIG_CONSOLE_SUBSYS + return console_getchar(); +#else + return zephyr_getchar(); +#endif +} + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { +#ifdef CONFIG_CONSOLE_SUBSYS + while (len--) { + char c = *str++; + while (console_putchar(c) == -1) { + k_sleep(1); + } + } +#else + static struct device *uart_console_dev; + if (uart_console_dev == NULL) { + uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME); + } + + while (len--) { + uart_poll_out(uart_console_dev, *str++); + } +#endif +} diff --git a/src/openmv/src/micropython/ports/zephyr/z_config.mk b/src/openmv/src/micropython/ports/zephyr/z_config.mk new file mode 100755 index 0000000..28addd8 --- /dev/null +++ b/src/openmv/src/micropython/ports/zephyr/z_config.mk @@ -0,0 +1,17 @@ +srctree = $(ZEPHYR_BASE) + +include $(Z_DOTCONFIG) +override ARCH = $(subst $(DQUOTE),,$(CONFIG_ARCH)) +SOC_NAME = $(subst $(DQUOTE),,$(CONFIG_SOC)) +SOC_SERIES = $(subst $(DQUOTE),,$(CONFIG_SOC_SERIES)) +SOC_FAMILY = $(subst $(DQUOTE),,$(CONFIG_SOC_FAMILY)) +ifeq ($(SOC_SERIES),) +SOC_PATH = $(SOC_NAME) +else +SOC_PATH = $(SOC_FAMILY)/$(SOC_SERIES) +endif + +KBUILD_CFLAGS := -c +include $(ZEPHYR_BASE)/scripts/Kbuild.include + +include $(ZEPHYR_BASE)/arch/$(ARCH)/Makefile diff --git a/src/openmv/src/micropython/py/argcheck.c b/src/openmv/src/micropython/py/argcheck.c new file mode 100755 index 0000000..c2b1b6c --- /dev/null +++ b/src/openmv/src/micropython/py/argcheck.c @@ -0,0 +1,149 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) { + // TODO maybe take the function name as an argument so we can print nicer error messages + + // The reverse of MP_OBJ_FUN_MAKE_SIG + bool takes_kw = sig & 1; + size_t n_args_min = sig >> 17; + size_t n_args_max = (sig >> 1) & 0xffff; + + if (n_kw && !takes_kw) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + mp_raise_TypeError("function doesn't take keyword arguments"); + } + } + + if (n_args_min == n_args_max) { + if (n_args != n_args_min) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function takes %d positional arguments but %d were given", + n_args_min, n_args)); + } + } + } else { + if (n_args < n_args_min) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function missing %d required positional arguments", + n_args_min - n_args)); + } + } else if (n_args > n_args_max) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function expected at most %d arguments, got %d", + n_args_max, n_args)); + } + } + } +} + +void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { + size_t pos_found = 0, kws_found = 0; + for (size_t i = 0; i < n_allowed; i++) { + mp_obj_t given_arg; + if (i < n_pos) { + if (allowed[i].flags & MP_ARG_KW_ONLY) { + goto extra_positional; + } + pos_found++; + given_arg = pos[i]; + } else { + mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP); + if (kw == NULL) { + if (allowed[i].flags & MP_ARG_REQUIRED) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%q' argument required", allowed[i].qst)); + } + } + out_vals[i] = allowed[i].defval; + continue; + } else { + kws_found++; + given_arg = kw->value; + } + } + if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_BOOL) { + out_vals[i].u_bool = mp_obj_is_true(given_arg); + } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) { + out_vals[i].u_int = mp_obj_get_int(given_arg); + } else { + assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ); + out_vals[i].u_obj = given_arg; + } + } + if (pos_found < n_pos) { + extra_positional: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + // TODO better error message + mp_raise_TypeError("extra positional arguments given"); + } + } + if (kws_found < kws->used) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + // TODO better error message + mp_raise_TypeError("extra keyword arguments given"); + } + } +} + +void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) { + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos); + mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals); +} + +NORETURN void mp_arg_error_terse_mismatch(void) { + mp_raise_TypeError("argument num/types mismatch"); +} + +#if MICROPY_CPYTHON_COMPAT +NORETURN void mp_arg_error_unimpl_kw(void) { + mp_raise_NotImplementedError("keyword argument(s) not yet implemented - use normal args instead"); +} +#endif diff --git a/src/openmv/src/micropython/py/asmarm.c b/src/openmv/src/micropython/py/asmarm.c new file mode 100755 index 0000000..3610f83 --- /dev/null +++ b/src/openmv/src/micropython/py/asmarm.c @@ -0,0 +1,376 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Fabian Vogt + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_ARM + +#include "py/asmarm.h" + +#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) + +void asm_arm_end_pass(asm_arm_t *as) { + if (as->base.pass == MP_ASM_PASS_EMIT) { +#ifdef __arm__ + // flush I- and D-cache + asm volatile( + "0:" + "mrc p15, 0, r15, c7, c10, 3\n" + "bne 0b\n" + "mov r0, #0\n" + "mcr p15, 0, r0, c7, c7, 0\n" + : : : "r0", "cc"); +#endif + } +} + +// Insert word into instruction flow +STATIC void emit(asm_arm_t *as, uint op) { + uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); + if (c != NULL) { + *(uint32_t*)c = op; + } +} + +// Insert word into instruction flow, add "ALWAYS" condition code +STATIC void emit_al(asm_arm_t *as, uint op) { + emit(as, op | ASM_ARM_CC_AL); +} + +// Basic instructions without condition code +STATIC uint asm_arm_op_push(uint reglist) { + // stmfd sp!, {reglist} + return 0x92d0000 | (reglist & 0xFFFF); +} + +STATIC uint asm_arm_op_pop(uint reglist) { + // ldmfd sp!, {reglist} + return 0x8bd0000 | (reglist & 0xFFFF); +} + +STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) { + // mov rd, rn + return 0x1a00000 | (rd << 12) | rn; +} + +STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) { + // mov rd, #imm + return 0x3a00000 | (rd << 12) | imm; +} + +STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) { + // mvn rd, #imm + return 0x3e00000 | (rd << 12) | imm; +} + +STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) { + // add rd, rn, #imm + return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF); +} + +STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) { + // add rd, rn, rm + return 0x0800000 | (rn << 16) | (rd << 12) | rm; +} + +STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) { + // sub rd, rn, #imm + return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF); +} + +STATIC uint asm_arm_op_sub_reg(uint rd, uint rn, uint rm) { + // sub rd, rn, rm + return 0x0400000 | (rn << 16) | (rd << 12) | rm; +} + +STATIC uint asm_arm_op_mul_reg(uint rd, uint rm, uint rs) { + // mul rd, rm, rs + assert(rd != rm); + return 0x0000090 | (rd << 16) | (rs << 8) | rm; +} + +STATIC uint asm_arm_op_and_reg(uint rd, uint rn, uint rm) { + // and rd, rn, rm + return 0x0000000 | (rn << 16) | (rd << 12) | rm; +} + +STATIC uint asm_arm_op_eor_reg(uint rd, uint rn, uint rm) { + // eor rd, rn, rm + return 0x0200000 | (rn << 16) | (rd << 12) | rm; +} + +STATIC uint asm_arm_op_orr_reg(uint rd, uint rn, uint rm) { + // orr rd, rn, rm + return 0x1800000 | (rn << 16) | (rd << 12) | rm; +} + +void asm_arm_bkpt(asm_arm_t *as) { + // bkpt #0 + emit_al(as, 0x1200070); +} + +// locals: +// - stored on the stack in ascending order +// - numbered 0 through num_locals-1 +// - SP points to first local +// +// | SP +// v +// l0 l1 l2 ... l(n-1) +// ^ ^ +// | low address | high address in RAM + +void asm_arm_entry(asm_arm_t *as, int num_locals) { + assert(num_locals >= 0); + + as->stack_adjust = 0; + as->push_reglist = 1 << ASM_ARM_REG_R1 + | 1 << ASM_ARM_REG_R2 + | 1 << ASM_ARM_REG_R3 + | 1 << ASM_ARM_REG_R4 + | 1 << ASM_ARM_REG_R5 + | 1 << ASM_ARM_REG_R6 + | 1 << ASM_ARM_REG_R7 + | 1 << ASM_ARM_REG_R8; + + // Only adjust the stack if there are more locals than usable registers + if (num_locals > 3) { + as->stack_adjust = num_locals * 4; + // Align stack to 8 bytes + if (num_locals & 1) { + as->stack_adjust += 4; + } + } + + emit_al(as, asm_arm_op_push(as->push_reglist | 1 << ASM_ARM_REG_LR)); + if (as->stack_adjust > 0) { + emit_al(as, asm_arm_op_sub_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); + } +} + +void asm_arm_exit(asm_arm_t *as) { + if (as->stack_adjust > 0) { + emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); + } + + emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << ASM_ARM_REG_PC))); +} + +void asm_arm_push(asm_arm_t *as, uint reglist) { + emit_al(as, asm_arm_op_push(reglist)); +} + +void asm_arm_pop(asm_arm_t *as, uint reglist) { + emit_al(as, asm_arm_op_pop(reglist)); +} + +void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) { + emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src)); +} + +void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) { + // TODO: There are more variants of immediate values + if ((imm & 0xFF) == imm) { + emit_al(as, asm_arm_op_mov_imm(rd, imm)); + } else if (imm < 0 && imm >= -256) { + // mvn is "move not", not "move negative" + emit_al(as, asm_arm_op_mvn_imm(rd, ~imm)); + } else { + //Insert immediate into code and jump over it + emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc] + emit_al(as, 0xa000000); // b pc + emit(as, imm); + } +} + +void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) { + // str rd, [sp, #local_num*4] + emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2)); +} + +void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) { + // ldr rd, [sp, #local_num*4] + emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2)); +} + +void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) { + // cmp rd, #imm + emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF)); +} + +void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) { + // cmp rd, rn + emit_al(as, 0x1500000 | (rd << 16) | rn); +} + +void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond) { + emit(as, asm_arm_op_mov_imm(rd, 1) | cond); // movCOND rd, #1 + emit(as, asm_arm_op_mov_imm(rd, 0) | (cond ^ (1 << 28))); // mov!COND rd, #0 +} + +void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { + // add rd, rn, rm + emit_al(as, asm_arm_op_add_reg(rd, rn, rm)); +} + +void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { + // sub rd, rn, rm + emit_al(as, asm_arm_op_sub_reg(rd, rn, rm)); +} + +void asm_arm_mul_reg_reg_reg(asm_arm_t *as, uint rd, uint rs, uint rm) { + // rs and rm are swapped because of restriction rd!=rm + // mul rd, rm, rs + emit_al(as, asm_arm_op_mul_reg(rd, rm, rs)); +} + +void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { + // and rd, rn, rm + emit_al(as, asm_arm_op_and_reg(rd, rn, rm)); +} + +void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { + // eor rd, rn, rm + emit_al(as, asm_arm_op_eor_reg(rd, rn, rm)); +} + +void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { + // orr rd, rn, rm + emit_al(as, asm_arm_op_orr_reg(rd, rn, rm)); +} + +void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) { + // add rd, sp, #local_num*4 + emit_al(as, asm_arm_op_add_imm(rd, ASM_ARM_REG_SP, local_num << 2)); +} + +void asm_arm_mov_reg_pcrel(asm_arm_t *as, uint reg_dest, uint label) { + assert(label < as->base.max_num_labels); + mp_uint_t dest = as->base.label_offsets[label]; + mp_int_t rel = dest - as->base.code_offset; + rel -= 12 + 8; // adjust for load of rel, and then PC+8 prefetch of add_reg_reg_reg + + // To load rel int reg_dest, insert immediate into code and jump over it + emit_al(as, 0x59f0000 | (reg_dest << 12)); // ldr rd, [pc] + emit_al(as, 0xa000000); // b pc + emit(as, rel); + + // Do reg_dest += PC + asm_arm_add_reg_reg_reg(as, reg_dest, reg_dest, ASM_ARM_REG_PC); +} + +void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs) { + // mov rd, rd, lsl rs + emit_al(as, 0x1a00010 | (rd << 12) | (rs << 8) | rd); +} + +void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) { + // mov rd, rd, asr rs + emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd); +} + +void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + // ldr rd, [rn, #off] + emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); +} + +void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) { + // ldrh rd, [rn] + emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12)); +} + +void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) { + // ldrb rd, [rn] + emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12)); +} + +void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + // str rd, [rm, #off] + emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); +} + +void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) { + // strh rd, [rm] + emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12)); +} + +void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) { + // strb rd, [rm] + emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12)); +} + +void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // str rd, [rm, rn, lsl #2] + emit_al(as, 0x7800100 | (rm << 16) | (rd << 12) | rn); +} + +void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // strh doesn't support scaled register index + emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1 + emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8] +} + +void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // strb rd, [rm, rn] + emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | rn); +} + +void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) { + assert(label < as->base.max_num_labels); + mp_uint_t dest = as->base.label_offsets[label]; + mp_int_t rel = dest - as->base.code_offset; + rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction + rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted + + if (SIGNED_FIT24(rel)) { + emit(as, cond | 0xa000000 | (rel & 0xffffff)); + } else { + printf("asm_arm_bcc: branch does not fit in 24 bits\n"); + } +} + +void asm_arm_b_label(asm_arm_t *as, uint label) { + asm_arm_bcc_label(as, ASM_ARM_CC_AL, label); +} + +void asm_arm_bl_ind(asm_arm_t *as, uint fun_id, uint reg_temp) { + // The table offset should fit into the ldr instruction + assert(fun_id < (0x1000 / 4)); + emit_al(as, asm_arm_op_mov_reg(ASM_ARM_REG_LR, ASM_ARM_REG_PC)); // mov lr, pc + emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4] +} + +void asm_arm_bx_reg(asm_arm_t *as, uint reg_src) { + emit_al(as, 0x012fff10 | reg_src); +} + +#endif // MICROPY_EMIT_ARM diff --git a/src/openmv/src/micropython/py/asmarm.h b/src/openmv/src/micropython/py/asmarm.h new file mode 100755 index 0000000..58a13cc --- /dev/null +++ b/src/openmv/src/micropython/py/asmarm.h @@ -0,0 +1,209 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Fabian Vogt + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMARM_H +#define MICROPY_INCLUDED_PY_ASMARM_H + +#include "py/misc.h" +#include "py/asmbase.h" + +#define ASM_ARM_REG_R0 (0) +#define ASM_ARM_REG_R1 (1) +#define ASM_ARM_REG_R2 (2) +#define ASM_ARM_REG_R3 (3) +#define ASM_ARM_REG_R4 (4) +#define ASM_ARM_REG_R5 (5) +#define ASM_ARM_REG_R6 (6) +#define ASM_ARM_REG_R7 (7) +#define ASM_ARM_REG_R8 (8) +#define ASM_ARM_REG_R9 (9) +#define ASM_ARM_REG_R10 (10) +#define ASM_ARM_REG_R11 (11) +#define ASM_ARM_REG_R12 (12) +#define ASM_ARM_REG_R13 (13) +#define ASM_ARM_REG_R14 (14) +#define ASM_ARM_REG_R15 (15) +#define ASM_ARM_REG_SP (ASM_ARM_REG_R13) +#define ASM_ARM_REG_LR (ASM_ARM_REG_R14) +#define ASM_ARM_REG_PC (ASM_ARM_REG_R15) + +#define ASM_ARM_CC_EQ (0x0 << 28) +#define ASM_ARM_CC_NE (0x1 << 28) +#define ASM_ARM_CC_CS (0x2 << 28) +#define ASM_ARM_CC_CC (0x3 << 28) +#define ASM_ARM_CC_MI (0x4 << 28) +#define ASM_ARM_CC_PL (0x5 << 28) +#define ASM_ARM_CC_VS (0x6 << 28) +#define ASM_ARM_CC_VC (0x7 << 28) +#define ASM_ARM_CC_HI (0x8 << 28) +#define ASM_ARM_CC_LS (0x9 << 28) +#define ASM_ARM_CC_GE (0xa << 28) +#define ASM_ARM_CC_LT (0xb << 28) +#define ASM_ARM_CC_GT (0xc << 28) +#define ASM_ARM_CC_LE (0xd << 28) +#define ASM_ARM_CC_AL (0xe << 28) + +typedef struct _asm_arm_t { + mp_asm_base_t base; + uint push_reglist; + uint stack_adjust; +} asm_arm_t; + +void asm_arm_end_pass(asm_arm_t *as); + +void asm_arm_entry(asm_arm_t *as, int num_locals); +void asm_arm_exit(asm_arm_t *as); + +void asm_arm_bkpt(asm_arm_t *as); + +// mov +void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src); +void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm); +void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd); +void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num); +void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond); + +// compare +void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm); +void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn); + +// arithmetic +void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_mul_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm); +void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num); +void asm_arm_mov_reg_pcrel(asm_arm_t *as, uint reg_dest, uint label); +void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs); +void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs); + +// memory +void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset); +void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn); +void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn); +void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm); +void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm); +// store to array +void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); + +// stack +void asm_arm_push(asm_arm_t *as, uint reglist); +void asm_arm_pop(asm_arm_t *as, uint reglist); + +// control flow +void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label); +void asm_arm_b_label(asm_arm_t *as, uint label); +void asm_arm_bl_ind(asm_arm_t *as, uint fun_id, uint reg_temp); +void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); + +// Holds a pointer to mp_fun_table +#define ASM_ARM_REG_FUN_TABLE ASM_ARM_REG_R7 + +#if GENERIC_ASM_API + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (4) + +#define REG_RET ASM_ARM_REG_R0 +#define REG_ARG_1 ASM_ARM_REG_R0 +#define REG_ARG_2 ASM_ARM_REG_R1 +#define REG_ARG_3 ASM_ARM_REG_R2 +#define REG_ARG_4 ASM_ARM_REG_R3 + +#define REG_TEMP0 ASM_ARM_REG_R0 +#define REG_TEMP1 ASM_ARM_REG_R1 +#define REG_TEMP2 ASM_ARM_REG_R2 + +#define REG_LOCAL_1 ASM_ARM_REG_R4 +#define REG_LOCAL_2 ASM_ARM_REG_R5 +#define REG_LOCAL_3 ASM_ARM_REG_R6 +#define REG_LOCAL_NUM (3) + +// Holds a pointer to mp_fun_table +#define REG_FUN_TABLE ASM_ARM_REG_FUN_TABLE + +#define ASM_T asm_arm_t +#define ASM_END_PASS asm_arm_end_pass +#define ASM_ENTRY asm_arm_entry +#define ASM_EXIT asm_arm_exit + +#define ASM_JUMP asm_arm_b_label +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + do { \ + asm_arm_cmp_reg_i8(as, reg, 0); \ + asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + do { \ + asm_arm_cmp_reg_i8(as, reg, 0); \ + asm_arm_bcc_label(as, ASM_ARM_CC_NE, label); \ + } while (0) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + do { \ + asm_arm_cmp_reg_reg(as, reg1, reg2); \ + asm_arm_bcc_label(as, ASM_ARM_CC_EQ, label); \ + } while (0) +#define ASM_JUMP_REG(as, reg) asm_arm_bx_reg((as), (reg)) +#define ASM_CALL_IND(as, idx) asm_arm_bl_ind(as, idx, ASM_ARM_REG_R3) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_arm_mov_reg_pcrel((as), (reg_dest), (label)) + +#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift)) +#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift)) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_arm_orr_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_arm_and_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_arm_add_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) + +#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) + +#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) +#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_str_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base)) +#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base)) +#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) + +#endif // GENERIC_ASM_API + +#endif // MICROPY_INCLUDED_PY_ASMARM_H diff --git a/src/openmv/src/micropython/py/asmbase.c b/src/openmv/src/micropython/py/asmbase.c new file mode 100755 index 0000000..4c84c3b --- /dev/null +++ b/src/openmv/src/micropython/py/asmbase.c @@ -0,0 +1,102 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/misc.h" +#include "py/asmbase.h" + +#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + +void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) { + as->max_num_labels = max_num_labels; + as->label_offsets = m_new(size_t, max_num_labels); +} + +void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { + if (free_code) { + MP_PLAT_FREE_EXEC(as->code_base, as->code_size); + } + m_del(size_t, as->label_offsets, as->max_num_labels); +} + +void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { + if (pass < MP_ASM_PASS_EMIT) { + // Reset labels so we can detect backwards jumps (and verify unique assignment) + memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); + } else { + // allocating executable RAM is platform specific + MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); + assert(as->code_base != NULL); + } + as->pass = pass; + as->code_offset = 0; +} + +// all functions must go through this one to emit bytes +// if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number +// of bytes needed and returns NULL, and callers should not store any data +uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) { + uint8_t *c = NULL; + if (as->pass == MP_ASM_PASS_EMIT) { + assert(as->code_offset + num_bytes_to_write <= as->code_size); + c = as->code_base + as->code_offset; + } + as->code_offset += num_bytes_to_write; + return c; +} + +void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { + assert(label < as->max_num_labels); + if (as->pass < MP_ASM_PASS_EMIT) { + // assign label offset + assert(as->label_offsets[label] == (size_t)-1); + as->label_offsets[label] = as->code_offset; + } else { + // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT + assert(as->label_offsets[label] == as->code_offset); + } +} + +// align must be a multiple of 2 +void mp_asm_base_align(mp_asm_base_t* as, unsigned int align) { + as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); +} + +// this function assumes a little endian machine +void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) { + uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize); + if (c != NULL) { + for (unsigned int i = 0; i < bytesize; i++) { + *c++ = val; + val >>= 8; + } + } +} + +#endif // MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM diff --git a/src/openmv/src/micropython/py/asmbase.h b/src/openmv/src/micropython/py/asmbase.h new file mode 100755 index 0000000..d2b4038 --- /dev/null +++ b/src/openmv/src/micropython/py/asmbase.h @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMBASE_H +#define MICROPY_INCLUDED_PY_ASMBASE_H + +#include +#include + +#define MP_ASM_PASS_COMPUTE (1) +#define MP_ASM_PASS_EMIT (2) + +typedef struct _mp_asm_base_t { + int pass; + size_t code_offset; + size_t code_size; + uint8_t *code_base; + + size_t max_num_labels; + size_t *label_offsets; +} mp_asm_base_t; + +void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels); +void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code); +void mp_asm_base_start_pass(mp_asm_base_t *as, int pass); +uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write); +void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label); +void mp_asm_base_align(mp_asm_base_t* as, unsigned int align); +void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val); + +static inline size_t mp_asm_base_get_code_pos(mp_asm_base_t *as) { + return as->code_offset; +} + +static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) { + return as->code_size; +} + +static inline void *mp_asm_base_get_code(mp_asm_base_t *as) { + #if defined(MP_PLAT_COMMIT_EXEC) + return MP_PLAT_COMMIT_EXEC(as->code_base, as->code_size); + #else + return as->code_base; + #endif +} + +#endif // MICROPY_INCLUDED_PY_ASMBASE_H diff --git a/src/openmv/src/micropython/py/asmthumb.c b/src/openmv/src/micropython/py/asmthumb.c new file mode 100755 index 0000000..4610239 --- /dev/null +++ b/src/openmv/src/micropython/py/asmthumb.c @@ -0,0 +1,390 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB + +#include "py/mphal.h" +#include "py/asmthumb.h" + +#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) +#define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128) +#define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0) +#define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0) +#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) +#define SIGNED_FIT9(x) (((x) & 0xffffff00) == 0) || (((x) & 0xffffff00) == 0xffffff00) +#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) +#define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) + +// Note: these actually take an imm12 but the high-bit is not encoded here +#define OP_ADD_W_RRI_HI(reg_src) (0xf200 | (reg_src)) +#define OP_ADD_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff)) +#define OP_SUB_W_RRI_HI(reg_src) (0xf2a0 | (reg_src)) +#define OP_SUB_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff)) + +#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base)) +#define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) + +static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { + return mp_asm_base_get_cur_to_write_bytes(&as->base, n); +} + +void asm_thumb_end_pass(asm_thumb_t *as) { + (void)as; + // could check labels are resolved... + + #if __ICACHE_PRESENT == 1 + if (as->base.pass == MP_ASM_PASS_EMIT) { + // flush D-cache, so the code emitted is stored in memory + MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size); + // invalidate I-cache + SCB_InvalidateICache(); + } + #endif +} + +/* +STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) { + byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); + c[0] = b1; +} +*/ + +/* +#define IMM32_L0(x) ((x) & 0xff) +#define IMM32_L1(x) (((x) >> 8) & 0xff) +#define IMM32_L2(x) (((x) >> 16) & 0xff) +#define IMM32_L3(x) (((x) >> 24) & 0xff) + +STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { + byte *c = asm_thumb_get_cur_to_write_bytes(as, 4); + c[0] = IMM32_L0(w32); + c[1] = IMM32_L1(w32); + c[2] = IMM32_L2(w32); + c[3] = IMM32_L3(w32); +} +*/ + +// rlolist is a bit map indicating desired lo-registers +#define OP_PUSH_RLIST(rlolist) (0xb400 | (rlolist)) +#define OP_PUSH_RLIST_LR(rlolist) (0xb400 | 0x0100 | (rlolist)) +#define OP_POP_RLIST(rlolist) (0xbc00 | (rlolist)) +#define OP_POP_RLIST_PC(rlolist) (0xbc00 | 0x0100 | (rlolist)) + +// The number of words must fit in 7 unsigned bits +#define OP_ADD_SP(num_words) (0xb000 | (num_words)) +#define OP_SUB_SP(num_words) (0xb080 | (num_words)) + +// locals: +// - stored on the stack in ascending order +// - numbered 0 through num_locals-1 +// - SP points to first local +// +// | SP +// v +// l0 l1 l2 ... l(n-1) +// ^ ^ +// | low address | high address in RAM + +void asm_thumb_entry(asm_thumb_t *as, int num_locals) { + assert(num_locals >= 0); + + // work out what to push and how many extra spaces to reserve on stack + // so that we have enough for all locals and it's aligned an 8-byte boundary + // we push extra regs (r1, r2, r3) to help do the stack adjustment + // we probably should just always subtract from sp, since this would be more efficient + // for push rlist, lowest numbered register at the lowest address + uint reglist; + uint stack_adjust; + // don't pop r0 because it's used for return value + switch (num_locals) { + case 0: + reglist = 0xf2; + stack_adjust = 0; + break; + + case 1: + reglist = 0xf2; + stack_adjust = 0; + break; + + case 2: + reglist = 0xfe; + stack_adjust = 0; + break; + + case 3: + reglist = 0xfe; + stack_adjust = 0; + break; + + default: + reglist = 0xfe; + stack_adjust = ((num_locals - 3) + 1) & (~1); + break; + } + asm_thumb_op16(as, OP_PUSH_RLIST_LR(reglist)); + if (stack_adjust > 0) { + if (UNSIGNED_FIT7(stack_adjust)) { + asm_thumb_op16(as, OP_SUB_SP(stack_adjust)); + } else { + asm_thumb_op32(as, OP_SUB_W_RRI_HI(ASM_THUMB_REG_SP), OP_SUB_W_RRI_LO(ASM_THUMB_REG_SP, stack_adjust * 4)); + } + } + as->push_reglist = reglist; + as->stack_adjust = stack_adjust; +} + +void asm_thumb_exit(asm_thumb_t *as) { + if (as->stack_adjust > 0) { + if (UNSIGNED_FIT7(as->stack_adjust)) { + asm_thumb_op16(as, OP_ADD_SP(as->stack_adjust)); + } else { + asm_thumb_op32(as, OP_ADD_W_RRI_HI(ASM_THUMB_REG_SP), OP_ADD_W_RRI_LO(ASM_THUMB_REG_SP, as->stack_adjust * 4)); + } + } + asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist)); +} + +STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) { + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; +} + +void asm_thumb_op16(asm_thumb_t *as, uint op) { + byte *c = asm_thumb_get_cur_to_write_bytes(as, 2); + if (c != NULL) { + // little endian + c[0] = op; + c[1] = op >> 8; + } +} + +void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2) { + byte *c = asm_thumb_get_cur_to_write_bytes(as, 4); + if (c != NULL) { + // little endian, op1 then op2 + c[0] = op1; + c[1] = op1 >> 8; + c[2] = op2; + c[3] = op2 >> 8; + } +} + +#define OP_FORMAT_4(op, rlo_dest, rlo_src) ((op) | ((rlo_src) << 3) | (rlo_dest)) + +void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src) { + assert(rlo_dest < ASM_THUMB_REG_R8); + assert(rlo_src < ASM_THUMB_REG_R8); + asm_thumb_op16(as, OP_FORMAT_4(op, rlo_dest, rlo_src)); +} + +void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { + uint op_lo; + if (reg_src < 8) { + op_lo = reg_src << 3; + } else { + op_lo = 0x40 | ((reg_src - 8) << 3); + } + if (reg_dest < 8) { + op_lo |= reg_dest; + } else { + op_lo |= 0x80 | (reg_dest - 8); + } + // mov reg_dest, reg_src + asm_thumb_op16(as, 0x4600 | op_lo); +} + +// if loading lo half with movw, the i16 value will be zero extended into the r32 register! +void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src) { + assert(reg_dest < ASM_THUMB_REG_R15); + // mov[wt] reg_dest, #i16_src + asm_thumb_op32(as, mov_op | ((i16_src >> 1) & 0x0400) | ((i16_src >> 12) & 0xf), ((i16_src << 4) & 0x7000) | (reg_dest << 8) | (i16_src & 0xff)); +} + +#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) + +bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + asm_thumb_op16(as, OP_B_N(rel)); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT12(rel); +} + +#define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) + +// all these bit arithmetics need coverage testing! +#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) +#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) + +bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + if (!wide) { + asm_thumb_op16(as, OP_BCC_N(cond, rel)); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel); + } else { + asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); + return true; + } +} + +#define OP_BL_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) +#define OP_BL_LO(byte_offset) (0xf800 | (((byte_offset) >> 1) & 0x07ff)) + +bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); +} + +void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { + // movw, movt does it in 8 bytes + // ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw + + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVT, reg_dest, i32 >> 16); +} + +void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { + if (reg_dest < 8 && UNSIGNED_FIT8(i32)) { + asm_thumb_mov_rlo_i8(as, reg_dest, i32); + } else if (UNSIGNED_FIT16(i32)) { + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, reg_dest, i32); + } else { + asm_thumb_mov_reg_i32(as, reg_dest, i32); + } +} + +#define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) +#define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) + +void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) { + assert(rlo_src < ASM_THUMB_REG_R8); + int word_offset = local_num; + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); + asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset)); +} + +void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { + assert(rlo_dest < ASM_THUMB_REG_R8); + int word_offset = local_num; + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); + asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset)); +} + +#define OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset) (0xa800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff)) + +void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) { + assert(rlo_dest < ASM_THUMB_REG_R8); + int word_offset = local_num; + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); + asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); +} + +void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4 + 4; // adjust for mov_reg_i16 and then PC+4 prefetch of add_reg_reg + rel |= 1; // to stay in Thumb state when jumping to this address + asm_thumb_mov_reg_i16(as, ASM_THUMB_OP_MOVW, rlo_dest, rel); // 4 bytes + asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes +} + +static inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { + asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4)); +} + +void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { + if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) { + asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset); + } else { + asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset); + } +} + +// this could be wrong, because it should have a range of +/- 16MiB... +#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) +#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) + +void asm_thumb_b_label(asm_thumb_t *as, uint label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + if (dest != (mp_uint_t)-1 && rel <= -4) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 12 bit relative jump + if (SIGNED_FIT12(rel)) { + asm_thumb_op16(as, OP_B_N(rel)); + } else { + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel)); + } +} + +void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction + if (dest != (mp_uint_t)-1 && rel <= -4) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 9 bit relative jump + if (SIGNED_FIT9(rel)) { + asm_thumb_op16(as, OP_BCC_N(cond, rel)); + } else { + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); + } +} + +#define OP_BLX(reg) (0x4780 | ((reg) << 3)) +#define OP_SVC(arg) (0xdf00 | (arg)) + +void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp) { + // Load ptr to function from table, indexed by fun_id, then call it + asm_thumb_ldr_reg_reg_i12_optimised(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id); + asm_thumb_op16(as, OP_BLX(reg_temp)); +} + +#endif // MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB diff --git a/src/openmv/src/micropython/py/asmthumb.h b/src/openmv/src/micropython/py/asmthumb.h new file mode 100755 index 0000000..9a44a78 --- /dev/null +++ b/src/openmv/src/micropython/py/asmthumb.h @@ -0,0 +1,346 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H +#define MICROPY_INCLUDED_PY_ASMTHUMB_H + +#include +#include "py/misc.h" +#include "py/asmbase.h" + +#define ASM_THUMB_REG_R0 (0) +#define ASM_THUMB_REG_R1 (1) +#define ASM_THUMB_REG_R2 (2) +#define ASM_THUMB_REG_R3 (3) +#define ASM_THUMB_REG_R4 (4) +#define ASM_THUMB_REG_R5 (5) +#define ASM_THUMB_REG_R6 (6) +#define ASM_THUMB_REG_R7 (7) +#define ASM_THUMB_REG_R8 (8) +#define ASM_THUMB_REG_R9 (9) +#define ASM_THUMB_REG_R10 (10) +#define ASM_THUMB_REG_R11 (11) +#define ASM_THUMB_REG_R12 (12) +#define ASM_THUMB_REG_R13 (13) +#define ASM_THUMB_REG_R14 (14) +#define ASM_THUMB_REG_R15 (15) +#define ASM_THUMB_REG_SP (ASM_THUMB_REG_R13) +#define ASM_THUMB_REG_LR (REG_R14) + +#define ASM_THUMB_CC_EQ (0x0) +#define ASM_THUMB_CC_NE (0x1) +#define ASM_THUMB_CC_CS (0x2) +#define ASM_THUMB_CC_CC (0x3) +#define ASM_THUMB_CC_MI (0x4) +#define ASM_THUMB_CC_PL (0x5) +#define ASM_THUMB_CC_VS (0x6) +#define ASM_THUMB_CC_VC (0x7) +#define ASM_THUMB_CC_HI (0x8) +#define ASM_THUMB_CC_LS (0x9) +#define ASM_THUMB_CC_GE (0xa) +#define ASM_THUMB_CC_LT (0xb) +#define ASM_THUMB_CC_GT (0xc) +#define ASM_THUMB_CC_LE (0xd) + +typedef struct _asm_thumb_t { + mp_asm_base_t base; + uint32_t push_reglist; + uint32_t stack_adjust; +} asm_thumb_t; + +void asm_thumb_end_pass(asm_thumb_t *as); + +void asm_thumb_entry(asm_thumb_t *as, int num_locals); +void asm_thumb_exit(asm_thumb_t *as); + +// argument order follows ARM, in general dest is first +// note there is a difference between movw and mov.w, and many others! + +#define ASM_THUMB_OP_IT (0xbf00) +#define ASM_THUMB_OP_ITE_EQ (0xbf0c) +#define ASM_THUMB_OP_ITE_CS (0xbf2c) +#define ASM_THUMB_OP_ITE_MI (0xbf4c) +#define ASM_THUMB_OP_ITE_VS (0xbf6c) +#define ASM_THUMB_OP_ITE_HI (0xbf8c) +#define ASM_THUMB_OP_ITE_GE (0xbfac) +#define ASM_THUMB_OP_ITE_GT (0xbfcc) + +#define ASM_THUMB_OP_NOP (0xbf00) +#define ASM_THUMB_OP_WFI (0xbf30) +#define ASM_THUMB_OP_CPSID_I (0xb672) // cpsid i, disable irq +#define ASM_THUMB_OP_CPSIE_I (0xb662) // cpsie i, enable irq + +void asm_thumb_op16(asm_thumb_t *as, uint op); +void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2); + +static inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask) + { asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask); } + +// FORMAT 1: move shifted register + +#define ASM_THUMB_FORMAT_1_LSL (0x0000) +#define ASM_THUMB_FORMAT_1_LSR (0x0800) +#define ASM_THUMB_FORMAT_1_ASR (0x1000) + +#define ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset) \ + ((op) | ((offset) << 6) | ((rlo_src) << 3) | (rlo_dest)) + +static inline void asm_thumb_format_1(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, uint offset) { + assert(rlo_dest < ASM_THUMB_REG_R8); + assert(rlo_src < ASM_THUMB_REG_R8); + asm_thumb_op16(as, ASM_THUMB_FORMAT_1_ENCODE(op, rlo_dest, rlo_src, offset)); +} + +// FORMAT 2: add/subtract + +#define ASM_THUMB_FORMAT_2_ADD (0x1800) +#define ASM_THUMB_FORMAT_2_SUB (0x1a00) +#define ASM_THUMB_FORMAT_2_REG_OPERAND (0x0000) +#define ASM_THUMB_FORMAT_2_IMM_OPERAND (0x0400) + +#define ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b) \ + ((op) | ((src_b) << 6) | ((rlo_src) << 3) | (rlo_dest)) + +static inline void asm_thumb_format_2(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src, int src_b) { + assert(rlo_dest < ASM_THUMB_REG_R8); + assert(rlo_src < ASM_THUMB_REG_R8); + asm_thumb_op16(as, ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b)); +} + +static inline void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) + { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); } +static inline void asm_thumb_add_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) + { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); } +static inline void asm_thumb_sub_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) + { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); } +static inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) + { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); } + +// FORMAT 3: move/compare/add/subtract immediate +// These instructions all do zero extension of the i8 value + +#define ASM_THUMB_FORMAT_3_MOV (0x2000) +#define ASM_THUMB_FORMAT_3_CMP (0x2800) +#define ASM_THUMB_FORMAT_3_ADD (0x3000) +#define ASM_THUMB_FORMAT_3_SUB (0x3800) + +#define ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8) ((op) | ((rlo) << 8) | (i8)) + +static inline void asm_thumb_format_3(asm_thumb_t *as, uint op, uint rlo, int i8) { + assert(rlo < ASM_THUMB_REG_R8); + asm_thumb_op16(as, ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8)); +} + +static inline void asm_thumb_mov_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_MOV, rlo, i8); } +static inline void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_CMP, rlo, i8); } +static inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_ADD, rlo, i8); } +static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8); } + +// FORMAT 4: ALU operations + +#define ASM_THUMB_FORMAT_4_AND (0x4000) +#define ASM_THUMB_FORMAT_4_EOR (0x4040) +#define ASM_THUMB_FORMAT_4_LSL (0x4080) +#define ASM_THUMB_FORMAT_4_LSR (0x40c0) +#define ASM_THUMB_FORMAT_4_ASR (0x4100) +#define ASM_THUMB_FORMAT_4_ADC (0x4140) +#define ASM_THUMB_FORMAT_4_SBC (0x4180) +#define ASM_THUMB_FORMAT_4_ROR (0x41c0) +#define ASM_THUMB_FORMAT_4_TST (0x4200) +#define ASM_THUMB_FORMAT_4_NEG (0x4240) +#define ASM_THUMB_FORMAT_4_CMP (0x4280) +#define ASM_THUMB_FORMAT_4_CMN (0x42c0) +#define ASM_THUMB_FORMAT_4_ORR (0x4300) +#define ASM_THUMB_FORMAT_4_MUL (0x4340) +#define ASM_THUMB_FORMAT_4_BIC (0x4380) +#define ASM_THUMB_FORMAT_4_MVN (0x43c0) + +void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src); + +static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) { asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src); } + +// FORMAT 5: hi register operations (add, cmp, mov, bx) +// For add/cmp/mov, at least one of the args must be a high register + +#define ASM_THUMB_FORMAT_5_ADD (0x4400) +#define ASM_THUMB_FORMAT_5_BX (0x4700) + +#define ASM_THUMB_FORMAT_5_ENCODE(op, r_dest, r_src) \ + ((op) | ((r_dest) << 4 & 0x0080) | ((r_src) << 3) | ((r_dest) & 0x0007)) + +static inline void asm_thumb_format_5(asm_thumb_t *as, uint op, uint r_dest, uint r_src) { + asm_thumb_op16(as, ASM_THUMB_FORMAT_5_ENCODE(op, r_dest, r_src)); +} + +static inline void asm_thumb_add_reg_reg(asm_thumb_t *as, uint r_dest, uint r_src) { + asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_ADD, r_dest, r_src); +} +static inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) { + asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_BX, 0, r_src); +} + +// FORMAT 9: load/store with immediate offset +// For word transfers the offset must be aligned, and >>2 + +// FORMAT 10: load/store halfword +// The offset must be aligned, and >>1 +// The load is zero extended into the register + +#define ASM_THUMB_FORMAT_9_STR (0x6000) +#define ASM_THUMB_FORMAT_9_LDR (0x6800) +#define ASM_THUMB_FORMAT_9_WORD_TRANSFER (0x0000) +#define ASM_THUMB_FORMAT_9_BYTE_TRANSFER (0x1000) + +#define ASM_THUMB_FORMAT_10_STRH (0x8000) +#define ASM_THUMB_FORMAT_10_LDRH (0x8800) + +#define ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset) \ + ((op) | (((offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest)) + +static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint offset) + { asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); } + +static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); } +static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); } +static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, byte_offset); } +static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); } +static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER , rlo_dest, rlo_base, byte_offset); } +static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) + { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset); } + +// TODO convert these to above format style + +#define ASM_THUMB_OP_MOVW (0xf240) +#define ASM_THUMB_OP_MOVT (0xf2c0) + +void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); +void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src); + +// these return true if the destination is in range, false otherwise +bool asm_thumb_b_n_label(asm_thumb_t *as, uint label); +bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide); +bool asm_thumb_bl_label(asm_thumb_t *as, uint label); + +void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience +void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience +void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience +void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience +void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience +void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label); + +void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint byte_offset); // convenience + +void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch +void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch +void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenience + +// Holds a pointer to mp_fun_table +#define ASM_THUMB_REG_FUN_TABLE ASM_THUMB_REG_R7 + +#if GENERIC_ASM_API + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (4) + +#define REG_RET ASM_THUMB_REG_R0 +#define REG_ARG_1 ASM_THUMB_REG_R0 +#define REG_ARG_2 ASM_THUMB_REG_R1 +#define REG_ARG_3 ASM_THUMB_REG_R2 +#define REG_ARG_4 ASM_THUMB_REG_R3 +// rest of args go on stack + +#define REG_TEMP0 ASM_THUMB_REG_R0 +#define REG_TEMP1 ASM_THUMB_REG_R1 +#define REG_TEMP2 ASM_THUMB_REG_R2 + +#define REG_LOCAL_1 ASM_THUMB_REG_R4 +#define REG_LOCAL_2 ASM_THUMB_REG_R5 +#define REG_LOCAL_3 ASM_THUMB_REG_R6 +#define REG_LOCAL_NUM (3) + +#define REG_FUN_TABLE ASM_THUMB_REG_FUN_TABLE + +#define ASM_T asm_thumb_t +#define ASM_END_PASS asm_thumb_end_pass +#define ASM_ENTRY asm_thumb_entry +#define ASM_EXIT asm_thumb_exit + +#define ASM_JUMP asm_thumb_b_label +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + do { \ + asm_thumb_cmp_rlo_i8(as, reg, 0); \ + asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + do { \ + asm_thumb_cmp_rlo_i8(as, reg, 0); \ + asm_thumb_bcc_label(as, ASM_THUMB_CC_NE, label); \ + } while (0) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + do { \ + asm_thumb_cmp_rlo_rlo(as, reg1, reg2); \ + asm_thumb_bcc_label(as, ASM_THUMB_CC_EQ, label); \ + } while (0) +#define ASM_JUMP_REG(as, reg) asm_thumb_bx_reg((as), (reg)) +#define ASM_CALL_IND(as, idx) asm_thumb_bl_ind(as, idx, ASM_THUMB_REG_R3) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_PCREL(as, rlo_dest, label) asm_thumb_mov_reg_pcrel((as), (rlo_dest), (label)) + +#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift)) +#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift)) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ORR, (reg_dest), (reg_src)) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_EOR, (reg_dest), (reg_src)) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_AND, (reg_dest), (reg_src)) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_thumb_add_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_MUL, (reg_dest), (reg_src)) + +#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) + +#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) + +#endif // GENERIC_ASM_API + +#endif // MICROPY_INCLUDED_PY_ASMTHUMB_H diff --git a/src/openmv/src/micropython/py/asmx64.c b/src/openmv/src/micropython/py/asmx64.c new file mode 100755 index 0000000..3609f49 --- /dev/null +++ b/src/openmv/src/micropython/py/asmx64.c @@ -0,0 +1,630 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_X64 + +#include "py/asmx64.h" + +/* all offsets are measured in multiples of 8 bytes */ +#define WORD_SIZE (8) + +#define OPCODE_NOP (0x90) +#define OPCODE_PUSH_R64 (0x50) /* +rq */ +#define OPCODE_PUSH_I64 (0x68) +#define OPCODE_PUSH_M64 (0xff) /* /6 */ +#define OPCODE_POP_R64 (0x58) /* +rq */ +#define OPCODE_RET (0xc3) +#define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */ +#define OPCODE_MOV_I64_TO_R64 (0xb8) /* +rq */ +#define OPCODE_MOV_I32_TO_RM32 (0xc7) +#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */ +#define OPCODE_MOV_R64_TO_RM64 (0x89) /* /r */ +#define OPCODE_MOV_RM64_TO_R64 (0x8b) /* /r */ +#define OPCODE_MOVZX_RM8_TO_R64 (0xb6) /* 0x0f 0xb6/r */ +#define OPCODE_MOVZX_RM16_TO_R64 (0xb7) /* 0x0f 0xb7/r */ +#define OPCODE_LEA_MEM_TO_R64 (0x8d) /* /r */ +#define OPCODE_AND_R64_TO_RM64 (0x21) /* /r */ +#define OPCODE_OR_R64_TO_RM64 (0x09) /* /r */ +#define OPCODE_XOR_R64_TO_RM64 (0x31) /* /r */ +#define OPCODE_ADD_R64_TO_RM64 (0x01) /* /r */ +#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */ +#define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */ +#define OPCODE_SUB_R64_FROM_RM64 (0x29) +#define OPCODE_SUB_I32_FROM_RM64 (0x81) /* /5 */ +#define OPCODE_SUB_I8_FROM_RM64 (0x83) /* /5 */ +//#define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */ +//#define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */ +//#define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */ +#define OPCODE_SHL_RM64_CL (0xd3) /* /4 */ +#define OPCODE_SAR_RM64_CL (0xd3) /* /7 */ +//#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */ +//#define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */ +#define OPCODE_CMP_R64_WITH_RM64 (0x39) /* /r */ +//#define OPCODE_CMP_RM32_WITH_R32 (0x3b) +#define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */ +#define OPCODE_TEST_R64_WITH_RM64 (0x85) /* /r */ +#define OPCODE_JMP_REL8 (0xeb) +#define OPCODE_JMP_REL32 (0xe9) +#define OPCODE_JMP_RM64 (0xff) /* /4 */ +#define OPCODE_JCC_REL8 (0x70) /* | jcc type */ +#define OPCODE_JCC_REL32_A (0x0f) +#define OPCODE_JCC_REL32_B (0x80) /* | jcc type */ +#define OPCODE_SETCC_RM8_A (0x0f) +#define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */ +#define OPCODE_CALL_REL32 (0xe8) +#define OPCODE_CALL_RM32 (0xff) /* /2 */ +#define OPCODE_LEAVE (0xc9) + +#define MODRM_R64(x) (((x) & 0x7) << 3) +#define MODRM_RM_DISP0 (0x00) +#define MODRM_RM_DISP8 (0x40) +#define MODRM_RM_DISP32 (0x80) +#define MODRM_RM_REG (0xc0) +#define MODRM_RM_R64(x) ((x) & 0x7) + +#define OP_SIZE_PREFIX (0x66) + +#define REX_PREFIX (0x40) +#define REX_W (0x08) // width +#define REX_R (0x04) // register +#define REX_X (0x02) // index +#define REX_B (0x01) // base +#define REX_W_FROM_R64(r64) ((r64) >> 0 & 0x08) +#define REX_R_FROM_R64(r64) ((r64) >> 1 & 0x04) +#define REX_X_FROM_R64(r64) ((r64) >> 2 & 0x02) +#define REX_B_FROM_R64(r64) ((r64) >> 3 & 0x01) + +#define IMM32_L0(x) ((x) & 0xff) +#define IMM32_L1(x) (((x) >> 8) & 0xff) +#define IMM32_L2(x) (((x) >> 16) & 0xff) +#define IMM32_L3(x) (((x) >> 24) & 0xff) +#define IMM64_L4(x) (((x) >> 32) & 0xff) +#define IMM64_L5(x) (((x) >> 40) & 0xff) +#define IMM64_L6(x) (((x) >> 48) & 0xff) +#define IMM64_L7(x) (((x) >> 56) & 0xff) + +#define UNSIGNED_FIT8(x) (((x) & 0xffffffffffffff00) == 0) +#define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0) +#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) + +static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) { + return mp_asm_base_get_cur_to_write_bytes(&as->base, n); +} + +STATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) { + byte* c = asm_x64_get_cur_to_write_bytes(as, 1); + if (c != NULL) { + c[0] = b1; + } +} + +STATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) { + byte* c = asm_x64_get_cur_to_write_bytes(as, 2); + if (c != NULL) { + c[0] = b1; + c[1] = b2; + } +} + +STATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) { + byte* c = asm_x64_get_cur_to_write_bytes(as, 3); + if (c != NULL) { + c[0] = b1; + c[1] = b2; + c[2] = b3; + } +} + +STATIC void asm_x64_write_word32(asm_x64_t *as, int w32) { + byte* c = asm_x64_get_cur_to_write_bytes(as, 4); + if (c != NULL) { + c[0] = IMM32_L0(w32); + c[1] = IMM32_L1(w32); + c[2] = IMM32_L2(w32); + c[3] = IMM32_L3(w32); + } +} + +STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) { + byte* c = asm_x64_get_cur_to_write_bytes(as, 8); + if (c != NULL) { + c[0] = IMM32_L0(w64); + c[1] = IMM32_L1(w64); + c[2] = IMM32_L2(w64); + c[3] = IMM32_L3(w64); + c[4] = IMM64_L4(w64); + c[5] = IMM64_L5(w64); + c[6] = IMM64_L6(w64); + c[7] = IMM64_L7(w64); + } +} + +/* unused +STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) { + byte* c; + assert(offset + 4 <= as->code_size); + c = as->code_base + offset; + c[0] = IMM32_L0(w32); + c[1] = IMM32_L1(w32); + c[2] = IMM32_L2(w32); + c[3] = IMM32_L3(w32); +} +*/ + +STATIC void asm_x64_write_r64_disp(asm_x64_t *as, int r64, int disp_r64, int disp_offset) { + uint8_t rm_disp; + if (disp_offset == 0 && (disp_r64 & 7) != ASM_X64_REG_RBP) { + rm_disp = MODRM_RM_DISP0; + } else if (SIGNED_FIT8(disp_offset)) { + rm_disp = MODRM_RM_DISP8; + } else { + rm_disp = MODRM_RM_DISP32; + } + asm_x64_write_byte_1(as, MODRM_R64(r64) | rm_disp | MODRM_RM_R64(disp_r64)); + if ((disp_r64 & 7) == ASM_X64_REG_RSP) { + // Special case for rsp and r12, they need a SIB byte + asm_x64_write_byte_1(as, 0x24); + } + if (rm_disp == MODRM_RM_DISP8) { + asm_x64_write_byte_1(as, IMM32_L0(disp_offset)); + } else if (rm_disp == MODRM_RM_DISP32) { + asm_x64_write_word32(as, disp_offset); + } +} + +STATIC void asm_x64_generic_r64_r64(asm_x64_t *as, int dest_r64, int src_r64, int op) { + asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), op, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); +} + +void asm_x64_nop(asm_x64_t *as) { + asm_x64_write_byte_1(as, OPCODE_NOP); +} + +void asm_x64_push_r64(asm_x64_t *as, int src_r64) { + if (src_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_PUSH_R64 | (src_r64 & 7)); + } +} + +/* +void asm_x64_push_i32(asm_x64_t *as, int src_i32) { + asm_x64_write_byte_1(as, OPCODE_PUSH_I64); + asm_x64_write_word32(as, src_i32); // will be sign extended to 64 bits +} +*/ + +/* +void asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) { + assert(src_r64 < 8); + asm_x64_write_byte_1(as, OPCODE_PUSH_M64); + asm_x64_write_r64_disp(as, 6, src_r64, src_offset); +} +*/ + +void asm_x64_pop_r64(asm_x64_t *as, int dest_r64) { + if (dest_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_POP_R64 | (dest_r64 & 7)); + } +} + +STATIC void asm_x64_ret(asm_x64_t *as) { + asm_x64_write_byte_1(as, OPCODE_RET); +} + +void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_MOV_R64_TO_RM64); +} + +void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { + if (src_r64 < 8 && dest_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R8_TO_RM8); + } + asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); +} + +void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { + if (src_r64 < 8 && dest_r64 < 8) { + asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64); + } else { + asm_x64_write_byte_3(as, OP_SIZE_PREFIX, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); + } + asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); +} + +void asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { + if (src_r64 < 8 && dest_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_MOV_R64_TO_RM64); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); + } + asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); +} + +void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) { + // use REX prefix for 64 bit operation + asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64); + asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp); +} + +void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { + assert(src_r64 < 8); + if (dest_r64 < 8) { + asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64); + } else { + asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64); + } + asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); +} + +void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { + assert(src_r64 < 8); + if (dest_r64 < 8) { + asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64); + } else { + asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64); + } + asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); +} + +void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { + assert(src_r64 < 8); + if (dest_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_TO_R64); + } + asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); +} + +void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { + // use REX prefix for 64 bit operation + asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64); + asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); +} + +STATIC void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { + // use REX prefix for 64 bit operation + assert(src_r64 < 8); + assert(dest_r64 < 8); + asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_LEA_MEM_TO_R64); + asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); +} + +/* +void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) { + assert(dest_r64 < 8); + asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8); +} +*/ + +STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) { + // cpu defaults to i32 to r64, with zero extension + if (dest_r64 < 8) { + asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64); + } else { + asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); + } + asm_x64_write_word32(as, src_i32); +} + +void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) { + // cpu defaults to i32 to r64 + // to mov i64 to r64 need to use REX prefix + asm_x64_write_byte_2(as, + REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_B), + OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7)); + asm_x64_write_word64(as, src_i64); +} + +void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64) { + // TODO use movzx, movsx if possible + if (UNSIGNED_FIT32(src_i64)) { + // 5 bytes + asm_x64_mov_i32_to_r64(as, src_i64 & 0xffffffff, dest_r64); + } else { + // 10 bytes + asm_x64_mov_i64_to_r64(as, src_i64, dest_r64); + } +} + +void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_AND_R64_TO_RM64); +} + +void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_OR_R64_TO_RM64); +} + +void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64); +} + +void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64) { + asm_x64_generic_r64_r64(as, dest_r64, 4, OPCODE_SHL_RM64_CL); +} + +void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64) { + asm_x64_generic_r64_r64(as, dest_r64, 7, OPCODE_SAR_RM64_CL); +} + +void asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_ADD_R64_TO_RM64); +} + +void asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_SUB_R64_FROM_RM64); +} + +void asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) { + // imul reg64, reg/mem64 -- 0x0f 0xaf /r + asm_x64_write_byte_1(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64)); + asm_x64_write_byte_3(as, 0x0f, 0xaf, MODRM_R64(dest_r64) | MODRM_RM_REG | MODRM_RM_R64(src_r64)); +} + +/* +void asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) { + if (SIGNED_FIT8(src_i32)) { + // defaults to 32 bit operation + asm_x64_write_byte_2(as, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32)); + asm_x64_write_byte_1(as, src_i32 & 0xff); + } else { + // defaults to 32 bit operation + asm_x64_write_byte_2(as, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32)); + asm_x64_write_word32(as, src_i32); + } +} +*/ + +STATIC void asm_x64_sub_r64_i32(asm_x64_t *as, int dest_r64, int src_i32) { + assert(dest_r64 < 8); + if (SIGNED_FIT8(src_i32)) { + // use REX prefix for 64 bit operation + asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); + asm_x64_write_byte_1(as, src_i32 & 0xff); + } else { + // use REX prefix for 64 bit operation + asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64)); + asm_x64_write_word32(as, src_i32); + } +} + +/* +void asm_x64_shl_r32_by_imm(asm_x64_t *as, int r32, int imm) { + asm_x64_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(r32)); + asm_x64_write_byte_1(as, imm); +} + +void asm_x64_shr_r32_by_imm(asm_x64_t *as, int r32, int imm) { + asm_x64_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(r32)); + asm_x64_write_byte_1(as, imm); +} + +void asm_x64_sar_r32_by_imm(asm_x64_t *as, int r32, int imm) { + asm_x64_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(r32)); + asm_x64_write_byte_1(as, imm); +} +*/ + +void asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) { + asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_CMP_R64_WITH_RM64); +} + +/* +void asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) { + if (SIGNED_FIT8(src_i32)) { + asm_x64_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32)); + asm_x64_write_byte_1(as, src_i32 & 0xff); + } else { + asm_x64_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32)); + asm_x64_write_word32(as, src_i32); + } +} +*/ + +void asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b) { + assert(src_r64_a < 8); + assert(src_r64_b < 8); + asm_x64_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R64(src_r64_a) | MODRM_RM_REG | MODRM_RM_R64(src_r64_b)); +} + +void asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) { + asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_TEST_R64_WITH_RM64); +} + +void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) { + assert(dest_r8 < 8); + asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8)); +} + +void asm_x64_jmp_reg(asm_x64_t *as, int src_r64) { + assert(src_r64 < 8); + asm_x64_write_byte_2(as, OPCODE_JMP_RM64, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(src_r64)); +} + +STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) { + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; +} + +void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + if (dest != (mp_uint_t)-1 && rel < 0) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 8 bit relative jump + rel -= 2; + if (SIGNED_FIT8(rel)) { + asm_x64_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff); + } else { + rel += 2; + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + rel -= 5; + asm_x64_write_byte_1(as, OPCODE_JMP_REL32); + asm_x64_write_word32(as, rel); + } +} + +void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + if (dest != (mp_uint_t)-1 && rel < 0) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 8 bit relative jump + rel -= 2; + if (SIGNED_FIT8(rel)) { + asm_x64_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff); + } else { + rel += 2; + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + rel -= 6; + asm_x64_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type); + asm_x64_write_word32(as, rel); + } +} + +void asm_x64_entry(asm_x64_t *as, int num_locals) { + assert(num_locals >= 0); + asm_x64_push_r64(as, ASM_X64_REG_RBP); + asm_x64_push_r64(as, ASM_X64_REG_RBX); + asm_x64_push_r64(as, ASM_X64_REG_R12); + asm_x64_push_r64(as, ASM_X64_REG_R13); + num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary + asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE); + as->num_locals = num_locals; +} + +void asm_x64_exit(asm_x64_t *as) { + asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, -as->num_locals * WORD_SIZE); + asm_x64_pop_r64(as, ASM_X64_REG_R13); + asm_x64_pop_r64(as, ASM_X64_REG_R12); + asm_x64_pop_r64(as, ASM_X64_REG_RBX); + asm_x64_pop_r64(as, ASM_X64_REG_RBP); + asm_x64_ret(as); +} + +// locals: +// - stored on the stack in ascending order +// - numbered 0 through as->num_locals-1 +// - RSP points to the first local +// +// | RSP +// v +// l0 l1 l2 ... l(n-1) +// ^ ^ +// | low address | high address in RAM +// +STATIC int asm_x64_local_offset_from_rsp(asm_x64_t *as, int local_num) { + (void)as; + // Stack is full descending, RSP points to local0 + return local_num * WORD_SIZE; +} + +void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64) { + asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, src_local_num), dest_r64); +} + +void asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num) { + asm_x64_mov_r64_to_mem64(as, src_r64, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, dest_local_num)); +} + +void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) { + int offset = asm_x64_local_offset_from_rsp(as, local_num); + if (offset == 0) { + asm_x64_mov_r64_r64(as, dest_r64, ASM_X64_REG_RSP); + } else { + asm_x64_lea_disp_to_r64(as, ASM_X64_REG_RSP, offset, dest_r64); + } +} + +void asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - (as->base.code_offset + 7); + asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64), OPCODE_LEA_MEM_TO_R64, MODRM_R64(dest_r64) | MODRM_RM_R64(5)); + asm_x64_write_word32(as, rel); +} + +/* +void asm_x64_push_local(asm_x64_t *as, int local_num) { + asm_x64_push_disp(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, local_num)); +} + +void asm_x64_push_local_addr(asm_x64_t *as, int local_num, int temp_r64) { + asm_x64_mov_r64_r64(as, temp_r64, ASM_X64_REG_RSP); + asm_x64_add_i32_to_r32(as, asm_x64_local_offset_from_rsp(as, local_num), temp_r64); + asm_x64_push_r64(as, temp_r64); +} +*/ + +/* + can't use these because code might be relocated when resized + +void asm_x64_call(asm_x64_t *as, void* func) { + asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP); + asm_x64_write_byte_1(as, OPCODE_CALL_REL32); + asm_x64_write_word32(as, func - (void*)(as->code_cur + 4)); + asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP); +} + +void asm_x64_call_i1(asm_x64_t *as, void* func, int i1) { + asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP); + asm_x64_sub_i32_from_r32(as, 12, ASM_X64_REG_RSP); + asm_x64_push_i32(as, i1); + asm_x64_write_byte_1(as, OPCODE_CALL_REL32); + asm_x64_write_word32(as, func - (void*)(as->code_cur + 4)); + asm_x64_add_i32_to_r32(as, 16, ASM_X64_REG_RSP); + asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP); +} +*/ + +void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r64) { + assert(temp_r64 < 8); + asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_FUN_TABLE, fun_id * WORD_SIZE, temp_r64); + asm_x64_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R64(2) | MODRM_RM_REG | MODRM_RM_R64(temp_r64)); +} + +#endif // MICROPY_EMIT_X64 diff --git a/src/openmv/src/micropython/py/asmx64.h b/src/openmv/src/micropython/py/asmx64.h new file mode 100755 index 0000000..1c8755a --- /dev/null +++ b/src/openmv/src/micropython/py/asmx64.h @@ -0,0 +1,212 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMX64_H +#define MICROPY_INCLUDED_PY_ASMX64_H + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/asmbase.h" + +// AMD64 calling convention is: +// - args pass in: RDI, RSI, RDX, RCX, R08, R09 +// - return value in RAX +// - stack must be aligned on a 16-byte boundary before all calls +// - RAX, RCX, RDX, RSI, RDI, R08, R09, R10, R11 are caller-save +// - RBX, RBP, R12, R13, R14, R15 are callee-save + +// In the functions below, argument order follows x86 docs and generally +// the destination is the first argument. +// NOTE: this is a change from the old convention used in this file and +// some functions still use the old (reverse) convention. + +#define ASM_X64_REG_RAX (0) +#define ASM_X64_REG_RCX (1) +#define ASM_X64_REG_RDX (2) +#define ASM_X64_REG_RBX (3) +#define ASM_X64_REG_RSP (4) +#define ASM_X64_REG_RBP (5) +#define ASM_X64_REG_RSI (6) +#define ASM_X64_REG_RDI (7) +#define ASM_X64_REG_R08 (8) +#define ASM_X64_REG_R09 (9) +#define ASM_X64_REG_R10 (10) +#define ASM_X64_REG_R11 (11) +#define ASM_X64_REG_R12 (12) +#define ASM_X64_REG_R13 (13) +#define ASM_X64_REG_R14 (14) +#define ASM_X64_REG_R15 (15) + +// condition codes, used for jcc and setcc (despite their j-name!) +#define ASM_X64_CC_JB (0x2) // below, unsigned +#define ASM_X64_CC_JZ (0x4) +#define ASM_X64_CC_JE (0x4) +#define ASM_X64_CC_JNZ (0x5) +#define ASM_X64_CC_JNE (0x5) +#define ASM_X64_CC_JL (0xc) // less, signed +#define ASM_X64_CC_JGE (0xd) // greater or equal, signed +#define ASM_X64_CC_JLE (0xe) // less or equal, signed +#define ASM_X64_CC_JG (0xf) // greater, signed + +typedef struct _asm_x64_t { + mp_asm_base_t base; + int num_locals; +} asm_x64_t; + +static inline void asm_x64_end_pass(asm_x64_t *as) { + (void)as; +} + +void asm_x64_nop(asm_x64_t* as); +void asm_x64_push_r64(asm_x64_t* as, int src_r64); +void asm_x64_pop_r64(asm_x64_t* as, int dest_r64); +void asm_x64_mov_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); +void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64); +void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64); +void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); +void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); +void asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); +void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp); +void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64); +void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64); +void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64); +void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64); +void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64); +void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64); +void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64); +void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64); +void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64); +void asm_x64_add_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); +void asm_x64_sub_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); +void asm_x64_mul_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); +void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b); +void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b); +void asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b); +void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8); +void asm_x64_jmp_reg(asm_x64_t *as, int src_r64); +void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label); +void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label); +void asm_x64_entry(asm_x64_t* as, int num_locals); +void asm_x64_exit(asm_x64_t* as); +void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64); +void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num); +void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64); +void asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label); +void asm_x64_call_ind(asm_x64_t* as, size_t fun_id, int temp_r32); + +// Holds a pointer to mp_fun_table +#define ASM_X64_REG_FUN_TABLE ASM_X64_REG_RBP + +#if GENERIC_ASM_API + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (8) + +#define REG_RET ASM_X64_REG_RAX +#define REG_ARG_1 ASM_X64_REG_RDI +#define REG_ARG_2 ASM_X64_REG_RSI +#define REG_ARG_3 ASM_X64_REG_RDX +#define REG_ARG_4 ASM_X64_REG_RCX +#define REG_ARG_5 ASM_X64_REG_R08 + +// caller-save +#define REG_TEMP0 ASM_X64_REG_RAX +#define REG_TEMP1 ASM_X64_REG_RDI +#define REG_TEMP2 ASM_X64_REG_RSI + +// callee-save +#define REG_LOCAL_1 ASM_X64_REG_RBX +#define REG_LOCAL_2 ASM_X64_REG_R12 +#define REG_LOCAL_3 ASM_X64_REG_R13 +#define REG_LOCAL_NUM (3) + +// Holds a pointer to mp_fun_table +#define REG_FUN_TABLE ASM_X64_REG_FUN_TABLE + +#define ASM_T asm_x64_t +#define ASM_END_PASS asm_x64_end_pass +#define ASM_ENTRY asm_x64_entry +#define ASM_EXIT asm_x64_exit + +#define ASM_JUMP asm_x64_jmp_label +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + do { \ + if (bool_test) { \ + asm_x64_test_r8_with_r8((as), (reg), (reg)); \ + } else { \ + asm_x64_test_r64_with_r64((as), (reg), (reg)); \ + } \ + asm_x64_jcc_label(as, ASM_X64_CC_JZ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + do { \ + if (bool_test) { \ + asm_x64_test_r8_with_r8((as), (reg), (reg)); \ + } else { \ + asm_x64_test_r64_with_r64((as), (reg), (reg)); \ + } \ + asm_x64_jcc_label(as, ASM_X64_CC_JNZ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + do { \ + asm_x64_cmp_r64_with_r64(as, reg1, reg2); \ + asm_x64_jcc_label(as, ASM_X64_CC_JE, label); \ + } while (0) +#define ASM_JUMP_REG(as, reg) asm_x64_jmp_reg((as), (reg)) +#define ASM_CALL_IND(as, idx) asm_x64_call_ind(as, idx, ASM_X64_REG_RAX) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest)) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest)) +#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x64_mov_reg_pcrel((as), (reg_dest), (label)) + +#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg)) +#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg)) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x64_or_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x64_xor_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x64_and_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x64_add_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src)) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src)) + +#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (reg_dest)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 0, (reg_dest)) + +#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0) +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) + +#endif // GENERIC_ASM_API + +#endif // MICROPY_INCLUDED_PY_ASMX64_H diff --git a/src/openmv/src/micropython/py/asmx86.c b/src/openmv/src/micropython/py/asmx86.c new file mode 100755 index 0000000..8ce576a --- /dev/null +++ b/src/openmv/src/micropython/py/asmx86.c @@ -0,0 +1,526 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_X86 + +#include "py/asmx86.h" + +/* all offsets are measured in multiples of 4 bytes */ +#define WORD_SIZE (4) + +#define OPCODE_NOP (0x90) +#define OPCODE_PUSH_R32 (0x50) +//#define OPCODE_PUSH_I32 (0x68) +//#define OPCODE_PUSH_M32 (0xff) /* /6 */ +#define OPCODE_POP_R32 (0x58) +#define OPCODE_RET (0xc3) +//#define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */ +#define OPCODE_MOV_I32_TO_R32 (0xb8) +//#define OPCODE_MOV_I32_TO_RM32 (0xc7) +#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */ +#define OPCODE_MOV_R32_TO_RM32 (0x89) /* /r */ +#define OPCODE_MOV_RM32_TO_R32 (0x8b) /* /r */ +#define OPCODE_MOVZX_RM8_TO_R32 (0xb6) /* 0x0f 0xb6/r */ +#define OPCODE_MOVZX_RM16_TO_R32 (0xb7) /* 0x0f 0xb7/r */ +#define OPCODE_LEA_MEM_TO_R32 (0x8d) /* /r */ +#define OPCODE_AND_R32_TO_RM32 (0x21) /* /r */ +#define OPCODE_OR_R32_TO_RM32 (0x09) /* /r */ +#define OPCODE_XOR_R32_TO_RM32 (0x31) /* /r */ +#define OPCODE_ADD_R32_TO_RM32 (0x01) +#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */ +#define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */ +#define OPCODE_SUB_R32_FROM_RM32 (0x29) +#define OPCODE_SUB_I32_FROM_RM32 (0x81) /* /5 */ +#define OPCODE_SUB_I8_FROM_RM32 (0x83) /* /5 */ +//#define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */ +//#define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */ +//#define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */ +#define OPCODE_SHL_RM32_CL (0xd3) /* /4 */ +#define OPCODE_SAR_RM32_CL (0xd3) /* /7 */ +//#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */ +//#define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */ +#define OPCODE_CMP_R32_WITH_RM32 (0x39) +//#define OPCODE_CMP_RM32_WITH_R32 (0x3b) +#define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */ +#define OPCODE_TEST_R32_WITH_RM32 (0x85) /* /r */ +#define OPCODE_JMP_REL8 (0xeb) +#define OPCODE_JMP_REL32 (0xe9) +#define OPCODE_JMP_RM32 (0xff) /* /4 */ +#define OPCODE_JCC_REL8 (0x70) /* | jcc type */ +#define OPCODE_JCC_REL32_A (0x0f) +#define OPCODE_JCC_REL32_B (0x80) /* | jcc type */ +#define OPCODE_SETCC_RM8_A (0x0f) +#define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */ +#define OPCODE_CALL_REL32 (0xe8) +#define OPCODE_CALL_RM32 (0xff) /* /2 */ +#define OPCODE_LEAVE (0xc9) + +#define MODRM_R32(x) ((x) << 3) +#define MODRM_RM_DISP0 (0x00) +#define MODRM_RM_DISP8 (0x40) +#define MODRM_RM_DISP32 (0x80) +#define MODRM_RM_REG (0xc0) +#define MODRM_RM_R32(x) (x) + +#define OP_SIZE_PREFIX (0x66) + +#define IMM32_L0(x) ((x) & 0xff) +#define IMM32_L1(x) (((x) >> 8) & 0xff) +#define IMM32_L2(x) (((x) >> 16) & 0xff) +#define IMM32_L3(x) (((x) >> 24) & 0xff) + +#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) + +STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) { + byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1); + if (c != NULL) { + c[0] = b1; + } +} + +STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) { + byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2); + if (c != NULL) { + c[0] = b1; + c[1] = b2; + } +} + +STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) { + byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3); + if (c != NULL) { + c[0] = b1; + c[1] = b2; + c[2] = b3; + } +} + +STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) { + byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); + if (c != NULL) { + c[0] = IMM32_L0(w32); + c[1] = IMM32_L1(w32); + c[2] = IMM32_L2(w32); + c[3] = IMM32_L3(w32); + } +} + +STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) { + uint8_t rm_disp; + if (disp_offset == 0 && disp_r32 != ASM_X86_REG_EBP) { + rm_disp = MODRM_RM_DISP0; + } else if (SIGNED_FIT8(disp_offset)) { + rm_disp = MODRM_RM_DISP8; + } else { + rm_disp = MODRM_RM_DISP32; + } + asm_x86_write_byte_1(as, MODRM_R32(r32) | rm_disp | MODRM_RM_R32(disp_r32)); + if (disp_r32 == ASM_X86_REG_ESP) { + // Special case for esp, it needs a SIB byte + asm_x86_write_byte_1(as, 0x24); + } + if (rm_disp == MODRM_RM_DISP8) { + asm_x86_write_byte_1(as, IMM32_L0(disp_offset)); + } else if (rm_disp == MODRM_RM_DISP32) { + asm_x86_write_word32(as, disp_offset); + } +} + +STATIC void asm_x86_generic_r32_r32(asm_x86_t *as, int dest_r32, int src_r32, int op) { + asm_x86_write_byte_2(as, op, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); +} + +#if 0 +STATIC void asm_x86_nop(asm_x86_t *as) { + asm_x86_write_byte_1(as, OPCODE_NOP); +} +#endif + +STATIC void asm_x86_push_r32(asm_x86_t *as, int src_r32) { + asm_x86_write_byte_1(as, OPCODE_PUSH_R32 | src_r32); +} + +#if 0 +void asm_x86_push_i32(asm_x86_t *as, int src_i32) { + asm_x86_write_byte_1(as, OPCODE_PUSH_I32); + asm_x86_write_word32(as, src_i32); +} + +void asm_x86_push_disp(asm_x86_t *as, int src_r32, int src_offset) { + asm_x86_write_byte_1(as, OPCODE_PUSH_M32); + asm_x86_write_r32_disp(as, 6, src_r32, src_offset); +} +#endif + +STATIC void asm_x86_pop_r32(asm_x86_t *as, int dest_r32) { + asm_x86_write_byte_1(as, OPCODE_POP_R32 | dest_r32); +} + +STATIC void asm_x86_ret(asm_x86_t *as) { + asm_x86_write_byte_1(as, OPCODE_RET); +} + +void asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_MOV_R32_TO_RM32); +} + +void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) { + asm_x86_write_byte_1(as, OPCODE_MOV_R8_TO_RM8); + asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp); +} + +void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) { + asm_x86_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R32_TO_RM32); + asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp); +} + +void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) { + asm_x86_write_byte_1(as, OPCODE_MOV_R32_TO_RM32); + asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp); +} + +void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) { + asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R32); + asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp); +} + +void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) { + asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R32); + asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp); +} + +void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) { + asm_x86_write_byte_1(as, OPCODE_MOV_RM32_TO_R32); + asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp); +} + +STATIC void asm_x86_lea_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) { + asm_x86_write_byte_1(as, OPCODE_LEA_MEM_TO_R32); + asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp); +} + +#if 0 +void asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) { + asm_x86_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r32, src_i8); +} +#endif + +void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32) { + asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32); + asm_x86_write_word32(as, src_i32); +} + +void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_AND_R32_TO_RM32); +} + +void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_OR_R32_TO_RM32); +} + +void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_XOR_R32_TO_RM32); +} + +void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32) { + asm_x86_generic_r32_r32(as, dest_r32, 4, OPCODE_SHL_RM32_CL); +} + +void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32) { + asm_x86_generic_r32_r32(as, dest_r32, 7, OPCODE_SAR_RM32_CL); +} + +void asm_x86_add_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_ADD_R32_TO_RM32); +} + +STATIC void asm_x86_add_i32_to_r32(asm_x86_t *as, int src_i32, int dest_r32) { + if (SIGNED_FIT8(src_i32)) { + asm_x86_write_byte_2(as, OPCODE_ADD_I8_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); + asm_x86_write_byte_1(as, src_i32 & 0xff); + } else { + asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); + asm_x86_write_word32(as, src_i32); + } +} + +void asm_x86_sub_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_SUB_R32_FROM_RM32); +} + +STATIC void asm_x86_sub_r32_i32(asm_x86_t *as, int dest_r32, int src_i32) { + if (SIGNED_FIT8(src_i32)) { + // defaults to 32 bit operation + asm_x86_write_byte_2(as, OPCODE_SUB_I8_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); + asm_x86_write_byte_1(as, src_i32 & 0xff); + } else { + // defaults to 32 bit operation + asm_x86_write_byte_2(as, OPCODE_SUB_I32_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); + asm_x86_write_word32(as, src_i32); + } +} + +void asm_x86_mul_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) { + // imul reg32, reg/mem32 -- 0x0f 0xaf /r + asm_x86_write_byte_3(as, 0x0f, 0xaf, MODRM_R32(dest_r32) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); +} + +#if 0 +/* shifts not tested */ +void asm_x86_shl_r32_by_imm(asm_x86_t *as, int r32, int imm) { + asm_x86_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(r32)); + asm_x86_write_byte_1(as, imm); +} + +void asm_x86_shr_r32_by_imm(asm_x86_t *as, int r32, int imm) { + asm_x86_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(r32)); + asm_x86_write_byte_1(as, imm); +} + +void asm_x86_sar_r32_by_imm(asm_x86_t *as, int r32, int imm) { + asm_x86_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(r32)); + asm_x86_write_byte_1(as, imm); +} +#endif + +void asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) { + asm_x86_generic_r32_r32(as, src_r32_b, src_r32_a, OPCODE_CMP_R32_WITH_RM32); +} + +#if 0 +void asm_x86_cmp_i32_with_r32(asm_x86_t *as, int src_i32, int src_r32) { + if (SIGNED_FIT8(src_i32)) { + asm_x86_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); + asm_x86_write_byte_1(as, src_i32 & 0xff); + } else { + asm_x86_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); + asm_x86_write_word32(as, src_i32); + } +} +#endif + +void asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b) { + asm_x86_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R32(src_r32_a) | MODRM_RM_REG | MODRM_RM_R32(src_r32_b)); +} + +void asm_x86_test_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) { + asm_x86_generic_r32_r32(as, src_r32_b, src_r32_a, OPCODE_TEST_R32_WITH_RM32); +} + +void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) { + asm_x86_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r8)); +} + +void asm_x86_jmp_reg(asm_x86_t *as, int src_r32) { + asm_x86_write_byte_2(as, OPCODE_JMP_RM32, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(src_r32)); +} + +STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) { + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; +} + +void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + if (dest != (mp_uint_t)-1 && rel < 0) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 8 bit relative jump + rel -= 2; + if (SIGNED_FIT8(rel)) { + asm_x86_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff); + } else { + rel += 2; + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + rel -= 5; + asm_x86_write_byte_1(as, OPCODE_JMP_REL32); + asm_x86_write_word32(as, rel); + } +} + +void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) { + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + if (dest != (mp_uint_t)-1 && rel < 0) { + // is a backwards jump, so we know the size of the jump on the first pass + // calculate rel assuming 8 bit relative jump + rel -= 2; + if (SIGNED_FIT8(rel)) { + asm_x86_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff); + } else { + rel += 2; + goto large_jump; + } + } else { + // is a forwards jump, so need to assume it's large + large_jump: + rel -= 6; + asm_x86_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type); + asm_x86_write_word32(as, rel); + } +} + +void asm_x86_entry(asm_x86_t *as, int num_locals) { + assert(num_locals >= 0); + asm_x86_push_r32(as, ASM_X86_REG_EBP); + asm_x86_push_r32(as, ASM_X86_REG_EBX); + asm_x86_push_r32(as, ASM_X86_REG_ESI); + asm_x86_push_r32(as, ASM_X86_REG_EDI); + num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary + asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, num_locals * WORD_SIZE); + as->num_locals = num_locals; +} + +void asm_x86_exit(asm_x86_t *as) { + asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, -as->num_locals * WORD_SIZE); + asm_x86_pop_r32(as, ASM_X86_REG_EDI); + asm_x86_pop_r32(as, ASM_X86_REG_ESI); + asm_x86_pop_r32(as, ASM_X86_REG_EBX); + asm_x86_pop_r32(as, ASM_X86_REG_EBP); + asm_x86_ret(as); +} + +STATIC int asm_x86_arg_offset_from_esp(asm_x86_t *as, size_t arg_num) { + // Above esp are: locals, 4 saved registers, return eip, arguments + return (as->num_locals + 4 + 1 + arg_num) * WORD_SIZE; +} + +#if 0 +void asm_x86_push_arg(asm_x86_t *as, int src_arg_num) { + asm_x86_push_disp(as, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, src_arg_num)); +} +#endif + +void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32) { + asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, src_arg_num), dest_r32); +} + +#if 0 +void asm_x86_mov_r32_to_arg(asm_x86_t *as, int src_r32, int dest_arg_num) { + asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_ESP, asm_x86_arg_offset_from_esp(as, dest_arg_num)); +} +#endif + +// locals: +// - stored on the stack in ascending order +// - numbered 0 through as->num_locals-1 +// - ESP points to the first local +// +// | ESP +// v +// l0 l1 l2 ... l(n-1) +// ^ ^ +// | low address | high address in RAM +// +STATIC int asm_x86_local_offset_from_esp(asm_x86_t *as, int local_num) { + (void)as; + // Stack is full descending, ESP points to local0 + return local_num * WORD_SIZE; +} + +void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32) { + asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, src_local_num), dest_r32); +} + +void asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num) { + asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, dest_local_num)); +} + +void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) { + int offset = asm_x86_local_offset_from_esp(as, local_num); + if (offset == 0) { + asm_x86_mov_r32_r32(as, dest_r32, ASM_X86_REG_ESP); + } else { + asm_x86_lea_disp_to_r32(as, ASM_X86_REG_ESP, offset, dest_r32); + } +} + +void asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r32, mp_uint_t label) { + asm_x86_write_byte_1(as, OPCODE_CALL_REL32); + asm_x86_write_word32(as, 0); + mp_uint_t dest = get_label_dest(as, label); + mp_int_t rel = dest - as->base.code_offset; + asm_x86_pop_r32(as, dest_r32); + // PC rel is usually a forward reference, so need to assume it's large + asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32)); + asm_x86_write_word32(as, rel); +} + +#if 0 +void asm_x86_push_local(asm_x86_t *as, int local_num) { + asm_x86_push_disp(as, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, local_num)); +} + +void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) +{ + asm_x86_mov_r32_r32(as, temp_r32, ASM_X86_REG_ESP); + asm_x86_add_i32_to_r32(as, asm_x86_local_offset_from_esp(as, local_num), temp_r32); + asm_x86_push_r32(as, temp_r32); +} +#endif + +void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32) { + // TODO align stack on 16-byte boundary before the call + assert(n_args <= 5); + if (n_args > 4) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_5); + } + if (n_args > 3) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_4); + } + if (n_args > 2) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_3); + } + if (n_args > 1) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_2); + } + if (n_args > 0) { + asm_x86_push_r32(as, ASM_X86_REG_ARG_1); + } + + // Load the pointer to the function and make the call + asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_FUN_TABLE, fun_id * WORD_SIZE, temp_r32); + asm_x86_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R32(2) | MODRM_RM_REG | MODRM_RM_R32(temp_r32)); + + // the caller must clean up the stack + if (n_args > 0) { + asm_x86_add_i32_to_r32(as, WORD_SIZE * n_args, ASM_X86_REG_ESP); + } +} + +#endif // MICROPY_EMIT_X86 diff --git a/src/openmv/src/micropython/py/asmx86.h b/src/openmv/src/micropython/py/asmx86.h new file mode 100755 index 0000000..82a8629 --- /dev/null +++ b/src/openmv/src/micropython/py/asmx86.h @@ -0,0 +1,210 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMX86_H +#define MICROPY_INCLUDED_PY_ASMX86_H + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/asmbase.h" + +// x86 cdecl calling convention is: +// - args passed on the stack in reverse order +// - return value in EAX +// - caller cleans up the stack after a call +// - stack must be aligned to 16-byte boundary before all calls +// - EAX, ECX, EDX are caller-save +// - EBX, ESI, EDI, EBP, ESP, EIP are callee-save + +// In the functions below, argument order follows x86 docs and generally +// the destination is the first argument. +// NOTE: this is a change from the old convention used in this file and +// some functions still use the old (reverse) convention. + +#define ASM_X86_REG_EAX (0) +#define ASM_X86_REG_ECX (1) +#define ASM_X86_REG_EDX (2) +#define ASM_X86_REG_EBX (3) +#define ASM_X86_REG_ESP (4) +#define ASM_X86_REG_EBP (5) +#define ASM_X86_REG_ESI (6) +#define ASM_X86_REG_EDI (7) + +// x86 passes values on the stack, but the emitter is register based, so we need +// to define registers that can temporarily hold the function arguments. They +// need to be defined here so that asm_x86_call_ind can push them onto the stack +// before the call. +#define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX +#define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX +#define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX +#define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX +#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI + +// condition codes, used for jcc and setcc (despite their j-name!) +#define ASM_X86_CC_JB (0x2) // below, unsigned +#define ASM_X86_CC_JZ (0x4) +#define ASM_X86_CC_JE (0x4) +#define ASM_X86_CC_JNZ (0x5) +#define ASM_X86_CC_JNE (0x5) +#define ASM_X86_CC_JL (0xc) // less, signed +#define ASM_X86_CC_JGE (0xd) // greater or equal, signed +#define ASM_X86_CC_JLE (0xe) // less or equal, signed +#define ASM_X86_CC_JG (0xf) // greater, signed + +typedef struct _asm_x86_t { + mp_asm_base_t base; + int num_locals; +} asm_x86_t; + +static inline void asm_x86_end_pass(asm_x86_t *as) { + (void)as; +} + +void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); +void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32); +void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); +void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); +void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp); +void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32); +void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32); +void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32); +void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32); +void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32); +void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32); +void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32); +void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32); +void asm_x86_add_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); +void asm_x86_sub_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); +void asm_x86_mul_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); +void asm_x86_cmp_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b); +void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b); +void asm_x86_test_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b); +void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8); +void asm_x86_jmp_reg(asm_x86_t *as, int src_r86); +void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label); +void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label); +void asm_x86_entry(asm_x86_t* as, int num_locals); +void asm_x86_exit(asm_x86_t* as); +void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32); +void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32); +void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num); +void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32); +void asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r64, mp_uint_t label); +void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r32); + +// Holds a pointer to mp_fun_table +#define ASM_X86_REG_FUN_TABLE ASM_X86_REG_EBP + +#if GENERIC_ASM_API + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (4) + +#define REG_RET ASM_X86_REG_EAX +#define REG_ARG_1 ASM_X86_REG_ARG_1 +#define REG_ARG_2 ASM_X86_REG_ARG_2 +#define REG_ARG_3 ASM_X86_REG_ARG_3 +#define REG_ARG_4 ASM_X86_REG_ARG_4 +#define REG_ARG_5 ASM_X86_REG_ARG_5 + +// caller-save, so can be used as temporaries +#define REG_TEMP0 ASM_X86_REG_EAX +#define REG_TEMP1 ASM_X86_REG_ECX +#define REG_TEMP2 ASM_X86_REG_EDX + +// callee-save, so can be used as locals +#define REG_LOCAL_1 ASM_X86_REG_EBX +#define REG_LOCAL_2 ASM_X86_REG_ESI +#define REG_LOCAL_3 ASM_X86_REG_EDI +#define REG_LOCAL_NUM (3) + +// Holds a pointer to mp_fun_table +#define REG_FUN_TABLE ASM_X86_REG_FUN_TABLE + +#define ASM_T asm_x86_t +#define ASM_END_PASS asm_x86_end_pass +#define ASM_ENTRY asm_x86_entry +#define ASM_EXIT asm_x86_exit + +#define ASM_JUMP asm_x86_jmp_label +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + do { \ + if (bool_test) { \ + asm_x86_test_r8_with_r8(as, reg, reg); \ + } else { \ + asm_x86_test_r32_with_r32(as, reg, reg); \ + } \ + asm_x86_jcc_label(as, ASM_X86_CC_JZ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + do { \ + if (bool_test) { \ + asm_x86_test_r8_with_r8(as, reg, reg); \ + } else { \ + asm_x86_test_r32_with_r32(as, reg, reg); \ + } \ + asm_x86_jcc_label(as, ASM_X86_CC_JNZ, label); \ + } while (0) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + do { \ + asm_x86_cmp_r32_with_r32(as, reg1, reg2); \ + asm_x86_jcc_label(as, ASM_X86_CC_JE, label); \ + } while (0) +#define ASM_JUMP_REG(as, reg) asm_x86_jmp_reg((as), (reg)) +#define ASM_CALL_IND(as, idx) asm_x86_call_ind(as, idx, mp_f_n_args[idx], ASM_X86_REG_EAX) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest)) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest)) +#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x86_mov_reg_pcrel((as), (reg_dest), (label)) + +#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg)) +#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg)) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x86_or_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x86_xor_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_x86_and_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_x86_add_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src)) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src)) + +#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (reg_dest)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) + +#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) + +#endif // GENERIC_ASM_API + +#endif // MICROPY_INCLUDED_PY_ASMX86_H diff --git a/src/openmv/src/micropython/py/asmxtensa.c b/src/openmv/src/micropython/py/asmxtensa.c new file mode 100755 index 0000000..8da56ff --- /dev/null +++ b/src/openmv/src/micropython/py/asmxtensa.c @@ -0,0 +1,223 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA + +#include "py/asmxtensa.h" + +#define WORD_SIZE (4) +#define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) +#define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) +#define NUM_REGS_SAVED (5) + +void asm_xtensa_end_pass(asm_xtensa_t *as) { + as->num_const = as->cur_const; + as->cur_const = 0; + + #if 0 + // make a hex dump of the machine code + if (as->base.pass == MP_ASM_PASS_EMIT) { + uint8_t *d = as->base.code_base; + printf("XTENSA ASM:"); + for (int i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { + if (i % 16 == 0) { + printf("\n%08x:", (uint32_t)&d[i]); + } + if (i % 2 == 0) { + printf(" "); + } + printf("%02x", d[i]); + } + printf("\n"); + } + #endif +} + +void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + + // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned + as->stack_adjust = (((NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; + if (SIGNED_FIT8(-as->stack_adjust)) { + asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust); + } else { + asm_xtensa_op_movi(as, ASM_XTENSA_REG_A9, as->stack_adjust); + asm_xtensa_op_sub(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A9); + } + + // save return value (a0) and callee-save registers (a12, a13, a14, a15) + asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); + for (int i = 1; i < NUM_REGS_SAVED; ++i) { + asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); + } +} + +void asm_xtensa_exit(asm_xtensa_t *as) { + // restore registers + for (int i = NUM_REGS_SAVED - 1; i >= 1; --i) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i); + } + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0); + + // restore stack-pointer and return + if (SIGNED_FIT8(as->stack_adjust)) { + asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, as->stack_adjust); + } else { + asm_xtensa_op_movi(as, ASM_XTENSA_REG_A9, as->stack_adjust); + asm_xtensa_op_add_n(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A9); + } + + asm_xtensa_op_ret_n(as); +} + +STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) { + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; +} + +void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op) { + uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2); + if (c != NULL) { + c[0] = op; + c[1] = op >> 8; + } +} + +void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op) { + uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3); + if (c != NULL) { + c[0] = op; + c[1] = op >> 8; + c[2] = op >> 16; + } +} + +void asm_xtensa_j_label(asm_xtensa_t *as, uint label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 4; + // we assume rel, as a signed int, fits in 18-bits + asm_xtensa_op_j(as, rel); +} + +void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 4; + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) { + printf("ERROR: xtensa bccz out of range\n"); + } + asm_xtensa_op_bccz(as, cond, reg, rel); +} + +void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 4; + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { + printf("ERROR: xtensa bcc out of range\n"); + } + asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); +} + +// convenience function; reg_dest must be different from reg_src[12] +void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2) { + asm_xtensa_op_movi_n(as, reg_dest, 1); + asm_xtensa_op_bcc(as, cond, reg_src1, reg_src2, 1); + asm_xtensa_op_movi_n(as, reg_dest, 0); +} + +void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { + if (SIGNED_FIT12(i32)) { + asm_xtensa_op_movi(as, reg_dest, i32); + } else { + // load the constant + uint32_t const_table_offset = (uint8_t*)as->const_table - as->base.code_base; + asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, const_table_offset + as->cur_const * WORD_SIZE); + // store the constant in the table + if (as->const_table != NULL) { + as->const_table[as->cur_const] = i32; + } + ++as->cur_const; + } +} + +void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) { + asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); +} + +void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) { + asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num); +} + +void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) { + uint off = (NUM_REGS_SAVED + local_num) * WORD_SIZE; + if (SIGNED_FIT8(off)) { + asm_xtensa_op_addi(as, reg_dest, ASM_XTENSA_REG_A1, off); + } else { + asm_xtensa_op_movi(as, reg_dest, off); + asm_xtensa_op_add_n(as, reg_dest, reg_dest, ASM_XTENSA_REG_A1); + } +} + +void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label) { + // Get relative offset from PC + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset; + rel -= 3 + 3; // account for 3 bytes of movi instruction, 3 bytes call0 adjustment + asm_xtensa_op_movi(as, reg_dest, rel); // imm has 12-bit range + + // Use call0 to get PC+3 into a0 + // call0 destination must be aligned on 4 bytes: + // - code_offset&3=0: off=0, pad=1 + // - code_offset&3=1: off=0, pad=0 + // - code_offset&3=2: off=1, pad=3 + // - code_offset&3=3: off=1, pad=2 + uint32_t off = as->base.code_offset >> 1 & 1; + uint32_t pad = (5 - as->base.code_offset) & 3; + asm_xtensa_op_call0(as, off); + mp_asm_base_get_cur_to_write_bytes(&as->base, pad); + + // Add PC to relative offset + asm_xtensa_op_add_n(as, reg_dest, reg_dest, ASM_XTENSA_REG_A0); +} + +void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx) { + if (idx < 16) { + asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_FUN_TABLE, idx); + } else { + asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_FUN_TABLE, idx); + } + asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); +} + +#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA diff --git a/src/openmv/src/micropython/py/asmxtensa.h b/src/openmv/src/micropython/py/asmxtensa.h new file mode 100755 index 0000000..a595dc2 --- /dev/null +++ b/src/openmv/src/micropython/py/asmxtensa.h @@ -0,0 +1,327 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMXTENSA_H +#define MICROPY_INCLUDED_PY_ASMXTENSA_H + +#include "py/asmbase.h" + +// calling conventions: +// up to 6 args in a2-a7 +// return value in a2 +// PC stored in a0 +// stack pointer is a1, stack full descending, is aligned to 16 bytes +// callee save: a1, a12, a13, a14, a15 +// caller save: a3 + +#define ASM_XTENSA_REG_A0 (0) +#define ASM_XTENSA_REG_A1 (1) +#define ASM_XTENSA_REG_A2 (2) +#define ASM_XTENSA_REG_A3 (3) +#define ASM_XTENSA_REG_A4 (4) +#define ASM_XTENSA_REG_A5 (5) +#define ASM_XTENSA_REG_A6 (6) +#define ASM_XTENSA_REG_A7 (7) +#define ASM_XTENSA_REG_A8 (8) +#define ASM_XTENSA_REG_A9 (9) +#define ASM_XTENSA_REG_A10 (10) +#define ASM_XTENSA_REG_A11 (11) +#define ASM_XTENSA_REG_A12 (12) +#define ASM_XTENSA_REG_A13 (13) +#define ASM_XTENSA_REG_A14 (14) +#define ASM_XTENSA_REG_A15 (15) + +// for bccz +#define ASM_XTENSA_CCZ_EQ (0) +#define ASM_XTENSA_CCZ_NE (1) + +// for bcc and setcc +#define ASM_XTENSA_CC_NONE (0) +#define ASM_XTENSA_CC_EQ (1) +#define ASM_XTENSA_CC_LT (2) +#define ASM_XTENSA_CC_LTU (3) +#define ASM_XTENSA_CC_ALL (4) +#define ASM_XTENSA_CC_BC (5) +#define ASM_XTENSA_CC_ANY (8) +#define ASM_XTENSA_CC_NE (9) +#define ASM_XTENSA_CC_GE (10) +#define ASM_XTENSA_CC_GEU (11) +#define ASM_XTENSA_CC_NALL (12) +#define ASM_XTENSA_CC_BS (13) + +// macros for encoding instructions (little endian versions) +#define ASM_XTENSA_ENCODE_RRR(op0, op1, op2, r, s, t) \ + ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RRI4(op0, op1, r, s, t, imm4) \ + (((imm4) << 20) | ((op1) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RRI8(op0, r, s, t, imm8) \ + ((((uint32_t)imm8) << 16) | ((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RI16(op0, t, imm16) \ + (((imm16) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RSR(op0, op1, op2, rs, t) \ + (((op2) << 20) | ((op1) << 16) | ((rs) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_CALL(op0, n, offset) \ + (((offset) << 6) | ((n) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_CALLX(op0, op1, op2, r, s, m, n) \ + ((((uint32_t)op2) << 20) | (((uint32_t)op1) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_BRI8(op0, r, s, m, n, imm8) \ + (((imm8) << 16) | ((r) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_BRI12(op0, s, m, n, imm12) \ + (((imm12) << 12) | ((s) << 8) | ((m) << 6) | ((n) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RRRN(op0, r, s, t) \ + (((r) << 12) | ((s) << 8) | ((t) << 4) | (op0)) +#define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \ + ((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0)) + +typedef struct _asm_xtensa_t { + mp_asm_base_t base; + uint32_t cur_const; + uint32_t num_const; + uint32_t *const_table; + uint32_t stack_adjust; +} asm_xtensa_t; + +void asm_xtensa_end_pass(asm_xtensa_t *as); + +void asm_xtensa_entry(asm_xtensa_t *as, int num_locals); +void asm_xtensa_exit(asm_xtensa_t *as); + +void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op); +void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op); + +// raw instructions + +static inline void asm_xtensa_op_add_n(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(10, reg_dest, reg_src_a, reg_src_b)); +} + +static inline void asm_xtensa_op_addi(asm_xtensa_t *as, uint reg_dest, uint reg_src, int imm8) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 12, reg_src, reg_dest, imm8 & 0xff)); +} + +static inline void asm_xtensa_op_and(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 1, reg_dest, reg_src_a, reg_src_b)); +} + +static inline void asm_xtensa_op_bcc(asm_xtensa_t *as, uint cond, uint reg_src1, uint reg_src2, int32_t rel8) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, cond, reg_src1, reg_src2, rel8 & 0xff)); +} + +static inline void asm_xtensa_op_bccz(asm_xtensa_t *as, uint cond, uint reg_src, int32_t rel12) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, cond, 1, rel12 & 0xfff)); +} + +static inline void asm_xtensa_op_call0(asm_xtensa_t *as, int32_t rel18) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(5, 0, rel18 & 0x3ffff)); +} + +static inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0)); +} + +static inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff)); +} + +static inline void asm_xtensa_op_jx(asm_xtensa_t *as, uint reg) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 2, 2)); +} + +static inline void asm_xtensa_op_l8ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint byte_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0, reg_base, reg_dest, byte_offset & 0xff)); +} + +static inline void asm_xtensa_op_l16ui(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint half_word_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 1, reg_base, reg_dest, half_word_offset & 0xff)); +} + +static inline void asm_xtensa_op_l32i(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 2, reg_base, reg_dest, word_offset & 0xff)); +} + +static inline void asm_xtensa_op_l32i_n(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(8, word_offset & 0xf, reg_base, reg_dest)); +} + +static inline void asm_xtensa_op_l32r(asm_xtensa_t *as, uint reg_dest, uint32_t op_off, uint32_t dest_off) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RI16(1, reg_dest, ((dest_off - ((op_off + 3) & ~3)) >> 2) & 0xffff)); +} + +static inline void asm_xtensa_op_mov_n(asm_xtensa_t *as, uint reg_dest, uint reg_src) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 0, reg_src, reg_dest)); +} + +static inline void asm_xtensa_op_movi(asm_xtensa_t *as, uint reg_dest, int32_t imm12) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 10, (imm12 >> 8) & 0xf, reg_dest, imm12 & 0xff)); +} + +static inline void asm_xtensa_op_movi_n(asm_xtensa_t *as, uint reg_dest, int imm4) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RI7(12, reg_dest, imm4)); +} + +static inline void asm_xtensa_op_mull(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 2, 8, reg_dest, reg_src_a, reg_src_b)); +} + +static inline void asm_xtensa_op_or(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 2, reg_dest, reg_src_a, reg_src_b)); +} + +static inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0)); +} + +static inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff)); +} + +static inline void asm_xtensa_op_s16i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint half_word_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 5, reg_base, reg_src, half_word_offset & 0xff)); +} + +static inline void asm_xtensa_op_s32i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 6, reg_base, reg_src, word_offset & 0xff)); +} + +static inline void asm_xtensa_op_s32i_n(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { + asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(9, word_offset & 0xf, reg_base, reg_src)); +} + +static inline void asm_xtensa_op_sll(asm_xtensa_t *as, uint reg_dest, uint reg_src) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, reg_dest, reg_src, 0)); +} + +static inline void asm_xtensa_op_sra(asm_xtensa_t *as, uint reg_dest, uint reg_src) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, reg_dest, 0, reg_src)); +} + +static inline void asm_xtensa_op_ssl(asm_xtensa_t *as, uint reg_src) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 1, reg_src, 0)); +} + +static inline void asm_xtensa_op_ssr(asm_xtensa_t *as, uint reg_src) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 0, reg_src, 0)); +} + +static inline void asm_xtensa_op_sub(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 12, reg_dest, reg_src_a, reg_src_b)); +} + +static inline void asm_xtensa_op_xor(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 0, 3, reg_dest, reg_src_a, reg_src_b)); +} + +// convenience functions +void asm_xtensa_j_label(asm_xtensa_t *as, uint label); +void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label); +void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label); +void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, uint reg_src1, uint reg_src2); +void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32); +void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); +void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); +void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); +void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); +void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); + +// Holds a pointer to mp_fun_table +#define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15 + +#if GENERIC_ASM_API + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (4) + +#define REG_RET ASM_XTENSA_REG_A2 +#define REG_ARG_1 ASM_XTENSA_REG_A2 +#define REG_ARG_2 ASM_XTENSA_REG_A3 +#define REG_ARG_3 ASM_XTENSA_REG_A4 +#define REG_ARG_4 ASM_XTENSA_REG_A5 +#define REG_ARG_5 ASM_XTENSA_REG_A6 + +#define REG_TEMP0 ASM_XTENSA_REG_A2 +#define REG_TEMP1 ASM_XTENSA_REG_A3 +#define REG_TEMP2 ASM_XTENSA_REG_A4 + +#define REG_LOCAL_1 ASM_XTENSA_REG_A12 +#define REG_LOCAL_2 ASM_XTENSA_REG_A13 +#define REG_LOCAL_3 ASM_XTENSA_REG_A14 +#define REG_LOCAL_NUM (3) + +#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE + +#define ASM_T asm_xtensa_t +#define ASM_END_PASS asm_xtensa_end_pass +#define ASM_ENTRY asm_xtensa_entry +#define ASM_EXIT asm_xtensa_exit + +#define ASM_JUMP asm_xtensa_j_label +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_EQ, reg, label) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + asm_xtensa_bccz_reg_label(as, ASM_XTENSA_CCZ_NE, reg, label) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label) +#define ASM_JUMP_REG(as, reg) asm_xtensa_op_jx((as), (reg)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) +#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_xtensa_mov_reg_pcrel((as), (reg_dest), (label)) + +#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ + do { \ + asm_xtensa_op_ssl((as), (reg_shift)); \ + asm_xtensa_op_sll((as), (reg_dest), (reg_dest)); \ + } while (0) +#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) \ + do { \ + asm_xtensa_op_ssr((as), (reg_shift)); \ + asm_xtensa_op_sra((as), (reg_dest), (reg_dest)); \ + } while (0) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_or((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_xor((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_and((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_add_n((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_sub((as), (reg_dest), (reg_dest), (reg_src)) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src)) + +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_op_s32i_n((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0) + +#endif // GENERIC_ASM_API + +#endif // MICROPY_INCLUDED_PY_ASMXTENSA_H diff --git a/src/openmv/src/micropython/py/bc.c b/src/openmv/src/micropython/py/bc.c new file mode 100755 index 0000000..89d8b74 --- /dev/null +++ b/src/openmv/src/micropython/py/bc.c @@ -0,0 +1,415 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/bc0.h" +#include "py/bc.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +mp_uint_t mp_decode_uint(const byte **ptr) { + mp_uint_t unum = 0; + byte val; + const byte *p = *ptr; + do { + val = *p++; + unum = (unum << 7) | (val & 0x7f); + } while ((val & 0x80) != 0); + *ptr = p; + return unum; +} + +// This function is used to help reduce stack usage at the caller, for the case when +// the caller doesn't need to increase the ptr argument. If ptr is a local variable +// and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler +// must allocate a slot on the stack for ptr, and this slot cannot be reused for +// anything else in the function because the pointer may have been stored in a global +// and reused later in the function. +mp_uint_t mp_decode_uint_value(const byte *ptr) { + return mp_decode_uint(&ptr); +} + +// This function is used to help reduce stack usage at the caller, for the case when +// the caller doesn't need the actual value and just wants to skip over it. +const byte *mp_decode_uint_skip(const byte *ptr) { + while ((*ptr++) & 0x80) { + } + return ptr; +} + +STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE + // generic message, used also for other argument issues + (void)f; + (void)expected; + (void)given; + mp_arg_error_terse_mismatch(); +#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL + (void)f; + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function takes %d positional arguments but %d were given", expected, given)); +#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "%q() takes %d positional arguments but %d were given", + mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given)); +#endif +} + +#if DEBUG_PRINT +STATIC void dump_args(const mp_obj_t *a, size_t sz) { + DEBUG_printf("%p: ", a); + for (size_t i = 0; i < sz; i++) { + DEBUG_printf("%p ", a[i]); + } + DEBUG_printf("\n"); +} +#else +#define dump_args(...) (void)0 +#endif + +// On entry code_state should be allocated somewhere (stack/heap) and +// contain the following valid entries: +// - code_state->fun_bc should contain a pointer to the function object +// - code_state->ip should contain the offset in bytes from the pointer +// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native) +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // This function is pretty complicated. It's main aim is to be efficient in speed and RAM + // usage for the common case of positional only args. + + // get the function object that we want to set up (could be bytecode or native code) + mp_obj_fun_bc_t *self = code_state->fun_bc; + + // ip comes in as an offset into bytecode, so turn it into a true pointer + code_state->ip = self->bytecode + (size_t)code_state->ip; + + #if MICROPY_STACKLESS + code_state->prev = NULL; + #endif + + // get params + size_t n_state = mp_decode_uint(&code_state->ip); + code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack + size_t scope_flags = *code_state->ip++; + size_t n_pos_args = *code_state->ip++; + size_t n_kwonly_args = *code_state->ip++; + size_t n_def_pos_args = *code_state->ip++; + + code_state->sp = &code_state->state[0] - 1; + code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1; + + // zero out the local stack to begin with + memset(code_state->state, 0, n_state * sizeof(*code_state->state)); + + const mp_obj_t *kwargs = args + n_args; + + // var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed) + mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - n_pos_args - n_kwonly_args]; + + // check positional arguments + + if (n_args > n_pos_args) { + // given more than enough arguments + if ((scope_flags & MP_SCOPE_FLAG_VARARGS) == 0) { + fun_pos_args_mismatch(self, n_pos_args, n_args); + } + // put extra arguments in varargs tuple + *var_pos_kw_args-- = mp_obj_new_tuple(n_args - n_pos_args, args + n_pos_args); + n_args = n_pos_args; + } else { + if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) { + DEBUG_printf("passing empty tuple as *args\n"); + *var_pos_kw_args-- = mp_const_empty_tuple; + } + // Apply processing and check below only if we don't have kwargs, + // otherwise, kw handling code below has own extensive checks. + if (n_kw == 0 && (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) == 0) { + if (n_args >= (size_t)(n_pos_args - n_def_pos_args)) { + // given enough arguments, but may need to use some default arguments + for (size_t i = n_args; i < n_pos_args; i++) { + code_state->state[n_state - 1 - i] = self->extra_args[i - (n_pos_args - n_def_pos_args)]; + } + } else { + fun_pos_args_mismatch(self, n_pos_args - n_def_pos_args, n_args); + } + } + } + + // copy positional args into state + for (size_t i = 0; i < n_args; i++) { + code_state->state[n_state - 1 - i] = args[i]; + } + + // check keyword arguments + + if (n_kw != 0 || (scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { + DEBUG_printf("Initial args: "); + dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + + mp_obj_t dict = MP_OBJ_NULL; + if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { + dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0? + *var_pos_kw_args = dict; + } + + // get pointer to arg_names array + const mp_obj_t *arg_names = (const mp_obj_t*)self->const_table; + + for (size_t i = 0; i < n_kw; i++) { + // the keys in kwargs are expected to be qstr objects + mp_obj_t wanted_arg_name = kwargs[2 * i]; + for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) { + if (wanted_arg_name == arg_names[j]) { + if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function got multiple values for argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); + } + code_state->state[n_state - 1 - j] = kwargs[2 * i + 1]; + goto continue2; + } + } + // Didn't find name match with positional args + if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("unexpected keyword argument"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "unexpected keyword argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); + } + } + mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); +continue2:; + } + + DEBUG_printf("Args with kws flattened: "); + dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + + // fill in defaults for positional args + mp_obj_t *d = &code_state->state[n_state - n_pos_args]; + mp_obj_t *s = &self->extra_args[n_def_pos_args - 1]; + for (size_t i = n_def_pos_args; i > 0; i--, d++, s--) { + if (*d == MP_OBJ_NULL) { + *d = *s; + } + } + + DEBUG_printf("Args after filling default positional: "); + dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + + // Check that all mandatory positional args are specified + while (d < &code_state->state[n_state]) { + if (*d++ == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function missing required positional argument #%d", &code_state->state[n_state] - d)); + } + } + + // Check that all mandatory keyword args are specified + // Fill in default kw args if we have them + for (size_t i = 0; i < n_kwonly_args; i++) { + if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) { + mp_map_elem_t *elem = NULL; + if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) { + elem = mp_map_lookup(&((mp_obj_dict_t*)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP); + } + if (elem != NULL) { + code_state->state[n_state - 1 - n_pos_args - i] = elem->value; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]))); + } + } + } + + } else { + // no keyword arguments given + if (n_kwonly_args != 0) { + mp_raise_TypeError("function missing keyword-only argument"); + } + if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { + *var_pos_kw_args = mp_obj_new_dict(0); + } + } + + // get the ip and skip argument names + const byte *ip = code_state->ip; + + // jump over code info (source file and line-number mapping) + ip += mp_decode_uint_value(ip); + + // bytecode prelude: initialise closed over variables + size_t local_num; + while ((local_num = *ip++) != 255) { + code_state->state[n_state - 1 - local_num] = + mp_obj_new_cell(code_state->state[n_state - 1 - local_num]); + } + + // now that we skipped over the prelude, set the ip for the VM + code_state->ip = ip; + + DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", n_pos_args, n_kwonly_args); + dump_args(code_state->state + n_state - n_pos_args - n_kwonly_args, n_pos_args + n_kwonly_args); + dump_args(code_state->state, n_state); +} + +#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE + +// The following table encodes the number of bytes that a specific opcode +// takes up. There are 3 special opcodes that always have an extra byte: +// MP_BC_MAKE_CLOSURE +// MP_BC_MAKE_CLOSURE_DEFARGS +// MP_BC_RAISE_VARARGS +// There are 4 special opcodes that have an extra byte only when +// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled: +// MP_BC_LOAD_NAME +// MP_BC_LOAD_GLOBAL +// MP_BC_LOAD_ATTR +// MP_BC_STORE_ATTR +#define OC4(a, b, c, d) (a | (b << 2) | (c << 4) | (d << 6)) +#define U (0) // undefined opcode +#define B (MP_OPCODE_BYTE) // single byte +#define Q (MP_OPCODE_QSTR) // single byte plus 2-byte qstr +#define V (MP_OPCODE_VAR_UINT) // single byte plus variable encoded unsigned int +#define O (MP_OPCODE_OFFSET) // single byte plus 2-byte bytecode offset +STATIC const byte opcode_format_table[64] = { + OC4(U, U, U, U), // 0x00-0x03 + OC4(U, U, U, U), // 0x04-0x07 + OC4(U, U, U, U), // 0x08-0x0b + OC4(U, U, U, U), // 0x0c-0x0f + OC4(B, B, B, U), // 0x10-0x13 + OC4(V, U, Q, V), // 0x14-0x17 + OC4(B, V, V, Q), // 0x18-0x1b + OC4(Q, Q, Q, Q), // 0x1c-0x1f + OC4(B, B, V, V), // 0x20-0x23 + OC4(Q, Q, Q, B), // 0x24-0x27 + OC4(V, V, Q, Q), // 0x28-0x2b + OC4(U, U, U, U), // 0x2c-0x2f + OC4(B, B, B, B), // 0x30-0x33 + OC4(B, O, O, O), // 0x34-0x37 + OC4(O, O, U, U), // 0x38-0x3b + OC4(U, O, B, O), // 0x3c-0x3f + OC4(O, B, B, O), // 0x40-0x43 + OC4(B, B, O, B), // 0x44-0x47 + OC4(U, U, U, U), // 0x48-0x4b + OC4(U, U, U, U), // 0x4c-0x4f + OC4(V, V, U, V), // 0x50-0x53 + OC4(B, U, V, V), // 0x54-0x57 + OC4(V, V, V, B), // 0x58-0x5b + OC4(B, B, B, U), // 0x5c-0x5f + OC4(V, V, V, V), // 0x60-0x63 + OC4(V, V, V, V), // 0x64-0x67 + OC4(Q, Q, B, U), // 0x68-0x6b + OC4(U, U, U, U), // 0x6c-0x6f + + OC4(B, B, B, B), // 0x70-0x73 + OC4(B, B, B, B), // 0x74-0x77 + OC4(B, B, B, B), // 0x78-0x7b + OC4(B, B, B, B), // 0x7c-0x7f + OC4(B, B, B, B), // 0x80-0x83 + OC4(B, B, B, B), // 0x84-0x87 + OC4(B, B, B, B), // 0x88-0x8b + OC4(B, B, B, B), // 0x8c-0x8f + OC4(B, B, B, B), // 0x90-0x93 + OC4(B, B, B, B), // 0x94-0x97 + OC4(B, B, B, B), // 0x98-0x9b + OC4(B, B, B, B), // 0x9c-0x9f + OC4(B, B, B, B), // 0xa0-0xa3 + OC4(B, B, B, B), // 0xa4-0xa7 + OC4(B, B, B, B), // 0xa8-0xab + OC4(B, B, B, B), // 0xac-0xaf + + OC4(B, B, B, B), // 0xb0-0xb3 + OC4(B, B, B, B), // 0xb4-0xb7 + OC4(B, B, B, B), // 0xb8-0xbb + OC4(B, B, B, B), // 0xbc-0xbf + + OC4(B, B, B, B), // 0xc0-0xc3 + OC4(B, B, B, B), // 0xc4-0xc7 + OC4(B, B, B, B), // 0xc8-0xcb + OC4(B, B, B, B), // 0xcc-0xcf + + OC4(B, B, B, B), // 0xd0-0xd3 + OC4(U, U, U, B), // 0xd4-0xd7 + OC4(B, B, B, B), // 0xd8-0xdb + OC4(B, B, B, B), // 0xdc-0xdf + + OC4(B, B, B, B), // 0xe0-0xe3 + OC4(B, B, B, B), // 0xe4-0xe7 + OC4(B, B, B, B), // 0xe8-0xeb + OC4(B, B, B, B), // 0xec-0xef + + OC4(B, B, B, B), // 0xf0-0xf3 + OC4(B, B, B, B), // 0xf4-0xf7 + OC4(U, U, U, U), // 0xf8-0xfb + OC4(U, U, U, U), // 0xfc-0xff +}; +#undef OC4 +#undef U +#undef B +#undef Q +#undef V +#undef O + +uint mp_opcode_format(const byte *ip, size_t *opcode_size) { + uint f = (opcode_format_table[*ip >> 2] >> (2 * (*ip & 3))) & 3; + const byte *ip_start = ip; + if (f == MP_OPCODE_QSTR) { + ip += 3; + } else { + int extra_byte = ( + *ip == MP_BC_RAISE_VARARGS + || *ip == MP_BC_MAKE_CLOSURE + || *ip == MP_BC_MAKE_CLOSURE_DEFARGS + #if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE + || *ip == MP_BC_LOAD_NAME + || *ip == MP_BC_LOAD_GLOBAL + || *ip == MP_BC_LOAD_ATTR + || *ip == MP_BC_STORE_ATTR + #endif + ); + ip += 1; + if (f == MP_OPCODE_VAR_UINT) { + while ((*ip++ & 0x80) != 0) { + } + } else if (f == MP_OPCODE_OFFSET) { + ip += 2; + } + ip += extra_byte; + } + *opcode_size = ip - ip_start; + return f; +} + +#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE diff --git a/src/openmv/src/micropython/py/bc.h b/src/openmv/src/micropython/py/bc.h new file mode 100755 index 0000000..ebfdeaa --- /dev/null +++ b/src/openmv/src/micropython/py/bc.h @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_BC_H +#define MICROPY_INCLUDED_PY_BC_H + +#include "py/runtime.h" +#include "py/objfun.h" + +// bytecode layout: +// +// n_state : var uint +// n_exc_stack : var uint +// scope_flags : byte +// n_pos_args : byte number of arguments this function takes +// n_kwonly_args : byte number of keyword-only arguments this function takes +// n_def_pos_args : byte number of default positional arguments +// +// code_info_size : var uint | code_info_size counts bytes in this chunk +// simple_name : var qstr | +// source_file : var qstr | +// | +// | only needed if bytecode contains pointers +// +// local_num0 : byte | +// ... : byte | +// local_numN : byte | N = num_cells +// 255 : byte | end of list sentinel +// | +// +// +// constant table layout: +// +// argname0 : obj (qstr) +// ... : obj (qstr) +// argnameN : obj (qstr) N = num_pos_args + num_kwonly_args +// const0 : obj +// constN : obj + +// Exception stack entry +typedef struct _mp_exc_stack_t { + const byte *handler; + // bit 0 is saved currently_in_except_block value + // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY + mp_obj_t *val_sp; + // Saved exception, valid if currently_in_except_block bit is 1 + mp_obj_base_t *prev_exc; +} mp_exc_stack_t; + +typedef struct _mp_code_state_t { + // The fun_bc entry points to the underlying function object that is being executed. + // It is needed to access the start of bytecode and the const_table. + // It is also needed to prevent the GC from reclaiming the bytecode during execution, + // because the ip pointer below will always point to the interior of the bytecode. + mp_obj_fun_bc_t *fun_bc; + const byte *ip; + mp_obj_t *sp; + // bit 0 is saved currently_in_except_block value + mp_exc_stack_t *exc_sp; + mp_obj_dict_t *old_globals; + #if MICROPY_STACKLESS + struct _mp_code_state_t *prev; + #endif + // Variable-length + mp_obj_t state[0]; + // Variable-length, never accessed by name, only as (void*)(state + n_state) + //mp_exc_stack_t exc_state[0]; +} mp_code_state_t; + +mp_uint_t mp_decode_uint(const byte **ptr); +mp_uint_t mp_decode_uint_value(const byte *ptr); +const byte *mp_decode_uint_skip(const byte *ptr); + +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); +void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table); +const byte *mp_bytecode_print_str(const byte *ip); +#define mp_bytecode_print_inst(code, const_table) mp_bytecode_print2(code, 1, const_table) + +// Helper macros to access pointer with least significant bits holding flags +#define MP_TAGPTR_PTR(x) ((void*)((uintptr_t)(x) & ~((uintptr_t)3))) +#define MP_TAGPTR_TAG0(x) ((uintptr_t)(x) & 1) +#define MP_TAGPTR_TAG1(x) ((uintptr_t)(x) & 2) +#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((uintptr_t)(ptr) | (tag))) + +#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE + +#define MP_OPCODE_BYTE (0) +#define MP_OPCODE_QSTR (1) +#define MP_OPCODE_VAR_UINT (2) +#define MP_OPCODE_OFFSET (3) + +uint mp_opcode_format(const byte *ip, size_t *opcode_size); + +#endif + +#endif // MICROPY_INCLUDED_PY_BC_H diff --git a/src/openmv/src/micropython/py/bc0.h b/src/openmv/src/micropython/py/bc0.h new file mode 100755 index 0000000..70acfb0 --- /dev/null +++ b/src/openmv/src/micropython/py/bc0.h @@ -0,0 +1,119 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_BC0_H +#define MICROPY_INCLUDED_PY_BC0_H + +// MicroPython byte-codes. +// The comment at the end of the line (if it exists) tells the arguments to the byte-code. + +#define MP_BC_LOAD_CONST_FALSE (0x10) +#define MP_BC_LOAD_CONST_NONE (0x11) +#define MP_BC_LOAD_CONST_TRUE (0x12) +#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int +#define MP_BC_LOAD_CONST_STRING (0x16) // qstr +#define MP_BC_LOAD_CONST_OBJ (0x17) // ptr +#define MP_BC_LOAD_NULL (0x18) + +#define MP_BC_LOAD_FAST_N (0x19) // uint +#define MP_BC_LOAD_DEREF (0x1a) // uint +#define MP_BC_LOAD_NAME (0x1b) // qstr +#define MP_BC_LOAD_GLOBAL (0x1c) // qstr +#define MP_BC_LOAD_ATTR (0x1d) // qstr +#define MP_BC_LOAD_METHOD (0x1e) // qstr +#define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr +#define MP_BC_LOAD_BUILD_CLASS (0x20) +#define MP_BC_LOAD_SUBSCR (0x21) + +#define MP_BC_STORE_FAST_N (0x22) // uint +#define MP_BC_STORE_DEREF (0x23) // uint +#define MP_BC_STORE_NAME (0x24) // qstr +#define MP_BC_STORE_GLOBAL (0x25) // qstr +#define MP_BC_STORE_ATTR (0x26) // qstr +#define MP_BC_STORE_SUBSCR (0x27) + +#define MP_BC_DELETE_FAST (0x28) // uint +#define MP_BC_DELETE_DEREF (0x29) // uint +#define MP_BC_DELETE_NAME (0x2a) // qstr +#define MP_BC_DELETE_GLOBAL (0x2b) // qstr + +#define MP_BC_DUP_TOP (0x30) +#define MP_BC_DUP_TOP_TWO (0x31) +#define MP_BC_POP_TOP (0x32) +#define MP_BC_ROT_TWO (0x33) +#define MP_BC_ROT_THREE (0x34) + +#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess +#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned +#define MP_BC_WITH_CLEANUP (0x3e) +#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned +#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned +#define MP_BC_END_FINALLY (0x41) +#define MP_BC_GET_ITER (0x42) +#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned +#define MP_BC_POP_BLOCK (0x44) +#define MP_BC_POP_EXCEPT (0x45) +#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte +#define MP_BC_GET_ITER_STACK (0x47) + +#define MP_BC_BUILD_TUPLE (0x50) // uint +#define MP_BC_BUILD_LIST (0x51) // uint +#define MP_BC_BUILD_MAP (0x53) // uint +#define MP_BC_STORE_MAP (0x54) +#define MP_BC_BUILD_SET (0x56) // uint +#define MP_BC_BUILD_SLICE (0x58) // uint +#define MP_BC_STORE_COMP (0x57) // uint +#define MP_BC_UNPACK_SEQUENCE (0x59) // uint +#define MP_BC_UNPACK_EX (0x5a) // uint + +#define MP_BC_RETURN_VALUE (0x5b) +#define MP_BC_RAISE_VARARGS (0x5c) // byte +#define MP_BC_YIELD_VALUE (0x5d) +#define MP_BC_YIELD_FROM (0x5e) + +#define MP_BC_MAKE_FUNCTION (0x60) // uint +#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint +#define MP_BC_MAKE_CLOSURE (0x62) // uint +#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint +#define MP_BC_CALL_FUNCTION (0x64) // uint +#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint +#define MP_BC_CALL_METHOD (0x66) // uint +#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint + +#define MP_BC_IMPORT_NAME (0x68) // qstr +#define MP_BC_IMPORT_FROM (0x69) // qstr +#define MP_BC_IMPORT_STAR (0x6a) + +#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64) +#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16) +#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16) +#define MP_BC_UNARY_OP_MULTI (0xd0) // + op( +#include +#include +#include +#include + +#include "py/binary.h" +#include "py/smallint.h" +#include "py/objint.h" +#include "py/runtime.h" + +// Helpers to work with binary-encoded data + +#ifndef alignof +#define alignof(type) offsetof(struct { char c; type t; }, t) +#endif + +size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) { + size_t size = 0; + int align = 1; + switch (struct_type) { + case '<': case '>': + switch (val_type) { + case 'b': case 'B': + size = 1; break; + case 'h': case 'H': + size = 2; break; + case 'i': case 'I': + size = 4; break; + case 'l': case 'L': + size = 4; break; + case 'q': case 'Q': + size = 8; break; + case 'P': case 'O': case 'S': + size = sizeof(void*); break; + case 'f': + size = sizeof(float); break; + case 'd': + size = sizeof(double); break; + } + break; + case '@': { + // TODO: + // The simplest heuristic for alignment is to align by value + // size, but that doesn't work for "bigger than int" types, + // for example, long long may very well have long alignment + // So, we introduce separate alignment handling, but having + // formal support for that is different from actually supporting + // particular (or any) ABI. + switch (val_type) { + case BYTEARRAY_TYPECODE: + case 'b': case 'B': + align = size = 1; break; + case 'h': case 'H': + align = alignof(short); + size = sizeof(short); break; + case 'i': case 'I': + align = alignof(int); + size = sizeof(int); break; + case 'l': case 'L': + align = alignof(long); + size = sizeof(long); break; + case 'q': case 'Q': + align = alignof(long long); + size = sizeof(long long); break; + case 'P': case 'O': case 'S': + align = alignof(void*); + size = sizeof(void*); break; + case 'f': + align = alignof(float); + size = sizeof(float); break; + case 'd': + align = alignof(double); + size = sizeof(double); break; + } + } + } + + if (size == 0) { + mp_raise_ValueError("bad typecode"); + } + + if (palign != NULL) { + *palign = align; + } + return size; +} + +mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { + mp_int_t val = 0; + switch (typecode) { + case 'b': + val = ((signed char*)p)[index]; + break; + case BYTEARRAY_TYPECODE: + case 'B': + val = ((unsigned char*)p)[index]; + break; + case 'h': + val = ((short*)p)[index]; + break; + case 'H': + val = ((unsigned short*)p)[index]; + break; + case 'i': + return mp_obj_new_int(((int*)p)[index]); + case 'I': + return mp_obj_new_int_from_uint(((unsigned int*)p)[index]); + case 'l': + return mp_obj_new_int(((long*)p)[index]); + case 'L': + return mp_obj_new_int_from_uint(((unsigned long*)p)[index]); + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + case 'q': + return mp_obj_new_int_from_ll(((long long*)p)[index]); + case 'Q': + return mp_obj_new_int_from_ull(((unsigned long long*)p)[index]); + #endif +#if MICROPY_PY_BUILTINS_FLOAT + case 'f': + return mp_obj_new_float(((float*)p)[index]); + case 'd': + return mp_obj_new_float(((double*)p)[index]); +#endif + // Extension to CPython: array of objects + case 'O': + return ((mp_obj_t*)p)[index]; + // Extension to CPython: array of pointers + case 'P': + return mp_obj_new_int((mp_int_t)(uintptr_t)((void**)p)[index]); + } + return MP_OBJ_NEW_SMALL_INT(val); +} + +// The long long type is guaranteed to hold at least 64 bits, and size is at +// most 8 (for q and Q), so we will always be able to parse the given data +// and fit it into a long long. +long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) { + int delta; + if (!big_endian) { + delta = -1; + src += size - 1; + } else { + delta = 1; + } + + long long val = 0; + if (is_signed && *src & 0x80) { + val = -1; + } + for (uint i = 0; i < size; i++) { + val <<= 8; + val |= *src; + src += delta; + } + + return val; +} + +#define is_signed(typecode) (typecode > 'Z') +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { + byte *p = *ptr; + mp_uint_t align; + + size_t size = mp_binary_get_size(struct_type, val_type, &align); + if (struct_type == '@') { + // Make pointer aligned + p = (byte*)MP_ALIGN(p, (size_t)align); + #if MP_ENDIANNESS_LITTLE + struct_type = '<'; + #else + struct_type = '>'; + #endif + } + *ptr = p + size; + + long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); + + if (val_type == 'O') { + return (mp_obj_t)(mp_uint_t)val; + } else if (val_type == 'S') { + const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; + return mp_obj_new_str(s_val, strlen(s_val)); +#if MICROPY_PY_BUILTINS_FLOAT + } else if (val_type == 'f') { + union { uint32_t i; float f; } fpu = {val}; + return mp_obj_new_float(fpu.f); + } else if (val_type == 'd') { + union { uint64_t i; double f; } fpu = {val}; + return mp_obj_new_float(fpu.f); +#endif + } else if (is_signed(val_type)) { + if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) { + return mp_obj_new_int((mp_int_t)val); + } else { + return mp_obj_new_int_from_ll(val); + } + } else { + if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) { + return mp_obj_new_int_from_uint((mp_uint_t)val); + } else { + return mp_obj_new_int_from_ull(val); + } + } +} + +void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) { + if (MP_ENDIANNESS_LITTLE && !big_endian) { + memcpy(dest, &val, val_sz); + } else if (MP_ENDIANNESS_BIG && big_endian) { + // only copy the least-significant val_sz bytes + memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz); + } else { + const byte *src; + if (MP_ENDIANNESS_LITTLE) { + src = (const byte*)&val + val_sz; + } else { + src = (const byte*)&val + sizeof(mp_uint_t); + } + while (val_sz--) { + *dest++ = *--src; + } + } +} + +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) { + byte *p = *ptr; + mp_uint_t align; + + size_t size = mp_binary_get_size(struct_type, val_type, &align); + if (struct_type == '@') { + // Make pointer aligned + p = (byte*)MP_ALIGN(p, (size_t)align); + if (MP_ENDIANNESS_LITTLE) { + struct_type = '<'; + } else { + struct_type = '>'; + } + } + *ptr = p + size; + + mp_uint_t val; + switch (val_type) { + case 'O': + val = (mp_uint_t)val_in; + break; +#if MICROPY_PY_BUILTINS_FLOAT + case 'f': { + union { uint32_t i; float f; } fp_sp; + fp_sp.f = mp_obj_get_float(val_in); + val = fp_sp.i; + break; + } + case 'd': { + union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp; + fp_dp.f = mp_obj_get_float(val_in); + if (BYTES_PER_WORD == 8) { + val = fp_dp.i64; + } else { + int be = struct_type == '>'; + mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]); + p += sizeof(uint32_t); + val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be]; + } + break; + } +#endif + default: + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); + return; + } else + #endif + { + val = mp_obj_get_int(val_in); + // zero/sign extend if needed + if (BYTES_PER_WORD < 8 && size > sizeof(val)) { + int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00; + memset(p, c, size); + if (struct_type == '>') { + p += size - sizeof(val); + } + } + } + } + + mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); +} + +void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) { + switch (typecode) { +#if MICROPY_PY_BUILTINS_FLOAT + case 'f': + ((float*)p)[index] = mp_obj_get_float(val_in); + break; + case 'd': + ((double*)p)[index] = mp_obj_get_float(val_in); + break; +#endif + // Extension to CPython: array of objects + case 'O': + ((mp_obj_t*)p)[index] = val_in; + break; + default: + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + size_t size = mp_binary_get_size('@', typecode, NULL); + mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, + size, (uint8_t*)p + index * size); + return; + } + #endif + mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in)); + } +} + +void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) { + switch (typecode) { + case 'b': + ((signed char*)p)[index] = val; + break; + case BYTEARRAY_TYPECODE: + case 'B': + ((unsigned char*)p)[index] = val; + break; + case 'h': + ((short*)p)[index] = val; + break; + case 'H': + ((unsigned short*)p)[index] = val; + break; + case 'i': + ((int*)p)[index] = val; + break; + case 'I': + ((unsigned int*)p)[index] = val; + break; + case 'l': + ((long*)p)[index] = val; + break; + case 'L': + ((unsigned long*)p)[index] = val; + break; + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + case 'q': + ((long long*)p)[index] = val; + break; + case 'Q': + ((unsigned long long*)p)[index] = val; + break; + #endif +#if MICROPY_PY_BUILTINS_FLOAT + case 'f': + ((float*)p)[index] = val; + break; + case 'd': + ((double*)p)[index] = val; + break; +#endif + // Extension to CPython: array of pointers + case 'P': + ((void**)p)[index] = (void*)(uintptr_t)val; + break; + } +} diff --git a/src/openmv/src/micropython/py/binary.h b/src/openmv/src/micropython/py/binary.h new file mode 100755 index 0000000..0dae6a2 --- /dev/null +++ b/src/openmv/src/micropython/py/binary.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_BINARY_H +#define MICROPY_INCLUDED_PY_BINARY_H + +#include "py/obj.h" + +// Use special typecode to differentiate repr() of bytearray vs array.array('B') +// (underlyingly they're same). Can't use 0 here because that's used to detect +// type-specification errors due to end-of-string. +#define BYTEARRAY_TYPECODE 1 + +size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign); +mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index); +void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in); +void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val); +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); +void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); +long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src); +void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val); + +#endif // MICROPY_INCLUDED_PY_BINARY_H diff --git a/src/openmv/src/micropython/py/builtin.h b/src/openmv/src/micropython/py/builtin.h new file mode 100755 index 0000000..6f8964a --- /dev/null +++ b/src/openmv/src/micropython/py/builtin.h @@ -0,0 +1,124 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_BUILTIN_H +#define MICROPY_INCLUDED_PY_BUILTIN_H + +#include "py/obj.h" + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); +mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args); + +MP_DECLARE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_abs_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_all_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_any_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_globals_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hash_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hex_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_id_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_iter_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_print_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_repr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj); +// Defined by a port, but declared here for simplicity +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); + +MP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj); + +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); + +extern const mp_obj_module_t mp_module___main__; +extern const mp_obj_module_t mp_module_builtins; +extern const mp_obj_module_t mp_module_array; +extern const mp_obj_module_t mp_module_collections; +extern const mp_obj_module_t mp_module_io; +extern const mp_obj_module_t mp_module_math; +extern const mp_obj_module_t mp_module_cmath; +extern const mp_obj_module_t mp_module_micropython; +extern const mp_obj_module_t mp_module_ustruct; +extern const mp_obj_module_t mp_module_sys; +extern const mp_obj_module_t mp_module_gc; +extern const mp_obj_module_t mp_module_thread; + +extern const mp_obj_dict_t mp_module_builtins_globals; + +// extmod modules +extern const mp_obj_module_t mp_module_uerrno; +extern const mp_obj_module_t mp_module_uctypes; +extern const mp_obj_module_t mp_module_uzlib; +extern const mp_obj_module_t mp_module_ujson; +extern const mp_obj_module_t mp_module_ure; +extern const mp_obj_module_t mp_module_uheapq; +extern const mp_obj_module_t mp_module_uhashlib; +extern const mp_obj_module_t mp_module_ucryptolib; +extern const mp_obj_module_t mp_module_ubinascii; +extern const mp_obj_module_t mp_module_urandom; +extern const mp_obj_module_t mp_module_uselect; +extern const mp_obj_module_t mp_module_ussl; +extern const mp_obj_module_t mp_module_utimeq; +extern const mp_obj_module_t mp_module_machine; +extern const mp_obj_module_t mp_module_lwip; +extern const mp_obj_module_t mp_module_websocket; +extern const mp_obj_module_t mp_module_webrepl; +extern const mp_obj_module_t mp_module_framebuf; +extern const mp_obj_module_t mp_module_btree; + +extern const char MICROPY_PY_BUILTINS_HELP_TEXT[]; + +#endif // MICROPY_INCLUDED_PY_BUILTIN_H diff --git a/src/openmv/src/micropython/py/builtinevex.c b/src/openmv/src/micropython/py/builtinevex.c new file mode 100755 index 0000000..846603f --- /dev/null +++ b/src/openmv/src/micropython/py/builtinevex.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objfun.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/builtin.h" + +#if MICROPY_PY_BUILTINS_COMPILE + +typedef struct _mp_obj_code_t { + mp_obj_base_t base; + mp_obj_t module_fun; +} mp_obj_code_t; + +STATIC const mp_obj_type_t mp_type_code = { + { &mp_type_type }, + .name = MP_QSTR_code, +}; + +STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { + // save context and set new context + mp_obj_dict_t *old_globals = mp_globals_get(); + mp_obj_dict_t *old_locals = mp_locals_get(); + mp_globals_set(globals); + mp_locals_set(locals); + + // a bit of a hack: fun_bc will re-set globals, so need to make sure it's + // the correct one + if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) { + mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(self->module_fun); + fun_bc->globals = globals; + } + + // execute code + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_call_function_0(self->module_fun); + nlr_pop(); + mp_globals_set(old_globals); + mp_locals_set(old_locals); + return ret; + } else { + // exception; restore context and re-raise same exception + mp_globals_set(old_globals); + mp_locals_set(old_locals); + nlr_jump(nlr.ret_val); + } +} + +STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + + // get the source + size_t str_len; + const char *str = mp_obj_str_get_data(args[0], &str_len); + + // get the filename + qstr filename = mp_obj_str_get_qstr(args[1]); + + // create the lexer + mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0); + + // get the compile mode + qstr mode = mp_obj_str_get_qstr(args[2]); + mp_parse_input_kind_t parse_input_kind; + switch (mode) { + case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break; + case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break; + case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break; + default: + mp_raise_ValueError("bad compile mode"); + } + + mp_obj_code_t *code = m_new_obj(mp_obj_code_t); + code->base.type = &mp_type_code; + code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL); + return MP_OBJ_FROM_PTR(code); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile); + +#endif // MICROPY_PY_BUILTINS_COMPILE + +#if MICROPY_PY_BUILTINS_EVAL_EXEC + +STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) { + // work out the context + mp_obj_dict_t *globals = mp_globals_get(); + mp_obj_dict_t *locals = mp_locals_get(); + for (size_t i = 1; i < 3 && i < n_args; ++i) { + if (args[i] != mp_const_none) { + if (!MP_OBJ_IS_TYPE(args[i], &mp_type_dict)) { + mp_raise_TypeError(NULL); + } + locals = MP_OBJ_TO_PTR(args[i]); + if (i == 1) { + globals = locals; + } + } + } + + #if MICROPY_PY_BUILTINS_COMPILE + if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) { + return code_execute(MP_OBJ_TO_PTR(args[0]), globals, locals); + } + #endif + + size_t str_len; + const char *str = mp_obj_str_get_data(args[0], &str_len); + + // create the lexer + // MP_PARSE_SINGLE_INPUT is used to indicate a file input + mp_lexer_t *lex; + if (MICROPY_PY_BUILTINS_EXECFILE && parse_input_kind == MP_PARSE_SINGLE_INPUT) { + lex = mp_lexer_new_from_file(str); + parse_input_kind = MP_PARSE_FILE_INPUT; + } else { + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0); + } + + return mp_parse_compile_execute(lex, parse_input_kind, globals, locals); +} + +STATIC mp_obj_t mp_builtin_eval(size_t n_args, const mp_obj_t *args) { + return eval_exec_helper(n_args, args, MP_PARSE_EVAL_INPUT); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj, 1, 3, mp_builtin_eval); + +STATIC mp_obj_t mp_builtin_exec(size_t n_args, const mp_obj_t *args) { + return eval_exec_helper(n_args, args, MP_PARSE_FILE_INPUT); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec); + +#endif // MICROPY_PY_BUILTINS_EVAL_EXEC + +#if MICROPY_PY_BUILTINS_EXECFILE +STATIC mp_obj_t mp_builtin_execfile(size_t n_args, const mp_obj_t *args) { + // MP_PARSE_SINGLE_INPUT is used to indicate a file input + return eval_exec_helper(n_args, args, MP_PARSE_SINGLE_INPUT); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj, 1, 3, mp_builtin_execfile); +#endif diff --git a/src/openmv/src/micropython/py/builtinhelp.c b/src/openmv/src/micropython/py/builtinhelp.c new file mode 100755 index 0000000..b36f4c9 --- /dev/null +++ b/src/openmv/src/micropython/py/builtinhelp.c @@ -0,0 +1,179 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/builtin.h" +#include "py/objmodule.h" + +#if MICROPY_PY_BUILTINS_HELP + +const char mp_help_default_text[] = +"Welcome to MicroPython!\n" +"\n" +"For online docs please visit http://docs.micropython.org/\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, exit or do a soft reset\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; + +STATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { + mp_print_str(MP_PYTHON_PRINTER, " "); + mp_obj_print(name_o, PRINT_STR); + mp_print_str(MP_PYTHON_PRINTER, " -- "); + mp_obj_print(value, PRINT_STR); + mp_print_str(MP_PYTHON_PRINTER, "\n"); +} + +#if MICROPY_PY_BUILTINS_HELP_MODULES +STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) { + for (size_t i = 0; i < map->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + mp_obj_list_append(list, map->table[i].key); + } + } +} + +#if MICROPY_MODULE_FROZEN +STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) { + while (*name) { + size_t l = strlen(name); + // name should end in '.py' and we strip it off + mp_obj_list_append(list, mp_obj_new_str(name, l - 3)); + name += l + 1; + } +} +#endif + +STATIC void mp_help_print_modules(void) { + mp_obj_t list = mp_obj_new_list(0, NULL); + + mp_help_add_from_map(list, &mp_builtin_module_map); + + #if MICROPY_MODULE_WEAK_LINKS + mp_help_add_from_map(list, &mp_builtin_module_weak_links_map); + #endif + + #if MICROPY_MODULE_FROZEN_STR + extern const char mp_frozen_str_names[]; + mp_help_add_from_names(list, mp_frozen_str_names); + #endif + + #if MICROPY_MODULE_FROZEN_MPY + extern const char mp_frozen_mpy_names[]; + mp_help_add_from_names(list, mp_frozen_mpy_names); + #endif + + // sort the list so it's printed in alphabetical order + mp_obj_list_sort(1, &list, (mp_map_t*)&mp_const_empty_map); + + // print the list of modules in a column-first order + #define NUM_COLUMNS (4) + #define COLUMN_WIDTH (18) + size_t len; + mp_obj_t *items; + mp_obj_list_get(list, &len, &items); + unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS; + for (unsigned int i = 0; i < num_rows; ++i) { + unsigned int j = i; + for (;;) { + int l = mp_print_str(MP_PYTHON_PRINTER, mp_obj_str_get_str(items[j])); + j += num_rows; + if (j >= len) { + break; + } + int gap = COLUMN_WIDTH - l; + while (gap < 1) { + gap += COLUMN_WIDTH; + } + while (gap--) { + mp_print_str(MP_PYTHON_PRINTER, " "); + } + } + mp_print_str(MP_PYTHON_PRINTER, "\n"); + } + + // let the user know there may be other modules available from the filesystem + mp_print_str(MP_PYTHON_PRINTER, "Plus any modules on the filesystem\n"); +} +#endif + +STATIC void mp_help_print_obj(const mp_obj_t obj) { + #if MICROPY_PY_BUILTINS_HELP_MODULES + if (obj == MP_OBJ_NEW_QSTR(MP_QSTR_modules)) { + mp_help_print_modules(); + return; + } + #endif + + mp_obj_type_t *type = mp_obj_get_type(obj); + + // try to print something sensible about the given object + mp_print_str(MP_PYTHON_PRINTER, "object "); + mp_obj_print(obj, PRINT_STR); + mp_printf(MP_PYTHON_PRINTER, " is of type %q\n", type->name); + + mp_map_t *map = NULL; + if (type == &mp_type_module) { + map = &mp_obj_module_get_globals(obj)->map; + } else { + if (type == &mp_type_type) { + type = MP_OBJ_TO_PTR(obj); + } + if (type->locals_dict != NULL) { + map = &type->locals_dict->map; + } + } + if (map != NULL) { + for (uint i = 0; i < map->alloc; i++) { + if (map->table[i].key != MP_OBJ_NULL) { + mp_help_print_info_about_object(map->table[i].key, map->table[i].value); + } + } + } +} + +STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // print a general help message + mp_print_str(MP_PYTHON_PRINTER, MICROPY_PY_BUILTINS_HELP_TEXT); + } else { + // try to print something sensible about the given object + mp_help_print_obj(args[0]); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, mp_builtin_help); + +#endif // MICROPY_PY_BUILTINS_HELP diff --git a/src/openmv/src/micropython/py/builtinimport.c b/src/openmv/src/micropython/py/builtinimport.c new file mode 100755 index 0000000..b8ed096 --- /dev/null +++ b/src/openmv/src/micropython/py/builtinimport.c @@ -0,0 +1,515 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/compile.h" +#include "py/objmodule.h" +#include "py/persistentcode.h" +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/frozenmod.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +#if MICROPY_ENABLE_EXTERNAL_IMPORT + +#define PATH_SEP_CHAR '/' + +bool mp_obj_is_package(mp_obj_t module) { + mp_obj_t dest[2]; + mp_load_method_maybe(module, MP_QSTR___path__, dest); + return dest[0] != MP_OBJ_NULL; +} + +// Stat either frozen or normal module by a given path +// (whatever is available, if at all). +STATIC mp_import_stat_t mp_import_stat_any(const char *path) { + #if MICROPY_MODULE_FROZEN + mp_import_stat_t st = mp_frozen_stat(path); + if (st != MP_IMPORT_STAT_NO_EXIST) { + return st; + } + #endif + return mp_import_stat(path); +} + +STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) { + mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); + if (stat == MP_IMPORT_STAT_FILE) { + return stat; + } + + #if MICROPY_PERSISTENT_CODE_LOAD + vstr_ins_byte(path, path->len - 2, 'm'); + stat = mp_import_stat_any(vstr_null_terminated_str(path)); + if (stat == MP_IMPORT_STAT_FILE) { + return stat; + } + #endif + + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { + mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); + DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); + if (stat == MP_IMPORT_STAT_DIR) { + return stat; + } + + // not a directory, add .py and try as a file + vstr_add_str(path, ".py"); + return stat_file_py_or_mpy(path); +} + +STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) { +#if MICROPY_PY_SYS + // extract the list of paths + size_t path_num; + mp_obj_t *path_items; + mp_obj_list_get(mp_sys_path, &path_num, &path_items); + + if (path_num == 0) { +#endif + // mp_sys_path is empty, so just use the given file name + vstr_add_strn(dest, file_str, file_len); + return stat_dir_or_file(dest); +#if MICROPY_PY_SYS + } else { + // go through each path looking for a directory or file + for (size_t i = 0; i < path_num; i++) { + vstr_reset(dest); + size_t p_len; + const char *p = mp_obj_str_get_data(path_items[i], &p_len); + if (p_len > 0) { + vstr_add_strn(dest, p, p_len); + vstr_add_char(dest, PATH_SEP_CHAR); + } + vstr_add_strn(dest, file_str, file_len); + mp_import_stat_t stat = stat_dir_or_file(dest); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; + } + } + + // could not find a directory or file + return MP_IMPORT_STAT_NO_EXIST; + } +#endif +} + +#if MICROPY_ENABLE_COMPILER +STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) { + #if MICROPY_PY___FILE__ + qstr source_name = lex->source_name; + mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + #endif + + // parse, compile and execute the module in its context + mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); + mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); +} +#endif + +#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY +STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { + #if MICROPY_PY___FILE__ + // TODO + //qstr source_name = lex->source_name; + //mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + #endif + + // execute the module in its context + mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); + + // save context + mp_obj_dict_t *volatile old_globals = mp_globals_get(); + mp_obj_dict_t *volatile old_locals = mp_locals_get(); + + // set new context + mp_globals_set(mod_globals); + mp_locals_set(mod_globals); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t module_fun = mp_make_function_from_raw_code(raw_code, MP_OBJ_NULL, MP_OBJ_NULL); + mp_call_function_0(module_fun); + + // finish nlr block, restore context + nlr_pop(); + mp_globals_set(old_globals); + mp_locals_set(old_locals); + } else { + // exception; restore context and re-raise same exception + mp_globals_set(old_globals); + mp_locals_set(old_locals); + nlr_jump(nlr.ret_val); + } +} +#endif + +STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { + #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER + char *file_str = vstr_null_terminated_str(file); + #endif + + // If we support frozen modules (either as str or mpy) then try to find the + // requested filename in the list of frozen module filenames. + #if MICROPY_MODULE_FROZEN + void *modref; + int frozen_type = mp_find_frozen_module(file_str, file->len, &modref); + #endif + + // If we support frozen str modules and the compiler is enabled, and we + // found the filename in the list of frozen files, then load and execute it. + #if MICROPY_MODULE_FROZEN_STR + if (frozen_type == MP_FROZEN_STR) { + do_load_from_lexer(module_obj, modref); + return; + } + #endif + + // If we support frozen mpy modules and we found a corresponding file (and + // its data) in the list of frozen files, execute it. + #if MICROPY_MODULE_FROZEN_MPY + if (frozen_type == MP_FROZEN_MPY) { + do_execute_raw_code(module_obj, modref); + return; + } + #endif + + // If we support loading .mpy files then check if the file extension is of + // the correct format and, if so, load and execute the file. + #if MICROPY_PERSISTENT_CODE_LOAD + if (file_str[file->len - 3] == 'm') { + mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); + do_execute_raw_code(module_obj, raw_code); + return; + } + #endif + + // If we can compile scripts then load the file and compile and execute it. + #if MICROPY_ENABLE_COMPILER + { + mp_lexer_t *lex = mp_lexer_new_from_file(file_str); + do_load_from_lexer(module_obj, lex); + return; + } + #else + + // If we get here then the file was not frozen and we can't compile scripts. + mp_raise_msg(&mp_type_ImportError, "script compilation not supported"); + #endif +} + +STATIC void chop_component(const char *start, const char **end) { + const char *p = *end; + while (p > start) { + if (*--p == '.') { + *end = p; + return; + } + } + *end = p; +} + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { +#if DEBUG_PRINT + DEBUG_printf("__import__:\n"); + for (size_t i = 0; i < n_args; i++) { + DEBUG_printf(" "); + mp_obj_print(args[i], PRINT_REPR); + DEBUG_printf("\n"); + } +#endif + + mp_obj_t module_name = args[0]; + mp_obj_t fromtuple = mp_const_none; + mp_int_t level = 0; + if (n_args >= 4) { + fromtuple = args[3]; + if (n_args >= 5) { + level = MP_OBJ_SMALL_INT_VALUE(args[4]); + if (level < 0) { + mp_raise_ValueError(NULL); + } + } + } + + size_t mod_len; + const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); + + if (level != 0) { + // What we want to do here is to take name of current module, + // chop trailing components, and concatenate with passed-in + // module name, thus resolving relative import name into absolute. + // This even appears to be correct per + // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name + // "Relative imports use a module's __name__ attribute to determine that + // module's position in the package hierarchy." + level--; + mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + assert(this_name_q != MP_OBJ_NULL); + #if MICROPY_CPYTHON_COMPAT + if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { + // This is a module run by -m command-line switch, get its real name from backup attribute + this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + } + #endif + mp_map_t *globals_map = &mp_globals_get()->map; + mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); + bool is_pkg = (elem != NULL); + +#if DEBUG_PRINT + DEBUG_printf("Current module/package: "); + mp_obj_print(this_name_q, PRINT_REPR); + DEBUG_printf(", is_package: %d", is_pkg); + DEBUG_printf("\n"); +#endif + + size_t this_name_l; + const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); + + const char *p = this_name + this_name_l; + if (!is_pkg) { + // We have module, but relative imports are anchored at package, so + // go there. + chop_component(this_name, &p); + } + + while (level--) { + chop_component(this_name, &p); + } + + // We must have some component left over to import from + if (p == this_name) { + mp_raise_ValueError("cannot perform relative import"); + } + + uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); + char *new_mod = mp_local_alloc(new_mod_l); + memcpy(new_mod, this_name, p - this_name); + if (mod_len != 0) { + new_mod[p - this_name] = '.'; + memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len); + } + + qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); + mp_local_free(new_mod); + DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); + module_name = MP_OBJ_NEW_QSTR(new_mod_q); + mod_str = qstr_str(new_mod_q); + mod_len = new_mod_l; + } + + // check if module already exists + qstr module_name_qstr = mp_obj_str_get_qstr(module_name); + mp_obj_t module_obj = mp_module_get(module_name_qstr); + if (module_obj != MP_OBJ_NULL) { + DEBUG_printf("Module already loaded\n"); + // If it's not a package, return module right away + char *p = strchr(mod_str, '.'); + if (p == NULL) { + return module_obj; + } + // If fromlist is not empty, return leaf module + if (fromtuple != mp_const_none) { + return module_obj; + } + // Otherwise, we need to return top-level package + qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); + return mp_module_get(pkg_name); + } + DEBUG_printf("Module not yet loaded\n"); + + uint last = 0; + VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) + module_obj = MP_OBJ_NULL; + mp_obj_t top_module_obj = MP_OBJ_NULL; + mp_obj_t outer_module_obj = MP_OBJ_NULL; + uint i; + for (i = 1; i <= mod_len; i++) { + if (i == mod_len || mod_str[i] == '.') { + // create a qstr for the module name up to this depth + qstr mod_name = qstr_from_strn(mod_str, i); + DEBUG_printf("Processing module: %s\n", qstr_str(mod_name)); + DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path)); + + // find the file corresponding to the module name + mp_import_stat_t stat; + if (vstr_len(&path) == 0) { + // first module in the dotted-name; search for a directory or file + stat = find_file(mod_str, i, &path); + } else { + // latter module in the dotted-name; append to path + vstr_add_char(&path, PATH_SEP_CHAR); + vstr_add_strn(&path, mod_str + last, i - last); + stat = stat_dir_or_file(&path); + } + DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); + + if (stat == MP_IMPORT_STAT_NO_EXIST) { + #if MICROPY_MODULE_WEAK_LINKS + // check if there is a weak link to this module + if (i == mod_len) { + mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP); + if (el == NULL) { + goto no_exist; + } + // found weak linked module + module_obj = el->value; + mp_module_call_init(mod_name, module_obj); + } else { + no_exist: + #else + { + #endif + // couldn't find the file, so fail + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_ImportError, "module not found"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "no module named '%q'", mod_name)); + } + } + } else { + // found the file, so get the module + module_obj = mp_module_get(mod_name); + } + + if (module_obj == MP_OBJ_NULL) { + // module not already loaded, so load it! + + module_obj = mp_obj_new_module(mod_name); + + // if args[3] (fromtuple) has magic value False, set up + // this module for command-line "-m" option (set module's + // name to __main__ instead of real name). Do this only + // for *modules* however - packages never have their names + // replaced, instead they're -m'ed using a special __main__ + // submodule in them. (This all apparently is done to not + // touch package name itself, which is important for future + // imports). + if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) { + mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + #if MICROPY_CPYTHON_COMPAT + // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules). + mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj); + // Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's. + mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name)); + #endif + } + + if (stat == MP_IMPORT_STAT_DIR) { + DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); + // https://docs.python.org/3/reference/import.html + // "Specifically, any module that contains a __path__ attribute is considered a package." + mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path))); + size_t orig_path_len = path.len; + vstr_add_char(&path, PATH_SEP_CHAR); + vstr_add_str(&path, "__init__.py"); + if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) { + //mp_warning("%s is imported as namespace package", vstr_str(&path)); + } else { + do_load(module_obj, &path); + } + path.len = orig_path_len; + } else { // MP_IMPORT_STAT_FILE + do_load(module_obj, &path); + // This should be the last component in the import path. If there are + // remaining components then it's an ImportError because the current path + // (the module that was just loaded) is not a package. This will be caught + // on the next iteration because the file will not exist. + } + } + if (outer_module_obj != MP_OBJ_NULL) { + qstr s = qstr_from_strn(mod_str + last, i - last); + mp_store_attr(outer_module_obj, s, module_obj); + } + outer_module_obj = module_obj; + if (top_module_obj == MP_OBJ_NULL) { + top_module_obj = module_obj; + } + last = i + 1; + } + } + + // If fromlist is not empty, return leaf module + if (fromtuple != mp_const_none) { + return module_obj; + } + // Otherwise, we need to return top-level package + return top_module_obj; +} + +#else // MICROPY_ENABLE_EXTERNAL_IMPORT + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { + // Check that it's not a relative import + if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) { + mp_raise_NotImplementedError("relative import"); + } + + // Check if module already exists, and return it if it does + qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); + mp_obj_t module_obj = mp_module_get(module_name_qstr); + if (module_obj != MP_OBJ_NULL) { + return module_obj; + } + + #if MICROPY_MODULE_WEAK_LINKS + // Check if there is a weak link to this module + mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP); + if (el != NULL) { + // Found weak-linked module + mp_module_call_init(module_name_qstr, el->value); + return el->value; + } + #endif + + // Couldn't find the module, so fail + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_ImportError, "module not found"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "no module named '%q'", module_name_qstr)); + } +} + +#endif // MICROPY_ENABLE_EXTERNAL_IMPORT + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); diff --git a/src/openmv/src/micropython/py/compile.c b/src/openmv/src/micropython/py/compile.c new file mode 100755 index 0000000..e90b366 --- /dev/null +++ b/src/openmv/src/micropython/py/compile.c @@ -0,0 +1,3525 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/scope.h" +#include "py/emit.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/asmbase.h" + +#if MICROPY_ENABLE_COMPILER + +// TODO need to mangle __attr names + +#define INVALID_LABEL (0xffff) + +typedef enum { +// define rules with a compile function +#define DEF_RULE(rule, comp, kind, ...) PN_##rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + PN_const_object, // special node for a constant, generic Python object +// define rules without a compile function +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) PN_##rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +} pn_kind_t; + +#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE + +#if NEED_METHOD_TABLE + +// we need a method table to do the lookup for the emitter functions +#define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) +#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) +#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) +#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) + +#else + +// if we only have the bytecode emitter enabled then we can do a direct call to the functions +#define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) +#define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) +#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) +#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) + +#endif + +#if MICROPY_EMIT_NATIVE +// define a macro to access external native emitter +#if MICROPY_EMIT_X64 +#define NATIVE_EMITTER(f) emit_native_x64_##f +#elif MICROPY_EMIT_X86 +#define NATIVE_EMITTER(f) emit_native_x86_##f +#elif MICROPY_EMIT_THUMB +#define NATIVE_EMITTER(f) emit_native_thumb_##f +#elif MICROPY_EMIT_ARM +#define NATIVE_EMITTER(f) emit_native_arm_##f +#elif MICROPY_EMIT_XTENSA +#define NATIVE_EMITTER(f) emit_native_xtensa_##f +#else +#error "unknown native emitter" +#endif +#endif + +#if MICROPY_EMIT_INLINE_ASM +// define macros for inline assembler +#if MICROPY_EMIT_INLINE_THUMB +#define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb +#define ASM_EMITTER(f) emit_inline_thumb_##f +#elif MICROPY_EMIT_INLINE_XTENSA +#define ASM_DECORATOR_QSTR MP_QSTR_asm_xtensa +#define ASM_EMITTER(f) emit_inline_xtensa_##f +#else +#error "unknown asm emitter" +#endif +#endif + +#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm)) +#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__)) + +// elements in this struct are ordered to make it compact +typedef struct _compiler_t { + qstr source_file; + + uint8_t is_repl; + uint8_t pass; // holds enum type pass_kind_t + uint8_t have_star; + + // try to keep compiler clean from nlr + mp_obj_t compile_error; // set to an exception object if there's an error + size_t compile_error_line; // set to best guess of line of error + + uint next_label; + + uint16_t num_dict_params; + uint16_t num_default_params; + + uint16_t break_label; // highest bit set indicates we are breaking out of a for loop + uint16_t continue_label; + uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT + uint16_t break_continue_except_level; + + scope_t *scope_head; + scope_t *scope_cur; + + emit_t *emit; // current emitter + #if NEED_METHOD_TABLE + const emit_method_table_t *emit_method_table; // current emit method table + #endif + + #if MICROPY_EMIT_INLINE_ASM + emit_inline_asm_t *emit_inline_asm; // current emitter for inline asm + const emit_inline_asm_method_table_t *emit_inline_asm_method_table; // current emit method table for inline asm + #endif +} compiler_t; + +STATIC void compile_error_set_line(compiler_t *comp, mp_parse_node_t pn) { + // if the line of the error is unknown then try to update it from the pn + if (comp->compile_error_line == 0 && MP_PARSE_NODE_IS_STRUCT(pn)) { + comp->compile_error_line = ((mp_parse_node_struct_t*)pn)->source_line; + } +} + +STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) { + // only register the error if there has been no other error + if (comp->compile_error == MP_OBJ_NULL) { + comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); + compile_error_set_line(comp, pn); + } +} + +STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); +STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind); +STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); + +STATIC uint comp_next_label(compiler_t *comp) { + return comp->next_label++; +} + +#if MICROPY_EMIT_NATIVE +STATIC void reserve_labels_for_native(compiler_t *comp, int n) { + if (comp->scope_cur->emit_options != MP_EMIT_OPT_BYTECODE) { + comp->next_label += n; + } +} +#else +#define reserve_labels_for_native(comp, n) +#endif + +STATIC void compile_increase_except_level(compiler_t *comp, uint label, int kind) { + EMIT_ARG(setup_block, label, kind); + comp->cur_except_level += 1; + if (comp->cur_except_level > comp->scope_cur->exc_stack_size) { + comp->scope_cur->exc_stack_size = comp->cur_except_level; + } +} + +STATIC void compile_decrease_except_level(compiler_t *comp) { + assert(comp->cur_except_level > 0); + comp->cur_except_level -= 1; + EMIT(end_finally); + reserve_labels_for_native(comp, 1); +} + +STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) { + scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options); + scope->parent = comp->scope_cur; + scope->next = NULL; + if (comp->scope_head == NULL) { + comp->scope_head = scope; + } else { + scope_t *s = comp->scope_head; + while (s->next != NULL) { + s = s->next; + } + s->next = scope; + } + return scope; +} + +typedef void (*apply_list_fun_t)(compiler_t *comp, mp_parse_node_t pn); + +STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, apply_list_fun_t f) { + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (int i = 0; i < num_nodes; i++) { + f(comp, pns->nodes[i]); + } + } else if (!MP_PARSE_NODE_IS_NULL(pn)) { + f(comp, pn); + } +} + +STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) { + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (int i = 0; i < num_nodes; i++) { + compile_node(comp, pns->nodes[i]); + if (comp->compile_error != MP_OBJ_NULL) { + // add line info for the error in case it didn't have a line number + compile_error_set_line(comp, pns->nodes[i]); + return; + } + } +} + +STATIC void compile_load_id(compiler_t *comp, qstr qst) { + if (comp->pass == MP_PASS_SCOPE) { + mp_emit_common_get_id_for_load(comp->scope_cur, qst); + } else { + #if NEED_METHOD_TABLE + mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst); + #else + mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_load_id_ops, comp->scope_cur, qst); + #endif + } +} + +STATIC void compile_store_id(compiler_t *comp, qstr qst) { + if (comp->pass == MP_PASS_SCOPE) { + mp_emit_common_get_id_for_modification(comp->scope_cur, qst); + } else { + #if NEED_METHOD_TABLE + mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst); + #else + mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_store_id_ops, comp->scope_cur, qst); + #endif + } +} + +STATIC void compile_delete_id(compiler_t *comp, qstr qst) { + if (comp->pass == MP_PASS_SCOPE) { + mp_emit_common_get_id_for_modification(comp->scope_cur, qst); + } else { + #if NEED_METHOD_TABLE + mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst); + #else + mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_delete_id_ops, comp->scope_cur, qst); + #endif + } +} + +STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) { + int total = 0; + if (!MP_PARSE_NODE_IS_NULL(pn)) { + compile_node(comp, pn); + total += 1; + } + if (pns_list != NULL) { + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list); + for (int i = 0; i < n; i++) { + compile_node(comp, pns_list->nodes[i]); + } + total += n; + } + EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE); +} + +STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) { + // a simple tuple expression + c_tuple(comp, MP_PARSE_NODE_NULL, pns); +} + +STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) { + if (mp_parse_node_is_const_false(pn)) { + if (jump_if == false) { + EMIT_ARG(jump, label); + } + return; + } else if (mp_parse_node_is_const_true(pn)) { + if (jump_if == true) { + EMIT_ARG(jump, label); + } + return; + } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) { + if (jump_if == false) { + and_or_logic1:; + uint label2 = comp_next_label(comp); + for (int i = 0; i < n - 1; i++) { + c_if_cond(comp, pns->nodes[i], !jump_if, label2); + } + c_if_cond(comp, pns->nodes[n - 1], jump_if, label); + EMIT_ARG(label_assign, label2); + } else { + and_or_logic2: + for (int i = 0; i < n; i++) { + c_if_cond(comp, pns->nodes[i], jump_if, label); + } + } + return; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) { + if (jump_if == false) { + goto and_or_logic2; + } else { + goto and_or_logic1; + } + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) { + c_if_cond(comp, pns->nodes[0], !jump_if, label); + return; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_atom_paren) { + // cond is something in parenthesis + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // empty tuple, acts as false for the condition + if (jump_if == false) { + EMIT_ARG(jump, label); + } + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); + // non-empty tuple, acts as true for the condition + if (jump_if == true) { + EMIT_ARG(jump, label); + } + } + return; + } + } + + // nothing special, fall back to default compiling for node and jump + compile_node(comp, pn); + EMIT_ARG(pop_jump_if, jump_if, label); +} + +typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t; +STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind); + +STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) { + if (assign_kind != ASSIGN_AUG_STORE) { + compile_node(comp, pns->nodes[0]); + } + + if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); + if (assign_kind != ASSIGN_AUG_STORE) { + for (int i = 0; i < n - 1; i++) { + compile_node(comp, pns1->nodes[i]); + } + } + assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1])); + pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; + } + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { + if (assign_kind == ASSIGN_AUG_STORE) { + EMIT(rot_three); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); + } else { + compile_node(comp, pns1->nodes[0]); + if (assign_kind == ASSIGN_AUG_LOAD) { + EMIT(dup_top_two); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); + } else { + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); + } + } + return; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { + assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); + if (assign_kind == ASSIGN_AUG_LOAD) { + EMIT(dup_top); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_LOAD); + } else { + if (assign_kind == ASSIGN_AUG_STORE) { + EMIT(rot_two); + } + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_STORE); + } + return; + } + } + + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); +} + +// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail) +STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) { + uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1; + + // look for star expression + uint have_star_index = -1; + if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) { + EMIT_ARG(unpack_ex, 0, num_tail); + have_star_index = 0; + } + for (uint i = 0; i < num_tail; i++) { + if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) { + if (have_star_index == (uint)-1) { + EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1); + have_star_index = num_head + i; + } else { + compile_syntax_error(comp, nodes_tail[i], "multiple *x in assignment"); + return; + } + } + } + if (have_star_index == (uint)-1) { + EMIT_ARG(unpack_sequence, num_head + num_tail); + } + if (num_head != 0) { + if (0 == have_star_index) { + c_assign(comp, ((mp_parse_node_struct_t*)node_head)->nodes[0], ASSIGN_STORE); + } else { + c_assign(comp, node_head, ASSIGN_STORE); + } + } + for (uint i = 0; i < num_tail; i++) { + if (num_head + i == have_star_index) { + c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE); + } else { + c_assign(comp, nodes_tail[i], ASSIGN_STORE); + } + } +} + +// assigns top of stack to pn +STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { + assert(!MP_PARSE_NODE_IS_NULL(pn)); + if (MP_PARSE_NODE_IS_LEAF(pn)) { + if (MP_PARSE_NODE_IS_ID(pn)) { + qstr arg = MP_PARSE_NODE_LEAF_ARG(pn); + switch (assign_kind) { + case ASSIGN_STORE: + case ASSIGN_AUG_STORE: + compile_store_id(comp, arg); + break; + case ASSIGN_AUG_LOAD: + default: + compile_load_id(comp, arg); + break; + } + } else { + goto cannot_assign; + } + } else { + // pn must be a struct + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + switch (MP_PARSE_NODE_STRUCT_KIND(pns)) { + case PN_atom_expr_normal: + // lhs is an index or attribute + c_assign_atom_expr(comp, pns, assign_kind); + break; + + case PN_testlist_star_expr: + case PN_exprlist: + // lhs is a tuple + if (assign_kind != ASSIGN_STORE) { + goto cannot_assign; + } + c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); + break; + + case PN_atom_paren: + // lhs is something in parenthesis + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // empty tuple + goto cannot_assign; + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); + if (assign_kind != ASSIGN_STORE) { + goto cannot_assign; + } + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + goto testlist_comp; + } + break; + + case PN_atom_bracket: + // lhs is something in brackets + if (assign_kind != ASSIGN_STORE) { + goto cannot_assign; + } + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // empty list, assignment allowed + c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL); + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + goto testlist_comp; + } else { + // brackets around 1 item + c_assign_tuple(comp, pns->nodes[0], 0, NULL); + } + break; + + default: + goto cannot_assign; + } + return; + + testlist_comp: + // lhs is a sequence + if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { + // sequence of one item, with trailing comma + assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); + c_assign_tuple(comp, pns->nodes[0], 0, NULL); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { + // sequence of many items + uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2); + c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { + goto cannot_assign; + } else { + // sequence with 2 items + goto sequence_with_2_items; + } + } else { + // sequence with 2 items + sequence_with_2_items: + c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes); + } + return; + } + return; + + cannot_assign: + compile_syntax_error(comp, pn, "can't assign to expression"); +} + +// stuff for lambda and comprehensions and generators: +// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults +// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults +// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple) +STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) { + assert(n_pos_defaults >= 0); + assert(n_kw_defaults >= 0); + + // set flags + if (n_kw_defaults > 0) { + this_scope->scope_flags |= MP_SCOPE_FLAG_DEFKWARGS; + } + this_scope->num_def_pos_args = n_pos_defaults; + + #if MICROPY_EMIT_NATIVE + // When creating a function/closure it will take a reference to the current globals + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS; + #endif + + // make closed over variables, if any + // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython) + int nfree = 0; + if (comp->scope_cur->kind != SCOPE_MODULE) { + for (int i = 0; i < comp->scope_cur->id_info_len; i++) { + id_info_t *id = &comp->scope_cur->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { + for (int j = 0; j < this_scope->id_info_len; j++) { + id_info_t *id2 = &this_scope->id_info[j]; + if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { + // in MicroPython we load closures using LOAD_FAST + EMIT_LOAD_FAST(id->qst, id->local_num); + nfree += 1; + } + } + } + } + } + + // make the function/closure + if (nfree == 0) { + EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults); + } else { + EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults); + } +} + +STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) { + // For efficiency of the code below we extract the parse-node kind here + int pn_kind; + if (MP_PARSE_NODE_IS_ID(pn)) { + pn_kind = -1; + } else { + assert(MP_PARSE_NODE_IS_STRUCT(pn)); + pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn); + } + + if (pn_kind == PN_typedargslist_star || pn_kind == PN_varargslist_star) { + comp->have_star = true; + /* don't need to distinguish bare from named star + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // bare star + } else { + // named star + } + */ + + } else if (pn_kind == PN_typedargslist_dbl_star || pn_kind == PN_varargslist_dbl_star) { + // named double star + // TODO do we need to do anything with this? + + } else { + mp_parse_node_t pn_id; + mp_parse_node_t pn_equal; + if (pn_kind == -1) { + // this parameter is just an id + + pn_id = pn; + pn_equal = MP_PARSE_NODE_NULL; + + } else if (pn_kind == PN_typedargslist_name) { + // this parameter has a colon and/or equal specifier + + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + pn_id = pns->nodes[0]; + //pn_colon = pns->nodes[1]; // unused + pn_equal = pns->nodes[2]; + + } else { + assert(pn_kind == PN_varargslist_name); // should be + // this parameter has an equal specifier + + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + pn_id = pns->nodes[0]; + pn_equal = pns->nodes[1]; + } + + if (MP_PARSE_NODE_IS_NULL(pn_equal)) { + // this parameter does not have a default value + + // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid) + if (!comp->have_star && comp->num_default_params != 0) { + compile_syntax_error(comp, pn, "non-default argument follows default argument"); + return; + } + + } else { + // this parameter has a default value + // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why + + if (comp->have_star) { + comp->num_dict_params += 1; + // in MicroPython we put the default dict parameters into a dictionary using the bytecode + if (comp->num_dict_params == 1) { + // in MicroPython we put the default positional parameters into a tuple using the bytecode + // we need to do this here before we start building the map for the default keywords + if (comp->num_default_params > 0) { + EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); + } else { + EMIT(load_null); // sentinel indicating empty default positional args + } + // first default dict param, so make the map + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + } + + // compile value then key, then store it to the dict + compile_node(comp, pn_equal); + EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id)); + EMIT(store_map); + } else { + comp->num_default_params += 1; + compile_node(comp, pn_equal); + } + } + } +} + +STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_node_t pn_params, pn_kind_t pn_list_kind) { + // When we call compile_funcdef_lambdef_param below it can compile an arbitrary + // expression for default arguments, which may contain a lambda. The lambda will + // call here in a nested way, so we must save and restore the relevant state. + bool orig_have_star = comp->have_star; + uint16_t orig_num_dict_params = comp->num_dict_params; + uint16_t orig_num_default_params = comp->num_default_params; + + // compile default parameters + comp->have_star = false; + comp->num_dict_params = 0; + comp->num_default_params = 0; + apply_to_single_or_list(comp, pn_params, pn_list_kind, compile_funcdef_lambdef_param); + + if (comp->compile_error != MP_OBJ_NULL) { + return; + } + + // in MicroPython we put the default positional parameters into a tuple using the bytecode + // the default keywords args may have already made the tuple; if not, do it now + if (comp->num_default_params > 0 && comp->num_dict_params == 0) { + EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); + EMIT(load_null); // sentinel indicating empty default keyword args + } + + // make the function + close_over_variables_etc(comp, scope, comp->num_default_params, comp->num_dict_params); + + // restore state + comp->have_star = orig_have_star; + comp->num_dict_params = orig_num_dict_params; + comp->num_default_params = orig_num_default_params; +} + +// leaves function object on stack +// returns function name +STATIC qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) { + if (comp->pass == MP_PASS_SCOPE) { + // create a new scope for this function + scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options); + // store the function scope so the compiling function can use it at each pass + pns->nodes[4] = (mp_parse_node_t)s; + } + + // get the scope for this function + scope_t *fscope = (scope_t*)pns->nodes[4]; + + // compile the function definition + compile_funcdef_lambdef(comp, fscope, pns->nodes[1], PN_typedargslist); + + // return its name (the 'f' in "def f(...):") + return fscope->simple_name; +} + +// leaves class object on stack +// returns class name +STATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) { + if (comp->pass == MP_PASS_SCOPE) { + // create a new scope for this class + scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options); + // store the class scope so the compiling function can use it at each pass + pns->nodes[3] = (mp_parse_node_t)s; + } + + EMIT(load_build_class); + + // scope for this class + scope_t *cscope = (scope_t*)pns->nodes[3]; + + // compile the class + close_over_variables_etc(comp, cscope, 0, 0); + + // get its name + EMIT_ARG(load_const_str, cscope->simple_name); + + // nodes[1] has parent classes, if any + // empty parenthesis (eg class C():) gets here as an empty PN_classdef_2 and needs special handling + mp_parse_node_t parents = pns->nodes[1]; + if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) { + parents = MP_PARSE_NODE_NULL; + } + compile_trailer_paren_helper(comp, parents, false, 2); + + // return its name (the 'C' in class C(...):") + return cscope->simple_name; +} + +// returns true if it was a built-in decorator (even if the built-in had an error) +STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_node_t *name_nodes, uint *emit_options) { + if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) { + return false; + } + + if (name_len != 2) { + compile_syntax_error(comp, name_nodes[0], "invalid micropython decorator"); + return true; + } + + qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]); + if (attr == MP_QSTR_bytecode) { + *emit_options = MP_EMIT_OPT_BYTECODE; +#if MICROPY_EMIT_NATIVE + } else if (attr == MP_QSTR_native) { + *emit_options = MP_EMIT_OPT_NATIVE_PYTHON; + } else if (attr == MP_QSTR_viper) { + *emit_options = MP_EMIT_OPT_VIPER; +#endif + #if MICROPY_EMIT_INLINE_ASM + } else if (attr == ASM_DECORATOR_QSTR) { + *emit_options = MP_EMIT_OPT_ASM; + #endif + } else { + compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator"); + } + + return true; +} + +STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { + // get the list of decorators + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns->nodes[0], PN_decorators, &nodes); + + // inherit emit options for this function/class definition + uint emit_options = comp->scope_cur->emit_options; + + // compile each decorator + int num_built_in_decorators = 0; + for (int i = 0; i < n; i++) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be + mp_parse_node_struct_t *pns_decorator = (mp_parse_node_struct_t*)nodes[i]; + + // nodes[0] contains the decorator function, which is a dotted name + mp_parse_node_t *name_nodes; + int name_len = mp_parse_node_extract_list(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes); + + // check for built-in decorators + if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) { + // this was a built-in + num_built_in_decorators += 1; + + } else { + // not a built-in, compile normally + + // compile the decorator function + compile_node(comp, name_nodes[0]); + for (int j = 1; j < name_len; j++) { + assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]), MP_EMIT_ATTR_LOAD); + } + + // nodes[1] contains arguments to the decorator function, if any + if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) { + // call the decorator function with the arguments in nodes[1] + compile_node(comp, pns_decorator->nodes[1]); + } + } + } + + // compile the body (funcdef, async funcdef or classdef) and get its name + mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1]; + qstr body_name = 0; + if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) { + body_name = compile_funcdef_helper(comp, pns_body, emit_options); + #if MICROPY_PY_ASYNC_AWAIT + } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) { + assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0])); + mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0]; + body_name = compile_funcdef_helper(comp, pns0, emit_options); + scope_t *fscope = (scope_t*)pns0->nodes[4]; + fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + #endif + } else { + assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be + body_name = compile_classdef_helper(comp, pns_body, emit_options); + } + + // call each decorator + for (int i = 0; i < n - num_built_in_decorators; i++) { + EMIT_ARG(call_function, 1, 0, 0); + } + + // store func/class object into name + compile_store_id(comp, body_name); +} + +STATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) { + qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options); + // store function object into function name + compile_store_id(comp, fname); +} + +STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { + if (MP_PARSE_NODE_IS_ID(pn)) { + compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn)); + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + + compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node + + if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) { + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); + for (int i = 0; i < n - 1; i++) { + compile_node(comp, pns1->nodes[i]); + } + assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1])); + pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; + } + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { + compile_node(comp, pns1->nodes[0]); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { + assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_DELETE); + } else { + goto cannot_delete; + } + } else { + goto cannot_delete; + } + + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) { + pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; + if (MP_PARSE_NODE_IS_NULL(pn)) { + goto cannot_delete; + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp + + if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) { + // sequence of one item, with trailing comma + assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0])); + c_del_stmt(comp, pns->nodes[0]); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) { + // sequence of many items + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); + c_del_stmt(comp, pns->nodes[0]); + for (int i = 0; i < n; i++) { + c_del_stmt(comp, pns1->nodes[i]); + } + } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) { + goto cannot_delete; + } else { + // sequence with 2 items + goto sequence_with_2_items; + } + } else { + // sequence with 2 items + sequence_with_2_items: + c_del_stmt(comp, pns->nodes[0]); + c_del_stmt(comp, pns->nodes[1]); + } + } + } else { + // some arbitrary statement that we can't delete (eg del 1) + goto cannot_delete; + } + + return; + +cannot_delete: + compile_syntax_error(comp, (mp_parse_node_t)pn, "can't delete expression"); +} + +STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt); +} + +STATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + uint16_t label; + const char *error_msg; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) { + label = comp->break_label; + error_msg = "'break' outside loop"; + } else { + label = comp->continue_label; + error_msg = "'continue' outside loop"; + } + if (label == INVALID_LABEL) { + compile_syntax_error(comp, (mp_parse_node_t)pns, error_msg); + } + assert(comp->cur_except_level >= comp->break_continue_except_level); + EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level); +} + +STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->scope_cur->kind != SCOPE_FUNCTION) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "'return' outside function"); + return; + } + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // no argument to 'return', so return None + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } else if (MICROPY_COMP_RETURN_IF_EXPR + && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) { + // special case when returning an if-expression; to match CPython optimisation + mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0]; + mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1]; + + uint l_fail = comp_next_label(comp); + c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition + compile_node(comp, pns_test_if_expr->nodes[0]); // success value + EMIT(return_value); + EMIT_ARG(label_assign, l_fail); + compile_node(comp, pns_test_if_else->nodes[1]); // failure value + } else { + compile_node(comp, pns->nodes[0]); + } + EMIT(return_value); +} + +STATIC void compile_yield_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_node(comp, pns->nodes[0]); + EMIT(pop_top); +} + +STATIC void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // raise + EMIT_ARG(raise_varargs, 0); + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) { + // raise x from y + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + compile_node(comp, pns->nodes[0]); + compile_node(comp, pns->nodes[1]); + EMIT_ARG(raise_varargs, 2); + } else { + // raise x + compile_node(comp, pns->nodes[0]); + EMIT_ARG(raise_varargs, 1); + } +} + +// q_base holds the base of the name +// eg a -> q_base=a +// a.b.c -> q_base=a +STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { + bool is_as = false; + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + // a name of the form x as y; unwrap it + *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); + pn = pns->nodes[0]; + is_as = true; + } + if (MP_PARSE_NODE_IS_NULL(pn)) { + // empty name (eg, from . import x) + *q_base = MP_QSTR_; + EMIT_ARG(import, MP_QSTR_, MP_EMIT_IMPORT_NAME); // import the empty string + } else if (MP_PARSE_NODE_IS_ID(pn)) { + // just a simple name + qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn); + if (!is_as) { + *q_base = q_full; + } + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + { + // a name of the form a.b.c + if (!is_as) { + *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + } + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + int len = n - 1; + for (int i = 0; i < n; i++) { + len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); + } + char *q_ptr = mp_local_alloc(len); + char *str_dest = q_ptr; + for (int i = 0; i < n; i++) { + if (i > 0) { + *str_dest++ = '.'; + } + size_t str_src_len; + const byte *str_src = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &str_src_len); + memcpy(str_dest, str_src, str_src_len); + str_dest += str_src_len; + } + qstr q_full = qstr_from_strn(q_ptr, len); + mp_local_free(q_ptr); + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); + if (is_as) { + for (int i = 1; i < n; i++) { + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD); + } + } + } + } +} + +STATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) { + EMIT_ARG(load_const_small_int, 0); // level 0 import + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything + qstr q_base; + do_import_name(comp, pn, &q_base); + compile_store_id(comp, q_base); +} + +STATIC void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) { + apply_to_single_or_list(comp, pns->nodes[0], PN_dotted_as_names, compile_dotted_as_name); +} + +STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { + mp_parse_node_t pn_import_source = pns->nodes[0]; + + // extract the preceding .'s (if any) for a relative import, to compute the import level + uint import_level = 0; + do { + mp_parse_node_t pn_rel; + if (MP_PARSE_NODE_IS_TOKEN(pn_import_source) || MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_one_or_more_period_or_ellipsis)) { + // This covers relative imports with dots only like "from .. import" + pn_rel = pn_import_source; + pn_import_source = MP_PARSE_NODE_NULL; + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) { + // This covers relative imports starting with dot(s) like "from .foo import" + mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t*)pn_import_source; + pn_rel = pns_2b->nodes[0]; + pn_import_source = pns_2b->nodes[1]; + assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be + } else { + // Not a relative import + break; + } + + // get the list of . and/or ...'s + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes); + + // count the total number of .'s + for (int i = 0; i < n; i++) { + if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) { + import_level++; + } else { + // should be an MP_TOKEN_ELLIPSIS + import_level += 3; + } + } + } while (0); + + if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { + EMIT_ARG(load_const_small_int, import_level); + + // build the "fromlist" tuple + EMIT_ARG(load_const_str, MP_QSTR__star_); + EMIT_ARG(build, 1, MP_EMIT_BUILD_TUPLE); + + // do the import + qstr dummy_q; + do_import_name(comp, pn_import_source, &dummy_q); + EMIT_ARG(import, MP_QSTR_NULL, MP_EMIT_IMPORT_STAR); + + } else { + EMIT_ARG(load_const_small_int, import_level); + + // build the "fromlist" tuple + mp_parse_node_t *pn_nodes; + int n = mp_parse_node_extract_list(&pns->nodes[1], PN_import_as_names, &pn_nodes); + for (int i = 0; i < n; i++) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); + mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; + qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id + EMIT_ARG(load_const_str, id2); + } + EMIT_ARG(build, n, MP_EMIT_BUILD_TUPLE); + + // do the import + qstr dummy_q; + do_import_name(comp, pn_import_source, &dummy_q); + for (int i = 0; i < n; i++) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); + mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; + qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id + EMIT_ARG(import, id2, MP_EMIT_IMPORT_FROM); + if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) { + compile_store_id(comp, id2); + } else { + compile_store_id(comp, MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1])); + } + } + EMIT(pop_top); + } +} + +STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { + if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) { + compile_syntax_error(comp, pn, "identifier redefined as global"); + return; + } + id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; + + // if the id exists in the global scope, set its kind to EXPLICIT_GLOBAL + id_info = scope_find_global(comp->scope_cur, qst); + if (id_info != NULL) { + id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; + } +} + +STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { + if (added) { + scope_find_local_and_close_over(comp->scope_cur, id_info, qst); + if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + compile_syntax_error(comp, pn, "no binding for nonlocal found"); + } + } else if (id_info->kind != ID_INFO_KIND_FREE) { + compile_syntax_error(comp, pn, "identifier redefined as nonlocal"); + } +} + +STATIC void compile_global_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->pass == MP_PASS_SCOPE) { + bool is_global = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_global_stmt; + + if (!is_global && comp->scope_cur->kind == SCOPE_MODULE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't declare nonlocal in outer code"); + return; + } + + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); + for (int i = 0; i < n; i++) { + qstr qst = MP_PARSE_NODE_LEAF_ARG(nodes[i]); + bool added; + id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); + if (is_global) { + compile_declare_global(comp, (mp_parse_node_t)pns, qst, added, id_info); + } else { + compile_declare_nonlocal(comp, (mp_parse_node_t)pns, qst, added, id_info); + } + } + } +} + +STATIC void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // with optimisations enabled we don't compile assertions + if (MP_STATE_VM(mp_optimise_value) != 0) { + return; + } + + uint l_end = comp_next_label(comp); + c_if_cond(comp, pns->nodes[0], true, l_end); + EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython + if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { + // assertion message + compile_node(comp, pns->nodes[1]); + EMIT_ARG(call_function, 1, 0, 0); + } + EMIT_ARG(raise_varargs, 1); + EMIT_ARG(label_assign, l_end); +} + +STATIC void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + uint l_end = comp_next_label(comp); + + // optimisation: don't emit anything when "if False" + if (!mp_parse_node_is_const_false(pns->nodes[0])) { + uint l_fail = comp_next_label(comp); + c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition + + compile_node(comp, pns->nodes[1]); // if block + + // optimisation: skip everything else when "if True" + if (mp_parse_node_is_const_true(pns->nodes[0])) { + goto done; + } + + if ( + // optimisation: don't jump over non-existent elif/else blocks + !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])) + // optimisation: don't jump if last instruction was return + && !EMIT(last_emit_was_return_value) + ) { + // jump over elif/else blocks + EMIT_ARG(jump, l_end); + } + + EMIT_ARG(label_assign, l_fail); + } + + // compile elif blocks (if any) + mp_parse_node_t *pn_elif; + int n_elif = mp_parse_node_extract_list(&pns->nodes[2], PN_if_stmt_elif_list, &pn_elif); + for (int i = 0; i < n_elif; i++) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be + mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pn_elif[i]; + + // optimisation: don't emit anything when "if False" + if (!mp_parse_node_is_const_false(pns_elif->nodes[0])) { + uint l_fail = comp_next_label(comp); + c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition + + compile_node(comp, pns_elif->nodes[1]); // elif block + + // optimisation: skip everything else when "elif True" + if (mp_parse_node_is_const_true(pns_elif->nodes[0])) { + goto done; + } + + // optimisation: don't jump if last instruction was return + if (!EMIT(last_emit_was_return_value)) { + EMIT_ARG(jump, l_end); + } + EMIT_ARG(label_assign, l_fail); + } + } + + // compile else block + compile_node(comp, pns->nodes[3]); // can be null + +done: + EMIT_ARG(label_assign, l_end); +} + +#define START_BREAK_CONTINUE_BLOCK \ + uint16_t old_break_label = comp->break_label; \ + uint16_t old_continue_label = comp->continue_label; \ + uint16_t old_break_continue_except_level = comp->break_continue_except_level; \ + uint break_label = comp_next_label(comp); \ + uint continue_label = comp_next_label(comp); \ + comp->break_label = break_label; \ + comp->continue_label = continue_label; \ + comp->break_continue_except_level = comp->cur_except_level; + +#define END_BREAK_CONTINUE_BLOCK \ + comp->break_label = old_break_label; \ + comp->continue_label = old_continue_label; \ + comp->break_continue_except_level = old_break_continue_except_level; + +STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + START_BREAK_CONTINUE_BLOCK + + if (!mp_parse_node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False" + uint top_label = comp_next_label(comp); + if (!mp_parse_node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for "while True" + EMIT_ARG(jump, continue_label); + } + EMIT_ARG(label_assign, top_label); + compile_node(comp, pns->nodes[1]); // body + EMIT_ARG(label_assign, continue_label); + c_if_cond(comp, pns->nodes[0], true, top_label); // condition + } + + // break/continue apply to outer loop (if any) in the else block + END_BREAK_CONTINUE_BLOCK + + compile_node(comp, pns->nodes[2]); // else + + EMIT_ARG(label_assign, break_label); +} + +// This function compiles an optimised for-loop of the form: +// for in range(, , ): +// +// else: +// +// must be an identifier and must be a small-int. +// +// Semantics of for-loop require: +// - final failing value should not be stored in the loop variable +// - if the loop never runs, the loop variable should never be assigned +// - assignments to , or in the body do not alter the loop +// ( is a constant for us, so no need to worry about it changing) +// +// If is a small-int, then the stack during the for-loop contains just +// the current value of . Otherwise, the stack contains then the +// current value of . +STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) { + START_BREAK_CONTINUE_BLOCK + + uint top_label = comp_next_label(comp); + uint entry_label = comp_next_label(comp); + + // put the end value on the stack if it's not a small-int constant + bool end_on_stack = !MP_PARSE_NODE_IS_SMALL_INT(pn_end); + if (end_on_stack) { + compile_node(comp, pn_end); + } + + // compile: start + compile_node(comp, pn_start); + + EMIT_ARG(jump, entry_label); + EMIT_ARG(label_assign, top_label); + + // duplicate next value and store it to var + EMIT(dup_top); + c_assign(comp, pn_var, ASSIGN_STORE); + + // compile body + compile_node(comp, pn_body); + + EMIT_ARG(label_assign, continue_label); + + // compile: var + step + compile_node(comp, pn_step); + EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD); + + EMIT_ARG(label_assign, entry_label); + + // compile: if var end: goto top + if (end_on_stack) { + EMIT(dup_top_two); + EMIT(rot_two); + } else { + EMIT(dup_top); + compile_node(comp, pn_end); + } + assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step)); + if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) { + EMIT_ARG(binary_op, MP_BINARY_OP_LESS); + } else { + EMIT_ARG(binary_op, MP_BINARY_OP_MORE); + } + EMIT_ARG(pop_jump_if, true, top_label); + + // break/continue apply to outer loop (if any) in the else block + END_BREAK_CONTINUE_BLOCK + + // Compile the else block. We must pop the iterator variables before + // executing the else code because it may contain break/continue statements. + uint end_label = 0; + if (!MP_PARSE_NODE_IS_NULL(pn_else)) { + // discard final value of "var", and possible "end" value + EMIT(pop_top); + if (end_on_stack) { + EMIT(pop_top); + } + compile_node(comp, pn_else); + end_label = comp_next_label(comp); + EMIT_ARG(jump, end_label); + EMIT_ARG(adjust_stack_size, 1 + end_on_stack); + } + + EMIT_ARG(label_assign, break_label); + + // discard final value of var that failed the loop condition + EMIT(pop_top); + + // discard value if it's on the stack + if (end_on_stack) { + EMIT(pop_top); + } + + if (!MP_PARSE_NODE_IS_NULL(pn_else)) { + EMIT_ARG(label_assign, end_label); + } +} + +STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // this bit optimises: for in range(...), turning it into an explicitly incremented variable + // this is actually slower, but uses no heap memory + // for viper it will be much, much faster + if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_atom_expr_normal)) { + mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range + && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pns_it->nodes[1]) == PN_trailer_paren) { + mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0]; + mp_parse_node_t *args; + int n_args = mp_parse_node_extract_list(&pn_range_args, PN_arglist, &args); + mp_parse_node_t pn_range_start; + mp_parse_node_t pn_range_end; + mp_parse_node_t pn_range_step; + bool optimize = false; + if (1 <= n_args && n_args <= 3) { + optimize = true; + if (n_args == 1) { + pn_range_start = mp_parse_node_new_small_int(0); + pn_range_end = args[0]; + pn_range_step = mp_parse_node_new_small_int(1); + } else if (n_args == 2) { + pn_range_start = args[0]; + pn_range_end = args[1]; + pn_range_step = mp_parse_node_new_small_int(1); + } else { + pn_range_start = args[0]; + pn_range_end = args[1]; + pn_range_step = args[2]; + // the step must be a non-zero constant integer to do the optimisation + if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step) + || MP_PARSE_NODE_LEAF_SMALL_INT(pn_range_step) == 0) { + optimize = false; + } + } + // arguments must be able to be compiled as standard expressions + if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_start)) { + int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_range_start); + if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { + optimize = false; + } + } + if (optimize && MP_PARSE_NODE_IS_STRUCT(pn_range_end)) { + int k = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_range_end); + if (k == PN_arglist_star || k == PN_arglist_dbl_star || k == PN_argument) { + optimize = false; + } + } + } + if (optimize) { + compile_for_stmt_optimised_range(comp, pns->nodes[0], pn_range_start, pn_range_end, pn_range_step, pns->nodes[2], pns->nodes[3]); + return; + } + } + } + + START_BREAK_CONTINUE_BLOCK + comp->break_label |= MP_EMIT_BREAK_FROM_FOR; + + uint pop_label = comp_next_label(comp); + + compile_node(comp, pns->nodes[1]); // iterator + EMIT_ARG(get_iter, true); + EMIT_ARG(label_assign, continue_label); + EMIT_ARG(for_iter, pop_label); + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable + compile_node(comp, pns->nodes[2]); // body + if (!EMIT(last_emit_was_return_value)) { + EMIT_ARG(jump, continue_label); + } + EMIT_ARG(label_assign, pop_label); + EMIT(for_iter_end); + + // break/continue apply to outer loop (if any) in the else block + END_BREAK_CONTINUE_BLOCK + + compile_node(comp, pns->nodes[3]); // else (may be empty) + + EMIT_ARG(label_assign, break_label); +} + +STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) { + // setup code + uint l1 = comp_next_label(comp); + uint success_label = comp_next_label(comp); + + compile_increase_except_level(comp, l1, MP_EMIT_SETUP_BLOCK_EXCEPT); + + compile_node(comp, pn_body); // body + EMIT(pop_block); + EMIT_ARG(jump, success_label); // jump over exception handler + + EMIT_ARG(label_assign, l1); // start of exception handler + EMIT(start_except_handler); + + // at this point the top of the stack contains the exception instance that was raised + + uint l2 = comp_next_label(comp); + + for (int i = 0; i < n_except; i++) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_excepts[i], PN_try_stmt_except)); // should be + mp_parse_node_struct_t *pns_except = (mp_parse_node_struct_t*)pn_excepts[i]; + + qstr qstr_exception_local = 0; + uint end_finally_label = comp_next_label(comp); + + if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { + // this is a catch all exception handler + if (i + 1 != n_except) { + compile_syntax_error(comp, pn_excepts[i], "default 'except' must be last"); + compile_decrease_except_level(comp); + return; + } + } else { + // this exception handler requires a match to a certain type of exception + mp_parse_node_t pns_exception_expr = pns_except->nodes[0]; + if (MP_PARSE_NODE_IS_STRUCT(pns_exception_expr)) { + mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pns_exception_expr; + if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_try_stmt_as_name) { + // handler binds the exception to a local + pns_exception_expr = pns3->nodes[0]; + qstr_exception_local = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[1]); + } + } + EMIT(dup_top); + compile_node(comp, pns_exception_expr); + EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); + EMIT_ARG(pop_jump_if, false, end_finally_label); + } + + // either discard or store the exception instance + if (qstr_exception_local == 0) { + EMIT(pop_top); + } else { + compile_store_id(comp, qstr_exception_local); + } + + uint l3 = 0; + if (qstr_exception_local != 0) { + l3 = comp_next_label(comp); + compile_increase_except_level(comp, l3, MP_EMIT_SETUP_BLOCK_FINALLY); + } + compile_node(comp, pns_except->nodes[1]); + if (qstr_exception_local != 0) { + EMIT(pop_block); + } + EMIT(pop_except); + if (qstr_exception_local != 0) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(label_assign, l3); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + compile_store_id(comp, qstr_exception_local); + compile_delete_id(comp, qstr_exception_local); + + compile_decrease_except_level(comp); + } + EMIT_ARG(jump, l2); + EMIT_ARG(label_assign, end_finally_label); + EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance + } + + compile_decrease_except_level(comp); + EMIT(end_except_handler); + + EMIT_ARG(label_assign, success_label); + compile_node(comp, pn_else); // else block, can be null + EMIT_ARG(label_assign, l2); +} + +STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) { + uint l_finally_block = comp_next_label(comp); + + compile_increase_except_level(comp, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY); + + if (n_except == 0) { + assert(MP_PARSE_NODE_IS_NULL(pn_else)); + EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state + compile_node(comp, pn_body); + EMIT_ARG(adjust_stack_size, -3); + } else { + compile_try_except(comp, pn_body, n_except, pn_except, pn_else); + } + EMIT(pop_block); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(label_assign, l_finally_block); + compile_node(comp, pn_finally); + + compile_decrease_except_level(comp); +} + +STATIC void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should be + { + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_finally) { + // just try-finally + compile_try_finally(comp, pns->nodes[0], 0, NULL, MP_PARSE_NODE_NULL, pns2->nodes[0]); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_try_stmt_except_and_more) { + // try-except and possibly else and/or finally + mp_parse_node_t *pn_excepts; + int n_except = mp_parse_node_extract_list(&pns2->nodes[0], PN_try_stmt_except_list, &pn_excepts); + if (MP_PARSE_NODE_IS_NULL(pns2->nodes[2])) { + // no finally + compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1]); + } else { + // have finally + compile_try_finally(comp, pns->nodes[0], n_except, pn_excepts, pns2->nodes[1], ((mp_parse_node_struct_t*)pns2->nodes[2])->nodes[0]); + } + } else { + // just try-except + mp_parse_node_t *pn_excepts; + int n_except = mp_parse_node_extract_list(&pns->nodes[1], PN_try_stmt_except_list, &pn_excepts); + compile_try_except(comp, pns->nodes[0], n_except, pn_excepts, MP_PARSE_NODE_NULL); + } + } +} + +STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) { + if (n == 0) { + // no more pre-bits, compile the body of the with + compile_node(comp, body); + } else { + uint l_end = comp_next_label(comp); + if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { + // this pre-bit is of the form "a as b" + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; + compile_node(comp, pns->nodes[0]); + compile_increase_except_level(comp, l_end, MP_EMIT_SETUP_BLOCK_WITH); + c_assign(comp, pns->nodes[1], ASSIGN_STORE); + } else { + // this pre-bit is just an expression + compile_node(comp, nodes[0]); + compile_increase_except_level(comp, l_end, MP_EMIT_SETUP_BLOCK_WITH); + EMIT(pop_top); + } + // compile additional pre-bits and the body + compile_with_stmt_helper(comp, n - 1, nodes + 1, body); + // finish this with block + EMIT_ARG(with_cleanup, l_end); + reserve_labels_for_native(comp, 3); // used by native's with_cleanup + compile_decrease_except_level(comp); + } +} + +STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); + assert(n > 0); + + // compile in a nested fashion + compile_with_stmt_helper(comp, n, nodes, pns->nodes[1]); +} + +STATIC void compile_yield_from(compiler_t *comp) { + EMIT_ARG(get_iter, false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(yield, MP_EMIT_YIELD_FROM); + reserve_labels_for_native(comp, 3); +} + +#if MICROPY_PY_ASYNC_AWAIT +STATIC void compile_await_object_method(compiler_t *comp, qstr method) { + EMIT_ARG(load_method, method, false); + EMIT_ARG(call_method, 0, 0, 0); + compile_yield_from(comp); +} + +STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // comp->break_label |= MP_EMIT_BREAK_FROM_FOR; + + qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); + uint while_else_label = comp_next_label(comp); + uint try_exception_label = comp_next_label(comp); + uint try_else_label = comp_next_label(comp); + uint try_finally_label = comp_next_label(comp); + + compile_node(comp, pns->nodes[1]); // iterator + compile_await_object_method(comp, MP_QSTR___aiter__); + compile_store_id(comp, context); + + START_BREAK_CONTINUE_BLOCK + + EMIT_ARG(label_assign, continue_label); + + compile_increase_except_level(comp, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT); + + compile_load_id(comp, context); + compile_await_object_method(comp, MP_QSTR___anext__); + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable + EMIT(pop_block); + EMIT_ARG(jump, try_else_label); + + EMIT_ARG(label_assign, try_exception_label); + EMIT(start_except_handler); + EMIT(dup_top); + EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration); + EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); + EMIT_ARG(pop_jump_if, false, try_finally_label); + EMIT(pop_top); // pop exception instance + EMIT(pop_except); + EMIT_ARG(jump, while_else_label); + + EMIT_ARG(label_assign, try_finally_label); + EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack + compile_decrease_except_level(comp); + EMIT(end_except_handler); + + EMIT_ARG(label_assign, try_else_label); + compile_node(comp, pns->nodes[2]); // body + + EMIT_ARG(jump, continue_label); + // break/continue apply to outer loop (if any) in the else block + END_BREAK_CONTINUE_BLOCK + + EMIT_ARG(label_assign, while_else_label); + compile_node(comp, pns->nodes[3]); // else + + EMIT_ARG(label_assign, break_label); +} + +STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) { + if (n == 0) { + // no more pre-bits, compile the body of the with + compile_node(comp, body); + } else { + uint l_finally_block = comp_next_label(comp); + uint l_aexit_no_exc = comp_next_label(comp); + uint l_ret_unwind_jump = comp_next_label(comp); + uint l_end = comp_next_label(comp); + + if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { + // this pre-bit is of the form "a as b" + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; + compile_node(comp, pns->nodes[0]); + EMIT(dup_top); + compile_await_object_method(comp, MP_QSTR___aenter__); + c_assign(comp, pns->nodes[1], ASSIGN_STORE); + } else { + // this pre-bit is just an expression + compile_node(comp, nodes[0]); + EMIT(dup_top); + compile_await_object_method(comp, MP_QSTR___aenter__); + EMIT(pop_top); + } + + // To keep the Python stack size down, and because we can't access values on + // this stack further down than 3 elements (via rot_three), we don't preload + // __aexit__ (as per normal with) but rather wait until we need it below. + + // Start the try-finally statement + compile_increase_except_level(comp, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY); + + // Compile any additional pre-bits of the "async with", and also the body + EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state + compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); + EMIT_ARG(adjust_stack_size, -3); + + // Finish the "try" block + EMIT(pop_block); + + // At this point, after the with body has executed, we have 3 cases: + // 1. no exception, we just fall through to this point; stack: (..., ctx_mgr) + // 2. exception propagating out, we get to the finally block; stack: (..., ctx_mgr, exc) + // 3. return or unwind jump, we get to the finally block; stack: (..., ctx_mgr, X, INT) + + // Handle case 1: call __aexit__ + // Stack: (..., ctx_mgr) + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception + EMIT(rot_two); + EMIT_ARG(jump, l_aexit_no_exc); // jump to code below to call __aexit__ + + // Start of "finally" block + // At this point we have case 2 or 3, we detect which one by the TOS being an exception or not + EMIT_ARG(label_assign, l_finally_block); + + // Detect if TOS an exception or not + EMIT(dup_top); + EMIT_LOAD_GLOBAL(MP_QSTR_Exception); + EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); + EMIT_ARG(pop_jump_if, false, l_ret_unwind_jump); // if not an exception then we have case 3 + + // Handle case 2: call __aexit__ and either swallow or re-raise the exception + // Stack: (..., ctx_mgr, exc) + EMIT(dup_top); + EMIT(rot_three); + EMIT(rot_two); + EMIT_ARG(load_method, MP_QSTR___aexit__, false); + EMIT(rot_three); + EMIT(rot_three); + EMIT(dup_top); + #if MICROPY_CPYTHON_COMPAT + EMIT_ARG(attr, MP_QSTR___class__, MP_EMIT_ATTR_LOAD); // get type(exc) + #else + compile_load_id(comp, MP_QSTR_type); + EMIT(rot_two); + EMIT_ARG(call_function, 1, 0, 0); // get type(exc) + #endif + EMIT(rot_two); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // dummy traceback value + // Stack: (..., exc, __aexit__, ctx_mgr, type(exc), exc, None) + EMIT_ARG(call_method, 3, 0, 0); + compile_yield_from(comp); + EMIT_ARG(pop_jump_if, false, l_end); + EMIT(pop_top); // pop exception + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // replace with None to swallow exception + EMIT_ARG(jump, l_end); + EMIT_ARG(adjust_stack_size, 2); + + // Handle case 3: call __aexit__ + // Stack: (..., ctx_mgr, X, INT) + EMIT_ARG(label_assign, l_ret_unwind_jump); + EMIT(rot_three); + EMIT(rot_three); + EMIT_ARG(label_assign, l_aexit_no_exc); + EMIT_ARG(load_method, MP_QSTR___aexit__, false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT(dup_top); + EMIT(dup_top); + EMIT_ARG(call_method, 3, 0, 0); + compile_yield_from(comp); + EMIT(pop_top); + EMIT_ARG(adjust_stack_size, -1); + + // End of "finally" block + // Stack can have one of three configurations: + // a. (..., None) - from either case 1, or case 2 with swallowed exception + // b. (..., exc) - from case 2 with re-raised exception + // c. (..., X, INT) - from case 3 + EMIT_ARG(label_assign, l_end); + compile_decrease_except_level(comp); + } +} + +STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); + assert(n > 0); + + // compile in a nested fashion + compile_async_with_stmt_helper(comp, n, nodes, pns->nodes[1]); +} + +STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[0])); + mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_funcdef) { + // async def + compile_funcdef(comp, pns0); + scope_t *fscope = (scope_t*)pns0->nodes[4]; + fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { + // async for + compile_async_for_stmt(comp, pns0); + } else { + // async with + assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt); + compile_async_with_stmt(comp, pns0); + } +} +#endif + +STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { + if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) { + // for REPL, evaluate then print the expression + compile_load_id(comp, MP_QSTR___repl_print__); + compile_node(comp, pns->nodes[0]); + EMIT_ARG(call_function, 1, 0, 0); + EMIT(pop_top); + + } else { + // for non-REPL, evaluate then discard the expression + if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) + || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object)) { + // do nothing with a lonely constant + } else { + compile_node(comp, pns->nodes[0]); // just an expression + EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack + } + } + } else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + int kind = MP_PARSE_NODE_STRUCT_KIND(pns1); + if (kind == PN_expr_stmt_augassign) { + c_assign(comp, pns->nodes[0], ASSIGN_AUG_LOAD); // lhs load for aug assign + compile_node(comp, pns1->nodes[1]); // rhs + assert(MP_PARSE_NODE_IS_TOKEN(pns1->nodes[0])); + mp_binary_op_t op; + switch (MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])) { + case MP_TOKEN_DEL_PIPE_EQUAL: op = MP_BINARY_OP_INPLACE_OR; break; + case MP_TOKEN_DEL_CARET_EQUAL: op = MP_BINARY_OP_INPLACE_XOR; break; + case MP_TOKEN_DEL_AMPERSAND_EQUAL: op = MP_BINARY_OP_INPLACE_AND; break; + case MP_TOKEN_DEL_DBL_LESS_EQUAL: op = MP_BINARY_OP_INPLACE_LSHIFT; break; + case MP_TOKEN_DEL_DBL_MORE_EQUAL: op = MP_BINARY_OP_INPLACE_RSHIFT; break; + case MP_TOKEN_DEL_PLUS_EQUAL: op = MP_BINARY_OP_INPLACE_ADD; break; + case MP_TOKEN_DEL_MINUS_EQUAL: op = MP_BINARY_OP_INPLACE_SUBTRACT; break; + case MP_TOKEN_DEL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_MULTIPLY; break; + case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break; + case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break; + case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break; + case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break; + } + EMIT_ARG(binary_op, op); + c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign + } else if (kind == PN_expr_stmt_assign_list) { + int rhs = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) - 1; + compile_node(comp, pns1->nodes[rhs]); // rhs + // following CPython, we store left-most first + if (rhs > 0) { + EMIT(dup_top); + } + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store + for (int i = 0; i < rhs; i++) { + if (i + 1 < rhs) { + EMIT(dup_top); + } + c_assign(comp, pns1->nodes[i], ASSIGN_STORE); // middle store + } + } else { + plain_assign: + #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) + && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) { + mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; + pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0); + // Can only optimise a tuple-to-tuple assignment when all of the following hold: + // - equal number of items in LHS and RHS tuples + // - 2 or 3 items in the tuples + // - there are no star expressions in the LHS tuple + if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) + && (n_pns0 == 2 + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + || n_pns0 == 3 + #endif + ) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) + #endif + ) { + // Optimisation for a, b = c, d or a, b, c = d, e, f + compile_node(comp, pns1->nodes[0]); // rhs + compile_node(comp, pns1->nodes[1]); // rhs + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + compile_node(comp, pns1->nodes[2]); // rhs + EMIT(rot_three); + } + #endif + EMIT(rot_two); + c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store + c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store + } + #endif + return; + } + } + #endif + + compile_node(comp, pns->nodes[1]); // rhs + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store + } + } else { + goto plain_assign; + } +} + +STATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else)); + mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1]; + + uint l_fail = comp_next_label(comp); + uint l_end = comp_next_label(comp); + c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition + compile_node(comp, pns->nodes[0]); // success value + EMIT_ARG(jump, l_end); + EMIT_ARG(label_assign, l_fail); + EMIT_ARG(adjust_stack_size, -1); // adjust stack size + compile_node(comp, pns_test_if_else->nodes[1]); // failure value + EMIT_ARG(label_assign, l_end); +} + +STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->pass == MP_PASS_SCOPE) { + // create a new scope for this lambda + scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (mp_parse_node_t)pns, comp->scope_cur->emit_options); + // store the lambda scope so the compiling function (this one) can use it at each pass + pns->nodes[2] = (mp_parse_node_t)s; + } + + // get the scope for this lambda + scope_t *this_scope = (scope_t*)pns->nodes[2]; + + // compile the lambda definition + compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist); +} + +STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { + bool cond = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test; + uint l_end = comp_next_label(comp); + int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (int i = 0; i < n; i += 1) { + compile_node(comp, pns->nodes[i]); + if (i + 1 < n) { + EMIT_ARG(jump_if_or_pop, cond, l_end); + } + } + EMIT_ARG(label_assign, l_end); +} + +STATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_node(comp, pns->nodes[0]); + EMIT_ARG(unary_op, MP_UNARY_OP_NOT); +} + +STATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + compile_node(comp, pns->nodes[0]); + bool multi = (num_nodes > 3); + uint l_fail = 0; + if (multi) { + l_fail = comp_next_label(comp); + } + for (int i = 1; i + 1 < num_nodes; i += 2) { + compile_node(comp, pns->nodes[i + 1]); + if (i + 2 < num_nodes) { + EMIT(dup_top); + EMIT(rot_three); + } + if (MP_PARSE_NODE_IS_TOKEN(pns->nodes[i])) { + mp_binary_op_t op; + switch (MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])) { + case MP_TOKEN_OP_LESS: op = MP_BINARY_OP_LESS; break; + case MP_TOKEN_OP_MORE: op = MP_BINARY_OP_MORE; break; + case MP_TOKEN_OP_DBL_EQUAL: op = MP_BINARY_OP_EQUAL; break; + case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break; + case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break; + case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break; + case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break; + } + EMIT_ARG(binary_op, op); + } else { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])); // should be + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[i]; + int kind = MP_PARSE_NODE_STRUCT_KIND(pns2); + if (kind == PN_comp_op_not_in) { + EMIT_ARG(binary_op, MP_BINARY_OP_NOT_IN); + } else { + assert(kind == PN_comp_op_is); // should be + if (MP_PARSE_NODE_IS_NULL(pns2->nodes[0])) { + EMIT_ARG(binary_op, MP_BINARY_OP_IS); + } else { + EMIT_ARG(binary_op, MP_BINARY_OP_IS_NOT); + } + } + } + if (i + 2 < num_nodes) { + EMIT_ARG(jump_if_or_pop, false, l_fail); + } + } + if (multi) { + uint l_end = comp_next_label(comp); + EMIT_ARG(jump, l_end); + EMIT_ARG(label_assign, l_fail); + EMIT_ARG(adjust_stack_size, 1); + EMIT(rot_two); + EMIT(pop_top); + EMIT_ARG(label_assign, l_end); + } +} + +STATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "*x must be assignment target"); +} + +STATIC void compile_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns) { + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_xor_expr - PN_expr == MP_BINARY_OP_XOR); + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_and_expr - PN_expr == MP_BINARY_OP_AND); + mp_binary_op_t binary_op = MP_BINARY_OP_OR + MP_PARSE_NODE_STRUCT_KIND(pns) - PN_expr; + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + compile_node(comp, pns->nodes[0]); + for (int i = 1; i < num_nodes; ++i) { + compile_node(comp, pns->nodes[i]); + EMIT_ARG(binary_op, binary_op); + } +} + +STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) { + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + compile_node(comp, pns->nodes[0]); + for (int i = 1; i + 1 < num_nodes; i += 2) { + compile_node(comp, pns->nodes[i + 1]); + mp_binary_op_t op; + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]); + switch (tok) { + case MP_TOKEN_OP_PLUS: op = MP_BINARY_OP_ADD; break; + case MP_TOKEN_OP_MINUS: op = MP_BINARY_OP_SUBTRACT; break; + case MP_TOKEN_OP_STAR: op = MP_BINARY_OP_MULTIPLY; break; + case MP_TOKEN_OP_DBL_SLASH: op = MP_BINARY_OP_FLOOR_DIVIDE; break; + case MP_TOKEN_OP_SLASH: op = MP_BINARY_OP_TRUE_DIVIDE; break; + case MP_TOKEN_OP_PERCENT: op = MP_BINARY_OP_MODULO; break; + case MP_TOKEN_OP_DBL_LESS: op = MP_BINARY_OP_LSHIFT; break; + default: + assert(tok == MP_TOKEN_OP_DBL_MORE); + op = MP_BINARY_OP_RSHIFT; + break; + } + EMIT_ARG(binary_op, op); + } +} + +STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_node(comp, pns->nodes[1]); + mp_unary_op_t op; + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + switch (tok) { + case MP_TOKEN_OP_PLUS: op = MP_UNARY_OP_POSITIVE; break; + case MP_TOKEN_OP_MINUS: op = MP_UNARY_OP_NEGATIVE; break; + default: + assert(tok == MP_TOKEN_OP_TILDE); + op = MP_UNARY_OP_INVERT; + break; + } + EMIT_ARG(unary_op, op); +} + +STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) { + // compile the subject of the expression + compile_node(comp, pns->nodes[0]); + + // compile_atom_expr_await may call us with a NULL node + if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { + return; + } + + // get the array of trailers (known to be an array of PARSE_NODE_STRUCT) + size_t num_trail = 1; + mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t**)&pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) { + num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]); + pns_trail = (mp_parse_node_struct_t**)&pns_trail[0]->nodes[0]; + } + + // the current index into the array of trailers + size_t i = 0; + + // handle special super() call + if (comp->scope_cur->kind == SCOPE_FUNCTION + && MP_PARSE_NODE_IS_ID(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren + && MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) { + // at this point we have matched "super()" within a function + + // load the class for super to search for a parent + compile_load_id(comp, MP_QSTR___class__); + + // look for first argument to function (assumes it's "self") + bool found = false; + id_info_t *id = &comp->scope_cur->id_info[0]; + for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) { + if (id->flags & ID_FLAG_IS_PARAM) { + // first argument found; load it + compile_load_id(comp, id->qst); + found = true; + break; + } + } + if (!found) { + compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0], + "super() can't find self"); // really a TypeError + return; + } + + if (num_trail >= 3 + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[1]) == PN_trailer_period + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[2]) == PN_trailer_paren) { + // optimisation for method calls super().f(...), to eliminate heap allocation + mp_parse_node_struct_t *pns_period = pns_trail[1]; + mp_parse_node_struct_t *pns_paren = pns_trail[2]; + EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), true); + compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); + i = 3; + } else { + // a super() call + EMIT_ARG(call_function, 2, 0, 0); + i = 1; + } + } + + // compile the remaining trailers + for (; i < num_trail; i++) { + if (i + 1 < num_trail + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period + && MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) { + // optimisation for method calls a.f(...), following PyPy + mp_parse_node_struct_t *pns_period = pns_trail[i]; + mp_parse_node_struct_t *pns_paren = pns_trail[i + 1]; + EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), false); + compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); + i += 1; + } else { + // node is one of: trailer_paren, trailer_bracket, trailer_period + compile_node(comp, (mp_parse_node_t)pns_trail[i]); + } + } +} + +STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_generic_all_nodes(comp, pns); // 2 nodes, arguments of power + EMIT_ARG(binary_op, MP_BINARY_OP_POWER); +} + +STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) { + // function to call is on top of stack + + // get the list of arguments + mp_parse_node_t *args; + int n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &args); + + // compile the arguments + // Rather than calling compile_node on the list, we go through the list of args + // explicitly here so that we can count the number of arguments and give sensible + // error messages. + int n_positional = n_positional_extra; + uint n_keyword = 0; + uint star_flags = 0; + mp_parse_node_struct_t *star_args_node = NULL, *dblstar_args_node = NULL; + for (int i = 0; i < n_args; i++) { + if (MP_PARSE_NODE_IS_STRUCT(args[i])) { + mp_parse_node_struct_t *pns_arg = (mp_parse_node_struct_t*)args[i]; + if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_star) { + if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) { + compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "can't have multiple *x"); + return; + } + star_flags |= MP_EMIT_STAR_FLAG_SINGLE; + star_args_node = pns_arg; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_arglist_dbl_star) { + if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { + compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "can't have multiple **x"); + return; + } + star_flags |= MP_EMIT_STAR_FLAG_DOUBLE; + dblstar_args_node = pns_arg; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns_arg) == PN_argument) { + if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns_arg->nodes[1], PN_comp_for)) { + if (!MP_PARSE_NODE_IS_ID(pns_arg->nodes[0])) { + compile_syntax_error(comp, (mp_parse_node_t)pns_arg, "LHS of keyword arg must be an id"); + return; + } + EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns_arg->nodes[0])); + compile_node(comp, pns_arg->nodes[1]); + n_keyword += 1; + } else { + compile_comprehension(comp, pns_arg, SCOPE_GEN_EXPR); + n_positional++; + } + } else { + goto normal_argument; + } + } else { + normal_argument: + if (star_flags) { + compile_syntax_error(comp, args[i], "non-keyword arg after */**"); + return; + } + if (n_keyword > 0) { + compile_syntax_error(comp, args[i], "non-keyword arg after keyword arg"); + return; + } + compile_node(comp, args[i]); + n_positional++; + } + } + + // compile the star/double-star arguments if we had them + // if we had one but not the other then we load "null" as a place holder + if (star_flags != 0) { + if (star_args_node == NULL) { + EMIT(load_null); + } else { + compile_node(comp, star_args_node->nodes[0]); + } + if (dblstar_args_node == NULL) { + EMIT(load_null); + } else { + compile_node(comp, dblstar_args_node->nodes[0]); + } + } + + // emit the function/method call + if (is_method_call) { + EMIT_ARG(call_method, n_positional, n_keyword, star_flags); + } else { + EMIT_ARG(call_function, n_positional, n_keyword, star_flags); + } +} + +// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node +STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) { + assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2); + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for)); + mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1]; + + if (comp->pass == MP_PASS_SCOPE) { + // create a new scope for this comprehension + scope_t *s = scope_new_and_link(comp, kind, (mp_parse_node_t)pns, comp->scope_cur->emit_options); + // store the comprehension scope so the compiling function (this one) can use it at each pass + pns_comp_for->nodes[3] = (mp_parse_node_t)s; + } + + // get the scope for this comprehension + scope_t *this_scope = (scope_t*)pns_comp_for->nodes[3]; + + // compile the comprehension + close_over_variables_etc(comp, this_scope, 0, 0); + + compile_node(comp, pns_comp_for->nodes[1]); // source of the iterator + if (kind == SCOPE_GEN_EXPR) { + EMIT_ARG(get_iter, false); + } + EMIT_ARG(call_function, 1, 0, 0); +} + +STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // an empty tuple + c_tuple(comp, MP_PARSE_NODE_NULL, NULL); + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1])); + if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { + // tuple of one item, with trailing comma + assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); + c_tuple(comp, pns->nodes[0], NULL); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { + // tuple of many items + c_tuple(comp, pns->nodes[0], pns2); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { + // generator expression + compile_comprehension(comp, pns, SCOPE_GEN_EXPR); + } else { + // tuple with 2 items + goto tuple_with_2_items; + } + } else { + // tuple with 2 items + tuple_with_2_items: + c_tuple(comp, MP_PARSE_NODE_NULL, pns); + } + } +} + +STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // empty list + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) { + mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pns2->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) { + // list of one item, with trailing comma + assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0])); + compile_node(comp, pns2->nodes[0]); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) { + // list of many items + compile_node(comp, pns2->nodes[0]); + compile_generic_all_nodes(comp, pns3); + EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) { + // list comprehension + compile_comprehension(comp, pns2, SCOPE_LIST_COMP); + } else { + // list with 2 items + goto list_with_2_items; + } + } else { + // list with 2 items + list_with_2_items: + compile_node(comp, pns2->nodes[0]); + compile_node(comp, pns2->nodes[1]); + EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST); + } + } else { + // list with 1 item + compile_node(comp, pns->nodes[0]); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); + } +} + +STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { + mp_parse_node_t pn = pns->nodes[0]; + if (MP_PARSE_NODE_IS_NULL(pn)) { + // empty dict + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { + pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { + // dict with one element + EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); + compile_node(comp, pn); + EMIT(store_map); + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) { + // dict/set with multiple elements + + // get tail elements (2nd, 3rd, ...) + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes); + + // first element sets whether it's a dict or set + bool is_dict; + if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { + // a dictionary + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); + compile_node(comp, pns->nodes[0]); + EMIT(store_map); + is_dict = true; + } else { + // a set + compile_node(comp, pns->nodes[0]); // 1st value of set + is_dict = false; + } + + // process rest of elements + for (int i = 0; i < n; i++) { + mp_parse_node_t pn_i = nodes[i]; + bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn_i, PN_dictorsetmaker_item); + compile_node(comp, pn_i); + if (is_dict) { + if (!is_key_value) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); + } else { + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dict"); + } + return; + } + EMIT(store_map); + } else { + if (is_key_value) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); + } else { + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting just a value for set"); + } + return; + } + } + } + + #if MICROPY_PY_BUILTINS_SET + // if it's a set, build it + if (!is_dict) { + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_SET); + } + #endif + } else { + assert(MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for); // should be + // dict/set comprehension + if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { + // a dictionary comprehension + compile_comprehension(comp, pns, SCOPE_DICT_COMP); + } else { + // a set comprehension + compile_comprehension(comp, pns, SCOPE_SET_COMP); + } + } + } else { + // set with one element + goto set_with_one_element; + } + } else { + // set with one element + set_with_one_element: + #if MICROPY_PY_BUILTINS_SET + compile_node(comp, pn); + EMIT_ARG(build, 1, MP_EMIT_BUILD_SET); + #else + assert(0); + #endif + } +} + +STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { + compile_trailer_paren_helper(comp, pns->nodes[0], false, 0); +} + +STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { + // object who's index we want is on top of stack + compile_node(comp, pns->nodes[0]); // the index + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); +} + +STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) { + // object who's attribute we want is on top of stack + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]), MP_EMIT_ATTR_LOAD); // attribute to get +} + +#if MICROPY_PY_BUILTINS_SLICE +STATIC void compile_subscript(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_2) { + compile_node(comp, pns->nodes[0]); // start of slice + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be + pns = (mp_parse_node_struct_t*)pns->nodes[1]; + } else { + // pns is a PN_subscript_3, load None for start of slice + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } + + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be + mp_parse_node_t pn = pns->nodes[0]; + if (MP_PARSE_NODE_IS_NULL(pn)) { + // [?:] + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); + } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { + pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + pn = pns->nodes[0]; + if (MP_PARSE_NODE_IS_NULL(pn)) { + // [?::] + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); + } else { + // [?::x] + compile_node(comp, pn); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); + } + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) { + compile_node(comp, pns->nodes[0]); + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be + pns = (mp_parse_node_struct_t*)pns->nodes[1]; + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // [?:x:] + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); + } else { + // [?:x:x] + compile_node(comp, pns->nodes[0]); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); + } + } else { + // [?:x] + compile_node(comp, pn); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); + } + } else { + // [?:x] + compile_node(comp, pn); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); + } +} +#endif // MICROPY_PY_BUILTINS_SLICE + +STATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) { + // if this is called then we are compiling a dict key:value pair + compile_node(comp, pns->nodes[1]); // value + compile_node(comp, pns->nodes[0]); // key +} + +STATIC void compile_classdef(compiler_t *comp, mp_parse_node_struct_t *pns) { + qstr cname = compile_classdef_helper(comp, pns, comp->scope_cur->emit_options); + // store class object into class name + compile_store_id(comp, cname); +} + +STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "'yield' outside function"); + return; + } + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); + reserve_labels_for_native(comp, 1); + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + compile_node(comp, pns->nodes[0]); + compile_yield_from(comp); + } else { + compile_node(comp, pns->nodes[0]); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); + reserve_labels_for_native(comp, 1); + } +} + +#if MICROPY_PY_ASYNC_AWAIT +STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "'await' outside function"); + return; + } + compile_atom_expr_normal(comp, pns); + compile_yield_from(comp); +} +#endif + +STATIC mp_obj_t get_const_object(mp_parse_node_struct_t *pns) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // nodes are 32-bit pointers, but need to extract 64-bit object + return (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32); + #else + return (mp_obj_t)pns->nodes[0]; + #endif +} + +STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) { + #if MICROPY_EMIT_NATIVE + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; + #endif + EMIT_ARG(load_const_obj, get_const_object(pns)); +} + +typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*); +STATIC const compile_function_t compile_function[] = { +// only define rules with a compile function +#define c(f) compile_##f +#define DEF_RULE(rule, comp, kind, ...) comp, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef c +#undef DEF_RULE +#undef DEF_RULE_NC + compile_const_object, +}; + +STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { + if (MP_PARSE_NODE_IS_NULL(pn)) { + // pass + } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { + mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn); + #if MICROPY_DYNAMIC_COMPILER + mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1)); + if ((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask) { + // integer fits in target runtime's small-int + EMIT_ARG(load_const_small_int, arg); + } else { + // integer doesn't fit, so create a multi-precision int object + // (but only create the actual object on the last pass) + if (comp->pass != MP_PASS_EMIT) { + EMIT_ARG(load_const_obj, mp_const_none); + } else { + EMIT_ARG(load_const_obj, mp_obj_new_int_from_ll(arg)); + } + #if MICROPY_EMIT_NATIVE + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; + #endif + } + #else + EMIT_ARG(load_const_small_int, arg); + #endif + } else if (MP_PARSE_NODE_IS_LEAF(pn)) { + uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); + switch (MP_PARSE_NODE_LEAF_KIND(pn)) { + case MP_PARSE_NODE_ID: compile_load_id(comp, arg); break; + case MP_PARSE_NODE_STRING: EMIT_ARG(load_const_str, arg); break; + case MP_PARSE_NODE_BYTES: + // only create and load the actual bytes object on the last pass + if (comp->pass != MP_PASS_EMIT) { + EMIT_ARG(load_const_obj, mp_const_none); + } else { + size_t len; + const byte *data = qstr_data(arg, &len); + EMIT_ARG(load_const_obj, mp_obj_new_bytes(data, len)); + } + #if MICROPY_EMIT_NATIVE + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; + #endif + break; + case MP_PARSE_NODE_TOKEN: default: + if (arg == MP_TOKEN_NEWLINE) { + // this can occur when file_input lets through a NEWLINE (eg if file starts with a newline) + // or when single_input lets through a NEWLINE (user enters a blank line) + // do nothing + } else { + EMIT_ARG(load_const_tok, arg); + } + break; + } + } else { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + EMIT_ARG(set_source_line, pns->source_line); + assert(MP_PARSE_NODE_STRUCT_KIND(pns) <= PN_const_object); + compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)]; + f(comp, pns); + } +} + +#if MICROPY_EMIT_NATIVE +STATIC int compile_viper_type_annotation(compiler_t *comp, mp_parse_node_t pn_annotation) { + int native_type = MP_NATIVE_TYPE_OBJ; + if (MP_PARSE_NODE_IS_NULL(pn_annotation)) { + // No annotation, type defaults to object + } else if (MP_PARSE_NODE_IS_ID(pn_annotation)) { + qstr type_name = MP_PARSE_NODE_LEAF_ARG(pn_annotation); + native_type = mp_native_type_from_qstr(type_name); + if (native_type < 0) { + comp->compile_error = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, "unknown type '%q'", type_name); + native_type = 0; + } + } else { + compile_syntax_error(comp, pn_annotation, "annotation must be an identifier"); + } + return native_type; +} +#endif + +STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) { + // check that **kw is last + if ((comp->scope_cur->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { + compile_syntax_error(comp, pn, "invalid syntax"); + return; + } + + qstr param_name = MP_QSTR_NULL; + uint param_flag = ID_FLAG_IS_PARAM; + mp_parse_node_struct_t *pns = NULL; + if (MP_PARSE_NODE_IS_ID(pn)) { + param_name = MP_PARSE_NODE_LEAF_ARG(pn); + if (comp->have_star) { + // comes after a star, so counts as a keyword-only parameter + comp->scope_cur->num_kwonly_args += 1; + } else { + // comes before a star, so counts as a positional parameter + comp->scope_cur->num_pos_args += 1; + } + } else { + assert(MP_PARSE_NODE_IS_STRUCT(pn)); + pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) { + // named parameter with possible annotation + param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + if (comp->have_star) { + // comes after a star, so counts as a keyword-only parameter + comp->scope_cur->num_kwonly_args += 1; + } else { + // comes before a star, so counts as a positional parameter + comp->scope_cur->num_pos_args += 1; + } + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) { + if (comp->have_star) { + // more than one star + compile_syntax_error(comp, pn, "invalid syntax"); + return; + } + comp->have_star = true; + param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_STAR_PARAM; + if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { + // bare star + // TODO see http://www.python.org/dev/peps/pep-3102/ + //assert(comp->scope_cur->num_dict_params == 0); + pns = NULL; + } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) { + // named star + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; + param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + pns = NULL; + } else { + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)); // should be + // named star with possible annotation + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS; + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + } + } else { + // double star with possible annotation + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star); // should be + param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM; + comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS; + } + } + + if (param_name != MP_QSTR_NULL) { + bool added; + id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added); + if (!added) { + compile_syntax_error(comp, pn, "argument name reused"); + return; + } + id_info->kind = ID_INFO_KIND_LOCAL; + id_info->flags = param_flag; + + #if MICROPY_EMIT_NATIVE + if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER && pn_name == PN_typedargslist_name && pns != NULL) { + id_info->flags |= compile_viper_type_annotation(comp, pns->nodes[1]) << ID_FLAG_VIPER_TYPE_POS; + } + #else + (void)pns; + #endif + } +} + +STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) { + compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star); +} + +STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) { + compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star); +} + +STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pns_comp_for, mp_parse_node_t pn_inner_expr, int for_depth) { + uint l_top = comp_next_label(comp); + uint l_end = comp_next_label(comp); + EMIT_ARG(label_assign, l_top); + EMIT_ARG(for_iter, l_end); + c_assign(comp, pns_comp_for->nodes[0], ASSIGN_STORE); + mp_parse_node_t pn_iter = pns_comp_for->nodes[2]; + + tail_recursion: + if (MP_PARSE_NODE_IS_NULL(pn_iter)) { + // no more nested if/for; compile inner expression + compile_node(comp, pn_inner_expr); + if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); + reserve_labels_for_native(comp, 1); + EMIT(pop_top); + } else { + EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); + } + } else if (MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_if) { + // if condition + mp_parse_node_struct_t *pns_comp_if = (mp_parse_node_struct_t*)pn_iter; + c_if_cond(comp, pns_comp_if->nodes[0], false, l_top); + pn_iter = pns_comp_if->nodes[1]; + goto tail_recursion; + } else { + assert(MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_for); // should be + // for loop + mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter; + compile_node(comp, pns_comp_for2->nodes[1]); + EMIT_ARG(get_iter, true); + compile_scope_comp_iter(comp, pns_comp_for2, pn_inner_expr, for_depth + 1); + } + + EMIT_ARG(jump, l_top); + EMIT_ARG(label_assign, l_end); + EMIT(for_iter_end); +} + +STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) { +#if MICROPY_ENABLE_DOC_STRING + // see http://www.python.org/dev/peps/pep-0257/ + + // look for the first statement + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { + // a statement; fall through + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_file_input_2)) { + // file input; find the first non-newline node + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (int i = 0; i < num_nodes; i++) { + pn = pns->nodes[i]; + if (!(MP_PARSE_NODE_IS_LEAF(pn) && MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN && MP_PARSE_NODE_LEAF_ARG(pn) == MP_TOKEN_NEWLINE)) { + // not a newline, so this is the first statement; finish search + break; + } + } + // if we didn't find a non-newline then it's okay to fall through; pn will be a newline and so doc-string test below will fail gracefully + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_suite_block_stmts)) { + // a list of statements; get the first one + pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; + } else { + return; + } + + // check the first statement for a doc string + if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) + && MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING) + || (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_const_object) + && MP_OBJ_IS_STR(get_const_object((mp_parse_node_struct_t*)pns->nodes[0])))) { + // compile the doc string + compile_node(comp, pns->nodes[0]); + // store the doc string + compile_store_id(comp, MP_QSTR___doc__); + } + } +#else + (void)comp; + (void)pn; +#endif +} + +STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { + comp->pass = pass; + comp->scope_cur = scope; + comp->next_label = 0; + EMIT_ARG(start_pass, pass, scope); + reserve_labels_for_native(comp, 6); // used by native's start_pass + + if (comp->pass == MP_PASS_SCOPE) { + // reset maximum stack sizes in scope + // they will be computed in this first pass + scope->stack_size = 0; + scope->exc_stack_size = 0; + } + + // compile + if (MP_PARSE_NODE_IS_STRUCT_KIND(scope->pn, PN_eval_input)) { + assert(scope->kind == SCOPE_MODULE); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + compile_node(comp, pns->nodes[0]); // compile the expression + EMIT(return_value); + } else if (scope->kind == SCOPE_MODULE) { + if (!comp->is_repl) { + check_for_doc_string(comp, scope->pn); + } + compile_node(comp, scope->pn); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT(return_value); + } else if (scope->kind == SCOPE_FUNCTION) { + assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef); + + // work out number of parameters, keywords and default parameters, and add them to the id_info array + // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) + if (comp->pass == MP_PASS_SCOPE) { + comp->have_star = false; + apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param); + + #if MICROPY_EMIT_NATIVE + if (scope->emit_options == MP_EMIT_OPT_VIPER) { + // Compile return type; pns->nodes[2] is return/whole function annotation + scope->scope_flags |= compile_viper_type_annotation(comp, pns->nodes[2]) << MP_SCOPE_FLAG_VIPERRET_POS; + } + #endif // MICROPY_EMIT_NATIVE + } + + compile_node(comp, pns->nodes[3]); // 3 is function body + // emit return if it wasn't the last opcode + if (!EMIT(last_emit_was_return_value)) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + EMIT(return_value); + } + } else if (scope->kind == SCOPE_LAMBDA) { + assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3); + + // work out number of parameters, keywords and default parameters, and add them to the id_info array + // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc) + if (comp->pass == MP_PASS_SCOPE) { + comp->have_star = false; + apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param); + } + + compile_node(comp, pns->nodes[1]); // 1 is lambda body + + // if the lambda is a generator, then we return None, not the result of the expression of the lambda + if (scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + EMIT(pop_top); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } + EMIT(return_value); + } else if (scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) { + // a bit of a hack at the moment + + assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2); + assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for)); + mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1]; + + // We need a unique name for the comprehension argument (the iterator). + // CPython uses .0, but we should be able to use anything that won't + // clash with a user defined variable. Best to use an existing qstr, + // so we use the blank qstr. + qstr qstr_arg = MP_QSTR_; + if (comp->pass == MP_PASS_SCOPE) { + bool added; + id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added); + assert(added); + id_info->kind = ID_INFO_KIND_LOCAL; + scope->num_pos_args = 1; + } + + if (scope->kind == SCOPE_LIST_COMP) { + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); + } else if (scope->kind == SCOPE_DICT_COMP) { + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); + #if MICROPY_PY_BUILTINS_SET + } else if (scope->kind == SCOPE_SET_COMP) { + EMIT_ARG(build, 0, MP_EMIT_BUILD_SET); + #endif + } + + // There are 4 slots on the stack for the iterator, and the first one is + // NULL to indicate that the second one points to the iterator object. + if (scope->kind == SCOPE_GEN_EXPR) { + MP_STATIC_ASSERT(MP_OBJ_ITER_BUF_NSLOTS == 4); + EMIT(load_null); + compile_load_id(comp, qstr_arg); + EMIT(load_null); + EMIT(load_null); + } else { + compile_load_id(comp, qstr_arg); + EMIT_ARG(get_iter, true); + } + + compile_scope_comp_iter(comp, pns_comp_for, pns->nodes[0], 0); + + if (scope->kind == SCOPE_GEN_EXPR) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } + EMIT(return_value); + } else { + assert(scope->kind == SCOPE_CLASS); + assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_classdef); + + if (comp->pass == MP_PASS_SCOPE) { + bool added; + id_info_t *id_info = scope_find_or_add_id(scope, MP_QSTR___class__, &added); + assert(added); + id_info->kind = ID_INFO_KIND_LOCAL; + } + + compile_load_id(comp, MP_QSTR___name__); + compile_store_id(comp, MP_QSTR___module__); + EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name + compile_store_id(comp, MP_QSTR___qualname__); + + check_for_doc_string(comp, pns->nodes[2]); + compile_node(comp, pns->nodes[2]); // 2 is class body + + id_info_t *id = scope_find(scope, MP_QSTR___class__); + assert(id != NULL); + if (id->kind == ID_INFO_KIND_LOCAL) { + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } else { + EMIT_LOAD_FAST(MP_QSTR___class__, id->local_num); + } + EMIT(return_value); + } + + EMIT(end_pass); + + // make sure we match all the exception levels + assert(comp->cur_except_level == 0); +} + +#if MICROPY_EMIT_INLINE_ASM +// requires 3 passes: SCOPE, CODE_SIZE, EMIT +STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) { + comp->pass = pass; + comp->scope_cur = scope; + comp->next_label = 0; + + if (scope->kind != SCOPE_FUNCTION) { + compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler must be a function"); + return; + } + + if (comp->pass > MP_PASS_SCOPE) { + EMIT_INLINE_ASM_ARG(start_pass, comp->pass, &comp->compile_error); + } + + // get the function definition parse node + assert(MP_PARSE_NODE_IS_STRUCT(scope->pn)); + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn; + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef); + + //qstr f_id = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // function name + + // parameters are in pns->nodes[1] + if (comp->pass == MP_PASS_CODE_SIZE) { + mp_parse_node_t *pn_params; + int n_params = mp_parse_node_extract_list(&pns->nodes[1], PN_typedargslist, &pn_params); + scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params); + if (comp->compile_error != MP_OBJ_NULL) { + goto inline_asm_error; + } + } + + // pns->nodes[2] is function return annotation + mp_uint_t type_sig = MP_NATIVE_TYPE_INT; + mp_parse_node_t pn_annotation = pns->nodes[2]; + if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) { + // nodes[2] can be null or a test-expr + if (MP_PARSE_NODE_IS_ID(pn_annotation)) { + qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation); + switch (ret_type) { + case MP_QSTR_object: type_sig = MP_NATIVE_TYPE_OBJ; break; + case MP_QSTR_bool: type_sig = MP_NATIVE_TYPE_BOOL; break; + case MP_QSTR_int: type_sig = MP_NATIVE_TYPE_INT; break; + case MP_QSTR_uint: type_sig = MP_NATIVE_TYPE_UINT; break; + default: compile_syntax_error(comp, pn_annotation, "unknown type"); return; + } + } else { + compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier"); + } + } + + mp_parse_node_t pn_body = pns->nodes[3]; // body + mp_parse_node_t *nodes; + int num = mp_parse_node_extract_list(&pn_body, PN_suite_block_stmts, &nodes); + + for (int i = 0; i < num; i++) { + assert(MP_PARSE_NODE_IS_STRUCT(nodes[i])); + mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i]; + if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) { + // no instructions + continue; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_expr_stmt) { + // not an instruction; error + not_an_instruction: + compile_syntax_error(comp, nodes[i], "expecting an assembler instruction"); + return; + } + + // check structure of parse node + assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])); + if (!MP_PARSE_NODE_IS_NULL(pns2->nodes[1])) { + goto not_an_instruction; + } + pns2 = (mp_parse_node_struct_t*)pns2->nodes[0]; + if (MP_PARSE_NODE_STRUCT_KIND(pns2) != PN_atom_expr_normal) { + goto not_an_instruction; + } + if (!MP_PARSE_NODE_IS_ID(pns2->nodes[0])) { + goto not_an_instruction; + } + if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns2->nodes[1], PN_trailer_paren)) { + goto not_an_instruction; + } + + // parse node looks like an instruction + // get instruction name and args + qstr op = MP_PARSE_NODE_LEAF_ARG(pns2->nodes[0]); + pns2 = (mp_parse_node_struct_t*)pns2->nodes[1]; // PN_trailer_paren + mp_parse_node_t *pn_arg; + int n_args = mp_parse_node_extract_list(&pns2->nodes[0], PN_arglist, &pn_arg); + + // emit instructions + if (op == MP_QSTR_label) { + if (!(n_args == 1 && MP_PARSE_NODE_IS_ID(pn_arg[0]))) { + compile_syntax_error(comp, nodes[i], "'label' requires 1 argument"); + return; + } + uint lab = comp_next_label(comp); + if (pass > MP_PASS_SCOPE) { + if (!EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]))) { + compile_syntax_error(comp, nodes[i], "label redefined"); + return; + } + } + } else if (op == MP_QSTR_align) { + if (!(n_args == 1 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { + compile_syntax_error(comp, nodes[i], "'align' requires 1 argument"); + return; + } + if (pass > MP_PASS_SCOPE) { + mp_asm_base_align((mp_asm_base_t*)comp->emit_inline_asm, + MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0])); + } + } else if (op == MP_QSTR_data) { + if (!(n_args >= 2 && MP_PARSE_NODE_IS_SMALL_INT(pn_arg[0]))) { + compile_syntax_error(comp, nodes[i], "'data' requires at least 2 arguments"); + return; + } + if (pass > MP_PASS_SCOPE) { + mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]); + for (uint j = 1; j < n_args; j++) { + if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) { + compile_syntax_error(comp, nodes[i], "'data' requires integer arguments"); + return; + } + mp_asm_base_data((mp_asm_base_t*)comp->emit_inline_asm, + bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j])); + } + } + } else { + if (pass > MP_PASS_SCOPE) { + EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg); + } + } + + if (comp->compile_error != MP_OBJ_NULL) { + pns = pns2; // this is the parse node that had the error + goto inline_asm_error; + } + } + + if (comp->pass > MP_PASS_SCOPE) { + EMIT_INLINE_ASM_ARG(end_pass, type_sig); + + if (comp->pass == MP_PASS_EMIT) { + void *f = mp_asm_base_get_code((mp_asm_base_t*)comp->emit_inline_asm); + mp_emit_glue_assign_native(comp->scope_cur->raw_code, MP_CODE_NATIVE_ASM, + f, mp_asm_base_get_code_size((mp_asm_base_t*)comp->emit_inline_asm), + NULL, comp->scope_cur->num_pos_args, 0, type_sig); + } + } + + if (comp->compile_error != MP_OBJ_NULL) { + // inline assembler had an error; set line for its exception + inline_asm_error: + comp->compile_error_line = pns->source_line; + } +} +#endif + +STATIC void scope_compute_things(scope_t *scope) { + // in MicroPython we put the *x parameter after all other parameters (except **y) + if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { + id_info_t *id_param = NULL; + for (int i = scope->id_info_len - 1; i >= 0; i--) { + id_info_t *id = &scope->id_info[i]; + if (id->flags & ID_FLAG_IS_STAR_PARAM) { + if (id_param != NULL) { + // swap star param with last param + id_info_t temp = *id_param; *id_param = *id; *id = temp; + } + break; + } else if (id_param == NULL && id->flags == ID_FLAG_IS_PARAM) { + id_param = id; + } + } + } + + // in functions, turn implicit globals into explicit globals + // compute the index of each local + scope->num_locals = 0; + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (scope->kind == SCOPE_CLASS && id->qst == MP_QSTR___class__) { + // __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL + continue; + } + if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; + } + #if MICROPY_EMIT_NATIVE + if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { + // This function makes a reference to a global variable + if (scope->emit_options == MP_EMIT_OPT_VIPER + && mp_native_type_from_qstr(id->qst) >= MP_NATIVE_TYPE_INT) { + // A casting operator in viper mode, not a real global reference + } else { + scope->scope_flags |= MP_SCOPE_FLAG_REFGLOBALS; + } + } + #endif + // params always count for 1 local, even if they are a cell + if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) { + id->local_num = scope->num_locals++; + } + } + + // compute the index of cell vars + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + // in MicroPython the cells come right after the fast locals + // parameters are not counted here, since they remain at the start + // of the locals, even if they are cell vars + if (id->kind == ID_INFO_KIND_CELL && !(id->flags & ID_FLAG_IS_PARAM)) { + id->local_num = scope->num_locals; + scope->num_locals += 1; + } + } + + // compute the index of free vars + // make sure they are in the order of the parent scope + if (scope->parent != NULL) { + int num_free = 0; + for (int i = 0; i < scope->parent->id_info_len; i++) { + id_info_t *id = &scope->parent->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { + for (int j = 0; j < scope->id_info_len; j++) { + id_info_t *id2 = &scope->id_info[j]; + if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) { + assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params + // in MicroPython the frees come first, before the params + id2->local_num = num_free; + num_free += 1; + } + } + } + } + // in MicroPython shift all other locals after the free locals + if (num_free > 0) { + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (id->kind != ID_INFO_KIND_FREE || (id->flags & ID_FLAG_IS_PARAM)) { + id->local_num += num_free; + } + } + scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function + scope->num_locals += num_free; + } + } +} + +#if !MICROPY_PERSISTENT_CODE_SAVE +STATIC +#endif +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { + // put compiler state on the stack, it's relatively small + compiler_t comp_state = {0}; + compiler_t *comp = &comp_state; + + comp->source_file = source_file; + comp->is_repl = is_repl; + comp->break_label = INVALID_LABEL; + comp->continue_label = INVALID_LABEL; + + // create the module scope + scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, parse_tree->root, emit_opt); + + // create standard emitter; it's used at least for MP_PASS_SCOPE + emit_t *emit_bc = emit_bc_new(); + + // compile pass 1 + comp->emit = emit_bc; + #if MICROPY_EMIT_NATIVE + comp->emit_method_table = &emit_bc_method_table; + #endif + uint max_num_labels = 0; + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { + if (false) { + #if MICROPY_EMIT_INLINE_ASM + } else if (s->emit_options == MP_EMIT_OPT_ASM) { + compile_scope_inline_asm(comp, s, MP_PASS_SCOPE); + #endif + } else { + compile_scope(comp, s, MP_PASS_SCOPE); + } + + // update maximim number of labels needed + if (comp->next_label > max_num_labels) { + max_num_labels = comp->next_label; + } + } + + // compute some things related to scope and identifiers + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { + scope_compute_things(s); + } + + // set max number of labels now that it's calculated + emit_bc_set_max_num_labels(emit_bc, max_num_labels); + + // compile pass 2 and 3 +#if MICROPY_EMIT_NATIVE + emit_t *emit_native = NULL; +#endif + for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) { + if (false) { + // dummy + + #if MICROPY_EMIT_INLINE_ASM + } else if (s->emit_options == MP_EMIT_OPT_ASM) { + // inline assembly + if (comp->emit_inline_asm == NULL) { + comp->emit_inline_asm = ASM_EMITTER(new)(max_num_labels); + } + comp->emit = NULL; + comp->emit_inline_asm_method_table = &ASM_EMITTER(method_table); + compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + #if MICROPY_EMIT_INLINE_XTENSA + // Xtensa requires an extra pass to compute size of l32r const table + // TODO this can be improved by calculating it during SCOPE pass + // but that requires some other structural changes to the asm emitters + compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE); + #endif + if (comp->compile_error == MP_OBJ_NULL) { + compile_scope_inline_asm(comp, s, MP_PASS_EMIT); + } + #endif + + } else { + + // choose the emit type + + switch (s->emit_options) { + +#if MICROPY_EMIT_NATIVE + case MP_EMIT_OPT_NATIVE_PYTHON: + case MP_EMIT_OPT_VIPER: + if (emit_native == NULL) { + emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels); + } + comp->emit_method_table = &NATIVE_EMITTER(method_table); + comp->emit = emit_native; + break; +#endif // MICROPY_EMIT_NATIVE + + default: + comp->emit = emit_bc; + #if MICROPY_EMIT_NATIVE + comp->emit_method_table = &emit_bc_method_table; + #endif + break; + } + + // need a pass to compute stack size + compile_scope(comp, s, MP_PASS_STACK_SIZE); + + // second last pass: compute code size + if (comp->compile_error == MP_OBJ_NULL) { + compile_scope(comp, s, MP_PASS_CODE_SIZE); + } + + // final pass: emit code + if (comp->compile_error == MP_OBJ_NULL) { + compile_scope(comp, s, MP_PASS_EMIT); + } + } + } + + if (comp->compile_error != MP_OBJ_NULL) { + // if there is no line number for the error then use the line + // number for the start of this scope + compile_error_set_line(comp, comp->scope_cur->pn); + // add a traceback to the exception using relevant source info + mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, + comp->compile_error_line, comp->scope_cur->simple_name); + } + + // free the emitters + + emit_bc_free(emit_bc); +#if MICROPY_EMIT_NATIVE + if (emit_native != NULL) { + NATIVE_EMITTER(free)(emit_native); + } +#endif + #if MICROPY_EMIT_INLINE_ASM + if (comp->emit_inline_asm != NULL) { + ASM_EMITTER(free)(comp->emit_inline_asm); + } + #endif + + // free the parse tree + mp_parse_tree_clear(parse_tree); + + // free the scopes + mp_raw_code_t *outer_raw_code = module_scope->raw_code; + for (scope_t *s = module_scope; s;) { + scope_t *next = s->next; + scope_free(s); + s = next; + } + + if (comp->compile_error != MP_OBJ_NULL) { + nlr_raise(comp->compile_error); + } else { + return outer_raw_code; + } +} + +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl) { + mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, emit_opt, is_repl); + // return function that executes the outer module + return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); +} + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/compile.h b/src/openmv/src/micropython/py/compile.h new file mode 100755 index 0000000..99a17a8 --- /dev/null +++ b/src/openmv/src/micropython/py/compile.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_COMPILE_H +#define MICROPY_INCLUDED_PY_COMPILE_H + +#include "py/lexer.h" +#include "py/parse.h" +#include "py/emitglue.h" + +// the compiler will raise an exception if an error occurred +// the compiler will clear the parse tree before it returns +mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); + +#if MICROPY_PERSISTENT_CODE_SAVE +// this has the same semantics as mp_compile +mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt, bool is_repl); +#endif + +// this is implemented in runtime.c +mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals); + +#endif // MICROPY_INCLUDED_PY_COMPILE_H diff --git a/src/openmv/src/micropython/py/emit.h b/src/openmv/src/micropython/py/emit.h new file mode 100755 index 0000000..84972dd --- /dev/null +++ b/src/openmv/src/micropython/py/emit.h @@ -0,0 +1,276 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_EMIT_H +#define MICROPY_INCLUDED_PY_EMIT_H + +#include "py/lexer.h" +#include "py/scope.h" + +/* Notes on passes: + * We don't know exactly the opcodes in pass 1 because they depend on the + * closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which + * depends on determining the scope of variables in each function, and this + * is not known until the end of pass 1. + * As a consequence, we don't know the maximum stack size until the end of pass 2. + * This is problematic for some emitters (x64) since they need to know the maximum + * stack size to compile the entry to the function, and this affects code size. + */ + +typedef enum { + MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels + MP_PASS_STACK_SIZE = 2, // work out maximum stack size + MP_PASS_CODE_SIZE = 3, // work out code size and label offsets + MP_PASS_EMIT = 4, // emit code +} pass_kind_t; + +#define MP_EMIT_STAR_FLAG_SINGLE (0x01) +#define MP_EMIT_STAR_FLAG_DOUBLE (0x02) + +#define MP_EMIT_BREAK_FROM_FOR (0x8000) + +// Kind for emit_id_ops->local() +#define MP_EMIT_IDOP_LOCAL_FAST (0) +#define MP_EMIT_IDOP_LOCAL_DEREF (1) + +// Kind for emit_id_ops->global() +#define MP_EMIT_IDOP_GLOBAL_NAME (0) +#define MP_EMIT_IDOP_GLOBAL_GLOBAL (1) + +// Kind for emit->import() +#define MP_EMIT_IMPORT_NAME (0) +#define MP_EMIT_IMPORT_FROM (1) +#define MP_EMIT_IMPORT_STAR (2) + +// Kind for emit->subscr() +#define MP_EMIT_SUBSCR_LOAD (0) +#define MP_EMIT_SUBSCR_STORE (1) +#define MP_EMIT_SUBSCR_DELETE (2) + +// Kind for emit->attr() +#define MP_EMIT_ATTR_LOAD (0) +#define MP_EMIT_ATTR_STORE (1) +#define MP_EMIT_ATTR_DELETE (2) + +// Kind for emit->setup_block() +#define MP_EMIT_SETUP_BLOCK_WITH (0) +#define MP_EMIT_SETUP_BLOCK_EXCEPT (2) +#define MP_EMIT_SETUP_BLOCK_FINALLY (3) + +// Kind for emit->build() +#define MP_EMIT_BUILD_TUPLE (0) +#define MP_EMIT_BUILD_LIST (1) +#define MP_EMIT_BUILD_MAP (3) +#define MP_EMIT_BUILD_SET (6) +#define MP_EMIT_BUILD_SLICE (8) + +// Kind for emit->yield() +#define MP_EMIT_YIELD_VALUE (0) +#define MP_EMIT_YIELD_FROM (1) + +typedef struct _emit_t emit_t; + +typedef struct _mp_emit_method_table_id_ops_t { + void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); + void (*global)(emit_t *emit, qstr qst, int kind); +} mp_emit_method_table_id_ops_t; + +typedef struct _emit_method_table_t { + void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); + void (*end_pass)(emit_t *emit); + bool (*last_emit_was_return_value)(emit_t *emit); + void (*adjust_stack_size)(emit_t *emit, mp_int_t delta); + void (*set_source_line)(emit_t *emit, mp_uint_t line); + + mp_emit_method_table_id_ops_t load_id; + mp_emit_method_table_id_ops_t store_id; + mp_emit_method_table_id_ops_t delete_id; + + void (*label_assign)(emit_t *emit, mp_uint_t l); + void (*import)(emit_t *emit, qstr qst, int kind); + void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); + void (*load_const_small_int)(emit_t *emit, mp_int_t arg); + void (*load_const_str)(emit_t *emit, qstr qst); + void (*load_const_obj)(emit_t *emit, mp_obj_t obj); + void (*load_null)(emit_t *emit); + void (*load_method)(emit_t *emit, qstr qst, bool is_super); + void (*load_build_class)(emit_t *emit); + void (*subscr)(emit_t *emit, int kind); + void (*attr)(emit_t *emit, qstr qst, int kind); + void (*dup_top)(emit_t *emit); + void (*dup_top_two)(emit_t *emit); + void (*pop_top)(emit_t *emit); + void (*rot_two)(emit_t *emit); + void (*rot_three)(emit_t *emit); + void (*jump)(emit_t *emit, mp_uint_t label); + void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label); + void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label); + void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); + void (*setup_block)(emit_t *emit, mp_uint_t label, int kind); + void (*with_cleanup)(emit_t *emit, mp_uint_t label); + void (*end_finally)(emit_t *emit); + void (*get_iter)(emit_t *emit, bool use_stack); + void (*for_iter)(emit_t *emit, mp_uint_t label); + void (*for_iter_end)(emit_t *emit); + void (*pop_block)(emit_t *emit); + void (*pop_except)(emit_t *emit); + void (*unary_op)(emit_t *emit, mp_unary_op_t op); + void (*binary_op)(emit_t *emit, mp_binary_op_t op); + void (*build)(emit_t *emit, mp_uint_t n_args, int kind); + void (*store_map)(emit_t *emit); + void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index); + void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args); + void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); + void (*make_function)(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); + void (*make_closure)(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); + void (*call_function)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); + void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); + void (*return_value)(emit_t *emit); + void (*raise_varargs)(emit_t *emit, mp_uint_t n_args); + void (*yield)(emit_t *emit, int kind); + + // these methods are used to control entry to/exit from an exception handler + // they may or may not emit code + void (*start_except_handler)(emit_t *emit); + void (*end_except_handler)(emit_t *emit); +} emit_method_table_t; + +int mp_native_type_from_qstr(qstr qst); + +void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst); +void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst); +void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst); + +extern const emit_method_table_t emit_bc_method_table; +extern const emit_method_table_t emit_native_x64_method_table; +extern const emit_method_table_t emit_native_x86_method_table; +extern const emit_method_table_t emit_native_thumb_method_table; +extern const emit_method_table_t emit_native_arm_method_table; +extern const emit_method_table_t emit_native_xtensa_method_table; + +extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops; +extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops; +extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops; + +emit_t *emit_bc_new(void); +emit_t *emit_native_x64_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); + +void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels); + +void emit_bc_free(emit_t *emit); +void emit_native_x64_free(emit_t *emit); +void emit_native_x86_free(emit_t *emit); +void emit_native_thumb_free(emit_t *emit); +void emit_native_arm_free(emit_t *emit); +void emit_native_xtensa_free(emit_t *emit); + +void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); +void mp_emit_bc_end_pass(emit_t *emit); +bool mp_emit_bc_last_emit_was_return_value(emit_t *emit); +void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); +void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); + +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind); + +void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l); +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok); +void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg); +void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); +void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj); +void mp_emit_bc_load_null(emit_t *emit); +void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super); +void mp_emit_bc_load_build_class(emit_t *emit); +void mp_emit_bc_subscr(emit_t *emit, int kind); +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_dup_top(emit_t *emit); +void mp_emit_bc_dup_top_two(emit_t *emit); +void mp_emit_bc_pop_top(emit_t *emit); +void mp_emit_bc_rot_two(emit_t *emit); +void mp_emit_bc_rot_three(emit_t *emit); +void mp_emit_bc_jump(emit_t *emit, mp_uint_t label); +void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label); +void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); +void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind); +void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); +void mp_emit_bc_end_finally(emit_t *emit); +void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); +void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); +void mp_emit_bc_for_iter_end(emit_t *emit); +void mp_emit_bc_pop_block(emit_t *emit); +void mp_emit_bc_pop_except(emit_t *emit); +void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); +void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind); +void mp_emit_bc_store_map(emit_t *emit); +void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index); +void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args); +void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); +void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); +void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults); +void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); +void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); +void mp_emit_bc_return_value(emit_t *emit); +void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args); +void mp_emit_bc_yield(emit_t *emit, int kind); +void mp_emit_bc_start_except_handler(emit_t *emit); +void mp_emit_bc_end_except_handler(emit_t *emit); + +typedef struct _emit_inline_asm_t emit_inline_asm_t; + +typedef struct _emit_inline_asm_method_table_t { + void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot); + void (*end_pass)(emit_inline_asm_t *emit, mp_uint_t type_sig); + mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params); + bool (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id); + void (*op)(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args); +} emit_inline_asm_method_table_t; + +extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table; +extern const emit_inline_asm_method_table_t emit_inline_xtensa_method_table; + +emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels); +emit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels); + +void emit_inline_thumb_free(emit_inline_asm_t *emit); +void emit_inline_xtensa_free(emit_inline_asm_t *emit); + +#if MICROPY_WARNINGS +void mp_emitter_warning(pass_kind_t pass, const char *msg); +#else +#define mp_emitter_warning(pass, msg) +#endif + +#endif // MICROPY_INCLUDED_PY_EMIT_H diff --git a/src/openmv/src/micropython/py/emitbc.c b/src/openmv/src/micropython/py/emitbc.c new file mode 100755 index 0000000..98e1d1b --- /dev/null +++ b/src/openmv/src/micropython/py/emitbc.c @@ -0,0 +1,995 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/mpstate.h" +#include "py/emit.h" +#include "py/bc0.h" + +#if MICROPY_ENABLE_COMPILER + +#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) +#define DUMMY_DATA_SIZE (BYTES_FOR_INT) + +struct _emit_t { + // Accessed as mp_obj_t, so must be aligned as such, and we rely on the + // memory allocator returning a suitably aligned pointer. + // Should work for cases when mp_obj_t is 64-bit on a 32-bit machine. + byte dummy_data[DUMMY_DATA_SIZE]; + + pass_kind_t pass : 8; + mp_uint_t last_emit_was_return_value : 8; + + int stack_size; + + scope_t *scope; + + mp_uint_t last_source_line_offset; + mp_uint_t last_source_line; + + mp_uint_t max_num_labels; + mp_uint_t *label_offsets; + + size_t code_info_offset; + size_t code_info_size; + size_t bytecode_offset; + size_t bytecode_size; + byte *code_base; // stores both byte code and code info + + #if MICROPY_PERSISTENT_CODE + uint16_t ct_cur_obj; + uint16_t ct_num_obj; + uint16_t ct_cur_raw_code; + #endif + mp_uint_t *const_table; +}; + +emit_t *emit_bc_new(void) { + emit_t *emit = m_new0(emit_t, 1); + return emit; +} + +void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) { + emit->max_num_labels = max_num_labels; + emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels); +} + +void emit_bc_free(emit_t *emit) { + m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels); + m_del_obj(emit_t, emit); +} + +typedef byte *(*emit_allocator_t)(emit_t *emit, int nbytes); + +STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t val) { + // We store each 7 bits in a separate byte, and that's how many bytes needed + byte buf[BYTES_FOR_INT]; + byte *p = buf + sizeof(buf); + // We encode in little-ending order, but store in big-endian, to help decoding + do { + *--p = val & 0x7f; + val >>= 7; + } while (val != 0); + byte *c = allocator(emit, buf + sizeof(buf) - p); + while (p != buf + sizeof(buf) - 1) { + *c++ = *p++ | 0x80; + } + *c = *p; +} + +// all functions must go through this one to emit code info +STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) { + //printf("emit %d\n", num_bytes_to_write); + if (emit->pass < MP_PASS_EMIT) { + emit->code_info_offset += num_bytes_to_write; + return emit->dummy_data; + } else { + assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size); + byte *c = emit->code_base + emit->code_info_offset; + emit->code_info_offset += num_bytes_to_write; + return c; + } +} + +STATIC void emit_write_code_info_byte(emit_t* emit, byte val) { + *emit_get_cur_to_write_code_info(emit, 1) = val; +} + +STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) { + emit_write_uint(emit, emit_get_cur_to_write_code_info, val); +} + +STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) { + #if MICROPY_PERSISTENT_CODE + assert((qst >> 16) == 0); + byte *c = emit_get_cur_to_write_code_info(emit, 2); + c[0] = qst; + c[1] = qst >> 8; + #else + emit_write_uint(emit, emit_get_cur_to_write_code_info, qst); + #endif +} + +#if MICROPY_ENABLE_SOURCE_LINE +STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) { + assert(bytes_to_skip > 0 || lines_to_skip > 0); + //printf(" %d %d\n", bytes_to_skip, lines_to_skip); + while (bytes_to_skip > 0 || lines_to_skip > 0) { + mp_uint_t b, l; + if (lines_to_skip <= 6 || bytes_to_skip > 0xf) { + // use 0b0LLBBBBB encoding + b = MIN(bytes_to_skip, 0x1f); + if (b < bytes_to_skip) { + // we can't skip any lines until we skip all the bytes + l = 0; + } else { + l = MIN(lines_to_skip, 0x3); + } + *emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5); + } else { + // use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + b = MIN(bytes_to_skip, 0xf); + l = MIN(lines_to_skip, 0x7ff); + byte *ci = emit_get_cur_to_write_code_info(emit, 2); + ci[0] = 0x80 | b | ((l >> 4) & 0x70); + ci[1] = l; + } + bytes_to_skip -= b; + lines_to_skip -= l; + } +} +#endif + +// all functions must go through this one to emit byte code +STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) { + //printf("emit %d\n", num_bytes_to_write); + if (emit->pass < MP_PASS_EMIT) { + emit->bytecode_offset += num_bytes_to_write; + return emit->dummy_data; + } else { + assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size); + byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset; + emit->bytecode_offset += num_bytes_to_write; + return c; + } +} + +STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { + byte *c = emit_get_cur_to_write_bytecode(emit, 1); + c[0] = b1; +} + +STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { + byte *c = emit_get_cur_to_write_bytecode(emit, 2); + c[0] = b1; + c[1] = b2; +} + +// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign +STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) { + emit_write_bytecode_byte(emit, b1); + + // We store each 7 bits in a separate byte, and that's how many bytes needed + byte buf[BYTES_FOR_INT]; + byte *p = buf + sizeof(buf); + // We encode in little-ending order, but store in big-endian, to help decoding + do { + *--p = num & 0x7f; + num >>= 7; + } while (num != 0 && num != -1); + // Make sure that highest bit we stored (mask 0x40) matches sign + // of the number. If not, store extra byte just to encode sign + if (num == -1 && (*p & 0x40) == 0) { + *--p = 0x7f; + } else if (num == 0 && (*p & 0x40) != 0) { + *--p = 0; + } + + byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p); + while (p != buf + sizeof(buf) - 1) { + *c++ = *p++ | 0x80; + } + *c = *p; +} + +STATIC void emit_write_bytecode_byte_uint(emit_t *emit, byte b, mp_uint_t val) { + emit_write_bytecode_byte(emit, b); + emit_write_uint(emit, emit_get_cur_to_write_bytecode, val); +} + +#if MICROPY_PERSISTENT_CODE +STATIC void emit_write_bytecode_byte_const(emit_t *emit, byte b, mp_uint_t n, mp_uint_t c) { + if (emit->pass == MP_PASS_EMIT) { + emit->const_table[n] = c; + } + emit_write_bytecode_byte_uint(emit, b, n); +} +#endif + +STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) { + #if MICROPY_PERSISTENT_CODE + assert((qst >> 16) == 0); + byte *c = emit_get_cur_to_write_bytecode(emit, 3); + c[0] = b; + c[1] = qst; + c[2] = qst >> 8; + #else + emit_write_bytecode_byte_uint(emit, b, qst); + #endif +} + +STATIC void emit_write_bytecode_byte_obj(emit_t *emit, byte b, mp_obj_t obj) { + #if MICROPY_PERSISTENT_CODE + emit_write_bytecode_byte_const(emit, b, + emit->scope->num_pos_args + emit->scope->num_kwonly_args + + emit->ct_cur_obj++, (mp_uint_t)obj); + #else + // aligns the pointer so it is friendly to GC + emit_write_bytecode_byte(emit, b); + emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t)); + mp_obj_t *c = (mp_obj_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t)); + // Verify thar c is already uint-aligned + assert(c == MP_ALIGN(c, sizeof(mp_obj_t))); + *c = obj; + #endif +} + +STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_t *rc) { + #if MICROPY_PERSISTENT_CODE + emit_write_bytecode_byte_const(emit, b, + emit->scope->num_pos_args + emit->scope->num_kwonly_args + + emit->ct_num_obj + emit->ct_cur_raw_code++, (mp_uint_t)(uintptr_t)rc); + #else + // aligns the pointer so it is friendly to GC + emit_write_bytecode_byte(emit, b); + emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void*)); + void **c = (void**)emit_get_cur_to_write_bytecode(emit, sizeof(void*)); + // Verify thar c is already uint-aligned + assert(c == MP_ALIGN(c, sizeof(void*))); + *c = rc; + #endif +} + +// unsigned labels are relative to ip following this instruction, stored as 16 bits +STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_uint_t label) { + mp_uint_t bytecode_offset; + if (emit->pass < MP_PASS_EMIT) { + bytecode_offset = 0; + } else { + bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3; + } + byte *c = emit_get_cur_to_write_bytecode(emit, 3); + c[0] = b1; + c[1] = bytecode_offset; + c[2] = bytecode_offset >> 8; +} + +// signed labels are relative to ip following this instruction, stored as 16 bits, in excess +STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint_t label) { + int bytecode_offset; + if (emit->pass < MP_PASS_EMIT) { + bytecode_offset = 0; + } else { + bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000; + } + byte *c = emit_get_cur_to_write_bytecode(emit, 3); + c[0] = b1; + c[1] = bytecode_offset; + c[2] = bytecode_offset >> 8; +} + +void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { + emit->pass = pass; + emit->stack_size = 0; + emit->last_emit_was_return_value = false; + emit->scope = scope; + emit->last_source_line_offset = 0; + emit->last_source_line = 1; + #ifndef NDEBUG + // With debugging enabled labels are checked for unique assignment + if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) { + memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); + } + #endif + emit->bytecode_offset = 0; + emit->code_info_offset = 0; + + // Write local state size and exception stack size. + { + mp_uint_t n_state = scope->num_locals + scope->stack_size; + if (n_state == 0) { + // Need at least 1 entry in the state, in the case an exception is + // propagated through this function, the exception is returned in + // the highest slot in the state (fastn[0], see vm.c). + n_state = 1; + } + emit_write_code_info_uint(emit, n_state); + emit_write_code_info_uint(emit, scope->exc_stack_size); + } + + // Write scope flags and number of arguments. + // TODO check that num args all fit in a byte + emit_write_code_info_byte(emit, emit->scope->scope_flags); + emit_write_code_info_byte(emit, emit->scope->num_pos_args); + emit_write_code_info_byte(emit, emit->scope->num_kwonly_args); + emit_write_code_info_byte(emit, emit->scope->num_def_pos_args); + + // Write size of the rest of the code info. We don't know how big this + // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes + // for it and hope that is enough! TODO assert this or something. + if (pass == MP_PASS_EMIT) { + emit_write_code_info_uint(emit, emit->code_info_size - emit->code_info_offset); + } else { + emit_get_cur_to_write_code_info(emit, 2); + } + + // Write the name and source file of this function. + emit_write_code_info_qstr(emit, scope->simple_name); + emit_write_code_info_qstr(emit, scope->source_file); + + // bytecode prelude: initialise closed over variables + for (int i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + assert(id->local_num < 255); + emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell + } + } + emit_write_bytecode_byte(emit, 255); // end of list sentinel + + #if MICROPY_PERSISTENT_CODE + emit->ct_cur_obj = 0; + emit->ct_cur_raw_code = 0; + #endif + + if (pass == MP_PASS_EMIT) { + // Write argument names (needed to resolve positional args passed as + // keywords). We store them as full word-sized objects for efficient access + // in mp_setup_code_state this is the start of the prelude and is guaranteed + // to be aligned on a word boundary. + + // For a given argument position (indexed by i) we need to find the + // corresponding id_info which is a parameter, as it has the correct + // qstr name to use as the argument name. Note that it's not a simple + // 1-1 mapping (ie i!=j in general) because of possible closed-over + // variables. In the case that the argument i has no corresponding + // parameter we use "*" as its name (since no argument can ever be named + // "*"). We could use a blank qstr but "*" is better for debugging. + // Note: there is some wasted RAM here for the case of storing a qstr + // for each closed-over variable, and maybe there is a better way to do + // it, but that would require changes to mp_setup_code_state. + for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { + qstr qst = MP_QSTR__star_; + for (int j = 0; j < scope->id_info_len; ++j) { + id_info_t *id = &scope->id_info[j]; + if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { + qst = id->qst; + break; + } + } + emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); + } + } +} + +void mp_emit_bc_end_pass(emit_t *emit) { + if (emit->pass == MP_PASS_SCOPE) { + return; + } + + // check stack is back to zero size + assert(emit->stack_size == 0); + + emit_write_code_info_byte(emit, 0); // end of line number info + + #if MICROPY_PERSISTENT_CODE + assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->ct_num_obj == emit->ct_cur_obj)); + emit->ct_num_obj = emit->ct_cur_obj; + #endif + + if (emit->pass == MP_PASS_CODE_SIZE) { + #if !MICROPY_PERSISTENT_CODE + // so bytecode is aligned + emit->code_info_offset = (size_t)MP_ALIGN(emit->code_info_offset, sizeof(mp_uint_t)); + #endif + + // calculate size of total code-info + bytecode, in bytes + emit->code_info_size = emit->code_info_offset; + emit->bytecode_size = emit->bytecode_offset; + emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size); + + #if MICROPY_PERSISTENT_CODE + emit->const_table = m_new0(mp_uint_t, + emit->scope->num_pos_args + emit->scope->num_kwonly_args + + emit->ct_cur_obj + emit->ct_cur_raw_code); + #else + emit->const_table = m_new0(mp_uint_t, + emit->scope->num_pos_args + emit->scope->num_kwonly_args); + #endif + + } else if (emit->pass == MP_PASS_EMIT) { + mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + emit->code_info_size + emit->bytecode_size, + #endif + emit->const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + emit->ct_cur_obj, emit->ct_cur_raw_code, + #endif + emit->scope->scope_flags); + } +} + +bool mp_emit_bc_last_emit_was_return_value(emit_t *emit) { + return emit->last_emit_was_return_value; +} + +void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) { + if (emit->pass == MP_PASS_SCOPE) { + return; + } + assert((mp_int_t)emit->stack_size + delta >= 0); + emit->stack_size += delta; + if (emit->stack_size > emit->scope->stack_size) { + emit->scope->stack_size = emit->stack_size; + } + emit->last_emit_was_return_value = false; +} + +static inline void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) { + mp_emit_bc_adjust_stack_size(emit, stack_size_delta); +} + +void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) { + //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset); +#if MICROPY_ENABLE_SOURCE_LINE + if (MP_STATE_VM(mp_optimise_value) >= 3) { + // If we compile with -O3, don't store line numbers. + return; + } + if (source_line > emit->last_source_line) { + mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset; + mp_uint_t lines_to_skip = source_line - emit->last_source_line; + emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip); + emit->last_source_line_offset = emit->bytecode_offset; + emit->last_source_line = source_line; + } +#else + (void)emit; + (void)source_line; +#endif +} + +void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { + emit_bc_pre(emit, 0); + if (emit->pass == MP_PASS_SCOPE) { + return; + } + assert(l < emit->max_num_labels); + if (emit->pass < MP_PASS_EMIT) { + // assign label offset + assert(emit->label_offsets[l] == (mp_uint_t)-1); + emit->label_offsets[l] = emit->bytecode_offset; + } else { + // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT + assert(emit->label_offsets[l] == emit->bytecode_offset); + } +} + +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME); + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM); + if (kind == MP_EMIT_IMPORT_FROM) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, -1); + } + if (kind == MP_EMIT_IMPORT_STAR) { + emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); + } else { + emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst); + } +} + +void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { + emit_bc_pre(emit, 1); + switch (tok) { + case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break; + case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break; + case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break; + default: + assert(tok == MP_TOKEN_ELLIPSIS); + emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + break; + } +} + +void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) { + emit_bc_pre(emit, 1); + if (-16 <= arg && arg <= 47) { + emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg); + } else { + emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg); + } +} + +void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst); +} + +void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, obj); +} + +void mp_emit_bc_load_null(emit_t *emit) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); +} + +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N); + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF); + (void)qst; + emit_bc_pre(emit, 1); + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { + emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); + } else { + emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num); + } +} + +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME); + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL); + (void)qst; + emit_bc_pre(emit, 1); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME + kind, qst); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { + emit_write_bytecode_byte(emit, 0); + } +} + +void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) { + emit_bc_pre(emit, 1 - 2 * is_super); + emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst); +} + +void mp_emit_bc_load_build_class(emit_t *emit) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); +} + +void mp_emit_bc_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); + } else { + if (kind == MP_EMIT_SUBSCR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_three(emit); + } + emit_bc_pre(emit, -3); + emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); + } +} + +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); + } else { + if (kind == MP_EMIT_ATTR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_two(emit); + } + emit_bc_pre(emit, -2); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); + } + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { + emit_write_bytecode_byte(emit, 0); + } +} + +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N); + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF); + (void)qst; + emit_bc_pre(emit, -1); + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { + emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); + } else { + emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num); + } +} + +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME); + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL); + emit_bc_pre(emit, -1); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst); +} + +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); + (void)qst; + emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num); +} + +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME); + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL); + emit_bc_pre(emit, 0); + emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst); +} + +void mp_emit_bc_dup_top(emit_t *emit) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte(emit, MP_BC_DUP_TOP); +} + +void mp_emit_bc_dup_top_two(emit_t *emit) { + emit_bc_pre(emit, 2); + emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO); +} + +void mp_emit_bc_pop_top(emit_t *emit) { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_POP_TOP); +} + +void mp_emit_bc_rot_two(emit_t *emit) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_ROT_TWO); +} + +void mp_emit_bc_rot_three(emit_t *emit) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_ROT_THREE); +} + +void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label); +} + +void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { + emit_bc_pre(emit, -1); + if (cond) { + emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label); + } else { + emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label); + } +} + +void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { + emit_bc_pre(emit, -1); + if (cond) { + emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label); + } else { + emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); + } +} + +void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { + if (except_depth == 0) { + emit_bc_pre(emit, 0); + if (label & MP_EMIT_BREAK_FROM_FOR) { + // need to pop the iterator if we are breaking out of a for loop + emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + // also pop the iter_buf + for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) { + emit_write_bytecode_byte(emit, MP_BC_POP_TOP); + } + } + emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + } else { + emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR); + emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth); + } +} + +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY); + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { + // The SETUP_WITH opcode pops ctx_mgr from the top of the stack + // and then pushes 3 entries: __exit__, ctx_mgr, as_value. + emit_bc_pre(emit, 2); + } else { + emit_bc_pre(emit, 0); + } + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label); +} + +void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { + mp_emit_bc_pop_block(emit); + mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); + mp_emit_bc_label_assign(emit, label); + emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method + emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); + emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) +} + +void mp_emit_bc_end_finally(emit_t *emit) { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_END_FINALLY); +} + +void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { + emit_bc_pre(emit, use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0); + emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); +} + +void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label); +} + +void mp_emit_bc_for_iter_end(emit_t *emit) { + emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); +} + +void mp_emit_bc_pop_block(emit_t *emit) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK); +} + +void mp_emit_bc_pop_except(emit_t *emit) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT); +} + +void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op); +} + +void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { + bool invert = false; + if (op == MP_BINARY_OP_NOT_IN) { + invert = true; + op = MP_BINARY_OP_IN; + } else if (op == MP_BINARY_OP_IS_NOT) { + invert = true; + op = MP_BINARY_OP_IS; + } + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op); + if (invert) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT); + } +} + +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) { + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE); + if (kind == MP_EMIT_BUILD_MAP) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, 1 - n_args); + } + emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args); +} + +void mp_emit_bc_store_map(emit_t *emit) { + emit_bc_pre(emit, -2); + emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); +} + +void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { + int t; + int n; + if (kind == SCOPE_LIST_COMP) { + n = 0; + t = 0; + } else if (!MICROPY_PY_BUILTINS_SET || kind == SCOPE_DICT_COMP) { + n = 1; + t = 1; + } else if (MICROPY_PY_BUILTINS_SET) { + n = 0; + t = 2; + } + emit_bc_pre(emit, -1 - n); + // the lower 2 bits of the opcode argument indicate the collection type + emit_write_bytecode_byte_uint(emit, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t); +} + +void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) { + emit_bc_pre(emit, -1 + n_args); + emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args); +} + +void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { + emit_bc_pre(emit, -1 + n_left + n_right + 1); + emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8)); +} + +void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { + if (n_pos_defaults == 0 && n_kw_defaults == 0) { + emit_bc_pre(emit, 1); + emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION, scope->raw_code); + } else { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); + } +} + +void mp_emit_bc_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { + if (n_pos_defaults == 0 && n_kw_defaults == 0) { + emit_bc_pre(emit, -n_closed_over + 1); + emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE, scope->raw_code); + emit_write_bytecode_byte(emit, n_closed_over); + } else { + assert(n_closed_over <= 255); + emit_bc_pre(emit, -2 - (mp_int_t)n_closed_over + 1); + emit_write_bytecode_byte_raw_code(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); + emit_write_bytecode_byte(emit, n_closed_over); + } +} + +STATIC void emit_bc_call_function_method_helper(emit_t *emit, mp_int_t stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + if (star_flags) { + emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - 2); + emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + } else { + emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword); + emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + } +} + +void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags); +} + +void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags); +} + +void mp_emit_bc_return_value(emit_t *emit) { + emit_bc_pre(emit, -1); + emit->last_emit_was_return_value = true; + emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE); +} + +void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { + assert(n_args <= 2); + emit_bc_pre(emit, -n_args); + emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); +} + +void mp_emit_bc_yield(emit_t *emit, int kind) { + MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM); + emit_bc_pre(emit, -kind); + emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); +} + +void mp_emit_bc_start_except_handler(emit_t *emit) { + mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state +} + +void mp_emit_bc_end_except_handler(emit_t *emit) { + mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust +} + +#if MICROPY_EMIT_NATIVE +const emit_method_table_t emit_bc_method_table = { + mp_emit_bc_start_pass, + mp_emit_bc_end_pass, + mp_emit_bc_last_emit_was_return_value, + mp_emit_bc_adjust_stack_size, + mp_emit_bc_set_source_line, + + { + mp_emit_bc_load_local, + mp_emit_bc_load_global, + }, + { + mp_emit_bc_store_local, + mp_emit_bc_store_global, + }, + { + mp_emit_bc_delete_local, + mp_emit_bc_delete_global, + }, + + mp_emit_bc_label_assign, + mp_emit_bc_import, + mp_emit_bc_load_const_tok, + mp_emit_bc_load_const_small_int, + mp_emit_bc_load_const_str, + mp_emit_bc_load_const_obj, + mp_emit_bc_load_null, + mp_emit_bc_load_method, + mp_emit_bc_load_build_class, + mp_emit_bc_subscr, + mp_emit_bc_attr, + mp_emit_bc_dup_top, + mp_emit_bc_dup_top_two, + mp_emit_bc_pop_top, + mp_emit_bc_rot_two, + mp_emit_bc_rot_three, + mp_emit_bc_jump, + mp_emit_bc_pop_jump_if, + mp_emit_bc_jump_if_or_pop, + mp_emit_bc_unwind_jump, + mp_emit_bc_setup_block, + mp_emit_bc_with_cleanup, + mp_emit_bc_end_finally, + mp_emit_bc_get_iter, + mp_emit_bc_for_iter, + mp_emit_bc_for_iter_end, + mp_emit_bc_pop_block, + mp_emit_bc_pop_except, + mp_emit_bc_unary_op, + mp_emit_bc_binary_op, + mp_emit_bc_build, + mp_emit_bc_store_map, + mp_emit_bc_store_comp, + mp_emit_bc_unpack_sequence, + mp_emit_bc_unpack_ex, + mp_emit_bc_make_function, + mp_emit_bc_make_closure, + mp_emit_bc_call_function, + mp_emit_bc_call_method, + mp_emit_bc_return_value, + mp_emit_bc_raise_varargs, + mp_emit_bc_yield, + + mp_emit_bc_start_except_handler, + mp_emit_bc_end_except_handler, +}; +#else +const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = { + mp_emit_bc_load_local, + mp_emit_bc_load_global, +}; + +const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = { + mp_emit_bc_store_local, + mp_emit_bc_store_global, +}; + +const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { + mp_emit_bc_delete_local, + mp_emit_bc_delete_global, +}; +#endif + +#endif //MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/emitcommon.c b/src/openmv/src/micropython/py/emitcommon.c new file mode 100755 index 0000000..89cc2c9 --- /dev/null +++ b/src/openmv/src/micropython/py/emitcommon.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/emit.h" + +#if MICROPY_ENABLE_COMPILER + +void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { + // name adding/lookup + bool added; + id_info_t *id = scope_find_or_add_id(scope, qst, &added); + if (added) { + scope_find_local_and_close_over(scope, id, qst); + } +} + +void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) { + // name adding/lookup + bool added; + id_info_t *id = scope_find_or_add_id(scope, qst, &added); + if (added) { + if (SCOPE_IS_FUNC_LIKE(scope->kind)) { + id->kind = ID_INFO_KIND_LOCAL; + } else { + id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; + } + } else if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + // rebind as a local variable + id->kind = ID_INFO_KIND_LOCAL; + } +} + +void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emit_method_table, scope_t *scope, qstr qst) { + // assumes pass is greater than 1, ie that all identifiers are defined in the scope + + id_info_t *id = scope_find(scope, qst); + assert(id != NULL); + + // call the emit backend with the correct code + if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_NAME); + } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL); + } else if (id->kind == ID_INFO_KIND_LOCAL) { + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST); + } else { + assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE); + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_DEREF); + } +} + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/emitglue.c b/src/openmv/src/micropython/py/emitglue.c new file mode 100755 index 0000000..064a838 --- /dev/null +++ b/src/openmv/src/micropython/py/emitglue.c @@ -0,0 +1,177 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// This code glues the code emitters to the runtime. + +#include +#include +#include +#include + +#include "py/emitglue.h" +#include "py/runtime0.h" +#include "py/bc.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define WRITE_CODE (1) +#define DEBUG_printf DEBUG_printf +#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#define DEBUG_OP_printf(...) (void)0 +#endif + +#if MICROPY_DEBUG_PRINTERS +mp_uint_t mp_verbose_flag = 0; +#endif + +mp_raw_code_t *mp_emit_glue_new_raw_code(void) { + mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1); + rc->kind = MP_CODE_RESERVED; + return rc; +} + +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif + const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t n_obj, uint16_t n_raw_code, + #endif + mp_uint_t scope_flags) { + + rc->kind = MP_CODE_BYTECODE; + rc->scope_flags = scope_flags; + rc->data.u_byte.bytecode = code; + rc->data.u_byte.const_table = const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + rc->data.u_byte.bc_len = len; + rc->data.u_byte.n_obj = n_obj; + rc->data.u_byte.n_raw_code = n_raw_code; + #endif + +#ifdef DEBUG_PRINT + #if !MICROPY_DEBUG_PRINTERS + const size_t len = 0; + #endif + DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " flags=%x\n", code, len, (uint)scope_flags); +#endif +#if MICROPY_DEBUG_PRINTERS + if (mp_verbose_flag >= 2) { + mp_bytecode_print(rc, code, len, const_table); + } +#endif +} + +#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig) { + assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); + rc->kind = kind; + rc->scope_flags = scope_flags; + rc->n_pos_args = n_pos_args; + rc->data.u_native.fun_data = fun_data; + rc->data.u_native.const_table = const_table; + rc->data.u_native.type_sig = type_sig; + +#ifdef DEBUG_PRINT + DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags); + for (mp_uint_t i = 0; i < fun_len; i++) { + if (i > 0 && i % 16 == 0) { + DEBUG_printf("\n"); + } + DEBUG_printf(" %02x", ((byte*)fun_data)[i]); + } + DEBUG_printf("\n"); + +#ifdef WRITE_CODE + FILE *fp_write_code = fopen("out-code", "wb"); + fwrite(fun_data, fun_len, 1, fp_write_code); + fclose(fp_write_code); +#endif +#else + (void)fun_len; +#endif +} +#endif + +mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) { + DEBUG_OP_printf("make_function_from_raw_code %p\n", rc); + assert(rc != NULL); + + // def_args must be MP_OBJ_NULL or a tuple + assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple)); + + // def_kw_args must be MP_OBJ_NULL or a dict + assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict)); + + // make the function, depending on the raw code kind + mp_obj_t fun; + switch (rc->kind) { + #if MICROPY_EMIT_NATIVE + case MP_CODE_NATIVE_PY: + case MP_CODE_NATIVE_VIPER: + fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->data.u_native.fun_data, rc->data.u_native.const_table); + // Check for a generator function, and if so change the type of the object + if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { + ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap; + } + break; + #endif + #if MICROPY_EMIT_INLINE_ASM + case MP_CODE_NATIVE_ASM: + fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); + break; + #endif + default: + // rc->kind should always be set and BYTECODE is the only remaining case + assert(rc->kind == MP_CODE_BYTECODE); + fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table); + // check for generator functions and if so change the type of the object + if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) { + ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap; + } + break; + } + + return fun; +} + +mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) { + DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args); + // make function object + mp_obj_t ffun; + if (n_closed_over & 0x100) { + // default positional and keyword args given + ffun = mp_make_function_from_raw_code(rc, args[0], args[1]); + } else { + // default positional and keyword args not given + ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); + } + // wrap function in closure object + return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2)); +} diff --git a/src/openmv/src/micropython/py/emitglue.h b/src/openmv/src/micropython/py/emitglue.h new file mode 100755 index 0000000..d39a10e --- /dev/null +++ b/src/openmv/src/micropython/py/emitglue.h @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_EMITGLUE_H +#define MICROPY_INCLUDED_PY_EMITGLUE_H + +#include "py/obj.h" + +// These variables and functions glue the code emitters to the runtime. + +// These must fit in 8 bits; see scope.h +enum { + MP_EMIT_OPT_NONE, + MP_EMIT_OPT_BYTECODE, + MP_EMIT_OPT_NATIVE_PYTHON, + MP_EMIT_OPT_VIPER, + MP_EMIT_OPT_ASM, +}; + +typedef enum { + MP_CODE_UNUSED, + MP_CODE_RESERVED, + MP_CODE_BYTECODE, + MP_CODE_NATIVE_PY, + MP_CODE_NATIVE_VIPER, + MP_CODE_NATIVE_ASM, +} mp_raw_code_kind_t; + +typedef struct _mp_raw_code_t { + mp_uint_t kind : 3; // of type mp_raw_code_kind_t + mp_uint_t scope_flags : 7; + mp_uint_t n_pos_args : 11; + union { + struct { + const byte *bytecode; + const mp_uint_t *const_table; + #if MICROPY_PERSISTENT_CODE_SAVE + mp_uint_t bc_len; + uint16_t n_obj; + uint16_t n_raw_code; + #endif + } u_byte; + struct { + void *fun_data; + const mp_uint_t *const_table; + mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc + } u_native; + } data; +} mp_raw_code_t; + +mp_raw_code_t *mp_emit_glue_new_raw_code(void); + +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif + const mp_uint_t *const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + uint16_t n_obj, uint16_t n_raw_code, + #endif + mp_uint_t scope_flags); +void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, const mp_uint_t *const_table, mp_uint_t n_pos_args, mp_uint_t scope_flags, mp_uint_t type_sig); + +mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); +mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args); + +#endif // MICROPY_INCLUDED_PY_EMITGLUE_H diff --git a/src/openmv/src/micropython/py/emitinlinethumb.c b/src/openmv/src/micropython/py/emitinlinethumb.c new file mode 100755 index 0000000..0649c59 --- /dev/null +++ b/src/openmv/src/micropython/py/emitinlinethumb.c @@ -0,0 +1,822 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/emit.h" +#include "py/asmthumb.h" + +#if MICROPY_EMIT_INLINE_THUMB + +typedef enum { +// define rules with a compile function +#define DEF_RULE(rule, comp, kind, ...) PN_##rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + PN_const_object, // special node for a constant, generic Python object +// define rules without a compile function +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) PN_##rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +} pn_kind_t; + +struct _emit_inline_asm_t { + asm_thumb_t as; + uint16_t pass; + mp_obj_t *error_slot; + mp_uint_t max_num_labels; + qstr *label_lookup; +}; + +STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const char *msg) { + *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); +} + +STATIC void emit_inline_thumb_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) { + *emit->error_slot = exc; +} + +emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) { + emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); + memset(&emit->as, 0, sizeof(emit->as)); + mp_asm_base_init(&emit->as.base, max_num_labels); + emit->max_num_labels = max_num_labels; + emit->label_lookup = m_new(qstr, max_num_labels); + return emit; +} + +void emit_inline_thumb_free(emit_inline_asm_t *emit) { + m_del(qstr, emit->label_lookup, emit->max_num_labels); + mp_asm_base_deinit(&emit->as.base, false); + m_del_obj(emit_inline_asm_t, emit); +} + +STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) { + emit->pass = pass; + emit->error_slot = error_slot; + if (emit->pass == MP_PASS_CODE_SIZE) { + memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); + } + mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); + asm_thumb_entry(&emit->as, 0); +} + +STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { + asm_thumb_exit(&emit->as); + asm_thumb_end_pass(&emit->as); +} + +STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) { + if (n_params > 4) { + emit_inline_thumb_error_msg(emit, "can only have up to 4 parameters to Thumb assembly"); + return 0; + } + for (mp_uint_t i = 0; i < n_params; i++) { + if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { + emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3"); + return 0; + } + const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); + if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { + emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3"); + return 0; + } + } + return n_params; +} + +STATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { + assert(label_num < emit->max_num_labels); + if (emit->pass == MP_PASS_CODE_SIZE) { + // check for duplicate label on first pass + for (uint i = 0; i < emit->max_num_labels; i++) { + if (emit->label_lookup[i] == label_id) { + return false; + } + } + } + emit->label_lookup[label_num] = label_id; + mp_asm_base_label_assign(&emit->as.base, label_num); + return true; +} + +typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; +STATIC const reg_name_t reg_name_table[] = { + {0, "r0\0"}, + {1, "r1\0"}, + {2, "r2\0"}, + {3, "r3\0"}, + {4, "r4\0"}, + {5, "r5\0"}, + {6, "r6\0"}, + {7, "r7\0"}, + {8, "r8\0"}, + {9, "r9\0"}, + {10, "r10"}, + {11, "r11"}, + {12, "r12"}, + {13, "r13"}, + {14, "r14"}, + {15, "r15"}, + {10, "sl\0"}, + {11, "fp\0"}, + {13, "sp\0"}, + {14, "lr\0"}, + {15, "pc\0"}, +}; + +#define MAX_SPECIAL_REGISTER_NAME_LENGTH 7 +typedef struct _special_reg_name_t { byte reg; char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1]; } special_reg_name_t; +STATIC const special_reg_name_t special_reg_name_table[] = { + {5, "IPSR"}, + {17, "BASEPRI"}, +}; + +// return empty string in case of error, so we can attempt to parse the string +// without a special check if it was in fact a string +STATIC const char *get_arg_str(mp_parse_node_t pn) { + if (MP_PARSE_NODE_IS_ID(pn)) { + qstr qst = MP_PARSE_NODE_LEAF_ARG(pn); + return qstr_str(qst); + } else { + return ""; + } +} + +STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) { + const char *reg_str = get_arg_str(pn); + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { + const reg_name_t *r = ®_name_table[i]; + if (reg_str[0] == r->name[0] + && reg_str[1] == r->name[1] + && reg_str[2] == r->name[2] + && (reg_str[2] == '\0' || reg_str[3] == '\0')) { + if (r->reg > max_reg) { + emit_inline_thumb_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects at most r%d", op, max_reg)); + return 0; + } else { + return r->reg; + } + } + } + emit_inline_thumb_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects a register", op)); + return 0; +} + +STATIC mp_uint_t get_arg_special_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + const char *reg_str = get_arg_str(pn); + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(special_reg_name_table); i++) { + const special_reg_name_t *r = &special_reg_name_table[i]; + if (strcmp(r->name, reg_str) == 0) { + return r->reg; + } + } + emit_inline_thumb_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects a special register", op)); + return 0; +} + +#if MICROPY_EMIT_INLINE_THUMB_FLOAT +STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + const char *reg_str = get_arg_str(pn); + if (reg_str[0] == 's' && reg_str[1] != '\0') { + mp_uint_t regno = 0; + for (++reg_str; *reg_str; ++reg_str) { + mp_uint_t v = *reg_str; + if (!('0' <= v && v <= '9')) { + goto malformed; + } + regno = 10 * regno + v - '0'; + } + if (regno > 31) { + emit_inline_thumb_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects at most r%d", op, 31)); + return 0; + } else { + return regno; + } + } +malformed: + emit_inline_thumb_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects an FPU register", op)); + return 0; +} +#endif + +STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + // a register list looks like {r0, r1, r2} and is parsed as a Python set + + if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_brace)) { + goto bad_arg; + } + + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 1); // should always be + pn = pns->nodes[0]; + + mp_uint_t reglist = 0; + + if (MP_PARSE_NODE_IS_ID(pn)) { + // set with one element + reglist |= 1 << get_arg_reg(emit, op, pn, 15); + } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { + pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) { + // set with multiple elements + + // get first element of set (we rely on get_arg_reg to catch syntax errors) + reglist |= 1 << get_arg_reg(emit, op, pns->nodes[0], 15); + + // get tail elements (2nd, 3rd, ...) + mp_parse_node_t *nodes; + int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes); + + // process rest of elements + for (int i = 0; i < n; i++) { + reglist |= 1 << get_arg_reg(emit, op, nodes[i], 15); + } + } else { + goto bad_arg; + } + } else { + goto bad_arg; + } + } else { + goto bad_arg; + } + + return reglist; + +bad_arg: + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op)); + return 0; +} + +STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint32_t fit_mask) { + mp_obj_t o; + if (!mp_parse_node_get_int_maybe(pn, &o)) { + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op)); + return 0; + } + uint32_t i = mp_obj_get_int_truncated(o); + if ((i & (~fit_mask)) != 0) { + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer 0x%x doesn't fit in mask 0x%x", op, i, fit_mask)); + return 0; + } + return i; +} + +STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_parse_node_t *pn_base, mp_parse_node_t *pn_offset) { + if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_bracket)) { + goto bad_arg; + } + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { + goto bad_arg; + } + pns = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) != 2) { + goto bad_arg; + } + + *pn_base = pns->nodes[0]; + *pn_offset = pns->nodes[1]; + return true; + +bad_arg: + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an address of the form [a, b]", op)); + return false; +} + +STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + if (!MP_PARSE_NODE_IS_ID(pn)) { + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op)); + return 0; + } + qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn); + for (uint i = 0; i < emit->max_num_labels; i++) { + if (emit->label_lookup[i] == label_qstr) { + return i; + } + } + // only need to have the labels on the last pass + if (emit->pass == MP_PASS_EMIT) { + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr)); + } + return 0; +} + +typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t; +STATIC const cc_name_t cc_name_table[] = { + { ASM_THUMB_CC_EQ, "eq" }, + { ASM_THUMB_CC_NE, "ne" }, + { ASM_THUMB_CC_CS, "cs" }, + { ASM_THUMB_CC_CC, "cc" }, + { ASM_THUMB_CC_MI, "mi" }, + { ASM_THUMB_CC_PL, "pl" }, + { ASM_THUMB_CC_VS, "vs" }, + { ASM_THUMB_CC_VC, "vc" }, + { ASM_THUMB_CC_HI, "hi" }, + { ASM_THUMB_CC_LS, "ls" }, + { ASM_THUMB_CC_GE, "ge" }, + { ASM_THUMB_CC_LT, "lt" }, + { ASM_THUMB_CC_GT, "gt" }, + { ASM_THUMB_CC_LE, "le" }, +}; + +typedef struct _format_4_op_t { byte op; char name[3]; } format_4_op_t; +#define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops +STATIC const format_4_op_t format_4_op_table[] = { + { X(ASM_THUMB_FORMAT_4_EOR), "eor" }, + { X(ASM_THUMB_FORMAT_4_LSL), "lsl" }, + { X(ASM_THUMB_FORMAT_4_LSR), "lsr" }, + { X(ASM_THUMB_FORMAT_4_ASR), "asr" }, + { X(ASM_THUMB_FORMAT_4_ADC), "adc" }, + { X(ASM_THUMB_FORMAT_4_SBC), "sbc" }, + { X(ASM_THUMB_FORMAT_4_ROR), "ror" }, + { X(ASM_THUMB_FORMAT_4_TST), "tst" }, + { X(ASM_THUMB_FORMAT_4_NEG), "neg" }, + { X(ASM_THUMB_FORMAT_4_CMP), "cmp" }, + { X(ASM_THUMB_FORMAT_4_CMN), "cmn" }, + { X(ASM_THUMB_FORMAT_4_ORR), "orr" }, + { X(ASM_THUMB_FORMAT_4_MUL), "mul" }, + { X(ASM_THUMB_FORMAT_4_BIC), "bic" }, + { X(ASM_THUMB_FORMAT_4_MVN), "mvn" }, +}; +#undef X + +// name is actually a qstr, which should fit in 16 bits +typedef struct _format_9_10_op_t { uint16_t op; uint16_t name; } format_9_10_op_t; +#define X(x) (x) +STATIC const format_9_10_op_t format_9_10_op_table[] = { + { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_ldr }, + { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_ldrb }, + { X(ASM_THUMB_FORMAT_10_LDRH), MP_QSTR_ldrh }, + { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_str }, + { X(ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER), MP_QSTR_strb }, + { X(ASM_THUMB_FORMAT_10_STRH), MP_QSTR_strh }, +}; +#undef X + +#if MICROPY_EMIT_INLINE_THUMB_FLOAT +// actual opcodes are: 0xee00 | op.hi_nibble, 0x0a00 | op.lo_nibble +typedef struct _format_vfp_op_t { byte op; char name[3]; } format_vfp_op_t; +STATIC const format_vfp_op_t format_vfp_op_table[] = { + { 0x30, "add" }, + { 0x34, "sub" }, + { 0x20, "mul" }, + { 0x80, "div" }, +}; +#endif + +// shorthand alias for whether we allow ARMv7-M instructions +#define ARMV7M MICROPY_EMIT_INLINE_THUMB_ARMV7M + +STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { + // TODO perhaps make two tables: + // one_args = + // "b", LAB, asm_thumb_b_n, + // "bgt", LAB, asm_thumb_bgt_n, + // two_args = + // "movs", RLO, I8, asm_thumb_movs_reg_i8 + // "movw", REG, REG, asm_thumb_movw_reg_i16 + // three_args = + // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 + + size_t op_len; + const char *op_str = (const char*)qstr_data(op, &op_len); + + #if MICROPY_EMIT_INLINE_THUMB_FLOAT + if (op_str[0] == 'v') { + // floating point operations + if (n_args == 2) { + mp_uint_t op_code = 0x0ac0, op_code_hi; + if (op == MP_QSTR_vcmp) { + op_code_hi = 0xeeb4; + op_vfp_twoargs:; + mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); + mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[1]); + asm_thumb_op32(&emit->as, + op_code_hi | ((vd & 1) << 6), + op_code | ((vd & 0x1e) << 11) | ((vm & 1) << 5) | (vm & 0x1e) >> 1); + } else if (op == MP_QSTR_vsqrt) { + op_code_hi = 0xeeb1; + goto op_vfp_twoargs; + } else if (op == MP_QSTR_vneg) { + op_code_hi = 0xeeb1; + op_code = 0x0a40; + goto op_vfp_twoargs; + } else if (op == MP_QSTR_vcvt_f32_s32) { + op_code_hi = 0xeeb8; // int to float + goto op_vfp_twoargs; + } else if (op == MP_QSTR_vcvt_s32_f32) { + op_code_hi = 0xeebd; // float to int + goto op_vfp_twoargs; + } else if (op == MP_QSTR_vmrs) { + mp_uint_t reg_dest; + const char *reg_str0 = get_arg_str(pn_args[0]); + if (strcmp(reg_str0, "APSR_nzcv") == 0) { + reg_dest = 15; + } else { + reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + } + const char *reg_str1 = get_arg_str(pn_args[1]); + if (strcmp(reg_str1, "FPSCR") == 0) { + // FP status to ARM reg + asm_thumb_op32(&emit->as, 0xeef1, 0x0a10 | (reg_dest << 12)); + } else { + goto unknown_op; + } + } else if (op == MP_QSTR_vmov) { + op_code_hi = 0xee00; + mp_uint_t r_arm, vm; + const char *reg_str = get_arg_str(pn_args[0]); + if (reg_str[0] == 'r') { + r_arm = get_arg_reg(emit, op_str, pn_args[0], 15); + vm = get_arg_vfpreg(emit, op_str, pn_args[1]); + op_code_hi |= 0x10; + } else { + vm = get_arg_vfpreg(emit, op_str, pn_args[0]); + r_arm = get_arg_reg(emit, op_str, pn_args[1], 15); + } + asm_thumb_op32(&emit->as, + op_code_hi | ((vm & 0x1e) >> 1), + 0x0a10 | (r_arm << 12) | ((vm & 1) << 7)); + } else if (op == MP_QSTR_vldr) { + op_code_hi = 0xed90; + op_vldr_vstr:; + mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); + mp_parse_node_t pn_base, pn_offset; + if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { + mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7); + mp_uint_t i8; + i8 = get_arg_i(emit, op_str, pn_offset, 0x3fc) >> 2; + asm_thumb_op32(&emit->as, + op_code_hi | rlo_base | ((vd & 1) << 6), + 0x0a00 | ((vd & 0x1e) << 11) | i8); + } + } else if (op == MP_QSTR_vstr) { + op_code_hi = 0xed80; + goto op_vldr_vstr; + } else { + goto unknown_op; + } + } else if (n_args == 3) { + // search table for arith ops + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_vfp_op_table); i++) { + if (strncmp(op_str + 1, format_vfp_op_table[i].name, 3) == 0 && op_str[4] == '\0') { + mp_uint_t op_code_hi = 0xee00 | (format_vfp_op_table[i].op & 0xf0); + mp_uint_t op_code = 0x0a00 | ((format_vfp_op_table[i].op & 0x0f) << 4); + mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]); + mp_uint_t vn = get_arg_vfpreg(emit, op_str, pn_args[1]); + mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[2]); + asm_thumb_op32(&emit->as, + op_code_hi | ((vd & 1) << 6) | (vn >> 1), + op_code | (vm >> 1) | ((vm & 1) << 5) | ((vd & 0x1e) << 11) | ((vn & 1) << 7)); + return; + } + } + goto unknown_op; + } else { + goto unknown_op; + } + } else + #endif + if (n_args == 0) { + if (op == MP_QSTR_nop) { + asm_thumb_op16(&emit->as, ASM_THUMB_OP_NOP); + } else if (op == MP_QSTR_wfi) { + asm_thumb_op16(&emit->as, ASM_THUMB_OP_WFI); + } else { + goto unknown_op; + } + + } else if (n_args == 1) { + if (op == MP_QSTR_b) { + int label_num = get_arg_label(emit, op_str, pn_args[0]); + if (!asm_thumb_b_n_label(&emit->as, label_num)) { + goto branch_not_in_range; + } + } else if (op == MP_QSTR_bl) { + int label_num = get_arg_label(emit, op_str, pn_args[0]); + if (!asm_thumb_bl_label(&emit->as, label_num)) { + goto branch_not_in_range; + } + } else if (op == MP_QSTR_bx) { + mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15); + asm_thumb_op16(&emit->as, 0x4700 | (r << 3)); + } else if (op_str[0] == 'b' && (op_len == 3 + || (op_len == 5 && op_str[3] == '_' + && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) { + mp_uint_t cc = -1; + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { + if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { + cc = cc_name_table[i].cc; + } + } + if (cc == (mp_uint_t)-1) { + goto unknown_op; + } + int label_num = get_arg_label(emit, op_str, pn_args[0]); + if (!asm_thumb_bcc_nw_label(&emit->as, cc, label_num, op_len == 5 && op_str[4] == 'w')) { + goto branch_not_in_range; + } + } else if (ARMV7M && op_str[0] == 'i' && op_str[1] == 't') { + const char *arg_str = get_arg_str(pn_args[0]); + mp_uint_t cc = -1; + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { + if (arg_str[0] == cc_name_table[i].name[0] + && arg_str[1] == cc_name_table[i].name[1] + && arg_str[2] == '\0') { + cc = cc_name_table[i].cc; + break; + } + } + if (cc == (mp_uint_t)-1) { + goto unknown_op; + } + const char *os = op_str + 2; + while (*os != '\0') { + os++; + } + if (os > op_str + 5) { + goto unknown_op; + } + mp_uint_t it_mask = 8; + while (--os >= op_str + 2) { + it_mask >>= 1; + if (*os == 't') { + it_mask |= (cc & 1) << 3; + } else if (*os == 'e') { + it_mask |= ((~cc) & 1) << 3; + } else { + goto unknown_op; + } + } + asm_thumb_it_cc(&emit->as, cc, it_mask); + } else if (op == MP_QSTR_cpsid) { + // TODO check pn_args[0] == i + asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSID_I); + } else if (op == MP_QSTR_cpsie) { + // TODO check pn_args[0] == i + asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSIE_I); + } else if (op == MP_QSTR_push) { + mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]); + if ((reglist & 0xff00) == 0) { + asm_thumb_op16(&emit->as, 0xb400 | reglist); + } else { + if (!ARMV7M) { + goto unknown_op; + } + asm_thumb_op32(&emit->as, 0xe92d, reglist); + } + } else if (op == MP_QSTR_pop) { + mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]); + if ((reglist & 0xff00) == 0) { + asm_thumb_op16(&emit->as, 0xbc00 | reglist); + } else { + if (!ARMV7M) { + goto unknown_op; + } + asm_thumb_op32(&emit->as, 0xe8bd, reglist); + } + } else { + goto unknown_op; + } + + } else if (n_args == 2) { + if (MP_PARSE_NODE_IS_ID(pn_args[1])) { + // second arg is a register (or should be) + mp_uint_t op_code, op_code_hi; + if (op == MP_QSTR_mov) { + mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + mp_uint_t reg_src = get_arg_reg(emit, op_str, pn_args[1], 15); + asm_thumb_mov_reg_reg(&emit->as, reg_dest, reg_src); + } else if (ARMV7M && op == MP_QSTR_clz) { + op_code_hi = 0xfab0; + op_code = 0xf080; + mp_uint_t rd, rm; + op_clz_rbit: + rd = get_arg_reg(emit, op_str, pn_args[0], 15); + rm = get_arg_reg(emit, op_str, pn_args[1], 15); + asm_thumb_op32(&emit->as, op_code_hi | rm, op_code | (rd << 8) | rm); + } else if (ARMV7M && op == MP_QSTR_rbit) { + op_code_hi = 0xfa90; + op_code = 0xf0a0; + goto op_clz_rbit; + } else if (ARMV7M && op == MP_QSTR_mrs){ + mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 12); + mp_uint_t reg_src = get_arg_special_reg(emit, op_str, pn_args[1]); + asm_thumb_op32(&emit->as, 0xf3ef, 0x8000 | (reg_dest << 8) | reg_src); + } else { + if (op == MP_QSTR_and_) { + op_code = ASM_THUMB_FORMAT_4_AND; + mp_uint_t reg_dest, reg_src; + op_format_4: + reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7); + reg_src = get_arg_reg(emit, op_str, pn_args[1], 7); + asm_thumb_format_4(&emit->as, op_code, reg_dest, reg_src); + return; + } + // search table for ALU ops + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_4_op_table); i++) { + if (strncmp(op_str, format_4_op_table[i].name, 3) == 0 && op_str[3] == '\0') { + op_code = 0x4000 | (format_4_op_table[i].op << 4); + goto op_format_4; + } + } + goto unknown_op; + } + } else { + // second arg is not a register + mp_uint_t op_code; + if (op == MP_QSTR_mov) { + op_code = ASM_THUMB_FORMAT_3_MOV; + mp_uint_t rlo_dest, i8_src; + op_format_3: + rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); + i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff); + asm_thumb_format_3(&emit->as, op_code, rlo_dest, i8_src); + } else if (op == MP_QSTR_cmp) { + op_code = ASM_THUMB_FORMAT_3_CMP; + goto op_format_3; + } else if (op == MP_QSTR_add) { + op_code = ASM_THUMB_FORMAT_3_ADD; + goto op_format_3; + } else if (op == MP_QSTR_sub) { + op_code = ASM_THUMB_FORMAT_3_SUB; + goto op_format_3; + } else if (ARMV7M && op == MP_QSTR_movw) { + op_code = ASM_THUMB_OP_MOVW; + mp_uint_t reg_dest; + op_movw_movt: + reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff); + asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src); + } else if (ARMV7M && op == MP_QSTR_movt) { + op_code = ASM_THUMB_OP_MOVT; + goto op_movw_movt; + } else if (ARMV7M && op == MP_QSTR_movwt) { + // this is a convenience instruction + mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff); + asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVW, reg_dest, i_src & 0xffff); + asm_thumb_mov_reg_i16(&emit->as, ASM_THUMB_OP_MOVT, reg_dest, (i_src >> 16) & 0xffff); + } else if (ARMV7M && op == MP_QSTR_ldrex) { + mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + mp_parse_node_t pn_base, pn_offset; + if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { + mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15); + mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2; + asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8); + } + } else { + // search table for ldr/str instructions + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(format_9_10_op_table); i++) { + if (op == format_9_10_op_table[i].name) { + op_code = format_9_10_op_table[i].op; + mp_parse_node_t pn_base, pn_offset; + mp_uint_t rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); + if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) { + mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7); + mp_uint_t i5; + if (op_code & ASM_THUMB_FORMAT_9_BYTE_TRANSFER) { + i5 = get_arg_i(emit, op_str, pn_offset, 0x1f); + } else if (op_code & ASM_THUMB_FORMAT_10_STRH) { // also catches LDRH + i5 = get_arg_i(emit, op_str, pn_offset, 0x3e) >> 1; + } else { + i5 = get_arg_i(emit, op_str, pn_offset, 0x7c) >> 2; + } + asm_thumb_format_9_10(&emit->as, op_code, rlo_dest, rlo_base, i5); + return; + } + break; + } + } + goto unknown_op; + } + } + + } else if (n_args == 3) { + mp_uint_t op_code; + if (op == MP_QSTR_lsl) { + op_code = ASM_THUMB_FORMAT_1_LSL; + mp_uint_t rlo_dest, rlo_src, i5; + op_format_1: + rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); + rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7); + i5 = get_arg_i(emit, op_str, pn_args[2], 0x1f); + asm_thumb_format_1(&emit->as, op_code, rlo_dest, rlo_src, i5); + } else if (op == MP_QSTR_lsr) { + op_code = ASM_THUMB_FORMAT_1_LSR; + goto op_format_1; + } else if (op == MP_QSTR_asr) { + op_code = ASM_THUMB_FORMAT_1_ASR; + goto op_format_1; + } else if (op == MP_QSTR_add) { + op_code = ASM_THUMB_FORMAT_2_ADD; + mp_uint_t rlo_dest, rlo_src; + op_format_2: + rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7); + rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7); + int src_b; + if (MP_PARSE_NODE_IS_ID(pn_args[2])) { + op_code |= ASM_THUMB_FORMAT_2_REG_OPERAND; + src_b = get_arg_reg(emit, op_str, pn_args[2], 7); + } else { + op_code |= ASM_THUMB_FORMAT_2_IMM_OPERAND; + src_b = get_arg_i(emit, op_str, pn_args[2], 0x7); + } + asm_thumb_format_2(&emit->as, op_code, rlo_dest, rlo_src, src_b); + } else if (ARMV7M && op == MP_QSTR_sdiv) { + op_code = 0xfb90; // sdiv high part + mp_uint_t rd, rn, rm; + op_sdiv_udiv: + rd = get_arg_reg(emit, op_str, pn_args[0], 15); + rn = get_arg_reg(emit, op_str, pn_args[1], 15); + rm = get_arg_reg(emit, op_str, pn_args[2], 15); + asm_thumb_op32(&emit->as, op_code | rn, 0xf0f0 | (rd << 8) | rm); + } else if (ARMV7M && op == MP_QSTR_udiv) { + op_code = 0xfbb0; // udiv high part + goto op_sdiv_udiv; + } else if (op == MP_QSTR_sub) { + op_code = ASM_THUMB_FORMAT_2_SUB; + goto op_format_2; + } else if (ARMV7M && op == MP_QSTR_strex) { + mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15); + mp_uint_t r_src = get_arg_reg(emit, op_str, pn_args[1], 15); + mp_parse_node_t pn_base, pn_offset; + if (get_arg_addr(emit, op_str, pn_args[2], &pn_base, &pn_offset)) { + mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15); + mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2; + asm_thumb_op32(&emit->as, 0xe840 | r_base, (r_src << 12) | (r_dest << 8) | i8); + } + } else { + goto unknown_op; + } + + } else { + goto unknown_op; + } + + return; + +unknown_op: + emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Thumb instruction '%s' with %d arguments", op_str, n_args)); + return; + +branch_not_in_range: + emit_inline_thumb_error_msg(emit, "branch not in range"); + return; +} + +const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { + emit_inline_thumb_start_pass, + emit_inline_thumb_end_pass, + emit_inline_thumb_count_params, + emit_inline_thumb_label, + emit_inline_thumb_op, +}; + +#endif // MICROPY_EMIT_INLINE_THUMB diff --git a/src/openmv/src/micropython/py/emitinlinextensa.c b/src/openmv/src/micropython/py/emitinlinextensa.c new file mode 100755 index 0000000..b5f9189 --- /dev/null +++ b/src/openmv/src/micropython/py/emitinlinextensa.c @@ -0,0 +1,345 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/emit.h" +#include "py/asmxtensa.h" + +#if MICROPY_EMIT_INLINE_XTENSA + +struct _emit_inline_asm_t { + asm_xtensa_t as; + uint16_t pass; + mp_obj_t *error_slot; + mp_uint_t max_num_labels; + qstr *label_lookup; +}; + +STATIC void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, const char *msg) { + *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg); +} + +STATIC void emit_inline_xtensa_error_exc(emit_inline_asm_t *emit, mp_obj_t exc) { + *emit->error_slot = exc; +} + +emit_inline_asm_t *emit_inline_xtensa_new(mp_uint_t max_num_labels) { + emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); + memset(&emit->as, 0, sizeof(emit->as)); + mp_asm_base_init(&emit->as.base, max_num_labels); + emit->max_num_labels = max_num_labels; + emit->label_lookup = m_new(qstr, max_num_labels); + return emit; +} + +void emit_inline_xtensa_free(emit_inline_asm_t *emit) { + m_del(qstr, emit->label_lookup, emit->max_num_labels); + mp_asm_base_deinit(&emit->as.base, false); + m_del_obj(emit_inline_asm_t, emit); +} + +STATIC void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, mp_obj_t *error_slot) { + emit->pass = pass; + emit->error_slot = error_slot; + if (emit->pass == MP_PASS_CODE_SIZE) { + memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); + } + mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); + asm_xtensa_entry(&emit->as, 0); +} + +STATIC void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) { + asm_xtensa_exit(&emit->as); + asm_xtensa_end_pass(&emit->as); +} + +STATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) { + if (n_params > 4) { + emit_inline_xtensa_error_msg(emit, "can only have up to 4 parameters to Xtensa assembly"); + return 0; + } + for (mp_uint_t i = 0; i < n_params; i++) { + if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { + emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5"); + return 0; + } + const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); + if (!(strlen(p) == 2 && p[0] == 'a' && p[1] == '2' + i)) { + emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5"); + return 0; + } + } + return n_params; +} + +STATIC bool emit_inline_xtensa_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) { + assert(label_num < emit->max_num_labels); + if (emit->pass == MP_PASS_CODE_SIZE) { + // check for duplicate label on first pass + for (uint i = 0; i < emit->max_num_labels; i++) { + if (emit->label_lookup[i] == label_id) { + return false; + } + } + } + emit->label_lookup[label_num] = label_id; + mp_asm_base_label_assign(&emit->as.base, label_num); + return true; +} + +typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; +STATIC const reg_name_t reg_name_table[] = { + {0, "a0\0"}, + {1, "a1\0"}, + {2, "a2\0"}, + {3, "a3\0"}, + {4, "a4\0"}, + {5, "a5\0"}, + {6, "a6\0"}, + {7, "a7\0"}, + {8, "a8\0"}, + {9, "a9\0"}, + {10, "a10"}, + {11, "a11"}, + {12, "a12"}, + {13, "a13"}, + {14, "a14"}, + {15, "a15"}, +}; + +// return empty string in case of error, so we can attempt to parse the string +// without a special check if it was in fact a string +STATIC const char *get_arg_str(mp_parse_node_t pn) { + if (MP_PARSE_NODE_IS_ID(pn)) { + qstr qst = MP_PARSE_NODE_LEAF_ARG(pn); + return qstr_str(qst); + } else { + return ""; + } +} + +STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + const char *reg_str = get_arg_str(pn); + for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { + const reg_name_t *r = ®_name_table[i]; + if (reg_str[0] == r->name[0] + && reg_str[1] == r->name[1] + && reg_str[2] == r->name[2] + && (reg_str[2] == '\0' || reg_str[3] == '\0')) { + return r->reg; + } + } + emit_inline_xtensa_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + "'%s' expects a register", op)); + return 0; +} + +STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int min, int max) { + mp_obj_t o; + if (!mp_parse_node_get_int_maybe(pn, &o)) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op)); + return 0; + } + uint32_t i = mp_obj_get_int_truncated(o); + if (min != max && ((int)i < min || (int)i > max)) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer %d isn't within range %d..%d", op, i, min, max)); + return 0; + } + return i; +} + +STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) { + if (!MP_PARSE_NODE_IS_ID(pn)) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op)); + return 0; + } + qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn); + for (uint i = 0; i < emit->max_num_labels; i++) { + if (emit->label_lookup[i] == label_qstr) { + return i; + } + } + // only need to have the labels on the last pass + if (emit->pass == MP_PASS_EMIT) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr)); + } + return 0; +} + +#define RRR (0) +#define RRI8 (1) +#define RRI8_B (2) + +typedef struct _opcode_table_3arg_t { + uint16_t name; // actually a qstr, which should fit in 16 bits + uint8_t type; + uint8_t a0 : 4; + uint8_t a1 : 4; +} opcode_table_3arg_t; + +STATIC const opcode_table_3arg_t opcode_table_3arg[] = { + // arithmetic opcodes: reg, reg, reg + {MP_QSTR_and_, RRR, 0, 1}, + {MP_QSTR_or_, RRR, 0, 2}, + {MP_QSTR_xor, RRR, 0, 3}, + {MP_QSTR_add, RRR, 0, 8}, + {MP_QSTR_sub, RRR, 0, 12}, + {MP_QSTR_mull, RRR, 2, 8}, + + // load/store/addi opcodes: reg, reg, imm + // upper nibble of type encodes the range of the immediate arg + {MP_QSTR_l8ui, RRI8 | 0x10, 2, 0}, + {MP_QSTR_l16ui, RRI8 | 0x30, 2, 1}, + {MP_QSTR_l32i, RRI8 | 0x50, 2, 2}, + {MP_QSTR_s8i, RRI8 | 0x10, 2, 4}, + {MP_QSTR_s16i, RRI8 | 0x30, 2, 5}, + {MP_QSTR_s32i, RRI8 | 0x50, 2, 6}, + {MP_QSTR_l16si, RRI8 | 0x30, 2, 9}, + {MP_QSTR_addi, RRI8 | 0x00, 2, 12}, + + // branch opcodes: reg, reg, label + {MP_QSTR_ball, RRI8_B, ASM_XTENSA_CC_ALL, 0}, + {MP_QSTR_bany, RRI8_B, ASM_XTENSA_CC_ANY, 0}, + {MP_QSTR_bbc, RRI8_B, ASM_XTENSA_CC_BC, 0}, + {MP_QSTR_bbs, RRI8_B, ASM_XTENSA_CC_BS, 0}, + {MP_QSTR_beq, RRI8_B, ASM_XTENSA_CC_EQ, 0}, + {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0}, + {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0}, + {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0}, + {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0}, + {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0}, + {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0}, +}; + +STATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { + size_t op_len; + const char *op_str = (const char*)qstr_data(op, &op_len); + + if (n_args == 0) { + if (op == MP_QSTR_ret_n) { + asm_xtensa_op_ret_n(&emit->as); + } else { + goto unknown_op; + } + + } else if (n_args == 1) { + if (op == MP_QSTR_callx0) { + uint r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_callx0(&emit->as, r0); + } else if (op == MP_QSTR_j) { + int label = get_arg_label(emit, op_str, pn_args[0]); + asm_xtensa_j_label(&emit->as, label); + } else if (op == MP_QSTR_jx) { + uint r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_jx(&emit->as, r0); + } else { + goto unknown_op; + } + + } else if (n_args == 2) { + uint r0 = get_arg_reg(emit, op_str, pn_args[0]); + if (op == MP_QSTR_beqz) { + int label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); + } else if (op == MP_QSTR_bnez) { + int label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); + } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { + // we emit mov.n for both "mov" and "mov_n" opcodes + uint r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op_mov_n(&emit->as, r0, r1); + } else if (op == MP_QSTR_movi) { + // for convenience we emit l32r if the integer doesn't fit in movi + uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); + asm_xtensa_mov_reg_i32(&emit->as, r0, imm); + } else { + goto unknown_op; + } + + } else if (n_args == 3) { + // search table for 3 arg instructions + for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { + const opcode_table_3arg_t *o = &opcode_table_3arg[i]; + if (op == o->name) { + uint r0 = get_arg_reg(emit, op_str, pn_args[0]); + uint r1 = get_arg_reg(emit, op_str, pn_args[1]); + if (o->type == RRR) { + uint r2 = get_arg_reg(emit, op_str, pn_args[2]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); + } else if (o->type == RRI8_B) { + int label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); + } else { + int shift, min, max; + if ((o->type & 0xf0) == 0) { + shift = 0; + min = -128; + max = 127; + } else { + shift = (o->type & 0xf0) >> 5; + min = 0; + max = 0xff << shift; + } + uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); + } + return; + } + } + goto unknown_op; + + } else { + goto unknown_op; + } + + return; + +unknown_op: + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Xtensa instruction '%s' with %d arguments", op_str, n_args)); + return; + + /* +branch_not_in_range: + emit_inline_xtensa_error_msg(emit, "branch not in range"); + return; + */ +} + +const emit_inline_asm_method_table_t emit_inline_xtensa_method_table = { + emit_inline_xtensa_start_pass, + emit_inline_xtensa_end_pass, + emit_inline_xtensa_count_params, + emit_inline_xtensa_label, + emit_inline_xtensa_op, +}; + +#endif // MICROPY_EMIT_INLINE_XTENSA diff --git a/src/openmv/src/micropython/py/emitnarm.c b/src/openmv/src/micropython/py/emitnarm.c new file mode 100755 index 0000000..8297ad6 --- /dev/null +++ b/src/openmv/src/micropython/py/emitnarm.c @@ -0,0 +1,20 @@ +// ARM specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_ARM + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmarm.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (3) // r4 +#define NLR_BUF_IDX_LOCAL_2 (4) // r5 +#define NLR_BUF_IDX_LOCAL_3 (5) // r6 + +#define N_ARM (1) +#define EXPORT_FUN(name) emit_native_arm_##name +#include "py/emitnative.c" + +#endif diff --git a/src/openmv/src/micropython/py/emitnative.c b/src/openmv/src/micropython/py/emitnative.c new file mode 100755 index 0000000..a198ffb --- /dev/null +++ b/src/openmv/src/micropython/py/emitnative.c @@ -0,0 +1,2749 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Essentially normal Python has 1 type: Python objects +// Viper has more than 1 type, and is just a more complicated (a superset of) Python. +// If you declare everything in Viper as a Python object (ie omit type decls) then +// it should in principle be exactly the same as Python native. +// Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc. +// In practice we won't have a VM but rather do this in asm which is actually very minimal. + +// Because it breaks strict Python equivalence it should be a completely separate +// decorator. It breaks equivalence because overflow on integers wraps around. +// It shouldn't break equivalence if you don't use the new types, but since the +// type decls might be used in normal Python for other reasons, it's probably safest, +// cleanest and clearest to make it a separate decorator. + +// Actually, it does break equivalence because integers default to native integers, +// not Python objects. + +// for x in l[0:8]: can be compiled into a native loop if l has pointer type + +#include +#include +#include + +#include "py/emit.h" +#include "py/bc.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +// wrapper around everything in this file +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA + +// C stack layout for native functions: +// 0: nlr_buf_t [optional] +// emit->code_state_start: mp_code_state_t +// emit->stack_start: Python object stack | emit->n_state +// locals (reversed, L0 at end) | +// +// C stack layout for native generator functions: +// 0=emit->stack_start: nlr_buf_t +// +// Then REG_GENERATOR_STATE points to: +// 0=emit->code_state_start: mp_code_state_t +// emit->stack_start: Python object stack | emit->n_state +// locals (reversed, L0 at end) | +// +// C stack layout for viper functions: +// 0: nlr_buf_t [optional] +// emit->code_state_start: fun_obj, old_globals [optional] +// emit->stack_start: Python object stack | emit->n_state +// locals (reversed, L0 at end) | +// (L0-L2 may be in regs instead) + +// Word index of nlr_buf_t.ret_val +#define NLR_BUF_IDX_RET_VAL (1) + +// Whether the viper function needs access to fun_obj +#define NEED_FUN_OBJ(emit) ((emit)->scope->exc_stack_size > 0 \ + || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS))) + +// Whether the native/viper function needs to be wrapped in an exception handler +#define NEED_GLOBAL_EXC_HANDLER(emit) ((emit)->scope->exc_stack_size > 0 \ + || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_REFGLOBALS))) + +// Whether registers can be used to store locals (only true if there are no +// exception handlers, because otherwise an nlr_jump will restore registers to +// their state at the start of the function and updates to locals will be lost) +#define CAN_USE_REGS_FOR_LOCALS(emit) ((emit)->scope->exc_stack_size == 0 && !(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) + +// Indices within the local C stack for various variables +#define LOCAL_IDX_EXC_VAL(emit) (NLR_BUF_IDX_RET_VAL) +#define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1) +#define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (NLR_BUF_IDX_LOCAL_2) +#define LOCAL_IDX_RET_VAL(emit) (NLR_BUF_IDX_LOCAL_3) +#define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)) +#define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) +#define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t)) +#define LOCAL_IDX_LOCAL_VAR(emit, local_num) ((emit)->stack_start + (emit)->n_state - 1 - (local_num)) + +#define REG_GENERATOR_STATE (REG_LOCAL_3) + +#define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \ + *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ + } while (0) + +typedef enum { + STACK_VALUE, + STACK_REG, + STACK_IMM, +} stack_info_kind_t; + +// these enums must be distinct and the bottom 4 bits +// must correspond to the correct MP_NATIVE_TYPE_xxx value +typedef enum { + VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ, + VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL, + VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT, + VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT, + VTYPE_PTR = 0x00 | MP_NATIVE_TYPE_PTR, + VTYPE_PTR8 = 0x00 | MP_NATIVE_TYPE_PTR8, + VTYPE_PTR16 = 0x00 | MP_NATIVE_TYPE_PTR16, + VTYPE_PTR32 = 0x00 | MP_NATIVE_TYPE_PTR32, + + VTYPE_PTR_NONE = 0x50 | MP_NATIVE_TYPE_PTR, + + VTYPE_UNBOUND = 0x60 | MP_NATIVE_TYPE_OBJ, + VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ, +} vtype_kind_t; + +int mp_native_type_from_qstr(qstr qst) { + switch (qst) { + case MP_QSTR_object: return MP_NATIVE_TYPE_OBJ; + case MP_QSTR_bool: return MP_NATIVE_TYPE_BOOL; + case MP_QSTR_int: return MP_NATIVE_TYPE_INT; + case MP_QSTR_uint: return MP_NATIVE_TYPE_UINT; + case MP_QSTR_ptr: return MP_NATIVE_TYPE_PTR; + case MP_QSTR_ptr8: return MP_NATIVE_TYPE_PTR8; + case MP_QSTR_ptr16: return MP_NATIVE_TYPE_PTR16; + case MP_QSTR_ptr32: return MP_NATIVE_TYPE_PTR32; + default: return -1; + } +} + +STATIC qstr vtype_to_qstr(vtype_kind_t vtype) { + switch (vtype) { + case VTYPE_PYOBJ: return MP_QSTR_object; + case VTYPE_BOOL: return MP_QSTR_bool; + case VTYPE_INT: return MP_QSTR_int; + case VTYPE_UINT: return MP_QSTR_uint; + case VTYPE_PTR: return MP_QSTR_ptr; + case VTYPE_PTR8: return MP_QSTR_ptr8; + case VTYPE_PTR16: return MP_QSTR_ptr16; + case VTYPE_PTR32: return MP_QSTR_ptr32; + case VTYPE_PTR_NONE: default: return MP_QSTR_None; + } +} + +typedef struct _stack_info_t { + vtype_kind_t vtype; + stack_info_kind_t kind; + union { + int u_reg; + mp_int_t u_imm; + } data; +} stack_info_t; + +#define UNWIND_LABEL_UNUSED (0x7fff) +#define UNWIND_LABEL_DO_FINAL_UNWIND (0x7ffe) + +typedef struct _exc_stack_entry_t { + uint16_t label : 15; + uint16_t is_finally : 1; + uint16_t unwind_label : 15; + uint16_t is_active : 1; +} exc_stack_entry_t; + +struct _emit_t { + mp_obj_t *error_slot; + uint *label_slot; + uint exit_label; + int pass; + + bool do_viper_types; + + mp_uint_t local_vtype_alloc; + vtype_kind_t *local_vtype; + + mp_uint_t stack_info_alloc; + stack_info_t *stack_info; + vtype_kind_t saved_stack_vtype; + + size_t exc_stack_alloc; + size_t exc_stack_size; + exc_stack_entry_t *exc_stack; + + int prelude_offset; + int start_offset; + int n_state; + uint16_t code_state_start; + uint16_t stack_start; + int stack_size; + + uint16_t const_table_cur_obj; + uint16_t const_table_num_obj; + uint16_t const_table_cur_raw_code; + mp_uint_t *const_table; + + bool last_emit_was_return_value; + + scope_t *scope; + + ASM_T *as; +}; + +STATIC const uint8_t reg_local_table[REG_LOCAL_NUM] = {REG_LOCAL_1, REG_LOCAL_2, REG_LOCAL_3}; + +STATIC void emit_native_global_exc_entry(emit_t *emit); +STATIC void emit_native_global_exc_exit(emit_t *emit); + +emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) { + emit_t *emit = m_new0(emit_t, 1); + emit->error_slot = error_slot; + emit->label_slot = label_slot; + emit->stack_info_alloc = 8; + emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc); + emit->exc_stack_alloc = 8; + emit->exc_stack = m_new(exc_stack_entry_t, emit->exc_stack_alloc); + emit->as = m_new0(ASM_T, 1); + mp_asm_base_init(&emit->as->base, max_num_labels); + return emit; +} + +void EXPORT_FUN(free)(emit_t *emit) { + mp_asm_base_deinit(&emit->as->base, false); + m_del_obj(ASM_T, emit->as); + m_del(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc); + m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc); + m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc); + m_del_obj(emit_t, emit); +} + +STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg); + +STATIC void emit_native_mov_reg_const(emit_t *emit, int reg_dest, int const_val) { + ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_FUN_TABLE, const_val); +} + +STATIC void emit_native_mov_state_reg(emit_t *emit, int local_num, int reg_src) { + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, REG_GENERATOR_STATE, local_num); + } else { + ASM_MOV_LOCAL_REG(emit->as, local_num, reg_src); + } +} + +STATIC void emit_native_mov_reg_state(emit_t *emit, int reg_dest, int local_num) { + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_GENERATOR_STATE, local_num); + } else { + ASM_MOV_REG_LOCAL(emit->as, reg_dest, local_num); + } +} + +STATIC void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local_num) { + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + ASM_MOV_REG_IMM(emit->as, reg_dest, local_num * ASM_WORD_SIZE); + ASM_ADD_REG_REG(emit->as, reg_dest, REG_GENERATOR_STATE); + } else { + ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, local_num); + } +} + +#define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \ + do { \ + ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \ + emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \ + } while (false) + +STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { + DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); + + emit->pass = pass; + emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER; + emit->stack_size = 0; + emit->const_table_cur_obj = 1; // first entry is for mp_fun_table + emit->const_table_cur_raw_code = 0; + emit->last_emit_was_return_value = false; + emit->scope = scope; + + // allocate memory for keeping track of the types of locals + if (emit->local_vtype_alloc < scope->num_locals) { + emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals); + emit->local_vtype_alloc = scope->num_locals; + } + + // set default type for arguments + mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args; + if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) { + num_args += 1; + } + if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) { + num_args += 1; + } + for (mp_uint_t i = 0; i < num_args; i++) { + emit->local_vtype[i] = VTYPE_PYOBJ; + } + + // Set viper type for arguments + if (emit->do_viper_types) { + for (int i = 0; i < emit->scope->id_info_len; ++i) { + id_info_t *id = &emit->scope->id_info[i]; + if (id->flags & ID_FLAG_IS_PARAM) { + assert(id->local_num < emit->local_vtype_alloc); + emit->local_vtype[id->local_num] = id->flags >> ID_FLAG_VIPER_TYPE_POS; + } + } + } + + // local variables begin unbound, and have unknown type + for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) { + emit->local_vtype[i] = VTYPE_UNBOUND; + } + + // values on stack begin unbound + for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) { + emit->stack_info[i].kind = STACK_VALUE; + emit->stack_info[i].vtype = VTYPE_UNBOUND; + } + + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); + + // generate code for entry to function + + // Work out start of code state (mp_code_state_t or reduced version for viper) + emit->code_state_start = 0; + if (NEED_GLOBAL_EXC_HANDLER(emit)) { + emit->code_state_start = sizeof(nlr_buf_t) / sizeof(uintptr_t); + } + + if (emit->do_viper_types) { + // Work out size of state (locals plus stack) + // n_state counts all stack and locals, even those in registers + emit->n_state = scope->num_locals + scope->stack_size; + int num_locals_in_regs = 0; + if (CAN_USE_REGS_FOR_LOCALS(emit)) { + num_locals_in_regs = scope->num_locals; + if (num_locals_in_regs > REG_LOCAL_NUM) { + num_locals_in_regs = REG_LOCAL_NUM; + } + // Need a spot for REG_LOCAL_3 if 4 or more args (see below) + if (scope->num_pos_args >= 4) { + --num_locals_in_regs; + } + } + + // Work out where the locals and Python stack start within the C stack + if (NEED_GLOBAL_EXC_HANDLER(emit)) { + // Reserve 2 words for function object and old globals + emit->stack_start = emit->code_state_start + 2; + } else if (scope->scope_flags & MP_SCOPE_FLAG_HASCONSTS) { + // Reserve 1 word for function object, to access const table + emit->stack_start = emit->code_state_start + 1; + } else { + emit->stack_start = emit->code_state_start + 0; + } + + // Entry to function + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); + + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); + #endif + + // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0); + + // Store function object (passed as first arg) to stack if needed + if (NEED_FUN_OBJ(emit)) { + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + } + + // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3 + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_3); + #else + ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_ARG_2); + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_3); + ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_4); + #endif + + // Check number of args matches this function, and call mp_arg_check_num_sig if not + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_ARG_2, *emit->label_slot + 4, true); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, scope->num_pos_args); + ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_3, *emit->label_slot + 5); + mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 4); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, MP_OBJ_FUN_MAKE_SIG(scope->num_pos_args, scope->num_pos_args, false)); + ASM_CALL_IND(emit->as, MP_F_ARG_CHECK_NUM_SIG); + mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 5); + + // Store arguments into locals (reg or stack), converting to native if needed + for (int i = 0; i < emit->scope->num_pos_args; i++) { + int r = REG_ARG_1; + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_LOCAL_3, i); + if (emit->local_vtype[i] != VTYPE_PYOBJ) { + emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, emit->local_vtype[i], REG_ARG_2); + r = REG_RET; + } + // REG_LOCAL_3 points to the args array so be sure not to overwrite it if it's still needed + if (i < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit) && (i != 2 || emit->scope->num_pos_args == 3)) { + ASM_MOV_REG_REG(emit->as, reg_local_table[i], r); + } else { + emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, i), r); + } + } + // Get 3rd local from the stack back into REG_LOCAL_3 if this reg couldn't be written to above + if (emit->scope->num_pos_args >= 4 && CAN_USE_REGS_FOR_LOCALS(emit)) { + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, LOCAL_IDX_LOCAL_VAR(emit, 2)); + } + + emit_native_global_exc_entry(emit); + + } else { + // work out size of state (locals plus stack) + emit->n_state = scope->num_locals + scope->stack_size; + + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + emit->code_state_start = 0; + emit->stack_start = sizeof(mp_code_state_t) / sizeof(mp_uint_t); + mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_offset); + mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); + ASM_ENTRY(emit->as, sizeof(nlr_buf_t) / sizeof(uintptr_t)); + + // Put address of code_state into REG_GENERATOR_STATE + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE); + #else + ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_ARG_1); + #endif + + // Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); + #endif + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_ARG_2); + + // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, emit->scope->num_pos_args + emit->scope->num_kwonly_args); + } else { + // The locals and stack start after the code_state structure + emit->stack_start = emit->code_state_start + sizeof(mp_code_state_t) / sizeof(mp_uint_t); + + // Allocate space on C-stack for code_state structure, which includes state + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state); + + // Prepare incoming arguments for call to mp_setup_code_state + + #if N_X86 + asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4); + #endif + + // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args); + + // Set code_state.fun_bc + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1); + + // Set code_state.ip (offset from start of this function to prelude info) + // TODO this encoding may change size in the final pass, need to make it fixed + emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), emit->prelude_offset, REG_ARG_1); + + // Put address of code_state into first arg + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start); + + // Call mp_setup_code_state to prepare code_state structure + #if N_THUMB + asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); + #elif N_ARM + asm_arm_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4); + #else + ASM_CALL_IND(emit->as, MP_F_SETUP_CODE_STATE); + #endif + } + + emit_native_global_exc_entry(emit); + + // cache some locals in registers, but only if no exception handlers + if (CAN_USE_REGS_FOR_LOCALS(emit)) { + for (int i = 0; i < REG_LOCAL_NUM && i < scope->num_locals; ++i) { + ASM_MOV_REG_LOCAL(emit->as, reg_local_table[i], LOCAL_IDX_LOCAL_VAR(emit, i)); + } + } + + // set the type of closed over variables + for (mp_uint_t i = 0; i < scope->id_info_len; i++) { + id_info_t *id = &scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + emit->local_vtype[id->local_num] = VTYPE_PYOBJ; + } + } + + if (pass == MP_PASS_EMIT) { + // write argument names as qstr objects + // see comment in corresponding part of emitbc.c about the logic here + for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) { + qstr qst = MP_QSTR__star_; + for (int j = 0; j < scope->id_info_len; ++j) { + id_info_t *id = &scope->id_info[j]; + if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) { + qst = id->qst; + break; + } + } + emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst); + } + } + } + +} + +STATIC void emit_native_end_pass(emit_t *emit) { + emit_native_global_exc_exit(emit); + + if (!emit->do_viper_types) { + emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); + mp_asm_base_data(&emit->as->base, 1, 0x80 | ((emit->n_state >> 7) & 0x7f)); + mp_asm_base_data(&emit->as->base, 1, emit->n_state & 0x7f); + mp_asm_base_data(&emit->as->base, 1, 0); // n_exc_stack + mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args); + + // write code info + #if MICROPY_PERSISTENT_CODE + mp_asm_base_data(&emit->as->base, 1, 5); + mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name); + mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8); + mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file); + mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8); + #else + mp_asm_base_data(&emit->as->base, 1, 1); + #endif + + // bytecode prelude: initialise closed over variables + for (int i = 0; i < emit->scope->id_info_len; i++) { + id_info_t *id = &emit->scope->id_info[i]; + if (id->kind == ID_INFO_KIND_CELL) { + assert(id->local_num < 255); + mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell + } + } + mp_asm_base_data(&emit->as->base, 1, 255); // end of list sentinel + } + + ASM_END_PASS(emit->as); + + // check stack is back to zero size + assert(emit->stack_size == 0); + assert(emit->exc_stack_size == 0); + + // Deal with const table accounting + assert(emit->pass <= MP_PASS_STACK_SIZE || (emit->const_table_num_obj == emit->const_table_cur_obj)); + emit->const_table_num_obj = emit->const_table_cur_obj; + if (emit->pass == MP_PASS_CODE_SIZE) { + size_t const_table_alloc = emit->const_table_num_obj + emit->const_table_cur_raw_code; + size_t nqstr = 0; + if (!emit->do_viper_types) { + // Add room for qstr names of arguments + nqstr = emit->scope->num_pos_args + emit->scope->num_kwonly_args; + const_table_alloc += nqstr; + } + emit->const_table = m_new(mp_uint_t, const_table_alloc); + // Store mp_fun_table pointer just after qstrs + emit->const_table[nqstr] = (mp_uint_t)(uintptr_t)mp_fun_table; + } + + if (emit->pass == MP_PASS_EMIT) { + void *f = mp_asm_base_get_code(&emit->as->base); + mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base); + + mp_emit_glue_assign_native(emit->scope->raw_code, + emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, + f, f_len, emit->const_table, + emit->scope->num_pos_args, emit->scope->scope_flags, 0); + } +} + +STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) { + return emit->last_emit_was_return_value; +} + +STATIC void ensure_extra_stack(emit_t *emit, size_t delta) { + if (emit->stack_size + delta > emit->stack_info_alloc) { + size_t new_alloc = (emit->stack_size + delta + 8) & ~3; + emit->stack_info = m_renew(stack_info_t, emit->stack_info, emit->stack_info_alloc, new_alloc); + emit->stack_info_alloc = new_alloc; + } +} + +STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) { + assert((mp_int_t)emit->stack_size + stack_size_delta >= 0); + assert((mp_int_t)emit->stack_size + stack_size_delta <= (mp_int_t)emit->stack_info_alloc); + emit->stack_size += stack_size_delta; + if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) { + emit->scope->stack_size = emit->stack_size; + } +#ifdef DEBUG_PRINT + DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta); + for (int i = 0; i < emit->stack_size; i++) { + stack_info_t *si = &emit->stack_info[i]; + DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg); + } + DEBUG_printf("\n"); +#endif +} + +STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) { + DEBUG_printf("adjust_stack_size(" INT_FMT ")\n", delta); + if (delta > 0) { + ensure_extra_stack(emit, delta); + } + // If we are adjusting the stack in a positive direction (pushing) then we + // need to fill in values for the stack kind and vtype of the newly-pushed + // entries. These should be set to "value" (ie not reg or imm) because we + // should only need to adjust the stack due to a jump to this part in the + // code (and hence we have settled the stack before the jump). + for (mp_int_t i = 0; i < delta; i++) { + stack_info_t *si = &emit->stack_info[emit->stack_size + i]; + si->kind = STACK_VALUE; + // TODO we don't know the vtype to use here. At the moment this is a + // hack to get the case of multi comparison working. + if (delta == 1) { + si->vtype = emit->saved_stack_vtype; + } else { + si->vtype = VTYPE_PYOBJ; + } + } + adjust_stack(emit, delta); +} + +STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) { + (void)emit; + (void)source_line; +} + +// this must be called at start of emit functions +STATIC void emit_native_pre(emit_t *emit) { + emit->last_emit_was_return_value = false; +} + +// depth==0 is top, depth==1 is before top, etc +STATIC stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) { + return &emit->stack_info[emit->stack_size - 1 - depth]; +} + +// depth==0 is top, depth==1 is before top, etc +STATIC vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) { + if (emit->do_viper_types) { + return peek_stack(emit, depth)->vtype; + } else { + // Type is always PYOBJ even if the intermediate stored value is not + return VTYPE_PYOBJ; + } +} + +// pos=1 is TOS, pos=2 is next, etc +// use pos=0 for no skipping +STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) { + skip_stack_pos = emit->stack_size - skip_stack_pos; + for (int i = 0; i < emit->stack_size; i++) { + if (i != skip_stack_pos) { + stack_info_t *si = &emit->stack_info[i]; + if (si->kind == STACK_REG && si->data.u_reg == reg_needed) { + si->kind = STACK_VALUE; + emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg); + } + } + } +} + +STATIC void need_reg_all(emit_t *emit) { + for (int i = 0; i < emit->stack_size; i++) { + stack_info_t *si = &emit->stack_info[i]; + if (si->kind == STACK_REG) { + si->kind = STACK_VALUE; + emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg); + } + } +} + +STATIC vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_info_t *si, bool convert_to_pyobj) { + if (!convert_to_pyobj && emit->do_viper_types) { + ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm); + return si->vtype; + } else { + if (si->vtype == VTYPE_PYOBJ) { + ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm); + } else if (si->vtype == VTYPE_BOOL) { + emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_FALSE_OBJ + si->data.u_imm); + } else if (si->vtype == VTYPE_INT || si->vtype == VTYPE_UINT) { + ASM_MOV_REG_IMM(emit->as, reg_dest, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm)); + } else if (si->vtype == VTYPE_PTR_NONE) { + emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_NONE_OBJ); + } else { + mp_raise_NotImplementedError("conversion to object"); + } + return VTYPE_PYOBJ; + } +} + +STATIC void need_stack_settled(emit_t *emit) { + DEBUG_printf(" need_stack_settled; stack_size=%d\n", emit->stack_size); + for (int i = 0; i < emit->stack_size; i++) { + stack_info_t *si = &emit->stack_info[i]; + if (si->kind == STACK_REG) { + DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i); + si->kind = STACK_VALUE; + emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg); + } + } + for (int i = 0; i < emit->stack_size; i++) { + stack_info_t *si = &emit->stack_info[i]; + if (si->kind == STACK_IMM) { + DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i); + si->kind = STACK_VALUE; + si->vtype = load_reg_stack_imm(emit, REG_TEMP0, si, false); + emit_native_mov_state_reg(emit, emit->stack_start + i, REG_TEMP0); + } + } +} + +// pos=1 is TOS, pos=2 is next, etc +STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) { + need_reg_single(emit, reg_dest, pos); + stack_info_t *si = &emit->stack_info[emit->stack_size - pos]; + *vtype = si->vtype; + switch (si->kind) { + case STACK_VALUE: + emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - pos); + break; + + case STACK_REG: + if (si->data.u_reg != reg_dest) { + ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg); + } + break; + + case STACK_IMM: + *vtype = load_reg_stack_imm(emit, reg_dest, si, false); + break; + } +} + +// does an efficient X=pop(); discard(); push(X) +// needs a (non-temp) register in case the poped element was stored in the stack +STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) { + stack_info_t *si = &emit->stack_info[emit->stack_size - 2]; + si[0] = si[1]; + if (si->kind == STACK_VALUE) { + // if folded element was on the stack we need to put it in a register + emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - 1); + si->kind = STACK_REG; + si->data.u_reg = reg_dest; + } + adjust_stack(emit, -1); +} + +// If stacked value is in a register and the register is not r1 or r2, then +// *reg_dest is set to that register. Otherwise the value is put in *reg_dest. +STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) { + emit->last_emit_was_return_value = false; + stack_info_t *si = peek_stack(emit, 0); + if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) { + *vtype = si->vtype; + *reg_dest = si->data.u_reg; + need_reg_single(emit, *reg_dest, 1); + } else { + emit_access_stack(emit, 1, vtype, *reg_dest); + } + adjust_stack(emit, -1); +} + +STATIC void emit_pre_pop_discard(emit_t *emit) { + emit->last_emit_was_return_value = false; + adjust_stack(emit, -1); +} + +STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) { + emit->last_emit_was_return_value = false; + emit_access_stack(emit, 1, vtype, reg_dest); + adjust_stack(emit, -1); +} + +STATIC void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) { + emit_pre_pop_reg(emit, vtypea, rega); + emit_pre_pop_reg(emit, vtypeb, regb); +} + +STATIC void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb, vtype_kind_t *vtypec, int regc) { + emit_pre_pop_reg(emit, vtypea, rega); + emit_pre_pop_reg(emit, vtypeb, regb); + emit_pre_pop_reg(emit, vtypec, regc); +} + +STATIC void emit_post(emit_t *emit) { + (void)emit; +} + +STATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) { + stack_info_t *si = &emit->stack_info[emit->stack_size - 1]; + si->vtype = new_vtype; +} + +STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) { + ensure_extra_stack(emit, 1); + stack_info_t *si = &emit->stack_info[emit->stack_size]; + si->vtype = vtype; + si->kind = STACK_REG; + si->data.u_reg = reg; + adjust_stack(emit, 1); +} + +STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) { + ensure_extra_stack(emit, 1); + stack_info_t *si = &emit->stack_info[emit->stack_size]; + si->vtype = vtype; + si->kind = STACK_IMM; + si->data.u_imm = imm; + adjust_stack(emit, 1); +} + +STATIC void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) { + emit_post_push_reg(emit, vtypea, rega); + emit_post_push_reg(emit, vtypeb, regb); +} + +STATIC void emit_post_push_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc) { + emit_post_push_reg(emit, vtypea, rega); + emit_post_push_reg(emit, vtypeb, regb); + emit_post_push_reg(emit, vtypec, regc); +} + +STATIC void emit_post_push_reg_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc, vtype_kind_t vtyped, int regd) { + emit_post_push_reg(emit, vtypea, rega); + emit_post_push_reg(emit, vtypeb, regb); + emit_post_push_reg(emit, vtypec, regc); + emit_post_push_reg(emit, vtyped, regd); +} + +STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) { + need_reg_all(emit); + ASM_CALL_IND(emit->as, fun_kind); +} + +STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { + need_reg_all(emit); + ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val); + ASM_CALL_IND(emit->as, fun_kind); +} + +STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) { + need_reg_all(emit); + ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1); + ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2); + ASM_CALL_IND(emit->as, fun_kind); +} + +// vtype of all n_pop objects is VTYPE_PYOBJ +// Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack. +// If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET. +// Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer). +STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) { + need_reg_all(emit); + + // First, store any immediate values to their respective place on the stack. + for (mp_uint_t i = 0; i < n_pop; i++) { + stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; + // must push any imm's to stack + // must convert them to VTYPE_PYOBJ for viper code + if (si->kind == STACK_IMM) { + si->kind = STACK_VALUE; + si->vtype = load_reg_stack_imm(emit, reg_dest, si, true); + emit_native_mov_state_reg(emit, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + } + + // verify that this value is on the stack + assert(si->kind == STACK_VALUE); + } + + // Second, convert any non-VTYPE_PYOBJ to that type. + for (mp_uint_t i = 0; i < n_pop; i++) { + stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; + if (si->vtype != VTYPE_PYOBJ) { + mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i; + emit_native_mov_reg_state(emit, REG_ARG_1, local_num); + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type + emit_native_mov_state_reg(emit, local_num, REG_RET); + si->vtype = VTYPE_PYOBJ; + DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num); + } + } + + // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest. + adjust_stack(emit, -n_pop); + emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size); +} + +// vtype of all n_push objects is VTYPE_PYOBJ +STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) { + need_reg_all(emit); + ensure_extra_stack(emit, n_push); + for (mp_uint_t i = 0; i < n_push; i++) { + emit->stack_info[emit->stack_size + i].kind = STACK_VALUE; + emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ; + } + emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size); + adjust_stack(emit, n_push); +} + +STATIC void emit_native_push_exc_stack(emit_t *emit, uint label, bool is_finally) { + if (emit->exc_stack_size + 1 > emit->exc_stack_alloc) { + size_t new_alloc = emit->exc_stack_alloc + 4; + emit->exc_stack = m_renew(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc, new_alloc); + emit->exc_stack_alloc = new_alloc; + } + + exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size++]; + e->label = label; + e->is_finally = is_finally; + e->unwind_label = UNWIND_LABEL_UNUSED; + e->is_active = true; + + ASM_MOV_REG_PCREL(emit->as, REG_RET, label); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET); +} + +STATIC void emit_native_leave_exc_stack(emit_t *emit, bool start_of_handler) { + assert(emit->exc_stack_size > 0); + + // Get current exception handler and deactivate it + exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1]; + e->is_active = false; + + // Find next innermost active exception handler, to restore as current handler + for (--e; e >= emit->exc_stack && !e->is_active; --e) { + } + + // Update the PC of the new exception handler + if (e < emit->exc_stack) { + // No active handler, clear handler PC to zero + if (start_of_handler) { + // Optimisation: PC is already cleared by global exc handler + return; + } + ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + } else { + // Found new active handler, get its PC + ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); + } + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET); +} + +STATIC exc_stack_entry_t *emit_native_pop_exc_stack(emit_t *emit) { + assert(emit->exc_stack_size > 0); + exc_stack_entry_t *e = &emit->exc_stack[--emit->exc_stack_size]; + assert(e->is_active == false); + return e; +} + +STATIC void emit_load_reg_with_ptr(emit_t *emit, int reg, mp_uint_t ptr, size_t table_off) { + if (!emit->do_viper_types) { + // Skip qstr names of arguments + table_off += emit->scope->num_pos_args + emit->scope->num_kwonly_args; + } + if (emit->pass == MP_PASS_EMIT) { + emit->const_table[table_off] = ptr; + } + emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t)); + ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off); +} + +STATIC void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) { + size_t table_off = emit->const_table_cur_obj++; + emit_load_reg_with_ptr(emit, reg, (mp_uint_t)obj, table_off); +} + +STATIC void emit_load_reg_with_raw_code(emit_t *emit, int reg, mp_raw_code_t *rc) { + size_t table_off = emit->const_table_num_obj + emit->const_table_cur_raw_code++; + emit_load_reg_with_ptr(emit, reg, (mp_uint_t)rc, table_off); +} + +STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) { + DEBUG_printf("label_assign(" UINT_FMT ")\n", l); + + bool is_finally = false; + if (emit->exc_stack_size > 0) { + exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1]; + is_finally = e->is_finally && e->label == l; + } + + if (is_finally) { + // Label is at start of finally handler: store TOS into exception slot + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_TEMP0); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + } + + emit_native_pre(emit); + // need to commit stack because we can jump here from elsewhere + need_stack_settled(emit); + mp_asm_base_label_assign(&emit->as->base, l); + emit_post(emit); + + if (is_finally) { + // Label is at start of finally handler: pop exception stack + emit_native_leave_exc_stack(emit, false); + } +} + +STATIC void emit_native_global_exc_entry(emit_t *emit) { + // Note: 4 labels are reserved for this function, starting at *emit->label_slot + + emit->exit_label = *emit->label_slot; + + if (NEED_GLOBAL_EXC_HANDLER(emit)) { + mp_uint_t nlr_label = *emit->label_slot + 1; + mp_uint_t start_label = *emit->label_slot + 2; + mp_uint_t global_except_label = *emit->label_slot + 3; + + if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + // Set new globals + emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit)); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t)); + emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); + + // Save old globals (or NULL if globals didn't change) + emit_native_mov_state_reg(emit, LOCAL_IDX_OLD_GLOBALS(emit), REG_RET); + } + + if (emit->scope->exc_stack_size == 0) { + if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + // Optimisation: if globals didn't change don't push the nlr context + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, false); + } + + // Wrap everything in an nlr context + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); + emit_call(emit, MP_F_NLR_PUSH); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true); + } else { + // Clear the unwind state + ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_TEMP0); + + // Put PC of start code block into REG_LOCAL_1 + ASM_MOV_REG_PCREL(emit->as, REG_LOCAL_1, start_label); + + // Wrap everything in an nlr context + emit_native_label_assign(emit, nlr_label); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, LOCAL_IDX_EXC_HANDLER_UNWIND(emit)); + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); + emit_call(emit, MP_F_NLR_PUSH); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_LOCAL_2); + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true); + + // Clear PC of current code block, and jump there to resume execution + ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_TEMP0); + ASM_JUMP_REG(emit->as, REG_LOCAL_1); + + // Global exception handler: check for valid exception handler + emit_native_label_assign(emit, global_except_label); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit)); + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false); + } + + if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + // Restore old globals + emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit)); + emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); + } + + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + // Store return value in state[0] + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit)); + ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, offsetof(mp_code_state_t, state) / sizeof(uintptr_t)); + + // Load return kind + ASM_MOV_REG_IMM(emit->as, REG_RET, MP_VM_RETURN_EXCEPTION); + + ASM_EXIT(emit->as); + } else { + // Re-raise exception out to caller + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + emit_call(emit, MP_F_NATIVE_RAISE); + } + + // Label for start of function + emit_native_label_assign(emit, start_label); + + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_GEN_PC(emit)); + ASM_JUMP_REG(emit->as, REG_TEMP0); + emit->start_offset = mp_asm_base_get_code_pos(&emit->as->base); + + // This is the first entry of the generator + + // Check LOCAL_IDX_EXC_VAL for any injected value + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + emit_call(emit, MP_F_NATIVE_RAISE); + } + } +} + +STATIC void emit_native_global_exc_exit(emit_t *emit) { + // Label for end of function + emit_native_label_assign(emit, emit->exit_label); + + if (NEED_GLOBAL_EXC_HANDLER(emit)) { + // Get old globals + if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit)); + + if (emit->scope->exc_stack_size == 0) { + // Optimisation: if globals didn't change then don't restore them and don't do nlr_pop + ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false); + } + + // Restore old globals + emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS); + } + + // Pop the nlr context + emit_call(emit, MP_F_NLR_POP); + + if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + if (emit->scope->exc_stack_size == 0) { + // Destination label for above optimisation + emit_native_label_assign(emit, emit->exit_label + 1); + } + } + + // Load return value + ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_RET_VAL(emit)); + } + + ASM_EXIT(emit->as); +} + +STATIC void emit_native_import_name(emit_t *emit, qstr qst) { + DEBUG_printf("import_name %s\n", qstr_str(qst)); + + // get arguments from stack: arg2 = fromlist, arg3 = level + // If using viper types these arguments must be converted to proper objects, and + // to accomplish this viper types are turned off for the emit_pre_pop_reg_reg call. + bool orig_do_viper_types = emit->do_viper_types; + emit->do_viper_types = false; + vtype_kind_t vtype_fromlist; + vtype_kind_t vtype_level; + emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3); + assert(vtype_fromlist == VTYPE_PYOBJ); + assert(vtype_level == VTYPE_PYOBJ); + emit->do_viper_types = orig_do_viper_types; + + emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_import_from(emit_t *emit, qstr qst) { + DEBUG_printf("import_from %s\n", qstr_str(qst)); + emit_native_pre(emit); + vtype_kind_t vtype_module; + emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module + assert(vtype_module == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_import_star(emit_t *emit) { + DEBUG_printf("import_star\n"); + vtype_kind_t vtype_module; + emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module + assert(vtype_module == VTYPE_PYOBJ); + emit_call(emit, MP_F_IMPORT_ALL); + emit_post(emit); +} + +STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_IMPORT_NAME) { + emit_native_import_name(emit, qst); + } else if (kind == MP_EMIT_IMPORT_FROM) { + emit_native_import_from(emit, qst); + } else { + emit_native_import_star(emit); + } +} + +STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { + DEBUG_printf("load_const_tok(tok=%u)\n", tok); + if (tok == MP_TOKEN_ELLIPSIS) { + emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); + } else { + emit_native_pre(emit); + if (tok == MP_TOKEN_KW_NONE) { + emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); + } else { + emit_post_push_imm(emit, VTYPE_BOOL, tok == MP_TOKEN_KW_FALSE ? 0 : 1); + } + } +} + +STATIC void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) { + DEBUG_printf("load_const_small_int(int=" INT_FMT ")\n", arg); + emit_native_pre(emit); + emit_post_push_imm(emit, VTYPE_INT, arg); +} + +STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { + emit_native_pre(emit); + // TODO: Eventually we want to be able to work with raw pointers in viper to + // do native array access. For now we just load them as any other object. + /* + if (emit->do_viper_types) { + // load a pointer to the asciiz string? + emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst)); + } else + */ + { + emit_post_push_imm(emit, VTYPE_PYOBJ, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + } +} + +STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { + emit_native_pre(emit); + need_reg_single(emit, REG_RET, 0); + emit_load_reg_with_object(emit, REG_RET, obj); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_load_null(emit_t *emit) { + emit_native_pre(emit); + emit_post_push_imm(emit, VTYPE_PYOBJ, 0); +} + +STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { + DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); + vtype_kind_t vtype = emit->local_vtype[local_num]; + if (vtype == VTYPE_UNBOUND) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "local '%q' used before type known", qst); + } + emit_native_pre(emit); + if (local_num < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) { + emit_post_push_reg(emit, vtype, reg_local_table[local_num]); + } else { + need_reg_single(emit, REG_TEMP0, 0); + emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_LOCAL_VAR(emit, local_num)); + emit_post_push_reg(emit, vtype, REG_TEMP0); + } +} + +STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { + DEBUG_printf("load_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); + need_reg_single(emit, REG_RET, 0); + emit_native_load_fast(emit, qst, local_num); + vtype_kind_t vtype; + int reg_base = REG_RET; + emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1); + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_RET, reg_base, 1); + // closed over vars are always Python objects + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_load_fast(emit, qst, local_num); + } else { + emit_native_load_deref(emit, qst, local_num); + } +} + +STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME); + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL); + emit_native_pre(emit); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + DEBUG_printf("load_name(%s)\n", qstr_str(qst)); + } else { + DEBUG_printf("load_global(%s)\n", qstr_str(qst)); + if (emit->do_viper_types) { + // check for builtin casting operators + int native_type = mp_native_type_from_qstr(qst); + if (native_type >= MP_NATIVE_TYPE_INT) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, native_type); + return; + } + } + } + emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { + // depends on type of subject: + // - integer, function, pointer to integers: error + // - pointer to structure: get member, quite easy + // - Python object: call mp_load_attr, and needs to be typed to convert result + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base + assert(vtype_base == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) { + if (is_super) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr + emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name + } else { + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base + assert(vtype_base == VTYPE_PYOBJ); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name + } +} + +STATIC void emit_native_load_build_class(emit_t *emit) { + emit_native_pre(emit); + emit_call(emit, MP_F_LOAD_BUILD_CLASS); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_load_subscr(emit_t *emit) { + DEBUG_printf("load_subscr\n"); + // need to compile: base[index] + + // pop: index, base + // optimise case where index is an immediate + vtype_kind_t vtype_base = peek_vtype(emit, 1); + + if (vtype_base == VTYPE_PYOBJ) { + // standard Python subscr + // TODO factor this implicit cast code with other uses of it + vtype_kind_t vtype_index = peek_vtype(emit, 0); + if (vtype_index == VTYPE_PYOBJ) { + emit_pre_pop_reg(emit, &vtype_index, REG_ARG_2); + } else { + emit_pre_pop_reg(emit, &vtype_index, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype_index, REG_ARG_2); // arg2 = type + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + } + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + // viper load + // TODO The different machine architectures have very different + // capabilities and requirements for loads, so probably best to + // write a completely separate load-optimiser for each one. + stack_info_t *top = peek_stack(emit, 0); + if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) { + // index is an immediate + mp_int_t index_value = top->data.u_imm; + emit_pre_pop_discard(emit); // discard index + int reg_base = REG_ARG_1; + int reg_index = REG_ARG_2; + emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_index); + switch (vtype_base) { + case VTYPE_PTR8: { + // pointer to 8-bit memory + // TODO optimise to use thumb ldrb r1, [r2, r3] + if (index_value != 0) { + // index is non-zero + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); + break; + } + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base + reg_base = reg_index; + } + ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index) + break; + } + case VTYPE_PTR16: { + // pointer to 16-bit memory + if (index_value != 0) { + // index is a non-zero immediate + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); + break; + } + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base + reg_base = reg_index; + } + ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index) + break; + } + case VTYPE_PTR32: { + // pointer to 32-bit memory + if (index_value != 0) { + // index is a non-zero immediate + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); + break; + } + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base + reg_base = reg_index; + } + ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index) + break; + } + default: + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't load from '%q'", vtype_to_qstr(vtype_base)); + } + } else { + // index is not an immediate + vtype_kind_t vtype_index; + int reg_index = REG_ARG_2; + emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, REG_ARG_1); + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); + if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't load with '%q' index", vtype_to_qstr(vtype_index)); + } + switch (vtype_base) { + case VTYPE_PTR8: { + // pointer to 8-bit memory + // TODO optimise to use thumb ldrb r1, [r2, r3] + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index) + break; + } + case VTYPE_PTR16: { + // pointer to 16-bit memory + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index) + break; + } + case VTYPE_PTR32: { + // pointer to word-size memory + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index) + break; + } + default: + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't load from '%q'", vtype_to_qstr(vtype_base)); + } + } + emit_post_push_reg(emit, VTYPE_INT, REG_RET); + } +} + +STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { + vtype_kind_t vtype; + if (local_num < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) { + emit_pre_pop_reg(emit, &vtype, reg_local_table[local_num]); + } else { + emit_pre_pop_reg(emit, &vtype, REG_TEMP0); + emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, local_num), REG_TEMP0); + } + emit_post(emit); + + // check types + if (emit->local_vtype[local_num] == VTYPE_UNBOUND) { + // first time this local is assigned, so give it a type of the object stored in it + emit->local_vtype[local_num] = vtype; + } else if (emit->local_vtype[local_num] != vtype) { + // type of local is not the same as object stored in it + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "local '%q' has type '%q' but source is '%q'", + qst, vtype_to_qstr(emit->local_vtype[local_num]), vtype_to_qstr(vtype)); + } +} + +STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { + DEBUG_printf("store_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num); + need_reg_single(emit, REG_TEMP0, 0); + need_reg_single(emit, REG_TEMP1, 0); + emit_native_load_fast(emit, qst, local_num); + vtype_kind_t vtype; + int reg_base = REG_TEMP0; + emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1); + int reg_src = REG_TEMP1; + emit_pre_pop_reg_flexible(emit, &vtype, ®_src, reg_base, reg_base); + ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, reg_base, 1); + emit_post(emit); +} + +STATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_store_fast(emit, qst, local_num); + } else { + emit_native_store_deref(emit, qst, local_num); + } +} + +STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME); + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + assert(vtype == VTYPE_PYOBJ); + } else { + vtype_kind_t vtype = peek_vtype(emit, 0); + if (vtype == VTYPE_PYOBJ) { + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + } else { + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + } + } + emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name + emit_post(emit); +} + +STATIC void emit_native_store_attr(emit_t *emit, qstr qst) { + vtype_kind_t vtype_base, vtype_val; + emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value + assert(vtype_base == VTYPE_PYOBJ); + assert(vtype_val == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name + emit_post(emit); +} + +STATIC void emit_native_store_subscr(emit_t *emit) { + DEBUG_printf("store_subscr\n"); + // need to compile: base[index] = value + + // pop: index, base, value + // optimise case where index is an immediate + vtype_kind_t vtype_base = peek_vtype(emit, 1); + + if (vtype_base == VTYPE_PYOBJ) { + // standard Python subscr + vtype_kind_t vtype_index = peek_vtype(emit, 0); + vtype_kind_t vtype_value = peek_vtype(emit, 2); + if (vtype_index != VTYPE_PYOBJ || vtype_value != VTYPE_PYOBJ) { + // need to implicitly convert non-objects to objects + // TODO do this properly + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, 3); + adjust_stack(emit, 3); + } + emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3); + emit_call(emit, MP_F_OBJ_SUBSCR); + } else { + // viper store + // TODO The different machine architectures have very different + // capabilities and requirements for stores, so probably best to + // write a completely separate store-optimiser for each one. + stack_info_t *top = peek_stack(emit, 0); + if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) { + // index is an immediate + mp_int_t index_value = top->data.u_imm; + emit_pre_pop_discard(emit); // discard index + vtype_kind_t vtype_value; + int reg_base = REG_ARG_1; + int reg_index = REG_ARG_2; + int reg_value = REG_ARG_3; + emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_value); + #if N_X86 + // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) + emit_pre_pop_reg(emit, &vtype_value, reg_value); + #else + emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, reg_base, reg_index); + #endif + if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't store '%q'", vtype_to_qstr(vtype_value)); + } + switch (vtype_base) { + case VTYPE_PTR8: { + // pointer to 8-bit memory + // TODO optimise to use thumb strb r1, [r2, r3] + if (index_value != 0) { + // index is non-zero + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); + break; + } + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); + #if N_ARM + asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); + return; + #endif + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base + reg_base = reg_index; + } + ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index) + break; + } + case VTYPE_PTR16: { + // pointer to 16-bit memory + if (index_value != 0) { + // index is a non-zero immediate + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); + break; + } + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base + reg_base = reg_index; + } + ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index) + break; + } + case VTYPE_PTR32: { + // pointer to 32-bit memory + if (index_value != 0) { + // index is a non-zero immediate + #if N_THUMB + if (index_value > 0 && index_value < 32) { + asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); + break; + } + #endif + #if N_ARM + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); + asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); + return; + #endif + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); + ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base + reg_base = reg_index; + } + ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index) + break; + } + default: + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't store to '%q'", vtype_to_qstr(vtype_base)); + } + } else { + // index is not an immediate + vtype_kind_t vtype_index, vtype_value; + int reg_index = REG_ARG_2; + int reg_value = REG_ARG_3; + emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, reg_value); + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); + if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't store with '%q' index", vtype_to_qstr(vtype_index)); + } + #if N_X86 + // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) + emit_pre_pop_reg(emit, &vtype_value, reg_value); + #else + emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, REG_ARG_1, reg_index); + #endif + if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't store '%q'", vtype_to_qstr(vtype_value)); + } + switch (vtype_base) { + case VTYPE_PTR8: { + // pointer to 8-bit memory + // TODO optimise to use thumb strb r1, [r2, r3] + #if N_ARM + asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); + break; + #endif + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index) + break; + } + case VTYPE_PTR16: { + // pointer to 16-bit memory + #if N_ARM + asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); + break; + #endif + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index) + break; + } + case VTYPE_PTR32: { + // pointer to 32-bit memory + #if N_ARM + asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); + break; + #endif + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base + ASM_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index) + break; + } + default: + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't store to '%q'", vtype_to_qstr(vtype_base)); + } + } + + } +} + +STATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL + // to mark deleted vars but then every var would need to be checked on + // each access. Very inefficient, so just set value to None to enable GC. + emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); + emit_native_store_fast(emit, qst, local_num); + } else { + // TODO implement me! + } +} + +STATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME); + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL); + emit_native_pre(emit); + emit_call_with_imm_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); + emit_post(emit); +} + +STATIC void emit_native_delete_attr(emit_t *emit, qstr qst) { + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base + assert(vtype_base == VTYPE_PYOBJ); + emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, qst, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete) + emit_post(emit); +} + +STATIC void emit_native_delete_subscr(emit_t *emit) { + vtype_kind_t vtype_index, vtype_base; + emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base + assert(vtype_index == VTYPE_PYOBJ); + assert(vtype_base == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); +} + +STATIC void emit_native_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_native_load_subscr(emit); + } else if (kind == MP_EMIT_SUBSCR_STORE) { + emit_native_store_subscr(emit); + } else { + emit_native_delete_subscr(emit); + } +} + +STATIC void emit_native_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_native_load_attr(emit, qst); + } else if (kind == MP_EMIT_ATTR_STORE) { + emit_native_store_attr(emit, qst); + } else { + emit_native_delete_attr(emit, qst); + } +} + +STATIC void emit_native_dup_top(emit_t *emit) { + DEBUG_printf("dup_top\n"); + vtype_kind_t vtype; + int reg = REG_TEMP0; + emit_pre_pop_reg_flexible(emit, &vtype, ®, -1, -1); + emit_post_push_reg_reg(emit, vtype, reg, vtype, reg); +} + +STATIC void emit_native_dup_top_two(emit_t *emit) { + vtype_kind_t vtype0, vtype1; + emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1); + emit_post_push_reg_reg_reg_reg(emit, vtype1, REG_TEMP1, vtype0, REG_TEMP0, vtype1, REG_TEMP1, vtype0, REG_TEMP0); +} + +STATIC void emit_native_pop_top(emit_t *emit) { + DEBUG_printf("pop_top\n"); + emit_pre_pop_discard(emit); + emit_post(emit); +} + +STATIC void emit_native_rot_two(emit_t *emit) { + DEBUG_printf("rot_two\n"); + vtype_kind_t vtype0, vtype1; + emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1); + emit_post_push_reg_reg(emit, vtype0, REG_TEMP0, vtype1, REG_TEMP1); +} + +STATIC void emit_native_rot_three(emit_t *emit) { + DEBUG_printf("rot_three\n"); + vtype_kind_t vtype0, vtype1, vtype2; + emit_pre_pop_reg_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1, &vtype2, REG_TEMP2); + emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1); +} + +STATIC void emit_native_jump(emit_t *emit, mp_uint_t label) { + DEBUG_printf("jump(label=" UINT_FMT ")\n", label); + emit_native_pre(emit); + // need to commit stack because we are jumping elsewhere + need_stack_settled(emit); + ASM_JUMP(emit->as, label); + emit_post(emit); +} + +STATIC void emit_native_jump_helper(emit_t *emit, bool cond, mp_uint_t label, bool pop) { + vtype_kind_t vtype = peek_vtype(emit, 0); + if (vtype == VTYPE_PYOBJ) { + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + if (!pop) { + adjust_stack(emit, 1); + } + emit_call(emit, MP_F_OBJ_IS_TRUE); + } else { + emit_pre_pop_reg(emit, &vtype, REG_RET); + if (!pop) { + adjust_stack(emit, 1); + } + if (!(vtype == VTYPE_BOOL || vtype == VTYPE_INT || vtype == VTYPE_UINT)) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't implicitly convert '%q' to 'bool'", vtype_to_qstr(vtype)); + } + } + // For non-pop need to save the vtype so that emit_native_adjust_stack_size + // can use it. This is a bit of a hack. + if (!pop) { + emit->saved_stack_vtype = vtype; + } + // need to commit stack because we may jump elsewhere + need_stack_settled(emit); + // Emit the jump + if (cond) { + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ); + } else { + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ); + } + if (!pop) { + adjust_stack(emit, -1); + } + emit_post(emit); +} + +STATIC void emit_native_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) { + DEBUG_printf("pop_jump_if(cond=%u, label=" UINT_FMT ")\n", cond, label); + emit_native_jump_helper(emit, cond, label, true); +} + +STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) { + DEBUG_printf("jump_if_or_pop(cond=%u, label=" UINT_FMT ")\n", cond, label); + emit_native_jump_helper(emit, cond, label, false); +} + +STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { + if (except_depth > 0) { + exc_stack_entry_t *first_finally = NULL; + exc_stack_entry_t *prev_finally = NULL; + exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1]; + for (; except_depth > 0; --except_depth, --e) { + if (e->is_finally && e->is_active) { + // Found an active finally handler + if (first_finally == NULL) { + first_finally = e; + } + if (prev_finally != NULL) { + // Mark prev finally as needed to unwind a jump + prev_finally->unwind_label = e->label; + } + prev_finally = e; + } + } + if (prev_finally == NULL) { + // No finally, handle the jump ourselves + // First, restore the exception handler address for the jump + if (e < emit->exc_stack) { + ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET); + } else { + ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); + } + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET); + } else { + // Last finally should do our jump for us + // Mark finally as needing to decide the type of jump + prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND; + ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET); + // Cancel any active exception (see also emit_native_pop_except) + emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET); + // Jump to the innermost active finally + label = first_finally->label; + } + } + emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); +} + +STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { + // the context manager is on the top of the stack + // stack: (..., ctx_mgr) + + // get __exit__ method + vtype_kind_t vtype; + emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr + assert(vtype == VTYPE_PYOBJ); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2); + // stack: (..., ctx_mgr, __exit__, self) + + emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // __exit__ + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // ctx_mgr + emit_post_push_reg(emit, vtype, REG_ARG_2); // __exit__ + emit_post_push_reg(emit, vtype, REG_ARG_3); // self + // stack: (..., __exit__, self) + // REG_ARG_1=ctx_mgr + + // get __enter__ method + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name + // stack: (..., __exit__, self, __enter__, self) + + // call __enter__ method + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2); // pointer to items, including meth and self + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 0, REG_ARG_1, 0, REG_ARG_2); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__ + // stack: (..., __exit__, self, as_value) + + // need to commit stack because we may jump elsewhere + need_stack_settled(emit); + emit_native_push_exc_stack(emit, label, true); + + emit_native_dup_top(emit); + // stack: (..., __exit__, self, as_value, as_value) +} + +STATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) { + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { + emit_native_setup_with(emit, label); + } else { + // Set up except and finally + emit_native_pre(emit); + need_stack_settled(emit); + emit_native_push_exc_stack(emit, label, kind == MP_EMIT_SETUP_BLOCK_FINALLY); + emit_post(emit); + } +} + +STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { + // Note: 3 labels are reserved for this function, starting at *emit->label_slot + + // stack: (..., __exit__, self, as_value) + emit_native_pre(emit); + emit_native_leave_exc_stack(emit, false); + adjust_stack(emit, -1); + // stack: (..., __exit__, self) + + // Label for case where __exit__ is called from an unwind jump + emit_native_label_assign(emit, *emit->label_slot + 2); + + // call __exit__ + emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); + emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); + emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); + + // Replace exc with None and finish + emit_native_jump(emit, *emit->label_slot); + + // nlr_catch + // Don't use emit_native_label_assign because this isn't a real finally label + mp_asm_base_label_assign(&emit->as->base, label); + + // Leave with's exception handler + emit_native_leave_exc_stack(emit, true); + + // Adjust stack counter for: __exit__, self (implicitly discard as_value which is above self) + emit_native_adjust_stack_size(emit, 2); + // stack: (..., __exit__, self) + + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc + + // Check if exc is None and jump to non-exc handler if it is + emit_native_mov_reg_const(emit, REG_ARG_2, MP_F_CONST_NONE_OBJ); + ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_2, *emit->label_slot + 2); + + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc) + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc) + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1); // push exc value + emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); // traceback info + // Stack: (..., __exit__, self, type(exc), exc, traceback) + + // call __exit__ method + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5); + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2); + // Stack: (...) + + // If REG_RET is true then we need to replace exception with None (swallow exception) + if (REG_ARG_1 != REG_RET) { + ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET); + } + emit_call(emit, MP_F_OBJ_IS_TRUE); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 1, true); + + // Replace exception with None + emit_native_label_assign(emit, *emit->label_slot); + emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + + // end of with cleanup nlr_catch block + emit_native_label_assign(emit, *emit->label_slot + 1); + + // Exception is in nlr_buf.ret_val slot +} + +STATIC void emit_native_end_finally(emit_t *emit) { + // logic: + // exc = pop_stack + // if exc == None: pass + // else: raise exc + // the check if exc is None is done in the MP_F_NATIVE_RAISE stub + emit_native_pre(emit); + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + emit_call(emit, MP_F_NATIVE_RAISE); + + // Get state for this finally and see if we need to unwind + exc_stack_entry_t *e = emit_native_pop_exc_stack(emit); + if (e->unwind_label != UNWIND_LABEL_UNUSED) { + ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_EXC_HANDLER_UNWIND(emit)); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot, false); + if (e->unwind_label == UNWIND_LABEL_DO_FINAL_UNWIND) { + ASM_JUMP_REG(emit->as, REG_RET); + } else { + emit_native_jump(emit, e->unwind_label); + } + emit_native_label_assign(emit, *emit->label_slot); + } + + emit_post(emit); +} + +STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { + // perhaps the difficult one, as we want to rewrite for loops using native code + // in cases where we iterate over a Python object, can we use normal runtime calls? + + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + assert(vtype == VTYPE_PYOBJ); + if (use_stack) { + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS); + emit_call(emit, MP_F_NATIVE_GETITER); + } else { + // mp_getiter will allocate the iter_buf on the heap + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0); + emit_call(emit, MP_F_NATIVE_GETITER); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } +} + +STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { + emit_native_pre(emit); + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); + adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); + emit_call(emit, MP_F_NATIVE_ITERNEXT); + #ifdef NDEBUG + MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false); + #else + ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION); + ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); + #endif + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_for_iter_end(emit_t *emit) { + // adjust stack counter (we get here from for_iter ending, which popped the value for us) + emit_native_pre(emit); + adjust_stack(emit, -MP_OBJ_ITER_BUF_NSLOTS); + emit_post(emit); +} + +STATIC void emit_native_pop_block(emit_t *emit) { + emit_native_pre(emit); + if (!emit->exc_stack[emit->exc_stack_size - 1].is_finally) { + emit_native_leave_exc_stack(emit, false); + } + emit_post(emit); +} + +STATIC void emit_native_pop_except(emit_t *emit) { + // Cancel any active exception so subsequent handlers don't see it + emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); +} + +STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + if (vtype == VTYPE_PYOBJ) { + emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + adjust_stack(emit, 1); + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "unary op %q not implemented", mp_unary_op_method_name[op]); + } +} + +STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { + DEBUG_printf("binary_op(" UINT_FMT ")\n", op); + vtype_kind_t vtype_lhs = peek_vtype(emit, 1); + vtype_kind_t vtype_rhs = peek_vtype(emit, 0); + if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) { + // for integers, inplace and normal ops are equivalent, so use just normal ops + if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) { + op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR; + } + + #if N_X64 || N_X86 + // special cases for x86 and shifting + if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) { + #if N_X64 + emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET); + #else + emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET); + #endif + if (op == MP_BINARY_OP_LSHIFT) { + ASM_LSL_REG(emit->as, REG_RET); + } else { + ASM_ASR_REG(emit->as, REG_RET); + } + emit_post_push_reg(emit, VTYPE_INT, REG_RET); + return; + } + #endif + + // special cases for floor-divide and module because we dispatch to helper functions + if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) { + emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1); + if (op == MP_BINARY_OP_FLOOR_DIVIDE) { + emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE); + } else { + emit_call(emit, MP_F_SMALL_INT_MODULO); + } + emit_post_push_reg(emit, VTYPE_INT, REG_RET); + return; + } + + int reg_rhs = REG_ARG_3; + emit_pre_pop_reg_flexible(emit, &vtype_rhs, ®_rhs, REG_RET, REG_ARG_2); + emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2); + if (0) { + // dummy + #if !(N_X64 || N_X86) + } else if (op == MP_BINARY_OP_LSHIFT) { + ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_RSHIFT) { + ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + #endif + } else if (op == MP_BINARY_OP_OR) { + ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_XOR) { + ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_AND) { + ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_ADD) { + ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_SUBTRACT) { + ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (op == MP_BINARY_OP_MULTIPLY) { + ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs); + emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); + } else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) { + // comparison ops are (in enum order): + // MP_BINARY_OP_LESS + // MP_BINARY_OP_MORE + // MP_BINARY_OP_EQUAL + // MP_BINARY_OP_LESS_EQUAL + // MP_BINARY_OP_MORE_EQUAL + // MP_BINARY_OP_NOT_EQUAL + need_reg_single(emit, REG_RET, 0); + #if N_X64 + asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET); + asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2); + static byte ops[6] = { + ASM_X64_CC_JL, + ASM_X64_CC_JG, + ASM_X64_CC_JE, + ASM_X64_CC_JLE, + ASM_X64_CC_JGE, + ASM_X64_CC_JNE, + }; + asm_x64_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET); + #elif N_X86 + asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET); + asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2); + static byte ops[6] = { + ASM_X86_CC_JL, + ASM_X86_CC_JG, + ASM_X86_CC_JE, + ASM_X86_CC_JLE, + ASM_X86_CC_JGE, + ASM_X86_CC_JNE, + }; + asm_x86_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET); + #elif N_THUMB + asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs); + static uint16_t ops[6] = { + ASM_THUMB_OP_ITE_GE, + ASM_THUMB_OP_ITE_GT, + ASM_THUMB_OP_ITE_EQ, + ASM_THUMB_OP_ITE_GT, + ASM_THUMB_OP_ITE_GE, + ASM_THUMB_OP_ITE_EQ, + }; + static byte ret[6] = { 0, 1, 1, 0, 1, 0, }; + asm_thumb_op16(emit->as, ops[op - MP_BINARY_OP_LESS]); + asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS]); + asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS] ^ 1); + #elif N_ARM + asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs); + static uint ccs[6] = { + ASM_ARM_CC_LT, + ASM_ARM_CC_GT, + ASM_ARM_CC_EQ, + ASM_ARM_CC_LE, + ASM_ARM_CC_GE, + ASM_ARM_CC_NE, + }; + asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]); + #elif N_XTENSA + static uint8_t ccs[6] = { + ASM_XTENSA_CC_LT, + 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args + ASM_XTENSA_CC_EQ, + 0x80 | ASM_XTENSA_CC_GE, // for LE we'll swap args + ASM_XTENSA_CC_GE, + ASM_XTENSA_CC_NE, + }; + uint8_t cc = ccs[op - MP_BINARY_OP_LESS]; + if ((cc & 0x80) == 0) { + asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs); + } else { + asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2); + } + #else + #error not implemented + #endif + emit_post_push_reg(emit, VTYPE_BOOL, REG_RET); + } else { + // TODO other ops not yet implemented + adjust_stack(emit, 1); + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "binary op %q not implemented", mp_binary_op_method_name[op]); + } + } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) { + emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2); + bool invert = false; + if (op == MP_BINARY_OP_NOT_IN) { + invert = true; + op = MP_BINARY_OP_IN; + } else if (op == MP_BINARY_OP_IS_NOT) { + invert = true; + op = MP_BINARY_OP_IS; + } + emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1); + if (invert) { + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1); + } + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + adjust_stack(emit, -1); + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "can't do binary op between '%q' and '%q'", + vtype_to_qstr(vtype_lhs), vtype_to_qstr(vtype_rhs)); + } +} + +#if MICROPY_PY_BUILTINS_SLICE +STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args); +#endif + +STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) { + // for viper: call runtime, with types of args + // if wrapped in byte_array, or something, allocates memory and fills it + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET); + #if MICROPY_PY_BUILTINS_SLICE + if (kind == MP_EMIT_BUILD_SLICE) { + emit_native_build_slice(emit, n_args); + return; + } + #endif + emit_native_pre(emit); + if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items + } + emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set +} + +STATIC void emit_native_store_map(emit_t *emit) { + vtype_kind_t vtype_key, vtype_value, vtype_map; + emit_pre_pop_reg_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3, &vtype_map, REG_ARG_1); // key, value, map + assert(vtype_key == VTYPE_PYOBJ); + assert(vtype_value == VTYPE_PYOBJ); + assert(vtype_map == VTYPE_PYOBJ); + emit_call(emit, MP_F_STORE_MAP); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map +} + +#if MICROPY_PY_BUILTINS_SLICE +STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { + DEBUG_printf("build_slice %d\n", n_args); + if (n_args == 2) { + vtype_kind_t vtype_start, vtype_stop; + emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop + assert(vtype_start == VTYPE_PYOBJ); + assert(vtype_stop == VTYPE_PYOBJ); + emit_native_mov_reg_const(emit, REG_ARG_3, MP_F_CONST_NONE_OBJ); // arg3 = step + } else { + assert(n_args == 3); + vtype_kind_t vtype_start, vtype_stop, vtype_step; + emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step + assert(vtype_start == VTYPE_PYOBJ); + assert(vtype_stop == VTYPE_PYOBJ); + assert(vtype_step == VTYPE_PYOBJ); + } + emit_call(emit, MP_F_NEW_SLICE); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} +#endif + +STATIC void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_index) { + mp_fun_kind_t f; + if (kind == SCOPE_LIST_COMP) { + vtype_kind_t vtype_item; + emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); + assert(vtype_item == VTYPE_PYOBJ); + f = MP_F_LIST_APPEND; + #if MICROPY_PY_BUILTINS_SET + } else if (kind == SCOPE_SET_COMP) { + vtype_kind_t vtype_item; + emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2); + assert(vtype_item == VTYPE_PYOBJ); + f = MP_F_STORE_SET; + #endif + } else { + // SCOPE_DICT_COMP + vtype_kind_t vtype_key, vtype_value; + emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3); + assert(vtype_key == VTYPE_PYOBJ); + assert(vtype_value == VTYPE_PYOBJ); + f = MP_F_STORE_MAP; + } + vtype_kind_t vtype_collection; + emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1); + assert(vtype_collection == VTYPE_PYOBJ); + emit_call(emit, f); + emit_post(emit); +} + +STATIC void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) { + DEBUG_printf("unpack_sequence %d\n", n_args); + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq + assert(vtype_base == VTYPE_PYOBJ); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args +} + +STATIC void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) { + DEBUG_printf("unpack_ex %d %d\n", n_left, n_right); + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq + assert(vtype_base == VTYPE_PYOBJ); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right +} + +STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { + // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them + emit_native_pre(emit); + if (n_pos_defaults == 0 && n_kw_defaults == 0) { + need_reg_all(emit); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NULL); + } else { + vtype_kind_t vtype_def_tuple, vtype_def_dict; + emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2); + assert(vtype_def_tuple == VTYPE_PYOBJ); + assert(vtype_def_dict == VTYPE_PYOBJ); + need_reg_all(emit); + } + emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code); + ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) { + emit_native_pre(emit); + if (n_pos_defaults == 0 && n_kw_defaults == 0) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over); + } else { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over); + } + emit_load_reg_with_raw_code(emit, REG_ARG_1, scope->raw_code); + ASM_CALL_IND(emit->as, MP_F_MAKE_CLOSURE_FROM_RAW_CODE); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +} + +STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + DEBUG_printf("call_function(n_pos=" UINT_FMT ", n_kw=" UINT_FMT ", star_flags=" UINT_FMT ")\n", n_positional, n_keyword, star_flags); + + // TODO: in viper mode, call special runtime routine with type info for args, + // and wanted type info for return, to remove need for boxing/unboxing + + emit_native_pre(emit); + vtype_kind_t vtype_fun = peek_vtype(emit, n_positional + 2 * n_keyword); + if (vtype_fun == VTYPE_BUILTIN_CAST) { + // casting operator + assert(n_positional == 1 && n_keyword == 0); + assert(!star_flags); + DEBUG_printf(" cast to %d\n", vtype_fun); + vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm; + switch (peek_vtype(emit, 0)) { + case VTYPE_PYOBJ: { + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + emit_pre_pop_discard(emit); + emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, vtype_cast, REG_ARG_2); // arg2 = type + emit_post_push_reg(emit, vtype_cast, REG_RET); + break; + } + case VTYPE_BOOL: + case VTYPE_INT: + case VTYPE_UINT: + case VTYPE_PTR: + case VTYPE_PTR8: + case VTYPE_PTR16: + case VTYPE_PTR32: + case VTYPE_PTR_NONE: + emit_fold_stack_top(emit, REG_ARG_1); + emit_post_top_set_vtype(emit, vtype_cast); + break; + default: + // this can happen when casting a cast: int(int) + mp_raise_NotImplementedError("casting"); + } + } else { + assert(vtype_fun == VTYPE_PYOBJ); + if (star_flags) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 0, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + if (n_positional != 0 || n_keyword != 0) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args + } + emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function + emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } + } +} + +STATIC void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + if (star_flags) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 4); // pointer to args + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 1, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + emit_native_pre(emit); + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self + emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } +} + +STATIC void emit_native_return_value(emit_t *emit) { + DEBUG_printf("return_value\n"); + + if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { + // Save pointer to current stack position for caller to access return value + emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1); + emit_native_mov_state_reg(emit, offsetof(mp_code_state_t, sp) / sizeof(uintptr_t), REG_TEMP0); + + // Put return type in return value slot + ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_NORMAL); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0); + + // Do the unwinding jump to get to the return handler + emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size); + emit->last_emit_was_return_value = true; + return; + } + + if (emit->do_viper_types) { + vtype_kind_t return_vtype = emit->scope->scope_flags >> MP_SCOPE_FLAG_VIPERRET_POS; + if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { + emit_pre_pop_discard(emit); + if (return_vtype == VTYPE_PYOBJ) { + emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ); + } else { + ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0); + } + } else { + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_RET : REG_ARG_1); + if (vtype != return_vtype) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, + "return expected '%q' but got '%q'", + vtype_to_qstr(return_vtype), vtype_to_qstr(vtype)); + } + } + if (return_vtype != VTYPE_PYOBJ) { + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2); + } + } else { + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_RET); + assert(vtype == VTYPE_PYOBJ); + } + if (NEED_GLOBAL_EXC_HANDLER(emit)) { + // Save return value for the global exception handler to use + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_RET); + } + emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size); + emit->last_emit_was_return_value = true; +} + +STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { + assert(n_args == 1); + vtype_kind_t vtype_exc; + emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise + if (vtype_exc != VTYPE_PYOBJ) { + EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "must raise an object"); + } + // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type)) + emit_call(emit, MP_F_NATIVE_RAISE); +} + +STATIC void emit_native_yield(emit_t *emit, int kind) { + // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot + + if (emit->do_viper_types) { + mp_raise_NotImplementedError("native yield"); + } + emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; + + need_stack_settled(emit); + + if (kind == MP_EMIT_YIELD_FROM) { + + // Top of yield-from loop, conceptually implementing: + // for item in generator: + // yield item + + // Jump to start of loop + emit_native_jump(emit, *emit->label_slot + 2); + + // Label for top of loop + emit_native_label_assign(emit, *emit->label_slot + 1); + } + + // Save pointer to current stack position for caller to access yielded value + emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1); + emit_native_mov_state_reg(emit, offsetof(mp_code_state_t, sp) / sizeof(uintptr_t), REG_TEMP0); + + // Put return type in return value slot + ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_YIELD); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0); + + // Save re-entry PC + ASM_MOV_REG_PCREL(emit->as, REG_TEMP0, *emit->label_slot); + emit_native_mov_state_reg(emit, LOCAL_IDX_GEN_PC(emit), REG_TEMP0); + + // Jump to exit handler + ASM_JUMP(emit->as, emit->exit_label); + + // Label re-entry point + mp_asm_base_label_assign(&emit->as->base, *emit->label_slot); + + // Re-open any active exception handler + if (emit->exc_stack_size > 0) { + // Find innermost active exception handler, to restore as current handler + exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1]; + for (; e >= emit->exc_stack; --e) { + if (e->is_active) { + // Found active handler, get its PC + ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET); + } + } + } + + emit_native_adjust_stack_size(emit, 1); // send_value + + if (kind == MP_EMIT_YIELD_VALUE) { + // Check LOCAL_IDX_EXC_VAL for any injected value + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + emit_call(emit, MP_F_NATIVE_RAISE); + } else { + // Label loop entry + emit_native_label_assign(emit, *emit->label_slot + 2); + + // Get the next item from the delegate generator + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // send_value + emit_access_stack(emit, 1, &vtype, REG_ARG_1); // generator + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_3, LOCAL_IDX_EXC_VAL(emit)); // throw_value + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_3); + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 1); // ret_value + emit_call(emit, MP_F_NATIVE_YIELD_FROM); + + // If returned non-zero then generator continues + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, *emit->label_slot + 1, true); + + // Pop exhausted gen, replace with ret_value + emit_native_adjust_stack_size(emit, 1); // ret_value + emit_fold_stack_top(emit, REG_ARG_1); + } +} + +STATIC void emit_native_start_except_handler(emit_t *emit) { + // Protected block has finished so leave the current exception handler + emit_native_leave_exc_stack(emit, true); + + // Get and push nlr_buf.ret_val + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit)); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0); +} + +STATIC void emit_native_end_except_handler(emit_t *emit) { + adjust_stack(emit, -1); // pop the exception (end_finally didn't use it) +} + +const emit_method_table_t EXPORT_FUN(method_table) = { + emit_native_start_pass, + emit_native_end_pass, + emit_native_last_emit_was_return_value, + emit_native_adjust_stack_size, + emit_native_set_source_line, + + { + emit_native_load_local, + emit_native_load_global, + }, + { + emit_native_store_local, + emit_native_store_global, + }, + { + emit_native_delete_local, + emit_native_delete_global, + }, + + emit_native_label_assign, + emit_native_import, + emit_native_load_const_tok, + emit_native_load_const_small_int, + emit_native_load_const_str, + emit_native_load_const_obj, + emit_native_load_null, + emit_native_load_method, + emit_native_load_build_class, + emit_native_subscr, + emit_native_attr, + emit_native_dup_top, + emit_native_dup_top_two, + emit_native_pop_top, + emit_native_rot_two, + emit_native_rot_three, + emit_native_jump, + emit_native_pop_jump_if, + emit_native_jump_if_or_pop, + emit_native_unwind_jump, + emit_native_setup_block, + emit_native_with_cleanup, + emit_native_end_finally, + emit_native_get_iter, + emit_native_for_iter, + emit_native_for_iter_end, + emit_native_pop_block, + emit_native_pop_except, + emit_native_unary_op, + emit_native_binary_op, + emit_native_build, + emit_native_store_map, + emit_native_store_comp, + emit_native_unpack_sequence, + emit_native_unpack_ex, + emit_native_make_function, + emit_native_make_closure, + emit_native_call_function, + emit_native_call_method, + emit_native_return_value, + emit_native_raise_varargs, + emit_native_yield, + + emit_native_start_except_handler, + emit_native_end_except_handler, +}; + +#endif diff --git a/src/openmv/src/micropython/py/emitnthumb.c b/src/openmv/src/micropython/py/emitnthumb.c new file mode 100755 index 0000000..1c33e7a --- /dev/null +++ b/src/openmv/src/micropython/py/emitnthumb.c @@ -0,0 +1,20 @@ +// thumb specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_THUMB + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmthumb.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (3) // r4 +#define NLR_BUF_IDX_LOCAL_2 (4) // r5 +#define NLR_BUF_IDX_LOCAL_3 (5) // r6 + +#define N_THUMB (1) +#define EXPORT_FUN(name) emit_native_thumb_##name +#include "py/emitnative.c" + +#endif diff --git a/src/openmv/src/micropython/py/emitnx64.c b/src/openmv/src/micropython/py/emitnx64.c new file mode 100755 index 0000000..4abb3ec --- /dev/null +++ b/src/openmv/src/micropython/py/emitnx64.c @@ -0,0 +1,20 @@ +// x64 specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_X64 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx64.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (5) // rbx +#define NLR_BUF_IDX_LOCAL_2 (6) // r12 +#define NLR_BUF_IDX_LOCAL_3 (7) // r13 + +#define N_X64 (1) +#define EXPORT_FUN(name) emit_native_x64_##name +#include "py/emitnative.c" + +#endif diff --git a/src/openmv/src/micropython/py/emitnx86.c b/src/openmv/src/micropython/py/emitnx86.c new file mode 100755 index 0000000..7c96c3b --- /dev/null +++ b/src/openmv/src/micropython/py/emitnx86.c @@ -0,0 +1,76 @@ +// x86 specific stuff + +#include "py/mpconfig.h" +#include "py/runtime0.h" + +#if MICROPY_EMIT_X86 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx86.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (5) // ebx +#define NLR_BUF_IDX_LOCAL_2 (7) // esi +#define NLR_BUF_IDX_LOCAL_3 (6) // edi + +// x86 needs a table to know how many args a given function has +STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { + [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, + [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, + [MP_F_NATIVE_SWAP_GLOBALS] = 1, + [MP_F_LOAD_NAME] = 1, + [MP_F_LOAD_GLOBAL] = 1, + [MP_F_LOAD_BUILD_CLASS] = 0, + [MP_F_LOAD_ATTR] = 2, + [MP_F_LOAD_METHOD] = 3, + [MP_F_LOAD_SUPER_METHOD] = 2, + [MP_F_STORE_NAME] = 2, + [MP_F_STORE_GLOBAL] = 2, + [MP_F_STORE_ATTR] = 3, + [MP_F_OBJ_SUBSCR] = 3, + [MP_F_OBJ_IS_TRUE] = 1, + [MP_F_UNARY_OP] = 2, + [MP_F_BINARY_OP] = 3, + [MP_F_BUILD_TUPLE] = 2, + [MP_F_BUILD_LIST] = 2, + [MP_F_LIST_APPEND] = 2, + [MP_F_BUILD_MAP] = 1, + [MP_F_STORE_MAP] = 3, + #if MICROPY_PY_BUILTINS_SET + [MP_F_BUILD_SET] = 2, + [MP_F_STORE_SET] = 2, + #endif + [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, + [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW_VAR] = 3, + [MP_F_NATIVE_GETITER] = 2, + [MP_F_NATIVE_ITERNEXT] = 1, + [MP_F_NLR_PUSH] = 1, + [MP_F_NLR_POP] = 0, + [MP_F_NATIVE_RAISE] = 1, + [MP_F_IMPORT_NAME] = 3, + [MP_F_IMPORT_FROM] = 2, + [MP_F_IMPORT_ALL] = 1, + #if MICROPY_PY_BUILTINS_SLICE + [MP_F_NEW_SLICE] = 3, + #endif + [MP_F_UNPACK_SEQUENCE] = 3, + [MP_F_UNPACK_EX] = 3, + [MP_F_DELETE_NAME] = 1, + [MP_F_DELETE_GLOBAL] = 1, + [MP_F_NEW_CELL] = 1, + [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, + [MP_F_ARG_CHECK_NUM_SIG] = 3, + [MP_F_SETUP_CODE_STATE] = 4, + [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, + [MP_F_SMALL_INT_MODULO] = 2, + [MP_F_NATIVE_YIELD_FROM] = 3, +}; + +#define N_X86 (1) +#define EXPORT_FUN(name) emit_native_x86_##name +#include "py/emitnative.c" + +#endif diff --git a/src/openmv/src/micropython/py/emitnxtensa.c b/src/openmv/src/micropython/py/emitnxtensa.c new file mode 100755 index 0000000..34089e9 --- /dev/null +++ b/src/openmv/src/micropython/py/emitnxtensa.c @@ -0,0 +1,20 @@ +// Xtensa specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_XTENSA + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmxtensa.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (8) // a12 +#define NLR_BUF_IDX_LOCAL_2 (9) // a13 +#define NLR_BUF_IDX_LOCAL_3 (10) // a14 + +#define N_XTENSA (1) +#define EXPORT_FUN(name) emit_native_xtensa_##name +#include "py/emitnative.c" + +#endif diff --git a/src/openmv/src/micropython/py/formatfloat.c b/src/openmv/src/micropython/py/formatfloat.c new file mode 100755 index 0000000..dc7fc1d --- /dev/null +++ b/src/openmv/src/micropython/py/formatfloat.c @@ -0,0 +1,429 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE + +#include +#include +#include +#include +#include "py/formatfloat.h" + +/*********************************************************************** + + Routine for converting a arbitrary floating + point number into a string. + + The code in this funcion was inspired from Fred Bayer's pdouble.c. + Since pdouble.c was released as Public Domain, I'm releasing this + code as public domain as well. + + The original code can be found in https://github.com/dhylands/format-float + + Dave Hylands + +***********************************************************************/ + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +// 1 sign bit, 8 exponent bits, and 23 mantissa bits. +// exponent values 0 and 255 are reserved, exponent can be 1 to 254. +// exponent is stored with a bias of 127. +// The min and max floats are on the order of 1x10^37 and 1x10^-37 + +#define FPTYPE float +#define FPCONST(x) x##F +#define FPROUND_TO_ONE 0.9999995F +#define FPDECEXP 32 +#define FPMIN_BUF_SIZE 6 // +9e+99 + +#define FLT_SIGN_MASK 0x80000000 +#define FLT_EXP_MASK 0x7F800000 +#define FLT_MAN_MASK 0x007FFFFF + +union floatbits { + float f; + uint32_t u; +}; +static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; } +#define fp_isnan(x) isnan(x) +#define fp_isinf(x) isinf(x) +static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; } +static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; } + +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + +#define FPTYPE double +#define FPCONST(x) x +#define FPROUND_TO_ONE 0.999999999995 +#define FPDECEXP 256 +#define FPMIN_BUF_SIZE 7 // +9e+199 +#define fp_signbit(x) signbit(x) +#define fp_isnan(x) isnan(x) +#define fp_isinf(x) isinf(x) +#define fp_iszero(x) (x == 0) +#define fp_isless1(x) (x < 1.0) + +#endif + +static const FPTYPE g_pos_pow[] = { + #if FPDECEXP > 32 + 1e256, 1e128, 1e64, + #endif + 1e32, 1e16, 1e8, 1e4, 1e2, 1e1 +}; +static const FPTYPE g_neg_pow[] = { + #if FPDECEXP > 32 + 1e-256, 1e-128, 1e-64, + #endif + 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1 +}; + +int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { + + char *s = buf; + + if (buf_size <= FPMIN_BUF_SIZE) { + // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. + // If the buffer does not have enough room for this (plus null terminator) + // then don't try to format the float. + + if (buf_size >= 2) { + *s++ = '?'; + } + if (buf_size >= 1) { + *s = '\0'; + } + return buf_size >= 2; + } + if (fp_signbit(f) && !fp_isnan(f)) { + *s++ = '-'; + f = -f; + } else { + if (sign) { + *s++ = sign; + } + } + + // buf_remaining contains bytes available for digits and exponent. + // It is buf_size minus room for the sign and null byte. + int buf_remaining = buf_size - 1 - (s - buf); + + { + char uc = fmt & 0x20; + if (fp_isinf(f)) { + *s++ = 'I' ^ uc; + *s++ = 'N' ^ uc; + *s++ = 'F' ^ uc; + goto ret; + } else if (fp_isnan(f)) { + *s++ = 'N' ^ uc; + *s++ = 'A' ^ uc; + *s++ = 'N' ^ uc; + ret: + *s = '\0'; + return s - buf; + } + } + + if (prec < 0) { + prec = 6; + } + char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt + fmt |= 0x20; // Force fmt to be lowercase + char org_fmt = fmt; + if (fmt == 'g' && prec == 0) { + prec = 1; + } + int e, e1; + int dec = 0; + char e_sign = '\0'; + int num_digits = 0; + const FPTYPE *pos_pow = g_pos_pow; + const FPTYPE *neg_pow = g_neg_pow; + + if (fp_iszero(f)) { + e = 0; + if (fmt == 'f') { + // Truncate precision to prevent buffer overflow + if (prec + 2 > buf_remaining) { + prec = buf_remaining - 2; + } + num_digits = prec + 1; + } else { + // Truncate precision to prevent buffer overflow + if (prec + 6 > buf_remaining) { + prec = buf_remaining - 6; + } + if (fmt == 'e') { + e_sign = '+'; + } + } + } else if (fp_isless1(f)) { + // We need to figure out what an integer digit will be used + // in case 'f' is used (or we revert other format to it below). + // As we just tested number to be <1, this is obviously 0, + // but we can round it up to 1 below. + char first_dig = '0'; + if (f >= FPROUND_TO_ONE) { + first_dig = '1'; + } + + // Build negative exponent + for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*neg_pow > f) { + e += e1; + f *= *pos_pow; + } + } + char e_sign_char = '-'; + if (fp_isless1(f) && f >= FPROUND_TO_ONE) { + f = FPCONST(1.0); + if (e == 0) { + e_sign_char = '+'; + } + } else if (fp_isless1(f)) { + e++; + f *= FPCONST(10.0); + } + + // If the user specified 'g' format, and e is <= 4, then we'll switch + // to the fixed format ('f') + + if (fmt == 'f' || (fmt == 'g' && e <= 4)) { + fmt = 'f'; + dec = -1; + *s++ = first_dig; + + if (org_fmt == 'g') { + prec += (e - 1); + } + + // truncate precision to prevent buffer overflow + if (prec + 2 > buf_remaining) { + prec = buf_remaining - 2; + } + + num_digits = prec; + if (num_digits) { + *s++ = '.'; + while (--e && num_digits) { + *s++ = '0'; + num_digits--; + } + } + } else { + // For e & g formats, we'll be printing the exponent, so set the + // sign. + e_sign = e_sign_char; + dec = 0; + + if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { + prec = buf_remaining - FPMIN_BUF_SIZE; + if (fmt == 'g') { + prec++; + } + } + } + } else { + // Build positive exponent + for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*pos_pow <= f) { + e += e1; + f *= *neg_pow; + } + } + + // It can be that f was right on the edge of an entry in pos_pow needs to be reduced + if ((int)f >= 10) { + e += 1; + f *= FPCONST(0.1); + } + + // If the user specified fixed format (fmt == 'f') and e makes the + // number too big to fit into the available buffer, then we'll + // switch to the 'e' format. + + if (fmt == 'f') { + if (e >= buf_remaining) { + fmt = 'e'; + } else if ((e + prec + 2) > buf_remaining) { + prec = buf_remaining - e - 2; + if (prec < 0) { + // This means no decimal point, so we can add one back + // for the decimal. + prec++; + } + } + } + if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) { + prec = buf_remaining - FPMIN_BUF_SIZE; + } + if (fmt == 'g'){ + // Truncate precision to prevent buffer overflow + if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) { + prec = buf_remaining - (FPMIN_BUF_SIZE - 1); + } + } + // If the user specified 'g' format, and e is < prec, then we'll switch + // to the fixed format. + + if (fmt == 'g' && e < prec) { + fmt = 'f'; + prec -= (e + 1); + } + if (fmt == 'f') { + dec = e; + num_digits = prec + e + 1; + } else { + e_sign = '+'; + } + } + if (prec < 0) { + // This can happen when the prec is trimmed to prevent buffer overflow + prec = 0; + } + + // We now have num.f as a floating point number between >= 1 and < 10 + // (or equal to zero), and e contains the absolute value of the power of + // 10 exponent. and (dec + 1) == the number of dgits before the decimal. + + // For e, prec is # digits after the decimal + // For f, prec is # digits after the decimal + // For g, prec is the max number of significant digits + // + // For e & g there will be a single digit before the decimal + // for f there will be e digits before the decimal + + if (fmt == 'e') { + num_digits = prec + 1; + } else if (fmt == 'g') { + if (prec == 0) { + prec = 1; + } + num_digits = prec; + } + + // Print the digits of the mantissa + for (int i = 0; i < num_digits; ++i, --dec) { + int32_t d = (int32_t)f; + if (d < 0) { + *s++ = '0'; + } else { + *s++ = '0' + d; + } + if (dec == 0 && prec > 0) { + *s++ = '.'; + } + f -= (FPTYPE)d; + f *= FPCONST(10.0); + } + + // Round + // If we print non-exponential format (i.e. 'f'), but a digit we're going + // to round by (e) is too far away, then there's nothing to round. + if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) { + char *rs = s; + rs--; + while (1) { + if (*rs == '.') { + rs--; + continue; + } + if (*rs < '0' || *rs > '9') { + // + or - + rs++; // So we sit on the digit to the right of the sign + break; + } + if (*rs < '9') { + (*rs)++; + break; + } + *rs = '0'; + if (rs == buf) { + break; + } + rs--; + } + if (*rs == '0') { + // We need to insert a 1 + if (rs[1] == '.' && fmt != 'f') { + // We're going to round 9.99 to 10.00 + // Move the decimal point + rs[0] = '.'; + rs[1] = '0'; + if (e_sign == '-') { + e--; + if (e == 0) { + e_sign = '+'; + } + } else { + e++; + } + } else { + // Need at extra digit at the end to make room for the leading '1' + s++; + } + char *ss = s; + while (ss > rs) { + *ss = ss[-1]; + ss--; + } + *rs = '1'; + } + } + + // verify that we did not overrun the input buffer so far + assert((size_t)(s + 1 - buf) <= buf_size); + + if (org_fmt == 'g' && prec > 0) { + // Remove trailing zeros and a trailing decimal point + while (s[-1] == '0') { + s--; + } + if (s[-1] == '.') { + s--; + } + } + // Append the exponent + if (e_sign) { + *s++ = e_char; + *s++ = e_sign; + if (FPMIN_BUF_SIZE == 7 && e >= 100) { + *s++ = '0' + (e / 100); + } + *s++ = '0' + ((e / 10) % 10); + *s++ = '0' + (e % 10); + } + *s = '\0'; + + // verify that we did not overrun the input buffer + assert((size_t)(s + 1 - buf) <= buf_size); + + return s - buf; +} + +#endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE diff --git a/src/openmv/src/micropython/py/formatfloat.h b/src/openmv/src/micropython/py/formatfloat.h new file mode 100755 index 0000000..9a1643b --- /dev/null +++ b/src/openmv/src/micropython/py/formatfloat.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_FORMATFLOAT_H +#define MICROPY_INCLUDED_PY_FORMATFLOAT_H + +#include "py/mpconfig.h" + +#if MICROPY_PY_BUILTINS_FLOAT +int mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign); +#endif + +#endif // MICROPY_INCLUDED_PY_FORMATFLOAT_H diff --git a/src/openmv/src/micropython/py/frozenmod.c b/src/openmv/src/micropython/py/frozenmod.c new file mode 100755 index 0000000..06d4f84 --- /dev/null +++ b/src/openmv/src/micropython/py/frozenmod.c @@ -0,0 +1,156 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/lexer.h" +#include "py/frozenmod.h" + +#if MICROPY_MODULE_FROZEN_STR + +#ifndef MICROPY_MODULE_FROZEN_LEXER +#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str_len +#else +mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len); +#endif + +extern const char mp_frozen_str_names[]; +extern const uint32_t mp_frozen_str_sizes[]; +extern const char mp_frozen_str_content[]; + +// On input, *len contains size of name, on output - size of content +const char *mp_find_frozen_str(const char *str, size_t *len) { + const char *name = mp_frozen_str_names; + + size_t offset = 0; + for (int i = 0; *name != 0; i++) { + size_t l = strlen(name); + if (l == *len && !memcmp(str, name, l)) { + *len = mp_frozen_str_sizes[i]; + return mp_frozen_str_content + offset; + } + name += l + 1; + offset += mp_frozen_str_sizes[i] + 1; + } + return NULL; +} + +STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) { + size_t name_len = len; + const char *content = mp_find_frozen_str(str, &len); + + if (content == NULL) { + return NULL; + } + + qstr source = qstr_from_strn(str, name_len); + mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0); + return lex; +} + +#endif + +#if MICROPY_MODULE_FROZEN_MPY + +#include "py/emitglue.h" + +extern const char mp_frozen_mpy_names[]; +extern const mp_raw_code_t *const mp_frozen_mpy_content[]; + +STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) { + const char *name = mp_frozen_mpy_names; + for (size_t i = 0; *name != 0; i++) { + size_t l = strlen(name); + if (l == len && !memcmp(str, name, l)) { + return mp_frozen_mpy_content[i]; + } + name += l + 1; + } + return NULL; +} + +#endif + +#if MICROPY_MODULE_FROZEN + +STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) { + size_t len = strlen(str); + + for (int i = 0; *name != 0; i++) { + size_t l = strlen(name); + if (l >= len && !memcmp(str, name, len)) { + if (name[len] == 0) { + return MP_IMPORT_STAT_FILE; + } else if (name[len] == '/') { + return MP_IMPORT_STAT_DIR; + } + } + name += l + 1; + } + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_import_stat_t mp_frozen_stat(const char *str) { + mp_import_stat_t stat; + + #if MICROPY_MODULE_FROZEN_STR + stat = mp_frozen_stat_helper(mp_frozen_str_names, str); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; + } + #endif + + #if MICROPY_MODULE_FROZEN_MPY + stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; + } + #endif + + return MP_IMPORT_STAT_NO_EXIST; +} + +int mp_find_frozen_module(const char *str, size_t len, void **data) { + #if MICROPY_MODULE_FROZEN_STR + mp_lexer_t *lex = mp_lexer_frozen_str(str, len); + if (lex != NULL) { + *data = lex; + return MP_FROZEN_STR; + } + #endif + #if MICROPY_MODULE_FROZEN_MPY + const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len); + if (rc != NULL) { + *data = (void*)rc; + return MP_FROZEN_MPY; + } + #endif + return MP_FROZEN_NONE; +} + +#endif diff --git a/src/openmv/src/micropython/py/frozenmod.h b/src/openmv/src/micropython/py/frozenmod.h new file mode 100755 index 0000000..8cddef6 --- /dev/null +++ b/src/openmv/src/micropython/py/frozenmod.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_FROZENMOD_H +#define MICROPY_INCLUDED_PY_FROZENMOD_H + +#include "py/lexer.h" + +enum { + MP_FROZEN_NONE, + MP_FROZEN_STR, + MP_FROZEN_MPY, +}; + +int mp_find_frozen_module(const char *str, size_t len, void **data); +const char *mp_find_frozen_str(const char *str, size_t *len); +mp_import_stat_t mp_frozen_stat(const char *str); + +#endif // MICROPY_INCLUDED_PY_FROZENMOD_H diff --git a/src/openmv/src/micropython/py/gc.c b/src/openmv/src/micropython/py/gc.c new file mode 100755 index 0000000..0725724 --- /dev/null +++ b/src/openmv/src/micropython/py/gc.c @@ -0,0 +1,951 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" + +#if MICROPY_ENABLE_GC + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +// make this 1 to dump the heap each time it changes +#define EXTENSIVE_HEAP_PROFILING (0) + +// make this 1 to zero out swept memory to more eagerly +// detect untraced object still in use +#define CLEAR_ON_SWEEP (0) + +#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD) +#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK) + +// ATB = allocation table byte +// 0b00 = FREE -- free block +// 0b01 = HEAD -- head of a chain of blocks +// 0b10 = TAIL -- in the tail of a chain of blocks +// 0b11 = MARK -- marked head block + +#define AT_FREE (0) +#define AT_HEAD (1) +#define AT_TAIL (2) +#define AT_MARK (3) + +#define BLOCKS_PER_ATB (4) +#define ATB_MASK_0 (0x03) +#define ATB_MASK_1 (0x0c) +#define ATB_MASK_2 (0x30) +#define ATB_MASK_3 (0xc0) + +#define ATB_0_IS_FREE(a) (((a) & ATB_MASK_0) == 0) +#define ATB_1_IS_FREE(a) (((a) & ATB_MASK_1) == 0) +#define ATB_2_IS_FREE(a) (((a) & ATB_MASK_2) == 0) +#define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0) + +#define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1))) +#define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3) +#define ATB_ANY_TO_FREE(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0) +#define ATB_FREE_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0) +#define ATB_FREE_TO_TAIL(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0) +#define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0) +#define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0) + +#define BLOCK_FROM_PTR(ptr) (((byte*)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK) +#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start))) +#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB) + +#if MICROPY_ENABLE_FINALISER +// FTB = finaliser table byte +// if set, then the corresponding block may have a finaliser + +#define BLOCKS_PER_FTB (8) + +#define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1) +#define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0) +#define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0) +#endif + +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +#define GC_ENTER() mp_thread_mutex_lock(&MP_STATE_MEM(gc_mutex), 1) +#define GC_EXIT() mp_thread_mutex_unlock(&MP_STATE_MEM(gc_mutex)) +#else +#define GC_ENTER() +#define GC_EXIT() +#endif + +// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool +void gc_init(void *start, void *end) { + // align end pointer on block boundary + end = (void*)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1))); + DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start); + + // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes): + // T = A + F + P + // F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB + // P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK + // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK) + size_t total_byte_len = (byte*)end - (byte*)start; +#if MICROPY_ENABLE_FINALISER + MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK); +#else + MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK); +#endif + + MP_STATE_MEM(gc_alloc_table_start) = (byte*)start; + +#if MICROPY_ENABLE_FINALISER + size_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB; + MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len); +#endif + + size_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; + MP_STATE_MEM(gc_pool_start) = (byte*)end - gc_pool_block_len * BYTES_PER_BLOCK; + MP_STATE_MEM(gc_pool_end) = end; + +#if MICROPY_ENABLE_FINALISER + assert(MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len); +#endif + + // clear ATBs + memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len)); + +#if MICROPY_ENABLE_FINALISER + // clear FTBs + memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len); +#endif + + // set last free ATB index to start of heap + MP_STATE_MEM(gc_last_free_atb_index) = 0; + + // unlock the GC + MP_STATE_MEM(gc_lock_depth) = 0; + + // allow auto collection + MP_STATE_MEM(gc_auto_collect_enabled) = 1; + + #if MICROPY_GC_ALLOC_THRESHOLD + // by default, maxuint for gc threshold, effectively turning gc-by-threshold off + MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; + MP_STATE_MEM(gc_alloc_amount) = 0; + #endif + + #if MICROPY_PY_THREAD + mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); + #endif + + DEBUG_printf("GC layout:\n"); + DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); +#if MICROPY_ENABLE_FINALISER + DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB); +#endif + DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); +} + +void gc_lock(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; + GC_EXIT(); +} + +void gc_unlock(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)--; + GC_EXIT(); +} + +bool gc_is_locked(void) { + return MP_STATE_MEM(gc_lock_depth) != 0; +} + +// ptr should be of type void* +#define VERIFY_PTR(ptr) ( \ + ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \ + && ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \ + && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ + ) + +#ifndef TRACE_MARK +#if DEBUG_PRINT +#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr) +#else +#define TRACE_MARK(block, ptr) +#endif +#endif + +// Take the given block as the topmost block on the stack. Check all it's +// children: mark the unmarked child blocks and put those newly marked +// blocks on the stack. When all children have been checked, pop off the +// topmost block on the stack and repeat with that one. +STATIC void gc_mark_subtree(size_t block) { + // Start with the block passed in the argument. + size_t sp = 0; + for (;;) { + // work out number of consecutive blocks in the chain starting with this one + size_t n_blocks = 0; + do { + n_blocks += 1; + } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL); + + // check this block's children + void **ptrs = (void**)PTR_FROM_BLOCK(block); + for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) { + void *ptr = *ptrs; + if (VERIFY_PTR(ptr)) { + // Mark and push this pointer + size_t childblock = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(childblock) == AT_HEAD) { + // an unmarked head, mark it, and push it on gc stack + TRACE_MARK(childblock, ptr); + ATB_HEAD_TO_MARK(childblock); + if (sp < MICROPY_ALLOC_GC_STACK_SIZE) { + MP_STATE_MEM(gc_stack)[sp++] = childblock; + } else { + MP_STATE_MEM(gc_stack_overflow) = 1; + } + } + } + } + + // Are there any blocks on the stack? + if (sp == 0) { + break; // No, stack is empty, we're done. + } + + // pop the next block off the stack + block = MP_STATE_MEM(gc_stack)[--sp]; + } +} + +STATIC void gc_deal_with_stack_overflow(void) { + while (MP_STATE_MEM(gc_stack_overflow)) { + MP_STATE_MEM(gc_stack_overflow) = 0; + + // scan entire memory looking for blocks which have been marked but not their children + for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { + // trace (again) if mark bit set + if (ATB_GET_KIND(block) == AT_MARK) { + gc_mark_subtree(block); + } + } + } +} + +STATIC void gc_sweep(void) { + #if MICROPY_PY_GC_COLLECT_RETVAL + MP_STATE_MEM(gc_collected) = 0; + #endif + // free unmarked heads and their tails + int free_tail = 0; + for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { + switch (ATB_GET_KIND(block)) { + case AT_HEAD: +#if MICROPY_ENABLE_FINALISER + if (FTB_GET(block)) { + mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block); + if (obj->type != NULL) { + // if the object has a type then see if it has a __del__ method + mp_obj_t dest[2]; + mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest); + if (dest[0] != MP_OBJ_NULL) { + // load_method returned a method, execute it in a protected environment + #if MICROPY_ENABLE_SCHEDULER + mp_sched_lock(); + #endif + mp_call_function_1_protected(dest[0], dest[1]); + #if MICROPY_ENABLE_SCHEDULER + mp_sched_unlock(); + #endif + } + } + // clear finaliser flag + FTB_CLEAR(block); + } +#endif + free_tail = 1; + DEBUG_printf("gc_sweep(%p)\n", PTR_FROM_BLOCK(block)); + #if MICROPY_PY_GC_COLLECT_RETVAL + MP_STATE_MEM(gc_collected)++; + #endif + // fall through to free the head + + case AT_TAIL: + if (free_tail) { + ATB_ANY_TO_FREE(block); + #if CLEAR_ON_SWEEP + memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK); + #endif + } + break; + + case AT_MARK: + ATB_MARK_TO_HEAD(block); + free_tail = 0; + break; + } + } +} + +void gc_collect_start(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; + #if MICROPY_GC_ALLOC_THRESHOLD + MP_STATE_MEM(gc_alloc_amount) = 0; + #endif + MP_STATE_MEM(gc_stack_overflow) = 0; + + // Trace root pointers. This relies on the root pointers being organised + // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, + // dict_globals, then the root pointer section of mp_state_vm. + void **ptrs = (void**)(void*)&mp_state_ctx; + size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals); + size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk); + gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*)); + + #if MICROPY_ENABLE_PYSTACK + // Trace root pointers from the Python stack. + ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif +} + +void gc_collect_root(void **ptrs, size_t len) { + for (size_t i = 0; i < len; i++) { + void *ptr = ptrs[i]; + if (VERIFY_PTR(ptr)) { + size_t block = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(block) == AT_HEAD) { + // An unmarked head: mark it, and mark all its children + TRACE_MARK(block, ptr); + ATB_HEAD_TO_MARK(block); + gc_mark_subtree(block); + } + } + } +} + +void gc_collect_end(void) { + gc_deal_with_stack_overflow(); + gc_sweep(); + MP_STATE_MEM(gc_last_free_atb_index) = 0; + MP_STATE_MEM(gc_lock_depth)--; + GC_EXIT(); +} + +void gc_sweep_all(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; + MP_STATE_MEM(gc_stack_overflow) = 0; + gc_collect_end(); +} + +void gc_info(gc_info_t *info) { + GC_ENTER(); + info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start); + info->used = 0; + info->free = 0; + info->max_free = 0; + info->num_1block = 0; + info->num_2block = 0; + info->max_block = 0; + bool finish = false; + for (size_t block = 0, len = 0, len_free = 0; !finish;) { + size_t kind = ATB_GET_KIND(block); + switch (kind) { + case AT_FREE: + info->free += 1; + len_free += 1; + len = 0; + break; + + case AT_HEAD: + info->used += 1; + len = 1; + break; + + case AT_TAIL: + info->used += 1; + len += 1; + break; + + case AT_MARK: + // shouldn't happen + break; + } + + block++; + finish = (block == MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); + // Get next block type if possible + if (!finish) { + kind = ATB_GET_KIND(block); + } + + if (finish || kind == AT_FREE || kind == AT_HEAD) { + if (len == 1) { + info->num_1block += 1; + } else if (len == 2) { + info->num_2block += 1; + } + if (len > info->max_block) { + info->max_block = len; + } + if (finish || kind == AT_HEAD) { + if (len_free > info->max_free) { + info->max_free = len_free; + } + len_free = 0; + } + } + } + + info->used *= BYTES_PER_BLOCK; + info->free *= BYTES_PER_BLOCK; + GC_EXIT(); +} + +void *gc_alloc(size_t n_bytes, bool has_finaliser) { + size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK; + DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks); + + // check for 0 allocation + if (n_blocks == 0) { + return NULL; + } + + GC_ENTER(); + + // check if GC is locked + if (MP_STATE_MEM(gc_lock_depth) > 0) { + GC_EXIT(); + return NULL; + } + + size_t i; + size_t end_block; + size_t start_block; + size_t n_free; + int collected = !MP_STATE_MEM(gc_auto_collect_enabled); + + #if MICROPY_GC_ALLOC_THRESHOLD + if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { + GC_EXIT(); + gc_collect(); + collected = 1; + GC_ENTER(); + } + #endif + + for (;;) { + + // look for a run of n_blocks available blocks + n_free = 0; + for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) { + byte a = MP_STATE_MEM(gc_alloc_table_start)[i]; + if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; } + if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; } + if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; } + if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; } + } + + GC_EXIT(); + // nothing found! + if (collected) { + return NULL; + } + DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes); + gc_collect(); + collected = 1; + GC_ENTER(); + } + + // found, ending at block i inclusive +found: + // get starting and end blocks, both inclusive + end_block = i; + start_block = i - n_free + 1; + + // Set last free ATB index to block after last block we found, for start of + // next scan. To reduce fragmentation, we only do this if we were looking + // for a single free block, which guarantees that there are no free blocks + // before this one. Also, whenever we free or shink a block we must check + // if this index needs adjusting (see gc_realloc and gc_free). + if (n_free == 1) { + MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB; + } + + // mark first block as used head + ATB_FREE_TO_HEAD(start_block); + + // mark rest of blocks as used tail + // TODO for a run of many blocks can make this more efficient + for (size_t bl = start_block + 1; bl <= end_block; bl++) { + ATB_FREE_TO_TAIL(bl); + } + + // get pointer to first block + // we must create this pointer before unlocking the GC so a collection can find it + void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK); + DEBUG_printf("gc_alloc(%p)\n", ret_ptr); + + #if MICROPY_GC_ALLOC_THRESHOLD + MP_STATE_MEM(gc_alloc_amount) += n_blocks; + #endif + + GC_EXIT(); + + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK); + #else + // zero out the additional bytes of the newly allocated blocks + // This is needed because the blocks may have previously held pointers + // to the heap and will not be set to something else if the caller + // doesn't actually use the entire block. As such they will continue + // to point to the heap and may prevent other blocks from being reclaimed. + memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes); + #endif + + #if MICROPY_ENABLE_FINALISER + if (has_finaliser) { + // clear type pointer in case it is never set + ((mp_obj_base_t*)ret_ptr)->type = NULL; + // set mp_obj flag only if it has a finaliser + GC_ENTER(); + FTB_SET(start_block); + GC_EXIT(); + } + #else + (void)has_finaliser; + #endif + + #if EXTENSIVE_HEAP_PROFILING + gc_dump_alloc_table(); + #endif + + return ret_ptr; +} + +/* +void *gc_alloc(mp_uint_t n_bytes) { + return _gc_alloc(n_bytes, false); +} + +void *gc_alloc_with_finaliser(mp_uint_t n_bytes) { + return _gc_alloc(n_bytes, true); +} +*/ + +// force the freeing of a piece of memory +// TODO: freeing here does not call finaliser +void gc_free(void *ptr) { + GC_ENTER(); + if (MP_STATE_MEM(gc_lock_depth) > 0) { + // TODO how to deal with this error? + GC_EXIT(); + return; + } + + DEBUG_printf("gc_free(%p)\n", ptr); + + if (ptr == NULL) { + GC_EXIT(); + } else { + // get the GC block number corresponding to this pointer + assert(VERIFY_PTR(ptr)); + size_t block = BLOCK_FROM_PTR(ptr); + assert(ATB_GET_KIND(block) == AT_HEAD); + + #if MICROPY_ENABLE_FINALISER + FTB_CLEAR(block); + #endif + + // set the last_free pointer to this block if it's earlier in the heap + if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) { + MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB; + } + + // free head and all of its tail blocks + do { + ATB_ANY_TO_FREE(block); + block += 1; + } while (ATB_GET_KIND(block) == AT_TAIL); + + GC_EXIT(); + + #if EXTENSIVE_HEAP_PROFILING + gc_dump_alloc_table(); + #endif + } +} + +size_t gc_nbytes(const void *ptr) { + GC_ENTER(); + if (VERIFY_PTR(ptr)) { + size_t block = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(block) == AT_HEAD) { + // work out number of consecutive blocks in the chain starting with this on + size_t n_blocks = 0; + do { + n_blocks += 1; + } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL); + GC_EXIT(); + return n_blocks * BYTES_PER_BLOCK; + } + } + + // invalid pointer + GC_EXIT(); + return 0; +} + +#if 0 +// old, simple realloc that didn't expand memory in place +void *gc_realloc(void *ptr, mp_uint_t n_bytes) { + mp_uint_t n_existing = gc_nbytes(ptr); + if (n_bytes <= n_existing) { + return ptr; + } else { + bool has_finaliser; + if (ptr == NULL) { + has_finaliser = false; + } else { +#if MICROPY_ENABLE_FINALISER + has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr)); +#else + has_finaliser = false; +#endif + } + void *ptr2 = gc_alloc(n_bytes, has_finaliser); + if (ptr2 == NULL) { + return ptr2; + } + memcpy(ptr2, ptr, n_existing); + gc_free(ptr); + return ptr2; + } +} + +#else // Alternative gc_realloc impl + +void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { + // check for pure allocation + if (ptr_in == NULL) { + return gc_alloc(n_bytes, false); + } + + // check for pure free + if (n_bytes == 0) { + gc_free(ptr_in); + return NULL; + } + + void *ptr = ptr_in; + + GC_ENTER(); + + if (MP_STATE_MEM(gc_lock_depth) > 0) { + GC_EXIT(); + return NULL; + } + + // get the GC block number corresponding to this pointer + assert(VERIFY_PTR(ptr)); + size_t block = BLOCK_FROM_PTR(ptr); + assert(ATB_GET_KIND(block) == AT_HEAD); + + // compute number of new blocks that are requested + size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; + + // Get the total number of consecutive blocks that are already allocated to + // this chunk of memory, and then count the number of free blocks following + // it. Stop if we reach the end of the heap, or if we find enough extra + // free blocks to satisfy the realloc. Note that we need to compute the + // total size of the existing memory chunk so we can correctly and + // efficiently shrink it (see below for shrinking code). + size_t n_free = 0; + size_t n_blocks = 1; // counting HEAD block + size_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; + for (size_t bl = block + n_blocks; bl < max_block; bl++) { + byte block_type = ATB_GET_KIND(bl); + if (block_type == AT_TAIL) { + n_blocks++; + continue; + } + if (block_type == AT_FREE) { + n_free++; + if (n_blocks + n_free >= new_blocks) { + // stop as soon as we find enough blocks for n_bytes + break; + } + continue; + } + break; + } + + // return original ptr if it already has the requested number of blocks + if (new_blocks == n_blocks) { + GC_EXIT(); + return ptr_in; + } + + // check if we can shrink the allocated area + if (new_blocks < n_blocks) { + // free unneeded tail blocks + for (size_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) { + ATB_ANY_TO_FREE(bl); + } + + // set the last_free pointer to end of this block if it's earlier in the heap + if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) { + MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB; + } + + GC_EXIT(); + + #if EXTENSIVE_HEAP_PROFILING + gc_dump_alloc_table(); + #endif + + return ptr_in; + } + + // check if we can expand in place + if (new_blocks <= n_blocks + n_free) { + // mark few more blocks as used tail + for (size_t bl = block + n_blocks; bl < block + new_blocks; bl++) { + assert(ATB_GET_KIND(bl) == AT_FREE); + ATB_FREE_TO_TAIL(bl); + } + + GC_EXIT(); + + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK); + #else + // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc) + memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes); + #endif + + #if EXTENSIVE_HEAP_PROFILING + gc_dump_alloc_table(); + #endif + + return ptr_in; + } + + #if MICROPY_ENABLE_FINALISER + bool ftb_state = FTB_GET(block); + #else + bool ftb_state = false; + #endif + + GC_EXIT(); + + if (!allow_move) { + // not allowed to move memory block so return failure + return NULL; + } + + // can't resize inplace; try to find a new contiguous chain + void *ptr_out = gc_alloc(n_bytes, ftb_state); + + // check that the alloc succeeded + if (ptr_out == NULL) { + return NULL; + } + + DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out); + memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK); + gc_free(ptr_in); + return ptr_out; +} +#endif // Alternative gc_realloc impl + +void gc_dump_info(void) { + gc_info_t info; + gc_info(&info); + mp_printf(&mp_plat_print, "GC: total: %u, used: %u, free: %u\n", + (uint)info.total, (uint)info.used, (uint)info.free); + mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n", + (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free); +} + +void gc_dump_alloc_table(void) { + GC_ENTER(); + static const size_t DUMP_BYTES_PER_LINE = 64; + #if !EXTENSIVE_HEAP_PROFILING + // When comparing heap output we don't want to print the starting + // pointer of the heap because it changes from run to run. + mp_printf(&mp_plat_print, "GC memory layout; from %p:", MP_STATE_MEM(gc_pool_start)); + #endif + for (size_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) { + if (bl % DUMP_BYTES_PER_LINE == 0) { + // a new line of blocks + { + // check if this line contains only free blocks + size_t bl2 = bl; + while (bl2 < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) { + bl2++; + } + if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) { + // there are at least 2 lines containing only free blocks, so abbreviate their printing + mp_printf(&mp_plat_print, "\n (%u lines all free)", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE); + bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1)); + if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) { + // got to end of heap + break; + } + } + } + // print header for new line of blocks + // (the cast to uint32_t is for 16-bit ports) + //mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); + mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff)); + } + int c = ' '; + switch (ATB_GET_KIND(bl)) { + case AT_FREE: c = '.'; break; + /* this prints out if the object is reachable from BSS or STACK (for unix only) + case AT_HEAD: { + c = 'h'; + void **ptrs = (void**)(void*)&mp_state_ctx; + mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t); + for (mp_uint_t i = 0; i < len; i++) { + mp_uint_t ptr = (mp_uint_t)ptrs[i]; + if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) { + c = 'B'; + break; + } + } + if (c == 'h') { + ptrs = (void**)&c; + len = ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t); + for (mp_uint_t i = 0; i < len; i++) { + mp_uint_t ptr = (mp_uint_t)ptrs[i]; + if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) { + c = 'S'; + break; + } + } + } + break; + } + */ + /* this prints the uPy object type of the head block */ + case AT_HEAD: { + void **ptr = (void**)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK); + if (*ptr == &mp_type_tuple) { c = 'T'; } + else if (*ptr == &mp_type_list) { c = 'L'; } + else if (*ptr == &mp_type_dict) { c = 'D'; } + else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) { c = 'S'; } + #if MICROPY_PY_BUILTINS_BYTEARRAY + else if (*ptr == &mp_type_bytearray) { c = 'A'; } + #endif + #if MICROPY_PY_ARRAY + else if (*ptr == &mp_type_array) { c = 'A'; } + #endif + #if MICROPY_PY_BUILTINS_FLOAT + else if (*ptr == &mp_type_float) { c = 'F'; } + #endif + else if (*ptr == &mp_type_fun_bc) { c = 'B'; } + else if (*ptr == &mp_type_module) { c = 'M'; } + else { + c = 'h'; + #if 0 + // This code prints "Q" for qstr-pool data, and "q" for qstr-str + // data. It can be useful to see how qstrs are being allocated, + // but is disabled by default because it is very slow. + for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) { + if ((qstr_pool_t*)ptr == pool) { + c = 'Q'; + break; + } + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + if ((const byte*)ptr == *q) { + c = 'q'; + break; + } + } + } + #endif + } + break; + } + case AT_TAIL: c = '='; break; + case AT_MARK: c = 'm'; break; + } + mp_printf(&mp_plat_print, "%c", c); + } + mp_print_str(&mp_plat_print, "\n"); + GC_EXIT(); +} + +#if 0 +// For testing the GC functions +void gc_test(void) { + mp_uint_t len = 500; + mp_uint_t *heap = malloc(len); + gc_init(heap, heap + len / sizeof(mp_uint_t)); + void *ptrs[100]; + { + mp_uint_t **p = gc_alloc(16, false); + p[0] = gc_alloc(64, false); + p[1] = gc_alloc(1, false); + p[2] = gc_alloc(1, false); + p[3] = gc_alloc(1, false); + mp_uint_t ***p2 = gc_alloc(16, false); + p2[0] = p; + p2[1] = p; + ptrs[0] = p2; + } + for (int i = 0; i < 25; i+=2) { + mp_uint_t *p = gc_alloc(i, false); + printf("p=%p\n", p); + if (i & 3) { + //ptrs[i] = p; + } + } + + printf("Before GC:\n"); + gc_dump_alloc_table(); + printf("Starting GC...\n"); + gc_collect_start(); + gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void*)); + gc_collect_end(); + printf("After GC:\n"); + gc_dump_alloc_table(); +} +#endif + +#endif // MICROPY_ENABLE_GC diff --git a/src/openmv/src/micropython/py/gc.h b/src/openmv/src/micropython/py/gc.h new file mode 100755 index 0000000..73d86e6 --- /dev/null +++ b/src/openmv/src/micropython/py/gc.h @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_GC_H +#define MICROPY_INCLUDED_PY_GC_H + +#include + +#include "py/mpconfig.h" +#include "py/misc.h" + +void gc_init(void *start, void *end); + +// These lock/unlock functions can be nested. +// They can be used to prevent the GC from allocating/freeing. +void gc_lock(void); +void gc_unlock(void); +bool gc_is_locked(void); + +// A given port must implement gc_collect by using the other collect functions. +void gc_collect(void); +void gc_collect_start(void); +void gc_collect_root(void **ptrs, size_t len); +void gc_collect_end(void); + +// Use this function to sweep the whole heap and run all finalisers +void gc_sweep_all(void); + +void *gc_alloc(size_t n_bytes, bool has_finaliser); +void gc_free(void *ptr); // does not call finaliser +size_t gc_nbytes(const void *ptr); +void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move); + +typedef struct _gc_info_t { + size_t total; + size_t used; + size_t free; + size_t max_free; + size_t num_1block; + size_t num_2block; + size_t max_block; +} gc_info_t; + +void gc_info(gc_info_t *info); +void gc_dump_info(void); +void gc_dump_alloc_table(void); + +#endif // MICROPY_INCLUDED_PY_GC_H diff --git a/src/openmv/src/micropython/py/grammar.h b/src/openmv/src/micropython/py/grammar.h new file mode 100755 index 0000000..5a5b682 --- /dev/null +++ b/src/openmv/src/micropython/py/grammar.h @@ -0,0 +1,357 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// rules for writing rules: +// - zero_or_more is implemented using opt_rule around a one_or_more rule +// - don't put opt_rule in arguments of or rule; instead, wrap the call to this or rule in opt_rule + +// # Start symbols for the grammar: +// # single_input is a single interactive statement; +// # file_input is a module or sequence of commands read from an input file; +// # eval_input is the input for the eval() functions. +// # NB: compound_stmt in single_input is followed by extra NEWLINE! --> not in MicroPython +// single_input: NEWLINE | simple_stmt | compound_stmt +// file_input: (NEWLINE | stmt)* ENDMARKER +// eval_input: testlist NEWLINE* ENDMARKER + +DEF_RULE_NC(single_input, or(3), tok(NEWLINE), rule(simple_stmt), rule(compound_stmt)) +DEF_RULE(file_input, c(generic_all_nodes), and_ident(1), opt_rule(file_input_2)) +DEF_RULE(file_input_2, c(generic_all_nodes), one_or_more, rule(file_input_3)) +DEF_RULE_NC(file_input_3, or(2), tok(NEWLINE), rule(stmt)) +DEF_RULE_NC(eval_input, and_ident(2), rule(testlist), opt_rule(eval_input_2)) +DEF_RULE_NC(eval_input_2, and(1), tok(NEWLINE)) + +// decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE +// decorators: decorator+ +// decorated: decorators (classdef | funcdef | async_funcdef) +// funcdef: 'def' NAME parameters ['->' test] ':' suite +// async_funcdef: 'async' funcdef +// parameters: '(' [typedargslist] ')' +// typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* [',' ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]] | '*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef +// tfpdef: NAME [':' test] +// varargslist: vfpdef ['=' test] (',' vfpdef ['=' test])* [',' ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef +// vfpdef: NAME + +DEF_RULE_NC(decorator, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE)) +DEF_RULE_NC(decorators, one_or_more, rule(decorator)) +DEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body)) +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE_NC(decorated_body, or(3), rule(classdef), rule(funcdef), rule(async_funcdef)) +DEF_RULE_NC(async_funcdef, and(2), tok(KW_ASYNC), rule(funcdef)) +#else +DEF_RULE_NC(decorated_body, or(2), rule(classdef), rule(funcdef)) +#endif +DEF_RULE(funcdef, c(funcdef), and_blank(8), tok(KW_DEF), tok(NAME), tok(DEL_PAREN_OPEN), opt_rule(typedargslist), tok(DEL_PAREN_CLOSE), opt_rule(funcdefrettype), tok(DEL_COLON), rule(suite)) +DEF_RULE_NC(funcdefrettype, and_ident(2), tok(DEL_MINUS_MORE), rule(test)) +// note: typedargslist lets through more than is allowed, compiler does further checks +DEF_RULE_NC(typedargslist, list_with_end, rule(typedargslist_item), tok(DEL_COMMA)) +DEF_RULE_NC(typedargslist_item, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star)) +DEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal)) +DEF_RULE_NC(typedargslist_star, and(2), tok(OP_STAR), opt_rule(tfpdef)) +DEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(typedargslist_colon)) +DEF_RULE_NC(typedargslist_colon, and_ident(2), tok(DEL_COLON), rule(test)) +DEF_RULE_NC(typedargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test)) +DEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(typedargslist_colon)) +// note: varargslist lets through more than is allowed, compiler does further checks +DEF_RULE_NC(varargslist, list_with_end, rule(varargslist_item), tok(DEL_COMMA)) +DEF_RULE_NC(varargslist_item, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star)) +DEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(varargslist_equal)) +DEF_RULE_NC(varargslist_star, and(2), tok(OP_STAR), opt_rule(vfpdef)) +DEF_RULE_NC(varargslist_dbl_star, and(2), tok(OP_DBL_STAR), tok(NAME)) +DEF_RULE_NC(varargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test)) +DEF_RULE_NC(vfpdef, and_ident(1), tok(NAME)) + +// stmt: compound_stmt | simple_stmt + +DEF_RULE_NC(stmt, or(2), rule(compound_stmt), rule(simple_stmt)) + +// simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE + +DEF_RULE_NC(simple_stmt, and_ident(2), rule(simple_stmt_2), tok(NEWLINE)) +DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON)) + +// small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt +// expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*) +// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] +// augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' +// # For normal assignments, additional restrictions enforced by the interpreter + +DEF_RULE_NC(small_stmt, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt)) +DEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2)) +DEF_RULE_NC(expr_stmt_2, or(2), rule(expr_stmt_augassign), rule(expr_stmt_assign_list)) +DEF_RULE_NC(expr_stmt_augassign, and_ident(2), rule(augassign), rule(expr_stmt_6)) +DEF_RULE_NC(expr_stmt_assign_list, one_or_more, rule(expr_stmt_assign)) +DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6)) +DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr)) +DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA)) +DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test)) +DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL)) + +// del_stmt: 'del' exprlist +// pass_stmt: 'pass' +// flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +// break_stmt: 'break' +// continue_stmt: 'continue' +// return_stmt: 'return' [testlist] +// yield_stmt: yield_expr +// raise_stmt: 'raise' [test ['from' test]] + +DEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist)) +DEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS)) +DEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt)) +DEF_RULE(break_stmt, c(break_cont_stmt), and(1), tok(KW_BREAK)) +DEF_RULE(continue_stmt, c(break_cont_stmt), and(1), tok(KW_CONTINUE)) +DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist)) +DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr)) +DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg)) +DEF_RULE_NC(raise_stmt_arg, and_ident(2), rule(test), opt_rule(raise_stmt_from)) +DEF_RULE_NC(raise_stmt_from, and_ident(2), tok(KW_FROM), rule(test)) + +// import_stmt: import_name | import_from +// import_name: 'import' dotted_as_names +// import_from: 'from' (('.' | '...')* dotted_name | ('.' | '...')+) 'import' ('*' | '(' import_as_names ')' | import_as_names) +// import_as_name: NAME ['as' NAME] +// dotted_as_name: dotted_name ['as' NAME] +// import_as_names: import_as_name (',' import_as_name)* [','] +// dotted_as_names: dotted_as_name (',' dotted_as_name)* +// dotted_name: NAME ('.' NAME)* +// global_stmt: 'global' NAME (',' NAME)* +// nonlocal_stmt: 'nonlocal' NAME (',' NAME)* +// assert_stmt: 'assert' test [',' test] + +DEF_RULE_NC(import_stmt, or(2), rule(import_name), rule(import_from)) +DEF_RULE(import_name, c(import_name), and(2), tok(KW_IMPORT), rule(dotted_as_names)) +DEF_RULE(import_from, c(import_from), and(4), tok(KW_FROM), rule(import_from_2), tok(KW_IMPORT), rule(import_from_3)) +DEF_RULE_NC(import_from_2, or(2), rule(dotted_name), rule(import_from_2b)) +DEF_RULE_NC(import_from_2b, and_ident(2), rule(one_or_more_period_or_ellipsis), opt_rule(dotted_name)) +DEF_RULE_NC(import_from_3, or(3), tok(OP_STAR), rule(import_as_names_paren), rule(import_as_names)) +DEF_RULE_NC(import_as_names_paren, and_ident(3), tok(DEL_PAREN_OPEN), rule(import_as_names), tok(DEL_PAREN_CLOSE)) +DEF_RULE_NC(one_or_more_period_or_ellipsis, one_or_more, rule(period_or_ellipsis)) +DEF_RULE_NC(period_or_ellipsis, or(2), tok(DEL_PERIOD), tok(ELLIPSIS)) +DEF_RULE_NC(import_as_name, and(2), tok(NAME), opt_rule(as_name)) +DEF_RULE_NC(dotted_as_name, and_ident(2), rule(dotted_name), opt_rule(as_name)) +DEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME)) +DEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA)) +DEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA)) +DEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD)) +DEF_RULE(global_stmt, c(global_nonlocal_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) +DEF_RULE(nonlocal_stmt, c(global_nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) +DEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA)) +DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra)) +DEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test)) + +// compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt +// if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +// while_stmt: 'while' test ':' suite ['else' ':' suite] +// for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] +// try_stmt: 'try' ':' suite ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite) +// # NB compile.c makes sure that the default except clause is last +// except_clause: 'except' [test ['as' NAME]] +// with_stmt: 'with' with_item (',' with_item)* ':' suite +// with_item: test ['as' expr] +// suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT +// async_stmt: 'async' (funcdef | with_stmt | for_stmt) + +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE_NC(compound_stmt, or(9), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated), rule(async_stmt)) +DEF_RULE(async_stmt, c(async_stmt), and(2), tok(KW_ASYNC), rule(async_stmt_2)) +DEF_RULE_NC(async_stmt_2, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt)) +#else +DEF_RULE_NC(compound_stmt, or(8), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated)) +#endif +DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt)) +DEF_RULE_NC(if_stmt_elif_list, one_or_more, rule(if_stmt_elif)) +DEF_RULE_NC(if_stmt_elif, and(4), tok(KW_ELIF), rule(test), tok(DEL_COLON), rule(suite)) +DEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(test), tok(DEL_COLON), rule(suite), opt_rule(else_stmt)) +DEF_RULE(for_stmt, c(for_stmt), and(7), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(testlist), tok(DEL_COLON), rule(suite), opt_rule(else_stmt)) +DEF_RULE(try_stmt, c(try_stmt), and(4), tok(KW_TRY), tok(DEL_COLON), rule(suite), rule(try_stmt_2)) +DEF_RULE_NC(try_stmt_2, or(2), rule(try_stmt_except_and_more), rule(try_stmt_finally)) +DEF_RULE_NC(try_stmt_except_and_more, and_ident(3), rule(try_stmt_except_list), opt_rule(else_stmt), opt_rule(try_stmt_finally)) +DEF_RULE_NC(try_stmt_except, and(4), tok(KW_EXCEPT), opt_rule(try_stmt_as_name), tok(DEL_COLON), rule(suite)) +DEF_RULE_NC(try_stmt_as_name, and_ident(2), rule(test), opt_rule(as_name)) +DEF_RULE_NC(try_stmt_except_list, one_or_more, rule(try_stmt_except)) +DEF_RULE_NC(try_stmt_finally, and(3), tok(KW_FINALLY), tok(DEL_COLON), rule(suite)) +DEF_RULE_NC(else_stmt, and_ident(3), tok(KW_ELSE), tok(DEL_COLON), rule(suite)) +DEF_RULE(with_stmt, c(with_stmt), and(4), tok(KW_WITH), rule(with_stmt_list), tok(DEL_COLON), rule(suite)) +DEF_RULE_NC(with_stmt_list, list, rule(with_item), tok(DEL_COMMA)) +DEF_RULE_NC(with_item, and_ident(2), rule(test), opt_rule(with_item_as)) +DEF_RULE_NC(with_item_as, and_ident(2), tok(KW_AS), rule(expr)) +DEF_RULE_NC(suite, or(2), rule(suite_block), rule(simple_stmt)) +DEF_RULE_NC(suite_block, and_ident(4), tok(NEWLINE), tok(INDENT), rule(suite_block_stmts), tok(DEDENT)) +DEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt)) + +// test: or_test ['if' or_test 'else' test] | lambdef +// test_nocond: or_test | lambdef_nocond +// lambdef: 'lambda' [varargslist] ':' test +// lambdef_nocond: 'lambda' [varargslist] ':' test_nocond + +DEF_RULE_NC(test, or(2), rule(lambdef), rule(test_if_expr)) +DEF_RULE(test_if_expr, c(test_if_expr), and_ident(2), rule(or_test), opt_rule(test_if_else)) +DEF_RULE_NC(test_if_else, and(4), tok(KW_IF), rule(or_test), tok(KW_ELSE), rule(test)) +DEF_RULE_NC(test_nocond, or(2), rule(lambdef_nocond), rule(or_test)) +DEF_RULE(lambdef, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test)) +DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(varargslist), tok(DEL_COLON), rule(test_nocond)) + +// or_test: and_test ('or' and_test)* +// and_test: not_test ('and' not_test)* +// not_test: 'not' not_test | comparison +// comparison: expr (comp_op expr)* +// comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not' +// star_expr: '*' expr +// expr: xor_expr ('|' xor_expr)* +// xor_expr: and_expr ('^' and_expr)* +// and_expr: shift_expr ('&' shift_expr)* +// shift_expr: arith_expr (('<<'|'>>') arith_expr)* +// arith_expr: term (('+'|'-') term)* +// term: factor (('*'|'/'|'%'|'//') factor)* +// factor: ('+'|'-'|'~') factor | power +// power: atom_expr ['**' factor] +// atom_expr: 'await' atom trailer* | atom trailer* + +DEF_RULE(or_test, c(or_and_test), list, rule(and_test), tok(KW_OR)) +DEF_RULE(and_test, c(or_and_test), list, rule(not_test), tok(KW_AND)) +DEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison)) +DEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test)) +DEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op)) +DEF_RULE_NC(comp_op, or(9), tok(OP_LESS), tok(OP_MORE), tok(OP_DBL_EQUAL), tok(OP_LESS_EQUAL), tok(OP_MORE_EQUAL), tok(OP_NOT_EQUAL), tok(KW_IN), rule(comp_op_not_in), rule(comp_op_is)) +DEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN)) +DEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not)) +DEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT)) +DEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr)) +DEF_RULE(expr, c(binary_op), list, rule(xor_expr), tok(OP_PIPE)) +DEF_RULE(xor_expr, c(binary_op), list, rule(and_expr), tok(OP_CARET)) +DEF_RULE(and_expr, c(binary_op), list, rule(shift_expr), tok(OP_AMPERSAND)) +DEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op)) +DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE)) +DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op)) +DEF_RULE_NC(arith_op, or(2), tok(OP_PLUS), tok(OP_MINUS)) +DEF_RULE(term, c(term), list, rule(factor), rule(term_op)) +DEF_RULE_NC(term_op, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH)) +DEF_RULE_NC(factor, or(2), rule(factor_2), rule(power)) +DEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor)) +DEF_RULE_NC(factor_op, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE)) +DEF_RULE(power, c(power), and_ident(2), rule(atom_expr), opt_rule(power_dbl_star)) +#if MICROPY_PY_ASYNC_AWAIT +DEF_RULE_NC(atom_expr, or(2), rule(atom_expr_await), rule(atom_expr_normal)) +DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom), opt_rule(atom_expr_trailers)) +#else +DEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal)) +#endif +DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers)) +DEF_RULE_NC(atom_expr_trailers, one_or_more, rule(trailer)) +DEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor)) + +// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' +// testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) +// trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + +DEF_RULE_NC(atom, or(12), tok(NAME), tok(INTEGER), tok(FLOAT_OR_IMAG), tok(STRING), tok(BYTES), tok(ELLIPSIS), tok(KW_NONE), tok(KW_TRUE), tok(KW_FALSE), rule(atom_paren), rule(atom_bracket), rule(atom_brace)) +DEF_RULE(atom_paren, c(atom_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(atom_2b), tok(DEL_PAREN_CLOSE)) +DEF_RULE_NC(atom_2b, or(2), rule(yield_expr), rule(testlist_comp)) +DEF_RULE(atom_bracket, c(atom_bracket), and(3), tok(DEL_BRACKET_OPEN), opt_rule(testlist_comp), tok(DEL_BRACKET_CLOSE)) +DEF_RULE(atom_brace, c(atom_brace), and(3), tok(DEL_BRACE_OPEN), opt_rule(dictorsetmaker), tok(DEL_BRACE_CLOSE)) +DEF_RULE_NC(testlist_comp, and_ident(2), rule(testlist_comp_2), opt_rule(testlist_comp_3)) +DEF_RULE_NC(testlist_comp_2, or(2), rule(star_expr), rule(test)) +DEF_RULE_NC(testlist_comp_3, or(2), rule(comp_for), rule(testlist_comp_3b)) +DEF_RULE_NC(testlist_comp_3b, and_ident(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c)) +DEF_RULE_NC(testlist_comp_3c, list_with_end, rule(testlist_comp_2), tok(DEL_COMMA)) +DEF_RULE_NC(trailer, or(3), rule(trailer_paren), rule(trailer_bracket), rule(trailer_period)) +DEF_RULE(trailer_paren, c(trailer_paren), and(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE)) +DEF_RULE(trailer_bracket, c(trailer_bracket), and(3), tok(DEL_BRACKET_OPEN), rule(subscriptlist), tok(DEL_BRACKET_CLOSE)) +DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME)) + +// subscriptlist: subscript (',' subscript)* [','] +// subscript: test | [test] ':' [test] [sliceop] +// sliceop: ':' [test] + +#if MICROPY_PY_BUILTINS_SLICE +DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA)) +DEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2)) +DEF_RULE(subscript_2, c(subscript), and_ident(2), rule(test), opt_rule(subscript_3)) +DEF_RULE(subscript_3, c(subscript), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) +DEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d)) +DEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test)) +DEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop)) +DEF_RULE_NC(sliceop, and(2), tok(DEL_COLON), opt_rule(test)) +#else +DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA)) +#endif + +// exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] +// testlist: test (',' test)* [','] +// dictorsetmaker: (test ':' test (comp_for | (',' test ':' test)* [','])) | (test (comp_for | (',' test)* [','])) + +DEF_RULE_NC(exprlist, list_with_end, rule(exprlist_2), tok(DEL_COMMA)) +DEF_RULE_NC(exprlist_2, or(2), rule(star_expr), rule(expr)) +DEF_RULE(testlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA)) +// TODO dictorsetmaker lets through more than is allowed +DEF_RULE_NC(dictorsetmaker, and_ident(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail)) +#if MICROPY_PY_BUILTINS_SET +DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(dictorsetmaker_colon)) +DEF_RULE_NC(dictorsetmaker_colon, and_ident(2), tok(DEL_COLON), rule(test)) +#else +DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(3), rule(test), tok(DEL_COLON), rule(test)) +#endif +DEF_RULE_NC(dictorsetmaker_tail, or(2), rule(comp_for), rule(dictorsetmaker_list)) +DEF_RULE_NC(dictorsetmaker_list, and(2), tok(DEL_COMMA), opt_rule(dictorsetmaker_list2)) +DEF_RULE_NC(dictorsetmaker_list2, list_with_end, rule(dictorsetmaker_item), tok(DEL_COMMA)) + +// classdef: 'class' NAME ['(' [arglist] ')'] ':' suite + +DEF_RULE(classdef, c(classdef), and_blank(5), tok(KW_CLASS), tok(NAME), opt_rule(classdef_2), tok(DEL_COLON), rule(suite)) +DEF_RULE_NC(classdef_2, and_ident(3), tok(DEL_PAREN_OPEN), opt_rule(arglist), tok(DEL_PAREN_CLOSE)) + +// arglist: (argument ',')* (argument [','] | '*' test (',' argument)* [',' '**' test] | '**' test) + +// TODO arglist lets through more than is allowed, compiler needs to do further verification +DEF_RULE_NC(arglist, list_with_end, rule(arglist_2), tok(DEL_COMMA)) +DEF_RULE_NC(arglist_2, or(3), rule(arglist_star), rule(arglist_dbl_star), rule(argument)) +DEF_RULE_NC(arglist_star, and(2), tok(OP_STAR), rule(test)) +DEF_RULE_NC(arglist_dbl_star, and(2), tok(OP_DBL_STAR), rule(test)) + +// # The reason that keywords are test nodes instead of NAME is that using NAME +// # results in an ambiguity. ast.c makes sure it's a NAME. +// argument: test [comp_for] | test '=' test # Really [keyword '='] test +// comp_iter: comp_for | comp_if +// comp_for: 'for' exprlist 'in' or_test [comp_iter] +// comp_if: 'if' test_nocond [comp_iter] + +DEF_RULE_NC(argument, and_ident(2), rule(test), opt_rule(argument_2)) +DEF_RULE_NC(argument_2, or(2), rule(comp_for), rule(argument_3)) +DEF_RULE_NC(argument_3, and_ident(2), tok(DEL_EQUAL), rule(test)) +DEF_RULE_NC(comp_iter, or(2), rule(comp_for), rule(comp_if)) +DEF_RULE_NC(comp_for, and_blank(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter)) +DEF_RULE_NC(comp_if, and(3), tok(KW_IF), rule(test_nocond), opt_rule(comp_iter)) + +// # not used in grammar, but may appear in "node" passed from Parser to Compiler +// encoding_decl: NAME + +// yield_expr: 'yield' [yield_arg] +// yield_arg: 'from' test | testlist + +DEF_RULE(yield_expr, c(yield_expr), and(2), tok(KW_YIELD), opt_rule(yield_arg)) +DEF_RULE_NC(yield_arg, or(2), rule(yield_arg_from), rule(testlist)) +DEF_RULE_NC(yield_arg_from, and(2), tok(KW_FROM), rule(test)) diff --git a/src/openmv/src/micropython/py/lexer.c b/src/openmv/src/micropython/py/lexer.c new file mode 100755 index 0000000..e161700 --- /dev/null +++ b/src/openmv/src/micropython/py/lexer.c @@ -0,0 +1,764 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/reader.h" +#include "py/lexer.h" +#include "py/runtime.h" + +#if MICROPY_ENABLE_COMPILER + +#define TAB_SIZE (8) + +// TODO seems that CPython allows NULL byte in the input stream +// don't know if that's intentional or not, but we don't allow it + +#define MP_LEXER_EOF ((unichar)MP_READER_EOF) +#define CUR_CHAR(lex) ((lex)->chr0) + +STATIC bool is_end(mp_lexer_t *lex) { + return lex->chr0 == MP_LEXER_EOF; +} + +STATIC bool is_physical_newline(mp_lexer_t *lex) { + return lex->chr0 == '\n'; +} + +STATIC bool is_char(mp_lexer_t *lex, byte c) { + return lex->chr0 == c; +} + +STATIC bool is_char_or(mp_lexer_t *lex, byte c1, byte c2) { + return lex->chr0 == c1 || lex->chr0 == c2; +} + +STATIC bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) { + return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3; +} + +STATIC bool is_char_following(mp_lexer_t *lex, byte c) { + return lex->chr1 == c; +} + +STATIC bool is_char_following_or(mp_lexer_t *lex, byte c1, byte c2) { + return lex->chr1 == c1 || lex->chr1 == c2; +} + +STATIC bool is_char_following_following_or(mp_lexer_t *lex, byte c1, byte c2) { + return lex->chr2 == c1 || lex->chr2 == c2; +} + +STATIC bool is_char_and(mp_lexer_t *lex, byte c1, byte c2) { + return lex->chr0 == c1 && lex->chr1 == c2; +} + +STATIC bool is_whitespace(mp_lexer_t *lex) { + return unichar_isspace(lex->chr0); +} + +STATIC bool is_letter(mp_lexer_t *lex) { + return unichar_isalpha(lex->chr0); +} + +STATIC bool is_digit(mp_lexer_t *lex) { + return unichar_isdigit(lex->chr0); +} + +STATIC bool is_following_digit(mp_lexer_t *lex) { + return unichar_isdigit(lex->chr1); +} + +STATIC bool is_following_base_char(mp_lexer_t *lex) { + const unichar chr1 = lex->chr1 | 0x20; + return chr1 == 'b' || chr1 == 'o' || chr1 == 'x'; +} + +STATIC bool is_following_odigit(mp_lexer_t *lex) { + return lex->chr1 >= '0' && lex->chr1 <= '7'; +} + +STATIC bool is_string_or_bytes(mp_lexer_t *lex) { + return is_char_or(lex, '\'', '\"') + || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"')) + || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r')) + && is_char_following_following_or(lex, '\'', '\"')); +} + +// to easily parse utf-8 identifiers we allow any raw byte with high bit set +STATIC bool is_head_of_identifier(mp_lexer_t *lex) { + return is_letter(lex) || lex->chr0 == '_' || lex->chr0 >= 0x80; +} + +STATIC bool is_tail_of_identifier(mp_lexer_t *lex) { + return is_head_of_identifier(lex) || is_digit(lex); +} + +STATIC void next_char(mp_lexer_t *lex) { + if (lex->chr0 == '\n') { + // a new line + ++lex->line; + lex->column = 1; + } else if (lex->chr0 == '\t') { + // a tab + lex->column = (((lex->column - 1 + TAB_SIZE) / TAB_SIZE) * TAB_SIZE) + 1; + } else { + // a character worth one column + ++lex->column; + } + + lex->chr0 = lex->chr1; + lex->chr1 = lex->chr2; + lex->chr2 = lex->reader.readbyte(lex->reader.data); + + if (lex->chr1 == '\r') { + // CR is a new line, converted to LF + lex->chr1 = '\n'; + if (lex->chr2 == '\n') { + // CR LF is a single new line, throw out the extra LF + lex->chr2 = lex->reader.readbyte(lex->reader.data); + } + } + + // check if we need to insert a newline at end of file + if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') { + lex->chr2 = '\n'; + } +} + +STATIC void indent_push(mp_lexer_t *lex, size_t indent) { + if (lex->num_indent_level >= lex->alloc_indent_level) { + lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC); + lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC; + } + lex->indent_level[lex->num_indent_level++] = indent; +} + +STATIC size_t indent_top(mp_lexer_t *lex) { + return lex->indent_level[lex->num_indent_level - 1]; +} + +STATIC void indent_pop(mp_lexer_t *lex) { + lex->num_indent_level -= 1; +} + +// some tricky operator encoding: +// = begin with , if this opchar matches then begin here +// e = end with , if this opchar matches then end +// c = continue with , if this opchar matches then continue matching +// this means if the start of two ops are the same then they are equal til the last char + +STATIC const char *const tok_enc = + "()[]{},:;@~" // singles + "e=c>e=" // > >= >> >>= + "*e=c*e=" // * *= ** **= + "+e=" // + += + "-e=e>" // - -= -> + "&e=" // & &= + "|e=" // | |= + "/e=c/e=" // / /= // //= + "%e=" // % %= + "^e=" // ^ ^= + "=e=" // = == + "!."; // start of special cases: != . ... + +// TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries +STATIC const uint8_t tok_enc_kind[] = { + MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, + MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, + MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE, + MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_AT, MP_TOKEN_OP_TILDE, + + MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL, + MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL, + MP_TOKEN_OP_STAR, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_DEL_DBL_STAR_EQUAL, + MP_TOKEN_OP_PLUS, MP_TOKEN_DEL_PLUS_EQUAL, + MP_TOKEN_OP_MINUS, MP_TOKEN_DEL_MINUS_EQUAL, MP_TOKEN_DEL_MINUS_MORE, + MP_TOKEN_OP_AMPERSAND, MP_TOKEN_DEL_AMPERSAND_EQUAL, + MP_TOKEN_OP_PIPE, MP_TOKEN_DEL_PIPE_EQUAL, + MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL, + MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL, + MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL, + MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL, +}; + +// must have the same order as enum in lexer.h +// must be sorted according to strcmp +STATIC const char *const tok_kw[] = { + "False", + "None", + "True", + "__debug__", + "and", + "as", + "assert", + #if MICROPY_PY_ASYNC_AWAIT + "async", + "await", + #endif + "break", + "class", + "continue", + "def", + "del", + "elif", + "else", + "except", + "finally", + "for", + "from", + "global", + "if", + "import", + "in", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", +}; + +// This is called with CUR_CHAR() before first hex digit, and should return with +// it pointing to last hex digit +// num_digits must be greater than zero +STATIC bool get_hex(mp_lexer_t *lex, size_t num_digits, mp_uint_t *result) { + mp_uint_t num = 0; + while (num_digits-- != 0) { + next_char(lex); + unichar c = CUR_CHAR(lex); + if (!unichar_isxdigit(c)) { + return false; + } + num = (num << 4) + unichar_xdigit_value(c); + } + *result = num; + return true; +} + +STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) { + // get first quoting character + char quote_char = '\''; + if (is_char(lex, '\"')) { + quote_char = '\"'; + } + next_char(lex); + + // work out if it's a single or triple quoted literal + size_t num_quotes; + if (is_char_and(lex, quote_char, quote_char)) { + // triple quotes + next_char(lex); + next_char(lex); + num_quotes = 3; + } else { + // single quotes + num_quotes = 1; + } + + size_t n_closing = 0; + while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) { + if (is_char(lex, quote_char)) { + n_closing += 1; + vstr_add_char(&lex->vstr, CUR_CHAR(lex)); + } else { + n_closing = 0; + if (is_char(lex, '\\')) { + next_char(lex); + unichar c = CUR_CHAR(lex); + if (is_raw) { + // raw strings allow escaping of quotes, but the backslash is also emitted + vstr_add_char(&lex->vstr, '\\'); + } else { + switch (c) { + // note: "c" can never be MP_LEXER_EOF because next_char + // always inserts a newline at the end of the input stream + case '\n': c = MP_LEXER_EOF; break; // backslash escape the newline, just ignore it + case '\\': break; + case '\'': break; + case '"': break; + case 'a': c = 0x07; break; + case 'b': c = 0x08; break; + case 't': c = 0x09; break; + case 'n': c = 0x0a; break; + case 'v': c = 0x0b; break; + case 'f': c = 0x0c; break; + case 'r': c = 0x0d; break; + case 'u': + case 'U': + if (lex->tok_kind == MP_TOKEN_BYTES) { + // b'\u1234' == b'\\u1234' + vstr_add_char(&lex->vstr, '\\'); + break; + } + // Otherwise fall through. + case 'x': + { + mp_uint_t num = 0; + if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) { + // not enough hex chars for escape sequence + lex->tok_kind = MP_TOKEN_INVALID; + } + c = num; + break; + } + case 'N': + // Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the + // entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly + // 3MB of text; even gzip-compressed and with minimal structure, it'll take + // roughly half a meg of storage. This form of Unicode escape may be added + // later on, but it's definitely not a priority right now. -- CJA 20140607 + mp_raise_NotImplementedError("unicode name escapes"); + break; + default: + if (c >= '0' && c <= '7') { + // Octal sequence, 1-3 chars + size_t digits = 3; + mp_uint_t num = c - '0'; + while (is_following_odigit(lex) && --digits != 0) { + next_char(lex); + num = num * 8 + (CUR_CHAR(lex) - '0'); + } + c = num; + } else { + // unrecognised escape character; CPython lets this through verbatim as '\' and then the character + vstr_add_char(&lex->vstr, '\\'); + } + break; + } + } + if (c != MP_LEXER_EOF) { + if (MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) { + if (c < 0x110000 && lex->tok_kind == MP_TOKEN_STRING) { + vstr_add_char(&lex->vstr, c); + } else if (c < 0x100 && lex->tok_kind == MP_TOKEN_BYTES) { + vstr_add_byte(&lex->vstr, c); + } else { + // unicode character out of range + // this raises a generic SyntaxError; could provide more info + lex->tok_kind = MP_TOKEN_INVALID; + } + } else { + // without unicode everything is just added as an 8-bit byte + if (c < 0x100) { + vstr_add_byte(&lex->vstr, c); + } else { + // 8-bit character out of range + // this raises a generic SyntaxError; could provide more info + lex->tok_kind = MP_TOKEN_INVALID; + } + } + } + } else { + // Add the "character" as a byte so that we remain 8-bit clean. + // This way, strings are parsed correctly whether or not they contain utf-8 chars. + vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + } + } + next_char(lex); + } + + // check we got the required end quotes + if (n_closing < num_quotes) { + lex->tok_kind = MP_TOKEN_LONELY_STRING_OPEN; + } + + // cut off the end quotes from the token text + vstr_cut_tail_bytes(&lex->vstr, n_closing); +} + +STATIC bool skip_whitespace(mp_lexer_t *lex, bool stop_at_newline) { + bool had_physical_newline = false; + while (!is_end(lex)) { + if (is_physical_newline(lex)) { + if (stop_at_newline && lex->nested_bracket_level == 0) { + break; + } + had_physical_newline = true; + next_char(lex); + } else if (is_whitespace(lex)) { + next_char(lex); + } else if (is_char(lex, '#')) { + next_char(lex); + while (!is_end(lex) && !is_physical_newline(lex)) { + next_char(lex); + } + // had_physical_newline will be set on next loop + } else if (is_char_and(lex, '\\', '\n')) { + // line-continuation, so don't set had_physical_newline + next_char(lex); + next_char(lex); + } else { + break; + } + } + return had_physical_newline; +} + +void mp_lexer_to_next(mp_lexer_t *lex) { + // start new token text + vstr_reset(&lex->vstr); + + // skip white space and comments + bool had_physical_newline = skip_whitespace(lex, false); + + // set token source information + lex->tok_line = lex->line; + lex->tok_column = lex->column; + + if (lex->emit_dent < 0) { + lex->tok_kind = MP_TOKEN_DEDENT; + lex->emit_dent += 1; + + } else if (lex->emit_dent > 0) { + lex->tok_kind = MP_TOKEN_INDENT; + lex->emit_dent -= 1; + + } else if (had_physical_newline && lex->nested_bracket_level == 0) { + lex->tok_kind = MP_TOKEN_NEWLINE; + + size_t num_spaces = lex->column - 1; + if (num_spaces == indent_top(lex)) { + } else if (num_spaces > indent_top(lex)) { + indent_push(lex, num_spaces); + lex->emit_dent += 1; + } else { + while (num_spaces < indent_top(lex)) { + indent_pop(lex); + lex->emit_dent -= 1; + } + if (num_spaces != indent_top(lex)) { + lex->tok_kind = MP_TOKEN_DEDENT_MISMATCH; + } + } + + } else if (is_end(lex)) { + lex->tok_kind = MP_TOKEN_END; + + } else if (is_string_or_bytes(lex)) { + // a string or bytes literal + + // Python requires adjacent string/bytes literals to be automatically + // concatenated. We do it here in the tokeniser to make efficient use of RAM, + // because then the lexer's vstr can be used to accumulate the string literal, + // in contrast to creating a parse tree of strings and then joining them later + // in the compiler. It's also more compact in code size to do it here. + + // MP_TOKEN_END is used to indicate that this is the first string token + lex->tok_kind = MP_TOKEN_END; + + // Loop to accumulate string/bytes literals + do { + // parse type codes + bool is_raw = false; + mp_token_kind_t kind = MP_TOKEN_STRING; + int n_char = 0; + if (is_char(lex, 'u')) { + n_char = 1; + } else if (is_char(lex, 'b')) { + kind = MP_TOKEN_BYTES; + n_char = 1; + if (is_char_following(lex, 'r')) { + is_raw = true; + n_char = 2; + } + } else if (is_char(lex, 'r')) { + is_raw = true; + n_char = 1; + if (is_char_following(lex, 'b')) { + kind = MP_TOKEN_BYTES; + n_char = 2; + } + } + + // Set or check token kind + if (lex->tok_kind == MP_TOKEN_END) { + lex->tok_kind = kind; + } else if (lex->tok_kind != kind) { + // Can't concatenate string with bytes + break; + } + + // Skip any type code characters + if (n_char != 0) { + next_char(lex); + if (n_char == 2) { + next_char(lex); + } + } + + // Parse the literal + parse_string_literal(lex, is_raw); + + // Skip whitespace so we can check if there's another string following + skip_whitespace(lex, true); + + } while (is_string_or_bytes(lex)); + + } else if (is_head_of_identifier(lex)) { + lex->tok_kind = MP_TOKEN_NAME; + + // get first char (add as byte to remain 8-bit clean and support utf-8) + vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + next_char(lex); + + // get tail chars + while (!is_end(lex) && is_tail_of_identifier(lex)) { + vstr_add_byte(&lex->vstr, CUR_CHAR(lex)); + next_char(lex); + } + + // Check if the name is a keyword. + // We also check for __debug__ here and convert it to its value. This is + // so the parser gives a syntax error on, eg, x.__debug__. Otherwise, we + // need to check for this special token in many places in the compiler. + const char *s = vstr_null_terminated_str(&lex->vstr); + for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) { + int cmp = strcmp(s, tok_kw[i]); + if (cmp == 0) { + lex->tok_kind = MP_TOKEN_KW_FALSE + i; + if (lex->tok_kind == MP_TOKEN_KW___DEBUG__) { + lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE); + } + break; + } else if (cmp < 0) { + // Table is sorted and comparison was less-than, so stop searching + break; + } + } + + } else if (is_digit(lex) || (is_char(lex, '.') && is_following_digit(lex))) { + bool forced_integer = false; + if (is_char(lex, '.')) { + lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; + } else { + lex->tok_kind = MP_TOKEN_INTEGER; + if (is_char(lex, '0') && is_following_base_char(lex)) { + forced_integer = true; + } + } + + // get first char + vstr_add_char(&lex->vstr, CUR_CHAR(lex)); + next_char(lex); + + // get tail chars + while (!is_end(lex)) { + if (!forced_integer && is_char_or(lex, 'e', 'E')) { + lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; + vstr_add_char(&lex->vstr, 'e'); + next_char(lex); + if (is_char(lex, '+') || is_char(lex, '-')) { + vstr_add_char(&lex->vstr, CUR_CHAR(lex)); + next_char(lex); + } + } else if (is_letter(lex) || is_digit(lex) || is_char(lex, '.')) { + if (is_char_or3(lex, '.', 'j', 'J')) { + lex->tok_kind = MP_TOKEN_FLOAT_OR_IMAG; + } + vstr_add_char(&lex->vstr, CUR_CHAR(lex)); + next_char(lex); + } else if (is_char(lex, '_')) { + next_char(lex); + } else { + break; + } + } + + } else { + // search for encoded delimiter or operator + + const char *t = tok_enc; + size_t tok_enc_index = 0; + for (; *t != 0 && !is_char(lex, *t); t += 1) { + if (*t == 'e' || *t == 'c') { + t += 1; + } + tok_enc_index += 1; + } + + next_char(lex); + + if (*t == 0) { + // didn't match any delimiter or operator characters + lex->tok_kind = MP_TOKEN_INVALID; + + } else if (*t == '!') { + // "!=" is a special case because "!" is not a valid operator + if (is_char(lex, '=')) { + next_char(lex); + lex->tok_kind = MP_TOKEN_OP_NOT_EQUAL; + } else { + lex->tok_kind = MP_TOKEN_INVALID; + } + + } else if (*t == '.') { + // "." and "..." are special cases because ".." is not a valid operator + if (is_char_and(lex, '.', '.')) { + next_char(lex); + next_char(lex); + lex->tok_kind = MP_TOKEN_ELLIPSIS; + } else { + lex->tok_kind = MP_TOKEN_DEL_PERIOD; + } + + } else { + // matched a delimiter or operator character + + // get the maximum characters for a valid token + t += 1; + size_t t_index = tok_enc_index; + while (*t == 'c' || *t == 'e') { + t_index += 1; + if (is_char(lex, t[1])) { + next_char(lex); + tok_enc_index = t_index; + if (*t == 'e') { + break; + } + } else if (*t == 'c') { + break; + } + t += 2; + } + + // set token kind + lex->tok_kind = tok_enc_kind[tok_enc_index]; + + // compute bracket level for implicit line joining + if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACKET_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACE_OPEN) { + lex->nested_bracket_level += 1; + } else if (lex->tok_kind == MP_TOKEN_DEL_PAREN_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACKET_CLOSE || lex->tok_kind == MP_TOKEN_DEL_BRACE_CLOSE) { + lex->nested_bracket_level -= 1; + } + } + } +} + +mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) { + mp_lexer_t *lex = m_new_obj(mp_lexer_t); + + lex->source_name = src_name; + lex->reader = reader; + lex->line = 1; + lex->column = (size_t)-2; // account for 3 dummy bytes + lex->emit_dent = 0; + lex->nested_bracket_level = 0; + lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT; + lex->num_indent_level = 1; + lex->indent_level = m_new(uint16_t, lex->alloc_indent_level); + vstr_init(&lex->vstr, 32); + + // store sentinel for first indentation level + lex->indent_level[0] = 0; + + // load lexer with start of file, advancing lex->column to 1 + // start with dummy bytes and use next_char() for proper EOL/EOF handling + lex->chr0 = lex->chr1 = lex->chr2 = 0; + next_char(lex); + next_char(lex); + next_char(lex); + + // preload first token + mp_lexer_to_next(lex); + + // Check that the first token is in the first column. If it's not then we + // convert the token kind to INDENT so that the parser gives a syntax error. + if (lex->tok_column != 1) { + lex->tok_kind = MP_TOKEN_INDENT; + } + + return lex; +} + +mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len) { + mp_reader_t reader; + mp_reader_new_mem(&reader, (const byte*)str, len, free_len); + return mp_lexer_new(src_name, reader); +} + +#if MICROPY_READER_POSIX || MICROPY_READER_VFS + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_reader_t reader; + mp_reader_new_file(&reader, filename); + return mp_lexer_new(qstr_from_str(filename), reader); +} + +#if MICROPY_HELPER_LEXER_UNIX + +mp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd) { + mp_reader_t reader; + mp_reader_new_file_from_fd(&reader, fd, close_fd); + return mp_lexer_new(filename, reader); +} + +#endif + +#endif + +void mp_lexer_free(mp_lexer_t *lex) { + if (lex) { + lex->reader.close(lex->reader.data); + vstr_clear(&lex->vstr); + m_del(uint16_t, lex->indent_level, lex->alloc_indent_level); + m_del_obj(mp_lexer_t, lex); + } +} + +#if 0 +// This function is used to print the current token and should only be +// needed to debug the lexer, so it's not available via a config option. +void mp_lexer_show_token(const mp_lexer_t *lex) { + printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:%zu", lex->tok_line, lex->tok_column, lex->tok_kind, lex->vstr.buf, lex->vstr.len); + if (lex->vstr.len > 0) { + const byte *i = (const byte *)lex->vstr.buf; + const byte *j = (const byte *)i + lex->vstr.len; + printf(" "); + while (i < j) { + unichar c = utf8_get_char(i); + i = utf8_next_char(i); + if (unichar_isprint(c)) { + printf("%c", (int)c); + } else { + printf("?"); + } + } + } + printf("\n"); +} +#endif + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/lexer.h b/src/openmv/src/micropython/py/lexer.h new file mode 100755 index 0000000..a297091 --- /dev/null +++ b/src/openmv/src/micropython/py/lexer.h @@ -0,0 +1,195 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_LEXER_H +#define MICROPY_INCLUDED_PY_LEXER_H + +#include + +#include "py/mpconfig.h" +#include "py/qstr.h" +#include "py/reader.h" + +/* lexer.h -- simple tokeniser for MicroPython + * + * Uses (byte) length instead of null termination. + * Tokens are the same - UTF-8 with (byte) length. + */ + +typedef enum _mp_token_kind_t { + MP_TOKEN_END, + + MP_TOKEN_INVALID, + MP_TOKEN_DEDENT_MISMATCH, + MP_TOKEN_LONELY_STRING_OPEN, + + MP_TOKEN_NEWLINE, + MP_TOKEN_INDENT, + MP_TOKEN_DEDENT, + + MP_TOKEN_NAME, + MP_TOKEN_INTEGER, + MP_TOKEN_FLOAT_OR_IMAG, + MP_TOKEN_STRING, + MP_TOKEN_BYTES, + + MP_TOKEN_ELLIPSIS, + + MP_TOKEN_KW_FALSE, + MP_TOKEN_KW_NONE, + MP_TOKEN_KW_TRUE, + MP_TOKEN_KW___DEBUG__, + MP_TOKEN_KW_AND, + MP_TOKEN_KW_AS, + MP_TOKEN_KW_ASSERT, + #if MICROPY_PY_ASYNC_AWAIT + MP_TOKEN_KW_ASYNC, + MP_TOKEN_KW_AWAIT, + #endif + MP_TOKEN_KW_BREAK, + MP_TOKEN_KW_CLASS, + MP_TOKEN_KW_CONTINUE, + MP_TOKEN_KW_DEF, + MP_TOKEN_KW_DEL, + MP_TOKEN_KW_ELIF, + MP_TOKEN_KW_ELSE, + MP_TOKEN_KW_EXCEPT, + MP_TOKEN_KW_FINALLY, + MP_TOKEN_KW_FOR, + MP_TOKEN_KW_FROM, + MP_TOKEN_KW_GLOBAL, + MP_TOKEN_KW_IF, + MP_TOKEN_KW_IMPORT, + MP_TOKEN_KW_IN, + MP_TOKEN_KW_IS, + MP_TOKEN_KW_LAMBDA, + MP_TOKEN_KW_NONLOCAL, + MP_TOKEN_KW_NOT, + MP_TOKEN_KW_OR, + MP_TOKEN_KW_PASS, + MP_TOKEN_KW_RAISE, + MP_TOKEN_KW_RETURN, + MP_TOKEN_KW_TRY, + MP_TOKEN_KW_WHILE, + MP_TOKEN_KW_WITH, + MP_TOKEN_KW_YIELD, + + MP_TOKEN_OP_PLUS, + MP_TOKEN_OP_MINUS, + MP_TOKEN_OP_STAR, + MP_TOKEN_OP_DBL_STAR, + MP_TOKEN_OP_SLASH, + MP_TOKEN_OP_DBL_SLASH, + MP_TOKEN_OP_PERCENT, + MP_TOKEN_OP_LESS, + MP_TOKEN_OP_DBL_LESS, + MP_TOKEN_OP_MORE, + MP_TOKEN_OP_DBL_MORE, + MP_TOKEN_OP_AMPERSAND, + MP_TOKEN_OP_PIPE, + MP_TOKEN_OP_CARET, + MP_TOKEN_OP_TILDE, + MP_TOKEN_OP_LESS_EQUAL, + MP_TOKEN_OP_MORE_EQUAL, + MP_TOKEN_OP_DBL_EQUAL, + MP_TOKEN_OP_NOT_EQUAL, + + MP_TOKEN_DEL_PAREN_OPEN, + MP_TOKEN_DEL_PAREN_CLOSE, + MP_TOKEN_DEL_BRACKET_OPEN, + MP_TOKEN_DEL_BRACKET_CLOSE, + MP_TOKEN_DEL_BRACE_OPEN, + MP_TOKEN_DEL_BRACE_CLOSE, + MP_TOKEN_DEL_COMMA, + MP_TOKEN_DEL_COLON, + MP_TOKEN_DEL_PERIOD, + MP_TOKEN_DEL_SEMICOLON, + MP_TOKEN_DEL_AT, + MP_TOKEN_DEL_EQUAL, + MP_TOKEN_DEL_PLUS_EQUAL, + MP_TOKEN_DEL_MINUS_EQUAL, + MP_TOKEN_DEL_STAR_EQUAL, + MP_TOKEN_DEL_SLASH_EQUAL, + MP_TOKEN_DEL_DBL_SLASH_EQUAL, + MP_TOKEN_DEL_PERCENT_EQUAL, + MP_TOKEN_DEL_AMPERSAND_EQUAL, + MP_TOKEN_DEL_PIPE_EQUAL, + MP_TOKEN_DEL_CARET_EQUAL, + MP_TOKEN_DEL_DBL_MORE_EQUAL, + MP_TOKEN_DEL_DBL_LESS_EQUAL, + MP_TOKEN_DEL_DBL_STAR_EQUAL, + MP_TOKEN_DEL_MINUS_MORE, +} mp_token_kind_t; + +// this data structure is exposed for efficiency +// public members are: source_name, tok_line, tok_column, tok_kind, vstr +typedef struct _mp_lexer_t { + qstr source_name; // name of source + mp_reader_t reader; // stream source + + unichar chr0, chr1, chr2; // current cached characters from source + + size_t line; // current source line + size_t column; // current source column + + mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit + mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines + + size_t alloc_indent_level; + size_t num_indent_level; + uint16_t *indent_level; + + size_t tok_line; // token source line + size_t tok_column; // token source column + mp_token_kind_t tok_kind; // token kind + vstr_t vstr; // token data +} mp_lexer_t; + +mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader); +mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len); + +void mp_lexer_free(mp_lexer_t *lex); +void mp_lexer_to_next(mp_lexer_t *lex); + +/******************************************************************/ +// platform specific import function; must be implemented for a specific port +// TODO tidy up, rename, or put elsewhere + +//mp_lexer_t *mp_import_open_file(qstr mod_name); + +typedef enum { + MP_IMPORT_STAT_NO_EXIST, + MP_IMPORT_STAT_DIR, + MP_IMPORT_STAT_FILE, +} mp_import_stat_t; + +mp_import_stat_t mp_import_stat(const char *path); +mp_lexer_t *mp_lexer_new_from_file(const char *filename); + +#if MICROPY_HELPER_LEXER_UNIX +mp_lexer_t *mp_lexer_new_from_fd(qstr filename, int fd, bool close_fd); +#endif + +#endif // MICROPY_INCLUDED_PY_LEXER_H diff --git a/src/openmv/src/micropython/py/makeqstrdata.py b/src/openmv/src/micropython/py/makeqstrdata.py new file mode 100755 index 0000000..3c0a609 --- /dev/null +++ b/src/openmv/src/micropython/py/makeqstrdata.py @@ -0,0 +1,169 @@ +""" +Process raw qstr file and output qstr data with length, hash and data bytes. + +This script works with Python 2.6, 2.7, 3.3 and 3.4. +""" + +from __future__ import print_function + +import re +import sys + +# Python 2/3 compatibility: +# - iterating through bytes is different +# - codepoint2name lives in a different module +import platform +if platform.python_version_tuple()[0] == '2': + bytes_cons = lambda val, enc=None: bytearray(val) + from htmlentitydefs import codepoint2name +elif platform.python_version_tuple()[0] == '3': + bytes_cons = bytes + from html.entities import codepoint2name +# end compatibility code + +codepoint2name[ord('-')] = 'hyphen'; + +# add some custom names to map characters that aren't in HTML +codepoint2name[ord(' ')] = 'space' +codepoint2name[ord('\'')] = 'squot' +codepoint2name[ord(',')] = 'comma' +codepoint2name[ord('.')] = 'dot' +codepoint2name[ord(':')] = 'colon' +codepoint2name[ord(';')] = 'semicolon' +codepoint2name[ord('/')] = 'slash' +codepoint2name[ord('%')] = 'percent' +codepoint2name[ord('#')] = 'hash' +codepoint2name[ord('(')] = 'paren_open' +codepoint2name[ord(')')] = 'paren_close' +codepoint2name[ord('[')] = 'bracket_open' +codepoint2name[ord(']')] = 'bracket_close' +codepoint2name[ord('{')] = 'brace_open' +codepoint2name[ord('}')] = 'brace_close' +codepoint2name[ord('*')] = 'star' +codepoint2name[ord('!')] = 'bang' +codepoint2name[ord('\\')] = 'backslash' +codepoint2name[ord('+')] = 'plus' +codepoint2name[ord('$')] = 'dollar' +codepoint2name[ord('=')] = 'equals' +codepoint2name[ord('?')] = 'question' +codepoint2name[ord('@')] = 'at_sign' +codepoint2name[ord('^')] = 'caret' +codepoint2name[ord('|')] = 'pipe' +codepoint2name[ord('~')] = 'tilde' + +# this must match the equivalent function in qstr.c +def compute_hash(qstr, bytes_hash): + hash = 5381 + for b in qstr: + hash = (hash * 33) ^ b + # Make sure that valid hash is never zero, zero means "hash not computed" + return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1 + +def qstr_escape(qst): + def esc_char(m): + c = ord(m.group(0)) + try: + name = codepoint2name[c] + except KeyError: + name = '0x%02x' % c + return "_" + name + '_' + return re.sub(r'[^A-Za-z0-9_]', esc_char, qst) + +def parse_input_headers(infiles): + # read the qstrs in from the input files + qcfgs = {} + qstrs = {} + for infile in infiles: + with open(infile, 'rt') as f: + for line in f: + line = line.strip() + + # is this a config line? + match = re.match(r'^QCFG\((.+), (.+)\)', line) + if match: + value = match.group(2) + if value[0] == '(' and value[-1] == ')': + # strip parenthesis from config value + value = value[1:-1] + qcfgs[match.group(1)] = value + continue + + # is this a QSTR line? + match = re.match(r'^Q\((.*)\)$', line) + if not match: + continue + + # get the qstr value + qstr = match.group(1) + + # special case to specify control characters + if qstr == '\\n': + qstr = '\n' + + # work out the corresponding qstr name + ident = qstr_escape(qstr) + + # don't add duplicates + if ident in qstrs: + continue + + # add the qstr to the list, with order number to retain original order in file + order = len(qstrs) + # but put special method names like __add__ at the top of list, so + # that their id's fit into a byte + if ident == "": + # Sort empty qstr above all still + order = -200000 + elif ident == "__dir__": + # Put __dir__ after empty qstr for builtin dir() to work + order = -190000 + elif ident.startswith("__"): + order -= 100000 + qstrs[ident] = (order, ident, qstr) + + if not qcfgs: + sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n") + sys.exit(1) + + return qcfgs, qstrs + +def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): + qbytes = bytes_cons(qstr, 'utf8') + qlen = len(qbytes) + qhash = compute_hash(qbytes, cfg_bytes_hash) + if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): + # qstr is all printable ASCII so render it as-is (for easier debugging) + qdata = qstr + else: + # qstr contains non-printable codes so render entire thing as hex pairs + qdata = ''.join(('\\x%02x' % b) for b in qbytes) + if qlen >= (1 << (8 * cfg_bytes_len)): + print('qstr is too long:', qstr) + assert False + qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len)) + qhash_str = ('\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash)) + return '(const byte*)"%s%s" "%s"' % (qhash_str, qlen_str, qdata) + +def print_qstr_data(qcfgs, qstrs): + # get config variables + cfg_bytes_len = int(qcfgs['BYTES_IN_LEN']) + cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH']) + + # print out the starter of the generated C header file + print('// This file was automatically generated by makeqstrdata.py') + print('') + + # add NULL qstr with no hash or data + print('QDEF(MP_QSTR_NULL, (const byte*)"%s%s" "")' % ('\\x00' * cfg_bytes_hash, '\\x00' * cfg_bytes_len)) + + # go through each qstr and print it out + for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]): + qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr) + print('QDEF(MP_QSTR_%s, %s)' % (ident, qbytes)) + +def do_work(infiles): + qcfgs, qstrs = parse_input_headers(infiles) + print_qstr_data(qcfgs, qstrs) + +if __name__ == "__main__": + do_work(sys.argv[1:]) diff --git a/src/openmv/src/micropython/py/makeqstrdata.pyc b/src/openmv/src/micropython/py/makeqstrdata.pyc new file mode 100644 index 0000000..cb4c6c0 Binary files /dev/null and b/src/openmv/src/micropython/py/makeqstrdata.pyc differ diff --git a/src/openmv/src/micropython/py/makeqstrdefs.py b/src/openmv/src/micropython/py/makeqstrdefs.py new file mode 100755 index 0000000..1764401 --- /dev/null +++ b/src/openmv/src/micropython/py/makeqstrdefs.py @@ -0,0 +1,115 @@ +""" +This script processes the output from the C preprocessor and extracts all +qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'. + +This script works with Python 2.6, 2.7, 3.3 and 3.4. +""" + +from __future__ import print_function + +import re +import sys +import os + +# Blacklist of qstrings that are specially handled in further +# processing and should be ignored +QSTRING_BLACK_LIST = set(['NULL', 'number_of']) + + +def write_out(fname, output): + if output: + for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]: + fname = fname.replace(m, r) + with open(args.output_dir + "/" + fname + ".qstr", "w") as f: + f.write("\n".join(output) + "\n") + +def process_file(f): + re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"") + re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+') + output = [] + last_fname = None + for line in f: + if line.isspace(): + continue + # match gcc-like output (# n "file") and msvc-like output (#line n "file") + if line.startswith(('# ', '#line')): + m = re_line.match(line) + assert m is not None + fname = m.group(1) + if not fname.endswith(".c"): + continue + if fname != last_fname: + write_out(last_fname, output) + output = [] + last_fname = fname + continue + for match in re_qstr.findall(line): + name = match.replace('MP_QSTR_', '') + if name not in QSTRING_BLACK_LIST: + output.append('Q(' + name + ')') + + write_out(last_fname, output) + return "" + + +def cat_together(): + import glob + import hashlib + hasher = hashlib.md5() + all_lines = [] + outf = open(args.output_dir + "/out", "wb") + for fname in glob.glob(args.output_dir + "/*.qstr"): + with open(fname, "rb") as f: + lines = f.readlines() + all_lines += lines + all_lines.sort() + all_lines = b"\n".join(all_lines) + outf.write(all_lines) + outf.close() + hasher.update(all_lines) + new_hash = hasher.hexdigest() + #print(new_hash) + old_hash = None + try: + with open(args.output_file + ".hash") as f: + old_hash = f.read() + except IOError: + pass + if old_hash != new_hash: + print("QSTR updated") + try: + # rename below might fail if file exists + os.remove(args.output_file) + except: + pass + os.rename(args.output_dir + "/out", args.output_file) + with open(args.output_file + ".hash", "w") as f: + f.write(new_hash) + else: + print("QSTR not updated") + + +if __name__ == "__main__": + if len(sys.argv) != 5: + print('usage: %s command input_filename output_dir output_file' % sys.argv[0]) + sys.exit(2) + + class Args: + pass + args = Args() + args.command = sys.argv[1] + args.input_filename = sys.argv[2] + args.output_dir = sys.argv[3] + args.output_file = sys.argv[4] + + try: + os.makedirs(args.output_dir) + except OSError: + pass + + if args.command == "split": + with open(args.input_filename) as infile: + process_file(infile) + + if args.command == "cat": + cat_together() diff --git a/src/openmv/src/micropython/py/makeversionhdr.py b/src/openmv/src/micropython/py/makeversionhdr.py new file mode 100755 index 0000000..aedc292 --- /dev/null +++ b/src/openmv/src/micropython/py/makeversionhdr.py @@ -0,0 +1,107 @@ +""" +Generate header file with macros defining MicroPython version info. + +This script works with Python 2.6, 2.7, 3.3 and 3.4. +""" + +from __future__ import print_function + +import sys +import os +import datetime +import subprocess + +def get_version_info_from_git(): + # Python 2.6 doesn't have check_output, so check for that + try: + subprocess.check_output + subprocess.check_call + except AttributeError: + return None + + # Note: git describe doesn't work if no tag is available + try: + git_tag = subprocess.check_output(["git", "describe", "--dirty", "--always"], stderr=subprocess.STDOUT, universal_newlines=True).strip() + except subprocess.CalledProcessError as er: + if er.returncode == 128: + # git exit code of 128 means no repository found + return None + git_tag = "" + except OSError: + return None + try: + git_hash = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], stderr=subprocess.STDOUT, universal_newlines=True).strip() + except subprocess.CalledProcessError: + git_hash = "unknown" + except OSError: + return None + + try: + # Check if there are any modified files. + subprocess.check_call(["git", "diff", "--no-ext-diff", "--quiet", "--exit-code"], stderr=subprocess.STDOUT) + # Check if there are any staged files. + subprocess.check_call(["git", "diff-index", "--cached", "--quiet", "HEAD", "--"], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + git_hash += "-dirty" + except OSError: + return None + + # Try to extract MicroPython version from git tag + if git_tag.startswith("v"): + ver = git_tag[1:].split("-")[0].split(".") + if len(ver) == 2: + ver.append("0") + else: + ver = ["0", "0", "1"] + + return git_tag, git_hash, ver + +def get_version_info_from_docs_conf(): + with open(os.path.join(os.path.dirname(sys.argv[0]), "..", "docs", "conf.py")) as f: + for line in f: + if line.startswith("version = release = '"): + ver = line.strip().split(" = ")[2].strip("'") + git_tag = "v" + ver + ver = ver.split(".") + if len(ver) == 2: + ver.append("0") + return git_tag, "", ver + return None + +def make_version_header(filename): + # Get version info using git, with fallback to docs/conf.py + info = get_version_info_from_git() + if info is None: + info = get_version_info_from_docs_conf() + + git_tag, git_hash, ver = info + + # Generate the file with the git and version info + file_data = """\ +// This file was generated by py/makeversionhdr.py +#define MICROPY_GIT_TAG "%s" +#define MICROPY_GIT_HASH "%s" +#define MICROPY_BUILD_DATE "%s" +#define MICROPY_VERSION_MAJOR (%s) +#define MICROPY_VERSION_MINOR (%s) +#define MICROPY_VERSION_MICRO (%s) +#define MICROPY_VERSION_STRING "%s.%s.%s" +""" % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"), + ver[0], ver[1], ver[2], ver[0], ver[1], ver[2]) + + # Check if the file contents changed from last time + write_file = True + if os.path.isfile(filename): + with open(filename, 'r') as f: + existing_data = f.read() + if existing_data == file_data: + write_file = False + + # Only write the file if we need to + if write_file: + print("GEN %s" % filename) + with open(filename, 'w') as f: + f.write(file_data) + +if __name__ == "__main__": + make_version_header(sys.argv[1]) diff --git a/src/openmv/src/micropython/py/malloc.c b/src/openmv/src/micropython/py/malloc.c new file mode 100755 index 0000000..f8ed148 --- /dev/null +++ b/src/openmv/src/micropython/py/malloc.c @@ -0,0 +1,219 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/mpstate.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +#if MICROPY_MEM_STATS +#if !MICROPY_MALLOC_USES_ALLOCATED_SIZE +#error MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE +#endif +#define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); } +#endif + +#if MICROPY_ENABLE_GC +#include "py/gc.h" + +// We redirect standard alloc functions to GC heap - just for the rest of +// this module. In the rest of MicroPython source, system malloc can be +// freely accessed - for interfacing with system and 3rd-party libs for +// example. On the other hand, some (e.g. bare-metal) ports may use GC +// heap as system heap, so, to avoid warnings, we do undef's first. +#undef malloc +#undef free +#undef realloc +#define malloc(b) gc_alloc((b), false) +#define malloc_with_finaliser(b) gc_alloc((b), true) +#define free gc_free +#define realloc(ptr, n) gc_realloc(ptr, n, true) +#define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) +#else + +// GC is disabled. Use system malloc/realloc/free. + +#if MICROPY_ENABLE_FINALISER +#error MICROPY_ENABLE_FINALISER requires MICROPY_ENABLE_GC +#endif + +STATIC void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { + if (allow_move) { + return realloc(ptr, n_bytes); + } else { + // We are asked to resize, but without moving the memory region pointed to + // by ptr. Unless the underlying memory manager has special provision for + // this behaviour there is nothing we can do except fail to resize. + return NULL; + } +} + +#endif // MICROPY_ENABLE_GC + +void *m_malloc(size_t num_bytes) { + void *ptr = malloc(num_bytes); + if (ptr == NULL && num_bytes != 0) { + m_malloc_fail(num_bytes); + } +#if MICROPY_MEM_STATS + MP_STATE_MEM(total_bytes_allocated) += num_bytes; + MP_STATE_MEM(current_bytes_allocated) += num_bytes; + UPDATE_PEAK(); +#endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); + return ptr; +} + +void *m_malloc_maybe(size_t num_bytes) { + void *ptr = malloc(num_bytes); +#if MICROPY_MEM_STATS + MP_STATE_MEM(total_bytes_allocated) += num_bytes; + MP_STATE_MEM(current_bytes_allocated) += num_bytes; + UPDATE_PEAK(); +#endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); + return ptr; +} + +#if MICROPY_ENABLE_FINALISER +void *m_malloc_with_finaliser(size_t num_bytes) { + void *ptr = malloc_with_finaliser(num_bytes); + if (ptr == NULL && num_bytes != 0) { + m_malloc_fail(num_bytes); + } +#if MICROPY_MEM_STATS + MP_STATE_MEM(total_bytes_allocated) += num_bytes; + MP_STATE_MEM(current_bytes_allocated) += num_bytes; + UPDATE_PEAK(); +#endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); + return ptr; +} +#endif + +void *m_malloc0(size_t num_bytes) { + void *ptr = m_malloc(num_bytes); + // If this config is set then the GC clears all memory, so we don't need to. + #if !MICROPY_GC_CONSERVATIVE_CLEAR + memset(ptr, 0, num_bytes); + #endif + return ptr; +} + +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE +void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) { +#else +void *m_realloc(void *ptr, size_t new_num_bytes) { +#endif + void *new_ptr = realloc(ptr, new_num_bytes); + if (new_ptr == NULL && new_num_bytes != 0) { + m_malloc_fail(new_num_bytes); + } +#if MICROPY_MEM_STATS + // At first thought, "Total bytes allocated" should only grow, + // after all, it's *total*. But consider for example 2K block + // shrunk to 1K and then grown to 2K again. It's still 2K + // allocated total. If we process only positive increments, + // we'll count 3K. + size_t diff = new_num_bytes - old_num_bytes; + MP_STATE_MEM(total_bytes_allocated) += diff; + MP_STATE_MEM(current_bytes_allocated) += diff; + UPDATE_PEAK(); +#endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif + return new_ptr; +} + +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE +void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move) { +#else +void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) { +#endif + void *new_ptr = realloc_ext(ptr, new_num_bytes, allow_move); +#if MICROPY_MEM_STATS + // At first thought, "Total bytes allocated" should only grow, + // after all, it's *total*. But consider for example 2K block + // shrunk to 1K and then grown to 2K again. It's still 2K + // allocated total. If we process only positive increments, + // we'll count 3K. + // Also, don't count failed reallocs. + if (!(new_ptr == NULL && new_num_bytes != 0)) { + size_t diff = new_num_bytes - old_num_bytes; + MP_STATE_MEM(total_bytes_allocated) += diff; + MP_STATE_MEM(current_bytes_allocated) += diff; + UPDATE_PEAK(); + } +#endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif + return new_ptr; +} + +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE +void m_free(void *ptr, size_t num_bytes) { +#else +void m_free(void *ptr) { +#endif + free(ptr); +#if MICROPY_MEM_STATS + MP_STATE_MEM(current_bytes_allocated) -= num_bytes; +#endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + DEBUG_printf("free %p, %d\n", ptr, num_bytes); + #else + DEBUG_printf("free %p\n", ptr); + #endif +} + +#if MICROPY_MEM_STATS +size_t m_get_total_bytes_allocated(void) { + return MP_STATE_MEM(total_bytes_allocated); +} + +size_t m_get_current_bytes_allocated(void) { + return MP_STATE_MEM(current_bytes_allocated); +} + +size_t m_get_peak_bytes_allocated(void) { + return MP_STATE_MEM(peak_bytes_allocated); +} +#endif diff --git a/src/openmv/src/micropython/py/map.c b/src/openmv/src/micropython/py/map.c new file mode 100755 index 0000000..fc5e1b1 --- /dev/null +++ b/src/openmv/src/micropython/py/map.c @@ -0,0 +1,435 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/runtime.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +// Fixed empty map. Useful when need to call kw-receiving functions +// without any keywords from C, etc. +const mp_map_t mp_const_empty_map = { + .all_keys_are_qstrs = 0, + .is_fixed = 1, + .is_ordered = 1, + .used = 0, + .alloc = 0, + .table = NULL, +}; + +// This table of sizes is used to control the growth of hash tables. +// The first set of sizes are chosen so the allocation fits exactly in a +// 4-word GC block, and it's not so important for these small values to be +// prime. The latter sizes are prime and increase at an increasing rate. +STATIC const uint16_t hash_allocation_sizes[] = { + 0, 2, 4, 6, 8, 10, 12, // +2 + 17, 23, 29, 37, 47, 59, 73, // *1.25 + 97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33 + 3229, 4831, 7243, 10861, 16273, 24407, 36607, 54907, // *1.5 +}; + +STATIC size_t get_hash_alloc_greater_or_equal_to(size_t x) { + for (size_t i = 0; i < MP_ARRAY_SIZE(hash_allocation_sizes); i++) { + if (hash_allocation_sizes[i] >= x) { + return hash_allocation_sizes[i]; + } + } + // ran out of primes in the table! + // return something sensible, at least make it odd + return (x + x / 2) | 1; +} + +/******************************************************************************/ +/* map */ + +void mp_map_init(mp_map_t *map, size_t n) { + if (n == 0) { + map->alloc = 0; + map->table = NULL; + } else { + map->alloc = n; + map->table = m_new0(mp_map_elem_t, map->alloc); + } + map->used = 0; + map->all_keys_are_qstrs = 1; + map->is_fixed = 0; + map->is_ordered = 0; +} + +void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table) { + map->alloc = n; + map->used = n; + map->all_keys_are_qstrs = 1; + map->is_fixed = 1; + map->is_ordered = 1; + map->table = (mp_map_elem_t*)table; +} + +// Differentiate from mp_map_clear() - semantics is different +void mp_map_deinit(mp_map_t *map) { + if (!map->is_fixed) { + m_del(mp_map_elem_t, map->table, map->alloc); + } + map->used = map->alloc = 0; +} + +void mp_map_clear(mp_map_t *map) { + if (!map->is_fixed) { + m_del(mp_map_elem_t, map->table, map->alloc); + } + map->alloc = 0; + map->used = 0; + map->all_keys_are_qstrs = 1; + map->is_fixed = 0; + map->table = NULL; +} + +STATIC void mp_map_rehash(mp_map_t *map) { + size_t old_alloc = map->alloc; + size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1); + DEBUG_printf("mp_map_rehash(%p): " UINT_FMT " -> " UINT_FMT "\n", map, old_alloc, new_alloc); + mp_map_elem_t *old_table = map->table; + mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc); + // If we reach this point, table resizing succeeded, now we can edit the old map. + map->alloc = new_alloc; + map->used = 0; + map->all_keys_are_qstrs = 1; + map->table = new_table; + for (size_t i = 0; i < old_alloc; i++) { + if (old_table[i].key != MP_OBJ_NULL && old_table[i].key != MP_OBJ_SENTINEL) { + mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value; + } + } + m_del(mp_map_elem_t, old_table, old_alloc); +} + +// MP_MAP_LOOKUP behaviour: +// - returns NULL if not found, else the slot it was found in with key,value non-null +// MP_MAP_LOOKUP_ADD_IF_NOT_FOUND behaviour: +// - returns slot, with key non-null and value=MP_OBJ_NULL if it was added +// MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour: +// - returns NULL if not found, else the slot if was found in with key null and value non-null +mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { + // If the map is a fixed array then we must only be called for a lookup + assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP); + + // Work out if we can compare just pointers + bool compare_only_ptrs = map->all_keys_are_qstrs; + if (compare_only_ptrs) { + if (MP_OBJ_IS_QSTR(index)) { + // Index is a qstr, so can just do ptr comparison. + } else if (MP_OBJ_IS_TYPE(index, &mp_type_str)) { + // Index is a non-interned string. + // We can either intern the string, or force a full equality comparison. + // We chose the latter, since interning costs time and potentially RAM, + // and it won't necessarily benefit subsequent calls because these calls + // most likely won't pass the newly-interned string. + compare_only_ptrs = false; + } else if (lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + // If we are not adding, then we can return straight away a failed + // lookup because we know that the index will never be found. + return NULL; + } + } + + // if the map is an ordered array then we must do a brute force linear search + if (map->is_ordered) { + for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) { + if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) { + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) { + // remove the found element by moving the rest of the array down + mp_obj_t value = elem->value; + --map->used; + memmove(elem, elem + 1, (top - elem - 1) * sizeof(*elem)); + // put the found element after the end so the caller can access it if needed + elem = &map->table[map->used]; + elem->key = MP_OBJ_NULL; + elem->value = value; + } + #endif + return elem; + } + } + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) { + return NULL; + } + if (map->used == map->alloc) { + // TODO: Alloc policy + map->alloc += 4; + map->table = m_renew(mp_map_elem_t, map->table, map->used, map->alloc); + mp_seq_clear(map->table, map->used, map->alloc, sizeof(*map->table)); + } + mp_map_elem_t *elem = map->table + map->used++; + elem->key = index; + if (!MP_OBJ_IS_QSTR(index)) { + map->all_keys_are_qstrs = 0; + } + return elem; + #else + return NULL; + #endif + } + + // map is a hash table (not an ordered array), so do a hash lookup + + if (map->alloc == 0) { + if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + mp_map_rehash(map); + } else { + return NULL; + } + } + + // get hash of index, with fast path for common case of qstr + mp_uint_t hash; + if (MP_OBJ_IS_QSTR(index)) { + hash = qstr_hash(MP_OBJ_QSTR_VALUE(index)); + } else { + hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); + } + + size_t pos = hash % map->alloc; + size_t start_pos = pos; + mp_map_elem_t *avail_slot = NULL; + for (;;) { + mp_map_elem_t *slot = &map->table[pos]; + if (slot->key == MP_OBJ_NULL) { + // found NULL slot, so index is not in table + if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + map->used += 1; + if (avail_slot == NULL) { + avail_slot = slot; + } + avail_slot->key = index; + avail_slot->value = MP_OBJ_NULL; + if (!MP_OBJ_IS_QSTR(index)) { + map->all_keys_are_qstrs = 0; + } + return avail_slot; + } else { + return NULL; + } + } else if (slot->key == MP_OBJ_SENTINEL) { + // found deleted slot, remember for later + if (avail_slot == NULL) { + avail_slot = slot; + } + } else if (slot->key == index || (!compare_only_ptrs && mp_obj_equal(slot->key, index))) { + // found index + // Note: CPython does not replace the index; try x={True:'true'};x[1]='one';x + if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + // delete element in this slot + map->used--; + if (map->table[(pos + 1) % map->alloc].key == MP_OBJ_NULL) { + // optimisation if next slot is empty + slot->key = MP_OBJ_NULL; + } else { + slot->key = MP_OBJ_SENTINEL; + } + // keep slot->value so that caller can access it if needed + } + return slot; + } + + // not yet found, keep searching in this table + pos = (pos + 1) % map->alloc; + + if (pos == start_pos) { + // search got back to starting position, so index is not in table + if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + if (avail_slot != NULL) { + // there was an available slot, so use that + map->used++; + avail_slot->key = index; + avail_slot->value = MP_OBJ_NULL; + if (!MP_OBJ_IS_QSTR(index)) { + map->all_keys_are_qstrs = 0; + } + return avail_slot; + } else { + // not enough room in table, rehash it + mp_map_rehash(map); + // restart the search for the new element + start_pos = pos = hash % map->alloc; + } + } else { + return NULL; + } + } + } +} + +/******************************************************************************/ +/* set */ + +#if MICROPY_PY_BUILTINS_SET + +void mp_set_init(mp_set_t *set, size_t n) { + set->alloc = n; + set->used = 0; + set->table = m_new0(mp_obj_t, set->alloc); +} + +STATIC void mp_set_rehash(mp_set_t *set) { + size_t old_alloc = set->alloc; + mp_obj_t *old_table = set->table; + set->alloc = get_hash_alloc_greater_or_equal_to(set->alloc + 1); + set->used = 0; + set->table = m_new0(mp_obj_t, set->alloc); + for (size_t i = 0; i < old_alloc; i++) { + if (old_table[i] != MP_OBJ_NULL && old_table[i] != MP_OBJ_SENTINEL) { + mp_set_lookup(set, old_table[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + } + } + m_del(mp_obj_t, old_table, old_alloc); +} + +mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { + // Note: lookup_kind can be MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND which + // is handled by using bitwise operations. + + if (set->alloc == 0) { + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + mp_set_rehash(set); + } else { + return MP_OBJ_NULL; + } + } + mp_uint_t hash = MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, index)); + size_t pos = hash % set->alloc; + size_t start_pos = pos; + mp_obj_t *avail_slot = NULL; + for (;;) { + mp_obj_t elem = set->table[pos]; + if (elem == MP_OBJ_NULL) { + // found NULL slot, so index is not in table + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + if (avail_slot == NULL) { + avail_slot = &set->table[pos]; + } + set->used++; + *avail_slot = index; + return index; + } else { + return MP_OBJ_NULL; + } + } else if (elem == MP_OBJ_SENTINEL) { + // found deleted slot, remember for later + if (avail_slot == NULL) { + avail_slot = &set->table[pos]; + } + } else if (mp_obj_equal(elem, index)) { + // found index + if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + // delete element + set->used--; + if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { + // optimisation if next slot is empty + set->table[pos] = MP_OBJ_NULL; + } else { + set->table[pos] = MP_OBJ_SENTINEL; + } + } + return elem; + } + + // not yet found, keep searching in this table + pos = (pos + 1) % set->alloc; + + if (pos == start_pos) { + // search got back to starting position, so index is not in table + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + if (avail_slot != NULL) { + // there was an available slot, so use that + set->used++; + *avail_slot = index; + return index; + } else { + // not enough room in table, rehash it + mp_set_rehash(set); + // restart the search for the new element + start_pos = pos = hash % set->alloc; + } + } else { + return MP_OBJ_NULL; + } + } + } +} + +mp_obj_t mp_set_remove_first(mp_set_t *set) { + for (size_t pos = 0; pos < set->alloc; pos++) { + if (MP_SET_SLOT_IS_FILLED(set, pos)) { + mp_obj_t elem = set->table[pos]; + // delete element + set->used--; + if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { + // optimisation if next slot is empty + set->table[pos] = MP_OBJ_NULL; + } else { + set->table[pos] = MP_OBJ_SENTINEL; + } + return elem; + } + } + return MP_OBJ_NULL; +} + +void mp_set_clear(mp_set_t *set) { + m_del(mp_obj_t, set->table, set->alloc); + set->alloc = 0; + set->used = 0; + set->table = NULL; +} + +#endif // MICROPY_PY_BUILTINS_SET + +#if defined(DEBUG_PRINT) && DEBUG_PRINT +void mp_map_dump(mp_map_t *map) { + for (size_t i = 0; i < map->alloc; i++) { + if (map->table[i].key != MP_OBJ_NULL) { + mp_obj_print(map->table[i].key, PRINT_REPR); + } else { + DEBUG_printf("(nil)"); + } + DEBUG_printf(": %p\n", map->table[i].value); + } + DEBUG_printf("---\n"); +} +#endif diff --git a/src/openmv/src/micropython/py/misc.h b/src/openmv/src/micropython/py/misc.h new file mode 100755 index 0000000..e6d25b8 --- /dev/null +++ b/src/openmv/src/micropython/py/misc.h @@ -0,0 +1,223 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MISC_H +#define MICROPY_INCLUDED_PY_MISC_H + +// a mini library of useful types and functions + +/** types *******************************************************/ + +#include +#include +#include + +typedef unsigned char byte; +typedef unsigned int uint; + +/** generic ops *************************************************/ + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +// Classical double-indirection stringification of preprocessor macro's value +#define _MP_STRINGIFY(x) #x +#define MP_STRINGIFY(x) _MP_STRINGIFY(x) + +// Static assertion macro +#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) + +/** memory allocation ******************************************/ + +// TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element) + +#define m_new(type, num) ((type*)(m_malloc(sizeof(type) * (num)))) +#define m_new_maybe(type, num) ((type*)(m_malloc_maybe(sizeof(type) * (num)))) +#define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num)))) +#define m_new_obj(type) (m_new(type, 1)) +#define m_new_obj_maybe(type) (m_new_maybe(type, 1)) +#define m_new_obj_var(obj_type, var_type, var_num) ((obj_type*)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num))) +#define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num))) +#if MICROPY_ENABLE_FINALISER +#define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type)))) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type*)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num))) +#else +#define m_new_obj_with_finaliser(type) m_new_obj(type) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num) +#endif +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE +#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) +#define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move)))) +#define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num)) +#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num))) +#else +#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (new_num)))) +#define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move)))) +#define m_del(type, ptr, num) ((void)(num), m_free(ptr)) +#define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr)) +#endif +#define m_del_obj(type, ptr) (m_del(type, ptr, 1)) + +void *m_malloc(size_t num_bytes); +void *m_malloc_maybe(size_t num_bytes); +void *m_malloc_with_finaliser(size_t num_bytes); +void *m_malloc0(size_t num_bytes); +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE +void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes); +void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move); +void m_free(void *ptr, size_t num_bytes); +#else +void *m_realloc(void *ptr, size_t new_num_bytes); +void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move); +void m_free(void *ptr); +#endif +NORETURN void m_malloc_fail(size_t num_bytes); + +#if MICROPY_MEM_STATS +size_t m_get_total_bytes_allocated(void); +size_t m_get_current_bytes_allocated(void); +size_t m_get_peak_bytes_allocated(void); +#endif + +/** array helpers ***********************************************/ + +// get the number of elements in a fixed-size array +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +// align ptr to the nearest multiple of "alignment" +#define MP_ALIGN(ptr, alignment) (void*)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1)) + +/** unichar / UTF-8 *********************************************/ + +#if MICROPY_PY_BUILTINS_STR_UNICODE +// with unicode enabled we need a type which can fit chars up to 0x10ffff +typedef uint32_t unichar; +#else +// without unicode enabled we can only need to fit chars up to 0xff +// (on 16-bit archs uint is 16-bits and more efficient than uint32_t) +typedef uint unichar; +#endif + +#if MICROPY_PY_BUILTINS_STR_UNICODE +unichar utf8_get_char(const byte *s); +const byte *utf8_next_char(const byte *s); +size_t utf8_charlen(const byte *str, size_t len); +#else +static inline unichar utf8_get_char(const byte *s) { return *s; } +static inline const byte *utf8_next_char(const byte *s) { return s + 1; } +static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; } +#endif + +bool unichar_isspace(unichar c); +bool unichar_isalpha(unichar c); +bool unichar_isprint(unichar c); +bool unichar_isdigit(unichar c); +bool unichar_isxdigit(unichar c); +bool unichar_isident(unichar c); +bool unichar_isupper(unichar c); +bool unichar_islower(unichar c); +unichar unichar_tolower(unichar c); +unichar unichar_toupper(unichar c); +mp_uint_t unichar_xdigit_value(unichar c); +#define UTF8_IS_NONASCII(ch) ((ch) & 0x80) +#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) + +/** variable string *********************************************/ + +typedef struct _vstr_t { + size_t alloc; + size_t len; + char *buf; + bool fixed_buf : 1; +} vstr_t; + +// convenience macro to declare a vstr with a fixed size buffer on the stack +#define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf); + +void vstr_init(vstr_t *vstr, size_t alloc); +void vstr_init_len(vstr_t *vstr, size_t len); +void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf); +struct _mp_print_t; +void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print); +void vstr_clear(vstr_t *vstr); +vstr_t *vstr_new(size_t alloc); +void vstr_free(vstr_t *vstr); +static inline void vstr_reset(vstr_t *vstr) { vstr->len = 0; } +static inline char *vstr_str(vstr_t *vstr) { return vstr->buf; } +static inline size_t vstr_len(vstr_t *vstr) { return vstr->len; } +void vstr_hint_size(vstr_t *vstr, size_t size); +char *vstr_extend(vstr_t *vstr, size_t size); +char *vstr_add_len(vstr_t *vstr, size_t len); +char *vstr_null_terminated_str(vstr_t *vstr); +void vstr_add_byte(vstr_t *vstr, byte v); +void vstr_add_char(vstr_t *vstr, unichar chr); +void vstr_add_str(vstr_t *vstr, const char *str); +void vstr_add_strn(vstr_t *vstr, const char *str, size_t len); +void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b); +void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr); +void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut); +void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut); +void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut); +void vstr_printf(vstr_t *vstr, const char *fmt, ...); + +/** non-dynamic size-bounded variable buffer/string *************/ + +#define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf; +#define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf; +#define CHECKBUF_APPEND(buf, src, src_len) \ + { size_t l = MIN(src_len, buf##_len); \ + memcpy(buf##_p, src, l); \ + buf##_len -= l; \ + buf##_p += l; } +#define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; } +#define CHECKBUF_LEN(buf) (buf##_p - buf) + +#ifdef va_start +void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap); +#endif + +// Debugging helpers +int DEBUG_printf(const char *fmt, ...); + +extern mp_uint_t mp_verbose_flag; + +/** float internals *************/ + +#if MICROPY_PY_BUILTINS_FLOAT +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define MP_FLOAT_EXP_BITS (11) +#define MP_FLOAT_FRAC_BITS (52) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define MP_FLOAT_EXP_BITS (8) +#define MP_FLOAT_FRAC_BITS (23) +#endif +#define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1) +#endif // MICROPY_PY_BUILTINS_FLOAT + +#endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/src/openmv/src/micropython/py/mkenv.mk b/src/openmv/src/micropython/py/mkenv.mk new file mode 100755 index 0000000..2c9c86a --- /dev/null +++ b/src/openmv/src/micropython/py/mkenv.mk @@ -0,0 +1,70 @@ +ifneq ($(lastword a b),b) +$(error These Makefiles require make 3.81 or newer) +endif + +# Set TOP to be the path to get from the current directory (where make was +# invoked) to the top of the tree. $(lastword $(MAKEFILE_LIST)) returns +# the name of this makefile relative to where make was invoked. +# +# We assume that this file is in the py directory so we use $(dir ) twice +# to get to the top of the tree. + +THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) +TOP := $(patsubst %/py/mkenv.mk,%,$(THIS_MAKEFILE)) + +# Turn on increased build verbosity by defining BUILD_VERBOSE in your main +# Makefile or in your environment. You can also use V=1 on the make command +# line. + +ifeq ("$(origin V)", "command line") +BUILD_VERBOSE=$(V) +endif +ifndef BUILD_VERBOSE +BUILD_VERBOSE = 0 +endif +ifeq ($(BUILD_VERBOSE),0) +Q = @ +else +Q = +endif +# Since this is a new feature, advertise it +ifeq ($(BUILD_VERBOSE),0) +$(info Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.) +endif + +# default settings; can be overridden in main Makefile + +PY_SRC ?= $(TOP)/py +BUILD ?= build + +RM = rm +ECHO = @echo +CP = cp +MKDIR = mkdir +SED = sed +PYTHON = python + +AS = $(CROSS_COMPILE)as +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +LD = $(CROSS_COMPILE)ld +OBJCOPY = $(CROSS_COMPILE)objcopy +SIZE = $(CROSS_COMPILE)size +STRIP = $(CROSS_COMPILE)strip +AR = $(CROSS_COMPILE)ar +ifeq ($(MICROPY_FORCE_32BIT),1) +CC += -m32 +CXX += -m32 +LD += -m32 +endif + +MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py +MPY_CROSS = $(TOP)/mpy-cross/mpy-cross +MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py + +all: +.PHONY: all + +.DELETE_ON_ERROR: + +MKENV_INCLUDED = 1 diff --git a/src/openmv/src/micropython/py/mkrules.mk b/src/openmv/src/micropython/py/mkrules.mk new file mode 100755 index 0000000..6a11c62 --- /dev/null +++ b/src/openmv/src/micropython/py/mkrules.mk @@ -0,0 +1,197 @@ +ifneq ($(MKENV_INCLUDED),1) +# We assume that mkenv is in the same directory as this file. +THIS_MAKEFILE = $(lastword $(MAKEFILE_LIST)) +include $(dir $(THIS_MAKEFILE))mkenv.mk +endif + +# This file expects that OBJ contains a list of all of the object files. +# The directory portion of each object file is used to locate the source +# and should not contain any ..'s but rather be relative to the top of the +# tree. +# +# So for example, py/map.c would have an object file name py/map.o +# The object files will go into the build directory and mantain the same +# directory structure as the source tree. So the final dependency will look +# like this: +# +# build/py/map.o: py/map.c +# +# We set vpath to point to the top of the tree so that the source files +# can be located. By following this scheme, it allows a single build rule +# to be used to compile all .c files. + +vpath %.S . $(TOP) +$(BUILD)/%.o: %.S + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS) -c -o $@ $< + +vpath %.s . $(TOP) +$(BUILD)/%.o: %.s + $(ECHO) "AS $<" + $(Q)$(AS) -o $@ $< + +define compile_c +$(ECHO) "CC $<" +$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.c . $(TOP) +$(BUILD)/%.o: %.c + $(call compile_c) + +QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR +QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp + +vpath %.c . $(TOP) + +$(BUILD)/%.pp: %.c + $(ECHO) "PreProcess $<" + $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< + +# The following rule uses | to create an order only prerequisite. Order only +# prerequisites only get built if they don't exist. They don't cause timestamp +# checking to be performed. +# +# We don't know which source files actually need the generated.h (since +# it is #included from str.h). The compiler generated dependencies will cause +# the right .o's to get recompiled if the generated.h file changes. Adding +# an order-only dependency to all of the .o's will cause the generated .h +# to get built before we try to compile any of them. +$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h + +# The logic for qstr regeneration is: +# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^) +# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?) +# - else, process all source files ($^) [this covers "make -B" which can set $? to empty] +$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h + $(ECHO) "GEN $@" + $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last; + +$(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED) + $(Q)touch $@ + +$(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split + $(ECHO) "GEN $@" + $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED) + +# $(sort $(var)) removes duplicates +# +# The net effect of this, is it causes the objects to depend on the +# object directories (but only for existence), and the object directories +# will be created if they don't exist. +OBJ_DIRS = $(sort $(dir $(OBJ))) +$(OBJ): | $(OBJ_DIRS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +$(HEADER_BUILD): + $(MKDIR) -p $@ + +ifneq ($(FROZEN_DIR),) +$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) + $(ECHO) "GEN $@" + $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ +endif + +ifneq ($(FROZEN_MPY_DIR),) +# to build the MicroPython cross compiler +$(TOP)/mpy-cross/mpy-cross: $(TOP)/py/*.[ch] $(TOP)/mpy-cross/*.[ch] $(TOP)/ports/windows/fmode.c + $(Q)$(MAKE) -C $(TOP)/mpy-cross + +# make a list of all the .py files that need compiling and freezing +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) + +# to build .mpy files from .py files +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $< + +# to build frozen_mpy.c from all .mpy files +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h + @$(ECHO) "GEN $@" + $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ +endif + +ifneq ($(PROG),) +# Build a standalone executable (unix does this) + +all: $(PROG) + +$(PROG): $(OBJ) + $(ECHO) "LINK $@" +# Do not pass COPT here - it's *C* compiler optimizations. For example, +# we may want to compile using Thumb, but link with non-Thumb libc. + $(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS) +ifndef DEBUG + $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG) +endif + $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG) + +clean: clean-prog +clean-prog: + $(RM) -f $(PROG) + $(RM) -f $(PROG).map + +.PHONY: clean-prog +endif + +LIBMICROPYTHON = libmicropython.a + +# We can execute extra commands after library creation using +# LIBMICROPYTHON_EXTRA_CMD. This may be needed e.g. to integrate +# with 3rd-party projects which don't have proper dependency +# tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some +# other file to cause needed effect, e.g. relinking with new lib. +lib $(LIBMICROPYTHON): $(OBJ) + $(AR) rcs $(LIBMICROPYTHON) $^ + $(LIBMICROPYTHON_EXTRA_CMD) + +clean_py: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) +.PHONY: clean_py + +# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup. +# We run rmdir below to avoid empty backup dir (it will silently fail if backup +# is non-empty). +clean-frozen: + if [ -n "$(FROZEN_MPY_DIR)" ]; then \ + backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi + + if [ -n "$(FROZEN_DIR)" ]; then \ + backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi +.PHONY: clean-frozen + +print-cfg: + $(ECHO) "PY_SRC = $(PY_SRC)" + $(ECHO) "BUILD = $(BUILD)" + $(ECHO) "OBJ = $(OBJ)" +.PHONY: print-cfg + +print-def: + @$(ECHO) "The following defines are built into the $(CC) compiler" + touch __empty__.c + @$(CC) -E -Wp,-dM __empty__.c + @$(RM) -f __empty__.c + +-include $(OBJ:.o=.P) diff --git a/src/openmv/src/micropython/py/modarray.c b/src/openmv/src/micropython/py/modarray.c new file mode 100755 index 0000000..c0cdca9 --- /dev/null +++ b/src/openmv/src/micropython/py/modarray.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +#if MICROPY_PY_ARRAY + +STATIC const mp_rom_map_elem_t mp_module_array_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_array) }, + { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_type_array) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_table); + +const mp_obj_module_t mp_module_array = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_array_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/py/modbuiltins.c b/src/openmv/src/micropython/py/modbuiltins.c new file mode 100755 index 0000000..c4de325 --- /dev/null +++ b/src/openmv/src/micropython/py/modbuiltins.c @@ -0,0 +1,760 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/smallint.h" +#include "py/objint.h" +#include "py/objstr.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/stream.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + +#if MICROPY_PY_IO +extern struct _mp_dummy_t mp_sys_stdout_obj; // type is irrelevant, just need pointer +#endif + +// args[0] is function from class body +// args[1] is class name +// args[2:] are base objects +STATIC mp_obj_t mp_builtin___build_class__(size_t n_args, const mp_obj_t *args) { + assert(2 <= n_args); + + // set the new classes __locals__ object + mp_obj_dict_t *old_locals = mp_locals_get(); + mp_obj_t class_locals = mp_obj_new_dict(0); + mp_locals_set(MP_OBJ_TO_PTR(class_locals)); + + // call the class code + mp_obj_t cell = mp_call_function_0(args[0]); + + // restore old __locals__ object + mp_locals_set(old_locals); + + // get the class type (meta object) from the base objects + mp_obj_t meta; + if (n_args == 2) { + // no explicit bases, so use 'type' + meta = MP_OBJ_FROM_PTR(&mp_type_type); + } else { + // use type of first base object + meta = MP_OBJ_FROM_PTR(mp_obj_get_type(args[2])); + } + + // TODO do proper metaclass resolution for multiple base objects + + // create the new class using a call to the meta object + mp_obj_t meta_args[3]; + meta_args[0] = args[1]; // class name + meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases + meta_args[2] = class_locals; // dict of members + mp_obj_t new_class = mp_call_function_n_kw(meta, 3, 0, meta_args); + + // store into cell if neede + if (cell != mp_const_none) { + mp_obj_cell_set(cell, new_class); + } + + return new_class; +} +MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__); + +STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) { + return mp_unary_op(MP_UNARY_OP_ABS, o_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs); + +STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(o_in, &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!mp_obj_is_true(item)) { + return mp_const_false; + } + } + return mp_const_true; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all); + +STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(o_in, &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_is_true(item)) { + return mp_const_true; + } + } + return mp_const_false; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any); + +STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) { + mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in }; + return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin); + +STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) { + if (mp_obj_is_callable(o_in)) { + return mp_const_true; + } else { + return mp_const_false; + } +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); + +STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { + #if MICROPY_PY_BUILTINS_STR_UNICODE + mp_uint_t c = mp_obj_get_int(o_in); + uint8_t str[4]; + int len = 0; + if (c < 0x80) { + *str = c; len = 1; + } else if (c < 0x800) { + str[0] = (c >> 6) | 0xC0; + str[1] = (c & 0x3F) | 0x80; + len = 2; + } else if (c < 0x10000) { + str[0] = (c >> 12) | 0xE0; + str[1] = ((c >> 6) & 0x3F) | 0x80; + str[2] = (c & 0x3F) | 0x80; + len = 3; + } else if (c < 0x110000) { + str[0] = (c >> 18) | 0xF0; + str[1] = ((c >> 12) & 0x3F) | 0x80; + str[2] = ((c >> 6) & 0x3F) | 0x80; + str[3] = (c & 0x3F) | 0x80; + len = 4; + } else { + mp_raise_ValueError("chr() arg not in range(0x110000)"); + } + return mp_obj_new_str_via_qstr((char*)str, len); + #else + mp_int_t ord = mp_obj_get_int(o_in); + if (0 <= ord && ord <= 0xff) { + uint8_t str[1] = {ord}; + return mp_obj_new_str_via_qstr((char*)str, 1); + } else { + mp_raise_ValueError("chr() arg not in range(256)"); + } + #endif +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); + +STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { + mp_obj_t dir = mp_obj_new_list(0, NULL); + if (n_args == 0) { + // Make a list of names in the local namespace + mp_obj_dict_t *dict = mp_locals_get(); + for (size_t i = 0; i < dict->map.alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { + mp_obj_list_append(dir, dict->map.table[i].key); + } + } + } else { // n_args == 1 + // Make a list of names in the given object + // Implemented by probing all possible qstrs with mp_load_method_maybe + size_t nqstr = QSTR_TOTAL(); + for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) { + mp_obj_t dest[2]; + mp_load_method_protected(args[0], i, dest, false); + if (dest[0] != MP_OBJ_NULL) { + #if MICROPY_PY_ALL_SPECIAL_METHODS + // Support for __dir__: see if we can dispatch to this special method + // This relies on MP_QSTR__dir__ being first after MP_QSTR_ + if (i == MP_QSTR___dir__ && dest[1] != MP_OBJ_NULL) { + return mp_call_method_n_kw(0, 0, dest); + } + #endif + mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); + } + } + } + return dir; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir); + +STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) { + return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod); + +STATIC mp_obj_t mp_builtin_hash(mp_obj_t o_in) { + // result is guaranteed to be a (small) int + return mp_unary_op(MP_UNARY_OP_HASH, o_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash); + +STATIC mp_obj_t mp_builtin_hex(mp_obj_t o_in) { + #if MICROPY_PY_BUILTINS_STR_OP_MODULO + return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_x), o_in); + #else + mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_x_brace_close_), o_in }; + return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL); + #endif +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hex_obj, mp_builtin_hex); + +#if MICROPY_PY_BUILTINS_INPUT + +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" + +// A port can define mp_hal_readline if they want to use a custom function here +#ifndef mp_hal_readline +#define mp_hal_readline readline +#endif + +STATIC mp_obj_t mp_builtin_input(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + mp_obj_print(args[0], PRINT_STR); + } + vstr_t line; + vstr_init(&line, 16); + int ret = mp_hal_readline(&line, ""); + if (ret == CHAR_CTRL_C) { + nlr_raise(mp_obj_new_exception(&mp_type_KeyboardInterrupt)); + } + if (line.len == 0 && ret == CHAR_CTRL_D) { + nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); + } + return mp_obj_new_str_from_vstr(&mp_type_str, &line); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj, 0, 1, mp_builtin_input); + +#endif + +STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) { + return mp_getiter(o_in, NULL); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter); + +#if MICROPY_PY_BUILTINS_MIN_MAX + +STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs, mp_uint_t op) { + mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP); + mp_map_elem_t *default_elem; + mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value; + if (n_args == 1) { + // given an iterable + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[0], &iter_buf); + mp_obj_t best_key = MP_OBJ_NULL; + mp_obj_t best_obj = MP_OBJ_NULL; + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item); + if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) { + best_key = key; + best_obj = item; + } + } + if (best_obj == MP_OBJ_NULL) { + default_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_default), MP_MAP_LOOKUP); + if (default_elem != NULL) { + best_obj = default_elem->value; + } else { + mp_raise_ValueError("arg is an empty sequence"); + } + } + return best_obj; + } else { + // given many args + mp_obj_t best_key = MP_OBJ_NULL; + mp_obj_t best_obj = MP_OBJ_NULL; + for (size_t i = 0; i < n_args; i++) { + mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]); + if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) { + best_key = key; + best_obj = args[i]; + } + } + return best_obj; + } +} + +STATIC mp_obj_t mp_builtin_max(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max); + +STATIC mp_obj_t mp_builtin_min(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min); + +#endif + +STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { + mp_obj_t ret = mp_iternext_allow_raise(o); + if (ret == MP_OBJ_STOP_ITERATION) { + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next); + +STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { + #if MICROPY_PY_BUILTINS_STR_OP_MODULO + return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_o), o_in); + #else + mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_o_brace_close_), o_in }; + return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL); + #endif +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); + +STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { + size_t len; + const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len); + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (MP_OBJ_IS_STR(o_in)) { + len = utf8_charlen(str, len); + if (len == 1) { + return mp_obj_new_int(utf8_get_char(str)); + } + } else + #endif + { + // a bytes object, or a str without unicode support (don't sign extend the char) + if (len == 1) { + return MP_OBJ_NEW_SMALL_INT(str[0]); + } + } + + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("ord expects a character"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "ord() expected a character, but string of length %d found", (int)len)); + } +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord); + +STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { + switch (n_args) { + case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); + default: +#if !MICROPY_PY_BUILTINS_POW3 + mp_raise_msg(&mp_type_NotImplementedError, "3-arg pow() not supported"); +#elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ + return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); +#else + return mp_obj_int_pow3(args[0], args[1], args[2]); +#endif + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow); + +STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sep, ARG_end, ARG_file }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} }, + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} }, + #endif + }; + + // parse args (a union is used to reduce the amount of C stack that is needed) + union { + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + size_t len[2]; + } u; + mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); + + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor}; + #endif + + // extract the objects first because we are going to use the other part of the union + mp_obj_t sep = u.args[ARG_sep].u_obj; + mp_obj_t end = u.args[ARG_end].u_obj; + const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]); + const char *end_data = mp_obj_str_get_data(end, &u.len[1]); + + for (size_t i = 0; i < n_args; i++) { + if (i > 0) { + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + mp_stream_write_adaptor(print.data, sep_data, u.len[0]); + #else + mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0); + #endif + } + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + mp_obj_print_helper(&print, pos_args[i], PRINT_STR); + #else + mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR); + #endif + } + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + mp_stream_write_adaptor(print.data, end_data, u.len[1]); + #else + mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0); + #endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print); + +STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { + if (o != mp_const_none) { + mp_obj_print_helper(MP_PYTHON_PRINTER, o, PRINT_REPR); + mp_print_str(MP_PYTHON_PRINTER, "\n"); + #if MICROPY_CAN_OVERRIDE_BUILTINS + // Set "_" special variable + mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o}; + mp_type_module.attr(MP_OBJ_FROM_PTR(&mp_module_builtins), MP_QSTR__, dest); + #endif + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__); + +STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) { + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 16, &print); + mp_obj_print_helper(&print, o_in, PRINT_REPR); + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); + +STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { + mp_obj_t o_in = args[0]; + if (MP_OBJ_IS_INT(o_in)) { + if (n_args <= 1) { + return o_in; + } + + #if !MICROPY_PY_BUILTINS_ROUND_INT + mp_raise_NotImplementedError(NULL); + #else + mp_int_t num_dig = mp_obj_get_int(args[1]); + if (num_dig >= 0) { + return o_in; + } + + mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig)); + mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2)); + mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult); + mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) { + return rounded; + } else if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, modulo, half_mult))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + // round to even number + mp_obj_t floor = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, o_in, mult); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_AND, floor, MP_OBJ_NEW_SMALL_INT(1)))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + return rounded; + } + } + #endif + } +#if MICROPY_PY_BUILTINS_FLOAT + mp_float_t val = mp_obj_get_float(o_in); + if (n_args > 1) { + mp_int_t num_dig = mp_obj_get_int(args[1]); + mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig); + // TODO may lead to overflow + mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult; + return mp_obj_new_float(rounded); + } + mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val); + return mp_obj_new_int_from_float(rounded); +#else + mp_int_t r = mp_obj_get_int(o_in); + return mp_obj_new_int(r); +#endif +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round); + +STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) { + mp_obj_t value; + switch (n_args) { + case 1: value = MP_OBJ_NEW_SMALL_INT(0); break; + default: value = args[1]; break; + } + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[0], &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + value = mp_binary_op(MP_BINARY_OP_ADD, value, item); + } + return value; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); + +STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args > 1) { + mp_raise_TypeError("must use keyword argument for key function"); + } + mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); + mp_obj_list_sort(1, &self, kwargs); + + return self; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted); + +// See mp_load_attr() if making any changes +static inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) { + mp_obj_t dest[2]; + // use load_method, raising or not raising exception + ((defval == MP_OBJ_NULL) ? mp_load_method : mp_load_method_maybe)(base, attr, dest); + if (dest[0] == MP_OBJ_NULL) { + return defval; + } else if (dest[1] == MP_OBJ_NULL) { + // load_method returned just a normal attribute + return dest[0]; + } else { + // load_method returned a method, so build a bound method object + return mp_obj_new_bound_meth(dest[0], dest[1]); + } +} + +STATIC mp_obj_t mp_builtin_getattr(size_t n_args, const mp_obj_t *args) { + mp_obj_t defval = MP_OBJ_NULL; + if (n_args > 2) { + defval = args[2]; + } + return mp_load_attr_default(args[0], mp_obj_str_get_qstr(args[1]), defval); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr); + +STATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) { + mp_store_attr(base, mp_obj_str_get_qstr(attr), value); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr); + +#if MICROPY_CPYTHON_COMPAT +STATIC mp_obj_t mp_builtin_delattr(mp_obj_t base, mp_obj_t attr) { + return mp_builtin_setattr(base, attr, MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); +#endif + +STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { + qstr attr = mp_obj_str_get_qstr(attr_in); + mp_obj_t dest[2]; + mp_load_method_protected(object_in, attr, dest, false); + return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); + +STATIC mp_obj_t mp_builtin_globals(void) { + return MP_OBJ_FROM_PTR(mp_globals_get()); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_builtin_globals); + +STATIC mp_obj_t mp_builtin_locals(void) { + return MP_OBJ_FROM_PTR(mp_locals_get()); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals); + +// These are defined in terms of MicroPython API functions right away +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id); +MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len); + +STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_builtins) }, + + // built-in core functions + { MP_ROM_QSTR(MP_QSTR___build_class__), MP_ROM_PTR(&mp_builtin___build_class___obj) }, + { MP_ROM_QSTR(MP_QSTR___import__), MP_ROM_PTR(&mp_builtin___import___obj) }, + { MP_ROM_QSTR(MP_QSTR___repl_print__), MP_ROM_PTR(&mp_builtin___repl_print___obj) }, + + // built-in types + { MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_PTR(&mp_type_bool) }, + { MP_ROM_QSTR(MP_QSTR_bytes), MP_ROM_PTR(&mp_type_bytes) }, + #if MICROPY_PY_BUILTINS_BYTEARRAY + { MP_ROM_QSTR(MP_QSTR_bytearray), MP_ROM_PTR(&mp_type_bytearray) }, + #endif + #if MICROPY_PY_BUILTINS_COMPLEX + { MP_ROM_QSTR(MP_QSTR_complex), MP_ROM_PTR(&mp_type_complex) }, + #endif + { MP_ROM_QSTR(MP_QSTR_dict), MP_ROM_PTR(&mp_type_dict) }, + #if MICROPY_PY_BUILTINS_ENUMERATE + { MP_ROM_QSTR(MP_QSTR_enumerate), MP_ROM_PTR(&mp_type_enumerate) }, + #endif + #if MICROPY_PY_BUILTINS_FILTER + { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&mp_type_filter) }, + #endif + #if MICROPY_PY_BUILTINS_FLOAT + { MP_ROM_QSTR(MP_QSTR_float), MP_ROM_PTR(&mp_type_float) }, + #endif + #if MICROPY_PY_BUILTINS_SET && MICROPY_PY_BUILTINS_FROZENSET + { MP_ROM_QSTR(MP_QSTR_frozenset), MP_ROM_PTR(&mp_type_frozenset) }, + #endif + { MP_ROM_QSTR(MP_QSTR_int), MP_ROM_PTR(&mp_type_int) }, + { MP_ROM_QSTR(MP_QSTR_list), MP_ROM_PTR(&mp_type_list) }, + { MP_ROM_QSTR(MP_QSTR_map), MP_ROM_PTR(&mp_type_map) }, + #if MICROPY_PY_BUILTINS_MEMORYVIEW + { MP_ROM_QSTR(MP_QSTR_memoryview), MP_ROM_PTR(&mp_type_memoryview) }, + #endif + { MP_ROM_QSTR(MP_QSTR_object), MP_ROM_PTR(&mp_type_object) }, + #if MICROPY_PY_BUILTINS_PROPERTY + { MP_ROM_QSTR(MP_QSTR_property), MP_ROM_PTR(&mp_type_property) }, + #endif + { MP_ROM_QSTR(MP_QSTR_range), MP_ROM_PTR(&mp_type_range) }, + #if MICROPY_PY_BUILTINS_REVERSED + { MP_ROM_QSTR(MP_QSTR_reversed), MP_ROM_PTR(&mp_type_reversed) }, + #endif + #if MICROPY_PY_BUILTINS_SET + { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mp_type_set) }, + #endif + #if MICROPY_PY_BUILTINS_SLICE + { MP_ROM_QSTR(MP_QSTR_slice), MP_ROM_PTR(&mp_type_slice) }, + #endif + { MP_ROM_QSTR(MP_QSTR_str), MP_ROM_PTR(&mp_type_str) }, + { MP_ROM_QSTR(MP_QSTR_super), MP_ROM_PTR(&mp_type_super) }, + { MP_ROM_QSTR(MP_QSTR_tuple), MP_ROM_PTR(&mp_type_tuple) }, + { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&mp_type_type) }, + { MP_ROM_QSTR(MP_QSTR_zip), MP_ROM_PTR(&mp_type_zip) }, + + { MP_ROM_QSTR(MP_QSTR_classmethod), MP_ROM_PTR(&mp_type_classmethod) }, + { MP_ROM_QSTR(MP_QSTR_staticmethod), MP_ROM_PTR(&mp_type_staticmethod) }, + + // built-in objects + { MP_ROM_QSTR(MP_QSTR_Ellipsis), MP_ROM_PTR(&mp_const_ellipsis_obj) }, + #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED + { MP_ROM_QSTR(MP_QSTR_NotImplemented), MP_ROM_PTR(&mp_const_notimplemented_obj) }, + #endif + + // built-in user functions + { MP_ROM_QSTR(MP_QSTR_abs), MP_ROM_PTR(&mp_builtin_abs_obj) }, + { MP_ROM_QSTR(MP_QSTR_all), MP_ROM_PTR(&mp_builtin_all_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&mp_builtin_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_bin), MP_ROM_PTR(&mp_builtin_bin_obj) }, + { MP_ROM_QSTR(MP_QSTR_callable), MP_ROM_PTR(&mp_builtin_callable_obj) }, + #if MICROPY_PY_BUILTINS_COMPILE + { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mp_builtin_compile_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, + { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, + #if MICROPY_PY_BUILTINS_EVAL_EXEC + { MP_ROM_QSTR(MP_QSTR_eval), MP_ROM_PTR(&mp_builtin_eval_obj) }, + { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&mp_builtin_exec_obj) }, + #endif + #if MICROPY_PY_BUILTINS_EXECFILE + { MP_ROM_QSTR(MP_QSTR_execfile), MP_ROM_PTR(&mp_builtin_execfile_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_getattr), MP_ROM_PTR(&mp_builtin_getattr_obj) }, + { MP_ROM_QSTR(MP_QSTR_setattr), MP_ROM_PTR(&mp_builtin_setattr_obj) }, + { MP_ROM_QSTR(MP_QSTR_globals), MP_ROM_PTR(&mp_builtin_globals_obj) }, + { MP_ROM_QSTR(MP_QSTR_hasattr), MP_ROM_PTR(&mp_builtin_hasattr_obj) }, + { MP_ROM_QSTR(MP_QSTR_hash), MP_ROM_PTR(&mp_builtin_hash_obj) }, + #if MICROPY_PY_BUILTINS_HELP + { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&mp_builtin_help_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_hex), MP_ROM_PTR(&mp_builtin_hex_obj) }, + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&mp_builtin_id_obj) }, + #if MICROPY_PY_BUILTINS_INPUT + { MP_ROM_QSTR(MP_QSTR_input), MP_ROM_PTR(&mp_builtin_input_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_isinstance), MP_ROM_PTR(&mp_builtin_isinstance_obj) }, + { MP_ROM_QSTR(MP_QSTR_issubclass), MP_ROM_PTR(&mp_builtin_issubclass_obj) }, + { MP_ROM_QSTR(MP_QSTR_iter), MP_ROM_PTR(&mp_builtin_iter_obj) }, + { MP_ROM_QSTR(MP_QSTR_len), MP_ROM_PTR(&mp_builtin_len_obj) }, + { MP_ROM_QSTR(MP_QSTR_locals), MP_ROM_PTR(&mp_builtin_locals_obj) }, + #if MICROPY_PY_BUILTINS_MIN_MAX + { MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&mp_builtin_max_obj) }, + { MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&mp_builtin_min_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&mp_builtin_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_oct), MP_ROM_PTR(&mp_builtin_oct_obj) }, + { MP_ROM_QSTR(MP_QSTR_ord), MP_ROM_PTR(&mp_builtin_ord_obj) }, + { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_builtin_pow_obj) }, + { MP_ROM_QSTR(MP_QSTR_print), MP_ROM_PTR(&mp_builtin_print_obj) }, + { MP_ROM_QSTR(MP_QSTR_repr), MP_ROM_PTR(&mp_builtin_repr_obj) }, + { MP_ROM_QSTR(MP_QSTR_round), MP_ROM_PTR(&mp_builtin_round_obj) }, + { MP_ROM_QSTR(MP_QSTR_sorted), MP_ROM_PTR(&mp_builtin_sorted_obj) }, + { MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&mp_builtin_sum_obj) }, + + // built-in exceptions + { MP_ROM_QSTR(MP_QSTR_BaseException), MP_ROM_PTR(&mp_type_BaseException) }, + { MP_ROM_QSTR(MP_QSTR_ArithmeticError), MP_ROM_PTR(&mp_type_ArithmeticError) }, + { MP_ROM_QSTR(MP_QSTR_AssertionError), MP_ROM_PTR(&mp_type_AssertionError) }, + { MP_ROM_QSTR(MP_QSTR_AttributeError), MP_ROM_PTR(&mp_type_AttributeError) }, + { MP_ROM_QSTR(MP_QSTR_EOFError), MP_ROM_PTR(&mp_type_EOFError) }, + { MP_ROM_QSTR(MP_QSTR_Exception), MP_ROM_PTR(&mp_type_Exception) }, + { MP_ROM_QSTR(MP_QSTR_GeneratorExit), MP_ROM_PTR(&mp_type_GeneratorExit) }, + { MP_ROM_QSTR(MP_QSTR_ImportError), MP_ROM_PTR(&mp_type_ImportError) }, + { MP_ROM_QSTR(MP_QSTR_IndentationError), MP_ROM_PTR(&mp_type_IndentationError) }, + { MP_ROM_QSTR(MP_QSTR_IndexError), MP_ROM_PTR(&mp_type_IndexError) }, + { MP_ROM_QSTR(MP_QSTR_KeyboardInterrupt), MP_ROM_PTR(&mp_type_KeyboardInterrupt) }, + { MP_ROM_QSTR(MP_QSTR_KeyError), MP_ROM_PTR(&mp_type_KeyError) }, + { MP_ROM_QSTR(MP_QSTR_LookupError), MP_ROM_PTR(&mp_type_LookupError) }, + { MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_MemoryError) }, + { MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) }, + { MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) }, + { MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) }, + { MP_ROM_QSTR(MP_QSTR_OverflowError), MP_ROM_PTR(&mp_type_OverflowError) }, + { MP_ROM_QSTR(MP_QSTR_RuntimeError), MP_ROM_PTR(&mp_type_RuntimeError) }, + #if MICROPY_PY_ASYNC_AWAIT + { MP_ROM_QSTR(MP_QSTR_StopAsyncIteration), MP_ROM_PTR(&mp_type_StopAsyncIteration) }, + #endif + { MP_ROM_QSTR(MP_QSTR_StopIteration), MP_ROM_PTR(&mp_type_StopIteration) }, + { MP_ROM_QSTR(MP_QSTR_SyntaxError), MP_ROM_PTR(&mp_type_SyntaxError) }, + { MP_ROM_QSTR(MP_QSTR_SystemExit), MP_ROM_PTR(&mp_type_SystemExit) }, + { MP_ROM_QSTR(MP_QSTR_TypeError), MP_ROM_PTR(&mp_type_TypeError) }, + #if MICROPY_PY_BUILTINS_STR_UNICODE + { MP_ROM_QSTR(MP_QSTR_UnicodeError), MP_ROM_PTR(&mp_type_UnicodeError) }, + #endif + { MP_ROM_QSTR(MP_QSTR_ValueError), MP_ROM_PTR(&mp_type_ValueError) }, + #if MICROPY_EMIT_NATIVE + { MP_ROM_QSTR(MP_QSTR_ViperTypeError), MP_ROM_PTR(&mp_type_ViperTypeError) }, + #endif + { MP_ROM_QSTR(MP_QSTR_ZeroDivisionError), MP_ROM_PTR(&mp_type_ZeroDivisionError) }, + // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ + // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation + + // Extra builtins as defined by a port + MICROPY_PORT_BUILTINS +}; + +MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table); + +const mp_obj_module_t mp_module_builtins = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_builtins_globals, +}; diff --git a/src/openmv/src/micropython/py/modcmath.c b/src/openmv/src/micropython/py/modcmath.c new file mode 100755 index 0000000..70fd542 --- /dev/null +++ b/src/openmv/src/micropython/py/modcmath.c @@ -0,0 +1,152 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH + +#include + +// phase(z): returns the phase of the number z in the range (-pi, +pi] +STATIC mp_obj_t mp_cmath_phase(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase); + +// polar(z): returns the polar form of z as a tuple +STATIC mp_obj_t mp_cmath_polar(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_obj_t tuple[2] = { + mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)), + mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)), + }; + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar); + +// rect(r, phi): returns the complex number with modulus r and phase phi +STATIC mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) { + mp_float_t r = mp_obj_get_float(r_obj); + mp_float_t phi = mp_obj_get_float(phi_obj); + return mp_obj_new_complex(r * MICROPY_FLOAT_C_FUN(cos)(phi), r * MICROPY_FLOAT_C_FUN(sin)(phi)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect); + +// exp(z): return the exponential of z +STATIC mp_obj_t mp_cmath_exp(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_float_t exp_real = MICROPY_FLOAT_C_FUN(exp)(real); + return mp_obj_new_complex(exp_real * MICROPY_FLOAT_C_FUN(cos)(imag), exp_real * MICROPY_FLOAT_C_FUN(sin)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp); + +// log(z): return the natural logarithm of z, with branch cut along the negative real axis +// TODO can take second argument, being the base +STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real*real + imag*imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log); + +#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS +// log10(z): return the base-10 logarithm of z, with branch cut along the negative real axis +STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real*real + imag*imag), 0.4342944819032518 * MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10); +#endif + +// sqrt(z): return the square-root of z +STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real*real + imag*imag, 0.25); + mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real); + return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt); + +// cos(z): return the cosine of z +STATIC mp_obj_t mp_cmath_cos(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), -MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos); + +// sin(z): return the sine of z +STATIC mp_obj_t mp_cmath_sin(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sin_obj, mp_cmath_sin); + +STATIC const mp_rom_map_elem_t mp_module_cmath_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cmath) }, + { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e }, + { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi }, + { MP_ROM_QSTR(MP_QSTR_phase), MP_ROM_PTR(&mp_cmath_phase_obj) }, + { MP_ROM_QSTR(MP_QSTR_polar), MP_ROM_PTR(&mp_cmath_polar_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&mp_cmath_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_cmath_exp_obj) }, + { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_cmath_log_obj) }, + #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS + { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_cmath_log10_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_cmath_sqrt_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_cmath_acos_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_cmath_asin_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_cmath_atan_obj) }, + { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_cmath_cos_obj) }, + { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_cmath_sin_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_cmath_tan_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_cmath_acosh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_cmath_asinh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_cmath_atanh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_cmath_cosh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_cmath_sinh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_cmath_tanh_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_cmath_isfinite_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_cmath_isinf_obj) }, + //{ MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_cmath_isnan_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_cmath_globals, mp_module_cmath_globals_table); + +const mp_obj_module_t mp_module_cmath = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_cmath_globals, +}; + +#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH diff --git a/src/openmv/src/micropython/py/modcollections.c b/src/openmv/src/micropython/py/modcollections.c new file mode 100755 index 0000000..bb64884 --- /dev/null +++ b/src/openmv/src/micropython/py/modcollections.c @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +#if MICROPY_PY_COLLECTIONS + +STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) }, + #if MICROPY_PY_COLLECTIONS_DEQUE + { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) }, + #endif + { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) }, + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections_globals_table); + +const mp_obj_module_t mp_module_collections = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_collections_globals, +}; + +#endif // MICROPY_PY_COLLECTIONS diff --git a/src/openmv/src/micropython/py/modgc.c b/src/openmv/src/micropython/py/modgc.c new file mode 100755 index 0000000..55e73de --- /dev/null +++ b/src/openmv/src/micropython/py/modgc.c @@ -0,0 +1,118 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" +#include "py/obj.h" +#include "py/gc.h" + +#if MICROPY_PY_GC && MICROPY_ENABLE_GC + +// collect(): run a garbage collection +STATIC mp_obj_t py_gc_collect(void) { + gc_collect(); +#if MICROPY_PY_GC_COLLECT_RETVAL + return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_collected)); +#else + return mp_const_none; +#endif +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect); + +// disable(): disable the garbage collector +STATIC mp_obj_t gc_disable(void) { + MP_STATE_MEM(gc_auto_collect_enabled) = 0; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable); + +// enable(): enable the garbage collector +STATIC mp_obj_t gc_enable(void) { + MP_STATE_MEM(gc_auto_collect_enabled) = 1; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable); + +STATIC mp_obj_t gc_isenabled(void) { + return mp_obj_new_bool(MP_STATE_MEM(gc_auto_collect_enabled)); +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled); + +// mem_free(): return the number of bytes of available heap RAM +STATIC mp_obj_t gc_mem_free(void) { + gc_info_t info; + gc_info(&info); + return MP_OBJ_NEW_SMALL_INT(info.free); +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free); + +// mem_alloc(): return the number of bytes of heap RAM that are allocated +STATIC mp_obj_t gc_mem_alloc(void) { + gc_info_t info; + gc_info(&info); + return MP_OBJ_NEW_SMALL_INT(info.used); +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc); + +#if MICROPY_GC_ALLOC_THRESHOLD +STATIC mp_obj_t gc_threshold(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_MEM(gc_alloc_threshold) == (size_t)-1) { + return MP_OBJ_NEW_SMALL_INT(-1); + } + return mp_obj_new_int(MP_STATE_MEM(gc_alloc_threshold) * MICROPY_BYTES_PER_GC_BLOCK); + } + mp_int_t val = mp_obj_get_int(args[0]); + if (val < 0) { + MP_STATE_MEM(gc_alloc_threshold) = (size_t)-1; + } else { + MP_STATE_MEM(gc_alloc_threshold) = val / MICROPY_BYTES_PER_GC_BLOCK; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gc_threshold_obj, 0, 1, gc_threshold); +#endif + +STATIC const mp_rom_map_elem_t mp_module_gc_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gc) }, + { MP_ROM_QSTR(MP_QSTR_collect), MP_ROM_PTR(&gc_collect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&gc_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&gc_enable_obj) }, + { MP_ROM_QSTR(MP_QSTR_isenabled), MP_ROM_PTR(&gc_isenabled_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_free), MP_ROM_PTR(&gc_mem_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_alloc), MP_ROM_PTR(&gc_mem_alloc_obj) }, + #if MICROPY_GC_ALLOC_THRESHOLD + { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&gc_threshold_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table); + +const mp_obj_module_t mp_module_gc = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_gc_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/py/modio.c b/src/openmv/src/micropython/py/modio.c new file mode 100755 index 0000000..e75432b --- /dev/null +++ b/src/openmv/src/micropython/py/modio.c @@ -0,0 +1,284 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/stream.h" +#include "py/binary.h" +#include "py/objarray.h" +#include "py/objstringio.h" +#include "py/frozenmod.h" + +#if MICROPY_PY_IO + +extern const mp_obj_type_t mp_type_fileio; +extern const mp_obj_type_t mp_type_textio; + +#if MICROPY_PY_IO_IOBASE + +STATIC const mp_obj_type_t mp_type_iobase; + +STATIC mp_obj_base_t iobase_singleton = {&mp_type_iobase}; + +STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)args; + return MP_OBJ_FROM_PTR(&iobase_singleton); +} + +STATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode, qstr qst) { + mp_obj_t dest[3]; + mp_load_method(obj, qst, dest); + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf}; + dest[2] = MP_OBJ_FROM_PTR(&ar); + mp_obj_t ret = mp_call_method_n_kw(1, 0, dest); + if (ret == mp_const_none) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } else { + return mp_obj_get_int(ret); + } +} +STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, buf, size, errcode, MP_QSTR_readinto); +} + +STATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, (void*)buf, size, errcode, MP_QSTR_write); +} + +STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_t dest[4]; + mp_load_method(obj, MP_QSTR_ioctl, dest); + dest[2] = mp_obj_new_int_from_uint(request); + dest[3] = mp_obj_new_int_from_uint(arg); + mp_int_t ret = mp_obj_get_int(mp_call_method_n_kw(2, 0, dest)); + if (ret >= 0) { + return ret; + } else { + *errcode = -ret; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_stream_p_t iobase_p = { + .read = iobase_read, + .write = iobase_write, + .ioctl = iobase_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_iobase = { + { &mp_type_type }, + .name = MP_QSTR_IOBase, + .make_new = iobase_make_new, + .protocol = &iobase_p, +}; + +#endif // MICROPY_PY_IO_IOBASE + +#if MICROPY_PY_IO_BUFFEREDWRITER +typedef struct _mp_obj_bufwriter_t { + mp_obj_base_t base; + mp_obj_t stream; + size_t alloc; + size_t len; + byte buf[0]; +} mp_obj_bufwriter_t; + +STATIC mp_obj_t bufwriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + size_t alloc = mp_obj_get_int(args[1]); + mp_obj_bufwriter_t *o = m_new_obj_var(mp_obj_bufwriter_t, byte, alloc); + o->base.type = type; + o->stream = args[0]; + o->alloc = alloc; + o->len = 0; + return o; +} + +STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in); + + mp_uint_t org_size = size; + + while (size > 0) { + mp_uint_t rem = self->alloc - self->len; + if (size < rem) { + memcpy(self->buf + self->len, buf, size); + self->len += size; + return org_size; + } + + // Buffer flushing policy here is to flush entire buffer all the time. + // This allows e.g. to have a block device as backing storage and write + // entire block to it. memcpy below is not ideal and could be optimized + // in some cases. But the way it is now it at least ensures that buffer + // is word-aligned, to guard against obscure cases when it matters, e.g. + // https://github.com/micropython/micropython/issues/1863 + memcpy(self->buf + self->len, buf, rem); + buf = (byte*)buf + rem; + size -= rem; + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); + if (*errcode != 0) { + return MP_STREAM_ERROR; + } + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->alloc); + self->len = 0; + } + + return org_size; +} + +STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { + mp_obj_bufwriter_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->len != 0) { + int err; + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->len); + self->len = 0; + if (err != 0) { + mp_raise_OSError(err); + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bufwriter_flush_obj, bufwriter_flush); + +STATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&bufwriter_flush_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table); + +STATIC const mp_stream_p_t bufwriter_stream_p = { + .write = bufwriter_write, +}; + +STATIC const mp_obj_type_t bufwriter_type = { + { &mp_type_type }, + .name = MP_QSTR_BufferedWriter, + .make_new = bufwriter_make_new, + .protocol = &bufwriter_stream_p, + .locals_dict = (mp_obj_dict_t*)&bufwriter_locals_dict, +}; +#endif // MICROPY_PY_IO_BUFFEREDWRITER + +#if MICROPY_PY_IO_RESOURCE_STREAM +STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { + VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); + size_t len; + + // As an extension to pkg_resources.resource_stream(), we support + // package parameter being None, the path_in is interpreted as a + // raw path. + if (package_in != mp_const_none) { + mp_obj_t args[5]; + args[0] = package_in; + args[1] = mp_const_none; // TODO should be globals + args[2] = mp_const_none; // TODO should be locals + args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module + args[4] = MP_OBJ_NEW_SMALL_INT(0); + + // TODO lookup __import__ and call that instead of going straight to builtin implementation + mp_obj_t pkg = mp_builtin___import__(5, args); + + mp_obj_t dest[2]; + mp_load_method_maybe(pkg, MP_QSTR___path__, dest); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError(NULL); + } + + const char *path = mp_obj_str_get_data(dest[0], &len); + vstr_add_strn(&path_buf, path, len); + vstr_add_byte(&path_buf, '/'); + } + + const char *path = mp_obj_str_get_data(path_in, &len); + vstr_add_strn(&path_buf, path, len); + + len = path_buf.len; + const char *data = mp_find_frozen_str(path_buf.buf, &len); + if (data != NULL) { + mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); + o->base.type = &mp_type_bytesio; + o->vstr = m_new_obj(vstr_t); + vstr_init_fixed_buf(o->vstr, len + 1, (char*)data); + o->vstr->len = len; + o->pos = 0; + return MP_OBJ_FROM_PTR(o); + } + + mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); + return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); +#endif + +STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) }, + // Note: mp_builtin_open_obj should be defined by port, it's not + // part of the core. + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + #if MICROPY_PY_IO_IOBASE + { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) }, + #endif + #if MICROPY_PY_IO_RESOURCE_STREAM + { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, + #endif + #if MICROPY_PY_IO_FILEIO + { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_TextIOWrapper), MP_ROM_PTR(&mp_type_textio) }, + #endif + #endif + { MP_ROM_QSTR(MP_QSTR_StringIO), MP_ROM_PTR(&mp_type_stringio) }, + #if MICROPY_PY_IO_BYTESIO + { MP_ROM_QSTR(MP_QSTR_BytesIO), MP_ROM_PTR(&mp_type_bytesio) }, + #endif + #if MICROPY_PY_IO_BUFFEREDWRITER + { MP_ROM_QSTR(MP_QSTR_BufferedWriter), MP_ROM_PTR(&bufwriter_type) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table); + +const mp_obj_module_t mp_module_io = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_io_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/py/modmath.c b/src/openmv/src/micropython/py/modmath.c new file mode 100755 index 0000000..d106f24 --- /dev/null +++ b/src/openmv/src/micropython/py/modmath.c @@ -0,0 +1,359 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH + +#include + +// M_PI is not part of the math.h standard and may not be defined +// And by defining our own we can ensure it uses the correct const format. +#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) + +STATIC NORETURN void math_error(void) { + mp_raise_ValueError("math domain error"); +} + +STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) { + mp_float_t x = mp_obj_get_float(x_obj); + mp_float_t ans = f(x); + if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) { + math_error(); + } + return mp_obj_new_float(ans); +} + +STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(mp_float_t, mp_float_t)) { + mp_float_t x = mp_obj_get_float(x_obj); + mp_float_t y = mp_obj_get_float(y_obj); + mp_float_t ans = f(x, y); + if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) { + math_error(); + } + return mp_obj_new_float(ans); +} + +#define MATH_FUN_1(py_name, c_name) \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \ + return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \ + } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); + +#define MATH_FUN_1_TO_BOOL(py_name, c_name) \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); + +#define MATH_FUN_1_TO_INT(py_name, c_name) \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); + +#define MATH_FUN_2(py_name, c_name) \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \ + return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \ + } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name); + +#define MATH_FUN_2_FLT_INT(py_name, c_name) \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \ + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \ + } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name); + +#if MP_NEED_LOG2 +#undef log2 +#undef log2f +// 1.442695040888963407354163704 is 1/_M_LN2 +mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) { + return MICROPY_FLOAT_C_FUN(log)(x) * MICROPY_FLOAT_CONST(1.442695040888963407354163704); +} +#endif + +// sqrt(x): returns the square root of x +MATH_FUN_1(sqrt, sqrt) +// pow(x, y): returns x to the power of y +MATH_FUN_2(pow, pow) +// exp(x) +MATH_FUN_1(exp, exp) +#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS +// expm1(x) +MATH_FUN_1(expm1, expm1) +// log2(x) +MATH_FUN_1(log2, log2) +// log10(x) +MATH_FUN_1(log10, log10) +// cosh(x) +MATH_FUN_1(cosh, cosh) +// sinh(x) +MATH_FUN_1(sinh, sinh) +// tanh(x) +MATH_FUN_1(tanh, tanh) +// acosh(x) +MATH_FUN_1(acosh, acosh) +// asinh(x) +MATH_FUN_1(asinh, asinh) +// atanh(x) +MATH_FUN_1(atanh, atanh) +#endif +// cos(x) +MATH_FUN_1(cos, cos) +// sin(x) +MATH_FUN_1(sin, sin) +// tan(x) +MATH_FUN_1(tan, tan) +// acos(x) +MATH_FUN_1(acos, acos) +// asin(x) +MATH_FUN_1(asin, asin) +// atan(x) +MATH_FUN_1(atan, atan) +// atan2(y, x) +MATH_FUN_2(atan2, atan2) +// ceil(x) +MATH_FUN_1_TO_INT(ceil, ceil) +// copysign(x, y) +STATIC mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) { + return MICROPY_FLOAT_C_FUN(copysign)(x, y); +} +MATH_FUN_2(copysign, copysign_func) +// fabs(x) +STATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) { + return MICROPY_FLOAT_C_FUN(fabs)(x); +} +MATH_FUN_1(fabs, fabs_func) +// floor(x) +MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float +// fmod(x, y) +MATH_FUN_2(fmod, fmod) +// isfinite(x) +MATH_FUN_1_TO_BOOL(isfinite, isfinite) +// isinf(x) +MATH_FUN_1_TO_BOOL(isinf, isinf) +// isnan(x) +MATH_FUN_1_TO_BOOL(isnan, isnan) +// trunc(x) +MATH_FUN_1_TO_INT(trunc, trunc) +// ldexp(x, exp) +MATH_FUN_2_FLT_INT(ldexp, ldexp) +#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS +// erf(x): return the error function of x +MATH_FUN_1(erf, erf) +// erfc(x): return the complementary error function of x +MATH_FUN_1(erfc, erfc) +// gamma(x): return the gamma function of x +MATH_FUN_1(gamma, tgamma) +// lgamma(x): return the natural logarithm of the gamma function of x +MATH_FUN_1(lgamma, lgamma) +#endif +//TODO: fsum + +// Function that takes a variable number of arguments + +// log(x[, base]) +STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) { + mp_float_t x = mp_obj_get_float(args[0]); + if (x <= (mp_float_t)0.0) { + math_error(); + } + mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x); + if (n_args == 1) { + return mp_obj_new_float(l); + } else { + mp_float_t base = mp_obj_get_float(args[1]); + if (base <= (mp_float_t)0.0) { + math_error(); + } else if (base == (mp_float_t)1.0) { + mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + } + return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log); + +// Functions that return a tuple + +// frexp(x): converts a floating-point number to fractional and integral components +STATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) { + int int_exponent = 0; + mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_float(significand); + tuple[1] = mp_obj_new_int(int_exponent); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp); + +// modf(x) +STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) { + mp_float_t int_part = 0.0; + mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_float(fractional_part); + tuple[1] = mp_obj_new_float(int_part); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf); + +// Angular conversions + +// radians(x) +STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) { + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians); + +// degrees(x) +STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) { + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees); + +#if MICROPY_PY_MATH_FACTORIAL + +#if MICROPY_OPT_MATH_FACTORIAL + +// factorial(x): slightly efficient recursive implementation +STATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) { + if (start == end) { + return mp_obj_new_int(start); + } else if (end - start == 1) { + return mp_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end)); + } else if (end - start == 2) { + mp_obj_t left = MP_OBJ_NEW_SMALL_INT(start); + mp_obj_t middle = MP_OBJ_NEW_SMALL_INT(start + 1); + mp_obj_t right = MP_OBJ_NEW_SMALL_INT(end); + mp_obj_t tmp = mp_binary_op(MP_BINARY_OP_MULTIPLY, left, middle); + return mp_binary_op(MP_BINARY_OP_MULTIPLY, tmp, right); + } else { + mp_uint_t middle = start + ((end - start) >> 1); + mp_obj_t left = mp_math_factorial_inner(start, middle); + mp_obj_t right = mp_math_factorial_inner(middle + 1, end); + return mp_binary_op(MP_BINARY_OP_MULTIPLY, left, right); + } +} +STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) { + mp_int_t max = mp_obj_get_int(x_obj); + if (max < 0) { + mp_raise_msg(&mp_type_ValueError, "negative factorial"); + } else if (max == 0) { + return MP_OBJ_NEW_SMALL_INT(1); + } + return mp_math_factorial_inner(1, max); +} + +#else + +// factorial(x): squared difference implementation +// based on http://www.luschny.de/math/factorial/index.html +STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) { + mp_int_t max = mp_obj_get_int(x_obj); + if (max < 0) { + mp_raise_msg(&mp_type_ValueError, "negative factorial"); + } else if (max <= 1) { + return MP_OBJ_NEW_SMALL_INT(1); + } + mp_int_t h = max >> 1; + mp_int_t q = h * h; + mp_int_t r = q << 1; + if (max & 1) { + r *= max; + } + mp_obj_t prod = MP_OBJ_NEW_SMALL_INT(r); + for (mp_int_t num = 1; num < max - 2; num += 2) { + q -= num; + prod = mp_binary_op(MP_BINARY_OP_MULTIPLY, prod, MP_OBJ_NEW_SMALL_INT(q)); + } + return prod; +} + +#endif + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_factorial_obj, mp_math_factorial); + +#endif + +STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) }, + { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e }, + { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi }, + { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) }, + { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) }, + { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) }, + #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS + { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) }, + #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS + { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) }, + { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) }, + { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) }, + { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) }, + { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) }, + { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) }, + { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) }, + { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) }, + { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) }, + { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) }, + { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) }, + { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) }, + { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) }, + { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) }, + { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) }, + { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) }, + { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) }, + { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) }, + { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) }, + { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) }, + { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) }, + { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) }, + { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) }, + { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) }, + { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) }, + { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) }, + { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) }, + { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) }, + #if MICROPY_PY_MATH_FACTORIAL + { MP_ROM_QSTR(MP_QSTR_factorial), MP_ROM_PTR(&mp_math_factorial_obj) }, + #endif + #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS + { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) }, + { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) }, + { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) }, + { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table); + +const mp_obj_module_t mp_module_math = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_math_globals, +}; + +#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH diff --git a/src/openmv/src/micropython/py/modmicropython.c b/src/openmv/src/micropython/py/modmicropython.c new file mode 100755 index 0000000..864d1a5 --- /dev/null +++ b/src/openmv/src/micropython/py/modmicropython.c @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/builtin.h" +#include "py/stackctrl.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" + +// Various builtins specific to MicroPython runtime, +// living in micropython module + +#if MICROPY_ENABLE_COMPILER +STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); + } else { + MP_STATE_VM(mp_optimise_value) = mp_obj_get_int(args[0]); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); +#endif + +#if MICROPY_PY_MICROPYTHON_MEM_INFO + +#if MICROPY_MEM_STATS +STATIC mp_obj_t mp_micropython_mem_total(void) { + return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total); + +STATIC mp_obj_t mp_micropython_mem_current(void) { + return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_mem_current); + +STATIC mp_obj_t mp_micropython_mem_peak(void) { + return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak); +#endif + +mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) { + (void)args; +#if MICROPY_MEM_STATS + mp_printf(&mp_plat_print, "mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n", + (mp_uint_t)m_get_total_bytes_allocated(), (mp_uint_t)m_get_current_bytes_allocated(), (mp_uint_t)m_get_peak_bytes_allocated()); +#endif +#if MICROPY_STACK_CHECK + mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " UINT_FMT "\n", + mp_stack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit)); +#else + mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_stack_usage()); +#endif +#if MICROPY_ENABLE_GC + gc_dump_info(); + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } +#else + (void)n_args; +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_mem_info_obj, 0, 1, mp_micropython_mem_info); + +STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { + (void)args; + size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + mp_printf(&mp_plat_print, "qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", + n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + if (n_args == 1) { + // arg given means dump qstr data + qstr_dump_data(); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info); + +#endif // MICROPY_PY_MICROPYTHON_MEM_INFO + +#if MICROPY_PY_MICROPYTHON_STACK_USE +STATIC mp_obj_t mp_micropython_stack_use(void) { + return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); +#endif + +#if MICROPY_ENABLE_PYSTACK +STATIC mp_obj_t mp_micropython_pystack_use(void) { + return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_pystack_use_obj, mp_micropython_pystack_use); +#endif + +#if MICROPY_ENABLE_GC +STATIC mp_obj_t mp_micropython_heap_lock(void) { + gc_lock(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_heap_lock); + +STATIC mp_obj_t mp_micropython_heap_unlock(void) { + gc_unlock(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock); +#endif + +#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf); +#endif + +#if MICROPY_KBD_EXCEPTION +STATIC mp_obj_t mp_micropython_kbd_intr(mp_obj_t int_chr_in) { + mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd_intr); +#endif + +#if MICROPY_ENABLE_SCHEDULER +STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { + if (!mp_sched_schedule(function, arg)) { + mp_raise_msg(&mp_type_RuntimeError, "schedule stack full"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule); +#endif + +STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, + { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, + #if MICROPY_ENABLE_COMPILER + { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, + #endif +#if MICROPY_PY_MICROPYTHON_MEM_INFO +#if MICROPY_MEM_STATS + { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_current), MP_ROM_PTR(&mp_micropython_mem_current_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_peak), MP_ROM_PTR(&mp_micropython_mem_peak_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) }, +#endif + #if MICROPY_PY_MICROPYTHON_STACK_USE + { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) }, + #endif +#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) + { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, +#endif + #if MICROPY_ENABLE_PYSTACK + { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) }, + #endif + #if MICROPY_ENABLE_GC + { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) }, + #endif + #if MICROPY_KBD_EXCEPTION + { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) }, + #endif + #if MICROPY_ENABLE_SCHEDULER + { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython_globals_table); + +const mp_obj_module_t mp_module_micropython = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_micropython_globals, +}; diff --git a/src/openmv/src/micropython/py/modstruct.c b/src/openmv/src/micropython/py/modstruct.c new file mode 100755 index 0000000..8617a8e --- /dev/null +++ b/src/openmv/src/micropython/py/modstruct.c @@ -0,0 +1,267 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/objtuple.h" +#include "py/binary.h" +#include "py/parsenum.h" + +#if MICROPY_PY_STRUCT + +/* + This module implements most of character typecodes from CPython, with + some extensions: + + O - (Pointer to) an arbitrary Python object. This is useful for callback + data, etc. Note that you must keep reference to passed object in + your Python application, otherwise it may be garbage-collected, + and then when you get back this value from callback it may be + invalid (and lead to crash). + S - Pointer to a string (returned as a Python string). Note the + difference from "Ns", - the latter says "in this place of structure + is character data of up to N bytes length", while "S" means + "in this place of a structure is a pointer to zero-terminated + character data". + */ + +STATIC char get_fmt_type(const char **fmt) { + char t = **fmt; + switch (t) { + case '!': + t = '>'; + break; + case '@': + case '=': + case '<': + case '>': + break; + default: + return '@'; + } + // Skip type char + (*fmt)++; + return t; +} + +STATIC mp_uint_t get_fmt_num(const char **p) { + const char *num = *p; + uint len = 1; + while (unichar_isdigit(*++num)) { + len++; + } + mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10, NULL)); + *p = num; + return val; +} + +STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) { + char fmt_type = get_fmt_type(&fmt); + size_t total_cnt = 0; + size_t size; + for (size = 0; *fmt; fmt++) { + mp_uint_t cnt = 1; + if (unichar_isdigit(*fmt)) { + cnt = get_fmt_num(&fmt); + } + + if (*fmt == 's') { + total_cnt += 1; + size += cnt; + } else { + total_cnt += cnt; + mp_uint_t align; + size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); + while (cnt--) { + // Apply alignment + size = (size + align - 1) & ~(align - 1); + size += sz; + } + } + } + *total_sz = size; + return total_cnt; +} + +STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { + const char *fmt = mp_obj_str_get_str(fmt_in); + size_t size; + calc_size_items(fmt, &size); + return MP_OBJ_NEW_SMALL_INT(size); +} +MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize); + +STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { + // unpack requires that the buffer be exactly the right size. + // unpack_from requires that the buffer be "big enough". + // Since we implement unpack and unpack_from using the same function + // we relax the "exact" requirement, and only implement "big enough". + const char *fmt = mp_obj_str_get_str(args[0]); + size_t total_sz; + size_t num_items = calc_size_items(fmt, &total_sz); + char fmt_type = get_fmt_type(&fmt); + mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL)); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + byte *p = bufinfo.buf; + byte *end_p = &p[bufinfo.len]; + mp_int_t offset = 0; + + if (n_args > 2) { + // offset arg provided + offset = mp_obj_get_int(args[2]); + if (offset < 0) { + // negative offsets are relative to the end of the buffer + offset = bufinfo.len + offset; + if (offset < 0) { + mp_raise_ValueError("buffer too small"); + } + } + p += offset; + } + + // Check that the input buffer is big enough to unpack all the values + if (p + total_sz > end_p) { + mp_raise_ValueError("buffer too small"); + } + + for (size_t i = 0; i < num_items;) { + mp_uint_t cnt = 1; + if (unichar_isdigit(*fmt)) { + cnt = get_fmt_num(&fmt); + } + mp_obj_t item; + if (*fmt == 's') { + item = mp_obj_new_bytes(p, cnt); + p += cnt; + res->items[i++] = item; + } else { + while (cnt--) { + item = mp_binary_get_val(fmt_type, *fmt, &p); + res->items[i++] = item; + } + } + fmt++; + } + return MP_OBJ_FROM_PTR(res); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_unpack_from_obj, 2, 3, struct_unpack_from); + +// This function assumes there is enough room in p to store all the values +STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, const mp_obj_t *args) { + const char *fmt = mp_obj_str_get_str(fmt_in); + char fmt_type = get_fmt_type(&fmt); + + size_t i; + for (i = 0; i < n_args;) { + mp_uint_t cnt = 1; + if (*fmt == '\0') { + // more arguments given than used by format string; CPython raises struct.error here + break; + } + if (unichar_isdigit(*fmt)) { + cnt = get_fmt_num(&fmt); + } + + if (*fmt == 's') { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ); + mp_uint_t to_copy = cnt; + if (bufinfo.len < to_copy) { + to_copy = bufinfo.len; + } + memcpy(p, bufinfo.buf, to_copy); + memset(p + to_copy, 0, cnt - to_copy); + p += cnt; + } else { + // If we run out of args then we just finish; CPython would raise struct.error + while (cnt-- && i < n_args) { + mp_binary_set_val(fmt_type, *fmt, args[i++], &p); + } + } + fmt++; + } +} + +STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) { + // TODO: "The arguments must match the values required by the format exactly." + mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); + vstr_t vstr; + vstr_init_len(&vstr, size); + byte *p = (byte*)vstr.buf; + memset(p, 0, size); + struct_pack_into_internal(args[0], p, n_args - 1, &args[1]); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack); + +STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + mp_int_t offset = mp_obj_get_int(args[2]); + if (offset < 0) { + // negative offsets are relative to the end of the buffer + offset = (mp_int_t)bufinfo.len + offset; + if (offset < 0) { + mp_raise_ValueError("buffer too small"); + } + } + byte *p = (byte *)bufinfo.buf; + byte *end_p = &p[bufinfo.len]; + p += offset; + + // Check that the output buffer is big enough to hold all the values + mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0])); + if (p + sz > end_p) { + mp_raise_ValueError("buffer too small"); + } + + struct_pack_into_internal(args[0], p, n_args - 3, &args[3]); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_into_obj, 3, MP_OBJ_FUN_ARGS_MAX, struct_pack_into); + +STATIC const mp_rom_map_elem_t mp_module_struct_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ustruct) }, + { MP_ROM_QSTR(MP_QSTR_calcsize), MP_ROM_PTR(&struct_calcsize_obj) }, + { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&struct_pack_obj) }, + { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&struct_pack_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&struct_unpack_from_obj) }, + { MP_ROM_QSTR(MP_QSTR_unpack_from), MP_ROM_PTR(&struct_unpack_from_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_table); + +const mp_obj_module_t mp_module_ustruct = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_struct_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/py/modsys.c b/src/openmv/src/micropython/py/modsys.c new file mode 100755 index 0000000..98addfc --- /dev/null +++ b/src/openmv/src/micropython/py/modsys.c @@ -0,0 +1,215 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" +#include "py/objlist.h" +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/objint.h" +#include "py/objtype.h" +#include "py/stream.h" +#include "py/smallint.h" +#include "py/runtime.h" + +#if MICROPY_PY_SYS + +#include "genhdr/mpversion.h" + +// defined per port; type of these is irrelevant, just need pointer +extern struct _mp_dummy_t mp_sys_stdin_obj; +extern struct _mp_dummy_t mp_sys_stdout_obj; +extern struct _mp_dummy_t mp_sys_stderr_obj; + +#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES +const mp_print_t mp_sys_stdout_print = {&mp_sys_stdout_obj, mp_stream_write_adaptor}; +#endif + +// version - Python language version that this implementation conforms to, as a string +STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0"); + +// version_info - Python language version that this implementation conforms to, as a tuple of ints +#define I(n) MP_OBJ_NEW_SMALL_INT(n) +// TODO: CPython is now at 5-element array, but save 2 els so far... +STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}}; + +// sys.implementation object +// this holds the MicroPython version +STATIC const mp_obj_tuple_t mp_sys_implementation_version_info_obj = { + {&mp_type_tuple}, + 3, + { I(MICROPY_VERSION_MAJOR), I(MICROPY_VERSION_MINOR), I(MICROPY_VERSION_MICRO) } +}; +#if MICROPY_PY_ATTRTUPLE +STATIC const qstr impl_fields[] = { MP_QSTR_name, MP_QSTR_version }; +STATIC MP_DEFINE_ATTRTUPLE( + mp_sys_implementation_obj, + impl_fields, + 2, + MP_ROM_QSTR(MP_QSTR_micropython), + MP_ROM_PTR(&mp_sys_implementation_version_info_obj) +); +#else +STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = { + {&mp_type_tuple}, + 2, + { + MP_ROM_QSTR(MP_QSTR_micropython), + MP_ROM_PTR(&mp_sys_implementation_version_info_obj), + } +}; +#endif + +#undef I + +#ifdef MICROPY_PY_SYS_PLATFORM +// platform - the platform that MicroPython is running on +STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM); +#endif + +// exit([retval]): raise SystemExit, with optional argument given to the exception +STATIC mp_obj_t mp_sys_exit(size_t n_args, const mp_obj_t *args) { + mp_obj_t exc; + if (n_args == 0) { + exc = mp_obj_new_exception(&mp_type_SystemExit); + } else { + exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]); + } + nlr_raise(exc); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit); + +STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) { + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + void *stream_obj = &mp_sys_stdout_obj; + if (n_args > 1) { + mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE); + stream_obj = MP_OBJ_TO_PTR(args[1]); + } + + mp_print_t print = {stream_obj, mp_stream_write_adaptor}; + mp_obj_print_exception(&print, args[0]); + #else + (void)n_args; + mp_obj_print_exception(&mp_plat_print, args[0]); + #endif + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_print_exception_obj, 1, 2, mp_sys_print_exception); + +#if MICROPY_PY_SYS_EXC_INFO +STATIC mp_obj_t mp_sys_exc_info(void) { + mp_obj_t cur_exc = MP_OBJ_FROM_PTR(MP_STATE_VM(cur_exception)); + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + + if (cur_exc == MP_OBJ_NULL) { + t->items[0] = mp_const_none; + t->items[1] = mp_const_none; + t->items[2] = mp_const_none; + return MP_OBJ_FROM_PTR(t); + } + + t->items[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(cur_exc)); + t->items[1] = cur_exc; + t->items[2] = mp_const_none; + return MP_OBJ_FROM_PTR(t); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info); +#endif + +#if MICROPY_PY_SYS_GETSIZEOF +STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { + return mp_unary_op(MP_UNARY_OP_SIZEOF, obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); +#endif + +STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) }, + + { MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&MP_STATE_VM(mp_sys_path_obj)) }, + { MP_ROM_QSTR(MP_QSTR_argv), MP_ROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)) }, + { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&version_obj) }, + { MP_ROM_QSTR(MP_QSTR_version_info), MP_ROM_PTR(&mp_sys_version_info_obj) }, + { MP_ROM_QSTR(MP_QSTR_implementation), MP_ROM_PTR(&mp_sys_implementation_obj) }, + #ifdef MICROPY_PY_SYS_PLATFORM + { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_obj) }, + #endif + #if MP_ENDIANNESS_LITTLE + { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_little) }, + #else + { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_big) }, + #endif + + #if MICROPY_PY_SYS_MAXSIZE + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + // Maximum mp_int_t value is not representable as small int, so we have + // little choice but to use MP_SMALL_INT_MAX. Apps also should be careful + // to not try to compare sys.maxsize to some literal number (as this + // number might not fit in available int size), but instead count number + // of "one" bits in sys.maxsize. + { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_INT(MP_SMALL_INT_MAX) }, + #else + { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_PTR(&mp_maxsize_obj) }, + #endif + #endif + + #if MICROPY_PY_SYS_EXIT + { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) }, + #endif + + #if MICROPY_PY_SYS_STDFILES + { MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) }, + { MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) }, + { MP_ROM_QSTR(MP_QSTR_stderr), MP_ROM_PTR(&mp_sys_stderr_obj) }, + #endif + + #if MICROPY_PY_SYS_MODULES + { MP_ROM_QSTR(MP_QSTR_modules), MP_ROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)) }, + #endif + #if MICROPY_PY_SYS_EXC_INFO + { MP_ROM_QSTR(MP_QSTR_exc_info), MP_ROM_PTR(&mp_sys_exc_info_obj) }, + #endif + #if MICROPY_PY_SYS_GETSIZEOF + { MP_ROM_QSTR(MP_QSTR_getsizeof), MP_ROM_PTR(&mp_sys_getsizeof_obj) }, + #endif + + /* + * Extensions to CPython + */ + + { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&mp_sys_print_exception_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table); + +const mp_obj_module_t mp_module_sys = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_sys_globals, +}; + +#endif diff --git a/src/openmv/src/micropython/py/modthread.c b/src/openmv/src/micropython/py/modthread.c new file mode 100755 index 0000000..61ada50 --- /dev/null +++ b/src/openmv/src/micropython/py/modthread.c @@ -0,0 +1,300 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/stackctrl.h" + +#if MICROPY_PY_THREAD + +#include "py/mpthread.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +/****************************************************************/ +// Lock object + +STATIC const mp_obj_type_t mp_type_thread_lock; + +typedef struct _mp_obj_thread_lock_t { + mp_obj_base_t base; + mp_thread_mutex_t mutex; + volatile bool locked; +} mp_obj_thread_lock_t; + +STATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) { + mp_obj_thread_lock_t *self = m_new_obj(mp_obj_thread_lock_t); + self->base.type = &mp_type_thread_lock; + mp_thread_mutex_init(&self->mutex); + self->locked = false; + return self; +} + +STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]); + bool wait = true; + if (n_args > 1) { + wait = mp_obj_get_int(args[1]); + // TODO support timeout arg + } + MP_THREAD_GIL_EXIT(); + int ret = mp_thread_mutex_lock(&self->mutex, wait); + MP_THREAD_GIL_ENTER(); + if (ret == 0) { + return mp_const_false; + } else if (ret == 1) { + self->locked = true; + return mp_const_true; + } else { + mp_raise_OSError(-ret); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire); + +STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->locked) { + mp_raise_msg(&mp_type_RuntimeError, NULL); + } + self->locked = false; + MP_THREAD_GIL_EXIT(); + mp_thread_mutex_unlock(&self->mutex); + MP_THREAD_GIL_ENTER(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release); + +STATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) { + mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->locked); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked); + +STATIC mp_obj_t thread_lock___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; // unused + return thread_lock_release(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock___exit___obj, 4, 4, thread_lock___exit__); + +STATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) }, + { MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) }, + { MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&thread_lock_acquire_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&thread_lock___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table); + +STATIC const mp_obj_type_t mp_type_thread_lock = { + { &mp_type_type }, + .name = MP_QSTR_lock, + .locals_dict = (mp_obj_dict_t*)&thread_lock_locals_dict, +}; + +/****************************************************************/ +// _thread module + +STATIC size_t thread_stack_size = 0; + +STATIC mp_obj_t mod_thread_get_ident(void) { + return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident); + +STATIC mp_obj_t mod_thread_stack_size(size_t n_args, const mp_obj_t *args) { + mp_obj_t ret = mp_obj_new_int_from_uint(thread_stack_size); + if (n_args == 0) { + thread_stack_size = 0; + } else { + thread_stack_size = mp_obj_get_int(args[0]); + } + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_stack_size_obj, 0, 1, mod_thread_stack_size); + +typedef struct _thread_entry_args_t { + mp_obj_dict_t *dict_locals; + mp_obj_dict_t *dict_globals; + size_t stack_size; + mp_obj_t fun; + size_t n_args; + size_t n_kw; + mp_obj_t args[]; +} thread_entry_args_t; + +STATIC void *thread_entry(void *args_in) { + // Execution begins here for a new thread. We do not have the GIL. + + thread_entry_args_t *args = (thread_entry_args_t*)args_in; + + mp_state_thread_t ts; + mp_thread_set_state(&ts); + + mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan + mp_stack_set_limit(args->stack_size); + + #if MICROPY_ENABLE_PYSTACK + // TODO threading and pystack is not fully supported, for now just make a small stack + mp_obj_t mini_pystack[128]; + mp_pystack_init(mini_pystack, &mini_pystack[128]); + #endif + + // set locals and globals from the calling context + mp_locals_set(args->dict_locals); + mp_globals_set(args->dict_globals); + + MP_THREAD_GIL_ENTER(); + + // signal that we are set up and running + mp_thread_start(); + + // TODO set more thread-specific state here: + // mp_pending_exception? (root pointer) + // cur_exception (root pointer) + + DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top)); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args); + nlr_pop(); + } else { + // uncaught exception + // check for SystemExit + mp_obj_base_t *exc = (mp_obj_base_t*)nlr.ret_val; + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + // swallow exception silently + } else { + // print exception out + mp_printf(MICROPY_ERROR_PRINTER, "Unhandled exception in thread started by "); + mp_obj_print_helper(MICROPY_ERROR_PRINTER, args->fun, PRINT_REPR); + mp_printf(MICROPY_ERROR_PRINTER, "\n"); + mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(exc)); + } + } + + DEBUG_printf("[thread] finish ts=%p\n", &ts); + + // signal that we are finished + mp_thread_finish(); + + MP_THREAD_GIL_EXIT(); + + return NULL; +} + +STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) { + // This structure holds the Python function and arguments for thread entry. + // We copy all arguments into this structure to keep ownership of them. + // We must be very careful about root pointers because this pointer may + // disappear from our address space before the thread is created. + thread_entry_args_t *th_args; + + // get positional arguments + size_t pos_args_len; + mp_obj_t *pos_args_items; + mp_obj_get_array(args[1], &pos_args_len, &pos_args_items); + + // check for keyword arguments + if (n_args == 2) { + // just position arguments + th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len); + th_args->n_kw = 0; + } else { + // positional and keyword arguments + if (mp_obj_get_type(args[2]) != &mp_type_dict) { + mp_raise_TypeError("expecting a dict for keyword args"); + } + mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; + th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); + th_args->n_kw = map->used; + // copy across the keyword arguments + for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + th_args->args[n++] = map->table[i].key; + th_args->args[n++] = map->table[i].value; + } + } + } + + // copy agross the positional arguments + th_args->n_args = pos_args_len; + memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t)); + + // pass our locals and globals into the new thread + th_args->dict_locals = mp_locals_get(); + th_args->dict_globals = mp_globals_get(); + + // set the stack size to use + th_args->stack_size = thread_stack_size; + + // set the function for thread entry + th_args->fun = args[0]; + + // spawn the thread! + mp_thread_create(thread_entry, th_args, &th_args->stack_size); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread); + +STATIC mp_obj_t mod_thread_exit(void) { + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit); + +STATIC mp_obj_t mod_thread_allocate_lock(void) { + return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock); + +STATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) }, + { MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) }, + { MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) }, + { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) }, + { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table); + +const mp_obj_module_t mp_module_thread = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_thread_globals, +}; + +#endif // MICROPY_PY_THREAD diff --git a/src/openmv/src/micropython/py/moduerrno.c b/src/openmv/src/micropython/py/moduerrno.c new file mode 100755 index 0000000..de66c94 --- /dev/null +++ b/src/openmv/src/micropython/py/moduerrno.c @@ -0,0 +1,122 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/mperrno.h" + +#if MICROPY_PY_UERRNO + +// This list can be defined per port in mpconfigport.h to tailor it to a +// specific port's needs. If it's not defined then we provide a default. +#ifndef MICROPY_PY_UERRNO_LIST +#define MICROPY_PY_UERRNO_LIST \ + X(EPERM) \ + X(ENOENT) \ + X(EIO) \ + X(EBADF) \ + X(EAGAIN) \ + X(ENOMEM) \ + X(EACCES) \ + X(EEXIST) \ + X(ENODEV) \ + X(EISDIR) \ + X(EINVAL) \ + X(EOPNOTSUPP) \ + X(EADDRINUSE) \ + X(ECONNABORTED) \ + X(ECONNRESET) \ + X(ENOBUFS) \ + X(ENOTCONN) \ + X(ETIMEDOUT) \ + X(ECONNREFUSED) \ + X(EHOSTUNREACH) \ + X(EALREADY) \ + X(EINPROGRESS) \ + +#endif + +#if MICROPY_PY_UERRNO_ERRORCODE +STATIC const mp_rom_map_elem_t errorcode_table[] = { + #define X(e) { MP_ROM_INT(MP_ ## e), MP_ROM_QSTR(MP_QSTR_## e) }, + MICROPY_PY_UERRNO_LIST + #undef X +}; + +STATIC const mp_obj_dict_t errorcode_dict = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 0, // keys are integers + .is_fixed = 1, + .is_ordered = 1, + .used = MP_ARRAY_SIZE(errorcode_table), + .alloc = MP_ARRAY_SIZE(errorcode_table), + .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)errorcode_table, + }, +}; +#endif + +STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) }, + #if MICROPY_PY_UERRNO_ERRORCODE + { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) }, + #endif + + #define X(e) { MP_ROM_QSTR(MP_QSTR_## e), MP_ROM_INT(MP_ ## e) }, + MICROPY_PY_UERRNO_LIST + #undef X +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table); + +const mp_obj_module_t mp_module_uerrno = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_uerrno_globals, +}; + +qstr mp_errno_to_str(mp_obj_t errno_val) { + #if MICROPY_PY_UERRNO_ERRORCODE + // We have the errorcode dict so can do a lookup using the hash map + mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP); + if (elem == NULL) { + return MP_QSTR_NULL; + } else { + return MP_OBJ_QSTR_VALUE(elem->value); + } + #else + // We don't have the errorcode dict so do a simple search in the modules dict + for (size_t i = 0; i < MP_ARRAY_SIZE(mp_module_uerrno_globals_table); ++i) { + if (errno_val == mp_module_uerrno_globals_table[i].value) { + return MP_OBJ_QSTR_VALUE(mp_module_uerrno_globals_table[i].key); + } + } + return MP_QSTR_NULL; + #endif +} + +#endif //MICROPY_PY_UERRNO diff --git a/src/openmv/src/micropython/py/mpconfig.h b/src/openmv/src/micropython/py/mpconfig.h new file mode 100755 index 0000000..10a373c --- /dev/null +++ b/src/openmv/src/micropython/py/mpconfig.h @@ -0,0 +1,1459 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPCONFIG_H +#define MICROPY_INCLUDED_PY_MPCONFIG_H + +// This file contains default configuration settings for MicroPython. +// You can override any of the options below using mpconfigport.h file +// located in a directory of your port. + +// mpconfigport.h is a file containing configuration settings for a +// particular port. mpconfigport.h is actually a default name for +// such config, and it can be overridden using MP_CONFIGFILE preprocessor +// define (you can do that by passing CFLAGS_EXTRA='-DMP_CONFIGFILE=""' +// argument to make when using standard MicroPython makefiles). +// This is useful to have more than one config per port, for example, +// release vs debug configs, etc. Note that if you switch from one config +// to another, you must rebuild from scratch using "-B" switch to make. + +#ifdef MP_CONFIGFILE +#include MP_CONFIGFILE +#else +#include +#endif + +// Any options not explicitly set in mpconfigport.h will get default +// values below. + +/*****************************************************************************/ +/* Object representation */ + +// A MicroPython object is a machine word having the following form: +// - xxxx...xxx1 : a small int, bits 1 and above are the value +// - xxxx...xx10 : a qstr, bits 2 and above are the value +// - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object) +#define MICROPY_OBJ_REPR_A (0) + +// A MicroPython object is a machine word having the following form: +// - xxxx...xx01 : a small int, bits 2 and above are the value +// - xxxx...xx11 : a qstr, bits 2 and above are the value +// - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object) +#define MICROPY_OBJ_REPR_B (1) + +// A MicroPython object is a machine word having the following form (called R): +// - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value +// - 01111111 1qqqqqqq qqqqqqqq qqqqq110 str with 20-bit qstr value +// - s1111111 10000000 00000000 00000010 +/- inf +// - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0 +// - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff +// - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) +// Str and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000. +// This makes strs easier to encode/decode as they have zeros in the top 9 bits. +// This scheme only works with 32-bit word size and float enabled. +#define MICROPY_OBJ_REPR_C (2) + +// A MicroPython object is a 64-bit word having the following form (called R): +// - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff +// - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf +// - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan +// - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int +// - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str +// - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) +// Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. +// This makes pointers have all zeros in the top 32 bits. +// Small-ints and strs have 1 as LSB to make sure they don't look like pointers +// to the garbage collector. +#define MICROPY_OBJ_REPR_D (3) + +#ifndef MICROPY_OBJ_REPR +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) +#endif + +/*****************************************************************************/ +/* Memory allocation policy */ + +// Number of bytes in memory allocation/GC block. Any size allocated will be +// rounded up to be multiples of this. +#ifndef MICROPY_BYTES_PER_GC_BLOCK +#define MICROPY_BYTES_PER_GC_BLOCK (4 * BYTES_PER_WORD) +#endif + +// Number of words allocated (in BSS) to the GC stack (minimum is 1) +#ifndef MICROPY_ALLOC_GC_STACK_SIZE +#define MICROPY_ALLOC_GC_STACK_SIZE (64) +#endif + +// Be conservative and always clear to zero newly (re)allocated memory in the GC. +// This helps eliminate stray pointers that hold on to memory that's no longer +// used. It decreases performance due to unnecessary memory clearing. +// A memory manager which always clears memory can set this to 0. +// TODO Do analysis to understand why some memory is not properly cleared and +// find a more efficient way to clear it. +#ifndef MICROPY_GC_CONSERVATIVE_CLEAR +#define MICROPY_GC_CONSERVATIVE_CLEAR (MICROPY_ENABLE_GC) +#endif + +// Support automatic GC when reaching allocation threshold, +// configurable by gc.threshold(). +#ifndef MICROPY_GC_ALLOC_THRESHOLD +#define MICROPY_GC_ALLOC_THRESHOLD (1) +#endif + +// Number of bytes to allocate initially when creating new chunks to store +// interned string data. Smaller numbers lead to more chunks being needed +// and more wastage at the end of the chunk. Larger numbers lead to wasted +// space at the end when no more strings need interning. +#ifndef MICROPY_ALLOC_QSTR_CHUNK_INIT +#define MICROPY_ALLOC_QSTR_CHUNK_INIT (128) +#endif + +// Initial amount for lexer indentation level +#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT +#define MICROPY_ALLOC_LEXER_INDENT_INIT (10) +#endif + +// Increment for lexer indentation level +#ifndef MICROPY_ALLOC_LEXEL_INDENT_INC +#define MICROPY_ALLOC_LEXEL_INDENT_INC (8) +#endif + +// Initial amount for parse rule stack +#ifndef MICROPY_ALLOC_PARSE_RULE_INIT +#define MICROPY_ALLOC_PARSE_RULE_INIT (64) +#endif + +// Increment for parse rule stack +#ifndef MICROPY_ALLOC_PARSE_RULE_INC +#define MICROPY_ALLOC_PARSE_RULE_INC (16) +#endif + +// Initial amount for parse result stack +#ifndef MICROPY_ALLOC_PARSE_RESULT_INIT +#define MICROPY_ALLOC_PARSE_RESULT_INIT (32) +#endif + +// Increment for parse result stack +#ifndef MICROPY_ALLOC_PARSE_RESULT_INC +#define MICROPY_ALLOC_PARSE_RESULT_INC (16) +#endif + +// Strings this length or less will be interned by the parser +#ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN +#define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10) +#endif + +// Number of bytes to allocate initially when creating new chunks to store +// parse nodes. Small leads to fragmentation, large leads to excess use. +#ifndef MICROPY_ALLOC_PARSE_CHUNK_INIT +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (128) +#endif + +// Initial amount for ids in a scope +#ifndef MICROPY_ALLOC_SCOPE_ID_INIT +#define MICROPY_ALLOC_SCOPE_ID_INIT (4) +#endif + +// Increment for ids in a scope +#ifndef MICROPY_ALLOC_SCOPE_ID_INC +#define MICROPY_ALLOC_SCOPE_ID_INC (6) +#endif + +// Maximum length of a path in the filesystem +// So we can allocate a buffer on the stack for path manipulation in import +#ifndef MICROPY_ALLOC_PATH_MAX +#define MICROPY_ALLOC_PATH_MAX (512) +#endif + +// Initial size of module dict +#ifndef MICROPY_MODULE_DICT_SIZE +#define MICROPY_MODULE_DICT_SIZE (1) +#endif + +// Whether realloc/free should be passed allocated memory region size +// You must enable this if MICROPY_MEM_STATS is enabled +#ifndef MICROPY_MALLOC_USES_ALLOCATED_SIZE +#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (0) +#endif + +// Number of bytes used to store qstr length +// Dictates hard limit on maximum Python identifier length, but 1 byte +// (limit of 255 bytes in an identifier) should be enough for everyone +#ifndef MICROPY_QSTR_BYTES_IN_LEN +#define MICROPY_QSTR_BYTES_IN_LEN (1) +#endif + +// Number of bytes used to store qstr hash +#ifndef MICROPY_QSTR_BYTES_IN_HASH +#define MICROPY_QSTR_BYTES_IN_HASH (2) +#endif + +// Avoid using C stack when making Python function calls. C stack still +// may be used if there's no free heap. +#ifndef MICROPY_STACKLESS +#define MICROPY_STACKLESS (0) +#endif + +// Never use C stack when making Python function calls. This may break +// testsuite as will subtly change which exception is thrown in case +// of too deep recursion and other similar cases. +#ifndef MICROPY_STACKLESS_STRICT +#define MICROPY_STACKLESS_STRICT (0) +#endif + +// Don't use alloca calls. As alloca() is not part of ANSI C, this +// workaround option is provided for compilers lacking this de-facto +// standard function. The way it works is allocating from heap, and +// relying on garbage collection to free it eventually. This is of +// course much less optimal than real alloca(). +#if defined(MICROPY_NO_ALLOCA) && MICROPY_NO_ALLOCA +#undef alloca +#define alloca(x) m_malloc(x) +#endif + +/*****************************************************************************/ +/* MicroPython emitters */ + +// Whether to support loading of persistent code +#ifndef MICROPY_PERSISTENT_CODE_LOAD +#define MICROPY_PERSISTENT_CODE_LOAD (0) +#endif + +// Whether to support saving of persistent code +#ifndef MICROPY_PERSISTENT_CODE_SAVE +#define MICROPY_PERSISTENT_CODE_SAVE (0) +#endif + +// Whether generated code can persist independently of the VM/runtime instance +// This is enabled automatically when needed by other features +#ifndef MICROPY_PERSISTENT_CODE +#define MICROPY_PERSISTENT_CODE (MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE || MICROPY_MODULE_FROZEN_MPY) +#endif + +// Whether to emit x64 native code +#ifndef MICROPY_EMIT_X64 +#define MICROPY_EMIT_X64 (0) +#endif + +// Whether to emit x86 native code +#ifndef MICROPY_EMIT_X86 +#define MICROPY_EMIT_X86 (0) +#endif + +// Whether to emit thumb native code +#ifndef MICROPY_EMIT_THUMB +#define MICROPY_EMIT_THUMB (0) +#endif + +// Whether to enable the thumb inline assembler +#ifndef MICROPY_EMIT_INLINE_THUMB +#define MICROPY_EMIT_INLINE_THUMB (0) +#endif + +// Whether to enable ARMv7-M instruction support in the Thumb2 inline assembler +#ifndef MICROPY_EMIT_INLINE_THUMB_ARMV7M +#define MICROPY_EMIT_INLINE_THUMB_ARMV7M (1) +#endif + +// Whether to enable float support in the Thumb2 inline assembler +#ifndef MICROPY_EMIT_INLINE_THUMB_FLOAT +#define MICROPY_EMIT_INLINE_THUMB_FLOAT (1) +#endif + +// Whether to emit ARM native code +#ifndef MICROPY_EMIT_ARM +#define MICROPY_EMIT_ARM (0) +#endif + +// Whether to emit Xtensa native code +#ifndef MICROPY_EMIT_XTENSA +#define MICROPY_EMIT_XTENSA (0) +#endif + +// Whether to enable the Xtensa inline assembler +#ifndef MICROPY_EMIT_INLINE_XTENSA +#define MICROPY_EMIT_INLINE_XTENSA (0) +#endif + +// Convenience definition for whether any native emitter is enabled +#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA) + +// Convenience definition for whether any inline assembler emitter is enabled +#define MICROPY_EMIT_INLINE_ASM (MICROPY_EMIT_INLINE_THUMB || MICROPY_EMIT_INLINE_XTENSA) + +/*****************************************************************************/ +/* Compiler configuration */ + +// Whether to include the compiler +#ifndef MICROPY_ENABLE_COMPILER +#define MICROPY_ENABLE_COMPILER (1) +#endif + +// Whether the compiler is dynamically configurable (ie at runtime) +#ifndef MICROPY_DYNAMIC_COMPILER +#define MICROPY_DYNAMIC_COMPILER (0) +#endif + +// Configure dynamic compiler macros +#if MICROPY_DYNAMIC_COMPILER +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode) +#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode) +#else +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE +#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE +#endif + +// Whether to enable constant folding; eg 1+2 rewritten as 3 +#ifndef MICROPY_COMP_CONST_FOLDING +#define MICROPY_COMP_CONST_FOLDING (1) +#endif + +// Whether to enable lookup of constants in modules; eg module.CONST +#ifndef MICROPY_COMP_MODULE_CONST +#define MICROPY_COMP_MODULE_CONST (0) +#endif + +// Whether to enable constant optimisation; id = const(value) +#ifndef MICROPY_COMP_CONST +#define MICROPY_COMP_CONST (1) +#endif + +// Whether to enable optimisation of: a, b = c, d +// Costs 124 bytes (Thumb2) +#ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#endif + +// Whether to enable optimisation of: a, b, c = d, e, f +// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2) +#ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#endif + +// Whether to enable optimisation of: return a if b else c +// Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use +#ifndef MICROPY_COMP_RETURN_IF_EXPR +#define MICROPY_COMP_RETURN_IF_EXPR (0) +#endif + +/*****************************************************************************/ +/* Internal debugging stuff */ + +// Whether to collect memory allocation stats +#ifndef MICROPY_MEM_STATS +#define MICROPY_MEM_STATS (0) +#endif + +// The mp_print_t printer used for debugging output +#ifndef MICROPY_DEBUG_PRINTER +#define MICROPY_DEBUG_PRINTER (&mp_plat_print) +#endif + +// Whether to build functions that print debugging info: +// mp_bytecode_print +// mp_parse_node_print +#ifndef MICROPY_DEBUG_PRINTERS +#define MICROPY_DEBUG_PRINTERS (0) +#endif + +// Whether to enable all debugging outputs (it will be extremely verbose) +#ifndef MICROPY_DEBUG_VERBOSE +#define MICROPY_DEBUG_VERBOSE (0) +#endif + +/*****************************************************************************/ +/* Optimisations */ + +// Whether to use computed gotos in the VM, or a switch +// Computed gotos are roughly 10% faster, and increase VM code size by a little +// Note: enabling this will use the gcc-specific extensions of ranged designated +// initialisers and addresses of labels, which are not part of the C99 standard. +#ifndef MICROPY_OPT_COMPUTED_GOTO +#define MICROPY_OPT_COMPUTED_GOTO (0) +#endif + +// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR, +// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and +// uses a bit of extra code ROM, but greatly improves lookup speed. +#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE +#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#endif + +// Whether to use fast versions of bitwise operations (and, or, xor) when the +// arguments are both positive. Increases Thumb2 code size by about 250 bytes. +#ifndef MICROPY_OPT_MPZ_BITWISE +#define MICROPY_OPT_MPZ_BITWISE (0) +#endif + + +// Whether math.factorial is large, fast and recursive (1) or small and slow (0). +#ifndef MICROPY_OPT_MATH_FACTORIAL +#define MICROPY_OPT_MATH_FACTORIAL (0) +#endif + +/*****************************************************************************/ +/* Python internal features */ + +// Whether to enable import of external modules +// When disabled, only importing of built-in modules is supported +// When enabled, a port must implement mp_import_stat (among other things) +#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT +#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#endif + +// Whether to use the POSIX reader for importing files +#ifndef MICROPY_READER_POSIX +#define MICROPY_READER_POSIX (0) +#endif + +// Whether to use the VFS reader for importing files +#ifndef MICROPY_READER_VFS +#define MICROPY_READER_VFS (0) +#endif + +// Hook for the VM at the start of the opcode loop (can contain variable +// definitions usable by the other hook functions) +#ifndef MICROPY_VM_HOOK_INIT +#define MICROPY_VM_HOOK_INIT +#endif + +// Hook for the VM during the opcode loop (but only after jump opcodes) +#ifndef MICROPY_VM_HOOK_LOOP +#define MICROPY_VM_HOOK_LOOP +#endif + +// Hook for the VM just before return opcode is finished being interpreted +#ifndef MICROPY_VM_HOOK_RETURN +#define MICROPY_VM_HOOK_RETURN +#endif + +// Whether to include the garbage collector +#ifndef MICROPY_ENABLE_GC +#define MICROPY_ENABLE_GC (0) +#endif + +// Whether to enable finalisers in the garbage collector (ie call __del__) +#ifndef MICROPY_ENABLE_FINALISER +#define MICROPY_ENABLE_FINALISER (0) +#endif + +// Whether to enable a separate allocator for the Python stack. +// If enabled then the code must call mp_pystack_init before mp_init. +#ifndef MICROPY_ENABLE_PYSTACK +#define MICROPY_ENABLE_PYSTACK (0) +#endif + +// Number of bytes that memory returned by mp_pystack_alloc will be aligned by. +#ifndef MICROPY_PYSTACK_ALIGN +#define MICROPY_PYSTACK_ALIGN (8) +#endif + +// Whether to check C stack usage. C stack used for calling Python functions, +// etc. Not checking means segfault on overflow. +#ifndef MICROPY_STACK_CHECK +#define MICROPY_STACK_CHECK (0) +#endif + +// Whether to have an emergency exception buffer +#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) +#endif +#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF +# ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE +# define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation +# endif +#endif + +// Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function +#ifndef MICROPY_KBD_EXCEPTION +#define MICROPY_KBD_EXCEPTION (0) +#endif + +// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt +// handler) - if supported by a particular port. +#ifndef MICROPY_ASYNC_KBD_INTR +#define MICROPY_ASYNC_KBD_INTR (0) +#endif + +// Whether to include REPL helper function +#ifndef MICROPY_HELPER_REPL +#define MICROPY_HELPER_REPL (0) +#endif + +// Whether to include emacs-style readline behavior in REPL +#ifndef MICROPY_REPL_EMACS_KEYS +#define MICROPY_REPL_EMACS_KEYS (0) +#endif + +// Whether to implement auto-indent in REPL +#ifndef MICROPY_REPL_AUTO_INDENT +#define MICROPY_REPL_AUTO_INDENT (0) +#endif + +// Whether port requires event-driven REPL functions +#ifndef MICROPY_REPL_EVENT_DRIVEN +#define MICROPY_REPL_EVENT_DRIVEN (0) +#endif + +// Whether to include lexer helper function for unix +#ifndef MICROPY_HELPER_LEXER_UNIX +#define MICROPY_HELPER_LEXER_UNIX (0) +#endif + +// Long int implementation +#define MICROPY_LONGINT_IMPL_NONE (0) +#define MICROPY_LONGINT_IMPL_LONGLONG (1) +#define MICROPY_LONGINT_IMPL_MPZ (2) + +#ifndef MICROPY_LONGINT_IMPL +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef long long mp_longint_impl_t; +#endif + +// Whether to include information in the byte code to determine source +// line number (increases RAM usage, but doesn't slow byte code execution) +#ifndef MICROPY_ENABLE_SOURCE_LINE +#define MICROPY_ENABLE_SOURCE_LINE (0) +#endif + +// Whether to include doc strings (increases RAM usage) +#ifndef MICROPY_ENABLE_DOC_STRING +#define MICROPY_ENABLE_DOC_STRING (0) +#endif + +// Exception messages are short static strings +#define MICROPY_ERROR_REPORTING_TERSE (1) +// Exception messages provide basic error details +#define MICROPY_ERROR_REPORTING_NORMAL (2) +// Exception messages provide full info, e.g. object names +#define MICROPY_ERROR_REPORTING_DETAILED (3) + +#ifndef MICROPY_ERROR_REPORTING +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#endif + +// Whether issue warnings during compiling/execution +#ifndef MICROPY_WARNINGS +#define MICROPY_WARNINGS (0) +#endif + +// This macro is used when printing runtime warnings and errors +#ifndef MICROPY_ERROR_PRINTER +#define MICROPY_ERROR_PRINTER (&mp_plat_print) +#endif + +// Float and complex implementation +#define MICROPY_FLOAT_IMPL_NONE (0) +#define MICROPY_FLOAT_IMPL_FLOAT (1) +#define MICROPY_FLOAT_IMPL_DOUBLE (2) + +#ifndef MICROPY_FLOAT_IMPL +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#endif + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x##F +#define MICROPY_FLOAT_C_FUN(fun) fun##f +typedef float mp_float_t; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x +#define MICROPY_FLOAT_C_FUN(fun) fun +typedef double mp_float_t; +#else +#define MICROPY_PY_BUILTINS_FLOAT (0) +#endif + +#ifndef MICROPY_PY_BUILTINS_COMPLEX +#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT) +#endif + +// Whether to provide a high-quality hash for float and complex numbers. +// Otherwise the default is a very simple but correct hashing function. +#ifndef MICROPY_FLOAT_HIGH_QUALITY_HASH +#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0) +#endif + +// Enable features which improve CPython compatibility +// but may lead to more code size/memory usage. +// TODO: Originally intended as generic category to not +// add bunch of once-off options. May need refactoring later +#ifndef MICROPY_CPYTHON_COMPAT +#define MICROPY_CPYTHON_COMPAT (1) +#endif + +// Perform full checks as done by CPython. Disabling this +// may produce incorrect results, if incorrect data is fed, +// but should not lead to MicroPython crashes or similar +// grave issues (in other words, only user app should be, +// affected, not system). +#ifndef MICROPY_FULL_CHECKS +#define MICROPY_FULL_CHECKS (1) +#endif + +// Whether POSIX-semantics non-blocking streams are supported +#ifndef MICROPY_STREAMS_NON_BLOCK +#define MICROPY_STREAMS_NON_BLOCK (0) +#endif + +// Whether to provide stream functions with POSIX-like signatures +// (useful for porting existing libraries to MicroPython). +#ifndef MICROPY_STREAMS_POSIX_API +#define MICROPY_STREAMS_POSIX_API (0) +#endif + +// Whether to call __init__ when importing builtin modules for the first time +#ifndef MICROPY_MODULE_BUILTIN_INIT +#define MICROPY_MODULE_BUILTIN_INIT (0) +#endif + +// Whether to support module-level __getattr__ (see PEP 562) +#ifndef MICROPY_MODULE_GETATTR +#define MICROPY_MODULE_GETATTR (0) +#endif + +// Whether module weak links are supported +#ifndef MICROPY_MODULE_WEAK_LINKS +#define MICROPY_MODULE_WEAK_LINKS (0) +#endif + +// Whether frozen modules are supported in the form of strings +#ifndef MICROPY_MODULE_FROZEN_STR +#define MICROPY_MODULE_FROZEN_STR (0) +#endif + +// Whether frozen modules are supported in the form of .mpy files +#ifndef MICROPY_MODULE_FROZEN_MPY +#define MICROPY_MODULE_FROZEN_MPY (0) +#endif + +// Convenience macro for whether frozen modules are supported +#ifndef MICROPY_MODULE_FROZEN +#define MICROPY_MODULE_FROZEN (MICROPY_MODULE_FROZEN_STR || MICROPY_MODULE_FROZEN_MPY) +#endif + +// Whether you can override builtins in the builtins module +#ifndef MICROPY_CAN_OVERRIDE_BUILTINS +#define MICROPY_CAN_OVERRIDE_BUILTINS (0) +#endif + +// Whether to check that the "self" argument of a builtin method has the +// correct type. Such an explicit check is only needed if a builtin +// method escapes to Python land without a first argument, eg +// list.append([], 1). Without this check such calls will have undefined +// behaviour (usually segfault) if the first argument is the wrong type. +#ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) +#endif + +// Whether to use internally defined errno's (otherwise system provided ones) +#ifndef MICROPY_USE_INTERNAL_ERRNO +#define MICROPY_USE_INTERNAL_ERRNO (0) +#endif + +// Whether to use internally defined *printf() functions (otherwise external ones) +#ifndef MICROPY_USE_INTERNAL_PRINTF +#define MICROPY_USE_INTERNAL_PRINTF (1) +#endif + +// Support for internal scheduler +#ifndef MICROPY_ENABLE_SCHEDULER +#define MICROPY_ENABLE_SCHEDULER (0) +#endif + +// Maximum number of entries in the scheduler +#ifndef MICROPY_SCHEDULER_DEPTH +#define MICROPY_SCHEDULER_DEPTH (4) +#endif + +// Support for generic VFS sub-system +#ifndef MICROPY_VFS +#define MICROPY_VFS (0) +#endif + +// Support for VFS POSIX component, to mount a POSIX filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_POSIX (0) +#endif + +// Support for VFS FAT component, to mount a FAT filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_FAT (0) +#endif + +/*****************************************************************************/ +/* Fine control over Python builtins, classes, modules, etc */ + +// Whether to support multiple inheritance of Python classes. Multiple +// inheritance makes some C functions inherently recursive, and adds a bit of +// code overhead. +#ifndef MICROPY_MULTIPLE_INHERITANCE +#define MICROPY_MULTIPLE_INHERITANCE (1) +#endif + +// Whether to implement attributes on functions +#ifndef MICROPY_PY_FUNCTION_ATTRS +#define MICROPY_PY_FUNCTION_ATTRS (0) +#endif + +// Whether to support the descriptors __get__, __set__, __delete__ +// This costs some code size and makes load/store/delete of instance +// attributes slower for the classes that use this feature +#ifndef MICROPY_PY_DESCRIPTORS +#define MICROPY_PY_DESCRIPTORS (0) +#endif + +// Whether to support class __delattr__ and __setattr__ methods +// This costs some code size and makes store/delete of instance +// attributes slower for the classes that use this feature +#ifndef MICROPY_PY_DELATTR_SETATTR +#define MICROPY_PY_DELATTR_SETATTR (0) +#endif + +// Support for async/await/async for/async with +#ifndef MICROPY_PY_ASYNC_AWAIT +#define MICROPY_PY_ASYNC_AWAIT (1) +#endif + +// Non-standard .pend_throw() method for generators, allowing for +// Future-like behavior with respect to exception handling: an +// exception set with .pend_throw() will activate on the next call +// to generator's .send() or .__next__(). (This is useful to implement +// async schedulers.) +#ifndef MICROPY_PY_GENERATOR_PEND_THROW +#define MICROPY_PY_GENERATOR_PEND_THROW (1) +#endif + +// Issue a warning when comparing str and bytes objects +#ifndef MICROPY_PY_STR_BYTES_CMP_WARN +#define MICROPY_PY_STR_BYTES_CMP_WARN (0) +#endif + +// Whether str object is proper unicode +#ifndef MICROPY_PY_BUILTINS_STR_UNICODE +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#endif + +// Whether to check for valid UTF-8 when converting bytes to str +#ifndef MICROPY_PY_BUILTINS_STR_UNICODE_CHECK +#define MICROPY_PY_BUILTINS_STR_UNICODE_CHECK (MICROPY_PY_BUILTINS_STR_UNICODE) +#endif + +// Whether str.center() method provided +#ifndef MICROPY_PY_BUILTINS_STR_CENTER +#define MICROPY_PY_BUILTINS_STR_CENTER (0) +#endif + +// Whether str.count() method provided +#ifndef MICROPY_PY_BUILTINS_STR_COUNT +#define MICROPY_PY_BUILTINS_STR_COUNT (1) +#endif + +// Whether str % (...) formatting operator provided +#ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1) +#endif + +// Whether str.partition()/str.rpartition() method provided +#ifndef MICROPY_PY_BUILTINS_STR_PARTITION +#define MICROPY_PY_BUILTINS_STR_PARTITION (0) +#endif + +// Whether str.splitlines() method provided +#ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) +#endif + +// Whether to support bytearray object +#ifndef MICROPY_PY_BUILTINS_BYTEARRAY +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#endif + +// Whether to support memoryview object +#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW +#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#endif + +// Whether to support set object +#ifndef MICROPY_PY_BUILTINS_SET +#define MICROPY_PY_BUILTINS_SET (1) +#endif + +// Whether to support slice subscript operators and slice object +#ifndef MICROPY_PY_BUILTINS_SLICE +#define MICROPY_PY_BUILTINS_SLICE (1) +#endif + +// Whether to support slice attribute read access, +// i.e. slice.start, slice.stop, slice.step +#ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#endif + +// Whether to support frozenset object +#ifndef MICROPY_PY_BUILTINS_FROZENSET +#define MICROPY_PY_BUILTINS_FROZENSET (0) +#endif + +// Whether to support property object +#ifndef MICROPY_PY_BUILTINS_PROPERTY +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#endif + +// Whether to implement the start/stop/step attributes (readback) on +// the "range" builtin type. Rarely used, and costs ~60 bytes (x86). +#ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#endif + +// Whether to support binary ops [only (in)equality is defined] between range +// objects. With this option disabled all range objects that are not exactly +// the same object will compare as not-equal. With it enabled the semantics +// match CPython and ranges are equal if they yield the same sequence of items. +#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP +#define MICROPY_PY_BUILTINS_RANGE_BINOP (0) +#endif + +// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120 +#ifndef MICROPY_PY_BUILTINS_ROUND_INT +#define MICROPY_PY_BUILTINS_ROUND_INT (0) +#endif + +// Whether to support timeout exceptions (like socket.timeout) +#ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR +#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) +#endif + +// Whether to support complete set of special methods for user +// classes, or only the most used ones. "Inplace" methods are +// controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below. +// "Reverse" methods are controlled by +// MICROPY_PY_REVERSE_SPECIAL_METHODS below. +#ifndef MICROPY_PY_ALL_SPECIAL_METHODS +#define MICROPY_PY_ALL_SPECIAL_METHODS (0) +#endif + +// Whether to support all inplace arithmetic operarion methods +// (__imul__, etc.) +#ifndef MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS +#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (0) +#endif + +// Whether to support reverse arithmetic operarion methods +// (__radd__, etc.). Additionally gated by +// MICROPY_PY_ALL_SPECIAL_METHODS. +#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) +#endif + +// Whether to support compile function +#ifndef MICROPY_PY_BUILTINS_COMPILE +#define MICROPY_PY_BUILTINS_COMPILE (0) +#endif + +// Whether to support enumerate function(type) +#ifndef MICROPY_PY_BUILTINS_ENUMERATE +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#endif + +// Whether to support eval and exec functions +// By default they are supported if the compiler is enabled +#ifndef MICROPY_PY_BUILTINS_EVAL_EXEC +#define MICROPY_PY_BUILTINS_EVAL_EXEC (MICROPY_ENABLE_COMPILER) +#endif + +// Whether to support the Python 2 execfile function +#ifndef MICROPY_PY_BUILTINS_EXECFILE +#define MICROPY_PY_BUILTINS_EXECFILE (0) +#endif + +// Whether to support filter function(type) +#ifndef MICROPY_PY_BUILTINS_FILTER +#define MICROPY_PY_BUILTINS_FILTER (1) +#endif + +// Whether to support reversed function(type) +#ifndef MICROPY_PY_BUILTINS_REVERSED +#define MICROPY_PY_BUILTINS_REVERSED (1) +#endif + +// Whether to define "NotImplemented" special constant +#ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0) +#endif + +// Whether to provide the built-in input() function. The implementation of this +// uses mp-readline, so can only be enabled if the port uses this readline. +#ifndef MICROPY_PY_BUILTINS_INPUT +#define MICROPY_PY_BUILTINS_INPUT (0) +#endif + +// Whether to support min/max functions +#ifndef MICROPY_PY_BUILTINS_MIN_MAX +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#endif + +// Support for calls to pow() with 3 integer arguments +#ifndef MICROPY_PY_BUILTINS_POW3 +#define MICROPY_PY_BUILTINS_POW3 (0) +#endif + +// Whether to provide the help function +#ifndef MICROPY_PY_BUILTINS_HELP +#define MICROPY_PY_BUILTINS_HELP (0) +#endif + +// Use this to configure the help text shown for help(). It should be a +// variable with the type "const char*". A sensible default is provided. +#ifndef MICROPY_PY_BUILTINS_HELP_TEXT +#define MICROPY_PY_BUILTINS_HELP_TEXT mp_help_default_text +#endif + +// Add the ability to list the available modules when executing help('modules') +#ifndef MICROPY_PY_BUILTINS_HELP_MODULES +#define MICROPY_PY_BUILTINS_HELP_MODULES (0) +#endif + +// Whether to set __file__ for imported modules +#ifndef MICROPY_PY___FILE__ +#define MICROPY_PY___FILE__ (1) +#endif + +// Whether to provide mem-info related functions in micropython module +#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO +#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#endif + +// Whether to provide "micropython.stack_use" function +#ifndef MICROPY_PY_MICROPYTHON_STACK_USE +#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO) +#endif + +// Whether to provide "array" module. Note that large chunk of the +// underlying code is shared with "bytearray" builtin type, so to +// get real savings, it should be disabled too. +#ifndef MICROPY_PY_ARRAY +#define MICROPY_PY_ARRAY (1) +#endif + +// Whether to support slice assignments for array (and bytearray). +// This is rarely used, but adds ~0.5K of code. +#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) +#endif + +// Whether to support attrtuple type (MicroPython extension) +// It provides space-efficient tuples with attribute access +#ifndef MICROPY_PY_ATTRTUPLE +#define MICROPY_PY_ATTRTUPLE (1) +#endif + +// Whether to provide "collections" module +#ifndef MICROPY_PY_COLLECTIONS +#define MICROPY_PY_COLLECTIONS (1) +#endif + +// Whether to provide "ucollections.deque" type +#ifndef MICROPY_PY_COLLECTIONS_DEQUE +#define MICROPY_PY_COLLECTIONS_DEQUE (0) +#endif + +// Whether to provide "collections.OrderedDict" type +#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) +#endif + +// Whether to provide the _asdict function for namedtuple +#ifndef MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (0) +#endif + +// Whether to provide "math" module +#ifndef MICROPY_PY_MATH +#define MICROPY_PY_MATH (1) +#endif + +// Whether to provide special math functions: math.{erf,erfc,gamma,lgamma} +#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0) +#endif + +// Whether to provide math.factorial function +#ifndef MICROPY_PY_MATH_FACTORIAL +#define MICROPY_PY_MATH_FACTORIAL (0) +#endif + +// Whether to provide "cmath" module +#ifndef MICROPY_PY_CMATH +#define MICROPY_PY_CMATH (0) +#endif + +// Whether to provide "gc" module +#ifndef MICROPY_PY_GC +#define MICROPY_PY_GC (1) +#endif + +// Whether to return number of collected objects from gc.collect() +#ifndef MICROPY_PY_GC_COLLECT_RETVAL +#define MICROPY_PY_GC_COLLECT_RETVAL (0) +#endif + +// Whether to provide "io" module +#ifndef MICROPY_PY_IO +#define MICROPY_PY_IO (1) +#endif + +// Whether to provide "io.IOBase" class to support user streams +#ifndef MICROPY_PY_IO_IOBASE +#define MICROPY_PY_IO_IOBASE (0) +#endif + +// Whether to provide "uio.resource_stream()" function with +// the semantics of CPython's pkg_resources.resource_stream() +// (allows to access binary resources in frozen source packages). +// Note that the same functionality can be achieved in "pure +// Python" by prepocessing binary resources into Python source +// and bytecode-freezing it (with a simple helper module available +// e.g. in micropython-lib). +#ifndef MICROPY_PY_IO_RESOURCE_STREAM +#define MICROPY_PY_IO_RESOURCE_STREAM (0) +#endif + +// Whether to provide "io.FileIO" class +#ifndef MICROPY_PY_IO_FILEIO +#define MICROPY_PY_IO_FILEIO (0) +#endif + +// Whether to provide "io.BytesIO" class +#ifndef MICROPY_PY_IO_BYTESIO +#define MICROPY_PY_IO_BYTESIO (1) +#endif + +// Whether to provide "io.BufferedWriter" class +#ifndef MICROPY_PY_IO_BUFFEREDWRITER +#define MICROPY_PY_IO_BUFFEREDWRITER (0) +#endif + +// Whether to provide "struct" module +#ifndef MICROPY_PY_STRUCT +#define MICROPY_PY_STRUCT (1) +#endif + +// Whether to provide "sys" module +#ifndef MICROPY_PY_SYS +#define MICROPY_PY_SYS (1) +#endif + +// Whether to provide "sys.maxsize" constant +#ifndef MICROPY_PY_SYS_MAXSIZE +#define MICROPY_PY_SYS_MAXSIZE (0) +#endif + +// Whether to provide "sys.modules" dictionary +#ifndef MICROPY_PY_SYS_MODULES +#define MICROPY_PY_SYS_MODULES (1) +#endif + +// Whether to provide "sys.exc_info" function +// Avoid enabling this, this function is Python2 heritage +#ifndef MICROPY_PY_SYS_EXC_INFO +#define MICROPY_PY_SYS_EXC_INFO (0) +#endif + +// Whether to provide "sys.exit" function +#ifndef MICROPY_PY_SYS_EXIT +#define MICROPY_PY_SYS_EXIT (1) +#endif + +// Whether to provide "sys.getsizeof" function +#ifndef MICROPY_PY_SYS_GETSIZEOF +#define MICROPY_PY_SYS_GETSIZEOF (0) +#endif + +// Whether to provide sys.{stdin,stdout,stderr} objects +#ifndef MICROPY_PY_SYS_STDFILES +#define MICROPY_PY_SYS_STDFILES (0) +#endif + +// Whether to provide sys.{stdin,stdout,stderr}.buffer object +// This is implemented per-port +#ifndef MICROPY_PY_SYS_STDIO_BUFFER +#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#endif + +// Whether to provide "uerrno" module +#ifndef MICROPY_PY_UERRNO +#define MICROPY_PY_UERRNO (0) +#endif + +// Whether to provide the uerrno.errorcode dict +#ifndef MICROPY_PY_UERRNO_ERRORCODE +#define MICROPY_PY_UERRNO_ERRORCODE (1) +#endif + +// Whether to provide "uselect" module (baremetal implementation) +#ifndef MICROPY_PY_USELECT +#define MICROPY_PY_USELECT (0) +#endif + +// Whether to provide "utime" module functions implementation +// in terms of mp_hal_* functions. +#ifndef MICROPY_PY_UTIME_MP_HAL +#define MICROPY_PY_UTIME_MP_HAL (0) +#endif + +// Period of values returned by utime.ticks_ms(), ticks_us(), ticks_cpu() +// functions. Should be power of two. All functions above use the same +// period, so if underlying hardware/API has different periods, the +// minimum of them should be used. The value below is the maximum value +// this parameter can take (corresponding to 30 bit tick values on 32-bit +// system). +#ifndef MICROPY_PY_UTIME_TICKS_PERIOD +#define MICROPY_PY_UTIME_TICKS_PERIOD (MP_SMALL_INT_POSITIVE_MASK + 1) +#endif + +// Whether to provide "_thread" module +#ifndef MICROPY_PY_THREAD +#define MICROPY_PY_THREAD (0) +#endif + +// Whether to make the VM/runtime thread-safe using a global lock +// If not enabled then thread safety must be provided at the Python level +#ifndef MICROPY_PY_THREAD_GIL +#define MICROPY_PY_THREAD_GIL (MICROPY_PY_THREAD) +#endif + +// Number of VM jump-loops to do before releasing the GIL. +// Set this to 0 to disable the divisor. +#ifndef MICROPY_PY_THREAD_GIL_VM_DIVISOR +#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) +#endif + +// Extended modules + +#ifndef MICROPY_PY_UCTYPES +#define MICROPY_PY_UCTYPES (0) +#endif + +#ifndef MICROPY_PY_UZLIB +#define MICROPY_PY_UZLIB (0) +#endif + +#ifndef MICROPY_PY_UJSON +#define MICROPY_PY_UJSON (0) +#endif + +#ifndef MICROPY_PY_URE +#define MICROPY_PY_URE (0) +#endif + +#ifndef MICROPY_PY_URE_MATCH_GROUPS +#define MICROPY_PY_URE_MATCH_GROUPS (0) +#endif + +#ifndef MICROPY_PY_URE_MATCH_SPAN_START_END +#define MICROPY_PY_URE_MATCH_SPAN_START_END (0) +#endif + +#ifndef MICROPY_PY_URE_SUB +#define MICROPY_PY_URE_SUB (0) +#endif + +#ifndef MICROPY_PY_UHEAPQ +#define MICROPY_PY_UHEAPQ (0) +#endif + +// Optimized heap queue for relative timestamps +#ifndef MICROPY_PY_UTIMEQ +#define MICROPY_PY_UTIMEQ (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB +#define MICROPY_PY_UHASHLIB (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB_MD5 +#define MICROPY_PY_UHASHLIB_MD5 (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB_SHA1 +#define MICROPY_PY_UHASHLIB_SHA1 (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB_SHA256 +#define MICROPY_PY_UHASHLIB_SHA256 (1) +#endif + +#ifndef MICROPY_PY_UCRYPTOLIB +#define MICROPY_PY_UCRYPTOLIB (0) +#endif + +#ifndef MICROPY_PY_UCRYPTOLIB_CONSTS +#define MICROPY_PY_UCRYPTOLIB_CONSTS (0) +#endif + +#ifndef MICROPY_PY_UBINASCII +#define MICROPY_PY_UBINASCII (0) +#endif + +// Depends on MICROPY_PY_UZLIB +#ifndef MICROPY_PY_UBINASCII_CRC32 +#define MICROPY_PY_UBINASCII_CRC32 (0) +#endif + +#ifndef MICROPY_PY_URANDOM +#define MICROPY_PY_URANDOM (0) +#endif + +// Whether to include: randrange, randint, choice, random, uniform +#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0) +#endif + +#ifndef MICROPY_PY_MACHINE +#define MICROPY_PY_MACHINE (0) +#endif + +// Whether to include: time_pulse_us +#ifndef MICROPY_PY_MACHINE_PULSE +#define MICROPY_PY_MACHINE_PULSE (0) +#endif + +#ifndef MICROPY_PY_MACHINE_I2C +#define MICROPY_PY_MACHINE_I2C (0) +#endif + +#ifndef MICROPY_PY_MACHINE_SPI +#define MICROPY_PY_MACHINE_SPI (0) +#endif + +#ifndef MICROPY_PY_USSL +#define MICROPY_PY_USSL (0) +// Whether to add finaliser code to ussl objects +#define MICROPY_PY_USSL_FINALISER (0) +#endif + +#ifndef MICROPY_PY_WEBSOCKET +#define MICROPY_PY_WEBSOCKET (0) +#endif + +#ifndef MICROPY_PY_FRAMEBUF +#define MICROPY_PY_FRAMEBUF (0) +#endif + +#ifndef MICROPY_PY_BTREE +#define MICROPY_PY_BTREE (0) +#endif + +/*****************************************************************************/ +/* Hooks for a port to add builtins */ + +// Additional builtin function definitions - see builtintables.c:builtin_object_table for format. +#ifndef MICROPY_PORT_BUILTINS +#define MICROPY_PORT_BUILTINS +#endif + +// Additional builtin module definitions - see builtintables.c:builtin_module_table for format. +#ifndef MICROPY_PORT_BUILTIN_MODULES +#define MICROPY_PORT_BUILTIN_MODULES +#endif + +// Any module weak links - see builtintables.c:mp_builtin_module_weak_links_table. +#ifndef MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS +#endif + +// Additional constant definitions for the compiler - see compile.c:mp_constants_table. +#ifndef MICROPY_PORT_CONSTANTS +#define MICROPY_PORT_CONSTANTS +#endif + +// Any root pointers for GC scanning - see mpstate.c +#ifndef MICROPY_PORT_ROOT_POINTERS +#define MICROPY_PORT_ROOT_POINTERS +#endif + +/*****************************************************************************/ +/* Miscellaneous settings */ + +// All uPy objects in ROM must be aligned on at least a 4 byte boundary +// so that the small-int/qstr/pointer distinction can be made. For machines +// that don't do this (eg 16-bit CPU), define the following macro to something +// like __attribute__((aligned(4))). +#ifndef MICROPY_OBJ_BASE_ALIGNMENT +#define MICROPY_OBJ_BASE_ALIGNMENT +#endif + +// On embedded platforms, these will typically enable/disable irqs. +#ifndef MICROPY_BEGIN_ATOMIC_SECTION +#define MICROPY_BEGIN_ATOMIC_SECTION() (0) +#endif +#ifndef MICROPY_END_ATOMIC_SECTION +#define MICROPY_END_ATOMIC_SECTION(state) (void)(state) +#endif + +// Allow to override static modifier for global objects, e.g. to use with +// object code analysis tools which don't support static symbols. +#ifndef STATIC +#define STATIC static +#endif + +// Number of bytes in a word +#ifndef BYTES_PER_WORD +#define BYTES_PER_WORD (sizeof(mp_uint_t)) +#endif + +#define BITS_PER_BYTE (8) +#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) +// mp_int_t value with most significant bit set +#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1)) + +// Make sure both MP_ENDIANNESS_LITTLE and MP_ENDIANNESS_BIG are +// defined and that they are the opposite of each other. +#if defined(MP_ENDIANNESS_LITTLE) +#define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE) +#elif defined(MP_ENDIANNESS_BIG) +#define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG) +#else + // Endianness not defined by port so try to autodetect it. + #if defined(__BYTE_ORDER__) + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define MP_ENDIANNESS_LITTLE (1) + #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define MP_ENDIANNESS_LITTLE (0) + #endif + #else + #include + #if defined(__BYTE_ORDER) + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define MP_ENDIANNESS_LITTLE (1) + #elif __BYTE_ORDER == __BIG_ENDIAN + #define MP_ENDIANNESS_LITTLE (0) + #endif + #endif + #endif + #ifndef MP_ENDIANNESS_LITTLE + #error endianness not defined and cannot detect it + #endif + #define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE) +#endif + +// Make a pointer to RAM callable (eg set lower bit for Thumb code) +// (This scheme won't work if we want to mix Thumb and normal ARM code.) +#ifndef MICROPY_MAKE_POINTER_CALLABLE +#define MICROPY_MAKE_POINTER_CALLABLE(p) (p) +#endif + +// If these MP_PLAT_*_EXEC macros are overridden then the memory allocated by them +// must be somehow reachable for marking by the GC, since the native code +// generators store pointers to GC managed memory in the code. +#ifndef MP_PLAT_ALLOC_EXEC +#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while (0) +#endif + +#ifndef MP_PLAT_FREE_EXEC +#define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size) +#endif + +// This macro is used to do all output (except when MICROPY_PY_IO is defined) +#ifndef MP_PLAT_PRINT_STRN +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#endif + +#ifndef MP_SSIZE_MAX +#define MP_SSIZE_MAX SSIZE_MAX +#endif + +// printf format spec to use for mp_int_t and friends +#ifndef INT_FMT +#if defined(__LP64__) +// Archs where mp_int_t == long, long != int +#define UINT_FMT "%lu" +#define INT_FMT "%ld" +#elif defined(_WIN64) +#define UINT_FMT "%llu" +#define INT_FMT "%lld" +#else +// Archs where mp_int_t == int +#define UINT_FMT "%u" +#define INT_FMT "%d" +#endif +#endif //INT_FMT + +// Modifier for function which doesn't return +#ifndef NORETURN +#define NORETURN __attribute__((noreturn)) +#endif + +// Modifier for weak functions +#ifndef MP_WEAK +#define MP_WEAK __attribute__((weak)) +#endif + +// Modifier for functions which should be never inlined +#ifndef MP_NOINLINE +#define MP_NOINLINE __attribute__((noinline)) +#endif + +// Modifier for functions which should be always inlined +#ifndef MP_ALWAYSINLINE +#define MP_ALWAYSINLINE __attribute__((always_inline)) +#endif + +// Condition is likely to be true, to help branch prediction +#ifndef MP_LIKELY +#define MP_LIKELY(x) __builtin_expect((x), 1) +#endif + +// Condition is likely to be false, to help branch prediction +#ifndef MP_UNLIKELY +#define MP_UNLIKELY(x) __builtin_expect((x), 0) +#endif + +#ifndef MP_HTOBE16 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) )) +# define MP_BE16TOH(x) MP_HTOBE16(x) +#else +# define MP_HTOBE16(x) (x) +# define MP_BE16TOH(x) (x) +#endif +#endif + +#ifndef MP_HTOBE32 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE32(x) ((uint32_t)( (((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff) )) +# define MP_BE32TOH(x) MP_HTOBE32(x) +#else +# define MP_HTOBE32(x) (x) +# define MP_BE32TOH(x) (x) +#endif +#endif + +#endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/src/openmv/src/micropython/py/mperrno.h b/src/openmv/src/micropython/py/mperrno.h new file mode 100755 index 0000000..0cad75a --- /dev/null +++ b/src/openmv/src/micropython/py/mperrno.h @@ -0,0 +1,150 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPERRNO_H +#define MICROPY_INCLUDED_PY_MPERRNO_H + +#include "py/mpconfig.h" + +#if MICROPY_USE_INTERNAL_ERRNO + +// MP_Exxx errno's are defined directly as numeric values +// (Linux constants are used as a reference) + +#define MP_EPERM (1) // Operation not permitted +#define MP_ENOENT (2) // No such file or directory +#define MP_ESRCH (3) // No such process +#define MP_EINTR (4) // Interrupted system call +#define MP_EIO (5) // I/O error +#define MP_ENXIO (6) // No such device or address +#define MP_E2BIG (7) // Argument list too long +#define MP_ENOEXEC (8) // Exec format error +#define MP_EBADF (9) // Bad file number +#define MP_ECHILD (10) // No child processes +#define MP_EAGAIN (11) // Try again +#define MP_ENOMEM (12) // Out of memory +#define MP_EACCES (13) // Permission denied +#define MP_EFAULT (14) // Bad address +#define MP_ENOTBLK (15) // Block device required +#define MP_EBUSY (16) // Device or resource busy +#define MP_EEXIST (17) // File exists +#define MP_EXDEV (18) // Cross-device link +#define MP_ENODEV (19) // No such device +#define MP_ENOTDIR (20) // Not a directory +#define MP_EISDIR (21) // Is a directory +#define MP_EINVAL (22) // Invalid argument +#define MP_ENFILE (23) // File table overflow +#define MP_EMFILE (24) // Too many open files +#define MP_ENOTTY (25) // Not a typewriter +#define MP_ETXTBSY (26) // Text file busy +#define MP_EFBIG (27) // File too large +#define MP_ENOSPC (28) // No space left on device +#define MP_ESPIPE (29) // Illegal seek +#define MP_EROFS (30) // Read-only file system +#define MP_EMLINK (31) // Too many links +#define MP_EPIPE (32) // Broken pipe +#define MP_EDOM (33) // Math argument out of domain of func +#define MP_ERANGE (34) // Math result not representable +#define MP_EWOULDBLOCK MP_EAGAIN // Operation would block +#define MP_EOPNOTSUPP (95) // Operation not supported on transport endpoint +#define MP_EAFNOSUPPORT (97) // Address family not supported by protocol +#define MP_EADDRINUSE (98) // Address already in use +#define MP_ECONNABORTED (103) // Software caused connection abort +#define MP_ECONNRESET (104) // Connection reset by peer +#define MP_ENOBUFS (105) // No buffer space available +#define MP_EISCONN (106) // Transport endpoint is already connected +#define MP_ENOTCONN (107) // Transport endpoint is not connected +#define MP_ETIMEDOUT (110) // Connection timed out +#define MP_ECONNREFUSED (111) // Connection refused +#define MP_EHOSTUNREACH (113) // No route to host +#define MP_EALREADY (114) // Operation already in progress +#define MP_EINPROGRESS (115) // Operation now in progress + +#else + +// MP_Exxx errno's are defined in terms of system supplied ones + +#include + +#define MP_EPERM EPERM +#define MP_ENOENT ENOENT +#define MP_ESRCH ESRCH +#define MP_EINTR EINTR +#define MP_EIO EIO +#define MP_ENXIO ENXIO +#define MP_E2BIG E2BIG +#define MP_ENOEXEC ENOEXEC +#define MP_EBADF EBADF +#define MP_ECHILD ECHILD +#define MP_EAGAIN EAGAIN +#define MP_ENOMEM ENOMEM +#define MP_EACCES EACCES +#define MP_EFAULT EFAULT +#define MP_ENOTBLK ENOTBLK +#define MP_EBUSY EBUSY +#define MP_EEXIST EEXIST +#define MP_EXDEV EXDEV +#define MP_ENODEV ENODEV +#define MP_ENOTDIR ENOTDIR +#define MP_EISDIR EISDIR +#define MP_EINVAL EINVAL +#define MP_ENFILE ENFILE +#define MP_EMFILE EMFILE +#define MP_ENOTTY ENOTTY +#define MP_ETXTBSY ETXTBSY +#define MP_EFBIG EFBIG +#define MP_ENOSPC ENOSPC +#define MP_ESPIPE ESPIPE +#define MP_EROFS EROFS +#define MP_EMLINK EMLINK +#define MP_EPIPE EPIPE +#define MP_EDOM EDOM +#define MP_ERANGE ERANGE +#define MP_EWOULDBLOCK EWOULDBLOCK +#define MP_EOPNOTSUPP EOPNOTSUPP +#define MP_EAFNOSUPPORT EAFNOSUPPORT +#define MP_EADDRINUSE EADDRINUSE +#define MP_ECONNABORTED ECONNABORTED +#define MP_ECONNRESET ECONNRESET +#define MP_ENOBUFS ENOBUFS +#define MP_EISCONN EISCONN +#define MP_ENOTCONN ENOTCONN +#define MP_ETIMEDOUT ETIMEDOUT +#define MP_ECONNREFUSED ECONNREFUSED +#define MP_EHOSTUNREACH EHOSTUNREACH +#define MP_EALREADY EALREADY +#define MP_EINPROGRESS EINPROGRESS + +#endif + +#if MICROPY_PY_UERRNO + +#include "py/obj.h" + +qstr mp_errno_to_str(mp_obj_t errno_val); + +#endif + +#endif // MICROPY_INCLUDED_PY_MPERRNO_H diff --git a/src/openmv/src/micropython/py/mphal.h b/src/openmv/src/micropython/py/mphal.h new file mode 100755 index 0000000..92de01d --- /dev/null +++ b/src/openmv/src/micropython/py/mphal.h @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPHAL_H +#define MICROPY_INCLUDED_PY_MPHAL_H + +#include "py/mpconfig.h" + +#ifdef MICROPY_MPHALPORT_H +#include MICROPY_MPHALPORT_H +#else +#include +#endif + +#ifndef mp_hal_stdin_rx_chr +int mp_hal_stdin_rx_chr(void); +#endif + +#ifndef mp_hal_stdout_tx_str +void mp_hal_stdout_tx_str(const char *str); +#endif + +#ifndef mp_hal_stdout_tx_strn +void mp_hal_stdout_tx_strn(const char *str, size_t len); +#endif + +#ifndef mp_hal_stdout_tx_strn_cooked +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len); +#endif + +#ifndef mp_hal_delay_ms +void mp_hal_delay_ms(mp_uint_t ms); +#endif + +#ifndef mp_hal_delay_us +void mp_hal_delay_us(mp_uint_t us); +#endif + +#ifndef mp_hal_ticks_ms +mp_uint_t mp_hal_ticks_ms(void); +#endif + +#ifndef mp_hal_ticks_us +mp_uint_t mp_hal_ticks_us(void); +#endif + +#ifndef mp_hal_ticks_cpu +mp_uint_t mp_hal_ticks_cpu(void); +#endif + +// If port HAL didn't define its own pin API, use generic +// "virtual pin" API from the core. +#ifndef mp_hal_pin_obj_t +#define mp_hal_pin_obj_t mp_obj_t +#define mp_hal_get_pin_obj(pin) (pin) +#define mp_hal_pin_read(pin) mp_virtual_pin_read(pin) +#define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v) +#include "extmod/virtpin.h" +#endif + +#endif // MICROPY_INCLUDED_PY_MPHAL_H diff --git a/src/openmv/src/micropython/py/mpprint.c b/src/openmv/src/micropython/py/mpprint.c new file mode 100755 index 0000000..c2e6530 --- /dev/null +++ b/src/openmv/src/micropython/py/mpprint.c @@ -0,0 +1,570 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "py/mphal.h" +#include "py/mpprint.h" +#include "py/obj.h" +#include "py/objint.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include "py/formatfloat.h" +#endif + +static const char pad_spaces[] = " "; +static const char pad_zeroes[] = "0000000000000000"; + +STATIC void plat_print_strn(void *env, const char *str, size_t len) { + (void)env; + MP_PLAT_PRINT_STRN(str, len); +} + +const mp_print_t mp_plat_print = {NULL, plat_print_strn}; + +int mp_print_str(const mp_print_t *print, const char *str) { + size_t len = strlen(str); + if (len) { + print->print_strn(print->data, str, len); + } + return len; +} + +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) { + int left_pad = 0; + int right_pad = 0; + int pad = width - len; + int pad_size; + int total_chars_printed = 0; + const char *pad_chars; + + if (!fill || fill == ' ') { + pad_chars = pad_spaces; + pad_size = sizeof(pad_spaces) - 1; + } else if (fill == '0') { + pad_chars = pad_zeroes; + pad_size = sizeof(pad_zeroes) - 1; + } else { + // Other pad characters are fairly unusual, so we'll take the hit + // and output them 1 at a time. + pad_chars = &fill; + pad_size = 1; + } + + if (flags & PF_FLAG_CENTER_ADJUST) { + left_pad = pad / 2; + right_pad = pad - left_pad; + } else if (flags & PF_FLAG_LEFT_ADJUST) { + right_pad = pad; + } else { + left_pad = pad; + } + + if (left_pad > 0) { + total_chars_printed += left_pad; + while (left_pad > 0) { + int p = left_pad; + if (p > pad_size) { + p = pad_size; + } + print->print_strn(print->data, pad_chars, p); + left_pad -= p; + } + } + if (len) { + print->print_strn(print->data, str, len); + total_chars_printed += len; + } + if (right_pad > 0) { + total_chars_printed += right_pad; + while (right_pad > 0) { + int p = right_pad; + if (p > pad_size) { + p = pad_size; + } + print->print_strn(print->data, pad_chars, p); + right_pad -= p; + } + } + return total_chars_printed; +} + +// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null +// We can use 16 characters for 32-bit and 32 characters for 64-bit +#define INT_BUF_SIZE (sizeof(mp_int_t) * 4) + +// Our mp_vprintf function below does not support the '#' format modifier to +// print the prefix of a non-base-10 number, so we don't need code for this. +#define SUPPORT_INT_BASE_PREFIX (0) + +// This function is used exclusively by mp_vprintf to format ints. +// It needs to be a separate function to mp_print_mp_int, since converting to a mp_int looses the MSB. +STATIC int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) { + char sign = 0; + if (sgn) { + if ((mp_int_t)x < 0) { + sign = '-'; + x = -x; + } else if (flags & PF_FLAG_SHOW_SIGN) { + sign = '+'; + } else if (flags & PF_FLAG_SPACE_SIGN) { + sign = ' '; + } + } + + char buf[INT_BUF_SIZE]; + char *b = buf + INT_BUF_SIZE; + + if (x == 0) { + *(--b) = '0'; + } else { + do { + int c = x % base; + x /= base; + if (c >= 10) { + c += base_char - 10; + } else { + c += '0'; + } + *(--b) = c; + } while (b > buf && x != 0); + } + + #if SUPPORT_INT_BASE_PREFIX + char prefix_char = '\0'; + + if (flags & PF_FLAG_SHOW_PREFIX) { + if (base == 2) { + prefix_char = base_char + 'b' - 'a'; + } else if (base == 8) { + prefix_char = base_char + 'o' - 'a'; + } else if (base == 16) { + prefix_char = base_char + 'x' - 'a'; + } + } + #endif + + int len = 0; + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + if (sign) { + len += mp_print_strn(print, &sign, 1, flags, fill, 1); + width--; + } + #if SUPPORT_INT_BASE_PREFIX + if (prefix_char) { + len += mp_print_strn(print, "0", 1, flags, fill, 1); + len += mp_print_strn(print, &prefix_char, 1, flags, fill, 1); + width -= 2; + } + #endif + } else { + #if SUPPORT_INT_BASE_PREFIX + if (prefix_char && b > &buf[1]) { + *(--b) = prefix_char; + *(--b) = '0'; + } + #endif + if (sign && b > buf) { + *(--b) = sign; + } + } + + len += mp_print_strn(print, b, buf + INT_BUF_SIZE - b, flags, fill, width); + return len; +} + +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) { + // These are the only values for "base" that are required to be supported by this + // function, since Python only allows the user to format integers in these bases. + // If needed this function could be generalised to handle other values. + assert(base == 2 || base == 8 || base == 10 || base == 16); + + if (!MP_OBJ_IS_INT(x)) { + // This will convert booleans to int, or raise an error for + // non-integer types. + x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); + } + + if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') { + if (prec > width) { + width = prec; + } + prec = 0; + } + char prefix_buf[4]; + char *prefix = prefix_buf; + + if (mp_obj_int_sign(x) >= 0) { + if (flags & PF_FLAG_SHOW_SIGN) { + *prefix++ = '+'; + } else if (flags & PF_FLAG_SPACE_SIGN) { + *prefix++ = ' '; + } + } + + if (flags & PF_FLAG_SHOW_PREFIX) { + if (base == 2) { + *prefix++ = '0'; + *prefix++ = base_char + 'b' - 'a'; + } else if (base == 8) { + *prefix++ = '0'; + if (flags & PF_FLAG_SHOW_OCTAL_LETTER) { + *prefix++ = base_char + 'o' - 'a'; + } + } else if (base == 16) { + *prefix++ = '0'; + *prefix++ = base_char + 'x' - 'a'; + } + } + *prefix = '\0'; + int prefix_len = prefix - prefix_buf; + prefix = prefix_buf; + + char comma = '\0'; + if (flags & PF_FLAG_SHOW_COMMA) { + comma = ','; + } + + // The size of this buffer is rather arbitrary. If it's not large + // enough, a dynamic one will be allocated. + char stack_buf[sizeof(mp_int_t) * 4]; + char *buf = stack_buf; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size = 0; + char *str; + + if (prec > 1) { + flags |= PF_FLAG_PAD_AFTER_SIGN; + } + char sign = '\0'; + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + // We add the pad in this function, so since the pad goes after + // the sign & prefix, we format without a prefix + str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, + x, base, NULL, base_char, comma); + if (*str == '-') { + sign = *str++; + fmt_size--; + } + } else { + str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, + x, base, prefix, base_char, comma); + } + + int spaces_before = 0; + int spaces_after = 0; + + if (prec > 1) { + // If prec was specified, then prec specifies the width to zero-pad the + // the number to. This zero-padded number then gets left or right + // aligned in width characters. + + int prec_width = fmt_size; // The digits + if (prec_width < prec) { + prec_width = prec; + } + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + if (sign) { + prec_width++; + } + prec_width += prefix_len; + } + if (prec_width < width) { + if (flags & PF_FLAG_LEFT_ADJUST) { + spaces_after = width - prec_width; + } else { + spaces_before = width - prec_width; + } + } + fill = '0'; + flags &= ~PF_FLAG_LEFT_ADJUST; + } + + int len = 0; + if (spaces_before) { + len += mp_print_strn(print, "", 0, 0, ' ', spaces_before); + } + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + // pad after sign implies pad after prefix as well. + if (sign) { + len += mp_print_strn(print, &sign, 1, 0, 0, 1); + width--; + } + if (prefix_len) { + len += mp_print_strn(print, prefix, prefix_len, 0, 0, 1); + width -= prefix_len; + } + } + if (prec > 1) { + width = prec; + } + + len += mp_print_strn(print, str, fmt_size, flags, fill, width); + + if (spaces_after) { + len += mp_print_strn(print, "", 0, 0, ' ', spaces_after); + } + + if (buf != stack_buf) { + m_del(char, buf, buf_size); + } + return len; +} + +#if MICROPY_PY_BUILTINS_FLOAT +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) { + char buf[32]; + char sign = '\0'; + int chrs = 0; + + if (flags & PF_FLAG_SHOW_SIGN) { + sign = '+'; + } + else + if (flags & PF_FLAG_SPACE_SIGN) { + sign = ' '; + } + + int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); + + char *s = buf; + + if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) { + buf[len++] = '%'; + buf[len] = '\0'; + } + + // buf[0] < '0' returns true if the first character is space, + or - + if ((flags & PF_FLAG_PAD_AFTER_SIGN) && buf[0] < '0') { + // We have a sign character + s++; + chrs += mp_print_strn(print, &buf[0], 1, 0, 0, 1); + width--; + len--; + } + + chrs += mp_print_strn(print, s, len, flags, fill, width); + + return chrs; +} +#endif + +int mp_printf(const mp_print_t *print, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(print, fmt, ap); + va_end(ap); + return ret; +} + +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { + int chrs = 0; + for (;;) { + { + const char *f = fmt; + while (*f != '\0' && *f != '%') { + ++f; // XXX UTF8 advance char + } + if (f > fmt) { + print->print_strn(print->data, fmt, f - fmt); + chrs += f - fmt; + fmt = f; + } + } + + if (*fmt == '\0') { + break; + } + + // move past % character + ++fmt; + + // parse flags, if they exist + int flags = 0; + char fill = ' '; + while (*fmt != '\0') { + if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST; + else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN; + else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN; + else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ; + else if (*fmt == '0') { + flags |= PF_FLAG_PAD_AFTER_SIGN; + fill = '0'; + } else break; + ++fmt; + } + + // parse width, if it exists + int width = 0; + for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { + width = width * 10 + *fmt - '0'; + } + + // parse precision, if it exists + int prec = -1; + if (*fmt == '.') { + ++fmt; + if (*fmt == '*') { + ++fmt; + prec = va_arg(args, int); + } else { + prec = 0; + for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { + prec = prec * 10 + *fmt - '0'; + } + } + if (prec < 0) { + prec = 0; + } + } + + // parse long specifiers (only for LP64 model where they make a difference) + #ifndef __LP64__ + const + #endif + bool long_arg = false; + if (*fmt == 'l') { + ++fmt; + #ifdef __LP64__ + long_arg = true; + #endif + } + + if (*fmt == '\0') { + break; + } + + switch (*fmt) { + case 'b': + if (va_arg(args, int)) { + chrs += mp_print_strn(print, "true", 4, flags, fill, width); + } else { + chrs += mp_print_strn(print, "false", 5, flags, fill, width); + } + break; + case 'c': + { + char str = va_arg(args, int); + chrs += mp_print_strn(print, &str, 1, flags, fill, width); + break; + } + case 'q': + { + qstr qst = va_arg(args, qstr); + size_t len; + const char *str = (const char*)qstr_data(qst, &len); + if (prec < 0) { + prec = len; + } + chrs += mp_print_strn(print, str, prec, flags, fill, width); + break; + } + case 's': + { + const char *str = va_arg(args, const char*); + #ifndef NDEBUG + // With debugging enabled, catch printing of null string pointers + if (prec != 0 && str == NULL) { + chrs += mp_print_strn(print, "(null)", 6, flags, fill, width); + break; + } + #endif + if (prec < 0) { + prec = strlen(str); + } + chrs += mp_print_strn(print, str, prec, flags, fill, width); + break; + } + case 'u': + chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 10, 'a', flags, fill, width); + break; + case 'd': + chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); + break; + case 'x': + case 'X': { + char fmt_c = *fmt - 'X' + 'A'; + mp_uint_t val; + if (long_arg) { + val = va_arg(args, unsigned long int); + } else { + val = va_arg(args, unsigned int); + } + chrs += mp_print_int(print, val, 0, 16, fmt_c, flags, fill, width); + break; + } + case 'p': + case 'P': // don't bother to handle upcase for 'P' + // Use unsigned long int to work on both ILP32 and LP64 systems + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width); + break; +#if MICROPY_PY_BUILTINS_FLOAT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + { +#if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE)) + mp_float_t f = va_arg(args, double); + chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec); +#else +#error Unknown MICROPY FLOAT IMPL +#endif + break; + } +#endif + // Because 'l' is eaten above, another 'l' means %ll. We need to support + // this length specifier for OBJ_REPR_D (64-bit NaN boxing). + // TODO Either enable this unconditionally, or provide a specific config var. + #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) + case 'l': { + unsigned long long int arg_value = va_arg(args, unsigned long long int); + ++fmt; + if (*fmt == 'u' || *fmt == 'd') { + chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); + break; + } + assert(!"unsupported fmt char"); + } + #endif + default: + // if it's not %% then it's an unsupported format character + assert(*fmt == '%' || !"unsupported fmt char"); + print->print_strn(print->data, fmt, 1); + chrs += 1; + break; + } + ++fmt; + } + return chrs; +} diff --git a/src/openmv/src/micropython/py/mpprint.h b/src/openmv/src/micropython/py/mpprint.h new file mode 100755 index 0000000..07462bd --- /dev/null +++ b/src/openmv/src/micropython/py/mpprint.h @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPPRINT_H +#define MICROPY_INCLUDED_PY_MPPRINT_H + +#include "py/mpconfig.h" + +#define PF_FLAG_LEFT_ADJUST (0x001) +#define PF_FLAG_SHOW_SIGN (0x002) +#define PF_FLAG_SPACE_SIGN (0x004) +#define PF_FLAG_NO_TRAILZ (0x008) +#define PF_FLAG_SHOW_PREFIX (0x010) +#define PF_FLAG_SHOW_COMMA (0x020) +#define PF_FLAG_PAD_AFTER_SIGN (0x040) +#define PF_FLAG_CENTER_ADJUST (0x080) +#define PF_FLAG_ADD_PERCENT (0x100) +#define PF_FLAG_SHOW_OCTAL_LETTER (0x200) + +#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES +# define MP_PYTHON_PRINTER &mp_sys_stdout_print +#else +# define MP_PYTHON_PRINTER &mp_plat_print +#endif + +typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len); + +typedef struct _mp_print_t { + void *data; + mp_print_strn_t print_strn; +} mp_print_t; + +// All (non-debug) prints go through one of the two interfaces below. +// 1) Wrapper for platform print function, which wraps MP_PLAT_PRINT_STRN. +extern const mp_print_t mp_plat_print; +#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES +// 2) Wrapper for printing to sys.stdout. +extern const mp_print_t mp_sys_stdout_print; +#endif + +int mp_print_str(const mp_print_t *print, const char *str); +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width); +#if MICROPY_PY_BUILTINS_FLOAT +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec); +#endif + +int mp_printf(const mp_print_t *print, const char *fmt, ...); +#ifdef va_start +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); +#endif + +#endif // MICROPY_INCLUDED_PY_MPPRINT_H diff --git a/src/openmv/src/micropython/py/mpstate.c b/src/openmv/src/micropython/py/mpstate.c new file mode 100755 index 0000000..6ce64ad --- /dev/null +++ b/src/openmv/src/micropython/py/mpstate.c @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_DYNAMIC_COMPILER +mp_dynamic_compiler_t mp_dynamic_compiler = {0}; +#endif + +mp_state_ctx_t mp_state_ctx; diff --git a/src/openmv/src/micropython/py/mpstate.h b/src/openmv/src/micropython/py/mpstate.h new file mode 100755 index 0000000..8c3b710 --- /dev/null +++ b/src/openmv/src/micropython/py/mpstate.h @@ -0,0 +1,268 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPSTATE_H +#define MICROPY_INCLUDED_PY_MPSTATE_H + +#include + +#include "py/mpconfig.h" +#include "py/mpthread.h" +#include "py/misc.h" +#include "py/nlr.h" +#include "py/obj.h" +#include "py/objlist.h" +#include "py/objexcept.h" + +// This file contains structures defining the state of the MicroPython +// memory system, runtime and virtual machine. The state is a global +// variable, but in the future it is hoped that the state can become local. + +// This structure contains dynamic configuration for the compiler. +#if MICROPY_DYNAMIC_COMPILER +typedef struct mp_dynamic_compiler_t { + uint8_t small_int_bits; // must be <= host small_int_bits + bool opt_cache_map_lookup_in_bytecode; + bool py_builtins_str_unicode; +} mp_dynamic_compiler_t; +extern mp_dynamic_compiler_t mp_dynamic_compiler; +#endif + +// These are the values for sched_state +#define MP_SCHED_IDLE (1) +#define MP_SCHED_LOCKED (-1) +#define MP_SCHED_PENDING (0) // 0 so it's a quick check in the VM + +typedef struct _mp_sched_item_t { + mp_obj_t func; + mp_obj_t arg; +} mp_sched_item_t; + +// This structure hold information about the memory allocation system. +typedef struct _mp_state_mem_t { + #if MICROPY_MEM_STATS + size_t total_bytes_allocated; + size_t current_bytes_allocated; + size_t peak_bytes_allocated; + #endif + + byte *gc_alloc_table_start; + size_t gc_alloc_table_byte_len; + #if MICROPY_ENABLE_FINALISER + byte *gc_finaliser_table_start; + #endif + byte *gc_pool_start; + byte *gc_pool_end; + + int gc_stack_overflow; + size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; + uint16_t gc_lock_depth; + + // This variable controls auto garbage collection. If set to 0 then the + // GC won't automatically run when gc_alloc can't find enough blocks. But + // you can still allocate/free memory and also explicitly call gc_collect. + uint16_t gc_auto_collect_enabled; + + #if MICROPY_GC_ALLOC_THRESHOLD + size_t gc_alloc_amount; + size_t gc_alloc_threshold; + #endif + + size_t gc_last_free_atb_index; + + #if MICROPY_PY_GC_COLLECT_RETVAL + size_t gc_collected; + #endif + + #if MICROPY_PY_THREAD + // This is a global mutex used to make the GC thread-safe. + mp_thread_mutex_t gc_mutex; + #endif +} mp_state_mem_t; + +// This structure hold runtime and VM information. It includes a section +// which contains root pointers that must be scanned by the GC. +typedef struct _mp_state_vm_t { + // + // CONTINUE ROOT POINTER SECTION + // This must start at the start of this structure and follows + // the state in the mp_state_thread_t structure, continuing + // the root pointer section from there. + // + + qstr_pool_t *last_pool; + + // non-heap memory for creating an exception if we can't allocate RAM + mp_obj_exception_t mp_emergency_exception_obj; + + // memory for exception arguments if we can't allocate RAM + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + #if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0 + // statically allocated buf (needs to be aligned to mp_obj_t) + mp_obj_t mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE / sizeof(mp_obj_t)]; + #else + // dynamically allocated buf + byte *mp_emergency_exception_buf; + #endif + #endif + + #if MICROPY_KBD_EXCEPTION + // exception object of type KeyboardInterrupt + mp_obj_exception_t mp_kbd_exception; + #endif + + // dictionary with loaded modules (may be exposed as sys.modules) + mp_obj_dict_t mp_loaded_modules_dict; + + // pending exception object (MP_OBJ_NULL if not pending) + volatile mp_obj_t mp_pending_exception; + + #if MICROPY_ENABLE_SCHEDULER + mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; + #endif + + // current exception being handled, for sys.exc_info() + #if MICROPY_PY_SYS_EXC_INFO + mp_obj_base_t *cur_exception; + #endif + + // dictionary for the __main__ module + mp_obj_dict_t dict_main; + + // these two lists must be initialised per port, after the call to mp_init + mp_obj_list_t mp_sys_path_obj; + mp_obj_list_t mp_sys_argv_obj; + + // dictionary for overridden builtins + #if MICROPY_CAN_OVERRIDE_BUILTINS + mp_obj_dict_t *mp_module_builtins_override_dict; + #endif + + // include any root pointers defined by a port + MICROPY_PORT_ROOT_POINTERS + + // root pointers for extmod + + #if MICROPY_REPL_EVENT_DRIVEN + vstr_t *repl_line; + #endif + + #if MICROPY_PY_OS_DUPTERM + mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; + #endif + + #if MICROPY_PY_LWIP_SLIP + mp_obj_t lwip_slip_stream; + #endif + + #if MICROPY_VFS + struct _mp_vfs_mount_t *vfs_cur; + struct _mp_vfs_mount_t *vfs_mount_table; + #endif + + // + // END ROOT POINTER SECTION + //////////////////////////////////////////////////////////// + + // pointer and sizes to store interned string data + // (qstr_last_chunk can be root pointer but is also stored in qstr pool) + byte *qstr_last_chunk; + size_t qstr_last_alloc; + size_t qstr_last_used; + + #if MICROPY_PY_THREAD + // This is a global mutex used to make qstr interning thread-safe. + mp_thread_mutex_t qstr_mutex; + #endif + + #if MICROPY_ENABLE_COMPILER + mp_uint_t mp_optimise_value; + #endif + + // size of the emergency exception buf, if it's dynamically allocated + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0 + mp_int_t mp_emergency_exception_buf_size; + #endif + + #if MICROPY_ENABLE_SCHEDULER + volatile int16_t sched_state; + uint16_t sched_sp; + #endif + + #if MICROPY_PY_THREAD_GIL + // This is a global mutex used to make the VM/runtime thread-safe. + mp_thread_mutex_t gil_mutex; + #endif +} mp_state_vm_t; + +// This structure holds state that is specific to a given thread. +// Everything in this structure is scanned for root pointers. +typedef struct _mp_state_thread_t { + // Stack top at the start of program + char *stack_top; + + #if MICROPY_STACK_CHECK + size_t stack_limit; + #endif + + #if MICROPY_ENABLE_PYSTACK + uint8_t *pystack_start; + uint8_t *pystack_end; + uint8_t *pystack_cur; + #endif + + //////////////////////////////////////////////////////////// + // START ROOT POINTER SECTION + // Everything that needs GC scanning must start here, and + // is followed by state in the mp_state_vm_t structure. + // + + mp_obj_dict_t *dict_locals; + mp_obj_dict_t *dict_globals; + + nlr_buf_t *nlr_top; +} mp_state_thread_t; + +// This structure combines the above 3 structures. +// The order of the entries are important for root pointer scanning in the GC to work. +typedef struct _mp_state_ctx_t { + mp_state_thread_t thread; + mp_state_vm_t vm; + mp_state_mem_t mem; +} mp_state_ctx_t; + +extern mp_state_ctx_t mp_state_ctx; + +#define MP_STATE_VM(x) (mp_state_ctx.vm.x) +#define MP_STATE_MEM(x) (mp_state_ctx.mem.x) + +#if MICROPY_PY_THREAD +extern mp_state_thread_t *mp_thread_get_state(void); +#define MP_STATE_THREAD(x) (mp_thread_get_state()->x) +#else +#define MP_STATE_THREAD(x) (mp_state_ctx.thread.x) +#endif + +#endif // MICROPY_INCLUDED_PY_MPSTATE_H diff --git a/src/openmv/src/micropython/py/mpthread.h b/src/openmv/src/micropython/py/mpthread.h new file mode 100755 index 0000000..602df83 --- /dev/null +++ b/src/openmv/src/micropython/py/mpthread.h @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPTHREAD_H +#define MICROPY_INCLUDED_PY_MPTHREAD_H + +#include "py/mpconfig.h" + +#if MICROPY_PY_THREAD + +#ifdef MICROPY_MPTHREADPORT_H +#include MICROPY_MPTHREADPORT_H +#else +#include +#endif + +struct _mp_state_thread_t; + +struct _mp_state_thread_t *mp_thread_get_state(void); +void mp_thread_set_state(void *state); +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size); +void mp_thread_start(void); +void mp_thread_finish(void); +void mp_thread_mutex_init(mp_thread_mutex_t *mutex); +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait); +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex); + +#endif // MICROPY_PY_THREAD + +#if MICROPY_PY_THREAD && MICROPY_PY_THREAD_GIL +#include "py/mpstate.h" +#define MP_THREAD_GIL_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(gil_mutex), 1) +#define MP_THREAD_GIL_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(gil_mutex)) +#else +#define MP_THREAD_GIL_ENTER() +#define MP_THREAD_GIL_EXIT() +#endif + +#endif // MICROPY_INCLUDED_PY_MPTHREAD_H diff --git a/src/openmv/src/micropython/py/mpz.c b/src/openmv/src/micropython/py/mpz.c new file mode 100755 index 0000000..8687092 --- /dev/null +++ b/src/openmv/src/micropython/py/mpz.c @@ -0,0 +1,1735 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mpz.h" + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + +#define DIG_SIZE (MPZ_DIG_SIZE) +#define DIG_MASK ((MPZ_LONG_1 << DIG_SIZE) - 1) +#define DIG_MSB (MPZ_LONG_1 << (DIG_SIZE - 1)) +#define DIG_BASE (MPZ_LONG_1 << DIG_SIZE) + +/* + mpz is an arbitrary precision integer type with a public API. + + mpn functions act on non-negative integers represented by an array of generalised + digits (eg a word per digit). You also need to specify separately the length of the + array. There is no public API for mpn. Rather, the functions are used by mpz to + implement its features. + + Integer values are stored little endian (first digit is first in memory). + + Definition of normalise: ? +*/ + +STATIC size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) { + for (--idig; idig >= oidig && *idig == 0; --idig) { + } + return idig + 1 - oidig; +} + +/* compares i with j + returns sign(i - j) + assumes i, j are normalised +*/ +STATIC int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_t jlen) { + if (ilen < jlen) { return -1; } + if (ilen > jlen) { return 1; } + + for (idig += ilen, jdig += ilen; ilen > 0; --ilen) { + mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig); + if (cmp < 0) { return -1; } + if (cmp > 0) { return 1; } + } + + return 0; +} + +/* computes i = j << n + returns number of digits in i + assumes enough memory in i; assumes normalised j; assumes n > 0 + can have i, j pointing to same memory +*/ +STATIC size_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) { + mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE; + mp_uint_t n_part = n % DIG_SIZE; + if (n_part == 0) { + n_part = DIG_SIZE; + } + + // start from the high end of the digit arrays + idig += jlen + n_whole - 1; + jdig += jlen - 1; + + // shift the digits + mpz_dbl_dig_t d = 0; + for (size_t i = jlen; i > 0; i--, idig--, jdig--) { + d |= *jdig; + *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK; + d <<= DIG_SIZE; + } + + // store remaining bits + *idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK; + idig -= n_whole - 1; + memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t)); + + // work out length of result + jlen += n_whole; + while (jlen != 0 && idig[jlen - 1] == 0) { + jlen--; + } + + // return length of result + return jlen; +} + +/* computes i = j >> n + returns number of digits in i + assumes enough memory in i; assumes normalised j; assumes n > 0 + can have i, j pointing to same memory +*/ +STATIC size_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mp_uint_t n) { + mp_uint_t n_whole = n / DIG_SIZE; + mp_uint_t n_part = n % DIG_SIZE; + + if (n_whole >= jlen) { + return 0; + } + + jdig += n_whole; + jlen -= n_whole; + + for (size_t i = jlen; i > 0; i--, idig++, jdig++) { + mpz_dbl_dig_t d = *jdig; + if (i > 1) { + d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE; + } + d >>= n_part; + *idig = d & DIG_MASK; + } + + if (idig[-1] == 0) { + jlen--; + } + + return jlen; +} + +/* computes i = j + k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + mpz_dbl_dig_t carry = 0; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig; + *idig = carry & DIG_MASK; + carry >>= DIG_SIZE; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + carry += *jdig; + *idig = carry & DIG_MASK; + carry >>= DIG_SIZE; + } + + if (carry != 0) { + *idig++ = carry; + } + + return idig - oidig; +} + +/* computes i = j - k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes j >= k + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + mpz_dbl_dig_signed_t borrow = 0; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig; + *idig = borrow & DIG_MASK; + borrow >>= DIG_SIZE; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + borrow += *jdig; + *idig = borrow & DIG_MASK; + borrow >>= DIG_SIZE; + } + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#if MICROPY_OPT_MPZ_BITWISE + +/* computes i = j & k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed) + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig & *kdig; + } + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#endif + +/* i = -((-j) & (-k)) = ~((~j + 1) & (~k + 1)) + 1 + i = (j & (-k)) = (j & (~k + 1)) = ( j & (~k + 1)) + i = ((-j) & k) = ((~j + 1) & k) = ((~j + 1) & k ) + computes general form: + i = (im ^ (((j ^ jm) + jc) & ((k ^ km) + kc))) + ic where Xm = Xc == 0 ? 0 : DIG_MASK + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes length j >= length k + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, + mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { + mpz_dig_t *oidig = idig; + mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK; + mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; + mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; + + for (; jlen > 0; ++idig, ++jdig) { + carryj += *jdig ^ jmask; + carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; + carryi += ((carryj & carryk) ^ imask) & DIG_MASK; + *idig = carryi & DIG_MASK; + carryk >>= DIG_SIZE; + carryj >>= DIG_SIZE; + carryi >>= DIG_SIZE; + } + + if (0 != carryi) { + *idig++ = carryi; + } + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#if MICROPY_OPT_MPZ_BITWISE + +/* computes i = j | k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig | *kdig; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + *idig = *jdig; + } + + return idig - oidig; +} + +#endif + +/* i = -((-j) | (-k)) = ~((~j + 1) | (~k + 1)) + 1 + i = -(j | (-k)) = -(j | (~k + 1)) = ~( j | (~k + 1)) + 1 + i = -((-j) | k) = -((~j + 1) | k) = ~((~j + 1) | k ) + 1 + computes general form: + i = ~(((j ^ jm) + jc) | ((k ^ km) + kc)) + 1 where Xm = Xc == 0 ? 0 : DIG_MASK + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes length j >= length k + can have i, j, k pointing to same memory +*/ + +#if MICROPY_OPT_MPZ_BITWISE + +STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, + mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { + mpz_dig_t *oidig = idig; + mpz_dbl_dig_t carryi = 1; + mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; + mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; + + for (; jlen > 0; ++idig, ++jdig) { + carryj += *jdig ^ jmask; + carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; + carryi += ((carryj | carryk) ^ DIG_MASK) & DIG_MASK; + *idig = carryi & DIG_MASK; + carryk >>= DIG_SIZE; + carryj >>= DIG_SIZE; + carryi >>= DIG_SIZE; + } + + // At least one of j,k must be negative so the above for-loop runs at least + // once. For carryi to be non-zero here it must be equal to 1 at the end of + // each iteration of the loop. So the accumulation of carryi must overflow + // each time, ie carryi += 0xff..ff. So carryj|carryk must be 0 in the + // DIG_MASK bits on each iteration. But considering all cases of signs of + // j,k one sees that this is not possible. + assert(carryi == 0); + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#else + +STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, + mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { + mpz_dig_t *oidig = idig; + mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK; + mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK; + mpz_dig_t kmask = (0 == carryk) ? 0 : DIG_MASK; + + for (; jlen > 0; ++idig, ++jdig) { + carryj += *jdig ^ jmask; + carryk += (--klen <= --jlen) ? (*kdig++ ^ kmask) : kmask; + carryi += ((carryj | carryk) ^ imask) & DIG_MASK; + *idig = carryi & DIG_MASK; + carryk >>= DIG_SIZE; + carryj >>= DIG_SIZE; + carryi >>= DIG_SIZE; + } + + // See comment in above mpn_or_neg for why carryi must be 0. + assert(carryi == 0); + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#endif + +#if MICROPY_OPT_MPZ_BITWISE + +/* computes i = j ^ k + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + + jlen -= klen; + + for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) { + *idig = *jdig ^ *kdig; + } + + for (; jlen > 0; --jlen, ++idig, ++jdig) { + *idig = *jdig; + } + + return mpn_remove_trailing_zeros(oidig, idig); +} + +#endif + +/* i = (-j) ^ (-k) = ~(j - 1) ^ ~(k - 1) = (j - 1) ^ (k - 1) + i = -(j ^ (-k)) = -(j ^ ~(k - 1)) = ~(j ^ ~(k - 1)) + 1 = (j ^ (k - 1)) + 1 + i = -((-j) ^ k) = -(~(j - 1) ^ k) = ~(~(j - 1) ^ k) + 1 = ((j - 1) ^ k) + 1 + computes general form: + i = ((j - 1 + jc) ^ (k - 1 + kc)) + ic + returns number of digits in i + assumes enough memory in i; assumes normalised j, k; assumes length j >= length k + can have i, j, k pointing to same memory +*/ +STATIC size_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen, + mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) { + mpz_dig_t *oidig = idig; + + for (; jlen > 0; ++idig, ++jdig) { + carryj += *jdig + DIG_MASK; + carryk += (--klen <= --jlen) ? (*kdig++ + DIG_MASK) : DIG_MASK; + carryi += (carryj ^ carryk) & DIG_MASK; + *idig = carryi & DIG_MASK; + carryk >>= DIG_SIZE; + carryj >>= DIG_SIZE; + carryi >>= DIG_SIZE; + } + + if (0 != carryi) { + *idig++ = carryi; + } + + return mpn_remove_trailing_zeros(oidig, idig); +} + +/* computes i = i * d1 + d2 + returns number of digits in i + assumes enough memory in i; assumes normalised i; assumes dmul != 0 +*/ +STATIC size_t mpn_mul_dig_add_dig(mpz_dig_t *idig, size_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) { + mpz_dig_t *oidig = idig; + mpz_dbl_dig_t carry = dadd; + + for (; ilen > 0; --ilen, ++idig) { + carry += (mpz_dbl_dig_t)*idig * (mpz_dbl_dig_t)dmul; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2 + *idig = carry & DIG_MASK; + carry >>= DIG_SIZE; + } + + if (carry != 0) { + *idig++ = carry; + } + + return idig - oidig; +} + +/* computes i = j * k + returns number of digits in i + assumes enough memory in i; assumes i is zeroed; assumes normalised j, k + can have j, k point to same memory +*/ +STATIC size_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mpz_dig_t *kdig, size_t klen) { + mpz_dig_t *oidig = idig; + size_t ilen = 0; + + for (; klen > 0; --klen, ++idig, ++kdig) { + mpz_dig_t *id = idig; + mpz_dbl_dig_t carry = 0; + + size_t jl = jlen; + for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) { + carry += (mpz_dbl_dig_t)*id + (mpz_dbl_dig_t)*jd * (mpz_dbl_dig_t)*kdig; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2 + *id = carry & DIG_MASK; + carry >>= DIG_SIZE; + } + + if (carry != 0) { + *id++ = carry; + } + + ilen = id - oidig; + } + + return ilen; +} + +/* natural_div - quo * den + new_num = old_num (ie num is replaced with rem) + assumes den != 0 + assumes num_dig has enough memory to be extended by 1 digit + assumes quo_dig has enough memory (as many digits as num) + assumes quo_dig is filled with zeros +*/ +STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_dig, size_t den_len, mpz_dig_t *quo_dig, size_t *quo_len) { + mpz_dig_t *orig_num_dig = num_dig; + mpz_dig_t *orig_quo_dig = quo_dig; + mpz_dig_t norm_shift = 0; + mpz_dbl_dig_t lead_den_digit; + + // handle simple cases + { + int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len); + if (cmp == 0) { + *num_len = 0; + quo_dig[0] = 1; + *quo_len = 1; + return; + } else if (cmp < 0) { + // numerator remains the same + *quo_len = 0; + return; + } + } + + // We need to normalise the denominator (leading bit of leading digit is 1) + // so that the division routine works. Since the denominator memory is + // read-only we do the normalisation on the fly, each time a digit of the + // denominator is needed. We need to know is how many bits to shift by. + + // count number of leading zeros in leading digit of denominator + { + mpz_dig_t d = den_dig[den_len - 1]; + while ((d & DIG_MSB) == 0) { + d <<= 1; + ++norm_shift; + } + } + + // now need to shift numerator by same amount as denominator + // first, increase length of numerator in case we need more room to shift + num_dig[*num_len] = 0; + ++(*num_len); + for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) { + mpz_dig_t n = *num; + *num = ((n << norm_shift) | carry) & DIG_MASK; + carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift); + } + + // cache the leading digit of the denominator + lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift; + if (den_len >= 2) { + lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift); + } + + // point num_dig to last digit in numerator + num_dig += *num_len - 1; + + // calculate number of digits in quotient + *quo_len = *num_len - den_len; + + // point to last digit to store for quotient + quo_dig += *quo_len - 1; + + // keep going while we have enough digits to divide + while (*num_len > den_len) { + mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1]; + + // get approximate quotient + quo /= lead_den_digit; + + // Multiply quo by den and subtract from num to get remainder. + // We have different code here to handle different compile-time + // configurations of mpz: + // + // 1. DIG_SIZE is stricly less than half the number of bits + // available in mpz_dbl_dig_t. In this case we can use a + // slightly more optimal (in time and space) routine that + // uses the extra bits in mpz_dbl_dig_signed_t to store a + // sign bit. + // + // 2. DIG_SIZE is exactly half the number of bits available in + // mpz_dbl_dig_t. In this (common) case we need to be careful + // not to overflow the borrow variable. And the shifting of + // borrow needs some special logic (it's a shift right with + // round up). + // + const mpz_dig_t *d = den_dig; + mpz_dbl_dig_t d_norm = 0; + mpz_dbl_dig_t borrow = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2 + *n = borrow & DIG_MASK; + borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE; + #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2 + if (x >= *n || *n - x <= borrow) { + borrow += x - (mpz_dbl_dig_t)*n; + *n = (-borrow) & DIG_MASK; + borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up + } else { + *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK; + borrow = 0; + } + #endif + } + + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + // Borrow was negative in the above for-loop, make it positive for next if-block. + borrow = -borrow; + #endif + + // At this point we have either: + // + // 1. quo was the correct value and the most-sig-digit of num is exactly + // cancelled by borrow (borrow == *num_dig). In this case there is + // nothing more to do. + // + // 2. quo was too large, we subtracted too many den from num, and the + // most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1). + // In this case we must reduce quo and add back den to num until the + // carry from this operation cancels out the borrow. + // + borrow -= *num_dig; + for (; borrow != 0; --quo) { + d = den_dig; + d_norm = 0; + mpz_dbl_dig_t carry = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); + *n = carry & DIG_MASK; + carry >>= DIG_SIZE; + } + borrow -= carry; + } + + // store this digit of the quotient + *quo_dig = quo & DIG_MASK; + --quo_dig; + + // move down to next digit of numerator + --num_dig; + --(*num_len); + } + + // unnormalise numerator (remainder now) + for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) { + mpz_dig_t n = *num; + *num = ((n >> norm_shift) | carry) & DIG_MASK; + carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift); + } + + // strip trailing zeros + + while (*quo_len > 0 && orig_quo_dig[*quo_len - 1] == 0) { + --(*quo_len); + } + + while (*num_len > 0 && orig_num_dig[*num_len - 1] == 0) { + --(*num_len); + } +} + +#define MIN_ALLOC (2) + +void mpz_init_zero(mpz_t *z) { + z->neg = 0; + z->fixed_dig = 0; + z->alloc = 0; + z->len = 0; + z->dig = NULL; +} + +void mpz_init_from_int(mpz_t *z, mp_int_t val) { + mpz_init_zero(z); + mpz_set_from_int(z, val); +} + +void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t alloc, mp_int_t val) { + z->neg = 0; + z->fixed_dig = 1; + z->alloc = alloc; + z->len = 0; + z->dig = dig; + mpz_set_from_int(z, val); +} + +void mpz_deinit(mpz_t *z) { + if (z != NULL && !z->fixed_dig) { + m_del(mpz_dig_t, z->dig, z->alloc); + } +} + +#if 0 +these functions are unused + +mpz_t *mpz_zero(void) { + mpz_t *z = m_new_obj(mpz_t); + mpz_init_zero(z); + return z; +} + +mpz_t *mpz_from_int(mp_int_t val) { + mpz_t *z = mpz_zero(); + mpz_set_from_int(z, val); + return z; +} + +mpz_t *mpz_from_ll(long long val, bool is_signed) { + mpz_t *z = mpz_zero(); + mpz_set_from_ll(z, val, is_signed); + return z; +} + +#if MICROPY_PY_BUILTINS_FLOAT +mpz_t *mpz_from_float(mp_float_t val) { + mpz_t *z = mpz_zero(); + mpz_set_from_float(z, val); + return z; +} +#endif + +mpz_t *mpz_from_str(const char *str, size_t len, bool neg, unsigned int base) { + mpz_t *z = mpz_zero(); + mpz_set_from_str(z, str, len, neg, base); + return z; +} +#endif + +STATIC void mpz_free(mpz_t *z) { + if (z != NULL) { + m_del(mpz_dig_t, z->dig, z->alloc); + m_del_obj(mpz_t, z); + } +} + +STATIC void mpz_need_dig(mpz_t *z, size_t need) { + if (need < MIN_ALLOC) { + need = MIN_ALLOC; + } + + if (z->dig == NULL || z->alloc < need) { + // if z has fixed digit buffer there's not much we can do as the caller will + // be expecting a buffer with at least "need" bytes (but it shouldn't happen) + assert(!z->fixed_dig); + z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need); + z->alloc = need; + } +} + +STATIC mpz_t *mpz_clone(const mpz_t *src) { + assert(src->alloc != 0); + mpz_t *z = m_new_obj(mpz_t); + z->neg = src->neg; + z->fixed_dig = 0; + z->alloc = src->alloc; + z->len = src->len; + z->dig = m_new(mpz_dig_t, z->alloc); + memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); + return z; +} + +/* sets dest = src + can have dest, src the same +*/ +void mpz_set(mpz_t *dest, const mpz_t *src) { + mpz_need_dig(dest, src->len); + dest->neg = src->neg; + dest->len = src->len; + memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t)); +} + +void mpz_set_from_int(mpz_t *z, mp_int_t val) { + if (val == 0) { + z->len = 0; + return; + } + + mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT); + + mp_uint_t uval; + if (val < 0) { + z->neg = 1; + uval = -val; + } else { + z->neg = 0; + uval = val; + } + + z->len = 0; + while (uval > 0) { + z->dig[z->len++] = uval & DIG_MASK; + uval >>= DIG_SIZE; + } +} + +void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) { + mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL); + + unsigned long long uval; + if (is_signed && val < 0) { + z->neg = 1; + uval = -val; + } else { + z->neg = 0; + uval = val; + } + + z->len = 0; + while (uval > 0) { + z->dig[z->len++] = uval & DIG_MASK; + uval >>= DIG_SIZE; + } +} + +#if MICROPY_PY_BUILTINS_FLOAT +void mpz_set_from_float(mpz_t *z, mp_float_t src) { +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +typedef uint64_t mp_float_int_t; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +typedef uint32_t mp_float_int_t; +#endif + union { + mp_float_t f; + #if MP_ENDIANNESS_LITTLE + struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; + #else + struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; + #endif + } u = {src}; + + z->neg = u.p.sgn; + if (u.p.exp == 0) { + // value == 0 || value < 1 + mpz_set_from_int(z, 0); + } else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) { + // u.p.frc == 0 indicates inf, else NaN + // should be handled by caller + mpz_set_from_int(z, 0); + } else { + const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS; + if (adj_exp < 0) { + // value < 1 , truncates to 0 + mpz_set_from_int(z, 0); + } else if (adj_exp == 0) { + // 1 <= value < 2 , so truncates to 1 + mpz_set_from_int(z, 1); + } else { + // 2 <= value + const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE; + const unsigned int rem = adj_exp % DIG_SIZE; + int dig_ind, shft; + mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS); + + if (adj_exp < MP_FLOAT_FRAC_BITS) { + shft = 0; + dig_ind = 0; + frc >>= MP_FLOAT_FRAC_BITS - adj_exp; + } else { + shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; + dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE; + } + mpz_need_dig(z, dig_cnt); + z->len = dig_cnt; + if (dig_ind != 0) { + memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t)); + } + if (shft != 0) { + z->dig[dig_ind++] = (frc << shft) & DIG_MASK; + frc >>= DIG_SIZE - shft; + } +#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1) + while (dig_ind != dig_cnt) { + z->dig[dig_ind++] = frc & DIG_MASK; + frc >>= DIG_SIZE; + } +#else + if (dig_ind != dig_cnt) { + z->dig[dig_ind] = frc; + } +#endif + } + } +} +#endif + +// returns number of bytes from str that were processed +size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base) { + assert(base <= 36); + + const char *cur = str; + const char *top = str + len; + + mpz_need_dig(z, len * 8 / DIG_SIZE + 1); + + if (neg) { + z->neg = 1; + } else { + z->neg = 0; + } + + z->len = 0; + for (; cur < top; ++cur) { // XXX UTF8 next char + //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char + mp_uint_t v = *cur; + if ('0' <= v && v <= '9') { + v -= '0'; + } else if ('A' <= v && v <= 'Z') { + v -= 'A' - 10; + } else if ('a' <= v && v <= 'z') { + v -= 'a' - 10; + } else { + break; + } + if (v >= base) { + break; + } + z->len = mpn_mul_dig_add_dig(z->dig, z->len, base, v); + } + + return cur - str; +} + +void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf) { + int delta = 1; + if (big_endian) { + buf += len - 1; + delta = -1; + } + + mpz_need_dig(z, (len * 8 + DIG_SIZE - 1) / DIG_SIZE); + + mpz_dig_t d = 0; + int num_bits = 0; + z->neg = 0; + z->len = 0; + while (len) { + while (len && num_bits < DIG_SIZE) { + d |= *buf << num_bits; + num_bits += 8; + buf += delta; + len--; + } + z->dig[z->len++] = d & DIG_MASK; + // Need this #if because it's C undefined behavior to do: uint32_t >> 32 + #if DIG_SIZE != 8 && DIG_SIZE != 16 && DIG_SIZE != 32 + d >>= DIG_SIZE; + #else + d = 0; + #endif + num_bits -= DIG_SIZE; + } + + z->len = mpn_remove_trailing_zeros(z->dig, z->dig + z->len); +} + +#if 0 +these functions are unused + +bool mpz_is_pos(const mpz_t *z) { + return z->len > 0 && z->neg == 0; +} + +bool mpz_is_odd(const mpz_t *z) { + return z->len > 0 && (z->dig[0] & 1) != 0; +} + +bool mpz_is_even(const mpz_t *z) { + return z->len == 0 || (z->dig[0] & 1) == 0; +} +#endif + +int mpz_cmp(const mpz_t *z1, const mpz_t *z2) { + // to catch comparison of -0 with +0 + if (z1->len == 0 && z2->len == 0) { + return 0; + } + int cmp = (int)z2->neg - (int)z1->neg; + if (cmp != 0) { + return cmp; + } + cmp = mpn_cmp(z1->dig, z1->len, z2->dig, z2->len); + if (z1->neg != 0) { + cmp = -cmp; + } + return cmp; +} + +#if 0 +// obsolete +// compares mpz with an integer that fits within DIG_SIZE bits +mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) { + mp_int_t cmp; + if (z->neg == 0) { + if (sml_int < 0) return 1; + if (sml_int == 0) { + if (z->len == 0) return 0; + return 1; + } + if (z->len == 0) return -1; + assert(sml_int < (1 << DIG_SIZE)); + if (z->len != 1) return 1; + cmp = z->dig[0] - sml_int; + } else { + if (sml_int > 0) return -1; + if (sml_int == 0) { + if (z->len == 0) return 0; + return -1; + } + if (z->len == 0) return 1; + assert(sml_int > -(1 << DIG_SIZE)); + if (z->len != 1) return -1; + cmp = -z->dig[0] - sml_int; + } + if (cmp < 0) return -1; + if (cmp > 0) return 1; + return 0; +} +#endif + +#if 0 +these functions are unused + +/* returns abs(z) +*/ +mpz_t *mpz_abs(const mpz_t *z) { + // TODO: handle case of z->alloc=0 + mpz_t *z2 = mpz_clone(z); + z2->neg = 0; + return z2; +} + +/* returns -z +*/ +mpz_t *mpz_neg(const mpz_t *z) { + // TODO: handle case of z->alloc=0 + mpz_t *z2 = mpz_clone(z); + z2->neg = 1 - z2->neg; + return z2; +} + +/* returns lhs + rhs + can have lhs, rhs the same +*/ +mpz_t *mpz_add(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t *z = mpz_zero(); + mpz_add_inpl(z, lhs, rhs); + return z; +} + +/* returns lhs - rhs + can have lhs, rhs the same +*/ +mpz_t *mpz_sub(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t *z = mpz_zero(); + mpz_sub_inpl(z, lhs, rhs); + return z; +} + +/* returns lhs * rhs + can have lhs, rhs the same +*/ +mpz_t *mpz_mul(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t *z = mpz_zero(); + mpz_mul_inpl(z, lhs, rhs); + return z; +} + +/* returns lhs ** rhs + can have lhs, rhs the same +*/ +mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t *z = mpz_zero(); + mpz_pow_inpl(z, lhs, rhs); + return z; +} + +/* computes new integers in quo and rem such that: + quo * rhs + rem = lhs + 0 <= rem < rhs + can have lhs, rhs the same +*/ +void mpz_divmod(const mpz_t *lhs, const mpz_t *rhs, mpz_t **quo, mpz_t **rem) { + *quo = mpz_zero(); + *rem = mpz_zero(); + mpz_divmod_inpl(*quo, *rem, lhs, rhs); +} +#endif + +/* computes dest = abs(z) + can have dest, z the same +*/ +void mpz_abs_inpl(mpz_t *dest, const mpz_t *z) { + if (dest != z) { + mpz_set(dest, z); + } + dest->neg = 0; +} + +/* computes dest = -z + can have dest, z the same +*/ +void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) { + if (dest != z) { + mpz_set(dest, z); + } + dest->neg = 1 - dest->neg; +} + +/* computes dest = ~z (= -z - 1) + can have dest, z the same +*/ +void mpz_not_inpl(mpz_t *dest, const mpz_t *z) { + if (dest != z) { + mpz_set(dest, z); + } + if (dest->len == 0) { + mpz_need_dig(dest, 1); + dest->dig[0] = 1; + dest->len = 1; + dest->neg = 1; + } else if (dest->neg) { + dest->neg = 0; + mpz_dig_t k = 1; + dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1); + } else { + mpz_need_dig(dest, dest->len + 1); + mpz_dig_t k = 1; + dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1); + dest->neg = 1; + } +} + +/* computes dest = lhs << rhs + can have dest, lhs the same +*/ +void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) { + if (lhs->len == 0 || rhs == 0) { + mpz_set(dest, lhs); + } else { + mpz_need_dig(dest, lhs->len + (rhs + DIG_SIZE - 1) / DIG_SIZE); + dest->len = mpn_shl(dest->dig, lhs->dig, lhs->len, rhs); + dest->neg = lhs->neg; + } +} + +/* computes dest = lhs >> rhs + can have dest, lhs the same +*/ +void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs) { + if (lhs->len == 0 || rhs == 0) { + mpz_set(dest, lhs); + } else { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_shr(dest->dig, lhs->dig, lhs->len, rhs); + dest->neg = lhs->neg; + if (dest->neg) { + // arithmetic shift right, rounding to negative infinity + mp_uint_t n_whole = rhs / DIG_SIZE; + mp_uint_t n_part = rhs % DIG_SIZE; + mpz_dig_t round_up = 0; + for (size_t i = 0; i < lhs->len && i < n_whole; i++) { + if (lhs->dig[i] != 0) { + round_up = 1; + break; + } + } + if (n_whole < lhs->len && (lhs->dig[n_whole] & ((1 << n_part) - 1)) != 0) { + round_up = 1; + } + if (round_up) { + if (dest->len == 0) { + // dest == 0, so need to add 1 by hand (answer will be -1) + dest->dig[0] = 1; + dest->len = 1; + } else { + // dest > 0, so can use mpn_add to add 1 + dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1); + } + } + } + } +} + +/* computes dest = lhs + rhs + can have dest, lhs, rhs the same +*/ +void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + if (lhs->neg == rhs->neg) { + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } + + dest->neg = lhs->neg; +} + +/* computes dest = lhs - rhs + can have dest, lhs, rhs the same +*/ +void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + bool neg = false; + + if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + neg = true; + } + + if (lhs->neg != rhs->neg) { + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_add(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } + + if (neg) { + dest->neg = 1 - lhs->neg; + } else { + dest->neg = lhs->neg; + } +} + +/* computes dest = lhs & rhs + can have dest, lhs, rhs the same +*/ +void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + // make sure lhs has the most digits + if (lhs->len < rhs->len) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + #if MICROPY_OPT_MPZ_BITWISE + + if ((0 == lhs->neg) && (0 == rhs->neg)) { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len); + dest->neg = 0; + } else { + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, + lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg); + dest->neg = lhs->neg & rhs->neg; + } + + #else + + mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); + dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, + (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg); + dest->neg = lhs->neg & rhs->neg; + + #endif +} + +/* computes dest = lhs | rhs + can have dest, lhs, rhs the same +*/ +void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + // make sure lhs has the most digits + if (lhs->len < rhs->len) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + #if MICROPY_OPT_MPZ_BITWISE + + if ((0 == lhs->neg) && (0 == rhs->neg)) { + mpz_need_dig(dest, lhs->len); + dest->len = mpn_or(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + dest->neg = 0; + } else { + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, + 0 != lhs->neg, 0 != rhs->neg); + dest->neg = 1; + } + + #else + + mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); + dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, + (lhs->neg || rhs->neg), lhs->neg, rhs->neg); + dest->neg = lhs->neg | rhs->neg; + + #endif +} + +/* computes dest = lhs ^ rhs + can have dest, lhs, rhs the same +*/ +void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + // make sure lhs has the most digits + if (lhs->len < rhs->len) { + const mpz_t *temp = lhs; + lhs = rhs; + rhs = temp; + } + + #if MICROPY_OPT_MPZ_BITWISE + + if (lhs->neg == rhs->neg) { + mpz_need_dig(dest, lhs->len); + if (lhs->neg == 0) { + dest->len = mpn_xor(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + } else { + dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 0, 0, 0); + } + dest->neg = 0; + } else { + mpz_need_dig(dest, lhs->len + 1); + dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1, + 0 == lhs->neg, 0 == rhs->neg); + dest->neg = 1; + } + + #else + + mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg)); + dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, + (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg); + dest->neg = lhs->neg ^ rhs->neg; + + #endif +} + +/* computes dest = lhs * rhs + can have dest, lhs, rhs the same +*/ +void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (lhs->len == 0 || rhs->len == 0) { + mpz_set_from_int(dest, 0); + return; + } + + mpz_t *temp = NULL; + if (lhs == dest) { + lhs = temp = mpz_clone(lhs); + if (rhs == dest) { + rhs = lhs; + } + } else if (rhs == dest) { + rhs = temp = mpz_clone(rhs); + } + + mpz_need_dig(dest, lhs->len + rhs->len); // min mem l+r-1, max mem l+r + memset(dest->dig, 0, dest->alloc * sizeof(mpz_dig_t)); + dest->len = mpn_mul(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); + + if (lhs->neg == rhs->neg) { + dest->neg = 0; + } else { + dest->neg = 1; + } + + mpz_free(temp); +} + +/* computes dest = lhs ** rhs + can have dest, lhs, rhs the same +*/ +void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { + if (lhs->len == 0 || rhs->neg != 0) { + mpz_set_from_int(dest, 0); + return; + } + + if (rhs->len == 0) { + mpz_set_from_int(dest, 1); + return; + } + + mpz_t *x = mpz_clone(lhs); + mpz_t *n = mpz_clone(rhs); + + mpz_set_from_int(dest, 1); + + while (n->len > 0) { + if ((n->dig[0] & 1) != 0) { + mpz_mul_inpl(dest, dest, x); + } + n->len = mpn_shr(n->dig, n->dig, n->len, 1); + if (n->len == 0) { + break; + } + mpz_mul_inpl(x, x, x); + } + + mpz_free(x); + mpz_free(n); +} + +/* computes dest = (lhs ** rhs) % mod + can have dest, lhs, rhs the same; mod can't be the same as dest +*/ +void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) { + if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) { + mpz_set_from_int(dest, 0); + return; + } + + mpz_set_from_int(dest, 1); + + if (rhs->len == 0) { + return; + } + + mpz_t *x = mpz_clone(lhs); + mpz_t *n = mpz_clone(rhs); + mpz_t quo; mpz_init_zero(&quo); + + while (n->len > 0) { + if ((n->dig[0] & 1) != 0) { + mpz_mul_inpl(dest, dest, x); + mpz_divmod_inpl(&quo, dest, dest, mod); + } + n->len = mpn_shr(n->dig, n->dig, n->len, 1); + if (n->len == 0) { + break; + } + mpz_mul_inpl(x, x, x); + mpz_divmod_inpl(&quo, x, x, mod); + } + + mpz_deinit(&quo); + mpz_free(x); + mpz_free(n); +} + +#if 0 +these functions are unused + +/* computes gcd(z1, z2) + based on Knuth's modified gcd algorithm (I think?) + gcd(z1, z2) >= 0 + gcd(0, 0) = 0 + gcd(z, 0) = abs(z) +*/ +mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) { + if (z1->len == 0) { + // TODO: handle case of z2->alloc=0 + mpz_t *a = mpz_clone(z2); + a->neg = 0; + return a; + } else if (z2->len == 0) { + mpz_t *a = mpz_clone(z1); + a->neg = 0; + return a; + } + + mpz_t *a = mpz_clone(z1); + mpz_t *b = mpz_clone(z2); + mpz_t c; mpz_init_zero(&c); + a->neg = 0; + b->neg = 0; + + for (;;) { + if (mpz_cmp(a, b) < 0) { + if (a->len == 0) { + mpz_free(a); + mpz_deinit(&c); + return b; + } + mpz_t *t = a; a = b; b = t; + } + if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0 + break; + } + mpz_set(&c, b); + do { + mpz_add_inpl(&c, &c, &c); + } while (mpz_cmp(&c, a) <= 0); + c.len = mpn_shr(c.dig, c.dig, c.len, 1); + mpz_sub_inpl(a, a, &c); + } + + mpz_deinit(&c); + + if (b->len == 1 && b->dig[0] == 1) { // compute b == 1; could be mpz_cmp_small_int(b, 1) == 0 + mpz_free(a); + return b; + } else { + mpz_free(b); + return a; + } +} + +/* computes lcm(z1, z2) + = abs(z1) / gcd(z1, z2) * abs(z2) + lcm(z1, z1) >= 0 + lcm(0, 0) = 0 + lcm(z, 0) = 0 +*/ +mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) { + if (z1->len == 0 || z2->len == 0) { + return mpz_zero(); + } + + mpz_t *gcd = mpz_gcd(z1, z2); + mpz_t *quo = mpz_zero(); + mpz_t *rem = mpz_zero(); + mpz_divmod_inpl(quo, rem, z1, gcd); + mpz_mul_inpl(rem, quo, z2); + mpz_free(gcd); + mpz_free(quo); + rem->neg = 0; + return rem; +} +#endif + +/* computes new integers in quo and rem such that: + quo * rhs + rem = lhs + 0 <= rem < rhs + can have lhs, rhs the same + assumes rhs != 0 (undefined behaviour if it is) +*/ +void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) { + assert(!mpz_is_zero(rhs)); + + mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary? + memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t)); + dest_quo->len = 0; + mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary? + mpz_set(dest_rem, lhs); + mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len); + + // check signs and do Python style modulo + if (lhs->neg != rhs->neg) { + dest_quo->neg = 1; + if (!mpz_is_zero(dest_rem)) { + mpz_t mpzone; mpz_init_from_int(&mpzone, -1); + mpz_add_inpl(dest_quo, dest_quo, &mpzone); + mpz_add_inpl(dest_rem, dest_rem, rhs); + } + } +} + +#if 0 +these functions are unused + +/* computes floor(lhs / rhs) + can have lhs, rhs the same +*/ +mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t *quo = mpz_zero(); + mpz_t rem; mpz_init_zero(&rem); + mpz_divmod_inpl(quo, &rem, lhs, rhs); + mpz_deinit(&rem); + return quo; +} + +/* computes lhs % rhs ( >= 0) + can have lhs, rhs the same +*/ +mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) { + mpz_t quo; mpz_init_zero(&quo); + mpz_t *rem = mpz_zero(); + mpz_divmod_inpl(&quo, rem, lhs, rhs); + mpz_deinit(&quo); + return rem; +} +#endif + +// must return actual int value if it fits in mp_int_t +mp_int_t mpz_hash(const mpz_t *z) { + mp_uint_t val = 0; + mpz_dig_t *d = z->dig + z->len; + + while (d-- > z->dig) { + val = (val << DIG_SIZE) | *d; + } + + if (z->neg != 0) { + val = -val; + } + + return val; +} + +bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) { + mp_uint_t val = 0; + mpz_dig_t *d = i->dig + i->len; + + while (d-- > i->dig) { + if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) { + // will overflow + return false; + } + val = (val << DIG_SIZE) | *d; + } + + if (i->neg != 0) { + val = -val; + } + + *value = val; + return true; +} + +bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { + if (i->neg != 0) { + // can't represent signed values + return false; + } + + mp_uint_t val = 0; + mpz_dig_t *d = i->dig + i->len; + + while (d-- > i->dig) { + if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { + // will overflow + return false; + } + val = (val << DIG_SIZE) | *d; + } + + *value = val; + return true; +} + +// writes at most len bytes to buf (so buf should be zeroed before calling) +void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { + byte *b = buf; + if (big_endian) { + b += len; + } + mpz_dig_t *zdig = z->dig; + int bits = 0; + mpz_dbl_dig_t d = 0; + mpz_dbl_dig_t carry = 1; + for (size_t zlen = z->len; zlen > 0; --zlen) { + bits += DIG_SIZE; + d = (d << DIG_SIZE) | *zdig++; + for (; bits >= 8; bits -= 8, d >>= 8) { + mpz_dig_t val = d; + if (z->neg) { + val = (~val & 0xff) + carry; + carry = val >> 8; + } + if (big_endian) { + *--b = val; + if (b == buf) { + return; + } + } else { + *b++ = val; + if (b == buf + len) { + return; + } + } + } + } +} + +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mpz_as_float(const mpz_t *i) { + mp_float_t val = 0; + mpz_dig_t *d = i->dig + i->len; + + while (d-- > i->dig) { + val = val * DIG_BASE + *d; + } + + if (i->neg != 0) { + val = -val; + } + + return val; +} +#endif + +#if 0 +this function is unused +char *mpz_as_str(const mpz_t *i, unsigned int base) { + char *s = m_new(char, mp_int_format_size(mpz_max_num_bits(i), base, NULL, '\0')); + mpz_as_str_inpl(i, base, NULL, 'a', '\0', s); + return s; +} +#endif + +// assumes enough space in str as calculated by mp_int_format_size +// base must be between 2 and 32 inclusive +// returns length of string, not including null byte +size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) { + assert(str != NULL); + assert(2 <= base && base <= 32); + + size_t ilen = i->len; + + char *s = str; + if (ilen == 0) { + if (prefix) { + while (*prefix) + *s++ = *prefix++; + } + *s++ = '0'; + *s = '\0'; + return s - str; + } + + // make a copy of mpz digits, so we can do the div/mod calculation + mpz_dig_t *dig = m_new(mpz_dig_t, ilen); + memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t)); + + // convert + char *last_comma = str; + bool done; + do { + mpz_dig_t *d = dig + ilen; + mpz_dbl_dig_t a = 0; + + // compute next remainder + while (--d >= dig) { + a = (a << DIG_SIZE) | *d; + *d = a / base; + a %= base; + } + + // convert to character + a += '0'; + if (a > '9') { + a += base_char - '9' - 1; + } + *s++ = a; + + // check if number is zero + done = true; + for (d = dig; d < dig + ilen; ++d) { + if (*d != 0) { + done = false; + break; + } + } + if (comma && (s - last_comma) == 3) { + *s++ = comma; + last_comma = s; + } + } + while (!done); + + // free the copy of the digits array + m_del(mpz_dig_t, dig, ilen); + + if (prefix) { + const char *p = &prefix[strlen(prefix)]; + while (p > prefix) { + *s++ = *--p; + } + } + if (i->neg != 0) { + *s++ = '-'; + } + + // reverse string + for (char *u = str, *v = s - 1; u < v; ++u, --v) { + char temp = *u; + *u = *v; + *v = temp; + } + + *s = '\0'; // null termination + + return s - str; +} + +#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ diff --git a/src/openmv/src/micropython/py/mpz.h b/src/openmv/src/micropython/py/mpz.h new file mode 100755 index 0000000..3c36cac --- /dev/null +++ b/src/openmv/src/micropython/py/mpz.h @@ -0,0 +1,147 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_MPZ_H +#define MICROPY_INCLUDED_PY_MPZ_H + +#include + +#include "py/mpconfig.h" +#include "py/misc.h" + +// This mpz module implements arbitrary precision integers. +// +// The storage for each digit is defined by mpz_dig_t. The actual number of +// bits in mpz_dig_t that are used is defined by MPZ_DIG_SIZE. The machine must +// also provide a type that is twice as wide as mpz_dig_t, in both signed and +// unsigned versions. +// +// MPZ_DIG_SIZE can be between 4 and 8*sizeof(mpz_dig_t), but it makes most +// sense to have it as large as possible. If MPZ_DIG_SIZE is not already +// defined then it is auto-detected below, depending on the machine. The types +// are then set based on the value of MPZ_DIG_SIZE (although they can be freely +// changed so long as the constraints mentioned above are met). + +#ifndef MPZ_DIG_SIZE + #if defined(__x86_64__) || defined(_WIN64) + // 64-bit machine, using 32-bit storage for digits + #define MPZ_DIG_SIZE (32) + #else + // default: 32-bit machine, using 16-bit storage for digits + #define MPZ_DIG_SIZE (16) + #endif +#endif + +#if MPZ_DIG_SIZE > 16 +#define MPZ_DBL_DIG_SIZE (64) +typedef uint32_t mpz_dig_t; +typedef uint64_t mpz_dbl_dig_t; +typedef int64_t mpz_dbl_dig_signed_t; +#elif MPZ_DIG_SIZE > 8 +#define MPZ_DBL_DIG_SIZE (32) +typedef uint16_t mpz_dig_t; +typedef uint32_t mpz_dbl_dig_t; +typedef int32_t mpz_dbl_dig_signed_t; +#elif MPZ_DIG_SIZE > 4 +#define MPZ_DBL_DIG_SIZE (16) +typedef uint8_t mpz_dig_t; +typedef uint16_t mpz_dbl_dig_t; +typedef int16_t mpz_dbl_dig_signed_t; +#else +#define MPZ_DBL_DIG_SIZE (8) +typedef uint8_t mpz_dig_t; +typedef uint8_t mpz_dbl_dig_t; +typedef int8_t mpz_dbl_dig_signed_t; +#endif + +#ifdef _WIN64 + #ifdef __MINGW32__ + #define MPZ_LONG_1 1LL + #else + #define MPZ_LONG_1 1i64 + #endif +#else + #define MPZ_LONG_1 1L +#endif + +// these define the maximum storage needed to hold an int or long long +#define MPZ_NUM_DIG_FOR_INT ((sizeof(mp_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE) +#define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE) + +typedef struct _mpz_t { + size_t neg : 1; + size_t fixed_dig : 1; + size_t alloc : 8 * sizeof(size_t) - 2; + size_t len; + mpz_dig_t *dig; +} mpz_t; + +// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer +#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val); + +void mpz_init_zero(mpz_t *z); +void mpz_init_from_int(mpz_t *z, mp_int_t val); +void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, size_t dig_alloc, mp_int_t val); +void mpz_deinit(mpz_t *z); + +void mpz_set(mpz_t *dest, const mpz_t *src); +void mpz_set_from_int(mpz_t *z, mp_int_t src); +void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed); +#if MICROPY_PY_BUILTINS_FLOAT +void mpz_set_from_float(mpz_t *z, mp_float_t src); +#endif +size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base); +void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf); + +static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; } +static inline bool mpz_is_neg(const mpz_t *z) { return z->len != 0 && z->neg != 0; } +int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs); + +void mpz_abs_inpl(mpz_t *dest, const mpz_t *z); +void mpz_neg_inpl(mpz_t *dest, const mpz_t *z); +void mpz_not_inpl(mpz_t *dest, const mpz_t *z); +void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs); +void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_uint_t rhs); +void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod); +void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); +void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); + +static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; } +mp_int_t mpz_hash(const mpz_t *z); +bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); +bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); +void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf); +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mpz_as_float(const mpz_t *z); +#endif +size_t mpz_as_str_inpl(const mpz_t *z, unsigned int base, const char *prefix, char base_char, char comma, char *str); + +#endif // MICROPY_INCLUDED_PY_MPZ_H diff --git a/src/openmv/src/micropython/py/nativeglue.c b/src/openmv/src/micropython/py/nativeglue.c new file mode 100755 index 0000000..b7031a5 --- /dev/null +++ b/src/openmv/src/micropython/py/nativeglue.c @@ -0,0 +1,240 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/emitglue.h" +#include "py/bc.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +#if MICROPY_EMIT_NATIVE + +// convert a MicroPython object to a valid native value based on type +mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) { + DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type); + switch (type & 0xf) { + case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj; + case MP_NATIVE_TYPE_BOOL: + case MP_NATIVE_TYPE_INT: + case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj); + default: { // cast obj to a pointer + mp_buffer_info_t bufinfo; + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_RW)) { + return (mp_uint_t)bufinfo.buf; + } else { + // assume obj is an integer that represents an address + return mp_obj_get_int_truncated(obj); + } + } + } +} + +#endif + +#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM + +// convert a native value to a MicroPython object based on type +mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) { + DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type); + switch (type & 0xf) { + case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val; + case MP_NATIVE_TYPE_BOOL: return mp_obj_new_bool(val); + case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val); + case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val); + default: // a pointer + // we return just the value of the pointer as an integer + return mp_obj_new_int_from_uint(val); + } +} + +#endif + +#if MICROPY_EMIT_NATIVE + +mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals) { + if (new_globals == NULL) { + // Globals were the originally the same so don't restore them + return NULL; + } + mp_obj_dict_t *old_globals = mp_globals_get(); + if (old_globals == new_globals) { + // Don't set globals if they are the same, and return NULL to indicate this + return NULL; + } + mp_globals_set(new_globals); + return old_globals; +} + +// wrapper that accepts n_args and n_kw in one argument +// (native emitter can only pass at most 3 arguments to a function) +mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args) { + return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args); +} + +// wrapper that makes raise obj and raises it +// END_FINALLY opcode requires that we don't raise if o==None +void mp_native_raise(mp_obj_t o) { + if (o != MP_OBJ_NULL && o != mp_const_none) { + nlr_raise(mp_make_raise_obj(o)); + } +} + +// wrapper that handles iterator buffer +STATIC mp_obj_t mp_native_getiter(mp_obj_t obj, mp_obj_iter_buf_t *iter) { + if (iter == NULL) { + return mp_getiter(obj, NULL); + } else { + obj = mp_getiter(obj, iter); + if (obj != MP_OBJ_FROM_PTR(iter)) { + // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. + iter->base.type = MP_OBJ_NULL; + iter->buf[0] = obj; + } + return NULL; + } +} + +// wrapper that handles iterator buffer +STATIC mp_obj_t mp_native_iternext(mp_obj_iter_buf_t *iter) { + mp_obj_t obj; + if (iter->base.type == MP_OBJ_NULL) { + obj = iter->buf[0]; + } else { + obj = MP_OBJ_FROM_PTR(iter); + } + return mp_iternext(obj); +} + +STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value) { + mp_vm_return_kind_t ret_kind; + nlr_buf_t nlr_buf; + mp_obj_t throw_value = *ret_value; + if (nlr_push(&nlr_buf) == 0) { + if (throw_value != MP_OBJ_NULL) { + send_value = MP_OBJ_NULL; + } + ret_kind = mp_resume(gen, send_value, throw_value, ret_value); + nlr_pop(); + } else { + ret_kind = MP_VM_RETURN_EXCEPTION; + *ret_value = nlr_buf.ret_val; + } + + if (ret_kind == MP_VM_RETURN_YIELD) { + return true; + } else if (ret_kind == MP_VM_RETURN_NORMAL) { + if (*ret_value == MP_OBJ_STOP_ITERATION) { + *ret_value = mp_const_none; + } + } else { + assert(ret_kind == MP_VM_RETURN_EXCEPTION); + if (!mp_obj_exception_match(*ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + nlr_raise(*ret_value); + } + *ret_value = mp_obj_exception_get_value(*ret_value); + } + + if (throw_value != MP_OBJ_NULL && mp_obj_exception_match(throw_value, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { + nlr_raise(mp_make_raise_obj(throw_value)); + } + + return false; +} + +// these must correspond to the respective enum in runtime0.h +const void *const mp_fun_table[MP_F_NUMBER_OF] = { + &mp_const_none_obj, + &mp_const_false_obj, + &mp_const_true_obj, + mp_convert_obj_to_native, + mp_convert_native_to_obj, + mp_native_swap_globals, + mp_load_name, + mp_load_global, + mp_load_build_class, + mp_load_attr, + mp_load_method, + mp_load_super_method, + mp_store_name, + mp_store_global, + mp_store_attr, + mp_obj_subscr, + mp_obj_is_true, + mp_unary_op, + mp_binary_op, + mp_obj_new_tuple, + mp_obj_new_list, + mp_obj_list_append, + mp_obj_new_dict, + mp_obj_dict_store, +#if MICROPY_PY_BUILTINS_SET + mp_obj_set_store, + mp_obj_new_set, +#endif + mp_make_function_from_raw_code, + mp_native_call_function_n_kw, + mp_call_method_n_kw, + mp_call_method_n_kw_var, + mp_native_getiter, + mp_native_iternext, + nlr_push, + nlr_pop, + mp_native_raise, + mp_import_name, + mp_import_from, + mp_import_all, +#if MICROPY_PY_BUILTINS_SLICE + mp_obj_new_slice, +#endif + mp_unpack_sequence, + mp_unpack_ex, + mp_delete_name, + mp_delete_global, + mp_obj_new_cell, + mp_make_closure_from_raw_code, + mp_arg_check_num_sig, + mp_setup_code_state, + mp_small_int_floor_divide, + mp_small_int_modulo, + mp_native_yield_from, +}; + +/* +void mp_f_vector(mp_fun_kind_t fun_kind) { + (mp_f_table[fun_kind])(); +} +*/ + +#endif // MICROPY_EMIT_NATIVE diff --git a/src/openmv/src/micropython/py/nlr.c b/src/openmv/src/micropython/py/nlr.c new file mode 100755 index 0000000..03d0157 --- /dev/null +++ b/src/openmv/src/micropython/py/nlr.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if !MICROPY_NLR_SETJMP +// When not using setjmp, nlr_push_tail is called from inline asm so needs special care +#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif +#endif + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} diff --git a/src/openmv/src/micropython/py/nlr.h b/src/openmv/src/micropython/py/nlr.h new file mode 100755 index 0000000..90595a1 --- /dev/null +++ b/src/openmv/src/micropython/py/nlr.h @@ -0,0 +1,153 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_NLR_H +#define MICROPY_INCLUDED_PY_NLR_H + +// non-local return +// exception handling, basically a stack of setjmp/longjmp buffers + +#include +#include + +#include "py/mpconfig.h" + +// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch +#if !MICROPY_NLR_SETJMP +// A lot of nlr-related things need different treatment on Windows +#if defined(_WIN32) || defined(__CYGWIN__) +#define MICROPY_NLR_OS_WINDOWS 1 +#else +#define MICROPY_NLR_OS_WINDOWS 0 +#endif +#if defined(__i386__) + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) +#elif defined(__x86_64__) + #define MICROPY_NLR_X64 (1) + #if MICROPY_NLR_OS_WINDOWS + #define MICROPY_NLR_NUM_REGS (10) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif +#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) + #define MICROPY_NLR_THUMB (1) + #define MICROPY_NLR_NUM_REGS (10) +#elif defined(__xtensa__) + #define MICROPY_NLR_XTENSA (1) + #define MICROPY_NLR_NUM_REGS (10) +#else + #define MICROPY_NLR_SETJMP (1) + //#warning "No native NLR support for this arch, using setjmp implementation" +#endif +#endif + +#if MICROPY_NLR_SETJMP +#include +#endif + +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) + + #if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; + #else + void *regs[MICROPY_NLR_NUM_REGS]; + #endif + + #if MICROPY_ENABLE_PYSTACK + void *pystack; + #endif +}; + +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack +#else +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf +#endif + +// Helper macro to use at the start of a specific nlr_jump implementation +#define MP_NLR_JUMP_HEAD(val, top) \ + nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ + nlr_buf_t *top = *_top_ptr; \ + if (top == NULL) { \ + nlr_jump_fail(val); \ + } \ + top->ret_val = val; \ + MP_NLR_RESTORE_PYSTACK(top); \ + *_top_ptr = top->prev; \ + +#if MICROPY_NLR_SETJMP +// nlr_push() must be defined as a macro, because "The stack context will be +// invalidated if the function which called setjmp() returns." +// For this case it is safe to call nlr_push_tail() first. +#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) +#else +unsigned int nlr_push(nlr_buf_t *); +#endif + +unsigned int nlr_push_tail(nlr_buf_t *top); +void nlr_pop(void); +NORETURN void nlr_jump(void *val); + +// This must be implemented by a port. It's called by nlr_jump +// if no nlr buf has been pushed. It must not return, but rather +// should bail out with a fatal error. +NORETURN void nlr_jump_fail(void *val); + +// use nlr_raise instead of nlr_jump so that debugging is easier +#ifndef MICROPY_DEBUG_NLR +#define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val)) +#else +#include "mpstate.h" +#define nlr_raise(val) \ + do { \ + /*printf("nlr_raise: nlr_top=%p\n", MP_STATE_THREAD(nlr_top)); \ + fflush(stdout);*/ \ + void *_val = MP_OBJ_TO_PTR(val); \ + assert(_val != NULL); \ + assert(mp_obj_is_exception_instance(val)); \ + nlr_jump(_val); \ + } while (0) + +#if !MICROPY_NLR_SETJMP +#define nlr_push(val) \ + assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) + +/* +#define nlr_push(val) \ + printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) +*/ +#endif + +#endif + +#endif // MICROPY_INCLUDED_PY_NLR_H diff --git a/src/openmv/src/micropython/py/nlrsetjmp.c b/src/openmv/src/micropython/py/nlrsetjmp.c new file mode 100755 index 0000000..960dd86 --- /dev/null +++ b/src/openmv/src/micropython/py/nlrsetjmp.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_SETJMP + +void nlr_jump(void *val) { + nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); + nlr_buf_t *top = *top_ptr; + if (top == NULL) { + nlr_jump_fail(val); + } + top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); + *top_ptr = top->prev; + longjmp(top->jmpbuf, 1); +} + +#endif diff --git a/src/openmv/src/micropython/py/nlrthumb.c b/src/openmv/src/micropython/py/nlrthumb.c new file mode 100755 index 0000000..c283023 --- /dev/null +++ b/src/openmv/src/micropython/py/nlrthumb.c @@ -0,0 +1,131 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_THUMB + +#undef nlr_push + +// We only need the functions here if we are on arm/thumb, and we are not +// using setjmp/longjmp. +// +// For reference, arm/thumb callee save regs are: +// r4-r11, r13=sp + +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm volatile ( + "str r4, [r0, #12] \n" // store r4 into nlr_buf + "str r5, [r0, #16] \n" // store r5 into nlr_buf + "str r6, [r0, #20] \n" // store r6 into nlr_buf + "str r7, [r0, #24] \n" // store r7 into nlr_buf + +#if defined(__ARM_ARCH_6M__) + "mov r1, r8 \n" + "str r1, [r0, #28] \n" // store r8 into nlr_buf + "mov r1, r9 \n" + "str r1, [r0, #32] \n" // store r9 into nlr_buf + "mov r1, r10 \n" + "str r1, [r0, #36] \n" // store r10 into nlr_buf + "mov r1, r11 \n" + "str r1, [r0, #40] \n" // store r11 into nlr_buf + "mov r1, r13 \n" + "str r1, [r0, #44] \n" // store r13=sp into nlr_buf + "mov r1, lr \n" + "str r1, [r0, #8] \n" // store lr into nlr_buf +#else + "str r8, [r0, #28] \n" // store r8 into nlr_buf + "str r9, [r0, #32] \n" // store r9 into nlr_buf + "str r10, [r0, #36] \n" // store r10 into nlr_buf + "str r11, [r0, #40] \n" // store r11 into nlr_buf + "str r13, [r0, #44] \n" // store r13=sp into nlr_buf + "str lr, [r0, #8] \n" // store lr into nlr_buf +#endif + +#if defined(__ARM_ARCH_6M__) + "ldr r1, nlr_push_tail_var \n" + "bx r1 \n" // do the rest in C + ".align 2 \n" + "nlr_push_tail_var: .word nlr_push_tail \n" +#else + "b nlr_push_tail \n" // do the rest in C +#endif + ); + + #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) + // Older versions of gcc give an error when naked functions don't return a value + // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement + return 0; + #endif +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm volatile ( + "mov r0, %0 \n" // r0 points to nlr_buf + "ldr r4, [r0, #12] \n" // load r4 from nlr_buf + "ldr r5, [r0, #16] \n" // load r5 from nlr_buf + "ldr r6, [r0, #20] \n" // load r6 from nlr_buf + "ldr r7, [r0, #24] \n" // load r7 from nlr_buf + +#if defined(__ARM_ARCH_6M__) + "ldr r1, [r0, #28] \n" // load r8 from nlr_buf + "mov r8, r1 \n" + "ldr r1, [r0, #32] \n" // load r9 from nlr_buf + "mov r9, r1 \n" + "ldr r1, [r0, #36] \n" // load r10 from nlr_buf + "mov r10, r1 \n" + "ldr r1, [r0, #40] \n" // load r11 from nlr_buf + "mov r11, r1 \n" + "ldr r1, [r0, #44] \n" // load r13=sp from nlr_buf + "mov r13, r1 \n" + "ldr r1, [r0, #8] \n" // load lr from nlr_buf + "mov lr, r1 \n" +#else + "ldr r8, [r0, #28] \n" // load r8 from nlr_buf + "ldr r9, [r0, #32] \n" // load r9 from nlr_buf + "ldr r10, [r0, #36] \n" // load r10 from nlr_buf + "ldr r11, [r0, #40] \n" // load r11 from nlr_buf + "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf + "ldr lr, [r0, #8] \n" // load lr from nlr_buf +#endif + "movs r0, #1 \n" // return 1, non-local return + "bx lr \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers + ); + + #if defined(__GNUC__) + __builtin_unreachable(); + #else + for (;;); // needed to silence compiler warning + #endif +} + +#endif // MICROPY_NLR_THUMB diff --git a/src/openmv/src/micropython/py/nlrx64.c b/src/openmv/src/micropython/py/nlrx64.c new file mode 100755 index 0000000..a3a1cf3 --- /dev/null +++ b/src/openmv/src/micropython/py/nlrx64.c @@ -0,0 +1,114 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_X64 + +#undef nlr_push + +// x86-64 callee-save registers are: +// rbx, rbp, rsp, r12, r13, r14, r15 + +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); + +unsigned int nlr_push(nlr_buf_t *nlr) { + (void)nlr; + + #if MICROPY_NLR_OS_WINDOWS + + __asm volatile ( + "movq (%rsp), %rax \n" // load return %rip + "movq %rax, 16(%rcx) \n" // store %rip into nlr_buf + "movq %rbp, 24(%rcx) \n" // store %rbp into nlr_buf + "movq %rsp, 32(%rcx) \n" // store %rsp into nlr_buf + "movq %rbx, 40(%rcx) \n" // store %rbx into nlr_buf + "movq %r12, 48(%rcx) \n" // store %r12 into nlr_buf + "movq %r13, 56(%rcx) \n" // store %r13 into nlr_buf + "movq %r14, 64(%rcx) \n" // store %r14 into nlr_buf + "movq %r15, 72(%rcx) \n" // store %r15 into nlr_buf + "movq %rdi, 80(%rcx) \n" // store %rdr into nlr_buf + "movq %rsi, 88(%rcx) \n" // store %rsi into nlr_buf + "jmp nlr_push_tail \n" // do the rest in C + ); + + #else + + __asm volatile ( + #if defined(__APPLE__) || defined(__MACH__) + "pop %rbp \n" // undo function's prelude + #endif + "movq (%rsp), %rax \n" // load return %rip + "movq %rax, 16(%rdi) \n" // store %rip into nlr_buf + "movq %rbp, 24(%rdi) \n" // store %rbp into nlr_buf + "movq %rsp, 32(%rdi) \n" // store %rsp into nlr_buf + "movq %rbx, 40(%rdi) \n" // store %rbx into nlr_buf + "movq %r12, 48(%rdi) \n" // store %r12 into nlr_buf + "movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf + "movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf + "movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf + #if defined(__APPLE__) || defined(__MACH__) + "jmp _nlr_push_tail \n" // do the rest in C + #else + "jmp nlr_push_tail \n" // do the rest in C + #endif + ); + + #endif + + return 0; // needed to silence compiler warning +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm volatile ( + "movq %0, %%rcx \n" // %rcx points to nlr_buf + #if MICROPY_NLR_OS_WINDOWS + "movq 88(%%rcx), %%rsi \n" // load saved %rsi + "movq 80(%%rcx), %%rdi \n" // load saved %rdr + #endif + "movq 72(%%rcx), %%r15 \n" // load saved %r15 + "movq 64(%%rcx), %%r14 \n" // load saved %r14 + "movq 56(%%rcx), %%r13 \n" // load saved %r13 + "movq 48(%%rcx), %%r12 \n" // load saved %r12 + "movq 40(%%rcx), %%rbx \n" // load saved %rbx + "movq 32(%%rcx), %%rsp \n" // load saved %rsp + "movq 24(%%rcx), %%rbp \n" // load saved %rbp + "movq 16(%%rcx), %%rax \n" // load saved %rip + "movq %%rax, (%%rsp) \n" // store saved %rip to stack + "xorq %%rax, %%rax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return + "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers + ); + + for (;;); // needed to silence compiler warning +} + +#endif // MICROPY_NLR_X64 diff --git a/src/openmv/src/micropython/py/nlrx86.c b/src/openmv/src/micropython/py/nlrx86.c new file mode 100755 index 0000000..59b97d8 --- /dev/null +++ b/src/openmv/src/micropython/py/nlrx86.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_X86 + +#undef nlr_push + +// For reference, x86 callee save regs are: +// ebx, esi, edi, ebp, esp, eip + +#if MICROPY_NLR_OS_WINDOWS +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif + +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8 +// Since gcc 8.0 the naked attribute is supported +#define USE_NAKED (1) +#define UNDO_PRELUDE (0) +#elif defined(__ZEPHYR__) || defined(__ANDROID__) +// Zephyr and Android use a different calling convention by default +#define USE_NAKED (0) +#define UNDO_PRELUDE (0) +#else +#define USE_NAKED (0) +#define UNDO_PRELUDE (1) +#endif + +#if USE_NAKED +__attribute__((naked)) +#endif +unsigned int nlr_push(nlr_buf_t *nlr) { + #if !USE_NAKED + (void)nlr; + #endif + + __asm volatile ( + #if UNDO_PRELUDE + "pop %ebp \n" // undo function's prelude + #endif + "mov 4(%esp), %edx \n" // load nlr_buf + "mov (%esp), %eax \n" // load return %eip + "mov %eax, 8(%edx) \n" // store %eip into nlr_buf + "mov %ebp, 12(%edx) \n" // store %ebp into nlr_buf + "mov %esp, 16(%edx) \n" // store %esp into nlr_buf + "mov %ebx, 20(%edx) \n" // store %ebx into nlr_buf + "mov %edi, 24(%edx) \n" // store %edi into nlr_buf + "mov %esi, 28(%edx) \n" // store %esi into nlr_buf + "jmp nlr_push_tail \n" // do the rest in C + ); + + #if !USE_NAKED + return 0; // needed to silence compiler warning + #endif +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm volatile ( + "mov %0, %%edx \n" // %edx points to nlr_buf + "mov 28(%%edx), %%esi \n" // load saved %esi + "mov 24(%%edx), %%edi \n" // load saved %edi + "mov 20(%%edx), %%ebx \n" // load saved %ebx + "mov 16(%%edx), %%esp \n" // load saved %esp + "mov 12(%%edx), %%ebp \n" // load saved %ebp + "mov 8(%%edx), %%eax \n" // load saved %eip + "mov %%eax, (%%esp) \n" // store saved %eip to stack + "xor %%eax, %%eax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return + "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers + ); + + for (;;); // needed to silence compiler warning +} + +#endif // MICROPY_NLR_X86 diff --git a/src/openmv/src/micropython/py/nlrxtensa.c b/src/openmv/src/micropython/py/nlrxtensa.c new file mode 100755 index 0000000..cd3dee3 --- /dev/null +++ b/src/openmv/src/micropython/py/nlrxtensa.c @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_XTENSA + +#undef nlr_push + +// Xtensa calling conventions: +// a0 = return address +// a1 = stack pointer +// a2 = first arg, return value +// a3-a7 = rest of args + +unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm volatile ( + "s32i.n a0, a2, 8 \n" // save regs... + "s32i.n a1, a2, 12 \n" + "s32i.n a8, a2, 16 \n" + "s32i.n a9, a2, 20 \n" + "s32i.n a10, a2, 24 \n" + "s32i.n a11, a2, 28 \n" + "s32i.n a12, a2, 32 \n" + "s32i.n a13, a2, 36 \n" + "s32i.n a14, a2, 40 \n" + "s32i.n a15, a2, 44 \n" + "j nlr_push_tail \n" // do the rest in C + ); + + return 0; // needed to silence compiler warning +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm volatile ( + "mov.n a2, %0 \n" // a2 points to nlr_buf + "l32i.n a0, a2, 8 \n" // restore regs... + "l32i.n a1, a2, 12 \n" + "l32i.n a8, a2, 16 \n" + "l32i.n a9, a2, 20 \n" + "l32i.n a10, a2, 24 \n" + "l32i.n a11, a2, 28 \n" + "l32i.n a12, a2, 32 \n" + "l32i.n a13, a2, 36 \n" + "l32i.n a14, a2, 40 \n" + "l32i.n a15, a2, 44 \n" + "movi.n a2, 1 \n" // return 1, non-local return + "ret.n \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers + ); + + for (;;); // needed to silence compiler warning +} + +#endif // MICROPY_NLR_XTENSA diff --git a/src/openmv/src/micropython/py/obj.c b/src/openmv/src/micropython/py/obj.c new file mode 100755 index 0000000..5eb2b09 --- /dev/null +++ b/src/openmv/src/micropython/py/obj.c @@ -0,0 +1,535 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/obj.h" +#include "py/objtype.h" +#include "py/objint.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stackctrl.h" +#include "py/stream.h" // for mp_obj_print + +mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { + if (MP_OBJ_IS_SMALL_INT(o_in)) { + return (mp_obj_type_t*)&mp_type_int; + } else if (MP_OBJ_IS_QSTR(o_in)) { + return (mp_obj_type_t*)&mp_type_str; + #if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(o_in)) { + return (mp_obj_type_t*)&mp_type_float; + #endif + } else { + const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in); + return (mp_obj_type_t*)o->type; + } +} + +const char *mp_obj_get_type_str(mp_const_obj_t o_in) { + return qstr_str(mp_obj_get_type(o_in)->name); +} + +void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + // There can be data structures nested too deep, or just recursive + MP_STACK_CHECK(); +#ifndef NDEBUG + if (o_in == MP_OBJ_NULL) { + mp_print_str(print, "(nil)"); + return; + } +#endif + mp_obj_type_t *type = mp_obj_get_type(o_in); + if (type->print != NULL) { + type->print((mp_print_t*)print, o_in, kind); + } else { + mp_printf(print, "<%q>", type->name); + } +} + +void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { + mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind); +} + +// helper function to print an exception with traceback +void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { + if (mp_obj_is_exception_instance(exc)) { + size_t n, *values; + mp_obj_exception_get_traceback(exc, &n, &values); + if (n > 0) { + assert(n % 3 == 0); + mp_print_str(print, "Traceback (most recent call last):\n"); + for (int i = n - 3; i >= 0; i -= 3) { +#if MICROPY_ENABLE_SOURCE_LINE + mp_printf(print, " File \"%q\", line %d", values[i], (int)values[i + 1]); +#else + mp_printf(print, " File \"%q\"", values[i]); +#endif + // the block name can be NULL if it's unknown + qstr block = values[i + 2]; + if (block == MP_QSTR_NULL) { + mp_print_str(print, "\n"); + } else { + mp_printf(print, ", in %q\n", block); + } + } + } + } + mp_obj_print_helper(print, exc, PRINT_EXC); + mp_print_str(print, "\n"); +} + +bool mp_obj_is_true(mp_obj_t arg) { + if (arg == mp_const_false) { + return 0; + } else if (arg == mp_const_true) { + return 1; + } else if (arg == mp_const_none) { + return 0; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) { + return 0; + } else { + return 1; + } + } else { + mp_obj_type_t *type = mp_obj_get_type(arg); + if (type->unary_op != NULL) { + mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg); + if (result != MP_OBJ_NULL) { + return result == mp_const_true; + } + } + + mp_obj_t len = mp_obj_len_maybe(arg); + if (len != MP_OBJ_NULL) { + // obj has a length, truth determined if len != 0 + return len != MP_OBJ_NEW_SMALL_INT(0); + } else { + // any other obj is true per Python semantics + return 1; + } + } +} + +bool mp_obj_is_callable(mp_obj_t o_in) { + mp_call_fun_t call = mp_obj_get_type(o_in)->call; + if (call != mp_obj_instance_call) { + return call != NULL; + } + return mp_obj_instance_is_callable(o_in); +} + +// This function implements the '==' operator (and so the inverse of '!='). +// +// From the Python language reference: +// (https://docs.python.org/3/reference/expressions.html#not-in) +// "The objects need not have the same type. If both are numbers, they are converted +// to a common type. Otherwise, the == and != operators always consider objects of +// different types to be unequal." +// +// This means that False==0 and True==1 are true expressions. +// +// Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich +// comparison returns NotImplemented, == and != are decided by comparing the object +// pointer." +bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { + // Float (and complex) NaN is never equal to anything, not even itself, + // so we must have a special check here to cover those cases. + if (o1 == o2 + #if MICROPY_PY_BUILTINS_FLOAT + && !mp_obj_is_float(o1) + #endif + #if MICROPY_PY_BUILTINS_COMPLEX + && !MP_OBJ_IS_TYPE(o1, &mp_type_complex) + #endif + ) { + return true; + } + if (o1 == mp_const_none || o2 == mp_const_none) { + return false; + } + + // fast path for small ints + if (MP_OBJ_IS_SMALL_INT(o1)) { + if (MP_OBJ_IS_SMALL_INT(o2)) { + // both SMALL_INT, and not equal if we get here + return false; + } else { + mp_obj_t temp = o2; o2 = o1; o1 = temp; + // o2 is now the SMALL_INT, o1 is not + // fall through to generic op + } + } + + // fast path for strings + if (MP_OBJ_IS_STR(o1)) { + if (MP_OBJ_IS_STR(o2)) { + // both strings, use special function + return mp_obj_str_equal(o1, o2); + } else { + // a string is never equal to anything else + goto str_cmp_err; + } + } else if (MP_OBJ_IS_STR(o2)) { + // o1 is not a string (else caught above), so the objects are not equal + str_cmp_err: + #if MICROPY_PY_STR_BYTES_CMP_WARN + if (MP_OBJ_IS_TYPE(o1, &mp_type_bytes) || MP_OBJ_IS_TYPE(o2, &mp_type_bytes)) { + mp_warning("Comparison between bytes and str"); + } + #endif + return false; + } + + // generic type, call binary_op(MP_BINARY_OP_EQUAL) + mp_obj_type_t *type = mp_obj_get_type(o1); + if (type->binary_op != NULL) { + mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2); + if (r != MP_OBJ_NULL) { + return r == mp_const_true ? true : false; + } + } + + // equality not implemented, and objects are not the same object, so + // they are defined as not equal + return false; +} + +mp_int_t mp_obj_get_int(mp_const_obj_t arg) { + // This function essentially performs implicit type conversion to int + // Note that Python does NOT provide implicit type conversion from + // float to int in the core expression language, try some_list[1.0]. + if (arg == mp_const_false) { + return 0; + } else if (arg == mp_const_true) { + return 1; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + return MP_OBJ_SMALL_INT_VALUE(arg); + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + return mp_obj_int_get_checked(arg); + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("can't convert to int"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "can't convert %s to int", mp_obj_get_type_str(arg))); + } + } +} + +mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { + if (MP_OBJ_IS_INT(arg)) { + return mp_obj_int_get_truncated(arg); + } else { + return mp_obj_get_int(arg); + } +} + +// returns false if arg is not of integral type +// returns true and sets *value if it is of integral type +// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t +bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) { + if (arg == mp_const_false) { + *value = 0; + } else if (arg == mp_const_true) { + *value = 1; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + *value = MP_OBJ_SMALL_INT_VALUE(arg); + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + *value = mp_obj_int_get_checked(arg); + } else { + return false; + } + return true; +} + +#if MICROPY_PY_BUILTINS_FLOAT +bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) { + mp_float_t val; + + if (arg == mp_const_false) { + val = 0; + } else if (arg == mp_const_true) { + val = 1; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + val = MP_OBJ_SMALL_INT_VALUE(arg); + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + val = mp_obj_int_as_float_impl(arg); + #endif + } else if (mp_obj_is_float(arg)) { + val = mp_obj_float_get(arg); + } else { + return false; + } + + *value = val; + return true; +} + +mp_float_t mp_obj_get_float(mp_obj_t arg) { + mp_float_t val; + + if (!mp_obj_get_float_maybe(arg, &val)) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("can't convert to float"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "can't convert %s to float", mp_obj_get_type_str(arg))); + } + } + + return val; +} + +#if MICROPY_PY_BUILTINS_COMPLEX +void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { + if (arg == mp_const_false) { + *real = 0; + *imag = 0; + } else if (arg == mp_const_true) { + *real = 1; + *imag = 0; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + *real = MP_OBJ_SMALL_INT_VALUE(arg); + *imag = 0; + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + *real = mp_obj_int_as_float_impl(arg); + *imag = 0; + #endif + } else if (mp_obj_is_float(arg)) { + *real = mp_obj_float_get(arg); + *imag = 0; + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { + mp_obj_complex_get(arg, real, imag); + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("can't convert to complex"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "can't convert %s to complex", mp_obj_get_type_str(arg))); + } + } +} +#endif +#endif + +// note: returned value in *items may point to the interior of a GC block +void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { + if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { + mp_obj_tuple_get(o, len, items); + } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { + mp_obj_list_get(o, len, items); + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("expected tuple/list"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "object '%s' isn't a tuple or list", mp_obj_get_type_str(o))); + } + } +} + +// note: returned value in *items may point to the interior of a GC block +void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) { + size_t seq_len; + mp_obj_get_array(o, &seq_len, items); + if (seq_len != len) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_ValueError("tuple/list has wrong length"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "requested length %d but object has length %d", (int)len, (int)seq_len)); + } + } +} + +// is_slice determines whether the index is a slice index +size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { + mp_int_t i; + if (MP_OBJ_IS_SMALL_INT(index)) { + i = MP_OBJ_SMALL_INT_VALUE(index); + } else if (!mp_obj_get_int_maybe(index, &i)) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("indices must be integers"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "%q indices must be integers, not %s", + type->name, mp_obj_get_type_str(index))); + } + } + + if (i < 0) { + i += len; + } + if (is_slice) { + if (i < 0) { + i = 0; + } else if ((mp_uint_t)i > len) { + i = len; + } + } else { + if (i < 0 || (mp_uint_t)i >= len) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_IndexError, "index out of range"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, + "%q index out of range", type->name)); + } + } + } + + // By this point 0 <= i <= len and so fits in a size_t + return (size_t)i; +} + +mp_obj_t mp_obj_id(mp_obj_t o_in) { + mp_int_t id = (mp_int_t)o_in; + if (!MP_OBJ_IS_OBJ(o_in)) { + return mp_obj_new_int(id); + } else if (id >= 0) { + // Many OSes and CPUs have affinity for putting "user" memories + // into low half of address space, and "system" into upper half. + // We're going to take advantage of that and return small int + // (signed) for such "user" addresses. + return MP_OBJ_NEW_SMALL_INT(id); + } else { + // If that didn't work, well, let's return long int, just as + // a (big) positive value, so it will never clash with the range + // of small int returned in previous case. + return mp_obj_new_int_from_uint((mp_uint_t)id); + } +} + +// will raise a TypeError if object has no length +mp_obj_t mp_obj_len(mp_obj_t o_in) { + mp_obj_t len = mp_obj_len_maybe(o_in); + if (len == MP_OBJ_NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object has no len"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); + } + } else { + return len; + } +} + +// may return MP_OBJ_NULL +mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { + if ( +#if !MICROPY_PY_BUILTINS_STR_UNICODE + // It's simple - unicode is slow, non-unicode is fast + MP_OBJ_IS_STR(o_in) || +#endif + MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { + GET_STR_LEN(o_in, l); + return MP_OBJ_NEW_SMALL_INT(l); + } else { + mp_obj_type_t *type = mp_obj_get_type(o_in); + if (type->unary_op != NULL) { + return type->unary_op(MP_UNARY_OP_LEN, o_in); + } else { + return MP_OBJ_NULL; + } + } +} + +mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { + mp_obj_type_t *type = mp_obj_get_type(base); + if (type->subscr != NULL) { + mp_obj_t ret = type->subscr(base, index, value); + if (ret != MP_OBJ_NULL) { + return ret; + } + // TODO: call base classes here? + } + if (value == MP_OBJ_NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object doesn't support item deletion"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object doesn't support item deletion", mp_obj_get_type_str(base))); + } + } else if (value == MP_OBJ_SENTINEL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object isn't subscriptable"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't subscriptable", mp_obj_get_type_str(base))); + } + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object doesn't support item assignment"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object doesn't support item assignment", mp_obj_get_type_str(base))); + } + } +} + +// Return input argument. Useful as .getiter for objects which are +// their own iterators, etc. +mp_obj_t mp_identity(mp_obj_t self) { + return self; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); + +mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) { + (void)iter_buf; + return self; +} + +bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mp_obj_type_t *type = mp_obj_get_type(obj); + if (type->buffer_p.get_buffer == NULL) { + return false; + } + int ret = type->buffer_p.get_buffer(obj, bufinfo, flags); + if (ret != 0) { + return false; + } + return true; +} + +void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + if (!mp_get_buffer(obj, bufinfo, flags)) { + mp_raise_TypeError("object with buffer protocol required"); + } +} + +mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + switch (op) { + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); + default: return MP_OBJ_NULL; // op not supported + } +} diff --git a/src/openmv/src/micropython/py/obj.h b/src/openmv/src/micropython/py/obj.h new file mode 100755 index 0000000..1e37abc --- /dev/null +++ b/src/openmv/src/micropython/py/obj.h @@ -0,0 +1,867 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJ_H +#define MICROPY_INCLUDED_PY_OBJ_H + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/qstr.h" +#include "py/mpprint.h" +#include "py/runtime0.h" + +// This is the definition of the opaque MicroPython object type. +// All concrete objects have an encoding within this type and the +// particular encoding is specified by MICROPY_OBJ_REPR. +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +typedef uint64_t mp_obj_t; +typedef uint64_t mp_const_obj_t; +#else +typedef void *mp_obj_t; +typedef const void *mp_const_obj_t; +#endif + +// This mp_obj_type_t struct is a concrete MicroPython object which holds info +// about a type. See below for actual definition of the struct. +typedef struct _mp_obj_type_t mp_obj_type_t; + +// Anything that wants to be a concrete MicroPython object must have mp_obj_base_t +// as its first member (small ints, qstr objs and inline floats are not concrete). +struct _mp_obj_base_t { + const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT; +}; +typedef struct _mp_obj_base_t mp_obj_base_t; + +// These fake objects are used to indicate certain things in arguments or return +// values, and should only be used when explicitly allowed. +// +// - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation. +// - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency. +// - MP_OBJ_SENTINEL : used for various internal purposes where one needs +// an object which is unique from all other objects, including MP_OBJ_NULL. +// +// For debugging purposes they are all different. For non-debug mode, we alias +// as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0. + +#ifdef NDEBUG +#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) +#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)0)) +#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)4)) +#else +#define MP_OBJ_NULL (MP_OBJ_FROM_PTR((void*)0)) +#define MP_OBJ_STOP_ITERATION (MP_OBJ_FROM_PTR((void*)4)) +#define MP_OBJ_SENTINEL (MP_OBJ_FROM_PTR((void*)8)) +#endif + +// These macros/inline functions operate on objects and depend on the +// particular object representation. They are used to query, pack and +// unpack small ints, qstrs and full object pointers. + +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A + +static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 1) != 0); } +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) +#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) + +static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 3) == 2); } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2)) + +#if MICROPY_PY_BUILTINS_FLOAT +#define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) +#define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj) +extern const struct _mp_obj_float_t mp_const_float_e_obj; +extern const struct _mp_obj_float_t mp_const_float_pi_obj; + +#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +mp_float_t mp_obj_float_get(mp_obj_t self_in); +mp_obj_t mp_obj_new_float(mp_float_t value); +#endif + +static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 3) == 0); } + +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B + +static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 3) == 1); } +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2) +#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1)) + +static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 3) == 3); } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 3)) + +#if MICROPY_PY_BUILTINS_FLOAT +#define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) +#define mp_const_float_pi MP_ROM_PTR(&mp_const_float_pi_obj) +extern const struct _mp_obj_float_t mp_const_float_e_obj; +extern const struct _mp_obj_float_t mp_const_float_pi_obj; + +#define mp_obj_is_float(o) MP_OBJ_IS_TYPE((o), &mp_type_float) +mp_float_t mp_obj_float_get(mp_obj_t self_in); +mp_obj_t mp_obj_new_float(mp_float_t value); +#endif + +static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 1) == 0); } + +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + +static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 1) != 0); } +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1) +#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) + +#if MICROPY_PY_BUILTINS_FLOAT +#define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000)) +#define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000)) + +static inline bool mp_obj_is_float(mp_const_obj_t o) + { return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006; } +static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { + union { + mp_float_t f; + mp_uint_t u; + } num = {.u = ((mp_uint_t)o - 0x80800000) & ~3}; + return num.f; +} +static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + union { + mp_float_t f; + mp_uint_t u; + } num = {.f = f}; + return (mp_obj_t)(((num.u & ~0x3) | 2) + 0x80800000); +} +#endif + +static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) + { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; } +#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006)) + +static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) + { return ((((mp_int_t)(o)) & 3) == 0); } + +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + +static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) + { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17) +#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001) + +static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) + { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } +#define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff) +#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) + +#if MICROPY_PY_BUILTINS_FLOAT + +#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_DOUBLE +#error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE +#endif + +#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} +#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} + +static inline bool mp_obj_is_float(mp_const_obj_t o) { + return ((uint64_t)(o) & 0xfffc000000000000) != 0; +} +static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { + union { + mp_float_t f; + uint64_t r; + } num = {.r = o - 0x8004000000000000}; + return num.f; +} +static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + union { + mp_float_t f; + uint64_t r; + } num = {.f = f}; + return num.r + 0x8004000000000000; +} +#endif + +static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) + { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000); } +#define MP_OBJ_TO_PTR(o) ((void*)(uintptr_t)(o)) +#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p))) + +// rom object storage needs special handling to widen 32-bit pointer to 64-bits +typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; } mp_rom_obj_t; +#define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)} +#define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)} +#if MP_ENDIANNESS_LITTLE +#define MP_ROM_PTR(p) {.u32 = {.lo = (p), .hi = NULL}} +#else +#define MP_ROM_PTR(p) {.u32 = {.lo = NULL, .hi = (p)}} +#endif + +#endif + +// Macros to convert between mp_obj_t and concrete object types. +// These are identity operations in MicroPython, but ability to override +// these operations are provided to experiment with other methods of +// object representation and memory management. + +// Cast mp_obj_t to object pointer +#ifndef MP_OBJ_TO_PTR +#define MP_OBJ_TO_PTR(o) ((void*)o) +#endif + +// Cast object pointer to mp_obj_t +#ifndef MP_OBJ_FROM_PTR +#define MP_OBJ_FROM_PTR(p) ((mp_obj_t)p) +#endif + +// Macros to create objects that are stored in ROM. + +#ifndef MP_ROM_INT +typedef mp_const_obj_t mp_rom_obj_t; +#define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i) +#define MP_ROM_QSTR(q) MP_OBJ_NEW_QSTR(q) +#define MP_ROM_PTR(p) (p) +/* for testing +typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; +#define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)} +#define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)} +#define MP_ROM_PTR(p) {.o = p} +*/ +#endif + +// The macros below are derived from the ones above and are used to +// check for more specific object types. +// Note: these are kept as macros because inline functions sometimes use much +// more code space than the equivalent macros, depending on the compiler. + +#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that +#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) +#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)) +#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) +#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) + +// These macros are used to declare and define constant function objects +// You can put "static" in front of the definitions to make them local + +#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_var_t obj_name + +#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below +#define MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw) (((n_args_min) << 17) | ((n_args_max) << 1) | ((takes_kw) ? 1 : 0)) + +#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_0}, .fun._0 = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_1}, .fun._1 = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_2}, .fun._2 = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_3}, .fun._3 = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name} +#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name} + +// These macros are used to define constant map/dict objects +// You can put "static" in front of the definition to make it local + +#define MP_DEFINE_CONST_MAP(map_name, table_name) \ + const mp_map_t map_name = { \ + .all_keys_are_qstrs = 1, \ + .is_fixed = 1, \ + .is_ordered = 1, \ + .used = MP_ARRAY_SIZE(table_name), \ + .alloc = MP_ARRAY_SIZE(table_name), \ + .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \ + } + +#define MP_DEFINE_CONST_DICT(dict_name, table_name) \ + const mp_obj_dict_t dict_name = { \ + .base = {&mp_type_dict}, \ + .map = { \ + .all_keys_are_qstrs = 1, \ + .is_fixed = 1, \ + .is_ordered = 1, \ + .used = MP_ARRAY_SIZE(table_name), \ + .alloc = MP_ARRAY_SIZE(table_name), \ + .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \ + }, \ + } + +// These macros are used to declare and define constant staticmethond and classmethod objects +// You can put "static" in front of the definitions to make them local + +#define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name +#define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_rom_obj_static_class_method_t obj_name + +#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name} +#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name} + +// Underlying map/hash table implementation (not dict object or map function) + +typedef struct _mp_map_elem_t { + mp_obj_t key; + mp_obj_t value; +} mp_map_elem_t; + +typedef struct _mp_rom_map_elem_t { + mp_rom_obj_t key; + mp_rom_obj_t value; +} mp_rom_map_elem_t; + +// TODO maybe have a truncated mp_map_t for fixed tables, since alloc=used +// put alloc last in the structure, so the truncated version does not need it +// this would save 1 ROM word for all ROM objects that have a locals_dict +// would also need a trucated dict structure + +typedef struct _mp_map_t { + size_t all_keys_are_qstrs : 1; + size_t is_fixed : 1; // a fixed array that can't be modified; must also be ordered + size_t is_ordered : 1; // an ordered array + size_t used : (8 * sizeof(size_t) - 3); + size_t alloc; + mp_map_elem_t *table; +} mp_map_t; + +// mp_set_lookup requires these constants to have the values they do +typedef enum _mp_map_lookup_kind_t { + MP_MAP_LOOKUP = 0, + MP_MAP_LOOKUP_ADD_IF_NOT_FOUND = 1, + MP_MAP_LOOKUP_REMOVE_IF_FOUND = 2, + MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup +} mp_map_lookup_kind_t; + +extern const mp_map_t mp_const_empty_map; + +static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, size_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); } + +void mp_map_init(mp_map_t *map, size_t n); +void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table); +mp_map_t *mp_map_new(size_t n); +void mp_map_deinit(mp_map_t *map); +void mp_map_free(mp_map_t *map); +mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); +void mp_map_clear(mp_map_t *map); +void mp_map_dump(mp_map_t *map); + +// Underlying set implementation (not set object) + +typedef struct _mp_set_t { + size_t alloc; + size_t used; + mp_obj_t *table; +} mp_set_t; + +static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, size_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); } + +void mp_set_init(mp_set_t *set, size_t n); +mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); +mp_obj_t mp_set_remove_first(mp_set_t *set); +void mp_set_clear(mp_set_t *set); + +// Type definitions for methods + +typedef mp_obj_t (*mp_fun_0_t)(void); +typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t); +typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t); +typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t); +typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); +// mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing +// this arg to mp_map_lookup(). +typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); + +typedef enum { + PRINT_STR = 0, + PRINT_REPR = 1, + PRINT_EXC = 2, // Special format for printing exception in unhandled exception message + PRINT_JSON = 3, + PRINT_RAW = 4, // Special format for printing bytes as an undercorated string + PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses +} mp_print_kind_t; + +typedef struct _mp_obj_iter_buf_t { + mp_obj_base_t base; + mp_obj_t buf[3]; +} mp_obj_iter_buf_t; + +// The number of slots that an mp_obj_iter_buf_t needs on the Python value stack. +// It's rounded up in case mp_obj_base_t is smaller than mp_obj_t (eg for OBJ_REPR_D). +#define MP_OBJ_ITER_BUF_NSLOTS ((sizeof(mp_obj_iter_buf_t) + sizeof(mp_obj_t) - 1) / sizeof(mp_obj_t)) + +typedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind); +typedef mp_obj_t (*mp_make_new_fun_t)(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); +typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args); +typedef mp_obj_t (*mp_unary_op_fun_t)(mp_unary_op_t op, mp_obj_t); +typedef mp_obj_t (*mp_binary_op_fun_t)(mp_binary_op_t op, mp_obj_t, mp_obj_t); +typedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); +typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); +typedef mp_obj_t (*mp_getiter_fun_t)(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf); + +// Buffer protocol +typedef struct _mp_buffer_info_t { + // if we'd bother to support various versions of structure + // (with different number of fields), we can distinguish + // them with ver = sizeof(struct). Cons: overkill for *micro*? + //int ver; // ? + + void *buf; // can be NULL if len == 0 + size_t len; // in bytes + int typecode; // as per binary.h + + // Rationale: to load arbitrary-sized sprites directly to LCD + // Cons: a bit adhoc usecase + // int stride; +} mp_buffer_info_t; +#define MP_BUFFER_READ (1) +#define MP_BUFFER_WRITE (2) +#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE) +typedef struct _mp_buffer_p_t { + mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); +} mp_buffer_p_t; +bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); +void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); + +struct _mp_obj_type_t { + // A type is an object so must start with this entry, which points to mp_type_type. + mp_obj_base_t base; + + // Flags associated with this type. + uint16_t flags; + + // The name of this type, a qstr. + uint16_t name; + + // Corresponds to __repr__ and __str__ special methods. + mp_print_fun_t print; + + // Corresponds to __new__ and __init__ special methods, to make an instance of the type. + mp_make_new_fun_t make_new; + + // Corresponds to __call__ special method, ie T(...). + mp_call_fun_t call; + + // Implements unary and binary operations. + // Can return MP_OBJ_NULL if the operation is not supported. + mp_unary_op_fun_t unary_op; + mp_binary_op_fun_t binary_op; + + // Implements load, store and delete attribute. + // + // dest[0] = MP_OBJ_NULL means load + // return: for fail, do nothing + // for attr, dest[0] = value + // for method, dest[0] = method, dest[1] = self + // + // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete + // dest[0,1] = {MP_OBJ_SENTINEL, object} means store + // return: for fail, do nothing + // for success set dest[0] = MP_OBJ_NULL + mp_attr_fun_t attr; + + // Implements load, store and delete subscripting: + // - value = MP_OBJ_SENTINEL means load + // - value = MP_OBJ_NULL means delete + // - all other values mean store the value + // Can return MP_OBJ_NULL if operation not supported. + mp_subscr_fun_t subscr; + + // Corresponds to __iter__ special method. + // Can use the given mp_obj_iter_buf_t to store iterator object, + // otherwise can return a pointer to an object on the heap. + mp_getiter_fun_t getiter; + + // Corresponds to __next__ special method. May return MP_OBJ_STOP_ITERATION + // as an optimisation instead of raising StopIteration() with no args. + mp_fun_1_t iternext; + + // Implements the buffer protocol if supported by this type. + mp_buffer_p_t buffer_p; + + // One of disjoint protocols (interfaces), like mp_stream_p_t, etc. + const void *protocol; + + // A pointer to the parents of this type: + // - 0 parents: pointer is NULL (object is implicitly the single parent) + // - 1 parent: a pointer to the type of that parent + // - 2 or more parents: pointer to a tuple object containing the parent types + const void *parent; + + // A dict mapping qstrs to objects local methods/constants/etc. + struct _mp_obj_dict_t *locals_dict; +}; + +// Constant types, globally accessible +extern const mp_obj_type_t mp_type_type; +extern const mp_obj_type_t mp_type_object; +extern const mp_obj_type_t mp_type_NoneType; +extern const mp_obj_type_t mp_type_bool; +extern const mp_obj_type_t mp_type_int; +extern const mp_obj_type_t mp_type_str; +extern const mp_obj_type_t mp_type_bytes; +extern const mp_obj_type_t mp_type_bytearray; +extern const mp_obj_type_t mp_type_memoryview; +extern const mp_obj_type_t mp_type_float; +extern const mp_obj_type_t mp_type_complex; +extern const mp_obj_type_t mp_type_tuple; +extern const mp_obj_type_t mp_type_list; +extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail) +extern const mp_obj_type_t mp_type_enumerate; +extern const mp_obj_type_t mp_type_filter; +extern const mp_obj_type_t mp_type_deque; +extern const mp_obj_type_t mp_type_dict; +extern const mp_obj_type_t mp_type_ordereddict; +extern const mp_obj_type_t mp_type_range; +extern const mp_obj_type_t mp_type_set; +extern const mp_obj_type_t mp_type_frozenset; +extern const mp_obj_type_t mp_type_slice; +extern const mp_obj_type_t mp_type_zip; +extern const mp_obj_type_t mp_type_array; +extern const mp_obj_type_t mp_type_super; +extern const mp_obj_type_t mp_type_gen_wrap; +extern const mp_obj_type_t mp_type_native_gen_wrap; +extern const mp_obj_type_t mp_type_gen_instance; +extern const mp_obj_type_t mp_type_fun_builtin_0; +extern const mp_obj_type_t mp_type_fun_builtin_1; +extern const mp_obj_type_t mp_type_fun_builtin_2; +extern const mp_obj_type_t mp_type_fun_builtin_3; +extern const mp_obj_type_t mp_type_fun_builtin_var; +extern const mp_obj_type_t mp_type_fun_bc; +extern const mp_obj_type_t mp_type_module; +extern const mp_obj_type_t mp_type_staticmethod; +extern const mp_obj_type_t mp_type_classmethod; +extern const mp_obj_type_t mp_type_property; +extern const mp_obj_type_t mp_type_stringio; +extern const mp_obj_type_t mp_type_bytesio; +extern const mp_obj_type_t mp_type_reversed; +extern const mp_obj_type_t mp_type_polymorph_iter; + +// Exceptions +extern const mp_obj_type_t mp_type_BaseException; +extern const mp_obj_type_t mp_type_ArithmeticError; +extern const mp_obj_type_t mp_type_AssertionError; +extern const mp_obj_type_t mp_type_AttributeError; +extern const mp_obj_type_t mp_type_EOFError; +extern const mp_obj_type_t mp_type_Exception; +extern const mp_obj_type_t mp_type_GeneratorExit; +extern const mp_obj_type_t mp_type_ImportError; +extern const mp_obj_type_t mp_type_IndentationError; +extern const mp_obj_type_t mp_type_IndexError; +extern const mp_obj_type_t mp_type_KeyboardInterrupt; +extern const mp_obj_type_t mp_type_KeyError; +extern const mp_obj_type_t mp_type_LookupError; +extern const mp_obj_type_t mp_type_MemoryError; +extern const mp_obj_type_t mp_type_NameError; +extern const mp_obj_type_t mp_type_NotImplementedError; +extern const mp_obj_type_t mp_type_OSError; +extern const mp_obj_type_t mp_type_TimeoutError; +extern const mp_obj_type_t mp_type_OverflowError; +extern const mp_obj_type_t mp_type_RuntimeError; +extern const mp_obj_type_t mp_type_StopAsyncIteration; +extern const mp_obj_type_t mp_type_StopIteration; +extern const mp_obj_type_t mp_type_SyntaxError; +extern const mp_obj_type_t mp_type_SystemExit; +extern const mp_obj_type_t mp_type_TypeError; +extern const mp_obj_type_t mp_type_UnicodeError; +extern const mp_obj_type_t mp_type_ValueError; +extern const mp_obj_type_t mp_type_ViperTypeError; +extern const mp_obj_type_t mp_type_ZeroDivisionError; + +// Constant objects, globally accessible +// The macros are for convenience only +#define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj)) +#define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj)) +#define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj)) +#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj)) +#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj)) +#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj)) +extern const struct _mp_obj_none_t mp_const_none_obj; +extern const struct _mp_obj_bool_t mp_const_false_obj; +extern const struct _mp_obj_bool_t mp_const_true_obj; +extern const struct _mp_obj_str_t mp_const_empty_bytes_obj; +extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; +extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj; +extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj; +extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; + +// General API for objects + +mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); +static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; } +mp_obj_t mp_obj_new_cell(mp_obj_t obj); +mp_obj_t mp_obj_new_int(mp_int_t value); +mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); +mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) +mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) +mp_obj_t mp_obj_new_str(const char* data, size_t len); +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len); +mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); +mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); +mp_obj_t mp_obj_new_bytearray(size_t n, void *items); +mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items); +#if MICROPY_PY_BUILTINS_FLOAT +mp_obj_t mp_obj_new_int_from_float(mp_float_t val); +mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); +#endif +mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type); +mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); +mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args); +mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg); +mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) +mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); +mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); +mp_obj_t mp_obj_new_fun_viper(size_t n_args, void *fun_data, mp_uint_t type_sig); +mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig); +mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); +mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); +mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); +mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); +mp_obj_t mp_obj_new_dict(size_t n_args); +mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); +mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); +mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self); +mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf); +mp_obj_t mp_obj_new_module(qstr module_name); +mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items); + +mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); +const char *mp_obj_get_type_str(mp_const_obj_t o_in); +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects +mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type); + +void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); +void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); + +bool mp_obj_is_true(mp_obj_t arg); +bool mp_obj_is_callable(mp_obj_t o_in); +bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); + +static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int +mp_int_t mp_obj_get_int(mp_const_obj_t arg); +mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); +bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mp_obj_get_float(mp_obj_t self_in); +bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value); +void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); +#endif +//qstr mp_obj_get_qstr(mp_obj_t arg); +void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block +void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block +size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); +mp_obj_t mp_obj_id(mp_obj_t o_in); +mp_obj_t mp_obj_len(mp_obj_t o_in); +mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); // may return MP_OBJ_NULL +mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val); +mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in); + +// cell +mp_obj_t mp_obj_cell_get(mp_obj_t self_in); +void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj); + +// int +// For long int, returns value truncated to mp_int_t +mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in); +// Will raise exception if value doesn't fit into mp_int_t +mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in); + +// exception +#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new) +bool mp_obj_is_exception_type(mp_obj_t self_in); +bool mp_obj_is_exception_instance(mp_obj_t self_in); +bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type); +void mp_obj_exception_clear_traceback(mp_obj_t self_in); +void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block); +void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values); +mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in); +mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in); +void mp_init_emergency_exception_buf(void); + +// str +bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2); +qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr +const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); +mp_obj_t mp_obj_str_intern(mp_obj_t str); +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj); +void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); + +#if MICROPY_PY_BUILTINS_FLOAT +// float +#if MICROPY_FLOAT_HIGH_QUALITY_HASH +mp_int_t mp_float_hash(mp_float_t val); +#else +static inline mp_int_t mp_float_hash(mp_float_t val) { return (mp_int_t)val; } +#endif +mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported + +// complex +void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); +mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported +#else +#define mp_obj_is_float(o) (false) +#endif + +// tuple +void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); +void mp_obj_tuple_del(mp_obj_t self_in); +mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); + +// list +mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); +mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); +void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); +void mp_obj_list_set_len(mp_obj_t self_in, size_t len); +void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); +mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); + +// dict +typedef struct _mp_obj_dict_t { + mp_obj_base_t base; + mp_map_t map; +} mp_obj_dict_t; +void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args); +size_t mp_obj_dict_len(mp_obj_t self_in); +mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index); +mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); +mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key); +static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) { + return &((mp_obj_dict_t*)MP_OBJ_TO_PTR(dict))->map; +} + +// set +void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); + +// slice +void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); + +// functions + +typedef struct _mp_obj_fun_builtin_fixed_t { + mp_obj_base_t base; + union { + mp_fun_0_t _0; + mp_fun_1_t _1; + mp_fun_2_t _2; + mp_fun_3_t _3; + } fun; +} mp_obj_fun_builtin_fixed_t; + +typedef struct _mp_obj_fun_builtin_var_t { + mp_obj_base_t base; + uint32_t sig; // see MP_OBJ_FUN_MAKE_SIG + union { + mp_fun_var_t var; + mp_fun_kw_t kw; + } fun; +} mp_obj_fun_builtin_var_t; + +qstr mp_obj_fun_get_name(mp_const_obj_t fun); +qstr mp_obj_code_get_name(const byte *code_info); + +mp_obj_t mp_identity(mp_obj_t self); +MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); +mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf); + +// module +typedef struct _mp_obj_module_t { + mp_obj_base_t base; + mp_obj_dict_t *globals; +} mp_obj_module_t; +static inline mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t module) { + return ((mp_obj_module_t*)MP_OBJ_TO_PTR(module))->globals; +} +// check if given module object is a package +bool mp_obj_is_package(mp_obj_t module); + +// staticmethod and classmethod types; defined here so we can make const versions +// this structure is used for instances of both staticmethod and classmethod +typedef struct _mp_obj_static_class_method_t { + mp_obj_base_t base; + mp_obj_t fun; +} mp_obj_static_class_method_t; +typedef struct _mp_rom_obj_static_class_method_t { + mp_obj_base_t base; + mp_rom_obj_t fun; +} mp_rom_obj_static_class_method_t; + +// property +const mp_obj_t *mp_obj_property_get(mp_obj_t self_in); + +// sequence helpers + +// slice indexes resolved to particular sequence +typedef struct { + mp_uint_t start; + mp_uint_t stop; + mp_int_t step; +} mp_bound_slice_t; + +void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); +#if MICROPY_PY_BUILTINS_SLICE +bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); +#endif +#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t)) +#define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); } +bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2); +bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2); +mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args); +mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value); +mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes); +// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems +#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz)) +#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \ + /*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * (item_sz));*/ \ + memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \ + /*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \ + memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz)); + +// Note: dest and slice regions may overlap +#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \ + /*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \ + memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \ + memmove(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); + +#endif // MICROPY_INCLUDED_PY_OBJ_H diff --git a/src/openmv/src/micropython/py/objarray.c b/src/openmv/src/micropython/py/objarray.c new file mode 100755 index 0000000..bdef341 --- /dev/null +++ b/src/openmv/src/micropython/py/objarray.c @@ -0,0 +1,633 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/objstr.h" +#include "py/objarray.h" + +#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW + +// About memoryview object: We want to reuse as much code as possible from +// array, and keep the memoryview object 4 words in size so it fits in 1 GC +// block. Also, memoryview must keep a pointer to the base of the buffer so +// that the buffer is not GC'd if the original parent object is no longer +// around (we are assuming that all memoryview'able objects return a pointer +// which points to the start of a GC chunk). Given the above constraints we +// do the following: +// - typecode high bit is set if the buffer is read-write (else read-only) +// - free is the offset in elements to the first item in the memoryview +// - len is the length in elements +// - items points to the start of the original buffer +// Note that we don't handle the case where the original buffer might change +// size due to a resize of the original parent object. + +// make (& TYPECODE_MASK) a null operation if memorview not enabled +#if MICROPY_PY_BUILTINS_MEMORYVIEW +#define TYPECODE_MASK (0x7f) +#else +#define TYPECODE_MASK (~(size_t)0) +#endif + +STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf); +STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg); +STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in); +STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); + +/******************************************************************************/ +// array + +#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); + if (o->typecode == BYTEARRAY_TYPECODE) { + mp_print_str(print, "bytearray(b"); + mp_str_print_quoted(print, o->items, o->len, true); + } else { + mp_printf(print, "array('%c'", o->typecode); + if (o->len > 0) { + mp_print_str(print, ", ["); + for (size_t i = 0; i < o->len; i++) { + if (i > 0) { + mp_print_str(print, ", "); + } + mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR); + } + mp_print_str(print, "]"); + } + } + mp_print_str(print, ")"); +} +#endif + +#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +STATIC mp_obj_array_t *array_new(char typecode, size_t n) { + int typecode_size = mp_binary_get_size('@', typecode, NULL); + mp_obj_array_t *o = m_new_obj(mp_obj_array_t); + #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY + o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array; + #elif MICROPY_PY_BUILTINS_BYTEARRAY + o->base.type = &mp_type_bytearray; + #else + o->base.type = &mp_type_array; + #endif + o->typecode = typecode; + o->free = 0; + o->len = n; + o->items = m_new(byte, typecode_size * o->len); + return o; +} +#endif + +#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { + // bytearrays can be raw-initialised from anything with the buffer protocol + // other arrays can only be raw-initialised from bytes and bytearray objects + mp_buffer_info_t bufinfo; + if (((MICROPY_PY_BUILTINS_BYTEARRAY + && typecode == BYTEARRAY_TYPECODE) + || (MICROPY_PY_ARRAY + && (MP_OBJ_IS_TYPE(initializer, &mp_type_bytes) + || (MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(initializer, &mp_type_bytearray))))) + && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) { + // construct array from raw bytes + // we round-down the len to make it a multiple of sz (CPython raises error) + size_t sz = mp_binary_get_size('@', typecode, NULL); + size_t len = bufinfo.len / sz; + mp_obj_array_t *o = array_new(typecode, len); + memcpy(o->items, bufinfo.buf, len * sz); + return MP_OBJ_FROM_PTR(o); + } + + size_t len; + // Try to create array of exact len if initializer len is known + mp_obj_t len_in = mp_obj_len_maybe(initializer); + if (len_in == MP_OBJ_NULL) { + len = 0; + } else { + len = MP_OBJ_SMALL_INT_VALUE(len_in); + } + + mp_obj_array_t *array = array_new(typecode, len); + + mp_obj_t iterable = mp_getiter(initializer, NULL); + mp_obj_t item; + size_t i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (len == 0) { + array_append(MP_OBJ_FROM_PTR(array), item); + } else { + mp_binary_set_val_array(typecode, array->items, i++, item); + } + } + + return MP_OBJ_FROM_PTR(array); +} +#endif + +#if MICROPY_PY_ARRAY +STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 1, 2, false); + + // get typecode + const char *typecode = mp_obj_str_get_str(args[0]); + + if (n_args == 1) { + // 1 arg: make an empty array + return MP_OBJ_FROM_PTR(array_new(*typecode, 0)); + } else { + // 2 args: construct the array from the given object + return array_construct(*typecode, args[1]); + } +} +#endif + +#if MICROPY_PY_BUILTINS_BYTEARRAY +STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + // Can take 2nd/3rd arg if constructs from str + mp_arg_check_num(n_args, n_kw, 0, 3, false); + + if (n_args == 0) { + // no args: construct an empty bytearray + return MP_OBJ_FROM_PTR(array_new(BYTEARRAY_TYPECODE, 0)); + } else if (MP_OBJ_IS_INT(args[0])) { + // 1 arg, an integer: construct a blank bytearray of that length + mp_uint_t len = mp_obj_get_int(args[0]); + mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); + memset(o->items, 0, len); + return MP_OBJ_FROM_PTR(o); + } else { + // 1 arg: construct the bytearray from that + return array_construct(BYTEARRAY_TYPECODE, args[0]); + } +} +#endif + +#if MICROPY_PY_BUILTINS_MEMORYVIEW + +mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) { + mp_obj_array_t *self = m_new_obj(mp_obj_array_t); + self->base.type = &mp_type_memoryview; + self->typecode = typecode; + self->free = 0; + self->len = nitems; + self->items = items; + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + + // TODO possibly allow memoryview constructor to take start/stop so that one + // can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM) + + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + + mp_obj_array_t *self = MP_OBJ_TO_PTR(mp_obj_new_memoryview(bufinfo.typecode, + bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL), + bufinfo.buf)); + + // test if the object can be written to + if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { + self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer + } + + return MP_OBJ_FROM_PTR(self); +} +#endif + +STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len); + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in); + switch (op) { + case MP_BINARY_OP_ADD: { + // allow to add anything that has the buffer protocol (extension to CPython) + mp_buffer_info_t lhs_bufinfo; + mp_buffer_info_t rhs_bufinfo; + array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(rhs_in, &rhs_bufinfo, MP_BUFFER_READ); + + size_t sz = mp_binary_get_size('@', lhs_bufinfo.typecode, NULL); + + // convert byte count to element count (in case rhs is not multiple of sz) + size_t rhs_len = rhs_bufinfo.len / sz; + + // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count + mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len); + mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte); + return MP_OBJ_FROM_PTR(res); + } + + case MP_BINARY_OP_INPLACE_ADD: { + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (lhs->base.type == &mp_type_memoryview) { + return MP_OBJ_NULL; // op not supported + } + #endif + array_extend(lhs_in, rhs_in); + return lhs_in; + } + + case MP_BINARY_OP_CONTAINS: { + #if MICROPY_PY_BUILTINS_BYTEARRAY + // Can search string only in bytearray + mp_buffer_info_t lhs_bufinfo; + mp_buffer_info_t rhs_bufinfo; + if (mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { + if (!MP_OBJ_IS_TYPE(lhs_in, &mp_type_bytearray)) { + return mp_const_false; + } + array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); + return mp_obj_new_bool( + find_subbytes(lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len, 1) != NULL); + } + #endif + + // Otherwise, can only look for a scalar numeric value in an array + if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) { + mp_raise_NotImplementedError(NULL); + } + + return mp_const_false; + } + + case MP_BINARY_OP_EQUAL: { + mp_buffer_info_t lhs_bufinfo; + mp_buffer_info_t rhs_bufinfo; + array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); + if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { + return mp_const_false; + } + return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len)); + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { + // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) + assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->free == 0) { + size_t item_sz = mp_binary_get_size('@', self->typecode, NULL); + // TODO: alloc policy + self->free = 8; + self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free)); + mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz); + } + mp_binary_set_val_array(self->typecode, self->items, self->len, arg); + // only update length/free if set succeeded + self->len++; + self->free--; + return mp_const_none; // return None, as per CPython +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append); + +STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { + // self is not a memoryview, so we don't need to use (& TYPECODE_MASK) + assert((MICROPY_PY_BUILTINS_BYTEARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)) + || (MICROPY_PY_ARRAY && MP_OBJ_IS_TYPE(self_in, &mp_type_array))); + mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); + + // allow to extend by anything that has the buffer protocol (extension to CPython) + mp_buffer_info_t arg_bufinfo; + mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ); + + size_t sz = mp_binary_get_size('@', self->typecode, NULL); + + // convert byte count to element count + size_t len = arg_bufinfo.len / sz; + + // make sure we have enough room to extend + // TODO: alloc policy; at the moment we go conservative + if (self->free < len) { + self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); + self->free = 0; + } else { + self->free -= len; + } + + // extend + mp_seq_copy((byte*)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); + self->len += len; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_extend_obj, array_extend); +#endif + +STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete item + // TODO implement + // TODO: confirmed that both bytearray and array.array support + // slice deletion + return MP_OBJ_NULL; // op not supported + } else { + mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in); + if (0) { +#if MICROPY_PY_BUILTINS_SLICE + } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) { + mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + } + if (value != MP_OBJ_SENTINEL) { + #if MICROPY_PY_ARRAY_SLICE_ASSIGN + // Assign + size_t src_len; + void *src_items; + size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); + if (MP_OBJ_IS_OBJ(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) { + // value is array, bytearray or memoryview + mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); + if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { + compat_error: + mp_raise_ValueError("lhs and rhs should be compatible"); + } + src_len = src_slice->len; + src_items = src_slice->items; + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (MP_OBJ_IS_TYPE(value, &mp_type_memoryview)) { + src_items = (uint8_t*)src_items + (src_slice->free * item_sz); + } + #endif + } else if (MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + if (item_sz != 1) { + goto compat_error; + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); + src_len = bufinfo.len; + src_items = bufinfo.buf; + } else { + mp_raise_NotImplementedError("array/bytes required on right side"); + } + + // TODO: check src/dst compat + mp_int_t len_adj = src_len - (slice.stop - slice.start); + uint8_t* dest_items = o->items; + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (o->base.type == &mp_type_memoryview) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { + // store to read-only memoryview not allowed + return MP_OBJ_NULL; + } + if (len_adj != 0) { + goto compat_error; + } + dest_items += o->free * item_sz; + } + #endif + if (len_adj > 0) { + if (len_adj > o->free) { + // TODO: alloc policy; at the moment we go conservative + o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz); + o->free = 0; + dest_items = o->items; + } + mp_seq_replace_slice_grow_inplace(dest_items, o->len, + slice.start, slice.stop, src_items, src_len, len_adj, item_sz); + } else { + mp_seq_replace_slice_no_grow(dest_items, o->len, + slice.start, slice.stop, src_items, src_len, item_sz); + // Clear "freed" elements at the end of list + // TODO: This is actually only needed for typecode=='O' + mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); + // TODO: alloc policy after shrinking + } + o->len += len_adj; + return mp_const_none; + #else + return MP_OBJ_NULL; // op not supported + #endif + } + + mp_obj_array_t *res; + size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); + assert(sz > 0); + if (0) { + // dummy + #if MICROPY_PY_BUILTINS_MEMORYVIEW + } else if (o->base.type == &mp_type_memoryview) { + res = m_new_obj(mp_obj_array_t); + *res = *o; + res->free += slice.start; + res->len = slice.stop - slice.start; + #endif + } else { + res = array_new(o->typecode, slice.stop - slice.start); + memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz); + } + return MP_OBJ_FROM_PTR(res); +#endif + } else { + size_t index = mp_get_index(o->base.type, o->len, index_in, false); + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (o->base.type == &mp_type_memoryview) { + index += o->free; + if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { + // store to read-only memoryview + return MP_OBJ_NULL; + } + } + #endif + if (value == MP_OBJ_SENTINEL) { + // load + return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index); + } else { + // store + mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value); + return mp_const_none; + } + } + } +} + +STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); + size_t sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL); + bufinfo->buf = o->items; + bufinfo->len = o->len * sz; + bufinfo->typecode = o->typecode & TYPECODE_MASK; + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (o->base.type == &mp_type_memoryview) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) { + // read-only memoryview + return 1; + } + bufinfo->buf = (uint8_t*)bufinfo->buf + (size_t)o->free * sz; + } + #else + (void)flags; + #endif + return 0; +} + +#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +STATIC const mp_rom_map_elem_t array_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&array_append_obj) }, + { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&array_extend_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table); +#endif + +#if MICROPY_PY_ARRAY +const mp_obj_type_t mp_type_array = { + { &mp_type_type }, + .name = MP_QSTR_array, + .print = array_print, + .make_new = array_make_new, + .getiter = array_iterator_new, + .unary_op = array_unary_op, + .binary_op = array_binary_op, + .subscr = array_subscr, + .buffer_p = { .get_buffer = array_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&array_locals_dict, +}; +#endif + +#if MICROPY_PY_BUILTINS_BYTEARRAY +const mp_obj_type_t mp_type_bytearray = { + { &mp_type_type }, + .name = MP_QSTR_bytearray, + .print = array_print, + .make_new = bytearray_make_new, + .getiter = array_iterator_new, + .unary_op = array_unary_op, + .binary_op = array_binary_op, + .subscr = array_subscr, + .buffer_p = { .get_buffer = array_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&array_locals_dict, +}; +#endif + +#if MICROPY_PY_BUILTINS_MEMORYVIEW +const mp_obj_type_t mp_type_memoryview = { + { &mp_type_type }, + .name = MP_QSTR_memoryview, + .make_new = memoryview_make_new, + .getiter = array_iterator_new, + .unary_op = array_unary_op, + .binary_op = array_binary_op, + .subscr = array_subscr, + .buffer_p = { .get_buffer = array_get_buffer }, +}; +#endif + +/* unused +size_t mp_obj_array_len(mp_obj_t self_in) { + return ((mp_obj_array_t *)self_in)->len; +} +*/ + +#if MICROPY_PY_BUILTINS_BYTEARRAY +mp_obj_t mp_obj_new_bytearray(size_t n, void *items) { + mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n); + memcpy(o->items, items, n); + return MP_OBJ_FROM_PTR(o); +} + +// Create bytearray which references specified memory area +mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items) { + mp_obj_array_t *o = m_new_obj(mp_obj_array_t); + o->base.type = &mp_type_bytearray; + o->typecode = BYTEARRAY_TYPECODE; + o->free = 0; + o->len = n; + o->items = items; + return MP_OBJ_FROM_PTR(o); +} +#endif + +/******************************************************************************/ +// array iterator + +typedef struct _mp_obj_array_it_t { + mp_obj_base_t base; + mp_obj_array_t *array; + size_t offset; + size_t cur; +} mp_obj_array_it_t; + +STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) { + mp_obj_array_it_t *self = MP_OBJ_TO_PTR(self_in); + if (self->cur < self->array->len) { + return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++); + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC const mp_obj_type_t array_it_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity_getiter, + .iternext = array_it_iternext, +}; + +STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in); + mp_obj_array_it_t *o = (mp_obj_array_it_t*)iter_buf; + o->base.type = &array_it_type; + o->array = array; + o->offset = 0; + o->cur = 0; + #if MICROPY_PY_BUILTINS_MEMORYVIEW + if (array->base.type == &mp_type_memoryview) { + o->offset = array->free; + } + #endif + return MP_OBJ_FROM_PTR(o); +} + +#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW diff --git a/src/openmv/src/micropython/py/objarray.h b/src/openmv/src/micropython/py/objarray.h new file mode 100755 index 0000000..0dad705 --- /dev/null +++ b/src/openmv/src/micropython/py/objarray.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJARRAY_H +#define MICROPY_INCLUDED_PY_OBJARRAY_H + +#include "py/obj.h" + +// Used only for memoryview types, set in "typecode" to indicate a writable memoryview +#define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80) + +typedef struct _mp_obj_array_t { + mp_obj_base_t base; + size_t typecode : 8; + // free is number of unused elements after len used elements + // alloc size = len + free + size_t free : (8 * sizeof(size_t) - 8); + size_t len; // in elements + void *items; +} mp_obj_array_t; + +#endif // MICROPY_INCLUDED_PY_OBJARRAY_H diff --git a/src/openmv/src/micropython/py/objattrtuple.c b/src/openmv/src/micropython/py/objattrtuple.c new file mode 100755 index 0000000..3cc298d --- /dev/null +++ b/src/openmv/src/micropython/py/objattrtuple.c @@ -0,0 +1,95 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objtuple.h" + +#if MICROPY_PY_ATTRTUPLE || MICROPY_PY_COLLECTIONS + +// this helper function is used by collections.namedtuple +#if !MICROPY_PY_COLLECTIONS +STATIC +#endif +void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o) { + mp_print_str(print, "("); + for (size_t i = 0; i < o->len; i++) { + if (i > 0) { + mp_print_str(print, ", "); + } + mp_printf(print, "%q=", fields[i]); + mp_obj_print_helper(print, o->items[i], PRINT_REPR); + } + mp_print_str(print, ")"); +} + +#endif + +#if MICROPY_PY_ATTRTUPLE + +STATIC void mp_obj_attrtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in); + const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(o->items[o->len]); + mp_obj_attrtuple_print_helper(print, fields, o); +} + +STATIC void mp_obj_attrtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + size_t len = self->len; + const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(self->items[len]); + for (size_t i = 0; i < len; i++) { + if (fields[i] == attr) { + dest[0] = self->items[i]; + return; + } + } + } +} + +mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items) { + mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n + 1); + o->base.type = &mp_type_attrtuple; + o->len = n; + for (size_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + o->items[n] = MP_OBJ_FROM_PTR(fields); + return MP_OBJ_FROM_PTR(o); +} + +const mp_obj_type_t mp_type_attrtuple = { + { &mp_type_type }, + .name = MP_QSTR_tuple, // reuse tuple to save on a qstr + .print = mp_obj_attrtuple_print, + .unary_op = mp_obj_tuple_unary_op, + .binary_op = mp_obj_tuple_binary_op, + .attr = mp_obj_attrtuple_attr, + .subscr = mp_obj_tuple_subscr, + .getiter = mp_obj_tuple_getiter, +}; + +#endif // MICROPY_PY_ATTRTUPLE diff --git a/src/openmv/src/micropython/py/objbool.c b/src/openmv/src/micropython/py/objbool.c new file mode 100755 index 0000000..5755b18 --- /dev/null +++ b/src/openmv/src/micropython/py/objbool.c @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +typedef struct _mp_obj_bool_t { + mp_obj_base_t base; + bool value; +} mp_obj_bool_t; + +STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_bool_t *self = MP_OBJ_TO_PTR(self_in); + if (MICROPY_PY_UJSON && kind == PRINT_JSON) { + if (self->value) { + mp_print_str(print, "true"); + } else { + mp_print_str(print, "false"); + } + } else { + if (self->value) { + mp_print_str(print, "True"); + } else { + mp_print_str(print, "False"); + } + } +} + +STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + if (n_args == 0) { + return mp_const_false; + } else { + return mp_obj_new_bool(mp_obj_is_true(args[0])); + } +} + +STATIC mp_obj_t bool_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + if (op == MP_UNARY_OP_LEN) { + return MP_OBJ_NULL; + } + mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in); + return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value)); +} + +STATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in); + return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in); +} + +const mp_obj_type_t mp_type_bool = { + { &mp_type_type }, + .name = MP_QSTR_bool, + .print = bool_print, + .make_new = bool_make_new, + .unary_op = bool_unary_op, + .binary_op = bool_binary_op, +}; + +const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false}; +const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true}; diff --git a/src/openmv/src/micropython/py/objboundmeth.c b/src/openmv/src/micropython/py/objboundmeth.c new file mode 100755 index 0000000..b0df6a6 --- /dev/null +++ b/src/openmv/src/micropython/py/objboundmeth.c @@ -0,0 +1,117 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +typedef struct _mp_obj_bound_meth_t { + mp_obj_base_t base; + mp_obj_t meth; + mp_obj_t self; +} mp_obj_bound_meth_t; + +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED +STATIC void bound_meth_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(o_in); + mp_printf(print, "self, PRINT_REPR); + mp_print_str(print, "."); + mp_obj_print_helper(print, o->meth, PRINT_REPR); + mp_print_str(print, ">"); +} +#endif + +mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // need to insert self before all other args and then call meth + size_t n_total = n_args + 2 * n_kw; + mp_obj_t *args2 = NULL; + #if MICROPY_ENABLE_PYSTACK + args2 = mp_pystack_alloc(sizeof(mp_obj_t) * (1 + n_total)); + #else + mp_obj_t *free_args2 = NULL; + if (n_total > 4) { + // try to use heap to allocate temporary args array + args2 = m_new_maybe(mp_obj_t, 1 + n_total); + free_args2 = args2; + } + if (args2 == NULL) { + // (fallback to) use stack to allocate temporary args array + args2 = alloca(sizeof(mp_obj_t) * (1 + n_total)); + } + #endif + args2[0] = self; + memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t)); + mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2); + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(args2); + #else + if (free_args2 != NULL) { + m_del(mp_obj_t, free_args2, 1 + n_total); + } + #endif + return res; +} + +STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_bound_meth_t *self = MP_OBJ_TO_PTR(self_in); + return mp_call_method_self_n_kw(self->meth, self->self, n_args, n_kw, args); +} + +#if MICROPY_PY_FUNCTION_ATTRS +STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + if (attr == MP_QSTR___name__) { + mp_obj_bound_meth_t *o = MP_OBJ_TO_PTR(self_in); + dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth)); + } +} +#endif + +STATIC const mp_obj_type_t mp_type_bound_meth = { + { &mp_type_type }, + .name = MP_QSTR_bound_method, +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + .print = bound_meth_print, +#endif + .call = bound_meth_call, +#if MICROPY_PY_FUNCTION_ATTRS + .attr = bound_meth_attr, +#endif +}; + +mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self) { + mp_obj_bound_meth_t *o = m_new_obj(mp_obj_bound_meth_t); + o->base.type = &mp_type_bound_meth; + o->meth = meth; + o->self = self; + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objcell.c b/src/openmv/src/micropython/py/objcell.c new file mode 100755 index 0000000..1119064 --- /dev/null +++ b/src/openmv/src/micropython/py/objcell.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +typedef struct _mp_obj_cell_t { + mp_obj_base_t base; + mp_obj_t obj; +} mp_obj_cell_t; + +mp_obj_t mp_obj_cell_get(mp_obj_t self_in) { + mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in); + return self->obj; +} + +void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) { + mp_obj_cell_t *self = MP_OBJ_TO_PTR(self_in); + self->obj = obj; +} + +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED +STATIC void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_cell_t *o = MP_OBJ_TO_PTR(o_in); + mp_printf(print, "obj); + if (o->obj == MP_OBJ_NULL) { + mp_print_str(print, "(nil)"); + } else { + mp_obj_print_helper(print, o->obj, PRINT_REPR); + } + mp_print_str(print, ">"); +} +#endif + +STATIC const mp_obj_type_t mp_type_cell = { + { &mp_type_type }, + .name = MP_QSTR_, // cell representation is just value in < > +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + .print = cell_print, +#endif +}; + +mp_obj_t mp_obj_new_cell(mp_obj_t obj) { + mp_obj_cell_t *o = m_new_obj(mp_obj_cell_t); + o->base.type = &mp_type_cell; + o->obj = obj; + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objclosure.c b/src/openmv/src/micropython/py/objclosure.c new file mode 100755 index 0000000..4eb9eb8 --- /dev/null +++ b/src/openmv/src/micropython/py/objclosure.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +typedef struct _mp_obj_closure_t { + mp_obj_base_t base; + mp_obj_t fun; + size_t n_closed; + mp_obj_t closed[]; +} mp_obj_closure_t; + +STATIC mp_obj_t closure_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_closure_t *self = MP_OBJ_TO_PTR(self_in); + + // need to concatenate closed-over-vars and args + + size_t n_total = self->n_closed + n_args + 2 * n_kw; + if (n_total <= 5) { + // use stack to allocate temporary args array + mp_obj_t args2[5]; + memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t)); + memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); + return mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2); + } else { + // use heap to allocate temporary args array + mp_obj_t *args2 = m_new(mp_obj_t, n_total); + memcpy(args2, self->closed, self->n_closed * sizeof(mp_obj_t)); + memcpy(args2 + self->n_closed, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); + mp_obj_t res = mp_call_function_n_kw(self->fun, self->n_closed + n_args, n_kw, args2); + m_del(mp_obj_t, args2, n_total); + return res; + } +} + +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED +STATIC void closure_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_closure_t *o = MP_OBJ_TO_PTR(o_in); + mp_print_str(print, "fun, PRINT_REPR); + mp_printf(print, " at %p, n_closed=%u ", o, (int)o->n_closed); + for (size_t i = 0; i < o->n_closed; i++) { + if (o->closed[i] == MP_OBJ_NULL) { + mp_print_str(print, "(nil)"); + } else { + mp_obj_print_helper(print, o->closed[i], PRINT_REPR); + } + mp_print_str(print, " "); + } + mp_print_str(print, ">"); +} +#endif + +const mp_obj_type_t closure_type = { + { &mp_type_type }, + .name = MP_QSTR_closure, +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + .print = closure_print, +#endif + .call = closure_call, +}; + +mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed_over, const mp_obj_t *closed) { + mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over); + o->base.type = &closure_type; + o->fun = fun; + o->n_closed = n_closed_over; + memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t)); + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objcomplex.c b/src/openmv/src/micropython/py/objcomplex.c new file mode 100755 index 0000000..42b396d --- /dev/null +++ b/src/openmv/src/micropython/py/objcomplex.c @@ -0,0 +1,254 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/parsenum.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_COMPLEX + +#include +#include "py/formatfloat.h" + +typedef struct _mp_obj_complex_t { + mp_obj_base_t base; + mp_float_t real; + mp_float_t imag; +} mp_obj_complex_t; + +STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + char buf[16]; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + const int precision = 6; + #else + const int precision = 7; + #endif +#else + char buf[32]; + const int precision = 16; +#endif + if (o->real == 0) { + mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); + mp_printf(print, "%sj", buf); + } else { + mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0'); + mp_printf(print, "(%s", buf); + if (o->imag >= 0 || isnan(o->imag)) { + mp_print_str(print, "+"); + } + mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); + mp_printf(print, "%sj)", buf); + } +} + +STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 2, false); + + switch (n_args) { + case 0: + return mp_obj_new_complex(0, 0); + + case 1: + if (MP_OBJ_IS_STR(args[0])) { + // a string, parse it + size_t l; + const char *s = mp_obj_str_get_data(args[0], &l); + return mp_parse_num_decimal(s, l, true, true, NULL); + } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + // a complex, just return it + return args[0]; + } else { + // something else, try to cast it to a complex + return mp_obj_new_complex(mp_obj_get_float(args[0]), 0); + } + + case 2: + default: { + mp_float_t real, imag; + if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { + mp_obj_complex_get(args[0], &real, &imag); + } else { + real = mp_obj_get_float(args[0]); + imag = 0; + } + if (MP_OBJ_IS_TYPE(args[1], &mp_type_complex)) { + mp_float_t real2, imag2; + mp_obj_complex_get(args[1], &real2, &imag2); + real -= imag2; + imag += real2; + } else { + imag += mp_obj_get_float(args[1]); + } + return mp_obj_new_complex(real, imag); + } + } +} + +STATIC mp_obj_t complex_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->real != 0 || o->imag != 0); + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag)); + case MP_UNARY_OP_POSITIVE: return o_in; + case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag); + case MP_UNARY_OP_ABS: + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(o->real*o->real + o->imag*o->imag)); + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t complex_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_complex_t *lhs = MP_OBJ_TO_PTR(lhs_in); + return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in); +} + +STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); + if (attr == MP_QSTR_real) { + dest[0] = mp_obj_new_float(self->real); + } else if (attr == MP_QSTR_imag) { + dest[0] = mp_obj_new_float(self->imag); + } +} + +const mp_obj_type_t mp_type_complex = { + { &mp_type_type }, + .name = MP_QSTR_complex, + .print = complex_print, + .make_new = complex_make_new, + .unary_op = complex_unary_op, + .binary_op = complex_binary_op, + .attr = complex_attr, +}; + +mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) { + mp_obj_complex_t *o = m_new_obj(mp_obj_complex_t); + o->base.type = &mp_type_complex; + o->real = real; + o->imag = imag; + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_complex)); + mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in); + *real = self->real; + *imag = self->imag; +} + +mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) { + mp_float_t rhs_real, rhs_imag; + mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible) + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: + lhs_real += rhs_real; + lhs_imag += rhs_imag; + break; + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: + lhs_real -= rhs_real; + lhs_imag -= rhs_imag; + break; + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: { + mp_float_t real; + multiply: + real = lhs_real * rhs_real - lhs_imag * rhs_imag; + lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real; + lhs_real = real; + break; + } + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + mp_raise_TypeError("can't truncate-divide a complex number"); + + case MP_BINARY_OP_TRUE_DIVIDE: + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + if (rhs_imag == 0) { + if (rhs_real == 0) { + mp_raise_msg(&mp_type_ZeroDivisionError, "complex divide by zero"); + } + lhs_real /= rhs_real; + lhs_imag /= rhs_real; + } else if (rhs_real == 0) { + mp_float_t real = lhs_imag / rhs_imag; + lhs_imag = -lhs_real / rhs_imag; + lhs_real = real; + } else { + mp_float_t rhs_len_sq = rhs_real*rhs_real + rhs_imag*rhs_imag; + rhs_real /= rhs_len_sq; + rhs_imag /= -rhs_len_sq; + goto multiply; + } + break; + + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: { + // z1**z2 = exp(z2*ln(z1)) + // = exp(z2*(ln(|z1|)+i*arg(z1))) + // = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) ) + // = exp(x3 + i*y3) + // = exp(x3)*(cos(y3) + i*sin(y3)) + mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real*lhs_real + lhs_imag*lhs_imag); + if (abs1 == 0) { + if (rhs_imag == 0 && rhs_real >= 0) { + lhs_real = (rhs_real == 0); + } else { + mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"); + } + } else { + mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); + mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real); + mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1; + mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1; + mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3); + lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3); + lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3); + } + break; + } + + case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag); + + default: + return MP_OBJ_NULL; // op not supported + } + return mp_obj_new_complex(lhs_real, lhs_imag); +} + +#endif diff --git a/src/openmv/src/micropython/py/objdeque.c b/src/openmv/src/micropython/py/objdeque.c new file mode 100755 index 0000000..1cff1f8 --- /dev/null +++ b/src/openmv/src/micropython/py/objdeque.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include // for ssize_t +#include + +#include "py/mpconfig.h" +#if MICROPY_PY_COLLECTIONS_DEQUE + +#include "py/runtime.h" + +typedef struct _mp_obj_deque_t { + mp_obj_base_t base; + size_t alloc; + size_t i_get; + size_t i_put; + mp_obj_t *items; + uint32_t flags; + #define FLAG_CHECK_OVERFLOW 1 +} mp_obj_deque_t; + +STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + + /* Initialization from existing sequence is not supported, so an empty + tuple must be passed as such. */ + if (args[0] != mp_const_empty_tuple) { + mp_raise_ValueError(NULL); + } + + // Protect against -1 leading to zero-length allocation and bad array access + mp_int_t maxlen = mp_obj_get_int(args[1]); + if (maxlen < 0) { + mp_raise_ValueError(NULL); + } + + mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t); + o->base.type = type; + o->alloc = maxlen + 1; + o->i_get = o->i_put = 0; + o->items = m_new0(mp_obj_t, o->alloc); + + if (n_args > 2) { + o->flags = mp_obj_get_int(args[2]); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(self->i_get != self->i_put); + case MP_UNARY_OP_LEN: { + ssize_t len = self->i_put - self->i_get; + if (len < 0) { + len += self->alloc; + } + return MP_OBJ_NEW_SMALL_INT(len); + } + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + size_t new_i_put = self->i_put + 1; + if (new_i_put == self->alloc) { + new_i_put = 0; + } + + if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) { + mp_raise_msg(&mp_type_IndexError, "full"); + } + + self->items[self->i_put] = arg; + self->i_put = new_i_put; + + if (self->i_get == new_i_put) { + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); + +STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->i_get == self->i_put) { + mp_raise_msg(&mp_type_IndexError, "empty"); + } + + mp_obj_t ret = self->items[self->i_get]; + self->items[self->i_get] = MP_OBJ_NULL; + + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); + +#if 0 +STATIC mp_obj_t deque_clear(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + self->i_get = self->i_put = 0; + mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear); +#endif + +STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) }, + #if 0 + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table); + +const mp_obj_type_t mp_type_deque = { + { &mp_type_type }, + .name = MP_QSTR_deque, + .make_new = deque_make_new, + .unary_op = deque_unary_op, + .locals_dict = (mp_obj_dict_t*)&deque_locals_dict, +}; + +#endif // MICROPY_PY_COLLECTIONS_DEQUE diff --git a/src/openmv/src/micropython/py/objdict.c b/src/openmv/src/micropython/py/objdict.c new file mode 100755 index 0000000..6ecd7f6 --- /dev/null +++ b/src/openmv/src/micropython/py/objdict.c @@ -0,0 +1,602 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/objtype.h" + +#define MP_OBJ_IS_DICT_TYPE(o) (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) + +STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); + +// This is a helper function to iterate through a dictionary. The state of +// the iteration is held in *cur and should be initialised with zero for the +// first call. Will return NULL when no more elements are available. +STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) { + size_t max = dict->map.alloc; + mp_map_t *map = &dict->map; + + for (size_t i = *cur; i < max; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + *cur = i + 1; + return &(map->table[i]); + } + } + + return NULL; +} + +STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + bool first = true; + if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { + kind = PRINT_REPR; + } + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + mp_printf(print, "%q(", self->base.type->name); + } + mp_print_str(print, "{"); + size_t cur = 0; + mp_map_elem_t *next = NULL; + while ((next = dict_iter_next(self, &cur)) != NULL) { + if (!first) { + mp_print_str(print, ", "); + } + first = false; + mp_obj_print_helper(print, next->key, kind); + mp_print_str(print, ": "); + mp_obj_print_helper(print, next->value, kind); + } + mp_print_str(print, "}"); + if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict) { + mp_print_str(print, ")"); + } +} + +STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_t dict_out = mp_obj_new_dict(0); + mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out); + dict->base.type = type; + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + if (type == &mp_type_ordereddict) { + dict->map.is_ordered = 1; + } + #endif + if (n_args > 0 || n_kw > 0) { + mp_obj_t args2[2] = {dict_out, args[0]}; // args[0] is always valid, even if it's not a positional arg + mp_map_t kwargs; + mp_map_init_fixed_table(&kwargs, n_kw, args + n_args); + dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2 + } + return dict_out; +} + +STATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->map.used != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used); + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in); + switch (op) { + case MP_BINARY_OP_CONTAINS: { + mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); + return mp_obj_new_bool(elem != NULL); + } + case MP_BINARY_OP_EQUAL: { + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT + if (MP_UNLIKELY(MP_OBJ_IS_TYPE(lhs_in, &mp_type_ordereddict) && MP_OBJ_IS_TYPE(rhs_in, &mp_type_ordereddict))) { + // Iterate through both dictionaries simultaneously and compare keys and values. + mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); + size_t c1 = 0, c2 = 0; + mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2); + for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) { + if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) { + return mp_const_false; + } + } + return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false; + } else + #endif + if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in); + if (o->map.used != rhs->map.used) { + return mp_const_false; + } + + size_t cur = 0; + mp_map_elem_t *next = NULL; + while ((next = dict_iter_next(o, &cur)) != NULL) { + mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP); + if (elem == NULL || !mp_obj_equal(next->value, elem->value)) { + return mp_const_false; + } + } + return mp_const_true; + } else { + // dict is not equal to instance of any other type + return mp_const_false; + } + } + default: + // op not supported + return MP_OBJ_NULL; + } +} + +// Note: Make sure this is inlined in load part of dict_subscr() below. +mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); + if (elem == NULL) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); + } else { + return elem->value; + } +} + +STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete + mp_obj_dict_delete(self_in, index); + return mp_const_none; + } else if (value == MP_OBJ_SENTINEL) { + // load + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); + if (elem == NULL) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); + } else { + return elem->value; + } + } else { + // store + mp_obj_dict_store(self_in, index, value); + return mp_const_none; + } +} + +/******************************************************************************/ +/* dict methods */ + +STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { + if (dict->map.is_fixed) { + mp_raise_TypeError(NULL); + } +} + +STATIC mp_obj_t dict_clear(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); + + mp_map_clear(&self->map); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear); + +STATIC mp_obj_t dict_copy(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t other_out = mp_obj_new_dict(self->map.alloc); + mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out); + other->base.type = self->base.type; + other->map.used = self->map.used; + other->map.all_keys_are_qstrs = self->map.all_keys_are_qstrs; + other->map.is_fixed = 0; + other->map.is_ordered = self->map.is_ordered; + memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t)); + return other_out; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); + +// this is a classmethod +STATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) { + mp_obj_t iter = mp_getiter(args[1], NULL); + mp_obj_t value = mp_const_none; + mp_obj_t next = MP_OBJ_NULL; + + if (n_args > 2) { + value = args[2]; + } + + // optimisation to allocate result based on len of argument + mp_obj_t self_out; + mp_obj_t len = mp_obj_len_maybe(args[1]); + if (len == MP_OBJ_NULL) { + /* object's type doesn't have a __len__ slot */ + self_out = mp_obj_new_dict(0); + } else { + self_out = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len)); + } + + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_out); + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + } + + return self_out; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromkeys_fun_obj)); + +STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + if (lookup_kind != MP_MAP_LOOKUP) { + mp_ensure_not_fixed(self); + } + mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); + mp_obj_t value; + if (elem == NULL || elem->value == MP_OBJ_NULL) { + if (n_args == 2) { + if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, args[1])); + } else { + value = mp_const_none; + } + } else { + value = args[2]; + } + if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + elem->value = value; + } + } else { + value = elem->value; + if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + elem->value = MP_OBJ_NULL; // so that GC can collect the deleted value + } + } + return value; +} + +STATIC mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) { + return dict_get_helper(n_args, args, MP_MAP_LOOKUP); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get); + +STATIC mp_obj_t dict_pop(size_t n_args, const mp_obj_t *args) { + return dict_get_helper(n_args, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop); + +STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) { + return dict_get_helper(n_args, args, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault); + +STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); + size_t cur = 0; + mp_map_elem_t *next = dict_iter_next(self, &cur); + if (next == NULL) { + mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty"); + } + self->map.used--; + mp_obj_t items[] = {next->key, next->value}; + next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted + next->value = MP_OBJ_NULL; + mp_obj_t tuple = mp_obj_new_tuple(2, items); + + return tuple; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); + +STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + mp_ensure_not_fixed(self); + + mp_arg_check_num(n_args, kwargs->used, 1, 2, true); + + if (n_args == 2) { + // given a positional argument + + if (MP_OBJ_IS_DICT_TYPE(args[1])) { + // update from other dictionary (make sure other is not self) + if (args[1] != args[0]) { + size_t cur = 0; + mp_map_elem_t *elem = NULL; + while ((elem = dict_iter_next((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) { + mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value; + } + } + } else { + // update from a generic iterable of pairs + mp_obj_t iter = mp_getiter(args[1], NULL); + mp_obj_t next = MP_OBJ_NULL; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_obj_t inneriter = mp_getiter(next, NULL); + mp_obj_t key = mp_iternext(inneriter); + mp_obj_t value = mp_iternext(inneriter); + mp_obj_t stop = mp_iternext(inneriter); + if (key == MP_OBJ_STOP_ITERATION + || value == MP_OBJ_STOP_ITERATION + || stop != MP_OBJ_STOP_ITERATION) { + mp_raise_ValueError("dict update sequence has wrong length"); + } else { + mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + } + } + } + } + + // update the dict with any keyword args + for (size_t i = 0; i < kwargs->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update); + + +/******************************************************************************/ +/* dict views */ + +STATIC const mp_obj_type_t dict_view_type; +STATIC const mp_obj_type_t dict_view_it_type; + +typedef enum _mp_dict_view_kind_t { + MP_DICT_VIEW_ITEMS, + MP_DICT_VIEW_KEYS, + MP_DICT_VIEW_VALUES, +} mp_dict_view_kind_t; + +STATIC const char *const mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; + +typedef struct _mp_obj_dict_view_it_t { + mp_obj_base_t base; + mp_dict_view_kind_t kind; + mp_obj_t dict; + size_t cur; +} mp_obj_dict_view_it_t; + +typedef struct _mp_obj_dict_view_t { + mp_obj_base_t base; + mp_obj_t dict; + mp_dict_view_kind_t kind; +} mp_obj_dict_view_t; + +STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); + mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); + mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); + + if (next == NULL) { + return MP_OBJ_STOP_ITERATION; + } else { + switch (self->kind) { + case MP_DICT_VIEW_ITEMS: + default: { + mp_obj_t items[] = {next->key, next->value}; + return mp_obj_new_tuple(2, items); + } + case MP_DICT_VIEW_KEYS: + return next->key; + case MP_DICT_VIEW_VALUES: + return next->value; + } + } +} + +STATIC const mp_obj_type_t dict_view_it_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity_getiter, + .iternext = dict_view_it_iternext, +}; + +STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_check_self(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); + mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); + mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; + o->base.type = &dict_view_it_type; + o->kind = view->kind; + o->dict = view->dict; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + +STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); + mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); + bool first = true; + mp_print_str(print, mp_dict_view_names[self->kind]); + mp_print_str(print, "(["); + mp_obj_iter_buf_t iter_buf; + mp_obj_t self_iter = dict_view_getiter(self_in, &iter_buf); + mp_obj_t next = MP_OBJ_NULL; + while ((next = dict_view_it_iternext(self_iter)) != MP_OBJ_STOP_ITERATION) { + if (!first) { + mp_print_str(print, ", "); + } + first = false; + mp_obj_print_helper(print, next, PRINT_REPR); + } + mp_print_str(print, "])"); +} + +STATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + // only supported for the 'keys' kind until sets and dicts are refactored + mp_obj_dict_view_t *o = MP_OBJ_TO_PTR(lhs_in); + if (o->kind != MP_DICT_VIEW_KEYS) { + return MP_OBJ_NULL; // op not supported + } + if (op != MP_BINARY_OP_CONTAINS) { + return MP_OBJ_NULL; // op not supported + } + return dict_binary_op(op, o->dict, rhs_in); +} + +STATIC const mp_obj_type_t dict_view_type = { + { &mp_type_type }, + .name = MP_QSTR_dict_view, + .print = dict_view_print, + .binary_op = dict_view_binary_op, + .getiter = dict_view_getiter, +}; + +STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { + mp_obj_dict_view_t *o = m_new_obj(mp_obj_dict_view_t); + o->base.type = &dict_view_type; + o->dict = dict; + o->kind = kind; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + return mp_obj_new_dict_view(self_in, kind); +} + +STATIC mp_obj_t dict_items(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_ITEMS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_items_obj, dict_items); + +STATIC mp_obj_t dict_keys(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_KEYS); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_keys_obj, dict_keys); + +STATIC mp_obj_t dict_values(mp_obj_t self_in) { + return dict_view(self_in, MP_DICT_VIEW_VALUES); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); + +/******************************************************************************/ +/* dict iterator */ + +STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; + o->base.type = &dict_view_it_type; + o->kind = MP_DICT_VIEW_KEYS; + o->dict = self_in; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +/* dict constructors & public C API */ + +STATIC const mp_rom_map_elem_t dict_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&dict_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dict_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_fromkeys), MP_ROM_PTR(&dict_fromkeys_obj) }, + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&dict_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&dict_items_obj) }, + { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&dict_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&dict_pop_obj) }, + { MP_ROM_QSTR(MP_QSTR_popitem), MP_ROM_PTR(&dict_popitem_obj) }, + { MP_ROM_QSTR(MP_QSTR_setdefault), MP_ROM_PTR(&dict_setdefault_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&dict_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&dict_values_obj) }, + { MP_ROM_QSTR(MP_QSTR___getitem__), MP_ROM_PTR(&mp_op_getitem_obj) }, + { MP_ROM_QSTR(MP_QSTR___setitem__), MP_ROM_PTR(&mp_op_setitem_obj) }, + { MP_ROM_QSTR(MP_QSTR___delitem__), MP_ROM_PTR(&mp_op_delitem_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(dict_locals_dict, dict_locals_dict_table); + +const mp_obj_type_t mp_type_dict = { + { &mp_type_type }, + .name = MP_QSTR_dict, + .print = dict_print, + .make_new = dict_make_new, + .unary_op = dict_unary_op, + .binary_op = dict_binary_op, + .subscr = dict_subscr, + .getiter = dict_getiter, + .locals_dict = (mp_obj_dict_t*)&dict_locals_dict, +}; + +#if MICROPY_PY_COLLECTIONS_ORDEREDDICT +const mp_obj_type_t mp_type_ordereddict = { + { &mp_type_type }, + .name = MP_QSTR_OrderedDict, + .print = dict_print, + .make_new = dict_make_new, + .unary_op = dict_unary_op, + .binary_op = dict_binary_op, + .subscr = dict_subscr, + .getiter = dict_getiter, + .parent = &mp_type_dict, + .locals_dict = (mp_obj_dict_t*)&dict_locals_dict, +}; +#endif + +void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args) { + dict->base.type = &mp_type_dict; + mp_map_init(&dict->map, n_args); +} + +mp_obj_t mp_obj_new_dict(size_t n_args) { + mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t); + mp_obj_dict_init(o, n_args); + return MP_OBJ_FROM_PTR(o); +} + +size_t mp_obj_dict_len(mp_obj_t self_in) { + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + return self->map.used; +} + +mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); + mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + return self_in; +} + +mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) { + mp_obj_t args[2] = {self_in, key}; + dict_get_helper(2, args, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return self_in; +} diff --git a/src/openmv/src/micropython/py/objenumerate.c b/src/openmv/src/micropython/py/objenumerate.c new file mode 100755 index 0000000..1a9d30f --- /dev/null +++ b/src/openmv/src/micropython/py/objenumerate.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_ENUMERATE + +typedef struct _mp_obj_enumerate_t { + mp_obj_base_t base; + mp_obj_t iter; + mp_int_t cur; +} mp_obj_enumerate_t; + +STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in); + +STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +#if MICROPY_CPYTHON_COMPAT + static const mp_arg_t allowed_args[] = { + { MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_INT, {.u_int = 0} }, + }; + + // parse args + struct { + mp_arg_val_t iterable, start; + } arg_vals; + mp_arg_parse_all_kw_array(n_args, n_kw, args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals); + + // create enumerate object + mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); + o->base.type = type; + o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL); + o->cur = arg_vals.start.u_int; +#else + (void)n_kw; + mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t); + o->base.type = type; + o->iter = mp_getiter(args[0], NULL); + o->cur = n_args > 1 ? mp_obj_get_int(args[1]) : 0; +#endif + + return MP_OBJ_FROM_PTR(o); +} + +const mp_obj_type_t mp_type_enumerate = { + { &mp_type_type }, + .name = MP_QSTR_enumerate, + .make_new = enumerate_make_new, + .iternext = enumerate_iternext, + .getiter = mp_identity_getiter, +}; + +STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_enumerate)); + mp_obj_enumerate_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t next = mp_iternext(self->iter); + if (next == MP_OBJ_STOP_ITERATION) { + return MP_OBJ_STOP_ITERATION; + } else { + mp_obj_t items[] = {MP_OBJ_NEW_SMALL_INT(self->cur++), next}; + return mp_obj_new_tuple(2, items); + } +} + +#endif // MICROPY_PY_BUILTINS_ENUMERATE diff --git a/src/openmv/src/micropython/py/objexcept.c b/src/openmv/src/micropython/py/objexcept.c new file mode 100755 index 0000000..1e746bc --- /dev/null +++ b/src/openmv/src/micropython/py/objexcept.c @@ -0,0 +1,519 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mperrno.h" + +// Number of items per traceback entry (file, line, block) +#define TRACEBACK_ENTRY_LEN (3) + +// Number of traceback entries to reserve in the emergency exception buffer +#define EMG_TRACEBACK_ALLOC (2 * TRACEBACK_ENTRY_LEN) + +// Optionally allocated buffer for storing the first argument of an exception +// allocated when the heap is locked. +#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF +# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0 +#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE + +void mp_init_emergency_exception_buf(void) { + // Nothing to do since the buffer was declared statically. We put this + // definition here so that the calling code can call this function + // regardless of how its configured (makes the calling code a bit cleaner). +} + +#else +#define mp_emergency_exception_buf_size MP_STATE_VM(mp_emergency_exception_buf_size) + +void mp_init_emergency_exception_buf(void) { + mp_emergency_exception_buf_size = 0; + MP_STATE_VM(mp_emergency_exception_buf) = NULL; +} + +mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { + mp_int_t size = mp_obj_get_int(size_in); + void *buf = NULL; + if (size > 0) { + buf = m_new(byte, size); + } + + int old_size = mp_emergency_exception_buf_size; + void *old_buf = MP_STATE_VM(mp_emergency_exception_buf); + + // Update the 2 variables atomically so that an interrupt can't occur + // between the assignments. + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_emergency_exception_buf_size = size; + MP_STATE_VM(mp_emergency_exception_buf) = buf; + MICROPY_END_ATOMIC_SECTION(atomic_state); + + if (old_buf != NULL) { + m_del(byte, old_buf, old_size); + } + return mp_const_none; +} +#endif +#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + +// Instance of GeneratorExit exception - needed by generator.close() +// This would belong to objgenerator.c, but to keep mp_obj_exception_t +// definition module-private so far, have it here. +const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; + +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in); + mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; + bool is_subclass = kind & PRINT_EXC_SUBCLASS; + if (!is_subclass && (k == PRINT_REPR || k == PRINT_EXC)) { + mp_print_str(print, qstr_str(o->base.type->name)); + } + + if (k == PRINT_EXC) { + mp_print_str(print, ": "); + } + + if (k == PRINT_STR || k == PRINT_EXC) { + if (o->args == NULL || o->args->len == 0) { + mp_print_str(print, ""); + return; + } else if (o->args->len == 1) { + #if MICROPY_PY_UERRNO + // try to provide a nice OSError error message + if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { + qstr qst = mp_errno_to_str(o->args->items[0]); + if (qst != MP_QSTR_NULL) { + mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); + return; + } + } + #endif + mp_obj_print_helper(print, o->args->items[0], PRINT_STR); + return; + } + } + mp_obj_tuple_print(print, MP_OBJ_FROM_PTR(o->args), kind); +} + +mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); + + // Try to allocate memory for the exception, with fallback to emergency exception object + mp_obj_exception_t *o_exc = m_new_obj_maybe(mp_obj_exception_t); + if (o_exc == NULL) { + o_exc = &MP_STATE_VM(mp_emergency_exception_obj); + } + + // Populate the exception object + o_exc->base.type = type; + o_exc->traceback_data = NULL; + + mp_obj_tuple_t *o_tuple; + if (n_args == 0) { + // No args, can use the empty tuple straightaway + o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; + } else { + // Try to allocate memory for the tuple containing the args + o_tuple = m_new_obj_var_maybe(mp_obj_tuple_t, mp_obj_t, n_args); + + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + // If we are called by mp_obj_new_exception_msg_varg then it will have + // reserved room (after the traceback data) for a tuple with 1 element. + // Otherwise we are free to use the whole buffer after the traceback data. + if (o_tuple == NULL && mp_emergency_exception_buf_size >= + EMG_TRACEBACK_ALLOC * sizeof(size_t) + sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t)) { + o_tuple = (mp_obj_tuple_t*) + ((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + EMG_TRACEBACK_ALLOC * sizeof(size_t)); + } + #endif + + if (o_tuple == NULL) { + // No memory for a tuple, fallback to an empty tuple + o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; + } else { + // Have memory for a tuple so populate it + o_tuple->base.type = &mp_type_tuple; + o_tuple->len = n_args; + memcpy(o_tuple->items, args, n_args * sizeof(mp_obj_t)); + } + } + + // Store the tuple of args in the exception object + o_exc->args = o_tuple; + + return MP_OBJ_FROM_PTR(o_exc); +} + +// Get exception "value" - that is, first argument, or None +mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { + mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); + if (self->args->len == 0) { + return mp_const_none; + } else { + return self->args->items[0]; + } +} + +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); + if (dest[0] != MP_OBJ_NULL) { + // store/delete attribute + if (attr == MP_QSTR___traceback__ && dest[1] == mp_const_none) { + // We allow 'exc.__traceback__ = None' assignment as low-level + // optimization of pre-allocating exception instance and raising + // it repeatedly - this avoids memory allocation during raise. + // However, uPy will keep adding traceback entries to such + // exception instance, so before throwing it, traceback should + // be cleared like above. + self->traceback_len = 0; + dest[0] = MP_OBJ_NULL; // indicate success + } + return; + } + if (attr == MP_QSTR_args) { + dest[0] = MP_OBJ_FROM_PTR(self->args); + } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) { + dest[0] = mp_obj_exception_get_value(self_in); + } +} + +const mp_obj_type_t mp_type_BaseException = { + { &mp_type_type }, + .name = MP_QSTR_BaseException, + .print = mp_obj_exception_print, + .make_new = mp_obj_exception_make_new, + .attr = mp_obj_exception_attr, +}; + +// List of all exceptions, arranged as in the table at: +// http://docs.python.org/3/library/exceptions.html +MP_DEFINE_EXCEPTION(SystemExit, BaseException) +MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) +MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) +MP_DEFINE_EXCEPTION(Exception, BaseException) + #if MICROPY_PY_ASYNC_AWAIT + MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception) + #endif + MP_DEFINE_EXCEPTION(StopIteration, Exception) + MP_DEFINE_EXCEPTION(ArithmeticError, Exception) + //MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError) + MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError) + MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError) + MP_DEFINE_EXCEPTION(AssertionError, Exception) + MP_DEFINE_EXCEPTION(AttributeError, Exception) + //MP_DEFINE_EXCEPTION(BufferError, Exception) + //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) use OSError instead + MP_DEFINE_EXCEPTION(EOFError, Exception) + MP_DEFINE_EXCEPTION(ImportError, Exception) + //MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead + MP_DEFINE_EXCEPTION(LookupError, Exception) + MP_DEFINE_EXCEPTION(IndexError, LookupError) + MP_DEFINE_EXCEPTION(KeyError, LookupError) + MP_DEFINE_EXCEPTION(MemoryError, Exception) + MP_DEFINE_EXCEPTION(NameError, Exception) + /* + MP_DEFINE_EXCEPTION(UnboundLocalError, NameError) + */ + MP_DEFINE_EXCEPTION(OSError, Exception) +#if MICROPY_PY_BUILTINS_TIMEOUTERROR + MP_DEFINE_EXCEPTION(TimeoutError, OSError) +#endif + /* + MP_DEFINE_EXCEPTION(BlockingIOError, OSError) + MP_DEFINE_EXCEPTION(ChildProcessError, OSError) + MP_DEFINE_EXCEPTION(ConnectionError, OSError) + MP_DEFINE_EXCEPTION(BrokenPipeError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionAbortedError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionRefusedError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionResetError, ConnectionError) + MP_DEFINE_EXCEPTION(InterruptedError, OSError) + MP_DEFINE_EXCEPTION(IsADirectoryError, OSError) + MP_DEFINE_EXCEPTION(NotADirectoryError, OSError) + MP_DEFINE_EXCEPTION(PermissionError, OSError) + MP_DEFINE_EXCEPTION(ProcessLookupError, OSError) + MP_DEFINE_EXCEPTION(FileExistsError, OSError) + MP_DEFINE_EXCEPTION(FileNotFoundError, OSError) + MP_DEFINE_EXCEPTION(ReferenceError, Exception) + */ + MP_DEFINE_EXCEPTION(RuntimeError, Exception) + MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError) + MP_DEFINE_EXCEPTION(SyntaxError, Exception) + MP_DEFINE_EXCEPTION(IndentationError, SyntaxError) + /* + MP_DEFINE_EXCEPTION(TabError, IndentationError) + */ + //MP_DEFINE_EXCEPTION(SystemError, Exception) + MP_DEFINE_EXCEPTION(TypeError, Exception) +#if MICROPY_EMIT_NATIVE + MP_DEFINE_EXCEPTION(ViperTypeError, TypeError) +#endif + MP_DEFINE_EXCEPTION(ValueError, Exception) +#if MICROPY_PY_BUILTINS_STR_UNICODE + MP_DEFINE_EXCEPTION(UnicodeError, ValueError) + //TODO: Implement more UnicodeError subclasses which take arguments +#endif + /* + MP_DEFINE_EXCEPTION(Warning, Exception) + MP_DEFINE_EXCEPTION(DeprecationWarning, Warning) + MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning) + MP_DEFINE_EXCEPTION(RuntimeWarning, Warning) + MP_DEFINE_EXCEPTION(SyntaxWarning, Warning) + MP_DEFINE_EXCEPTION(UserWarning, Warning) + MP_DEFINE_EXCEPTION(FutureWarning, Warning) + MP_DEFINE_EXCEPTION(ImportWarning, Warning) + MP_DEFINE_EXCEPTION(UnicodeWarning, Warning) + MP_DEFINE_EXCEPTION(BytesWarning, Warning) + MP_DEFINE_EXCEPTION(ResourceWarning, Warning) + */ + +mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { + return mp_obj_new_exception_args(exc_type, 0, NULL); +} + +// "Optimized" version for common(?) case of having 1 exception arg +mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { + return mp_obj_new_exception_args(exc_type, 1, &arg); +} + +mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) { + assert(exc_type->make_new == mp_obj_exception_make_new); + return exc_type->make_new(exc_type, n_args, 0, args); +} + +mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg) { + return mp_obj_new_exception_msg_varg(exc_type, msg); +} + +// The following struct and function implement a simple printer that conservatively +// allocates memory and truncates the output data if no more memory can be obtained. +// It leaves room for a null byte at the end of the buffer. + +struct _exc_printer_t { + bool allow_realloc; + size_t alloc; + size_t len; + byte *buf; +}; + +STATIC void exc_add_strn(void *data, const char *str, size_t len) { + struct _exc_printer_t *pr = data; + if (pr->len + len >= pr->alloc) { + // Not enough room for data plus a null byte so try to grow the buffer + if (pr->allow_realloc) { + size_t new_alloc = pr->alloc + len + 16; + byte *new_buf = m_renew_maybe(byte, pr->buf, pr->alloc, new_alloc, true); + if (new_buf == NULL) { + pr->allow_realloc = false; + len = pr->alloc - pr->len - 1; + } else { + pr->alloc = new_alloc; + pr->buf = new_buf; + } + } else { + len = pr->alloc - pr->len - 1; + } + } + memcpy(pr->buf + pr->len, str, len); + pr->len += len; +} + +mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { + assert(fmt != NULL); + + // Check that the given type is an exception type + assert(exc_type->make_new == mp_obj_exception_make_new); + + // Try to allocate memory for the message + mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t); + size_t o_str_alloc = strlen(fmt) + 1; + byte *o_str_buf = m_new_maybe(byte, o_str_alloc); + + bool used_emg_buf = false; + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + // If memory allocation failed and there is an emergency buffer then try to use + // that buffer to store the string object and its data (at least 16 bytes for + // the string data), reserving room at the start for the traceback and 1-tuple. + if ((o_str == NULL || o_str_buf == NULL) + && mp_emergency_exception_buf_size >= EMG_TRACEBACK_ALLOC * sizeof(size_t) + + sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t) + sizeof(mp_obj_str_t) + 16) { + used_emg_buf = true; + o_str = (mp_obj_str_t*)((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + + EMG_TRACEBACK_ALLOC * sizeof(size_t) + sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t)); + o_str_buf = (byte*)&o_str[1]; + o_str_alloc = (uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + + mp_emergency_exception_buf_size - o_str_buf; + } + #endif + + if (o_str == NULL) { + // No memory for the string object so create the exception with no args + return mp_obj_exception_make_new(exc_type, 0, 0, NULL); + } + + if (o_str_buf == NULL) { + // No memory for the string buffer: assume that the fmt string is in ROM + // and use that data as the data of the string + o_str->len = o_str_alloc - 1; // will be equal to strlen(fmt) + o_str->data = (const byte*)fmt; + } else { + // We have some memory to format the string + struct _exc_printer_t exc_pr = {!used_emg_buf, o_str_alloc, 0, o_str_buf}; + mp_print_t print = {&exc_pr, exc_add_strn}; + va_list ap; + va_start(ap, fmt); + mp_vprintf(&print, fmt, ap); + va_end(ap); + exc_pr.buf[exc_pr.len] = '\0'; + o_str->len = exc_pr.len; + o_str->data = exc_pr.buf; + } + + // Create the string object and call mp_obj_exception_make_new to create the exception + o_str->base.type = &mp_type_str; + o_str->hash = qstr_compute_hash(o_str->data, o_str->len); + mp_obj_t arg = MP_OBJ_FROM_PTR(o_str); + return mp_obj_exception_make_new(exc_type, 1, 0, &arg); +} + +// return true if the given object is an exception type +bool mp_obj_is_exception_type(mp_obj_t self_in) { + if (MP_OBJ_IS_TYPE(self_in, &mp_type_type)) { + // optimisation when self_in is a builtin exception + mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); + if (self->make_new == mp_obj_exception_make_new) { + return true; + } + } + return mp_obj_is_subclass_fast(self_in, MP_OBJ_FROM_PTR(&mp_type_BaseException)); +} + +// return true if the given object is an instance of an exception type +bool mp_obj_is_exception_instance(mp_obj_t self_in) { + return mp_obj_is_exception_type(MP_OBJ_FROM_PTR(mp_obj_get_type(self_in))); +} + +// Return true if exception (type or instance) is a subclass of given +// exception type. Assumes exc_type is a subclass of BaseException, as +// defined by mp_obj_is_exception_type(exc_type). +bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) { + // if exc is an instance of an exception, then extract and use its type + if (mp_obj_is_exception_instance(exc)) { + exc = MP_OBJ_FROM_PTR(mp_obj_get_type(exc)); + } + return mp_obj_is_subclass_fast(exc, exc_type); +} + +// traceback handling functions + +#define GET_NATIVE_EXCEPTION(self, self_in) \ + /* make sure self_in is an exception instance */ \ + assert(mp_obj_is_exception_instance(self_in)); \ + mp_obj_exception_t *self; \ + if (mp_obj_is_native_exception_instance(self_in)) { \ + self = MP_OBJ_TO_PTR(self_in); \ + } else { \ + self = MP_OBJ_TO_PTR(((mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in))->subobj[0]); \ + } + +void mp_obj_exception_clear_traceback(mp_obj_t self_in) { + GET_NATIVE_EXCEPTION(self, self_in); + // just set the traceback to the null object + // we don't want to call any memory management functions here + self->traceback_data = NULL; +} + +void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block) { + GET_NATIVE_EXCEPTION(self, self_in); + + // append this traceback info to traceback data + // if memory allocation fails (eg because gc is locked), just return + + if (self->traceback_data == NULL) { + self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN); + if (self->traceback_data == NULL) { + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + if (mp_emergency_exception_buf_size >= EMG_TRACEBACK_ALLOC * sizeof(size_t)) { + // There is room in the emergency buffer for traceback data + size_t *tb = (size_t*)MP_STATE_VM(mp_emergency_exception_buf); + self->traceback_data = tb; + self->traceback_alloc = EMG_TRACEBACK_ALLOC; + } else { + // Can't allocate and no room in emergency buffer + return; + } + #else + // Can't allocate + return; + #endif + } else { + // Allocated the traceback data on the heap + self->traceback_alloc = TRACEBACK_ENTRY_LEN; + } + self->traceback_len = 0; + } else if (self->traceback_len + TRACEBACK_ENTRY_LEN > self->traceback_alloc) { + #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + if (self->traceback_data == (size_t*)MP_STATE_VM(mp_emergency_exception_buf)) { + // Can't resize the emergency buffer + return; + } + #endif + // be conservative with growing traceback data + size_t *tb_data = m_renew_maybe(size_t, self->traceback_data, self->traceback_alloc, + self->traceback_alloc + TRACEBACK_ENTRY_LEN, true); + if (tb_data == NULL) { + return; + } + self->traceback_data = tb_data; + self->traceback_alloc += TRACEBACK_ENTRY_LEN; + } + + size_t *tb_data = &self->traceback_data[self->traceback_len]; + self->traceback_len += TRACEBACK_ENTRY_LEN; + tb_data[0] = file; + tb_data[1] = line; + tb_data[2] = block; +} + +void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values) { + GET_NATIVE_EXCEPTION(self, self_in); + + if (self->traceback_data == NULL) { + *n = 0; + *values = NULL; + } else { + *n = self->traceback_len; + *values = self->traceback_data; + } +} diff --git a/src/openmv/src/micropython/py/objexcept.h b/src/openmv/src/micropython/py/objexcept.h new file mode 100755 index 0000000..7c30762 --- /dev/null +++ b/src/openmv/src/micropython/py/objexcept.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJEXCEPT_H +#define MICROPY_INCLUDED_PY_OBJEXCEPT_H + +#include "py/obj.h" +#include "py/objtuple.h" + +typedef struct _mp_obj_exception_t { + mp_obj_base_t base; + size_t traceback_alloc : (8 * sizeof(size_t) / 2); + size_t traceback_len : (8 * sizeof(size_t) / 2); + size_t *traceback_data; + mp_obj_tuple_t *args; +} mp_obj_exception_t; + +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); + +#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ +const mp_obj_type_t mp_type_ ## exc_name = { \ + { &mp_type_type }, \ + .name = MP_QSTR_ ## exc_name, \ + .print = mp_obj_exception_print, \ + .make_new = mp_obj_exception_make_new, \ + .attr = mp_obj_exception_attr, \ + .parent = &mp_type_ ## base_name, \ +}; + +#endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H diff --git a/src/openmv/src/micropython/py/objfilter.c b/src/openmv/src/micropython/py/objfilter.c new file mode 100755 index 0000000..cb965d8 --- /dev/null +++ b/src/openmv/src/micropython/py/objfilter.c @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FILTER + +typedef struct _mp_obj_filter_t { + mp_obj_base_t base; + mp_obj_t fun; + mp_obj_t iter; +} mp_obj_filter_t; + +STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t); + o->base.type = type; + o->fun = args[0]; + o->iter = mp_getiter(args[1], NULL); + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); + mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t next; + while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { + mp_obj_t val; + if (self->fun != mp_const_none) { + val = mp_call_function_n_kw(self->fun, 1, 0, &next); + } else { + val = next; + } + if (mp_obj_is_true(val)) { + return next; + } + } + return MP_OBJ_STOP_ITERATION; +} + +const mp_obj_type_t mp_type_filter = { + { &mp_type_type }, + .name = MP_QSTR_filter, + .make_new = filter_make_new, + .getiter = mp_identity_getiter, + .iternext = filter_iternext, +}; + +#endif // MICROPY_PY_BUILTINS_FILTER diff --git a/src/openmv/src/micropython/py/objfloat.c b/src/openmv/src/micropython/py/objfloat.c new file mode 100755 index 0000000..4db1bb8 --- /dev/null +++ b/src/openmv/src/micropython/py/objfloat.c @@ -0,0 +1,330 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/parsenum.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FLOAT + +#include +#include "py/formatfloat.h" + +#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D + +// M_E and M_PI are not part of the math.h standard and may not be defined +#ifndef M_E +#define M_E (2.7182818284590452354) +#endif +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +typedef struct _mp_obj_float_t { + mp_obj_base_t base; + mp_float_t value; +} mp_obj_float_t; + +const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E}; +const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI}; + +#endif + +#if MICROPY_FLOAT_HIGH_QUALITY_HASH +// must return actual integer value if it fits in mp_int_t +mp_int_t mp_float_hash(mp_float_t src) { +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +typedef uint64_t mp_float_uint_t; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +typedef uint32_t mp_float_uint_t; +#endif + union { + mp_float_t f; + #if MP_ENDIANNESS_LITTLE + struct { mp_float_uint_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p; + #else + struct { mp_float_uint_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p; + #endif + mp_float_uint_t i; + } u = {.f = src}; + + mp_int_t val; + const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS; + if (adj_exp < 0) { + // value < 1; must be sure to handle 0.0 correctly (ie return 0) + val = u.i; + } else { + // if adj_exp is max then: u.p.frc==0 indicates inf, else NaN + // else: 1 <= value + mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS); + + if (adj_exp <= MP_FLOAT_FRAC_BITS) { + // number may have a fraction; xor the integer part with the fractional part + val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp)) + ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); + } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) { + // the number is a (big) whole integer and will fit in val's signed-width + val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS); + } else { + // integer part will overflow val's width so just use what bits we can + val = frc; + } + } + + if (u.p.sgn) { + val = -(mp_uint_t)val; + } + + return val; +} +#endif + +STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_float_t o_val = mp_obj_float_get(o_in); +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + char buf[16]; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + const int precision = 6; + #else + const int precision = 7; + #endif +#else + char buf[32]; + const int precision = 16; +#endif + mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0'); + mp_print_str(print, buf); + if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { + // Python floats always have decimal point (unless inf or nan) + mp_print_str(print, ".0"); + } +} + +STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + switch (n_args) { + case 0: + return mp_obj_new_float(0); + + case 1: + default: { + mp_buffer_info_t bufinfo; + if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { + // a textual representation, parse it + return mp_parse_num_decimal(bufinfo.buf, bufinfo.len, false, false, NULL); + } else if (mp_obj_is_float(args[0])) { + // a float, just return it + return args[0]; + } else { + // something else, try to cast it to a float + return mp_obj_new_float(mp_obj_get_float(args[0])); + } + } + } +} + +STATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_float_t val = mp_obj_float_get(o_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(val != 0); + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val)); + case MP_UNARY_OP_POSITIVE: return o_in; + case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-val); + case MP_UNARY_OP_ABS: { + if (signbit(val)) { + return mp_obj_new_float(-val); + } else { + return o_in; + } + } + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_float_t lhs_val = mp_obj_float_get(lhs_in); +#if MICROPY_PY_BUILTINS_COMPLEX + if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in); + } else +#endif + { + return mp_obj_float_binary_op(op, lhs_val, rhs_in); + } +} + +const mp_obj_type_t mp_type_float = { + { &mp_type_type }, + .name = MP_QSTR_float, + .print = float_print, + .make_new = float_make_new, + .unary_op = float_unary_op, + .binary_op = float_binary_op, +}; + +#if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D + +mp_obj_t mp_obj_new_float(mp_float_t value) { + mp_obj_float_t *o = m_new(mp_obj_float_t, 1); + o->base.type = &mp_type_float; + o->value = value; + return MP_OBJ_FROM_PTR(o); +} + +mp_float_t mp_obj_float_get(mp_obj_t self_in) { + assert(mp_obj_is_float(self_in)); + mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in); + return self->value; +} + +#endif + +STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) { + // logic here follows that of CPython + // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations + // x == (x//y)*y + (x%y) + // divmod(x, y) == (x//y, x%y) + mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y); + mp_float_t div = (*x - mod) / *y; + + // Python specs require that mod has same sign as second operand + if (mod == 0.0) { + mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y); + } else { + if ((mod < 0.0) != (*y < 0.0)) { + mod += *y; + div -= 1.0; + } + } + + mp_float_t floordiv; + if (div == 0.0) { + // if division is zero, take the correct sign of zero + floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y); + } else { + // Python specs require that x == (x//y)*y + (x%y) + floordiv = MICROPY_FLOAT_C_FUN(floor)(div); + if (div - floordiv > 0.5) { + floordiv += 1.0; + } + } + + // return results + *x = floordiv; + *y = mod; +} + +mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs_in) { + mp_float_t rhs_val; + if (!mp_obj_get_float_maybe(rhs_in, &rhs_val)) { + return MP_OBJ_NULL; // op not supported + } + + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break; + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break; + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break; + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + zero_division_error: + mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + } + // Python specs require that x == (x//y)*y + (x%y) so we must + // call divmod to compute the correct floor division, which + // returns the floor divide in lhs_val. + mp_obj_float_divmod(&lhs_val, &rhs_val); + break; + case MP_BINARY_OP_TRUE_DIVIDE: + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + if (rhs_val == 0) { + goto zero_division_error; + } + lhs_val /= rhs_val; + break; + case MP_BINARY_OP_MODULO: + case MP_BINARY_OP_INPLACE_MODULO: + if (rhs_val == 0) { + goto zero_division_error; + } + lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val); + // Python specs require that mod has same sign as second operand + if (lhs_val == 0.0) { + lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val); + } else { + if ((lhs_val < 0.0) != (rhs_val < 0.0)) { + lhs_val += rhs_val; + } + } + break; + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: + if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) { + goto zero_division_error; + } + if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) { + #if MICROPY_PY_BUILTINS_COMPLEX + return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in); + #else + mp_raise_ValueError("complex values not supported"); + #endif + } + lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); + break; + case MP_BINARY_OP_DIVMOD: { + if (rhs_val == 0) { + goto zero_division_error; + } + mp_obj_float_divmod(&lhs_val, &rhs_val); + mp_obj_t tuple[2] = { + mp_obj_new_float(lhs_val), + mp_obj_new_float(rhs_val), + }; + return mp_obj_new_tuple(2, tuple); + } + case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_val == rhs_val); + case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); + + default: + return MP_OBJ_NULL; // op not supported + } + return mp_obj_new_float(lhs_val); +} + +#endif // MICROPY_PY_BUILTINS_FLOAT diff --git a/src/openmv/src/micropython/py/objfun.c b/src/openmv/src/micropython/py/objfun.c new file mode 100755 index 0000000..112eadb --- /dev/null +++ b/src/openmv/src/micropython/py/objfun.c @@ -0,0 +1,526 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objtuple.h" +#include "py/objfun.h" +#include "py/runtime.h" +#include "py/bc.h" +#include "py/stackctrl.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +// Note: the "name" entry in mp_obj_type_t for a function type must be +// MP_QSTR_function because it is used to determine if an object is of generic +// function type. + +/******************************************************************************/ +/* builtin functions */ + +STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)args; + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return self->fun._0(); +} + +const mp_obj_type_t mp_type_fun_builtin_0 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_0_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 1, 1, false); + return self->fun._1(args[0]); +} + +const mp_obj_type_t mp_type_fun_builtin_1 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_1_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 2, 2, false); + return self->fun._2(args[0], args[1]); +} + +const mp_obj_type_t mp_type_fun_builtin_2 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_2_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 3, 3, false); + return self->fun._3(args[0], args[1], args[2]); +} + +const mp_obj_type_t mp_type_fun_builtin_3 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_3_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); + mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); + + // check number of arguments + mp_arg_check_num_sig(n_args, n_kw, self->sig); + + if (self->sig & 1) { + // function allows keywords + + // we create a map directly from the given args array + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + return self->fun.kw(n_args, args, &kw_args); + + } else { + // function takes a variable number of arguments, but no keywords + + return self->fun.var(n_args, args); + } +} + +const mp_obj_type_t mp_type_fun_builtin_var = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_var_call, + .unary_op = mp_generic_unary_op, +}; + +/******************************************************************************/ +/* byte code functions */ + +qstr mp_obj_code_get_name(const byte *code_info) { + code_info = mp_decode_uint_skip(code_info); // skip code_info_size entry + #if MICROPY_PERSISTENT_CODE + return code_info[0] | (code_info[1] << 8); + #else + return mp_decode_uint_value(code_info); + #endif +} + +#if MICROPY_EMIT_NATIVE +STATIC const mp_obj_type_t mp_type_fun_native; +#endif + +qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) { + const mp_obj_fun_bc_t *fun = MP_OBJ_TO_PTR(fun_in); + #if MICROPY_EMIT_NATIVE + if (fun->base.type == &mp_type_fun_native || fun->base.type == &mp_type_native_gen_wrap) { + // TODO native functions don't have name stored + return MP_QSTR_; + } + #endif + + const byte *bc = fun->bytecode; + bc = mp_decode_uint_skip(bc); // skip n_state + bc = mp_decode_uint_skip(bc); // skip n_exc_stack + bc++; // skip scope_params + bc++; // skip n_pos_args + bc++; // skip n_kwonly_args + bc++; // skip n_def_pos_args + return mp_obj_code_get_name(bc); +} + +#if MICROPY_CPYTHON_COMPAT +STATIC void fun_bc_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(o_in); + mp_printf(print, "", mp_obj_fun_get_name(o_in), o); +} +#endif + +#if DEBUG_PRINT +STATIC void dump_args(const mp_obj_t *a, size_t sz) { + DEBUG_printf("%p: ", a); + for (size_t i = 0; i < sz; i++) { + DEBUG_printf("%p ", a[i]); + } + DEBUG_printf("\n"); +} +#else +#define dump_args(...) (void)0 +#endif + +// With this macro you can tune the maximum number of function state bytes +// that will be allocated on the stack. Any function that needs more +// than this will try to use the heap, with fallback to stack allocation. +#define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t)) + +// Set this to 1 to enable a simple stack overflow check. +#define VM_DETECT_STACK_OVERFLOW (0) + +#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \ + { \ + /* bytecode prelude: state size and exception stack size */ \ + n_state_out_var = mp_decode_uint_value(bytecode); \ + size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \ + \ + n_state_out_var += VM_DETECT_STACK_OVERFLOW; \ + \ + /* state size in bytes */ \ + state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ + + n_exc_stack * sizeof(mp_exc_stack_t); \ + } + +#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ + code_state->fun_bc = _fun_bc; \ + code_state->ip = 0; \ + mp_setup_code_state(code_state, n_args, n_kw, args); \ + code_state->old_globals = mp_globals_get(); + +#if MICROPY_STACKLESS +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + MP_STACK_CHECK(); + mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); + + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); + + mp_code_state_t *code_state; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else + // If we use m_new_obj_var(), then on no memory, MemoryError will be + // raised. But this is not correct exception for a function call, + // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(), + // return NULL, then vm.c takes the needed action (either raise + // RuntimeError or fallback to stack allocation). + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); + if (!code_state) { + return NULL; + } + #endif + + INIT_CODESTATE(code_state, self, n_args, n_kw, args); + + // execute the byte code with the correct globals context + mp_globals_set(self->globals); + + return code_state; +} +#endif + +STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + MP_STACK_CHECK(); + + DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw); + DEBUG_printf("Input pos args: "); + dump_args(args, n_args); + DEBUG_printf("Input kw args: "); + dump_args(args + n_args, n_kw * 2); + + mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); + + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); + + // allocate state for locals and stack + mp_code_state_t *code_state = NULL; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else + if (state_size > VM_MAX_STATE_ON_STACK) { + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); + } + if (code_state == NULL) { + code_state = alloca(sizeof(mp_code_state_t) + state_size); + state_size = 0; // indicate that we allocated using alloca + } + #endif + + INIT_CODESTATE(code_state, self, n_args, n_kw, args); + + // execute the byte code with the correct globals context + mp_globals_set(self->globals); + mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); + mp_globals_set(code_state->old_globals); + +#if VM_DETECT_STACK_OVERFLOW + if (vm_return_kind == MP_VM_RETURN_NORMAL) { + if (code_state->sp < code_state->state) { + printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state); + assert(0); + } + } + // We can't check the case when an exception is returned in state[n_state - 1] + // and there are no arguments, because in this case our detection slot may have + // been overwritten by the returned exception (which is allowed). + if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) { + // Just check to see that we have at least 1 null object left in the state. + bool overflow = true; + for (size_t i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) { + if (code_state->state[i] == MP_OBJ_NULL) { + overflow = false; + break; + } + } + if (overflow) { + printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state); + assert(0); + } + } +#endif + + mp_obj_t result; + if (vm_return_kind == MP_VM_RETURN_NORMAL) { + // return value is in *sp + result = *code_state->sp; + } else { + // must be an exception because normal functions can't yield + assert(vm_return_kind == MP_VM_RETURN_EXCEPTION); + // return value is in fastn[0]==state[n_state - 1] + result = code_state->state[0]; + } + + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(code_state); + #else + // free the state if it was allocated on the heap + if (state_size != 0) { + m_del_var(mp_code_state_t, byte, state_size, code_state); + } + #endif + + if (vm_return_kind == MP_VM_RETURN_NORMAL) { + return result; + } else { // MP_VM_RETURN_EXCEPTION + nlr_raise(result); + } +} + +#if MICROPY_PY_FUNCTION_ATTRS +void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + if (attr == MP_QSTR___name__) { + dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in)); + } +} +#endif + +const mp_obj_type_t mp_type_fun_bc = { + { &mp_type_type }, + .name = MP_QSTR_function, +#if MICROPY_CPYTHON_COMPAT + .print = fun_bc_print, +#endif + .call = fun_bc_call, + .unary_op = mp_generic_unary_op, +#if MICROPY_PY_FUNCTION_ATTRS + .attr = mp_obj_fun_bc_attr, +#endif +}; + +mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table) { + size_t n_def_args = 0; + size_t n_extra_args = 0; + mp_obj_tuple_t *def_args = MP_OBJ_TO_PTR(def_args_in); + if (def_args_in != MP_OBJ_NULL) { + assert(MP_OBJ_IS_TYPE(def_args_in, &mp_type_tuple)); + n_def_args = def_args->len; + n_extra_args = def_args->len; + } + if (def_kw_args != MP_OBJ_NULL) { + n_extra_args += 1; + } + mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args); + o->base.type = &mp_type_fun_bc; + o->globals = mp_globals_get(); + o->bytecode = code; + o->const_table = const_table; + if (def_args != NULL) { + memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t)); + } + if (def_kw_args != MP_OBJ_NULL) { + o->extra_args[n_def_args] = def_kw_args; + } + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +/* native functions */ + +#if MICROPY_EMIT_NATIVE + +STATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + MP_STACK_CHECK(); + mp_obj_fun_bc_t *self = self_in; + mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode); + return fun(self_in, n_args, n_kw, args); +} + +STATIC const mp_obj_type_t mp_type_fun_native = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_native_call, + .unary_op = mp_generic_unary_op, +}; + +mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table) { + mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte*)fun_data, const_table); + o->base.type = &mp_type_fun_native; + return o; +} + +#endif // MICROPY_EMIT_NATIVE + +/******************************************************************************/ +/* inline assembler functions */ + +#if MICROPY_EMIT_INLINE_ASM + +typedef struct _mp_obj_fun_asm_t { + mp_obj_base_t base; + size_t n_args; + void *fun_data; // GC must be able to trace this pointer + mp_uint_t type_sig; +} mp_obj_fun_asm_t; + +typedef mp_uint_t (*inline_asm_fun_0_t)(void); +typedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t); +typedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t); +typedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t); +typedef mp_uint_t (*inline_asm_fun_4_t)(mp_uint_t, mp_uint_t, mp_uint_t, mp_uint_t); + +// convert a MicroPython object to a sensible value for inline asm +STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { + // TODO for byte_array, pass pointer to the array + if (MP_OBJ_IS_SMALL_INT(obj)) { + return MP_OBJ_SMALL_INT_VALUE(obj); + } else if (obj == mp_const_none) { + return 0; + } else if (obj == mp_const_false) { + return 0; + } else if (obj == mp_const_true) { + return 1; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_int)) { + return mp_obj_int_get_truncated(obj); + } else if (MP_OBJ_IS_STR(obj)) { + // pointer to the string (it's probably constant though!) + size_t l; + return (mp_uint_t)mp_obj_str_get_data(obj, &l); + } else { + mp_obj_type_t *type = mp_obj_get_type(obj); + if (0) { +#if MICROPY_PY_BUILTINS_FLOAT + } else if (type == &mp_type_float) { + // convert float to int (could also pass in float registers) + return (mp_int_t)mp_obj_float_get(obj); +#endif + } else if (type == &mp_type_tuple || type == &mp_type_list) { + // pointer to start of tuple (could pass length, but then could use len(x) for that) + size_t len; + mp_obj_t *items; + mp_obj_get_array(obj, &len, &items); + return (mp_uint_t)items; + } else { + mp_buffer_info_t bufinfo; + if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) { + // supports the buffer protocol, return a pointer to the data + return (mp_uint_t)bufinfo.buf; + } else { + // just pass along a pointer to the object + return (mp_uint_t)obj; + } + } + } +} + +STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_fun_asm_t *self = self_in; + + mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); + + void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); + + mp_uint_t ret; + if (n_args == 0) { + ret = ((inline_asm_fun_0_t)fun)(); + } else if (n_args == 1) { + ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0])); + } else if (n_args == 2) { + ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1])); + } else if (n_args == 3) { + ret = ((inline_asm_fun_3_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2])); + } else { + // compiler allows at most 4 arguments + assert(n_args == 4); + ret = ((inline_asm_fun_4_t)fun)( + convert_obj_for_inline_asm(args[0]), + convert_obj_for_inline_asm(args[1]), + convert_obj_for_inline_asm(args[2]), + convert_obj_for_inline_asm(args[3]) + ); + } + + return mp_convert_native_to_obj(ret, self->type_sig); +} + +STATIC const mp_obj_type_t mp_type_fun_asm = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_asm_call, + .unary_op = mp_generic_unary_op, +}; + +mp_obj_t mp_obj_new_fun_asm(size_t n_args, void *fun_data, mp_uint_t type_sig) { + mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t); + o->base.type = &mp_type_fun_asm; + o->n_args = n_args; + o->fun_data = fun_data; + o->type_sig = type_sig; + return o; +} + +#endif // MICROPY_EMIT_INLINE_ASM diff --git a/src/openmv/src/micropython/py/objfun.h b/src/openmv/src/micropython/py/objfun.h new file mode 100755 index 0000000..257b8a6 --- /dev/null +++ b/src/openmv/src/micropython/py/objfun.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJFUN_H +#define MICROPY_INCLUDED_PY_OBJFUN_H + +#include "py/obj.h" + +typedef struct _mp_obj_fun_bc_t { + mp_obj_base_t base; + mp_obj_dict_t *globals; // the context within which this function was defined + const byte *bytecode; // bytecode for the function + const mp_uint_t *const_table; // constant table + // the following extra_args array is allocated space to take (in order): + // - values of positional default args (if any) + // - a single slot for default kw args dict (if it has them) + // - a single slot for var args tuple (if it takes them) + // - a single slot for kw args dict (if it takes them) + mp_obj_t extra_args[]; +} mp_obj_fun_bc_t; + +void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); + +#endif // MICROPY_INCLUDED_PY_OBJFUN_H diff --git a/src/openmv/src/micropython/py/objgenerator.c b/src/openmv/src/micropython/py/objgenerator.c new file mode 100755 index 0000000..348d2d7 --- /dev/null +++ b/src/openmv/src/micropython/py/objgenerator.c @@ -0,0 +1,319 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/bc.h" +#include "py/objgenerator.h" +#include "py/objfun.h" +#include "py/stackctrl.h" + +/******************************************************************************/ +/* generator wrapper */ + +typedef struct _mp_obj_gen_instance_t { + mp_obj_base_t base; + mp_obj_dict_t *globals; + mp_code_state_t code_state; +} mp_obj_gen_instance_t; + +STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // A generating function is just a bytecode function with type mp_type_gen_wrap + mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in); + + // bytecode prelude: get state size and exception stack size + size_t n_state = mp_decode_uint_value(self_fun->bytecode); + size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode)); + + // allocate the generator object, with room for local stack and exception stack + mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, + n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); + o->base.type = &mp_type_gen_instance; + + o->globals = self_fun->globals; + o->code_state.fun_bc = self_fun; + o->code_state.ip = 0; + mp_setup_code_state(&o->code_state, n_args, n_kw, args); + return MP_OBJ_FROM_PTR(o); +} + +const mp_obj_type_t mp_type_gen_wrap = { + { &mp_type_type }, + .name = MP_QSTR_generator, + .call = gen_wrap_call, + .unary_op = mp_generic_unary_op, + #if MICROPY_PY_FUNCTION_ATTRS + .attr = mp_obj_fun_bc_attr, + #endif +}; + +/******************************************************************************/ +// native generator wrapper + +#if MICROPY_EMIT_NATIVE + +STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // The state for a native generating function is held in the same struct as a bytecode function + mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in); + + // Determine start of prelude, and extract n_state from it + uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0]; + size_t n_state = mp_decode_uint_value(self_fun->bytecode + prelude_offset); + size_t n_exc_stack = 0; + + // Allocate the generator object, with room for local stack and exception stack + mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, + n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); + o->base.type = &mp_type_gen_instance; + + // Parse the input arguments and set up the code state + o->globals = self_fun->globals; + o->code_state.fun_bc = self_fun; + o->code_state.ip = (const byte*)prelude_offset; + mp_setup_code_state(&o->code_state, n_args, n_kw, args); + + // Indicate we are a native function, which doesn't use this variable + o->code_state.exc_sp = NULL; + + // Prepare the generator instance for execution + uintptr_t start_offset = ((uintptr_t*)self_fun->bytecode)[1]; + o->code_state.ip = MICROPY_MAKE_POINTER_CALLABLE((void*)(self_fun->bytecode + start_offset)); + + return MP_OBJ_FROM_PTR(o); +} + +const mp_obj_type_t mp_type_native_gen_wrap = { + { &mp_type_type }, + .name = MP_QSTR_generator, + .call = native_gen_wrap_call, + .unary_op = mp_generic_unary_op, + #if MICROPY_PY_FUNCTION_ATTRS + .attr = mp_obj_fun_bc_attr, + #endif +}; + +#endif // MICROPY_EMIT_NATIVE + +/******************************************************************************/ +/* generator instance */ + +STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self); +} + +mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + MP_STACK_CHECK(); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (self->code_state.ip == 0) { + // Trying to resume already stopped generator + *ret_val = MP_OBJ_STOP_ITERATION; + return MP_VM_RETURN_NORMAL; + } + if (self->code_state.sp == self->code_state.state - 1) { + if (send_value != mp_const_none) { + mp_raise_TypeError("can't send non-None value to a just-started generator"); + } + } else { + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (*self->code_state.sp != mp_const_none) { + throw_value = *self->code_state.sp; + *self->code_state.sp = MP_OBJ_NULL; + } else + #endif + { + *self->code_state.sp = send_value; + } + } + + // We set self->globals=NULL while executing, for a sentinel to ensure the generator + // cannot be reentered during execution + if (self->globals == NULL) { + mp_raise_ValueError("generator already executing"); + } + + // Set up the correct globals context for the generator and execute it + self->code_state.old_globals = mp_globals_get(); + mp_globals_set(self->globals); + self->globals = NULL; + + mp_vm_return_kind_t ret_kind; + + #if MICROPY_EMIT_NATIVE + if (self->code_state.exc_sp == NULL) { + // A native generator, with entry point 2 words into the "bytecode" pointer + typedef uintptr_t (*mp_fun_native_gen_t)(void*, mp_obj_t); + mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void*)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t))); + ret_kind = fun((void*)&self->code_state, throw_value); + } else + #endif + { + // A bytecode generator + ret_kind = mp_execute_bytecode(&self->code_state, throw_value); + } + + self->globals = mp_globals_get(); + mp_globals_set(self->code_state.old_globals); + + switch (ret_kind) { + case MP_VM_RETURN_NORMAL: + default: + // Explicitly mark generator as completed. If we don't do this, + // subsequent next() may re-execute statements after last yield + // again and again, leading to side effects. + self->code_state.ip = 0; + *ret_val = *self->code_state.sp; + break; + + case MP_VM_RETURN_YIELD: + *ret_val = *self->code_state.sp; + #if MICROPY_PY_GENERATOR_PEND_THROW + *self->code_state.sp = mp_const_none; + #endif + break; + + case MP_VM_RETURN_EXCEPTION: { + self->code_state.ip = 0; + *ret_val = self->code_state.state[0]; + // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(*ret_val)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration"); + } + break; + } + } + + return ret_kind; +} + +STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) { + mp_obj_t ret; + switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) { + case MP_VM_RETURN_NORMAL: + default: + // Optimize return w/o value in case generator is used in for loop + if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) { + return MP_OBJ_STOP_ITERATION; + } else { + nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); + } + + case MP_VM_RETURN_YIELD: + return ret; + + case MP_VM_RETURN_EXCEPTION: + nlr_raise(ret); + } +} + +STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) { + return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL); +} + +STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { + mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL); + if (ret == MP_OBJ_STOP_ITERATION) { + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); + +STATIC mp_obj_t gen_instance_close(mp_obj_t self_in); +STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) { + mp_obj_t exc = (n_args == 2) ? args[1] : args[2]; + + mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); + if (ret == MP_OBJ_STOP_ITERATION) { + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw); + +STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { + mp_obj_t ret; + switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { + case MP_VM_RETURN_YIELD: + mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); + + // Swallow GeneratorExit (== successful close), and re-raise any other + case MP_VM_RETURN_EXCEPTION: + // ret should always be an instance of an exception class + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(ret)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { + return mp_const_none; + } + nlr_raise(ret); + + default: + // The only choice left is MP_VM_RETURN_NORMAL which is successful close + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); + +STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (self->code_state.sp == self->code_state.state - 1) { + mp_raise_TypeError("can't pend throw to just-started generator"); + } + mp_obj_t prev = *self->code_state.sp; + *self->code_state.sp = exc_in; + return prev; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); + +STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) }, + #if MICROPY_PY_GENERATOR_PEND_THROW + { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); + +const mp_obj_type_t mp_type_gen_instance = { + { &mp_type_type }, + .name = MP_QSTR_generator, + .print = gen_instance_print, + .unary_op = mp_generic_unary_op, + .getiter = mp_identity_getiter, + .iternext = gen_instance_iternext, + .locals_dict = (mp_obj_dict_t*)&gen_instance_locals_dict, +}; diff --git a/src/openmv/src/micropython/py/objgenerator.h b/src/openmv/src/micropython/py/objgenerator.h new file mode 100755 index 0000000..80bf9cd --- /dev/null +++ b/src/openmv/src/micropython/py/objgenerator.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJGENERATOR_H +#define MICROPY_INCLUDED_PY_OBJGENERATOR_H + +#include "py/obj.h" +#include "py/runtime.h" + +mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_val, mp_obj_t throw_val, mp_obj_t *ret_val); + +#endif // MICROPY_INCLUDED_PY_OBJGENERATOR_H diff --git a/src/openmv/src/micropython/py/objgetitemiter.c b/src/openmv/src/micropython/py/objgetitemiter.c new file mode 100755 index 0000000..ec41c2c --- /dev/null +++ b/src/openmv/src/micropython/py/objgetitemiter.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +// this is a wrapper object that turns something that has a __getitem__ method into an iterator + +typedef struct _mp_obj_getitem_iter_t { + mp_obj_base_t base; + mp_obj_t args[3]; +} mp_obj_getitem_iter_t; + +STATIC mp_obj_t it_iternext(mp_obj_t self_in) { + mp_obj_getitem_iter_t *self = MP_OBJ_TO_PTR(self_in); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // try to get next item + mp_obj_t value = mp_call_method_n_kw(1, 0, self->args); + self->args[2] = MP_OBJ_NEW_SMALL_INT(MP_OBJ_SMALL_INT_VALUE(self->args[2]) + 1); + nlr_pop(); + return value; + } else { + // an exception was raised + mp_obj_type_t *t = (mp_obj_type_t*)((mp_obj_base_t*)nlr.ret_val)->type; + if (t == &mp_type_StopIteration || t == &mp_type_IndexError) { + // return MP_OBJ_STOP_ITERATION instead of raising + return MP_OBJ_STOP_ITERATION; + } else { + // re-raise exception + nlr_jump(nlr.ret_val); + } + } +} + +STATIC const mp_obj_type_t it_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity_getiter, + .iternext = it_iternext, +}; + +// args are those returned from mp_load_method_maybe (ie either an attribute or a method) +mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_getitem_iter_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t*)iter_buf; + o->base.type = &it_type; + o->args[0] = args[0]; + o->args[1] = args[1]; + o->args[2] = MP_OBJ_NEW_SMALL_INT(0); + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objint.c b/src/openmv/src/micropython/py/objint.c new file mode 100755 index 0000000..cd8f20c --- /dev/null +++ b/src/openmv/src/micropython/py/objint.c @@ -0,0 +1,465 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/parsenum.h" +#include "py/smallint.h" +#include "py/objint.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/binary.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + +// This dispatcher function is expected to be independent of the implementation of long int +STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 2, false); + + switch (n_args) { + case 0: + return MP_OBJ_NEW_SMALL_INT(0); + + case 1: + if (MP_OBJ_IS_INT(args[0])) { + // already an int (small or long), just return it + return args[0]; + } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + // a string, parse it + size_t l; + const char *s = mp_obj_str_get_data(args[0], &l); + return mp_parse_num_integer(s, l, 0, NULL); +#if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(args[0])) { + return mp_obj_new_int_from_float(mp_obj_float_get(args[0])); +#endif + } else { + // try to convert to small int (eg from bool) + return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0])); + } + + case 2: + default: { + // should be a string, parse it + size_t l; + const char *s = mp_obj_str_get_data(args[0], &l); + return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL); + } + } +} + +#if MICROPY_PY_BUILTINS_FLOAT + +typedef enum { + MP_FP_CLASS_FIT_SMALLINT, + MP_FP_CLASS_FIT_LONGINT, + MP_FP_CLASS_OVERFLOW +} mp_fp_as_int_class_t; + +STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { + union { + mp_float_t f; +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + uint32_t i; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + uint32_t i[2]; +#endif + } u = {val}; + + uint32_t e; +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + e = u.i; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + e = u.i[MP_ENDIANNESS_LITTLE]; +#endif +#define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32) +#define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32) + + if (e & (1U << MP_FLOAT_SIGN_SHIFT_I32)) { +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + e |= u.i[MP_ENDIANNESS_BIG] != 0; +#endif + if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) { + // handle case of -0 (when sign is set but rest of bits are zero) + e = 0; + } else { + e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; + } + } else { + e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1); + } + // 8 * sizeof(uintptr_t) counts the number of bits for a small int + // TODO provide a way to configure this properly + if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) { + return MP_FP_CLASS_FIT_SMALLINT; + } +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + if (e <= (((sizeof(long long) * BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { + return MP_FP_CLASS_FIT_LONGINT; + } +#endif +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + return MP_FP_CLASS_FIT_LONGINT; +#else + return MP_FP_CLASS_OVERFLOW; +#endif +} +#undef MP_FLOAT_SIGN_SHIFT_I32 +#undef MP_FLOAT_EXP_SHIFT_I32 + +mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { + int cl = fpclassify(val); + if (cl == FP_INFINITE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); + } else if (cl == FP_NAN) { + mp_raise_ValueError("can't convert NaN to int"); + } else { + mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); + if (icl == MP_FP_CLASS_FIT_SMALLINT) { + return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + } else { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_float(&o->mpz, val); + return MP_OBJ_FROM_PTR(o); + } + #else + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + } else if (icl == MP_FP_CLASS_FIT_LONGINT) { + return mp_obj_new_int_from_ll((long long)val); + #endif + } else { + mp_raise_ValueError("float too big"); + } + #endif + } +} + +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef mp_longint_impl_t fmt_int_t; +typedef unsigned long long fmt_uint_t; +#else +typedef mp_int_t fmt_int_t; +typedef mp_uint_t fmt_uint_t; +#endif + +void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + // The size of this buffer is rather arbitrary. If it's not large + // enough, a dynamic one will be allocated. + char stack_buf[sizeof(fmt_int_t) * 4]; + char *buf = stack_buf; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size; + + char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0'); + mp_print_str(print, str); + + if (buf != stack_buf) { + m_del(char, buf, buf_size); + } +} + +STATIC const uint8_t log_base2_floor[] = { + 0, 1, 1, 2, + 2, 2, 2, 3, + 3, 3, 3, 3, + 3, 3, 3, 4, + /* if needed, these are the values for higher bases + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 5 + */ +}; + +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { + assert(2 <= base && base <= 16); + size_t num_digits = num_bits / log_base2_floor[base - 1] + 1; + size_t num_commas = comma ? num_digits / 3 : 0; + size_t prefix_len = prefix ? strlen(prefix) : 0; + return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte +} + +// This routine expects you to pass in a buffer and size (in *buf and *buf_size). +// If, for some reason, this buffer is too small, then it will allocate a +// buffer and return the allocated buffer and size in *buf and *buf_size. It +// is the callers responsibility to free this allocated buffer. +// +// The resulting formatted string will be returned from this function and the +// formatted size will be in *fmt_size. +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, + int base, const char *prefix, char base_char, char comma) { + fmt_int_t num; + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + // Only have small ints; get the integer value to format. + num = MP_OBJ_SMALL_INT_VALUE(self_in); + #else + if (MP_OBJ_IS_SMALL_INT(self_in)) { + // A small int; get the integer value to format. + num = MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + // Not a small int. + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + const mp_obj_int_t *self = self_in; + // Get the value to format; mp_obj_get_int truncates to mp_int_t. + num = self->val; + #else + // Delegate to the implementation for the long int. + return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma); + #endif + } + #endif + + char sign = '\0'; + if (num < 0) { + num = -num; + sign = '-'; + } + + size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); + if (needed_size > *buf_size) { + *buf = m_new(char, needed_size); + *buf_size = needed_size; + } + char *str = *buf; + + char *b = str + needed_size; + *(--b) = '\0'; + char *last_comma = b; + + if (num == 0) { + *(--b) = '0'; + } else { + do { + // The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic + int c = (fmt_uint_t)num % base; + num = (fmt_uint_t)num / base; + if (c >= 10) { + c += base_char - 10; + } else { + c += '0'; + } + *(--b) = c; + if (comma && num != 0 && b > str && (last_comma - b) == 3) { + *(--b) = comma; + last_comma = b; + } + } + while (b > str && num != 0); + } + if (prefix) { + size_t prefix_len = strlen(prefix); + char *p = b - prefix_len; + if (p > str) { + b = p; + while (*prefix) { + *p++ = *prefix++; + } + } + } + if (sign && b > str) { + *(--b) = sign; + } + *fmt_size = *buf + needed_size - b - 1; + + return b; +} + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + +int mp_obj_int_sign(mp_obj_t self_in) { + mp_int_t val = mp_obj_get_int(self_in); + if (val < 0) { + return -1; + } else if (val > 0) { + return 1; + } else { + return 0; + } +} + +// This is called for operations on SMALL_INT that are not handled by mp_unary_op +mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + return MP_OBJ_NULL; // op not supported +} + +// This is called for operations on SMALL_INT that are not handled by mp_binary_op +mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); +} + +// This is called only with strings whose value doesn't fit in SMALL_INT +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { + mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); + return mp_const_none; +} + +// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) +mp_obj_t mp_obj_new_int_from_ll(long long val) { + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); + return mp_const_none; +} + +// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) +mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); + return mp_const_none; +} + +mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { + // SMALL_INT accepts only signed numbers, so make sure the input + // value fits completely in the small-int positive range. + if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); + return mp_const_none; +} + +mp_obj_t mp_obj_new_int(mp_int_t value) { + if (MP_SMALL_INT_FITS(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); + return mp_const_none; +} + +mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { + return MP_OBJ_SMALL_INT_VALUE(self_in); +} + +mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { + return MP_OBJ_SMALL_INT_VALUE(self_in); +} + +#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + +// This dispatcher function is expected to be independent of the implementation of long int +// It handles the extra cases for integer-like arithmetic +mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (rhs_in == mp_const_false) { + // false acts as 0 + return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0)); + } else if (rhs_in == mp_const_true) { + // true acts as 0 + return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); + } else if (op == MP_BINARY_OP_MULTIPLY) { + if (MP_OBJ_IS_STR_OR_BYTES(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { + // multiply is commutative for these types, so delegate to them + return mp_binary_op(op, rhs_in, lhs_in); + } + } + return MP_OBJ_NULL; // op not supported +} + +// this is a classmethod +STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { + // TODO: Support signed param (assumes signed=False at the moment) + (void)n_args; + + // get the buffer info + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + const byte* buf = (const byte*)bufinfo.buf; + int delta = 1; + if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) { + buf += bufinfo.len - 1; + delta = -1; + } + + mp_uint_t value = 0; + size_t len = bufinfo.len; + for (; len--; buf += delta) { + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if (value > (MP_SMALL_INT_MAX >> 8)) { + // Result will overflow a small-int so construct a big-int + return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); + } + #endif + value = (value << 8) | *buf; + } + return mp_obj_new_int_from_uint(value); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj)); + +STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) { + // TODO: Support signed param (assumes signed=False) + (void)n_args; + + mp_int_t len = mp_obj_get_int(args[1]); + if (len < 0) { + mp_raise_ValueError(NULL); + } + bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little); + + vstr_t vstr; + vstr_init_len(&vstr, len); + byte *data = (byte*)vstr.buf; + memset(data, 0, len); + + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if (!MP_OBJ_IS_SMALL_INT(args[0])) { + mp_obj_int_to_bytes_impl(args[0], big_endian, len, data); + } else + #endif + { + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]); + size_t l = MIN((size_t)len, sizeof(val)); + mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val); + } + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 3, 4, int_to_bytes); + +STATIC const mp_rom_map_elem_t int_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_to_bytes), MP_ROM_PTR(&int_to_bytes_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table); + +const mp_obj_type_t mp_type_int = { + { &mp_type_type }, + .name = MP_QSTR_int, + .print = mp_obj_int_print, + .make_new = mp_obj_int_make_new, + .unary_op = mp_obj_int_unary_op, + .binary_op = mp_obj_int_binary_op, + .locals_dict = (mp_obj_dict_t*)&int_locals_dict, +}; diff --git a/src/openmv/src/micropython/py/objint.h b/src/openmv/src/micropython/py/objint.h new file mode 100755 index 0000000..4b95acd --- /dev/null +++ b/src/openmv/src/micropython/py/objint.h @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJINT_H +#define MICROPY_INCLUDED_PY_OBJINT_H + +#include "py/mpz.h" +#include "py/obj.h" + +typedef struct _mp_obj_int_t { + mp_obj_base_t base; +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + mp_longint_impl_t val; +#elif MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + mpz_t mpz; +#endif +} mp_obj_int_t; + +extern const mp_obj_int_t mp_maxsize_obj; + +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in); +#endif + +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); + +mp_obj_int_t *mp_obj_int_new_mpz(void); + +void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, + int base, const char *prefix, char base_char, char comma); +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, + int base, const char *prefix, char base_char, char comma); +mp_int_t mp_obj_int_hash(mp_obj_t self_in); +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); +int mp_obj_int_sign(mp_obj_t self_in); +mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in); +mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); +mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); +mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus); + +#endif // MICROPY_INCLUDED_PY_OBJINT_H diff --git a/src/openmv/src/micropython/py/objint_longlong.c b/src/openmv/src/micropython/py/objint_longlong.c new file mode 100755 index 0000000..485803c --- /dev/null +++ b/src/openmv/src/micropython/py/objint_longlong.c @@ -0,0 +1,290 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/smallint.h" +#include "py/objint.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + +#if MICROPY_PY_SYS_MAXSIZE +// Export value for sys.maxsize +const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; +#endif + +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { + int delta = 1; + if (!big_endian) { + buf += len - 1; + delta = -1; + } + + mp_longint_impl_t value = 0; + for (; len--; buf += delta) { + value = (value << 8) | *buf; + } + return mp_obj_new_int_from_ll(value); +} + +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; + long long val = self->val; + if (big_endian) { + byte *b = buf + len; + while (b > buf) { + *--b = val; + val >>= 8; + } + } else { + for (; len > 0; --len) { + *buf++ = val; + val >>= 8; + } + } +} + +int mp_obj_int_sign(mp_obj_t self_in) { + mp_longint_impl_t val; + if (MP_OBJ_IS_SMALL_INT(self_in)) { + val = MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + mp_obj_int_t *self = self_in; + val = self->val; + } + if (val < 0) { + return -1; + } else if (val > 0) { + return 1; + } else { + return 0; + } +} + +mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_obj_int_t *o = o_in; + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->val != 0); + + // truncate value to fit in mp_int_t, which gives the same hash as + // small int if the value fits without truncation + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); + + case MP_UNARY_OP_POSITIVE: return o_in; + case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val); + case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val); + case MP_UNARY_OP_ABS: { + mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in); + if (self->val >= 0) { + return o_in; + } + self = mp_obj_new_int_from_ll(self->val); + // TODO could overflow long long + self->val = -self->val; + return MP_OBJ_FROM_PTR(self); + } + default: return MP_OBJ_NULL; // op not supported + } +} + +mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + long long lhs_val; + long long rhs_val; + + if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); + } else { + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + lhs_val = ((mp_obj_int_t*)lhs_in)->val; + } + + if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); + } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + rhs_val = ((mp_obj_int_t*)rhs_in)->val; + } else { + // delegate to generic function to check for extra cases + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); + } + + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: + return mp_obj_new_int_from_ll(lhs_val + rhs_val); + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: + return mp_obj_new_int_from_ll(lhs_val - rhs_val); + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: + return mp_obj_new_int_from_ll(lhs_val * rhs_val); + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_int_from_ll(lhs_val / rhs_val); + case MP_BINARY_OP_MODULO: + case MP_BINARY_OP_INPLACE_MODULO: + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_int_from_ll(lhs_val % rhs_val); + + case MP_BINARY_OP_AND: + case MP_BINARY_OP_INPLACE_AND: + return mp_obj_new_int_from_ll(lhs_val & rhs_val); + case MP_BINARY_OP_OR: + case MP_BINARY_OP_INPLACE_OR: + return mp_obj_new_int_from_ll(lhs_val | rhs_val); + case MP_BINARY_OP_XOR: + case MP_BINARY_OP_INPLACE_XOR: + return mp_obj_new_int_from_ll(lhs_val ^ rhs_val); + + case MP_BINARY_OP_LSHIFT: + case MP_BINARY_OP_INPLACE_LSHIFT: + return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); + case MP_BINARY_OP_RSHIFT: + case MP_BINARY_OP_INPLACE_RSHIFT: + return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); + + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: { + if (rhs_val < 0) { + #if MICROPY_PY_BUILTINS_FLOAT + return mp_obj_float_binary_op(op, lhs_val, rhs_in); + #else + mp_raise_ValueError("negative power with no float support"); + #endif + } + long long ans = 1; + while (rhs_val > 0) { + if (rhs_val & 1) { + ans *= lhs_val; + } + if (rhs_val == 1) { + break; + } + rhs_val /= 2; + lhs_val *= lhs_val; + } + return mp_obj_new_int_from_ll(ans); + } + + case MP_BINARY_OP_LESS: + return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: + return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: + return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: + return mp_obj_new_bool(lhs_val >= rhs_val); + case MP_BINARY_OP_EQUAL: + return mp_obj_new_bool(lhs_val == rhs_val); + + default: + return MP_OBJ_NULL; // op not supported + } + +zero_division: + mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); +} + +mp_obj_t mp_obj_new_int(mp_int_t value) { + if (MP_SMALL_INT_FITS(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ll(value); +} + +mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { + // SMALL_INT accepts only signed numbers, so make sure the input + // value fits completely in the small-int positive range. + if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ll(value); +} + +mp_obj_t mp_obj_new_int_from_ll(long long val) { + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + o->val = val; + return o; +} + +mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { + // TODO raise an exception if the unsigned long long won't fit + if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { + mp_raise_msg(&mp_type_OverflowError, "ulonglong too large"); + } + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + o->val = val; + return o; +} + +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { + // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated + // TODO check overflow + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + char *endptr; + o->val = strtoll(*str, &endptr, base); + *str = endptr; + return o; +} + +mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { + if (MP_OBJ_IS_SMALL_INT(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = self_in; + return self->val; + } +} + +mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { + // TODO: Check overflow + return mp_obj_int_get_truncated(self_in); +} + +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; + return self->val; +} +#endif + +#endif diff --git a/src/openmv/src/micropython/py/objint_mpz.c b/src/openmv/src/micropython/py/objint_mpz.c new file mode 100755 index 0000000..e59c123 --- /dev/null +++ b/src/openmv/src/micropython/py/objint_mpz.c @@ -0,0 +1,422 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/parsenumbase.h" +#include "py/smallint.h" +#include "py/objint.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + +#if MICROPY_PY_SYS_MAXSIZE +// Export value for sys.maxsize +#define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1) +STATIC const mpz_dig_t maxsize_dig[] = { + #define NUM_DIG 1 + (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK, + #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 0) > DIG_MASK + #undef NUM_DIG + #define NUM_DIG 2 + (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK, + #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 1) > DIG_MASK + #undef NUM_DIG + #define NUM_DIG 3 + (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK, + #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK + #undef NUM_DIG + #define NUM_DIG 4 + (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK, + #if (MP_SSIZE_MAX >> MPZ_DIG_SIZE * 3) > DIG_MASK + #error cannot encode MP_SSIZE_MAX as mpz + #endif + #endif + #endif + #endif +}; +const mp_obj_int_t mp_maxsize_obj = { + {&mp_type_int}, + {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t*)maxsize_dig} +}; +#undef DIG_MASK +#undef NUM_DIG +#endif + +mp_obj_int_t *mp_obj_int_new_mpz(void) { + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + mpz_init_zero(&o->mpz); + return o; +} + +// This routine expects you to pass in a buffer and size (in *buf and buf_size). +// If, for some reason, this buffer is too small, then it will allocate a +// buffer and return the allocated buffer and size in *buf and *buf_size. It +// is the callers responsibility to free this allocated buffer. +// +// The resulting formatted string will be returned from this function and the +// formatted size will be in *fmt_size. +// +// This particular routine should only be called for the mpz representation of the int. +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, + int base, const char *prefix, char base_char, char comma) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + + size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); + if (needed_size > *buf_size) { + *buf = m_new(char, needed_size); + *buf_size = needed_size; + } + char *str = *buf; + + *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str); + + return str; +} + +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_bytes(&o->mpz, big_endian, len, buf); + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + memset(buf, 0, len); + mpz_as_bytes(&self->mpz, big_endian, len, buf); +} + +int mp_obj_int_sign(mp_obj_t self_in) { + if (MP_OBJ_IS_SMALL_INT(self_in)) { + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self_in); + if (val < 0) { + return -1; + } else if (val > 0) { + return 1; + } else { + return 0; + } + } + mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + if (self->mpz.len == 0) { + return 0; + } else if (self->mpz.neg == 0) { + return 1; + } else { + return -1; + } +} + +mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_obj_int_t *o = MP_OBJ_TO_PTR(o_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(!mpz_is_zero(&o->mpz)); + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz)); + case MP_UNARY_OP_POSITIVE: return o_in; + case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); } + case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); } + case MP_UNARY_OP_ABS: { + mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in); + if (self->mpz.neg == 0) { + return o_in; + } + mp_obj_int_t *self2 = mp_obj_int_new_mpz(); + mpz_abs_inpl(&self2->mpz, &self->mpz); + return MP_OBJ_FROM_PTR(self2); + } + default: return MP_OBJ_NULL; // op not supported + } +} + +mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + const mpz_t *zlhs; + const mpz_t *zrhs; + mpz_t z_int; + mpz_dig_t z_int_dig[MPZ_NUM_DIG_FOR_INT]; + + // lhs could be a small int (eg small-int + mpz) + if (MP_OBJ_IS_SMALL_INT(lhs_in)) { + mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); + zlhs = &z_int; + } else { + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; + } + + // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) + if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in)); + zrhs = &z_int; + } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { + zrhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(rhs_in))->mpz; +#if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(rhs_in)) { + return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); +#if MICROPY_PY_BUILTINS_COMPLEX + } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { + return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); +#endif +#endif + } else { + // delegate to generic function to check for extra cases + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); + } + + if (0) { +#if MICROPY_PY_BUILTINS_FLOAT + } else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { + if (mpz_is_zero(zrhs)) { + goto zero_division_error; + } + mp_float_t flhs = mpz_as_float(zlhs); + mp_float_t frhs = mpz_as_float(zrhs); + return mp_obj_new_float(flhs / frhs); +#endif + + } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { + mp_obj_int_t *res = mp_obj_int_new_mpz(); + + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: + mpz_add_inpl(&res->mpz, zlhs, zrhs); + break; + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: + mpz_sub_inpl(&res->mpz, zlhs, zrhs); + break; + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: + mpz_mul_inpl(&res->mpz, zlhs, zrhs); + break; + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { + if (mpz_is_zero(zrhs)) { + zero_division_error: + mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); + } + mpz_t rem; mpz_init_zero(&rem); + mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); + mpz_deinit(&rem); + break; + } + case MP_BINARY_OP_MODULO: + case MP_BINARY_OP_INPLACE_MODULO: { + if (mpz_is_zero(zrhs)) { + goto zero_division_error; + } + mpz_t quo; mpz_init_zero(&quo); + mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); + mpz_deinit(&quo); + break; + } + + case MP_BINARY_OP_AND: + case MP_BINARY_OP_INPLACE_AND: + mpz_and_inpl(&res->mpz, zlhs, zrhs); + break; + case MP_BINARY_OP_OR: + case MP_BINARY_OP_INPLACE_OR: + mpz_or_inpl(&res->mpz, zlhs, zrhs); + break; + case MP_BINARY_OP_XOR: + case MP_BINARY_OP_INPLACE_XOR: + mpz_xor_inpl(&res->mpz, zlhs, zrhs); + break; + + case MP_BINARY_OP_LSHIFT: + case MP_BINARY_OP_INPLACE_LSHIFT: + case MP_BINARY_OP_RSHIFT: + case MP_BINARY_OP_INPLACE_RSHIFT: { + mp_int_t irhs = mp_obj_int_get_checked(rhs_in); + if (irhs < 0) { + mp_raise_ValueError("negative shift count"); + } + if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { + mpz_shl_inpl(&res->mpz, zlhs, irhs); + } else { + mpz_shr_inpl(&res->mpz, zlhs, irhs); + } + break; + } + + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: + if (mpz_is_neg(zrhs)) { + #if MICROPY_PY_BUILTINS_FLOAT + return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); + #else + mp_raise_ValueError("negative power with no float support"); + #endif + } + mpz_pow_inpl(&res->mpz, zlhs, zrhs); + break; + + default: { + assert(op == MP_BINARY_OP_DIVMOD); + if (mpz_is_zero(zrhs)) { + goto zero_division_error; + } + mp_obj_int_t *quo = mp_obj_int_new_mpz(); + mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs); + mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; + return mp_obj_new_tuple(2, tuple); + } + } + + return MP_OBJ_FROM_PTR(res); + + } else { + int cmp = mpz_cmp(zlhs, zrhs); + switch (op) { + case MP_BINARY_OP_LESS: + return mp_obj_new_bool(cmp < 0); + case MP_BINARY_OP_MORE: + return mp_obj_new_bool(cmp > 0); + case MP_BINARY_OP_LESS_EQUAL: + return mp_obj_new_bool(cmp <= 0); + case MP_BINARY_OP_MORE_EQUAL: + return mp_obj_new_bool(cmp >= 0); + case MP_BINARY_OP_EQUAL: + return mp_obj_new_bool(cmp == 0); + + default: + return MP_OBJ_NULL; // op not supported + } + } +} + +#if MICROPY_PY_BUILTINS_POW3 +STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { + if (MP_OBJ_IS_SMALL_INT(arg)) { + mpz_init_from_int(temp, MP_OBJ_SMALL_INT_VALUE(arg)); + return temp; + } else { + mp_obj_int_t *arp_p = MP_OBJ_TO_PTR(arg); + return &(arp_p->mpz); + } +} + +mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { + if (!MP_OBJ_IS_INT(base) || !MP_OBJ_IS_INT(exponent) || !MP_OBJ_IS_INT(modulus)) { + mp_raise_TypeError("pow() with 3 arguments requires integers"); + } else { + mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int + mp_obj_int_t *res_p = (mp_obj_int_t *) MP_OBJ_TO_PTR(result); + + mpz_t l_temp, r_temp, m_temp; + mpz_t *lhs = mp_mpz_for_int(base, &l_temp); + mpz_t *rhs = mp_mpz_for_int(exponent, &r_temp); + mpz_t *mod = mp_mpz_for_int(modulus, &m_temp); + + mpz_pow3_inpl(&(res_p->mpz), lhs, rhs, mod); + + if (lhs == &l_temp) { mpz_deinit(lhs); } + if (rhs == &r_temp) { mpz_deinit(rhs); } + if (mod == &m_temp) { mpz_deinit(mod); } + return result; + } +} +#endif + +mp_obj_t mp_obj_new_int(mp_int_t value) { + if (MP_SMALL_INT_FITS(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ll(value); +} + +mp_obj_t mp_obj_new_int_from_ll(long long val) { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_ll(&o->mpz, val, true); + return MP_OBJ_FROM_PTR(o); +} + +mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_ll(&o->mpz, val, false); + return MP_OBJ_FROM_PTR(o); +} + +mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { + // SMALL_INT accepts only signed numbers, so make sure the input + // value fits completely in the small-int positive range. + if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ull(value); +} + +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); + *str += n; + return MP_OBJ_FROM_PTR(o); +} + +mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { + if (MP_OBJ_IS_SMALL_INT(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + // hash returns actual int value if it fits in mp_int_t + return mpz_hash(&self->mpz); + } +} + +mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { + if (MP_OBJ_IS_SMALL_INT(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t value; + if (mpz_as_int_checked(&self->mpz, &value)) { + return value; + } else { + // overflow + mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); + } + } +} + +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); + return mpz_as_float(&self->mpz); +} +#endif + +#endif diff --git a/src/openmv/src/micropython/py/objlist.c b/src/openmv/src/micropython/py/objlist.c new file mode 100755 index 0000000..1a18f93 --- /dev/null +++ b/src/openmv/src/micropython/py/objlist.c @@ -0,0 +1,529 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stackctrl.h" + +STATIC mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf); +STATIC mp_obj_list_t *list_new(size_t n); +STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in); +STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args); + +// TODO: Move to mpconfig.h +#define LIST_MIN_ALLOC 4 + +/******************************************************************************/ +/* list */ + +STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + mp_obj_list_t *o = MP_OBJ_TO_PTR(o_in); + if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { + kind = PRINT_REPR; + } + mp_print_str(print, "["); + for (size_t i = 0; i < o->len; i++) { + if (i > 0) { + mp_print_str(print, ", "); + } + mp_obj_print_helper(print, o->items[i], kind); + } + mp_print_str(print, "]"); +} + +STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { + mp_obj_t iter = mp_getiter(iterable, NULL); + mp_obj_t item; + while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_obj_list_append(list, item); + } + return list; +} + +STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + switch (n_args) { + case 0: + // return a new, empty list + return mp_obj_new_list(0, NULL); + + case 1: + default: { + // make list from iterable + // TODO: optimize list/tuple + mp_obj_t list = mp_obj_new_list(0, NULL); + return list_extend_from_iter(list, args[0]); + } + } +} + +STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { + mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs); + switch (op) { + case MP_BINARY_OP_ADD: { + if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + return MP_OBJ_NULL; // op not supported + } + mp_obj_list_t *p = MP_OBJ_TO_PTR(rhs); + mp_obj_list_t *s = list_new(o->len + p->len); + mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); + return MP_OBJ_FROM_PTR(s); + } + case MP_BINARY_OP_INPLACE_ADD: { + list_extend(lhs, rhs); + return lhs; + } + case MP_BINARY_OP_MULTIPLY: { + mp_int_t n; + if (!mp_obj_get_int_maybe(rhs, &n)) { + return MP_OBJ_NULL; // op not supported + } + if (n < 0) { + n = 0; + } + mp_obj_list_t *s = list_new(o->len * n); + mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); + return MP_OBJ_FROM_PTR(s); + } + case MP_BINARY_OP_EQUAL: + case MP_BINARY_OP_LESS: + case MP_BINARY_OP_LESS_EQUAL: + case MP_BINARY_OP_MORE: + case MP_BINARY_OP_MORE_EQUAL: { + if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) { + if (op == MP_BINARY_OP_EQUAL) { + return mp_const_false; + } + return MP_OBJ_NULL; // op not supported + } + + mp_obj_list_t *another = MP_OBJ_TO_PTR(rhs); + bool res = mp_seq_cmp_objs(op, o->items, o->len, another->items, another->len); + return mp_obj_new_bool(res); + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { + mp_raise_NotImplementedError(NULL); + } + + mp_int_t len_adj = slice.start - slice.stop; + //printf("Len adj: %d\n", len_adj); + assert(len_adj <= 0); + mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, sizeof(*self->items)); + // Clear "freed" elements at the end of list + mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); + self->len += len_adj; + return mp_const_none; + } +#endif + mp_obj_t args[2] = {self_in, index}; + list_pop(2, args); + return mp_const_none; + } else if (value == MP_OBJ_SENTINEL) { + // load + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { + return mp_seq_extract_slice(self->len, self->items, &slice); + } + mp_obj_list_t *res = list_new(slice.stop - slice.start); + mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); + return MP_OBJ_FROM_PTR(res); + } +#endif + size_t index_val = mp_get_index(self->base.type, self->len, index, false); + return self->items[index_val]; + } else { +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + size_t value_len; mp_obj_t *value_items; + mp_obj_get_array(value, &value_len, &value_items); + mp_bound_slice_t slice_out; + if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { + mp_raise_NotImplementedError(NULL); + } + mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); + //printf("Len adj: %d\n", len_adj); + if (len_adj > 0) { + if (self->len + len_adj > self->alloc) { + // TODO: Might optimize memory copies here by checking if block can + // be grown inplace or not + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); + self->alloc = self->len + len_adj; + } + mp_seq_replace_slice_grow_inplace(self->items, self->len, + slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items)); + } else { + mp_seq_replace_slice_no_grow(self->items, self->len, + slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items)); + // Clear "freed" elements at the end of list + mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); + // TODO: apply allocation policy re: alloc_size + } + self->len += len_adj; + return mp_const_none; + } +#endif + mp_obj_list_store(self_in, index, value); + return mp_const_none; + } +} + +STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + return mp_obj_new_list_iterator(o_in, 0, iter_buf); +} + +mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + if (self->len >= self->alloc) { + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); + self->alloc *= 2; + mp_seq_clear(self->items, self->len + 1, self->alloc, sizeof(*self->items)); + } + self->items[self->len++] = arg; + return mp_const_none; // return None, as per CPython +} + +STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in); + + if (self->len + arg->len > self->alloc) { + // TODO: use alloc policy for "4" + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + arg->len + 4); + self->alloc = self->len + arg->len + 4; + mp_seq_clear(self->items, self->len + arg->len, self->alloc, sizeof(*self->items)); + } + + memcpy(self->items + self->len, arg->items, sizeof(mp_obj_t) * arg->len); + self->len += arg->len; + } else { + list_extend_from_iter(self_in, arg_in); + } + return mp_const_none; // return None, as per CPython +} + +STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); + if (self->len == 0) { + mp_raise_msg(&mp_type_IndexError, "pop from empty list"); + } + size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); + mp_obj_t ret = self->items[index]; + self->len -= 1; + memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); + // Clear stale pointer from slot which just got freed to prevent GC issues + self->items[self->len] = MP_OBJ_NULL; + if (self->alloc > LIST_MIN_ALLOC && self->alloc > 2 * self->len) { + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc/2); + self->alloc /= 2; + } + return ret; +} + +STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { + MP_STACK_CHECK(); + while (head < tail) { + mp_obj_t *h = head - 1; + mp_obj_t *t = tail; + mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn + for (;;) { + do ++h; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result); + do --t; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result); + if (h >= t) break; + mp_obj_t x = h[0]; + h[0] = t[0]; + t[0] = x; + } + mp_obj_t x = h[0]; + h[0] = tail[0]; + tail[0] = x; + // do the smaller recursive call first, to keep stack within O(log(N)) + if (t - head < tail - h - 1) { + mp_quicksort(head, t, key_fn, binop_less_result); + head = h + 1; + } else { + mp_quicksort(h + 1, tail, key_fn, binop_less_result); + tail = t; + } + } +} + +// TODO Python defines sort to be stable but ours is not +mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + struct { + mp_arg_val_t key, reverse; + } args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + if (self->len > 1) { + mp_quicksort(self->items, self->items + self->len - 1, + args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj, + args.reverse.u_bool ? mp_const_false : mp_const_true); + } + + return mp_const_none; +} + +STATIC mp_obj_t list_clear(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + self->len = 0; + self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); + self->alloc = LIST_MIN_ALLOC; + mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); + return mp_const_none; +} + +STATIC mp_obj_t list_copy(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_list(self->len, self->items); +} + +STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + return mp_seq_count_obj(self->items, self->len, value); +} + +STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); + return mp_seq_index_obj(self->items, self->len, n_args, args); +} + +STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + // insert has its own strange index logic + mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); + if (index < 0) { + index += self->len; + } + if (index < 0) { + index = 0; + } + if ((size_t)index > self->len) { + index = self->len; + } + + mp_obj_list_append(self_in, mp_const_none); + + for (mp_int_t i = self->len-1; i > index; i--) { + self->items[i] = self->items[i-1]; + } + self->items[index] = obj; + + return mp_const_none; +} + +mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_t args[] = {self_in, value}; + args[1] = list_index(2, args); + list_pop(2, args); + + return mp_const_none; +} + +STATIC mp_obj_t list_reverse(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + + mp_int_t len = self->len; + for (mp_int_t i = 0; i < len/2; i++) { + mp_obj_t a = self->items[i]; + self->items[i] = self->items[len-i-1]; + self->items[len-i-1] = a; + } + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(list_insert_obj, list_insert); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_pop_obj, 1, 2, list_pop); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, mp_obj_list_remove); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 1, mp_obj_list_sort); + +STATIC const mp_rom_map_elem_t list_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&list_append_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&list_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&list_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&list_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_extend), MP_ROM_PTR(&list_extend_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&list_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&list_insert_obj) }, + { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&list_pop_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&list_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_reverse), MP_ROM_PTR(&list_reverse_obj) }, + { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&list_sort_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(list_locals_dict, list_locals_dict_table); + +const mp_obj_type_t mp_type_list = { + { &mp_type_type }, + .name = MP_QSTR_list, + .print = list_print, + .make_new = list_make_new, + .unary_op = list_unary_op, + .binary_op = list_binary_op, + .subscr = list_subscr, + .getiter = list_getiter, + .locals_dict = (mp_obj_dict_t*)&list_locals_dict, +}; + +void mp_obj_list_init(mp_obj_list_t *o, size_t n) { + o->base.type = &mp_type_list; + o->alloc = n < LIST_MIN_ALLOC ? LIST_MIN_ALLOC : n; + o->len = n; + o->items = m_new(mp_obj_t, o->alloc); + mp_seq_clear(o->items, n, o->alloc, sizeof(*o->items)); +} + +STATIC mp_obj_list_t *list_new(size_t n) { + mp_obj_list_t *o = m_new_obj(mp_obj_list_t); + mp_obj_list_init(o, n); + return o; +} + +mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { + mp_obj_list_t *o = list_new(n); + if (items != NULL) { + for (size_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + } + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + *len = self->len; + *items = self->items; +} + +void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { + // trust that the caller knows what it's doing + // TODO realloc if len got much smaller than alloc + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + self->len = len; +} + +void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); + size_t i = mp_get_index(self->base.type, self->len, index, false); + self->items[i] = value; +} + +/******************************************************************************/ +/* list iterator */ + +typedef struct _mp_obj_list_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t list; + size_t cur; +} mp_obj_list_it_t; + +STATIC mp_obj_t list_it_iternext(mp_obj_t self_in) { + mp_obj_list_it_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); + if (self->cur < list->len) { + mp_obj_t o_out = list->items[self->cur]; + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_list_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_list_it_t *o = (mp_obj_list_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = list_it_iternext; + o->list = list; + o->cur = cur; + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objlist.h b/src/openmv/src/micropython/py/objlist.h new file mode 100755 index 0000000..a43663d --- /dev/null +++ b/src/openmv/src/micropython/py/objlist.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJLIST_H +#define MICROPY_INCLUDED_PY_OBJLIST_H + +#include "py/obj.h" + +typedef struct _mp_obj_list_t { + mp_obj_base_t base; + size_t alloc; + size_t len; + mp_obj_t *items; +} mp_obj_list_t; + +void mp_obj_list_init(mp_obj_list_t *o, size_t n); + +#endif // MICROPY_INCLUDED_PY_OBJLIST_H diff --git a/src/openmv/src/micropython/py/objmap.c b/src/openmv/src/micropython/py/objmap.c new file mode 100755 index 0000000..908c615 --- /dev/null +++ b/src/openmv/src/micropython/py/objmap.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +typedef struct _mp_obj_map_t { + mp_obj_base_t base; + size_t n_iters; + mp_obj_t fun; + mp_obj_t iters[]; +} mp_obj_map_t; + +STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, MP_OBJ_FUN_ARGS_MAX, false); + mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1); + o->base.type = type; + o->n_iters = n_args - 1; + o->fun = args[0]; + for (size_t i = 0; i < n_args - 1; i++) { + o->iters[i] = mp_getiter(args[i + 1], NULL); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t map_iternext(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); + mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); + + for (size_t i = 0; i < self->n_iters; i++) { + mp_obj_t next = mp_iternext(self->iters[i]); + if (next == MP_OBJ_STOP_ITERATION) { + m_del(mp_obj_t, nextses, self->n_iters); + return MP_OBJ_STOP_ITERATION; + } + nextses[i] = next; + } + return mp_call_function_n_kw(self->fun, self->n_iters, 0, nextses); +} + +const mp_obj_type_t mp_type_map = { + { &mp_type_type }, + .name = MP_QSTR_map, + .make_new = map_make_new, + .getiter = mp_identity_getiter, + .iternext = map_iternext, +}; diff --git a/src/openmv/src/micropython/py/objmodule.c b/src/openmv/src/micropython/py/objmodule.c new file mode 100755 index 0000000..3a00b7d --- /dev/null +++ b/src/openmv/src/micropython/py/objmodule.c @@ -0,0 +1,279 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objmodule.h" +#include "py/runtime.h" +#include "py/builtin.h" + +STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); + + const char *module_name = ""; + mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_MAP_LOOKUP); + if (elem != NULL) { + module_name = mp_obj_str_get_str(elem->value); + } + +#if MICROPY_PY___FILE__ + // If we store __file__ to imported modules then try to lookup this + // symbol to give more information about the module. + elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); + if (elem != NULL) { + mp_printf(print, "", module_name, mp_obj_str_get_str(elem->value)); + return; + } +#endif + + mp_printf(print, "", module_name); +} + +STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem != NULL) { + dest[0] = elem->value; + #if MICROPY_MODULE_GETATTR + } else if (attr != MP_QSTR___getattr__) { + elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP); + if (elem != NULL) { + dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr)); + } + #endif + } + } else { + // delete/store attribute + mp_obj_dict_t *dict = self->globals; + if (dict->map.is_fixed) { + #if MICROPY_CAN_OVERRIDE_BUILTINS + if (dict == &mp_module_builtins_globals) { + if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) { + MP_STATE_VM(mp_module_builtins_override_dict) = MP_OBJ_TO_PTR(mp_obj_new_dict(1)); + } + dict = MP_STATE_VM(mp_module_builtins_override_dict); + } else + #endif + { + // can't delete or store to fixed map + return; + } + } + if (dest[1] == MP_OBJ_NULL) { + // delete attribute + mp_obj_dict_delete(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr)); + } else { + // store attribute + mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(attr), dest[1]); + } + dest[0] = MP_OBJ_NULL; // indicate success + } +} + +const mp_obj_type_t mp_type_module = { + { &mp_type_type }, + .name = MP_QSTR_module, + .print = module_print, + .attr = module_attr, +}; + +mp_obj_t mp_obj_new_module(qstr module_name) { + mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; + mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + // We could error out if module already exists, but let C extensions + // add new members to existing modules. + if (el->value != MP_OBJ_NULL) { + return el->value; + } + + // create new module object + mp_obj_module_t *o = m_new_obj(mp_obj_module_t); + o->base.type = &mp_type_module; + o->globals = MP_OBJ_TO_PTR(mp_obj_new_dict(MICROPY_MODULE_DICT_SIZE)); + + // store __name__ entry in the module + mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(module_name)); + + // store the new module into the slot in the global dict holding all modules + el->value = MP_OBJ_FROM_PTR(o); + + // return the new module + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +// Global module table and related functions + +STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { + { MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) }, + { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) }, + { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) }, + +#if MICROPY_PY_ARRAY + { MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&mp_module_array) }, +#endif +#if MICROPY_PY_IO + { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) }, +#endif +#if MICROPY_PY_COLLECTIONS + { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) }, +#endif +#if MICROPY_PY_STRUCT + { MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) }, +#endif + +#if MICROPY_PY_BUILTINS_FLOAT +#if MICROPY_PY_MATH + { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) }, +#endif +#if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH + { MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) }, +#endif +#endif +#if MICROPY_PY_SYS + { MP_ROM_QSTR(MP_QSTR_sys), MP_ROM_PTR(&mp_module_sys) }, +#endif +#if MICROPY_PY_GC && MICROPY_ENABLE_GC + { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) }, +#endif +#if MICROPY_PY_THREAD + { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) }, +#endif + + // extmod modules + +#if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) }, +#endif +#if MICROPY_PY_UCTYPES + { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, +#endif +#if MICROPY_PY_UZLIB + { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) }, +#endif +#if MICROPY_PY_UJSON + { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) }, +#endif +#if MICROPY_PY_URE + { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) }, +#endif +#if MICROPY_PY_UHEAPQ + { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) }, +#endif +#if MICROPY_PY_UTIMEQ + { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) }, +#endif +#if MICROPY_PY_UHASHLIB + { MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) }, +#endif +#if MICROPY_PY_UCRYPTOLIB + { MP_ROM_QSTR(MP_QSTR_ucryptolib), MP_ROM_PTR(&mp_module_ucryptolib) }, +#endif +#if MICROPY_PY_UBINASCII + { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) }, +#endif +#if MICROPY_PY_URANDOM + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) }, +#endif +#if MICROPY_PY_USELECT + { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) }, +#endif +#if MICROPY_PY_USSL + { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) }, +#endif +#if MICROPY_PY_LWIP + { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) }, +#endif +#if MICROPY_PY_WEBSOCKET + { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) }, +#endif +#if MICROPY_PY_WEBREPL + { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) }, +#endif +#if MICROPY_PY_FRAMEBUF + { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) }, +#endif +#if MICROPY_PY_BTREE + { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) }, +#endif + + // extra builtin modules as defined by a port + MICROPY_PORT_BUILTIN_MODULES +}; + +MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); + +#if MICROPY_MODULE_WEAK_LINKS +STATIC const mp_rom_map_elem_t mp_builtin_module_weak_links_table[] = { + MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS +}; + +MP_DEFINE_CONST_MAP(mp_builtin_module_weak_links_map, mp_builtin_module_weak_links_table); +#endif + +// returns MP_OBJ_NULL if not found +mp_obj_t mp_module_get(qstr module_name) { + mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; + // lookup module + mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + + if (el == NULL) { + // module not found, look for builtin module names + el = mp_map_lookup((mp_map_t*)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (el == NULL) { + return MP_OBJ_NULL; + } + mp_module_call_init(module_name, el->value); + } + + // module found, return it + return el->value; +} + +void mp_module_register(qstr qst, mp_obj_t module) { + mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; + mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; +} + +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + // Look for __init__ and call it if it exists + mp_obj_t dest[2]; + mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + // Register module so __init__ is not called again. + // If a module can be referenced by more than one name (eg due to weak links) + // then __init__ will still be called for each distinct import, and it's then + // up to the particular module to make sure it's __init__ code only runs once. + mp_module_register(module_name, module_obj); + } +} +#endif diff --git a/src/openmv/src/micropython/py/objmodule.h b/src/openmv/src/micropython/py/objmodule.h new file mode 100755 index 0000000..b7702ec --- /dev/null +++ b/src/openmv/src/micropython/py/objmodule.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJMODULE_H +#define MICROPY_INCLUDED_PY_OBJMODULE_H + +#include "py/obj.h" + +extern const mp_map_t mp_builtin_module_map; +extern const mp_map_t mp_builtin_module_weak_links_map; + +mp_obj_t mp_module_get(qstr module_name); +void mp_module_register(qstr qstr, mp_obj_t module); + +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj); +#else +static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + (void)module_name; + (void)module_obj; +} +#endif + +#endif // MICROPY_INCLUDED_PY_OBJMODULE_H diff --git a/src/openmv/src/micropython/py/objnamedtuple.c b/src/openmv/src/micropython/py/objnamedtuple.c new file mode 100755 index 0000000..e7de899 --- /dev/null +++ b/src/openmv/src/micropython/py/objnamedtuple.c @@ -0,0 +1,184 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objtuple.h" +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/objnamedtuple.h" + +#if MICROPY_PY_COLLECTIONS + +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { + for (size_t i = 0; i < type->n_fields; i++) { + if (type->fields[i] == name) { + return i; + } + } + return (size_t)-1; +} + +#if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +STATIC mp_obj_t namedtuple_asdict(mp_obj_t self_in) { + mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); + const qstr *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields; + mp_obj_t dict = mp_obj_new_dict(self->tuple.len); + //make it an OrderedDict + mp_obj_dict_t *dictObj = MP_OBJ_TO_PTR(dict); + dictObj->base.type = &mp_type_ordereddict; + dictObj->map.is_ordered = 1; + for (size_t i = 0; i < self->tuple.len; ++i) { + mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(fields[i]), self->tuple.items[i]); + } + return dict; +} +MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict); +#endif + +STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); + mp_printf(print, "%q", o->tuple.base.type->name); + const qstr *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields; + mp_obj_attrtuple_print_helper(print, fields, &o->tuple); +} + +STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); + #if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT + if (attr == MP_QSTR__asdict) { + dest[0] = MP_OBJ_FROM_PTR(&namedtuple_asdict_obj); + dest[1] = self_in; + return; + } + #endif + size_t id = mp_obj_namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + if (id == (size_t)-1) { + return; + } + dest[0] = self->tuple.items[id]; + } else { + // delete/store attribute + // provide more detailed error message than we'd get by just returning + mp_raise_msg(&mp_type_AttributeError, "can't set attribute"); + } +} + +STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + const mp_obj_namedtuple_type_t *type = (const mp_obj_namedtuple_type_t*)type_in; + size_t num_fields = type->n_fields; + if (n_args + n_kw != num_fields) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function takes %d positional arguments but %d were given", + num_fields, n_args + n_kw)); + } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "%q() takes %d positional arguments but %d were given", + type->base.name, num_fields, n_args + n_kw)); + } + } + + // Create a tuple and set the type to this namedtuple + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_fields, NULL)); + tuple->base.type = type_in; + + // Copy the positional args into the first slots of the namedtuple + memcpy(&tuple->items[0], args, sizeof(mp_obj_t) * n_args); + + // Fill in the remaining slots with the keyword args + memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw); + for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { + qstr kw = mp_obj_str_get_qstr(args[i]); + size_t id = mp_obj_namedtuple_find_field(type, kw); + if (id == (size_t)-1) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "unexpected keyword argument '%q'", kw)); + } + } + if (tuple->items[id] != MP_OBJ_NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_arg_error_terse_mismatch(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "function got multiple values for argument '%q'", kw)); + } + } + tuple->items[id] = args[i + 1]; + } + + return MP_OBJ_FROM_PTR(tuple); +} + +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields) { + mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); + memset(&o->base, 0, sizeof(o->base)); + o->n_fields = n_fields; + for (size_t i = 0; i < n_fields; i++) { + o->fields[i] = mp_obj_str_get_qstr(fields[i]); + } + return o; +} + +STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { + mp_obj_namedtuple_type_t *o = mp_obj_new_namedtuple_base(n_fields, fields); + o->base.base.type = &mp_type_type; + o->base.name = name; + o->base.print = namedtuple_print; + o->base.make_new = namedtuple_make_new; + o->base.unary_op = mp_obj_tuple_unary_op; + o->base.binary_op = mp_obj_tuple_binary_op; + o->base.attr = namedtuple_attr; + o->base.subscr = mp_obj_tuple_subscr; + o->base.getiter = mp_obj_tuple_getiter; + o->base.parent = &mp_type_tuple; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { + qstr name = mp_obj_str_get_qstr(name_in); + size_t n_fields; + mp_obj_t *fields; + #if MICROPY_CPYTHON_COMPAT + if (MP_OBJ_IS_STR(fields_in)) { + fields_in = mp_obj_str_split(1, &fields_in); + } + #endif + mp_obj_get_array(fields_in, &n_fields, &fields); + return mp_obj_new_namedtuple_type(name, n_fields, fields); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); + +#endif // MICROPY_PY_COLLECTIONS diff --git a/src/openmv/src/micropython/py/objnamedtuple.h b/src/openmv/src/micropython/py/objnamedtuple.h new file mode 100755 index 0000000..d32af35 --- /dev/null +++ b/src/openmv/src/micropython/py/objnamedtuple.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H +#define MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H + +#include "py/objtuple.h" + +typedef struct _mp_obj_namedtuple_type_t { + mp_obj_type_t base; + size_t n_fields; + qstr fields[]; +} mp_obj_namedtuple_type_t; + +typedef struct _mp_obj_namedtuple_t { + mp_obj_tuple_t tuple; +} mp_obj_namedtuple_t; + +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name); +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields); + +#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H diff --git a/src/openmv/src/micropython/py/objnone.c b/src/openmv/src/micropython/py/objnone.c new file mode 100755 index 0000000..da10318 --- /dev/null +++ b/src/openmv/src/micropython/py/objnone.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" + +typedef struct _mp_obj_none_t { + mp_obj_base_t base; +} mp_obj_none_t; + +STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)self_in; + if (MICROPY_PY_UJSON && kind == PRINT_JSON) { + mp_print_str(print, "null"); + } else { + mp_print_str(print, "None"); + } +} + +const mp_obj_type_t mp_type_NoneType = { + { &mp_type_type }, + .name = MP_QSTR_NoneType, + .print = none_print, + .unary_op = mp_generic_unary_op, +}; + +const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}}; diff --git a/src/openmv/src/micropython/py/objobject.c b/src/openmv/src/micropython/py/objobject.c new file mode 100755 index 0000000..265fcfb --- /dev/null +++ b/src/openmv/src/micropython/py/objobject.c @@ -0,0 +1,84 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objtype.h" +#include "py/runtime.h" + +typedef struct _mp_obj_object_t { + mp_obj_base_t base; +} mp_obj_object_t; + +STATIC mp_obj_t object_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)args; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_obj_object_t *o = m_new_obj(mp_obj_object_t); + o->base.type = type; + return MP_OBJ_FROM_PTR(o); +} + +#if MICROPY_CPYTHON_COMPAT +STATIC mp_obj_t object___init__(mp_obj_t self) { + (void)self; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); + +STATIC mp_obj_t object___new__(mp_obj_t cls) { + if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { + mp_raise_TypeError("__new__ arg must be a user-type"); + } + // This executes only "__new__" part of instance creation. + // TODO: This won't work well for classes with native bases. + // TODO: This is a hack, should be resolved along the lines of + // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 + const mp_obj_type_t *native_base; + return MP_OBJ_FROM_PTR(mp_obj_new_instance(MP_OBJ_TO_PTR(cls), &native_base)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj)); + +STATIC const mp_rom_map_elem_t object_locals_dict_table[] = { + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) }, + #endif + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table); +#endif + +const mp_obj_type_t mp_type_object = { + { &mp_type_type }, + .name = MP_QSTR_object, + .make_new = object_make_new, + #if MICROPY_CPYTHON_COMPAT + .locals_dict = (mp_obj_dict_t*)&object_locals_dict, + #endif +}; diff --git a/src/openmv/src/micropython/py/objpolyiter.c b/src/openmv/src/micropython/py/objpolyiter.c new file mode 100755 index 0000000..01880bf --- /dev/null +++ b/src/openmv/src/micropython/py/objpolyiter.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +// This is universal iterator type which calls "iternext" method stored in +// particular object instance. (So, each instance of this time can have its +// own iteration behavior.) Having this type saves to define type objects +// for various internal iterator objects. + +// Any instance should have these 2 fields at the beginning +typedef struct _mp_obj_polymorph_iter_t { + mp_obj_base_t base; + mp_fun_1_t iternext; +} mp_obj_polymorph_iter_t; + +STATIC mp_obj_t polymorph_it_iternext(mp_obj_t self_in) { + mp_obj_polymorph_iter_t *self = MP_OBJ_TO_PTR(self_in); + // Redirect call to object instance's iternext method + return self->iternext(self_in); +} + +const mp_obj_type_t mp_type_polymorph_iter = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity_getiter, + .iternext = polymorph_it_iternext, +}; diff --git a/src/openmv/src/micropython/py/objproperty.c b/src/openmv/src/micropython/py/objproperty.c new file mode 100755 index 0000000..b66d24a --- /dev/null +++ b/src/openmv/src/micropython/py/objproperty.c @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_PROPERTY + +typedef struct _mp_obj_property_t { + mp_obj_base_t base; + mp_obj_t proxy[3]; // getter, setter, deleter +} mp_obj_property_t; + +STATIC mp_obj_t property_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + enum { ARG_fget, ARG_fset, ARG_fdel, ARG_doc }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_doc, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + }; + mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); + + mp_obj_property_t *o = m_new_obj(mp_obj_property_t); + o->base.type = type; + o->proxy[0] = vals[ARG_fget].u_obj; + o->proxy[1] = vals[ARG_fset].u_obj; + o->proxy[2] = vals[ARG_fdel].u_obj; + // vals[ARG_doc] is silently discarded + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t property_getter(mp_obj_t self_in, mp_obj_t getter) { + mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); + *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); + p2->proxy[0] = getter; + return MP_OBJ_FROM_PTR(p2); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_getter_obj, property_getter); + +STATIC mp_obj_t property_setter(mp_obj_t self_in, mp_obj_t setter) { + mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); + *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); + p2->proxy[1] = setter; + return MP_OBJ_FROM_PTR(p2); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_setter_obj, property_setter); + +STATIC mp_obj_t property_deleter(mp_obj_t self_in, mp_obj_t deleter) { + mp_obj_property_t *p2 = m_new_obj(mp_obj_property_t); + *p2 = *(mp_obj_property_t*)MP_OBJ_TO_PTR(self_in); + p2->proxy[2] = deleter; + return MP_OBJ_FROM_PTR(p2); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(property_deleter_obj, property_deleter); + +STATIC const mp_rom_map_elem_t property_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_getter), MP_ROM_PTR(&property_getter_obj) }, + { MP_ROM_QSTR(MP_QSTR_setter), MP_ROM_PTR(&property_setter_obj) }, + { MP_ROM_QSTR(MP_QSTR_deleter), MP_ROM_PTR(&property_deleter_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(property_locals_dict, property_locals_dict_table); + +const mp_obj_type_t mp_type_property = { + { &mp_type_type }, + .name = MP_QSTR_property, + .make_new = property_make_new, + .locals_dict = (mp_obj_dict_t*)&property_locals_dict, +}; + +const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); + mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in); + return self->proxy; +} + +#endif // MICROPY_PY_BUILTINS_PROPERTY diff --git a/src/openmv/src/micropython/py/objrange.c b/src/openmv/src/micropython/py/objrange.c new file mode 100755 index 0000000..86aa0cc --- /dev/null +++ b/src/openmv/src/micropython/py/objrange.c @@ -0,0 +1,224 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +/******************************************************************************/ +/* range iterator */ + +typedef struct _mp_obj_range_it_t { + mp_obj_base_t base; + // TODO make these values generic objects or something + mp_int_t cur; + mp_int_t stop; + mp_int_t step; +} mp_obj_range_it_t; + +STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) { + mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in); + if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) { + mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur); + o->cur += o->step; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC const mp_obj_type_t range_it_type = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity_getiter, + .iternext = range_it_iternext, +}; + +STATIC mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t step, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_range_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_range_it_t *o = (mp_obj_range_it_t*)iter_buf; + o->base.type = &range_it_type; + o->cur = cur; + o->stop = stop; + o->step = step; + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +/* range */ + +typedef struct _mp_obj_range_t { + mp_obj_base_t base; + // TODO make these values generic objects or something + mp_int_t start; + mp_int_t stop; + mp_int_t step; +} mp_obj_range_t; + +STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "range(" INT_FMT ", " INT_FMT "", self->start, self->stop); + if (self->step == 1) { + mp_print_str(print, ")"); + } else { + mp_printf(print, ", " INT_FMT ")", self->step); + } +} + +STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 3, false); + + mp_obj_range_t *o = m_new_obj(mp_obj_range_t); + o->base.type = type; + o->start = 0; + o->step = 1; + + if (n_args == 1) { + o->stop = mp_obj_get_int(args[0]); + } else { + o->start = mp_obj_get_int(args[0]); + o->stop = mp_obj_get_int(args[1]); + if (n_args == 3) { + o->step = mp_obj_get_int(args[2]); + if (o->step == 0) { + mp_raise_ValueError("zero step"); + } + } + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_int_t range_len(mp_obj_range_t *self) { + // When computing length, need to take into account step!=1 and step<0. + mp_int_t len = self->stop - self->start + self->step; + if (self->step > 0) { + len -= 1; + } else { + len += 1; + } + len = len / self->step; + if (len < 0) { + len = 0; + } + return len; +} + +STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t len = range_len(self); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len > 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); + default: return MP_OBJ_NULL; // op not supported + } +} + +#if MICROPY_PY_BUILTINS_RANGE_BINOP +STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) { + return MP_OBJ_NULL; // op not supported + } + mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in); + mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in); + mp_int_t lhs_len = range_len(lhs); + mp_int_t rhs_len = range_len(rhs); + return mp_obj_new_bool( + lhs_len == rhs_len + && (lhs_len == 0 + || (lhs->start == rhs->start + && (lhs_len == 1 || lhs->step == rhs->step))) + ); +} +#endif + +STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_SENTINEL) { + // load + mp_obj_range_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t len = range_len(self); +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + mp_seq_get_fast_slice_indexes(len, index, &slice); + mp_obj_range_t *o = m_new_obj(mp_obj_range_t); + o->base.type = &mp_type_range; + o->start = self->start + slice.start * self->step; + o->stop = self->start + slice.stop * self->step; + o->step = slice.step * self->step; + if (slice.step < 0) { + // Negative slice steps have inclusive stop, so adjust for exclusive + o->stop -= self->step; + } + return MP_OBJ_FROM_PTR(o); + } +#endif + size_t index_val = mp_get_index(self->base.type, len, index, false); + return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step); + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t range_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in); + return mp_obj_new_range_iterator(o->start, o->stop, o->step, iter_buf); +} + + +#if MICROPY_PY_BUILTINS_RANGE_ATTRS +STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + mp_obj_range_t *o = MP_OBJ_TO_PTR(o_in); + if (attr == MP_QSTR_start) { + dest[0] = mp_obj_new_int(o->start); + } else if (attr == MP_QSTR_stop) { + dest[0] = mp_obj_new_int(o->stop); + } else if (attr == MP_QSTR_step) { + dest[0] = mp_obj_new_int(o->step); + } +} +#endif + +const mp_obj_type_t mp_type_range = { + { &mp_type_type }, + .name = MP_QSTR_range, + .print = range_print, + .make_new = range_make_new, + .unary_op = range_unary_op, + #if MICROPY_PY_BUILTINS_RANGE_BINOP + .binary_op = range_binary_op, + #endif + .subscr = range_subscr, + .getiter = range_getiter, +#if MICROPY_PY_BUILTINS_RANGE_ATTRS + .attr = range_attr, +#endif +}; diff --git a/src/openmv/src/micropython/py/objreversed.c b/src/openmv/src/micropython/py/objreversed.c new file mode 100755 index 0000000..e498b55 --- /dev/null +++ b/src/openmv/src/micropython/py/objreversed.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_REVERSED + +typedef struct _mp_obj_reversed_t { + mp_obj_base_t base; + mp_obj_t seq; // sequence object that we are reversing + mp_uint_t cur_index; // current index, plus 1; 0=no more, 1=last one (index 0) +} mp_obj_reversed_t; + +STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // check if __reversed__ exists, and if so delegate to it + mp_obj_t dest[2]; + mp_load_method_maybe(args[0], MP_QSTR___reversed__, dest); + if (dest[0] != MP_OBJ_NULL) { + return mp_call_method_n_kw(0, 0, dest); + } + + mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t); + o->base.type = type; + o->seq = args[0]; + o->cur_index = mp_obj_get_int(mp_obj_len(args[0])); // start at the end of the sequence + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); + mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in); + + // "raise" stop iteration if we are at the end (the start) of the sequence + if (self->cur_index == 0) { + return MP_OBJ_STOP_ITERATION; + } + + // pre-decrement and index sequence + self->cur_index -= 1; + return mp_obj_subscr(self->seq, MP_OBJ_NEW_SMALL_INT(self->cur_index), MP_OBJ_SENTINEL); +} + +const mp_obj_type_t mp_type_reversed = { + { &mp_type_type }, + .name = MP_QSTR_reversed, + .make_new = reversed_make_new, + .getiter = mp_identity_getiter, + .iternext = reversed_iternext, +}; + +#endif // MICROPY_PY_BUILTINS_REVERSED diff --git a/src/openmv/src/micropython/py/objset.c b/src/openmv/src/micropython/py/objset.c new file mode 100755 index 0000000..799ba9d --- /dev/null +++ b/src/openmv/src/micropython/py/objset.c @@ -0,0 +1,598 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/builtin.h" + +#if MICROPY_PY_BUILTINS_SET + +typedef struct _mp_obj_set_t { + mp_obj_base_t base; + mp_set_t set; +} mp_obj_set_t; + +typedef struct _mp_obj_set_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_set_t *set; + size_t cur; +} mp_obj_set_it_t; + +STATIC mp_obj_t set_it_iternext(mp_obj_t self_in); + +STATIC bool is_set_or_frozenset(mp_obj_t o) { + return MP_OBJ_IS_TYPE(o, &mp_type_set) +#if MICROPY_PY_BUILTINS_FROZENSET + || MP_OBJ_IS_TYPE(o, &mp_type_frozenset) +#endif + ; +} + +// This macro is shorthand for mp_check_self to verify the argument is a set. +#define check_set(o) mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)) + +// This macro is shorthand for mp_check_self to verify the argument is a +// set or frozenset for methods that operate on both of these types. +#define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o)) + +STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + #if MICROPY_PY_BUILTINS_FROZENSET + bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset); + #endif + if (self->set.used == 0) { + #if MICROPY_PY_BUILTINS_FROZENSET + if (is_frozen) { + mp_print_str(print, "frozen"); + } + #endif + mp_print_str(print, "set()"); + return; + } + bool first = true; + #if MICROPY_PY_BUILTINS_FROZENSET + if (is_frozen) { + mp_print_str(print, "frozenset("); + } + #endif + mp_print_str(print, "{"); + for (size_t i = 0; i < self->set.alloc; i++) { + if (MP_SET_SLOT_IS_FILLED(&self->set, i)) { + if (!first) { + mp_print_str(print, ", "); + } + first = false; + mp_obj_print_helper(print, self->set.table[i], PRINT_REPR); + } + } + mp_print_str(print, "}"); + #if MICROPY_PY_BUILTINS_FROZENSET + if (is_frozen) { + mp_print_str(print, ")"); + } + #endif +} + +STATIC mp_obj_t set_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + switch (n_args) { + case 0: { + // create a new, empty set + mp_obj_set_t *set = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL)); + // set actual set/frozenset type + set->base.type = type; + return MP_OBJ_FROM_PTR(set); + } + + case 1: + default: { // can only be 0 or 1 arg + // 1 argument, an iterable from which we make a new set + mp_obj_t set = mp_obj_new_set(0, NULL); + mp_obj_t iterable = mp_getiter(args[0], NULL); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_obj_set_store(set, item); + } + // Set actual set/frozenset type + ((mp_obj_set_t*)MP_OBJ_TO_PTR(set))->base.type = type; + return set; + } + } +} + +STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) { + mp_obj_set_it_t *self = MP_OBJ_TO_PTR(self_in); + size_t max = self->set->set.alloc; + mp_set_t *set = &self->set->set; + + for (size_t i = self->cur; i < max; i++) { + if (MP_SET_SLOT_IS_FILLED(set, i)) { + self->cur = i + 1; + return set->table[i]; + } + } + + return MP_OBJ_STOP_ITERATION; +} + +STATIC mp_obj_t set_getiter(mp_obj_t set_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_set_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_set_it_t *o = (mp_obj_set_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = set_it_iternext; + o->set = (mp_obj_set_t *)MP_OBJ_TO_PTR(set_in); + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + + +/******************************************************************************/ +/* set methods */ + +STATIC mp_obj_t set_add(mp_obj_t self_in, mp_obj_t item) { + check_set(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_add_obj, set_add); + +STATIC mp_obj_t set_clear(mp_obj_t self_in) { + check_set(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + + mp_set_clear(&self->set); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_clear_obj, set_clear); + +STATIC mp_obj_t set_copy(mp_obj_t self_in) { + check_set_or_frozenset(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_set_t *other = m_new_obj(mp_obj_set_t); + other->base.type = self->base.type; + mp_set_init(&other->set, self->set.alloc); + other->set.used = self->set.used; + memcpy(other->set.table, self->set.table, self->set.alloc * sizeof(mp_obj_t)); + return MP_OBJ_FROM_PTR(other); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_copy_obj, set_copy); + +STATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) { + check_set(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard); + +STATIC mp_obj_t set_diff_int(size_t n_args, const mp_obj_t *args, bool update) { + mp_obj_t self; + if (update) { + check_set(args[0]); + self = args[0]; + } else { + self = set_copy(args[0]); + } + + for (size_t i = 1; i < n_args; i++) { + mp_obj_t other = args[i]; + if (self == other) { + set_clear(self); + } else { + mp_set_t *self_set = &((mp_obj_set_t*)MP_OBJ_TO_PTR(self))->set; + mp_obj_t iter = mp_getiter(other, NULL); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_set_lookup(self_set, next, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + } + } + } + + return self; +} + +STATIC mp_obj_t set_diff(size_t n_args, const mp_obj_t *args) { + return set_diff_int(n_args, args, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_obj, 1, set_diff); + +STATIC mp_obj_t set_diff_update(size_t n_args, const mp_obj_t *args) { + set_diff_int(n_args, args, true); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_diff_update_obj, 1, set_diff_update); + +STATIC mp_obj_t set_intersect_int(mp_obj_t self_in, mp_obj_t other, bool update) { + if (update) { + check_set(self_in); + } else { + check_set_or_frozenset(self_in); + } + + if (self_in == other) { + return update ? mp_const_none : set_copy(self_in); + } + + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_set_t *out = MP_OBJ_TO_PTR(mp_obj_new_set(0, NULL)); + + mp_obj_t iter = mp_getiter(other, NULL); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { + set_add(MP_OBJ_FROM_PTR(out), next); + } + } + + if (update) { + m_del(mp_obj_t, self->set.table, self->set.alloc); + self->set.alloc = out->set.alloc; + self->set.used = out->set.used; + self->set.table = out->set.table; + } + + return update ? mp_const_none : MP_OBJ_FROM_PTR(out); +} + +STATIC mp_obj_t set_intersect(mp_obj_t self_in, mp_obj_t other) { + return set_intersect_int(self_in, other, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_obj, set_intersect); + +STATIC mp_obj_t set_intersect_update(mp_obj_t self_in, mp_obj_t other) { + return set_intersect_int(self_in, other, true); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_intersect_update_obj, set_intersect_update); + +STATIC mp_obj_t set_isdisjoint(mp_obj_t self_in, mp_obj_t other) { + check_set_or_frozenset(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(other, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_set_lookup(&self->set, next, MP_MAP_LOOKUP)) { + return mp_const_false; + } + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_isdisjoint_obj, set_isdisjoint); + +STATIC mp_obj_t set_issubset_internal(mp_obj_t self_in, mp_obj_t other_in, bool proper) { + mp_obj_set_t *self; + bool cleanup_self = false; + if (is_set_or_frozenset(self_in)) { + self = MP_OBJ_TO_PTR(self_in); + } else { + self = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &self_in)); + cleanup_self = true; + } + + mp_obj_set_t *other; + bool cleanup_other = false; + if (is_set_or_frozenset(other_in)) { + other = MP_OBJ_TO_PTR(other_in); + } else { + other = MP_OBJ_TO_PTR(set_make_new(&mp_type_set, 1, 0, &other_in)); + cleanup_other = true; + } + mp_obj_t out = mp_const_true; + if (proper && self->set.used == other->set.used) { + out = mp_const_false; + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = set_getiter(MP_OBJ_FROM_PTR(self), &iter_buf); + mp_obj_t next; + while ((next = set_it_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (!mp_set_lookup(&other->set, next, MP_MAP_LOOKUP)) { + out = mp_const_false; + break; + } + } + } + // TODO: Should free objects altogether + if (cleanup_self) { + set_clear(MP_OBJ_FROM_PTR(self)); + } + if (cleanup_other) { + set_clear(MP_OBJ_FROM_PTR(other)); + } + return out; +} +STATIC mp_obj_t set_issubset(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(self_in, other_in, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issubset_obj, set_issubset); + +STATIC mp_obj_t set_issubset_proper(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(self_in, other_in, true); +} + +STATIC mp_obj_t set_issuperset(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(other_in, self_in, false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_issuperset_obj, set_issuperset); + +STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) { + return set_issubset_internal(other_in, self_in, true); +} + +STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { + assert(is_set_or_frozenset(other_in)); + check_set_or_frozenset(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in); + if (self->set.used != other->set.used) { + return mp_const_false; + } + return set_issubset(self_in, other_in); +} + +STATIC mp_obj_t set_pop(mp_obj_t self_in) { + check_set(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t obj = mp_set_remove_first(&self->set); + if (obj == MP_OBJ_NULL) { + mp_raise_msg(&mp_type_KeyError, "pop from an empty set"); + } + return obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop); + +STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) { + check_set(self_in); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, item)); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_remove_obj, set_remove); + +STATIC mp_obj_t set_symmetric_difference_update(mp_obj_t self_in, mp_obj_t other_in) { + check_set_or_frozenset(self_in); // can be frozenset due to call from set_symmetric_difference + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t iter = mp_getiter(other_in, NULL); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_update_obj, set_symmetric_difference_update); + +STATIC mp_obj_t set_symmetric_difference(mp_obj_t self_in, mp_obj_t other_in) { + mp_obj_t self_out = set_copy(self_in); + set_symmetric_difference_update(self_out, other_in); + return self_out; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_symmetric_difference_obj, set_symmetric_difference); + +STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) { + mp_obj_t iter = mp_getiter(other_in, NULL); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + mp_set_lookup(&self->set, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + } +} + +STATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) { + check_set(args[0]); + for (size_t i = 1; i < n_args; i++) { + set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(set_update_obj, 1, set_update); + +STATIC mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) { + check_set_or_frozenset(self_in); + mp_obj_t self = set_copy(self_in); + set_update_int(MP_OBJ_TO_PTR(self), other_in); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union); + +STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->set.used != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used); +#if MICROPY_PY_BUILTINS_FROZENSET + case MP_UNARY_OP_HASH: + if (MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset)) { + // start hash with unique value + mp_int_t hash = (mp_int_t)(uintptr_t)&mp_type_frozenset; + size_t max = self->set.alloc; + mp_set_t *set = &self->set; + + for (size_t i = 0; i < max; i++) { + if (MP_SET_SLOT_IS_FILLED(set, i)) { + hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, set->table[i])); + } + } + return MP_OBJ_NEW_SMALL_INT(hash); + } +#endif + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { + mp_obj_t args[] = {lhs, rhs}; + #if MICROPY_PY_BUILTINS_FROZENSET + bool update = MP_OBJ_IS_TYPE(lhs, &mp_type_set); + #else + bool update = true; + #endif + if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) { + // For all ops except containment the RHS must be a set/frozenset + return MP_OBJ_NULL; + } + switch (op) { + case MP_BINARY_OP_OR: + return set_union(lhs, rhs); + case MP_BINARY_OP_XOR: + return set_symmetric_difference(lhs, rhs); + case MP_BINARY_OP_AND: + return set_intersect(lhs, rhs); + case MP_BINARY_OP_SUBTRACT: + return set_diff(2, args); + case MP_BINARY_OP_INPLACE_OR: + if (update) { + set_update(2, args); + return lhs; + } else { + return set_union(lhs, rhs); + } + case MP_BINARY_OP_INPLACE_XOR: + if (update) { + set_symmetric_difference_update(lhs, rhs); + return lhs; + } else { + return set_symmetric_difference(lhs, rhs); + } + case MP_BINARY_OP_INPLACE_AND: + rhs = set_intersect_int(lhs, rhs, update); + if (update) { + return lhs; + } else { + return rhs; + } + case MP_BINARY_OP_INPLACE_SUBTRACT: + return set_diff_int(2, args, update); + case MP_BINARY_OP_LESS: + return set_issubset_proper(lhs, rhs); + case MP_BINARY_OP_MORE: + return set_issuperset_proper(lhs, rhs); + case MP_BINARY_OP_EQUAL: + return set_equal(lhs, rhs); + case MP_BINARY_OP_LESS_EQUAL: + return set_issubset(lhs, rhs); + case MP_BINARY_OP_MORE_EQUAL: + return set_issuperset(lhs, rhs); + case MP_BINARY_OP_CONTAINS: { + mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs); + mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP); + return mp_obj_new_bool(elem != MP_OBJ_NULL); + } + default: + return MP_OBJ_NULL; // op not supported + } +} + +/******************************************************************************/ +/* set constructors & public C API */ + + +STATIC const mp_rom_map_elem_t set_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&set_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&set_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_discard), MP_ROM_PTR(&set_discard_obj) }, + { MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_difference_update), MP_ROM_PTR(&set_diff_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) }, + { MP_ROM_QSTR(MP_QSTR_intersection_update), MP_ROM_PTR(&set_intersect_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) }, + { MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) }, + { MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) }, + { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&set_pop_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&set_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) }, + { MP_ROM_QSTR(MP_QSTR_symmetric_difference_update), MP_ROM_PTR(&set_symmetric_difference_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&set_update_obj) }, + { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table); + +const mp_obj_type_t mp_type_set = { + { &mp_type_type }, + .name = MP_QSTR_set, + .print = set_print, + .make_new = set_make_new, + .unary_op = set_unary_op, + .binary_op = set_binary_op, + .getiter = set_getiter, + .locals_dict = (mp_obj_dict_t*)&set_locals_dict, +}; + +#if MICROPY_PY_BUILTINS_FROZENSET +STATIC const mp_rom_map_elem_t frozenset_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&set_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&set_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_intersection), MP_ROM_PTR(&set_intersect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isdisjoint), MP_ROM_PTR(&set_isdisjoint_obj) }, + { MP_ROM_QSTR(MP_QSTR_issubset), MP_ROM_PTR(&set_issubset_obj) }, + { MP_ROM_QSTR(MP_QSTR_issuperset), MP_ROM_PTR(&set_issuperset_obj) }, + { MP_ROM_QSTR(MP_QSTR_symmetric_difference), MP_ROM_PTR(&set_symmetric_difference_obj) }, + { MP_ROM_QSTR(MP_QSTR_union), MP_ROM_PTR(&set_union_obj) }, + { MP_ROM_QSTR(MP_QSTR___contains__), MP_ROM_PTR(&mp_op_contains_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(frozenset_locals_dict, frozenset_locals_dict_table); + +const mp_obj_type_t mp_type_frozenset = { + { &mp_type_type }, + .name = MP_QSTR_frozenset, + .print = set_print, + .make_new = set_make_new, + .unary_op = set_unary_op, + .binary_op = set_binary_op, + .getiter = set_getiter, + .locals_dict = (mp_obj_dict_t*)&frozenset_locals_dict, +}; +#endif + +mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) { + mp_obj_set_t *o = m_new_obj(mp_obj_set_t); + o->base.type = &mp_type_set; + mp_set_init(&o->set, n_args); + for (size_t i = 0; i < n_args; i++) { + mp_set_lookup(&o->set, items[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + } + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); + mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); + mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); +} + +#endif // MICROPY_PY_BUILTINS_SET diff --git a/src/openmv/src/micropython/py/objsingleton.c b/src/openmv/src/micropython/py/objsingleton.c new file mode 100755 index 0000000..6753539 --- /dev/null +++ b/src/openmv/src/micropython/py/objsingleton.c @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" + +/******************************************************************************/ +/* singleton objects defined by Python */ + +typedef struct _mp_obj_singleton_t { + mp_obj_base_t base; + qstr name; +} mp_obj_singleton_t; + +STATIC void singleton_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_singleton_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "%q", self->name); +} + +const mp_obj_type_t mp_type_singleton = { + { &mp_type_type }, + .name = MP_QSTR_, + .print = singleton_print, +}; + +const mp_obj_singleton_t mp_const_ellipsis_obj = {{&mp_type_singleton}, MP_QSTR_Ellipsis}; +#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED +const mp_obj_singleton_t mp_const_notimplemented_obj = {{&mp_type_singleton}, MP_QSTR_NotImplemented}; +#endif diff --git a/src/openmv/src/micropython/py/objslice.c b/src/openmv/src/micropython/py/objslice.c new file mode 100755 index 0000000..e50aa07 --- /dev/null +++ b/src/openmv/src/micropython/py/objslice.c @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" + +/******************************************************************************/ +/* slice object */ + +#if MICROPY_PY_BUILTINS_SLICE + +typedef struct _mp_obj_slice_t { + mp_obj_base_t base; + mp_obj_t start; + mp_obj_t stop; + mp_obj_t step; +} mp_obj_slice_t; + +STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in); + mp_print_str(print, "slice("); + mp_obj_print_helper(print, o->start, PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, o->stop, PRINT_REPR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, o->step, PRINT_REPR); + mp_print_str(print, ")"); +} + +#if MICROPY_PY_BUILTINS_SLICE_ATTRS +STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + if (attr == MP_QSTR_start) { + dest[0] = self->start; + } else if (attr == MP_QSTR_stop) { + dest[0] = self->stop; + } else if (attr == MP_QSTR_step) { + dest[0] = self->step; + } +} +#endif + +const mp_obj_type_t mp_type_slice = { + { &mp_type_type }, + .name = MP_QSTR_slice, + .print = slice_print, +#if MICROPY_PY_BUILTINS_SLICE_ATTRS + .attr = slice_attr, +#endif +}; + +mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { + mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t); + o->base.type = &mp_type_slice; + o->start = ostart; + o->stop = ostop; + o->step = ostep; + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice)); + mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + *start = self->start; + *stop = self->stop; + *step = self->step; +} + +#endif diff --git a/src/openmv/src/micropython/py/objstr.c b/src/openmv/src/micropython/py/objstr.c new file mode 100755 index 0000000..1b12147 --- /dev/null +++ b/src/openmv/src/micropython/py/objstr.c @@ -0,0 +1,2224 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/unicode.h" +#include "py/objstr.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stackctrl.h" + +#if MICROPY_PY_BUILTINS_STR_OP_MODULO +STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict); +#endif + +STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); +STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); + +/******************************************************************************/ +/* str */ + +void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) { + // this escapes characters, but it will be very slow to print (calling print many times) + bool has_single_quote = false; + bool has_double_quote = false; + for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { + if (*s == '\'') { + has_single_quote = true; + } else if (*s == '"') { + has_double_quote = true; + } + } + int quote_char = '\''; + if (has_single_quote && !has_double_quote) { + quote_char = '"'; + } + mp_printf(print, "%c", quote_char); + for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { + if (*s == quote_char) { + mp_printf(print, "\\%c", quote_char); + } else if (*s == '\\') { + mp_print_str(print, "\\\\"); + } else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) { + // In strings, anything which is not ascii control character + // is printed as is, this includes characters in range 0x80-0xff + // (which can be non-Latin letters, etc.) + mp_printf(print, "%c", *s); + } else if (*s == '\n') { + mp_print_str(print, "\\n"); + } else if (*s == '\r') { + mp_print_str(print, "\\r"); + } else if (*s == '\t') { + mp_print_str(print, "\\t"); + } else { + mp_printf(print, "\\x%02x", *s); + } + } + mp_printf(print, "%c", quote_char); +} + +#if MICROPY_PY_UJSON +void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) { + // for JSON spec, see http://www.ietf.org/rfc/rfc4627.txt + // if we are given a valid utf8-encoded string, we will print it in a JSON-conforming way + mp_print_str(print, "\""); + for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { + if (*s == '"' || *s == '\\') { + mp_printf(print, "\\%c", *s); + } else if (*s >= 32) { + // this will handle normal and utf-8 encoded chars + mp_printf(print, "%c", *s); + } else if (*s == '\n') { + mp_print_str(print, "\\n"); + } else if (*s == '\r') { + mp_print_str(print, "\\r"); + } else if (*s == '\t') { + mp_print_str(print, "\\t"); + } else { + // this will handle control chars + mp_printf(print, "\\u%04x", *s); + } + } + mp_print_str(print, "\""); +} +#endif + +STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + #if MICROPY_PY_UJSON + if (kind == PRINT_JSON) { + mp_str_print_json(print, str_data, str_len); + return; + } + #endif + #if !MICROPY_PY_BUILTINS_STR_UNICODE + bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes); + #else + bool is_bytes = true; + #endif + if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) { + mp_printf(print, "%.*s", str_len, str_data); + } else { + if (is_bytes) { + mp_print_str(print, "b"); + } + mp_str_print_quoted(print, str_data, str_len, is_bytes); + } +} + +mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +#if MICROPY_CPYTHON_COMPAT + if (n_kw != 0) { + mp_arg_error_unimpl_kw(); + } +#endif + + mp_arg_check_num(n_args, n_kw, 0, 3, false); + + switch (n_args) { + case 0: + return MP_OBJ_NEW_QSTR(MP_QSTR_); + + case 1: { + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 16, &print); + mp_obj_print_helper(&print, args[0], PRINT_STR); + return mp_obj_new_str_from_vstr(type, &vstr); + } + + default: // 2 or 3 args + // TODO: validate 2nd/3rd args + if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { + GET_STR_DATA_LEN(args[0], str_data, str_len); + GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } + #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK + if (!utf8_check(str_data, str_len)) { + mp_raise_msg(&mp_type_UnicodeError, NULL); + } + #endif + + // Check if a qstr with this data already exists + qstr q = qstr_find_strn((const char*)str_data, str_len); + if (q != MP_QSTR_NULL) { + return MP_OBJ_NEW_QSTR(q); + } + + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); + o->data = str_data; + o->hash = str_hash; + return MP_OBJ_FROM_PTR(o); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + #if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK + if (!utf8_check(bufinfo.buf, bufinfo.len)) { + mp_raise_msg(&mp_type_UnicodeError, NULL); + } + #endif + return mp_obj_new_str(bufinfo.buf, bufinfo.len); + } + } +} + +STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + + #if MICROPY_CPYTHON_COMPAT + if (n_kw != 0) { + mp_arg_error_unimpl_kw(); + } + #else + (void)n_kw; + #endif + + if (n_args == 0) { + return mp_const_empty_bytes; + } + + if (MP_OBJ_IS_STR(args[0])) { + if (n_args < 2 || n_args > 3) { + goto wrong_args; + } + GET_STR_DATA_LEN(args[0], str_data, str_len); + GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len)); + o->data = str_data; + o->hash = str_hash; + return MP_OBJ_FROM_PTR(o); + } + + if (n_args > 1) { + goto wrong_args; + } + + if (MP_OBJ_IS_SMALL_INT(args[0])) { + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); + if (len < 0) { + mp_raise_ValueError(NULL); + } + vstr_t vstr; + vstr_init_len(&vstr, len); + memset(vstr.buf, 0, len); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + + // check if argument has the buffer protocol + mp_buffer_info_t bufinfo; + if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { + return mp_obj_new_bytes(bufinfo.buf, bufinfo.len); + } + + vstr_t vstr; + // Try to create array of exact len if initializer len is known + mp_obj_t len_in = mp_obj_len_maybe(args[0]); + if (len_in == MP_OBJ_NULL) { + vstr_init(&vstr, 16); + } else { + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in); + vstr_init(&vstr, len); + } + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[0], &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_int_t val = mp_obj_get_int(item); + #if MICROPY_FULL_CHECKS + if (val < 0 || val > 255) { + mp_raise_ValueError("bytes value out of range"); + } + #endif + vstr_add_byte(&vstr, val); + } + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + +wrong_args: + mp_raise_TypeError("wrong number of arguments"); +} + +// like strstr but with specified length and allows \0 bytes +// TODO replace with something more efficient/standard +const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) { + if (hlen >= nlen) { + size_t str_index, str_index_end; + if (direction > 0) { + str_index = 0; + str_index_end = hlen - nlen; + } else { + str_index = hlen - nlen; + str_index_end = 0; + } + for (;;) { + if (memcmp(&haystack[str_index], needle, nlen) == 0) { + //found + return haystack + str_index; + } + if (str_index == str_index_end) { + //not found + break; + } + str_index += direction; + } + } + return NULL; +} + +// Note: this function is used to check if an object is a str or bytes, which +// works because both those types use it as their binary_op method. Revisit +// MP_OBJ_IS_STR_OR_BYTES if this fact changes. +mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + // check for modulo + if (op == MP_BINARY_OP_MODULO) { + #if MICROPY_PY_BUILTINS_STR_OP_MODULO + mp_obj_t *args = &rhs_in; + size_t n_args = 1; + mp_obj_t dict = MP_OBJ_NULL; + if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { + // TODO: Support tuple subclasses? + mp_obj_tuple_get(rhs_in, &n_args, &args); + } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) { + dict = rhs_in; + } + return str_modulo_format(lhs_in, n_args, args, dict); + #else + return MP_OBJ_NULL; + #endif + } + + // from now on we need lhs type and data, so extract them + mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in); + GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); + + // check for multiply + if (op == MP_BINARY_OP_MULTIPLY) { + mp_int_t n; + if (!mp_obj_get_int_maybe(rhs_in, &n)) { + return MP_OBJ_NULL; // op not supported + } + if (n <= 0) { + if (lhs_type == &mp_type_str) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str + } else { + return mp_const_empty_bytes; + } + } + vstr_t vstr; + vstr_init_len(&vstr, lhs_len * n); + mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf); + return mp_obj_new_str_from_vstr(lhs_type, &vstr); + } + + // From now on all operations allow: + // - str with str + // - bytes with bytes + // - bytes with bytearray + // - bytes with array.array + // To do this efficiently we use the buffer protocol to extract the raw + // data for the rhs, but only if the lhs is a bytes object. + // + // NOTE: CPython does not allow comparison between bytes ard array.array + // (even if the array is of type 'b'), even though it allows addition of + // such types. We are not compatible with this (we do allow comparison + // of bytes with anything that has the buffer protocol). It would be + // easy to "fix" this with a bit of extra logic below, but it costs code + // size and execution time so we don't. + + const byte *rhs_data; + size_t rhs_len; + if (lhs_type == mp_obj_get_type(rhs_in)) { + GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_); + rhs_data = rhs_data_; + rhs_len = rhs_len_; + } else if (lhs_type == &mp_type_bytes) { + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) { + return MP_OBJ_NULL; // op not supported + } + rhs_data = bufinfo.buf; + rhs_len = bufinfo.len; + } else { + // LHS is str and RHS has an incompatible type + // (except if operation is EQUAL, but that's handled by mp_obj_equal) + bad_implicit_conversion(rhs_in); + } + + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: { + if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) { + return rhs_in; + } + if (rhs_len == 0) { + return lhs_in; + } + + vstr_t vstr; + vstr_init_len(&vstr, lhs_len + rhs_len); + memcpy(vstr.buf, lhs_data, lhs_len); + memcpy(vstr.buf + lhs_len, rhs_data, rhs_len); + return mp_obj_new_str_from_vstr(lhs_type, &vstr); + } + + case MP_BINARY_OP_CONTAINS: + return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); + + //case MP_BINARY_OP_NOT_EQUAL: // This is never passed here + case MP_BINARY_OP_EQUAL: // This will be passed only for bytes, str is dealt with in mp_obj_equal() + case MP_BINARY_OP_LESS: + case MP_BINARY_OP_LESS_EQUAL: + case MP_BINARY_OP_MORE: + case MP_BINARY_OP_MORE_EQUAL: + return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len)); + + default: + return MP_OBJ_NULL; // op not supported + } +} + +#if !MICROPY_PY_BUILTINS_STR_UNICODE +// objstrunicode defines own version +const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, + mp_obj_t index, bool is_slice) { + size_t index_val = mp_get_index(type, self_len, index, is_slice); + return self_data + index_val; +} +#endif + +// This is used for both bytes and 8-bit strings. This is not used for unicode strings. +STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + GET_STR_DATA_LEN(self_in, self_data, self_len); + if (value == MP_OBJ_SENTINEL) { + // load +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) { + mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + } + return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start); + } +#endif + size_t index_val = mp_get_index(type, self_len, index, false); + // If we have unicode enabled the type will always be bytes, so take the short cut. + if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { + return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); + } else { + return mp_obj_new_str_via_qstr((char*)&self_data[index_val], 1); + } + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + const mp_obj_type_t *self_type = mp_obj_get_type(self_in); + + // get separation string + GET_STR_DATA_LEN(self_in, sep_str, sep_len); + + // process args + size_t seq_len; + mp_obj_t *seq_items; + + if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { + // arg is not a list nor a tuple, try to convert it to a list + // TODO: Try to optimize? + arg = mp_type_list.make_new(&mp_type_list, 1, 0, &arg); + } + mp_obj_get_array(arg, &seq_len, &seq_items); + + // count required length + size_t required_len = 0; + for (size_t i = 0; i < seq_len; i++) { + if (mp_obj_get_type(seq_items[i]) != self_type) { + mp_raise_TypeError( + "join expects a list of str/bytes objects consistent with self object"); + } + if (i > 0) { + required_len += sep_len; + } + GET_STR_LEN(seq_items[i], l); + required_len += l; + } + + // make joined string + vstr_t vstr; + vstr_init_len(&vstr, required_len); + byte *data = (byte*)vstr.buf; + for (size_t i = 0; i < seq_len; i++) { + if (i > 0) { + memcpy(data, sep_str, sep_len); + data += sep_len; + } + GET_STR_DATA_LEN(seq_items[i], s, l); + memcpy(data, s, l); + data += l; + } + + // return joined string + return mp_obj_new_str_from_vstr(self_type, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); + +mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + mp_int_t splits = -1; + mp_obj_t sep = mp_const_none; + if (n_args > 1) { + sep = args[1]; + if (n_args > 2) { + splits = mp_obj_get_int(args[2]); + } + } + + mp_obj_t res = mp_obj_new_list(0, NULL); + GET_STR_DATA_LEN(args[0], s, len); + const byte *top = s + len; + + if (sep == mp_const_none) { + // sep not given, so separate on whitespace + + // Initial whitespace is not counted as split, so we pre-do it + while (s < top && unichar_isspace(*s)) s++; + while (s < top && splits != 0) { + const byte *start = s; + while (s < top && !unichar_isspace(*s)) s++; + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); + if (s >= top) { + break; + } + while (s < top && unichar_isspace(*s)) s++; + if (splits > 0) { + splits--; + } + } + + if (s < top) { + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s)); + } + + } else { + // sep given + if (mp_obj_get_type(sep) != self_type) { + bad_implicit_conversion(sep); + } + + size_t sep_len; + const char *sep_str = mp_obj_str_get_data(sep, &sep_len); + + if (sep_len == 0) { + mp_raise_ValueError("empty separator"); + } + + for (;;) { + const byte *start = s; + for (;;) { + if (splits == 0 || s + sep_len > top) { + s = top; + break; + } else if (memcmp(s, sep_str, sep_len) == 0) { + break; + } + s++; + } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); + if (s >= top) { + break; + } + s += sep_len; + if (splits > 0) { + splits--; + } + } + } + + return res; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split); + +#if MICROPY_PY_BUILTINS_STR_SPLITLINES +STATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_keepends }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]); + mp_obj_t res = mp_obj_new_list(0, NULL); + + GET_STR_DATA_LEN(pos_args[0], s, len); + const byte *top = s + len; + + while (s < top) { + const byte *start = s; + size_t match = 0; + while (s < top) { + if (*s == '\n') { + match = 1; + break; + } else if (*s == '\r') { + if (s[1] == '\n') { + match = 2; + } else { + match = 1; + } + break; + } + s++; + } + size_t sub_len = s - start; + if (args[ARG_keepends].u_bool) { + sub_len += match; + } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); + s += match; + } + + return res; +} +MP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines); +#endif + +STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { + if (n_args < 3) { + // If we don't have split limit, it doesn't matter from which side + // we split. + return mp_obj_str_split(n_args, args); + } + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + mp_obj_t sep = args[1]; + GET_STR_DATA_LEN(args[0], s, len); + + mp_int_t splits = mp_obj_get_int(args[2]); + if (splits < 0) { + // Negative limit means no limit, so delegate to split(). + return mp_obj_str_split(n_args, args); + } + + mp_int_t org_splits = splits; + // Preallocate list to the max expected # of elements, as we + // will fill it from the end. + mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(splits + 1, NULL)); + mp_int_t idx = splits; + + if (sep == mp_const_none) { + mp_raise_NotImplementedError("rsplit(None,n)"); + } else { + size_t sep_len; + const char *sep_str = mp_obj_str_get_data(sep, &sep_len); + + if (sep_len == 0) { + mp_raise_ValueError("empty separator"); + } + + const byte *beg = s; + const byte *last = s + len; + for (;;) { + s = last - sep_len; + for (;;) { + if (splits == 0 || s < beg) { + break; + } else if (memcmp(s, sep_str, sep_len) == 0) { + break; + } + s--; + } + if (s < beg || splits == 0) { + res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg); + break; + } + res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len); + last = s; + splits--; + } + if (idx != 0) { + // We split less parts than split limit, now go cleanup surplus + size_t used = org_splits + 1 - idx; + memmove(res->items, &res->items[idx], used * sizeof(mp_obj_t)); + mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items)); + res->len = used; + } + } + + return MP_OBJ_FROM_PTR(res); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); + +STATIC mp_obj_t str_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + + // check argument type + if (mp_obj_get_type(args[1]) != self_type) { + bad_implicit_conversion(args[1]); + } + + GET_STR_DATA_LEN(args[0], haystack, haystack_len); + GET_STR_DATA_LEN(args[1], needle, needle_len); + + const byte *start = haystack; + const byte *end = haystack + haystack_len; + if (n_args >= 3 && args[2] != mp_const_none) { + start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true); + } + if (n_args >= 4 && args[3] != mp_const_none) { + end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true); + } + + if (end < start) { + goto out_error; + } + + const byte *p = find_subbytes(start, end - start, needle, needle_len, direction); + if (p == NULL) { + out_error: + // not found + if (is_index) { + mp_raise_ValueError("substring not found"); + } else { + return MP_OBJ_NEW_SMALL_INT(-1); + } + } else { + // found + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (self_type == &mp_type_str) { + return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p)); + } + #endif + return MP_OBJ_NEW_SMALL_INT(p - haystack); + } +} + +STATIC mp_obj_t str_find(size_t n_args, const mp_obj_t *args) { + return str_finder(n_args, args, 1, false); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); + +STATIC mp_obj_t str_rfind(size_t n_args, const mp_obj_t *args) { + return str_finder(n_args, args, -1, false); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); + +STATIC mp_obj_t str_index(size_t n_args, const mp_obj_t *args) { + return str_finder(n_args, args, 1, true); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index); + +STATIC mp_obj_t str_rindex(size_t n_args, const mp_obj_t *args) { + return str_finder(n_args, args, -1, true); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex); + +// TODO: (Much) more variety in args +STATIC mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) { + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + GET_STR_DATA_LEN(args[0], str, str_len); + size_t prefix_len; + const char *prefix = mp_obj_str_get_data(args[1], &prefix_len); + const byte *start = str; + if (n_args > 2) { + start = str_index_to_ptr(self_type, str, str_len, args[2], true); + } + if (prefix_len + (start - str) > str_len) { + return mp_const_false; + } + return mp_obj_new_bool(memcmp(start, prefix, prefix_len) == 0); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); + +STATIC mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) { + GET_STR_DATA_LEN(args[0], str, str_len); + size_t suffix_len; + const char *suffix = mp_obj_str_get_data(args[1], &suffix_len); + if (n_args > 2) { + mp_raise_NotImplementedError("start/end indices"); + } + + if (suffix_len > str_len) { + return mp_const_false; + } + return mp_obj_new_bool(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); + +enum { LSTRIP, RSTRIP, STRIP }; + +STATIC mp_obj_t str_uni_strip(int type, size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + + const byte *chars_to_del; + uint chars_to_del_len; + static const byte whitespace[] = " \t\n\r\v\f"; + + if (n_args == 1) { + chars_to_del = whitespace; + chars_to_del_len = sizeof(whitespace) - 1; + } else { + if (mp_obj_get_type(args[1]) != self_type) { + bad_implicit_conversion(args[1]); + } + GET_STR_DATA_LEN(args[1], s, l); + chars_to_del = s; + chars_to_del_len = l; + } + + GET_STR_DATA_LEN(args[0], orig_str, orig_str_len); + + size_t first_good_char_pos = 0; + bool first_good_char_pos_set = false; + size_t last_good_char_pos = 0; + size_t i = 0; + int delta = 1; + if (type == RSTRIP) { + i = orig_str_len - 1; + delta = -1; + } + for (size_t len = orig_str_len; len > 0; len--) { + if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) { + if (!first_good_char_pos_set) { + first_good_char_pos_set = true; + first_good_char_pos = i; + if (type == LSTRIP) { + last_good_char_pos = orig_str_len - 1; + break; + } else if (type == RSTRIP) { + first_good_char_pos = 0; + last_good_char_pos = i; + break; + } + } + last_good_char_pos = i; + } + i += delta; + } + + if (!first_good_char_pos_set) { + // string is all whitespace, return '' + if (self_type == &mp_type_str) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); + } else { + return mp_const_empty_bytes; + } + } + + assert(last_good_char_pos >= first_good_char_pos); + //+1 to accommodate the last character + size_t stripped_len = last_good_char_pos - first_good_char_pos + 1; + if (stripped_len == orig_str_len) { + // If nothing was stripped, don't bother to dup original string + // TODO: watch out for this case when we'll get to bytearray.strip() + assert(first_good_char_pos == 0); + return args[0]; + } + return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len); +} + +STATIC mp_obj_t str_strip(size_t n_args, const mp_obj_t *args) { + return str_uni_strip(STRIP, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); + +STATIC mp_obj_t str_lstrip(size_t n_args, const mp_obj_t *args) { + return str_uni_strip(LSTRIP, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip); + +STATIC mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) { + return str_uni_strip(RSTRIP, n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); + +#if MICROPY_PY_BUILTINS_STR_CENTER +STATIC mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) { + GET_STR_DATA_LEN(str_in, str, str_len); + mp_uint_t width = mp_obj_get_int(width_in); + if (str_len >= width) { + return str_in; + } + + vstr_t vstr; + vstr_init_len(&vstr, width); + memset(vstr.buf, ' ', width); + int left = (width - str_len) / 2; + memcpy(vstr.buf + left, str, str_len); + return mp_obj_new_str_from_vstr(mp_obj_get_type(str_in), &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center); +#endif + +// Takes an int arg, but only parses unsigned numbers, and only changes +// *num if at least one digit was parsed. +STATIC const char *str_to_int(const char *str, const char *top, int *num) { + if (str < top && '0' <= *str && *str <= '9') { + *num = 0; + do { + *num = *num * 10 + (*str - '0'); + str++; + } + while (str < top && '0' <= *str && *str <= '9'); + } + return str; +} + +STATIC bool isalignment(char ch) { + return ch && strchr("<>=^", ch) != NULL; +} + +STATIC bool istype(char ch) { + return ch && strchr("bcdeEfFgGnosxX%", ch) != NULL; +} + +STATIC bool arg_looks_integer(mp_obj_t arg) { + return MP_OBJ_IS_TYPE(arg, &mp_type_bool) || MP_OBJ_IS_INT(arg); +} + +STATIC bool arg_looks_numeric(mp_obj_t arg) { + return arg_looks_integer(arg) +#if MICROPY_PY_BUILTINS_FLOAT + || mp_obj_is_float(arg) +#endif + ; +} + +#if MICROPY_PY_BUILTINS_STR_OP_MODULO +STATIC mp_obj_t arg_as_int(mp_obj_t arg) { +#if MICROPY_PY_BUILTINS_FLOAT + if (mp_obj_is_float(arg)) { + return mp_obj_new_int_from_float(mp_obj_float_get(arg)); + } +#endif + return arg; +} +#endif + +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE +STATIC NORETURN void terse_str_format_value_error(void) { + mp_raise_ValueError("bad format string"); +} +#else +// define to nothing to improve coverage +#define terse_str_format_value_error() +#endif + +STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 16, &print); + + for (; str < top; str++) { + if (*str == '}') { + str++; + if (str < top && *str == '}') { + vstr_add_byte(&vstr, '}'); + continue; + } + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("single '}' encountered in format string"); + } + } + if (*str != '{') { + vstr_add_byte(&vstr, *str); + continue; + } + + str++; + if (str < top && *str == '{') { + vstr_add_byte(&vstr, '{'); + continue; + } + + // replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}" + + const char *field_name = NULL; + const char *field_name_top = NULL; + char conversion = '\0'; + const char *format_spec = NULL; + + if (str < top && *str != '}' && *str != '!' && *str != ':') { + field_name = (const char *)str; + while (str < top && *str != '}' && *str != '!' && *str != ':') { + ++str; + } + field_name_top = (const char *)str; + } + + // conversion ::= "r" | "s" + + if (str < top && *str == '!') { + str++; + if (str < top && (*str == 'r' || *str == 's')) { + conversion = *str++; + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { + mp_raise_ValueError("bad conversion specifier"); + } else { + if (str >= top) { + mp_raise_ValueError( + "end of format while looking for conversion specifier"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unknown conversion specifier %c", *str)); + } + } + } + } + + if (str < top && *str == ':') { + str++; + // {:} is the same as {}, which is the same as {!s} + // This makes a difference when passing in a True or False + // '{}'.format(True) returns 'True' + // '{:d}'.format(True) returns '1' + // So we treat {:} as {} and this later gets treated to be {!s} + if (*str != '}') { + format_spec = str; + for (int nest = 1; str < top;) { + if (*str == '{') { + ++nest; + } else if (*str == '}') { + if (--nest == 0) { + break; + } + } + ++str; + } + } + } + if (str >= top) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("unmatched '{' in format"); + } + } + if (*str != '}') { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("expected ':' after format specifier"); + } + } + + mp_obj_t arg = mp_const_none; + + if (field_name) { + int index = 0; + if (MP_LIKELY(unichar_isdigit(*field_name))) { + if (*arg_i > 0) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError( + "can't switch from automatic field numbering to manual field specification"); + } + } + field_name = str_to_int(field_name, field_name_top, &index); + if ((uint)index >= n_args - 1) { + mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); + } + arg = args[index + 1]; + *arg_i = -1; + } else { + const char *lookup; + for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); + mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr? + field_name = lookup; + mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); + if (key_elem == NULL) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, field_q)); + } + arg = key_elem->value; + } + if (field_name < field_name_top) { + mp_raise_NotImplementedError("attributes not supported yet"); + } + } else { + if (*arg_i < 0) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError( + "can't switch from manual field specification to automatic field numbering"); + } + } + if ((uint)*arg_i >= n_args - 1) { + mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); + } + arg = args[(*arg_i) + 1]; + (*arg_i)++; + } + if (!format_spec && !conversion) { + conversion = 's'; + } + if (conversion) { + mp_print_kind_t print_kind; + if (conversion == 's') { + print_kind = PRINT_STR; + } else { + assert(conversion == 'r'); + print_kind = PRINT_REPR; + } + vstr_t arg_vstr; + mp_print_t arg_print; + vstr_init_print(&arg_vstr, 16, &arg_print); + mp_obj_print_helper(&arg_print, arg, print_kind); + arg = mp_obj_new_str_from_vstr(&mp_type_str, &arg_vstr); + } + + char fill = '\0'; + char align = '\0'; + int width = -1; + int precision = -1; + char type = '\0'; + int flags = 0; + + if (format_spec) { + // The format specifier (from http://docs.python.org/2/library/string.html#formatspec) + // + // [[fill]align][sign][#][0][width][,][.precision][type] + // fill ::= + // align ::= "<" | ">" | "=" | "^" + // sign ::= "+" | "-" | " " + // width ::= integer + // precision ::= integer + // type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" + + // recursively call the formatter to format any nested specifiers + MP_STACK_CHECK(); + vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs); + const char *s = vstr_null_terminated_str(&format_spec_vstr); + const char *stop = s + format_spec_vstr.len; + if (isalignment(*s)) { + align = *s++; + } else if (*s && isalignment(s[1])) { + fill = *s++; + align = *s++; + } + if (*s == '+' || *s == '-' || *s == ' ') { + if (*s == '+') { + flags |= PF_FLAG_SHOW_SIGN; + } else if (*s == ' ') { + flags |= PF_FLAG_SPACE_SIGN; + } + s++; + } + if (*s == '#') { + flags |= PF_FLAG_SHOW_PREFIX; + s++; + } + if (*s == '0') { + if (!align) { + align = '='; + } + if (!fill) { + fill = '0'; + } + } + s = str_to_int(s, stop, &width); + if (*s == ',') { + flags |= PF_FLAG_SHOW_COMMA; + s++; + } + if (*s == '.') { + s++; + s = str_to_int(s, stop, &precision); + } + if (istype(*s)) { + type = *s++; + } + if (*s) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("invalid format specifier"); + } + } + vstr_clear(&format_spec_vstr); + } + if (!align) { + if (arg_looks_numeric(arg)) { + align = '>'; + } else { + align = '<'; + } + } + if (!fill) { + fill = ' '; + } + + if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) { + if (type == 's') { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("sign not allowed in string format specifier"); + } + } + if (type == 'c') { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError( + "sign not allowed with integer format specifier 'c'"); + } + } + } + + switch (align) { + case '<': flags |= PF_FLAG_LEFT_ADJUST; break; + case '=': flags |= PF_FLAG_PAD_AFTER_SIGN; break; + case '^': flags |= PF_FLAG_CENTER_ADJUST; break; + } + + if (arg_looks_integer(arg)) { + switch (type) { + case 'b': + mp_print_mp_int(&print, arg, 2, 'a', flags, fill, width, 0); + continue; + + case 'c': + { + char ch = mp_obj_get_int(arg); + mp_print_strn(&print, &ch, 1, flags, fill, width); + continue; + } + + case '\0': // No explicit format type implies 'd' + case 'n': // I don't think we support locales in uPy so use 'd' + case 'd': + mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0); + continue; + + case 'o': + if (flags & PF_FLAG_SHOW_PREFIX) { + flags |= PF_FLAG_SHOW_OCTAL_LETTER; + } + + mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, 0); + continue; + + case 'X': + case 'x': + mp_print_mp_int(&print, arg, 16, type - ('X' - 'A'), flags, fill, width, 0); + continue; + + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case '%': + // The floating point formatters all work with anything that + // looks like an integer + break; + + default: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unknown format code '%c' for object of type '%s'", + type, mp_obj_get_type_str(arg))); + } + } + } + + // NOTE: no else here. We need the e, f, g etc formats for integer + // arguments (from above if) to take this if. + if (arg_looks_numeric(arg)) { + if (!type) { + + // Even though the docs say that an unspecified type is the same + // as 'g', there is one subtle difference, when the exponent + // is one less than the precision. + // + // '{:10.1}'.format(0.0) ==> '0e+00' + // '{:10.1g}'.format(0.0) ==> '0' + // + // TODO: Figure out how to deal with this. + // + // A proper solution would involve adding a special flag + // or something to format_float, and create a format_double + // to deal with doubles. In order to fix this when using + // sprintf, we'd need to use the e format and tweak the + // returned result to strip trailing zeros like the g format + // does. + // + // {:10.3} and {:10.2e} with 1.23e2 both produce 1.23e+02 + // but with 1.e2 you get 1e+02 and 1.00e+02 + // + // Stripping the trailing 0's (like g) does would make the + // e format give us the right format. + // + // CPython sources say: + // Omitted type specifier. Behaves in the same way as repr(x) + // and str(x) if no precision is given, else like 'g', but with + // at least one digit after the decimal point. */ + + type = 'g'; + } + if (type == 'n') { + type = 'g'; + } + + switch (type) { +#if MICROPY_PY_BUILTINS_FLOAT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + mp_print_float(&print, mp_obj_get_float(arg), type, flags, fill, width, precision); + break; + + case '%': + flags |= PF_FLAG_ADD_PERCENT; + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + #define F100 100.0F + #else + #define F100 100.0 + #endif + mp_print_float(&print, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision); + #undef F100 + break; +#endif + + default: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unknown format code '%c' for object of type '%s'", + type, mp_obj_get_type_str(arg))); + } + } + } else { + // arg doesn't look like a number + + if (align == '=') { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError( + "'=' alignment not allowed in string format specifier"); + } + } + + switch (type) { + case '\0': // no explicit format type implies 's' + case 's': { + size_t slen; + const char *s = mp_obj_str_get_data(arg, &slen); + if (precision < 0) { + precision = slen; + } + if (slen > (size_t)precision) { + slen = precision; + } + mp_print_strn(&print, s, slen, flags, fill, width); + break; + } + + default: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unknown format code '%c' for object of type '%s'", + type, mp_obj_get_type_str(arg))); + } + } + } + } + + return vstr; +} + +mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + + GET_STR_DATA_LEN(args[0], str, len); + int arg_i = 0; + vstr_t vstr = mp_obj_str_format_helper((const char*)str, (const char*)str + len, &arg_i, n_args, args, kwargs); + return mp_obj_new_str_from_vstr(mp_obj_get_type(args[0]), &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_KW(str_format_obj, 1, mp_obj_str_format); + +#if MICROPY_PY_BUILTINS_STR_OP_MODULO +STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(pattern)); + + GET_STR_DATA_LEN(pattern, str, len); + const byte *start_str = str; + bool is_bytes = MP_OBJ_IS_TYPE(pattern, &mp_type_bytes); + size_t arg_i = 0; + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 16, &print); + + for (const byte *top = str + len; str < top; str++) { + mp_obj_t arg = MP_OBJ_NULL; + if (*str != '%') { + vstr_add_byte(&vstr, *str); + continue; + } + if (++str >= top) { + goto incomplete_format; + } + if (*str == '%') { + vstr_add_byte(&vstr, '%'); + continue; + } + + // Dictionary value lookup + if (*str == '(') { + if (dict == MP_OBJ_NULL) { + mp_raise_TypeError("format needs a dict"); + } + arg_i = 1; // we used up the single dict argument + const byte *key = ++str; + while (*str != ')') { + if (str >= top) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("incomplete format key"); + } + } + ++str; + } + mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key); + arg = mp_obj_dict_get(dict, k_obj); + str++; + } + + int flags = 0; + char fill = ' '; + int alt = 0; + while (str < top) { + if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST; + else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN; + else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN; + else if (*str == '#') alt = PF_FLAG_SHOW_PREFIX; + else if (*str == '0') { + flags |= PF_FLAG_PAD_AFTER_SIGN; + fill = '0'; + } else break; + str++; + } + // parse width, if it exists + int width = 0; + if (str < top) { + if (*str == '*') { + if (arg_i >= n_args) { + goto not_enough_args; + } + width = mp_obj_get_int(args[arg_i++]); + str++; + } else { + str = (const byte*)str_to_int((const char*)str, (const char*)top, &width); + } + } + int prec = -1; + if (str < top && *str == '.') { + if (++str < top) { + if (*str == '*') { + if (arg_i >= n_args) { + goto not_enough_args; + } + prec = mp_obj_get_int(args[arg_i++]); + str++; + } else { + prec = 0; + str = (const byte*)str_to_int((const char*)str, (const char*)top, &prec); + } + } + } + + if (str >= top) { +incomplete_format: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + mp_raise_ValueError("incomplete format"); + } + } + + // Tuple value lookup + if (arg == MP_OBJ_NULL) { + if (arg_i >= n_args) { +not_enough_args: + mp_raise_TypeError("format string needs more arguments"); + } + arg = args[arg_i++]; + } + switch (*str) { + case 'c': + if (MP_OBJ_IS_STR(arg)) { + size_t slen; + const char *s = mp_obj_str_get_data(arg, &slen); + if (slen != 1) { + mp_raise_TypeError("%%c needs int or char"); + } + mp_print_strn(&print, s, 1, flags, ' ', width); + } else if (arg_looks_integer(arg)) { + char ch = mp_obj_get_int(arg); + mp_print_strn(&print, &ch, 1, flags, ' ', width); + } else { + mp_raise_TypeError("integer needed"); + } + break; + + case 'd': + case 'i': + case 'u': + mp_print_mp_int(&print, arg_as_int(arg), 10, 'a', flags, fill, width, prec); + break; + +#if MICROPY_PY_BUILTINS_FLOAT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + mp_print_float(&print, mp_obj_get_float(arg), *str, flags, fill, width, prec); + break; +#endif + + case 'o': + if (alt) { + flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER); + } + mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, prec); + break; + + case 'r': + case 's': + { + vstr_t arg_vstr; + mp_print_t arg_print; + vstr_init_print(&arg_vstr, 16, &arg_print); + mp_print_kind_t print_kind = (*str == 'r' ? PRINT_REPR : PRINT_STR); + if (print_kind == PRINT_STR && is_bytes && MP_OBJ_IS_TYPE(arg, &mp_type_bytes)) { + // If we have something like b"%s" % b"1", bytes arg should be + // printed undecorated. + print_kind = PRINT_RAW; + } + mp_obj_print_helper(&arg_print, arg, print_kind); + uint vlen = arg_vstr.len; + if (prec < 0) { + prec = vlen; + } + if (vlen > (uint)prec) { + vlen = prec; + } + mp_print_strn(&print, arg_vstr.buf, vlen, flags, ' ', width); + vstr_clear(&arg_vstr); + break; + } + + case 'X': + case 'x': + mp_print_mp_int(&print, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec); + break; + + default: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + terse_str_format_value_error(); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unsupported format character '%c' (0x%x) at index %d", + *str, *str, str - start_str)); + } + } + } + + if (arg_i != n_args) { + mp_raise_TypeError("format string didn't convert all arguments"); + } + + return mp_obj_new_str_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr); +} +#endif + +// The implementation is optimized, returning the original string if there's +// nothing to replace. +STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + + mp_int_t max_rep = -1; + if (n_args == 4) { + max_rep = mp_obj_get_int(args[3]); + if (max_rep == 0) { + return args[0]; + } else if (max_rep < 0) { + max_rep = -1; + } + } + + // if max_rep is still -1 by this point we will need to do all possible replacements + + // check argument types + + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + + if (mp_obj_get_type(args[1]) != self_type) { + bad_implicit_conversion(args[1]); + } + + if (mp_obj_get_type(args[2]) != self_type) { + bad_implicit_conversion(args[2]); + } + + // extract string data + + GET_STR_DATA_LEN(args[0], str, str_len); + GET_STR_DATA_LEN(args[1], old, old_len); + GET_STR_DATA_LEN(args[2], new, new_len); + + // old won't exist in str if it's longer, so nothing to replace + if (old_len > str_len) { + return args[0]; + } + + // data for the replaced string + byte *data = NULL; + vstr_t vstr; + + // do 2 passes over the string: + // first pass computes the required length of the replaced string + // second pass does the replacements + for (;;) { + size_t replaced_str_index = 0; + size_t num_replacements_done = 0; + const byte *old_occurrence; + const byte *offset_ptr = str; + size_t str_len_remain = str_len; + if (old_len == 0) { + // if old_str is empty, copy new_str to start of replaced string + // copy the replacement string + if (data != NULL) { + memcpy(data, new, new_len); + } + replaced_str_index += new_len; + num_replacements_done++; + } + while (num_replacements_done != (size_t)max_rep && str_len_remain > 0 && (old_occurrence = find_subbytes(offset_ptr, str_len_remain, old, old_len, 1)) != NULL) { + if (old_len == 0) { + old_occurrence += 1; + } + // copy from just after end of last occurrence of to-be-replaced string to right before start of next occurrence + if (data != NULL) { + memcpy(data + replaced_str_index, offset_ptr, old_occurrence - offset_ptr); + } + replaced_str_index += old_occurrence - offset_ptr; + // copy the replacement string + if (data != NULL) { + memcpy(data + replaced_str_index, new, new_len); + } + replaced_str_index += new_len; + offset_ptr = old_occurrence + old_len; + str_len_remain = str + str_len - offset_ptr; + num_replacements_done++; + } + + // copy from just after end of last occurrence of to-be-replaced string to end of old string + if (data != NULL) { + memcpy(data + replaced_str_index, offset_ptr, str_len_remain); + } + replaced_str_index += str_len_remain; + + if (data == NULL) { + // first pass + if (num_replacements_done == 0) { + // no substr found, return original string + return args[0]; + } else { + // substr found, allocate new string + vstr_init_len(&vstr, replaced_str_index); + data = (byte*)vstr.buf; + assert(data != NULL); + } + } else { + // second pass, we are done + break; + } + } + + return mp_obj_new_str_from_vstr(self_type, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); + +#if MICROPY_PY_BUILTINS_STR_COUNT +STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { + const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); + + // check argument type + if (mp_obj_get_type(args[1]) != self_type) { + bad_implicit_conversion(args[1]); + } + + GET_STR_DATA_LEN(args[0], haystack, haystack_len); + GET_STR_DATA_LEN(args[1], needle, needle_len); + + const byte *start = haystack; + const byte *end = haystack + haystack_len; + if (n_args >= 3 && args[2] != mp_const_none) { + start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true); + } + if (n_args >= 4 && args[3] != mp_const_none) { + end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true); + } + + // if needle_len is zero then we count each gap between characters as an occurrence + if (needle_len == 0) { + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1); + } + + // count the occurrences + mp_int_t num_occurrences = 0; + for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) { + if (memcmp(haystack_ptr, needle, needle_len) == 0) { + num_occurrences++; + haystack_ptr += needle_len; + } else { + haystack_ptr = utf8_next_char(haystack_ptr); + } + } + + return MP_OBJ_NEW_SMALL_INT(num_occurrences); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); +#endif + +#if MICROPY_PY_BUILTINS_STR_PARTITION +STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, int direction) { + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_obj_type_t *self_type = mp_obj_get_type(self_in); + if (self_type != mp_obj_get_type(arg)) { + bad_implicit_conversion(arg); + } + + GET_STR_DATA_LEN(self_in, str, str_len); + GET_STR_DATA_LEN(arg, sep, sep_len); + + if (sep_len == 0) { + mp_raise_ValueError("empty separator"); + } + + mp_obj_t result[3]; + if (self_type == &mp_type_str) { + result[0] = MP_OBJ_NEW_QSTR(MP_QSTR_); + result[1] = MP_OBJ_NEW_QSTR(MP_QSTR_); + result[2] = MP_OBJ_NEW_QSTR(MP_QSTR_); + } else { + result[0] = mp_const_empty_bytes; + result[1] = mp_const_empty_bytes; + result[2] = mp_const_empty_bytes; + } + + if (direction > 0) { + result[0] = self_in; + } else { + result[2] = self_in; + } + + const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction); + if (position_ptr != NULL) { + size_t position = position_ptr - str; + result[0] = mp_obj_new_str_of_type(self_type, str, position); + result[1] = arg; + result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len); + } + + return mp_obj_new_tuple(3, result); +} + +STATIC mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) { + return str_partitioner(self_in, arg, 1); +} +MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); + +STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) { + return str_partitioner(self_in, arg, -1); +} +MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); +#endif + +// Supposedly not too critical operations, so optimize for code size +STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) { + GET_STR_DATA_LEN(self_in, self_data, self_len); + vstr_t vstr; + vstr_init_len(&vstr, self_len); + byte *data = (byte*)vstr.buf; + for (size_t i = 0; i < self_len; i++) { + *data++ = op(*self_data++); + } + return mp_obj_new_str_from_vstr(mp_obj_get_type(self_in), &vstr); +} + +STATIC mp_obj_t str_lower(mp_obj_t self_in) { + return str_caseconv(unichar_tolower, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); + +STATIC mp_obj_t str_upper(mp_obj_t self_in) { + return str_caseconv(unichar_toupper, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); + +STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) { + GET_STR_DATA_LEN(self_in, self_data, self_len); + + if (self_len == 0) { + return mp_const_false; // default to False for empty str + } + + if (f != unichar_isupper && f != unichar_islower) { + for (size_t i = 0; i < self_len; i++) { + if (!f(*self_data++)) { + return mp_const_false; + } + } + } else { + bool contains_alpha = false; + + for (size_t i = 0; i < self_len; i++) { // only check alphanumeric characters + if (unichar_isalpha(*self_data++)) { + contains_alpha = true; + if (!f(*(self_data - 1))) { // -1 because we already incremented above + return mp_const_false; + } + } + } + + if (!contains_alpha) { + return mp_const_false; + } + } + + return mp_const_true; +} + +STATIC mp_obj_t str_isspace(mp_obj_t self_in) { + return str_uni_istype(unichar_isspace, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); + +STATIC mp_obj_t str_isalpha(mp_obj_t self_in) { + return str_uni_istype(unichar_isalpha, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha); + +STATIC mp_obj_t str_isdigit(mp_obj_t self_in) { + return str_uni_istype(unichar_isdigit, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit); + +STATIC mp_obj_t str_isupper(mp_obj_t self_in) { + return str_uni_istype(unichar_isupper, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper); + +STATIC mp_obj_t str_islower(mp_obj_t self_in) { + return str_uni_istype(unichar_islower, self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); + +#if MICROPY_CPYTHON_COMPAT +// These methods are superfluous in the presence of str() and bytes() +// constructors. +// TODO: should accept kwargs too +STATIC mp_obj_t bytes_decode(size_t n_args, const mp_obj_t *args) { + mp_obj_t new_args[2]; + if (n_args == 1) { + new_args[0] = args[0]; + new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8); + args = new_args; + n_args++; + } + return mp_obj_str_make_new(&mp_type_str, n_args, 0, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode); + +// TODO: should accept kwargs too +STATIC mp_obj_t str_encode(size_t n_args, const mp_obj_t *args) { + mp_obj_t new_args[2]; + if (n_args == 1) { + new_args[0] = args[0]; + new_args[1] = MP_OBJ_NEW_QSTR(MP_QSTR_utf_hyphen_8); + args = new_args; + n_args++; + } + return bytes_make_new(NULL, n_args, 0, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode); +#endif + +mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + if (flags == MP_BUFFER_READ) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + bufinfo->buf = (void*)str_data; + bufinfo->len = str_len; + bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access + return 0; + } else { + // can't write to a string + bufinfo->buf = NULL; + bufinfo->len = 0; + bufinfo->typecode = -1; + return 1; + } +} + +STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = { +#if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&bytes_decode_obj) }, + #if !MICROPY_PY_BUILTINS_STR_UNICODE + // If we have separate unicode type, then here we have methods only + // for bytes type, and it should not have encode() methods. Otherwise, + // we have non-compliant-but-practical bytestring type, which shares + // method table with bytes, so they both have encode() and decode() + // methods (which should do type checking at runtime). + { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) }, + #endif +#endif + { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) }, + { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) }, + { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) }, + { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) }, + #if MICROPY_PY_BUILTINS_STR_SPLITLINES + { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) }, + { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) }, + { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) }, + { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) }, + { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) }, + { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) }, + { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, + { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, + #if MICROPY_PY_BUILTINS_STR_COUNT + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, + #endif + #if MICROPY_PY_BUILTINS_STR_PARTITION + { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, + { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, + #endif + #if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, + { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, + { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, + { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) }, + { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) }, + { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) }, + { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(str8_locals_dict, str8_locals_dict_table); + +#if !MICROPY_PY_BUILTINS_STR_UNICODE +STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); + +const mp_obj_type_t mp_type_str = { + { &mp_type_type }, + .name = MP_QSTR_str, + .print = str_print, + .make_new = mp_obj_str_make_new, + .binary_op = mp_obj_str_binary_op, + .subscr = bytes_subscr, + .getiter = mp_obj_new_str_iterator, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&str8_locals_dict, +}; +#endif + +// Reuses most of methods from str +const mp_obj_type_t mp_type_bytes = { + { &mp_type_type }, + .name = MP_QSTR_bytes, + .print = str_print, + .make_new = bytes_make_new, + .binary_op = mp_obj_str_binary_op, + .subscr = bytes_subscr, + .getiter = mp_obj_new_bytes_iterator, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&str8_locals_dict, +}; + +// The zero-length bytes object, with data that includes a null-terminating byte +const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte*)""}; + +// Create a str/bytes object using the given data. New memory is allocated and +// the data is copied across. This function should only be used if the type is bytes, +// or if the type is str and the string data is known to be not interned. +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len) { + mp_obj_str_t *o = m_new_obj(mp_obj_str_t); + o->base.type = type; + o->len = len; + if (data) { + o->hash = qstr_compute_hash(data, len); + byte *p = m_new(byte, len + 1); + o->data = p; + memcpy(p, data, len * sizeof(byte)); + p[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings + } + return MP_OBJ_FROM_PTR(o); +} + +// Create a str/bytes object using the given data. If the type is str and the string +// data is already interned, then a qstr object is returned. Otherwise new memory is +// allocated for the object and the data is copied across. +mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { + if (type == &mp_type_str) { + return mp_obj_new_str((const char*)data, len); + } else { + return mp_obj_new_bytes(data, len); + } +} + +// Create a str using a qstr to store the data; may use existing or new qstr. +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { + return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +} + +// Create a str/bytes object from the given vstr. The vstr buffer is resized to +// the exact length required and then reused for the str/bytes object. The vstr +// is cleared and can safely be passed to vstr_free if it was heap allocated. +mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { + // if not a bytes object, look if a qstr with this data already exists + if (type == &mp_type_str) { + qstr q = qstr_find_strn(vstr->buf, vstr->len); + if (q != MP_QSTR_NULL) { + vstr_clear(vstr); + vstr->alloc = 0; + return MP_OBJ_NEW_QSTR(q); + } + } + + // make a new str/bytes object + mp_obj_str_t *o = m_new_obj(mp_obj_str_t); + o->base.type = type; + o->len = vstr->len; + o->hash = qstr_compute_hash((byte*)vstr->buf, vstr->len); + if (vstr->len + 1 == vstr->alloc) { + o->data = (byte*)vstr->buf; + } else { + o->data = (byte*)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1); + } + ((byte*)o->data)[o->len] = '\0'; // add null byte + vstr->buf = NULL; + vstr->alloc = 0; + return MP_OBJ_FROM_PTR(o); +} + +mp_obj_t mp_obj_new_str(const char* data, size_t len) { + qstr q = qstr_find_strn(data, len); + if (q != MP_QSTR_NULL) { + // qstr with this data already exists + return MP_OBJ_NEW_QSTR(q); + } else { + // no existing qstr, don't make one + return mp_obj_new_str_copy(&mp_type_str, (const byte*)data, len); + } +} + +mp_obj_t mp_obj_str_intern(mp_obj_t str) { + GET_STR_DATA_LEN(str, data, len); + return mp_obj_new_str_via_qstr((const char*)data, len); +} + +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) { + size_t len; + const char *data = mp_obj_str_get_data(obj, &len); + return mp_obj_new_str_via_qstr((const char*)data, len); +} + +mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { + return mp_obj_new_str_copy(&mp_type_bytes, data, len); +} + +bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { + if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) { + return s1 == s2; + } else { + GET_STR_HASH(s1, h1); + GET_STR_HASH(s2, h2); + // If any of hashes is 0, it means it's not valid + if (h1 != 0 && h2 != 0 && h1 != h2) { + return false; + } + GET_STR_DATA_LEN(s1, d1, l1); + GET_STR_DATA_LEN(s2, d2, l2); + if (l1 != l2) { + return false; + } + return memcmp(d1, d2, l1) == 0; + } +} + +STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("can't convert to str implicitly"); + } else { + const qstr src_name = mp_obj_get_type(self_in)->name; + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "can't convert '%q' object to %q implicitly", + src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str)); + } +} + +// use this if you will anyway convert the string to a qstr +// will be more efficient for the case where it's already a qstr +qstr mp_obj_str_get_qstr(mp_obj_t self_in) { + if (MP_OBJ_IS_QSTR(self_in)) { + return MP_OBJ_QSTR_VALUE(self_in); + } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_str)) { + mp_obj_str_t *self = MP_OBJ_TO_PTR(self_in); + return qstr_from_strn((char*)self->data, self->len); + } else { + bad_implicit_conversion(self_in); + } +} + +// only use this function if you need the str data to be zero terminated +// at the moment all strings are zero terminated to help with C ASCIIZ compatibility +const char *mp_obj_str_get_str(mp_obj_t self_in) { + if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + GET_STR_DATA_LEN(self_in, s, l); + (void)l; // len unused + return (const char*)s; + } else { + bad_implicit_conversion(self_in); + } +} + +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { + if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { + GET_STR_DATA_LEN(self_in, s, l); + *len = l; + return (const char*)s; + } else { + bad_implicit_conversion(self_in); + } +} + +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len) { + if (MP_OBJ_IS_QSTR(self_in)) { + return qstr_data(MP_OBJ_QSTR_VALUE(self_in), len); + } else { + *len = ((mp_obj_str_t*)self_in)->len; + return ((mp_obj_str_t*)self_in)->data; + } +} +#endif + +/******************************************************************************/ +/* str iterator */ + +typedef struct _mp_obj_str8_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t str; + size_t cur; +} mp_obj_str8_it_t; + +#if !MICROPY_PY_BUILTINS_STR_UNICODE +STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { + mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); + GET_STR_DATA_LEN(self->str, str, len); + if (self->cur < len) { + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)str + self->cur, 1); + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = str_it_iternext; + o->str = str; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} +#endif + +STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) { + mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); + GET_STR_DATA_LEN(self->str, str, len); + if (self->cur < len) { + mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]); + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_str8_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_str8_it_t *o = (mp_obj_str8_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = bytes_it_iternext; + o->str = str; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objstr.h b/src/openmv/src/micropython/py/objstr.h new file mode 100755 index 0000000..4e55cad --- /dev/null +++ b/src/openmv/src/micropython/py/objstr.h @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJSTR_H +#define MICROPY_INCLUDED_PY_OBJSTR_H + +#include "py/obj.h" + +typedef struct _mp_obj_str_t { + mp_obj_base_t base; + mp_uint_t hash; + // len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte + size_t len; + const byte *data; +} mp_obj_str_t; + +#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str} + +// use this macro to extract the string hash +// warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data +#define GET_STR_HASH(str_obj_in, str_hash) \ + mp_uint_t str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->hash; } + +// use this macro to extract the string length +#define GET_STR_LEN(str_obj_in, str_len) \ + size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; } + +// use this macro to extract the string data and length +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +const byte *mp_obj_str_get_data_no_check(mp_obj_t self_in, size_t *len); +#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ + size_t str_len; const byte *str_data = mp_obj_str_get_data_no_check(str_obj_in, &str_len); +#else +#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ + const byte *str_data; size_t str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \ + else { str_len = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->len; str_data = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->data; } +#endif + +mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len); +mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); +mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len); +mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len); + +mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); +mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); + +const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, + mp_obj_t index, bool is_slice); +const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction); + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_join_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_splitlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_format_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_partition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_center_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_lower_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_upper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isspace_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); + +#endif // MICROPY_INCLUDED_PY_OBJSTR_H diff --git a/src/openmv/src/micropython/py/objstringio.c b/src/openmv/src/micropython/py/objstringio.c new file mode 100755 index 0000000..b405ee2 --- /dev/null +++ b/src/openmv/src/micropython/py/objstringio.c @@ -0,0 +1,277 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objstr.h" +#include "py/objstringio.h" +#include "py/runtime.h" +#include "py/stream.h" + +#if MICROPY_PY_IO + +#if MICROPY_CPYTHON_COMPAT +STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { + if (o->vstr == NULL) { + mp_raise_ValueError("I/O operation on closed file"); + } +} +#else +#define check_stringio_is_open(o) +#endif + +STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, self->base.type == &mp_type_stringio ? "" : "", self); +} + +STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + (void)errcode; + mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); + check_stringio_is_open(o); + if (o->vstr->len <= o->pos) { // read to EOF, or seeked to EOF or beyond + return 0; + } + mp_uint_t remaining = o->vstr->len - o->pos; + if (size > remaining) { + size = remaining; + } + memcpy(buf, o->vstr->buf + o->pos, size); + o->pos += size; + return size; +} + +STATIC void stringio_copy_on_write(mp_obj_stringio_t *o) { + const void *buf = o->vstr->buf; + o->vstr->buf = m_new(char, o->vstr->len); + memcpy(o->vstr->buf, buf, o->vstr->len); + o->vstr->fixed_buf = false; + o->ref_obj = MP_OBJ_NULL; +} + +STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + (void)errcode; + mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); + check_stringio_is_open(o); + + if (o->vstr->fixed_buf) { + stringio_copy_on_write(o); + } + + mp_uint_t new_pos = o->pos + size; + if (new_pos < size) { + // Writing bytes will overflow o->pos beyond limit of mp_uint_t. + *errcode = MP_EFBIG; + return MP_STREAM_ERROR; + } + mp_uint_t org_len = o->vstr->len; + if (new_pos > o->vstr->alloc) { + // Take all what's already allocated... + o->vstr->len = o->vstr->alloc; + // ... and add more + vstr_add_len(o->vstr, new_pos - o->vstr->alloc); + } + // If there was a seek past EOF, clear the hole + if (o->pos > org_len) { + memset(o->vstr->buf + org_len, 0, o->pos - org_len); + } + memcpy(o->vstr->buf + o->pos, buf, size); + o->pos = new_pos; + if (new_pos > o->vstr->len) { + o->vstr->len = new_pos; + } + return size; +} + +STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in); + switch (request) { + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + mp_uint_t ref = 0; + switch (s->whence) { + case MP_SEEK_CUR: + ref = o->pos; + break; + case MP_SEEK_END: + ref = o->vstr->len; + break; + } + mp_uint_t new_pos = ref + s->offset; + + // For MP_SEEK_SET, offset is unsigned + if (s->whence != MP_SEEK_SET && s->offset < 0) { + if (new_pos > ref) { + // Negative offset from SEEK_CUR or SEEK_END went past 0. + // CPython sets position to 0, POSIX returns an EINVAL error + new_pos = 0; + } + } else if (new_pos < ref) { + // positive offset went beyond the limit of mp_uint_t + *errcode = MP_EINVAL; // replace with MP_EOVERFLOW when defined + return MP_STREAM_ERROR; + } + s->offset = o->pos = new_pos; + return 0; + } + case MP_STREAM_FLUSH: + return 0; + case MP_STREAM_CLOSE: + #if MICROPY_CPYTHON_COMPAT + vstr_free(o->vstr); + o->vstr = NULL; + #else + vstr_clear(o->vstr); + o->vstr->alloc = 0; + o->vstr->len = 0; + o->pos = 0; + #endif + return 0; + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes) + +STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { + mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); + check_stringio_is_open(self); + // TODO: Try to avoid copying string + return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); + +STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); + +STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) { + mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); + o->base.type = type; + o->pos = 0; + o->ref_obj = MP_OBJ_NULL; + return o; +} + +STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)n_kw; // TODO check n_kw==0 + + mp_uint_t sz = 16; + bool initdata = false; + mp_buffer_info_t bufinfo; + + mp_obj_stringio_t *o = stringio_new(type_in); + + if (n_args > 0) { + if (MP_OBJ_IS_INT(args[0])) { + sz = mp_obj_get_int(args[0]); + } else { + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + + if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { + o->vstr = m_new_obj(vstr_t); + vstr_init_fixed_buf(o->vstr, bufinfo.len, bufinfo.buf); + o->vstr->len = bufinfo.len; + o->ref_obj = args[0]; + return MP_OBJ_FROM_PTR(o); + } + + sz = bufinfo.len; + initdata = true; + } + } + + o->vstr = vstr_new(sz); + + if (initdata) { + stringio_write(MP_OBJ_FROM_PTR(o), bufinfo.buf, bufinfo.len, NULL); + // Cur ptr is always at the beginning of buffer at the construction + o->pos = 0; + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table); + +STATIC const mp_stream_p_t stringio_stream_p = { + .read = stringio_read, + .write = stringio_write, + .ioctl = stringio_ioctl, + .is_text = true, +}; + +STATIC const mp_stream_p_t bytesio_stream_p = { + .read = stringio_read, + .write = stringio_write, + .ioctl = stringio_ioctl, +}; + +const mp_obj_type_t mp_type_stringio = { + { &mp_type_type }, + .name = MP_QSTR_StringIO, + .print = stringio_print, + .make_new = stringio_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &stringio_stream_p, + .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, +}; + +#if MICROPY_PY_IO_BYTESIO +const mp_obj_type_t mp_type_bytesio = { + { &mp_type_type }, + .name = MP_QSTR_BytesIO, + .print = stringio_print, + .make_new = stringio_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &bytesio_stream_p, + .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict, +}; +#endif + +#endif diff --git a/src/openmv/src/micropython/py/objstringio.h b/src/openmv/src/micropython/py/objstringio.h new file mode 100755 index 0000000..56738f4 --- /dev/null +++ b/src/openmv/src/micropython/py/objstringio.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJSTRINGIO_H +#define MICROPY_INCLUDED_PY_OBJSTRINGIO_H + +#include "py/obj.h" + +typedef struct _mp_obj_stringio_t { + mp_obj_base_t base; + vstr_t *vstr; + // StringIO has single pointer used for both reading and writing + mp_uint_t pos; + // Underlying object buffered by this StringIO + mp_obj_t ref_obj; +} mp_obj_stringio_t; + +#endif // MICROPY_INCLUDED_PY_OBJSTRINGIO_H diff --git a/src/openmv/src/micropython/py/objstrunicode.c b/src/openmv/src/micropython/py/objstrunicode.c new file mode 100755 index 0000000..13da922 --- /dev/null +++ b/src/openmv/src/micropython/py/objstrunicode.c @@ -0,0 +1,314 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objstr.h" +#include "py/objlist.h" +#include "py/runtime.h" + +#if MICROPY_PY_BUILTINS_STR_UNICODE + +STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); + +/******************************************************************************/ +/* str */ + +STATIC void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) { + // this escapes characters, but it will be very slow to print (calling print many times) + bool has_single_quote = false; + bool has_double_quote = false; + for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { + if (*s == '\'') { + has_single_quote = true; + } else if (*s == '"') { + has_double_quote = true; + } + } + unichar quote_char = '\''; + if (has_single_quote && !has_double_quote) { + quote_char = '"'; + } + mp_printf(print, "%c", quote_char); + const byte *s = str_data, *top = str_data + str_len; + while (s < top) { + unichar ch; + ch = utf8_get_char(s); + s = utf8_next_char(s); + if (ch == quote_char) { + mp_printf(print, "\\%c", quote_char); + } else if (ch == '\\') { + mp_print_str(print, "\\\\"); + } else if (32 <= ch && ch <= 126) { + mp_printf(print, "%c", ch); + } else if (ch == '\n') { + mp_print_str(print, "\\n"); + } else if (ch == '\r') { + mp_print_str(print, "\\r"); + } else if (ch == '\t') { + mp_print_str(print, "\\t"); + } else if (ch < 0x100) { + mp_printf(print, "\\x%02x", ch); + } else if (ch < 0x10000) { + mp_printf(print, "\\u%04x", ch); + } else { + mp_printf(print, "\\U%08x", ch); + } + } + mp_printf(print, "%c", quote_char); +} + +STATIC void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + #if MICROPY_PY_UJSON + if (kind == PRINT_JSON) { + mp_str_print_json(print, str_data, str_len); + return; + } + #endif + if (kind == PRINT_STR) { + mp_printf(print, "%.*s", str_len, str_data); + } else { + uni_print_quoted(print, str_data, str_len); + } +} + +STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(str_len != 0); + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len)); + default: + return MP_OBJ_NULL; // op not supported + } +} + +// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or +// be capped to the first/last character of the string, depending on is_slice. +const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, + mp_obj_t index, bool is_slice) { + // All str functions also handle bytes objects, and they call str_index_to_ptr(), + // so it must handle bytes. + if (type == &mp_type_bytes) { + // Taken from objstr.c:str_index_to_ptr() + size_t index_val = mp_get_index(type, self_len, index, is_slice); + return self_data + index_val; + } + + mp_int_t i; + // Copied from mp_get_index; I don't want bounds checking, just give me + // the integer as-is. (I can't bounds-check without scanning the whole + // string; an out-of-bounds index will be caught in the loops below.) + if (MP_OBJ_IS_SMALL_INT(index)) { + i = MP_OBJ_SMALL_INT_VALUE(index); + } else if (!mp_obj_get_int_maybe(index, &i)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); + } + const byte *s, *top = self_data + self_len; + if (i < 0) + { + // Negative indexing is performed by counting from the end of the string. + for (s = top - 1; i; --s) { + if (s < self_data) { + if (is_slice) { + return self_data; + } + mp_raise_msg(&mp_type_IndexError, "string index out of range"); + } + if (!UTF8_IS_CONT(*s)) { + ++i; + } + } + ++s; + } else { + // Positive indexing, correspondingly, counts from the start of the string. + // It's assumed that negative indexing will generally be used with small + // absolute values (eg str[-1], not str[-1000000]), which means it'll be + // more efficient this way. + s = self_data; + while (1) { + // First check out-of-bounds + if (s >= top) { + if (is_slice) { + return top; + } + mp_raise_msg(&mp_type_IndexError, "string index out of range"); + } + // Then check completion + if (i-- == 0) { + break; + } + // Then skip UTF-8 char + ++s; + while (UTF8_IS_CONT(*s)) { + ++s; + } + } + } + return s; +} + +STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + assert(type == &mp_type_str); + GET_STR_DATA_LEN(self_in, self_data, self_len); + if (value == MP_OBJ_SENTINEL) { + // load +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_obj_t ostart, ostop, ostep; + mp_obj_slice_get(index, &ostart, &ostop, &ostep); + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { + mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + } + + const byte *pstart, *pstop; + if (ostart != mp_const_none) { + pstart = str_index_to_ptr(type, self_data, self_len, ostart, true); + } else { + pstart = self_data; + } + if (ostop != mp_const_none) { + // pstop will point just after the stop character. This depends on + // the \0 at the end of the string. + pstop = str_index_to_ptr(type, self_data, self_len, ostop, true); + } else { + pstop = self_data + self_len; + } + if (pstop < pstart) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); + } + return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart); + } +#endif + const byte *s = str_index_to_ptr(type, self_data, self_len, index, false); + int len = 1; + if (UTF8_IS_NONASCII(*s)) { + // Count the number of 1 bits (after the first) + for (char mask = 0x40; *s & mask; mask >>= 1) { + ++len; + } + } + return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { +#if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) }, +#endif + { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) }, + { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_rindex), MP_ROM_PTR(&str_rindex_obj) }, + { MP_ROM_QSTR(MP_QSTR_join), MP_ROM_PTR(&str_join_obj) }, + { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&str_split_obj) }, + #if MICROPY_PY_BUILTINS_STR_SPLITLINES + { MP_ROM_QSTR(MP_QSTR_splitlines), MP_ROM_PTR(&str_splitlines_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_rsplit), MP_ROM_PTR(&str_rsplit_obj) }, + { MP_ROM_QSTR(MP_QSTR_startswith), MP_ROM_PTR(&str_startswith_obj) }, + { MP_ROM_QSTR(MP_QSTR_endswith), MP_ROM_PTR(&str_endswith_obj) }, + { MP_ROM_QSTR(MP_QSTR_strip), MP_ROM_PTR(&str_strip_obj) }, + { MP_ROM_QSTR(MP_QSTR_lstrip), MP_ROM_PTR(&str_lstrip_obj) }, + { MP_ROM_QSTR(MP_QSTR_rstrip), MP_ROM_PTR(&str_rstrip_obj) }, + { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&str_format_obj) }, + { MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&str_replace_obj) }, + #if MICROPY_PY_BUILTINS_STR_COUNT + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, + #endif + #if MICROPY_PY_BUILTINS_STR_PARTITION + { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, + { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, + #endif + #if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, + { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, + { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, + { MP_ROM_QSTR(MP_QSTR_isalpha), MP_ROM_PTR(&str_isalpha_obj) }, + { MP_ROM_QSTR(MP_QSTR_isdigit), MP_ROM_PTR(&str_isdigit_obj) }, + { MP_ROM_QSTR(MP_QSTR_isupper), MP_ROM_PTR(&str_isupper_obj) }, + { MP_ROM_QSTR(MP_QSTR_islower), MP_ROM_PTR(&str_islower_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(struni_locals_dict, struni_locals_dict_table); + +const mp_obj_type_t mp_type_str = { + { &mp_type_type }, + .name = MP_QSTR_str, + .print = uni_print, + .make_new = mp_obj_str_make_new, + .unary_op = uni_unary_op, + .binary_op = mp_obj_str_binary_op, + .subscr = str_subscr, + .getiter = mp_obj_new_str_iterator, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, + .locals_dict = (mp_obj_dict_t*)&struni_locals_dict, +}; + +/******************************************************************************/ +/* str iterator */ + +typedef struct _mp_obj_str_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t str; + size_t cur; +} mp_obj_str_it_t; + +STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { + mp_obj_str_it_t *self = MP_OBJ_TO_PTR(self_in); + GET_STR_DATA_LEN(self->str, str, len); + if (self->cur < len) { + const byte *cur = str + self->cur; + const byte *end = utf8_next_char(str + self->cur); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur); + self->cur += end - cur; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_str_it_t *o = (mp_obj_str_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = str_it_iternext; + o->str = str; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + +#endif // MICROPY_PY_BUILTINS_STR_UNICODE diff --git a/src/openmv/src/micropython/py/objtuple.c b/src/openmv/src/micropython/py/objtuple.c new file mode 100755 index 0000000..34b7664 --- /dev/null +++ b/src/openmv/src/micropython/py/objtuple.c @@ -0,0 +1,292 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objtuple.h" +#include "py/runtime.h" + +/******************************************************************************/ +/* tuple */ + +void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in); + if (MICROPY_PY_UJSON && kind == PRINT_JSON) { + mp_print_str(print, "["); + } else { + mp_print_str(print, "("); + kind = PRINT_REPR; + } + for (size_t i = 0; i < o->len; i++) { + if (i > 0) { + mp_print_str(print, ", "); + } + mp_obj_print_helper(print, o->items[i], kind); + } + if (MICROPY_PY_UJSON && kind == PRINT_JSON) { + mp_print_str(print, "]"); + } else { + if (o->len == 1) { + mp_print_str(print, ","); + } + mp_print_str(print, ")"); + } +} + +STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + switch (n_args) { + case 0: + // return a empty tuple + return mp_const_empty_tuple; + + case 1: + default: { + // 1 argument, an iterable from which we make a new tuple + if (MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + return args[0]; + } + + // TODO optimise for cases where we know the length of the iterator + + size_t alloc = 4; + size_t len = 0; + mp_obj_t *items = m_new(mp_obj_t, alloc); + + mp_obj_t iterable = mp_getiter(args[0], NULL); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (len >= alloc) { + items = m_renew(mp_obj_t, items, alloc, alloc * 2); + alloc *= 2; + } + items[len++] = item; + } + + mp_obj_t tuple = mp_obj_new_tuple(len, items); + m_del(mp_obj_t, items, alloc); + + return tuple; + } + } +} + +// Don't pass MP_BINARY_OP_NOT_EQUAL here +STATIC mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { + // type check is done on getiter method to allow tuple, namedtuple, attrtuple + mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); + mp_obj_type_t *another_type = mp_obj_get_type(another_in); + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + if (another_type->getiter != mp_obj_tuple_getiter) { + // Slow path for user subclasses + another_in = mp_instance_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple)); + if (another_in == MP_OBJ_NULL) { + if (op == MP_BINARY_OP_EQUAL) { + return mp_const_false; + } + return MP_OBJ_NULL; + } + } + mp_obj_tuple_t *another = MP_OBJ_TO_PTR(another_in); + + return mp_obj_new_bool(mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len)); +} + +mp_obj_t mp_obj_tuple_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0); + case MP_UNARY_OP_HASH: { + // start hash with pointer to empty tuple, to make it fairly unique + mp_int_t hash = (mp_int_t)mp_const_empty_tuple; + for (size_t i = 0; i < self->len; i++) { + hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, self->items[i])); + } + return MP_OBJ_NEW_SMALL_INT(hash); + } + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len); + default: return MP_OBJ_NULL; // op not supported + } +} + +mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { + mp_obj_tuple_t *o = MP_OBJ_TO_PTR(lhs); + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: { + if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) { + return MP_OBJ_NULL; // op not supported + } + mp_obj_tuple_t *p = MP_OBJ_TO_PTR(rhs); + mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len + p->len, NULL)); + mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t); + return MP_OBJ_FROM_PTR(s); + } + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: { + mp_int_t n; + if (!mp_obj_get_int_maybe(rhs, &n)) { + return MP_OBJ_NULL; // op not supported + } + if (n <= 0) { + return mp_const_empty_tuple; + } + mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL)); + mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); + return MP_OBJ_FROM_PTR(s); + } + case MP_BINARY_OP_EQUAL: + case MP_BINARY_OP_LESS: + case MP_BINARY_OP_LESS_EQUAL: + case MP_BINARY_OP_MORE: + case MP_BINARY_OP_MORE_EQUAL: + return tuple_cmp_helper(op, lhs, rhs); + + default: + return MP_OBJ_NULL; // op not supported + } +} + +mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_SENTINEL) { + // load + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { + mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); + } + mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice.stop - slice.start, NULL)); + mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); + return MP_OBJ_FROM_PTR(res); + } +#endif + size_t index_value = mp_get_index(self->base.type, self->len, index, false); + return self->items[index_value]; + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + return mp_seq_count_obj(self->items, self->len, value); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count); + +STATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]); + return mp_seq_index_obj(self->items, self->len, n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tuple_index_obj, 2, 4, tuple_index); + +STATIC const mp_rom_map_elem_t tuple_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tuple_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&tuple_index_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(tuple_locals_dict, tuple_locals_dict_table); + +const mp_obj_type_t mp_type_tuple = { + { &mp_type_type }, + .name = MP_QSTR_tuple, + .print = mp_obj_tuple_print, + .make_new = mp_obj_tuple_make_new, + .unary_op = mp_obj_tuple_unary_op, + .binary_op = mp_obj_tuple_binary_op, + .subscr = mp_obj_tuple_subscr, + .getiter = mp_obj_tuple_getiter, + .locals_dict = (mp_obj_dict_t*)&tuple_locals_dict, +}; + +// the zero-length tuple +const mp_obj_tuple_t mp_const_empty_tuple_obj = {{&mp_type_tuple}, 0}; + +mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { + if (n == 0) { + return mp_const_empty_tuple; + } + mp_obj_tuple_t *o = m_new_obj_var(mp_obj_tuple_t, mp_obj_t, n); + o->base.type = &mp_type_tuple; + o->len = n; + if (items) { + for (size_t i = 0; i < n; i++) { + o->items[i] = items[i]; + } + } + return MP_OBJ_FROM_PTR(o); +} + +void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + *len = self->len; + *items = &self->items[0]; +} + +void mp_obj_tuple_del(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); + m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self); +} + +/******************************************************************************/ +/* tuple iterator */ + +typedef struct _mp_obj_tuple_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_tuple_t *tuple; + size_t cur; +} mp_obj_tuple_it_t; + +STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) { + mp_obj_tuple_it_t *self = MP_OBJ_TO_PTR(self_in); + if (self->cur < self->tuple->len) { + mp_obj_t o_out = self->tuple->items[self->cur]; + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_tuple_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_tuple_it_t *o = (mp_obj_tuple_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = tuple_it_iternext; + o->tuple = MP_OBJ_TO_PTR(o_in); + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} diff --git a/src/openmv/src/micropython/py/objtuple.h b/src/openmv/src/micropython/py/objtuple.h new file mode 100755 index 0000000..74cde88 --- /dev/null +++ b/src/openmv/src/micropython/py/objtuple.h @@ -0,0 +1,64 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJTUPLE_H +#define MICROPY_INCLUDED_PY_OBJTUPLE_H + +#include "py/obj.h" + +typedef struct _mp_obj_tuple_t { + mp_obj_base_t base; + size_t len; + mp_obj_t items[]; +} mp_obj_tuple_t; + +typedef struct _mp_rom_obj_tuple_t { + mp_obj_base_t base; + size_t len; + mp_rom_obj_t items[]; +} mp_rom_obj_tuple_t; + +void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +mp_obj_t mp_obj_tuple_unary_op(mp_unary_op_t op, mp_obj_t self_in); +mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); +mp_obj_t mp_obj_tuple_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value); +mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf); + +extern const mp_obj_type_t mp_type_attrtuple; + +#define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ + const mp_rom_obj_tuple_t tuple_obj_name = { \ + .base = {&mp_type_attrtuple}, \ + .len = nitems, \ + .items = { __VA_ARGS__ , MP_ROM_PTR((void*)fields) } \ + } + +#if MICROPY_PY_COLLECTIONS +void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_tuple_t *o); +#endif + +mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items); + +#endif // MICROPY_INCLUDED_PY_OBJTUPLE_H diff --git a/src/openmv/src/micropython/py/objtype.c b/src/openmv/src/micropython/py/objtype.c new file mode 100755 index 0000000..0881ae3 --- /dev/null +++ b/src/openmv/src/micropython/py/objtype.c @@ -0,0 +1,1392 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * Copyright (c) 2014-2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/objtype.h" +#include "py/runtime.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + +#define ENABLE_SPECIAL_ACCESSORS \ + (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) + +#define TYPE_FLAG_IS_SUBCLASSED (0x0001) +#define TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) + +STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); + +/******************************************************************************/ +// instance object + +STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { + int count = 0; + for (;;) { + if (type == &mp_type_object) { + // Not a "real" type, end search here. + return count; + } else if (mp_obj_is_native_type(type)) { + // Native types don't have parents (at least not from our perspective) so end. + *last_native_base = type; + return count + 1; + } else if (type->parent == NULL) { + // No parents so end search here. + return count; + #if MICROPY_MULTIPLE_INHERITANCE + } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { + // Multiple parents, search through them all recursively. + const mp_obj_tuple_t *parent_tuple = type->parent; + const mp_obj_t *item = parent_tuple->items; + const mp_obj_t *top = item + parent_tuple->len; + for (; item < top; ++item) { + assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item); + count += instance_count_native_bases(bt, last_native_base); + } + return count; + #endif + } else { + // A single parent, use iteration to continue the search. + type = type->parent; + } + } +} + +// This wrapper function is allows a subclass of a native type to call the +// __init__() method (corresponding to type->make_new) of the native type. +STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]); + const mp_obj_type_t *native_base = NULL; + instance_count_native_bases(self->base.type, &native_base); + self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper); + +#if !MICROPY_CPYTHON_COMPAT +STATIC +#endif +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) { + size_t num_native_bases = instance_count_native_bases(class, native_base); + assert(num_native_bases < 2); + mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, num_native_bases); + o->base.type = class; + mp_map_init(&o->members, 0); + // Initialise the native base-class slot (should be 1 at most) with a valid + // object. It doesn't matter which object, so long as it can be uniquely + // distinguished from a native class that is initialised. + if (num_native_bases != 0) { + o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + } + return o; +} + +// TODO +// This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO +// http://python-history.blogspot.com/2010/06/method-resolution-order.html +// https://www.python.org/download/releases/2.3/mro/ +// +// will keep lookup->dest[0]'s value (should be MP_OBJ_NULL on invocation) if attribute +// is not found +// will set lookup->dest[0] to MP_OBJ_SENTINEL if special method was found in a native +// type base via slot id (as specified by lookup->meth_offset). As there can be only one +// native base, it's known that it applies to instance->subobj[0]. In most cases, we also +// don't need to know which type it was - because instance->subobj[0] is of that type. +// The only exception is when object is not yet constructed, then we need to know base +// native type to construct its instance->subobj[0] from. But this case is handled via +// instance_count_native_bases(), which returns a native base which it saw. +struct class_lookup_data { + mp_obj_instance_t *obj; + qstr attr; + size_t meth_offset; + mp_obj_t *dest; + bool is_type; +}; + +STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) { + assert(lookup->dest[0] == MP_OBJ_NULL); + assert(lookup->dest[1] == MP_OBJ_NULL); + for (;;) { + DEBUG_printf("mp_obj_class_lookup: Looking up %s in %s\n", qstr_str(lookup->attr), qstr_str(type->name)); + // Optimize special method lookup for native types + // This avoids extra method_name => slot lookup. On the other hand, + // this should not be applied to class types, as will result in extra + // lookup either. + if (lookup->meth_offset != 0 && mp_obj_is_native_type(type)) { + if (*(void**)((char*)type + lookup->meth_offset) != NULL) { + DEBUG_printf("mp_obj_class_lookup: Matched special meth slot (off=%d) for %s\n", + lookup->meth_offset, qstr_str(lookup->attr)); + lookup->dest[0] = MP_OBJ_SENTINEL; + return; + } + } + + if (type->locals_dict != NULL) { + // search locals_dict (the set of methods/attributes) + assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now + mp_map_t *locals_map = &type->locals_dict->map; + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP); + if (elem != NULL) { + if (lookup->is_type) { + // If we look up a class method, we need to return original type for which we + // do a lookup, not a (base) type in which we found the class method. + const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj; + mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest); + } else { + mp_obj_instance_t *obj = lookup->obj; + mp_obj_t obj_obj; + if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) { + // If we're dealing with native base class, then it applies to native sub-object + obj_obj = obj->subobj[0]; + } else { + obj_obj = MP_OBJ_FROM_PTR(obj); + } + mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest); + } +#if DEBUG_PRINT + DEBUG_printf("mp_obj_class_lookup: Returning: "); + mp_obj_print_helper(MICROPY_DEBUG_PRINTER, lookup->dest[0], PRINT_REPR); + if (lookup->dest[1] != MP_OBJ_NULL) { + // Don't try to repr() lookup->dest[1], as we can be called recursively + DEBUG_printf(" <%s @%p>", mp_obj_get_type_str(lookup->dest[1]), MP_OBJ_TO_PTR(lookup->dest[1])); + } + DEBUG_printf("\n"); +#endif + return; + } + } + + // Previous code block takes care about attributes defined in .locals_dict, + // but some attributes of native types may be handled using .load_attr method, + // so make sure we try to lookup those too. + if (lookup->obj != NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) { + mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest); + if (lookup->dest[0] != MP_OBJ_NULL) { + return; + } + } + + // attribute not found, keep searching base classes + + if (type->parent == NULL) { + DEBUG_printf("mp_obj_class_lookup: No more parents\n"); + return; + #if MICROPY_MULTIPLE_INHERITANCE + } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { + const mp_obj_tuple_t *parent_tuple = type->parent; + const mp_obj_t *item = parent_tuple->items; + const mp_obj_t *top = item + parent_tuple->len - 1; + for (; item < top; ++item) { + assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); + if (bt == &mp_type_object) { + // Not a "real" type + continue; + } + mp_obj_class_lookup(lookup, bt); + if (lookup->dest[0] != MP_OBJ_NULL) { + return; + } + } + + // search last base (simple tail recursion elimination) + assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); + type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); + #endif + } else { + type = type->parent; + } + if (type == &mp_type_object) { + // Not a "real" type + return; + } + } +} + +STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__; + mp_obj_t member[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = self, + .attr = meth, + .meth_offset = offsetof(mp_obj_type_t, print), + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) { + // If there's no __str__, fall back to __repr__ + lookup.attr = MP_QSTR___repr__; + lookup.meth_offset = 0; + mp_obj_class_lookup(&lookup, self->base.type); + } + + if (member[0] == MP_OBJ_SENTINEL) { + // Handle Exception subclasses specially + if (mp_obj_is_native_exception_instance(self->subobj[0])) { + if (kind != PRINT_STR) { + mp_print_str(print, qstr_str(self->base.type->name)); + } + mp_obj_print_helper(print, self->subobj[0], kind | PRINT_EXC_SUBCLASS); + } else { + mp_obj_print_helper(print, self->subobj[0], kind); + } + return; + } + + if (member[0] != MP_OBJ_NULL) { + mp_obj_t r = mp_call_function_1(member[0], self_in); + mp_obj_print_helper(print, r, PRINT_STR); + return; + } + + // TODO: CPython prints fully-qualified type name + mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self); +} + +mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(mp_obj_is_instance_type(self)); + + // look for __new__ function + mp_obj_t init_fn[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = NULL, + .attr = MP_QSTR___new__, + .meth_offset = offsetof(mp_obj_type_t, make_new), + .dest = init_fn, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self); + + const mp_obj_type_t *native_base = NULL; + mp_obj_instance_t *o; + if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) { + // Either there is no __new__() method defined or there is a native + // constructor. In both cases create a blank instance. + o = mp_obj_new_instance(self, &native_base); + + // Since type->make_new() implements both __new__() and __init__() in + // one go, of which the latter may be overridden by the Python subclass, + // we defer (see the end of this function) the call of the native + // constructor to give a chance for the Python __init__() method to call + // said native constructor. + + } else { + // Call Python class __new__ function with all args to create an instance + mp_obj_t new_ret; + if (n_args == 0 && n_kw == 0) { + mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)}; + new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2); + } else { + mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw); + args2[0] = MP_OBJ_FROM_PTR(self); + memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); + new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2); + m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); + } + + // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ + // "If __new__() does not return an instance of cls, then the new + // instance's __init__() method will not be invoked." + if (mp_obj_get_type(new_ret) != self) { + return new_ret; + } + + // The instance returned by __new__() becomes the new object + o = MP_OBJ_TO_PTR(new_ret); + } + + // now call Python class __init__ function with all args + // This method has a chance to call super().__init__() to construct a + // possible native base class. + init_fn[0] = init_fn[1] = MP_OBJ_NULL; + lookup.obj = o; + lookup.attr = MP_QSTR___init__; + lookup.meth_offset = 0; + mp_obj_class_lookup(&lookup, self); + if (init_fn[0] != MP_OBJ_NULL) { + mp_obj_t init_ret; + if (n_args == 0 && n_kw == 0) { + init_ret = mp_call_method_n_kw(0, 0, init_fn); + } else { + mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw); + args2[0] = init_fn[0]; + args2[1] = init_fn[1]; + memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t)); + init_ret = mp_call_method_n_kw(n_args, n_kw, args2); + m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw); + } + if (init_ret != mp_const_none) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("__init__() should return None"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); + } + } + + } + + // If the type had a native base that was not explicitly initialised + // (constructed) by the Python __init__() method then construct it now. + if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); + } + + return MP_OBJ_FROM_PTR(o); +} + +// Qstrs for special methods are guaranteed to have a small value, so we use byte +// type to represent them. +const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = { + [MP_UNARY_OP_BOOL] = MP_QSTR___bool__, + [MP_UNARY_OP_LEN] = MP_QSTR___len__, + [MP_UNARY_OP_HASH] = MP_QSTR___hash__, + #if MICROPY_PY_ALL_SPECIAL_METHODS + [MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__, + [MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__, + [MP_UNARY_OP_INVERT] = MP_QSTR___invert__, + [MP_UNARY_OP_ABS] = MP_QSTR___abs__, + #endif + #if MICROPY_PY_SYS_GETSIZEOF + [MP_UNARY_OP_SIZEOF] = MP_QSTR___sizeof__, + #endif +}; + +STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + + #if MICROPY_PY_SYS_GETSIZEOF + if (MP_UNLIKELY(op == MP_UNARY_OP_SIZEOF)) { + // TODO: This doesn't count inherited objects (self->subobj) + const mp_obj_type_t *native_base; + size_t num_native_bases = instance_count_native_bases(mp_obj_get_type(self_in), &native_base); + + size_t sz = sizeof(*self) + sizeof(*self->subobj) * num_native_bases + + sizeof(*self->members.table) * self->members.alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + + qstr op_name = mp_unary_op_method_name[op]; + /* Still try to lookup native slot + if (op_name == 0) { + return MP_OBJ_NULL; + } + */ + mp_obj_t member[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = self, + .attr = op_name, + .meth_offset = offsetof(mp_obj_type_t, unary_op), + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_SENTINEL) { + return mp_unary_op(op, self->subobj[0]); + } else if (member[0] != MP_OBJ_NULL) { + mp_obj_t val = mp_call_function_1(member[0], self_in); + // __hash__ must return a small int + if (op == MP_UNARY_OP_HASH) { + val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val)); + } + return val; + } else { + if (op == MP_UNARY_OP_HASH) { + lookup.attr = MP_QSTR___eq__; + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_NULL) { + // https://docs.python.org/3/reference/datamodel.html#object.__hash__ + // "User-defined classes have __eq__() and __hash__() methods by default; + // with them, all objects compare unequal (except with themselves) and + // x.__hash__() returns an appropriate value such that x == y implies + // both that x is y and hash(x) == hash(y)." + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)self_in); + } + // "A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None. + // When the __hash__() method of a class is None, instances of the class will raise an appropriate TypeError" + } + + return MP_OBJ_NULL; // op not supported + } +} + +// Binary-op enum values not listed here will have the default value of 0 in the +// table, corresponding to MP_QSTR_NULL, and are therefore unsupported (a lookup will +// fail). They can be added at the expense of code size for the qstr. +// Qstrs for special methods are guaranteed to have a small value, so we use byte +// type to represent them. +const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { + [MP_BINARY_OP_LESS] = MP_QSTR___lt__, + [MP_BINARY_OP_MORE] = MP_QSTR___gt__, + [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__, + [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__, + [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__, + // MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result + [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__, + + // If an inplace method is not found a normal method will be used as a fallback + [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__, + [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__, + #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS + [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__, + [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__, + [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__, + [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__, + [MP_BINARY_OP_INPLACE_POWER] = MP_QSTR___ipow__, + [MP_BINARY_OP_INPLACE_OR] = MP_QSTR___ior__, + [MP_BINARY_OP_INPLACE_XOR] = MP_QSTR___ixor__, + [MP_BINARY_OP_INPLACE_AND] = MP_QSTR___iand__, + [MP_BINARY_OP_INPLACE_LSHIFT] = MP_QSTR___ilshift__, + [MP_BINARY_OP_INPLACE_RSHIFT] = MP_QSTR___irshift__, + #endif + + [MP_BINARY_OP_ADD] = MP_QSTR___add__, + [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__, + #if MICROPY_PY_ALL_SPECIAL_METHODS + [MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__, + [MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__, + [MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__, + [MP_BINARY_OP_MODULO] = MP_QSTR___mod__, + [MP_BINARY_OP_DIVMOD] = MP_QSTR___divmod__, + [MP_BINARY_OP_POWER] = MP_QSTR___pow__, + [MP_BINARY_OP_OR] = MP_QSTR___or__, + [MP_BINARY_OP_XOR] = MP_QSTR___xor__, + [MP_BINARY_OP_AND] = MP_QSTR___and__, + [MP_BINARY_OP_LSHIFT] = MP_QSTR___lshift__, + [MP_BINARY_OP_RSHIFT] = MP_QSTR___rshift__, + #endif + + #if MICROPY_PY_REVERSE_SPECIAL_METHODS + [MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__, + [MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__, + #if MICROPY_PY_ALL_SPECIAL_METHODS + [MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__, + [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__, + [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__, + [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__, + [MP_BINARY_OP_REVERSE_POWER] = MP_QSTR___rpow__, + [MP_BINARY_OP_REVERSE_OR] = MP_QSTR___ror__, + [MP_BINARY_OP_REVERSE_XOR] = MP_QSTR___rxor__, + [MP_BINARY_OP_REVERSE_AND] = MP_QSTR___rand__, + [MP_BINARY_OP_REVERSE_LSHIFT] = MP_QSTR___rlshift__, + [MP_BINARY_OP_REVERSE_RSHIFT] = MP_QSTR___rrshift__, + #endif + #endif +}; + +STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + // Note: For ducktyping, CPython does not look in the instance members or use + // __getattr__ or __getattribute__. It only looks in the class dictionary. + mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in); +retry:; + qstr op_name = mp_binary_op_method_name[op]; + /* Still try to lookup native slot + if (op_name == 0) { + return MP_OBJ_NULL; + } + */ + mp_obj_t dest[3] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = lhs, + .attr = op_name, + .meth_offset = offsetof(mp_obj_type_t, binary_op), + .dest = dest, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, lhs->base.type); + + mp_obj_t res; + if (dest[0] == MP_OBJ_SENTINEL) { + res = mp_binary_op(op, lhs->subobj[0], rhs_in); + } else if (dest[0] != MP_OBJ_NULL) { + dest[2] = rhs_in; + res = mp_call_method_n_kw(1, 0, dest); + } else { + // If this was an inplace method, fallback to normal method + // https://docs.python.org/3/reference/datamodel.html#object.__iadd__ : + // "If a specific method is not defined, the augmented assignment + // falls back to the normal methods." + if (op >= MP_BINARY_OP_INPLACE_OR && op <= MP_BINARY_OP_INPLACE_POWER) { + op -= MP_BINARY_OP_INPLACE_OR - MP_BINARY_OP_OR; + goto retry; + } + return MP_OBJ_NULL; // op not supported + } + + #if MICROPY_PY_BUILTINS_NOTIMPLEMENTED + // NotImplemented means "try other fallbacks (like calling __rop__ + // instead of __op__) and if nothing works, raise TypeError". As + // MicroPython doesn't implement any fallbacks, signal to raise + // TypeError right away. + if (res == mp_const_notimplemented) { + return MP_OBJ_NULL; // op not supported + } + #endif + + return res; +} + +STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + // logic: look in instance members then class locals + assert(mp_obj_is_instance_type(mp_obj_get_type(self_in))); + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + + mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem != NULL) { + // object member, always treated as a value + dest[0] = elem->value; + return; + } +#if MICROPY_CPYTHON_COMPAT + if (attr == MP_QSTR___dict__) { + // Create a new dict with a copy of the instance's map items. + // This creates, unlike CPython, a 'read-only' __dict__: modifying + // it will not result in modifications to the actual instance members. + mp_map_t *map = &self->members; + mp_obj_t attr_dict = mp_obj_new_dict(map->used); + for (size_t i = 0; i < map->alloc; ++i) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value); + } + } + dest[0] = attr_dict; + return; + } +#endif + struct class_lookup_data lookup = { + .obj = self, + .attr = attr, + .meth_offset = 0, + .dest = dest, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + mp_obj_t member = dest[0]; + if (member != MP_OBJ_NULL) { + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors to check so return straightaway + return; + } + + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + // object member is a property; delegate the load to the property + // Note: This is an optimisation for code size and execution time. + // The proper way to do it is have the functionality just below + // in a __get__ method of the property object, and then it would + // be called by the descriptor code down below. But that way + // requires overhead for the nested mp_call's and overhead for + // the code. + const mp_obj_t *proxy = mp_obj_property_get(member); + if (proxy[0] == mp_const_none) { + mp_raise_msg(&mp_type_AttributeError, "unreadable attribute"); + } else { + dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); + } + return; + } + #endif + + #if MICROPY_PY_DESCRIPTORS + // found a class attribute; if it has a __get__ method then call it with the + // class instance and class as arguments and return the result + // Note that this is functionally correct but very slow: each load_attr + // requires an extra mp_load_method_maybe to check for the __get__. + mp_obj_t attr_get_method[4]; + mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method); + if (attr_get_method[0] != MP_OBJ_NULL) { + attr_get_method[2] = self_in; + attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)); + dest[0] = mp_call_method_n_kw(2, 0, attr_get_method); + } + #endif + return; + } + + // try __getattr__ + if (attr != MP_QSTR___getattr__) { + #if MICROPY_PY_DELATTR_SETATTR + // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup + // to __getattr__. If we followed CPython's behaviour then __setattr__/__delattr__ + // would have already been found in the "object" base class. + if (attr == MP_QSTR___setattr__ || attr == MP_QSTR___delattr__) { + return; + } + #endif + + mp_obj_t dest2[3]; + mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2); + if (dest2[0] != MP_OBJ_NULL) { + // __getattr__ exists, call it and return its result + dest2[2] = MP_OBJ_NEW_QSTR(attr); + dest[0] = mp_call_method_n_kw(1, 0, dest2); + return; + } + } +} + +STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors so skip their checks + goto skip_special_accessors; + } + + #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS + // With property and/or descriptors enabled we need to do a lookup + // first in the class dict for the attribute to see if the store should + // be delegated. + mp_obj_t member[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = self, + .attr = attr, + .meth_offset = 0, + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + + if (member[0] != MP_OBJ_NULL) { + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) { + // attribute exists and is a property; delegate the store/delete + // Note: This is an optimisation for code size and execution time. + // The proper way to do it is have the functionality just below in + // a __set__/__delete__ method of the property object, and then it + // would be called by the descriptor code down below. But that way + // requires overhead for the nested mp_call's and overhead for + // the code. + const mp_obj_t *proxy = mp_obj_property_get(member[0]); + mp_obj_t dest[2] = {self_in, value}; + if (value == MP_OBJ_NULL) { + // delete attribute + if (proxy[2] == mp_const_none) { + // TODO better error message? + return false; + } else { + mp_call_function_n_kw(proxy[2], 1, 0, dest); + return true; + } + } else { + // store attribute + if (proxy[1] == mp_const_none) { + // TODO better error message? + return false; + } else { + mp_call_function_n_kw(proxy[1], 2, 0, dest); + return true; + } + } + } + #endif + + #if MICROPY_PY_DESCRIPTORS + // found a class attribute; if it has a __set__/__delete__ method then + // call it with the class instance (and value) as arguments + if (value == MP_OBJ_NULL) { + // delete attribute + mp_obj_t attr_delete_method[3]; + mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method); + if (attr_delete_method[0] != MP_OBJ_NULL) { + attr_delete_method[2] = self_in; + mp_call_method_n_kw(1, 0, attr_delete_method); + return true; + } + } else { + // store attribute + mp_obj_t attr_set_method[4]; + mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method); + if (attr_set_method[0] != MP_OBJ_NULL) { + attr_set_method[2] = self_in; + attr_set_method[3] = value; + mp_call_method_n_kw(2, 0, attr_set_method); + return true; + } + } + #endif + } + #endif + + #if MICROPY_PY_DELATTR_SETATTR + if (value == MP_OBJ_NULL) { + // delete attribute + // try __delattr__ first + mp_obj_t attr_delattr_method[3]; + mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method); + if (attr_delattr_method[0] != MP_OBJ_NULL) { + // __delattr__ exists, so call it + attr_delattr_method[2] = MP_OBJ_NEW_QSTR(attr); + mp_call_method_n_kw(1, 0, attr_delattr_method); + return true; + } + } else { + // store attribute + // try __setattr__ first + mp_obj_t attr_setattr_method[4]; + mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method); + if (attr_setattr_method[0] != MP_OBJ_NULL) { + // __setattr__ exists, so call it + attr_setattr_method[2] = MP_OBJ_NEW_QSTR(attr); + attr_setattr_method[3] = value; + mp_call_method_n_kw(2, 0, attr_setattr_method); + return true; + } + } + #endif + +skip_special_accessors: + + if (value == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return elem != NULL; + } else { + // store attribute + mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + return true; + } +} + +STATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + mp_obj_instance_load_attr(self_in, attr, dest); + } else { + if (mp_obj_instance_store_attr(self_in, attr, dest[1])) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } +} + +STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t member[4] = {MP_OBJ_NULL, MP_OBJ_NULL, index, value}; + struct class_lookup_data lookup = { + .obj = self, + .meth_offset = offsetof(mp_obj_type_t, subscr), + .dest = member, + .is_type = false, + }; + if (value == MP_OBJ_NULL) { + // delete item + lookup.attr = MP_QSTR___delitem__; + } else if (value == MP_OBJ_SENTINEL) { + // load item + lookup.attr = MP_QSTR___getitem__; + } else { + // store item + lookup.attr = MP_QSTR___setitem__; + } + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_SENTINEL) { + return mp_obj_subscr(self->subobj[0], index, value); + } else if (member[0] != MP_OBJ_NULL) { + size_t n_args = value == MP_OBJ_NULL || value == MP_OBJ_SENTINEL ? 1 : 2; + mp_obj_t ret = mp_call_method_n_kw(n_args, 0, member); + if (value == MP_OBJ_SENTINEL) { + return ret; + } else { + return mp_const_none; + } + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t mp_obj_instance_get_call(mp_obj_t self_in, mp_obj_t *member) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + struct class_lookup_data lookup = { + .obj = self, + .attr = MP_QSTR___call__, + .meth_offset = offsetof(mp_obj_type_t, call), + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + return member[0]; +} + +bool mp_obj_instance_is_callable(mp_obj_t self_in) { + mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; + return mp_obj_instance_get_call(self_in, member) != MP_OBJ_NULL; +} + +mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; + mp_obj_t call = mp_obj_instance_get_call(self_in, member); + if (call == MP_OBJ_NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object not callable"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't callable", mp_obj_get_type_str(self_in))); + } + } + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (call == MP_OBJ_SENTINEL) { + return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args); + } + + return mp_call_method_self_n_kw(member[0], member[1], n_args, n_kw, args); +} + +STATIC mp_obj_t instance_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t member[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = self, + .attr = MP_QSTR___iter__, + .meth_offset = offsetof(mp_obj_type_t, getiter), + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_NULL) { + return MP_OBJ_NULL; + } else if (member[0] == MP_OBJ_SENTINEL) { + mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); + return type->getiter(self->subobj[0], iter_buf); + } else { + return mp_call_method_n_kw(0, 0, member); + } +} + +STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t member[2] = {MP_OBJ_NULL}; + struct class_lookup_data lookup = { + .obj = self, + .attr = MP_QSTR_, // don't actually look for a method + .meth_offset = offsetof(mp_obj_type_t, buffer_p.get_buffer), + .dest = member, + .is_type = false, + }; + mp_obj_class_lookup(&lookup, self->base.type); + if (member[0] == MP_OBJ_SENTINEL) { + mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]); + return type->buffer_p.get_buffer(self->subobj[0], bufinfo, flags); + } else { + return 1; // object does not support buffer protocol + } +} + +/******************************************************************************/ +// type object +// - the struct is mp_obj_type_t and is defined in obj.h so const types can be made +// - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object +// - creating a new class (a new type) creates a new mp_obj_type_t + +#if ENABLE_SPECIAL_ACCESSORS +STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { + #if MICROPY_PY_DELATTR_SETATTR + if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) { + return true; + } + #endif + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(value, &mp_type_property)) { + return true; + } + #endif + #if MICROPY_PY_DESCRIPTORS + static const uint8_t to_check[] = { + MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, + }; + for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) { + mp_obj_t dest_temp[2]; + mp_load_method_protected(value, to_check[i], dest_temp, true); + if (dest_temp[0] != MP_OBJ_NULL) { + return true; + } + } + #endif + return false; +} +#endif + +STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->name); +} + +STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + + mp_arg_check_num(n_args, n_kw, 1, 3, false); + + switch (n_args) { + case 1: + return MP_OBJ_FROM_PTR(mp_obj_get_type(args[0])); + + case 3: + // args[0] = name + // args[1] = bases tuple + // args[2] = locals dict + return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); + + default: + mp_raise_TypeError("type takes 1 or 3 arguments"); + } +} + +STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // instantiate an instance of a class + + mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->make_new == NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("cannot create instance"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "cannot create '%q' instances", self->name)); + } + } + + // make new instance + mp_obj_t o = self->make_new(self, n_args, n_kw, args); + + // return new instance + return o; +} + +STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); + mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); + + if (dest[0] == MP_OBJ_NULL) { + // load attribute + #if MICROPY_CPYTHON_COMPAT + if (attr == MP_QSTR___name__) { + dest[0] = MP_OBJ_NEW_QSTR(self->name); + return; + } + #endif + struct class_lookup_data lookup = { + .obj = (mp_obj_instance_t*)self, + .attr = attr, + .meth_offset = 0, + .dest = dest, + .is_type = true, + }; + mp_obj_class_lookup(&lookup, self); + } else { + // delete/store attribute + + if (self->locals_dict != NULL) { + assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now + mp_map_t *locals_map = &self->locals_dict->map; + if (locals_map->is_fixed) { + // can't apply delete/store to a fixed map + return; + } + if (dest[1] == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + if (elem != NULL) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } else { + #if ENABLE_SPECIAL_ACCESSORS + // Check if we add any special accessor methods with this store + if (!(self->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) { + if (self->flags & TYPE_FLAG_IS_SUBCLASSED) { + // This class is already subclassed so can't have special accessors added + mp_raise_msg(&mp_type_AttributeError, "can't add special method to already-subclassed class"); + } + self->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + } + #endif + + // store attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + elem->value = dest[1]; + dest[0] = MP_OBJ_NULL; // indicate success + } + } + } +} + +const mp_obj_type_t mp_type_type = { + { &mp_type_type }, + .name = MP_QSTR_type, + .print = type_print, + .make_new = type_make_new, + .call = type_call, + .unary_op = mp_generic_unary_op, + .attr = type_attr, +}; + +mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { + // Verify input objects have expected type + if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { + mp_raise_TypeError(NULL); + } + if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { + mp_raise_TypeError(NULL); + } + + // TODO might need to make a copy of locals_dict; at least that's how CPython does it + + // Basic validation of base classes + uint16_t base_flags = 0; + size_t bases_len; + mp_obj_t *bases_items; + mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); + for (size_t i = 0; i < bases_len; i++) { + if (!MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)) { + mp_raise_TypeError(NULL); + } + mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); + // TODO: Verify with CPy, tested on function type + if (t->make_new == NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("type isn't an acceptable base type"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "type '%q' isn't an acceptable base type", t->name)); + } + } + #if ENABLE_SPECIAL_ACCESSORS + if (mp_obj_is_instance_type(t)) { + t->flags |= TYPE_FLAG_IS_SUBCLASSED; + base_flags |= t->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + #endif + } + + mp_obj_type_t *o = m_new0(mp_obj_type_t, 1); + o->base.type = &mp_type_type; + o->flags = base_flags; + o->name = name; + o->print = instance_print; + o->make_new = mp_obj_instance_make_new; + o->call = mp_obj_instance_call; + o->unary_op = instance_unary_op; + o->binary_op = instance_binary_op; + o->attr = mp_obj_instance_attr; + o->subscr = instance_subscr; + o->getiter = instance_getiter; + //o->iternext = ; not implemented + o->buffer_p.get_buffer = instance_get_buffer; + + if (bases_len > 0) { + // Inherit protocol from a base class. This allows to define an + // abstract base class which would translate C-level protocol to + // Python method calls, and any subclass inheriting from it will + // support this feature. + o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol; + + if (bases_len >= 2) { + #if MICROPY_MULTIPLE_INHERITANCE + o->parent = MP_OBJ_TO_PTR(bases_tuple); + #else + mp_raise_NotImplementedError("multiple inheritance not supported"); + #endif + } else { + o->parent = MP_OBJ_TO_PTR(bases_items[0]); + } + } + + o->locals_dict = MP_OBJ_TO_PTR(locals_dict); + + #if ENABLE_SPECIAL_ACCESSORS + // Check if the class has any special accessor methods + if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + for (size_t i = 0; i < o->locals_dict->map.alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) { + const mp_map_elem_t *elem = &o->locals_dict->map.table[i]; + if (check_for_special_accessors(elem->key, elem->value)) { + o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + break; + } + } + } + } + #endif + + const mp_obj_type_t *native_base; + size_t num_native_bases = instance_count_native_bases(o, &native_base); + if (num_native_bases > 1) { + mp_raise_TypeError("multiple bases have instance lay-out conflict"); + } + + mp_map_t *locals_map = &o->locals_dict->map; + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); + if (elem != NULL) { + // __new__ slot exists; check if it is a function + if (MP_OBJ_IS_FUN(elem->value)) { + // __new__ is a function, wrap it in a staticmethod decorator + elem->value = static_class_method_make_new(&mp_type_staticmethod, 1, 0, &elem->value); + } + } + + return MP_OBJ_FROM_PTR(o); +} + +/******************************************************************************/ +// super object + +typedef struct _mp_obj_super_t { + mp_obj_base_t base; + mp_obj_t type; + mp_obj_t obj; +} mp_obj_super_t; + +STATIC void super_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); + mp_print_str(print, "type, PRINT_STR); + mp_print_str(print, ", "); + mp_obj_print_helper(print, self->obj, PRINT_STR); + mp_print_str(print, ">"); +} + +STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + // 0 arguments are turned into 2 in the compiler + // 1 argument is not yet implemented + mp_arg_check_num(n_args, n_kw, 2, 2, false); + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { + mp_raise_TypeError(NULL); + } + mp_obj_super_t *o = m_new_obj(mp_obj_super_t); + *o = (mp_obj_super_t){{type_in}, args[0], args[1]}; + return MP_OBJ_FROM_PTR(o); +} + +STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super)); + mp_obj_super_t *self = MP_OBJ_TO_PTR(self_in); + + assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type)); + + mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type); + + struct class_lookup_data lookup = { + .obj = MP_OBJ_TO_PTR(self->obj), + .attr = attr, + .meth_offset = 0, + .dest = dest, + .is_type = false, + }; + + // Allow a call super().__init__() to reach any native base classes + if (attr == MP_QSTR___init__) { + lookup.meth_offset = offsetof(mp_obj_type_t, make_new); + } + + if (type->parent == NULL) { + // no parents, do nothing + #if MICROPY_MULTIPLE_INHERITANCE + } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { + const mp_obj_tuple_t *parent_tuple = type->parent; + size_t len = parent_tuple->len; + const mp_obj_t *items = parent_tuple->items; + for (size_t i = 0; i < len; i++) { + assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); + if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) { + // The "object" type will be searched at the end of this function, + // and we don't want to lookup native methods in object. + continue; + } + mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i])); + if (dest[0] != MP_OBJ_NULL) { + break; + } + } + #endif + } else if (type->parent != &mp_type_object) { + mp_obj_class_lookup(&lookup, type->parent); + } + + if (dest[0] != MP_OBJ_NULL) { + if (dest[0] == MP_OBJ_SENTINEL) { + // Looked up native __init__ so defer to it + dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + dest[1] = self->obj; + } + return; + } + + // Reset meth_offset so we don't look up any native methods in object, + // because object never takes up the native base-class slot. + lookup.meth_offset = 0; + + mp_obj_class_lookup(&lookup, &mp_type_object); +} + +const mp_obj_type_t mp_type_super = { + { &mp_type_type }, + .name = MP_QSTR_super, + .print = super_print, + .make_new = super_make_new, + .attr = super_attr, +}; + +void mp_load_super_method(qstr attr, mp_obj_t *dest) { + mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]}; + mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest); +} + +/******************************************************************************/ +// subclassing and built-ins specific to types + +// object and classinfo should be type objects +// (but the function will fail gracefully if they are not) +bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { + for (;;) { + if (object == classinfo) { + return true; + } + + // not equivalent classes, keep searching base classes + + // object should always be a type object, but just return false if it's not + if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + return false; + } + + const mp_obj_type_t *self = MP_OBJ_TO_PTR(object); + + if (self->parent == NULL) { + // type has no parents + return false; + #if MICROPY_MULTIPLE_INHERITANCE + } else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) { + // get the base objects (they should be type objects) + const mp_obj_tuple_t *parent_tuple = self->parent; + const mp_obj_t *item = parent_tuple->items; + const mp_obj_t *top = item + parent_tuple->len - 1; + + // iterate through the base objects + for (; item < top; ++item) { + if (mp_obj_is_subclass_fast(*item, classinfo)) { + return true; + } + } + + // search last base (simple tail recursion elimination) + object = *item; + #endif + } else { + // type has 1 parent + object = MP_OBJ_FROM_PTR(self->parent); + } + } +} + +STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { + size_t len; + mp_obj_t *items; + if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) { + len = 1; + items = &classinfo; + } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { + mp_obj_tuple_get(classinfo, &len, &items); + } else { + mp_raise_TypeError("issubclass() arg 2 must be a class or a tuple of classes"); + } + + for (size_t i = 0; i < len; i++) { + // We explicitly check for 'object' here since no-one explicitly derives from it + if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) { + return mp_const_true; + } + } + return mp_const_false; +} + +STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { + if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { + mp_raise_TypeError("issubclass() arg 1 must be a class"); + } + return mp_obj_is_subclass(object, classinfo); +} + +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass); + +STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) { + return mp_obj_is_subclass(MP_OBJ_FROM_PTR(mp_obj_get_type(object)), classinfo); +} + +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance); + +mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type) { + mp_obj_type_t *self_type = mp_obj_get_type(self_in); + if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(self_type), native_type)) { + return MP_OBJ_NULL; + } + mp_obj_instance_t *self = (mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in); + return self->subobj[0]; +} + +/******************************************************************************/ +// staticmethod and classmethod types (probably should go in a different file) + +STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(self == &mp_type_staticmethod || self == &mp_type_classmethod); + + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t); + *o = (mp_obj_static_class_method_t){{self}, args[0]}; + return MP_OBJ_FROM_PTR(o); +} + +const mp_obj_type_t mp_type_staticmethod = { + { &mp_type_type }, + .name = MP_QSTR_staticmethod, + .make_new = static_class_method_make_new, +}; + +const mp_obj_type_t mp_type_classmethod = { + { &mp_type_type }, + .name = MP_QSTR_classmethod, + .make_new = static_class_method_make_new, +}; diff --git a/src/openmv/src/micropython/py/objtype.h b/src/openmv/src/micropython/py/objtype.h new file mode 100755 index 0000000..3fc8c6e --- /dev/null +++ b/src/openmv/src/micropython/py/objtype.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_OBJTYPE_H +#define MICROPY_INCLUDED_PY_OBJTYPE_H + +#include "py/obj.h" + +// instance object +// creating an instance of a class makes one of these objects +typedef struct _mp_obj_instance_t { + mp_obj_base_t base; + mp_map_t members; + mp_obj_t subobj[]; + // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them +} mp_obj_instance_t; + +#if MICROPY_CPYTHON_COMPAT +// this is needed for object.__new__ +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base); +#endif + +// these need to be exposed so mp_obj_is_callable can work correctly +bool mp_obj_instance_is_callable(mp_obj_t self_in); +mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); + +#define mp_obj_is_instance_type(type) ((type)->make_new == mp_obj_instance_make_new) +#define mp_obj_is_native_type(type) ((type)->make_new != mp_obj_instance_make_new) +// this needs to be exposed for the above macros to work correctly +mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); + +#endif // MICROPY_INCLUDED_PY_OBJTYPE_H diff --git a/src/openmv/src/micropython/py/objzip.c b/src/openmv/src/micropython/py/objzip.c new file mode 100755 index 0000000..0183925 --- /dev/null +++ b/src/openmv/src/micropython/py/objzip.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objtuple.h" +#include "py/runtime.h" + +typedef struct _mp_obj_zip_t { + mp_obj_base_t base; + size_t n_iters; + mp_obj_t iters[]; +} mp_obj_zip_t; + +STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false); + + mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args); + o->base.type = type; + o->n_iters = n_args; + for (size_t i = 0; i < n_args; i++) { + o->iters[i] = mp_getiter(args[i], NULL); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); + mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); + if (self->n_iters == 0) { + return MP_OBJ_STOP_ITERATION; + } + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL)); + + for (size_t i = 0; i < self->n_iters; i++) { + mp_obj_t next = mp_iternext(self->iters[i]); + if (next == MP_OBJ_STOP_ITERATION) { + mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple)); + return MP_OBJ_STOP_ITERATION; + } + tuple->items[i] = next; + } + return MP_OBJ_FROM_PTR(tuple); +} + +const mp_obj_type_t mp_type_zip = { + { &mp_type_type }, + .name = MP_QSTR_zip, + .make_new = zip_make_new, + .getiter = mp_identity_getiter, + .iternext = zip_iternext, +}; diff --git a/src/openmv/src/micropython/py/opmethods.c b/src/openmv/src/micropython/py/opmethods.c new file mode 100755 index 0000000..247fa5b --- /dev/null +++ b/src/openmv/src/micropython/py/opmethods.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/builtin.h" + +STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + return type->subscr(self_in, key_in, MP_OBJ_SENTINEL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_op_getitem_obj, op_getitem); + +STATIC mp_obj_t op_setitem(mp_obj_t self_in, mp_obj_t key_in, mp_obj_t value_in) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + return type->subscr(self_in, key_in, value_in); +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_op_setitem_obj, op_setitem); + +STATIC mp_obj_t op_delitem(mp_obj_t self_in, mp_obj_t key_in) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + return type->subscr(self_in, key_in, MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem); + +STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) { + mp_obj_type_t *type = mp_obj_get_type(lhs_in); + return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains); diff --git a/src/openmv/src/micropython/py/parse.c b/src/openmv/src/micropython/py/parse.c new file mode 100755 index 0000000..6c5ebbe --- /dev/null +++ b/src/openmv/src/micropython/py/parse.c @@ -0,0 +1,1182 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include // for ssize_t +#include +#include + +#include "py/lexer.h" +#include "py/parse.h" +#include "py/parsenum.h" +#include "py/runtime.h" +#include "py/objint.h" +#include "py/objstr.h" +#include "py/builtin.h" + +#if MICROPY_ENABLE_COMPILER + +#define RULE_ACT_ARG_MASK (0x0f) +#define RULE_ACT_KIND_MASK (0x30) +#define RULE_ACT_ALLOW_IDENT (0x40) +#define RULE_ACT_ADD_BLANK (0x80) +#define RULE_ACT_OR (0x10) +#define RULE_ACT_AND (0x20) +#define RULE_ACT_LIST (0x30) + +#define RULE_ARG_KIND_MASK (0xf000) +#define RULE_ARG_ARG_MASK (0x0fff) +#define RULE_ARG_TOK (0x1000) +#define RULE_ARG_RULE (0x2000) +#define RULE_ARG_OPT_RULE (0x3000) + +// (un)comment to use rule names; for debugging +//#define USE_RULE_NAME (1) + +enum { +// define rules with a compile function +#define DEF_RULE(rule, comp, kind, ...) RULE_##rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + RULE_const_object, // special node for a constant, generic Python object + +// define rules without a compile function +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_##rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; + +// Define an array of actions corresponding to each rule +STATIC const uint8_t rule_act_table[] = { +#define or(n) (RULE_ACT_OR | n) +#define and(n) (RULE_ACT_AND | n) +#define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT) +#define and_blank(n) (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK) +#define one_or_more (RULE_ACT_LIST | 2) +#define list (RULE_ACT_LIST | 1) +#define list_with_end (RULE_ACT_LIST | 3) + +#define DEF_RULE(rule, comp, kind, ...) kind, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + + 0, // RULE_const_object + +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) kind, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef or +#undef and +#undef and_ident +#undef and_blank +#undef one_or_more +#undef list +#undef list_with_end +}; + +// Define the argument data for each rule, as a combined array +STATIC const uint16_t rule_arg_combined_table[] = { +#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) +#define rule(r) (RULE_ARG_RULE | RULE_##r) +#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) + +#define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) __VA_ARGS__, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef tok +#undef rule +#undef opt_rule +}; + +// Macro to create a list of N identifiers where N is the number of variable arguments to the macro +#define RULE_EXPAND(x) x +#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule)) +#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__)) +#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__ +#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, + +// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table +enum { +#define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__) +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; + +// Macro to compute the start of a rule in rule_arg_combined_table +#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule)) +#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__)) +#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13 +#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r, + +// Use the above enum values to create a table of offsets for each rule's arg +// data, which indexes rule_arg_combined_table. The offsets require 9 bits of +// storage but only the lower 8 bits are stored here. The 9th bit is computed +// in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant. +STATIC const uint8_t rule_arg_offset_table[] = { +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + 0, // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; + +// Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table +static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 = +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +0; + +#if USE_RULE_NAME +// Define an array of rule names corresponding to each rule +STATIC const char *const rule_name_table[] = { +#define DEF_RULE(rule, comp, kind, ...) #rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + "", // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) #rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; +#endif + +typedef struct _rule_stack_t { + size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number + size_t rule_id : 8; // this must be large enough to fit largest rule number + size_t arg_i; // this dictates the maximum nodes in a "list" of things +} rule_stack_t; + +typedef struct _mp_parse_chunk_t { + size_t alloc; + union { + size_t used; + struct _mp_parse_chunk_t *next; + } union_; + byte data[]; +} mp_parse_chunk_t; + +typedef struct _parser_t { + size_t rule_stack_alloc; + size_t rule_stack_top; + rule_stack_t *rule_stack; + + size_t result_stack_alloc; + size_t result_stack_top; + mp_parse_node_t *result_stack; + + mp_lexer_t *lexer; + + mp_parse_tree_t tree; + mp_parse_chunk_t *cur_chunk; + + #if MICROPY_COMP_CONST + mp_map_t consts; + #endif +} parser_t; + +STATIC const uint16_t *get_rule_arg(uint8_t r_id) { + size_t off = rule_arg_offset_table[r_id]; + if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) { + off |= 0x100; + } + return &rule_arg_combined_table[off]; +} + +STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { + // use a custom memory allocator to store parse nodes sequentially in large chunks + + mp_parse_chunk_t *chunk = parser->cur_chunk; + + if (chunk != NULL && chunk->union_.used + num_bytes > chunk->alloc) { + // not enough room at end of previously allocated chunk so try to grow + mp_parse_chunk_t *new_data = (mp_parse_chunk_t*)m_renew_maybe(byte, chunk, + sizeof(mp_parse_chunk_t) + chunk->alloc, + sizeof(mp_parse_chunk_t) + chunk->alloc + num_bytes, false); + if (new_data == NULL) { + // could not grow existing memory; shrink it to fit previous + (void)m_renew_maybe(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc, + sizeof(mp_parse_chunk_t) + chunk->union_.used, false); + chunk->alloc = chunk->union_.used; + chunk->union_.next = parser->tree.chunk; + parser->tree.chunk = chunk; + chunk = NULL; + } else { + // could grow existing memory + chunk->alloc += num_bytes; + } + } + + if (chunk == NULL) { + // no previous chunk, allocate a new chunk + size_t alloc = MICROPY_ALLOC_PARSE_CHUNK_INIT; + if (alloc < num_bytes) { + alloc = num_bytes; + } + chunk = (mp_parse_chunk_t*)m_new(byte, sizeof(mp_parse_chunk_t) + alloc); + chunk->alloc = alloc; + chunk->union_.used = 0; + parser->cur_chunk = chunk; + } + + byte *ret = chunk->data + chunk->union_.used; + chunk->union_.used += num_bytes; + return ret; +} + +STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) { + if (parser->rule_stack_top >= parser->rule_stack_alloc) { + rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC); + parser->rule_stack = rs; + parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC; + } + rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; + rs->src_line = src_line; + rs->rule_id = rule_id; + rs->arg_i = arg_i; +} + +STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { + assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE); + size_t rule_id = arg & RULE_ARG_ARG_MASK; + push_rule(parser, parser->lexer->tok_line, rule_id, 0); +} + +STATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) { + parser->rule_stack_top -= 1; + uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id; + *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; + *src_line = parser->rule_stack[parser->rule_stack_top].src_line; + return rule_id; +} + +bool mp_parse_node_is_const_false(mp_parse_node_t pn) { + return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE) + || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0); +} + +bool mp_parse_node_is_const_true(mp_parse_node_t pn) { + return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) + || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0); +} + +bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { + if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { + *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn)); + return true; + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // nodes are 32-bit pointers, but need to extract 64-bit object + *o = (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32); + #else + *o = (mp_obj_t)pns->nodes[0]; + #endif + return MP_OBJ_IS_INT(*o); + } else { + return false; + } +} + +int mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) { + if (MP_PARSE_NODE_IS_NULL(*pn)) { + *nodes = NULL; + return 0; + } else if (MP_PARSE_NODE_IS_LEAF(*pn)) { + *nodes = pn; + return 1; + } else { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)(*pn); + if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) { + *nodes = pn; + return 1; + } else { + *nodes = pns->nodes; + return MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + } + } +} + +#if MICROPY_DEBUG_PRINTERS +void mp_parse_node_print(mp_parse_node_t pn, size_t indent) { + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line); + } else { + printf(" "); + } + for (size_t i = 0; i < indent; i++) { + printf(" "); + } + if (MP_PARSE_NODE_IS_NULL(pn)) { + printf("NULL\n"); + } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { + mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn); + printf("int(" INT_FMT ")\n", arg); + } else if (MP_PARSE_NODE_IS_LEAF(pn)) { + uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn); + switch (MP_PARSE_NODE_LEAF_KIND(pn)) { + case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break; + case MP_PARSE_NODE_STRING: printf("str(%s)\n", qstr_str(arg)); break; + case MP_PARSE_NODE_BYTES: printf("bytes(%s)\n", qstr_str(arg)); break; + default: + assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN); + printf("tok(%u)\n", (uint)arg); break; + } + } else { + // node must be a mp_parse_node_struct_t + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + printf("literal const(%016llx)\n", (uint64_t)pns->nodes[0] | ((uint64_t)pns->nodes[1] << 32)); + #else + printf("literal const(%p)\n", (mp_obj_t)pns->nodes[0]); + #endif + } else { + size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + #if USE_RULE_NAME + printf("%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); + #else + printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); + #endif + for (size_t i = 0; i < n; i++) { + mp_parse_node_print(pns->nodes[i], indent + 2); + } + } + } +} +#endif // MICROPY_DEBUG_PRINTERS + +/* +STATIC void result_stack_show(parser_t *parser) { + printf("result stack, most recent first\n"); + for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) { + mp_parse_node_print(parser->result_stack[i], 0); + } +} +*/ + +STATIC mp_parse_node_t pop_result(parser_t *parser) { + assert(parser->result_stack_top > 0); + return parser->result_stack[--parser->result_stack_top]; +} + +STATIC mp_parse_node_t peek_result(parser_t *parser, size_t pos) { + assert(parser->result_stack_top > pos); + return parser->result_stack[parser->result_stack_top - 1 - pos]; +} + +STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) { + if (parser->result_stack_top >= parser->result_stack_alloc) { + mp_parse_node_t *stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MICROPY_ALLOC_PARSE_RESULT_INC); + parser->result_stack = stack; + parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC; + } + parser->result_stack[parser->result_stack_top++] = pn; +} + +STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, mp_obj_t obj) { + mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_obj_t)); + pn->source_line = src_line; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // nodes are 32-bit pointers, but need to store 64-bit object + pn->kind_num_nodes = RULE_const_object | (2 << 8); + pn->nodes[0] = (uint64_t)obj; + pn->nodes[1] = (uint64_t)obj >> 32; + #else + pn->kind_num_nodes = RULE_const_object | (1 << 8); + pn->nodes[0] = (uintptr_t)obj; + #endif + return (mp_parse_node_t)pn; +} + +STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) { + (void)parser; + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val); + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // A parse node is only 32-bits and the small-int value must fit in 31-bits + if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) { + return make_node_const_object(parser, 0, o_val); + } + #endif + return mp_parse_node_new_small_int(val); +} + +STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { + mp_parse_node_t pn; + mp_lexer_t *lex = parser->lexer; + if (lex->tok_kind == MP_TOKEN_NAME) { + qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len); + #if MICROPY_COMP_CONST + // if name is a standalone identifier, look it up in the table of dynamic constants + mp_map_elem_t *elem; + if (rule_id == RULE_atom + && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { + if (MP_OBJ_IS_SMALL_INT(elem->value)) { + pn = mp_parse_node_new_small_int_checked(parser, elem->value); + } else { + pn = make_node_const_object(parser, lex->tok_line, elem->value); + } + } else { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); + } + #else + (void)rule_id; + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); + #endif + } else if (lex->tok_kind == MP_TOKEN_INTEGER) { + mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); + if (MP_OBJ_IS_SMALL_INT(o)) { + pn = mp_parse_node_new_small_int_checked(parser, o); + } else { + pn = make_node_const_object(parser, lex->tok_line, o); + } + } else if (lex->tok_kind == MP_TOKEN_FLOAT_OR_IMAG) { + mp_obj_t o = mp_parse_num_decimal(lex->vstr.buf, lex->vstr.len, true, false, lex); + pn = make_node_const_object(parser, lex->tok_line, o); + } else if (lex->tok_kind == MP_TOKEN_STRING || lex->tok_kind == MP_TOKEN_BYTES) { + // Don't automatically intern all strings/bytes. doc strings (which are usually large) + // will be discarded by the compiler, and so we shouldn't intern them. + qstr qst = MP_QSTR_NULL; + if (lex->vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) { + // intern short strings + qst = qstr_from_strn(lex->vstr.buf, lex->vstr.len); + } else { + // check if this string is already interned + qst = qstr_find_strn(lex->vstr.buf, lex->vstr.len); + } + if (qst != MP_QSTR_NULL) { + // qstr exists, make a leaf node + pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst); + } else { + // not interned, make a node holding a pointer to the string/bytes object + mp_obj_t o = mp_obj_new_str_copy( + lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes, + (const byte*)lex->vstr.buf, lex->vstr.len); + pn = make_node_const_object(parser, lex->tok_line, o); + } + } else { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, lex->tok_kind); + } + push_result_node(parser, pn); +} + +#if MICROPY_COMP_MODULE_CONST +STATIC const mp_rom_map_elem_t mp_constants_table[] = { + #if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, + #endif + #if MICROPY_PY_UCTYPES + { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, + #endif + // Extra constants as defined by a port + MICROPY_PORT_CONSTANTS +}; +STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); +#endif + +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args); + +#if MICROPY_COMP_CONST_FOLDING +STATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { + if (rule_id == RULE_or_test + || rule_id == RULE_and_test) { + // folding for binary logical ops: or and + size_t copy_to = *num_args; + for (size_t i = copy_to; i > 0;) { + mp_parse_node_t pn = peek_result(parser, --i); + parser->result_stack[parser->result_stack_top - copy_to] = pn; + if (i == 0) { + // always need to keep the last value + break; + } + if (rule_id == RULE_or_test) { + if (mp_parse_node_is_const_true(pn)) { + // + break; + } else if (!mp_parse_node_is_const_false(pn)) { + copy_to -= 1; + } + } else { + // RULE_and_test + if (mp_parse_node_is_const_false(pn)) { + break; + } else if (!mp_parse_node_is_const_true(pn)) { + copy_to -= 1; + } + } + } + copy_to -= 1; // copy_to now contains number of args to pop + + // pop and discard all the short-circuited expressions + for (size_t i = 0; i < copy_to; ++i) { + pop_result(parser); + } + *num_args -= copy_to; + + // we did a complete folding if there's only 1 arg left + return *num_args == 1; + + } else if (rule_id == RULE_not_test_2) { + // folding for unary logical op: not + mp_parse_node_t pn = peek_result(parser, 0); + if (mp_parse_node_is_const_false(pn)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_TRUE); + } else if (mp_parse_node_is_const_true(pn)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_FALSE); + } else { + return false; + } + pop_result(parser); + push_result_node(parser, pn); + return true; + } + + return false; +} + +STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { + // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 + // it does not do partial folding, eg 1 + 2 + x -> 3 + x + + mp_obj_t arg0; + if (rule_id == RULE_expr + || rule_id == RULE_xor_expr + || rule_id == RULE_and_expr) { + // folding for binary ops: | ^ & + mp_parse_node_t pn = peek_result(parser, num_args - 1); + if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + return false; + } + mp_binary_op_t op; + if (rule_id == RULE_expr) { + op = MP_BINARY_OP_OR; + } else if (rule_id == RULE_xor_expr) { + op = MP_BINARY_OP_XOR; + } else { + op = MP_BINARY_OP_AND; + } + for (ssize_t i = num_args - 2; i >= 0; --i) { + pn = peek_result(parser, i); + mp_obj_t arg1; + if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + return false; + } + arg0 = mp_binary_op(op, arg0, arg1); + } + } else if (rule_id == RULE_shift_expr + || rule_id == RULE_arith_expr + || rule_id == RULE_term) { + // folding for binary ops: << >> + - * / % // + mp_parse_node_t pn = peek_result(parser, num_args - 1); + if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + return false; + } + for (ssize_t i = num_args - 2; i >= 1; i -= 2) { + pn = peek_result(parser, i - 1); + mp_obj_t arg1; + if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + return false; + } + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i)); + static const uint8_t token_to_op[] = { + MP_BINARY_OP_ADD, + MP_BINARY_OP_SUBTRACT, + MP_BINARY_OP_MULTIPLY, + 255,//MP_BINARY_OP_POWER, + 255,//MP_BINARY_OP_TRUE_DIVIDE, + MP_BINARY_OP_FLOOR_DIVIDE, + MP_BINARY_OP_MODULO, + 255,//MP_BINARY_OP_LESS + MP_BINARY_OP_LSHIFT, + 255,//MP_BINARY_OP_MORE + MP_BINARY_OP_RSHIFT, + }; + mp_binary_op_t op = token_to_op[tok - MP_TOKEN_OP_PLUS]; + if (op == (mp_binary_op_t)255) { + return false; + } + int rhs_sign = mp_obj_int_sign(arg1); + if (op <= MP_BINARY_OP_RSHIFT) { + // << and >> can't have negative rhs + if (rhs_sign < 0) { + return false; + } + } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) { + // % and // can't have zero rhs + if (rhs_sign == 0) { + return false; + } + } + arg0 = mp_binary_op(op, arg0, arg1); + } + } else if (rule_id == RULE_factor_2) { + // folding for unary ops: + - ~ + mp_parse_node_t pn = peek_result(parser, 0); + if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + return false; + } + mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1)); + mp_unary_op_t op; + if (tok == MP_TOKEN_OP_PLUS) { + op = MP_UNARY_OP_POSITIVE; + } else if (tok == MP_TOKEN_OP_MINUS) { + op = MP_UNARY_OP_NEGATIVE; + } else { + assert(tok == MP_TOKEN_OP_TILDE); // should be + op = MP_UNARY_OP_INVERT; + } + arg0 = mp_unary_op(op, arg0); + + #if MICROPY_COMP_CONST + } else if (rule_id == RULE_expr_stmt) { + mp_parse_node_t pn1 = peek_result(parser, 0); + if (!MP_PARSE_NODE_IS_NULL(pn1) + && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) + || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) { + // this node is of the form = + mp_parse_node_t pn0 = peek_result(parser, 1); + if (MP_PARSE_NODE_IS_ID(pn0) + && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal) + && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t*)pn1)->nodes[0]) + && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn1)->nodes[0]) == MP_QSTR_const + && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t*)pn1)->nodes[1], RULE_trailer_paren) + ) { + // code to assign dynamic constants: id = const(value) + + // get the id + qstr id = MP_PARSE_NODE_LEAF_ARG(pn0); + + // get the value + mp_parse_node_t pn_value = ((mp_parse_node_struct_t*)((mp_parse_node_struct_t*)pn1)->nodes[1])->nodes[0]; + mp_obj_t value; + if (!mp_parse_node_get_int_maybe(pn_value, &value)) { + mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, + "constant must be an integer"); + mp_obj_exception_add_traceback(exc, parser->lexer->source_name, + ((mp_parse_node_struct_t*)pn1)->source_line, MP_QSTR_NULL); + nlr_raise(exc); + } + + // store the value in the table of dynamic constants + mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + assert(elem->value == MP_OBJ_NULL); + elem->value = value; + + // If the constant starts with an underscore then treat it as a private + // variable and don't emit any code to store the value to the id. + if (qstr_str(id)[0] == '_') { + pop_result(parser); // pop const(value) + pop_result(parser); // pop id + push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass" + return true; + } + + // replace const(value) with value + pop_result(parser); + push_result_node(parser, pn_value); + + // finished folding this assignment, but we still want it to be part of the tree + return false; + } + } + return false; + #endif + + #if MICROPY_COMP_MODULE_CONST + } else if (rule_id == RULE_atom_expr_normal) { + mp_parse_node_t pn0 = peek_result(parser, 1); + mp_parse_node_t pn1 = peek_result(parser, 0); + if (!(MP_PARSE_NODE_IS_ID(pn0) + && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period))) { + return false; + } + // id1.id2 + // look it up in constant table, see if it can be replaced with an integer + mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pn1; + assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); + qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0); + qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]); + mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP); + if (elem == NULL) { + return false; + } + mp_obj_t dest[2]; + mp_load_method_maybe(elem->value, q_attr, dest); + if (!(dest[0] != MP_OBJ_NULL && MP_OBJ_IS_INT(dest[0]) && dest[1] == MP_OBJ_NULL)) { + return false; + } + arg0 = dest[0]; + #endif + + } else { + return false; + } + + // success folding this rule + + for (size_t i = num_args; i > 0; i--) { + pop_result(parser); + } + if (MP_OBJ_IS_SMALL_INT(arg0)) { + push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0)); + } else { + // TODO reuse memory for parse node struct? + push_result_node(parser, make_node_const_object(parser, 0, arg0)); + } + + return true; +} +#endif + +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) { + // optimise away parenthesis around an expression if possible + if (rule_id == RULE_atom_paren) { + // there should be just 1 arg for this rule + mp_parse_node_t pn = peek_result(parser, 0); + if (MP_PARSE_NODE_IS_NULL(pn)) { + // need to keep parenthesis for () + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_testlist_comp)) { + // need to keep parenthesis for (a, b, ...) + } else { + // parenthesis around a single expression, so it's just the expression + return; + } + } + + #if MICROPY_COMP_CONST_FOLDING + if (fold_logical_constants(parser, rule_id, &num_args)) { + // we folded this rule so return straight away + return; + } + if (fold_constants(parser, rule_id, num_args)) { + // we folded this rule so return straight away + return; + } + #endif + + mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args); + pn->source_line = src_line; + pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); + for (size_t i = num_args; i > 0; i--) { + pn->nodes[i - 1] = pop_result(parser); + } + push_result_node(parser, (mp_parse_node_t)pn); +} + +mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { + + // initialise parser and allocate memory for its stacks + + parser_t parser; + + parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT; + parser.rule_stack_top = 0; + parser.rule_stack = m_new(rule_stack_t, parser.rule_stack_alloc); + + parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT; + parser.result_stack_top = 0; + parser.result_stack = m_new(mp_parse_node_t, parser.result_stack_alloc); + + parser.lexer = lex; + + parser.tree.chunk = NULL; + parser.cur_chunk = NULL; + + #if MICROPY_COMP_CONST + mp_map_init(&parser.consts, 0); + #endif + + // work out the top-level rule to use, and push it on the stack + size_t top_level_rule; + switch (input_kind) { + case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break; + case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; + default: top_level_rule = RULE_file_input; + } + push_rule(&parser, lex->tok_line, top_level_rule, 0); + + // parse! + + bool backtrack = false; + + for (;;) { + next_rule: + if (parser.rule_stack_top == 0) { + break; + } + + // Pop the next rule to process it + size_t i; // state for the current rule + size_t rule_src_line; // source line for the first token matched by the current rule + uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line); + uint8_t rule_act = rule_act_table[rule_id]; + const uint16_t *rule_arg = get_rule_arg(rule_id); + size_t n = rule_act & RULE_ACT_ARG_MASK; + + #if 0 + // debugging + printf("depth=" UINT_FMT " ", parser.rule_stack_top); + for (int j = 0; j < parser.rule_stack_top; ++j) { + printf(" "); + } + printf("%s n=" UINT_FMT " i=" UINT_FMT " bt=%d\n", rule_name_table[rule_id], n, i, backtrack); + #endif + + switch (rule_act & RULE_ACT_KIND_MASK) { + case RULE_ACT_OR: + if (i > 0 && !backtrack) { + goto next_rule; + } else { + backtrack = false; + } + for (; i < n; ++i) { + uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK; + if (kind == RULE_ARG_TOK) { + if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) { + push_result_token(&parser, rule_id); + mp_lexer_to_next(lex); + goto next_rule; + } + } else { + assert(kind == RULE_ARG_RULE); + if (i + 1 < n) { + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule + } + push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule + goto next_rule; + } + } + backtrack = true; + break; + + case RULE_ACT_AND: { + + // failed, backtrack if we can, else syntax error + if (backtrack) { + assert(i > 0); + if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { + // an optional rule that failed, so continue with next arg + push_result_node(&parser, MP_PARSE_NODE_NULL); + backtrack = false; + } else { + // a mandatory rule that failed, so propagate backtrack + if (i > 1) { + // already eaten tokens so can't backtrack + goto syntax_error; + } else { + goto next_rule; + } + } + } + + // progress through the rule + for (; i < n; ++i) { + if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + // need to match a token + mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK; + if (lex->tok_kind == tok_kind) { + // matched token + if (tok_kind == MP_TOKEN_NAME) { + push_result_token(&parser, rule_id); + } + mp_lexer_to_next(lex); + } else { + // failed to match token + if (i > 0) { + // already eaten tokens so can't backtrack + goto syntax_error; + } else { + // this rule failed, so backtrack + backtrack = true; + goto next_rule; + } + } + } else { + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule + push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule + goto next_rule; + } + } + + assert(i == n); + + // matched the rule, so now build the corresponding parse_node + + #if !MICROPY_ENABLE_DOC_STRING + // this code discards lonely statements, such as doc strings + if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { + mp_parse_node_t p = peek_result(&parser, 1); + if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) + || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) { + pop_result(&parser); // MP_PARSE_NODE_NULL + pop_result(&parser); // const expression (leaf or RULE_const_object) + // Pushing the "pass" rule here will overwrite any RULE_const_object + // entry that was on the result stack, allowing the GC to reclaim + // the memory from the const object when needed. + push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0); + break; + } + } + #endif + + // count number of arguments for the parse node + i = 0; + size_t num_not_nil = 0; + for (size_t x = n; x > 0;) { + --x; + if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK; + if (tok_kind == MP_TOKEN_NAME) { + // only tokens which were names are pushed to stack + i += 1; + num_not_nil += 1; + } + } else { + // rules are always pushed + if (peek_result(&parser, i) != MP_PARSE_NODE_NULL) { + num_not_nil += 1; + } + i += 1; + } + } + + if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) { + // this rule has only 1 argument and should not be emitted + mp_parse_node_t pn = MP_PARSE_NODE_NULL; + for (size_t x = 0; x < i; ++x) { + mp_parse_node_t pn2 = pop_result(&parser); + if (pn2 != MP_PARSE_NODE_NULL) { + pn = pn2; + } + } + push_result_node(&parser, pn); + } else { + // this rule must be emitted + + if (rule_act & RULE_ACT_ADD_BLANK) { + // and add an extra blank node at the end (used by the compiler to store data) + push_result_node(&parser, MP_PARSE_NODE_NULL); + i += 1; + } + + push_result_rule(&parser, rule_src_line, rule_id, i); + } + break; + } + + default: { + assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); + + // n=2 is: item item* + // n=1 is: item (sep item)* + // n=3 is: item (sep item)* [sep] + bool had_trailing_sep; + if (backtrack) { + list_backtrack: + had_trailing_sep = false; + if (n == 2) { + if (i == 1) { + // fail on item, first time round; propagate backtrack + goto next_rule; + } else { + // fail on item, in later rounds; finish with this rule + backtrack = false; + } + } else { + if (i == 1) { + // fail on item, first time round; propagate backtrack + goto next_rule; + } else if ((i & 1) == 1) { + // fail on item, in later rounds; have eaten tokens so can't backtrack + if (n == 3) { + // list allows trailing separator; finish parsing list + had_trailing_sep = true; + backtrack = false; + } else { + // list doesn't allowing trailing separator; fail + goto syntax_error; + } + } else { + // fail on separator; finish parsing list + backtrack = false; + } + } + } else { + for (;;) { + size_t arg = rule_arg[i & 1 & n]; + if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) { + if (i & 1 & n) { + // separators which are tokens are not pushed to result stack + } else { + push_result_token(&parser, rule_id); + } + mp_lexer_to_next(lex); + // got element of list, so continue parsing list + i += 1; + } else { + // couldn't get element of list + i += 1; + backtrack = true; + goto list_backtrack; + } + } else { + assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE); + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule + push_rule_from_arg(&parser, arg); // push child of list-rule + goto next_rule; + } + } + } + assert(i >= 1); + + // compute number of elements in list, result in i + i -= 1; + if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + // don't count separators when they are tokens + i = (i + 1) / 2; + } + + if (i == 1) { + // list matched single item + if (had_trailing_sep) { + // if there was a trailing separator, make a list of a single item + push_result_rule(&parser, rule_src_line, rule_id, i); + } else { + // just leave single item on stack (ie don't wrap in a list) + } + } else { + push_result_rule(&parser, rule_src_line, rule_id, i); + } + break; + } + } + } + + #if MICROPY_COMP_CONST + mp_map_deinit(&parser.consts); + #endif + + // truncate final chunk and link into chain of chunks + if (parser.cur_chunk != NULL) { + (void)m_renew_maybe(byte, parser.cur_chunk, + sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc, + sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used, + false); + parser.cur_chunk->alloc = parser.cur_chunk->union_.used; + parser.cur_chunk->union_.next = parser.tree.chunk; + parser.tree.chunk = parser.cur_chunk; + } + + if ( + lex->tok_kind != MP_TOKEN_END // check we are at the end of the token stream + || parser.result_stack_top == 0 // check that we got a node (can fail on empty input) + ) { + syntax_error:; + mp_obj_t exc; + if (lex->tok_kind == MP_TOKEN_INDENT) { + exc = mp_obj_new_exception_msg(&mp_type_IndentationError, + "unexpected indent"); + } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) { + exc = mp_obj_new_exception_msg(&mp_type_IndentationError, + "unindent doesn't match any outer indent level"); + } else { + exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, + "invalid syntax"); + } + // add traceback to give info about file name and location + // we don't have a 'block' name, so just pass the NULL qstr to indicate this + mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); + nlr_raise(exc); + } + + // get the root parse node that we created + assert(parser.result_stack_top == 1); + parser.tree.root = parser.result_stack[0]; + + // free the memory that we don't need anymore + m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc); + m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc); + + // we also free the lexer on behalf of the caller + mp_lexer_free(lex); + + return parser.tree; +} + +void mp_parse_tree_clear(mp_parse_tree_t *tree) { + mp_parse_chunk_t *chunk = tree->chunk; + while (chunk != NULL) { + mp_parse_chunk_t *next = chunk->union_.next; + m_del(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc); + chunk = next; + } +} + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/parse.h b/src/openmv/src/micropython/py/parse.h new file mode 100755 index 0000000..9a1a2b4 --- /dev/null +++ b/src/openmv/src/micropython/py/parse.h @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PARSE_H +#define MICROPY_INCLUDED_PY_PARSE_H + +#include +#include + +#include "py/obj.h" + +struct _mp_lexer_t; + +// a mp_parse_node_t is: +// - 0000...0000: no node +// - xxxx...xxx1: a small integer; bits 1 and above are the signed value, 2's complement +// - xxxx...xx00: pointer to mp_parse_node_struct_t +// - xx...xx0010: an identifier; bits 4 and above are the qstr +// - xx...xx0110: a string; bits 4 and above are the qstr holding the value +// - xx...xx1010: a string of bytes; bits 4 and above are the qstr holding the value +// - xx...xx1110: a token; bits 4 and above are mp_token_kind_t + +#define MP_PARSE_NODE_NULL (0) +#define MP_PARSE_NODE_SMALL_INT (0x1) +#define MP_PARSE_NODE_ID (0x02) +#define MP_PARSE_NODE_STRING (0x06) +#define MP_PARSE_NODE_BYTES (0x0a) +#define MP_PARSE_NODE_TOKEN (0x0e) + +typedef uintptr_t mp_parse_node_t; // must be pointer size + +typedef struct _mp_parse_node_struct_t { + uint32_t source_line; // line number in source file + uint32_t kind_num_nodes; // parse node kind, and number of nodes + mp_parse_node_t nodes[]; // nodes +} mp_parse_node_struct_t; + +// macros for mp_parse_node_t usage +// some of these evaluate their argument more than once + +#define MP_PARSE_NODE_IS_NULL(pn) ((pn) == MP_PARSE_NODE_NULL) +#define MP_PARSE_NODE_IS_LEAF(pn) ((pn) & 3) +#define MP_PARSE_NODE_IS_STRUCT(pn) ((pn) != MP_PARSE_NODE_NULL && ((pn) & 3) == 0) +#define MP_PARSE_NODE_IS_STRUCT_KIND(pn, k) ((pn) != MP_PARSE_NODE_NULL && ((pn) & 3) == 0 && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)(pn)) == (k)) + +#define MP_PARSE_NODE_IS_SMALL_INT(pn) (((pn) & 0x1) == MP_PARSE_NODE_SMALL_INT) +#define MP_PARSE_NODE_IS_ID(pn) (((pn) & 0x0f) == MP_PARSE_NODE_ID) +#define MP_PARSE_NODE_IS_TOKEN(pn) (((pn) & 0x0f) == MP_PARSE_NODE_TOKEN) +#define MP_PARSE_NODE_IS_TOKEN_KIND(pn, k) ((pn) == (MP_PARSE_NODE_TOKEN | ((k) << 4))) + +#define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x0f) +#define MP_PARSE_NODE_LEAF_ARG(pn) (((uintptr_t)(pn)) >> 4) +#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(intptr_t)(pn)) >> 1) +#define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff) +#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8) + +static inline mp_parse_node_t mp_parse_node_new_small_int(mp_int_t val) { + return (mp_parse_node_t)(MP_PARSE_NODE_SMALL_INT | ((mp_uint_t)val << 1)); +} +static inline mp_parse_node_t mp_parse_node_new_leaf(size_t kind, mp_int_t arg) { + return (mp_parse_node_t)(kind | ((mp_uint_t)arg << 4)); +} +bool mp_parse_node_is_const_false(mp_parse_node_t pn); +bool mp_parse_node_is_const_true(mp_parse_node_t pn); +bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o); +int mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes); +void mp_parse_node_print(mp_parse_node_t pn, size_t indent); + +typedef enum { + MP_PARSE_SINGLE_INPUT, + MP_PARSE_FILE_INPUT, + MP_PARSE_EVAL_INPUT, +} mp_parse_input_kind_t; + +typedef struct _mp_parse_t { + mp_parse_node_t root; + struct _mp_parse_chunk_t *chunk; +} mp_parse_tree_t; + +// the parser will raise an exception if an error occurred +// the parser will free the lexer before it returns +mp_parse_tree_t mp_parse(struct _mp_lexer_t *lex, mp_parse_input_kind_t input_kind); +void mp_parse_tree_clear(mp_parse_tree_t *tree); + +#endif // MICROPY_INCLUDED_PY_PARSE_H diff --git a/src/openmv/src/micropython/py/parsenum.c b/src/openmv/src/micropython/py/parsenum.c new file mode 100755 index 0000000..ae9b834 --- /dev/null +++ b/src/openmv/src/micropython/py/parsenum.c @@ -0,0 +1,358 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/parsenumbase.h" +#include "py/parsenum.h" +#include "py/smallint.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + +STATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { + // if lex!=NULL then the parser called us and we need to convert the + // exception's type from ValueError to SyntaxError and add traceback info + if (lex != NULL) { + ((mp_obj_base_t*)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError; + mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL); + } + nlr_raise(exc); +} + +mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) { + const byte *restrict str = (const byte *)str_; + const byte *restrict top = str + len; + bool neg = false; + mp_obj_t ret_val; + + // check radix base + if ((base != 0 && base < 2) || base > 36) { + // this won't be reached if lex!=NULL + mp_raise_ValueError("int() arg 2 must be >= 2 and <= 36"); + } + + // skip leading space + for (; str < top && unichar_isspace(*str); str++) { + } + + // parse optional sign + if (str < top) { + if (*str == '+') { + str++; + } else if (*str == '-') { + str++; + neg = true; + } + } + + // parse optional base prefix + str += mp_parse_num_base((const char*)str, top - str, &base); + + // string should be an integer number + mp_int_t int_val = 0; + const byte *restrict str_val_start = str; + for (; str < top; str++) { + // get next digit as a value + mp_uint_t dig = *str; + if ('0' <= dig && dig <= '9') { + dig -= '0'; + } else if (dig == '_') { + continue; + } else { + dig |= 0x20; // make digit lower-case + if ('a' <= dig && dig <= 'z') { + dig -= 'a' - 10; + } else { + // unknown character + break; + } + } + if (dig >= (mp_uint_t)base) { + break; + } + + // add next digi and check for overflow + if (mp_small_int_mul_overflow(int_val, base)) { + goto overflow; + } + int_val = int_val * base + dig; + if (!MP_SMALL_INT_FITS(int_val)) { + goto overflow; + } + } + + // negate value if needed + if (neg) { + int_val = -int_val; + } + + // create the small int + ret_val = MP_OBJ_NEW_SMALL_INT(int_val); + +have_ret_val: + // check we parsed something + if (str == str_val_start) { + goto value_error; + } + + // skip trailing space + for (; str < top && unichar_isspace(*str); str++) { + } + + // check we reached the end of the string + if (str != top) { + goto value_error; + } + + // return the object + return ret_val; + +overflow: + // reparse using long int + { + const char *s2 = (const char*)str_val_start; + ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base); + str = (const byte*)s2; + goto have_ret_val; + } + +value_error: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError, + "invalid syntax for integer"); + raise_exc(exc, lex); + } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { + mp_obj_t exc = mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "invalid syntax for integer with base %d", base); + raise_exc(exc, lex); + } else { + vstr_t vstr; + mp_print_t print; + vstr_init_print(&vstr, 50, &print); + mp_printf(&print, "invalid syntax for integer with base %d: ", base); + mp_str_print_quoted(&print, str_val_start, top - str_val_start, true); + mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_ValueError, + mp_obj_new_str_from_vstr(&mp_type_str, &vstr)); + raise_exc(exc, lex); + } +} + +typedef enum { + PARSE_DEC_IN_INTG, + PARSE_DEC_IN_FRAC, + PARSE_DEC_IN_EXP, +} parse_dec_in_t; + +mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) { +#if MICROPY_PY_BUILTINS_FLOAT + +// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float +// EXACT_POWER_OF_10 is the largest value of x so that 10^x can be stored exactly in a float +// Note: EXACT_POWER_OF_10 is at least floor(log_5(2^mantissa_length)). Indeed, 10^n = 2^n * 5^n +// so we only have to store the 5^n part in the mantissa (the 2^n part will go into the float's +// exponent). +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define DEC_VAL_MAX 1e20F +#define SMALL_NORMAL_VAL (1e-37F) +#define SMALL_NORMAL_EXP (-37) +#define EXACT_POWER_OF_10 (9) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define DEC_VAL_MAX 1e200 +#define SMALL_NORMAL_VAL (1e-307) +#define SMALL_NORMAL_EXP (-307) +#define EXACT_POWER_OF_10 (22) +#endif + + const char *top = str + len; + mp_float_t dec_val = 0; + bool dec_neg = false; + bool imag = false; + + // skip leading space + for (; str < top && unichar_isspace(*str); str++) { + } + + // parse optional sign + if (str < top) { + if (*str == '+') { + str++; + } else if (*str == '-') { + str++; + dec_neg = true; + } + } + + const char *str_val_start = str; + + // determine what the string is + if (str < top && (str[0] | 0x20) == 'i') { + // string starts with 'i', should be 'inf' or 'infinity' (case insensitive) + if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { + // inf + str += 3; + dec_val = INFINITY; + if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { + // infinity + str += 5; + } + } + } else if (str < top && (str[0] | 0x20) == 'n') { + // string starts with 'n', should be 'nan' (case insensitive) + if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { + // NaN + str += 3; + dec_val = MICROPY_FLOAT_C_FUN(nan)(""); + } + } else { + // string should be a decimal number + parse_dec_in_t in = PARSE_DEC_IN_INTG; + bool exp_neg = false; + int exp_val = 0; + int exp_extra = 0; + while (str < top) { + unsigned int dig = *str++; + if ('0' <= dig && dig <= '9') { + dig -= '0'; + if (in == PARSE_DEC_IN_EXP) { + // don't overflow exp_val when adding next digit, instead just truncate + // it and the resulting float will still be correct, either inf or 0.0 + // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) + if (exp_val < (INT_MAX / 2 - 9) / 10) { + exp_val = 10 * exp_val + dig; + } + } else { + if (dec_val < DEC_VAL_MAX) { + // dec_val won't overflow so keep accumulating + dec_val = 10 * dec_val + dig; + if (in == PARSE_DEC_IN_FRAC) { + --exp_extra; + } + } else { + // dec_val might overflow and we anyway can't represent more digits + // of precision, so ignore the digit and just adjust the exponent + if (in == PARSE_DEC_IN_INTG) { + ++exp_extra; + } + } + } + } else if (in == PARSE_DEC_IN_INTG && dig == '.') { + in = PARSE_DEC_IN_FRAC; + } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { + in = PARSE_DEC_IN_EXP; + if (str < top) { + if (str[0] == '+') { + str++; + } else if (str[0] == '-') { + str++; + exp_neg = true; + } + } + if (str == top) { + goto value_error; + } + } else if (allow_imag && (dig | 0x20) == 'j') { + imag = true; + break; + } else if (dig == '_') { + continue; + } else { + // unknown character + str--; + break; + } + } + + // work out the exponent + if (exp_neg) { + exp_val = -exp_val; + } + + // apply the exponent, making sure it's not a subnormal value + exp_val += exp_extra; + if (exp_val < SMALL_NORMAL_EXP) { + exp_val -= SMALL_NORMAL_EXP; + dec_val *= SMALL_NORMAL_VAL; + } + + // At this point, we need to multiply the mantissa by its base 10 exponent. If possible, + // we would rather manipulate numbers that have an exact representation in IEEE754. It + // turns out small positive powers of 10 do, whereas small negative powers of 10 don't. + // So in that case, we'll yield a division of exact values rather than a multiplication + // of slightly erroneous values. + if (exp_val < 0 && exp_val >= -EXACT_POWER_OF_10) { + dec_val /= MICROPY_FLOAT_C_FUN(pow)(10, -exp_val); + } else { + dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); + } + } + + // negate value if needed + if (dec_neg) { + dec_val = -dec_val; + } + + // check we parsed something + if (str == str_val_start) { + goto value_error; + } + + // skip trailing space + for (; str < top && unichar_isspace(*str); str++) { + } + + // check we reached the end of the string + if (str != top) { + goto value_error; + } + + // return the object +#if MICROPY_PY_BUILTINS_COMPLEX + if (imag) { + return mp_obj_new_complex(0, dec_val); + } else if (force_complex) { + return mp_obj_new_complex(dec_val, 0); + } +#else + if (imag || force_complex) { + raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); + } +#endif + else { + return mp_obj_new_float(dec_val); + } + +value_error: + raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for number"), lex); + +#else + raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "decimal numbers not supported"), lex); +#endif +} diff --git a/src/openmv/src/micropython/py/parsenum.h b/src/openmv/src/micropython/py/parsenum.h new file mode 100755 index 0000000..a5bed73 --- /dev/null +++ b/src/openmv/src/micropython/py/parsenum.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PARSENUM_H +#define MICROPY_INCLUDED_PY_PARSENUM_H + +#include "py/mpconfig.h" +#include "py/lexer.h" +#include "py/obj.h" + +// these functions raise a SyntaxError if lex!=NULL, else a ValueError +mp_obj_t mp_parse_num_integer(const char *restrict str, size_t len, int base, mp_lexer_t *lex); +mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex); + +#endif // MICROPY_INCLUDED_PY_PARSENUM_H diff --git a/src/openmv/src/micropython/py/parsenumbase.c b/src/openmv/src/micropython/py/parsenumbase.c new file mode 100755 index 0000000..ba10591 --- /dev/null +++ b/src/openmv/src/micropython/py/parsenumbase.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/parsenumbase.h" + +// find real radix base, and strip preceding '0x', '0o' and '0b' +// puts base in *base, and returns number of bytes to skip the prefix +size_t mp_parse_num_base(const char *str, size_t len, int *base) { + const byte *p = (const byte*)str; + if (len <= 1) { + goto no_prefix; + } + unichar c = *(p++); + if ((*base == 0 || *base == 16) && c == '0') { + c = *(p++); + if ((c | 32) == 'x') { + *base = 16; + } else if (*base == 0 && (c | 32) == 'o') { + *base = 8; + } else if (*base == 0 && (c | 32) == 'b') { + *base = 2; + } else { + if (*base == 0) { + *base = 10; + } + p -= 2; + } + } else if (*base == 8 && c == '0') { + c = *(p++); + if ((c | 32) != 'o') { + p -= 2; + } + } else if (*base == 2 && c == '0') { + c = *(p++); + if ((c | 32) != 'b') { + p -= 2; + } + } else { + p--; + no_prefix: + if (*base == 0) { + *base = 10; + } + } + return p - (const byte*)str; +} diff --git a/src/openmv/src/micropython/py/parsenumbase.h b/src/openmv/src/micropython/py/parsenumbase.h new file mode 100755 index 0000000..3a525f9 --- /dev/null +++ b/src/openmv/src/micropython/py/parsenumbase.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PARSENUMBASE_H +#define MICROPY_INCLUDED_PY_PARSENUMBASE_H + +#include "py/mpconfig.h" + +size_t mp_parse_num_base(const char *str, size_t len, int *base); + +#endif // MICROPY_INCLUDED_PY_PARSENUMBASE_H diff --git a/src/openmv/src/micropython/py/persistentcode.c b/src/openmv/src/micropython/py/persistentcode.c new file mode 100755 index 0000000..7113b0d --- /dev/null +++ b/src/openmv/src/micropython/py/persistentcode.c @@ -0,0 +1,403 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/reader.h" +#include "py/emitglue.h" +#include "py/persistentcode.h" +#include "py/bc.h" + +#if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE + +#include "py/smallint.h" + +// The current version of .mpy files +#define MPY_VERSION (3) + +// The feature flags byte encodes the compile-time config options that +// affect the generate bytecode. +#define MPY_FEATURE_FLAGS ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ + ) +// This is a version of the flags that can be configured at runtime. +#define MPY_FEATURE_FLAGS_DYNAMIC ( \ + ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \ + | ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ + ) + +#if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER) +// The bytecode will depend on the number of bits in a small-int, and +// this function computes that (could make it a fixed constant, but it +// would need to be defined in mpconfigport.h). +STATIC int mp_small_int_bits(void) { + mp_int_t i = MP_SMALL_INT_MAX; + int n = 1; + while (i != 0) { + i >>= 1; + ++n; + } + return n; +} +#endif + +typedef struct _bytecode_prelude_t { + uint n_state; + uint n_exc_stack; + uint scope_flags; + uint n_pos_args; + uint n_kwonly_args; + uint n_def_pos_args; + uint code_info_size; +} bytecode_prelude_t; + +// ip will point to start of opcodes +// ip2 will point to simple_name, source_file qstrs +STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_t *prelude) { + prelude->n_state = mp_decode_uint(ip); + prelude->n_exc_stack = mp_decode_uint(ip); + prelude->scope_flags = *(*ip)++; + prelude->n_pos_args = *(*ip)++; + prelude->n_kwonly_args = *(*ip)++; + prelude->n_def_pos_args = *(*ip)++; + *ip2 = *ip; + prelude->code_info_size = mp_decode_uint(ip2); + *ip += prelude->code_info_size; + while (*(*ip)++ != 255) { + } +} + +#endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE + +#if MICROPY_PERSISTENT_CODE_LOAD + +#include "py/parsenum.h" + +STATIC int read_byte(mp_reader_t *reader) { + return reader->readbyte(reader->data); +} + +STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) { + while (len-- > 0) { + *buf++ = reader->readbyte(reader->data); + } +} + +STATIC size_t read_uint(mp_reader_t *reader) { + size_t unum = 0; + for (;;) { + byte b = reader->readbyte(reader->data); + unum = (unum << 7) | (b & 0x7f); + if ((b & 0x80) == 0) { + break; + } + } + return unum; +} + +STATIC qstr load_qstr(mp_reader_t *reader) { + size_t len = read_uint(reader); + char *str = m_new(char, len); + read_bytes(reader, (byte*)str, len); + qstr qst = qstr_from_strn(str, len); + m_del(char, str, len); + return qst; +} + +STATIC mp_obj_t load_obj(mp_reader_t *reader) { + byte obj_type = read_byte(reader); + if (obj_type == 'e') { + return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj); + } else { + size_t len = read_uint(reader); + vstr_t vstr; + vstr_init_len(&vstr, len); + read_bytes(reader, (byte*)vstr.buf, len); + if (obj_type == 's' || obj_type == 'b') { + return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr); + } else if (obj_type == 'i') { + return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); + } else { + assert(obj_type == 'f' || obj_type == 'c'); + return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL); + } + } +} + +STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { + while (ip < ip_top) { + size_t sz; + uint f = mp_opcode_format(ip, &sz); + if (f == MP_OPCODE_QSTR) { + qstr qst = load_qstr(reader); + ip[1] = qst; + ip[2] = qst >> 8; + } + ip += sz; + } +} + +STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { + // load bytecode + size_t bc_len = read_uint(reader); + byte *bytecode = m_new(byte, bc_len); + read_bytes(reader, bytecode, bc_len); + + // extract prelude + const byte *ip = bytecode; + const byte *ip2; + bytecode_prelude_t prelude; + extract_prelude(&ip, &ip2, &prelude); + + // load qstrs and link global qstr ids into bytecode + qstr simple_name = load_qstr(reader); + qstr source_file = load_qstr(reader); + ((byte*)ip2)[0] = simple_name; ((byte*)ip2)[1] = simple_name >> 8; + ((byte*)ip2)[2] = source_file; ((byte*)ip2)[3] = source_file >> 8; + load_bytecode_qstrs(reader, (byte*)ip, bytecode + bc_len); + + // load constant table + size_t n_obj = read_uint(reader); + size_t n_raw_code = read_uint(reader); + mp_uint_t *const_table = m_new(mp_uint_t, prelude.n_pos_args + prelude.n_kwonly_args + n_obj + n_raw_code); + mp_uint_t *ct = const_table; + for (size_t i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + *ct++ = (mp_uint_t)MP_OBJ_NEW_QSTR(load_qstr(reader)); + } + for (size_t i = 0; i < n_obj; ++i) { + *ct++ = (mp_uint_t)load_obj(reader); + } + for (size_t i = 0; i < n_raw_code; ++i) { + *ct++ = (mp_uint_t)(uintptr_t)load_raw_code(reader); + } + + // create raw_code and return it + mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); + mp_emit_glue_assign_bytecode(rc, bytecode, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + bc_len, + #endif + const_table, + #if MICROPY_PERSISTENT_CODE_SAVE + n_obj, n_raw_code, + #endif + prelude.scope_flags); + return rc; +} + +mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { + byte header[4]; + read_bytes(reader, header, sizeof(header)); + if (header[0] != 'M' + || header[1] != MPY_VERSION + || header[2] != MPY_FEATURE_FLAGS + || header[3] > mp_small_int_bits()) { + mp_raise_ValueError("incompatible .mpy file"); + } + mp_raw_code_t *rc = load_raw_code(reader); + reader->close(reader->data); + return rc; +} + +mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { + mp_reader_t reader; + mp_reader_new_mem(&reader, buf, len, 0); + return mp_raw_code_load(&reader); +} + +mp_raw_code_t *mp_raw_code_load_file(const char *filename) { + mp_reader_t reader; + mp_reader_new_file(&reader, filename); + return mp_raw_code_load(&reader); +} + +#endif // MICROPY_PERSISTENT_CODE_LOAD + +#if MICROPY_PERSISTENT_CODE_SAVE + +#include "py/objstr.h" + +STATIC void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) { + print->print_strn(print->data, (const char*)data, len); +} + +#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) +STATIC void mp_print_uint(mp_print_t *print, size_t n) { + byte buf[BYTES_FOR_INT]; + byte *p = buf + sizeof(buf); + *--p = n & 0x7f; + n >>= 7; + for (; n != 0; n >>= 7) { + *--p = 0x80 | (n & 0x7f); + } + print->print_strn(print->data, (char*)p, buf + sizeof(buf) - p); +} + +STATIC void save_qstr(mp_print_t *print, qstr qst) { + size_t len; + const byte *str = qstr_data(qst, &len); + mp_print_uint(print, len); + mp_print_bytes(print, str, len); +} + +STATIC void save_obj(mp_print_t *print, mp_obj_t o) { + if (MP_OBJ_IS_STR_OR_BYTES(o)) { + byte obj_type; + if (MP_OBJ_IS_STR(o)) { + obj_type = 's'; + } else { + obj_type = 'b'; + } + mp_uint_t len; + const char *str = mp_obj_str_get_data(o, &len); + mp_print_bytes(print, &obj_type, 1); + mp_print_uint(print, len); + mp_print_bytes(print, (const byte*)str, len); + } else if (MP_OBJ_TO_PTR(o) == &mp_const_ellipsis_obj) { + byte obj_type = 'e'; + mp_print_bytes(print, &obj_type, 1); + } else { + // we save numbers using a simplistic text representation + // TODO could be improved + byte obj_type; + if (MP_OBJ_IS_TYPE(o, &mp_type_int)) { + obj_type = 'i'; + #if MICROPY_PY_BUILTINS_COMPLEX + } else if (MP_OBJ_IS_TYPE(o, &mp_type_complex)) { + obj_type = 'c'; + #endif + } else { + assert(mp_obj_is_float(o)); + obj_type = 'f'; + } + vstr_t vstr; + mp_print_t pr; + vstr_init_print(&vstr, 10, &pr); + mp_obj_print_helper(&pr, o, PRINT_REPR); + mp_print_bytes(print, &obj_type, 1); + mp_print_uint(print, vstr.len); + mp_print_bytes(print, (const byte*)vstr.buf, vstr.len); + vstr_clear(&vstr); + } +} + +STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *ip_top) { + while (ip < ip_top) { + size_t sz; + uint f = mp_opcode_format(ip, &sz); + if (f == MP_OPCODE_QSTR) { + qstr qst = ip[1] | (ip[2] << 8); + save_qstr(print, qst); + } + ip += sz; + } +} + +STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { + if (rc->kind != MP_CODE_BYTECODE) { + mp_raise_ValueError("can only save bytecode"); + } + + // save bytecode + mp_print_uint(print, rc->data.u_byte.bc_len); + mp_print_bytes(print, rc->data.u_byte.bytecode, rc->data.u_byte.bc_len); + + // extract prelude + const byte *ip = rc->data.u_byte.bytecode; + const byte *ip2; + bytecode_prelude_t prelude; + extract_prelude(&ip, &ip2, &prelude); + + // save qstrs + save_qstr(print, ip2[0] | (ip2[1] << 8)); // simple_name + save_qstr(print, ip2[2] | (ip2[3] << 8)); // source_file + save_bytecode_qstrs(print, ip, rc->data.u_byte.bytecode + rc->data.u_byte.bc_len); + + // save constant table + mp_print_uint(print, rc->data.u_byte.n_obj); + mp_print_uint(print, rc->data.u_byte.n_raw_code); + const mp_uint_t *const_table = rc->data.u_byte.const_table; + for (uint i = 0; i < prelude.n_pos_args + prelude.n_kwonly_args; ++i) { + mp_obj_t o = (mp_obj_t)*const_table++; + save_qstr(print, MP_OBJ_QSTR_VALUE(o)); + } + for (uint i = 0; i < rc->data.u_byte.n_obj; ++i) { + save_obj(print, (mp_obj_t)*const_table++); + } + for (uint i = 0; i < rc->data.u_byte.n_raw_code; ++i) { + save_raw_code(print, (mp_raw_code_t*)(uintptr_t)*const_table++); + } +} + +void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) { + // header contains: + // byte 'M' + // byte version + // byte feature flags + // byte number of bits in a small int + byte header[4] = {'M', MPY_VERSION, MPY_FEATURE_FLAGS_DYNAMIC, + #if MICROPY_DYNAMIC_COMPILER + mp_dynamic_compiler.small_int_bits, + #else + mp_small_int_bits(), + #endif + }; + mp_print_bytes(print, header, sizeof(header)); + + save_raw_code(print, rc); +} + +// here we define mp_raw_code_save_file depending on the port +// TODO abstract this away properly + +#if defined(__i386__) || defined(__x86_64__) || defined(__unix__) + +#include +#include +#include + +STATIC void fd_print_strn(void *env, const char *str, size_t len) { + int fd = (intptr_t)env; + ssize_t ret = write(fd, str, len); + (void)ret; +} + +void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename) { + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + mp_print_t fd_print = {(void*)(intptr_t)fd, fd_print_strn}; + mp_raw_code_save(rc, &fd_print); + close(fd); +} + +#else +#error mp_raw_code_save_file not implemented for this platform +#endif + +#endif // MICROPY_PERSISTENT_CODE_SAVE diff --git a/src/openmv/src/micropython/py/persistentcode.h b/src/openmv/src/micropython/py/persistentcode.h new file mode 100755 index 0000000..d04e0b6 --- /dev/null +++ b/src/openmv/src/micropython/py/persistentcode.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PERSISTENTCODE_H +#define MICROPY_INCLUDED_PY_PERSISTENTCODE_H + +#include "py/mpprint.h" +#include "py/reader.h" +#include "py/emitglue.h" + +mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader); +mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len); +mp_raw_code_t *mp_raw_code_load_file(const char *filename); + +void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print); +void mp_raw_code_save_file(mp_raw_code_t *rc, const char *filename); + +#endif // MICROPY_INCLUDED_PY_PERSISTENTCODE_H diff --git a/src/openmv/src/micropython/py/py.mk b/src/openmv/src/micropython/py/py.mk new file mode 100755 index 0000000..f55ee50 --- /dev/null +++ b/src/openmv/src/micropython/py/py.mk @@ -0,0 +1,332 @@ +# where py object files go (they have a name prefix to prevent filename clashes) +PY_BUILD = $(BUILD)/py + +# where autogenerated header files go +HEADER_BUILD = $(BUILD)/genhdr + +# file containing qstr defs for the core Python bit +PY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h + +# If qstr autogeneration is not disabled we specify the output header +# for all collected qstrings. +ifneq ($(QSTR_AUTOGEN_DISABLE),1) +QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h +endif + +# Any files listed by this variable will cause a full regeneration of qstrs +QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h + +# some code is performance bottleneck and compiled with other optimization options +CSUPEROPT = -O3 + +# this sets the config file for FatFs +CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" + +ifeq ($(MICROPY_PY_USSL),1) +CFLAGS_MOD += -DMICROPY_PY_USSL=1 +ifeq ($(MICROPY_SSL_AXTLS),1) +CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include +AXTLS_DIR = lib/axtls +$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-unused-const-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA) +SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ + ssl/asn1.c \ + ssl/loader.c \ + ssl/tls1.c \ + ssl/tls1_svr.c \ + ssl/tls1_clnt.c \ + ssl/x509.c \ + crypto/aes.c \ + crypto/bigint.c \ + crypto/crypto_misc.c \ + crypto/hmac.c \ + crypto/md5.c \ + crypto/rsa.c \ + crypto/sha1.c \ + ) +else ifeq ($(MICROPY_SSL_MBEDTLS),1) +# Can be overridden by ports which have "builtin" mbedTLS +MICROPY_SSL_MBEDTLS_INCLUDE ?= $(TOP)/lib/mbedtls/include +CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(MICROPY_SSL_MBEDTLS_INCLUDE) +LDFLAGS_MOD += -L$(TOP)/lib/mbedtls/library -lmbedx509 -lmbedtls -lmbedcrypto +endif +endif + +#ifeq ($(MICROPY_PY_LWIP),1) +#CFLAGS_MOD += -DMICROPY_PY_LWIP=1 -I../lib/lwip/src/include -I../lib/lwip/src/include/ipv4 -I../extmod/lwip-include +#endif + +ifeq ($(MICROPY_PY_LWIP),1) +LWIP_DIR = lib/lwip/src +INC += -I$(TOP)/lib/lwip/src/include -I$(TOP)/lib/lwip/src/include/ipv4 -I$(TOP)/extmod/lwip-include +CFLAGS_MOD += -DMICROPY_PY_LWIP=1 +SRC_MOD += extmod/modlwip.c lib/netutils/netutils.c +SRC_MOD += $(addprefix $(LWIP_DIR)/,\ + core/def.c \ + core/dns.c \ + core/init.c \ + core/mem.c \ + core/memp.c \ + core/netif.c \ + core/pbuf.c \ + core/raw.c \ + core/stats.c \ + core/sys.c \ + core/tcp.c \ + core/tcp_in.c \ + core/tcp_out.c \ + core/timers.c \ + core/udp.c \ + core/ipv4/autoip.c \ + core/ipv4/icmp.c \ + core/ipv4/igmp.c \ + core/ipv4/inet.c \ + core/ipv4/inet_chksum.c \ + core/ipv4/ip_addr.c \ + core/ipv4/ip.c \ + core/ipv4/ip_frag.c \ + ) +ifeq ($(MICROPY_PY_LWIP_SLIP),1) +CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1 +SRC_MOD += $(LWIP_DIR)/netif/slipif.c +endif +endif + +ifeq ($(MICROPY_PY_BTREE),1) +BTREE_DIR = lib/berkeley-db-1.xx +BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA) +INC += -I$(TOP)/$(BTREE_DIR)/PORT/include +SRC_MOD += extmod/modbtree.c +SRC_MOD += $(addprefix $(BTREE_DIR)/,\ +btree/bt_close.c \ +btree/bt_conv.c \ +btree/bt_debug.c \ +btree/bt_delete.c \ +btree/bt_get.c \ +btree/bt_open.c \ +btree/bt_overflow.c \ +btree/bt_page.c \ +btree/bt_put.c \ +btree/bt_search.c \ +btree/bt_seq.c \ +btree/bt_split.c \ +btree/bt_utils.c \ +mpool/mpool.c \ + ) +CFLAGS_MOD += -DMICROPY_PY_BTREE=1 +# we need to suppress certain warnings to get berkeley-db to compile cleanly +# and we have separate BTREE_DEFS so the definitions don't interfere with other source code +$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS) +$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) +endif + +# py object files +PY_CORE_O_BASENAME = $(addprefix py/,\ + mpstate.o \ + nlr.o \ + nlrx86.o \ + nlrx64.o \ + nlrthumb.o \ + nlrxtensa.o \ + nlrsetjmp.o \ + malloc.o \ + gc.o \ + pystack.o \ + qstr.o \ + vstr.o \ + mpprint.o \ + unicode.o \ + mpz.o \ + reader.o \ + lexer.o \ + parse.o \ + scope.o \ + compile.o \ + emitcommon.o \ + emitbc.o \ + asmbase.o \ + asmx64.o \ + emitnx64.o \ + asmx86.o \ + emitnx86.o \ + asmthumb.o \ + emitnthumb.o \ + emitinlinethumb.o \ + asmarm.o \ + emitnarm.o \ + asmxtensa.o \ + emitnxtensa.o \ + emitinlinextensa.o \ + formatfloat.o \ + parsenumbase.o \ + parsenum.o \ + emitglue.o \ + persistentcode.o \ + runtime.o \ + runtime_utils.o \ + scheduler.o \ + nativeglue.o \ + stackctrl.o \ + argcheck.o \ + warning.o \ + map.o \ + obj.o \ + objarray.o \ + objattrtuple.o \ + objbool.o \ + objboundmeth.o \ + objcell.o \ + objclosure.o \ + objcomplex.o \ + objdeque.o \ + objdict.o \ + objenumerate.o \ + objexcept.o \ + objfilter.o \ + objfloat.o \ + objfun.o \ + objgenerator.o \ + objgetitemiter.o \ + objint.o \ + objint_longlong.o \ + objint_mpz.o \ + objlist.o \ + objmap.o \ + objmodule.o \ + objobject.o \ + objpolyiter.o \ + objproperty.o \ + objnone.o \ + objnamedtuple.o \ + objrange.o \ + objreversed.o \ + objset.o \ + objsingleton.o \ + objslice.o \ + objstr.o \ + objstrunicode.o \ + objstringio.o \ + objtuple.o \ + objtype.o \ + objzip.o \ + opmethods.o \ + sequence.o \ + stream.o \ + binary.o \ + builtinimport.o \ + builtinevex.o \ + builtinhelp.o \ + modarray.o \ + modbuiltins.o \ + modcollections.o \ + modgc.o \ + modio.o \ + modmath.o \ + modcmath.o \ + modmicropython.o \ + modstruct.o \ + modsys.o \ + moduerrno.o \ + modthread.o \ + vm.o \ + bc.o \ + showbc.o \ + repl.o \ + smallint.o \ + frozenmod.o \ + ) + +PY_EXTMOD_O_BASENAME = \ + extmod/moductypes.o \ + extmod/modujson.o \ + extmod/modure.o \ + extmod/moduzlib.o \ + extmod/moduheapq.o \ + extmod/modutimeq.o \ + extmod/moduhashlib.o \ + extmod/moducryptolib.o \ + extmod/modubinascii.o \ + extmod/virtpin.o \ + extmod/machine_mem.o \ + extmod/machine_pinbase.o \ + extmod/machine_signal.o \ + extmod/machine_pulse.o \ + extmod/machine_i2c.o \ + extmod/machine_spi.o \ + extmod/modussl_axtls.o \ + extmod/modussl_mbedtls.o \ + extmod/modurandom.o \ + extmod/moduselect.o \ + extmod/modwebsocket.o \ + extmod/modwebrepl.o \ + extmod/modframebuf.o \ + extmod/vfs.o \ + extmod/vfs_reader.o \ + extmod/vfs_posix.o \ + extmod/vfs_posix_file.o \ + extmod/vfs_fat.o \ + extmod/vfs_fat_diskio.o \ + extmod/vfs_fat_file.o \ + extmod/utime_mphal.o \ + extmod/uos_dupterm.o \ + lib/embed/abort_.o \ + lib/utils/printf.o \ + +# prepend the build destination prefix to the py object files +PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME)) +PY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME)) + +# this is a convenience variable for ports that want core, extmod and frozen code +PY_O = $(PY_CORE_O) $(PY_EXTMOD_O) + +# object file for frozen files +ifneq ($(FROZEN_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen.o +endif + +# object file for frozen bytecode (frozen .mpy files) +ifneq ($(FROZEN_MPY_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o +endif + +# Sources that may contain qstrings +SRC_QSTR_IGNORE = py/nlr% +SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c) + +# Anything that depends on FORCE will be considered out-of-date +FORCE: +.PHONY: FORCE + +$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD) + $(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $@ + +# mpconfigport.mk is optional, but changes to it may drastically change +# overall config, so they need to be caught +MPCONFIGPORT_MK = $(wildcard mpconfigport.mk) + +# qstr data +# Adding an order only dependency on $(HEADER_BUILD) causes $(HEADER_BUILD) to get +# created before we run the script to generate the .h +# Note: we need to protect the qstr names from the preprocessor, so we wrap +# the lines in "" and then unwrap after the preprocessor is finished. +$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD) + $(ECHO) "GEN $@" + $(Q)cat $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^"\(Q(.*)\)"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h + $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@ + +# Force nlr code to always be compiled with space-saving optimisation so +# that the function preludes are of a minimal and predictable form. +$(PY_BUILD)/nlr%.o: CFLAGS += -Os + +# optimising gc for speed; 5ms down to 4ms on pybv2 +$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT) + +# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster) +$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT) +# Optimizing vm.o for modern deeply pipelined CPUs with branch predictors +# may require disabling tail jump optimization. This will make sure that +# each opcode has its own dispatching jump which will improve branch +# branch predictor efficiency. +# http://article.gmane.org/gmane.comp.lang.lua.general/75426 +# http://hg.python.org/cpython/file/b127046831e2/Python/ceval.c#l828 +# http://www.emulators.com/docs/nx25_nostradamus.htm +#-fno-crossjumping diff --git a/src/openmv/src/micropython/py/pystack.c b/src/openmv/src/micropython/py/pystack.c new file mode 100755 index 0000000..552e59d --- /dev/null +++ b/src/openmv/src/micropython/py/pystack.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end) { + MP_STATE_THREAD(pystack_start) = start; + MP_STATE_THREAD(pystack_end) = end; + MP_STATE_THREAD(pystack_cur) = start; +} + +void *mp_pystack_alloc(size_t n_bytes) { + n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1); + #if MP_PYSTACK_DEBUG + n_bytes += MICROPY_PYSTACK_ALIGN; + #endif + if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) { + // out of memory in the pystack + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted))); + } + void *ptr = MP_STATE_THREAD(pystack_cur); + MP_STATE_THREAD(pystack_cur) += n_bytes; + #if MP_PYSTACK_DEBUG + *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN) = n_bytes; + #endif + return ptr; +} + +#endif diff --git a/src/openmv/src/micropython/py/pystack.h b/src/openmv/src/micropython/py/pystack.h new file mode 100755 index 0000000..82ac374 --- /dev/null +++ b/src/openmv/src/micropython/py/pystack.h @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PYSTACK_H +#define MICROPY_INCLUDED_PY_PYSTACK_H + +#include "py/mpstate.h" + +// Enable this debugging option to check that the amount of memory freed is +// consistent with amounts that were previously allocated. +#define MP_PYSTACK_DEBUG (0) + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end); +void *mp_pystack_alloc(size_t n_bytes); + +// This function can free multiple continuous blocks at once: just pass the +// pointer to the block that was allocated first and it and all subsequently +// allocated blocks will be freed. +static inline void mp_pystack_free(void *ptr) { + assert((uint8_t*)ptr >= MP_STATE_THREAD(pystack_start)); + assert((uint8_t*)ptr <= MP_STATE_THREAD(pystack_cur)); + #if MP_PYSTACK_DEBUG + size_t n_bytes_to_free = MP_STATE_THREAD(pystack_cur) - (uint8_t*)ptr; + size_t n_bytes = *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN); + while (n_bytes < n_bytes_to_free) { + n_bytes += *(size_t*)(MP_STATE_THREAD(pystack_cur) - n_bytes - MICROPY_PYSTACK_ALIGN); + } + if (n_bytes != n_bytes_to_free) { + mp_printf(&mp_plat_print, "mp_pystack_free() failed: %u != %u\n", (uint)n_bytes_to_free, + (uint)*(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN)); + assert(0); + } + #endif + MP_STATE_THREAD(pystack_cur) = (uint8_t*)ptr; +} + +static inline void mp_pystack_realloc(void *ptr, size_t n_bytes) { + mp_pystack_free(ptr); + mp_pystack_alloc(n_bytes); +} + +static inline size_t mp_pystack_usage(void) { + return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start); +} + +static inline size_t mp_pystack_limit(void) { + return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start); +} + +#endif + +#if !MICROPY_ENABLE_PYSTACK + +#define mp_local_alloc(n_bytes) alloca(n_bytes) + +static inline void mp_local_free(void *ptr) { + (void)ptr; +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return m_new(uint8_t, n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes); +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + m_del(uint8_t, ptr, n_bytes); +} + +#else + +static inline void *mp_local_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void mp_local_free(void *ptr) { + mp_pystack_free(ptr); +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + (void)old_n_bytes; + mp_pystack_realloc(ptr, new_n_bytes); + return ptr; +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + (void)n_bytes; + mp_pystack_free(ptr); +} + +#endif + +#endif // MICROPY_INCLUDED_PY_PYSTACK_H diff --git a/src/openmv/src/micropython/py/qstr.c b/src/openmv/src/micropython/py/qstr.c new file mode 100755 index 0000000..08c3e25 --- /dev/null +++ b/src/openmv/src/micropython/py/qstr.c @@ -0,0 +1,296 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/mpstate.h" +#include "py/qstr.h" +#include "py/gc.h" + +// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) +// ultimately we will replace this with a static hash table of some kind +// also probably need to include the length in the string data, to allow null bytes in the string + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +// A qstr is an index into the qstr pool. +// The data for a qstr contains (hash, length, data): +// - hash (configurable number of bytes) +// - length (configurable number of bytes) +// - data ("length" number of bytes) +// - \0 terminated (so they can be printed using printf) + +#if MICROPY_QSTR_BYTES_IN_HASH == 1 + #define Q_HASH_MASK (0xff) + #define Q_GET_HASH(q) ((mp_uint_t)(q)[0]) + #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); } while (0) +#elif MICROPY_QSTR_BYTES_IN_HASH == 2 + #define Q_HASH_MASK (0xffff) + #define Q_GET_HASH(q) ((mp_uint_t)(q)[0] | ((mp_uint_t)(q)[1] << 8)) + #define Q_SET_HASH(q, hash) do { (q)[0] = (hash); (q)[1] = (hash) >> 8; } while (0) +#else + #error unimplemented qstr hash decoding +#endif +#define Q_GET_ALLOC(q) (MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1) +#define Q_GET_DATA(q) ((q) + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN) +#if MICROPY_QSTR_BYTES_IN_LEN == 1 + #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH]) + #define Q_SET_LENGTH(q, len) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); } while (0) +#elif MICROPY_QSTR_BYTES_IN_LEN == 2 + #define Q_GET_LENGTH(q) ((q)[MICROPY_QSTR_BYTES_IN_HASH] | ((q)[MICROPY_QSTR_BYTES_IN_HASH + 1] << 8)) + #define Q_SET_LENGTH(q, len) do { (q)[MICROPY_QSTR_BYTES_IN_HASH] = (len); (q)[MICROPY_QSTR_BYTES_IN_HASH + 1] = (len) >> 8; } while (0) +#else + #error unimplemented qstr length decoding +#endif + +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +#define QSTR_ENTER() mp_thread_mutex_lock(&MP_STATE_VM(qstr_mutex), 1) +#define QSTR_EXIT() mp_thread_mutex_unlock(&MP_STATE_VM(qstr_mutex)) +#else +#define QSTR_ENTER() +#define QSTR_EXIT() +#endif + +// this must match the equivalent function in makeqstrdata.py +mp_uint_t qstr_compute_hash(const byte *data, size_t len) { + // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html + mp_uint_t hash = 5381; + for (const byte *top = data + len; data < top; data++) { + hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data + } + hash &= Q_HASH_MASK; + // Make sure that valid hash is never zero, zero means "hash not computed" + if (hash == 0) { + hash++; + } + return hash; +} + +const qstr_pool_t mp_qstr_const_pool = { + NULL, // no previous pool + 0, // no previous pool + 10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below) + MP_QSTRnumber_of, // corresponds to number of strings in array just below + { +#ifndef NO_QSTR +#define QDEF(id, str) str, +#include "genhdr/qstrdefs.generated.h" +#undef QDEF +#endif + }, +}; + +#ifdef MICROPY_QSTR_EXTRA_POOL +extern const qstr_pool_t MICROPY_QSTR_EXTRA_POOL; +#define CONST_POOL MICROPY_QSTR_EXTRA_POOL +#else +#define CONST_POOL mp_qstr_const_pool +#endif + +void qstr_init(void) { + MP_STATE_VM(last_pool) = (qstr_pool_t*)&CONST_POOL; // we won't modify the const_pool since it has no allocated room left + MP_STATE_VM(qstr_last_chunk) = NULL; + + #if MICROPY_PY_THREAD + mp_thread_mutex_init(&MP_STATE_VM(qstr_mutex)); + #endif +} + +STATIC const byte *find_qstr(qstr q) { + // search pool for this qstr + // total_prev_len==0 in the final pool, so the loop will always terminate + qstr_pool_t *pool = MP_STATE_VM(last_pool); + while (q < pool->total_prev_len) { + pool = pool->prev; + } + return pool->qstrs[q - pool->total_prev_len]; +} + +// qstr_mutex must be taken while in this function +STATIC qstr qstr_add(const byte *q_ptr) { + DEBUG_printf("QSTR: add hash=%d len=%d data=%.*s\n", Q_GET_HASH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_LENGTH(q_ptr), Q_GET_DATA(q_ptr)); + + // make sure we have room in the pool for a new qstr + if (MP_STATE_VM(last_pool)->len >= MP_STATE_VM(last_pool)->alloc) { + qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char*, MP_STATE_VM(last_pool)->alloc * 2); + if (pool == NULL) { + QSTR_EXIT(); + m_malloc_fail(MP_STATE_VM(last_pool)->alloc * 2); + } + pool->prev = MP_STATE_VM(last_pool); + pool->total_prev_len = MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len; + pool->alloc = MP_STATE_VM(last_pool)->alloc * 2; + pool->len = 0; + MP_STATE_VM(last_pool) = pool; + DEBUG_printf("QSTR: allocate new pool of size %d\n", MP_STATE_VM(last_pool)->alloc); + } + + // add the new qstr + MP_STATE_VM(last_pool)->qstrs[MP_STATE_VM(last_pool)->len++] = q_ptr; + + // return id for the newly-added qstr + return MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len - 1; +} + +qstr qstr_find_strn(const char *str, size_t str_len) { + // work out hash of str + mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len); + + // search pools for the data + for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) { + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + if (Q_GET_HASH(*q) == str_hash && Q_GET_LENGTH(*q) == str_len && memcmp(Q_GET_DATA(*q), str, str_len) == 0) { + return pool->total_prev_len + (q - pool->qstrs); + } + } + } + + // not found; return null qstr + return 0; +} + +qstr qstr_from_str(const char *str) { + return qstr_from_strn(str, strlen(str)); +} + +qstr qstr_from_strn(const char *str, size_t len) { + assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); + QSTR_ENTER(); + qstr q = qstr_find_strn(str, len); + if (q == 0) { + // qstr does not exist in interned pool so need to add it + + // compute number of bytes needed to intern this string + size_t n_bytes = MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1; + + if (MP_STATE_VM(qstr_last_chunk) != NULL && MP_STATE_VM(qstr_last_used) + n_bytes > MP_STATE_VM(qstr_last_alloc)) { + // not enough room at end of previously interned string so try to grow + byte *new_p = m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_alloc) + n_bytes, false); + if (new_p == NULL) { + // could not grow existing memory; shrink it to fit previous + (void)m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used), false); + MP_STATE_VM(qstr_last_chunk) = NULL; + } else { + // could grow existing memory + MP_STATE_VM(qstr_last_alloc) += n_bytes; + } + } + + if (MP_STATE_VM(qstr_last_chunk) == NULL) { + // no existing memory for the interned string so allocate a new chunk + size_t al = n_bytes; + if (al < MICROPY_ALLOC_QSTR_CHUNK_INIT) { + al = MICROPY_ALLOC_QSTR_CHUNK_INIT; + } + MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, al); + if (MP_STATE_VM(qstr_last_chunk) == NULL) { + // failed to allocate a large chunk so try with exact size + MP_STATE_VM(qstr_last_chunk) = m_new_maybe(byte, n_bytes); + if (MP_STATE_VM(qstr_last_chunk) == NULL) { + QSTR_EXIT(); + m_malloc_fail(n_bytes); + } + al = n_bytes; + } + MP_STATE_VM(qstr_last_alloc) = al; + MP_STATE_VM(qstr_last_used) = 0; + } + + // allocate memory from the chunk for this new interned string's data + byte *q_ptr = MP_STATE_VM(qstr_last_chunk) + MP_STATE_VM(qstr_last_used); + MP_STATE_VM(qstr_last_used) += n_bytes; + + // store the interned strings' data + mp_uint_t hash = qstr_compute_hash((const byte*)str, len); + Q_SET_HASH(q_ptr, hash); + Q_SET_LENGTH(q_ptr, len); + memcpy(q_ptr + MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN, str, len); + q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; + q = qstr_add(q_ptr); + } + QSTR_EXIT(); + return q; +} + +mp_uint_t qstr_hash(qstr q) { + return Q_GET_HASH(find_qstr(q)); +} + +size_t qstr_len(qstr q) { + const byte *qd = find_qstr(q); + return Q_GET_LENGTH(qd); +} + +const char *qstr_str(qstr q) { + const byte *qd = find_qstr(q); + return (const char*)Q_GET_DATA(qd); +} + +const byte *qstr_data(qstr q, size_t *len) { + const byte *qd = find_qstr(q); + *len = Q_GET_LENGTH(qd); + return Q_GET_DATA(qd); +} + +void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes) { + QSTR_ENTER(); + *n_pool = 0; + *n_qstr = 0; + *n_str_data_bytes = 0; + *n_total_bytes = 0; + for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) { + *n_pool += 1; + *n_qstr += pool->len; + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + *n_str_data_bytes += Q_GET_ALLOC(*q); + } + #if MICROPY_ENABLE_GC + *n_total_bytes += gc_nbytes(pool); // this counts actual bytes used in heap + #else + *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc; + #endif + } + *n_total_bytes += *n_str_data_bytes; + QSTR_EXIT(); +} + +#if MICROPY_PY_MICROPYTHON_MEM_INFO +void qstr_dump_data(void) { + QSTR_ENTER(); + for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL && pool != &CONST_POOL; pool = pool->prev) { + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + mp_printf(&mp_plat_print, "Q(%s)\n", Q_GET_DATA(*q)); + } + } + QSTR_EXIT(); +} +#endif diff --git a/src/openmv/src/micropython/py/qstr.h b/src/openmv/src/micropython/py/qstr.h new file mode 100755 index 0000000..f4375ee --- /dev/null +++ b/src/openmv/src/micropython/py/qstr.h @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_QSTR_H +#define MICROPY_INCLUDED_PY_QSTR_H + +#include "py/mpconfig.h" +#include "py/misc.h" + +// See qstrdefs.h for a list of qstr's that are available as constants. +// Reference them as MP_QSTR_xxxx. +// +// Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx") +// for qstrs that are referenced this way, but you don't want to have them in ROM. + +// first entry in enum will be MP_QSTR_NULL=0, which indicates invalid/no qstr +enum { +#ifndef NO_QSTR +#define QDEF(id, str) id, +#include "genhdr/qstrdefs.generated.h" +#undef QDEF +#endif + MP_QSTRnumber_of, // no underscore so it can't clash with any of the above +}; + +typedef size_t qstr; + +typedef struct _qstr_pool_t { + struct _qstr_pool_t *prev; + size_t total_prev_len; + size_t alloc; + size_t len; + const byte *qstrs[]; +} qstr_pool_t; + +#define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s))) +#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len) + +void qstr_init(void); + +mp_uint_t qstr_compute_hash(const byte *data, size_t len); +qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if not found + +qstr qstr_from_str(const char *str); +qstr qstr_from_strn(const char *str, size_t len); + +mp_uint_t qstr_hash(qstr q); +const char *qstr_str(qstr q); +size_t qstr_len(qstr q); +const byte *qstr_data(qstr q, size_t *len); + +void qstr_pool_info(size_t *n_pool, size_t *n_qstr, size_t *n_str_data_bytes, size_t *n_total_bytes); +void qstr_dump_data(void); + +#endif // MICROPY_INCLUDED_PY_QSTR_H diff --git a/src/openmv/src/micropython/py/qstrdefs.h b/src/openmv/src/micropython/py/qstrdefs.h new file mode 100755 index 0000000..5c8b13b --- /dev/null +++ b/src/openmv/src/micropython/py/qstrdefs.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" + +// All the qstr definitions in this file are available as constants. +// That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx. + +// qstr configuration passed to makeqstrdata.py of the form QCFG(key, value) +QCFG(BYTES_IN_LEN, MICROPY_QSTR_BYTES_IN_LEN) +QCFG(BYTES_IN_HASH, MICROPY_QSTR_BYTES_IN_HASH) + +Q() +Q(*) +Q(_) +Q(/) +#if MICROPY_PY_BUILTINS_STR_OP_MODULO +Q(%#o) +Q(%#x) +#else +Q({:#o}) +Q({:#x}) +#endif +Q({:#b}) +Q( ) +Q(\n) +Q(maximum recursion depth exceeded) +Q() +Q() +Q() +Q() +Q() +Q() +Q() +Q() +Q(utf-8) + +#if MICROPY_ENABLE_PYSTACK +Q(pystack exhausted) +#endif diff --git a/src/openmv/src/micropython/py/reader.c b/src/openmv/src/micropython/py/reader.c new file mode 100755 index 0000000..8036410 --- /dev/null +++ b/src/openmv/src/micropython/py/reader.c @@ -0,0 +1,138 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/reader.h" + +typedef struct _mp_reader_mem_t { + size_t free_len; // if >0 mem is freed on close by: m_free(beg, free_len) + const byte *beg; + const byte *cur; + const byte *end; +} mp_reader_mem_t; + +STATIC mp_uint_t mp_reader_mem_readbyte(void *data) { + mp_reader_mem_t *reader = (mp_reader_mem_t*)data; + if (reader->cur < reader->end) { + return *reader->cur++; + } else { + return MP_READER_EOF; + } +} + +STATIC void mp_reader_mem_close(void *data) { + mp_reader_mem_t *reader = (mp_reader_mem_t*)data; + if (reader->free_len > 0) { + m_del(char, (char*)reader->beg, reader->free_len); + } + m_del_obj(mp_reader_mem_t, reader); +} + +void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len) { + mp_reader_mem_t *rm = m_new_obj(mp_reader_mem_t); + rm->free_len = free_len; + rm->beg = buf; + rm->cur = buf; + rm->end = buf + len; + reader->data = rm; + reader->readbyte = mp_reader_mem_readbyte; + reader->close = mp_reader_mem_close; +} + +#if MICROPY_READER_POSIX + +#include +#include +#include + +typedef struct _mp_reader_posix_t { + bool close_fd; + int fd; + size_t len; + size_t pos; + byte buf[20]; +} mp_reader_posix_t; + +STATIC mp_uint_t mp_reader_posix_readbyte(void *data) { + mp_reader_posix_t *reader = (mp_reader_posix_t*)data; + if (reader->pos >= reader->len) { + if (reader->len == 0) { + return MP_READER_EOF; + } else { + int n = read(reader->fd, reader->buf, sizeof(reader->buf)); + if (n <= 0) { + reader->len = 0; + return MP_READER_EOF; + } + reader->len = n; + reader->pos = 0; + } + } + return reader->buf[reader->pos++]; +} + +STATIC void mp_reader_posix_close(void *data) { + mp_reader_posix_t *reader = (mp_reader_posix_t*)data; + if (reader->close_fd) { + close(reader->fd); + } + m_del_obj(mp_reader_posix_t, reader); +} + +void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { + mp_reader_posix_t *rp = m_new_obj(mp_reader_posix_t); + rp->close_fd = close_fd; + rp->fd = fd; + int n = read(rp->fd, rp->buf, sizeof(rp->buf)); + if (n == -1) { + if (close_fd) { + close(fd); + } + mp_raise_OSError(errno); + } + rp->len = n; + rp->pos = 0; + reader->data = rp; + reader->readbyte = mp_reader_posix_readbyte; + reader->close = mp_reader_posix_close; +} + +#if !MICROPY_VFS_POSIX +// If MICROPY_VFS_POSIX is defined then this function is provided by the VFS layer +void mp_reader_new_file(mp_reader_t *reader, const char *filename) { + int fd = open(filename, O_RDONLY, 0644); + if (fd < 0) { + mp_raise_OSError(errno); + } + mp_reader_new_file_from_fd(reader, fd, true); +} +#endif + +#endif diff --git a/src/openmv/src/micropython/py/reader.h b/src/openmv/src/micropython/py/reader.h new file mode 100755 index 0000000..8511c72 --- /dev/null +++ b/src/openmv/src/micropython/py/reader.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_READER_H +#define MICROPY_INCLUDED_PY_READER_H + +#include "py/obj.h" + +// the readbyte function must return the next byte in the input stream +// it must return MP_READER_EOF if end of stream +// it can be called again after returning MP_READER_EOF, and in that case must return MP_READER_EOF +#define MP_READER_EOF ((mp_uint_t)(-1)) + +typedef struct _mp_reader_t { + void *data; + mp_uint_t (*readbyte)(void *data); + void (*close)(void *data); +} mp_reader_t; + +void mp_reader_new_mem(mp_reader_t *reader, const byte *buf, size_t len, size_t free_len); +void mp_reader_new_file(mp_reader_t *reader, const char *filename); +void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd); + +#endif // MICROPY_INCLUDED_PY_READER_H diff --git a/src/openmv/src/micropython/py/repl.c b/src/openmv/src/micropython/py/repl.c new file mode 100755 index 0000000..da0fefb --- /dev/null +++ b/src/openmv/src/micropython/py/repl.c @@ -0,0 +1,269 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/repl.h" + +#if MICROPY_HELPER_REPL + +STATIC bool str_startswith_word(const char *str, const char *head) { + size_t i; + for (i = 0; str[i] && head[i]; i++) { + if (str[i] != head[i]) { + return false; + } + } + return head[i] == '\0' && (str[i] == '\0' || !unichar_isident(str[i])); +} + +bool mp_repl_continue_with_input(const char *input) { + // check for blank input + if (input[0] == '\0') { + return false; + } + + // check if input starts with a certain keyword + bool starts_with_compound_keyword = + input[0] == '@' + || str_startswith_word(input, "if") + || str_startswith_word(input, "while") + || str_startswith_word(input, "for") + || str_startswith_word(input, "try") + || str_startswith_word(input, "with") + || str_startswith_word(input, "def") + || str_startswith_word(input, "class") + #if MICROPY_PY_ASYNC_AWAIT + || str_startswith_word(input, "async") + #endif + ; + + // check for unmatched open bracket, quote or escape quote + #define Q_NONE (0) + #define Q_1_SINGLE (1) + #define Q_1_DOUBLE (2) + #define Q_3_SINGLE (3) + #define Q_3_DOUBLE (4) + int n_paren = 0; + int n_brack = 0; + int n_brace = 0; + int in_quote = Q_NONE; + const char *i; + for (i = input; *i; i++) { + if (*i == '\'') { + if ((in_quote == Q_NONE || in_quote == Q_3_SINGLE) && i[1] == '\'' && i[2] == '\'') { + i += 2; + in_quote = Q_3_SINGLE - in_quote; + } else if (in_quote == Q_NONE || in_quote == Q_1_SINGLE) { + in_quote = Q_1_SINGLE - in_quote; + } + } else if (*i == '"') { + if ((in_quote == Q_NONE || in_quote == Q_3_DOUBLE) && i[1] == '"' && i[2] == '"') { + i += 2; + in_quote = Q_3_DOUBLE - in_quote; + } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) { + in_quote = Q_1_DOUBLE - in_quote; + } + } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"' || i[1] == '\\')) { + if (in_quote != Q_NONE) { + i++; + } + } else if (in_quote == Q_NONE) { + switch (*i) { + case '(': n_paren += 1; break; + case ')': n_paren -= 1; break; + case '[': n_brack += 1; break; + case ']': n_brack -= 1; break; + case '{': n_brace += 1; break; + case '}': n_brace -= 1; break; + default: break; + } + } + } + + // continue if unmatched 3-quotes + if (in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { + return true; + } + + // continue if unmatched brackets, but only if not in a 1-quote + if ((n_paren > 0 || n_brack > 0 || n_brace > 0) && in_quote == Q_NONE) { + return true; + } + + // continue if last character was backslash (for line continuation) + if (i[-1] == '\\') { + return true; + } + + // continue if compound keyword and last line was not empty + if (starts_with_compound_keyword && i[-1] != '\n') { + return true; + } + + // otherwise, don't continue + return false; +} + +size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str) { + // scan backwards to find start of "a.b.c" chain + const char *org_str = str; + const char *top = str + len; + for (const char *s = top; --s >= str;) { + if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { + ++s; + str = s; + break; + } + } + + size_t nqstr = QSTR_TOTAL(); + + // begin search in outer global dict which is accessed from __main__ + mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__); + mp_obj_t dest[2]; + + for (;;) { + // get next word in string to complete + const char *s_start = str; + while (str < top && *str != '.') { + ++str; + } + size_t s_len = str - s_start; + + if (str < top) { + // a complete word, lookup in current object + qstr q = qstr_find_strn(s_start, s_len); + if (q == MP_QSTR_NULL) { + // lookup will fail + return 0; + } + mp_load_method_protected(obj, q, dest, true); + obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found + + if (obj == MP_OBJ_NULL) { + // lookup failed + return 0; + } + + // skip '.' to move to next word + ++str; + + } else { + // end of string, do completion on this partial name + + // look for matches + const char *match_str = NULL; + size_t match_len = 0; + qstr q_first = 0, q_last = 0; + for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_protected(obj, q, dest, true); + if (dest[0] != MP_OBJ_NULL) { + if (match_str == NULL) { + match_str = d_str; + match_len = d_len; + } else { + // search for longest common prefix of match_str and d_str + // (assumes these strings are null-terminated) + for (size_t j = s_len; j <= match_len && j <= d_len; ++j) { + if (match_str[j] != d_str[j]) { + match_len = j; + break; + } + } + } + if (q_first == 0) { + q_first = q; + } + q_last = q; + } + } + } + + // nothing found + if (q_first == 0) { + // If there're no better alternatives, and if it's first word + // in the line, try to complete "import". + if (s_start == org_str) { + static const char import_str[] = "import "; + if (memcmp(s_start, import_str, s_len) == 0) { + *compl_str = import_str + s_len; + return sizeof(import_str) - 1 - s_len; + } + } + + return 0; + } + + // 1 match found, or multiple matches with a common prefix + if (q_first == q_last || match_len > s_len) { + *compl_str = match_str + s_len; + return match_len - s_len; + } + + // multiple matches found, print them out + + #define WORD_SLOT_LEN (16) + #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) + + int line_len = MAX_LINE_LEN; // force a newline for first word + for (qstr q = q_first; q <= q_last; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_protected(obj, q, dest, true); + if (dest[0] != MP_OBJ_NULL) { + int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; + if (gap < 2) { + gap += WORD_SLOT_LEN; + } + if (line_len + gap + d_len <= MAX_LINE_LEN) { + // TODO optimise printing of gap? + for (int j = 0; j < gap; ++j) { + mp_print_str(print, " "); + } + mp_print_str(print, d_str); + line_len += gap + d_len; + } else { + mp_printf(print, "\n%s", d_str); + line_len = d_len; + } + } + } + } + mp_print_str(print, "\n"); + + return (size_t)(-1); // indicate many matches + } + } +} + +#endif // MICROPY_HELPER_REPL diff --git a/src/openmv/src/micropython/py/repl.h b/src/openmv/src/micropython/py/repl.h new file mode 100755 index 0000000..a7a4136 --- /dev/null +++ b/src/openmv/src/micropython/py/repl.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_REPL_H +#define MICROPY_INCLUDED_PY_REPL_H + +#include "py/mpconfig.h" +#include "py/misc.h" +#include "py/mpprint.h" + +#if MICROPY_HELPER_REPL +bool mp_repl_continue_with_input(const char *input); +size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print, const char **compl_str); +#endif + +#endif // MICROPY_INCLUDED_PY_REPL_H diff --git a/src/openmv/src/micropython/py/ringbuf.h b/src/openmv/src/micropython/py/ringbuf.h new file mode 100755 index 0000000..b416927 --- /dev/null +++ b/src/openmv/src/micropython/py/ringbuf.h @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_RINGBUF_H +#define MICROPY_INCLUDED_PY_RINGBUF_H + +typedef struct _ringbuf_t { + uint8_t *buf; + uint16_t size; + uint16_t iget; + uint16_t iput; +} ringbuf_t; + +// Static initialization: +// byte buf_array[N]; +// ringbuf_t buf = {buf_array, sizeof(buf_array)}; + +// Dynamic initialization. This creates root pointer! +#define ringbuf_alloc(r, sz) \ +{ \ + (r)->buf = m_new(uint8_t, sz); \ + (r)->size = sz; \ + (r)->iget = (r)->iput = 0; \ +} + +static inline int ringbuf_get(ringbuf_t *r) { + if (r->iget == r->iput) { + return -1; + } + uint8_t v = r->buf[r->iget++]; + if (r->iget >= r->size) { + r->iget = 0; + } + return v; +} + +static inline int ringbuf_put(ringbuf_t *r, uint8_t v) { + uint32_t iput_new = r->iput + 1; + if (iput_new >= r->size) { + iput_new = 0; + } + if (iput_new == r->iget) { + return -1; + } + r->buf[r->iput] = v; + r->iput = iput_new; + return 0; +} + +#endif // MICROPY_INCLUDED_PY_RINGBUF_H diff --git a/src/openmv/src/micropython/py/runtime.c b/src/openmv/src/micropython/py/runtime.c new file mode 100755 index 0000000..8f020f5 --- /dev/null +++ b/src/openmv/src/micropython/py/runtime.c @@ -0,0 +1,1472 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/parsenum.h" +#include "py/compile.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/objmodule.h" +#include "py/objgenerator.h" +#include "py/smallint.h" +#include "py/runtime.h" +#include "py/builtin.h" +#include "py/stackctrl.h" +#include "py/gc.h" + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#define DEBUG_OP_printf(...) (void)0 +#endif + +const mp_obj_module_t mp_module___main__ = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&MP_STATE_VM(dict_main), +}; + +void mp_init(void) { + qstr_init(); + + // no pending exceptions to start with + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + #if MICROPY_ENABLE_SCHEDULER + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + MP_STATE_VM(sched_sp) = 0; + #endif + +#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF + mp_init_emergency_exception_buf(); +#endif + + #if MICROPY_KBD_EXCEPTION + // initialise the exception object for raising KeyboardInterrupt + MP_STATE_VM(mp_kbd_exception).base.type = &mp_type_KeyboardInterrupt; + MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0; + MP_STATE_VM(mp_kbd_exception).traceback_len = 0; + MP_STATE_VM(mp_kbd_exception).traceback_data = NULL; + MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj; + #endif + + // call port specific initialization if any +#ifdef MICROPY_PORT_INIT_FUNC + MICROPY_PORT_INIT_FUNC; +#endif + + #if MICROPY_ENABLE_COMPILER + // optimization disabled by default + MP_STATE_VM(mp_optimise_value) = 0; + #endif + + // init global module dict + mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); + + // initialise the __main__ module + mp_obj_dict_init(&MP_STATE_VM(dict_main), 1); + mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(dict_main)), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + + // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) + mp_locals_set(&MP_STATE_VM(dict_main)); + mp_globals_set(&MP_STATE_VM(dict_main)); + + #if MICROPY_CAN_OVERRIDE_BUILTINS + // start with no extensions to builtins + MP_STATE_VM(mp_module_builtins_override_dict) = NULL; + #endif + + #if MICROPY_PY_OS_DUPTERM + for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) { + MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL; + } + #endif + + #if MICROPY_FSUSERMOUNT + // zero out the pointers to the user-mounted devices + memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount))); + #endif + + #if MICROPY_VFS + // initialise the VFS sub-system + MP_STATE_VM(vfs_cur) = NULL; + MP_STATE_VM(vfs_mount_table) = NULL; + #endif + + #if MICROPY_PY_THREAD_GIL + mp_thread_mutex_init(&MP_STATE_VM(gil_mutex)); + #endif + + MP_THREAD_GIL_ENTER(); +} + +void mp_deinit(void) { + //mp_obj_dict_free(&dict_main); + //mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map)); + + // call port specific deinitialization if any +#ifdef MICROPY_PORT_DEINIT_FUNC + MICROPY_PORT_DEINIT_FUNC; +#endif +} + +mp_obj_t mp_load_name(qstr qst) { + // logic: search locals, globals, builtins + DEBUG_OP_printf("load name %s\n", qstr_str(qst)); + // If we're at the outer scope (locals == globals), dispatch to load_global right away + if (mp_locals_get() != mp_globals_get()) { + mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem != NULL) { + return elem->value; + } + } + return mp_load_global(qst); +} + +mp_obj_t mp_load_global(qstr qst) { + // logic: search globals, builtins + DEBUG_OP_printf("load global %s\n", qstr_str(qst)); + mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem == NULL) { + #if MICROPY_CAN_OVERRIDE_BUILTINS + if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) { + // lookup in additional dynamic table of builtins first + elem = mp_map_lookup(&MP_STATE_VM(mp_module_builtins_override_dict)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem != NULL) { + return elem->value; + } + } + #endif + elem = mp_map_lookup((mp_map_t*)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem == NULL) { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_NameError, "name not defined"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, + "name '%q' isn't defined", qst)); + } + } + } + return elem->value; +} + +mp_obj_t mp_load_build_class(void) { + DEBUG_OP_printf("load_build_class\n"); + #if MICROPY_CAN_OVERRIDE_BUILTINS + if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) { + // lookup in additional dynamic table of builtins first + mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_module_builtins_override_dict)->map, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP); + if (elem != NULL) { + return elem->value; + } + } + #endif + return MP_OBJ_FROM_PTR(&mp_builtin___build_class___obj); +} + +void mp_store_name(qstr qst, mp_obj_t obj) { + DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qst), obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj); +} + +void mp_delete_name(qstr qst) { + DEBUG_OP_printf("delete name %s\n", qstr_str(qst)); + // TODO convert KeyError to NameError if qst not found + mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst)); +} + +void mp_store_global(qstr qst, mp_obj_t obj) { + DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qst), obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj); +} + +void mp_delete_global(qstr qst) { + DEBUG_OP_printf("delete global %s\n", qstr_str(qst)); + // TODO convert KeyError to NameError if qst not found + mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst)); +} + +mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { + DEBUG_OP_printf("unary " UINT_FMT " %q %p\n", op, mp_unary_op_method_name[op], arg); + + if (op == MP_UNARY_OP_NOT) { + // "not x" is the negative of whether "x" is true per Python semantics + return mp_obj_new_bool(mp_obj_is_true(arg) == 0); + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(val != 0); + case MP_UNARY_OP_HASH: + return arg; + case MP_UNARY_OP_POSITIVE: + return arg; + case MP_UNARY_OP_NEGATIVE: + // check for overflow + if (val == MP_SMALL_INT_MIN) { + return mp_obj_new_int(-val); + } else { + return MP_OBJ_NEW_SMALL_INT(-val); + } + case MP_UNARY_OP_ABS: + if (val >= 0) { + return arg; + } else if (val == MP_SMALL_INT_MIN) { + // check for overflow + return mp_obj_new_int(-val); + } else { + return MP_OBJ_NEW_SMALL_INT(-val); + } + default: + assert(op == MP_UNARY_OP_INVERT); + return MP_OBJ_NEW_SMALL_INT(~val); + } + } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { + // fast path for hashing str/bytes + GET_STR_HASH(arg, h); + if (h == 0) { + GET_STR_DATA_LEN(arg, data, len); + h = qstr_compute_hash(data, len); + } + return MP_OBJ_NEW_SMALL_INT(h); + } else { + mp_obj_type_t *type = mp_obj_get_type(arg); + if (type->unary_op != NULL) { + mp_obj_t result = type->unary_op(op, arg); + if (result != MP_OBJ_NULL) { + return result; + } + } + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("unsupported type for operator"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "unsupported type for %q: '%s'", + mp_unary_op_method_name[op], mp_obj_get_type_str(arg))); + } + } +} + +mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { + DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs); + + // TODO correctly distinguish inplace operators for mutable objects + // lookup logic that CPython uses for +=: + // check for implemented += + // then check for implemented + + // then check for implemented seq.inplace_concat + // then check for implemented seq.concat + // then fail + // note that list does not implement + or +=, so that inplace_concat is reached first for += + + // deal with is + if (op == MP_BINARY_OP_IS) { + return mp_obj_new_bool(lhs == rhs); + } + + // deal with == and != for all types + if (op == MP_BINARY_OP_EQUAL || op == MP_BINARY_OP_NOT_EQUAL) { + if (mp_obj_equal(lhs, rhs)) { + if (op == MP_BINARY_OP_EQUAL) { + return mp_const_true; + } else { + return mp_const_false; + } + } else { + if (op == MP_BINARY_OP_EQUAL) { + return mp_const_false; + } else { + return mp_const_true; + } + } + } + + // deal with exception_match for all types + if (op == MP_BINARY_OP_EXCEPTION_MATCH) { + // rhs must be issubclass(rhs, BaseException) + if (mp_obj_is_exception_type(rhs)) { + if (mp_obj_exception_match(lhs, rhs)) { + return mp_const_true; + } else { + return mp_const_false; + } + } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_tuple)) { + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(rhs); + for (size_t i = 0; i < tuple->len; i++) { + rhs = tuple->items[i]; + if (!mp_obj_is_exception_type(rhs)) { + goto unsupported_op; + } + if (mp_obj_exception_match(lhs, rhs)) { + return mp_const_true; + } + } + return mp_const_false; + } + goto unsupported_op; + } + + if (MP_OBJ_IS_SMALL_INT(lhs)) { + mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs); + if (MP_OBJ_IS_SMALL_INT(rhs)) { + mp_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs); + // This is a binary operation: lhs_val op rhs_val + // We need to be careful to handle overflow; see CERT INT32-C + // Operations that can overflow: + // + result always fits in mp_int_t, then handled by SMALL_INT check + // - result always fits in mp_int_t, then handled by SMALL_INT check + // * checked explicitly + // / if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check + // % if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check + // << checked explicitly + switch (op) { + case MP_BINARY_OP_OR: + case MP_BINARY_OP_INPLACE_OR: lhs_val |= rhs_val; break; + case MP_BINARY_OP_XOR: + case MP_BINARY_OP_INPLACE_XOR: lhs_val ^= rhs_val; break; + case MP_BINARY_OP_AND: + case MP_BINARY_OP_INPLACE_AND: lhs_val &= rhs_val; break; + case MP_BINARY_OP_LSHIFT: + case MP_BINARY_OP_INPLACE_LSHIFT: { + if (rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError("negative shift count"); + } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { + // left-shift will overflow, so use higher precision integer + lhs = mp_obj_new_int_from_ll(lhs_val); + goto generic_binary_op; + } else { + // use standard precision + lhs_val <<= rhs_val; + } + break; + } + case MP_BINARY_OP_RSHIFT: + case MP_BINARY_OP_INPLACE_RSHIFT: + if (rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError("negative shift count"); + } else { + // standard precision is enough for right-shift + if (rhs_val >= (mp_int_t)BITS_PER_WORD) { + // Shifting to big amounts is underfined behavior + // in C and is CPU-dependent; propagate sign bit. + rhs_val = BITS_PER_WORD - 1; + } + lhs_val >>= rhs_val; + } + break; + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break; + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break; + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: { + + // If long long type exists and is larger than mp_int_t, then + // we can use the following code to perform overflow-checked multiplication. + // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow. + #if 0 + // compute result using long long precision + long long res = (long long)lhs_val * (long long)rhs_val; + if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) { + // result overflowed SMALL_INT, so return higher precision integer + return mp_obj_new_int_from_ll(res); + } else { + // use standard precision + lhs_val = (mp_int_t)res; + } + #endif + + if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { + // use higher precision + lhs = mp_obj_new_int_from_ll(lhs_val); + goto generic_binary_op; + } else { + // use standard precision + return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); + } + } + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } + lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val); + break; + + #if MICROPY_PY_BUILTINS_FLOAT + case MP_BINARY_OP_TRUE_DIVIDE: + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); + #endif + + case MP_BINARY_OP_MODULO: + case MP_BINARY_OP_INPLACE_MODULO: { + if (rhs_val == 0) { + goto zero_division; + } + lhs_val = mp_small_int_modulo(lhs_val, rhs_val); + break; + } + + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: + if (rhs_val < 0) { + #if MICROPY_PY_BUILTINS_FLOAT + lhs = mp_obj_new_float(lhs_val); + goto generic_binary_op; + #else + mp_raise_ValueError("negative power with no float support"); + #endif + } else { + mp_int_t ans = 1; + while (rhs_val > 0) { + if (rhs_val & 1) { + if (mp_small_int_mul_overflow(ans, lhs_val)) { + goto power_overflow; + } + ans *= lhs_val; + } + if (rhs_val == 1) { + break; + } + rhs_val /= 2; + if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { + goto power_overflow; + } + lhs_val *= lhs_val; + } + lhs_val = ans; + } + break; + + power_overflow: + // use higher precision + lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); + goto generic_binary_op; + + case MP_BINARY_OP_DIVMOD: { + if (rhs_val == 0) { + goto zero_division; + } + // to reduce stack usage we don't pass a temp array of the 2 items + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(lhs_val, rhs_val)); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(lhs_val, rhs_val)); + return MP_OBJ_FROM_PTR(tuple); + } + + case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); + + default: + goto unsupported_op; + } + // This is an inlined version of mp_obj_new_int, for speed + if (MP_SMALL_INT_FITS(lhs_val)) { + return MP_OBJ_NEW_SMALL_INT(lhs_val); + } else { + return mp_obj_new_int_from_ll(lhs_val); + } +#if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(rhs)) { + mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs); + if (res == MP_OBJ_NULL) { + goto unsupported_op; + } else { + return res; + } +#if MICROPY_PY_BUILTINS_COMPLEX + } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { + mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); + if (res == MP_OBJ_NULL) { + goto unsupported_op; + } else { + return res; + } +#endif +#endif + } + } + + // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args. + if (op == MP_BINARY_OP_IN) { + op = MP_BINARY_OP_CONTAINS; + mp_obj_t temp = lhs; + lhs = rhs; + rhs = temp; + } + + // generic binary_op supplied by type + mp_obj_type_t *type; +generic_binary_op: + type = mp_obj_get_type(lhs); + if (type->binary_op != NULL) { + mp_obj_t result = type->binary_op(op, lhs, rhs); + if (result != MP_OBJ_NULL) { + return result; + } + } + +#if MICROPY_PY_REVERSE_SPECIAL_METHODS + if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_REVERSE_POWER) { + mp_obj_t t = rhs; + rhs = lhs; + lhs = t; + if (op <= MP_BINARY_OP_POWER) { + op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + goto generic_binary_op; + } + + // Convert __rop__ back to __op__ for error message + op -= MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + } +#endif + + if (op == MP_BINARY_OP_CONTAINS) { + // If type didn't support containment then explicitly walk the iterator. + // mp_getiter will raise the appropriate exception if lhs is not iterable. + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(lhs, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_equal(next, rhs)) { + return mp_const_true; + } + } + return mp_const_false; + } + +unsupported_op: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("unsupported type for operator"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "unsupported types for %q: '%s', '%s'", + mp_binary_op_method_name[op], mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs))); + } + +zero_division: + mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero"); +} + +mp_obj_t mp_call_function_0(mp_obj_t fun) { + return mp_call_function_n_kw(fun, 0, 0, NULL); +} + +mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg) { + return mp_call_function_n_kw(fun, 1, 0, &arg); +} + +mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { + mp_obj_t args[2]; + args[0] = arg1; + args[1] = arg2; + return mp_call_function_n_kw(fun, 2, 0, args); +} + +// args contains, eg: arg0 arg1 key0 value0 key1 value1 +mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // TODO improve this: fun object can specify its type and we parse here the arguments, + // passing to the function arrays of fixed and keyword arguments + + DEBUG_OP_printf("calling function %p(n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", fun_in, n_args, n_kw, args); + + // get the type + mp_obj_type_t *type = mp_obj_get_type(fun_in); + + // do the call + if (type->call != NULL) { + return type->call(fun_in, n_args, n_kw, args); + } + + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object not callable"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't callable", mp_obj_get_type_str(fun_in))); + } +} + +// args contains: fun self/NULL arg(0) ... arg(n_args-2) arg(n_args-1) kw_key(0) kw_val(0) ... kw_key(n_kw-1) kw_val(n_kw-1) +// if n_args==0 and n_kw==0 then there are only fun and self/NULL +mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) { + DEBUG_OP_printf("call method (fun=%p, self=%p, n_args=" UINT_FMT ", n_kw=" UINT_FMT ", args=%p)\n", args[0], args[1], n_args, n_kw, args); + int adjust = (args[1] == MP_OBJ_NULL) ? 0 : 1; + return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust); +} + +// This function only needs to be exposed externally when in stackless mode. +#if !MICROPY_STACKLESS +STATIC +#endif +void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) { + mp_obj_t fun = *args++; + mp_obj_t self = MP_OBJ_NULL; + if (have_self) { + self = *args++; // may be MP_OBJ_NULL + } + uint n_args = n_args_n_kw & 0xff; + uint n_kw = (n_args_n_kw >> 8) & 0xff; + mp_obj_t pos_seq = args[n_args + 2 * n_kw]; // may be MP_OBJ_NULL + mp_obj_t kw_dict = args[n_args + 2 * n_kw + 1]; // may be MP_OBJ_NULL + + DEBUG_OP_printf("call method var (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p, seq=%p, dict=%p)\n", fun, self, n_args, n_kw, args, pos_seq, kw_dict); + + // We need to create the following array of objects: + // args[0 .. n_args] unpacked(pos_seq) args[n_args .. n_args + 2 * n_kw] unpacked(kw_dict) + // TODO: optimize one day to avoid constructing new arg array? Will be hard. + + // The new args array + mp_obj_t *args2; + uint args2_alloc; + uint args2_len = 0; + + // Try to get a hint for the size of the kw_dict + uint kw_dict_len = 0; + if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + kw_dict_len = mp_obj_dict_len(kw_dict); + } + + // Extract the pos_seq sequence to the new args array. + // Note that it can be arbitrary iterator. + if (pos_seq == MP_OBJ_NULL) { + // no sequence + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed pos args + mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); + args2_len += n_args; + + } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) { + // optimise the case of a tuple and list + + // get the items + size_t len; + mp_obj_t *items; + mp_obj_get_array(pos_seq, &len, &items); + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed and variable position args + mp_seq_cat(args2 + args2_len, args, n_args, items, len, mp_obj_t); + args2_len += n_args + len; + + } else { + // generic iterator + + // allocate memory for the new array of args + args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); + + // copy the self + if (self != MP_OBJ_NULL) { + args2[args2_len++] = self; + } + + // copy the fixed position args + mp_seq_copy(args2 + args2_len, args, n_args, mp_obj_t); + args2_len += n_args; + + // extract the variable position args from the iterator + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(pos_seq, &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (args2_len >= args2_alloc) { + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t)); + args2_alloc *= 2; + } + args2[args2_len++] = item; + } + } + + // The size of the args2 array now is the number of positional args. + uint pos_args_len = args2_len; + + // Copy the fixed kw args. + mp_seq_copy(args2 + args2_len, args + n_args, 2 * n_kw, mp_obj_t); + args2_len += 2 * n_kw; + + // Extract (key,value) pairs from kw_dict dictionary and append to args2. + // Note that it can be arbitrary iterator. + if (kw_dict == MP_OBJ_NULL) { + // pass + } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) { + // dictionary + mp_map_t *map = mp_obj_dict_get_map(kw_dict); + assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above + for (size_t i = 0; i < map->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + // the key must be a qstr, so intern it if it's a string + mp_obj_t key = map->table[i].key; + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); + } + args2[args2_len++] = key; + args2[args2_len++] = map->table[i].value; + } + } + } else { + // generic mapping: + // - call keys() to get an iterable of all keys in the mapping + // - call __getitem__ for each key to get the corresponding value + + // get the keys iterable + mp_obj_t dest[3]; + mp_load_method(kw_dict, MP_QSTR_keys, dest); + mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest), NULL); + + mp_obj_t key; + while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // expand size of args array if needed + if (args2_len + 1 >= args2_alloc) { + uint new_alloc = args2_alloc * 2; + if (new_alloc < 4) { + new_alloc = 4; + } + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t)); + args2_alloc = new_alloc; + } + + // the key must be a qstr, so intern it if it's a string + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); + } + + // get the value corresponding to the key + mp_load_method(kw_dict, MP_QSTR___getitem__, dest); + dest[2] = key; + mp_obj_t value = mp_call_method_n_kw(1, 0, dest); + + // store the key/value pair in the argument array + args2[args2_len++] = key; + args2[args2_len++] = value; + } + } + + out_args->fun = fun; + out_args->args = args2; + out_args->n_args = pos_args_len; + out_args->n_kw = (args2_len - pos_args_len) / 2; + out_args->n_alloc = args2_alloc; +} + +mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args) { + mp_call_args_t out_args; + mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); + + mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + + return res; +} + +// unpacked items are stored in reverse order into the array pointed to by items +void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { + size_t seq_len; + if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + mp_obj_t *seq_items; + mp_obj_get_array(seq_in, &seq_len, &seq_items); + if (seq_len < num) { + goto too_short; + } else if (seq_len > num) { + goto too_long; + } + for (size_t i = 0; i < num; i++) { + items[i] = seq_items[num - 1 - i]; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(seq_in, &iter_buf); + + for (seq_len = 0; seq_len < num; seq_len++) { + mp_obj_t el = mp_iternext(iterable); + if (el == MP_OBJ_STOP_ITERATION) { + goto too_short; + } + items[num - 1 - seq_len] = el; + } + if (mp_iternext(iterable) != MP_OBJ_STOP_ITERATION) { + goto too_long; + } + } + return; + +too_short: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_ValueError("wrong number of values to unpack"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "need more than %d values to unpack", (int)seq_len)); + } +too_long: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_ValueError("wrong number of values to unpack"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "too many values to unpack (expected %d)", (int)num)); + } +} + +// unpacked items are stored in reverse order into the array pointed to by items +void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { + size_t num_left = num_in & 0xff; + size_t num_right = (num_in >> 8) & 0xff; + DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); + size_t seq_len; + if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + mp_obj_t *seq_items; + mp_obj_get_array(seq_in, &seq_len, &seq_items); + if (seq_len < num_left + num_right) { + goto too_short; + } + for (size_t i = 0; i < num_right; i++) { + items[i] = seq_items[seq_len - 1 - i]; + } + items[num_right] = mp_obj_new_list(seq_len - num_left - num_right, seq_items + num_left); + for (size_t i = 0; i < num_left; i++) { + items[num_right + 1 + i] = seq_items[num_left - 1 - i]; + } + } else { + // Generic iterable; this gets a bit messy: we unpack known left length to the + // items destination array, then the rest to a dynamically created list. Once the + // iterable is exhausted, we take from this list for the right part of the items. + // TODO Improve to waste less memory in the dynamically created list. + mp_obj_t iterable = mp_getiter(seq_in, NULL); + mp_obj_t item; + for (seq_len = 0; seq_len < num_left; seq_len++) { + item = mp_iternext(iterable); + if (item == MP_OBJ_STOP_ITERATION) { + goto too_short; + } + items[num_left + num_right + 1 - 1 - seq_len] = item; + } + mp_obj_list_t *rest = MP_OBJ_TO_PTR(mp_obj_new_list(0, NULL)); + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_obj_list_append(MP_OBJ_FROM_PTR(rest), item); + } + if (rest->len < num_right) { + goto too_short; + } + items[num_right] = MP_OBJ_FROM_PTR(rest); + for (size_t i = 0; i < num_right; i++) { + items[num_right - 1 - i] = rest->items[rest->len - num_right + i]; + } + mp_obj_list_set_len(MP_OBJ_FROM_PTR(rest), rest->len - num_right); + } + return; + +too_short: + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_ValueError("wrong number of values to unpack"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "need more than %d values to unpack", (int)seq_len)); + } +} + +mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { + DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr)); + // use load_method + mp_obj_t dest[2]; + mp_load_method(base, attr, dest); + if (dest[1] == MP_OBJ_NULL) { + // load_method returned just a normal attribute + return dest[0]; + } else { + // load_method returned a method, so build a bound method object + return mp_obj_new_bound_meth(dest[0], dest[1]); + } +} + +#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG + +// The following "checked fun" type is local to the mp_convert_member_lookup +// function, and serves to check that the first argument to a builtin function +// has the correct type. + +typedef struct _mp_obj_checked_fun_t { + mp_obj_base_t base; + const mp_obj_type_t *type; + mp_obj_t fun; +} mp_obj_checked_fun_t; + +STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_obj_checked_fun_t *self = MP_OBJ_TO_PTR(self_in); + if (n_args > 0) { + const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); + if (arg0_type != self->type) { + if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { + mp_raise_TypeError("argument has wrong type"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); + } + } + } + return mp_call_function_n_kw(self->fun, n_args, n_kw, args); +} + +STATIC const mp_obj_type_t mp_type_checked_fun = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = checked_fun_call, +}; + +STATIC mp_obj_t mp_obj_new_checked_fun(const mp_obj_type_t *type, mp_obj_t fun) { + mp_obj_checked_fun_t *o = m_new_obj(mp_obj_checked_fun_t); + o->base.type = &mp_type_checked_fun; + o->type = type; + o->fun = fun; + return MP_OBJ_FROM_PTR(o); +} + +#endif // MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG + +// Given a member that was extracted from an instance, convert it correctly +// and put the result in the dest[] array for a possible method call. +// Conversion means dealing with static/class methods, callables, and values. +// see http://docs.python.org/3/howto/descriptor.html +void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) { + if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { + // return just the function + dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; + } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { + // return a bound method, with self being the type of this object + // this type should be the type of the original instance, not the base + // type (which is what is passed in the 'type' argument to this function) + if (self != MP_OBJ_NULL) { + type = mp_obj_get_type(self); + } + dest[0] = ((mp_obj_static_class_method_t*)MP_OBJ_TO_PTR(member))->fun; + dest[1] = MP_OBJ_FROM_PTR(type); + } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) { + // Don't try to bind types (even though they're callable) + dest[0] = member; + } else if (MP_OBJ_IS_FUN(member) + || (MP_OBJ_IS_OBJ(member) + && (((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_closure + || ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { + // only functions, closures and generators objects can be bound to self + #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG + const mp_obj_type_t *m_type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type; + if (self == MP_OBJ_NULL + && (m_type == &mp_type_fun_builtin_0 + || m_type == &mp_type_fun_builtin_1 + || m_type == &mp_type_fun_builtin_2 + || m_type == &mp_type_fun_builtin_3 + || m_type == &mp_type_fun_builtin_var)) { + // we extracted a builtin method without a first argument, so we must + // wrap this function in a type checker + dest[0] = mp_obj_new_checked_fun(type, member); + } else + #endif + { + // return a bound method, with self being this object + dest[0] = member; + dest[1] = self; + } + } else { + // class member is a value, so just return that value + dest[0] = member; + } +} + +// no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL +// normal attribute found, returns: dest[0] == , dest[1] == MP_OBJ_NULL +// method attribute found, returns: dest[0] == , dest[1] == +void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { + // clear output to indicate no attribute/method found yet + dest[0] = MP_OBJ_NULL; + dest[1] = MP_OBJ_NULL; + + // get the type + mp_obj_type_t *type = mp_obj_get_type(obj); + + // look for built-in names + if (0) { +#if MICROPY_CPYTHON_COMPAT + } else if (attr == MP_QSTR___class__) { + // a.__class__ is equivalent to type(a) + dest[0] = MP_OBJ_FROM_PTR(type); +#endif + + } else if (attr == MP_QSTR___next__ && type->iternext != NULL) { + dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); + dest[1] = obj; + + } else if (type->attr != NULL) { + // this type can do its own load, so call it + type->attr(obj, attr, dest); + + } else if (type->locals_dict != NULL) { + // generic method lookup + // this is a lookup in the object (ie not class or type) + assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now + mp_map_t *locals_map = &type->locals_dict->map; + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem != NULL) { + mp_convert_member_lookup(obj, type, elem->value, dest); + } + } +} + +void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { + DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr)); + + mp_load_method_maybe(base, attr, dest); + + if (dest[0] == MP_OBJ_NULL) { + // no attribute/method called attr + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); + } else { + // following CPython, we give a more detailed error message for type objects + if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + "type object '%q' has no attribute '%q'", + ((mp_obj_type_t*)MP_OBJ_TO_PTR(base))->name, attr)); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + "'%s' object has no attribute '%q'", + mp_obj_get_type_str(base), attr)); + } + } + } +} + +// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_load_method_maybe(obj, attr, dest); + nlr_pop(); + } else { + if (!catch_all_exc + && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + MP_OBJ_FROM_PTR(&mp_type_AttributeError))) { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } +} + +void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { + DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); + mp_obj_type_t *type = mp_obj_get_type(base); + if (type->attr != NULL) { + mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; + type->attr(base, attr, dest); + if (dest[0] == MP_OBJ_NULL) { + // success + return; + } + } + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + "'%s' object has no attribute '%q'", + mp_obj_get_type_str(base), attr)); + } +} + +mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + assert(o_in); + mp_obj_type_t *type = mp_obj_get_type(o_in); + + // Check for native getiter which is the identity. We handle this case explicitly + // so we don't unnecessarily allocate any RAM for the iter_buf, which won't be used. + if (type->getiter == mp_identity_getiter) { + return o_in; + } + + // if caller did not provide a buffer then allocate one on the heap + if (iter_buf == NULL) { + iter_buf = m_new_obj(mp_obj_iter_buf_t); + } + + // check for native getiter (corresponds to __iter__) + if (type->getiter != NULL) { + mp_obj_t iter = type->getiter(o_in, iter_buf); + if (iter != MP_OBJ_NULL) { + return iter; + } + } + + // check for __getitem__ + mp_obj_t dest[2]; + mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __getitem__ exists, create and return an iterator + return mp_obj_new_getitem_iter(dest, iter_buf); + } + + // object not iterable + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object not iterable"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't iterable", mp_obj_get_type_str(o_in))); + } +} + +// may return MP_OBJ_STOP_ITERATION as an optimisation instead of raise StopIteration() +// may also raise StopIteration() +mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { + mp_obj_type_t *type = mp_obj_get_type(o_in); + if (type->iternext != NULL) { + return type->iternext(o_in); + } else { + // check for __next__ method + mp_obj_t dest[2]; + mp_load_method_maybe(o_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __next__ exists, call it and return its result + return mp_call_method_n_kw(0, 0, dest); + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object not an iterator"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't an iterator", mp_obj_get_type_str(o_in))); + } + } + } +} + +// will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration() (or any subclass thereof) +// may raise other exceptions +mp_obj_t mp_iternext(mp_obj_t o_in) { + MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext + mp_obj_type_t *type = mp_obj_get_type(o_in); + if (type->iternext != NULL) { + return type->iternext(o_in); + } else { + // check for __next__ method + mp_obj_t dest[2]; + mp_load_method_maybe(o_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + // __next__ exists, call it and return its result + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_call_method_n_kw(0, 0, dest); + nlr_pop(); + return ret; + } else { + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + return MP_OBJ_STOP_ITERATION; + } else { + nlr_jump(nlr.ret_val); + } + } + } else { + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("object not an iterator"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "'%s' object isn't an iterator", mp_obj_get_type_str(o_in))); + } + } + } +} + +// TODO: Unclear what to do with StopIterarion exception here. +mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { + assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL)); + mp_obj_type_t *type = mp_obj_get_type(self_in); + + if (type == &mp_type_gen_instance) { + return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val); + } + + if (type->iternext != NULL && send_value == mp_const_none) { + mp_obj_t ret = type->iternext(self_in); + *ret_val = ret; + if (ret != MP_OBJ_STOP_ITERATION) { + return MP_VM_RETURN_YIELD; + } else { + // Emulate raise StopIteration() + // Special case, handled in vm.c + return MP_VM_RETURN_NORMAL; + } + } + + mp_obj_t dest[3]; // Reserve slot for send() arg + + // Python instance iterator protocol + if (send_value == mp_const_none) { + mp_load_method_maybe(self_in, MP_QSTR___next__, dest); + if (dest[0] != MP_OBJ_NULL) { + *ret_val = mp_call_method_n_kw(0, 0, dest); + return MP_VM_RETURN_YIELD; + } + } + + // Either python instance generator protocol, or native object + // generator protocol. + if (send_value != MP_OBJ_NULL) { + mp_load_method(self_in, MP_QSTR_send, dest); + dest[2] = send_value; + *ret_val = mp_call_method_n_kw(1, 0, dest); + return MP_VM_RETURN_YIELD; + } + + assert(throw_value != MP_OBJ_NULL); + { + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(throw_value)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { + mp_load_method_maybe(self_in, MP_QSTR_close, dest); + if (dest[0] != MP_OBJ_NULL) { + // TODO: Exceptions raised in close() are not propagated, + // printed to sys.stderr + *ret_val = mp_call_method_n_kw(0, 0, dest); + // We assume one can't "yield" from close() + return MP_VM_RETURN_NORMAL; + } + } else { + mp_load_method_maybe(self_in, MP_QSTR_throw, dest); + if (dest[0] != MP_OBJ_NULL) { + dest[2] = throw_value; + *ret_val = mp_call_method_n_kw(1, 0, dest); + // If .throw() method returned, we assume it's value to yield + // - any exception would be thrown with nlr_raise(). + return MP_VM_RETURN_YIELD; + } + } + // If there's nowhere to throw exception into, then we assume that object + // is just incapable to handle it, so any exception thrown into it + // will be propagated up. This behavior is approved by test_pep380.py + // test_delegation_of_close_to_non_generator(), + // test_delegating_throw_to_non_generator() + *ret_val = mp_make_raise_obj(throw_value); + return MP_VM_RETURN_EXCEPTION; + } +} + +mp_obj_t mp_make_raise_obj(mp_obj_t o) { + DEBUG_printf("raise %p\n", o); + if (mp_obj_is_exception_type(o)) { + // o is an exception type (it is derived from BaseException (or is BaseException)) + // create and return a new exception instance by calling o + // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError) + // could have const instances in ROM which we return here instead + return mp_call_function_n_kw(o, 0, 0, NULL); + } else if (mp_obj_is_exception_instance(o)) { + // o is an instance of an exception, so use it as the exception + return o; + } else { + // o cannot be used as an exception, so return a type error (which will be raised by the caller) + return mp_obj_new_exception_msg(&mp_type_TypeError, "exceptions must derive from BaseException"); + } +} + +mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { + DEBUG_printf("import name '%s' level=%d\n", qstr_str(name), MP_OBJ_SMALL_INT_VALUE(level)); + + // build args array + mp_obj_t args[5]; + args[0] = MP_OBJ_NEW_QSTR(name); + args[1] = mp_const_none; // TODO should be globals + args[2] = mp_const_none; // TODO should be locals + args[3] = fromlist; + args[4] = level; + + // TODO lookup __import__ and call that instead of going straight to builtin implementation + return mp_builtin___import__(5, args); +} + +mp_obj_t mp_import_from(mp_obj_t module, qstr name) { + DEBUG_printf("import from %p %s\n", module, qstr_str(name)); + + mp_obj_t dest[2]; + + mp_load_method_maybe(module, name, dest); + + if (dest[1] != MP_OBJ_NULL) { + // Hopefully we can't import bound method from an object +import_error: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "cannot import name %q", name)); + } + + if (dest[0] != MP_OBJ_NULL) { + return dest[0]; + } + + #if MICROPY_ENABLE_EXTERNAL_IMPORT + + // See if it's a package, then can try FS import + if (!mp_obj_is_package(module)) { + goto import_error; + } + + mp_load_method_maybe(module, MP_QSTR___name__, dest); + size_t pkg_name_len; + const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); + + const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); + char *dot_name = mp_local_alloc(dot_name_len); + memcpy(dot_name, pkg_name, pkg_name_len); + dot_name[pkg_name_len] = '.'; + memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name)); + qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len); + mp_local_free(dot_name); + + // For fromlist, pass sentinel "non empty" value to force returning of leaf module + return mp_import_name(dot_name_q, mp_const_true, MP_OBJ_NEW_SMALL_INT(0)); + + #else + + // Package import not supported with external imports disabled + goto import_error; + + #endif +} + +void mp_import_all(mp_obj_t module) { + DEBUG_printf("import all %p\n", module); + + // TODO: Support __all__ + mp_map_t *map = &mp_obj_module_get_globals(module)->map; + for (size_t i = 0; i < map->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + qstr name = MP_OBJ_QSTR_VALUE(map->table[i].key); + if (*qstr_str(name) != '_') { + mp_store_name(name, map->table[i].value); + } + } + } +} + +#if MICROPY_ENABLE_COMPILER + +// this is implemented in this file so it can optimise access to locals/globals +mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { + // save context + mp_obj_dict_t *volatile old_globals = mp_globals_get(); + mp_obj_dict_t *volatile old_locals = mp_locals_get(); + + // set new context + mp_globals_set(globals); + mp_locals_set(locals); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + + mp_obj_t ret; + if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) { + // for compile only, return value is the module function + ret = module_fun; + } else { + // execute module function and get return value + ret = mp_call_function_0(module_fun); + } + + // finish nlr block, restore context and return value + nlr_pop(); + mp_globals_set(old_globals); + mp_locals_set(old_locals); + return ret; + } else { + // exception; restore context and re-raise same exception + mp_globals_set(old_globals); + mp_locals_set(old_locals); + nlr_jump(nlr.ret_val); + } +} + +#endif // MICROPY_ENABLE_COMPILER + +NORETURN void m_malloc_fail(size_t num_bytes) { + DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes); + #if MICROPY_ENABLE_GC + if (gc_is_locked()) { + mp_raise_msg(&mp_type_MemoryError, "memory allocation failed, heap is locked"); + } + #endif + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, + "memory allocation failed, allocating %u bytes", (uint)num_bytes)); +} + +NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg) { + if (msg == NULL) { + nlr_raise(mp_obj_new_exception(exc_type)); + } else { + nlr_raise(mp_obj_new_exception_msg(exc_type, msg)); + } +} + +NORETURN void mp_raise_ValueError(const char *msg) { + mp_raise_msg(&mp_type_ValueError, msg); +} + +NORETURN void mp_raise_TypeError(const char *msg) { + mp_raise_msg(&mp_type_TypeError, msg); +} + +NORETURN void mp_raise_OSError(int errno_) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_))); +} + +NORETURN void mp_raise_NotImplementedError(const char *msg) { + mp_raise_msg(&mp_type_NotImplementedError, msg); +} + +#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK +NORETURN void mp_raise_recursion_depth(void) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); +} +#endif diff --git a/src/openmv/src/micropython/py/runtime.h b/src/openmv/src/micropython/py/runtime.h new file mode 100755 index 0000000..57df959 --- /dev/null +++ b/src/openmv/src/micropython/py/runtime.h @@ -0,0 +1,187 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_RUNTIME_H +#define MICROPY_INCLUDED_PY_RUNTIME_H + +#include "py/mpstate.h" +#include "py/pystack.h" + +typedef enum { + MP_VM_RETURN_NORMAL, + MP_VM_RETURN_YIELD, + MP_VM_RETURN_EXCEPTION, +} mp_vm_return_kind_t; + +typedef enum { + MP_ARG_BOOL = 0x001, + MP_ARG_INT = 0x002, + MP_ARG_OBJ = 0x003, + MP_ARG_KIND_MASK = 0x0ff, + MP_ARG_REQUIRED = 0x100, + MP_ARG_KW_ONLY = 0x200, +} mp_arg_flag_t; + +typedef union _mp_arg_val_t { + bool u_bool; + mp_int_t u_int; + mp_obj_t u_obj; + mp_rom_obj_t u_rom_obj; +} mp_arg_val_t; + +typedef struct _mp_arg_t { + uint16_t qst; + uint16_t flags; + mp_arg_val_t defval; +} mp_arg_t; + +// Tables mapping operator enums to qstrs, defined in objtype.c +extern const byte mp_unary_op_method_name[]; +extern const byte mp_binary_op_method_name[]; + +void mp_init(void); +void mp_deinit(void); + +void mp_handle_pending(void); +void mp_handle_pending_tail(mp_uint_t atomic_state); + +#if MICROPY_ENABLE_SCHEDULER +void mp_sched_lock(void); +void mp_sched_unlock(void); +static inline unsigned int mp_sched_num_pending(void) { return MP_STATE_VM(sched_sp); } +bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); +#endif + +// extra printing method specifically for mp_obj_t's which are integral type +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); + +void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig); +static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { + mp_arg_check_num_sig(n_args, n_kw, (uint32_t)MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw)); +} +void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); +void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); +NORETURN void mp_arg_error_terse_mismatch(void); +NORETURN void mp_arg_error_unimpl_kw(void); + +static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); } +static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; } +static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_THREAD(dict_globals); } +static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; } + +mp_obj_t mp_load_name(qstr qst); +mp_obj_t mp_load_global(qstr qst); +mp_obj_t mp_load_build_class(void); +void mp_store_name(qstr qst, mp_obj_t obj); +void mp_store_global(qstr qst, mp_obj_t obj); +void mp_delete_name(qstr qst); +void mp_delete_global(qstr qst); + +mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg); +mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs); + +mp_obj_t mp_call_function_0(mp_obj_t fun); +mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg); +mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); +mp_obj_t mp_call_function_n_kw(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); +mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args); +// Call function and catch/dump exception - for Python callbacks from C code +// (return MP_OBJ_NULL in case of exception). +mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); + +typedef struct _mp_call_args_t { + mp_obj_t fun; + size_t n_args, n_kw, n_alloc; + mp_obj_t *args; +} mp_call_args_t; + +#if MICROPY_STACKLESS +// Takes arguments which are the most general mix of Python arg types, and +// prepares argument array suitable for passing to ->call() method of a +// function object (and mp_call_function_n_kw()). +// (Only needed in stackless mode.) +void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args); +#endif + +void mp_unpack_sequence(mp_obj_t seq, size_t num, mp_obj_t *items); +void mp_unpack_ex(mp_obj_t seq, size_t num, mp_obj_t *items); +mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value); +mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); +void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); +void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); +void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc); +void mp_load_super_method(qstr attr, mp_obj_t *dest); +void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); + +mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf); +mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATION instead of raising StopIteration() +mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...) +mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val); + +mp_obj_t mp_make_raise_obj(mp_obj_t o); + +mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level); +mp_obj_t mp_import_from(mp_obj_t module, qstr name); +void mp_import_all(mp_obj_t module); + +NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); +//NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); +NORETURN void mp_raise_ValueError(const char *msg); +NORETURN void mp_raise_TypeError(const char *msg); +NORETURN void mp_raise_NotImplementedError(const char *msg); +NORETURN void mp_raise_OSError(int errno_); +NORETURN void mp_raise_recursion_depth(void); + +#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG +#undef mp_check_self +#define mp_check_self(pred) +#else +// A port may define to raise TypeError for example +#ifndef mp_check_self +#define mp_check_self(pred) assert(pred) +#endif +#endif + +// helper functions for native/viper code +mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); +mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type); +mp_obj_dict_t *mp_native_swap_globals(mp_obj_dict_t *new_globals); +mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, size_t n_args_kw, const mp_obj_t *args); +void mp_native_raise(mp_obj_t o); + +#define mp_sys_path (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_path_obj))) +#define mp_sys_argv (MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_sys_argv_obj))) + +#if MICROPY_WARNINGS +void mp_warning(const char *msg, ...); +#else +#define mp_warning(...) +#endif + +#endif // MICROPY_INCLUDED_PY_RUNTIME_H diff --git a/src/openmv/src/micropython/py/runtime0.h b/src/openmv/src/micropython/py/runtime0.h new file mode 100755 index 0000000..56cc6cf --- /dev/null +++ b/src/openmv/src/micropython/py/runtime0.h @@ -0,0 +1,209 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_RUNTIME0_H +#define MICROPY_INCLUDED_PY_RUNTIME0_H + +// The first four must fit in 8 bits, see emitbc.c +// The remaining must fit in 16 bits, see scope.h +#define MP_SCOPE_FLAG_VARARGS (0x01) +#define MP_SCOPE_FLAG_VARKEYWORDS (0x02) +#define MP_SCOPE_FLAG_GENERATOR (0x04) +#define MP_SCOPE_FLAG_DEFKWARGS (0x08) +#define MP_SCOPE_FLAG_REFGLOBALS (0x10) // used only if native emitter enabled +#define MP_SCOPE_FLAG_HASCONSTS (0x20) // used only if native emitter enabled +#define MP_SCOPE_FLAG_VIPERRET_POS (6) // 3 bits used for viper return type + +// types for native (viper) function signature +#define MP_NATIVE_TYPE_OBJ (0x00) +#define MP_NATIVE_TYPE_BOOL (0x01) +#define MP_NATIVE_TYPE_INT (0x02) +#define MP_NATIVE_TYPE_UINT (0x03) +#define MP_NATIVE_TYPE_PTR (0x04) +#define MP_NATIVE_TYPE_PTR8 (0x05) +#define MP_NATIVE_TYPE_PTR16 (0x06) +#define MP_NATIVE_TYPE_PTR32 (0x07) + +typedef enum { + // These ops may appear in the bytecode. Changing this group + // in any way requires changing the bytecode version. + MP_UNARY_OP_POSITIVE, + MP_UNARY_OP_NEGATIVE, + MP_UNARY_OP_INVERT, + MP_UNARY_OP_NOT, + + // Following ops cannot appear in the bytecode + MP_UNARY_OP_NUM_BYTECODE, + + MP_UNARY_OP_BOOL = MP_UNARY_OP_NUM_BYTECODE, // __bool__ + MP_UNARY_OP_LEN, // __len__ + MP_UNARY_OP_HASH, // __hash__; must return a small int + MP_UNARY_OP_ABS, // __abs__ + MP_UNARY_OP_SIZEOF, // for sys.getsizeof() + + MP_UNARY_OP_NUM_RUNTIME, +} mp_unary_op_t; + +// Note: the first 9+12+12 of these are used in bytecode and changing +// them requires changing the bytecode version. +typedef enum { + // 9 relational operations, should return a bool + MP_BINARY_OP_LESS, + MP_BINARY_OP_MORE, + MP_BINARY_OP_EQUAL, + MP_BINARY_OP_LESS_EQUAL, + MP_BINARY_OP_MORE_EQUAL, + MP_BINARY_OP_NOT_EQUAL, + MP_BINARY_OP_IN, + MP_BINARY_OP_IS, + MP_BINARY_OP_EXCEPTION_MATCH, + + // 12 inplace arithmetic operations + MP_BINARY_OP_INPLACE_OR, + MP_BINARY_OP_INPLACE_XOR, + MP_BINARY_OP_INPLACE_AND, + MP_BINARY_OP_INPLACE_LSHIFT, + MP_BINARY_OP_INPLACE_RSHIFT, + MP_BINARY_OP_INPLACE_ADD, + MP_BINARY_OP_INPLACE_SUBTRACT, + MP_BINARY_OP_INPLACE_MULTIPLY, + MP_BINARY_OP_INPLACE_FLOOR_DIVIDE, + MP_BINARY_OP_INPLACE_TRUE_DIVIDE, + MP_BINARY_OP_INPLACE_MODULO, + MP_BINARY_OP_INPLACE_POWER, + + // 12 normal arithmetic operations + MP_BINARY_OP_OR, + MP_BINARY_OP_XOR, + MP_BINARY_OP_AND, + MP_BINARY_OP_LSHIFT, + MP_BINARY_OP_RSHIFT, + MP_BINARY_OP_ADD, + MP_BINARY_OP_SUBTRACT, + MP_BINARY_OP_MULTIPLY, + MP_BINARY_OP_FLOOR_DIVIDE, + MP_BINARY_OP_TRUE_DIVIDE, + MP_BINARY_OP_MODULO, + MP_BINARY_OP_POWER, + + // Operations below this line don't appear in bytecode, they + // just identify special methods. + MP_BINARY_OP_NUM_BYTECODE, + + // MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_* +#if MICROPY_PY_REVERSE_SPECIAL_METHODS + MP_BINARY_OP_REVERSE_OR = MP_BINARY_OP_NUM_BYTECODE, + MP_BINARY_OP_REVERSE_XOR, + MP_BINARY_OP_REVERSE_AND, + MP_BINARY_OP_REVERSE_LSHIFT, + MP_BINARY_OP_REVERSE_RSHIFT, + MP_BINARY_OP_REVERSE_ADD, + MP_BINARY_OP_REVERSE_SUBTRACT, + MP_BINARY_OP_REVERSE_MULTIPLY, + MP_BINARY_OP_REVERSE_FLOOR_DIVIDE, + MP_BINARY_OP_REVERSE_TRUE_DIVIDE, + MP_BINARY_OP_REVERSE_MODULO, + MP_BINARY_OP_REVERSE_POWER, +#endif + + // This is not emitted by the compiler but is supported by the runtime + MP_BINARY_OP_DIVMOD + #if !MICROPY_PY_REVERSE_SPECIAL_METHODS + = MP_BINARY_OP_NUM_BYTECODE + #endif + , + + // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args. + // A type should implement this containment operator instead of MP_BINARY_OP_IN. + MP_BINARY_OP_CONTAINS, + + MP_BINARY_OP_NUM_RUNTIME, + + // These 2 are not supported by the runtime and must be synthesised by the emitter + MP_BINARY_OP_NOT_IN, + MP_BINARY_OP_IS_NOT, +} mp_binary_op_t; + +typedef enum { + MP_F_CONST_NONE_OBJ = 0, + MP_F_CONST_FALSE_OBJ, + MP_F_CONST_TRUE_OBJ, + MP_F_CONVERT_OBJ_TO_NATIVE, + MP_F_CONVERT_NATIVE_TO_OBJ, + MP_F_NATIVE_SWAP_GLOBALS, + MP_F_LOAD_NAME, + MP_F_LOAD_GLOBAL, + MP_F_LOAD_BUILD_CLASS, + MP_F_LOAD_ATTR, + MP_F_LOAD_METHOD, + MP_F_LOAD_SUPER_METHOD, + MP_F_STORE_NAME, + MP_F_STORE_GLOBAL, + MP_F_STORE_ATTR, + MP_F_OBJ_SUBSCR, + MP_F_OBJ_IS_TRUE, + MP_F_UNARY_OP, + MP_F_BINARY_OP, + MP_F_BUILD_TUPLE, + MP_F_BUILD_LIST, + MP_F_LIST_APPEND, + MP_F_BUILD_MAP, + MP_F_STORE_MAP, +#if MICROPY_PY_BUILTINS_SET + MP_F_STORE_SET, + MP_F_BUILD_SET, +#endif + MP_F_MAKE_FUNCTION_FROM_RAW_CODE, + MP_F_NATIVE_CALL_FUNCTION_N_KW, + MP_F_CALL_METHOD_N_KW, + MP_F_CALL_METHOD_N_KW_VAR, + MP_F_NATIVE_GETITER, + MP_F_NATIVE_ITERNEXT, + MP_F_NLR_PUSH, + MP_F_NLR_POP, + MP_F_NATIVE_RAISE, + MP_F_IMPORT_NAME, + MP_F_IMPORT_FROM, + MP_F_IMPORT_ALL, +#if MICROPY_PY_BUILTINS_SLICE + MP_F_NEW_SLICE, +#endif + MP_F_UNPACK_SEQUENCE, + MP_F_UNPACK_EX, + MP_F_DELETE_NAME, + MP_F_DELETE_GLOBAL, + MP_F_NEW_CELL, + MP_F_MAKE_CLOSURE_FROM_RAW_CODE, + MP_F_ARG_CHECK_NUM_SIG, + MP_F_SETUP_CODE_STATE, + MP_F_SMALL_INT_FLOOR_DIVIDE, + MP_F_SMALL_INT_MODULO, + MP_F_NATIVE_YIELD_FROM, + MP_F_NUMBER_OF, +} mp_fun_kind_t; + +extern const void *const mp_fun_table[MP_F_NUMBER_OF]; + +#endif // MICROPY_INCLUDED_PY_RUNTIME0_H diff --git a/src/openmv/src/micropython/py/runtime_utils.c b/src/openmv/src/micropython/py/runtime_utils.c new file mode 100755 index 0000000..b92c6bd --- /dev/null +++ b/src/openmv/src/micropython/py/runtime_utils.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_call_function_1(fun, arg); + nlr_pop(); + return ret; + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; + } +} + +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t ret = mp_call_function_2(fun, arg1, arg2); + nlr_pop(); + return ret; + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; + } +} diff --git a/src/openmv/src/micropython/py/scheduler.c b/src/openmv/src/micropython/py/scheduler.c new file mode 100755 index 0000000..30851a4 --- /dev/null +++ b/src/openmv/src/micropython/py/scheduler.c @@ -0,0 +1,117 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#if MICROPY_ENABLE_SCHEDULER + +// A variant of this is inlined in the VM at the pending exception check +void mp_handle_pending(void) { + if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + if (obj != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + if (!mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + nlr_raise(obj); + } + mp_handle_pending_tail(atomic_state); + } +} + +// This function should only be called be mp_sched_handle_pending, +// or by the VM's inlined version of that function. +void mp_handle_pending_tail(mp_uint_t atomic_state) { + MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; + if (MP_STATE_VM(sched_sp) > 0) { + mp_sched_item_t item = MP_STATE_VM(sched_stack)[--MP_STATE_VM(sched_sp)]; + MICROPY_END_ATOMIC_SECTION(atomic_state); + mp_call_function_1_protected(item.func, item.arg); + } else { + MICROPY_END_ATOMIC_SECTION(atomic_state); + } + mp_sched_unlock(); +} + +void mp_sched_lock(void) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + if (MP_STATE_VM(sched_state) < 0) { + --MP_STATE_VM(sched_state); + } else { + MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); +} + +void mp_sched_unlock(void) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + if (++MP_STATE_VM(sched_state) == 0) { + // vm became unlocked + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } else { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + } + MICROPY_END_ATOMIC_SECTION(atomic_state); +} + +bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + bool ret; + if (MP_STATE_VM(sched_sp) < MICROPY_SCHEDULER_DEPTH) { + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].func = function; + MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].arg = arg; + ++MP_STATE_VM(sched_sp); + ret = true; + } else { + // schedule stack is full + ret = false; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + return ret; +} + +#else // MICROPY_ENABLE_SCHEDULER + +// A variant of this is inlined in the VM at the pending exception check +void mp_handle_pending(void) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } +} + +#endif // MICROPY_ENABLE_SCHEDULER diff --git a/src/openmv/src/micropython/py/scope.c b/src/openmv/src/micropython/py/scope.c new file mode 100755 index 0000000..1a6ae7b --- /dev/null +++ b/src/openmv/src/micropython/py/scope.c @@ -0,0 +1,150 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/scope.h" + +#if MICROPY_ENABLE_COMPILER + +// these low numbered qstrs should fit in 8 bits +STATIC const uint8_t scope_simple_name_table[] = { + [SCOPE_MODULE] = MP_QSTR__lt_module_gt_, + [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_, + [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_, + [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_, + [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_, + [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_, +}; + +scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) { + scope_t *scope = m_new0(scope_t, 1); + scope->kind = kind; + scope->pn = pn; + scope->source_file = source_file; + if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) { + assert(MP_PARSE_NODE_IS_STRUCT(pn)); + scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn)->nodes[0]); + } else { + scope->simple_name = scope_simple_name_table[kind]; + } + scope->raw_code = mp_emit_glue_new_raw_code(); + scope->emit_options = emit_options; + scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT; + scope->id_info = m_new(id_info_t, scope->id_info_alloc); + + return scope; +} + +void scope_free(scope_t *scope) { + m_del(id_info_t, scope->id_info, scope->id_info_alloc); + m_del(scope_t, scope, 1); +} + +id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, bool *added) { + id_info_t *id_info = scope_find(scope, qst); + if (id_info != NULL) { + *added = false; + return id_info; + } + + // make sure we have enough memory + if (scope->id_info_len >= scope->id_info_alloc) { + scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC); + scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC; + } + + // add new id to end of array of all ids; this seems to match CPython + // important thing is that function arguments are first, but that is + // handled by the compiler because it adds arguments before compiling the body + id_info = &scope->id_info[scope->id_info_len++]; + + id_info->kind = 0; + id_info->flags = 0; + id_info->local_num = 0; + id_info->qst = qst; + *added = true; + return id_info; +} + +id_info_t *scope_find(scope_t *scope, qstr qst) { + for (mp_uint_t i = 0; i < scope->id_info_len; i++) { + if (scope->id_info[i].qst == qst) { + return &scope->id_info[i]; + } + } + return NULL; +} + +id_info_t *scope_find_global(scope_t *scope, qstr qst) { + while (scope->parent != NULL) { + scope = scope->parent; + } + return scope_find(scope, qst); +} + +STATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) { + assert(scope->parent != NULL); // we should have at least 1 parent + for (scope_t *s = scope->parent;; s = s->parent) { + assert(s->parent != NULL); // we should not get to the outer scope + bool added; + id_info_t *id = scope_find_or_add_id(s, qst, &added); + if (added) { + // variable not previously declared in this scope, so declare it as free and keep searching parents + id->kind = ID_INFO_KIND_FREE; + } else { + // variable is declared in this scope, so finish + if (id->kind == ID_INFO_KIND_LOCAL) { + // variable local to this scope, close it over + id->kind = ID_INFO_KIND_CELL; + } else { + // ID_INFO_KIND_FREE: variable already closed over in a parent scope + // ID_INFO_KIND_CELL: variable already closed over in this scope + assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL); + } + return; + } + } +} + +void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst) { + if (scope->parent != NULL) { + for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) { + id_info_t *id2 = scope_find(s, qst); + if (id2 != NULL) { + if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) { + id->kind = ID_INFO_KIND_FREE; + scope_close_over_in_parents(scope, qst); + return; + } + break; + } + } + } + id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT; +} + +#endif // MICROPY_ENABLE_COMPILER diff --git a/src/openmv/src/micropython/py/scope.h b/src/openmv/src/micropython/py/scope.h new file mode 100755 index 0000000..5e9a0eb --- /dev/null +++ b/src/openmv/src/micropython/py/scope.h @@ -0,0 +1,98 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_SCOPE_H +#define MICROPY_INCLUDED_PY_SCOPE_H + +#include "py/parse.h" +#include "py/emitglue.h" + +enum { + ID_INFO_KIND_GLOBAL_IMPLICIT, + ID_INFO_KIND_GLOBAL_EXPLICIT, + ID_INFO_KIND_LOCAL, // in a function f, written and only referenced by f + ID_INFO_KIND_CELL, // in a function f, read/written by children of f + ID_INFO_KIND_FREE, // in a function f, belongs to the parent of f +}; + +enum { + ID_FLAG_IS_PARAM = 0x01, + ID_FLAG_IS_STAR_PARAM = 0x02, + ID_FLAG_IS_DBL_STAR_PARAM = 0x04, + ID_FLAG_VIPER_TYPE_POS = 4, +}; + +typedef struct _id_info_t { + uint8_t kind; + uint8_t flags; + // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local + // whet it's an ID_INFO_KIND_CELL/FREE this is the unique number of the closed over variable + uint16_t local_num; + qstr qst; +} id_info_t; + +#define SCOPE_IS_FUNC_LIKE(s) ((s) >= SCOPE_LAMBDA) + +// scope is a "block" in Python parlance +typedef enum { + SCOPE_MODULE, + SCOPE_CLASS, + SCOPE_LAMBDA, + SCOPE_LIST_COMP, + SCOPE_DICT_COMP, + SCOPE_SET_COMP, + SCOPE_GEN_EXPR, + SCOPE_FUNCTION, +} scope_kind_t; + +typedef struct _scope_t { + scope_kind_t kind; + struct _scope_t *parent; + struct _scope_t *next; + mp_parse_node_t pn; + mp_raw_code_t *raw_code; + uint16_t source_file; // a qstr + uint16_t simple_name; // a qstr + uint16_t scope_flags; // see runtime0.h + uint16_t emit_options; // see emitglue.h + uint16_t num_pos_args; + uint16_t num_kwonly_args; + uint16_t num_def_pos_args; + uint16_t num_locals; + uint16_t stack_size; // maximum size of the locals stack + uint16_t exc_stack_size; // maximum size of the exception stack + uint16_t id_info_alloc; + uint16_t id_info_len; + id_info_t *id_info; +} scope_t; + +scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options); +void scope_free(scope_t *scope); +id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added); +id_info_t *scope_find(scope_t *scope, qstr qstr); +id_info_t *scope_find_global(scope_t *scope, qstr qstr); +void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst); + +#endif // MICROPY_INCLUDED_PY_SCOPE_H diff --git a/src/openmv/src/micropython/py/sequence.c b/src/openmv/src/micropython/py/sequence.c new file mode 100755 index 0000000..c66fde9 --- /dev/null +++ b/src/openmv/src/micropython/py/sequence.c @@ -0,0 +1,276 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +// Helpers for sequence types + +#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } + +// Implements backend of sequence * integer operation. Assumes elements are +// memory-adjacent in sequence. +void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) { + for (size_t i = 0; i < times; i++) { + size_t copy_sz = item_sz * len; + memcpy(dest, items, copy_sz); + dest = (char*)dest + copy_sz; + } +} + +#if MICROPY_PY_BUILTINS_SLICE + +bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { + mp_obj_t ostart, ostop, ostep; + mp_int_t start, stop; + mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { + indexes->step = mp_obj_get_int(ostep); + if (indexes->step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } else { + indexes->step = 1; + } + + if (ostart == mp_const_none) { + if (indexes->step > 0) { + start = 0; + } else { + start = len - 1; + } + } else { + start = mp_obj_get_int(ostart); + } + if (ostop == mp_const_none) { + if (indexes->step > 0) { + stop = len; + } else { + stop = 0; + } + } else { + stop = mp_obj_get_int(ostop); + if (stop >= 0 && indexes->step < 0) { + stop += 1; + } + } + + // Unlike subscription, out-of-bounds slice indexes are never error + if (start < 0) { + start = len + start; + if (start < 0) { + if (indexes->step < 0) { + start = -1; + } else { + start = 0; + } + } + } else if (indexes->step > 0 && (mp_uint_t)start > len) { + start = len; + } else if (indexes->step < 0 && (mp_uint_t)start >= len) { + start = len - 1; + } + if (stop < 0) { + stop = len + stop; + if (stop < 0) { + stop = -1; + } + if (indexes->step < 0) { + stop += 1; + } + } else if ((mp_uint_t)stop > len) { + stop = len; + } + + // CPython returns empty sequence in such case, or point for assignment is at start + if (indexes->step > 0 && start > stop) { + stop = start; + } else if (indexes->step < 0 && start < stop) { + stop = start + 1; + } + + indexes->start = start; + indexes->stop = stop; + + return indexes->step == 1; +} + +#endif + +mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) { + (void)len; // TODO can we remove len from the arg list? + + mp_int_t start = indexes->start, stop = indexes->stop; + mp_int_t step = indexes->step; + + mp_obj_t res = mp_obj_new_list(0, NULL); + + if (step < 0) { + while (start >= stop) { + mp_obj_list_append(res, seq[start]); + start += step; + } + } else { + while (start < stop) { + mp_obj_list_append(res, seq[start]); + start += step; + } + } + return res; +} + +// Special-case comparison function for sequences of bytes +// Don't pass MP_BINARY_OP_NOT_EQUAL here +bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2) { + if (op == MP_BINARY_OP_EQUAL && len1 != len2) { + return false; + } + + // Let's deal only with > & >= + if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { + SWAP(const byte*, data1, data2); + SWAP(size_t, len1, len2); + if (op == MP_BINARY_OP_LESS) { + op = MP_BINARY_OP_MORE; + } else { + op = MP_BINARY_OP_MORE_EQUAL; + } + } + size_t min_len = len1 < len2 ? len1 : len2; + int res = memcmp(data1, data2, min_len); + if (op == MP_BINARY_OP_EQUAL) { + // If we are checking for equality, here're the answer + return res == 0; + } + if (res < 0) { + return false; + } + if (res > 0) { + return true; + } + + // If we had tie in the last element... + // ... and we have lists of different lengths... + if (len1 != len2) { + if (len1 < len2) { + // ... then longer list length wins (we deal only with >) + return false; + } + } else if (op == MP_BINARY_OP_MORE) { + // Otherwise, if we have strict relation, equality means failure + return false; + } + return true; +} + +// Special-case comparison function for sequences of mp_obj_t +// Don't pass MP_BINARY_OP_NOT_EQUAL here +bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2) { + if (op == MP_BINARY_OP_EQUAL && len1 != len2) { + return false; + } + + // Let's deal only with > & >= + if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { + SWAP(const mp_obj_t *, items1, items2); + SWAP(size_t, len1, len2); + if (op == MP_BINARY_OP_LESS) { + op = MP_BINARY_OP_MORE; + } else { + op = MP_BINARY_OP_MORE_EQUAL; + } + } + + size_t len = len1 < len2 ? len1 : len2; + for (size_t i = 0; i < len; i++) { + // If current elements equal, can't decide anything - go on + if (mp_obj_equal(items1[i], items2[i])) { + continue; + } + + // Othewise, if they are not equal, we can have final decision based on them + if (op == MP_BINARY_OP_EQUAL) { + // In particular, if we are checking for equality, here're the answer + return false; + } + + // Otherwise, application of relation op gives the answer + return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true); + } + + // If we had tie in the last element... + // ... and we have lists of different lengths... + if (len1 != len2) { + if (len1 < len2) { + // ... then longer list length wins (we deal only with >) + return false; + } + } else if (op == MP_BINARY_OP_MORE) { + // Otherwise, if we have strict relation, sequence equality means failure + return false; + } + + return true; +} + +// Special-case of index() which searches for mp_obj_t +mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) { + mp_obj_type_t *type = mp_obj_get_type(args[0]); + mp_obj_t value = args[1]; + size_t start = 0; + size_t stop = len; + + if (n_args >= 3) { + start = mp_get_index(type, len, args[2], true); + if (n_args >= 4) { + stop = mp_get_index(type, len, args[3], true); + } + } + + for (size_t i = start; i < stop; i++) { + if (mp_obj_equal(items[i], value)) { + // Common sense says this cannot overflow small int + return MP_OBJ_NEW_SMALL_INT(i); + } + } + + mp_raise_ValueError("object not in sequence"); +} + +mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) { + size_t count = 0; + for (size_t i = 0; i < len; i++) { + if (mp_obj_equal(items[i], value)) { + count++; + } + } + + // Common sense says this cannot overflow small int + return MP_OBJ_NEW_SMALL_INT(count); +} diff --git a/src/openmv/src/micropython/py/showbc.c b/src/openmv/src/micropython/py/showbc.c new file mode 100755 index 0000000..3deb18c --- /dev/null +++ b/src/openmv/src/micropython/py/showbc.c @@ -0,0 +1,568 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/bc0.h" +#include "py/bc.h" + +#if MICROPY_DEBUG_PRINTERS + +// redirect all printfs in this file to the platform print stream +#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) + +#define DECODE_UINT { \ + unum = 0; \ + do { \ + unum = (unum << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0); \ +} +#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) +#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) + +#if MICROPY_PERSISTENT_CODE + +#define DECODE_QSTR \ + qst = ip[0] | ip[1] << 8; \ + ip += 2; +#define DECODE_PTR \ + DECODE_UINT; \ + unum = mp_showbc_const_table[unum] +#define DECODE_OBJ \ + DECODE_UINT; \ + unum = mp_showbc_const_table[unum] + +#else + +#define DECODE_QSTR { \ + qst = 0; \ + do { \ + qst = (qst << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0); \ +} +#define DECODE_PTR do { \ + ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \ + unum = (uintptr_t)*(void**)ip; \ + ip += sizeof(void*); \ +} while (0) +#define DECODE_OBJ do { \ + ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \ + unum = (mp_uint_t)*(mp_obj_t*)ip; \ + ip += sizeof(mp_obj_t); \ +} while (0) + +#endif + +const byte *mp_showbc_code_start; +const mp_uint_t *mp_showbc_const_table; + +void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len, const mp_uint_t *const_table) { + mp_showbc_code_start = ip; + + // get bytecode parameters + mp_uint_t n_state = mp_decode_uint(&ip); + mp_uint_t n_exc_stack = mp_decode_uint(&ip); + /*mp_uint_t scope_flags =*/ ip++; + mp_uint_t n_pos_args = *ip++; + mp_uint_t n_kwonly_args = *ip++; + /*mp_uint_t n_def_pos_args =*/ ip++; + + const byte *code_info = ip; + mp_uint_t code_info_size = mp_decode_uint(&code_info); + ip += code_info_size; + + #if MICROPY_PERSISTENT_CODE + qstr block_name = code_info[0] | (code_info[1] << 8); + qstr source_file = code_info[2] | (code_info[3] << 8); + code_info += 4; + #else + qstr block_name = mp_decode_uint(&code_info); + qstr source_file = mp_decode_uint(&code_info); + #endif + printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n", + qstr_str(source_file), qstr_str(block_name), descr, mp_showbc_code_start, len); + + // raw bytecode dump + printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size); + for (mp_uint_t i = 0; i < len; i++) { + if (i > 0 && i % 16 == 0) { + printf("\n"); + } + printf(" %02x", mp_showbc_code_start[i]); + } + printf("\n"); + + // bytecode prelude: arg names (as qstr objects) + printf("arg names:"); + for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) { + printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(const_table[i]))); + } + printf("\n"); + + printf("(N_STATE " UINT_FMT ")\n", n_state); + printf("(N_EXC_STACK " UINT_FMT ")\n", n_exc_stack); + + // for printing line number info + const byte *bytecode_start = ip; + + // bytecode prelude: initialise closed over variables + { + uint local_num; + while ((local_num = *ip++) != 255) { + printf("(INIT_CELL %u)\n", local_num); + } + len -= ip - mp_showbc_code_start; + } + + // print out line number info + { + mp_int_t bc = bytecode_start - ip; + mp_uint_t source_line = 1; + printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); + for (const byte* ci = code_info; *ci;) { + if ((ci[0] & 0x80) == 0) { + // 0b0LLBBBBB encoding + bc += ci[0] & 0x1f; + source_line += ci[0] >> 5; + ci += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + bc += ci[0] & 0xf; + source_line += ((ci[0] << 4) & 0x700) | ci[1]; + ci += 2; + } + printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); + } + } + mp_bytecode_print2(ip, len - 0, const_table); +} + +const byte *mp_bytecode_print_str(const byte *ip) { + mp_uint_t unum; + qstr qst; + + switch (*ip++) { + case MP_BC_LOAD_CONST_FALSE: + printf("LOAD_CONST_FALSE"); + break; + + case MP_BC_LOAD_CONST_NONE: + printf("LOAD_CONST_NONE"); + break; + + case MP_BC_LOAD_CONST_TRUE: + printf("LOAD_CONST_TRUE"); + break; + + case MP_BC_LOAD_CONST_SMALL_INT: { + mp_int_t num = 0; + if ((ip[0] & 0x40) != 0) { + // Number is negative + num--; + } + do { + num = (num << 7) | (*ip & 0x7f); + } while ((*ip++ & 0x80) != 0); + printf("LOAD_CONST_SMALL_INT " INT_FMT, num); + break; + } + + case MP_BC_LOAD_CONST_STRING: + DECODE_QSTR; + printf("LOAD_CONST_STRING '%s'", qstr_str(qst)); + break; + + case MP_BC_LOAD_CONST_OBJ: + DECODE_OBJ; + printf("LOAD_CONST_OBJ %p=", MP_OBJ_TO_PTR(unum)); + mp_obj_print_helper(&mp_plat_print, (mp_obj_t)unum, PRINT_REPR); + break; + + case MP_BC_LOAD_NULL: + printf("LOAD_NULL"); + break; + + case MP_BC_LOAD_FAST_N: + DECODE_UINT; + printf("LOAD_FAST_N " UINT_FMT, unum); + break; + + case MP_BC_LOAD_DEREF: + DECODE_UINT; + printf("LOAD_DEREF " UINT_FMT, unum); + break; + + case MP_BC_LOAD_NAME: + DECODE_QSTR; + printf("LOAD_NAME %s", qstr_str(qst)); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + printf(" (cache=%u)", *ip++); + } + break; + + case MP_BC_LOAD_GLOBAL: + DECODE_QSTR; + printf("LOAD_GLOBAL %s", qstr_str(qst)); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + printf(" (cache=%u)", *ip++); + } + break; + + case MP_BC_LOAD_ATTR: + DECODE_QSTR; + printf("LOAD_ATTR %s", qstr_str(qst)); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + printf(" (cache=%u)", *ip++); + } + break; + + case MP_BC_LOAD_METHOD: + DECODE_QSTR; + printf("LOAD_METHOD %s", qstr_str(qst)); + break; + + case MP_BC_LOAD_SUPER_METHOD: + DECODE_QSTR; + printf("LOAD_SUPER_METHOD %s", qstr_str(qst)); + break; + + case MP_BC_LOAD_BUILD_CLASS: + printf("LOAD_BUILD_CLASS"); + break; + + case MP_BC_LOAD_SUBSCR: + printf("LOAD_SUBSCR"); + break; + + case MP_BC_STORE_FAST_N: + DECODE_UINT; + printf("STORE_FAST_N " UINT_FMT, unum); + break; + + case MP_BC_STORE_DEREF: + DECODE_UINT; + printf("STORE_DEREF " UINT_FMT, unum); + break; + + case MP_BC_STORE_NAME: + DECODE_QSTR; + printf("STORE_NAME %s", qstr_str(qst)); + break; + + case MP_BC_STORE_GLOBAL: + DECODE_QSTR; + printf("STORE_GLOBAL %s", qstr_str(qst)); + break; + + case MP_BC_STORE_ATTR: + DECODE_QSTR; + printf("STORE_ATTR %s", qstr_str(qst)); + if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { + printf(" (cache=%u)", *ip++); + } + break; + + case MP_BC_STORE_SUBSCR: + printf("STORE_SUBSCR"); + break; + + case MP_BC_DELETE_FAST: + DECODE_UINT; + printf("DELETE_FAST " UINT_FMT, unum); + break; + + case MP_BC_DELETE_DEREF: + DECODE_UINT; + printf("DELETE_DEREF " UINT_FMT, unum); + break; + + case MP_BC_DELETE_NAME: + DECODE_QSTR; + printf("DELETE_NAME %s", qstr_str(qst)); + break; + + case MP_BC_DELETE_GLOBAL: + DECODE_QSTR; + printf("DELETE_GLOBAL %s", qstr_str(qst)); + break; + + case MP_BC_DUP_TOP: + printf("DUP_TOP"); + break; + + case MP_BC_DUP_TOP_TWO: + printf("DUP_TOP_TWO"); + break; + + case MP_BC_POP_TOP: + printf("POP_TOP"); + break; + + case MP_BC_ROT_TWO: + printf("ROT_TWO"); + break; + + case MP_BC_ROT_THREE: + printf("ROT_THREE"); + break; + + case MP_BC_JUMP: + DECODE_SLABEL; + printf("JUMP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_POP_JUMP_IF_TRUE: + DECODE_SLABEL; + printf("POP_JUMP_IF_TRUE " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_POP_JUMP_IF_FALSE: + DECODE_SLABEL; + printf("POP_JUMP_IF_FALSE " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_JUMP_IF_TRUE_OR_POP: + DECODE_SLABEL; + printf("JUMP_IF_TRUE_OR_POP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_JUMP_IF_FALSE_OR_POP: + DECODE_SLABEL; + printf("JUMP_IF_FALSE_OR_POP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_SETUP_WITH: + DECODE_ULABEL; // loop-like labels are always forward + printf("SETUP_WITH " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_WITH_CLEANUP: + printf("WITH_CLEANUP"); + break; + + case MP_BC_UNWIND_JUMP: + DECODE_SLABEL; + printf("UNWIND_JUMP " UINT_FMT " %d", (mp_uint_t)(ip + unum - mp_showbc_code_start), *ip); + ip += 1; + break; + + case MP_BC_SETUP_EXCEPT: + DECODE_ULABEL; // except labels are always forward + printf("SETUP_EXCEPT " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_SETUP_FINALLY: + DECODE_ULABEL; // except labels are always forward + printf("SETUP_FINALLY " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_END_FINALLY: + // if TOS is an exception, reraises the exception (3 values on TOS) + // if TOS is an integer, does something else + // if TOS is None, just pops it and continues + // else error + printf("END_FINALLY"); + break; + + case MP_BC_GET_ITER: + printf("GET_ITER"); + break; + + case MP_BC_GET_ITER_STACK: + printf("GET_ITER_STACK"); + break; + + case MP_BC_FOR_ITER: + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start)); + break; + + case MP_BC_POP_BLOCK: + // pops block and restores the stack + printf("POP_BLOCK"); + break; + + case MP_BC_POP_EXCEPT: + // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate + printf("POP_EXCEPT"); + break; + + case MP_BC_BUILD_TUPLE: + DECODE_UINT; + printf("BUILD_TUPLE " UINT_FMT, unum); + break; + + case MP_BC_BUILD_LIST: + DECODE_UINT; + printf("BUILD_LIST " UINT_FMT, unum); + break; + + case MP_BC_BUILD_MAP: + DECODE_UINT; + printf("BUILD_MAP " UINT_FMT, unum); + break; + + case MP_BC_STORE_MAP: + printf("STORE_MAP"); + break; + + case MP_BC_BUILD_SET: + DECODE_UINT; + printf("BUILD_SET " UINT_FMT, unum); + break; + +#if MICROPY_PY_BUILTINS_SLICE + case MP_BC_BUILD_SLICE: + DECODE_UINT; + printf("BUILD_SLICE " UINT_FMT, unum); + break; +#endif + + case MP_BC_STORE_COMP: + DECODE_UINT; + printf("STORE_COMP " UINT_FMT, unum); + break; + + case MP_BC_UNPACK_SEQUENCE: + DECODE_UINT; + printf("UNPACK_SEQUENCE " UINT_FMT, unum); + break; + + case MP_BC_UNPACK_EX: + DECODE_UINT; + printf("UNPACK_EX " UINT_FMT, unum); + break; + + case MP_BC_MAKE_FUNCTION: + DECODE_PTR; + printf("MAKE_FUNCTION %p", (void*)(uintptr_t)unum); + break; + + case MP_BC_MAKE_FUNCTION_DEFARGS: + DECODE_PTR; + printf("MAKE_FUNCTION_DEFARGS %p", (void*)(uintptr_t)unum); + break; + + case MP_BC_MAKE_CLOSURE: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + printf("MAKE_CLOSURE %p " UINT_FMT, (void*)(uintptr_t)unum, n_closed_over); + break; + } + + case MP_BC_MAKE_CLOSURE_DEFARGS: { + DECODE_PTR; + mp_uint_t n_closed_over = *ip++; + printf("MAKE_CLOSURE_DEFARGS %p " UINT_FMT, (void*)(uintptr_t)unum, n_closed_over); + break; + } + + case MP_BC_CALL_FUNCTION: + DECODE_UINT; + printf("CALL_FUNCTION n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); + break; + + case MP_BC_CALL_FUNCTION_VAR_KW: + DECODE_UINT; + printf("CALL_FUNCTION_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD: + DECODE_UINT; + printf("CALL_METHOD n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); + break; + + case MP_BC_CALL_METHOD_VAR_KW: + DECODE_UINT; + printf("CALL_METHOD_VAR_KW n=" UINT_FMT " nkw=" UINT_FMT, unum & 0xff, (unum >> 8) & 0xff); + break; + + case MP_BC_RETURN_VALUE: + printf("RETURN_VALUE"); + break; + + case MP_BC_RAISE_VARARGS: + unum = *ip++; + printf("RAISE_VARARGS " UINT_FMT, unum); + break; + + case MP_BC_YIELD_VALUE: + printf("YIELD_VALUE"); + break; + + case MP_BC_YIELD_FROM: + printf("YIELD_FROM"); + break; + + case MP_BC_IMPORT_NAME: + DECODE_QSTR; + printf("IMPORT_NAME '%s'", qstr_str(qst)); + break; + + case MP_BC_IMPORT_FROM: + DECODE_QSTR; + printf("IMPORT_FROM '%s'", qstr_str(qst)); + break; + + case MP_BC_IMPORT_STAR: + printf("IMPORT_STAR"); + break; + + default: + if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { + printf("LOAD_CONST_SMALL_INT " INT_FMT, (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16); + } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { + printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI); + } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { + printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI); + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { + printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI); + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { + mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; + printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); + } else { + printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]); + assert(0); + return ip; + } + break; + } + + return ip; +} + +void mp_bytecode_print2(const byte *ip, size_t len, const mp_uint_t *const_table) { + mp_showbc_code_start = ip; + mp_showbc_const_table = const_table; + while (ip < len + mp_showbc_code_start) { + printf("%02u ", (uint)(ip - mp_showbc_code_start)); + ip = mp_bytecode_print_str(ip); + printf("\n"); + } +} + +#endif // MICROPY_DEBUG_PRINTERS diff --git a/src/openmv/src/micropython/py/smallint.c b/src/openmv/src/micropython/py/smallint.c new file mode 100755 index 0000000..aa542ca --- /dev/null +++ b/src/openmv/src/micropython/py/smallint.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/smallint.h" + +bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + if (x > (MP_SMALL_INT_MAX / y)) { + return true; + } + } else { // x positive, y nonpositive + if (y < (MP_SMALL_INT_MIN / x)) { + return true; + } + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + if (x < (MP_SMALL_INT_MIN / y)) { + return true; + } + } else { // x and y are nonpositive + if (x != 0 && y < (MP_SMALL_INT_MAX / x)) { + return true; + } + } // End if x and y are nonpositive + } // End if x is nonpositive + return false; +} + +mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) { + // Python specs require that mod has same sign as second operand + dividend %= divisor; + if ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)) { + dividend += divisor; + } + return dividend; +} + +mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom) { + if (num >= 0) { + if (denom < 0) { + num += -denom - 1; + } + } else { + if (denom >= 0) { + num += -denom + 1; + } + } + return num / denom; +} diff --git a/src/openmv/src/micropython/py/smallint.h b/src/openmv/src/micropython/py/smallint.h new file mode 100755 index 0000000..6a3c752 --- /dev/null +++ b/src/openmv/src/micropython/py/smallint.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_SMALLINT_H +#define MICROPY_INCLUDED_PY_SMALLINT_H + +#include "py/mpconfig.h" +#include "py/misc.h" + +// Functions for small integer arithmetic + +#ifndef MP_SMALL_INT_MIN + +// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0) +// Mask to truncate mp_int_t to positive value +#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1)) + +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B + +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)WORD_MSBIT_HIGH) >> 2)) +#define MP_SMALL_INT_FITS(n) ((((n) & MP_SMALL_INT_MIN) == 0) || (((n) & MP_SMALL_INT_MIN) == MP_SMALL_INT_MIN)) +// Mask to truncate mp_int_t to positive value +#define MP_SMALL_INT_POSITIVE_MASK ~(WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1) | (WORD_MSBIT_HIGH >> 2)) + +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0) +// Mask to truncate mp_int_t to positive value +#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1)) + +#endif + +#endif + +#define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN))) + +bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y); +mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor); +mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom); + +#endif // MICROPY_INCLUDED_PY_SMALLINT_H diff --git a/src/openmv/src/micropython/py/stackctrl.c b/src/openmv/src/micropython/py/stackctrl.c new file mode 100755 index 0000000..5c07796 --- /dev/null +++ b/src/openmv/src/micropython/py/stackctrl.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stackctrl.h" + +void mp_stack_ctrl_init(void) { + volatile int stack_dummy; + MP_STATE_THREAD(stack_top) = (char*)&stack_dummy; +} + +void mp_stack_set_top(void *top) { + MP_STATE_THREAD(stack_top) = top; +} + +mp_uint_t mp_stack_usage(void) { + // Assumes descending stack + volatile int stack_dummy; + return MP_STATE_THREAD(stack_top) - (char*)&stack_dummy; +} + +#if MICROPY_STACK_CHECK + +void mp_stack_set_limit(mp_uint_t limit) { + MP_STATE_THREAD(stack_limit) = limit; +} + +void mp_stack_check(void) { + if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { + mp_raise_recursion_depth(); + } +} + +#endif // MICROPY_STACK_CHECK diff --git a/src/openmv/src/micropython/py/stackctrl.h b/src/openmv/src/micropython/py/stackctrl.h new file mode 100755 index 0000000..ff8da0a --- /dev/null +++ b/src/openmv/src/micropython/py/stackctrl.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_STACKCTRL_H +#define MICROPY_INCLUDED_PY_STACKCTRL_H + +#include "py/mpconfig.h" + +void mp_stack_ctrl_init(void); +void mp_stack_set_top(void *top); +mp_uint_t mp_stack_usage(void); + +#if MICROPY_STACK_CHECK + +void mp_stack_set_limit(mp_uint_t limit); +void mp_stack_check(void); +#define MP_STACK_CHECK() mp_stack_check() + +#else + +#define mp_stack_set_limit(limit) +#define MP_STACK_CHECK() + +#endif + +#endif // MICROPY_INCLUDED_PY_STACKCTRL_H diff --git a/src/openmv/src/micropython/py/stream.c b/src/openmv/src/micropython/py/stream.c new file mode 100755 index 0000000..2a9acde --- /dev/null +++ b/src/openmv/src/micropython/py/stream.c @@ -0,0 +1,555 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/objstr.h" +#include "py/stream.h" +#include "py/runtime.h" + +// This file defines generic Python stream read/write methods which +// dispatch to the underlying stream interface of an object. + +// TODO: should be in mpconfig.h +#define DEFAULT_BUFFER_SIZE 256 + +STATIC mp_obj_t stream_readall(mp_obj_t self_in); + +#define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes) + +// Returns error condition in *errcode, if non-zero, return value is number of bytes written +// before error condition occurred. If *errcode == 0, returns total bytes written (which will +// be equal to input size). +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { + byte *buf = buf_; + typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + io_func_t io_func; + const mp_stream_p_t *stream_p = mp_get_stream(stream); + if (flags & MP_STREAM_RW_WRITE) { + io_func = (io_func_t)stream_p->write; + } else { + io_func = stream_p->read; + } + + *errcode = 0; + mp_uint_t done = 0; + while (size > 0) { + mp_uint_t out_sz = io_func(stream, buf, size, errcode); + // For read, out_sz == 0 means EOF. For write, it's unspecified + // what it means, but we don't make any progress, so returning + // is still the best option. + if (out_sz == 0) { + return done; + } + if (out_sz == MP_STREAM_ERROR) { + // If we read something before getting EAGAIN, don't leak it + if (mp_is_nonblocking_error(*errcode) && done != 0) { + *errcode = 0; + } + return done; + } + if (flags & MP_STREAM_RW_ONCE) { + return out_sz; + } + + buf += out_sz; + size -= out_sz; + done += out_sz; + } + return done; +} + +const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_stream_p_t *stream_p = type->protocol; + if (stream_p == NULL + || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) + || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) + || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { + // CPython: io.UnsupportedOperation, OSError subclass + mp_raise_msg(&mp_type_OSError, "stream operation not supported"); + } + return stream_p; +} + +STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { + // What to do if sz < -1? Python docs don't specify this case. + // CPython does a readall, but here we silently let negatives through, + // and they will cause a MemoryError. + mp_int_t sz; + if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) { + return stream_readall(args[0]); + } + + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (stream_p->is_text) { + // We need to read sz number of unicode characters. Because we don't have any + // buffering, and because the stream API can only read bytes, we must read here + // in units of bytes and must never over read. If we want sz chars, then reading + // sz bytes will never over-read, so we follow this approach, in a loop to keep + // reading until we have exactly enough chars. This will be 1 read for text + // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII + // chars. For text with lots of non-ASCII chars, it'll be pretty inefficient + // in time and memory. + + vstr_t vstr; + vstr_init(&vstr, sz); + mp_uint_t more_bytes = sz; + mp_uint_t last_buf_offset = 0; + while (more_bytes > 0) { + char *p = vstr_add_len(&vstr, more_bytes); + int error; + mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error); + if (error != 0) { + vstr_cut_tail_bytes(&vstr, more_bytes); + if (mp_is_nonblocking_error(error)) { + // With non-blocking streams, we read as much as we can. + // If we read nothing, return None, just like read(). + // Otherwise, return data read so far. + // TODO what if we have read only half a non-ASCII char? + if (vstr.len == 0) { + vstr_clear(&vstr); + return mp_const_none; + } + break; + } + mp_raise_OSError(error); + } + + if (out_sz < more_bytes) { + // Finish reading. + // TODO what if we have read only half a non-ASCII char? + vstr_cut_tail_bytes(&vstr, more_bytes - out_sz); + if (out_sz == 0) { + break; + } + } + + // count chars from bytes just read + for (mp_uint_t off = last_buf_offset;;) { + byte b = vstr.buf[off]; + int n; + if (!UTF8_IS_NONASCII(b)) { + // 1-byte ASCII char + n = 1; + } else if ((b & 0xe0) == 0xc0) { + // 2-byte char + n = 2; + } else if ((b & 0xf0) == 0xe0) { + // 3-byte char + n = 3; + } else if ((b & 0xf8) == 0xf0) { + // 4-byte char + n = 4; + } else { + // TODO + n = 5; + } + if (off + n <= vstr.len) { + // got a whole char in n bytes + off += n; + sz -= 1; + last_buf_offset = off; + if (off >= vstr.len) { + more_bytes = sz; + break; + } + } else { + // didn't get a whole char, so work out how many extra bytes are needed for + // this partial char, plus bytes for additional chars that we want + more_bytes = (off + n - vstr.len) + (sz - 1); + break; + } + } + } + + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); + } + #endif + + vstr_t vstr; + vstr_init_len(&vstr, sz); + int error; + mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags); + if (error != 0) { + vstr_clear(&vstr); + if (mp_is_nonblocking_error(error)) { + // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read + // "If the object is in non-blocking mode and no bytes are available, + // None is returned." + // This is actually very weird, as naive truth check will treat + // this as EOF. + return mp_const_none; + } + mp_raise_OSError(error); + } else { + vstr.len = out_sz; + return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); + } +} + +STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read); + +STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); + +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { + int error; + mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); + if (error != 0) { + if (mp_is_nonblocking_error(error)) { + // http://docs.python.org/3/library/io.html#io.RawIOBase.write + // "None is returned if the raw stream is set not to block and + // no single byte could be readily written to it." + return mp_const_none; + } + mp_raise_OSError(error); + } else { + return MP_OBJ_NEW_SMALL_INT(out_sz); + } +} + +// This is used to adapt a stream object to an mp_print_t interface +void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { + mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); +} + +STATIC mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + size_t max_len = (size_t)-1; + size_t off = 0; + if (n_args == 3) { + max_len = mp_obj_get_int_truncated(args[2]); + } else if (n_args == 4) { + off = mp_obj_get_int_truncated(args[2]); + max_len = mp_obj_get_int_truncated(args[3]); + if (off > bufinfo.len) { + off = bufinfo.len; + } + } + bufinfo.len -= off; + return mp_stream_write(args[0], (byte*)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method); + +STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); + +STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + + // CPython extension: if 2nd arg is provided, that's max len to read, + // instead of full buffer. Similar to + // https://docs.python.org/3/library/socket.html#socket.socket.recv_into + mp_uint_t len = bufinfo.len; + if (n_args > 2) { + len = mp_obj_get_int(args[2]); + if (len > bufinfo.len) { + len = bufinfo.len; + } + } + + int error; + mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); + if (error != 0) { + if (mp_is_nonblocking_error(error)) { + return mp_const_none; + } + mp_raise_OSError(error); + } else { + return MP_OBJ_NEW_SMALL_INT(out_sz); + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); + +STATIC mp_obj_t stream_readall(mp_obj_t self_in) { + const mp_stream_p_t *stream_p = mp_get_stream(self_in); + + mp_uint_t total_size = 0; + vstr_t vstr; + vstr_init(&vstr, DEFAULT_BUFFER_SIZE); + char *p = vstr.buf; + mp_uint_t current_read = DEFAULT_BUFFER_SIZE; + while (true) { + int error; + mp_uint_t out_sz = stream_p->read(self_in, p, current_read, &error); + if (out_sz == MP_STREAM_ERROR) { + if (mp_is_nonblocking_error(error)) { + // With non-blocking streams, we read as much as we can. + // If we read nothing, return None, just like read(). + // Otherwise, return data read so far. + if (total_size == 0) { + return mp_const_none; + } + break; + } + mp_raise_OSError(error); + } + if (out_sz == 0) { + break; + } + total_size += out_sz; + if (out_sz < current_read) { + current_read -= out_sz; + p += out_sz; + } else { + p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE); + current_read = DEFAULT_BUFFER_SIZE; + } + } + + vstr.len = total_size; + return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); +} + +// Unbuffered, inefficient implementation of readline() for raw I/O files. +STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) { + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + + mp_int_t max_size = -1; + if (n_args > 1) { + max_size = MP_OBJ_SMALL_INT_VALUE(args[1]); + } + + vstr_t vstr; + if (max_size != -1) { + vstr_init(&vstr, max_size); + } else { + vstr_init(&vstr, 16); + } + + while (max_size == -1 || max_size-- != 0) { + char *p = vstr_add_len(&vstr, 1); + int error; + mp_uint_t out_sz = stream_p->read(args[0], p, 1, &error); + if (out_sz == MP_STREAM_ERROR) { + if (mp_is_nonblocking_error(error)) { + if (vstr.len == 1) { + // We just incremented it, but otherwise we read nothing + // and immediately got EAGAIN. This case is not well + // specified in + // https://docs.python.org/3/library/io.html#io.IOBase.readline + // unlike similar case for read(). But we follow the latter's + // behavior - return None. + vstr_clear(&vstr); + return mp_const_none; + } else { + goto done; + } + } + mp_raise_OSError(error); + } + if (out_sz == 0) { +done: + // Back out previously added byte + // Consider, what's better - read a char and get OutOfMemory (so read + // char is lost), or allocate first as we do. + vstr_cut_tail_bytes(&vstr, 1); + break; + } + if (*p == '\n') { + break; + } + } + + return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline); + +// TODO take an optional extra argument (what does it do exactly?) +STATIC mp_obj_t stream_unbuffered_readlines(mp_obj_t self) { + mp_obj_t lines = mp_obj_new_list(0, NULL); + for (;;) { + mp_obj_t line = stream_unbuffered_readline(1, &self); + if (!mp_obj_is_true(line)) { + break; + } + mp_obj_list_append(lines, line); + } + return lines; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj, stream_unbuffered_readlines); + +mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { + mp_obj_t l_in = stream_unbuffered_readline(1, &self); + if (mp_obj_is_true(l_in)) { + return l_in; + } + return MP_OBJ_STOP_ITERATION; +} + +mp_obj_t mp_stream_close(mp_obj_t stream) { + const mp_stream_p_t *stream_p = mp_get_stream(stream); + int error; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); + +STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { + struct mp_stream_seek_t seek_s; + // TODO: Could be uint64 + seek_s.offset = mp_obj_get_int(args[1]); + seek_s.whence = SEEK_SET; + if (n_args == 3) { + seek_s.whence = mp_obj_get_int(args[2]); + } + + // In POSIX, it's error to seek before end of stream, we enforce it here. + if (seek_s.whence == SEEK_SET && seek_s.offset < 0) { + mp_raise_OSError(MP_EINVAL); + } + + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + int error; + mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + + // TODO: Could be uint64 + return mp_obj_new_int_from_uint(seek_s.offset); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj, 2, 3, stream_seek); + +STATIC mp_obj_t stream_tell(mp_obj_t self) { + mp_obj_t offset = MP_OBJ_NEW_SMALL_INT(0); + mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(SEEK_CUR); + const mp_obj_t args[3] = {self, offset, whence}; + return stream_seek(3, args); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell); + +STATIC mp_obj_t stream_flush(mp_obj_t self) { + const mp_stream_p_t *stream_p = mp_get_stream(self); + int error; + mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush); + +STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + uintptr_t val = 0; + if (n_args > 2) { + if (mp_get_buffer(args[2], &bufinfo, MP_BUFFER_WRITE)) { + val = (uintptr_t)bufinfo.buf; + } else { + val = mp_obj_get_int_truncated(args[2]); + } + } + + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + int error; + mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + + return mp_obj_new_int(res); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj, 2, 3, stream_ioctl); + +#if MICROPY_STREAMS_POSIX_API +/* + * POSIX-like functions + * + * These functions have POSIX-compatible signature (except for "void *stream" + * first argument instead of "int fd"). They are useful to port existing + * POSIX-compatible software to work with MicroPython streams. + */ + +// errno-like variable. If any of the functions below returned with error +// status, this variable will contain error no. +int mp_stream_errno; + +ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &mp_stream_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &mp_stream_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { + const mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + struct mp_stream_seek_t seek_s; + seek_s.offset = offset; + seek_s.whence = whence; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &mp_stream_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return seek_s.offset; +} + +int mp_stream_posix_fsync(void *stream) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = o->type->protocol; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &mp_stream_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return res; +} + +#endif diff --git a/src/openmv/src/micropython/py/stream.h b/src/openmv/src/micropython/py/stream.h new file mode 100755 index 0000000..f4c6d30 --- /dev/null +++ b/src/openmv/src/micropython/py/stream.h @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_STREAM_H +#define MICROPY_INCLUDED_PY_STREAM_H + +#include "py/obj.h" +#include "py/mperrno.h" + +#define MP_STREAM_ERROR ((mp_uint_t)-1) + +// Stream ioctl request codes +#define MP_STREAM_FLUSH (1) +#define MP_STREAM_SEEK (2) +#define MP_STREAM_POLL (3) +#define MP_STREAM_CLOSE (4) +#define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) +#define MP_STREAM_GET_OPTS (6) // Get stream options +#define MP_STREAM_SET_OPTS (7) // Set stream options +#define MP_STREAM_GET_DATA_OPTS (8) // Get data/message options +#define MP_STREAM_SET_DATA_OPTS (9) // Set data/message options +#define MP_STREAM_GET_FILENO (10) // Get fileno of underlying file + +// These poll ioctl values are compatible with Linux +#define MP_STREAM_POLL_RD (0x0001) +#define MP_STREAM_POLL_WR (0x0004) +#define MP_STREAM_POLL_ERR (0x0008) +#define MP_STREAM_POLL_HUP (0x0010) + +// Argument structure for MP_STREAM_SEEK +struct mp_stream_seek_t { + // If whence == MP_SEEK_SET, offset should be treated as unsigned. + // This allows dealing with full-width stream sizes (16, 32, 64, + // etc. bits). For other seek types, should be treated as signed. + mp_off_t offset; + int whence; +}; + +// seek ioctl "whence" values +#define MP_SEEK_SET (0) +#define MP_SEEK_CUR (1) +#define MP_SEEK_END (2) + +// Stream protocol +typedef struct _mp_stream_p_t { + // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values + // are implementation-dependent, but will be exposed to user, e.g. via exception). + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); + mp_uint_t is_text : 1; // default is bytes, set this for text stream +} mp_stream_p_t; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); + +// these are for mp_get_stream_raise and can be or'd together +#define MP_STREAM_OP_READ (1) +#define MP_STREAM_OP_WRITE (2) +#define MP_STREAM_OP_IOCTL (4) + +// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods +static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) { + return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol; +} + +const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); +mp_obj_t mp_stream_close(mp_obj_t stream); + +// Iterator which uses mp_stream_unbuffered_readline_obj +mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); + +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags); + +// C-level helper functions +#define MP_STREAM_RW_READ 0 +#define MP_STREAM_RW_WRITE 2 +#define MP_STREAM_RW_ONCE 1 +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, byte flags); +#define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte*)buf, size, err, MP_STREAM_RW_WRITE) +#define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ) + +void mp_stream_write_adaptor(void *self, const char *buf, size_t len); + +#if MICROPY_STREAMS_POSIX_API +// Functions with POSIX-compatible signatures +// "stream" is assumed to be a pointer to a concrete object with the stream protocol +ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len); +ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len); +off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence); +int mp_stream_posix_fsync(void *stream); +#endif + +#if MICROPY_STREAMS_NON_BLOCK +#define mp_is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK) +#else +#define mp_is_nonblocking_error(errno) (0) +#endif + +#endif // MICROPY_INCLUDED_PY_STREAM_H diff --git a/src/openmv/src/micropython/py/unicode.c b/src/openmv/src/micropython/py/unicode.c new file mode 100755 index 0000000..935dc90 --- /dev/null +++ b/src/openmv/src/micropython/py/unicode.c @@ -0,0 +1,205 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/unicode.h" + +// attribute flags +#define FL_PRINT (0x01) +#define FL_SPACE (0x02) +#define FL_DIGIT (0x04) +#define FL_ALPHA (0x08) +#define FL_UPPER (0x10) +#define FL_LOWER (0x20) +#define FL_XDIGIT (0x40) + +// shorthand character attributes +#define AT_PR (FL_PRINT) +#define AT_SP (FL_SPACE | FL_PRINT) +#define AT_DI (FL_DIGIT | FL_PRINT | FL_XDIGIT) +#define AT_AL (FL_ALPHA | FL_PRINT) +#define AT_UP (FL_UPPER | FL_ALPHA | FL_PRINT) +#define AT_LO (FL_LOWER | FL_ALPHA | FL_PRINT) +#define AT_UX (FL_UPPER | FL_ALPHA | FL_PRINT | FL_XDIGIT) +#define AT_LX (FL_LOWER | FL_ALPHA | FL_PRINT | FL_XDIGIT) + +// table of attributes for ascii characters +STATIC const uint8_t attr[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, AT_SP, AT_SP, AT_SP, AT_SP, AT_SP, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + AT_SP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, + AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, + AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, + AT_DI, AT_DI, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, + AT_PR, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UP, + AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, + AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, + AT_UP, AT_UP, AT_UP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, + AT_PR, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LX, AT_LO, + AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, + AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, + AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0 +}; + +#if MICROPY_PY_BUILTINS_STR_UNICODE + +unichar utf8_get_char(const byte *s) { + unichar ord = *s++; + if (!UTF8_IS_NONASCII(ord)) return ord; + ord &= 0x7F; + for (unichar mask = 0x40; ord & mask; mask >>= 1) { + ord &= ~mask; + } + while (UTF8_IS_CONT(*s)) { + ord = (ord << 6) | (*s++ & 0x3F); + } + return ord; +} + +const byte *utf8_next_char(const byte *s) { + ++s; + while (UTF8_IS_CONT(*s)) { + ++s; + } + return s; +} + +mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { + mp_uint_t i = 0; + while (ptr > s) { + if (!UTF8_IS_CONT(*--ptr)) { + i++; + } + } + + return i; +} + +size_t utf8_charlen(const byte *str, size_t len) { + size_t charlen = 0; + for (const byte *top = str + len; str < top; ++str) { + if (!UTF8_IS_CONT(*str)) { + ++charlen; + } + } + return charlen; +} + +#endif + +// Be aware: These unichar_is* functions are actually ASCII-only! +bool unichar_isspace(unichar c) { + return c < 128 && (attr[c] & FL_SPACE) != 0; +} + +bool unichar_isalpha(unichar c) { + return c < 128 && (attr[c] & FL_ALPHA) != 0; +} + +/* unused +bool unichar_isprint(unichar c) { + return c < 128 && (attr[c] & FL_PRINT) != 0; +} +*/ + +bool unichar_isdigit(unichar c) { + return c < 128 && (attr[c] & FL_DIGIT) != 0; +} + +bool unichar_isxdigit(unichar c) { + return c < 128 && (attr[c] & FL_XDIGIT) != 0; +} + +bool unichar_isident(unichar c) { + return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0 || c == '_'); +} + +bool unichar_isupper(unichar c) { + return c < 128 && (attr[c] & FL_UPPER) != 0; +} + +bool unichar_islower(unichar c) { + return c < 128 && (attr[c] & FL_LOWER) != 0; +} + +unichar unichar_tolower(unichar c) { + if (unichar_isupper(c)) { + return c + 0x20; + } + return c; +} + +unichar unichar_toupper(unichar c) { + if (unichar_islower(c)) { + return c - 0x20; + } + return c; +} + +mp_uint_t unichar_xdigit_value(unichar c) { + // c is assumed to be hex digit + mp_uint_t n = c - '0'; + if (n > 9) { + n &= ~('a' - 'A'); + n -= ('A' - ('9' + 1)); + } + return n; +} + +#if MICROPY_PY_BUILTINS_STR_UNICODE + +bool utf8_check(const byte *p, size_t len) { + uint8_t need = 0; + const byte *end = p + len; + for (; p < end; p++) { + byte c = *p; + if (need) { + if (c >= 0x80) { + need--; + } else { + // mismatch + return 0; + } + } else { + if (c >= 0xc0) { + if (c >= 0xf8) { + // mismatch + return 0; + } + need = (0xe5 >> ((c >> 3) & 0x6)) & 3; + } else if (c >= 0x80) { + // mismatch + return 0; + } + } + } + return need == 0; // no pending fragments allowed +} + +#endif diff --git a/src/openmv/src/micropython/py/unicode.h b/src/openmv/src/micropython/py/unicode.h new file mode 100755 index 0000000..c1fb517 --- /dev/null +++ b/src/openmv/src/micropython/py/unicode.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_UNICODE_H +#define MICROPY_INCLUDED_PY_UNICODE_H + +#include "py/mpconfig.h" +#include "py/misc.h" + +mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr); +bool utf8_check(const byte *p, size_t len); + +#endif // MICROPY_INCLUDED_PY_UNICODE_H diff --git a/src/openmv/src/micropython/py/vm.c b/src/openmv/src/micropython/py/vm.c new file mode 100755 index 0000000..828ea79 --- /dev/null +++ b/src/openmv/src/micropython/py/vm.c @@ -0,0 +1,1476 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/emitglue.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "py/bc0.h" +#include "py/bc.h" + +#if 0 +#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); +#else +#define TRACE(ip) +#endif + +// Value stack grows up (this makes it incompatible with native C stack, but +// makes sure that arguments to functions are in natural order arg1..argN +// (Python semantics mandates left-to-right evaluation order, including for +// function arguments). Stack pointer is pre-incremented and points at the +// top element. +// Exception stack also grows up, top element is also pointed at. + +#define DECODE_UINT \ + mp_uint_t unum = 0; \ + do { \ + unum = (unum << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0) +#define DECODE_ULABEL size_t ulab = (ip[0] | (ip[1] << 8)); ip += 2 +#define DECODE_SLABEL size_t slab = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2 + +#if MICROPY_PERSISTENT_CODE + +#define DECODE_QSTR \ + qstr qst = ip[0] | ip[1] << 8; \ + ip += 2; +#define DECODE_PTR \ + DECODE_UINT; \ + void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum] +#define DECODE_OBJ \ + DECODE_UINT; \ + mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum] + +#else + +#define DECODE_QSTR qstr qst = 0; \ + do { \ + qst = (qst << 7) + (*ip & 0x7f); \ + } while ((*ip++ & 0x80) != 0) +#define DECODE_PTR \ + ip = (byte*)MP_ALIGN(ip, sizeof(void*)); \ + void *ptr = *(void**)ip; \ + ip += sizeof(void*) +#define DECODE_OBJ \ + ip = (byte*)MP_ALIGN(ip, sizeof(mp_obj_t)); \ + mp_obj_t obj = *(mp_obj_t*)ip; \ + ip += sizeof(mp_obj_t) + +#endif + +#define PUSH(val) *++sp = (val) +#define POP() (*sp--) +#define TOP() (*sp) +#define SET_TOP(val) *sp = (val) + +#if MICROPY_PY_SYS_EXC_INFO +#define CLEAR_SYS_EXC_INFO() MP_STATE_VM(cur_exception) = NULL; +#else +#define CLEAR_SYS_EXC_INFO() +#endif + +#define PUSH_EXC_BLOCK(with_or_finally) do { \ + DECODE_ULABEL; /* except labels are always forward */ \ + ++exc_sp; \ + exc_sp->handler = ip + ulab; \ + exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \ + exc_sp->prev_exc = NULL; \ + currently_in_except_block = 0; /* in a try block now */ \ +} while (0) + +#define POP_EXC_BLOCK() \ + currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \ + exc_sp--; /* pop back to previous exception handler */ \ + CLEAR_SYS_EXC_INFO() /* just clear sys.exc_info(), not compliant, but it shouldn't be used in 1st place */ + +// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) +// sp points to bottom of stack which grows up +// returns: +// MP_VM_RETURN_NORMAL, sp valid, return value in *sp +// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp +// MP_VM_RETURN_EXCEPTION, exception in fastn[0] +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { +#define SELECTIVE_EXC_IP (0) +#if SELECTIVE_EXC_IP +#define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */ +#define MARK_EXC_IP_GLOBAL() +#else +#define MARK_EXC_IP_SELECTIVE() +#define MARK_EXC_IP_GLOBAL() { code_state->ip = ip; } /* stores ip pointing to last opcode */ +#endif +#if MICROPY_OPT_COMPUTED_GOTO + #include "py/vmentrytable.h" + #define DISPATCH() do { \ + TRACE(ip); \ + MARK_EXC_IP_GLOBAL(); \ + goto *entry_table[*ip++]; \ + } while (0) + #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check + #define ENTRY(op) entry_##op + #define ENTRY_DEFAULT entry_default +#else + #define DISPATCH() goto dispatch_loop + #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check + #define ENTRY(op) case op + #define ENTRY_DEFAULT default +#endif + + // nlr_raise needs to be implemented as a goto, so that the C compiler's flow analyser + // sees that it's possible for us to jump from the dispatch loop to the exception + // handler. Without this, the code may have a different stack layout in the dispatch + // loop and the exception handler, leading to very obscure bugs. + #define RAISE(o) do { nlr_pop(); nlr.ret_val = MP_OBJ_TO_PTR(o); goto exception_handler; } while (0) + +#if MICROPY_STACKLESS +run_code_state: ; +#endif + // Pointers which are constant for particular invocation of mp_execute_bytecode() + mp_obj_t * /*const*/ fastn; + mp_exc_stack_t * /*const*/ exc_stack; + { + size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + fastn = &code_state->state[n_state - 1]; + exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); + } + + // variables that are visible to the exception handler (declared volatile) + volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions + mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + + #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR + // This needs to be volatile and outside the VM loop so it persists across handling + // of any exceptions. Otherwise it's possible that the VM never gives up the GIL. + volatile int gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #endif + + // outer exception handling loop + for (;;) { + nlr_buf_t nlr; +outer_dispatch_loop: + if (nlr_push(&nlr) == 0) { + // local variables that are not visible to the exception handler + const byte *ip = code_state->ip; + mp_obj_t *sp = code_state->sp; + mp_obj_t obj_shared; + MICROPY_VM_HOOK_INIT + + // If we have exception to inject, now that we finish setting up + // execution context, raise it. This works as if RAISE_VARARGS + // bytecode was executed. + // Injecting exc into yield from generator is a special case, + // handled by MP_BC_YIELD_FROM itself + if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { + mp_obj_t exc = inject_exc; + inject_exc = MP_OBJ_NULL; + exc = mp_make_raise_obj(exc); + RAISE(exc); + } + + // loop to execute byte code + for (;;) { +dispatch_loop: +#if MICROPY_OPT_COMPUTED_GOTO + DISPATCH(); +#else + TRACE(ip); + MARK_EXC_IP_GLOBAL(); + switch (*ip++) { +#endif + + ENTRY(MP_BC_LOAD_CONST_FALSE): + PUSH(mp_const_false); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_NONE): + PUSH(mp_const_none); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_TRUE): + PUSH(mp_const_true); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_SMALL_INT): { + mp_int_t num = 0; + if ((ip[0] & 0x40) != 0) { + // Number is negative + num--; + } + do { + num = (num << 7) | (*ip & 0x7f); + } while ((*ip++ & 0x80) != 0); + PUSH(MP_OBJ_NEW_SMALL_INT(num)); + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_CONST_STRING): { + DECODE_QSTR; + PUSH(MP_OBJ_NEW_QSTR(qst)); + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_CONST_OBJ): { + DECODE_OBJ; + PUSH(obj); + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_NULL): + PUSH(MP_OBJ_NULL); + DISPATCH(); + + ENTRY(MP_BC_LOAD_FAST_N): { + DECODE_UINT; + obj_shared = fastn[-unum]; + load_check: + if (obj_shared == MP_OBJ_NULL) { + local_name_error: { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment"); + RAISE(obj); + } + } + PUSH(obj_shared); + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_DEREF): { + DECODE_UINT; + obj_shared = mp_obj_cell_get(fastn[-unum]); + goto load_check; + } + + #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE + ENTRY(MP_BC_LOAD_NAME): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + PUSH(mp_load_name(qst)); + DISPATCH(); + } + #else + ENTRY(MP_BC_LOAD_NAME): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_uint_t x = *ip; + if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { + PUSH(mp_locals_get()->map.table[x].value); + } else { + mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem != NULL) { + *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; + PUSH(elem->value); + } else { + PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); + } + } + ip++; + DISPATCH(); + } + #endif + + #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE + ENTRY(MP_BC_LOAD_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + PUSH(mp_load_global(qst)); + DISPATCH(); + } + #else + ENTRY(MP_BC_LOAD_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_uint_t x = *ip; + if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { + PUSH(mp_globals_get()->map.table[x].value); + } else { + mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (elem != NULL) { + *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; + PUSH(elem->value); + } else { + PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); + } + } + ip++; + DISPATCH(); + } + #endif + + #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE + ENTRY(MP_BC_LOAD_ATTR): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + SET_TOP(mp_load_attr(TOP(), qst)); + DISPATCH(); + } + #else + ENTRY(MP_BC_LOAD_ATTR): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t top = TOP(); + if (mp_obj_is_instance_type(mp_obj_get_type(top))) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); + mp_uint_t x = *ip; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_map_elem_t *elem; + if (x < self->members.alloc && self->members.table[x].key == key) { + elem = &self->members.table[x]; + } else { + elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); + if (elem != NULL) { + *(byte*)ip = elem - &self->members.table[0]; + } else { + goto load_attr_cache_fail; + } + } + SET_TOP(elem->value); + ip++; + DISPATCH(); + } + load_attr_cache_fail: + SET_TOP(mp_load_attr(top, qst)); + ip++; + DISPATCH(); + } + #endif + + ENTRY(MP_BC_LOAD_METHOD): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_load_method(*sp, qst, sp); + sp += 1; + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_SUPER_METHOD): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + sp -= 1; + mp_load_super_method(qst, sp - 1); + DISPATCH(); + } + + ENTRY(MP_BC_LOAD_BUILD_CLASS): + MARK_EXC_IP_SELECTIVE(); + PUSH(mp_load_build_class()); + DISPATCH(); + + ENTRY(MP_BC_LOAD_SUBSCR): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t index = POP(); + SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL)); + DISPATCH(); + } + + ENTRY(MP_BC_STORE_FAST_N): { + DECODE_UINT; + fastn[-unum] = POP(); + DISPATCH(); + } + + ENTRY(MP_BC_STORE_DEREF): { + DECODE_UINT; + mp_obj_cell_set(fastn[-unum], POP()); + DISPATCH(); + } + + ENTRY(MP_BC_STORE_NAME): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_store_name(qst, POP()); + DISPATCH(); + } + + ENTRY(MP_BC_STORE_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_store_global(qst, POP()); + DISPATCH(); + } + + #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE + ENTRY(MP_BC_STORE_ATTR): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_store_attr(sp[0], qst, sp[-1]); + sp -= 2; + DISPATCH(); + } + #else + // This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or + // MICROPY_PY_DESCRIPTORS enabled because if the attr exists in + // self->members then it can't be a property or have descriptors. A + // consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND + // in the fast-path below, because that store could override a property. + ENTRY(MP_BC_STORE_ATTR): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t top = TOP(); + if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); + mp_uint_t x = *ip; + mp_obj_t key = MP_OBJ_NEW_QSTR(qst); + mp_map_elem_t *elem; + if (x < self->members.alloc && self->members.table[x].key == key) { + elem = &self->members.table[x]; + } else { + elem = mp_map_lookup(&self->members, key, MP_MAP_LOOKUP); + if (elem != NULL) { + *(byte*)ip = elem - &self->members.table[0]; + } else { + goto store_attr_cache_fail; + } + } + elem->value = sp[-1]; + sp -= 2; + ip++; + DISPATCH(); + } + store_attr_cache_fail: + mp_store_attr(sp[0], qst, sp[-1]); + sp -= 2; + ip++; + DISPATCH(); + } + #endif + + ENTRY(MP_BC_STORE_SUBSCR): + MARK_EXC_IP_SELECTIVE(); + mp_obj_subscr(sp[-1], sp[0], sp[-2]); + sp -= 3; + DISPATCH(); + + ENTRY(MP_BC_DELETE_FAST): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + if (fastn[-unum] == MP_OBJ_NULL) { + goto local_name_error; + } + fastn[-unum] = MP_OBJ_NULL; + DISPATCH(); + } + + ENTRY(MP_BC_DELETE_DEREF): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { + goto local_name_error; + } + mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL); + DISPATCH(); + } + + ENTRY(MP_BC_DELETE_NAME): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_delete_name(qst); + DISPATCH(); + } + + ENTRY(MP_BC_DELETE_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_delete_global(qst); + DISPATCH(); + } + + ENTRY(MP_BC_DUP_TOP): { + mp_obj_t top = TOP(); + PUSH(top); + DISPATCH(); + } + + ENTRY(MP_BC_DUP_TOP_TWO): + sp += 2; + sp[0] = sp[-2]; + sp[-1] = sp[-3]; + DISPATCH(); + + ENTRY(MP_BC_POP_TOP): + sp -= 1; + DISPATCH(); + + ENTRY(MP_BC_ROT_TWO): { + mp_obj_t top = sp[0]; + sp[0] = sp[-1]; + sp[-1] = top; + DISPATCH(); + } + + ENTRY(MP_BC_ROT_THREE): { + mp_obj_t top = sp[0]; + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = top; + DISPATCH(); + } + + ENTRY(MP_BC_JUMP): { + DECODE_SLABEL; + ip += slab; + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + ENTRY(MP_BC_POP_JUMP_IF_TRUE): { + DECODE_SLABEL; + if (mp_obj_is_true(POP())) { + ip += slab; + } + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + ENTRY(MP_BC_POP_JUMP_IF_FALSE): { + DECODE_SLABEL; + if (!mp_obj_is_true(POP())) { + ip += slab; + } + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP): { + DECODE_SLABEL; + if (mp_obj_is_true(TOP())) { + ip += slab; + } else { + sp--; + } + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP): { + DECODE_SLABEL; + if (mp_obj_is_true(TOP())) { + sp--; + } else { + ip += slab; + } + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + ENTRY(MP_BC_SETUP_WITH): { + MARK_EXC_IP_SELECTIVE(); + // stack: (..., ctx_mgr) + mp_obj_t obj = TOP(); + mp_load_method(obj, MP_QSTR___exit__, sp); + mp_load_method(obj, MP_QSTR___enter__, sp + 2); + mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 2); + sp += 1; + PUSH_EXC_BLOCK(1); + PUSH(ret); + // stack: (..., __exit__, ctx_mgr, as_value) + DISPATCH(); + } + + ENTRY(MP_BC_WITH_CLEANUP): { + MARK_EXC_IP_SELECTIVE(); + // Arriving here, there's "exception control block" on top of stack, + // and __exit__ method (with self) underneath it. Bytecode calls __exit__, + // and "deletes" it off stack, shifting "exception control block" + // to its place. + // The bytecode emitter ensures that there is enough space on the Python + // value stack to hold the __exit__ method plus an additional 4 entries. + if (TOP() == mp_const_none) { + // stack: (..., __exit__, ctx_mgr, None) + sp[1] = mp_const_none; + sp[2] = mp_const_none; + sp -= 2; + mp_call_method_n_kw(3, 0, sp); + SET_TOP(mp_const_none); + } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + // Getting here there are two distinct cases: + // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1)) + // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc)) + // For both cases we do exactly the same thing. + mp_obj_t data = sp[-1]; + mp_obj_t cause = sp[0]; + sp[-1] = mp_const_none; + sp[0] = mp_const_none; + sp[1] = mp_const_none; + mp_call_method_n_kw(3, 0, sp - 3); + sp[-3] = data; + sp[-2] = cause; + sp -= 2; // we removed (__exit__, ctx_mgr) + } else { + assert(mp_obj_is_exception_instance(TOP())); + // stack: (..., __exit__, ctx_mgr, exc_instance) + // Need to pass (exc_type, exc_instance, None) as arguments to __exit__. + sp[1] = sp[0]; + sp[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(sp[0])); + sp[2] = mp_const_none; + sp -= 2; + mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp); + if (mp_obj_is_true(ret_value)) { + // We need to silence/swallow the exception. This is done + // by popping the exception and the __exit__ handler and + // replacing it with None, which signals END_FINALLY to just + // execute the finally handler normally. + SET_TOP(mp_const_none); + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); + } else { + // We need to re-raise the exception. We pop __exit__ handler + // by copying the exception instance down to the new top-of-stack. + sp[0] = sp[3]; + } + } + DISPATCH(); + } + + ENTRY(MP_BC_UNWIND_JUMP): { + MARK_EXC_IP_SELECTIVE(); + DECODE_SLABEL; + PUSH((mp_obj_t)(mp_uint_t)(uintptr_t)(ip + slab)); // push destination ip for jump + PUSH((mp_obj_t)(mp_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack) +unwind_jump:; + mp_uint_t unum = (mp_uint_t)POP(); // get number of exception handlers to unwind + while ((unum & 0x7f) > 0) { + unum -= 1; + assert(exc_sp >= exc_stack); + if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { + // Getting here the stack looks like: + // (..., X, dest_ip) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on the stack so it can return back to us when it is + // done (when WITH_CLEANUP or END_FINALLY reached). + // The sentinel is the number of exception handlers left to + // unwind, which is a non-negative integer. + PUSH(MP_OBJ_NEW_SMALL_INT(unum)); + ip = exc_sp->handler; // get exception handler byte code address + exc_sp--; // pop exception handler + goto dispatch_loop; // run the exception handler + } + POP_EXC_BLOCK(); + } + ip = (const byte*)MP_OBJ_TO_PTR(POP()); // pop destination ip for jump + if (unum != 0) { + // pop the exhausted iterator + sp -= MP_OBJ_ITER_BUF_NSLOTS; + } + DISPATCH_WITH_PEND_EXC_CHECK(); + } + + // matched against: POP_BLOCK or POP_EXCEPT (anything else?) + ENTRY(MP_BC_SETUP_EXCEPT): + ENTRY(MP_BC_SETUP_FINALLY): { + MARK_EXC_IP_SELECTIVE(); + #if SELECTIVE_EXC_IP + PUSH_EXC_BLOCK((code_state->ip[-1] == MP_BC_SETUP_FINALLY) ? 1 : 0); + #else + PUSH_EXC_BLOCK((code_state->ip[0] == MP_BC_SETUP_FINALLY) ? 1 : 0); + #endif + DISPATCH(); + } + + ENTRY(MP_BC_END_FINALLY): + MARK_EXC_IP_SELECTIVE(); + // if TOS is None, just pops it and continues + // if TOS is an integer, finishes coroutine and returns control to caller + // if TOS is an exception, reraises the exception + if (TOP() == mp_const_none) { + sp--; + } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + // We finished "finally" coroutine and now dispatch back + // to our caller, based on TOS value + mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); + if (cause < 0) { + // A negative cause indicates unwind return + goto unwind_return; + } else { + // Otherwise it's an unwind jump and we must push as a raw + // number the number of exception handlers to unwind + PUSH((mp_obj_t)cause); + goto unwind_jump; + } + } else { + assert(mp_obj_is_exception_instance(TOP())); + RAISE(TOP()); + } + DISPATCH(); + + ENTRY(MP_BC_GET_ITER): + MARK_EXC_IP_SELECTIVE(); + SET_TOP(mp_getiter(TOP(), NULL)); + DISPATCH(); + + // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on + // the Python value stack. These slots are either used to store the + // iterator object itself, or the first slot is MP_OBJ_NULL and + // the second slot holds a reference to the iterator object. + ENTRY(MP_BC_GET_ITER_STACK): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = TOP(); + mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp; + sp += MP_OBJ_ITER_BUF_NSLOTS - 1; + obj = mp_getiter(obj, iter_buf); + if (obj != MP_OBJ_FROM_PTR(iter_buf)) { + // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. + sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL; + sp[-MP_OBJ_ITER_BUF_NSLOTS + 2] = obj; + } + DISPATCH(); + } + + ENTRY(MP_BC_FOR_ITER): { + MARK_EXC_IP_SELECTIVE(); + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + code_state->sp = sp; + mp_obj_t obj; + if (sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] == MP_OBJ_NULL) { + obj = sp[-MP_OBJ_ITER_BUF_NSLOTS + 2]; + } else { + obj = MP_OBJ_FROM_PTR(&sp[-MP_OBJ_ITER_BUF_NSLOTS + 1]); + } + mp_obj_t value = mp_iternext_allow_raise(obj); + if (value == MP_OBJ_STOP_ITERATION) { + sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator + ip += ulab; // jump to after for-block + } else { + PUSH(value); // push the next iteration value + } + DISPATCH(); + } + + // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH + ENTRY(MP_BC_POP_BLOCK): + // we are exiting an exception handler, so pop the last one of the exception-stack + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); + DISPATCH(); + + // matched against: SETUP_EXCEPT + ENTRY(MP_BC_POP_EXCEPT): + assert(exc_sp >= exc_stack); + assert(currently_in_except_block); + POP_EXC_BLOCK(); + DISPATCH(); + + ENTRY(MP_BC_BUILD_TUPLE): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_tuple(unum, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_BUILD_LIST): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_list(unum, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_BUILD_MAP): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + PUSH(mp_obj_new_dict(unum)); + DISPATCH(); + } + + ENTRY(MP_BC_STORE_MAP): + MARK_EXC_IP_SELECTIVE(); + sp -= 2; + mp_obj_dict_store(sp[0], sp[2], sp[1]); + DISPATCH(); + +#if MICROPY_PY_BUILTINS_SET + ENTRY(MP_BC_BUILD_SET): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_set(unum, sp)); + DISPATCH(); + } +#endif + +#if MICROPY_PY_BUILTINS_SLICE + ENTRY(MP_BC_BUILD_SLICE): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t step = mp_const_none; + if (*ip++ == 3) { + // 3-argument slice includes step + step = POP(); + } + mp_obj_t stop = POP(); + mp_obj_t start = TOP(); + SET_TOP(mp_obj_new_slice(start, stop, step)); + DISPATCH(); + } +#endif + + ENTRY(MP_BC_STORE_COMP): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + mp_obj_t obj = sp[-(unum >> 2)]; + if ((unum & 3) == 0) { + mp_obj_list_append(obj, sp[0]); + sp--; + } else if (!MICROPY_PY_BUILTINS_SET || (unum & 3) == 1) { + mp_obj_dict_store(obj, sp[0], sp[-1]); + sp -= 2; + #if MICROPY_PY_BUILTINS_SET + } else { + mp_obj_set_store(obj, sp[0]); + sp--; + #endif + } + DISPATCH(); + } + + ENTRY(MP_BC_UNPACK_SEQUENCE): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + mp_unpack_sequence(sp[0], unum, sp); + sp += unum - 1; + DISPATCH(); + } + + ENTRY(MP_BC_UNPACK_EX): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + mp_unpack_ex(sp[0], unum, sp); + sp += (unum & 0xff) + ((unum >> 8) & 0xff); + DISPATCH(); + } + + ENTRY(MP_BC_MAKE_FUNCTION): { + DECODE_PTR; + PUSH(mp_make_function_from_raw_code(ptr, MP_OBJ_NULL, MP_OBJ_NULL)); + DISPATCH(); + } + + ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): { + DECODE_PTR; + // Stack layout: def_tuple def_dict <- TOS + mp_obj_t def_dict = POP(); + SET_TOP(mp_make_function_from_raw_code(ptr, TOP(), def_dict)); + DISPATCH(); + } + + ENTRY(MP_BC_MAKE_CLOSURE): { + DECODE_PTR; + size_t n_closed_over = *ip++; + // Stack layout: closed_overs <- TOS + sp -= n_closed_over - 1; + SET_TOP(mp_make_closure_from_raw_code(ptr, n_closed_over, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): { + DECODE_PTR; + size_t n_closed_over = *ip++; + // Stack layout: def_tuple def_dict closed_overs <- TOS + sp -= 2 + n_closed_over - 1; + SET_TOP(mp_make_closure_from_raw_code(ptr, 0x100 | n_closed_over, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_CALL_FUNCTION): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); + #if MICROPY_STACKLESS + if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { + code_state->ip = ip; + code_state->sp = sp; + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + deep_recursion_error: + mp_raise_recursion_depth(); + #endif + } else + #endif + { + new_state->prev = code_state; + code_state = new_state; + nlr_pop(); + goto run_code_state; + } + } + #endif + SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); + DISPATCH(); + } + + ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have following stack layout here: + // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2; + #if MICROPY_STACKLESS + if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { + code_state->ip = ip; + code_state->sp = sp; + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + + mp_call_args_t out_args; + mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); + + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + out_args.n_args, out_args.n_kw, out_args.args); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { + new_state->prev = code_state; + code_state = new_state; + nlr_pop(); + goto run_code_state; + } + } + #endif + SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_CALL_METHOD): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; + #if MICROPY_STACKLESS + if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { + code_state->ip = ip; + code_state->sp = sp; + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + + size_t n_args = unum & 0xff; + size_t n_kw = (unum >> 8) & 0xff; + int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; + + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { + new_state->prev = code_state; + code_state = new_state; + nlr_pop(); + goto run_code_state; + } + } + #endif + SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_CALL_METHOD_VAR_KW): { + MARK_EXC_IP_SELECTIVE(); + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have following stack layout here: + // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3; + #if MICROPY_STACKLESS + if (mp_obj_get_type(*sp) == &mp_type_fun_bc) { + code_state->ip = ip; + code_state->sp = sp; + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + + mp_call_args_t out_args; + mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); + + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + out_args.n_args, out_args.n_kw, out_args.args); + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { + new_state->prev = code_state; + code_state = new_state; + nlr_pop(); + goto run_code_state; + } + } + #endif + SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); + DISPATCH(); + } + + ENTRY(MP_BC_RETURN_VALUE): + MARK_EXC_IP_SELECTIVE(); +unwind_return: + // Search for and execute finally handlers that aren't already active + while (exc_sp >= exc_stack) { + if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp)) { + // Found a finally handler that isn't active. + // Getting here the stack looks like: + // (..., X, [iter0, iter1, ...,] ret_val) + // where X is pointed to by exc_sp->val_sp and in the case + // of a "with" block contains the context manager info. + // There may be 0 or more for-iterators between X and the + // return value, and these must be removed before control can + // pass to the finally code. We simply copy the ret_value down + // over these iterators, if they exist. If they don't then the + // following is a null operation. + mp_obj_t *finally_sp = MP_TAGPTR_PTR(exc_sp->val_sp); + finally_sp[1] = sp[0]; + sp = &finally_sp[1]; + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on a stack so it can return back to us when it is + // done (when WITH_CLEANUP or END_FINALLY reached). + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); + ip = exc_sp->handler; + POP_EXC_BLOCK(); + goto dispatch_loop; + } + POP_EXC_BLOCK(); + } + nlr_pop(); + code_state->sp = sp; + assert(exc_sp == exc_stack - 1); + MICROPY_VM_HOOK_RETURN + #if MICROPY_STACKLESS + if (code_state->prev != NULL) { + mp_obj_t res = *sp; + mp_globals_set(code_state->old_globals); + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; + *code_state->sp = res; + goto run_code_state; + } + #endif + return MP_VM_RETURN_NORMAL; + + ENTRY(MP_BC_RAISE_VARARGS): { + MARK_EXC_IP_SELECTIVE(); + mp_uint_t unum = *ip; + mp_obj_t obj; + if (unum == 2) { + mp_warning("exception chaining not supported"); + // ignore (pop) "from" argument + sp--; + } + if (unum == 0) { + // search for the inner-most previous exception, to reraise it + obj = MP_OBJ_NULL; + for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { + if (e->prev_exc != NULL) { + obj = MP_OBJ_FROM_PTR(e->prev_exc); + break; + } + } + if (obj == MP_OBJ_NULL) { + obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "no active exception to reraise"); + RAISE(obj); + } + } else { + obj = TOP(); + } + obj = mp_make_raise_obj(obj); + RAISE(obj); + } + + ENTRY(MP_BC_YIELD_VALUE): +yield: + nlr_pop(); + code_state->ip = ip; + code_state->sp = sp; + code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + return MP_VM_RETURN_YIELD; + + ENTRY(MP_BC_YIELD_FROM): { + MARK_EXC_IP_SELECTIVE(); +//#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) +#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) +#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { mp_obj_t raise_t = mp_make_raise_obj(t); RAISE(raise_t); } + mp_vm_return_kind_t ret_kind; + mp_obj_t send_value = POP(); + mp_obj_t t_exc = MP_OBJ_NULL; + mp_obj_t ret_value; + code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration + if (inject_exc != MP_OBJ_NULL) { + t_exc = inject_exc; + inject_exc = MP_OBJ_NULL; + ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &ret_value); + } else { + ret_kind = mp_resume(TOP(), send_value, MP_OBJ_NULL, &ret_value); + } + + if (ret_kind == MP_VM_RETURN_YIELD) { + ip--; + PUSH(ret_value); + goto yield; + } else if (ret_kind == MP_VM_RETURN_NORMAL) { + // Pop exhausted gen + sp--; + if (ret_value == MP_OBJ_STOP_ITERATION) { + // Optimize StopIteration + // TODO: get StopIteration's value + PUSH(mp_const_none); + } else { + PUSH(ret_value); + } + + // If we injected GeneratorExit downstream, then even + // if it was swallowed, we re-raise GeneratorExit + GENERATOR_EXIT_IF_NEEDED(t_exc); + DISPATCH(); + } else { + assert(ret_kind == MP_VM_RETURN_EXCEPTION); + // Pop exhausted gen + sp--; + if (EXC_MATCH(ret_value, MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + PUSH(mp_obj_exception_get_value(ret_value)); + // If we injected GeneratorExit downstream, then even + // if it was swallowed, we re-raise GeneratorExit + GENERATOR_EXIT_IF_NEEDED(t_exc); + DISPATCH(); + } else { + RAISE(ret_value); + } + } + } + + ENTRY(MP_BC_IMPORT_NAME): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t obj = POP(); + SET_TOP(mp_import_name(qst, obj, TOP())); + DISPATCH(); + } + + ENTRY(MP_BC_IMPORT_FROM): { + MARK_EXC_IP_SELECTIVE(); + DECODE_QSTR; + mp_obj_t obj = mp_import_from(TOP(), qst); + PUSH(obj); + DISPATCH(); + } + + ENTRY(MP_BC_IMPORT_STAR): + MARK_EXC_IP_SELECTIVE(); + mp_import_all(POP()); + DISPATCH(); + +#if MICROPY_OPT_COMPUTED_GOTO + ENTRY(MP_BC_LOAD_CONST_SMALL_INT_MULTI): + PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_FAST_MULTI): + obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]]; + goto load_check; + + ENTRY(MP_BC_STORE_FAST_MULTI): + fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP(); + DISPATCH(); + + ENTRY(MP_BC_UNARY_OP_MULTI): + MARK_EXC_IP_SELECTIVE(); + SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); + DISPATCH(); + + ENTRY(MP_BC_BINARY_OP_MULTI): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t rhs = POP(); + mp_obj_t lhs = TOP(); + SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); + DISPATCH(); + } + + ENTRY_DEFAULT: + MARK_EXC_IP_SELECTIVE(); +#else + ENTRY_DEFAULT: + if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { + PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16)); + DISPATCH(); + } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { + obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]]; + goto load_check; + } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { + fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP(); + DISPATCH(); + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { + SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); + DISPATCH(); + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { + mp_obj_t rhs = POP(); + mp_obj_t lhs = TOP(); + SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); + DISPATCH(); + } else +#endif + { + mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); + nlr_pop(); + fastn[0] = obj; + return MP_VM_RETURN_EXCEPTION; + } + +#if !MICROPY_OPT_COMPUTED_GOTO + } // switch +#endif + +pending_exception_check: + MICROPY_VM_HOOK_LOOP + + #if MICROPY_ENABLE_SCHEDULER + // This is an inlined variant of mp_handle_pending + if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + MARK_EXC_IP_SELECTIVE(); + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + if (obj != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + if (!mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + RAISE(obj); + } + mp_handle_pending_tail(atomic_state); + } + #else + // This is an inlined variant of mp_handle_pending + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + RAISE(obj); + } + #endif + + #if MICROPY_PY_THREAD_GIL + #if MICROPY_PY_THREAD_GIL_VM_DIVISOR + if (--gil_divisor == 0) + #endif + { + #if MICROPY_PY_THREAD_GIL_VM_DIVISOR + gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #endif + #if MICROPY_ENABLE_SCHEDULER + // can only switch threads if the scheduler is unlocked + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) + #endif + { + MP_THREAD_GIL_EXIT(); + MP_THREAD_GIL_ENTER(); + } + } + #endif + + } // for loop + + } else { +exception_handler: + // exception occurred + + #if MICROPY_PY_SYS_EXC_INFO + MP_STATE_VM(cur_exception) = nlr.ret_val; + #endif + + #if SELECTIVE_EXC_IP + // with selective ip, we store the ip 1 byte past the opcode, so move ptr back + code_state->ip -= 1; + #endif + + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) { + if (code_state->ip) { + // check if it's a StopIteration within a for block + if (*code_state->ip == MP_BC_FOR_ITER) { + const byte *ip = code_state->ip + 1; + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + code_state->ip = ip + ulab; // jump to after for-block + code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator + goto outer_dispatch_loop; // continue with dispatch loop + } else if (*code_state->ip == MP_BC_YIELD_FROM) { + // StopIteration inside yield from call means return a value of + // yield from, so inject exception's value as yield from's result + // (Instead of stack pop then push we just replace exhausted gen with value) + *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + code_state->ip++; // yield from is over, move to next instruction + goto outer_dispatch_loop; // continue with dispatch loop + } + } + } + +#if MICROPY_STACKLESS +unwind_loop: +#endif + // set file and line number that the exception occurred at + // TODO: don't set traceback for exceptions re-raised by END_FINALLY. + // But consider how to handle nested exceptions. + if (nlr.ret_val != &mp_const_GeneratorExit_obj) { + const byte *ip = code_state->fun_bc->bytecode; + ip = mp_decode_uint_skip(ip); // skip n_state + ip = mp_decode_uint_skip(ip); // skip n_exc_stack + ip++; // skip scope_params + ip++; // skip n_pos_args + ip++; // skip n_kwonly_args + ip++; // skip n_def_pos_args + size_t bc = code_state->ip - ip; + size_t code_info_size = mp_decode_uint_value(ip); + ip = mp_decode_uint_skip(ip); // skip code_info_size + bc -= code_info_size; + #if MICROPY_PERSISTENT_CODE + qstr block_name = ip[0] | (ip[1] << 8); + qstr source_file = ip[2] | (ip[3] << 8); + ip += 4; + #else + qstr block_name = mp_decode_uint_value(ip); + ip = mp_decode_uint_skip(ip); + qstr source_file = mp_decode_uint_value(ip); + ip = mp_decode_uint_skip(ip); + #endif + size_t source_line = 1; + size_t c; + while ((c = *ip)) { + size_t b, l; + if ((c & 0x80) == 0) { + // 0b0LLBBBBB encoding + b = c & 0x1f; + l = c >> 5; + ip += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + b = c & 0xf; + l = ((c << 4) & 0x700) | ip[1]; + ip += 2; + } + if (bc >= b) { + bc -= b; + source_line += l; + } else { + // found source line corresponding to bytecode offset + break; + } + } + mp_obj_exception_add_traceback(MP_OBJ_FROM_PTR(nlr.ret_val), source_file, source_line, block_name); + } + + while (currently_in_except_block) { + // nested exception + + assert(exc_sp >= exc_stack); + + // TODO make a proper message for nested exception + // at the moment we are just raising the very last exception (the one that caused the nested exception) + + // move up to previous exception handler + POP_EXC_BLOCK(); + } + + if (exc_sp >= exc_stack) { + // set flag to indicate that we are now handling an exception + currently_in_except_block = 1; + + // catch exception and pass to byte code + code_state->ip = exc_sp->handler; + mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); + // save this exception in the stack so it can be used in a reraise, if needed + exc_sp->prev_exc = nlr.ret_val; + // push exception object so it can be handled by bytecode + PUSH(MP_OBJ_FROM_PTR(nlr.ret_val)); + code_state->sp = sp; + + #if MICROPY_STACKLESS + } else if (code_state->prev != NULL) { + mp_globals_set(code_state->old_globals); + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; + size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + fastn = &code_state->state[n_state - 1]; + exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); + // variables that are visible to the exception handler (declared volatile) + currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions + exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack + goto unwind_loop; + + #endif + } else { + // propagate exception to higher level + // Note: ip and sp don't have usable values at this point + code_state->state[0] = MP_OBJ_FROM_PTR(nlr.ret_val); // put exception here because sp is invalid + return MP_VM_RETURN_EXCEPTION; + } + } + } +} diff --git a/src/openmv/src/micropython/py/vmentrytable.h b/src/openmv/src/micropython/py/vmentrytable.h new file mode 100755 index 0000000..615f4e2 --- /dev/null +++ b/src/openmv/src/micropython/py/vmentrytable.h @@ -0,0 +1,118 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winitializer-overrides" +#endif // __clang__ + +static const void *const entry_table[256] = { + [0 ... 255] = &&entry_default, + [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE, + [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE, + [MP_BC_LOAD_CONST_TRUE] = &&entry_MP_BC_LOAD_CONST_TRUE, + [MP_BC_LOAD_CONST_SMALL_INT] = &&entry_MP_BC_LOAD_CONST_SMALL_INT, + [MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING, + [MP_BC_LOAD_CONST_OBJ] = &&entry_MP_BC_LOAD_CONST_OBJ, + [MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL, + [MP_BC_LOAD_FAST_N] = &&entry_MP_BC_LOAD_FAST_N, + [MP_BC_LOAD_DEREF] = &&entry_MP_BC_LOAD_DEREF, + [MP_BC_LOAD_NAME] = &&entry_MP_BC_LOAD_NAME, + [MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL, + [MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR, + [MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD, + [MP_BC_LOAD_SUPER_METHOD] = &&entry_MP_BC_LOAD_SUPER_METHOD, + [MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS, + [MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR, + [MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N, + [MP_BC_STORE_DEREF] = &&entry_MP_BC_STORE_DEREF, + [MP_BC_STORE_NAME] = &&entry_MP_BC_STORE_NAME, + [MP_BC_STORE_GLOBAL] = &&entry_MP_BC_STORE_GLOBAL, + [MP_BC_STORE_ATTR] = &&entry_MP_BC_STORE_ATTR, + [MP_BC_STORE_SUBSCR] = &&entry_MP_BC_STORE_SUBSCR, + [MP_BC_DELETE_FAST] = &&entry_MP_BC_DELETE_FAST, + [MP_BC_DELETE_DEREF] = &&entry_MP_BC_DELETE_DEREF, + [MP_BC_DELETE_NAME] = &&entry_MP_BC_DELETE_NAME, + [MP_BC_DELETE_GLOBAL] = &&entry_MP_BC_DELETE_GLOBAL, + [MP_BC_DUP_TOP] = &&entry_MP_BC_DUP_TOP, + [MP_BC_DUP_TOP_TWO] = &&entry_MP_BC_DUP_TOP_TWO, + [MP_BC_POP_TOP] = &&entry_MP_BC_POP_TOP, + [MP_BC_ROT_TWO] = &&entry_MP_BC_ROT_TWO, + [MP_BC_ROT_THREE] = &&entry_MP_BC_ROT_THREE, + [MP_BC_JUMP] = &&entry_MP_BC_JUMP, + [MP_BC_POP_JUMP_IF_TRUE] = &&entry_MP_BC_POP_JUMP_IF_TRUE, + [MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE, + [MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP, + [MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP, + [MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH, + [MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP, + [MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP, + [MP_BC_SETUP_EXCEPT] = &&entry_MP_BC_SETUP_EXCEPT, + [MP_BC_SETUP_FINALLY] = &&entry_MP_BC_SETUP_FINALLY, + [MP_BC_END_FINALLY] = &&entry_MP_BC_END_FINALLY, + [MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER, + [MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK, + [MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER, + [MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK, + [MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT, + [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE, + [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST, + [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP, + [MP_BC_STORE_MAP] = &&entry_MP_BC_STORE_MAP, + #if MICROPY_PY_BUILTINS_SET + [MP_BC_BUILD_SET] = &&entry_MP_BC_BUILD_SET, + #endif + #if MICROPY_PY_BUILTINS_SLICE + [MP_BC_BUILD_SLICE] = &&entry_MP_BC_BUILD_SLICE, + #endif + [MP_BC_STORE_COMP] = &&entry_MP_BC_STORE_COMP, + [MP_BC_UNPACK_SEQUENCE] = &&entry_MP_BC_UNPACK_SEQUENCE, + [MP_BC_UNPACK_EX] = &&entry_MP_BC_UNPACK_EX, + [MP_BC_MAKE_FUNCTION] = &&entry_MP_BC_MAKE_FUNCTION, + [MP_BC_MAKE_FUNCTION_DEFARGS] = &&entry_MP_BC_MAKE_FUNCTION_DEFARGS, + [MP_BC_MAKE_CLOSURE] = &&entry_MP_BC_MAKE_CLOSURE, + [MP_BC_MAKE_CLOSURE_DEFARGS] = &&entry_MP_BC_MAKE_CLOSURE_DEFARGS, + [MP_BC_CALL_FUNCTION] = &&entry_MP_BC_CALL_FUNCTION, + [MP_BC_CALL_FUNCTION_VAR_KW] = &&entry_MP_BC_CALL_FUNCTION_VAR_KW, + [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD, + [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW, + [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE, + [MP_BC_RAISE_VARARGS] = &&entry_MP_BC_RAISE_VARARGS, + [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE, + [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM, + [MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME, + [MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM, + [MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR, + [MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI, + [MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI, + [MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI, + [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI, + [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI, +}; + +#if __clang__ +#pragma clang diagnostic pop +#endif // __clang__ diff --git a/src/openmv/src/micropython/py/vstr.c b/src/openmv/src/micropython/py/vstr.c new file mode 100755 index 0000000..869b278 --- /dev/null +++ b/src/openmv/src/micropython/py/vstr.c @@ -0,0 +1,245 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/mpconfig.h" +#include "py/runtime.h" +#include "py/mpprint.h" + +// returned value is always at least 1 greater than argument +#define ROUND_ALLOC(a) (((a) & ((~0U) - 7)) + 8) + +// Init the vstr so it allocs exactly given number of bytes. Set length to zero. +void vstr_init(vstr_t *vstr, size_t alloc) { + if (alloc < 1) { + alloc = 1; + } + vstr->alloc = alloc; + vstr->len = 0; + vstr->buf = m_new(char, vstr->alloc); + vstr->fixed_buf = false; +} + +// Init the vstr so it allocs exactly enough ram to hold a null-terminated +// string of the given length, and set the length. +void vstr_init_len(vstr_t *vstr, size_t len) { + vstr_init(vstr, len + 1); + vstr->len = len; +} + +void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf) { + vstr->alloc = alloc; + vstr->len = 0; + vstr->buf = buf; + vstr->fixed_buf = true; +} + +void vstr_init_print(vstr_t *vstr, size_t alloc, mp_print_t *print) { + vstr_init(vstr, alloc); + print->data = vstr; + print->print_strn = (mp_print_strn_t)vstr_add_strn; +} + +void vstr_clear(vstr_t *vstr) { + if (!vstr->fixed_buf) { + m_del(char, vstr->buf, vstr->alloc); + } + vstr->buf = NULL; +} + +vstr_t *vstr_new(size_t alloc) { + vstr_t *vstr = m_new_obj(vstr_t); + vstr_init(vstr, alloc); + return vstr; +} + +void vstr_free(vstr_t *vstr) { + if (vstr != NULL) { + if (!vstr->fixed_buf) { + m_del(char, vstr->buf, vstr->alloc); + } + m_del_obj(vstr_t, vstr); + } +} + +// Extend vstr strictly by requested size, return pointer to newly added chunk. +char *vstr_extend(vstr_t *vstr, size_t size) { + if (vstr->fixed_buf) { + // We can't reallocate, and the caller is expecting the space to + // be there, so the only safe option is to raise an exception. + mp_raise_msg(&mp_type_RuntimeError, NULL); + } + char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size); + char *p = new_buf + vstr->alloc; + vstr->alloc += size; + vstr->buf = new_buf; + return p; +} + +STATIC void vstr_ensure_extra(vstr_t *vstr, size_t size) { + if (vstr->len + size > vstr->alloc) { + if (vstr->fixed_buf) { + // We can't reallocate, and the caller is expecting the space to + // be there, so the only safe option is to raise an exception. + mp_raise_msg(&mp_type_RuntimeError, NULL); + } + size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16); + char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); + vstr->alloc = new_alloc; + vstr->buf = new_buf; + } +} + +void vstr_hint_size(vstr_t *vstr, size_t size) { + vstr_ensure_extra(vstr, size); +} + +char *vstr_add_len(vstr_t *vstr, size_t len) { + vstr_ensure_extra(vstr, len); + char *buf = vstr->buf + vstr->len; + vstr->len += len; + return buf; +} + +// Doesn't increase len, just makes sure there is a null byte at the end +char *vstr_null_terminated_str(vstr_t *vstr) { + // If there's no more room, add single byte + if (vstr->alloc == vstr->len) { + vstr_extend(vstr, 1); + } + vstr->buf[vstr->len] = '\0'; + return vstr->buf; +} + +void vstr_add_byte(vstr_t *vstr, byte b) { + byte *buf = (byte*)vstr_add_len(vstr, 1); + buf[0] = b; +} + +void vstr_add_char(vstr_t *vstr, unichar c) { +#if MICROPY_PY_BUILTINS_STR_UNICODE + // TODO: Can this be simplified and deduplicated? + // Is it worth just calling vstr_add_len(vstr, 4)? + if (c < 0x80) { + byte *buf = (byte*)vstr_add_len(vstr, 1); + *buf = (byte)c; + } else if (c < 0x800) { + byte *buf = (byte*)vstr_add_len(vstr, 2); + buf[0] = (c >> 6) | 0xC0; + buf[1] = (c & 0x3F) | 0x80; + } else if (c < 0x10000) { + byte *buf = (byte*)vstr_add_len(vstr, 3); + buf[0] = (c >> 12) | 0xE0; + buf[1] = ((c >> 6) & 0x3F) | 0x80; + buf[2] = (c & 0x3F) | 0x80; + } else { + assert(c < 0x110000); + byte *buf = (byte*)vstr_add_len(vstr, 4); + buf[0] = (c >> 18) | 0xF0; + buf[1] = ((c >> 12) & 0x3F) | 0x80; + buf[2] = ((c >> 6) & 0x3F) | 0x80; + buf[3] = (c & 0x3F) | 0x80; + } +#else + vstr_add_byte(vstr, c); +#endif +} + +void vstr_add_str(vstr_t *vstr, const char *str) { + vstr_add_strn(vstr, str, strlen(str)); +} + +void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) { + vstr_ensure_extra(vstr, len); + memmove(vstr->buf + vstr->len, str, len); + vstr->len += len; +} + +STATIC char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) { + size_t l = vstr->len; + if (byte_pos > l) { + byte_pos = l; + } + if (byte_len > 0) { + // ensure room for the new bytes + vstr_ensure_extra(vstr, byte_len); + // copy up the string to make room for the new bytes + memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos); + // increase the length + vstr->len += byte_len; + } + return vstr->buf + byte_pos; +} + +void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) { + char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1); + *s = b; +} + +void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) { + // TODO UNICODE + char *s = vstr_ins_blank_bytes(vstr, char_pos, 1); + *s = chr; +} + +void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) { + vstr_cut_out_bytes(vstr, 0, bytes_to_cut); +} + +void vstr_cut_tail_bytes(vstr_t *vstr, size_t len) { + if (len > vstr->len) { + vstr->len = 0; + } else { + vstr->len -= len; + } +} + +void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut) { + if (byte_pos >= vstr->len) { + return; + } else if (byte_pos + bytes_to_cut >= vstr->len) { + vstr->len = byte_pos; + } else { + memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut); + vstr->len -= bytes_to_cut; + } +} + +void vstr_printf(vstr_t *vstr, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vstr_vprintf(vstr, fmt, ap); + va_end(ap); +} + +void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap) { + mp_print_t print = {vstr, (mp_print_strn_t)vstr_add_strn}; + mp_vprintf(&print, fmt, ap); +} diff --git a/src/openmv/src/micropython/py/warning.c b/src/openmv/src/micropython/py/warning.c new file mode 100755 index 0000000..12d0f9c --- /dev/null +++ b/src/openmv/src/micropython/py/warning.c @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/emit.h" +#include "py/runtime.h" + +#if MICROPY_WARNINGS + +void mp_warning(const char *msg, ...) { + va_list args; + va_start(args, msg); + mp_print_str(MICROPY_ERROR_PRINTER, "Warning: "); + mp_vprintf(MICROPY_ERROR_PRINTER, msg, args); + mp_print_str(MICROPY_ERROR_PRINTER, "\n"); + va_end(args); +} + +void mp_emitter_warning(pass_kind_t pass, const char *msg) { + if (pass == MP_PASS_CODE_SIZE) { + mp_warning(msg, NULL); + } +} + +#endif // MICROPY_WARNINGS diff --git a/src/openmv/src/micropython/tests/README b/src/openmv/src/micropython/tests/README new file mode 100755 index 0000000..3458f36 --- /dev/null +++ b/src/openmv/src/micropython/tests/README @@ -0,0 +1,18 @@ +This directory contains tests for various functionality areas of MicroPython. +To run all stable tests, run "run-tests" script in this directory. + +Tests of capabilities not supported on all platforms should be written +to check for the capability being present. If it is not, the test +should merely output 'SKIP' followed by the line terminator, and call +sys.exit() to raise SystemExit, instead of attempting to test the +missing capability. The testing framework (run-tests in this +directory, test_main.c in qemu_arm) recognizes this as a skipped test. + +There are a few features for which this mechanism cannot be used to +condition a test. The run-tests script uses small scripts in the +feature_check directory to check whether each such feature is present, +and skips the relevant tests if not. + +When creating new tests, anything that relies on float support should go in the +float/ subdirectory. Anything that relies on import x, where x is not a built-in +module, should go in the import/ subdirectory. diff --git a/src/openmv/src/micropython/tests/basics/0prelim.py b/src/openmv/src/micropython/tests/basics/0prelim.py new file mode 100755 index 0000000..2da65dc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/0prelim.py @@ -0,0 +1,4 @@ +# all tests need print to work! make sure it does work + +print(1) +print('abc') diff --git a/src/openmv/src/micropython/tests/basics/andor.py b/src/openmv/src/micropython/tests/basics/andor.py new file mode 100755 index 0000000..4deddaf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/andor.py @@ -0,0 +1,5 @@ +# test short circuit expressions outside if conditionals +print(() or 1) +print((1,) or 1) +print(() and 1) +print((1,) and 1) diff --git a/src/openmv/src/micropython/tests/basics/array1.py b/src/openmv/src/micropython/tests/basics/array1.py new file mode 100755 index 0000000..bad8790 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array1.py @@ -0,0 +1,36 @@ +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +a = array.array('B', [1, 2, 3]) +print(a, len(a)) +i = array.array('I', [1, 2, 3]) +print(i, len(i)) +print(a[0]) +print(i[-1]) +a = array.array('l', [-1]) +print(len(a), a[0]) +a1 = array.array('l', [1, 2, 3]) +a2 = array.array('L', [1, 2, 3]) +print(a2[1]) +print(a1 == a2) + +# Empty arrays +print(len(array.array('h'))) +print(array.array('i')) + +# bool operator acting on arrays +print(bool(array.array('i'))) +print(bool(array.array('i', [1]))) + +# containment, with incorrect type +print('12' in array.array('B', b'12')) +print([] in array.array('B', b'12')) + +# bad typecode +try: + array.array('X') +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/array_add.py b/src/openmv/src/micropython/tests/basics/array_add.py new file mode 100755 index 0000000..76ce59f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_add.py @@ -0,0 +1,16 @@ +# test array + array +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +a1 = array.array('I', [1]) +a2 = array.array('I', [2]) +print(a1 + a2) + +a1 += array.array('I', [3, 4]) +print(a1) + +a1.extend(array.array('I', [5])) +print(a1) diff --git a/src/openmv/src/micropython/tests/basics/array_construct.py b/src/openmv/src/micropython/tests/basics/array_construct.py new file mode 100755 index 0000000..2221de9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_construct.py @@ -0,0 +1,20 @@ +# test construction of array.array from different objects + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# tuple, list +print(array('b', (1, 2))) +print(array('h', [1, 2])) + +# raw copy from bytes, bytearray +print(array('h', b'22')) # should be byteorder-neutral +print(array('h', bytearray(2))) +print(array('i', bytearray(4))) + +# convert from other arrays +print(array('H', array('b', [1, 2]))) +print(array('b', array('I', [1, 2]))) diff --git a/src/openmv/src/micropython/tests/basics/array_construct2.py b/src/openmv/src/micropython/tests/basics/array_construct2.py new file mode 100755 index 0000000..c305b7f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_construct2.py @@ -0,0 +1,8 @@ +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# construct from something with unknown length (requires generators) +print(array('i', (i for i in range(10)))) diff --git a/src/openmv/src/micropython/tests/basics/array_construct_endian.py b/src/openmv/src/micropython/tests/basics/array_construct_endian.py new file mode 100755 index 0000000..990d7b1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_construct_endian.py @@ -0,0 +1,10 @@ +# test construction of array.array from different objects + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# raw copy from bytes, bytearray +print(array('h', b'12')) diff --git a/src/openmv/src/micropython/tests/basics/array_intbig.py b/src/openmv/src/micropython/tests/basics/array_intbig.py new file mode 100755 index 0000000..5702a8a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_intbig.py @@ -0,0 +1,22 @@ +# test array types QqLl that require big-ints + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +print(array('L', [0, 2**32-1])) +print(array('l', [-2**31, 0, 2**31-1])) + +print(array('q')) +print(array('Q')) + +print(array('q', [0])) +print(array('Q', [0])) + +print(array('q', [-2**63, -1, 0, 1, 2, 2**63-1])) +print(array('Q', [0, 1, 2, 2**64-1])) + +print(bytes(array('q', [-1]))) +print(bytes(array('Q', [2**64-1]))) diff --git a/src/openmv/src/micropython/tests/basics/array_micropython.py b/src/openmv/src/micropython/tests/basics/array_micropython.py new file mode 100755 index 0000000..e26ad7a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_micropython.py @@ -0,0 +1,16 @@ +# test MicroPython-specific features of array.array +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +# arrays of objects +a = array.array('O') +a.append(1) +print(a[0]) + +# arrays of pointers +a = array.array('P') +a.append(1) +print(a[0]) diff --git a/src/openmv/src/micropython/tests/basics/array_micropython.py.exp b/src/openmv/src/micropython/tests/basics/array_micropython.py.exp new file mode 100755 index 0000000..6ed281c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/array_micropython.py.exp @@ -0,0 +1,2 @@ +1 +1 diff --git a/src/openmv/src/micropython/tests/basics/assign1.py b/src/openmv/src/micropython/tests/basics/assign1.py new file mode 100755 index 0000000..118747f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/assign1.py @@ -0,0 +1,11 @@ +# test assignments + +a = 1 +print(a) + +a = b = 2 +print(a, b) + +a = b = c = 3 +print(a, b, c) + diff --git a/src/openmv/src/micropython/tests/basics/async_await.py b/src/openmv/src/micropython/tests/basics/async_await.py new file mode 100755 index 0000000..23b3ba9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_await.py @@ -0,0 +1,17 @@ +# test basic await expression +# adapted from PEP0492 + +async def abinary(n): + print(n) + if n <= 0: + return 1 + l = await abinary(n - 1) + r = await abinary(n - 1) + return l + 1 + r + +o = abinary(4) +try: + while True: + o.send(None) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_await.py.exp b/src/openmv/src/micropython/tests/basics/async_await.py.exp new file mode 100755 index 0000000..b51c388 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_await.py.exp @@ -0,0 +1,32 @@ +4 +3 +2 +1 +0 +0 +1 +0 +0 +2 +1 +0 +0 +1 +0 +0 +3 +2 +1 +0 +0 +1 +0 +0 +2 +1 +0 +0 +1 +0 +0 +finished diff --git a/src/openmv/src/micropython/tests/basics/async_await2.py b/src/openmv/src/micropython/tests/basics/async_await2.py new file mode 100755 index 0000000..129d375 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_await2.py @@ -0,0 +1,27 @@ +# test await expression + +import sys +if sys.implementation.name == 'micropython': + # uPy allows normal generators to be awaitables + coroutine = lambda f: f +else: + import types + coroutine = types.coroutine + +@coroutine +def wait(value): + print('wait value:', value) + msg = yield 'message from wait(%u)' % value + print('wait got back:', msg) + return 10 + +async def f(): + x = await wait(1)**2 + print('x =', x) + +coro = f() +print('return from send:', coro.send(None)) +try: + coro.send('message from main') +except StopIteration: + print('got StopIteration') diff --git a/src/openmv/src/micropython/tests/basics/async_await2.py.exp b/src/openmv/src/micropython/tests/basics/async_await2.py.exp new file mode 100755 index 0000000..fc9ff0a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_await2.py.exp @@ -0,0 +1,5 @@ +wait value: 1 +return from send: message from wait(1) +wait got back: message from main +x = 100 +got StopIteration diff --git a/src/openmv/src/micropython/tests/basics/async_def.py b/src/openmv/src/micropython/tests/basics/async_def.py new file mode 100755 index 0000000..e345703 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_def.py @@ -0,0 +1,16 @@ +# test async def + +def dec(f): + print('decorator') + return f + +# test definition with a decorator +@dec +async def foo(): + print('foo') + +coro = foo() +try: + coro.send(None) +except StopIteration: + print('StopIteration') diff --git a/src/openmv/src/micropython/tests/basics/async_def.py.exp b/src/openmv/src/micropython/tests/basics/async_def.py.exp new file mode 100755 index 0000000..f555ace --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_def.py.exp @@ -0,0 +1,3 @@ +decorator +foo +StopIteration diff --git a/src/openmv/src/micropython/tests/basics/async_for.py b/src/openmv/src/micropython/tests/basics/async_for.py new file mode 100755 index 0000000..6b4e136 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_for.py @@ -0,0 +1,29 @@ +# test basic async for execution +# example taken from PEP0492 + +class AsyncIteratorWrapper: + def __init__(self, obj): + print('init') + self._it = iter(obj) + + async def __aiter__(self): + print('aiter') + return self + + async def __anext__(self): + print('anext') + try: + value = next(self._it) + except StopIteration: + raise StopAsyncIteration + return value + +async def coro(): + async for letter in AsyncIteratorWrapper('abc'): + print(letter) + +o = coro() +try: + o.send(None) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_for.py.exp b/src/openmv/src/micropython/tests/basics/async_for.py.exp new file mode 100755 index 0000000..1f728a6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_for.py.exp @@ -0,0 +1,10 @@ +init +aiter +anext +a +anext +b +anext +c +anext +finished diff --git a/src/openmv/src/micropython/tests/basics/async_for2.py b/src/openmv/src/micropython/tests/basics/async_for2.py new file mode 100755 index 0000000..89584fc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_for2.py @@ -0,0 +1,48 @@ +# test waiting within "async for" aiter/anext functions + +import sys +if sys.implementation.name == 'micropython': + # uPy allows normal generators to be awaitables + coroutine = lambda f: f +else: + import types + coroutine = types.coroutine + +@coroutine +def f(x): + print('f start:', x) + yield x + 1 + yield x + 2 + return x + 3 + +class ARange: + def __init__(self, high): + print('init') + self.cur = 0 + self.high = high + + async def __aiter__(self): + print('aiter') + print('f returned:', await f(10)) + return self + + async def __anext__(self): + print('anext') + print('f returned:', await f(20)) + if self.cur < self.high: + val = self.cur + self.cur += 1 + return val + else: + raise StopAsyncIteration + +async def coro(): + async for x in ARange(4): + print('x', x) + +o = coro() +try: + while True: + print('coro yielded:', o.send(None)) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_for2.py.exp b/src/openmv/src/micropython/tests/basics/async_for2.py.exp new file mode 100755 index 0000000..886232f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_for2.py.exp @@ -0,0 +1,36 @@ +init +aiter +f start: 10 +coro yielded: 11 +coro yielded: 12 +f returned: 13 +anext +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +x 0 +anext +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +x 1 +anext +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +x 2 +anext +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +x 3 +anext +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +finished diff --git a/src/openmv/src/micropython/tests/basics/async_with.py b/src/openmv/src/micropython/tests/basics/async_with.py new file mode 100755 index 0000000..5af0c5d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with.py @@ -0,0 +1,29 @@ +# test simple async with execution + +class AContext: + async def __aenter__(self): + print('enter') + return 1 + async def __aexit__(self, exc_type, exc, tb): + print('exit', exc_type, exc) + +async def f(): + async with AContext(): + print('body') + +o = f() +try: + o.send(None) +except StopIteration: + print('finished') + +async def g(): + async with AContext() as ac: + print(ac) + raise ValueError('error') + +o = g() +try: + o.send(None) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/async_with.py.exp b/src/openmv/src/micropython/tests/basics/async_with.py.exp new file mode 100755 index 0000000..d00b18c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with.py.exp @@ -0,0 +1,8 @@ +enter +body +exit None None +finished +enter +1 +exit error +ValueError diff --git a/src/openmv/src/micropython/tests/basics/async_with2.py b/src/openmv/src/micropython/tests/basics/async_with2.py new file mode 100755 index 0000000..44421ae --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with2.py @@ -0,0 +1,37 @@ +# test waiting within async with enter/exit functions + +import sys +if sys.implementation.name == 'micropython': + # uPy allows normal generators to be awaitables + coroutine = lambda f: f +else: + import types + coroutine = types.coroutine + +@coroutine +def f(x): + print('f start:', x) + yield x + 1 + yield x + 2 + return x + 3 + +class AContext: + async def __aenter__(self): + print('enter') + print('f returned:', await f(10)) + async def __aexit__(self, exc_type, exc, tb): + print('exit', exc_type, exc) + print('f returned:', await f(20)) + +async def coro(): + async with AContext(): + print('body start') + print('body f returned:', await f(30)) + print('body end') + +o = coro() +try: + while True: + print('coro yielded:', o.send(None)) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_with2.py.exp b/src/openmv/src/micropython/tests/basics/async_with2.py.exp new file mode 100755 index 0000000..76b173b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with2.py.exp @@ -0,0 +1,17 @@ +enter +f start: 10 +coro yielded: 11 +coro yielded: 12 +f returned: 13 +body start +f start: 30 +coro yielded: 31 +coro yielded: 32 +body f returned: 33 +body end +exit None None +f start: 20 +coro yielded: 21 +coro yielded: 22 +f returned: 23 +finished diff --git a/src/openmv/src/micropython/tests/basics/async_with_break.py b/src/openmv/src/micropython/tests/basics/async_with_break.py new file mode 100755 index 0000000..39bcbcc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with_break.py @@ -0,0 +1,59 @@ +# test async with, escaped by a break + +class AContext: + async def __aenter__(self): + print('enter') + return 1 + async def __aexit__(self, exc_type, exc, tb): + print('exit', exc_type, exc) + +async def f1(): + while 1: + async with AContext(): + print('body') + break + print('no 1') + print('no 2') + +o = f1() +try: + print(o.send(None)) +except StopIteration: + print('finished') + +async def f2(): + while 1: + try: + async with AContext(): + print('body') + break + print('no 1') + finally: + print('finally') + print('no 2') + +o = f2() +try: + print(o.send(None)) +except StopIteration: + print('finished') + +async def f3(): + while 1: + try: + try: + async with AContext(): + print('body') + break + print('no 1') + finally: + print('finally inner') + finally: + print('finally outer') + print('no 2') + +o = f3() +try: + print(o.send(None)) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_with_break.py.exp b/src/openmv/src/micropython/tests/basics/async_with_break.py.exp new file mode 100755 index 0000000..d077a88 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with_break.py.exp @@ -0,0 +1,15 @@ +enter +body +exit None None +finished +enter +body +exit None None +finally +finished +enter +body +exit None None +finally inner +finally outer +finished diff --git a/src/openmv/src/micropython/tests/basics/async_with_return.py b/src/openmv/src/micropython/tests/basics/async_with_return.py new file mode 100755 index 0000000..9af88b8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with_return.py @@ -0,0 +1,50 @@ +# test async with, escaped by a return + +class AContext: + async def __aenter__(self): + print('enter') + return 1 + async def __aexit__(self, exc_type, exc, tb): + print('exit', exc_type, exc) + +async def f1(): + async with AContext(): + print('body') + return + +o = f1() +try: + o.send(None) +except StopIteration: + print('finished') + +async def f2(): + try: + async with AContext(): + print('body') + return + finally: + print('finally') + +o = f2() +try: + o.send(None) +except StopIteration: + print('finished') + +async def f3(): + try: + try: + async with AContext(): + print('body') + return + finally: + print('finally inner') + finally: + print('finally outer') + +o = f3() +try: + o.send(None) +except StopIteration: + print('finished') diff --git a/src/openmv/src/micropython/tests/basics/async_with_return.py.exp b/src/openmv/src/micropython/tests/basics/async_with_return.py.exp new file mode 100755 index 0000000..d077a88 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/async_with_return.py.exp @@ -0,0 +1,15 @@ +enter +body +exit None None +finished +enter +body +exit None None +finally +finished +enter +body +exit None None +finally inner +finally outer +finished diff --git a/src/openmv/src/micropython/tests/basics/attrtuple1.py b/src/openmv/src/micropython/tests/basics/attrtuple1.py new file mode 100755 index 0000000..78a0fbe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/attrtuple1.py @@ -0,0 +1,19 @@ +# test attrtuple +# we can't test this type directly so we use sys.implementation object + +import sys +t = sys.implementation + +# It can be just a normal tuple on small ports +try: + t.name +except AttributeError: + print("SKIP") + raise SystemExit + + +# test printing of attrtuple +print(str(t).find("version=") > 0) + +# test read attr +print(isinstance(t.name, str)) diff --git a/src/openmv/src/micropython/tests/basics/bool1.py b/src/openmv/src/micropython/tests/basics/bool1.py new file mode 100755 index 0000000..35d9ed8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bool1.py @@ -0,0 +1,17 @@ +# tests for bool objects + +# basic logic +print(not False) +print(not True) +print(False and True) +print(False or True) + +# unary operators +print(+True) +print(-True) + +# unsupported unary op +try: + len(False) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/boundmeth1.py b/src/openmv/src/micropython/tests/basics/boundmeth1.py new file mode 100755 index 0000000..f483ba4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/boundmeth1.py @@ -0,0 +1,30 @@ +# tests basics of bound methods + +# uPy and CPython differ when printing a bound method, so just print the type +print(type(repr([].append))) + +class A: + def f(self): + return 0 + def g(self, a): + return a + def h(self, a, b, c, d, e, f): + return a + b + c + d + e + f + +# bound method with no extra args +m = A().f +print(m()) + +# bound method with 1 extra arg +m = A().g +print(m(1)) + +# bound method with lots of extra args +m = A().h +print(m(1, 2, 3, 4, 5, 6)) + +# can't assign attributes to a bound method +try: + A().f.x = 1 +except AttributeError: + print('AttributeError') diff --git a/src/openmv/src/micropython/tests/basics/break.py b/src/openmv/src/micropython/tests/basics/break.py new file mode 100755 index 0000000..c303ea0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/break.py @@ -0,0 +1,13 @@ +while True: + break + +for i in range(4): + print('one', i) + if i > 2: + break + print('two', i) + +for i in [1, 2, 3, 4]: + if i == 3: + break + print(i) diff --git a/src/openmv/src/micropython/tests/basics/builtin_abs.py b/src/openmv/src/micropython/tests/basics/builtin_abs.py new file mode 100755 index 0000000..142344e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_abs.py @@ -0,0 +1,6 @@ +# test builtin abs + +print(abs(False)) +print(abs(True)) +print(abs(1)) +print(abs(-1)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_abs_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_abs_intbig.py new file mode 100755 index 0000000..8afb7fc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_abs_intbig.py @@ -0,0 +1,13 @@ +# test builtin abs + +# bignum +print(abs(123456789012345678901234567890)) +print(abs(-123456789012345678901234567890)) + +# edge cases for 32 and 64 bit archs (small int overflow when negating) +print(abs(-0x3fffffff - 1)) +print(abs(-0x3fffffffffffffff - 1)) + +# edge case for nan-boxing with 47-bit small int +i = -0x3fffffffffff +print(abs(i - 1)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_allany.py b/src/openmv/src/micropython/tests/basics/builtin_allany.py new file mode 100755 index 0000000..07052e4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_allany.py @@ -0,0 +1,19 @@ +# test builtin "all" and "any" + +tests = ( + (), + [], + [False], + [True], + [False, True], + [True, False], + [False, False], + [True, True], + range(10), +) + +for test in tests: + print(all(test)) + +for test in tests: + print(any(test)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_bin.py b/src/openmv/src/micropython/tests/basics/builtin_bin.py new file mode 100755 index 0000000..85af406 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_bin.py @@ -0,0 +1,11 @@ +# test builtin bin function + +print(bin(1)) +print(bin(-1)) +print(bin(15)) +print(bin(-15)) + +print(bin(12345)) +print(bin(0b10101)) + +print(bin(0b10101010101010101010)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_bin_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_bin_intbig.py new file mode 100755 index 0000000..345e1f6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_bin_intbig.py @@ -0,0 +1,3 @@ +# test builtin bin function + +print(bin(12345678901234567890)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_callable.py b/src/openmv/src/micropython/tests/basics/builtin_callable.py new file mode 100755 index 0000000..3ae49f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_callable.py @@ -0,0 +1,43 @@ +# test builtin callable + +# primitives should not be callable +print(callable(None)) +print(callable(1)) +print(callable([])) +print(callable("dfsd")) + +# modules should not be callabe +import sys +print(callable(sys)) + +# builtins should be callable +print(callable(callable)) + +# lambdas should be callable +print(callable(lambda:None)) + +# user defined functions should be callable +def f(): + pass +print(callable(f)) + +# types should be callable, but not instances +class A: + pass +print(callable(A)) +print(callable(A())) + +# instances with __call__ method should be callable +class B: + def __call__(self): + pass +print(callable(B())) + +# this checks internal use of callable when extracting members from an instance +class C: + def f(self): + return "A.f" +class D: + g = C() # g is a value and is not callable +print(callable(D().g)) +print(D().g.f()) diff --git a/src/openmv/src/micropython/tests/basics/builtin_chr.py b/src/openmv/src/micropython/tests/basics/builtin_chr.py new file mode 100755 index 0000000..02d783a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_chr.py @@ -0,0 +1,9 @@ +# test builtin chr (whether or not we support unicode) + +print(chr(65)) + +try: + chr(0x110000) +except ValueError: + print("ValueError") + diff --git a/src/openmv/src/micropython/tests/basics/builtin_compile.py b/src/openmv/src/micropython/tests/basics/builtin_compile.py new file mode 100755 index 0000000..bf272ac --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_compile.py @@ -0,0 +1,49 @@ +# test compile builtin + +def have_compile(): + try: + compile + return True + except NameError: + return False + +def test(): + global x + + c = compile("print(x)", "file", "exec") + + try: + exec(c) + except NameError: + print("NameError") + + # global variable for compiled code to access + x = 1 + + exec(c) + + exec(c, {"x":2}) + exec(c, {}, {"x":3}) + + # single/eval mode + exec(compile('print(1 + 1)', 'file', 'single')) + print(eval(compile('1 + 1', 'file', 'eval'))) + + # bad mode + try: + compile('1', 'file', '') + except ValueError: + print("ValueError") + + # exception within compiled code + try: + exec(compile('noexist', 'file', 'exec')) + except NameError: + print("NameError") + print(x) # check 'x' still exists as a global + +if have_compile(): + test() +else: + print("SKIP") + raise SystemExit diff --git a/src/openmv/src/micropython/tests/basics/builtin_delattr.py b/src/openmv/src/micropython/tests/basics/builtin_delattr.py new file mode 100755 index 0000000..65bd0f2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_delattr.py @@ -0,0 +1,23 @@ +# test builtin delattr +try: + delattr +except: + print("SKIP") + raise SystemExit + +class A: pass +a = A() +a.x = 1 +print(a.x) + +delattr(a, 'x') + +try: + a.x +except AttributeError: + print('AttributeError') + +try: + delattr(a, 'x') +except AttributeError: + print('AttributeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_dir.py b/src/openmv/src/micropython/tests/basics/builtin_dir.py new file mode 100755 index 0000000..c15a76f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_dir.py @@ -0,0 +1,38 @@ +# test builtin dir + +# dir of locals +print('__name__' in dir()) + +# dir of module +import sys +print('exit' in dir(sys)) + +# dir of type +print('append' in dir(list)) + +class Foo: + def __init__(self): + self.x = 1 +foo = Foo() +print('__init__' in dir(foo)) +print('x' in dir(foo)) + +# dir of subclass +class A: + def a(): + pass +class B(A): + def b(): + pass +d = dir(B()) +print(d.count('a'), d.count('b')) + +# dir of class with multiple bases and a common parent +class C(A): + def c(): + pass +class D(B, C): + def d(): + pass +d = dir(D()) +print(d.count('a'), d.count('b'), d.count('c'), d.count('d')) diff --git a/src/openmv/src/micropython/tests/basics/builtin_divmod.py b/src/openmv/src/micropython/tests/basics/builtin_divmod.py new file mode 100755 index 0000000..26b3ae3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_divmod.py @@ -0,0 +1,15 @@ +# test builtin divmod + +print(divmod(0, 2)) +print(divmod(3, 4)) +print(divmod(20, 3)) + +try: + divmod(1, 0) +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + divmod('a', 'b') +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/builtin_divmod_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_divmod_intbig.py new file mode 100755 index 0000000..758e834 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_divmod_intbig.py @@ -0,0 +1,13 @@ +# test builtin divmod + +try: + divmod(1 << 65, 0) +except ZeroDivisionError: + print("ZeroDivisionError") + +# bignum +l = (1 << 65) + 123 +print(divmod(3, l)) +print(divmod(l, 5)) +print(divmod(l + 3, l)) +print(divmod(l * 20, l + 2)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_ellipsis.py b/src/openmv/src/micropython/tests/basics/builtin_ellipsis.py new file mode 100755 index 0000000..d88647a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_ellipsis.py @@ -0,0 +1,6 @@ +# tests that .../Ellipsis exists + +print(...) +print(Ellipsis) + +print(... == Ellipsis) diff --git a/src/openmv/src/micropython/tests/basics/builtin_enumerate.py b/src/openmv/src/micropython/tests/basics/builtin_enumerate.py new file mode 100755 index 0000000..fcbf869 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_enumerate.py @@ -0,0 +1,23 @@ +try: + enumerate +except: + print("SKIP") + raise SystemExit + +print(list(enumerate([]))) +print(list(enumerate([1, 2, 3]))) +print(list(enumerate([1, 2, 3], 5))) +print(list(enumerate([1, 2, 3], -5))) +print(list(enumerate(range(100)))) + +# specifying args with keywords +print(list(enumerate([1, 2, 3], start=1))) +print(list(enumerate(iterable=[1, 2, 3]))) +print(list(enumerate(iterable=[1, 2, 3], start=1))) + +# check handling of extra positional args (exercises some logic in mp_arg_parse_all) +# don't print anything because it doesn't error with MICROPY_CPYTHON_COMPAT disabled +try: + enumerate([], 1, 2) +except TypeError: + pass diff --git a/src/openmv/src/micropython/tests/basics/builtin_eval.py b/src/openmv/src/micropython/tests/basics/builtin_eval.py new file mode 100755 index 0000000..9b49a20 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_eval.py @@ -0,0 +1,19 @@ +# builtin eval + +try: + eval +except NameError: + print("SKIP") + raise SystemExit + +eval('1 + 2') +eval('1 + 2\n') +eval('1 + 2\n\n#comment\n') + +x = 4 +eval('x') + +eval('lambda x: x + 10')(-5) + +y = 6 +eval('lambda: y * 2')() diff --git a/src/openmv/src/micropython/tests/basics/builtin_eval_error.py b/src/openmv/src/micropython/tests/basics/builtin_eval_error.py new file mode 100755 index 0000000..ef0a32d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_eval_error.py @@ -0,0 +1,12 @@ +# test if eval raises SyntaxError + +try: + eval +except NameError: + print("SKIP") + raise SystemExit + +try: + print(eval("[1,,]")) +except SyntaxError: + print("SyntaxError") diff --git a/src/openmv/src/micropython/tests/basics/builtin_exec.py b/src/openmv/src/micropython/tests/basics/builtin_exec.py new file mode 100755 index 0000000..2e417a4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_exec.py @@ -0,0 +1,40 @@ +# test builtin exec + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + +print(exec("def foo(): return 42")) +print(foo()) + +d = {} +exec("def bar(): return 84", d) +print(d["bar"]()) + +# passing None/dict as args to globals/locals +foo = 11 +exec('print(foo)') +exec('print(foo)', None) +exec('print(foo)', {'foo':3}, None) +exec('print(foo)', None, {'foo':3}) +exec('print(foo)', None, {'bar':3}) +exec('print(foo)', {'bar':3}, locals()) + +try: + exec('print(foo)', {'bar':3}, None) +except NameError: + print('NameError') + +# invalid arg passed to globals +try: + exec('print(1)', 'foo') +except TypeError: + print('TypeError') + +# invalid arg passed to locals +try: + exec('print(1)', None, 123) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_filter.py b/src/openmv/src/micropython/tests/basics/builtin_filter.py new file mode 100755 index 0000000..c6d97cf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_filter.py @@ -0,0 +1,8 @@ +try: + filter +except: + print("SKIP") + raise SystemExit + +print(list(filter(lambda x: x & 1, range(-3, 4)))) +print(list(filter(None, range(-3, 4)))) diff --git a/src/openmv/src/micropython/tests/basics/builtin_getattr.py b/src/openmv/src/micropython/tests/basics/builtin_getattr.py new file mode 100755 index 0000000..59cb7e7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_getattr.py @@ -0,0 +1,18 @@ +class A: + + var = 132 + + def __init__(self): + self.var2 = 34 + + def meth(self, i): + return 42 + i + + +a = A() +print(getattr(a, "var")) +print(getattr(a, "var2")) +print(getattr(a, "meth")(5)) +print(getattr(a, "_none_such", 123)) +print(getattr(list, "foo", 456)) +print(getattr(a, "va" + "r2")) diff --git a/src/openmv/src/micropython/tests/basics/builtin_hasattr.py b/src/openmv/src/micropython/tests/basics/builtin_hasattr.py new file mode 100755 index 0000000..c60033b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hasattr.py @@ -0,0 +1,46 @@ +class A: + + var = 132 + + def __init__(self): + self.var2 = 34 + + def meth(self, i): + return 42 + i + + +a = A() +print(hasattr(a, "var")) +print(hasattr(a, "var2")) +print(hasattr(a, "meth")) +print(hasattr(a, "_none_such")) +print(hasattr(list, "foo")) + +class C: + + def __getattr__(self, attr): + if attr == "exists": + return attr + elif attr == "raise": + raise Exception(123) + raise AttributeError + +c = C() +print(hasattr(c, "exists")) +print(hasattr(c, "doesnt_exist")) + +# ensure that non-AttributeError exceptions propagate out of hasattr +try: + hasattr(c, "raise") +except Exception as er: + print(er) + +try: + hasattr(1, b'123') +except TypeError: + print('TypeError') + +try: + hasattr(1, 123) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_hash.py b/src/openmv/src/micropython/tests/basics/builtin_hash.py new file mode 100755 index 0000000..704895f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hash.py @@ -0,0 +1,50 @@ +# test builtin hash function + +print(hash(False)) +print(hash(True)) +print({():1}) # hash tuple +print({(1,):1}) # hash non-empty tuple +print(hash in {hash:1}) # hash function + +try: + hash([]) +except TypeError: + print("TypeError") + +class A: + def __hash__(self): + return 123 + def __repr__(self): + return "a instance" + +print(hash(A())) +print({A():1}) + +# all user-classes have default __hash__ +class B: + pass +hash(B()) + +# if __eq__ is defined then default __hash__ is not used +class C: + def __eq__(self, another): + return True +try: + hash(C()) +except TypeError: + print("TypeError") + +# __hash__ must return an int +class D: + def __hash__(self): + return None +try: + hash(D()) +except TypeError: + print("TypeError") + +# __hash__ returning a bool should be converted to an int +class E: + def __hash__(self): + return True +print(hash(E())) diff --git a/src/openmv/src/micropython/tests/basics/builtin_hash_gen.py b/src/openmv/src/micropython/tests/basics/builtin_hash_gen.py new file mode 100755 index 0000000..d42e5eb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hash_gen.py @@ -0,0 +1,7 @@ +# test builtin hash function, on generators + +def gen(): + yield + +print(type(hash(gen))) +print(type(hash(gen()))) diff --git a/src/openmv/src/micropython/tests/basics/builtin_hash_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_hash_intbig.py new file mode 100755 index 0000000..df51f72 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hash_intbig.py @@ -0,0 +1,13 @@ +# test builtin hash function + +print({1 << 66:1}) # hash big int +print({-(1 << 66):2}) # hash negative big int + +# __hash__ returning a large number should be truncated +class F: + def __hash__(self): + return 1 << 70 | 1 +print(hash(F()) != 0) + +# this had a particular error with internal integer arithmetic of hash function +print(hash(6699999999999999999999999999999999999999999999999999999999999999999999) != 0) diff --git a/src/openmv/src/micropython/tests/basics/builtin_help.py b/src/openmv/src/micropython/tests/basics/builtin_help.py new file mode 100755 index 0000000..6ec3965 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_help.py @@ -0,0 +1,17 @@ +# test builtin help function + +try: + help +except NameError: + print("SKIP") + raise SystemExit + +help() # no args +help(help) # help for a function +help(int) # help for a class +help(1) # help for an instance +import micropython +help(micropython) # help for a module +help('modules') # list available modules + +print('done') # so last bit of output is predictable diff --git a/src/openmv/src/micropython/tests/basics/builtin_help.py.exp b/src/openmv/src/micropython/tests/basics/builtin_help.py.exp new file mode 100755 index 0000000..ed8a7d7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_help.py.exp @@ -0,0 +1,14 @@ +######## +object is of type function +object is of type type + from_bytes -- + to_bytes -- +object 1 is of type int + from_bytes -- + to_bytes -- +object is of type module + __name__ -- micropython + const -- + opt_level -- +######## +done diff --git a/src/openmv/src/micropython/tests/basics/builtin_hex.py b/src/openmv/src/micropython/tests/basics/builtin_hex.py new file mode 100755 index 0000000..95d7425 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hex.py @@ -0,0 +1,9 @@ +# test builtin hex function + +print(hex(1)) +print(hex(-1)) +print(hex(15)) +print(hex(-15)) + +print(hex(12345)) +print(hex(0x12345)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_hex_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_hex_intbig.py new file mode 100755 index 0000000..7049ca3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_hex_intbig.py @@ -0,0 +1,4 @@ +# test builtin hex function + +print(hex(12345678901234567890)) +print(hex(0x12345678901234567890)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_id.py b/src/openmv/src/micropython/tests/basics/builtin_id.py new file mode 100755 index 0000000..1d617c4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_id.py @@ -0,0 +1,10 @@ +print(id(1) == id(2)) +print(id(None) == id(None)) +# This can't be true per Python semantics, just CPython implementation detail +#print(id([]) == id([])) + +l = [1, 2] +print(id(l) == id(l)) + +f = lambda:None +print(id(f) == id(f)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_issubclass.py b/src/openmv/src/micropython/tests/basics/builtin_issubclass.py new file mode 100755 index 0000000..6febc03 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_issubclass.py @@ -0,0 +1,17 @@ +# test builtin issubclass + +class A: + pass + +print(issubclass(A, A)) +print(issubclass(A, (A,))) + +try: + issubclass(A, 1) +except TypeError: + print('TypeError') + +try: + issubclass('a', 1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_len1.py b/src/openmv/src/micropython/tests/basics/builtin_len1.py new file mode 100755 index 0000000..6a08239 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_len1.py @@ -0,0 +1,13 @@ +# builtin len + +print(len(())) +print(len((1,))) +print(len((1, 2))) + +print(len([])) +x = [1, 2, 3] +print(len(x)) + +f = len +print(f({})) +print(f({1:2, 3:4})) diff --git a/src/openmv/src/micropython/tests/basics/builtin_locals.py b/src/openmv/src/micropython/tests/basics/builtin_locals.py new file mode 100755 index 0000000..e60759a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_locals.py @@ -0,0 +1,13 @@ +# test builtin locals() + +x = 123 +print(locals()['x']) + +class A: + y = 1 + def f(self): + pass + + print('x' in locals()) + print(locals()['y']) + print('f' in locals()) diff --git a/src/openmv/src/micropython/tests/basics/builtin_map.py b/src/openmv/src/micropython/tests/basics/builtin_map.py new file mode 100755 index 0000000..8fce352 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_map.py @@ -0,0 +1,4 @@ +print(list(map(lambda x: x & 1, range(-3, 4)))) +print(list(map(abs, range(-3, 4)))) +print(list(map(tuple, [[i] for i in range(-3, 4)]))) +print(list(map(pow, range(4), range(4)))) diff --git a/src/openmv/src/micropython/tests/basics/builtin_minmax.py b/src/openmv/src/micropython/tests/basics/builtin_minmax.py new file mode 100755 index 0000000..184398e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_minmax.py @@ -0,0 +1,47 @@ +# test builtin min and max functions +try: + min + max +except: + print("SKIP") + raise SystemExit + +print(min(0,1)) +print(min(1,0)) +print(min(0,-1)) +print(min(-1,0)) + +print(max(0,1)) +print(max(1,0)) +print(max(0,-1)) +print(max(-1,0)) + +print(min([1,2,4,0,-1,2])) +print(max([1,2,4,0,-1,2])) + +# test with key function +lst = [2, 1, 3, 4] +print(min(lst, key=lambda x:x)) +print(min(lst, key=lambda x:-x)) +print(min(1, 2, 3, 4, key=lambda x:-x)) +print(min(4, 3, 2, 1, key=lambda x:-x)) +print(max(lst, key=lambda x:x)) +print(max(lst, key=lambda x:-x)) +print(max(1, 2, 3, 4, key=lambda x:-x)) +print(max(4, 3, 2, 1, key=lambda x:-x)) + +# need at least 1 item in the iterable +try: + min([]) +except ValueError: + print("ValueError") + +# 'default' tests +print(min([1, 2, 3, 4, 5], default=-1)) +print(min([], default=-1)) +print(max([1, 2, 3, 4, 5], default=-1)) +print(max([], default=-1)) +# make sure it works with lazy iterables +# can't use Python generators here, as they're not supported +# byy native codegenerator. +print(min(enumerate([]), default=-10)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_oct.py b/src/openmv/src/micropython/tests/basics/builtin_oct.py new file mode 100755 index 0000000..6dc48a6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_oct.py @@ -0,0 +1,9 @@ +# test builtin oct function + +print(oct(1)) +print(oct(-1)) +print(oct(15)) +print(oct(-15)) + +print(oct(12345)) +print(oct(0o12345)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_oct_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_oct_intbig.py new file mode 100755 index 0000000..4dc28ab --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_oct_intbig.py @@ -0,0 +1,4 @@ +# test builtin oct function + +print(oct(12345678901234567890)) +print(oct(0o12345670123456701234)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_ord.py b/src/openmv/src/micropython/tests/basics/builtin_ord.py new file mode 100755 index 0000000..1556970 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_ord.py @@ -0,0 +1,28 @@ +# test builtin ord (whether or not we support unicode) + +print(ord('a')) + +try: + ord('') +except TypeError: + print("TypeError") + +# bytes also work in ord + +print(ord(b'a')) +print(ord(b'\x00')) +print(ord(b'\x01')) +print(ord(b'\x7f')) +print(ord(b'\x80')) +print(ord(b'\xff')) + +try: + ord(b'') +except TypeError: + print("TypeError") + +# argument must be a string +try: + ord(1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_override.py b/src/openmv/src/micropython/tests/basics/builtin_override.py new file mode 100755 index 0000000..9f91341 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_override.py @@ -0,0 +1,18 @@ +# test overriding builtins + +import builtins + +# override generic builtin +try: + builtins.abs = lambda x: x + 1 +except AttributeError: + print("SKIP") + raise SystemExit + +print(abs(1)) + +# __build_class__ is handled in a special way +builtins.__build_class__ = lambda x, y: ('class', y) +class A: + pass +print(A) diff --git a/src/openmv/src/micropython/tests/basics/builtin_pow.py b/src/openmv/src/micropython/tests/basics/builtin_pow.py new file mode 100755 index 0000000..5012a76 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_pow.py @@ -0,0 +1,7 @@ +# test builtin pow() with integral values +# 2 arg version + +print(pow(0, 1)) +print(pow(1, 0)) +print(pow(-2, 3)) +print(pow(3, 8)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_pow3.py b/src/openmv/src/micropython/tests/basics/builtin_pow3.py new file mode 100755 index 0000000..94e657b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_pow3.py @@ -0,0 +1,30 @@ +# test builtin pow() with integral values +# 3 arg version + +try: + print(pow(3, 4, 7)) +except NotImplementedError: + print("SKIP") + raise SystemExit + +# test some edge cases +print(pow(1, 1, 1)) +print(pow(0, 1, 1)) +print(pow(1, 0, 1)) +print(pow(1, 0, 2)) + +# 3 arg pow is defined to only work on integers +try: + print(pow("x", 5, 6)) +except TypeError: + print("TypeError expected") + +try: + print(pow(4, "y", 6)) +except TypeError: + print("TypeError expected") + +try: + print(pow(4, 5, "z")) +except TypeError: + print("TypeError expected") diff --git a/src/openmv/src/micropython/tests/basics/builtin_pow3_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_pow3_intbig.py new file mode 100755 index 0000000..bedc8b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_pow3_intbig.py @@ -0,0 +1,22 @@ +# test builtin pow() with integral values +# 3 arg version + +try: + print(pow(3, 4, 7)) +except NotImplementedError: + print("SKIP") + raise SystemExit + +print(pow(555557, 1000002, 1000003)) + +# Tests for 3 arg pow with large values + +# This value happens to be prime +x = 0xd48a1e2a099b1395895527112937a391d02d4a208bce5d74b281cf35a57362502726f79a632f063a83c0eba66196712d963aa7279ab8a504110a668c0fc38a7983c51e6ee7a85cae87097686ccdc359ee4bbf2c583bce524e3f7836bded1c771a4efcb25c09460a862fc98e18f7303df46aaeb34da46b0c4d61d5cd78350f3edb60e6bc4befa712a849 +y = 0x3accf60bb1a5365e4250d1588eb0fe6cd81ad495e9063f90880229f2a625e98c59387238670936afb2cafc5b79448e4414d6cd5e9901aa845aa122db58ddd7b9f2b17414600a18c47494ed1f3d49d005a5 + +print(hex(pow(2, 200, x))) # Should not overflow, just 1 << 200 +print(hex(pow(2, x-1, x))) # Should be 1, since x is prime +print(hex(pow(y, x-1, x))) # Should be 1, since x is prime +print(hex(pow(y, y-1, x))) # Should be a 'big value' +print(hex(pow(y, y-1, y))) # Should be a 'big value' diff --git a/src/openmv/src/micropython/tests/basics/builtin_print.py b/src/openmv/src/micropython/tests/basics/builtin_print.py new file mode 100755 index 0000000..880aaf4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_print.py @@ -0,0 +1,20 @@ +# test builtin print function + +print() +print(None) +print('') +print(1) +print(1, 2) + +print(sep='') +print(sep='x') +print(end='') +print(end='x\n') +print(1, sep='') +print(1, end='') +print(1, sep='', end='') +print(1, 2, sep='') +print(1, 2, end='') +print(1, 2, sep='', end='') + +print([{1:2}]) diff --git a/src/openmv/src/micropython/tests/basics/builtin_property.py b/src/openmv/src/micropython/tests/basics/builtin_property.py new file mode 100755 index 0000000..4b08ee9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_property.py @@ -0,0 +1,113 @@ +# test builtin property +try: + property +except: + print("SKIP") + raise SystemExit + +# create a property object explicitly +property() +property(1, 2, 3) + +# use its accessor methods +p = property() +p.getter(1) +p.setter(2) +p.deleter(3) + +# basic use as a decorator +class A: + def __init__(self, x): + self._x = x + + @property + def x(self): + print("x get") + return self._x + +a = A(1) +print(a.x) + +try: + a.x = 2 +except AttributeError: + print("AttributeError") + +# explicit use within a class +class B: + def __init__(self, x): + self._x = x + + def xget(self): + print("x get") + return self._x + + def xset(self, value): + print("x set") + self._x = value + + def xdel(self): + print("x del") + + x = property(xget, xset, xdel) + +b = B(3) +print(b.x) +b.x = 4 +print(b.x) +del b.x + +# full use as a decorator +class C: + def __init__(self, x): + self._x = x + + @property + def x(self): + print("x get") + return self._x + + @x.setter + def x(self, value): + print("x set") + self._x = value + + @x.deleter + def x(self): + print("x del") + +c = C(5) +print(c.x) +c.x = 6 +print(c.x) +del c.x + +# a property that has no get, set or del +class D: + prop = property() +d = D() +try: + d.prop +except AttributeError: + print('AttributeError') +try: + d.prop = 1 +except AttributeError: + print('AttributeError') +try: + del d.prop +except AttributeError: + print('AttributeError') + +# properties take keyword arguments +class E: + p = property(lambda self: 42, doc="This is truth.") + # not tested for because the other keyword arguments are not accepted + # q = property(fget=lambda self: 21, doc="Half the truth.") +print(E().p) + +# a property as an instance member should not be delegated to +class F: + def __init__(self): + self.prop_member = property() +print(type(F().prop_member)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_property_inherit.py b/src/openmv/src/micropython/tests/basics/builtin_property_inherit.py new file mode 100755 index 0000000..27a0913 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_property_inherit.py @@ -0,0 +1,53 @@ +# test builtin property combined with inheritance +try: + property +except: + print("SKIP") + raise SystemExit + +# test property in a base class works for derived classes +class A: + @property + def x(self): + print('A x') + return 123 +class B(A): + pass +class C(B): + pass +class D: + pass +class E(C, D): + pass +print(A().x) +print(B().x) +print(C().x) +print(E().x) + +# test that we can add a property to base class after creation +class F: + pass +F.foo = property(lambda self: print('foo get')) +class G(F): + pass +F().foo +G().foo + +# should be able to add a property to already-subclassed class because it already has one +F.bar = property(lambda self: print('bar get')) +F().bar +G().bar + +# test case where class (H here) is already subclassed before adding attributes +class H: + pass +class I(H): + pass + +# should be able to add a normal member to already-subclassed class +H.val = 2 +print(I().val) + +# should be able to add a property to the derived class +I.baz = property(lambda self: print('baz get')) +I().baz diff --git a/src/openmv/src/micropython/tests/basics/builtin_range.py b/src/openmv/src/micropython/tests/basics/builtin_range.py new file mode 100755 index 0000000..66226ba --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_range.py @@ -0,0 +1,60 @@ +# test builtin range type + +# print +print(range(4)) + +# bool +print(bool(range(0))) +print(bool(range(10))) + +# len +print(len(range(0))) +print(len(range(4))) +print(len(range(1, 4))) +print(len(range(1, 4, 2))) +print(len(range(1, 4, -1))) +print(len(range(4, 1, -1))) +print(len(range(4, 1, -2))) + +# subscr +print(range(4)[0]) +print(range(4)[1]) +print(range(4)[-1]) + +# slice +print(range(4)[0:]) +print(range(4)[1:]) +print(range(4)[1:2]) +print(range(4)[1:3]) +print(range(4)[1::2]) +print(range(4)[1:-2:2]) +print(range(1, 4)[:]) +print(range(1, 4)[0:]) +print(range(1, 4)[1:]) +print(range(1, 4)[:-1]) +print(range(7, -2, -4)[:]) +print(range(1, 100, 5)[5:15:3]) +print(range(1, 100, 5)[15:5:-3]) +print(range(100, 1, -5)[5:15:3]) +print(range(100, 1, -5)[15:5:-3]) + +# for this case uPy gives a different stop value but the listed elements are still correct +print(list(range(7, -2, -4)[2:-2:])) + +# zero step +try: + range(1, 2, 0) +except ValueError: + print("ValueError") + +# bad unary op +try: + -range(1) +except TypeError: + print("TypeError") + +# bad subscription (can't store) +try: + range(1)[0] = 1 +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/builtin_range_attrs.py b/src/openmv/src/micropython/tests/basics/builtin_range_attrs.py new file mode 100755 index 0000000..05d666d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_range_attrs.py @@ -0,0 +1,18 @@ +# test attributes of builtin range type + +try: + range(0).start +except AttributeError: + print("SKIP") + raise SystemExit + +# attrs +print(range(1, 2, 3).start) +print(range(1, 2, 3).stop) +print(range(1, 2, 3).step) + +# bad attr (can't store) +try: + range(4).start = 0 +except AttributeError: + print('AttributeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_range_binop.py b/src/openmv/src/micropython/tests/basics/builtin_range_binop.py new file mode 100755 index 0000000..e4e054c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_range_binop.py @@ -0,0 +1,32 @@ +# test binary operations on range objects; (in)equality only + +# this "feature test" actually tests the implementation but is the best we can do +if range(1) != range(1): + print("SKIP") + raise SystemExit + +# basic (in)equality +print(range(1) == range(1)) +print(range(1) != range(1)) +print(range(1) != range(2)) + +# empty range +print(range(0) == range(0)) +print(range(1, 0) == range(0)) +print(range(1, 4, -1) == range(6, 3)) + +# 1 element range +print(range(1, 4, 10) == range(1, 4, 10)) +print(range(1, 4, 10) == range(1, 4, 20)) +print(range(1, 4, 10) == range(1, 8, 20)) + +# more than 1 element +print(range(0, 3, 2) == range(0, 3, 2)) +print(range(0, 3, 2) == range(0, 4, 2)) +print(range(0, 3, 2) == range(0, 5, 2)) + +# unsupported binary op +try: + range(1) + 10 +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_reversed.py b/src/openmv/src/micropython/tests/basics/builtin_reversed.py new file mode 100755 index 0000000..f43505a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_reversed.py @@ -0,0 +1,44 @@ +# test the builtin reverse() function +try: + reversed +except: + print("SKIP") + raise SystemExit + +# list +print(list(reversed([]))) +print(list(reversed([1]))) +print(list(reversed([1, 2, 3]))) + +# tuple +print(list(reversed(()))) +print(list(reversed((1, 2, 3)))) + +# string +for c in reversed('ab'): + print(c) + +# bytes +for b in reversed(b'1234'): + print(b) + +# range +for i in reversed(range(3)): + print(i) + +# user object +class A: + def __init__(self): + pass + def __len__(self): + return 3 + def __getitem__(self, pos): + return pos + 1 +for a in reversed(A()): + print(a) + +# user object with __reversed__ +class B: + def __reversed__(self): + return [1, 2, 3] +print(reversed(B())) diff --git a/src/openmv/src/micropython/tests/basics/builtin_round.py b/src/openmv/src/micropython/tests/basics/builtin_round.py new file mode 100755 index 0000000..579bae3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_round.py @@ -0,0 +1,8 @@ +# test round() with integral values + +tests = [ + False, True, + 0, 1, -1, 10 +] +for t in tests: + print(round(t)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_round_int.py b/src/openmv/src/micropython/tests/basics/builtin_round_int.py new file mode 100755 index 0000000..a201762 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_round_int.py @@ -0,0 +1,18 @@ +# test round() with integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +tests = [ + (1, False), (1, True), + (124, -1), (125, -1), (126, -1), + (5, -1), (15, -1), (25, -1), + (12345, 0), (12345, -1), (12345, 1), + (-1234, 0), (-1234, -1), (-1234, 1), +] +for t in tests: + print(round(*t)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_round_intbig.py b/src/openmv/src/micropython/tests/basics/builtin_round_intbig.py new file mode 100755 index 0000000..adf9d29 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_round_intbig.py @@ -0,0 +1,17 @@ +# test round() with large integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +i = 2**70 + +tests = [ + (i, 0), (i, -1), (i, -10), (i, 1), + (-i, 0), (-i, -1), (-i, -10), (-i, 1), +] +for t in tests: + print(round(*t)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_setattr.py b/src/openmv/src/micropython/tests/basics/builtin_setattr.py new file mode 100755 index 0000000..e4acb14 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_setattr.py @@ -0,0 +1,25 @@ +class A: + + var = 132 + + def __init__(self): + self.var2 = 34 + + +a = A() +setattr(a, "var", 123) +setattr(a, "var2", 56) +print(a.var) +print(a.var2) + +try: + setattr(a, b'var3', 1) +except TypeError: + print('TypeError') + +# try setattr on a built-in function +try: + setattr(int, 'to_bytes', 1) +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_slice.py b/src/openmv/src/micropython/tests/basics/builtin_slice.py new file mode 100755 index 0000000..df84d5c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_slice.py @@ -0,0 +1,11 @@ +# test builtin slice + +# print slice +class A: + def __getitem__(self, idx): + print(idx) + return idx +s = A()[1:2:3] + +# check type +print(type(s) is slice) diff --git a/src/openmv/src/micropython/tests/basics/builtin_sorted.py b/src/openmv/src/micropython/tests/basics/builtin_sorted.py new file mode 100755 index 0000000..6435f86 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_sorted.py @@ -0,0 +1,16 @@ +# test builtin sorted +try: + sorted + set +except: + print("SKIP") + raise SystemExit + +print(sorted(set(range(100)))) +print(sorted(set(range(100)), key=lambda x: x + 100*(x % 2))) + +# need to use keyword argument +try: + sorted([], None) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/builtin_sum.py b/src/openmv/src/micropython/tests/basics/builtin_sum.py new file mode 100755 index 0000000..e45b82c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_sum.py @@ -0,0 +1,14 @@ +# test builtin "sum" + +tests = ( + (), + [], + [0], + [1], + [0, 1, 2], + range(10), +) + +for test in tests: + print(sum(test)) + print(sum(test, -2)) diff --git a/src/openmv/src/micropython/tests/basics/builtin_type.py b/src/openmv/src/micropython/tests/basics/builtin_type.py new file mode 100755 index 0000000..c5fb366 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_type.py @@ -0,0 +1,31 @@ +# test builtin type + +print(type(int)) + +try: + type() +except TypeError: + print('TypeError') + +try: + type(1, 2) +except TypeError: + print('TypeError') + +# second arg should be a tuple +try: + type('abc', None, None) +except TypeError: + print('TypeError') + +# third arg should be a dict +try: + type('abc', (), None) +except TypeError: + print('TypeError') + +# elements of second arg (the bases) should be types +try: + type('abc', (1,), {}) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/builtin_zip.py b/src/openmv/src/micropython/tests/basics/builtin_zip.py new file mode 100755 index 0000000..66f2544 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/builtin_zip.py @@ -0,0 +1,9 @@ +try: + zip + set +except NameError: + print("SKIP") + raise SystemExit + +print(list(zip())) +print(list(zip([1], set([2, 3])))) diff --git a/src/openmv/src/micropython/tests/basics/bytearray1.py b/src/openmv/src/micropython/tests/basics/bytearray1.py new file mode 100755 index 0000000..b598500 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray1.py @@ -0,0 +1,39 @@ +print(bytearray(4)) +a = bytearray([1, 2, 200]) +print(type(a)) +print(a[0], a[2]) +print(a[-1]) +print(a) +a[2] = 255 +print(a[-1]) +a.append(10) +print(len(a)) + +s = 0 +for i in a: + s += i +print(s) + +print(a[1:]) +print(a[:-1]) +print(a[2:3]) + +print(str(bytearray(b"123"), "utf-8")) + +# Comparisons +print(bytearray([1]) == bytearray([1])) +print(bytearray([1]) == bytearray([2])) +print(bytearray([1]) == b"1") +print(b"1" == bytearray([1])) +print(bytearray() == bytearray()) + +# comparison with other type should return False +print(bytearray() == 1) + +# TODO: other comparisons + +# __contains__ +b = bytearray(b"\0foo\0") +print(b"foo" in b) +print(b"foo\x01" in b) +print(b"" in b) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_add.py b/src/openmv/src/micropython/tests/basics/bytearray_add.py new file mode 100755 index 0000000..a7e2b57 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_add.py @@ -0,0 +1,18 @@ +# test bytearray + bytearray + +b = bytearray(2) +b[0] = 1 +b[1] = 2 +print(b + bytearray(2)) + +# inplace add +b += bytearray(3) +print(b) + +# extend +b.extend(bytearray(4)) +print(b) + +# this inplace add tests the code when the buffer doesn't need to be increased +b = bytearray() +b += b'' diff --git a/src/openmv/src/micropython/tests/basics/bytearray_append.py b/src/openmv/src/micropython/tests/basics/bytearray_append.py new file mode 100755 index 0000000..06e62c6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_append.py @@ -0,0 +1,15 @@ +# test bytearray.append method + +a = bytearray(4) +print(a) + +# append should append a single byte +a.append(2) +print(a) + +# a should not be modified if append fails +try: + a.append(None) +except TypeError: + print('TypeError') +print(a) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_construct.py b/src/openmv/src/micropython/tests/basics/bytearray_construct.py new file mode 100755 index 0000000..75fdc41 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_construct.py @@ -0,0 +1,7 @@ +# test construction of bytearray from different objects + +print(bytearray(b'123')) +print(bytearray('1234', 'utf-8')) +print(bytearray('12345', 'utf-8', 'strict')) +print(bytearray((1, 2))) +print(bytearray([1, 2])) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_construct_array.py b/src/openmv/src/micropython/tests/basics/bytearray_construct_array.py new file mode 100755 index 0000000..bde5fa0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_construct_array.py @@ -0,0 +1,10 @@ +# test construction of bytearray from different objects +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# arrays +print(bytearray(array('b', [1, 2]))) +print(bytearray(array('h', [0x101, 0x202]))) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_construct_endian.py b/src/openmv/src/micropython/tests/basics/bytearray_construct_endian.py new file mode 100755 index 0000000..0002f19 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_construct_endian.py @@ -0,0 +1,10 @@ +# test construction of bytearray from different objects +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# arrays +print(bytearray(array('h', [1, 2]))) +print(bytearray(array('I', [1, 2]))) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_intbig.py b/src/openmv/src/micropython/tests/basics/bytearray_intbig.py new file mode 100755 index 0000000..334eabe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_intbig.py @@ -0,0 +1 @@ +print(bytearray(2**65 - (2**65 - 1))) diff --git a/src/openmv/src/micropython/tests/basics/bytearray_slice_assign.py b/src/openmv/src/micropython/tests/basics/bytearray_slice_assign.py new file mode 100755 index 0000000..7f7d1d1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytearray_slice_assign.py @@ -0,0 +1,61 @@ +try: + bytearray()[:] = bytearray() +except TypeError: + print("SKIP") + raise SystemExit + +# test slices; only 2 argument version supported by MicroPython at the moment +x = bytearray(range(10)) + +# Assignment +l = bytearray(x) +l[1:3] = bytearray([10, 20]) +print(l) +l = bytearray(x) +l[1:3] = bytearray([10]) +print(l) +l = bytearray(x) +l[1:3] = bytearray() +print(l) +l = bytearray(x) +#del l[1:3] +print(l) + +l = bytearray(x) +l[:3] = bytearray([10, 20]) +print(l) +l = bytearray(x) +l[:3] = bytearray() +print(l) +l = bytearray(x) +#del l[:3] +print(l) + +l = bytearray(x) +l[:-3] = bytearray([10, 20]) +print(l) +l = bytearray(x) +l[:-3] = bytearray() +print(l) +l = bytearray(x) +#del l[:-3] +print(l) + +# slice assignment that extends the array +b = bytearray(2) +b[2:] = bytearray(10) +print(b) + +b = bytearray(10) +b[:-1] = bytearray(500) +print(len(b), b[0], b[-1]) + +# extension with self on RHS +b = bytearray(x) +b[4:] = b +print(b) + +# Assignment of bytes to array slice +b = bytearray(2) +b[1:1] = b"12345" +print(b) diff --git a/src/openmv/src/micropython/tests/basics/bytes.py b/src/openmv/src/micropython/tests/basics/bytes.py new file mode 100755 index 0000000..0b6b14f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes.py @@ -0,0 +1,64 @@ +# literals +print(b'123') +print(br'123') +print(rb'123') +print(b'\u1234') + +# construction +print(bytes()) +print(bytes(b'abc')) + +# make sure empty bytes is converted correctly +print(str(bytes(), 'utf-8')) + +a = b"123" +print(a) +print(str(a)) +print(repr(a)) +print(a[0], a[2]) +print(a[-1]) +print(str(a, "utf-8")) +print(str(a, "utf-8", "ignore")) +try: + str(a, "utf-8", "ignore", "toomuch") +except TypeError: + print("TypeError") + +s = 0 +for i in a: + s += i +print(s) + + +print(bytes("abc", "utf-8")) +print(bytes("abc", "utf-8", "replace")) +try: + bytes("abc") +except TypeError: + print("TypeError") +try: + bytes("abc", "utf-8", "replace", "toomuch") +except TypeError: + print("TypeError") + +print(bytes(3)) + +print(bytes([3, 2, 1])) +print(bytes(range(5))) + +# Make sure bytes are not mistreated as unicode +x = b"\xff\x8e\xfe}\xfd\x7f" +print(len(x)) +print(x[0], x[1], x[2], x[3]) + +# Make sure init values are not mistreated as unicode chars +# For sequence of known len +print(bytes([128, 255])) +# For sequence of unknown len +print(bytes(iter([128, 255]))) + +# Shouldn't be able to make bytes with negative length +try: + bytes(-1) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/bytes_add.py b/src/openmv/src/micropython/tests/basics/bytes_add.py new file mode 100755 index 0000000..ebccf06 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_add.py @@ -0,0 +1,8 @@ +# test bytes + other + +print(b"123" + b"456") +print(b"123" + bytearray(2)) + +print(b"123" + b"") # RHS is empty, can be optimised +print(b"" + b"123") # LHS is empty, can be optimised +print(b"" + bytearray(1)) # LHS is empty but can't be optimised diff --git a/src/openmv/src/micropython/tests/basics/bytes_add_array.py b/src/openmv/src/micropython/tests/basics/bytes_add_array.py new file mode 100755 index 0000000..b17556d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_add_array.py @@ -0,0 +1,11 @@ +# test bytes + other +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +# should be byteorder-neutral +print(b"123" + array.array('h', [0x1515])) + +print(b"\x01\x02" + array.array('b', [1, 2])) diff --git a/src/openmv/src/micropython/tests/basics/bytes_add_endian.py b/src/openmv/src/micropython/tests/basics/bytes_add_endian.py new file mode 100755 index 0000000..8cfffa7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_add_endian.py @@ -0,0 +1,8 @@ +# test bytes + other +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +print(b"123" + array.array('i', [1])) diff --git a/src/openmv/src/micropython/tests/basics/bytes_compare.py b/src/openmv/src/micropython/tests/basics/bytes_compare.py new file mode 100755 index 0000000..292267b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_compare.py @@ -0,0 +1,53 @@ +print(b"" == b"") +print(b"" > b"") +print(b"" < b"") +print(b"" == b"1") +print(b"1" == b"") +print("==") +print(b"" > b"1") +print(b"1" > b"") +print(b"" < b"1") +print(b"1" < b"") +print(b"" >= b"1") +print(b"1" >= b"") +print(b"" <= b"1") +print(b"1" <= b"") + +print(b"1" == b"1") +print(b"1" != b"1") +print(b"1" == b"2") +print(b"1" == b"10") + +print(b"1" > b"1") +print(b"1" > b"2") +print(b"2" > b"1") +print(b"10" > b"1") +print(b"1/" > b"1") +print(b"1" > b"10") +print(b"1" > b"1/") + +print(b"1" < b"1") +print(b"2" < b"1") +print(b"1" < b"2") +print(b"1" < b"10") +print(b"1" < b"1/") +print(b"10" < b"1") +print(b"1/" < b"1") + +print(b"1" >= b"1") +print(b"1" >= b"2") +print(b"2" >= b"1") +print(b"10" >= b"1") +print(b"1/" >= b"1") +print(b"1" >= b"10") +print(b"1" >= b"1/") + +print(b"1" <= b"1") +print(b"2" <= b"1") +print(b"1" <= b"2") +print(b"1" <= b"10") +print(b"1" <= b"1/") +print(b"10" <= b"1") +print(b"1/" <= b"1") + +print(b'o' == b'\n') diff --git a/src/openmv/src/micropython/tests/basics/bytes_compare2.py b/src/openmv/src/micropython/tests/basics/bytes_compare2.py new file mode 100755 index 0000000..4d5de21 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_compare2.py @@ -0,0 +1,5 @@ +print(b"1" == 1) +print(b"123" == bytearray(b"123")) +print(b'123' < bytearray(b"124")) +print(b'123' > bytearray(b"122")) +print(bytearray(b"23") in b"1234") diff --git a/src/openmv/src/micropython/tests/basics/bytes_compare3.py b/src/openmv/src/micropython/tests/basics/bytes_compare3.py new file mode 100755 index 0000000..4b9cbd5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_compare3.py @@ -0,0 +1,9 @@ +# Based on MicroPython config option, comparison of str and bytes +# or vice versa may issue a runtime warning. On CPython, if run as +# "python3 -b", only comparison of str to bytes issues a warning, +# not the other way around (while exactly comparison of bytes to +# str would be the most common error, as in sock.recv(3) == "GET"). +# Update: the issue above with CPython apparently happens in REPL, +# when run as a script, both lines issue a warning. +print("123" == b"123") +print(b"123" == "123") diff --git a/src/openmv/src/micropython/tests/basics/bytes_compare3.py.exp b/src/openmv/src/micropython/tests/basics/bytes_compare3.py.exp new file mode 100755 index 0000000..7b117b9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_compare3.py.exp @@ -0,0 +1,4 @@ +######## +False +######## +False diff --git a/src/openmv/src/micropython/tests/basics/bytes_compare_array.py b/src/openmv/src/micropython/tests/basics/bytes_compare_array.py new file mode 100755 index 0000000..ad378de --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_compare_array.py @@ -0,0 +1,9 @@ +try: + import array +except ImportError: + print("SKIP") + raise SystemExit + +print(array.array('b', [1, 2]) in b'\x01\x02\x03') +# CPython gives False here +#print(b"\x01\x02\x03" == array.array("B", [1, 2, 3])) diff --git a/src/openmv/src/micropython/tests/basics/bytes_construct.py b/src/openmv/src/micropython/tests/basics/bytes_construct.py new file mode 100755 index 0000000..0d638c0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_construct.py @@ -0,0 +1,24 @@ +# test construction of bytes from different objects + +# tuple, list, bytearray +print(bytes((1, 2))) +print(bytes([1, 2])) +print(bytes(bytearray(4))) + +# constructor value out of range +try: + bytes([-1]) +except ValueError: + print('ValueError') + +# constructor value out of range +try: + bytes([256]) +except ValueError: + print('ValueError') + +# error in construction +try: + a = bytes([1, 2, 3], 1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/bytes_construct_array.py b/src/openmv/src/micropython/tests/basics/bytes_construct_array.py new file mode 100755 index 0000000..453eb59 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_construct_array.py @@ -0,0 +1,10 @@ +# test construction of bytes from different objects +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# arrays +print(bytes(array('b', [1, 2]))) +print(bytes(array('h', [0x101, 0x202]))) diff --git a/src/openmv/src/micropython/tests/basics/bytes_construct_endian.py b/src/openmv/src/micropython/tests/basics/bytes_construct_endian.py new file mode 100755 index 0000000..cf1a9f4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_construct_endian.py @@ -0,0 +1,11 @@ +# test construction of bytes from different objects + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +# arrays +print(bytes(array('h', [1, 2]))) +print(bytes(array('I', [1, 2]))) diff --git a/src/openmv/src/micropython/tests/basics/bytes_construct_intbig.py b/src/openmv/src/micropython/tests/basics/bytes_construct_intbig.py new file mode 100755 index 0000000..c32de18 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_construct_intbig.py @@ -0,0 +1,4 @@ +# test construction of bytes from different objects + +# long ints +print(ord(bytes([14953042807679334000 & 0xff]))) diff --git a/src/openmv/src/micropython/tests/basics/bytes_count.py b/src/openmv/src/micropython/tests/basics/bytes_count.py new file mode 100755 index 0000000..5fa0730 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_count.py @@ -0,0 +1,54 @@ +try: + bytes.count +except AttributeError: + print("SKIP") + raise SystemExit + +print(b"".count(b"")) +print(b"".count(b"a")) +print(b"a".count(b"")) +print(b"a".count(b"a")) +print(b"a".count(b"b")) +print(b"b".count(b"a")) + +print(b"aaa".count(b"")) +print(b"aaa".count(b"a")) +print(b"aaa".count(b"aa")) +print(b"aaa".count(b"aaa")) +print(b"aaa".count(b"aaaa")) + +print(b"aaaa".count(b"")) +print(b"aaaa".count(b"a")) +print(b"aaaa".count(b"aa")) +print(b"aaaa".count(b"aaa")) +print(b"aaaa".count(b"aaaa")) +print(b"aaaa".count(b"aaaaa")) + +print(b"aaa".count(b"", 1)) +print(b"aaa".count(b"", 2)) +print(b"aaa".count(b"", 3)) + +print(b"aaa".count(b"", 1, 2)) + +print(b"asdfasdfaaa".count(b"asdf", -100)) +print(b"asdfasdfaaa".count(b"asdf", -8)) +print(b"asdf".count(b's', True)) +print(b"asdf".count(b'a', True)) +print(b"asdf".count(b'a', False)) +print(b"asdf".count(b'a', 1 == 2)) +print(b"hello world".count(b'l')) +print(b"hello world".count(b'l', 5)) +print(b"hello world".count(b'l', 3)) +print(b"hello world".count(b'z', 3, 6)) +print(b"aaaa".count(b'a')) +print(b"aaaa".count(b'a', 0, 3)) +print(b"aaaa".count(b'a', 0, 4)) +print(b"aaaa".count(b'a', 0, 5)) +print(b"aaaa".count(b'a', 1, 5)) +print(b"aaaa".count(b'a', -1, 5)) +print(b"abbabba".count(b"abba")) + +def t(): + return True + +print(b"0000".count(b'0', t())) diff --git a/src/openmv/src/micropython/tests/basics/bytes_find.py b/src/openmv/src/micropython/tests/basics/bytes_find.py new file mode 100755 index 0000000..75ef979 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_find.py @@ -0,0 +1,26 @@ +print(b"hello world".find(b"ll")) +print(b"hello world".find(b"ll", None)) +print(b"hello world".find(b"ll", 1)) +print(b"hello world".find(b"ll", 1, None)) +print(b"hello world".find(b"ll", None, None)) +print(b"hello world".find(b"ll", 1, -1)) +print(b"hello world".find(b"ll", 1, 1)) +print(b"hello world".find(b"ll", 1, 2)) +print(b"hello world".find(b"ll", 1, 3)) +print(b"hello world".find(b"ll", 1, 4)) +print(b"hello world".find(b"ll", 1, 5)) +print(b"hello world".find(b"ll", -100)) +print(b"0000".find(b'0')) +print(b"0000".find(b'0', 0)) +print(b"0000".find(b'0', 1)) +print(b"0000".find(b'0', 2)) +print(b"0000".find(b'0', 3)) +print(b"0000".find(b'0', 4)) +print(b"0000".find(b'0', 5)) +print(b"0000".find(b'-1', 3)) +print(b"0000".find(b'1', 3)) +print(b"0000".find(b'1', 4)) +print(b"0000".find(b'1', 5)) + +# Non-ascii values (make sure not treated as unicode-like) +print(b"\x80abc".find(b"a", 1)) diff --git a/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py b/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py new file mode 100755 index 0000000..70246e7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py @@ -0,0 +1,7 @@ +# This test requires CPython3.5 +print(b"%%" % ()) +print(b"=%d=" % 1) +print(b"=%d=%d=" % (1, 2)) + +print(b"=%s=" % b"str") +print(b"=%r=" % b"str") diff --git a/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py.exp b/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py.exp new file mode 100755 index 0000000..782b7f9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_format_modulo.py.exp @@ -0,0 +1,5 @@ +b'%' +b'=1=' +b'=1=2=' +b'=str=' +b"=b'str'=" diff --git a/src/openmv/src/micropython/tests/basics/bytes_gen.py b/src/openmv/src/micropython/tests/basics/bytes_gen.py new file mode 100755 index 0000000..12031ef --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_gen.py @@ -0,0 +1,5 @@ +# construct a bytes object from a generator +def gen(): + for i in range(4): + yield i +print(bytes(gen())) diff --git a/src/openmv/src/micropython/tests/basics/bytes_large.py b/src/openmv/src/micropython/tests/basics/bytes_large.py new file mode 100755 index 0000000..9b6b79b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_large.py @@ -0,0 +1,2 @@ +b1 = b"long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes long bytes" +b2 = b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" b"concatenated bytes" diff --git a/src/openmv/src/micropython/tests/basics/bytes_mult.py b/src/openmv/src/micropython/tests/basics/bytes_mult.py new file mode 100755 index 0000000..0effd93 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_mult.py @@ -0,0 +1,12 @@ +# basic multiplication +print(b'0' * 5) + +# check negative, 0, positive; lhs and rhs multiplication +for i in (-4, -2, 0, 2, 4): + print(i * b'12') + print(b'12' * i) + +# check that we don't modify existing object +a = b'123' +c = a * 3 +print(a, c) diff --git a/src/openmv/src/micropython/tests/basics/bytes_partition.py b/src/openmv/src/micropython/tests/basics/bytes_partition.py new file mode 100755 index 0000000..5b503f5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_partition.py @@ -0,0 +1,35 @@ +try: + str.partition +except AttributeError: + print("SKIP") + raise SystemExit + +print(b"asdf".partition(b'g')) +print(b"asdf".partition(b'a')) +print(b"asdf".partition(b's')) +print(b"asdf".partition(b'f')) +print(b"asdf".partition(b'd')) +print(b"asdf".partition(b'asd')) +print(b"asdf".partition(b'sdf')) +print(b"asdf".partition(b'as')) +print(b"asdf".partition(b'df')) +print(b"asdf".partition(b'asdf')) +print(b"asdf".partition(b'asdfa')) +print(b"asdf".partition(b'fasdf')) +print(b"asdf".partition(b'fasdfa')) +print(b"abba".partition(b'a')) +print(b"abba".partition(b'b')) + +try: + print(b"asdf".partition(1)) +except TypeError: + print("Raised TypeError") +else: + print("Did not raise TypeError") + +try: + print(b"asdf".partition(b'')) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/bytes_replace.py b/src/openmv/src/micropython/tests/basics/bytes_replace.py new file mode 100755 index 0000000..24f03e6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_replace.py @@ -0,0 +1,13 @@ +print(b"".replace(b"a", b"b")) +print(b"aaa".replace(b"a", b"b", 0)) +print(b"aaa".replace(b"a", b"b", -5)) +print(b"asdfasdf".replace(b"a", b"b")) +print(b"aabbaabbaabbaa".replace(b"aa", b"cc", 3)) +print(b"a".replace(b"aa", b"bb")) +print(b"testingtesting".replace(b"ing", b"")) +print(b"testINGtesting".replace(b"ing", b"ING!")) + +print(b"".replace(b"", b"1")) +print(b"A".replace(b"", b"1")) +print(b"AB".replace(b"", b"1")) +print(b"AB".replace(b"", b"12")) diff --git a/src/openmv/src/micropython/tests/basics/bytes_split.py b/src/openmv/src/micropython/tests/basics/bytes_split.py new file mode 100755 index 0000000..a9dda1e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_split.py @@ -0,0 +1,28 @@ +# default separator (whitespace) +print(b"a b".split()) +print(b" a b ".split(None)) +print(b" a b ".split(None, 1)) +print(b" a b ".split(None, 2)) +print(b" a b c ".split(None, 1)) +print(b" a b c ".split(None, 0)) +print(b" a b c ".split(None, -1)) + +# empty separator should fail +try: + b"abc".split(b'') +except ValueError: + print("ValueError") + +# non-empty separator +print(b"abc".split(b"a")) +print(b"abc".split(b"b")) +print(b"abc".split(b"c")) +print(b"abc".split(b"z")) +print(b"abc".split(b"ab")) +print(b"abc".split(b"bc")) +print(b"abc".split(b"abc")) +print(b"abc".split(b"abcd")) +print(b"abcabc".split(b"bc")) +print(b"abcabc".split(b"bc", 0)) +print(b"abcabc".split(b"bc", 1)) +print(b"abcabc".split(b"bc", 2)) diff --git a/src/openmv/src/micropython/tests/basics/bytes_strip.py b/src/openmv/src/micropython/tests/basics/bytes_strip.py new file mode 100755 index 0000000..71e4ac1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_strip.py @@ -0,0 +1,16 @@ +print(b"".strip()) +print(b" \t\n\r\v\f".strip()) +print(b" T E S T".strip()) +print(b"abcabc".strip(b"ce")) +print(b"aaa".strip(b"b")) +print(b"abc efg ".strip(b"g a")) + +print(b' spacious '.lstrip()) +print(b'www.example.com'.lstrip(b'cmowz.')) + +print(b' spacious '.rstrip()) +print(b'mississippi'.rstrip(b'ipz')) + +# Test that stripping unstrippable string returns original object +s = b"abc" +print(id(s.strip()) == id(s)) diff --git a/src/openmv/src/micropython/tests/basics/bytes_subscr.py b/src/openmv/src/micropython/tests/basics/bytes_subscr.py new file mode 100755 index 0000000..d6ab7bd --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/bytes_subscr.py @@ -0,0 +1,15 @@ +# test [...] of bytes + +print(b'123'[0]) +print(b'123'[1]) +print(b'123'[-1]) + +try: + b'123'[1] = 4 +except TypeError: + print('TypeError') + +try: + del b'123'[1] +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/class1.py b/src/openmv/src/micropython/tests/basics/class1.py new file mode 100755 index 0000000..bf5f08e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class1.py @@ -0,0 +1,28 @@ +# basic class + +def go(): + class C: + def f(): + print(1) + + def g(self): + print(2) + + def set(self, value): + self.value = value + + def print(self): + print(self.value) + + C.f() + C() + C().g() + + o = C() + o.set(3) + o.print() + + C.set(o, 4) + C.print(o) + +go() diff --git a/src/openmv/src/micropython/tests/basics/class2.py b/src/openmv/src/micropython/tests/basics/class2.py new file mode 100755 index 0000000..8ab3ef2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class2.py @@ -0,0 +1,26 @@ +# class with __init__ + +class C1: + def __init__(self): + self.x = 1 + +c1 = C1() +print(type(c1) == C1) +print(c1.x) + +class C2: + def __init__(self, x): + self.x = x + +c2 = C2(4) +print(type(c2) == C2) +print(c2.x) + +# __init__ should return None +class C3: + def __init__(self): + return 10 +try: + C3() +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/class3.py b/src/openmv/src/micropython/tests/basics/class3.py new file mode 100755 index 0000000..3b4f0bb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class3.py @@ -0,0 +1,24 @@ +# inheritance + +class A: + def a(): + print('A.a() called') + +class B(A): + pass + +print(type(A)) +print(type(B)) + +print(issubclass(A, A)) +print(issubclass(A, B)) +print(issubclass(B, A)) +print(issubclass(B, B)) + +print(isinstance(A(), A)) +print(isinstance(A(), B)) +print(isinstance(B(), A)) +print(isinstance(B(), B)) + +A.a() +B.a() diff --git a/src/openmv/src/micropython/tests/basics/class_bind_self.py b/src/openmv/src/micropython/tests/basics/class_bind_self.py new file mode 100755 index 0000000..16e4f5a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_bind_self.py @@ -0,0 +1,54 @@ +# test for correct binding of self when accessing attr of an instance + +class A: + def __init__(self, arg): + self.val = arg + def __str__(self): + return 'A.__str__ ' + str(self.val) + def __call__(self, arg): + return 'A.__call__', arg + def foo(self, arg): + return 'A.foo', self.val, arg + +def make_closure(x_in): + x = x_in + def closure(y): + return x, y is c + return closure + +class C: + # these act like methods and bind self + + def f1(self, arg): + return 'C.f1', self is c, arg + f2 = lambda self, arg: ('C.f2', self is c, arg) + f3 = make_closure('f3') # closure + def f4(self, arg): # generator + yield self is c, arg + + # these act like simple variables and don't bind self + + f5 = int # builtin type + f6 = abs # builtin function + f7 = A # user type + f8 = A(8) # user instance which is callable + f9 = A(9).foo # user bound method + +c = C() +print(c.f1(1)) +print(c.f2(2)) +print(c.f3()) +print(next(c.f4(4))) +print(c.f5(5)) +#print(c.f6(-6)) not working in uPy +print(c.f7(7)) +print(c.f8(8)) +print(c.f9(9)) + +# not working in uPy +#class C(list): +# # this acts like a method and binds self +# f1 = list.extend +#c = C() +#c.f1([3, 1, 2]) +#print(c) diff --git a/src/openmv/src/micropython/tests/basics/class_binop.py b/src/openmv/src/micropython/tests/basics/class_binop.py new file mode 100755 index 0000000..774f0af --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_binop.py @@ -0,0 +1,31 @@ +class foo(object): + def __init__(self, value): + self.x = value + + def __eq__(self, other): + print('eq') + return self.x == other.x + + def __lt__(self, other): + print('lt') + return self.x < other.x + + def __gt__(self, other): + print('gt') + return self.x > other.x + + def __le__(self, other): + print('le') + return self.x <= other.x + + def __ge__(self, other): + print('ge') + return self.x >= other.x + +for i in range(3): + for j in range(3): + print(foo(i) == foo(j)) + print(foo(i) < foo(j)) + print(foo(i) > foo(j)) + print(foo(i) <= foo(j)) + print(foo(i) >= foo(j)) diff --git a/src/openmv/src/micropython/tests/basics/class_call.py b/src/openmv/src/micropython/tests/basics/class_call.py new file mode 100755 index 0000000..b7a3d70 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_call.py @@ -0,0 +1,18 @@ +class C1: + def __call__(self, val): + print('call', val) + return 'item' + +class C2: + + def __getattr__(self, k): + pass + +c1 = C1() +print(c1(1)) + +c2 = C2() +try: + print(c2(1)) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/class_contains.py b/src/openmv/src/micropython/tests/basics/class_contains.py new file mode 100755 index 0000000..b6dd366 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_contains.py @@ -0,0 +1,23 @@ +# A contains everything +class A: + def __contains__(self, key): + return True + +a = A() +print(True in a) +print(1 in a) +print(() in a) + +# B contains given things +class B: + def __init__(self, items): + self.items = items + def __contains__(self, key): + return key in self.items + +b = B([]) +print(1 in b) +b = B([1, 2]) +print(1 in b) +print(2 in b) +print(3 in b) diff --git a/src/openmv/src/micropython/tests/basics/class_delattr_setattr.py b/src/openmv/src/micropython/tests/basics/class_delattr_setattr.py new file mode 100755 index 0000000..190b487 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_delattr_setattr.py @@ -0,0 +1,62 @@ +# test __delattr__ and __setattr__ + +# feature test for __setattr__/__delattr__ +try: + class Test(): + def __delattr__(self, attr): pass + del Test().noexist +except AttributeError: + print('SKIP') + raise SystemExit + +# this class just prints the calls to see if they were executed +class A(): + def __getattr__(self, attr): + print('get', attr) + return 1 + def __setattr__(self, attr, val): + print('set', attr, val) + def __delattr__(self, attr): + print('del', attr) +a = A() + +# check basic behaviour +print(getattr(a, 'foo')) +setattr(a, 'bar', 2) +delattr(a, 'baz') + +# check meta behaviour +getattr(a, '__getattr__') # should not call A.__getattr__ +getattr(a, '__setattr__') # should not call A.__getattr__ +getattr(a, '__delattr__') # should not call A.__getattr__ +setattr(a, '__setattr__', 1) # should call A.__setattr__ +delattr(a, '__delattr__') # should call A.__delattr__ + +# this class acts like a dictionary +class B: + def __init__(self, d): + # store the dict in the class, not instance, so + # we don't get infinite recursion in __getattr_ + B.d = d + + def __getattr__(self, attr): + if attr in B.d: + return B.d[attr] + else: + raise AttributeError(attr) + + def __setattr__(self, attr, value): + B.d[attr] = value + + def __delattr__(self, attr): + del B.d[attr] + +a = B({"a":1, "b":2}) +print(a.a, a.b) +a.a = 3 +print(a.a, a.b) +del a.a +try: + print(a.a) +except AttributeError: + print("AttributeError") diff --git a/src/openmv/src/micropython/tests/basics/class_descriptor.py b/src/openmv/src/micropython/tests/basics/class_descriptor.py new file mode 100755 index 0000000..54f3862 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_descriptor.py @@ -0,0 +1,34 @@ +class Descriptor: + def __get__(self, obj, cls): + print('get') + print(type(obj) is Main) + print(cls is Main) + return 'result' + + def __set__(self, obj, val): + print('set') + print(type(obj) is Main) + print(val) + + def __delete__(self, obj): + print('delete') + print(type(obj) is Main) + +class Main: + Forward = Descriptor() + +m = Main() +try: + m.__class__ +except AttributeError: + print("SKIP") + raise SystemExit + +r = m.Forward +if 'Descriptor' in repr(r.__class__): + print('SKIP') + raise SystemExit + +print(r) +m.Forward = 'a' +del m.Forward diff --git a/src/openmv/src/micropython/tests/basics/class_emptybases.py b/src/openmv/src/micropython/tests/basics/class_emptybases.py new file mode 100755 index 0000000..6d79245 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_emptybases.py @@ -0,0 +1,2 @@ +class A(): + pass diff --git a/src/openmv/src/micropython/tests/basics/class_getattr.py b/src/openmv/src/micropython/tests/basics/class_getattr.py new file mode 100755 index 0000000..eadf2b2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_getattr.py @@ -0,0 +1,14 @@ +# test that __getattr__ and instance members don't override builtins +class C: + def __init__(self): + self.__add__ = lambda: print('member __add__') + def __add__(self, x): + print('__add__') + def __getattr__(self, attr): + print('__getattr__', attr) + return None + +c = C() +c.add # should call __getattr__ +c.__add__() # should load __add__ instance directly +c + 1 # should call __add__ method directly diff --git a/src/openmv/src/micropython/tests/basics/class_inherit1.py b/src/openmv/src/micropython/tests/basics/class_inherit1.py new file mode 100755 index 0000000..9ca2d9f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_inherit1.py @@ -0,0 +1,21 @@ +class A: + def __init__(self, x): + print('A init', x) + self.x = x + + def f(self): + print(self.x, self.y) + +class B(A): + def __init__(self, x, y): + A.__init__(self, x) + print('B init', x, y) + self.y = y + + def g(self): + print(self.x, self.y) + +A(1) +b = B(1, 2) +b.f() +b.g() diff --git a/src/openmv/src/micropython/tests/basics/class_inherit_mul.py b/src/openmv/src/micropython/tests/basics/class_inherit_mul.py new file mode 100755 index 0000000..4a43a7f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_inherit_mul.py @@ -0,0 +1,42 @@ +# test multiple inheritance of user classes + +class A: + def __init__(self, x): + print('A init', x) + self.x = x + + def f(self): + print(self.x) + + def f2(self): + print(self.x) + +class B: + def __init__(self, x): + print('B init', x) + self.x = x + + def f(self): + print(self.x) + + def f3(self): + print(self.x) + + +class Sub(A, B): + def __init__(self): + A.__init__(self, 1) + B.__init__(self, 2) + print('Sub init') + + def g(self): + print(self.x) + +print(issubclass(Sub, A)) +print(issubclass(Sub, B)) + +o = Sub() +print(o.x) +o.f() +o.f2() +o.f3() diff --git a/src/openmv/src/micropython/tests/basics/class_inplace_op.py b/src/openmv/src/micropython/tests/basics/class_inplace_op.py new file mode 100755 index 0000000..62aad8c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_inplace_op.py @@ -0,0 +1,47 @@ +# Case 1: Immutable object (e.g. number-like) +# __iadd__ should not be defined, will be emulated using __add__ + +class A: + + def __init__(self, v): + self.v = v + + def __add__(self, o): + return A(self.v + o.v) + + def __repr__(self): + return "A(%s)" % self.v + +a = A(5) +b = a +a += A(3) +print(a) +# Should be original a's value, i.e. A(5) +print(b) + +# Case 2: Mutable object (e.g. list-like) +# __iadd__ should be defined + +class L: + + def __init__(self, v): + self.v = v + + def __add__(self, o): + # Should not be caled in this test + print("L.__add__") + return L(self.v + o.v) + + def __iadd__(self, o): + self.v += o.v + return self + + def __repr__(self): + return "L(%s)" % self.v + +c = L([1, 2]) +d = c +c += L([3, 4]) +print(c) +# Should be updated c's value, i.e. L([1, 2, 3, 4]) +print(d) diff --git a/src/openmv/src/micropython/tests/basics/class_instance_override.py b/src/openmv/src/micropython/tests/basics/class_instance_override.py new file mode 100755 index 0000000..6afbcd9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_instance_override.py @@ -0,0 +1,10 @@ +# test that we can override a class method with an instance method + +class A: + def foo(self): + return 1 + +a = A() +print(a.foo()) +a.foo = lambda:2 +print(a.foo()) diff --git a/src/openmv/src/micropython/tests/basics/class_item.py b/src/openmv/src/micropython/tests/basics/class_item.py new file mode 100755 index 0000000..1d9488b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_item.py @@ -0,0 +1,26 @@ +# test class with __getitem__, __setitem__, __delitem__ methods + +class C: + def __getitem__(self, item): + print('get', item) + return 'item' + + def __setitem__(self, item, value): + print('set', item, value) + + def __delitem__(self, item): + print('del', item) + +c = C() +print(c[1]) +c[1] = 2 +del c[3] + +# index not supported +class A: + pass +a = A() +try: + a[1] +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/class_misc.py b/src/openmv/src/micropython/tests/basics/class_misc.py new file mode 100755 index 0000000..82b9b34 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_misc.py @@ -0,0 +1,9 @@ +# converting user instance to buffer +class C: + pass + +c = C() +try: + d = bytearray(c) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/class_new.py b/src/openmv/src/micropython/tests/basics/class_new.py new file mode 100755 index 0000000..1f6a86c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_new.py @@ -0,0 +1,66 @@ +try: + # If we don't expose object.__new__ (small ports), there's + # nothing to test. + object.__new__ +except AttributeError: + print("SKIP") + raise SystemExit + +class A: + def __new__(cls): + print("A.__new__") + return super(cls, A).__new__(cls) + + def __init__(self): + print("A.__init__") + + def meth(self): + print('A.meth') + +#print(A.__new__) +#print(A.__init__) + +a = A() +a.meth() + +a = A.__new__(A) +a.meth() + +#print(a.meth) +#print(a.__init__) +#print(a.__new__) + +# __new__ should automatically be a staticmethod, so this should work +a = a.__new__(A) +a.meth() + +# __new__ returns not an instance of the class (None here), __init__ +# should not be called + +class B: + def __new__(self, v1, v2): + print("B.__new__", v1, v2) + + def __init__(self, v1, v2): + # Should not be called in this test + print("B.__init__", v1, v2) + +print("B inst:", B(1, 2)) + + +# Variation of the above, __new__ returns an instance of another class, +# __init__ should not be called + +class Dummy: pass + +class C: + def __new__(cls): + print("C.__new__") + return Dummy() + + def __init__(self): + # Should not be called in this test + print("C.__init__") + +c = C() +print(isinstance(c, Dummy)) diff --git a/src/openmv/src/micropython/tests/basics/class_notimpl.py b/src/openmv/src/micropython/tests/basics/class_notimpl.py new file mode 100755 index 0000000..7fd8166 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_notimpl.py @@ -0,0 +1,50 @@ +# Test that returning of NotImplemented from binary op methods leads to +# TypeError. +try: + NotImplemented +except NameError: + print("SKIP") + raise SystemExit + +class C: + def __init__(self, value): + self.value = value + + def __str__(self): + return "C(%s)" % self.value + + def __add__(self, rhs): + print(self, '+', rhs) + return NotImplemented + + def __sub__(self, rhs): + print(self, '-', rhs) + return NotImplemented + + def __lt__(self, rhs): + print(self, '<', rhs) + return NotImplemented + + def __neg__(self): + print('-', self) + return NotImplemented + +c = C(0) + +try: + c + 1 +except TypeError: + print("TypeError") + +try: + c - 2 +except TypeError: + print("TypeError") + +try: + c < 1 +except TypeError: + print("TypeError") + +# NotImplemented isn't handled specially in unary methods +print(-c) diff --git a/src/openmv/src/micropython/tests/basics/class_number.py b/src/openmv/src/micropython/tests/basics/class_number.py new file mode 100755 index 0000000..e1dbf4a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_number.py @@ -0,0 +1,15 @@ +# test class with __add__ and __sub__ methods + +class C: + def __init__(self, value): + self.value = value + + def __add__(self, rhs): + print(self.value, '+', rhs) + + def __sub__(self, rhs): + print(self.value, '-', rhs) + +c = C(0) +c + 1 +c - 2 diff --git a/src/openmv/src/micropython/tests/basics/class_reverse_op.py b/src/openmv/src/micropython/tests/basics/class_reverse_op.py new file mode 100755 index 0000000..d41c55c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_reverse_op.py @@ -0,0 +1,18 @@ +class A: + + def __init__(self, v): + self.v = v + + def __add__(self, o): + if isinstance(o, A): + return A(self.v + o.v) + return A(self.v + o) + + def __radd__(self, o): + return A(self.v + o) + + def __repr__(self): + return "A(%s)" % self.v + +print(A(3) + 1) +print(2 + A(5)) diff --git a/src/openmv/src/micropython/tests/basics/class_staticclassmethod.py b/src/openmv/src/micropython/tests/basics/class_staticclassmethod.py new file mode 100755 index 0000000..edde419 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_staticclassmethod.py @@ -0,0 +1,40 @@ +# test static and class methods + +class C: + @staticmethod + def f(rhs): + print('f', rhs) + @classmethod + def g(self, rhs): + print('g', rhs) + + # builtin wrapped in staticmethod + @staticmethod + def __sub__(rhs): + print('sub', rhs) + # builtin wrapped in classmethod + @classmethod + def __add__(self, rhs): + print('add', rhs) + + # subscript special methods wrapped in staticmethod + @staticmethod + def __getitem__(item): + print('static get', item) + return 'item' + @staticmethod + def __setitem__(item, value): + print('static set', item, value) + @staticmethod + def __delitem__(item): + print('static del', item) + +c = C() + +c.f(0) +c.g(0) +c - 1 +c + 2 +print(c[1]) +c[1] = 2 +del c[3] diff --git a/src/openmv/src/micropython/tests/basics/class_store.py b/src/openmv/src/micropython/tests/basics/class_store.py new file mode 100755 index 0000000..658da45 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_store.py @@ -0,0 +1,17 @@ +# store to class vs instance + +class C: + pass + +c = C() +c.x = 1 +print(c.x) +C.x = 2 +C.y = 3 +print(c.x, c.y) +print(C.x, C.y) +print(C().x, C().y) +c = C() +print(c.x) +c.x = 4 +print(c.x) diff --git a/src/openmv/src/micropython/tests/basics/class_store_class.py b/src/openmv/src/micropython/tests/basics/class_store_class.py new file mode 100755 index 0000000..797f88f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_store_class.py @@ -0,0 +1,51 @@ +# Inspired by urlparse.py from CPython 3.3 stdlib +# There was a bug in MicroPython that under some conditions class stored +# in instance attribute later was returned "bound" as if it was a method, +# which caused class constructor to receive extra argument. +try: + from collections import namedtuple +except ImportError: + try: + from ucollections import namedtuple + except ImportError: + print("SKIP") + raise SystemExit + +_DefragResultBase = namedtuple('DefragResult', [ 'foo', 'bar' ]) + +class _ResultMixinStr(object): + def encode(self): + return self._encoded_counterpart(*(x.encode() for x in self)) + +class _ResultMixinBytes(object): + def decode(self): + return self._decoded_counterpart(*(x.decode() for x in self)) + +class DefragResult(_DefragResultBase, _ResultMixinStr): + pass + +class DefragResultBytes(_DefragResultBase, _ResultMixinBytes): + pass + + +DefragResult._encoded_counterpart = DefragResultBytes +DefragResultBytes._decoded_counterpart = DefragResult + +# Due to differences in type and native subclass printing, +# the best thing we can do here is to just test that no exceptions +# happen + +#print(DefragResult, DefragResult._encoded_counterpart) +#print(DefragResultBytes, DefragResultBytes._decoded_counterpart) + +o1 = DefragResult("a", "b") +#print(o1, type(o1)) +o2 = DefragResultBytes("a", "b") +#print(o2, type(o2)) + +#print(o1._encoded_counterpart) +_o1 = o1.encode() +print(_o1[0], _o1[1]) +#print(_o1, type(_o1)) + +print("All's ok") diff --git a/src/openmv/src/micropython/tests/basics/class_str.py b/src/openmv/src/micropython/tests/basics/class_str.py new file mode 100755 index 0000000..46dae2b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_str.py @@ -0,0 +1,44 @@ +class C1: + def __init__(self, value): + self.value = value + + def __str__(self): + return "str".format(self.value) + +class C2: + def __init__(self, value): + self.value = value + + def __repr__(self): + return "repr".format(self.value) + +class C3: + def __init__(self, value): + self.value = value + + def __str__(self): + return "str".format(self.value) + + def __repr__(self): + return "repr".format(self.value) + +c1 = C1(1) +print(c1) + +c2 = C2(2) +print(c2) + +s11 = str(c1) +print(s11) +# This will use builtin repr(), which uses id(), which is of course different +# between CPython and MicroPython +s12 = repr(c1) +print("C1 object at" in s12) + +s21 = str(c2) +print(s21) +s22 = repr(c2) +print(s22) + +c3 = C3(1) +print(c3) diff --git a/src/openmv/src/micropython/tests/basics/class_super.py b/src/openmv/src/micropython/tests/basics/class_super.py new file mode 100755 index 0000000..b6ee683 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_super.py @@ -0,0 +1,53 @@ +class Base: + + def __init__(self): + self.a = 1 + + def meth(self): + print("in Base meth", self.a) + +class Sub(Base): + + def meth(self): + print("in Sub meth") + return super().meth() + +a = Sub() +a.meth() + +# printing super +class A: + def p(self): + print(str(super())[:18]) +A().p() + + +# test compiler's handling of long expressions with super +class A: + bar = 123 + def foo(self): + print('A foo') + return [1, 2, 3] +class B(A): + def foo(self): + print('B foo') + print(super().bar) # accessing attribute after super() + return super().foo().count(2) # calling a subsequent method +print(B().foo()) + +# first arg to super must be a type +try: + super(1, 1) +except TypeError: + print('TypeError') + +# store/delete of super attribute not allowed +assert hasattr(super(B, B()), 'foo') +try: + super(B, B()).foo = 1 +except AttributeError: + print('AttributeError') +try: + del super(B, B()).foo +except AttributeError: + print('AttributeError') diff --git a/src/openmv/src/micropython/tests/basics/class_super_aslocal.py b/src/openmv/src/micropython/tests/basics/class_super_aslocal.py new file mode 100755 index 0000000..c925911 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_super_aslocal.py @@ -0,0 +1,9 @@ +# test using the name "super" as a local variable + +class A: + def foo(self): + super = [1, 2] + super.pop() + print(super) + +A().foo() diff --git a/src/openmv/src/micropython/tests/basics/class_super_closure.py b/src/openmv/src/micropython/tests/basics/class_super_closure.py new file mode 100755 index 0000000..41acae9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_super_closure.py @@ -0,0 +1,18 @@ +# test that no-arg super() works when self is closed over + +class A: + def __init__(self): + self.val = 4 + def foo(self): + # we access a member of self to check that self is correct + return list(range(self.val)) +class B(A): + def foo(self): + # self is closed over because it's referenced in the list comprehension + # and then super() must detect this and load from the closure cell + return [self.bar(i) for i in super().foo()] + def bar(self, x): + return 2 * x + +print(A().foo()) +print(B().foo()) diff --git a/src/openmv/src/micropython/tests/basics/class_super_multinherit.py b/src/openmv/src/micropython/tests/basics/class_super_multinherit.py new file mode 100755 index 0000000..642a73c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_super_multinherit.py @@ -0,0 +1,16 @@ +# test super with multiple inheritance + +class A: + def foo(self): + print('A.foo') + +class B: + def foo(self): + print('B.foo') + +class C(A, B): + def foo(self): + print('C.foo') + super().foo() + +C().foo() diff --git a/src/openmv/src/micropython/tests/basics/class_super_object.py b/src/openmv/src/micropython/tests/basics/class_super_object.py new file mode 100755 index 0000000..1fddbb3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_super_object.py @@ -0,0 +1,22 @@ +# Calling object.__init__() via super().__init__ +try: + # If we don't expose object.__init__ (small ports), there's + # nothing to test. + object.__init__ +except AttributeError: + print("SKIP") + raise SystemExit + +class Test(object): + def __init__(self): + super().__init__() + print("Test.__init__") + +t = Test() + +class Test2: + def __init__(self): + super().__init__() + print("Test2.__init__") + +t = Test2() diff --git a/src/openmv/src/micropython/tests/basics/class_use_other.py b/src/openmv/src/micropython/tests/basics/class_use_other.py new file mode 100755 index 0000000..c6aa94a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/class_use_other.py @@ -0,0 +1,12 @@ +# check that we can use an instance of B in a method of A + +class A: + def store(a, b): + a.value = b + +class B: + pass + +b = B() +A.store(b, 1) +print(b.value) diff --git a/src/openmv/src/micropython/tests/basics/closure1.py b/src/openmv/src/micropython/tests/basics/closure1.py new file mode 100755 index 0000000..610cb70 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/closure1.py @@ -0,0 +1,16 @@ +# closures + +def f(x): + y = 2 * x + def g(z): + return y + z + return g + +print(f(1)(1)) + +x = f(2) +y = f(3) +print(x(1), x(2), x(3)) +print(y(1), y(2), y(3)) +print(x(1), x(2), x(3)) +print(y(1), y(2), y(3)) diff --git a/src/openmv/src/micropython/tests/basics/closure2.py b/src/openmv/src/micropython/tests/basics/closure2.py new file mode 100755 index 0000000..e4e5154 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/closure2.py @@ -0,0 +1,16 @@ +# closures; closing over an argument + +def f(x): + y = 2 * x + def g(z): + return x + y + z + return g + +print(f(1)(1)) + +x = f(2) +y = f(3) +print(x(1), x(2), x(3)) +print(y(1), y(2), y(3)) +print(x(1), x(2), x(3)) +print(y(1), y(2), y(3)) diff --git a/src/openmv/src/micropython/tests/basics/closure_defargs.py b/src/openmv/src/micropython/tests/basics/closure_defargs.py new file mode 100755 index 0000000..96b1092 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/closure_defargs.py @@ -0,0 +1,11 @@ +# test closure with default args + +def f(): + a = 1 + def bar(b = 10, c = 20): + print(a + b + c) + bar() + bar(2) + bar(2, 3) + +print(f()) diff --git a/src/openmv/src/micropython/tests/basics/closure_manyvars.py b/src/openmv/src/micropython/tests/basics/closure_manyvars.py new file mode 100755 index 0000000..4ae7237 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/closure_manyvars.py @@ -0,0 +1,9 @@ +# test closure with lots of closed over variables + +def f(): + a, b, c, d, e, f, g, h = [i for i in range(8)] + def x(): + print(a, b, c, d, e, f, g, h) + x() + +f() diff --git a/src/openmv/src/micropython/tests/basics/closure_namedarg.py b/src/openmv/src/micropython/tests/basics/closure_namedarg.py new file mode 100755 index 0000000..5c0c451 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/closure_namedarg.py @@ -0,0 +1,9 @@ +# test passing named arg to closed-over function + +def f(): + x = 1 + def g(z): + print(x, z) + return g + +f()(z=42) diff --git a/src/openmv/src/micropython/tests/basics/compare_multi.py b/src/openmv/src/micropython/tests/basics/compare_multi.py new file mode 100755 index 0000000..1abd180 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/compare_multi.py @@ -0,0 +1,4 @@ +print(1 < 2 < 3) +print(1 < 2 < 3 < 4) +print(1 > 2 < 3) +print(1 < 2 > 3) diff --git a/src/openmv/src/micropython/tests/basics/comprehension1.py b/src/openmv/src/micropython/tests/basics/comprehension1.py new file mode 100755 index 0000000..892d6b4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/comprehension1.py @@ -0,0 +1,19 @@ +def f(): + # list comprehension + + print([a + 1 for a in range(5)]) + print([(a, b) for a in range(3) for b in range(2)]) + print([a * 2 for a in range(7) if a > 3]) + + print([a for a in [1, 3, 5]]) + print([a for a in [a for a in range(4)]]) + + # dict comprehension + + d = {a : 2 * a for a in range(5)} + print(d[0], d[1], d[2], d[3], d[4]) + + # set comprehension + # see set_comprehension.py + +f() diff --git a/src/openmv/src/micropython/tests/basics/containment.py b/src/openmv/src/micropython/tests/basics/containment.py new file mode 100755 index 0000000..4c94a9b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/containment.py @@ -0,0 +1,35 @@ +# sets, see set_containment +for i in 1, 2: + for o in {1:2}, {1:2}.keys(): + print("{} in {}: {}".format(i, o, i in o)) + print("{} not in {}: {}".format(i, o, i not in o)) + +haystack = "supercalifragilistc" +for needle in [haystack[i:] for i in range(len(haystack))]: + print(needle, "in", haystack, "::", needle in haystack) + print(needle, "not in", haystack, "::", needle not in haystack) + print(haystack, "in", needle, "::", haystack in needle) + print(haystack, "not in", needle, "::", haystack not in needle) +for needle in [haystack[:i+1] for i in range(len(haystack))]: + print(needle, "in", haystack, "::", needle in haystack) + print(needle, "not in", haystack, "::", needle not in haystack) + print(haystack, "in", needle, "::", haystack in needle) + print(haystack, "not in", needle, "::", haystack not in needle) + +# containment of bytes/ints in bytes +print(b'' in b'123') +print(b'0' in b'123', b'1' in b'123') +print(48 in b'123', 49 in b'123') + +# containment of int in str is an error +try: + 1 in '123' +except TypeError: + print('TypeError') + +# until here, the tests would work without the 'second attempt' iteration thing. + +for i in 1, 2: + for o in [], [1], [1, 2]: + print("{} in {}: {}".format(i, o, i in o)) + print("{} not in {}: {}".format(i, o, i not in o)) diff --git a/src/openmv/src/micropython/tests/basics/continue.py b/src/openmv/src/micropython/tests/basics/continue.py new file mode 100755 index 0000000..6b388d5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/continue.py @@ -0,0 +1,16 @@ +for i in range(4): + print('one', i) + if i > 2: + continue + print('two', i) + +for i in range(4): + print('one', i) + if i < 2: + continue + print('two', i) + +for i in [1, 2, 3, 4]: + if i == 3: + continue + print(i) diff --git a/src/openmv/src/micropython/tests/basics/decorator.py b/src/openmv/src/micropython/tests/basics/decorator.py new file mode 100755 index 0000000..deb341d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/decorator.py @@ -0,0 +1,24 @@ +# test decorators + +def dec(f): + print('dec') + return f + +def dec_arg(x): + print(x) + return lambda f:f + +# plain decorator +@dec +def f(): + pass + +# decorator with arg +@dec_arg('dec_arg') +def g(): + pass + +# decorator of class +@dec +class A: + pass diff --git a/src/openmv/src/micropython/tests/basics/del_attr.py b/src/openmv/src/micropython/tests/basics/del_attr.py new file mode 100755 index 0000000..8487b97 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_attr.py @@ -0,0 +1,39 @@ +class C: + def f(): + pass + +# del a class attribute + +del C.f +try: + print(C.x) +except AttributeError: + print("AttributeError") +try: + del C.f +except AttributeError: + print("AttributeError") + +# del an instance attribute + +c = C() + +c.x = 1 +print(c.x) + +del c.x +try: + print(c.x) +except AttributeError: + print("AttributeError") +try: + del c.x +except AttributeError: + print("AttributeError") + +# try to del an attribute of a built-in class +try: + del int.to_bytes +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') diff --git a/src/openmv/src/micropython/tests/basics/del_deref.py b/src/openmv/src/micropython/tests/basics/del_deref.py new file mode 100755 index 0000000..1e7c0e4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_deref.py @@ -0,0 +1,22 @@ +def f(): + x = 1 + y = 2 + def g(): + nonlocal x + print(y) + try: + print(x) + except NameError: + print("NameError") + def h(): + nonlocal x + print(y) + try: + del x + except NameError: + print("NameError") + print(x, y) + del x + g() + h() +f() diff --git a/src/openmv/src/micropython/tests/basics/del_global.py b/src/openmv/src/micropython/tests/basics/del_global.py new file mode 100755 index 0000000..d740357 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_global.py @@ -0,0 +1,61 @@ +# del global + +def do_del(): + global x + del x + +x = 1 +print(x) +do_del() +try: + print(x) +except NameError: + print("NameError") +try: + do_del() +except: # NameError: + # FIXME uPy returns KeyError for this + print("NameError") + +# delete globals using a list + +a = 1 +del (a,) +try: + print(a) +except NameError: + print("NameError") + +a = 2 +b = 3 +del (a, b) +try: + print(a) +except NameError: + print("NameError") +try: + print(b) +except NameError: + print("NameError") + +a = 1 +b = 2 +c = 3 +del (a, b, c) +try: + print(a) +except NameError: + print("NameError") +try: + print(b) +except NameError: + print("NameError") +try: + print(c) +except NameError: + print("NameError") + +a = 1 +b = 2 +c = 3 +del (a, (b, c)) diff --git a/src/openmv/src/micropython/tests/basics/del_local.py b/src/openmv/src/micropython/tests/basics/del_local.py new file mode 100755 index 0000000..05aa98b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_local.py @@ -0,0 +1,25 @@ +# delete local then try to reference it +def f(): + x = 1 + y = 2 + print(x, y) + del x + print(y) + try: + print(x) + except NameError: + print("NameError"); +f() + +# delete local then try to delete it again +def g(): + x = 3 + y = 4 + print(x, y) + del x + print(y) + try: + del x + except NameError: + print("NameError"); +g() diff --git a/src/openmv/src/micropython/tests/basics/del_name.py b/src/openmv/src/micropython/tests/basics/del_name.py new file mode 100755 index 0000000..c92be54 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_name.py @@ -0,0 +1,18 @@ +# del name + +x = 1 +print(x) +del x +try: + print(x) +except NameError: + print("NameError") +try: + del x +except: # NameError: + # FIXME uPy returns KeyError for this + print("NameError") + +class C: + def f(): + pass diff --git a/src/openmv/src/micropython/tests/basics/del_subscr.py b/src/openmv/src/micropython/tests/basics/del_subscr.py new file mode 100755 index 0000000..0e66cf1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/del_subscr.py @@ -0,0 +1,18 @@ +l = [1, 2, 3] +print(l) +del l[0] +print(l) +del l[-1] +print(l) + +d = {1:2, 3:4, 5:6} +del d[1] +del d[3] +print(d) +del d[5] +print(d) + +# delete nested subscr +d = {0:{0:0}} +del d[0][0] +print(d) diff --git a/src/openmv/src/micropython/tests/basics/deque1.py b/src/openmv/src/micropython/tests/basics/deque1.py new file mode 100755 index 0000000..19966fc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/deque1.py @@ -0,0 +1,68 @@ +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +d = deque((), 2) +print(len(d)) +print(bool(d)) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(len(d)) +print(bool(d)) +print(d.popleft()) +print(len(d)) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(len(d)) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError: + print("IndexError") + +d.append(5) +d.append(6) +d.append(7) +print(len(d)) +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError: + print("IndexError") + +# Case where get index wraps around when appending to full deque +d = deque((), 2) +d.append(1) +d.append(2) +d.append(3) +d.append(4) +d.append(5) +print(d.popleft(), d.popleft()) + +# Negative maxlen is not allowed +try: + deque((), -1) +except ValueError: + print("ValueError") + +# Unsupported unary op +try: + ~d +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/deque2.py b/src/openmv/src/micropython/tests/basics/deque2.py new file mode 100755 index 0000000..22d370e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/deque2.py @@ -0,0 +1,66 @@ +# Tests for deques with "check overflow" flag and other extensions +# wrt to CPython. +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +# Initial sequence is not supported +try: + deque([1, 2, 3], 10) +except ValueError: + print("ValueError") + +# Not even empty list, only empty tuple +try: + deque([], 10) +except ValueError: + print("ValueError") + +# Only fixed-size deques are supported, so length arg is mandatory +try: + deque(()) +except TypeError: + print("TypeError") + +d = deque((), 2, True) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(d.popleft()) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError as e: + print(repr(e)) + +d.append(5) +d.append(6) +print(len(d)) +try: + d.append(7) +except IndexError as e: + print(repr(e)) +print(len(d)) + +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError as e: + print(repr(e)) diff --git a/src/openmv/src/micropython/tests/basics/deque2.py.exp b/src/openmv/src/micropython/tests/basics/deque2.py.exp new file mode 100755 index 0000000..3df8acf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/deque2.py.exp @@ -0,0 +1,15 @@ +ValueError +ValueError +TypeError +IndexError +None +1 +2 +3 4 +IndexError('empty',) +2 +IndexError('full',) +2 +5 6 +0 +IndexError('empty',) diff --git a/src/openmv/src/micropython/tests/basics/dict1.py b/src/openmv/src/micropython/tests/basics/dict1.py new file mode 100755 index 0000000..0cec511 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict1.py @@ -0,0 +1,42 @@ +# basic dictionary + +d = {} +print(d) +d[2] = 123 +print(d) +d = {1:2} +d[3] = 3 +print(len(d), d[1], d[3]) +d[1] = 0 +print(len(d), d[1], d[3]) +print(str(d) == '{1: 0, 3: 3}' or str(d) == '{3: 3, 1: 0}') + +x = 1 +while x < 100: + d[x] = x + x += 1 +print(d[50]) + +# equality operator on dicts of different size +print({} == {1:1}) + +# equality operator on dicts of same size but with different keys +print({1:1} == {2:1}) + +# value not found +try: + {}[0] +except KeyError as er: + print('KeyError', er, er.args) + +# unsupported unary op +try: + +{} +except TypeError: + print('TypeError') + +# unsupported binary op +try: + {} + {} +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/dict2.py b/src/openmv/src/micropython/tests/basics/dict2.py new file mode 100755 index 0000000..ca96448 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict2.py @@ -0,0 +1,14 @@ +# using strings as keys in dict + +d = {'1': 1, '2': 2} +print(d['1'], d['2']) + +d['3'] = 3 +print(d['1'], d['2'], d['3']) + +d['2'] = 222 +print(d['1'], d['2'], d['3']) + +d2 = dict(d) +print('2' in d2) +print(id(d) != id(d2), d == d2) diff --git a/src/openmv/src/micropython/tests/basics/dict_clear.py b/src/openmv/src/micropython/tests/basics/dict_clear.py new file mode 100755 index 0000000..575a848 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_clear.py @@ -0,0 +1,6 @@ +d = {1: 2, 3: 4} +print(len(d)) +d.clear() +print(d) +d[2] = 42 +print(d) diff --git a/src/openmv/src/micropython/tests/basics/dict_construct.py b/src/openmv/src/micropython/tests/basics/dict_construct.py new file mode 100755 index 0000000..0035e9c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_construct.py @@ -0,0 +1,16 @@ +# dict constructor + +d = dict() +print(d) + +d = dict({1:2}) +print(d) + +d = dict(a=1) +print(d) + +d = dict({1:2}, a=3) +print(d[1], d['a']) + +d = dict([(1, 2)], a=3, b=4) +print(d[1], d['a'], d['b']) diff --git a/src/openmv/src/micropython/tests/basics/dict_copy.py b/src/openmv/src/micropython/tests/basics/dict_copy.py new file mode 100755 index 0000000..e2fc94a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_copy.py @@ -0,0 +1,5 @@ +a = {i: 2*i for i in range(100)} +b = a.copy() +for i in range(100): + print(i, b[i]) +print(len(b)) diff --git a/src/openmv/src/micropython/tests/basics/dict_del.py b/src/openmv/src/micropython/tests/basics/dict_del.py new file mode 100755 index 0000000..d908fea --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_del.py @@ -0,0 +1,21 @@ +for n in range(20): + print('testing dict with {} items'.format(n)) + for i in range(n): + # create dict + d = dict() + for j in range(n): + d[str(j)] = j + print(len(d)) + + # delete an item + del d[str(i)] + print(len(d)) + + # check items + for j in range(n): + if str(j) in d: + if j == i: + print(j, 'in d, but it should not be') + else: + if j != i: + print(j, 'not in d, but it should be') diff --git a/src/openmv/src/micropython/tests/basics/dict_fixed.py b/src/openmv/src/micropython/tests/basics/dict_fixed.py new file mode 100755 index 0000000..4261a06 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_fixed.py @@ -0,0 +1,48 @@ +# test that fixed dictionaries cannot be modified + +try: + import uerrno +except ImportError: + print("SKIP") + raise SystemExit + +# Save a copy of uerrno.errorcode, so we can check later +# that it hasn't been modified. +errorcode_copy = uerrno.errorcode.copy() + +try: + uerrno.errorcode.popitem() +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.pop(0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.setdefault(0, 0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.update([(1, 2)]) +except TypeError: + print("TypeError") + +try: + del uerrno.errorcode[1] +except TypeError: + print("TypeError") + +try: + uerrno.errorcode[1] = 'foo' +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.clear() +except TypeError: + print("TypeError") + +assert uerrno.errorcode == errorcode_copy diff --git a/src/openmv/src/micropython/tests/basics/dict_fixed.py.exp b/src/openmv/src/micropython/tests/basics/dict_fixed.py.exp new file mode 100755 index 0000000..ffaeb40 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_fixed.py.exp @@ -0,0 +1,7 @@ +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError diff --git a/src/openmv/src/micropython/tests/basics/dict_from_iter.py b/src/openmv/src/micropython/tests/basics/dict_from_iter.py new file mode 100755 index 0000000..dc76801 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_from_iter.py @@ -0,0 +1,14 @@ +print(dict([(1, "foo")])) +d = dict([("foo", "foo2"), ("bar", "baz")]) +print(sorted(d.keys())) +print(sorted(d.values())) + +try: + dict(((1,),)) +except ValueError: + print("ValueError") + +try: + dict(((1, 2, 3),)) +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/dict_fromkeys.py b/src/openmv/src/micropython/tests/basics/dict_fromkeys.py new file mode 100755 index 0000000..7b11319 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_fromkeys.py @@ -0,0 +1,9 @@ +d = dict.fromkeys([1, 2, 3, 4]) +l = list(d.keys()) +l.sort() +print(l) + +d = dict.fromkeys([1, 2, 3, 4], 42) +l = list(d.values()) +l.sort() +print(l) diff --git a/src/openmv/src/micropython/tests/basics/dict_fromkeys2.py b/src/openmv/src/micropython/tests/basics/dict_fromkeys2.py new file mode 100755 index 0000000..dce1e8e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_fromkeys2.py @@ -0,0 +1,10 @@ +try: + reversed +except: + print("SKIP") + raise SystemExit + +# argument to fromkeys has no __len__ +d = dict.fromkeys(reversed(range(1))) +#d = dict.fromkeys((x for x in range(1))) +print(d) diff --git a/src/openmv/src/micropython/tests/basics/dict_get.py b/src/openmv/src/micropython/tests/basics/dict_get.py new file mode 100755 index 0000000..fb43a45 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_get.py @@ -0,0 +1,3 @@ +for d in {}, {42:2}: + print(d.get(42)) + print(d.get(42,2)) diff --git a/src/openmv/src/micropython/tests/basics/dict_intern.py b/src/openmv/src/micropython/tests/basics/dict_intern.py new file mode 100755 index 0000000..93efb2d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_intern.py @@ -0,0 +1,15 @@ +# check that interned strings are compared against non-interned strings + +di = {"key1": "value"} + +# lookup interned string +k = "key1" +print(k in di) + +# lookup non-interned string +k2 = "key" + "1" +print(k == k2) +print(k2 in di) + +# lookup non-interned string +print("".join(['k', 'e', 'y', '1']) in di) diff --git a/src/openmv/src/micropython/tests/basics/dict_iterator.py b/src/openmv/src/micropython/tests/basics/dict_iterator.py new file mode 100755 index 0000000..b3df2ec --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_iterator.py @@ -0,0 +1,5 @@ +d = {1: 2, 3: 4} +els = [] +for i in d: + els.append((i, d[i])) +print(sorted(els)) diff --git a/src/openmv/src/micropython/tests/basics/dict_pop.py b/src/openmv/src/micropython/tests/basics/dict_pop.py new file mode 100755 index 0000000..602560c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_pop.py @@ -0,0 +1,12 @@ +d = {1: 2, 3: 4} +print(d.pop(3), d) +print(d) +print(d.pop(1, 42), d) +print(d.pop(1, 42), d) +print(d.pop(1, None), d) +try: + print(d.pop(1), "!!!",) +except KeyError: + print("Raised KeyError") +else: + print("Did not rise KeyError!") diff --git a/src/openmv/src/micropython/tests/basics/dict_popitem.py b/src/openmv/src/micropython/tests/basics/dict_popitem.py new file mode 100755 index 0000000..e37bcec --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_popitem.py @@ -0,0 +1,16 @@ +els = [] +d = {1:2,3:4} +a = d.popitem() +print(len(d)) +els.append(a) +a = d.popitem() +print(len(d)) +els.append(a) +try: + print(d.popitem(), "!!!",) +except KeyError: + print("Raised KeyError") +else: + print("Did not raise KeyError") +print(sorted(els)) + diff --git a/src/openmv/src/micropython/tests/basics/dict_setdefault.py b/src/openmv/src/micropython/tests/basics/dict_setdefault.py new file mode 100755 index 0000000..57d0ba4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_setdefault.py @@ -0,0 +1,13 @@ +d = {} +print(d.setdefault(1)) +print(d.setdefault(1)) +print(d.setdefault(5, 42)) +print(d.setdefault(5, 1)) +print(d[1]) +print(d[5]) +d.pop(5) +print(d.setdefault(5, 1)) +print(d[1]) +print(d[5]) + + diff --git a/src/openmv/src/micropython/tests/basics/dict_specialmeth.py b/src/openmv/src/micropython/tests/basics/dict_specialmeth.py new file mode 100755 index 0000000..7a944fe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_specialmeth.py @@ -0,0 +1,7 @@ +# dict object with special methods + +d = {} +d.__setitem__('2', 'two') +print(d.__getitem__('2')) +d.__delitem__('2') +print(d) diff --git a/src/openmv/src/micropython/tests/basics/dict_update.py b/src/openmv/src/micropython/tests/basics/dict_update.py new file mode 100755 index 0000000..ab1a633 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_update.py @@ -0,0 +1,16 @@ +d = {1:2, 3:4} +print(len(d)) +d.update(["ab"]) +print(d[1]) +print(d[3]) +print(d["a"]) +print(len(d)) +d.update([(1,4)]) +print(d[1]) +print(len(d)) + +# using keywords +d.update(a=5) +print(d['a']) +d.update([(1,5)], b=6) +print(d[1], d['b']) diff --git a/src/openmv/src/micropython/tests/basics/dict_views.py b/src/openmv/src/micropython/tests/basics/dict_views.py new file mode 100755 index 0000000..7ebcc1f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/dict_views.py @@ -0,0 +1,21 @@ +d = {1: 2} +for m in d.items, d.values, d.keys: + print(m()) + print(list(m())) + +# print a view with more than one item +print({1:1, 2:1}.values()) + +# unsupported binary op on a dict values view +try: + {1:1}.values() + 1 +except TypeError: + print('TypeError') + +# unsupported binary op on a dict keys view +try: + {1:1}.keys() + 1 +except TypeError: + print('TypeError') + +# set operations still to come diff --git a/src/openmv/src/micropython/tests/basics/equal.py b/src/openmv/src/micropython/tests/basics/equal.py new file mode 100755 index 0000000..665d7fd --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/equal.py @@ -0,0 +1,75 @@ +# test equality + +print(None == None) + +print(False == None) +print(False == False) +print(False == True) + +print(() == ()) +print(() == []) +print([] == []) +print(() == {}) +print({} == ()) + +print(() == None) +print(() == False) +print(() == print) + +print([] == None) +print([] == False) +print([] == print) + +print({} == None) +print({} == False) +print({} == print) + +print(1 == 1) +print(1 == 2) +print(1 == ()) +print(1 == []) +print(1 == {}) +print(1 == 'a') + +print('a' == 'a') +print('a' == 'ab') +print('a' == 1) +print('a' == ()) + +# same as above but with != + +print(None != None) + +print(False != None) +print(False != False) +print(False != True) + +print(() != ()) +print(() != []) +print([] != []) +print(() != {}) +print({} != ()) + +print(() != None) +print(() != False) +print(() != print) + +print([] != None) +print([] != False) +print([] != print) + +print({} != None) +print({} != False) +print({} != print) + +print(1 != 1) +print(1 != 2) +print(1 != ()) +print(1 != []) +print(1 != {}) +print(1 != 'a') + +print('a' != 'a') +print('a' != 'ab') +print('a' != 1) +print('a' != ()) diff --git a/src/openmv/src/micropython/tests/basics/equal_class.py b/src/openmv/src/micropython/tests/basics/equal_class.py new file mode 100755 index 0000000..3806f7c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/equal_class.py @@ -0,0 +1,25 @@ +# test equality for classes/instances to other types + +class A: + pass + +class B: + pass + +class C(A): + pass + +print(A == None) +print(None == A) + +print(A == A) +print(A() == A) +print(A() == A()) + +print(A == B) +print(A() == B) +print(A() == B()) + +print(A == C) +print(A() == C) +print(A() == C()) diff --git a/src/openmv/src/micropython/tests/basics/errno1.py b/src/openmv/src/micropython/tests/basics/errno1.py new file mode 100755 index 0000000..d7a5ccd --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/errno1.py @@ -0,0 +1,21 @@ +# test errno's and uerrno module + +try: + import uerrno +except ImportError: + print("SKIP") + raise SystemExit + +# check that constants exist and are integers +print(type(uerrno.EIO)) + +# check that errors are rendered in a nice way +msg = str(OSError(uerrno.EIO)) +print(msg[:7], msg[-5:]) + +# check that unknown errno is still rendered +print(str(OSError(9999))) + +# this tests a failed constant lookup in errno +errno = uerrno +print(errno.__name__) diff --git a/src/openmv/src/micropython/tests/basics/errno1.py.exp b/src/openmv/src/micropython/tests/basics/errno1.py.exp new file mode 100755 index 0000000..7dd2275 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/errno1.py.exp @@ -0,0 +1,4 @@ + +[Errno ] EIO +9999 +uerrno diff --git a/src/openmv/src/micropython/tests/basics/except_match_tuple.py b/src/openmv/src/micropython/tests/basics/except_match_tuple.py new file mode 100755 index 0000000..fea2f51 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/except_match_tuple.py @@ -0,0 +1,21 @@ +# test exception matching against a tuple + +try: + fail +except (Exception,): + print('except 1') + +try: + fail +except (Exception, Exception): + print('except 2') + +try: + fail +except (TypeError, NameError): + print('except 3') + +try: + fail +except (TypeError, ValueError, Exception): + print('except 4') diff --git a/src/openmv/src/micropython/tests/basics/exception1.py b/src/openmv/src/micropython/tests/basics/exception1.py new file mode 100755 index 0000000..d83764c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/exception1.py @@ -0,0 +1,14 @@ +print(repr(IndexError())) +print(str(IndexError())) + +print(str(IndexError("foo"))) + +a = IndexError(1, "test", [100, 200]) +print(repr(a)) +print(str(a)) +print(a.args) + +s = StopIteration() +print(s.value) +s = StopIteration(1, 2, 3) +print(s.value) diff --git a/src/openmv/src/micropython/tests/basics/exception_chain.py b/src/openmv/src/micropython/tests/basics/exception_chain.py new file mode 100755 index 0000000..c3a7d6b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/exception_chain.py @@ -0,0 +1,6 @@ +# Exception chaining is not supported, but check that basic +# exception works as expected. +try: + raise Exception from None +except Exception: + print("Caught Exception") diff --git a/src/openmv/src/micropython/tests/basics/exception_chain.py.exp b/src/openmv/src/micropython/tests/basics/exception_chain.py.exp new file mode 100755 index 0000000..13635b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/exception_chain.py.exp @@ -0,0 +1,2 @@ +Warning: exception chaining not supported +Caught Exception diff --git a/src/openmv/src/micropython/tests/basics/exceptpoly.py b/src/openmv/src/micropython/tests/basics/exceptpoly.py new file mode 100755 index 0000000..9e210de --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/exceptpoly.py @@ -0,0 +1,99 @@ +try: + raise ArithmeticError +except Exception: + print("Caught ArithmeticError via Exception") + +try: + raise ArithmeticError +except ArithmeticError: + print("Caught ArithmeticError") + +try: + raise AssertionError +except Exception: + print("Caught AssertionError via Exception") + +try: + raise AssertionError +except AssertionError: + print("Caught AssertionError") + +try: + raise AttributeError +except Exception: + print("Caught AttributeError via Exception") + +try: + raise AttributeError +except AttributeError: + print("Caught AttributeError") + +try: + raise EOFError +except Exception: + print("Caught EOFError via Exception") + +try: + raise EOFError +except EOFError: + print("Caught EOFError") + +try: + raise Exception +except BaseException: + print("Caught Exception via BaseException") + +try: + raise Exception +except Exception: + print("Caught Exception") + +try: + raise ImportError +except Exception: + print("Caught ImportError via Exception") + +try: + raise ImportError +except ImportError: + print("Caught ImportError") + +try: + raise IndentationError +except SyntaxError: + print("Caught IndentationError via SyntaxError") + +try: + raise IndentationError +except IndentationError: + print("Caught IndentationError") + +try: + raise IndexError +except LookupError: + print("Caught IndexError via LookupError") + +try: + raise IndexError +except IndexError: + print("Caught IndexError") + +try: + raise KeyError +except LookupError: + print("Caught KeyError via LookupError") + +try: + raise KeyError +except KeyError: + print("Caught KeyError") + +try: + raise LookupError +except Exception: + print("Caught LookupError via Exception") + +try: + raise LookupError +except LookupError: + print("Caught LookupError") diff --git a/src/openmv/src/micropython/tests/basics/exceptpoly2.py b/src/openmv/src/micropython/tests/basics/exceptpoly2.py new file mode 100755 index 0000000..e75308d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/exceptpoly2.py @@ -0,0 +1,99 @@ +try: + raise MemoryError +except Exception: + print("Caught MemoryError via Exception") + +try: + raise MemoryError +except MemoryError: + print("Caught MemoryError") + +try: + raise NameError +except Exception: + print("Caught NameError via Exception") + +try: + raise NameError +except NameError: + print("Caught NameError") + +try: + raise NotImplementedError +except RuntimeError: + print("Caught NotImplementedError via RuntimeError") + +try: + raise NotImplementedError +except NotImplementedError: + print("Caught NotImplementedError") + +try: + raise OSError +except Exception: + print("Caught OSError via Exception") + +try: + raise OSError +except OSError: + print("Caught OSError") + +try: + raise OverflowError +except ArithmeticError: + print("Caught OverflowError via ArithmeticError") + +try: + raise OverflowError +except OverflowError: + print("Caught OverflowError") + +try: + raise RuntimeError +except Exception: + print("Caught RuntimeError via Exception") + +try: + raise RuntimeError +except RuntimeError: + print("Caught RuntimeError") + +try: + raise SyntaxError +except Exception: + print("Caught SyntaxError via Exception") + +try: + raise SyntaxError +except SyntaxError: + print("Caught SyntaxError") + +try: + raise TypeError +except Exception: + print("Caught TypeError via Exception") + +try: + raise TypeError +except TypeError: + print("Caught TypeError") + +try: + raise ValueError +except Exception: + print("Caught ValueError via Exception") + +try: + raise ValueError +except ValueError: + print("Caught ValueError") + +try: + raise ZeroDivisionError +except ArithmeticError: + print("Caught ZeroDivisionError via ArithmeticError") + +try: + raise ZeroDivisionError +except ZeroDivisionError: + print("Caught ZeroDivisionError") diff --git a/src/openmv/src/micropython/tests/basics/floordivide.py b/src/openmv/src/micropython/tests/basics/floordivide.py new file mode 100755 index 0000000..60e7634 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/floordivide.py @@ -0,0 +1,14 @@ +# check modulo matches python definition + +# This tests compiler version +print(123 // 7) +print(-123 // 7) +print(123 // -7) +print(-123 // -7) + +a = 10000001 +b = 10000000 +print(a // b) +print(a // -b) +print(-a // b) +print(-a // -b) diff --git a/src/openmv/src/micropython/tests/basics/floordivide_intbig.py b/src/openmv/src/micropython/tests/basics/floordivide_intbig.py new file mode 100755 index 0000000..422329f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/floordivide_intbig.py @@ -0,0 +1,15 @@ +# check modulo matches python definition + +a = 987654321987987987987987987987 +b = 19 + +print(a // b) +print(a // -b) +print(-a // b) +print(-a // -b) +a = 10000000000000000000000000000000000000000000 +b = 100 +print(a // b) +print(a // -b) +print(-a // b) +print(-a // -b) diff --git a/src/openmv/src/micropython/tests/basics/for1.py b/src/openmv/src/micropython/tests/basics/for1.py new file mode 100755 index 0000000..c619941 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for1.py @@ -0,0 +1,19 @@ +# basic for loop + +def f(): + for x in range(2): + for y in range(2): + for z in range(2): + print(x, y, z) + +f() + +# range with negative step +for i in range(3, -1, -1): + print(i) + +a = -1 +# range with non-constant step - we optimize constant steps, so this +# will be executed differently +for i in range(3, -1, a): + print(i) diff --git a/src/openmv/src/micropython/tests/basics/for2.py b/src/openmv/src/micropython/tests/basics/for2.py new file mode 100755 index 0000000..62f056e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for2.py @@ -0,0 +1,8 @@ +i = 'init' +for i in range(0): + pass +print(i) # should not have been modified + +for i in range(10): + pass +print(i) # should be last successful value of loop diff --git a/src/openmv/src/micropython/tests/basics/for3.py b/src/openmv/src/micropython/tests/basics/for3.py new file mode 100755 index 0000000..56617df --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for3.py @@ -0,0 +1,11 @@ +# test assigning to iterator within the loop +for i in range(2): + print(i) + i = 2 + +# test assigning to range parameter within the loop +# (since we optimise for loops, this needs checking, currently it fails) +n = 2 +for i in range(n): + print(i) + n = 0 diff --git a/src/openmv/src/micropython/tests/basics/for_break.py b/src/openmv/src/micropython/tests/basics/for_break.py new file mode 100755 index 0000000..f8bb057 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for_break.py @@ -0,0 +1,27 @@ +# Testcase for break in a for [within bunch of other code] +# https://github.com/micropython/micropython/issues/635 + +def foo(): + seq = [1, 2, 3] + v = 100 + i = 5 + while i > 0: + print(i) + for a in seq: + if a == 2: + break + i -= 1 + +foo() + +# break from within nested for loop +def bar(): + l = [1, 2, 3] + for e1 in l: + print(e1) + for e2 in l: + print(e1, e2) + if e2 == 2: + break + +bar() diff --git a/src/openmv/src/micropython/tests/basics/for_else.py b/src/openmv/src/micropython/tests/basics/for_else.py new file mode 100755 index 0000000..0bb9415 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for_else.py @@ -0,0 +1,43 @@ +# test for-else statement + +# test optimised range with simple else +for i in range(2): + print(i) +else: + print('else') + +# test optimised range with break over else +for i in range(2): + print(i) + break +else: + print('else') + +# test nested optimised range with continue in the else +for i in range(4): + print(i) + for j in range(4): + pass + else: + continue + break + +# test optimised range with non-constant end value +N = 2 +for i in range(N): + print(i) +else: + print('else') + +# test generic iterator with simple else +for i in [0, 1]: + print(i) +else: + print('else') + +# test generic iterator with break over else +for i in [0, 1]: + print(i) + break +else: + print('else') diff --git a/src/openmv/src/micropython/tests/basics/for_range.py b/src/openmv/src/micropython/tests/basics/for_range.py new file mode 100755 index 0000000..fc73627 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for_range.py @@ -0,0 +1,70 @@ +# test for+range, mostly to check optimisation of this pair + +# apply args using * +for x in range(*(1, 3)): + print(x) +for x in range(1, *(6, 2)): + print(x) + +# zero step +try: + for x in range(1, 2, 0): + pass +except ValueError: + print('ValueError') + +# apply args using ** +try: + for x in range(**{'end':1}): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, **{'end':1}): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, 1, **{'step':1}): + print(x) +except TypeError: + print('TypeError') + +# keyword args +try: + for x in range(end=1): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, end=1): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(start=0, end=1): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, 1, step=1): + print(x) +except TypeError: + print('TypeError') + +# argument is a comprehension +try: + for x in range(0 for i in []): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, (0 for i in [])): + print(x) +except TypeError: + print('TypeError') +try: + for x in range(0, 1, (0 for i in [])): + print(x) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/for_return.py b/src/openmv/src/micropython/tests/basics/for_return.py new file mode 100755 index 0000000..0441352 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/for_return.py @@ -0,0 +1,7 @@ +# test returning from within a for loop + +def f(): + for i in [1, 2, 3]: + return i + +print(f()) diff --git a/src/openmv/src/micropython/tests/basics/frozenset1.py b/src/openmv/src/micropython/tests/basics/frozenset1.py new file mode 100755 index 0000000..7bec24c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset1.py @@ -0,0 +1,19 @@ +# basic sets + +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +s = frozenset() +print(s) + +s = frozenset({1}) +print(s) + +s = frozenset({3, 4, 3, 1}) +print(sorted(s)) + +# frozensets are hashable unlike sets +print({frozenset("1"): 2}) diff --git a/src/openmv/src/micropython/tests/basics/frozenset_add.py b/src/openmv/src/micropython/tests/basics/frozenset_add.py new file mode 100755 index 0000000..fe24fba --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset_add.py @@ -0,0 +1,16 @@ +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +s = frozenset({1, 2, 3, 4}) +try: + print(s.add(5)) +except AttributeError: + print("AttributeError") + +try: + print(s.update([5])) +except AttributeError: + print("AttributeError") diff --git a/src/openmv/src/micropython/tests/basics/frozenset_binop.py b/src/openmv/src/micropython/tests/basics/frozenset_binop.py new file mode 100755 index 0000000..61af07a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset_binop.py @@ -0,0 +1,35 @@ +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +sets = [ + frozenset(), frozenset({1}), frozenset({1, 2}), frozenset({1, 2, 3}), frozenset({2, 3}), + frozenset({2, 3, 5}), frozenset({5}), frozenset({7}) +] +for s in sets: + for t in sets: + print(sorted(s), '|', sorted(t), '=', sorted(s | t)) + print(sorted(s), '^', sorted(t), '=', sorted(s ^ t)) + print(sorted(s), '&', sorted(t), '=', sorted(s & t)) + print(sorted(s), '-', sorted(t), '=', sorted(s - t)) + u = s.copy() + u |= t + print(sorted(s), "|=", sorted(t), '-->', sorted(u)) + u = s.copy() + u ^= t + print(sorted(s), "^=", sorted(t), '-->', sorted(u)) + u = s.copy() + u &= t + print(sorted(s), "&=", sorted(t), "-->", sorted(u)) + u = s.copy() + u -= t + print(sorted(s), "-=", sorted(t), "-->", sorted(u)) + + print(sorted(s), '==', sorted(t), '=', s == t) + print(sorted(s), '!=', sorted(t), '=', s != t) + print(sorted(s), '>', sorted(t), '=', s > t) + print(sorted(s), '>=', sorted(t), '=', s >= t) + print(sorted(s), '<', sorted(t), '=', s < t) + print(sorted(s), '<=', sorted(t), '=', s <= t) diff --git a/src/openmv/src/micropython/tests/basics/frozenset_copy.py b/src/openmv/src/micropython/tests/basics/frozenset_copy.py new file mode 100755 index 0000000..c90f541 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset_copy.py @@ -0,0 +1,11 @@ +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +s = frozenset({1, 2, 3, 4}) +t = s.copy() +print(type(t)) +for i in s, t: + print(sorted(i)) diff --git a/src/openmv/src/micropython/tests/basics/frozenset_difference.py b/src/openmv/src/micropython/tests/basics/frozenset_difference.py new file mode 100755 index 0000000..bc8b9c2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset_difference.py @@ -0,0 +1,20 @@ +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +l = [1, 2, 3, 4] +s = frozenset(l) +outs = [s.difference(), + s.difference(frozenset({1})), + s.difference(frozenset({1}), [1, 2]), + s.difference(frozenset({1}), {1, 2}, {2, 3})] +for out in outs: + print(type(out), sorted(out)) + +s = frozenset(l) +try: + print(s.difference_update({1})) +except AttributeError: + print("AttributeError") diff --git a/src/openmv/src/micropython/tests/basics/frozenset_set.py b/src/openmv/src/micropython/tests/basics/frozenset_set.py new file mode 100755 index 0000000..3bf456a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/frozenset_set.py @@ -0,0 +1,12 @@ +try: + frozenset +except NameError: + print("SKIP") + raise SystemExit + +# Examples from https://docs.python.org/3/library/stdtypes.html#set +# "Instances of set are compared to instances of frozenset based on their +# members. For example:" +print(set('abc') == frozenset('abc')) +# This doesn't work in uPy +#print(set('abc') in set([frozenset('abc')])) diff --git a/src/openmv/src/micropython/tests/basics/fun1.py b/src/openmv/src/micropython/tests/basics/fun1.py new file mode 100755 index 0000000..e12bdbe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun1.py @@ -0,0 +1,5 @@ +# calling a function + +def f(): + print(1) +f() diff --git a/src/openmv/src/micropython/tests/basics/fun2.py b/src/openmv/src/micropython/tests/basics/fun2.py new file mode 100755 index 0000000..a3c3e7b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun2.py @@ -0,0 +1,10 @@ +# calling a function from a function + +def f(x): + print(x + 1) + +def g(x): + f(2 * x) + f(4 * x) + +g(3) diff --git a/src/openmv/src/micropython/tests/basics/fun3.py b/src/openmv/src/micropython/tests/basics/fun3.py new file mode 100755 index 0000000..f1458df --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun3.py @@ -0,0 +1,6 @@ +# function with large number of arguments + +def fun(a, b, c, d, e, f, g): + return a + b + c * d + e * f * g + +print(fun(1, 2, 3, 4, 5, 6, 7)) diff --git a/src/openmv/src/micropython/tests/basics/fun_annotations.py b/src/openmv/src/micropython/tests/basics/fun_annotations.py new file mode 100755 index 0000000..85f808a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_annotations.py @@ -0,0 +1,4 @@ +def foo(x: int, y: list) -> dict: + return {x: y} + +print(foo(1, [2, 3])) diff --git a/src/openmv/src/micropython/tests/basics/fun_calldblstar.py b/src/openmv/src/micropython/tests/basics/fun_calldblstar.py new file mode 100755 index 0000000..4a50369 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_calldblstar.py @@ -0,0 +1,22 @@ +# test calling a function with keywords given by **dict + +def f(a, b): + print(a, b) + +f(1, **{'b':2}) +f(1, **{'b':val for val in range(1)}) + +try: + f(1, **{len:2}) +except TypeError: + print('TypeError') + +# test calling a method with keywords given by **dict + +class A: + def f(self, a, b): + print(a, b) + +a = A() +a.f(1, **{'b':2}) +a.f(1, **{'b':val for val in range(1)}) diff --git a/src/openmv/src/micropython/tests/basics/fun_calldblstar2.py b/src/openmv/src/micropython/tests/basics/fun_calldblstar2.py new file mode 100755 index 0000000..8795eaf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_calldblstar2.py @@ -0,0 +1,19 @@ +# test passing a string object as the key for a keyword argument + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + +# they key in this dict is a string object and is not interned +args = {'thisisaverylongargumentname': 123} + +# when this string is executed it will intern the keyword argument +exec("def foo(*,thisisaverylongargumentname=1):\n print(thisisaverylongargumentname)") + +# test default arg +foo() + +# the string from the dict should match the interned keyword argument +foo(**args) diff --git a/src/openmv/src/micropython/tests/basics/fun_calldblstar3.py b/src/openmv/src/micropython/tests/basics/fun_calldblstar3.py new file mode 100755 index 0000000..b796d52 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_calldblstar3.py @@ -0,0 +1,17 @@ +# test passing a user-defined mapping as the argument to ** + +def foo(**kw): + print(sorted(kw.items())) + +class Mapping: + def keys(self): + # the long string checks the case of string interning + return ['a', 'b', 'c', 'abcdefghijklmnopqrst'] + + def __getitem__(self, key): + if key == 'a': + return 1 + else: + return 2 + +foo(**Mapping()) diff --git a/src/openmv/src/micropython/tests/basics/fun_callstar.py b/src/openmv/src/micropython/tests/basics/fun_callstar.py new file mode 100755 index 0000000..a27a288 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_callstar.py @@ -0,0 +1,41 @@ +# function calls with *pos + +def foo(a, b, c): + print(a, b, c) + +foo(*(1, 2, 3)) +foo(1, *(2, 3)) +foo(1, 2, *(3,)) +foo(1, 2, 3, *()) + +# Another sequence type +foo(1, 2, *[100]) + +# Iterator +foo(*range(3)) + +# pos then iterator +foo(1, *range(2, 4)) + +# an iterator with many elements +def foo(*rest): + print(rest) +foo(*range(10)) + +# method calls with *pos + +class A: + def foo(self, a, b, c): + print(a, b, c) + +a = A() +a.foo(*(1, 2, 3)) +a.foo(1, *(2, 3)) +a.foo(1, 2, *(3,)) +a.foo(1, 2, 3, *()) + +# Another sequence type +a.foo(1, 2, *[100]) + +# Iterator +a.foo(*range(3)) diff --git a/src/openmv/src/micropython/tests/basics/fun_callstardblstar.py b/src/openmv/src/micropython/tests/basics/fun_callstardblstar.py new file mode 100755 index 0000000..f2fd291 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_callstardblstar.py @@ -0,0 +1,17 @@ +# test calling a function with *tuple and **dict + +def f(a, b, c, d): + print(a, b, c, d) + +f(*(1, 2), **{'c':3, 'd':4}) +f(*(1, 2), **{['c', 'd'][i]:(3 + i) for i in range(2)}) + +# test calling a method with *tuple and **dict + +class A: + def f(self, a, b, c, d): + print(a, b, c, d) + +a = A() +a.f(*(1, 2), **{'c':3, 'd':4}) +a.f(*(1, 2), **{['c', 'd'][i]:(3 + i) for i in range(2)}) diff --git a/src/openmv/src/micropython/tests/basics/fun_defargs.py b/src/openmv/src/micropython/tests/basics/fun_defargs.py new file mode 100755 index 0000000..1466c44 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_defargs.py @@ -0,0 +1,29 @@ +# testing default args to a function + +def fun1(val=5): + print(val) + +fun1() +fun1(10) + +def fun2(p1, p2=100, p3="foo"): + print(p1, p2, p3) + +fun2(1) +fun2(1, None) +fun2(0, "bar", 200) +try: + fun2() +except TypeError: + print("TypeError") +try: + fun2(1, 2, 3, 4) +except TypeError: + print("TypeError") + +# lambda as default arg (exposes nested behaviour in compiler) +def f(x=lambda:1): + return x() +print(f()) +print(f(f)) +print(f(lambda:2)) diff --git a/src/openmv/src/micropython/tests/basics/fun_defargs2.py b/src/openmv/src/micropython/tests/basics/fun_defargs2.py new file mode 100755 index 0000000..8b72ed8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_defargs2.py @@ -0,0 +1,19 @@ +# overriding default arguments + +def foo(a, b=3): + print(a, b) + +# override with positional +foo(1, 333) + +# override with keyword +foo(1, b=333) + +# override with keyword +foo(a=2, b=333) + +def foo2(a=1, b=2): + print(a, b) + +# default and keyword +foo2(b='two') diff --git a/src/openmv/src/micropython/tests/basics/fun_error.py b/src/openmv/src/micropython/tests/basics/fun_error.py new file mode 100755 index 0000000..3e79c72 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_error.py @@ -0,0 +1,44 @@ +# test errors from bad function calls + +# function doesn't take keyword args +try: + [].append(x=1) +except TypeError: + print('TypeError') + +# function with variable number of positional args given too few +try: + round() +except TypeError: + print('TypeError') + +# function with variable number of positional args given too many +try: + round(1, 2, 3) +except TypeError: + print('TypeError') + +# function with fixed number of positional args given wrong number +try: + [].append(1, 2) +except TypeError: + print('TypeError') + +# function with keyword args given extra positional args +try: + [].sort(1) +except TypeError: + print('TypeError') + +# function with keyword args given extra keyword args +try: + [].sort(noexist=1) +except TypeError: + print('TypeError') + +# kw given for positional, but a different positional is missing +try: + def f(x, y): pass + f(x=1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/fun_error2.py b/src/openmv/src/micropython/tests/basics/fun_error2.py new file mode 100755 index 0000000..39fd0af --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_error2.py @@ -0,0 +1,12 @@ +# test errors from bad function calls +try: + enumerate +except: + print("SKIP") + raise SystemExit + +# function with keyword args not given a specific keyword arg +try: + enumerate() +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/fun_kwargs.py b/src/openmv/src/micropython/tests/basics/fun_kwargs.py new file mode 100755 index 0000000..9f4f2b7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_kwargs.py @@ -0,0 +1,35 @@ +def f1(a): + print(a) + +f1(123) +f1(a=123) +try: + f1(b=123) +except TypeError: + print("TypeError") + +def f2(a, b): + print(a, b) + +f2(1, 2) +f2(a=3, b=4) +f2(b=5, a=6) +f2(7, b=8) +try: + f2(9, a=10) +except TypeError: + print("TypeError") + +def f3(a, b, *args): + print(a, b, args) + + +f3(1, b=3) +try: + f3(1, a=3) +except TypeError: + print("TypeError") +try: + f3(1, 2, 3, 4, a=5) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/fun_kwonly.py b/src/openmv/src/micropython/tests/basics/fun_kwonly.py new file mode 100755 index 0000000..7694c8d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_kwonly.py @@ -0,0 +1,66 @@ +# to test keyword-only arguments + +# simplest case +def f(*, a): + print(a) + +f(a=1) + +# with 2 keyword-only args +def f(*, a, b): + print(a, b) + +f(a=1, b=2) +f(b=1, a=2) + +# positional followed by bare star +def f(a, *, b, c): + print(a, b, c) + +f(1, b=3, c=4) +f(1, c=3, b=4) +f(1, **{'b':'3', 'c':4}) + +try: + f(1) +except TypeError: + print("TypeError") + +try: + f(1, b=2) +except TypeError: + print("TypeError") + +try: + f(1, c=2) +except TypeError: + print("TypeError") + +# with **kw +def f(a, *, b, **kw): + print(a, b, kw) + +f(1, b=2) +f(1, b=2, c=3) + +# with named star +def f(*a, b, c): + print(a, b, c) + +f(b=1, c=2) +f(c=1, b=2) + +# with positional and named star +def f(a, *b, c): + print(a, b, c) + +f(1, c=2) +f(1, 2, c=3) +f(a=1, c=3) + +# lambda as kw-only arg (exposes nested behaviour in compiler) +def f(*, x=lambda:1): + return x() +print(f()) +print(f(x=f)) +print(f(x=lambda:2)) diff --git a/src/openmv/src/micropython/tests/basics/fun_kwonlydef.py b/src/openmv/src/micropython/tests/basics/fun_kwonlydef.py new file mode 100755 index 0000000..56a08ee --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_kwonlydef.py @@ -0,0 +1,36 @@ +# test function args, keyword only with default value + +# a single arg with a default +def f1(*, a=1): + print(a) +f1() +f1(a=2) + +# 1 arg default, 1 not +def f2(*, a=1, b): + print(a, b) +f2(b=2) +f2(a=2, b=3) + +# 1 positional, 1 arg default, 1 not +def f3(a, *, b=2, c): + print(a, b, c) +f3(1, c=3) +f3(1, b=3, c=4) +f3(1, **{'c':3}) +f3(1, **{'b':'3', 'c':4}) + +# many args, not all with defaults +def f4(*, a=1, b, c=3, d, e=5, f): + print(a, b, c, d, e, f) +f4(b=2, d=4, f=6) +f4(a=11, b=2, d=4, f=6) +f4(a=11, b=2, c=33, d=4, e=55, f=6) +f4(f=6, e=55, d=4, c=33, b=2, a=11) + +# positional with default, then keyword only +def f5(a, b=4, *c, d=8): + print(a, b, c, d) +f5(1) +f5(1, d=9) +f5(1, b=44, d=9) diff --git a/src/openmv/src/micropython/tests/basics/fun_kwvarargs.py b/src/openmv/src/micropython/tests/basics/fun_kwvarargs.py new file mode 100755 index 0000000..bdc10fc --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_kwvarargs.py @@ -0,0 +1,25 @@ +def f1(**kwargs): + print(kwargs) + +f1() +f1(a=1) + +def f2(a, **kwargs): + print(a, kwargs) + +f2(1) +f2(1, b=2) + +def f3(a, *vargs, **kwargs): + print(a, vargs, kwargs) + +f3(1) +f3(1, 2) +f3(1, b=2) +f3(1, 2, b=3) + +def f4(*vargs, **kwargs): + print(vargs, kwargs) +f4(*(1, 2)) +f4(kw_arg=3) +f4(*(1, 2), kw_arg=3) diff --git a/src/openmv/src/micropython/tests/basics/fun_largestate.py b/src/openmv/src/micropython/tests/basics/fun_largestate.py new file mode 100755 index 0000000..124f1e5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_largestate.py @@ -0,0 +1,159 @@ +# test large function (stack) state + +# this function creates 127 locals +def f(): + x0 = 1 + x1 = 1 + x2 = 1 + x3 = 1 + x4 = 1 + x5 = 1 + x6 = 1 + x7 = 1 + x8 = 1 + x9 = 1 + x10 = 1 + x11 = 1 + x12 = 1 + x13 = 1 + x14 = 1 + x15 = 1 + x16 = 1 + x17 = 1 + x18 = 1 + x19 = 1 + x20 = 1 + x21 = 1 + x22 = 1 + x23 = 1 + x24 = 1 + x25 = 1 + x26 = 1 + x27 = 1 + x28 = 1 + x29 = 1 + x30 = 1 + x31 = 1 + x32 = 1 + x33 = 1 + x34 = 1 + x35 = 1 + x36 = 1 + x37 = 1 + x38 = 1 + x39 = 1 + x40 = 1 + x41 = 1 + x42 = 1 + x43 = 1 + x44 = 1 + x45 = 1 + x46 = 1 + x47 = 1 + x48 = 1 + x49 = 1 + x50 = 1 + x51 = 1 + x52 = 1 + x53 = 1 + x54 = 1 + x55 = 1 + x56 = 1 + x57 = 1 + x58 = 1 + x59 = 1 + x60 = 1 + x61 = 1 + x62 = 1 + x63 = 1 + x64 = 1 + x65 = 1 + x66 = 1 + x67 = 1 + x68 = 1 + x69 = 1 + x70 = 1 + x71 = 1 + x72 = 1 + x73 = 1 + x74 = 1 + x75 = 1 + x76 = 1 + x77 = 1 + x78 = 1 + x79 = 1 + x80 = 1 + x81 = 1 + x82 = 1 + x83 = 1 + x84 = 1 + x85 = 1 + x86 = 1 + x87 = 1 + x88 = 1 + x89 = 1 + x90 = 1 + x91 = 1 + x92 = 1 + x93 = 1 + x94 = 1 + x95 = 1 + x96 = 1 + x97 = 1 + x98 = 1 + x99 = 1 + x100 = 1 + x101 = 1 + x102 = 1 + x103 = 1 + x104 = 1 + x105 = 1 + x106 = 1 + x107 = 1 + x108 = 1 + x109 = 1 + x110 = 1 + x111 = 1 + x112 = 1 + x113 = 1 + x114 = 1 + x115 = 1 + x116 = 1 + x117 = 1 + x118 = 1 + x119 = 1 + x120 = 1 + x121 = 1 + x122 = 1 + x123 = 1 + x124 = 1 + x125 = 1 + x126 = 1 +f() + +# this function pushes 128 elements onto the function stack +def g(): + x = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,] +g() + +# this function exercises load_fast_n and store_fast_n opcodes +def h(): + x0 = 1 + x1 = x0 + x2 = x1 + x3 = x2 + x4 = x3 + x5 = x4 + x6 = x5 + x7 = x6 + x8 = x7 + x9 = x8 + x10 = x9 + x11 = x10 + x12 = x11 + x13 = x12 + x14 = x13 + x15 = x14 + x16 = x15 + x17 = x16 +h() diff --git a/src/openmv/src/micropython/tests/basics/fun_name.py b/src/openmv/src/micropython/tests/basics/fun_name.py new file mode 100755 index 0000000..a724f41 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_name.py @@ -0,0 +1,17 @@ +def Fun(): + pass + +class A: + def __init__(self): + pass + def Fun(self): + pass + +try: + print(Fun.__name__) + print(A.__init__.__name__) + print(A.Fun.__name__) + print(A().Fun.__name__) +except AttributeError: + print('SKIP') + raise SystemExit diff --git a/src/openmv/src/micropython/tests/basics/fun_str.py b/src/openmv/src/micropython/tests/basics/fun_str.py new file mode 100755 index 0000000..3cfe46b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_str.py @@ -0,0 +1,5 @@ +# test str of function + +def f(): + pass +print(str(f)[:8]) diff --git a/src/openmv/src/micropython/tests/basics/fun_varargs.py b/src/openmv/src/micropython/tests/basics/fun_varargs.py new file mode 100755 index 0000000..ff29c33 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/fun_varargs.py @@ -0,0 +1,41 @@ +# function with just varargs +def f1(*args): + print(args) + +f1() +f1(1) +f1(1, 2) + +# function with 1 arg, then varargs +def f2(a, *args): + print(a, args) + +f2(1) +f2(1, 2) +f2(1, 2, 3) + +# function with 2 args, then varargs +def f3(a, b, *args): + print(a, b, args) + +f3(1, 2) +f3(1, 2, 3) +f3(1, 2, 3, 4) + +# function with 1 default arg, then varargs +def f4(a=0, *args): + print(a, args) + +f4() +f4(1) +f4(1, 2) +f4(1, 2, 3) + +# function with 1 arg, 1 default arg, then varargs +def f5(a, b=0, *args): + print(a, b, args) + +f5(1) +f5(1, 2) +f5(1, 2, 3) +f5(1, 2, 3, 4) diff --git a/src/openmv/src/micropython/tests/basics/gc1.py b/src/openmv/src/micropython/tests/basics/gc1.py new file mode 100755 index 0000000..332bf97 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gc1.py @@ -0,0 +1,34 @@ +# basic tests for gc module + +try: + import gc +except ImportError: + print("SKIP") + raise SystemExit + +print(gc.isenabled()) +gc.disable() +print(gc.isenabled()) +gc.enable() +print(gc.isenabled()) + +gc.collect() + +if hasattr(gc, 'mem_free'): + # uPy has these extra functions + # just test they execute and return an int + assert type(gc.mem_free()) is int + assert type(gc.mem_alloc()) is int + +if hasattr(gc, 'threshold'): + # uPy has this extra function + # check execution and returns + assert(gc.threshold(1) is None) + assert(gc.threshold() == 0) + assert(gc.threshold(-1) is None) + assert(gc.threshold() == -1) + + # Setting a low threshold should trigger collection at the list alloc + gc.threshold(1) + [[], []] + gc.threshold(-1) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from.py b/src/openmv/src/micropython/tests/basics/gen_yield_from.py new file mode 100755 index 0000000..037644e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from.py @@ -0,0 +1,27 @@ +# Case of terminating subgen using return with value +def gen(): + yield 1 + yield 2 + return 3 + +def gen2(): + print("here1") + print((yield from gen())) + print("here2") + +g = gen2() +print(list(g)) + + +# StopIteration from within a Python function, within a native iterator (map), within a yield from +def gen7(x): + if x < 3: + return x + else: + raise StopIteration(444) + +def gen8(): + print((yield from map(gen7, range(100)))) + +g = gen8() +print(list(g)) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_close.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_close.py new file mode 100755 index 0000000..e3e0116 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_close.py @@ -0,0 +1,123 @@ +def gen(): + yield 1 + yield 2 + yield 3 + yield 4 + +def gen2(): + yield -1 + print((yield from gen())) + yield 10 + yield 11 + +g = gen2() +print(next(g)) +print(next(g)) +g.close() +try: + print(next(g)) +except StopIteration: + print("StopIteration") + + +# Now variation of same test, but with leaf generator +# swallowing GeneratorExit exception - its upstream gen +# generator should still receive one. +def gen3(): + yield 1 + try: + yield 2 + except GeneratorExit: + print("leaf caught GeneratorExit and swallowed it") + return + yield 3 + yield 4 + +def gen4(): + yield -1 + try: + print((yield from gen3())) + except GeneratorExit: + print("delegating caught GeneratorExit") + raise + yield 10 + yield 11 + +g = gen4() +print(next(g)) +print(next(g)) +print(next(g)) +g.close() +try: + print(next(g)) +except StopIteration: + print("StopIteration") + + +# Yet another variation - leaf generator gets GeneratorExit, +# and reraises a new GeneratorExit. This still should close chain properly. +def gen5(): + yield 1 + try: + yield 2 + except GeneratorExit: + print("leaf caught GeneratorExit and reraised GeneratorExit") + raise GeneratorExit(123) + yield 3 + yield 4 + +def gen6(): + yield -1 + try: + print((yield from gen5())) + except GeneratorExit: + print("delegating caught GeneratorExit") + raise + yield 10 + yield 11 + +g = gen6() +print(next(g)) +print(next(g)) +print(next(g)) +g.close() +try: + print(next(g)) +except StopIteration: + print("StopIteration") + +# case where generator ignores the close request and yields instead +def gen7(): + try: + yield 123 + except GeneratorExit: + yield 456 + +g = gen7() +print(next(g)) +try: + g.close() +except RuntimeError: + print('RuntimeError') + +# case where close is propagated up to a built-in iterator +def gen8(): + g = range(2) + yield from g +g = gen8() +print(next(g)) +g.close() + +# case with a user-defined close method +class Iter: + def __iter__(self): + return self + def __next__(self): + return 1 + def close(self): + print('close') +def gen9(): + yield from Iter() +g = gen9() +print(next(g)) +g.close() diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_ducktype.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_ducktype.py new file mode 100755 index 0000000..c02ec67 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_ducktype.py @@ -0,0 +1,66 @@ +class MyGen: + + def __init__(self): + self.v = 0 + + def __iter__(self): + return self + + def __next__(self): + self.v += 1 + if self.v > 5: + raise StopIteration + return self.v + +def gen(): + yield from MyGen() + +def gen2(): + yield from gen() + +print(list(gen())) +print(list(gen2())) + + +class Incrementer: + + def __iter__(self): + return self + + def __next__(self): + return self.send(None) + + def send(self, val): + if val is None: + return "Incrementer initialized" + return val + 1 + +def gen3(): + yield from Incrementer() + +g = gen3() +print(next(g)) +print(g.send(5)) +print(g.send(100)) + + +# +# Test proper handling of StopIteration vs other exceptions +# +class MyIter: + def __iter__(self): + return self + def __next__(self): + raise StopIteration(42) + +def gen4(): + global ret + ret = yield from MyIter() + 1//0 + +ret = None +try: + print(list(gen4())) +except ZeroDivisionError: + print("ZeroDivisionError") +print(ret) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_exc.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_exc.py new file mode 100755 index 0000000..01c954f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_exc.py @@ -0,0 +1,13 @@ +def gen(): + yield 1 + yield 2 + raise ValueError + +def gen2(): + try: + print((yield from gen())) + except ValueError: + print("caught ValueError from downstream") + +g = gen2() +print(list(g)) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_executing.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_executing.py new file mode 100755 index 0000000..cad0c76 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_executing.py @@ -0,0 +1,15 @@ +# yielding from an already executing generator is not allowed + +def f(): + yield 1 + # g here is already executing so this will raise an exception + yield from g + +g = f() + +print(next(g)) + +try: + next(g) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_iter.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_iter.py new file mode 100755 index 0000000..be76572 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_iter.py @@ -0,0 +1,13 @@ +def gen(): + yield from (1, 2, 3) + +def gen2(): + yield from gen() + +def gen3(): + yield from (4, 5) + yield 6 + +print(list(gen())) +print(list(gen2())) +print(list(gen3())) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_send.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_send.py new file mode 100755 index 0000000..c2e94b5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_send.py @@ -0,0 +1,14 @@ +def gen(): + print("sent:", (yield 1)) + yield 2 + +def gen2(): + print((yield from gen())) + +g = gen2() +next(g) +print("yielded:", g.send("val")) +try: + next(g) +except StopIteration: + print("StopIteration") diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_stopped.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_stopped.py new file mode 100755 index 0000000..468679b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_stopped.py @@ -0,0 +1,18 @@ +# Yielding from stopped generator is ok and results in None + +def gen(): + return 1 + # This yield is just to make this a generator + yield + +f = gen() + +def run(): + print((yield from f)) + print((yield from f)) + print((yield from f)) + +try: + next(run()) +except StopIteration: + print("StopIteration") diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_throw.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw.py new file mode 100755 index 0000000..703158f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw.py @@ -0,0 +1,18 @@ +def gen(): + try: + yield 1 + except ValueError: + print("got ValueError from upstream!") + yield "str1" + raise TypeError + +def gen2(): + print((yield from gen())) + +g = gen2() +print(next(g)) +print(g.throw(ValueError)) +try: + print(next(g)) +except TypeError: + print("got TypeError from downstream!") diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_throw2.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw2.py new file mode 100755 index 0000000..6b59a78 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw2.py @@ -0,0 +1,24 @@ +# outer generator ignores a thrown GeneratorExit (this is allowed) + +def gen(): + try: + yield 123 + except GeneratorExit: + print('GeneratorExit') + +def gen2(): + try: + yield from gen() + except GeneratorExit: + print('GeneratorExit outer') + yield 789 + +# thrown a class +g = gen2() +print(next(g)) +print(g.throw(GeneratorExit)) + +# thrown an instance +g = gen2() +print(next(g)) +print(g.throw(GeneratorExit())) diff --git a/src/openmv/src/micropython/tests/basics/gen_yield_from_throw3.py b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw3.py new file mode 100755 index 0000000..85b6f71 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/gen_yield_from_throw3.py @@ -0,0 +1,57 @@ +# yield-from a user-defined generator with a throw() method + +class Iter: + def __iter__(self): + return self + + def __next__(self): + return 1 + + def throw(self, x): + print('throw', x) + return 456 + +def gen(): + yield from Iter() + +# calling close() should not call throw() +g = gen() +print(next(g)) +g.close() + +# can throw a non-exception object +g = gen() +print(next(g)) +print(g.throw(123)) + +# throwing an exception class just injects that class +g = gen() +print(next(g)) +print(g.throw(ZeroDivisionError)) + +# this user-defined generator doesn't have a throw() method +class Iter2: + def __iter__(self): + return self + + def __next__(self): + return 1 + +def gen2(): + yield from Iter2() + +# the thrown ValueError is not intercepted by the user class +g = gen2() +print(next(g)) +try: + g.throw(ValueError) +except: + print('ValueError') + +# the thrown 123 is not an exception so raises a TypeError +g = gen2() +print(next(g)) +try: + g.throw(123) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/generator1.py b/src/openmv/src/micropython/tests/basics/generator1.py new file mode 100755 index 0000000..ea1d3b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator1.py @@ -0,0 +1,25 @@ +def f(x): + print('a') + y = x + print('b') + while y > 0: + print('c') + y -= 1 + print('d') + yield y + print('e') + print('f') + return None + +for val in f(3): + print(val) + +#gen = f(3) +#print(gen) +#print(gen.__next__()) +#print(gen.__next__()) +#print(gen.__next__()) +#print(gen.__next__()) + +# test printing, but only the first chars that match CPython +print(repr(f(0))[0:17]) diff --git a/src/openmv/src/micropython/tests/basics/generator2.py b/src/openmv/src/micropython/tests/basics/generator2.py new file mode 100755 index 0000000..0dfc98a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator2.py @@ -0,0 +1,3 @@ +gen = (i for i in range(10)) +for i in gen: + print(i) diff --git a/src/openmv/src/micropython/tests/basics/generator_args.py b/src/openmv/src/micropython/tests/basics/generator_args.py new file mode 100755 index 0000000..608210b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_args.py @@ -0,0 +1,17 @@ +# Handling of "complicated" arg forms to generators +# https://github.com/micropython/micropython/issues/397 +def gen(v=5): + for i in range(v): + yield i + +print(list(gen())) +print(list(gen(v=10))) + + +def g(*args, **kwargs): + for i in args: + yield i + for k, v in kwargs.items(): + yield (k, v) + +print(list(g(1, 2, 3, foo="bar"))) diff --git a/src/openmv/src/micropython/tests/basics/generator_close.py b/src/openmv/src/micropython/tests/basics/generator_close.py new file mode 100755 index 0000000..1ccc78d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_close.py @@ -0,0 +1,60 @@ +def gen1(): + yield 1 + yield 2 + +# Test that it's possible to close just created gen +g = gen1() +print(g.close()) +try: + next(g) +except StopIteration: + print("StopIteration") + +# Test that it's possible to close gen in progress +g = gen1() +print(next(g)) +print(g.close()) +try: + next(g) + print("No StopIteration") +except StopIteration: + print("StopIteration") + +# Test that it's possible to close finished gen +g = gen1() +print(list(g)) +print(g.close()) +try: + next(g) + print("No StopIteration") +except StopIteration: + print("StopIteration") + + +# Throwing GeneratorExit in response to close() is ok +def gen2(): + try: + yield 1 + yield 2 + except: + print('raising GeneratorExit') + raise GeneratorExit + +g = gen2() +next(g) +print(g.close()) + +# Any other exception is propagated to the .close() caller +def gen3(): + try: + yield 1 + yield 2 + except: + raise ValueError + +g = gen3() +next(g) +try: + print(g.close()) +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/generator_closure.py b/src/openmv/src/micropython/tests/basics/generator_closure.py new file mode 100755 index 0000000..ecf524a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_closure.py @@ -0,0 +1,32 @@ +# a generator that closes over outer variables +def f(): + x = 1 # closed over by g + def g(): + yield x + yield x + 1 + return g() +for i in f(): + print(i) + +# a generator that has its variables closed over +def f(): + x = 1 # closed over by g + def g(): + return x + 1 + yield g() + x = 2 + yield g() +for i in f(): + print(i) + +# using comprehensions, the inner generator closes over y +generator_of_generators = (((x, y) for x in range(2)) for y in range(3)) +for i in generator_of_generators: + for j in i: + print(j) + +# test that printing of closed-over generators doesn't lead to segfaults +def genc(): + foo = 1 + repr(lambda: (yield foo)) +genc() diff --git a/src/openmv/src/micropython/tests/basics/generator_exc.py b/src/openmv/src/micropython/tests/basics/generator_exc.py new file mode 100755 index 0000000..09aca5d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_exc.py @@ -0,0 +1,53 @@ +# Test proper handling of exceptions within generator across yield +def gen(): + try: + yield 1 + raise ValueError + except ValueError: + print("Caught") + yield 2 + +for i in gen(): + print(i) + + +# Test throwing exceptions out of generator +def gen2(): + yield 1 + raise ValueError + yield 2 + yield 3 + +g = gen2() +print(next(g)) +try: + print(next(g)) +except ValueError: + print("ValueError") + +try: + print(next(g)) +except StopIteration: + print("StopIteration") + + +# Test throwing exception into generator +def gen3(): + yield 1 + try: + yield 2 + except ValueError: + print("ValueError received") + yield 3 + yield 4 + yield 5 + +g = gen3() +print(next(g)) +print(next(g)) +print("out of throw:", g.throw(ValueError)) +print(next(g)) +try: + print("out of throw2:", g.throw(ValueError)) +except ValueError: + print("Boomerang ValueError caught") diff --git a/src/openmv/src/micropython/tests/basics/generator_name.py b/src/openmv/src/micropython/tests/basics/generator_name.py new file mode 100755 index 0000000..77259a8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_name.py @@ -0,0 +1,16 @@ +# test __name__ on generator functions + +def Fun(): + yield + +class A: + def Fun(self): + yield + +try: + print(Fun.__name__) + print(A.Fun.__name__) + print(A().Fun.__name__) +except AttributeError: + print('SKIP') + raise SystemExit diff --git a/src/openmv/src/micropython/tests/basics/generator_pend_throw.py b/src/openmv/src/micropython/tests/basics/generator_pend_throw.py new file mode 100755 index 0000000..f00ff79 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_pend_throw.py @@ -0,0 +1,31 @@ +def gen(): + i = 0 + while 1: + yield i + i += 1 + +g = gen() + +try: + g.pend_throw +except AttributeError: + print("SKIP") + raise SystemExit + + +print(next(g)) +print(next(g)) +g.pend_throw(ValueError()) + +v = None +try: + v = next(g) +except Exception as e: + print("raised", repr(e)) + +print("ret was:", v) + +try: + gen().pend_throw(ValueError()) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/generator_pend_throw.py.exp b/src/openmv/src/micropython/tests/basics/generator_pend_throw.py.exp new file mode 100755 index 0000000..ed4d882 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_pend_throw.py.exp @@ -0,0 +1,5 @@ +0 +1 +raised ValueError() +ret was: None +TypeError diff --git a/src/openmv/src/micropython/tests/basics/generator_pep479.py b/src/openmv/src/micropython/tests/basics/generator_pep479.py new file mode 100755 index 0000000..e422c34 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_pep479.py @@ -0,0 +1,29 @@ +# tests for correct PEP479 behaviour (introduced in Python 3.5) + +# basic case: StopIteration is converted into a RuntimeError +def gen(): + yield 1 + raise StopIteration +g = gen() +print(next(g)) +try: + next(g) +except RuntimeError: + print('RuntimeError') + +# trying to continue a failed generator now raises StopIteration +try: + next(g) +except StopIteration: + print('StopIteration') + +# throwing a StopIteration which is uncaught will be converted into a RuntimeError +def gen(): + yield 1 + yield 2 +g = gen() +print(next(g)) +try: + g.throw(StopIteration) +except RuntimeError: + print('RuntimeError') diff --git a/src/openmv/src/micropython/tests/basics/generator_pep479.py.exp b/src/openmv/src/micropython/tests/basics/generator_pep479.py.exp new file mode 100755 index 0000000..c64fe49 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_pep479.py.exp @@ -0,0 +1,5 @@ +1 +RuntimeError +StopIteration +1 +RuntimeError diff --git a/src/openmv/src/micropython/tests/basics/generator_return.py b/src/openmv/src/micropython/tests/basics/generator_return.py new file mode 100755 index 0000000..2b3464a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_return.py @@ -0,0 +1,16 @@ +def gen(): + yield 1 + return 42 + +g = gen() +print(next(g)) +try: + print(next(g)) +except StopIteration as e: + print(type(e), e.args) + +# trying next again should raise StopIteration with no arguments +try: + print(next(g)) +except StopIteration as e: + print(type(e), e.args) diff --git a/src/openmv/src/micropython/tests/basics/generator_send.py b/src/openmv/src/micropython/tests/basics/generator_send.py new file mode 100755 index 0000000..c472c31 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_send.py @@ -0,0 +1,37 @@ +def f(): + n = 0 + while True: + n = yield n + 1 + print(n) + +g = f() +try: + g.send(1) +except TypeError: + print("caught") + +print(g.send(None)) +print(g.send(100)) +print(g.send(200)) + + +def f2(): + print("entering") + for i in range(3): + print(i) + yield + print("returning 1") + print("returning 2") + +g = f2() +g.send(None) +g.send(1) +g.send(1) +try: + g.send(1) +except StopIteration: + print("caught") +try: + g.send(1) +except StopIteration: + print("caught") diff --git a/src/openmv/src/micropython/tests/basics/generator_throw.py b/src/openmv/src/micropython/tests/basics/generator_throw.py new file mode 100755 index 0000000..bf5ff33 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/generator_throw.py @@ -0,0 +1,43 @@ +# case where generator doesn't intercept the thrown/injected exception +def gen(): + yield 123 + yield 456 + +g = gen() +print(next(g)) +try: + g.throw(KeyError) +except KeyError: + print('got KeyError from downstream!') + +# case where a thrown exception is caught and stops the generator +def gen(): + try: + yield 1 + yield 2 + except: + pass +g = gen() +print(next(g)) +try: + g.throw(ValueError) +except StopIteration: + print('got StopIteration') + +# generator ignores a thrown GeneratorExit (this is allowed) +def gen(): + try: + yield 123 + except GeneratorExit: + print('GeneratorExit') + yield 456 + +# thrown a class +g = gen() +print(next(g)) +print(g.throw(GeneratorExit)) + +# thrown an instance +g = gen() +print(next(g)) +print(g.throw(GeneratorExit())) diff --git a/src/openmv/src/micropython/tests/basics/getattr.py b/src/openmv/src/micropython/tests/basics/getattr.py new file mode 100755 index 0000000..2257da3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/getattr.py @@ -0,0 +1,28 @@ +# test __getattr__ + +class A: + def __init__(self, d): + self.d = d + + def __getattr__(self, attr): + return self.d[attr] + +a = A({'a':1, 'b':2}) +print(a.a, a.b) + +# test that any exception raised in __getattr__ propagates out +class A: + def __getattr__(self, attr): + if attr == "value": + raise ValueError(123) + else: + raise AttributeError(456) +a = A() +try: + a.value +except ValueError as er: + print(er) +try: + a.attr +except AttributeError as er: + print(er) diff --git a/src/openmv/src/micropython/tests/basics/getitem.py b/src/openmv/src/micropython/tests/basics/getitem.py new file mode 100755 index 0000000..4944641 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/getitem.py @@ -0,0 +1,38 @@ +# create a class that has a __getitem__ method +class A: + def __getitem__(self, index): + print('getitem', index) + if index > 10: + raise StopIteration + +# test __getitem__ +A()[0] +A()[1] + +# iterate using a for loop +for i in A(): + pass + +# iterate manually +it = iter(A()) +try: + while True: + next(it) +except StopIteration: + pass + +# this class raises an IndexError to stop the iteration +class A: + def __getitem__(self, i): + raise IndexError +print(list(A())) + +# this class raises a non-StopIteration exception on iteration +class A: + def __getitem__(self, i): + raise TypeError +try: + for i in A(): + pass +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/globals_del.py b/src/openmv/src/micropython/tests/basics/globals_del.py new file mode 100755 index 0000000..a1638ac --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/globals_del.py @@ -0,0 +1,27 @@ +""" +1 +""" + +def _f(): pass +FunctionType = type(_f) +LambdaType = type(lambda: None) +CodeType = None +MappingProxyType = None +SimpleNamespace = None + +def _g(): + yield 1 +GeneratorType = type(_g()) + +class _C: + def _m(self): pass +MethodType = type(_C()._m) + +BuiltinFunctionType = type(len) +BuiltinMethodType = type([].append) + +del _f + +# print only the first 8 chars, since we have different str rep to CPython +print(str(FunctionType)[:8]) +print(str(BuiltinFunctionType)[:8]) diff --git a/src/openmv/src/micropython/tests/basics/ifcond.py b/src/openmv/src/micropython/tests/basics/ifcond.py new file mode 100755 index 0000000..9264aa7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/ifcond.py @@ -0,0 +1,92 @@ +# test if conditions which are optimised by the compiler + +if 0: + print(5) +else: + print(6) + +if 1: + print(7) + +if 2: + print(8) + +if -1: + print(9) +elif 1: + print(10) + +if 0: + print(11) +else: + print(12) + +if 0: + print(13) +elif 1: + print(14) + +if 0: + print(15) +elif 0: + print(16) +else: + print(17) + +if not False: + print('a') + +if not True: + print('a') +else: + print('b') + +if False: + print('a') +else: + print('b') + +if True: + print('a') + +if (1,): + print('a') + +if not (1,): + print('a') +else: + print('b') + +f2 = 0 + +def f(t1, t2, f1): + if False: + print(1) + if True: + print(1) + if (): + print(1) + if (1,): + print(1) + if (1, 2): + print(1) + if t1 and t2: + print(1) + if (t1 and t2): # parsed differently to above + print(1) + if not (t1 and f1): + print(1) + if t1 or t2: + print(1) + if (t1 or t2): # parse differently to above + print(1) + if f1 or t1: + print(1) + if not (f1 or f2): + print(1) + if t1 and f1 or t1 and t2: + print(1) + if (f1 or t1) and (f2 or t2): + print(1) + +f(True, 1, False) diff --git a/src/openmv/src/micropython/tests/basics/ifexpr.py b/src/openmv/src/micropython/tests/basics/ifexpr.py new file mode 100755 index 0000000..66f94f9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/ifexpr.py @@ -0,0 +1,9 @@ +# test if-expressions + +print(1 if 0 else 2) +print(3 if 1 else 4) + +def f(x): + print('a' if x else 'b') +f([]) +f([1]) diff --git a/src/openmv/src/micropython/tests/basics/int1.py b/src/openmv/src/micropython/tests/basics/int1.py new file mode 100755 index 0000000..2d92105 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int1.py @@ -0,0 +1,90 @@ +print(int(False)) +print(int(True)) + +print(int(0)) +print(int(1)) +print(int(+1)) +print(int(-1)) + +print(int('0')) +print(int('+0')) +print(int('-0')) +print(int('1')) +print(int('+1')) +print(int('-1')) +print(int('01')) +print(int('9')) +print(int('10')) +print(int('+10')) +print(int('-10')) +print(int('12')) +print(int('-12')) +print(int('99')) +print(int('100')) +print(int('314')) +print(int(' 314')) +print(int('314 ')) +print(int(' \t\t 314 \t\t ')) +print(int(' 1 ')) +print(int(' -3 ')) + +print(int('0', 10)) +print(int('1', 10)) +print(int(' \t 1 \t ', 10)) +print(int('11', 10)) +print(int('11', 16)) +print(int('11', 8)) +print(int('11', 2)) +print(int('11', 36)) +print(int('xyz', 36)) +print(int('0o123', 0)) +print(int('8388607')) +print(int('0x123', 16)) +print(int('0X123', 16)) +print(int('0A', 16)) +print(int('0o123', 8)) +print(int('0O123', 8)) +print(int('0123', 8)) +print(int('0b100', 2)) +print(int('0B100', 2)) +print(int('0100', 2)) +print(int(' \t 0o12', 8)) +print(int('0o12 \t ', 8)) +print(int(b"12", 10)) +print(int(b"12")) + + +def test(value, base): + try: + print(int(value, base)) + except ValueError: + print('ValueError') + + +test('x', 0) +test('1x', 0) +test(' 1x', 0) +test(' 1' + chr(2) + ' ', 0) +test('', 0) +test(' ', 0) +test(' \t\t ', 0) +test('0x', 16) +test('0x', 0) +test('0o', 8) +test('0o', 0) +test('0b', 2) +test('0b', 0) +test('0b2', 2) +test('0o8', 8) +test('0xg', 16) +test('1 1', 16) +test('123', 37) + +# check that we don't parse this as a floating point number +print(0x1e+1) + +# can't convert list to int +try: + int([]) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/int2.py b/src/openmv/src/micropython/tests/basics/int2.py new file mode 100755 index 0000000..9ef20f9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int2.py @@ -0,0 +1,7 @@ +# test basic int operations + +# test conversion of bool on RHS of binary op +a = False +print(1 + a) +a = True +print(1 + a) diff --git a/src/openmv/src/micropython/tests/basics/int_big1.py b/src/openmv/src/micropython/tests/basics/int_big1.py new file mode 100755 index 0000000..40d16c4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big1.py @@ -0,0 +1,110 @@ +# to test arbitrariy precision integers + +x = 1000000000000000000000000000000 +xn = -1000000000000000000000000000000 +y = 2000000000000000000000000000000 + +# printing +print(x) +print(y) +print('%#X' % (x - x)) # print prefix +print('{:#,}'.format(x)) # print with commas + +# addition +print(x + 1) +print(x + y) +print(x + xn == 0) +print(bool(x + xn)) + +# subtraction +print(x - 1) +print(x - y) +print(y - x) +print(x - x == 0) +print(bool(x - x)) + +# multiplication +print(x * 2) +print(x * y) + +# integer division +print(x // 2) +print(y // x) + +# bit inversion +print(~x) +print(~(-x)) + +# left shift +x = 0x10000000000000000000000 +for i in range(32): + x = x << 1 + print(x) + +# right shift +x = 0x10000000000000000000000 +for i in range(32): + x = x >> 1 + print(x) + +# left shift of a negative number +for i in range(8): + print(-10000000000000000000000000 << i) + print(-10000000000000000000000001 << i) + print(-10000000000000000000000002 << i) + print(-10000000000000000000000003 << i) + print(-10000000000000000000000004 << i) + +# right shift of a negative number +for i in range(8): + print(-10000000000000000000000000 >> i) + print(-10000000000000000000000001 >> i) + print(-10000000000000000000000002 >> i) + print(-10000000000000000000000003 >> i) + print(-10000000000000000000000004 >> i) + +# conversion from string +print(int("123456789012345678901234567890")) +print(int("-123456789012345678901234567890")) +print(int("123456789012345678901234567890abcdef", 16)) +print(int("123456789012345678901234567890ABCDEF", 16)) +print(int("1234567890abcdefghijklmnopqrstuvwxyz", 36)) + +# invalid characters in string +try: + print(int("123456789012345678901234567890abcdef")) +except ValueError: + print('ValueError'); +try: + print(int("123456789012345678901234567890\x01")) +except ValueError: + print('ValueError'); + +# test constant integer with more than 255 chars +x = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d1aaaaaaa +print(x) + +# test parsing ints just on threshold of small to big +# for 32 bit archs +x = 1073741823 # small +x = -1073741823 # small +x = 1073741824 # big +x = -1073741824 # big +# for nan-boxing with 47-bit small ints +print(int('0x3fffffffffff', 16)) # small +print(int('-0x3fffffffffff', 16)) # small +print(int('0x400000000000', 16)) # big +print(int('-0x400000000000', 16)) # big +# for 64 bit archs +x = 4611686018427387903 # small +x = -4611686018427387903 # small +x = 4611686018427387904 # big +x = -4611686018427387904 # big + +# sys.maxsize is a constant mpz, so test it's compatible with dynamic ones +import sys +print(sys.maxsize + 1 - 1 == sys.maxsize) + +# test extraction of big int value via mp_obj_get_int_maybe +x = 1 << 70 +print('a' * (x + 4 - x)) diff --git a/src/openmv/src/micropython/tests/basics/int_big_add.py b/src/openmv/src/micropython/tests/basics/int_big_add.py new file mode 100755 index 0000000..b64b76f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_add.py @@ -0,0 +1,16 @@ +# tests transition from small to large int representation by addition + +# 31-bit overflow +i = 0x3fffffff +print(i + i) +print(-i + -i) + +# 47-bit overflow +i = 0x3fffffffffff +print(i + i) +print(-i + -i) + +# 63-bit overflow +i = 0x3fffffffffffffff +print(i + i) +print(-i + -i) diff --git a/src/openmv/src/micropython/tests/basics/int_big_and.py b/src/openmv/src/micropython/tests/basics/int_big_and.py new file mode 100755 index 0000000..062a4f2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_and.py @@ -0,0 +1,41 @@ +print(0 & (1 << 80)) +print(0 & (1 << 80) == 0) +print(bool(0 & (1 << 80))) + +a = 0xfffffffffffffffffffffffffffff +print(a & (1 << 80)) +print((a & (1 << 80)) >> 80) +print((a & (1 << 80)) >> 80 == 1) + +# test negative on rhs +a = 123456789012345678901234567890 +print(a & -1) +print(a & -2) +print(a & -2345678901234567890123456789) +print(a & (-a)) +print(a & (-a - 1)) +print(a & (-a + 1)) + +# test negative on lhs +a = 123456789012345678901234567890 +print(-1 & a) +print(-2 & a) +print(-2345678901234567890123456789 & a) +print((-a) & a) +print((-a) & 0xffffffff) +print((-a) & 0xffffffffffffffffffffffffffffffff) +print((-a) & 2) +print((-(1 << 70)) & 2) + +# test negative on lhs and rhs +mpz = 1 << 70 +a = 123456789012345678901234567890 +print(-1 & (-a)) +print(-2 & (-a)) +print(-2345678901234567890123456789 & (-a)) +print((-a) & (-a)) +print((-a) & (-0xffffffff)) +print((-a) & (-0xffffffffffffffffffffffffffffffff)) +print((-1) & (-0xffffffffffffffffffffffffffffffff)) +print((-a) & (-2)) +print((-mpz) & (-2)) diff --git a/src/openmv/src/micropython/tests/basics/int_big_and2.py b/src/openmv/src/micropython/tests/basics/int_big_and2.py new file mode 100755 index 0000000..f8c81fe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_and2.py @@ -0,0 +1,51 @@ +# test + + + +print( 97989513389222316022151446562729620153292831887555425160965597396 + & 23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + & 37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + & 98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + & 15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + & 63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + & 59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + & 86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + & 9487909752) + +# test - - + +print( -97989513389222316022151446562729620153292831887555425160965597396 + & -23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + & -37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + & -98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + & -15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + & -63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + & -59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + & -86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + & -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_and3.py b/src/openmv/src/micropython/tests/basics/int_big_and3.py new file mode 100755 index 0000000..788ecd8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_and3.py @@ -0,0 +1,51 @@ +# test - + + +print( -97989513389222316022151446562729620153292831887555425160965597396 + & 23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + & 37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + & 98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + & 15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + & 63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + & 59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + & 86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + & 9487909752) + +# test + - + +print( 97989513389222316022151446562729620153292831887555425160965597396 + & -23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + & -37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + & -98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + & -15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + & -63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + & -59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + & -86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + & -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_cmp.py b/src/openmv/src/micropython/tests/basics/int_big_cmp.py new file mode 100755 index 0000000..7cb7412 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_cmp.py @@ -0,0 +1,10 @@ +# test bignum comparisons + +i = 1 << 65 + +print(i == 0) +print(i != 0) +print(i < 0) +print(i > 0) +print(i <= 0) +print(i >= 0) diff --git a/src/openmv/src/micropython/tests/basics/int_big_div.py b/src/openmv/src/micropython/tests/basics/int_big_div.py new file mode 100755 index 0000000..642f051 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_div.py @@ -0,0 +1,10 @@ +for lhs in (1000000000000000000000000, 10000000000100000000000000, 10012003400000000000000007, 12349083434598210349871029923874109871234789): + for rhs in range(1, 555): + print(lhs // rhs) + +# these check an edge case on 64-bit machines where two mpz limbs +# are used and the most significant one has the MSB set +x = 0x8000000000000000 +print((x + 1) // x) +x = 0x86c60128feff5330 +print((x + 1) // x) diff --git a/src/openmv/src/micropython/tests/basics/int_big_error.py b/src/openmv/src/micropython/tests/basics/int_big_error.py new file mode 100755 index 0000000..79809ae --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_error.py @@ -0,0 +1,41 @@ +# test errors operating on bignum + +i = 1 << 65 + +try: + i << -1 +except ValueError: + print("ValueError") + +try: + len(i) +except TypeError: + print("TypeError") + +try: + 1 in i +except TypeError: + print("TypeError") + +# overflow because arg of bytearray is being converted to machine int +try: + bytearray(i) +except OverflowError: + print('OverflowError') + +# to test conversion of negative mpz to machine int +# (we know << will convert to machine int, even though it fails to do the shift) +try: + i << (-(i >> 40)) +except ValueError: + print('ValueError') + +try: + i // 0 +except ZeroDivisionError: + print('ZeroDivisionError') + +try: + i % 0 +except ZeroDivisionError: + print('ZeroDivisionError') diff --git a/src/openmv/src/micropython/tests/basics/int_big_lshift.py b/src/openmv/src/micropython/tests/basics/int_big_lshift.py new file mode 100755 index 0000000..14db90b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_lshift.py @@ -0,0 +1,20 @@ +# tests transition from small to large int representation by left-shift operation +for i in range(1, 17): + for shift in range(70): + print(i, '<<', shift, '=', i << shift) + +# test bit-shifting negative integers +for i in range(8): + print(-100000000000000000000000000000 << i) + print(-100000000000000000000000000001 << i) + print(-100000000000000000000000000002 << i) + print(-100000000000000000000000000003 << i) + print(-100000000000000000000000000004 << i) + print(-100000000000000000000000000000 >> i) + print(-100000000000000000000000000001 >> i) + print(-100000000000000000000000000002 >> i) + print(-100000000000000000000000000003 >> i) + print(-100000000000000000000000000004 >> i) + +# shl by zero +print((1<<70) << 0) diff --git a/src/openmv/src/micropython/tests/basics/int_big_mod.py b/src/openmv/src/micropython/tests/basics/int_big_mod.py new file mode 100755 index 0000000..e87221c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_mod.py @@ -0,0 +1,17 @@ +# test % operation on big integers + +delta = 100000000000000000000000000000012345 + +for i in range(11): + for j in range(11): + x = delta * (i - 5) + y = delta * (j - 5) + if y != 0: + print(x % y) + +# these check an edge case on 64-bit machines where two mpz limbs +# are used and the most significant one has the MSB set +x = 0x8000000000000000 +print((x + 1) % x) +x = 0x86c60128feff5330 +print((x + 1) % x) diff --git a/src/openmv/src/micropython/tests/basics/int_big_mul.py b/src/openmv/src/micropython/tests/basics/int_big_mul.py new file mode 100755 index 0000000..6010075 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_mul.py @@ -0,0 +1,23 @@ +# tests transition from small to large int representation by multiplication +for rhs in range(2, 11): + lhs = 1 + for k in range(100): + res = lhs * rhs + print(lhs, '*', rhs, '=', res) + lhs = res + +# below tests pos/neg combinations that overflow small int + +# 31-bit overflow +i = 1 << 20 +print(i * i) +print(i * -i) +print(-i * i) +print(-i * -i) + +# 63-bit overflow +i = 1 << 40 +print(i * i) +print(i * -i) +print(-i * i) +print(-i * -i) diff --git a/src/openmv/src/micropython/tests/basics/int_big_or.py b/src/openmv/src/micropython/tests/basics/int_big_or.py new file mode 100755 index 0000000..17d9935 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_or.py @@ -0,0 +1,45 @@ +print(0 | (1 << 80)) + +a = 0xfffffffffffffffffffffffffffff +print(a | (1 << 200)) + +# test + + + +print(0 | (1 << 80)) +print((1 << 80) | (1 << 80)) +print((1 << 80) | 0) + +a = 0xfffffffffffffffffffffffffffff +print(a | (1 << 100)) +print(a | (1 << 200)) +print(a | a == 0) +print(bool(a | a)) + +# test - + + +print((-1 << 80) | (1 << 80)) +print((-1 << 80) | 0) + +print((-a) | (1 << 100)) +print((-a) | (1 << 200)) +print((-a) | a == 0) +print(bool((-a) | a)) + +# test + - + +print(0 | (-1 << 80)) +print((1 << 80) | (-1 << 80)) + +print(a | (-1 << 100)) +print(a | (-1 << 200)) +print(a | (-a) == 0) +print(bool(a | (-a))) + +# test - - + +print((-1 << 80) | (-1 << 80)) + +print((-a) | (-1 << 100)) +print((-a) | (-1 << 200)) +print((-a) | (-a) == 0) +print(bool((-a) | (-a))) diff --git a/src/openmv/src/micropython/tests/basics/int_big_or2.py b/src/openmv/src/micropython/tests/basics/int_big_or2.py new file mode 100755 index 0000000..2554951 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_or2.py @@ -0,0 +1,50 @@ +# test + + +print( 97989513389222316022151446562729620153292831887555425160965597396 + | 23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + | 37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + | 98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + | 15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + | 63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + | 59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + | 86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + | 9487909752) + +# test - - + +print( -97989513389222316022151446562729620153292831887555425160965597396 + | -23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + | -37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + | -98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + | -15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + | -63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + | -59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + | -86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + | -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_or3.py b/src/openmv/src/micropython/tests/basics/int_big_or3.py new file mode 100755 index 0000000..07edaea --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_or3.py @@ -0,0 +1,51 @@ +# test - + + +print( -97989513389222316022151446562729620153292831887555425160965597396 + | 23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + | 37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + | 98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + | 15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + | 63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + | 59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + | 86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + | 9487909752) + +# test + - + +print( 97989513389222316022151446562729620153292831887555425160965597396 + | -23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + | -37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + | -98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + | -15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + | -63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + | -59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + | -86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + | -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_pow.py b/src/openmv/src/micropython/tests/basics/int_big_pow.py new file mode 100755 index 0000000..0f75e31 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_pow.py @@ -0,0 +1,8 @@ +# test bignum power + +i = 1 << 65 + +print(0 ** i) +print(i ** 0) +print(i ** 1) +print(i ** 2) diff --git a/src/openmv/src/micropython/tests/basics/int_big_rshift.py b/src/openmv/src/micropython/tests/basics/int_big_rshift.py new file mode 100755 index 0000000..e6e2a66 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_rshift.py @@ -0,0 +1,9 @@ +i = 123456789012345678901234567890 +print(i >> 1) +print(i >> 1000) + +# result needs rounding up +i = -(1 << 70) +print(i >> 80) +i = -0xffffffffffffffff +print(i >> 32) diff --git a/src/openmv/src/micropython/tests/basics/int_big_unary.py b/src/openmv/src/micropython/tests/basics/int_big_unary.py new file mode 100755 index 0000000..fe6a48a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_unary.py @@ -0,0 +1,8 @@ +# test bignum unary operations + +i = 1 << 65 + +print(bool(i)) +print(+i) +print(-i) +print(~i) diff --git a/src/openmv/src/micropython/tests/basics/int_big_xor.py b/src/openmv/src/micropython/tests/basics/int_big_xor.py new file mode 100755 index 0000000..cd1d9ae --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_xor.py @@ -0,0 +1,42 @@ +# test + + + +print(0 ^ (1 << 80)) +print((1 << 80) ^ (1 << 80)) +print((1 << 80) ^ 0) + +a = 0xfffffffffffffffffffffffffffff +print(a ^ (1 << 100)) +print(a ^ (1 << 200)) +print(a ^ a == 0) +print(bool(a ^ a)) + +# test - + + +print((-1 << 80) ^ (1 << 80)) +print((-1 << 80) ^ 0) + +print((-a) ^ (1 << 100)) +print((-a) ^ (1 << 200)) +print((-a) ^ a == 0) +print(bool((-a) ^ a)) +i = -1 +print(i ^ 0xffffffffffffffff) # carry overflows to higher digit + +# test + - + +print(0 ^ (-1 << 80)) +print((1 << 80) ^ (-1 << 80)) + +print(a ^ (-1 << 100)) +print(a ^ (-1 << 200)) +print(a ^ (-a) == 0) +print(bool(a ^ (-a))) + +# test - - + +print((-1 << 80) ^ (-1 << 80)) + +print((-a) ^ (-1 << 100)) +print((-a) ^ (-1 << 200)) +print((-a) ^ (-a) == 0) +print(bool((-a) ^ (-a))) diff --git a/src/openmv/src/micropython/tests/basics/int_big_xor2.py b/src/openmv/src/micropython/tests/basics/int_big_xor2.py new file mode 100755 index 0000000..b5b3db6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_xor2.py @@ -0,0 +1,51 @@ +# test + + + +print( 97989513389222316022151446562729620153292831887555425160965597396 + ^ 23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + ^ 37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + ^ 98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + ^ 15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + ^ 63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + ^ 59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + ^ 86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + ^ 9487909752) + +# test - - + +print( -97989513389222316022151446562729620153292831887555425160965597396 + ^ -23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + ^ -37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + ^ -98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + ^ -15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + ^ -63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + ^ -59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + ^ -86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + ^ -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_xor3.py b/src/openmv/src/micropython/tests/basics/int_big_xor3.py new file mode 100755 index 0000000..00881e3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_xor3.py @@ -0,0 +1,51 @@ +# test - + + +print( -97989513389222316022151446562729620153292831887555425160965597396 + ^ 23716683549865351578586448630079789776107310103486834795830390982) + +print( -53817081128841898634258263553430908085326601592682411889506742059 + ^ 37042558948907407488299113387826240429667200950043601129661240876) + +print( -26167512042587370698808974207700979337713004510730289760097826496 + ^ 98456276326770292376138852628141531773120376436197321310863125849) + +print( -21085380307304977067262070503651827226504797285572981274069266136 + ^ 15928222825828272388778130358888206480162413547887287646273147570) + +print( -40827393422334167255488276244226338235131323044408420081160772273 + ^ 63815443187857978125545555033672525708399848575557475462799643340) + +print( -5181013159871685724135944379095645225188360725917119022722046448 + ^ 59734090450462480092384049604830976376887859531148103803093112493) + +print( -283894311 + ^ 86526825689187217371383854139783231460931720533100376593106943447) + +print( -40019818573920230246248826511203818792007462193311949166285967147 + ^ 9487909752) + +# test + - + +print( 97989513389222316022151446562729620153292831887555425160965597396 + ^ -23716683549865351578586448630079789776107310103486834795830390982) + +print( 53817081128841898634258263553430908085326601592682411889506742059 + ^ -37042558948907407488299113387826240429667200950043601129661240876) + +print( 26167512042587370698808974207700979337713004510730289760097826496 + ^ -98456276326770292376138852628141531773120376436197321310863125849) + +print( 21085380307304977067262070503651827226504797285572981274069266136 + ^ -15928222825828272388778130358888206480162413547887287646273147570) + +print( 40827393422334167255488276244226338235131323044408420081160772273 + ^ -63815443187857978125545555033672525708399848575557475462799643340) + +print( 5181013159871685724135944379095645225188360725917119022722046448 + ^ -59734090450462480092384049604830976376887859531148103803093112493) + +print( 283894311 + ^ -86526825689187217371383854139783231460931720533100376593106943447) + +print( 40019818573920230246248826511203818792007462193311949166285967147 + ^ -9487909752) diff --git a/src/openmv/src/micropython/tests/basics/int_big_zeroone.py b/src/openmv/src/micropython/tests/basics/int_big_zeroone.py new file mode 100755 index 0000000..7e0b7a7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_big_zeroone.py @@ -0,0 +1,28 @@ +# test [0,-0,1,-1] edge cases of bignum + +long_zero = (2**64) >> 65 +long_neg_zero = -long_zero +long_one = long_zero + 1 +long_neg_one = -long_one + +cases = [long_zero, long_neg_zero, long_one, long_neg_one] + +print(cases) +print([-c for c in cases]) +print([~c for c in cases]) +print([c >> 1 for c in cases]) +print([c << 1 for c in cases]) + +# comparison of 0/-0/+0 +print(long_zero == 0) +print(long_neg_zero == 0) +print(long_one - 1 == 0) +print(long_neg_one + 1 == 0) +print(long_zero < 1) +print(long_zero < -1) +print(long_zero > 1) +print(long_zero > -1) +print(long_neg_zero < 1) +print(long_neg_zero < -1) +print(long_neg_zero > 1) +print(long_neg_zero > -1) diff --git a/src/openmv/src/micropython/tests/basics/int_bytes.py b/src/openmv/src/micropython/tests/basics/int_bytes.py new file mode 100755 index 0000000..d1837ea --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_bytes.py @@ -0,0 +1,22 @@ +print((10).to_bytes(1, "little")) +print((111111).to_bytes(4, "little")) +print((100).to_bytes(10, "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) + +# check that extra zero bytes don't change the internal int value +print(int.from_bytes(bytes(20), "little") == 0) +print(int.from_bytes(b"\x01" + bytes(20), "little") == 1) + +# big-endian conversion +print((10).to_bytes(1, "big")) +print((100).to_bytes(10, "big")) +print(int.from_bytes(b"\0\0\0\0\0\0\0\0\0\x01", "big")) +print(int.from_bytes(b"\x01\0", "big")) + +# negative number of bytes should raise an error +try: + (1).to_bytes(-1, "little") +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/int_bytes_intbig.py b/src/openmv/src/micropython/tests/basics/int_bytes_intbig.py new file mode 100755 index 0000000..147362b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_bytes_intbig.py @@ -0,0 +1,14 @@ +print((2**64).to_bytes(9, "little")) +print((2**64).to_bytes(9, "big")) + +b = bytes(range(20)) + +il = int.from_bytes(b, "little") +ib = int.from_bytes(b, "big") +print(il) +print(ib) +print(il.to_bytes(20, "little")) +print(ib.to_bytes(20, "big")) + +# check that extra zero bytes don't change the internal int value +print(int.from_bytes(b + bytes(10), "little") == int.from_bytes(b, "little")) diff --git a/src/openmv/src/micropython/tests/basics/int_constfolding.py b/src/openmv/src/micropython/tests/basics/int_constfolding.py new file mode 100755 index 0000000..158897f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_constfolding.py @@ -0,0 +1,37 @@ +# tests int constant folding in compiler + +# positive +print(+1) +print(+100) + +# negation +print(-1) +print(-(-1)) + +# 1's complement +print(~0) +print(~1) +print(~-1) + +# addition +print(1 + 2) + +# subtraction +print(1 - 2) +print(2 - 1) + +# multiplication +print(1 * 2) +print(123 * 456) + +# floor div and modulo +print(123 // 7, 123 % 7) +print(-123 // 7, -123 % 7) +print(123 // -7, 123 % -7) +print(-123 // -7, -123 % -7) + +# won't fold so an exception can be raised at runtime +try: + 1 << -1 +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/int_constfolding_intbig.py b/src/openmv/src/micropython/tests/basics/int_constfolding_intbig.py new file mode 100755 index 0000000..714f155 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_constfolding_intbig.py @@ -0,0 +1,19 @@ +# tests int constant folding in compiler + +# negation +print(-0x3fffffff) # 32-bit edge case +print(-0x3fffffffffffffff) # 64-bit edge case +print(-(-0x3fffffff - 1)) # 32-bit edge case +print(-(-0x3fffffffffffffff - 1)) # 64-bit edge case + +# 1's complement +print(~0x3fffffff) # 32-bit edge case +print(~0x3fffffffffffffff) # 64-bit edge case +print(~(-0x3fffffff - 1)) # 32-bit edge case +print(~(-0x3fffffffffffffff - 1)) # 64-bit edge case + +# zero big-num on rhs +print(1 + ((1 << 65) - (1 << 65))) + +# negative big-num on rhs +print(1 + (-(1 << 65))) diff --git a/src/openmv/src/micropython/tests/basics/int_divmod.py b/src/openmv/src/micropython/tests/basics/int_divmod.py new file mode 100755 index 0000000..2e87813 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_divmod.py @@ -0,0 +1,7 @@ +# test integer floor division and modulo + +# test all combination of +/-/0 cases +for i in range(-2, 3): + for j in range(-4, 5): + if j != 0: + print(i, j, i // j, i % j, divmod(i, j)) diff --git a/src/openmv/src/micropython/tests/basics/int_divmod_intbig.py b/src/openmv/src/micropython/tests/basics/int_divmod_intbig.py new file mode 100755 index 0000000..ea8de07 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_divmod_intbig.py @@ -0,0 +1,9 @@ +# test integer floor division and modulo + +# this tests bignum modulo +a = 987654321987987987987987987987 +b = 19 +print(a % b) +print(a % -b) +print(-a % b) +print(-a % -b) diff --git a/src/openmv/src/micropython/tests/basics/int_divzero.py b/src/openmv/src/micropython/tests/basics/int_divzero.py new file mode 100755 index 0000000..aa38eee --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_divzero.py @@ -0,0 +1,9 @@ +try: + 1 // 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + 1 % 0 +except ZeroDivisionError: + print("ZeroDivisionError") diff --git a/src/openmv/src/micropython/tests/basics/int_intbig.py b/src/openmv/src/micropython/tests/basics/int_intbig.py new file mode 100755 index 0000000..a22075d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_intbig.py @@ -0,0 +1,54 @@ +# This tests long ints for 32-bit machine + +a = 0x1ffffffff +b = 0x100000000 +print(a) +print(b) +print(a + b) +print(a - b) +print(b - a) +# overflows long long implementation +#print(a * b) +print(a // b) +print(a % b) +print("&", a & b) +print(a | b) +print(a ^ b) +print(a << 3) +print(a >> 1) + +a += b +print(a) +a -= 123456 +print(a) +a *= 257 +print(a) +a //= 257 +print(a) +a %= b +print(a) +a ^= b +print(a) +a |= b +print(a) +a &= b +print("&=", a) +a <<= 5 +print(a) +a >>= 1 +print(a) + +# Test referential integrity of long ints +a = 0x1ffffffff +b = a +a += 1 +print(a) +print(b) + +# Bitwise ops on 64-bit + +a = 0x1ffffffffffffffff +b = 0x10000000000000000 +print("&", a & b) +print(a | b) +print(a ^ b) diff --git a/src/openmv/src/micropython/tests/basics/int_small.py b/src/openmv/src/micropython/tests/basics/int_small.py new file mode 100755 index 0000000..4d47104 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/int_small.py @@ -0,0 +1,84 @@ +# This tests small int range for 32-bit machine + +# Small ints are variable-length encoded in MicroPython, so first +# test that encoding works as expected. + +print(0) +print(1) +print(-1) +# Value is split in 7-bit "subwords", and taking into account that all +# ints in Python are signed, there're 6 bits of magnitude. So, around 2^6 +# there's "turning point" +print(63) +print(64) +print(65) +print(-63) +print(-64) +print(-65) +# Maximum values of small ints on 32-bit platform +print(1073741823) +# Per python semantics, lexical integer is without a sign (i.e. positive) +# and '-' is unary minus operation applied to it. That's why -1073741824 +# (min two-complement's negative value) is not allowed. +print(-1073741823) + +# Operations tests + +# compile-time constexprs +print(1 + 3) +print(3 - 2) +print(2 * 3) +print(1 & 3) +print(1 | 2) +print(1 ^ 3) +print(+3) +print(-3) +print(~3) + +a = 0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a += 0xff +print(a) +# This would overflow +#a += 1 + +a = -0x3fffff +print(a) +a *= 0x10 +print(a) +a *= 0x10 +print(a) +a -= 0xff +print(a) +# This still doesn't overflow +a -= 1 +print(a) +# This would overflow +#a -= 1 + +# negative shifts are not allowed +try: + a << -1 +except ValueError: + print("ValueError") +try: + a >> -1 +except ValueError: + print("ValueError") + +# Shifts to big amounts are undefined behavior in C and is CPU-specific + +# These are compile-time constexprs +print(1 >> 32) +print(1 >> 64) +print(1 >> 128) + +# These are runtime calcs +a = 1 +print(a >> 32) +print(a >> 64) +print(a >> 128) diff --git a/src/openmv/src/micropython/tests/basics/io_buffered_writer.py b/src/openmv/src/micropython/tests/basics/io_buffered_writer.py new file mode 100755 index 0000000..c2cedb9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_buffered_writer.py @@ -0,0 +1,27 @@ +import uio as io + +try: + io.BytesIO + io.BufferedWriter +except AttributeError: + print('SKIP') + raise SystemExit + +bts = io.BytesIO() +buf = io.BufferedWriter(bts, 8) + +buf.write(b"foobar") +print(bts.getvalue()) +buf.write(b"foobar") +# CPython has different flushing policy, so value below is different +print(bts.getvalue()) +buf.flush() +print(bts.getvalue()) +buf.flush() +print(bts.getvalue()) + +# special case when alloc is a factor of total buffer length +bts = io.BytesIO() +buf = io.BufferedWriter(bts, 1) +buf.write(b"foo") +print(bts.getvalue()) diff --git a/src/openmv/src/micropython/tests/basics/io_buffered_writer.py.exp b/src/openmv/src/micropython/tests/basics/io_buffered_writer.py.exp new file mode 100755 index 0000000..d086935 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_buffered_writer.py.exp @@ -0,0 +1,5 @@ +b'' +b'foobarfo' +b'foobarfoobar' +b'foobarfoobar' +b'foo' diff --git a/src/openmv/src/micropython/tests/basics/io_bytesio_cow.py b/src/openmv/src/micropython/tests/basics/io_bytesio_cow.py new file mode 100755 index 0000000..92654a0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_bytesio_cow.py @@ -0,0 +1,20 @@ +# Make sure that write operations on io.BytesIO don't +# change original object it was constructed from. +try: + import uio as io +except ImportError: + import io + +b = b"foobar" + +a = io.BytesIO(b) +a.write(b"1") +print(b) +print(a.getvalue()) + +b = bytearray(b"foobar") + +a = io.BytesIO(b) +a.write(b"1") +print(b) +print(a.getvalue()) diff --git a/src/openmv/src/micropython/tests/basics/io_bytesio_ext.py b/src/openmv/src/micropython/tests/basics/io_bytesio_ext.py new file mode 100755 index 0000000..e454b2f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_bytesio_ext.py @@ -0,0 +1,28 @@ +# Extended stream operations on io.BytesIO +try: + import uio as io +except ImportError: + import io + +a = io.BytesIO(b"foobar") +a.seek(10) +print(a.read(10)) + +a = io.BytesIO() +print(a.seek(8)) +a.write(b"123") +print(a.getvalue()) + +print(a.seek(0, 1)) + +print(a.seek(-1, 2)) +a.write(b"0") +print(a.getvalue()) + +a.flush() +print(a.getvalue()) + +a.seek(0) +arr = bytearray(10) +print(a.readinto(arr)) +print(arr) diff --git a/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py b/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py new file mode 100755 index 0000000..8f624fd --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py @@ -0,0 +1,13 @@ +try: + import uio as io +except ImportError: + import io + +a = io.BytesIO(b"foobar") +try: + a.seek(-10) +except Exception as e: + # CPython throws ValueError, but MicroPython has consistent stream + # interface, so BytesIO raises the same error as a real file, which + # is OSError(EINVAL). + print(type(e), e.args[0] > 0) diff --git a/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py.exp b/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py.exp new file mode 100755 index 0000000..724aaf6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_bytesio_ext2.py.exp @@ -0,0 +1 @@ + True diff --git a/src/openmv/src/micropython/tests/basics/io_iobase.py b/src/openmv/src/micropython/tests/basics/io_iobase.py new file mode 100755 index 0000000..6f554b0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_iobase.py @@ -0,0 +1,19 @@ +try: + import uio as io +except: + import io + +try: + io.IOBase +except AttributeError: + print('SKIP') + raise SystemExit + + +class MyIO(io.IOBase): + def write(self, buf): + # CPython and uPy pass in different types for buf (str vs bytearray) + print('write', len(buf)) + return len(buf) + +print('test', file=MyIO()) diff --git a/src/openmv/src/micropython/tests/basics/io_stringio1.py b/src/openmv/src/micropython/tests/basics/io_stringio1.py new file mode 100755 index 0000000..9f7c1e4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_stringio1.py @@ -0,0 +1,45 @@ +try: + import uio as io +except ImportError: + import io + +a = io.StringIO() +print('io.StringIO' in repr(a)) +print(a.getvalue()) +print(a.read()) + +a = io.StringIO("foobar") +print(a.getvalue()) +print(a.read()) +print(a.read()) + +a = io.StringIO() +a.write("foo") +print(a.getvalue()) + +a = io.StringIO("foo") +a.write("12") +print(a.getvalue()) + +a = io.StringIO("foo") +a.write("123") +print(a.getvalue()) + +a = io.StringIO("foo") +a.write("1234") +print(a.getvalue()) + +a = io.StringIO() +a.write("foo") +print(a.read()) + +a = io.StringIO() +a.close() +for f in [a.read, a.getvalue, lambda:a.write("")]: + # CPython throws for operations on closed I/O, MicroPython makes + # the underlying string empty unless MICROPY_CPYTHON_COMPAT defined + try: + f() + print("ValueError") + except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/io_stringio_with.py b/src/openmv/src/micropython/tests/basics/io_stringio_with.py new file mode 100755 index 0000000..c359754 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_stringio_with.py @@ -0,0 +1,9 @@ +try: + import uio as io +except ImportError: + import io + +# test __enter__/__exit__ +with io.StringIO() as b: + b.write("foo") + print(b.getvalue()) diff --git a/src/openmv/src/micropython/tests/basics/io_write_ext.py b/src/openmv/src/micropython/tests/basics/io_write_ext.py new file mode 100755 index 0000000..5a6eaa3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_write_ext.py @@ -0,0 +1,26 @@ +# This tests extended (MicroPython-specific) form of write: +# write(buf, len) and write(buf, offset, len) +import uio + +try: + uio.BytesIO +except AttributeError: + print('SKIP') + raise SystemExit + +buf = uio.BytesIO() + +buf.write(b"foo", 2) +print(buf.getvalue()) + +buf.write(b"foo", 100) +print(buf.getvalue()) + +buf.write(b"foobar", 1, 3) +print(buf.getvalue()) + +buf.write(b"foobar", 1, 100) +print(buf.getvalue()) + +buf.write(b"foobar", 100, 100) +print(buf.getvalue()) diff --git a/src/openmv/src/micropython/tests/basics/io_write_ext.py.exp b/src/openmv/src/micropython/tests/basics/io_write_ext.py.exp new file mode 100755 index 0000000..0f9c6bf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/io_write_ext.py.exp @@ -0,0 +1,5 @@ +b'fo' +b'fofoo' +b'fofoooob' +b'fofooooboobar' +b'fofooooboobar' diff --git a/src/openmv/src/micropython/tests/basics/is_isnot.py b/src/openmv/src/micropython/tests/basics/is_isnot.py new file mode 100755 index 0000000..990190a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/is_isnot.py @@ -0,0 +1,14 @@ +print(1 is 1) +print(1 is 2) +print(1 is not 1) +print(1 is not 2) + + +print([1, 2] is [1, 2]) +a = [1, 2] +b = a +print(b is a) + +# TODO: strings require special "is" handling, postponed +# until qstr refactor. +#print("a" is "a") diff --git a/src/openmv/src/micropython/tests/basics/iter0.py b/src/openmv/src/micropython/tests/basics/iter0.py new file mode 100755 index 0000000..d20ade7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/iter0.py @@ -0,0 +1,9 @@ +# builtin type that is not iterable +try: + for i in 1: + pass +except TypeError: + print('TypeError') + +# builtin type that is iterable, calling __next__ explicitly +print(iter(range(4)).__next__()) diff --git a/src/openmv/src/micropython/tests/basics/iter1.py b/src/openmv/src/micropython/tests/basics/iter1.py new file mode 100755 index 0000000..26e9a2e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/iter1.py @@ -0,0 +1,79 @@ +# test user defined iterators + +# this class is not iterable +class NotIterable: + pass +try: + for i in NotIterable(): + pass +except TypeError: + print('TypeError') + +# this class has no __next__ implementation +class NotIterable: + def __iter__(self): + return self +try: + print(all(NotIterable())) +except TypeError: + print('TypeError') + +class MyStopIteration(StopIteration): + pass + +class myiter: + def __init__(self, i): + self.i = i + + def __iter__(self): + return self + + def __next__(self): + if self.i <= 0: + # stop in the usual way + raise StopIteration + elif self.i == 10: + # stop with an argument + raise StopIteration(42) + elif self.i == 20: + # raise a non-stop exception + raise TypeError + elif self.i == 30: + # raise a user-defined stop iteration + print('raising MyStopIteration') + raise MyStopIteration + else: + # return the next value + self.i -= 1 + return self.i + +for i in myiter(5): + print(i) + +for i in myiter(12): + print(i) + +try: + for i in myiter(22): + print(i) +except TypeError: + print('raised TypeError') + +try: + for i in myiter(5): + print(i) + raise StopIteration +except StopIteration: + print('raised StopIteration') + +for i in myiter(32): + print(i) + +# repeat some of the above tests but use tuple() to walk the iterator (tests mp_iternext) +print(tuple(myiter(5))) +print(tuple(myiter(12))) +print(tuple(myiter(32))) +try: + tuple(myiter(22)) +except TypeError: + print('raised TypeError') diff --git a/src/openmv/src/micropython/tests/basics/iter2.py b/src/openmv/src/micropython/tests/basics/iter2.py new file mode 100755 index 0000000..763f59c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/iter2.py @@ -0,0 +1,23 @@ +# user defined iterator used in something other than a for loop + +class MyStopIteration(StopIteration): + pass + +class myiter: + def __init__(self, i): + self.i = i + + def __iter__(self): + return self + + def __next__(self): + if self.i == 0: + raise StopIteration + elif self.i == 1: + raise StopIteration(1) + elif self.i == 2: + raise MyStopIteration + +print(list(myiter(0))) +print(list(myiter(1))) +print(list(myiter(2))) diff --git a/src/openmv/src/micropython/tests/basics/iter_of_iter.py b/src/openmv/src/micropython/tests/basics/iter_of_iter.py new file mode 100755 index 0000000..d775b6a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/iter_of_iter.py @@ -0,0 +1,7 @@ +i = iter(iter((1, 2, 3))) +print(list(i)) +i = iter(iter([1, 2, 3])) +print(list(i)) +i = iter(iter({1:2, 3:4, 5:6})) +print(sorted(i)) +# set, see set_iter_of_iter.py diff --git a/src/openmv/src/micropython/tests/basics/lambda1.py b/src/openmv/src/micropython/tests/basics/lambda1.py new file mode 100755 index 0000000..06111d6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/lambda1.py @@ -0,0 +1,4 @@ +# lambda + +f = lambda x, y: x + 3 * y +print(f(3, 5)) diff --git a/src/openmv/src/micropython/tests/basics/lambda_defargs.py b/src/openmv/src/micropython/tests/basics/lambda_defargs.py new file mode 100755 index 0000000..095d4cd --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/lambda_defargs.py @@ -0,0 +1,12 @@ +# test default args with lambda + +f = lambda x=1: x +print(f(), f(2), f(x=3)) + +y = 'y' +f = lambda x=y: x +print(f()) + +f = lambda x, y=[]: (x, y) +f(0)[1].append(1) +print(f(1), f(x=2), f(3, 4), f(4, y=5)) diff --git a/src/openmv/src/micropython/tests/basics/lexer.py b/src/openmv/src/micropython/tests/basics/lexer.py new file mode 100755 index 0000000..181d62d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/lexer.py @@ -0,0 +1,85 @@ +# test the lexer + +try: + eval + exec +except NameError: + print("SKIP") + raise SystemExit + +# __debug__ is a special symbol +print(type(__debug__)) + +# short input +exec("") +exec("\n") +exec("\n\n") +exec("\r") +exec("\r\r") +exec("\t") +exec("\r\n") +exec("\nprint(1)") +exec("\rprint(2)") +exec("\r\nprint(3)") +exec("\n5") +exec("\r6") +exec("\r\n7") +print(eval("1")) +print(eval("12")) +print(eval("123")) +print(eval("1\n")) +print(eval("12\n")) +print(eval("123\n")) +print(eval("1\r")) +print(eval("12\r")) +print(eval("123\r")) + +# line continuation +print(eval("'123' \\\r '456'")) +print(eval("'123' \\\n '456'")) +print(eval("'123' \\\r\n '456'")) +print(eval("'123'\\\r'456'")) +print(eval("'123'\\\n'456'")) +print(eval("'123'\\\r\n'456'")) + +# backslash used to escape a line-break in a string +print('a\ +b') + +# lots of indentation +def a(x): + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + if x: + print(x) +a(1) + +# badly formed hex escape sequences +try: + exec(r"'\x0'") +except SyntaxError: + print("SyntaxError") +try: + exec(r"b'\x0'") +except SyntaxError: + print("SyntaxError") +try: + exec(r"'\u000'") +except SyntaxError: + print("SyntaxError") +try: + exec(r"'\U0000000'") +except SyntaxError: + print("SyntaxError") diff --git a/src/openmv/src/micropython/tests/basics/list1.py b/src/openmv/src/micropython/tests/basics/list1.py new file mode 100755 index 0000000..fa426c0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list1.py @@ -0,0 +1,30 @@ +# basic list functionality +x = [1, 2, 3 * 4] +print(x) +x[0] = 4 +print(x) +x[1] += -4 +print(x) +x.append(5) +print(x) +f = x.append +f(4) +print(x) + +x.extend([100, 200]) +print(x) +x.extend(range(3)) +print(x) + +x += [2, 1] +print(x) + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) + +# unsupported type on RHS of add +try: + [] + None +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/list_clear.py b/src/openmv/src/micropython/tests/basics/list_clear.py new file mode 100755 index 0000000..406d7e8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_clear.py @@ -0,0 +1,4 @@ +# tests list.clear +x = [1, 2, 3, 4] +x.clear() +print(x) diff --git a/src/openmv/src/micropython/tests/basics/list_compare.py b/src/openmv/src/micropython/tests/basics/list_compare.py new file mode 100755 index 0000000..fd656c7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_compare.py @@ -0,0 +1,60 @@ +print([] == []) +print([] > []) +print([] < []) +print([] == [1]) +print([1] == []) +print([] > [1]) +print([1] > []) +print([] < [1]) +print([1] < []) +print([] >= [1]) +print([1] >= []) +print([] <= [1]) +print([1] <= []) + +print([1] == [1]) +print([1] != [1]) +print([1] == [2]) +print([1] == [1, 0]) + +print([1] > [1]) +print([1] > [2]) +print([2] > [1]) +print([1, 0] > [1]) +print([1, -1] > [1]) +print([1] > [1, 0]) +print([1] > [1, -1]) + +print([1] < [1]) +print([2] < [1]) +print([1] < [2]) +print([1] < [1, 0]) +print([1] < [1, -1]) +print([1, 0] < [1]) +print([1, -1] < [1]) + +print([1] >= [1]) +print([1] >= [2]) +print([2] >= [1]) +print([1, 0] >= [1]) +print([1, -1] >= [1]) +print([1] >= [1, 0]) +print([1] >= [1, -1]) + +print([1] <= [1]) +print([2] <= [1]) +print([1] <= [2]) +print([1] <= [1, 0]) +print([1] <= [1, -1]) +print([1, 0] <= [1]) +print([1, -1] <= [1]) + + +print([] == {}) +print([] != {}) +print([1] == (1,)) + +try: + print([] < {}) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/list_copy.py b/src/openmv/src/micropython/tests/basics/list_copy.py new file mode 100755 index 0000000..bc45078 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_copy.py @@ -0,0 +1,7 @@ +# list copy tests +a = [1, 2, []] +b = a.copy() +a[-1].append(1) +a.append(4) +print(a) +print(b) diff --git a/src/openmv/src/micropython/tests/basics/list_count.py b/src/openmv/src/micropython/tests/basics/list_count.py new file mode 100755 index 0000000..db93b3a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_count.py @@ -0,0 +1,6 @@ +# list count tests +a = [1, 2, 3] +a = a + a + a +b = [0, 0, a, 0, a, 0] +print(a.count(2)) +print(b.count(a)) diff --git a/src/openmv/src/micropython/tests/basics/list_extend.py b/src/openmv/src/micropython/tests/basics/list_extend.py new file mode 100755 index 0000000..21cdb41 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_extend.py @@ -0,0 +1,33 @@ +# test list.__iadd__ and list.extend (they are equivalent) + +l = [1, 2] +l.extend([]) +print(l) + +l.extend([3]) +print(l) + +l.extend([4, 5]) +print(l) + +l.extend(range(6, 10)) +print(l) + +l.extend("abc") +print(l) + +l = [1, 2] +l += [] +print(l) + +l += [3] +print(l) + +l += [4, 5] +print(l) + +l += range(6, 10) +print(l) + +l += "abc" +print(l) diff --git a/src/openmv/src/micropython/tests/basics/list_index.py b/src/openmv/src/micropython/tests/basics/list_index.py new file mode 100755 index 0000000..0bd28ac --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_index.py @@ -0,0 +1,37 @@ +a = [1, 2, 3] +print(a.index(1)) +print(a.index(2)) +print(a.index(3)) +print(a.index(3, 2)) +print(a.index(1, -100)) +print(a.index(1, False)) + +try: + print(a.index(1, True)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print(a.index(3, 2, 2)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +a = a + a +b = [0, 0, a] +print(a.index(2)) +print(b.index(a)) +print(a.index(2, 2)) + +try: + a.index(2, 2, 2) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +# 3rd argument to index greater than length of list +print([1, 2].index(1, 0, 4)) diff --git a/src/openmv/src/micropython/tests/basics/list_insert.py b/src/openmv/src/micropython/tests/basics/list_insert.py new file mode 100755 index 0000000..6db97cf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_insert.py @@ -0,0 +1,9 @@ +a = [1, 2, 3] +a.insert(1, 42) +print(a) +a.insert(-1, -1) +print(a) +a.insert(99, 99) +print(a) +a.insert(-99, -99) +print(a) diff --git a/src/openmv/src/micropython/tests/basics/list_mult.py b/src/openmv/src/micropython/tests/basics/list_mult.py new file mode 100755 index 0000000..548f885 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_mult.py @@ -0,0 +1,18 @@ +# basic multiplication +print([0] * 5) + +# check negative, 0, positive; lhs and rhs multiplication +for i in (-4, -2, 0, 2, 4): + print(i * [1, 2]) + print([1, 2] * i) + +# check that we don't modify existing list +a = [1, 2, 3] +c = a * 3 +print(a, c) + +# unsupported type on RHS +try: + [] * None +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/list_pop.py b/src/openmv/src/micropython/tests/basics/list_pop.py new file mode 100755 index 0000000..87ed456 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_pop.py @@ -0,0 +1,17 @@ +# list poppin' +a = [1, 2, 3] +print(a.pop()) +print(a.pop()) +print(a.pop()) +try: + print(a.pop()) +except IndexError: + print("IndexError raised") +else: + raise AssertionError("No IndexError raised") + +# popping such that list storage shrinks (tests implementation detail of uPy) +l = list(range(20)) +for i in range(len(l)): + l.pop() +print(l) diff --git a/src/openmv/src/micropython/tests/basics/list_remove.py b/src/openmv/src/micropython/tests/basics/list_remove.py new file mode 100755 index 0000000..81b2b3d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_remove.py @@ -0,0 +1,9 @@ +a = [1, 2, 3] +print(a.remove(2)) +print(a) +try: + a.remove(2) +except ValueError: + print("Raised ValueError") +else: + raise AssertionError("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/list_reverse.py b/src/openmv/src/micropython/tests/basics/list_reverse.py new file mode 100755 index 0000000..38acf1f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_reverse.py @@ -0,0 +1,5 @@ +a = [] +for i in range(100): + a.append(i) + a.reverse() +print(a) diff --git a/src/openmv/src/micropython/tests/basics/list_slice.py b/src/openmv/src/micropython/tests/basics/list_slice.py new file mode 100755 index 0000000..fc08e58 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_slice.py @@ -0,0 +1,28 @@ +# test list slices, getting values + +x = list(range(10)) +a = 2 +b = 4 +c = 3 +print(x[:]) +print(x[::]) +print(x[::c]) +print(x[:b]) +print(x[:b:]) +print(x[:b:c]) +print(x[a]) +print(x[a:]) +print(x[a::]) +print(x[a::c]) +print(x[a:b]) +print(x[a:b:]) +print(x[a:b:c]) + +# these should not raise IndexError +print([][1:]) +print([][-1:]) + +try: + [][::0] +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/list_slice_3arg.py b/src/openmv/src/micropython/tests/basics/list_slice_3arg.py new file mode 100755 index 0000000..a5eda80 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_slice_3arg.py @@ -0,0 +1,39 @@ +x = list(range(10)) +print(x[::-1]) +print(x[::2]) +print(x[::-2]) + +x = list(range(9)) +print(x[::-1]) +print(x[::2]) +print(x[::-2]) + +x = list(range(5)) +print(x[:0:-1]) +print(x[:1:-1]) +print(x[:2:-1]) +print(x[0::-1]) +print(x[1::-1]) +print(x[2::-1]) + +x = list(range(5)) +print(x[0:0:-1]) +print(x[4:4:-1]) +print(x[5:5:-1]) + +x = list(range(10)) +print(x[-1:-1:-1]) +print(x[-1:-2:-1]) +print(x[-1:-11:-1]) +print(x[-10:-11:-1]) +print(x[:-15:-1]) + +# test negative indices that are out-of-bounds +print([][::-1]) +print([1][::-1]) +print([][0:-10:-1]) +print([1][0:-10:-1]) +print([][:-20:-1]) +print([1][:-20:-1]) +print([][-20::-1]) +print([1][-20::-1]) diff --git a/src/openmv/src/micropython/tests/basics/list_slice_assign.py b/src/openmv/src/micropython/tests/basics/list_slice_assign.py new file mode 100755 index 0000000..8856157 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_slice_assign.py @@ -0,0 +1,47 @@ +# test slices; only 2 argument version supported by MicroPython at the moment +x = list(range(10)) + +# Assignment +l = list(x) +l[1:3] = [10, 20] +print(l) +l = list(x) +l[1:3] = [10] +print(l) +l = list(x) +l[1:3] = [] +print(l) +l = list(x) +del l[1:3] +print(l) + +l = list(x) +l[:3] = [10, 20] +print(l) +l = list(x) +l[:3] = [] +print(l) +l = list(x) +del l[:3] +print(l) + +l = list(x) +l[:-3] = [10, 20] +print(l) +l = list(x) +l[:-3] = [] +print(l) +l = list(x) +del l[:-3] +print(l) + +# assign a tuple +l = [1, 2, 3] +l[0:1] = (10, 11, 12) +print(l) + +# RHS of slice must be an iterable +try: + [][0:1] = 123 +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/list_slice_assign_grow.py b/src/openmv/src/micropython/tests/basics/list_slice_assign_grow.py new file mode 100755 index 0000000..fa25623 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_slice_assign_grow.py @@ -0,0 +1,33 @@ +x = list(range(2)) + +l = list(x) +l[0:0] = [10] +print(l) +l = list(x) +l[:0] = [10, 20] +print(l) +l = list(x) +l[0:0] = [10, 20, 30, 40] +print(l) + +l = list(x) +l[1:1] = [10, 20, 30, 40] +print(l) + +l = list(x) +l[2:] = [10, 20, 30, 40] +print(l) + +# Weird cases +l = list(x) +l[1:0] = [10, 20, 30, 40] +print(l) + +l = list(x) +l[100:100] = [10, 20, 30, 40] +print(l) + +# growing by using itself on RHS +l = list(range(10)) +l[4:] = l +print(l) diff --git a/src/openmv/src/micropython/tests/basics/list_sort.py b/src/openmv/src/micropython/tests/basics/list_sort.py new file mode 100755 index 0000000..d10e2a6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_sort.py @@ -0,0 +1,49 @@ +l = [1, 3, 2, 5] + +print(l) +print(sorted(l)) +l.sort() +print(l) +print(l == sorted(l)) + +print(sorted(l, key=lambda x: -x)) +l.sort(key=lambda x: -x) +print(l) +print(l == sorted(l, key=lambda x: -x)) + +print(sorted(l, key=lambda x: -x, reverse=True)) +l.sort(key=lambda x: -x, reverse=True) +print(l) +print(l == sorted(l, key=lambda x: -x, reverse=True)) + +print(sorted(l, reverse=True)) +l.sort(reverse=True) +print(l) +print(l == sorted(l, reverse=True)) + +print(sorted(l, reverse=False)) +l.sort(reverse=False) +print(l) +print(l == sorted(l, reverse=False)) + +# test large lists (should not stack overflow) +l = list(range(200)) +l.sort() +print(l[0], l[-1]) +l.sort(reverse=True) +print(l[0], l[-1]) + +# test user-defined ordering +class A: + def __init__(self, x): + self.x = x + def __lt__(self, other): + return self.x > other.x + def __repr__(self): + return str(self.x) +l = [A(5), A(2), A(1), A(3), A(4)] +print(l) +l.sort() +print(l) +l.sort(reverse=True) +print(l) diff --git a/src/openmv/src/micropython/tests/basics/list_sum.py b/src/openmv/src/micropython/tests/basics/list_sum.py new file mode 100755 index 0000000..e46042b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/list_sum.py @@ -0,0 +1,5 @@ +# list addition +a = [1,2,3] +b = [4,5,6] +c = a + b +print(c) diff --git a/src/openmv/src/micropython/tests/basics/logic_constfolding.py b/src/openmv/src/micropython/tests/basics/logic_constfolding.py new file mode 100755 index 0000000..14afe61 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/logic_constfolding.py @@ -0,0 +1,26 @@ +# tests logical constant folding in parser + +def f_true(): + print('f_true') + return True + +def f_false(): + print('f_false') + return False + +print(0 or False) +print(1 or foo) +print(f_false() or 1 or foo) +print(f_false() or 1 or f_true()) + +print(0 and foo) +print(1 and True) +print(f_true() and 0 and foo) +print(f_true() and 1 and f_false()) + +print(not 0) +print(not False) +print(not 1) +print(not True) +print(not not 0) +print(not not 1) diff --git a/src/openmv/src/micropython/tests/basics/memoryerror.py b/src/openmv/src/micropython/tests/basics/memoryerror.py new file mode 100755 index 0000000..18053f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryerror.py @@ -0,0 +1,13 @@ +# test out-of-memory with malloc +l = list(range(1000)) +try: + 1000000000 * l +except MemoryError: + print('MemoryError') +print(len(l), l[0], l[-1]) + +# test out-of-memory with realloc +try: + [].extend(range(1000000000)) +except MemoryError: + print('MemoryError') diff --git a/src/openmv/src/micropython/tests/basics/memoryerror.py.exp b/src/openmv/src/micropython/tests/basics/memoryerror.py.exp new file mode 100755 index 0000000..3d6c7f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryerror.py.exp @@ -0,0 +1,3 @@ +MemoryError +1000 0 999 +MemoryError diff --git a/src/openmv/src/micropython/tests/basics/memoryview1.py b/src/openmv/src/micropython/tests/basics/memoryview1.py new file mode 100755 index 0000000..c4cc6ff --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryview1.py @@ -0,0 +1,96 @@ +# test memoryview +try: + memoryview +except: + print("SKIP") + raise SystemExit + +# test reading from bytes +b = b'1234' +m = memoryview(b) +print(len(m)) +print(m[0], m[1], m[-1]) +print(list(m)) + +# test writing to bytes +try: + m[0] = 1 +except TypeError: + print("TypeError") +try: + m[0:2] = b'00' +except TypeError: + print("TypeError") + +# test writing to bytearray +b = bytearray(b) +m = memoryview(b) +m[0] = 1 +print(b) +print(list(m)) + +# test slice +m = memoryview(b'1234') +print(list(m[1:])) +print(list(m[1:-1])) + +# this tests get_buffer of memoryview +m = memoryview(bytearray(2)) +print(bytearray(m)) +print(list(memoryview(memoryview(b'1234')))) # read-only memoryview + +import array +a = array.array('i', [1, 2, 3, 4]) +m = memoryview(a) +print(list(m)) +print(list(m[1:-1])) +m[2] = 6 +print(a) + +# test slice assignment between memoryviews +b1 = bytearray(b'1234') +b2 = bytearray(b'5678') +b3 = bytearray(b'5678') +m1 = memoryview(b1) +m2 = memoryview(b2) +m3 = memoryview(b3) +m2[1:3] = m1[0:2] +print(b2) +b3[1:3] = m1[0:2] +print(b3) +m1[2:4] = b3[1:3] +print(b1) + +try: + m2[1:3] = b1[0:4] +except ValueError: + print("ValueError") + +try: + m2[1:3] = m1[0:4] +except ValueError: + print("ValueError") + +try: + m2[0:4] = m1[1:3] +except ValueError: + print("ValueError") + +# test memoryview of arrays with items sized larger than 1 +a1 = array.array('i', [0]*5) +m4 = memoryview(a1) +a2 = array.array('i', [3]*5) +m5 = memoryview(a2) +m4[1:3] = m5[1:3] +print(a1) + +try: + m4[1:3] = m2[1:3] +except ValueError: + print("ValueError") + +# invalid assignment on RHS +try: + memoryview(array.array('i'))[0:2] = b'1234' +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/memoryview2.py b/src/openmv/src/micropython/tests/basics/memoryview2.py new file mode 100755 index 0000000..06a7be5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryview2.py @@ -0,0 +1,13 @@ +# test memoryview accessing maximum values for signed/unsigned elements +try: + from array import array + memoryview +except: + print("SKIP") + raise SystemExit + +print(list(memoryview(b'\x7f\x80\x81\xff'))) +print(list(memoryview(array('b', [0x7f, -0x80])))) +print(list(memoryview(array('B', [0x7f, 0x80, 0x81, 0xff])))) +print(list(memoryview(array('h', [0x7f00, -0x8000])))) +print(list(memoryview(array('H', [0x7f00, 0x8000, 0x8100, 0xffff])))) diff --git a/src/openmv/src/micropython/tests/basics/memoryview_gc.py b/src/openmv/src/micropython/tests/basics/memoryview_gc.py new file mode 100755 index 0000000..d366cbb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryview_gc.py @@ -0,0 +1,23 @@ +# test memoryview retains pointer to original object/buffer +try: + memoryview +except: + print("SKIP") + raise SystemExit + +b = bytearray(10) +m = memoryview(b)[1:] +for i in range(len(m)): + m[i] = i + +# reclaim b, but hopefully not the buffer +b = None +import gc +gc.collect() + +# allocate lots of memory +for i in range(100000): + [42, 42, 42, 42] + +# check that the memoryview is still what we want +print(list(m)) diff --git a/src/openmv/src/micropython/tests/basics/memoryview_intbig.py b/src/openmv/src/micropython/tests/basics/memoryview_intbig.py new file mode 100755 index 0000000..a76d9cb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/memoryview_intbig.py @@ -0,0 +1,10 @@ +# test memoryview accessing maximum values for signed/unsigned elements +try: + from array import array + memoryview +except: + print("SKIP") + raise SystemExit + +print(list(memoryview(array('i', [0x7f000000, -0x80000000])))) +print(list(memoryview(array('I', [0x7f000000, 0x80000000, 0x81000000, 0xffffffff])))) diff --git a/src/openmv/src/micropython/tests/basics/module1.py b/src/openmv/src/micropython/tests/basics/module1.py new file mode 100755 index 0000000..c158af5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/module1.py @@ -0,0 +1,13 @@ +# test behaviour of module objects + +# this module should always exist +import __main__ + +# print module +print(repr(__main__).startswith(">' +# OK: 2 & (3 << 1) = 2 & 6 = 2 +# BAD: (2 & 3) << 1 = 2 << 1 = 4 +print(2 & 3 << 1) +# OK: 6 & (4 >> 1) = 6 & 2 = 2 +# BAD: (6 & 4) >> 1 = 2 >> 1 = 1 +print(6 & 4 >> 1) + +# '+', '-' +# OK: 1 << (1 + 1) = 1 << 2 = 4 +# BAD: (1 << 1) + 1 = 2 + 1 = 3 +print(1 << 1 + 1) + +# '*', '/', '//', '%' +# OK: 2 + (2 * 2) = 2 + 4 = 6 +# BAD: (2 + 2) * 2 = 4 * 2 = 8 +print(2 + 2 * 2) + +# '+x', '-x', '~x' + +# '**' +# OK: -(2**2) = -4 +# BAD: (-2)**2 = 4 +print(-2**2) +# OK: 2**(-1) = 0.5 +print(2**-0) + +# (expr...) +print((2 + 2) * 2) diff --git a/src/openmv/src/micropython/tests/basics/ordereddict1.py b/src/openmv/src/micropython/tests/basics/ordereddict1.py new file mode 100755 index 0000000..d1633f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/ordereddict1.py @@ -0,0 +1,26 @@ +try: + from collections import OrderedDict +except ImportError: + try: + from ucollections import OrderedDict + except ImportError: + print("SKIP") + raise SystemExit + +d = OrderedDict([(10, 20), ("b", 100), (1, 2)]) +print(len(d)) +print(list(d.keys())) +print(list(d.values())) +del d["b"] +print(len(d)) +print(list(d.keys())) +print(list(d.values())) + +# access remaining elements after deleting +print(d[10], d[1]) + +# add an element after deleting +d["abc"] = 123 +print(len(d)) +print(list(d.keys())) +print(list(d.values())) diff --git a/src/openmv/src/micropython/tests/basics/ordereddict_eq.py b/src/openmv/src/micropython/tests/basics/ordereddict_eq.py new file mode 100755 index 0000000..c69daf8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/ordereddict_eq.py @@ -0,0 +1,43 @@ +try: + from collections import OrderedDict +except ImportError: + try: + from ucollections import OrderedDict + except ImportError: + print("SKIP") + raise SystemExit + +x = OrderedDict() +y = OrderedDict() +x['a'] = 1 +x['b'] = 2 +y['a'] = 1 +y['b'] = 2 +print(x) +print(y) +print(x == y) + +z = OrderedDict() +z['b'] = 2 +z['a'] = 1 +print(y) +print(z) +print(y == z) + +del z['b'] +z['b'] = 2 +print(y) +print(z) +print(y == z) + +del x['a'] +del y['a'] +print(x) +print(y) +print(x == y) + +del z['b'] +del y['b'] +print(y) +print(z) +print(y == z) diff --git a/src/openmv/src/micropython/tests/basics/ordereddict_eq.py.exp b/src/openmv/src/micropython/tests/basics/ordereddict_eq.py.exp new file mode 100755 index 0000000..892ba0e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/ordereddict_eq.py.exp @@ -0,0 +1,15 @@ +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'a': 1, 'b': 2}) +True +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'b': 2, 'a': 1}) +False +OrderedDict({'a': 1, 'b': 2}) +OrderedDict({'a': 1, 'b': 2}) +True +OrderedDict({'b': 2}) +OrderedDict({'b': 2}) +True +OrderedDict({}) +OrderedDict({'a': 1}) +False diff --git a/src/openmv/src/micropython/tests/basics/parser.py b/src/openmv/src/micropython/tests/basics/parser.py new file mode 100755 index 0000000..626b67a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/parser.py @@ -0,0 +1,30 @@ +# parser tests + +try: + compile +except NameError: + print("SKIP") + raise SystemExit + +# completely empty string +# uPy and CPy differ for this case +#try: +# compile("", "stdin", "single") +#except SyntaxError: +# print("SyntaxError") +try: + compile("", "stdin", "eval") +except SyntaxError: + print("SyntaxError") +compile("", "stdin", "exec") + +# empty continued line +try: + compile("\\\n", "stdin", "single") +except SyntaxError: + print("SyntaxError") +try: + compile("\\\n", "stdin", "eval") +except SyntaxError: + print("SyntaxError") +compile("\\\n", "stdin", "exec") diff --git a/src/openmv/src/micropython/tests/basics/python34.py b/src/openmv/src/micropython/tests/basics/python34.py new file mode 100755 index 0000000..4030db1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/python34.py @@ -0,0 +1,42 @@ +# tests that differ when running under Python 3.4 vs 3.5/3.6/3.7 + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + +# from basics/fun_kwvarargs.py +# test evaluation order of arguments (in 3.4 it's backwards, 3.5 it's fixed) +def f4(*vargs, **kwargs): + print(vargs, kwargs) +def print_ret(x): + print(x) + return x +f4(*print_ret(['a', 'b']), kw_arg=print_ret(None)) + +# test evaluation order of dictionary key/value pair (in 3.4 it's backwards) +{print_ret(1):print_ret(2)} + +# from basics/syntaxerror.py +def test_syntax(code): + try: + exec(code) + except SyntaxError: + print("SyntaxError") +test_syntax("f(*a, *b)") # can't have multiple * (in 3.5 we can) +test_syntax("f(**a, **b)") # can't have multiple ** (in 3.5 we can) +test_syntax("f(*a, b)") # can't have positional after * +test_syntax("f(**a, b)") # can't have positional after ** +test_syntax("() = []") # can't assign to empty tuple (in 3.6 we can) +test_syntax("del ()") # can't delete empty tuple (in 3.6 we can) + +# from basics/sys1.py +# uPy prints version 3.4 +import sys +print(sys.version[:3]) +print(sys.version_info[0], sys.version_info[1]) + +# from basics/exception1.py +# in 3.7 no comma is printed if there is only 1 arg (in 3.4-3.6 one is printed) +print(repr(IndexError("foo"))) diff --git a/src/openmv/src/micropython/tests/basics/python34.py.exp b/src/openmv/src/micropython/tests/basics/python34.py.exp new file mode 100755 index 0000000..8480171 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/python34.py.exp @@ -0,0 +1,14 @@ +None +['a', 'b'] +('a', 'b') {'kw_arg': None} +2 +1 +SyntaxError +SyntaxError +SyntaxError +SyntaxError +SyntaxError +SyntaxError +3.4 +3 4 +IndexError('foo',) diff --git a/src/openmv/src/micropython/tests/basics/python36.py b/src/openmv/src/micropython/tests/basics/python36.py new file mode 100755 index 0000000..20ecd92 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/python36.py @@ -0,0 +1,10 @@ +# tests for things that only Python 3.6 supports + +# underscores in numeric literals +print(100_000) +print(0b1010_0101) +print(0xff_ff) + +# underscore supported by int constructor +print(int('1_2_3')) +print(int('0o1_2_3', 8)) diff --git a/src/openmv/src/micropython/tests/basics/python36.py.exp b/src/openmv/src/micropython/tests/basics/python36.py.exp new file mode 100755 index 0000000..4b65daa --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/python36.py.exp @@ -0,0 +1,5 @@ +100000 +165 +65535 +123 +83 diff --git a/src/openmv/src/micropython/tests/basics/return1.py b/src/openmv/src/micropython/tests/basics/return1.py new file mode 100755 index 0000000..7209d87 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/return1.py @@ -0,0 +1,13 @@ +# test return statement + +def f(): + return +print(f()) + +def g(): + return 1 +print(g()) + +def f(x): + return 1 if x else 2 +print(f(0), f(1)) diff --git a/src/openmv/src/micropython/tests/basics/scope.py b/src/openmv/src/micropython/tests/basics/scope.py new file mode 100755 index 0000000..11704c4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/scope.py @@ -0,0 +1,43 @@ +# test scoping rules + +# explicit global variable +a = 1 +def f(): + global a + global a, a # should be able to redefine as global + a = 2 +f() +print(a) + +# explicit nonlocal variable +def f(): + a = 1 + def g(): + nonlocal a + nonlocal a, a # should be able to redefine as nonlocal + a = 2 + g() + return a +print(f()) + +# nonlocal at inner-inner level (h) +def f(): + x = 1 + def g(): + def h(): + nonlocal x + return x + return h + return g +print(f()()()) + +# nonlocal declared at outer level (g), and referenced by inner level (h) +def f(): + x = 1 + def g(): + nonlocal x + def h(): + return x + return h + return g +print(f()()()) diff --git a/src/openmv/src/micropython/tests/basics/self_type_check.py b/src/openmv/src/micropython/tests/basics/self_type_check.py new file mode 100755 index 0000000..947e362 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/self_type_check.py @@ -0,0 +1,31 @@ +# make sure type of first arg (self) to a builtin method is checked + +list.append + +try: + list.append() +except TypeError as e: + print("TypeError") + +try: + list.append(1) +except TypeError as e: + print("TypeError") + +try: + list.append(1, 2) +except TypeError as e: + print("TypeError") + +l = [] +list.append(l, 2) +print(l) + +try: + getattr(list, "append")(1, 2) +except TypeError as e: + print("TypeError") + +l = [] +getattr(list, "append")(l, 2) +print(l) diff --git a/src/openmv/src/micropython/tests/basics/seq_unpack.py b/src/openmv/src/micropython/tests/basics/seq_unpack.py new file mode 100755 index 0000000..084ddb9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/seq_unpack.py @@ -0,0 +1,43 @@ +# Basics +a, b = 1, 2 +print(a, b) +a, b = (1, 2) +print(a, b) +(a, b) = 1, 2 +print(a, b) +(a, b) = (1, 2) +print(a, b) + +# Tuples/lists are optimized +a, b = [1, 2] +print(a, b) +[a, b] = 100, 200 +print(a, b) + +# optimised 3-way swap +a = 1 +b = 2 +c = 3 +a, b, c = b, c, a +print(a, b, c) + +try: + a, b, c = (1, 2) +except ValueError: + print("ValueError") +try: + a, b, c = [1, 2, 3, 4] +except ValueError: + print("ValueError") + +# Generic iterable object +a, b, c = range(3) +print(a, b, c) +try: + a, b, c = range(2) +except ValueError: + print("ValueError") +try: + a, b, c = range(4) +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/set_add.py b/src/openmv/src/micropython/tests/basics/set_add.py new file mode 100755 index 0000000..ac81f48 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_add.py @@ -0,0 +1,3 @@ +s = {1, 2, 3, 4} +print(s.add(5)) +print(sorted(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_basic.py b/src/openmv/src/micropython/tests/basics/set_basic.py new file mode 100755 index 0000000..6ea69e4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_basic.py @@ -0,0 +1,17 @@ +# basic sets + +s = {1} +print(s) + +s = {3, 4, 3, 1} +print(sorted(s)) + +# expression in constructor +s = {1 + len(s)} +print(s) + +# Sets are not hashable +try: + {s: 1} +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/set_binop.py b/src/openmv/src/micropython/tests/basics/set_binop.py new file mode 100755 index 0000000..bf55f87 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_binop.py @@ -0,0 +1,72 @@ +# test set binary operations + +sets = [set(), {1}, {1, 2}, {1, 2, 3}, {2, 3}, {2, 3, 5}, {5}, {7}] +for s in sets: + for t in sets: + print(sorted(s), '|', sorted(t), '=', sorted(s | t)) + print(sorted(s), '^', sorted(t), '=', sorted(s ^ t)) + print(sorted(s), '&', sorted(t), '=', sorted(s & t)) + print(sorted(s), '-', sorted(t), '=', sorted(s - t)) + u = s.copy() + u |= t + print(sorted(s), "|=", sorted(t), '-->', sorted(u)) + u = s.copy() + u ^= t + print(sorted(s), "^=", sorted(t), '-->', sorted(u)) + u = s.copy() + u &= t + print(sorted(s), "&=", sorted(t), "-->", sorted(u)) + u = s.copy() + u -= t + print(sorted(s), "-=", sorted(t), "-->", sorted(u)) + + print(sorted(s), '==', sorted(t), '=', s == t) + print(sorted(s), '!=', sorted(t), '=', s != t) + print(sorted(s), '>', sorted(t), '=', s > t) + print(sorted(s), '>=', sorted(t), '=', s >= t) + print(sorted(s), '<', sorted(t), '=', s < t) + print(sorted(s), '<=', sorted(t), '=', s <= t) + +print(set('abc') == 1) + +# make sure inplace operators modify the set + +s1 = s2 = set('abc') +s1 |= set('ad') +print(s1 is s2, len(s1)) + +s1 = s2 = set('abc') +s1 ^= set('ad') +print(s1 is s2, len(s1)) + +s1 = s2 = set('abc') +s1 &= set('ad') +print(s1 is s2, len(s1)) + +s1 = s2 = set('abc') +s1 -= set('ad') +print(s1 is s2, len(s1)) + +# RHS must be a set +try: + print(set('12') >= '1') +except TypeError: + print('TypeError') + +# RHS must be a set +try: + print(set('12') <= '123') +except TypeError: + print('TypeError') + +# unsupported operator +try: + set('abc') * set('abc') +except TypeError: + print('TypeError') + +# unsupported operator with RHS not a set +try: + set('abc') * 2 +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/set_clear.py b/src/openmv/src/micropython/tests/basics/set_clear.py new file mode 100755 index 0000000..6fda93f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_clear.py @@ -0,0 +1,3 @@ +s = {1, 2, 3, 4} +print(s.clear()) +print(list(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_comprehension.py b/src/openmv/src/micropython/tests/basics/set_comprehension.py new file mode 100755 index 0000000..12a9a29 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_comprehension.py @@ -0,0 +1 @@ +print({a for a in range(5)}) diff --git a/src/openmv/src/micropython/tests/basics/set_containment.py b/src/openmv/src/micropython/tests/basics/set_containment.py new file mode 100755 index 0000000..97694f7 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_containment.py @@ -0,0 +1,4 @@ +for i in 1, 2: + for o in {}, {1}, {2}: + print("{} in {}: {}".format(i, o, i in o)) + print("{} not in {}: {}".format(i, o, i not in o)) diff --git a/src/openmv/src/micropython/tests/basics/set_copy.py b/src/openmv/src/micropython/tests/basics/set_copy.py new file mode 100755 index 0000000..646fae0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_copy.py @@ -0,0 +1,6 @@ +s = {1, 2, 3, 4} +t = s.copy() +s.add(5) +t.add(7) +for i in s, t: + print(sorted(i)) diff --git a/src/openmv/src/micropython/tests/basics/set_difference.py b/src/openmv/src/micropython/tests/basics/set_difference.py new file mode 100755 index 0000000..97b63a8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_difference.py @@ -0,0 +1,19 @@ +l = [1, 2, 3, 4] +s = set(l) +outs = [s.difference(), + s.difference({1}), + s.difference({1}, [1, 2]), + s.difference({1}, {1, 2}, {2, 3})] +for out in outs: + print(sorted(out)) + +s = set(l) +print(s.difference_update()) +print(sorted(s)) +print(s.difference_update({1})) +print(sorted(s)) +print(s.difference_update({1}, [2])) +print(sorted(s)) + +s.difference_update(s) +print(s) diff --git a/src/openmv/src/micropython/tests/basics/set_discard.py b/src/openmv/src/micropython/tests/basics/set_discard.py new file mode 100755 index 0000000..baac264 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_discard.py @@ -0,0 +1,3 @@ +s = {1, 2} +print(s.discard(1)) +print(list(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_intersection.py b/src/openmv/src/micropython/tests/basics/set_intersection.py new file mode 100755 index 0000000..73804c8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_intersection.py @@ -0,0 +1,7 @@ +s = {1, 2, 3, 4} +print(sorted(s)) +print(sorted(s.intersection({1, 3}))) +print(sorted(s.intersection([3, 4]))) + +print(s.intersection_update([1])) +print(sorted(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_isdisjoint.py b/src/openmv/src/micropython/tests/basics/set_isdisjoint.py new file mode 100755 index 0000000..7fb7e76 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_isdisjoint.py @@ -0,0 +1,6 @@ +s = {1, 2, 3, 4} +print(s.isdisjoint({1})) +print(s.isdisjoint([2])) +print(s.isdisjoint([])) +print(s.isdisjoint({7,8,9,10})) +print(s.isdisjoint([7,8,9,1])) diff --git a/src/openmv/src/micropython/tests/basics/set_isfooset.py b/src/openmv/src/micropython/tests/basics/set_isfooset.py new file mode 100755 index 0000000..27dedea --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_isfooset.py @@ -0,0 +1,6 @@ +sets = [set(), {1}, {1, 2, 3}, {3, 4, 5}, {5, 6, 7}] +args = sets + [[1], [1, 2], [1, 2 ,3]] +for i in sets: + for j in args: + print(i.issubset(j)) + print(i.issuperset(j)) diff --git a/src/openmv/src/micropython/tests/basics/set_iter.py b/src/openmv/src/micropython/tests/basics/set_iter.py new file mode 100755 index 0000000..2960177 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_iter.py @@ -0,0 +1,5 @@ +s = {1, 2, 3, 4} +l = list(s) +l.sort() +print(l) + diff --git a/src/openmv/src/micropython/tests/basics/set_iter_of_iter.py b/src/openmv/src/micropython/tests/basics/set_iter_of_iter.py new file mode 100755 index 0000000..e3e91fa --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_iter_of_iter.py @@ -0,0 +1,2 @@ +i = iter(iter({1, 2, 3})) +print(sorted(i)) diff --git a/src/openmv/src/micropython/tests/basics/set_pop.py b/src/openmv/src/micropython/tests/basics/set_pop.py new file mode 100755 index 0000000..e951ca5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_pop.py @@ -0,0 +1,18 @@ +s = {1} +print(s.pop()) +try: + print(s.pop(), "!!!") +except KeyError: + pass +else: + print("Failed to raise KeyError") + +# this tests an optimisation in mp_set_remove_first +# N must not be equal to one of the values in hash_allocation_sizes +N = 11 +s = set(range(N)) +while s: + print(s.pop()) # last pop() should trigger the optimisation +for i in range(N): + s.add(i) # check that we can add the numbers back to the set +print(sorted(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_remove.py b/src/openmv/src/micropython/tests/basics/set_remove.py new file mode 100755 index 0000000..0727239 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_remove.py @@ -0,0 +1,33 @@ +# basic test +s = {1} +print(s.remove(1)) +print(list(s)) +try: + print(s.remove(1), "!!!") +except KeyError as er: + print('KeyError', er.args[0]) +else: + print("failed to raise KeyError") + +# test sets of varying size +for n in range(20): + print('testing set with {} items'.format(n)) + for i in range(n): + # create set + s = set() + for j in range(n): + s.add(str(j)) + print(len(s)) + + # delete an item + s.remove(str(i)) + print(len(s)) + + # check items + for j in range(n): + if str(j) in s: + if j == i: + print(j, 'in s, but it should not be') + else: + if j != i: + print(j, 'not in s, but it should be') diff --git a/src/openmv/src/micropython/tests/basics/set_specialmeth.py b/src/openmv/src/micropython/tests/basics/set_specialmeth.py new file mode 100755 index 0000000..76036f3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_specialmeth.py @@ -0,0 +1,5 @@ +# set object with special methods + +s = {1, 2} +print(s.__contains__(1)) +print(s.__contains__(3)) diff --git a/src/openmv/src/micropython/tests/basics/set_symmetric_difference.py b/src/openmv/src/micropython/tests/basics/set_symmetric_difference.py new file mode 100755 index 0000000..ec3cae0 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_symmetric_difference.py @@ -0,0 +1,5 @@ +print(sorted({1,2}.symmetric_difference({2,3}))) +print(sorted({1,2}.symmetric_difference([2,3]))) +s = {1,2} +print(s.symmetric_difference_update({2,3})) +print(sorted(s)) diff --git a/src/openmv/src/micropython/tests/basics/set_type.py b/src/openmv/src/micropython/tests/basics/set_type.py new file mode 100755 index 0000000..787a99e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_type.py @@ -0,0 +1,15 @@ +# set type + +# This doesn't really work as expected, because {None} +# leads SyntaxError during parsing. +try: + set +except NameError: + print("SKIP") + raise SystemExit + +print(set) + +print(type(set()) == set) + +print(type({None}) == set) diff --git a/src/openmv/src/micropython/tests/basics/set_union.py b/src/openmv/src/micropython/tests/basics/set_union.py new file mode 100755 index 0000000..572d12f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_union.py @@ -0,0 +1 @@ +print(sorted({1}.union({2}))) diff --git a/src/openmv/src/micropython/tests/basics/set_unop.py b/src/openmv/src/micropython/tests/basics/set_unop.py new file mode 100755 index 0000000..1f96dee --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_unop.py @@ -0,0 +1,12 @@ +# test set unary operations + +print(bool(set())) +print(bool(set('abc'))) + +print(len(set())) +print(len(set('abc'))) + +try: + hash(set('abc')) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/set_update.py b/src/openmv/src/micropython/tests/basics/set_update.py new file mode 100755 index 0000000..5e4e2a8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/set_update.py @@ -0,0 +1,7 @@ +s = {1} +s.update() +print(s) +s.update([2]) +print(sorted(s)) +s.update([1,3], [2,2,4]) +print(sorted(s)) diff --git a/src/openmv/src/micropython/tests/basics/slice_attrs.py b/src/openmv/src/micropython/tests/basics/slice_attrs.py new file mode 100755 index 0000000..e85ead4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/slice_attrs.py @@ -0,0 +1,24 @@ +# test builtin slice attributes access + +# print slice attributes +class A: + def __getitem__(self, idx): + print(idx.start, idx.stop, idx.step) + +try: + t = A()[1:2] +except: + print("SKIP") + raise SystemExit + + +A()[1:2:3] + +# test storing to attr (shouldn't be allowed) +class B: + def __getitem__(self, idx): + try: + idx.start = 0 + except AttributeError: + print('AttributeError') +B()[:] diff --git a/src/openmv/src/micropython/tests/basics/slice_intbig.py b/src/openmv/src/micropython/tests/basics/slice_intbig.py new file mode 100755 index 0000000..cc82052 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/slice_intbig.py @@ -0,0 +1,5 @@ +# test slicing when arguments are bignums + +print(list(range(10))[(1<<66)>>65:]) +print(list(range(10))[:(1<<66)>>65]) +print(list(range(10))[::(1<<66)>>65]) diff --git a/src/openmv/src/micropython/tests/basics/slots_bool_len.py b/src/openmv/src/micropython/tests/basics/slots_bool_len.py new file mode 100755 index 0000000..481fe9b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/slots_bool_len.py @@ -0,0 +1,17 @@ +class A: + def __bool__(self): + print('__bool__') + return True + def __len__(self): + print('__len__') + return 1 + +class B: + def __len__(self): + print('__len__') + return 0 + +print(bool(A())) +print(len(A())) +print(bool(B())) +print(len(B())) diff --git a/src/openmv/src/micropython/tests/basics/special_methods.py b/src/openmv/src/micropython/tests/basics/special_methods.py new file mode 100755 index 0000000..9f57247 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/special_methods.py @@ -0,0 +1,108 @@ +class Cud(): + + def __init__(self): + print("__init__ called") + + def __repr__(self): + print("__repr__ called") + return "" + + def __lt__(self, other): + print("__lt__ called") + + def __le__(self, other): + print("__le__ called") + + def __eq__(self, other): + print("__eq__ called") + + def __ne__(self, other): + print("__ne__ called") + + def __ge__(self, other): + print("__ge__ called") + + def __gt__(self, other): + print("__gt__ called") + + def __abs__(self): + print("__abs__ called") + + def __add__(self, other): + print("__add__ called") + + def __and__(self, other): + print("__and__ called") + + def __floordiv__(self, other): + print("__floordiv__ called") + + def __index__(self, other): + print("__index__ called") + + def __inv__(self): + print("__inv__ called") + + def __invert__(self): + print("__invert__ called") + + def __lshift__(self, val): + print("__lshift__ called") + + def __mod__(self, val): + print("__mod__ called") + + def __mul__(self, other): + print("__mul__ called") + + def __matmul__(self, other): + print("__matmul__ called") + + def __neg__(self): + print("__neg__ called") + + def __or__(self, other): + print("__or__ called") + + def __pos__(self): + print("__pos__ called") + + def __pow__(self, val): + print("__pow__ called") + + def __rshift__(self, val): + print("__rshift__ called") + + def __sub__(self, other): + print("__sub__ called") + + def __truediv__(self, other): + print("__truediv__ called") + + def __div__(self, other): + print("__div__ called") + + def __xor__(self, other): + print("__xor__ called") + + def __iadd__(self, other): + print("__iadd__ called") + return self + + def __isub__(self, other): + print("__isub__ called") + return self + +cud1 = Cud() +cud2 = Cud() + +str(cud1) +cud1 < cud2 +cud1 <= cud2 +cud1 == cud2 +cud1 >= cud2 +cud1 > cud2 +cud1 + cud2 +cud1 - cud2 + +# more in special_methods2.py diff --git a/src/openmv/src/micropython/tests/basics/special_methods2.py b/src/openmv/src/micropython/tests/basics/special_methods2.py new file mode 100755 index 0000000..c21618e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/special_methods2.py @@ -0,0 +1,139 @@ +class Cud(): + + def __init__(self): + #print("__init__ called") + pass + + def __repr__(self): + print("__repr__ called") + return "" + + def __lt__(self, other): + print("__lt__ called") + + def __le__(self, other): + print("__le__ called") + + def __eq__(self, other): + print("__eq__ called") + + def __ne__(self, other): + print("__ne__ called") + + def __ge__(self, other): + print("__ge__ called") + + def __gt__(self, other): + print("__gt__ called") + + def __abs__(self): + print("__abs__ called") + + def __add__(self, other): + print("__add__ called") + + def __and__(self, other): + print("__and__ called") + + def __floordiv__(self, other): + print("__floordiv__ called") + + def __index__(self, other): + print("__index__ called") + + def __inv__(self): + print("__inv__ called") + + def __invert__(self): + print("__invert__ called") + + def __lshift__(self, val): + print("__lshift__ called") + + def __mod__(self, val): + print("__mod__ called") + + def __mul__(self, other): + print("__mul__ called") + + def __matmul__(self, other): + print("__matmul__ called") + + def __neg__(self): + print("__neg__ called") + + def __or__(self, other): + print("__or__ called") + + def __pos__(self): + print("__pos__ called") + + def __pow__(self, val): + print("__pow__ called") + + def __rshift__(self, val): + print("__rshift__ called") + + def __sub__(self, other): + print("__sub__ called") + + def __truediv__(self, other): + print("__truediv__ called") + + def __div__(self, other): + print("__div__ called") + + def __xor__(self, other): + print("__xor__ called") + + def __iadd__(self, other): + print("__iadd__ called") + return self + + def __isub__(self, other): + print("__isub__ called") + return self + + def __dir__(self): + return ['a', 'b', 'c'] + +cud1 = Cud() +cud2 = Cud() + +try: + +cud1 +except TypeError: + print("SKIP") + raise SystemExit + +# the following require MICROPY_PY_ALL_SPECIAL_METHODS ++cud1 +-cud1 +~cud1 +cud1 * cud2 +cud1 / cud2 +cud2 // cud1 +cud1 += cud2 +cud1 -= cud2 +cud1 % 2 +cud1 ** 2 +cud1 | cud2 +cud1 & cud2 +cud1 ^ cud2 +cud1 << 1 +cud1 >> 1 + +# test that dir() delegates to __dir__ special method +print(dir(cud1)) + +# test that dir() does not delegate to __dir__ for the type +print('a' in dir(Cud)) + +# TODO: the following operations are not supported on every ports +# +# ne is not supported, !(eq) is called instead +#cud1 != cud2 +# +# in the followin test, cpython still calls __eq__ +# cud3=cud1 +# cud3==cud1 diff --git a/src/openmv/src/micropython/tests/basics/string1.py b/src/openmv/src/micropython/tests/basics/string1.py new file mode 100755 index 0000000..b3abfb9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string1.py @@ -0,0 +1,54 @@ +# basic strings + +# literals +print('abc') +print(r'abc') +print(u'abc') +print(repr('\a\b\t\n\v\f\r')) +print('\z') # unrecognised escape char + +# construction +print(str()) +print(str('abc')) + +# inplace addition +x = 'abc' +print(x) +x += 'def' +print(x) + +# binary ops +print('123' + "456") +print('123' * 5) +try: + '123' * '1' +except TypeError: + print('TypeError') +try: + '123' + 1 +except TypeError: + print('TypeError') + +# subscription +print('abc'[1]) +print('abc'[-1]) +try: + 'abc'[100] +except IndexError: + print('IndexError') +try: + 'abc'[-4] +except IndexError: + print('IndexError') + +# iter +print(list('str')) + +# comparison +print('123' + '789' == '123789') +print('a' + 'b' != 'a' + 'b ') +print('1' + '2' > '2') +print('1' + '2' < '2') + +# printing quote char in string +print(repr('\'\"')) diff --git a/src/openmv/src/micropython/tests/basics/string_center.py b/src/openmv/src/micropython/tests/basics/string_center.py new file mode 100755 index 0000000..40e8af4 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_center.py @@ -0,0 +1,13 @@ +try: + str.center +except: + print("SKIP") + raise SystemExit + +print("foo".center(0)) +print("foo".center(1)) +print("foo".center(3)) +print("foo".center(4)) +print("foo".center(5)) +print("foo".center(6)) +print("foo".center(20)) diff --git a/src/openmv/src/micropython/tests/basics/string_compare.py b/src/openmv/src/micropython/tests/basics/string_compare.py new file mode 100755 index 0000000..6515809 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_compare.py @@ -0,0 +1,58 @@ +print("" == "") +print("" > "") +print("" < "") +print("" == "1") +print("1" == "") +print("" > "1") +print("1" > "") +print("" < "1") +print("1" < "") +print("" >= "1") +print("1" >= "") +print("" <= "1") +print("1" <= "") + +print("1" == "1") +print("1" != "1") +print("1" == "2") +print("1" == "10") + +print("1" > "1") +print("1" > "2") +print("2" > "1") +print("10" > "1") +print("1/" > "1") +print("1" > "10") +print("1" > "1/") + +print("1" < "1") +print("2" < "1") +print("1" < "2") +print("1" < "10") +print("1" < "1/") +print("10" < "1") +print("1/" < "1") + +print("1" >= "1") +print("1" >= "2") +print("2" >= "1") +print("10" >= "1") +print("1/" >= "1") +print("1" >= "10") +print("1" >= "1/") + +print("1" <= "1") +print("2" <= "1") +print("1" <= "2") +print("1" <= "10") +print("1" <= "1/") +print("10" <= "1") +print("1/" <= "1") + +# this tests an internal string that doesn't have a hash with a string +# that does have a hash, but the lengths of the two strings are different +import sys +print(sys.version == 'a long string that has a hash') + +# this special string would have a hash of 0 but is incremented to 1 +print('Q+?' == 'Q' + '+?') diff --git a/src/openmv/src/micropython/tests/basics/string_count.py b/src/openmv/src/micropython/tests/basics/string_count.py new file mode 100755 index 0000000..8fb5c98 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_count.py @@ -0,0 +1,59 @@ +try: + str.count +except AttributeError: + print("SKIP") + raise SystemExit + +print("".count("")) +print("".count("a")) +print("a".count("")) +print("a".count("a")) +print("a".count("b")) +print("b".count("a")) + +print("aaa".count("")) +print("aaa".count("a")) +print("aaa".count("aa")) +print("aaa".count("aaa")) +print("aaa".count("aaaa")) + +print("aaaa".count("")) +print("aaaa".count("a")) +print("aaaa".count("aa")) +print("aaaa".count("aaa")) +print("aaaa".count("aaaa")) +print("aaaa".count("aaaaa")) + +print("aaa".count("", 1)) +print("aaa".count("", 2)) +print("aaa".count("", 3)) + +print("aaa".count("", 1, 2)) + +print("asdfasdfaaa".count("asdf", -100)) +print("asdfasdfaaa".count("asdf", -8)) +print("asdf".count('s', True)) +print("asdf".count('a', True)) +print("asdf".count('a', False)) +print("asdf".count('a', 1 == 2)) +print("hello world".count('l')) +print("hello world".count('l', 5)) +print("hello world".count('l', 3)) +print("hello world".count('z', 3, 6)) +print("aaaa".count('a')) +print("aaaa".count('a', 0, 3)) +print("aaaa".count('a', 0, 4)) +print("aaaa".count('a', 0, 5)) +print("aaaa".count('a', 1, 5)) +print("aaaa".count('a', -1, 5)) +print("abbabba".count("abba")) + +def t(): + return True + +print("0000".count('0', t())) + +try: + 'abc'.count(1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/string_cr_conversion.py b/src/openmv/src/micropython/tests/basics/string_cr_conversion.py new file mode 100755 index 0000000..0c3ba16 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_cr_conversion.py @@ -0,0 +1 @@ +# this file has CR line endings to test lexer's conversion of them to LF # in triple quoted strings print(repr("""abc def""")) \ No newline at end of file diff --git a/src/openmv/src/micropython/tests/basics/string_crlf_conversion.py b/src/openmv/src/micropython/tests/basics/string_crlf_conversion.py new file mode 100755 index 0000000..f911210 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_crlf_conversion.py @@ -0,0 +1,4 @@ +# this file has CRLF line endings to test lexer's conversion of them to LF +# in triple quoted strings +print(repr("""abc +def""")) diff --git a/src/openmv/src/micropython/tests/basics/string_endswith.py b/src/openmv/src/micropython/tests/basics/string_endswith.py new file mode 100755 index 0000000..683562d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_endswith.py @@ -0,0 +1,17 @@ +print("foobar".endswith("bar")) +print("foobar".endswith("baR")) +print("foobar".endswith("bar1")) +print("foobar".endswith("foobar")) +print("foobar".endswith("")) +print("foobar".endswith("foobarbaz")) + +#print("1foobar".startswith("foo", 1)) +#print("1foo".startswith("foo", 1)) +#print("1foo".startswith("1foo", 1)) +#print("1fo".startswith("foo", 1)) +#print("1fo".startswith("foo", 10)) + +try: + "foobar".endswith(1) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/string_endswith_upy.py b/src/openmv/src/micropython/tests/basics/string_endswith_upy.py new file mode 100755 index 0000000..06a4e71 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_endswith_upy.py @@ -0,0 +1,6 @@ +# MicroPython doesn't support tuple argument + +try: + "foobar".endswith(("bar", "sth")) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/string_endswith_upy.py.exp b/src/openmv/src/micropython/tests/basics/string_endswith_upy.py.exp new file mode 100755 index 0000000..6002b71 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_endswith_upy.py.exp @@ -0,0 +1 @@ +TypeError diff --git a/src/openmv/src/micropython/tests/basics/string_escape.py b/src/openmv/src/micropython/tests/basics/string_escape.py new file mode 100755 index 0000000..000a871 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_escape.py @@ -0,0 +1,11 @@ +a = "a\1b" +print(len(a)) +print(ord(a[1])) +print(len("a\123b")) +a = "a\12345b" +print(len(a)) +print(ord(a[1])) + +a = "a\xffb" +print(len(a)) +print(ord(a[1])) diff --git a/src/openmv/src/micropython/tests/basics/string_find.py b/src/openmv/src/micropython/tests/basics/string_find.py new file mode 100755 index 0000000..f9fcad3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_find.py @@ -0,0 +1,29 @@ +print("hello world".find("ll")) +print("hello world".find("ll", None)) +print("hello world".find("ll", 1)) +print("hello world".find("ll", 1, None)) +print("hello world".find("ll", None, None)) +print("hello world".find("ll", 1, -1)) +print("hello world".find("ll", 1, 1)) +print("hello world".find("ll", 1, 2)) +print("hello world".find("ll", 1, 3)) +print("hello world".find("ll", 1, 4)) +print("hello world".find("ll", 1, 5)) +print("hello world".find("ll", -100)) +print("0000".find('0')) +print("0000".find('0', 0)) +print("0000".find('0', 1)) +print("0000".find('0', 2)) +print("0000".find('0', 3)) +print("0000".find('0', 4)) +print("0000".find('0', 5)) +print("0000".find('-1', 3)) +print("0000".find('1', 3)) +print("0000".find('1', 4)) +print("0000".find('1', 5)) +print("aaaaaaaaaaa".find("bbb", 9, 2)) + +try: + 'abc'.find(1) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/string_format.py b/src/openmv/src/micropython/tests/basics/string_format.py new file mode 100755 index 0000000..8b25924 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_format.py @@ -0,0 +1,76 @@ +# basic functionality test for {} format string + +def test(fmt, *args): + print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<') + +test("}}{{") +test("{}-{}", 1, [4, 5]) +test("{0}-{1}", 1, [4, 5]) +test("{1}-{0}", 1, [4, 5]) +test("{:x}", 1) +test("{!r}", 2) +test("{:x}", 0x10) +test("{!r}", "foo") +test("{!s}", "foo") +test("{0!r:>10s} {0!s:>10s}", "foo") + +test("{:4b}", 10) +test("{:4c}", 48) +test("{:4d}", 123) +test("{:4n}", 123) +test("{:4o}", 123) +test("{:4x}", 123) +test("{:4X}", 123) + +test("{:4,d}", 12345678) + +test("{:#4b}", 10) +test("{:#4o}", 123) +test("{:#4x}", 123) +test("{:#4X}", 123) + +test("{:#4d}", 0) +test("{:#4b}", 0) +test("{:#4o}", 0) +test("{:#4x}", 0) +test("{:#4X}", 0) + +test("{:<6s}", "ab") +test("{:>6s}", "ab") +test("{:^6s}", "ab") +test("{:.1s}", "ab") + +test("{: <6d}", 123) +test("{: <6d}", -123) +test("{:0<6d}", 123) +test("{:0<6d}", -123) +test("{:@<6d}", 123) +test("{:@<6d}", -123) + +test("{:@< 6d}", 123) +test("{:@< 6d}", -123) +test("{:@<+6d}", 123) +test("{:@<+6d}", -123) +test("{:@<-6d}", 123) +test("{:@<-6d}", -123) + +test("{:@>6d}", -123) +test("{:@<6d}", -123) +test("{:@=6d}", -123) +test("{:06d}", -123) + +test("{:>20}", "foo") +test("{:^20}", "foo") +test("{:<20}", "foo") + +# nested format specifiers +print("{:{}}".format(123, '#>10')) +print("{:{}{}{}}".format(123, '#', '>', '10')) +print("{0:{1}{2}}".format(123, '#>', '10')) +print("{text:{align}{width}}".format(text="foo", align="<", width=20)) +print("{text:{align}{width}}".format(text="foo", align="^", width=10)) +print("{text:{align}{width}}".format(text="foo", align=">", width=30)) + +print("{foo}/foo".format(foo="bar")) +print("{}".format(123, foo="bar")) +print("{}-{foo}".format(123, foo="bar")) diff --git a/src/openmv/src/micropython/tests/basics/string_format2.py b/src/openmv/src/micropython/tests/basics/string_format2.py new file mode 100755 index 0000000..881ff4f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_format2.py @@ -0,0 +1,64 @@ +# comprehensive functionality test for {} format string + +int_tests = False # these take a while +char_tests = True +str_tests = True + +def test(fmt, *args): + print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<') + +def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): + fmt = '{' + if conv: + fmt += '!' + fmt += conv + fmt += ':' + if alignment: + fmt += fill + fmt += alignment + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + if fill == '0' and alignment == '=': + fmt = '{:' + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + +if int_tests: + int_nums = (-1234, -123, -12, -1, 0, 1, 12, 123, 1234, True, False) + #int_nums = (-12, -1, 0, 1, 12, True, False) + for type in ('', 'b', 'd', 'o', 'x', 'X'): + for width in ('', '1', '3', '5', '7'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', ' ', '0', '@'): + for sign in ('', '+', '-', ' '): + for prefix in ('', '#'): + for num in int_nums: + test_fmt('', fill, alignment, sign, prefix, width, '', type, num) + +if char_tests: + for width in ('', '1', '2'): + for alignment in ('', '<', '>', '^'): + for fill in ('', ' ', '0', '@'): + test_fmt('', fill, alignment, '', '', width, '', 'c', 48) + +if str_tests: + for conv in ('', 'r', 's'): + for width in ('', '1', '4', '10'): + for alignment in ('', '<', '>', '^'): + for fill in ('', ' ', '0', '@'): + for str in ('', 'a', 'bcd', 'This is a test with a longer string'): + test_fmt(conv, fill, alignment, '', '', width, '', 's', str) diff --git a/src/openmv/src/micropython/tests/basics/string_format_error.py b/src/openmv/src/micropython/tests/basics/string_format_error.py new file mode 100755 index 0000000..708348d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_format_error.py @@ -0,0 +1,90 @@ +# tests for errors in {} format string + +try: + '{0:0}'.format('zzz') +except (ValueError): + print('ValueError') + +try: + '{1:}'.format(1) +except IndexError: + print('IndexError') + +try: + '}'.format('zzzz') +except ValueError: + print('ValueError') + +# end of format parsing conversion specifier +try: + '{!'.format('a') +except ValueError: + print('ValueError') + +# unknown conversion specifier +try: + 'abc{!d}'.format('1') +except ValueError: + print('ValueError') + +try: + '{abc'.format('zzzz') +except ValueError: + print('ValueError') + +# expected ':' after specifier +try: + '{!s :}'.format(2) +except ValueError: + print('ValueError') + +try: + '{}{0}'.format(1, 2) +except ValueError: + print('ValueError') + +try: + '{1:}'.format(1) +except IndexError: + print('IndexError') + +try: + '{ 0 :*^10}'.format(12) +except KeyError: + print('KeyError') + +try: + '{0}{}'.format(1) +except ValueError: + print('ValueError') + +try: + '{}{}'.format(1) +except IndexError: + print('IndexError') + +try: + '{0:+s}'.format('1') +except ValueError: + print('ValueError') + +try: + '{0:+c}'.format(1) +except ValueError: + print('ValueError') + +try: + '{0:s}'.format(1) +except ValueError: + print('ValueError') + +try: + '{:*"1"}'.format('zz') +except ValueError: + print('ValueError') + +# unknown format code for str arg +try: + '{:X}'.format('zz') +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/string_format_modulo.py b/src/openmv/src/micropython/tests/basics/string_format_modulo.py new file mode 100755 index 0000000..77bbcfb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_format_modulo.py @@ -0,0 +1,102 @@ +print("%%" % ()) +print("=%s=" % 1) +print("=%s=%s=" % (1, 2)) +print("=%s=" % (1,)) +print("=%s=" % [1, 2]) + +print("=%s=" % "str") +print("=%r=" % "str") + +try: + print("=%s=%s=" % 1) +except TypeError: + print("TypeError") + +try: + print("=%s=%s=%s=" % (1, 2)) +except TypeError: + print("TypeError") + +try: + print("=%s=" % (1, 2)) +except TypeError: + print("TypeError") + +print("%s" % True) +print("%s" % 1) +print("%.1s" % "ab") + +print("%r" % True) +print("%r" % 1) + +print("%c" % 48) +print("%c" % 'a') +print("%10s" % 'abc') +print("%-10s" % 'abc') + +# Should be able to print dicts; in this case they aren't used +# to lookup keywords in formats like %(foo)s +print('%s' % {}) +print('%s' % ({},)) + +# Cases when "*" used and there's not enough values total +try: + print("%*s" % 5) +except TypeError: + print("TypeError") +try: + print("%*.*s" % (1, 15)) +except TypeError: + print("TypeError") + +print("%(foo)s" % {"foo": "bar", "baz": False}) +print("%s %(foo)s %(foo)s" % {"foo": 1}) +try: + print("%(foo)s" % {}) +except KeyError: + print("KeyError") +# Using in "*" with dict got to fail +try: + print("%(foo)*s" % {"foo": "bar"}) +except TypeError: + print("TypeError") + +# When using %(foo)s format the single argument must be a dict +try: + '%(foo)s' % 1 +except TypeError: + print('TypeError') +try: + '%(foo)s' % ({},) +except TypeError: + print('TypeError') + +try: + '%(a' % {'a':1} +except ValueError: + print('ValueError') + +try: + '%.*d %.*d' % (20, 5) +except TypeError: + print('TypeError') + +try: + a = '%*' % 1 +except (ValueError): + print('ValueError') + +try: + '%c' % 'aa' +except TypeError: + print('TypeError') + +try: + '%l' % 1 +except ValueError: + print('ValueError') + +try: + 'a%' % 1 +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/basics/string_format_modulo_int.py b/src/openmv/src/micropython/tests/basics/string_format_modulo_int.py new file mode 100755 index 0000000..d1f29db --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_format_modulo_int.py @@ -0,0 +1,41 @@ +# test string modulo formatting with int values + +# basic cases +print("%d" % 10) +print("%+d" % 10) +print("% d" % 10) +print("%d" % -10) +print("%d" % True) +print("%i" % -10) +print("%i" % True) +print("%u" % -10) +print("%u" % True) +print("%x" % 18) +print("%o" % 18) +print("%X" % 18) +print("%#x" % 18) +print("%#X" % 18) +print("%#6o" % 18) +print("%#6x" % 18) +print("%#06x" % 18) + +# with * +print("%*d" % (5, 10)) +print("%*.*d" % (2, 2, 20)) +print("%*.*d" % (5, 8, 20)) + +# precision +for val in (-12, 12): + print(">%8.4d<" % val) + print(">% 8.4d<" % val) + print(">%+8.4d<" % val) + print(">%08.4d<" % val) + print(">%-8.4d<" % val) + print(">%-08.4d<" % val) + print(">%-+08.4d<" % val) + +# test + option with various amount of padding +for pad in ('', ' ', '0'): + for n in (1, 2, 3): + for val in (-1, 0, 1): + print(('%+' + pad + str(n) + 'd') % val) diff --git a/src/openmv/src/micropython/tests/basics/string_index.py b/src/openmv/src/micropython/tests/basics/string_index.py new file mode 100755 index 0000000..31f6900 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_index.py @@ -0,0 +1,78 @@ +print("hello world".index("ll")) +print("hello world".index("ll", None)) +print("hello world".index("ll", 1)) +print("hello world".index("ll", 1, None)) +print("hello world".index("ll", None, None)) +print("hello world".index("ll", 1, -1)) + +try: + print("hello world".index("ll", 1, 1)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("hello world".index("ll", 1, 2)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("hello world".index("ll", 1, 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +print("hello world".index("ll", 1, 4)) +print("hello world".index("ll", 1, 5)) +print("hello world".index("ll", -100)) +print("0000".index('0')) +print("0000".index('0', 0)) +print("0000".index('0', 1)) +print("0000".index('0', 2)) +print("0000".index('0', 3)) + +try: + print("0000".index('0', 4)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".index('0', 5)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".index('-1', 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".index('1', 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".index('1', 4)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".index('1', 5)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/string_istest.py b/src/openmv/src/micropython/tests/basics/string_istest.py new file mode 100755 index 0000000..7ea6c45 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_istest.py @@ -0,0 +1,20 @@ +print("".isspace()) +print(" \t\n\r\v\f".isspace()) +print("a".isspace()) +print(" \t\n\r\v\fa".isspace()) +print("".isalpha()) +print("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha()) +print("0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha()) +print("this ".isalpha()) +print("".isdigit()) +print("0123456789".isdigit()) +print("0123456789a".isdigit()) +print("0123456789 ".isdigit()) +print("".isupper()) +print("CHEESE-CAKE WITH ... _FROSTING_*99".isupper()) +print("aB".isupper()) +print("".islower()) +print("cheese-cake with ... _frosting_*99".islower()) +print("aB".islower()) +print("123".islower()) +print("123a".islower()) diff --git a/src/openmv/src/micropython/tests/basics/string_join.py b/src/openmv/src/micropython/tests/basics/string_join.py new file mode 100755 index 0000000..82f1b79 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_join.py @@ -0,0 +1,42 @@ +print(','.join(())) +print(','.join(('a',))) +print(','.join(('a', 'b'))) + +print(','.join([])) +print(','.join(['a'])) +print(','.join(['a', 'b'])) + +print(''.join('')) +print(''.join('abc')) +print(','.join('abc')) +print(','.join('abc' for i in range(5))) + +print(b','.join([b'abc', b'123'])) + +try: + ''.join(None) +except TypeError: + print("TypeError") + +try: + print(b','.join(['abc', b'123'])) +except TypeError: + print("TypeError") + +try: + print(','.join([b'abc', b'123'])) +except TypeError: + print("TypeError") + +# joined by the compiler +print("a" "b") +print("a" '''b''') +print("a" # inline comment + "b") +print("a" \ + "b") + +# the following should not be joined by the compiler +x = 'a' +'b' +print(x) diff --git a/src/openmv/src/micropython/tests/basics/string_large.py b/src/openmv/src/micropython/tests/basics/string_large.py new file mode 100755 index 0000000..90a4af2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_large.py @@ -0,0 +1,2 @@ +s1 = "long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string long string" +s2 = "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" "concatenated string" diff --git a/src/openmv/src/micropython/tests/basics/string_mult.py b/src/openmv/src/micropython/tests/basics/string_mult.py new file mode 100755 index 0000000..c0713c1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_mult.py @@ -0,0 +1,12 @@ +# basic multiplication +print('0' * 5) + +# check negative, 0, positive; lhs and rhs multiplication +for i in (-4, -2, 0, 2, 4): + print(i * '12') + print('12' * i) + +# check that we don't modify existing object +a = '123' +c = a * 3 +print(a, c) diff --git a/src/openmv/src/micropython/tests/basics/string_partition.py b/src/openmv/src/micropython/tests/basics/string_partition.py new file mode 100755 index 0000000..bc36388 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_partition.py @@ -0,0 +1,46 @@ +try: + str.partition +except AttributeError: + print("SKIP") + raise SystemExit + +print("asdf".partition('g')) +print("asdf".partition('a')) +print("asdf".partition('s')) +print("asdf".partition('f')) +print("asdf".partition('d')) +print("asdf".partition('asd')) +print("asdf".partition('sdf')) +print("asdf".partition('as')) +print("asdf".partition('df')) +print("asdf".partition('asdf')) +print("asdf".partition('asdfa')) +print("asdf".partition('fasdf')) +print("asdf".partition('fasdfa')) +print("abba".partition('a')) +print("abba".partition('b')) + +try: + print("asdf".partition(1)) +except TypeError: + print("Raised TypeError") +else: + print("Did not raise TypeError") + +try: + print("asdf".partition('')) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +# Bytes +print(b"abba".partition(b'b')) +try: + print(b"abba".partition('b')) +except TypeError: + print("Raised TypeError") +try: + print("abba".partition(b'b')) +except TypeError: + print("Raised TypeError") diff --git a/src/openmv/src/micropython/tests/basics/string_replace.py b/src/openmv/src/micropython/tests/basics/string_replace.py new file mode 100755 index 0000000..f03b389 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_replace.py @@ -0,0 +1,24 @@ +print("".replace("a", "b")) +print("aaa".replace("b", "c")) +print("aaa".replace("a", "b", 0)) +print("aaa".replace("a", "b", -5)) +print("asdfasdf".replace("a", "b")) +print("aabbaabbaabbaa".replace("aa", "cc", 3)) +print("a".replace("aa", "bb")) +print("testingtesting".replace("ing", "")) +print("testINGtesting".replace("ing", "ING!")) + +print("".replace("", "1")) +print("A".replace("", "1")) +print("AB".replace("", "1")) +print("AB".replace("", "12")) + +try: + 'abc'.replace(1, 2) +except TypeError: + print('TypeError') + +try: + 'abc'.replace('1', 2) +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/string_repr.py b/src/openmv/src/micropython/tests/basics/string_repr.py new file mode 100755 index 0000000..2a3ef25 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_repr.py @@ -0,0 +1,4 @@ +# anything above 0xa0 is printed as Unicode by CPython +# the abobe is CPython implementation detail, stick to ASCII +for c in range(0x80): + print("0x%02x: %s" % (c, repr(chr(c)))) diff --git a/src/openmv/src/micropython/tests/basics/string_rfind.py b/src/openmv/src/micropython/tests/basics/string_rfind.py new file mode 100755 index 0000000..54269d6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_rfind.py @@ -0,0 +1,24 @@ +print("hello world".rfind("ll")) +print("hello world".rfind("ll", None)) +print("hello world".rfind("ll", 1)) +print("hello world".rfind("ll", 1, None)) +print("hello world".rfind("ll", None, None)) +print("hello world".rfind("ll", 1, -1)) +print("hello world".rfind("ll", 1, 1)) +print("hello world".rfind("ll", 1, 2)) +print("hello world".rfind("ll", 1, 3)) +print("hello world".rfind("ll", 1, 4)) +print("hello world".rfind("ll", 1, 5)) +print("hello world".rfind("ll", -100)) +print("0000".rfind('0')) +print("0000".rfind('0', 0)) +print("0000".rfind('0', 1)) +print("0000".rfind('0', 2)) +print("0000".rfind('0', 3)) +print("0000".rfind('0', 4)) +print("0000".rfind('0', 5)) +print("0000".rfind('-1', 3)) +print("0000".rfind('1', 3)) +print("0000".rfind('1', 4)) +print("0000".rfind('1', 5)) +print("aaaaaaaaaaa".rfind("bbb", 9, 2)) diff --git a/src/openmv/src/micropython/tests/basics/string_rindex.py b/src/openmv/src/micropython/tests/basics/string_rindex.py new file mode 100755 index 0000000..25acd37 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_rindex.py @@ -0,0 +1,78 @@ +print("hello world".rindex("ll")) +print("hello world".rindex("ll", None)) +print("hello world".rindex("ll", 1)) +print("hello world".rindex("ll", 1, None)) +print("hello world".rindex("ll", None, None)) +print("hello world".rindex("ll", 1, -1)) + +try: + print("hello world".rindex("ll", 1, 1)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("hello world".rindex("ll", 1, 2)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("hello world".rindex("ll", 1, 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +print("hello world".rindex("ll", 1, 4)) +print("hello world".rindex("ll", 1, 5)) +print("hello world".rindex("ll", -100)) +print("0000".rindex('0')) +print("0000".rindex('0', 0)) +print("0000".rindex('0', 1)) +print("0000".rindex('0', 2)) +print("0000".rindex('0', 3)) + +try: + print("0000".rindex('0', 4)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".rindex('0', 5)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".rindex('-1', 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".rindex('1', 3)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".rindex('1', 4)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +try: + print("0000".rindex('1', 5)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/string_rpartition.py b/src/openmv/src/micropython/tests/basics/string_rpartition.py new file mode 100755 index 0000000..6d65dfa --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_rpartition.py @@ -0,0 +1,35 @@ +try: + str.partition +except AttributeError: + print("SKIP") + raise SystemExit + +print("asdf".rpartition('g')) +print("asdf".rpartition('a')) +print("asdf".rpartition('s')) +print("asdf".rpartition('f')) +print("asdf".rpartition('d')) +print("asdf".rpartition('asd')) +print("asdf".rpartition('sdf')) +print("asdf".rpartition('as')) +print("asdf".rpartition('df')) +print("asdf".rpartition('asdf')) +print("asdf".rpartition('asdfa')) +print("asdf".rpartition('fasdf')) +print("asdf".rpartition('fasdfa')) +print("abba".rpartition('a')) +print("abba".rpartition('b')) + +try: + print("asdf".rpartition(1)) +except TypeError: + print("Raised TypeError") +else: + print("Did not raise TypeError") + +try: + print("asdf".rpartition('')) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/string_rsplit.py b/src/openmv/src/micropython/tests/basics/string_rsplit.py new file mode 100755 index 0000000..b92b8f3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_rsplit.py @@ -0,0 +1,58 @@ +# default separator (whitespace) +print("a b".rsplit()) +#print(" a b ".rsplit(None)) +#print(" a b ".rsplit(None, 1)) +#print(" a b ".rsplit(None, 2)) +#print(" a b c ".rsplit(None, 1)) +#print(" a b c ".rsplit(None, 0)) +#print(" a b c ".rsplit(None, -1)) + +# empty separator should fail (this actually delegates to .split()) +try: + "abc".rsplit('') +except ValueError: + print("ValueError") + +# empty separator should fail (error handled in .rsplit()) +try: + 'a a a a'.rsplit('', 5) +except ValueError: + print('ValueError') + +# bad separator type +try: + 'a a a a'.rsplit(1) +except TypeError: + print('TypeError') + +# non-empty separator +print("abc".rsplit("a")) +print("abc".rsplit("b")) +print("abc".rsplit("c")) +print("abc".rsplit("z")) +print("abc".rsplit("ab")) +print("abc".rsplit("bc")) +print("abc".rsplit("abc")) +print("abc".rsplit("abcd")) +print("abcabc".rsplit("bc")) +print("abcabc".rsplit("bc", 0)) +print("abcabc".rsplit("bc", 1)) +print("abcabc".rsplit("bc", 2)) + +print("10/11/12".rsplit("/", 1)) +print("10/11/12".rsplit("/", 2)) +print("10/11/12".rsplit("/", 3)) +print("10/11/12".rsplit("/", 4)) +print("10/11/12".rsplit("/", 5)) + +print("/*10/*11/*12/*".rsplit("/*", 1)) +print("/*10/*11/*12/*".rsplit("/*", 2)) +print("/*10/*11/*12/*".rsplit("/*", 3)) +print("/*10/*11/*12/*".rsplit("/*", 4)) +print("/*10/*11/*12/*".rsplit("/*", 5)) + +print(b"abcabc".rsplit(b"bc", 2)) + +# negative "maxsplit" should delegate to .split() +print('abaca'.rsplit('a', -1)) +print('abaca'.rsplit('a', -2)) diff --git a/src/openmv/src/micropython/tests/basics/string_slice.py b/src/openmv/src/micropython/tests/basics/string_slice.py new file mode 100755 index 0000000..89853d3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_slice.py @@ -0,0 +1,35 @@ +print("123"[0:1]) + +print("123"[0:2]) + +print("123"[:1]) + +print("123"[1:]) + +# Idiom for copying sequence +print("123"[:]) + +print("123"[:-1]) + +# Weird cases +print("123"[0:0]) +print("123"[1:0]) +print("123"[1:1]) +print("123"[-1:-1]) +print("123"[-3:]) +print("123"[-3:3]) +print("123"[0:]) +print("123"[:0]) +print("123"[:-3]) +print("123"[:-4]) +# Range check testing, don't segfault, please ;-) +print("123"[:1000000]) +print("123"[1000000:]) +print("123"[:-1000000]) +print("123"[-1000000:]) +# No IndexError! +print(""[1:1]) +print(""[-1:-1]) + +# bytes +print(b"123"[0:2]) diff --git a/src/openmv/src/micropython/tests/basics/string_split.py b/src/openmv/src/micropython/tests/basics/string_split.py new file mode 100755 index 0000000..0670734 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_split.py @@ -0,0 +1,32 @@ +# default separator (whitespace) +print("a b".split()) +print(" a b ".split(None)) +print(" a b ".split(None, 1)) +print(" a b ".split(None, 2)) +print(" a b c ".split(None, 1)) +print(" a b c ".split(None, 0)) +print(" a b c ".split(None, -1)) +print("foo\n\t\x07\v\nbar".split()) +print("foo\nbar\n".split()) + +# empty separator should fail +try: + "abc".split('') +except ValueError: + print("ValueError") + +# non-empty separator +print("abc".split("a")) +print("abc".split("b")) +print("abc".split("c")) +print("abc".split("z")) +print("abc".split("ab")) +print("abc".split("bc")) +print("abc".split("abc")) +print("abc".split("abcd")) +print("abcabc".split("bc")) +print("abcabc".split("bc", 0)) +print("abcabc".split("bc", 1)) +print("abcabc".split("bc", 2)) + +print(b"abcabc".split(b"bc", 2)) diff --git a/src/openmv/src/micropython/tests/basics/string_splitlines.py b/src/openmv/src/micropython/tests/basics/string_splitlines.py new file mode 100755 index 0000000..c4c3fcb --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_splitlines.py @@ -0,0 +1,37 @@ +# test string.splitlines() method + +try: + str.splitlines +except: + print("SKIP") + raise SystemExit + +# test \n as newline +print("foo\nbar".splitlines()) +print("foo\nbar\n".splitlines()) +print("foo and\nbar\n".splitlines()) +print("foo\nbar\n\n".splitlines()) +print("foo\n\nbar\n\n".splitlines()) +print("\nfoo\nbar\n".splitlines()) + +# test \r as newline +print("foo\rbar\r".splitlines()) +print("\rfoo and\r\rbar\r".splitlines()) + +# test \r\n as newline +print("foo\r\nbar\r\n".splitlines()) +print("\r\nfoo and\r\n\r\nbar\r\n".splitlines()) + +# test keepends arg +print("foo\nbar".splitlines(True)) +print("foo\nbar\n".splitlines(True)) +print("foo\nbar\n\n".splitlines(True)) +print("foo\rbar".splitlines(keepends=True)) +print("foo\rbar\r\r".splitlines(keepends=True)) +print("foo\r\nbar".splitlines(keepends=True)) +print("foo\r\nbar\r\n\r\n".splitlines(keepends=True)) + +# test splitting bytes objects +print(b"foo\nbar".splitlines()) +print(b"foo\nbar\n".splitlines()) +print(b"foo\r\nbar\r\n\r\n".splitlines(True)) diff --git a/src/openmv/src/micropython/tests/basics/string_startswith.py b/src/openmv/src/micropython/tests/basics/string_startswith.py new file mode 100755 index 0000000..e63ae3c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_startswith.py @@ -0,0 +1,16 @@ +print("foobar".startswith("foo")) +print("foobar".startswith("Foo")) +print("foobar".startswith("foo1")) +print("foobar".startswith("foobar")) +print("foobar".startswith("")) + +print("1foobar".startswith("foo", 1)) +print("1foo".startswith("foo", 1)) +print("1foo".startswith("1foo", 1)) +print("1fo".startswith("foo", 1)) +print("1fo".startswith("foo", 10)) + +try: + "foobar".startswith(1) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/string_startswith_upy.py b/src/openmv/src/micropython/tests/basics/string_startswith_upy.py new file mode 100755 index 0000000..9ea1796 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_startswith_upy.py @@ -0,0 +1,6 @@ +# MicroPython doesn't support tuple argument + +try: + "foobar".startswith(("foo", "sth")) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/string_startswith_upy.py.exp b/src/openmv/src/micropython/tests/basics/string_startswith_upy.py.exp new file mode 100755 index 0000000..6002b71 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_startswith_upy.py.exp @@ -0,0 +1 @@ +TypeError diff --git a/src/openmv/src/micropython/tests/basics/string_strip.py b/src/openmv/src/micropython/tests/basics/string_strip.py new file mode 100755 index 0000000..971a4aa --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_strip.py @@ -0,0 +1,44 @@ +print("".strip()) +print(" \t\n\r\v\f".strip()) +print(" T E S T".strip()) +print("abcabc".strip("ce")) +print("aaa".strip("b")) +print("abc efg ".strip("g a")) + +print(' spacious '.lstrip()) +print('www.example.com'.lstrip('cmowz.')) + +print(' spacious '.rstrip()) +print('mississippi'.rstrip('ipz')) + +print(b'mississippi'.rstrip(b'ipz')) +try: + print(b'mississippi'.rstrip('ipz')) +except TypeError: + print("TypeError") +try: + print('mississippi'.rstrip(b'ipz')) +except TypeError: + print("TypeError") + +# single-char subj string used to give a problem +print("a".strip()) +print("a".lstrip()) +print("a".rstrip()) +print(" a".strip()) +print(" a".lstrip()) +print(" a".rstrip()) +print("a ".strip()) +print("a ".lstrip()) +print("a ".rstrip()) + +# \0 used to give a problem + +print("\0abc\0".strip()) +print("\0abc\0".lstrip()) +print("\0abc\0".rstrip()) +print("\0abc\0".strip("\0")) + +# Test that stripping unstrippable string returns original object +s = "abc" +print(id(s.strip()) == id(s)) diff --git a/src/openmv/src/micropython/tests/basics/string_upperlow.py b/src/openmv/src/micropython/tests/basics/string_upperlow.py new file mode 100755 index 0000000..950ea24 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/string_upperlow.py @@ -0,0 +1,4 @@ +print("".lower()) +print(" t\tn\nr\rv\vf\f".upper()) +print(" T E S T".lower()) +print("*@a1b2cabc_[]/\\".upper()) diff --git a/src/openmv/src/micropython/tests/basics/struct1.py b/src/openmv/src/micropython/tests/basics/struct1.py new file mode 100755 index 0000000..db34342 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/struct1.py @@ -0,0 +1,98 @@ +try: + import ustruct as struct +except: + try: + import struct + except ImportError: + print("SKIP") + raise SystemExit + +print(struct.calcsize("bI")) +print(struct.unpack(">bI", b"\x80\0\0\x01\0")) + +# 32-bit little-endian specific +#print(struct.unpack("bI", b"\x80\xaa\x55\xaa\0\0\x01\0")) + +print(struct.pack("l", 1)) +print(struct.pack("i", 1)) +print(struct.pack("h", 1)) +print(struct.pack("b", 1)) + +print(struct.pack("bI", -128, 256)) + +print(struct.calcsize("100sI")) +print(struct.calcsize("97sI")) +print(struct.unpack("<6sH", b"foo\0\0\0\x12\x34")) +print(struct.pack("<6sH", b"foo", 10000)) + +s = struct.pack("BHBI", 10, 100, 200, 300) +v = struct.unpack("BHBI", s) +print(v == (10, 100, 200, 300)) + +# network byte order +print(struct.pack('!i', 123)) + +# check that we get an error if the buffer is too small +try: + struct.unpack('I', b'\x00\x00\x00') +except: + print('struct.error') + +# first arg must be a string +try: + struct.pack(1, 2) +except TypeError: + print('TypeError') + +# make sure that unknown types are detected +try: + struct.pack("z", 1) +except: + print("Unknown type") + +# Initially repitition counters were supported only for strings, +# but later were implemented for all. +print(struct.unpack("<3B2h", b"foo\x12\x34\xff\xff")) +print(struct.pack("<3B", 1, 2, 3)) + +# pack_into +buf = bytearray(b'>>>123<<<') +struct.pack_into('Q", 1)) +print(struct.pack("Q", 2**64 - 1)) +print(struct.pack("Q", 0xffffffffffffffff)) +print(struct.pack("q", -1)) +print(struct.pack("Q", 1234567890123456789)) +print(struct.pack(">q", -1234567890123456789)) +print(struct.unpack("Q", b"\x12\x34\x56\x78\x90\x12\x34\x56")) +print(struct.unpack("q", b"\xf2\x34\x56\x78\x90\x12\x34\x56")) + +# check maximum unpack +print(struct.unpack("subscr +print(a[-1]) +a[0] = -1 +print(a) +# Test another base type unary op +print(len(a)) + +# Test binary op of base type, with 2nd arg being raw base type +print(a + [20, 30, 40]) +# Test binary op of base type, with 2nd arg being same class as 1st arg +# TODO: Faults +#print(a + a) + +def foo(): + print("hello from foo") + +try: + class myfunc(type(foo)): + pass +except TypeError: + print("TypeError") + +# multiple bases with layout conflict +try: + class A(type, tuple): + None +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/subclass_native2_list.py b/src/openmv/src/micropython/tests/basics/subclass_native2_list.py new file mode 100755 index 0000000..9ad0b77 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native2_list.py @@ -0,0 +1,26 @@ +class Base1: + def __init__(self, *args): + print("Base1.__init__", args) + +class Clist1(Base1, list): + pass + +a = Clist1() +print(len(a)) +# Not compliant - list assignment should happen in list.__init__, which is not called +# because there's Base1.__init__, but we assign in list.__new__ +#a = Clist1([1, 2, 3]) +#print(len(a)) + +print("---") + +class Clist2(list, Base1): + pass + +# Not compliant - should call list.__init__, but we don't have it +#a = Clist2() +#print(len(a)) + +# Not compliant - should call list.__init__, but we don't have it +#a = Clist2([1, 2, 3]) +#print(len(a)) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native2_tuple.py b/src/openmv/src/micropython/tests/basics/subclass_native2_tuple.py new file mode 100755 index 0000000..9eb69e1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native2_tuple.py @@ -0,0 +1,21 @@ +class Base1: + def __init__(self, *args): + print("Base1.__init__", args) + +class Ctuple1(Base1, tuple): + pass + +a = Ctuple1() +print(len(a)) +a = Ctuple1([1, 2, 3]) +print(len(a)) + +print("---") + +class Ctuple2(tuple, Base1): + pass + +a = Ctuple2() +print(len(a)) +a = Ctuple2([1, 2, 3]) +print(len(a)) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native3.py b/src/openmv/src/micropython/tests/basics/subclass_native3.py new file mode 100755 index 0000000..6745b77 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native3.py @@ -0,0 +1,22 @@ +class MyExc(Exception): + pass + +e = MyExc(100, "Some error") +print(e) +print(repr(e)) +print(e.args) + +try: + raise MyExc("Some error", 1) +except MyExc as e: + print("Caught exception:", repr(e)) + +try: + raise MyExc("Some error2", 2) +except Exception as e: + print("Caught exception:", repr(e)) + +try: + raise MyExc("Some error2") +except: + print("Caught user exception") diff --git a/src/openmv/src/micropython/tests/basics/subclass_native4.py b/src/openmv/src/micropython/tests/basics/subclass_native4.py new file mode 100755 index 0000000..b426793 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native4.py @@ -0,0 +1,9 @@ +# Test calling non-special method inherited from native type + +class mylist(list): + pass + +l = mylist([1, 2, 3]) +print(l) +l.append(10) +print(l) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native5.py b/src/openmv/src/micropython/tests/basics/subclass_native5.py new file mode 100755 index 0000000..6127dae --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native5.py @@ -0,0 +1,12 @@ +# Subclass from 2 bases explicitly subclasses from object + +class Base1(object): + pass + +class Base2(object): + pass + +class Sub(Base1, Base2): + pass + +o = Sub() diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_buffer.py b/src/openmv/src/micropython/tests/basics/subclass_native_buffer.py new file mode 100755 index 0000000..43c3819 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_buffer.py @@ -0,0 +1,16 @@ +# test when we subclass a type with the buffer protocol + +class my_bytes(bytes): + pass + +b1 = my_bytes([0, 1]) +b2 = my_bytes([2, 3]) +b3 = bytes([4, 5]) + +# addition will use the buffer protocol on the RHS +print(b1 + b2) +print(b1 + b3) +print(b3 + b1) + +# bytearray construction will use the buffer protocol +print(bytearray(b1)) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_call.py b/src/openmv/src/micropython/tests/basics/subclass_native_call.py new file mode 100755 index 0000000..c645575 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_call.py @@ -0,0 +1,30 @@ +# test calling a subclass of a native class that supports calling + +# For this test we need a native class that can be subclassed (has make_new) +# and is callable (has call). The only one available is machine.Signal, which +# in turns needs PinBase. +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase + machine.Signal +except AttributeError: + print("SKIP") + raise SystemExit + +class Pin(machine.PinBase): + #def __init__(self): + # self.v = 0 + + def value(self, v=None): + return 42 + +class MySignal(machine.Signal): + pass + +s = MySignal(Pin()) + +# apply call to the subclass, which should call the native base +print(s()) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_call.py.exp b/src/openmv/src/micropython/tests/basics/subclass_native_call.py.exp new file mode 100755 index 0000000..d81cc07 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_call.py.exp @@ -0,0 +1 @@ +42 diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_cmp.py b/src/openmv/src/micropython/tests/basics/subclass_native_cmp.py new file mode 100755 index 0000000..1a095bf --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_cmp.py @@ -0,0 +1,9 @@ +# Test calling non-special method inherited from native type + +class mytuple(tuple): + pass + +t = mytuple((1, 2, 3)) +print(t) +print(t == (1, 2, 3)) +print((1, 2, 3) == t) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_containment.py b/src/openmv/src/micropython/tests/basics/subclass_native_containment.py new file mode 100755 index 0000000..7400f75 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_containment.py @@ -0,0 +1,22 @@ +# test containment operator on subclass of a native type + +class mylist(list): + pass + +class mydict(dict): + pass + +class mybytes(bytes): + pass + +l = mylist([1, 2, 3]) +print(0 in l) +print(1 in l) + +d = mydict({1:1, 2:2}) +print(0 in l) +print(1 in l) + +b = mybytes(b'1234') +print(0 in b) +print(b'1' in b) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_init.py b/src/openmv/src/micropython/tests/basics/subclass_native_init.py new file mode 100755 index 0000000..38d2f23 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_init.py @@ -0,0 +1,44 @@ +# test subclassing a native type and overriding __init__ + +# overriding list.__init__() +class L(list): + def __init__(self, a, b): + super().__init__([a, b]) +print(L(2, 3)) + +# inherits implicitly from object +class A: + def __init__(self): + print("A.__init__") + super().__init__() +A() + +# inherits explicitly from object +class B(object): + def __init__(self): + print("B.__init__") + super().__init__() +B() + +# multiple inheritance with object explicitly mentioned +class C: + pass +class D(C, object): + def __init__(self): + print('D.__init__') + super().__init__() + def reinit(self): + print('D.foo') + super().__init__() +a = D() +a.__init__() +a.reinit() + +# call __init__() after object is already init'd +class L(list): + def reinit(self): + super().__init__(range(2)) +a = L(range(5)) +print(a) +a.reinit() +print(a) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_iter.py b/src/openmv/src/micropython/tests/basics/subclass_native_iter.py new file mode 100755 index 0000000..0f6b369 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_iter.py @@ -0,0 +1,7 @@ +# test subclassing a native type which can be iterated over + +class mymap(map): + pass + +m = mymap(lambda x: x + 10, range(4)) +print(list(m)) diff --git a/src/openmv/src/micropython/tests/basics/subclass_native_specmeth.py b/src/openmv/src/micropython/tests/basics/subclass_native_specmeth.py new file mode 100755 index 0000000..91ffc96 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/subclass_native_specmeth.py @@ -0,0 +1,18 @@ +# Test calling non-special method inherited from native type + +class mylist(list): + pass + +l = mylist([1, 2, 3]) +print(l) +print([e for e in l]) + + +class mylist2(list): + + def __iter__(self): + return iter([10, 20, 30]) + +l = mylist2([1, 2, 3]) +print(l) +print([e for e in l]) diff --git a/src/openmv/src/micropython/tests/basics/syntaxerror.py b/src/openmv/src/micropython/tests/basics/syntaxerror.py new file mode 100755 index 0000000..8e706c6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/syntaxerror.py @@ -0,0 +1,133 @@ +# test syntax errors + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + +def test_syntax(code): + try: + exec(code) + print("no SyntaxError") + except IndentationError: + print("IndentationError") + except SyntaxError: + print("SyntaxError") + +# non-newline after line-continuation character (lexer error) +test_syntax("a \\a\n") + +# dedent mismatch (lexer error) +test_syntax("def f():\n a\n a\n") + +# unclosed string (lexer error) +test_syntax("'abc") + +# invalid (lexer error) +test_syntax("!") +test_syntax("$") +test_syntax("`") + +# bad indentation (lexer error) +test_syntax(" a\n") + +# malformed integer literal (parser error) +test_syntax("123z") + +# input doesn't match the grammar (parser error) +test_syntax('1 or 2 or') +test_syntax('{1:') + +# can't assign to literals +test_syntax("1 = 2") +test_syntax("'' = 1") +test_syntax("{} = 1") + +# can't assign to comprehension +test_syntax("(i for i in a) = 1") + +# can't assign to function +test_syntax("f() = 1") + +# can't assign to power +test_syntax("f**2 = 1") + +# can't assign to power of composite +test_syntax("f[0]**2 = 1") + +# can't have *x on RHS +test_syntax("x = *x") + +# can't have multiple *x on LHS +test_syntax("*a, *b = c") + +# can't do augmented assignment to tuple +test_syntax("a, b += c") +test_syntax("(a, b) += c") + +# can't do augmented assignment to list +test_syntax("[a, b] += c") + +# non-default argument can't follow default argument +test_syntax("def f(a=1, b): pass") + +# can't delete these things +test_syntax("del f()") +test_syntax("del f[0]**2") +test_syntax("del (a for a in a)") + +# must be in a "loop" +test_syntax("break") +test_syntax("continue") + +# must be in a function +test_syntax("return") +test_syntax("yield") +test_syntax("nonlocal a") +test_syntax("await 1") + +# error on uPy, warning on CPy +#test_syntax("def f():\n a = 1\n global a") + +# default except must be last +test_syntax("try:\n a\nexcept:\n pass\nexcept:\n pass") + +# LHS of keywords must be id's +test_syntax("f(1=2)") + +# non-keyword after keyword +test_syntax("f(a=1, 2)") + +# doesn't error on uPy but should +#test_syntax("f(1, i for i in i)") + +# all elements of dict/set must be pairs or singles +test_syntax("{1:2, 3}") +test_syntax("{1, 2:3}") + +# can't mix non-bytes with bytes when concatenating +test_syntax("'abc' b'def'") + +# can't reuse same name for argument +test_syntax("def f(a, a): pass") + +# nonlocal must exist in outer function/class scope +test_syntax("def f():\n def g():\n nonlocal a") + +# param can't be redefined as global +test_syntax('def f(x):\n global x') + +# param can't be redefined as nonlocal +test_syntax('def f(x):\n nonlocal x') + +# can define variable to be both nonlocal and global +test_syntax('def f():\n nonlocal x\n global x') + +# can't have multiple *'s +test_syntax('def f(x, *a, *):\n pass') +test_syntax('lambda x, *a, *: 1') + +# **kw must be last +test_syntax('def f(x, *a, **kw, r):\n pass') +test_syntax('lambda x, *a, **kw, r: 1') diff --git a/src/openmv/src/micropython/tests/basics/sys1.py b/src/openmv/src/micropython/tests/basics/sys1.py new file mode 100755 index 0000000..0d74a12 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/sys1.py @@ -0,0 +1,30 @@ +# test sys module + +import sys + +print(sys.__name__) +print(type(sys.path)) +print(type(sys.argv)) +print(sys.byteorder in ('little', 'big')) + +try: + print(sys.maxsize > 100) +except AttributeError: + # Effectively skip subtests + print(True) + +try: + print(sys.implementation.name in ('cpython', 'micropython')) +except AttributeError: + # Effectively skip subtests + print(True) + +try: + raise SystemExit +except SystemExit as e: + print("SystemExit", e.args) + +try: + sys.exit(42) +except SystemExit as e: + print("SystemExit", e.args) diff --git a/src/openmv/src/micropython/tests/basics/sys_getsizeof.py b/src/openmv/src/micropython/tests/basics/sys_getsizeof.py new file mode 100755 index 0000000..fe1b403 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/sys_getsizeof.py @@ -0,0 +1,22 @@ +# test sys.getsizeof() function + +import sys +try: + sys.getsizeof +except AttributeError: + print('SKIP') + raise SystemExit + +print(sys.getsizeof([1, 2]) >= 2) +print(sys.getsizeof({1: 2}) >= 2) + +class A: + pass +print(sys.getsizeof(A()) > 0) + +# Only test deque if we have it +try: + from ucollections import deque + assert sys.getsizeof(deque((), 1)) > 0 +except ImportError: + pass diff --git a/src/openmv/src/micropython/tests/basics/true_value.py b/src/openmv/src/micropython/tests/basics/true_value.py new file mode 100755 index 0000000..9ec209f --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/true_value.py @@ -0,0 +1,30 @@ +# Test true-ish value handling + +if not False: + print("False") + +if not None: + print("None") + +if not 0: + print("0") + +if not "": + print("Empty string") +if "foo": + print("Non-empty string") + +if not (): + print("Empty tuple") +if ("",): + print("Non-empty tuple") + +if not []: + print("Empty list") +if [0]: + print("Non-empty list") + +if not {}: + print("Empty dict") +if {0:0}: + print("Non-empty dict") diff --git a/src/openmv/src/micropython/tests/basics/try1.py b/src/openmv/src/micropython/tests/basics/try1.py new file mode 100755 index 0000000..56d3075 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try1.py @@ -0,0 +1,11 @@ +# basic exceptions +x = 1 +try: + x.a() +except: + print(x) + +try: + raise IndexError +except IndexError: + print("caught") diff --git a/src/openmv/src/micropython/tests/basics/try2.py b/src/openmv/src/micropython/tests/basics/try2.py new file mode 100755 index 0000000..11e60b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try2.py @@ -0,0 +1,49 @@ +# nested try's + +try: + print("try 1") + try: + print("try 2") + foo() + except: + print("except 2") + bar() +except: + print("except 1") + +try: + print("try 1") + try: + print("try 2") + foo() + except TypeError: + print("except 2") + bar() +except NameError: + print("except 1") + +# raised exception not contained in except tuple +try: + try: + raise Exception + except (RuntimeError, SyntaxError): + print('except 2') +except Exception: + print('except 1') + +# Check that exceptions across function boundaries work as expected +def func1(): + try: + print("try func1") + func2() + except NameError: + print("except func1") + +def func2(): + try: + print("try func2") + foo() + except TypeError: + print("except func2") + +func1() diff --git a/src/openmv/src/micropython/tests/basics/try3.py b/src/openmv/src/micropython/tests/basics/try3.py new file mode 100755 index 0000000..31bacd3 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try3.py @@ -0,0 +1,17 @@ +# nested exceptions + +def f(): + try: + foo() + except: + print("except 1") + try: + baz() + except: + print("except 2") + bar() + +try: + f() +except: + print("f except") diff --git a/src/openmv/src/micropython/tests/basics/try4.py b/src/openmv/src/micropython/tests/basics/try4.py new file mode 100755 index 0000000..4d324c1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try4.py @@ -0,0 +1,21 @@ +# triple nested exceptions + +def f(): + try: + foo() + except: + print("except 1") + try: + bar() + except: + print("except 2") + try: + baz() + except: + print("except 3") + bak() + +try: + f() +except: + print("f except") diff --git a/src/openmv/src/micropython/tests/basics/try_as_var.py b/src/openmv/src/micropython/tests/basics/try_as_var.py new file mode 100755 index 0000000..4f02f9c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_as_var.py @@ -0,0 +1,10 @@ +try: + raise ValueError(534) +except ValueError as e: + print(type(e), e.args) + +# Var bound in except block is automatically deleted +try: + e +except NameError: + print("NameError") diff --git a/src/openmv/src/micropython/tests/basics/try_continue.py b/src/openmv/src/micropython/tests/basics/try_continue.py new file mode 100755 index 0000000..4a199b8 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_continue.py @@ -0,0 +1,13 @@ +# test continue within exception handler + +def f(): + lst = [1, 2, 3] + for x in lst: + print('a', x) + try: + if x == 2: + raise Exception + except Exception: + continue + print('b', x) +f() diff --git a/src/openmv/src/micropython/tests/basics/try_error.py b/src/openmv/src/micropython/tests/basics/try_error.py new file mode 100755 index 0000000..ca2a6f2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_error.py @@ -0,0 +1,17 @@ +# test bad exception match + +try: + try: + a + except 1: + pass +except TypeError: + print("TypeError") + +try: + try: + a + except (1,): + pass +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/try_finally1.py b/src/openmv/src/micropython/tests/basics/try_finally1.py new file mode 100755 index 0000000..67ebe0b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally1.py @@ -0,0 +1,96 @@ +print("noexc-finally") +try: + print("try") +finally: + print("finally") + +print("noexc-finally-finally") +try: + print("try1") + try: + print("try2") + finally: + print("finally2") +finally: + print("finally1") +print() + +print("noexc-finally-func-finally") +def func2(): + try: + print("try2") + finally: + print("finally2") + +try: + print("try1") + func2() +finally: + print("finally1") +print() + + +print("exc-finally-except") +try: + print("try1") + try: + print("try2") + foo() + except: + print("except2") +finally: + print("finally1") +print() + +print("exc-finally-except-filter") +try: + print("try1") + try: + print("try2") + foo() + except NameError: + print("except2") +finally: + print("finally1") +print() + + +print("exc-except-finally-finally") +try: # top-level catch-all except to not fail script + try: + print("try1") + try: + print("try2") + foo() + finally: + print("finally2") + finally: + print("finally1") +except: + print("catch-all except") +print() + +# case where a try-except within a finally cancels the exception +print("exc-finally-subexcept") +try: + print("try1") +finally: + try: + print("try2") + foo + except: + print("except2") + print("finally1") +print() + +# case where exception is raised after a finally has finished (tests that the finally doesn't run again) +def func(): + try: + print("try") + finally: + print("finally") + foo +try: + func() +except: + print("except") diff --git a/src/openmv/src/micropython/tests/basics/try_finally2.py b/src/openmv/src/micropython/tests/basics/try_finally2.py new file mode 100755 index 0000000..3c4171d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally2.py @@ -0,0 +1,30 @@ +# check that the Python stack does not overflow when the finally +# block itself uses more stack than the rest of the function +def f1(a, b): + pass +def test1(): + val = 1 + try: + raise ValueError() + finally: + f1(2, 2) # use some stack + print(val) # check that the local variable is the same +try: + test1() +except ValueError: + pass + +# same as above but with 3 args instead of 2, to use an extra stack entry +def f2(a, b, c): + pass +def test2(): + val = 1 + try: + raise ValueError() + finally: + f2(2, 2, 2) # use some stack + print(val) # check that the local variable is the same +try: + test2() +except ValueError: + pass diff --git a/src/openmv/src/micropython/tests/basics/try_finally_loops.py b/src/openmv/src/micropython/tests/basics/try_finally_loops.py new file mode 100755 index 0000000..a4b8019 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally_loops.py @@ -0,0 +1,68 @@ +# Test various loop types, some may be implemented/optimized differently +while True: + try: + break + finally: + print('finally 1') + + +for i in [1, 5, 10]: + try: + continue + finally: + print('finally 2') + +for i in range(3): + try: + continue + finally: + print('finally 3') + +# Multi-level +for i in range(4): + print(i) + try: + while True: + try: + try: + break + finally: + print('finally 1') + finally: + print('finally 2') + print('here') + finally: + print('finnaly 3') + +# break from within try-finally, within for-loop +for i in [1]: + try: + print(i) + break + finally: + print('finally 4') + +# Test unwind-jump where there is nothing in the body of the try or finally. +# This checks that the bytecode emitter allocates enough stack for the unwind. +for i in [1]: + try: + break + finally: + pass + +# The following test checks that the globals dict is valid after a call to a +# function that has an unwind jump. +# There was a bug where an unwind jump would trash the globals dict upon return +# from a function, because it used the Python-stack incorrectly. +def f(): + for i in [1]: + try: + break + finally: + pass +def g(): + global global_var + f() + print(global_var) +global_var = 'global' +g() diff --git a/src/openmv/src/micropython/tests/basics/try_finally_return.py b/src/openmv/src/micropython/tests/basics/try_finally_return.py new file mode 100755 index 0000000..31a507e --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally_return.py @@ -0,0 +1,72 @@ +def func1(): + try: + return "it worked" + finally: + print("finally 1") + +print(func1()) + + +def func2(): + try: + return "it worked" + finally: + print("finally 2") + +def func3(): + try: + s = func2() + return s + ", did this work?" + finally: + print("finally 3") + +print(func3()) + +# for loop within try-finally +def f(): + try: + for i in [1, 2]: + return i + finally: + print('finally') +print(f()) + +# multiple for loops within try-finally +def f(): + try: + for i in [1, 2]: + for j in [3, 4]: + return (i, j) + finally: + print('finally') +print(f()) + +# multiple for loops and nested try-finally's +def f(): + try: + for i in [1, 2]: + for j in [3, 4]: + try: + for k in [5, 6]: + for l in [7, 8]: + return (i, j, k, l) + finally: + print('finally 2') + finally: + print('finally 1') +print(f()) + +# multiple for loops that are optimised, and nested try-finally's +def f(): + try: + for i in range(1, 3): + for j in range(3, 5): + try: + for k in range(5, 7): + for l in range(7, 9): + return (i, j, k, l) + finally: + print('finally 2') + finally: + print('finally 1') +print(f()) diff --git a/src/openmv/src/micropython/tests/basics/try_finally_return2.py b/src/openmv/src/micropython/tests/basics/try_finally_return2.py new file mode 100755 index 0000000..e3ea5f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally_return2.py @@ -0,0 +1,104 @@ +# test 'return' within the finally block +# it should swallow the exception + +# simple case +def f(): + try: + raise ValueError() + finally: + print('finally') + return 0 + print('got here') +print(f()) + +# nested, return in outer +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + print('got here') + finally: + print('finally 2') + return 2 + print('got here') +print(f()) + +# nested, return in inner +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + return 1 + print('got here') + finally: + print('finally 2') + print('got here') +print(f()) + +# nested, return in inner and outer +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + return 1 + print('got here') + finally: + print('finally 2') + return 2 + print('got here') +print(f()) + +# nested with reraise +def f(): + try: + try: + raise ValueError + except: + raise + print('got here') + finally: + print('finally') + return 0 + print('got here') +print(f()) + +# triple nesting with reraise +def f(): + try: + try: + try: + raise ValueError + except: + raise + except: + raise + finally: + print('finally') + return 0 +print(f()) + +# exception when matching exception +def f(): + try: + raise ValueError + except NonExistingError: + pass + finally: + print('finally') + return 0 +print(f()) + +# raising exception class, not instance +def f(): + try: + raise ValueError + finally: + print('finally') + return 0 +print(f()) diff --git a/src/openmv/src/micropython/tests/basics/try_finally_return3.py b/src/openmv/src/micropython/tests/basics/try_finally_return3.py new file mode 100755 index 0000000..a2a06ee --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally_return3.py @@ -0,0 +1,103 @@ +# test 'return' within the finally block, with nested finally's +# only inactive finally's should be executed, and only once + +# basic nested finally's, the print should only be executed once +def f(): + try: + raise TypeError + finally: + print(1) + try: + raise ValueError + finally: + return 42 +print(f()) + +# similar to above but more nesting +def f(): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + pass + finally: + return 42 +print(f()) + +# similar to above but even more nesting +def f(): + try: + raise ValueError + finally: + print(1) + try: + raise TypeError + finally: + print(2) + try: + raise Exception + finally: + print(3) + return 42 +print(f()) + +# upon return some try's are active, some finally's are active, some inactive +def f(): + try: + try: + pass + finally: + print(2) + return 42 + finally: + print(1) +print(f()) + +# same as above but raise instead of pass +def f(): + try: + try: + raise ValueError + finally: + print(2) + return 42 + finally: + print(1) +print(f()) + +# upon return exception stack holds: active finally, inactive finally, active finally +def f(): + try: + raise Exception + finally: + print(1) + try: + try: + pass + finally: + print(3) + return 42 + finally: + print(2) +print(f()) + +# same as above but raise instead of pass in innermost try block +def f(): + try: + raise Exception + finally: + print(1) + try: + try: + raise Exception + finally: + print(3) + return 42 + finally: + print(2) +print(f()) diff --git a/src/openmv/src/micropython/tests/basics/try_finally_return4.py b/src/openmv/src/micropython/tests/basics/try_finally_return4.py new file mode 100755 index 0000000..8b54fe9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_finally_return4.py @@ -0,0 +1,83 @@ +# test try-finally with return, where unwinding return has to go through +# another try-finally which may affect the behaviour of the return + +# case where a simple try-finally executes during an unwinding return +def f(x): + try: + try: + if x: + return 42 + finally: + try: + print(1) + finally: + print(2) + print(3) + print(4) + finally: + print(5) +print(f(0)) +print(f(1)) + +# case where an unwinding return is replaced by another one +def f(x): + try: + try: + if x: + return 42 + finally: + try: + print(1) + return 43 + finally: + print(2) + print(3) + print(4) + finally: + print(5) +print(f(0)) +print(f(1)) + +# case where an unwinding return is cancelled by an exception +def f(x): + try: + try: + if x: + return 42 + finally: + try: + print(1) + raise ValueError # cancels any active return + finally: + print(2) + print(3) + print(4) + finally: + print(5) +try: + print(f(0)) +except: + print('caught') +try: + print(f(1)) +except: + print('caught') + +# case where an unwinding return is cancelled then resumed +def f(x): + try: + try: + if x: + return 42 + finally: + try: + print(1) + raise Exception # cancels any active return + except: # cancels the exception and resumes any active return + print(2) + print(3) + print(4) + finally: + print(5) +print(f(0)) +print(f(1)) diff --git a/src/openmv/src/micropython/tests/basics/try_reraise.py b/src/openmv/src/micropython/tests/basics/try_reraise.py new file mode 100755 index 0000000..bf5e77c --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_reraise.py @@ -0,0 +1,19 @@ +# Reraising last exception with raise w/o args + +def f(): + try: + raise ValueError("val", 3) + except: + raise + +try: + f() +except ValueError as e: + print(repr(e)) + + +# Can reraise only in except block +try: + raise +except RuntimeError: + print("RuntimeError") diff --git a/src/openmv/src/micropython/tests/basics/try_reraise2.py b/src/openmv/src/micropython/tests/basics/try_reraise2.py new file mode 100755 index 0000000..5648d24 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_reraise2.py @@ -0,0 +1,32 @@ +# Reraise not the latest occurred exception +def f(): + try: + raise ValueError("val", 3) + except: + try: + print(1) + raise TypeError + except: + print(2) + try: + print(3) + try: + print(4) + raise AttributeError + except: + print(5) + pass + print(6) + raise + except TypeError: + print(7) + pass + print(8) + print(9) + # This should raise original ValueError, not the most recently occurred AttributeError + raise + +try: + f() +except ValueError as e: + print(repr(e)) diff --git a/src/openmv/src/micropython/tests/basics/try_return.py b/src/openmv/src/micropython/tests/basics/try_return.py new file mode 100755 index 0000000..492c18d --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/try_return.py @@ -0,0 +1,11 @@ +# test use of return with try-except + +def f(l, i): + try: + return l[i] + except IndexError: + print('IndexError') + return -1 + +print(f([1], 0)) +print(f([], 0)) diff --git a/src/openmv/src/micropython/tests/basics/tuple1.py b/src/openmv/src/micropython/tests/basics/tuple1.py new file mode 100755 index 0000000..a7956c1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/tuple1.py @@ -0,0 +1,37 @@ +# basic tuple functionality +x = (1, 2, 3 * 4) +print(x) +try: + x[0] = 4 +except TypeError: + print("TypeError") +print(x) +try: + x.append(5) +except AttributeError: + print("AttributeError") + +print(x[1:]) +print(x[:-1]) +print(x[2:3]) + +print(x + (10, 100, 10000)) + +# inplace add operator +x += (10, 11, 12) +print(x) + +# construction of tuple from large iterator (tests implementation detail of uPy) +print(tuple(range(20))) + +# unsupported unary operation +try: + +() +except TypeError: + print('TypeError') + +# unsupported type on RHS of add +try: + () + None +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/tuple_compare.py b/src/openmv/src/micropython/tests/basics/tuple_compare.py new file mode 100755 index 0000000..9558eb1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/tuple_compare.py @@ -0,0 +1,65 @@ +print(() == ()) +print(() > ()) +print(() < ()) +print(() == (1,)) +print((1,) == ()) +print(() > (1,)) +print((1,) > ()) +print(() < (1,)) +print((1,) < ()) +print(() >= (1,)) +print((1,) >= ()) +print(() <= (1,)) +print((1,) <= ()) + +print((1,) == (1,)) +print((1,) != (1,)) +print((1,) == (2,)) +print((1,) == (1, 0,)) + +print((1,) > (1,)) +print((1,) > (2,)) +print((2,) > (1,)) +print((1, 0,) > (1,)) +print((1, -1,) > (1,)) +print((1,) > (1, 0,)) +print((1,) > (1, -1,)) + +print((1,) < (1,)) +print((2,) < (1,)) +print((1,) < (2,)) +print((1,) < (1, 0,)) +print((1,) < (1, -1,)) +print((1, 0,) < (1,)) +print((1, -1,) < (1,)) + +print((1,) >= (1,)) +print((1,) >= (2,)) +print((2,) >= (1,)) +print((1, 0,) >= (1,)) +print((1, -1,) >= (1,)) +print((1,) >= (1, 0,)) +print((1,) >= (1, -1,)) + +print((1,) <= (1,)) +print((2,) <= (1,)) +print((1,) <= (2,)) +print((1,) <= (1, 0,)) +print((1,) <= (1, -1,)) +print((1, 0,) <= (1,)) +print((1, -1,) <= (1,)) + +print((10, 0) > (1, 1)) +print((10, 0) < (1, 1)) +print((0, 0, 10, 0) > (0, 0, 1, 1)) +print((0, 0, 10, 0) < (0, 0, 1, 1)) + + +print(() == {}) +print(() != {}) +print((1,) == [1]) + +try: + print(() < {}) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/basics/tuple_count.py b/src/openmv/src/micropython/tests/basics/tuple_count.py new file mode 100755 index 0000000..7f42ede --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/tuple_count.py @@ -0,0 +1,5 @@ +a = (1, 2, 3) +a = a + a + a +b = (0, 0, a, 0, a, 0) +print(a.count(2)) +print(b.count(a)) diff --git a/src/openmv/src/micropython/tests/basics/tuple_index.py b/src/openmv/src/micropython/tests/basics/tuple_index.py new file mode 100755 index 0000000..1aef100 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/tuple_index.py @@ -0,0 +1,24 @@ +a = (1, 2, 3) +print(a.index(1)) +print(a.index(2)) +print(a.index(3)) +print(a.index(3, 2)) +try: + print(a.index(3, 2, 2)) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") + +a = a + a +b = (0, 0, a) +print(a.index(2)) +print(b.index(a)) +print(a.index(2, 2)) + +try: + a.index(2, 2, 2) +except ValueError: + print("Raised ValueError") +else: + print("Did not raise ValueError") diff --git a/src/openmv/src/micropython/tests/basics/tuple_mult.py b/src/openmv/src/micropython/tests/basics/tuple_mult.py new file mode 100755 index 0000000..cac9518 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/tuple_mult.py @@ -0,0 +1,23 @@ +# basic multiplication +print((0,) * 5) + +# check negative, 0, positive; lhs and rhs multiplication +for i in (-4, -2, 0, 2, 4): + print(i * (1, 2)) + print((1, 2) * i) + +# check that we don't modify existing tuple +a = (1, 2, 3) +c = a * 3 +print(a, c) + +# inplace multiplication +a = (1, 2) +a *= 2 +print(a) + +# unsupported type on RHS +try: + () * None +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/basics/types1.py b/src/openmv/src/micropython/tests/basics/types1.py new file mode 100755 index 0000000..e098abe --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/types1.py @@ -0,0 +1,25 @@ +# basic types +# similar test for set type is done in set_type.py + +print(bool) +print(int) +print(tuple) +print(list) +print(dict) + +print(type(bool()) == bool) +print(type(int()) == int) +print(type(tuple()) == tuple) +print(type(list()) == list) +print(type(dict()) == dict) + +print(type(False) == bool) +print(type(0) == int) +print(type(()) == tuple) +print(type([]) == list) +print(type({}) == dict) + +try: + bool.foo +except AttributeError: + print("AttributeError") diff --git a/src/openmv/src/micropython/tests/basics/types2.py b/src/openmv/src/micropython/tests/basics/types2.py new file mode 100755 index 0000000..ba7be6b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/types2.py @@ -0,0 +1,14 @@ +# Types are hashable +print(hash(type) != 0) +print(hash(int) != 0) +print(hash(list) != 0) +class Foo: pass +print(hash(Foo) != 0) + +print(int == int) +print(int != list) + +d = {} +d[int] = list +d[list] = int +print(len(d)) diff --git a/src/openmv/src/micropython/tests/basics/unary_op.py b/src/openmv/src/micropython/tests/basics/unary_op.py new file mode 100755 index 0000000..bd78a20 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/unary_op.py @@ -0,0 +1,27 @@ +x = 1 +print(+x) +print(-x) +print(~x) + +print(not None) +print(not False) +print(not True) +print(not 0) +print(not 1) +print(not -1) +print(not ()) +print(not (1,)) +print(not []) +print(not [1,]) +print(not {}) +print(not {1:1}) + +# check user instance +class A: pass +print(not A()) + +# check user instances derived from builtins +class B(int): pass +print(not B()) +class C(list): pass +print(not C()) diff --git a/src/openmv/src/micropython/tests/basics/unboundlocal.py b/src/openmv/src/micropython/tests/basics/unboundlocal.py new file mode 100755 index 0000000..5573da1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/unboundlocal.py @@ -0,0 +1,19 @@ +# locals referenced before assignment + +def f1(): + print(x) + x = 1 + +def f2(): + for i in range(0): + print(i) + print(i) + +def check(f): + try: + f() + except NameError: + print("NameError") + +check(f1) +check(f2) diff --git a/src/openmv/src/micropython/tests/basics/unpack1.py b/src/openmv/src/micropython/tests/basics/unpack1.py new file mode 100755 index 0000000..1e8b53a --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/unpack1.py @@ -0,0 +1,79 @@ +# unpack sequences + +a, = 1, ; print(a) +a, b = 2, 3 ; print(a, b) +a, b, c = 1, 2, 3; print(a, b, c) + +a, = range(1); print(a) +a, b = range(2); print(a, b) +a, b, c = range(3); print(a, b, c) + +(a) = range(1); print(a) +(a,) = range(1); print(a) +(a, b) = range(2); print(a, b) +(a, b, c) = range(3); print(a, b, c) +(a, (b, c)) = [-1, range(2)]; print(a, b, c) + +# lists + +[] = [] +[a] = range(1); print(a) +[a, b] = range(2); print(a, b) +[a, b, c] = range(3); print(a, b, c) + +# with star + +*a, = () ; print(a) +*a, = 4, ; print(a) +*a, = 5, 6 ; print(a) + +*a, b = 7, ; print(a, b) +*a, b = 8, 9 ; print(a, b) +*a, b = 10, 11, 12 ; print(a, b) + +a, *b = 13, ; print(a, b) +a, *b = 14, 15 ; print(a, b) +a, *b = 16, 17, 18 ; print(a, b) + +a, *b, c = 19, 20 ; print(a, b) +a, *b, c = 21, 22, 23 ; print(a, b) +a, *b, c = 24, 25, 26, 27 ; print(a, b) + +a = [28, 29] +*b, = a +print(a, b, a == b, a is b) + +[*a] = [1, 2, 3] +print(a) + +try: + a, *b, c = (30,) +except ValueError: + print("ValueError") + +# with star and generic iterator + +*a, = range(5) ; print(a) +*a, b = range(5) ; print(a, b) +*a, b, c = range(5) ; print(a, b, c) +a, *b = range(5) ; print(a, b) +a, *b, c = range(5) ; print(a, b, c) +a, *b, c, d = range(5) ; print(a, b, c, d) +a, b, *c = range(5) ; print(a, b, c) +a, b, *c, d = range(5) ; print(a, b, c, d) +a, b, *c, d, e = range(5) ; print(a, b, c, d, e) + +*a, = [x * 2 for x in [1, 2, 3, 4]] ; print(a) +*a, b = [x * 2 for x in [1, 2, 3, 4]] ; print(a, b) +a, *b = [x * 2 for x in [1, 2, 3, 4]] ; print(a, b) +a, *b, c = [x * 2 for x in [1, 2, 3, 4]]; print(a, b, c) + +try: + a, *b, c = range(0) +except ValueError: + print("ValueError") + +try: + a, *b, c = range(1) +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/basics/while1.py b/src/openmv/src/micropython/tests/basics/while1.py new file mode 100755 index 0000000..a9bb5d2 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/while1.py @@ -0,0 +1,12 @@ +# basic while loop + +x = 0 +while x < 2: + y = 0 + while y < 2: + z = 0 + while z < 2: + z = z + 1 + print(x, y, z) + y = y + 1 + x = x + 1 diff --git a/src/openmv/src/micropython/tests/basics/while_cond.py b/src/openmv/src/micropython/tests/basics/while_cond.py new file mode 100755 index 0000000..eccc7a6 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/while_cond.py @@ -0,0 +1,36 @@ +# test while conditions which are optimised by the compiler + +while 0: + print(0) +else: + print(1) + +while 1: + print(2) + break + +while 2: + print(3) + break + +while -1: + print(4) + break + +while False: + print('a') +else: + print('b') + +while True: + print('a') + break + +while not False: + print('a') + break + +while not True: + print('a') +else: + print('b') diff --git a/src/openmv/src/micropython/tests/basics/while_nest_exc.py b/src/openmv/src/micropython/tests/basics/while_nest_exc.py new file mode 100755 index 0000000..35a23a9 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/while_nest_exc.py @@ -0,0 +1,13 @@ +# test nested whiles within a try-except + +while 1: + print(1) + try: + print(2) + while 1: + print(3) + break + except: + print(4) + print(5) + break diff --git a/src/openmv/src/micropython/tests/basics/with1.py b/src/openmv/src/micropython/tests/basics/with1.py new file mode 100755 index 0000000..57a8070 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/with1.py @@ -0,0 +1,71 @@ +class CtxMgr: + + def __enter__(self): + print("__enter__") + return self + + def __exit__(self, a, b, c): + print("__exit__", repr(a), repr(b)) + + +with CtxMgr() as a: + print(isinstance(a, CtxMgr)) + +try: + with CtxMgr() as a: + raise ValueError +except ValueError: + print("ValueError") + + +class CtxMgr2: + + def __enter__(self): + print("__enter__") + return self + + def __exit__(self, a, b, c): + print("__exit__", repr(a), repr(b)) + return True + +try: + with CtxMgr2() as a: + raise ValueError + print("No ValueError2") +except ValueError: + print("ValueError2") + + +# These recursive try-finally tests are attempt to get some interpretation +# of last phrase in http://docs.python.org/3.4/library/dis.html#opcode-WITH_CLEANUP +# "If the stack represents an exception, and the function call returns a 'true' +# value, this information is "zapped" and replaced with a single WHY_SILENCED +# to prevent END_FINALLY from re-raising the exception. (But non-local gotos +# will still be resumed.)" +print("===") +with CtxMgr2() as a: + try: + try: + raise ValueError + print("No ValueError3") + finally: + print("finally1") + finally: + print("finally2") + +print("===") +try: + try: + with CtxMgr2() as a: + try: + try: + raise ValueError + print("No ValueError3") + finally: + print("finally1") + finally: + print("finally2") + finally: + print("finally3") +finally: + print("finally4") diff --git a/src/openmv/src/micropython/tests/basics/with_break.py b/src/openmv/src/micropython/tests/basics/with_break.py new file mode 100755 index 0000000..f1063d5 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/with_break.py @@ -0,0 +1,14 @@ +class CtxMgr: + + def __enter__(self): + print("__enter__") + return self + + def __exit__(self, a, b, c): + print("__exit__", repr(a), repr(b)) + +for i in range(5): + print(i) + with CtxMgr(): + if i == 3: + break diff --git a/src/openmv/src/micropython/tests/basics/with_continue.py b/src/openmv/src/micropython/tests/basics/with_continue.py new file mode 100755 index 0000000..fc2b24b --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/with_continue.py @@ -0,0 +1,14 @@ +class CtxMgr: + + def __enter__(self): + print("__enter__") + return self + + def __exit__(self, a, b, c): + print("__exit__", repr(a), repr(b)) + +for i in range(5): + print(i) + with CtxMgr(): + if i == 3: + continue diff --git a/src/openmv/src/micropython/tests/basics/with_raise.py b/src/openmv/src/micropython/tests/basics/with_raise.py new file mode 100755 index 0000000..67eab09 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/with_raise.py @@ -0,0 +1,44 @@ +# test with when context manager raises in __enter__/__exit__ + +class CtxMgr: + def __init__(self, id): + self.id = id + + def __enter__(self): + print("__enter__", self.id) + if 10 <= self.id < 20: + raise Exception('enter', self.id) + return self + + def __exit__(self, a, b, c): + print("__exit__", self.id, repr(a), repr(b)) + if 15 <= self.id < 25: + raise Exception('exit', self.id) + +# no raising +try: + with CtxMgr(1): + pass +except Exception as e: + print(e) + +# raise in enter +try: + with CtxMgr(10): + pass +except Exception as e: + print(e) + +# raise in enter and exit +try: + with CtxMgr(15): + pass +except Exception as e: + print(e) + +# raise in exit +try: + with CtxMgr(20): + pass +except Exception as e: + print(e) diff --git a/src/openmv/src/micropython/tests/basics/with_return.py b/src/openmv/src/micropython/tests/basics/with_return.py new file mode 100755 index 0000000..fd848f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/basics/with_return.py @@ -0,0 +1,53 @@ +class CtxMgr: + def __init__(self, id): + self.id = id + + def __enter__(self): + print("__enter__", self.id) + return self + + def __exit__(self, a, b, c): + print("__exit__", self.id, repr(a), repr(b)) + +# simple case +def foo(): + with CtxMgr(1): + return 4 +print(foo()) + +# for loop within with (iterator needs removing upon return) +def f(): + with CtxMgr(1): + for i in [1, 2]: + return i +print(f()) + +# multiple for loops within with +def f(): + with CtxMgr(1): + for i in [1, 2]: + for j in [3, 4]: + return (i, j) +print(f()) + +# multiple for loops within nested withs +def f(): + with CtxMgr(1): + for i in [1, 2]: + for j in [3, 4]: + with CtxMgr(2): + for k in [5, 6]: + for l in [7, 8]: + return (i, j, k, l) +print(f()) + +# multiple for loops that are optimised, and nested withs +def f(): + with CtxMgr(1): + for i in range(1, 3): + for j in range(3, 5): + with CtxMgr(2): + for k in range(5, 7): + for l in range(7, 9): + return (i, j, k, l) +print(f()) diff --git a/src/openmv/src/micropython/tests/bench/arrayop-1-list_inplace.py b/src/openmv/src/micropython/tests/bench/arrayop-1-list_inplace.py new file mode 100755 index 0000000..0ee1ef2 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/arrayop-1-list_inplace.py @@ -0,0 +1,12 @@ +# Array operation +# Type: list, inplace operation using for. What's good about this +# method is that it doesn't require any extra memory allocation. +import bench + +def test(num): + for i in iter(range(num//10000)): + arr = [0] * 1000 + for i in range(len(arr)): + arr[i] += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/arrayop-2-list_map.py b/src/openmv/src/micropython/tests/bench/arrayop-2-list_map.py new file mode 100755 index 0000000..9d5095c --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/arrayop-2-list_map.py @@ -0,0 +1,12 @@ +# Array operation +# Type: list, map() call. This method requires allocation of +# the same amount of memory as original array (to hold result +# array). On the other hand, input array stays intact. +import bench + +def test(num): + for i in iter(range(num//10000)): + arr = [0] * 1000 + arr2 = list(map(lambda x: x + 1, arr)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/arrayop-3-bytearray_inplace.py b/src/openmv/src/micropython/tests/bench/arrayop-3-bytearray_inplace.py new file mode 100755 index 0000000..a6d6280 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/arrayop-3-bytearray_inplace.py @@ -0,0 +1,12 @@ +# Array operation +# Type: bytearray, inplace operation using for. What's good about this +# method is that it doesn't require any extra memory allocation. +import bench + +def test(num): + for i in iter(range(num//10000)): + arr = bytearray(b"\0" * 1000) + for i in range(len(arr)): + arr[i] += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/arrayop-4-bytearray_map.py b/src/openmv/src/micropython/tests/bench/arrayop-4-bytearray_map.py new file mode 100755 index 0000000..1b92a40 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/arrayop-4-bytearray_map.py @@ -0,0 +1,12 @@ +# Array operation +# Type: list, map() call. This method requires allocation of +# the same amount of memory as original array (to hold result +# array). On the other hand, input array stays intact. +import bench + +def test(num): + for i in iter(range(num//10000)): + arr = bytearray(b"\0" * 1000) + arr2 = bytearray(map(lambda x: x + 1, arr)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/bench.py b/src/openmv/src/micropython/tests/bench/bench.py new file mode 100755 index 0000000..0cd40a9 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bench.py @@ -0,0 +1,10 @@ +import time + + +ITERS = 20000000 + +def run(f): + t = time.time() + f(ITERS) + t = time.time() - t + print(t) diff --git a/src/openmv/src/micropython/tests/bench/bytealloc-1-bytes_n.py b/src/openmv/src/micropython/tests/bench/bytealloc-1-bytes_n.py new file mode 100755 index 0000000..4a4bbc6 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bytealloc-1-bytes_n.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num // 1000)): + bytes(10000) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/bytealloc-2-repeat.py b/src/openmv/src/micropython/tests/bench/bytealloc-2-repeat.py new file mode 100755 index 0000000..786a804 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bytealloc-2-repeat.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num // 1000)): + b"\0" * 10000 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/bytebuf-1-inplace.py b/src/openmv/src/micropython/tests/bench/bytebuf-1-inplace.py new file mode 100755 index 0000000..7e7d939 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bytebuf-1-inplace.py @@ -0,0 +1,11 @@ +# Doing some operation on bytearray +# Inplace - the most memory efficient way +import bench + +def test(num): + for i in iter(range(num//10000)): + ba = bytearray(b"\0" * 1000) + for i in range(len(ba)): + ba[i] += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/bytebuf-2-join_map_bytes.py b/src/openmv/src/micropython/tests/bench/bytebuf-2-join_map_bytes.py new file mode 100755 index 0000000..daa6229 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bytebuf-2-join_map_bytes.py @@ -0,0 +1,12 @@ +# Doing some operation on bytearray +# Pretty weird way - map bytearray thru function, but make sure that +# function return bytes of size 1, then join them together. Surely, +# this is slowest way to do it. +import bench + +def test(num): + for i in iter(range(num//10000)): + ba = bytearray(b"\0" * 1000) + ba2 = b''.join(map(lambda x:bytes([x + 1]), ba)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/bytebuf-3-bytarray_map.py b/src/openmv/src/micropython/tests/bench/bytebuf-3-bytarray_map.py new file mode 100755 index 0000000..078d08e --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/bytebuf-3-bytarray_map.py @@ -0,0 +1,10 @@ +# Doing some operation on bytearray +# No joins, but still map(). +import bench + +def test(num): + for i in iter(range(num//10000)): + ba = bytearray(b"\0" * 1000) + ba2 = bytearray(map(lambda x: x + 1, ba)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-1-list_bound.py b/src/openmv/src/micropython/tests/bench/from_iter-1-list_bound.py new file mode 100755 index 0000000..d209dae --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-1-list_bound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = list(l) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-2-list_unbound.py b/src/openmv/src/micropython/tests/bench/from_iter-2-list_unbound.py new file mode 100755 index 0000000..be019c5 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-2-list_unbound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = list(map(lambda x: x, l)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-3-tuple_bound.py b/src/openmv/src/micropython/tests/bench/from_iter-3-tuple_bound.py new file mode 100755 index 0000000..7b7fa36 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-3-tuple_bound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = tuple(l) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-4-tuple_unbound.py b/src/openmv/src/micropython/tests/bench/from_iter-4-tuple_unbound.py new file mode 100755 index 0000000..7c7f134 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-4-tuple_unbound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = tuple(map(lambda x: x, l)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-5-bytes_bound.py b/src/openmv/src/micropython/tests/bench/from_iter-5-bytes_bound.py new file mode 100755 index 0000000..b793a32 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-5-bytes_bound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = bytes(l) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-6-bytes_unbound.py b/src/openmv/src/micropython/tests/bench/from_iter-6-bytes_unbound.py new file mode 100755 index 0000000..20aa556 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-6-bytes_unbound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = bytes(map(lambda x: x, l)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-7-bytearray_bound.py b/src/openmv/src/micropython/tests/bench/from_iter-7-bytearray_bound.py new file mode 100755 index 0000000..72001a0 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-7-bytearray_bound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = bytearray(l) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/from_iter-8-bytearray_unbound.py b/src/openmv/src/micropython/tests/bench/from_iter-8-bytearray_unbound.py new file mode 100755 index 0000000..e2263b8 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/from_iter-8-bytearray_unbound.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + for i in iter(range(num//10000)): + l = [0] * 1000 + l2 = bytearray(map(lambda x: x, l)) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_args-1.1-pos_1.py b/src/openmv/src/micropython/tests/bench/func_args-1.1-pos_1.py new file mode 100755 index 0000000..eee0ea8 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_args-1.1-pos_1.py @@ -0,0 +1,10 @@ +import bench + +def func(a): + pass + +def test(num): + for i in iter(range(num)): + func(i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_args-1.2-pos_3.py b/src/openmv/src/micropython/tests/bench/func_args-1.2-pos_3.py new file mode 100755 index 0000000..7e03ee2 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_args-1.2-pos_3.py @@ -0,0 +1,10 @@ +import bench + +def func(a, b, c): + pass + +def test(num): + for i in iter(range(num)): + func(i, i, i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_args-2-pos_default_2_of_3.py b/src/openmv/src/micropython/tests/bench/func_args-2-pos_default_2_of_3.py new file mode 100755 index 0000000..1fa0fbd --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_args-2-pos_default_2_of_3.py @@ -0,0 +1,10 @@ +import bench + +def func(a, b=1, c=2): + pass + +def test(num): + for i in iter(range(num)): + func(i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_args-3.1-kw_1.py b/src/openmv/src/micropython/tests/bench/func_args-3.1-kw_1.py new file mode 100755 index 0000000..7bc81e5 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_args-3.1-kw_1.py @@ -0,0 +1,10 @@ +import bench + +def func(a): + pass + +def test(num): + for i in iter(range(num)): + func(a=i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_args-3.2-kw_3.py b/src/openmv/src/micropython/tests/bench/func_args-3.2-kw_3.py new file mode 100755 index 0000000..7f95106 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_args-3.2-kw_3.py @@ -0,0 +1,10 @@ +import bench + +def func(a, b, c): + pass + +def test(num): + for i in iter(range(num)): + func(c=i, b=i, a=i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_builtin-1-enum_pos.py b/src/openmv/src/micropython/tests/bench/func_builtin-1-enum_pos.py new file mode 100755 index 0000000..2093516 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_builtin-1-enum_pos.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num//20)): + enumerate([1, 2], 1) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/func_builtin-2-enum_kw.py b/src/openmv/src/micropython/tests/bench/func_builtin-2-enum_kw.py new file mode 100755 index 0000000..6c5e444 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/func_builtin-2-enum_kw.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num//20)): + enumerate(iterable=[1, 2], start=1) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/funcall-1-inline.py b/src/openmv/src/micropython/tests/bench/funcall-1-inline.py new file mode 100755 index 0000000..fbeb796 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/funcall-1-inline.py @@ -0,0 +1,9 @@ +# Function call overhead test +# Establish a baseline for performing a trivial operation inline +import bench + +def test(num): + for i in iter(range(num)): + a = i + 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/funcall-2-funcall.py b/src/openmv/src/micropython/tests/bench/funcall-2-funcall.py new file mode 100755 index 0000000..d5c36c6 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/funcall-2-funcall.py @@ -0,0 +1,12 @@ +# Function call overhead test +# Perform the same trivial operation as global function call +import bench + +def f(x): + return x + 1 + +def test(num): + for i in iter(range(num)): + a = f(i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/funcall-3-funcall-local.py b/src/openmv/src/micropython/tests/bench/funcall-3-funcall-local.py new file mode 100755 index 0000000..1a6d728 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/funcall-3-funcall-local.py @@ -0,0 +1,16 @@ +# Function call overhead test +# Perform the same trivial operation as calling function, cached in a +# local variable. This is commonly known optimization for overly dynamic +# languages (the idea is to cut on symbolic look up overhead, as local +# variables are accessed by offset, not by name) +import bench + +def f(x): + return x + 1 + +def test(num): + f_ = f + for i in iter(range(num)): + a = f_(i) + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-1-range.py b/src/openmv/src/micropython/tests/bench/loop_count-1-range.py new file mode 100755 index 0000000..e22adf6 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-1-range.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in range(num): + pass + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-2-range_iter.py b/src/openmv/src/micropython/tests/bench/loop_count-2-range_iter.py new file mode 100755 index 0000000..fe4a385 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-2-range_iter.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + for i in iter(range(num)): + pass + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-3-while_up.py b/src/openmv/src/micropython/tests/bench/loop_count-3-while_up.py new file mode 100755 index 0000000..1ab8054 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-3-while_up.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + i = 0 + while i < num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-4-while_down_gt.py b/src/openmv/src/micropython/tests/bench/loop_count-4-while_down_gt.py new file mode 100755 index 0000000..de8dee2 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-4-while_down_gt.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + while num > 0: + num -= 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-5-while_down_ne.py b/src/openmv/src/micropython/tests/bench/loop_count-5-while_down_ne.py new file mode 100755 index 0000000..b9a1af4 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-5-while_down_ne.py @@ -0,0 +1,7 @@ +import bench + +def test(num): + while num != 0: + num -= 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/loop_count-5.1-while_down_ne_localvar.py b/src/openmv/src/micropython/tests/bench/loop_count-5.1-while_down_ne_localvar.py new file mode 100755 index 0000000..96bdb91 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/loop_count-5.1-while_down_ne_localvar.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + zero = 0 + while num != zero: + num -= 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-1-constant.py b/src/openmv/src/micropython/tests/bench/var-1-constant.py new file mode 100755 index 0000000..eec9779 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-1-constant.py @@ -0,0 +1,8 @@ +import bench + +def test(num): + i = 0 + while i < 20000000: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-2-global.py b/src/openmv/src/micropython/tests/bench/var-2-global.py new file mode 100755 index 0000000..5758ad6 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-2-global.py @@ -0,0 +1,10 @@ +import bench + +ITERS = 20000000 + +def test(num): + i = 0 + while i < ITERS: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-3-local.py b/src/openmv/src/micropython/tests/bench/var-3-local.py new file mode 100755 index 0000000..124b484 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-3-local.py @@ -0,0 +1,10 @@ +import bench + + +def test(num): + ITERS = 20000000 + i = 0 + while i < ITERS: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-4-arg.py b/src/openmv/src/micropython/tests/bench/var-4-arg.py new file mode 100755 index 0000000..cf050c5 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-4-arg.py @@ -0,0 +1,9 @@ +import bench + + +def test(num): + i = 0 + while i < num: + i += 1 + +bench.run(lambda n:test(20000000)) diff --git a/src/openmv/src/micropython/tests/bench/var-5-class-attr.py b/src/openmv/src/micropython/tests/bench/var-5-class-attr.py new file mode 100755 index 0000000..02ae874 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-5-class-attr.py @@ -0,0 +1,11 @@ +import bench + +class Foo: + num = 20000000 + +def test(num): + i = 0 + while i < Foo.num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-6-instance-attr.py b/src/openmv/src/micropython/tests/bench/var-6-instance-attr.py new file mode 100755 index 0000000..787ed87 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-6-instance-attr.py @@ -0,0 +1,14 @@ +import bench + +class Foo: + + def __init__(self): + self.num = 20000000 + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-6.1-instance-attr-5.py b/src/openmv/src/micropython/tests/bench/var-6.1-instance-attr-5.py new file mode 100755 index 0000000..e8d3383 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-6.1-instance-attr-5.py @@ -0,0 +1,18 @@ +import bench + +class Foo: + + def __init__(self): + self.num1 = 0 + self.num2 = 0 + self.num3 = 0 + self.num4 = 0 + self.num = 20000000 + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-7-instance-meth.py b/src/openmv/src/micropython/tests/bench/var-7-instance-meth.py new file mode 100755 index 0000000..f9d463f --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-7-instance-meth.py @@ -0,0 +1,17 @@ +import bench + +class Foo: + + def __init__(self): + self._num = 20000000 + + def num(self): + return self._num + +def test(num): + o = Foo() + i = 0 + while i < o.num(): + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-8-namedtuple-1st.py b/src/openmv/src/micropython/tests/bench/var-8-namedtuple-1st.py new file mode 100755 index 0000000..d862480 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-8-namedtuple-1st.py @@ -0,0 +1,12 @@ +import bench +from ucollections import namedtuple + +T = namedtuple("Tup", ["num", "bar"]) + +def test(num): + t = T(20000000, 0) + i = 0 + while i < t.num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/bench/var-8.1-namedtuple-5th.py b/src/openmv/src/micropython/tests/bench/var-8.1-namedtuple-5th.py new file mode 100755 index 0000000..0bcf661 --- /dev/null +++ b/src/openmv/src/micropython/tests/bench/var-8.1-namedtuple-5th.py @@ -0,0 +1,12 @@ +import bench +from ucollections import namedtuple + +T = namedtuple("Tup", ["foo1", "foo2", "foo3", "foo4", "num"]) + +def test(num): + t = T(0, 0, 0, 0, 20000000) + i = 0 + while i < t.num: + i += 1 + +bench.run(test) diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py b/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py new file mode 100755 index 0000000..79d3bb4 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py @@ -0,0 +1,4 @@ +# cmdline: -O +# test optimisation output +print(__debug__) +assert 0 diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py.exp b/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py.exp new file mode 100755 index 0000000..bc59c12 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_optimise.py.exp @@ -0,0 +1 @@ +False diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py b/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py new file mode 100755 index 0000000..da36c80 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py @@ -0,0 +1,12 @@ +# cmdline: -v -v -v +# test printing of the parse-tree + +for i in (): + pass +a = None +b = 'str' +c = 'a very long str that will not be interned' +d = b'bytes' +e = b'a very long bytes that will not be interned' +f = 123456789012345678901234567890 +g = 123 diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py.exp b/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py.exp new file mode 100755 index 0000000..12a1bfb --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_parsetree.py.exp @@ -0,0 +1,73 @@ +---------------- +[ 4] rule(1) (n=9) + tok(4) +[ 4] rule(22) (n=4) + id(i) +[ 4] rule(44) (n=1) + NULL +[ 5] rule(8) (n=0) + NULL +[ 6] rule(5) (n=2) + id(a) + tok(14) +[ 7] rule(5) (n=2) + id(b) + str(str) +[ 8] rule(5) (n=2) + id(c) +[ 8] literal \.\+ +[ 9] rule(5) (n=2) + id(d) + bytes(bytes) +[ 10] rule(5) (n=2) + id(e) +[ 10] literal \.\+ +[ 11] rule(5) (n=2) + id(f) +[ 11] literal \.\+ +[ 12] rule(5) (n=2) + id(g) + int(123) +---------------- +File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: +(N_STATE 5) +(N_EXC_STACK 0) + bc=-1 line=1 + bc=0 line=4 + bc=9 line=5 + bc=12 line=6 + bc=16 line=7 + bc=22 line=8 + bc=27 line=9 + bc=32 line=10 + bc=37 line=11 + bc=42 line=12 +00 BUILD_TUPLE 0 +02 GET_ITER_STACK +03 FOR_ITER 12 +06 STORE_NAME i +09 JUMP 3 +12 LOAD_CONST_NONE +13 STORE_NAME a +16 LOAD_CONST_STRING 'str' +19 STORE_NAME b +22 LOAD_CONST_OBJ \.\+ +24 STORE_NAME c +27 LOAD_CONST_OBJ \.\+ +29 STORE_NAME d +32 LOAD_CONST_OBJ \.\+ +34 STORE_NAME e +37 LOAD_CONST_OBJ \.\+ +39 STORE_NAME f +42 LOAD_CONST_SMALL_INT 123 +45 STORE_NAME g +48 LOAD_CONST_NONE +49 RETURN_VALUE +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py b/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py new file mode 100755 index 0000000..6e99fc4 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py @@ -0,0 +1,156 @@ +# cmdline: -v -v +# test printing of all bytecodes + +def f(): + # constants + a = None + False + True + a = 0 + a = 1000 + a = -1000 + + # constructing data + a = 1 + b = (1, 2) + c = [1, 2] + d = {1, 2} + e = {} + f = {1:2} + g = 'a' + h = b'a' + + # unary/binary ops + i = 1 + j = 2 + k = a + b + l = -a + m = not a + m = a == b == c + m = not (a == b and b == c) + + # attributes + n = b.c + b.c = n + + # subscript + p = b[0] + b[0] = p + b[0] += p + + # slice + a = b[::] + + # sequenc unpacking + a, b = c + a, *a = a + + # tuple swapping + a, b = b, a + a, b, c = c, b, a + + # del fast + del a + + # globals + global gl + gl = a + del gl + + # comprehensions + a = (b for c in d if e) + a = [b for c in d if e] + a = {b:b for c in d if e} + + # function calls + a() + a(1) + a(b=1) + a(*b) + + # method calls + a.b() + a.b(1) + a.b(c=1) + a.b(*c) + + # jumps + if a: + x + else: + y + while a: + b + while not a: + b + a = a or a + + # for loop + for a in b: + c + + # exceptions + try: + while a: + break + except: + b + finally: + c + while a: + try: + break + except: + pass + + # with + with a: + b + + # closed over variables + x = 1 + def closure(): + a = x + 1 + x = 1 + del x + + # import + import a + from a import b + from a import * + + # raise + raise + raise 1 + + # return + return + return 1 + +# function with lots of locals +def f(): + l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = 1 + m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = m10 = 2 + l10 + m10 + +# functions with default args +def f(a=1): + pass + + def f(b=2): + return b + a + +# function which yields +def f(): + yield + yield 1 + yield from 1 + +# class +class Class: + pass + +# delete name +del Class + +# load super method +def f(self): + super().f() diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py.exp b/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py.exp new file mode 100755 index 0000000..1274cda --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_showbc.py.exp @@ -0,0 +1,548 @@ +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: +(N_STATE 3) +(N_EXC_STACK 0) + bc=-1 line=1 +######## + bc=\\d\+ line=155 +00 MAKE_FUNCTION \.\+ +\\d\+ STORE_NAME f +\\d\+ MAKE_FUNCTION \.\+ +\\d\+ STORE_NAME f +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ BUILD_TUPLE 1 +\\d\+ LOAD_NULL +\\d\+ MAKE_FUNCTION_DEFARGS \.\+ +\\d\+ STORE_NAME f +\\d\+ MAKE_FUNCTION \.\+ +\\d\+ STORE_NAME f +\\d\+ LOAD_BUILD_CLASS +\\d\+ MAKE_FUNCTION \.\+ +\\d\+ LOAD_CONST_STRING 'Class' +\\d\+ CALL_FUNCTION n=2 nkw=0 +\\d\+ STORE_NAME Class +\\d\+ DELETE_NAME Class +\\d\+ MAKE_FUNCTION \.\+ +\\d\+ STORE_NAME f +\\d\+ LOAD_CONST_NONE +\\d\+ RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+rg names: +(N_STATE 22) +(N_EXC_STACK 2) +(INIT_CELL 14) +(INIT_CELL 15) +(INIT_CELL 16) + bc=-4 line=1 +######## + bc=\\d\+ line=126 +00 LOAD_CONST_NONE +01 LOAD_CONST_FALSE +02 BINARY_OP 26 __add__ +03 LOAD_CONST_TRUE +04 BINARY_OP 26 __add__ +05 STORE_FAST 0 +06 LOAD_CONST_SMALL_INT 0 +07 STORE_FAST 0 +08 LOAD_CONST_SMALL_INT 1000 +11 STORE_FAST 0 +12 LOAD_CONST_SMALL_INT -1000 +15 STORE_FAST 0 +16 LOAD_CONST_SMALL_INT 1 +17 STORE_FAST 0 +18 LOAD_CONST_SMALL_INT 1 +19 LOAD_CONST_SMALL_INT 2 +20 BUILD_TUPLE 2 +22 STORE_DEREF 14 +24 LOAD_CONST_SMALL_INT 1 +25 LOAD_CONST_SMALL_INT 2 +26 BUILD_LIST 2 +28 STORE_FAST 1 +29 LOAD_CONST_SMALL_INT 1 +30 LOAD_CONST_SMALL_INT 2 +31 BUILD_SET 2 +33 STORE_FAST 2 +34 BUILD_MAP 0 +36 STORE_DEREF 15 +38 BUILD_MAP 1 +40 LOAD_CONST_SMALL_INT 2 +41 LOAD_CONST_SMALL_INT 1 +42 STORE_MAP +43 STORE_FAST 3 +44 LOAD_CONST_STRING 'a' +47 STORE_FAST 4 +48 LOAD_CONST_OBJ \.\+ +\\d\+ STORE_FAST 5 +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ STORE_FAST 6 +\\d\+ LOAD_CONST_SMALL_INT 2 +\\d\+ STORE_FAST 7 +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ BINARY_OP 26 __add__ +\\d\+ STORE_FAST 8 +\\d\+ LOAD_FAST 0 +\\d\+ UNARY_OP 1 +\\d\+ STORE_FAST 9 +\\d\+ LOAD_FAST 0 +\\d\+ UNARY_OP 3 +\\d\+ STORE_FAST 10 +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ DUP_TOP +\\d\+ ROT_THREE +\\d\+ BINARY_OP 2 __eq__ +\\d\+ JUMP_IF_FALSE_OR_POP \\d\+ +\\d\+ LOAD_FAST 1 +\\d\+ BINARY_OP 2 __eq__ +\\d\+ JUMP \\d\+ +\\d\+ ROT_TWO +\\d\+ POP_TOP +\\d\+ STORE_FAST 10 +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ BINARY_OP 2 __eq__ +\\d\+ JUMP_IF_FALSE_OR_POP \\d\+ +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_FAST 1 +\\d\+ BINARY_OP 2 __eq__ +\\d\+ UNARY_OP 3 +\\d\+ STORE_FAST 10 +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_ATTR c (cache=0) +\\d\+ STORE_FAST 11 +\\d\+ LOAD_FAST 11 +\\d\+ LOAD_DEREF 14 +\\d\+ STORE_ATTR c (cache=0) +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ LOAD_SUBSCR +\\d\+ STORE_FAST 12 +\\d\+ LOAD_FAST 12 +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ STORE_SUBSCR +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ DUP_TOP_TWO +\\d\+ LOAD_SUBSCR +\\d\+ LOAD_FAST 12 +\\d\+ BINARY_OP 14 __iadd__ +\\d\+ ROT_THREE +\\d\+ STORE_SUBSCR +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_CONST_NONE +\\d\+ LOAD_CONST_NONE +\\d\+ BUILD_SLICE 2 +\\d\+ LOAD_SUBSCR +\\d\+ STORE_FAST 0 +\\d\+ LOAD_FAST 1 +\\d\+ UNPACK_SEQUENCE 2 +\\d\+ STORE_FAST 0 +\\d\+ STORE_DEREF 14 +\\d\+ LOAD_FAST 0 +\\d\+ UNPACK_EX 1 +\\d\+ STORE_FAST 0 +\\d\+ STORE_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_FAST 0 +\\d\+ ROT_TWO +\\d\+ STORE_FAST 0 +\\d\+ STORE_DEREF 14 +\\d\+ LOAD_FAST 1 +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_FAST 0 +\\d\+ ROT_THREE +\\d\+ ROT_TWO +\\d\+ STORE_FAST 0 +\\d\+ STORE_DEREF 14 +\\d\+ STORE_FAST 1 +\\d\+ DELETE_FAST 0 +\\d\+ LOAD_FAST 0 +\\d\+ STORE_GLOBAL gl +\\d\+ DELETE_GLOBAL gl +\\d\+ LOAD_FAST 14 +\\d\+ LOAD_FAST 15 +\\d\+ MAKE_CLOSURE \.\+ 2 +\\d\+ LOAD_FAST 2 +\\d\+ GET_ITER +\\d\+ CALL_FUNCTION n=1 nkw=0 +\\d\+ STORE_FAST 0 +\\d\+ LOAD_FAST 14 +\\d\+ LOAD_FAST 15 +\\d\+ MAKE_CLOSURE \.\+ 2 +\\d\+ LOAD_FAST 2 +\\d\+ CALL_FUNCTION n=1 nkw=0 +\\d\+ STORE_FAST 0 +\\d\+ LOAD_FAST 14 +\\d\+ LOAD_FAST 15 +\\d\+ MAKE_CLOSURE \.\+ 2 +\\d\+ LOAD_FAST 2 +\\d\+ CALL_FUNCTION n=1 nkw=0 +\\d\+ STORE_FAST 0 +\\d\+ LOAD_FAST 0 +\\d\+ CALL_FUNCTION n=0 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ CALL_FUNCTION n=1 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_CONST_STRING 'b' +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ CALL_FUNCTION n=0 nkw=1 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ LOAD_NULL +\\d\+ CALL_FUNCTION_VAR_KW n=0 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_METHOD b +\\d\+ CALL_METHOD n=0 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_METHOD b +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ CALL_METHOD n=1 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_METHOD b +\\d\+ LOAD_CONST_STRING 'c' +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ CALL_METHOD n=0 nkw=1 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_METHOD b +\\d\+ LOAD_FAST 1 +\\d\+ LOAD_NULL +\\d\+ CALL_METHOD_VAR_KW n=0 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_FALSE \\d\+ +\\d\+ LOAD_DEREF 16 +\\d\+ POP_TOP +\\d\+ JUMP \\d\+ +\\d\+ LOAD_GLOBAL y (cache=0) +\\d\+ POP_TOP +\\d\+ JUMP \\d\+ +\\d\+ LOAD_DEREF 14 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_TRUE \\d\+ +\\d\+ JUMP \\d\+ +\\d\+ LOAD_DEREF 14 +\\d\+ POP_TOP +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_FALSE \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ JUMP_IF_TRUE_OR_POP \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ STORE_FAST 0 +\\d\+ LOAD_DEREF 14 +\\d\+ GET_ITER_STACK +\\d\+ FOR_ITER \\d\+ +\\d\+ STORE_FAST 0 +\\d\+ LOAD_FAST 1 +\\d\+ POP_TOP +\\d\+ JUMP \\d\+ +\\d\+ SETUP_FINALLY \\d\+ +\\d\+ SETUP_EXCEPT \\d\+ +\\d\+ JUMP \\d\+ +\\d\+ JUMP \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_TRUE \\d\+ +\\d\+ POP_BLOCK +\\d\+ JUMP \\d\+ +\\d\+ POP_TOP +\\d\+ LOAD_DEREF 14 +\\d\+ POP_TOP +\\d\+ POP_EXCEPT +\\d\+ JUMP \\d\+ +\\d\+ END_FINALLY +\\d\+ POP_BLOCK +\\d\+ LOAD_CONST_NONE +\\d\+ LOAD_FAST 1 +\\d\+ POP_TOP +\\d\+ END_FINALLY +\\d\+ JUMP \\d\+ +\\d\+ SETUP_EXCEPT \\d\+ +\\d\+ UNWIND_JUMP \\d\+ 1 +\\d\+ POP_BLOCK +\\d\+ JUMP \\d\+ +\\d\+ POP_TOP +\\d\+ POP_EXCEPT +\\d\+ JUMP \\d\+ +\\d\+ END_FINALLY +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_TRUE \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ SETUP_WITH \\d\+ +\\d\+ POP_TOP +\\d\+ LOAD_DEREF 14 +\\d\+ POP_TOP +\\d\+ POP_BLOCK +\\d\+ LOAD_CONST_NONE +\\d\+ WITH_CLEANUP +\\d\+ END_FINALLY +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ STORE_DEREF 16 +\\d\+ LOAD_FAST_N 16 +\\d\+ MAKE_CLOSURE \.\+ 1 +\\d\+ STORE_FAST 13 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ LOAD_CONST_NONE +\\d\+ IMPORT_NAME 'a' +\\d\+ STORE_FAST 0 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ LOAD_CONST_STRING 'b' +\\d\+ BUILD_TUPLE 1 +\\d\+ IMPORT_NAME 'a' +\\d\+ IMPORT_FROM 'b' +\\d\+ STORE_DEREF 14 +\\d\+ POP_TOP +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ LOAD_CONST_STRING '*' +\\d\+ BUILD_TUPLE 1 +\\d\+ IMPORT_NAME 'a' +\\d\+ IMPORT_STAR +\\d\+ RAISE_VARARGS 0 +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ RAISE_VARARGS 1 +\\d\+ LOAD_CONST_NONE +\\d\+ RETURN_VALUE +\\d\+ LOAD_CONST_SMALL_INT 1 +\\d\+ RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+rg names: +(N_STATE 22) +(N_EXC_STACK 0) + bc=-1 line=1 +######## + bc=\\d\+ line=132 +00 LOAD_CONST_SMALL_INT 1 +01 DUP_TOP +02 STORE_FAST 0 +03 DUP_TOP +04 STORE_FAST 1 +05 DUP_TOP +06 STORE_FAST 2 +07 DUP_TOP +08 STORE_FAST 3 +09 DUP_TOP +10 STORE_FAST 4 +11 DUP_TOP +12 STORE_FAST 5 +13 DUP_TOP +14 STORE_FAST 6 +15 DUP_TOP +16 STORE_FAST 7 +17 DUP_TOP +18 STORE_FAST 8 +19 STORE_FAST 9 +20 LOAD_CONST_SMALL_INT 2 +21 DUP_TOP +22 STORE_FAST 10 +23 DUP_TOP +24 STORE_FAST 11 +25 DUP_TOP +26 STORE_FAST 12 +27 DUP_TOP +28 STORE_FAST 13 +29 DUP_TOP +30 STORE_FAST 14 +31 DUP_TOP +32 STORE_FAST 15 +33 DUP_TOP +34 STORE_FAST_N 16 +36 DUP_TOP +37 STORE_FAST_N 17 +39 DUP_TOP +40 STORE_FAST_N 18 +42 STORE_FAST_N 19 +44 LOAD_FAST 9 +45 LOAD_FAST_N 19 +47 BINARY_OP 26 __add__ +48 POP_TOP +49 LOAD_CONST_NONE +50 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: a +(N_STATE 5) +(N_EXC_STACK 0) +(INIT_CELL 0) +######## + bc=\\d\+ line=138 +00 LOAD_CONST_SMALL_INT 2 +01 BUILD_TUPLE 1 +03 LOAD_NULL +04 LOAD_FAST 0 +05 MAKE_CLOSURE_DEFARGS \.\+ 1 +\\d\+ STORE_FAST 1 +\\d\+ LOAD_CONST_NONE +\\d\+ RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: +(N_STATE 2) +(N_EXC_STACK 0) + bc=-1 line=1 + bc=0 line=143 + bc=3 line=144 + bc=6 line=145 +00 LOAD_CONST_NONE +01 YIELD_VALUE +02 POP_TOP +03 LOAD_CONST_SMALL_INT 1 +04 YIELD_VALUE +05 POP_TOP +06 LOAD_CONST_SMALL_INT 1 +07 GET_ITER +08 LOAD_CONST_NONE +09 YIELD_FROM +10 POP_TOP +11 LOAD_CONST_NONE +12 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'Class' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: +(N_STATE 1) +(N_EXC_STACK 0) + bc=-1 line=1 + bc=13 line=149 +00 LOAD_NAME __name__ (cache=0) +04 STORE_NAME __module__ +07 LOAD_CONST_STRING 'Class' +10 STORE_NAME __qualname__ +13 LOAD_CONST_NONE +14 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: self +(N_STATE 4) +(N_EXC_STACK 0) + bc=-1 line=1 + bc=0 line=156 +00 LOAD_GLOBAL super (cache=0) +\\d\+ LOAD_GLOBAL __class__ (cache=0) +\\d\+ LOAD_FAST 0 +\\d\+ LOAD_SUPER_METHOD f +\\d\+ CALL_METHOD n=0 nkw=0 +\\d\+ POP_TOP +\\d\+ LOAD_CONST_NONE +\\d\+ RETURN_VALUE +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: * * * +(N_STATE 9) +(N_EXC_STACK 0) + bc=-\\d\+ line=1 +00 LOAD_NULL +01 LOAD_FAST 2 +02 LOAD_NULL +03 LOAD_NULL +04 FOR_ITER 20 +07 STORE_FAST 3 +08 LOAD_DEREF 1 +10 POP_JUMP_IF_FALSE 4 +13 LOAD_DEREF 0 +15 YIELD_VALUE +16 POP_TOP +17 JUMP 4 +20 LOAD_CONST_NONE +21 RETURN_VALUE +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: * * * +(N_STATE 10) +(N_EXC_STACK 0) + bc=-\\d\+ line=1 +00 BUILD_LIST 0 +02 LOAD_FAST 2 +03 GET_ITER_STACK +04 FOR_ITER 20 +07 STORE_FAST 3 +08 LOAD_DEREF 1 +10 POP_JUMP_IF_FALSE 4 +13 LOAD_DEREF 0 +15 STORE_COMP 20 +17 JUMP 4 +20 RETURN_VALUE +File cmdline/cmd_showbc.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: * * * +(N_STATE 11) +(N_EXC_STACK 0) + bc=-\\d\+ line=1 +######## +00 BUILD_MAP 0 +02 LOAD_FAST 2 +03 GET_ITER_STACK +04 FOR_ITER 22 +07 STORE_FAST 3 +08 LOAD_DEREF 1 +10 POP_JUMP_IF_FALSE 4 +13 LOAD_DEREF 0 +15 LOAD_DEREF 0 +17 STORE_COMP 25 +19 JUMP 4 +22 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'closure' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: * +(N_STATE 4) +(N_EXC_STACK 0) + bc=-\\d\+ line=1 +######## + bc=\\d\+ line=113 +00 LOAD_DEREF 0 +02 LOAD_CONST_SMALL_INT 1 +03 BINARY_OP 26 __add__ +04 STORE_FAST 1 +05 LOAD_CONST_SMALL_INT 1 +06 STORE_DEREF 0 +08 DELETE_DEREF 0 +10 LOAD_CONST_NONE +11 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## +\.\+5b +arg names: * b +(N_STATE 4) +(N_EXC_STACK 0) + bc=-\\d\+ line=1 +######## + bc=\\d\+ line=139 +00 LOAD_FAST 1 +01 LOAD_DEREF 0 +03 BINARY_OP 26 __add__ +04 RETURN_VALUE +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py b/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py new file mode 100755 index 0000000..b599a7a --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py @@ -0,0 +1,3 @@ +# cmdline: -v -v +# test verbose output +print(1) diff --git a/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py.exp b/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py.exp new file mode 100755 index 0000000..f562261 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/cmd_verbose.py.exp @@ -0,0 +1,21 @@ +File cmdline/cmd_verbose.py, code block '' (descriptor: \.\+, bytecode \.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): + 02 \.\+ +######## +\.\+5b +arg names: +(N_STATE 2) +(N_EXC_STACK 0) + bc=-1 line=1 + bc=0 line=3 +00 LOAD_NAME print (cache=0) +04 LOAD_CONST_SMALL_INT 1 +05 CALL_FUNCTION n=1 nkw=0 +07 POP_TOP +08 LOAD_CONST_NONE +09 RETURN_VALUE +1 +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ diff --git a/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py b/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py new file mode 100755 index 0000000..27cad42 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py @@ -0,0 +1,9 @@ +# tests for autocompletion +impo sys +not_exist.  +not_exist  +x = '123' +1, x.isdi () +i = str +i.lowe ('ABC') +None.  diff --git a/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py.exp b/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py.exp new file mode 100755 index 0000000..7500298 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_autocomplete.py.exp @@ -0,0 +1,14 @@ +MicroPython \.\+ version +Use \.\+ +>>> # tests for autocompletion +>>> import sys +>>> not_exist. +>>> not_exist +>>> x = '123' +>>> 1, x.isdigit() +(1, True) +>>> i = str +>>> i.lower('ABC') +'abc' +>>> None. +>>> diff --git a/src/openmv/src/micropython/tests/cmdline/repl_basic.py b/src/openmv/src/micropython/tests/cmdline/repl_basic.py new file mode 100755 index 0000000..cbd5d3a --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_basic.py @@ -0,0 +1,4 @@ +# basic REPL tests +print(1) + +2 diff --git a/src/openmv/src/micropython/tests/cmdline/repl_basic.py.exp b/src/openmv/src/micropython/tests/cmdline/repl_basic.py.exp new file mode 100755 index 0000000..2b390ea --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_basic.py.exp @@ -0,0 +1,10 @@ +MicroPython \.\+ version +Use \.\+ +>>> # basic REPL tests +>>> print(1) +1 +>>> print(1) +1 +>>> 2 +2 +>>> diff --git a/src/openmv/src/micropython/tests/cmdline/repl_cont.py b/src/openmv/src/micropython/tests/cmdline/repl_cont.py new file mode 100755 index 0000000..921274b --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_cont.py @@ -0,0 +1,34 @@ +# check REPL allows to continue input +1 \ ++ 2 +'"' +"'" +'\'' +"\"" +'\'(' +"\"(" +print("\"(") +print('\'(') +print("\'(") +print('\"(') +'abc' +"abc" +'''abc +def''' +"""ABC +DEF""" +print( +1 + 2) +l = [1, +2] +print(l) +d = {1:'one', +2:'two'} +print(d[2]) +def f(x): +print(x) + +f(3) +if1=1 +if1 = 2 +print(if1) diff --git a/src/openmv/src/micropython/tests/cmdline/repl_cont.py.exp b/src/openmv/src/micropython/tests/cmdline/repl_cont.py.exp new file mode 100755 index 0000000..834c18a --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_cont.py.exp @@ -0,0 +1,57 @@ +MicroPython \.\+ version +Use \.\+ +>>> # check REPL allows to continue input +>>> 1 \\\\ +... + 2 +3 +>>> '"' +'"' +>>> "'" +"'" +>>> '\\\\'' +"'" +>>> "\\\\"" +'"' +>>> '\\\\'(' +"'(" +>>> "\\\\"(" +'"(' +>>> print("\\\\"(") +"( +>>> print('\\\\'(') +'( +>>> print("\\\\'(") +'( +>>> print('\\\\"(') +"( +>>> 'abc' +'abc' +>>> "abc" +'abc' +>>> '''abc +... def''' +'abc\\\\ndef' +>>> """ABC +... DEF""" +'ABC\\\\nDEF' +>>> print( +... 1 + 2) +3 +>>> l = [1, +... 2] +>>> print(l) +[1, 2] +>>> d = {1:'one', +... 2:'two'} +>>> print(d[2]) +two +>>> def f(x): +... print(x) +...  +>>> f(3) +3 +>>> if1=1 +>>> if1 = 2 +>>> print(if1) +2 +>>> diff --git a/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py b/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py new file mode 100755 index 0000000..ae9e6e1 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py @@ -0,0 +1,10 @@ +# REPL tests of GNU-ish readline navigation +# history buffer navigation +1 +2 +3 + + +# input line motion +t = 12 +'boofar fbar' diff --git a/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py.exp b/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py.exp new file mode 100755 index 0000000..6102c19 --- /dev/null +++ b/src/openmv/src/micropython/tests/cmdline/repl_emacs_keys.py.exp @@ -0,0 +1,19 @@ +MicroPython \.\+ version +Use \.\+ +>>> # REPL tests of GNU-ish readline navigation +>>> # history buffer navigation +>>> 1 +1 +>>> 2 +2 +>>> 3 +3 +>>> 321 +1 +>>> 1323 +3 +>>> # input line motion +>>> t = 121 +>>> \.\+ +'foobar' +>>> diff --git a/src/openmv/src/micropython/tests/cpydiff/builtin_next_arg2.py b/src/openmv/src/micropython/tests/cpydiff/builtin_next_arg2.py new file mode 100755 index 0000000..5df2d6e --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/builtin_next_arg2.py @@ -0,0 +1,12 @@ +""" +categories: Modules,builtins +description: Second argument to next() is not implemented +cause: MicroPython is optimised for code space. +workaround: Instead of ``val = next(it, deflt)`` use:: + + try: + val = next(it) + except StopIteration: + val = deflt +""" +print(next(iter(range(0)), 42)) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_class_delnotimpl.py b/src/openmv/src/micropython/tests/cpydiff/core_class_delnotimpl.py new file mode 100755 index 0000000..c51c3d5 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_class_delnotimpl.py @@ -0,0 +1,16 @@ +""" +categories: Core,Classes +description: Special method __del__ not implemented for user-defined classes +cause: Unknown +workaround: Unknown +""" +import gc + +class Foo(): + def __del__(self): + print('__del__') + +f = Foo() +del f + +gc.collect() diff --git a/src/openmv/src/micropython/tests/cpydiff/core_class_mro.py b/src/openmv/src/micropython/tests/cpydiff/core_class_mro.py new file mode 100755 index 0000000..99713e7 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_class_mro.py @@ -0,0 +1,15 @@ +""" +categories: Core,Classes +description: Method Resolution Order (MRO) is not compliant with CPython +cause: Depth first non-exhaustive method resolution order +workaround: Avoid complex class hierarchies with multiple inheritance and complex method overrides. Keep in mind that many languages don't support multiple inheritance at all. +""" +class Foo: + def __str__(self): + return "Foo" + +class C(tuple, Foo): + pass + +t = C((1, 2, 3)) +print(t) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_class_supermultiple.py b/src/openmv/src/micropython/tests/cpydiff/core_class_supermultiple.py new file mode 100755 index 0000000..f0823ee --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_class_supermultiple.py @@ -0,0 +1,27 @@ +""" +categories: Core,Classes +description: When inheriting from multiple classes super() only calls one class +cause: See :ref:`cpydiff_core_class_mro` +workaround: See :ref:`cpydiff_core_class_mro` +""" +class A: + def __init__(self): + print("A.__init__") + +class B(A): + def __init__(self): + print("B.__init__") + super().__init__() + +class C(A): + def __init__(self): + print("C.__init__") + super().__init__() + + +class D(B,C): + def __init__(self): + print("D.__init__") + super().__init__() + +D() diff --git a/src/openmv/src/micropython/tests/cpydiff/core_class_superproperty.py b/src/openmv/src/micropython/tests/cpydiff/core_class_superproperty.py new file mode 100755 index 0000000..1ec2105 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_class_superproperty.py @@ -0,0 +1,18 @@ +""" +categories: Core,Classes +description: Calling super() getter property in subclass will return a property object, not the value +cause: Unknown +workaround: Unknown +""" +class A: + @property + def p(self): + return {"a":10} + +class AA(A): + @property + def p(self): + return super().p + +a = AA() +print(a.p) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_function_argcount.py b/src/openmv/src/micropython/tests/cpydiff/core_function_argcount.py new file mode 100755 index 0000000..5f3dca4 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_function_argcount.py @@ -0,0 +1,10 @@ +""" +categories: Core,Functions +description: Error messages for methods may display unexpected argument counts +cause: MicroPython counts "self" as an argument. +workaround: Interpret error messages with the information above in mind. +""" +try: + [].append() +except Exception as e: + print(e) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_function_userattr.py b/src/openmv/src/micropython/tests/cpydiff/core_function_userattr.py new file mode 100755 index 0000000..2972939 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_function_userattr.py @@ -0,0 +1,11 @@ +""" +categories: Core,Functions +description: User-defined attributes for functions are not supported +cause: MicroPython is highly optimized for memory usage. +workaround: Use external dictionary, e.g. ``FUNC_X[f] = 0``. +""" +def f(): + pass + +f.x = 0 +print(f.x) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_generator_noexit.py b/src/openmv/src/micropython/tests/cpydiff/core_generator_noexit.py new file mode 100755 index 0000000..c25fbe7 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_generator_noexit.py @@ -0,0 +1,24 @@ +""" +categories: Core,Generator +description: Context manager __exit__() not called in a generator which does not run to completion +cause: Unknown +workaround: Unknown +""" +class foo(object): + def __enter__(self): + print('Enter') + def __exit__(self, *args): + print('Exit') + +def bar(x): + with foo(): + while True: + x += 1 + yield x + +def func(): + g = bar(0) + for _ in range(3): + print(next(g)) + +func() diff --git a/src/openmv/src/micropython/tests/cpydiff/core_import_path.py b/src/openmv/src/micropython/tests/cpydiff/core_import_path.py new file mode 100755 index 0000000..04fc4bd --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_import_path.py @@ -0,0 +1,9 @@ +""" +categories: Core,import +description: __path__ attribute of a package has a different type (single string instead of list of strings) in MicroPython +cause: MicroPython does't support namespace packages split across filesystem. Beyond that, MicroPython's import system is highly optimized for minimal memory usage. +workaround: Details of import handling is inherently implementation dependent. Don't rely on such details in portable applications. +""" +import modules + +print(modules.__path__) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_import_prereg.py b/src/openmv/src/micropython/tests/cpydiff/core_import_prereg.py new file mode 100755 index 0000000..4a71217 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_import_prereg.py @@ -0,0 +1,17 @@ +""" +categories: Core,import +description: Failed to load modules are still registered as loaded +cause: To make module handling more efficient, it's not wrapped with exception handling. +workaround: Test modules before production use; during development, use ``del sys.modules["name"]``, or just soft or hard reset the board. +""" +import sys + +try: + from modules import foo +except NameError as e: + print(e) +try: + from modules import foo + print('Should not get here') +except NameError as e: + print(e) diff --git a/src/openmv/src/micropython/tests/cpydiff/core_import_split_ns_pkgs.py b/src/openmv/src/micropython/tests/cpydiff/core_import_split_ns_pkgs.py new file mode 100755 index 0000000..700620c --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_import_split_ns_pkgs.py @@ -0,0 +1,14 @@ +""" +categories: Core,import +description: MicroPython does't support namespace packages split across filesystem. +cause: MicroPython's import system is highly optimized for simplicity, minimal memory usage, and minimal filesystem search overhead. +workaround: Don't install modules belonging to the same namespace package in different directories. For MicroPython, it's recommended to have at most 3-component module search paths: for your current application, per-user (writable), system-wide (non-writable). +""" +import sys +sys.path.append(sys.path[1] + "/modules") +sys.path.append(sys.path[1] + "/modules2") + +import subpkg.foo +import subpkg.bar + +print("Two modules of a split namespace package imported") diff --git a/src/openmv/src/micropython/tests/cpydiff/core_locals.py b/src/openmv/src/micropython/tests/cpydiff/core_locals.py new file mode 100755 index 0000000..0240e5a --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_locals.py @@ -0,0 +1,11 @@ +""" +categories: Core,Runtime +description: Local variables aren't included in locals() result +cause: MicroPython doesn't maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can't be accessed by a name. +workaround: Unknown +""" +def test(): + val = 2 + print(locals()) + +test() diff --git a/src/openmv/src/micropython/tests/cpydiff/core_locals_eval.py b/src/openmv/src/micropython/tests/cpydiff/core_locals_eval.py new file mode 100755 index 0000000..8416e3b --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/core_locals_eval.py @@ -0,0 +1,14 @@ +""" +categories: Core,Runtime +description: Code running in eval() function doesn't have access to local variables +cause: MicroPython doesn't maintain symbolic local environment, it is optimized to an array of slots. Thus, local variables can't be accessed by a name. Effectively, ``eval(expr)`` in MicroPython is equivalent to ``eval(expr, globals(), globals())``. +workaround: Unknown +""" +val = 1 + +def test(): + val = 2 + print(val) + eval("print(val)") + +test() diff --git a/src/openmv/src/micropython/tests/cpydiff/modules/__init__.py b/src/openmv/src/micropython/tests/cpydiff/modules/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/cpydiff/modules/foo.py b/src/openmv/src/micropython/tests/cpydiff/modules/foo.py new file mode 100755 index 0000000..e6e33a7 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules/foo.py @@ -0,0 +1,2 @@ +print('foo') +xxx diff --git a/src/openmv/src/micropython/tests/cpydiff/modules/subpkg/foo.py b/src/openmv/src/micropython/tests/cpydiff/modules/subpkg/foo.py new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/cpydiff/modules2/subpkg/bar.py b/src/openmv/src/micropython/tests/cpydiff/modules2/subpkg/bar.py new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_array_containment.py b/src/openmv/src/micropython/tests/cpydiff/modules_array_containment.py new file mode 100755 index 0000000..190a3c2 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_array_containment.py @@ -0,0 +1,8 @@ +""" +categories: Modules,array +description: Looking for integer not implemented +cause: Unknown +workaround: Unknown +""" +import array +print(1 in array.array('B', b'12')) diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_array_deletion.py b/src/openmv/src/micropython/tests/cpydiff/modules_array_deletion.py new file mode 100755 index 0000000..97f988d --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_array_deletion.py @@ -0,0 +1,10 @@ +""" +categories: Modules,array +description: Array deletion not implemented +cause: Unknown +workaround: Unknown +""" +import array +a = array.array('b', (1, 2, 3)) +del a[1] +print(a) diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_array_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/modules_array_subscrstep.py new file mode 100755 index 0000000..1103f18 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_array_subscrstep.py @@ -0,0 +1,9 @@ +""" +categories: Modules,array +description: Subscript with step != 1 is not yet implemented +cause: Unknown +workaround: Unknown +""" +import array +a = array.array('b', (1, 2, 3)) +print(a[3:2:2]) diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_deque.py b/src/openmv/src/micropython/tests/cpydiff/modules_deque.py new file mode 100755 index 0000000..a503ea4 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_deque.py @@ -0,0 +1,9 @@ +""" +categories: Modules,deque +description: Deque not implemented +cause: Unknown +workaround: Use regular lists. micropython-lib has implementation of collections.deque. +""" +import collections +D = collections.deque() +print(D) diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_json_nonserializable.py b/src/openmv/src/micropython/tests/cpydiff/modules_json_nonserializable.py new file mode 100755 index 0000000..913b734 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_json_nonserializable.py @@ -0,0 +1,14 @@ +""" +categories: Modules,json +description: JSON module does not throw exception when object is not serialisable +cause: Unknown +workaround: Unknown +""" +import json +a = bytes(x for x in range(256)) +try: + z = json.dumps(a) + x = json.loads(z) + print('Should not get here') +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_struct_fewargs.py b/src/openmv/src/micropython/tests/cpydiff/modules_struct_fewargs.py new file mode 100755 index 0000000..08d32ca --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_struct_fewargs.py @@ -0,0 +1,12 @@ +""" +categories: Modules,struct +description: Struct pack with too few args, not checked by uPy +cause: Unknown +workaround: Unknown +""" +import struct +try: + print(struct.pack('bb', 1)) + print('Should not get here') +except: + print('struct.error') diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_struct_manyargs.py b/src/openmv/src/micropython/tests/cpydiff/modules_struct_manyargs.py new file mode 100755 index 0000000..cdbb5c6 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_struct_manyargs.py @@ -0,0 +1,12 @@ +""" +categories: Modules,struct +description: Struct pack with too many args, not checked by uPy +cause: Unknown +workaround: Unknown +""" +import struct +try: + print(struct.pack('bb', 1, 2, 3)) + print('Should not get here') +except: + print('struct.error') diff --git a/src/openmv/src/micropython/tests/cpydiff/modules_sys_stdassign.py b/src/openmv/src/micropython/tests/cpydiff/modules_sys_stdassign.py new file mode 100755 index 0000000..1bf2a59 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/modules_sys_stdassign.py @@ -0,0 +1,9 @@ +""" +categories: Modules,sys +description: Overriding sys.stdin, sys.stdout and sys.stderr not possible +cause: They are stored in read-only memory. +workaround: Unknown +""" +import sys +sys.stdin = None +print(sys.stdin) diff --git a/src/openmv/src/micropython/tests/cpydiff/syntax_spaces.py b/src/openmv/src/micropython/tests/cpydiff/syntax_spaces.py new file mode 100755 index 0000000..8578a51 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/syntax_spaces.py @@ -0,0 +1,18 @@ +""" +categories: Syntax,Spaces +description: uPy requires spaces between literal numbers and keywords, CPy doesn't +cause: Unknown +workaround: Unknown +""" +try: + print(eval('1and 0')) +except SyntaxError: + print('Should have worked') +try: + print(eval('1or 0')) +except SyntaxError: + print('Should have worked') +try: + print(eval('1if 1else 0')) +except SyntaxError: + print('Should have worked') diff --git a/src/openmv/src/micropython/tests/cpydiff/syntax_unicode_nameesc.py b/src/openmv/src/micropython/tests/cpydiff/syntax_unicode_nameesc.py new file mode 100755 index 0000000..21628c9 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/syntax_unicode_nameesc.py @@ -0,0 +1,7 @@ +""" +categories: Syntax,Unicode +description: Unicode name escapes are not implemented +cause: Unknown +workaround: Unknown +""" +print("\N{LATIN SMALL LETTER A}") diff --git a/src/openmv/src/micropython/tests/cpydiff/types_bytearray_sliceassign.py b/src/openmv/src/micropython/tests/cpydiff/types_bytearray_sliceassign.py new file mode 100755 index 0000000..e4068b0 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_bytearray_sliceassign.py @@ -0,0 +1,9 @@ +""" +categories: Types,bytearray +description: Array slice assignment with unsupported RHS +cause: Unknown +workaround: Unknown +""" +b = bytearray(4) +b[0:1] = [1, 2] +print(b) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_bytes_format.py b/src/openmv/src/micropython/tests/cpydiff/types_bytes_format.py new file mode 100755 index 0000000..697ee52 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_bytes_format.py @@ -0,0 +1,7 @@ +""" +categories: Types,bytes +description: bytes objects support .format() method +cause: MicroPython strives to be a more regular implementation, so if both `str` and `bytes` support ``__mod__()`` (the % operator), it makes sense to support ``format()`` for both too. Support for ``__mod__`` can also be compiled out, which leaves only ``format()`` for bytes formatting. +workaround: If you are interested in CPython compatibility, don't use ``.format()`` on bytes objects. +""" +print(b'{}'.format(1)) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_bytes_keywords.py b/src/openmv/src/micropython/tests/cpydiff/types_bytes_keywords.py new file mode 100755 index 0000000..4dc383f --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_bytes_keywords.py @@ -0,0 +1,7 @@ +""" +categories: Types,bytes +description: bytes() with keywords not implemented +cause: Unknown +workaround: Pass the encoding as a positional paramter, e.g. ``print(bytes('abc', 'utf-8'))`` +""" +print(bytes('abc', encoding='utf8')) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_bytes_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/types_bytes_subscrstep.py new file mode 100755 index 0000000..2871bda --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_bytes_subscrstep.py @@ -0,0 +1,7 @@ +""" +categories: Types,bytes +description: Bytes subscription with step != 1 not implemented +cause: MicroPython is highly optimized for memory usage. +workaround: Use explicit loop for this very rare operation. +""" +print(b'123'[0:3:2]) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_exception_chaining.py b/src/openmv/src/micropython/tests/cpydiff/types_exception_chaining.py new file mode 100755 index 0000000..836c4eb --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_exception_chaining.py @@ -0,0 +1,10 @@ +""" +categories: Types,Exception +description: Exception chaining not implemented +cause: Unknown +workaround: Unknown +""" +try: + raise TypeError +except TypeError: + raise ValueError diff --git a/src/openmv/src/micropython/tests/cpydiff/types_exception_instancevar.py b/src/openmv/src/micropython/tests/cpydiff/types_exception_instancevar.py new file mode 100755 index 0000000..adc3533 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_exception_instancevar.py @@ -0,0 +1,9 @@ +""" +categories: Types,Exception +description: User-defined attributes for builtin exceptions are not supported +cause: MicroPython is highly optimized for memory usage. +workaround: Use user-defined exception subclasses. +""" +e = Exception() +e.x = 0 +print(e.x) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_exception_loops.py b/src/openmv/src/micropython/tests/cpydiff/types_exception_loops.py new file mode 100755 index 0000000..8d326cb --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_exception_loops.py @@ -0,0 +1,12 @@ +""" +categories: Types,Exception +description: Exception in while loop condition may have unexpected line number +cause: Condition checks are optimized to happen at the end of loop body, and that line number is reported. +workaround: Unknown +""" +l = ["-foo", "-bar"] + +i = 0 +while l[i][0] == "-": + print("iter") + i += 1 diff --git a/src/openmv/src/micropython/tests/cpydiff/types_exception_subclassinit.py b/src/openmv/src/micropython/tests/cpydiff/types_exception_subclassinit.py new file mode 100755 index 0000000..39cdaf4 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_exception_subclassinit.py @@ -0,0 +1,15 @@ +""" +categories: Types,Exception +description: Exception.__init__ method does not exist. +cause: Subclassing native classes is not fully supported in MicroPython. +workaround: Call using ``super()`` instead:: + + class A(Exception): + def __init__(self): + super().__init__() +""" +class A(Exception): + def __init__(self): + Exception.__init__(self) + +a = A() diff --git a/src/openmv/src/micropython/tests/cpydiff/types_float_rounding.py b/src/openmv/src/micropython/tests/cpydiff/types_float_rounding.py new file mode 100755 index 0000000..c8d3cfb --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_float_rounding.py @@ -0,0 +1,7 @@ +""" +categories: Types,float +description: uPy and CPython outputs formats may differ +cause: Unknown +workaround: Unknown +""" +print('%.1g' % -9.9) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_int_subclassconv.py b/src/openmv/src/micropython/tests/cpydiff/types_int_subclassconv.py new file mode 100755 index 0000000..260b060 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_int_subclassconv.py @@ -0,0 +1,11 @@ +""" +categories: Types,int +description: No int conversion for int-derived types available +cause: Unknown +workaround: Avoid subclassing builtin types unless really needed. Prefer https://en.wikipedia.org/wiki/Composition_over_inheritance . +""" +class A(int): + __add__ = lambda self, other: A(int(self) + other) + +a = A(42) +print(a+a) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_list_delete_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/types_list_delete_subscrstep.py new file mode 100755 index 0000000..36e6f52 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_list_delete_subscrstep.py @@ -0,0 +1,9 @@ +""" +categories: Types,list +description: List delete with step != 1 not implemented +cause: Unknown +workaround: Use explicit loop for this rare operation. +""" +l = [1, 2, 3, 4] +del l[0:4:2] +print(l) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_list_store_noniter.py b/src/openmv/src/micropython/tests/cpydiff/types_list_store_noniter.py new file mode 100755 index 0000000..1d69b4a --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_list_store_noniter.py @@ -0,0 +1,9 @@ +""" +categories: Types,list +description: List slice-store with non-iterable on RHS is not implemented +cause: RHS is restricted to be a tuple or list +workaround: Use ``list()`` on RHS to convert the iterable to a list +""" +l = [10, 20] +l[0:1] = range(4) +print(l) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_list_store_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/types_list_store_subscrstep.py new file mode 100755 index 0000000..1460372 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_list_store_subscrstep.py @@ -0,0 +1,9 @@ +""" +categories: Types,list +description: List store with step != 1 not implemented +cause: Unknown +workaround: Use explicit loop for this rare operation. +""" +l = [1, 2, 3, 4] +l[0:4:2] = [5, 6] +print(l) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_endswith.py b/src/openmv/src/micropython/tests/cpydiff/types_str_endswith.py new file mode 100755 index 0000000..ac2600b --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_endswith.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: Start/end indices such as str.endswith(s, start) not implemented +cause: Unknown +workaround: Unknown +""" +print('abc'.endswith('c', 1)) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_formatsubscr.py b/src/openmv/src/micropython/tests/cpydiff/types_str_formatsubscr.py new file mode 100755 index 0000000..dd1d8d3 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_formatsubscr.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: Attributes/subscr not implemented +cause: Unknown +workaround: Unknown +""" +print('{a[0]}'.format(a=[1, 2])) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_keywords.py b/src/openmv/src/micropython/tests/cpydiff/types_str_keywords.py new file mode 100755 index 0000000..b336b1a --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_keywords.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: str(...) with keywords not implemented +cause: Unknown +workaround: Input the encoding format directly. eg ``print(bytes('abc', 'utf-8'))`` +""" +print(str(b'abc', encoding='utf8')) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_ljust_rjust.py b/src/openmv/src/micropython/tests/cpydiff/types_str_ljust_rjust.py new file mode 100755 index 0000000..fa3f594 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_ljust_rjust.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: str.ljust() and str.rjust() not implemented +cause: MicroPython is highly optimized for memory usage. Easy workarounds available. +workaround: Instead of ``s.ljust(10)`` use ``"%-10s" % s``, instead of ``s.rjust(10)`` use ``"% 10s" % s``. Alternatively, ``"{:<10}".format(s)`` or ``"{:>10}".format(s)``. +""" +print('abc'.ljust(10)) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_rsplitnone.py b/src/openmv/src/micropython/tests/cpydiff/types_str_rsplitnone.py new file mode 100755 index 0000000..cadf869 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_rsplitnone.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: None as first argument for rsplit such as str.rsplit(None, n) not implemented +cause: Unknown +workaround: Unknown +""" +print('a a a'.rsplit(None, 1)) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_subclassequality.py b/src/openmv/src/micropython/tests/cpydiff/types_str_subclassequality.py new file mode 100755 index 0000000..8aec1ea --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_subclassequality.py @@ -0,0 +1,11 @@ +""" +categories: Types,str +description: Instance of a subclass of str cannot be compared for equality with an instance of a str +cause: Unknown +workaround: Unknown +""" +class S(str): + pass + +s = S('hello') +print(s == 'hello') diff --git a/src/openmv/src/micropython/tests/cpydiff/types_str_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/types_str_subscrstep.py new file mode 100755 index 0000000..0c2fce1 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_str_subscrstep.py @@ -0,0 +1,7 @@ +""" +categories: Types,str +description: Subscript with step != 1 is not yet implemented +cause: Unknown +workaround: Unknown +""" +print('abcdefghi'[0:9:2]) diff --git a/src/openmv/src/micropython/tests/cpydiff/types_tuple_subscrstep.py b/src/openmv/src/micropython/tests/cpydiff/types_tuple_subscrstep.py new file mode 100755 index 0000000..f90f3c5 --- /dev/null +++ b/src/openmv/src/micropython/tests/cpydiff/types_tuple_subscrstep.py @@ -0,0 +1,7 @@ +""" +categories: Types,tuple +description: Tuple load with step != 1 not implemented +cause: Unknown +workaround: Unknown +""" +print((1, 2, 3, 4)[0:4:2]) diff --git a/src/openmv/src/micropython/tests/extmod/btree1.py b/src/openmv/src/micropython/tests/extmod/btree1.py new file mode 100755 index 0000000..59638ef --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/btree1.py @@ -0,0 +1,89 @@ +try: + import btree + import uio + import uerrno +except ImportError: + print("SKIP") + raise SystemExit + +#f = open("_test.db", "w+b") +f = uio.BytesIO() +db = btree.open(f, pagesize=512) + +db[b"foo3"] = b"bar3" +db[b"foo1"] = b"bar1" +db[b"foo2"] = b"bar2" +db[b"bar1"] = b"foo1" + +dbstr = str(db) +print(dbstr[:7], dbstr[-1:]) + +print(db[b"foo2"]) +try: + print(db[b"foo"]) +except KeyError: + print("KeyError") +print(db.get(b"foo")) +print(db.get(b"foo", b"dflt")) + +del db[b"foo2"] +try: + del db[b"foo"] +except KeyError: + print("KeyError") + +for k, v in db.items(): + print((k, v)) + +print("---") +for k, v in db.items(None, None): + print((k, v)) + +print("---") +for k, v in db.items(b"f"): + print((k, v)) + +print("---") +for k, v in db.items(b"f", b"foo3"): + print((k, v)) + +print("---") +for k, v in db.items(None, b"foo3"): + print((k, v)) + +print("---") +for k, v in db.items(b"f", b"foo3", btree.INCL): + print((k, v)) + +print("---") +for k, v in db.items(None, None, btree.DESC): + print((k, v)) + +print(db.seq(1, b"foo1")) +print(db.seq(1, b"qux")) + +try: + db.seq(b"foo1") +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +print(list(db.keys())) +print(list(db.values())) + +for k in db: + print(k) + +db.put(b"baz1", b"qux1") + +print("foo1", "foo1" in db) +print("foo2", "foo2" in db) +print("baz1", "baz1" in db) + +try: + print(db + db[b"foo1"]) +except TypeError: + print("TypeError") + +db.flush() +db.close() +f.close() diff --git a/src/openmv/src/micropython/tests/extmod/btree1.py.exp b/src/openmv/src/micropython/tests/extmod/btree1.py.exp new file mode 100755 index 0000000..a467252 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/btree1.py.exp @@ -0,0 +1,40 @@ + +b'bar2' +KeyError +None +b'dflt' +KeyError +(b'bar1', b'foo1') +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'bar1', b'foo1') +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo1', b'bar1') +--- +(b'bar1', b'foo1') +(b'foo1', b'bar1') +--- +(b'foo1', b'bar1') +(b'foo3', b'bar3') +--- +(b'foo3', b'bar3') +(b'foo1', b'bar1') +(b'bar1', b'foo1') +(b'foo1', b'bar1') +None +True +[b'bar1', b'foo1', b'foo3'] +[b'foo1', b'bar1', b'bar3'] +b'bar1' +b'foo1' +b'foo3' +foo1 True +foo2 False +baz1 True +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/framebuf1.py b/src/openmv/src/micropython/tests/extmod/framebuf1.py new file mode 100755 index 0000000..2c13665 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf1.py @@ -0,0 +1,109 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +w = 5 +h = 16 +size = w * h // 8 +buf = bytearray(size) +maps = {framebuf.MONO_VLSB : 'MONO_VLSB', + framebuf.MONO_HLSB : 'MONO_HLSB', + framebuf.MONO_HMSB : 'MONO_HMSB'} + +for mapping in maps.keys(): + for x in range(size): + buf[x] = 0 + fbuf = framebuf.FrameBuffer(buf, w, h, mapping) + print(maps[mapping]) + # access as buffer + print(memoryview(fbuf)[0]) + + # fill + fbuf.fill(1) + print(buf) + fbuf.fill(0) + print(buf) + + # put pixel + fbuf.pixel(0, 0, 1) + fbuf.pixel(4, 0, 1) + fbuf.pixel(0, 15, 1) + fbuf.pixel(4, 15, 1) + print(buf) + + # clear pixel + fbuf.pixel(4, 15, 0) + print(buf) + + # get pixel + print(fbuf.pixel(0, 0), fbuf.pixel(1, 1)) + + # hline + fbuf.fill(0) + fbuf.hline(0, 1, w, 1) + print('hline', buf) + + # vline + fbuf.fill(0) + fbuf.vline(1, 0, h, 1) + print('vline', buf) + + # rect + fbuf.fill(0) + fbuf.rect(1, 1, 3, 3, 1) + print('rect', buf) + + #fill rect + fbuf.fill(0) + fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation + fbuf.fill_rect(1, 1, 3, 3, 1) + print('fill_rect', buf) + + # line + fbuf.fill(0) + fbuf.line(1, 1, 3, 3, 1) + print('line', buf) + + # line steep negative gradient + fbuf.fill(0) + fbuf.line(3, 3, 2, 1, 1) + print('line', buf) + + # scroll + fbuf.fill(0) + fbuf.pixel(2, 7, 1) + fbuf.scroll(0, 1) + print(buf) + fbuf.scroll(0, -2) + print(buf) + fbuf.scroll(1, 0) + print(buf) + fbuf.scroll(-1, 0) + print(buf) + fbuf.scroll(2, 2) + print(buf) + + # print text + fbuf.fill(0) + fbuf.text("hello", 0, 0, 1) + print(buf) + fbuf.text("hello", 0, 0, 0) # clear + print(buf) + + # char out of font range set to chr(127) + fbuf.text(str(chr(31)), 0, 0) + print(buf) + print() + +# test invalid constructor, and stride argument +try: + fbuf = framebuf.FrameBuffer(buf, w, h, -1, w) +except ValueError: + print("ValueError") + +# test legacy constructor +fbuf = framebuf.FrameBuffer1(buf, w, h) +fbuf = framebuf.FrameBuffer1(buf, w, h, w) +print(framebuf.MVLSB == framebuf.MONO_VLSB) diff --git a/src/openmv/src/micropython/tests/extmod/framebuf1.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf1.py.exp new file mode 100755 index 0000000..d954623 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf1.py.exp @@ -0,0 +1,68 @@ +MONO_VLSB +0 +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x80') +bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x00') +1 0 +hline bytearray(b'\x02\x02\x02\x02\x02\x00\x00\x00\x00\x00') +vline bytearray(b'\x00\xff\x00\x00\x00\x00\xff\x00\x00\x00') +rect bytearray(b'\x00\x0e\n\x0e\x00\x00\x00\x00\x00\x00') +fill_rect bytearray(b'\x00\x0e\x0e\x0e\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x02\x04\x08\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x00\x06\x08\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00') +bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00@\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') +bytearray(b'\x00\x7f\x7f\x04\x04\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\xaaU\xaaU\xaa\x00\x00\x00\x00\x00') + +MONO_HLSB +0 +bytearray(b'\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00') +1 0 +hline bytearray(b'\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00') +vline bytearray(b'@@@@@@@@@@') +rect bytearray(b'\x00pPp\x00\x00\x00\x00\x00\x00') +fill_rect bytearray(b'\x00ppp\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00@ \x10\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00 \x10\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00 \x00') +bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00') +bytearray(b'``x````\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'P\xa8P\xa8P\xa8P\xa8\x00\x00') + +MONO_HMSB +0 +bytearray(b'\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00') +1 0 +hline bytearray(b'\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00') +vline bytearray(b'\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02') +rect bytearray(b'\x00\x0e\n\x0e\x00\x00\x00\x00\x00\x00') +fill_rect bytearray(b'\x00\x0e\x0e\x0e\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x02\x04\x08\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x04\x04\x08\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00') +bytearray(b'\x06\x06\x1e\x06\x06\x06\x06\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\n\x15\n\x15\n\x15\n\x15\x00\x00') + +ValueError +True diff --git a/src/openmv/src/micropython/tests/extmod/framebuf16.py b/src/openmv/src/micropython/tests/extmod/framebuf16.py new file mode 100755 index 0000000..fe81f7f --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf16.py @@ -0,0 +1,59 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + print(buf[y * w * 2:(y + 1) * w * 2]) + print("-->8--") + +w = 4 +h = 5 +buf = bytearray(w * h * 2) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.RGB565) + +# fill +fbuf.fill(0xffff) +printbuf() +fbuf.fill(0x0000) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0xeeee) +fbuf.pixel(3, 0, 0xee00) +fbuf.pixel(0, 4, 0x00ee) +fbuf.pixel(3, 4, 0x0ee0) +printbuf() + +# get pixel +print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0x0000) +fbuf.pixel(2, 2, 0xffff) +printbuf() +fbuf.scroll(0, 1) +printbuf() +fbuf.scroll(1, 0) +printbuf() +fbuf.scroll(-1, -2) +printbuf() + +w2 = 2 +h2 = 3 +buf2 = bytearray(w2 * h2 * 2) +fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.RGB565) + +fbuf2.fill(0x0000) +fbuf2.pixel(0, 0, 0x0ee0) +fbuf2.pixel(0, 2, 0xee00) +fbuf2.pixel(1, 0, 0x00ee) +fbuf2.pixel(1, 2, 0xe00e) +fbuf.fill(0xffff) +fbuf.blit(fbuf2, 3, 3, 0x0000) +fbuf.blit(fbuf2, -1, -1, 0x0000) +fbuf.blit(fbuf2, 16, 16, 0x0000) +printbuf() diff --git a/src/openmv/src/micropython/tests/extmod/framebuf16.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf16.py.exp new file mode 100755 index 0000000..c41dc19 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf16.py.exp @@ -0,0 +1,57 @@ +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\xee\xee\x00\x00\x00\x00\x00\xee') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\xee\x00\x00\x00\x00\x00\xe0\x0e') +-->8-- +238 0 +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\xff\xff\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\x0e\xe0\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xe0\x0e') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8-- diff --git a/src/openmv/src/micropython/tests/extmod/framebuf2.py b/src/openmv/src/micropython/tests/extmod/framebuf2.py new file mode 100755 index 0000000..a313170 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf2.py @@ -0,0 +1,62 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%u' % ((buf[(x + y * w) // 4] >> ((x & 3) << 1)) & 3), end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h // 4) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS2_HMSB) + +# fill +fbuf.fill(3) +printbuf() +fbuf.fill(0) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 1) +fbuf.pixel(3, 0, 2) +fbuf.pixel(0, 4, 3) +fbuf.pixel(3, 4, 2) +printbuf() + +# get pixel +print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0) +fbuf.pixel(2, 2, 3) +printbuf() +fbuf.scroll(0, 1) +printbuf() +fbuf.scroll(1, 0) +printbuf() +fbuf.scroll(-1, -2) +printbuf() + +w2 = 2 +h2 = 3 +buf2 = bytearray(w2 * h2 // 4) +fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.GS2_HMSB) + +# blit +fbuf2.fill(0) +fbuf2.pixel(0, 0, 1) +fbuf2.pixel(0, 2, 2) +fbuf2.pixel(1, 0, 1) +fbuf2.pixel(1, 2, 2) +fbuf.fill(3) +fbuf.blit(fbuf2, 3, 3, 0) +fbuf.blit(fbuf2, -1, -1, 0) +fbuf.blit(fbuf2, 16, 16, 0) +printbuf() diff --git a/src/openmv/src/micropython/tests/extmod/framebuf2.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf2.py.exp new file mode 100755 index 0000000..c53e518 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf2.py.exp @@ -0,0 +1,57 @@ +--8<-- +33333333 +33333333 +33333333 +33333333 +33333333 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00000000 +00000000 +-->8-- +--8<-- +10020000 +00000000 +00000000 +00000000 +30020000 +-->8-- +3 0 +--8<-- +00000000 +00000000 +00300000 +00000000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00300000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +00000000 +00300000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +33333333 +23333333 +33333333 +33311333 +33333333 +-->8-- diff --git a/src/openmv/src/micropython/tests/extmod/framebuf4.py b/src/openmv/src/micropython/tests/extmod/framebuf4.py new file mode 100755 index 0000000..8358fa5 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf4.py @@ -0,0 +1,53 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + print(buf[y * w // 2:(y + 1) * w // 2]) + print("-->8--") + +w = 16 +h = 8 +buf = bytearray(w * h // 2) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS4_HMSB) + +# fill +fbuf.fill(0x0f) +printbuf() +fbuf.fill(0xa0) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0x01) +printbuf() +fbuf.pixel(w-1, 0, 0x02) +printbuf() +fbuf.pixel(w-1, h-1, 0x03) +printbuf() +fbuf.pixel(0, h-1, 0x04) +printbuf() + +# get pixel +print(fbuf.pixel(0, 0), fbuf.pixel(w-1, 0), fbuf.pixel(w-1, h-1), fbuf.pixel(0, h-1)) +print(fbuf.pixel(1, 0), fbuf.pixel(w-2, 0), fbuf.pixel(w-2, h-1), fbuf.pixel(1, h-1)) + +# fill rect +fbuf.fill_rect(0, 0, w, h, 0x0f) +printbuf() +fbuf.fill_rect(0, 0, w, h, 0xf0) +fbuf.fill_rect(1, 0, w//2+1, 1, 0xf1) +printbuf() +fbuf.fill_rect(1, 0, w//2+1, 1, 0x10) +fbuf.fill_rect(1, 0, w//2, 1, 0xf1) +printbuf() +fbuf.fill_rect(1, 0, w//2, 1, 0x10) +fbuf.fill_rect(0, h-4, w//2+1, 4, 0xaf) +printbuf() +fbuf.fill_rect(0, h-4, w//2+1, 4, 0xb0) +fbuf.fill_rect(0, h-4, w//2, 4, 0xaf) +printbuf() +fbuf.fill_rect(0, h-4, w//2, 4, 0xb0) diff --git a/src/openmv/src/micropython/tests/extmod/framebuf4.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf4.py.exp new file mode 100755 index 0000000..0865470 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf4.py.exp @@ -0,0 +1,112 @@ +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x10\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x10\x00\x00\x00\x00\x00\x00\x02') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x10\x00\x00\x00\x00\x00\x00\x02') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x03') +-->8-- +--8<-- +bytearray(b'\x10\x00\x00\x00\x00\x00\x00\x02') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'@\x00\x00\x00\x00\x00\x00\x03') +-->8-- +1 2 3 4 +0 0 0 0 +--8<-- +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff') +-->8-- +--8<-- +bytearray(b'\x01\x11\x11\x11\x11\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x01\x11\x11\x11\x10\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\xf0\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\xf0\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\xf0\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\xf0\x00\x00\x00') +-->8-- +--8<-- +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\x00\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\x00\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\x00\x00\x00\x00') +bytearray(b'\xff\xff\xff\xff\x00\x00\x00\x00') +-->8-- diff --git a/src/openmv/src/micropython/tests/extmod/framebuf8.py b/src/openmv/src/micropython/tests/extmod/framebuf8.py new file mode 100755 index 0000000..b6899aa --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf8.py @@ -0,0 +1,32 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%02x' % buf[(x + y * w)], end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +# fill +fbuf.fill(0x55) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0x11) +fbuf.pixel(w - 1, 0, 0x22) +fbuf.pixel(0, h - 1, 0x33) +fbuf.pixel(w - 1, h - 1, 0xff) +printbuf() + +# get pixel +print(hex(fbuf.pixel(0, h - 1)), hex(fbuf.pixel(1, 1))) diff --git a/src/openmv/src/micropython/tests/extmod/framebuf8.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf8.py.exp new file mode 100755 index 0000000..01d8976 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf8.py.exp @@ -0,0 +1,15 @@ +--8<-- +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +-->8-- +--8<-- +1155555555555522 +5555555555555555 +5555555555555555 +5555555555555555 +33555555555555ff +-->8-- +0x33 0x55 diff --git a/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py b/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py new file mode 100755 index 0000000..6363c22 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py @@ -0,0 +1,20 @@ +# test subclassing framebuf.FrameBuffer + +try: + import framebuf +except ImportError: + print('SKIP') + raise SystemExit + +class FB(framebuf.FrameBuffer): + def __init__(self, n): + self.n = n + super().__init__(bytearray(2 * n * n), n, n, framebuf.RGB565) + + def foo(self): + self.hline(0, 2, self.n, 0x0304) + +fb = FB(n=3) +fb.pixel(0, 0, 0x0102) +fb.foo() +print(bytes(fb)) diff --git a/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py.exp b/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py.exp new file mode 100755 index 0000000..23d53cc --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/framebuf_subclass.py.exp @@ -0,0 +1 @@ +b'\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x03\x04\x03\x04\x03' diff --git a/src/openmv/src/micropython/tests/extmod/machine1.py b/src/openmv/src/micropython/tests/extmod/machine1.py new file mode 100755 index 0000000..6ff38cc --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine1.py @@ -0,0 +1,28 @@ +# test machine module + +try: + try: + import umachine as machine + except ImportError: + import machine + machine.mem8 +except: + print("SKIP") + raise SystemExit + +print(machine.mem8) + +try: + machine.mem16[1] +except ValueError: + print("ValueError") + +try: + machine.mem16[1] = 1 +except ValueError: + print("ValueError") + +try: + del machine.mem8[0] +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/extmod/machine1.py.exp b/src/openmv/src/micropython/tests/extmod/machine1.py.exp new file mode 100755 index 0000000..bb421ea --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine1.py.exp @@ -0,0 +1,4 @@ +<8-bit memory> +ValueError +ValueError +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/machine_pinbase.py b/src/openmv/src/micropython/tests/extmod/machine_pinbase.py new file mode 100755 index 0000000..e917755 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_pinbase.py @@ -0,0 +1,30 @@ +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase +except AttributeError: + print("SKIP") + raise SystemExit + + +class MyPin(machine.PinBase): + + def __init__(self): + print("__init__") + self.v = False + + def value(self, v=None): + print("value:", v) + if v is None: + self.v = not self.v + return int(self.v) + +p = MyPin() + +print(p.value()) +print(p.value()) +print(p.value()) +p.value(1) +p.value(0) diff --git a/src/openmv/src/micropython/tests/extmod/machine_pinbase.py.exp b/src/openmv/src/micropython/tests/extmod/machine_pinbase.py.exp new file mode 100755 index 0000000..b31cd98 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_pinbase.py.exp @@ -0,0 +1,9 @@ +__init__ +value: None +1 +value: None +0 +value: None +1 +value: 1 +value: 0 diff --git a/src/openmv/src/micropython/tests/extmod/machine_pulse.py b/src/openmv/src/micropython/tests/extmod/machine_pulse.py new file mode 100755 index 0000000..d525974 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_pulse.py @@ -0,0 +1,46 @@ +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase + machine.time_pulse_us +except AttributeError: + print("SKIP") + raise SystemExit + + +class ConstPin(machine.PinBase): + + def __init__(self, value): + self.v = value + + def value(self, v=None): + if v is None: + return self.v + else: + self.v = v + + +class TogglePin(machine.PinBase): + + def __init__(self): + self.v = 0 + + def value(self, v=None): + if v is None: + self.v = 1 - self.v + print("value:", self.v) + return self.v + + +p = TogglePin() + +t = machine.time_pulse_us(p, 1) +print(type(t)) +t = machine.time_pulse_us(p, 0) +print(type(t)) + +p = ConstPin(0) +print(machine.time_pulse_us(p, 1, 10)) +print(machine.time_pulse_us(p, 0, 10)) diff --git a/src/openmv/src/micropython/tests/extmod/machine_pulse.py.exp b/src/openmv/src/micropython/tests/extmod/machine_pulse.py.exp new file mode 100755 index 0000000..20d4c10 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_pulse.py.exp @@ -0,0 +1,9 @@ +value: 1 +value: 0 + +value: 1 +value: 0 +value: 1 + +-2 +-1 diff --git a/src/openmv/src/micropython/tests/extmod/machine_signal.py b/src/openmv/src/micropython/tests/extmod/machine_signal.py new file mode 100755 index 0000000..53f4f58 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_signal.py @@ -0,0 +1,39 @@ +# test machine.Signal class + +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase + machine.Signal +except AttributeError: + print("SKIP") + raise SystemExit + +class Pin(machine.PinBase): + def __init__(self): + self.v = 0 + + def value(self, v=None): + if v is None: + return self.v + else: + self.v = int(v) + + +# test non-inverted +p = Pin() +s = machine.Signal(p) +s.value(0) +print(p.value(), s.value()) +s.value(1) +print(p.value(), s.value()) + +# test inverted, and using on/off methods +p = Pin() +s = machine.Signal(p, invert=True) +s.off() +print(p.value(), s.value()) +s.on() +print(p.value(), s.value()) diff --git a/src/openmv/src/micropython/tests/extmod/machine_signal.py.exp b/src/openmv/src/micropython/tests/extmod/machine_signal.py.exp new file mode 100755 index 0000000..7e9dd67 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/machine_signal.py.exp @@ -0,0 +1,4 @@ +0 0 +1 1 +1 0 +0 1 diff --git a/src/openmv/src/micropython/tests/extmod/ticks_diff.py b/src/openmv/src/micropython/tests/extmod/ticks_diff.py new file mode 100755 index 0000000..4d8df83 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ticks_diff.py @@ -0,0 +1,33 @@ +from utime import ticks_diff, ticks_add + +MAX = ticks_add(0, -1) +# Should be done like this to avoid small int overflow +MODULO_HALF = MAX // 2 + 1 + +# Invariants: +# if ticks_diff(a, b) = c, +# then ticks_diff(b, a) = -c + +assert ticks_diff(1, 0) == 1, ticks_diff(1, 0) +assert ticks_diff(0, 1) == -1 + +assert ticks_diff(0, MAX) == 1 +assert ticks_diff(MAX, 0) == -1 + +assert ticks_diff(0, MAX - 1) == 2 + +# Maximum "positive" distance +assert ticks_diff(MODULO_HALF, 1) == MODULO_HALF - 1, ticks_diff(MODULO_HALF, 1) +# Step further, and it becomes a negative distance +assert ticks_diff(MODULO_HALF, 0) == -MODULO_HALF + +# Offsetting that in either direction doesn't affect the result +off = 100 +# Cheating and skipping to use ticks_add() when we know there's no wraparound +# Real apps should use always it. +assert ticks_diff(MODULO_HALF + off, 1 + off) == MODULO_HALF - 1 +assert ticks_diff(MODULO_HALF + off, 0 + off) == -MODULO_HALF +assert ticks_diff(MODULO_HALF - off, ticks_add(1, -off)) == MODULO_HALF - 1 +assert ticks_diff(MODULO_HALF - off, ticks_add(0, -off)) == -MODULO_HALF + +print("OK") diff --git a/src/openmv/src/micropython/tests/extmod/ticks_diff.py.exp b/src/openmv/src/micropython/tests/extmod/ticks_diff.py.exp new file mode 100755 index 0000000..d86bac9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ticks_diff.py.exp @@ -0,0 +1 @@ +OK diff --git a/src/openmv/src/micropython/tests/extmod/time_ms_us.py b/src/openmv/src/micropython/tests/extmod/time_ms_us.py new file mode 100755 index 0000000..135cf1e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/time_ms_us.py @@ -0,0 +1,22 @@ +import utime +try: + utime.sleep_ms +except AttributeError: + print("SKIP") + raise SystemExit + +utime.sleep_ms(1) +utime.sleep_us(1) + +t0 = utime.ticks_ms() +t1 = utime.ticks_ms() +print(0 <= utime.ticks_diff(t1, t0) <= 1) + +t0 = utime.ticks_us() +t1 = utime.ticks_us() +print(0 <= utime.ticks_diff(t1, t0) <= 500) + +# ticks_cpu may not be implemented, at least make sure it doesn't decrease +t0 = utime.ticks_cpu() +t1 = utime.ticks_cpu() +print(utime.ticks_diff(t1, t0) >= 0) diff --git a/src/openmv/src/micropython/tests/extmod/time_ms_us.py.exp b/src/openmv/src/micropython/tests/extmod/time_ms_us.py.exp new file mode 100755 index 0000000..b8ca7e7 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/time_ms_us.py.exp @@ -0,0 +1,3 @@ +True +True +True diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_a2b_base64.py b/src/openmv/src/micropython/tests/extmod/ubinascii_a2b_base64.py new file mode 100755 index 0000000..05a3169 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_a2b_base64.py @@ -0,0 +1,46 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +print(binascii.a2b_base64(b'')) +print(binascii.a2b_base64(b'Zg==')) +print(binascii.a2b_base64(b'Zm8=')) +print(binascii.a2b_base64(b'Zm9v')) +print(binascii.a2b_base64(b'Zm9vYg==')) +print(binascii.a2b_base64(b'Zm9vYmE=')) +print(binascii.a2b_base64(b'Zm9vYmFy')) + +print(binascii.a2b_base64(b'AAECAwQFBgc=')) +print(binascii.a2b_base64(b'CAkKCwwNDg8=')) +print(binascii.a2b_base64(b'f4D/')) +print(binascii.a2b_base64(b'f4D+')) # convert '+' +print(binascii.a2b_base64(b'MTIzNEFCQ0RhYmNk')) + +# Ignore invalid characters and pad sequences +print(binascii.a2b_base64(b'Zm9v\n')) +print(binascii.a2b_base64(b'Zm\x009v\n')) +print(binascii.a2b_base64(b'Zm9v==')) +print(binascii.a2b_base64(b'Zm9v===')) +print(binascii.a2b_base64(b'Zm9v===YmFy')) + +try: + print(binascii.a2b_base64(b'abc')) +except ValueError: + print("ValueError") +try: + print(binascii.a2b_base64(b'abcde=')) +except ValueError: + print("ValueError") +try: + print(binascii.a2b_base64(b'ab*d')) +except ValueError: + print("ValueError") +try: + print(binascii.a2b_base64(b'ab=cdef=')) +except ValueError: + print("ValueError") diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_b2a_base64.py b/src/openmv/src/micropython/tests/extmod/ubinascii_b2a_base64.py new file mode 100755 index 0000000..f4bb69f --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_b2a_base64.py @@ -0,0 +1,22 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +print(binascii.b2a_base64(b'')) +print(binascii.b2a_base64(b'f')) +print(binascii.b2a_base64(b'fo')) +print(binascii.b2a_base64(b'foo')) +print(binascii.b2a_base64(b'foob')) +print(binascii.b2a_base64(b'fooba')) +print(binascii.b2a_base64(b'foobar')) + +print(binascii.b2a_base64(b'\x00\x01\x02\x03\x04\x05\x06\x07')) +print(binascii.b2a_base64(b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f')) +print(binascii.b2a_base64(b'\x7f\x80\xff')) +print(binascii.b2a_base64(b'1234ABCDabcd')) +print(binascii.b2a_base64(b'\x00\x00>')) # convert into '+' diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_crc32.py b/src/openmv/src/micropython/tests/extmod/ubinascii_crc32.py new file mode 100755 index 0000000..89664a9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_crc32.py @@ -0,0 +1,24 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +try: + binascii.crc32 +except AttributeError: + print("SKIP") + raise SystemExit + +print(hex(binascii.crc32(b'The quick brown fox jumps over the lazy dog'))) +print(hex(binascii.crc32(b'\x00' * 32))) +print(hex(binascii.crc32(b'\xff' * 32))) +print(hex(binascii.crc32(bytes(range(32))))) + +print(hex(binascii.crc32(b' over the lazy dog', binascii.crc32(b'The quick brown fox jumps')))) +print(hex(binascii.crc32(b'\x00' * 16, binascii.crc32(b'\x00' * 16)))) +print(hex(binascii.crc32(b'\xff' * 16, binascii.crc32(b'\xff' * 16)))) +print(hex(binascii.crc32(bytes(range(16, 32)), binascii.crc32(bytes(range(16)))))) diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_hexlify.py b/src/openmv/src/micropython/tests/extmod/ubinascii_hexlify.py new file mode 100755 index 0000000..bc99287 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_hexlify.py @@ -0,0 +1,13 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +print(binascii.hexlify(b'\x00\x01\x02\x03\x04\x05\x06\x07')) +print(binascii.hexlify(b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f')) +print(binascii.hexlify(b'\x7f\x80\xff')) +print(binascii.hexlify(b'1234ABCDabcd')) diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py b/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py new file mode 100755 index 0000000..77084ec --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py @@ -0,0 +1,15 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +# two arguments supported in uPy but not CPython +a = binascii.hexlify(b'123', ':') +print(a) + +# zero length buffer +print(binascii.hexlify(b'', b':')) diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py.exp b/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py.exp new file mode 100755 index 0000000..a195d26 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_micropython.py.exp @@ -0,0 +1,2 @@ +b'31:32:33' +b'' diff --git a/src/openmv/src/micropython/tests/extmod/ubinascii_unhexlify.py b/src/openmv/src/micropython/tests/extmod/ubinascii_unhexlify.py new file mode 100755 index 0000000..865abfe --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ubinascii_unhexlify.py @@ -0,0 +1,23 @@ +try: + try: + import ubinascii as binascii + except ImportError: + import binascii +except ImportError: + print("SKIP") + raise SystemExit + +print(binascii.unhexlify(b'0001020304050607')) +print(binascii.unhexlify(b'08090a0b0c0d0e0f')) +print(binascii.unhexlify(b'7f80ff')) +print(binascii.unhexlify(b'313233344142434461626364')) + +try: + a = binascii.unhexlify(b'0') # odd buffer length +except ValueError: + print('ValueError') + +try: + a = binascii.unhexlify(b'gg') # digit not hex +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py new file mode 100755 index 0000000..4c5ea6a --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py @@ -0,0 +1,15 @@ +try: + from Crypto.Cipher import AES + aes = AES.new +except ImportError: + try: + from ucryptolib import aes + except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 4, 2, b"5678" * 4) +enc = crypto.encrypt(bytes(range(32))) +print(enc) +crypto = aes(b"1234" * 4, 2, b"5678" * 4) +print(crypto.decrypt(enc)) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py.exp new file mode 100755 index 0000000..cc73553 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_cbc.py.exp @@ -0,0 +1,2 @@ +b'\x1d\x84\xfa\xaa%\x0e9\x143\x8b6\xf8\xdf^yh\xd0\x94g\xf4\xcf\x1d\xa0I)\x8a\xa0\x00u0+C' +b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py new file mode 100755 index 0000000..89451b2 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py @@ -0,0 +1,15 @@ +try: + from Crypto.Cipher import AES + aes = AES.new +except ImportError: + try: + from ucryptolib import aes + except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 4, 1) +enc = crypto.encrypt(bytes(range(32))) +print(enc) +crypto = aes(b"1234" * 4, 1) +print(crypto.decrypt(enc)) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py.exp new file mode 100755 index 0000000..b0fd15b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb.py.exp @@ -0,0 +1,2 @@ +b'Iz\xfe9\x17\xac\xa4X\x12\x04\x10\xf5K~#\xc7\xac;\xf9\xc6E\xa8\xca~\xf1\xee\xd3f%\xf1\x8d\xfe' +b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py new file mode 100755 index 0000000..55b676d --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py @@ -0,0 +1,16 @@ +# This tests minimal configuration of ucrypto module, which is +# AES128 encryption (anything else, including AES128 decryption, +# is optional). +try: + from Crypto.Cipher import AES + aes = AES.new +except ImportError: + try: + from ucryptolib import aes + except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 4, 1) +enc = crypto.encrypt(bytes(range(32))) +print(enc) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py.exp new file mode 100755 index 0000000..9921d4b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_enc.py.exp @@ -0,0 +1 @@ +b'Iz\xfe9\x17\xac\xa4X\x12\x04\x10\xf5K~#\xc7\xac;\xf9\xc6E\xa8\xca~\xf1\xee\xd3f%\xf1\x8d\xfe' diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py new file mode 100755 index 0000000..88ccb02 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py @@ -0,0 +1,15 @@ +# Inplace operations (input and output buffer is the same) +try: + from ucryptolib import aes +except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 4, 1) +buf = bytearray(bytes(range(32))) +crypto.encrypt(buf, buf) +print(buf) + +crypto = aes(b"1234" * 4, 1) +crypto.decrypt(buf, buf) +print(buf) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py.exp new file mode 100755 index 0000000..b7f7bf5 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_inpl.py.exp @@ -0,0 +1,2 @@ +bytearray(b'Iz\xfe9\x17\xac\xa4X\x12\x04\x10\xf5K~#\xc7\xac;\xf9\xc6E\xa8\xca~\xf1\xee\xd3f%\xf1\x8d\xfe') +bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f') diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py new file mode 100755 index 0000000..ff832d7 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py @@ -0,0 +1,16 @@ +# Operations with pre-allocated output buffer +try: + from ucryptolib import aes +except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 4, 1) +enc = bytearray(32) +crypto.encrypt(bytes(range(32)), enc) +print(enc) + +crypto = aes(b"1234" * 4, 1) +dec = bytearray(32) +crypto.decrypt(enc, dec) +print(dec) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py.exp new file mode 100755 index 0000000..b7f7bf5 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes128_ecb_into.py.exp @@ -0,0 +1,2 @@ +bytearray(b'Iz\xfe9\x17\xac\xa4X\x12\x04\x10\xf5K~#\xc7\xac;\xf9\xc6E\xa8\xca~\xf1\xee\xd3f%\xf1\x8d\xfe') +bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f') diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py new file mode 100755 index 0000000..a907f26 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py @@ -0,0 +1,15 @@ +try: + from Crypto.Cipher import AES + aes = AES.new +except ImportError: + try: + from ucryptolib import aes + except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 8, 2, b"5678" * 4) +enc = crypto.encrypt(bytes(range(32))) +print(enc) +crypto = aes(b"1234" * 8, 2, b"5678" * 4) +print(crypto.decrypt(enc)) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py.exp new file mode 100755 index 0000000..51262db --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_cbc.py.exp @@ -0,0 +1,2 @@ +b'\xb4\x0b\xff\xdd\xfc\xb5\x03\x88[m\xc1\x01+:\x03M\x18\xb03\x0f\x971g\x10\xb1\x98>\x9b\x17\xb7-\xb2' +b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py new file mode 100755 index 0000000..326383a --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py @@ -0,0 +1,15 @@ +try: + from Crypto.Cipher import AES + aes = AES.new +except ImportError: + try: + from ucryptolib import aes + except ImportError: + print("SKIP") + raise SystemExit + +crypto = aes(b"1234" * 8, 1) +enc = crypto.encrypt(bytes(range(32))) +print(enc) +crypto = aes(b"1234" * 8, 1) +print(crypto.decrypt(enc)) diff --git a/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py.exp b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py.exp new file mode 100755 index 0000000..a00a4eb --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ucryptolib_aes256_ecb.py.exp @@ -0,0 +1,2 @@ +b'\xe2\xe0\xdd\xef\xc3\xcd\x88/!>\xf6\xa2\xef/\xd15z+`\xb2\xb2\xd7}!:V>\xeb\x19\xbf|\xea' +b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py b/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py new file mode 100755 index 0000000..6b4d3d7 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py @@ -0,0 +1,53 @@ +# This test checks previously known problem values for 32-bit ports. +# It's less useful for 64-bit ports. +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +buf = b"12345678abcd" +struct = uctypes.struct( + uctypes.addressof(buf), + {"f32": uctypes.UINT32 | 0, "f64": uctypes.UINT64 | 4}, + uctypes.LITTLE_ENDIAN +) + +struct.f32 = 0x7fffffff +print(buf) + +struct.f32 = 0x80000000 +print(buf) + +struct.f32 = 0xff010203 +print(buf) + +struct.f64 = 0x80000000 +print(buf) + +struct.f64 = 0x80000000 * 2 +print(buf) + +print("=") + +buf = b"12345678abcd" +struct = uctypes.struct( + uctypes.addressof(buf), + {"f32": uctypes.UINT32 | 0, "f64": uctypes.UINT64 | 4}, + uctypes.BIG_ENDIAN +) + +struct.f32 = 0x7fffffff +print(buf) + +struct.f32 = 0x80000000 +print(buf) + +struct.f32 = 0xff010203 +print(buf) + +struct.f64 = 0x80000000 +print(buf) + +struct.f64 = 0x80000000 * 2 +print(buf) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py.exp new file mode 100755 index 0000000..d1fc1fe --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_32bit_intbig.py.exp @@ -0,0 +1,11 @@ +b'\xff\xff\xff\x7f5678abcd' +b'\x00\x00\x00\x805678abcd' +b'\x03\x02\x01\xff5678abcd' +b'\x03\x02\x01\xff\x00\x00\x00\x80\x00\x00\x00\x00' +b'\x03\x02\x01\xff\x00\x00\x00\x00\x01\x00\x00\x00' += +b'\x7f\xff\xff\xff5678abcd' +b'\x80\x00\x00\x005678abcd' +b'\xff\x01\x02\x035678abcd' +b'\xff\x01\x02\x03\x00\x00\x00\x00\x80\x00\x00\x00' +b'\xff\x01\x02\x03\x00\x00\x00\x01\x00\x00\x00\x00' diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py new file mode 100755 index 0000000..6afa7e0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py @@ -0,0 +1,58 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + # arr is array at offset 0, of UINT8 elements, array size is 2 + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + # arr2 is array at offset 0, size 2, of structures defined recursively + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2), + + # aligned + "arr5": (uctypes.ARRAY | 0, uctypes.UINT32 | 1), + # unaligned + "arr6": (uctypes.ARRAY | 1, uctypes.UINT32 | 1), + + "arr7": (uctypes.ARRAY | 0, 1, {"l": uctypes.UINT32 | 0}), + "arr8": (uctypes.ARRAY | 1, 1, {"l": uctypes.UINT32 | 0}) +} + +data = bytearray(5) + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +# assign byte +S.arr[0] = 0x11 +print(hex(S.arr[0])) +assert hex(S.arr[0]) == "0x11" + +# assign word +S.arr3[0] = 0x2233 +print(hex(S.arr3[0])) +assert hex(S.arr3[0]) == "0x2233" + +# assign word, with index +S.arr3[1] = 0x4455 +print(hex(S.arr3[1])) +assert hex(S.arr3[1]) == "0x4455" + +# assign long, aligned +S.arr5[0] = 0x66778899 +print(hex(S.arr5[0])) +assert hex(S.arr5[0]) == "0x66778899" + +print(S.arr5[0] == S.arr7[0].l) +assert S.arr5[0] == S.arr7[0].l + + +# assign long, unaligned +S.arr6[0] = 0xAABBCCDD +print(hex(S.arr6[0])) +assert hex(S.arr6[0]) == "0xaabbccdd" + +print(S.arr6[0] == S.arr8[0].l) +assert S.arr6[0] == S.arr8[0].l + diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py.exp new file mode 100755 index 0000000..8d57bc8 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_le.py.exp @@ -0,0 +1,7 @@ +0x11 +0x2233 +0x4455 +0x66778899 +True +0xaabbccdd +True diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py new file mode 100755 index 0000000..a538bf9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py @@ -0,0 +1,89 @@ +import sys +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +if sys.byteorder != "little": + print("SKIP") + raise SystemExit + +desc = { + # arr is array at offset 0, of UINT8 elements, array size is 2 + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + # arr2 is array at offset 0, size 2, of structures defined recursively + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2), + + # aligned + "arr5": (uctypes.ARRAY | 0, uctypes.UINT32 | 1), + "arr7": (uctypes.ARRAY | 0, 1, {"l": uctypes.UINT32 | 0}), + + "arr8": (uctypes.ARRAY | 0, uctypes.INT8 | 1), + "arr9": (uctypes.ARRAY | 0, uctypes.INT16 | 1), + "arr10": (uctypes.ARRAY | 0, uctypes.INT32 | 1), + "arr11": (uctypes.ARRAY | 0, uctypes.INT64 | 1), + "arr12": (uctypes.ARRAY | 0, uctypes.UINT64| 1), + "arr13": (uctypes.ARRAY | 1, 1, {"l": {}}), +} + +data = bytearray(8) + +S = uctypes.struct(uctypes.addressof(data), desc) + +# assign byte +S.arr[0] = 0x11 +print(hex(S.arr[0])) +assert hex(S.arr[0]) == "0x11" + +# assign word +S.arr3[0] = 0x2233 +print(hex(S.arr3[0])) +assert hex(S.arr3[0]) == "0x2233" + +# assign word, with index +S.arr3[1] = 0x4455 +print(hex(S.arr3[1])) +assert hex(S.arr3[1]) == "0x4455" + +# assign long, aligned +S.arr5[0] = 0x66778899 +print(hex(S.arr5[0])) +assert hex(S.arr5[0]) == "0x66778899" + +print(S.arr5[0] == S.arr7[0].l) +assert S.arr5[0] == S.arr7[0].l + +# assign int8 +S.arr8[0] = 0x11 +print(hex(S.arr8[0])) +assert hex(S.arr8[0]) == "0x11" + +# assign int16 +S.arr9[0] = 0x1122 +print(hex(S.arr9[0])) +assert hex(S.arr9[0]) == "0x1122" + +# assign int32 +S.arr10[0] = 0x11223344 +print(hex(S.arr10[0])) +assert hex(S.arr10[0]) == "0x11223344" + +# index out of range +try: + print(S.arr8[2]) +except IndexError: + print("IndexError") + +# syntax error in descriptor +try: + S.arr13[0].l = 0x11 +except TypeError: + print("TypeError") + +# operation not supported +try: + S.arr13[0] = 0x11 +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py.exp new file mode 100755 index 0000000..9d67b1c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le.py.exp @@ -0,0 +1,11 @@ +0x11 +0x2233 +0x4455 +0x66778899 +True +0x11 +0x1122 +0x11223344 +IndexError +TypeError +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py new file mode 100755 index 0000000..84dfba0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py @@ -0,0 +1,43 @@ +import sys +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +if sys.byteorder != "little": + print("SKIP") + raise SystemExit + +desc = { + # arr is array at offset 0, of UINT8 elements, array size is 2 + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + # arr2 is array at offset 0, size 2, of structures defined recursively + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2), + + # aligned + "arr5": (uctypes.ARRAY | 0, uctypes.UINT32 | 1), + "arr7": (uctypes.ARRAY | 0, 1, {"l": uctypes.UINT32 | 0}), + + "arr8": (uctypes.ARRAY | 0, uctypes.INT8 | 1), + "arr9": (uctypes.ARRAY | 0, uctypes.INT16 | 1), + "arr10": (uctypes.ARRAY | 0, uctypes.INT32 | 1), + "arr11": (uctypes.ARRAY | 0, uctypes.INT64 | 1), + "arr12": (uctypes.ARRAY | 0, uctypes.UINT64| 1), + "arr13": (uctypes.ARRAY | 1, 1, {"l": {}}), +} + +data = bytearray(8) + +S = uctypes.struct(uctypes.addressof(data), desc) + +# assign int64 +S.arr11[0] = 0x11223344 +print(hex(S.arr11[0])) +assert hex(S.arr11[0]) == "0x11223344" + +# assign uint64 +S.arr12[0] = 0x11223344 +print(hex(S.arr12[0])) +assert hex(S.arr12[0]) == "0x11223344" diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py.exp new file mode 100755 index 0000000..0394e9a --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_array_assign_native_le_intbig.py.exp @@ -0,0 +1,2 @@ +0x11223344 +0x11223344 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py b/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py new file mode 100755 index 0000000..77c93c3 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py @@ -0,0 +1,22 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr2": (uctypes.ARRAY | 2, uctypes.INT8 | 2), +} + +data = bytearray(b"01234567") + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +# Arrays of UINT8 are accessed as bytearrays +print(S.arr) +# But not INT8, because value range is different +print(type(S.arr2)) + +# convert to buffer +print(bytearray(S)) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py.exp new file mode 100755 index 0000000..7c84edb --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_bytearray.py.exp @@ -0,0 +1,3 @@ +bytearray(b'01') + +bytearray(b'0123') diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py b/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py new file mode 100755 index 0000000..ab2535d --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py @@ -0,0 +1,10 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b'01234567') + +print(uctypes.bytes_at(uctypes.addressof(data), 4)) +print(uctypes.bytearray_at(uctypes.addressof(data), 4)) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py.exp new file mode 100755 index 0000000..e1ae4d0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_byteat.py.exp @@ -0,0 +1,2 @@ +b'0123' +bytearray(b'0123') diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_error.py b/src/openmv/src/micropython/tests/extmod/uctypes_error.py new file mode 100755 index 0000000..95ba0fa --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_error.py @@ -0,0 +1,37 @@ +# test general errors with uctypes + +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b"01234567") + +# del subscr not supported +S = uctypes.struct(uctypes.addressof(data), {}) +try: + del S[0] +except TypeError: + print('TypeError') + +# list is an invalid descriptor +S = uctypes.struct(uctypes.addressof(data), []) +try: + S.x +except TypeError: + print('TypeError') + +# can't access attribute with invalid descriptor +S = uctypes.struct(uctypes.addressof(data), {'x':[]}) +try: + S.x +except TypeError: + print('TypeError') + +# can't assign to aggregate +S = uctypes.struct(uctypes.addressof(data), {'x':(uctypes.ARRAY | 0, uctypes.INT8 | 2)}) +try: + S.x = 1 +except TypeError: + print('TypeError') diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_error.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_error.py.exp new file mode 100755 index 0000000..802c260 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_error.py.exp @@ -0,0 +1,4 @@ +TypeError +TypeError +TypeError +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_le.py new file mode 100755 index 0000000..7df5ac0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_le.py @@ -0,0 +1,91 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + "s0": uctypes.UINT16 | 0, + "sub": (0, { + "b0": uctypes.UINT8 | 0, + "b1": uctypes.UINT8 | 1, + }), + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + "bitf1": uctypes.BFUINT16 | 0 | 8 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + + "bf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf1": uctypes.BFUINT16 | 0 | 4 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf2": uctypes.BFUINT16 | 0 | 8 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf3": uctypes.BFUINT16 | 0 | 12 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + + "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), +} + +data = bytearray(b"01") + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +#print(S) +print(hex(S.s0)) +assert hex(S.s0) == "0x3130" +#print(S.sub.b0) +print(S.sub.b0, S.sub.b1) +assert S.sub.b0, S.sub.b1 == (0x30, 0x31) + +try: + S[0] + assert False, "Can't index struct" +except TypeError: + print("TypeError") + +print("arr:", S.arr[0], S.arr[1]) +assert (S.arr[0], S.arr[1]) == (0x30, 0x31) + +print("arr of struct:", S.arr2[0].b, S.arr2[1].b) +assert (S.arr2[0].b, S.arr2[1].b) == (0x30, 0x31) + + +try: + S.arr[2] + assert False, "Out of bounds index" +except IndexError: + print("IndexError") + +print("bf:", S.bitf0, S.bitf1) +assert (S.bitf0, S.bitf1) == (0x30, 0x31) + +print("bf 4bit:", S.bf3, S.bf2, S.bf1, S.bf0) +assert (S.bf3, S.bf2, S.bf1, S.bf0) == (3, 1, 3, 0) + + +# Write access + +S.sub.b0 = ord("2") +print(data) +assert bytes(data) == b"21" + +S.bf3 = 5 +print(data) +assert bytes(data) == b"2Q" + +desc2 = { + "bf8": uctypes.BFUINT8 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf32": uctypes.BFUINT32 | 0 | 20 << uctypes.BF_POS | 4 << uctypes.BF_LEN +} + +data2 = bytearray(b"0123") + +S2 = uctypes.struct(uctypes.addressof(data2), desc2, uctypes.LITTLE_ENDIAN) + +# bitfield using uint8 as base type +S2.bf8 = 5 +print(data2) +assert bytes(data2) == b"5123" + +# bitfield using uint32 as base type +S2.bf32 = 5 +print(data2) +assert bytes(data2) == b"51R3" diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_le.py.exp new file mode 100755 index 0000000..2598b4e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_le.py.exp @@ -0,0 +1,12 @@ +0x3130 +48 49 +TypeError +arr: 48 49 +arr of struct: 48 49 +IndexError +bf: 48 49 +bf 4bit: 3 1 3 0 +bytearray(b'21') +bytearray(b'2Q') +bytearray(b'5123') +bytearray(b'51R3') diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py b/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py new file mode 100755 index 0000000..84ff2b8 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py @@ -0,0 +1,24 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + "f32": uctypes.FLOAT32 | 0, + "f64": uctypes.FLOAT64 | 0, + "uf64": uctypes.FLOAT64 | 2, # unaligned +} + +data = bytearray(10) + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +S.f32 = 12.34 +print('%.4f' % S.f32) + +S.f64 = 12.34 +print('%.4f' % S.f64) + +S.uf64 = 12.34 +print('%.4f' % S.uf64) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py.exp new file mode 100755 index 0000000..a35a1da --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_le_float.py.exp @@ -0,0 +1,3 @@ +12.3400 +12.3400 +12.3400 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py b/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py new file mode 100755 index 0000000..acef470 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py @@ -0,0 +1,20 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + "f32": uctypes.FLOAT32 | 0, + "f64": uctypes.FLOAT64 | 0, +} + +data = bytearray(8) + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.NATIVE) + +S.f32 = 12.34 +print('%.4f' % S.f32) + +S.f64 = 12.34 +print('%.4f' % S.f64) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py.exp new file mode 100755 index 0000000..6abf0be --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_native_float.py.exp @@ -0,0 +1,2 @@ +12.3400 +12.3400 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py new file mode 100755 index 0000000..8bba03b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py @@ -0,0 +1,99 @@ +# This test is exactly like uctypes_le.py, but uses native structure layout. +# Codepaths for packed vs native structures are different. This test only works +# on little-endian machine (no matter if 32 or 64 bit). +import sys +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +if sys.byteorder != "little": + print("SKIP") + raise SystemExit + + +desc = { + "s0": uctypes.UINT16 | 0, + "sub": (0, { + "b0": uctypes.UINT8 | 0, + "b1": uctypes.UINT8 | 1, + }), + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + "bitf1": uctypes.BFUINT16 | 0 | 8 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + + "bf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf1": uctypes.BFUINT16 | 0 | 4 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf2": uctypes.BFUINT16 | 0 | 8 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf3": uctypes.BFUINT16 | 0 | 12 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + + "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), +} + +data = bytearray(b"01") + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.NATIVE) + +#print(S) +print(hex(S.s0)) +assert hex(S.s0) == "0x3130" +#print(S.sub.b0) +print(S.sub.b0, S.sub.b1) +assert S.sub.b0, S.sub.b1 == (0x30, 0x31) + +try: + S[0] + assert False, "Can't index struct" +except TypeError: + print("TypeError") + +print("arr:", S.arr[0], S.arr[1]) +assert (S.arr[0], S.arr[1]) == (0x30, 0x31) + +print("arr of struct:", S.arr2[0].b, S.arr2[1].b) +assert (S.arr2[0].b, S.arr2[1].b) == (0x30, 0x31) + + +try: + S.arr[2] + assert False, "Out of bounds index" +except IndexError: + print("IndexError") + +print("bf:", S.bitf0, S.bitf1) +assert (S.bitf0, S.bitf1) == (0x30, 0x31) + +print("bf 4bit:", S.bf3, S.bf2, S.bf1, S.bf0) +assert (S.bf3, S.bf2, S.bf1, S.bf0) == (3, 1, 3, 0) + +# Write access + +S.sub.b0 = ord("2") +print(data) +assert bytes(data) == b"21" + +S.bf3 = 5 +print(data) +assert bytes(data) == b"2Q" + +desc2 = { + "bf8": uctypes.BFUINT8 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + "bf32": uctypes.BFUINT32 | 0 | 20 << uctypes.BF_POS | 4 << uctypes.BF_LEN +} + +data2 = bytearray(b"0123") + +S2 = uctypes.struct(uctypes.addressof(data2), desc2, uctypes.NATIVE) + +# bitfield using uint8 as base type +S2.bf8 = 5 +print(data2) +assert bytes(data2) == b"5123" + +# bitfield using uint32 as base type +S2.bf32 = 5 +print(data2) +assert bytes(data2) == b"51R3" diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py.exp new file mode 100755 index 0000000..2598b4e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_native_le.py.exp @@ -0,0 +1,12 @@ +0x3130 +48 49 +TypeError +arr: 48 49 +arr of struct: 48 49 +IndexError +bf: 48 49 +bf 4bit: 3 1 3 0 +bytearray(b'21') +bytearray(b'2Q') +bytearray(b'5123') +bytearray(b'51R3') diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_print.py b/src/openmv/src/micropython/tests/extmod/uctypes_print.py new file mode 100755 index 0000000..c310238 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_print.py @@ -0,0 +1,25 @@ +# test printing of uctypes objects +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +# we use an address of "0" because we just want to print something deterministic +# and don't actually need to set/get any values in the struct + +desc = {"arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 1)} +S = uctypes.struct(0, desc) +print(S) + +desc2 = [(uctypes.ARRAY | 0, uctypes.UINT8 | 1)] +S2 = uctypes.struct(0, desc2) +print(S2) + +desc3 = ((uctypes.ARRAY | 0, uctypes.UINT8 | 1)) +S3 = uctypes.struct(0, desc3) +print(S3) + +desc4 = ((uctypes.PTR | 0, uctypes.UINT8 | 1)) +S4 = uctypes.struct(0, desc4) +print(S4) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_print.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_print.py.exp new file mode 100755 index 0000000..63daefc --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_print.py.exp @@ -0,0 +1,4 @@ + + + + diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py new file mode 100755 index 0000000..056e456 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py @@ -0,0 +1,34 @@ +import sys +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +if sys.byteorder != "little": + print("SKIP") + raise SystemExit + +desc = { + "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr16": (uctypes.PTR | 0, uctypes.UINT16), + "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), +} + +bytes = b"01" + +addr = uctypes.addressof(bytes) +buf = addr.to_bytes(uctypes.sizeof(desc), "little") + +S = uctypes.struct(uctypes.addressof(buf), desc, uctypes.LITTLE_ENDIAN) + +print(S.ptr[0]) +assert S.ptr[0] == ord("0") +print(S.ptr[1]) +assert S.ptr[1] == ord("1") +print(hex(S.ptr16[0])) +assert hex(S.ptr16[0]) == "0x3130" +print(S.ptr2[0].b, S.ptr2[1].b) +print (S.ptr2[0].b, S.ptr2[1].b) +print(hex(S.ptr16[0])) +assert (S.ptr2[0].b, S.ptr2[1].b) == (48, 49) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py.exp new file mode 100755 index 0000000..30d159e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_le.py.exp @@ -0,0 +1,6 @@ +48 +49 +0x3130 +48 49 +48 49 +0x3130 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py new file mode 100755 index 0000000..24508b1 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py @@ -0,0 +1,35 @@ +import sys +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +if sys.byteorder != "little": + print("SKIP") + raise SystemExit + + +desc = { + "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr16": (uctypes.PTR | 0, uctypes.UINT16), + "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), +} + +bytes = b"01" + +addr = uctypes.addressof(bytes) +buf = addr.to_bytes(uctypes.sizeof(desc), "little") + +S = uctypes.struct(uctypes.addressof(buf), desc, uctypes.NATIVE) + +print(S.ptr[0]) +assert S.ptr[0] == ord("0") +print(S.ptr[1]) +assert S.ptr[1] == ord("1") +print(hex(S.ptr16[0])) +assert hex(S.ptr16[0]) == "0x3130" +print(S.ptr2[0].b, S.ptr2[1].b) +print (S.ptr2[0].b, S.ptr2[1].b) +print(hex(S.ptr16[0])) +assert (S.ptr2[0].b, S.ptr2[1].b) == (48, 49) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py.exp new file mode 100755 index 0000000..30d159e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_ptr_native_le.py.exp @@ -0,0 +1,6 @@ +48 +49 +0x3130 +48 49 +48 49 +0x3130 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py new file mode 100755 index 0000000..e42e06c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py @@ -0,0 +1,47 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + # arr is array at offset 0, of UINT8 elements, array size is 2 + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + # arr2 is array at offset 0, size 2, of structures defined recursively + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2), + "arr4": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0, "w": uctypes.UINT16 | 1}), + "sub": (0, { + 'b1': uctypes.BFUINT8 | 0 | 4 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + 'b2': uctypes.BFUINT8 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + }), +} + +data = bytearray(b"01234567") + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +print(uctypes.sizeof(S.arr)) +assert uctypes.sizeof(S.arr) == 2 + +print(uctypes.sizeof(S.arr2)) +assert uctypes.sizeof(S.arr2) == 2 + +print(uctypes.sizeof(S.arr3)) + +try: + print(uctypes.sizeof(S.arr3[0])) +except TypeError: + print("TypeError") + +print(uctypes.sizeof(S.arr4)) +assert uctypes.sizeof(S.arr4) == 6 + +print(uctypes.sizeof(S.sub)) +assert uctypes.sizeof(S.sub) == 1 + +# invalid descriptor +try: + print(uctypes.sizeof([])) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py.exp new file mode 100755 index 0000000..b35b11a --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof.py.exp @@ -0,0 +1,7 @@ +2 +2 +4 +TypeError +6 +1 +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py new file mode 100755 index 0000000..1ba8871 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py @@ -0,0 +1,8 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +print(uctypes.sizeof({'f':uctypes.FLOAT32})) +print(uctypes.sizeof({'f':uctypes.FLOAT64})) diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py.exp new file mode 100755 index 0000000..de78180 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_float.py.exp @@ -0,0 +1,2 @@ +4 +8 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py new file mode 100755 index 0000000..2108e81 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py @@ -0,0 +1,27 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = { + "f1": 0 | uctypes.UINT32, + "f2": 4 | uctypes.UINT8, +} + + +# uctypes.NATIVE is default +print(uctypes.sizeof(desc) == uctypes.sizeof(desc, uctypes.NATIVE)) + +# Here we assume that that we run on a platform with convential ABI +# (which rounds up structure size based on max alignment). For platforms +# where that doesn't hold, this tests should be just disabled in the runner. +print(uctypes.sizeof(desc, uctypes.NATIVE) > uctypes.sizeof(desc, uctypes.LITTLE_ENDIAN)) + +# When taking sizeof of instantiated structure, layout type param +# is prohibited (because structure already has its layout type). +s = uctypes.struct(0, desc, uctypes.LITTLE_ENDIAN) +try: + uctypes.sizeof(s, uctypes.LITTLE_ENDIAN) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py.exp new file mode 100755 index 0000000..281f208 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_layout.py.exp @@ -0,0 +1,3 @@ +True +True +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_native.py b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_native.py new file mode 100755 index 0000000..32c740e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_native.py @@ -0,0 +1,57 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +S1 = {} +assert uctypes.sizeof(S1) == 0 + +S2 = {"a": uctypes.UINT8 | 0} +assert uctypes.sizeof(S2) == 1 + +S3 = { + "a": uctypes.UINT8 | 0, + "b": uctypes.UINT8 | 1, +} +assert uctypes.sizeof(S3) == 2 + +S4 = { + "a": uctypes.UINT8 | 0, + "b": uctypes.UINT32 | 4, + "c": uctypes.UINT8 | 8, +} +assert uctypes.sizeof(S4) == 12 + +S5 = { + "a": uctypes.UINT8 | 0, + "b": uctypes.UINT32 | 4, + "c": uctypes.UINT8 | 8, + "d": uctypes.UINT32 | 0, + "sub": (4, { + "b0": uctypes.UINT8 | 0, + "b1": uctypes.UINT8 | 1, + }), +} + +assert uctypes.sizeof(S5) == 12 + +s5 = uctypes.struct(0, S5) +assert uctypes.sizeof(s5) == 12 +assert uctypes.sizeof(s5.sub) == 2 + +S6 = { + "ptr": (uctypes.PTR | 0, uctypes.UINT8), +} +# As if there're no other arch bitnesses +assert uctypes.sizeof(S6) in (4, 8) + +S7 = { + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 5), +} +assert uctypes.sizeof(S7) == 5 + +S8 = { + "arr": (uctypes.ARRAY | 0, 3, {"a": uctypes.UINT32 | 0, "b": uctypes.UINT8 | 4}), +} +assert uctypes.sizeof(S8) == 24 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_native.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_native.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py new file mode 100755 index 0000000..192ee91 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py @@ -0,0 +1,48 @@ +try: + from ucollections import OrderedDict + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +desc = OrderedDict({ + # arr is array at offset 0, of UINT8 elements, array size is 2 + "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + # arr2 is array at offset 0, size 2, of structures defined recursively + "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr3": (uctypes.ARRAY | 2, uctypes.UINT16 | 2), + "arr4": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0, "w": uctypes.UINT16 | 1}), + "sub": (0, { + 'b1': uctypes.BFUINT8 | 0 | 4 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + 'b2': uctypes.BFUINT8 | 0 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN, + }), +}) + +data = bytearray(b"01234567") + +S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) + +print(uctypes.sizeof(S.arr)) +assert uctypes.sizeof(S.arr) == 2 + +print(uctypes.sizeof(S.arr2)) +assert uctypes.sizeof(S.arr2) == 2 + +print(uctypes.sizeof(S.arr3)) + +try: + print(uctypes.sizeof(S.arr3[0])) +except TypeError: + print("TypeError") + +print(uctypes.sizeof(S.arr4)) +assert uctypes.sizeof(S.arr4) == 6 + +print(uctypes.sizeof(S.sub)) +assert uctypes.sizeof(S.sub) == 1 + +# invalid descriptor +try: + print(uctypes.sizeof([])) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py.exp b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py.exp new file mode 100755 index 0000000..b35b11a --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uctypes_sizeof_od.py.exp @@ -0,0 +1,7 @@ +2 +2 +4 +TypeError +6 +1 +TypeError diff --git a/src/openmv/src/micropython/tests/extmod/uhashlib_md5.py b/src/openmv/src/micropython/tests/extmod/uhashlib_md5.py new file mode 100755 index 0000000..10b6d05 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uhashlib_md5.py @@ -0,0 +1,21 @@ +try: + import uhashlib as hashlib +except ImportError: + try: + import hashlib + except ImportError: + # This is neither uPy, nor cPy, so must be uPy with + # uhashlib module disabled. + print("SKIP") + raise SystemExit + +try: + hashlib.md5 +except AttributeError: + # MD5 is only available on some ports + print("SKIP") + raise SystemExit + +md5 = hashlib.md5(b'hello') +md5.update(b'world') +print(md5.digest()) diff --git a/src/openmv/src/micropython/tests/extmod/uhashlib_sha1.py b/src/openmv/src/micropython/tests/extmod/uhashlib_sha1.py new file mode 100755 index 0000000..4f70668 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uhashlib_sha1.py @@ -0,0 +1,21 @@ +try: + import uhashlib as hashlib +except ImportError: + try: + import hashlib + except ImportError: + # This is neither uPy, nor cPy, so must be uPy with + # uhashlib module disabled. + print("SKIP") + raise SystemExit + +try: + hashlib.sha1 +except AttributeError: + # SHA1 is only available on some ports + print("SKIP") + raise SystemExit + +sha1 = hashlib.sha1(b'hello') +sha1.update(b'world') +print(sha1.digest()) diff --git a/src/openmv/src/micropython/tests/extmod/uhashlib_sha256.py b/src/openmv/src/micropython/tests/extmod/uhashlib_sha256.py new file mode 100755 index 0000000..676d479 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uhashlib_sha256.py @@ -0,0 +1,38 @@ +try: + import uhashlib as hashlib +except ImportError: + try: + import hashlib + except ImportError: + # This is neither uPy, nor cPy, so must be uPy with + # uhashlib module disabled. + print("SKIP") + raise SystemExit + + +h = hashlib.sha256() +print(h.digest()) + +h = hashlib.sha256() +h.update(b"123") +print(h.digest()) + +h = hashlib.sha256() +h.update(b"abcd" * 1000) +print(h.digest()) + +print(hashlib.sha256(b"\xff" * 64).digest()) + +# 56 bytes is a boundary case in the algorithm +print(hashlib.sha256(b"\xff" * 56).digest()) + +# TODO: running .digest() several times in row is not supported() +#h = hashlib.sha256(b'123') +#print(h.digest()) +#print(h.digest()) + +# TODO: partial digests are not supported +#h = hashlib.sha256(b'123') +#print(h.digest()) +#h.update(b'456') +#print(h.digest()) diff --git a/src/openmv/src/micropython/tests/extmod/uheapq1.py b/src/openmv/src/micropython/tests/extmod/uheapq1.py new file mode 100755 index 0000000..7c1fe4e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uheapq1.py @@ -0,0 +1,40 @@ +try: + import uheapq as heapq +except: + try: + import heapq + except ImportError: + print("SKIP") + raise SystemExit + +try: + heapq.heappop([]) +except IndexError: + print("IndexError") + +try: + heapq.heappush((), 1) +except TypeError: + print("TypeError") + +def pop_and_print(h): + l = [] + while h: + l.append(str(heapq.heappop(h))) + print(' '.join(l)) + +h = [] +heapq.heappush(h, 3) +heapq.heappush(h, 1) +heapq.heappush(h, 2) +print(h) +pop_and_print(h) + +h = [4, 3, 8, 9, 10, 2, 7, 11, 5] +heapq.heapify(h) +print(h) +heapq.heappush(h, 1) +heapq.heappush(h, 6) +heapq.heappush(h, 12) +print(h) +pop_and_print(h) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dump.py b/src/openmv/src/micropython/tests/extmod/ujson_dump.py new file mode 100755 index 0000000..b1cb4a9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dump.py @@ -0,0 +1,30 @@ +try: + from uio import StringIO + import ujson as json +except: + try: + from io import StringIO + import json + except ImportError: + print("SKIP") + raise SystemExit + +s = StringIO() +json.dump(False, s) +print(s.getvalue()) + +s = StringIO() +json.dump({"a": (2, [3, None])}, s) +print(s.getvalue()) + +# dump to a small-int not allowed +try: + json.dump(123, 1) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') + +# dump to an object not allowed +try: + json.dump(123, {}) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dump_iobase.py b/src/openmv/src/micropython/tests/extmod/ujson_dump_iobase.py new file mode 100755 index 0000000..51d507c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dump_iobase.py @@ -0,0 +1,33 @@ +# test ujson.dump in combination with uio.IOBase + +try: + import uio as io + import ujson as json +except ImportError: + try: + import io, json + except ImportError: + print('SKIP') + raise SystemExit + +if not hasattr(io, 'IOBase'): + print('SKIP') + raise SystemExit + + +# a user stream that only has the write method +class S(io.IOBase): + def __init__(self): + self.buf = '' + def write(self, buf): + if type(buf) == bytearray: + # uPy passes a bytearray, CPython passes a str + buf = str(buf, 'ascii') + self.buf += buf + return len(buf) + + +# dump to the user stream +s = S() +json.dump([123, {}], s) +print(s.buf) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dumps.py b/src/openmv/src/micropython/tests/extmod/ujson_dumps.py new file mode 100755 index 0000000..d732718 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dumps.py @@ -0,0 +1,28 @@ +try: + import ujson as json +except ImportError: + try: + import json + except ImportError: + print("SKIP") + raise SystemExit + +print(json.dumps(False)) +print(json.dumps(True)) +print(json.dumps(None)) +print(json.dumps(1)) +print(json.dumps('abc')) +print(json.dumps('\x00\x01\x7e')) +print(json.dumps([])) +print(json.dumps([1])) +print(json.dumps([1, 2])) +print(json.dumps([1, True])) +print(json.dumps(())) +print(json.dumps((1,))) +print(json.dumps((1, 2))) +print(json.dumps((1, (2, 3)))) +print(json.dumps({})) +print(json.dumps({"a":1})) +print(json.dumps({"a":(2,[3,None])})) +print(json.dumps('"quoted"')) +print(json.dumps('space\n\r\tspace')) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py b/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py new file mode 100755 index 0000000..21a388c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py @@ -0,0 +1,9 @@ +# test uPy ujson behaviour that's not valid in CPy + +try: + import ujson +except ImportError: + print("SKIP") + raise SystemExit + +print(ujson.dumps(b'1234')) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py.exp b/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py.exp new file mode 100755 index 0000000..51712af --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dumps_extra.py.exp @@ -0,0 +1 @@ +"1234" diff --git a/src/openmv/src/micropython/tests/extmod/ujson_dumps_float.py b/src/openmv/src/micropython/tests/extmod/ujson_dumps_float.py new file mode 100755 index 0000000..e8cceb6 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_dumps_float.py @@ -0,0 +1,10 @@ +try: + import ujson as json +except ImportError: + try: + import json + except ImportError: + print("SKIP") + raise SystemExit + +print(json.dumps(1.2)) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_load.py b/src/openmv/src/micropython/tests/extmod/ujson_load.py new file mode 100755 index 0000000..9725ab2 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_load.py @@ -0,0 +1,15 @@ +try: + from uio import StringIO + import ujson as json +except: + try: + from io import StringIO + import json + except ImportError: + print("SKIP") + raise SystemExit + +print(json.load(StringIO('null'))) +print(json.load(StringIO('"abc\\u0064e"'))) +print(json.load(StringIO('[false, true, 1, -2]'))) +print(json.load(StringIO('{"a":true}'))) diff --git a/src/openmv/src/micropython/tests/extmod/ujson_loads.py b/src/openmv/src/micropython/tests/extmod/ujson_loads.py new file mode 100755 index 0000000..adba3c0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_loads.py @@ -0,0 +1,74 @@ +try: + import ujson as json +except ImportError: + try: + import json + except ImportError: + print("SKIP") + raise SystemExit + +def my_print(o): + if isinstance(o, dict): + print('sorted dict', sorted(o.items())) + else: + print(o) + +my_print(json.loads('null')) +my_print(json.loads('false')) +my_print(json.loads('true')) +my_print(json.loads('1')) +my_print(json.loads('-2')) +my_print(json.loads('"abc\\u0064e"')) +my_print(json.loads('[]')) +my_print(json.loads('[null]')) +my_print(json.loads('[null,false,true]')) +my_print(json.loads(' [ null , false , true ] ')) +my_print(json.loads('{}')) +my_print(json.loads('{"a":true}')) +my_print(json.loads('{"a":null, "b":false, "c":true}')) +my_print(json.loads('{"a":[], "b":[1], "c":{"3":4}}')) +my_print(json.loads('"abc\\bdef"')) +my_print(json.loads('"abc\\fdef"')) +my_print(json.loads('"abc\\ndef"')) +my_print(json.loads('"abc\\rdef"')) +my_print(json.loads('"abc\\tdef"')) +my_print(json.loads('"abc\\uabcd"')) + +# whitespace handling +my_print(json.loads('{\n\t"a":[]\r\n, "b":[1], "c":{"3":4} \n\r\t\r\r\r\n}')) + +# loading nothing should raise exception +try: + json.loads('') +except ValueError: + print('ValueError') + +# string which is not closed +try: + my_print(json.loads('"abc')) +except ValueError: + print('ValueError') + +# unaccompanied closing brace +try: + my_print(json.loads(']')) +except ValueError: + print('ValueError') + +# unspecified object type +try: + my_print(json.loads('a')) +except ValueError: + print('ValueError') + +# bad property name +try: + my_print(json.loads('{{}:"abc"}')) +except ValueError: + print('ValueError') + +# unexpected characters after white space +try: + my_print(json.loads('[null] a')) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/extmod/ujson_loads_float.py b/src/openmv/src/micropython/tests/extmod/ujson_loads_float.py new file mode 100755 index 0000000..f1b8cc3 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ujson_loads_float.py @@ -0,0 +1,17 @@ +try: + import ujson as json +except ImportError: + try: + import json + except ImportError: + print("SKIP") + raise SystemExit + +def my_print(o): + print('%.3f' % o) + +my_print(json.loads('1.2')) +my_print(json.loads('1e2')) +my_print(json.loads('-2.3')) +my_print(json.loads('-2e3')) +my_print(json.loads('-2e-3')) diff --git a/src/openmv/src/micropython/tests/extmod/urandom_basic.py b/src/openmv/src/micropython/tests/extmod/urandom_basic.py new file mode 100755 index 0000000..57e6b26 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/urandom_basic.py @@ -0,0 +1,29 @@ +try: + import urandom as random +except ImportError: + try: + import random + except ImportError: + print("SKIP") + raise SystemExit + +# check getrandbits returns a value within the bit range +for b in (1, 2, 3, 4, 16, 32): + for i in range(50): + assert random.getrandbits(b) < (1 << b) + +# check that seed(0) gives a non-zero value +random.seed(0) +print(random.getrandbits(16) != 0) + +# check that PRNG is repeatable +random.seed(1) +r = random.getrandbits(16) +random.seed(1) +print(random.getrandbits(16) == r) + +# check that it throws an error for zero bits +try: + random.getrandbits(0) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/extmod/urandom_extra.py b/src/openmv/src/micropython/tests/extmod/urandom_extra.py new file mode 100755 index 0000000..0cfd928 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/urandom_extra.py @@ -0,0 +1,69 @@ +try: + import urandom as random +except ImportError: + try: + import random + except ImportError: + print("SKIP") + raise SystemExit + +try: + random.randint +except AttributeError: + print('SKIP') + raise SystemExit + +print('randrange') +for i in range(50): + assert 0 <= random.randrange(4) < 4 + assert 2 <= random.randrange(2, 6) < 6 + assert -2 <= random.randrange(-2, 2) < 2 + assert random.randrange(1, 9, 2) in (1, 3, 5, 7) + assert random.randrange(2, 1, -1) in (1, 2) + +# empty range +try: + random.randrange(0) +except ValueError: + print('ValueError') + +# empty range +try: + random.randrange(2, 1) +except ValueError: + print('ValueError') + +# zero step +try: + random.randrange(2, 1, 0) +except ValueError: + print('ValueError') + +# empty range +try: + random.randrange(2, 1, 1) +except ValueError: + print('ValueError') + +print('randint') +for i in range(50): + assert 0 <= random.randint(0, 4) <= 4 + assert 2 <= random.randint(2, 6) <= 6 + assert -2 <= random.randint(-2, 2) <= 2 + +# empty range +try: + random.randint(2, 1) +except ValueError: + print('ValueError') + +print('choice') +lst = [1, 2, 5, 6] +for i in range(50): + assert random.choice(lst) in lst + +# empty sequence +try: + random.choice([]) +except IndexError: + print('IndexError') diff --git a/src/openmv/src/micropython/tests/extmod/urandom_extra_float.py b/src/openmv/src/micropython/tests/extmod/urandom_extra_float.py new file mode 100755 index 0000000..f665fd1 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/urandom_extra_float.py @@ -0,0 +1,24 @@ +try: + import urandom as random +except ImportError: + try: + import random + except ImportError: + print("SKIP") + raise SystemExit + +try: + random.randint +except AttributeError: + print('SKIP') + raise SystemExit + +print('random') +for i in range(50): + assert 0 <= random.random() < 1 + +print('uniform') +for i in range(50): + assert 0 <= random.uniform(0, 4) <= 4 + assert 2 <= random.uniform(2, 6) <= 6 + assert -2 <= random.uniform(-2, 2) <= 2 diff --git a/src/openmv/src/micropython/tests/extmod/ure1.py b/src/openmv/src/micropython/tests/extmod/ure1.py new file mode 100755 index 0000000..54471ed --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure1.py @@ -0,0 +1,90 @@ +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +r = re.compile(".+") +m = r.match("abc") +print(m.group(0)) +try: + m.group(1) +except IndexError: + print("IndexError") + +# conversion of re and match to string +str(r) +str(m) + +r = re.compile("(.+)1") +m = r.match("xyz781") +print(m.group(0)) +print(m.group(1)) +try: + m.group(2) +except IndexError: + print("IndexError") + +r = re.compile("[a-cu-z]") +m = r.match("a") +print(m.group(0)) +m = r.match("z") +print(m.group(0)) +m = r.match("d") +print(m) +m = r.match("A") +print(m) +print("===") + +r = re.compile("[^a-cu-z]") +m = r.match("a") +print(m) +m = r.match("z") +print(m) +m = r.match("d") +print(m.group(0)) +m = r.match("A") +print(m.group(0)) +print("===") + +# '-' character within character class block +print(re.match("[-a]+", "-a]d").group(0)) +print(re.match("[a-]+", "-a]d").group(0)) +print("===") + +r = re.compile("o+") +m = r.search("foobar") +print(m.group(0)) +try: + m.group(1) +except IndexError: + print("IndexError") + + +m = re.match(".*", "foo") +print(m.group(0)) + +m = re.search("w.r", "hello world") +print(m.group(0)) + +m = re.match('a+?', 'ab'); print(m.group(0)) +m = re.match('a*?', 'ab'); print(m.group(0)) +m = re.match('^ab$', 'ab'); print(m.group(0)) +m = re.match('a|b', 'b'); print(m.group(0)) +m = re.match('a|b|c', 'c'); print(m.group(0)) + +# Case where anchors fail to match +r = re.compile("^b|b$") +m = r.search("abc") +print(m) + +try: + re.compile("*") +except: + print("Caught invalid regex") + +# bytes objects +m = re.match(rb'a+?', b'ab'); print(m.group(0)) diff --git a/src/openmv/src/micropython/tests/extmod/ure_debug.py b/src/openmv/src/micropython/tests/extmod/ure_debug.py new file mode 100755 index 0000000..cfb264b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_debug.py @@ -0,0 +1,8 @@ +# test printing debugging info when compiling +try: + import ure +except ImportError: + print("SKIP") + raise SystemExit + +ure.compile('^a|b[0-9]\w$', ure.DEBUG) diff --git a/src/openmv/src/micropython/tests/extmod/ure_debug.py.exp b/src/openmv/src/micropython/tests/extmod/ure_debug.py.exp new file mode 100755 index 0000000..45f5e20 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_debug.py.exp @@ -0,0 +1,15 @@ + 0: rsplit 5 (3) + 2: any + 3: jmp 0 (-5) + 5: save 0 + 7: split 14 (5) + 9: assert bol +10: char a +12: jmp 23 (9) +14: char b +16: class 1 0x30-0x39 +20: namedclass w +22: assert eol +23: save 1 +25: match +Bytes: 26, insts: 14 diff --git a/src/openmv/src/micropython/tests/extmod/ure_error.py b/src/openmv/src/micropython/tests/extmod/ure_error.py new file mode 100755 index 0000000..f52f735 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_error.py @@ -0,0 +1,25 @@ +# test errors in regex + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +def test_re(r): + try: + re.compile(r) + print("OK") + except: # uPy and CPy use different errors, so just ignore the type + print("Error") + +test_re(r'?') +test_re(r'*') +test_re(r'+') +test_re(r')') +test_re(r'[') +test_re(r'([') +test_re(r'([)') diff --git a/src/openmv/src/micropython/tests/extmod/ure_group.py b/src/openmv/src/micropython/tests/extmod/ure_group.py new file mode 100755 index 0000000..4e39468 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_group.py @@ -0,0 +1,32 @@ +# test groups, and nested groups + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +def print_groups(match): + print('----') + try: + i = 0 + while True: + print(match.group(i)) + i += 1 + except IndexError: + pass + +m = re.match(r'(([0-9]*)([a-z]*)[0-9]*)','1234hello567') +print_groups(m) + +m = re.match(r'([0-9]*)(([a-z]*)([0-9]*))','1234hello567') +print_groups(m) + +# optional group that matches +print_groups(re.match(r'(a)?b(c)', 'abc')) + +# optional group that doesn't match +print_groups(re.match(r'(a)?b(c)', 'bc')) diff --git a/src/openmv/src/micropython/tests/extmod/ure_groups.py b/src/openmv/src/micropython/tests/extmod/ure_groups.py new file mode 100755 index 0000000..4fac896 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_groups.py @@ -0,0 +1,33 @@ +# test match.groups() + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +try: + m = re.match(".", "a") + m.groups +except AttributeError: + print('SKIP') + raise SystemExit + + +m = re.match(r'(([0-9]*)([a-z]*)[0-9]*)','1234hello567') +print(m.groups()) + +m = re.match(r'([0-9]*)(([a-z]*)([0-9]*))','1234hello567') +print(m.groups()) + +# optional group that matches +print(re.match(r'(a)?b(c)', 'abc').groups()) + +# optional group that doesn't match +print(re.match(r'(a)?b(c)', 'bc').groups()) + +# only a single match +print(re.match(r'abc', 'abc').groups()) diff --git a/src/openmv/src/micropython/tests/extmod/ure_namedclass.py b/src/openmv/src/micropython/tests/extmod/ure_namedclass.py new file mode 100755 index 0000000..215d096 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_namedclass.py @@ -0,0 +1,32 @@ +# test named char classes + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +def print_groups(match): + print('----') + try: + i = 0 + while True: + print(m.group(i)) + i += 1 + except IndexError: + pass + +m = re.match(r'\w+','1234hello567 abc') +print_groups(m) + +m = re.match(r'(\w+)\s+(\w+)','ABC \t1234hello567 abc') +print_groups(m) + +m = re.match(r'(\S+)\s+(\D+)','ABC \thello abc567 abc') +print_groups(m) + +m = re.match(r'(([0-9]*)([a-z]*)\d*)','1234hello567') +print_groups(m) diff --git a/src/openmv/src/micropython/tests/extmod/ure_span.py b/src/openmv/src/micropython/tests/extmod/ure_span.py new file mode 100755 index 0000000..50f4439 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_span.py @@ -0,0 +1,40 @@ +# test match.span(), and nested spans + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +try: + m = re.match(".", "a") + m.span +except AttributeError: + print('SKIP') + raise SystemExit + + +def print_spans(match): + print('----') + try: + i = 0 + while True: + print(match.span(i), match.start(i), match.end(i)) + i += 1 + except IndexError: + pass + +m = re.match(r'(([0-9]*)([a-z]*)[0-9]*)','1234hello567') +print_spans(m) + +m = re.match(r'([0-9]*)(([a-z]*)([0-9]*))','1234hello567') +print_spans(m) + +# optional span that matches +print_spans(re.match(r'(a)?b(c)', 'abc')) + +# optional span that doesn't match +print_spans(re.match(r'(a)?b(c)', 'bc')) diff --git a/src/openmv/src/micropython/tests/extmod/ure_split.py b/src/openmv/src/micropython/tests/extmod/ure_split.py new file mode 100755 index 0000000..a8b9c16 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_split.py @@ -0,0 +1,33 @@ +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +r = re.compile(" ") +s = r.split("a b c foobar") +print(s) + +r = re.compile(" +") +s = r.split("a b c foobar") +print(s) + +r = re.compile(" +") +s = r.split("a b c foobar", 1) +print(s) + +r = re.compile(" +") +s = r.split("a b c foobar", 2) +print(s) + +r = re.compile("[a-f]+") +s = r.split("0a3b9") +print(s) + +# bytes objects +r = re.compile(b"x") +s = r.split(b"fooxbar") +print(s) diff --git a/src/openmv/src/micropython/tests/extmod/ure_split_empty.py b/src/openmv/src/micropython/tests/extmod/ure_split_empty.py new file mode 100755 index 0000000..76ce97e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_split_empty.py @@ -0,0 +1,23 @@ +# test splitting with pattern matches that can be empty +# +# CPython 3.5 issues a FutureWarning for these tests because their +# behaviour will change in a future version. MicroPython just stops +# splitting as soon as an empty match is found. + +try: + import ure as re +except ImportError: + print("SKIP") + raise SystemExit + +r = re.compile(" *") +s = r.split("a b c foobar") +print(s) + +r = re.compile("x*") +s = r.split("foo") +print(s) + +r = re.compile("x*") +s = r.split("axbc") +print(s) diff --git a/src/openmv/src/micropython/tests/extmod/ure_split_empty.py.exp b/src/openmv/src/micropython/tests/extmod/ure_split_empty.py.exp new file mode 100755 index 0000000..42cfea0 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_split_empty.py.exp @@ -0,0 +1,3 @@ +['a b c foobar'] +['foo'] +['axbc'] diff --git a/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py b/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py new file mode 100755 index 0000000..da6e965 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py @@ -0,0 +1,11 @@ +try: + import ure as re +except ImportError: + print("SKIP") + raise SystemExit + +r = re.compile('( )') +try: + s = r.split("a b c foobar") +except NotImplementedError: + print('NotImplementedError') diff --git a/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py.exp b/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py.exp new file mode 100755 index 0000000..437f616 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_split_notimpl.py.exp @@ -0,0 +1 @@ +NotImplementedError diff --git a/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py b/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py new file mode 100755 index 0000000..d3ce0c5 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py @@ -0,0 +1,13 @@ +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print("SKIP") + raise SystemExit + +try: + re.match("(a*)*", "aaa") +except RuntimeError: + print("RuntimeError") diff --git a/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py.exp b/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py.exp new file mode 100755 index 0000000..8a2b9bf --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_stack_overflow.py.exp @@ -0,0 +1 @@ +RuntimeError diff --git a/src/openmv/src/micropython/tests/extmod/ure_sub.py b/src/openmv/src/micropython/tests/extmod/ure_sub.py new file mode 100755 index 0000000..4aeb865 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_sub.py @@ -0,0 +1,61 @@ +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print('SKIP') + raise SystemExit + +try: + re.sub +except AttributeError: + print('SKIP') + raise SystemExit + + +def multiply(m): + return str(int(m.group(0)) * 2) + +print(re.sub("\d+", multiply, "10 20 30 40 50")) + +print(re.sub("\d+", lambda m: str(int(m.group(0)) // 2), "10 20 30 40 50")) + +def A(): + return "A" +print(re.sub('a', A(), 'aBCBABCDabcda.')) + +print( + re.sub( + r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', + 'static PyObject*\npy_\\1(void){\n return;\n}\n', + '\n\ndef myfunc():\n\ndef myfunc1():\n\ndef myfunc2():' + ) +) + +print( + re.compile( + '(calzino) (blu|bianco|verde) e (scarpa) (blu|bianco|verde)' + ).sub( + r'\g<1> colore \2 con \g<3> colore \4? ...', + 'calzino blu e scarpa verde' + ) +) + +# no matches at all +print(re.sub('a', 'b', 'c')) + +# with maximum substitution count specified +print(re.sub('a', 'b', '1a2a3a', 2)) + +# invalid group +try: + re.sub('(a)', 'b\\2', 'a') +except: + print('invalid group') + +# invalid group with very large number (to test overflow in uPy) +try: + re.sub('(a)', 'b\\199999999999999999999999999999999999999', 'a') +except: + print('invalid group') diff --git a/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py b/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py new file mode 100755 index 0000000..4795b31 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py @@ -0,0 +1,19 @@ +# test re.sub with unmatched groups, behaviour changed in CPython 3.5 + +try: + import ure as re +except ImportError: + try: + import re + except ImportError: + print('SKIP') + raise SystemExit + +try: + re.sub +except AttributeError: + print('SKIP') + raise SystemExit + +# first group matches, second optional group doesn't so is replaced with a blank +print(re.sub(r'(a)(b)?', r'\2-\1', '1a2')) diff --git a/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py.exp b/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py.exp new file mode 100755 index 0000000..1e5f0fd --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ure_sub_unmatched.py.exp @@ -0,0 +1 @@ +1-a2 diff --git a/src/openmv/src/micropython/tests/extmod/uselect_poll_basic.py b/src/openmv/src/micropython/tests/extmod/uselect_poll_basic.py new file mode 100755 index 0000000..828fda1 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uselect_poll_basic.py @@ -0,0 +1,34 @@ +try: + import usocket as socket, uselect as select, uerrno as errno +except ImportError: + try: + import socket, select, errno + except ImportError: + print("SKIP") + raise SystemExit + + +poller = select.poll() + +s = socket.socket() + +poller.register(s) +# https://docs.python.org/3/library/select.html#select.poll.register +# "Registering a file descriptor that’s already registered is not an error, +# and has the same effect as registering the descriptor exactly once." +poller.register(s) + +# 2 args are mandatory unlike register() +try: + poller.modify(s) +except TypeError: + print("modify:TypeError") + +poller.modify(s, select.POLLIN) + +poller.unregister(s) + +try: + poller.modify(s, select.POLLIN) +except OSError as e: + assert e.args[0] == errno.ENOENT diff --git a/src/openmv/src/micropython/tests/extmod/ussl_basic.py b/src/openmv/src/micropython/tests/extmod/ussl_basic.py new file mode 100755 index 0000000..e8710ed --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ussl_basic.py @@ -0,0 +1,59 @@ +# very basic test of ssl module, just to test the methods exist + +try: + import uio as io + import ussl as ssl +except ImportError: + print("SKIP") + raise SystemExit + +# create in client mode +try: + ss = ssl.wrap_socket(io.BytesIO()) +except OSError as er: + print('wrap_socket:', repr(er)) + +# create in server mode (can use this object for further tests) +socket = io.BytesIO() +ss = ssl.wrap_socket(socket, server_side=1) + +# print +print(repr(ss)[:12]) + +# setblocking +try: + ss.setblocking(False) +except NotImplementedError: + print('setblocking: NotImplementedError') +ss.setblocking(True) + +# write +print(ss.write(b'aaaa')) + +# read (underlying socket has no data) +print(ss.read(8)) + +# read (underlying socket has data, but it's bad data) +socket.write(b'aaaaaaaaaaaaaaaa') +socket.seek(0) +try: + ss.read(8) +except OSError as er: + print('read:', repr(er)) + +# close +ss.close() +# close 2nd time +ss.close() + +# read on closed socket +try: + ss.read(10) +except OSError as er: + print('read:', repr(er)) + +# write on closed socket +try: + ss.write(b'aaaa') +except OSError as er: + print('write:', repr(er)) diff --git a/src/openmv/src/micropython/tests/extmod/ussl_basic.py.exp b/src/openmv/src/micropython/tests/extmod/ussl_basic.py.exp new file mode 100755 index 0000000..cb9c51f --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/ussl_basic.py.exp @@ -0,0 +1,9 @@ +ssl_handshake_status: -256 +wrap_socket: OSError(5,) +<_SSLSocket +setblocking: NotImplementedError +4 +b'' +read: OSError(-261,) +read: OSError(9,) +write: OSError(9,) diff --git a/src/openmv/src/micropython/tests/extmod/utimeq1.py b/src/openmv/src/micropython/tests/extmod/utimeq1.py new file mode 100755 index 0000000..dc7f3b6 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/utimeq1.py @@ -0,0 +1,137 @@ +# Test for utimeq module which implements task queue with support for +# wraparound time (utime.ticks_ms() style). +try: + from utime import ticks_add, ticks_diff + from utimeq import utimeq +except ImportError: + print("SKIP") + raise SystemExit + +DEBUG = 0 + +MAX = ticks_add(0, -1) +MODULO_HALF = MAX // 2 + 1 + +if DEBUG: + def dprint(*v): + print(*v) +else: + def dprint(*v): + pass + +# Try not to crash on invalid data +h = utimeq(10) +try: + h.push(1) + assert False +except TypeError: + pass + +try: + h.pop(1) + assert False +except IndexError: + pass + +# unsupported unary op +try: + ~h + assert False +except TypeError: + pass + +# pushing on full queue +h = utimeq(1) +h.push(1, 0, 0) +try: + h.push(2, 0, 0) + assert False +except IndexError: + pass + +# popping into invalid type +try: + h.pop([]) + assert False +except TypeError: + pass + +# length +assert len(h) == 1 + +# peektime +assert h.peektime() == 1 + +# peektime with empty queue +try: + utimeq(1).peektime() + assert False +except IndexError: + pass + +def pop_all(h): + l = [] + while h: + item = [0, 0, 0] + h.pop(item) + #print("!", item) + l.append(tuple(item)) + dprint(l) + return l + +def add(h, v): + h.push(v, 0, 0) + dprint("-----") + #h.dump() + dprint("-----") + +h = utimeq(10) +add(h, 0) +add(h, MAX) +add(h, MAX - 1) +add(h, 101) +add(h, 100) +add(h, MAX - 2) +dprint(h) +l = pop_all(h) +for i in range(len(l) - 1): + diff = ticks_diff(l[i + 1][0], l[i][0]) + assert diff > 0 + +def edge_case(edge, offset): + h = utimeq(10) + add(h, ticks_add(0, offset)) + add(h, ticks_add(edge, offset)) + dprint(h) + l = pop_all(h) + diff = ticks_diff(l[1][0], l[0][0]) + dprint(diff, diff > 0) + return diff + +dprint("===") +diff = edge_case(MODULO_HALF - 1, 0) +assert diff == MODULO_HALF - 1 +assert edge_case(MODULO_HALF - 1, 100) == diff +assert edge_case(MODULO_HALF - 1, -100) == diff + +# We expect diff to be always positive, per the definition of heappop() which should return +# the smallest value. +# This is the edge case where this invariant breaks, due to assymetry of two's-complement +# range - there's one more negative integer than positive, so heappushing values like below +# will then make ticks_diff() return the minimum negative value. We could make heappop +# return them in a different order, but ticks_diff() result would be the same. Conclusion: +# never add to a heap values where (a - b) == MODULO_HALF (and which are >= MODULO_HALF +# ticks apart in real time of course). +dprint("===") +diff = edge_case(MODULO_HALF, 0) +assert diff == -MODULO_HALF +assert edge_case(MODULO_HALF, 100) == diff +assert edge_case(MODULO_HALF, -100) == diff + +dprint("===") +diff = edge_case(MODULO_HALF + 1, 0) +assert diff == MODULO_HALF - 1 +assert edge_case(MODULO_HALF + 1, 100) == diff +assert edge_case(MODULO_HALF + 1, -100) == diff + +print("OK") diff --git a/src/openmv/src/micropython/tests/extmod/utimeq1.py.exp b/src/openmv/src/micropython/tests/extmod/utimeq1.py.exp new file mode 100755 index 0000000..d86bac9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/utimeq1.py.exp @@ -0,0 +1 @@ +OK diff --git a/src/openmv/src/micropython/tests/extmod/utimeq_stable.py b/src/openmv/src/micropython/tests/extmod/utimeq_stable.py new file mode 100755 index 0000000..9fb522d --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/utimeq_stable.py @@ -0,0 +1,22 @@ +try: + from utimeq import utimeq +except ImportError: + print("SKIP") + raise SystemExit + +h = utimeq(10) + +# Check that for 2 same-key items, the queue is stable (pops items +# in the same order they were pushed). Unfortunately, this no longer +# holds for more same-key values, as the underlying heap structure +# is not stable itself. +h.push(100, 20, 0) +h.push(100, 10, 0) + +res = [0, 0, 0] +h.pop(res) +assert res == [100, 20, 0] +h.pop(res) +assert res == [100, 10, 0] + +print("OK") diff --git a/src/openmv/src/micropython/tests/extmod/utimeq_stable.py.exp b/src/openmv/src/micropython/tests/extmod/utimeq_stable.py.exp new file mode 100755 index 0000000..d86bac9 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/utimeq_stable.py.exp @@ -0,0 +1 @@ +OK diff --git a/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py b/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py new file mode 100755 index 0000000..112a825 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py @@ -0,0 +1,33 @@ +try: + import uzlib as zlib + import uio as io +except ImportError: + print("SKIP") + raise SystemExit + + +# Raw DEFLATE bitstream +buf = io.BytesIO(b'\xcbH\xcd\xc9\xc9\x07\x00') +inp = zlib.DecompIO(buf, -8) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(buf.seek(0, 1)) +print(inp.read(2)) +print(inp.read()) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(inp.read()) +print(buf.seek(0, 1)) + + +# zlib bitstream +inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc1')) +print(inp.read(10)) +print(inp.read()) + +# zlib bitstream, wrong checksum +inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc0')) +try: + print(inp.read()) +except OSError as e: + print(repr(e)) diff --git a/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py.exp b/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py.exp new file mode 100755 index 0000000..3f5f360 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uzlib_decompio.py.exp @@ -0,0 +1,12 @@ +0 +b'h' +2 +b'el' +b'lo' +7 +b'' +b'' +7 +b'0000000000' +b'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +OSError(22,) diff --git a/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py b/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py new file mode 100755 index 0000000..02087f7 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py @@ -0,0 +1,50 @@ +try: + import uzlib as zlib + import uio as io +except ImportError: + print("SKIP") + raise SystemExit + + +# gzip bitstream +buf = io.BytesIO(b'\x1f\x8b\x08\x08\x99\x0c\xe5W\x00\x03hello\x00\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00') +inp = zlib.DecompIO(buf, 16 + 8) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(buf.seek(0, 1)) +print(inp.read(2)) +print(inp.read()) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(inp.read()) +print(buf.seek(0, 1)) + +# Check FHCRC field +buf = io.BytesIO(b'\x1f\x8b\x08\x02\x99\x0c\xe5W\x00\x03\x00\x00\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00') +inp = zlib.DecompIO(buf, 16 + 8) +print(inp.read()) + +# Check FEXTRA field +buf = io.BytesIO(b'\x1f\x8b\x08\x04\x99\x0c\xe5W\x00\x03\x01\x00X\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00') +inp = zlib.DecompIO(buf, 16 + 8) +print(inp.read()) + +# broken header +buf = io.BytesIO(b'\x1f\x8c\x08\x08\x99\x0c\xe5W\x00\x03hello\x00\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00') +try: + inp = zlib.DecompIO(buf, 16 + 8) +except ValueError: + print("ValueError") + +# broken crc32 +buf = io.BytesIO(b'\x1f\x8b\x08\x08\x99\x0c\xe5W\x00\x03hello\x00\xcbH\xcd\xc9\xc9\x07\x00\x86\xa7\x106\x05\x00\x00\x00') +inp = zlib.DecompIO(buf, 16 + 8) +try: + inp.read(6) +except OSError as e: + print(repr(e)) + +# broken uncompressed size - not checked so far +#buf = io.BytesIO(b'\x1f\x8b\x08\x08\x99\x0c\xe5W\x00\x03hello\x00\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x06\x00\x00\x00') +#inp = zlib.DecompIO(buf, 16 + 8) +#inp.read(6) diff --git a/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py.exp b/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py.exp new file mode 100755 index 0000000..20a30c8 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uzlib_decompio_gz.py.exp @@ -0,0 +1,13 @@ +16 +b'h' +18 +b'el' +b'lo' +31 +b'' +b'' +31 +b'hello' +b'hello' +ValueError +OSError(22,) diff --git a/src/openmv/src/micropython/tests/extmod/uzlib_decompress.py b/src/openmv/src/micropython/tests/extmod/uzlib_decompress.py new file mode 100755 index 0000000..dd6e487 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/uzlib_decompress.py @@ -0,0 +1,51 @@ +try: + import zlib +except ImportError: + try: + import uzlib as zlib + except ImportError: + print("SKIP") + raise SystemExit + +PATTERNS = [ + # Packed results produced by CPy's zlib.compress() + (b'0', b'x\x9c3\x00\x00\x001\x001'), + (b'a', b'x\x9cK\x04\x00\x00b\x00b'), + (b'0' * 100, b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc1'), + (bytes(range(64)), b'x\x9cc`dbfaec\xe7\xe0\xe4\xe2\xe6\xe1\xe5\xe3\x17\x10\x14\x12\x16\x11\x15\x13\x97\x90\x94\x92\x96\x91\x95\x93WPTRVQUS\xd7\xd0\xd4\xd2\xd6\xd1\xd5\xd370426153\xb7\xb0\xb4\xb2\xb6\xb1\xb5\xb3\x07\x00\xaa\xe0\x07\xe1'), + (b'hello', b'x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15'), # compression level 0 + # adaptive/dynamic huffman tree + (b'13371813150|13764518736|12345678901', b'x\x9c\x05\xc1\x81\x01\x000\x04\x04\xb1\x95\\\x1f\xcfn\x86o\x82d\x06Qq\xc8\x9d\xc5X}I}\x00\x951D>I}\x00\x951D>I}\x00\x951D>I}\x00\x951D', b'x\x9c\x05\xc11\x01\x00\x00\x00\x010\x95\x14py\x84\x12C_\x9bR\x8cV\x8a\xd1J1Z)F\x1fw`\x089'), +] + +for unpacked, packed in PATTERNS: + assert zlib.decompress(packed) == unpacked + print(unpacked) + + +# Raw DEFLATE bitstream +v = b'\xcbH\xcd\xc9\xc9\x07\x00' +exp = b"hello" +out = zlib.decompress(v, -15) +assert(out == exp) +print(exp) +# Even when you ask CPython zlib.compress to produce Raw DEFLATE stream, +# it returns it with adler2 and oriignal size appended, as if it was a +# zlib stream. Make sure there're no random issues decompressing such. +v = b'\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00' +out = zlib.decompress(v, -15) +assert(out == exp) + +# this should error +try: + zlib.decompress(b'abc') +except Exception: + print("Exception") + +# invalid block type +try: + zlib.decompress(b'\x07', -15) # final-block, block-type=3 (invalid) +except Exception as er: + print('Exception') diff --git a/src/openmv/src/micropython/tests/extmod/vfs_basic.py b/src/openmv/src/micropython/tests/extmod/vfs_basic.py new file mode 100755 index 0000000..fbcc92b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_basic.py @@ -0,0 +1,147 @@ +# test VFS functionality without any particular filesystem type + +try: + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class Filesystem: + def __init__(self, id): + self.id = id + def mount(self, readonly, mkfs): + print(self.id, 'mount', readonly, mkfs) + def umount(self): + print(self.id, 'umount') + def ilistdir(self, dir): + print(self.id, 'ilistdir', dir) + return iter([('a%d' % self.id, 0, 0)]) + def chdir(self, dir): + print(self.id, 'chdir', dir) + def getcwd(self): + print(self.id, 'getcwd') + return 'dir%d' % self.id + def mkdir(self, path): + print(self.id, 'mkdir', path) + def remove(self, path): + print(self.id, 'remove', path) + def rename(self, old_path, new_path): + print(self.id, 'rename', old_path, new_path) + def rmdir(self, path): + print(self.id, 'rmdir', path) + def stat(self, path): + print(self.id, 'stat', path) + return (self.id,) + def statvfs(self, path): + print(self.id, 'statvfs', path) + return (self.id,) + def open(self, file, mode): + print(self.id, 'open', file, mode) + + +# first we umount any existing mount points the target may have +try: + uos.umount('/') +except OSError: + pass +for path in uos.listdir('/'): + uos.umount('/' + path) + +# stat root dir +print(uos.stat('/')) + +# statvfs root dir; verify that f_namemax has a sensible size +print(uos.statvfs('/')[9] >= 32) + +# getcwd when in root dir +print(uos.getcwd()) + +# basic mounting and listdir +uos.mount(Filesystem(1), '/test_mnt') +print(uos.listdir()) + +# ilistdir +i = uos.ilistdir() +print(next(i)) +try: + next(i) +except StopIteration: + print('StopIteration') +try: + next(i) +except StopIteration: + print('StopIteration') + +# referencing the mount point in different ways +print(uos.listdir('test_mnt')) +print(uos.listdir('/test_mnt')) + +# mounting another filesystem +uos.mount(Filesystem(2), '/test_mnt2', readonly=True) +print(uos.listdir()) +print(uos.listdir('/test_mnt2')) + +# mounting over an existing mount point +try: + uos.mount(Filesystem(3), '/test_mnt2') +except OSError: + print('OSError') + +# mkdir of a mount point +try: + uos.mkdir('/test_mnt') +except OSError: + print('OSError') + +# rename across a filesystem +try: + uos.rename('/test_mnt/a', '/test_mnt2/b') +except OSError: + print('OSError') + +# delegating to mounted filesystem +uos.chdir('test_mnt') +print(uos.listdir()) +print(uos.getcwd()) +uos.mkdir('test_dir') +uos.remove('test_file') +uos.rename('test_file', 'test_file2') +uos.rmdir('test_dir') +print(uos.stat('test_file')) +print(uos.statvfs('/test_mnt')) +open('test_file') +open('test_file', 'wb') + +# umount +uos.umount('/test_mnt') +uos.umount('/test_mnt2') + +# umount a non-existent mount point +try: + uos.umount('/test_mnt') +except OSError: + print('OSError') + +# root dir +uos.mount(Filesystem(3), '/') +print(uos.stat('/')) +print(uos.statvfs('/')) +print(uos.listdir()) +open('test') + +uos.mount(Filesystem(4), '/mnt') +print(uos.listdir()) +print(uos.listdir('/mnt')) +uos.chdir('/mnt') +print(uos.listdir()) + +# chdir to a subdir within root-mounted vfs, and then listdir +uos.chdir('/subdir') +print(uos.listdir()) +uos.chdir('/') + +uos.umount('/') +print(uos.listdir('/')) +uos.umount('/mnt') diff --git a/src/openmv/src/micropython/tests/extmod/vfs_basic.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_basic.py.exp new file mode 100755 index 0000000..0ae2c2c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_basic.py.exp @@ -0,0 +1,60 @@ +(16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) +True +/ +1 mount False False +['test_mnt'] +('test_mnt', 16384, 0) +StopIteration +StopIteration +1 ilistdir / +['a1'] +1 ilistdir / +['a1'] +2 mount True False +['test_mnt', 'test_mnt2'] +2 ilistdir / +['a2'] +3 mount False False +OSError +OSError +OSError +1 chdir / +1 ilistdir +['a1'] +1 getcwd +/test_mntdir1 +1 mkdir test_dir +1 remove test_file +1 rename test_file test_file2 +1 rmdir test_dir +1 stat test_file +(1,) +1 statvfs / +(1,) +1 open test_file r +1 open test_file wb +1 umount +2 umount +OSError +3 mount False False +(16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) +3 statvfs / +(3,) +3 ilistdir / +['a3'] +3 open test r +4 mount False False +3 ilistdir / +['mnt', 'a3'] +4 ilistdir / +['a4'] +4 chdir / +4 ilistdir +['a4'] +3 chdir /subdir +3 ilistdir +['a3'] +3 chdir / +3 umount +['mnt'] +4 umount diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py new file mode 100755 index 0000000..51cd765 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py @@ -0,0 +1,137 @@ +try: + import uerrno + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(50) +except MemoryError: + print("SKIP") + raise SystemExit + +uos.VfsFat.mkfs(bdev) +vfs = uos.VfsFat(bdev) +uos.mount(vfs, '/ramdisk') +uos.chdir('/ramdisk') + +# file IO +f = open("foo_file.txt", "w") +print(str(f)[:17], str(f)[-1:]) +f.write("hello!") +f.flush() +f.close() +f.close() # allowed +try: + f.write("world!") +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + f.read() +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + f.flush() +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + open("foo_file.txt", "x") +except OSError as e: + print(e.args[0] == uerrno.EEXIST) + +with open("foo_file.txt", "a") as f: + f.write("world!") + +with open("foo_file.txt") as f2: + print(f2.read()) + print(f2.tell()) + + f2.seek(0, 0) # SEEK_SET + print(f2.read(1)) + + f2.seek(0, 1) # SEEK_CUR + print(f2.read(1)) + f2.seek(2, 1) # SEEK_CUR + print(f2.read(1)) + + f2.seek(-2, 2) # SEEK_END + print(f2.read(1)) + +# using constructor of FileIO type to open a file +# no longer working with new VFS sub-system +#FileIO = type(f) +#with FileIO("/ramdisk/foo_file.txt") as f: +# print(f.read()) + +# dirs +vfs.mkdir("foo_dir") + +try: + vfs.rmdir("foo_file.txt") +except OSError as e: + print(e.args[0] == 20) # uerrno.ENOTDIR + +vfs.remove("foo_file.txt") +print(list(vfs.ilistdir())) + +# Here we test that opening a file with the heap locked fails correctly. This +# is a special case because file objects use a finaliser and allocating with a +# finaliser is a different path to normal allocation. It would be better to +# test this in the core tests but there are no core objects that use finaliser. +import micropython +micropython.heap_lock() +try: + vfs.open('x', 'r') +except MemoryError: + print('MemoryError') +micropython.heap_unlock() + +# Here we test that the finaliser is actually called during a garbage collection. +import gc +N = 4 +for i in range(N): + n = 'x%d' % i + f = vfs.open(n, 'w') + f.write(n) + f = None # release f without closing + [0, 1, 2, 3] # use up Python stack so f is really gone +gc.collect() # should finalise all N files by closing them +for i in range(N): + with vfs.open('x%d' % i, 'r') as f: + print(f.read()) diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py.exp new file mode 100755 index 0000000..4eb5040 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio1.py.exp @@ -0,0 +1,18 @@ + +True +True +True +True +hello!world! +12 +h +e +o +d +True +[('foo_dir', 16384, 0, 0)] +MemoryError +x0 +x1 +x2 +x3 diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py new file mode 100755 index 0000000..9b9a11e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py @@ -0,0 +1,114 @@ +try: + import uerrno + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(50) +except MemoryError: + print("SKIP") + raise SystemExit + +uos.VfsFat.mkfs(bdev) +vfs = uos.VfsFat(bdev) +uos.mount(vfs, '/ramdisk') +uos.chdir('/ramdisk') + +try: + vfs.mkdir("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EEXIST) + +try: + vfs.remove("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EISDIR) + +try: + vfs.remove("no_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + +try: + vfs.rename("foo_dir", "/null/file") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + +# file in dir +with open("foo_dir/file-in-dir.txt", "w+t") as f: + f.write("data in file") + +with open("foo_dir/file-in-dir.txt", "r+b") as f: + print(f.read()) + +with open("foo_dir/sub_file.txt", "w") as f: + f.write("subdir file") + +# directory not empty +try: + vfs.rmdir("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EACCES) + +# trim full path +vfs.rename("foo_dir/file-in-dir.txt", "foo_dir/file.txt") +print(list(vfs.ilistdir("foo_dir"))) + +vfs.rename("foo_dir/file.txt", "moved-to-root.txt") +print(list(vfs.ilistdir())) + +# check that renaming to existing file will overwrite it +with open("temp", "w") as f: + f.write("new text") +vfs.rename("temp", "moved-to-root.txt") +print(list(vfs.ilistdir())) +with open("moved-to-root.txt") as f: + print(f.read()) + +# valid removes +vfs.remove("foo_dir/sub_file.txt") +vfs.rmdir("foo_dir") +print(list(vfs.ilistdir())) + +# disk full +try: + bsize = vfs.statvfs("/ramdisk")[0] + free = vfs.statvfs("/ramdisk")[2] + 1 + f = open("large_file.txt", "wb") + f.write(bytearray(bsize * free)) +except OSError as e: + print("ENOSPC:", e.args[0] == 28) # uerrno.ENOSPC diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py.exp new file mode 100755 index 0000000..2684053 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_fileio2.py.exp @@ -0,0 +1,11 @@ +True +True +True +b'data in file' +True +[('sub_file.txt', 32768, 0, 11), ('file.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 8)] +new text +[('moved-to-root.txt', 32768, 0, 8)] +ENOSPC: True diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py b/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py new file mode 100755 index 0000000..488697f --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py @@ -0,0 +1,119 @@ +try: + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(50) + bdev2 = RAMFS(50) +except MemoryError: + print("SKIP") + raise SystemExit + +# first we umount any existing mount points the target may have +try: + uos.umount('/') +except OSError: + pass +for path in uos.listdir('/'): + uos.umount('/' + path) + +uos.VfsFat.mkfs(bdev) +uos.mount(bdev, '/') + +print(uos.getcwd()) + +f = open('test.txt', 'w') +f.write('hello') +f.close() + +print(uos.listdir()) +print(uos.listdir('/')) +print(uos.stat('')[:-3]) +print(uos.stat('/')[:-3]) +print(uos.stat('test.txt')[:-3]) +print(uos.stat('/test.txt')[:-3]) + +f = open('/test.txt') +print(f.read()) +f.close() + +uos.rename('test.txt', 'test2.txt') +print(uos.listdir()) +uos.rename('test2.txt', '/test3.txt') +print(uos.listdir()) +uos.rename('/test3.txt', 'test4.txt') +print(uos.listdir()) +uos.rename('/test4.txt', '/test5.txt') +print(uos.listdir()) + +uos.mkdir('dir') +print(uos.listdir()) +uos.mkdir('/dir2') +print(uos.listdir()) +uos.mkdir('dir/subdir') +print(uos.listdir('dir')) +for exist in ('', '/', 'dir', '/dir', 'dir/subdir'): + try: + uos.mkdir(exist) + except OSError as er: + print('mkdir OSError', er.args[0] == 17) # EEXIST + +uos.chdir('/') +print(uos.stat('test5.txt')[:-3]) + +uos.VfsFat.mkfs(bdev2) +uos.mount(bdev2, '/sys') +print(uos.listdir()) +print(uos.listdir('sys')) +print(uos.listdir('/sys')) + +uos.rmdir('dir2') +uos.remove('test5.txt') +print(uos.listdir()) + +uos.umount('/') +print(uos.getcwd()) +print(uos.listdir()) +print(uos.listdir('sys')) + +# test importing a file from a mounted FS +import sys +sys.path.clear() +sys.path.append('/sys') +with open('sys/test_module.py', 'w') as f: + f.write('print("test_module!")') +import test_module diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py.exp new file mode 100755 index 0000000..24429ee --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_more.py.exp @@ -0,0 +1,29 @@ +/ +['test.txt'] +['test.txt'] +(16384, 0, 0, 0, 0, 0, 0) +(16384, 0, 0, 0, 0, 0, 0) +(32768, 0, 0, 0, 0, 0, 5) +(32768, 0, 0, 0, 0, 0, 5) +hello +['test2.txt'] +['test3.txt'] +['test4.txt'] +['test5.txt'] +['test5.txt', 'dir'] +['test5.txt', 'dir', 'dir2'] +['subdir'] +mkdir OSError True +mkdir OSError True +mkdir OSError True +mkdir OSError True +mkdir OSError True +(32768, 0, 0, 0, 0, 0, 5) +['sys', 'test5.txt', 'dir', 'dir2'] +[] +[] +['sys', 'dir'] +/ +['sys'] +[] +test_module! diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py b/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py new file mode 100755 index 0000000..3caaa36 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py @@ -0,0 +1,58 @@ +try: + import uerrno + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + +class RAMFS_OLD: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def sync(self): + pass + + def count(self): + return len(self.data) // self.SEC_SIZE + + +try: + bdev = RAMFS_OLD(50) +except MemoryError: + print("SKIP") + raise SystemExit + +uos.VfsFat.mkfs(bdev) +vfs = uos.VfsFat(bdev) +uos.mount(vfs, "/ramdisk") + +# file io +with vfs.open("file.txt", "w") as f: + f.write("hello!") + +print(list(vfs.ilistdir())) + +with vfs.open("file.txt", "r") as f: + print(f.read()) + +vfs.remove("file.txt") +print(list(vfs.ilistdir())) diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py.exp new file mode 100755 index 0000000..b974683 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_oldproto.py.exp @@ -0,0 +1,3 @@ +[('file.txt', 32768, 0, 6)] +hello! +[] diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py b/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py new file mode 100755 index 0000000..f6e5c64 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py @@ -0,0 +1,97 @@ +try: + import uerrno + import uos +except ImportError: + print("SKIP") + raise SystemExit + +try: + uos.VfsFat +except AttributeError: + print("SKIP") + raise SystemExit + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(50) +except MemoryError: + print("SKIP") + raise SystemExit + +uos.VfsFat.mkfs(bdev) + +print(b"FOO_FILETXT" not in bdev.data) +print(b"hello!" not in bdev.data) + +vfs = uos.VfsFat(bdev) +uos.mount(vfs, "/ramdisk") + +print("statvfs:", vfs.statvfs("/ramdisk")) +print("getcwd:", vfs.getcwd()) + +try: + vfs.stat("no_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + +with vfs.open("foo_file.txt", "w") as f: + f.write("hello!") +print(list(vfs.ilistdir())) + +print("stat root:", vfs.stat("/")) +print("stat file:", vfs.stat("foo_file.txt")[:-3]) # timestamps differ across runs + +print(b"FOO_FILETXT" in bdev.data) +print(b"hello!" in bdev.data) + +vfs.mkdir("foo_dir") +vfs.chdir("foo_dir") +print("getcwd:", vfs.getcwd()) +print(list(vfs.ilistdir())) + +with vfs.open("sub_file.txt", "w") as f: + f.write("subdir file") + +try: + vfs.chdir("sub_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + +vfs.chdir("..") +print("getcwd:", vfs.getcwd()) + +uos.umount(vfs) + +vfs = uos.VfsFat(bdev) +print(list(vfs.ilistdir(b""))) + +# list a non-existent directory +try: + vfs.ilistdir(b"no_exist") +except OSError as e: + print('ENOENT:', e.args[0] == uerrno.ENOENT) diff --git a/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py.exp new file mode 100755 index 0000000..ef6cf1e --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_fat_ramdisk.py.exp @@ -0,0 +1,16 @@ +True +True +statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255) +getcwd: / +True +[('foo_file.txt', 32768, 0, 6)] +stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) +stat file: (32768, 0, 0, 0, 0, 0, 6) +True +True +getcwd: /foo_dir +[] +True +getcwd: / +[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)] +ENOENT: True diff --git a/src/openmv/src/micropython/tests/extmod/vfs_userfs.py b/src/openmv/src/micropython/tests/extmod/vfs_userfs.py new file mode 100755 index 0000000..7f6e48c --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_userfs.py @@ -0,0 +1,69 @@ +# test VFS functionality with a user-defined filesystem +# also tests parts of uio.IOBase implementation + +import sys + +try: + import uio + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + print('ioctl', req, arg) + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + print('stat', path) + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + print('open', path, mode) + return UserFile(self.files[path]) + + +# create and mount a user filesystem +user_files = { + '/data.txt': b"some data in a text file\n", + '/usermod1.py': b"print('in usermod1')\nimport usermod2", + '/usermod2.py': b"print('in usermod2')", +} +uos.mount(UserFS(user_files), '/userfs') + +# open and read a file +f = open('/userfs/data.txt') +print(f.read()) + +# import files from the user filesystem +sys.path.append('/userfs') +import usermod1 + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/src/openmv/src/micropython/tests/extmod/vfs_userfs.py.exp b/src/openmv/src/micropython/tests/extmod/vfs_userfs.py.exp new file mode 100755 index 0000000..6a4d925 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/vfs_userfs.py.exp @@ -0,0 +1,12 @@ +open /data.txt r +b'some data in a text file\n' +stat /usermod1 +stat /usermod1.py +open /usermod1.py r +ioctl 4 0 +in usermod1 +stat /usermod2 +stat /usermod2.py +open /usermod2.py r +ioctl 4 0 +in usermod2 diff --git a/src/openmv/src/micropython/tests/extmod/websocket_basic.py b/src/openmv/src/micropython/tests/extmod/websocket_basic.py new file mode 100755 index 0000000..9a80503 --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/websocket_basic.py @@ -0,0 +1,60 @@ +try: + import uio + import uerrno + import websocket +except ImportError: + print("SKIP") + raise SystemExit + +# put raw data in the stream and do a websocket read +def ws_read(msg, sz): + ws = websocket.websocket(uio.BytesIO(msg)) + return ws.read(sz) + +# do a websocket write and then return the raw data from the stream +def ws_write(msg, sz): + s = uio.BytesIO() + ws = websocket.websocket(s) + ws.write(msg) + s.seek(0) + return s.read(sz) + +# basic frame +print(ws_read(b"\x81\x04ping", 4)) +print(ws_read(b"\x80\x04ping", 4)) # FRAME_CONT +print(ws_write(b"pong", 6)) + +# split frames are not supported +# print(ws_read(b"\x01\x04ping", 4)) + +# extended payloads +print(ws_read(b'\x81~\x00\x80' + b'ping' * 32, 128)) +print(ws_write(b"pong" * 32, 132)) + +# mask (returned data will be 'mask' ^ 'mask') +print(ws_read(b"\x81\x84maskmask", 4)) + +# close control frame +s = uio.BytesIO(b'\x88\x00') # FRAME_CLOSE +ws = websocket.websocket(s) +print(ws.read(1)) +s.seek(2) +print(s.read(4)) + +# misc control frames +print(ws_read(b"\x89\x00\x81\x04ping", 4)) # FRAME_PING +print(ws_read(b"\x8a\x00\x81\x04pong", 4)) # FRAME_PONG + +# close method +ws = websocket.websocket(uio.BytesIO()) +ws.close() + +# ioctl +ws = websocket.websocket(uio.BytesIO()) +print(ws.ioctl(8)) # GET_DATA_OPTS +print(ws.ioctl(9, 2)) # SET_DATA_OPTS +print(ws.ioctl(9)) +try: + ws.ioctl(-1) +except OSError as e: + print("ioctl: EINVAL:", e.args[0] == uerrno.EINVAL) diff --git a/src/openmv/src/micropython/tests/extmod/websocket_basic.py.exp b/src/openmv/src/micropython/tests/extmod/websocket_basic.py.exp new file mode 100755 index 0000000..2d7657b --- /dev/null +++ b/src/openmv/src/micropython/tests/extmod/websocket_basic.py.exp @@ -0,0 +1,14 @@ +b'ping' +b'ping' +b'\x81\x04pong' +b'pingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingping' +b'\x81~\x00\x80pongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpong' +b'\x00\x00\x00\x00' +b'' +b'\x81\x02\x88\x00' +b'ping' +b'pong' +0 +1 +2 +ioctl: EINVAL: True diff --git a/src/openmv/src/micropython/tests/feature_check/README b/src/openmv/src/micropython/tests/feature_check/README new file mode 100755 index 0000000..d062020 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/README @@ -0,0 +1,4 @@ +This directory doesn't contain real tests, but code snippets to detect +various interpreter features, which can't be/inconvenient to detecte by +other means. Scripts here are executed by run-tests at the beginning of +testsuite to decide what other test groups to run/exclude. diff --git a/src/openmv/src/micropython/tests/feature_check/async_check.py b/src/openmv/src/micropython/tests/feature_check/async_check.py new file mode 100755 index 0000000..0f6361c --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/async_check.py @@ -0,0 +1,3 @@ +# check if async/await keywords are supported +async def foo(): + await 1 diff --git a/src/openmv/src/micropython/tests/feature_check/async_check.py.exp b/src/openmv/src/micropython/tests/feature_check/async_check.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/byteorder.py b/src/openmv/src/micropython/tests/feature_check/byteorder.py new file mode 100755 index 0000000..d60f939 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/byteorder.py @@ -0,0 +1,2 @@ +import sys +print(sys.byteorder) diff --git a/src/openmv/src/micropython/tests/feature_check/byteorder.py.exp b/src/openmv/src/micropython/tests/feature_check/byteorder.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/complex.py b/src/openmv/src/micropython/tests/feature_check/complex.py new file mode 100755 index 0000000..a22eb52 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/complex.py @@ -0,0 +1,6 @@ +try: + complex + print("complex") +except NameError: + print("no") + diff --git a/src/openmv/src/micropython/tests/feature_check/complex.py.exp b/src/openmv/src/micropython/tests/feature_check/complex.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/const.py b/src/openmv/src/micropython/tests/feature_check/const.py new file mode 100755 index 0000000..db32e8c --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/const.py @@ -0,0 +1 @@ +x = const(1) diff --git a/src/openmv/src/micropython/tests/feature_check/const.py.exp b/src/openmv/src/micropython/tests/feature_check/const.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/coverage.py b/src/openmv/src/micropython/tests/feature_check/coverage.py new file mode 100755 index 0000000..dcda53e --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/coverage.py @@ -0,0 +1,5 @@ +try: + extra_coverage + print('coverage') +except NameError: + print('no') diff --git a/src/openmv/src/micropython/tests/feature_check/coverage.py.exp b/src/openmv/src/micropython/tests/feature_check/coverage.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/float.py b/src/openmv/src/micropython/tests/feature_check/float.py new file mode 100755 index 0000000..af93f59 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/float.py @@ -0,0 +1,13 @@ +# detect how many bits of precision the floating point implementation has + +try: + float +except NameError: + print(0) +else: + if float('1.0000001') == float('1.0'): + print(30) + elif float('1e300') == float('inf'): + print(32) + else: + print(64) diff --git a/src/openmv/src/micropython/tests/feature_check/float.py.exp b/src/openmv/src/micropython/tests/feature_check/float.py.exp new file mode 100755 index 0000000..900731f --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/float.py.exp @@ -0,0 +1 @@ +64 diff --git a/src/openmv/src/micropython/tests/feature_check/int_big.py b/src/openmv/src/micropython/tests/feature_check/int_big.py new file mode 100755 index 0000000..f30285a --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/int_big.py @@ -0,0 +1,2 @@ +# Check whether arbitrary-precision integers (MPZ) are supported +print(1000000000000000000000000000000000000000000000) diff --git a/src/openmv/src/micropython/tests/feature_check/int_big.py.exp b/src/openmv/src/micropython/tests/feature_check/int_big.py.exp new file mode 100755 index 0000000..9dfe335 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/int_big.py.exp @@ -0,0 +1 @@ +1000000000000000000000000000000000000000000000 diff --git a/src/openmv/src/micropython/tests/feature_check/native_check.py b/src/openmv/src/micropython/tests/feature_check/native_check.py new file mode 100755 index 0000000..3971d13 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/native_check.py @@ -0,0 +1,4 @@ +# this test for the availability of native emitter +@micropython.native +def f(): + pass diff --git a/src/openmv/src/micropython/tests/feature_check/native_check.py.exp b/src/openmv/src/micropython/tests/feature_check/native_check.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py b/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py new file mode 100755 index 0000000..3209716 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py @@ -0,0 +1,3 @@ +# Check for emacs keys in REPL +t = +11 +t == 2 diff --git a/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py.exp b/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py.exp new file mode 100755 index 0000000..82a4e28 --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/repl_emacs_check.py.exp @@ -0,0 +1,7 @@ +MicroPython \.\+ version +Use \.\+ +>>> # Check for emacs keys in REPL +>>> t = \.\+ +>>> t == 2 +True +>>> diff --git a/src/openmv/src/micropython/tests/feature_check/reverse_ops.py b/src/openmv/src/micropython/tests/feature_check/reverse_ops.py new file mode 100755 index 0000000..668748b --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/reverse_ops.py @@ -0,0 +1,9 @@ +class Foo: + + def __radd__(self, other): + pass + +try: + 5 + Foo() +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/feature_check/reverse_ops.py.exp b/src/openmv/src/micropython/tests/feature_check/reverse_ops.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/feature_check/set_check.py b/src/openmv/src/micropython/tests/feature_check/set_check.py new file mode 100755 index 0000000..ec186cc --- /dev/null +++ b/src/openmv/src/micropython/tests/feature_check/set_check.py @@ -0,0 +1,2 @@ +# check if set literal syntax is supported +{1} diff --git a/src/openmv/src/micropython/tests/feature_check/set_check.py.exp b/src/openmv/src/micropython/tests/feature_check/set_check.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/float/array_construct.py b/src/openmv/src/micropython/tests/float/array_construct.py new file mode 100755 index 0000000..9386758 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/array_construct.py @@ -0,0 +1,10 @@ +# test construction of array from array with float type + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +print(array('f', array('h', [1, 2]))) +print(array('d', array('f', [1, 2]))) diff --git a/src/openmv/src/micropython/tests/float/builtin_float_abs.py b/src/openmv/src/micropython/tests/float/builtin_float_abs.py new file mode 100755 index 0000000..c0935c6 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_abs.py @@ -0,0 +1,13 @@ +# test builtin abs function with float args + +for val in ( + '1.0', + '-1.0', + '0.0', + '-0.0', + 'nan', + '-nan', + 'inf', + '-inf', + ): + print(val, abs(float(val))) diff --git a/src/openmv/src/micropython/tests/float/builtin_float_hash.py b/src/openmv/src/micropython/tests/float/builtin_float_hash.py new file mode 100755 index 0000000..7a7e374 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_hash.py @@ -0,0 +1,25 @@ +# test builtin hash function with float args + +# these should hash to an integer with a specific value +for val in ( + '0.0', + '-0.0', + '1.0', + '2.0', + '-12.0', + '12345.0', + ): + print(val, hash(float(val))) + +# just check that these values are hashable +for val in ( + '0.1', + '-0.1', + '10.3', + '0.4e3', + '1e16', + 'inf', + '-inf', + 'nan', + ): + print(val, type(hash(float(val)))) diff --git a/src/openmv/src/micropython/tests/float/builtin_float_minmax.py b/src/openmv/src/micropython/tests/float/builtin_float_minmax.py new file mode 100755 index 0000000..266ed13 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_minmax.py @@ -0,0 +1,32 @@ +# test builtin min and max functions with float args +try: + min + max +except: + print("SKIP") + raise SystemExit + +print(min(0, 1.0)) +print(min(1.0, 0)) +print(min(0, -1.0)) +print(min(-1.0, 0)) + +print(max(0, 1.0)) +print(max(1.0, 0)) +print(max(0, -1.0)) +print(max(-1.0, 0)) + +print(min(1.5, -1.5)) +print(min(-1.5, 1.5)) + +print(max(1.5, -1.5)) +print(max(-1.5, 1.5)) + +print(min([1, 2.9, 4, 0, -1, 2])) +print(max([1, 2.9, 4, 0, -1, 2])) + +print(min([1, 2.9, 4, 6.5, -1, 2])) +print(max([1, 2.9, 4, 6.5, -1, 2])) +print(min([1, 2.9, 4, -6.5, -1, 2])) +print(max([1, 2.9, 4, -6.5, -1, 2])) + diff --git a/src/openmv/src/micropython/tests/float/builtin_float_pow.py b/src/openmv/src/micropython/tests/float/builtin_float_pow.py new file mode 100755 index 0000000..2de1b48 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_pow.py @@ -0,0 +1,11 @@ +# test builtin pow function with float args + +print(pow(0.0, 0.0)) +print(pow(0, 1.0)) +print(pow(1.0, 1)) +print(pow(2.0, 3.0)) +print(pow(2.0, -4.0)) + +print(pow(0.0, float('inf'))) +print(pow(0.0, float('-inf'))) +print(pow(0.0, float('nan'))) diff --git a/src/openmv/src/micropython/tests/float/builtin_float_round.py b/src/openmv/src/micropython/tests/float/builtin_float_round.py new file mode 100755 index 0000000..63cb39a --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_round.py @@ -0,0 +1,24 @@ +# test round() with floats + +# check basic cases +tests = [ + [0.0], [1.0], [0.1], [-0.1], [123.4], [123.6], [-123.4], [-123.6], + [1.234567, 5], [1.23456, 1], [1.23456, 0], [1234.56, -2] +] +for t in tests: + print(round(*t)) + +# check .5 cases +for i in range(11): + print(round((i - 5) / 2)) + +# test second arg +for i in range(-1, 3): + print(round(1.47, i)) + +# test inf and nan +for val in (float('inf'), float('nan')): + try: + round(val) + except (ValueError, OverflowError) as e: + print(type(e)) diff --git a/src/openmv/src/micropython/tests/float/builtin_float_round_intbig.py b/src/openmv/src/micropython/tests/float/builtin_float_round_intbig.py new file mode 100755 index 0000000..2083e3e --- /dev/null +++ b/src/openmv/src/micropython/tests/float/builtin_float_round_intbig.py @@ -0,0 +1,4 @@ +# test round() with floats that return large integers + +for x in (-1e25, 1e25): + print('%.3g' % round(x)) diff --git a/src/openmv/src/micropython/tests/float/bytearray_construct.py b/src/openmv/src/micropython/tests/float/bytearray_construct.py new file mode 100755 index 0000000..e960d62 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/bytearray_construct.py @@ -0,0 +1,9 @@ +# test construction of bytearray from array with float type + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +print(bytearray(array('f', [1, 2.3]))) diff --git a/src/openmv/src/micropython/tests/float/bytes_construct.py b/src/openmv/src/micropython/tests/float/bytes_construct.py new file mode 100755 index 0000000..0e4482e --- /dev/null +++ b/src/openmv/src/micropython/tests/float/bytes_construct.py @@ -0,0 +1,9 @@ +# test construction of bytearray from array with float type + +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +print(bytes(array('f', [1, 2.3]))) diff --git a/src/openmv/src/micropython/tests/float/cmath_fun.py b/src/openmv/src/micropython/tests/float/cmath_fun.py new file mode 100755 index 0000000..d3df25e --- /dev/null +++ b/src/openmv/src/micropython/tests/float/cmath_fun.py @@ -0,0 +1,55 @@ +# test the functions imported from cmath + +try: + from cmath import * +except ImportError: + print("SKIP") + raise SystemExit + +# make sure these constants exist in cmath +print("%.5g" % e) +print("%.5g" % pi) + +test_values_non_zero = [] +base_values = (0.0, 0.5, 1.2345, 10.) +for r in base_values: + for i in base_values: + if r != 0. or i != 0.: + test_values_non_zero.append(complex(r, i)) + if r != 0.: + test_values_non_zero.append(complex(-r, i)) + if i != 0.: + test_values_non_zero.append(complex(r, -i)) + if r != 0. and i != 0.: + test_values_non_zero.append(complex(-r, -i)) +test_values = [complex(0., 0.),] + test_values_non_zero +print(test_values) + +functions = [ + ('phase', phase, test_values), + ('polar', polar, test_values), + ('rect', rect, ((0, 0), (0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (-1, 1), (1, -1), (123., -456.))), + ('exp', exp, test_values), + ('log', log, test_values_non_zero), + ('sqrt', sqrt, test_values), + ('cos', cos, test_values), + ('sin', sin, test_values), +] + +for f_name, f, test_vals in functions: + print(f_name) + for val in test_vals: + if type(val) == tuple: + ret = f(*val) + else: + ret = f(val) + if type(ret) == float: + print("%.5g" % ret) + elif type(ret) == tuple: + print("%.5g %.5g" % ret) + else: + # some test (eg cmath.sqrt(-0.5)) disagree with CPython with tiny real part + real = ret.real + if abs(real) < 1e-6: + real = 0. + print("complex(%.5g, %.5g)" % (real, ret.imag)) diff --git a/src/openmv/src/micropython/tests/float/cmath_fun_special.py b/src/openmv/src/micropython/tests/float/cmath_fun_special.py new file mode 100755 index 0000000..471fda8 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/cmath_fun_special.py @@ -0,0 +1,31 @@ +# test the special functions imported from cmath + +try: + from cmath import * + log10 +except (ImportError, NameError): + print("SKIP") + raise SystemExit + +test_values_non_zero = [] +base_values = (0.0, 0.5, 1.2345, 10.) +for r in base_values: + for i in base_values: + if r != 0. or i != 0.: + test_values_non_zero.append(complex(r, i)) + if r != 0.: + test_values_non_zero.append(complex(-r, i)) + if i != 0.: + test_values_non_zero.append(complex(r, -i)) + if r != 0. and i != 0.: + test_values_non_zero.append(complex(-r, -i)) + +functions = [ + ('log10', log10, test_values_non_zero), +] + +for f_name, f, test_vals in functions: + print(f_name) + for val in test_vals: + ret = f(val) + print("complex(%.5g, %.5g)" % (ret.real, ret.imag)) diff --git a/src/openmv/src/micropython/tests/float/complex1.py b/src/openmv/src/micropython/tests/float/complex1.py new file mode 100755 index 0000000..479b4b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/complex1.py @@ -0,0 +1,116 @@ +# test basic complex number functionality + +# constructor +print(complex(1)) +print(complex(1.2)) +print(complex(1.2j)) +print(complex("1")) +print(complex("1.2")) +print(complex("1.2j")) +print(complex(1, 2)) +print(complex(1j, 2j)) + +# unary ops +print(bool(1j)) +print(+(1j)) +print(-(1 + 2j)) + +# binary ops +print(1j + False) +print(1j + True) +print(1j + 2) +print(1j + 2j) +print(1j - 2) +print(1j - 2j) +print(1j * 2) +print(1j * 2j) +print(1j / 2) +print((1j / 2j).real) +print(1j / (1 + 2j)) +ans = 0j ** 0; print("%.5g %.5g" % (ans.real, ans.imag)) +ans = 0j ** 1; print("%.5g %.5g" % (ans.real, ans.imag)) +ans = 0j ** 0j; print("%.5g %.5g" % (ans.real, ans.imag)) +ans = 1j ** 2.5; print("%.5g %.5g" % (ans.real, ans.imag)) +ans = 1j ** 2.5j; print("%.5g %.5g" % (ans.real, ans.imag)) + +# comparison +print(1j == 1) +print(1j == 1j) + +# comparison of nan is special +nan = float('nan') * 1j +print(nan == 1j) +print(nan == nan) + +# builtin abs +print(abs(1j)) +print("%.5g" % abs(1j + 2)) + +# builtin hash +print(hash(1 + 0j)) +print(type(hash(1j))) + +# float on lhs should delegate to complex +print(1.2 + 3j) + +# negative base and fractional power should create a complex +ans = (-1) ** 2.3; print("%.5g %.5g" % (ans.real, ans.imag)) +ans = (-1.2) ** -3.4; print("%.5g %.5g" % (ans.real, ans.imag)) + +# check printing of inf/nan +print(float('nan') * 1j) +print(float('-nan') * 1j) +print(float('inf') * (1 + 1j)) +print(float('-inf') * (1 + 1j)) + +# can't assign to attributes +try: + (1j).imag = 0 +except AttributeError: + print('AttributeError') + +# can't convert rhs to complex +try: + 1j + [] +except TypeError: + print("TypeError") + +# unsupported unary op +try: + ~(1j) +except TypeError: + print("TypeError") + +# unsupported binary op +try: + 1j // 2 +except TypeError: + print("TypeError") + +# unsupported binary op +try: + 1j < 2j +except TypeError: + print("TypeError") + +#small int on LHS, complex on RHS, unsupported op +try: + print(1 | 1j) +except TypeError: + print('TypeError') + +# zero division +try: + 1j / 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +# zero division via power +try: + 0j ** -1 +except ZeroDivisionError: + print("ZeroDivisionError") +try: + 0j ** 1j +except ZeroDivisionError: + print("ZeroDivisionError") diff --git a/src/openmv/src/micropython/tests/float/complex1_intbig.py b/src/openmv/src/micropython/tests/float/complex1_intbig.py new file mode 100755 index 0000000..ed2390b --- /dev/null +++ b/src/openmv/src/micropython/tests/float/complex1_intbig.py @@ -0,0 +1,4 @@ +# test basic complex number functionality + +# convert bignum to complex on rhs +ans = 1j + (1 << 70); print("%.5g %.5g" % (ans.real, ans.imag)) diff --git a/src/openmv/src/micropython/tests/float/float1.py b/src/openmv/src/micropython/tests/float/float1.py new file mode 100755 index 0000000..54807e5 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float1.py @@ -0,0 +1,119 @@ +# test basic float capabilities + +# literals +print(.12) +print(1.) +print(1.2) +print(0e0) +print(0e+0) +print(0e-0) + +# float construction +print(float(1.2)) +print(float("1.2")) +print(float("+1")) +print(float("1e1")) +print(float("1e+1")) +print(float("1e-1")) +print(float("inf")) +print(float("-inf")) +print(float("INF")) +print(float("infinity")) +print(float("INFINITY")) +print(float("nan")) +print(float("-nan")) +print(float("NaN")) +try: + float("") +except ValueError: + print("ValueError") +try: + float("1e+") +except ValueError: + print("ValueError") +try: + float("1z") +except ValueError: + print("ValueError") + +# construct from something with the buffer protocol +print(float(b"1.2")) +print(float(bytearray(b"3.4"))) + +# unary operators +print(bool(0.0)) +print(bool(1.2)) +print(+(1.2)) +print(-(1.2)) + +# division of integers +x = 1 / 2 +print(x) + +# /= operator +a = 1 +a /= 2 +print(a) + +# floor division +print(1.0 // 2) +print(2.0 // 2) + +# comparison +print(1.2 <= 3.4) +print(1.2 <= -3.4) +print(1.2 >= 3.4) +print(1.2 >= -3.4) + +# comparison of nan is special +nan = float('nan') +print(nan == 1.2) +print(nan == nan) + +try: + 1.0 / 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + 1.0 // 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + 1.2 % 0 +except ZeroDivisionError: + print("ZeroDivisionError") + +try: + 0.0 ** -1 +except ZeroDivisionError: + print("ZeroDivisionError") + +# unsupported unary ops + +try: + ~1.2 +except TypeError: + print("TypeError") + +try: + 1.2 in 3.4 +except TypeError: + print("TypeError") + +# small int on LHS, float on RHS, unsupported op +try: + print(1 | 1.0) +except TypeError: + print('TypeError') + +# can't convert list to float +try: + float([]) +except TypeError: + print("TypeError") + +# test constant float with more than 255 chars +x = 1.84728699436059052516398251149631771898472869943605905251639825114963177189847286994360590525163982511496317718984728699436059052516398251149631771898472869943605905251639825114963177189847286994360590525163982511496317718984728699436059052516398251149631771898472869943605905251639825114963177189 +print("%.5f" % x) diff --git a/src/openmv/src/micropython/tests/float/float2int_doubleprec_intbig.py b/src/openmv/src/micropython/tests/float/float2int_doubleprec_intbig.py new file mode 100755 index 0000000..de2137d --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float2int_doubleprec_intbig.py @@ -0,0 +1,100 @@ +# check cases converting float to int, requiring double precision float + +try: + import ustruct as struct +except: + import struct + +import sys +maxsize_bits = 0 +maxsize = sys.maxsize +while maxsize: + maxsize >>= 1 + maxsize_bits += 1 + +# work out configuration values +is_64bit = maxsize_bits > 32 +# 0 = none, 1 = long long, 2 = mpz +ll_type = None +if is_64bit: + if maxsize_bits < 63: + ll_type = 0 +else: + if maxsize_bits < 31: + ll_type = 0 +if ll_type is None: + one = 1 + if one << 65 < one << 62: + ll_type = 1 + else: + ll_type = 2 + +# This case occurs with time.time() values +if ll_type != 0: + print(int(1418774543.)) + print("%d" % 1418774543.) + if ll_type == 3: + print(int(2.**100)) + print("%d" % 2.**100) +else: + print(int(1073741823.)) + print("%d" % 1073741823.) + +testpass = True +p2_rng = ((30,63,1024),(62,63,1024))[is_64bit][ll_type] +for i in range(0,p2_rng): + bitcnt = len(bin(int(2.**i))) - 3; + if i != bitcnt: + print('fail: 2**%u was %u bits long' % (i, bitcnt)); + testpass = False +print("power of 2 test: %s" % (testpass and 'passed' or 'failed')) + +testpass = True +p10_rng = ((9,18,23),(18,18,23))[is_64bit][ll_type] +for i in range(0,p10_rng): + digcnt = len(str(int(10.**i))) - 1; + if i != digcnt: + print('fail: 10**%u was %u digits long' % (i, digcnt)); + testpass = False +print("power of 10 test: %s" % (testpass and 'passed' or 'failed')) + +def fp2int_test(num, name, should_fail): + try: + x = int(num) + passed = ~should_fail + except: + passed = should_fail + print('%s: %s' % (name, passed and 'passed' or 'failed')) + +if ll_type != 2: + if ll_type == 0: + if is_64bit: + neg_bad_fp = -1.00000005*2.**62. + pos_bad_fp = 2.**62. + neg_good_fp = -2.**62. + pos_good_fp = 0.99999993*2.**62. + else: + neg_bad_fp = -1.00000005*2.**30. + pos_bad_fp = 2.**30. + neg_good_fp = -2.**30. + pos_good_fp = 0.9999999499*2.**30. + else: + neg_bad_fp = -0.51*2.**64. + pos_bad_fp = 2.**63. + neg_good_fp = -2.**63. + pos_good_fp = 1.9999998*2.**62. + + fp2int_test(neg_bad_fp, 'neg bad', True) + fp2int_test(pos_bad_fp, 'pos bad', True) + fp2int_test(neg_good_fp, 'neg good', False) + fp2int_test(pos_good_fp, 'pos good', False) +else: + fp2int_test(-1.9999999999999981*2.**1023., 'large neg', False) + fp2int_test(1.9999999999999981*2.**1023., 'large pos', False) + +fp2int_test(float('inf'), 'inf test', True) +fp2int_test(float('nan'), 'NaN test', True) + +# test numbers < 1 (this used to fail; see issue #1044) +fp2int_test(0.0001, 'small num', False) +struct.pack('I', int(1/2)) diff --git a/src/openmv/src/micropython/tests/float/float2int_fp30_intbig.py b/src/openmv/src/micropython/tests/float/float2int_fp30_intbig.py new file mode 100755 index 0000000..fbb94a4 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float2int_fp30_intbig.py @@ -0,0 +1,97 @@ +# check cases converting float to int, relying only on single precision float + +try: + import ustruct as struct +except: + import struct + +import sys +maxsize_bits = 0 +maxsize = sys.maxsize +while maxsize: + maxsize >>= 1 + maxsize_bits += 1 + +# work out configuration values +is_64bit = maxsize_bits > 32 +# 0 = none, 1 = long long, 2 = mpz +ll_type = None +if is_64bit: + if maxsize_bits < 63: + ll_type = 0 +else: + if maxsize_bits < 31: + ll_type = 0 +if ll_type is None: + one = 1 + if one << 65 < one << 62: + ll_type = 1 + else: + ll_type = 2 + +# basic conversion +print(int(14187744.)) +print("%d" % 14187744.) +if ll_type == 2: + print(int(2.**100)) + print("%d" % 2.**100) + +testpass = True +p2_rng = ((30,63,127),(62,63,127))[is_64bit][ll_type] +for i in range(0,p2_rng): + bitcnt = len(bin(int(2.**i))) - 3; + if i != bitcnt: + print('fail: 2.**%u was %u bits long' % (i, bitcnt)); + testpass = False +print("power of 2 test: %s" % (testpass and 'passed' or 'failed')) + +# TODO why does 10**12 fail this test for single precision float? +testpass = True +p10_rng = 9 +for i in range(0,p10_rng): + digcnt = len(str(int(10.**i))) - 1; + if i != digcnt: + print('fail: 10.**%u was %u digits long' % (i, digcnt)); + testpass = False +print("power of 10 test: %s" % (testpass and 'passed' or 'failed')) + +def fp2int_test(num, name, should_fail): + try: + x = int(num) + passed = ~should_fail + except: + passed = should_fail + print('%s: %s' % (name, passed and 'passed' or 'failed')) + +if ll_type != 2: + if ll_type == 0: + if is_64bit: + neg_bad_fp = -1.00000005*2.**62. + pos_bad_fp = 2.**62. + neg_good_fp = -2.**62. + pos_good_fp = 0.99999993*2.**62. + else: + neg_bad_fp = -1.00000005*2.**30. + pos_bad_fp = 2.**30. + neg_good_fp = -2.**30. + pos_good_fp = 0.9999999499*2.**30. + else: + neg_bad_fp = -0.51*2.**64. + pos_bad_fp = 2.**63. + neg_good_fp = -2.**63. + pos_good_fp = 1.9999998*2.**62. + + fp2int_test(neg_bad_fp, 'neg bad', True) + fp2int_test(pos_bad_fp, 'pos bad', True) + fp2int_test(neg_good_fp, 'neg good', False) + fp2int_test(pos_good_fp, 'pos good', False) +else: + fp2int_test(-1.999999879*2.**126., 'large neg', False) + fp2int_test(1.999999879*2.**126., 'large pos', False) + +fp2int_test(float('inf'), 'inf test', True) +fp2int_test(float('nan'), 'NaN test', True) + +# test numbers < 1 (this used to fail; see issue #1044) +fp2int_test(0.0001, 'small num', False) +struct.pack('I', int(1/2)) diff --git a/src/openmv/src/micropython/tests/float/float2int_intbig.py b/src/openmv/src/micropython/tests/float/float2int_intbig.py new file mode 100755 index 0000000..3596d2f --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float2int_intbig.py @@ -0,0 +1,99 @@ +# check cases converting float to int, relying only on single precision float + +try: + import ustruct as struct +except: + import struct + +import sys + +maxsize_bits = 0 +maxsize = sys.maxsize +while maxsize: + maxsize >>= 1 + maxsize_bits += 1 + +# work out configuration values +is_64bit = maxsize_bits > 32 +# 0 = none, 1 = long long, 2 = mpz +ll_type = None +if is_64bit: + if maxsize_bits < 63: + ll_type = 0 +else: + if maxsize_bits < 31: + ll_type = 0 +if ll_type is None: + one = 1 + if one << 65 < one << 62: + ll_type = 1 + else: + ll_type = 2 + + +# basic conversion +print(int(14187745.)) +print("%d" % 14187745.) +if ll_type == 2: + print(int(2.**100)) + print("%d" % 2.**100) + +testpass = True +p2_rng = ((30,63,127),(62,63,127))[is_64bit][ll_type] +for i in range(0,p2_rng): + bitcnt = len(bin(int(2.**i))) - 3; + if i != bitcnt: + print('fail: 2.**%u was %u bits long' % (i, bitcnt)); + testpass = False +print("power of 2 test: %s" % (testpass and 'passed' or 'failed')) + +# TODO why does 10**12 fail this test for single precision float? +testpass = True +p10_rng = 9 if (ll_type == 0 and ~is_64bit) else 11 +for i in range(0,p10_rng): + digcnt = len(str(int(10.**i))) - 1; + if i != digcnt: + print('fail: 10.**%u was %u digits long' % (i, digcnt)); + testpass = False +print("power of 10 test: %s" % (testpass and 'passed' or 'failed')) + +def fp2int_test(num, name, should_fail): + try: + x = int(num) + passed = ~should_fail + except: + passed = should_fail + print('%s: %s' % (name, passed and 'passed' or 'failed')) + +if ll_type != 2: + if ll_type == 0: + if is_64bit: + neg_bad_fp = -1.00000005*2.**62. + pos_bad_fp = 2.**62. + neg_good_fp = -2.**62. + pos_good_fp = 0.99999993*2.**62. + else: + neg_bad_fp = -1.00000005*2.**30. + pos_bad_fp = 2.**30. + neg_good_fp = -2.**30. + pos_good_fp = 0.9999999499*2.**30. + else: + neg_bad_fp = -0.51*2.**64. + pos_bad_fp = 2.**63. + neg_good_fp = -2.**63. + pos_good_fp = 1.9999998*2.**62. + + fp2int_test(neg_bad_fp, 'neg bad', True) + fp2int_test(pos_bad_fp, 'pos bad', True) + fp2int_test(neg_good_fp, 'neg good', False) + fp2int_test(pos_good_fp, 'pos good', False) +else: + fp2int_test(-1.999999879*2.**127., 'large neg', False) + fp2int_test(1.999999879*2.**127., 'large pos', False) + +fp2int_test(float('inf'), 'inf test', True) +fp2int_test(float('nan'), 'NaN test', True) + +# test numbers < 1 (this used to fail; see issue #1044) +fp2int_test(0.0001, 'small num', False) +struct.pack('I', int(1/2)) diff --git a/src/openmv/src/micropython/tests/float/float_array.py b/src/openmv/src/micropython/tests/float/float_array.py new file mode 100755 index 0000000..8c8edcf --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_array.py @@ -0,0 +1,20 @@ +try: + from array import array +except ImportError: + print("SKIP") + raise SystemExit + +def test(a): + print(a) + a.append(1.2) + print(len(a), '%.3f' % a[0]) + a.append(1) + a.append(False) + print(len(a), '%.3f %.3f' % (a[1], a[2])) + a[-1] = 3.45 + print('%.3f' % a[-1]) + +test(array('f')) +test(array('d')) + +print('{:.4f}'.format(array('f', b'\xcc\xcc\xcc=')[0])) diff --git a/src/openmv/src/micropython/tests/float/float_compare.py b/src/openmv/src/micropython/tests/float/float_compare.py new file mode 100755 index 0000000..105923a --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_compare.py @@ -0,0 +1,22 @@ +# Extended float comparisons + +class Foo: + pass + +foo = Foo() + +print(foo == 1.0) +print(1.0 == foo) +print(1.0 == Foo) +print(1.0 == []) +print(1.0 == {}) + +try: + print(foo < 1.0) +except TypeError: + print("TypeError") + +try: + print(1.0 < foo) +except TypeError: + print("TypeError") diff --git a/src/openmv/src/micropython/tests/float/float_divmod.py b/src/openmv/src/micropython/tests/float/float_divmod.py new file mode 100755 index 0000000..8e7cd43 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_divmod.py @@ -0,0 +1,25 @@ +# test floating point floor divide and modulus +# it has some tricky corner cases + +def test(x, y): + div, mod = divmod(x, y) + print('%.8f %.8f %.8f %.8f' % (x // y, x % y, div, mod)) + print(div == x // y, mod == x % y, abs(div * y + mod - x) < 1e-15) + +test(1.23456, 0.7) +test(-1.23456, 0.7) +test(1.23456, -0.7) +test(-1.23456, -0.7) + +a = 1.23456 +b = 0.7 +test(a, b) +test(a, -b) +test(-a, b) +test(-a, -b) + +for i in range(25): + x = (i - 12.5) / 6 + for j in range(25): + y = (j - 12.5) / 6 + test(x, y) diff --git a/src/openmv/src/micropython/tests/float/float_divmod_relaxed.py b/src/openmv/src/micropython/tests/float/float_divmod_relaxed.py new file mode 100755 index 0000000..a9450fa --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_divmod_relaxed.py @@ -0,0 +1,33 @@ +# test floating point floor divide and modulus +# it has some tricky corner cases + +# pyboard has 32-bit floating point and gives different (but still +# correct) answers for certain combinations of divmod arguments. + +def test(x, y): + div, mod = divmod(x, y) + print(div == x // y, mod == x % y, abs(div * y + mod - x) < 1e-6) + +test(1.23456, 0.7) +test(-1.23456, 0.7) +test(1.23456, -0.7) +test(-1.23456, -0.7) + +a = 1.23456 +b = 0.7 +test(a, b) +test(a, -b) +test(-a, b) +test(-a, -b) + +for i in range(25): + x = (i - 12.5) / 6 + for j in range(25): + y = (j - 12.5) / 6 + test(x, y) + +# test division by zero error +try: + divmod(1.0, 0) +except ZeroDivisionError: + print('ZeroDivisionError') diff --git a/src/openmv/src/micropython/tests/float/float_format.py b/src/openmv/src/micropython/tests/float/float_format.py new file mode 100755 index 0000000..d43535c --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_format.py @@ -0,0 +1,19 @@ +# test float formatting + +# general rounding +for val in (116, 1111, 1234, 5010, 11111): + print('%.0f' % val) + print('%.1f' % val) + print('%.3f' % val) + +# make sure rounding is done at the correct precision +for prec in range(8): + print(('%%.%df' % prec) % 6e-5) + +# check certain cases that had a digit value of 10 render as a ":" character +print('%.2e' % float('9' * 51 + 'e-39')) +print('%.2e' % float('9' * 40 + 'e-21')) + +# check a case that would render negative digit values, eg ")" characters +# the string is converted back to a float to check for no illegal characters +float('%.23e' % 1e-80) diff --git a/src/openmv/src/micropython/tests/float/float_parse.py b/src/openmv/src/micropython/tests/float/float_parse.py new file mode 100755 index 0000000..4b5fc61 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_parse.py @@ -0,0 +1,36 @@ +# test parsing of floats + +inf = float('inf') + +# it shouldn't matter where the decimal point is if the exponent balances the value +print(float('1234') - float('0.1234e4')) +print(float('1.015625') - float('1015625e-6')) + +# very large integer part with a very negative exponent should cancel out +print('%.4e' % float('9' * 60 + 'e-60')) +print('%.4e' % float('9' * 60 + 'e-40')) + +# many fractional digits +print(float('.' + '9' * 70)) +print(float('.' + '9' * 70 + 'e20')) +print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) + +# tiny fraction with large exponent +print(float('.' + '0' * 60 + '1e10') == float('1e-51')) +print(float('.' + '0' * 60 + '9e25') == float('9e-36')) +print(float('.' + '0' * 60 + '9e40') == float('9e-21')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-37')) +print(float('10.0000000000000000000e-38')) +print(float('100.000000000000000000e-39')) + +# very large exponent literal +print(float('1e4294967301')) +print(float('1e-4294967301')) +print(float('1e18446744073709551621')) +print(float('1e-18446744073709551621')) + +# check small decimals are as close to their true value as possible +for n in range(1, 10): + print(float('0.%u' % n) == n / 10) diff --git a/src/openmv/src/micropython/tests/float/float_parse_doubleprec.py b/src/openmv/src/micropython/tests/float/float_parse_doubleprec.py new file mode 100755 index 0000000..dcc0dd5 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_parse_doubleprec.py @@ -0,0 +1,21 @@ +# test parsing of floats, requiring double-precision + +# very large integer part with a very negative exponent should cancel out +print(float('9' * 400 + 'e-100')) +print(float('9' * 400 + 'e-200')) +print(float('9' * 400 + 'e-400')) + +# many fractional digits +print(float('.' + '9' * 400)) +print(float('.' + '9' * 400 + 'e100')) +print(float('.' + '9' * 400 + 'e-100')) + +# tiny fraction with large exponent +print('%.14e' % float('.' + '0' * 400 + '9e100')) +print('%.14e' % float('.' + '0' * 400 + '9e200')) +print('%.14e' % float('.' + '0' * 400 + '9e400')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-307')) +print(float('10.0000000000000000000e-308')) +print(float('100.000000000000000000e-309')) diff --git a/src/openmv/src/micropython/tests/float/float_struct.py b/src/openmv/src/micropython/tests/float/float_struct.py new file mode 100755 index 0000000..c4c186b --- /dev/null +++ b/src/openmv/src/micropython/tests/float/float_struct.py @@ -0,0 +1,18 @@ +# test struct package with floats +try: + try: + import ustruct as struct + except: + import struct +except ImportError: + print("SKIP") + raise SystemExit + +i = 1. + 1/2 +# TODO: it looks like '=' format modifier is not yet supported +# for fmt in ('f', 'd', '>f', '>d', 'f', '>d', '' + fmt.format(*args) + '<') + +test("{:10.4}", 123.456) +test("{:10.4e}", 123.456) +test("{:10.4e}", -123.456) +test("{:10.4f}", 123.456) +test("{:10.4f}", -123.456) +test("{:10.4g}", 123.456) +test("{:10.4g}", -123.456) +test("{:10.4n}", 123.456) +test("{:e}", 100) +test("{:f}", 200) +test("{:g}", 300) + +test("{:10.4E}", 123.456) +test("{:10.4E}", -123.456) +test("{:10.4F}", 123.456) +test("{:10.4F}", -123.456) +test("{:10.4G}", 123.456) +test("{:10.4G}", -123.456) + +test("{:06e}", float("inf")) +test("{:06e}", float("-inf")) +test("{:06e}", float("nan")) + +# The following fails right now +#test("{:10.1}", 0.0) + +print("%.0f" % (1.750000 % 0.08333333333)) +# Below isn't compatible with single-precision float +#print("%.1f" % (1.750000 % 0.08333333333)) +#print("%.2f" % (1.750000 % 0.08333333333)) +#print("%.12f" % (1.750000 % 0.08333333333)) + +# tests for errors in format string + +try: + '{:10.1b}'.format(0.0) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/float/string_format2.py b/src/openmv/src/micropython/tests/float/string_format2.py new file mode 100755 index 0000000..269023e --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format2.py @@ -0,0 +1,106 @@ +# Change the following to True to get a much more comprehensive set of tests +# to run, albeit, which take considerably longer. + +full_tests = False + +def test(fmt, *args): + print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<') + +def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): + fmt = '{' + if conv: + fmt += '!' + fmt += conv + fmt += ':' + if alignment: + fmt += fill + fmt += alignment + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + if fill == '0' and alignment == '=': + fmt = '{:' + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + +eg_nums = (0.0, -0.0, 0.1, 1.234, 12.3459, 1.23456789, 123456789.0, -0.0, + -0.1, -1.234, -12.3459, 1e4, 1e-4, 1e5, 1e-5, 1e6, 1e-6, 1e10, + 1e37, -1e37, 1e-37, -1e-37, + 1.23456e8, 1.23456e7, 1.23456e6, 1.23456e5, 1.23456e4, 1.23456e3, 1.23456e2, 1.23456e1, 1.23456e0, + 1.23456e-1, 1.23456e-2, 1.23456e-3, 1.23456e-4, 1.23456e-5, 1.23456e-6, 1.23456e-7, 1.23456e-8, + -1.23456e8, -1.23456e7, -1.23456e6, -1.23456e5, -1.23456e4, -1.23456e3, -1.23456e2, -1.23456e1, -1.23456e0, + -1.23456e-1, -1.23456e-2, -1.23456e-3, -1.23456e-4, -1.23456e-5, -1.23456e-6, -1.23456e-7, -1.23456e-8) + +if full_tests: + for type in ('e', 'E', 'g', 'G', 'n'): + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', '@', '0', ' '): + for sign in ('', '+', '-', ' '): + for prec in ('', '1', '3', '6'): + for num in eg_nums: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + +# Note: We use 1.23459 rather than 1.2345 because '{:3f}'.format(1.2345) +# rounds differently than print("%.3f", 1.2345); + +f_nums = (0.0, -0.0, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, + 0.0012, 0.0123, 0.1234, 1.23459, 12.3456, + -0.0001, -0.001, -0.01, -0.1, -1.0, -10.0, + -0.0012, -0.0123, -0.1234, -1.23459, -12.3456) + +if full_tests: + for type in ('f', 'F'): + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', ' ', '0', '@'): + for sign in ('', '+', '-', ' '): + # An empty precision defaults to 6, but when uPy is + # configured to use a float, we can only use a + # precision of 6 with numbers less than 10 and still + # get results that compare to CPython (which uses + # long doubles). + for prec in ('1', '2', '3'): + for num in f_nums: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + for num in int_nums2: + test_fmt('', fill, alignment, sign, '', width, '', type, num) + +pct_nums1 = (0.1, 0.58, 0.99, -0.1, -0.58, -0.99) +pct_nums2 = (True, False, 1, 0, -1) + +if full_tests: + type = '%' + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', ' ', '0', '@'): + for sign in ('', '+', '-', ' '): + # An empty precision defaults to 6, but when uPy is + # configured to use a float, we can only use a + # precision of 6 with numbers less than 10 and still + # get results that compare to CPython (which uses + # long doubles). + for prec in ('1', '2', '3'): + for num in pct_nums1: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + for num in pct_nums2: + test_fmt('', fill, alignment, sign, '', width, '', type, num) +else: + for num in pct_nums1: + test_fmt('', '', '', '', '', '', '1', '%', num) + +# We don't currently test a type of '' with floats (see the detailed comment +# in objstr.c) diff --git a/src/openmv/src/micropython/tests/float/string_format_fp30.py b/src/openmv/src/micropython/tests/float/string_format_fp30.py new file mode 100755 index 0000000..77b2a52 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_fp30.py @@ -0,0 +1,41 @@ +def test(fmt, *args): + print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<') + +test("{:10.4}", 123.456) +test("{:10.4e}", 123.456) +test("{:10.4e}", -123.456) +#test("{:10.4f}", 123.456) +#test("{:10.4f}", -123.456) +test("{:10.4g}", 123.456) +test("{:10.4g}", -123.456) +test("{:10.4n}", 123.456) +test("{:e}", 100) +test("{:f}", 200) +test("{:g}", 300) + +test("{:10.4E}", 123.456) +test("{:10.4E}", -123.456) +#test("{:10.4F}", 123.456) +#test("{:10.4F}", -123.456) +test("{:10.4G}", 123.456) +test("{:10.4G}", -123.456) + +test("{:06e}", float("inf")) +test("{:06e}", float("-inf")) +test("{:06e}", float("nan")) + +# The following fails right now +#test("{:10.1}", 0.0) + +print("%.0f" % (1.750000 % 0.08333333333)) +# Below isn't compatible with single-precision float +#print("%.1f" % (1.750000 % 0.08333333333)) +#print("%.2f" % (1.750000 % 0.08333333333)) +#print("%.12f" % (1.750000 % 0.08333333333)) + +# tests for errors in format string + +try: + '{:10.1b}'.format(0.0) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/float/string_format_modulo.py b/src/openmv/src/micropython/tests/float/string_format_modulo.py new file mode 100755 index 0000000..aea5342 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_modulo.py @@ -0,0 +1,49 @@ +print("%s" % 1.0) +print("%r" % 1.0) + +print("%d" % 1.0) +print("%i" % 1.0) +print("%u" % 1.0) + +# these 3 have different behaviour in Python 3.x versions +# uPy raises a TypeError, following Python 3.5 (earlier versions don't) +#print("%x" % 18.0) +#print("%o" % 18.0) +#print("%X" % 18.0) + +print("%e" % 1.23456) +print("%E" % 1.23456) +print("%f" % 1.23456) +print("%F" % 1.23456) +print("%g" % 1.23456) +print("%G" % 1.23456) + +print("%06e" % float("inf")) +print("%06e" % float("-inf")) +print("%06e" % float("nan")) + +print("%02.3d" % 123) # prec > width +print("%+f %+f" % (1.23, -1.23)) # float sign +print("% f % f" % (1.23, -1.23)) # float space sign +print("%0f" % -1.23) # negative number with 0 padding + +# numbers with large negative exponents +print('%f' % 1e-10) +print('%f' % 1e-20) +print('%f' % 1e-50) +print('%f' % 1e-100) +print('%f' % 1e-300) + +# large decimal precision should be truncated and not overflow buffer +# the output depends on the FP calculation so only first 2 digits are printed +# (the 'g' with small e are printed using 'f' style, so need to be checked) +print(('%.40f' % 1e-300)[:2]) +print(('%.40g' % 1e-1)[:2]) +print(('%.40g' % 1e-2)[:2]) +print(('%.40g' % 1e-3)[:2]) +print(('%.40g' % 1e-4)[:2]) + +print("%.0g" % 1) # 0 precision 'g' + +print('%.1e' % 9.99) # round up with positive exponent +print('%.1e' % 0.999) # round up with negative exponent diff --git a/src/openmv/src/micropython/tests/float/string_format_modulo2.py b/src/openmv/src/micropython/tests/float/string_format_modulo2.py new file mode 100755 index 0000000..f6b1ae5 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_modulo2.py @@ -0,0 +1,24 @@ +# test formatting floats with large precision, that it doesn't overflow the buffer + +def test(num, num_str): + if num == float('inf') or num == 0.0 and num_str != '0.0': + # skip numbers that overflow or underflow the FP precision + return + for kind in ('e', 'f', 'g'): + # check precision either side of the size of the buffer (32 bytes) + for prec in range(23, 36, 2): + fmt = '%.' + '%d' % prec + kind + s = fmt % num + check = abs(float(s) - num) + if num > 1: + check /= num + if check > 1e-6: + print('FAIL', num_str, fmt, s, len(s), check) + +# check pure zero +test(0.0, '0.0') + +# check some powers of 10, making sure to include exponents with 3 digits +for e in range(-8, 8): + num = pow(10, e) + test(num, '1e%d' % e) diff --git a/src/openmv/src/micropython/tests/float/string_format_modulo2_intbig.py b/src/openmv/src/micropython/tests/float/string_format_modulo2_intbig.py new file mode 100755 index 0000000..9992ba6 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_modulo2_intbig.py @@ -0,0 +1,21 @@ +# test formatting floats with large precision, that it doesn't overflow the buffer + +def test(num, num_str): + if num == float('inf') or num == 0.0 and num_str != '0.0': + # skip numbers that overflow or underflow the FP precision + return + for kind in ('e', 'f', 'g'): + # check precision either side of the size of the buffer (32 bytes) + for prec in range(23, 36, 2): + fmt = '%.' + '%d' % prec + kind + s = fmt % num + check = abs(float(s) - num) + if num > 1: + check /= num + if check > 1e-6: + print('FAIL', num_str, fmt, s, len(s), check) + +# check most powers of 10, making sure to include exponents with 3 digits +for e in range(-101, 102): + num = pow(10, e) + test(num, '1e%d' % e) diff --git a/src/openmv/src/micropython/tests/float/string_format_modulo3.py b/src/openmv/src/micropython/tests/float/string_format_modulo3.py new file mode 100755 index 0000000..5d26f25 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_modulo3.py @@ -0,0 +1,3 @@ +# uPy and CPython outputs differ for the following +print("%.1g" % -9.9) # round up 'g' with '-' sign +print("%.2g" % 99.9) # round up diff --git a/src/openmv/src/micropython/tests/float/string_format_modulo3.py.exp b/src/openmv/src/micropython/tests/float/string_format_modulo3.py.exp new file mode 100755 index 0000000..71432b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/string_format_modulo3.py.exp @@ -0,0 +1,2 @@ +-10 +100 diff --git a/src/openmv/src/micropython/tests/float/true_value.py b/src/openmv/src/micropython/tests/float/true_value.py new file mode 100755 index 0000000..df415f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/true_value.py @@ -0,0 +1,7 @@ +# Test true-ish value handling + +if not 0.0: + print("float 0") + +if not 0+0j: + print("complex 0") diff --git a/src/openmv/src/micropython/tests/float/types.py b/src/openmv/src/micropython/tests/float/types.py new file mode 100755 index 0000000..75674c9 --- /dev/null +++ b/src/openmv/src/micropython/tests/float/types.py @@ -0,0 +1,17 @@ +# float types + +print(float) +print(complex) + +print(type(float()) == float) +print(type(complex()) == complex) + +print(type(0.0) == float) +print(type(1j) == complex) + +# hashing float types + +d = dict() +d[float] = complex +d[complex] = float +print(len(d)) diff --git a/src/openmv/src/micropython/tests/import/builtin_import.py b/src/openmv/src/micropython/tests/import/builtin_import.py new file mode 100755 index 0000000..088f631 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/builtin_import.py @@ -0,0 +1,16 @@ +# test calling builtin import function + +# basic test +__import__('builtins') + +# first arg should be a string +try: + __import__(1) +except TypeError: + print('TypeError') + +# level argument should be non-negative +try: + __import__('xyz', None, None, None, -1) +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/import/gen_context.py b/src/openmv/src/micropython/tests/import/gen_context.py new file mode 100755 index 0000000..02f1531 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/gen_context.py @@ -0,0 +1,9 @@ +import gen_context2 + +GLOBAL = "GLOBAL" + +def gen(): + print(GLOBAL) + yield 1 + +gen_context2.call(gen()) diff --git a/src/openmv/src/micropython/tests/import/gen_context2.py b/src/openmv/src/micropython/tests/import/gen_context2.py new file mode 100755 index 0000000..0d8048a --- /dev/null +++ b/src/openmv/src/micropython/tests/import/gen_context2.py @@ -0,0 +1,2 @@ +def call(g): + next(g) diff --git a/src/openmv/src/micropython/tests/import/import1a.py b/src/openmv/src/micropython/tests/import/import1a.py new file mode 100755 index 0000000..16b2d4d --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import1a.py @@ -0,0 +1,2 @@ +import import1b +print(import1b.var) diff --git a/src/openmv/src/micropython/tests/import/import1b.py b/src/openmv/src/micropython/tests/import/import1b.py new file mode 100755 index 0000000..be74eca --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import1b.py @@ -0,0 +1,4 @@ +var = 123 + +def throw(): + raise ValueError diff --git a/src/openmv/src/micropython/tests/import/import2a.py b/src/openmv/src/micropython/tests/import/import2a.py new file mode 100755 index 0000000..def6aeb --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import2a.py @@ -0,0 +1,5 @@ +from import1b import var +print(var) + +from import1b import var as var2 +print(var2) diff --git a/src/openmv/src/micropython/tests/import/import3a.py b/src/openmv/src/micropython/tests/import/import3a.py new file mode 100755 index 0000000..2e9d41f --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import3a.py @@ -0,0 +1,2 @@ +from import1b import * +print(var) diff --git a/src/openmv/src/micropython/tests/import/import_file.py b/src/openmv/src/micropython/tests/import/import_file.py new file mode 100755 index 0000000..cb9a88a --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_file.py @@ -0,0 +1,2 @@ +import import1b +print(import1b.__file__) diff --git a/src/openmv/src/micropython/tests/import/import_pkg1.py b/src/openmv/src/micropython/tests/import/import_pkg1.py new file mode 100755 index 0000000..fe6e447 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg1.py @@ -0,0 +1,16 @@ +import pkg.mod + +print(pkg.__name__) +print(pkg.mod.__name__) +print(pkg.mod.foo()) + +# Import 2nd time, must be same module objects +pkg_ = __import__("pkg.mod") +print(pkg_ is not pkg.mod) +print(pkg_ is pkg) +print(pkg_.mod is pkg.mod) + +# import using "as" +import pkg.mod as mm +print(mm is pkg.mod) +print(mm.foo()) diff --git a/src/openmv/src/micropython/tests/import/import_pkg2.py b/src/openmv/src/micropython/tests/import/import_pkg2.py new file mode 100755 index 0000000..2e9f341 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg2.py @@ -0,0 +1,18 @@ +from pkg.mod import foo + +try: + pkg +except NameError: + print("NameError") +try: + pkg.mod +except NameError: + print("NameError") +print(foo()) + +# Import few times, must be same module objects +mod_1 = __import__("pkg.mod", None, None, ("foo",)) +mod_2 = __import__("pkg.mod", None, None, ("foo",)) +print(mod_1 is mod_2) +print(mod_1.foo is mod_2.foo) +print(foo is mod_1.foo) diff --git a/src/openmv/src/micropython/tests/import/import_pkg3.py b/src/openmv/src/micropython/tests/import/import_pkg3.py new file mode 100755 index 0000000..0ee885b --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg3.py @@ -0,0 +1,6 @@ +from pkg import mod + +print(mod.foo()) + +import pkg.mod +print(mod is pkg.mod) diff --git a/src/openmv/src/micropython/tests/import/import_pkg4.py b/src/openmv/src/micropython/tests/import/import_pkg4.py new file mode 100755 index 0000000..90b6f2e --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg4.py @@ -0,0 +1,2 @@ +# Testing that "recursive" imports (pkg2/__init__.py imports from pkg2) work +import pkg2 diff --git a/src/openmv/src/micropython/tests/import/import_pkg5.py b/src/openmv/src/micropython/tests/import/import_pkg5.py new file mode 100755 index 0000000..aa74bb4 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg5.py @@ -0,0 +1,6 @@ +# This tests relative imports as used in pkg3 +import pkg3 +import pkg3.mod1 +import pkg3.subpkg1.mod1 + +pkg3.subpkg1.mod1.foo() diff --git a/src/openmv/src/micropython/tests/import/import_pkg6.py b/src/openmv/src/micropython/tests/import/import_pkg6.py new file mode 100755 index 0000000..3d26e6f --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg6.py @@ -0,0 +1,2 @@ +# This tests relative imports as used in pkg6 +import pkg6 diff --git a/src/openmv/src/micropython/tests/import/import_pkg7.py b/src/openmv/src/micropython/tests/import/import_pkg7.py new file mode 100755 index 0000000..e1463eb --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg7.py @@ -0,0 +1,2 @@ +# This tests ... relative imports as used in pkg7 and imports beyond package root +import pkg7.subpkg1.subpkg2.mod3 diff --git a/src/openmv/src/micropython/tests/import/import_pkg8.py b/src/openmv/src/micropython/tests/import/import_pkg8.py new file mode 100755 index 0000000..4c1e832 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/import_pkg8.py @@ -0,0 +1,2 @@ +# import with no __init__.py files +import pkg8.mod diff --git a/src/openmv/src/micropython/tests/import/module_getattr.py b/src/openmv/src/micropython/tests/import/module_getattr.py new file mode 100755 index 0000000..4a18f41 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/module_getattr.py @@ -0,0 +1,23 @@ +# test __getattr__ on module + +# ensure that does_not_exist doesn't exist to start with +this = __import__(__name__) +try: + this.does_not_exist + assert False +except AttributeError: + pass + +# define __getattr__ +def __getattr__(attr): + if attr == 'does_not_exist': + return False + raise AttributeError + +# do feature test (will also test functionality if the feature exists) +if not hasattr(this, 'does_not_exist'): + print('SKIP') + raise SystemExit + +# check that __getattr__ works as expected +print(this.does_not_exist) diff --git a/src/openmv/src/micropython/tests/import/module_getattr.py.exp b/src/openmv/src/micropython/tests/import/module_getattr.py.exp new file mode 100755 index 0000000..bc59c12 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/module_getattr.py.exp @@ -0,0 +1 @@ +False diff --git a/src/openmv/src/micropython/tests/import/mpy_invalid.py b/src/openmv/src/micropython/tests/import/mpy_invalid.py new file mode 100755 index 0000000..6a4e116 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/mpy_invalid.py @@ -0,0 +1,67 @@ +# test importing of invalid .mpy files + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + return UserFile(self.files[path]) + + +# these are the test .mpy files +user_files = { + '/mod0.mpy': b'', # empty file + '/mod1.mpy': b'M', # too short header + '/mod2.mpy': b'M\x00\x00\x00', # bad version +} + +# create and mount a user filesystem +uos.mount(UserFS(user_files), '/userfs') +sys.path.append('/userfs') + +# import .mpy files from the user filesystem +for i in range(len(user_files)): + mod = 'mod%u' % i + try: + __import__(mod) + except ValueError as er: + print(mod, 'ValueError', er) + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/src/openmv/src/micropython/tests/import/mpy_invalid.py.exp b/src/openmv/src/micropython/tests/import/mpy_invalid.py.exp new file mode 100755 index 0000000..1727ea1 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/mpy_invalid.py.exp @@ -0,0 +1,3 @@ +mod0 ValueError incompatible .mpy file +mod1 ValueError incompatible .mpy file +mod2 ValueError incompatible .mpy file diff --git a/src/openmv/src/micropython/tests/import/pkg/__init__.py b/src/openmv/src/micropython/tests/import/pkg/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/import/pkg/mod.py b/src/openmv/src/micropython/tests/import/pkg/mod.py new file mode 100755 index 0000000..9e67bdd --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg/mod.py @@ -0,0 +1,2 @@ +def foo(): + return 42 diff --git a/src/openmv/src/micropython/tests/import/pkg2/__init__.py b/src/openmv/src/micropython/tests/import/pkg2/__init__.py new file mode 100755 index 0000000..101ac7d --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg2/__init__.py @@ -0,0 +1 @@ +from pkg2 import mod1 diff --git a/src/openmv/src/micropython/tests/import/pkg2/mod1.py b/src/openmv/src/micropython/tests/import/pkg2/mod1.py new file mode 100755 index 0000000..03754a4 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg2/mod1.py @@ -0,0 +1 @@ +from pkg2 import mod2 diff --git a/src/openmv/src/micropython/tests/import/pkg2/mod2.py b/src/openmv/src/micropython/tests/import/pkg2/mod2.py new file mode 100755 index 0000000..97dadcd --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg2/mod2.py @@ -0,0 +1 @@ +print("in mod2") diff --git a/src/openmv/src/micropython/tests/import/pkg3/__init__.py b/src/openmv/src/micropython/tests/import/pkg3/__init__.py new file mode 100755 index 0000000..8b92fa9 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg3/__init__.py @@ -0,0 +1 @@ +print("pkg __name__:", __name__) diff --git a/src/openmv/src/micropython/tests/import/pkg3/mod1.py b/src/openmv/src/micropython/tests/import/pkg3/mod1.py new file mode 100755 index 0000000..28a0f5b --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg3/mod1.py @@ -0,0 +1,2 @@ +print("mod1 __name__:", __name__) +from . import mod2 diff --git a/src/openmv/src/micropython/tests/import/pkg3/mod2.py b/src/openmv/src/micropython/tests/import/pkg3/mod2.py new file mode 100755 index 0000000..67f43ba --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg3/mod2.py @@ -0,0 +1,5 @@ +print("mod2 __name__:", __name__) +print("in mod2") + +def foo(): + print("mod2.foo()") diff --git a/src/openmv/src/micropython/tests/import/pkg3/subpkg1/__init__.py b/src/openmv/src/micropython/tests/import/pkg3/subpkg1/__init__.py new file mode 100755 index 0000000..72b5423 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg3/subpkg1/__init__.py @@ -0,0 +1 @@ +print("subpkg1 __name__:", __name__) diff --git a/src/openmv/src/micropython/tests/import/pkg3/subpkg1/mod1.py b/src/openmv/src/micropython/tests/import/pkg3/subpkg1/mod1.py new file mode 100755 index 0000000..7a2ae44 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg3/subpkg1/mod1.py @@ -0,0 +1,2 @@ +print("subpkg1.mod1 __name__:", __name__) +from ..mod2 import foo diff --git a/src/openmv/src/micropython/tests/import/pkg6/__init__.py b/src/openmv/src/micropython/tests/import/pkg6/__init__.py new file mode 100755 index 0000000..923531c --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg6/__init__.py @@ -0,0 +1,2 @@ +from .x import * +print('init') diff --git a/src/openmv/src/micropython/tests/import/pkg6/x/__init__.py b/src/openmv/src/micropython/tests/import/pkg6/x/__init__.py new file mode 100755 index 0000000..6b8b84d --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg6/x/__init__.py @@ -0,0 +1,2 @@ +from .y import * +print('x') diff --git a/src/openmv/src/micropython/tests/import/pkg6/x/y.py b/src/openmv/src/micropython/tests/import/pkg6/x/y.py new file mode 100755 index 0000000..e8d863c --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg6/x/y.py @@ -0,0 +1 @@ +print('y') diff --git a/src/openmv/src/micropython/tests/import/pkg7/__init__.py b/src/openmv/src/micropython/tests/import/pkg7/__init__.py new file mode 100755 index 0000000..8b92fa9 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/__init__.py @@ -0,0 +1 @@ +print("pkg __name__:", __name__) diff --git a/src/openmv/src/micropython/tests/import/pkg7/mod1.py b/src/openmv/src/micropython/tests/import/pkg7/mod1.py new file mode 100755 index 0000000..6b57411 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/mod1.py @@ -0,0 +1,2 @@ +print('mod1') +foo = 'mod1.foo' diff --git a/src/openmv/src/micropython/tests/import/pkg7/mod2.py b/src/openmv/src/micropython/tests/import/pkg7/mod2.py new file mode 100755 index 0000000..039a5d1 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/mod2.py @@ -0,0 +1,2 @@ +print('mod2') +bar = 'mod2.bar' diff --git a/src/openmv/src/micropython/tests/import/pkg7/subpkg1/__init__.py b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/__init__.py new file mode 100755 index 0000000..8b92fa9 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/__init__.py @@ -0,0 +1 @@ +print("pkg __name__:", __name__) diff --git a/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/__init__.py b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/__init__.py new file mode 100755 index 0000000..8b92fa9 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/__init__.py @@ -0,0 +1 @@ +print("pkg __name__:", __name__) diff --git a/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/mod3.py b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/mod3.py new file mode 100755 index 0000000..c73e208 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg7/subpkg1/subpkg2/mod3.py @@ -0,0 +1,10 @@ +from ... import mod1 +from ...mod2 import bar +print(mod1.foo) +print(bar) + +# attempted relative import beyond top-level package +try: + from .... import mod1 +except ValueError: + print('ValueError') diff --git a/src/openmv/src/micropython/tests/import/pkg8/mod.py b/src/openmv/src/micropython/tests/import/pkg8/mod.py new file mode 100755 index 0000000..b98f02c --- /dev/null +++ b/src/openmv/src/micropython/tests/import/pkg8/mod.py @@ -0,0 +1 @@ +print('foo') diff --git a/src/openmv/src/micropython/tests/import/rel_import_inv.py b/src/openmv/src/micropython/tests/import/rel_import_inv.py new file mode 100755 index 0000000..1f3b35e --- /dev/null +++ b/src/openmv/src/micropython/tests/import/rel_import_inv.py @@ -0,0 +1,4 @@ +try: + from . import foo +except: + print("Invalid relative import caught") diff --git a/src/openmv/src/micropython/tests/import/try_module.py b/src/openmv/src/micropython/tests/import/try_module.py new file mode 100755 index 0000000..03a9db1 --- /dev/null +++ b/src/openmv/src/micropython/tests/import/try_module.py @@ -0,0 +1,15 @@ +# Regression test for #290 - throwing exception in another module led to +# its namespace stick and namespace of current module not coming back. +import import1b + +def func1(): + print('func1') + +def func2(): + try: + import1b.throw() + except ValueError: + pass + func1() + +func2() diff --git a/src/openmv/src/micropython/tests/inlineasm/asmargs.py b/src/openmv/src/micropython/tests/inlineasm/asmargs.py new file mode 100755 index 0000000..047d9ed --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmargs.py @@ -0,0 +1,29 @@ +# test passing arguments + +@micropython.asm_thumb +def arg0(): + mov(r0, 1) +print(arg0()) + +@micropython.asm_thumb +def arg1(r0): + add(r0, r0, 1) +print(arg1(1)) + +@micropython.asm_thumb +def arg2(r0, r1): + add(r0, r0, r1) +print(arg2(1, 2)) + +@micropython.asm_thumb +def arg3(r0, r1, r2): + add(r0, r0, r1) + add(r0, r0, r2) +print(arg3(1, 2, 3)) + +@micropython.asm_thumb +def arg4(r0, r1, r2, r3): + add(r0, r0, r1) + add(r0, r0, r2) + add(r0, r0, r3) +print(arg4(1, 2, 3, 4)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmargs.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmargs.py.exp new file mode 100755 index 0000000..e33a696 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmargs.py.exp @@ -0,0 +1,5 @@ +1 +2 +3 +6 +10 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmbcc.py b/src/openmv/src/micropython/tests/inlineasm/asmbcc.py new file mode 100755 index 0000000..540fa65 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmbcc.py @@ -0,0 +1,27 @@ +# test bcc instructions +# at the moment only tests beq, narrow and wide versions + +@micropython.asm_thumb +def f(r0): + mov(r1, r0) + + mov(r0, 10) + cmp(r1, 1) + beq(end) + + mov(r0, 20) + cmp(r1, 2) + beq_n(end) + + mov(r0, 30) + cmp(r1, 3) + beq_w(end) + + mov(r0, 0) + + label(end) + +print(f(0)) +print(f(1)) +print(f(2)) +print(f(3)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmbcc.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmbcc.py.exp new file mode 100755 index 0000000..39da7d1 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmbcc.py.exp @@ -0,0 +1,4 @@ +0 +10 +20 +30 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmbitops.py b/src/openmv/src/micropython/tests/inlineasm/asmbitops.py new file mode 100755 index 0000000..8cf92b3 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmbitops.py @@ -0,0 +1,13 @@ +@micropython.asm_thumb +def clz(r0): + clz(r0, r0) + +print(clz(0xf0)) +print(clz(0x8000)) + +@micropython.asm_thumb +def rbit(r0): + rbit(r0, r0) + +print(hex(rbit(0xf0))) +print(hex(rbit(0x8000))) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmbitops.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmbitops.py.exp new file mode 100755 index 0000000..8c56004 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmbitops.py.exp @@ -0,0 +1,4 @@ +24 +16 +0xf000000 +0x10000 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmblbx.py b/src/openmv/src/micropython/tests/inlineasm/asmblbx.py new file mode 100755 index 0000000..d08c0ed --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmblbx.py @@ -0,0 +1,21 @@ +# test bl and bx instructions + +@micropython.asm_thumb +def f(r0): + # jump over the internal functions + b(entry) + + label(func1) + add(r0, 2) + bx(lr) + + label(func2) + sub(r0, 1) + bx(lr) + + label(entry) + bl(func1) + bl(func2) + +print(f(0)) +print(f(1)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmblbx.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmblbx.py.exp new file mode 100755 index 0000000..1191247 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmblbx.py.exp @@ -0,0 +1,2 @@ +1 +2 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmconst.py b/src/openmv/src/micropython/tests/inlineasm/asmconst.py new file mode 100755 index 0000000..299a250 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmconst.py @@ -0,0 +1,8 @@ +# test constants in assembler + +@micropython.asm_thumb +def c1(): + movwt(r0, 0xffffffff) + movwt(r1, 0xf0000000) + sub(r0, r0, r1) +print(hex(c1())) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmconst.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmconst.py.exp new file mode 100755 index 0000000..3ef9fca --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmconst.py.exp @@ -0,0 +1 @@ +0xfffffff diff --git a/src/openmv/src/micropython/tests/inlineasm/asmdiv.py b/src/openmv/src/micropython/tests/inlineasm/asmdiv.py new file mode 100755 index 0000000..b97d566 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmdiv.py @@ -0,0 +1,16 @@ +@micropython.asm_thumb +def sdiv(r0, r1): + sdiv(r0, r0, r1) + +@micropython.asm_thumb +def udiv(r0, r1): + udiv(r0, r0, r1) + +print(sdiv(1234, 3)) +print(sdiv(-1234, 3)) +print(sdiv(1234, -3)) +print(sdiv(-1234, -3)) + +print(udiv(1234, 3)) +print(udiv(0xffffffff, 0x7fffffff)) +print(udiv(0xffffffff, 0xffffffff)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmdiv.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmdiv.py.exp new file mode 100755 index 0000000..f1b80de --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmdiv.py.exp @@ -0,0 +1,7 @@ +411 +-411 +-411 +411 +411 +2 +1 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py b/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py new file mode 100755 index 0000000..b5fcecb --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py @@ -0,0 +1,15 @@ +@micropython.asm_thumb # r0 = r0+r1-r2 +def add_sub(r0, r1, r2): + vmov(s0, r0) + vcvt_f32_s32(s0, s0) + vmov(s1, r1) + vcvt_f32_s32(s1, s1) + vmov(s2, r2) + vcvt_f32_s32(s2, s2) + vadd(s0, s0, s1) + vsub(s0, s0, s2) + vcvt_s32_f32(s31, s0) + vmov(r0, s31) + +print(add_sub(100, 20, 30)) + diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py.exp new file mode 100755 index 0000000..d61f00d --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpaddsub.py.exp @@ -0,0 +1 @@ +90 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py b/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py new file mode 100755 index 0000000..d4fa1f2 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py @@ -0,0 +1,14 @@ +@micropython.asm_thumb # test vcmp, vmrs +def f(r0, r1): + vmov(s0, r0) + vcvt_f32_s32(s0, s0) + vmov(s1, r1) + vcvt_f32_s32(s1, s1) + vcmp(s1, s0) + vmrs(r0, FPSCR) + mov(r1, 28) + lsr(r0, r1) + +print(f(0,1)) +print(f(1,1)) +print(f(1,0)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py.exp new file mode 100755 index 0000000..104b358 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpcmp.py.exp @@ -0,0 +1,3 @@ +2 +6 +8 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py b/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py new file mode 100755 index 0000000..8fa9af6 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py @@ -0,0 +1,12 @@ +import array +@micropython.asm_thumb # test vldr, vstr +def arrayadd(r0): + vldr(s0, [r0, 0]) + vldr(s1, [r0, 4]) + vadd(s2, s0, s1) + vstr(s2, [r0, 8]) + +z = array.array("f", [2, 4, 10]) +arrayadd(z) +print(z[2]) + diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py.exp new file mode 100755 index 0000000..e0ea36f --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpldrstr.py.exp @@ -0,0 +1 @@ +6.0 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py b/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py new file mode 100755 index 0000000..edf9511 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py @@ -0,0 +1,15 @@ +@micropython.asm_thumb # r0 = (int)(r0*r1/r2) +def muldiv(r0, r1, r2): + vmov(s0, r0) + vcvt_f32_s32(s0, s0) + vmov(s1, r1) + vcvt_f32_s32(s1, s1) + vmov(s2, r2) + vcvt_f32_s32(s2, s2) + vmul(s7, s0, s1) + vdiv(s8, s7, s2) + vcvt_s32_f32(s31, s8) + vmov(r0, s31) + +print(muldiv(100, 10, 50)) + diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py.exp new file mode 100755 index 0000000..209e3ef --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpmuldiv.py.exp @@ -0,0 +1 @@ +20 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py b/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py new file mode 100755 index 0000000..f2c2d3a --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py @@ -0,0 +1,15 @@ +# test vsqrt, vneg +@micropython.asm_thumb # r0 = -(int)(sqrt(r0)*r1) +def sqrt_test(r0, r1): + vmov(s1, r0) + vcvt_f32_s32(s1, s1) + vsqrt(s1, s1) + vmov(s2, r1) + vcvt_f32_s32(s2, s2) + vmul(s0, s1, s2) + vneg(s7, s0) + vcvt_s32_f32(s31, s7) + vmov(r0, s31) + +print(sqrt_test(256, 10)) + diff --git a/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py.exp new file mode 100755 index 0000000..88a1e93 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmfpsqrt.py.exp @@ -0,0 +1 @@ +-160 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmit.py b/src/openmv/src/micropython/tests/inlineasm/asmit.py new file mode 100755 index 0000000..57bfcc7 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmit.py @@ -0,0 +1,16 @@ +# test it instruction + +@micropython.asm_thumb +def f(r0, r1): + cmp(r0, r1) + it(eq) + mov(r0, 100) +print(f(0, 0), f(1, 2)) + +@micropython.asm_thumb +def g(r0, r1): + cmp(r0, r1) + ite(eq) + mov(r0, 100) + mov(r0, 200) +print(g(0, 0), g(0, 1)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmit.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmit.py.exp new file mode 100755 index 0000000..d06c72d --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmit.py.exp @@ -0,0 +1,2 @@ +100 1 +100 200 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py b/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py new file mode 100755 index 0000000..c900543 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py @@ -0,0 +1,8 @@ +@micropython.asm_thumb +def f(r0, r1, r2): + push({r0}) + push({r1, r2}) + pop({r0}) + pop({r1, r2}) + +print(f(0, 1, 2)) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py.exp new file mode 100755 index 0000000..d00491f --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmpushpop.py.exp @@ -0,0 +1 @@ +1 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmrettype.py b/src/openmv/src/micropython/tests/inlineasm/asmrettype.py new file mode 100755 index 0000000..f191869 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmrettype.py @@ -0,0 +1,21 @@ +# test return type of inline asm + +@micropython.asm_thumb +def ret_obj(r0) -> object: + pass +ret_obj(print)(1) + +@micropython.asm_thumb +def ret_bool(r0) -> bool: + pass +print(ret_bool(0), ret_bool(1)) + +@micropython.asm_thumb +def ret_int(r0) -> int: + lsl(r0, r0, 29) +print(ret_int(0), hex(ret_int(1)), hex(ret_int(2)), hex(ret_int(4))) + +@micropython.asm_thumb +def ret_uint(r0) -> uint: + lsl(r0, r0, 29) +print(ret_uint(0), hex(ret_uint(1)), hex(ret_uint(2)), hex(ret_uint(4))) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmrettype.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmrettype.py.exp new file mode 100755 index 0000000..cbb49d2 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmrettype.py.exp @@ -0,0 +1,4 @@ +1 +False True +0 0x20000000 0x40000000 -0x80000000 +0 0x20000000 0x40000000 0x80000000 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmshift.py b/src/openmv/src/micropython/tests/inlineasm/asmshift.py new file mode 100755 index 0000000..0df2187 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmshift.py @@ -0,0 +1,29 @@ +@micropython.asm_thumb +def lsl1(r0): + lsl(r0, r0, 1) +print(hex(lsl1(0x123))) + +@micropython.asm_thumb +def lsl23(r0): + lsl(r0, r0, 23) +print(hex(lsl23(1))) + +@micropython.asm_thumb +def lsr1(r0): + lsr(r0, r0, 1) +print(hex(lsr1(0x123))) + +@micropython.asm_thumb +def lsr31(r0): + lsr(r0, r0, 31) +print(hex(lsr31(0x80000000))) + +@micropython.asm_thumb +def asr1(r0): + asr(r0, r0, 1) +print(hex(asr1(0x123))) + +@micropython.asm_thumb +def asr31(r0): + asr(r0, r0, 31) +print(hex(asr31(0x80000000))) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmshift.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmshift.py.exp new file mode 100755 index 0000000..c6c3a72 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmshift.py.exp @@ -0,0 +1,6 @@ +0x246 +0x800000 +0x91 +0x1 +0x91 +-0x1 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py b/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py new file mode 100755 index 0000000..edfe4c2 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py @@ -0,0 +1,11 @@ +@micropython.asm_thumb +def getIPSR(): + mrs(r0, IPSR) + +@micropython.asm_thumb +def getBASEPRI(): + mrs(r0, BASEPRI) + +print(getBASEPRI()) +print(getIPSR()) + diff --git a/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py.exp new file mode 100755 index 0000000..aa47d0d --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmspecialregs.py.exp @@ -0,0 +1,2 @@ +0 +0 diff --git a/src/openmv/src/micropython/tests/inlineasm/asmsum.py b/src/openmv/src/micropython/tests/inlineasm/asmsum.py new file mode 100755 index 0000000..07e71c7 --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmsum.py @@ -0,0 +1,57 @@ +@micropython.asm_thumb +def asm_sum_words(r0, r1): + + # r0 = len + # r1 = ptr + # r2 = sum + # r3 = dummy + mov(r2, 0) + + b(loop_entry) + + label(loop1) + ldr(r3, [r1, 0]) + add(r2, r2, r3) + + add(r1, r1, 4) + sub(r0, r0, 1) + + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + + mov(r0, r2) + +@micropython.asm_thumb +def asm_sum_bytes(r0, r1): + + # r0 = len + # r1 = ptr + # r2 = sum + # r3 = dummy + mov(r2, 0) + + b(loop_entry) + + label(loop1) + ldrb(r3, [r1, 0]) + add(r2, r2, r3) + + add(r1, r1, 1) + sub(r0, r0, 1) + + label(loop_entry) + cmp(r0, 0) + bgt(loop1) + + mov(r0, r2) + +import array + +b = array.array('l', (100, 200, 300, 400)) +n = asm_sum_words(len(b), b) +print(b, n) + +b = array.array('b', (10, 20, 30, 40, 50, 60, 70, 80)) +n = asm_sum_bytes(len(b), b) +print(b, n) diff --git a/src/openmv/src/micropython/tests/inlineasm/asmsum.py.exp b/src/openmv/src/micropython/tests/inlineasm/asmsum.py.exp new file mode 100755 index 0000000..d50a94c --- /dev/null +++ b/src/openmv/src/micropython/tests/inlineasm/asmsum.py.exp @@ -0,0 +1,2 @@ +array('l', [100, 200, 300, 400]) 1000 +array('b', [10, 20, 30, 40, 50, 60, 70, 80]) 360 diff --git a/src/openmv/src/micropython/tests/io/argv.py b/src/openmv/src/micropython/tests/io/argv.py new file mode 100755 index 0000000..a13f2ca --- /dev/null +++ b/src/openmv/src/micropython/tests/io/argv.py @@ -0,0 +1,2 @@ +import sys +print(sys.argv) diff --git a/src/openmv/src/micropython/tests/io/builtin_print_file.py b/src/openmv/src/micropython/tests/io/builtin_print_file.py new file mode 100755 index 0000000..d9b8e2a --- /dev/null +++ b/src/openmv/src/micropython/tests/io/builtin_print_file.py @@ -0,0 +1,17 @@ +# test builtin print function, using file= argument + +import sys + +try: + sys.stdout +except AttributeError: + print('SKIP') + raise SystemExit + +print(file=sys.stdout) +print('test', file=sys.stdout) + +try: + print(file=1) +except (AttributeError, OSError): # CPython and uPy differ in error message + print('Error') diff --git a/src/openmv/src/micropython/tests/io/data/bigfile1 b/src/openmv/src/micropython/tests/io/data/bigfile1 new file mode 100755 index 0000000..5afbf01 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/data/bigfile1 @@ -0,0 +1,148 @@ +{ + "info": { + "maintainer": null, + "docs_url": "", + "requires_python": null, + "maintainer_email": null, + "cheesecake_code_kwalitee_id": null, + "keywords": null, + "package_url": "http://pypi.python.org/pypi/micropython-uasyncio", + "author": "MicroPython Developers", + "author_email": "micro-python@googlegroups.com", + "download_url": "UNKNOWN", + "platform": "UNKNOWN", + "version": "0.8.1", + "cheesecake_documentation_id": null, + "_pypi_hidden": false, + "description": "Lightweight asyncio-like library built around native Python coroutines, not around un-Python devices like callback mess.", + "release_url": "http://pypi.python.org/pypi/micropython-uasyncio/0.8.1", + "downloads": { + "last_month": 942, + "last_week": 173, + "last_day": 29 + }, + "_pypi_ordering": 6, + "classifiers": [], + "name": "micropython-uasyncio", + "bugtrack_url": null, + "license": "MIT", + "summary": "uasyncio module for MicroPython", + "home_page": "https://github.com/micropython/micropython/issues/405", + "stable_version": null, + "cheesecake_installability_id": null + }, + "releases": { + "0.8": [ + { + "has_sig": false, + "upload_time": "2015-01-01T23:52:41", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.8.tar.gz", + "md5_digest": "5df4d0d6b5fdb7c05fc418e5785e1336", + "downloads": 352, + "filename": "micropython-uasyncio-0.8.tar.gz", + "packagetype": "sdist", + "size": 2476 + } + ], + "0.6.2": [ + { + "has_sig": false, + "upload_time": "2014-10-18T11:26:52", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.6.2.tar.gz", + "md5_digest": "c85fa7c11ef437f4e73c1fcd639db066", + "downloads": 475, + "filename": "micropython-uasyncio-0.6.2.tar.gz", + "packagetype": "sdist", + "size": 3262 + } + ], + "0.6.1": [ + { + "has_sig": false, + "upload_time": "2014-10-11T02:21:17", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.6.1.tar.gz", + "md5_digest": "48cb0db7d8249d5f4a86db9c4b302d03", + "downloads": 507, + "filename": "micropython-uasyncio-0.6.1.tar.gz", + "packagetype": "sdist", + "size": 3237 + } + ], + "0.8.1": [ + { + "has_sig": false, + "upload_time": "2015-01-04T20:02:03", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.8.1.tar.gz", + "md5_digest": "940d2647b8355289d54de543ff710b05", + "downloads": 249, + "filename": "micropython-uasyncio-0.8.1.tar.gz", + "packagetype": "sdist", + "size": 2484 + } + ], + "0.7": [ + { + "has_sig": false, + "upload_time": "2014-10-23T22:02:11", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.7.tar.gz", + "md5_digest": "81250a0ee6649b5117878d5788ba96d3", + "downloads": 457, + "filename": "micropython-uasyncio-0.7.tar.gz", + "packagetype": "sdist", + "size": 2277 + } + ], + "0.7.1": [ + { + "has_sig": false, + "upload_time": "2014-11-04T00:56:16", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.7.1.tar.gz", + "md5_digest": "21eda0501142830730cd82e1b0fa1a33", + "downloads": 412, + "filename": "micropython-uasyncio-0.7.1.tar.gz", + "packagetype": "sdist", + "size": 2474 + } + ], + "0.6": [ + { + "has_sig": false, + "upload_time": "2014-08-27T00:17:45", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.6.tar.gz", + "md5_digest": "9d0b15108c5ade3a6902c9370c9dacf1", + "downloads": 668, + "filename": "micropython-uasyncio-0.6.tar.gz", + "packagetype": "sdist", + "size": 3246 + } + ] + }, + "urls": [ + { + "has_sig": false, + "upload_time": "2015-01-04T20:02:03", + "comment_text": "", + "python_version": "source", + "url": "https://pypi.python.org/packages/source/m/micropython-uasyncio/micropython-uasyncio-0.8.1.tar.gz", + "md5_digest": "940d2647b8355289d54de543ff710b05", + "downloads": 249, + "filename": "micropython-uasyncio-0.8.1.tar.gz", + "packagetype": "sdist", + "size": 2484 + } + ] +} \ No newline at end of file diff --git a/src/openmv/src/micropython/tests/io/data/file1 b/src/openmv/src/micropython/tests/io/data/file1 new file mode 100755 index 0000000..e082063 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/data/file1 @@ -0,0 +1,3 @@ +longer line1 +line2 +line3 diff --git a/src/openmv/src/micropython/tests/io/data/file2 b/src/openmv/src/micropython/tests/io/data/file2 new file mode 100755 index 0000000..274c005 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/data/file2 @@ -0,0 +1 @@ +1234 \ No newline at end of file diff --git a/src/openmv/src/micropython/tests/io/file1.py b/src/openmv/src/micropython/tests/io/file1.py new file mode 100755 index 0000000..af4176b --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file1.py @@ -0,0 +1,46 @@ +f = open("io/data/file1") +print(f.read(5)) +print(f.readline()) +print(f.read()) +f = open("io/data/file1") +print(f.readlines()) +f = open("io/data/file1","r") +print(f.readlines()) +f = open("io/data/file1","rb") +print(f.readlines()) +f = open("io/data/file1",mode="r") +print(f.readlines()) +f = open("io/data/file1",mode="rb") +print(f.readlines()) + +# write() error +f = open('io/data/file1', 'r') +try: + f.write('x') +except OSError: + print('OSError') +f.close() + +# read(n) error on binary file +f = open('io/data/file1', 'ab') +try: + f.read(1) +except OSError: + print('OSError') +f.close() + +# read(n) error on text file +f = open('io/data/file1', 'at') +try: + f.read(1) +except OSError: + print('OSError') +f.close() + +# read() w/o args error +f = open('io/data/file1', 'ab') +try: + f.read() +except OSError: + print('OSError') +f.close() diff --git a/src/openmv/src/micropython/tests/io/file_iter.py b/src/openmv/src/micropython/tests/io/file_iter.py new file mode 100755 index 0000000..48e8739 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_iter.py @@ -0,0 +1,3 @@ +f = open("io/data/file1") +for l in f: + print(l) diff --git a/src/openmv/src/micropython/tests/io/file_long_read.py b/src/openmv/src/micropython/tests/io/file_long_read.py new file mode 100755 index 0000000..8bdd484 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_long_read.py @@ -0,0 +1,3 @@ +f = open("io/data/file1") +b = f.read(100) +print(len(b)) diff --git a/src/openmv/src/micropython/tests/io/file_long_read2.py b/src/openmv/src/micropython/tests/io/file_long_read2.py new file mode 100755 index 0000000..337a5fb --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_long_read2.py @@ -0,0 +1,4 @@ +f = open("io/data/bigfile1") +b = f.read() +print(len(b)) +print(b) diff --git a/src/openmv/src/micropython/tests/io/file_long_read3.py b/src/openmv/src/micropython/tests/io/file_long_read3.py new file mode 100755 index 0000000..d8b0cce --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_long_read3.py @@ -0,0 +1,4 @@ +f = open("io/data/bigfile1", "rb") +b = f.read(512) +print(len(b)) +print(b) diff --git a/src/openmv/src/micropython/tests/io/file_readinto.py b/src/openmv/src/micropython/tests/io/file_readinto.py new file mode 100755 index 0000000..cbefc6e --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_readinto.py @@ -0,0 +1,14 @@ +b = bytearray(30) +f = open("io/data/file1", "rb") +print(f.readinto(b)) +print(b) +f = open("io/data/file2", "rb") +print(f.readinto(b)) +print(b) + +# readinto() on writable file +f = open('io/data/file1', 'ab') +try: + f.readinto(bytearray(4)) +except OSError: + print('OSError') diff --git a/src/openmv/src/micropython/tests/io/file_readinto_len.py b/src/openmv/src/micropython/tests/io/file_readinto_len.py new file mode 100755 index 0000000..84cc8cf --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_readinto_len.py @@ -0,0 +1,10 @@ +b = bytearray(30) +f = open("io/data/file1", "rb") +# 2nd arg (length to read) is extension to CPython +print(f.readinto(b, 8)) +print(b) + +b = bytearray(4) +f = open("io/data/file1", "rb") +print(f.readinto(b, 8)) +print(b) diff --git a/src/openmv/src/micropython/tests/io/file_readinto_len.py.exp b/src/openmv/src/micropython/tests/io/file_readinto_len.py.exp new file mode 100755 index 0000000..a787711 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_readinto_len.py.exp @@ -0,0 +1,4 @@ +8 +bytearray(b'longer l\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +4 +bytearray(b'long') diff --git a/src/openmv/src/micropython/tests/io/file_readline.py b/src/openmv/src/micropython/tests/io/file_readline.py new file mode 100755 index 0000000..25e7659 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_readline.py @@ -0,0 +1,14 @@ +f = open("io/data/file1") +print(f.readline()) +print(f.readline(3)) +print(f.readline(4)) +print(f.readline(5)) +print(f.readline()) + +# readline() on writable file +f = open('io/data/file1', 'ab') +try: + f.readline() +except OSError: + print('OSError') +f.close() diff --git a/src/openmv/src/micropython/tests/io/file_seek.py b/src/openmv/src/micropython/tests/io/file_seek.py new file mode 100755 index 0000000..10fb1fd --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_seek.py @@ -0,0 +1,34 @@ +f = open("io/data/file1", "rb") +print(f.seek(6)) +print(f.read(5)) +print(f.tell()) + +print(f.seek(0, 1)) +print(f.read(4)) +print(f.tell()) + +print(f.seek(-6, 2)) +print(f.read(20)) +print(f.tell()) + +print(f.seek(0, 0)) +print(f.read(5)) +print(f.tell()) + +f.close() + +# test text mode +f = open("io/data/file1", "rt") +print(f.seek(6)) +print(f.read(5)) +print(f.tell()) +f.close() + +# seek closed file +f = open('io/data/file1', 'r') +f.close() +try: + f.seek(1) +except (OSError, ValueError): + # CPy raises ValueError, uPy raises OSError + print('OSError or ValueError') diff --git a/src/openmv/src/micropython/tests/io/file_stdio.py b/src/openmv/src/micropython/tests/io/file_stdio.py new file mode 100755 index 0000000..cbdb070 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_stdio.py @@ -0,0 +1,4 @@ +import sys + +print(sys.stdin.fileno()) +print(sys.stdout.fileno()) diff --git a/src/openmv/src/micropython/tests/io/file_with.py b/src/openmv/src/micropython/tests/io/file_with.py new file mode 100755 index 0000000..ee1e702 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/file_with.py @@ -0,0 +1,21 @@ +f = open("io/data/file1") + +with f as f2: + print(f2.read()) + +# File should be closed +try: + f.read() +except: + # Note: CPython and us throw different exception trying to read from + # close file. + print("can't read file after with") + + +# Regression test: test that exception in with initialization properly +# thrown and doesn't crash. +try: + with open('__non_existent', 'r'): + pass +except OSError: + print("OSError") diff --git a/src/openmv/src/micropython/tests/io/open_append.py b/src/openmv/src/micropython/tests/io/open_append.py new file mode 100755 index 0000000..a696823 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/open_append.py @@ -0,0 +1,37 @@ +try: + import uos as os +except ImportError: + import os + +if not hasattr(os, "unlink"): + print("SKIP") + raise SystemExit + +# cleanup in case testfile exists +try: + os.unlink("testfile") +except OSError: + pass + +# Should create a file +f = open("testfile", "a") +f.write("foo") +f.close() + +f = open("testfile") +print(f.read()) +f.close() + +f = open("testfile", "a") +f.write("bar") +f.close() + +f = open("testfile") +print(f.read()) +f.close() + +# cleanup +try: + os.unlink("testfile") +except OSError: + pass diff --git a/src/openmv/src/micropython/tests/io/open_plus.py b/src/openmv/src/micropython/tests/io/open_plus.py new file mode 100755 index 0000000..bba96fa --- /dev/null +++ b/src/openmv/src/micropython/tests/io/open_plus.py @@ -0,0 +1,47 @@ +try: + import uos as os +except ImportError: + import os + +if not hasattr(os, "unlink"): + print("SKIP") + raise SystemExit + +# cleanup in case testfile exists +try: + os.unlink("testfile") +except OSError: + pass + +try: + f = open("testfile", "r+b") + print("Unexpectedly opened non-existing file") +except OSError: + print("Expected OSError") + pass + +f = open("testfile", "w+b") +f.write(b"1234567890") +f.seek(0) +print(f.read()) +f.close() + +# Open with truncation +f = open("testfile", "w+b") +f.write(b"abcdefg") +f.seek(0) +print(f.read()) +f.close() + +# Open without truncation +f = open("testfile", "r+b") +f.write(b"1234") +f.seek(0) +print(f.read()) +f.close() + +# cleanup +try: + os.unlink("testfile") +except OSError: + pass diff --git a/src/openmv/src/micropython/tests/io/resource_stream.py b/src/openmv/src/micropython/tests/io/resource_stream.py new file mode 100755 index 0000000..37d985b --- /dev/null +++ b/src/openmv/src/micropython/tests/io/resource_stream.py @@ -0,0 +1,15 @@ +import uio +import sys + +try: + uio.resource_stream +except AttributeError: + print('SKIP') + raise SystemExit + +buf = uio.resource_stream("data", "file2") +print(buf.read()) + +# resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack +buf = uio.resource_stream(None, sys.path[0] + "/data/file2") +print(buf.read()) diff --git a/src/openmv/src/micropython/tests/io/resource_stream.py.exp b/src/openmv/src/micropython/tests/io/resource_stream.py.exp new file mode 100755 index 0000000..75404a3 --- /dev/null +++ b/src/openmv/src/micropython/tests/io/resource_stream.py.exp @@ -0,0 +1,2 @@ +1234 +1234 diff --git a/src/openmv/src/micropython/tests/jni/README b/src/openmv/src/micropython/tests/jni/README new file mode 100755 index 0000000..8418bb8 --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/README @@ -0,0 +1,12 @@ +Running "jni" module tests (as well as just using this module) requires +being able to load libjvm.so, which requires path to it set via +LD_LIBRARY_PATH environment variable. This path is not set automatically +and there is no easy way to guess it, because there can be installed +different implementations of JVM, for one implementation, there can be +different versions, and single version may include different variants +of JVM. + +For example, for OpenJDK 7 on x86_64, following may work: + +LD_LIBRARY_PATH=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server ./run-tests jni/*.py + diff --git a/src/openmv/src/micropython/tests/jni/list.py b/src/openmv/src/micropython/tests/jni/list.py new file mode 100755 index 0000000..d58181d --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/list.py @@ -0,0 +1,15 @@ +import jni +try: + ArrayList = jni.cls("java/util/ArrayList") +except: + print("SKIP") + raise SystemExit + +l = ArrayList() +print(l) +l.add("one") +l.add("two") + +print(l.toString()) +print(l) +print(l[0], l[1]) diff --git a/src/openmv/src/micropython/tests/jni/list.py.exp b/src/openmv/src/micropython/tests/jni/list.py.exp new file mode 100755 index 0000000..cc34bb0 --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/list.py.exp @@ -0,0 +1,4 @@ +[] +[one, two] +[one, two] +one two diff --git a/src/openmv/src/micropython/tests/jni/object.py b/src/openmv/src/micropython/tests/jni/object.py new file mode 100755 index 0000000..aa67615 --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/object.py @@ -0,0 +1,15 @@ +import jni +try: + Integer = jni.cls("java/lang/Integer") +except: + print("SKIP") + raise SystemExit + +# Create object +i = Integer(42) +print(i) +# Call object method +print(i.hashCode()) +# Pass object to another method +System = jni.cls("java/lang/System") +System.out.println(i) diff --git a/src/openmv/src/micropython/tests/jni/object.py.exp b/src/openmv/src/micropython/tests/jni/object.py.exp new file mode 100755 index 0000000..bda709e --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/object.py.exp @@ -0,0 +1,3 @@ +42 +42 +42 diff --git a/src/openmv/src/micropython/tests/jni/system_out.py b/src/openmv/src/micropython/tests/jni/system_out.py new file mode 100755 index 0000000..86c4b9e --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/system_out.py @@ -0,0 +1,8 @@ +try: + import jni + System = jni.cls("java/lang/System") +except: + print("SKIP") + raise SystemExit + +System.out.println("Hello, Java!") diff --git a/src/openmv/src/micropython/tests/jni/system_out.py.exp b/src/openmv/src/micropython/tests/jni/system_out.py.exp new file mode 100755 index 0000000..01dd954 --- /dev/null +++ b/src/openmv/src/micropython/tests/jni/system_out.py.exp @@ -0,0 +1 @@ +Hello, Java! diff --git a/src/openmv/src/micropython/tests/micropython/const.py b/src/openmv/src/micropython/tests/micropython/const.py new file mode 100755 index 0000000..660a095 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const.py @@ -0,0 +1,25 @@ +# test constant optimisation + +from micropython import const + +X = const(123) +Y = const(X + 456) + +print(X, Y + 1) + +def f(): + print(X, Y + 1) + +f() + +_X = const(12) +_Y = const(_X + 34) + +print(_X, _Y) + +class A: + Z = const(1) + _Z = const(2) + print(Z, _Z) + +print(hasattr(A, 'Z'), hasattr(A, '_Z')) diff --git a/src/openmv/src/micropython/tests/micropython/const.py.exp b/src/openmv/src/micropython/tests/micropython/const.py.exp new file mode 100755 index 0000000..ece6a5c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const.py.exp @@ -0,0 +1,5 @@ +123 580 +123 580 +12 46 +1 2 +True False diff --git a/src/openmv/src/micropython/tests/micropython/const2.py b/src/openmv/src/micropython/tests/micropython/const2.py new file mode 100755 index 0000000..60085a1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const2.py @@ -0,0 +1,34 @@ +# check that consts are not replaced in anything except standalone identifiers + +from micropython import const + +X = const(1) +Y = const(2) +Z = const(3) + +# import that uses a constant +import micropython as X +print(globals()['X']) + +# function name that matches a constant +def X(): + print('function X', X) +globals()['X']() + +# arguments that match a constant +def f(X, *Y, **Z): + pass +f(1) + +# class name that matches a constant +class X: + def f(self): + print('class X', X) +globals()['X']().f() + +# constant within a class +class A: + C1 = const(4) + def X(self): + print('method X', Y, C1, self.C1) +A().X() diff --git a/src/openmv/src/micropython/tests/micropython/const2.py.exp b/src/openmv/src/micropython/tests/micropython/const2.py.exp new file mode 100755 index 0000000..0568f91 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const2.py.exp @@ -0,0 +1,4 @@ + +function X 1 +class X 1 +method X 2 4 4 diff --git a/src/openmv/src/micropython/tests/micropython/const_error.py b/src/openmv/src/micropython/tests/micropython/const_error.py new file mode 100755 index 0000000..6d3d135 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const_error.py @@ -0,0 +1,15 @@ +# make sure syntax error works correctly for bad const definition + +from micropython import const + +def test_syntax(code): + try: + exec(code) + except SyntaxError: + print("SyntaxError") + +# argument not a constant +test_syntax("a = const(x)") + +# redefined constant +test_syntax("A = const(1); A = const(2)") diff --git a/src/openmv/src/micropython/tests/micropython/const_error.py.exp b/src/openmv/src/micropython/tests/micropython/const_error.py.exp new file mode 100755 index 0000000..5275689 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const_error.py.exp @@ -0,0 +1,2 @@ +SyntaxError +SyntaxError diff --git a/src/openmv/src/micropython/tests/micropython/const_intbig.py b/src/openmv/src/micropython/tests/micropython/const_intbig.py new file mode 100755 index 0000000..e749026 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const_intbig.py @@ -0,0 +1,13 @@ +# test constant optimisation, with consts that are bignums + +from micropython import const + +# check we can make consts from bignums +Z1 = const(0xffffffff) +Z2 = const(0xffffffffffffffff) +print(hex(Z1), hex(Z2)) + +# check arithmetic with bignum +Z3 = const(Z1 + Z2) +Z4 = const((1 << 100) + Z1) +print(hex(Z3), hex(Z4)) diff --git a/src/openmv/src/micropython/tests/micropython/const_intbig.py.exp b/src/openmv/src/micropython/tests/micropython/const_intbig.py.exp new file mode 100755 index 0000000..137f86c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/const_intbig.py.exp @@ -0,0 +1,2 @@ +0xffffffff 0xffffffffffffffff +0x100000000fffffffe 0x100000000000000000ffffffff diff --git a/src/openmv/src/micropython/tests/micropython/decorator.py b/src/openmv/src/micropython/tests/micropython/decorator.py new file mode 100755 index 0000000..bf68896 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/decorator.py @@ -0,0 +1,7 @@ +# test micropython-specific decorators + +@micropython.bytecode +def f(): + return 'bytecode' + +print(f()) diff --git a/src/openmv/src/micropython/tests/micropython/decorator.py.exp b/src/openmv/src/micropython/tests/micropython/decorator.py.exp new file mode 100755 index 0000000..b37707e --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/decorator.py.exp @@ -0,0 +1 @@ +bytecode diff --git a/src/openmv/src/micropython/tests/micropython/decorator_error.py b/src/openmv/src/micropython/tests/micropython/decorator_error.py new file mode 100755 index 0000000..c7da311 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/decorator_error.py @@ -0,0 +1,11 @@ +# test syntax errors for uPy-specific decorators + +def test_syntax(code): + try: + exec(code) + except SyntaxError: + print("SyntaxError") + +# invalid micropython decorators +test_syntax("@micropython.a\ndef f(): pass") +test_syntax("@micropython.a.b\ndef f(): pass") diff --git a/src/openmv/src/micropython/tests/micropython/decorator_error.py.exp b/src/openmv/src/micropython/tests/micropython/decorator_error.py.exp new file mode 100755 index 0000000..5275689 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/decorator_error.py.exp @@ -0,0 +1,2 @@ +SyntaxError +SyntaxError diff --git a/src/openmv/src/micropython/tests/micropython/emg_exc.py b/src/openmv/src/micropython/tests/micropython/emg_exc.py new file mode 100755 index 0000000..4a9fa18 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/emg_exc.py @@ -0,0 +1,34 @@ +# test that emergency exceptions work + +import micropython +import sys +try: + import uio +except ImportError: + print("SKIP") + raise SystemExit + +# some ports need to allocate heap for the emg exc +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def f(): + micropython.heap_lock() + try: + raise ValueError(1) + except ValueError as er: + exc = er + micropython.heap_unlock() + + # print the exception + buf = uio.StringIO() + sys.print_exception(exc, buf) + for l in buf.getvalue().split("\n"): + if l.startswith(" File "): + print(l.split('"')[2]) + else: + print(l) + +f() diff --git a/src/openmv/src/micropython/tests/micropython/emg_exc.py.exp b/src/openmv/src/micropython/tests/micropython/emg_exc.py.exp new file mode 100755 index 0000000..fd2cfb2 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/emg_exc.py.exp @@ -0,0 +1,4 @@ +Traceback (most recent call last): +, line 20, in f +ValueError: 1 + diff --git a/src/openmv/src/micropython/tests/micropython/extreme_exc.py b/src/openmv/src/micropython/tests/micropython/extreme_exc.py new file mode 100755 index 0000000..b9db964 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/extreme_exc.py @@ -0,0 +1,85 @@ +# test some extreme cases of allocating exceptions and tracebacks + +import micropython + +# Check for stackless build, which can't call functions without +# allocating a frame on the heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + +# some ports need to allocate heap for the emergency exception +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def main(): + # create an exception with many args while heap is locked + # should revert to empty tuple for args + micropython.heap_lock() + e = Exception(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + micropython.heap_unlock() + print(repr(e)) + + # create an exception with a long formatted error message while heap is locked + # should use emergency exception buffer and truncate the message + def f(): + pass + micropython.heap_lock() + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:10]) + + # create an exception with a long formatted error message while heap is low + # should use the heap and truncate the message + lst = [] + while 1: + try: + lst = [lst] + except MemoryError: + break + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + lst[0] = None + lst = None + print(repr(e)[:10]) + + # raise a deep exception with the heap locked + # should use emergency exception and be unable to resize traceback array + def g(): + g() + micropython.heap_lock() + try: + g() + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:13]) + + # create an exception on the heap with some traceback on the heap, but then + # raise it with the heap locked so it can't allocate any more traceback + exc = Exception('my exception') + try: + raise exc + except: + pass + def h(e): + raise e + micropython.heap_lock() + try: + h(exc) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + +main() diff --git a/src/openmv/src/micropython/tests/micropython/extreme_exc.py.exp b/src/openmv/src/micropython/tests/micropython/extreme_exc.py.exp new file mode 100755 index 0000000..956257e --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/extreme_exc.py.exp @@ -0,0 +1,5 @@ +Exception() +TypeError( +TypeError( +RuntimeError( +Exception('my exception',) diff --git a/src/openmv/src/micropython/tests/micropython/heap_lock.py b/src/openmv/src/micropython/tests/micropython/heap_lock.py new file mode 100755 index 0000000..ca3f580 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heap_lock.py @@ -0,0 +1,25 @@ +# check that heap_lock/heap_unlock work as expected + +import micropython + +l = [] +l2 = list(range(100)) + +micropython.heap_lock() + +# general allocation on the heap +try: + print([]) +except MemoryError: + print('MemoryError') + +# expansion of a heap block +try: + l.extend(l2) +except MemoryError: + print('MemoryError') + +micropython.heap_unlock() + +# check that allocation works after an unlock +print([]) diff --git a/src/openmv/src/micropython/tests/micropython/heap_lock.py.exp b/src/openmv/src/micropython/tests/micropython/heap_lock.py.exp new file mode 100755 index 0000000..819c326 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heap_lock.py.exp @@ -0,0 +1,3 @@ +MemoryError +MemoryError +[] diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc.py b/src/openmv/src/micropython/tests/micropython/heapalloc.py new file mode 100755 index 0000000..f74bb92 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc.py @@ -0,0 +1,43 @@ +# check that we can do certain things without allocating heap memory + +import micropython + +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + +def f1(a): + print(a) + +def f2(a, b=2): + print(a, b) + +def f3(a, b, c, d): + x1 = x2 = a + x3 = x4 = b + x5 = x6 = c + x7 = x8 = d + print(x1, x3, x5, x7, x2 + x4 + x6 + x8) + +global_var = 1 + +def test(): + global global_var, global_exc + global_var = 2 # set an existing global variable + for i in range(2): # for loop + f1(i) # function call + f1(i * 2 + 1) # binary operation with small ints + f1(a=i) # keyword arguments + f2(i) # default arg (second one) + f2(i, i) # 2 args + f3(1, 2, 3, 4) # function with lots of local state + +# call test() with heap allocation disabled +micropython.heap_lock() +test() +micropython.heap_unlock() diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc.py.exp new file mode 100755 index 0000000..c8cffe1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc.py.exp @@ -0,0 +1,11 @@ +0 +1 +0 +0 2 +0 0 +1 +3 +1 +1 2 +1 1 +1 2 3 4 10 diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py new file mode 100755 index 0000000..4aae2ab --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py @@ -0,0 +1,18 @@ +try: + import uio +except ImportError: + print("SKIP") + raise SystemExit + +import micropython + +data = b"1234" * 16 +buf = uio.BytesIO(64) + +micropython.heap_lock() + +buf.write(data) + +micropython.heap_unlock() + +print(buf.getvalue()) diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py.exp new file mode 100755 index 0000000..675761c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio.py.exp @@ -0,0 +1 @@ +b'1234123412341234123412341234123412341234123412341234123412341234' diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py new file mode 100755 index 0000000..cd76f58 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py @@ -0,0 +1,20 @@ +# Creating BytesIO from immutable object should not immediately +# copy its content. +try: + import uio + import micropython + micropython.mem_total +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +data = b"1234" * 256 + +before = micropython.mem_total() + +buf = uio.BytesIO(data) + +after = micropython.mem_total() + +print(after - before < len(data)) diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py.exp new file mode 100755 index 0000000..0ca9514 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_bytesio2.py.exp @@ -0,0 +1 @@ +True diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py b/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py new file mode 100755 index 0000000..fb63a84 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py @@ -0,0 +1,23 @@ +# Test that we can raise and catch (preallocated) exception +# without memory allocation. +import micropython + +e = ValueError("error") + +def func(): + micropython.heap_lock() + try: + # This works as is because traceback is not allocated + # if not possible (heap is locked, no memory). If heap + # is not locked, this would allocate a traceback entry. + # To avoid that, traceback should be warmed up (by raising + # it once after creation) and then cleared before each + # raise with: + # e.__traceback__ = None + raise e + except Exception as e2: + print(e2) + micropython.heap_unlock() + +func() +print("ok") diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py.exp new file mode 100755 index 0000000..1e9edc7 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_exc_raise.py.exp @@ -0,0 +1,2 @@ +error +ok diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py b/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py new file mode 100755 index 0000000..3cc497b --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py @@ -0,0 +1,31 @@ +# Test that calling clazz.__call__() with up to at least 3 arguments +# doesn't require heap allocation. +import micropython + +class Foo0: + def __call__(self): + print("__call__") + +class Foo1: + def __call__(self, a): + print("__call__", a) + +class Foo2: + def __call__(self, a, b): + print("__call__", a, b) + +class Foo3: + def __call__(self, a, b, c): + print("__call__", a, b, c) + +f0 = Foo0() +f1 = Foo1() +f2 = Foo2() +f3 = Foo3() + +micropython.heap_lock() +f0() +f1(1) +f2(1, 2) +f3(1, 2, 3) +micropython.heap_unlock() diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py.exp new file mode 100755 index 0000000..0b06bb2 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_inst_call.py.exp @@ -0,0 +1,4 @@ +__call__ +__call__ 1 +__call__ 1 2 +__call__ 1 2 3 diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py b/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py new file mode 100755 index 0000000..5fe5044 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py @@ -0,0 +1,9 @@ +# Test that int.from_bytes() for small number of bytes generates +# small int. +import micropython + +micropython.heap_lock() +print(int.from_bytes(b"1", "little")) +print(int.from_bytes(b"12", "little")) +print(int.from_bytes(b"2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "little")) +micropython.heap_unlock() diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py.exp new file mode 100755 index 0000000..5ac6a57 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_int_from_bytes.py.exp @@ -0,0 +1,3 @@ +49 +12849 +50 diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_iter.py b/src/openmv/src/micropython/tests/micropython/heapalloc_iter.py new file mode 100755 index 0000000..163e172 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_iter.py @@ -0,0 +1,70 @@ +# test that iterating doesn't use the heap +try: + frozenset + import array +except (NameError, ImportError): + print("SKIP") + raise SystemExit + +try: + from micropython import heap_lock, heap_unlock +except (ImportError, AttributeError): + heap_lock = heap_unlock = lambda:0 + +def do_iter(l): + heap_lock() + for i in l: + print(i) + heap_unlock() + +def gen_func(): + yield 1 + yield 2 + +# pre-create collections to iterate over +ba = bytearray(b'123') +ar = array.array('H', (123, 456)) +t = (1, 2, 3) +l = [1, 2] +d = {1:2} +s = set((1,)) +fs = frozenset((1,)) +g1 = (100 + x for x in range(2)) +g2 = gen_func() + +# test containment (both success and failure) with the heap locked +heap_lock() +print(49 in b'123', 255 in b'123') +print(1 in t, -1 in t) +print(1 in l, -1 in l) +print(1 in d, -1 in d) +print(1 in s, -1 in s) +heap_unlock() + +# test unpacking with the heap locked +unp0 = unp1 = unp2 = None # preallocate slots for globals +heap_lock() +unp0, unp1, unp2 = t +print(unp0, unp1, unp2) +heap_unlock() + +# test certain builtins with the heap locked +heap_lock() +print(all(t)) +print(any(t)) +print(min(t)) +print(max(t)) +print(sum(t)) +heap_unlock() + +# test iterating over collections with the heap locked +do_iter(b'123') +do_iter(ba) +do_iter(ar) +do_iter(t) +do_iter(l) +do_iter(d) +do_iter(s) +do_iter(fs) +do_iter(g1) +do_iter(g2) diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_str.py b/src/openmv/src/micropython/tests/micropython/heapalloc_str.py new file mode 100755 index 0000000..39aa56c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_str.py @@ -0,0 +1,18 @@ +# String operations which don't require allocation +import micropython + +micropython.heap_lock() + +# Concatenating empty string returns original string +b"" + b"" +b"" + b"1" +b"2" + b"" + +"" + "" +"" + "1" +"2" + "" + +# If no replacements done, returns original string +"foo".replace(",", "_") + +micropython.heap_unlock() diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_str.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_str.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_super.py b/src/openmv/src/micropython/tests/micropython/heapalloc_super.py new file mode 100755 index 0000000..a8c2339 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_super.py @@ -0,0 +1,26 @@ +# test super() operations which don't require allocation +import micropython + +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + +class A: + def foo(self): + print('A foo') + return 42 +class B(A): + def foo(self): + print('B foo') + print(super().foo()) + +b = B() + +micropython.heap_lock() +b.foo() +micropython.heap_unlock() diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_super.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_super.py.exp new file mode 100755 index 0000000..5dabd0c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_super.py.exp @@ -0,0 +1,3 @@ +B foo +A foo +42 diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py b/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py new file mode 100755 index 0000000..813dea4 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py @@ -0,0 +1,40 @@ +# test that we can generate a traceback without allocating + +import micropython +import sys +try: + import uio +except ImportError: + print("SKIP") + raise SystemExit + +# preallocate exception instance with some room for a traceback +global_exc = StopIteration() +try: + raise global_exc +except: + pass + +def test(): + micropython.heap_lock() + global global_exc + global_exc.__traceback__ = None + try: + raise global_exc + except StopIteration: + print('StopIteration') + micropython.heap_unlock() + +# call test() with heap allocation disabled +test() + +# print the exception that was raised +buf = uio.StringIO() +sys.print_exception(global_exc, buf) +for l in buf.getvalue().split("\n"): + # uPy on pyboard prints as file, so remove filename. + if l.startswith(" File "): + l = l.split('"') + print(l[0], l[2]) + else: + print(l) diff --git a/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py.exp b/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py.exp new file mode 100755 index 0000000..facd0af --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/heapalloc_traceback.py.exp @@ -0,0 +1,5 @@ +StopIteration +Traceback (most recent call last): + File , line 23, in test +StopIteration: + diff --git a/src/openmv/src/micropython/tests/micropython/kbd_intr.py b/src/openmv/src/micropython/tests/micropython/kbd_intr.py new file mode 100755 index 0000000..879c9a2 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/kbd_intr.py @@ -0,0 +1,12 @@ +# test the micropython.kbd_intr() function + +import micropython + +try: + micropython.kbd_intr +except AttributeError: + print('SKIP') + raise SystemExit + +# just check we can actually call it +micropython.kbd_intr(3) diff --git a/src/openmv/src/micropython/tests/micropython/kbd_intr.py.exp b/src/openmv/src/micropython/tests/micropython/kbd_intr.py.exp new file mode 100755 index 0000000..e69de29 diff --git a/src/openmv/src/micropython/tests/micropython/meminfo.py b/src/openmv/src/micropython/tests/micropython/meminfo.py new file mode 100755 index 0000000..698bbbd --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/meminfo.py @@ -0,0 +1,12 @@ +# tests meminfo functions in micropython module + +import micropython + +# these functions are not always available +if not hasattr(micropython, 'mem_info'): + print('SKIP') +else: + micropython.mem_info() + micropython.mem_info(1) + micropython.qstr_info() + micropython.qstr_info(1) diff --git a/src/openmv/src/micropython/tests/micropython/meminfo.py.exp b/src/openmv/src/micropython/tests/micropython/meminfo.py.exp new file mode 100755 index 0000000..a229a7f --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/meminfo.py.exp @@ -0,0 +1,14 @@ +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ +mem: total=\\d\+, current=\\d\+, peak=\\d\+ +stack: \\d\+ out of \\d\+ +GC: total: \\d\+, used: \\d\+, free: \\d\+ + No. of 1-blocks: \\d\+, 2-blocks: \\d\+, max blk sz: \\d\+, max free sz: \\d\+ +GC memory layout; from \[0-9a-f\]\+: +######## +qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+ +qstr pool: n_pool=1, n_qstr=\\d, n_str_data_bytes=\\d\+, n_total_bytes=\\d\+ +######## +Q(SKIP) diff --git a/src/openmv/src/micropython/tests/micropython/memstats.py b/src/openmv/src/micropython/tests/micropython/memstats.py new file mode 100755 index 0000000..78e4d24 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/memstats.py @@ -0,0 +1,17 @@ +# tests meminfo functions in micropython module + +import micropython + +# these functions are not always available +if not hasattr(micropython, 'mem_total'): + print('SKIP') +else: + t = micropython.mem_total() + c = micropython.mem_current() + p = micropython.mem_peak() + + l = list(range(10000)) + + print(micropython.mem_total() > t) + print(micropython.mem_current() > c) + print(micropython.mem_peak() > p) diff --git a/src/openmv/src/micropython/tests/micropython/memstats.py.exp b/src/openmv/src/micropython/tests/micropython/memstats.py.exp new file mode 100755 index 0000000..b8ca7e7 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/memstats.py.exp @@ -0,0 +1,3 @@ +True +True +True diff --git a/src/openmv/src/micropython/tests/micropython/native_closure.py b/src/openmv/src/micropython/tests/micropython/native_closure.py new file mode 100755 index 0000000..6c0592e --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_closure.py @@ -0,0 +1,32 @@ +# test native emitter can handle closures correctly + +# basic closure +@micropython.native +def f(): + x = 1 + @micropython.native + def g(): + nonlocal x + return x + return g +print(f()()) + +# closing over an argument +@micropython.native +def f(x): + @micropython.native + def g(): + nonlocal x + return x + return g +print(f(2)()) + +# closing over an argument and a normal local +@micropython.native +def f(x): + y = 2 * x + @micropython.native + def g(z): + return x + y + z + return g +print(f(2)(3)) diff --git a/src/openmv/src/micropython/tests/micropython/native_closure.py.exp b/src/openmv/src/micropython/tests/micropython/native_closure.py.exp new file mode 100755 index 0000000..7f42772 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_closure.py.exp @@ -0,0 +1,3 @@ +1 +2 +9 diff --git a/src/openmv/src/micropython/tests/micropython/native_const.py b/src/openmv/src/micropython/tests/micropython/native_const.py new file mode 100755 index 0000000..37b491c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_const.py @@ -0,0 +1,14 @@ +# test loading constants in native functions + +@micropython.native +def f(): + return b'bytes' +print(f()) + +@micropython.native +def f(): + @micropython.native + def g(): + return 123 + return g +print(f()()) diff --git a/src/openmv/src/micropython/tests/micropython/native_const.py.exp b/src/openmv/src/micropython/tests/micropython/native_const.py.exp new file mode 100755 index 0000000..9002a0c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_const.py.exp @@ -0,0 +1,2 @@ +b'bytes' +123 diff --git a/src/openmv/src/micropython/tests/micropython/native_const_intbig.py b/src/openmv/src/micropython/tests/micropython/native_const_intbig.py new file mode 100755 index 0000000..611b39d --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_const_intbig.py @@ -0,0 +1,7 @@ +# check loading constants + +@micropython.native +def f(): + return 123456789012345678901234567890 + +print(f()) diff --git a/src/openmv/src/micropython/tests/micropython/native_const_intbig.py.exp b/src/openmv/src/micropython/tests/micropython/native_const_intbig.py.exp new file mode 100755 index 0000000..1d52d22 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_const_intbig.py.exp @@ -0,0 +1 @@ +123456789012345678901234567890 diff --git a/src/openmv/src/micropython/tests/micropython/native_misc.py b/src/openmv/src/micropython/tests/micropython/native_misc.py new file mode 100755 index 0000000..0cd521d --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_misc.py @@ -0,0 +1,31 @@ +# tests for natively compiled functions + +# basic test +@micropython.native +def native_test(x): + print(1, [], x) +native_test(2) + +# check that GC doesn't collect the native function +import gc +gc.collect() +native_test(3) + +# native with 2 args +@micropython.native +def f(a, b): + print(a + b) +f(1, 2) + +# native with 3 args +@micropython.native +def f(a, b, c): + print(a + b + c) +f(1, 2, 3) + +# check not operator +@micropython.native +def f(a): + print(not a) +f(False) +f(True) diff --git a/src/openmv/src/micropython/tests/micropython/native_misc.py.exp b/src/openmv/src/micropython/tests/micropython/native_misc.py.exp new file mode 100755 index 0000000..b3e1389 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_misc.py.exp @@ -0,0 +1,6 @@ +1 [] 2 +1 [] 3 +3 +6 +True +False diff --git a/src/openmv/src/micropython/tests/micropython/native_try.py b/src/openmv/src/micropython/tests/micropython/native_try.py new file mode 100755 index 0000000..2e41bf2 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_try.py @@ -0,0 +1,39 @@ +# test native try handling + +# basic try-finally +@micropython.native +def f(): + try: + fail + finally: + print('finally') +try: + f() +except NameError: + print('NameError') + +# nested try-except with try-finally +@micropython.native +def f(): + try: + try: + fail + finally: + print('finally') + except NameError: + print('NameError') +f() + +# check that locals written to in try blocks keep their values +@micropython.native +def f(): + a = 100 + try: + print(a) + a = 200 + fail + except NameError: + print(a) + a = 300 + print(a) +f() diff --git a/src/openmv/src/micropython/tests/micropython/native_try.py.exp b/src/openmv/src/micropython/tests/micropython/native_try.py.exp new file mode 100755 index 0000000..96596ce --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_try.py.exp @@ -0,0 +1,7 @@ +finally +NameError +finally +NameError +100 +200 +300 diff --git a/src/openmv/src/micropython/tests/micropython/native_try_deep.py b/src/openmv/src/micropython/tests/micropython/native_try_deep.py new file mode 100755 index 0000000..7fac4f0 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_try_deep.py @@ -0,0 +1,34 @@ +# test native try handling + +# deeply nested try (9 deep) +@micropython.native +def f(): + try: + try: + try: + try: + try: + try: + try: + try: + try: + raise ValueError + finally: + print(8) + finally: + print(7) + finally: + print(6) + finally: + print(5) + finally: + print(4) + finally: + print(3) + finally: + print(2) + finally: + print(1) + except ValueError: + print('ValueError') +f() diff --git a/src/openmv/src/micropython/tests/micropython/native_try_deep.py.exp b/src/openmv/src/micropython/tests/micropython/native_try_deep.py.exp new file mode 100755 index 0000000..84c6bea --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_try_deep.py.exp @@ -0,0 +1,9 @@ +8 +7 +6 +5 +4 +3 +2 +1 +ValueError diff --git a/src/openmv/src/micropython/tests/micropython/native_with.py b/src/openmv/src/micropython/tests/micropython/native_with.py new file mode 100755 index 0000000..343f3e8 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_with.py @@ -0,0 +1,28 @@ +# test with handling within a native function + +class C: + def __init__(self): + print('__init__') + def __enter__(self): + print('__enter__') + def __exit__(self, a, b, c): + print('__exit__', a, b, c) + +# basic with +@micropython.native +def f(): + with C(): + print(1) +f() + +# nested with and try-except +@micropython.native +def f(): + try: + with C(): + print(1) + fail + print(2) + except NameError: + print('NameError') +f() diff --git a/src/openmv/src/micropython/tests/micropython/native_with.py.exp b/src/openmv/src/micropython/tests/micropython/native_with.py.exp new file mode 100755 index 0000000..7e28663 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/native_with.py.exp @@ -0,0 +1,9 @@ +__init__ +__enter__ +1 +__exit__ None None None +__init__ +__enter__ +1 +__exit__ name 'fail' isn't defined None +NameError diff --git a/src/openmv/src/micropython/tests/micropython/opt_level.py b/src/openmv/src/micropython/tests/micropython/opt_level.py new file mode 100755 index 0000000..5a10047 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/opt_level.py @@ -0,0 +1,19 @@ +import micropython as micropython + +# check we can get and set the level +micropython.opt_level(0) +print(micropython.opt_level()) +micropython.opt_level(1) +print(micropython.opt_level()) + +# check that the optimisation levels actually differ +micropython.opt_level(0) +exec('print(__debug__)') +micropython.opt_level(1) +exec('print(__debug__)') +exec('assert 0') + +# check that level 3 doesn't store line numbers +# the expected output is that any line is printed as "line 1" +micropython.opt_level(3) +exec('try:\n xyz\nexcept NameError as er:\n import sys\n sys.print_exception(er)') diff --git a/src/openmv/src/micropython/tests/micropython/opt_level.py.exp b/src/openmv/src/micropython/tests/micropython/opt_level.py.exp new file mode 100755 index 0000000..6372f6c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/opt_level.py.exp @@ -0,0 +1,7 @@ +0 +1 +True +False +Traceback (most recent call last): + File "", line 1, in +NameError: name 'xyz' isn't defined diff --git a/src/openmv/src/micropython/tests/micropython/schedule.py b/src/openmv/src/micropython/tests/micropython/schedule.py new file mode 100755 index 0000000..74f90cb --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/schedule.py @@ -0,0 +1,60 @@ +# test micropython.schedule() function + +import micropython + +try: + micropython.schedule +except AttributeError: + print('SKIP') + raise SystemExit + +# Basic test of scheduling a function. + +def callback(arg): + global done + print(arg) + done = True + +done = False +micropython.schedule(callback, 1) +while not done: + pass + +# Test that callbacks can be scheduled from within a callback, but +# that they don't execute until the outer callback is finished. + +def callback_inner(arg): + global done + print('inner') + done += 1 + +def callback_outer(arg): + global done + micropython.schedule(callback_inner, 0) + # need a loop so that the VM can check for pending events + for i in range(2): + pass + print('outer') + done += 1 + +done = 0 +micropython.schedule(callback_outer, 0) +while done != 2: + pass + +# Test that scheduling too many callbacks leads to an exception. To do this we +# must schedule from within a callback to guarantee that the scheduler is locked. + +def callback(arg): + global done + try: + for i in range(100): + micropython.schedule(lambda x:x, None) + except RuntimeError: + print('RuntimeError') + done = True + +done = False +micropython.schedule(callback, None) +while not done: + pass diff --git a/src/openmv/src/micropython/tests/micropython/schedule.py.exp b/src/openmv/src/micropython/tests/micropython/schedule.py.exp new file mode 100755 index 0000000..c4a3e12 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/schedule.py.exp @@ -0,0 +1,4 @@ +1 +outer +inner +RuntimeError diff --git a/src/openmv/src/micropython/tests/micropython/stack_use.py b/src/openmv/src/micropython/tests/micropython/stack_use.py new file mode 100755 index 0000000..bc71475 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/stack_use.py @@ -0,0 +1,7 @@ +# tests stack_use function in micropython module +import micropython + +if not hasattr(micropython, 'stack_use'): + print('SKIP') +else: + print(type(micropython.stack_use())) # output varies diff --git a/src/openmv/src/micropython/tests/micropython/stack_use.py.exp b/src/openmv/src/micropython/tests/micropython/stack_use.py.exp new file mode 100755 index 0000000..fe37cea --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/stack_use.py.exp @@ -0,0 +1 @@ + diff --git a/src/openmv/src/micropython/tests/micropython/viper_addr.py b/src/openmv/src/micropython/tests/micropython/viper_addr.py new file mode 100755 index 0000000..cd953ce --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_addr.py @@ -0,0 +1,29 @@ +# test passing addresses to viper + +@micropython.viper +def get_addr(x:ptr) -> ptr: + return x + +@micropython.viper +def memset(dest:ptr8, c:int, n:int): + for i in range(n): + dest[i] = c + +# create array and get its address +ar = bytearray('0000') +addr = get_addr(ar) +print(type(ar)) +print(type(addr)) +print(ar) + +# pass array as an object +memset(ar, ord('1'), len(ar)) +print(ar) + +# pass direct pointer to array buffer +memset(addr, ord('2'), len(ar)) +print(ar) + +# pass direct pointer to array buffer, with offset +memset(addr + 2, ord('3'), len(ar) - 2) +print(ar) diff --git a/src/openmv/src/micropython/tests/micropython/viper_addr.py.exp b/src/openmv/src/micropython/tests/micropython/viper_addr.py.exp new file mode 100755 index 0000000..87a18e1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_addr.py.exp @@ -0,0 +1,6 @@ + + +bytearray(b'0000') +bytearray(b'1111') +bytearray(b'2222') +bytearray(b'2233') diff --git a/src/openmv/src/micropython/tests/micropython/viper_args.py b/src/openmv/src/micropython/tests/micropython/viper_args.py new file mode 100755 index 0000000..ee8e823 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_args.py @@ -0,0 +1,44 @@ +# test calling viper functions with different number of args + +@micropython.viper +def f0(): + print(0) +f0() + +@micropython.viper +def f1(x1:int): + print(x1) +f1(1) + +@micropython.viper +def f2(x1:int, x2:int): + print(x1, x2) +f2(1, 2) + +@micropython.viper +def f3(x1:int, x2:int, x3:int): + print(x1, x2, x3) +f3(1, 2, 3) + +@micropython.viper +def f4(x1:int, x2:int, x3:int, x4:int): + print(x1, x2, x3, x4) +f4(1, 2, 3, 4) + +@micropython.viper +def f5(x1:int, x2:int, x3:int, x4:int, x5:int): + print(x1, x2, x3, x4, x5) +f5(1, 2, 3, 4, 5) + +@micropython.viper +def f6(x1:int, x2:int, x3:int, x4:int, x5:int, x6:int): + print(x1, x2, x3, x4, x5, x6) +f6(1, 2, 3, 4, 5, 6) + +# test compiling *x, **x, * args (currently unsupported at runtime) +@micropython.viper +def f(*x, **y): + pass +@micropython.viper +def f(*): + pass diff --git a/src/openmv/src/micropython/tests/micropython/viper_args.py.exp b/src/openmv/src/micropython/tests/micropython/viper_args.py.exp new file mode 100755 index 0000000..6d64c58 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_args.py.exp @@ -0,0 +1,7 @@ +0 +1 +1 2 +1 2 3 +1 2 3 4 +1 2 3 4 5 +1 2 3 4 5 6 diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py b/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py new file mode 100755 index 0000000..4d711f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py @@ -0,0 +1,69 @@ +# test arithmetic operators + +@micropython.viper +def add(x:int, y:int): + print(x + y) + print(y + x) +add(1, 2) +add(42, 3) +add(-1, 2) +add(-42, -3) + +@micropython.viper +def sub(x:int, y:int): + print(x - y) + print(y - x) +sub(1, 2) +sub(42, 3) +sub(-1, 2) +sub(-42, -3) + +@micropython.viper +def mul(x:int, y:int): + print(x * y) + print(y * x) +mul(0, 1) +mul(1, -1) +mul(1, 2) +mul(8, 3) +mul(-3, 4) +mul(-9, -6) + +@micropython.viper +def shl(x:int, y:int): + print(x << y) +shl(1, 0) +shl(1, 3) +shl(1, 30) +shl(42, 10) +shl(-42, 10) + +@micropython.viper +def shr(x:int, y:int): + print(x >> y) +shr(1, 0) +shr(1, 3) +shr(42, 2) +shr(-42, 2) + +@micropython.viper +def and_(x:int, y:int): + print(x & y, y & x) +and_(1, 0) +and_(1, 3) +and_(0xf0, 0x3f) +and_(-42, 6) + +@micropython.viper +def or_(x:int, y:int): + print(x | y, y | x) +or_(1, 0) +or_(1, 2) +or_(-42, 5) + +@micropython.viper +def xor(x:int, y:int): + print(x ^ y, y ^ x) +xor(1, 0) +xor(1, 2) +xor(-42, 5) diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py.exp b/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py.exp new file mode 100755 index 0000000..156e3af --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_arith.py.exp @@ -0,0 +1,47 @@ +3 +3 +45 +45 +1 +1 +-45 +-45 +-1 +1 +39 +-39 +-3 +3 +-39 +39 +0 +0 +-1 +-1 +2 +2 +24 +24 +-12 +-12 +54 +54 +1 +8 +1073741824 +43008 +-43008 +1 +0 +10 +-11 +0 0 +1 1 +48 48 +6 6 +1 1 +3 3 +-41 -41 +1 1 +3 3 +-45 -45 diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py b/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py new file mode 100755 index 0000000..dcf91ed --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py @@ -0,0 +1,21 @@ +# test comparison operators +@micropython.viper +def f(x:int, y:int): + if x < y: + print(x, "<", y) + if x > y: + print(x, ">", y) + if x == y: + print(x, "==", y) + if x <= y: + print(x, "<=", y) + if x >= y: + print(x, ">=", y) + if x != y: + print(x, "!=", y) + +f(1, 1) +f(2, 1) +f(1, 2) +f(2, -1) +f(-2, 1) diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py.exp b/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py.exp new file mode 100755 index 0000000..20a8289 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_comp.py.exp @@ -0,0 +1,15 @@ +1 == 1 +1 <= 1 +1 >= 1 +2 > 1 +2 >= 1 +2 != 1 +1 < 2 +1 <= 2 +1 != 2 +2 > -1 +2 >= -1 +2 != -1 +-2 < 1 +-2 <= 1 +-2 != 1 diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py b/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py new file mode 100755 index 0000000..c7c0408 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py @@ -0,0 +1,9 @@ +# comparisons with immediate boundary values +@micropython.viper +def f(a: int): + print(a == -1, a == -255, a == -256, a == -257) + +f(-1) +f(-255) +f(-256) +f(-257) diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py.exp b/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py.exp new file mode 100755 index 0000000..3da9d09 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_comp_imm.py.exp @@ -0,0 +1,4 @@ +True False False False +False True False False +False False True False +False False False True diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py b/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py new file mode 100755 index 0000000..8224249 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py @@ -0,0 +1,18 @@ +# test floor-division and modulo operators + +@micropython.viper +def div(x:int, y:int) -> int: + return x // y + +@micropython.viper +def mod(x:int, y:int) -> int: + return x % y + +def dm(x, y): + print(div(x, y), mod(x, y)) + +for x in (-6, 6): + for y in range(-7, 8): + if y == 0: + continue + dm(x, y) diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py.exp b/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py.exp new file mode 100755 index 0000000..4fc971d --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_divmod.py.exp @@ -0,0 +1,28 @@ +0 -6 +1 0 +1 -1 +1 -2 +2 0 +3 0 +6 0 +-6 0 +-3 0 +-2 0 +-2 2 +-2 4 +-1 0 +-1 1 +-1 -1 +-1 0 +-2 -4 +-2 -2 +-2 0 +-3 0 +-6 0 +6 0 +3 0 +2 0 +1 2 +1 1 +1 0 +0 6 diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py b/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py new file mode 100755 index 0000000..8065db2 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py @@ -0,0 +1,21 @@ +# test multi comparison operators +@micropython.viper +def f(x:int, y:int): + if 0 < x < y: + print(x, "<", y) + if 3 > x > y: + print(x, ">", y) + if 1 == x == y: + print(x, "==", y) + if -2 == x <= y: + print(x, "<=", y) + if 2 == x >= y: + print(x, ">=", y) + if 2 == x != y: + print(x, "!=", y) + +f(1, 1) +f(2, 1) +f(1, 2) +f(2, -1) +f(-2, 1) diff --git a/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py.exp b/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py.exp new file mode 100755 index 0000000..e5e9787 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_binop_multi_comp.py.exp @@ -0,0 +1,9 @@ +1 == 1 +2 > 1 +2 >= 1 +2 != 1 +1 < 2 +2 > -1 +2 >= -1 +2 != -1 +-2 <= 1 diff --git a/src/openmv/src/micropython/tests/micropython/viper_cond.py b/src/openmv/src/micropython/tests/micropython/viper_cond.py new file mode 100755 index 0000000..bbb3f69 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_cond.py @@ -0,0 +1,33 @@ +# using False as a conditional +@micropython.viper +def f(): + x = False + if x: + pass + else: + print("not x", x) +f() + +# using True as a conditional +@micropython.viper +def f(): + x = True + if x: + print("x", x) +f() + +# using an int as a conditional +@micropython.viper +def g(): + y = 1 + if y: + print("y", y) +g() + +# using an int as a conditional that has the lower 16-bits clear +@micropython.viper +def h(): + z = 0x10000 + if z: + print("z", z) +h() diff --git a/src/openmv/src/micropython/tests/micropython/viper_cond.py.exp b/src/openmv/src/micropython/tests/micropython/viper_cond.py.exp new file mode 100755 index 0000000..beacd48 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_cond.py.exp @@ -0,0 +1,4 @@ +not x False +x True +y 1 +z 65536 diff --git a/src/openmv/src/micropython/tests/micropython/viper_const.py b/src/openmv/src/micropython/tests/micropython/viper_const.py new file mode 100755 index 0000000..5085ede --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_const.py @@ -0,0 +1,14 @@ +# test loading constants in viper functions + +@micropython.viper +def f(): + return b'bytes' +print(f()) + +@micropython.viper +def f(): + @micropython.viper + def g() -> int: + return 123 + return g +print(f()()) diff --git a/src/openmv/src/micropython/tests/micropython/viper_const.py.exp b/src/openmv/src/micropython/tests/micropython/viper_const.py.exp new file mode 100755 index 0000000..9002a0c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_const.py.exp @@ -0,0 +1,2 @@ +b'bytes' +123 diff --git a/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py b/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py new file mode 100755 index 0000000..6b44973 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py @@ -0,0 +1,7 @@ +# check loading constants + +@micropython.viper +def f(): + return 123456789012345678901234567890 + +print(f()) diff --git a/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py.exp b/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py.exp new file mode 100755 index 0000000..1d52d22 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_const_intbig.py.exp @@ -0,0 +1 @@ +123456789012345678901234567890 diff --git a/src/openmv/src/micropython/tests/micropython/viper_error.py b/src/openmv/src/micropython/tests/micropython/viper_error.py new file mode 100755 index 0000000..ff32f54 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_error.py @@ -0,0 +1,78 @@ +# test syntax and type errors specific to viper code generation + +def test(code): + try: + exec(code) + except (SyntaxError, ViperTypeError, NotImplementedError) as e: + print(repr(e)) + +# viper: annotations must be identifiers +test("@micropython.viper\ndef f(a:1): pass") +test("@micropython.viper\ndef f() -> 1: pass") + +# unknown type +test("@micropython.viper\ndef f(x:unknown_type): pass") + +# local used before type known +test(""" +@micropython.viper +def f(): + print(x) + x = 1 +""") + +# type mismatch storing to local +test(""" +@micropython.viper +def f(): + x = 1 + y = [] + x = y +""") + +# can't implicitly convert type to bool +test(""" +@micropython.viper +def f(): + x = ptr(0) + if x: + pass +""") + +# incorrect return type +test("@micropython.viper\ndef f() -> int: return []") + +# can't do binary op between incompatible types +test("@micropython.viper\ndef f(): 1 + []") + +# can't load +test("@micropython.viper\ndef f(): 1[0]") +test("@micropython.viper\ndef f(): 1[x]") + +# can't store +test("@micropython.viper\ndef f(): 1[0] = 1") +test("@micropython.viper\ndef f(): 1[x] = 1") +test("@micropython.viper\ndef f(x:int): x[0] = x") +test("@micropython.viper\ndef f(x:ptr32): x[0] = None") +test("@micropython.viper\ndef f(x:ptr32): x[x] = None") + +# must raise an object +test("@micropython.viper\ndef f(): raise 1") + +# unary ops not implemented +test("@micropython.viper\ndef f(x:int): +x") +test("@micropython.viper\ndef f(x:int): -x") +test("@micropython.viper\ndef f(x:int): ~x") + +# binary op not implemented +test("@micropython.viper\ndef f(x:int): res = x in x") + +# yield (from) not implemented +test("@micropython.viper\ndef f(): yield") +test("@micropython.viper\ndef f(): yield from f") + +# passing a ptr to a Python function not implemented +test("@micropython.viper\ndef f(): print(ptr(1))") + +# cast of a casting identifier not implemented +test("@micropython.viper\ndef f(): int(int)") diff --git a/src/openmv/src/micropython/tests/micropython/viper_error.py.exp b/src/openmv/src/micropython/tests/micropython/viper_error.py.exp new file mode 100755 index 0000000..da9a0ca --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_error.py.exp @@ -0,0 +1,24 @@ +SyntaxError('annotation must be an identifier',) +SyntaxError('annotation must be an identifier',) +ViperTypeError("unknown type 'unknown_type'",) +ViperTypeError("local 'x' used before type known",) +ViperTypeError("local 'x' has type 'int' but source is 'object'",) +ViperTypeError("can't implicitly convert 'ptr' to 'bool'",) +ViperTypeError("return expected 'int' but got 'object'",) +ViperTypeError("can't do binary op between 'int' and 'object'",) +ViperTypeError("can't load from 'int'",) +ViperTypeError("can't load from 'int'",) +ViperTypeError("can't store to 'int'",) +ViperTypeError("can't store to 'int'",) +ViperTypeError("can't store to 'int'",) +ViperTypeError("can't store 'None'",) +ViperTypeError("can't store 'None'",) +ViperTypeError('must raise an object',) +ViperTypeError('unary op __pos__ not implemented',) +ViperTypeError('unary op __neg__ not implemented',) +ViperTypeError('unary op __invert__ not implemented',) +ViperTypeError('binary op not implemented',) +NotImplementedError('native yield',) +NotImplementedError('native yield',) +NotImplementedError('conversion to object',) +NotImplementedError('casting',) diff --git a/src/openmv/src/micropython/tests/micropython/viper_globals.py b/src/openmv/src/micropython/tests/micropython/viper_globals.py new file mode 100755 index 0000000..9c68dc3 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_globals.py @@ -0,0 +1,19 @@ +# test that viper functions capture their globals context + +gl = {} + +exec(""" +@micropython.viper +def f(): + return x +""", gl) + +# x is not yet in the globals, f should not see it +try: + print(gl['f']()) +except NameError: + print('NameError') + +# x is in globals, f should now see it +gl['x'] = 123 +print(gl['f']()) diff --git a/src/openmv/src/micropython/tests/micropython/viper_globals.py.exp b/src/openmv/src/micropython/tests/micropython/viper_globals.py.exp new file mode 100755 index 0000000..5731b89 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_globals.py.exp @@ -0,0 +1,2 @@ +NameError +123 diff --git a/src/openmv/src/micropython/tests/micropython/viper_import.py b/src/openmv/src/micropython/tests/micropython/viper_import.py new file mode 100755 index 0000000..9878007 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_import.py @@ -0,0 +1,10 @@ +# test import within viper function + +@micropython.viper +def f(): + import micropython + print(micropython.const(1)) + + from micropython import const + print(const(2)) +f() diff --git a/src/openmv/src/micropython/tests/micropython/viper_import.py.exp b/src/openmv/src/micropython/tests/micropython/viper_import.py.exp new file mode 100755 index 0000000..1191247 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_import.py.exp @@ -0,0 +1,2 @@ +1 +2 diff --git a/src/openmv/src/micropython/tests/micropython/viper_misc.py b/src/openmv/src/micropython/tests/micropython/viper_misc.py new file mode 100755 index 0000000..021e03f --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_misc.py @@ -0,0 +1,116 @@ +import micropython + +# viper function taking and returning ints +@micropython.viper +def viper_int(x:int, y:int) -> int: + return x + y + 3 +print(viper_int(1, 2)) + +# viper function taking and returning objects +@micropython.viper +def viper_object(x:object, y:object) -> object: + return x + y +print(viper_object(1, 2)) + +# return None as non-object (should return 0) +@micropython.viper +def viper_ret_none() -> int: + return None +print(viper_ret_none()) + +# return Ellipsis as object +@micropython.viper +def viper_ret_ellipsis() -> object: + return ... +print(viper_ret_ellipsis()) + +# 3 args +@micropython.viper +def viper_3args(a:int, b:int, c:int) -> int: + return a + b + c +print(viper_3args(1, 2, 3)) + +# 4 args +@micropython.viper +def viper_4args(a:int, b:int, c:int, d:int) -> int: + return a + b + c + d +# viper call with 4 args not yet supported +#print(viper_4args(1, 2, 3, 4)) + +# a local (should have automatic type int) +@micropython.viper +def viper_local(x:int) -> int: + y = 4 + return x + y +print(viper_local(3)) + +# without type annotation, types should default to object +@micropython.viper +def viper_no_annotation(x, y): + return x * y +print(viper_no_annotation(4, 5)) + +# a for loop +@micropython.viper +def viper_for(a:int, b:int) -> int: + total = 0 + for x in range(a, b): + total += x + return total +print(viper_for(10, 10000)) + +# accessing a global +@micropython.viper +def viper_access_global(): + global gl + gl = 1 + return gl +print(viper_access_global(), gl) + +# calling print with object and int types +@micropython.viper +def viper_print(x, y:int): + print(x, y + 1) +viper_print(1, 2) + +# convert constants to objects in tuple +@micropython.viper +def viper_tuple_consts(x): + return (x, 1, False, True) +print(viper_tuple_consts(0)) + +# making a tuple from an object and an int +@micropython.viper +def viper_tuple(x, y:int): + return (x, y + 1) +print(viper_tuple(1, 2)) + +# making a list from an object and an int +@micropython.viper +def viper_list(x, y:int): + return [x, y + 1] +print(viper_list(1, 2)) + +# making a set from an object and an int +@micropython.viper +def viper_set(x, y:int): + return {x, y + 1} +print(sorted(list(viper_set(1, 2)))) + +# raising an exception +@micropython.viper +def viper_raise(x:int): + raise OSError(x) +try: + viper_raise(1) +except OSError as e: + print(repr(e)) + +# calling GC after defining the function +@micropython.viper +def viper_gc() -> int: + return 1 +print(viper_gc()) +import gc +gc.collect() +print(viper_gc()) diff --git a/src/openmv/src/micropython/tests/micropython/viper_misc.py.exp b/src/openmv/src/micropython/tests/micropython/viper_misc.py.exp new file mode 100755 index 0000000..e446277 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_misc.py.exp @@ -0,0 +1,17 @@ +6 +3 +0 +Ellipsis +6 +7 +20 +49994955 +1 1 +1 3 +(0, 1, False, True) +(1, 3) +[1, 3] +[1, 3] +OSError(1,) +1 +1 diff --git a/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py b/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py new file mode 100755 index 0000000..e036435 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py @@ -0,0 +1,8 @@ +import micropython + +# unsigned ints +@micropython.viper +def viper_uint() -> uint: + return uint(-1) +import sys +print(viper_uint() == (sys.maxsize << 1 | 1)) diff --git a/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py.exp b/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py.exp new file mode 100755 index 0000000..0ca9514 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_misc_intbig.py.exp @@ -0,0 +1 @@ +True diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py b/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py new file mode 100755 index 0000000..0b865eb --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py @@ -0,0 +1,32 @@ +# test loading from ptr16 type +# only works on little endian machines + +@micropython.viper +def get(src:ptr16) -> int: + return src[0] + +@micropython.viper +def get1(src:ptr16) -> int: + return src[1] + +@micropython.viper +def memadd(src:ptr16, n:int) -> int: + sum = 0 + for i in range(n): + sum += src[i] + return sum + +@micropython.viper +def memadd2(src_in) -> int: + src = ptr16(src_in) + n = int(len(src_in)) >> 1 + sum = 0 + for i in range(n): + sum += src[i] + return sum + +b = bytearray(b'1234') +print(b) +print(get(b), get1(b)) +print(memadd(b, 2)) +print(memadd2(b)) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py.exp new file mode 100755 index 0000000..2d86b97 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr16_load.py.exp @@ -0,0 +1,4 @@ +bytearray(b'1234') +12849 13363 +26212 +26212 diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py b/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py new file mode 100755 index 0000000..5a5f25d --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py @@ -0,0 +1,36 @@ +# test ptr16 type + +@micropython.viper +def set(dest:ptr16, val:int): + dest[0] = val + +@micropython.viper +def set1(dest:ptr16, val:int): + dest[1] = val + +@micropython.viper +def memset(dest:ptr16, val:int, n:int): + for i in range(n): + dest[i] = val + +@micropython.viper +def memset2(dest_in, val:int): + dest = ptr16(dest_in) + n = int(len(dest_in)) >> 1 + for i in range(n): + dest[i] = val + +b = bytearray(4) +print(b) + +set(b, 0x4242) +print(b) + +set1(b, 0x4343) +print(b) + +memset(b, 0x4444, len(b) // 2) +print(b) + +memset2(b, 0x4545) +print(b) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py.exp new file mode 100755 index 0000000..31a6dfb --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr16_store.py.exp @@ -0,0 +1,5 @@ +bytearray(b'\x00\x00\x00\x00') +bytearray(b'BB\x00\x00') +bytearray(b'BBCC') +bytearray(b'DDDD') +bytearray(b'EEEE') diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py b/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py new file mode 100755 index 0000000..4d8b384 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py @@ -0,0 +1,31 @@ +# test loading from ptr32 type + +@micropython.viper +def get(src:ptr32) -> int: + return src[0] + +@micropython.viper +def get1(src:ptr32) -> int: + return src[1] + +@micropython.viper +def memadd(src:ptr32, n:int) -> int: + sum = 0 + for i in range(n): + sum += src[i] + return sum + +@micropython.viper +def memadd2(src_in) -> int: + src = ptr32(src_in) + n = int(len(src_in)) >> 2 + sum = 0 + for i in range(n): + sum += src[i] + return sum + +b = bytearray(b'\x12\x12\x12\x12\x34\x34\x34\x34') +print(b) +print(hex(get(b)), hex(get1(b))) +print(hex(memadd(b, 2))) +print(hex(memadd2(b))) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py.exp new file mode 100755 index 0000000..7ea37f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr32_load.py.exp @@ -0,0 +1,4 @@ +bytearray(b'\x12\x12\x12\x124444') +0x12121212 0x34343434 +0x46464646 +0x46464646 diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py b/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py new file mode 100755 index 0000000..973086e --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py @@ -0,0 +1,36 @@ +# test store to ptr32 type + +@micropython.viper +def set(dest:ptr32, val:int): + dest[0] = val + +@micropython.viper +def set1(dest:ptr32, val:int): + dest[1] = val + +@micropython.viper +def memset(dest:ptr32, val:int, n:int): + for i in range(n): + dest[i] = val + +@micropython.viper +def memset2(dest_in, val:int): + dest = ptr32(dest_in) + n = int(len(dest_in)) >> 2 + for i in range(n): + dest[i] = val + +b = bytearray(8) +print(b) + +set(b, 0x42424242) +print(b) + +set1(b, 0x43434343) +print(b) + +memset(b, 0x44444444, len(b) // 4) +print(b) + +memset2(b, 0x45454545) +print(b) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py.exp new file mode 100755 index 0000000..de8d0ec --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr32_store.py.exp @@ -0,0 +1,5 @@ +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'BBBB\x00\x00\x00\x00') +bytearray(b'BBBBCCCC') +bytearray(b'DDDDDDDD') +bytearray(b'EEEEEEEE') diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py b/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py new file mode 100755 index 0000000..0ccf8a1 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py @@ -0,0 +1,31 @@ +# test loading from ptr8 type + +@micropython.viper +def get(src:ptr8) -> int: + return src[0] + +@micropython.viper +def get1(src:ptr8) -> int: + return src[1] + +@micropython.viper +def memadd(src:ptr8, n:int) -> int: + sum = 0 + for i in range(n): + sum += src[i] + return sum + +@micropython.viper +def memadd2(src_in) -> int: + src = ptr8(src_in) + n = int(len(src_in)) + sum = 0 + for i in range(n): + sum += src[i] + return sum + +b = bytearray(b'1234') +print(b) +print(get(b), get1(b)) +print(memadd(b, 4)) +print(memadd2(b)) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py.exp new file mode 100755 index 0000000..d899bbe --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr8_load.py.exp @@ -0,0 +1,4 @@ +bytearray(b'1234') +49 50 +202 +202 diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py b/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py new file mode 100755 index 0000000..5a8622e --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py @@ -0,0 +1,36 @@ +# test ptr8 type + +@micropython.viper +def set(dest:ptr8, val:int): + dest[0] = val + +@micropython.viper +def set1(dest:ptr8, val:int): + dest[1] = val + +@micropython.viper +def memset(dest:ptr8, val:int, n:int): + for i in range(n): + dest[i] = val + +@micropython.viper +def memset2(dest_in, val:int): + dest = ptr8(dest_in) + n = int(len(dest_in)) + for i in range(n): + dest[i] = val + +b = bytearray(4) +print(b) + +set(b, 41) +print(b) + +set1(b, 42) +print(b) + +memset(b, 43, len(b)) +print(b) + +memset2(b, 44) +print(b) diff --git a/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py.exp b/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py.exp new file mode 100755 index 0000000..b2fbe42 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_ptr8_store.py.exp @@ -0,0 +1,5 @@ +bytearray(b'\x00\x00\x00\x00') +bytearray(b')\x00\x00\x00') +bytearray(b')*\x00\x00') +bytearray(b'++++') +bytearray(b',,,,') diff --git a/src/openmv/src/micropython/tests/micropython/viper_subscr.py b/src/openmv/src/micropython/tests/micropython/viper_subscr.py new file mode 100755 index 0000000..2198ed7 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_subscr.py @@ -0,0 +1,20 @@ +# test standard Python subscr using viper types + +@micropython.viper +def get(dest, i:int): + i += 1 + return dest[i] + +@micropython.viper +def set(dest, i:int, val:int): + i += 1 + dest[i] = val + 1 + +ar = [i for i in range(3)] + +for i in range(len(ar)): + set(ar, i - 1, i) +print(ar) + +for i in range(len(ar)): + print(get(ar, i - 1)) diff --git a/src/openmv/src/micropython/tests/micropython/viper_subscr.py.exp b/src/openmv/src/micropython/tests/micropython/viper_subscr.py.exp new file mode 100755 index 0000000..e68032c --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_subscr.py.exp @@ -0,0 +1,4 @@ +[1, 2, 3] +1 +2 +3 diff --git a/src/openmv/src/micropython/tests/micropython/viper_try.py b/src/openmv/src/micropython/tests/micropython/viper_try.py new file mode 100755 index 0000000..d75b341 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_try.py @@ -0,0 +1,40 @@ +# test try handling within a viper function + +# basic try-finally +@micropython.viper +def f(): + try: + fail + finally: + print('finally') +try: + f() +except NameError: + print('NameError') + +# nested try-except with try-finally +@micropython.viper +def f(): + try: + try: + fail + finally: + print('finally') + except NameError: + print('NameError') +f() + +# check that locals written to in try blocks keep their values +@micropython.viper +def f(): + a = 100 + try: + print(a) + a = 200 + fail + except NameError: + print(a) + a = 300 + print(a) +f() + diff --git a/src/openmv/src/micropython/tests/micropython/viper_try.py.exp b/src/openmv/src/micropython/tests/micropython/viper_try.py.exp new file mode 100755 index 0000000..96596ce --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_try.py.exp @@ -0,0 +1,7 @@ +finally +NameError +finally +NameError +100 +200 +300 diff --git a/src/openmv/src/micropython/tests/micropython/viper_with.py b/src/openmv/src/micropython/tests/micropython/viper_with.py new file mode 100755 index 0000000..2bc3c4f --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_with.py @@ -0,0 +1,28 @@ +# test with handling within a viper function + +class C: + def __init__(self): + print('__init__') + def __enter__(self): + print('__enter__') + def __exit__(self, a, b, c): + print('__exit__', a, b, c) + +# basic with +@micropython.viper +def f(): + with C(): + print(1) +f() + +# nested with and try-except +@micropython.viper +def f(): + try: + with C(): + print(1) + fail + print(2) + except NameError: + print('NameError') +f() diff --git a/src/openmv/src/micropython/tests/micropython/viper_with.py.exp b/src/openmv/src/micropython/tests/micropython/viper_with.py.exp new file mode 100755 index 0000000..7e28663 --- /dev/null +++ b/src/openmv/src/micropython/tests/micropython/viper_with.py.exp @@ -0,0 +1,9 @@ +__init__ +__enter__ +1 +__exit__ None None None +__init__ +__enter__ +1 +__exit__ name 'fail' isn't defined None +NameError diff --git a/src/openmv/src/micropython/tests/misc/features.py b/src/openmv/src/micropython/tests/misc/features.py new file mode 100755 index 0000000..874945b --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/features.py @@ -0,0 +1,165 @@ +try: + str.count +except AttributeError: + print("SKIP") + raise SystemExit + +# mad.py +# Alf Clement 27-Mar-2014 +# +zero=0 +three=3 +print("1") +print("2") +print(three) +print("{}".format(4)) +five=25//5 +print(int(five)) +j=0 +for i in range(4): + j += i +print(j) +print(3+4) +try: + a=4//zero +except: + print(8) +print("xxxxxxxxx".count("x")) +def ten(): + return 10 +print(ten()) +a=[] +for i in range(13): + a.append(i) +print(a[11]) +print(a[-1]) +str="0123456789" +print(str[1]+str[3]) +def p(s): + print(s) +p("14") +p(15) +class A: + def __init__(self): + self.a=16 + def print(self): + print(self.a) + def set(self,b): + self.a=b +a=A() +a.print() +a.set(17) +a.print() +b=A() +b.set(a.a + 1) +b.print() +for i in range(20): + pass +print(i) +if 20 > 30: + a="1" +else: + a="2" +if 0 < 4: + print(a+"0") +else: + print(a+"1") +a=[20,21,22,23,24] +for i in a: + if i < 21: + continue + if i > 21: + break + print(i) +b=[a,a,a] +print(b[1][2]) +print(161//7) +a=24 +while True: + try: + def gcheck(): + global a + print(a) + gcheck() + class c25(): + x=25 + x=c25() + print(x.x) + raise + except: + print(26) + print(27+zero) + break +print(28) +k=29 +def f(): + global k + k = yield k +print(next(f())) +while True: + k+= 1 + if k < 30: + continue + break +print(k) +for i in [1,2,3]: + class A(): + def __init__(self, c): + self.a = i+10*c + b = A(3) + print(b.a) +print(34) +p=0 +for i in range(35, -1, -1): + print(i) + p = p + 1 + if p > 0: + break +p=36 +while p == 36: + print(p) + p=37 +print(p) +for i in [38]: + print(i) +print(int(exec("def foo(): return 38") == None)+foo()) +d = {} +exec("def bar(): return 40", d) +print(d["bar"]()) +def fib2(n): + result = [] + a, b = 0, 1 + while a < n: + result.append(a) + a, b = b, a+b + return result +print(fib2(100)[-2]-14) +Answer={} +Answer["ForAll"]=42 +print(Answer["ForAll"]) +i = 43 +def f(i=i): + print(i) +i = 44 +f() +print(i) +while True: + try: + if None != True: + print(45) + break + else: + print(0) + except: + print(0) +print(46) +print(46+1) +def u(p): + if p > 3: + return 3*p + else: + return u(2*p)-3*u(p) +print(u(16)) +def u49(): + return 49 +print(u49()) diff --git a/src/openmv/src/micropython/tests/misc/non_compliant.py b/src/openmv/src/micropython/tests/misc/non_compliant.py new file mode 100755 index 0000000..580583b --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/non_compliant.py @@ -0,0 +1,151 @@ +# tests for things that are not implemented, or have non-compliant behaviour + +try: + import array + import ustruct +except ImportError: + print("SKIP") + raise SystemExit + +# when super can't find self +try: + exec('def f(): super()') +except SyntaxError: + print('SyntaxError') + +# store to exception attribute is not allowed +try: + ValueError().x = 0 +except AttributeError: + print('AttributeError') + +# array deletion not implemented +try: + a = array.array('b', (1, 2, 3)) + del a[1] +except TypeError: + print('TypeError') + +# slice with step!=1 not implemented +try: + a = array.array('b', (1, 2, 3)) + print(a[3:2:2]) +except NotImplementedError: + print('NotImplementedError') + +# containment, looking for integer not implemented +try: + print(1 in array.array('B', b'12')) +except NotImplementedError: + print('NotImplementedError') + +# uPy raises TypeError, shold be ValueError +try: + '%c' % b'\x01\x02' +except (TypeError, ValueError): + print('TypeError, ValueError') + +# attributes/subscr not implemented +try: + print('{a[0]}'.format(a=[1, 2])) +except NotImplementedError: + print('NotImplementedError') + +# str(...) with keywords not implemented +try: + str(b'abc', encoding='utf8') +except NotImplementedError: + print('NotImplementedError') + +# str.rsplit(None, n) not implemented +try: + 'a a a'.rsplit(None, 1) +except NotImplementedError: + print('NotImplementedError') + +# str.endswith(s, start) not implemented +try: + 'abc'.endswith('c', 1) +except NotImplementedError: + print('NotImplementedError') + +# str subscr with step!=1 not implemented +try: + print('abc'[1:2:3]) +except NotImplementedError: + print('NotImplementedError') + +# bytes(...) with keywords not implemented +try: + bytes('abc', encoding='utf8') +except NotImplementedError: + print('NotImplementedError') + +# bytes subscr with step!=1 not implemented +try: + b'123'[0:3:2] +except NotImplementedError: + print('NotImplementedError') + +# tuple load with step!=1 not implemented +try: + ()[2:3:4] +except NotImplementedError: + print('NotImplementedError') + +# list store with step!=1 not implemented +try: + [][2:3:4] = [] +except NotImplementedError: + print('NotImplementedError') + +# list delete with step!=1 not implemented +try: + del [][2:3:4] +except NotImplementedError: + print('NotImplementedError') + +# struct pack with too many args, not checked by uPy +print(ustruct.pack('bb', 1, 2, 3)) + +# struct pack with too few args, not checked by uPy +print(ustruct.pack('bb', 1)) + +# array slice assignment with unsupported RHS +try: + bytearray(4)[0:1] = [1, 2] +except NotImplementedError: + print('NotImplementedError') + +# can't assign attributes to a function +def f(): + pass +try: + f.x = 1 +except AttributeError: + print('AttributeError') + +# can't call a function type (ie make new instances of a function) +try: + type(f)() +except TypeError: + print('TypeError') + +# test when object explicitly listed at not-last position in parent tuple +# this is not compliant with CPython because of illegal MRO +class A: + def foo(self): + print('A.foo') +class B(object, A): + pass +B().foo() + +# can't assign property (or other special accessors) to already-subclassed class +class A: + pass +class B(A): + pass +try: + A.bar = property() +except AttributeError: + print('AttributeError') diff --git a/src/openmv/src/micropython/tests/misc/non_compliant.py.exp b/src/openmv/src/micropython/tests/misc/non_compliant.py.exp new file mode 100755 index 0000000..3f15a14 --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/non_compliant.py.exp @@ -0,0 +1,23 @@ +SyntaxError +AttributeError +TypeError +NotImplementedError +NotImplementedError +TypeError, ValueError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError +b'\x01\x02' +b'\x01\x00' +NotImplementedError +AttributeError +TypeError +A.foo +AttributeError diff --git a/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py b/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py new file mode 100755 index 0000000..7e50d28 --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py @@ -0,0 +1,31 @@ +# lexer tests for things that are not implemented, or have non-compliant behaviour + +def test(code): + try: + exec(code) + print('no Error') + except SyntaxError: + print('SyntaxError') + except NotImplementedError: + print('NotImplementedError') + +# uPy requires spaces between literal numbers and keywords, CPy doesn't +try: + eval('1and 0') +except SyntaxError: + print('SyntaxError') +try: + eval('1or 0') +except SyntaxError: + print('SyntaxError') +try: + eval('1if 1else 0') +except SyntaxError: + print('SyntaxError') +try: + eval('1if 0else 0') +except SyntaxError: + print('SyntaxError') + +# unicode name escapes are not implemented +test('"\\N{LATIN SMALL LETTER A}"') diff --git a/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py.exp b/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py.exp new file mode 100755 index 0000000..cf1882a --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/non_compliant_lexer.py.exp @@ -0,0 +1,5 @@ +SyntaxError +SyntaxError +SyntaxError +SyntaxError +NotImplementedError diff --git a/src/openmv/src/micropython/tests/misc/print_exception.py b/src/openmv/src/micropython/tests/misc/print_exception.py new file mode 100755 index 0000000..9543163 --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/print_exception.py @@ -0,0 +1,67 @@ +import sys +try: + try: + import uio as io + except ImportError: + import io +except ImportError: + print("SKIP") + raise SystemExit + +if hasattr(sys, 'print_exception'): + print_exception = sys.print_exception +else: + import traceback + print_exception = lambda e, f: traceback.print_exception(None, e, sys.exc_info()[2], file=f) + +def print_exc(e): + buf = io.StringIO() + print_exception(e, buf) + s = buf.getvalue() + for l in s.split("\n"): + # uPy on pyboard prints as file, so remove filename. + if l.startswith(" File "): + l = l.split('"') + print(l[0], l[2]) + # uPy and CPy tracebacks differ in that CPy prints a source line for + # each traceback entry. In this case, we know that offending line + # has 4-space indent, so filter it out. + elif not l.startswith(" "): + print(l) + +# basic exception message +try: + raise Exception('msg') +except Exception as e: + print('caught') + print_exc(e) + +# exception message with more than 1 source-code line +def f(): + g() +def g(): + raise Exception('fail') +try: + f() +except Exception as e: + print('caught') + print_exc(e) + +# Here we have a function with lots of bytecode generated for a single source-line, and +# there is an error right at the end of the bytecode. It should report the correct line. +def f(): + f([1, 2], [1, 2], [1, 2], {1:1, 1:1, 1:1, 1:1, 1:1, 1:1, 1:f.X}) + return 1 +try: + f() +except Exception as e: + print_exc(e) + +# Test non-stream object passed as output object, only valid for uPy +if hasattr(sys, 'print_exception'): + try: + sys.print_exception(Exception, 1) + had_exception = False + except OSError: + had_exception = True + assert had_exception diff --git a/src/openmv/src/micropython/tests/misc/rge_sm.py b/src/openmv/src/micropython/tests/misc/rge_sm.py new file mode 100755 index 0000000..5bbf9d4 --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/rge_sm.py @@ -0,0 +1,114 @@ +# evolve the RGEs of the standard model from electroweak scale up +# by dpgeorge + +import math + +class RungeKutta(object): + def __init__(self, functions, initConditions, t0, dh, save=True): + self.Trajectory, self.save = [[t0] + initConditions], save + self.functions = [lambda *args: 1.0] + list(functions) + self.N, self.dh = len(self.functions), dh + self.coeff = [1.0/6.0, 2.0/6.0, 2.0/6.0, 1.0/6.0] + self.InArgCoeff = [0.0, 0.5, 0.5, 1.0] + + def iterate(self): + step = self.Trajectory[-1][:] + istep, iac = step[:], self.InArgCoeff + k, ktmp = self.N * [0.0], self.N * [0.0] + for ic, c in enumerate(self.coeff): + for if_, f in enumerate(self.functions): + arguments = [ (x + k[i]*iac[ic]) for i, x in enumerate(istep)] + try: + feval = f(*arguments) + except OverflowError: + return False + if abs(feval) > 1e2: # stop integrating + return False + ktmp[if_] = self.dh * feval + k = ktmp[:] + step = [s + c*k[ik] for ik,s in enumerate(step)] + if self.save: + self.Trajectory += [step] + else: + self.Trajectory = [step] + return True + + def solve(self, finishtime): + while self.Trajectory[-1][0] < finishtime: + if not self.iterate(): + break + + def solveNSteps(self, nSteps): + for i in range(nSteps): + if not self.iterate(): + break + + def series(self): + return zip(*self.Trajectory) + +# 1-loop RGES for the main parameters of the SM +# couplings are: g1, g2, g3 of U(1), SU(2), SU(3); yt (top Yukawa), lambda (Higgs quartic) +# see arxiv.org/abs/0812.4950, eqs 10-15 +sysSM = ( + lambda *a: 41.0 / 96.0 / math.pi**2 * a[1]**3, # g1 + lambda *a: -19.0 / 96.0 / math.pi**2 * a[2]**3, # g2 + lambda *a: -42.0 / 96.0 / math.pi**2 * a[3]**3, # g3 + lambda *a: 1.0 / 16.0 / math.pi**2 * (9.0 / 2.0 * a[4]**3 - 8.0 * a[3]**2 * a[4] - 9.0 / 4.0 * a[2]**2 * a[4] - 17.0 / 12.0 * a[1]**2 * a[4]), # yt + lambda *a: 1.0 / 16.0 / math.pi**2 * (24.0 * a[5]**2 + 12.0 * a[4]**2 * a[5] - 9.0 * a[5] * (a[2]**2 + 1.0 / 3.0 * a[1]**2) - 6.0 * a[4]**4 + 9.0 / 8.0 * a[2]**4 + 3.0 / 8.0 * a[1]**4 + 3.0 / 4.0 * a[2]**2 * a[1]**2), # lambda +) + +def drange(start, stop, step): + r = start + while r < stop: + yield r + r += step + +def phaseDiagram(system, trajStart, trajPlot, h=0.1, tend=1.0, range=1.0): + tstart = 0.0 + for i in drange(0, range, 0.1 * range): + for j in drange(0, range, 0.1 * range): + rk = RungeKutta(system, trajStart(i, j), tstart, h) + rk.solve(tend) + # draw the line + for tr in rk.Trajectory: + x, y = trajPlot(tr) + print(x, y) + print() + # draw the arrow + continue + l = (len(rk.Trajectory) - 1) / 3 + if l > 0 and 2 * l < len(rk.Trajectory): + p1 = rk.Trajectory[l] + p2 = rk.Trajectory[2 * l] + x1, y1 = trajPlot(p1) + x2, y2 = trajPlot(p2) + dx = -0.5 * (y2 - y1) # orthogonal to line + dy = 0.5 * (x2 - x1) # orthogonal to line + #l = math.sqrt(dx*dx + dy*dy) + #if abs(l) > 1e-3: + # l = 0.1 / l + # dx *= l + # dy *= l + print(x1 + dx, y1 + dy) + print(x2, y2) + print(x1 - dx, y1 - dy) + print() + +def singleTraj(system, trajStart, h=0.02, tend=1.0): + tstart = 0.0 + + # compute the trajectory + + rk = RungeKutta(system, trajStart, tstart, h) + rk.solve(tend) + + # print out trajectory + + for i in range(len(rk.Trajectory)): + tr = rk.Trajectory[i] + print(' '.join(["{:.4f}".format(t) for t in tr])) + +#phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17)) + +# initial conditions at M_Z +singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.5, tend=math.log(10**17)) # true values diff --git a/src/openmv/src/micropython/tests/misc/sys_exc_info.py b/src/openmv/src/micropython/tests/misc/sys_exc_info.py new file mode 100755 index 0000000..bf9438e --- /dev/null +++ b/src/openmv/src/micropython/tests/misc/sys_exc_info.py @@ -0,0 +1,21 @@ +import sys +try: + sys.exc_info +except: + print("SKIP") + raise SystemExit + +def f(): + print(sys.exc_info()[0:2]) + +try: + raise ValueError('value', 123) +except: + print(sys.exc_info()[0:2]) + f() + +# Outside except block, sys.exc_info() should be back to None's +f() + +# Recursive except blocks are not handled - just don't +# use exc_info() at all, use explicit variables in "except". diff --git a/src/openmv/src/micropython/tests/net_hosted/README b/src/openmv/src/micropython/tests/net_hosted/README new file mode 100755 index 0000000..724dd61 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/README @@ -0,0 +1,11 @@ +This directory contains network tests which require just "peer to peer" +network connection between test host and device under test, instead of +full Internet connection. + +Note that setup for these tests and tests themselves are WIP, and may +not yet fully correspond to the functional specification above. + +So far, these tests are not run as part of the main testsuite and need +to be run seperately (from the main test/ directory): + + ./run-tests net_hosted/*.py diff --git a/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py b/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py new file mode 100755 index 0000000..56f3288 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py @@ -0,0 +1,16 @@ +# test that socket.accept() on a non-blocking socket raises EAGAIN + +try: + import usocket as socket +except: + import socket + +s = socket.socket() +s.bind(socket.getaddrinfo('127.0.0.1', 8123)[0][-1]) +s.setblocking(False) +s.listen(1) +try: + s.accept() +except OSError as er: + print(er.args[0] == 11) # 11 is EAGAIN +s.close() diff --git a/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py.exp b/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py.exp new file mode 100755 index 0000000..0ca9514 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/accept_nonblock.py.exp @@ -0,0 +1 @@ +True diff --git a/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py b/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py new file mode 100755 index 0000000..44b3b8c --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py @@ -0,0 +1,22 @@ +# test that socket.accept() on a socket with timeout raises ETIMEDOUT + +try: + import usocket as socket +except: + import socket + +try: + socket.socket.settimeout +except AttributeError: + print('SKIP') + raise SystemExit + +s = socket.socket() +s.bind(socket.getaddrinfo('127.0.0.1', 8123)[0][-1]) +s.settimeout(1) +s.listen(1) +try: + s.accept() +except OSError as er: + print(er.args[0] in (110, 'timed out')) # 110 is ETIMEDOUT; CPython uses a string +s.close() diff --git a/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py.exp b/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py.exp new file mode 100755 index 0000000..0ca9514 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/accept_timeout.py.exp @@ -0,0 +1 @@ +True diff --git a/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py b/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py new file mode 100755 index 0000000..6479978 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py @@ -0,0 +1,20 @@ +# test that socket.connect() on a non-blocking socket raises EINPROGRESS + +try: + import usocket as socket +except: + import socket + + +def test(peer_addr): + s = socket.socket() + s.setblocking(False) + try: + s.connect(peer_addr) + except OSError as er: + print(er.args[0] == 115) # 115 is EINPROGRESS + s.close() + + +if __name__ == "__main__": + test(socket.getaddrinfo('micropython.org', 80)[0][-1]) diff --git a/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py.exp b/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py.exp new file mode 100755 index 0000000..0ca9514 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/connect_nonblock.py.exp @@ -0,0 +1 @@ +True diff --git a/src/openmv/src/micropython/tests/net_hosted/connect_poll.py b/src/openmv/src/micropython/tests/net_hosted/connect_poll.py new file mode 100755 index 0000000..ece6aa0 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/connect_poll.py @@ -0,0 +1,32 @@ +# test that socket.connect() has correct polling behaviour before, during and after + +try: + import usocket as socket, uselect as select +except: + import socket, select + + +def test(peer_addr): + s = socket.socket() + poller = select.poll() + poller.register(s) + + # test poll before connect + # note: CPython can return POLLHUP, so use the IN|OUT mask + p = poller.poll(0) + print(len(p), p[0][-1] & (select.POLLIN | select.POLLOUT)) + + s.connect(peer_addr) + + # test poll during connection + print(len(poller.poll(0))) + + # test poll after connection is established + p = poller.poll(1000) + print(len(p), p[0][-1]) + + s.close() + + +if __name__ == "__main__": + test(socket.getaddrinfo('micropython.org', 80)[0][-1]) diff --git a/src/openmv/src/micropython/tests/net_hosted/connect_poll.py.exp b/src/openmv/src/micropython/tests/net_hosted/connect_poll.py.exp new file mode 100755 index 0000000..cdf520e --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/connect_poll.py.exp @@ -0,0 +1,3 @@ +1 4 +1 +1 4 diff --git a/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py b/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py new file mode 100755 index 0000000..e265c83 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py @@ -0,0 +1,21 @@ +# test ssl.getpeercert() method + +try: + import usocket as socket + import ussl as ssl +except: + import socket + import ssl + + +def test(peer_addr): + s = socket.socket() + s.connect(peer_addr) + s = ssl.wrap_socket(s) + cert = s.getpeercert(True) + print(type(cert), len(cert) > 100) + s.close() + + +if __name__ == "__main__": + test(socket.getaddrinfo('micropython.org', 443)[0][-1]) diff --git a/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py.exp b/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py.exp new file mode 100755 index 0000000..ff7ef5a --- /dev/null +++ b/src/openmv/src/micropython/tests/net_hosted/ssl_getpeercert.py.exp @@ -0,0 +1 @@ + True diff --git a/src/openmv/src/micropython/tests/net_inet/README b/src/openmv/src/micropython/tests/net_inet/README new file mode 100755 index 0000000..9a5614e --- /dev/null +++ b/src/openmv/src/micropython/tests/net_inet/README @@ -0,0 +1,5 @@ +This directory contains network tests which require Internet connection. +Note that these tests are not run as part of the main testsuite and need +to be run seperately (from the main test/ directory): + + ./run-tests net_inet/*.py diff --git a/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py b/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py new file mode 100755 index 0000000..bf8071d --- /dev/null +++ b/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py @@ -0,0 +1,59 @@ +try: + import usocket as _socket +except: + import _socket +try: + import ussl as ssl +except: + import ssl + # CPython only supports server_hostname with SSLContext + ssl = ssl.SSLContext() + + +def test_one(site, opts): + ai = _socket.getaddrinfo(site, 443) + addr = ai[0][-1] + + s = _socket.socket() + + try: + s.connect(addr) + + if "sni" in opts: + s = ssl.wrap_socket(s, server_hostname=opts["host"]) + else: + s = ssl.wrap_socket(s) + + s.write(b"GET / HTTP/1.0\r\nHost: %s\r\n\r\n" % bytes(site, 'latin')) + resp = s.read(4096) +# print(resp) + + finally: + s.close() + + +SITES = [ + "google.com", + "www.google.com", + "api.telegram.org", + {"host": "api.pushbullet.com", "sni": True}, +# "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", + {"host": "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", "sni": True}, +] + + +def main(): + for site in SITES: + opts = {} + if isinstance(site, dict): + opts = site + site = opts["host"] + + try: + test_one(site, opts) + print(site, "ok") + except Exception as e: + print(site, repr(e)) + + +main() diff --git a/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py.exp b/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py.exp new file mode 100755 index 0000000..2f3c113 --- /dev/null +++ b/src/openmv/src/micropython/tests/net_inet/test_tls_sites.py.exp @@ -0,0 +1,5 @@ +google.com ok +www.google.com ok +api.telegram.org ok +api.pushbullet.com ok +w9rybpfril.execute-api.ap-southeast-2.amazonaws.com ok diff --git a/src/openmv/src/micropython/tests/pyb/accel.py b/src/openmv/src/micropython/tests/pyb/accel.py new file mode 100755 index 0000000..e5a1a2e --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/accel.py @@ -0,0 +1,9 @@ +import pyb + +accel = pyb.Accel() +print(accel) +accel.x() +accel.y() +accel.z() +accel.tilt() +accel.filtered_xyz() diff --git a/src/openmv/src/micropython/tests/pyb/accel.py.exp b/src/openmv/src/micropython/tests/pyb/accel.py.exp new file mode 100755 index 0000000..28070be --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/accel.py.exp @@ -0,0 +1 @@ + diff --git a/src/openmv/src/micropython/tests/pyb/adc.py b/src/openmv/src/micropython/tests/pyb/adc.py new file mode 100755 index 0000000..0bd9b9d --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/adc.py @@ -0,0 +1,62 @@ +from pyb import ADC, Timer + +adct = ADC(16) # Temperature 930 -> 20C +print(adct) +adcv = ADC(17) # Voltage 1500 -> 3.3V +print(adcv) + +# read single sample; 2.5V-5V is pass range +val = adcv.read() +assert val > 1000 and val < 2000 + +# timer for read_timed +tim = Timer(5, freq=500) + +# read into bytearray +buf = bytearray(b'\xff' * 50) +adcv.read_timed(buf, tim) +print(len(buf)) +for i in buf: + assert i > 50 and i < 150 + +# read into arrays with different element sizes +import array +arv = array.array('h', 25 * [0x7fff]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 + +arv = array.array('i', 30 * [-1]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 + +# Test read_timed_multi +arv = bytearray(b'\xff'*50) +art = bytearray(b'\xff'*50) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 60 and i < 125 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 15 and i < 200 + +arv = array.array('i', 25 * [-1]) +art = array.array('i', 25 * [-1]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 + +arv = array.array('h', 25 * [0x7fff]) +art = array.array('h', 25 * [0x7fff]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 diff --git a/src/openmv/src/micropython/tests/pyb/adc.py.exp b/src/openmv/src/micropython/tests/pyb/adc.py.exp new file mode 100755 index 0000000..1aae16f --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/adc.py.exp @@ -0,0 +1,5 @@ + + +50 +25 +30 diff --git a/src/openmv/src/micropython/tests/pyb/adcall.py b/src/openmv/src/micropython/tests/pyb/adcall.py new file mode 100755 index 0000000..cfe179a --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/adcall.py @@ -0,0 +1,31 @@ +from pyb import Pin, ADCAll + +pins = [Pin.cpu.A0, Pin.cpu.A1, Pin.cpu.A2, Pin.cpu.A3] + +# set pins to IN mode, init ADCAll, then check pins are ANALOG +for p in pins: + p.init(p.IN) +adc = ADCAll(12) +for p in pins: + print(p) + +# set pins to IN mode, init ADCAll with mask, then check some pins are ANALOG +for p in pins: + p.init(p.IN) +adc = ADCAll(12, 0x70003) +for p in pins: + print(p) + +# init all pins to ANALOG +adc = ADCAll(12) +print(adc) + +# read all channels +for c in range(19): + print(type(adc.read_channel(c))) + +# call special reading functions +print(0 < adc.read_core_temp() < 100) +print(0 < adc.read_core_vbat() < 4) +print(0 < adc.read_core_vref() < 2) +print(0 < adc.read_vref() < 4) diff --git a/src/openmv/src/micropython/tests/pyb/adcall.py.exp b/src/openmv/src/micropython/tests/pyb/adcall.py.exp new file mode 100755 index 0000000..5a85ba7 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/adcall.py.exp @@ -0,0 +1,32 @@ +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.ANALOG) +Pin(Pin.cpu.A3, mode=Pin.ANALOG) +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.IN) +Pin(Pin.cpu.A3, mode=Pin.IN) + + + + + + + + + + + + + + + + + + + + +True +True +True +True diff --git a/src/openmv/src/micropython/tests/pyb/can.py b/src/openmv/src/micropython/tests/pyb/can.py new file mode 100755 index 0000000..8a08ea9 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/can.py @@ -0,0 +1,309 @@ +try: + from pyb import CAN +except ImportError: + print('SKIP') + raise SystemExit + +from array import array +import micropython +import pyb + +# test we can correctly create by id or name +for bus in (-1, 0, 1, 2, 3, "YA", "YB", "YC"): + try: + CAN(bus, CAN.LOOPBACK) + print("CAN", bus) + except ValueError: + print("ValueError", bus) +CAN(1).deinit() + +CAN.initfilterbanks(14) +can = CAN(1) +print(can) + +# Test state when de-init'd +print(can.state() == can.STOPPED) + +can.init(CAN.LOOPBACK) +print(can) +print(can.any(0)) + +# Test state when freshly created +print(can.state() == can.ERROR_ACTIVE) + +# Test that restart can be called +can.restart() + +# Test info returns a sensible value +print(can.info()) + +# Catch all filter +can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) + +can.send('abcd', 123, timeout=5000) +print(can.any(0), can.info()) +print(can.recv(0)) + +can.send('abcd', -1, timeout=5000) +print(can.recv(0)) + +can.send('abcd', 0x7FF + 1, timeout=5000) +print(can.recv(0)) + +# Test too long message +try: + can.send('abcdefghi', 0x7FF, timeout=5000) +except ValueError: + print('passed') +else: + print('failed') + +# Test that recv can work without allocating memory on the heap + +buf = bytearray(10) +l = [0, 0, 0, memoryview(buf)] +l2 = None + +micropython.heap_lock() + +can.send('', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('1234', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('01234567', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('abc', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +micropython.heap_unlock() + +# Test that recv can work with different arrays behind the memoryview +can.send('abc', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('B', range(8)))])[3])) +can.send('def', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('b', range(8)))])[3])) + +# Test for non-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, 1) +except TypeError: + print('TypeError') + +# Test for too-short-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0]) +except ValueError: + print('ValueError') + +# Test for non-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, 0]) +except TypeError: + print('TypeError') + +# Test for read-only-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(bytes(8))]) +except ValueError: + print('ValueError') + +# Test for bad-typecode-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(array('i', range(8)))]) +except ValueError: + print('ValueError') + +del can + +# Testing extended IDs +can = CAN(1, CAN.LOOPBACK, extframe = True) +# Catch all filter +can.setfilter(0, CAN.MASK32, 0, (0, 0)) + +print(can) + +try: + can.send('abcde', 0x7FF + 1, timeout=5000) +except ValueError: + print('failed') +else: + r = can.recv(0) + if r[0] == 0x7FF+1 and r[3] == b'abcde': + print('passed') + else: + print('failed, wrong data received') + +# Test filters +for n in [0, 8, 16, 24]: + filter_id = 0b00001000 << n + filter_mask = 0b00011100 << n + id_ok = 0b00001010 << n + id_fail = 0b00011010 << n + + can.clearfilter(0) + can.setfilter(0, pyb.CAN.MASK32, 0, (filter_id, filter_mask)) + + can.send('ok', id_ok, timeout=3) + if can.any(0): + msg = can.recv(0) + print((hex(filter_id), hex(filter_mask), hex(msg[0]), msg[3])) + + can.send("fail", id_fail, timeout=3) + if can.any(0): + msg = can.recv(0) + print((hex(filter_id), hex(filter_mask), hex(msg[0]), msg[3])) + +del can + +# Test RxCallbacks +can = CAN(1, CAN.LOOPBACK) +can.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4)) +can.setfilter(1, CAN.LIST16, 1, (5, 6, 7, 8)) +def cb0(bus, reason): + print('cb0') + if reason == 0: + print('pending') + if reason == 1: + print('full') + if reason == 2: + print('overflow') + +def cb1(bus, reason): + print('cb1') + if reason == 0: + print('pending') + if reason == 1: + print('full') + if reason == 2: + print('overflow') + +def cb0a(bus, reason): + print('cb0a') + if reason == 0: + print('pending') + if reason == 1: + print('full') + if reason == 2: + print('overflow') + +def cb1a(bus, reason): + print('cb1a') + if reason == 0: + print('pending') + if reason == 1: + print('full') + if reason == 2: + print('overflow') + + +can.rxcallback(0, cb0) +can.rxcallback(1, cb1) + +can.send('11111111',1, timeout=5000) +can.send('22222222',2, timeout=5000) +can.send('33333333',3, timeout=5000) +can.rxcallback(0, cb0a) +can.send('44444444',4, timeout=5000) + +can.send('55555555',5, timeout=5000) +can.send('66666666',6, timeout=5000) +can.send('77777777',7, timeout=5000) +can.rxcallback(1, cb1a) +can.send('88888888',8, timeout=5000) + +print(can.recv(0)) +print(can.recv(0)) +print(can.recv(0)) +print(can.recv(1)) +print(can.recv(1)) +print(can.recv(1)) + +can.send('11111111',1, timeout=5000) +can.send('55555555',5, timeout=5000) + +print(can.recv(0)) +print(can.recv(1)) + +del can + +# Testing asynchronous send +can = CAN(1, CAN.LOOPBACK) +can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) + +while can.any(0): + can.recv(0) + +can.send('abcde', 1, timeout=0) +print(can.any(0)) +while not can.any(0): + pass + +print(can.recv(0)) + +try: + can.send('abcde', 2, timeout=0) + can.send('abcde', 3, timeout=0) + can.send('abcde', 4, timeout=0) + can.send('abcde', 5, timeout=0) +except OSError as e: + if str(e) == '16': + print('passed') + else: + print('failed') + +pyb.delay(500) +while can.any(0): + print(can.recv(0)) + +# Testing rtr messages +bus1 = CAN(1, CAN.LOOPBACK) +bus2 = CAN(2, CAN.LOOPBACK, extframe = True) +while bus1.any(0): + bus1.recv(0) +while bus2.any(0): + bus2.recv(0) +bus1.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4)) +bus1.setfilter(1, CAN.LIST16, 0, (5, 6, 7, 8), rtr=(True, True, True, True)) +bus1.setfilter(2, CAN.MASK16, 0, (64, 64, 32, 32), rtr=(False, True)) +bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True)) +bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False)) +bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,)) +bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,)) + +bus1.send('',1,rtr=True) +print(bus1.any(0)) +bus1.send('',5,rtr=True) +print(bus1.recv(0)) +bus1.send('',6,rtr=True) +print(bus1.recv(0)) +bus1.send('',7,rtr=True) +print(bus1.recv(0)) +bus1.send('',16,rtr=True) +print(bus1.any(0)) +bus1.send('',32,rtr=True) +print(bus1.recv(0)) + +bus2.send('',1,rtr=True) +print(bus2.recv(0)) +bus2.send('',2,rtr=True) +print(bus2.recv(0)) +bus2.send('',3,rtr=True) +print(bus2.recv(0)) +bus2.send('',4,rtr=True) +print(bus2.any(0)) diff --git a/src/openmv/src/micropython/tests/pyb/can.py.exp b/src/openmv/src/micropython/tests/pyb/can.py.exp new file mode 100755 index 0000000..687935e --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/can.py.exp @@ -0,0 +1,76 @@ +ValueError -1 +ValueError 0 +CAN 1 +CAN 2 +ValueError 3 +CAN YA +CAN YB +ValueError YC +CAN(1) +True +CAN(1, CAN.LOOPBACK, extframe=False, auto_restart=False) +False +True +[0, 0, 0, 0, 0, 0, 0, 0] +True [0, 0, 0, 0, 0, 0, 1, 0] +(123, False, 0, b'abcd') +(2047, False, 0, b'abcd') +(0, False, 0, b'abcd') +passed +[42, False, 0, ] 0 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 4 bytearray(b'1234\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 8 bytearray(b'01234567\x00\x00') +[42, False, 0, ] 3 bytearray(b'abc34567\x00\x00') +b'abc' +b'def' +TypeError +ValueError +TypeError +ValueError +ValueError +CAN(1, CAN.LOOPBACK, extframe=True, auto_restart=False) +passed +('0x8', '0x1c', '0xa', b'ok') +('0x800', '0x1c00', '0xa00', b'ok') +('0x80000', '0x1c0000', '0xa0000', b'ok') +('0x8000000', '0x1c000000', '0xa000000', b'ok') +cb0 +pending +cb0 +full +cb0a +overflow +cb1 +pending +cb1 +full +cb1a +overflow +(1, False, 0, b'11111111') +(2, False, 1, b'22222222') +(4, False, 3, b'44444444') +(5, False, 0, b'55555555') +(6, False, 1, b'66666666') +(8, False, 3, b'88888888') +cb0a +pending +cb1a +pending +(1, False, 0, b'11111111') +(5, False, 0, b'55555555') +False +(1, False, 0, b'abcde') +passed +(2, False, 0, b'abcde') +(3, False, 0, b'abcde') +(4, False, 0, b'abcde') +False +(5, True, 4, b'') +(6, True, 5, b'') +(7, True, 6, b'') +False +(32, True, 9, b'') +(1, True, 0, b'') +(2, True, 1, b'') +(3, True, 2, b'') +False diff --git a/src/openmv/src/micropython/tests/pyb/dac.py b/src/openmv/src/micropython/tests/pyb/dac.py new file mode 100755 index 0000000..ca68ec7 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/dac.py @@ -0,0 +1,18 @@ +import pyb + +if not hasattr(pyb, 'DAC'): + print('SKIP') + raise SystemExit + +dac = pyb.DAC(1) +print(dac) +dac.noise(100) +dac.triangle(100) +dac.write(0) +dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) +pyb.delay(20) +dac.write(0) + +# test buffering arg +dac = pyb.DAC(1, buffering=True) +dac.write(0) diff --git a/src/openmv/src/micropython/tests/pyb/dac.py.exp b/src/openmv/src/micropython/tests/pyb/dac.py.exp new file mode 100755 index 0000000..7ee9965 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/dac.py.exp @@ -0,0 +1 @@ +DAC(1, bits=8) diff --git a/src/openmv/src/micropython/tests/pyb/extint.py b/src/openmv/src/micropython/tests/pyb/extint.py new file mode 100755 index 0000000..ae98ccd --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/extint.py @@ -0,0 +1,17 @@ +import pyb + +# test basic functionality +ext = pyb.ExtInt('Y1', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_DOWN, lambda l:print('line:', l)) +ext.disable() +ext.enable() +print(ext.line()) +ext.swint() + +# test swint while disabled, then again after re-enabled +ext.disable() +ext.swint() +ext.enable() +ext.swint() + +# disable now that the test is finished +ext.disable() diff --git a/src/openmv/src/micropython/tests/pyb/extint.py.exp b/src/openmv/src/micropython/tests/pyb/extint.py.exp new file mode 100755 index 0000000..1f9da98 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/extint.py.exp @@ -0,0 +1,3 @@ +6 +line: 6 +line: 6 diff --git a/src/openmv/src/micropython/tests/pyb/halerror.py b/src/openmv/src/micropython/tests/pyb/halerror.py new file mode 100755 index 0000000..1a6bce1 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/halerror.py @@ -0,0 +1,15 @@ +# test hal errors + +import pyb + +i2c = pyb.I2C(2, pyb.I2C.MASTER) +try: + i2c.recv(1, 1) +except OSError as e: + print(repr(e)) + +can = pyb.CAN(1, pyb.CAN.NORMAL) +try: + can.send('1', 1, timeout=50) +except OSError as e: + print(repr(e)) diff --git a/src/openmv/src/micropython/tests/pyb/halerror.py.exp b/src/openmv/src/micropython/tests/pyb/halerror.py.exp new file mode 100755 index 0000000..0f3f262 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/halerror.py.exp @@ -0,0 +1,2 @@ +OSError(5,) +OSError(110,) diff --git a/src/openmv/src/micropython/tests/pyb/i2c.py b/src/openmv/src/micropython/tests/pyb/i2c.py new file mode 100755 index 0000000..6875e5a --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/i2c.py @@ -0,0 +1,32 @@ +import pyb +from pyb import I2C + +# test we can correctly create by id or name +for bus in (-1, 0, 1, 2, 3, "X", "Y", "Z"): + try: + I2C(bus) + print("I2C", bus) + except ValueError: + print("ValueError", bus) + +i2c = I2C(1) + +i2c.init(I2C.MASTER, baudrate=400000) +print(i2c.scan()) +i2c.deinit() + +# use accelerometer to test i2c bus + +accel_addr = 76 + +pyb.Accel() # this will init the MMA for us +i2c.init(I2C.MASTER, baudrate=400000) + +print(i2c.scan()) +print(i2c.is_ready(accel_addr)) + +print(i2c.mem_read(1, accel_addr, 7, timeout=500)) +i2c.mem_write(0, accel_addr, 0, timeout=500) + +i2c.send(7, addr=accel_addr) +i2c.recv(1, addr=accel_addr) diff --git a/src/openmv/src/micropython/tests/pyb/i2c.py.exp b/src/openmv/src/micropython/tests/pyb/i2c.py.exp new file mode 100755 index 0000000..709fb41 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/i2c.py.exp @@ -0,0 +1,12 @@ +ValueError -1 +ValueError 0 +I2C 1 +I2C 2 +ValueError 3 +I2C X +I2C Y +ValueError Z +[] +[76] +True +b'\x01' diff --git a/src/openmv/src/micropython/tests/pyb/i2c_error.py b/src/openmv/src/micropython/tests/pyb/i2c_error.py new file mode 100755 index 0000000..3201d63 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/i2c_error.py @@ -0,0 +1,50 @@ +# test I2C errors, with polling (disabled irqs) and DMA + +import pyb +from pyb import I2C + +# init accelerometer +pyb.Accel() + +# get I2C bus +i2c = I2C(1, I2C.MASTER, dma=True) + +# test polling mem_read +pyb.disable_irq() +i2c.mem_read(1, 76, 0x0a) # should succeed +pyb.enable_irq() +try: + pyb.disable_irq() + i2c.mem_read(1, 77, 0x0a) # should fail +except OSError as e: + pyb.enable_irq() + print(repr(e)) +i2c.mem_read(1, 76, 0x0a) # should succeed + +# test polling mem_write +pyb.disable_irq() +i2c.mem_write(1, 76, 0x0a) # should succeed +pyb.enable_irq() +try: + pyb.disable_irq() + i2c.mem_write(1, 77, 0x0a) # should fail +except OSError as e: + pyb.enable_irq() + print(repr(e)) +i2c.mem_write(1, 76, 0x0a) # should succeed + +# test DMA mem_read +i2c.mem_read(1, 76, 0x0a) # should succeed +try: + i2c.mem_read(1, 77, 0x0a) # should fail +except OSError as e: + print(repr(e)) +i2c.mem_read(1, 76, 0x0a) # should succeed + +# test DMA mem_write +i2c.mem_write(1, 76, 0x0a) # should succeed +try: + i2c.mem_write(1, 77, 0x0a) # should fail +except OSError as e: + print(repr(e)) +i2c.mem_write(1, 76, 0x0a) # should succeed diff --git a/src/openmv/src/micropython/tests/pyb/i2c_error.py.exp b/src/openmv/src/micropython/tests/pyb/i2c_error.py.exp new file mode 100755 index 0000000..bd403f7 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/i2c_error.py.exp @@ -0,0 +1,4 @@ +OSError(5,) +OSError(5,) +OSError(5,) +OSError(5,) diff --git a/src/openmv/src/micropython/tests/pyb/irq.py b/src/openmv/src/micropython/tests/pyb/irq.py new file mode 100755 index 0000000..42d2765 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/irq.py @@ -0,0 +1,22 @@ +import pyb + +def test_irq(): + # test basic disable/enable + i1 = pyb.disable_irq() + print(i1) + pyb.enable_irq() # by default should enable IRQ + + # check that interrupts are enabled by waiting for ticks + pyb.delay(10) + + # check nested disable/enable + i1 = pyb.disable_irq() + i2 = pyb.disable_irq() + print(i1, i2) + pyb.enable_irq(i2) + pyb.enable_irq(i1) + + # check that interrupts are enabled by waiting for ticks + pyb.delay(10) + +test_irq() diff --git a/src/openmv/src/micropython/tests/pyb/irq.py.exp b/src/openmv/src/micropython/tests/pyb/irq.py.exp new file mode 100755 index 0000000..aea065f --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/irq.py.exp @@ -0,0 +1,2 @@ +True +True False diff --git a/src/openmv/src/micropython/tests/pyb/led.py b/src/openmv/src/micropython/tests/pyb/led.py new file mode 100755 index 0000000..d2a17eb --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/led.py @@ -0,0 +1,40 @@ +import pyb +from pyb import LED + +l1 = pyb.LED(1) +l2 = pyb.LED(2) +l3 = pyb.LED(3) +l4 = pyb.LED(4) + +leds = [LED(i) for i in range(1, 5)] +pwm_leds = leds[2:] + +# test printing +for l in leds: + print(l) + +# test on and off +for l in leds: + l.on() + assert l.intensity() == 255 + pyb.delay(100) + l.off() + assert l.intensity() == 0 + pyb.delay(100) + +# test toggle +for l in 2 * leds: + l.toggle() + assert l.intensity() in (0, 255) + pyb.delay(100) + +# test intensity +for l in pwm_leds: + for i in range(256): + l.intensity(i) + assert l.intensity() == i + pyb.delay(1) + for i in range(255, -1, -1): + l.intensity(i) + assert l.intensity() == i + pyb.delay(1) diff --git a/src/openmv/src/micropython/tests/pyb/led.py.exp b/src/openmv/src/micropython/tests/pyb/led.py.exp new file mode 100755 index 0000000..4e8d856 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/led.py.exp @@ -0,0 +1,4 @@ +LED(1) +LED(2) +LED(3) +LED(4) diff --git a/src/openmv/src/micropython/tests/pyb/modstm.py b/src/openmv/src/micropython/tests/pyb/modstm.py new file mode 100755 index 0000000..f1e147c --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/modstm.py @@ -0,0 +1,13 @@ +# test stm module + +import stm +import pyb + +# test storing a full 32-bit number +# turn on then off the A15(=yellow) LED +BSRR = 0x18 +stm.mem32[stm.GPIOA + BSRR] = 0x00008000 +pyb.delay(100) +print(hex(stm.mem32[stm.GPIOA + stm.GPIO_ODR] & 0x00008000)) +stm.mem32[stm.GPIOA + BSRR] = 0x80000000 +print(hex(stm.mem32[stm.GPIOA + stm.GPIO_ODR] & 0x00008000)) diff --git a/src/openmv/src/micropython/tests/pyb/modstm.py.exp b/src/openmv/src/micropython/tests/pyb/modstm.py.exp new file mode 100755 index 0000000..a24c9f8 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/modstm.py.exp @@ -0,0 +1,2 @@ +0x8000 +0x0 diff --git a/src/openmv/src/micropython/tests/pyb/modtime.py b/src/openmv/src/micropython/tests/pyb/modtime.py new file mode 100755 index 0000000..d45440a --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/modtime.py @@ -0,0 +1,59 @@ +import time + +DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +def is_leap(year): + return (year % 4) == 0 + +def test(): + seconds = 0 + wday = 5 # Jan 1, 2000 was a Saturday + for year in range(2000, 2034): + print("Testing %d" % year) + yday = 1 + for month in range(1, 13): + if month == 2 and is_leap(year): + DAYS_PER_MONTH[2] = 29 + else: + DAYS_PER_MONTH[2] = 28 + for day in range(1, DAYS_PER_MONTH[month] + 1): + secs = time.mktime((year, month, day, 0, 0, 0, 0, 0)) + if secs != seconds: + print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + tuple = time.localtime(seconds) + secs = time.mktime(tuple) + if secs != seconds: + print("localtime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + return + seconds += 86400 + if yday != tuple[7]: + print("locatime for %d-%02d-%02d got yday %d, expecting %d" % (year, month, day, tuple[7], yday)) + return + if wday != tuple[6]: + print("locatime for %d-%02d-%02d got wday %d, expecting %d" % (year, month, day, tuple[6], wday)) + return + yday += 1 + wday = (wday + 1) % 7 + +def spot_test(seconds, expected_time): + actual_time = time.localtime(seconds) + for i in range(len(actual_time)): + if actual_time[i] != expected_time[i]: + print("time.localtime(", seconds, ") returned", actual_time, "expecting", expected_time) + return + print("time.localtime(", seconds, ") returned", actual_time, "(pass)") + + +test() +spot_test( 0, (2000, 1, 1, 0, 0, 0, 5, 1)) +spot_test( 1, (2000, 1, 1, 0, 0, 1, 5, 1)) +spot_test( 59, (2000, 1, 1, 0, 0, 59, 5, 1)) +spot_test( 60, (2000, 1, 1, 0, 1, 0, 5, 1)) +spot_test( 3599, (2000, 1, 1, 0, 59, 59, 5, 1)) +spot_test( 3600, (2000, 1, 1, 1, 0, 0, 5, 1)) +spot_test( -1, (1999, 12, 31, 23, 59, 59, 4, 365)) +spot_test( 447549467, (2014, 3, 7, 23, 17, 47, 4, 66)) +spot_test( -940984933, (1970, 3, 7, 23, 17, 47, 5, 66)) +spot_test(-1072915199, (1966, 1, 1, 0, 0, 1, 5, 1)) +spot_test(-1072915200, (1966, 1, 1, 0, 0, 0, 5, 1)) +spot_test(-1072915201, (1965, 12, 31, 23, 59, 59, 4, 365)) diff --git a/src/openmv/src/micropython/tests/pyb/modtime.py.exp b/src/openmv/src/micropython/tests/pyb/modtime.py.exp new file mode 100755 index 0000000..3e1f6e9 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/modtime.py.exp @@ -0,0 +1,46 @@ +Testing 2000 +Testing 2001 +Testing 2002 +Testing 2003 +Testing 2004 +Testing 2005 +Testing 2006 +Testing 2007 +Testing 2008 +Testing 2009 +Testing 2010 +Testing 2011 +Testing 2012 +Testing 2013 +Testing 2014 +Testing 2015 +Testing 2016 +Testing 2017 +Testing 2018 +Testing 2019 +Testing 2020 +Testing 2021 +Testing 2022 +Testing 2023 +Testing 2024 +Testing 2025 +Testing 2026 +Testing 2027 +Testing 2028 +Testing 2029 +Testing 2030 +Testing 2031 +Testing 2032 +Testing 2033 +time.localtime( 0 ) returned (2000, 1, 1, 0, 0, 0, 5, 1) (pass) +time.localtime( 1 ) returned (2000, 1, 1, 0, 0, 1, 5, 1) (pass) +time.localtime( 59 ) returned (2000, 1, 1, 0, 0, 59, 5, 1) (pass) +time.localtime( 60 ) returned (2000, 1, 1, 0, 1, 0, 5, 1) (pass) +time.localtime( 3599 ) returned (2000, 1, 1, 0, 59, 59, 5, 1) (pass) +time.localtime( 3600 ) returned (2000, 1, 1, 1, 0, 0, 5, 1) (pass) +time.localtime( -1 ) returned (1999, 12, 31, 23, 59, 59, 4, 365) (pass) +time.localtime( 447549467 ) returned (2014, 3, 7, 23, 17, 47, 4, 66) (pass) +time.localtime( -940984933 ) returned (1970, 3, 7, 23, 17, 47, 5, 66) (pass) +time.localtime( -1072915199 ) returned (1966, 1, 1, 0, 0, 1, 5, 1) (pass) +time.localtime( -1072915200 ) returned (1966, 1, 1, 0, 0, 0, 5, 1) (pass) +time.localtime( -1072915201 ) returned (1965, 12, 31, 23, 59, 59, 4, 365) (pass) diff --git a/src/openmv/src/micropython/tests/pyb/pin.py b/src/openmv/src/micropython/tests/pyb/pin.py new file mode 100755 index 0000000..9b37883 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pin.py @@ -0,0 +1,33 @@ +from pyb import Pin + +p = Pin('Y1', Pin.IN) +print(p) +print(p.name()) +print(p.pin()) +print(p.port()) + +p = Pin('Y1', Pin.IN, Pin.PULL_UP) +p = Pin('Y1', Pin.IN, pull=Pin.PULL_UP) +p = Pin('Y1', mode=Pin.IN, pull=Pin.PULL_UP) +print(p) +print(p.value()) + +p.init(p.IN, p.PULL_DOWN) +p.init(p.IN, pull=p.PULL_DOWN) +p.init(mode=p.IN, pull=p.PULL_DOWN) +print(p) +print(p.value()) + +p.init(p.OUT_PP) +p.low() +print(p.value()) +p.high() +print(p.value()) +p.value(0) +print(p.value()) +p.value(1) +print(p.value()) +p.value(False) +print(p.value()) +p.value(True) +print(p.value()) diff --git a/src/openmv/src/micropython/tests/pyb/pin.py.exp b/src/openmv/src/micropython/tests/pyb/pin.py.exp new file mode 100755 index 0000000..f2f7038 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pin.py.exp @@ -0,0 +1,14 @@ +Pin(Pin.cpu.C6, mode=Pin.IN) +C6 +6 +2 +Pin(Pin.cpu.C6, mode=Pin.IN, pull=Pin.PULL_UP) +1 +Pin(Pin.cpu.C6, mode=Pin.IN, pull=Pin.PULL_DOWN) +0 +0 +1 +0 +1 +0 +1 diff --git a/src/openmv/src/micropython/tests/pyb/pyb1.py b/src/openmv/src/micropython/tests/pyb/pyb1.py new file mode 100755 index 0000000..443722c --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb1.py @@ -0,0 +1,39 @@ +# basic tests of pyb module + +import pyb + +# test delay + +pyb.delay(-1) +pyb.delay(0) +pyb.delay(1) + +start = pyb.millis() +pyb.delay(17) +print((pyb.millis() - start) // 5) # should print 3 + +# test udelay + +pyb.udelay(-1) +pyb.udelay(0) +pyb.udelay(1) + +start = pyb.millis() +pyb.udelay(17000) +print((pyb.millis() - start) // 5) # should print 3 + +# other + +pyb.disable_irq() +pyb.enable_irq() + +print(pyb.have_cdc()) + +pyb.sync() + +print(len(pyb.unique_id())) + +pyb.wfi() + +pyb.fault_debug(True) +pyb.fault_debug(False) diff --git a/src/openmv/src/micropython/tests/pyb/pyb1.py.exp b/src/openmv/src/micropython/tests/pyb/pyb1.py.exp new file mode 100755 index 0000000..5816ea9 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb1.py.exp @@ -0,0 +1,4 @@ +3 +3 +True +12 diff --git a/src/openmv/src/micropython/tests/pyb/pyb_f405.py b/src/openmv/src/micropython/tests/pyb/pyb_f405.py new file mode 100755 index 0000000..2f161ae --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb_f405.py @@ -0,0 +1,10 @@ +# test pyb module on F405 MCUs + +import os, pyb + +if not 'STM32F405' in os.uname().machine: + print('SKIP') + raise SystemExit + +print(pyb.freq()) +print(type(pyb.rng())) diff --git a/src/openmv/src/micropython/tests/pyb/pyb_f405.py.exp b/src/openmv/src/micropython/tests/pyb/pyb_f405.py.exp new file mode 100755 index 0000000..a90aa02 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb_f405.py.exp @@ -0,0 +1,2 @@ +(168000000, 168000000, 42000000, 84000000) + diff --git a/src/openmv/src/micropython/tests/pyb/pyb_f411.py b/src/openmv/src/micropython/tests/pyb/pyb_f411.py new file mode 100755 index 0000000..50de302 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb_f411.py @@ -0,0 +1,9 @@ +# test pyb module on F411 MCUs + +import os, pyb + +if not 'STM32F411' in os.uname().machine: + print('SKIP') + raise SystemExit + +print(pyb.freq()) diff --git a/src/openmv/src/micropython/tests/pyb/pyb_f411.py.exp b/src/openmv/src/micropython/tests/pyb/pyb_f411.py.exp new file mode 100755 index 0000000..79e0a10 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/pyb_f411.py.exp @@ -0,0 +1 @@ +(96000000, 96000000, 24000000, 48000000) diff --git a/src/openmv/src/micropython/tests/pyb/rtc.py b/src/openmv/src/micropython/tests/pyb/rtc.py new file mode 100755 index 0000000..844526b --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/rtc.py @@ -0,0 +1,79 @@ +import pyb, stm +from pyb import RTC + +rtc = RTC() +rtc.init() +print(rtc) + +# make sure that 1 second passes correctly +rtc.datetime((2014, 1, 1, 1, 0, 0, 0, 0)) +pyb.delay(1002) +print(rtc.datetime()[:7]) + +def set_and_print(datetime): + rtc.datetime(datetime) + print(rtc.datetime()[:7]) + +# make sure that setting works correctly +set_and_print((2000, 1, 1, 1, 0, 0, 0, 0)) +set_and_print((2000, 1, 31, 1, 0, 0, 0, 0)) +set_and_print((2000, 12, 31, 1, 0, 0, 0, 0)) +set_and_print((2016, 12, 31, 1, 0, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 0, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 1, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 12, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 13, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 23, 0, 0, 0)) +set_and_print((2016, 12, 31, 7, 23, 1, 0, 0)) +set_and_print((2016, 12, 31, 7, 23, 59, 0, 0)) +set_and_print((2016, 12, 31, 7, 23, 59, 1, 0)) +set_and_print((2016, 12, 31, 7, 23, 59, 59, 0)) +set_and_print((2099, 12, 31, 7, 23, 59, 59, 0)) + +# check that calibration works correctly +# save existing calibration value: +cal_tmp = rtc.calibration() + +def set_and_print_calib(cal): + rtc.calibration(cal) + print(rtc.calibration()) + +set_and_print_calib(512) +set_and_print_calib(511) +set_and_print_calib(345) +set_and_print_calib(1) +set_and_print_calib(0) +set_and_print_calib(-1) +set_and_print_calib(-123) +set_and_print_calib(-510) +set_and_print_calib(-511) + +# restore existing calibration value +rtc.calibration(cal_tmp) + +# Check register settings for wakeup +def set_and_print_wakeup(ms): + try: + rtc.wakeup(ms) + wucksel = stm.mem32[stm.RTC + stm.RTC_CR] & 7 + wut = stm.mem32[stm.RTC + stm.RTC_WUTR] & 0xffff + except ValueError: + wucksel = -1 + wut = -1 + print((wucksel, wut)) + +set_and_print_wakeup(0) +set_and_print_wakeup(1) +set_and_print_wakeup(4000) +set_and_print_wakeup(4001) +set_and_print_wakeup(8000) +set_and_print_wakeup(8001) +set_and_print_wakeup(16000) +set_and_print_wakeup(16001) +set_and_print_wakeup(32000) +set_and_print_wakeup(32001) +set_and_print_wakeup(0x10000*1000) +set_and_print_wakeup(0x10001*1000) +set_and_print_wakeup(0x1ffff*1000) +set_and_print_wakeup(0x20000*1000) +set_and_print_wakeup(0x20001*1000) # exception diff --git a/src/openmv/src/micropython/tests/pyb/rtc.py.exp b/src/openmv/src/micropython/tests/pyb/rtc.py.exp new file mode 100755 index 0000000..7d3aaf6 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/rtc.py.exp @@ -0,0 +1,40 @@ + +(2014, 1, 1, 1, 0, 0, 1) +(2000, 1, 1, 1, 0, 0, 0) +(2000, 1, 31, 1, 0, 0, 0) +(2000, 12, 31, 1, 0, 0, 0) +(2016, 12, 31, 1, 0, 0, 0) +(2016, 12, 31, 7, 0, 0, 0) +(2016, 12, 31, 7, 1, 0, 0) +(2016, 12, 31, 7, 12, 0, 0) +(2016, 12, 31, 7, 13, 0, 0) +(2016, 12, 31, 7, 23, 0, 0) +(2016, 12, 31, 7, 23, 1, 0) +(2016, 12, 31, 7, 23, 59, 0) +(2016, 12, 31, 7, 23, 59, 1) +(2016, 12, 31, 7, 23, 59, 59) +(2099, 12, 31, 7, 23, 59, 59) +512 +511 +345 +1 +0 +-1 +-123 +-510 +-511 +(3, 0) +(3, 15) +(3, 65535) +(2, 32775) +(2, 65535) +(1, 32771) +(1, 65535) +(0, 32769) +(0, 65535) +(4, 31) +(4, 65535) +(6, 0) +(6, 65534) +(6, 65535) +(-1, -1) diff --git a/src/openmv/src/micropython/tests/pyb/servo.py b/src/openmv/src/micropython/tests/pyb/servo.py new file mode 100755 index 0000000..d15cafe --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/servo.py @@ -0,0 +1,16 @@ +from pyb import Servo + +servo = Servo(1) +print(servo) + +servo.angle(0) +servo.angle(10, 100) + +servo.speed(-10) +servo.speed(10, 100) + +servo.pulse_width(1500) +print(servo.pulse_width()) + +servo.calibration(630, 2410, 1490, 2460, 2190) +print(servo.calibration()) diff --git a/src/openmv/src/micropython/tests/pyb/servo.py.exp b/src/openmv/src/micropython/tests/pyb/servo.py.exp new file mode 100755 index 0000000..ac6032b --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/servo.py.exp @@ -0,0 +1,3 @@ + +1500 +(630, 2410, 1490, 2460, 2190) diff --git a/src/openmv/src/micropython/tests/pyb/spi.py b/src/openmv/src/micropython/tests/pyb/spi.py new file mode 100755 index 0000000..88cc975 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/spi.py @@ -0,0 +1,33 @@ +from pyb import SPI + +# test we can correctly create by id or name +for bus in (-1, 0, 1, 2, 3, "X", "Y", "Z"): + try: + SPI(bus) + print("SPI", bus) + except ValueError: + print("ValueError", bus) + +spi = SPI(1) +print(spi) + +spi = SPI(1, SPI.MASTER) +spi = SPI(1, SPI.MASTER, baudrate=500000) +spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None) +print(spi) + +spi.init(SPI.SLAVE, phase=1) +print(spi) +try: + # need to flush input before we get an error (error is what we want to test) + for i in range(10): + spi.recv(1, timeout=100) +except OSError: + print("OSError") + +spi.init(SPI.MASTER) +spi.send(1, timeout=100) +print(spi.recv(1, timeout=100)) +print(spi.send_recv(1, timeout=100)) + +spi.deinit() diff --git a/src/openmv/src/micropython/tests/pyb/spi.py.exp b/src/openmv/src/micropython/tests/pyb/spi.py.exp new file mode 100755 index 0000000..a0d8357 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/spi.py.exp @@ -0,0 +1,14 @@ +ValueError -1 +ValueError 0 +SPI 1 +SPI 2 +ValueError 3 +SPI X +SPI Y +ValueError Z +SPI(1) +SPI(1, SPI.MASTER, baudrate=328125, prescaler=256, polarity=1, phase=0, bits=8) +SPI(1, SPI.SLAVE, polarity=1, phase=1, bits=8) +OSError +b'\xff' +b'\xff' diff --git a/src/openmv/src/micropython/tests/pyb/switch.py b/src/openmv/src/micropython/tests/pyb/switch.py new file mode 100755 index 0000000..7c44adb --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/switch.py @@ -0,0 +1,6 @@ +from pyb import Switch + +sw = Switch() +print(sw()) +sw.callback(print) +sw.callback(None) diff --git a/src/openmv/src/micropython/tests/pyb/switch.py.exp b/src/openmv/src/micropython/tests/pyb/switch.py.exp new file mode 100755 index 0000000..bc59c12 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/switch.py.exp @@ -0,0 +1 @@ +False diff --git a/src/openmv/src/micropython/tests/pyb/timer.py b/src/openmv/src/micropython/tests/pyb/timer.py new file mode 100755 index 0000000..6132069 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/timer.py @@ -0,0 +1,13 @@ +# check basic functionality of the timer class + +import pyb +from pyb import Timer + +tim = Timer(4) +tim = Timer(4, prescaler=100, period=200) +print(tim.prescaler()) +print(tim.period()) +tim.prescaler(300) +print(tim.prescaler()) +tim.period(400) +print(tim.period()) diff --git a/src/openmv/src/micropython/tests/pyb/timer.py.exp b/src/openmv/src/micropython/tests/pyb/timer.py.exp new file mode 100755 index 0000000..5c46230 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/timer.py.exp @@ -0,0 +1,4 @@ +100 +200 +300 +400 diff --git a/src/openmv/src/micropython/tests/pyb/timer_callback.py b/src/openmv/src/micropython/tests/pyb/timer_callback.py new file mode 100755 index 0000000..864dd47 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/timer_callback.py @@ -0,0 +1,49 @@ +# check callback feature of the timer class + +import pyb +from pyb import Timer + +# callback function that disables the callback when called +def cb1(t): + print("cb1") + t.callback(None) + +# callback function that disables the timer when called +def cb2(t): + print("cb2") + t.deinit() + +# callback where cb4 closes over cb3.y +def cb3(x): + y = x + def cb4(t): + print("cb4", y) + t.callback(None) + return cb4 + +# create a timer with a callback, using callback(None) to stop +tim = Timer(1, freq=100, callback=cb1) +pyb.delay(5) +print("before cb1") +pyb.delay(15) + +# create a timer with a callback, using deinit to stop +tim = Timer(2, freq=100, callback=cb2) +pyb.delay(5) +print("before cb2") +pyb.delay(15) + +# create a timer, then set the freq, then set the callback +tim = Timer(4) +tim.init(freq=100) +tim.callback(cb1) +pyb.delay(5) +print("before cb1") +pyb.delay(15) + +# test callback with a closure +tim.init(freq=100) +tim.callback(cb3(3)) +pyb.delay(5) +print("before cb4") +pyb.delay(15) diff --git a/src/openmv/src/micropython/tests/pyb/timer_callback.py.exp b/src/openmv/src/micropython/tests/pyb/timer_callback.py.exp new file mode 100755 index 0000000..9be7cf5 --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/timer_callback.py.exp @@ -0,0 +1,8 @@ +before cb1 +cb1 +before cb2 +cb2 +before cb1 +cb1 +before cb4 +cb4 3 diff --git a/src/openmv/src/micropython/tests/pyb/uart.py b/src/openmv/src/micropython/tests/pyb/uart.py new file mode 100755 index 0000000..838dd9c --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/uart.py @@ -0,0 +1,32 @@ +from pyb import UART + +# test we can correctly create by id or name +for bus in (-1, 0, 1, 2, 3, 4, 5, 6, 7, "XA", "XB", "YA", "YB", "Z"): + try: + UART(bus, 9600) + print("UART", bus) + except ValueError: + print("ValueError", bus) + +uart = UART(1) +uart = UART(1, 9600) +uart = UART(1, 9600, bits=8, parity=None, stop=1) +print(uart) + +uart.init(2400) +print(uart) + +print(uart.any()) +print(uart.write('123')) +print(uart.write(b'abcd')) +print(uart.writechar(1)) + +# make sure this method exists +uart.sendbreak() + +# non-blocking mode +uart = UART(1, 9600, timeout=0) +print(uart.write(b'1')) +print(uart.write(b'abcd')) +print(uart.writechar(1)) +print(uart.read(100)) diff --git a/src/openmv/src/micropython/tests/pyb/uart.py.exp b/src/openmv/src/micropython/tests/pyb/uart.py.exp new file mode 100755 index 0000000..b5fe0cd --- /dev/null +++ b/src/openmv/src/micropython/tests/pyb/uart.py.exp @@ -0,0 +1,24 @@ +ValueError -1 +ValueError 0 +UART 1 +UART 2 +UART 3 +UART 4 +ValueError 5 +UART 6 +ValueError 7 +UART XA +UART XB +UART YA +UART YB +ValueError Z +UART(1, baudrate=9600, bits=8, parity=None, stop=1, timeout=1000, timeout_char=3, read_buf_len=64) +UART(1, baudrate=2400, bits=8, parity=None, stop=1, timeout=1000, timeout_char=7, read_buf_len=64) +0 +3 +4 +None +1 +4 +None +None diff --git a/src/openmv/src/micropython/tests/pybnative/for.py b/src/openmv/src/micropython/tests/pybnative/for.py new file mode 100755 index 0000000..309c6c1 --- /dev/null +++ b/src/openmv/src/micropython/tests/pybnative/for.py @@ -0,0 +1,15 @@ +import pyb + +@micropython.native +def f1(n): + for i in range(n): + print(i) + +f1(4) + +@micropython.native +def f2(r): + for i in r: + print(i) + +f2(range(4)) diff --git a/src/openmv/src/micropython/tests/pybnative/for.py.exp b/src/openmv/src/micropython/tests/pybnative/for.py.exp new file mode 100755 index 0000000..d4dc73e --- /dev/null +++ b/src/openmv/src/micropython/tests/pybnative/for.py.exp @@ -0,0 +1,8 @@ +0 +1 +2 +3 +0 +1 +2 +3 diff --git a/src/openmv/src/micropython/tests/pybnative/while.py b/src/openmv/src/micropython/tests/pybnative/while.py new file mode 100755 index 0000000..3ea7221 --- /dev/null +++ b/src/openmv/src/micropython/tests/pybnative/while.py @@ -0,0 +1,15 @@ +import pyb + +@micropython.native +def f(led, n, d): + led.off() + i = 0 + while i < n: + print(i) + led.toggle() + pyb.delay(d) + i += 1 + led.off() + +f(pyb.LED(1), 2, 150) +f(pyb.LED(2), 4, 50) diff --git a/src/openmv/src/micropython/tests/pybnative/while.py.exp b/src/openmv/src/micropython/tests/pybnative/while.py.exp new file mode 100755 index 0000000..d95e7f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/pybnative/while.py.exp @@ -0,0 +1,6 @@ +0 +1 +0 +1 +2 +3 diff --git a/src/openmv/src/micropython/tests/run-bench-tests b/src/openmv/src/micropython/tests/run-bench-tests new file mode 100755 index 0000000..f4a6776 --- /dev/null +++ b/src/openmv/src/micropython/tests/run-bench-tests @@ -0,0 +1,97 @@ +#! /usr/bin/env python3 + +import os +import subprocess +import sys +import argparse +import re +from glob import glob +from collections import defaultdict + +# Tests require at least CPython 3.3. If your default python3 executable +# is of lower version, you can point MICROPY_CPYTHON3 environment var +# to the correct executable. +if os.name == 'nt': + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe') +else: + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython') + +def run_tests(pyb, test_dict): + test_count = 0 + testcase_count = 0 + + for base_test, tests in sorted(test_dict.items()): + print(base_test + ":") + for test_file in tests: + + # run MicroPython + if pyb is None: + # run on PC + try: + output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file[0]]) + except subprocess.CalledProcessError: + output_mupy = b'CRASH' + else: + # run on pyboard + pyb.enter_raw_repl() + try: + output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') + except pyboard.PyboardError: + output_mupy = b'CRASH' + + output_mupy = float(output_mupy.strip()) + test_file[1] = output_mupy + testcase_count += 1 + + test_count += 1 + baseline = None + for t in tests: + if baseline is None: + baseline = t[1] + print(" %.3fs (%+06.2f%%) %s" % (t[1], (t[1] * 100 / baseline) - 100, t[0])) + + print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) + + # all tests succeeded + return True + +def main(): + cmd_parser = argparse.ArgumentParser(description='Run tests for MicroPython.') + cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + # Note pyboard support is copied over from run-tests, not testes, and likely needs revamping + if args.pyboard: + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') + pyb.enter_raw_repl() + else: + pyb = None + + if len(args.files) == 0: + if pyb is None: + # run PC tests + test_dirs = ('bench',) + else: + # run pyboard tests + test_dirs = ('basics', 'float', 'pyb') + tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) + else: + # tests explicitly given + tests = sorted(args.files) + + test_dict = defaultdict(lambda: []) + for t in tests: + m = re.match(r"(.+?)-(.+)\.py", t) + if not m: + continue + test_dict[m.group(1)].append([t, None]) + + if not run_tests(pyb, test_dict): + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/tests/run-tests b/src/openmv/src/micropython/tests/run-tests new file mode 100755 index 0000000..d72ae9d --- /dev/null +++ b/src/openmv/src/micropython/tests/run-tests @@ -0,0 +1,574 @@ +#! /usr/bin/env python3 + +import os +import subprocess +import sys +import platform +import argparse +import re +from glob import glob + +# Tests require at least CPython 3.3. If your default python3 executable +# is of lower version, you can point MICROPY_CPYTHON3 environment var +# to the correct executable. +if os.name == 'nt': + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/windows/micropython.exe') +else: + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../ports/unix/micropython') + +# mpy-cross is only needed if --via-mpy command-line arg is passed +MPYCROSS = os.getenv('MICROPY_MPYCROSS', '../mpy-cross/mpy-cross') + +# Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale +os.environ['PYTHONIOENCODING'] = 'utf-8' + +def rm_f(fname): + if os.path.exists(fname): + os.remove(fname) + + +# unescape wanted regex chars and escape unwanted ones +def convert_regex_escapes(line): + cs = [] + escape = False + for c in str(line, 'utf8'): + if escape: + escape = False + cs.append(c) + elif c == '\\': + escape = True + elif c in ('(', ')', '[', ']', '{', '}', '.', '*', '+', '^', '$'): + cs.append('\\' + c) + else: + cs.append(c) + # accept carriage-return(s) before final newline + if cs[-1] == '\n': + cs[-1] = '\r*\n' + return bytes(''.join(cs), 'utf8') + + +def run_micropython(pyb, args, test_file, is_special=False): + special_tests = ( + 'micropython/meminfo.py', 'basics/bytes_compare3.py', + 'basics/builtin_help.py', 'thread/thread_exc2.py', + ) + had_crash = False + if pyb is None: + # run on PC + if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests: + # special handling for tests of the unix cmdline program + is_special = True + + if is_special: + # check for any cmdline options needed for this test + args = [MICROPYTHON] + with open(test_file, 'rb') as f: + line = f.readline() + if line.startswith(b'# cmdline:'): + # subprocess.check_output on Windows only accepts strings, not bytes + args += [str(c, 'utf-8') for c in line[10:].strip().split()] + + # run the test, possibly with redirected input + try: + if 'repl_' in test_file: + # Need to use a PTY to test command line editing + try: + import pty + except ImportError: + # in case pty module is not available, like on Windows + return b'SKIP\n' + import select + + def get(required=False): + rv = b'' + while True: + ready = select.select([master], [], [], 0.02) + if ready[0] == [master]: + rv += os.read(master, 1024) + else: + if not required or rv: + return rv + + def send_get(what): + os.write(master, what) + return get() + + with open(test_file, 'rb') as f: + # instead of: output_mupy = subprocess.check_output(args, stdin=f) + master, slave = pty.openpty() + p = subprocess.Popen(args, stdin=slave, stdout=slave, + stderr=subprocess.STDOUT, bufsize=0) + banner = get(True) + output_mupy = banner + b''.join(send_get(line) for line in f) + send_get(b'\x04') # exit the REPL, so coverage info is saved + p.kill() + os.close(master) + os.close(slave) + else: + output_mupy = subprocess.check_output(args + [test_file], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + return b'CRASH' + + else: + # a standard test run on PC + + # create system command + cmdlist = [MICROPYTHON, '-X', 'emit=' + args.emit] + if args.heapsize is not None: + cmdlist.extend(['-X', 'heapsize=' + args.heapsize]) + + # if running via .mpy, first compile the .py file + if args.via_mpy: + subprocess.check_output([MPYCROSS, '-mcache-lookup-bc', '-o', 'mpytest.mpy', test_file]) + cmdlist.extend(['-m', 'mpytest']) + else: + cmdlist.append(test_file) + + # run the actual test + try: + output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as er: + had_crash = True + output_mupy = er.output + b'CRASH' + + # clean up if we had an intermediate .mpy file + if args.via_mpy: + rm_f('mpytest.mpy') + + else: + # run on pyboard + pyb.enter_raw_repl() + try: + output_mupy = pyb.execfile(test_file) + except pyboard.PyboardError as e: + had_crash = True + if not is_special and e.args[0] == 'exception': + output_mupy = e.args[1] + e.args[2] + b'CRASH' + else: + output_mupy = b'CRASH' + + # canonical form for all ports/platforms is to use \n for end-of-line + output_mupy = output_mupy.replace(b'\r\n', b'\n') + + # don't try to convert the output if we should skip this test + if had_crash or output_mupy in (b'SKIP\n', b'CRASH'): + return output_mupy + + if is_special or test_file in special_tests: + # convert parts of the output that are not stable across runs + with open(test_file + '.exp', 'rb') as f: + lines_exp = [] + for line in f.readlines(): + if line == b'########\n': + line = (line,) + else: + line = (line, re.compile(convert_regex_escapes(line))) + lines_exp.append(line) + lines_mupy = [line + b'\n' for line in output_mupy.split(b'\n')] + if output_mupy.endswith(b'\n'): + lines_mupy = lines_mupy[:-1] # remove erroneous last empty line + i_mupy = 0 + for i in range(len(lines_exp)): + if lines_exp[i][0] == b'########\n': + # 8x #'s means match 0 or more whole lines + line_exp = lines_exp[i + 1] + skip = 0 + while i_mupy + skip < len(lines_mupy) and not line_exp[1].match(lines_mupy[i_mupy + skip]): + skip += 1 + if i_mupy + skip >= len(lines_mupy): + lines_mupy[i_mupy] = b'######## FAIL\n' + break + del lines_mupy[i_mupy:i_mupy + skip] + lines_mupy.insert(i_mupy, b'########\n') + i_mupy += 1 + else: + # a regex + if lines_exp[i][1].match(lines_mupy[i_mupy]): + lines_mupy[i_mupy] = lines_exp[i][0] + else: + #print("don't match: %r %s" % (lines_exp[i][1], lines_mupy[i_mupy])) # DEBUG + pass + i_mupy += 1 + if i_mupy >= len(lines_mupy): + break + output_mupy = b''.join(lines_mupy) + + return output_mupy + + +def run_feature_check(pyb, args, base_path, test_file): + return run_micropython(pyb, args, base_path + "/feature_check/" + test_file, is_special=True) + + +def run_tests(pyb, tests, args, base_path="."): + test_count = 0 + testcase_count = 0 + passed_count = 0 + failed_tests = [] + skipped_tests = [] + + skip_tests = set() + skip_native = False + skip_int_big = False + skip_set_type = False + skip_async = False + skip_const = False + skip_revops = False + skip_endian = False + has_complex = True + has_coverage = False + + upy_float_precision = 32 + + # If we're asked to --list-tests, we can't assume that there's a + # connection to target, so we can't run feature checks usefully. + if not (args.list_tests or args.write_exp): + # Check if micropython.native is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'native_check.py') + if output == b'CRASH': + skip_native = True + + # Check if arbitrary-precision integers are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'int_big.py') + if output != b'1000000000000000000000000000000000000000000000\n': + skip_int_big = True + + # Check if set type (and set literals) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'set_check.py') + if output == b'CRASH': + skip_set_type = True + + # Check if async/await keywords are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'async_check.py') + if output == b'CRASH': + skip_async = True + + # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'const.py') + if output == b'CRASH': + skip_const = True + + # Check if __rOP__ special methods are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') + if output == b'TypeError\n': + skip_revops = True + + # Check if emacs repl is supported, and skip such tests if it's not + t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') + if not 'True' in str(t, 'ascii'): + skip_tests.add('cmdline/repl_emacs_keys.py') + + upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') + upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py')) + has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' + has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' + cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) + skip_endian = (upy_byteorder != cpy_byteorder) + + # Some tests shouldn't be run under Travis CI + if os.getenv('TRAVIS') == 'true': + skip_tests.add('basics/memoryerror.py') + skip_tests.add('thread/thread_gc1.py') # has reliability issues + skip_tests.add('thread/thread_lock4.py') # has reliability issues + skip_tests.add('thread/stress_heap.py') # has reliability issues + skip_tests.add('thread/stress_recurse.py') # has reliability issues + + if upy_float_precision == 0: + skip_tests.add('extmod/uctypes_le_float.py') + skip_tests.add('extmod/uctypes_native_float.py') + skip_tests.add('extmod/uctypes_sizeof_float.py') + skip_tests.add('extmod/ujson_dumps_float.py') + skip_tests.add('extmod/ujson_loads_float.py') + skip_tests.add('extmod/urandom_extra_float.py') + skip_tests.add('misc/rge_sm.py') + if upy_float_precision < 32: + skip_tests.add('float/float2int_intbig.py') # requires fp32, there's float2int_fp30_intbig.py instead + skip_tests.add('float/string_format.py') # requires fp32, there's string_format_fp30.py instead + skip_tests.add('float/bytes_construct.py') # requires fp32 + skip_tests.add('float/bytearray_construct.py') # requires fp32 + if upy_float_precision < 64: + skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead + skip_tests.add('float/float2int_doubleprec_intbig.py') + skip_tests.add('float/float_parse_doubleprec.py') + + if not has_complex: + skip_tests.add('float/complex1.py') + skip_tests.add('float/complex1_intbig.py') + skip_tests.add('float/int_big_float.py') + skip_tests.add('float/true_value.py') + skip_tests.add('float/types.py') + + if not has_coverage: + skip_tests.add('cmdline/cmd_parsetree.py') + + # Some tests shouldn't be run on a PC + if args.target == 'unix': + # unix build does not have the GIL so can't run thread mutation tests + for t in tests: + if t.startswith('thread/mutate_'): + skip_tests.add(t) + + # Some tests shouldn't be run on pyboard + if args.target != 'unix': + skip_tests.add('basics/exception_chain.py') # warning is not printed + skip_tests.add('micropython/meminfo.py') # output is very different to PC output + skip_tests.add('extmod/machine_mem.py') # raw memory access not supported + + if args.target == 'wipy': + skip_tests.add('misc/print_exception.py') # requires error reporting full + skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes + skip_tests.add('extmod/zlibd_decompress.py') # requires zlib + skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy + skip_tests.add('extmod/urandom_basic.py') # requires urandom + skip_tests.add('extmod/urandom_extra.py') # requires urandom + elif args.target == 'esp8266': + skip_tests.add('misc/rge_sm.py') # too large + elif args.target == 'minimal': + skip_tests.add('basics/class_inplace_op.py') # all special methods not supported + skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support + skip_tests.add('misc/rge_sm.py') # too large + skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored + elif args.target == 'nrf': + skip_tests.add('basics/memoryview1.py') # no item assignment for memoryview + skip_tests.add('extmod/ticks_diff.py') # unimplemented: utime.ticks_diff + skip_tests.add('extmod/time_ms_us.py') # unimplemented: utime.ticks_ms + skip_tests.add('extmod/urandom_basic.py') # unimplemented: urandom.seed + skip_tests.add('micropython/opt_level.py') # no support for line numbers + skip_tests.add('misc/non_compliant.py') # no item assignment for bytearray + for t in tests: + if t.startswith('basics/io_'): + skip_tests.add(t) + + # Some tests are known to fail on 64-bit machines + if pyb is None and platform.architecture()[0] == '64bit': + pass + + # Some tests use unsupported features on Windows + if os.name == 'nt': + skip_tests.add('import/import_file.py') # works but CPython prints forward slashes + + # Some tests are known to fail with native emitter + # Remove them from the below when they work + if args.emit == 'native': + skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from_close generator_name'.split()}) # require raise_varargs, generator name + skip_tests.update({'basics/async_%s.py' % t for t in 'with with2 with_break with_return'.split()}) # require async_with + skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs + skip_tests.add('basics/del_deref.py') # requires checking for unbound local + skip_tests.add('basics/del_local.py') # requires checking for unbound local + skip_tests.add('basics/exception_chain.py') # raise from is not supported + skip_tests.add('basics/try_finally_return2.py') # requires raise_varargs + skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local + skip_tests.add('misc/features.py') # requires raise_varargs + skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info + skip_tests.add('misc/sys_exc_info.py') # sys.exc_info() is not supported for native + skip_tests.add('micropython/emg_exc.py') # because native doesn't have proper traceback info + skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info + skip_tests.add('micropython/schedule.py') # native code doesn't check pending events + + for test_file in tests: + test_file = test_file.replace('\\', '/') + + if args.filters: + # Default verdict is the opposit of the first action + verdict = "include" if args.filters[0][0] == "exclude" else "exclude" + for action, pat in args.filters: + if pat.search(test_file): + verdict = action + if verdict == "exclude": + continue + + test_basename = test_file.replace('..', '_').replace('./', '').replace('/', '_') + test_name = os.path.splitext(os.path.basename(test_file))[0] + is_native = test_name.startswith("native_") or test_name.startswith("viper_") + is_endian = test_name.endswith("_endian") + is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") + is_set_type = test_name.startswith("set_") or test_name.startswith("frozenset") + is_async = test_name.startswith("async_") + is_const = test_name.startswith("const") + + skip_it = test_file in skip_tests + skip_it |= skip_native and is_native + skip_it |= skip_endian and is_endian + skip_it |= skip_int_big and is_int_big + skip_it |= skip_set_type and is_set_type + skip_it |= skip_async and is_async + skip_it |= skip_const and is_const + skip_it |= skip_revops and test_name.startswith("class_reverse_op") + + if args.list_tests: + if not skip_it: + print(test_file) + continue + + if skip_it: + print("skip ", test_file) + skipped_tests.append(test_name) + continue + + # get expected output + test_file_expected = test_file + '.exp' + if os.path.isfile(test_file_expected): + # expected output given by a file, so read that in + with open(test_file_expected, 'rb') as f: + output_expected = f.read() + else: + # run CPython to work out expected output + try: + output_expected = subprocess.check_output([CPYTHON3, '-B', test_file]) + if args.write_exp: + with open(test_file_expected, 'wb') as f: + f.write(output_expected) + except subprocess.CalledProcessError: + output_expected = b'CPYTHON3 CRASH' + + # canonical form for all host platforms is to use \n for end-of-line + output_expected = output_expected.replace(b'\r\n', b'\n') + + if args.write_exp: + continue + + # run MicroPython + output_mupy = run_micropython(pyb, args, test_file) + + if output_mupy == b'SKIP\n': + print("skip ", test_file) + skipped_tests.append(test_name) + continue + + testcase_count += len(output_expected.splitlines()) + + filename_expected = test_basename + ".exp" + filename_mupy = test_basename + ".out" + + if output_expected == output_mupy: + print("pass ", test_file) + passed_count += 1 + rm_f(filename_expected) + rm_f(filename_mupy) + else: + with open(filename_expected, "wb") as f: + f.write(output_expected) + with open(filename_mupy, "wb") as f: + f.write(output_mupy) + print("FAIL ", test_file) + failed_tests.append(test_name) + + test_count += 1 + + if args.list_tests: + return True + + print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) + print("{} tests passed".format(passed_count)) + + if len(skipped_tests) > 0: + print("{} tests skipped: {}".format(len(skipped_tests), ' '.join(skipped_tests))) + if len(failed_tests) > 0: + print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests))) + return False + + # all tests succeeded + return True + + +class append_filter(argparse.Action): + + def __init__(self, option_strings, dest, **kwargs): + super().__init__(option_strings, dest, default=[], **kwargs) + + def __call__(self, parser, args, value, option): + if not hasattr(args, self.dest): + args.filters = [] + if option.startswith(("-e", "--e")): + option = "exclude" + else: + option = "include" + args.filters.append((option, re.compile(value))) + + +def main(): + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Run and manage tests for MicroPython.', + epilog='''\ +Options -i and -e can be multiple and processed in the order given. Regex +"search" (vs "match") operation is used. An action (include/exclude) of +the last matching regex is used: + run-tests -i async - exclude all, then include tests containg "async" anywhere + run-tests -e '/big.+int' - include all, then exclude by regex + run-tests -e async -i async_foo - include all, exclude async, yet still include async_foo +''') + cmd_parser.add_argument('--target', default='unix', help='the target platform') + cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') + cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') + cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') + cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') + cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') + cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py') + cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py') + cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython') + cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') + cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') + cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') + cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first') + cmd_parser.add_argument('--keep-path', action='store_true', help='do not clear MICROPYPATH when running tests') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf') + if args.target == 'unix' or args.list_tests: + pyb = None + elif args.target in EXTERNAL_TARGETS: + global pyboard + sys.path.append('../tools') + import pyboard + pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) + pyb.enter_raw_repl() + else: + raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS)) + + if len(args.files) == 0: + if args.test_dirs is None: + if args.target == 'pyboard': + # run pyboard tests + test_dirs = ('basics', 'micropython', 'float', 'misc', 'stress', 'extmod', 'pyb', 'pybnative', 'inlineasm') + elif args.target in ('esp8266', 'esp32', 'minimal', 'nrf'): + test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod') + elif args.target == 'wipy': + # run WiPy tests + test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'wipy') + else: + # run PC tests + test_dirs = ( + 'basics', 'micropython', 'float', 'import', 'io', 'misc', + 'stress', 'unicode', 'extmod', 'unix', 'cmdline', + ) + else: + # run tests from these directories + test_dirs = args.test_dirs + tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) + else: + # tests explicitly given + tests = args.files + + if not args.keep_path: + # clear search path to make sure tests use only builtin modules + os.environ['MICROPYPATH'] = '' + + # Even if we run completely different tests in a different directory, + # we need to access feature_check's from the same directory as the + # run-tests script itself. + base_path = os.path.dirname(sys.argv[0]) or "." + try: + res = run_tests(pyb, tests, args, base_path) + finally: + if pyb: + pyb.close() + + if not res: + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/tests/run-tests-exp.py b/src/openmv/src/micropython/tests/run-tests-exp.py new file mode 100755 index 0000000..3af8fea --- /dev/null +++ b/src/openmv/src/micropython/tests/run-tests-exp.py @@ -0,0 +1,96 @@ +# +# This is minimal MicroPython variant of run-tests script, which uses +# .exp files as generated by run-tests --write-exp. It is useful to run +# testsuite on systems which have neither CPython3 nor unix shell. +# This script is intended to be run by the same interpreter executable +# which is to be tested, so should use minimal language functionality. +# +import sys +import uos as os + + +tests = [ + "basics", "micropython", "float", "import", "io", + " misc", "unicode", "extmod", "unix" +] + +if sys.platform == 'win32': + MICROPYTHON = "micropython.exe" +else: + MICROPYTHON = "micropython" + + +def should_skip(test): + if test.startswith("native"): + return True + if test.startswith("viper"): + return True + +test_count = 0 +passed_count = 0 +skip_count = 0 + +for suite in tests: + #print("Running in: %s" % suite) + if sys.platform == 'win32': + # dir /b prints only contained filenames, one on a line + # http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/dir.mspx + r = os.system("dir /b %s/*.py >tests.lst" % suite) + else: + r = os.system("ls %s/*.py | xargs -n1 basename >tests.lst" % suite) + assert r == 0 + + with open("tests.lst") as f: + testcases = f.readlines() + testcases = [l[:-1] for l in testcases] + assert testcases, "No tests found in dir '%s', which is implausible" % suite + #print(testcases) + for t in testcases: + if t == "native_check.py": + continue + + qtest = "%s/%s" % (suite, t) + + if should_skip(t): + print("skip " + qtest) + skip_count += 1 + continue + + exp = None + try: + f = open(qtest + ".exp") + exp = f.read() + f.close() + except OSError: + pass + + if exp is not None: + #print("run " + qtest) + r = os.system(MICROPYTHON + " %s >.tst.out" % qtest) + if r == 0: + f = open(".tst.out") + out = f.read() + f.close() + else: + out = "CRASH" + + if out == "SKIP\n": + print("skip " + qtest) + skip_count += 1 + else: + if out == exp: + print("pass " + qtest) + passed_count += 1 + else: + print("FAIL " + qtest) + + test_count += 1 + else: + skip_count += 1 + +print("%s tests performed" % test_count) +print("%s tests passed" % passed_count) +if test_count != passed_count: + print("%s tests failed" % (test_count - passed_count)) +if skip_count: + print("%s tests skipped" % skip_count) diff --git a/src/openmv/src/micropython/tests/run-tests-exp.sh b/src/openmv/src/micropython/tests/run-tests-exp.sh new file mode 100755 index 0000000..8f81b96 --- /dev/null +++ b/src/openmv/src/micropython/tests/run-tests-exp.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# +# This is plain shell variant of run-tests script, which uses .exp files +# as generated by run-tests --write-exp. It is useful to run testsuite +# on embedded systems which don't have CPython3. +# + +RM="rm -f" +MP_PY=micropython + +numtests=0 +numtestcases=0 +numpassed=0 +numskipped=0 +numfailed=0 +nameskipped= +namefailed= + +if [ $# -eq 0 ] +then + tests="basics/*.py micropython/*.py float/*.py import/*.py io/*.py misc/*.py unicode/*.py extmod/*.py unix/*.py" +else + tests="$@" +fi + +for infile in $tests +do + basename=`basename $infile .py` + outfile=${basename}.py.out + expfile=$infile.exp + + $MP_PY $infile > $outfile + numtestcases=$(expr $numtestcases + $(cat $expfile | wc -l)) + + if grep -q "SKIP\|SyntaxError: invalid micropython decorator" $outfile + then + # we don't count tests that explicitly ask to be skipped + # we don't count tests that fail due to unsupported decorator + echo "skip $infile" + $RM $outfile + numskipped=$(expr $numskipped + 1) + nameskipped="$nameskipped $basename" + else + diff --brief $expfile $outfile > /dev/null + + if [ $? -eq 0 ] + then + echo "pass $infile" + $RM $outfile + numpassed=$(expr $numpassed + 1) + else + echo "FAIL $infile" + numfailed=$(expr $numfailed + 1) + namefailed="$namefailed $basename" + fi + fi + + numtests=$(expr $numtests + 1) +done + +echo "$numtests tests performed ($numtestcases individual testcases)" +echo "$numpassed tests passed" +if [ $numskipped != 0 ] +then + echo "$numskipped tests skipped -$nameskipped" +fi +if [ $numfailed != 0 ] +then + echo "$numfailed tests failed -$namefailed" + exit 1 +else + exit 0 +fi diff --git a/src/openmv/src/micropython/tests/stress/dict_copy.py b/src/openmv/src/micropython/tests/stress/dict_copy.py new file mode 100755 index 0000000..36db9bb --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/dict_copy.py @@ -0,0 +1,7 @@ +# copying a large dictionary + +a = {i:2*i for i in range(1000)} +b = a.copy() +for i in range(1000): + print(i, b[i]) +print(len(b)) diff --git a/src/openmv/src/micropython/tests/stress/dict_create.py b/src/openmv/src/micropython/tests/stress/dict_create.py new file mode 100755 index 0000000..e9db40a --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/dict_create.py @@ -0,0 +1,8 @@ +# create a large dictionary + +d = {} +x = 1 +while x < 1000: + d[x] = x + x += 1 +print(d[500]) diff --git a/src/openmv/src/micropython/tests/stress/dict_create_max.py b/src/openmv/src/micropython/tests/stress/dict_create_max.py new file mode 100755 index 0000000..3c75db2 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/dict_create_max.py @@ -0,0 +1,13 @@ +# The aim with this test is to hit the maximum resize/rehash size of a dict, +# where there are no more primes in the table of growing allocation sizes. +# This value is 54907 items. + +d = {} +try: + for i in range(54908): + d[i] = i +except MemoryError: + pass + +# Just check the dict still has the first value +print(d[0]) diff --git a/src/openmv/src/micropython/tests/stress/gc_trace.py b/src/openmv/src/micropython/tests/stress/gc_trace.py new file mode 100755 index 0000000..72dc7b6 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/gc_trace.py @@ -0,0 +1,17 @@ +# test that the GC can trace nested objects + +try: + import gc +except ImportError: + print("SKIP") + raise SystemExit + +# test a big shallow object pointing to many unique objects +lst = [[i] for i in range(200)] +gc.collect() +print(lst) + +# test a deep object +lst = [[[[[(i, j, k, l)] for i in range(3)] for j in range(3)] for k in range(3)] for l in range(3)] +gc.collect() +print(lst) diff --git a/src/openmv/src/micropython/tests/stress/list_sort.py b/src/openmv/src/micropython/tests/stress/list_sort.py new file mode 100755 index 0000000..3a7701a --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/list_sort.py @@ -0,0 +1,6 @@ +# test large list sorting (should not stack overflow) +l = list(range(2000)) +l.sort() +print(l[0], l[-1]) +l.sort(reverse=True) +print(l[0], l[-1]) diff --git a/src/openmv/src/micropython/tests/stress/recursion.py b/src/openmv/src/micropython/tests/stress/recursion.py new file mode 100755 index 0000000..227f483 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursion.py @@ -0,0 +1,7 @@ +def foo(): + foo() + +try: + foo() +except RuntimeError: + print("RuntimeError") diff --git a/src/openmv/src/micropython/tests/stress/recursive_data.py b/src/openmv/src/micropython/tests/stress/recursive_data.py new file mode 100755 index 0000000..3b7fa50 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursive_data.py @@ -0,0 +1,13 @@ +# This tests that printing recursive data structure doesn't lead to segfault. +try: + import uio as io +except ImportError: + print("SKIP") + raise SystemExit + +l = [1, 2, 3, None] +l[-1] = l +try: + print(l, file=io.StringIO()) +except RuntimeError: + print("RuntimeError") diff --git a/src/openmv/src/micropython/tests/stress/recursive_data.py.exp b/src/openmv/src/micropython/tests/stress/recursive_data.py.exp new file mode 100755 index 0000000..8a2b9bf --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursive_data.py.exp @@ -0,0 +1 @@ +RuntimeError diff --git a/src/openmv/src/micropython/tests/stress/recursive_gen.py b/src/openmv/src/micropython/tests/stress/recursive_gen.py new file mode 100755 index 0000000..0e0d391 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursive_gen.py @@ -0,0 +1,18 @@ +# test deeply recursive generators + +# simple "yield from" recursion +def gen(): + yield from gen() +try: + list(gen()) +except RuntimeError: + print('RuntimeError') + +# recursion via an iterator over a generator +def gen2(): + for x in gen2(): + yield x +try: + next(gen2()) +except RuntimeError: + print('RuntimeError') diff --git a/src/openmv/src/micropython/tests/stress/recursive_iternext.py b/src/openmv/src/micropython/tests/stress/recursive_iternext.py new file mode 100755 index 0000000..edb5a84 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursive_iternext.py @@ -0,0 +1,57 @@ +# This tests that recursion with iternext doesn't lead to segfault. +try: + enumerate + filter + map + max + zip +except: + print("SKIP") + raise SystemExit + +# We need to pick an N that is large enough to hit the recursion +# limit, but not too large that we run out of heap memory. +try: + # large stack/heap, eg unix + [0] * 80000 + N = 2400 +except: + try: + # medium, eg pyboard + [0] * 10000 + N = 1000 + except: + # small, eg esp8266 + N = 100 + +try: + x = (1, 2) + for i in range(N): + x = enumerate(x) + tuple(x) +except RuntimeError: + print("RuntimeError") + +try: + x = (1, 2) + for i in range(N): + x = filter(None, x) + tuple(x) +except RuntimeError: + print("RuntimeError") + +try: + x = (1, 2) + for i in range(N): + x = map(max, x, ()) + tuple(x) +except RuntimeError: + print("RuntimeError") + +try: + x = (1, 2) + for i in range(N): + x = zip(x) + tuple(x) +except RuntimeError: + print("RuntimeError") diff --git a/src/openmv/src/micropython/tests/stress/recursive_iternext.py.exp b/src/openmv/src/micropython/tests/stress/recursive_iternext.py.exp new file mode 100755 index 0000000..80d1488 --- /dev/null +++ b/src/openmv/src/micropython/tests/stress/recursive_iternext.py.exp @@ -0,0 +1,4 @@ +RuntimeError +RuntimeError +RuntimeError +RuntimeError diff --git a/src/openmv/src/micropython/tests/thread/mutate_bytearray.py b/src/openmv/src/micropython/tests/thread/mutate_bytearray.py new file mode 100755 index 0000000..f3276f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/mutate_bytearray.py @@ -0,0 +1,45 @@ +# test concurrent mutating access to a shared bytearray object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared bytearray +ba = bytearray() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + l = len(ba) + ba.append(i) + assert len(ba) >= l + 1 + + l = len(ba) + ba.extend(bytearray([i])) + assert len(ba) >= l + 1 + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 +n_repeat = 4 # use 40 for more stressful test (uses more heap) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (n_repeat, i * 256 // n_thread, (i + 1) * 256 // n_thread)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check bytearray has correct contents +print(len(ba)) +count = [0 for _ in range(256)] +for b in ba: + count[b] += 1 +print(count) + diff --git a/src/openmv/src/micropython/tests/thread/mutate_dict.py b/src/openmv/src/micropython/tests/thread/mutate_dict.py new file mode 100755 index 0000000..c57d332 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/mutate_dict.py @@ -0,0 +1,42 @@ +# test concurrent mutating access to a shared dict object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared dict +di = {'a':'A', 'b':'B', 'c':'C', 'd':'D'} + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + di[i] = repeat + i + assert di[i] == repeat + i + + del di[i] + assert i not in di + + di[i] = repeat + i + assert di[i] == repeat + i + + assert di.pop(i) == repeat + i + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (30, i * 300, (i + 1) * 300)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check dict has correct contents +print(sorted(di.items())) diff --git a/src/openmv/src/micropython/tests/thread/mutate_instance.py b/src/openmv/src/micropython/tests/thread/mutate_instance.py new file mode 100755 index 0000000..a1ae428 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/mutate_instance.py @@ -0,0 +1,43 @@ +# test concurrent mutating access to a shared user instance +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared user class and instance +class User: + def __init__(self): + self.a = 'A' + self.b = 'B' + self.c = 'C' +user = User() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + setattr(user, 'attr_%u' % i, repeat + i) + assert getattr(user, 'attr_%u' % i) == repeat + i + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_repeat = 30 +n_range = 50 # 300 for stressful test (uses more heap) +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (n_repeat, i * n_range, (i + 1) * n_range)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check user instance has correct contents +print(user.a, user.b, user.c) +for i in range(n_thread * n_range): + assert getattr(user, 'attr_%u' % i) == n_repeat - 1 + i diff --git a/src/openmv/src/micropython/tests/thread/mutate_list.py b/src/openmv/src/micropython/tests/thread/mutate_list.py new file mode 100755 index 0000000..764a9bd --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/mutate_list.py @@ -0,0 +1,44 @@ +# test concurrent mutating access to a shared list object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared list +li = list() + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + li.append(i) + assert li.count(i) == repeat + 1 + + li.extend([i, i]) + assert li.count(i) == repeat + 3 + + li.remove(i) + assert li.count(i) == repeat + 2 + + li.remove(i) + assert li.count(i) == repeat + 1 + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (4, i * 60, (i + 1) * 60)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check list has correct contents +li.sort() +print(li) diff --git a/src/openmv/src/micropython/tests/thread/mutate_set.py b/src/openmv/src/micropython/tests/thread/mutate_set.py new file mode 100755 index 0000000..5492d86 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/mutate_set.py @@ -0,0 +1,37 @@ +# test concurrent mutating access to a shared set object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# the shared set +se = set([-1, -2, -3, -4]) + +# main thread function +def th(n, lo, hi): + for repeat in range(n): + for i in range(lo, hi): + se.add(i) + assert i in se + + se.remove(i) + assert i not in se + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (50, i * 500, (i + 1) * 500)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass + +# check set has correct contents +print(sorted(se)) diff --git a/src/openmv/src/micropython/tests/thread/stress_aes.py b/src/openmv/src/micropython/tests/thread/stress_aes.py new file mode 100755 index 0000000..df75e61 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/stress_aes.py @@ -0,0 +1,255 @@ +# Stress test for threads using AES encryption routines. +# +# AES was chosen because it is integer based and inplace so doesn't use the +# heap. It is therefore a good test of raw performance and correctness of the +# VM/runtime. It can be used to measure threading performance (concurrency is +# in principle possible) and correctness (it's non trivial for the encryption/ +# decryption to give the correct answer). +# +# The AES code comes first (code originates from a C version authored by D.P.George) +# and then the test harness at the bottom. It can be tuned to be more/less +# aggressive by changing the amount of data to encrypt, the number of loops and +# the number of threads. +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +################################################################## +# discrete arithmetic routines, mostly from a precomputed table + +# non-linear, invertible, substitution box +aes_s_box_table = bytes(( + 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16, +)) + +# multiplication of polynomials modulo x^8 + x^4 + x^3 + x + 1 = 0x11b +def aes_gf8_mul_2(x): + if x & 0x80: + return (x << 1) ^ 0x11b + else: + return x << 1 + +def aes_gf8_mul_3(x): + return x ^ aes_gf8_mul_2(x) + +# non-linear, invertible, substitution box +def aes_s_box(a): + return aes_s_box_table[a & 0xff] + +# return 0x02^(a-1) in GF(2^8) +def aes_r_con(a): + ans = 1 + while a > 1: + ans <<= 1; + if ans & 0x100: + ans ^= 0x11b + a -= 1 + return ans + +################################################################## +# basic AES algorithm; see FIPS-197 +# +# Think of it as a pseudo random number generator, with each +# symbol in the sequence being a 16 byte block (the state). The +# key is a parameter of the algorithm and tells which particular +# sequence of random symbols you want. The initial vector, IV, +# sets the start of the sequence. The idea of a strong cipher +# is that it's very difficult to guess the key even if you know +# a large part of the sequence. The basic AES algorithm simply +# provides such a sequence. En/de-cryption is implemented here +# using OCB, where the sequence is xored against the plaintext. +# Care must be taken to (almost) always choose a different IV. + +# all inputs must be size 16 +def aes_add_round_key(state, w): + for i in range(16): + state[i] ^= w[i] + +# combined sub_bytes, shift_rows, mix_columns, add_round_key +# all inputs must be size 16 +def aes_sb_sr_mc_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = aes_gf8_mul_2(x0) ^ aes_gf8_mul_3(x1) ^ x2 ^ x3 ^ w[w_idx] + temp[temp_idx + 1] = x0 ^ aes_gf8_mul_2(x1) ^ aes_gf8_mul_3(x2) ^ x3 ^ w[w_idx + 1] + temp[temp_idx + 2] = x0 ^ x1 ^ aes_gf8_mul_2(x2) ^ aes_gf8_mul_3(x3) ^ w[w_idx + 2] + temp[temp_idx + 3] = aes_gf8_mul_3(x0) ^ x1 ^ x2 ^ aes_gf8_mul_2(x3) ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# combined sub_bytes, shift_rows, add_round_key +# all inputs must be size 16 +def aes_sb_sr_ark(state, w, w_idx, temp): + temp_idx = 0 + for i in range(4): + x0 = aes_s_box_table[state[i * 4]] + x1 = aes_s_box_table[state[1 + ((i + 1) & 3) * 4]] + x2 = aes_s_box_table[state[2 + ((i + 2) & 3) * 4]] + x3 = aes_s_box_table[state[3 + ((i + 3) & 3) * 4]] + temp[temp_idx] = x0 ^ w[w_idx] + temp[temp_idx + 1] = x1 ^ w[w_idx + 1] + temp[temp_idx + 2] = x2 ^ w[w_idx + 2] + temp[temp_idx + 3] = x3 ^ w[w_idx + 3] + w_idx += 4 + temp_idx += 4 + for i in range(16): + state[i] = temp[i] + +# take state as input and change it to the next state in the sequence +# state and temp have size 16, w has size 16 * (Nr + 1), Nr >= 1 +def aes_state(state, w, temp, nr): + aes_add_round_key(state, w) + w_idx = 16 + for i in range(nr - 1): + aes_sb_sr_mc_ark(state, w, w_idx, temp) + w_idx += 16 + aes_sb_sr_ark(state, w, w_idx, temp) + +# expand 'key' to 'w' for use with aes_state +# key has size 4 * Nk, w has size 16 * (Nr + 1), temp has size 16 +def aes_key_expansion(key, w, temp, nk, nr): + for i in range(4 * nk): + w[i] = key[i] + w_idx = 4 * nk - 4 + for i in range(nk, 4 * (nr + 1)): + t = temp + t_idx = 0 + if i % nk == 0: + t[0] = aes_s_box(w[w_idx + 1]) ^ aes_r_con(i // nk) + for j in range(1, 4): + t[j] = aes_s_box(w[w_idx + (j + 1) % 4]) + elif nk > 6 and i % nk == 4: + for j in range(0, 4): + t[j] = aes_s_box(w[w_idx + j]) + else: + t = w + t_idx = w_idx + w_idx += 4 + for j in range(4): + w[w_idx + j] = w[w_idx + j - 4 * nk] ^ t[t_idx + j] + +################################################################## +# simple use of AES algorithm, using output feedback (OFB) mode + +class AES: + def __init__(self, keysize): + if keysize == 128: + self.nk = 4 + self.nr = 10 + elif keysize == 192: + self.nk = 6 + self.nr = 12 + else: + assert keysize == 256 + self.nk = 8 + self.nr = 14 + + self.state = bytearray(16) + self.w = bytearray(16 * (self.nr + 1)) + self.temp = bytearray(16) + self.state_pos = 16 + + def set_key(self, key): + aes_key_expansion(key, self.w, self.temp, self.nk, self.nr) + self.state_pos = 16 + + def set_iv(self, iv): + for i in range(16): + self.state[i] = iv[i] + self.state_pos = 16; + + def get_some_state(self, n_needed): + if self.state_pos >= 16: + aes_state(self.state, self.w, self.temp, self.nr) + self.state_pos = 0 + n = 16 - self.state_pos + if n > n_needed: + n = n_needed + return n + + def apply_to(self, data): + idx = 0 + n = len(data) + while n > 0: + ln = self.get_some_state(n) + n -= ln + for i in range(ln): + data[idx + i] ^= self.state[self.state_pos + i] + idx += ln + self.state_pos += n + +################################################################## +# test code + +try: + import utime as time +except ImportError: + import time +import _thread + +class LockedCounter: + def __init__(self): + self.lock = _thread.allocate_lock() + self.value = 0 + + def add(self, val): + self.lock.acquire() + self.value += val + self.lock.release() + +count = LockedCounter() + +def thread_entry(): + global count + + aes = AES(256) + key = bytearray(256 // 8) + iv = bytearray(16) + data = bytearray(128) + # from now on we don't use the heap + + for loop in range(5): + # encrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(8): + aes.apply_to(data) + + # decrypt + aes.set_key(key) + aes.set_iv(iv) + for i in range(8): + aes.apply_to(data) + + # verify + for i in range(len(data)): + assert data[i] == 0 + + count.add(1) + +if __name__ == '__main__': + n_thread = 20 + for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + while count.value < n_thread: + time.sleep(1) diff --git a/src/openmv/src/micropython/tests/thread/stress_create.py b/src/openmv/src/micropython/tests/thread/stress_create.py new file mode 100755 index 0000000..2399746 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/stress_create.py @@ -0,0 +1,22 @@ +# stress test for creating many threads + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(n): + pass + +thread_num = 0 +while thread_num < 500: + try: + _thread.start_new_thread(thread_entry, (thread_num,)) + thread_num += 1 + except MemoryError: + pass + +# wait for the last threads to terminate +time.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/stress_heap.py b/src/openmv/src/micropython/tests/thread/stress_heap.py new file mode 100755 index 0000000..5482a9a --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/stress_heap.py @@ -0,0 +1,46 @@ +# stress test for the heap by allocating lots of objects within threads +# allocates about 5mb on the heap +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def last(l): + return l[-1] + +def thread_entry(n): + # allocate a bytearray and fill it + data = bytearray(i for i in range(256)) + + # run a loop which allocates a small list and uses it each iteration + lst = 8 * [0] + sum = 0 + for i in range(n): + sum += last(lst) + lst = [0, 0, 0, 0, 0, 0, 0, i + 1] + + # check that the bytearray still has the right data + for i, b in enumerate(data): + assert i == b + + # print the result of the loop and indicate we are finished + with lock: + print(sum, lst[-1]) + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 10 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10000,)) + +# wait for threads to finish +while n_finished < n_thread: + time.sleep(1) diff --git a/src/openmv/src/micropython/tests/thread/stress_recurse.py b/src/openmv/src/micropython/tests/thread/stress_recurse.py new file mode 100755 index 0000000..68367c4 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/stress_recurse.py @@ -0,0 +1,25 @@ +# test hitting the function recursion limit within a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(): + foo() + +def thread_entry(): + try: + foo() + except RuntimeError: + print('RuntimeError') + global finished + finished = True + +finished = False + +_thread.start_new_thread(thread_entry, ()) + +# busy wait for thread to finish +while not finished: + pass +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_exc1.py b/src/openmv/src/micropython/tests/thread/thread_exc1.py new file mode 100755 index 0000000..10fb94b --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_exc1.py @@ -0,0 +1,30 @@ +# test raising and catching an exception within a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(): + raise ValueError + +def thread_entry(): + try: + foo() + except ValueError: + pass + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_exc2.py b/src/openmv/src/micropython/tests/thread/thread_exc2.py new file mode 100755 index 0000000..35cb324 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_exc2.py @@ -0,0 +1,10 @@ +# test raising exception within thread which is not caught +import utime +import _thread + +def thread_entry(): + raise ValueError + +_thread.start_new_thread(thread_entry, ()) +utime.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_exc2.py.exp b/src/openmv/src/micropython/tests/thread/thread_exc2.py.exp new file mode 100755 index 0000000..cc7a20a --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_exc2.py.exp @@ -0,0 +1,5 @@ +Unhandled exception in thread started by +Traceback (most recent call last): + File \.\+, line 6, in thread_entry +ValueError: +done diff --git a/src/openmv/src/micropython/tests/thread/thread_exit1.py b/src/openmv/src/micropython/tests/thread/thread_exit1.py new file mode 100755 index 0000000..88cdd16 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_exit1.py @@ -0,0 +1,19 @@ +# test _thread.exit() function +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(): + _thread.exit() + +_thread.start_new_thread(thread_entry, ()) +_thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_exit2.py b/src/openmv/src/micropython/tests/thread/thread_exit2.py new file mode 100755 index 0000000..368a11b --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_exit2.py @@ -0,0 +1,19 @@ +# test raising SystemExit to finish a thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(): + raise SystemExit + +_thread.start_new_thread(thread_entry, ()) +_thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_gc1.py b/src/openmv/src/micropython/tests/thread/thread_gc1.py new file mode 100755 index 0000000..8dcbf7e --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_gc1.py @@ -0,0 +1,34 @@ +# test that we can run the garbage collector within threads +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import gc +import _thread + +def thread_entry(n): + # allocate a bytearray and fill it + data = bytearray(i for i in range(256)) + + # do some work and call gc.collect() a few times + for i in range(n): + for i in range(len(data)): + data[i] = data[i] + gc.collect() + + # print whether the data remains intact and indicate we are finished + with lock: + print(list(data) == list(range(256))) + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10,)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass diff --git a/src/openmv/src/micropython/tests/thread/thread_ident1.py b/src/openmv/src/micropython/tests/thread/thread_ident1.py new file mode 100755 index 0000000..217fce7 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_ident1.py @@ -0,0 +1,21 @@ +# test _thread.get_ident() function +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def thread_entry(): + tid = _thread.get_ident() + print('thread', type(tid) == int, tid != 0, tid != tid_main) + global finished + finished = True + +tid_main = _thread.get_ident() +print('main', type(tid_main) == int, tid_main != 0) + +finished = False +_thread.start_new_thread(thread_entry, ()) + +while not finished: + pass +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_lock1.py b/src/openmv/src/micropython/tests/thread/thread_lock1.py new file mode 100755 index 0000000..ba5c7df --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_lock1.py @@ -0,0 +1,46 @@ +# test _thread lock object using a single thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +# create lock +lock = _thread.allocate_lock() + +print(type(lock) == _thread.LockType) + +# should be unlocked +print(lock.locked()) + +# basic acquire and release +print(lock.acquire()) +print(lock.locked()) +lock.release() +print(lock.locked()) + +# try acquire twice (second should fail) +print(lock.acquire()) +print(lock.locked()) +print(lock.acquire(0)) +print(lock.locked()) +lock.release() +print(lock.locked()) + +# test with capabilities of lock +with lock: + print(lock.locked()) + +# test that lock is unlocked if an error is rasied +try: + with lock: + print(lock.locked()) + raise KeyError +except KeyError: + print('KeyError') + print(lock.locked()) + +# test that we can't release an unlocked lock +try: + lock.release() +except RuntimeError: + print('RuntimeError') diff --git a/src/openmv/src/micropython/tests/thread/thread_lock2.py b/src/openmv/src/micropython/tests/thread/thread_lock2.py new file mode 100755 index 0000000..405f10b --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_lock2.py @@ -0,0 +1,24 @@ +# test _thread lock objects with multiple threads +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +lock = _thread.allocate_lock() + +def thread_entry(): + lock.acquire() + print('have it') + lock.release() + +# spawn the threads +for i in range(4): + _thread.start_new_thread(thread_entry, ()) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_lock3.py b/src/openmv/src/micropython/tests/thread/thread_lock3.py new file mode 100755 index 0000000..607898d --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_lock3.py @@ -0,0 +1,27 @@ +# test thread coordination using a lock object +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +lock = _thread.allocate_lock() +n_thread = 10 +n_finished = 0 + +def thread_entry(idx): + global n_finished + while True: + with lock: + if n_finished == idx: + break + print('my turn:', idx) + with lock: + n_finished += 1 + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (i,)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass diff --git a/src/openmv/src/micropython/tests/thread/thread_lock4.py b/src/openmv/src/micropython/tests/thread/thread_lock4.py new file mode 100755 index 0000000..2f9d42d --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_lock4.py @@ -0,0 +1,51 @@ +# test using lock to coordinate access to global mutable objects +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def fac(n): + x = 1 + for i in range(1, n + 1): + x *= i + return x + +def thread_entry(): + while True: + with jobs_lock: + try: + f, arg = jobs.pop(0) + except IndexError: + return + ans = f(arg) + with output_lock: + output.append((arg, ans)) + +# create a list of jobs +jobs = [(fac, i) for i in range(20, 80)] +jobs_lock = _thread.allocate_lock() +n_jobs = len(jobs) + +# create a list to store the results +output = [] +output_lock = _thread.allocate_lock() + +# spawn threads to do the jobs +for i in range(4): + _thread.start_new_thread(thread_entry, ()) + +# wait for the jobs to complete +while True: + with jobs_lock: + if len(output) == n_jobs: + break + time.sleep(1) + +# sort and print the results +output.sort(key=lambda x: x[0]) +for arg, ans in output: + print(arg, ans) diff --git a/src/openmv/src/micropython/tests/thread/thread_qstr1.py b/src/openmv/src/micropython/tests/thread/thread_qstr1.py new file mode 100755 index 0000000..f4136d9 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_qstr1.py @@ -0,0 +1,39 @@ +# test concurrent interning of strings +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +# function to check the interned string +def check(s, val): + assert type(s) == str + assert int(s) == val + +# main thread function +def th(base, n): + for i in range(n): + # this will intern the string and check it + exec("check('%u', %u)" % (base + i, base + i)) + + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 +n_qstr_per_thread = 100 # make 1000 for a more stressful test (uses more heap) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(th, (i * n_qstr_per_thread, n_qstr_per_thread)) + +# wait for threads to finish +while n_finished < n_thread: + time.sleep(1) + +print('pass') diff --git a/src/openmv/src/micropython/tests/thread/thread_shared1.py b/src/openmv/src/micropython/tests/thread/thread_shared1.py new file mode 100755 index 0000000..13c6651 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_shared1.py @@ -0,0 +1,31 @@ +# test capability for threads to access a shared immutable data structure +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(i): + pass + +def thread_entry(n, tup): + for i in tup: + foo(i) + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# the shared data structure +tup = (1, 2, 3, 4) + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (100, tup)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print(tup) diff --git a/src/openmv/src/micropython/tests/thread/thread_shared2.py b/src/openmv/src/micropython/tests/thread/thread_shared2.py new file mode 100755 index 0000000..e4bfe78 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_shared2.py @@ -0,0 +1,32 @@ +# test capability for threads to access a shared mutable data structure +# (without contention because they access different parts of the structure) +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import _thread + +def foo(lst, i): + lst[i] += 1 + +def thread_entry(n, lst, idx): + for i in range(n): + foo(lst, idx) + with lock: + global n_finished + n_finished += 1 + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# the shared data structure +lst = [0, 0] + +# spawn threads +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ((i + 1) * 10, lst, i)) + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print(lst) diff --git a/src/openmv/src/micropython/tests/thread/thread_sleep1.py b/src/openmv/src/micropython/tests/thread/thread_sleep1.py new file mode 100755 index 0000000..032ec17 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_sleep1.py @@ -0,0 +1,31 @@ +# test threads sleeping +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime + sleep_ms = utime.sleep_ms +except ImportError: + import time + sleep_ms = lambda t: time.sleep(t / 1000) + +import _thread + +lock = _thread.allocate_lock() +n_thread = 4 +n_finished = 0 + +def thread_entry(t): + global n_finished + sleep_ms(t) + sleep_ms(2 * t) + with lock: + n_finished += 1 + +for i in range(n_thread): + _thread.start_new_thread(thread_entry, (10 * i,)) + +# wait for threads to finish +while n_finished < n_thread: + sleep_ms(100) +print('done', n_thread) diff --git a/src/openmv/src/micropython/tests/thread/thread_stacksize1.py b/src/openmv/src/micropython/tests/thread/thread_stacksize1.py new file mode 100755 index 0000000..62b6e5e --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_stacksize1.py @@ -0,0 +1,47 @@ +# test setting the thread stack size +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +import sys +import _thread + +# different implementations have different minimum sizes +if sys.implementation.name == 'micropython': + sz = 2 * 1024 +else: + sz = 32 * 1024 + +def foo(): + pass + +def thread_entry(): + foo() + with lock: + global n_finished + n_finished += 1 + +# reset stack size to default +_thread.stack_size() + +# test set/get of stack size +print(_thread.stack_size()) +print(_thread.stack_size(sz)) +print(_thread.stack_size() == sz) +print(_thread.stack_size()) + +lock = _thread.allocate_lock() +n_thread = 2 +n_finished = 0 + +# set stack size and spawn a few threads +_thread.stack_size(sz) +for i in range(n_thread): + _thread.start_new_thread(thread_entry, ()) + +# reset stack size to default (for subsequent scripts on baremetal) +_thread.stack_size() + +# busy wait for threads to finish +while n_finished < n_thread: + pass +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_start1.py b/src/openmv/src/micropython/tests/thread/thread_start1.py new file mode 100755 index 0000000..d23a74a --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_start1.py @@ -0,0 +1,23 @@ +# test basic capability to start a new thread +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def foo(): + pass + +def thread_entry(n): + for i in range(n): + foo() + +_thread.start_new_thread(thread_entry, (10,)) +_thread.start_new_thread(thread_entry, (20,)) + +# wait for threads to finish +time.sleep(1) +print('done') diff --git a/src/openmv/src/micropython/tests/thread/thread_start2.py b/src/openmv/src/micropython/tests/thread/thread_start2.py new file mode 100755 index 0000000..d0913e3 --- /dev/null +++ b/src/openmv/src/micropython/tests/thread/thread_start2.py @@ -0,0 +1,26 @@ +# test capability to start a thread with keyword args +# +# MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + +try: + import utime as time +except ImportError: + import time +import _thread + +def thread_entry(a0, a1, a2, a3): + print('thread', a0, a1, a2, a3) + +# spawn thread using kw args +_thread.start_new_thread(thread_entry, (10, 20), {'a2': 0, 'a3': 1}) + +# wait for thread to finish +time.sleep(1) + +# incorrect argument where dictionary is needed for keyword args +try: + _thread.start_new_thread(thread_entry, (), ()) +except TypeError: + print('TypeError') + +print('done') diff --git a/src/openmv/src/micropython/tests/unicode/data/utf-8_1.txt b/src/openmv/src/micropython/tests/unicode/data/utf-8_1.txt new file mode 100755 index 0000000..d84c480 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/data/utf-8_1.txt @@ -0,0 +1 @@ +Привет diff --git a/src/openmv/src/micropython/tests/unicode/data/utf-8_2.txt b/src/openmv/src/micropython/tests/unicode/data/utf-8_2.txt new file mode 100755 index 0000000..6f14297 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/data/utf-8_2.txt @@ -0,0 +1,2 @@ +aαbβcγdδ +ã🙠diff --git a/src/openmv/src/micropython/tests/unicode/file1.py b/src/openmv/src/micropython/tests/unicode/file1.py new file mode 100755 index 0000000..08b7d25 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/file1.py @@ -0,0 +1,4 @@ +f = open("unicode/data/utf-8_1.txt", encoding="utf-8") +l = f.readline() +print(l) +print(len(l)) diff --git a/src/openmv/src/micropython/tests/unicode/file2.py b/src/openmv/src/micropython/tests/unicode/file2.py new file mode 100755 index 0000000..8c45f91 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/file2.py @@ -0,0 +1,26 @@ +# test reading a given number of characters + +def do(mode): + if mode == 'rb': + enc = None + else: + enc = 'utf-8' + f = open('unicode/data/utf-8_2.txt', mode=mode, encoding=enc) + print(f.read(1)) + print(f.read(1)) + print(f.read(2)) + print(f.read(4)) + + # skip to end of line + f.readline() + + # check 3-byte utf-8 char + print(f.read(1 if mode == 'rt' else 3)) + + # check 4-byte utf-8 char + print(f.read(1 if mode == 'rt' else 4)) + + f.close() + +do('rb') +do('rt') diff --git a/src/openmv/src/micropython/tests/unicode/unicode.py b/src/openmv/src/micropython/tests/unicode/unicode.py new file mode 100755 index 0000000..3a35ce8 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode.py @@ -0,0 +1,49 @@ +# Test a UTF-8 encoded literal +s = "asdf©qwer" +for i in range(len(s)): + print("s[%d]: %s %X"%(i, s[i], ord(s[i]))) + +# Test all three forms of Unicode escape, and +# all blocks of UTF-8 byte patterns +s = "a\xA9\xFF\u0123\u0800\uFFEE\U0001F44C" +for i in range(-len(s), len(s)): + print("s[%d]: %s %X"%(i, s[i], ord(s[i]))) + print("s[:%d]: %d chars, '%s'"%(i, len(s[:i]), s[:i])) + for j in range(i, len(s)): + print("s[%d:%d]: %d chars, '%s'"%(i, j, len(s[i:j]), s[i:j])) + print("s[%d:]: %d chars, '%s'"%(i, len(s[i:]), s[i:])) + +# Test UTF-8 encode and decode +enc = s.encode() +print(enc, enc.decode() == s) + +# printing of unicode chars using repr +# NOTE: for some characters (eg \u10ff) we differ to CPython +print(repr('a\uffff')) +print(repr('a\U0001ffff')) + +# test invalid escape code +try: + eval('"\\U00110000"') +except SyntaxError: + print('SyntaxError') + +# test unicode string given to int +try: + int('\u0200') +except ValueError: + print('ValueError') + +# test invalid UTF-8 string +try: + str(b'ab\xa1', 'utf8') +except UnicodeError: + print('UnicodeError') +try: + str(b'ab\xf8', 'utf8') +except UnicodeError: + print('UnicodeError') +try: + str(bytearray(b'ab\xc0a'), 'utf8') +except UnicodeError: + print('UnicodeError') diff --git a/src/openmv/src/micropython/tests/unicode/unicode_chr.py b/src/openmv/src/micropython/tests/unicode/unicode_chr.py new file mode 100755 index 0000000..248eb58 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_chr.py @@ -0,0 +1,5 @@ +# test builtin chr with unicode characters + +print(chr(945)) +print(chr(0x800)) +print(chr(0x10000)) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_id.py b/src/openmv/src/micropython/tests/unicode/unicode_id.py new file mode 100755 index 0000000..10f540c --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_id.py @@ -0,0 +1,27 @@ +# test unicode in identifiers + +# comment +# αβγδϵφζ + +# global identifiers +α = 1 +αβγ = 2 +bβ = 3 +βb = 4 +print(α, αβγ, bβ, βb) + +# function, argument, local identifiers +def α(β, γ): + δ = β + γ + print(β, γ, δ) +α(1, 2) + +# class, method identifiers +class φ: + def __init__(self): + pass + def δ(self, ϵ): + print(ϵ) +zζzζz = φ() +if hasattr(zζzζz, "δ"): + zζzζz.δ(ϵ=123) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_index.py b/src/openmv/src/micropython/tests/unicode/unicode_index.py new file mode 100755 index 0000000..3c31468 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_index.py @@ -0,0 +1,6 @@ +print("Привет".find("Ñ‚")) +print("Привет".find("П")) +print("Привет".rfind("Ñ‚")) +print("Привет".rfind("П")) +print("Привет".index("Ñ‚")) +print("Привет".index("П")) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_iter.py b/src/openmv/src/micropython/tests/unicode/unicode_iter.py new file mode 100755 index 0000000..f08a4ac --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_iter.py @@ -0,0 +1,4 @@ +for c in "Hello": + print(c) +for c in "Привет": + print(c) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_ord.py b/src/openmv/src/micropython/tests/unicode/unicode_ord.py new file mode 100755 index 0000000..47cfa1c --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_ord.py @@ -0,0 +1,3 @@ +# test builtin ord with unicode characters + +print(ord('α')) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_pos.py b/src/openmv/src/micropython/tests/unicode/unicode_pos.py new file mode 100755 index 0000000..6a59829 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_pos.py @@ -0,0 +1,5 @@ +# str methods with explicit start/end pos +print("Привет".startswith("П")) +print("Привет".startswith("Ñ€", 1)) +print("абвба".find("а", 1)) +print("абвба".find("а", 1, -1)) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_str_format.py b/src/openmv/src/micropython/tests/unicode/unicode_str_format.py new file mode 100755 index 0000000..bf8505a --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_str_format.py @@ -0,0 +1,4 @@ +# test handling of unicode chars in format strings + +print('α'.format()) +print('{α}'.format(α=1)) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_str_modulo.py b/src/openmv/src/micropython/tests/unicode/unicode_str_modulo.py new file mode 100755 index 0000000..e9b1524 --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_str_modulo.py @@ -0,0 +1,3 @@ +# test handling of unicode chars in string % formatting + +print('α' % ()) diff --git a/src/openmv/src/micropython/tests/unicode/unicode_subscr.py b/src/openmv/src/micropython/tests/unicode/unicode_subscr.py new file mode 100755 index 0000000..a2f434d --- /dev/null +++ b/src/openmv/src/micropython/tests/unicode/unicode_subscr.py @@ -0,0 +1,23 @@ +a = '¢пр' + +print(a[0], a[0:1]) +print(a[1], a[1:2]) +print(a[2], a[2:3]) +try: + print(a[3]) +except IndexError: + print("IndexError") +print(a[3:4]) + +print(a[-1]) +print(a[-2], a[-2:-1]) +print(a[-3], a[-3:-2]) +try: + print(a[-4]) +except IndexError: + print("IndexError") +print(a[-4:-3]) + +print(a[0:2]) +print(a[1:3]) +print(a[2:4]) diff --git a/src/openmv/src/micropython/tests/unix/extra_coverage.py b/src/openmv/src/micropython/tests/unix/extra_coverage.py new file mode 100755 index 0000000..13721f1 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/extra_coverage.py @@ -0,0 +1,74 @@ +try: + extra_coverage +except NameError: + print("SKIP") + raise SystemExit + +import uerrno +import uio + +data = extra_coverage() + +# test hashing of str/bytes that have an invalid hash +print(data[0], data[1]) +print(hash(data[0])) +print(hash(data[1])) +print(hash(bytes(data[0], 'utf8'))) +print(hash(str(data[1], 'utf8'))) + +# test streams +stream = data[2] # has set_error and set_buf. Write always returns error +stream.set_error(uerrno.EAGAIN) # non-blocking error +print(stream.read()) # read all encounters non-blocking error +print(stream.read(1)) # read 1 byte encounters non-blocking error +print(stream.readline()) # readline encounters non-blocking error +print(stream.readinto(bytearray(10))) # readinto encounters non-blocking error +print(stream.write(b'1')) # write encounters non-blocking error +print(stream.write1(b'1')) # write1 encounters non-blocking error +stream.set_buf(b'123') +print(stream.read(4)) # read encounters non-blocking error after successful reads +stream.set_buf(b'123') +print(stream.read1(4)) # read1 encounters non-blocking error after successful reads +stream.set_buf(b'123') +print(stream.readline(4)) # readline encounters non-blocking error after successful reads +try: + print(stream.ioctl(0, 0)) # ioctl encounters non-blocking error; raises OSError +except OSError: + print('OSError') +stream.set_error(0) +print(stream.ioctl(0, bytearray(10))) # successful ioctl call + +stream2 = data[3] # is textio +print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream + +# test BufferedWriter with stream errors +stream.set_error(uerrno.EAGAIN) +buf = uio.BufferedWriter(stream, 8) +print(buf.write(bytearray(16))) + +# test basic import of frozen scripts +import frzstr1 +import frzmpy1 + +# test import of frozen packages with __init__.py +import frzstr_pkg1 +print(frzstr_pkg1.x) +import frzmpy_pkg1 +print(frzmpy_pkg1.x) + +# test import of frozen packages without __init__.py +from frzstr_pkg2.mod import Foo +print(Foo.x) +from frzmpy_pkg2.mod import Foo +print(Foo.x) + +# test raising exception in frozen script +try: + import frzmpy2 +except ZeroDivisionError: + print('ZeroDivisionError') + +# test loading a resource from a frozen string +import uio +buf = uio.resource_stream('frzstr_pkg2', 'mod.py') +print(buf.read(21)) diff --git a/src/openmv/src/micropython/tests/unix/extra_coverage.py.exp b/src/openmv/src/micropython/tests/unix/extra_coverage.py.exp new file mode 100755 index 0000000..9df8527 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/extra_coverage.py.exp @@ -0,0 +1,106 @@ +# mp_printf +-123 +123 123 +-0123 +123 +123 +1ABCDEF +ab abc + +false true +(null) +-2147483648 +2147483648 +80000000 +80000000 +abc +# GC +0 +0 +# vstr +tests +sts + +test +tes +RuntimeError: +RuntimeError: +# repl +ame__ + +__class__ __name__ argv byteorder +exc_info exit getsizeof implementation +maxsize modules path platform +print_exception stderr stdin +stdout version version_info +ementation +# attrtuple +(start=1, stop=2, step=3) +# str +1 +# bytearray +data +# mpz +1 +12345678 +0 +0 +0 +0 +0 +1 +12345 +6 +# runtime utils +TypeError: unsupported type for __abs__: 'str' +TypeError: unsupported types for __divmod__: 'str', 'str' +Warning: test +# format float +? ++1e+00 ++1e+00 +# binary +123 +456 +# VM +2 1 +# scheduler +sched(0)=1 +sched(1)=1 +sched(2)=1 +sched(3)=1 +sched(4)=0 +unlocked +3 +2 +1 +0 +0123456789 b'0123456789' +7300 +7300 +7300 +7300 +None +None +None +None +None +None +b'123' +b'123' +b'123' +OSError +0 +None +None +frzstr1 +frzmpy1 +frzstr_pkg1.__init__ +1 +frzmpy_pkg1.__init__ +1 +frzstr_pkg2.mod +1 +frzmpy_pkg2.mod +1 +ZeroDivisionError +b'# test frozen package' diff --git a/src/openmv/src/micropython/tests/unix/ffi_callback.py b/src/openmv/src/micropython/tests/unix/ffi_callback.py new file mode 100755 index 0000000..23b058b --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_callback.py @@ -0,0 +1,33 @@ +try: + import ffi +except ImportError: + print("SKIP") + raise SystemExit + + +def ffi_open(names): + err = None + for n in names: + try: + mod = ffi.open(n) + return mod + except OSError as e: + err = e + raise err + +libc = ffi_open(('libc.so', 'libc.so.0', 'libc.so.6', 'libc.dylib')) + +qsort = libc.func("v", "qsort", "piip") + +def cmp(pa, pb): + a = ffi.as_bytearray(pa, 1) + b = ffi.as_bytearray(pb, 1) + #print("cmp:", a, b) + return a[0] - b[0] + +cmp_c = ffi.callback("i", cmp, "pp") + +s = bytearray(b"foobar") +print("org string:", s) +qsort(s, len(s), 1, cmp_c) +print("qsort'ed:", s) diff --git a/src/openmv/src/micropython/tests/unix/ffi_callback.py.exp b/src/openmv/src/micropython/tests/unix/ffi_callback.py.exp new file mode 100755 index 0000000..d06fec5 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_callback.py.exp @@ -0,0 +1,2 @@ +org string: bytearray(b'foobar') +qsort'ed: bytearray(b'abfoor') diff --git a/src/openmv/src/micropython/tests/unix/ffi_float.py b/src/openmv/src/micropython/tests/unix/ffi_float.py new file mode 100755 index 0000000..3174368 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_float.py @@ -0,0 +1,39 @@ +# test ffi float support +try: + import ffi +except ImportError: + print("SKIP") + raise SystemExit + + +def ffi_open(names): + err = None + for n in names: + try: + mod = ffi.open(n) + return mod + except OSError as e: + err = e + raise err + +libc = ffi_open(('libc.so', 'libc.so.0', 'libc.so.6', 'libc.dylib')) + +try: + strtof = libc.func("f", "strtof", "sp") +except OSError: + # Some libc's (e.g. Android's Bionic) define strtof as macro/inline func + # in terms of strtod(). + print("SKIP") + raise SystemExit + +print('%.6f' % strtof('1.23', None)) + +strtod = libc.func("d", "strtod", "sp") +print('%.6f' % strtod('1.23', None)) + +# test passing double and float args +libm = ffi_open(('libm.so', 'libm.so.6', 'libc.so.0', 'libc.so.6', 'libc.dylib')) +tgamma = libm.func('d', 'tgamma', 'd') +for fun in (tgamma,): + for val in (0.5, 1, 1.0, 1.5, 4, 4.0): + print('%.6f' % fun(val)) diff --git a/src/openmv/src/micropython/tests/unix/ffi_float.py.exp b/src/openmv/src/micropython/tests/unix/ffi_float.py.exp new file mode 100755 index 0000000..b9d7da2 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_float.py.exp @@ -0,0 +1,8 @@ +1.230000 +1.230000 +1.772454 +1.000000 +1.000000 +0.886227 +6.000000 +6.000000 diff --git a/src/openmv/src/micropython/tests/unix/ffi_float2.py b/src/openmv/src/micropython/tests/unix/ffi_float2.py new file mode 100755 index 0000000..721eb4d --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_float2.py @@ -0,0 +1,31 @@ +# test ffi float support +try: + import ffi +except ImportError: + print("SKIP") + raise SystemExit + + +def ffi_open(names): + err = None + for n in names: + try: + mod = ffi.open(n) + return mod + except OSError as e: + err = e + raise err + +libm = ffi_open(('libm.so', 'libm.so.6', 'libc.so.0', 'libc.so.6', 'libc.dylib')) + +# Some libc's implement tgammaf as header macro with tgamma(), so don't assume +# it'll be in library. +try: + tgammaf = libm.func('f', 'tgammaf', 'f') +except OSError: + print("SKIP") + raise SystemExit + +for fun in (tgammaf,): + for val in (0.5, 1, 1.0, 1.5, 4, 4.0): + print('%.6f' % fun(val)) diff --git a/src/openmv/src/micropython/tests/unix/ffi_float2.py.exp b/src/openmv/src/micropython/tests/unix/ffi_float2.py.exp new file mode 100755 index 0000000..58fc6a0 --- /dev/null +++ b/src/openmv/src/micropython/tests/unix/ffi_float2.py.exp @@ -0,0 +1,6 @@ +1.772454 +1.000000 +1.000000 +0.886227 +6.000000 +6.000000 diff --git a/src/openmv/src/micropython/tests/wipy/adc.py b/src/openmv/src/micropython/tests/wipy/adc.py new file mode 100755 index 0000000..6fd4373 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/adc.py @@ -0,0 +1,115 @@ +''' +ADC test for the CC3200 based boards. +''' + +from machine import ADC +import os + +mch = os.uname().machine +if 'LaunchPad' in mch: + adc_pin = 'GP5' + adc_channel = 3 +elif 'WiPy' in mch: + adc_pin = 'GP3' + adc_channel = 1 +else: + raise Exception('Board not supported!') + +adc = ADC(0) +print(adc) +adc = ADC() +print(adc) +adc = ADC(0, bits=12) +print(adc) + +apin = adc.channel(adc_channel) +print(apin) +apin = adc.channel(id=adc_channel) +print(apin) +apin = adc.channel(adc_channel, pin=adc_pin) +print(apin) +apin = adc.channel(id=adc_channel, pin=adc_pin) +print(apin) + +print(apin.value() > 3000) +print(apin() > 3000) + +# de-init must work +apin.deinit() +print(apin) + +adc.deinit() +print(adc) +print(apin) +adc.init() +print(adc) +print(apin) +apin.init() +print(apin) +print(apin() > 3000) + +# check for memory leaks... +for i in range (0, 1000): + adc = ADC() + apin = adc.channel(adc_channel) + +# next ones should raise +try: + adc = ADC(bits=17) +except: + print('Exception') + +try: + adc = ADC(id=1) +except: + print('Exception') + +try: + adc = ADC(0, 16) +except: + print('Exception') + +adc = ADC() +try: + apin = adc.channel(4) +except: + print('Exception') + +try: + apin = adc.channel(-1) +except: + print('Exception') + +try: + apin = adc.channel(0, pin='GP3') +except: + print('Exception') + +apin = adc.channel(1) +apin.deinit() +try: + apin() +except: + print('Exception') + +try: + apin.value() +except: + print('Exception') + +adc.deinit() +try: + apin.value() +except: + print('Exception') + +try: + apin = adc.channel(1) +except: + print('Exception') + +# re-init must work +adc.init() +apin.init() +print(apin) +print(apin() > 3000) diff --git a/src/openmv/src/micropython/tests/wipy/adc.py.exp b/src/openmv/src/micropython/tests/wipy/adc.py.exp new file mode 100755 index 0000000..a65cf49 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/adc.py.exp @@ -0,0 +1,28 @@ +ADC(0, bits=12) +ADC(0, bits=12) +ADC(0, bits=12) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +True +True +ADCChannel(1) +ADC(0) +ADCChannel(1) +ADC(0, bits=12) +ADCChannel(1) +ADCChannel(1, pin=GP3) +True +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +ADCChannel(1, pin=GP3) +True diff --git a/src/openmv/src/micropython/tests/wipy/i2c.py b/src/openmv/src/micropython/tests/wipy/i2c.py new file mode 100755 index 0000000..6931554 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/i2c.py @@ -0,0 +1,176 @@ +''' +I2C test for the CC3200 based boards. +A MPU-9150 sensor must be connected to the I2C bus. +''' + +from machine import I2C +import os +import time + +mch = os.uname().machine +if 'LaunchPad' in mch: + i2c_pins = ('GP11', 'GP10') +elif 'WiPy' in mch: + i2c_pins = ('GP15', 'GP10') +else: + raise Exception('Board not supported!') + +i2c = I2C(0, I2C.MASTER, baudrate=400000) +# try initing without the peripheral id +i2c = I2C() +print(i2c) +i2c = I2C(mode=I2C.MASTER, baudrate=50000, pins=i2c_pins) +print(i2c) + +i2c = I2C(0, I2C.MASTER, baudrate=100000) +print(i2c) +i2c = I2C(0, mode=I2C.MASTER, baudrate=400000) +print(i2c) +i2c = I2C(0, mode=I2C.MASTER, baudrate=400000, pins=i2c_pins) +print(i2c) + +addr = i2c.scan()[0] +print(addr) + +reg = bytearray(1) +reg2 = bytearray(2) +reg2_r = bytearray(2) + +# reset the sensor +reg[0] |= 0x80 +print(1 == i2c.writeto_mem(addr, 107, reg)) +time.sleep_ms(100) # wait for the sensor to reset... + +print(1 == i2c.readfrom_mem_into(addr, 107, reg)) # read the power management register 1 +print(0x40 == reg[0]) + +# now just read one byte +data = i2c.readfrom_mem(addr, 117, 1) # read the "who am I?" register +print(0x68 == data[0]) +print(len(data) == 1) +print(1 == i2c.readfrom_mem_into(addr, 117, reg)) # read the "who am I?" register again +print(0x68 == reg[0]) + +# now try reading two bytes +data = i2c.readfrom_mem(addr, 116, 2) # read the "who am I?" register +print(0x68 == data[1]) +print(data == b'\x00\x68') +print(len(data) == 2) +print(2 == i2c.readfrom_mem_into(addr, 116, reg2)) # read the "who am I?" register again +print(0x68 == reg2[1]) +print(reg2 == b'\x00\x68') + +print(1 == i2c.readfrom_mem_into(addr, 107, reg)) # read the power management register 1 +print(0x40 == reg[0]) +# clear the sleep bit +reg[0] = 0 +print(1 == i2c.writeto_mem(addr, 107, reg)) +# read it back +i2c.readfrom_mem_into(addr, 107, reg) +print(0 == reg[0]) + +# set the sleep bit +reg[0] = 0x40 +print(1 == i2c.writeto_mem(addr, 107, reg)) +# read it back +i2c.readfrom_mem_into(addr, 107, reg) +print(0x40 == reg[0]) + +# reset the sensor +reg[0] |= 0x80 +print(1 == i2c.writeto_mem(addr, 107, reg)) +time.sleep_ms(100) # wait for the sensor to reset... + +# now read and write two register at a time +print(2 == i2c.readfrom_mem_into(addr, 107, reg2)) +print(0x40 == reg2[0]) +print(0x00 == reg2[1]) +# clear the sleep bit +reg2[0] = 0 +# set some other bits +reg2[1] |= 0x03 +print(2 == i2c.writeto_mem(addr, 107, reg2)) +# read it back +i2c.readfrom_mem_into(addr, 107, reg2_r) +print(reg2 == reg2_r) + +# reset the sensor +reg[0] = 0x80 +print(1 == i2c.writeto_mem(addr, 107, reg)) +time.sleep_ms(100) # wait for the sensor to reset... + +# try some raw read and writes +reg[0] = 117 # register address +print(1 == i2c.writeto(addr, reg, stop=False)) # just write the register address +# now read +print(1 == i2c.readfrom_into(addr, reg)) +print(reg[0] == 0x68) +reg[0] = 117 # register address +print(1 == i2c.writeto(addr, reg, stop=False)) # just write the register address +# now read +print(0x68 == i2c.readfrom(addr, 1)[0]) + +i2c.readfrom_mem_into(addr, 107, reg2) +print(0x40 == reg2[0]) +print(0x00 == reg2[1]) + +reg2[0] = 107 # register address +reg2[1] = 0 +print(2 == i2c.writeto(addr, reg2, stop=True)) # write the register address and the data +i2c.readfrom_mem_into(addr, 107, reg) # check it back +print(reg[0] == 0) + +# check for memory leaks... +for i in range (0, 1000): + i2c = I2C(0, I2C.MASTER, baudrate=100000) + +# test deinit +i2c = I2C(0, I2C.MASTER, baudrate=100000) +i2c.deinit() +print(i2c) + +# next ones should raise +try: + i2c.scan() +except Exception: + print("Exception") + +try: + i2c.readfrom(addr, 1) +except Exception: + print("Exception") + +try: + i2c.readfrom_into(addr, reg) +except Exception: + print("Exception") + +try: + i2c.readfrom_mem_into(addr, 107, reg) +except Exception: + print("Exception") + +try: + i2c.writeto(addr, reg, stop=False) +except Exception: + print("Exception") + +try: + i2c.writeto_mem(addr, 107, reg) +except Exception: + print("Exception") + +try: + i2c.readfrom_mem(addr, 116, 2) +except Exception: + print("Exception") + +try: + I2C(1, I2C.MASTER, baudrate=100000) +except Exception: + print("Exception") + +# reinitialization must work +i2c.init(baudrate=400000) +print(i2c) + diff --git a/src/openmv/src/micropython/tests/wipy/i2c.py.exp b/src/openmv/src/micropython/tests/wipy/i2c.py.exp new file mode 100755 index 0000000..083da9b --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/i2c.py.exp @@ -0,0 +1,51 @@ +I2C(0, I2C.MASTER, baudrate=100000) +I2C(0, I2C.MASTER, baudrate=50000) +I2C(0, I2C.MASTER, baudrate=100000) +I2C(0, I2C.MASTER, baudrate=400000) +I2C(0, I2C.MASTER, baudrate=400000) +104 +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +I2C(0) +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +I2C(0, I2C.MASTER, baudrate=400000) diff --git a/src/openmv/src/micropython/tests/wipy/modwipy.py b/src/openmv/src/micropython/tests/wipy/modwipy.py new file mode 100755 index 0000000..7571af0 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/modwipy.py @@ -0,0 +1,21 @@ +''' +wipy module test for the CC3200 based boards +''' + +import os +import wipy + +mch = os.uname().machine +if not 'LaunchPad' in mch and not'WiPy' in mch: + raise Exception('Board not supported!') + +print(wipy.heartbeat() == True) +wipy.heartbeat(False) +print(wipy.heartbeat() == False) +wipy.heartbeat(True) +print(wipy.heartbeat() == True) + +try: + wipy.heartbeat(True, 1) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/modwipy.py.exp b/src/openmv/src/micropython/tests/wipy/modwipy.py.exp new file mode 100755 index 0000000..52eeb53 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/modwipy.py.exp @@ -0,0 +1,4 @@ +True +True +True +Exception diff --git a/src/openmv/src/micropython/tests/wipy/os.py b/src/openmv/src/micropython/tests/wipy/os.py new file mode 100755 index 0000000..0596a16 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/os.py @@ -0,0 +1,164 @@ +''' +os module test for the CC3200 based boards +''' + +from machine import SD +import os + +mch = os.uname().machine +if 'LaunchPad' in mch: + sd_pins = ('GP16', 'GP17', 'GP15') +elif 'WiPy' in mch: + sd_pins = ('GP10', 'GP11', 'GP15') +else: + raise Exception('Board not supported!') + +sd = SD(pins=sd_pins) + +os.mount(sd, '/sd') +os.mkfs('/sd') +os.chdir('/flash') +print(os.listdir()) + +os.chdir('/sd') +print(os.listdir()) + +# create a test directory in flash +os.mkdir('/flash/test') +os.chdir('/flash/test') +print(os.getcwd()) +os.chdir('..') +print(os.getcwd()) +os.chdir('test') +print(os.getcwd()) +# create a new file +f = open('test.txt', 'w') +test_bytes = os.urandom(1024) +n_w = f.write(test_bytes) +print(n_w == len(test_bytes)) +f.close() +f = open('test.txt', 'r') +r = bytes(f.read(), 'ascii') +# check that we can write and read it correctly +print(r == test_bytes) +f.close() +os.rename('test.txt', 'newtest.txt') +print(os.listdir()) +os.rename('/flash/test', '/flash/newtest') +print(os.listdir('/flash')) +os.remove('newtest.txt') +os.chdir('..') +os.rmdir('newtest') + +# create a test directory in the sd card +os.mkdir('/sd/test') +os.chdir('/sd/test') +print(os.getcwd()) +os.chdir('..') +print(os.getcwd()) +os.chdir('test') +print(os.getcwd()) +# create a new file +f = open('test.txt', 'w') +test_bytes = os.urandom(1024) +n_w = f.write(test_bytes) +print(n_w == len(test_bytes)) +f.close() +f = open('test.txt', 'r') +r = bytes(f.read(), 'ascii') +# check that we can write and read it correctly +print(r == test_bytes) +f.close() + +print('CC3200' in os.uname().machine) +print('WiPy' == os.uname().sysname) + +os.sync() +os.stat('/flash') +os.stat('/flash/sys') +os.stat('/flash/boot.py') +os.stat('/sd') +os.stat('/') +os.chdir('/sd/test') +os.remove('test.txt') +os.chdir('/sd') +os.rmdir('test') +os.listdir('/sd') +print(os.listdir('/')) +os.unmount('/sd') +print(os.listdir('/')) +os.mkfs(sd) +os.mount(sd, '/sd') +print(os.listdir('/')) +os.chdir('/flash') + +# next ones must raise +sd.deinit() +try: + os.listdir('/sd') +except: + print('Exception') + +#re-initialization must work +sd.init() +print(os.listdir('/sd')) + +try: + os.mount(sd, '/sd') +except: + print('Exception') + +try: + os.mount(sd, '/sd2') +except: + print('Exception') + +os.unmount('/sd') +try: + os.listdir('/sd') +except: + print('Exception') + +try: + os.unmount('/flash') +except: + print('Exception') + +try: + os.unmount('/something') +except: + print('Exception') + +try: + os.unmount('something') +except: + print('Exception') + +try: + os.mkfs('flash') # incorrect path format +except: + print('Exception') + +try: + os.remove('/flash/nofile.txt') +except: + print('Exception') + +try: + os.rename('/flash/nofile.txt', '/flash/nofile2.txt') +except: + print('Exception') + +try: + os.chdir('/flash/nodir') +except: + print('Exception') + +try: + os.listdir('/flash/nodir') +except: + print('Exception') + +os.mount(sd, '/sd') +print(os.listdir('/')) +os.unmount('/sd') diff --git a/src/openmv/src/micropython/tests/wipy/os.py.exp b/src/openmv/src/micropython/tests/wipy/os.py.exp new file mode 100755 index 0000000..a0f01e3 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/os.py.exp @@ -0,0 +1,32 @@ +['main.py', 'sys', 'lib', 'cert', 'boot.py'] +[] +/flash/test +/flash +/flash/test +True +True +['newtest.txt'] +['main.py', 'sys', 'lib', 'cert', 'boot.py', 'newtest'] +/sd/test +/sd +/sd/test +True +True +True +True +['flash', 'sd'] +['flash'] +['flash', 'sd'] +[] +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +['flash', 'sd'] diff --git a/src/openmv/src/micropython/tests/wipy/pin.py b/src/openmv/src/micropython/tests/wipy/pin.py new file mode 100755 index 0000000..22c7c61 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/pin.py @@ -0,0 +1,182 @@ +""" +This test need a set of pins which can be set as inputs and have no external +pull up or pull down connected. +GP12 and GP17 must be connected together +""" +from machine import Pin +import os + +mch = os.uname().machine +if 'LaunchPad' in mch: + pin_map = ['GP24', 'GP12', 'GP14', 'GP15', 'GP16', 'GP17', 'GP28', 'GP8', 'GP6', 'GP30', 'GP31', 'GP3', 'GP0', 'GP4', 'GP5'] + max_af_idx = 15 +elif 'WiPy' in mch: + pin_map = ['GP23', 'GP24', 'GP12', 'GP13', 'GP14', 'GP9', 'GP17', 'GP28', 'GP22', 'GP8', 'GP30', 'GP31', 'GP0', 'GP4', 'GP5'] + max_af_idx = 15 +else: + raise Exception('Board not supported!') + +# test initial value +p = Pin('GP12', Pin.IN) +Pin('GP17', Pin.OUT, value=1) +print(p() == 1) +Pin('GP17', Pin.OUT, value=0) +print(p() == 0) + +def test_noinit(): + for p in pin_map: + pin = Pin(p) + pin.value() + +def test_pin_read(pull): + # enable the pull resistor on all pins, then read the value + for p in pin_map: + pin = Pin(p, mode=Pin.IN, pull=pull) + for p in pin_map: + print(pin()) + +def test_pin_af(): + for p in pin_map: + for af in Pin(p).alt_list(): + if af[1] <= max_af_idx: + Pin(p, mode=Pin.ALT, alt=af[1]) + Pin(p, mode=Pin.ALT_OPEN_DRAIN, alt=af[1]) + +# test un-initialized pins +test_noinit() +# test with pull-up and pull-down +test_pin_read(Pin.PULL_UP) +test_pin_read(Pin.PULL_DOWN) + +# test all constructor combinations +pin = Pin(pin_map[0]) +pin = Pin(pin_map[0], mode=Pin.IN) +pin = Pin(pin_map[0], mode=Pin.OUT) +pin = Pin(pin_map[0], mode=Pin.IN, pull=Pin.PULL_DOWN) +pin = Pin(pin_map[0], mode=Pin.IN, pull=Pin.PULL_UP) +pin = Pin(pin_map[0], mode=Pin.OPEN_DRAIN, pull=Pin.PULL_UP) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_DOWN) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=None) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_UP) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.LOW_POWER) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.MED_POWER) +pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.HIGH_POWER) +pin = Pin(pin_map[0], mode=Pin.OUT, drive=pin.LOW_POWER) +pin = Pin(pin_map[0], Pin.OUT, Pin.PULL_DOWN) +pin = Pin(pin_map[0], Pin.ALT, Pin.PULL_UP) +pin = Pin(pin_map[0], Pin.ALT_OPEN_DRAIN, Pin.PULL_UP) +test_pin_af() # try the entire af range on all pins + +# test pin init and printing +pin = Pin(pin_map[0]) +pin.init(mode=Pin.IN) +print(pin) +pin.init(Pin.IN, Pin.PULL_DOWN) +print(pin) +pin.init(mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.LOW_POWER) +print(pin) +pin.init(mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.HIGH_POWER) +print(pin) + +# test value in OUT mode +pin = Pin(pin_map[0], mode=Pin.OUT) +pin.value(0) +pin.toggle() # test toggle +print(pin()) +pin.toggle() # test toggle again +print(pin()) +# test different value settings +pin(1) +print(pin.value()) +pin(0) +print(pin.value()) +pin.value(1) +print(pin()) +pin.value(0) +print(pin()) + +# test all getters and setters +pin = Pin(pin_map[0], mode=Pin.OUT) +# mode +print(pin.mode() == Pin.OUT) +pin.mode(Pin.IN) +print(pin.mode() == Pin.IN) +# pull +pin.pull(None) +print(pin.pull() == None) +pin.pull(Pin.PULL_DOWN) +print(pin.pull() == Pin.PULL_DOWN) +# drive +pin.drive(Pin.MED_POWER) +print(pin.drive() == Pin.MED_POWER) +pin.drive(Pin.HIGH_POWER) +print(pin.drive() == Pin.HIGH_POWER) +# id +print(pin.id() == pin_map[0]) + +# all the next ones MUST raise +try: + pin = Pin(pin_map[0], mode=Pin.OUT, pull=Pin.PULL_UP, drive=pin.IN) # incorrect drive value +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], mode=Pin.LOW_POWER, pull=Pin.PULL_UP) # incorrect mode value +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], mode=Pin.IN, pull=Pin.HIGH_POWER) # incorrect pull value +except Exception: + print('Exception') + +try: + pin = Pin('A0', Pin.OUT, Pin.PULL_DOWN) # incorrect pin id +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], Pin.IN, Pin.PULL_UP, alt=0) # af specified in GPIO mode +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], Pin.OUT, Pin.PULL_UP, alt=7) # af specified in GPIO mode +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], Pin.ALT, Pin.PULL_UP, alt=0) # incorrect af +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], Pin.ALT_OPEN_DRAIN, Pin.PULL_UP, alt=-1) # incorrect af +except Exception: + print('Exception') + +try: + pin = Pin(pin_map[0], Pin.ALT_OPEN_DRAIN, Pin.PULL_UP, alt=16) # incorrect af +except Exception: + print('Exception') + +try: + pin.mode(Pin.PULL_UP) # incorrect pin mode +except Exception: + print('Exception') + +try: + pin.pull(Pin.OUT) # incorrect pull +except Exception: + print('Exception') + +try: + pin.drive(Pin.IN) # incorrect drive strength +except Exception: + print('Exception') + +try: + pin.id('ABC') # id cannot be set +except Exception: + print('Exception') + diff --git a/src/openmv/src/micropython/tests/wipy/pin.py.exp b/src/openmv/src/micropython/tests/wipy/pin.py.exp new file mode 100755 index 0000000..0e3dddc --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/pin.py.exp @@ -0,0 +1,60 @@ +True +True +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +Pin('GP23', mode=Pin.IN, pull=None, drive=Pin.MED_POWER, alt=-1) +Pin('GP23', mode=Pin.IN, pull=Pin.PULL_DOWN, drive=Pin.MED_POWER, alt=-1) +Pin('GP23', mode=Pin.OUT, pull=Pin.PULL_UP, drive=Pin.LOW_POWER, alt=-1) +Pin('GP23', mode=Pin.OUT, pull=Pin.PULL_UP, drive=Pin.HIGH_POWER, alt=-1) +1 +0 +1 +0 +1 +0 +True +True +True +True +True +True +True +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/pin_irq.py b/src/openmv/src/micropython/tests/wipy/pin_irq.py new file mode 100755 index 0000000..875f1f9 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/pin_irq.py @@ -0,0 +1,116 @@ +''' +Pin IRQ test for the CC3200 based boards. +''' + +from machine import Pin +import machine +import os +import time + +mch = os.uname().machine +if 'LaunchPad' in mch: + pins = ['GP16', 'GP13'] +elif 'WiPy' in mch: + pins = ['GP16', 'GP13'] +else: + raise Exception('Board not supported!') + +pin0 = Pin(pins[0], mode=Pin.OUT, value=1) +pin1 = Pin(pins[1], mode=Pin.IN, pull=Pin.PULL_UP) + +def pin_handler (pin_o): + global pin_irq_count_trigger + global pin_irq_count_total + global _trigger + if _trigger & pin1_irq.flags(): + pin_irq_count_trigger += 1 + pin_irq_count_total += 1 + +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_FALLING +pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) +for i in range (0, 10): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 5) +print(pin_irq_count_total == 5) + +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_RISING +pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) +for i in range (0, 200): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 100) +print(pin_irq_count_total == 100) + +pin1_irq.disable() +pin0(1) +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +_trigger = Pin.IRQ_FALLING +pin1_irq.init(trigger=_trigger, handler=pin_handler) +pin0(0) +time.sleep_us(50) +print(pin_irq_count_trigger == 1) +print(pin_irq_count_total == 1) +pin0(1) +time.sleep_us(50) +print(pin_irq_count_trigger == 1) +print(pin_irq_count_total == 1) + +# check the call method +pin1_irq() +print(pin_irq_count_trigger == 1) # no flags since the irq was manually triggered +print(pin_irq_count_total == 2) + +pin1_irq.disable() +pin_irq_count_trigger = 0 +pin_irq_count_total = 0 +for i in range (0, 10): + pin0.toggle() + time.sleep_ms(5) +print(pin_irq_count_trigger == 0) +print(pin_irq_count_total == 0) + +# test waking up from suspended mode on low level +pin0(0) +t0 = time.ticks_ms() +pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.SLEEP) +machine.sleep() +print(time.ticks_ms() - t0 < 10) +print('Awake') + +# test waking up from suspended mode on high level +pin0(1) +t0 = time.ticks_ms() +pin1_irq.init(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.SLEEP) +machine.sleep() +print(time.ticks_ms() - t0 < 10) +print('Awake') + +# check for memory leaks +for i in range(0, 1000): + pin0_irq = pin0.irq(trigger=_trigger, handler=pin_handler) + pin1_irq = pin1.irq(trigger=_trigger, handler=pin_handler) + +# next ones must raise +try: + pin1_irq.init(trigger=123456, handler=pin_handler) +except: + print('Exception') + +try: + pin1_irq.init(trigger=Pin.IRQ_LOW_LEVEL, wake=1789456) +except: + print('Exception') + +try: + pin0_irq = pin0.irq(trigger=Pin.IRQ_RISING, wake=machine.SLEEP) # GP16 can't wake up from DEEPSLEEP +except: + print('Exception') + +pin0_irq.disable() +pin1_irq.disable() diff --git a/src/openmv/src/micropython/tests/wipy/pin_irq.py.exp b/src/openmv/src/micropython/tests/wipy/pin_irq.py.exp new file mode 100755 index 0000000..458bd95 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/pin_irq.py.exp @@ -0,0 +1,19 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +Awake +True +Awake +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/reset/reset.py b/src/openmv/src/micropython/tests/wipy/reset/reset.py new file mode 100755 index 0000000..35a970c --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/reset/reset.py @@ -0,0 +1,17 @@ +''' +Reset script for the cc3200 boards +This is needed to force the board to reboot +with the default WLAN AP settings +''' + +from machine import WDT +import time +import os + +mch = os.uname().machine +if not 'LaunchPad' in mch and not 'WiPy' in mch: + raise Exception('Board not supported!') + +wdt = WDT(timeout=1000) +print(wdt) +time.sleep_ms(900) diff --git a/src/openmv/src/micropython/tests/wipy/reset/reset.py.exp b/src/openmv/src/micropython/tests/wipy/reset/reset.py.exp new file mode 100755 index 0000000..4b6cc11 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/reset/reset.py.exp @@ -0,0 +1 @@ + diff --git a/src/openmv/src/micropython/tests/wipy/rtc.py b/src/openmv/src/micropython/tests/wipy/rtc.py new file mode 100755 index 0000000..2737ebe --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/rtc.py @@ -0,0 +1,117 @@ +''' +RTC test for the CC3200 based boards. +''' + +from machine import RTC +import os +import time + +mch = os.uname().machine +if not 'LaunchPad' in mch and not 'WiPy' in mch: + raise Exception('Board not supported!') + +rtc = RTC() +print(rtc) +print(rtc.now()[:6]) + +rtc = RTC(datetime=(2015, 8, 29, 9, 0, 0, 0, None)) +print(rtc.now()[:6]) + +rtc.deinit() +print(rtc.now()[:6]) + +rtc.init((2015, 8, 29, 9, 0, 0, 0, None)) +print(rtc.now()[:6]) +seconds = rtc.now()[5] +time.sleep_ms(1000) +print(rtc.now()[5] - seconds == 1) +seconds = rtc.now()[5] +time.sleep_ms(2000) +print(rtc.now()[5] - seconds == 2) + +# initialization with shorter tuples +rtc.init((2015, 9, 19, 8, 0, 0, 0)) +print(rtc.now()[5]) +rtc.init((2015, 9, 19, 8, 0, 0)) +print(rtc.now()[5]) +rtc.init((2015, 9, 19, 8, 0)) +print(rtc.now()[5]) +rtc.init((2015, 9, 19, 8)) +print(rtc.now()[4]) +rtc.init((2015, 9, 19)) +print(rtc.now()[3]) + +def set_and_print(datetime): + rtc.init(datetime) + print(rtc.now()[:6]) + +# make sure that setting works correctly +set_and_print((2000, 1, 1, 0, 0, 0, 0, None)) +set_and_print((2000, 1, 31, 0, 0, 0, 0, None)) +set_and_print((2000, 12, 31, 0, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 0, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 0, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 1, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 12, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 13, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 23, 0, 0, 0, None)) +set_and_print((2016, 12, 31, 23, 1, 0, 0, None)) +set_and_print((2016, 12, 31, 23, 59, 0, 50, None)) +set_and_print((2016, 12, 31, 23, 59, 1, 900, None)) +set_and_print((2016, 12, 31, 23, 59, 59, 100, None)) +set_and_print((2048, 12, 31, 23, 59, 59, 99999, None)) + +rtc.init((2015, 8, 29, 9, 0, 0, 0, None)) +rtc.alarm(0, 5000) +rtc.alarm(time=2000) +time.sleep_ms(1000) +left = rtc.alarm_left() +print(abs(left-1000) <= 10) +time.sleep_ms(1000) +print(rtc.alarm_left() == 0) +time.sleep_ms(100) +print(rtc.alarm_left(0) == 0) + +rtc.alarm(time=1000, repeat=True) +time.sleep_ms(1500) +left = rtc.alarm_left() +print(abs(left-500) <= 15) + +rtc.init((2015, 8, 29, 9, 0, 0, 0, None)) +rtc.alarm(time=(2015, 8, 29, 9, 0, 45)) +time.sleep_ms(1000) +left = rtc.alarm_left() +print(abs(left-44000) <= 90) +rtc.alarm_cancel() +rtc.deinit() + +# next ones must raise +try: + rtc.alarm(5000) +except: + print('Exception') + +try: + rtc.alarm_left(1) +except: + print('Exception') + +try: + rtc.alarm_cancel(1) +except: + print('Exception') + +try: + rtc.alarm(5000) +except: + print('Exception') + +try: + rtc = RTC(200000000) +except: + print('Exception') + +try: + rtc = RTC((2015, 8, 29, 9, 0, 0, 0, None)) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/rtc.py.exp b/src/openmv/src/micropython/tests/wipy/rtc.py.exp new file mode 100755 index 0000000..44f8f8b --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/rtc.py.exp @@ -0,0 +1,37 @@ + +(2015, 1, 1, 0, 0, 0) +(2015, 8, 29, 9, 0, 0) +(2015, 1, 1, 0, 0, 0) +(2015, 8, 29, 9, 0, 0) +True +True +0 +0 +0 +0 +0 +(2000, 1, 1, 0, 0, 0) +(2000, 1, 31, 0, 0, 0) +(2000, 12, 31, 0, 0, 0) +(2016, 12, 31, 0, 0, 0) +(2016, 12, 31, 0, 0, 0) +(2016, 12, 31, 1, 0, 0) +(2016, 12, 31, 12, 0, 0) +(2016, 12, 31, 13, 0, 0) +(2016, 12, 31, 23, 0, 0) +(2016, 12, 31, 23, 1, 0) +(2016, 12, 31, 23, 59, 0) +(2016, 12, 31, 23, 59, 1) +(2016, 12, 31, 23, 59, 59) +(2048, 12, 31, 23, 59, 59) +True +True +True +True +True +Exception +Exception +Exception +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/sd.py b/src/openmv/src/micropython/tests/wipy/sd.py new file mode 100755 index 0000000..92746e0 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/sd.py @@ -0,0 +1,46 @@ +''' +SD card test for the CC3200 based boards. +''' + +from machine import SD +import os + +mch = os.uname().machine +if 'LaunchPad' in mch: + sd_pins = ('GP16', 'GP17', 'GP15') +elif 'WiPy' in mch: + sd_pins = ('GP10', 'GP11', 'GP15') +else: + raise Exception('Board not supported!') + +sd = SD(pins=sd_pins) +print(sd) +sd.deinit() +print(sd) +sd.init(sd_pins) +print(sd) + +sd = SD(0, pins=sd_pins) +sd = SD(id=0, pins=sd_pins) +sd = SD(0, sd_pins) + +# check for memory leaks +for i in range(0, 1000): + sd = sd = SD(0, pins=sd_pins) + +# next ones should raise +try: + sd = SD(pins=()) +except Exception: + print("Exception") + +try: + sd = SD(pins=('GP10', 'GP11', 'GP8')) +except Exception: + print("Exception") + +try: + sd = SD(pins=('GP10', 'GP11')) +except Exception: + print("Exception") + diff --git a/src/openmv/src/micropython/tests/wipy/sd.py.exp b/src/openmv/src/micropython/tests/wipy/sd.py.exp new file mode 100755 index 0000000..eaa5f08 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/sd.py.exp @@ -0,0 +1,6 @@ + + + +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py b/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py new file mode 100755 index 0000000..ec3baa5 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py @@ -0,0 +1,89 @@ +''' +RTC IRQ test for the CC3200 based boards. +''' + +from machine import RTC +import machine +import os +import time + +mch = os.uname().machine +if not 'LaunchPad' in mch and not 'WiPy' in mch: + raise Exception('Board not supported!') + +def rtc_ticks_ms(rtc): + timedate = rtc.now() + return (timedate[5] * 1000) + (timedate[6] // 1000) + +rtc_irq_count = 0 + +def alarm_handler (rtc_o): + global rtc_irq + global rtc_irq_count + if rtc_irq.flags() & RTC.ALARM0: + rtc_irq_count += 1 + +rtc = RTC() +rtc.alarm(time=500, repeat=True) +rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler) + +# active mode +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 2) +rtc_irq_count = 0 +rtc.alarm(time=200, repeat=True) +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 5) + +rtc_irq_count = 0 +rtc.alarm(time=100, repeat=True) +time.sleep_ms(1000) +rtc.alarm_cancel() +print(rtc_irq_count == 10) + +# deep sleep mode +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=50, repeat=True) +rtc_irq.init(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP | machine.IDLE) +while rtc_irq_count < 3: + machine.sleep() +print(rtc_irq_count == 3) + +# no repetition +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=100, repeat=False) +time.sleep_ms(250) +print(rtc_irq_count == 1) + +rtc.alarm_cancel() +t0 = rtc_ticks_ms(rtc) +rtc.alarm(time=500, repeat=False) +machine.sleep() +t1 = rtc_ticks_ms(rtc) +print(abs(t1 - t0 - 500) < 20) + +# deep sleep repeated mode +rtc.alarm_cancel() +rtc_irq_count = 0 +rtc.alarm(time=500, repeat=True) +t0 = rtc_ticks_ms(rtc) +rtc_irq = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP) +while rtc_irq_count < 3: + machine.sleep() + t1 = rtc_ticks_ms(rtc) + print(abs(t1 - t0 - (500 * rtc_irq_count)) < 25) + +# next ones must raise +try: + rtc_irq = rtc.irq(trigger=10, handler=alarm_handler) +except: + print('Exception') + +try: + rtc_irq = rtc.irq(trigger=RTC.ALARM0, wake=1789456) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py.exp b/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py.exp new file mode 100755 index 0000000..a3eebc2 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/skipped/rtc_irq.py.exp @@ -0,0 +1,11 @@ +True +True +True +True +True +True +True +True +True +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/spi.py b/src/openmv/src/micropython/tests/wipy/spi.py new file mode 100755 index 0000000..6bd7aab --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/spi.py @@ -0,0 +1,147 @@ +''' +SPI test for the CC3200 based boards. +''' + +from machine import SPI +import os + +mch = os.uname().machine +if 'LaunchPad' in mch: + spi_pins = ('GP14', 'GP16', 'GP30') +elif 'WiPy' in mch: + spi_pins = ('GP14', 'GP16', 'GP30') +else: + raise Exception('Board not supported!') + +spi = SPI(0, SPI.MASTER, baudrate=2000000, polarity=0, phase=0, firstbit=SPI.MSB, pins=spi_pins) +print(spi) +spi = SPI(baudrate=5000000) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=200000, bits=16, polarity=0, phase=0) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=1) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=5000000, bits=32, polarity=1, phase=0) +print(spi) +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=1, phase=1) +print(spi) +spi.init(baudrate=20000000, polarity=0, phase=0) +print(spi) +spi=SPI() +print(spi) +SPI(mode=SPI.MASTER) +SPI(mode=SPI.MASTER, pins=spi_pins) +SPI(id=0, mode=SPI.MASTER, polarity=0, phase=0, pins=('GP14', 'GP16', 'GP15')) +SPI(0, SPI.MASTER, polarity=0, phase=0, pins=('GP31', 'GP16', 'GP15')) + +spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=0, pins=spi_pins) +print(spi.write('123456') == 6) +buffer_r = bytearray(10) +print(spi.readinto(buffer_r) == 10) +print(spi.readinto(buffer_r, write=0x55) == 10) +read = spi.read(10) +print(len(read) == 10) +read = spi.read(10, write=0xFF) +print(len(read) == 10) +buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) +print(spi.write_readinto(buffer_w, buffer_r) == 10) +print(buffer_w == buffer_r) + +# test all polaritiy and phase combinations +spi.init(polarity=1, phase=0, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +spi.init(polarity=1, phase=1, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +spi.init(polarity=0, phase=1, pins=None) +buffer_r = bytearray(10) +spi.write_readinto(buffer_w, buffer_r) +print(buffer_w == buffer_r) + +# test 16 and 32 bit transfers +buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]) +buffer_r = bytearray(12) +spi.init(SPI.MASTER, baudrate=10000000, bits=16, polarity=0, phase=0, pins=None) +print(spi.write_readinto(buffer_w, buffer_r) == 12) +print(buffer_w == buffer_r) + +buffer_r = bytearray(12) +spi.init(SPI.MASTER, baudrate=10000000, bits=32, polarity=0, phase=0, pins=None) +print(spi.write_readinto(buffer_w, buffer_r) == 12) +print(buffer_w == buffer_r) + +# check for memory leaks... +for i in range (0, 1000): + spi = SPI(0, SPI.MASTER, baudrate=1000000) + +# test deinit +spi = SPI(0, SPI.MASTER, baudrate=1000000) +spi.deinit() +print(spi) + +spi = SPI(0, SPI.MASTER, baudrate=1000000) +# next ones must fail +try: + spi = SPI(0, 10, baudrate=10000000, polarity=0, phase=0) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=10000000, polarity=1, phase=2) +except: + print("Exception") + +try: + spi = SPI(1, mode=SPI.MASTER, baudrate=10000000, polarity=1, phase=1) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0, firstbit=2) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=2, phase=0, pins=('GP1', 'GP2')) +except: + print("Exception") + +try: + spi = SPI(0, mode=SPI.MASTER, baudrate=2000000, polarity=0, phase=0, bits=9) +except: + print("Exception") + +spi.deinit() +try: + spi.read(15) +except Exception: + print("Exception") + +try: + spi.spi.readinto(buffer_r) +except Exception: + print("Exception") + +try: + spi.spi.write('abc') +except Exception: + print("Exception") + +try: + spi.write_readinto(buffer_w, buffer_r) +except Exception: + print("Exception") + +# reinitialization must work +spi.init(baudrate=500000) +print(spi) diff --git a/src/openmv/src/micropython/tests/wipy/spi.py.exp b/src/openmv/src/micropython/tests/wipy/spi.py.exp new file mode 100755 index 0000000..cc4ff40 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/spi.py.exp @@ -0,0 +1,35 @@ +SPI(0, SPI.MASTER, baudrate=2000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=5000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=200000, bits=16, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=10000000, bits=8, polarity=0, phase=1, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=5000000, bits=32, polarity=1, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=10000000, bits=8, polarity=1, phase=1, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=20000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +SPI(0, SPI.MASTER, baudrate=1000000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) +True +True +True +True +True +True +True +True +True +True +True +True +True +True +SPI(0) +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +SPI(0, SPI.MASTER, baudrate=500000, bits=8, polarity=0, phase=0, firstbit=SPI.MSB) diff --git a/src/openmv/src/micropython/tests/wipy/time.py b/src/openmv/src/micropython/tests/wipy/time.py new file mode 100755 index 0000000..e6237de --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/time.py @@ -0,0 +1,75 @@ +import time + +DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +def is_leap(year): + return (year % 4) == 0 + +def test(): + seconds = 0 + wday = 5 # Jan 1, 2000 was a Saturday + for year in range(2000, 2049): + print("Testing %d" % year) + yday = 1 + for month in range(1, 13): + if month == 2 and is_leap(year): + DAYS_PER_MONTH[2] = 29 + else: + DAYS_PER_MONTH[2] = 28 + for day in range(1, DAYS_PER_MONTH[month] + 1): + secs = time.mktime((year, month, day, 0, 0, 0, 0, 0)) + if secs != seconds: + print("mktime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + tuple = time.localtime(seconds) + secs = time.mktime(tuple) + if secs != seconds: + print("localtime failed for %d-%02d-%02d got %d expected %d" % (year, month, day, secs, seconds)) + return + seconds += 86400 + if yday != tuple[7]: + print("locatime for %d-%02d-%02d got yday %d, expecting %d" % (year, month, day, tuple[7], yday)) + return + if wday != tuple[6]: + print("locatime for %d-%02d-%02d got wday %d, expecting %d" % (year, month, day, tuple[6], wday)) + return + yday += 1 + wday = (wday + 1) % 7 + +def spot_test(seconds, expected_time): + actual_time = time.localtime(seconds) + for i in range(len(actual_time)): + if actual_time[i] != expected_time[i]: + print("time.localtime(", seconds, ") returned", actual_time, "expecting", expected_time) + return + print("time.localtime(", seconds, ") returned", actual_time, "(pass)") + +test() +spot_test( 0, (2000, 1, 1, 0, 0, 0, 5, 1)) +spot_test( 1, (2000, 1, 1, 0, 0, 1, 5, 1)) +spot_test( 59, (2000, 1, 1, 0, 0, 59, 5, 1)) +spot_test( 60, (2000, 1, 1, 0, 1, 0, 5, 1)) +spot_test( 3599, (2000, 1, 1, 0, 59, 59, 5, 1)) +spot_test( 3600, (2000, 1, 1, 1, 0, 0, 5, 1)) +spot_test( -1, (1999, 12, 31, 23, 59, 59, 4, 365)) +spot_test( 447549467, (2014, 3, 7, 23, 17, 47, 4, 66)) +spot_test( -940984933, (1970, 3, 7, 23, 17, 47, 5, 66)) +spot_test(-1072915199, (1966, 1, 1, 0, 0, 1, 5, 1)) +spot_test(-1072915200, (1966, 1, 1, 0, 0, 0, 5, 1)) +spot_test(-1072915201, (1965, 12, 31, 23, 59, 59, 4, 365)) + +t1 = time.time() +time.sleep(2) +t2 = time.time() +print(abs(time.ticks_diff(t1, t2) -2) <= 1) + +t1 = time.ticks_ms() +time.sleep_ms(50) +t2 = time.ticks_ms() +print(abs(time.ticks_diff(t1, t2)- 50) <= 1) + +t1 = time.ticks_us() +time.sleep_us(1000) +t2 = time.ticks_us() +print(time.ticks_diff(t1, t2) < 1500) + +print(time.ticks_diff(time.ticks_cpu(), time.ticks_cpu()) < 16384) diff --git a/src/openmv/src/micropython/tests/wipy/time.py.exp b/src/openmv/src/micropython/tests/wipy/time.py.exp new file mode 100755 index 0000000..24d798f --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/time.py.exp @@ -0,0 +1,65 @@ +Testing 2000 +Testing 2001 +Testing 2002 +Testing 2003 +Testing 2004 +Testing 2005 +Testing 2006 +Testing 2007 +Testing 2008 +Testing 2009 +Testing 2010 +Testing 2011 +Testing 2012 +Testing 2013 +Testing 2014 +Testing 2015 +Testing 2016 +Testing 2017 +Testing 2018 +Testing 2019 +Testing 2020 +Testing 2021 +Testing 2022 +Testing 2023 +Testing 2024 +Testing 2025 +Testing 2026 +Testing 2027 +Testing 2028 +Testing 2029 +Testing 2030 +Testing 2031 +Testing 2032 +Testing 2033 +Testing 2034 +Testing 2035 +Testing 2036 +Testing 2037 +Testing 2038 +Testing 2039 +Testing 2040 +Testing 2041 +Testing 2042 +Testing 2043 +Testing 2044 +Testing 2045 +Testing 2046 +Testing 2047 +Testing 2048 +time.localtime( 0 ) returned (2000, 1, 1, 0, 0, 0, 5, 1) (pass) +time.localtime( 1 ) returned (2000, 1, 1, 0, 0, 1, 5, 1) (pass) +time.localtime( 59 ) returned (2000, 1, 1, 0, 0, 59, 5, 1) (pass) +time.localtime( 60 ) returned (2000, 1, 1, 0, 1, 0, 5, 1) (pass) +time.localtime( 3599 ) returned (2000, 1, 1, 0, 59, 59, 5, 1) (pass) +time.localtime( 3600 ) returned (2000, 1, 1, 1, 0, 0, 5, 1) (pass) +time.localtime( -1 ) returned (1999, 12, 31, 23, 59, 59, 4, 365) (pass) +time.localtime( 447549467 ) returned (2014, 3, 7, 23, 17, 47, 4, 66) (pass) +time.localtime( -940984933 ) returned (1970, 3, 7, 23, 17, 47, 5, 66) (pass) +time.localtime( -1072915199 ) returned (1966, 1, 1, 0, 0, 1, 5, 1) (pass) +time.localtime( -1072915200 ) returned (1966, 1, 1, 0, 0, 0, 5, 1) (pass) +time.localtime( -1072915201 ) returned (1965, 12, 31, 23, 59, 59, 4, 365) (pass) +True +True +True +True diff --git a/src/openmv/src/micropython/tests/wipy/timer.py b/src/openmv/src/micropython/tests/wipy/timer.py new file mode 100755 index 0000000..f62899b --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/timer.py @@ -0,0 +1,117 @@ +''' +Timer test for the CC3200 based boards. +''' + +from machine import Timer +import os +import time + +mch = os.uname().machine +if 'LaunchPad' in mch: + pwm_pin = ('GP24') +elif 'WiPy' in mch: + pwm_pin = ('GP24') +else: + raise Exception('Board not supported!') + +for i in range(4): + tim = Timer(i, mode=Timer.PERIODIC) + print(tim) + ch = tim.channel(Timer.A, freq=5) + print(ch) + ch = tim.channel(Timer.B, freq=5) + print(ch) + tim = Timer(i, mode=Timer.ONE_SHOT) + print(tim) + ch = tim.channel(Timer.A, freq=50) + print(ch) + ch = tim.channel(Timer.B, freq=50) + print(ch) + tim = Timer(i, mode=Timer.PWM) + print(tim) + ch = tim.channel(Timer.A, freq=50000, duty_cycle=2000, polarity=Timer.POSITIVE) + print(ch) + ch = tim.channel(Timer.B, freq=50000, duty_cycle=8000, polarity=Timer.NEGATIVE) + print(ch) + tim.deinit() + print(tim) + +for i in range(4): + tim = Timer(i, mode=Timer.PERIODIC) + tim.deinit() + + +class TimerTest: + def __init__(self): + self.tim = Timer(0, mode=Timer.PERIODIC) + self.int_count = 0 + + def timer_isr(self, tim_ch): + self.int_count += 1 + +timer_test = TimerTest() +ch = timer_test.tim.channel(Timer.A, freq=5) +print(ch.freq() == 5) +ch.irq(handler=timer_test.timer_isr, trigger=Timer.TIMEOUT) +time.sleep_ms(1001) +print(timer_test.int_count == 5) + +ch.freq(100) +timer_test.int_count = 0 +time.sleep_ms(1001) +print(timer_test.int_count == 100) + +ch.freq(1000) +time.sleep_ms(1500) +timer_test.int_count = 0 +time.sleep_ms(2000) +print(timer_test.int_count == 2000) + +timer_test.tim.deinit() +timer_test.tim.init(mode=Timer.ONE_SHOT) +ch = timer_test.tim.channel(Timer.A, period=100000) +ch.irq(handler=timer_test.timer_isr, trigger=Timer.TIMEOUT) +timer_test.int_count = 0 +time.sleep_ms(101) +print(timer_test.int_count == 1) +time.sleep_ms(101) +print(timer_test.int_count == 1) +timer_test.tim.deinit() +print(timer_test.tim) + +# 32 bit modes +tim = Timer(0, mode=Timer.PERIODIC, width=32) +ch = tim.channel(Timer.A | Timer.B, period=5000000) + +# check for memory leaks... +for i in range(1000): + tim = Timer(0, mode=Timer.PERIODIC) + ch = tim.channel(Timer.A, freq=5) + +# next ones must fail +try: + tim = Timer(0, mode=12) +except: + print('Exception') + +try: + tim = Timer(4, mode=Timer.ONE_SHOT) +except: + print('Exception') + +try: + tim = Timer(0, mode=Timer.PWM, width=32) +except: + print('Exception') + +tim = Timer(0, mode=Timer.PWM) + +try: + ch = tim.channel(TIMER_A | TIMER_B, freq=10) +except: + print('Exception') + +try: + ch = tim.channel(TIMER_A, freq=4) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/timer.py.exp b/src/openmv/src/micropython/tests/wipy/timer.py.exp new file mode 100755 index 0000000..972d819 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/timer.py.exp @@ -0,0 +1,52 @@ +Timer(0, mode=Timer.PERIODIC) +timer.channel(Timer.A, freq=5) +timer.channel(Timer.B, freq=5) +Timer(0, mode=Timer.ONE_SHOT) +timer.channel(Timer.A, freq=50) +timer.channel(Timer.B, freq=50) +Timer(0, mode=Timer.PWM) +timer.channel(Timer.A, freq=50000, polarity=Timer.POSITIVE, duty_cycle=20.00) +timer.channel(Timer.B, freq=50000, polarity=Timer.NEGATIVE, duty_cycle=80.00) +Timer(0, mode=Timer.PWM) +Timer(1, mode=Timer.PERIODIC) +timer.channel(Timer.A, freq=5) +timer.channel(Timer.B, freq=5) +Timer(1, mode=Timer.ONE_SHOT) +timer.channel(Timer.A, freq=50) +timer.channel(Timer.B, freq=50) +Timer(1, mode=Timer.PWM) +timer.channel(Timer.A, freq=50000, polarity=Timer.POSITIVE, duty_cycle=20.00) +timer.channel(Timer.B, freq=50000, polarity=Timer.NEGATIVE, duty_cycle=80.00) +Timer(1, mode=Timer.PWM) +Timer(2, mode=Timer.PERIODIC) +timer.channel(Timer.A, freq=5) +timer.channel(Timer.B, freq=5) +Timer(2, mode=Timer.ONE_SHOT) +timer.channel(Timer.A, freq=50) +timer.channel(Timer.B, freq=50) +Timer(2, mode=Timer.PWM) +timer.channel(Timer.A, freq=50000, polarity=Timer.POSITIVE, duty_cycle=20.00) +timer.channel(Timer.B, freq=50000, polarity=Timer.NEGATIVE, duty_cycle=80.00) +Timer(2, mode=Timer.PWM) +Timer(3, mode=Timer.PERIODIC) +timer.channel(Timer.A, freq=5) +timer.channel(Timer.B, freq=5) +Timer(3, mode=Timer.ONE_SHOT) +timer.channel(Timer.A, freq=50) +timer.channel(Timer.B, freq=50) +Timer(3, mode=Timer.PWM) +timer.channel(Timer.A, freq=50000, polarity=Timer.POSITIVE, duty_cycle=20.00) +timer.channel(Timer.B, freq=50000, polarity=Timer.NEGATIVE, duty_cycle=80.00) +Timer(3, mode=Timer.PWM) +True +True +True +True +True +True +Timer(0, mode=Timer.ONE_SHOT) +Exception +Exception +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/uart.py b/src/openmv/src/micropython/tests/wipy/uart.py new file mode 100755 index 0000000..8e79401 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/uart.py @@ -0,0 +1,158 @@ +''' +UART test for the CC3200 based boards. +UART0 and UART1 must be connected together for this test to pass. +''' + +from machine import UART +from machine import Pin +import os +import time + +mch = os.uname().machine +if 'LaunchPad' in mch: + uart_id_range = range(0, 2) + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +elif 'WiPy' in mch: + uart_id_range = range(0, 2) + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +else: + raise Exception('Board not supported!') + +# just in case we have the repl duplicated on any of the uarts +os.dupterm(None) + +for uart_id in uart_id_range: + uart = UART(uart_id, 38400) + print(uart) + uart.init(57600, 8, None, 1, pins=uart_pins[uart_id][0]) + uart.init(baudrate=9600, stop=2, parity=UART.EVEN, pins=uart_pins[uart_id][1]) + uart.init(baudrate=115200, parity=UART.ODD, stop=0, pins=uart_pins[uart_id][0]) + uart = UART(baudrate=1000000) + uart.sendbreak() + +uart = UART(baudrate=1000000) +uart = UART() +print(uart) +uart = UART(baudrate=38400, pins=('GP12', 'GP13')) +print(uart) +uart = UART(pins=('GP12', 'GP13')) +print(uart) +uart = UART(pins=(None, 'GP17')) +print(uart) +uart = UART(baudrate=57600, pins=('GP16', 'GP17')) +print(uart) + +# now it's time for some loopback tests between the uarts +uart0 = UART(0, 1000000, pins=uart_pins[0][0]) +print(uart0) +uart1 = UART(1, 1000000, pins=uart_pins[1][0]) +print(uart1) + +print(uart0.write(b'123456') == 6) +print(uart1.read() == b'123456') + +print(uart1.write(b'123') == 3) +print(uart0.read(1) == b'1') +print(uart0.read(2) == b'23') +print(uart0.read() == None) + +uart0.write(b'123') +buf = bytearray(3) +print(uart1.readinto(buf, 1) == 1) +print(buf) +print(uart1.readinto(buf) == 2) +print(buf) + +# try initializing without the id +uart0 = UART(baudrate=1000000, pins=uart_pins[0][0]) +uart0.write(b'1234567890') +time.sleep_ms(2) # because of the fifo interrupt levels +print(uart1.any() == 10) +print(uart1.readline() == b'1234567890') +print(uart1.any() == 0) + +uart0.write(b'1234567890') +print(uart1.read() == b'1234567890') + +# tx only mode +uart0 = UART(0, 1000000, pins=('GP12', None)) +print(uart0.write(b'123456') == 6) +print(uart1.read() == b'123456') +print(uart1.write(b'123') == 3) +print(uart0.read() == None) + +# rx only mode +uart0 = UART(0, 1000000, pins=(None, 'GP13')) +print(uart0.write(b'123456') == 6) +print(uart1.read() == None) +print(uart1.write(b'123') == 3) +print(uart0.read() == b'123') + +# leave pins as they were (rx only mode) +uart0 = UART(0, 1000000, pins=None) +print(uart0.write(b'123456') == 6) +print(uart1.read() == None) +print(uart1.write(b'123') == 3) +print(uart0.read() == b'123') + +# no pin assignment +uart0 = UART(0, 1000000, pins=(None, None)) +print(uart0.write(b'123456789') == 9) +print(uart1.read() == None) +print(uart1.write(b'123456789') == 9) +print(uart0.read() == None) +print(Pin.board.GP12) +print(Pin.board.GP13) + +# check for memory leaks... +for i in range (0, 1000): + uart0 = UART(0, 1000000) + uart1 = UART(1, 1000000) + +# next ones must raise +try: + UART(0, 9600, parity=None, pins=('GP12', 'GP13', 'GP7')) +except Exception: + print('Exception') + +try: + UART(0, 9600, parity=UART.ODD, pins=('GP12', 'GP7')) +except Exception: + print('Exception') + +uart0 = UART(0, 1000000) +uart0.deinit() +try: + uart0.any() +except Exception: + print('Exception') + +try: + uart0.read() +except Exception: + print('Exception') + +try: + uart0.write('abc') +except Exception: + print('Exception') + +try: + uart0.sendbreak('abc') +except Exception: + print('Exception') + +try: + UART(2, 9600) +except Exception: + print('Exception') + +for uart_id in uart_id_range: + uart = UART(uart_id, 1000000) + uart.deinit() + # test printing an unitialized uart + print(uart) + # initialize it back and check that it works again + uart.init(115200) + print(uart) + uart.read() diff --git a/src/openmv/src/micropython/tests/wipy/uart.py.exp b/src/openmv/src/micropython/tests/wipy/uart.py.exp new file mode 100755 index 0000000..c8aeb77 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/uart.py.exp @@ -0,0 +1,52 @@ +UART(0, baudrate=38400, bits=8, parity=None, stop=1) +UART(1, baudrate=38400, bits=8, parity=None, stop=1) +UART(0, baudrate=9600, bits=8, parity=None, stop=1) +UART(0, baudrate=38400, bits=8, parity=None, stop=1) +UART(0, baudrate=9600, bits=8, parity=None, stop=1) +UART(1, baudrate=9600, bits=8, parity=None, stop=1) +UART(1, baudrate=57600, bits=8, parity=None, stop=1) +UART(0, baudrate=1000000, bits=8, parity=None, stop=1) +UART(1, baudrate=1000000, bits=8, parity=None, stop=1) +True +True +True +True +True +True +True +bytearray(b'1\x00\x00') +True +bytearray(b'23\x00') +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +Pin('GP12', mode=Pin.IN, pull=None, drive=Pin.MED_POWER, alt=-1) +Pin('GP13', mode=Pin.IN, pull=None, drive=Pin.MED_POWER, alt=-1) +Exception +Exception +Exception +Exception +Exception +Exception +Exception +UART(0) +UART(0, baudrate=115200, bits=8, parity=None, stop=1) +UART(1) +UART(1, baudrate=115200, bits=8, parity=None, stop=1) diff --git a/src/openmv/src/micropython/tests/wipy/uart_irq.py b/src/openmv/src/micropython/tests/wipy/uart_irq.py new file mode 100755 index 0000000..d4cd900 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/uart_irq.py @@ -0,0 +1,148 @@ +''' +UART IRQ test for the CC3200 based boards. +''' + +from machine import UART +import os +import time + +mch = os.uname().machine +if 'LaunchPad' in mch: + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +elif 'WiPy' in mch: + uart_pins = [[('GP12', 'GP13'), ('GP12', 'GP13', 'GP7', 'GP6')], [('GP16', 'GP17'), ('GP16', 'GP17', 'GP7', 'GP6')]] +else: + raise Exception('Board not supported!') + +# just in case we have stdio duplicated on any of the uarts +os.dupterm(None) + +uart0 = UART(0, 1000000, pins=uart_pins[0][0]) +uart1 = UART(1, 1000000, pins=uart_pins[1][0]) + +uart0_int_count = 0 +uart1_int_count = 0 + +def uart0_handler (uart_o): + global uart0_irq + global uart0_int_count + if (uart0_irq.flags() & UART.RX_ANY): + uart0_int_count += 1 + +def uart1_handler (uart_o): + global uart1_irq + global uart1_int_count + if (uart1_irq.flags() & UART.RX_ANY): + uart1_int_count += 1 + +uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler) +uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler) + +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +uart1.write(b'12345') +# wait for the characters to be received +while not uart0.any(): + pass + +time.sleep_us(100) +print(uart0.any() == 5) +print(uart0_int_count > 0) +print(uart0_irq.flags() == 0) +print(uart1_irq.flags() == 0) +print(uart0.read() == b'12345') + +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# disable the interrupt +uart1_irq.disable() +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count == 0) # no interrupt triggered this time +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# enable the interrupt +uart1_irq.enable() +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count > 0) +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +uart1_irq.init(trigger=UART.RX_ANY, handler=None) # No handler +# do it again +uart1_int_count = 0 +uart0.write(b'123') +# wait for the characters to be received +while not uart1.any(): + pass + +time.sleep_us(100) +print(uart1.any() == 3) +print(uart1_int_count == 0) # no interrupt handler called +print(uart1_irq.flags() == 0) +print(uart0_irq.flags() == 0) +print(uart1.read() == b'123') + +# check for memory leaks +for i in range(0, 1000): + uart0_irq = uart0.irq(trigger=UART.RX_ANY, handler=uart0_handler) + uart1_irq = uart1.irq(trigger=UART.RX_ANY, handler=uart1_handler) + +# next ones must raise +try: + uart0_irq = uart0.irq(trigger=100, handler=uart0_handler) +except: + print('Exception') + +try: + uart0_irq = uart0.irq(trigger=0) +except: + print('Exception') + +try: + uart0_irq = uart0.irq(trigger=UART.RX_ANY, wake=Sleep.SUSPENDED) +except: + print('Exception') + +uart0_irq.disable() +uart1_irq.disable() diff --git a/src/openmv/src/micropython/tests/wipy/uart_irq.py.exp b/src/openmv/src/micropython/tests/wipy/uart_irq.py.exp new file mode 100755 index 0000000..b165e82 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/uart_irq.py.exp @@ -0,0 +1,33 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/wdt.py b/src/openmv/src/micropython/tests/wipy/wdt.py new file mode 100755 index 0000000..a894b88 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wdt.py @@ -0,0 +1,38 @@ +''' +WDT test for the CC3200 based boards +''' + +from machine import WDT +import time + +# test the invalid cases first +try: + wdt = WDT(1) +except Exception: + print("Exception") + +try: + wdt = WDT(0, 500) +except Exception: + print("Exception") + +try: + wdt = WDT(1, timeout=2000) +except Exception: + print("Exception") + +wdt = WDT(timeout=1000) +print(wdt) + +try: + wdt = WDT(0, timeout=2000) +except Exception: + print("Exception") + +time.sleep_ms(500) +wdt.feed() +print(wdt) +time.sleep_ms(900) +wdt.feed() +print(wdt) +time.sleep_ms(950) diff --git a/src/openmv/src/micropython/tests/wipy/wdt.py.exp b/src/openmv/src/micropython/tests/wipy/wdt.py.exp new file mode 100755 index 0000000..71f5e13 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wdt.py.exp @@ -0,0 +1,7 @@ +Exception +Exception +Exception + +Exception + + diff --git a/src/openmv/src/micropython/tests/wipy/wlan/machine.py b/src/openmv/src/micropython/tests/wipy/wlan/machine.py new file mode 100755 index 0000000..2ee5299 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/machine.py @@ -0,0 +1,42 @@ +''' +machine test for the CC3200 based boards. +''' + +import machine +import os +from network import WLAN + +mch = os.uname().machine +if not 'LaunchPad' in mch and not'WiPy' in mch: + raise Exception('Board not supported!') + +wifi = WLAN() + +print(machine) +machine.idle() +print(machine.freq() == (80000000,)) +print(machine.unique_id() == wifi.mac()) + +machine.main('main.py') + +rand_nums = [] +for i in range(0, 100): + rand = machine.rng() + if rand not in rand_nums: + rand_nums.append(rand) + else: + print('RNG number repeated') + break + +for i in range(0, 10): + machine.idle() + +print("Active") + +print(machine.reset_cause() >= 0) +print(machine.wake_reason() >= 0) + +try: + machine.main(123456) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/wlan/machine.py.exp b/src/openmv/src/micropython/tests/wipy/wlan/machine.py.exp new file mode 100755 index 0000000..cc5b3f6 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/machine.py.exp @@ -0,0 +1,7 @@ + +True +True +Active +True +True +Exception diff --git a/src/openmv/src/micropython/tests/wipy/wlan/server.py b/src/openmv/src/micropython/tests/wipy/wlan/server.py new file mode 100755 index 0000000..05847e3 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/server.py @@ -0,0 +1,41 @@ +''' +network server test for the CC3200 based boards. +''' + +import os +import network + +mch = os.uname().machine +if not 'LaunchPad' in mch and not'WiPy' in mch: + raise Exception('Board not supported!') + +server = network.Server() + +print(server.timeout() == 300) +print(server.isrunning() == True) +server.deinit() +print(server.isrunning() == False) + +server.init(login=('test-user', 'test-password'), timeout=60) +print(server.isrunning() == True) +print(server.timeout() == 60) + +server.deinit() +print(server.isrunning() == False) +server.init() +print(server.isrunning() == True) + +try: + server.init(1) +except: + print('Exception') + +try: + server.init(0, login=('0000000000011111111111222222222222333333', 'abc')) +except: + print('Exception') + +try: + server.timeout(1) +except: + print('Exception') diff --git a/src/openmv/src/micropython/tests/wipy/wlan/server.py.exp b/src/openmv/src/micropython/tests/wipy/wlan/server.py.exp new file mode 100755 index 0000000..a125ec9 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/server.py.exp @@ -0,0 +1,10 @@ +True +True +True +True +True +True +True +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tests/wipy/wlan/wlan.py b/src/openmv/src/micropython/tests/wipy/wlan/wlan.py new file mode 100755 index 0000000..49e2e4a --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/wlan.py @@ -0,0 +1,182 @@ +''' +WLAN test for the CC3200 based boards. +''' + +from network import WLAN +import os +import time +import testconfig + +mch = os.uname().machine +if not 'LaunchPad' in mch and not 'WiPy' in mch: + raise Exception('Board not supported!') + + +def wait_for_connection(wifi, timeout=10): + while not wifi.isconnected() and timeout > 0: + time.sleep(1) + timeout -= 1 + if wifi.isconnected(): + print('Connected') + else: + print('Connection failed!') + + +wifi = WLAN(0, WLAN.STA) +print(wifi.mode() == WLAN.STA) +print(wifi.antenna() == WLAN.INT_ANT) + +wifi = WLAN(mode=WLAN.AP) +print(wifi.mode() == WLAN.AP) +print(wifi.channel() == 1) +print(wifi.auth() == None) +print(wifi.antenna() == WLAN.INT_ANT) +wifi = WLAN(0, mode=WLAN.AP, ssid='test-wlan', auth=(WLAN.WPA, '123456abc'), channel=7) +print(wifi.mode() == WLAN.AP) +print(wifi.channel() == 7) +print(wifi.ssid() == 'test-wlan') +print(wifi.auth() == (WLAN.WPA, '123456abc')) +print(wifi.antenna() == WLAN.INT_ANT) + +wifi = WLAN(mode=WLAN.STA) +print(wifi.mode() == WLAN.STA) +time.sleep(5) # this ensures a full network scan +scan_r = wifi.scan() +print(len(scan_r) > 3) +for net in scan_r: + if net.ssid == testconfig.wlan_ssid: + # test that the scan results contains the desired params + print(len(net.bssid) == 6) + print(net.channel == None) + print(net.sec == testconfig.wlan_auth[0]) + print(net.rssi < 0) + print('Network found') + break + +wifi.mode(WLAN.STA) +print(wifi.mode() == WLAN.STA) +wifi.channel(7) +print(wifi.channel() == 7) +wifi.ssid('t-wlan') +print(wifi.ssid() == 't-wlan') +wifi.auth(None) +print(wifi.auth() == None) +wifi.auth((WLAN.WEP, '11223344556677889900')) +print(wifi.auth() == (WLAN.WEP, '11223344556677889900')) +wifi.antenna(WLAN.INT_ANT) +print(wifi.antenna() == WLAN.INT_ANT) + +wifi.antenna(WLAN.EXT_ANT) +print(wifi.antenna() == WLAN.EXT_ANT) +time.sleep(2) # this ensures a full network scan +scan_r = wifi.scan() +print(len(scan_r) > 3) +for net in scan_r: + if net.ssid == testconfig.wlan_ssid: + print('Network found') + break + +wifi.antenna(WLAN.INT_ANT) +wifi.mode(WLAN.STA) +print(wifi.mode() == WLAN.STA) +wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=10000) +wait_for_connection(wifi) + +wifi.ifconfig(config='dhcp') +wait_for_connection(wifi) +print('0.0.0.0' not in wifi.ifconfig()) +wifi.ifconfig(0, ('192.168.178.109', '255.255.255.0', '192.168.178.1', '8.8.8.8')) +wait_for_connection(wifi) +print(wifi.ifconfig(0) == ('192.168.178.109', '255.255.255.0', '192.168.178.1', '8.8.8.8')) +wait_for_connection(wifi) + +print(wifi.isconnected() == True) +wifi.disconnect() +print(wifi.isconnected() == False) + +t0 = time.ticks_ms() +wifi.connect(testconfig.wlan_ssid, auth=testconfig.wlan_auth, timeout=0) +print(time.ticks_ms() - t0 < 500) + +wifi.disconnect() +print(wifi.isconnected() == False) + +# test init again +wifi.init(WLAN.AP, ssid='www.wipy.io', auth=None, channel=5, antenna=WLAN.INT_ANT) +print(wifi.mode() == WLAN.AP) + +# get the current instance without re-init +wifi = WLAN() +print(wifi.mode() == WLAN.AP) +wifi = WLAN(0) +print(wifi.mode() == WLAN.AP) + +# test the MAC address length +print(len(wifi.mac()) == 6) + +# next ones MUST raise +try: + wifi.init(mode=12345) +except: + print('Exception') + +try: + wifi.init(1, mode=WLAN.AP) +except: + print('Exception') + +try: + wifi.init(mode=WLAN.AP, ssid=None) +except: + print('Exception') + +try: + wifi = WLAN(mode=WLAN.AP, channel=12) +except: + print('Exception') + +try: + wifi.antenna(2) +except: + print('Exception') + +try: + wifi.mode(10) +except: + print('Exception') + +try: + wifi.ssid('11111sdfasdfasdfasdf564sdf654asdfasdf123451245ssdgfsdf1111111111111111111111111234123412341234asdfasdf') +except: + print('Exception') + +try: + wifi.auth((0)) +except: + print('Exception') + +try: + wifi.auth((0, None)) +except: + print('Exception') + +try: + wifi.auth((10, 10)) +except: + print('Exception') + +try: + wifi.channel(0) +except: + print('Exception') + +try: + wifi.ifconfig(1, 'dhcp') +except: + print('Exception') + +try: + wifi.ifconfig(config=()) +except: + print('Exception') + diff --git a/src/openmv/src/micropython/tests/wipy/wlan/wlan.py.exp b/src/openmv/src/micropython/tests/wipy/wlan/wlan.py.exp new file mode 100755 index 0000000..2bb3537 --- /dev/null +++ b/src/openmv/src/micropython/tests/wipy/wlan/wlan.py.exp @@ -0,0 +1,55 @@ +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +True +Network found +True +True +True +True +True +True +True +True +Network found +True +Connected +Connected +True +Connected +True +Connected +True +True +True +True +True +True +True +True +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception diff --git a/src/openmv/src/micropython/tools/.gitattributes b/src/openmv/src/micropython/tools/.gitattributes new file mode 100755 index 0000000..9206a0b --- /dev/null +++ b/src/openmv/src/micropython/tools/.gitattributes @@ -0,0 +1 @@ +*.tar.gz binary diff --git a/src/openmv/src/micropython/tools/.gitignore b/src/openmv/src/micropython/tools/.gitignore new file mode 100755 index 0000000..9f65f49 --- /dev/null +++ b/src/openmv/src/micropython/tools/.gitignore @@ -0,0 +1,8 @@ +tinytest/.gitignore +tinytest/.travis.yml +tinytest/Makefile +tinytest/Makefile.arm-cortex-m3-qemu +tinytest/Makefile.avr +tinytest/TODO +tinytest/portable_demo.c +tinytest/tinytest_demo.c diff --git a/src/openmv/src/micropython/tools/bootstrap_upip.sh b/src/openmv/src/micropython/tools/bootstrap_upip.sh new file mode 100755 index 0000000..2891775 --- /dev/null +++ b/src/openmv/src/micropython/tools/bootstrap_upip.sh @@ -0,0 +1,30 @@ +# This script performs bootstrap installation of upip package manager from PyPI +# All the other packages can be installed using it. + +saved="$PWD" + +if [ "$1" = "" ]; then + dest=~/.micropython/lib/ +else + dest="$1" +fi + +if [ -z "$TMPDIR" ]; then + cd /tmp +else + cd $TMPDIR +fi + +# Remove any stale old version +rm -rf micropython-upip-* +wget -nd -rH -l1 -D files.pythonhosted.org https://pypi.org/project/micropython-upip/ --reject=html + +tar xfz micropython-upip-*.tar.gz +tmpd="$PWD" + +cd "$saved" +mkdir -p "$dest" +cp "$tmpd"/micropython-upip-*/upip*.py "$dest" + +echo "upip is installed. To use:" +echo "micropython -m upip --help" diff --git a/src/openmv/src/micropython/tools/build-stm-latest.sh b/src/openmv/src/micropython/tools/build-stm-latest.sh new file mode 100755 index 0000000..07cb168 --- /dev/null +++ b/src/openmv/src/micropython/tools/build-stm-latest.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# function for building firmware +function do_build() { + descr=$1 + board=$2 + shift + shift + echo "building $descr $board" + build_dir=/tmp/stm-build-$board + make -B $@ BOARD=$board BUILD=$build_dir || exit 1 + mv $build_dir/firmware.dfu $dest_dir/$descr-$date-$git_tag.dfu + rm -rf $build_dir +} + +# check/get parameters +if [ $# != 1 ]; then + echo "usage: $0 " + exit 1 +fi + +dest_dir=$1 + +# check we are in the correct directory +if [ ! -r modpyb.c ]; then + echo "must be in stm directory" + exit 1 +fi + +# get the date +date=$(date '+%Y-%m-%d') + +# get the git tag +git_tag="$(git describe --dirty || echo unknown)" + +# build the versions +do_build pybv3 PYBV3 +do_build pybv3-network PYBV3 MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1 +do_build pybv10 PYBV10 +do_build pybv10-network PYBV10 MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1 +do_build stm32f4disc STM32F4DISC +do_build espruino-pico ESPRUINO_PICO diff --git a/src/openmv/src/micropython/tools/cc1 b/src/openmv/src/micropython/tools/cc1 new file mode 100755 index 0000000..827d588 --- /dev/null +++ b/src/openmv/src/micropython/tools/cc1 @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 + +""" +This is a middle-processor for MicroPython source files. It takes the output +of the C preprocessor, has the option to change it, then feeds this into the +C compiler. + +It currently has the ability to reorder static hash tables so they are actually +hashed, resulting in faster lookup times at runtime. + +To use, configure the Python variables below, and add the following line to the +Makefile: + +CFLAGS += -no-integrated-cpp -B$(shell pwd)/../tools +""" + +import sys +import os +import re + +################################################################################ +# these are the configuration variables +# TODO somehow make them externally configurable + +# this is the path to the true C compiler +cc1_path = '/usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/cc1' +#cc1_path = '/usr/lib/gcc/arm-none-eabi/5.3.0/cc1' + +# this must be the same as MICROPY_QSTR_BYTES_IN_HASH +bytes_in_qstr_hash = 2 + +# this must be 1 or more (can be a decimal) +# larger uses more code size but yields faster lookups +table_size_mult = 1 + +# these control output during processing +print_stats = True +print_debug = False + +# end configuration variables +################################################################################ + +# precompile regexs +re_preproc_line = re.compile(r'# [0-9]+ ') +re_map_entry = re.compile(r'\{.+?\(MP_QSTR_([A-Za-z0-9_]+)\).+\},') +re_mp_obj_dict_t = re.compile(r'(?P(static )?const mp_obj_dict_t (?P[a-z0-9_]+) = \{ \.base = \{&mp_type_dict\}, \.map = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') +re_mp_map_t = re.compile(r'(?P(static )?const mp_map_t (?P[a-z0-9_]+) = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') +re_mp_rom_map_elem_t = re.compile(r'static const mp_rom_map_elem_t [a-z_0-9]+\[\] = {$') + +# this must match the equivalent function in qstr.c +def compute_hash(qstr): + hash = 5381 + for char in qstr: + hash = (hash * 33) ^ ord(char) + # Make sure that valid hash is never zero, zero means "hash not computed" + return (hash & ((1 << (8 * bytes_in_qstr_hash)) - 1)) or 1 + +# this algo must match the equivalent in map.c +def hash_insert(map, key, value): + hash = compute_hash(key) + pos = hash % len(map) + start_pos = pos + if print_debug: + print(' insert %s: start at %u/%u -- ' % (key, pos, len(map)), end='') + while True: + if map[pos] is None: + # found empty slot, so key is not in table + if print_debug: + print('put at %u' % pos) + map[pos] = (key, value) + return + else: + # not yet found, keep searching + if map[pos][0] == key: + raise AssertionError("duplicate key '%s'" % (key,)) + pos = (pos + 1) % len(map) + assert pos != start_pos + +def hash_find(map, key): + hash = compute_hash(key) + pos = hash % len(map) + start_pos = pos + attempts = 0 + while True: + attempts += 1 + if map[pos] is None: + return attempts, None + elif map[pos][0] == key: + return attempts, map[pos][1] + else: + pos = (pos + 1) % len(map) + if pos == start_pos: + return attempts, None + +def process_map_table(file, line, output): + output.append(line) + + # consume all lines that are entries of the table and concat them + # (we do it this way because there can be multiple entries on one line) + table_contents = [] + while True: + line = file.readline() + if len(line) == 0: + print('unexpected end of input') + sys.exit(1) + line = line.strip() + if len(line) == 0: + # empty line + continue + if re_preproc_line.match(line): + # preprocessor line number comment + continue + if line == '};': + # end of table (we assume it appears on a single line) + break + table_contents.append(line) + + # make combined string of entries + entries_str = ''.join(table_contents) + + # split into individual entries + entries = [] + while entries_str: + # look for single entry, by matching nested braces + match = None + if entries_str[0] == '{': + nested_braces = 0 + for i in range(len(entries_str)): + if entries_str[i] == '{': + nested_braces += 1 + elif entries_str[i] == '}': + nested_braces -= 1 + if nested_braces == 0: + match = re_map_entry.match(entries_str[:i + 2]) + break + + if not match: + print('unknown line in table:', entries_str) + sys.exit(1) + + # extract single entry + line = match.group(0) + qstr = match.group(1) + entries_str = entries_str[len(line):].lstrip() + + # add the qstr and the whole line to list of all entries + entries.append((qstr, line)) + + # sort entries so hash table construction is deterministic + entries.sort() + + # create hash table + map = [None] * int(len(entries) * table_size_mult) + for qstr, line in entries: + # We assume that qstr does not have any escape sequences in it. + # This is reasonably safe, since keys in a module or class dict + # should be standard identifiers. + # TODO verify this and raise an error if escape sequence found + hash_insert(map, qstr, line) + + # compute statistics + total_attempts = 0 + for qstr, _ in entries: + attempts, line = hash_find(map, qstr) + assert line is not None + if print_debug: + print(' %s lookup took %u attempts' % (qstr, attempts)) + total_attempts += attempts + if len(entries): + stats = len(map), len(entries) / len(map), total_attempts / len(entries) + else: + stats = 0, 0, 0 + if print_debug: + print(' table stats: size=%d, load=%.2f, avg_lookups=%.1f' % stats) + + # output hash table + for row in map: + if row is None: + output.append('{ 0, 0 },\n') + else: + output.append(row[1] + '\n') + output.append('};\n') + + # skip to next non-blank line + while True: + line = file.readline() + if len(line) == 0: + print('unexpected end of input') + sys.exit(1) + line = line.strip() + if len(line) == 0: + continue + break + + # transform the is_ordered param from 1 to 0 + match = re_mp_obj_dict_t.match(line) + if match is None: + match = re_mp_map_t.match(line) + if match is None: + print('expecting mp_obj_dict_t or mp_map_t definition') + print(output[0]) + print(line) + sys.exit(1) + line = match.group('head') + '0' + match.group('tail') + '\n' + output.append(line) + + return (match.group('id'),) + stats + +def process_file(filename): + output = [] + file_changed = False + with open(filename, 'rt') as f: + while True: + line = f.readline() + if not line: + break + if re_mp_rom_map_elem_t.match(line): + file_changed = True + stats = process_map_table(f, line, output) + if print_stats: + print(' [%s: size=%d, load=%.2f, avg_lookups=%.1f]' % stats) + else: + output.append(line) + + if file_changed: + if print_debug: + print(' modifying static maps in', output[0].strip()) + with open(filename, 'wt') as f: + for line in output: + f.write(line) + +def main(): + # run actual C compiler + # need to quote args that have special characters in them + def quote(s): + if s.find('<') != -1 or s.find('>') != -1: + return "'" + s + "'" + else: + return s + ret = os.system(cc1_path + ' ' + ' '.join(quote(s) for s in sys.argv[1:])) + if ret != 0: + ret = (ret & 0x7f) or 127 # make it in range 0-127, but non-zero + sys.exit(ret) + + if sys.argv[1] == '-E': + # CPP has been run, now do our processing stage + for i, arg in enumerate(sys.argv): + if arg == '-o': + return process_file(sys.argv[i + 1]) + + print('%s: could not find "-o" option' % (sys.argv[0],)) + sys.exit(1) + elif sys.argv[1] == '-fpreprocessed': + # compiler has been run, nothing more to do + return + else: + # unknown processing stage + print('%s: unknown first option "%s"' % (sys.argv[0], sys.argv[1])) + sys.exit(1) + +if __name__ == '__main__': + main() diff --git a/src/openmv/src/micropython/tools/check_code_size.sh b/src/openmv/src/micropython/tools/check_code_size.sh new file mode 100755 index 0000000..2925ff1 --- /dev/null +++ b/src/openmv/src/micropython/tools/check_code_size.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# This script check that changes don't lead to code size regressions. +# (Size of the language core (== minimal port should not grow)). +# + +REFERENCE=$HOME/persist/firmware.bin +#REFERENCE=/tmp/micropython +#TRAVIS_PULL_REQUEST=false + +if [ -f $REFERENCE ]; then + size_old=$(stat -c%s $REFERENCE) + size_new=$(stat -c%s ports/minimal/build/firmware.bin) + echo "Old size: $size_old new size: $size_new" + if [ $size_new -gt $size_old ]; then + echo "Validation failure: Core code size increased" + if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then + exit 1 + fi + fi +else + echo "Warning: reference file doesn't exist, code size check didn't run" +fi diff --git a/src/openmv/src/micropython/tools/codestats.sh b/src/openmv/src/micropython/tools/codestats.sh new file mode 100755 index 0000000..09284a3 --- /dev/null +++ b/src/openmv/src/micropython/tools/codestats.sh @@ -0,0 +1,187 @@ +#!/bin/sh +# +# This script generates statistics (build size, speed) for successive +# revisions of the code. It checks out git commits one an a time, compiles +# various ports to determine their size, and runs pystone on the unix port. +# Results are collected in the output file. +# +# Note: you will need to copy this file out of the tools directory before +# executing because it does not exist in old revisions of the repository. + +# check that we are in the root directory of the repository +if [ ! -d py -o ! -d ports/unix -o ! -d ports/stm32 ]; then + echo "script must be run from root of the repository" + exit 1 +fi + +# output file for the data; data is appended if file already exists +output=codestats.dat + +# utility programs +RM=/bin/rm +AWK=awk +MAKE="make -j2" + +# these are the binaries that are built; some have 2 or 3 depending on version +bin_unix=ports/unix/micropython +bin_stm32=ports/stm32/build-PYBV10/firmware.elf +bin_barearm_1=ports/bare-arm/build/flash.elf +bin_barearm_2=ports/bare-arm/build/firmware.elf +bin_minimal=ports/minimal/build/firmware.elf +bin_cc3200_1=ports/cc3200/build/LAUNCHXL/application.axf +bin_cc3200_2=ports/cc3200/build/LAUNCHXL/release/application.axf +bin_cc3200_3=ports/cc3200/build/WIPY/release/application.axf + +# start at zero size; if build fails reuse previous valid size +size_unix="0" +size_stm32="0" +size_barearm="0" +size_minimal="0" +size_cc3200="0" + +# start at zero pystones +pystones="0" + +# this code runs pystone and averages the results +pystoneavg=/tmp/pystoneavg.py +cat > $pystoneavg << EOF +import pystone +samples = [pystone.pystones(300000)[1] for i in range(5)] +samples.sort() +stones = sum(samples[1:-1]) / (len(samples) - 2) # exclude smallest and largest +print("stones %g" % stones) +EOF + +function get_size() { + if [ -r $2 ]; then + size $2 | tail -n1 | $AWK '{print $1}' + else + echo $1 + fi +} + +function get_size2() { + if [ -r $2 ]; then + size $2 | tail -n1 | $AWK '{print $1}' + elif [ -r $3 ]; then + size $3 | tail -n1 | $AWK '{print $1}' + else + echo $1 + fi +} + +function get_size3() { + if [ -r $2 ]; then + size $2 | tail -n1 | $AWK '{print $1}' + elif [ -r $3 ]; then + size $3 | tail -n1 | $AWK '{print $1}' + elif [ -r $4 ]; then + size $4 | tail -n1 | $AWK '{print $1}' + else + echo $1 + fi +} + +# get the last revision in the data file; or start at v1.0 if no file +if [ -r $output ]; then + last_rev=$(tail -n1 $output | $AWK '{print $1}') +else + echo "# hash size_unix size_stm32 size_barearm size_minimal size_cc3200 pystones" > $output + last_rev="v1.0" +fi + +# get a list of hashes between last revision (exclusive) and master +hashes=$(git log --format=format:"%H" --reverse ${last_rev}..master) +#hashes=$(git log --format=format:"%H" --reverse ${last_rev}..master | $AWK '{if (NR % 10 == 0) print $0}') # do every 10th one + +for hash in $hashes; do + + #### checkout the revision #### + + git checkout $hash + if [ $? -ne 0 ]; then + echo "aborting" + exit 1 + fi + + #### apply patches to get it to build #### + + if grep -q '#if defined(MP_CLOCKS_PER_SEC) && (MP_CLOCKS_PER_SEC == 1000000) // POSIX' unix/modtime.c; then + echo apply patch + git apply - << EOF +diff --git a/unix/modtime.c b/unix/modtime.c +index 77d2945..dae0644 100644 +--- a/unix/modtime.c ++++ b/unix/modtime.c +@@ -55,10 +55,8 @@ void msec_sleep_tv(struct timeval *tv) { + #define MP_CLOCKS_PER_SEC CLOCKS_PER_SEC + #endif + +-#if defined(MP_CLOCKS_PER_SEC) && (MP_CLOCKS_PER_SEC == 1000000) // POSIX +-#define CLOCK_DIV 1000.0 +-#elif defined(MP_CLOCKS_PER_SEC) && (MP_CLOCKS_PER_SEC == 1000) // WIN32 +-#define CLOCK_DIV 1.0 ++#if defined(MP_CLOCKS_PER_SEC) ++#define CLOCK_DIV (MP_CLOCKS_PER_SEC / 1000.0F) + #else + #error Unsupported clock() implementation + #endif +EOF + fi + + #### unix #### + + $RM $bin_unix + $MAKE -C ports/unix CFLAGS_EXTRA=-DNDEBUG + size_unix=$(get_size $size_unix $bin_unix) + + # undo patch if it was applied + git checkout unix/modtime.c + + #### stm32 #### + + $RM $bin_stm32 + $MAKE -C ports/stm32 board=PYBV10 + size_stm32=$(get_size $size_stm32 $bin_stm32) + + #### bare-arm #### + + $RM $bin_barearm_1 $bin_barearm_2 + $MAKE -C ports/bare-arm + size_barearm=$(get_size2 $size_barearm $bin_barearm_1 $bin_barearm_2) + + #### minimal #### + + if [ -r ports/minimal/Makefile ]; then + $RM $bin_minimal + $MAKE -C ports/minimal CROSS=1 + size_minimal=$(get_size $size_minimal $bin_minimal) + fi + + #### cc3200 #### + + if [ -r ports/cc3200/Makefile ]; then + $RM $bin_cc3200_1 $bin_cc3200_2 $bin_cc3200_3 + $MAKE -C ports/cc3200 BTARGET=application + size_cc3200=$(get_size3 $size_cc3200 $bin_cc3200_1 $bin_cc3200_2 $bin_cc3200_3) + fi + + #### run pystone #### + + if [ -x $bin_unix ]; then + new_pystones=$($bin_unix $pystoneavg) + # only update the variable if pystone executed successfully + if echo $new_pystones | grep -q "^stones"; then + pystones=$(echo $new_pystones | $AWK '{print $2}') + fi + fi + + #### output data for this commit #### + + echo "$hash $size_unix $size_stm32 $size_barearm $size_minimal $size_cc3200 $pystones" >> $output + +done + +# checkout master and cleanup +git checkout master +$RM $pystoneavg diff --git a/src/openmv/src/micropython/tools/dfu.py b/src/openmv/src/micropython/tools/dfu.py new file mode 100755 index 0000000..ee89c75 --- /dev/null +++ b/src/openmv/src/micropython/tools/dfu.py @@ -0,0 +1,125 @@ +#!/usr/bin/python + +# Written by Antonio Galea - 2010/11/18 +# Distributed under Gnu LGPL 3.0 +# see http://www.gnu.org/licenses/lgpl-3.0.txt + +import sys,struct,zlib,os +from optparse import OptionParser + +DEFAULT_DEVICE="0x0483:0xdf11" + +def named(tuple,names): + return dict(zip(names.split(),tuple)) +def consume(fmt,data,names): + n = struct.calcsize(fmt) + return named(struct.unpack(fmt,data[:n]),names),data[n:] +def cstring(string): + return string.split('\0',1)[0] +def compute_crc(data): + return 0xFFFFFFFF & -zlib.crc32(data) -1 + +def parse(file,dump_images=False): + print ('File: "%s"' % file) + data = open(file,'rb').read() + crc = compute_crc(data[:-4]) + prefix, data = consume('<5sBIB',data,'signature version size targets') + print ('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) + for t in range(prefix['targets']): + tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') + tprefix['num'] = t + if tprefix['named']: + tprefix['name'] = cstring(tprefix['name']) + else: + tprefix['name'] = '' + print ('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix) + tsize = tprefix['size'] + target, data = data[:tsize], data[tsize:] + for e in range(tprefix['elements']): + eprefix, target = consume('<2I',target,'address size') + eprefix['num'] = e + print (' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix) + esize = eprefix['size'] + image, target = target[:esize], target[esize:] + if dump_images: + out = '%s.target%d.image%d.bin' % (file,t,e) + open(out,'wb').write(image) + print (' DUMPED IMAGE TO "%s"' % out) + if len(target): + print ("target %d: PARSE ERROR" % t) + suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') + print ('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix) + if crc != suffix['crc']: + print ("CRC ERROR: computed crc32 is 0x%08x" % crc) + data = data[16:] + if data: + print ("PARSE ERROR") + +def build(file,targets,device=DEFAULT_DEVICE): + data = b'' + for t,target in enumerate(targets): + tdata = b'' + for image in target: + # pad image to 8 bytes (needed at least for L476) + pad = (8 - len(image['data']) % 8 ) % 8 + image['data'] = image['data'] + bytes(bytearray(8)[0:pad]) + # + tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] + tdata = struct.pack('<6sBI255s2I',b'Target',0,1, b'ST...',len(tdata),len(target)) + tdata + data += tdata + data = struct.pack('<5sBIB',b'DfuSe',1,len(data)+11,len(targets)) + data + v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) + data += struct.pack('<4H3sB',0,d,v,0x011a,b'UFD',16) + crc = compute_crc(data) + data += struct.pack('= len(class_) or section[i] != class_[i]: + if i == 0: + filename = section[i].replace(' ', '_').lower() + rst = open(DOCPATH + filename + '.rst', 'w') + rst.write(HEADER) + rst.write(section[i] + '\n') + rst.write(RSTCHARS[0] * len(section[i])) + rst.write(time.strftime("\nGenerated %a %d %b %Y %X UTC\n\n", time.gmtime())) + toctree.append(filename) + else: + rst.write(section[i] + '\n') + rst.write(RSTCHARS[min(i, len(RSTCHARS)-1)] * len(section[i])) + rst.write('\n\n') + class_ = section + rst.write('.. _cpydiff_%s:\n\n' % output.name.rsplit('.', 1)[0]) + rst.write(output.desc + '\n') + rst.write('~' * len(output.desc) + '\n\n') + if output.cause != 'Unknown': + rst.write('**Cause:** ' + output.cause + '\n\n') + if output.workaround != 'Unknown': + rst.write('**Workaround:** ' + output.workaround + '\n\n') + + rst.write('Sample code::\n\n' + indent(output.code, TAB) + '\n') + output_cpy = indent(''.join(output.output_cpy[0:2]), TAB).rstrip() + output_cpy = ('::\n\n' if output_cpy != '' else '') + output_cpy + output_upy = indent(''.join(output.output_upy[0:2]), TAB).rstrip() + output_upy = ('::\n\n' if output_upy != '' else '') + output_upy + table = gen_table([['CPy output:', output_cpy], ['uPy output:', output_upy]]) + rst.write(table) + + template = open(INDEXTEMPLATE, 'r') + index = open(DOCPATH + INDEX, 'w') + index.write(HEADER) + index.write(template.read()) + for section in INDEXPRIORITY: + if section in toctree: + index.write(indent(section + '.rst', TAB)) + toctree.remove(section) + for section in toctree: + index.write(indent(section + '.rst', TAB)) + +def main(): + """ Main function """ + + # set search path so that test scripts find the test modules (and no other ones) + os.environ['PYTHONPATH'] = TESTPATH + os.environ['MICROPYPATH'] = TESTPATH + + files = readfiles() + results = run_tests(files) + gen_rst(results) + +main() diff --git a/src/openmv/src/micropython/tools/gendoc.py b/src/openmv/src/micropython/tools/gendoc.py new file mode 100755 index 0000000..61844d2 --- /dev/null +++ b/src/openmv/src/micropython/tools/gendoc.py @@ -0,0 +1,528 @@ +""" +Generate documentation for pyboard API from C files. +""" + +import os +import argparse +import re +import markdown + +# given a list of (name,regex) pairs, find the first one that matches the given line +def re_match_first(regexs, line): + for name, regex in regexs: + match = re.match(regex, line) + if match: + return name, match + return None, None + +def makedirs(d): + if not os.path.isdir(d): + os.makedirs(d) + +class Lexer: + class LexerError(Exception): + pass + + class EOF(Exception): + pass + + class Break(Exception): + pass + + def __init__(self, file): + self.filename = file + with open(file, 'rt') as f: + line_num = 0 + lines = [] + for line in f: + line_num += 1 + line = line.strip() + if line == '///': + lines.append((line_num, '')) + elif line.startswith('/// '): + lines.append((line_num, line[4:])) + elif len(lines) > 0 and lines[-1][1] is not None: + lines.append((line_num, None)) + if len(lines) > 0 and lines[-1][1] is not None: + lines.append((line_num, None)) + self.cur_line = 0 + self.lines = lines + + def opt_break(self): + if len(self.lines) > 0 and self.lines[0][1] is None: + self.lines.pop(0) + + def next(self): + if len(self.lines) == 0: + raise Lexer.EOF + else: + l = self.lines.pop(0) + self.cur_line = l[0] + if l[1] is None: + raise Lexer.Break + else: + return l[1] + + def error(self, msg): + print('({}:{}) {}'.format(self.filename, self.cur_line, msg)) + raise Lexer.LexerError + +class MarkdownWriter: + def __init__(self): + pass + + def start(self): + self.lines = [] + + def end(self): + return '\n'.join(self.lines) + + def heading(self, level, text): + if len(self.lines) > 0: + self.lines.append('') + self.lines.append(level * '#' + ' ' + text) + self.lines.append('') + + def para(self, text): + if len(self.lines) > 0 and self.lines[-1] != '': + self.lines.append('') + if isinstance(text, list): + self.lines.extend(text) + elif isinstance(text, str): + self.lines.append(text) + else: + assert False + self.lines.append('') + + def single_line(self, text): + self.lines.append(text) + + def module(self, name, short_descr, descr): + self.heading(1, 'module {}'.format(name)) + self.para(descr) + + def function(self, ctx, name, args, descr): + proto = '{}.{}{}'.format(ctx, self.name, self.args) + self.heading(3, '`' + proto + '`') + self.para(descr) + + def method(self, ctx, name, args, descr): + if name == '\\constructor': + proto = '{}{}'.format(ctx, args) + elif name == '\\call': + proto = '{}{}'.format(ctx, args) + else: + proto = '{}.{}{}'.format(ctx, name, args) + self.heading(3, '`' + proto + '`') + self.para(descr) + + def constant(self, ctx, name, descr): + self.single_line('`{}.{}` - {}'.format(ctx, name, descr)) + +class ReStructuredTextWriter: + head_chars = {1:'=', 2:'-', 3:'.'} + + def __init__(self): + pass + + def start(self): + self.lines = [] + + def end(self): + return '\n'.join(self.lines) + + def _convert(self, text): + return text.replace('`', '``').replace('*', '\\*') + + def heading(self, level, text, convert=True): + if len(self.lines) > 0: + self.lines.append('') + if convert: + text = self._convert(text) + self.lines.append(text) + self.lines.append(len(text) * self.head_chars[level]) + self.lines.append('') + + def para(self, text, indent=''): + if len(self.lines) > 0 and self.lines[-1] != '': + self.lines.append('') + if isinstance(text, list): + for t in text: + self.lines.append(indent + self._convert(t)) + elif isinstance(text, str): + self.lines.append(indent + self._convert(text)) + else: + assert False + self.lines.append('') + + def single_line(self, text): + self.lines.append(self._convert(text)) + + def module(self, name, short_descr, descr): + self.heading(1, ':mod:`{}` --- {}'.format(name, self._convert(short_descr)), convert=False) + self.lines.append('.. module:: {}'.format(name)) + self.lines.append(' :synopsis: {}'.format(short_descr)) + self.para(descr) + + def function(self, ctx, name, args, descr): + args = self._convert(args) + self.lines.append('.. function:: ' + name + args) + self.para(descr, indent=' ') + + def method(self, ctx, name, args, descr): + args = self._convert(args) + if name == '\\constructor': + self.lines.append('.. class:: ' + ctx + args) + elif name == '\\call': + self.lines.append('.. method:: ' + ctx + args) + else: + self.lines.append('.. method:: ' + ctx + '.' + name + args) + self.para(descr, indent=' ') + + def constant(self, ctx, name, descr): + self.lines.append('.. data:: ' + name) + self.para(descr, indent=' ') + +class DocValidateError(Exception): + pass + +class DocItem: + def __init__(self): + self.doc = [] + + def add_doc(self, lex): + try: + while True: + line = lex.next() + if len(line) > 0 or len(self.doc) > 0: + self.doc.append(line) + except Lexer.Break: + pass + + def dump(self, writer): + writer.para(self.doc) + +class DocConstant(DocItem): + def __init__(self, name, descr): + super().__init__() + self.name = name + self.descr = descr + + def dump(self, ctx, writer): + writer.constant(ctx, self.name, self.descr) + +class DocFunction(DocItem): + def __init__(self, name, args): + super().__init__() + self.name = name + self.args = args + + def dump(self, ctx, writer): + writer.function(ctx, self.name, self.args, self.doc) + +class DocMethod(DocItem): + def __init__(self, name, args): + super().__init__() + self.name = name + self.args = args + + def dump(self, ctx, writer): + writer.method(ctx, self.name, self.args, self.doc) + +class DocClass(DocItem): + def __init__(self, name, descr): + super().__init__() + self.name = name + self.descr = descr + self.constructors = {} + self.classmethods = {} + self.methods = {} + self.constants = {} + + def process_classmethod(self, lex, d): + name = d['id'] + if name == '\\constructor': + dict_ = self.constructors + else: + dict_ = self.classmethods + if name in dict_: + lex.error("multiple definition of method '{}'".format(name)) + method = dict_[name] = DocMethod(name, d['args']) + method.add_doc(lex) + + def process_method(self, lex, d): + name = d['id'] + dict_ = self.methods + if name in dict_: + lex.error("multiple definition of method '{}'".format(name)) + method = dict_[name] = DocMethod(name, d['args']) + method.add_doc(lex) + + def process_constant(self, lex, d): + name = d['id'] + if name in self.constants: + lex.error("multiple definition of constant '{}'".format(name)) + self.constants[name] = DocConstant(name, d['descr']) + lex.opt_break() + + def dump(self, writer): + writer.heading(1, 'class {}'.format(self.name)) + super().dump(writer) + if len(self.constructors) > 0: + writer.heading(2, 'Constructors') + for f in sorted(self.constructors.values(), key=lambda x:x.name): + f.dump(self.name, writer) + if len(self.classmethods) > 0: + writer.heading(2, 'Class methods') + for f in sorted(self.classmethods.values(), key=lambda x:x.name): + f.dump(self.name, writer) + if len(self.methods) > 0: + writer.heading(2, 'Methods') + for f in sorted(self.methods.values(), key=lambda x:x.name): + f.dump(self.name.lower(), writer) + if len(self.constants) > 0: + writer.heading(2, 'Constants') + for c in sorted(self.constants.values(), key=lambda x:x.name): + c.dump(self.name, writer) + +class DocModule(DocItem): + def __init__(self, name, descr): + super().__init__() + self.name = name + self.descr = descr + self.functions = {} + self.constants = {} + self.classes = {} + self.cur_class = None + + def new_file(self): + self.cur_class = None + + def process_function(self, lex, d): + name = d['id'] + if name in self.functions: + lex.error("multiple definition of function '{}'".format(name)) + function = self.functions[name] = DocFunction(name, d['args']) + function.add_doc(lex) + + #def process_classref(self, lex, d): + # name = d['id'] + # self.classes[name] = name + # lex.opt_break() + + def process_class(self, lex, d): + name = d['id'] + if name in self.classes: + lex.error("multiple definition of class '{}'".format(name)) + self.cur_class = self.classes[name] = DocClass(name, d['descr']) + self.cur_class.add_doc(lex) + + def process_classmethod(self, lex, d): + self.cur_class.process_classmethod(lex, d) + + def process_method(self, lex, d): + self.cur_class.process_method(lex, d) + + def process_constant(self, lex, d): + if self.cur_class is None: + # a module-level constant + name = d['id'] + if name in self.constants: + lex.error("multiple definition of constant '{}'".format(name)) + self.constants[name] = DocConstant(name, d['descr']) + lex.opt_break() + else: + # a class-level constant + self.cur_class.process_constant(lex, d) + + def validate(self): + if self.descr is None: + raise DocValidateError('module {} referenced but never defined'.format(self.name)) + + def dump(self, writer): + writer.module(self.name, self.descr, self.doc) + if self.functions: + writer.heading(2, 'Functions') + for f in sorted(self.functions.values(), key=lambda x:x.name): + f.dump(self.name, writer) + if self.constants: + writer.heading(2, 'Constants') + for c in sorted(self.constants.values(), key=lambda x:x.name): + c.dump(self.name, writer) + if self.classes: + writer.heading(2, 'Classes') + for c in sorted(self.classes.values(), key=lambda x:x.name): + writer.para('[`{}.{}`]({}) - {}'.format(self.name, c.name, c.name, c.descr)) + + def write_html(self, dir): + md_writer = MarkdownWriter() + md_writer.start() + self.dump(md_writer) + with open(os.path.join(dir, 'index.html'), 'wt') as f: + f.write(markdown.markdown(md_writer.end())) + for c in self.classes.values(): + class_dir = os.path.join(dir, c.name) + makedirs(class_dir) + md_writer.start() + md_writer.para('part of the [{} module](./)'.format(self.name)) + c.dump(md_writer) + with open(os.path.join(class_dir, 'index.html'), 'wt') as f: + f.write(markdown.markdown(md_writer.end())) + + def write_rst(self, dir): + rst_writer = ReStructuredTextWriter() + rst_writer.start() + self.dump(rst_writer) + with open(dir + '/' + self.name + '.rst', 'wt') as f: + f.write(rst_writer.end()) + for c in self.classes.values(): + rst_writer.start() + c.dump(rst_writer) + with open(dir + '/' + self.name + '.' + c.name + '.rst', 'wt') as f: + f.write(rst_writer.end()) + +class Doc: + def __init__(self): + self.modules = {} + self.cur_module = None + + def new_file(self): + self.cur_module = None + for m in self.modules.values(): + m.new_file() + + def check_module(self, lex): + if self.cur_module is None: + lex.error('module not defined') + + def process_module(self, lex, d): + name = d['id'] + if name not in self.modules: + self.modules[name] = DocModule(name, None) + self.cur_module = self.modules[name] + if self.cur_module.descr is not None: + lex.error("multiple definition of module '{}'".format(name)) + self.cur_module.descr = d['descr'] + self.cur_module.add_doc(lex) + + def process_moduleref(self, lex, d): + name = d['id'] + if name not in self.modules: + self.modules[name] = DocModule(name, None) + self.cur_module = self.modules[name] + lex.opt_break() + + def process_class(self, lex, d): + self.check_module(lex) + self.cur_module.process_class(lex, d) + + def process_function(self, lex, d): + self.check_module(lex) + self.cur_module.process_function(lex, d) + + def process_classmethod(self, lex, d): + self.check_module(lex) + self.cur_module.process_classmethod(lex, d) + + def process_method(self, lex, d): + self.check_module(lex) + self.cur_module.process_method(lex, d) + + def process_constant(self, lex, d): + self.check_module(lex) + self.cur_module.process_constant(lex, d) + + def validate(self): + for m in self.modules.values(): + m.validate() + + def dump(self, writer): + writer.heading(1, 'Modules') + writer.para('These are the Python modules that are implemented.') + for m in sorted(self.modules.values(), key=lambda x:x.name): + writer.para('[`{}`]({}/) - {}'.format(m.name, m.name, m.descr)) + + def write_html(self, dir): + md_writer = MarkdownWriter() + with open(os.path.join(dir, 'module', 'index.html'), 'wt') as f: + md_writer.start() + self.dump(md_writer) + f.write(markdown.markdown(md_writer.end())) + for m in self.modules.values(): + mod_dir = os.path.join(dir, 'module', m.name) + makedirs(mod_dir) + m.write_html(mod_dir) + + def write_rst(self, dir): + #with open(os.path.join(dir, 'module', 'index.html'), 'wt') as f: + # f.write(markdown.markdown(self.dump())) + for m in self.modules.values(): + m.write_rst(dir) + +regex_descr = r'(?P.*)' + +doc_regexs = ( + (Doc.process_module, re.compile(r'\\module (?P[a-z][a-z0-9]*) - ' + regex_descr + r'$')), + (Doc.process_moduleref, re.compile(r'\\moduleref (?P[a-z]+)$')), + (Doc.process_function, re.compile(r'\\function (?P[a-z0-9_]+)(?P\(.*\))$')), + (Doc.process_classmethod, re.compile(r'\\classmethod (?P\\?[a-z0-9_]+)(?P\(.*\))$')), + (Doc.process_method, re.compile(r'\\method (?P\\?[a-z0-9_]+)(?P\(.*\))$')), + (Doc.process_constant, re.compile(r'\\constant (?P[A-Za-z0-9_]+) - ' + regex_descr + r'$')), + #(Doc.process_classref, re.compile(r'\\classref (?P[A-Za-z0-9_]+)$')), + (Doc.process_class, re.compile(r'\\class (?P[A-Za-z0-9_]+) - ' + regex_descr + r'$')), +) + +def process_file(file, doc): + lex = Lexer(file) + doc.new_file() + try: + try: + while True: + line = lex.next() + fun, match = re_match_first(doc_regexs, line) + if fun == None: + lex.error('unknown line format: {}'.format(line)) + fun(doc, lex, match.groupdict()) + + except Lexer.Break: + lex.error('unexpected break') + + except Lexer.EOF: + pass + + except Lexer.LexerError: + return False + + return True + +def main(): + cmd_parser = argparse.ArgumentParser(description='Generate documentation for pyboard API from C files.') + cmd_parser.add_argument('--outdir', metavar='', default='gendoc-out', help='ouput directory') + cmd_parser.add_argument('--format', default='html', help='output format: html or rst') + cmd_parser.add_argument('files', nargs='+', help='input files') + args = cmd_parser.parse_args() + + doc = Doc() + for file in args.files: + print('processing', file) + if not process_file(file, doc): + return + try: + doc.validate() + except DocValidateError as e: + print(e) + + makedirs(args.outdir) + + if args.format == 'html': + doc.write_html(args.outdir) + elif args.format == 'rst': + doc.write_rst(args.outdir) + else: + print('unknown format:', args.format) + return + + print('written to', args.outdir) + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/tools/insert-usb-ids.py b/src/openmv/src/micropython/tools/insert-usb-ids.py new file mode 100755 index 0000000..cdccd3b --- /dev/null +++ b/src/openmv/src/micropython/tools/insert-usb-ids.py @@ -0,0 +1,34 @@ +# Reads the USB VID and PID from the file specified by sys.argv[1] and then +# inserts those values into the template file specified by sys.argv[2], +# printing the result to stdout + +from __future__ import print_function + +import sys +import re +import string + +needed_keys = ('USB_PID_CDC_MSC', 'USB_PID_CDC_HID', 'USB_PID_CDC', 'USB_VID') + +def parse_usb_ids(filename): + rv = dict() + for line in open(filename).readlines(): + line = line.rstrip('\r\n') + match = re.match('^#define\s+(\w+)\s+\(0x([0-9A-Fa-f]+)\)$', line) + if match and match.group(1).startswith('USBD_'): + key = match.group(1).replace('USBD', 'USB') + val = match.group(2) + print("key =", key, "val =", val) + if key in needed_keys: + rv[key] = val + for k in needed_keys: + if k not in rv: + raise Exception("Unable to parse %s from %s" % (k, filename)) + return rv + +if __name__ == "__main__": + usb_ids_file = sys.argv[1] + template_file = sys.argv[2] + replacements = parse_usb_ids(usb_ids_file) + for line in open(template_file, 'r').readlines(): + print(string.Template(line).safe_substitute(replacements), end='') diff --git a/src/openmv/src/micropython/tools/make-frozen.py b/src/openmv/src/micropython/tools/make-frozen.py new file mode 100755 index 0000000..1051b52 --- /dev/null +++ b/src/openmv/src/micropython/tools/make-frozen.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# Create frozen modules structure for MicroPython. +# +# Usage: +# +# Have a directory with modules to be frozen (only modules, not packages +# supported so far): +# +# frozen/foo.py +# frozen/bar.py +# +# Run script, passing path to the directory above: +# +# ./make-frozen.py frozen > frozen.c +# +# Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN_STR in +# config. +# +from __future__ import print_function +import sys +import os + + +def module_name(f): + return f + +modules = [] + +root = sys.argv[1].rstrip("/") +root_len = len(root) + +for dirpath, dirnames, filenames in os.walk(root): + for f in filenames: + fullpath = dirpath + "/" + f + st = os.stat(fullpath) + modules.append((fullpath[root_len + 1:], st)) + +print("#include ") +print("const char mp_frozen_str_names[] = {") +for f, st in modules: + m = module_name(f) + print('"%s\\0"' % m) +print('"\\0"};') + +print("const uint32_t mp_frozen_str_sizes[] = {") + +for f, st in modules: + print("%d," % st.st_size) + +print("};") + +print("const char mp_frozen_str_content[] = {") +for f, st in modules: + data = open(sys.argv[1] + "/" + f, "rb").read() + + # We need to properly escape the script data to create a C string. + # When C parses hex characters of the form \x00 it keeps parsing the hex + # data until it encounters a non-hex character. Thus one must create + # strings of the form "data\x01" "abc" to properly encode this kind of + # data. We could just encode all characters as hex digits but it's nice + # to be able to read the resulting C code as ASCII when possible. + + data = bytearray(data) # so Python2 extracts each byte as an integer + esc_dict = {ord('\n'): '\\n', ord('\r'): '\\r', ord('"'): '\\"', ord('\\'): '\\\\'} + chrs = ['"'] + break_str = False + for c in data: + try: + chrs.append(esc_dict[c]) + except KeyError: + if 32 <= c <= 126: + if break_str: + chrs.append('" "') + break_str = False + chrs.append(chr(c)) + else: + chrs.append('\\x%02x' % c) + break_str = True + chrs.append('\\0"') + print(''.join(chrs)) + +print("};") diff --git a/src/openmv/src/micropython/tools/mpy-tool.py b/src/openmv/src/micropython/tools/mpy-tool.py new file mode 100755 index 0000000..c667bd0 --- /dev/null +++ b/src/openmv/src/micropython/tools/mpy-tool.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Damien P. George +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Python 2/3 compatibility code +from __future__ import print_function +import platform +if platform.python_version_tuple()[0] == '2': + str_cons = lambda val, enc=None: val + bytes_cons = lambda val, enc=None: bytearray(val) + is_str_type = lambda o: type(o) is str + is_bytes_type = lambda o: type(o) is bytearray + is_int_type = lambda o: type(o) is int or type(o) is long +else: + str_cons = str + bytes_cons = bytes + is_str_type = lambda o: type(o) is str + is_bytes_type = lambda o: type(o) is bytes + is_int_type = lambda o: type(o) is int +# end compatibility code + +import sys +import struct +from collections import namedtuple + +sys.path.append(sys.path[0] + '/../py') +import makeqstrdata as qstrutil + +class FreezeError(Exception): + def __init__(self, rawcode, msg): + self.rawcode = rawcode + self.msg = msg + + def __str__(self): + return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg) + +class Config: + MPY_VERSION = 3 + MICROPY_LONGINT_IMPL_NONE = 0 + MICROPY_LONGINT_IMPL_LONGLONG = 1 + MICROPY_LONGINT_IMPL_MPZ = 2 +config = Config() + +MP_OPCODE_BYTE = 0 +MP_OPCODE_QSTR = 1 +MP_OPCODE_VAR_UINT = 2 +MP_OPCODE_OFFSET = 3 + +# extra bytes: +MP_BC_MAKE_CLOSURE = 0x62 +MP_BC_MAKE_CLOSURE_DEFARGS = 0x63 +MP_BC_RAISE_VARARGS = 0x5c +# extra byte if caching enabled: +MP_BC_LOAD_NAME = 0x1c +MP_BC_LOAD_GLOBAL = 0x1d +MP_BC_LOAD_ATTR = 0x1e +MP_BC_STORE_ATTR = 0x26 + +def make_opcode_format(): + def OC4(a, b, c, d): + return a | (b << 2) | (c << 4) | (d << 6) + U = 0 + B = 0 + Q = 1 + V = 2 + O = 3 + return bytes_cons(( + # this table is taken verbatim from py/bc.c + OC4(U, U, U, U), # 0x00-0x03 + OC4(U, U, U, U), # 0x04-0x07 + OC4(U, U, U, U), # 0x08-0x0b + OC4(U, U, U, U), # 0x0c-0x0f + OC4(B, B, B, U), # 0x10-0x13 + OC4(V, U, Q, V), # 0x14-0x17 + OC4(B, V, V, Q), # 0x18-0x1b + OC4(Q, Q, Q, Q), # 0x1c-0x1f + OC4(B, B, V, V), # 0x20-0x23 + OC4(Q, Q, Q, B), # 0x24-0x27 + OC4(V, V, Q, Q), # 0x28-0x2b + OC4(U, U, U, U), # 0x2c-0x2f + OC4(B, B, B, B), # 0x30-0x33 + OC4(B, O, O, O), # 0x34-0x37 + OC4(O, O, U, U), # 0x38-0x3b + OC4(U, O, B, O), # 0x3c-0x3f + OC4(O, B, B, O), # 0x40-0x43 + OC4(B, B, O, B), # 0x44-0x47 + OC4(U, U, U, U), # 0x48-0x4b + OC4(U, U, U, U), # 0x4c-0x4f + OC4(V, V, U, V), # 0x50-0x53 + OC4(B, U, V, V), # 0x54-0x57 + OC4(V, V, V, B), # 0x58-0x5b + OC4(B, B, B, U), # 0x5c-0x5f + OC4(V, V, V, V), # 0x60-0x63 + OC4(V, V, V, V), # 0x64-0x67 + OC4(Q, Q, B, U), # 0x68-0x6b + OC4(U, U, U, U), # 0x6c-0x6f + + OC4(B, B, B, B), # 0x70-0x73 + OC4(B, B, B, B), # 0x74-0x77 + OC4(B, B, B, B), # 0x78-0x7b + OC4(B, B, B, B), # 0x7c-0x7f + OC4(B, B, B, B), # 0x80-0x83 + OC4(B, B, B, B), # 0x84-0x87 + OC4(B, B, B, B), # 0x88-0x8b + OC4(B, B, B, B), # 0x8c-0x8f + OC4(B, B, B, B), # 0x90-0x93 + OC4(B, B, B, B), # 0x94-0x97 + OC4(B, B, B, B), # 0x98-0x9b + OC4(B, B, B, B), # 0x9c-0x9f + OC4(B, B, B, B), # 0xa0-0xa3 + OC4(B, B, B, B), # 0xa4-0xa7 + OC4(B, B, B, B), # 0xa8-0xab + OC4(B, B, B, B), # 0xac-0xaf + + OC4(B, B, B, B), # 0xb0-0xb3 + OC4(B, B, B, B), # 0xb4-0xb7 + OC4(B, B, B, B), # 0xb8-0xbb + OC4(B, B, B, B), # 0xbc-0xbf + + OC4(B, B, B, B), # 0xc0-0xc3 + OC4(B, B, B, B), # 0xc4-0xc7 + OC4(B, B, B, B), # 0xc8-0xcb + OC4(B, B, B, B), # 0xcc-0xcf + + OC4(B, B, B, B), # 0xd0-0xd3 + OC4(U, U, U, B), # 0xd4-0xd7 + OC4(B, B, B, B), # 0xd8-0xdb + OC4(B, B, B, B), # 0xdc-0xdf + + OC4(B, B, B, B), # 0xe0-0xe3 + OC4(B, B, B, B), # 0xe4-0xe7 + OC4(B, B, B, B), # 0xe8-0xeb + OC4(B, B, B, B), # 0xec-0xef + + OC4(B, B, B, B), # 0xf0-0xf3 + OC4(B, B, B, B), # 0xf4-0xf7 + OC4(U, U, U, U), # 0xf8-0xfb + OC4(U, U, U, U), # 0xfc-0xff + )) + +# this function mirrors that in py/bc.c +def mp_opcode_format(bytecode, ip, opcode_format=make_opcode_format()): + opcode = bytecode[ip] + ip_start = ip + f = (opcode_format[opcode >> 2] >> (2 * (opcode & 3))) & 3 + if f == MP_OPCODE_QSTR: + ip += 3 + else: + extra_byte = ( + opcode == MP_BC_RAISE_VARARGS + or opcode == MP_BC_MAKE_CLOSURE + or opcode == MP_BC_MAKE_CLOSURE_DEFARGS + or config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE and ( + opcode == MP_BC_LOAD_NAME + or opcode == MP_BC_LOAD_GLOBAL + or opcode == MP_BC_LOAD_ATTR + or opcode == MP_BC_STORE_ATTR + ) + ) + ip += 1 + if f == MP_OPCODE_VAR_UINT: + while bytecode[ip] & 0x80 != 0: + ip += 1 + ip += 1 + elif f == MP_OPCODE_OFFSET: + ip += 2 + ip += extra_byte + return f, ip - ip_start + +def decode_uint(bytecode, ip): + unum = 0 + while True: + val = bytecode[ip] + ip += 1 + unum = (unum << 7) | (val & 0x7f) + if not (val & 0x80): + break + return ip, unum + +def extract_prelude(bytecode): + ip = 0 + ip, n_state = decode_uint(bytecode, ip) + ip, n_exc_stack = decode_uint(bytecode, ip) + scope_flags = bytecode[ip]; ip += 1 + n_pos_args = bytecode[ip]; ip += 1 + n_kwonly_args = bytecode[ip]; ip += 1 + n_def_pos_args = bytecode[ip]; ip += 1 + ip2, code_info_size = decode_uint(bytecode, ip) + ip += code_info_size + while bytecode[ip] != 0xff: + ip += 1 + ip += 1 + # ip now points to first opcode + # ip2 points to simple_name qstr + return ip, ip2, (n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args, code_info_size) + +class RawCode: + # a set of all escaped names, to make sure they are unique + escaped_names = set() + + def __init__(self, bytecode, qstrs, objs, raw_codes): + # set core variables + self.bytecode = bytecode + self.qstrs = qstrs + self.objs = objs + self.raw_codes = raw_codes + + # extract prelude + self.ip, self.ip2, self.prelude = extract_prelude(self.bytecode) + self.simple_name = self._unpack_qstr(self.ip2) + self.source_file = self._unpack_qstr(self.ip2 + 2) + + def _unpack_qstr(self, ip): + qst = self.bytecode[ip] | self.bytecode[ip + 1] << 8 + return global_qstrs[qst] + + def dump(self): + # dump children first + for rc in self.raw_codes: + rc.freeze('') + # TODO + + def freeze(self, parent_name): + self.escaped_name = parent_name + self.simple_name.qstr_esc + + # make sure the escaped name is unique + i = 2 + while self.escaped_name in RawCode.escaped_names: + self.escaped_name = parent_name + self.simple_name.qstr_esc + str(i) + i += 1 + RawCode.escaped_names.add(self.escaped_name) + + # emit children first + for rc in self.raw_codes: + rc.freeze(self.escaped_name + '_') + + # generate bytecode data + print() + print('// frozen bytecode for file %s, scope %s%s' % (self.source_file.str, parent_name, self.simple_name.str)) + print('STATIC ', end='') + if not config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: + print('const ', end='') + print('byte bytecode_data_%s[%u] = {' % (self.escaped_name, len(self.bytecode))) + print(' ', end='') + for i in range(self.ip2): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + print(' ', self.simple_name.qstr_id, '& 0xff,', self.simple_name.qstr_id, '>> 8,') + print(' ', self.source_file.qstr_id, '& 0xff,', self.source_file.qstr_id, '>> 8,') + print(' ', end='') + for i in range(self.ip2 + 4, self.ip): + print(' 0x%02x,' % self.bytecode[i], end='') + print() + ip = self.ip + while ip < len(self.bytecode): + f, sz = mp_opcode_format(self.bytecode, ip) + if f == 1: + qst = self._unpack_qstr(ip + 1).qstr_id + print(' ', '0x%02x,' % self.bytecode[ip], qst, '& 0xff,', qst, '>> 8,') + else: + print(' ', ''.join('0x%02x, ' % self.bytecode[ip + i] for i in range(sz))) + ip += sz + print('};') + + # generate constant objects + for i, obj in enumerate(self.objs): + obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) + if obj is Ellipsis: + print('#define %s mp_const_ellipsis_obj' % obj_name) + elif is_str_type(obj) or is_bytes_type(obj): + if is_str_type(obj): + obj = bytes_cons(obj, 'utf8') + obj_type = 'mp_type_str' + else: + obj_type = 'mp_type_bytes' + print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' + % (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), + len(obj), ''.join(('\\x%02x' % b) for b in obj))) + elif is_int_type(obj): + if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: + # TODO check if we can actually fit this long-int into a small-int + raise FreezeError(self, 'target does not support long int') + elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG: + # TODO + raise FreezeError(self, 'freezing int to long-long is not implemented') + elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: + neg = 0 + if obj < 0: + obj = -obj + neg = 1 + bits_per_dig = config.MPZ_DIG_SIZE + digs = [] + z = obj + while z: + digs.append(z & ((1 << bits_per_dig) - 1)) + z >>= bits_per_dig + ndigs = len(digs) + digs = ','.join(('%#x' % d) for d in digs) + print('STATIC const mp_obj_int_t %s = {{&mp_type_int}, ' + '{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t*)(const uint%u_t[]){%s}}};' + % (obj_name, neg, ndigs, ndigs, bits_per_dig, bits_per_dig, digs)) + elif type(obj) is float: + print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') + print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' + % (obj_name, obj)) + print('#endif') + elif type(obj) is complex: + print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' + % (obj_name, obj.real, obj.imag)) + else: + raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) + + # generate constant table, if it has any entries + const_table_len = len(self.qstrs) + len(self.objs) + len(self.raw_codes) + if const_table_len: + print('STATIC const mp_rom_obj_t const_table_data_%s[%u] = {' + % (self.escaped_name, const_table_len)) + for qst in self.qstrs: + print(' MP_ROM_QSTR(%s),' % global_qstrs[qst].qstr_id) + for i in range(len(self.objs)): + if type(self.objs[i]) is float: + print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') + print(' MP_ROM_PTR(&const_obj_%s_%u),' % (self.escaped_name, i)) + print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') + n = struct.unpack('> 8 + +def read_bytecode_qstrs(file, bytecode, ip): + while ip < len(bytecode): + f, sz = mp_opcode_format(bytecode, ip) + if f == 1: + read_qstr_and_pack(file, bytecode, ip + 1) + ip += sz + +def read_raw_code(f): + bc_len = read_uint(f) + bytecode = bytearray(f.read(bc_len)) + ip, ip2, prelude = extract_prelude(bytecode) + read_qstr_and_pack(f, bytecode, ip2) # simple_name + read_qstr_and_pack(f, bytecode, ip2 + 2) # source_file + read_bytecode_qstrs(f, bytecode, ip) + n_obj = read_uint(f) + n_raw_code = read_uint(f) + qstrs = [read_qstr(f) for _ in range(prelude[3] + prelude[4])] + objs = [read_obj(f) for _ in range(n_obj)] + raw_codes = [read_raw_code(f) for _ in range(n_raw_code)] + return RawCode(bytecode, qstrs, objs, raw_codes) + +def read_mpy(filename): + with open(filename, 'rb') as f: + header = bytes_cons(f.read(4)) + if header[0] != ord('M'): + raise Exception('not a valid .mpy file') + if header[1] != config.MPY_VERSION: + raise Exception('incompatible .mpy version') + feature_flags = header[2] + config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE = (feature_flags & 1) != 0 + config.MICROPY_PY_BUILTINS_STR_UNICODE = (feature_flags & 2) != 0 + config.mp_small_int_bits = header[3] + return read_raw_code(f) + +def dump_mpy(raw_codes): + for rc in raw_codes: + rc.dump() + +def freeze_mpy(base_qstrs, raw_codes): + # add to qstrs + new = {} + for q in global_qstrs: + # don't add duplicates + if q.qstr_esc in base_qstrs or q.qstr_esc in new: + continue + new[q.qstr_esc] = (len(new), q.qstr_esc, q.str) + new = sorted(new.values(), key=lambda x: x[0]) + + print('#include "py/mpconfig.h"') + print('#include "py/objint.h"') + print('#include "py/objstr.h"') + print('#include "py/emitglue.h"') + print() + + print('#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u' % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) + print('#error "incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE"') + print('#endif') + print() + + print('#if MICROPY_LONGINT_IMPL != %u' % config.MICROPY_LONGINT_IMPL) + print('#error "incompatible MICROPY_LONGINT_IMPL"') + print('#endif') + print() + + if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: + print('#if MPZ_DIG_SIZE != %u' % config.MPZ_DIG_SIZE) + print('#error "incompatible MPZ_DIG_SIZE"') + print('#endif') + print() + + + print('#if MICROPY_PY_BUILTINS_FLOAT') + print('typedef struct _mp_obj_float_t {') + print(' mp_obj_base_t base;') + print(' mp_float_t value;') + print('} mp_obj_float_t;') + print('#endif') + print() + + print('#if MICROPY_PY_BUILTINS_COMPLEX') + print('typedef struct _mp_obj_complex_t {') + print(' mp_obj_base_t base;') + print(' mp_float_t real;') + print(' mp_float_t imag;') + print('} mp_obj_complex_t;') + print('#endif') + print() + + print('enum {') + for i in range(len(new)): + if i == 0: + print(' MP_QSTR_%s = MP_QSTRnumber_of,' % new[i][1]) + else: + print(' MP_QSTR_%s,' % new[i][1]) + print('};') + + # As in qstr.c, set so that the first dynamically allocated pool is twice this size; must be <= the len + qstr_pool_alloc = min(len(new), 10) + + print() + print('extern const qstr_pool_t mp_qstr_const_pool;'); + print('const qstr_pool_t mp_qstr_frozen_const_pool = {') + print(' (qstr_pool_t*)&mp_qstr_const_pool, // previous pool') + print(' MP_QSTRnumber_of, // previous pool size') + print(' %u, // allocated entries' % qstr_pool_alloc) + print(' %u, // used entries' % len(new)) + print(' {') + for _, _, qstr in new: + print(' %s,' + % qstrutil.make_bytes(config.MICROPY_QSTR_BYTES_IN_LEN, config.MICROPY_QSTR_BYTES_IN_HASH, qstr)) + print(' },') + print('};') + + for rc in raw_codes: + rc.freeze(rc.source_file.str.replace('/', '_')[:-3] + '_') + + print() + print('const char mp_frozen_mpy_names[] = {') + for rc in raw_codes: + module_name = rc.source_file.str + print('"%s\\0"' % module_name) + print('"\\0"};') + + print('const mp_raw_code_t *const mp_frozen_mpy_content[] = {') + for rc in raw_codes: + print(' &raw_code_%s,' % rc.escaped_name) + print('};') + +def main(): + import argparse + cmd_parser = argparse.ArgumentParser(description='A tool to work with MicroPython .mpy files.') + cmd_parser.add_argument('-d', '--dump', action='store_true', + help='dump contents of files') + cmd_parser.add_argument('-f', '--freeze', action='store_true', + help='freeze files') + cmd_parser.add_argument('-q', '--qstr-header', + help='qstr header file to freeze against') + cmd_parser.add_argument('-mlongint-impl', choices=['none', 'longlong', 'mpz'], default='mpz', + help='long-int implementation used by target (default mpz)') + cmd_parser.add_argument('-mmpz-dig-size', metavar='N', type=int, default=16, + help='mpz digit size used by target (default 16)') + cmd_parser.add_argument('files', nargs='+', + help='input .mpy files') + args = cmd_parser.parse_args() + + # set config values relevant to target machine + config.MICROPY_LONGINT_IMPL = { + 'none':config.MICROPY_LONGINT_IMPL_NONE, + 'longlong':config.MICROPY_LONGINT_IMPL_LONGLONG, + 'mpz':config.MICROPY_LONGINT_IMPL_MPZ, + }[args.mlongint_impl] + config.MPZ_DIG_SIZE = args.mmpz_dig_size + + # set config values for qstrs, and get the existing base set of qstrs + if args.qstr_header: + qcfgs, base_qstrs = qstrutil.parse_input_headers([args.qstr_header]) + config.MICROPY_QSTR_BYTES_IN_LEN = int(qcfgs['BYTES_IN_LEN']) + config.MICROPY_QSTR_BYTES_IN_HASH = int(qcfgs['BYTES_IN_HASH']) + else: + config.MICROPY_QSTR_BYTES_IN_LEN = 1 + config.MICROPY_QSTR_BYTES_IN_HASH = 1 + base_qstrs = {} + + raw_codes = [read_mpy(file) for file in args.files] + + if args.dump: + dump_mpy(raw_codes) + elif args.freeze: + try: + freeze_mpy(base_qstrs, raw_codes) + except FreezeError as er: + print(er, file=sys.stderr) + sys.exit(1) + +if __name__ == '__main__': + main() diff --git a/src/openmv/src/micropython/tools/mpy_bin2res.py b/src/openmv/src/micropython/tools/mpy_bin2res.py new file mode 100755 index 0000000..0c89e7e --- /dev/null +++ b/src/openmv/src/micropython/tools/mpy_bin2res.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# +# This tool converts binary resource files passed on the command line +# into a Python source file containing data from these files, which can +# be accessed using standard pkg_resources.resource_stream() function +# from micropython-lib: +# https://github.com/micropython/micropython-lib/tree/master/pkg_resources +# +import sys + +print("R = {") + +for fname in sys.argv[1:]: + with open(fname, "rb") as f: + b = f.read() + print("%r: %r," % (fname, b)) + +print("}") diff --git a/src/openmv/src/micropython/tools/mpy_cross_all.py b/src/openmv/src/micropython/tools/mpy_cross_all.py new file mode 100755 index 0000000..2bda71e --- /dev/null +++ b/src/openmv/src/micropython/tools/mpy_cross_all.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import argparse +import os +import os.path + +argparser = argparse.ArgumentParser(description="Compile all .py files to .mpy recursively") +argparser.add_argument("-o", "--out", help="output directory (default: input dir)") +argparser.add_argument("--target", help="select MicroPython target config") +argparser.add_argument("-mcache-lookup-bc", action="store_true", help="cache map lookups in the bytecode") +argparser.add_argument("dir", help="input directory") +args = argparser.parse_args() + +TARGET_OPTS = { + "unix": "-mcache-lookup-bc", + "baremetal": "", +} + +args.dir = args.dir.rstrip("/") + +if not args.out: + args.out = args.dir + +path_prefix_len = len(args.dir) + 1 + +for path, subdirs, files in os.walk(args.dir): + for f in files: + if f.endswith(".py"): + fpath = path + "/" + f + #print(fpath) + out_fpath = args.out + "/" + fpath[path_prefix_len:-3] + ".mpy" + out_dir = os.path.dirname(out_fpath) + if not os.path.isdir(out_dir): + os.makedirs(out_dir) + cmd = "mpy-cross -v -v %s -s %s %s -o %s" % (TARGET_OPTS.get(args.target, ""), + fpath[path_prefix_len:], fpath, out_fpath) + #print(cmd) + res = os.system(cmd) + assert res == 0 diff --git a/src/openmv/src/micropython/tools/pyboard.py b/src/openmv/src/micropython/tools/pyboard.py new file mode 100755 index 0000000..86a07a1 --- /dev/null +++ b/src/openmv/src/micropython/tools/pyboard.py @@ -0,0 +1,464 @@ +#!/usr/bin/env python +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2014-2016 Damien P. George +# Copyright (c) 2017 Paul Sokolovsky +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +""" +pyboard interface + +This module provides the Pyboard class, used to communicate with and +control a MicroPython device over a communication channel. Both real +boards and emulated devices (e.g. running in QEMU) are supported. +Various communication channels are supported, including a serial +connection, telnet-style network connection, external process +connection. + +Example usage: + + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') + +Or: + + pyb = pyboard.Pyboard('192.168.1.1') + +Then: + + pyb.enter_raw_repl() + pyb.exec('pyb.LED(1).on()') + pyb.exit_raw_repl() + +Note: if using Python2 then pyb.exec must be written as pyb.exec_. +To run a script from the local machine on the board and print out the results: + + import pyboard + pyboard.execfile('test.py', device='/dev/ttyACM0') + +This script can also be run directly. To execute a local script, use: + + ./pyboard.py test.py + +Or: + + python pyboard.py test.py + +""" + +import sys +import time +import os + +try: + stdout = sys.stdout.buffer +except AttributeError: + # Python2 doesn't have buffer attr + stdout = sys.stdout + +def stdout_write_bytes(b): + b = b.replace(b"\x04", b"") + stdout.write(b) + stdout.flush() + +class PyboardError(Exception): + pass + +class TelnetToSerial: + def __init__(self, ip, user, password, read_timeout=None): + self.tn = None + import telnetlib + self.tn = telnetlib.Telnet(ip, timeout=15) + self.read_timeout = read_timeout + if b'Login as:' in self.tn.read_until(b'Login as:', timeout=read_timeout): + self.tn.write(bytes(user, 'ascii') + b"\r\n") + + if b'Password:' in self.tn.read_until(b'Password:', timeout=read_timeout): + # needed because of internal implementation details of the telnet server + time.sleep(0.2) + self.tn.write(bytes(password, 'ascii') + b"\r\n") + + if b'for more information.' in self.tn.read_until(b'Type "help()" for more information.', timeout=read_timeout): + # login successful + from collections import deque + self.fifo = deque() + return + + raise PyboardError('Failed to establish a telnet connection with the board') + + def __del__(self): + self.close() + + def close(self): + if self.tn: + self.tn.close() + + def read(self, size=1): + while len(self.fifo) < size: + timeout_count = 0 + data = self.tn.read_eager() + if len(data): + self.fifo.extend(data) + timeout_count = 0 + else: + time.sleep(0.25) + if self.read_timeout is not None and timeout_count > 4 * self.read_timeout: + break + timeout_count += 1 + + data = b'' + while len(data) < size and len(self.fifo) > 0: + data += bytes([self.fifo.popleft()]) + return data + + def write(self, data): + self.tn.write(data) + return len(data) + + def inWaiting(self): + n_waiting = len(self.fifo) + if not n_waiting: + data = self.tn.read_eager() + self.fifo.extend(data) + return len(data) + else: + return n_waiting + + +class ProcessToSerial: + "Execute a process and emulate serial connection using its stdin/stdout." + + def __init__(self, cmd): + import subprocess + self.subp = subprocess.Popen(cmd, bufsize=0, shell=True, preexec_fn=os.setsid, + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + + # Initially was implemented with selectors, but that adds Python3 + # dependency. However, there can be race conditions communicating + # with a particular child process (like QEMU), and selectors may + # still work better in that case, so left inplace for now. + # + #import selectors + #self.sel = selectors.DefaultSelector() + #self.sel.register(self.subp.stdout, selectors.EVENT_READ) + + import select + self.poll = select.poll() + self.poll.register(self.subp.stdout.fileno()) + + def close(self): + import signal + os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM) + + def read(self, size=1): + data = b"" + while len(data) < size: + data += self.subp.stdout.read(size - len(data)) + return data + + def write(self, data): + self.subp.stdin.write(data) + return len(data) + + def inWaiting(self): + #res = self.sel.select(0) + res = self.poll.poll(0) + if res: + return 1 + return 0 + + +class ProcessPtyToTerminal: + """Execute a process which creates a PTY and prints slave PTY as + first line of its output, and emulate serial connection using + this PTY.""" + + def __init__(self, cmd): + import subprocess + import re + import serial + self.subp = subprocess.Popen(cmd.split(), bufsize=0, shell=False, preexec_fn=os.setsid, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pty_line = self.subp.stderr.readline().decode("utf-8") + m = re.search(r"/dev/pts/[0-9]+", pty_line) + if not m: + print("Error: unable to find PTY device in startup line:", pty_line) + self.close() + sys.exit(1) + pty = m.group() + # rtscts, dsrdtr params are to workaround pyserial bug: + # http://stackoverflow.com/questions/34831131/pyserial-does-not-play-well-with-virtual-port + self.ser = serial.Serial(pty, interCharTimeout=1, rtscts=True, dsrdtr=True) + + def close(self): + import signal + os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM) + + def read(self, size=1): + return self.ser.read(size) + + def write(self, data): + return self.ser.write(data) + + def inWaiting(self): + return self.ser.inWaiting() + + +class Pyboard: + def __init__(self, device, baudrate=115200, user='micro', password='python', wait=0): + if device.startswith("exec:"): + self.serial = ProcessToSerial(device[len("exec:"):]) + elif device.startswith("execpty:"): + self.serial = ProcessPtyToTerminal(device[len("qemupty:"):]) + elif device and device[0].isdigit() and device[-1].isdigit() and device.count('.') == 3: + # device looks like an IP address + self.serial = TelnetToSerial(device, user, password, read_timeout=10) + else: + import serial + delayed = False + for attempt in range(wait + 1): + try: + self.serial = serial.Serial(device, baudrate=baudrate, interCharTimeout=1) + break + except (OSError, IOError): # Py2 and Py3 have different errors + if wait == 0: + continue + if attempt == 0: + sys.stdout.write('Waiting {} seconds for pyboard '.format(wait)) + delayed = True + time.sleep(1) + sys.stdout.write('.') + sys.stdout.flush() + else: + if delayed: + print('') + raise PyboardError('failed to access ' + device) + if delayed: + print('') + + def close(self): + self.serial.close() + + def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): + data = self.serial.read(min_num_bytes) + if data_consumer: + data_consumer(data) + timeout_count = 0 + while True: + if data.endswith(ending): + break + elif self.serial.inWaiting() > 0: + new_data = self.serial.read(1) + data = data + new_data + if data_consumer: + data_consumer(new_data) + timeout_count = 0 + else: + timeout_count += 1 + if timeout is not None and timeout_count >= 100 * timeout: + break + time.sleep(0.01) + return data + + def enter_raw_repl(self): + self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program + + # flush input (without relying on serial.flushInput()) + n = self.serial.inWaiting() + while n > 0: + self.serial.read(n) + n = self.serial.inWaiting() + + self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL + data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n>') + if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'): + print(data) + raise PyboardError('could not enter raw repl') + + self.serial.write(b'\x04') # ctrl-D: soft reset + data = self.read_until(1, b'soft reboot\r\n') + if not data.endswith(b'soft reboot\r\n'): + print(data) + raise PyboardError('could not enter raw repl') + # By splitting this into 2 reads, it allows boot.py to print stuff, + # which will show up after the soft reboot and before the raw REPL. + data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n') + if not data.endswith(b'raw REPL; CTRL-B to exit\r\n'): + print(data) + raise PyboardError('could not enter raw repl') + + def exit_raw_repl(self): + self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL + + def follow(self, timeout, data_consumer=None): + # wait for normal output + data = self.read_until(1, b'\x04', timeout=timeout, data_consumer=data_consumer) + if not data.endswith(b'\x04'): + raise PyboardError('timeout waiting for first EOF reception') + data = data[:-1] + + # wait for error output + data_err = self.read_until(1, b'\x04', timeout=timeout) + if not data_err.endswith(b'\x04'): + raise PyboardError('timeout waiting for second EOF reception') + data_err = data_err[:-1] + + # return normal and error output + return data, data_err + + def exec_raw_no_follow(self, command): + if isinstance(command, bytes): + command_bytes = command + else: + command_bytes = bytes(command, encoding='utf8') + + # check we have a prompt + data = self.read_until(1, b'>') + if not data.endswith(b'>'): + raise PyboardError('could not enter raw repl') + + # write command + for i in range(0, len(command_bytes), 256): + self.serial.write(command_bytes[i:min(i + 256, len(command_bytes))]) + time.sleep(0.01) + self.serial.write(b'\x04') + + # check if we could exec command + data = self.serial.read(2) + if data != b'OK': + raise PyboardError('could not exec command (response: %r)' % data) + + def exec_raw(self, command, timeout=10, data_consumer=None): + self.exec_raw_no_follow(command); + return self.follow(timeout, data_consumer) + + def eval(self, expression): + ret = self.exec_('print({})'.format(expression)) + ret = ret.strip() + return ret + + def exec_(self, command): + ret, ret_err = self.exec_raw(command) + if ret_err: + raise PyboardError('exception', ret, ret_err) + return ret + + def execfile(self, filename): + with open(filename, 'rb') as f: + pyfile = f.read() + return self.exec_(pyfile) + + def get_time(self): + t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ') + return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6]) + +# in Python2 exec is a keyword so one must use "exec_" +# but for Python3 we want to provide the nicer version "exec" +setattr(Pyboard, "exec", Pyboard.exec_) + +def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', password='python'): + pyb = Pyboard(device, baudrate, user, password) + pyb.enter_raw_repl() + output = pyb.execfile(filename) + stdout_write_bytes(output) + pyb.exit_raw_repl() + pyb.close() + +def main(): + import argparse + cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') + cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') + cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') + cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') + cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') + cmd_parser.add_argument('-c', '--command', help='program passed in as string') + cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available') + cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') + cmd_parser.add_argument('files', nargs='*', help='input files') + args = cmd_parser.parse_args() + + # open the connection to the pyboard + try: + pyb = Pyboard(args.device, args.baudrate, args.user, args.password, args.wait) + except PyboardError as er: + print(er) + sys.exit(1) + + # run any command or file(s) + if args.command is not None or len(args.files): + # we must enter raw-REPL mode to execute commands + # this will do a soft-reset of the board + try: + pyb.enter_raw_repl() + except PyboardError as er: + print(er) + pyb.close() + sys.exit(1) + + def execbuffer(buf): + try: + ret, ret_err = pyb.exec_raw(buf, timeout=None, data_consumer=stdout_write_bytes) + except PyboardError as er: + print(er) + pyb.close() + sys.exit(1) + except KeyboardInterrupt: + sys.exit(1) + if ret_err: + pyb.exit_raw_repl() + pyb.close() + stdout_write_bytes(ret_err) + sys.exit(1) + + # run the command, if given + if args.command is not None: + execbuffer(args.command.encode('utf-8')) + + # run any files + for filename in args.files: + with open(filename, 'rb') as f: + pyfile = f.read() + execbuffer(pyfile) + + # exiting raw-REPL just drops to friendly-REPL mode + pyb.exit_raw_repl() + + # if asked explicitly, or no files given, then follow the output + if args.follow or (args.command is None and len(args.files) == 0): + try: + ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes) + except PyboardError as er: + print(er) + sys.exit(1) + except KeyboardInterrupt: + sys.exit(1) + if ret_err: + pyb.close() + stdout_write_bytes(ret_err) + sys.exit(1) + + # close the connection to the pyboard + pyb.close() + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/tools/pydfu.py b/src/openmv/src/micropython/tools/pydfu.py new file mode 100755 index 0000000..e7f4ab1 --- /dev/null +++ b/src/openmv/src/micropython/tools/pydfu.py @@ -0,0 +1,551 @@ +#!/usr/bin/env python +# This file is part of the OpenMV project. +# Copyright (c) 2013/2014 Ibrahim Abdelkader +# This work is licensed under the MIT license, see the file LICENSE for +# details. + +"""This module implements enough functionality to program the STM32F4xx over +DFU, without requiring dfu-util. + +See app note AN3156 for a description of the DFU protocol. +See document UM0391 for a dscription of the DFuse file. +""" + +from __future__ import print_function + +import argparse +import re +import struct +import sys +import usb.core +import usb.util +import zlib + +# VID/PID +__VID = 0x0483 +__PID = 0xdf11 + +# USB request __TIMEOUT +__TIMEOUT = 4000 + +# DFU commands +__DFU_DETACH = 0 +__DFU_DNLOAD = 1 +__DFU_UPLOAD = 2 +__DFU_GETSTATUS = 3 +__DFU_CLRSTATUS = 4 +__DFU_GETSTATE = 5 +__DFU_ABORT = 6 + +# DFU status +__DFU_STATE_APP_IDLE = 0x00 +__DFU_STATE_APP_DETACH = 0x01 +__DFU_STATE_DFU_IDLE = 0x02 +__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03 +__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04 +__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05 +__DFU_STATE_DFU_MANIFEST_SYNC = 0x06 +__DFU_STATE_DFU_MANIFEST = 0x07 +__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08 +__DFU_STATE_DFU_UPLOAD_IDLE = 0x09 +__DFU_STATE_DFU_ERROR = 0x0a + +_DFU_DESCRIPTOR_TYPE = 0x21 + + +# USB device handle +__dev = None + +__verbose = None + +# USB DFU interface +__DFU_INTERFACE = 0 + +# Python 3 deprecated getargspec in favour of getfullargspec, but +# Python 2 doesn't have the latter, so detect which one to use +import inspect +getargspec = getattr(inspect, 'getfullargspec', inspect.getargspec) + +if 'length' in getargspec(usb.util.get_string).args: + # PyUSB 1.0.0.b1 has the length argument + def get_string(dev, index): + return usb.util.get_string(dev, 255, index) +else: + # PyUSB 1.0.0.b2 dropped the length argument + def get_string(dev, index): + return usb.util.get_string(dev, index) + + +def init(): + """Initializes the found DFU device so that we can program it.""" + global __dev + devices = get_dfu_devices(idVendor=__VID, idProduct=__PID) + if not devices: + raise ValueError('No DFU device found') + if len(devices) > 1: + raise ValueError("Multiple DFU devices found") + __dev = devices[0] + __dev.set_configuration() + + # Claim DFU interface + usb.util.claim_interface(__dev, __DFU_INTERFACE) + + # Clear status + clr_status() + + +def clr_status(): + """Clears any error status (perhaps left over from a previous session).""" + __dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE, + None, __TIMEOUT) + + +def get_status(): + """Get the status of the last operation.""" + stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE, + 6, 20000) + # print (__DFU_STAT[stat[4]], stat) + return stat[4] + + +def mass_erase(): + """Performs a MASS erase (i.e. erases the entire device.""" + # Send DNLOAD with first byte=0x41 + __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, + "\x41", __TIMEOUT) + + # Execute last command + if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY: + raise Exception("DFU: erase failed") + + # Check command state + if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE: + raise Exception("DFU: erase failed") + + +def page_erase(addr): + """Erases a single page.""" + if __verbose: + print("Erasing page: 0x%x..." % (addr)) + + # Send DNLOAD with first byte=0x41 and page address + buf = struct.pack(" 0: + write_size = size + if not mass_erase_used: + for segment in mem_layout: + if addr >= segment['addr'] and \ + addr <= segment['last_addr']: + # We found the page containing the address we want to + # write, erase it + page_size = segment['page_size'] + page_addr = addr & ~(page_size - 1) + if addr + write_size > page_addr + page_size: + write_size = page_addr + page_size - addr + page_erase(page_addr) + break + write_memory(addr, data[:write_size], progress, + elem_addr, elem_size) + data = data[write_size:] + addr += write_size + size -= write_size + if progress: + progress(elem_addr, addr - elem_addr, elem_size) + + +def cli_progress(addr, offset, size): + """Prints a progress report suitable for use on the command line.""" + width = 25 + done = offset * width // size + print("\r0x{:08x} {:7d} [{}{}] {:3d}% " + .format(addr, size, '=' * done, ' ' * (width - done), + offset * 100 // size), end="") + try: + sys.stdout.flush() + except OSError: + pass # Ignore Windows CLI "WinError 87" on Python 3.6 + if offset == size: + print("") + + +def main(): + """Test program for verifying this files functionality.""" + global __verbose + # Parse CMD args + parser = argparse.ArgumentParser(description='DFU Python Util') + #parser.add_argument("path", help="file path") + parser.add_argument( + "-l", "--list", + help="list available DFU devices", + action="store_true", + default=False + ) + parser.add_argument( + "-m", "--mass-erase", + help="mass erase device", + action="store_true", + default=False + ) + parser.add_argument( + "-u", "--upload", + help="read file from DFU device", + dest="path", + default=False + ) + parser.add_argument( + "-v", "--verbose", + help="increase output verbosity", + action="store_true", + default=False + ) + args = parser.parse_args() + + __verbose = args.verbose + + if args.list: + list_dfu_devices(idVendor=__VID, idProduct=__PID) + return + + init() + + if args.mass_erase: + print ("Mass erase...") + mass_erase() + + if args.path: + elements = read_dfu_file(args.path) + if not elements: + return + print("Writing memory...") + write_elements(elements, args.mass_erase, progress=cli_progress) + + print("Exiting DFU...") + exit_dfu() + return + + print("No command specified") + +if __name__ == '__main__': + main() diff --git a/src/openmv/src/micropython/tools/tinytest-codegen.py b/src/openmv/src/micropython/tools/tinytest-codegen.py new file mode 100755 index 0000000..ad3b3bb --- /dev/null +++ b/src/openmv/src/micropython/tools/tinytest-codegen.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 + +import os, sys +from glob import glob +from re import sub +import argparse + + +def escape(s): + s = s.decode() + lookup = { + '\0': '\\0', + '\t': '\\t', + '\n': '\\n\"\n\"', + '\r': '\\r', + '\\': '\\\\', + '\"': '\\\"', + } + return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) + +def chew_filename(t): + return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t } + +def script_to_map(test_file): + r = {"name": chew_filename(test_file)["func"]} + with open(test_file, "rb") as f: + r["script"] = escape(f.read()) + with open(test_file + ".exp", "rb") as f: + r["output"] = escape(f.read()) + return r + +test_function = ( + "void {name}(void* data) {{\n" + " static const char pystr[] = {script};\n" + " static const char exp[] = {output};\n" + " upytest_set_expected_output(exp, sizeof(exp) - 1);\n" + " upytest_execute_test(pystr);\n" + "}}" +) + +testcase_struct = ( + "struct testcase_t {name}_tests[] = {{\n{body}\n END_OF_TESTCASES\n}};" +) +testcase_member = ( + " {{ \"{desc}\", {func}, TT_ENABLED_, 0, 0 }}," +) + +testgroup_struct = ( + "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};" +) +testgroup_member = ( + " {{ \"{name}\", {name}_tests }}," +) + +## XXX: may be we could have `--without ` argument... +# currently these tests are selected because they pass on qemu-arm +test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') +exclude_tests = ( + # pattern matching in .exp + 'basics/bytes_compare3.py', + 'extmod/ticks_diff.py', + 'extmod/time_ms_us.py', + 'extmod/uheapq_timeq.py', + # unicode char issue + 'extmod/ujson_loads.py', + # doesn't output to python stdout + 'extmod/ure_debug.py', + 'extmod/vfs_basic.py', + 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', + 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + # rounding issues + 'float/float_divmod.py', + # requires double precision floating point to work + 'float/float2int_doubleprec_intbig.py', + 'float/float_parse_doubleprec.py', + # inline asm FP tests (require Cortex-M4) + 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', + 'inlineasm/asmfpmuldiv.py','inlineasm/asmfpsqrt.py', + # different filename in output + 'micropython/emg_exc.py', + 'micropython/heapalloc_traceback.py', + # pattern matching in .exp + 'micropython/meminfo.py', +) + +output = [] +tests = [] + +argparser = argparse.ArgumentParser(description='Convert native MicroPython tests to tinytest/upytesthelper C code') +argparser.add_argument('--stdin', action="store_true", help='read list of tests from stdin') +args = argparser.parse_args() + +if not args.stdin: + for group in test_dirs: + tests += [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] +else: + for l in sys.stdin: + tests.append(l.rstrip()) + +output.extend([test_function.format(**script_to_map(test)) for test in tests]) +testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] +output.append(testcase_struct.format(name="", body='\n'.join(testcase_members))) + +testgroup_members = [testgroup_member.format(name=group) for group in [""]] + +output.append(testgroup_struct.format(body='\n'.join(testgroup_members))) + +## XXX: may be we could have `--output ` argument... +# Don't depend on what system locale is set, use utf8 encoding. +sys.stdout.buffer.write('\n\n'.join(output).encode('utf8')) diff --git a/src/openmv/src/micropython/tools/upip.py b/src/openmv/src/micropython/tools/upip.py new file mode 100755 index 0000000..a400c31 --- /dev/null +++ b/src/openmv/src/micropython/tools/upip.py @@ -0,0 +1,314 @@ +# +# upip - Package manager for MicroPython +# +# Copyright (c) 2015-2018 Paul Sokolovsky +# +# Licensed under the MIT license. +# +import sys +import gc +import uos as os +import uerrno as errno +import ujson as json +import uzlib +import upip_utarfile as tarfile +gc.collect() + + +debug = False +install_path = None +cleanup_files = [] +gzdict_sz = 16 + 15 + +file_buf = bytearray(512) + +class NotFoundError(Exception): + pass + +def op_split(path): + if path == "": + return ("", "") + r = path.rsplit("/", 1) + if len(r) == 1: + return ("", path) + head = r[0] + if not head: + head = "/" + return (head, r[1]) + +def op_basename(path): + return op_split(path)[1] + +# Expects *file* name +def _makedirs(name, mode=0o777): + ret = False + s = "" + comps = name.rstrip("/").split("/")[:-1] + if comps[0] == "": + s = "/" + for c in comps: + if s and s[-1] != "/": + s += "/" + s += c + try: + os.mkdir(s) + ret = True + except OSError as e: + if e.args[0] != errno.EEXIST and e.args[0] != errno.EISDIR: + raise + ret = False + return ret + + +def save_file(fname, subf): + global file_buf + with open(fname, "wb") as outf: + while True: + sz = subf.readinto(file_buf) + if not sz: + break + outf.write(file_buf, sz) + +def install_tar(f, prefix): + meta = {} + for info in f: + #print(info) + fname = info.name + try: + fname = fname[fname.index("/") + 1:] + except ValueError: + fname = "" + + save = True + for p in ("setup.", "PKG-INFO", "README"): + #print(fname, p) + if fname.startswith(p) or ".egg-info" in fname: + if fname.endswith("/requires.txt"): + meta["deps"] = f.extractfile(info).read() + save = False + if debug: + print("Skipping", fname) + break + + if save: + outfname = prefix + fname + if info.type != tarfile.DIRTYPE: + if debug: + print("Extracting " + outfname) + _makedirs(outfname) + subf = f.extractfile(info) + save_file(outfname, subf) + return meta + +def expandhome(s): + if "~/" in s: + h = os.getenv("HOME") + s = s.replace("~/", h + "/") + return s + +import ussl +import usocket +warn_ussl = True +def url_open(url): + global warn_ussl + + if debug: + print(url) + + proto, _, host, urlpath = url.split('/', 3) + try: + ai = usocket.getaddrinfo(host, 443, 0, usocket.SOCK_STREAM) + except OSError as e: + fatal("Unable to resolve %s (no Internet?)" % host, e) + #print("Address infos:", ai) + ai = ai[0] + + s = usocket.socket(ai[0], ai[1], ai[2]) + try: + #print("Connect address:", addr) + s.connect(ai[-1]) + + if proto == "https:": + s = ussl.wrap_socket(s, server_hostname=host) + if warn_ussl: + print("Warning: %s SSL certificate is not validated" % host) + warn_ussl = False + + # MicroPython rawsocket module supports file interface directly + s.write("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (urlpath, host)) + l = s.readline() + protover, status, msg = l.split(None, 2) + if status != b"200": + if status == b"404" or status == b"301": + raise NotFoundError("Package not found") + raise ValueError(status) + while 1: + l = s.readline() + if not l: + raise ValueError("Unexpected EOF in HTTP headers") + if l == b'\r\n': + break + except Exception as e: + s.close() + raise e + + return s + + +def get_pkg_metadata(name): + f = url_open("https://pypi.org/pypi/%s/json" % name) + try: + return json.load(f) + finally: + f.close() + + +def fatal(msg, exc=None): + print("Error:", msg) + if exc and debug: + raise exc + sys.exit(1) + +def install_pkg(pkg_spec, install_path): + data = get_pkg_metadata(pkg_spec) + + latest_ver = data["info"]["version"] + packages = data["releases"][latest_ver] + del data + gc.collect() + assert len(packages) == 1 + package_url = packages[0]["url"] + print("Installing %s %s from %s" % (pkg_spec, latest_ver, package_url)) + package_fname = op_basename(package_url) + f1 = url_open(package_url) + try: + f2 = uzlib.DecompIO(f1, gzdict_sz) + f3 = tarfile.TarFile(fileobj=f2) + meta = install_tar(f3, install_path) + finally: + f1.close() + del f3 + del f2 + gc.collect() + return meta + +def install(to_install, install_path=None): + # Calculate gzip dictionary size to use + global gzdict_sz + sz = gc.mem_free() + gc.mem_alloc() + if sz <= 65536: + gzdict_sz = 16 + 12 + + if install_path is None: + install_path = get_install_path() + if install_path[-1] != "/": + install_path += "/" + if not isinstance(to_install, list): + to_install = [to_install] + print("Installing to: " + install_path) + # sets would be perfect here, but don't depend on them + installed = [] + try: + while to_install: + if debug: + print("Queue:", to_install) + pkg_spec = to_install.pop(0) + if pkg_spec in installed: + continue + meta = install_pkg(pkg_spec, install_path) + installed.append(pkg_spec) + if debug: + print(meta) + deps = meta.get("deps", "").rstrip() + if deps: + deps = deps.decode("utf-8").split("\n") + to_install.extend(deps) + except Exception as e: + print("Error installing '{}': {}, packages may be partially installed".format( + pkg_spec, e), + file=sys.stderr) + +def get_install_path(): + global install_path + if install_path is None: + # sys.path[0] is current module's path + install_path = sys.path[1] + install_path = expandhome(install_path) + return install_path + +def cleanup(): + for fname in cleanup_files: + try: + os.unlink(fname) + except OSError: + print("Warning: Cannot delete " + fname) + +def help(): + print("""\ +upip - Simple PyPI package manager for MicroPython +Usage: micropython -m upip install [-p ] ... | -r +import upip; upip.install(package_or_list, []) + +If is not given, packages will be installed into sys.path[1] +(can be set from MICROPYPATH environment variable, if current system +supports that).""") + print("Current value of sys.path[1]:", sys.path[1]) + print("""\ + +Note: only MicroPython packages (usually, named micropython-*) are supported +for installation, upip does not support arbitrary code in setup.py. +""") + +def main(): + global debug + global install_path + install_path = None + + if len(sys.argv) < 2 or sys.argv[1] == "-h" or sys.argv[1] == "--help": + help() + return + + if sys.argv[1] != "install": + fatal("Only 'install' command supported") + + to_install = [] + + i = 2 + while i < len(sys.argv) and sys.argv[i][0] == "-": + opt = sys.argv[i] + i += 1 + if opt == "-h" or opt == "--help": + help() + return + elif opt == "-p": + install_path = sys.argv[i] + i += 1 + elif opt == "-r": + list_file = sys.argv[i] + i += 1 + with open(list_file) as f: + while True: + l = f.readline() + if not l: + break + if l[0] == "#": + continue + to_install.append(l.rstrip()) + elif opt == "--debug": + debug = True + else: + fatal("Unknown/unsupported option: " + opt) + + to_install.extend(sys.argv[i:]) + if not to_install: + help() + return + + install(to_install) + + if not debug: + cleanup() + + +if __name__ == "__main__": + main() diff --git a/src/openmv/src/micropython/tools/upip_utarfile.py b/src/openmv/src/micropython/tools/upip_utarfile.py new file mode 100755 index 0000000..460ca2c --- /dev/null +++ b/src/openmv/src/micropython/tools/upip_utarfile.py @@ -0,0 +1,94 @@ +import uctypes + +# http://www.gnu.org/software/tar/manual/html_node/Standard.html +TAR_HEADER = { + "name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100), + "size": (uctypes.ARRAY | 124, uctypes.UINT8 | 11), +} + +DIRTYPE = "dir" +REGTYPE = "file" + +def roundup(val, align): + return (val + align - 1) & ~(align - 1) + +class FileSection: + + def __init__(self, f, content_len, aligned_len): + self.f = f + self.content_len = content_len + self.align = aligned_len - content_len + + def read(self, sz=65536): + if self.content_len == 0: + return b"" + if sz > self.content_len: + sz = self.content_len + data = self.f.read(sz) + sz = len(data) + self.content_len -= sz + return data + + def readinto(self, buf): + if self.content_len == 0: + return 0 + if len(buf) > self.content_len: + buf = memoryview(buf)[:self.content_len] + sz = self.f.readinto(buf) + self.content_len -= sz + return sz + + def skip(self): + sz = self.content_len + self.align + if sz: + buf = bytearray(16) + while sz: + s = min(sz, 16) + self.f.readinto(buf, s) + sz -= s + +class TarInfo: + + def __str__(self): + return "TarInfo(%r, %s, %d)" % (self.name, self.type, self.size) + +class TarFile: + + def __init__(self, name=None, fileobj=None): + if fileobj: + self.f = fileobj + else: + self.f = open(name, "rb") + self.subf = None + + def next(self): + if self.subf: + self.subf.skip() + buf = self.f.read(512) + if not buf: + return None + + h = uctypes.struct(uctypes.addressof(buf), TAR_HEADER, uctypes.LITTLE_ENDIAN) + + # Empty block means end of archive + if h.name[0] == 0: + return None + + d = TarInfo() + d.name = str(h.name, "utf-8").rstrip("\0") + d.size = int(bytes(h.size), 8) + d.type = [REGTYPE, DIRTYPE][d.name[-1] == "/"] + self.subf = d.subf = FileSection(self.f, d.size, roundup(d.size, 512)) + return d + + def __iter__(self): + return self + + def __next__(self): + v = self.next() + if v is None: + raise StopIteration + return v + + def extractfile(self, tarinfo): + return tarinfo.subf diff --git a/src/openmv/src/omv/array.c b/src/openmv/src/omv/array.c new file mode 100755 index 0000000..98b74be --- /dev/null +++ b/src/openmv/src/omv/array.c @@ -0,0 +1,175 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Dynamic array. + * + */ +#include +#include +#include "xalloc.h" +#include "array.h" +#define ARRAY_INIT_SIZE (4) // Size of one GC block. + +void array_alloc(array_t **a, array_dtor_t dtor) +{ + array_t *array = xalloc(sizeof(array_t)); + array->index = 0; + array->length = ARRAY_INIT_SIZE; + array->dtor = dtor; + array->data = xalloc(ARRAY_INIT_SIZE * sizeof(void*)); + *a = array; +} + +void array_alloc_init(array_t **a, array_dtor_t dtor, int size) +{ + array_t *array = xalloc(sizeof(array_t)); + array->index = 0; + array->length = size; + array->dtor = dtor; + array->data = xalloc(size * sizeof(void*)); + *a = array; +} + +void array_clear(array_t *array) +{ + if (array->dtor != NULL) { + for (int i=0, j=array->index; idtor(array->data[i]); + } + } + xfree(array->data); + array->index = 0; + array->length = 0; + array->data = NULL; + // Note: realloc with null pointer and (size != 0) returns valid pointer. + // Note: realloc with valid pointer and (size == 0) returns null pointer. +} + +void array_free(array_t *array) +{ + array_clear(array); + xfree(array); +} + +int array_length(array_t *array) +{ + return array->index; // index is the actual length, length is the max length +} + +void *array_at(array_t *array, int idx) +{ + return array->data[idx]; +} + +void array_push_back(array_t *array, void *element) +{ + if (array->index == array->length) { + array->length += ARRAY_INIT_SIZE; + array->data = xrealloc(array->data, array->length * sizeof(void*)); + } + array->data[array->index++] = element; +} + +void *array_pop_back(array_t *array) +{ + void *el=NULL; + if (array->index) { + el = array->data[--array->index]; + } + return el; +} + +void *array_take(array_t *array, int idx) +{ + void *el=array->data[idx]; + if ((1 < array->index) && (idx < (array->index - 1))) { + /* Since dst is always < src we can just use memcpy */ + memcpy(array->data+idx, array->data+idx+1, (array->index-idx-1) * sizeof(void*)); + } + array->index--; + return el; +} + +void array_erase(array_t *array, int idx) +{ + if (array->dtor) { + array->dtor(array->data[idx]); + } + array_take(array, idx); +} + +void array_resize(array_t *array, int num) +{ + if (array->index != num) { + if (!num) { + array_clear(array); + } else { + if (array->index > num) { + if (array->dtor != NULL) { + for (int i=num, j=array->index; idtor(array->data[i]); + } + } + array->index = num; + } + // resize array + array->length = num; + array->data = xrealloc(array->data, array->length * sizeof(void*)); + } + } +} + +// see micropython quicksort (objlist.c -> mp_quicksort) +static void quicksort(void **head, void **tail, array_comp_t comp) +{ + MP_STACK_CHECK(); + while (head < tail) { + void **h = head - 1; + void **t = tail; + void *v = tail[0]; + for (;;) { + do ++h; while(h < t && comp(h[0], v) < 0); + do --t; while(h < t && comp(v, t[0]) < 0); + if (h >= t) break; + void *x = h[0]; + h[0] = t[0]; + t[0] = x; + } + void *x = h[0]; + h[0] = tail[0]; + tail[0] = x; + // do the smaller recursive call first, to keep stack within O(log(N)) + if (t - head < tail - h - 1) { + quicksort(head, t, comp); + head = h + 1; + } else { + quicksort(h + 1, tail, comp); + tail = t; + } + } +} + +// TODO Python defines sort to be stable but ours is not +void array_sort(array_t *array, array_comp_t comp) +{ + if (array->index > 1) { + quicksort(array->data, array->data + array->index - 1, comp); + } +} + +void array_isort(array_t *array, array_comp_t comp) +{ + if (array->index > 1) { + for (int i = 1; i < array->index; i++) { + int j = i-1; + void *t = array->data[i]; + while (j >= 0 && comp(array->data[j], t)) { + array->data[j+1] = array->data[j]; + j--; + } + array->data[j+1] = t; + } + } +} diff --git a/src/openmv/src/omv/array.h b/src/openmv/src/omv/array.h new file mode 100755 index 0000000..4af57a7 --- /dev/null +++ b/src/openmv/src/omv/array.h @@ -0,0 +1,35 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Dynamic array. + * + */ +#ifndef __ARRAY_H__ +#define __ARRAY_H__ +typedef void (*array_dtor_t)(void*); +typedef int (*array_comp_t)(const void*, const void*); +// (left < right) == negative +// (left == right) == zero +// (left > right) == positive +typedef struct { + int index; + int length; + void **data; + array_dtor_t dtor; +} array_t; +void array_alloc(array_t **a, array_dtor_t dtor); +void array_alloc_init(array_t **a, array_dtor_t dtor, int size); +void array_clear(array_t *array); +void array_free(array_t *array); +int array_length(array_t *array); +void *array_at(array_t *array, int idx); +void array_push_back(array_t *array, void *element); +void *array_pop_back(array_t *array); +void *array_take(array_t *array, int idx); +void array_erase(array_t *array, int idx); +void array_resize(array_t *array, int num); +void array_sort(array_t *array, array_comp_t comp); +void array_isort(array_t *array, array_comp_t comp); +#endif //__ARRAY_H__ diff --git a/src/openmv/src/omv/boards/OPENMV3/imlib_config.h b/src/openmv/src/omv/boards/OPENMV3/imlib_config.h new file mode 100755 index 0000000..9cd9b19 --- /dev/null +++ b/src/openmv/src/omv/boards/OPENMV3/imlib_config.h @@ -0,0 +1,123 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Image library configuration. + * + */ +#ifndef __IMLIB_CONFIG_H__ +#define __IMLIB_CONFIG_H__ + +// Enable binary ops +#define IMLIB_ENABLE_BINARY_OPS + +// Enable math ops +#define IMLIB_ENABLE_MATH_OPS + +// Enable flood_fill() +#define IMLIB_ENABLE_FLOOD_FILL + +// Enable mean() +#define IMLIB_ENABLE_MEAN + +// Enable median() +#define IMLIB_ENABLE_MEDIAN + +// Enable mode() +#define IMLIB_ENABLE_MODE + +// Enable midpoint() +#define IMLIB_ENABLE_MIDPOINT + +// Enable morph() +#define IMLIB_ENABLE_MORPH + +// Enable Gaussian +#define IMLIB_ENABLE_GAUSSIAN + +// Enable Laplacian +#define IMLIB_ENABLE_LAPLACIAN + +// Enable bilateral() +#define IMLIB_ENABLE_BILATERAL + +// Enable cartoon() +#define IMLIB_ENABLE_CARTOON + +// Enable remove_shadows() +#define IMLIB_ENABLE_REMOVE_SHADOWS + +// Enable linpolar() +#define IMLIB_ENABLE_LINPOLAR + +// Enable logpolar() +#define IMLIB_ENABLE_LOGPOLAR + +// Enable chrominvar() +#define IMLIB_ENABLE_CHROMINVAR + +// Enable illuminvar() +#define IMLIB_ENABLE_ILLUMINVAR + +// Enable invariant table +//#define IMLIB_ENABLE_INVARIANT_TABLE + +// Enable rotation_corr() +#define IMLIB_ENABLE_ROTATION_CORR + +// Enable phasecorrelate() +#define IMLIB_ENABLE_FIND_DISPLACEMENT + +// rotation_corr() is required by phasecorrelate() +#if defined(IMLIB_ENABLE_FIND_DISPLACEMENT)\ + && !defined(IMLIB_ENABLE_ROTATION_CORR) + #define IMLIB_ENABLE_ROTATION_CORR +#endif + +// Enable get_similarity() +#define IMLIB_ENABLE_GET_SIMILARITY + +// Enable find_lines() +#define IMLIB_ENABLE_FIND_LINES + +// Enable find_line_segments() +#define IMLIB_ENABLE_FIND_LINE_SEGMENTS + +// find_lines() is required by the old find_line_segments() +#if defined(IMLIB_ENABLE_FIND_LINE_SEGMENTS)\ + && !defined(IMLIB_ENABLE_FIND_LINES) + #define IMLIB_ENABLE_FIND_LINES +#endif + +// Enable find_circles() +#define IMLIB_ENABLE_FIND_CIRCLES + +// Enable find_rects() +#define IMLIB_ENABLE_FIND_RECTS + +// Enable find_qrcodes() (14 KB) +#define IMLIB_ENABLE_QRCODES + +// Enable find_apriltags() (64 KB) +#define IMLIB_ENABLE_APRILTAGS + +// Enable find_datamatrices() (26 KB) +#define IMLIB_ENABLE_DATAMATRICES + +// Enable find_barcodes() (42 KB) +#define IMLIB_ENABLE_BARCODES + +// Enable LENET (200+ KB). +#define IMLIB_ENABLE_LENET + +// Enable CMSIS NN +#define IMLIB_ENABLE_CNN + +// Enable FAST (20+ KBs). +#define IMLIB_ENABLE_FAST + +// Enable find_hog() +#define IMLIB_ENABLE_HOG + +#endif //__IMLIB_CONFIG_H__ diff --git a/src/openmv/src/omv/boards/OPENMV3/omv_boardconfig.h b/src/openmv/src/omv/boards/OPENMV3/omv_boardconfig.h new file mode 100755 index 0000000..d8e2b06 --- /dev/null +++ b/src/openmv/src/omv/boards/OPENMV3/omv_boardconfig.h @@ -0,0 +1,177 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Board configuration and pin definitions. + * + */ +#ifndef __OMV_BOARDCONFIG_H__ +#define __OMV_BOARDCONFIG_H__ + +// Architecture info +#define OMV_ARCH_STR "OMV3 K210-standalone" // 33 chars max +#define OMV_BOARD_TYPE "Kendryte-k210-demo" +//#define OMV_UNIQUE_ID_ADDR 0x1FF0F420 + +// Flash sectors for the bootloader. +// Flash FS sector, main FW sector, max sector. +#define OMV_FLASH_LAYOUT {1, 4, 11} + +#define OMV_XCLK_MCO (0U) +#define OMV_XCLK_TIM (1U) + +// Sensor external clock source. +#define OMV_XCLK_SOURCE (OMV_XCLK_TIM) + +// Sensor external clock timer frequency. +#define OMV_XCLK_FREQUENCY (9000000) + +// Sensor PLL register value. +#define OMV_OV7725_PLL_CONFIG (0x81) // x6 + +// Bootloader LED GPIO port/pin +#define OMV_BOOTLDR_LED_PIN (GPIO_PIN_1) +#define OMV_BOOTLDR_LED_PORT (GPIOC) + +// RAW buffer size +#define OMV_RAW_BUF_SIZE (307200) + +// If buffer size is bigger than this threshold, the quality is reduced. +// This is only used for JPEG images sent to the IDE not normal compression. +#define JPEG_QUALITY_THRESH (160*120*2) + +// Low and high JPEG QS. +#define JPEG_QUALITY_LOW 35 +#define JPEG_QUALITY_HIGH 60 + +// Linker script constants (see the linker script template stm32fxxx.ld.S). +// Note: fb_alloc is a stack-based, dynamically allocated memory on FB. +// The maximum available fb_alloc memory = FB_ALLOC_SIZE + FB_SIZE - (w*h*bpp). +#define OMV_FB_MEMORY SRAM1 // Framebuffer, fb_alloc +#define OMV_MAIN_MEMORY CCM // data, bss, stack and heap +#define OMV_DMA_MEMORY CCM // Misc DMA buffers + +#define OMV_FB_SIZE (301K) // FB memory: header + VGA/GS image +#define OMV_FB_ALLOC_SIZE (83K) // minimum fb alloc size +#define OMV_STACK_SIZE (4K) +#define OMV_HEAP_SIZE (54K) + +#define OMV_LINE_BUF_SIZE (3K) // Image line buffer round(640 * 2BPP * 2 buffers). +#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data +#define OMV_VFS_BUF_SIZE (1K) // VFS sturct + FATFS file buffer (624 bytes) +#define OMV_FFS_BUF_SIZE (32K) // Flash filesystem cache +#define OMV_JPEG_BUF_SIZE (23 * 1024) // IDE JPEG buffer (header + data). + +#define OMV_BOOT_ORIGIN 0x08000000 +#define OMV_BOOT_LENGTH 32K +#define OMV_TEXT_ORIGIN 0x08020000 +#define OMV_TEXT_LENGTH 1920K +#define OMV_CCM_ORIGIN 0x20000000 +#define OMV_CCM_LENGTH 128K // Note DTCM/ITCM memory is not cacheable on M7 +#define OMV_SRAM1_ORIGIN 0x20020000 +#define OMV_SRAM1_LENGTH 384K + +/* SCCB/I2C */ +#define SCCB_I2C (I2C1) +#define SCCB_AF (GPIO_AF4_I2C1) +#define SCCB_CLK_ENABLE() __I2C1_CLK_ENABLE() +#define SCCB_CLK_DISABLE() __I2C1_CLK_DISABLE() +#define SCCB_PORT (GPIOB) +#define SCCB_SCL_PIN (GPIO_PIN_8) +#define SCCB_SDA_PIN (GPIO_PIN_9) + +/* DCMI */ +#define DCMI_TIM (TIM1) +#define DCMI_TIM_PIN (GPIO_PIN_8) +#define DCMI_TIM_PORT (GPIOA) +#define DCMI_TIM_AF (GPIO_AF1_TIM1) +#define DCMI_TIM_CHANNEL (TIM_CHANNEL_1) +#define DCMI_TIM_CLK_ENABLE() __TIM1_CLK_ENABLE() +#define DCMI_TIM_CLK_DISABLE() __TIM1_CLK_DISABLE() +#define DCMI_TIM_PCLK_FREQ() HAL_RCC_GetPCLK2Freq() + +#define DCMI_RESET_PIN (GPIO_PIN_10) +#define DCMI_RESET_PORT (GPIOA) + +#define DCMI_PWDN_PIN (GPIO_PIN_5) +#define DCMI_PWDN_PORT (GPIOB) + +#define DCMI_D0_PIN (GPIO_PIN_6) +#define DCMI_D1_PIN (GPIO_PIN_7) +#define DCMI_D2_PIN (GPIO_PIN_0) +#define DCMI_D3_PIN (GPIO_PIN_1) +#define DCMI_D4_PIN (GPIO_PIN_4) +#define DCMI_D5_PIN (GPIO_PIN_6) +#define DCMI_D6_PIN (GPIO_PIN_5) +#define DCMI_D7_PIN (GPIO_PIN_6) + +#define DCMI_D0_PORT (GPIOC) +#define DCMI_D1_PORT (GPIOC) +#define DCMI_D2_PORT (GPIOE) +#define DCMI_D3_PORT (GPIOE) +#define DCMI_D4_PORT (GPIOE) +#define DCMI_D5_PORT (GPIOB) +#define DCMI_D6_PORT (GPIOE) +#define DCMI_D7_PORT (GPIOE) + +#define DCMI_HSYNC_PIN (GPIO_PIN_4) +#define DCMI_VSYNC_PIN (GPIO_PIN_7) +#define DCMI_PXCLK_PIN (GPIO_PIN_6) + +#define DCMI_HSYNC_PORT (GPIOA) +#define DCMI_VSYNC_PORT (GPIOB) +#define DCMI_PXCLK_PORT (GPIOA) + +#define DCMI_RESET_LOW() HAL_GPIO_WritePin(DCMI_RESET_PORT, DCMI_RESET_PIN, GPIO_PIN_RESET) +#define DCMI_RESET_HIGH() HAL_GPIO_WritePin(DCMI_RESET_PORT, DCMI_RESET_PIN, GPIO_PIN_SET) + +#define DCMI_PWDN_LOW() HAL_GPIO_WritePin(DCMI_PWDN_PORT, DCMI_PWDN_PIN, GPIO_PIN_RESET) +#define DCMI_PWDN_HIGH() HAL_GPIO_WritePin(DCMI_PWDN_PORT, DCMI_PWDN_PIN, GPIO_PIN_SET) + +#define DCMI_VSYNC_IRQN EXTI9_5_IRQn +#define DCMI_VSYNC_IRQ_LINE (7) + +#define WINC_SPI (SPI2) +#define WINC_SPI_AF (GPIO_AF5_SPI2) +#define WINC_SPI_TIMEOUT (1000) +// SPI1/2/3 clock source is PCLK1 (54MHz/2 == 27MHz). +#define WINC_SPI_PRESCALER (SPI_BAUDRATEPRESCALER_2) +#define WINC_SPI_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE() + +#define WINC_SPI_SCLK_PIN (GPIO_PIN_13) +#define WINC_SPI_MISO_PIN (GPIO_PIN_14) +#define WINC_SPI_MOSI_PIN (GPIO_PIN_15) + +#define WINC_SPI_SCLK_PORT (GPIOB) +#define WINC_SPI_MISO_PORT (GPIOB) +#define WINC_SPI_MOSI_PORT (GPIOB) + +#define WINC_EN_PIN (GPIO_PIN_5) +#define WINC_CS_PIN (GPIO_PIN_12) +#define WINC_RST_PIN (GPIO_PIN_12) +#define WINC_IRQ_PIN (pin_D13) + +#define WINC_EN_PORT (GPIOA) +#define WINC_CS_PORT (GPIOB) +#define WINC_RST_PORT (GPIOD) + +#define WINC_CS_LOW() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_RESET) +#define WINC_CS_HIGH() HAL_GPIO_WritePin(WINC_CS_PORT, WINC_CS_PIN, GPIO_PIN_SET) + +#define I2C_PORT GPIOB +#define I2C_SIOC_PIN GPIO_PIN_10 +#define I2C_SIOD_PIN GPIO_PIN_11 + +#define I2C_SIOC_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_SET) +#define I2C_SIOC_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOC_PIN, GPIO_PIN_RESET) + +#define I2C_SIOD_H() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_SET) +#define I2C_SIOD_L() HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, GPIO_PIN_RESET) + +#define I2C_SIOD_READ() HAL_GPIO_ReadPin(I2C_PORT, I2C_SIOD_PIN) +#define I2C_SIOD_WRITE(bit) HAL_GPIO_WritePin(I2C_PORT, I2C_SIOD_PIN, bit); + +#define I2C_SPIN_DELAY 24 + +#endif //__OMV_BOARDCONFIG_H__ diff --git a/src/openmv/src/omv/cambus.c b/src/openmv/src/omv/cambus.c new file mode 100755 index 0000000..27f5a8b --- /dev/null +++ b/src/openmv/src/omv/cambus.c @@ -0,0 +1,158 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SCCB (I2C like) driver. + * + */ +#include +#include "omv_boardconfig.h" +#include "cambus.h" +#define I2C_FREQUENCY (100000) +#define I2C_TIMEOUT (1000) + +//static I2C_HandleTypeDef I2CHandle; + +int cambus_init() +{ +#if 0 + /* Configure I2C */ + I2CHandle.Instance = SCCB_I2C; + I2CHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_H7) + I2CHandle.Init.Timing = 0x40912732; // 100KHz + #else + I2CHandle.Init.ClockSpeed = I2C_FREQUENCY; + I2CHandle.Init.DutyCycle = I2C_DUTYCYCLE_2; + #endif + I2CHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + I2CHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + I2CHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + I2CHandle.Init.OwnAddress1 = 0xFE; + I2CHandle.Init.OwnAddress2 = 0xFE; + + if (HAL_I2C_Init(&I2CHandle) != HAL_OK) { + /* Initialization Error */ + return -1; + } +#endif + return 0; +} + +int cambus_scan() +{ +#if 0 + for (uint8_t addr=0x08; addr<=0x77; addr++) { + __disable_irq(); + if (HAL_I2C_IsDeviceReady(&I2CHandle, addr << 1, 10, I2C_TIMEOUT) == HAL_OK) { + __enable_irq(); + return (addr << 1); + } + __enable_irq(); + } +#endif + return 0; +} + +int cambus_readb(uint8_t slv_addr, uint8_t reg_addr, uint8_t *reg_data) +{ +#if 0 + int ret = 0; + + __disable_irq(); + if((HAL_I2C_Master_Transmit(&I2CHandle, slv_addr, ®_addr, 1, I2C_TIMEOUT) != HAL_OK) + || (HAL_I2C_Master_Receive(&I2CHandle, slv_addr, reg_data, 1, I2C_TIMEOUT) != HAL_OK)) { + ret = -1; + } + __enable_irq(); + return ret; +#else + return 0; +#endif +} + +int cambus_writeb(uint8_t slv_addr, uint8_t reg_addr, uint8_t reg_data) +{ +#if 0 + int ret=0; + uint8_t buf[] = {reg_addr, reg_data}; + + __disable_irq(); + if(HAL_I2C_Master_Transmit(&I2CHandle, slv_addr, buf, 2, I2C_TIMEOUT) != HAL_OK) { + ret = -1; + } + __enable_irq(); + return ret; +#else + return 0; +#endif +} + +int cambus_readw(uint8_t slv_addr, uint8_t reg_addr, uint16_t *reg_data) +{ +#if 0 + int ret=0; + __disable_irq(); + if (HAL_I2C_Mem_Read(&I2CHandle, slv_addr, reg_addr, + I2C_MEMADD_SIZE_8BIT, (uint8_t*) reg_data, 2, I2C_TIMEOUT) != HAL_OK) { + ret = -1; + } + __enable_irq(); + *reg_data = (*reg_data >> 8) | (*reg_data << 8); + return ret; +#else + return 0; +#endif +} + +int cambus_writew(uint8_t slv_addr, uint8_t reg_addr, uint16_t reg_data) +{ +#if 0 + int ret=0; + reg_data = (reg_data >> 8) | (reg_data << 8); + __disable_irq(); + if (HAL_I2C_Mem_Write(&I2CHandle, slv_addr, reg_addr, + I2C_MEMADD_SIZE_8BIT, (uint8_t*) ®_data, 2, I2C_TIMEOUT) != HAL_OK) { + ret = -1; + } + __enable_irq(); + return ret; +#else + return 0; +#endif +} + +int cambus_readw2(uint8_t slv_addr, uint16_t reg_addr, uint16_t *reg_data) +{ +#if 0 + int ret=0; + __disable_irq(); + if (HAL_I2C_Mem_Read(&I2CHandle, slv_addr, reg_addr, + I2C_MEMADD_SIZE_16BIT, (uint8_t*) reg_data, 2, I2C_TIMEOUT) != HAL_OK) { + ret = -1; + } + __enable_irq(); + *reg_data = (*reg_data >> 8) | (*reg_data << 8); + return ret; +#else + return 0; +#endif +} + +int cambus_writew2(uint8_t slv_addr, uint16_t reg_addr, uint16_t reg_data) +{ +#if 0 + int ret=0; + reg_data = (reg_data >> 8) | (reg_data << 8); + __disable_irq(); + if (HAL_I2C_Mem_Write(&I2CHandle, slv_addr, reg_addr, + I2C_MEMADD_SIZE_16BIT, (uint8_t*) ®_data, 2, I2C_TIMEOUT) != HAL_OK) { + ret = -1; + } + __enable_irq(); + return ret; +#else + return 0; +#endif +} diff --git a/src/openmv/src/omv/cambus.h b/src/openmv/src/omv/cambus.h new file mode 100755 index 0000000..fde9d46 --- /dev/null +++ b/src/openmv/src/omv/cambus.h @@ -0,0 +1,20 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Camera bus driver. + * + */ +#ifndef __CAMBUS_H__ +#define __CAMBUS_H__ +#include +int cambus_init(); +int cambus_scan(); +int cambus_readb(uint8_t slv_addr, uint8_t reg_addr, uint8_t *reg_data); +int cambus_writeb(uint8_t slv_addr, uint8_t reg_addr, uint8_t reg_data); +int cambus_readw(uint8_t slv_addr, uint8_t reg_addr, uint16_t *reg_data); +int cambus_writew(uint8_t slv_addr, uint8_t reg_addr, uint16_t reg_data); +int cambus_readw2(uint8_t slv_addr, uint16_t reg_addr, uint16_t *reg_data); +int cambus_writew2(uint8_t slv_addr, uint16_t reg_addr, uint16_t reg_data); +#endif // __CAMBUS_H__ diff --git a/src/openmv/src/omv/common.h b/src/openmv/src/omv/common.h new file mode 100755 index 0000000..090b90f --- /dev/null +++ b/src/openmv/src/omv/common.h @@ -0,0 +1,36 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Common macros. + * + */ +#ifndef __OMV_COMMON_H__ +#ifndef ALWAYS_INLINE +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#ifndef BREAK +#define BREAK() __asm__ volatile ("BKPT") +#endif + +#ifndef DISABLE_OPT +#define DISABLE_OPT __attribute__((optimize("O0"))) +#endif + +#ifdef DEBUG_PRINTF +#define debug_printf(fmt, ...) \ + do { printf("%s(): " fmt, __func__, ##__VA_ARGS__);} while (0) +#else +#define debug_printf(...) +#endif + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +#endif //__OMV_COMMON_H__ diff --git a/src/openmv/src/omv/fb_alloc.c b/src/openmv/src/omv/fb_alloc.c new file mode 100755 index 0000000..b9f0fd2 --- /dev/null +++ b/src/openmv/src/omv/fb_alloc.c @@ -0,0 +1,132 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Interface for using extra frame buffer RAM as a stack. + * + */ +#include +#include "fb_alloc.h" +#include "framebuffer.h" + +char _fballoc; +static char *pointer = &_fballoc; + +/*__weak NORETURN*/ void fb_alloc_fail() +{ + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, + "Out of fast Frame Buffer Stack Memory!" + " Please reduce the resolution of the image you are running this algorithm on to bypass this issue!")); +} + +void fb_alloc_init0() +{ + pointer = &_fballoc; +} + +uint32_t fb_avail() +{ + int32_t temp = pointer - ((char *) MAIN_FB_PIXELS()) - sizeof(uint32_t); + + return (temp < sizeof(uint32_t)) ? 0 : temp; +} + +void fb_alloc_mark() +{ + char *new_pointer = pointer - sizeof(uint32_t); + + // Check if allocation overwrites the framebuffer pixels + if (new_pointer < (char *) MAIN_FB_PIXELS()) { + /*hutu nlr_raise_for_fb_alloc_mark*/ + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, + "Out of fast Frame Buffer Stack Memory!" + " Please reduce the resolution of the image you are running this algorithm on to bypass this issue!")); + } + + // fb_alloc does not allow regions which are a size of 0 to be alloced, + // meaning that the value below is always 8 or more but never 4. So, + // we will use a size value of 4 as a marker in the alloc stack. + *((uint32_t *) new_pointer) = sizeof(uint32_t); // Save size. + pointer = new_pointer; +} + +void fb_alloc_free_till_mark() +{ + while (pointer < &_fballoc) { + int size = *((uint32_t *) pointer); + pointer += size; // Get size and pop. + if (size == sizeof(uint32_t)) break; // Break on first marker. + } +} + +// returns null pointer without error if size==0 +void *fb_alloc(uint32_t size) +{ + if (!size) { + return NULL; + } + + size=((size+sizeof(uint32_t)-1)/sizeof(uint32_t))*sizeof(uint32_t);// Round Up + char *result = pointer - size; + char *new_pointer = result - sizeof(uint32_t); + + // Check if allocation overwrites the framebuffer pixels + if (new_pointer < (char *) MAIN_FB_PIXELS()) { + fb_alloc_fail(); + } + + // size is always 4/8/12/etc. so the value below must be 8 or more. + *((uint32_t *) new_pointer) = size + sizeof(uint32_t); // Save size. + pointer = new_pointer; + return result; +} + +// returns null pointer without error if passed size==0 +void *fb_alloc0(uint32_t size) +{ + void *mem = fb_alloc(size); + memset(mem, 0, size); // does nothing if size is zero. + return mem; +} + +void *fb_alloc_all(uint32_t *size) +{ + int32_t temp = pointer - ((char *) MAIN_FB_PIXELS()) - sizeof(uint32_t); + + if (temp < sizeof(uint32_t)) { + *size = 0; + return NULL; + } + + *size = (temp / sizeof(uint32_t)) * sizeof(uint32_t); // Round Down + char *result = pointer - *size; + char *new_pointer = result - sizeof(uint32_t); + + // size is always 4/8/12/etc. so the value below must be 8 or more. + *((uint32_t *) new_pointer) = *size + sizeof(uint32_t); // Save size. + pointer = new_pointer; + return result; +} + +// returns null pointer without error if returned size==0 +void *fb_alloc0_all(uint32_t *size) +{ + void *mem = fb_alloc_all(size); + memset(mem, 0, *size); // does nothing if size is zero. + return mem; +} + +void fb_free() +{ + if (pointer < &_fballoc) { + pointer += *((uint32_t *) pointer); // Get size and pop. + } +} + +void fb_free_all() +{ + while (pointer < &_fballoc) { + pointer += *((uint32_t *) pointer); // Get size and pop. + } +} diff --git a/src/openmv/src/omv/fb_alloc.h b/src/openmv/src/omv/fb_alloc.h new file mode 100755 index 0000000..3dd7669 --- /dev/null +++ b/src/openmv/src/omv/fb_alloc.h @@ -0,0 +1,23 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Interface for using extra frame buffer RAM as a stack. + * + */ +#ifndef __FB_ALLOC_H__ +#define __FB_ALLOC_H__ +#include +void fb_alloc_fail(); +void fb_alloc_init0(); +uint32_t fb_avail(); +void fb_alloc_mark(); +void fb_alloc_free_till_mark(); +void *fb_alloc(uint32_t size); +void *fb_alloc0(uint32_t size); +void *fb_alloc_all(uint32_t *size); // returns pointer and sets size +void *fb_alloc0_all(uint32_t *size); // returns pointer and sets size +void fb_free(); +void fb_free_all(); +#endif /* __FF_ALLOC_H__ */ diff --git a/src/openmv/src/omv/ff_wrapper.c b/src/openmv/src/omv/ff_wrapper.c new file mode 100755 index 0000000..6036748 --- /dev/null +++ b/src/openmv/src/omv/ff_wrapper.c @@ -0,0 +1,495 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * File System Helper Functions + * + */ +#include +#include "common.h" +#include "fb_alloc.h" +#include "ff_wrapper.h" +#define FF_MIN(x,y) (((x)<(y))?(x):(y)) + +/*hutu*/ +static char *ffs_strerr(FRESULT res) +{ + static const char *ffs_errors[]={ + "Succeeded", + "A hard error occurred in the low level disk I/O layer", + "Assertion failed", + "The physical drive cannot work", + "Could not find the file", + "Could not find the path", + "The path name format is invalid", + "Access denied due to prohibited access or directory full", + "Access denied due to prohibited access", + "The file/directory object is invalid", + "The physical drive is write protected", + "The logical drive number is invalid", + "The volume has no work area", + "There is no valid FAT volume", + "The f_mkfs() aborted due to any parameter error", + "Could not get a grant to access the volume within defined period", + "The operation is rejected according to the file sharing policy", + "LFN working buffer could not be allocated", + "Number of open files > _FS_SHARE", + "Given parameter is invalid", + }; + + if (res>sizeof(ffs_errors)/sizeof(ffs_errors[0])) { + return "unknown error"; + } else { + return ffs_errors[res]; + } +} + +NORETURN static void ff_fail(FIL *fp, FRESULT res) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerr(res))); +} + +NORETURN static void ff_read_fail(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Failed to read requested bytes!")); +} + +NORETURN static void ff_write_fail(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Failed to write requested bytes!")); +} + +NORETURN static void ff_expect_fail(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unexpected value read!")); +} + +NORETURN void ff_unsupported_format(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported format!")); +} + +NORETURN void ff_file_corrupted(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "File corrupted!")); +} + +NORETURN void ff_not_equal(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Images not equal!")); +} + +NORETURN void ff_no_intersection(FIL *fp) +{ + if (fp) f_close(fp); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No intersection!")); +} + +void file_read_open(FIL *fp, const char *path) +{ + FRESULT res = f_open_helper(fp, path, FA_READ|FA_OPEN_EXISTING); + if (res != FR_OK) ff_fail(fp, res); +} + +void file_write_open(FIL *fp, const char *path) +{ + FRESULT res = f_open_helper(fp, path, FA_WRITE|FA_CREATE_ALWAYS); + if (res != FR_OK) ff_fail(fp, res); +} + +void file_close(FIL *fp) +{ + FRESULT res = f_close(fp); + if (res != FR_OK) ff_fail(fp, res); +} + +void file_seek(FIL *fp, UINT offset) +{ + FRESULT res = f_lseek(fp, offset); + if (res != FR_OK) ff_fail(fp, res); +} + +void file_truncate(FIL *fp) +{ + FRESULT res = f_truncate(fp); + if (res != FR_OK) ff_fail(fp, res); +} + +void file_sync(FIL *fp) +{ + FRESULT res = f_sync(fp); + if (res != FR_OK) ff_fail(fp, res); +} + +// These wrapper functions are used for backward compatibility with +// OpenMV code using vanilla FatFS. Note: Extracted from cc3200 ftp.c + +STATIC FATFS *lookup_path(const TCHAR **path) { +#if 0 + mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path); + if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) { + return NULL; + } + // here we assume that the mounted device is FATFS + return &((fs_user_mount_t*)MP_OBJ_TO_PTR(fs->obj))->fatfs; +#endif + return NULL; +} + +FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_open(fs, fp, path, mode); +} + +FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_opendir(fs, dp, path); +} + +FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_stat(fs, path, fno); +} + +FRESULT f_mkdir_helper(const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_mkdir(fs, path); +} + +FRESULT f_unlink_helper(const TCHAR *path) { + FATFS *fs = lookup_path(&path); + if (fs == NULL) { + return FR_NO_PATH; + } + return f_unlink(fs, path); +} + +FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new) { + FATFS *fs_old = lookup_path(&path_old); + if (fs_old == NULL) { + return FR_NO_PATH; + } + FATFS *fs_new = lookup_path(&path_new); + if (fs_new == NULL) { + return FR_NO_PATH; + } + if (fs_old != fs_new) { + return FR_NO_PATH; + } + return f_rename(fs_new, path_old, path_new); +} +// When a sector boundary is encountered while writing a file and there are +// more than 512 bytes left to write FatFs will detect that it can bypass +// its internal write buffer and pass the data buffer passed to it directly +// to the disk write function. However, the disk write function needs the +// buffer to be aligned to a 4-byte boundary. FatFs doesn't know this and +// will pass an unaligned buffer if we don't fix the issue. To fix this problem +// we use a temporary buffer to fix the alignment and to speed everything up. + +// We use this temporary buffer for both reads and writes. The buffer allows us +// to do multi-block reads and writes which signifcantly speed things up. + +static uint32_t file_buffer_offset = 0; +static uint8_t *file_buffer_pointer = 0; +static uint32_t file_buffer_size = 0; +static uint32_t file_buffer_index = 0; + +void file_buffer_init0() +{ + file_buffer_offset = 0; + file_buffer_pointer = 0; + file_buffer_size = 0; + file_buffer_index = 0; +} + +ALWAYS_INLINE static void file_fill(FIL *fp) +{ + if (file_buffer_index == file_buffer_size) { + file_buffer_pointer -= file_buffer_offset; + file_buffer_size += file_buffer_offset; + file_buffer_offset = 0; + file_buffer_index = 0; + uint32_t file_remaining = f_size(fp) - f_tell(fp); + uint32_t can_do = FF_MIN(file_buffer_size, file_remaining); + UINT bytes; + FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != can_do) ff_read_fail(fp); + } +} + +ALWAYS_INLINE static void file_flush(FIL *fp) +{ + if (file_buffer_index == file_buffer_size) { + UINT bytes; + FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != file_buffer_index) ff_write_fail(fp); + file_buffer_pointer -= file_buffer_offset; + file_buffer_size += file_buffer_offset; + file_buffer_offset = 0; + file_buffer_index = 0; + } +} + +uint32_t file_tell_w_buf(FIL *fp) +{ + if (fp->flag & FA_READ) { + return f_tell(fp) - file_buffer_size + file_buffer_index; + } else { + return f_tell(fp) + file_buffer_index; + } +} + +uint32_t file_size_w_buf(FIL *fp) +{ + if (fp->flag & FA_READ) { + return f_size(fp); + } else { + return f_size(fp) + file_buffer_index; + } +} + +void file_buffer_on(FIL *fp) +{ + file_buffer_offset = f_tell(fp) % 4; + file_buffer_pointer = fb_alloc_all(&file_buffer_size) + file_buffer_offset; + if (!file_buffer_size) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "No memory!")); + } + file_buffer_size -= file_buffer_offset; + file_buffer_index = 0; + if (fp->flag & FA_READ) { + uint32_t file_remaining = f_size(fp) - f_tell(fp); + uint32_t can_do = FF_MIN(file_buffer_size, file_remaining); + UINT bytes; + FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != can_do) ff_read_fail(fp); + } +} + +void file_buffer_off(FIL *fp) +{ + if ((fp->flag & FA_WRITE) && file_buffer_index) { + UINT bytes; + FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != file_buffer_index) ff_write_fail(fp); + } + file_buffer_pointer = 0; + fb_free(); +} + +void read_byte(FIL *fp, uint8_t *value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // via massive reads. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(*value); i++) { + file_fill(fp); + ((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++]; + } + } else { + UINT bytes; + FRESULT res = f_read(fp, value, sizeof(*value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(*value)) ff_read_fail(fp); + } +} + +void read_byte_expect(FIL *fp, uint8_t value) +{ + uint8_t compare; + read_byte(fp, &compare); + if (value != compare) ff_expect_fail(fp); +} + +void read_byte_ignore(FIL *fp) +{ + uint8_t trash; + read_byte(fp, &trash); +} + +void read_word(FIL *fp, uint16_t *value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // via massive reads. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(*value); i++) { + file_fill(fp); + ((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++]; + } + } else { + UINT bytes; + FRESULT res = f_read(fp, value, sizeof(*value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(*value)) ff_read_fail(fp); + } +} + +void read_word_expect(FIL *fp, uint16_t value) +{ + uint16_t compare; + read_word(fp, &compare); + if (value != compare) ff_expect_fail(fp); +} + +void read_word_ignore(FIL *fp) +{ + uint16_t trash; + read_word(fp, &trash); +} + +void read_long(FIL *fp, uint32_t *value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // via massive reads. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(*value); i++) { + file_fill(fp); + ((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++]; + } + } else { + UINT bytes; + FRESULT res = f_read(fp, value, sizeof(*value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(*value)) ff_read_fail(fp); + } +} + +void read_long_expect(FIL *fp, uint32_t value) +{ + uint32_t compare; + read_long(fp, &compare); + if (value != compare) ff_expect_fail(fp); +} + +void read_long_ignore(FIL *fp) +{ + uint32_t trash; + read_long(fp, &trash); +} + +void read_data(FIL *fp, void *data, UINT size) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // via massive reads. So much so that the time wasted by + // all these operations does not cost us. + while (size) { + file_fill(fp); + uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index; + uint32_t can_do = FF_MIN(size, file_buffer_space_left); + memcpy(data, file_buffer_pointer+file_buffer_index, can_do); + file_buffer_index += can_do; + data += can_do; + size -= can_do; + } + } else { + UINT bytes; + FRESULT res = f_read(fp, data, size, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != size) ff_read_fail(fp); + } +} + +void write_byte(FIL *fp, uint8_t value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // before a write to the SD card. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(value); i++) { + file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i]; + file_flush(fp); + } + } else { + UINT bytes; + FRESULT res = f_write(fp, &value, sizeof(value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(value)) ff_write_fail(fp); + } +} + +void write_word(FIL *fp, uint16_t value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // before a write to the SD card. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(value); i++) { + file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i]; + file_flush(fp); + } + } else { + UINT bytes; + FRESULT res = f_write(fp, &value, sizeof(value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(value)) ff_write_fail(fp); + } +} + +void write_long(FIL *fp, uint32_t value) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // before a write to the SD card. So much so that the time wasted by + // all these operations does not cost us. + for (size_t i = 0; i < sizeof(value); i++) { + file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i]; + file_flush(fp); + } + } else { + UINT bytes; + FRESULT res = f_write(fp, &value, sizeof(value), &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != sizeof(value)) ff_write_fail(fp); + } +} + +void write_data(FIL *fp, const void *data, UINT size) +{ + if (file_buffer_pointer) { + // We get a massive speed boost by buffering up as much data as possible + // before a write to the SD card. So much so that the time wasted by + // all these operations does not cost us. + while (size) { + uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index; + uint32_t can_do = FF_MIN(size, file_buffer_space_left); + memcpy(file_buffer_pointer+file_buffer_index, data, can_do); + file_buffer_index += can_do; + data += can_do; + size -= can_do; + file_flush(fp); + } + } else { + UINT bytes; + FRESULT res = f_write(fp, data, size, &bytes); + if (res != FR_OK) ff_fail(fp, res); + if (bytes != size) ff_write_fail(fp); + } +} diff --git a/src/openmv/src/omv/ff_wrapper.h b/src/openmv/src/omv/ff_wrapper.h new file mode 100755 index 0000000..732f2f3 --- /dev/null +++ b/src/openmv/src/omv/ff_wrapper.h @@ -0,0 +1,54 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * File System Helper Functions + * + */ +#ifndef __FF_WRAPPER_H__ +#define __FF_WRAPPER_H__ +#include +#include +extern const char *ffs_strerror(FRESULT res); + +//OOFATFS wrappers +FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode); +FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path); +FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno); +FRESULT f_mkdir_helper(const TCHAR *path); +FRESULT f_unlink_helper(const TCHAR *path); +FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new); + +void ff_unsupported_format(FIL *fp); +void ff_file_corrupted(FIL *fp); +void ff_not_equal(FIL *fp); +void ff_no_intersection(FIL *fp); +void file_read_open(FIL *fp, const char *path); +void file_write_open(FIL *fp, const char *path); +void file_close(FIL *fp); +void file_seek(FIL *fp, UINT offset); +void file_truncate(FIL *fp); +void file_sync(FIL *fp); + +// File buffer functions. +void file_buffer_init0(); +void file_buffer_on(FIL *fp); // does fb_alloc_all +uint32_t file_tell_w_buf(FIL *fp); // valid between on and off +uint32_t file_size_w_buf(FIL *fp); // valid between on and off +void file_buffer_off(FIL *fp); // does fb_free +void read_byte(FIL *fp, uint8_t *value); +void read_byte_expect(FIL *fp, uint8_t value); +void read_byte_ignore(FIL *fp); +void read_word(FIL *fp, uint16_t *value); +void read_word_expect(FIL *fp, uint16_t value); +void read_word_ignore(FIL *fp); +void read_long(FIL *fp, uint32_t *value); +void read_long_expect(FIL *fp, uint32_t value); +void read_long_ignore(FIL *fp); +void read_data(FIL *fp, void *data, UINT size); +void write_byte(FIL *fp, uint8_t value); +void write_word(FIL *fp, uint16_t value); +void write_long(FIL *fp, uint32_t value); +void write_data(FIL *fp, const void *data, UINT size); +#endif /* __FF_WRAPPER_H__ */ diff --git a/src/openmv/src/omv/framebuffer.c b/src/openmv/src/omv/framebuffer.c new file mode 100755 index 0000000..99c3bec --- /dev/null +++ b/src/openmv/src/omv/framebuffer.c @@ -0,0 +1,93 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Framebuffer stuff. + * + */ +#include "imlib.h" +#include "omv_boardconfig.h" +#include "framebuffer.h" + +char _fb_base; +framebuffer_t *fb_framebuffer = (framebuffer_t *) &_fb_base; + +char _jpeg_buf; +jpegbuffer_t *jpeg_fb_framebuffer = (jpegbuffer_t *) &_jpeg_buf; + +uint32_t fb_buffer_size() +{ + switch (MAIN_FB()->bpp) { + case IMAGE_BPP_BINARY: { + return ((MAIN_FB()->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * MAIN_FB()->h; + } + case IMAGE_BPP_GRAYSCALE: { + return (MAIN_FB()->w * MAIN_FB()->h) * sizeof(uint8_t); + } + case IMAGE_BPP_RGB565: { + return (MAIN_FB()->w * MAIN_FB()->h) * sizeof(uint16_t); + } + case IMAGE_BPP_BAYER: { + return MAIN_FB()->w * MAIN_FB()->h; + } + default: { // JPEG + return MAIN_FB()->bpp; + } + } +} + +void fb_update_jpeg_buffer() +{ + static int overflow_count = 0; + + if ((MAIN_FB()->bpp > 3) && JPEG_FB()->enabled) { + // Lock FB + if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { + if((OMV_JPEG_BUF_SIZE-64) < MAIN_FB()->bpp) { + // image won't fit. so don't copy. + JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; + } else { + memcpy(JPEG_FB()->pixels, MAIN_FB()->pixels, MAIN_FB()->bpp); + JPEG_FB()->w = MAIN_FB()->w; JPEG_FB()->h = MAIN_FB()->h; JPEG_FB()->size = MAIN_FB()->bpp; + } + + // Unlock the framebuffer mutex + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); + } + } else if ((MAIN_FB()->bpp >= 0) && JPEG_FB()->enabled) { + // Lock FB + if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_OMV)) { + // Set JPEG src and dst images. + image_t src = {.w=MAIN_FB()->w, .h=MAIN_FB()->h, .bpp=MAIN_FB()->bpp, .pixels=MAIN_FB()->pixels}; + image_t dst = {.w=MAIN_FB()->w, .h=MAIN_FB()->h, .bpp=(OMV_JPEG_BUF_SIZE-64), .pixels=JPEG_FB()->pixels}; + + // Note: lower quality saves USB bandwidth and results in a faster IDE FPS. + bool overflow = jpeg_compress(&src, &dst, JPEG_FB()->quality, false); + if (overflow == true) { + // JPEG buffer overflowed, reduce JPEG quality for the next frame + // and skip the current frame. The IDE doesn't receive this frame. + if (JPEG_FB()->quality > 1) { + // Keep this quality for the next n frames + overflow_count = 60; + JPEG_FB()->quality = IM_MAX(1, (JPEG_FB()->quality/2)); + } + JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; + } else { + if (overflow_count) { + overflow_count--; + } + // No buffer overflow, increase quality up to max quality based on frame size + if (overflow_count == 0 && JPEG_FB()->quality + < ((fb_buffer_size() > JPEG_QUALITY_THRESH) ? JPEG_QUALITY_LOW:JPEG_QUALITY_HIGH)) { + JPEG_FB()->quality++; + } + // Set FB from JPEG image + JPEG_FB()->w = dst.w; JPEG_FB()->h = dst.h; JPEG_FB()->size = dst.bpp; + } + + // Unlock the framebuffer mutex + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_OMV); + } + } +} diff --git a/src/openmv/src/omv/framebuffer.h b/src/openmv/src/omv/framebuffer.h new file mode 100755 index 0000000..2396607 --- /dev/null +++ b/src/openmv/src/omv/framebuffer.h @@ -0,0 +1,50 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Framebuffer stuff. + * + */ +#ifndef __FRAMEBUFFER_H__ +#define __FRAMEBUFFER_H__ +#include +#include "mutex.h" + +typedef struct framebuffer { + int x,y; + int w,h; + int u,v; + int bpp; + uint8_t pixels[]; +} framebuffer_t; + +extern framebuffer_t *fb_framebuffer; + +typedef struct jpegbuffer { + int w,h; + int size; + int enabled; + int quality; + mutex_t lock; + uint8_t pixels[]; +} jpegbuffer_t; + +extern jpegbuffer_t *jpeg_fb_framebuffer; + +// Use these macros to get a pointer to main or JPEG framebuffer. +#define MAIN_FB() (fb_framebuffer) +#define JPEG_FB() (jpeg_fb_framebuffer) + +// Use this macro to get a pointer to the free SRAM area located after the framebuffer. +#define MAIN_FB_PIXELS() (MAIN_FB()->pixels + fb_buffer_size()) + +// Use this macro to get a pointer to the free SRAM area located after the framebuffer. +#define JPEG_FB_PIXELS() (JPEG_FB()->pixels + JPEG_FB()->size) + +// Returns the main frame buffer size, factoring in pixel formats. +uint32_t fb_buffer_size(); + +// Transfers the frame buffer to the jpeg frame buffer if not locked. +void fb_update_jpeg_buffer(); +#endif /* __FRAMEBUFFER_H__ */ diff --git a/src/openmv/src/omv/img/agast.c b/src/openmv/src/omv/img/agast.c new file mode 100755 index 0000000..009c3b6 --- /dev/null +++ b/src/openmv/src/omv/img/agast.c @@ -0,0 +1,1273 @@ +#include +#include +#include "imlib.h" +#include "xalloc.h" +#include "fb_alloc.h" +#include "gc.h" + +#define MAX_ROW (480) +#define MAX_CORNERS (2000) +#define Compare(X, Y) ((X)>=(Y)) + +typedef struct { + uint16_t x; + uint16_t y; + uint16_t score; +} corner_t; + +static int s_width=-1; +static int_fast16_t s_offset0; +static int_fast16_t s_offset1; +static int_fast16_t s_offset2; +static int_fast16_t s_offset3; +static int_fast16_t s_offset4; +static int_fast16_t s_offset5; +static int_fast16_t s_offset6; +static int_fast16_t s_offset7; + +static corner_t *agast58_detect(image_t *img, int b, int* num_corners, rectangle_t *roi); +static int agast58_score(const unsigned char* p, int bstart); +static void nonmax_suppression(corner_t *corners, int num_corners, array_t *keypoints); + +static kp_t *alloc_keypoint(uint16_t x, uint16_t y, uint16_t score) +{ + // Note must set keypoint descriptor to zeros + kp_t *kpt = xalloc0(sizeof*kpt); + kpt->x = x; + kpt->y = y; + kpt->score = score; + return kpt; +} + +static void init5_8_pattern(int image_width) +{ + if(image_width==s_width) + return; + + s_width=image_width; + + s_offset0=(-1)+(0)*s_width; + s_offset1=(-1)+(-1)*s_width; + s_offset2=(0)+(-1)*s_width; + s_offset3=(1)+(-1)*s_width; + s_offset4=(1)+(0)*s_width; + s_offset5=(1)+(1)*s_width; + s_offset6=(0)+(1)*s_width; + s_offset7=(-1)+(1)*s_width; +} + +void agast_detect(image_t *image, array_t *keypoints, int threshold, rectangle_t *roi) +{ + int num_corners=0; + init5_8_pattern(image->w); + + // Find corners + corner_t *corners = agast58_detect(image, threshold, &num_corners, roi); + if (num_corners) { + // Score corners + for(int i=0; ipixels + (corners[i].y*image->w + corners[i].x), threshold); + } + // Non-max suppression + nonmax_suppression(corners, num_corners, keypoints); + } + + // Free corners; + fb_free(); +} + +static void nonmax_suppression(corner_t *corners, int num_corners, array_t *keypoints) +{ + gc_info_t info; + + int last_row; + int16_t row_start[MAX_ROW+1]; + const int sz = num_corners; + + /* Point above points (roughly) to the pixel above + the one of interest, if there is a feature there.*/ + int point_above = 0; + int point_below = 0; + + /* Find where each row begins (the corners are output in raster scan order). + A beginning of -1 signifies that there are no corners on that row. */ + last_row = corners[sz-1].y; + + for(int i=0; iy != prev_row) { + row_start[c->y] = i; + prev_row = c->y; + } + } + + for(int i=0; i 0) { + if (corners[i-1].x == pos.x-1 && corners[i-1].y == pos.y && Compare(corners[i-1].score, score)) { + goto nonmax; + } + } + + /*Check right*/ + if (i < (sz - 1)) { + if (corners[i+1].x == pos.x+1 && corners[i+1].y == pos.y && Compare(corners[i+1].score, score)) { + goto nonmax; + } + } + + /*Check above (if there is a valid row above)*/ + if (pos.y != 0 && row_start[pos.y - 1] != -1) { + /*Make sure that current point_above is one row above.*/ + if(corners[point_above].y < pos.y - 1) + point_above = row_start[pos.y-1]; + + /*Make point_above point to the first of the pixels above the current point, if it exists.*/ + for (; corners[point_above].y < pos.y && corners[point_above].x < pos.x - 1; point_above++) { + + } + + for (int j=point_above; corners[j].y < pos.y && corners[j].x <= pos.x + 1; j++) { + int x = corners[j].x; + if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(corners[j].score, score)) + goto nonmax; + } + } + + /*Check below (if there is anything below)*/ + if (pos.y != last_row && row_start[pos.y + 1] != -1 && point_below < sz) /*Nothing below*/ { + if (corners[point_below].y < pos.y + 1) + point_below = row_start[pos.y+1]; + + /* Make point below point to one of the pixels belowthe current point, if it exists.*/ + for (; point_below < sz && corners[point_below].y == pos.y+1 && corners[point_below].x < pos.x - 1; point_below++) { + } + + for (int j=point_below; j < sz && corners[j].y == pos.y+1 && corners[j].x <= pos.x + 1; j++) { + int x = corners[j].x; + if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(corners[j].score, score)) + goto nonmax; + } + } + + gc_info(&info); + #define MIN_MEM (10*1024) + // Allocate keypoints until we're almost out of memory + if (info.free < MIN_MEM) { + // Try collecting memory + gc_collect(); + // If it didn't work break + gc_info(&info); + if (info.free < MIN_MEM) { + break; + } + } + + #undef MIN_MEM + array_push_back(keypoints, alloc_keypoint(pos.x, pos.y, pos.score)); + nonmax: + ; + } +} + +static corner_t *agast58_detect(image_t *img, int b, int* num_corners, rectangle_t *roi) +{ + int total=0; + register int x, y; + register int xsizeB=(roi->x+roi->w) - 2; + register int ysizeB=(roi->y+roi->h) - 1; + register int_fast16_t offset0, offset1, offset2, offset3, offset4, offset5, offset6, offset7; + register int width; + + offset0=s_offset0; + offset1=s_offset1; + offset2=s_offset2; + offset3=s_offset3; + offset4=s_offset4; + offset5=s_offset5; + offset6=s_offset6; + offset7=s_offset7; + width=s_width; + + // Try to alloc MAX_CORNERS or the actual max corners we can alloc. + int max_corners = IM_MIN(MAX_CORNERS, (fb_avail() / sizeof(corner_t))); + corner_t *corners = (corner_t*) fb_alloc(max_corners * sizeof(corner_t)); + + for(y=roi->y+1; y < ysizeB; y++) + { + x=roi->x; + while(1) + { +homogeneous: +{ + x++; + if(x>xsizeB) + break; + else + { + register const unsigned char* const p = img->pixels + y*width + x; + register const int cb = *p + b; + register const int c_b = *p - b; + if(p[offset0] > cb) + if(p[offset2] > cb) + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_structured; + else + if(p[offset7] > cb) + goto success_structured; + else + goto homogeneous; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_homogeneous; + else + if(p[offset7] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset5] > cb) + if(p[offset1] > cb) + goto success_structured; + else + if(p[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(p[offset1] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] > cb) + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset1] > cb) + goto success_homogeneous; + else + if(p[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else if(p[offset0] < c_b) + if(p[offset2] < c_b) + if(p[offset7] > cb) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] < c_b) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto success_structured; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto homogeneous; + else + if(p[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset6] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto success_structured; + else + if(p[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(p[offset1] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto homogeneous; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_structured; + else + goto homogeneous; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] < c_b) + if(p[offset7] < c_b) + if(p[offset6] < c_b) + if(p[offset1] < c_b) + goto success_homogeneous; + else + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } +} +structured: +{ + x++; + if(x>xsizeB) + break; + else + { + register const unsigned char* const p = img->pixels + y*width + x; + register const int cb = *p + b; + register const int c_b = *p - b; + if(p[offset0] > cb) + if(p[offset2] > cb) + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset7] > cb) + if(p[offset1] > cb) + goto success_structured; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset7] > cb) + if(p[offset1] > cb) + goto success_structured; + else + goto structured; + else + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset5] > cb) + if(p[offset1] > cb) + goto success_structured; + else + if(p[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(p[offset1] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(p[offset5] > cb) + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset1] > cb) + goto success_structured; + else + if(p[offset4] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + goto homogeneous; + else if(p[offset0] < c_b) + if(p[offset2] < c_b) + if(p[offset7] > cb) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + goto structured; + else + if(p[offset7] < c_b) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto success_structured; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset1] < c_b) + goto success_structured; + else + goto structured; + else + if(p[offset6] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto success_structured; + else + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + if(p[offset1] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_structured; + else + goto structured; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_structured; + else + goto structured; + else + goto structured; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto structured; + else + if(p[offset5] < c_b) + if(p[offset7] < c_b) + if(p[offset6] < c_b) + if(p[offset1] < c_b) + goto success_structured; + else + if(p[offset4] < c_b) + goto success_structured; + else + goto structured; + else + goto structured; + else + goto structured; + else + goto homogeneous; + else + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto success_homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + else + goto homogeneous; + } +} +success_homogeneous: + corners[total].x = x; + corners[total].y = y; + if(++total == max_corners) { + goto done; + } + goto homogeneous; +success_structured: + corners[total].x = x; + corners[total].y = y; + if(++total == max_corners) { + goto done; + } + goto structured; + } + } +done: + *num_corners = total; + return corners; +} + +//using also bisection as propsed by Edward Rosten in FAST, +//but it is based on the OAST +static int agast58_score(const unsigned char* p, int bstart) +{ + int bmin = bstart; + int bmax = 255; + int b = (bmax + bmin)/2; + + register int_fast16_t offset0=s_offset0; + register int_fast16_t offset1=s_offset1; + register int_fast16_t offset2=s_offset2; + register int_fast16_t offset3=s_offset3; + register int_fast16_t offset4=s_offset4; + register int_fast16_t offset5=s_offset5; + register int_fast16_t offset6=s_offset6; + register int_fast16_t offset7=s_offset7; + + while(1) + { + register const int cb = *p + b; + register const int c_b = *p - b; + if(p[offset0] > cb) + if(p[offset2] > cb) + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto is_a_corner; + else + if(p[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] > cb) + if(p[offset4] > cb) + goto is_a_corner; + else + if(p[offset7] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset5] > cb) + if(p[offset1] > cb) + goto is_a_corner; + else + if(p[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] > cb) + if(p[offset7] > cb) + if(p[offset6] > cb) + if(p[offset1] > cb) + goto is_a_corner; + else + if(p[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] < c_b) + if(p[offset3] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if(p[offset0] < c_b) + if(p[offset2] < c_b) + if(p[offset7] > cb) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] < c_b) + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto is_a_corner; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset6] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + goto is_a_corner; + else + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] > cb) + if(p[offset3] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset5] < c_b) + if(p[offset7] < c_b) + if(p[offset6] < c_b) + if(p[offset1] < c_b) + goto is_a_corner; + else + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset3] > cb) + if(p[offset5] > cb) + if(p[offset2] > cb) + if(p[offset1] > cb) + if(p[offset4] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] > cb) + if(p[offset4] > cb) + if(p[offset6] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset3] < c_b) + if(p[offset5] < c_b) + if(p[offset2] < c_b) + if(p[offset1] < c_b) + if(p[offset4] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if(p[offset7] < c_b) + if(p[offset4] < c_b) + if(p[offset6] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin=b; + goto end; + + is_not_a_corner: + bmax=b; + goto end; + + end: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b = (bmin + bmax) / 2; + } +} diff --git a/src/openmv/src/omv/img/apriltag.c b/src/openmv/src/omv/img/apriltag.c new file mode 100755 index 0000000..246b244 --- /dev/null +++ b/src/openmv/src/omv/img/apriltag.c @@ -0,0 +1,12162 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include +#include "imlib.h" + +#ifdef IMLIB_ENABLE_APRILTAGS +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" + +/* Copyright (C) 2013-2016, The Regents of The University of Michigan. +All rights reserved. + +This software was developed in the APRIL Robotics Lab under the +direction of Edwin Olson, ebolson@umich.edu. This software may be +available under alternative licensing terms; contact the address above. + +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. + +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 OWNER 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. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the Regents of The University of Michigan. +*/ +#define printf(format, ...) +#define fprintf(format, ...) +#define free(ptr) ({ umm_free(ptr); }) +#define malloc(size) ({ void *_r = umm_malloc(size); if(!_r) umm_alloc_fail(); _r; }) +#define realloc(ptr, size) ({ void *_r = umm_realloc((ptr), (size)); if(!_r) umm_alloc_fail(); _r; }) +#define calloc(num, item_size) ({ void *_r = umm_calloc((num), (item_size)); if(!_r) umm_alloc_fail(); _r; }) +#define assert(expression) +#define double float +#undef DBL_MIN +#define DBL_MIN FLT_MIN +#undef DBL_MAX +#define DBL_MAX FLT_MAX +#define sqrt(x) fast_sqrtf(x) +#define sqrtf(x) fast_sqrtf(x) +#define floor(x) fast_floorf(x) +#define floorf(x) fast_floorf(x) +#define ceil(x) fast_ceilf(x) +#define ceilf(x) fast_ceilf(x) +#define round(x) fast_roundf(x) +#define roundf(x) fast_roundf(x) +#define atan(x) fast_atanf(x) +#define atanf(x) fast_atanf(x) +#define atan2(y, x) fast_atan2f((y), (x)) +#define atan2f(y, x) fast_atan2f((y), (x)) +#define exp(x) fast_expf(x) +#define expf(x) fast_expf(x) +#define cbrt(x) fast_cbrtf(x) +#define cbrtf(x) fast_cbrtf(x) +#define fabs(x) fast_fabsf(x) +#define fabsf(x) fast_fabsf(x) +#define log(x) fast_log(x) +#define logf(x) fast_log(x) +#undef log2 +#define log2(x) fast_log2(x) +#undef log2f +#define log2f(x) fast_log2(x) + +#define sin(x) (x) +#define cos(x) (x) +#define fmin(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) +#define fminf(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) +#define fmax(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) +#define fmaxf(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "zarray.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Defines a structure which acts as a resize-able array ala Java's ArrayList. + */ +typedef struct zarray zarray_t; +struct zarray +{ + size_t el_sz; // size of each element + + int size; // how many elements? + int alloc; // we've allocated storage for how many elements? + char *data; +}; + +/** + * Creates and returns a variable array structure capable of holding elements of + * the specified size. It is the caller's responsibility to call zarray_destroy() + * on the returned array when it is no longer needed. + */ +static inline zarray_t *zarray_create(size_t el_sz) +{ + assert(el_sz > 0); + + zarray_t *za = (zarray_t*) calloc(1, sizeof(zarray_t)); + za->el_sz = el_sz; + return za; +} + +/** + * Creates and returns a variable array structure capable of holding elements of + * the specified size. It is the caller's responsibility to call zarray_destroy() + * on the returned array when it is no longer needed. + */ +static inline zarray_t *zarray_create_fail_ok(size_t el_sz) +{ + assert(el_sz > 0); + + zarray_t *za = (zarray_t*) umm_calloc(1, sizeof(zarray_t)); + if (za) za->el_sz = el_sz; + return za; +} + +/** + * Frees all resources associated with the variable array structure which was + * created by zarray_create(). After calling, 'za' will no longer be valid for storage. + */ +static inline void zarray_destroy(zarray_t *za) +{ + if (za == NULL) + return; + + if (za->data != NULL) + free(za->data); + memset(za, 0, sizeof(zarray_t)); + free(za); +} + +/** Allocate a new zarray that contains a copy of the data in the argument. **/ +static inline zarray_t *zarray_copy(const zarray_t *za) +{ + assert(za != NULL); + + zarray_t *zb = (zarray_t*) calloc(1, sizeof(zarray_t)); + zb->el_sz = za->el_sz; + zb->size = za->size; + zb->alloc = za->alloc; + zb->data = (char*) malloc(zb->alloc * zb->el_sz); + memcpy(zb->data, za->data, za->size * za->el_sz); + return zb; +} + +static int iceillog2(int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +/** + * Allocate a new zarray that contains a subset of the original + * elements. NOTE: end index is EXCLUSIVE, that is one past the last + * element you want. + */ +static inline zarray_t *zarray_copy_subset(const zarray_t *za, + int start_idx, + int end_idx_exclusive) +{ + zarray_t *out = (zarray_t*) calloc(1, sizeof(zarray_t)); + out->el_sz = za->el_sz; + out->size = end_idx_exclusive - start_idx; + out->alloc = iceillog2(out->size); // round up pow 2 + out->data = (char*) malloc(out->alloc * out->el_sz); + memcpy(out->data, za->data +(start_idx*out->el_sz), out->size*out->el_sz); + return out; +} + +/** + * Retrieves the number of elements currently being contained by the passed + * array, which may be different from its capacity. The index of the last element + * in the array will be one less than the returned value. + */ +static inline int zarray_size(const zarray_t *za) +{ + assert(za != NULL); + + return za->size; +} + +/** + * Returns 1 if zarray_size(za) == 0, + * returns 0 otherwise. + */ +/* +JUST CALL zarray_size +int zarray_isempty(const zarray_t *za) +{ + assert(za != NULL); + if (za->size <= 0) + return 1; + else + return 0; +} +*/ + + +/** + * Allocates enough internal storage in the supplied variable array structure to + * guarantee that the supplied number of elements (capacity) can be safely stored. + */ +static inline void zarray_ensure_capacity(zarray_t *za, int capacity) +{ + assert(za != NULL); + + if (capacity <= za->alloc) + return; + + while (za->alloc < capacity) { + za->alloc += 8; // use less memory // *= 2; + if (za->alloc < 8) + za->alloc = 8; + } + + za->data = (char*) realloc(za->data, za->alloc * za->el_sz); +} + +/** + * Adds a new element to the end of the supplied array, and sets its value + * (by copying) from the data pointed to by the supplied pointer 'p'. + * Automatically ensures that enough storage space is available for the new element. + */ +static inline void zarray_add(zarray_t *za, const void *p) +{ + assert(za != NULL); + assert(p != NULL); + + zarray_ensure_capacity(za, za->size + 1); + + memcpy(&za->data[za->size*za->el_sz], p, za->el_sz); + za->size++; +} + +/** + * Adds a new element to the end of the supplied array, and sets its value + * (by copying) from the data pointed to by the supplied pointer 'p'. + * Automatically ensures that enough storage space is available for the new element. + */ +static inline void zarray_add_fail_ok(zarray_t *za, const void *p) +{ + assert(za != NULL); + assert(p != NULL); + + if ((za->size + 1) > za->alloc) + { + char *old_data = za->data; + int old_alloc = za->alloc; + + while (za->alloc < (za->size + 1)) { + za->alloc += 8; // use less memory // *= 2; + if (za->alloc < 8) + za->alloc = 8; + } + + za->data = (char*) umm_realloc(za->data, za->alloc * za->el_sz); + + if (!za->data) { + za->data = old_data; + za->alloc = old_alloc; + return; + } + } + + memcpy(&za->data[za->size*za->el_sz], p, za->el_sz); + za->size++; +} + +/** + * Retrieves the element from the supplied array located at the zero-based + * index of 'idx' and copies its value into the variable pointed to by the pointer + * 'p'. + */ +static inline void zarray_get(const zarray_t *za, int idx, void *p) +{ + assert(za != NULL); + assert(p != NULL); + assert(idx >= 0); + assert(idx < za->size); + + memcpy(p, &za->data[idx*za->el_sz], za->el_sz); +} + +/** + * Similar to zarray_get(), but returns a "live" pointer to the internal + * storage, avoiding a memcpy. This pointer is not valid across + * operations which might move memory around (i.e. zarray_remove_value(), + * zarray_remove_index(), zarray_insert(), zarray_sort(), zarray_clear()). + * 'p' should be a pointer to the pointer which will be set to the internal address. + */ +inline static void zarray_get_volatile(const zarray_t *za, int idx, void *p) +{ + assert(za != NULL); + assert(p != NULL); + assert(idx >= 0); + assert(idx < za->size); + + *((void**) p) = &za->data[idx*za->el_sz]; +} + +inline static void zarray_truncate(zarray_t *za, int sz) +{ + assert(za != NULL); + assert(sz <= za->size); + za->size = sz; +} + +/** + * Copies the memory array used internally by zarray to store its owned + * elements to the address pointed by 'buffer'. It is the caller's responsibility + * to allocate zarray_size()*el_sz bytes for the copy to be stored and + * to free the memory when no longer needed. The memory allocated at 'buffer' + * and the internal zarray storage must not overlap. 'buffer_bytes' should be + * the size of the 'buffer' memory space, in bytes, and must be at least + * zarray_size()*el_sz. + * + * Returns the number of bytes copied into 'buffer'. + */ +static inline size_t zarray_copy_data(const zarray_t *za, void *buffer, size_t buffer_bytes) +{ + assert(za != NULL); + assert(buffer != NULL); + assert(buffer_bytes >= za->el_sz * za->size); + memcpy(buffer, za->data, za->el_sz * za->size); + return za->el_sz * za->size; +} + +/** + * Removes the entry at index 'idx'. + * If shuffle is true, the last element in the array will be placed in + * the newly-open space; if false, the zarray is compacted. + */ +static inline void zarray_remove_index(zarray_t *za, int idx, int shuffle) +{ + assert(za != NULL); + assert(idx >= 0); + assert(idx < za->size); + + if (shuffle) { + if (idx < za->size-1) + memcpy(&za->data[idx*za->el_sz], &za->data[(za->size-1)*za->el_sz], za->el_sz); + za->size--; + return; + } else { + // size = 10, idx = 7. Should copy 2 entries (at idx=8 and idx=9). + // size = 10, idx = 9. Should copy 0 entries. + int ncopy = za->size - idx - 1; + if (ncopy > 0) + memmove(&za->data[idx*za->el_sz], &za->data[(idx+1)*za->el_sz], ncopy*za->el_sz); + za->size--; + return; + } +} + +/** + * Remove the entry whose value is equal to the value pointed to by 'p'. + * If shuffle is true, the last element in the array will be placed in + * the newly-open space; if false, the zarray is compacted. At most + * one element will be removed. + * + * Note that objects will be compared using memcmp over the full size + * of the value. If the value is a struct that contains padding, + * differences in the padding bytes can cause comparisons to + * fail. Thus, it remains best practice to bzero all structs so that + * the padding is set to zero. + * + * Returns the number of elements removed (0 or 1). + */ +// remove the entry whose value is equal to the value pointed to by p. +// if shuffle is true, the last element in the array will be placed in +// the newly-open space; if false, the zarray is compacted. +static inline int zarray_remove_value(zarray_t *za, const void *p, int shuffle) +{ + assert(za != NULL); + assert(p != NULL); + + for (int idx = 0; idx < za->size; idx++) { + if (!memcmp(p, &za->data[idx*za->el_sz], za->el_sz)) { + zarray_remove_index(za, idx, shuffle); + return 1; + } + } + + return 0; +} + + +/** + * Creates a new entry and inserts it into the array so that it will have the + * index 'idx' (i.e. before the item which currently has that index). The value + * of the new entry is set to (copied from) the data pointed to by 'p'. 'idx' + * can be one larger than the current max index to place the new item at the end + * of the array, or zero to add it to an empty array. + */ +static inline void zarray_insert(zarray_t *za, int idx, const void *p) +{ + assert(za != NULL); + assert(p != NULL); + assert(idx >= 0); + assert(idx <= za->size); + + zarray_ensure_capacity(za, za->size + 1); + // size = 10, idx = 7. Should copy three entries (idx=7, idx=8, idx=9) + int ncopy = za->size - idx; + + memmove(&za->data[(idx+1)*za->el_sz], &za->data[idx*za->el_sz], ncopy*za->el_sz); + memcpy(&za->data[idx*za->el_sz], p, za->el_sz); + + za->size++; +} + + +/** + * Sets the value of the current element at index 'idx' by copying its value from + * the data pointed to by 'p'. The previous value of the changed element will be + * copied into the data pointed to by 'outp' if it is not null. + */ +static inline void zarray_set(zarray_t *za, int idx, const void *p, void *outp) +{ + assert(za != NULL); + assert(p != NULL); + assert(idx >= 0); + assert(idx < za->size); + + if (outp != NULL) + memcpy(outp, &za->data[idx*za->el_sz], za->el_sz); + + memcpy(&za->data[idx*za->el_sz], p, za->el_sz); +} + +/** + * Calls the supplied function for every element in the array in index order. + * The map function will be passed a pointer to each element in turn and must + * have the following format: + * + * void map_function(element_type *element) + */ +static inline void zarray_map(zarray_t *za, void (*f)(void*)) +{ + assert(za != NULL); + assert(f != NULL); + + for (int idx = 0; idx < za->size; idx++) + f(&za->data[idx*za->el_sz]); +} + +/** + * Calls the supplied function for every element in the array in index order. + * HOWEVER values are passed to the function, not pointers to values. In the + * case where the zarray stores object pointers, zarray_vmap allows you to + * pass in the object's destroy function (or free) directly. Can only be used + * with zarray's which contain pointer data. The map function should have the + * following format: + * + * void map_function(element_type *element) + */ + void zarray_vmap(zarray_t *za, void (*f)()); + +/** + * Removes all elements from the array and sets its size to zero. Pointers to + * any data elements obtained i.e. by zarray_get_volatile() will no longer be + * valid. + */ +static inline void zarray_clear(zarray_t *za) +{ + assert(za != NULL); + za->size = 0; +} + +/** + * Determines whether any element in the array has a value which matches the + * data pointed to by 'p'. + * + * Returns 1 if a match was found anywhere in the array, else 0. + */ +static inline int zarray_contains(const zarray_t *za, const void *p) +{ + assert(za != NULL); + assert(p != NULL); + + for (int idx = 0; idx < za->size; idx++) { + if (!memcmp(p, &za->data[idx*za->el_sz], za->el_sz)) { + return 1; + } + } + + return 0; +} + +/** + * Uses qsort() to sort the elements contained by the array in ascending order. + * Uses the supplied comparison function to determine the appropriate order. + * + * The comparison function will be passed a pointer to two elements to be compared + * and should return a measure of the difference between them (see strcmp()). + * I.e. it should return a negative number if the first element is 'less than' + * the second, zero if they are equivalent, and a positive number if the first + * element is 'greater than' the second. The function should have the following format: + * + * int comparison_function(const element_type *first, const element_type *second) + * + * zstrcmp() can be used as the comparison function for string elements, which + * will call strcmp() internally. + */ +static inline void zarray_sort(zarray_t *za, int (*compar)(const void*, const void*)) +{ + assert(za != NULL); + assert(compar != NULL); + if (za->size == 0) + return; + + qsort(za->data, za->size, za->el_sz, compar); +} + +/** + * A comparison function for comparing strings which can be used by zarray_sort() + * to sort arrays with char* elements. + */ + int zstrcmp(const void * a_pp, const void * b_pp); + +/** + * Find the index of an element, or return -1 if not found. Remember that p is + * a pointer to the element. + **/ +// returns -1 if not in array. Remember p is a pointer to the item. +static inline int zarray_index_of(const zarray_t *za, const void *p) +{ + assert(za != NULL); + assert(p != NULL); + + for (int i = 0; i < za->size; i++) { + if (!memcmp(p, &za->data[i*za->el_sz], za->el_sz)) + return i; + } + + return -1; +} + + + +/** + * Add all elements from 'source' into 'dest'. el_size must be the same + * for both lists + **/ +static inline void zarray_add_all(zarray_t * dest, const zarray_t * source) +{ + assert(dest->el_sz == source->el_sz); + + // Don't allocate on stack because el_sz could be larger than ~8 MB + // stack size + char *tmp = (char*)calloc(1, dest->el_sz); + + for (int i = 0; i < zarray_size(source); i++) { + zarray_get(source, i, tmp); + zarray_add(dest, tmp); + } + + free(tmp); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "zarray.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +int zstrcmp(const void * a_pp, const void * b_pp) +{ + assert(a_pp != NULL); + assert(b_pp != NULL); + + char * a = *(void**)a_pp; + char * b = *(void**)b_pp; + + return strcmp(a,b); +} + +void zarray_vmap(zarray_t *za, void (*f)()) +{ + assert(za != NULL); + assert(f != NULL); + assert(za->el_sz == sizeof(void*)); + + for (int idx = 0; idx < za->size; idx++) { + void *pp = &za->data[idx*za->el_sz]; + void *p = *(void**) pp; + f(p); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "math_util.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef M_TWOPI +# define M_TWOPI 6.2831853071795862319959 /* 2*pi */ +#endif + +#ifndef M_PI +# define M_PI 3.141592653589793238462643383279502884196 +#endif + +#define to_radians(x) ( (x) * (M_PI / 180.0 )) +#define to_degrees(x) ( (x) * (180.0 / M_PI )) + +#define max(A, B) (A < B ? B : A) +#define min(A, B) (A < B ? A : B) + + /* DEPRECATE, threshold meaningless without context. +static inline int dequals(double a, double b) +{ + double thresh = 1e-9; + return (fabs(a-b) < thresh); +} + */ + +static inline int dequals_mag(double a, double b, double thresh) +{ + return (fabs(a-b) < thresh); +} + +static inline int isq(int v) +{ + return v*v; +} + +static inline float fsq(float v) +{ + return v*v; +} + +static inline double sq(double v) +{ + return v*v; +} + +static inline double sgn(double v) +{ + return (v>=0) ? 1 : -1; +} + +// random number between [0, 1) +static inline float randf() +{ + return ((float) rand()) / (RAND_MAX + 1.0); +} + + +static inline float signed_randf() +{ + return randf()*2 - 1; +} + +// return a random integer between [0, bound) +static inline int irand(int bound) +{ + int v = (int) (randf()*bound); + if (v == bound) + return (bound-1); + //assert(v >= 0); + //assert(v < bound); + return v; +} + +/** Map vin to [0, 2*PI) **/ +static inline double mod2pi_positive(double vin) +{ + return vin - M_TWOPI * floor(vin / M_TWOPI); +} + +/** Map vin to [-PI, PI) **/ +static inline double mod2pi(double vin) +{ + return mod2pi_positive(vin + M_PI) - M_PI; +} + +/** Return vin such that it is within PI degrees of ref **/ +static inline double mod2pi_ref(double ref, double vin) +{ + return ref + mod2pi(vin - ref); +} + +/** Map vin to [0, 360) **/ +static inline double mod360_positive(double vin) +{ + return vin - 360 * floor(vin / 360); +} + +/** Map vin to [-180, 180) **/ +static inline double mod360(double vin) +{ + return mod360_positive(vin + 180) - 180; +} + +static inline int theta_to_int(double theta, int max) +{ + theta = mod2pi_ref(M_PI, theta); + int v = (int) (theta / M_TWOPI * max); + + if (v == max) + v = 0; + + assert (v >= 0 && v < max); + + return v; +} + +static inline int imin(int a, int b) +{ + return (a < b) ? a : b; +} + +static inline int imax(int a, int b) +{ + return (a > b) ? a : b; +} + +static inline int64_t imin64(int64_t a, int64_t b) +{ + return (a < b) ? a : b; +} + +static inline int64_t imax64(int64_t a, int64_t b) +{ + return (a > b) ? a : b; +} + +static inline int iclamp(int v, int minv, int maxv) +{ + return imax(minv, imin(v, maxv)); +} + +static inline double dclamp(double a, double min, double max) +{ + if (a < min) + return min; + if (a > max) + return max; + return a; +} + +static inline int fltcmp (float f1, float f2) +{ + float epsilon = f1-f2; + if (epsilon < 0.0) + return -1; + else if (epsilon > 0.0) + return 1; + else + return 0; +} + +static inline int dblcmp (double d1, double d2) +{ + double epsilon = d1-d2; + if (epsilon < 0.0) + return -1; + else if (epsilon > 0.0) + return 1; + else + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "svd22.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void svd22(const double A[4], double U[4], double S[2], double V[4]); + +// for the matrix [a b; b d] +void svd_sym_singular_values(double A00, double A01, double A11, + double *Lmin, double *Lmax); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "svd22.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** SVD 2x2. + + Computes singular values and vectors without squaring the input + matrix. With double precision math, results are accurate to about + 1E-16. + + U = [ cos(theta) -sin(theta) ] + [ sin(theta) cos(theta) ] + + S = [ e 0 ] + [ 0 f ] + + V = [ cos(phi) -sin(phi) ] + [ sin(phi) cos(phi) ] + + + Our strategy is basically to analytically multiply everything out + and then rearrange so that we can solve for theta, phi, e, and + f. (Derivation by ebolson@umich.edu 5/2016) + + V' = [ CP SP ] + [ -SP CP ] + +USV' = [ CT -ST ][ e*CP e*SP ] + [ ST CT ][ -f*SP f*CP ] + + = [e*CT*CP + f*ST*SP e*CT*SP - f*ST*CP ] + [e*ST*CP - f*SP*CT e*SP*ST + f*CP*CT ] + +A00+A11 = e*CT*CP + f*ST*SP + e*SP*ST + f*CP*CT + = e*(CP*CT + SP*ST) + f*(SP*ST + CP*CT) + = (e+f)(CP*CT + SP*ST) +B0 = (e+f)*cos(P-T) + +A00-A11 = e*CT*CP + f*ST*SP - e*SP*ST - f*CP*CT + = e*(CP*CT - SP*ST) - f*(-ST*SP + CP*CT) + = (e-f)(CP*CT - SP*ST) +B1 = (e-f)*cos(P+T) + +A01+A10 = e*CT*SP - f*ST*CP + e*ST*CP - f*SP*CT + = e(CT*SP + ST*CP) - f*(ST*CP + SP*CT) + = (e-f)*(CT*SP + ST*CP) +B2 = (e-f)*sin(P+T) + +A01-A10 = e*CT*SP - f*ST*CP - e*ST*CP + f*SP*CT + = e*(CT*SP - ST*CP) + f(SP*CT - ST*CP) + = (e+f)*(CT*SP - ST*CP) +B3 = (e+f)*sin(P-T) + +B0 = (e+f)*cos(P-T) +B1 = (e-f)*cos(P+T) +B2 = (e-f)*sin(P+T) +B3 = (e+f)*sin(P-T) + +B3/B0 = tan(P-T) + +B2/B1 = tan(P+T) + **/ +void svd22(const double A[4], double U[4], double S[2], double V[4]) +{ + double A00 = A[0]; + double A01 = A[1]; + double A10 = A[2]; + double A11 = A[3]; + + double B0 = A00 + A11; + double B1 = A00 - A11; + double B2 = A01 + A10; + double B3 = A01 - A10; + + double PminusT = atan2(B3, B0); + double PplusT = atan2(B2, B1); + + double P = (PminusT + PplusT) / 2; + double T = (-PminusT + PplusT) / 2; + + double CP = cos(P), SP = sin(P); + double CT = cos(T), ST = sin(T); + + U[0] = CT; + U[1] = -ST; + U[2] = ST; + U[3] = CT; + + V[0] = CP; + V[1] = -SP; + V[2] = SP; + V[3] = CP; + + // C0 = e+f. There are two ways to compute C0; we pick the one + // that is better conditioned. + double CPmT = cos(P-T), SPmT = sin(P-T); + double C0 = 0; + if (fabs(CPmT) > fabs(SPmT)) + C0 = B0 / CPmT; + else + C0 = B3 / SPmT; + + // C1 = e-f. There are two ways to compute C1; we pick the one + // that is better conditioned. + double CPpT = cos(P+T), SPpT = sin(P+T); + double C1 = 0; + if (fabs(CPpT) > fabs(SPpT)) + C1 = B1 / CPpT; + else + C1 = B2 / SPpT; + + // e and f are the singular values + double e = (C0 + C1) / 2; + double f = (C0 - C1) / 2; + + if (e < 0) { + e = -e; + U[0] = -U[0]; + U[2] = -U[2]; + } + + if (f < 0) { + f = -f; + U[1] = -U[1]; + U[3] = -U[3]; + } + + // sort singular values. + if (e > f) { + // already in big-to-small order. + S[0] = e; + S[1] = f; + } else { + // Curiously, this code never seems to get invoked. Why is it + // that S[0] always ends up the dominant vector? However, + // this code has been tested (flipping the logic forces us to + // sort the singular values in ascending order). + // + // P = [ 0 1 ; 1 0 ] + // USV' = (UP)(PSP)(PV') + // = (UP)(PSP)(VP)' + // = (UP)(PSP)(P'V')' + S[0] = f; + S[1] = e; + + // exchange columns of U and V + double tmp[2]; + tmp[0] = U[0]; + tmp[1] = U[2]; + U[0] = U[1]; + U[2] = U[3]; + U[1] = tmp[0]; + U[3] = tmp[1]; + + tmp[0] = V[0]; + tmp[1] = V[2]; + V[0] = V[1]; + V[2] = V[3]; + V[1] = tmp[0]; + V[3] = tmp[1]; + } + + /* + double SM[4] = { S[0], 0, 0, S[1] }; + + doubles_print_mat(U, 2, 2, "%20.10g"); + doubles_print_mat(SM, 2, 2, "%20.10g"); + doubles_print_mat(V, 2, 2, "%20.10g"); + printf("A:\n"); + doubles_print_mat(A, 2, 2, "%20.10g"); + + double SVt[4]; + doubles_mat_ABt(SM, 2, 2, V, 2, 2, SVt, 2, 2); + double USVt[4]; + doubles_mat_AB(U, 2, 2, SVt, 2, 2, USVt, 2, 2); + + printf("USVt\n"); + doubles_print_mat(USVt, 2, 2, "%20.10g"); + + double diff[4]; + for (int i = 0; i < 4; i++) + diff[i] = A[i] - USVt[i]; + + printf("diff\n"); + doubles_print_mat(diff, 2, 2, "%20.10g"); + + */ + +} + + +// for the matrix [a b; b d] +void svd_sym_singular_values(double A00, double A01, double A11, + double *Lmin, double *Lmax) +{ + double A10 = A01; + + double B0 = A00 + A11; + double B1 = A00 - A11; + double B2 = A01 + A10; + double B3 = A01 - A10; + + double PminusT = atan2(B3, B0); + double PplusT = atan2(B2, B1); + + double P = (PminusT + PplusT) / 2; + double T = (-PminusT + PplusT) / 2; + + // C0 = e+f. There are two ways to compute C0; we pick the one + // that is better conditioned. + double CPmT = cos(P-T), SPmT = sin(P-T); + double C0 = 0; + if (fabs(CPmT) > fabs(SPmT)) + C0 = B0 / CPmT; + else + C0 = B3 / SPmT; + + // C1 = e-f. There are two ways to compute C1; we pick the one + // that is better conditioned. + double CPpT = cos(P+T), SPpT = sin(P+T); + double C1 = 0; + if (fabs(CPpT) > fabs(SPpT)) + C1 = B1 / CPpT; + else + C1 = B2 / SPpT; + + // e and f are the singular values + double e = (C0 + C1) / 2; + double f = (C0 - C1) / 2; + + *Lmin = fmin(e, f); + *Lmax = fmax(e, f); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "matd.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Defines a matrix structure for holding double-precision values with + * data in row-major order (i.e. index = row*ncols + col). + * + * nrows and ncols are 1-based counts with the exception that a scalar (non-matrix) + * is represented with nrows=0 and/or ncols=0. + */ +typedef struct +{ + unsigned int nrows, ncols; + double data[]; +// double *data; +} matd_t; + +#define MATD_ALLOC(name, nrows, ncols) double name ## _storage [nrows*ncols]; matd_t name = { .nrows = nrows, .ncols = ncols, .data = &name ## _storage }; + +/** + * Defines a small value which can be used in place of zero for approximating + * calculations which are singular at zero values (i.e. inverting a matrix with + * a zero or near-zero determinant). + */ +#define MATD_EPS 1e-8 + +/** + * A macro to reference a specific matd_t data element given it's zero-based + * row and column indexes. Suitable for both retrieval and assignment. + */ +#define MATD_EL(m, row, col) (m)->data[((row)*(m)->ncols + (col))] + +/** + * Creates a double matrix with the given number of rows and columns (or a scalar + * in the case where rows=0 and/or cols=0). All data elements will be initialized + * to zero. It is the caller's responsibility to call matd_destroy() on the + * returned matrix. + */ +matd_t *matd_create(int rows, int cols); + +/** + * Creates a double matrix with the given number of rows and columns (or a scalar + * in the case where rows=0 and/or cols=0). All data elements will be initialized + * using the supplied array of data, which must contain at least rows*cols elements, + * arranged in row-major order (i.e. index = row*ncols + col). It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + */ +matd_t *matd_create_data(int rows, int cols, const double *data); + +/** + * Creates a double matrix with the given number of rows and columns (or a scalar + * in the case where rows=0 and/or cols=0). All data elements will be initialized + * using the supplied array of float data, which must contain at least rows*cols elements, + * arranged in row-major order (i.e. index = row*ncols + col). It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + */ +matd_t *matd_create_dataf(int rows, int cols, const float *data); + +/** + * Creates a square identity matrix with the given number of rows (and + * therefore columns), or a scalar with value 1 in the case where dim=0. + * It is the caller's responsibility to call matd_destroy() on the + * returned matrix. + */ +matd_t *matd_identity(int dim); + +/** + * Creates a scalar with the supplied value 'v'. It is the caller's responsibility + * to call matd_destroy() on the returned matrix. + * + * NOTE: Scalars are different than 1x1 matrices (implementation note: + * they are encoded as 0x0 matrices). For example: for matrices A*B, A + * and B must both have specific dimensions. However, if A is a + * scalar, there are no restrictions on the size of B. + */ +matd_t *matd_create_scalar(double v); + +/** + * Retrieves the cell value for matrix 'm' at the given zero-based row and column index. + * Performs more thorough validation checking than MATD_EL(). + */ +double matd_get(const matd_t *m, int row, int col); + +/** + * Assigns the given value to the matrix cell at the given zero-based row and + * column index. Performs more thorough validation checking than MATD_EL(). + */ +void matd_put(matd_t *m, int row, int col, double value); + +/** + * Retrieves the scalar value of the given element ('m' must be a scalar). + * Performs more thorough validation checking than MATD_EL(). + */ +double matd_get_scalar(const matd_t *m); + +/** + * Assigns the given value to the supplied scalar element ('m' must be a scalar). + * Performs more thorough validation checking than MATD_EL(). + */ +void matd_put_scalar(matd_t *m, double value); + +/** + * Creates an exact copy of the supplied matrix 'm'. It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + */ +matd_t *matd_copy(const matd_t *m); + +/** + * Creates a copy of a subset of the supplied matrix 'a'. The subset will include + * rows 'r0' through 'r1', inclusive ('r1' >= 'r0'), and columns 'c0' through 'c1', + * inclusive ('c1' >= 'c0'). All parameters are zero-based (i.e. matd_select(a, 0, 0, 0, 0) + * will return only the first cell). Cannot be used on scalars or to extend + * beyond the number of rows/columns of 'a'. It is the caller's responsibility to + * call matd_destroy() on the returned matrix. + */ +matd_t *matd_select(const matd_t *a, int r0, int r1, int c0, int c1); + +/** + * Prints the supplied matrix 'm' to standard output by applying the supplied + * printf format specifier 'fmt' for each individual element. Each row will + * be printed on a separate newline. + */ +void matd_print(const matd_t *m, const char *fmt); + +/** + * Prints the transpose of the supplied matrix 'm' to standard output by applying + * the supplied printf format specifier 'fmt' for each individual element. Each + * row will be printed on a separate newline. + */ +void matd_print_transpose(const matd_t *m, const char *fmt); + +/** + * Adds the two supplied matrices together, cell-by-cell, and returns the results + * as a new matrix of the same dimensions. The supplied matrices must have + * identical dimensions. It is the caller's responsibility to call matd_destroy() + * on the returned matrix. + */ +matd_t *matd_add(const matd_t *a, const matd_t *b); + +/** + * Adds the values of 'b' to matrix 'a', cell-by-cell, and overwrites the + * contents of 'a' with the results. The supplied matrices must have + * identical dimensions. + */ +void matd_add_inplace(matd_t *a, const matd_t *b); + +/** + * Subtracts matrix 'b' from matrix 'a', cell-by-cell, and returns the results + * as a new matrix of the same dimensions. The supplied matrices must have + * identical dimensions. It is the caller's responsibility to call matd_destroy() + * on the returned matrix. + */ +matd_t *matd_subtract(const matd_t *a, const matd_t *b); + +/** + * Subtracts the values of 'b' from matrix 'a', cell-by-cell, and overwrites the + * contents of 'a' with the results. The supplied matrices must have + * identical dimensions. + */ +void matd_subtract_inplace(matd_t *a, const matd_t *b); + +/** + * Scales all cell values of matrix 'a' by the given scale factor 's' and + * returns the result as a new matrix of the same dimensions. It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + */ +matd_t *matd_scale(const matd_t *a, double s); + +/** + * Scales all cell values of matrix 'a' by the given scale factor 's' and + * overwrites the contents of 'a' with the results. + */ +void matd_scale_inplace(matd_t *a, double s); + +/** + * Multiplies the two supplied matrices together (matrix product), and returns the + * results as a new matrix. The supplied matrices must have dimensions such that + * columns(a) = rows(b). The returned matrix will have a row count of rows(a) + * and a column count of columns(b). It is the caller's responsibility to call + * matd_destroy() on the returned matrix. + */ +matd_t *matd_multiply(const matd_t *a, const matd_t *b); + +/** + * Creates a matrix which is the transpose of the supplied matrix 'a'. It is the + * caller's responsibility to call matd_destroy() on the returned matrix. + */ +matd_t *matd_transpose(const matd_t *a); + +/** + * Calculates the determinant of the supplied matrix 'a'. + */ +double matd_det(const matd_t *a); + +/** + * Attempts to compute an inverse of the supplied matrix 'a' and return it as + * a new matrix. This is strictly only possible if the determinant of 'a' is + * non-zero (matd_det(a) != 0). + * + * If the determinant is zero, NULL is returned. It is otherwise the + * caller's responsibility to cope with the results caused by poorly + * conditioned matrices. (E.g.., if such a situation is likely to arise, compute + * the pseudo-inverse from the SVD.) + **/ +matd_t *matd_inverse(const matd_t *a); + +static inline void matd_set_data(matd_t *m, const double *data) +{ + memcpy(m->data, data, m->nrows * m->ncols * sizeof(double)); +} + +/** + * Determines whether the supplied matrix 'a' is a scalar (positive return) or + * not (zero return, indicating a matrix of dimensions at least 1x1). + */ +static inline int matd_is_scalar(const matd_t *a) +{ + assert(a != NULL); + return a->ncols == 0 || a->nrows == 0; +} + +/** + * Determines whether the supplied matrix 'a' is a row or column vector + * (positive return) or not (zero return, indicating either 'a' is a scalar or a + * matrix with at least one dimension > 1). + */ +static inline int matd_is_vector(const matd_t *a) +{ + assert(a != NULL); + return a->ncols == 1 || a->nrows == 1; +} + +/** + * Determines whether the supplied matrix 'a' is a row or column vector + * with a dimension of 'len' (positive return) or not (zero return). + */ +static inline int matd_is_vector_len(const matd_t *a, int len) +{ + assert(a != NULL); + return (a->ncols == 1 && a->nrows == len) || (a->ncols == len && a->nrows == 1); +} + +/** + * Calculates the magnitude of the supplied matrix 'a'. + */ +double matd_vec_mag(const matd_t *a); + +/** + * Calculates the magnitude of the distance between the points represented by + * matrices 'a' and 'b'. Both 'a' and 'b' must be vectors and have the same + * dimension (although one may be a row vector and one may be a column vector). + */ +double matd_vec_dist(const matd_t *a, const matd_t *b); + + +/** + * Same as matd_vec_dist, but only uses the first 'n' terms to compute distance + */ +double matd_vec_dist_n(const matd_t *a, const matd_t *b, int n); + +/** + * Calculates the dot product of two vectors. Both 'a' and 'b' must be vectors + * and have the same dimension (although one may be a row vector and one may be + * a column vector). + */ +double matd_vec_dot_product(const matd_t *a, const matd_t *b); + +/** + * Calculates the normalization of the supplied vector 'a' (i.e. a unit vector + * of the same dimension and orientation as 'a' with a magnitude of 1) and returns + * it as a new vector. 'a' must be a vector of any dimension and must have a + * non-zero magnitude. It is the caller's responsibility to call matd_destroy() + * on the returned matrix. + */ +matd_t *matd_vec_normalize(const matd_t *a); + +/** + * Calculates the cross product of supplied matrices 'a' and 'b' (i.e. a x b) + * and returns it as a new matrix. Both 'a' and 'b' must be vectors of dimension + * 3, but can be either row or column vectors. It is the caller's responsibility + * to call matd_destroy() on the returned matrix. + */ +matd_t *matd_crossproduct(const matd_t *a, const matd_t *b); + +double matd_err_inf(const matd_t *a, const matd_t *b); + +/** + * Creates a new matrix by applying a series of matrix operations, as expressed + * in 'expr', to the supplied list of matrices. Each matrix to be operated upon + * must be represented in the expression by a separate matrix placeholder, 'M', + * and there must be one matrix supplied as an argument for each matrix + * placeholder in the expression. All rules and caveats of the corresponding + * matrix operations apply to the operated-on matrices. It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + * + * Available operators (in order of increasing precedence): + * M+M add two matrices together + * M-M subtract one matrix from another + * M*M multiply to matrices together (matrix product) + * MM multiply to matrices together (matrix product) + * -M negate a matrix + * M^-1 take the inverse of a matrix + * M' take the transpose of a matrix + * + * Expressions can be combined together and grouped by enclosing them in + * parenthesis, i.e.: + * -M(M+M+M)-(M*M)^-1 + * + * Scalar values can be generated on-the-fly, i.e.: + * M*2.2 scales M by 2.2 + * -2+M adds -2 to all elements of M + * + * All whitespace in the expression is ignored. + */ +matd_t *matd_op(const char *expr, ...); + +/** + * Frees the memory associated with matrix 'm', being the result of an earlier + * call to a matd_*() function, after which 'm' will no longer be usable. + */ +void matd_destroy(matd_t *m); + +typedef struct +{ + matd_t *U; + matd_t *S; + matd_t *V; +} matd_svd_t; + +/** Compute a complete SVD of a matrix. The SVD exists for all + * matrices. For a matrix MxN, we will have: + * + * A = U*S*V' + * + * where A is MxN, U is MxM (and is an orthonormal basis), S is MxN + * (and is diagonal up to machine precision), and V is NxN (and is an + * orthonormal basis). + * + * The caller is responsible for destroying U, S, and V. + **/ +matd_svd_t matd_svd(matd_t *A); + +#define MATD_SVD_NO_WARNINGS 1 + matd_svd_t matd_svd_flags(matd_t *A, int flags); + +//////////////////////////////// +// PLU Decomposition + +// All square matrices (even singular ones) have a partially-pivoted +// LU decomposition such that A = PLU, where P is a permutation +// matrix, L is a lower triangular matrix, and U is an upper +// triangular matrix. +// +typedef struct +{ + // was the input matrix singular? When a zero pivot is found, this + // flag is set to indicate that this has happened. + int singular; + + unsigned int *piv; // permutation indices + int pivsign; // either +1 or -1 + + // The matd_plu_t object returned "owns" the enclosed LU matrix. It + // is not expected that the returned object is itself useful to + // users: it contains the L and U information all smushed + // together. + matd_t *lu; // combined L and U matrices, permuted so they can be triangular. +} matd_plu_t; + +matd_plu_t *matd_plu(const matd_t *a); +void matd_plu_destroy(matd_plu_t *mlu); +double matd_plu_det(const matd_plu_t *lu); +matd_t *matd_plu_p(const matd_plu_t *lu); +matd_t *matd_plu_l(const matd_plu_t *lu); +matd_t *matd_plu_u(const matd_plu_t *lu); +matd_t *matd_plu_solve(const matd_plu_t *mlu, const matd_t *b); + +// uses LU decomposition internally. +matd_t *matd_solve(matd_t *A, matd_t *b); + +//////////////////////////////// +// Cholesky Factorization + +/** + * Creates a double matrix with the Cholesky lower triangular matrix + * of A. A must be symmetric, positive definite. It is the caller's + * responsibility to call matd_destroy() on the returned matrix. + */ +//matd_t *matd_cholesky(const matd_t *A); + +typedef struct +{ + int is_spd; + matd_t *u; +} matd_chol_t; + +matd_chol_t *matd_chol(matd_t *A); +matd_t *matd_chol_solve(const matd_chol_t *chol, const matd_t *b); +void matd_chol_destroy(matd_chol_t *chol); +// only sensible on PSD matrices +matd_t *matd_chol_inverse(matd_t *a); + +void matd_ltransposetriangle_solve(matd_t *u, const double *b, double *x); +void matd_ltriangle_solve(matd_t *u, const double *b, double *x); +void matd_utriangle_solve(matd_t *u, const double *b, double *x); + + +double matd_max(matd_t *m); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "matd.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// a matd_t with rows=0 cols=0 is a SCALAR. + +// to ease creating mati, matf, etc. in the future. +#define TYPE double + +matd_t *matd_create(int rows, int cols) +{ + assert(rows >= 0); + assert(cols >= 0); + + if (rows == 0 || cols == 0) + return matd_create_scalar(0); + + matd_t *m = calloc(1, sizeof(matd_t) + (rows*cols*sizeof(double))); + m->nrows = rows; + m->ncols = cols; + + return m; +} + +matd_t *matd_create_scalar(TYPE v) +{ + matd_t *m = calloc(1, sizeof(matd_t) + sizeof(double)); + m->nrows = 0; + m->ncols = 0; + m->data[0] = v; + + return m; +} + +matd_t *matd_create_data(int rows, int cols, const TYPE *data) +{ + if (rows == 0 || cols == 0) + return matd_create_scalar(data[0]); + + matd_t *m = matd_create(rows, cols); + for (int i = 0; i < rows * cols; i++) + m->data[i] = data[i]; + + return m; +} + +matd_t *matd_create_dataf(int rows, int cols, const float *data) +{ + if (rows == 0 || cols == 0) + return matd_create_scalar(data[0]); + + matd_t *m = matd_create(rows, cols); + for (int i = 0; i < rows * cols; i++) + m->data[i] = (double)data[i]; + + return m; +} + +matd_t *matd_identity(int dim) +{ + if (dim == 0) + return matd_create_scalar(1); + + matd_t *m = matd_create(dim, dim); + for (int i = 0; i < dim; i++) + MATD_EL(m, i, i) = 1; + + return m; +} + +// row and col are zero-based +TYPE matd_get(const matd_t *m, int row, int col) +{ + assert(m != NULL); + assert(!matd_is_scalar(m)); + assert(row >= 0); + assert(row < m->nrows); + assert(col >= 0); + assert(col < m->ncols); + + return MATD_EL(m, row, col); +} + +// row and col are zero-based +void matd_put(matd_t *m, int row, int col, TYPE value) +{ + assert(m != NULL); + + if (matd_is_scalar(m)) { + matd_put_scalar(m, value); + return; + } + + assert(row >= 0); + assert(row < m->nrows); + assert(col >= 0); + assert(col < m->ncols); + + MATD_EL(m, row, col) = value; +} + +TYPE matd_get_scalar(const matd_t *m) +{ + assert(m != NULL); + assert(matd_is_scalar(m)); + + return (m->data[0]); +} + +void matd_put_scalar(matd_t *m, TYPE value) +{ + assert(m != NULL); + assert(matd_is_scalar(m)); + + m->data[0] = value; +} + +matd_t *matd_copy(const matd_t *m) +{ + assert(m != NULL); + + matd_t *x = matd_create(m->nrows, m->ncols); + if (matd_is_scalar(m)) + x->data[0] = m->data[0]; + else + memcpy(x->data, m->data, sizeof(TYPE)*m->ncols*m->nrows); + + return x; +} + +matd_t *matd_select(const matd_t * a, int r0, int r1, int c0, int c1) +{ + assert(a != NULL); + + assert(r0 >= 0 && r0 < a->nrows); + assert(c0 >= 0 && c0 < a->ncols); + + int nrows = r1 - r0 + 1; + int ncols = c1 - c0 + 1; + + matd_t * r = matd_create(nrows, ncols); + + for (int row = r0; row <= r1; row++) + for (int col = c0; col <= c1; col++) + MATD_EL(r,row-r0,col-c0) = MATD_EL(a,row,col); + + return r; +} + +void matd_print(const matd_t *m, const char *fmt) +{ + assert(m != NULL); + assert(fmt != NULL); + + if (matd_is_scalar(m)) { + printf(fmt, MATD_EL(m, 0, 0)); + printf("\n"); + } else { + for (int i = 0; i < m->nrows; i++) { + for (int j = 0; j < m->ncols; j++) { + printf(fmt, MATD_EL(m, i, j)); + } + printf("\n"); + } + } +} + +void matd_print_transpose(const matd_t *m, const char *fmt) +{ + assert(m != NULL); + assert(fmt != NULL); + + if (matd_is_scalar(m)) { + printf(fmt, MATD_EL(m, 0, 0)); + printf("\n"); + } else { + for (int j = 0; j < m->ncols; j++) { + for (int i = 0; i < m->nrows; i++) { + printf(fmt, MATD_EL(m, i, j)); + } + printf("\n"); + } + } +} + +void matd_destroy(matd_t *m) +{ + if (!m) + return; + + assert(m != NULL); + free(m); +} + +matd_t *matd_multiply(const matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + + if (matd_is_scalar(a)) + return matd_scale(b, a->data[0]); + if (matd_is_scalar(b)) + return matd_scale(a, b->data[0]); + + assert(a->ncols == b->nrows); + matd_t *m = matd_create(a->nrows, b->ncols); + + for (int i = 0; i < m->nrows; i++) { + for (int j = 0; j < m->ncols; j++) { + TYPE acc = 0; + for (int k = 0; k < a->ncols; k++) { + acc += MATD_EL(a, i, k) * MATD_EL(b, k, j); + } + MATD_EL(m, i, j) = acc; + } + } + + return m; +} + +matd_t *matd_scale(const matd_t *a, double s) +{ + assert(a != NULL); + + if (matd_is_scalar(a)) + return matd_create_scalar(a->data[0] * s); + + matd_t *m = matd_create(a->nrows, a->ncols); + + for (int i = 0; i < m->nrows; i++) { + for (int j = 0; j < m->ncols; j++) { + MATD_EL(m, i, j) = s * MATD_EL(a, i, j); + } + } + + return m; +} + +void matd_scale_inplace(matd_t *a, double s) +{ + assert(a != NULL); + + if (matd_is_scalar(a)) { + a->data[0] *= s; + return; + } + + for (int i = 0; i < a->nrows; i++) { + for (int j = 0; j < a->ncols; j++) { + MATD_EL(a, i, j) *= s; + } + } +} + +matd_t *matd_add(const matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(a->nrows == b->nrows); + assert(a->ncols == b->ncols); + + if (matd_is_scalar(a)) + return matd_create_scalar(a->data[0] + b->data[0]); + + matd_t *m = matd_create(a->nrows, a->ncols); + + for (int i = 0; i < m->nrows; i++) { + for (int j = 0; j < m->ncols; j++) { + MATD_EL(m, i, j) = MATD_EL(a, i, j) + MATD_EL(b, i, j); + } + } + + return m; +} + +void matd_add_inplace(matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(a->nrows == b->nrows); + assert(a->ncols == b->ncols); + + if (matd_is_scalar(a)) { + a->data[0] += b->data[0]; + return; + } + + for (int i = 0; i < a->nrows; i++) { + for (int j = 0; j < a->ncols; j++) { + MATD_EL(a, i, j) += MATD_EL(b, i, j); + } + } +} + + +matd_t *matd_subtract(const matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(a->nrows == b->nrows); + assert(a->ncols == b->ncols); + + if (matd_is_scalar(a)) + return matd_create_scalar(a->data[0] - b->data[0]); + + matd_t *m = matd_create(a->nrows, a->ncols); + + for (int i = 0; i < m->nrows; i++) { + for (int j = 0; j < m->ncols; j++) { + MATD_EL(m, i, j) = MATD_EL(a, i, j) - MATD_EL(b, i, j); + } + } + + return m; +} + +void matd_subtract_inplace(matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(a->nrows == b->nrows); + assert(a->ncols == b->ncols); + + if (matd_is_scalar(a)) { + a->data[0] -= b->data[0]; + return; + } + + for (int i = 0; i < a->nrows; i++) { + for (int j = 0; j < a->ncols; j++) { + MATD_EL(a, i, j) -= MATD_EL(b, i, j); + } + } +} + + +matd_t *matd_transpose(const matd_t *a) +{ + assert(a != NULL); + + if (matd_is_scalar(a)) + return matd_create_scalar(a->data[0]); + + matd_t *m = matd_create(a->ncols, a->nrows); + + for (int i = 0; i < a->nrows; i++) { + for (int j = 0; j < a->ncols; j++) { + MATD_EL(m, j, i) = MATD_EL(a, i, j); + } + } + return m; +} + +static +double matd_det_general(const matd_t *a) +{ + // Use LU decompositon to calculate the determinant + matd_plu_t *mlu = matd_plu(a); + matd_t *L = matd_plu_l(mlu); + matd_t *U = matd_plu_u(mlu); + + // The determinants of the L and U matrices are the products of + // their respective diagonal elements + double detL = 1; double detU = 1; + for (int i = 0; i < a->nrows; i++) { + detL *= matd_get(L, i, i); + detU *= matd_get(U, i, i); + } + + // The determinant of a can be calculated as + // epsilon*det(L)*det(U), + // where epsilon is just the sign of the corresponding permutation + // (which is +1 for an even number of permutations and is −1 + // for an uneven number of permutations). + double det = mlu->pivsign * detL * detU; + + // Cleanup + matd_plu_destroy(mlu); + matd_destroy(L); + matd_destroy(U); + + return det; +} + +double matd_det(const matd_t *a) +{ + assert(a != NULL); + assert(a->nrows == a->ncols); + + switch(a->nrows) { + case 0: + // scalar: invalid + assert(a->nrows > 0); + break; + + case 1: + // 1x1 matrix + return a->data[0]; + + case 2: + // 2x2 matrix + return a->data[0] * a->data[3] - a->data[1] * a->data[2]; + + case 3: + // 3x3 matrix + return a->data[0]*a->data[4]*a->data[8] + - a->data[0]*a->data[5]*a->data[7] + + a->data[1]*a->data[5]*a->data[6] + - a->data[1]*a->data[3]*a->data[8] + + a->data[2]*a->data[3]*a->data[7] + - a->data[2]*a->data[4]*a->data[6]; + + case 4: { + // 4x4 matrix + double m00 = MATD_EL(a,0,0), m01 = MATD_EL(a,0,1), m02 = MATD_EL(a,0,2), m03 = MATD_EL(a,0,3); + double m10 = MATD_EL(a,1,0), m11 = MATD_EL(a,1,1), m12 = MATD_EL(a,1,2), m13 = MATD_EL(a,1,3); + double m20 = MATD_EL(a,2,0), m21 = MATD_EL(a,2,1), m22 = MATD_EL(a,2,2), m23 = MATD_EL(a,2,3); + double m30 = MATD_EL(a,3,0), m31 = MATD_EL(a,3,1), m32 = MATD_EL(a,3,2), m33 = MATD_EL(a,3,3); + + return m00 * m11 * m22 * m33 - m00 * m11 * m23 * m32 - + m00 * m21 * m12 * m33 + m00 * m21 * m13 * m32 + m00 * m31 * m12 * m23 - + m00 * m31 * m13 * m22 - m10 * m01 * m22 * m33 + + m10 * m01 * m23 * m32 + m10 * m21 * m02 * m33 - + m10 * m21 * m03 * m32 - m10 * m31 * m02 * m23 + + m10 * m31 * m03 * m22 + m20 * m01 * m12 * m33 - + m20 * m01 * m13 * m32 - m20 * m11 * m02 * m33 + + m20 * m11 * m03 * m32 + m20 * m31 * m02 * m13 - + m20 * m31 * m03 * m12 - m30 * m01 * m12 * m23 + + m30 * m01 * m13 * m22 + m30 * m11 * m02 * m23 - + m30 * m11 * m03 * m22 - m30 * m21 * m02 * m13 + + m30 * m21 * m03 * m12; + } + + default: + return matd_det_general(a); + } + + assert(0); + return 0; +} + +// returns NULL if the matrix is (exactly) singular. Caller is +// otherwise responsible for knowing how to cope with badly +// conditioned matrices. +matd_t *matd_inverse(const matd_t *x) +{ + matd_t *m = NULL; + + assert(x != NULL); + assert(x->nrows == x->ncols); + + if (matd_is_scalar(x)) { + if (x->data[0] == 0) + return NULL; + + return matd_create_scalar(1.0 / x->data[0]); + } + + switch(x->nrows) { + case 1: { + double det = x->data[0]; + if (det == 0) + return NULL; + + double invdet = 1.0 / det; + + m = matd_create(x->nrows, x->nrows); + MATD_EL(m, 0, 0) = 1.0 * invdet; + return m; + } + + case 2: { + double det = x->data[0] * x->data[3] - x->data[1] * x->data[2]; + if (det == 0) + return NULL; + + double invdet = 1.0 / det; + + m = matd_create(x->nrows, x->nrows); + MATD_EL(m, 0, 0) = MATD_EL(x, 1, 1) * invdet; + MATD_EL(m, 0, 1) = - MATD_EL(x, 0, 1) * invdet; + MATD_EL(m, 1, 0) = - MATD_EL(x, 1, 0) * invdet; + MATD_EL(m, 1, 1) = MATD_EL(x, 0, 0) * invdet; + return m; + } + + default: { + matd_plu_t *plu = matd_plu(x); + + matd_t *inv = NULL; + if (!plu->singular) { + matd_t *ident = matd_identity(x->nrows); + inv = matd_plu_solve(plu, ident); + matd_destroy(ident); + } + + matd_plu_destroy(plu); + + return inv; + } + } + + return NULL; // unreachable +} + + + +// TODO Optimization: Some operations we could perform in-place, +// saving some memory allocation work. E.g., ADD, SUBTRACT. Just need +// to make sure that we don't do an in-place modification on a matrix +// that was an input argument! + +// handle right-associative operators, greedily consuming them. These +// include transpose and inverse. This is called by the main recursion +// method. +static inline matd_t *matd_op_gobble_right(const char *expr, int *pos, matd_t *acc, matd_t **garb, int *garbpos) +{ + while (expr[*pos] != 0) { + + switch (expr[*pos]) { + + case '\'': { + assert(acc != NULL); // either a syntax error or a math op failed, producing null + matd_t *res = matd_transpose(acc); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + + (*pos)++; + break; + } + + // handle inverse ^-1. No other exponents are allowed. + case '^': { + assert(acc != NULL); + assert(expr[*pos+1] == '-'); + assert(expr[*pos+2] == '1'); + + matd_t *res = matd_inverse(acc); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + + (*pos)+=3; + break; + } + + default: + return acc; + } + } + + return acc; +} + +// @garb, garbpos A list of every matrix allocated during evaluation... used to assist cleanup. +// @oneterm: we should return at the end of this term (i.e., stop at a PLUS, MINUS, LPAREN). +static matd_t *matd_op_recurse(const char *expr, int *pos, matd_t *acc, matd_t **args, int *argpos, + matd_t **garb, int *garbpos, int oneterm) +{ + while (expr[*pos] != 0) { + + switch (expr[*pos]) { + + case '(': { + if (oneterm && acc != NULL) + return acc; + (*pos)++; + matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 0); + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + if (acc == NULL) { + acc = rhs; + } else { + matd_t *res = matd_multiply(acc, rhs); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } + + break; + } + + case ')': { + if (oneterm) + return acc; + + (*pos)++; + return acc; + } + + case '*': { + (*pos)++; + + matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1); + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + if (acc == NULL) { + acc = rhs; + } else { + matd_t *res = matd_multiply(acc, rhs); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } + + break; + } + + case 'F': { + matd_t *rhs = args[*argpos]; + garb[*garbpos] = rhs; + (*garbpos)++; + + (*pos)++; + (*argpos)++; + + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + if (acc == NULL) { + acc = rhs; + } else { + matd_t *res = matd_multiply(acc, rhs); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } + + break; + } + + case 'M': { + matd_t *rhs = args[*argpos]; + + (*pos)++; + (*argpos)++; + + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + if (acc == NULL) { + acc = rhs; + } else { + matd_t *res = matd_multiply(acc, rhs); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } + + break; + } + +/* + case 'D': { + int rows = expr[*pos+1]-'0'; + int cols = expr[*pos+2]-'0'; + + matd_t *rhs = matd_create(rows, cols); + + break; + } +*/ + // a constant (SCALAR) defined inline. Treat just like M, creating a matd_t on the fly. +// case '0': +// case '1': +// case '2': +// case '3': +// case '4': +// case '5': +// case '6': +// case '7': +// case '8': +// case '9': +// case '.': { +// const char *start = &expr[*pos]; +// char *end; +// double s = strtod(start, &end); +// (*pos) += (end - start); +// matd_t *rhs = matd_create_scalar(s); +// garb[*garbpos] = rhs; +// (*garbpos)++; + +// rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + +// if (acc == NULL) { +// acc = rhs; +// } else { +// matd_t *res = matd_multiply(acc, rhs); +// garb[*garbpos] = res; +// (*garbpos)++; +// acc = res; +// } + +// break; +// } + + case '+': { + if (oneterm && acc != NULL) + return acc; + + // don't support unary plus + assert(acc != NULL); + (*pos)++; + matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1); + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + matd_t *res = matd_add(acc, rhs); + + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + break; + } + + case '-': { + if (oneterm && acc != NULL) + return acc; + + if (acc == NULL) { + // unary minus + (*pos)++; + matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1); + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + matd_t *res = matd_scale(rhs, -1); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } else { + // subtract + (*pos)++; + matd_t *rhs = matd_op_recurse(expr, pos, NULL, args, argpos, garb, garbpos, 1); + rhs = matd_op_gobble_right(expr, pos, rhs, garb, garbpos); + + matd_t *res = matd_subtract(acc, rhs); + garb[*garbpos] = res; + (*garbpos)++; + acc = res; + } + break; + } + + case ' ': { + // nothing to do. spaces are meaningless. + (*pos)++; + break; + } + + default: { + fprintf(stderr, "matd_op(): Unknown character: '%c'\n", expr[*pos]); + assert(expr[*pos] != expr[*pos]); + } + } + } + return acc; +} + +// always returns a new matrix. +matd_t *matd_op(const char *expr, ...) +{ + int nargs = 0; + int exprlen = 0; + + assert(expr != NULL); + + for (const char *p = expr; *p != 0; p++) { + if (*p == 'M' || *p == 'F') + nargs++; + exprlen++; + } + + assert(nargs > 0); + + if (!exprlen) // expr = "" + return NULL; + + va_list ap; + va_start(ap, expr); + + matd_t *args[nargs]; + for (int i = 0; i < nargs; i++) { + args[i] = va_arg(ap, matd_t*); + // XXX: sanity check argument; emit warning/error if args[i] + // doesn't look like a matd_t*. + } + + va_end(ap); + + int pos = 0; + int argpos = 0; + int garbpos = 0; + + matd_t *garb[2*exprlen]; // can't create more than 2 new result per character + // one result, and possibly one argument to free + + matd_t *res = matd_op_recurse(expr, &pos, NULL, args, &argpos, garb, &garbpos, 0); + + // 'res' may need to be freed as part of garbage collection (i.e. expr = "F") + matd_t *res_copy = (res ? matd_copy(res) : NULL); + + for (int i = 0; i < garbpos; i++) { + matd_destroy(garb[i]); + } + + return res_copy; +} + +double matd_vec_mag(const matd_t *a) +{ + assert(a != NULL); + assert(matd_is_vector(a)); + + double mag = 0.0; + int len = a->nrows*a->ncols; + for (int i = 0; i < len; i++) + mag += sq(a->data[i]); + return sqrt(mag); +} + +double matd_vec_dist(const matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(matd_is_vector(a) && matd_is_vector(b)); + assert(a->nrows*a->ncols == b->nrows*b->ncols); + + int lena = a->nrows*a->ncols; + return matd_vec_dist_n(a, b, lena); +} + +double matd_vec_dist_n(const matd_t *a, const matd_t *b, int n) +{ + assert(a != NULL); + assert(b != NULL); + assert(matd_is_vector(a) && matd_is_vector(b)); + + int lena = a->nrows*a->ncols; + int lenb = b->nrows*b->ncols; + + assert(n <= lena && n <= lenb); + + double mag = 0.0; + for (int i = 0; i < n; i++) + mag += sq(a->data[i] - b->data[i]); + return sqrt(mag); +} + +// find the index of the off-diagonal element with the largest mag +static inline int max_idx(const matd_t *A, int row, int maxcol) +{ + int maxi = 0; + double maxv = -1; + + for (int i = 0; i < maxcol; i++) { + if (i == row) + continue; + double v = fabs(MATD_EL(A, row, i)); + if (v > maxv) { + maxi = i; + maxv = v; + } + } + + return maxi; +} + +double matd_vec_dot_product(const matd_t *a, const matd_t *b) +{ + assert(a != NULL); + assert(b != NULL); + assert(matd_is_vector(a) && matd_is_vector(b)); + int adim = a->ncols*a->nrows; + int bdim = b->ncols*b->nrows; + assert(adim == bdim); + + double acc = 0; + for (int i = 0; i < adim; i++) { + acc += a->data[i] * b->data[i]; + } + return acc; +} + + +matd_t *matd_vec_normalize(const matd_t *a) +{ + assert(a != NULL); + assert(matd_is_vector(a)); + + double mag = matd_vec_mag(a); + assert(mag > 0); + + matd_t *b = matd_create(a->nrows, a->ncols); + + int len = a->nrows*a->ncols; + for(int i = 0; i < len; i++) + b->data[i] = a->data[i] / mag; + + return b; +} + +matd_t *matd_crossproduct(const matd_t *a, const matd_t *b) +{ // only defined for vecs (col or row) of length 3 + assert(a != NULL); + assert(b != NULL); + assert(matd_is_vector_len(a, 3) && matd_is_vector_len(b, 3)); + + matd_t * r = matd_create(a->nrows, a->ncols); + + r->data[0] = a->data[1] * b->data[2] - a->data[2] * b->data[1]; + r->data[1] = a->data[2] * b->data[0] - a->data[0] * b->data[2]; + r->data[2] = a->data[0] * b->data[1] - a->data[1] * b->data[0]; + + return r; +} + +TYPE matd_err_inf(const matd_t *a, const matd_t *b) +{ + assert(a->nrows == b->nrows); + assert(a->ncols == b->ncols); + + TYPE maxf = 0; + + for (int i = 0; i < a->nrows; i++) { + for (int j = 0; j < a->ncols; j++) { + TYPE av = MATD_EL(a, i, j); + TYPE bv = MATD_EL(b, i, j); + + TYPE err = fabs(av - bv); + maxf = fmax(maxf, err); + } + } + + return maxf; +} + +// Computes an SVD for square or tall matrices. This code doesn't work +// for wide matrices, because the bidiagonalization results in one +// non-zero element too far to the right for us to rotate away. +// +// Caller is responsible for destroying U, S, and V. +static matd_svd_t matd_svd_tall(matd_t *A, int flags) +{ + matd_t *B = matd_copy(A); + + // Apply householder reflections on each side to reduce A to + // bidiagonal form. Specifically: + // + // A = LS*B*RS' + // + // Where B is bidiagonal, and LS/RS are unitary. + // + // Why are we doing this? Some sort of transformation is necessary + // to reduce the matrix's nz elements to a square region. QR could + // work too. We need nzs confined to a square region so that the + // subsequent iterative process, which is based on rotations, can + // work. (To zero out a term at (i,j), our rotations will also + // affect (j,i). + // + // We prefer bidiagonalization over QR because it gets us "closer" + // to the SVD, which should mean fewer iterations. + + // LS: cumulative left-handed transformations + matd_t *LS = matd_identity(A->nrows); + + // RS: cumulative right-handed transformations. + matd_t *RS = matd_identity(A->ncols); + + for (int hhidx = 0; hhidx < A->nrows; hhidx++) { + + if (hhidx < A->ncols) { + // We construct the normal of the reflection plane: let u + // be the vector to reflect, x =[ M 0 0 0 ] the target + // location for u (u') after reflection (with M = ||u||). + // + // The normal vector is then n = (u - x), but since we + // could equally have the target location be x = [-M 0 0 0 + // ], we could use n = (u + x). + // + // We then normalize n. To ensure a reasonable magnitude, + // we select the sign of M so as to maximize the magnitude + // of the first element of (x +/- M). (Otherwise, we could + // end up with a divide-by-zero if u[0] and M cancel.) + // + // The householder reflection matrix is then H=(I - nn'), and + // u' = Hu. + // + // + int vlen = A->nrows - hhidx; + + double v[vlen]; + + double mag2 = 0; + for (int i = 0; i < vlen; i++) { + v[i] = MATD_EL(B, hhidx+i, hhidx); + mag2 += v[i]*v[i]; + } + + double oldv0 = v[0]; + if (oldv0 < 0) + v[0] -= sqrt(mag2); + else + v[0] += sqrt(mag2); + + mag2 += -oldv0*oldv0 + v[0]*v[0]; + + // normalize v + double mag = sqrt(mag2); + + // this case arises with matrices of all zeros, for example. + if (mag == 0) + continue; + + for (int i = 0; i < vlen; i++) + v[i] /= mag; + + // Q = I - 2vv' + //matd_t *Q = matd_identity(A->nrows); + //for (int i = 0; i < vlen; i++) + // for (int j = 0; j < vlen; j++) + // MATD_EL(Q, i+hhidx, j+hhidx) -= 2*v[i]*v[j]; + + + // LS = matd_op("F*M", LS, Q); + // Implementation: take each row of LS, compute dot product with n, + // subtract n (scaled by dot product) from it. + for (int i = 0; i < LS->nrows; i++) { + double dot = 0; + for (int j = 0; j < vlen; j++) + dot += MATD_EL(LS, i, hhidx+j) * v[j]; + for (int j = 0; j < vlen; j++) + MATD_EL(LS, i, hhidx+j) -= 2*dot*v[j]; + } + + // B = matd_op("M*F", Q, B); // should be Q', but Q is symmetric. + for (int i = 0; i < B->ncols; i++) { + double dot = 0; + for (int j = 0; j < vlen; j++) + dot += MATD_EL(B, hhidx+j, i) * v[j]; + for (int j = 0; j < vlen; j++) + MATD_EL(B, hhidx+j, i) -= 2*dot*v[j]; + } + } + + if (hhidx+2 < A->ncols) { + int vlen = A->ncols - hhidx - 1; + + double v[vlen]; + + double mag2 = 0; + for (int i = 0; i < vlen; i++) { + v[i] = MATD_EL(B, hhidx, hhidx+i+1); + mag2 += v[i]*v[i]; + } + + double oldv0 = v[0]; + if (oldv0 < 0) + v[0] -= sqrt(mag2); + else + v[0] += sqrt(mag2); + + mag2 += -oldv0*oldv0 + v[0]*v[0]; + + // compute magnitude of ([1 0 0..]+v) + double mag = sqrt(mag2); + + // this case can occur when the vectors are already perpendicular + if (mag == 0) + continue; + + for (int i = 0; i < vlen; i++) + v[i] /= mag; + + // TODO: optimize these multiplications + // matd_t *Q = matd_identity(A->ncols); + // for (int i = 0; i < vlen; i++) + // for (int j = 0; j < vlen; j++) + // MATD_EL(Q, i+1+hhidx, j+1+hhidx) -= 2*v[i]*v[j]; + + // RS = matd_op("F*M", RS, Q); + for (int i = 0; i < RS->nrows; i++) { + double dot = 0; + for (int j = 0; j < vlen; j++) + dot += MATD_EL(RS, i, hhidx+1+j) * v[j]; + for (int j = 0; j < vlen; j++) + MATD_EL(RS, i, hhidx+1+j) -= 2*dot*v[j]; + } + + // B = matd_op("F*M", B, Q); // should be Q', but Q is symmetric. + for (int i = 0; i < B->nrows; i++) { + double dot = 0; + for (int j = 0; j < vlen; j++) + dot += MATD_EL(B, i, hhidx+1+j) * v[j]; + for (int j = 0; j < vlen; j++) + MATD_EL(B, i, hhidx+1+j) -= 2*dot*v[j]; + } + } + } + + // maxiters used to be smaller to prevent us from looping forever, + // but this doesn't seem to happen any more with our more stable + // svd22 implementation. + int maxiters = 1UL << 5; // 1UL << 30; + assert(maxiters > 0); // reassure clang + int iter; + + double maxv; // maximum non-zero value being reduced this iteration + + double tol = 1E-5; // 1E-10; + + // which method will we use to find the largest off-diagonal + // element of B? + const int find_max_method = 1; //(B->ncols < 6) ? 2 : 1; + + // for each of the first B->ncols rows, which index has the + // maximum absolute value? (used by method 1) + int maxrowidx[B->ncols]; + int lastmaxi, lastmaxj; + + if (find_max_method == 1) { + for (int i = 2; i < B->ncols; i++) + maxrowidx[i] = max_idx(B, i, B->ncols); + + // note that we started the array at 2. That's because by setting + // these values below, we'll recompute first two entries on the + // first iteration! + lastmaxi = 0, lastmaxj = 1; + } + + for (iter = 0; iter < maxiters; iter++) { + + // No diagonalization required for 0x0 and 1x1 matrices. + if (B->ncols < 2) + break; + + // find the largest off-diagonal element of B, and put its + // coordinates in maxi, maxj. + int maxi, maxj; + + if (find_max_method == 1) { + // method 1 is the "smarter" method which does at least + // 4*ncols work. More work might be needed (up to + // ncols*ncols), depending on data. Thus, this might be a + // bit slower than the default method for very small + // matrices. + maxi = -1; + maxv = -1; + + // every iteration, we must deal with the fact that rows + // and columns lastmaxi and lastmaxj have been + // modified. Update maxrowidx accordingly. + + // now, EVERY row also had columns lastmaxi and lastmaxj modified. + for (int rowi = 0; rowi < B->ncols; rowi++) { + + // the magnitude of the largest off-diagonal element + // in this row. + double thismaxv; + + // row 'lastmaxi' and 'lastmaxj' have been completely + // changed. compute from scratch. + if (rowi == lastmaxi || rowi == lastmaxj) { + maxrowidx[rowi] = max_idx(B, rowi, B->ncols); + thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi])); + goto endrowi; + } + + // our maximum entry was just modified. We don't know + // if it went up or down, and so we don't know if it + // is still the maximum. We have to update from + // scratch. + if (maxrowidx[rowi] == lastmaxi || maxrowidx[rowi] == lastmaxj) { + maxrowidx[rowi] = max_idx(B, rowi, B->ncols); + thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi])); + goto endrowi; + } + + // This row is unchanged, except for columns + // 'lastmaxi' and 'lastmaxj', and those columns were + // not previously the largest entry... just check to + // see if they are now the maximum entry in their + // row. (Remembering to consider off-diagonal entries + // only!) + thismaxv = fabs(MATD_EL(B, rowi, maxrowidx[rowi])); + + // check column lastmaxi. Is it now the maximum? + if (lastmaxi != rowi) { + double v = fabs(MATD_EL(B, rowi, lastmaxi)); + if (v > thismaxv) { + thismaxv = v; + maxrowidx[rowi] = lastmaxi; + } + } + + // check column lastmaxj + if (lastmaxj != rowi) { + double v = fabs(MATD_EL(B, rowi, lastmaxj)); + if (v > thismaxv) { + thismaxv = v; + maxrowidx[rowi] = lastmaxj; + } + } + + // does this row have the largest value we've seen so far? + endrowi: + if (thismaxv > maxv) { + maxv = thismaxv; + maxi = rowi; + } + } + + assert(maxi >= 0); + maxj = maxrowidx[maxi]; + + // save these for the next iteration. + lastmaxi = maxi; + lastmaxj = maxj; + + if (maxv < tol) + break; + + } else if (find_max_method == 2) { + // brute-force (reference) version. + maxv = -1; + + // only search top "square" portion + for (int i = 0; i < B->ncols; i++) { + for (int j = 0; j < B->ncols; j++) { + if (i == j) + continue; + + double v = fabs(MATD_EL(B, i, j)); + + if (v > maxv) { + maxi = i; + maxj = j; + maxv = v; + } + } + } + + // termination condition. + if (maxv < tol) + break; + } else { + assert(0); + } + +// printf(">>> %5d %3d, %3d %15g\n", maxi, maxj, iter, maxv); + + // Now, solve the 2x2 SVD problem for the matrix + // [ A0 A1 ] + // [ A2 A3 ] + double A0 = MATD_EL(B, maxi, maxi); + double A1 = MATD_EL(B, maxi, maxj); + double A2 = MATD_EL(B, maxj, maxi); + double A3 = MATD_EL(B, maxj, maxj); + + if (1) { + double AQ[4]; + AQ[0] = A0; + AQ[1] = A1; + AQ[2] = A2; + AQ[3] = A3; + + double U[4], S[2], V[4]; + svd22(AQ, U, S, V); + +/* Reference (slow) implementation... + + // LS = LS * ROT(theta) = LS * QL + matd_t *QL = matd_identity(A->nrows); + MATD_EL(QL, maxi, maxi) = U[0]; + MATD_EL(QL, maxi, maxj) = U[1]; + MATD_EL(QL, maxj, maxi) = U[2]; + MATD_EL(QL, maxj, maxj) = U[3]; + + matd_t *QR = matd_identity(A->ncols); + MATD_EL(QR, maxi, maxi) = V[0]; + MATD_EL(QR, maxi, maxj) = V[1]; + MATD_EL(QR, maxj, maxi) = V[2]; + MATD_EL(QR, maxj, maxj) = V[3]; + + LS = matd_op("F*M", LS, QL); + RS = matd_op("F*M", RS, QR); // remember we'll transpose RS. + B = matd_op("M'*F*M", QL, B, QR); + + matd_destroy(QL); + matd_destroy(QR); +*/ + + // LS = matd_op("F*M", LS, QL); + for (int i = 0; i < LS->nrows; i++) { + double vi = MATD_EL(LS, i, maxi); + double vj = MATD_EL(LS, i, maxj); + + MATD_EL(LS, i, maxi) = U[0]*vi + U[2]*vj; + MATD_EL(LS, i, maxj) = U[1]*vi + U[3]*vj; + } + + // RS = matd_op("F*M", RS, QR); // remember we'll transpose RS. + for (int i = 0; i < RS->nrows; i++) { + double vi = MATD_EL(RS, i, maxi); + double vj = MATD_EL(RS, i, maxj); + + MATD_EL(RS, i, maxi) = V[0]*vi + V[2]*vj; + MATD_EL(RS, i, maxj) = V[1]*vi + V[3]*vj; + } + + // B = matd_op("M'*F*M", QL, B, QR); + // The QL matrix mixes rows of B. + for (int i = 0; i < B->ncols; i++) { + double vi = MATD_EL(B, maxi, i); + double vj = MATD_EL(B, maxj, i); + + MATD_EL(B, maxi, i) = U[0]*vi + U[2]*vj; + MATD_EL(B, maxj, i) = U[1]*vi + U[3]*vj; + } + + // The QR matrix mixes columns of B. + for (int i = 0; i < B->nrows; i++) { + double vi = MATD_EL(B, i, maxi); + double vj = MATD_EL(B, i, maxj); + + MATD_EL(B, i, maxi) = V[0]*vi + V[2]*vj; + MATD_EL(B, i, maxj) = V[1]*vi + V[3]*vj; + } + } + } + + if (!(flags & MATD_SVD_NO_WARNINGS) && iter == maxiters) { + printf("WARNING: maximum iters (maximum = %d, matrix %d x %d, max=%.15f)\n", + iter, A->nrows, A->ncols, maxv); + +// matd_print(A, "%15f"); + } + + // them all positive by flipping the corresponding columns of + // U/LS. + int idxs[A->ncols]; + double vals[A->ncols]; + for (int i = 0; i < A->ncols; i++) { + idxs[i] = i; + vals[i] = MATD_EL(B, i, i); + } + + // A bubble sort. Seriously. + int changed; + do { + changed = 0; + + for (int i = 0; i + 1 < A->ncols; i++) { + if (fabs(vals[i+1]) > fabs(vals[i])) { + int tmpi = idxs[i]; + idxs[i] = idxs[i+1]; + idxs[i+1] = tmpi; + + double tmpv = vals[i]; + vals[i] = vals[i+1]; + vals[i+1] = tmpv; + + changed = 1; + } + } + } while (changed); + + matd_t *LP = matd_identity(A->nrows); + matd_t *RP = matd_identity(A->ncols); + + for (int i = 0; i < A->ncols; i++) { + MATD_EL(LP, idxs[i], idxs[i]) = 0; // undo the identity above + MATD_EL(RP, idxs[i], idxs[i]) = 0; + + MATD_EL(LP, idxs[i], i) = vals[i] < 0 ? -1 : 1; + MATD_EL(RP, idxs[i], i) = 1; //vals[i] < 0 ? -1 : 1; + } + + // we've factored: + // LP*(something)*RP' + + // solve for (something) + B = matd_op("M'*F*M", LP, B, RP); + + // update LS and RS, remembering that RS will be transposed. + LS = matd_op("F*M", LS, LP); + RS = matd_op("F*M", RS, RP); + + matd_destroy(LP); + matd_destroy(RP); + + matd_svd_t res; + memset(&res, 0, sizeof(res)); + + // make B exactly diagonal + + for (int i = 0; i < B->nrows; i++) { + for (int j = 0; j < B->ncols; j++) { + if (i != j) + MATD_EL(B, i, j) = 0; + } + } + + res.U = LS; + res.S = B; + res.V = RS; + + return res; +} + +matd_svd_t matd_svd(matd_t *A) +{ + return matd_svd_flags(A, 0); +} + +matd_svd_t matd_svd_flags(matd_t *A, int flags) +{ + matd_svd_t res; + + if (A->ncols <= A->nrows) { + res = matd_svd_tall(A, flags); + } else { + matd_t *At = matd_transpose(A); + + // A =U S V' + // A'=V S' U' + + matd_svd_t tmp = matd_svd_tall(At, flags); + + memset(&res, 0, sizeof(res)); + res.U = tmp.V; //matd_transpose(tmp.V); + res.S = matd_transpose(tmp.S); + res.V = tmp.U; //matd_transpose(tmp.U); + + matd_destroy(tmp.S); + matd_destroy(At); + } + +/* + matd_t *check = matd_op("M*M*M'-M", res.U, res.S, res.V, A); + double maxerr = 0; + + for (int i = 0; i < check->nrows; i++) + for (int j = 0; j < check->ncols; j++) + maxerr = fmax(maxerr, fabs(MATD_EL(check, i, j))); + + matd_destroy(check); + + if (maxerr > 1e-7) { + printf("bad maxerr: %15f\n", maxerr); + } + + if (maxerr > 1e-5) { + printf("bad maxerr: %15f\n", maxerr); + matd_print(A, "%15f"); + assert(0); + } + +*/ + return res; +} + + +matd_plu_t *matd_plu(const matd_t *a) +{ + unsigned int *piv = calloc(a->nrows, sizeof(unsigned int)); + int pivsign = 1; + matd_t *lu = matd_copy(a); + + // only for square matrices. + assert(a->nrows == a->ncols); + + matd_plu_t *mlu = calloc(1, sizeof(matd_plu_t)); + + for (int i = 0; i < a->nrows; i++) + piv[i] = i; + + for (int j = 0; j < a->ncols; j++) { + for (int i = 0; i < a->nrows; i++) { + int kmax = i < j ? i : j; // min(i,j) + + // compute dot product of row i with column j (up through element kmax) + double acc = 0; + for (int k = 0; k < kmax; k++) + acc += MATD_EL(lu, i, k) * MATD_EL(lu, k, j); + + MATD_EL(lu, i, j) -= acc; + } + + // find pivot and exchange if necessary. + int p = j; + if (1) { + for (int i = j+1; i < lu->nrows; i++) { + if (fabs(MATD_EL(lu,i,j)) > fabs(MATD_EL(lu, p, j))) { + p = i; + } + } + } + + // swap rows p and j? + if (p != j) { + TYPE tmp[lu->ncols]; + memcpy(tmp, &MATD_EL(lu, p, 0), sizeof(TYPE) * lu->ncols); + memcpy(&MATD_EL(lu, p, 0), &MATD_EL(lu, j, 0), sizeof(TYPE) * lu->ncols); + memcpy(&MATD_EL(lu, j, 0), tmp, sizeof(TYPE) * lu->ncols); + int k = piv[p]; + piv[p] = piv[j]; + piv[j] = k; + pivsign = -pivsign; + } + + double LUjj = MATD_EL(lu, j, j); + + // If our pivot is very small (which means the matrix is + // singular or nearly singular), replace with a new pivot of the + // right sign. + if (fabs(LUjj) < MATD_EPS) { +/* + if (LUjj < 0) + LUjj = -MATD_EPS; + else + LUjj = MATD_EPS; + + MATD_EL(lu, j, j) = LUjj; +*/ + mlu->singular = 1; + } + + if (j < lu->ncols && j < lu->nrows && LUjj != 0) { + LUjj = 1.0 / LUjj; + for (int i = j+1; i < lu->nrows; i++) + MATD_EL(lu, i, j) *= LUjj; + } + } + + mlu->lu = lu; + mlu->piv = piv; + mlu->pivsign = pivsign; + + return mlu; +} + +void matd_plu_destroy(matd_plu_t *mlu) +{ + matd_destroy(mlu->lu); + free(mlu->piv); + memset(mlu, 0, sizeof(matd_plu_t)); + free(mlu); +} + +double matd_plu_det(const matd_plu_t *mlu) +{ + matd_t *lu = mlu->lu; + double det = mlu->pivsign; + + if (lu->nrows == lu->ncols) { + for (int i = 0; i < lu->ncols; i++) + det *= MATD_EL(lu, i, i); + } + + return det; +} + +matd_t *matd_plu_p(const matd_plu_t *mlu) +{ + matd_t *lu = mlu->lu; + matd_t *P = matd_create(lu->nrows, lu->nrows); + + for (int i = 0; i < lu->nrows; i++) { + MATD_EL(P, mlu->piv[i], i) = 1; + } + + return P; +} + +matd_t *matd_plu_l(const matd_plu_t *mlu) +{ + matd_t *lu = mlu->lu; + + matd_t *L = matd_create(lu->nrows, lu->ncols); + for (int i = 0; i < lu->nrows; i++) { + MATD_EL(L, i, i) = 1; + + for (int j = 0; j < i; j++) { + MATD_EL(L, i, j) = MATD_EL(lu, i, j); + } + } + + return L; +} + +matd_t *matd_plu_u(const matd_plu_t *mlu) +{ + matd_t *lu = mlu->lu; + + matd_t *U = matd_create(lu->ncols, lu->ncols); + for (int i = 0; i < lu->ncols; i++) { + for (int j = 0; j < lu->ncols; j++) { + if (i <= j) + MATD_EL(U, i, j) = MATD_EL(lu, i, j); + } + } + + return U; +} + +// PLU = A +// Ax = B +// PLUx = B +// LUx = P'B +matd_t *matd_plu_solve(const matd_plu_t *mlu, const matd_t *b) +{ + matd_t *x = matd_copy(b); + + // permute right hand side + for (int i = 0; i < mlu->lu->nrows; i++) + memcpy(&MATD_EL(x, i, 0), &MATD_EL(b, mlu->piv[i], 0), sizeof(TYPE) * b->ncols); + + // solve Ly = b + for (int k = 0; k < mlu->lu->nrows; k++) { + for (int i = k+1; i < mlu->lu->nrows; i++) { + double LUik = -MATD_EL(mlu->lu, i, k); + for (int t = 0; t < b->ncols; t++) + MATD_EL(x, i, t) += MATD_EL(x, k, t) * LUik; + } + } + + // solve Ux = y + for (int k = mlu->lu->ncols-1; k >= 0; k--) { + double LUkk = 1.0 / MATD_EL(mlu->lu, k, k); + for (int t = 0; t < b->ncols; t++) + MATD_EL(x, k, t) *= LUkk; + + for (int i = 0; i < k; i++) { + double LUik = -MATD_EL(mlu->lu, i, k); + for (int t = 0; t < b->ncols; t++) + MATD_EL(x, i, t) += MATD_EL(x, k, t) *LUik; + } + } + + return x; +} + +matd_t *matd_solve(matd_t *A, matd_t *b) +{ + matd_plu_t *mlu = matd_plu(A); + matd_t *x = matd_plu_solve(mlu, b); + + matd_plu_destroy(mlu); + return x; +} + +#if 0 + +static int randi() +{ + int v = random()&31; + v -= 15; + return v; +} + +static double randf() +{ + double v = 1.0 *random() / RAND_MAX; + return 2*v - 1; +} + +int main(int argc, char *argv[]) +{ + if (1) { + int maxdim = 16; + matd_t *A = matd_create(maxdim, maxdim); + + for (int iter = 0; 1; iter++) { + srand(iter); + + if (iter % 1000 == 0) + printf("%d\n", iter); + + int m = 1 + (random()%(maxdim-1)); + int n = 1 + (random()%(maxdim-1)); + + for (int i = 0; i < m*n; i++) + A->data[i] = randi(); + + A->nrows = m; + A->ncols = n; + +// printf("%d %d ", m, n); + matd_svd_t svd = matd_svd(A); + matd_destroy(svd.U); + matd_destroy(svd.S); + matd_destroy(svd.V); + + } + +/* matd_t *A = matd_create_data(2, 5, (double[]) { 1, 5, 2, 6, + 3, 3, 0, 7, + 1, 1, 0, -2, + 4, 0, 9, 9, 2, 6, 1, 3, 2, 5, 5, 4, -1, 2, 5, 9, 8, 2 }); + + matd_svd(A); +*/ + return 0; + } + + + struct svd22 s; + + srand(0); + + matd_t *A = matd_create(2, 2); + MATD_EL(A,0,0) = 4; + MATD_EL(A,0,1) = 7; + MATD_EL(A,1,0) = 2; + MATD_EL(A,1,1) = 6; + + matd_t *U = matd_create(2, 2); + matd_t *V = matd_create(2, 2); + matd_t *S = matd_create(2, 2); + + for (int iter = 0; 1; iter++) { + if (iter % 100000 == 0) + printf("%d\n", iter); + + MATD_EL(A,0,0) = randf(); + MATD_EL(A,0,1) = randf(); + MATD_EL(A,1,0) = randf(); + MATD_EL(A,1,1) = randf(); + + matd_svd22_impl(A->data, &s); + + memcpy(U->data, s.U, 4*sizeof(double)); + memcpy(V->data, s.V, 4*sizeof(double)); + MATD_EL(S,0,0) = s.S[0]; + MATD_EL(S,1,1) = s.S[1]; + + assert(s.S[0] >= s.S[1]); + assert(s.S[0] >= 0); + assert(s.S[1] >= 0); + if (s.S[0] == 0) { +// printf("*"); fflush(NULL); +// printf("%15f %15f %15f %15f\n", MATD_EL(A,0,0), MATD_EL(A,0,1), MATD_EL(A,1,0), MATD_EL(A,1,1)); + } + if (s.S[1] == 0) { +// printf("#"); fflush(NULL); + } + + matd_t *USV = matd_op("M*M*M'", U, S, V); + + double maxerr = 0; + for (int i = 0; i < 4; i++) + maxerr = fmax(maxerr, fabs(USV->data[i] - A->data[i])); + + if (0) { + printf("------------------------------------\n"); + printf("A:\n"); + matd_print(A, "%15f"); + printf("\nUSV':\n"); + matd_print(USV, "%15f"); + printf("maxerr: %.15f\n", maxerr); + printf("\n\n"); + } + + matd_destroy(USV); + + assert(maxerr < 0.00001); + } +} + +#endif + +// XXX NGV Cholesky +/*static double *matd_cholesky_raw(double *A, int n) + { + double *L = (double*)calloc(n * n, sizeof(double)); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < (i+1); j++) { + double s = 0; + for (int k = 0; k < j; k++) + s += L[i * n + k] * L[j * n + k]; + L[i * n + j] = (i == j) ? + sqrt(A[i * n + i] - s) : + (1.0 / L[j * n + j] * (A[i * n + j] - s)); + } + } + + return L; + } + + matd_t *matd_cholesky(const matd_t *A) + { + assert(A->nrows == A->ncols); + double *L_data = matd_cholesky_raw(A->data, A->nrows); + matd_t *L = matd_create_data(A->nrows, A->ncols, L_data); + free(L_data); + return L; + }*/ + +// NOTE: The below implementation of Cholesky is different from the one +// used in NGV. +matd_chol_t *matd_chol(matd_t *A) +{ + assert(A->nrows == A->ncols); + int N = A->nrows; + + // make upper right + matd_t *U = matd_copy(A); + + // don't actually need to clear lower-left... we won't touch it. +/* for (int i = 0; i < U->nrows; i++) { + for (int j = 0; j < i; j++) { +// assert(MATD_EL(U, i, j) == MATD_EL(U, j, i)); +MATD_EL(U, i, j) = 0; +} +} +*/ + int is_spd = 1; // (A->nrows == A->ncols); + + for (int i = 0; i < N; i++) { + double d = MATD_EL(U, i, i); + is_spd &= (d > 0); + + if (d < MATD_EPS) + d = MATD_EPS; + d = 1.0 / sqrt(d); + + for (int j = i; j < N; j++) + MATD_EL(U, i, j) *= d; + + for (int j = i+1; j < N; j++) { + double s = MATD_EL(U, i, j); + + if (s == 0) + continue; + + for (int k = j; k < N; k++) { + MATD_EL(U, j, k) -= MATD_EL(U, i, k)*s; + } + } + } + + matd_chol_t *chol = calloc(1, sizeof(matd_chol_t)); + chol->is_spd = is_spd; + chol->u = U; + return chol; +} + +void matd_chol_destroy(matd_chol_t *chol) +{ + matd_destroy(chol->u); + free(chol); +} + +// Solve: (U')x = b, U is upper triangular +void matd_ltransposetriangle_solve(matd_t *u, const TYPE *b, TYPE *x) +{ + int n = u->ncols; + memcpy(x, b, n*sizeof(TYPE)); + for (int i = 0; i < n; i++) { + x[i] /= MATD_EL(u, i, i); + + for (int j = i+1; j < u->ncols; j++) { + x[j] -= x[i] * MATD_EL(u, i, j); + } + } +} + +// Solve: Lx = b, L is lower triangular +void matd_ltriangle_solve(matd_t *L, const TYPE *b, TYPE *x) +{ + int n = L->ncols; + + for (int i = 0; i < n; i++) { + double acc = b[i]; + + for (int j = 0; j < i; j++) { + acc -= MATD_EL(L, i, j)*x[j]; + } + + x[i] = acc / MATD_EL(L, i, i); + } +} + +// solve Ux = b, U is upper triangular +void matd_utriangle_solve(matd_t *u, const TYPE *b, TYPE *x) +{ + for (int i = u->ncols-1; i >= 0; i--) { + double bi = b[i]; + + double diag = MATD_EL(u, i, i); + + for (int j = i+1; j < u->ncols; j++) + bi -= MATD_EL(u, i, j)*x[j]; + + x[i] = bi / diag; + } +} + +matd_t *matd_chol_solve(const matd_chol_t *chol, const matd_t *b) +{ + matd_t *u = chol->u; + + matd_t *x = matd_copy(b); + + // LUx = b + + // solve Ly = b ==> (U')y = b + + for (int i = 0; i < u->nrows; i++) { + for (int j = 0; j < i; j++) { + // b[i] -= L[i,j]*x[j]... replicated across columns of b + // ==> i.e., ==> + // b[i,k] -= L[i,j]*x[j,k] + for (int k = 0; k < b->ncols; k++) { + MATD_EL(x, i, k) -= MATD_EL(u, j, i)*MATD_EL(x, j, k); + } + } + // x[i] = b[i] / L[i,i] + for (int k = 0; k < b->ncols; k++) { + MATD_EL(x, i, k) /= MATD_EL(u, i, i); + } + } + + // solve Ux = y + for (int k = u->ncols-1; k >= 0; k--) { + double LUkk = 1.0 / MATD_EL(u, k, k); + for (int t = 0; t < b->ncols; t++) + MATD_EL(x, k, t) *= LUkk; + + for (int i = 0; i < k; i++) { + double LUik = -MATD_EL(u, i, k); + for (int t = 0; t < b->ncols; t++) + MATD_EL(x, i, t) += MATD_EL(x, k, t) *LUik; + } + } + + return x; +} + +/*void matd_chol_solve(matd_chol_t *chol, const TYPE *b, TYPE *x) + { + matd_t *u = chol->u; + + TYPE y[u->ncols]; + matd_ltransposetriangle_solve(u, b, y); + matd_utriangle_solve(u, y, x); + } +*/ +// only sensible on PSD matrices. had expected it to be faster than +// inverse via LU... for now, doesn't seem to be. +matd_t *matd_chol_inverse(matd_t *a) +{ + assert(a->nrows == a->ncols); + + matd_chol_t *chol = matd_chol(a); + + matd_t *eye = matd_identity(a->nrows); + matd_t *inv = matd_chol_solve(chol, eye); + matd_destroy(eye); + matd_chol_destroy(chol); + + return inv; +} + +double matd_max(matd_t *m) +{ + double d = -DBL_MAX; + for(int x=0; xnrows; x++) { + for(int y=0; yncols; y++) { + if(MATD_EL(m, x, y) > d) + d = MATD_EL(m, x, y); + } + } + + return d; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "homography.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + + /** Given a 3x3 homography matrix and the focal lengths of the + * camera, compute the pose of the tag. The focal lengths should + * be given in pixels. For example, if the camera's focal length + * is twice the width of the sensor, and the sensor is 600 pixels + * across, the focal length in pixels is 2*600. Note that the + * focal lengths in the fx and fy direction will be approximately + * equal for most lenses, and is not a function of aspect ratio. + * + * Theory: The homography matrix is the product of the camera + * projection matrix and the tag's pose matrix (the matrix that + * projects points from the tag's local coordinate system to the + * camera's coordinate frame). + * + * [ h00 h01 h02 h03] = [ fx 0 cx 0 ] [ R00 R01 R02 TX ] + * [ h10 h11 h12 h13] = [ 0 fy cy 0 ] [ R10 R11 R12 TY ] + * [ h20 h21 h22 h23] = [ 0 0 s 0 ] [ R20 R21 R22 TZ ] + * [ 0 0 0 1 ] + * + * fx is the focal length in the x direction of the camera + * (typically measured in pixels), fy is the focal length. cx and + * cy give the focal center (usually the middle of the image), and + * s is either +1 or -1, depending on the conventions you use. (We + * use 1.) + + * When observing a tag, the points we project in world space all + * have z=0, so we can form a 3x3 matrix by eliminating the 3rd + * column of the pose matrix. + * + * [ h00 h01 h02 ] = [ fx 0 cx 0 ] [ R00 R01 TX ] + * [ h10 h11 h12 ] = [ 0 fy cy 0 ] [ R10 R11 TY ] + * [ h20 h21 h22 ] = [ 0 0 s 0 ] [ R20 R21 TZ ] + * [ 0 0 1 ] + * + * (note that these h's are different from the ones above.) + * + * We can multiply the right-hand side to yield a set of equations + * relating the values of h to the values of the pose matrix. + * + * There are two wrinkles. The first is that the homography matrix + * is known only up to scale. We recover the unknown scale by + * constraining the magnitude of the first two columns of the pose + * matrix to be 1. We use the geometric average scale. The sign of + * the scale factor is recovered by constraining the observed tag + * to be in front of the camera. Once scaled, we recover the first + * two colmuns of the rotation matrix. The third column is the + * cross product of these. + * + * The second wrinkle is that the computed rotation matrix might + * not be exactly orthogonal, so we perform a polar decomposition + * to find a good pure rotation approximation. + * + * Tagsize is the size of the tag in your desired units. I.e., if + * your tag measures 0.25m along the side, your tag size is + * 0.25. (The homography is computed in terms of *half* the tag + * size, i.e., that a tag is 2 units wide as it spans from -1 to + * +1, but this code makes the appropriate adjustment.) + * + * A note on signs: + * + * The code below incorporates no additional negative signs, but + * respects the sign of any parameters that you pass in. Flipping + * the signs allows you to modify the projection to suit a wide + * variety of conditions. + * + * In the "pure geometry" projection matrix, the image appears + * upside down; i.e., the x and y coordinates on the left hand + * side are the opposite of those on the right of the camera + * projection matrix. This would happen for all parameters + * positive: recall that points in front of the camera have + * negative Z values, which will cause the sign of all points to + * flip. + * + * However, most cameras flip things so that the image appears + * "right side up" as though you were looking through the lens + * directly. This means that the projected points should have the + * same sign as the points on the right of the camera projection + * matrix. To achieve this, flip fx and fy. + * + * One further complication: cameras typically put y=0 at the top + * of the image, instead of the bottom. Thus you generally want to + * flip y yet again (so it's now positive again). + * + * General advice: you probably want fx negative, fy positive, cx + * and cy positive, and s=1. + **/ + +// correspondences is a list of float[4]s, consisting of the points x +// and y concatenated. We will compute a homography such that y = Hx +// Specifically, float [] { a, b, c, d } where x = [a b], y = [c d]. + + +#define HOMOGRAPHY_COMPUTE_FLAG_INVERSE 1 +#define HOMOGRAPHY_COMPUTE_FLAG_SVD 0 + +matd_t *homography_compute(zarray_t *correspondences, int flags); + +//void homography_project(const matd_t *H, double x, double y, double *ox, double *oy); +static inline void homography_project(const matd_t *H, double x, double y, double *ox, double *oy) +{ + double xx = MATD_EL(H, 0, 0)*x + MATD_EL(H, 0, 1)*y + MATD_EL(H, 0, 2); + double yy = MATD_EL(H, 1, 0)*x + MATD_EL(H, 1, 1)*y + MATD_EL(H, 1, 2); + double zz = MATD_EL(H, 2, 0)*x + MATD_EL(H, 2, 1)*y + MATD_EL(H, 2, 2); + + *ox = xx / zz; + *oy = yy / zz; +} + +// assuming that the projection matrix is: +// [ fx 0 cx 0 ] +// [ 0 fy cy 0 ] +// [ 0 0 1 0 ] +// +// And that the homography is equal to the projection matrix times the model matrix, +// recover the model matrix (which is returned). Note that the third column of the model +// matrix is missing in the expresison below, reflecting the fact that the homography assumes +// all points are at z=0 (i.e., planar) and that the element of z is thus omitted. +// (3x1 instead of 4x1). +// +// [ fx 0 cx 0 ] [ R00 R01 TX ] [ H00 H01 H02 ] +// [ 0 fy cy 0 ] [ R10 R11 TY ] = [ H10 H11 H12 ] +// [ 0 0 1 0 ] [ R20 R21 TZ ] = [ H20 H21 H22 ] +// [ 0 0 1 ] +// +// fx*R00 + cx*R20 = H00 (note, H only known up to scale; some additional adjustments required; see code.) +// fx*R01 + cx*R21 = H01 +// fx*TX + cx*TZ = H02 +// fy*R10 + cy*R20 = H10 +// fy*R11 + cy*R21 = H11 +// fy*TY + cy*TZ = H12 +// R20 = H20 +// R21 = H21 +// TZ = H22 +matd_t *homography_to_pose(const matd_t *H, double fx, double fy, double cx, double cy); + +// Similar to above +// Recover the model view matrix assuming that the projection matrix is: +// +// [ F 0 A 0 ] (see glFrustrum) +// [ 0 G B 0 ] +// [ 0 0 C D ] +// [ 0 0 -1 0 ] + +matd_t *homography_to_model_view(const matd_t *H, double F, double G, double A, double B, double C, double D); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "homography.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// correspondences is a list of float[4]s, consisting of the points x +// and y concatenated. We will compute a homography such that y = Hx +matd_t *homography_compute(zarray_t *correspondences, int flags) +{ + // compute centroids of both sets of points (yields a better + // conditioned information matrix) + double x_cx = 0, x_cy = 0; + double y_cx = 0, y_cy = 0; + + for (int i = 0; i < zarray_size(correspondences); i++) { + float *c; + zarray_get_volatile(correspondences, i, &c); + + x_cx += c[0]; + x_cy += c[1]; + y_cx += c[2]; + y_cy += c[3]; + } + + int sz = zarray_size(correspondences); + x_cx /= sz; + x_cy /= sz; + y_cx /= sz; + y_cy /= sz; + + // NB We don't normalize scale; it seems implausible that it could + // possibly make any difference given the dynamic range of IEEE + // doubles. + + matd_t *A = matd_create(9,9); + for (int i = 0; i < zarray_size(correspondences); i++) { + float *c; + zarray_get_volatile(correspondences, i, &c); + + // (below world is "x", and image is "y") + double worldx = c[0] - x_cx; + double worldy = c[1] - x_cy; + double imagex = c[2] - y_cx; + double imagey = c[3] - y_cy; + + double a03 = -worldx; + double a04 = -worldy; + double a05 = -1; + double a06 = worldx*imagey; + double a07 = worldy*imagey; + double a08 = imagey; + + MATD_EL(A, 3, 3) += a03*a03; + MATD_EL(A, 3, 4) += a03*a04; + MATD_EL(A, 3, 5) += a03*a05; + MATD_EL(A, 3, 6) += a03*a06; + MATD_EL(A, 3, 7) += a03*a07; + MATD_EL(A, 3, 8) += a03*a08; + MATD_EL(A, 4, 4) += a04*a04; + MATD_EL(A, 4, 5) += a04*a05; + MATD_EL(A, 4, 6) += a04*a06; + MATD_EL(A, 4, 7) += a04*a07; + MATD_EL(A, 4, 8) += a04*a08; + MATD_EL(A, 5, 5) += a05*a05; + MATD_EL(A, 5, 6) += a05*a06; + MATD_EL(A, 5, 7) += a05*a07; + MATD_EL(A, 5, 8) += a05*a08; + MATD_EL(A, 6, 6) += a06*a06; + MATD_EL(A, 6, 7) += a06*a07; + MATD_EL(A, 6, 8) += a06*a08; + MATD_EL(A, 7, 7) += a07*a07; + MATD_EL(A, 7, 8) += a07*a08; + MATD_EL(A, 8, 8) += a08*a08; + + double a10 = worldx; + double a11 = worldy; + double a12 = 1; + double a16 = -worldx*imagex; + double a17 = -worldy*imagex; + double a18 = -imagex; + + MATD_EL(A, 0, 0) += a10*a10; + MATD_EL(A, 0, 1) += a10*a11; + MATD_EL(A, 0, 2) += a10*a12; + MATD_EL(A, 0, 6) += a10*a16; + MATD_EL(A, 0, 7) += a10*a17; + MATD_EL(A, 0, 8) += a10*a18; + MATD_EL(A, 1, 1) += a11*a11; + MATD_EL(A, 1, 2) += a11*a12; + MATD_EL(A, 1, 6) += a11*a16; + MATD_EL(A, 1, 7) += a11*a17; + MATD_EL(A, 1, 8) += a11*a18; + MATD_EL(A, 2, 2) += a12*a12; + MATD_EL(A, 2, 6) += a12*a16; + MATD_EL(A, 2, 7) += a12*a17; + MATD_EL(A, 2, 8) += a12*a18; + MATD_EL(A, 6, 6) += a16*a16; + MATD_EL(A, 6, 7) += a16*a17; + MATD_EL(A, 6, 8) += a16*a18; + MATD_EL(A, 7, 7) += a17*a17; + MATD_EL(A, 7, 8) += a17*a18; + MATD_EL(A, 8, 8) += a18*a18; + + double a20 = -worldx*imagey; + double a21 = -worldy*imagey; + double a22 = -imagey; + double a23 = worldx*imagex; + double a24 = worldy*imagex; + double a25 = imagex; + + MATD_EL(A, 0, 0) += a20*a20; + MATD_EL(A, 0, 1) += a20*a21; + MATD_EL(A, 0, 2) += a20*a22; + MATD_EL(A, 0, 3) += a20*a23; + MATD_EL(A, 0, 4) += a20*a24; + MATD_EL(A, 0, 5) += a20*a25; + MATD_EL(A, 1, 1) += a21*a21; + MATD_EL(A, 1, 2) += a21*a22; + MATD_EL(A, 1, 3) += a21*a23; + MATD_EL(A, 1, 4) += a21*a24; + MATD_EL(A, 1, 5) += a21*a25; + MATD_EL(A, 2, 2) += a22*a22; + MATD_EL(A, 2, 3) += a22*a23; + MATD_EL(A, 2, 4) += a22*a24; + MATD_EL(A, 2, 5) += a22*a25; + MATD_EL(A, 3, 3) += a23*a23; + MATD_EL(A, 3, 4) += a23*a24; + MATD_EL(A, 3, 5) += a23*a25; + MATD_EL(A, 4, 4) += a24*a24; + MATD_EL(A, 4, 5) += a24*a25; + MATD_EL(A, 5, 5) += a25*a25; + } + + // make symmetric + for (int i = 0; i < 9; i++) + for (int j = i+1; j < 9; j++) + MATD_EL(A, j, i) = MATD_EL(A, i, j); + + matd_t *H = matd_create(3,3); + + if (flags & HOMOGRAPHY_COMPUTE_FLAG_INVERSE) { + // compute singular vector by (carefully) inverting the rank-deficient matrix. + + if (1) { + matd_t *Ainv = matd_inverse(A); + double scale = 0; + + for (int i = 0; i < 9; i++) + scale += sq(MATD_EL(Ainv, i, 0)); + scale = sqrt(scale); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + MATD_EL(H, i, j) = MATD_EL(Ainv, 3*i+j, 0) / scale; + + matd_destroy(Ainv); + } else { + + matd_t *b = matd_create_data(9, 1, (double[]) { 1, 0, 0, 0, 0, 0, 0, 0, 0 }); + matd_t *Ainv = NULL; + + if (0) { + matd_plu_t *lu = matd_plu(A); + Ainv = matd_plu_solve(lu, b); + matd_plu_destroy(lu); + } else { + matd_chol_t *chol = matd_chol(A); + Ainv = matd_chol_solve(chol, b); + matd_chol_destroy(chol); + } + + double scale = 0; + + for (int i = 0; i < 9; i++) + scale += sq(MATD_EL(Ainv, i, 0)); + scale = sqrt(scale); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + MATD_EL(H, i, j) = MATD_EL(Ainv, 3*i+j, 0) / scale; + + matd_destroy(b); + matd_destroy(Ainv); + } + + } else { + // compute singular vector using SVD. A bit slower, but more accurate. + matd_svd_t svd = matd_svd_flags(A, MATD_SVD_NO_WARNINGS); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + MATD_EL(H, i, j) = MATD_EL(svd.U, 3*i+j, 8); + + matd_destroy(svd.U); + matd_destroy(svd.S); + matd_destroy(svd.V); + + } + + matd_t *Tx = matd_identity(3); + MATD_EL(Tx,0,2) = -x_cx; + MATD_EL(Tx,1,2) = -x_cy; + + matd_t *Ty = matd_identity(3); + MATD_EL(Ty,0,2) = y_cx; + MATD_EL(Ty,1,2) = y_cy; + + matd_t *H2 = matd_op("M*M*M", Ty, H, Tx); + + matd_destroy(A); + matd_destroy(Tx); + matd_destroy(Ty); + matd_destroy(H); + + return H2; +} + + +// assuming that the projection matrix is: +// [ fx 0 cx 0 ] +// [ 0 fy cy 0 ] +// [ 0 0 1 0 ] +// +// And that the homography is equal to the projection matrix times the +// model matrix, recover the model matrix (which is returned). Note +// that the third column of the model matrix is missing in the +// expresison below, reflecting the fact that the homography assumes +// all points are at z=0 (i.e., planar) and that the element of z is +// thus omitted. (3x1 instead of 4x1). +// +// [ fx 0 cx 0 ] [ R00 R01 TX ] [ H00 H01 H02 ] +// [ 0 fy cy 0 ] [ R10 R11 TY ] = [ H10 H11 H12 ] +// [ 0 0 1 0 ] [ R20 R21 TZ ] = [ H20 H21 H22 ] +// [ 0 0 1 ] +// +// fx*R00 + cx*R20 = H00 (note, H only known up to scale; some additional adjustments required; see code.) +// fx*R01 + cx*R21 = H01 +// fx*TX + cx*TZ = H02 +// fy*R10 + cy*R20 = H10 +// fy*R11 + cy*R21 = H11 +// fy*TY + cy*TZ = H12 +// R20 = H20 +// R21 = H21 +// TZ = H22 + +matd_t *homography_to_pose(const matd_t *H, double fx, double fy, double cx, double cy) +{ + // Note that every variable that we compute is proportional to the scale factor of H. + double R20 = MATD_EL(H, 2, 0); + double R21 = MATD_EL(H, 2, 1); + double TZ = MATD_EL(H, 2, 2); + double R00 = (MATD_EL(H, 0, 0) - cx*R20) / fx; + double R01 = (MATD_EL(H, 0, 1) - cx*R21) / fx; + double TX = (MATD_EL(H, 0, 2) - cx*TZ) / fx; + double R10 = (MATD_EL(H, 1, 0) - cy*R20) / fy; + double R11 = (MATD_EL(H, 1, 1) - cy*R21) / fy; + double TY = (MATD_EL(H, 1, 2) - cy*TZ) / fy; + + // compute the scale by requiring that the rotation columns are unit length + // (Use geometric average of the two length vectors we have) + double length1 = sqrtf(R00*R00 + R10*R10 + R20*R20); + double length2 = sqrtf(R01*R01 + R11*R11 + R21*R21); + double s = 1.0 / sqrtf(length1 * length2); + + // get sign of S by requiring the tag to be in front the camera; + // we assume camera looks in the -Z direction. + if (TZ > 0) + s *= -1; + + R20 *= s; + R21 *= s; + TZ *= s; + R00 *= s; + R01 *= s; + TX *= s; + R10 *= s; + R11 *= s; + TY *= s; + + // now recover [R02 R12 R22] by noting that it is the cross product of the other two columns. + double R02 = R10*R21 - R20*R11; + double R12 = R20*R01 - R00*R21; + double R22 = R00*R11 - R10*R01; + + // Improve rotation matrix by applying polar decomposition. + if (1) { + // do polar decomposition. This makes the rotation matrix + // "proper", but probably increases the reprojection error. An + // iterative alignment step would be superior. + + matd_t *R = matd_create_data(3, 3, (double[]) { R00, R01, R02, + R10, R11, R12, + R20, R21, R22 }); + + matd_svd_t svd = matd_svd(R); + matd_destroy(R); + + R = matd_op("M*M'", svd.U, svd.V); + + matd_destroy(svd.U); + matd_destroy(svd.S); + matd_destroy(svd.V); + + R00 = MATD_EL(R, 0, 0); + R01 = MATD_EL(R, 0, 1); + R02 = MATD_EL(R, 0, 2); + R10 = MATD_EL(R, 1, 0); + R11 = MATD_EL(R, 1, 1); + R12 = MATD_EL(R, 1, 2); + R20 = MATD_EL(R, 2, 0); + R21 = MATD_EL(R, 2, 1); + R22 = MATD_EL(R, 2, 2); + + matd_destroy(R); + } + + return matd_create_data(4, 4, (double[]) { R00, R01, R02, TX, + R10, R11, R12, TY, + R20, R21, R22, TZ, + 0, 0, 0, 1 }); +} + +// Similar to above +// Recover the model view matrix assuming that the projection matrix is: +// +// [ F 0 A 0 ] (see glFrustrum) +// [ 0 G B 0 ] +// [ 0 0 C D ] +// [ 0 0 -1 0 ] + +matd_t *homography_to_model_view(const matd_t *H, double F, double G, double A, double B, double C, double D) +{ + // Note that every variable that we compute is proportional to the scale factor of H. + double R20 = -MATD_EL(H, 2, 0); + double R21 = -MATD_EL(H, 2, 1); + double TZ = -MATD_EL(H, 2, 2); + double R00 = (MATD_EL(H, 0, 0) - A*R20) / F; + double R01 = (MATD_EL(H, 0, 1) - A*R21) / F; + double TX = (MATD_EL(H, 0, 2) - A*TZ) / F; + double R10 = (MATD_EL(H, 1, 0) - B*R20) / G; + double R11 = (MATD_EL(H, 1, 1) - B*R21) / G; + double TY = (MATD_EL(H, 1, 2) - B*TZ) / G; + + // compute the scale by requiring that the rotation columns are unit length + // (Use geometric average of the two length vectors we have) + double length1 = sqrtf(R00*R00 + R10*R10 + R20*R20); + double length2 = sqrtf(R01*R01 + R11*R11 + R21*R21); + double s = 1.0 / sqrtf(length1 * length2); + + // get sign of S by requiring the tag to be in front of the camera + // (which is Z < 0) for our conventions. + if (TZ > 0) + s *= -1; + + R20 *= s; + R21 *= s; + TZ *= s; + R00 *= s; + R01 *= s; + TX *= s; + R10 *= s; + R11 *= s; + TY *= s; + + // now recover [R02 R12 R22] by noting that it is the cross product of the other two columns. + double R02 = R10*R21 - R20*R11; + double R12 = R20*R01 - R00*R21; + double R22 = R00*R11 - R10*R01; + + // TODO XXX: Improve rotation matrix by applying polar decomposition. + + return matd_create_data(4, 4, (double[]) { R00, R01, R02, TX, + R10, R11, R12, TY, + R20, R21, R22, TZ, + 0, 0, 0, 1 }); +} + +// Only uses the upper 3x3 matrix. +/* +static void matrix_to_quat(const matd_t *R, double q[4]) +{ + // see: "from quaternion to matrix and back" + + // trace: get the same result if R is 4x4 or 3x3: + double T = MATD_EL(R, 0, 0) + MATD_EL(R, 1, 1) + MATD_EL(R, 2, 2) + 1; + double S = 0; + + double m0 = MATD_EL(R, 0, 0); + double m1 = MATD_EL(R, 1, 0); + double m2 = MATD_EL(R, 2, 0); + double m4 = MATD_EL(R, 0, 1); + double m5 = MATD_EL(R, 1, 1); + double m6 = MATD_EL(R, 2, 1); + double m8 = MATD_EL(R, 0, 2); + double m9 = MATD_EL(R, 1, 2); + double m10 = MATD_EL(R, 2, 2); + + if (T > 0.0000001) { + S = sqrtf(T) * 2; + q[1] = -( m9 - m6 ) / S; + q[2] = -( m2 - m8 ) / S; + q[3] = -( m4 - m1 ) / S; + q[0] = 0.25 * S; + } else if ( m0 > m5 && m0 > m10 ) { // Column 0: + S = sqrtf( 1.0 + m0 - m5 - m10 ) * 2; + q[1] = -0.25 * S; + q[2] = -(m4 + m1 ) / S; + q[3] = -(m2 + m8 ) / S; + q[0] = (m9 - m6 ) / S; + } else if ( m5 > m10 ) { // Column 1: + S = sqrtf( 1.0 + m5 - m0 - m10 ) * 2; + q[1] = -(m4 + m1 ) / S; + q[2] = -0.25 * S; + q[3] = -(m9 + m6 ) / S; + q[0] = (m2 - m8 ) / S; + } else { + // Column 2: + S = sqrtf( 1.0 + m10 - m0 - m5 ) * 2; + q[1] = -(m2 + m8 ) / S; + q[2] = -(m9 + m6 ) / S; + q[3] = -0.25 * S; + q[0] = (m4 - m1 ) / S; + } + + double mag2 = 0; + for (int i = 0; i < 4; i++) + mag2 += q[i]*q[i]; + double norm = 1.0 / sqrtf(mag2); + for (int i = 0; i < 4; i++) + q[i] *= norm; +} +*/ + +// overwrites upper 3x3 area of matrix M. Doesn't touch any other elements of M. +void quat_to_matrix(const double q[4], matd_t *M) +{ + double w = q[0], x = q[1], y = q[2], z = q[3]; + + MATD_EL(M, 0, 0) = w*w + x*x - y*y - z*z; + MATD_EL(M, 0, 1) = 2*x*y - 2*w*z; + MATD_EL(M, 0, 2) = 2*x*z + 2*w*y; + + MATD_EL(M, 1, 0) = 2*x*y + 2*w*z; + MATD_EL(M, 1, 1) = w*w - x*x + y*y - z*z; + MATD_EL(M, 1, 2) = 2*y*z - 2*w*x; + + MATD_EL(M, 2, 0) = 2*x*z - 2*w*y; + MATD_EL(M, 2, 1) = 2*y*z + 2*w*x; + MATD_EL(M, 2, 2) = w*w - x*x - y*y + z*z; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "g2d.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// This library tries to avoid needless proliferation of types. +// +// A point is a double[2]. (Note that when passing a double[2] as an +// argument, it is passed by pointer, not by value.) +// +// A polygon is a zarray_t of double[2]. (Note that in this case, the +// zarray contains the actual vertex data, and not merely a pointer to +// some other data. IMPORTANT: A polygon must be specified in CCW +// order. It is implicitly closed (do not list the same point at the +// beginning at the end. +// +// Where sensible, it is assumed that objects should be allocated +// sparingly; consequently "init" style methods, rather than "create" +// methods are used. + +//////////////////////////////////////////////////////////////////// +// Lines + +typedef struct +{ + // Internal representation: a point that the line goes through (p) and + // the direction of the line (u). + double p[2]; + double u[2]; // always a unit vector +} g2d_line_t; + +// initialize a line object. +void g2d_line_init_from_points(g2d_line_t *line, const double p0[2], const double p1[2]); + +// The line defines a one-dimensional coordinate system whose origin +// is p. Where is q? (If q is not on the line, the point nearest q is +// returned. +double g2d_line_get_coordinate(const g2d_line_t *line, const double q[2]); + +// Intersect two lines. The intersection, if it exists, is written to +// p (if not NULL), and 1 is returned. Else, zero is returned. +int g2d_line_intersect_line(const g2d_line_t *linea, const g2d_line_t *lineb, double *p); + +//////////////////////////////////////////////////////////////////// +// Line Segments. line.p is always one endpoint; p1 is the other +// endpoint. +typedef struct +{ + g2d_line_t line; + double p1[2]; +} g2d_line_segment_t; + +void g2d_line_segment_init_from_points(g2d_line_segment_t *seg, const double p0[2], const double p1[2]); + +// Intersect two segments. The intersection, if it exists, is written +// to p (if not NULL), and 1 is returned. Else, zero is returned. +int g2d_line_segment_intersect_segment(const g2d_line_segment_t *sega, const g2d_line_segment_t *segb, double *p); + +void g2d_line_segment_closest_point(const g2d_line_segment_t *seg, const double *q, double *p); +double g2d_line_segment_closest_point_distance(const g2d_line_segment_t *seg, const double *q); + +//////////////////////////////////////////////////////////////////// +// Polygons + +zarray_t *g2d_polygon_create_data(double v[][2], int sz); + +zarray_t *g2d_polygon_create_zeros(int sz); + +zarray_t *g2d_polygon_create_empty(); + +void g2d_polygon_add(zarray_t *poly, double v[2]); + +// Takes a polygon in either CW or CCW and modifies it (if necessary) +// to be CCW. +void g2d_polygon_make_ccw(zarray_t *poly); + +// Return 1 if point q lies within poly. +int g2d_polygon_contains_point(const zarray_t *poly, double q[2]); + +// Do the edges of the polygons cross? (Does not test for containment). +int g2d_polygon_intersects_polygon(const zarray_t *polya, const zarray_t *polyb); + +// Does polya completely contain polyb? +int g2d_polygon_contains_polygon(const zarray_t *polya, const zarray_t *polyb); + +// Is there some point which is in both polya and polyb? +int g2d_polygon_overlaps_polygon(const zarray_t *polya, const zarray_t *polyb); + +// returns the number of points written to x. see comments. +int g2d_polygon_rasterize(const zarray_t *poly, double y, double *x); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "g2d.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +double g2d_distance(const double a[2], const double b[2]) +{ + return sqrtf(sq(a[0]-b[0]) + sq(a[1]-b[1])); +} + +zarray_t *g2d_polygon_create_empty() +{ + return zarray_create(sizeof(double[2])); +} + +void g2d_polygon_add(zarray_t *poly, double v[2]) +{ + zarray_add(poly, v); +} + +zarray_t *g2d_polygon_create_data(double v[][2], int sz) +{ + zarray_t *points = g2d_polygon_create_empty(); + + for (int i = 0; i < sz; i++) + g2d_polygon_add(points, v[i]); + + return points; +} + +zarray_t *g2d_polygon_create_zeros(int sz) +{ + zarray_t *points = zarray_create(sizeof(double[2])); + + double z[2] = { 0, 0 }; + + for (int i = 0; i < sz; i++) + zarray_add(points, z); + + return points; +} + +void g2d_polygon_make_ccw(zarray_t *poly) +{ + // Step one: we want the points in counter-clockwise order. + // If the points are in clockwise order, we'll reverse them. + double total_theta = 0; + double last_theta = 0; + + // Count the angle accumulated going around the polygon. If + // the sum is +2pi, it's CCW. Otherwise, we'll get -2pi. + int sz = zarray_size(poly); + + for (int i = 0; i <= sz; i++) { + double p0[2], p1[2]; + zarray_get(poly, i % sz, &p0); + zarray_get(poly, (i+1) % sz, &p1); + + double this_theta = atan2(p1[1]-p0[1], p1[0]-p0[0]); + + if (i > 0) { + double dtheta = mod2pi(this_theta-last_theta); + total_theta += dtheta; + } + + last_theta = this_theta; + } + + int ccw = (total_theta > 0); + + // reverse order if necessary. + if (!ccw) { + for (int i = 0; i < sz / 2; i++) { + double a[2], b[2]; + + zarray_get(poly, i, a); + zarray_get(poly, sz-1-i, b); + zarray_set(poly, i, b, NULL); + zarray_set(poly, sz-1-i, a, NULL); + } + } +} + +int g2d_polygon_contains_point_ref(const zarray_t *poly, double q[2]) +{ + // use winding. If the point is inside the polygon, we'll wrap + // around it (accumulating 6.28 radians). If we're outside the + // polygon, we'll accumulate zero. + int psz = zarray_size(poly); + + double acc_theta = 0; + + double last_theta; + + for (int i = 0; i <= psz; i++) { + double p[2]; + + zarray_get(poly, i % psz, &p); + + double this_theta = atan2(q[1]-p[1], q[0]-p[0]); + + if (i != 0) + acc_theta += mod2pi(this_theta - last_theta); + + last_theta = this_theta; + } + + return acc_theta > M_PI; +} + +/* +// sort by x coordinate, ascending +static int g2d_convex_hull_sort(const void *_a, const void *_b) +{ + double *a = (double*) _a; + double *b = (double*) _b; + + if (a[0] < b[0]) + return -1; + if (a[0] == b[0]) + return 0; + return 1; +} +*/ + +/* +zarray_t *g2d_convex_hull2(const zarray_t *points) +{ + zarray_t *hull = zarray_copy(points); + + zarray_sort(hull, g2d_convex_hull_sort); + + int hsz = zarray_size(hull); + int hout = 0; + + for (int hin = 1; hin < hsz; hin++) { + double *p; + zarray_get_volatile(hull, i, &p); + + // Everything to the right of hin is already convex. We now + // add one point, p, which begins "connected" by two + // (coincident) edges from the last right-most point to p. + double *last; + zarray_get_volatile(hull, hout, &last); + + // We now remove points from the convex hull by moving + } + + return hull; +} +*/ + +// creates and returns a zarray(double[2]). The resulting polygon is +// CCW and implicitly closed. Unnecessary colinear points are omitted. +zarray_t *g2d_convex_hull(const zarray_t *points) +{ + zarray_t *hull = zarray_create(sizeof(double[2])); + + // gift-wrap algorithm. + + // step 1: find left most point. + int insz = zarray_size(points); + + // must have at least 2 points. (XXX need 3?) + assert(insz >= 2); + + double *pleft = NULL; + for (int i = 0; i < insz; i++) { + double *p; + zarray_get_volatile(points, i, &p); + + if (pleft == NULL || p[0] < pleft[0]) + pleft = p; + } + + // cannot be NULL since there must be at least one point. + assert(pleft != NULL); + + zarray_add(hull, pleft); + + // step 2. gift wrap. Keep searching for points that make the + // smallest-angle left-hand turn. This implementation is carefully + // written to use only addition/subtraction/multiply. No division + // or sqrts. This guarantees exact results for integer-coordinate + // polygons (no rounding/precision problems). + double *p = pleft; + + while (1) { + assert(p != NULL); + + double *q = NULL; + double n0 = 0, n1 = 0; // the normal to the line (p, q) (not + // necessarily unit length). + + // Search for the point q for which the line (p,q) is most "to + // the right of" the other points. (i.e., every time we find a + // point that is to the right of our current line, we change + // lines.) + for (int i = 0; i < insz; i++) { + double *thisq; + zarray_get_volatile(points, i, &thisq); + + if (thisq == p) + continue; + + // the first time we find another point, we initialize our + // value of q, forming the line (p,q) + if (q == NULL) { + q = thisq; + n0 = q[1] - p[1]; + n1 = -q[0] + p[0]; + } else { + // we already have a line (p,q). is point thisq RIGHT OF line (p, q)? + double e0 = thisq[0] - p[0], e1 = thisq[1] - p[1]; + double dot = e0*n0 + e1*n1; + + if (dot > 0) { + // it is. change our line. + q = thisq; + n0 = q[1] - p[1]; + n1 = -q[0] + p[0]; + } + } + } + + // we must have elected *some* line, so long as there are at + // least 2 points in the polygon. + assert(q != NULL); + + // loop completed? + if (q == pleft) + break; + + int colinear = 0; + + // is this new point colinear with the last two? + if (zarray_size(hull) > 1) { + double *o; + zarray_get_volatile(hull, zarray_size(hull) - 2, &o); + + double e0 = o[0] - p[0]; + double e1 = o[1] - p[1]; + + if (n0*e0 + n1*e1 == 0) + colinear = 1; + } + + // if it is colinear, overwrite the last one. + if (colinear) + zarray_set(hull, zarray_size(hull)-1, q, NULL); + else + zarray_add(hull, q); + + p = q; + } + + return hull; +} + +// Find point p on the boundary of poly that is closest to q. +void g2d_polygon_closest_boundary_point(const zarray_t *poly, const double q[2], double *p) +{ + int psz = zarray_size(poly); + double min_dist = HUGE_VALF; + + for (int i = 0; i < psz; i++) { + double *p0, *p1; + + zarray_get_volatile(poly, i, &p0); + zarray_get_volatile(poly, (i+1) % psz, &p1); + + g2d_line_segment_t seg; + g2d_line_segment_init_from_points(&seg, p0, p1); + + double thisp[2]; + g2d_line_segment_closest_point(&seg, q, thisp); + + double dist = g2d_distance(q, thisp); + if (dist < min_dist) { + memcpy(p, thisp, sizeof(double[2])); + min_dist = dist; + } + } +} + +int g2d_polygon_contains_point(const zarray_t *poly, double q[2]) +{ + // use winding. If the point is inside the polygon, we'll wrap + // around it (accumulating 6.28 radians). If we're outside the + // polygon, we'll accumulate zero. + int psz = zarray_size(poly); + assert(psz > 0); + + int last_quadrant = 0; + int quad_acc = 0; + + for (int i = 0; i <= psz; i++) { + double *p; + + zarray_get_volatile(poly, i % psz, &p); + + // p[0] < q[0] p[1] < q[1] quadrant + // 0 0 0 + // 0 1 3 + // 1 0 1 + // 1 1 2 + + // p[1] < q[1] p[0] < q[0] quadrant + // 0 0 0 + // 0 1 1 + // 1 0 3 + // 1 1 2 + + int quadrant; + if (p[0] < q[0]) + quadrant = (p[1] < q[1]) ? 2 : 1; + else + quadrant = (p[1] < q[1]) ? 3 : 0; + + if (i > 0) { + int dquadrant = quadrant - last_quadrant; + + // encourage a jump table by mapping to small positive integers. + switch (dquadrant) { + case -3: + case 1: + quad_acc ++; + break; + case -1: + case 3: + quad_acc --; + break; + case 0: + break; + case -2: + case 2: + { + // get the previous point. + double *p0; + zarray_get_volatile(poly, i-1, &p0); + + // Consider the points p0 and p (the points around the + //polygon that we are tracing) and the query point q. + // + // If we've moved diagonally across quadrants, we want + // to measure whether we have rotated +PI radians or + // -PI radians. We can test this by computing the dot + // product of vector (p0-q) with the vector + // perpendicular to vector (p-q) + double nx = p[1] - q[1]; + double ny = -p[0] + q[0]; + + double dot = nx*(p0[0]-q[0]) + ny*(p0[1]-q[1]); + if (dot < 0) + quad_acc -= 2; + else + quad_acc += 2; + + break; + } + } + } + + last_quadrant = quadrant; + } + + int v = (quad_acc >= 2) || (quad_acc <= -2); + + if (0 && v != g2d_polygon_contains_point_ref(poly, q)) { + printf("FAILURE %d %d\n", v, quad_acc); + exit(-1); + } + + return v; +} + +void g2d_line_init_from_points(g2d_line_t *line, const double p0[2], const double p1[2]) +{ + line->p[0] = p0[0]; + line->p[1] = p0[1]; + line->u[0] = p1[0]-p0[0]; + line->u[1] = p1[1]-p0[1]; + double mag = sqrtf(sq(line->u[0]) + sq(line->u[1])); + + line->u[0] /= mag; + line->u[1] /= mag; +} + +double g2d_line_get_coordinate(const g2d_line_t *line, const double q[2]) +{ + return (q[0]-line->p[0])*line->u[0] + (q[1]-line->p[1])*line->u[1]; +} + +// Compute intersection of two line segments. If they intersect, +// result is stored in p and 1 is returned. Otherwise, zero is +// returned. p may be NULL. +int g2d_line_intersect_line(const g2d_line_t *linea, const g2d_line_t *lineb, double *p) +{ + // this implementation is many times faster than the original, + // mostly due to avoiding a general-purpose LU decomposition in + // Matrix.inverse(). + double m00, m01, m10, m11; + double i00, i01; + double b00, b10; + + m00 = linea->u[0]; + m01= -lineb->u[0]; + m10 = linea->u[1]; + m11= -lineb->u[1]; + + // determinant of m + double det = m00*m11-m01*m10; + + // parallel lines? + if (fabs(det) < 0.00000001) + return 0; + + // inverse of m + i00 = m11/det; + i01 = -m01/det; + + b00 = lineb->p[0] - linea->p[0]; + b10 = lineb->p[1] - linea->p[1]; + + double x00; //, x10; + x00 = i00*b00+i01*b10; + + if (p != NULL) { + p[0] = linea->u[0]*x00 + linea->p[0]; + p[1] = linea->u[1]*x00 + linea->p[1]; + } + + return 1; +} + + +void g2d_line_segment_init_from_points(g2d_line_segment_t *seg, const double p0[2], const double p1[2]) +{ + g2d_line_init_from_points(&seg->line, p0, p1); + seg->p1[0] = p1[0]; + seg->p1[1] = p1[1]; +} + +// Find the point p on segment seg that is closest to point q. +void g2d_line_segment_closest_point(const g2d_line_segment_t *seg, const double *q, double *p) +{ + double a = g2d_line_get_coordinate(&seg->line, seg->line.p); + double b = g2d_line_get_coordinate(&seg->line, seg->p1); + double c = g2d_line_get_coordinate(&seg->line, q); + + if (a < b) + c = dclamp(c, a, b); + else + c = dclamp(c, b, a); + + p[0] = seg->line.p[0] + c * seg->line.u[0]; + p[1] = seg->line.p[1] + c * seg->line.u[1]; +} + +// Compute intersection of two line segments. If they intersect, +// result is stored in p and 1 is returned. Otherwise, zero is +// returned. p may be NULL. +int g2d_line_segment_intersect_segment(const g2d_line_segment_t *sega, const g2d_line_segment_t *segb, double *p) +{ + double tmp[2]; + + if (!g2d_line_intersect_line(&sega->line, &segb->line, tmp)) + return 0; + + double a = g2d_line_get_coordinate(&sega->line, sega->line.p); + double b = g2d_line_get_coordinate(&sega->line, sega->p1); + double c = g2d_line_get_coordinate(&sega->line, tmp); + + // does intersection lie on the first line? + if ((ca && c>b)) + return 0; + + a = g2d_line_get_coordinate(&segb->line, segb->line.p); + b = g2d_line_get_coordinate(&segb->line, segb->p1); + c = g2d_line_get_coordinate(&segb->line, tmp); + + // does intersection lie on second line? + if ((ca && c>b)) + return 0; + + if (p != NULL) { + p[0] = tmp[0]; + p[1] = tmp[1]; + } + + return 1; +} + +// Compute intersection of a line segment and a line. If they +// intersect, result is stored in p and 1 is returned. Otherwise, zero +// is returned. p may be NULL. +int g2d_line_segment_intersect_line(const g2d_line_segment_t *seg, const g2d_line_t *line, double *p) +{ + double tmp[2]; + + if (!g2d_line_intersect_line(&seg->line, line, tmp)) + return 0; + + double a = g2d_line_get_coordinate(&seg->line, seg->line.p); + double b = g2d_line_get_coordinate(&seg->line, seg->p1); + double c = g2d_line_get_coordinate(&seg->line, tmp); + + // does intersection lie on the first line? + if ((ca && c>b)) + return 0; + + if (p != NULL) { + p[0] = tmp[0]; + p[1] = tmp[1]; + } + + return 1; +} + +// do the edges of polya and polyb collide? (Does NOT test for containment). +int g2d_polygon_intersects_polygon(const zarray_t *polya, const zarray_t *polyb) +{ + // do any of the line segments collide? If so, the answer is no. + + // dumb N^2 method. + for (int ia = 0; ia < zarray_size(polya); ia++) { + double pa0[2], pa1[2]; + zarray_get(polya, ia, pa0); + zarray_get(polya, (ia+1)%zarray_size(polya), pa1); + + g2d_line_segment_t sega; + g2d_line_segment_init_from_points(&sega, pa0, pa1); + + for (int ib = 0; ib < zarray_size(polyb); ib++) { + double pb0[2], pb1[2]; + zarray_get(polyb, ib, pb0); + zarray_get(polyb, (ib+1)%zarray_size(polyb), pb1); + + g2d_line_segment_t segb; + g2d_line_segment_init_from_points(&segb, pb0, pb1); + + if (g2d_line_segment_intersect_segment(&sega, &segb, NULL)) + return 1; + } + } + + return 0; +} + +// does polya completely contain polyb? +int g2d_polygon_contains_polygon(const zarray_t *polya, const zarray_t *polyb) +{ + // do any of the line segments collide? If so, the answer is no. + if (g2d_polygon_intersects_polygon(polya, polyb)) + return 0; + + // if none of the edges cross, then the polygon is either fully + // contained or fully outside. + double p[2]; + zarray_get(polyb, 0, p); + + return g2d_polygon_contains_point(polya, p); +} + +// compute a point that is inside the polygon. (It may not be *far* inside though) +void g2d_polygon_get_interior_point(const zarray_t *poly, double *p) +{ + // take the first three points, which form a triangle. Find the middle point + double a[2], b[2], c[2]; + + zarray_get(poly, 0, a); + zarray_get(poly, 1, b); + zarray_get(poly, 2, c); + + p[0] = (a[0]+b[0]+c[0])/3; + p[1] = (a[1]+b[1]+c[1])/3; +} + +int g2d_polygon_overlaps_polygon(const zarray_t *polya, const zarray_t *polyb) +{ + // do any of the line segments collide? If so, the answer is yes. + if (g2d_polygon_intersects_polygon(polya, polyb)) + return 1; + + // if none of the edges cross, then the polygon is either fully + // contained or fully outside. + double p[2]; + g2d_polygon_get_interior_point(polyb, p); + + if (g2d_polygon_contains_point(polya, p)) + return 1; + + g2d_polygon_get_interior_point(polya, p); + + if (g2d_polygon_contains_point(polyb, p)) + return 1; + + return 0; +} + +static int double_sort_up(const void *_a, const void *_b) +{ + double a = *((double*) _a); + double b = *((double*) _b); + + if (a < b) + return -1; + + if (a == b) + return 0; + + return 1; +} + +// Compute the crossings of the polygon along line y, storing them in +// the array x. X must be allocated to be at least as long as +// zarray_size(poly). X will be sorted, ready for +// rasterization. Returns the number of intersections (and elements +// written to x). +/* + To rasterize, do something like this: + + double res = 0.099; + for (double y = y0; y < y1; y += res) { + double xs[zarray_size(poly)]; + + int xsz = g2d_polygon_rasterize(poly, y, xs); + int xpos = 0; + int inout = 0; // start off "out" + + for (double x = x0; x < x1; x += res) { + while (x > xs[xpos] && xpos < xsz) { + xpos++; + inout ^= 1; + } + + if (inout) + printf("y"); + else + printf(" "); + } + printf("\n"); +*/ + +// returns the number of x intercepts +int g2d_polygon_rasterize(const zarray_t *poly, double y, double *x) +{ + int sz = zarray_size(poly); + + g2d_line_t line; + if (1) { + double p0[2] = { 0, y }; + double p1[2] = { 1, y }; + + g2d_line_init_from_points(&line, p0, p1); + } + + int xpos = 0; + + for (int i = 0; i < sz; i++) { + g2d_line_segment_t seg; + double *p0, *p1; + zarray_get_volatile(poly, i, &p0); + zarray_get_volatile(poly, (i+1)%sz, &p1); + + g2d_line_segment_init_from_points(&seg, p0, p1); + + double q[2]; + if (g2d_line_segment_intersect_line(&seg, &line, q)) + x[xpos++] = q[0]; + } + + qsort(x, xpos, sizeof(double), double_sort_up); + + return xpos; +} + +/* + /---(1,5) + (-2,4)-/ | + \ | + \ (1,2)--(2,2)\ + \ \ + \ \ + (0,0)------------------(4,0) +*/ +#if 0 + +#include "timeprofile.h" + +int main(int argc, char *argv[]) +{ + timeprofile_t *tp = timeprofile_create(); + + zarray_t *polya = g2d_polygon_create_data((double[][2]) { + { 0, 0}, + { 4, 0}, + { 2, 2}, + { 1, 2}, + { 1, 5}, + { -2,4} }, 6); + + zarray_t *polyb = g2d_polygon_create_data((double[][2]) { + { .1, .1}, + { .5, .1}, + { .1, .5 } }, 3); + + zarray_t *polyc = g2d_polygon_create_data((double[][2]) { + { 3, 0}, + { 5, 0}, + { 5, 1} }, 3); + + zarray_t *polyd = g2d_polygon_create_data((double[][2]) { + { 5, 5}, + { 6, 6}, + { 5, 6} }, 3); + +/* + 5 L---K + 4 |I--J + 3 |H-G + 2 |E-F + 1 |D--C + 0 A---B + 01234 +*/ + zarray_t *polyE = g2d_polygon_create_data((double[][2]) { + {0,0}, {4,0}, {4, 1}, {1,1}, + {1,2}, {3,2}, {3,3}, {1,3}, + {1,4}, {4,4}, {4,5}, {0,5}}, 12); + + srand(0); + + timeprofile_stamp(tp, "begin"); + + if (1) { + int niters = 100000; + + for (int i = 0; i < niters; i++) { + double q[2]; + q[0] = 10.0f * random() / RAND_MAX - 2; + q[1] = 10.0f * random() / RAND_MAX - 2; + + g2d_polygon_contains_point(polyE, q); + } + + timeprofile_stamp(tp, "fast"); + + for (int i = 0; i < niters; i++) { + double q[2]; + q[0] = 10.0f * random() / RAND_MAX - 2; + q[1] = 10.0f * random() / RAND_MAX - 2; + + g2d_polygon_contains_point_ref(polyE, q); + } + + timeprofile_stamp(tp, "slow"); + + for (int i = 0; i < niters; i++) { + double q[2]; + q[0] = 10.0f * random() / RAND_MAX - 2; + q[1] = 10.0f * random() / RAND_MAX - 2; + + int v0 = g2d_polygon_contains_point(polyE, q); + int v1 = g2d_polygon_contains_point_ref(polyE, q); + assert(v0 == v1); + } + + timeprofile_stamp(tp, "both"); + timeprofile_display(tp); + } + + if (1) { + zarray_t *poly = polyE; + + double res = 0.399; + for (double y = 5.2; y >= -.5; y -= res) { + double xs[zarray_size(poly)]; + + int xsz = g2d_polygon_rasterize(poly, y, xs); + int xpos = 0; + int inout = 0; // start off "out" + for (double x = -3; x < 6; x += res) { + while (x > xs[xpos] && xpos < xsz) { + xpos++; + inout ^= 1; + } + + if (inout) + printf("y"); + else + printf(" "); + } + printf("\n"); + + for (double x = -3; x < 6; x += res) { + double q[2] = {x, y}; + if (g2d_polygon_contains_point(poly, q)) + printf("X"); + else + printf(" "); + } + printf("\n"); + } + } + + + +/* +// CW order +double p[][2] = { { 0, 0}, +{ -2, 4}, +{1, 5}, +{1, 2}, +{2, 2}, +{4, 0} }; +*/ + + double q[2] = { 10, 10 }; + printf("0==%d\n", g2d_polygon_contains_point(polya, q)); + + q[0] = 1; q[1] = 1; + printf("1==%d\n", g2d_polygon_contains_point(polya, q)); + + q[0] = 3; q[1] = .5; + printf("1==%d\n", g2d_polygon_contains_point(polya, q)); + + q[0] = 1.2; q[1] = 2.1; + printf("0==%d\n", g2d_polygon_contains_point(polya, q)); + + printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyb)); + + printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyc)); + + printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyd)); + + //////////////////////////////////////////////////////// + // Test convex hull + if (1) { + zarray_t *hull = g2d_convex_hull(polyE); + + for (int k = 0; k < zarray_size(hull); k++) { + double *h; + zarray_get_volatile(hull, k, &h); + + printf("%15f, %15f\n", h[0], h[1]); + } + } + + for (int i = 0; i < 100000; i++) { + zarray_t *points = zarray_create(sizeof(double[2])); + + for (int j = 0; j < 100; j++) { + double q[2]; + q[0] = 10.0f * random() / RAND_MAX - 2; + q[1] = 10.0f * random() / RAND_MAX - 2; + + zarray_add(points, q); + } + + zarray_t *hull = g2d_convex_hull(points); + for (int j = 0; j < zarray_size(points); j++) { + double *q; + zarray_get_volatile(points, j, &q); + + int on_edge; + + double p[2]; + g2d_polygon_closest_boundary_point(hull, q, p); + if (g2d_distance(q, p) < .00001) + on_edge = 1; + + assert(on_edge || g2d_polygon_contains_point(hull, q)); + } + + zarray_destroy(hull); + zarray_destroy(points); + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "image_types.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// to support conversions between different types, we define all image +// types at once. Type-specific implementations can then #include this +// file, assured that the basic types of each image are known. + +typedef struct image_u8 image_u8_t; +struct image_u8 +{ + int32_t width; + int32_t height; + int32_t stride; + + uint8_t *buf; +}; + +typedef struct image_u8x3 image_u8x3_t; +struct image_u8x3 +{ + const int32_t width; + const int32_t height; + const int32_t stride; // bytes per line + + uint8_t *buf; +}; + +typedef struct image_u8x4 image_u8x4_t; +struct image_u8x4 +{ + const int32_t width; + const int32_t height; + const int32_t stride; // bytes per line + + uint8_t *buf; +}; + +typedef struct image_f32 image_f32_t; +struct image_f32 +{ + const int32_t width; + const int32_t height; + const int32_t stride; // floats per line + + float *buf; // indexed as buf[y*stride + x] +}; + +typedef struct image_u32 image_u32_t; +struct image_u32 +{ + const int32_t width; + const int32_t height; + const int32_t stride; // int32_ts per line + + uint32_t *buf; // indexed as buf[y*stride + x] +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "apriltag_math.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Computes the cholesky factorization of A, putting the lower +// triangular matrix into R. +static inline void mat33_chol(const double *A, + double *R) +{ + // A[0] = R[0]*R[0] + R[0] = sqrt(A[0]); + + // A[1] = R[0]*R[3]; + R[3] = A[1] / R[0]; + + // A[2] = R[0]*R[6]; + R[6] = A[2] / R[0]; + + // A[4] = R[3]*R[3] + R[4]*R[4] + R[4] = sqrt(A[4] - R[3]*R[3]); + + // A[5] = R[3]*R[6] + R[4]*R[7] + R[7] = (A[5] - R[3]*R[6]) / R[4]; + + // A[8] = R[6]*R[6] + R[7]*R[7] + R[8]*R[8] + R[8] = sqrt(A[8] - R[6]*R[6] - R[7]*R[7]); + + R[1] = 0; + R[2] = 0; + R[5] = 0; +} + +static inline void mat33_lower_tri_inv(const double *A, + double *R) +{ + // A[0]*R[0] = 1 + R[0] = 1 / A[0]; + + // A[3]*R[0] + A[4]*R[3] = 0 + R[3] = -A[3]*R[0] / A[4]; + + // A[4]*R[4] = 1 + R[4] = 1 / A[4]; + + // A[6]*R[0] + A[7]*R[3] + A[8]*R[6] = 0 + R[6] = (-A[6]*R[0] - A[7]*R[3]) / A[8]; + + // A[7]*R[4] + A[8]*R[7] = 0 + R[7] = -A[7]*R[4] / A[8]; + + // A[8]*R[8] = 1 + R[8] = 1 / A[8]; +} + + +static inline void mat33_sym_solve(const double *A, + const double *B, + double *R) +{ + double L[9]; + mat33_chol(A, L); + + double M[9]; + mat33_lower_tri_inv(L, M); + + double tmp[3]; + tmp[0] = M[0]*B[0]; + tmp[1] = M[3]*B[0] + M[4]*B[1]; + tmp[2] = M[6]*B[0] + M[7]*B[1] + M[8]*B[2]; + + R[0] = M[0]*tmp[0] + M[3]*tmp[1] + M[6]*tmp[2]; + R[1] = M[4]*tmp[1] + M[7]*tmp[2]; + R[2] = M[8]*tmp[2]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "apriltag.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct quad +{ + float p[4][2]; // corners + + // H: tag coordinates ([-1,1] at the black corners) to pixels + // Hinv: pixels to tag + matd_t *H, *Hinv; +}; + +// Represents a tag family. Every tag belongs to a tag family. Tag +// families are generated by the Java tool +// april.tag.TagFamilyGenerator and can be converted to C using +// april.tag.TagToC. +typedef struct apriltag_family apriltag_family_t; +struct apriltag_family +{ + // How many codes are there in this tag family? + uint32_t ncodes; + + // how wide (in bit-sizes) is the black border? (usually 1) + uint32_t black_border; + + // how many bits tall and wide is it? (e.g. 36bit tag ==> 6) + uint32_t d; + + // minimum hamming distance between any two codes. (e.g. 36h11 => 11) + uint32_t h; + + // The codes in the family. + uint64_t codes[]; +}; + +struct apriltag_quad_thresh_params +{ + // reject quads containing too few pixels + int min_cluster_pixels; + + // how many corner candidates to consider when segmenting a group + // of pixels into a quad. + int max_nmaxima; + + // Reject quads where pairs of edges have angles that are close to + // straight or close to 180 degrees. Zero means that no quads are + // rejected. (In radians). + float critical_rad; + + // When fitting lines to the contours, what is the maximum mean + // squared error allowed? This is useful in rejecting contours + // that are far from being quad shaped; rejecting these quads "early" + // saves expensive decoding processing. + float max_line_fit_mse; + + // When we build our model of black & white pixels, we add an + // extra check that the white model must be (overall) brighter + // than the black model. How much brighter? (in pixel values, + // [0,255]). . + int min_white_black_diff; + + // should the thresholded image be deglitched? Only useful for + // very noisy images + int deglitch; +}; + +// Represents a detector object. Upon creating a detector, all fields +// are set to reasonable values, but can be overridden by accessing +// these fields. +typedef struct apriltag_detector apriltag_detector_t; +struct apriltag_detector +{ + /////////////////////////////////////////////////////////////// + // User-configurable parameters. + + // When non-zero, the edges of the each quad are adjusted to "snap + // to" strong gradients nearby. This is useful when decimation is + // employed, as it can increase the quality of the initial quad + // estimate substantially. Generally recommended to be on (1). + // + // Very computationally inexpensive. Option is ignored if + // quad_decimate = 1. + int refine_edges; + + // when non-zero, detections are refined in a way intended to + // increase the number of detected tags. Especially effective for + // very small tags near the resolution threshold (e.g. 10px on a + // side). + int refine_decode; + + // when non-zero, detections are refined in a way intended to + // increase the accuracy of the extracted pose. This is done by + // maximizing the contrast around the black and white border of + // the tag. This generally increases the number of successfully + // detected tags, though not as effectively (or quickly) as + // refine_decode. + // + // This option must be enabled in order for "goodness" to be + // computed. + int refine_pose; + + struct apriltag_quad_thresh_params qtp; + + /////////////////////////////////////////////////////////////// + // Statistics relating to last processed frame + + uint32_t nedges; + uint32_t nsegments; + uint32_t nquads; + + /////////////////////////////////////////////////////////////// + // Internal variables below + + // Not freed on apriltag_destroy; a tag family can be shared + // between multiple users. The user should ultimately destroy the + // tag family passed into the constructor. + zarray_t *tag_families; +}; + +// Represents the detection of a tag. These are returned to the user +// and must be individually destroyed by the user. +typedef struct apriltag_detection apriltag_detection_t; +struct apriltag_detection +{ + // a pointer for convenience. not freed by apriltag_detection_destroy. + apriltag_family_t *family; + + // The decoded ID of the tag + int id; + + // How many error bits were corrected? Note: accepting large numbers of + // corrected errors leads to greatly increased false positive rates. + // NOTE: As of this implementation, the detector cannot detect tags with + // a hamming distance greater than 2. + int hamming; + + // A measure of the quality of tag localization: measures the + // average contrast of the pixels around the border of the + // tag. refine_pose must be enabled, or this field will be zero. + float goodness; + + // A measure of the quality of the binary decoding process: the + // average difference between the intensity of a data bit versus + // the decision threshold. Higher numbers roughly indicate better + // decodes. This is a reasonable measure of detection accuracy + // only for very small tags-- not effective for larger tags (where + // we could have sampled anywhere within a bit cell and still + // gotten a good detection.) + float decision_margin; + + // The 3x3 homography matrix describing the projection from an + // "ideal" tag (with corners at (-1,-1), (1,-1), (1,1), and (-1, + // 1)) to pixels in the image. This matrix will be freed by + // apriltag_detection_destroy. + matd_t *H; + + // The center of the detection in image pixel coordinates. + double c[2]; + + // The corners of the tag in image pixel coordinates. These always + // wrap counter-clock wise around the tag. + double p[4][2]; +}; + +// don't forget to add a family! +apriltag_detector_t *apriltag_detector_create(); + +// add a family to the apriltag detector. caller still "owns" the family. +// a single instance should only be provided to one apriltag detector instance. +void apriltag_detector_add_family_bits(apriltag_detector_t *td, apriltag_family_t *fam, int bits_corrected); + +// Tunable, but really, 2 is a good choice. Values of >=3 +// consume prohibitively large amounts of memory, and otherwise +// you want the largest value possible. +static inline void apriltag_detector_add_family(apriltag_detector_t *td, apriltag_family_t *fam) +{ + apriltag_detector_add_family_bits(td, fam, 2); +} + +// does not deallocate the family. +void apriltag_detector_remove_family(apriltag_detector_t *td, apriltag_family_t *fam); + +// unregister all families, but does not deallocate the underlying tag family objects. +void apriltag_detector_clear_families(apriltag_detector_t *td); + +// Destroy the april tag detector (but not the underlying +// apriltag_family_t used to initialize it.) +void apriltag_detector_destroy(apriltag_detector_t *td); + +// Detect tags from an image and return an array of +// apriltag_detection_t*. You can use apriltag_detections_destroy to +// free the array and the detections it contains, or call +// _detection_destroy and zarray_destroy yourself. +zarray_t *apriltag_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig); + +// Call this method on each of the tags returned by apriltag_detector_detect +void apriltag_detection_destroy(apriltag_detection_t *det); + +// destroys the array AND the detections within it. +void apriltag_detections_destroy(zarray_t *detections); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "tag16h5" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t tag16h5 = { + .ncodes = 30, + .black_border = 1, + .d = 4, + .h = 5, + .codes = { + 0x000000000000231bUL, + 0x0000000000002ea5UL, + 0x000000000000346aUL, + 0x00000000000045b9UL, + 0x00000000000079a6UL, + 0x0000000000007f6bUL, + 0x000000000000b358UL, + 0x000000000000e745UL, + 0x000000000000fe59UL, + 0x000000000000156dUL, + 0x000000000000380bUL, + 0x000000000000f0abUL, + 0x0000000000000d84UL, + 0x0000000000004736UL, + 0x0000000000008c72UL, + 0x000000000000af10UL, + 0x000000000000093cUL, + 0x00000000000093b4UL, + 0x000000000000a503UL, + 0x000000000000468fUL, + 0x000000000000e137UL, + 0x0000000000005795UL, + 0x000000000000df42UL, + 0x0000000000001c1dUL, + 0x000000000000e9dcUL, + 0x00000000000073adUL, + 0x000000000000ad5fUL, + 0x000000000000d530UL, + 0x00000000000007caUL, + 0x000000000000af2eUL + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "tag25h7" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t tag25h7 = { + .ncodes = 242, + .black_border = 1, + .d = 5, + .h = 7, + .codes = { + 0x00000000004b770dUL, + 0x00000000011693e6UL, + 0x0000000001a599abUL, + 0x0000000000c3a535UL, + 0x000000000152aafaUL, + 0x0000000000accd98UL, + 0x0000000001cad922UL, + 0x00000000002c2fadUL, + 0x0000000000bb3572UL, + 0x00000000014a3b37UL, + 0x000000000186524bUL, + 0x0000000000c99d4cUL, + 0x000000000023bfeaUL, + 0x000000000141cb74UL, + 0x0000000001d0d139UL, + 0x0000000001670aebUL, + 0x0000000000851675UL, + 0x000000000150334eUL, + 0x00000000006e3ed8UL, + 0x0000000000fd449dUL, + 0x0000000000aa55ecUL, + 0x0000000001c86176UL, + 0x00000000015e9b28UL, + 0x00000000007ca6b2UL, + 0x000000000147c38bUL, + 0x0000000001d6c950UL, + 0x00000000008b0e8cUL, + 0x00000000011a1451UL, + 0x0000000001562b65UL, + 0x00000000013f53c8UL, + 0x0000000000d58d7aUL, + 0x0000000000829ec9UL, + 0x0000000000faccf1UL, + 0x000000000136e405UL, + 0x00000000007a2f06UL, + 0x00000000010934cbUL, + 0x00000000016a8b56UL, + 0x0000000001a6a26aUL, + 0x0000000000f85545UL, + 0x000000000195c2e4UL, + 0x000000000024c8a9UL, + 0x00000000012bfc96UL, + 0x00000000016813aaUL, + 0x0000000001a42abeUL, + 0x0000000001573424UL, + 0x0000000001044573UL, + 0x0000000000b156c2UL, + 0x00000000005e6811UL, + 0x0000000001659bfeUL, + 0x0000000001d55a63UL, + 0x00000000005bf065UL, + 0x0000000000e28667UL, + 0x0000000001e9ba54UL, + 0x00000000017d7c5aUL, + 0x0000000001f5aa82UL, + 0x0000000001a2bbd1UL, + 0x00000000001ae9f9UL, + 0x0000000001259e51UL, + 0x000000000134062bUL, + 0x0000000000e1177aUL, + 0x0000000000ed07a8UL, + 0x000000000162be24UL, + 0x000000000059128bUL, + 0x0000000001663e8fUL, + 0x00000000001a83cbUL, + 0x000000000045bb59UL, + 0x000000000189065aUL, + 0x00000000004bb370UL, + 0x00000000016fb711UL, + 0x000000000122c077UL, + 0x0000000000eca17aUL, + 0x0000000000dbc1f4UL, + 0x000000000088d343UL, + 0x000000000058ac5dUL, + 0x0000000000ba02e8UL, + 0x00000000001a1d9dUL, + 0x0000000001c72eecUL, + 0x0000000000924bc5UL, + 0x0000000000dccab3UL, + 0x0000000000886d15UL, + 0x000000000178c965UL, + 0x00000000005bc69aUL, + 0x0000000001716261UL, + 0x000000000174e2ccUL, + 0x0000000001ed10f4UL, + 0x0000000000156aa8UL, + 0x00000000003e2a8aUL, + 0x00000000002752edUL, + 0x000000000153c651UL, + 0x0000000001741670UL, + 0x0000000000765b05UL, + 0x000000000119c0bbUL, + 0x000000000172a783UL, + 0x00000000004faca1UL, + 0x0000000000f31257UL, + 0x00000000012441fcUL, + 0x00000000000d3748UL, + 0x0000000000c21f15UL, + 0x0000000000ac5037UL, + 0x000000000180e592UL, + 0x00000000007d3210UL, + 0x0000000000a27187UL, + 0x00000000002beeafUL, + 0x000000000026ff57UL, + 0x0000000000690e82UL, + 0x000000000077765cUL, + 0x0000000001a9e1d7UL, + 0x000000000140be1aUL, + 0x0000000001aa1e3aUL, + 0x0000000001944f5cUL, + 0x00000000019b5032UL, + 0x0000000000169897UL, + 0x0000000001068eb9UL, + 0x0000000000f30dbcUL, + 0x000000000106a151UL, + 0x0000000001d53e95UL, + 0x0000000001348ceeUL, + 0x0000000000cf4fcaUL, + 0x0000000001728bb5UL, + 0x0000000000dc1eecUL, + 0x000000000069e8dbUL, + 0x00000000016e1523UL, + 0x000000000105fa25UL, + 0x00000000018abb0cUL, + 0x0000000000c4275dUL, + 0x00000000006d8e76UL, + 0x0000000000e8d6dbUL, + 0x0000000000e16fd7UL, + 0x0000000001ac2682UL, + 0x000000000077435bUL, + 0x0000000000a359ddUL, + 0x00000000003a9c4eUL, + 0x000000000123919aUL, + 0x0000000001e25817UL, + 0x000000000002a836UL, + 0x00000000001545a4UL, + 0x0000000001209c8dUL, + 0x0000000000bb5f69UL, + 0x0000000001dc1f02UL, + 0x00000000005d5f7eUL, + 0x00000000012d0581UL, + 0x00000000013786c2UL, + 0x0000000000e15409UL, + 0x0000000001aa3599UL, + 0x000000000139aad8UL, + 0x0000000000b09d2aUL, + 0x000000000054488fUL, + 0x00000000013c351cUL, + 0x0000000000976079UL, + 0x0000000000b25b12UL, + 0x0000000001addb34UL, + 0x0000000001cb23aeUL, + 0x0000000001175738UL, + 0x0000000001303bb8UL, + 0x0000000000d47716UL, + 0x000000000188ceeaUL, + 0x0000000000baf967UL, + 0x0000000001226d39UL, + 0x000000000135e99bUL, + 0x000000000034adc5UL, + 0x00000000002e384dUL, + 0x000000000090d3faUL, + 0x0000000000232713UL, + 0x00000000017d49b1UL, + 0x0000000000aa84d6UL, + 0x0000000000c2ddf8UL, + 0x0000000001665646UL, + 0x00000000004f345fUL, + 0x00000000002276b1UL, + 0x0000000001255dd7UL, + 0x00000000016f4cccUL, + 0x00000000004aaffcUL, + 0x0000000000c46da6UL, + 0x000000000085c7b3UL, + 0x0000000001311fcbUL, + 0x00000000009c6c4fUL, + 0x000000000187d947UL, + 0x00000000008578e4UL, + 0x0000000000e2bf0bUL, + 0x0000000000a01b4cUL, + 0x0000000000a1493bUL, + 0x00000000007ad766UL, + 0x0000000000ccfe82UL, + 0x0000000001981b5bUL, + 0x0000000001cacc85UL, + 0x0000000000562cdbUL, + 0x00000000015b0e78UL, + 0x00000000008f66c5UL, + 0x00000000003332bfUL, + 0x00000000012ce754UL, + 0x0000000000096a76UL, + 0x0000000001d5e3baUL, + 0x000000000027ea41UL, + 0x00000000014412dfUL, + 0x000000000067b9b4UL, + 0x0000000000daa51aUL, + 0x00000000001dcb17UL, + 0x00000000004d4afdUL, + 0x00000000006335d5UL, + 0x0000000000ee2334UL, + 0x00000000017d4e55UL, + 0x0000000001b8b0f0UL, + 0x00000000014999e3UL, + 0x0000000001513dfaUL, + 0x0000000000765cf2UL, + 0x000000000056af90UL, + 0x00000000012e16acUL, + 0x0000000001d3d86cUL, + 0x0000000000ff279bUL, + 0x00000000018822ddUL, + 0x000000000099d478UL, + 0x00000000008dc0d2UL, + 0x000000000034b666UL, + 0x0000000000cf9526UL, + 0x000000000186443dUL, + 0x00000000007a8e29UL, + 0x00000000019c6aa5UL, + 0x0000000001f2a27dUL, + 0x00000000012b2136UL, + 0x0000000000d0cd0dUL, + 0x00000000012cb320UL, + 0x00000000017ddb0bUL, + 0x000000000005353bUL, + 0x00000000015b2cafUL, + 0x0000000001e5a507UL, + 0x000000000120f1e5UL, + 0x000000000114605aUL, + 0x00000000014efe4cUL, + 0x0000000000568134UL, + 0x00000000011b9f92UL, + 0x000000000174d2a7UL, + 0x0000000000692b1dUL, + 0x000000000039e4feUL, + 0x0000000000aaff3dUL, + 0x000000000096224cUL, + 0x00000000013c9f77UL, + 0x000000000110ee8fUL, + 0x0000000000f17beaUL, + 0x000000000099fb5dUL, + 0x0000000000337141UL, + 0x000000000002b54dUL, + 0x0000000001233a70UL + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "tag25h9" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t tag25h9 = { + .ncodes = 35, + .black_border = 1, + .d = 5, + .h = 9, + .codes = { + 0x000000000155cbf1UL, + 0x0000000001e4d1b6UL, + 0x00000000017b0b68UL, + 0x0000000001eac9cdUL, + 0x00000000012e14ceUL, + 0x00000000003548bbUL, + 0x00000000007757e6UL, + 0x0000000001065dabUL, + 0x0000000001baa2e7UL, + 0x0000000000dea688UL, + 0x000000000081d927UL, + 0x000000000051b241UL, + 0x0000000000dbc8aeUL, + 0x0000000001e50e19UL, + 0x00000000015819d2UL, + 0x00000000016d8282UL, + 0x000000000163e035UL, + 0x00000000009d9b81UL, + 0x000000000173eec4UL, + 0x0000000000ae3a09UL, + 0x00000000005f7c51UL, + 0x0000000001a137fcUL, + 0x0000000000dc9562UL, + 0x0000000001802e45UL, + 0x0000000001c3542cUL, + 0x0000000000870fa4UL, + 0x0000000000914709UL, + 0x00000000016684f0UL, + 0x0000000000c8f2a5UL, + 0x0000000000833ebbUL, + 0x000000000059717fUL, + 0x00000000013cd050UL, + 0x0000000000fa0ad1UL, + 0x0000000001b763b0UL, + 0x0000000000b991ceUL + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "tag36h10" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t tag36h10 = { + .ncodes = 2320, + .black_border = 1, + .d = 6, + .h = 10, + .codes = { + 0x00000001ca92a687UL, + 0x000000020521ac4cUL, + 0x000000027a3fb7d6UL, + 0x00000002b4cebd9bUL, + 0x00000003647bceeaUL, + 0x000000039f0ad4afUL, + 0x00000003d999da74UL, + 0x000000044eb7e5feUL, + 0x0000000538f3fd12UL, + 0x00000005738302d7UL, + 0x000000065dbf19ebUL, + 0x000000070d6c2b3aUL, + 0x00000007f7a8424eUL, + 0x0000000832374813UL, + 0x000000086cc64dd8UL, + 0x00000008a755539dUL, + 0x00000009570264ecUL, + 0x0000000991916ab1UL, + 0x0000000a06af763bUL, + 0x0000000ab65c878aUL, + 0x0000000b2b7a9314UL, + 0x0000000b660998d9UL, + 0x0000000bdb27a463UL, + 0x0000000cc563bb77UL, + 0x0000000e24bdde15UL, + 0x0000000ed46aef64UL, + 0x0000000f4988faeeUL, + 0x000000006e5417c7UL, + 0x0000000158902edbUL, + 0x00000001cdae3a65UL, + 0x0000000242cc45efUL, + 0x000000027d5b4bb4UL, + 0x00000002b7ea5179UL, + 0x000000032d085d03UL, + 0x00000003679762c8UL, + 0x00000003a226688dUL, + 0x00000003dcb56e52UL, + 0x000000048c627fa1UL, + 0x00000005769e96b5UL, + 0x00000006264ba804UL, + 0x0000000660daadc9UL, + 0x00000006d5f8b953UL, + 0x000000074b16c4ddUL, + 0x00000007fac3d62cUL, + 0x000000091f8ef305UL, + 0x000000095a1df8caUL, + 0x0000000994acfe8fUL, + 0x0000000a09cb0a19UL, + 0x0000000a445a0fdeUL, + 0x0000000a7ee915a3UL, + 0x0000000ab9781b68UL, + 0x0000000af407212dUL, + 0x0000000b69252cb7UL, + 0x0000000c8df04990UL, + 0x0000000d3d9d5adfUL, + 0x0000000d782c60a4UL, + 0x0000000f12158907UL, + 0x00000001d0c9ce43UL, + 0x000000020b58d408UL, + 0x00000002f594eb1cUL, + 0x00000003a541fc6bUL, + 0x0000000454ef0dbaUL, + 0x000000053f2b24ceUL, + 0x0000000629673be2UL, + 0x000000074e3258bbUL, + 0x00000008ad8c7b59UL, + 0x00000009d2579832UL, + 0x0000000a8204a981UL, + 0x0000000af722b50bUL, + 0x0000000b6c40c095UL, + 0x0000000ba6cfc65aUL, + 0x0000000f15311ce5UL, + 0x00000000748b3f83UL, + 0x00000000af1a4548UL, + 0x00000000e9a94b0dUL, + 0x00000002be217935UL, + 0x00000003e2ec960eUL, + 0x00000004cd28ad22UL, + 0x0000000507b7b2e7UL, + 0x000000054246b8acUL, + 0x000000057cd5be71UL, + 0x00000006a1a0db4aUL, + 0x00000006dc2fe10fUL, + 0x0000000876190972UL, + 0x000000099ae4264bUL, + 0x0000000abfaf4324UL, + 0x0000000c9427714cUL, + 0x0000000d09457cd6UL, + 0x0000000d43d4829bUL, + 0x0000000ea32ea539UL, + 0x0000000f52dbb688UL, + 0x0000000161e2ea75UL, + 0x0000000286ae074eUL, + 0x000000066a2d6963UL, + 0x00000008b3c3a315UL, + 0x00000008ee52a8daUL, + 0x0000000a131dc5b3UL, + 0x0000000e6bbb3352UL, + 0x0000000f55f74a66UL, + 0x0000000005a45bb5UL, + 0x000000007ac2673fUL, + 0x00000001da1c89ddUL, + 0x0000000289c99b2cUL, + 0x00000003ae94b805UL, + 0x000000050deedaa3UL, + 0x00000005830ce62dUL, + 0x00000005bd9bebf2UL, + 0x0000000632b9f77cUL, + 0x00000006e26708cbUL, + 0x0000000841c12b69UL, + 0x000000092bfd427dUL, + 0x00000009668c4842UL, + 0x00000009dbaa53ccUL, + 0x0000000b007570a5UL, + 0x0000000b3b04766aUL, + 0x0000000c25408d7eUL, + 0x0000000ea965ccf5UL, + 0x0000000f93a1e409UL, + 0x00000000434ef558UL, + 0x00000001681a1231UL, + 0x00000001dd381dbbUL, + 0x0000000302033a94UL, + 0x000000075aa0a833UL, + 0x000000092f18d65bUL, + 0x00000009a436e1e5UL, + 0x0000000a1954ed6fUL, + 0x0000000b78af100dUL, + 0x0000000bb33e15d2UL, + 0x0000000c62eb2721UL, + 0x00000000466a8936UL, + 0x00000000f6179a85UL, + 0x000000016b35a60fUL, + 0x0000000589440de9UL, + 0x00000006738024fdUL, + 0x0000000847f85325UL, + 0x00000009e1e17b88UL, + 0x0000000acc1d929cUL, + 0x0000000b06ac9861UL, + 0x0000000d5042d213UL, + 0x0000000fd468118aUL, + 0x00000000f9332e63UL, + 0x0000000342c96815UL, + 0x000000037d586ddaUL, + 0x0000000551d09c02UL, + 0x00000005c6eea78cUL, + 0x00000006017dad51UL, + 0x00000009354ffe17UL, + 0x00000009aa6e09a1UL, + 0x0000000a94aa20b5UL, + 0x0000000acf39267aUL, + 0x0000000bb9753d8eUL, + 0x0000000bf4044353UL, + 0x000000008730b6b7UL, + 0x00000001716ccdcbUL, + 0x000000022119df1aUL, + 0x00000003f5920d42UL, + 0x000000058f7b35a5UL, + 0x00000006b446527eUL, + 0x0000000972fa97baUL, + 0x00000009e818a344UL, + 0x0000000a5d36aeceUL, + 0x0000000d1beaf40aUL, + 0x0000000dcb980559UL, + 0x0000000f65812dbcUL, + 0x0000000139f95be4UL, + 0x00000006b761e65cUL, + 0x00000006f1f0ec21UL, + 0x0000000a605242acUL, + 0x0000000e43d1a4c1UL, + 0x000000029c6f1260UL, + 0x0000000386ab2974UL, + 0x00000004e6054c12UL, + 0x00000008c984ae27UL, + 0x000000097931bf76UL, + 0x00000009ee4fcb00UL, + 0x0000000d22221bc6UL, + 0x0000000e46ed389fUL, + 0x0000000ebc0b4429UL, + 0x00000006f82813ddUL, + 0x0000000732b719a2UL, + 0x00000009072f47caUL, + 0x0000000941be4d8fUL, + 0x000000097c4d5354UL, + 0x00000009f16b5edeUL, + 0x0000000b8b548741UL, + 0x0000000d253dafa4UL, + 0x0000000d5fccb569UL, + 0x0000000d9a5bbb2eUL, + 0x0000000e4a08cc7dUL, + 0x00000003c77156f5UL, + 0x00000007aaf0b90aUL, + 0x0000000b53e1155aUL, + 0x0000000b8e701b1fUL, + 0x000000005c2b9448UL, + 0x000000014667ab5cUL, + 0x000000047a39fc22UL, + 0x00000004ef5807acUL, + 0x000000064eb22a4aUL, + 0x0000000982847b10UL, + 0x0000000aa74f97e9UL, + 0x0000000ae1de9daeUL, + 0x0000000b56fca938UL, + 0x0000000f750b1112UL, + 0x00000001bea14ac4UL, + 0x00000001f9305089UL, + 0x0000000233bf564eUL, + 0x000000031dfb6d62UL, + 0x00000003931978ecUL, + 0x000000052d02a14fUL, + 0x00000005a220acd9UL, + 0x0000000b1f893751UL, + 0x0000000fb2b5aab5UL, + 0x000000040b531854UL, + 0x00000005a53c40b7UL, + 0x00000008d90e917dUL, + 0x00000009139d9742UL, + 0x000000094e2c9d07UL, + 0x0000000d6c3b04e1UL, + 0x0000000e910621baUL, + 0x0000000f40b33309UL, + 0x00000001152b6131UL, + 0x000000032432951eUL, + 0x00000003d3dfa66dUL, + 0x000000065804e5e4UL, + 0x0000000ab0a25383UL, + 0x0000000b604f64d2UL, + 0x0000000de474a449UL, + 0x000000011846f50fUL, + 0x00000006d03e854cUL, + 0x00000007455c90d6UL, + 0x0000000ab3bde761UL, + 0x0000000dad013262UL, + 0x0000000e973d4976UL, + 0x00000002b54bb150UL, + 0x00000009577f58a1UL, + 0x00000009920e5e66UL, + 0x0000000b66868c8eUL, + 0x0000000f4a05eea3UL, + 0x00000003dd326207UL, + 0x00000005b1aa902fUL, + 0x000000099529f244UL, + 0x0000000b2f131aa7UL, + 0x0000000d038b48cfUL, + 0x0000000d3e1a4e94UL, + 0x000000024664cd82UL, + 0x000000036b2fea5bUL, + 0x000000095db6805dUL, + 0x0000000a0d6391acUL, + 0x0000000abd10a2fbUL, + 0x000000015f444a4cUL, + 0x00000002be9e6ceaUL, + 0x000000057d52b226UL, + 0x00000005f270bdb0UL, + 0x0000000b6fd94828UL, + 0x0000000879b19105UL, + 0x0000000d476d0a2eUL, + 0x0000000e6c382707UL, + 0x0000000dbfa6a996UL, + 0x00000001689705e6UL, + 0x00000003b22d3f98UL, + 0x0000000636527f0fUL, + 0x00000007d03ba772UL, + 0x0000000ee78d5a4dUL, + 0x0000000bf165a32aUL, + 0x0000000c2bf4a8efUL, + 0x0000000517be89f2UL, + 0x000000067718ac90UL, + 0x00000006b1a7b255UL, + 0x0000000726c5bddfUL, + 0x0000000bb9f23143UL, + 0x00000001375abbbbUL, + 0x0000000296b4de59UL, + 0x00000008893b745bUL, + 0x0000000a9842a848UL, + 0x0000000b827ebf5cUL, + 0x00000003840c894bUL, + 0x00000006b7deda11UL, + 0x0000000bc02958ffUL, + 0x000000055ba04b51UL, + 0x000000076aa77f3eUL, + 0x00000009b43db8f0UL, + 0x00000009eeccbeb5UL, + 0x0000000a295bc47aUL, + 0x0000000b4e26e153UL, + 0x0000000e476a2c54UL, + 0x00000006be1601cdUL, + 0x00000006f8a50792UL, + 0x000000097cca4709UL, + 0x0000000bc66080bbUL, + 0x00000001093a056eUL, + 0x00000006fbc09b70UL, + 0x0000000b8eed0ed4UL, + 0x0000000cee473172UL, + 0x000000023120b625UL, + 0x00000005da111275UL, + 0x0000000cf162c550UL, + 0x0000000ec8f68756UL, + 0x0000000b5db0c4a9UL, + 0x00000002b2ad1127UL, + 0x0000000536d2509eUL, + 0x00000009c9fec402UL, + 0x0000000c1394fdb4UL, + 0x000000006c326b53UL, + 0x00000005e99af5cbUL, + 0x0000000af1e574b9UL, + 0x0000000e6046cb44UL, + 0x0000000661d49533UL, + 0x00000008e5f9d4aaUL, + 0x0000000db3b54dd3UL, + 0x0000000e63625f22UL, + 0x0000000e9df164e7UL, + 0x0000000455e8f524UL, + 0x00000005b54317c2UL, + 0x0000000be258b389UL, + 0x000000054340a016UL, + 0x00000005b85eaba0UL, + 0x00000001284dcc1aUL, + 0x000000024d18e8f3UL, + 0x00000004d13e286aUL, + 0x00000008b4bd8a7fUL, + 0x0000000215a5770cUL, + 0x000000046572d87aUL, + 0x0000000c2c719ca4UL, + 0x00000004ddac77e2UL, + 0x0000000d19c94796UL, + 0x00000002d1c0d7d3UL, + 0x00000009ae8384e9UL, + 0x00000009e9128aaeUL, + 0x0000000ca7c6cfeaUL, + 0x0000000016282675UL, + 0x0000000ad985c97eUL, + 0x00000004af8bc195UL, + 0x00000009f580da26UL, + 0x0000000a6a9ee5b0UL, + 0x0000000bc9f9084eUL, + 0x0000000d63e230b1UL, + 0x0000000c4232a7b6UL, + 0x0000000d66fdc48fUL, + 0x0000000ec657e72dUL, + 0x0000000a364707a7UL, + 0x0000000f79208c5aUL, + 0x0000000de88a1f91UL, + 0x0000000574f9ddf6UL, + 0x000000065f35f50aUL, + 0x000000069ce08eadUL, + 0x0000000490f4ee9eUL, + 0x0000000c9282b88dUL, + 0x0000000752c4c7b8UL, + 0x0000000b364429cdUL, + 0x00000008b53a7e34UL, + 0x0000000be90ccefaUL, + 0x0000000b0507dfa2UL, + 0x000000000d525e90UL, + 0x00000005c549eecdUL, + 0x0000000e3bf5c446UL, + 0x0000000936c6d936UL, + 0x00000009747172d9UL, + 0x0000000ca843c39fUL, + 0x0000000d57f0d4eeUL, + 0x00000002d5595f66UL, + 0x0000000bfbb2462eUL, + 0x0000000266727b98UL, + 0x00000007ac679429UL, + 0x000000026fc53732UL, + 0x0000000656602d25UL, + 0x00000002eb1a6a78UL, + 0x00000004850392dbUL, + 0x0000000e5b098af2UL, + 0x0000000ab534c280UL, + 0x00000009ce143f4aUL, + 0x0000000f4b7cc9c2UL, + 0x0000000035b8e0d6UL, + 0x0000000871d5b08aUL, + 0x00000005b958930aUL, + 0x00000000b429a7faUL, + 0x000000054d8d431aUL, + 0x00000007d1b28291UL, + 0x0000000a1e645021UL, + 0x0000000b80da069dUL, + 0x0000000eef3b5d28UL, + 0x0000000263d3db6fUL, + 0x000000009592d503UL, + 0x00000004b9d86499UL, + 0x00000006c8df9886UL, + 0x0000000a3740ef11UL, + 0x0000000c4963b6dcUL, + 0x000000006da94672UL, + 0x000000053b64bf9bUL, + 0x0000000b2deb559dUL, + 0x0000000f116ab7b2UL, + 0x00000008ace1aa04UL, + 0x00000008ea8c43a7UL, + 0x00000006a4119dd3UL, + 0x000000099d54e8d4UL, + 0x0000000c969833d5UL, + 0x0000000f554c7911UL, + 0x00000003ade9e6b0UL, + 0x00000006e1bc3776UL, + 0x00000007916948c5UL, + 0x0000000dbe7ee48cUL, + 0x000000079484dca3UL, + 0x0000000f992e3a70UL, + 0x0000000884f81b73UL, + 0x0000000c68777d88UL, + 0x0000000603ee6fdaUL, + 0x0000000728b98cb3UL, + 0x0000000b12701684UL, + 0x0000000d5f21e414UL, + 0x0000000058652f15UL, + 0x00000002dc8a6e8cUL, + 0x00000004767396efUL, + 0x0000000b8dc549caUL, + 0x0000000f36b5a61aUL, + 0x00000000d09ece7dUL, + 0x0000000dda77175aUL, + 0x000000005e9c56d1UL, + 0x000000073e7a97c5UL, + 0x0000000b21f9f9daUL, + 0x0000000de3c9d2f4UL, + 0x000000069504ae32UL, + 0x000000077f40c546UL, + 0x0000000ed1217de6UL, + 0x00000003a1f88aedUL, + 0x0000000e623a9a18UL, + 0x00000000aeec67a8UL, + 0x0000000bea83aa19UL, + 0x000000092eeaf8bbUL, + 0x0000000a5d08d12eUL, + 0x0000000819a9bf38UL, + 0x0000000473d4f6c6UL, + 0x0000000b192431f5UL, + 0x0000000a6c92b484UL, + 0x00000007046885b5UL, + 0x0000000b9ab08cf7UL, + 0x0000000782d94cd9UL, + 0x0000000f158032faUL, + 0x0000000077f5e976UL, + 0x000000012dda2281UL, + 0x0000000e72417123UL, + 0x00000003056de487UL, + 0x0000000e3de9931aUL, + 0x0000000eb3079ea4UL, + 0x0000000e4420bad6UL, + 0x0000000439c2e4b6UL, + 0x000000047da4a615UL, + 0x00000000d7cfdda3UL, + 0x000000056afc5107UL, + 0x0000000e978c5f8bUL, + 0x00000005aede1266UL, + 0x0000000af1b79719UL, + 0x0000000f8b1b3239UL, + 0x000000075e8845dbUL, + 0x0000000bf1b4b93fUL, + 0x0000000fd5341b54UL, + 0x0000000a2373b2d3UL, + 0x00000005967e672bUL, + 0x0000000a2cc66e6dUL, + 0x0000000b17028581UL, + 0x0000000b54ad1f24UL, + 0x0000000e91d22b84UL, + 0x0000000de85c41f1UL, + 0x000000053d588e6fUL, + 0x0000000e9e407afcUL, + 0x0000000fc6272bb3UL, + 0x0000000a8ca0629aUL, + 0x0000000b86665d04UL, + 0x000000005a58fde9UL, + 0x00000001855b427eUL, + 0x0000000aabb42946UL, + 0x0000000e204ca78dUL, + 0x000000032897267bUL, + 0x00000000a78d7ae2UL, + 0x000000096536a598UL, + 0x0000000bf2aea0a9UL, + 0x00000000c9bcd56cUL, + 0x000000081eb921eaUL, + 0x00000002732fe125UL, + 0x00000002eb69808dUL, + 0x000000061f3bd153UL, + 0x00000008ddf0168fUL, + 0x0000000921d1d7eeUL, + 0x00000002bd48ca40UL, + 0x000000083ab154b8UL, + 0x00000005f436aee4UL, + 0x000000093dca0abcUL, + 0x000000026d75ad1eUL, + 0x0000000872a1ba54UL, + 0x0000000373a9f700UL, + 0x000000050d931f63UL, + 0x000000012d2f512cUL, + 0x0000000c6efdbb59UL, + 0x000000088e99ed22UL, + 0x0000000903b7f8acUL, + 0x0000000a9da1210fUL, + 0x0000000a2eba3d41UL, + 0x0000000fe9cd615cUL, + 0x0000000fb8911731UL, + 0x00000001cab3defcUL, + 0x0000000e6289b02dUL, + 0x000000066d6a35b6UL, + 0x0000000b0096a91aUL, + 0x0000000c9afcc532UL, + 0x000000080aebe5acUL, + 0x0000000d2f2e9768UL, + 0x0000000cc67edb56UL, + 0x0000000a51e37f35UL, + 0x00000006ac0eb6c3UL, + 0x00000006af2a4aa1UL, + 0x0000000e76290ecbUL, + 0x000000037e738db9UL, + 0x000000072d9b11c5UL, + 0x000000076e613f46UL, + 0x00000004f073278bUL, + 0x00000000e1eea307UL, + 0x0000000e9e8f9111UL, + 0x00000000793ee6f5UL, + 0x000000017304e15fUL, + 0x00000007a3361104UL, + 0x0000000731339958UL, + 0x00000008daa6a511UL, + 0x0000000a4037ef6bUL, + 0x0000000210896f2fUL, + 0x0000000afc535032UL, + 0x0000000e3025a0f8UL, + 0x000000063e21ba5fUL, + 0x00000003ebb5b8c8UL, + 0x0000000f9c6b06c3UL, + 0x0000000ca95ee37eUL, + 0x000000081f852bb4UL, + 0x0000000d6895d823UL, + 0x00000007040cca75UL, + 0x00000004d66ec391UL, + 0x00000004a216e588UL, + 0x000000051d6c18ceUL, + 0x000000047711c319UL, + 0x00000006ae7f794cUL, + 0x00000004abe694d7UL, + 0x0000000bc96f6f6eUL, + 0x000000057aa76cd2UL, + 0x0000000f948f2648UL, + 0x000000031bcd1bc3UL, + 0x000000094c7b3f1dUL, + 0x000000032eef86acUL, + 0x0000000668f8ff2eUL, + 0x00000006de170ab8UL, + 0x00000009341b93e2UL, + 0x0000000974e1c163UL, + 0x000000073182af6dUL, + 0x00000005d85fb48bUL, + 0x000000078b257bdeUL, + 0x0000000173d0eb29UL, + 0x00000005add785d1UL, + 0x0000000af6e83240UL, + 0x0000000dce79166cUL, + 0x000000022716840bUL, + 0x00000007b408f1d9UL, + 0x0000000de43a217eUL, + 0x000000036e10fb6eUL, + 0x0000000ea9a83ddfUL, + 0x00000004dcf50162UL, + 0x00000009aab07a8bUL, + 0x0000000281364431UL, + 0x00000008392dd46eUL, + 0x00000000945e6aceUL, + 0x00000008d07b3a82UL, + 0x0000000d012f1990UL, + 0x0000000b7098acc7UL, + 0x0000000c2fcfa16cUL, + 0x00000001e7c731a9UL, + 0x0000000f16ea68eeUL, + 0x00000002fa69cb03UL, + 0x00000004cee1f92bUL, + 0x00000001e20cfda2UL, + 0x00000009e9d1ef4dUL, + 0x0000000e83358a6dUL, + 0x000000059a873d48UL, + 0x0000000a6842b671UL, + 0x00000006885bdbefUL, + 0x000000073e4014faUL, + 0x00000007b9954840UL, + 0x0000000548157ffdUL, + 0x00000008853a8c5dUL, + 0x0000000eb8874fe0UL, + 0x0000000b25d4f257UL, + 0x000000036b447da5UL, + 0x000000071d87958fUL, + 0x0000000eedd91553UL, + 0x00000004af23612aUL, + 0x0000000278329eacUL, + 0x0000000191121b76UL, + 0x00000006e691175dUL, + 0x00000000bd140329UL, + 0x00000006ed4532ceUL, + 0x0000000d5e3c8ff4UL, + 0x0000000e26c64033UL, + 0x0000000494a2097bUL, + 0x0000000f5e36d440UL, + 0x0000000b7818d202UL, + 0x0000000a63548c34UL, + 0x0000000682f0bdfdUL, + 0x00000003d3c65c17UL, + 0x00000004c4399ae7UL, + 0x00000006b18e67ffUL, + 0x00000004778211a3UL, + 0x00000004089b2dd5UL, + 0x000000021edee850UL, + 0x0000000739cede72UL, + 0x0000000858dfc744UL, + 0x00000004bc5dba6cUL, + 0x000000021cbd3bdcUL, + 0x0000000ac83de313UL, + 0x00000006135f08daUL, + 0x0000000d3a3a9f0bUL, + 0x0000000eb2716099UL, + 0x000000040b88e413UL, + 0x0000000992442a25UL, + 0x0000000c639de695UL, + 0x0000000683bcc7c7UL, + 0x00000006245fc74fUL, + 0x0000000543766bd5UL, + 0x0000000375356569UL, + 0x0000000fa45b7a88UL, + 0x00000009f29b1207UL, + 0x0000000ba245457cUL, + 0x00000005b98e5ec9UL, + 0x0000000204aca6b6UL, + 0x0000000d52e9605bUL, + 0x0000000504a40d28UL, + 0x0000000ab6e1695eUL, + 0x0000000a26481ebbUL, + 0x00000009455ec341UL, + 0x00000002f05f98e9UL, + 0x0000000ead83365cUL, + 0x0000000b928d8486UL, + 0x00000007b860de0bUL, + 0x0000000964ef7da2UL, + 0x00000002422962b9UL, + 0x000000028f5ddfb2UL, + 0x00000008c5c63713UL, + 0x00000009068c6494UL, + 0x000000050aad5744UL, + 0x000000093e7cca30UL, + 0x00000009825e8b8fUL, + 0x00000003a8b4947dUL, + 0x0000000fa06737b5UL, + 0x0000000cb9c963e8UL, + 0x000000091a2bc332UL, + 0x0000000284666b59UL, + 0x0000000ceb82a1c8UL, + 0x0000000a2fe9f06aUL, + 0x000000006fa50365UL, + 0x000000019aa747faUL, + 0x0000000a6e117dc2UL, + 0x00000002b3810910UL, + 0x0000000ff7e857b2UL, + 0x0000000048b55c3eUL, + 0x0000000975456ac2UL, + 0x0000000ad200ed37UL, + 0x0000000e4d4d86efUL, + 0x0000000b3ec62491UL, + 0x00000008cd465c4eUL, + 0x00000008a2be2d94UL, + 0x00000005a9f7d648UL, + 0x000000059e067a85UL, + 0x0000000b5c35327eUL, + 0x0000000c4ca8714eUL, + 0x00000000e927a04cUL, + 0x0000000f71eac628UL, + 0x0000000109354e62UL, + 0x00000001037b1a5bUL, + 0x000000026c27f893UL, + 0x00000003597fa385UL, + 0x0000000ee24b62efUL, + 0x00000004b31f921cUL, + 0x0000000650244e5dUL, + 0x0000000cfec64526UL, + 0x0000000cd4bb0a21UL, + 0x0000000648c56197UL, + 0x0000000bd95056f8UL, + 0x0000000983c8c183UL, + 0x0000000ddc662f22UL, + 0x00000005631bb980UL, + 0x00000001203f56f3UL, + 0x00000006a0c37549UL, + 0x0000000a59baa8a4UL, + 0x00000006a23a5068UL, + 0x0000000ad609c354UL, + 0x0000000f6f6d5e74UL, + 0x000000036bc95f79UL, + 0x0000000424c92c62UL, + 0x00000003692abf50UL, + 0x00000000a4bc460dUL, + 0x00000001b4434b89UL, + 0x00000004eb31302dUL, + 0x00000009a3a891f9UL, + 0x000000093af8d5e7UL, + 0x0000000ef60bfa02UL, + 0x0000000607a378d6UL, + 0x00000005a5a7d835UL, + 0x0000000536c0f467UL, + 0x000000011f66a7feUL, + 0x000000074c7c43c5UL, + 0x000000066eae7c29UL, + 0x0000000f5a785d2cUL, + 0x0000000d3948a5c0UL, + 0x0000000ec1094aa4UL, + 0x0000000fcad61c19UL, + 0x000000049ca7108aUL, + 0x000000077437f4b6UL, + 0x0000000553083d4aUL, + 0x00000005c26c14cdUL, + 0x00000006eb4caceeUL, + 0x0000000e8aded63cUL, + 0x0000000132aa4b5cUL, + 0x000000057603a19eUL, + 0x0000000ee359dda3UL, + 0x0000000d0f5ea330UL, + 0x000000046b0f0b1fUL, + 0x0000000d47cbfc81UL, + 0x00000003ed1b37b0UL, + 0x00000004c8c752d8UL, + 0x0000000ac202044bUL, + 0x0000000207f16128UL, + 0x000000053f5c3981UL, + 0x000000070e1a33a2UL, + 0x0000000ed8348baaUL, + 0x0000000798f94a3eUL, + 0x00000008896c890eUL, + 0x0000000521425a3fUL, + 0x0000000c8329e9eaUL, + 0x000000041f238ba5UL, + 0x00000001093d3c81UL, + 0x0000000cab628e90UL, + 0x0000000a1b4bf356UL, + 0x000000092eee2fceUL, + 0x000000059d35b9afUL, + 0x00000002176e9f53UL, + 0x00000007c9abfb89UL, + 0x0000000b06d107e9UL, + 0x0000000e94c318d5UL, + 0x00000002f397ae30UL, + 0x0000000d7e5a1a48UL, + 0x000000098c4abc47UL, + 0x0000000574737c29UL, + 0x0000000d7f5401b2UL, + 0x0000000852b87bc6UL, + 0x00000001180fa957UL, + 0x0000000501c63328UL, + 0x0000000fd28c0d13UL, + 0x0000000f764aa079UL, + 0x0000000c8a6f8c5aUL, + 0x0000000975b10240UL, + 0x00000006bd33e4c0UL, + 0x0000000a1113e39cUL, + 0x0000000abcfa8fb8UL, + 0x0000000149ea1facUL, + 0x0000000f6443556fUL, + 0x0000000959da07e7UL, + 0x00000004721a2ac4UL, + 0x000000030bde0f15UL, + 0x0000000c7c4fdef8UL, + 0x0000000b7feb4465UL, + 0x000000056675073cUL, + 0x000000096f3f57b9UL, + 0x0000000876f0386eUL, + 0x0000000393f0a7e8UL, + 0x000000032b40ebd6UL, + 0x000000010a11346aUL, + 0x0000000fb81f48aeUL, + 0x00000000a892877eUL, + 0x000000086f636e08UL, + 0x00000004fbc4d72bUL, + 0x0000000561d5f314UL, + 0x0000000ca18e2835UL, + 0x00000007e6f519f5UL, + 0x00000008b94e7983UL, + 0x0000000619adfaf3UL, + 0x00000004c9ddbbabUL, + 0x0000000cb6a461f2UL, + 0x00000000f6e22456UL, + 0x0000000858c9b401UL, + 0x000000092dc1b3b8UL, + 0x00000003a783615bUL, + 0x0000000c74b66f67UL, + 0x0000000ea90891bcUL, + 0x000000031a829e4bUL, + 0x00000007bd38f505UL, + 0x0000000b4476ea80UL, + 0x00000001af371feaUL, + 0x000000084894ff56UL, + 0x00000000537584dfUL, + 0x0000000d4ebdd1d0UL, + 0x0000000b43cc192bUL, + 0x000000076700d287UL, + 0x0000000aaad9fa58UL, + 0x0000000fa511710fUL, + 0x00000006e54699e5UL, + 0x00000006d73391aeUL, + 0x00000003c2f1fb49UL, + 0x00000004fbd96a75UL, + 0x0000000252e6304bUL, + 0x0000000e72826214UL, + 0x00000008fe6c9336UL, + 0x0000000326397743UL, + 0x00000000e03bc524UL, + 0x0000000dedac9594UL, + 0x000000004ff19096UL, + 0x0000000409b4cdbbUL, + 0x0000000b15921888UL, + 0x0000000a259bcd6dUL, + 0x000000043c67f305UL, + 0x00000001dc65dcecUL, + 0x00000001730b4f85UL, + 0x0000000f8a48f16aUL, + 0x000000057a30e743UL, + 0x000000005afd9839UL, + 0x0000000682d5f3aeUL, + 0x00000000b694337eUL, + 0x0000000758c7dacfUL, + 0x000000018fa1ae7dUL, + 0x00000005ba9b5984UL, + 0x000000032e1d45ddUL, + 0x0000000672f05518UL, + 0x0000000382ffc5b1UL, + 0x00000008f0b08f33UL, + 0x0000000b4a4d9ff0UL, + 0x000000053ba0f980UL, + 0x00000002ac0751fbUL, + 0x0000000ab005de73UL, + 0x000000061ab7be9bUL, + 0x000000063078c9adUL, + 0x000000027659d148UL, + 0x0000000c653c684fUL, + 0x0000000ecee05017UL, + 0x000000024378ce5eUL, + 0x0000000d0f7e5bacUL, + 0x00000008b4bf4199UL, + 0x0000000b7aa495fbUL, + 0x0000000f3d6b78a5UL, + 0x000000098bab1024UL, + 0x00000006b4971fadUL, + 0x00000000723d6c89UL, + 0x0000000a17071a75UL, + 0x0000000d55a301f4UL, + 0x0000000988de925bUL, + 0x00000007ca276f45UL, + 0x0000000321b6e484UL, + 0x0000000316149ed6UL, + 0x0000000b8dba5bb9UL, + 0x0000000aad4df3f4UL, + 0x0000000178e204f5UL, + 0x000000095cd2e357UL, + 0x000000073fb8a733UL, + 0x000000084ca10c86UL, + 0x000000089498492dUL, + 0x00000005b9bdf383UL, + 0x000000066c58bb10UL, + 0x0000000f153ac21eUL, + 0x00000007ca5d3b04UL, + 0x0000000637a521c7UL, + 0x0000000b5ed589c1UL, + 0x0000000d0a3c644eUL, + 0x00000003d5d0754fUL, + 0x0000000c6b901174UL, + 0x00000003e96fd3edUL, + 0x000000079c2fdf8cUL, + 0x00000006594ae371UL, + 0x00000003504fd77aUL, + 0x000000032b81dcc7UL, + 0x000000057b4f3e35UL, + 0x00000004c9808072UL, + 0x0000000a06c10993UL, + 0x0000000b059666afUL, + 0x000000072b69c034UL, + 0x0000000e33ae836eUL, + 0x0000000ad6cadf0dUL, + 0x000000019573ace1UL, + 0x0000000d562fd1e7UL, + 0x0000000847804d9dUL, + 0x00000009e32f6734UL, + 0x00000002355c580fUL, + 0x00000002f177b8d6UL, + 0x0000000d689ac650UL, + 0x0000000071b70abcUL, + 0x0000000254915730UL, + 0x0000000c5934f949UL, + 0x0000000134d59d09UL, + 0x00000002c731fb06UL, + 0x0000000d90c6c5cbUL, + 0x0000000cc3f9bca4UL, + 0x0000000bf078980cUL, + 0x000000080838e95aUL, + 0x00000005ccd6f054UL, + 0x00000000378bae56UL, + 0x00000008d1ddb978UL, + 0x000000093b875cf4UL, + 0x0000000e2ce90bc6UL, + 0x0000000ec291b91bUL, + 0x0000000d0a11bdc1UL, + 0x0000000751be7244UL, + 0x0000000579fcd29eUL, + 0x0000000f76e5ccb1UL, + 0x0000000eb33da184UL, + 0x0000000c0ac75b0fUL, + 0x000000015454fb33UL, + 0x00000008b92a411cUL, + 0x00000007da34b476UL, + 0x00000004f413d45eUL, + 0x000000010ec1dbeaUL, + 0x0000000650739b93UL, + 0x0000000315e08a31UL, + 0x0000000d4fd5f1bdUL, + 0x0000000b5058a126UL, + 0x000000020d5cb63bUL, + 0x0000000c1598dfe7UL, + 0x0000000a0a2a338dUL, + 0x0000000e29af7686UL, + 0x000000083fd0cac9UL, + 0x000000014a8094d8UL, + 0x0000000816e0afa3UL, + 0x0000000499ef5d2cUL, + 0x0000000bddbd0d95UL, + 0x0000000a30839ca9UL, + 0x00000004fd33fb4cUL, + 0x0000000ef63557b7UL, + 0x0000000535f06ab2UL, + 0x00000000d47d352eUL, + 0x0000000a371e6dc4UL, + 0x00000008ac914b17UL, + 0x00000006ba9d69d7UL, + 0x0000000096da89aaUL, + 0x000000065bbd5d14UL, + 0x0000000d41d2c5c4UL, + 0x000000052a283583UL, + 0x00000004c1f56d26UL, + 0x000000086cd9984aUL, + 0x000000026cbcedc6UL, + 0x00000001aa0eaa03UL, + 0x0000000b95d5ad2cUL, + 0x0000000e2eb56b20UL, + 0x0000000ff49d9d5cUL, + 0x0000000cce338378UL, + 0x0000000330e9fac7UL, + 0x0000000e2f53974aUL, + 0x0000000668d1c6d5UL, + 0x0000000eca0ba751UL, + 0x00000008d48ab5e6UL, + 0x0000000d205e18cdUL, + 0x00000001c391633cUL, + 0x0000000ef5d02e5fUL, + 0x0000000d12bb5f20UL, + 0x0000000323215199UL, + 0x000000088f5b3ffcUL, + 0x0000000931445f29UL, + 0x0000000b893cb727UL, + 0x000000032851ecc0UL, + 0x000000080b44d81bUL, + 0x00000005aa48da98UL, + 0x000000046d1e1284UL, + 0x00000004c837ba14UL, + 0x0000000eb22c26deUL, + 0x0000000e51e9d246UL, + 0x00000008d03deee6UL, + 0x00000005af8e0909UL, + 0x0000000bde9773a4UL, + 0x0000000bf611cabfUL, + 0x0000000d24ac96e7UL, + 0x00000009fe919318UL, + 0x000000050d0206a6UL, + 0x0000000b43b9741cUL, + 0x0000000ba48d4fb3UL, + 0x00000006bccd7290UL, + 0x00000008bc6bfb9cUL, + 0x0000000e5a036c9fUL, + 0x0000000a80a2cfeeUL, + 0x0000000c193655a7UL, + 0x00000007c8e5170dUL, + 0x00000006141edbbbUL, + 0x00000004d6b990dcUL, + 0x0000000cc49b5702UL, + 0x00000002343fef58UL, + 0x0000000d50cb593cUL, + 0x00000004248a60cdUL, + 0x0000000901cfbd4cUL, + 0x000000064a4c8736UL, + 0x00000001b2dcbaeaUL, + 0x0000000d691e5f4cUL, + 0x0000000df352a493UL, + 0x00000001991ac7daUL, + 0x00000004c4879f45UL, + 0x00000009b34aadeeUL, + 0x000000052bb3db0dUL, + 0x00000007b9a8c9d3UL, + 0x0000000d7ce6e47eUL, + 0x0000000ec0b922d8UL, + 0x00000008079cab6bUL, + 0x0000000abadc8899UL, + 0x00000000f57b93b7UL, + 0x000000005c4ef219UL, + 0x0000000d7a438d49UL, + 0x0000000f55ecca97UL, + 0x0000000d07899f1dUL, + 0x0000000260947d6cUL, + 0x0000000ffbd21ab6UL, + 0x0000000d04ff923eUL, + 0x0000000964b72033UL, + 0x000000031ac3fd7eUL, + 0x0000000d2c52e2c4UL, + 0x0000000799a640efUL, + 0x000000098dd061edUL, + 0x00000005cb2ab7b8UL, + 0x000000072f3881c8UL, + 0x0000000e65ed1164UL, + 0x000000034fa0bd5bUL, + 0x000000064f9823cdUL, + 0x00000003797e1ac0UL, + 0x00000002fb8a4751UL, + 0x00000006f347342eUL, + 0x000000022dd7ea0aUL, + 0x0000000b19b65e57UL, + 0x000000044fe83e8aUL, + 0x000000007732732eUL, + 0x000000064de20ed7UL, + 0x000000006c9ea834UL, + 0x00000008ce066650UL, + 0x0000000c2a685ff0UL, + 0x000000064f19b01fUL, + 0x0000000491ab8a88UL, + 0x000000041212fe5aUL, + 0x00000006f9916f3bUL, + 0x0000000694f72e71UL, + 0x0000000ad7a5b35eUL, + 0x0000000f62795292UL, + 0x0000000c8cdc3d3aUL, + 0x0000000fbc6b3518UL, + 0x000000067b631901UL, + 0x00000005b5ba79d5UL, + 0x0000000f4fadebddUL, + 0x0000000ac7c802e7UL, + 0x0000000385712d9dUL, + 0x000000064bd375b4UL, + 0x0000000c9a11df70UL, + 0x000000088355bf31UL, + 0x0000000606ffbb0aUL, + 0x0000000bda93c2d5UL, + 0x00000007c5f94f0aUL, + 0x000000076fe26501UL, + 0x00000005d8b9153cUL, + 0x0000000886bbb218UL, + 0x0000000acee2fecaUL, + 0x00000002ad19a925UL, + 0x000000083b97855cUL, + 0x0000000d36608312UL, + 0x00000008ac60dbc7UL, + 0x00000000885c8f58UL, + 0x00000008abbdf891UL, + 0x0000000ea1602271UL, + 0x0000000ad654fee1UL, + 0x00000006c461195eUL, + 0x00000005eeb1a327UL, + 0x000000018d743962UL, + 0x00000001fc7c55a5UL, + 0x0000000aba749670UL, + 0x00000009c9a59c60UL, + 0x00000006e5bafc06UL, + 0x000000096977db12UL, + 0x0000000a97b6ebfaUL, + 0x000000063d2d9da6UL, + 0x0000000fab00cd60UL, + 0x0000000d7bdf4632UL, + 0x0000000f83878d59UL, + 0x0000000b1c2c462eUL, + 0x000000014e5144a7UL, + 0x0000000f4a909b28UL, + 0x0000000e979a185bUL, + 0x0000000908090a64UL, + 0x000000099eccd798UL, + 0x0000000348780a96UL, + 0x0000000fdc7ad169UL, + 0x0000000a600c2e5bUL, + 0x0000000b0968cd98UL, + 0x00000001a45ec098UL, + 0x000000099118c1b4UL, + 0x00000008afa5cd5aUL, + 0x00000001db7e655eUL, + 0x00000009f637e452UL, + 0x00000009568504e3UL, + 0x0000000045b2a662UL, + 0x0000000f2a1455a2UL, + 0x00000006c1ca9e75UL, + 0x000000030a4a4639UL, + 0x0000000c6c2c1a30UL, + 0x000000087500b452UL, + 0x00000005e338bb2eUL, + 0x0000000d9dd11dffUL, + 0x00000008c4b5d012UL, + 0x00000008191194e0UL, + 0x0000000dd11db867UL, + 0x0000000c67c151ceUL, + 0x00000005cb1a00e4UL, + 0x0000000098b7a1c6UL, + 0x0000000369f35cd4UL, + 0x0000000ca2190bdbUL, + 0x00000006e14bb3b9UL, + 0x00000008d5692f8cUL, + 0x0000000ca4b2f4f8UL, + 0x0000000787f06877UL, + 0x00000008acbb8550UL, + 0x0000000535f4b56aUL, + 0x0000000f4caf7ecbUL, + 0x0000000d4615b258UL, + 0x0000000347ca7070UL, + 0x00000003c798c85dUL, + 0x0000000460506465UL, + 0x0000000870d0a5dcUL, + 0x00000006510b2464UL, + 0x0000000d1dba5544UL, + 0x0000000d57789a33UL, + 0x0000000e2417c5baUL, + 0x0000000b5ff8628cUL, + 0x0000000a3bb22787UL, + 0x0000000a16b64f34UL, + 0x0000000421e81d3dUL, + 0x000000035b4596a7UL, + 0x00000008d7a2dd7eUL, + 0x000000050b2d83faUL, + 0x00000009ea87e7c2UL, + 0x0000000d5055e752UL, + 0x0000000f96aa9da5UL, + 0x0000000b096e2a07UL, + 0x000000049970b44bUL, + 0x0000000867fb1518UL, + 0x00000005d0f5dba2UL, + 0x00000001b191d11eUL, + 0x00000008e839bb8fUL, + 0x00000001cd4aca15UL, + 0x0000000971ec5615UL, + 0x00000007d72a7ebdUL, + 0x00000008b1253bfbUL, + 0x0000000e11de1d25UL, + 0x00000000a7566839UL, + 0x0000000f4f3542e0UL, + 0x00000001ea791e32UL, + 0x000000032a84f759UL, + 0x0000000646f1844eUL, + 0x000000042af26809UL, + 0x00000001f4b464ffUL, + 0x0000000da684d2d9UL, + 0x0000000d854f5fb9UL, + 0x00000004d4d3e91aUL, + 0x00000005af3ef4e2UL, + 0x00000008a1ef5ce7UL, + 0x00000002354febf3UL, + 0x0000000b3c5a8944UL, + 0x000000098b62a144UL, + 0x00000009bdba0b4eUL, + 0x000000004aa99b42UL, + 0x00000008099ea151UL, + 0x00000002185463a3UL, + 0x0000000b0a1ae997UL, + 0x0000000e628d5770UL, + 0x0000000b40b5ac89UL, + 0x000000027213b17dUL, + 0x00000004d21db5b5UL, + 0x000000010d0748f7UL, + 0x00000002276c7876UL, + 0x0000000b98bee56dUL, + 0x0000000bd1ca6ae8UL, + 0x0000000824ab48faUL, + 0x0000000c6f35ae62UL, + 0x00000003547a563cUL, + 0x0000000f1fc0d824UL, + 0x000000058f55ed75UL, + 0x0000000aa9d0de01UL, + 0x00000004719dde60UL, + 0x0000000d5386b3ddUL, + 0x00000004d8d9f666UL, + 0x0000000aee36013bUL, + 0x0000000ba4ee322fUL, + 0x0000000898d2db4eUL, + 0x00000009fe364808UL, + 0x0000000bb13e8045UL, + 0x0000000be346d43aUL, + 0x0000000b4c9f886fUL, + 0x0000000c9a6f53b8UL, + 0x00000000ed5a7b6fUL, + 0x00000002a1fac740UL, + 0x0000000b8c134a59UL, + 0x0000000b1f773993UL, + 0x0000000c4d9d0025UL, + 0x0000000ca905bdcaUL, + 0x00000003150a39a7UL, + 0x0000000e8329fad5UL, + 0x0000000bd4f98059UL, + 0x00000003bc5cf6cdUL, + 0x0000000c982fdd03UL, + 0x00000000a372de28UL, + 0x000000073fe2e35aUL, + 0x00000000b9f684ecUL, + 0x0000000c543ff680UL, + 0x00000001bcf5f09aUL, + 0x000000051b2a8099UL, + 0x0000000ee53277c2UL, + 0x00000000b3835a6cUL, + 0x0000000aed6765c1UL, + 0x000000092cfd64c8UL, + 0x0000000d20c60ed2UL, + 0x000000059dbd9f51UL, + 0x0000000b6acb694bUL, + 0x0000000427dcd5fdUL, + 0x0000000646336a75UL, + 0x00000008008dea4dUL, + 0x00000000af2bdc7cUL, + 0x0000000b8a46478aUL, + 0x0000000b02c535b6UL, + 0x0000000c645d8631UL, + 0x0000000044b4af3dUL, + 0x0000000c9edfe6cbUL, + 0x000000032ac8ea2aUL, + 0x000000079266a23fUL, + 0x0000000c2d902e93UL, + 0x00000006ae5cfbdbUL, + 0x00000002c66c633eUL, + 0x0000000eb7a8a4e3UL, + 0x0000000cb17281cfUL, + 0x00000007ca378680UL, + 0x00000007ac81509dUL, + 0x0000000a59a05073UL, + 0x0000000c9cb9f18dUL, + 0x0000000b78100d29UL, + 0x0000000fab49420aUL, + 0x0000000d0a4e69c4UL, + 0x0000000d6c33f722UL, + 0x000000068d21bff8UL, + 0x00000001fdad8ca3UL, + 0x00000002884d6968UL, + 0x0000000b091ff264UL, + 0x0000000eb5fb236fUL, + 0x0000000a3d2a1839UL, + 0x0000000527db0bc8UL, + 0x00000002dc68cd9fUL, + 0x0000000e3f4ea98aUL, + 0x0000000a629fe44fUL, + 0x0000000b73bd7d66UL, + 0x00000002abfd7b6bUL, + 0x00000001b4056054UL, + 0x0000000d6efaac28UL, + 0x00000000d13cc950UL, + 0x0000000ef84ead94UL, + 0x00000005b6ee0d50UL, + 0x00000000f4bec692UL, + 0x0000000de1b98881UL, + 0x000000055ccccd31UL, + 0x0000000086d9b84dUL, + 0x00000005ab736e3dUL, + 0x0000000167d2f005UL, + 0x0000000118ed1522UL, + 0x000000038bbdc903UL, + 0x000000039cd31ac2UL, + 0x000000031091bc51UL, + 0x0000000d66a87d3fUL, + 0x0000000afdade6d3UL, + 0x00000002bd1fe097UL, + 0x00000005cf545dd2UL, + 0x00000005e0af578eUL, + 0x00000006fe6dd4c9UL, + 0x0000000862bc8fcaUL, + 0x0000000cbce0b4c6UL, + 0x000000008b7fa8ddUL, + 0x00000003d108ae9fUL, + 0x0000000fed2d914aUL, + 0x0000000bab304bd8UL, + 0x0000000debe74f8dUL, + 0x00000001e857e3dcUL, + 0x0000000570340581UL, + 0x0000000114bbf4f5UL, + 0x0000000a3cfc0566UL, + 0x00000004026cd686UL, + 0x0000000266fb76cdUL, + 0x0000000b715773bbUL, + 0x00000002fd2785fdUL, + 0x0000000481b34cadUL, + 0x000000011c58d2baUL, + 0x00000003a5186f4dUL, + 0x0000000da55ab71cUL, + 0x0000000ac887db92UL, + 0x00000009bd6d5592UL, + 0x000000045857d12aUL, + 0x00000008c862f0b9UL, + 0x0000000870c88666UL, + 0x00000004a4f4901fUL, + 0x0000000774a993d0UL, + 0x0000000c9f16c81dUL, + 0x0000000eb415e9efUL, + 0x0000000307aa6302UL, + 0x0000000a246f21eeUL, + 0x00000001a4f8a9c2UL, + 0x00000000cf09f9b4UL, + 0x0000000db30dbb49UL, + 0x00000003581be36fUL, + 0x00000006919a4318UL, + 0x00000008ee677afdUL, + 0x00000005944b9d59UL, + 0x00000008d5fe61aaUL, + 0x000000077c174b1dUL, + 0x00000005cff8fa10UL, + 0x0000000c1ce82f48UL, + 0x00000007fbb18e65UL, + 0x00000000b6737103UL, + 0x0000000e2d30a9b6UL, + 0x00000006481ff469UL, + 0x00000005834b4d26UL, + 0x00000003bba517d5UL, + 0x0000000eee6e8080UL, + 0x00000005fe4fea5eUL, + 0x0000000e84e94c8cUL, + 0x0000000ba2ad0a2aUL, + 0x0000000a7f2aead0UL, + 0x000000063cecb46dUL, + 0x00000008943d7229UL, + 0x00000001d3878b2bUL, + 0x0000000f2b4efe94UL, + 0x0000000d9af1949dUL, + 0x0000000bb5824d39UL, + 0x0000000b8d8f5090UL, + 0x0000000ed5e19d08UL, + 0x000000060287437eUL, + 0x00000008fe6ae5c2UL, + 0x00000006c85ac058UL, + 0x0000000b906be1b8UL, + 0x0000000f9d423f65UL, + 0x00000006efed81d6UL, + 0x0000000781b67fa2UL, + 0x0000000e1dd437acUL, + 0x00000007a9201a8cUL, + 0x0000000fb444c819UL, + 0x0000000ce75af959UL, + 0x000000086df6e72bUL, + 0x0000000756695aa7UL, + 0x0000000b7b2bddf2UL, + 0x0000000f19a1b99eUL, + 0x00000009a5790e90UL, + 0x00000001d3b3eac0UL, + 0x0000000a5c5d9d2bUL, + 0x0000000152850218UL, + 0x0000000025c4ba6eUL, + 0x0000000d4a5f4bebUL, + 0x0000000709cec10eUL, + 0x000000094ddbdb6cUL, + 0x00000009d1218277UL, + 0x00000006190ca34aUL, + 0x0000000468ed6a3fUL, + 0x0000000801bda52eUL, + 0x0000000261b3f1a9UL, + 0x00000000b3494d9bUL, + 0x0000000583e2d7e5UL, + 0x00000009407a80f2UL, + 0x000000058e902456UL, + 0x00000009108c2273UL, + 0x000000059778ff8cUL, + 0x0000000d6ce05028UL, + 0x00000000286adc62UL, + 0x00000007ed3060dcUL, + 0x000000057b7e03edUL, + 0x00000003e3dce5c1UL, + 0x00000001bebc2295UL, + 0x0000000014a17c9aUL, + 0x0000000c7d90fbdaUL, + 0x00000008158ae35aUL, + 0x000000069d70a335UL, + 0x0000000d3ef97931UL, + 0x00000005793efb7aUL, + 0x0000000e6989ef43UL, + 0x0000000cd15f0116UL, + 0x0000000f9dbc6e25UL, + 0x0000000da4a91117UL, + 0x0000000054d0917aUL, + 0x000000060f2c3f15UL, + 0x00000007393b0a66UL, + 0x00000006630ed79bUL, + 0x0000000ed8589c60UL, + 0x00000007db37ab26UL, + 0x0000000c4631e80aUL, + 0x00000001badaf501UL, + 0x00000009bdef764dUL, + 0x0000000dd0949b4bUL, + 0x000000086f116771UL, + 0x0000000acd7ea109UL, + 0x00000007cc9d2f6bUL, + 0x00000003f5598822UL, + 0x00000004ba5a8d0cUL, + 0x000000066e7f9c42UL, + 0x000000033127fb36UL, + 0x00000000c85ff976UL, + 0x00000009dbb32ddfUL, + 0x00000003d06c7a56UL, + 0x0000000ac07601ddUL, + 0x00000005fda3d7e9UL, + 0x000000040a47aef0UL, + 0x0000000139928cd0UL, + 0x0000000183ab75ebUL, + 0x00000009dd6d1f4bUL, + 0x0000000954afec44UL, + 0x000000029953fe22UL, + 0x0000000f947e49b1UL, + 0x0000000a74266cb0UL, + 0x00000003bbb7fdabUL, + 0x00000008a72b63d1UL, + 0x00000008763e2fbbUL, + 0x00000008c9b4f9a2UL, + 0x0000000a35f5a861UL, + 0x000000099e54752cUL, + 0x00000002fdb8e16fUL, + 0x00000002d083ed68UL, + 0x0000000a05d36c5eUL, + 0x00000005460842feUL, + 0x0000000173ae0ee6UL, + 0x000000038b3c62e5UL, + 0x0000000476c1ae99UL, + 0x00000009a8cb898aUL, + 0x000000019d4032acUL, + 0x0000000a9c01d80bUL, + 0x0000000ca7d5e4deUL, + 0x0000000295d53115UL, + 0x0000000b26740e51UL, + 0x0000000bf21b0988UL, + 0x0000000167391c15UL, + 0x0000000d10af35c6UL, + 0x0000000d94750799UL, + 0x0000000cb986d117UL, + 0x000000001dddf588UL, + 0x000000071ed85f46UL, + 0x0000000a5437d58fUL, + 0x00000004029d1e25UL, + 0x0000000c580ec972UL, + 0x00000006847df8baUL, + 0x0000000e294d997bUL, + 0x0000000e2e8b10eeUL, + 0x00000001593103ddUL, + 0x0000000222103857UL, + 0x00000001e035591dUL, + 0x0000000b5c9ef2e9UL, + 0x00000009f815ec3eUL, + 0x0000000d1da2a021UL, + 0x000000054f171191UL, + 0x0000000e51f4a05eUL, + 0x0000000c15e7d603UL, + 0x0000000ba7f16b87UL, + 0x000000080b7a83e1UL, + 0x0000000720e2b18dUL, + 0x00000005ec0c069dUL, + 0x0000000a4f9f689cUL, + 0x00000005871cafdaUL, + 0x0000000c913140a2UL, + 0x00000007a8f2efd1UL, + 0x000000077064952cUL, + 0x00000004ea2d857fUL, + 0x0000000484523555UL, + 0x000000054971a9e3UL, + 0x0000000eb0694eb2UL, + 0x0000000b513c8e63UL, + 0x00000005c910db58UL, + 0x0000000ca87a4dd7UL, + 0x0000000b8ca63158UL, + 0x0000000b4b09431dUL, + 0x00000003dc9d50b7UL, + 0x00000007d57f02acUL, + 0x00000005c595b1b2UL, + 0x00000009e0caf698UL, + 0x0000000136b48555UL, + 0x0000000687dbcc2bUL, + 0x000000054bae2294UL, + 0x00000006899bbd7bUL, + 0x00000008108f46deUL, + 0x00000001dbe8cf08UL, + 0x0000000a02e1ae1dUL, + 0x00000000f5f26d59UL, + 0x0000000805cf202bUL, + 0x0000000afede5687UL, + 0x00000001583d5b30UL, + 0x0000000da9ed0620UL, + 0x0000000cf1237338UL, + 0x00000003a5a77bc4UL, + 0x0000000a17ffa0c6UL, + 0x000000029de4c387UL, + 0x000000007825d431UL, + 0x000000002d7b9b38UL, + 0x00000008ed0f26aaUL, + 0x000000056e54e30dUL, + 0x00000009620ab0e7UL, + 0x0000000c7e3ea94cUL, + 0x0000000d288a41e2UL, + 0x0000000f68884f1eUL, + 0x00000005ee02df09UL, + 0x0000000c02dbf645UL, + 0x0000000eac4c2424UL, + 0x0000000cab2d51e1UL, + 0x0000000037439577UL, + 0x00000005618ada43UL, + 0x00000002683b5859UL, + 0x00000008a607c1ceUL, + 0x0000000795fd9198UL, + 0x0000000b3edb11b8UL, + 0x0000000846939c5cUL, + 0x00000008b1f6fa23UL, + 0x0000000b1a2f2bfeUL, + 0x0000000b63a07ad7UL, + 0x00000005f8ea7b00UL, + 0x00000004ee9c6d0cUL, + 0x0000000990f2889bUL, + 0x0000000b7f7251d0UL, + 0x0000000ac3291369UL, + 0x00000009d8f36a7bUL, + 0x0000000d57342897UL, + 0x0000000efca98365UL, + 0x0000000dacc69f0eUL, + 0x00000003a70e4b3cUL, + 0x00000001e95c34c2UL, + 0x00000004caab6c06UL, + 0x00000007231f6ee1UL, + 0x000000037909aa04UL, + 0x0000000048c9a9ccUL, + 0x000000059cd081bcUL, + 0x00000004dd78c2e4UL, + 0x00000004979da10fUL, + 0x000000004749d0c5UL, + 0x0000000a17a4283bUL, + 0x0000000de7e1d52dUL, + 0x00000000e47cedf1UL, + 0x00000004fa48cbffUL, + 0x0000000545a932a0UL, + 0x00000006c2bd9eb8UL, + 0x0000000dd9bd3b8cUL, + 0x000000043332c1baUL, + 0x0000000501fa761dUL, + 0x00000007ec40adbbUL, + 0x00000004049f2b33UL, + 0x0000000cde28f57bUL, + 0x0000000f68c804b9UL, + 0x00000008f50fbd3eUL, + 0x000000054e1bc344UL, + 0x000000036b26e3a2UL, + 0x000000002e5ac9b1UL, + 0x000000010837858dUL, + 0x00000006ccac9e0bUL, + 0x0000000625ba8a52UL, + 0x0000000ac4c8b45cUL, + 0x0000000868678237UL, + 0x00000004187235feUL, + 0x0000000bd62663ceUL, + 0x0000000ea832dfb2UL, + 0x0000000d5a72f0a7UL, + 0x00000000659c855eUL, + 0x0000000bea7f5e48UL, + 0x0000000ff9566715UL, + 0x00000001bd06d99aUL, + 0x00000009666c578cUL, + 0x0000000c6527d3ecUL, + 0x0000000b541f3c61UL, + 0x0000000678a9ad70UL, + 0x000000036eaadfa3UL, + 0x0000000af74b01deUL, + 0x000000054cc3cdc3UL, + 0x0000000d2e587ce6UL, + 0x00000008694b9349UL, + 0x0000000d309898feUL, + 0x00000005c3250e09UL, + 0x000000084dcac28eUL, + 0x0000000f72add2dfUL, + 0x00000001901681a3UL, + 0x000000009e6a8fd4UL, + 0x000000012f614cd1UL, + 0x00000006d7801ac4UL, + 0x000000014cf1ca54UL, + 0x000000012a7eb608UL, + 0x00000005e7a3bf62UL, + 0x00000000ba5056a2UL, + 0x00000005bee44c9bUL, + 0x0000000819d7dc86UL, + 0x0000000062adc8fdUL, + 0x0000000bd3155d41UL, + 0x0000000cd8c6b38aUL, + 0x0000000e320fd50eUL, + 0x0000000e189d6655UL, + 0x00000006863c2831UL, + 0x00000000d2b9058fUL, + 0x000000023bfad8faUL, + 0x0000000199bd1216UL, + 0x000000056138afd7UL, + 0x0000000face83a93UL, + 0x00000009554da725UL, + 0x00000009b614dd91UL, + 0x000000098acbca3fUL, + 0x0000000d5f0d5f21UL, + 0x0000000eb59039e1UL, + 0x000000051d1ec82aUL, + 0x0000000a366ef3baUL, + 0x00000001ad0e01f0UL, + 0x00000007f038ad0bUL, + 0x00000003ee055321UL, + 0x00000003bf2dcbb7UL, + 0x0000000210e9856cUL, + 0x0000000e4fea8231UL, + 0x0000000b89444937UL, + 0x000000058852cc34UL, + 0x00000001ee29eea9UL, + 0x0000000b919c79f2UL, + 0x0000000ddc44d3adUL, + 0x0000000ddcbd4777UL, + 0x00000003c3982ba1UL, + 0x0000000dc8ebc45dUL, + 0x00000008b97712b1UL, + 0x00000009702ea21eUL, + 0x00000001f457e726UL, + 0x000000027c6f6e26UL, + 0x00000000a9797770UL, + 0x0000000d7615f53bUL, + 0x000000074f1cb6e1UL, + 0x0000000a32e4d7dcUL, + 0x00000002e89afd1dUL, + 0x00000000b03704d5UL, + 0x0000000cca58aab0UL, + 0x00000001e5749225UL, + 0x00000006e63a36baUL, + 0x0000000562992099UL, + 0x000000064701b950UL, + 0x0000000f94ed6196UL, + 0x0000000b3441b5f1UL, + 0x0000000c64fac247UL, + 0x0000000d72ebd98bUL, + 0x0000000fa1985b23UL, + 0x00000002df788358UL, + 0x000000088838b488UL, + 0x00000006091032b4UL, + 0x000000025ff2d736UL, + 0x0000000dce63d3d5UL, + 0x0000000bb5970414UL, + 0x000000044d8b5ffeUL, + 0x0000000e1a5666d8UL, + 0x0000000e34129125UL, + 0x00000000e23854b1UL, + 0x000000001b2a6dbeUL, + 0x0000000d11507bcdUL, + 0x0000000844531e6bUL, + 0x0000000d864a8611UL, + 0x0000000e2a5a7700UL, + 0x00000002d178962aUL, + 0x0000000156b07f01UL, + 0x000000048b59fec3UL, + 0x00000003d3d9d79cUL, + 0x00000001846fb339UL, + 0x0000000ddf1d03caUL, + 0x00000000998abaf9UL, + 0x0000000c9d76190bUL, + 0x000000067354a1a8UL, + 0x0000000cc89e2b09UL, + 0x0000000353356834UL, + 0x00000007ad97470eUL, + 0x0000000f4d560524UL, + 0x0000000534b7804eUL, + 0x000000014290c632UL, + 0x0000000b67d39d60UL, + 0x000000035b166febUL, + 0x000000088e6fb681UL, + 0x0000000a0f82ae1aUL, + 0x000000008460ce52UL, + 0x00000008b06a9012UL, + 0x0000000daf1299dcUL, + 0x0000000629ab696cUL, + 0x00000003113b448aUL, + 0x00000000db5ca215UL, + 0x00000003e00b1e2dUL, + 0x000000085a87f5abUL, + 0x0000000b3995ff20UL, + 0x000000085661554dUL, + 0x0000000e709c5384UL, + 0x00000000111ca99bUL, + 0x000000049e614279UL, + 0x0000000f14677ec4UL, + 0x00000008f6439bfbUL, + 0x0000000749faa461UL, + 0x00000001c4f9189aUL, + 0x0000000e8e9015caUL, + 0x0000000f6e68d510UL, + 0x0000000b3819319fUL, + 0x0000000da9f7119fUL, + 0x00000007787f40f8UL, + 0x0000000bc57f5716UL, + 0x000000060ff2897eUL, + 0x0000000b3a28a934UL, + 0x000000010b34c97cUL, + 0x0000000c14f53aedUL, + 0x0000000d3c4eaf5dUL, + 0x0000000b3148d39eUL, + 0x000000007874ea02UL, + 0x0000000f86692b4aUL, + 0x00000005b03a0e8dUL, + 0x0000000ce6db8cc6UL, + 0x00000008233d5908UL, + 0x0000000f163e3c06UL, + 0x0000000dff854cceUL, + 0x000000026706f1bcUL, + 0x000000094c358653UL, + 0x00000007384c9821UL, + 0x0000000e51b8e5d5UL, + 0x0000000eda32963bUL, + 0x0000000a073f392fUL, + 0x0000000c3ccfa213UL, + 0x000000034adf5216UL, + 0x0000000cb8da286bUL, + 0x00000003b5fbbf08UL, + 0x000000012812d1f8UL, + 0x0000000c97c54c39UL, + 0x0000000e1c3e36b9UL, + 0x0000000abb8dc0edUL, + 0x0000000019dcbbf6UL, + 0x000000025b0d7c4dUL, + 0x0000000045e6b5ceUL, + 0x000000017dc086caUL, + 0x0000000c3f425e6bUL, + 0x00000006fdee14f8UL, + 0x000000039155e6b4UL, + 0x00000000a191ec15UL, + 0x0000000398fcd7f4UL, + 0x0000000a6e2b0594UL, + 0x0000000fe5678d82UL, + 0x0000000e317eba1fUL, + 0x00000002c4f10ca1UL, + 0x0000000ae239c19eUL, + 0x000000018e663ed2UL, + 0x00000004a040b7e7UL, + 0x0000000bbca0849cUL, + 0x0000000ce05b3a74UL, + 0x00000007cee982fdUL, + 0x000000078ee54fa7UL, + 0x00000007b47bb0bdUL, + 0x00000007e8f19216UL, + 0x0000000d67d91cedUL, + 0x0000000ef5effe94UL, + 0x0000000ec1d1938dUL, + 0x00000004c05ef70eUL, + 0x00000000324442d9UL, + 0x0000000fb0183bb4UL, + 0x0000000fb7a0bd50UL, + 0x000000089aa17d87UL, + 0x0000000e4e6aed89UL, + 0x0000000dbecf68b4UL, + 0x0000000683770de4UL, + 0x0000000b9f41a136UL, + 0x0000000c7614caceUL, + 0x000000089c298386UL, + 0x0000000959cf09deUL, + 0x0000000ab30b19e3UL, + 0x0000000db2e4b614UL, + 0x000000026d30d39bUL, + 0x00000006ccefe452UL, + 0x0000000587c5035cUL, + 0x0000000ea73bbbe0UL, + 0x0000000dd9d91a11UL, + 0x0000000dd8c5e851UL, + 0x0000000e8b4aa077UL, + 0x00000008ccf8faddUL, + 0x000000047ddd3c0bUL, + 0x0000000635a92f19UL, + 0x0000000f0edfd1a3UL, + 0x00000001f760bf5eUL, + 0x0000000a83feb68aUL, + 0x00000004f74da9ddUL, + 0x000000052f759252UL, + 0x000000098bee689eUL, + 0x0000000c5fc8c3d5UL, + 0x00000008373d1286UL, + 0x0000000f5f1cdabdUL, + 0x0000000ada68d3e5UL, + 0x00000003bbb9eb5eUL, + 0x000000050cde8478UL, + 0x0000000f01f956e0UL, + 0x0000000a922f2842UL, + 0x0000000233a8b25aUL, + 0x000000071118b754UL, + 0x0000000b7f874552UL, + 0x000000044d757121UL, + 0x0000000b873b14ccUL, + 0x00000005bcc1db5cUL, + 0x0000000bf9b895ceUL, + 0x00000005e65bb620UL, + 0x0000000bbd1ed35cUL, + 0x0000000358e79973UL, + 0x000000062aa5a4a5UL, + 0x000000081715fc0fUL, + 0x00000008df03a76eUL, + 0x0000000376b7c6c7UL, + 0x0000000a07a49f2eUL, + 0x000000045e159b63UL, + 0x0000000dae5706b0UL, + 0x0000000b5e52c7ccUL, + 0x0000000206935e8eUL, + 0x000000039f0c5119UL, + 0x00000003cd58c574UL, + 0x0000000571986d35UL, + 0x0000000ad66da60fUL, + 0x000000002b1a6315UL, + 0x0000000d0131b533UL, + 0x0000000741a195c5UL, + 0x00000000b8663437UL, + 0x00000001cde52798UL, + 0x00000006b8e658b1UL, + 0x0000000b43c0d44dUL, + 0x000000045481d697UL, + 0x000000029de93df5UL, + 0x000000010549b874UL, + 0x0000000c056b5828UL, + 0x000000003fa830adUL, + 0x00000009496d14faUL, + 0x0000000f540592a0UL, + 0x0000000f31c8b855UL, + 0x000000064f2ba36bUL, + 0x0000000fe7c6e4f5UL, + 0x00000005e42a78b0UL, + 0x00000009c2b8b096UL, + 0x0000000dcb4a6e71UL, + 0x0000000d63b0e7edUL, + 0x0000000de1bcbcdaUL, + 0x000000068e7161f2UL, + 0x00000003e5ddf88dUL, + 0x0000000419a37501UL, + 0x0000000fad63e7abUL, + 0x0000000c6e81b4baUL, + 0x00000008329315d3UL, + 0x0000000c88d267e6UL, + 0x000000073a0ac25fUL, + 0x0000000e7b75690fUL, + 0x0000000dcbb95be2UL, + 0x00000007a1d2a059UL, + 0x0000000d8fac361eUL, + 0x00000006312ff5c9UL, + 0x0000000d2cf50d54UL, + 0x00000008c65fd00fUL, + 0x0000000aa1636532UL, + 0x0000000870c7285dUL, + 0x00000001894f0b84UL, + 0x00000004260cc5c3UL, + 0x0000000e9997b9ecUL, + 0x000000087a052144UL, + 0x00000008706babf6UL, + 0x0000000bd5f62ad3UL, + 0x00000001a7895439UL, + 0x0000000f7e294bbcUL, + 0x0000000bcc27ca26UL, + 0x00000003186a63d4UL, + 0x00000007f3ede4a4UL, + 0x0000000b64e32468UL, + 0x000000071f250d53UL, + 0x00000007c6513783UL, + 0x0000000b1778714aUL, + 0x000000094bf2c57fUL, + 0x000000064a9f893aUL, + 0x00000001305be654UL, + 0x0000000493e0c9f6UL, + 0x000000005ba6fed8UL, + 0x0000000c4a0c7a06UL, + 0x00000000cc2ec0ddUL, + 0x0000000d9a6769afUL, + 0x0000000724c78a49UL, + 0x0000000c85c981a4UL, + 0x000000012553c4cdUL, + 0x000000083cb892b1UL, + 0x0000000bc324ccc7UL, + 0x0000000ef43f6c1dUL, + 0x00000002d6748bb7UL, + 0x00000005efdce2d7UL, + 0x000000094af64f28UL, + 0x0000000f9d58feb3UL, + 0x0000000cf547ac63UL, + 0x0000000ceb309febUL, + 0x000000030beba8caUL, + 0x00000008ab2e486aUL, + 0x00000004a95d58adUL, + 0x000000025ce07c46UL, + 0x0000000712b93fd7UL, + 0x00000007f46acc81UL, + 0x000000064049d4beUL, + 0x000000065303aa09UL, + 0x0000000f3aad21b3UL, + 0x00000002903a6cd0UL, + 0x00000005a0e0467dUL, + 0x00000003c4fa64e4UL, + 0x00000005c6655126UL, + 0x0000000b40a2a67fUL, + 0x0000000b0c22c6e5UL, + 0x00000001507e039bUL, + 0x0000000b282b16b8UL, + 0x0000000c0e14a3d3UL, + 0x000000093d381427UL, + 0x00000006bb55bb87UL, + 0x0000000b675af72fUL, + 0x0000000fceb4f95eUL, + 0x000000066af6ebbdUL, + 0x000000020a44d1f2UL, + 0x00000006bc873916UL, + 0x0000000b8947bee8UL, + 0x00000004b6bed8a6UL, + 0x00000007012f7867UL, + 0x00000007eda3c150UL, + 0x0000000ab3ef1b8eUL, + 0x00000006d71466eeUL, + 0x0000000408c4e225UL, + 0x0000000e117838b1UL, + 0x00000000aef3a075UL, + 0x00000005a0779d4fUL, + 0x000000070a3b1d69UL, + 0x000000026ccd31fdUL, + 0x0000000ed64dd1b2UL, + 0x0000000981d4f60cUL, + 0x00000006a6e4fb61UL, + 0x000000052f15fc93UL, + 0x0000000032b3a64dUL, + 0x0000000ecb17d667UL, + 0x0000000a983fb935UL, + 0x000000037d23c88dUL, + 0x0000000b8590fbcbUL, + 0x0000000ec2f1a277UL, + 0x000000090d3053e6UL, + 0x0000000a36fa8ccdUL, + 0x000000044bd08eccUL, + 0x000000061dd197d9UL, + 0x0000000a307cfd82UL, + 0x00000001d09c2de4UL, + 0x00000005f6d74368UL, + 0x00000001327d1b2dUL, + 0x0000000594cc36b9UL, + 0x0000000fea1cba7cUL, + 0x000000050c31262dUL, + 0x0000000d99b1a6baUL, + 0x00000001bf789cd2UL, + 0x0000000e2f6f66f9UL, + 0x000000013d5edfc6UL, + 0x0000000bc3a9ab0cUL, + 0x00000001da5b2734UL, + 0x000000025ef4f2deUL, + 0x0000000dcb55a50aUL, + 0x00000009c6dbc6acUL, + 0x000000089a838853UL, + 0x0000000168f099eeUL, + 0x0000000d51601760UL, + 0x000000089f324f1aUL, + 0x00000002cb1ec1eaUL, + 0x00000006306de366UL, + 0x0000000012a2f11eUL, + 0x0000000b5c0bf797UL, + 0x00000005c5f02be4UL, + 0x00000005019f54beUL, + 0x00000006ae4a096aUL, + 0x00000004bce78778UL, + 0x000000094b65b97fUL, + 0x0000000d3f6e7bd2UL, + 0x00000001fbd2a84cUL, + 0x00000006d0127ab1UL, + 0x00000003e82799aaUL, + 0x00000004c1264dfeUL, + 0x0000000cf69c9360UL, + 0x00000004b43e5342UL, + 0x000000035d1f0372UL, + 0x0000000d78c18eb4UL, + 0x0000000262574101UL, + 0x0000000c2c5c7335UL, + 0x0000000bad04051aUL, + 0x00000001c481f94eUL, + 0x00000003285aa0deUL, + 0x00000008973e1f69UL, + 0x00000005d238c694UL, + 0x00000007b71847b9UL, + 0x0000000242f5675cUL, + 0x0000000cc5751c2dUL, + 0x0000000e09bc620bUL, + 0x00000000e4e904ddUL, + 0x000000007ca4f1a7UL, + 0x00000002ac79ae43UL, + 0x0000000e213d4250UL, + 0x0000000d4137c2b5UL, + 0x0000000ddfce11bcUL, + 0x0000000d1d658566UL, + 0x0000000213f5b1bbUL, + 0x0000000cd35be0a8UL, + 0x0000000cc67d7f91UL, + 0x0000000509bde098UL, + 0x000000074d3d8f46UL, + 0x000000051309c970UL, + 0x000000053e2bdf66UL, + 0x0000000a5dd3fed3UL, + 0x0000000a4e69b212UL, + 0x0000000b1d39936dUL, + 0x00000006b6c8926bUL, + 0x000000046540a7b0UL, + 0x00000002eebc599fUL, + 0x00000002e54a283eUL, + 0x0000000f9a328a9cUL, + 0x00000007ea9cfc53UL, + 0x00000005cffa2bdbUL, + 0x0000000464d16f8eUL, + 0x0000000eb09444bcUL, + 0x00000003f341b259UL, + 0x00000004d112b108UL, + 0x000000070cb94242UL, + 0x0000000974ed4ffdUL, + 0x00000001084da291UL, + 0x000000085673ca39UL, + 0x0000000d4d74766fUL, + 0x000000064a68e1deUL, + 0x0000000e35630caeUL, + 0x00000002073229dbUL, + 0x000000063d3a3902UL, + 0x000000031598ee06UL, + 0x0000000808d61126UL, + 0x0000000029957984UL, + 0x0000000d4f5f2649UL, + 0x00000009ec8a706bUL, + 0x0000000349981760UL, + 0x0000000c93ab23a6UL, + 0x00000002c7aa80daUL, + 0x0000000866f102baUL, + 0x0000000b15cff7bcUL, + 0x000000066a13a4caUL, + 0x000000054a755048UL, + 0x0000000d13fdb8d9UL, + 0x000000016ad5edf3UL, + 0x0000000e043bb154UL, + 0x0000000cc8755671UL, + 0x0000000cf9b2bfd5UL, + 0x00000003608890b4UL, + 0x0000000330fef315UL, + 0x0000000e3299ca65UL, + 0x00000000b60765e1UL, + 0x00000000e9bb17dcUL, + 0x000000095f474d8bUL, + 0x0000000e721d3d00UL, + 0x0000000d4679e565UL, + 0x0000000c80da6113UL, + 0x000000098deeff30UL, + 0x0000000c293bb871UL, + 0x0000000e79132f48UL, + 0x0000000b152dafbbUL, + 0x000000055f6a4386UL, + 0x0000000a1b8a4044UL, + 0x00000004f4187b05UL, + 0x00000000b17c2ed3UL, + 0x000000095d75ba04UL, + 0x0000000bbf12e96dUL, + 0x00000006abd1a52fUL, + 0x0000000f300bc991UL, + 0x0000000f0a7385d4UL, + 0x000000052964f82aUL, + 0x0000000a9962925fUL, + 0x0000000613b2eef1UL, + 0x00000005fd2c92a8UL, + 0x000000009ebecd05UL, + 0x000000036002b87aUL, + 0x0000000902c79eefUL, + 0x0000000394e63c7eUL, + 0x0000000133285064UL, + 0x0000000f7cfe2d4bUL, + 0x00000004f068522cUL, + 0x000000096fea1a0fUL, + 0x0000000c5a927b13UL, + 0x0000000e9a2c1994UL, + 0x00000005c53b3803UL, + 0x0000000f636b6188UL, + 0x0000000007c656e3UL, + 0x000000026af1fc5fUL, + 0x0000000ec2f40b78UL, + 0x0000000faa1921e5UL, + 0x00000006137a8b30UL, + 0x0000000028674f7bUL, + 0x00000003de184e35UL, + 0x0000000eeef093e6UL, + 0x0000000d44b3dae0UL, + 0x0000000bb7ab7d93UL, + 0x00000002ae18c956UL, + 0x0000000cde492bd6UL, + 0x00000001cee0216eUL, + 0x0000000f1e5830adUL, + 0x000000076f6c3299UL, + 0x0000000dea24af84UL, + 0x0000000277e75586UL, + 0x0000000a17318024UL, + 0x00000005c4739486UL, + 0x00000005e3de4725UL, + 0x00000006f67c9f6dUL, + 0x000000025f42791dUL, + 0x00000003c54d15b3UL, + 0x0000000ef98d9c32UL, + 0x000000042f64819dUL, + 0x000000016d5fd070UL, + 0x000000063cb98d4fUL, + 0x000000045a3ad27cUL, + 0x00000001b496b0acUL, + 0x0000000aa471c42dUL, + 0x00000000599346a2UL, + 0x00000000dc8d1c2dUL, + 0x00000007498928c1UL, + 0x0000000ea06e90ffUL, + 0x0000000b683baa32UL, + 0x0000000f93014e16UL, + 0x000000020575d56eUL, + 0x0000000794325589UL, + 0x00000001533e9935UL, + 0x000000086b8bcb70UL, + 0x0000000ce11faf5dUL, + 0x000000036c0bd318UL, + 0x0000000e5e8c1167UL, + 0x0000000e1831ba64UL, + 0x0000000e088dbfa4UL, + 0x0000000984479674UL, + 0x0000000afef02b29UL, + 0x000000048518c716UL, + 0x00000004301564ceUL, + 0x000000021cc88710UL, + 0x0000000d5c995278UL, + 0x0000000d8367de1cUL, + 0x00000004a51125e8UL, + 0x0000000113e1c226UL, + 0x0000000ef141e076UL, + 0x000000044097011dUL, + 0x00000004ca9d707cUL, + 0x000000040d8831f1UL, + 0x0000000bd9c3b1d8UL, + 0x0000000978364177UL, + 0x000000010f7606a9UL, + 0x000000046a64270aUL, + 0x000000042df1b22bUL, + 0x0000000e906cf2a0UL, + 0x0000000997da6fa5UL, + 0x0000000a5722c26fUL, + 0x0000000b14f58aaaUL, + 0x0000000afc167ad8UL, + 0x000000037be56e60UL, + 0x0000000de7f80d62UL, + 0x00000000c3fb0a64UL, + 0x0000000ce8ca802cUL, + 0x000000035032ed9dUL, + 0x0000000aa8ba3ee6UL, + 0x000000094b2e707cUL, + 0x00000002debbdae1UL, + 0x0000000f53e25fcfUL, + 0x0000000e935543ebUL, + 0x00000001462f0e90UL, + 0x000000054ce7d18cUL, + 0x00000002ddafdc5fUL, + 0x0000000700565deeUL, + 0x0000000fd408e0afUL, + 0x000000017d089decUL, + 0x0000000833ea2459UL, + 0x00000003c8d3776aUL, + 0x00000002e5eebac8UL, + 0x000000020cbf49b0UL, + 0x0000000c44675eb7UL, + 0x00000003a4b6beb1UL, + 0x0000000ce6f37c1eUL, + 0x000000063fba2e7cUL, + 0x00000005a05b553dUL, + 0x00000001286445b0UL, + 0x00000005e07a9b61UL, + 0x00000007d8397ea4UL, + 0x00000008084b7bbbUL, + 0x0000000b05b38097UL, + 0x000000029c3019eeUL, + 0x0000000ed1d2708bUL, + 0x00000009df8a4d47UL, + 0x0000000e4891e436UL, + 0x00000002a762ab72UL, + 0x000000092f70600fUL, + 0x000000092329a2cdUL, + 0x00000003e200c6edUL, + 0x00000008c0a7233eUL, + 0x000000060866806aUL, + 0x0000000f4fddd24aUL, + 0x0000000f78464c71UL, + 0x00000009c3d22242UL, + 0x00000003877ea6d1UL, + 0x0000000e2a6d54acUL, + 0x0000000497d2a5e7UL, + 0x0000000ca82f781eUL, + 0x0000000481524f4cUL, + 0x0000000dee088814UL, + 0x0000000b2a82d3a4UL, + 0x00000008e6afe6e5UL, + 0x0000000d6279a5daUL, + 0x00000004567cbc1aUL, + 0x00000005bec2b2fdUL, + 0x00000004ef452505UL, + 0x000000061d992cbaUL, + 0x0000000ab96be0cbUL, + 0x0000000708ef35d9UL, + 0x0000000b3f6f3623UL, + 0x000000036eb1801dUL, + 0x0000000badfee917UL, + 0x0000000a3db13cd0UL, + 0x00000001d1a12828UL, + 0x00000002500816ceUL, + 0x0000000cf7612148UL, + 0x00000000be6a3f4bUL, + 0x000000074142f3daUL, + 0x0000000ce5deed92UL, + 0x0000000f9530a786UL, + 0x0000000047c8bb38UL, + 0x0000000fcabfe88fUL, + 0x0000000bc83accb1UL, + 0x000000020cd9fb1fUL, + 0x0000000023dcceb3UL, + 0x00000009e969b8c4UL, + 0x00000006e28de934UL, + 0x000000080a399667UL, + 0x000000076a0b85adUL, + 0x000000021a84be3cUL, + 0x0000000a28d028b5UL, + 0x0000000c4e7690dfUL, + 0x0000000bfd9621e8UL, + 0x00000006f4bc0c24UL, + 0x0000000aa8e76bd7UL, + 0x0000000deb55dac9UL, + 0x0000000bb344fa8bUL, + 0x0000000fcaab4decUL, + 0x0000000146aba6cbUL, + 0x0000000f49ed6eb8UL, + 0x0000000dd57e9deaUL, + 0x0000000225d5d090UL, + 0x0000000d6e86c1c5UL, + 0x0000000639be5f39UL, + 0x0000000f5e7a6132UL, + 0x0000000d2968b09fUL, + 0x000000082b30ba1eUL, + 0x0000000803fa46ccUL, + 0x0000000c290fab00UL, + 0x000000010df59de5UL, + 0x000000051ae9dcfbUL, + 0x000000049af8516dUL, + 0x000000002b564ce6UL, + 0x0000000c615a1de0UL, + 0x0000000fef9864a4UL, + 0x0000000c16e27341UL, + 0x000000039e846736UL, + 0x00000001ecbb6746UL, + 0x0000000588d03a7cUL, + 0x000000010a0eaf9cUL, + 0x0000000671ccea6bUL, + 0x000000033a154603UL, + 0x0000000a7b003bc1UL, + 0x0000000c5fc3848dUL, + 0x000000078e50a9c7UL, + 0x000000017dbfb88eUL, + 0x00000004fd0ed541UL, + 0x000000084221debaUL, + 0x00000003132cf7e6UL, + 0x0000000b67e7ac53UL, + 0x0000000df6b28024UL, + 0x0000000785b9f7edUL, + 0x0000000e3d35320dUL, + 0x0000000159c06583UL, + 0x00000005c54a80a3UL, + 0x0000000ed4d4533bUL, + 0x0000000cf16c601aUL, + 0x00000005e94efbd1UL, + 0x00000005d587126eUL, + 0x0000000eef2f2807UL, + 0x000000009f3c558eUL, + 0x0000000736cfd539UL, + 0x0000000f5a922ae1UL, + 0x00000004e2ab9959UL, + 0x00000006a2dd34e7UL, + 0x00000008c9d30d23UL, + 0x0000000eba20b791UL, + 0x0000000d5c5095e3UL, + 0x0000000423d75a82UL, + 0x000000040cebaafeUL, + 0x000000065e08d288UL, + 0x00000002e4f6d767UL, + 0x0000000fe10d2f21UL, + 0x0000000110347bdaUL, + 0x0000000e43a9bfb3UL, + 0x0000000cdea483ccUL, + 0x0000000fb1e2d8c6UL, + 0x0000000d8a0af7a7UL, + 0x000000037d05b182UL, + 0x00000008d1241d83UL, + 0x0000000da1ea7b6eUL, + 0x000000065bea93dbUL, + 0x00000002a02f8753UL, + 0x0000000454243289UL, + 0x00000004150bc5a2UL, + 0x0000000bbabe5911UL, + 0x00000004cbcdbc59UL, + 0x0000000f0e61340bUL, + 0x000000030a2cdea8UL, + 0x00000005daecb091UL, + 0x00000005dc93d891UL, + 0x0000000c501b4051UL, + 0x0000000782cfba78UL, + 0x00000004c191b61eUL, + 0x0000000b7e27ef35UL, + 0x000000005a476838UL, + 0x00000009b0209574UL, + 0x0000000a775164cfUL, + 0x0000000d33d21701UL, + 0x00000003afcb7d45UL, + 0x00000004df2035cdUL, + 0x0000000498819a21UL, + 0x0000000293f9e506UL, + 0x00000009a35ff1c8UL, + 0x0000000c090ebe6bUL, + 0x0000000a4f0551d4UL, + 0x00000005dc0dc194UL, + 0x00000001388aeb31UL, + 0x0000000340b27bf4UL, + 0x00000003a0f320abUL, + 0x00000000996be75dUL, + 0x0000000b257ecf39UL, + 0x000000078d86f2f1UL, + 0x0000000673f5ff91UL, + 0x00000004538d7e3eUL, + 0x0000000de5bc4369UL + } +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "tag36h11" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t tag36h11 = { + .ncodes = 587, + .black_border = 1, + .d = 6, + .h = 11, + .codes = { + 0x0000000d5d628584UL, + 0x0000000d97f18b49UL, + 0x0000000dd280910eUL, + 0x0000000e479e9c98UL, + 0x0000000ebcbca822UL, + 0x0000000f31dab3acUL, + 0x0000000056a5d085UL, + 0x000000010652e1d4UL, + 0x000000022b1dfeadUL, + 0x0000000265ad0472UL, + 0x000000034fe91b86UL, + 0x00000003ff962cd5UL, + 0x000000043a25329aUL, + 0x0000000474b4385fUL, + 0x00000004e9d243e9UL, + 0x00000005246149aeUL, + 0x00000005997f5538UL, + 0x0000000683bb6c4cUL, + 0x00000006be4a7211UL, + 0x00000007e3158eeaUL, + 0x000000081da494afUL, + 0x0000000858339a74UL, + 0x00000008cd51a5feUL, + 0x00000009f21cc2d7UL, + 0x0000000a2cabc89cUL, + 0x0000000adc58d9ebUL, + 0x0000000b16e7dfb0UL, + 0x0000000b8c05eb3aUL, + 0x0000000d25ef139dUL, + 0x0000000d607e1962UL, + 0x0000000e4aba3076UL, + 0x00000002dde6a3daUL, + 0x000000043d40c678UL, + 0x00000005620be351UL, + 0x000000064c47fa65UL, + 0x0000000686d7002aUL, + 0x00000006c16605efUL, + 0x00000006fbf50bb4UL, + 0x00000008d06d39dcUL, + 0x00000009f53856b5UL, + 0x0000000adf746dc9UL, + 0x0000000bc9b084ddUL, + 0x0000000d290aa77bUL, + 0x0000000d9e28b305UL, + 0x0000000e4dd5c454UL, + 0x0000000fad2fe6f2UL, + 0x0000000181a8151aUL, + 0x000000026be42c2eUL, + 0x00000002e10237b8UL, + 0x0000000405cd5491UL, + 0x00000007742eab1cUL, + 0x000000085e6ac230UL, + 0x00000008d388cdbaUL, + 0x00000009f853ea93UL, + 0x0000000c41ea2445UL, + 0x0000000cf1973594UL, + 0x000000014a34a333UL, + 0x000000031eacd15bUL, + 0x00000006c79d2dabUL, + 0x000000073cbb3935UL, + 0x000000089c155bd3UL, + 0x00000008d6a46198UL, + 0x000000091133675dUL, + 0x0000000a708d89fbUL, + 0x0000000ae5ab9585UL, + 0x0000000b9558a6d4UL, + 0x0000000b98743ab2UL, + 0x0000000d6cec68daUL, + 0x00000001506bcaefUL, + 0x00000004becd217aUL, + 0x00000004f95c273fUL, + 0x0000000658b649ddUL, + 0x0000000a76c4b1b7UL, + 0x0000000ecf621f56UL, + 0x00000001c8a56a57UL, + 0x00000003628e92baUL, + 0x000000053706c0e2UL, + 0x00000005e6b3d231UL, + 0x00000007809cfa94UL, + 0x0000000e97eead6fUL, + 0x00000005af40604aUL, + 0x00000007492988adUL, + 0x0000000ed5994712UL, + 0x00000005eceaf9edUL, + 0x00000007c1632815UL, + 0x0000000c1a0095b4UL, + 0x0000000e9e25d52bUL, + 0x00000003a6705419UL, + 0x0000000a8333012fUL, + 0x00000004ce5704d0UL, + 0x0000000508e60a95UL, + 0x0000000877476120UL, + 0x0000000a864e950dUL, + 0x0000000ea45cfce7UL, + 0x000000019da047e8UL, + 0x000000024d4d5937UL, + 0x00000006e079cc9bUL, + 0x000000099f2e11d7UL, + 0x000000033aa50429UL, + 0x0000000499ff26c7UL, + 0x000000050f1d3251UL, + 0x000000066e7754efUL, + 0x000000096ad633ceUL, + 0x00000009a5653993UL, + 0x0000000aca30566cUL, + 0x0000000c298a790aUL, + 0x00000008be44b65dUL, + 0x0000000dc68f354bUL, + 0x000000016f7f919bUL, + 0x00000004dde0e826UL, + 0x0000000d548cbd9fUL, + 0x0000000e0439ceeeUL, + 0x0000000fd8b1fd16UL, + 0x000000076521bb7bUL, + 0x0000000d92375742UL, + 0x0000000cab16d40cUL, + 0x0000000730c9dd72UL, + 0x0000000ad9ba39c2UL, + 0x0000000b14493f87UL, + 0x000000052b15651fUL, + 0x0000000185409cadUL, + 0x000000077ae2c68dUL, + 0x000000094f5af4b5UL, + 0x00000000a13bad55UL, + 0x000000061ea437cdUL, + 0x0000000a022399e2UL, + 0x0000000203b163d1UL, + 0x00000007bba8f40eUL, + 0x000000095bc9442dUL, + 0x000000041c0b5358UL, + 0x00000008e9c6cc81UL, + 0x00000000eb549670UL, + 0x00000009da3a0b51UL, + 0x0000000d832a67a1UL, + 0x0000000dcd4350bcUL, + 0x00000004aa05fdd2UL, + 0x000000060c7bb44eUL, + 0x00000004b358b96cUL, + 0x0000000067299b45UL, + 0x0000000b9c89b5faUL, + 0x00000006975acaeaUL, + 0x000000062b8f7afaUL, + 0x000000033567c3d7UL, + 0x0000000bac139950UL, + 0x0000000a5927c62aUL, + 0x00000005c916e6a4UL, + 0x0000000260ecb7d5UL, + 0x000000029b7bbd9aUL, + 0x0000000903205f26UL, + 0x0000000ae72270a4UL, + 0x00000003d2ec51a7UL, + 0x000000082ea55324UL, + 0x000000011a6f3427UL, + 0x00000001ca1c4576UL, + 0x0000000a40c81aefUL, + 0x0000000bddccd730UL, + 0x00000000e617561eUL, + 0x0000000969317b0fUL, + 0x000000067f781364UL, + 0x0000000610912f96UL, + 0x0000000b2549fdfcUL, + 0x000000006e5aaa6bUL, + 0x0000000b6c475339UL, + 0x0000000c56836a4dUL, + 0x0000000844e351ebUL, + 0x00000004647f83b4UL, + 0x00000000908a04f5UL, + 0x00000007f51034c9UL, + 0x0000000aee537fcaUL, + 0x00000005e92494baUL, + 0x0000000d445808f4UL, + 0x000000028d68b563UL, + 0x000000004d25374bUL, + 0x00000002bc065f65UL, + 0x000000096dc3ea0cUL, + 0x00000004b2ade817UL, + 0x000000007c3fd502UL, + 0x0000000e768b5cafUL, + 0x000000017605cf6cUL, + 0x0000000182741ee4UL, + 0x000000062846097cUL, + 0x000000072b5ebf80UL, + 0x0000000263da6e13UL, + 0x0000000fa841bcb5UL, + 0x00000007e45e8c69UL, + 0x0000000653c81fa0UL, + 0x00000007443b5e70UL, + 0x00000000a5234afdUL, + 0x000000074756f24eUL, + 0x0000000157ebf02aUL, + 0x000000082ef46939UL, + 0x000000080d420264UL, + 0x00000002aeed3e98UL, + 0x0000000b0a1dd4f8UL, + 0x0000000b5436be13UL, + 0x00000007b7b4b13bUL, + 0x00000001ce80d6d3UL, + 0x000000016c08427dUL, + 0x0000000ee54462ddUL, + 0x00000001f7644cceUL, + 0x00000009c7b5cc92UL, + 0x0000000e369138f8UL, + 0x00000005d5a66e91UL, + 0x0000000485d62f49UL, + 0x0000000e6e819e94UL, + 0x0000000b1f340eb5UL, + 0x000000009d198ce2UL, + 0x0000000d60717437UL, + 0x00000000196b856cUL, + 0x0000000f0a6173a5UL, + 0x000000012c0e1ec6UL, + 0x000000062b82d5cfUL, + 0x0000000ad154c067UL, + 0x0000000ce3778832UL, + 0x00000006b0a7b864UL, + 0x00000004c7686694UL, + 0x00000005058ff3ecUL, + 0x0000000d5e21ea23UL, + 0x00000009ff4a76eeUL, + 0x00000009dd981019UL, + 0x00000001bad4d30aUL, + 0x0000000c601896d1UL, + 0x0000000973439b48UL, + 0x00000001ce7431a8UL, + 0x000000057a8021d6UL, + 0x0000000f9dba96e6UL, + 0x000000083a2e4e7cUL, + 0x00000008ea585380UL, + 0x0000000af6c0e744UL, + 0x0000000875b73babUL, + 0x0000000da34ca901UL, + 0x00000002ab9727efUL, + 0x0000000d39f21b9aUL, + 0x00000008a10b742fUL, + 0x00000005f8952dbaUL, + 0x0000000f8da71ab0UL, + 0x0000000c25f9df96UL, + 0x000000006f8a5d94UL, + 0x0000000e42e63e1aUL, + 0x0000000b78409d1bUL, + 0x0000000792229addUL, + 0x00000005acf8c455UL, + 0x00000002fc29a9b0UL, + 0x0000000ea486237bUL, + 0x0000000b0c9685a0UL, + 0x00000001ad748a47UL, + 0x000000003b4712d5UL, + 0x0000000f29216d30UL, + 0x00000008dad65e49UL, + 0x00000000a2cf09ddUL, + 0x00000000b5f174c6UL, + 0x0000000e54f57743UL, + 0x0000000b9cf54d78UL, + 0x00000004a312a88aUL, + 0x000000027babc962UL, + 0x0000000b86897111UL, + 0x0000000f2ff6c116UL, + 0x000000082274bd8aUL, + 0x000000097023505eUL, + 0x000000052d46edd1UL, + 0x0000000585c1f538UL, + 0x0000000bddd00e43UL, + 0x00000005590b74dfUL, + 0x0000000729404a1fUL, + 0x000000065320855eUL, + 0x0000000d3d4b6956UL, + 0x00000007ae374f14UL, + 0x00000002d7a60e06UL, + 0x0000000315cd9b5eUL, + 0x0000000fd36b4eacUL, + 0x0000000f1df7642bUL, + 0x000000055db27726UL, + 0x00000008f15ebc19UL, + 0x0000000992f8c531UL, + 0x000000062dea2a40UL, + 0x0000000928275cabUL, + 0x000000069c263cb9UL, + 0x0000000a774cca9eUL, + 0x0000000266b2110eUL, + 0x00000001b14acbb8UL, + 0x0000000624b8a71bUL, + 0x00000001c539406bUL, + 0x00000003086d529bUL, + 0x00000000111dd66eUL, + 0x000000098cd630bfUL, + 0x00000008b9d1ffdcUL, + 0x000000072b2f61e7UL, + 0x00000009ed9d672bUL, + 0x000000096cdd15f3UL, + 0x00000006366c2504UL, + 0x00000006ca9df73aUL, + 0x0000000a066d60f0UL, + 0x0000000e7a4b8addUL, + 0x00000008264647efUL, + 0x0000000aa195bf81UL, + 0x00000009a3db8244UL, + 0x0000000014d2df6aUL, + 0x00000000b63265b7UL, + 0x00000002f010de73UL, + 0x000000097e774986UL, + 0x0000000248affc29UL, + 0x0000000fb57dcd11UL, + 0x00000000b1a7e4d9UL, + 0x00000004bfa2d07dUL, + 0x000000054e5cdf96UL, + 0x00000004c15c1c86UL, + 0x0000000cd9c61166UL, + 0x0000000499380b2aUL, + 0x0000000540308d09UL, + 0x00000008b63fe66fUL, + 0x0000000c81aeb35eUL, + 0x000000086fe0bd5cUL, + 0x0000000ce2480c2aUL, + 0x00000001ab29ee60UL, + 0x00000008048daa15UL, + 0x0000000dbfeb2d39UL, + 0x0000000567c9858cUL, + 0x00000002b6edc5bcUL, + 0x00000002078fca82UL, + 0x0000000adacc22aaUL, + 0x0000000b92486f49UL, + 0x000000051fac5964UL, + 0x0000000691ee6420UL, + 0x0000000f63b3e129UL, + 0x000000039be7e572UL, + 0x0000000da2ce6c74UL, + 0x000000020cf17a5cUL, + 0x0000000ee55f9b6eUL, + 0x0000000fb8572726UL, + 0x0000000b2c2de548UL, + 0x0000000caa9bce92UL, + 0x0000000ae9182db3UL, + 0x000000074b6e5bd1UL, + 0x0000000137b252afUL, + 0x000000051f686881UL, + 0x0000000d672f6c02UL, + 0x0000000654146ce4UL, + 0x0000000f944bc825UL, + 0x0000000e8327f809UL, + 0x000000076a73fd59UL, + 0x0000000f79da4cb4UL, + 0x0000000956f8099bUL, + 0x00000007b5f2655cUL, + 0x0000000d06b114a6UL, + 0x0000000d0697ca50UL, + 0x000000027c390797UL, + 0x0000000bc61ed9b2UL, + 0x0000000cc12dd19bUL, + 0x0000000eb7818d2cUL, + 0x0000000092fcecdaUL, + 0x000000089ded4ea1UL, + 0x0000000256a0ba34UL, + 0x0000000b6948e627UL, + 0x00000001ef6b1054UL, + 0x00000008639294a2UL, + 0x0000000eda3780a4UL, + 0x000000039ee2af1dUL, + 0x0000000cd257edc5UL, + 0x00000002d9d6bc22UL, + 0x0000000121d3b47dUL, + 0x000000037e23f8adUL, + 0x0000000119f31cf6UL, + 0x00000002c97f4f09UL, + 0x0000000d502abfe0UL, + 0x000000010bc3ca77UL, + 0x000000053d7190efUL, + 0x000000090c3e62a6UL, + 0x00000007e9ebf675UL, + 0x0000000979ce23d1UL, + 0x000000027f0c98e9UL, + 0x0000000eafb4ae59UL, + 0x00000007ca7fe2bdUL, + 0x00000001490ca8f6UL, + 0x00000009123387baUL, + 0x0000000b3bc73888UL, + 0x00000003ea87e325UL, + 0x00000004888964aaUL, + 0x0000000a0188a6b9UL, + 0x0000000cd383c666UL, + 0x000000040029a3fdUL, + 0x0000000e1c00ac5cUL, + 0x000000039e6f2b6eUL, + 0x0000000de664f622UL, + 0x0000000e979a75e8UL, + 0x00000007c6b4c86cUL, + 0x0000000fd492e071UL, + 0x00000008fbb35118UL, + 0x000000040b4a09b7UL, + 0x0000000af80bd6daUL, + 0x000000070e0b2521UL, + 0x00000002f5c54d93UL, + 0x00000003f4a118d5UL, + 0x000000009c1897b9UL, + 0x0000000079776eacUL, + 0x0000000084b00b17UL, + 0x00000003a95ad90eUL, + 0x000000028c544095UL, + 0x000000039d457c05UL, + 0x00000007a3791a78UL, + 0x0000000bb770e22eUL, + 0x00000009a822bd6cUL, + 0x000000068a4b1fedUL, + 0x0000000a5fd27b3bUL, + 0x00000000c3995b79UL, + 0x0000000d1519dff1UL, + 0x00000008e7eee359UL, + 0x0000000cd3ca50b1UL, + 0x0000000b73b8b793UL, + 0x000000057aca1c43UL, + 0x0000000ec2655277UL, + 0x0000000785a2c1b3UL, + 0x000000075a07985aUL, + 0x0000000a4b01eb69UL, + 0x0000000a18a11347UL, + 0x0000000db1f28ca3UL, + 0x0000000877ec3e25UL, + 0x000000031f6341b8UL, + 0x00000001363a3a4cUL, + 0x0000000075d8b9baUL, + 0x00000007ae0792a9UL, + 0x0000000a83a21651UL, + 0x00000007f08f9fb5UL, + 0x00000000d0cf73a9UL, + 0x0000000b04dcc98eUL, + 0x0000000f65c7b0f8UL, + 0x000000065ddaf69aUL, + 0x00000002cf9b86b3UL, + 0x000000014cb51e25UL, + 0x0000000f48027b5bUL, + 0x00000000ec26ea8bUL, + 0x000000044bafd45cUL, + 0x0000000b12c7c0c4UL, + 0x0000000959fd9d82UL, + 0x0000000c77c9725aUL, + 0x000000048a22d462UL, + 0x00000008398e8072UL, + 0x0000000ec89b05ceUL, + 0x0000000bb682d4c9UL, + 0x0000000e5a86d2ffUL, + 0x0000000358f01134UL, + 0x00000008556ddcf6UL, + 0x000000067584b6e2UL, + 0x000000011609439fUL, + 0x000000008488816eUL, + 0x0000000aaf1a2c46UL, + 0x0000000f879898cfUL, + 0x00000008bbe5e2f7UL, + 0x0000000101eee363UL, + 0x0000000690f69377UL, + 0x0000000f5bd93cd9UL, + 0x0000000cea4c2bf6UL, + 0x00000009550be706UL, + 0x00000002c5b38a60UL, + 0x0000000e72033547UL, + 0x00000004458b0629UL, + 0x0000000ee8d9ed41UL, + 0x0000000d2f918d72UL, + 0x000000078dc39fd3UL, + 0x00000008212636f6UL, + 0x00000007450a72a7UL, + 0x0000000c4f0cf4c6UL, + 0x0000000367bcddcdUL, + 0x0000000c1caf8cc6UL, + 0x0000000a7f5b853dUL, + 0x00000009d536818bUL, + 0x0000000535e021b0UL, + 0x0000000a7eb8729eUL, + 0x0000000422a67b49UL, + 0x0000000929e928a6UL, + 0x000000048e8aefccUL, + 0x0000000a9897393cUL, + 0x00000005eb81d37eUL, + 0x00000001e80287b7UL, + 0x000000034770d903UL, + 0x00000002eef86728UL, + 0x000000059266ccb6UL, + 0x00000000110bba61UL, + 0x00000001dfd284efUL, + 0x0000000447439d1bUL, + 0x0000000fece0e599UL, + 0x00000009309f3703UL, + 0x000000080764d1ddUL, + 0x0000000353f1e6a0UL, + 0x00000002c1c12dccUL, + 0x0000000c1d21b9d7UL, + 0x0000000457ee453eUL, + 0x0000000d66faf540UL, + 0x000000044831e652UL, + 0x0000000cfd49a848UL, + 0x00000009312d4133UL, + 0x00000003f097d3eeUL, + 0x00000008c9ebef7aUL, + 0x0000000a99e29e88UL, + 0x00000000e9fab22cUL, + 0x00000004e748f4fbUL, + 0x0000000ecdee4288UL, + 0x0000000abce5f1d0UL, + 0x0000000c42f6876cUL, + 0x00000007ed402ea0UL, + 0x0000000e5c4242c3UL, + 0x0000000d5b2c31aeUL, + 0x0000000286863be6UL, + 0x0000000160444d94UL, + 0x00000005f0f5808eUL, + 0x0000000ae3d44b2aUL, + 0x00000009f5c5d109UL, + 0x00000008ad9316d7UL, + 0x00000003422ba064UL, + 0x00000002fed11d56UL, + 0x0000000bea6e3e04UL, + 0x000000004b029eecUL, + 0x00000006deed7435UL, + 0x00000003718ce17cUL, + 0x000000055857f5e2UL, + 0x00000002edac7b62UL, + 0x0000000085d6c512UL, + 0x0000000d6ca88e0fUL, + 0x00000002b7e1fc69UL, + 0x0000000a699d5c1bUL, + 0x0000000f05ad74deUL, + 0x00000004cf5fb56dUL, + 0x00000005725e07e1UL, + 0x000000072f18a2deUL, + 0x00000001cec52609UL, + 0x000000048534243cUL, + 0x00000002523a4d69UL, + 0x000000035c1b80d1UL, + 0x0000000a4d7338a7UL, + 0x00000000db1af012UL, + 0x0000000e61a9475dUL, + 0x000000005df03f91UL, + 0x000000097ae260bbUL, + 0x000000032d627fefUL, + 0x0000000b640f73c2UL, + 0x000000045a1ac9c6UL, + 0x00000006a2202de1UL, + 0x000000057d3e25f2UL, + 0x00000005aa9f986eUL, + 0x00000000cc859d8aUL, + 0x0000000e3ec6cca8UL, + 0x000000054e95e1aeUL, + 0x0000000446887b06UL, + 0x00000007516732beUL, + 0x00000003817ac8f5UL, + 0x00000003e26d938cUL, + 0x0000000aa81bc235UL, + 0x0000000df387ca1bUL, + 0x00000000f3a3b3f2UL, + 0x0000000b4bf69677UL, + 0x0000000ae21868edUL, + 0x000000081e1d2d9dUL, + 0x0000000a0a9ea14cUL, + 0x00000008eee297a9UL, + 0x00000004740c0559UL, + 0x0000000e8b141837UL, + 0x0000000ac69e0a3dUL, + 0x00000009ed83a1e1UL, + 0x00000005edb55ecbUL, + 0x000000007340fe81UL, + 0x000000050dfbc6bfUL, + 0x00000004f583508aUL, + 0x0000000cb1fb78bcUL, + 0x00000004025ced2fUL, + 0x000000039791ebecUL, + 0x000000053ee388f1UL, + 0x00000007d6c0bd23UL, + 0x000000093a995fbeUL, + 0x00000008a41728deUL, + 0x00000002fe70e053UL, + 0x0000000ab3db443aUL, + 0x00000001364edb05UL, + 0x000000047b6eeed6UL, + 0x000000012e71af01UL, + 0x000000052ff83587UL, + 0x00000003a1575dd8UL, + 0x00000003feaa3564UL, + 0x0000000eacf78ba7UL, + 0x00000000872b94f8UL, + 0x0000000da8ddf9a2UL, + 0x00000009aa920d2bUL, + 0x00000001f350ed36UL, + 0x000000018a5e861fUL, + 0x00000002c35b89c3UL, + 0x00000003347ac48aUL, + 0x00000007f23e022eUL, + 0x00000002459068fbUL, + 0x0000000e83be4b73UL + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "artoolkit" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const apriltag_family_t artoolkit = { + .ncodes = 512, + .black_border = 1, + .d = 6, + .h = 7, + .codes = { + 0x0006dc269c27UL, + 0x0006d4229e26UL, + 0x0006cc2e9825UL, + 0x0006c42a9a24UL, + 0x0006fc369423UL, + 0x0006f4329622UL, + 0x0006ec3e9021UL, + 0x0006e43a9220UL, + 0x00069c068c2fUL, + 0x000694028e2eUL, + 0x00068c0e882dUL, + 0x0006840a8a2cUL, + 0x0006bc16842bUL, + 0x0006b412862aUL, + 0x0006ac1e8029UL, + 0x0006a41a8228UL, + 0x00065c66bc37UL, + 0x00065462be36UL, + 0x00064c6eb835UL, + 0x0006446aba34UL, + 0x00067c76b433UL, + 0x00067472b632UL, + 0x00066c7eb031UL, + 0x0006647ab230UL, + 0x00061c46ac3fUL, + 0x00061442ae3eUL, + 0x00060c4ea83dUL, + 0x0006044aaa3cUL, + 0x00063c56a43bUL, + 0x00063452a63aUL, + 0x00062c5ea039UL, + 0x0006245aa238UL, + 0x0007dca6dc07UL, + 0x0007d4a2de06UL, + 0x0007ccaed805UL, + 0x0007c4aada04UL, + 0x0007fcb6d403UL, + 0x0007f4b2d602UL, + 0x0007ecbed001UL, + 0x0007e4bad200UL, + 0x00079c86cc0fUL, + 0x00079482ce0eUL, + 0x00078c8ec80dUL, + 0x0007848aca0cUL, + 0x0007bc96c40bUL, + 0x0007b492c60aUL, + 0x0007ac9ec009UL, + 0x0007a49ac208UL, + 0x00075ce6fc17UL, + 0x000754e2fe16UL, + 0x00074ceef815UL, + 0x000744eafa14UL, + 0x00077cf6f413UL, + 0x000774f2f612UL, + 0x00076cfef011UL, + 0x000764faf210UL, + 0x00071cc6ec1fUL, + 0x000714c2ee1eUL, + 0x00070ccee81dUL, + 0x000704caea1cUL, + 0x00073cd6e41bUL, + 0x000734d2e61aUL, + 0x00072cdee019UL, + 0x000724dae218UL, + 0x0004dd261c67UL, + 0x0004d5221e66UL, + 0x0004cd2e1865UL, + 0x0004c52a1a64UL, + 0x0004fd361463UL, + 0x0004f5321662UL, + 0x0004ed3e1061UL, + 0x0004e53a1260UL, + 0x00049d060c6fUL, + 0x000495020e6eUL, + 0x00048d0e086dUL, + 0x0004850a0a6cUL, + 0x0004bd16046bUL, + 0x0004b512066aUL, + 0x0004ad1e0069UL, + 0x0004a51a0268UL, + 0x00045d663c77UL, + 0x000455623e76UL, + 0x00044d6e3875UL, + 0x0004456a3a74UL, + 0x00047d763473UL, + 0x000475723672UL, + 0x00046d7e3071UL, + 0x0004657a3270UL, + 0x00041d462c7fUL, + 0x000415422e7eUL, + 0x00040d4e287dUL, + 0x0004054a2a7cUL, + 0x00043d56247bUL, + 0x00043552267aUL, + 0x00042d5e2079UL, + 0x0004255a2278UL, + 0x0005dda65c47UL, + 0x0005d5a25e46UL, + 0x0005cdae5845UL, + 0x0005c5aa5a44UL, + 0x0005fdb65443UL, + 0x0005f5b25642UL, + 0x0005edbe5041UL, + 0x0005e5ba5240UL, + 0x00059d864c4fUL, + 0x000595824e4eUL, + 0x00058d8e484dUL, + 0x0005858a4a4cUL, + 0x0005bd96444bUL, + 0x0005b592464aUL, + 0x0005ad9e4049UL, + 0x0005a59a4248UL, + 0x00055de67c57UL, + 0x000555e27e56UL, + 0x00054dee7855UL, + 0x000545ea7a54UL, + 0x00057df67453UL, + 0x000575f27652UL, + 0x00056dfe7051UL, + 0x000565fa7250UL, + 0x00051dc66c5fUL, + 0x000515c26e5eUL, + 0x00050dce685dUL, + 0x000505ca6a5cUL, + 0x00053dd6645bUL, + 0x000535d2665aUL, + 0x00052dde6059UL, + 0x000525da6258UL, + 0x0002de279ca7UL, + 0x0002d6239ea6UL, + 0x0002ce2f98a5UL, + 0x0002c62b9aa4UL, + 0x0002fe3794a3UL, + 0x0002f63396a2UL, + 0x0002ee3f90a1UL, + 0x0002e63b92a0UL, + 0x00029e078cafUL, + 0x000296038eaeUL, + 0x00028e0f88adUL, + 0x0002860b8aacUL, + 0x0002be1784abUL, + 0x0002b61386aaUL, + 0x0002ae1f80a9UL, + 0x0002a61b82a8UL, + 0x00025e67bcb7UL, + 0x00025663beb6UL, + 0x00024e6fb8b5UL, + 0x0002466bbab4UL, + 0x00027e77b4b3UL, + 0x00027673b6b2UL, + 0x00026e7fb0b1UL, + 0x0002667bb2b0UL, + 0x00021e47acbfUL, + 0x00021643aebeUL, + 0x00020e4fa8bdUL, + 0x0002064baabcUL, + 0x00023e57a4bbUL, + 0x00023653a6baUL, + 0x00022e5fa0b9UL, + 0x0002265ba2b8UL, + 0x0003dea7dc87UL, + 0x0003d6a3de86UL, + 0x0003ceafd885UL, + 0x0003c6abda84UL, + 0x0003feb7d483UL, + 0x0003f6b3d682UL, + 0x0003eebfd081UL, + 0x0003e6bbd280UL, + 0x00039e87cc8fUL, + 0x00039683ce8eUL, + 0x00038e8fc88dUL, + 0x0003868bca8cUL, + 0x0003be97c48bUL, + 0x0003b693c68aUL, + 0x0003ae9fc089UL, + 0x0003a69bc288UL, + 0x00035ee7fc97UL, + 0x000356e3fe96UL, + 0x00034eeff895UL, + 0x000346ebfa94UL, + 0x00037ef7f493UL, + 0x000376f3f692UL, + 0x00036efff091UL, + 0x000366fbf290UL, + 0x00031ec7ec9fUL, + 0x000316c3ee9eUL, + 0x00030ecfe89dUL, + 0x000306cbea9cUL, + 0x00033ed7e49bUL, + 0x000336d3e69aUL, + 0x00032edfe099UL, + 0x000326dbe298UL, + 0x0000df271ce7UL, + 0x0000d7231ee6UL, + 0x0000cf2f18e5UL, + 0x0000c72b1ae4UL, + 0x0000ff3714e3UL, + 0x0000f73316e2UL, + 0x0000ef3f10e1UL, + 0x0000e73b12e0UL, + 0x00009f070cefUL, + 0x000097030eeeUL, + 0x00008f0f08edUL, + 0x0000870b0aecUL, + 0x0000bf1704ebUL, + 0x0000b71306eaUL, + 0x0000af1f00e9UL, + 0x0000a71b02e8UL, + 0x00005f673cf7UL, + 0x000057633ef6UL, + 0x00004f6f38f5UL, + 0x0000476b3af4UL, + 0x00007f7734f3UL, + 0x0000777336f2UL, + 0x00006f7f30f1UL, + 0x0000677b32f0UL, + 0x00001f472cffUL, + 0x000017432efeUL, + 0x00000f4f28fdUL, + 0x0000074b2afcUL, + 0x00003f5724fbUL, + 0x0000375326faUL, + 0x00002f5f20f9UL, + 0x0000275b22f8UL, + 0x0001dfa75cc7UL, + 0x0001d7a35ec6UL, + 0x0001cfaf58c5UL, + 0x0001c7ab5ac4UL, + 0x0001ffb754c3UL, + 0x0001f7b356c2UL, + 0x0001efbf50c1UL, + 0x0001e7bb52c0UL, + 0x00019f874ccfUL, + 0x000197834eceUL, + 0x00018f8f48cdUL, + 0x0001878b4accUL, + 0x0001bf9744cbUL, + 0x0001b79346caUL, + 0x0001af9f40c9UL, + 0x0001a79b42c8UL, + 0x00015fe77cd7UL, + 0x000157e37ed6UL, + 0x00014fef78d5UL, + 0x000147eb7ad4UL, + 0x00017ff774d3UL, + 0x000177f376d2UL, + 0x00016fff70d1UL, + 0x000167fb72d0UL, + 0x00011fc76cdfUL, + 0x000117c36edeUL, + 0x00010fcf68ddUL, + 0x000107cb6adcUL, + 0x00013fd764dbUL, + 0x000137d366daUL, + 0x00012fdf60d9UL, + 0x000127db62d8UL, + 0x000ed8249d27UL, + 0x000ed0209f26UL, + 0x000ec82c9925UL, + 0x000ec0289b24UL, + 0x000ef8349523UL, + 0x000ef0309722UL, + 0x000ee83c9121UL, + 0x000ee0389320UL, + 0x000e98048d2fUL, + 0x000e90008f2eUL, + 0x000e880c892dUL, + 0x000e80088b2cUL, + 0x000eb814852bUL, + 0x000eb010872aUL, + 0x000ea81c8129UL, + 0x000ea0188328UL, + 0x000e5864bd37UL, + 0x000e5060bf36UL, + 0x000e486cb935UL, + 0x000e4068bb34UL, + 0x000e7874b533UL, + 0x000e7070b732UL, + 0x000e687cb131UL, + 0x000e6078b330UL, + 0x000e1844ad3fUL, + 0x000e1040af3eUL, + 0x000e084ca93dUL, + 0x000e0048ab3cUL, + 0x000e3854a53bUL, + 0x000e3050a73aUL, + 0x000e285ca139UL, + 0x000e2058a338UL, + 0x000fd8a4dd07UL, + 0x000fd0a0df06UL, + 0x000fc8acd905UL, + 0x000fc0a8db04UL, + 0x000ff8b4d503UL, + 0x000ff0b0d702UL, + 0x000fe8bcd101UL, + 0x000fe0b8d300UL, + 0x000f9884cd0fUL, + 0x000f9080cf0eUL, + 0x000f888cc90dUL, + 0x000f8088cb0cUL, + 0x000fb894c50bUL, + 0x000fb090c70aUL, + 0x000fa89cc109UL, + 0x000fa098c308UL, + 0x000f58e4fd17UL, + 0x000f50e0ff16UL, + 0x000f48ecf915UL, + 0x000f40e8fb14UL, + 0x000f78f4f513UL, + 0x000f70f0f712UL, + 0x000f68fcf111UL, + 0x000f60f8f310UL, + 0x000f18c4ed1fUL, + 0x000f10c0ef1eUL, + 0x000f08cce91dUL, + 0x000f00c8eb1cUL, + 0x000f38d4e51bUL, + 0x000f30d0e71aUL, + 0x000f28dce119UL, + 0x000f20d8e318UL, + 0x000cd9241d67UL, + 0x000cd1201f66UL, + 0x000cc92c1965UL, + 0x000cc1281b64UL, + 0x000cf9341563UL, + 0x000cf1301762UL, + 0x000ce93c1161UL, + 0x000ce1381360UL, + 0x000c99040d6fUL, + 0x000c91000f6eUL, + 0x000c890c096dUL, + 0x000c81080b6cUL, + 0x000cb914056bUL, + 0x000cb110076aUL, + 0x000ca91c0169UL, + 0x000ca1180368UL, + 0x000c59643d77UL, + 0x000c51603f76UL, + 0x000c496c3975UL, + 0x000c41683b74UL, + 0x000c79743573UL, + 0x000c71703772UL, + 0x000c697c3171UL, + 0x000c61783370UL, + 0x000c19442d7fUL, + 0x000c11402f7eUL, + 0x000c094c297dUL, + 0x000c01482b7cUL, + 0x000c3954257bUL, + 0x000c3150277aUL, + 0x000c295c2179UL, + 0x000c21582378UL, + 0x000dd9a45d47UL, + 0x000dd1a05f46UL, + 0x000dc9ac5945UL, + 0x000dc1a85b44UL, + 0x000df9b45543UL, + 0x000df1b05742UL, + 0x000de9bc5141UL, + 0x000de1b85340UL, + 0x000d99844d4fUL, + 0x000d91804f4eUL, + 0x000d898c494dUL, + 0x000d81884b4cUL, + 0x000db994454bUL, + 0x000db190474aUL, + 0x000da99c4149UL, + 0x000da1984348UL, + 0x000d59e47d57UL, + 0x000d51e07f56UL, + 0x000d49ec7955UL, + 0x000d41e87b54UL, + 0x000d79f47553UL, + 0x000d71f07752UL, + 0x000d69fc7151UL, + 0x000d61f87350UL, + 0x000d19c46d5fUL, + 0x000d11c06f5eUL, + 0x000d09cc695dUL, + 0x000d01c86b5cUL, + 0x000d39d4655bUL, + 0x000d31d0675aUL, + 0x000d29dc6159UL, + 0x000d21d86358UL, + 0x000ada259da7UL, + 0x000ad2219fa6UL, + 0x000aca2d99a5UL, + 0x000ac2299ba4UL, + 0x000afa3595a3UL, + 0x000af23197a2UL, + 0x000aea3d91a1UL, + 0x000ae23993a0UL, + 0x000a9a058dafUL, + 0x000a92018faeUL, + 0x000a8a0d89adUL, + 0x000a82098bacUL, + 0x000aba1585abUL, + 0x000ab21187aaUL, + 0x000aaa1d81a9UL, + 0x000aa21983a8UL, + 0x000a5a65bdb7UL, + 0x000a5261bfb6UL, + 0x000a4a6db9b5UL, + 0x000a4269bbb4UL, + 0x000a7a75b5b3UL, + 0x000a7271b7b2UL, + 0x000a6a7db1b1UL, + 0x000a6279b3b0UL, + 0x000a1a45adbfUL, + 0x000a1241afbeUL, + 0x000a0a4da9bdUL, + 0x000a0249abbcUL, + 0x000a3a55a5bbUL, + 0x000a3251a7baUL, + 0x000a2a5da1b9UL, + 0x000a2259a3b8UL, + 0x000bdaa5dd87UL, + 0x000bd2a1df86UL, + 0x000bcaadd985UL, + 0x000bc2a9db84UL, + 0x000bfab5d583UL, + 0x000bf2b1d782UL, + 0x000beabdd181UL, + 0x000be2b9d380UL, + 0x000b9a85cd8fUL, + 0x000b9281cf8eUL, + 0x000b8a8dc98dUL, + 0x000b8289cb8cUL, + 0x000bba95c58bUL, + 0x000bb291c78aUL, + 0x000baa9dc189UL, + 0x000ba299c388UL, + 0x000b5ae5fd97UL, + 0x000b52e1ff96UL, + 0x000b4aedf995UL, + 0x000b42e9fb94UL, + 0x000b7af5f593UL, + 0x000b72f1f792UL, + 0x000b6afdf191UL, + 0x000b62f9f390UL, + 0x000b1ac5ed9fUL, + 0x000b12c1ef9eUL, + 0x000b0acde99dUL, + 0x000b02c9eb9cUL, + 0x000b3ad5e59bUL, + 0x000b32d1e79aUL, + 0x000b2adde199UL, + 0x000b22d9e398UL, + 0x0008db251de7UL, + 0x0008d3211fe6UL, + 0x0008cb2d19e5UL, + 0x0008c3291be4UL, + 0x0008fb3515e3UL, + 0x0008f33117e2UL, + 0x0008eb3d11e1UL, + 0x0008e33913e0UL, + 0x00089b050defUL, + 0x000893010feeUL, + 0x00088b0d09edUL, + 0x000883090becUL, + 0x0008bb1505ebUL, + 0x0008b31107eaUL, + 0x0008ab1d01e9UL, + 0x0008a31903e8UL, + 0x00085b653df7UL, + 0x000853613ff6UL, + 0x00084b6d39f5UL, + 0x000843693bf4UL, + 0x00087b7535f3UL, + 0x0008737137f2UL, + 0x00086b7d31f1UL, + 0x0008637933f0UL, + 0x00081b452dffUL, + 0x000813412ffeUL, + 0x00080b4d29fdUL, + 0x000803492bfcUL, + 0x00083b5525fbUL, + 0x0008335127faUL, + 0x00082b5d21f9UL, + 0x0008235923f8UL, + 0x0009dba55dc7UL, + 0x0009d3a15fc6UL, + 0x0009cbad59c5UL, + 0x0009c3a95bc4UL, + 0x0009fbb555c3UL, + 0x0009f3b157c2UL, + 0x0009ebbd51c1UL, + 0x0009e3b953c0UL, + 0x00099b854dcfUL, + 0x000993814fceUL, + 0x00098b8d49cdUL, + 0x000983894bccUL, + 0x0009bb9545cbUL, + 0x0009b39147caUL, + 0x0009ab9d41c9UL, + 0x0009a39943c8UL, + 0x00095be57dd7UL, + 0x000953e17fd6UL, + 0x00094bed79d5UL, + 0x000943e97bd4UL, + 0x00097bf575d3UL, + 0x000973f177d2UL, + 0x00096bfd71d1UL, + 0x000963f973d0UL, + 0x00091bc56ddfUL, + 0x000913c16fdeUL, + 0x00090bcd69ddUL, + 0x000903c96bdcUL, + 0x00093bd565dbUL, + 0x000933d167daUL, + 0x00092bdd61d9UL, + 0x000923d963d8UL + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "union_find.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef struct unionfind unionfind_t; + +struct unionfind +{ + struct ufrec *data; +}; + +struct ufrec +{ + // the parent of this node. If a node's parent is its own index, + // then it is a root. + uint16_t parent; +}; + +static inline unionfind_t *unionfind_create(uint16_t maxid) +{ + unionfind_t *uf = (unionfind_t*) fb_alloc(sizeof(unionfind_t)); + uf->data = (struct ufrec*) fb_alloc((maxid+1) * sizeof(struct ufrec)); + for (int i = 0; i <= maxid; i++) { + uf->data[i].parent = i; + } + return uf; +} + +static inline void unionfind_destroy() +{ + fb_free(); + fb_free(); +} + +/* +static inline uint16_t unionfind_get_representative(unionfind_t *uf, uint16_t id) +{ + // base case: a node is its own parent + if (uf->data[id].parent == id) + return id; + + // otherwise, recurse + uint32_t root = unionfind_get_representative(uf, uf->data[id].parent); + + // short circuit the path. [XXX This write prevents tail recursion] + uf->data[id].parent = root; + + return root; +} +*/ + +// this one seems to be every-so-slightly faster than the recursive +// version above. +static inline uint16_t unionfind_get_representative(unionfind_t *uf, uint16_t id) +{ + uint16_t root = id; + + // chase down the root + while (uf->data[root].parent != root) { + root = uf->data[root].parent; + } + + // go back and collapse the tree. + // + // XXX: on some of our workloads that have very shallow trees + // (e.g. image segmentation), we are actually faster not doing + // this... + while (uf->data[id].parent != root) { + uint16_t tmp = uf->data[id].parent; + uf->data[id].parent = root; + id = tmp; + } + + return root; +} + +static inline uint16_t unionfind_connect(unionfind_t *uf, uint16_t aid, uint16_t bid) +{ + uint16_t aroot = unionfind_get_representative(uf, aid); + uint16_t broot = unionfind_get_representative(uf, bid); + + if (aroot != broot) + uf->data[broot].parent = aroot; + + return aroot; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "union_find.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "apriltag_quad_thresh.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// limitation: image size must be <32768 in width and height. This is +// because we use a fixed-point 16 bit integer representation with one +// fractional bit. + +static inline uint32_t u64hash_2(uint64_t x) { + return (2654435761 * x) >> 32; + return (uint32_t) x; +} + +struct uint32_zarray_entry +{ + uint32_t id; + zarray_t *cluster; + + struct uint32_zarray_entry *next; +}; + +#ifndef M_PI +# define M_PI 3.141592653589793238462643383279502884196 +#endif + +struct pt +{ + // Note: these represent 2*actual value. + uint16_t x, y; + float theta; + int16_t gx, gy; +}; + +struct remove_vertex +{ + int i; // which vertex to remove? + int left, right; // left vertex, right vertex + + double err; +}; + +struct segment +{ + int is_vertex; + + // always greater than zero, but right can be > size, which denotes + // a wrap around back to the beginning of the points. and left < right. + int left, right; +}; + +struct line_fit_pt +{ + double Mx, My; + double Mxx, Myy, Mxy; + double W; // total weight +}; + +static inline void ptsort(struct pt *pts, int sz) +{ +#define MAYBE_SWAP(arr,apos,bpos) \ + if (arr[apos].theta > arr[bpos].theta) { \ + tmp = arr[apos]; arr[apos] = arr[bpos]; arr[bpos] = tmp; \ + }; + + if (sz <= 1) + return; + + if (sz == 2) { + struct pt tmp; + MAYBE_SWAP(pts, 0, 1); + return; + } + + // NB: Using less-branch-intensive sorting networks here on the + // hunch that it's better for performance. + if (sz == 3) { // 3 element bubble sort is optimal + struct pt tmp; + MAYBE_SWAP(pts, 0, 1); + MAYBE_SWAP(pts, 1, 2); + MAYBE_SWAP(pts, 0, 1); + return; + } + + if (sz == 4) { // 4 element optimal sorting network. + struct pt tmp; + MAYBE_SWAP(pts, 0, 1); // sort each half, like a merge sort + MAYBE_SWAP(pts, 2, 3); + MAYBE_SWAP(pts, 0, 2); // minimum value is now at 0. + MAYBE_SWAP(pts, 1, 3); // maximum value is now at end. + MAYBE_SWAP(pts, 1, 2); // that only leaves the middle two. + return; + } + + if (sz == 5) { + // this 9-step swap is optimal for a sorting network, but two + // steps slower than a generic sort. + struct pt tmp; + MAYBE_SWAP(pts, 0, 1); // sort each half (3+2), like a merge sort + MAYBE_SWAP(pts, 3, 4); + MAYBE_SWAP(pts, 1, 2); + MAYBE_SWAP(pts, 0, 1); + MAYBE_SWAP(pts, 0, 3); // minimum element now at 0 + MAYBE_SWAP(pts, 2, 4); // maximum element now at end + MAYBE_SWAP(pts, 1, 2); // now resort the three elements 1-3. + MAYBE_SWAP(pts, 2, 3); + MAYBE_SWAP(pts, 1, 2); + return; + } + +#undef MAYBE_SWAP + + // a merge sort with temp storage. + + struct pt *tmp = fb_alloc(sizeof(struct pt) * sz); + + memcpy(tmp, pts, sizeof(struct pt) * sz); + + int asz = sz/2; + int bsz = sz - asz; + + struct pt *as = &tmp[0]; + struct pt *bs = &tmp[asz]; + + ptsort(as, asz); + ptsort(bs, bsz); + +#define MERGE(apos,bpos) \ + if (as[apos].theta < bs[bpos].theta) \ + pts[outpos++] = as[apos++]; \ + else \ + pts[outpos++] = bs[bpos++]; + + int apos = 0, bpos = 0, outpos = 0; + while (apos + 8 < asz && bpos + 8 < bsz) { + MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); + MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); MERGE(apos,bpos); + } + + while (apos < asz && bpos < bsz) { + MERGE(apos,bpos); + } + + if (apos < asz) + memcpy(&pts[outpos], &as[apos], (asz-apos)*sizeof(struct pt)); + if (bpos < bsz) + memcpy(&pts[outpos], &bs[bpos], (bsz-bpos)*sizeof(struct pt)); + + fb_free(); // tmp + +#undef MERGE +} + +// lfps contains *cumulative* moments for N points, with +// index j reflecting points [0,j] (inclusive). +// +// fit a line to the points [i0, i1] (inclusive). i0, i1 are both [0, +// sz) if i1 < i0, we treat this as a wrap around. +void fit_line(struct line_fit_pt *lfps, int sz, int i0, int i1, double *lineparm, double *err, double *mse) +{ + assert(i0 != i1); + assert(i0 >= 0 && i1 >= 0 && i0 < sz && i1 < sz); + + double Mx, My, Mxx, Myy, Mxy, W; + int N; // how many points are included in the set? + + if (i0 < i1) { + N = i1 - i0 + 1; + + Mx = lfps[i1].Mx; + My = lfps[i1].My; + Mxx = lfps[i1].Mxx; + Mxy = lfps[i1].Mxy; + Myy = lfps[i1].Myy; + W = lfps[i1].W; + + if (i0 > 0) { + Mx -= lfps[i0-1].Mx; + My -= lfps[i0-1].My; + Mxx -= lfps[i0-1].Mxx; + Mxy -= lfps[i0-1].Mxy; + Myy -= lfps[i0-1].Myy; + W -= lfps[i0-1].W; + } + + } else { + // i0 > i1, e.g. [15, 2]. Wrap around. + assert(i0 > 0); + + Mx = lfps[sz-1].Mx - lfps[i0-1].Mx; + My = lfps[sz-1].My - lfps[i0-1].My; + Mxx = lfps[sz-1].Mxx - lfps[i0-1].Mxx; + Mxy = lfps[sz-1].Mxy - lfps[i0-1].Mxy; + Myy = lfps[sz-1].Myy - lfps[i0-1].Myy; + W = lfps[sz-1].W - lfps[i0-1].W; + + Mx += lfps[i1].Mx; + My += lfps[i1].My; + Mxx += lfps[i1].Mxx; + Mxy += lfps[i1].Mxy; + Myy += lfps[i1].Myy; + W += lfps[i1].W; + + N = sz - i0 + i1 + 1; + } + + assert(N >= 2); + + double Ex = Mx / W; + double Ey = My / W; + double Cxx = Mxx / W - Ex*Ex; + double Cxy = Mxy / W - Ex*Ey; + double Cyy = Myy / W - Ey*Ey; + + double nx, ny; + + if (1) { + // on iOS about 5% of total CPU spent in these trig functions. + // 85 ms per frame on 5S, example.pnm + // + // XXX this was using the double-precision atan2. Was there a case where + // we needed that precision? Seems doubtful. + double normal_theta = .5 * atan2f(-2*Cxy, (Cyy - Cxx)); + nx = cosf(normal_theta); + ny = sinf(normal_theta); + } else { + // 73.5 ms per frame on 5S, example.pnm + double ty = -2*Cxy; + double tx = (Cyy - Cxx); + double mag = ty*ty + tx*tx; + + if (mag == 0) { + nx = 1; + ny = 0; + } else { + double norm = sqrtf(ty*ty + tx*tx); + tx /= norm; + + // ty is now sin(2theta) + // tx is now cos(2theta). We want sin(theta) and cos(theta) + + // due to precision err, tx could still have slightly too large magnitude. + if (tx > 1) { + ny = 0; + nx = 1; + } else if (tx < -1) { + ny = 1; + nx = 0; + } else { + // half angle formula + ny = sqrtf((1 - tx)/2); + nx = sqrtf((1 + tx)/2); + + // pick a consistent branch cut + if (ty < 0) + ny = - ny; + } + } + } + + if (lineparm) { + lineparm[0] = Ex; + lineparm[1] = Ey; + lineparm[2] = nx; + lineparm[3] = ny; + } + + // sum of squared errors = + // + // SUM_i ((p_x - ux)*nx + (p_y - uy)*ny)^2 + // SUM_i nx*nx*(p_x - ux)^2 + 2nx*ny(p_x -ux)(p_y-uy) + ny*ny*(p_y-uy)*(p_y-uy) + // nx*nx*SUM_i((p_x -ux)^2) + 2nx*ny*SUM_i((p_x-ux)(p_y-uy)) + ny*ny*SUM_i((p_y-uy)^2) + // + // nx*nx*N*Cxx + 2nx*ny*N*Cxy + ny*ny*N*Cyy + + // sum of squared errors + if (err) + *err = nx*nx*N*Cxx + 2*nx*ny*N*Cxy + ny*ny*N*Cyy; + + // mean squared error + if (mse) + *mse = nx*nx*Cxx + 2*nx*ny*Cxy + ny*ny*Cyy; +} + +int pt_compare_theta(const void *_a, const void *_b) +{ + struct pt *a = (struct pt*) _a; + struct pt *b = (struct pt*) _b; + + return (a->theta < b->theta) ? -1 : 1; +} + +int err_compare_descending(const void *_a, const void *_b) +{ + const double *a = _a; + const double *b = _b; + + return ((*a) < (*b)) ? 1 : -1; +} + +/* + + 1. Identify A) white points near a black point and B) black points near a white point. + + 2. Find the connected components within each of the classes above, + yielding clusters of "white-near-black" and + "black-near-white". (These two classes are kept separate). Each + segment has a unique id. + + 3. For every pair of "white-near-black" and "black-near-white" + clusters, find the set of points that are in one and adjacent to the + other. In other words, a "boundary" layer between the two + clusters. (This is actually performed by iterating over the pixels, + rather than pairs of clusters.) Critically, this helps keep nearby + edges from becoming connected. +*/ +int quad_segment_maxima(apriltag_detector_t *td, zarray_t *cluster, struct line_fit_pt *lfps, int indices[4]) +{ + int sz = zarray_size(cluster); + + // ksz: when fitting points, how many points on either side do we consider? + // (actual "kernel" width is 2ksz). + // + // This value should be about: 0.5 * (points along shortest edge). + // + // If all edges were equally-sized, that would give a value of + // sz/8. We make it somewhat smaller to account for tags at high + // aspects. + + // XXX Tunable. Maybe make a multiple of JPEG block size to increase robustness + // to JPEG compression artifacts? + int ksz = imin(20, sz / 12); + + // can't fit a quad if there are too few points. + if (ksz < 2) + return 0; + +// printf("sz %5d, ksz %3d\n", sz, ksz); + + double *errs = fb_alloc(sz * sizeof(double)); + + for (int i = 0; i < sz; i++) { + fit_line(lfps, sz, (i + sz - ksz) % sz, (i + ksz) % sz, NULL, &errs[i], NULL); + } + + // apply a low-pass filter to errs + if (1) { + double *y = fb_alloc(sz * sizeof(double)); + + // how much filter to apply? + + // XXX Tunable + double sigma = 1; // was 3 + + // cutoff = exp(-j*j/(2*sigma*sigma)); + // log(cutoff) = -j*j / (2*sigma*sigma) + // log(cutoff)*2*sigma*sigma = -j*j; + + // how big a filter should we use? We make our kernel big + // enough such that we represent any values larger than + // 'cutoff'. + + // XXX Tunable (though not super useful to change) + double cutoff = 0.05; + int fsz = sqrt(-log(cutoff)*2*sigma*sigma) + 1; + fsz = 2*fsz + 1; + + // For default values of cutoff = 0.05, sigma = 3, + // we have fsz = 17. + float *f = fb_alloc(fsz * sizeof(float)); + + for (int i = 0; i < fsz; i++) { + int j = i - fsz / 2; + f[i] = exp(-j*j/(2*sigma*sigma)); + } + + for (int iy = 0; iy < sz; iy++) { + double acc = 0; + + for (int i = 0; i < fsz; i++) { + acc += errs[(iy + i - fsz / 2 + sz) % sz] * f[i]; + } + y[iy] = acc; + } + + fb_free(); // f + memcpy(errs, y, sz * sizeof(double)); + fb_free(); // y + } + + int *maxima = fb_alloc(sz * sizeof(int)); + double *maxima_errs = fb_alloc(sz * sizeof(double)); + int nmaxima = 0; + + for (int i = 0; i < sz; i++) { + if (errs[i] > errs[(i+1)%sz] && errs[i] > errs[(i+sz-1)%sz]) { + maxima[nmaxima] = i; + maxima_errs[nmaxima] = errs[i]; + nmaxima++; + } + } + + // if we didn't get at least 4 maxima, we can't fit a quad. + if (nmaxima < 4) + return 0; + + // select only the best maxima if we have too many + int max_nmaxima = td->qtp.max_nmaxima; + + if (nmaxima > max_nmaxima) { + double *maxima_errs_copy = fb_alloc(nmaxima * sizeof(double)); + memcpy(maxima_errs_copy, maxima_errs, nmaxima * sizeof(double)); + + // throw out all but the best handful of maxima. Sorts descending. + qsort(maxima_errs_copy, nmaxima, sizeof(double), err_compare_descending); + + double maxima_thresh = maxima_errs_copy[max_nmaxima]; + int out = 0; + for (int in = 0; in < nmaxima; in++) { + if (maxima_errs[in] <= maxima_thresh) + continue; + maxima[out++] = maxima[in]; + } + nmaxima = out; + + fb_free(); // maxima_errs_copy + } + + fb_free(); // maxima_errs + fb_free(); // maxima + fb_free(); // errs + + int best_indices[4]; + double best_error = HUGE_VALF; + + double err01, err12, err23, err30; + double mse01, mse12, mse23, mse30; + double params01[4], params12[4], params23[4], params30[4]; + + // disallow quads where the angle is less than a critical value. + double max_dot = cos(td->qtp.critical_rad); //25*M_PI/180); + + for (int m0 = 0; m0 < nmaxima - 3; m0++) { + int i0 = maxima[m0]; + + for (int m1 = m0+1; m1 < nmaxima - 2; m1++) { + int i1 = maxima[m1]; + + fit_line(lfps, sz, i0, i1, params01, &err01, &mse01); + + if (mse01 > td->qtp.max_line_fit_mse) + continue; + + for (int m2 = m1+1; m2 < nmaxima - 1; m2++) { + int i2 = maxima[m2]; + + fit_line(lfps, sz, i1, i2, params12, &err12, &mse12); + if (mse12 > td->qtp.max_line_fit_mse) + continue; + + double dot = params01[2]*params12[2] + params01[3]*params12[3]; + if (fabs(dot) > max_dot) + continue; + + for (int m3 = m2+1; m3 < nmaxima; m3++) { + int i3 = maxima[m3]; + + fit_line(lfps, sz, i2, i3, params23, &err23, &mse23); + if (mse23 > td->qtp.max_line_fit_mse) + continue; + + fit_line(lfps, sz, i3, i0, params30, &err30, &mse30); + if (mse30 > td->qtp.max_line_fit_mse) + continue; + + double err = err01 + err12 + err23 + err30; + if (err < best_error) { + best_error = err; + best_indices[0] = i0; + best_indices[1] = i1; + best_indices[2] = i2; + best_indices[3] = i3; + } + } + } + } + } + + if (best_error == HUGE_VALF) + return 0; + + for (int i = 0; i < 4; i++) + indices[i] = best_indices[i]; + + if (best_error / sz < td->qtp.max_line_fit_mse) + return 1; + return 0; +} + +// return 1 if the quad looks okay, 0 if it should be discarded +int fit_quad(apriltag_detector_t *td, image_u8_t *im, zarray_t *cluster, struct quad *quad, bool overrideMode) +{ + int res = 0; + + int sz = zarray_size(cluster); + if (sz < 4) // can't fit a quad to less than 4 points + return 0; + + ///////////////////////////////////////////////////////////// + // Step 1. Sort points so they wrap around the center of the + // quad. We will constrain our quad fit to simply partition this + // ordered set into 4 groups. + + // compute a bounding box so that we can order the points + // according to their angle WRT the center. + int32_t xmax = 0, xmin = INT32_MAX, ymax = 0, ymin = INT32_MAX; + + for (int pidx = 0; pidx < zarray_size(cluster); pidx++) { + struct pt *p; + zarray_get_volatile(cluster, pidx, &p); + + xmax = imax(xmax, p->x); + xmin = imin(xmin, p->x); + + ymax = imax(ymax, p->y); + ymin = imin(ymin, p->y); + } + + // add some noise to (cx,cy) so that pixels get a more diverse set + // of theta estimates. This will help us remove more points. + // (Only helps a small amount. The actual noise values here don't + // matter much at all, but we want them [-1, 1]. (XXX with + // fixed-point, should range be bigger?) + double cx = (xmin + xmax) * 0.5 + 0.05118; + double cy = (ymin + ymax) * 0.5 + -0.028581; + + double dot = 0; + + for (int pidx = 0; pidx < zarray_size(cluster); pidx++) { + struct pt *p; + zarray_get_volatile(cluster, pidx, &p); + + double dx = p->x - cx; + double dy = p->y - cy; + + p->theta = atan2f(dy, dx); + + dot += dx*p->gx + dy*p->gy; +// p->theta = terrible_atan2(dy, dx); + } + + // Ensure that the black border is inside the white border. + if ((!overrideMode) && (dot < 0)) + return 0; + + // we now sort the points according to theta. This is a prepatory + // step for segmenting them into four lines. + if (1) { + // zarray_sort(cluster, pt_compare_theta); + ptsort((struct pt*) cluster->data, zarray_size(cluster)); + + // remove duplicate points. (A byproduct of our segmentation system.) + if (1) { + int outpos = 1; + + struct pt *last; + zarray_get_volatile(cluster, 0, &last); + + for (int i = 1; i < sz; i++) { + + struct pt *p; + zarray_get_volatile(cluster, i, &p); + + if (p->x != last->x || p->y != last->y) { + + if (i != outpos) { + struct pt *out; + zarray_get_volatile(cluster, outpos, &out); + memcpy(out, p, sizeof(struct pt)); + } + + outpos++; + } + + last = p; + } + + cluster->size = outpos; + sz = outpos; + } + + } else { + // This is a counting sort in which we retain at most one + // point for every bucket; the bucket index is computed from + // theta. Since a good quad completes a complete revolution, + // there's reason to think that we should get a good + // distribution of thetas. We might "lose" a few points due + // to collisions, but this shouldn't affect quality very much. + + // XXX tunable. Increase to reduce the likelihood of "losing" + // points due to collisions. + int nbuckets = 4*sz; + +#define ASSOC 2 + struct pt v[nbuckets][ASSOC]; + memset(v, 0, sizeof(v)); + + // put each point into a bucket. + for (int i = 0; i < sz; i++) { + struct pt *p; + zarray_get_volatile(cluster, i, &p); + + assert(p->theta >= -M_PI && p->theta <= M_PI); + + int bucket = (nbuckets - 1) * (p->theta + M_PI) / (2*M_PI); + assert(bucket >= 0 && bucket < nbuckets); + + for (int i = 0; i < ASSOC; i++) { + if (v[bucket][i].theta == 0) { + v[bucket][i] = *p; + break; + } + } + } + + // collect the points from the buckets and put them back into the array. + int outsz = 0; + for (int i = 0; i < nbuckets; i++) { + for (int j = 0; j < ASSOC; j++) { + if (v[i][j].theta != 0) { + zarray_set(cluster, outsz, &v[i][j], NULL); + outsz++; + } + } + } + + zarray_truncate(cluster, outsz); + sz = outsz; + } + + if (sz < 4) + return 0; + + ///////////////////////////////////////////////////////////// + // Step 2. Precompute statistics that allow line fit queries to be + // efficiently computed for any contiguous range of indices. + + struct line_fit_pt *lfps = fb_alloc0(sz * sizeof(struct line_fit_pt)); + + for (int i = 0; i < sz; i++) { + struct pt *p; + zarray_get_volatile(cluster, i, &p); + + if (i > 0) { + memcpy(&lfps[i], &lfps[i-1], sizeof(struct line_fit_pt)); + } + + if (0) { + // we now undo our fixed-point arithmetic. + double delta = 0.5; + double x = p->x * .5 + delta; + double y = p->y * .5 + delta; + double W; + + for (int dy = -1; dy <= 1; dy++) { + int iy = y + dy; + + if (iy < 0 || iy + 1 >= im->height) + continue; + + for (int dx = -1; dx <= 1; dx++) { + int ix = x + dx; + + if (ix < 0 || ix + 1 >= im->width) + continue; + + int grad_x = im->buf[iy * im->stride + ix + 1] - + im->buf[iy * im->stride + ix - 1]; + + int grad_y = im->buf[(iy+1) * im->stride + ix] - + im->buf[(iy-1) * im->stride + ix]; + + W = sqrtf(grad_x*grad_x + grad_y*grad_y) + 1; + +// double fx = x + dx, fy = y + dy; + double fx = ix + .5, fy = iy + .5; + lfps[i].Mx += W * fx; + lfps[i].My += W * fy; + lfps[i].Mxx += W * fx * fx; + lfps[i].Mxy += W * fx * fy; + lfps[i].Myy += W * fy * fy; + lfps[i].W += W; + } + } + } else { + // we now undo our fixed-point arithmetic. + double delta = 0.5; // adjust for pixel center bias + double x = p->x * .5 + delta; + double y = p->y * .5 + delta; + int ix = x, iy = y; + double W = 1; + + if (ix > 0 && ix+1 < im->width && iy > 0 && iy+1 < im->height) { + int grad_x = im->buf[iy * im->stride + ix + 1] - + im->buf[iy * im->stride + ix - 1]; + + int grad_y = im->buf[(iy+1) * im->stride + ix] - + im->buf[(iy-1) * im->stride + ix]; + + // XXX Tunable. How to shape the gradient magnitude? + W = sqrt(grad_x*grad_x + grad_y*grad_y) + 1; + } + + double fx = x, fy = y; + lfps[i].Mx += W * fx; + lfps[i].My += W * fy; + lfps[i].Mxx += W * fx * fx; + lfps[i].Mxy += W * fx * fy; + lfps[i].Myy += W * fy * fy; + lfps[i].W += W; + } + } + + int indices[4]; + if (1) { + if (!quad_segment_maxima(td, cluster, lfps, indices)) + goto finish; + } + +// printf("%d %d %d %d\n", indices[0], indices[1], indices[2], indices[3]); + + if (0) { + // no refitting here; just use those points as the vertices. + // Note, this is useful for debugging, but pretty bad in + // practice since this code path also omits several + // plausibility checks that save us tons of time in quad + // decoding. + for (int i = 0; i < 4; i++) { + struct pt *p; + zarray_get_volatile(cluster, indices[i], &p); + + quad->p[i][0] = .5*p->x; // undo fixed-point arith. + quad->p[i][1] = .5*p->y; + } + + res = 1; + + } else { + double lines[4][4]; + + for (int i = 0; i < 4; i++) { + int i0 = indices[i]; + int i1 = indices[(i+1)&3]; + + if (0) { + // if there are enough points, skip the points near the corners + // (because those tend not to be very good.) + if (i1-i0 > 8) { + int t = (i1-i0)/6; + if (t < 0) + t = -t; + + i0 = (i0 + t) % sz; + i1 = (i1 + sz - t) % sz; + } + } + + double err; + fit_line(lfps, sz, i0, i1, lines[i], NULL, &err); + + if (err > td->qtp.max_line_fit_mse) { + res = 0; + goto finish; + } + } + + for (int i = 0; i < 4; i++) { + // solve for the intersection of lines (i) and (i+1)&3. + // p0 + lambda0*u0 = p1 + lambda1*u1, where u0 and u1 + // are the line directions. + // + // lambda0*u0 - lambda1*u1 = (p1 - p0) + // + // rearrange (solve for lambdas) + // + // [u0_x -u1_x ] [lambda0] = [ p1_x - p0_x ] + // [u0_y -u1_y ] [lambda1] [ p1_y - p0_y ] + // + // remember that lines[i][0,1] = p, lines[i][2,3] = NORMAL vector. + // We want the unit vector, so we need the perpendiculars. Thus, below + // we have swapped the x and y components and flipped the y components. + + double A00 = lines[i][3], A01 = -lines[(i+1)&3][3]; + double A10 = -lines[i][2], A11 = lines[(i+1)&3][2]; + double B0 = -lines[i][0] + lines[(i+1)&3][0]; + double B1 = -lines[i][1] + lines[(i+1)&3][1]; + + double det = A00 * A11 - A10 * A01; + + // inverse. + double W00 = A11 / det, W01 = -A01 / det; + if (fabs(det) < 0.001) { + res = 0; + goto finish; + } + + // solve + double L0 = W00*B0 + W01*B1; + + // compute intersection + quad->p[i][0] = lines[i][0] + L0*A00; + quad->p[i][1] = lines[i][1] + L0*A10; + + if (0) { + // we should get the same intersection starting + // from point p1 and moving L1*u1. + double W10 = -A10 / det, W11 = A00 / det; + double L1 = W10*B0 + W11*B1; + + double x = lines[(i+1)&3][0] - L1*A10; + double y = lines[(i+1)&3][1] - L1*A11; + assert(fabs(x - quad->p[i][0]) < 0.001 && + fabs(y - quad->p[i][1]) < 0.001); + } + + res = 1; + } + } + + // reject quads that are too small + if (1) { + double area = 0; + + // get area of triangle formed by points 0, 1, 2, 0 + double length[3], p; + for (int i = 0; i < 3; i++) { + int idxa = i; // 0, 1, 2, + int idxb = (i+1) % 3; // 1, 2, 0 + length[i] = sqrt(sq(quad->p[idxb][0] - quad->p[idxa][0]) + + sq(quad->p[idxb][1] - quad->p[idxa][1])); + } + p = (length[0] + length[1] + length[2]) / 2; + + area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2])); + + // get area of triangle formed by points 2, 3, 0, 2 + for (int i = 0; i < 3; i++) { + int idxs[] = { 2, 3, 0, 2 }; + int idxa = idxs[i]; + int idxb = idxs[i+1]; + length[i] = sqrt(sq(quad->p[idxb][0] - quad->p[idxa][0]) + + sq(quad->p[idxb][1] - quad->p[idxa][1])); + } + p = (length[0] + length[1] + length[2]) / 2; + + area += sqrt(p*(p-length[0])*(p-length[1])*(p-length[2])); + + // we don't actually know the family yet (quad detection is generic.) + // This threshold is based on a 6x6 tag (which is actually 8x8) +// int d = fam->d + fam->black_border*2; + int d = 8; + if (area < d*d) { + res = 0; + goto finish; + } + } + + // reject quads whose cumulative angle change isn't equal to 2PI + if (1) { + double total = 0; + + for (int i = 0; i < 4; i++) { + int i0 = i, i1 = (i+1)&3, i2 = (i+2)&3; + + double theta0 = atan2f(quad->p[i0][1] - quad->p[i1][1], + quad->p[i0][0] - quad->p[i1][0]); + double theta1 = atan2f(quad->p[i2][1] - quad->p[i1][1], + quad->p[i2][0] - quad->p[i1][0]); + + double dtheta = theta0 - theta1; + if (dtheta < 0) + dtheta += 2*M_PI; + + if (dtheta < td->qtp.critical_rad || dtheta > (M_PI - td->qtp.critical_rad)) + res = 0; + + total += dtheta; + } + + // looking for 2PI + if (total < 6.2 || total > 6.4) { + res = 0; + goto finish; + } + } + + // adjust pixel coordinates; all math up 'til now uses pixel + // coordinates in which (0,0) is the lower left corner. But each + // pixel actually spans from to [x, x+1), [y, y+1) the mean value of which + // is +.5 higher than x & y. +/* double delta = .5; + for (int i = 0; i < 4; i++) { + quad->p[i][0] += delta; + quad->p[i][1] += delta; + } +*/ + finish: + + fb_free(); // lfps + + return res; +} + +#define DO_UNIONFIND(dx, dy) if (im->buf[y*s + dy*s + x + dx] == v) unionfind_connect(uf, y*w + x, y*w + dy*w + x + dx); + +static void do_unionfind_line(unionfind_t *uf, image_u8_t *im, int h, int w, int s, int y) +{ + assert(y+1 < im->height); + + for (int x = 1; x < w - 1; x++) { + uint8_t v = im->buf[y*s + x]; + + if (v == 127) + continue; + + // (dx,dy) pairs for 8 connectivity: + // (REFERENCE) (1, 0) + // (-1, 1) (0, 1) (1, 1) + // + DO_UNIONFIND(1, 0); + DO_UNIONFIND(0, 1); + if (v == 255) { + DO_UNIONFIND(-1, 1); + DO_UNIONFIND(1, 1); + } + } +} +#undef DO_UNIONFIND + +image_u8_t *threshold(apriltag_detector_t *td, image_u8_t *im) +{ + int w = im->width, h = im->height, s = im->stride; + assert(w < 32768); + assert(h < 32768); + + image_u8_t *threshim = fb_alloc(sizeof(image_u8_t)); + threshim->width = w; + threshim->height = h; + threshim->stride = s; + threshim->buf = fb_alloc(w * h); + assert(threshim->stride == s); + + // The idea is to find the maximum and minimum values in a + // window around each pixel. If it's a contrast-free region + // (max-min is small), don't try to binarize. Otherwise, + // threshold according to (max+min)/2. + // + // Mark low-contrast regions with value 127 so that we can skip + // future work on these areas too. + + // however, computing max/min around every pixel is needlessly + // expensive. We compute max/min for tiles. To avoid artifacts + // that arise when high-contrast features appear near a tile + // edge (and thus moving from one tile to another results in a + // large change in max/min value), the max/min values used for + // any pixel are computed from all 3x3 surrounding tiles. Thus, + // the max/min sampling area for nearby pixels overlap by at least + // one tile. + // + // The important thing is that the windows be large enough to + // capture edge transitions; the tag does not need to fit into + // a tile. + + // XXX Tunable. Generally, small tile sizes--- so long as they're + // large enough to span a single tag edge--- seem to be a winner. + const int tilesz = 4; + + // the last (possibly partial) tiles along each row and column will + // just use the min/max value from the last full tile. + int tw = w / tilesz; + int th = h / tilesz; + + uint8_t *im_max = fb_alloc(tw*th*sizeof(uint8_t)); + uint8_t *im_min = fb_alloc(tw*th*sizeof(uint8_t)); + + // first, collect min/max statistics for each tile + for (int ty = 0; ty < th; ty++) { + for (int tx = 0; tx < tw; tx++) { + uint8_t max = 0, min = 255; + + for (int dy = 0; dy < tilesz; dy++) { + + for (int dx = 0; dx < tilesz; dx++) { + + uint8_t v = im->buf[(ty*tilesz+dy)*s + tx*tilesz + dx]; + if (v < min) + min = v; + if (v > max) + max = v; + } + } + + im_max[ty*tw+tx] = max; + im_min[ty*tw+tx] = min; + } + } + + // second, apply 3x3 max/min convolution to "blur" these values + // over larger areas. This reduces artifacts due to abrupt changes + // in the threshold value. + if (1) { + uint8_t *im_max_tmp = fb_alloc(tw*th*sizeof(uint8_t)); + uint8_t *im_min_tmp = fb_alloc(tw*th*sizeof(uint8_t)); + + for (int ty = 0; ty < th; ty++) { + for (int tx = 0; tx < tw; tx++) { + uint8_t max = 0, min = 255; + + for (int dy = -1; dy <= 1; dy++) { + if (ty+dy < 0 || ty+dy >= th) + continue; + for (int dx = -1; dx <= 1; dx++) { + if (tx+dx < 0 || tx+dx >= tw) + continue; + + uint8_t m = im_max[(ty+dy)*tw+tx+dx]; + if (m > max) + max = m; + m = im_min[(ty+dy)*tw+tx+dx]; + if (m < min) + min = m; + } + } + + im_max_tmp[ty*tw + tx] = max; + im_min_tmp[ty*tw + tx] = min; + } + } + memcpy(im_max, im_max_tmp, tw*th*sizeof(uint8_t)); + memcpy(im_min, im_min_tmp, tw*th*sizeof(uint8_t)); + fb_free(); // im_min_tmp + fb_free(); // im_max_tmp + } + + for (int ty = 0; ty < th; ty++) { + for (int tx = 0; tx < tw; tx++) { + + int min = im_min[ty*tw + tx]; + int max = im_max[ty*tw + tx]; + + // low contrast region? (no edges) + if (max - min < td->qtp.min_white_black_diff) { + for (int dy = 0; dy < tilesz; dy++) { + int y = ty*tilesz + dy; + + for (int dx = 0; dx < tilesz; dx++) { + int x = tx*tilesz + dx; + + threshim->buf[y*s+x] = 127; + } + } + continue; + } + + // otherwise, actually threshold this tile. + + // argument for biasing towards dark; specular highlights + // can be substantially brighter than white tag parts + uint8_t thresh = min + (max - min) / 2; + + for (int dy = 0; dy < tilesz; dy++) { + int y = ty*tilesz + dy; + + for (int dx = 0; dx < tilesz; dx++) { + int x = tx*tilesz + dx; + + uint8_t v = im->buf[y*s+x]; + if (v > thresh) + threshim->buf[y*s+x] = 255; + else + threshim->buf[y*s+x] = 0; + } + } + } + } + + // we skipped over the non-full-sized tiles above. Fix those now. + if (1) { + for (int y = 0; y < h; y++) { + + // what is the first x coordinate we need to process in this row? + + int x0; + + if (y >= th*tilesz) { + x0 = 0; // we're at the bottom; do the whole row. + } else { + x0 = tw*tilesz; // we only need to do the right most part. + } + + // compute tile coordinates and clamp. + int ty = y / tilesz; + if (ty >= th) + ty = th - 1; + + for (int x = x0; x < w; x++) { + int tx = x / tilesz; + if (tx >= tw) + tx = tw - 1; + + int max = im_max[ty*tw + tx]; + int min = im_min[ty*tw + tx]; + int thresh = min + (max - min) / 2; + + uint8_t v = im->buf[y*s+x]; + if (v > thresh) + threshim->buf[y*s+x] = 255; + else + threshim->buf[y*s+x] = 0; + } + } + } + + fb_free(); // im_min + fb_free(); // im_max + + // this is a dilate/erode deglitching scheme that does not improve + // anything as far as I can tell. + if (0 || td->qtp.deglitch) { + image_u8_t *tmp = fb_alloc(sizeof(image_u8_t)); + tmp->width = w; + tmp->height = h; + tmp->stride = s; + tmp->buf = fb_alloc(w * h); + + for (int y = 1; y + 1 < h; y++) { + for (int x = 1; x + 1 < w; x++) { + uint8_t max = 0; + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + uint8_t v = threshim->buf[(y+dy)*s + x + dx]; + if (v > max) + max = v; + } + } + tmp->buf[y*s+x] = max; + } + } + + for (int y = 1; y + 1 < h; y++) { + for (int x = 1; x + 1 < w; x++) { + uint8_t min = 255; + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) { + uint8_t v = tmp->buf[(y+dy)*s + x + dx]; + if (v < min) + min = v; + } + } + threshim->buf[y*s+x] = min; + } + } + + fb_free(); // tmp->buf + fb_free(); // tmp + } + + return threshim; +} + +zarray_t *apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im, bool overrideMode) +{ + //////////////////////////////////////////////////////// + // step 1. threshold the image, creating the edge image. + + int w = im->width, h = im->height; + + image_u8_t *threshim = threshold(td, im); + int ts = threshim->stride; + + //////////////////////////////////////////////////////// + // step 2. find connected components. + + unionfind_t *uf = unionfind_create(w * h); + + for (int y = 0; y < h - 1; y++) { + do_unionfind_line(uf, threshim, h, w, ts, y); + } + + uint32_t nclustermap; + struct uint32_zarray_entry **clustermap = fb_alloc0_all(&nclustermap); + nclustermap /= sizeof(struct uint32_zarray_entry*); + if (!nclustermap) fb_alloc_fail(); + + for (int y = 1; y < h-1; y++) { + for (int x = 1; x < w-1; x++) { + + uint8_t v0 = threshim->buf[y*ts + x]; + if (v0 == 127) + continue; + + // XXX don't query this until we know we need it? + uint32_t rep0 = unionfind_get_representative(uf, y*w + x); + + // whenever we find two adjacent pixels such that one is + // white and the other black, we add the point half-way + // between them to a cluster associated with the unique + // ids of the white and black regions. + // + // We additionally compute the gradient direction (i.e., which + // direction was the white pixel?) Note: if (v1-v0) == 255, then + // (dx,dy) points towards the white pixel. if (v1-v0) == -255, then + // (dx,dy) points towards the black pixel. p.gx and p.gy will thus + // be -255, 0, or 255. + // + // Note that any given pixel might be added to multiple + // different clusters. But in the common case, a given + // pixel will be added multiple times to the same cluster, + // which increases the size of the cluster and thus the + // computational costs. + // + // A possible optimization would be to combine entries + // within the same cluster. + +#define DO_CONN(dx, dy) \ + if (1) { \ + uint8_t v1 = threshim->buf[y*ts + dy*ts + x + dx]; \ + \ + while (v0 + v1 == 255) { \ + uint32_t rep1 = unionfind_get_representative(uf, y*w + dy*w + x + dx); \ + uint32_t clusterid; \ + if (rep0 < rep1) \ + clusterid = (rep1 << 16) + rep0; \ + else \ + clusterid = (rep0 << 16) + rep1; \ + \ + /* XXX lousy hash function */ \ + uint32_t clustermap_bucket = u64hash_2(clusterid) % nclustermap; \ + struct uint32_zarray_entry *entry = clustermap[clustermap_bucket]; \ + while (entry && entry->id != clusterid) { \ + entry = entry->next; \ + } \ + \ + if (!entry) { \ + entry = umm_calloc(1, sizeof(struct uint32_zarray_entry)); \ + if (!entry) break; \ + entry->id = clusterid; \ + entry->cluster = zarray_create_fail_ok(sizeof(struct pt)); \ + if (!entry->cluster) { \ + free(entry); \ + break; \ + } \ + entry->next = clustermap[clustermap_bucket]; \ + clustermap[clustermap_bucket] = entry; \ + } \ + \ + struct pt p = { .x = 2*x + dx, .y = 2*y + dy, .gx = dx*((int) v1-v0), .gy = dy*((int) v1-v0)}; \ + zarray_add_fail_ok(entry->cluster, &p); \ + break; \ + } \ + } + + // do 4 connectivity. NB: Arguments must be [-1, 1] or we'll overflow .gx, .gy + DO_CONN(1, 0); + DO_CONN(0, 1); + + // do 8 connectivity + // DO_CONN(-1, 1); + // DO_CONN(1, 1); + } + } +#undef DO_CONN + + //////////////////////////////////////////////////////// + // step 3. process each connected component. + zarray_t *clusters = zarray_create_fail_ok(sizeof(zarray_t*)); //, uint32_zarray_hash_size(clustermap)); + if (clusters) { + for (int i = 0; i < nclustermap; i++) { + + for (struct uint32_zarray_entry *entry = clustermap[i]; entry; entry = entry->next) { + // XXX reject clusters here? + zarray_add_fail_ok(clusters, &entry->cluster); + } + } + } + + + int sz = clusters ? zarray_size(clusters) : 0; + + if (1) { + for (int i = 0; i < nclustermap; i++) { + struct uint32_zarray_entry *entry = clustermap[i]; + while (entry) { + // free any leaked cluster (zarray_add_fail_ok) + bool leaked = true; + for (int j = 0; j < sz; j++) { + zarray_t *cluster; + zarray_get(clusters, j, &cluster); + leaked &= entry->cluster != cluster; + } + if (leaked) free(entry->cluster); + struct uint32_zarray_entry *tmp = entry->next; + free(entry); + entry = tmp; + } + } + fb_free(); // clustermap + } + + unionfind_destroy(); + + fb_free(); // threshim->buf + fb_free(); // threshim + + zarray_t *quads = zarray_create_fail_ok(sizeof(struct quad)); + + if (quads) { + for (int i = 0; i < sz; i++) { + + zarray_t *cluster; + zarray_get(clusters, i, &cluster); + + if (zarray_size(cluster) < td->qtp.min_cluster_pixels) + continue; + + // a cluster should contain only boundary points around the + // tag. it cannot be bigger than the whole screen. (Reject + // large connected blobs that will be prohibitively slow to + // fit quads to.) A typical point along an edge is added three + // times (because it has 3 neighbors). The maximum perimeter + // is 2w+2h. + if (zarray_size(cluster) > 3*(2*w+2*h)) { + continue; + } + + struct quad quad; + memset(&quad, 0, sizeof(struct quad)); + + if (fit_quad(td, im, cluster, &quad, overrideMode)) { + + zarray_add_fail_ok(quads, &quad); + } + } + } + + // printf(" %d %d %d %d\n", indices[0], indices[1], indices[2], indices[3]); + + for (int i = 0; i < sz; i++) { + zarray_t *cluster; + zarray_get(clusters, i, &cluster); + zarray_destroy(cluster); + } + + if (clusters) zarray_destroy(clusters); + + + if (!quads) { + // we should have enough memory now + quads = zarray_create(sizeof(struct quad)); + } + return quads; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "apriltag.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef M_PI +# define M_PI 3.141592653589793238462643383279502884196 +#endif + +// Regresses a model of the form: +// intensity(x,y) = C0*x + C1*y + CC2 +// The J matrix is the: +// J = [ x1 y1 1 ] +// [ x2 y2 1 ] +// [ ... ] +// The A matrix is J'J + +struct graymodel +{ + double A[3][3]; + double B[3]; + double C[3]; +}; + +void graymodel_init(struct graymodel *gm) +{ + memset(gm, 0, sizeof(struct graymodel)); +} + +void graymodel_add(struct graymodel *gm, double x, double y, double gray) +{ + // update upper right entries of A = J'J + gm->A[0][0] += x*x; + gm->A[0][1] += x*y; + gm->A[0][2] += x; + gm->A[1][1] += y*y; + gm->A[1][2] += y; + gm->A[2][2] += 1; + + // update B = J'gray + gm->B[0] += x * gray; + gm->B[1] += y * gray; + gm->B[2] += gray; +} + +void graymodel_solve(struct graymodel *gm) +{ + mat33_sym_solve((double*) gm->A, gm->B, gm->C); +} + +double graymodel_interpolate(struct graymodel *gm, double x, double y) +{ + return gm->C[0]*x + gm->C[1]*y + gm->C[2]; +} + +struct quick_decode_entry +{ + uint64_t rcode; // the queried code + uint16_t id; // the tag ID (a small integer) + uint8_t hamming; // how many errors corrected? + uint8_t rotation; // number of rotations [0, 3] +}; + +struct quick_decode +{ + int nentries; + struct quick_decode_entry *entries; +}; + +/** if the bits in w were arranged in a d*d grid and that grid was + * rotated, what would the new bits in w be? + * The bits are organized like this (for d = 3): + * + * 8 7 6 2 5 8 0 1 2 + * 5 4 3 ==> 1 4 7 ==> 3 4 5 (rotate90 applied twice) + * 2 1 0 0 3 6 6 7 8 + **/ +static uint64_t rotate90(uint64_t w, uint32_t d) +{ + uint64_t wr = 0; + + for (int32_t r = d-1; r >=0; r--) { + for (int32_t c = 0; c < d; c++) { + int32_t b = r + d*c; + + wr = wr << 1; + + if ((w & (((uint64_t) 1) << b))!=0) + wr |= 1; + } + } + + return wr; +} + +void quad_destroy(struct quad *quad) +{ + if (!quad) + return; + + matd_destroy(quad->H); + matd_destroy(quad->Hinv); + free(quad); +} + +struct quad *quad_copy(struct quad *quad) +{ + struct quad *q = calloc(1, sizeof(struct quad)); + memcpy(q, quad, sizeof(struct quad)); + if (quad->H) + q->H = matd_copy(quad->H); + if (quad->Hinv) + q->Hinv = matd_copy(quad->Hinv); + return q; +} + +// http://en.wikipedia.org/wiki/Hamming_weight + +//types and constants used in the functions below +//uint64_t is an unsigned 64-bit integer variable type (defined in C99 version of C language) +const uint64_t m1 = 0x5555555555555555; //binary: 0101... +const uint64_t m2 = 0x3333333333333333; //binary: 00110011.. +const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ... +const uint64_t m8 = 0x00ff00ff00ff00ff; //binary: 8 zeros, 8 ones ... +const uint64_t m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ... +const uint64_t m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones +const uint64_t hff = 0xffffffffffffffff; //binary: all ones +const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3... + +//This is a naive implementation, shown for comparison, +//and to help in understanding the better functions. +//This algorithm uses 24 arithmetic operations (shift, add, and). +int popcount64a(uint64_t x) +{ + x = (x & m1 ) + ((x >> 1) & m1 ); //put count of each 2 bits into those 2 bits + x = (x & m2 ) + ((x >> 2) & m2 ); //put count of each 4 bits into those 4 bits + x = (x & m4 ) + ((x >> 4) & m4 ); //put count of each 8 bits into those 8 bits + x = (x & m8 ) + ((x >> 8) & m8 ); //put count of each 16 bits into those 16 bits + x = (x & m16) + ((x >> 16) & m16); //put count of each 32 bits into those 32 bits + x = (x & m32) + ((x >> 32) & m32); //put count of each 64 bits into those 64 bits + return x; +} + +//This uses fewer arithmetic operations than any other known +//implementation on machines with slow multiplication. +//This algorithm uses 17 arithmetic operations. +int popcount64b(uint64_t x) +{ + x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits + x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits + x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits + x += x >> 8; //put count of each 16 bits into their lowest 8 bits + x += x >> 16; //put count of each 32 bits into their lowest 8 bits + x += x >> 32; //put count of each 64 bits into their lowest 8 bits + return x & 0x7f; +} + +//This uses fewer arithmetic operations than any other known +//implementation on machines with fast multiplication. +//This algorithm uses 12 arithmetic operations, one of which is a multiply. +int popcount64c(uint64_t x) +{ + x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits + x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits + x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits + return (x * h01) >> 56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... +} + +// returns an entry with hamming set to 255 if no decode was found. +static void quick_decode_codeword(apriltag_family_t *tf, uint64_t rcode, + struct quick_decode_entry *entry) +{ + int threshold = imax(tf->h - tf->d - 1, 0); + + for (int ridx = 0; ridx < 4; ridx++) { + + for (int i = 0, j = tf->ncodes; i < j; i++) { + int hamming = popcount64c(tf->codes[i] ^ rcode); + if(hamming <= threshold) { + entry->rcode = rcode; + entry->id = i; + entry->hamming = hamming; + entry->rotation = ridx; + return; + } + } + + rcode = rotate90(rcode, tf->d); + } + + entry->rcode = 0; + entry->id = 65535; + entry->hamming = 255; + entry->rotation = 0; +} + +static inline int detection_compare_function(const void *_a, const void *_b) +{ + apriltag_detection_t *a = *(apriltag_detection_t**) _a; + apriltag_detection_t *b = *(apriltag_detection_t**) _b; + + return a->id - b->id; +} + +void apriltag_detector_remove_family(apriltag_detector_t *td, apriltag_family_t *fam) +{ + zarray_remove_value(td->tag_families, &fam, 0); +} + +void apriltag_detector_add_family_bits(apriltag_detector_t *td, apriltag_family_t *fam, int bits_corrected) +{ + zarray_add(td->tag_families, &fam); +} + +void apriltag_detector_clear_families(apriltag_detector_t *td) +{ + zarray_clear(td->tag_families); +} + +apriltag_detector_t *apriltag_detector_create() +{ + apriltag_detector_t *td = (apriltag_detector_t*) calloc(1, sizeof(apriltag_detector_t)); + + td->qtp.max_nmaxima = 10; + td->qtp.min_cluster_pixels = 5; + + td->qtp.max_line_fit_mse = 10.0; + td->qtp.critical_rad = 10 * M_PI / 180; + td->qtp.deglitch = 0; + td->qtp.min_white_black_diff = 5; + + td->tag_families = zarray_create(sizeof(apriltag_family_t*)); + + td->refine_edges = 1; + td->refine_pose = 0; + td->refine_decode = 0; + + return td; +} + +void apriltag_detector_destroy(apriltag_detector_t *td) +{ + apriltag_detector_clear_families(td); + + zarray_destroy(td->tag_families); + free(td); +} + +struct evaluate_quad_ret +{ + int64_t rcode; + double score; + matd_t *H, *Hinv; + + int decode_status; + struct quick_decode_entry e; +}; + +// returns non-zero if an error occurs (i.e., H has no inverse) +int quad_update_homographies(struct quad *quad) +{ + zarray_t *correspondences = zarray_create(sizeof(float[4])); + + for (int i = 0; i < 4; i++) { + float corr[4]; + + // At this stage of the pipeline, we have not attempted to decode the + // quad into an oriented tag. Thus, just act as if the quad is facing + // "up" with respect to our desired corners. We'll fix the rotation + // later. + // [-1, -1], [1, -1], [1, 1], [-1, 1] + corr[0] = (i==0 || i==3) ? -1 : 1; + corr[1] = (i==0 || i==1) ? -1 : 1; + + corr[2] = quad->p[i][0]; + corr[3] = quad->p[i][1]; + + zarray_add(correspondences, &corr); + } + + if (quad->H) + matd_destroy(quad->H); + if (quad->Hinv) + matd_destroy(quad->Hinv); + + // XXX Tunable + quad->H = homography_compute(correspondences, HOMOGRAPHY_COMPUTE_FLAG_SVD); + quad->Hinv = matd_inverse(quad->H); + zarray_destroy(correspondences); + + if (quad->H && quad->Hinv) + return 0; + + return -1; +} + +// compute a "score" for a quad that is independent of tag family +// encoding (but dependent upon the tag geometry) by considering the +// contrast around the exterior of the tag. +double quad_goodness(apriltag_family_t *family, image_u8_t *im, struct quad *quad) +{ + // when sampling from the white border, how much white border do + // we actually consider valid, measured in bit-cell units? (the + // outside portions are often intruded upon, so it could be advantageous to use + // less than the "nominal" 1.0. (Less than 1.0 not well tested.) + + // XXX Tunable + float white_border = 1; + + // in tag coordinates, how big is each bit cell? + double bit_size = 2.0 / (2*family->black_border + family->d); +// double inv_bit_size = 1.0 / bit_size; + + int32_t xmin = INT32_MAX, xmax = 0, ymin = INT32_MAX, ymax = 0; + + for (int i = 0; i < 4; i++) { + double tx = (i == 0 || i == 3) ? -1 - bit_size : 1 + bit_size; + double ty = (i == 0 || i == 1) ? -1 - bit_size : 1 + bit_size; + double x, y; + + homography_project(quad->H, tx, ty, &x, &y); + xmin = imin(xmin, x); + xmax = imax(xmax, x); + ymin = imin(ymin, y); + ymax = imax(ymax, y); + } + + // clamp bounding box to image dimensions + xmin = imax(0, xmin); + xmax = imin(im->width-1, xmax); + ymin = imax(0, ymin); + ymax = imin(im->height-1, ymax); + +// int nbits = family->d * family->d; + + int32_t W1 = 0, B1 = 0, Wn = 0, Bn = 0; // int64_t W1 = 0, B1 = 0, Wn = 0, Bn = 0; + + float wsz = bit_size*white_border; + float bsz = bit_size*family->black_border; + + matd_t *Hinv = quad->Hinv; +// matd_t *H = quad->H; + + // iterate over all the pixels in the tag. (Iterating in pixel space) + for (int y = ymin; y <= ymax; y++) { + + // we'll incrementally compute the homography + // projections. Begin by evaluating the homogeneous position + // [(xmin - .5f), y, 1]. Then, we'll update as we stride in + // the +x direction. + double Hx = MATD_EL(Hinv, 0, 0) * (.5 + (int) xmin) + + MATD_EL(Hinv, 0, 1) * (y + .5) + MATD_EL(Hinv, 0, 2); + double Hy = MATD_EL(Hinv, 1, 0) * (.5 + (int) xmin) + + MATD_EL(Hinv, 1, 1) * (y + .5) + MATD_EL(Hinv, 1, 2); + double Hh = MATD_EL(Hinv, 2, 0) * (.5 + (int) xmin) + + MATD_EL(Hinv, 2, 1) * (y + .5) + MATD_EL(Hinv, 2, 2); + + for (int x = xmin; x <= xmax; x++) { + // project the pixel center. + double tx, ty; + + // divide by homogeneous coordinate + tx = Hx / Hh; + ty = Hy / Hh; + + // if we move x one pixel to the right, here's what + // happens to our three pre-normalized coordinates. + Hx += MATD_EL(Hinv, 0, 0); + Hy += MATD_EL(Hinv, 1, 0); + Hh += MATD_EL(Hinv, 2, 0); + + float txa = fabsf((float) tx), tya = fabsf((float) ty); + float xymax = fmaxf(txa, tya); + +// if (txa >= 1 + wsz || tya >= 1 + wsz) + if (xymax >= 1 + wsz) + continue; + + uint8_t v = im->buf[y*im->stride + x]; + + // it's within the white border? +// if (txa >= 1 || tya >= 1) { + if (xymax >= 1) { + W1 += v; + Wn ++; + continue; + } + + // it's within the black border? +// if (txa >= 1 - bsz || tya >= 1 - bsz) { + if (xymax >= 1 - bsz) { + B1 += v; + Bn ++; + continue; + } + + // it must be a data bit. We don't do anything with these. + continue; + } + } + + + // score = average margin between white and black pixels near border. + double margin = 1.0 * W1 / Wn - 1.0 * B1 / Bn; +// printf("margin %f: W1 %f, B1 %f\n", margin, W1, B1); + + return margin; +} + +// returns the decision margin. Return < 0 if the detection should be rejected. +float quad_decode(apriltag_family_t *family, image_u8_t *im, struct quad *quad, struct quick_decode_entry *entry, image_u8_t *im_samples) +{ + // decode the tag binary contents by sampling the pixel + // closest to the center of each bit cell. + + int64_t rcode = 0; + + // how wide do we assume the white border is? + float white_border = 1.0; + + // We will compute a threshold by sampling known white/black cells around this tag. + // This sampling is achieved by considering a set of samples along lines. + // + // coordinates are given in bit coordinates. ([0, fam->d]). + // + // { initial x, initial y, delta x, delta y, WHITE=1 } + float patterns[] = { + // left white column + 0 - white_border / 2.0, 0.5, + 0, 1, + 1, + + // left black column + 0 + family->black_border / 2.0, 0.5, + 0, 1, + 0, + + // right white column + 2*family->black_border + family->d + white_border / 2.0, .5, + 0, 1, + 1, + + // right black column + 2*family->black_border + family->d - family->black_border / 2.0, .5, + 0, 1, + 0, + + // top white row + 0.5, -white_border / 2.0, + 1, 0, + 1, + + // top black row + 0.5, family->black_border / 2.0, + 1, 0, + 0, + + // bottom white row + 0.5, 2*family->black_border + family->d + white_border / 2.0, + 1, 0, + 1, + + // bottom black row + 0.5, 2*family->black_border + family->d - family->black_border / 2.0, + 1, 0, + 0 + + // XXX double-counts the corners. + }; + + struct graymodel whitemodel, blackmodel; + graymodel_init(&whitemodel); + graymodel_init(&blackmodel); + + for (int pattern_idx = 0; pattern_idx < sizeof(patterns)/(5*sizeof(float)); pattern_idx ++) { + float *pattern = &patterns[pattern_idx * 5]; + + int is_white = pattern[4]; + + for (int i = 0; i < 2*family->black_border + family->d; i++) { + double tagx01 = (pattern[0] + i*pattern[2]) / (2*family->black_border + family->d); + double tagy01 = (pattern[1] + i*pattern[3]) / (2*family->black_border + family->d); + + double tagx = 2*(tagx01-0.5); + double tagy = 2*(tagy01-0.5); + + double px, py; + homography_project(quad->H, tagx, tagy, &px, &py); + + // don't round + int ix = px; + int iy = py; + if (ix < 0 || iy < 0 || ix >= im->width || iy >= im->height) + continue; + + int v = im->buf[iy*im->stride + ix]; + + if (im_samples) { + im_samples->buf[iy*im_samples->stride + ix] = (1-is_white)*255; + } + + if (is_white) + graymodel_add(&whitemodel, tagx, tagy, v); + else + graymodel_add(&blackmodel, tagx, tagy, v); + } + } + + graymodel_solve(&whitemodel); + graymodel_solve(&blackmodel); + + // XXX Tunable + if (graymodel_interpolate(&whitemodel, 0, 0) - graymodel_interpolate(&blackmodel, 0, 0) < 0) + return -1; + + // compute the average decision margin (how far was each bit from + // the decision boundary? + // + // we score this separately for white and black pixels and return + // the minimum average threshold for black/white pixels. This is + // to penalize thresholds that are too close to an extreme. + float black_score = 0, white_score = 0; + float black_score_count = 1, white_score_count = 1; + + for (int bitidx = 0; bitidx < family->d * family->d; bitidx++) { + int bitx = bitidx % family->d; + int bity = bitidx / family->d; + + double tagx01 = (family->black_border + bitx + 0.5) / (2*family->black_border + family->d); + double tagy01 = (family->black_border + bity + 0.5) / (2*family->black_border + family->d); + + // scale to [-1, 1] + double tagx = 2*(tagx01-0.5); + double tagy = 2*(tagy01-0.5); + + double px, py; + homography_project(quad->H, tagx, tagy, &px, &py); + + rcode = (rcode << 1); + + // don't round. + int ix = px; + int iy = py; + + if (ix < 0 || iy < 0 || ix >= im->width || iy >= im->height) + continue; + + int v = im->buf[iy*im->stride + ix]; + + double thresh = (graymodel_interpolate(&blackmodel, tagx, tagy) + graymodel_interpolate(&whitemodel, tagx, tagy)) / 2.0; + if (v > thresh) { + white_score += (v - thresh); + white_score_count ++; + rcode |= 1; + } else { + black_score += (thresh - v); + black_score_count ++; + } + + if (im_samples) + im_samples->buf[iy*im_samples->stride + ix] = (1 - (rcode & 1)) * 255; + } + + quick_decode_codeword(family, rcode, entry); + + return fmin(white_score / white_score_count, black_score / black_score_count); +} + +double score_goodness(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user) +{ + return quad_goodness(family, im, quad); +} + +double score_decodability(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user) +{ + struct quick_decode_entry entry; + + float decision_margin = quad_decode(family, im, quad, &entry, NULL); + + // hamming trumps decision margin; maximum value for decision_margin is 255. + return decision_margin - entry.hamming*1000; +} + +// returns score of best quad +double optimize_quad_generic(apriltag_family_t *family, image_u8_t *im, struct quad *quad0, + float *stepsizes, int nstepsizes, + double (*score)(apriltag_family_t *family, image_u8_t *im, struct quad *quad, void *user), + void *user) +{ + struct quad *best_quad = quad_copy(quad0); + double best_score = score(family, im, best_quad, user); + + for (int stepsize_idx = 0; stepsize_idx < nstepsizes; stepsize_idx++) { + + int improved = 1; + + // when we make progress with a particular step size, how many + // times will we try to perform that same step size again? + // (max_repeat = 0 means ("don't repeat--- just move to the + // next step size"). + // XXX Tunable + int max_repeat = 1; + + for (int repeat = 0; repeat <= max_repeat && improved; repeat++) { + + improved = 0; + + // wiggle point i + for (int i = 0; i < 4; i++) { + + float stepsize = stepsizes[stepsize_idx]; + + // XXX Tunable (really 1 makes the best sense since) + int nsteps = 1; + + struct quad *this_best_quad = NULL; + double this_best_score = best_score; + + for (int sx = -nsteps; sx <= nsteps; sx++) { + for (int sy = -nsteps; sy <= nsteps; sy++) { + if (sx==0 && sy==0) + continue; + + struct quad *this_quad = quad_copy(best_quad); + this_quad->p[i][0] = best_quad->p[i][0] + sx*stepsize; + this_quad->p[i][1] = best_quad->p[i][1] + sy*stepsize; + if (quad_update_homographies(this_quad)) + continue; + + double this_score = score(family, im, this_quad, user); + + if (this_score > this_best_score) { + quad_destroy(this_best_quad); + + this_best_quad = this_quad; + this_best_score = this_score; + } else { + quad_destroy(this_quad); + } + } + } + + if (this_best_score > best_score) { + quad_destroy(best_quad); + best_quad = this_best_quad; + best_score = this_best_score; + improved = 1; + } + } + } + } + + matd_destroy(quad0->H); + matd_destroy(quad0->Hinv); + memcpy(quad0, best_quad, sizeof(struct quad)); // copy pointers + free(best_quad); + return best_score; +} + +static void refine_edges(apriltag_detector_t *td, image_u8_t *im_orig, struct quad *quad) +{ + double lines[4][4]; // for each line, [Ex Ey nx ny] + + for (int edge = 0; edge < 4; edge++) { + int a = edge, b = (edge + 1) & 3; // indices of the end points. + + // compute the normal to the current line estimate + double nx = quad->p[b][1] - quad->p[a][1]; + double ny = -quad->p[b][0] + quad->p[a][0]; + double mag = sqrt(nx*nx + ny*ny); + nx /= mag; + ny /= mag; + + // we will now fit a NEW line by sampling points near + // our original line that have large gradients. On really big tags, + // we're willing to sample more to get an even better estimate. + int nsamples = imax(16, mag / 8); // XXX tunable + + // stats for fitting a line... + double Mx = 0, My = 0, Mxx = 0, Mxy = 0, Myy = 0, N = 0; + + for (int s = 0; s < nsamples; s++) { + // compute a point along the line... Note, we're avoiding + // sampling *right* at the corners, since those points are + // the least reliable. + double alpha = (1.0 + s) / (nsamples + 1); + double x0 = alpha*quad->p[a][0] + (1-alpha)*quad->p[b][0]; + double y0 = alpha*quad->p[a][1] + (1-alpha)*quad->p[b][1]; + + // search along the normal to this line, looking at the + // gradients along the way. We're looking for a strong + // response. + double Mn = 0; + double Mcount = 0; + + // XXX tunable: how far to search? We want to search far + // enough that we find the best edge, but not so far that + // we hit other edges that aren't part of the tag. We + // shouldn't ever have to search more than quad_decimate, + // since otherwise we would (ideally) have started our + // search on another pixel in the first place. Likewise, + // for very small tags, we don't want the range to be too + // big. + double range = 1.0 + 1; + + // XXX tunable step size. + for (double n = -range; n <= range; n += 0.25) { + // Because of the guaranteed winding order of the + // points in the quad, we will start inside the white + // portion of the quad and work our way outward. + // + // sample to points (x1,y1) and (x2,y2) XXX tunable: + // how far +/- to look? Small values compute the + // gradient more precisely, but are more sensitive to + // noise. + double grange = 1; + int x1 = x0 + (n + grange)*nx; + int y1 = y0 + (n + grange)*ny; + if (x1 < 0 || x1 >= im_orig->width || y1 < 0 || y1 >= im_orig->height) + continue; + + int x2 = x0 + (n - grange)*nx; + int y2 = y0 + (n - grange)*ny; + if (x2 < 0 || x2 >= im_orig->width || y2 < 0 || y2 >= im_orig->height) + continue; + + int g1 = im_orig->buf[y1*im_orig->stride + x1]; + int g2 = im_orig->buf[y2*im_orig->stride + x2]; + + if (g1 < g2) // reject points whose gradient is "backwards". They can only hurt us. + continue; + + double weight = (g2 - g1)*(g2 - g1); // XXX tunable. What shape for weight=f(g2-g1)? + + // compute weighted average of the gradient at this point. + Mn += weight*n; + Mcount += weight; + } + + // what was the average point along the line? + if (Mcount == 0) + continue; + + double n0 = Mn / Mcount; + + // where is the point along the line? + double bestx = x0 + n0*nx; + double besty = y0 + n0*ny; + + // update our line fit statistics + Mx += bestx; + My += besty; + Mxx += bestx*bestx; + Mxy += bestx*besty; + Myy += besty*besty; + N++; + } + + // fit a line + double Ex = Mx / N, Ey = My / N; + double Cxx = Mxx / N - Ex*Ex; + double Cxy = Mxy / N - Ex*Ey; + double Cyy = Myy / N - Ey*Ey; + + double normal_theta = .5 * atan2f(-2*Cxy, (Cyy - Cxx)); + nx = cosf(normal_theta); + ny = sinf(normal_theta); + lines[edge][0] = Ex; + lines[edge][1] = Ey; + lines[edge][2] = nx; + lines[edge][3] = ny; + } + + // now refit the corners of the quad + for (int i = 0; i < 4; i++) { + + // solve for the intersection of lines (i) and (i+1)&3. + double A00 = lines[i][3], A01 = -lines[(i+1)&3][3]; + double A10 = -lines[i][2], A11 = lines[(i+1)&3][2]; + double B0 = -lines[i][0] + lines[(i+1)&3][0]; + double B1 = -lines[i][1] + lines[(i+1)&3][1]; + + double det = A00 * A11 - A10 * A01; + + // inverse. + if (fabs(det) > 0.001) { + // solve + double W00 = A11 / det, W01 = -A01 / det; + + double L0 = W00*B0 + W01*B1; + + // compute intersection + quad->p[i][0] = lines[i][0] + L0*A00; + quad->p[i][1] = lines[i][1] + L0*A10; + } else { + // this is a bad sign. We'll just keep the corner we had. +// printf("bad det: %15f %15f %15f %15f %15f\n", A00, A11, A10, A01, det); + } + } +} + +void apriltag_detection_destroy(apriltag_detection_t *det) +{ + if (det == NULL) + return; + + matd_destroy(det->H); + free(det); +} + +int prefer_smaller(int pref, double q0, double q1) +{ + if (pref) // already prefer something? exit. + return pref; + + if (q0 < q1) + return -1; // we now prefer q0 + if (q1 < q0) + return 1; // we now prefer q1 + + // no preference + return 0; +} + +zarray_t *apriltag_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig) +{ + if (zarray_size(td->tag_families) == 0) { + zarray_t *s = zarray_create(sizeof(apriltag_detection_t*)); + printf("apriltag.c: No tag families enabled."); + return s; + } + + /////////////////////////////////////////////////////////// + // Step 1. Detect quads according to requested image decimation + // and blurring parameters. + +// zarray_t *quads = apriltag_quad_gradient(td, im_orig); + zarray_t *quads = apriltag_quad_thresh(td, im_orig, false); + + zarray_t *detections = zarray_create(sizeof(apriltag_detection_t*)); + + td->nquads = zarray_size(quads); + + //////////////////////////////////////////////////////////////// + // Step 2. Decode tags from each quad. + if (1) { + for (int i = 0; i < zarray_size(quads); i++) { + struct quad *quad_original; + zarray_get_volatile(quads, i, &quad_original); + + // refine edges is not dependent upon the tag family, thus + // apply this optimization BEFORE the other work. + //if (td->quad_decimate > 1 && td->refine_edges) { + if (td->refine_edges) { + refine_edges(td, im_orig, quad_original); + } + + // make sure the homographies are computed... + if (quad_update_homographies(quad_original)) + continue; + + for (int famidx = 0; famidx < zarray_size(td->tag_families); famidx++) { + apriltag_family_t *family; + zarray_get(td->tag_families, famidx, &family); + + double goodness = 0; + + // since the geometry of tag families can vary, start any + // optimization process over with the original quad. + struct quad *quad = quad_copy(quad_original); + + // improve the quad corner positions by minimizing the + // variance within each intra-bit area. + if (td->refine_pose) { + // NB: We potentially step an integer + // number of times in each direction. To make each + // sample as useful as possible, the step sizes should + // not be integer multiples of each other. (I.e., + // probably don't use 1, 0.5, 0.25, etc.) + + // XXX Tunable + float stepsizes[] = { 1, .4, .16, .064 }; + int nstepsizes = sizeof(stepsizes)/sizeof(float); + + goodness = optimize_quad_generic(family, im_orig, quad, stepsizes, nstepsizes, score_goodness, NULL); + } + + if (td->refine_decode) { + // this optimizes decodability, but we don't report + // that value to the user. (so discard return value.) + // XXX Tunable + float stepsizes[] = { .4 }; + int nstepsizes = sizeof(stepsizes)/sizeof(float); + + optimize_quad_generic(family, im_orig, quad, stepsizes, nstepsizes, score_decodability, NULL); + } + + struct quick_decode_entry entry; + + float decision_margin = quad_decode(family, im_orig, quad, &entry, NULL); + + if (entry.hamming < 255 && decision_margin >= 0) { + apriltag_detection_t *det = calloc(1, sizeof(apriltag_detection_t)); + + det->family = family; + det->id = entry.id; + det->hamming = entry.hamming; + det->goodness = goodness; + det->decision_margin = decision_margin; + + double theta = -entry.rotation * M_PI / 2.0; + double c = cos(theta), s = sin(theta); + + // Fix the rotation of our homography to properly orient the tag + matd_t *R = matd_create(3,3); + MATD_EL(R, 0, 0) = c; + MATD_EL(R, 0, 1) = -s; + MATD_EL(R, 1, 0) = s; + MATD_EL(R, 1, 1) = c; + MATD_EL(R, 2, 2) = 1; + + det->H = matd_op("M*M", quad->H, R); + + matd_destroy(R); + + homography_project(det->H, 0, 0, &det->c[0], &det->c[1]); + + // [-1, -1], [1, -1], [1, 1], [-1, 1], Desired points + // [-1, 1], [1, 1], [1, -1], [-1, -1], FLIP Y + // adjust the points in det->p so that they correspond to + // counter-clockwise around the quad, starting at -1,-1. + for (int i = 0; i < 4; i++) { + int tcx = (i == 1 || i == 2) ? 1 : -1; + int tcy = (i < 2) ? 1 : -1; + + double p[2]; + + homography_project(det->H, tcx, tcy, &p[0], &p[1]); + + det->p[i][0] = p[0]; + det->p[i][1] = p[1]; + } + + zarray_add(detections, &det); + } + + quad_destroy(quad); + } + } + } + + //////////////////////////////////////////////////////////////// + // Step 3. Reconcile detections--- don't report the same tag more + // than once. (Allow non-overlapping duplicate detections.) + if (1) { + zarray_t *poly0 = g2d_polygon_create_zeros(4); + zarray_t *poly1 = g2d_polygon_create_zeros(4); + + for (int i0 = 0; i0 < zarray_size(detections); i0++) { + + apriltag_detection_t *det0; + zarray_get(detections, i0, &det0); + + for (int k = 0; k < 4; k++) + zarray_set(poly0, k, det0->p[k], NULL); + + for (int i1 = i0+1; i1 < zarray_size(detections); i1++) { + + apriltag_detection_t *det1; + zarray_get(detections, i1, &det1); + + if (det0->id != det1->id || det0->family != det1->family) + continue; + + for (int k = 0; k < 4; k++) + zarray_set(poly1, k, det1->p[k], NULL); + + if (g2d_polygon_overlaps_polygon(poly0, poly1)) { + // the tags overlap. Delete one, keep the other. + + int pref = 0; // 0 means undecided which one we'll keep. + pref = prefer_smaller(pref, det0->hamming, det1->hamming); // want small hamming + pref = prefer_smaller(pref, -det0->decision_margin, -det1->decision_margin); // want bigger margins + pref = prefer_smaller(pref, -det0->goodness, -det1->goodness); // want bigger goodness + + // if we STILL don't prefer one detection over the other, then pick + // any deterministic criterion. + for (int i = 0; i < 4; i++) { + pref = prefer_smaller(pref, det0->p[i][0], det1->p[i][0]); + pref = prefer_smaller(pref, det0->p[i][1], det1->p[i][1]); + } + + if (pref == 0) { + // at this point, we should only be undecided if the tag detections + // are *exactly* the same. How would that happen? + printf("uh oh, no preference for overlappingdetection\n"); + } + + if (pref < 0) { + // keep det0, destroy det1 + apriltag_detection_destroy(det1); + zarray_remove_index(detections, i1, 1); + i1--; // retry the same index + goto retry1; + } else { + // keep det1, destroy det0 + apriltag_detection_destroy(det0); + zarray_remove_index(detections, i0, 1); + i0--; // retry the same index. + goto retry0; + } + } + + retry1: ; + } + + retry0: ; + } + + zarray_destroy(poly0); + zarray_destroy(poly1); + } + + for (int i = 0; i < zarray_size(quads); i++) { + struct quad *quad; + zarray_get_volatile(quads, i, &quad); + matd_destroy(quad->H); + matd_destroy(quad->Hinv); + } + + zarray_destroy(quads); + + zarray_sort(detections, detection_compare_function); + + return detections; +} + + +// Call this method on each of the tags returned by apriltag_detector_detect +void apriltag_detections_destroy(zarray_t *detections) +{ + for (int i = 0; i < zarray_size(detections); i++) { + apriltag_detection_t *det; + zarray_get(detections, i, &det); + + apriltag_detection_destroy(det); + } + + zarray_destroy(detections); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void imlib_find_apriltags(list_t *out, image_t *ptr, rectangle_t *roi, apriltag_families_t families, + float fx, float fy, float cx, float cy) +{ + // Frame Buffer Memory Usage... + // -> GRAYSCALE Input Image = w*h*1 + // -> GRAYSCALE Threhsolded Image = w*h*1 + // -> UnionFind = w*h*2 (+w*h*1 for hash table) + size_t resolution = roi->w * roi->h; + size_t fb_alloc_need = resolution * (1 + 1 + 2 + 1); // read above... + umm_init_x(((fb_avail() - fb_alloc_need) / resolution) * resolution); + apriltag_detector_t *td = apriltag_detector_create(); + + if (families & TAG16H5) { + apriltag_detector_add_family(td, (apriltag_family_t *) &tag16h5); + } + + if (families & TAG25H7) { + apriltag_detector_add_family(td, (apriltag_family_t *) &tag25h7); + } + + if (families & TAG25H9) { + apriltag_detector_add_family(td, (apriltag_family_t *) &tag25h9); + } + + if (families & TAG36H10) { + apriltag_detector_add_family(td, (apriltag_family_t *) &tag36h10); + } + + if (families & TAG36H11) { + apriltag_detector_add_family(td, (apriltag_family_t *) &tag36h11); + } + + if (families & ARTOOLKIT) { + apriltag_detector_add_family(td, (apriltag_family_t *) &artoolkit); + } + + uint8_t *grayscale_image = fb_alloc(roi->w * roi->h); + + image_u8_t im; + im.width = roi->w; + im.height = roi->h; + im.stride = roi->w; + im.buf = grayscale_image; + + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + zarray_t *detections = apriltag_detector_detect(td, &im); + list_init(out, sizeof(find_apriltags_list_lnk_data_t)); + + for (int i = 0, j = zarray_size(detections); i < j; i++) { + apriltag_detection_t *det; + zarray_get(detections, i, &det); + + find_apriltags_list_lnk_data_t lnk_data; + rectangle_init(&(lnk_data.rect), fast_roundf(det->p[0][0]) + roi->x, fast_roundf(det->p[0][1]) + roi->y, 0, 0); + + for (size_t k = 1, l = (sizeof(det->p) / sizeof(det->p[0])); k < l; k++) { + rectangle_t temp; + rectangle_init(&temp, fast_roundf(det->p[k][0]) + roi->x, fast_roundf(det->p[k][1]) + roi->y, 0, 0); + rectangle_united(&(lnk_data.rect), &temp); + } + + // Add corners... + lnk_data.corners[0].x = fast_roundf(det->p[3][0]) + roi->x; // top-left + lnk_data.corners[0].y = fast_roundf(det->p[3][1]) + roi->y; // top-left + lnk_data.corners[1].x = fast_roundf(det->p[2][0]) + roi->x; // top-right + lnk_data.corners[1].y = fast_roundf(det->p[2][1]) + roi->y; // top-right + lnk_data.corners[2].x = fast_roundf(det->p[1][0]) + roi->x; // bottom-right + lnk_data.corners[2].y = fast_roundf(det->p[1][1]) + roi->y; // bottom-right + lnk_data.corners[3].x = fast_roundf(det->p[0][0]) + roi->x; // bottom-left + lnk_data.corners[3].y = fast_roundf(det->p[0][1]) + roi->y; // bottom-left + + lnk_data.id = det->id; + lnk_data.family = 0; + + if(det->family == &tag16h5) { + lnk_data.family |= TAG16H5; + } + + if(det->family == &tag25h7) { + lnk_data.family |= TAG25H7; + } + + if(det->family == &tag25h9) { + lnk_data.family |= TAG25H9; + } + + if(det->family == &tag36h10) { + lnk_data.family |= TAG36H10; + } + + if(det->family == &tag36h11) { + lnk_data.family |= TAG36H11; + } + + if(det->family == &artoolkit) { + lnk_data.family |= ARTOOLKIT; + } + + lnk_data.hamming = det->hamming; + lnk_data.centroid.x = fast_roundf(det->c[0]) + roi->x; + lnk_data.centroid.y = fast_roundf(det->c[1]) + roi->y; + lnk_data.goodness = det->goodness / 255.0; // scale to [0:1] + lnk_data.decision_margin = det->decision_margin / 255.0; // scale to [0:1] + + matd_t *pose = homography_to_pose(det->H, -fx, fy, cx, cy); + + lnk_data.x_translation = MATD_EL(pose, 0, 3); + lnk_data.y_translation = MATD_EL(pose, 1, 3); + lnk_data.z_translation = MATD_EL(pose, 2, 3); + lnk_data.x_rotation = fast_atan2f(MATD_EL(pose, 2, 1), MATD_EL(pose, 2, 2)); + lnk_data.y_rotation = fast_atan2f(-MATD_EL(pose, 2, 0), fast_sqrtf(sq(MATD_EL(pose, 2, 1)) + sq(MATD_EL(pose, 2, 2)))); + lnk_data.z_rotation = fast_atan2f(MATD_EL(pose, 1, 0), MATD_EL(pose, 0, 0)); + + matd_destroy(pose); + + list_push_back(out, &lnk_data); + } + + apriltag_detections_destroy(detections); + fb_free(); // grayscale_image; + apriltag_detector_destroy(td); + fb_free(); // umm_init_x(); +} + +#ifdef IMLIB_ENABLE_FIND_RECTS +void imlib_find_rects(list_t *out, image_t *ptr, rectangle_t *roi, uint32_t threshold) +{ + // Frame Buffer Memory Usage... + // -> GRAYSCALE Input Image = w*h*1 + // -> GRAYSCALE Threhsolded Image = w*h*1 + // -> UnionFind = w*h*4 (+w*h*2 for hash table) + size_t resolution = roi->w * roi->h; + size_t fb_alloc_need = resolution * (1 + 1 + 4 + 2); // read above... + umm_init_x(((fb_avail() - fb_alloc_need) / resolution) * resolution); + apriltag_detector_t *td = apriltag_detector_create(); + + uint8_t *grayscale_image = fb_alloc(roi->w * roi->h); + + image_u8_t im; + im.width = roi->w; + im.height = roi->h; + im.stride = roi->w; + im.buf = grayscale_image; + + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + /////////////////////////////////////////////////////////// + // Detect quads according to requested image decimation + // and blurring parameters. + +// zarray_t *detections = apriltag_quad_gradient(td, &im, true); + zarray_t *detections = apriltag_quad_thresh(td, &im, true); + + td->nquads = zarray_size(detections); + + //////////////////////////////////////////////////////////////// + // Decode tags from each quad. + if (1) { + for (int i = 0; i < zarray_size(detections); i++) { + struct quad *quad_original; + zarray_get_volatile(detections, i, &quad_original); + + // refine edges is not dependent upon the tag family, thus + // apply this optimization BEFORE the other work. + //if (td->quad_decimate > 1 && td->refine_edges) { + if (td->refine_edges) { + refine_edges(td, &im, quad_original); + } + + // make sure the homographies are computed... + if (quad_update_homographies(quad_original)) + continue; + } + } + + //////////////////////////////////////////////////////////////// + // Reconcile detections--- don't report the same tag more + // than once. (Allow non-overlapping duplicate detections.) + if (1) { + zarray_t *poly0 = g2d_polygon_create_zeros(4); + zarray_t *poly1 = g2d_polygon_create_zeros(4); + + for (int i0 = 0; i0 < zarray_size(detections); i0++) { + + struct quad *det0; + zarray_get_volatile(detections, i0, &det0); + + for (int k = 0; k < 4; k++) + zarray_set(poly0, k, det0->p[k], NULL); + + for (int i1 = i0+1; i1 < zarray_size(detections); i1++) { + + struct quad *det1; + zarray_get_volatile(detections, i1, &det1); + + for (int k = 0; k < 4; k++) + zarray_set(poly1, k, det1->p[k], NULL); + + if (g2d_polygon_overlaps_polygon(poly0, poly1)) { + // the tags overlap. Delete one, keep the other. + + int pref = 0; // 0 means undecided which one we'll keep. + + // if we STILL don't prefer one detection over the other, then pick + // any deterministic criterion. + for (int i = 0; i < 4; i++) { + pref = prefer_smaller(pref, det0->p[i][0], det1->p[i][0]); + pref = prefer_smaller(pref, det0->p[i][1], det1->p[i][1]); + } + + if (pref == 0) { + // at this point, we should only be undecided if the tag detections + // are *exactly* the same. How would that happen? + printf("uh oh, no preference for overlappingdetection\n"); + } + + if (pref < 0) { + // keep det0, destroy det1 + matd_destroy(det1->H); + matd_destroy(det1->Hinv); + zarray_remove_index(detections, i1, 1); + i1--; // retry the same index + goto retry1; + } else { + // keep det1, destroy det0 + matd_destroy(det0->H); + matd_destroy(det0->Hinv); + zarray_remove_index(detections, i0, 1); + i0--; // retry the same index. + goto retry0; + } + } + + retry1: ; + } + + retry0: ; + } + + zarray_destroy(poly0); + zarray_destroy(poly1); + } + + list_init(out, sizeof(find_rects_list_lnk_data_t)); + + const int r_diag_len = fast_roundf(fast_sqrtf((roi->w * roi->w) + (roi->h * roi->h))) * 2; + int *theta_buffer = fb_alloc(sizeof(int) * r_diag_len); + uint32_t *mag_buffer = fb_alloc(sizeof(uint32_t) * r_diag_len); + point_t *point_buffer = fb_alloc(sizeof(point_t) * r_diag_len); + + for (int i = 0, j = zarray_size(detections); i < j; i++) { + struct quad *det; + zarray_get_volatile(detections, i, &det); + + line_t lines[4]; + lines[0].x1 = fast_roundf(det->p[0][0]) + roi->x; lines[0].y1 = fast_roundf(det->p[0][1]) + roi->y; + lines[0].x2 = fast_roundf(det->p[1][0]) + roi->x; lines[0].y2 = fast_roundf(det->p[1][1]) + roi->y; + lines[1].x1 = fast_roundf(det->p[1][0]) + roi->x; lines[1].y1 = fast_roundf(det->p[1][1]) + roi->y; + lines[1].x2 = fast_roundf(det->p[2][0]) + roi->x; lines[1].y2 = fast_roundf(det->p[2][1]) + roi->y; + lines[2].x1 = fast_roundf(det->p[2][0]) + roi->x; lines[2].y1 = fast_roundf(det->p[2][1]) + roi->y; + lines[2].x2 = fast_roundf(det->p[3][0]) + roi->x; lines[2].y2 = fast_roundf(det->p[3][1]) + roi->y; + lines[3].x1 = fast_roundf(det->p[3][0]) + roi->x; lines[3].y1 = fast_roundf(det->p[3][1]) + roi->y; + lines[3].x2 = fast_roundf(det->p[0][0]) + roi->x; lines[3].y2 = fast_roundf(det->p[0][1]) + roi->y; + + uint32_t magnitude = 0; + + for (int i = 0; i < 4; i++) { + if(!lb_clip_line(&lines[i], 0, 0, ptr->w, ptr->h)) { + continue; + } + + size_t index = trace_line(ptr, &lines[i], theta_buffer, mag_buffer, point_buffer); + + for (int j = 0; j < index; j++) { + magnitude += mag_buffer[j]; + } + } + + if (magnitude < threshold) { + continue; + } + + find_rects_list_lnk_data_t lnk_data; + rectangle_init(&(lnk_data.rect), fast_roundf(det->p[0][0]) + roi->x, fast_roundf(det->p[0][1]) + roi->y, 0, 0); + + for (size_t k = 1, l = (sizeof(det->p) / sizeof(det->p[0])); k < l; k++) { + rectangle_t temp; + rectangle_init(&temp, fast_roundf(det->p[k][0]) + roi->x, fast_roundf(det->p[k][1]) + roi->y, 0, 0); + rectangle_united(&(lnk_data.rect), &temp); + } + + // Add corners... + lnk_data.corners[0].x = fast_roundf(det->p[3][0]) + roi->x; // top-left + lnk_data.corners[0].y = fast_roundf(det->p[3][1]) + roi->y; // top-left + lnk_data.corners[1].x = fast_roundf(det->p[2][0]) + roi->x; // top-right + lnk_data.corners[1].y = fast_roundf(det->p[2][1]) + roi->y; // top-right + lnk_data.corners[2].x = fast_roundf(det->p[1][0]) + roi->x; // bottom-right + lnk_data.corners[2].y = fast_roundf(det->p[1][1]) + roi->y; // bottom-right + lnk_data.corners[3].x = fast_roundf(det->p[0][0]) + roi->x; // bottom-left + lnk_data.corners[3].y = fast_roundf(det->p[0][1]) + roi->y; // bottom-left + + lnk_data.magnitude = magnitude; + + list_push_back(out, &lnk_data); + } + + fb_free(); // point_buffer + fb_free(); // mag_buffer + fb_free(); // theta_buffer + + zarray_destroy(detections); + fb_free(); // grayscale_image; + apriltag_detector_destroy(td); + fb_free(); // umm_init_x(); +} +#endif //IMLIB_ENABLE_FIND_RECTS + +#ifdef IMLIB_ENABLE_ROTATION_CORR +// http://jepsonsblog.blogspot.com/2012/11/rotation-in-3d-using-opencvs.html +void imlib_rotation_corr(image_t *img, float x_rotation, float y_rotation, float z_rotation, + float x_translation, float y_translation, + float zoom) +{ + umm_init_x(4000); // 200 20 byte heap blocks... + + float fov = (M_PI_2 * 2) / 3; // 60 deg FOV + float fov_2 = fov / 2.0; + float d = fast_sqrtf((img->w * img->w) + (img->h * img->h)); + float h = d / (2.0 * tanf(fov_2)); + float h_z = h * zoom; + + matd_t *A1 = matd_create(4, 3); + MATD_EL(A1, 0, 0) = 1; MATD_EL(A1, 0, 1) = 0; MATD_EL(A1, 0, 2) = -img->w / 2.0; + MATD_EL(A1, 1, 0) = 0; MATD_EL(A1, 1, 1) = 1; MATD_EL(A1, 1, 2) = -img->h / 2.0; + MATD_EL(A1, 2, 0) = 0; MATD_EL(A1, 2, 1) = 0; MATD_EL(A1, 2, 2) = 0; + MATD_EL(A1, 3, 0) = 0; MATD_EL(A1, 3, 1) = 0; MATD_EL(A1, 3, 2) = 1; // needed for h translation + + matd_t *RX = matd_create(4, 4); + MATD_EL(RX, 0, 0) = 1; MATD_EL(RX, 0, 1) = 0; MATD_EL(RX, 0, 2) = 0; MATD_EL(RX, 0, 3) = 0; + MATD_EL(RX, 1, 0) = 0; MATD_EL(RX, 1, 1) = +cosf(x_rotation); MATD_EL(RX, 1, 2) = -sinf(x_rotation); MATD_EL(RX, 1, 3) = 0; + MATD_EL(RX, 2, 0) = 0; MATD_EL(RX, 2, 1) = +sinf(x_rotation); MATD_EL(RX, 2, 2) = +cosf(x_rotation); MATD_EL(RX, 2, 3) = 0; + MATD_EL(RX, 3, 0) = 0; MATD_EL(RX, 3, 1) = 0; MATD_EL(RX, 3, 2) = 0; MATD_EL(RX, 3, 3) = 1; + + matd_t *RY = matd_create(4, 4); + MATD_EL(RY, 0, 0) = +cosf(y_rotation); MATD_EL(RY, 0, 1) = 0; MATD_EL(RY, 0, 2) = -sinf(y_rotation); MATD_EL(RY, 0, 3) = 0; + MATD_EL(RY, 1, 0) = 0; MATD_EL(RY, 1, 1) = 1; MATD_EL(RY, 1, 2) = 0; MATD_EL(RY, 1, 3) = 0; + MATD_EL(RY, 2, 0) = +sinf(y_rotation); MATD_EL(RY, 2, 1) = 0; MATD_EL(RY, 2, 2) = +cosf(y_rotation); MATD_EL(RY, 2, 3) = 0; + MATD_EL(RY, 3, 0) = 0; MATD_EL(RY, 3, 1) = 0; MATD_EL(RY, 3, 2) = 0; MATD_EL(RY, 3, 3) = 1; + + matd_t *RZ = matd_create(4, 4); + MATD_EL(RZ, 0, 0) = +cosf(z_rotation); MATD_EL(RZ, 0, 1) = -sinf(z_rotation); MATD_EL(RZ, 0, 2) = 0; MATD_EL(RZ, 0, 3) = 0; + MATD_EL(RZ, 1, 0) = +sinf(z_rotation); MATD_EL(RZ, 1, 1) = +cosf(z_rotation); MATD_EL(RZ, 1, 2) = 0; MATD_EL(RZ, 1, 3) = 0; + MATD_EL(RZ, 2, 0) = 0; MATD_EL(RZ, 2, 1) = 0; MATD_EL(RZ, 2, 2) = 1; MATD_EL(RZ, 2, 3) = 0; + MATD_EL(RZ, 3, 0) = 0; MATD_EL(RZ, 3, 1) = 0; MATD_EL(RZ, 3, 2) = 0; MATD_EL(RZ, 3, 3) = 1; + + matd_t *R = matd_op("M*M*M", RX, RY, RZ); + + matd_t *T = matd_create(4, 4); + MATD_EL(T, 0, 0) = 1; MATD_EL(T, 0, 1) = 0; MATD_EL(T, 0, 2) = 0; MATD_EL(T, 0, 3) = x_translation; + MATD_EL(T, 1, 0) = 0; MATD_EL(T, 1, 1) = 1; MATD_EL(T, 1, 2) = 0; MATD_EL(T, 1, 3) = y_translation; + MATD_EL(T, 2, 0) = 0; MATD_EL(T, 2, 1) = 0; MATD_EL(T, 2, 2) = 1; MATD_EL(T, 2, 3) = h; + MATD_EL(T, 3, 0) = 0; MATD_EL(T, 3, 1) = 0; MATD_EL(T, 3, 2) = 0; MATD_EL(T, 3, 3) = 1; + + matd_t *A2 = matd_create(3, 4); + MATD_EL(A2, 0, 0) = h_z; MATD_EL(A2, 0, 1) = 0; MATD_EL(A2, 0, 2) = img->w / 2.0; MATD_EL(A2, 0, 3) = 0; + MATD_EL(A2, 1, 0) = 0; MATD_EL(A2, 1, 1) = h_z; MATD_EL(A2, 1, 2) = img->h / 2.0; MATD_EL(A2, 1, 3) = 0; + MATD_EL(A2, 2, 0) = 0; MATD_EL(A2, 2, 1) = 0; MATD_EL(A2, 2, 2) = 1; MATD_EL(A2, 2, 3) = 0; + + matd_t *T1 = matd_op("M*M", R, A1); + matd_t *T2 = matd_op("M*M", T, T1); + matd_t *T3 = matd_op("M*M", A2, T2); + matd_t *T4 = matd_inverse(T3); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + // Create a temp copy of the image to pull pixels from. + uint32_t *tmp = fb_alloc(((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + memcpy(tmp, img->data, ((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + memset(img->data, 0, ((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + + if (T4) for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + float sourceX, sourceY; homography_project(T4, x, y, &sourceX, &sourceY); + int sourceX2 = round(sourceX); + int sourceY2 = round(sourceY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint32_t *ptr = tmp + (((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * sourceY2); + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(ptr, sourceX2); + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + // Create a temp copy of the image to pull pixels from. + uint8_t *tmp = fb_alloc(img->w * img->h * sizeof(uint8_t)); + memcpy(tmp, img->data, img->w * img->h * sizeof(uint8_t)); + memset(img->data, 0, img->w * img->h * sizeof(uint8_t)); + + if (T4) for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + float sourceX, sourceY; homography_project(T4, x, y, &sourceX, &sourceY); + int sourceX2 = round(sourceX); + int sourceY2 = round(sourceY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint8_t *ptr = tmp + (img->w * sourceY2); + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(ptr, sourceX2); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + // Create a temp copy of the image to pull pixels from. + uint16_t *tmp = fb_alloc(img->w * img->h * sizeof(uint16_t)); + memcpy(tmp, img->data, img->w * img->h * sizeof(uint16_t)); + memset(img->data, 0, img->w * img->h * sizeof(uint16_t)); + + if (T4) for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + float sourceX, sourceY; homography_project(T4, x, y, &sourceX, &sourceY); + int sourceX2 = round(sourceX); + int sourceY2 = round(sourceY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint16_t *ptr = tmp + (img->w * sourceY2); + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(ptr, sourceX2); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + default: { + break; + } + } + + if (T4) matd_destroy(T4); + matd_destroy(T3); + matd_destroy(T2); + matd_destroy(T1); + matd_destroy(A2); + matd_destroy(T); + matd_destroy(R); + matd_destroy(RZ); + matd_destroy(RY); + matd_destroy(RX); + matd_destroy(A1); + + fb_free(); // umm_init_x(); +} +#endif //IMLIB_ENABLE_ROTATION_CORR +#pragma GCC diagnostic pop +#endif //IMLIB_ENABLE_APRILTAGS diff --git a/src/openmv/src/omv/img/binary.c b/src/openmv/src/omv/img/binary.c new file mode 100755 index 0000000..0cf68bb --- /dev/null +++ b/src/openmv/src/omv/img/binary.c @@ -0,0 +1,843 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +#ifdef IMLIB_ENABLE_BINARY_OPS +void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask) +{ + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + if (!zero) { + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, + COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x), &lnk_data, invert)); + } + } + } else { + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + if (COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + IMAGE_CLEAR_BINARY_PIXEL_FAST(out_row_ptr, x); + } + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + if (out->bpp == IMAGE_BPP_BINARY) { + if (!zero) { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, + COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert) + ? COLOR_BINARY_MAX : COLOR_BINARY_MIN); + } + } + } else { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + if (COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, COLOR_BINARY_MIN); + } + } + } + } + } else { + if (!zero) { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, + COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert) + ? COLOR_GRAYSCALE_BINARY_MAX : COLOR_GRAYSCALE_BINARY_MIN); + } + } + } else { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + if (COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, COLOR_GRAYSCALE_BINARY_MIN); + } + } + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + if (out->bpp == IMAGE_BPP_BINARY) { + if (!zero) { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, + COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert) + ? COLOR_BINARY_MAX : COLOR_BINARY_MIN); + } + } + } else { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + if (COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, COLOR_BINARY_MIN); + } + } + } + } + break; + } else { + if (!zero) { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert) + ? COLOR_RGB565_BINARY_MAX : COLOR_RGB565_BINARY_MIN); + } + } + } else { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(out, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + if (COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, COLOR_RGB565_BINARY_MIN); + } + } + } + } + break; + } + break; + } + default: { + break; + } + } + } +} + +void imlib_invert(image_t *img) +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (uint32_t *start = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, 0), + *end = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, img->h); + start < end; start++) { + *start = ~*start; + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0), + *end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h); + start < end; start++) { + *start = ~*start; + } + break; + } + case IMAGE_BPP_RGB565: { + for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0), + *end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h); + start < end; start++) { + *start = ~*start; + } + break; + } + default: { + break; + } + } +} + +static void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] &= ((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + & IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] &= ((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + & IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] &= ((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + & IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_b_and_line_op, mask); +} + +static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] &= ~((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + & ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] &= ~((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + & ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] &= ~((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + & ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_nand(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_b_nand_line_op, mask); +} + +static void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] |= ((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + | IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] |= ((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + | IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] |= ((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + | IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_or(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_b_or_line_op, mask); +} + +static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] |= ~((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + | ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] |= ~((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + | ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] |= ~((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + | ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_nor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar,imlib_b_nor_line_op, mask); +} + +static void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] ^= ((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + ^ IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] ^= ((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + ^ IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] ^= ((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + ^ IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_b_xor_line_op, mask); +} + +static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) { + data[i] ^= ~((uint32_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, + (IMAGE_GET_BINARY_PIXEL_FAST(data, i) + ^ ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) { + data[i] ^= ~((uint8_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, + (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i) + ^ ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i))); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + + if(!mask) { + for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) { + data[i] ^= ~((uint16_t *) other)[i]; + } + } else { + for (int i = 0, j = img->w; i < j; i++) { + if (image_get_mask_pixel(mask, i, line)) { + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, + (IMAGE_GET_RGB565_PIXEL_FAST(data, i) + ^ ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i))); + } + } + } + break; + } + default: { + break; + } + } +} + +void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_b_xnor_line_op, mask); +} + +static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + + if ((mask && (!image_get_mask_pixel(mask, x, y))) + || (pixel == e_or_d)) { + continue; // Short circuit. + } + + int acc = e_or_d ? 0 : -1; // Don't count center pixel... + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + if (!e_or_d) { + // Preserve original pixel value... or clear it. + if (acc < threshold) IMAGE_CLEAR_BINARY_PIXEL_FAST(buf_row_ptr, x); + } else { + // Preserve original pixel value... or set it. + if (acc > threshold) IMAGE_SET_BINARY_PIXEL_FAST(buf_row_ptr, x); + } + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + + if ((mask && (!image_get_mask_pixel(mask, x, y))) + || (COLOR_GRAYSCALE_TO_BINARY(pixel) == e_or_d)) { + continue; // Short circuit. + } + + int acc = e_or_d ? 0 : -1; // Don't count center pixel... + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))); + } + } + + if (!e_or_d) { + // Preserve original pixel value... or clear it. + if (acc < threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, + COLOR_GRAYSCALE_BINARY_MIN); + } else { + // Preserve original pixel value... or set it. + if (acc > threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, + COLOR_GRAYSCALE_BINARY_MAX); + } + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + + if ((mask && (!image_get_mask_pixel(mask, x, y))) + || (COLOR_RGB565_TO_BINARY(pixel) == e_or_d)) { + continue; // Short circuit. + } + + int acc = e_or_d ? 0 : -1; // Don't count center pixel... + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))); + } + } + + if (!e_or_d) { + // Preserve original pixel value... or clear it. + if (acc < threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, + COLOR_RGB565_BINARY_MIN); + } else { + // Preserve original pixel value... or set it. + if (acc > threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, + COLOR_RGB565_BINARY_MAX); + } + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + default: { + break; + } + } +} + +void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask) +{ + // Threshold should be equal to (((ksize*2)+1)*((ksize*2)+1))-1 + // for normal operation. E.g. for ksize==3 -> threshold==8 + // Basically you're adjusting the number of data that + // must be set in the kernel (besides the center) for the output to be 1. + // Erode normally requires all data to be 1. + imlib_erode_dilate(img, ksize, threshold, 0, mask); +} + +void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask) +{ + // Threshold should be equal to 0 + // for normal operation. E.g. for ksize==3 -> threshold==0 + // Basically you're adjusting the number of data that + // must be set in the kernel (besides the center) for the output to be 1. + // Dilate normally requires one pixel to be 1. + imlib_erode_dilate(img, ksize, threshold, 1, mask); +} + +void imlib_open(image_t *img, int ksize, int threshold, image_t *mask) +{ + imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask); + imlib_dilate(img, ksize, 0 + threshold, mask); +} + +void imlib_close(image_t *img, int ksize, int threshold, image_t *mask) +{ + imlib_dilate(img, ksize, 0 + threshold, mask); + imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask); +} + +void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask) +{ + image_t temp; + temp.w = img->w; + temp.h = img->h; + temp.bpp = img->bpp; + temp.data = fb_alloc(image_size(img)); + memcpy(temp.data, img->data, image_size(img)); + imlib_open(&temp, ksize, threshold, mask); + imlib_difference(img, NULL, &temp, 0, mask); + fb_free(); +} + +void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask) +{ + image_t temp; + temp.w = img->w; + temp.h = img->h; + temp.bpp = img->bpp; + temp.data = fb_alloc(image_size(img)); + memcpy(temp.data, img->data, image_size(img)); + imlib_close(&temp, ksize, threshold, mask); + imlib_difference(img, NULL, &temp, 0, mask); + fb_free(); +} +#endif diff --git a/src/openmv/src/omv/img/blob.c b/src/openmv/src/omv/img/blob.c new file mode 100755 index 0000000..c0f1e12 --- /dev/null +++ b/src/openmv/src/omv/img/blob.c @@ -0,0 +1,945 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +typedef struct xylf +{ + int16_t x, y, l, r; +} +xylf_t; + +void imlib_find_blobs(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + list_t *thresholds, bool invert, unsigned int area_threshold, unsigned int pixels_threshold, + bool merge, int margin, + bool (*threshold_cb)(void*,find_blobs_list_lnk_data_t*), void *threshold_cb_arg, + bool (*merge_cb)(void*,find_blobs_list_lnk_data_t*,find_blobs_list_lnk_data_t*), void *merge_cb_arg) +{ + bitmap_t bitmap; // Same size as the image so we don't have to translate. + bitmap_alloc(&bitmap, ptr->w * ptr->h); + + lifo_t lifo; + size_t lifo_len; + lifo_alloc_all(&lifo, &lifo_len, sizeof(xylf_t)); + + list_init(out, sizeof(find_blobs_list_lnk_data_t)); + + size_t code = 0; + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + size_t row_index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(row_index, x))) + && COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + int old_x = x; + int old_y = y; + + int blob_x1 = x; + int blob_y1 = y; + int blob_x2 = x; + int blob_y2 = y; + int blob_pixels = 0; + int blob_cx = 0; + int blob_cy = 0; + long long blob_a = 0; + long long blob_b = 0; + long long blob_c = 0; + + // Scanline Flood Fill Algorithm // + + for(;;) { + int left = x, right = x; + uint32_t *row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + size_t index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + + while ((left > roi->x) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, left - 1))) + && COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, left - 1), &lnk_data, invert)) { + left--; + } + + while ((right < (roi->x + roi->w - 1)) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, right + 1))) + && COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, right + 1), &lnk_data, invert)) { + right++; + } + + blob_x1 = IM_MIN(blob_x1, left); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, right); + blob_y2 = IM_MAX(blob_y2, y); + for (int i = left; i <= right; i++) { + bitmap_bit_set(&bitmap, BITMAP_COMPUTE_INDEX(index, i)); + blob_pixels += 1; + blob_cx += i; + blob_cy += y; + blob_a += i*i; + blob_b += i*y; + blob_c += y*y; + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + + if (y > roi->y) { + row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y - 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (roi->y + roi->h - 1)) { + row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y + 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + + // http://www.cse.usf.edu/~r1k/MachineVisionBook/MachineVision.files/MachineVision_Chapter2.pdf + // https://www.strchr.com/standard_deviation_in_one_pass + // + // a = sigma(x*x) + (mx*sigma(x)) + (mx*sigma(x)) + (sigma()*mx*mx) + // b = sigma(x*y) + (mx*sigma(y)) + (my*sigma(x)) + (sigma()*mx*my) + // c = sigma(y*y) + (my*sigma(y)) + (my*sigma(y)) + (sigma()*my*my) + // + // blob_a = sigma(x*x) + // blob_b = sigma(x*y) + // blob_c = sigma(y*y) + // blob_cx = sigma(x) + // blob_cy = sigma(y) + // blob_pixels = sigma() + + int mx = blob_cx / blob_pixels; // x centroid + int my = blob_cy / blob_pixels; // y centroid + int small_blob_a = blob_a - ((mx * blob_cx) + (mx * blob_cx)) + (blob_pixels * mx * mx); + int small_blob_b = blob_b - ((mx * blob_cy) + (my * blob_cx)) + (blob_pixels * mx * my); + int small_blob_c = blob_c - ((my * blob_cy) + (my * blob_cy)) + (blob_pixels * my * my); + + find_blobs_list_lnk_data_t lnk_blob; + lnk_blob.rect.x = blob_x1; + lnk_blob.rect.y = blob_y1; + lnk_blob.rect.w = blob_x2 - blob_x1; + lnk_blob.rect.h = blob_y2 - blob_y1; + lnk_blob.pixels = blob_pixels; + lnk_blob.centroid.x = mx; + lnk_blob.centroid.y = my; + lnk_blob.rotation = (small_blob_a != small_blob_c) ? (fast_atan2f(2 * small_blob_b, small_blob_a - small_blob_c) / 2.0f) : 0.0f; + lnk_blob.code = 1 << code; + lnk_blob.count = 1; + + if (((lnk_blob.rect.w * lnk_blob.rect.h) >= area_threshold) && (lnk_blob.pixels >= pixels_threshold) + && ((threshold_cb_arg == NULL) || threshold_cb(threshold_cb_arg, &lnk_blob))) { + list_push_back(out, &lnk_blob); + } + + x = old_x; + y = old_y; + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + size_t row_index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(row_index, x))) + && COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + int old_x = x; + int old_y = y; + + int blob_x1 = x; + int blob_y1 = y; + int blob_x2 = x; + int blob_y2 = y; + int blob_pixels = 0; + int blob_cx = 0; + int blob_cy = 0; + long long blob_a = 0; + long long blob_b = 0; + long long blob_c = 0; + + // Scanline Flood Fill Algorithm // + + for(;;) { + int left = x, right = x; + uint8_t *row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + size_t index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + + while ((left > roi->x) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, left - 1))) + && COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left - 1), &lnk_data, invert)) { + left--; + } + + while ((right < (roi->x + roi->w - 1)) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, right + 1))) + && COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right + 1), &lnk_data, invert)) { + right++; + } + + blob_x1 = IM_MIN(blob_x1, left); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, right); + blob_y2 = IM_MAX(blob_y2, y); + for (int i = left; i <= right; i++) { + bitmap_bit_set(&bitmap, BITMAP_COMPUTE_INDEX(index, i)); + blob_pixels += 1; + blob_cx += i; + blob_cy += y; + blob_a += i*i; + blob_b += i*y; + blob_c += y*y; + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + + if (y > roi->y) { + row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y - 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (roi->y + roi->h - 1)) { + row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y + 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + + // http://www.cse.usf.edu/~r1k/MachineVisionBook/MachineVision.files/MachineVision_Chapter2.pdf + // https://www.strchr.com/standard_deviation_in_one_pass + // + // a = sigma(x*x) + (mx*sigma(x)) + (mx*sigma(x)) + (sigma()*mx*mx) + // b = sigma(x*y) + (mx*sigma(y)) + (my*sigma(x)) + (sigma()*mx*my) + // c = sigma(y*y) + (my*sigma(y)) + (my*sigma(y)) + (sigma()*my*my) + // + // blob_a = sigma(x*x) + // blob_b = sigma(x*y) + // blob_c = sigma(y*y) + // blob_cx = sigma(x) + // blob_cy = sigma(y) + // blob_pixels = sigma() + + int mx = blob_cx / blob_pixels; // x centroid + int my = blob_cy / blob_pixels; // y centroid + int small_blob_a = blob_a - ((mx * blob_cx) + (mx * blob_cx)) + (blob_pixels * mx * mx); + int small_blob_b = blob_b - ((mx * blob_cy) + (my * blob_cx)) + (blob_pixels * mx * my); + int small_blob_c = blob_c - ((my * blob_cy) + (my * blob_cy)) + (blob_pixels * my * my); + + find_blobs_list_lnk_data_t lnk_blob; + lnk_blob.rect.x = blob_x1; + lnk_blob.rect.y = blob_y1; + lnk_blob.rect.w = blob_x2 - blob_x1; + lnk_blob.rect.h = blob_y2 - blob_y1; + lnk_blob.pixels = blob_pixels; + lnk_blob.centroid.x = mx; + lnk_blob.centroid.y = my; + lnk_blob.rotation = (small_blob_a != small_blob_c) ? (fast_atan2f(2 * small_blob_b, small_blob_a - small_blob_c) / 2.0f) : 0.0f; + lnk_blob.code = 1 << code; + lnk_blob.count = 1; + + if (((lnk_blob.rect.w * lnk_blob.rect.h) >= area_threshold) && (lnk_blob.pixels >= pixels_threshold) + && ((threshold_cb_arg == NULL) || threshold_cb(threshold_cb_arg, &lnk_blob))) { + list_push_back(out, &lnk_blob); + } + + x = old_x; + y = old_y; + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + size_t row_index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(row_index, x))) + && COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + int old_x = x; + int old_y = y; + + int blob_x1 = x; + int blob_y1 = y; + int blob_x2 = x; + int blob_y2 = y; + int blob_pixels = 0; + int blob_cx = 0; + int blob_cy = 0; + long long blob_a = 0; + long long blob_b = 0; + long long blob_c = 0; + + // Scanline Flood Fill Algorithm // + + for(;;) { + int left = x, right = x; + uint16_t *row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + size_t index = BITMAP_COMPUTE_ROW_INDEX(ptr, y); + + while ((left > roi->x) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, left - 1))) + && COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, left - 1), &lnk_data, invert)) { + left--; + } + + while ((right < (roi->x + roi->w - 1)) + && (!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, right + 1))) + && COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, right + 1), &lnk_data, invert)) { + right++; + } + + blob_x1 = IM_MIN(blob_x1, left); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, right); + blob_y2 = IM_MAX(blob_y2, y); + for (int i = left; i <= right; i++) { + bitmap_bit_set(&bitmap, BITMAP_COMPUTE_INDEX(index, i)); + blob_pixels += 1; + blob_cx += i; + blob_cy += y; + blob_a += i*i; + blob_b += i*y; + blob_c += y*y; + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + + if (y > roi->y) { + row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y - 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (roi->y + roi->h - 1)) { + row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y + 1); + index = BITMAP_COMPUTE_ROW_INDEX(ptr, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!bitmap_bit_get(&bitmap, BITMAP_COMPUTE_INDEX(index, i))) + && COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), &lnk_data, invert)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + + // http://www.cse.usf.edu/~r1k/MachineVisionBook/MachineVision.files/MachineVision_Chapter2.pdf + // https://www.strchr.com/standard_deviation_in_one_pass + // + // a = sigma(x*x) + (mx*sigma(x)) + (mx*sigma(x)) + (sigma()*mx*mx) + // b = sigma(x*y) + (mx*sigma(y)) + (my*sigma(x)) + (sigma()*mx*my) + // c = sigma(y*y) + (my*sigma(y)) + (my*sigma(y)) + (sigma()*my*my) + // + // blob_a = sigma(x*x) + // blob_b = sigma(x*y) + // blob_c = sigma(y*y) + // blob_cx = sigma(x) + // blob_cy = sigma(y) + // blob_pixels = sigma() + + int mx = blob_cx / blob_pixels; // x centroid + int my = blob_cy / blob_pixels; // y centroid + int small_blob_a = blob_a - ((mx * blob_cx) + (mx * blob_cx)) + (blob_pixels * mx * mx); + int small_blob_b = blob_b - ((mx * blob_cy) + (my * blob_cx)) + (blob_pixels * mx * my); + int small_blob_c = blob_c - ((my * blob_cy) + (my * blob_cy)) + (blob_pixels * my * my); + + find_blobs_list_lnk_data_t lnk_blob; + lnk_blob.rect.x = blob_x1; + lnk_blob.rect.y = blob_y1; + lnk_blob.rect.w = blob_x2 - blob_x1; + lnk_blob.rect.h = blob_y2 - blob_y1; + lnk_blob.pixels = blob_pixels; + lnk_blob.centroid.x = mx; + lnk_blob.centroid.y = my; + lnk_blob.rotation = (small_blob_a != small_blob_c) ? (fast_atan2f(2 * small_blob_b, small_blob_a - small_blob_c) / 2.0f) : 0.0f; + lnk_blob.code = 1 << code; + lnk_blob.count = 1; + + if (((lnk_blob.rect.w * lnk_blob.rect.h) >= area_threshold) && (lnk_blob.pixels >= pixels_threshold) + && ((threshold_cb_arg == NULL) || threshold_cb(threshold_cb_arg, &lnk_blob))) { + list_push_back(out, &lnk_blob); + } + + x = old_x; + y = old_y; + } + } + } + break; + } + default: { + break; + } + } + + code += 1; + } + + lifo_free(&lifo); + bitmap_free(&bitmap); + + if (merge) { + for(;;) { + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(find_blobs_list_lnk_data_t)); + + while(list_size(out)) { + find_blobs_list_lnk_data_t lnk_blob; + list_pop_front(out, &lnk_blob); + + for (size_t k = 0, l = list_size(out); k < l; k++) { + find_blobs_list_lnk_data_t tmp_blob; + list_pop_front(out, &tmp_blob); + + rectangle_t temp; + temp.x = IM_MAX(IM_MIN(tmp_blob.rect.x - margin, INT16_MAX), INT16_MIN); + temp.y = IM_MAX(IM_MIN(tmp_blob.rect.y - margin, INT16_MAX), INT16_MIN); + temp.w = IM_MAX(IM_MIN(tmp_blob.rect.w + (margin * 2), INT16_MAX), 0); + temp.h = IM_MAX(IM_MIN(tmp_blob.rect.h + (margin * 2), INT16_MAX), 0); + + if (rectangle_overlap(&(lnk_blob.rect), &temp) + && ((merge_cb_arg == NULL) || merge_cb(merge_cb_arg, &lnk_blob, &tmp_blob))) { + rectangle_united(&(lnk_blob.rect), &(tmp_blob.rect)); + lnk_blob.centroid.x = ((lnk_blob.centroid.x * lnk_blob.pixels) + (tmp_blob.centroid.x * tmp_blob.pixels)) / (lnk_blob.pixels + tmp_blob.pixels); + lnk_blob.centroid.y = ((lnk_blob.centroid.y * lnk_blob.pixels) + (tmp_blob.centroid.y * tmp_blob.pixels)) / (lnk_blob.pixels + tmp_blob.pixels); + float sin_mean = ((sinf(lnk_blob.rotation) * lnk_blob.pixels) + (sinf(tmp_blob.rotation) * tmp_blob.pixels)) / (lnk_blob.pixels + tmp_blob.pixels); + float cos_mean = ((cosf(lnk_blob.rotation) * lnk_blob.pixels) + (cosf(tmp_blob.rotation) * tmp_blob.pixels)) / (lnk_blob.pixels + tmp_blob.pixels); + lnk_blob.rotation = fast_atan2f(sin_mean, cos_mean); + lnk_blob.pixels += tmp_blob.pixels; // won't overflow + lnk_blob.code |= tmp_blob.code; + lnk_blob.count = IM_MAX(IM_MIN(lnk_blob.count + tmp_blob.count, UINT16_MAX), 0); + merge_occured = true; + } else { + list_push_back(out, &tmp_blob); + } + } + + list_push_back(&out_temp, &lnk_blob); + } + + list_copy(out, &out_temp); + + if (!merge_occured) { + break; + } + } + } +} + +void imlib_flood_fill_int(image_t *out, image_t *img, int x, int y, + int seed_threshold, int floating_threshold, + flood_fill_call_back_t cb, void *data) +{ + lifo_t lifo; + size_t lifo_len; + lifo_alloc_all(&lifo, &lifo_len, sizeof(xylf_t)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for(int seed_pixel = IMAGE_GET_BINARY_PIXEL(img, x, y);;) { + int left = x, right = x; + uint32_t *row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + + while ((left > 0) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1)) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, left - 1), + IMAGE_GET_BINARY_PIXEL_FAST(row, left), floating_threshold)) { + left--; + } + + while ((right < (img->w - 1)) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1)) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, right + 1), + IMAGE_GET_BINARY_PIXEL_FAST(row, right), floating_threshold)) { + right++; + } + + for (int i = left; i <= right; i++) { + IMAGE_SET_BINARY_PIXEL_FAST(out_row, i); + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + uint32_t *old_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + + if (y > 0) { + row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y - 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), + IMAGE_GET_BINARY_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (img->h - 1)) { + row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y + 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row, i), + IMAGE_GET_BINARY_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (cb) cb(img, y, left, right, data); + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for(int seed_pixel = IMAGE_GET_GRAYSCALE_PIXEL(img, x, y);;) { + int left = x, right = x; + uint8_t *row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + + while ((left > 0) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1)) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left - 1), + IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, left), floating_threshold)) { + left--; + } + + while ((right < (img->w - 1)) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1)) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right + 1), + IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, right), floating_threshold)) { + right++; + } + + for (int i = left; i <= right; i++) { + IMAGE_SET_BINARY_PIXEL_FAST(out_row, i); + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + uint8_t *old_row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + + if (y > 0) { + row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y - 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), + IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (img->h - 1)) { + row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y + 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row, i), + IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (cb) cb(img, y, left, right, data); + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + break; + } + case IMAGE_BPP_RGB565: { + for(int seed_pixel = IMAGE_GET_RGB565_PIXEL(img, x, y);;) { + int left = x, right = x; + uint16_t *row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint32_t *out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y); + + while ((left > 0) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, left - 1)) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, left - 1), seed_pixel, seed_threshold) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, left - 1), + IMAGE_GET_RGB565_PIXEL_FAST(row, left), floating_threshold)) { + left--; + } + + while ((right < (img->w - 1)) + && (!IMAGE_GET_BINARY_PIXEL_FAST(out_row, right + 1)) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, right + 1), seed_pixel, seed_threshold) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, right + 1), + IMAGE_GET_RGB565_PIXEL_FAST(row, right), floating_threshold)) { + right++; + } + + for (int i = left; i <= right; i++) { + IMAGE_SET_BINARY_PIXEL_FAST(out_row, i); + } + + bool break_out = false; + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + uint16_t *old_row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + + if (y > 0) { + row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y - 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y - 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), + IMAGE_GET_RGB565_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + + if (y < (img->h - 1)) { + row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y + 1); + out_row = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y + 1); + + bool recurse = false; + for (int i = left; i <= right; i++) { + if ((!IMAGE_GET_BINARY_PIXEL_FAST(out_row, i)) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), seed_pixel, seed_threshold) + && COLOR_BOUND_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row, i), + IMAGE_GET_RGB565_PIXEL_FAST(old_row, i), floating_threshold)) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + } + if (recurse) { + break; + } + } + } + + if (cb) cb(img, y, left, right, data); + + if (!lifo_size(&lifo)) { + break_out = true; + break; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + + if (break_out) { + break; + } + } + break; + } + default: { + break; + } + } + + lifo_free(&lifo); +} diff --git a/src/openmv/src/omv/img/bmp.c b/src/openmv/src/omv/img/bmp.c new file mode 100755 index 0000000..cbcab2d --- /dev/null +++ b/src/openmv/src/omv/img/bmp.c @@ -0,0 +1,264 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * BMP reader/writer. + * + */ +#include +#include +#include "ff_wrapper.h" +#include "xalloc.h" +#include "imlib.h" + +// This function inits the geometry values of an image (opens file). +bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs) +{ + read_byte_expect(fp, 'B'); + read_byte_expect(fp, 'M'); + + uint32_t file_size; + read_long(fp, &file_size); + read_word_ignore(fp); + read_word_ignore(fp); + + uint32_t header_size; + read_long(fp, &header_size); + if (file_size <= header_size) ff_file_corrupted(fp); + + uint32_t data_size = file_size - header_size; + if (data_size % 4) ff_file_corrupted(fp); + + read_long_expect(fp, 40); + read_long(fp, (uint32_t*) &rs->bmp_w); + read_long(fp, (uint32_t*) &rs->bmp_h); + if ((rs->bmp_w == 0) || (rs->bmp_h == 0)) ff_file_corrupted(fp); + img->w = abs(rs->bmp_w); + img->h = abs(rs->bmp_h); + + read_word_expect(fp, 1); + read_word(fp, &rs->bmp_bpp); + if ((rs->bmp_bpp != 8) && (rs->bmp_bpp != 16) && (rs->bmp_bpp != 24)) ff_unsupported_format(fp); + img->bpp = (rs->bmp_bpp == 8) ? 1 : 2; + + read_long(fp, &rs->bmp_fmt); + if ((rs->bmp_fmt != 0) && (rs->bmp_fmt != 3)) ff_unsupported_format(fp); + + read_long_expect(fp, data_size); + read_long_ignore(fp); + read_long_ignore(fp); + read_long_ignore(fp); + read_long_ignore(fp); + + if (rs->bmp_bpp == 8) { + if (rs->bmp_fmt != 0) ff_unsupported_format(fp); + // Color Table (1024 bytes) + for (int i = 0; i < 256; i++) { + read_long_expect(fp, ((i) << 16) | ((i) << 8) | i); + } + } else if (rs->bmp_bpp == 16) { + if (rs->bmp_fmt != 3) ff_unsupported_format(fp); + // Bit Masks (12 bytes) + read_long_expect(fp, 0x1F << 11); + read_long_expect(fp, 0x3F << 5); + read_long_expect(fp, 0x1F); + } else if (rs->bmp_bpp == 24) { + if (rs->bmp_fmt == 3) { + // Bit Masks (12 bytes) + read_long_expect(fp, 0xFF << 16); + read_long_expect(fp, 0xFF << 8); + read_long_expect(fp, 0xFF); + } + } + + rs->bmp_row_bytes = (((img->w * rs->bmp_bpp) + 31) / 32) * 4; + if (data_size != (rs->bmp_row_bytes * img->h)) ff_file_corrupted(fp); + return (rs->bmp_h >= 0); +} + +// This function reads the pixel values of an image. +void bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, bmp_read_settings_t *rs) +{ + if (rs->bmp_bpp == 8) { + if ((rs->bmp_h < 0) && (rs->bmp_w >= 0) && (img->w == rs->bmp_row_bytes)) { + read_data(fp, // Super Fast - Zoom, Zoom! + img->pixels + (line_start * img->w), + (line_end - line_start) * img->w); + } else { + for (int i = line_start; i < line_end; i++) { + for (int j = 0; j < rs->bmp_row_bytes; j++) { + uint8_t pixel; + read_byte(fp, &pixel); + if (j < img->w) { + if (rs->bmp_h < 0) { // vertical flip (BMP file perspective) + if (rs->bmp_w < 0) { // horizontal flip (BMP file perspective) + IM_SET_GS_PIXEL(img, (img->w-j-1), i, pixel); + } else { + IM_SET_GS_PIXEL(img, j, i, pixel); + } + } else { + if (rs->bmp_w < 0) { + IM_SET_GS_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel); + } else { + IM_SET_GS_PIXEL(img, j, (img->h-i-1), pixel); + } + } + } + } + } + } + } else if (rs->bmp_bpp == 16) { + for (int i = line_start; i < line_end; i++) { + for (int j = 0, jj = rs->bmp_row_bytes / 2; j < jj; j++) { + uint16_t pixel; + read_word(fp, &pixel); + pixel = IM_SWAP16(pixel); + if (j < img->w) { + if (rs->bmp_h < 0) { // vertical flip (BMP file perspective) + if (rs->bmp_w < 0) { // horizontal flip (BMP file perspective) + IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel); + } else { + IM_SET_RGB565_PIXEL(img, j, i, pixel); + } + } else { + if (rs->bmp_w < 0) { + IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel); + } else { + IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel); + } + } + } + } + } + } else if (rs->bmp_bpp == 24) { + for (int i = line_start; i < line_end; i++) { + for (int j = 0, jj = rs->bmp_row_bytes / 3; j < jj; j++) { + uint8_t r, g, b; + read_byte(fp, &r); + read_byte(fp, &g); + read_byte(fp, &b); + uint16_t pixel = IM_RGB565(IM_R825(r), IM_G826(g), IM_B825(b)); + if (j < img->w) { + if (rs->bmp_h < 0) { // vertical flip + if (rs->bmp_w < 0) { // horizontal flip + IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel); + } else { + IM_SET_RGB565_PIXEL(img, j, i, pixel); + } + } else { + if (rs->bmp_w < 0) { + IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel); + } else { + IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel); + } + } + } + } + for (int j = 0, jj = rs->bmp_row_bytes % 3; j < jj; j++) { + read_byte_ignore(fp); + } + } + } +} + +void bmp_read(image_t *img, const char *path) +{ + FIL fp; + bmp_read_settings_t rs; + file_read_open(&fp, path); + file_buffer_on(&fp); + bmp_read_geometry(&fp, img, path, &rs); + if (!img->pixels) img->pixels = xalloc(img->w * img->h * img->bpp); + bmp_read_pixels(&fp, img, 0, img->h, &rs); + file_buffer_off(&fp); + file_close(&fp); +} + +void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r) +{ + rectangle_t rect; + if (!rectangle_subimg(img, r, &rect)) ff_no_intersection(NULL); + FIL fp; + file_write_open(&fp, path); + + file_buffer_on(&fp); + if (IM_IS_GS(img)) { + const int row_bytes = (((rect.w * 8) + 31) / 32) * 4; + const int data_size = (row_bytes * rect.h); + const int waste = (row_bytes / sizeof(uint8_t)) - rect.w; + // File Header (14 bytes) + write_byte(&fp, 'B'); + write_byte(&fp, 'M'); + write_long(&fp, 14 + 40 + 1024 + data_size); + write_word(&fp, 0); + write_word(&fp, 0); + write_long(&fp, 14 + 40 + 1024); + // Info Header (40 bytes) + write_long(&fp, 40); + write_long(&fp, rect.w); + write_long(&fp, -rect.h); // store the image flipped (correctly) + write_word(&fp, 1); + write_word(&fp, 8); + write_long(&fp, 0); + write_long(&fp, data_size); + write_long(&fp, 0); + write_long(&fp, 0); + write_long(&fp, 0); + write_long(&fp, 0); + // Color Table (1024 bytes) + for (int i = 0; i < 256; i++) { + write_long(&fp, ((i) << 16) | ((i) << 8) | i); + } + if ((rect.x == 0) && (rect.w == img->w) && (img->w == row_bytes)) { + write_data(&fp, // Super Fast - Zoom, Zoom! + img->pixels + (rect.y * img->w), + rect.w * rect.h); + } else { + for (int i = 0; i < rect.h; i++) { + write_data(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w); + for (int j = 0; j < waste; j++) { + write_byte(&fp, 0); + } + } + } + } else { + const int row_bytes = (((rect.w * 16) + 31) / 32) * 4; + const int data_size = (row_bytes * rect.h); + const int waste = (row_bytes / sizeof(uint16_t)) - rect.w; + // File Header (14 bytes) + write_byte(&fp, 'B'); + write_byte(&fp, 'M'); + write_long(&fp, 14 + 40 + 12 + data_size); + write_word(&fp, 0); + write_word(&fp, 0); + write_long(&fp, 14 + 40 + 12); + // Info Header (40 bytes) + write_long(&fp, 40); + write_long(&fp, rect.w); + write_long(&fp, -rect.h); // store the image flipped (correctly) + write_word(&fp, 1); + write_word(&fp, 16); + write_long(&fp, 3); + write_long(&fp, data_size); + write_long(&fp, 0); + write_long(&fp, 0); + write_long(&fp, 0); + write_long(&fp, 0); + // Bit Masks (12 bytes) + write_long(&fp, 0x1F << 11); + write_long(&fp, 0x3F << 5); + write_long(&fp, 0x1F); + for (int i = 0; i < rect.h; i++) { + for (int j = 0; j < rect.w; j++) { + write_word(&fp, IM_SWAP16(IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i)))); + } + for (int j = 0; j < waste; j++) { + write_word(&fp, 0); + } + } + } + file_buffer_off(&fp); + + file_close(&fp); +} diff --git a/src/openmv/src/omv/img/cascade.h b/src/openmv/src/omv/img/cascade.h new file mode 100755 index 0000000..c1b93bb --- /dev/null +++ b/src/openmv/src/omv/img/cascade.h @@ -0,0 +1,22 @@ +const int frontalface_window_w=24; +const int frontalface_window_h=24; +const int frontalface_n_stages=25; +const uint8_t frontalface_stages_array[]={9, 16, 27, 32, 52, 53, 62, 72, 83, 91, 99, 115, 127, 135, 136, 137, 159, 155, 169, 196, 197, 181, 199, 211, 200}; +const int16_t frontalface_stages_thresh_array[]={-1290, -1275, -1191, -1140, -1122, -1057, -1029, -994, -983, -933, -990, -951, -912, -947, -877, -899, -920, -868, -829, -821, -838, -849, -833, -862, -766}; +const int16_t frontalface_tree_thresh_array[]={-129, 50, 89, 23, 61, 407, 11, -77, 24, -86, 83, 87, 375, 148, -78, 33, 75, -28, -40, 64, -84, -563, 58, 41, 374, 285, 129, 58, 59, -12, 134, -29, 206, 192, -284, -200, 347, -7, 473, -210, -174, 1522, 79, 71, 162, -37, 7, 123, -322, 8, 110, -184, -269, 64, 596, 25, 27, 75, 81, -1136, 37, -154, 75, -45, 138, -146, -46, -267, -173, 7, -529, 93, -139, 107, 91, -23, 178, 234, 9, 53, -108, -23, -67, -279, 163, 770, 319, 0, 348, 36, 36, -96, 28, 138, -13, 119, -34, -44, -100, 15, -50, -19, 314, 117, 80, -119, -119, 80, 17, -145, -66, -90, -93, 68, -54, -138, 69, 13, 342, 1056, -149, -67, -15, -26, -15, -186, -98, -317, 96, -10, 491, 9, 285, -191, -205, 123, 373, 52, 65, 9, 130, 11, -49, 87, 124, -184, -293, 242, 27, 168, -3, -124, -52, 153, 100, 233, -66, -722, 721, -30, 249, -119, -186, 152, -99, -244, -123, 30, -8, 85, -27, 76, -181, 93, -4, 70, -141, 274, 973, -52, 43, 69, -29, 43, 25, 53, 12, -447, 33, 128, 130, 27, 107, 52, 107, -61, -159, -23, -6, -116, 271, 36, 46, -11, 46, 29, 130, 103, 30, 134, -11, -155, -159, 11, -221, -34, 138, -460, -42, -20, -38, -48, -95, 69, -98, -151, -252, 88, -15, 183, 234, -46, -49, 92, -81, 65, -37, -18, 521, 195, 219, -162, -275, 546, -856, -268, 253, -104, -142, -74, 61, 189, 63, 52, 201, 51, -76, 171, -210, -290, 68, -25, -161, 0, -91, 7, 4, 160, 254, 8, 3, -28, -97, -420, -39, 163, -53, -207, 102, -31, 175, 0, 37, 45, -214, -942, -67, -70, -150, -42, -56, 120, 98, 25, -91, -28, -166, -100, 10, -80, -121, -61, -248, -52, -82, -125, -84, -7, -128, 77, 25, -41, -5, -16, -180, -248, -134, -603, -48, 594, 210, 12, -178, 528, -373, 58, 134, 51, 60, -137, 583, -25, 74, 102, 190, -36, 167, -140, -162, 10, 112, 143, 18, 11, 144, 106, -64, -31, 85, 245, 159, 88, -112, 42, 101, -65, 199, 5, -360, 75, 144, -835, -68, 154, 9, -60, -197, -120, -189, -114, -23, -41, 46, 212, 136, -59, -140, -330, -3, 397, 149, 211, -100, 1340, 31, 662, -19, -75, 318, 77, -325, -278, -24, 130, -122, -329, 15, 137, 33, 413, -40, 29, 102, 1143, -181, -57, 564, 141, 76, 102, 234, 61, 36, 124, -180, 75, 43, -188, 339, -36, 175, -35, -17, 33, 396, -125, -249, -156, -39, 200, -170, -82, -4, -137, 79, -1, -1, -382, -318, 69, -87, -52, 32, 421, -153, 104, 2, -1182, 373, 493, -302, -135, -179, 741, -48, 18, 28, -97, -275, -267, 93, -77, -28, -164, -166, -50, -111, -361, -32, -171, 187, -577, -242, 17, -8, 1127, -108, 167, 22, 130, -169, -393, -47, 75, -139, -100, 200, -84, -94, 264, 51, -49, -108, -104, 160, -24, -139, 166, 104, 817, 50, 160, -126, -145, -252, -48, 274, -84, -91, 4, 146, 125, 22, -25, -124, -39, -233, 16, 138, -141, 192, -35, 268, -180, 70, 135, -86, 121, 226, -137, 80, -85, 133, -44, -40, -15, -171, -140, 41, -368, 106, -15, 130, 79, 7, -180, -183, -440, -526, -183, -180, -502, -81, -63, -200, 229, -40, 55, 26, 29, 19, 39, -112, -161, -125, -6, 781, 21, 98, -108, 22, 222, 0, 62, 69, 124, 26, 580, 79, -70, -25, -65, -414, -30, 181, -476, 19, 91, -49, 229, -35, 27, -74, -93, 52, -56, 128, 381, 106, 67, -7, -36, 92, -154, -22, -97, -108, 50, 395, -112, -64, -8, 49, -63, -17, -86, -69, -167, -33, -78, -181, -255, -4, 97, 87, 82, -117, 14, 233, -384, 72, 935, -749, -286, 62, 27, -65, 53, 53, -163, 61, -84, -91, -32, 62, -129, -126, -63, 144, -73, -13, 64, 122, 12, 347, -240, 183, 165, 154, 248, -81, -679, 282, 46, 6, 326, -234, 30, -73, 387, 22, 28, 141, -212, -283, -22, 280, -274, -86, 83, -192, 768, -177, 81, 33, 111, -375, -51, 60, 119, 35, -224, -60, 102, 190, 72, 668, 53, -64, 329, 144, 135, 49, 176, 124, 145, -59, 51, 41, 118, 2, 198, 132, 136, 26, -23, 52, 24, 10, -69, 115, 42, 40, 106, -104, -14, 37, 86, -209, -255, -135, -153, 508, -36, -245, 25, -72, 72, 21, -43, 855, -108, 241, -47, 188, -93, -33, 14, 202, 14, -126, 354, -559, -23, -73, -81, -235, -340, -220, -34, 226, -275, -97, 22, 87, -100, -80, -218, 29, -92, -337, 536, 58, 26, -188, 236, -24, -213, 190, 30, 88, -73, -152, -1, 102, 38, 132, -25, 210, -108, -63, 79, 137, 118, 0, -201, 313, 97, 15, -366, -61, -45, 387, 2254, 169, 101, 208, -69, -498, -14, 474, 151, 47, -82, -117, -23, -227, -60, -29, -184, 263, -60, 184, -4, 202, 119, 142, -25, 63, 11, -219, -78, -226, 230, -97, 7, -154, -98, 112, 473, -91, 54, -15, -10, 13, 154, -56, -11, -157, -142, 95, 143, -54, 52, 14, 412, 0, 47, -147, -86, 60, -21, 96, -102, -3, -165, 115, 187, 162, 206, -70, 328, 400, -63, -62, -67, -107, 36, -110, 31, -65, 85, 350, 97, -160, -319, -69, 486, 639, -188, -42, 392, 56, 9, 136, -136, 11, -269, 8, 91, -235, 27, 50, -33, 150, -1647, -90, -53, -52, 88, 48, -80, 263, 446, -139, -15, -44, -47, 106, 17, -195, 1, 472, 65, 231, -43, 508, -22, 48, -176, -135, -87, -50, -69, -10, -184, 159, 27, -67, 25, 187, 16, 0, 29, -204, -102, 126, 189, -13, -99, 49, 53, 242, -168, -344, 182, 100, -17, 100, -348, 89, -68, 133, 10, 226, -435, -32, 309, -380, 202, -48, 351, 331, -138, 63, 224, 87, 32, -153, 652, -282, -138, -259, 30, -39, -535, 235, -29, 127, 146, -129, -79, -29, 33, -178, 108, 131, -295, 128, -1, 11, 134, -59, 155, 11, -170, -101, 41, -85, 91, -152, -43, 227, 88, 0, 59, 441, 147, -16, 85, -122, 106, 43, 35, 87, 305, 19, 7, 4, 115, -133, 92, -88, 31, 59, 114, 23, -40, -16, -92, -162, -71, 36, -32, 110, -84, -294, -110, -194, -446, 55, -27, -16, -154, 35, -131, 239, -167, -81, -18, 68, 38, -80, 44, 155, 67, -81, 45, 21, -45, -43, 431, 224, 72, -127, -234, -46, 125, 7, 46, 333, 219, -98, 27, -132, 155, 63, -181, -94, 79, 425, -77, 158, 93, -128, 39, -201, -161, 196, 210, 58, -375, 26, 146, 207, -59, -158, -165, 97, 35, -544, 40, 20, -250, -1, 13, 86, 30, 101, -145, 81, 61, -94, -76, 1846, 48, -101, -183, -59, -100, 94, -102, 4, 63, -109, 5, -2, -130, -20, 127, -137, 49, -142, 40, 244, -267, -380, -168, 87, -104, -168, -72, 36, -47, -30, 3, -125, -77, -33, -142, 77, -77, -364, 28, -115, -1, -443, 65, 35, -103, -55, -31, 293, -55, 12, -208, -36, 877, 57, 174, 81, -137, 260, 89, -321, 58, -275, 534, -189, -122, -1, -91, -6, 49, 99, -193, -101, 89, 770, -318, -199, -70, -11, -404, -89, 250, -100, 138, 156, -82, 101, -99, -108, -14, 438, 184, 181, 4, 292, 146, -85, 1741, 46, -62, -62, -77, -13, 381, -51, -110, -96, -58, 115, 208, 47, -60, 935, 454, 13, 349, 90, -64, 1356, 36, 188, -154, -335, 891, 60, 214, 37, 32, -106, -12, 234, -25, -165, -83, -70, -99, 232, 1, 40, -215, -56, -124, -1230, -147, -225, 138, -33, -22, 12, 219, -513, 379, 157, -8, 39, 98, -73, -43, -29, 98, -75, 64, -199, 27, 40, 60, 397, 197, 40, -163, 93, 27, 244, 28, 64, -203, 214, 91, 168, -88, -339, 34, 323, -369, -119, 28, -33, 80, -60, 103, -64, 120, -34, 100, -138, -8, 124, 16, 113, 32, 180, -132, 85, 103, 26, -239, 130, -124, 61, -200, 340, 97, 67, -48, 0, 78, -41, -57, -422, -391, -169, 9, 439, 13, 119, 46, -49, -52, 100, 188, -111, 164, 94, -97, 317, -54, -88, -292, -22, 109, -161, 106, 200, 151, 323, 118, 25, -269, -282, -477, -5, -182, 209, -129, 86, -566, 213, 106, -49, -99, -103, 51, 234, 68, -93, 0, -31, 385, -255, 71, -90, -42, -38, -118, -86, -151, 43, 670, 388, 144, 52, 569, 48, -40, -24, -5, 132, -57, 4, 0, -1, 16, 58, -226, 383, 109, 15, -130, -92, 103, -127, -108, -56, -257, -183, -83, -32, 35, -111, -67, -56, 119, 153, -102, -261, -38, -3, -89, -73, -101, 643, 282, -45, -56, -126, 87, 381, 121, 0, -172, -92, -52, 114, -113, -25, -83, -50, -165, 121, 28, 66, 205, 8, 102, -64, 152, -324, -70, 134, -481, 493, 17, -297, 725, 34, -53, 77, 87, 259, -132, -96, 76, 127, -45, -52, -52, 281, 21, -158, 25, 717, 476, -94, -210, 920, 38, -485, 154, 90, -148, -540, -170, -135, 64, -161, -277, -109, 163, 412, -331, -87, -43, 3, 14, 77, -104, -16, -3, -202, 47, 141, -33, -91, -126, 179, 176, 111, 38, 386, 697, -193, 458, -58, 139, 88, 89, 337, 346, -225, -265, -93, 224, 0, 402, -29, 205, -23, 57, 87, -119, 1, 7, 35, 260, -114, 200, -120, 508, 32, 124, 103, 41, -68, -11, 173, -198, 118, -164, -168, 48, -87, -97, 73, -178, -37, 194, -58, 15, 14, -119, -26, -123, 32, 36, 393, -134, -54, 62, 49, -312, -49, 89, -11, -199, -42, -27, 35, 81, 90, -213, 80, 94, -61, -204, -283, 19, -138, -66, -205, 233, 167, -12, -133, 403, -156, -188, -489, -493, 289, 34, 93, 2, 141, -18, 96, 52, -46, -170, -382, -111, -89, -39, 284, 127, -203, -83, -62, -207, -84, -126, -18, -187, 68, 13, 100, -326, 182, -513, 73, 78, 163, 55, 66, 45, 160, -39, 114, -96, 110, 1, -168, 27, 196, -12, -35, -30, -7, -353, 191, 0, -66, 187, -112, -113, 31, -2, 452, 281, 7, 787, 644, -202, 212, 204, -174, -153, -152, 57, -1, 131, -17, 40, 382, 70, 34, -57, -31, 114, -77, -76, -149, 132, 244, 40, -144, 11, 33, 364, -123, -89, 154, 11, -43, 531, -72, -315, -78, -209, 8, 104, -97, -26, -154, 886, -54, 291, 229, 165, 258, 42, 256, -161, -22, 441, 69, 127, -94, -45, -19, -71, 77, 29, 77, 127, 85, 46, -233, 295, -81, -68, -163, 110, -16, 93, -282, 176, 35, 59, -47, -449, 185, -110, 73, 206, -122, 155, 760, -16, 41, -47, -26, 43, -83, 9, -6, 35, -99, 304, 69, -100, 123, 49, 355, -173, -10, -232, 96, -85, 29, 1399, 25, 133, 0, 2, 223, -41, -77, -21, -44, -204, 49, -9, 12, 16, -30, 212, 75, 716, 221, -1312, -110, 317, 97, 47, 133, -181, -239, 79, -183, -247, 47, 114, 267, 39, 10, 130, 135, 194, -80, -224, -92, 438, -149, 57, 85, 201, 148, 168, 64, -66, -12, -564, -39, -101, -571, -336, 15, -27, -65, -208, 68, 65, 14, -352, 135, -16, -98, 35, -113, -796, -445, -79, 12, 242, -222, -161, 337, -30, 30, 28, -63, -11, -289, -47, 2, -151, -133, -306, 169, -118, 189, 1041, 9, -339, -46, -528, 157, 417, -78, -248, 101, 109, 61, 107, -153, -21, 72, -139, -65, 80, -424, -78, -52, -66, -522, 78, 133, 38, 20, 169, -312, -298, 244, 83, -328, -73, 46, -104, -3, -59, 35, 224, -443, 94, 11, -8, -92, 340, -27, 313, 22, -42, 113, -95, -227, -166, -30, 69, -151, -80, -96, -177, -90, 67, -134, 292, 3, -34, -70, -76, -37, 75, -206, -96, -111, 26, 95, 53, -27, -92, -261, -204, 27, -228, 1308, 331, -61, 191, 24, -140, -143, 12, -57, -27, -216, -8, 75, 51, 52, -73, 7, -60, -61, 59, -44, -37, 18, 96, 130, -75, 80, 1685, -170, -42, 50, -35, 66, -42, -50, -206, 202, -168, 4, -205, -35, -205, 418, -58, 42, -48, 295, -77, -19, -238, 4, -202, -487, -74, -32, 212, 273, -56, -72, -172, -55, -45, -503, 195, 130, 17, -251, -11, -280, 424, 64, -40, -36, -261, 159, -163, 206, 189, 254, -265, 112, 1, -17, 193, 51, 188, 813, 68, 8, 91, -56, -31, -54, 200, 83, -68, -693, -464, -318, -63, -270, 34, 145, -159, -40, -94, 12, 53, 60, -246, 212, 101, -49, -404, 481, -77, -116, 53, -477, -15, 127, 103, -115, 149, -296, -170, 195, 269, 56, -113, -65, 303, -3, 73, -10, -37, 201, -125, 410, 13, 145, 1, 103, -21, 6, -66, -121, -6, -221, -271, 114, 118, -83, 50, 177, 762, 130, 57, -25, -22, 68, 106, -109, -69, 24, -11, -179, 211, 33, -216, 215, -51, 47, -97, -252, -7, 144, -75, -157, 408, 345, 164, 241, 612, 2, -136, 38, 176, -276, -1276, 121, 43, -118, -23, 116, -118, 102, 49, -174, 42, -283, -19, -57, -62, -41, -208, 125, -45, -25, 321, -41, 127, 164, 66, -186, -74, -57, -158, 129, -44, 49, 289, 2176, -60, -9, 204, -195, -374, 155, -63, -63, -235, -24, -286, -102, 70, -181, 180, 65, -379, 290, 236, -67, 98, 51, -222, -54, 25, 118, -90, 21, 352, -35, 27, -26, 36, 13, 169, -27, 125, -30, 364, 29, -74, -105, 447, -46, -235, 420, 110, -55, -1317, 837, -288, 154, -287, 258, 149, 16, -201, -293, -155, -12, 79, 46, -137, 376, 15, 52, -586, -396, -36, 65, 288, -155, 2113, -134, -148, 27, -66, 34, -563, 724, 32, 449, -124, -94, -12, -136, 54, 60, -54, -66, -118, -415, 154, -1169, 629, 0, -84, 153, 234, 20, -223, 103, 99, 147, -409, 345, 65, 138, -253, 286, -114, -52, 88, 411, 106, 116, 158, -190, -175, 15, 173, 80, 3, -17, 69, 147, -290, -258, 121, 155, -136, -129, 4, -293, -332, 18, -172, -268, 74, -211, -193, 71, -103, -166, -154, -54, 0, -46, 152, 13, -92, 95, -57, 30, -47, 215, 215, -48, 392, -65, 142, 142, 66, -181, -22, -269, -300, 67, -37, 24, -3, 841, -69, -78, -106, -89, -98, 193, -188, 108, -199, -76, 51, -4, -201, -71, -60, -938, -520, 42, 28, 1188, -975, 255, 19, -113, -69, -203, -306, 131, -386, -63, -16, 12, -41, -158, 141, -19, 2, 144, -96, -7, -68, 2705, 449, 55, -93, -335, -215, -103, -179, -74, 96, 140, 105, -108, 249, 592, 218, 46, -9, -121, 111, -14, -51, -363, -78, -68, 52, -55, 77, -26, -99, -121, 20, -23, 68, 156, -233, -220, -10, 1217, -364, -230, 151, -34, -9, -293, 21, -25, 63, 106, -49, -277, -60, 102, 77, -87, 38, 940, -155, -55, 148, 27, 395, -146, 44, 324, 134, -113, -16, 30, 459, -486, -170, -114, -512, 969, -120, 154, 295, 40, 213, -179, -157, -404, -499, -490, 126, 44, 232, 4, -115, -655, 20, 192, 99, 287, 40, -230, 449, 85, 143, 163, -19, 9, 103, -131, 308, -75, -52, -108, 90, 600, 14, 38, -35, -160, 101, -143, -75, -55, 25, -75, 58, -133, -10, -3, 194, -28, -176, 84, -91, 204, 253, -171, -13, 99, -70, -16, -58, -37, -506, -336, 268, -129, -326, -77, -20, -50, 5, 121, 115, 124, -70, -344, 30, 231, -21, -61, 224, -80, -275, -58, 122, 212, 168, -526, 9, 31, 186, -322, 32, -55, 118, -112, -298, -57, 177, 120, -130, 155, -91, 241, 127, 153, -85, -104, -29, -208, -84, 43, 130, -97, -24, 97, 114, 59, 445, -57, 16, -20, -348, 8, 1490, 904, -66, -197, 71, -140, -18, 528, 124, 180, 12, -107, -114, 48, 6, -14, -129, -131, 636, 360, -6, 38, 152, 328, -3, -20, 489, -18, -121, 109, 181, -99, 80, 22, -950, -104, -26, 16, -146, -58, -517, 281, 351, 63, 332, 75, -353, 296, -320, 396, -163, -39, 1, 49, -85, 237, 0, -70, 125, -3, 360, -159, 328, 161, 84, -274, 191, 321, 271, 123, 70, 82, 135, -60, -42, -117, -19, 1318, -69, -30, -122, -46, 19, 20, 792, 22, -279, -143, 20, 390, -257, -697, 43, -170, 520, 338, 349, 227, 18, 53, 237, -93, 197, 105, 28, -141, 120, -9, -392, 68, 106, 1, -27, 77, 0, -312, 205, -11, 66, 154, -50, 237, 19, 187, 87, 642, -42, 9, -95, -28, -140, -86, 8, -17, -58, -33, -38, -155, 19, -18, 21, -39, 184, 58, 670, 10, -15, -103, -79, 59, 211, -155, -121, -160, -119, -342, 1720, 245, -77, -24, -238, -50, 190, 4, -363, -94, 176, 0, 36, -72, 25, 93, -88, 252, -319, 46, -104, -155, 40, -56, 34, -292, 40, 450, 144, -457, -465, 68, -32, -135, 51, -172, 103, -99, -50, -466, -347, -100, -36, 45, -120, 26, 57, -54, 1164, -971, -457, 523, -257, 71, 5, 112, -178, 45, 85, -91, 133, 50, 34, 153, -57, 233, 20, -100, -46, 141, 99, -32, 143, 18, -340, -57, 5, -68, -314, -969, -411, 5, 90, -460, 67, 278, 65, 19, 27, 19, 10, 11, -123, 58, -247, -81, 127, 74, 4, -150, 49, 306, -961, 577, 25, -234, -226, -88, 105, -53, 9, 36, -36, 16, 102, -24, 17, -138, 182, -167, 161, -288, 146, -175, -86, -644, 32, 96, 305, -2, -66, -135, 199, 9, 185, 438, -165, 130, -235, 55, 292, -61, -41, 15, 66, -164, 110, 214, -78, -15, 310, -90}; +const int16_t frontalface_alpha1_array[]={534, -477, -386, -223, -199, 142, -432, -378, -219, 318, -414, -497, -142, 68, -684, -277, -90, 237, 296, -107, 373, 286, -89, -155, 99, -259, -421, 118, -167, -357, -129, 93, -77, -103, 269, -416, 72, -259, -42, 388, 451, -80, -25, -103, 43, 227, -95, 16, -447, -240, -13, -468, 295, -400, -147, -373, -213, -80, -111, 381, -246, -626, 44, 124, 45, -501, 253, -660, 368, -126, -596, -216, -369, 46, 17, 100, 37, 63, -193, -93, -594, 108, 284, -851, -311, -123, -276, -307, -112, -47, 77, 319, -152, 72, 123, 68, -335, 116, -443, -49, -412, 190, -68, -15, -89, -268, 211, 52, 52, -332, -335, -269, -351, -9, -255, 370, -95, -147, 4, -20, -294, 95, 67, 193, 57, -323, 222, -355, 16, -137, -90, -150, -85, 178, 220, 49, -228, -322, -220, -191, -323, -251, 164, -61, -87, 281, 402, -70, -280, 78, 66, -315, 104, -24, -105, 64, -240, 318, -83, 89, 14, -262, 263, 55, -408, -263, -378, -61, 74, -59, -309, 62, -350, 54, 83, -72, -591, 73, -69, -392, 19, 36, -282, 3, -88, 51, -104, -569, -73, -227, -285, -258, 66, -146, -141, -329, 446, -269, 145, 334, -118, -106, 92, -228, 75, -203, 39, 8, -100, 22, 141, -473, -123, -115, -216, 90, 47, -320, -208, -237, 144, 205, -217, -103, -391, 161, 150, -65, 74, -101, 53, 112, 240, 2, -259, -96, -206, -270, 51, -97, 54, -262, -263, -53, 225, 267, 35, -425, 204, -245, 50, -265, -315, -194, -99, -183, 141, -114, -279, 214, -65, 80, -268, 41, -176, 63, -129, 10, 36, -229, -116, 86, -202, -584, 100, 8, -277, -481, 37, -260, 39, -197, -29, 17, -450, 245, 119, 181, -281, -279, -67, -56, 47, -237, 502, 54, -300, -287, -43, 211, -295, -268, -279, 108, -235, -408, -169, 49, -162, -48, -27, -276, 87, 121, 249, -556, -164, -377, 108, 6, 40, -103, -510, -159, 259, -262, -291, -145, 78, -440, 59, -311, 83, -81, -28, 101, 0, 192, -212, -152, 40, 8, -133, -136, 51, 11, -233, 23, 54, -69, -26, 16, -237, 34, 50, -292, 43, -121, -553, 11, -8, -337, 94, -65, -19, -201, 435, 198, -382, -546, 145, 173, 63, 3, -2, 115, -243, -515, 101, -63, -14, 11, -125, -76, -153, -7, 95, -255, 36, -54, -337, 126, 108, -7, -202, -576, -65, -57, -73, -8, 152, -122, 58, -66, -153, 181, -143, -182, -285, -104, -97, -179, -139, -25, 216, 67, 39, -509, -82, 152, 5, -112, -228, 54, 3, 257, -376, -208, 29, 33, -301, 161, 47, -238, 9, 93, 50, -429, -787, 54, -293, 214, -71, 45, 246, 2, -136, 210, -50, -6, -347, -165, 215, 49, -186, -92, 14, 120, -290, 251, -72, -163, 95, -334, -523, 198, 44, -384, 73, 354, -57, -406, -305, -39, 66, -22, 192, 31, -93, -19, 200, -229, 211, 4, 289, -147, -5, -139, -313, 37, -71, -62, -219, 177, -42, 112, -250, -231, -202, -77, -230, -107, 117, 233, -376, -268, 74, -329, -219, 41, 40, 5, -42, -249, 252, 121, -245, -134, 43, -290, 66, 50, -13, 272, -47, -7, 255, -7, 0, -391, 8, 196, 41, -250, 118, 65, -206, -336, 51, 249, -48, -174, 48, -60, 63, -266, 131, 414, 764, 154, -158, 169, -287, -275, 207, -5, 173, 14, -33, -96, -149, -77, 151, 248, 233, -154, 11, -239, 46, -330, -11, -3, -68, -131, 106, -63, -57, 16, 48, -242, 94, 246, -785, 58, 0, 243, -25, 2, 165, -9, 177, -103, -165, 250, -26, 156, -260, -105, -149, -237, 30, -148, -98, 301, -220, -191, 235, 68, -72, -157, 147, 83, 22, 88, 60, -190, -231, -88, -239, -136, 235, -181, -222, -58, -77, 68, -302, -139, -69, -233, -112, 6, 202, 205, -51, -11, -231, 90, -50, -358, 0, -125, -312, 95, -75, -368, -577, 96, -75, -255, 12, 38, -3, -36, -4, -443, -61, 1, 9, 19, -434, 161, -85, 58, 49, 23, -446, -61, 301, 35, -139, -55, 16, 175, 445, 78, -54, -203, 95, -3, 310, -5, -271, -8, 9, -20, -491, 123, -50, 50, -49, 463, 199, 39, -42, -26, -9, -14, 71, 32, 5, 48, 18, 12, -69, 13, 97, 39, 6, 41, -157, -217, -208, -93, -304, 84, -130, -268, -129, -254, -24, 59, -26, 0, -167, 72, 39, -74, 349, 312, -209, -312, 30, -299, -273, -92, 125, 150, -19, 70, -1, 210, 33, -232, 2, 455, 146, -82, 49, 17, -99, -6, -491, -328, -103, -186, 148, 234, -132, 61, 42, -349, -437, -80, 38, 190, -104, 208, 84, -321, 353, -9, -47, -114, 173, -3, 86, -271, 37, -62, 33, -268, -387, 35, 73, -69, 47, 83, 29, -283, 205, -67, 4, 3, -78, -411, 19, -1, -61, 490, -64, -177, 46, -7, 16, 2, 38, 99, -397, 55, -12, -65, -46, 139, -177, 75, 236, -203, 84, -351, 16, 92, -39, 34, 27, -2, 0, -120, -2, -88, 383, -254, -147, -8, 102, 46, 139, 174, -230, -144, 92, -142, -274, -183, -120, 54, 171, -244, 208, 315, -78, 54, -231, 57, -101, 47, 39, 55, -378, -43, 9, 85, 1, 115, 39, -333, -62, 7, -57, 52, 175, -2, -51, 121, -283, 259, 106, 54, -296, 90, -393, 51, -6, 43, -306, -279, 71, -11, -67, 154, 97, 33, 30, -87, -43, 156, -124, -1030, -100, -22, 293, -5, 9, 144, -44, 323, 171, -105, -234, 0, -95, -108, -42, 38, 352, -86, 195, -177, -3, -26, 273, 47, -56, 65, -2, -73, -9, 84, -89, -368, -302, 566, -478, -196, -161, 218, -8, -49, 527, -29, -4, -10, -170, -14, 156, -146, 14, 44, -171, 75, -72, -27, -13, 115, -520, 43, -5, 77, -79, -460, -13, 53, -51, -244, -36, -279, 26, 15, -343, 12, -262, 21, -37, 168, -232, -127, -108, -122, 130, -59, 103, 115, -217, -238, -327, 149, -13, -222, -19, -63, -287, -371, 137, 17, 292, -63, -10, 150, 39, 43, -38, -102, 71, 0, 105, -365, -64, 11, -240, -69, -264, 161, 41, -64, -74, -2, 28, -49, 79, -1, -117, -3, -19, -68, 46, -48, -37, -134, -98, -1, -148, 5, -166, -86, 38, -64, -28, -249, 97, -266, -1410, 244, 2, 57, 42, -221, -721, -331, -208, 168, 1, 78, 65, -367, -43, -166, -13, -235, 137, -139, 39, -62, -130, -55, 29, -3, 311, -64, 57, 64, -83, -14, 0, -78, -62, 120, 98, -12, 54, -43, 29, -11, -103, -84, -185, -40, 49, 210, -110, -7, 28, 557, -12, -83, 294, -99, -429, -249, 53, -42, 60, -237, -188, 36, 2, -304, 622, 183, 40, -208, 238, -144, -202, -362, 97, -104, -61, -223, 39, -293, 39, 10, 111, 111, -24, -97, 228, 220, 153, -406, 43, 130, -110, -80, 270, -183, 63, -176, -151, 11, -157, -78, -351, -143, 1, 400, -404, -397, 44, -334, -353, -181, -10, 147, -126, -125, -154, 60, -20, -308, 59, -207, 157, -75, -156, -136, -329, -43, -28, 261, -200, -225, 29, -207, -18, -329, 121, -15, 44, -51, -17, -326, 31, 3, 158, -92, 134, -43, -304, 214, 90, -225, -36, -74, -8, 177, -165, -7, -2, 217, -531, -219, 98, -441, 140, -9, 149, -3, 38, 132, -5, -220, -116, 33, 33, -64, 5, -100, 21, -46, -158, -12, 45, -215, -48, -203, -60, -14, 67, -171, 172, 77, 37, -47, 48, 115, 34, -53, 82, -51, 40, -160, 42, -64, 39, 145, 146, -98, 56, -73, -166, -74, 116, -131, 4, 100, 304, -174, -217, -282, -50, -104, -75, -334, 60, 74, -620, 225, 205, 37, -208, -181, -186, 43, 708, 29, -1, 59, -79, -12, -297, -69, -138, 46, 160, 61, -240, -19, 10, 43, -8, 24, -101, -58, -70, -27, -12, 38, -5, -205, -53, 51, -46, 127, 299, -16, -59, -210, 155, -10, -294, -2, 96, -25, 171, 40, 97, 38, -174, 65, -7, -90, -9, -6, 27, 119, -72, -5, -83, -313, -4, 167, -133, -200, 0, -13, 4, -159, 45, 11, 116, 85, -598, -169, 117, -68, -47, -6, -8, 1, 108, -5, -8, 28, 74, 30, 37, -137, -15, -115, 310, -590, -183, 18, -313, 34, -7, 34, -37, 49, -95, 207, 214, -242, 11, -497, -54, 153, -56, 161, -59, 46, -178, 88, -224, 60, -15, -50, 247, -15, -116, 29, 463, 59, 126, 155, 102, -217, -202, -172, 9, 35, -35, 35, -51, -119, -241, 83, 70, 60, -147, -156, -144, -205, -207, 35, -42, 369, 34, -86, -29, -254, -123, 9, -278, 244, -265, 230, -259, 157, -21, 16, -239, -215, 155, -7, 33, -289, 194, 76, 5, -218, -15, 91, 0, -8, 151, 152, -300, -4, 41, -57, 70, -194, -58, 49, 42, 328, -138, 162, -127, -303, 5, 7, -53, 0, -56, -2, 114, -52, -196, -361, 49, 215, 32, -119, 132, -7, 62, 250, 51, -65, 43, -219, 143, -65, 1, -154, 107, 58, 23, -68, -185, -89, 29, -2, 52, 148, 4, -84, 351, 0, -3, 96, -703, 121, -148, -2, 89, 364, 61, -2, -4, -231, -54, 50, -23, -141, 47, 496, -67, -140, -655, -63, 41, 56, 79, -244, 32, -15, 10, -11, 10, 7, 264, -17, -152, -16, 14, -1, 37, -45, -152, -276, 199, -16, -4, -14, 87, -67, -33, 7, 6, 115, -50, -138, -3, 17, 174, -52, 182, -94, -220, -69, -88, -81, -176, -53, -126, 343, 11, -182, 257, -3, -209, 138, -86, -306, -227, 42, 160, -72, -163, -196, 116, -195, 11, -12, -5, -245, -179, -72, -64, -178, 117, 46, -161, -263, 88, -74, -113, 45, -2, 423, -1, 0, -158, 180, 100, -6, 120, 82, -314, 11, -42, 86, -218, 14, 133, 160, -157, -216, -16, -45, -7, -62, -60, 100, -68, 44, -277, 184, -304, 161, 338, -86, -65, 36, -298, -101, 126, 479, -227, -298, -171, -122, 30, -19, -51, 236, -68, -138, 4, -3, -45, 53, 5, -4, -48, 104, -52, -434, -7, -51, -115, 60, -46, -70, -118, 106, 37, 192, -48, 90, -164, 4, 270, 76, -55, 61, -8, -1, 19, 20, -35, -476, -47, 36, 411, -207, -356, 8, -141, 5, 113, 46, -16, 51, -81, 222, 163, 44, 61, 138, 612, 40, 0, -29, -269, -51, -54, 28, -439, 165, -2, 50, -221, 35, 86, -640, 129, -750, -153, 86, -283, 114, -266, 8, 135, -137, -128, -84, -81, 27, -36, 241, -139, 3, -80, -1, -195, 61, -24, -202, -26, -103, 52, 0, -1, -93, -365, -10, 67, -214, -125, -48, 59, -9, -456, -55, -45, -2, 77, -243, 8, 250, -5, -14, 167, 6, -1, 87, -1, -134, -149, 5, -93, 9, -37, -55, -277, -39, 11, -396, 42, -197, 28, 283, 70, -206, 36, 50, -12, -42, -32, -8, -16, -93, 30, -133, 166, 44, -50, -130, -17, -104, -54, -127, -52, 46, 3, -53, 63, -488, -182, -43, 48, 1, 43, -578, 616, -69, 80, -371, -4, -59, 36, -56, -29, 6, 45, -37, -134, 225, -123, -54, -18, -63, 2, -45, 33, -11, 44, -289, -57, 116, -38, -174, 166, 114, -22, -119, 74, -309, -11, -68, -33, 497, 39, -182, 235, -57, -185, 319, -370, -200, -218, -38, 140, 93, -8, -157, -16, -87, -77, 19, -249, 47, -15, 83, -75, -310, 33, -169, 42, -13, 51, -201, 73, 442, 4, -19, 81, 196, 47, -60, 44, -11, 205, -209, 38, -186, 145, 10, -507, 128, 102, -196, 221, -143, 10, -49, 47, -12, 362, 337, 12, -53, -319, 66, 58, -220, 80, 64, 68, -138, 183, -149, -190, 45, -275, 6, -115, -69, -125, 106, 41, -282, 166, 107, 90, -74, -338, -224, 66, -253, 162, 6, -144, 0, -24, -167, -119, -271, 129, -78, -285, -222, 168, -58, 46, -84, -30, 98, -228, 137, -14, -390, 19, -50, -163, 21, -110, 102, 135, -99, 224, -298, 279, 35, 34, -3, 45, -135, -28, 100, -65, -6, 202, -122, -44, 0, 4, 51, 47, -15, -83, -159, -8, 50, 52, -145, 191, 217, 42, -340, -15, 195, 57, -407, 30, -335, 0, 167, 18, -172, 85, 116, -11, 68, -212, -172, -18, 7, 34, -152, 103, -278, 74, 167, -501, -58, 40, -99, 439, -97, -791, -35, -16, -144, 64, -670, 15, 239, 35, -3, 15, 182, 37, -95, -60, -7, 47, -39, 38, -42, -18, -5, -46, -116, 68, -39, 17, 70, -787, -374, 226, 35, -263, 19, 30, 172, 54, 114, 9, -50, 34, 215, 44, -45, -36, 267, 28, -201, -155, -3, -523, -107, 6, -44, -56, -17, 330, -297, 17, -45, 56, 158, -118, -32, -77, -57, 64, 74, 49, -193, 21, -68, 34, -103, 41, 79, -68, 39, 293, -182, 106, -341, 36, -12, 163, -55, -206, -81, -164, -117, 117, 93, 6, 44, -246, -181, 18, -191, 174, -32, 18, 244, -72, 98, 0, 217, -236, -139, -1, 184, 49, 29, -13, -27, -46, 42, 52, 239, 0, 0, 185, 256, -11, 3, -241, -111, -45, 148, -5, -36, 249, -21, -529, 112, 73, -146, 88, 143, -37, 61, 110, 5, 46, 38, -50, 0, 323, 166, -264, -122, -53, 132, -54, 46, -37, -72, -114, 10, 101, 563, -71, 87, 73, 163, 20, -114, -251, 58, 214, 29, -9, -346, -45, 32, 205, 41, 39, -471, -206, -35, -6, -188, -116, 53, 102, -5, -127, 45, 11, 44, -118, 13, 38, 35, -73, -77, -251, 12, 60, 120, -53, 42, -144, -911, -9, -144, -7, -136, -56, 36, -88, 245, 445, 355, 13, -23, 9, 243, -34, 58, -56, 329, -1012, 96, -6, 43, -239, 33, -292, 126, -79, -97, -47, -151, -39, 82, -40, 193, -226, 61, -479, 33, -6, 119, 102, -400, -492, 34, 261, -24, 28, 154, -48, 29, -71, 185, -49, 39, -14, -412, -15, 41, -45, 1190, -43, 233, 56, -230, -96, -97, -46, -57, 181, 122, -47, 10, -59, -117, 85, -42, 57, 38, -380, -49, 34, -277, -151, -125, 152, -302, -156, -292, -421, -79, -177, -183, 57, 264, 115, -218, 148, -96, -67, -7, 52, 171, 44, -214, -8, 107, 17, -40, -181, -41, 99, 4, 12, -69, 216, 39, -237, 132, 35, -230, 50, 24, -15, 62, 156, 232, -80, -170, 15, 204, 48, 150, -65, -3, 52, -274, -148, -169, -123, 147, -13, 31, 28, -444, 34, -120, 178, 431, 203, -259, 36, 129, -40, -139, -44, 64, 238, -8, 89, 17, 36, -263, -50, -198, 33, -39, 38, -182, 284, 238, -50, 107, -132, -11, 13, -60, -226, -52, 34, -44, 14, 40, 182, -40, -88, -142, -924, 132, -22, 7, 60, -10, 117, -195, -957, -163, 49, -41, 5, -434, 303, -104, 39, 125, -62, -12, 111, 48, -112, -52, 79, -79, 35, -130, 122, 115, 33, -10, -88, 1, 20, 297, -82, -46, 0, -37, -101, -46, 37, -15, 87, 79, -9, -45, -258, -137, 123, 67, 9, -153, 39, -37, 3, -4, 91, 306, -158, -467, -7680, -61, -8, -39, -15, -165, 278, -66, 35, -53, 37, 7, 323, -32, -175, -122, -120, 65, -123, -61, 194, -89, -202, 120, 171, 63, -55, 71, 14, -255, -305, 38, -363, -72, 121, -15, -219, 42, -300, 67, 9, -10, 73, -360, -54, 86, -64, 10, 135, 64, 1, -127, 21, -133, -161, 329, 213, 28, -345, -346, 103, -67, 150, -42, 3, -4, -61, -137, 192, -41, -44, 59, 64, 33, -214, 603, 48, 37, -11, 45, -252, -41, -61, 36, -266, 50, -232, -7, -255, 187, 71, 1, -51, 165, -47, -74, -17, -3, -53, -91, 277, 54, 132, -112, 8, 3, 87, 84, -64, 35, -3, 48, 89, -9, -109, 170, -125, 33, -14, -147, 249, 45, -207, 71, -34, -17, -46, -40, 74, 113, -49, -2, -108, -218, 214, 25, -47, 64, -90, 41, -37, -54, -182, 8, -69, 92, -12, 33, -275, 6, -66, -454, 76, 50, -110, -130, 199, -161, -11, 30, -4, 22, 10, -486, -15, 227, -56, 147, -138, -20, -51, 106, -7, -30, 84, -5, -112, 30, 234, 28, -36, 51, 83, 40, -19, 29, -42, 57, -49, 29, -229, 91, -117, 60, -7, -130, -138, -227, 206, 3, -11, 18, -50, -1391, 114, -3, -38, 118, -422, -9, 88, 31, -15, 4, -70, -45, -82, 32, -127, 11, -10, 0, -391, 9, 25, 159, -238, -103, 24, 95, -59, 10, -127, 8, -128, 9, -16, 124, 34, -113, 7, 3, 3, 74, -103, 84, -136, -369, -202, -68, -139, 5, -127, -202, 204, -84, -69, -135, -144, -44, -23, -14, 60, 45, -109, 148, 8, 17, -321, 136, 298, 100, -188, -36, 30, -362, 113, -356, 131, -14, -20, -221, 133, -41, -43, -1, 162, -86, -8, 165, 13, 167, 49, -238, -174, 3, 257, -59, -185, -56, 42, -61, 130, 231, 35, -169, 205, -85, -142, -15, 87, 71, 300, 209, -47, 83, 50, -239, 6, -54, 189, -49, 178, 100, -18, 244, -13, 19, 13, 184, 36, 10, 137, -11, 8, -66, 40, -187, 21, -90, 72, -215, 38, -48, 113, -14, -79, 420, -199, -59, -92, 199, 302, -120, 56, -9, 107, -42, 40, -1, -7, -58, -15, -76, 56, 311, 3, -382, -98, -54, 0, -159, -108, 6, 33, 301, 8, -81, 216, 94, -133, -15, 202, -299, 10, -91, 53, -48, 65, 8, -253, -34, 86, -46, -251, -8, 298, 163, -59, -56, 41, -43, 66, -196, -69, 19, -9, -45, 48, 180, 17, 192, 49, -12, -114, 166, -14, -39, -156, -12, 28, -204, -48, -34, 124}; +const int16_t frontalface_alpha2_array[]={-567, 339, 272, 301, 322, -479, 112, 113, 218, -402, 302, 179, 442, -558, 116, 137, 238, -169, -76, 347, -50, -135, 292, 197, -387, 375, 256, -408, 212, 108, 269, -344, 371, 310, -117, 39, -400, 59, 327, -77, -13, 393, 239, 246, -757, -112, 102, -677, 72, 59, 275, 25, -274, 196, 353, 132, 149, 299, 244, -35, 70, 60, -343, -230, -418, 46, -97, 63, -75, 161, 13, 99, 25, -322, -609, -70, -291, -324, 69, 181, 9, -12, -89, 54, 277, 359, 189, 96, 323, 117, -245, 11, 138, -381, -134, -409, 39, -184, 17, 174, 19, -55, 335, 312, 217, 76, -83, -214, -171, 35, 19, 49, 17, 199, 31, 3, 135, 100, -542, 252, 24, -37, -148, -43, -163, 64, -69, 60, -323, 77, 135, 61, 132, -3, -66, -151, 267, 141, 163, 136, 92, 92, -128, 218, 292, -46, -80, 267, 50, -340, -179, 57, -131, 158, 121, -175, 29, -14, 211, -45, -396, 61, -81, -211, 13, 33, 9, 126, -146, 163, 16, -255, 9, -266, -138, 113, 0, -165, 205, 54, -270, -219, 16, 162, 144, -385, 96, 31, 173, 243, 125, 127, -320, 152, 77, 57, -25, 47, -119, -67, 106, 151, -117, 36, -249, 46, -339, -536, 131, -328, -118, 11, 88, 109, 42, -120, -427, 9, 59, 25, -48, -97, 50, 129, 59, -81, -3, 266, -213, 116, -384, -98, -27, -430, 61, 119, 45, 18, -395, 96, -317, 13, 58, 314, -11, -55, -486, 1, -21, 16, -195, 210, 75, 148, 229, 129, -180, 181, 68, -98, 66, -150, 43, -224, 60, -144, 98, -355, -273, 50, 111, -114, 57, -1, -133, -386, 47, 0, -568, 15, -303, 31, 181, -269, 49, -64, -54, -71, 62, 14, 50, 269, -440, 15, 7, -123, 41, 10, 82, -67, 38, 10, 39, -108, 47, 0, 79, -166, 39, 391, 166, 9, -25, -87, -4, -7, 42, 0, -45, -327, -388, 83, 38, 284, -157, 101, 73, 115, -174, 15, -442, 31, -207, 172, 215, -121, 242, -80, 45, 63, -109, -409, 96, 63, -369, -348, 69, -208, -191, 207, 220, -253, 39, -180, -103, 18, -184, 67, 37, -275, 311, 3, -39, 180, 85, 19, 12, -62, 31, -6, -30, -68, -165, -317, 260, -92, 52, -5, -75, 277, 311, -272, 43, 132, 63, -592, -83, 18, -441, 260, 38, -74, -86, -600, 39, -7, 60, 236, 79, -693, -8, 58, -267, 196, 71, -65, 280, 135, 103, 189, 188, 97, 93, 203, -84, -247, -271, 34, 154, -54, -375, 52, 26, -102, -411, -34, 2, 66, -183, -421, 6, -26, -137, 51, -258, -70, -136, 53, -9, -182, 4, -16, 203, -175, -55, 319, 37, -3, 276, 291, -1, 61, -52, -312, 13, 74, -171, 4, 6, 7, 151, 67, -85, 40, -6, -11, -114, 36, -97, 16, 203, 29, -1, 104, -98, 196, -57, -372, 66, 124, -56, 37, -51, 69, -48, 40, -419, 61, -1, -115, 112, 64, 6, 0, 389, -55, 5, 164, 147, 336, 74, 136, -114, -70, 52, 17, -133, 11, 47, -176, -215, -349, 66, 16, -4, -83, 51, 57, -274, 9, -183, -136, 249, -60, 117, -682, 6, -555, 191, 2, 254, -63, -156, 7, -34, -133, 38, 0, -157, -53, 122, 28, -383, 208, -17, 12, -1, -47, 24, -69, 40, -60, 50, 5, -4, -444, -14, -197, 171, 79, 65, 105, 4, -53, 10, 43, 209, 6, -87, 0, 64, -366, 85, 33, -79, 181, 49, -227, -70, 6, -44, -51, 29, -116, 100, -51, 52, -261, -23, -493, -17, 47, 56, -47, 95, -68, 147, 258, 144, 79, -286, 84, 134, -8, 30, 53, -72, -179, 187, 39, -87, -33, -245, -119, -134, 55, 16, 55, 12, 44, -56, 46, 14, 134, 143, -179, 11, 66, 148, 50, 54, 197, -63, -9, 282, 184, 11, -96, 286, 49, -297, 42, -3, -21, 152, 34, -8, 4, 136, 41, -192, -167, -314, 110, -305, 36, 138, 144, -203, 379, -7, 8, 76, -97, -135, 538, -10, 91, -45, -332, 35, 100, -184, 16, -42, -42, 187, 52, -75, 103, -44, 178, 0, 137, -191, 85, -9, 4, 186, -125, 197, 17, -47, -410, 304, 100, -412, 138, -81, -263, -202, -214, -160, 402, 98, 134, -72, -78, -223, -51, 20, 145, 114, 173, 49, -182, 29, 51, 93, 32, 147, -134, 122, -398, 48, -114, -54, 133, 7, -57, 37, 4, -252, 5, 50, 97, -37, -71, 154, -96, 264, -57, -303, 11, 274, -44, -18, 102, -311, -182, 46, -395, 42, -4, 60, 14, -4, -54, 47, -101, -657, -3, 42, 84, -124, -57, 48, -53, -153, -5, 15, -394, 95, 35, -4, -313, 0, -3, -317, 131, -181, 0, 37, -119, -106, 111, -243, -78, -506, -2, -8, 99, 150, -242, 54, -7, 297, -285, 53, -40, 46, 11, -191, -428, 195, -226, -630, -76, 41, -95, 152, 141, 104, -60, 40, -87, 24, 8, -13, -5, 234, -73, 136, -113, -655, -283, 145, 32, 223, 53, 14, -2, 43, -355, 0, -106, 4, -50, 132, 180, -171, 91, 48, 67, 68, -276, -71, 61, -63, 1, 181, -368, 12, -114, 88, -343, -132, -186, -6, 49, -224, -61, -320, -21, -124, 46, 159, 236, 198, -278, -59, 158, 258, 11, 1, 4, -73, -42, -2, -75, -7, -182, -388, -99, -5, 37, -105, 105, 141, 4, -75, -118, -132, 53, 367, -10, 34, 27, 57, 96, -50, 149, -171, -19, 298, 11, -55, 51, 10, 91, 49, 62, 325, -551, -41, 54, -50, 55, -255, 125, -44, -191, 139, -129, -245, 43, -336, 3, 61, 39, -3, 16, -11, 39, 13, 1, -341, 95, -38, 65, -267, 101, 8, 96, -53, 45, -165, -253, 8, 0, 120, 146, -487, -2, -13, -314, -277, -94, 60, 39, -486, 5, 156, 47, 550, 33, -132, 316, -8, 411, -1, 243, 495, -178, 78, 146, 148, 110, -51, 281, 14, -85, 57, 15, 47, -66, 182, 19, 232, 185, 53, -3, -29, -196, 10, 151, 83, -65, -143, -134, 75, 64, -120, -289, -67, -4, 40, -179, 59, 116, 36, -65, -453, 138, 85, -298, -638, 245, -65, -258, 49, -256, 106, 100, -92, 237, 85, 23, 62, -322, 43, -224, 33, 56, -129, 117, 142, 4, -43, 1, 28, -47, 210, -88, -356, 0, 29, -6, 30, -53, 136, -79, -13, -3, 107, 10, 162, 2, -16, 21, -102, 131, 35, 160, -698, -276, 8, 112, -61, -78, 66, -501, 189, 67, 43, -66, -73, -451, -6, 263, -319, -439, 52, 52, 51, 427, -90, -46, 31, -296, -1198, -37, 87, 78, 6, 55, 40, -2, -176, 311, -105, -4, 49, -107, 200, -8, 16, -48, -202, 150, -75, 106, 43, 6, -106, 91, 220, 25, -177, 9, -177, -247, 0, -83, 185, 77, -26, -55, -40, -5, -97, -69, 67, 142, 7, 16, -53, 16, 71, -226, 40, 108, 40, 31, 210, -43, 37, -7, -177, -6, 37, 9, 205, -63, 50, 34, 47, -89, 53, -3, -116, 3, 8, 69, 44, 17, 30, 284, 117, -47, 36, 2, -282, 0, 89, -7, -37, -634, -112, 180, 157, -6, -275, -181, 8, 44, 3, 287, 44, -46, -61, 0, 66, 66, 150, -55, 39, -290, 318, -48, 31, 2, -29, -14, -10, -276, 0, -216, -203, -54, 109, 0, 57, -98, -203, 104, 203, 29, 320, 197, 40, -471, -39, 0, 43, 1, 63, -469, -98, 5, -3, -72, -360, 204, -21, -56, -330, 139, -41, 136, -43, 10, -264, 81, -418, -51, -172, 231, -327, 193, 57, 79, -98, 70, -310, -79, -52, 52, 9, 40, 302, 84, 106, 45, -114, -28, -10, -12, -52, -290, 4, 57, 10, -285, -37, -1014, -252, -191, 77, 134, -1, 60, 20, -171, -53, -267, 0, 157, -217, -130, -325, 696, 39, 35, 87, 123, -514, -28, -298, 36, 157, -192, 256, -8, -47, 74, 152, 45, -54, 154, -6, 145, -69, 63, -52, -194, -65, -73, 8, -68, -293, 76, -339, 180, -115, -15, 112, 180, 61, 29, -280, 19, 29, 42, -218, 107, -166, 39, -87, 202, -57, -1, -15, 51, -57, 63, 186, 73, -285, 170, -67, 48, -281, -750, -70, -160, -94, 49, -498, 47, -39, 28, 5, 252, -11, -301, -239, -383, 400, -173, 27, 7, -43, 33, -133, 33, 124, 2, 138, -5, 127, -56, 4, 18, -2, -73, -571, 104, -51, 69, 22, -280, -37, -108, -52, 7, -55, 36, -3, 32, -162, -120, 499, -542, 126, 195, 101, -162, -147, -175, 70, 62, 69, 29, 61, -169, 107, -48, -234, 100, 113, 0, 43, -205, 46, -53, 56, -48, 37, -60, 55, -154, 39, 3, -23, -358, -126, -3, 0, -75, 51, 12, 38, -67, 266, -301, -14, -62, 43, -273, -342, 116, -95, 4, 60, -82, -261, -44, 61, -53, 44, -8, 257, -153, 96, -183, 82, -198, -15, 147, 32, -13, -162, -46, -543, 22, 4, -282, -98, -43, -98, 90, -233, -5, 0, 88, 89, 10, -13, -82, 2560, 85, 45, 42, -394, -255, 3, -51, 277, 50, 17, -215, 93, -70, 27, -59, 44, -214, -44, -37, 3, -194, 195, -2, 56, -91, 66, 7, -171, -37, 53, 12, 33, 102, -182, -74, 0, -2, -301, -475, 99, -284, 252, -177, 17, -639, 38, -547, 200, -184, -349, 186, 49, -10, 0, -465, 53, -362, -30, 66, 44, -156, 77, -58, 53, 17, 133, -126, 20, 128, -149, 153, 55, 156, 129, 105, 24, 60, 46, 10, -209, 57, -50, 206, 5, -19, 108, 39, 2, -232, -66, 68, 25, 57, -67, 35, -185, 131, -277, 37, 7, 64, 119, 33, -61, -157, 8, 44, -70, 61, 36, -61, -242, 24, -220, 98, 7, 12, -61, 64, -59, -52, -10, 154, 229, -69, 5, 163, -59, 8, 8, 42, -508, 97, -235, 58, 138, -32, 82, -155, -7, 7, -11, 2, -38, 43, 121, -89, -10, 40, -51, 22, -1, 36, 1, 38, -115, 71, 172, 23, 85, 35, -174, 138, 201, -122, -156, 106, 189, -34, 157, 37, -279, 57, 14, -54, 158, 64, 10, 0, -86, 2, 123, -44, 2, 81, -44, -2, 121, -68, -261, 146, -107, 737, 534, 36, 138, -400, -37, 33, -14, 147, 5, 95, -58, -104, -433, -117, 39, 8, -47, -122, -67, 13, -34, -173, -187, 78, -8, 83, 111, -1218, -15, -8, -196, -21, -6, -570, -61, 32, -50, 35, 7, -36, -12, -17, -10, 209, -48, 155, 112, 140, 118, -251, 182, -55, 64, -276, 131, -318, 52, -89, 52, 5, 140, 68, -261, -223, 205, 58, 36, -489, -83, 0, 42, 213, -18, -295, 38, 129, 74, -228, -11, -5, 247, -44, 70, -455, -6, -180, 84, -77, 148, 11, 48, -176, 39, -153, 96, 132, 36, 302, 234, -14, -256, -1, -431, -39, -47, -4, -65, -79, 107, 237, 103, -253, 65, 30, -263, 8, 0, -87, 38, 7, 47, 20, 57, 16, 56, -111, 97, 102, -68, -17, 40, 198, -154, -158, -181, -18, 21, 70, -15, -15, 129, 78, -128, 100, 51, -136, -160, 363, 40, -42, 38, 108, 37, 68, 110, 177, -86, -346, -15, -10, 60, -54, 53, -2, 11, -60, 70, 19, -5, -10, 128, 67, 81, -35, -7, -3, 11, 81, 43, -37, 31, -6, 42, 288, 9, -52, 138, 0, 107, 32, 55, -105, 28, -76, 63, -59, 39, -13, -595, -2, -171, -324, 3, -6, -7, -36, 96, -867, 4, -45, -79, 84, -46, -289, 17, -4, -47, -4, 3, -106, 30, -50, -6, -6, 16, 0, 125, 130, -41, -289, 22, -37, 219, 86, 30, -62, -75, 0, -36, -72, -72, 156, -105, 75, 36, -175, 31, -262, 54, 124, 80, -76, -255, 5, -7, -68, -96, 105, 33, 0, -54, -2, -14, -187, 42, -238, 64, 17, 41, -5, -39, 188, 46, -3, -9, 108, -252, 54, 76, -62, 36, -52, 102, -13, 318, 153, 40, -116, 57, -61, 10, 36, 21, -8, 13, -86, -104, -209, -83, 11, 56, -56, 45, -223, 5, 13, 88, -167, 150, -82, -60, -411, 38, 3, 142, -96, -109, 11, 11, -45, -76, -12, 47, -46, -16, -15, -361, -13, 113, -47, 208, 0, 14, -51, 58, -66, 33, 4, 36, -143, -75, 3, 0, -10, -64, -46, 37, 87, -258, 21, 15, 21, 30, 486, 66, 11, -10, -18, 220, -40, -654, -181, 422, -44, -20, 25, 68, -217, -143, 248, -281, 210, 73, -200, 52, 16, -45, 283, 178, -64, 29, -13, 11, -88, 29, -112, -186, -46, 9, -53, 71, 139, -28, -42, -201, 170, 41, -40, -1149, 3, 33, -187, 35, 20, 107, 165, 36, -599, 21, -13, 188, 178, -52, -45, 48, 839, 60, 76, -34, -74, -174, -3, 278, 50, -145, 36, -142, -58, 50, -87, 23, 0, 6, -12, -131, -305, 9, 126, 102, 176, 65, 79, -70, -69, -226, -139, 6, 54, -174, 60, -54, 172, -206, 4, 120, -15, -260, 1, 0, 63, -240, 2, -91, -417, -434, 132, 243, -296, -84, 0, -198, 190, -47, 8, -327, 170, -5, 59, 219, 7, -247, 132, -46, 81, -15, 5, -74, 59, -66, 15, 419, -114, -60, 206, -84, -363, 149, 99, -40, 2, -8, 41, 139, -3, 194, -189, 393, 52, 13, 75, -72, 22, 64, 4, -64, 22, -104, 44, -9, -206, -44, -503, -263, 31, 190, -113, -44, -31, -85, 37, -7, 84, -213, 45, 17, -96, -53, 116, 19, -72, -141, -53, 17, 193, -81, -291, 48, 42, -5, 135, -71, 16, 130, -371, 6, 30, -261, 47, -212, 36, 122, -156, 30, 16, -36, 16, -138, 100, -138, 9, 586, -153, 95, 12, -18, -11, -204, -161, -10, -404, -12, -8, 43, 41, 144, 30, 237, -41, 260, 8, -2, -29, -17, -172, -190, -6, -54, 36, -17, -579, -38, 106, -106, 15, 118, -338, 49, 19, 117, -127, -394, 29, -375, -28, 146, 24, 222, 14, -71, 75, 155, 100, 150, 163, -37, -74, 134, -228, 113, 45, -76, 409, -136, -107, 33, 251, -144, -2, 34, 24, -10, -7, 57, -7, 32, 65, 39, 0, -141, -44, 10, -3, -4, 35, 60, -331, -47, -50, -83, -1, 151, -60, 187, 279, 43, 257, -13, -240, 139, 103, 8, -89, 43, -51, -126, -4, -42, -106, 181, -78, 6, -42, 51, 1, 224, -44, -155, -49, 41, -196, -29, -9, 47, 1, 31, -49, 62, -99, -7680, -16, -179, 15, 0, -36, 0, -4, -107, -52, 45, 7, 77, -67, 18, -219, -12, -115, -119, -11, 73, -2, -902, 375, -333, -2, 21, -43, 64, -62, 51, -272, 127, 106, 34, 149, -805, 177, 77, -81, 14, 235, 51, 5, 33, -49, 40, -141, -11, -241, -1, -5, 28, 2, -21, 290, 195, -15, 23, 21, -281, -51, 36, -315, 3, -82, 58, 130, 18, 40, -45, 14, -18, -50, -220, -290, 40, -157, 178, -38, 44, 158, 108, 320, 36, 152, -201, -364, 7, -57, 81, 166, 28, 5, 8, -65, 232, 2, -245, 350, 55, -226, 16, -38, 32, -16, 28, 93, 70, 276, 52, 6, 14, 53, -400, 134, -335, -130, 16, 787, 99, 115, 109, -170, 71, 113, -64, 88, 8, -15, -62, -123, 184, -87, -210, 48, -7, -138, -10, 39, -56, 155, -3, -70, -10, -14, -140, 123, -84, 32, 138, 11, 106, 176, -58, -55, -185, 47, -118, 61, 8, 19, -47, -7680, -12, 40, -64, 47, -49, 58, -170, 165, 89, 53, -45, 78, 256, -16, -78, -240, -6, 21, -79, -216, -342, -155, -9, 83, 75, -384, -11, -37, -9, 153, -9, 14, -67, 91, 131, 0, 157, 46, -493, 157, 113, 62, -38, -46, -48, 58, -132, 89, -55, -73, 67, -127, -197, -82, -57, 131, 12, 1, 17, -485, -365, 46, -42, -71, -4, -1, 650, 73, 167, 69, -64, 14, 119, 65, 18, 43, -45, 611, 159, -16, 27, -234, 381, 50, 0, 267, 69, 14, -247, -89, -13, 71, 53, 29, -57, -25, 20, 41, -44, 32, -284, -1234, -163, 628, -130, 28, -362, 10, 85, 11, 0, 91, 112, -11, -235, 51, -59, 68, 12, -724, -40, -510, 334, -11, -52, -244, -541, -412, 179, -102, 113, -403, -10, -3, 6, -16, -215, 41, 1, 34, -41, 141, -275, 299, 97, 28, -47, 47, 243, 9, -16, 107, -54, -544, -380, 82, 48, 71, 68, -155, 5, 124, -238, 87, -15, 164, -101, -117, 55, 108, -162, -77, 103, -199, 41, -204, 65, -181, 189, -62, -33, 35, 229, -220, 218, -75, 49, -65, 55, -11, 48, 80, 42, -159, 49, -3, -8, 53, 47, 13, 49, 244, 63, -419, -23, -91, 51, -48, 209, -117, 36, -52, 13, -56, 36, 458, -483, -14, -26, -12, -23, -365, 82, -8, -4, 279, 79, -176, -1, 32, 100, -51, 232, -50, -132, -8, 32, -162, 16, 79, 43, 90, -190, 106, 0, -42, -133, 0, 15, 37, 33, -350, -1, -79, 21, -45, 36, -60, -5, -5, 118, 102, 7, 111, 17, -53, 92, -39, 71, -93, 106, -43, -167, -117, 18, -257, 108, 67, -266, -5, 400, 37, 0, -9, -223, 152, -14, -348, 65, -36, 43, 73, 52, -39, 19, 20, -94, -236, 20, 183, -224, -151, 123, 86, 80, 45, -75, -36, 142, -16, 50, 75, 171, 0, 30, -129, -55, -38, 102, 29, 21, -48, 40, -273, 13, -15, 169, 15, -63, 101, -24, -117, 37, 404, 19, 120, 30, -214, 20, -45, 32, 69, -110, 150, -9, -5, 36, -106, 53, 162, -131, -45, 175, -40, -62, -225, 45, -42, 88, 221, 30, -230, -277, -8, 55, 430, 0}; +const int8_t frontalface_num_rectangles_array[]={2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 3, 3, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 2, 3, 2, 2, 3, 3, 2, 2, 3, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 3, 3, 3, 2, 2, 3, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 3, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3}; +const int8_t frontalface_weights_array[]={-1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2}; +const int8_t frontalface_rectangles_array[]={6, 4, 12, 9, 6, 7, 12, 3, 6, 4, 12, 7, 10, 4, 4, 7, 3, 9, 18, 9, 3, 12, 18, 3, 8, 18, 9, 6, 8, 20, 9, 2, 3, 5, 4, 19, 5, 5, 2, 19, 6, 5, 12, 16, 6, 13, 12, 8, 5, 8, 12, 6, 5, 11, 12, 3, 11, 14, 4, 10, 11, 19, 4, 5, 4, 0, 7, 6, 4, 3, 7, 3, 6, 6, 12, 6, 6, 8, 12, 2, 6, 4, 12, 7, 10, 4, 4, 7, 1, 8, 19, 12, 1, 12, 19, 4, 0, 2, 24, 3, 8, 2, 8, 3, 9, 9, 6, 15, 9, 14, 6, 5, 5, 6, 14, 10, 5, 11, 14, 5, 5, 0, 14, 9, 5, 3, 14, 3, 13, 11, 9, 6, 16, 11, 3, 6, 7, 5, 6, 10, 9, 5, 2, 10, 10, 8, 6, 10, 12, 8, 2, 10, 2, 5, 4, 9, 4, 5, 2, 9, 18, 0, 6, 11, 20, 0, 2, 11, 0, 6, 24, 13, 8, 6, 8, 13, 9, 6, 6, 9, 11, 6, 2, 9, 7, 18, 10, 6, 7, 20, 10, 2, 5, 7, 14, 12, 5, 13, 14, 6, 0, 3, 24, 3, 8, 3, 8, 3, 5, 8, 15, 6, 5, 11, 15, 3, 9, 6, 5, 14, 9, 13, 5, 7, 9, 5, 6, 10, 11, 5, 2, 10, 6, 6, 3, 12, 6, 12, 3, 6, 3, 21, 18, 3, 9, 21, 6, 3, 5, 6, 13, 6, 5, 8, 13, 2, 18, 1, 6, 15, 18, 1, 3, 15, 1, 1, 6, 15, 4, 1, 3, 15, 0, 8, 24, 15, 8, 8, 8, 15, 5, 6, 14, 12, 5, 6, 7, 6, 12, 12, 7, 6, 2, 12, 21, 12, 2, 16, 21, 4, 8, 1, 4, 10, 10, 1, 2, 10, 2, 13, 20, 10, 2, 13, 10, 10, 0, 1, 6, 13, 2, 1, 2, 13, 20, 2, 4, 13, 20, 2, 2, 13, 0, 5, 22, 19, 11, 5, 11, 19, 18, 4, 6, 9, 20, 4, 2, 9, 0, 3, 6, 11, 2, 3, 2, 11, 12, 1, 4, 9, 12, 1, 2, 9, 0, 6, 19, 3, 0, 7, 19, 1, 12, 1, 4, 9, 12, 1, 2, 9, 8, 1, 4, 9, 10, 1, 2, 9, 5, 5, 14, 14, 12, 5, 7, 7, 5, 12, 7, 7, 1, 10, 18, 2, 1, 11, 18, 1, 17, 13, 4, 11, 17, 13, 2, 11, 0, 4, 6, 9, 0, 7, 6, 3, 6, 4, 12, 9, 6, 7, 12, 3, 6, 5, 12, 6, 10, 5, 4, 6, 0, 1, 24, 5, 8, 1, 8, 5, 4, 10, 18, 6, 4, 12, 18, 2, 2, 17, 12, 6, 2, 17, 6, 3, 8, 20, 6, 3, 19, 3, 4, 13, 19, 3, 2, 13, 1, 3, 4, 13, 3, 3, 2, 13, 0, 1, 24, 23, 8, 1, 8, 23, 1, 7, 8, 12, 1, 11, 8, 4, 14, 7, 3, 14, 14, 14, 3, 7, 3, 12, 16, 6, 3, 12, 8, 3, 11, 15, 8, 3, 6, 6, 12, 6, 6, 8, 12, 2, 8, 7, 6, 12, 8, 13, 6, 6, 15, 15, 9, 6, 15, 17, 9, 2, 1, 17, 18, 3, 1, 18, 18, 1, 4, 4, 16, 12, 4, 10, 16, 6, 0, 1, 4, 20, 2, 1, 2, 20, 3, 0, 18, 2, 3, 1, 18, 1, 1, 5, 20, 14, 1, 5, 10, 7, 11, 12, 10, 7, 5, 8, 14, 12, 5, 12, 14, 4, 3, 14, 7, 9, 3, 17, 7, 3, 14, 15, 9, 6, 14, 17, 9, 2, 1, 15, 9, 6, 1, 17, 9, 2, 11, 6, 8, 10, 15, 6, 4, 5, 11, 11, 4, 5, 5, 5, 14, 14, 5, 5, 7, 7, 12, 12, 7, 7, 6, 0, 12, 5, 10, 0, 4, 5, 9, 0, 6, 9, 9, 3, 6, 3, 9, 6, 6, 9, 11, 6, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 10, 6, 6, 9, 12, 6, 2, 9, 8, 6, 6, 9, 10, 6, 2, 9, 3, 8, 18, 4, 9, 8, 6, 4, 6, 0, 12, 9, 6, 3, 12, 3, 0, 0, 24, 6, 8, 0, 8, 6, 4, 7, 16, 12, 4, 11, 16, 4, 11, 6, 6, 6, 11, 6, 3, 6, 0, 20, 24, 3, 8, 20, 8, 3, 11, 6, 4, 9, 11, 6, 2, 9, 4, 13, 15, 4, 9, 13, 5, 4, 11, 6, 4, 9, 11, 6, 2, 9, 9, 6, 4, 9, 11, 6, 2, 9, 9, 12, 6, 12, 9, 18, 6, 6, 1, 22, 18, 2, 1, 23, 18, 1, 10, 7, 4, 10, 10, 12, 4, 5, 6, 7, 8, 10, 6, 12, 8, 5, 7, 6, 10, 6, 7, 8, 10, 2, 0, 14, 10, 4, 0, 16, 10, 2, 6, 18, 18, 2, 6, 19, 18, 1, 1, 1, 22, 3, 1, 2, 22, 1, 6, 16, 18, 3, 6, 17, 18, 1, 2, 4, 6, 15, 5, 4, 3, 15, 20, 4, 4, 10, 20, 4, 2, 10, 0, 4, 4, 10, 2, 4, 2, 10, 2, 16, 20, 6, 12, 16, 10, 3, 2, 19, 10, 3, 0, 12, 8, 9, 4, 12, 4, 9, 12, 0, 6, 9, 14, 0, 2, 9, 5, 10, 6, 6, 8, 10, 3, 6, 11, 8, 12, 6, 17, 8, 6, 3, 11, 11, 6, 3, 0, 8, 12, 6, 0, 8, 6, 3, 6, 11, 6, 3, 12, 0, 6, 9, 14, 0, 2, 9, 6, 0, 6, 9, 8, 0, 2, 9, 8, 14, 9, 6, 8, 16, 9, 2, 0, 16, 9, 6, 0, 18, 9, 2, 10, 8, 6, 10, 12, 8, 2, 10, 3, 19, 12, 3, 9, 19, 6, 3, 2, 10, 20, 2, 2, 11, 20, 1, 2, 9, 18, 12, 2, 9, 9, 6, 11, 15, 9, 6, 3, 0, 18, 24, 3, 0, 9, 24, 5, 6, 14, 10, 5, 6, 7, 5, 12, 11, 7, 5, 9, 5, 10, 12, 14, 5, 5, 6, 9, 11, 5, 6, 4, 5, 12, 12, 4, 5, 6, 6, 10, 11, 6, 6, 4, 14, 18, 3, 4, 15, 18, 1, 6, 13, 8, 8, 6, 17, 8, 4, 3, 16, 18, 6, 3, 19, 18, 3, 0, 0, 6, 6, 3, 0, 3, 6, 6, 6, 12, 18, 10, 6, 4, 18, 6, 1, 4, 14, 8, 1, 2, 14, 3, 2, 19, 2, 3, 3, 19, 1, 1, 8, 22, 13, 12, 8, 11, 13, 8, 9, 11, 4, 8, 11, 11, 2, 0, 12, 15, 10, 5, 12, 5, 10, 12, 16, 12, 6, 16, 16, 4, 6, 0, 16, 12, 6, 4, 16, 4, 6, 19, 1, 5, 12, 19, 5, 5, 4, 0, 2, 24, 4, 8, 2, 8, 4, 6, 8, 12, 4, 6, 10, 12, 2, 7, 5, 9, 6, 10, 5, 3, 6, 9, 17, 6, 6, 9, 20, 6, 3, 0, 7, 22, 15, 0, 12, 22, 5, 4, 1, 17, 9, 4, 4, 17, 3, 7, 5, 6, 10, 9, 5, 2, 10, 18, 1, 6, 8, 18, 1, 3, 8, 0, 1, 6, 7, 3, 1, 3, 7, 18, 0, 6, 22, 18, 0, 3, 22, 0, 0, 6, 22, 3, 0, 3, 22, 16, 7, 8, 16, 16, 7, 4, 16, 2, 10, 19, 6, 2, 12, 19, 2, 9, 9, 6, 12, 9, 13, 6, 4, 2, 15, 17, 6, 2, 17, 17, 2, 14, 7, 3, 14, 14, 14, 3, 7, 5, 6, 8, 10, 5, 6, 4, 5, 9, 11, 4, 5, 15, 8, 9, 11, 18, 8, 3, 11, 0, 8, 9, 11, 3, 8, 3, 11, 8, 6, 10, 18, 8, 15, 10, 9, 7, 7, 3, 14, 7, 14, 3, 7, 0, 14, 24, 8, 8, 14, 8, 8, 1, 10, 18, 14, 10, 10, 9, 14, 14, 12, 6, 6, 14, 15, 6, 3, 7, 0, 10, 16, 7, 0, 5, 8, 12, 8, 5, 8, 10, 0, 9, 6, 13, 0, 3, 6, 4, 3, 16, 4, 12, 3, 8, 4, 10, 0, 9, 6, 13, 0, 3, 6, 1, 1, 20, 4, 1, 1, 10, 2, 11, 3, 10, 2, 10, 0, 9, 6, 13, 0, 3, 6, 5, 0, 9, 6, 8, 0, 3, 6, 8, 18, 10, 6, 8, 20, 10, 2, 6, 3, 6, 9, 8, 3, 2, 9, 7, 3, 12, 6, 7, 5, 12, 2, 0, 10, 18, 3, 0, 11, 18, 1, 1, 10, 22, 3, 1, 11, 22, 1, 5, 11, 8, 8, 9, 11, 4, 8, 12, 11, 6, 6, 12, 11, 3, 6, 6, 11, 6, 6, 9, 11, 3, 6, 7, 10, 11, 6, 7, 12, 11, 2, 0, 13, 24, 4, 0, 13, 12, 2, 12, 15, 12, 2, 2, 4, 22, 12, 13, 4, 11, 6, 2, 10, 11, 6, 2, 0, 20, 17, 12, 0, 10, 17, 14, 0, 2, 24, 14, 0, 1, 24, 8, 0, 2, 24, 9, 0, 1, 24, 14, 1, 2, 22, 14, 1, 1, 22, 8, 1, 2, 22, 9, 1, 1, 22, 17, 6, 3, 18, 18, 6, 1, 18, 6, 14, 9, 6, 6, 16, 9, 2, 13, 14, 9, 4, 13, 16, 9, 2, 3, 18, 18, 3, 3, 19, 18, 1, 9, 4, 8, 18, 13, 4, 4, 9, 9, 13, 4, 9, 0, 17, 18, 3, 0, 18, 18, 1, 0, 2, 12, 4, 6, 2, 6, 4, 6, 8, 14, 6, 6, 11, 14, 3, 7, 5, 6, 6, 10, 5, 3, 6, 10, 5, 6, 16, 10, 13, 6, 8, 1, 4, 9, 16, 4, 4, 3, 16, 5, 0, 18, 9, 5, 3, 18, 3, 9, 15, 5, 8, 9, 19, 5, 4, 20, 0, 4, 9, 20, 0, 2, 9, 2, 0, 18, 3, 2, 1, 18, 1, 5, 22, 19, 2, 5, 23, 19, 1, 0, 0, 4, 9, 2, 0, 2, 9, 5, 6, 19, 18, 5, 12, 19, 6, 0, 1, 6, 9, 2, 1, 2, 9, 6, 5, 14, 12, 13, 5, 7, 6, 6, 11, 7, 6, 0, 1, 20, 2, 0, 2, 20, 1, 1, 2, 22, 3, 1, 3, 22, 1, 2, 8, 7, 9, 2, 11, 7, 3, 2, 12, 22, 4, 13, 12, 11, 2, 2, 14, 11, 2, 0, 12, 22, 4, 0, 12, 11, 2, 11, 14, 11, 2, 9, 7, 6, 11, 11, 7, 2, 11, 7, 1, 9, 6, 10, 1, 3, 6, 11, 2, 4, 10, 11, 7, 4, 5, 6, 4, 12, 12, 6, 10, 12, 6, 18, 1, 6, 15, 18, 6, 6, 5, 3, 15, 18, 3, 3, 16, 18, 1, 18, 5, 6, 9, 18, 8, 6, 3, 1, 5, 16, 6, 1, 5, 8, 3, 9, 8, 8, 3, 11, 0, 6, 9, 13, 0, 2, 9, 0, 4, 24, 14, 0, 4, 12, 7, 12, 11, 12, 7, 13, 0, 4, 13, 13, 0, 2, 13, 7, 0, 4, 13, 9, 0, 2, 13, 11, 6, 6, 9, 13, 6, 2, 9, 8, 7, 6, 9, 10, 7, 2, 9, 13, 17, 9, 6, 13, 19, 9, 2, 2, 18, 14, 6, 2, 18, 7, 3, 9, 21, 7, 3, 3, 18, 18, 4, 12, 18, 9, 2, 3, 20, 9, 2, 0, 20, 15, 4, 5, 20, 5, 4, 9, 15, 15, 9, 14, 15, 5, 9, 4, 4, 16, 4, 4, 6, 16, 2, 7, 6, 10, 6, 7, 8, 10, 2, 0, 14, 15, 10, 5, 14, 5, 10, 7, 9, 10, 14, 12, 9, 5, 7, 7, 16, 5, 7, 7, 6, 6, 9, 9, 6, 2, 9, 3, 6, 18, 3, 3, 7, 18, 1, 0, 10, 18, 3, 0, 11, 18, 1, 3, 16, 18, 4, 12, 16, 9, 2, 3, 18, 9, 2, 4, 6, 14, 6, 4, 6, 7, 3, 11, 9, 7, 3, 13, 0, 2, 18, 13, 0, 1, 18, 9, 0, 2, 18, 10, 0, 1, 18, 5, 7, 15, 10, 10, 7, 5, 10, 1, 20, 21, 4, 8, 20, 7, 4, 10, 5, 5, 18, 10, 14, 5, 9, 0, 2, 24, 6, 0, 2, 12, 3, 12, 5, 12, 3, 1, 1, 22, 8, 12, 1, 11, 4, 1, 5, 11, 4, 4, 0, 15, 9, 4, 3, 15, 3, 0, 0, 24, 19, 8, 0, 8, 19, 2, 21, 18, 3, 11, 21, 9, 3, 9, 7, 10, 4, 9, 7, 5, 4, 5, 7, 10, 4, 10, 7, 5, 4, 17, 8, 6, 16, 20, 8, 3, 8, 17, 16, 3, 8, 1, 15, 20, 4, 1, 15, 10, 2, 11, 17, 10, 2, 14, 15, 10, 6, 14, 17, 10, 2, 3, 0, 16, 9, 3, 3, 16, 3, 15, 6, 7, 15, 15, 11, 7, 5, 9, 1, 6, 13, 11, 1, 2, 13, 17, 2, 6, 14, 17, 2, 3, 14, 3, 14, 12, 10, 3, 14, 6, 5, 9, 19, 6, 5, 7, 6, 10, 6, 7, 8, 10, 2, 1, 2, 6, 14, 4, 2, 3, 14, 10, 4, 5, 12, 10, 8, 5, 4, 0, 17, 24, 5, 8, 17, 8, 5, 15, 7, 5, 12, 15, 11, 5, 4, 3, 1, 6, 12, 3, 1, 3, 6, 6, 7, 3, 6, 12, 13, 6, 6, 12, 16, 6, 3, 6, 13, 6, 6, 6, 16, 6, 3, 14, 6, 3, 16, 14, 14, 3, 8, 1, 12, 13, 6, 1, 14, 13, 2, 13, 1, 4, 9, 13, 1, 2, 9, 7, 0, 9, 6, 10, 0, 3, 6, 12, 2, 6, 9, 12, 2, 3, 9, 6, 2, 6, 9, 9, 2, 3, 9, 6, 18, 12, 6, 6, 20, 12, 2, 7, 6, 6, 9, 9, 6, 2, 9, 7, 7, 12, 3, 7, 7, 6, 3, 8, 3, 8, 21, 8, 10, 8, 7, 7, 4, 10, 12, 7, 8, 10, 4, 0, 1, 6, 9, 0, 4, 6, 3, 15, 2, 2, 20, 15, 2, 1, 20, 0, 3, 6, 9, 0, 6, 6, 3, 15, 3, 2, 21, 15, 3, 1, 21, 7, 0, 2, 23, 8, 0, 1, 23, 15, 8, 9, 4, 15, 10, 9, 2, 0, 8, 9, 4, 0, 10, 9, 2, 8, 14, 9, 6, 8, 16, 9, 2, 0, 14, 9, 6, 0, 16, 9, 2, 3, 10, 18, 4, 9, 10, 6, 4, 0, 0, 24, 19, 8, 0, 8, 19, 9, 1, 8, 12, 9, 7, 8, 6, 10, 6, 4, 10, 12, 6, 2, 10, 7, 9, 10, 12, 12, 9, 5, 6, 7, 15, 5, 6, 5, 0, 3, 19, 6, 0, 1, 19, 14, 0, 6, 10, 16, 0, 2, 10, 2, 0, 6, 12, 2, 0, 3, 6, 5, 6, 3, 6, 0, 11, 24, 2, 0, 12, 24, 1, 4, 9, 13, 4, 4, 11, 13, 2, 9, 8, 6, 9, 9, 11, 6, 3, 0, 12, 16, 4, 0, 14, 16, 2, 18, 12, 6, 9, 18, 15, 6, 3, 0, 12, 6, 9, 0, 15, 6, 3, 8, 7, 10, 4, 8, 7, 5, 4, 8, 7, 6, 9, 10, 7, 2, 9, 11, 0, 6, 9, 13, 0, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 12, 3, 6, 15, 14, 3, 2, 15, 6, 3, 6, 15, 8, 3, 2, 15, 15, 2, 9, 4, 15, 4, 9, 2, 5, 10, 6, 7, 8, 10, 3, 7, 9, 14, 6, 10, 9, 19, 6, 5, 7, 13, 5, 8, 7, 17, 5, 4, 14, 5, 3, 16, 14, 13, 3, 8, 2, 17, 18, 3, 2, 18, 18, 1, 5, 18, 19, 3, 5, 19, 19, 1, 9, 0, 6, 9, 11, 0, 2, 9, 12, 4, 3, 18, 13, 4, 1, 18, 9, 4, 3, 18, 10, 4, 1, 18, 3, 3, 18, 9, 9, 3, 6, 9, 6, 1, 6, 14, 8, 1, 2, 14, 12, 16, 9, 6, 12, 19, 9, 3, 1, 3, 20, 16, 1, 3, 10, 8, 11, 11, 10, 8, 12, 5, 6, 12, 15, 5, 3, 6, 12, 11, 3, 6, 1, 2, 22, 16, 1, 2, 11, 8, 12, 10, 11, 8, 10, 14, 5, 10, 10, 19, 5, 5, 3, 21, 18, 3, 3, 22, 18, 1, 10, 14, 6, 10, 12, 14, 2, 10, 0, 2, 24, 4, 8, 2, 8, 4, 6, 4, 12, 9, 6, 7, 12, 3, 6, 6, 12, 5, 10, 6, 4, 5, 5, 8, 14, 12, 5, 12, 14, 4, 4, 14, 8, 10, 4, 14, 4, 5, 8, 19, 4, 5, 11, 6, 5, 14, 11, 13, 5, 7, 7, 6, 3, 16, 7, 14, 3, 8, 3, 7, 18, 8, 9, 7, 6, 8, 2, 3, 20, 2, 2, 4, 20, 1, 3, 12, 19, 6, 3, 14, 19, 2, 8, 6, 6, 9, 10, 6, 2, 9, 16, 6, 6, 14, 16, 6, 3, 14, 7, 9, 6, 12, 9, 9, 2, 12, 18, 6, 6, 18, 21, 6, 3, 9, 18, 15, 3, 9, 0, 6, 6, 18, 0, 6, 3, 9, 3, 15, 3, 9, 18, 2, 6, 9, 18, 5, 6, 3, 3, 18, 15, 6, 3, 20, 15, 2, 18, 2, 6, 9, 18, 5, 6, 3, 0, 2, 6, 9, 0, 5, 6, 3, 5, 10, 18, 2, 5, 11, 18, 1, 6, 0, 12, 6, 6, 2, 12, 2, 10, 0, 6, 9, 12, 0, 2, 9, 8, 0, 6, 9, 10, 0, 2, 9, 15, 12, 9, 6, 15, 14, 9, 2, 3, 6, 13, 6, 3, 8, 13, 2, 15, 12, 9, 6, 15, 14, 9, 2, 2, 5, 6, 15, 5, 5, 3, 15, 8, 8, 9, 6, 11, 8, 3, 6, 8, 6, 3, 14, 8, 13, 3, 7, 15, 12, 9, 6, 15, 14, 9, 2, 4, 12, 10, 4, 9, 12, 5, 4, 13, 1, 4, 19, 13, 1, 2, 19, 7, 1, 4, 19, 9, 1, 2, 19, 18, 9, 6, 9, 18, 12, 6, 3, 1, 21, 18, 3, 1, 22, 18, 1, 14, 13, 10, 9, 14, 16, 10, 3, 1, 13, 22, 4, 1, 13, 11, 2, 12, 15, 11, 2, 4, 6, 16, 6, 12, 6, 8, 3, 4, 9, 8, 3, 1, 0, 18, 22, 1, 0, 9, 11, 10, 11, 9, 11, 10, 7, 8, 14, 14, 7, 4, 7, 10, 14, 4, 7, 0, 4, 6, 20, 0, 4, 3, 10, 3, 14, 3, 10, 15, 0, 6, 9, 17, 0, 2, 9, 3, 0, 6, 9, 5, 0, 2, 9, 15, 12, 6, 12, 18, 12, 3, 6, 15, 18, 3, 6, 3, 12, 6, 12, 3, 12, 3, 6, 6, 18, 3, 6, 15, 12, 9, 6, 15, 14, 9, 2, 0, 12, 9, 6, 0, 14, 9, 2, 4, 14, 19, 3, 4, 15, 19, 1, 2, 13, 19, 3, 2, 14, 19, 1, 14, 15, 10, 6, 14, 17, 10, 2, 6, 0, 10, 12, 6, 0, 5, 6, 11, 6, 5, 6, 17, 1, 6, 12, 20, 1, 3, 6, 17, 7, 3, 6, 1, 1, 6, 12, 1, 1, 3, 6, 4, 7, 3, 6, 16, 14, 6, 9, 16, 17, 6, 3, 7, 3, 9, 12, 7, 9, 9, 6, 12, 1, 4, 12, 12, 7, 4, 6, 4, 0, 14, 8, 4, 4, 14, 4, 10, 6, 6, 9, 12, 6, 2, 9, 2, 10, 18, 3, 8, 10, 6, 3, 15, 15, 9, 6, 15, 17, 9, 2, 0, 1, 21, 23, 7, 1, 7, 23, 6, 9, 17, 4, 6, 11, 17, 2, 1, 0, 11, 18, 1, 6, 11, 6, 6, 15, 13, 6, 6, 17, 13, 2, 0, 15, 9, 6, 0, 17, 9, 2, 8, 7, 15, 4, 13, 7, 5, 4, 9, 12, 6, 9, 9, 15, 6, 3, 6, 8, 18, 3, 12, 8, 6, 3, 0, 14, 24, 4, 8, 14, 8, 4, 16, 10, 3, 12, 16, 16, 3, 6, 0, 3, 24, 3, 0, 4, 24, 1, 14, 17, 10, 6, 14, 19, 10, 2, 1, 13, 18, 3, 7, 13, 6, 3, 5, 0, 18, 9, 5, 3, 18, 3, 4, 3, 16, 9, 4, 6, 16, 3, 16, 5, 3, 12, 16, 11, 3, 6, 0, 7, 18, 4, 6, 7, 6, 4, 10, 6, 6, 9, 12, 6, 2, 9, 9, 8, 6, 10, 11, 8, 2, 10, 9, 15, 6, 9, 11, 15, 2, 9, 3, 1, 18, 21, 12, 1, 9, 21, 6, 8, 12, 7, 6, 8, 6, 7, 8, 5, 6, 9, 10, 5, 2, 9, 0, 2, 24, 4, 8, 2, 8, 4, 14, 7, 5, 12, 14, 11, 5, 4, 5, 7, 5, 12, 5, 11, 5, 4, 9, 6, 6, 9, 11, 6, 2, 9, 0, 1, 6, 17, 3, 1, 3, 17, 3, 1, 19, 9, 3, 4, 19, 3, 3, 18, 12, 6, 3, 18, 6, 3, 9, 21, 6, 3, 20, 4, 4, 19, 20, 4, 2, 19, 0, 16, 10, 7, 5, 16, 5, 7, 8, 7, 10, 12, 13, 7, 5, 6, 8, 13, 5, 6, 6, 7, 10, 12, 6, 7, 5, 6, 11, 13, 5, 6, 9, 2, 9, 6, 12, 2, 3, 6, 1, 20, 21, 4, 8, 20, 7, 4, 9, 12, 9, 6, 9, 14, 9, 2, 7, 2, 9, 6, 10, 2, 3, 6, 13, 0, 4, 14, 13, 0, 2, 14, 7, 0, 4, 14, 9, 0, 2, 14, 14, 15, 9, 6, 14, 17, 9, 2, 2, 8, 18, 5, 8, 8, 6, 5, 18, 3, 6, 11, 20, 3, 2, 11, 6, 5, 11, 14, 6, 12, 11, 7, 18, 4, 6, 9, 18, 7, 6, 3, 7, 6, 9, 6, 7, 8, 9, 2, 18, 4, 6, 9, 18, 7, 6, 3, 0, 4, 6, 9, 0, 7, 6, 3, 9, 4, 9, 4, 9, 6, 9, 2, 0, 22, 19, 2, 0, 23, 19, 1, 17, 14, 6, 9, 17, 17, 6, 3, 1, 14, 6, 9, 1, 17, 6, 3, 14, 11, 4, 9, 14, 11, 2, 9, 6, 11, 4, 9, 8, 11, 2, 9, 3, 9, 18, 7, 9, 9, 6, 7, 9, 12, 6, 10, 9, 17, 6, 5, 12, 0, 6, 9, 14, 0, 2, 9, 6, 0, 6, 9, 8, 0, 2, 9, 6, 17, 18, 3, 6, 18, 18, 1, 1, 17, 18, 3, 1, 18, 18, 1, 10, 6, 11, 12, 10, 12, 11, 6, 5, 6, 14, 6, 5, 6, 7, 3, 12, 9, 7, 3, 5, 4, 15, 4, 5, 6, 15, 2, 0, 0, 22, 2, 0, 1, 22, 1, 0, 0, 24, 24, 8, 0, 8, 24, 1, 15, 18, 4, 10, 15, 9, 4, 6, 8, 12, 9, 6, 11, 12, 3, 4, 12, 7, 12, 4, 16, 7, 4, 1, 2, 22, 6, 12, 2, 11, 3, 1, 5, 11, 3, 5, 20, 14, 3, 12, 20, 7, 3, 0, 0, 24, 16, 12, 0, 12, 8, 0, 8, 12, 8, 3, 13, 18, 4, 3, 13, 9, 2, 12, 15, 9, 2, 2, 10, 22, 2, 2, 11, 22, 1, 6, 3, 11, 8, 6, 7, 11, 4, 14, 5, 6, 6, 14, 8, 6, 3, 0, 7, 24, 6, 0, 9, 24, 2, 14, 0, 10, 10, 19, 0, 5, 5, 14, 5, 5, 5, 0, 0, 10, 10, 0, 0, 5, 5, 5, 5, 5, 5, 0, 1, 24, 4, 12, 1, 12, 2, 0, 3, 12, 2, 0, 17, 18, 3, 0, 18, 18, 1, 5, 15, 16, 6, 13, 15, 8, 3, 5, 18, 8, 3, 3, 15, 16, 6, 3, 15, 8, 3, 11, 18, 8, 3, 6, 16, 18, 3, 6, 17, 18, 1, 0, 13, 21, 10, 0, 18, 21, 5, 13, 0, 6, 24, 15, 0, 2, 24, 7, 4, 6, 11, 9, 4, 2, 11, 9, 5, 9, 6, 12, 5, 3, 6, 1, 4, 2, 20, 1, 14, 2, 10, 13, 0, 6, 24, 15, 0, 2, 24, 5, 0, 6, 24, 7, 0, 2, 24, 16, 7, 6, 14, 19, 7, 3, 7, 16, 14, 3, 7, 4, 7, 4, 12, 6, 7, 2, 12, 0, 5, 24, 14, 8, 5, 8, 14, 5, 13, 10, 6, 5, 15, 10, 2, 12, 0, 6, 9, 14, 0, 2, 9, 2, 7, 6, 14, 2, 7, 3, 7, 5, 14, 3, 7, 15, 2, 9, 15, 18, 2, 3, 15, 0, 2, 6, 9, 2, 2, 2, 9, 12, 2, 10, 14, 17, 2, 5, 7, 12, 9, 5, 7, 11, 6, 2, 18, 12, 6, 1, 18, 9, 5, 15, 6, 14, 5, 5, 6, 8, 6, 6, 10, 10, 6, 2, 10, 12, 0, 6, 9, 14, 0, 2, 9, 3, 3, 9, 7, 6, 3, 3, 7, 6, 7, 14, 3, 6, 7, 7, 3, 7, 7, 8, 6, 11, 7, 4, 6, 12, 7, 7, 12, 12, 13, 7, 6, 10, 6, 4, 18, 10, 6, 2, 9, 12, 15, 2, 9, 16, 14, 6, 9, 16, 17, 6, 3, 4, 0, 6, 13, 6, 0, 2, 13, 2, 2, 21, 3, 9, 2, 7, 3, 5, 4, 5, 12, 5, 8, 5, 4, 10, 3, 4, 10, 10, 8, 4, 5, 8, 4, 5, 8, 8, 8, 5, 4, 6, 0, 11, 9, 6, 3, 11, 3, 6, 6, 12, 5, 10, 6, 4, 5, 0, 0, 24, 5, 8, 0, 8, 5, 1, 10, 23, 6, 1, 12, 23, 2, 3, 21, 18, 3, 9, 21, 6, 3, 3, 6, 21, 6, 3, 8, 21, 2, 0, 5, 6, 12, 2, 5, 2, 12, 10, 2, 4, 15, 10, 7, 4, 5, 8, 7, 8, 10, 8, 12, 8, 5, 5, 7, 15, 12, 10, 7, 5, 12, 0, 17, 10, 6, 0, 19, 10, 2, 14, 18, 9, 6, 14, 20, 9, 2, 9, 6, 6, 16, 9, 14, 6, 8, 14, 18, 9, 6, 14, 20, 9, 2, 1, 18, 9, 6, 1, 20, 9, 2, 15, 9, 9, 6, 15, 11, 9, 2, 0, 9, 9, 6, 0, 11, 9, 2, 17, 3, 6, 9, 19, 3, 2, 9, 2, 17, 18, 3, 2, 18, 18, 1, 3, 15, 21, 6, 3, 17, 21, 2, 9, 17, 6, 6, 9, 20, 6, 3, 18, 3, 6, 9, 18, 6, 6, 3, 0, 3, 6, 9, 0, 6, 6, 3, 4, 0, 16, 10, 12, 0, 8, 5, 4, 5, 8, 5, 2, 0, 10, 16, 2, 0, 5, 8, 7, 8, 5, 8, 14, 0, 10, 5, 14, 0, 5, 5, 0, 0, 10, 5, 5, 0, 5, 5, 18, 3, 6, 10, 18, 3, 3, 10, 5, 11, 12, 6, 5, 11, 6, 3, 11, 14, 6, 3, 21, 0, 3, 18, 22, 0, 1, 18, 6, 0, 6, 9, 8, 0, 2, 9, 8, 8, 9, 7, 11, 8, 3, 7, 7, 12, 8, 10, 7, 12, 4, 5, 11, 17, 4, 5, 21, 0, 3, 18, 22, 0, 1, 18, 10, 6, 4, 9, 12, 6, 2, 9, 15, 0, 9, 6, 15, 2, 9, 2, 0, 2, 24, 3, 0, 3, 24, 1, 11, 7, 6, 9, 13, 7, 2, 9, 7, 6, 6, 10, 9, 6, 2, 10, 12, 1, 6, 12, 14, 1, 2, 12, 6, 4, 12, 12, 6, 10, 12, 6, 14, 3, 2, 21, 14, 3, 1, 21, 6, 1, 12, 8, 6, 5, 12, 4, 3, 0, 18, 8, 3, 4, 18, 4, 3, 0, 18, 3, 3, 1, 18, 1, 0, 13, 24, 4, 12, 13, 12, 2, 0, 15, 12, 2, 10, 5, 4, 9, 12, 5, 2, 9, 11, 1, 6, 9, 13, 1, 2, 9, 6, 2, 6, 22, 8, 2, 2, 22, 16, 10, 8, 14, 20, 10, 4, 7, 16, 17, 4, 7, 3, 4, 16, 15, 3, 9, 16, 5, 16, 10, 8, 14, 20, 10, 4, 7, 16, 17, 4, 7, 0, 10, 8, 14, 0, 10, 4, 7, 4, 17, 4, 7, 10, 14, 11, 6, 10, 17, 11, 3, 0, 7, 24, 9, 8, 7, 8, 9, 13, 1, 4, 16, 13, 1, 2, 16, 7, 1, 4, 16, 9, 1, 2, 16, 5, 5, 16, 8, 13, 5, 8, 4, 5, 9, 8, 4, 0, 9, 6, 9, 0, 12, 6, 3, 6, 16, 18, 3, 6, 17, 18, 1, 3, 12, 6, 9, 3, 15, 6, 3, 8, 14, 9, 6, 8, 16, 9, 2, 2, 13, 8, 10, 2, 13, 4, 5, 6, 18, 4, 5, 15, 5, 3, 18, 15, 11, 3, 6, 3, 5, 18, 3, 3, 6, 18, 1, 17, 5, 6, 11, 19, 5, 2, 11, 1, 5, 6, 11, 3, 5, 2, 11, 19, 1, 4, 9, 19, 1, 2, 9, 1, 1, 4, 9, 3, 1, 2, 9, 4, 15, 18, 9, 4, 15, 9, 9, 6, 9, 12, 4, 6, 11, 12, 2, 15, 2, 9, 6, 15, 4, 9, 2, 0, 2, 9, 6, 0, 4, 9, 2, 15, 0, 6, 17, 17, 0, 2, 17, 3, 0, 6, 17, 5, 0, 2, 17, 8, 17, 9, 4, 8, 19, 9, 2, 6, 5, 3, 18, 6, 11, 3, 6, 5, 2, 14, 12, 5, 8, 14, 6, 10, 2, 3, 12, 10, 8, 3, 6, 10, 7, 14, 15, 10, 12, 14, 5, 0, 7, 14, 15, 0, 12, 14, 5, 15, 0, 9, 6, 15, 2, 9, 2, 0, 0, 9, 6, 0, 2, 9, 2, 12, 6, 6, 14, 14, 6, 2, 14, 9, 7, 6, 9, 11, 7, 2, 9, 12, 6, 6, 15, 14, 6, 2, 15, 6, 6, 6, 15, 8, 6, 2, 15, 15, 3, 8, 9, 15, 3, 4, 9, 0, 0, 9, 21, 3, 0, 3, 21, 11, 9, 8, 12, 11, 13, 8, 4, 6, 7, 10, 12, 6, 7, 5, 6, 11, 13, 5, 6, 10, 6, 4, 18, 12, 6, 2, 9, 10, 15, 2, 9, 0, 0, 6, 9, 0, 3, 6, 3, 3, 14, 18, 3, 3, 15, 18, 1, 3, 14, 8, 10, 3, 14, 4, 5, 7, 19, 4, 5, 0, 12, 24, 4, 12, 12, 12, 2, 0, 14, 12, 2, 0, 2, 3, 20, 1, 2, 1, 20, 12, 16, 10, 8, 17, 16, 5, 4, 12, 20, 5, 4, 2, 16, 10, 8, 2, 16, 5, 4, 7, 20, 5, 4, 7, 0, 10, 9, 7, 3, 10, 3, 0, 0, 24, 3, 8, 0, 8, 3, 3, 8, 15, 4, 3, 10, 15, 2, 6, 5, 12, 6, 10, 5, 4, 6, 5, 13, 14, 6, 5, 16, 14, 3, 11, 14, 4, 10, 11, 19, 4, 5, 0, 6, 6, 7, 3, 6, 3, 7, 18, 0, 6, 6, 18, 0, 3, 6, 3, 1, 18, 3, 3, 2, 18, 1, 9, 6, 14, 18, 9, 12, 14, 6, 0, 0, 6, 6, 3, 0, 3, 6, 13, 11, 6, 6, 13, 11, 3, 6, 0, 20, 24, 3, 8, 20, 8, 3, 13, 11, 6, 7, 13, 11, 3, 7, 4, 12, 10, 6, 4, 14, 10, 2, 13, 11, 6, 6, 13, 11, 3, 6, 5, 11, 6, 7, 8, 11, 3, 7, 7, 4, 11, 12, 7, 8, 11, 4, 6, 15, 10, 4, 6, 17, 10, 2, 14, 0, 6, 9, 16, 0, 2, 9, 4, 0, 6, 9, 6, 0, 2, 9, 11, 2, 4, 15, 11, 7, 4, 5, 0, 0, 20, 3, 0, 1, 20, 1, 13, 18, 10, 6, 13, 20, 10, 2, 2, 7, 6, 11, 5, 7, 3, 11, 10, 14, 10, 9, 10, 17, 10, 3, 8, 2, 4, 9, 10, 2, 2, 9, 14, 3, 10, 4, 14, 3, 5, 4, 6, 6, 12, 6, 6, 6, 6, 3, 12, 9, 6, 3, 8, 8, 8, 10, 12, 8, 4, 5, 8, 13, 4, 5, 7, 4, 4, 16, 7, 12, 4, 8, 8, 8, 9, 4, 8, 10, 9, 2, 5, 2, 14, 9, 5, 5, 14, 3, 3, 16, 19, 8, 3, 20, 19, 4, 0, 0, 10, 8, 5, 0, 5, 8, 5, 2, 16, 18, 5, 2, 8, 18, 0, 11, 24, 11, 8, 11, 8, 11, 3, 3, 18, 5, 3, 3, 9, 5, 1, 16, 18, 3, 1, 17, 18, 1, 5, 17, 18, 3, 5, 18, 18, 1, 1, 13, 9, 6, 1, 15, 9, 2, 1, 9, 23, 10, 1, 14, 23, 5, 3, 7, 18, 3, 3, 8, 18, 1, 6, 8, 12, 3, 6, 8, 6, 3, 6, 2, 3, 22, 7, 2, 1, 22, 14, 17, 10, 6, 14, 19, 10, 2, 1, 18, 10, 6, 1, 20, 10, 2, 11, 3, 6, 12, 13, 3, 2, 12, 10, 6, 4, 9, 12, 6, 2, 9, 11, 0, 6, 9, 13, 0, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 12, 10, 9, 6, 15, 10, 3, 6, 2, 11, 6, 9, 5, 11, 3, 9, 14, 5, 3, 19, 15, 5, 1, 19, 6, 6, 9, 6, 6, 8, 9, 2, 14, 5, 3, 19, 15, 5, 1, 19, 0, 3, 6, 9, 0, 6, 6, 3, 5, 21, 18, 3, 5, 22, 18, 1, 1, 10, 18, 4, 7, 10, 6, 4, 13, 4, 8, 10, 17, 4, 4, 5, 13, 9, 4, 5, 7, 8, 9, 6, 10, 8, 3, 6, 12, 9, 9, 8, 15, 9, 3, 8, 0, 6, 5, 12, 0, 10, 5, 4, 7, 6, 14, 6, 14, 6, 7, 3, 7, 9, 7, 3, 7, 5, 3, 19, 8, 5, 1, 19, 8, 4, 15, 20, 13, 4, 5, 20, 1, 4, 15, 20, 6, 4, 5, 20, 13, 10, 6, 6, 13, 10, 3, 6, 5, 10, 6, 6, 8, 10, 3, 6, 14, 2, 6, 14, 17, 2, 3, 7, 14, 9, 3, 7, 4, 2, 6, 14, 4, 2, 3, 7, 7, 9, 3, 7, 12, 4, 6, 7, 12, 4, 3, 7, 9, 4, 6, 9, 11, 4, 2, 9, 11, 4, 8, 10, 11, 4, 4, 10, 5, 4, 8, 10, 9, 4, 4, 10, 8, 18, 10, 6, 8, 20, 10, 2, 1, 18, 21, 6, 1, 20, 21, 2, 9, 2, 12, 6, 9, 2, 6, 6, 3, 2, 12, 6, 9, 2, 6, 6, 12, 5, 12, 6, 18, 5, 6, 3, 12, 8, 6, 3, 8, 8, 6, 9, 8, 11, 6, 3, 2, 7, 20, 6, 2, 9, 20, 2, 0, 5, 12, 6, 0, 5, 6, 3, 6, 8, 6, 3, 14, 14, 8, 10, 18, 14, 4, 5, 14, 19, 4, 5, 2, 14, 8, 10, 2, 14, 4, 5, 6, 19, 4, 5, 2, 11, 20, 13, 2, 11, 10, 13, 6, 9, 12, 5, 12, 9, 6, 5, 5, 6, 16, 6, 13, 6, 8, 3, 5, 9, 8, 3, 1, 19, 9, 4, 1, 21, 9, 2, 7, 5, 12, 5, 11, 5, 4, 5, 3, 5, 14, 12, 3, 5, 7, 6, 10, 11, 7, 6, 9, 4, 9, 6, 12, 4, 3, 6, 2, 6, 19, 3, 2, 7, 19, 1, 18, 10, 6, 9, 18, 13, 6, 3, 3, 7, 18, 2, 3, 8, 18, 1, 20, 2, 4, 18, 22, 2, 2, 9, 20, 11, 2, 9, 2, 18, 20, 3, 2, 19, 20, 1, 1, 9, 22, 3, 1, 10, 22, 1, 0, 2, 4, 18, 0, 2, 2, 9, 2, 11, 2, 9, 19, 0, 4, 23, 19, 0, 2, 23, 0, 3, 6, 19, 3, 3, 3, 19, 18, 2, 6, 9, 20, 2, 2, 9, 0, 5, 10, 6, 0, 7, 10, 2, 7, 0, 12, 12, 13, 0, 6, 6, 7, 6, 6, 6, 0, 3, 24, 6, 0, 3, 12, 3, 12, 6, 12, 3, 10, 14, 4, 10, 10, 19, 4, 5, 8, 9, 4, 15, 8, 14, 4, 5, 4, 11, 17, 6, 4, 14, 17, 3, 2, 5, 18, 8, 2, 5, 9, 4, 11, 9, 9, 4, 7, 6, 14, 6, 14, 6, 7, 3, 7, 9, 7, 3, 3, 6, 14, 6, 3, 6, 7, 3, 10, 9, 7, 3, 16, 5, 3, 18, 17, 5, 1, 18, 5, 5, 3, 18, 6, 5, 1, 18, 10, 10, 14, 4, 10, 12, 14, 2, 4, 10, 9, 4, 4, 12, 9, 2, 2, 0, 18, 9, 2, 3, 18, 3, 6, 3, 12, 8, 10, 3, 4, 8, 1, 1, 8, 5, 5, 1, 4, 5, 12, 7, 7, 8, 12, 11, 7, 4, 0, 12, 22, 4, 0, 14, 22, 2, 15, 6, 4, 15, 15, 11, 4, 5, 5, 7, 7, 8, 5, 11, 7, 4, 8, 18, 9, 4, 8, 20, 9, 2, 1, 2, 22, 4, 1, 4, 22, 2, 17, 3, 6, 17, 19, 3, 2, 17, 8, 2, 8, 18, 8, 11, 8, 9, 17, 0, 6, 12, 20, 0, 3, 6, 17, 6, 3, 6, 7, 0, 6, 9, 9, 0, 2, 9, 15, 5, 9, 12, 15, 11, 9, 6, 2, 22, 18, 2, 2, 23, 18, 1, 10, 10, 12, 6, 16, 10, 6, 3, 10, 13, 6, 3, 0, 1, 4, 11, 2, 1, 2, 11, 20, 0, 4, 10, 20, 0, 2, 10, 1, 3, 6, 17, 3, 3, 2, 17, 15, 15, 9, 6, 15, 17, 9, 2, 0, 13, 8, 9, 0, 16, 8, 3, 16, 8, 6, 12, 16, 12, 6, 4, 2, 8, 6, 12, 2, 12, 6, 4, 10, 2, 4, 15, 10, 7, 4, 5, 1, 5, 19, 3, 1, 6, 19, 1, 11, 8, 9, 7, 14, 8, 3, 7, 3, 8, 12, 9, 3, 11, 12, 3, 3, 6, 18, 3, 3, 7, 18, 1, 10, 0, 4, 12, 10, 6, 4, 6, 3, 9, 18, 14, 3, 9, 9, 14, 0, 0, 4, 9, 2, 0, 2, 9, 12, 5, 4, 18, 12, 5, 2, 18, 8, 5, 4, 18, 10, 5, 2, 18, 10, 5, 6, 10, 12, 5, 2, 10, 9, 4, 4, 11, 11, 4, 2, 11, 4, 16, 18, 3, 4, 17, 18, 1, 0, 16, 20, 3, 0, 17, 20, 1, 9, 9, 6, 12, 9, 13, 6, 4, 8, 13, 8, 8, 8, 17, 8, 4, 13, 10, 3, 12, 13, 16, 3, 6, 5, 9, 14, 14, 5, 9, 7, 7, 12, 16, 7, 7, 0, 0, 24, 10, 12, 0, 12, 5, 0, 5, 12, 5, 1, 11, 18, 2, 1, 12, 18, 1, 19, 5, 5, 12, 19, 9, 5, 4, 0, 5, 5, 12, 0, 9, 5, 4, 16, 6, 8, 18, 20, 6, 4, 9, 16, 15, 4, 9, 0, 6, 8, 18, 0, 6, 4, 9, 4, 15, 4, 9, 12, 5, 12, 12, 18, 5, 6, 6, 12, 11, 6, 6, 7, 6, 6, 9, 9, 6, 2, 9, 9, 13, 6, 11, 11, 13, 2, 11, 0, 5, 12, 12, 0, 5, 6, 6, 6, 11, 6, 6, 1, 2, 23, 3, 1, 3, 23, 1, 1, 15, 19, 3, 1, 16, 19, 1, 13, 17, 11, 4, 13, 19, 11, 2, 0, 13, 8, 5, 4, 13, 4, 5, 12, 10, 10, 4, 12, 10, 5, 4, 4, 6, 9, 9, 4, 9, 9, 3, 15, 14, 9, 6, 15, 16, 9, 2, 1, 12, 9, 6, 1, 14, 9, 2, 3, 10, 20, 8, 13, 10, 10, 4, 3, 14, 10, 4, 2, 0, 9, 18, 5, 0, 3, 18, 13, 11, 9, 10, 16, 11, 3, 10, 1, 2, 8, 5, 5, 2, 4, 5, 3, 4, 21, 6, 10, 4, 7, 6, 7, 0, 10, 14, 7, 0, 5, 7, 12, 7, 5, 7, 12, 17, 12, 4, 12, 19, 12, 2, 0, 6, 23, 4, 0, 8, 23, 2, 13, 10, 8, 10, 17, 10, 4, 5, 13, 15, 4, 5, 0, 16, 18, 3, 0, 17, 18, 1, 15, 16, 9, 4, 15, 18, 9, 2, 0, 16, 9, 4, 0, 18, 9, 2, 13, 11, 6, 6, 13, 11, 3, 6, 5, 11, 6, 6, 8, 11, 3, 6, 0, 3, 24, 6, 12, 3, 12, 3, 0, 6, 12, 3, 2, 4, 18, 3, 2, 5, 18, 1, 0, 0, 24, 4, 12, 0, 12, 2, 0, 2, 12, 2, 1, 16, 18, 3, 1, 17, 18, 1, 15, 15, 9, 6, 15, 17, 9, 2, 0, 15, 9, 6, 0, 17, 9, 2, 6, 17, 18, 3, 6, 18, 18, 1, 8, 8, 6, 10, 10, 8, 2, 10, 10, 6, 6, 9, 12, 6, 2, 9, 8, 8, 5, 8, 8, 12, 5, 4, 12, 8, 6, 8, 12, 12, 6, 4, 6, 5, 6, 11, 8, 5, 2, 11, 13, 6, 8, 9, 13, 9, 8, 3, 1, 7, 21, 6, 1, 9, 21, 2, 15, 5, 3, 12, 15, 11, 3, 6, 6, 9, 11, 12, 6, 13, 11, 4, 13, 8, 10, 8, 18, 8, 5, 4, 13, 12, 5, 4, 5, 8, 12, 3, 11, 8, 6, 3, 6, 11, 18, 4, 12, 11, 6, 4, 0, 0, 22, 22, 0, 11, 22, 11, 11, 2, 6, 8, 11, 6, 6, 4, 9, 0, 6, 9, 11, 0, 2, 9, 10, 0, 6, 9, 12, 0, 2, 9, 8, 3, 6, 14, 8, 3, 3, 7, 11, 10, 3, 7, 3, 10, 18, 8, 9, 10, 6, 8, 10, 0, 3, 14, 10, 7, 3, 7, 4, 3, 16, 20, 4, 13, 16, 10, 9, 4, 6, 10, 11, 4, 2, 10, 5, 0, 16, 4, 5, 2, 16, 2, 2, 5, 18, 4, 8, 5, 6, 4, 13, 0, 6, 9, 15, 0, 2, 9, 8, 4, 8, 5, 12, 4, 4, 5, 12, 10, 10, 4, 12, 10, 5, 4, 2, 10, 10, 4, 7, 10, 5, 4, 7, 11, 12, 5, 11, 11, 4, 5, 3, 10, 8, 10, 3, 10, 4, 5, 7, 15, 4, 5, 11, 12, 9, 8, 14, 12, 3, 8, 0, 21, 24, 3, 8, 21, 8, 3, 3, 20, 18, 4, 9, 20, 6, 4, 1, 15, 9, 6, 1, 17, 9, 2, 11, 17, 10, 4, 11, 19, 10, 2, 9, 12, 4, 12, 9, 18, 4, 6, 9, 6, 9, 6, 12, 6, 3, 6, 1, 13, 6, 9, 1, 16, 6, 3, 6, 16, 12, 4, 6, 18, 12, 2, 1, 5, 20, 3, 1, 6, 20, 1, 8, 1, 9, 9, 8, 4, 9, 3, 2, 19, 9, 4, 2, 21, 9, 2, 11, 1, 4, 18, 11, 7, 4, 6, 7, 2, 8, 12, 7, 2, 4, 6, 11, 8, 4, 6, 11, 10, 9, 8, 14, 10, 3, 8, 5, 11, 12, 5, 9, 11, 4, 5, 11, 9, 9, 6, 14, 9, 3, 6, 5, 10, 6, 9, 7, 10, 2, 9, 4, 7, 5, 12, 4, 11, 5, 4, 2, 0, 21, 6, 9, 0, 7, 6, 7, 6, 10, 6, 7, 8, 10, 2, 9, 0, 6, 15, 11, 0, 2, 15, 2, 2, 18, 2, 2, 3, 18, 1, 8, 17, 8, 6, 8, 20, 8, 3, 3, 0, 18, 2, 3, 1, 18, 1, 8, 0, 9, 6, 11, 0, 3, 6, 0, 17, 18, 3, 0, 18, 18, 1, 6, 7, 12, 5, 10, 7, 4, 5, 0, 3, 6, 9, 2, 3, 2, 9, 20, 2, 4, 9, 20, 2, 2, 9, 0, 2, 4, 9, 2, 2, 2, 9, 0, 1, 24, 4, 12, 1, 12, 2, 0, 3, 12, 2, 0, 16, 9, 6, 0, 18, 9, 2, 14, 13, 9, 6, 14, 15, 9, 2, 0, 15, 19, 3, 0, 16, 19, 1, 1, 5, 22, 12, 12, 5, 11, 6, 1, 11, 11, 6, 5, 13, 6, 6, 8, 13, 3, 6, 4, 2, 20, 3, 4, 3, 20, 1, 8, 14, 6, 10, 10, 14, 2, 10, 6, 12, 16, 6, 14, 12, 8, 3, 6, 15, 8, 3, 2, 13, 8, 9, 2, 16, 8, 3, 11, 8, 6, 14, 14, 8, 3, 7, 11, 15, 3, 7, 2, 12, 16, 6, 2, 12, 8, 3, 10, 15, 8, 3, 5, 16, 16, 8, 5, 20, 16, 4, 9, 1, 4, 12, 9, 7, 4, 6, 8, 2, 8, 10, 12, 2, 4, 5, 8, 7, 4, 5, 6, 6, 12, 6, 6, 6, 6, 3, 12, 9, 6, 3, 10, 7, 6, 9, 12, 7, 2, 9, 0, 0, 8, 12, 0, 0, 4, 6, 4, 6, 4, 6, 18, 8, 6, 9, 18, 11, 6, 3, 2, 12, 6, 6, 5, 12, 3, 6, 3, 21, 21, 3, 10, 21, 7, 3, 2, 0, 16, 6, 2, 3, 16, 3, 13, 6, 7, 6, 13, 9, 7, 3, 6, 4, 4, 14, 6, 11, 4, 7, 9, 7, 6, 9, 11, 7, 2, 9, 7, 8, 6, 14, 7, 8, 3, 7, 10, 15, 3, 7, 18, 8, 4, 16, 18, 16, 4, 8, 9, 14, 6, 10, 11, 14, 2, 10, 6, 11, 12, 5, 10, 11, 4, 5, 0, 12, 23, 3, 0, 13, 23, 1, 13, 0, 6, 12, 15, 0, 2, 12, 0, 10, 12, 5, 4, 10, 4, 5, 13, 2, 10, 4, 13, 4, 10, 2, 5, 0, 6, 12, 7, 0, 2, 12, 11, 6, 9, 6, 14, 6, 3, 6, 4, 6, 9, 6, 7, 6, 3, 6, 6, 11, 18, 13, 12, 11, 6, 13, 0, 11, 18, 13, 6, 11, 6, 13, 12, 16, 12, 6, 16, 16, 4, 6, 0, 6, 21, 3, 0, 7, 21, 1, 12, 16, 12, 6, 16, 16, 4, 6, 5, 7, 6, 14, 5, 14, 6, 7, 5, 10, 19, 2, 5, 11, 19, 1, 5, 4, 14, 4, 5, 6, 14, 2, 3, 18, 18, 4, 9, 18, 6, 4, 7, 0, 4, 9, 9, 0, 2, 9, 13, 3, 11, 4, 13, 5, 11, 2, 2, 0, 9, 6, 5, 0, 3, 6, 19, 1, 4, 23, 19, 1, 2, 23, 1, 1, 4, 23, 3, 1, 2, 23, 5, 16, 18, 3, 5, 17, 18, 1, 0, 3, 11, 4, 0, 5, 11, 2, 2, 16, 20, 3, 2, 17, 20, 1, 5, 3, 13, 4, 5, 5, 13, 2, 1, 9, 22, 15, 1, 9, 11, 15, 3, 4, 14, 3, 10, 4, 7, 3, 8, 7, 10, 4, 8, 7, 5, 4, 6, 7, 10, 4, 11, 7, 5, 4, 10, 4, 6, 9, 12, 4, 2, 9, 1, 12, 9, 6, 4, 12, 3, 6, 8, 3, 8, 10, 12, 3, 4, 5, 8, 8, 4, 5, 3, 6, 16, 6, 3, 6, 8, 3, 11, 9, 8, 3, 5, 6, 14, 6, 5, 9, 14, 3, 4, 3, 9, 6, 4, 5, 9, 2, 6, 3, 18, 2, 6, 4, 18, 1, 7, 6, 9, 6, 10, 6, 3, 6, 0, 1, 24, 3, 0, 2, 24, 1, 0, 17, 10, 6, 0, 19, 10, 2, 3, 18, 18, 3, 3, 19, 18, 1, 2, 5, 6, 16, 2, 5, 3, 8, 5, 13, 3, 8, 7, 6, 11, 6, 7, 8, 11, 2, 5, 2, 12, 22, 5, 13, 12, 11, 10, 7, 4, 10, 10, 12, 4, 5, 9, 0, 4, 18, 9, 6, 4, 6, 18, 8, 6, 9, 18, 11, 6, 3, 4, 7, 15, 10, 9, 7, 5, 10, 10, 5, 6, 9, 12, 5, 2, 9, 9, 9, 6, 10, 11, 9, 2, 10, 11, 14, 6, 10, 13, 14, 2, 10, 7, 14, 6, 10, 9, 14, 2, 10, 4, 8, 16, 9, 4, 11, 16, 3, 2, 11, 20, 3, 2, 12, 20, 1, 13, 0, 4, 13, 13, 0, 2, 13, 7, 0, 4, 13, 9, 0, 2, 13, 3, 1, 18, 7, 9, 1, 6, 7, 1, 11, 6, 9, 1, 14, 6, 3, 8, 18, 9, 6, 8, 20, 9, 2, 3, 9, 15, 6, 3, 11, 15, 2, 5, 10, 19, 2, 5, 11, 19, 1, 8, 6, 7, 16, 8, 14, 7, 8, 9, 14, 9, 6, 9, 16, 9, 2, 0, 7, 8, 12, 0, 11, 8, 4, 6, 4, 18, 3, 6, 5, 18, 1, 0, 16, 12, 6, 4, 16, 4, 6, 13, 13, 9, 4, 13, 15, 9, 2, 5, 8, 14, 14, 5, 8, 7, 7, 12, 15, 7, 7, 1, 16, 22, 6, 12, 16, 11, 3, 1, 19, 11, 3, 9, 0, 6, 9, 11, 0, 2, 9, 9, 5, 10, 10, 14, 5, 5, 5, 9, 10, 5, 5, 5, 5, 10, 10, 5, 5, 5, 5, 10, 10, 5, 5, 4, 6, 16, 6, 12, 6, 8, 3, 4, 9, 8, 3, 0, 7, 6, 9, 0, 10, 6, 3, 16, 10, 8, 14, 20, 10, 4, 7, 16, 17, 4, 7, 9, 12, 6, 12, 9, 18, 6, 6, 8, 10, 8, 12, 12, 10, 4, 6, 8, 16, 4, 6, 8, 0, 4, 9, 10, 0, 2, 9, 10, 4, 8, 16, 14, 4, 4, 8, 10, 12, 4, 8, 7, 10, 10, 6, 7, 12, 10, 2, 5, 6, 14, 14, 12, 6, 7, 7, 5, 13, 7, 7, 2, 11, 20, 2, 2, 12, 20, 1, 18, 8, 4, 16, 18, 16, 4, 8, 1, 11, 12, 10, 1, 11, 6, 5, 7, 16, 6, 5, 6, 9, 12, 4, 6, 11, 12, 2, 9, 12, 6, 7, 12, 12, 3, 7, 10, 4, 8, 16, 14, 4, 4, 8, 10, 12, 4, 8, 6, 4, 8, 16, 6, 4, 4, 8, 10, 12, 4, 8, 8, 9, 9, 6, 11, 9, 3, 6, 1, 5, 16, 12, 1, 5, 8, 6, 9, 11, 8, 6, 9, 9, 6, 8, 9, 9, 3, 8, 6, 0, 3, 18, 7, 0, 1, 18, 17, 9, 5, 14, 17, 16, 5, 7, 2, 9, 5, 14, 2, 16, 5, 7, 7, 4, 10, 6, 7, 7, 10, 3, 1, 3, 23, 18, 1, 9, 23, 6, 1, 1, 21, 3, 8, 1, 7, 3, 9, 6, 6, 9, 11, 6, 2, 9, 3, 18, 12, 6, 3, 18, 6, 3, 9, 21, 6, 3, 16, 8, 8, 16, 20, 8, 4, 8, 16, 16, 4, 8, 0, 19, 24, 4, 8, 19, 8, 4, 16, 8, 8, 16, 20, 8, 4, 8, 16, 16, 4, 8, 0, 8, 8, 16, 0, 8, 4, 8, 4, 16, 4, 8, 8, 12, 8, 10, 8, 17, 8, 5, 5, 7, 5, 8, 5, 11, 5, 4, 4, 1, 19, 2, 4, 2, 19, 1, 0, 12, 24, 9, 8, 12, 8, 9, 6, 0, 13, 8, 6, 4, 13, 4, 0, 0, 24, 3, 0, 1, 24, 1, 20, 3, 4, 11, 20, 3, 2, 11, 8, 6, 6, 9, 10, 6, 2, 9, 6, 11, 12, 8, 12, 11, 6, 4, 6, 15, 6, 4, 0, 8, 12, 6, 0, 8, 6, 3, 6, 11, 6, 3, 6, 17, 18, 3, 6, 18, 18, 1, 0, 14, 9, 6, 0, 16, 9, 2, 20, 3, 4, 9, 20, 3, 2, 9, 0, 3, 4, 9, 2, 3, 2, 9, 15, 0, 9, 19, 18, 0, 3, 19, 0, 0, 9, 19, 3, 0, 3, 19, 13, 11, 6, 8, 13, 11, 3, 8, 5, 11, 6, 8, 8, 11, 3, 8, 5, 11, 19, 3, 5, 12, 19, 1, 3, 20, 18, 4, 9, 20, 6, 4, 6, 6, 16, 6, 6, 8, 16, 2, 6, 0, 9, 6, 9, 0, 3, 6, 10, 3, 4, 14, 10, 10, 4, 7, 1, 5, 15, 12, 1, 11, 15, 6, 11, 12, 8, 5, 11, 12, 4, 5, 5, 0, 6, 9, 7, 0, 2, 9, 12, 0, 6, 9, 14, 0, 2, 9, 5, 5, 12, 8, 5, 5, 6, 4, 11, 9, 6, 4, 13, 12, 11, 6, 13, 14, 11, 2, 0, 13, 21, 3, 0, 14, 21, 1, 8, 1, 8, 12, 12, 1, 4, 6, 8, 7, 4, 6, 1, 0, 6, 12, 1, 0, 3, 6, 4, 6, 3, 6, 2, 2, 21, 2, 2, 3, 21, 1, 2, 2, 19, 3, 2, 3, 19, 1, 17, 10, 6, 14, 20, 10, 3, 7, 17, 17, 3, 7, 1, 10, 6, 14, 1, 10, 3, 7, 4, 17, 3, 7, 7, 6, 14, 14, 14, 6, 7, 7, 7, 13, 7, 7, 0, 12, 9, 6, 0, 14, 9, 2, 15, 14, 8, 9, 15, 17, 8, 3, 1, 1, 22, 4, 1, 1, 11, 2, 12, 3, 11, 2, 9, 11, 9, 6, 9, 13, 9, 2, 0, 15, 18, 3, 0, 16, 18, 1, 16, 14, 7, 9, 16, 17, 7, 3, 4, 3, 16, 4, 12, 3, 8, 4, 7, 6, 12, 5, 7, 6, 6, 5, 9, 6, 4, 9, 11, 6, 2, 9, 12, 1, 4, 10, 12, 1, 2, 10, 8, 1, 4, 10, 10, 1, 2, 10, 15, 15, 6, 9, 15, 18, 6, 3, 3, 15, 6, 9, 3, 18, 6, 3, 15, 1, 3, 19, 16, 1, 1, 19, 1, 3, 6, 9, 3, 3, 2, 9, 15, 0, 3, 19, 16, 0, 1, 19, 6, 3, 12, 4, 12, 3, 6, 4, 10, 5, 4, 9, 10, 5, 2, 9, 6, 0, 3, 19, 7, 0, 1, 19, 11, 1, 3, 12, 11, 7, 3, 6, 6, 7, 10, 5, 11, 7, 5, 5, 11, 3, 3, 18, 12, 3, 1, 18, 9, 3, 6, 12, 11, 3, 2, 12, 3, 7, 19, 3, 3, 8, 19, 1, 2, 7, 18, 3, 2, 8, 18, 1, 3, 13, 18, 4, 12, 13, 9, 2, 3, 15, 9, 2, 3, 5, 6, 9, 5, 5, 2, 9, 4, 1, 20, 4, 14, 1, 10, 2, 4, 3, 10, 2, 0, 1, 20, 4, 0, 1, 10, 2, 10, 3, 10, 2, 10, 15, 6, 6, 10, 15, 3, 6, 0, 2, 24, 8, 8, 2, 8, 8, 5, 5, 18, 3, 5, 6, 18, 1, 8, 15, 6, 6, 11, 15, 3, 6, 11, 12, 8, 5, 11, 12, 4, 5, 5, 12, 8, 5, 9, 12, 4, 5, 5, 0, 14, 6, 5, 2, 14, 2, 10, 2, 4, 15, 10, 7, 4, 5, 10, 7, 5, 12, 10, 11, 5, 4, 7, 9, 8, 14, 7, 9, 4, 7, 11, 16, 4, 7, 1, 5, 22, 6, 12, 5, 11, 3, 1, 8, 11, 3, 0, 5, 6, 6, 0, 8, 6, 3, 12, 17, 9, 4, 12, 19, 9, 2, 2, 18, 19, 3, 2, 19, 19, 1, 12, 17, 9, 4, 12, 19, 9, 2, 1, 17, 18, 3, 1, 18, 18, 1, 12, 17, 9, 4, 12, 19, 9, 2, 0, 0, 24, 3, 0, 1, 24, 1, 5, 0, 14, 4, 5, 2, 14, 2, 6, 14, 9, 6, 6, 16, 9, 2, 14, 13, 6, 9, 14, 16, 6, 3, 5, 20, 13, 4, 5, 22, 13, 2, 9, 9, 6, 12, 9, 13, 6, 4, 1, 10, 21, 3, 8, 10, 7, 3, 8, 8, 9, 6, 11, 8, 3, 6, 3, 10, 9, 7, 6, 10, 3, 7, 12, 10, 10, 8, 17, 10, 5, 4, 12, 14, 5, 4, 0, 15, 24, 3, 8, 15, 8, 3, 8, 5, 9, 6, 8, 7, 9, 2, 4, 13, 6, 9, 4, 16, 6, 3, 12, 17, 9, 4, 12, 19, 9, 2, 9, 12, 6, 6, 9, 15, 6, 3, 9, 9, 14, 10, 16, 9, 7, 5, 9, 14, 7, 5, 1, 9, 14, 10, 1, 9, 7, 5, 8, 14, 7, 5, 8, 7, 9, 17, 11, 7, 3, 17, 3, 4, 6, 20, 3, 4, 3, 10, 6, 14, 3, 10, 7, 8, 10, 4, 7, 8, 5, 4, 10, 7, 4, 9, 12, 7, 2, 9, 10, 15, 6, 9, 12, 15, 2, 9, 3, 8, 6, 16, 3, 8, 3, 8, 6, 16, 3, 8, 12, 17, 9, 4, 12, 19, 9, 2, 3, 17, 9, 4, 3, 19, 9, 2, 10, 1, 9, 6, 13, 1, 3, 6, 5, 7, 4, 10, 5, 12, 4, 5, 7, 5, 12, 6, 11, 5, 4, 6, 6, 4, 9, 8, 9, 4, 3, 8, 12, 16, 10, 8, 17, 16, 5, 4, 12, 20, 5, 4, 2, 16, 10, 8, 2, 16, 5, 4, 7, 20, 5, 4, 0, 0, 24, 4, 12, 0, 12, 2, 0, 2, 12, 2, 0, 6, 9, 6, 0, 8, 9, 2, 0, 4, 24, 6, 12, 4, 12, 3, 0, 7, 12, 3, 5, 0, 11, 4, 5, 2, 11, 2, 1, 1, 22, 4, 12, 1, 11, 2, 1, 3, 11, 2, 9, 6, 6, 18, 9, 15, 6, 9, 2, 9, 20, 4, 2, 11, 20, 2, 5, 2, 14, 14, 5, 9, 14, 7, 4, 2, 16, 6, 4, 5, 16, 3, 2, 3, 19, 3, 2, 4, 19, 1, 7, 1, 10, 4, 7, 3, 10, 2, 0, 9, 4, 15, 0, 14, 4, 5, 2, 10, 21, 3, 2, 11, 21, 1, 3, 0, 6, 6, 6, 0, 3, 6, 6, 4, 14, 9, 6, 7, 14, 3, 9, 1, 6, 9, 11, 1, 2, 9, 15, 8, 9, 9, 15, 11, 9, 3, 8, 0, 4, 21, 8, 7, 4, 7, 3, 22, 19, 2, 3, 23, 19, 1, 2, 15, 20, 3, 2, 16, 20, 1, 19, 0, 4, 13, 19, 0, 2, 13, 1, 7, 8, 8, 1, 11, 8, 4, 14, 14, 6, 9, 14, 17, 6, 3, 4, 14, 6, 9, 4, 17, 6, 3, 14, 5, 4, 10, 14, 5, 2, 10, 6, 5, 4, 10, 8, 5, 2, 10, 14, 5, 6, 6, 14, 8, 6, 3, 4, 5, 6, 6, 4, 8, 6, 3, 0, 2, 24, 21, 8, 2, 8, 21, 1, 2, 6, 13, 3, 2, 2, 13, 20, 0, 4, 21, 20, 0, 2, 21, 0, 4, 4, 20, 2, 4, 2, 20, 8, 16, 9, 6, 8, 18, 9, 2, 7, 0, 6, 9, 9, 0, 2, 9, 16, 12, 7, 9, 16, 15, 7, 3, 5, 21, 14, 3, 12, 21, 7, 3, 11, 5, 6, 9, 11, 5, 3, 9, 10, 5, 4, 10, 12, 5, 2, 10, 10, 6, 6, 9, 12, 6, 2, 9, 7, 5, 6, 9, 10, 5, 3, 9, 14, 14, 10, 4, 14, 16, 10, 2, 5, 5, 14, 14, 5, 5, 7, 7, 12, 12, 7, 7, 12, 8, 12, 6, 18, 8, 6, 3, 12, 11, 6, 3, 6, 6, 12, 12, 6, 6, 6, 6, 12, 12, 6, 6, 11, 13, 6, 10, 13, 13, 2, 10, 1, 10, 20, 8, 1, 10, 10, 4, 11, 14, 10, 4, 15, 13, 9, 6, 15, 15, 9, 2, 9, 0, 6, 9, 9, 3, 6, 3, 10, 1, 5, 14, 10, 8, 5, 7, 3, 4, 16, 6, 3, 6, 16, 2, 16, 3, 8, 9, 16, 6, 8, 3, 7, 13, 6, 10, 9, 13, 2, 10, 15, 13, 9, 6, 15, 15, 9, 2, 0, 13, 9, 6, 0, 15, 9, 2, 13, 16, 9, 6, 13, 18, 9, 2, 2, 16, 9, 6, 2, 18, 9, 2, 5, 16, 18, 3, 5, 17, 18, 1, 1, 16, 18, 3, 1, 17, 18, 1, 5, 0, 18, 3, 5, 1, 18, 1, 1, 1, 19, 2, 1, 2, 19, 1, 14, 2, 6, 11, 16, 2, 2, 11, 4, 15, 15, 6, 9, 15, 5, 6, 14, 2, 6, 11, 16, 2, 2, 11, 4, 2, 6, 11, 6, 2, 2, 11, 18, 2, 6, 9, 18, 5, 6, 3, 1, 2, 22, 4, 1, 2, 11, 2, 12, 4, 11, 2, 2, 0, 21, 12, 9, 0, 7, 12, 0, 12, 18, 3, 0, 13, 18, 1, 12, 2, 6, 9, 14, 2, 2, 9, 3, 10, 18, 3, 3, 11, 18, 1, 16, 3, 8, 9, 16, 6, 8, 3, 3, 7, 18, 3, 3, 8, 18, 1, 9, 11, 6, 9, 11, 11, 2, 9, 9, 8, 6, 9, 11, 8, 2, 9, 15, 0, 2, 18, 15, 0, 1, 18, 7, 0, 2, 18, 8, 0, 1, 18, 17, 3, 7, 9, 17, 6, 7, 3, 3, 18, 9, 6, 3, 20, 9, 2, 3, 18, 21, 3, 3, 19, 21, 1, 0, 3, 7, 9, 0, 6, 7, 3, 2, 7, 22, 3, 2, 8, 22, 1, 0, 3, 24, 16, 0, 3, 12, 8, 12, 11, 12, 8, 13, 17, 9, 4, 13, 19, 9, 2, 5, 5, 12, 8, 5, 5, 6, 4, 11, 9, 6, 4, 5, 6, 14, 6, 12, 6, 7, 3, 5, 9, 7, 3, 5, 16, 14, 6, 5, 16, 7, 3, 12, 19, 7, 3, 18, 2, 6, 9, 18, 5, 6, 3, 0, 2, 6, 9, 0, 5, 6, 3, 3, 4, 20, 10, 13, 4, 10, 5, 3, 9, 10, 5, 2, 13, 9, 8, 5, 13, 3, 8, 2, 1, 21, 15, 9, 1, 7, 15, 5, 12, 14, 8, 12, 12, 7, 8, 6, 7, 12, 4, 6, 7, 6, 4, 6, 5, 9, 6, 9, 5, 3, 6, 13, 11, 6, 6, 13, 11, 3, 6, 5, 11, 6, 6, 8, 11, 3, 6, 6, 4, 18, 2, 6, 5, 18, 1, 0, 2, 6, 11, 2, 2, 2, 11, 18, 0, 6, 15, 20, 0, 2, 15, 0, 0, 6, 13, 2, 0, 2, 13, 12, 0, 6, 9, 14, 0, 2, 9, 6, 0, 6, 9, 8, 0, 2, 9, 0, 2, 24, 4, 8, 2, 8, 4, 3, 13, 18, 4, 12, 13, 9, 4, 9, 7, 10, 4, 9, 7, 5, 4, 5, 8, 12, 3, 11, 8, 6, 3, 4, 14, 19, 3, 4, 15, 19, 1, 10, 0, 4, 20, 10, 10, 4, 10, 8, 15, 9, 6, 8, 17, 9, 2, 2, 9, 15, 4, 7, 9, 5, 4, 8, 4, 12, 7, 12, 4, 4, 7, 0, 10, 6, 9, 0, 13, 6, 3, 18, 5, 6, 9, 18, 8, 6, 3, 0, 18, 16, 6, 0, 18, 8, 3, 8, 21, 8, 3, 9, 18, 14, 6, 16, 18, 7, 3, 9, 21, 7, 3, 1, 20, 20, 4, 1, 20, 10, 2, 11, 22, 10, 2, 2, 8, 20, 6, 12, 8, 10, 3, 2, 11, 10, 3, 7, 8, 6, 9, 9, 8, 2, 9, 8, 5, 12, 8, 12, 5, 4, 8, 4, 5, 12, 8, 8, 5, 4, 8, 10, 6, 6, 9, 12, 6, 2, 9, 2, 0, 6, 16, 4, 0, 2, 16, 15, 4, 6, 12, 15, 8, 6, 4, 3, 4, 6, 12, 3, 8, 6, 4, 15, 12, 9, 6, 15, 14, 9, 2, 4, 0, 15, 22, 4, 11, 15, 11, 15, 12, 9, 6, 15, 14, 9, 2, 0, 12, 9, 6, 0, 14, 9, 2, 15, 15, 9, 6, 15, 17, 9, 2, 0, 15, 9, 6, 0, 17, 9, 2, 10, 0, 8, 10, 14, 0, 4, 5, 10, 5, 4, 5, 1, 0, 4, 16, 3, 0, 2, 16, 7, 6, 10, 6, 7, 8, 10, 2, 10, 12, 4, 10, 10, 17, 4, 5, 8, 4, 10, 6, 8, 6, 10, 2, 3, 22, 18, 2, 12, 22, 9, 2, 7, 7, 11, 6, 7, 9, 11, 2, 0, 0, 12, 10, 0, 0, 6, 5, 6, 5, 6, 5, 10, 1, 12, 6, 16, 1, 6, 3, 10, 4, 6, 3, 7, 16, 9, 4, 7, 18, 9, 2, 5, 7, 15, 16, 10, 7, 5, 16, 5, 10, 12, 13, 11, 10, 6, 13, 6, 2, 12, 6, 12, 2, 6, 3, 6, 5, 6, 3, 3, 9, 12, 9, 3, 12, 12, 3, 16, 2, 8, 6, 16, 5, 8, 3, 0, 2, 8, 6, 0, 5, 8, 3, 0, 3, 24, 11, 0, 3, 12, 11, 0, 13, 8, 10, 0, 13, 4, 5, 4, 18, 4, 5, 10, 14, 4, 10, 10, 19, 4, 5, 10, 2, 4, 21, 10, 9, 4, 7, 4, 4, 15, 9, 4, 7, 15, 3, 0, 1, 24, 6, 8, 1, 8, 6, 9, 6, 5, 16, 9, 14, 5, 8, 3, 21, 18, 3, 9, 21, 6, 3, 6, 5, 3, 12, 6, 11, 3, 6, 11, 6, 4, 9, 11, 6, 2, 9, 5, 6, 9, 8, 8, 6, 3, 8, 4, 3, 20, 2, 4, 4, 20, 1, 2, 10, 18, 3, 8, 10, 6, 3, 7, 15, 10, 6, 7, 17, 10, 2, 1, 4, 4, 18, 1, 4, 2, 9, 3, 13, 2, 9, 13, 0, 6, 9, 15, 0, 2, 9, 5, 0, 6, 9, 7, 0, 2, 9, 11, 0, 6, 9, 13, 0, 2, 9, 6, 7, 9, 6, 9, 7, 3, 6, 3, 0, 18, 2, 3, 1, 18, 1, 0, 10, 20, 4, 0, 10, 10, 2, 10, 12, 10, 2, 10, 2, 4, 12, 10, 8, 4, 6, 6, 5, 6, 12, 6, 5, 3, 6, 9, 11, 3, 6, 6, 0, 18, 22, 15, 0, 9, 11, 6, 11, 9, 11, 0, 0, 18, 22, 0, 0, 9, 11, 9, 11, 9, 11, 18, 2, 6, 11, 20, 2, 2, 11, 0, 2, 6, 11, 2, 2, 2, 11, 11, 0, 6, 9, 13, 0, 2, 9, 0, 0, 20, 3, 0, 1, 20, 1, 2, 2, 20, 2, 2, 3, 20, 1, 1, 10, 18, 2, 1, 11, 18, 1, 18, 7, 6, 9, 18, 10, 6, 3, 0, 0, 22, 9, 0, 3, 22, 3, 17, 3, 6, 9, 17, 6, 6, 3, 0, 7, 6, 9, 0, 10, 6, 3, 0, 6, 24, 6, 0, 8, 24, 2, 0, 2, 6, 10, 2, 2, 2, 10, 10, 6, 6, 9, 12, 6, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 15, 0, 6, 9, 17, 0, 2, 9, 3, 0, 6, 9, 5, 0, 2, 9, 15, 17, 9, 6, 15, 19, 9, 2, 0, 17, 18, 3, 0, 18, 18, 1, 15, 14, 9, 6, 15, 16, 9, 2, 0, 15, 23, 6, 0, 17, 23, 2, 5, 15, 18, 3, 5, 16, 18, 1, 0, 14, 9, 6, 0, 16, 9, 2, 9, 8, 8, 10, 13, 8, 4, 5, 9, 13, 4, 5, 3, 7, 15, 6, 8, 7, 5, 6, 9, 8, 8, 10, 13, 8, 4, 5, 9, 13, 4, 5, 5, 0, 6, 12, 8, 0, 3, 12, 9, 8, 8, 10, 13, 8, 4, 5, 9, 13, 4, 5, 8, 5, 6, 9, 10, 5, 2, 9, 10, 6, 4, 18, 12, 6, 2, 9, 10, 15, 2, 9, 5, 7, 12, 4, 11, 7, 6, 4, 9, 8, 8, 10, 13, 8, 4, 5, 9, 13, 4, 5, 7, 8, 8, 10, 7, 8, 4, 5, 11, 13, 4, 5, 11, 10, 6, 14, 14, 10, 3, 7, 11, 17, 3, 7, 9, 5, 6, 19, 12, 5, 3, 19, 6, 12, 12, 6, 12, 12, 6, 3, 6, 15, 6, 3, 1, 9, 18, 6, 1, 9, 9, 3, 10, 12, 9, 3, 16, 14, 8, 10, 20, 14, 4, 5, 16, 19, 4, 5, 0, 9, 22, 8, 0, 9, 11, 4, 11, 13, 11, 4, 8, 18, 12, 6, 14, 18, 6, 3, 8, 21, 6, 3, 0, 6, 20, 18, 0, 6, 10, 9, 10, 15, 10, 9, 3, 6, 20, 12, 13, 6, 10, 6, 3, 12, 10, 6, 0, 16, 10, 8, 0, 16, 5, 4, 5, 20, 5, 4, 6, 16, 18, 3, 6, 17, 18, 1, 0, 11, 19, 3, 0, 12, 19, 1, 14, 6, 6, 9, 14, 9, 6, 3, 1, 7, 22, 4, 1, 7, 11, 2, 12, 9, 11, 2, 13, 6, 7, 12, 13, 10, 7, 4, 4, 7, 11, 9, 4, 10, 11, 3, 12, 10, 10, 8, 17, 10, 5, 4, 12, 14, 5, 4, 2, 12, 9, 7, 5, 12, 3, 7, 16, 14, 6, 9, 16, 17, 6, 3, 3, 12, 6, 12, 3, 16, 6, 4, 14, 13, 6, 6, 14, 16, 6, 3, 8, 0, 6, 9, 10, 0, 2, 9, 9, 1, 6, 23, 11, 1, 2, 23, 0, 16, 9, 6, 0, 18, 9, 2, 4, 17, 18, 3, 4, 18, 18, 1, 5, 2, 13, 14, 5, 9, 13, 7, 15, 0, 8, 12, 19, 0, 4, 6, 15, 6, 4, 6, 0, 0, 8, 12, 0, 0, 4, 6, 4, 6, 4, 6, 8, 2, 8, 7, 8, 2, 4, 7, 1, 1, 6, 9, 3, 1, 2, 9, 14, 8, 6, 12, 17, 8, 3, 6, 14, 14, 3, 6, 4, 8, 6, 12, 4, 8, 3, 6, 7, 14, 3, 6, 16, 5, 5, 15, 16, 10, 5, 5, 3, 5, 5, 15, 3, 10, 5, 5, 18, 4, 6, 9, 18, 7, 6, 3, 1, 7, 6, 15, 1, 12, 6, 5, 11, 15, 12, 8, 17, 15, 6, 4, 11, 19, 6, 4, 0, 2, 24, 4, 0, 2, 12, 2, 12, 4, 12, 2, 15, 1, 2, 19, 15, 1, 1, 19, 7, 1, 2, 19, 8, 1, 1, 19, 22, 1, 2, 20, 22, 1, 1, 20, 0, 1, 2, 20, 1, 1, 1, 20, 18, 11, 6, 12, 20, 11, 2, 12, 0, 11, 6, 12, 2, 11, 2, 12, 3, 6, 18, 14, 3, 13, 18, 7, 6, 10, 7, 8, 6, 14, 7, 4, 7, 9, 12, 12, 7, 13, 12, 4, 2, 18, 18, 5, 11, 18, 9, 5, 4, 21, 20, 3, 4, 22, 20, 1, 9, 12, 6, 12, 9, 12, 3, 6, 12, 18, 3, 6, 4, 6, 18, 3, 4, 7, 18, 1, 3, 6, 18, 3, 3, 7, 18, 1, 18, 4, 6, 9, 18, 7, 6, 3, 2, 12, 9, 6, 2, 14, 9, 2, 4, 14, 18, 4, 13, 14, 9, 2, 4, 16, 9, 2, 7, 7, 6, 14, 7, 7, 3, 7, 10, 14, 3, 7, 7, 13, 12, 6, 13, 13, 6, 3, 7, 16, 6, 3, 6, 7, 12, 9, 10, 7, 4, 9, 12, 12, 6, 6, 12, 12, 3, 6, 0, 2, 4, 10, 0, 7, 4, 5, 8, 0, 9, 6, 11, 0, 3, 6, 2, 9, 12, 6, 2, 12, 12, 3, 13, 10, 6, 9, 13, 13, 6, 3, 5, 10, 6, 9, 5, 13, 6, 3, 9, 15, 9, 6, 9, 17, 9, 2, 5, 16, 12, 6, 5, 19, 12, 3, 3, 2, 20, 3, 3, 3, 20, 1, 2, 5, 12, 6, 6, 5, 4, 6, 11, 0, 3, 24, 12, 0, 1, 24, 3, 16, 15, 4, 8, 16, 5, 4, 9, 12, 6, 12, 9, 18, 6, 6, 1, 15, 12, 8, 1, 15, 6, 4, 7, 19, 6, 4, 15, 10, 8, 14, 19, 10, 4, 7, 15, 17, 4, 7, 1, 9, 8, 14, 1, 9, 4, 7, 5, 16, 4, 7, 9, 11, 9, 10, 9, 16, 9, 5, 6, 7, 12, 6, 6, 9, 12, 2, 10, 15, 6, 9, 12, 15, 2, 9, 7, 8, 9, 7, 10, 8, 3, 7, 10, 4, 8, 10, 14, 4, 4, 5, 10, 9, 4, 5, 4, 6, 6, 9, 4, 9, 6, 3, 0, 6, 24, 12, 8, 6, 8, 12, 3, 7, 6, 14, 6, 7, 3, 14, 19, 8, 5, 8, 19, 12, 5, 4, 0, 8, 5, 8, 0, 12, 5, 4, 17, 3, 6, 6, 17, 6, 6, 3, 1, 3, 6, 6, 1, 6, 6, 3, 18, 2, 6, 9, 18, 5, 6, 3, 0, 2, 6, 9, 0, 5, 6, 3, 3, 3, 18, 6, 3, 5, 18, 2, 2, 3, 9, 6, 2, 5, 9, 2, 9, 3, 10, 8, 14, 3, 5, 4, 9, 7, 5, 4, 5, 3, 10, 8, 5, 3, 5, 4, 10, 7, 5, 4, 10, 11, 6, 12, 10, 11, 3, 12, 8, 11, 6, 11, 11, 11, 3, 11, 7, 8, 10, 4, 7, 8, 5, 4, 9, 6, 6, 7, 12, 6, 3, 7, 5, 18, 18, 3, 5, 19, 18, 1, 8, 4, 6, 9, 10, 4, 2, 9, 8, 1, 9, 7, 11, 1, 3, 7, 6, 11, 6, 6, 9, 11, 3, 6, 14, 12, 4, 11, 14, 12, 2, 11, 6, 12, 4, 11, 8, 12, 2, 11, 8, 0, 12, 18, 12, 0, 4, 18, 2, 12, 10, 5, 7, 12, 5, 5, 2, 20, 22, 3, 2, 21, 22, 1, 0, 4, 2, 20, 1, 4, 1, 20, 0, 2, 24, 4, 8, 2, 8, 4, 7, 8, 10, 4, 7, 10, 10, 2, 6, 7, 8, 10, 6, 7, 4, 5, 10, 12, 4, 5, 14, 0, 6, 14, 17, 0, 3, 7, 14, 7, 3, 7, 4, 11, 5, 8, 4, 15, 5, 4, 2, 0, 20, 9, 2, 3, 20, 3, 6, 7, 12, 8, 6, 7, 6, 4, 12, 11, 6, 4, 9, 17, 6, 6, 9, 20, 6, 3, 7, 10, 10, 4, 7, 12, 10, 2, 6, 5, 12, 9, 10, 5, 4, 9, 5, 11, 6, 8, 8, 11, 3, 8, 18, 4, 4, 17, 18, 4, 2, 17, 0, 0, 6, 6, 3, 0, 3, 6, 18, 4, 4, 17, 18, 4, 2, 17, 2, 4, 4, 17, 4, 4, 2, 17, 5, 18, 19, 3, 5, 19, 19, 1, 11, 0, 2, 18, 11, 9, 2, 9, 15, 4, 2, 18, 15, 13, 2, 9, 7, 4, 2, 18, 7, 13, 2, 9, 7, 11, 10, 8, 12, 11, 5, 4, 7, 15, 5, 4, 10, 6, 4, 9, 12, 6, 2, 9, 10, 0, 6, 9, 12, 0, 2, 9, 2, 9, 16, 8, 2, 9, 8, 4, 10, 13, 8, 4, 14, 15, 6, 9, 14, 18, 6, 3, 8, 7, 6, 9, 10, 7, 2, 9, 14, 15, 6, 9, 14, 18, 6, 3, 3, 12, 12, 6, 3, 14, 12, 2, 14, 12, 9, 6, 14, 14, 9, 2, 1, 12, 9, 6, 1, 14, 9, 2, 3, 7, 18, 3, 3, 8, 18, 1, 1, 7, 22, 6, 1, 9, 22, 2, 18, 4, 6, 6, 18, 7, 6, 3, 0, 4, 6, 6, 0, 7, 6, 3, 5, 11, 16, 6, 5, 14, 16, 3, 6, 16, 9, 4, 6, 18, 9, 2, 14, 15, 6, 9, 14, 18, 6, 3, 4, 15, 6, 9, 4, 18, 6, 3, 15, 1, 6, 23, 17, 1, 2, 23, 0, 21, 24, 3, 8, 21, 8, 3, 0, 20, 24, 4, 8, 20, 8, 4, 3, 1, 6, 23, 5, 1, 2, 23, 3, 17, 18, 3, 3, 18, 18, 1, 0, 16, 18, 3, 0, 17, 18, 1, 1, 16, 22, 4, 12, 16, 11, 2, 1, 18, 11, 2, 0, 16, 9, 6, 0, 18, 9, 2, 2, 10, 21, 3, 9, 10, 7, 3, 2, 18, 12, 6, 2, 18, 6, 3, 8, 21, 6, 3, 0, 5, 24, 4, 0, 7, 24, 2, 10, 2, 4, 15, 10, 7, 4, 5, 10, 7, 6, 12, 10, 13, 6, 6, 6, 6, 6, 9, 8, 6, 2, 9, 11, 0, 6, 9, 13, 0, 2, 9, 9, 7, 6, 9, 11, 7, 2, 9, 2, 1, 20, 3, 2, 2, 20, 1, 1, 18, 12, 6, 1, 18, 6, 3, 7, 21, 6, 3, 13, 2, 4, 13, 13, 2, 2, 13, 6, 7, 12, 4, 12, 7, 6, 4, 10, 1, 4, 13, 10, 1, 2, 13, 6, 0, 3, 18, 7, 0, 1, 18, 14, 3, 10, 5, 14, 3, 5, 5, 6, 15, 12, 8, 10, 15, 4, 8, 9, 10, 6, 9, 11, 10, 2, 9, 8, 3, 4, 9, 10, 3, 2, 9, 17, 0, 6, 14, 20, 0, 3, 7, 17, 7, 3, 7, 1, 0, 6, 14, 1, 0, 3, 7, 4, 7, 3, 7, 14, 0, 6, 16, 17, 0, 3, 8, 14, 8, 3, 8, 7, 4, 4, 10, 9, 4, 2, 10, 3, 17, 18, 6, 12, 17, 9, 3, 3, 20, 9, 3, 1, 20, 22, 4, 12, 20, 11, 4, 14, 3, 10, 5, 14, 3, 5, 5, 0, 3, 10, 5, 5, 3, 5, 5, 12, 6, 12, 16, 16, 6, 4, 16, 0, 6, 12, 16, 4, 6, 4, 16, 10, 9, 5, 15, 10, 14, 5, 5, 1, 18, 21, 2, 1, 19, 21, 1, 15, 0, 9, 6, 15, 2, 9, 2, 6, 1, 12, 4, 12, 1, 6, 4, 6, 0, 12, 12, 12, 0, 6, 6, 6, 6, 6, 6, 8, 10, 8, 12, 8, 10, 4, 6, 12, 16, 4, 6, 14, 16, 10, 8, 19, 16, 5, 4, 14, 20, 5, 4, 0, 16, 10, 8, 0, 16, 5, 4, 5, 20, 5, 4, 10, 12, 12, 5, 14, 12, 4, 5, 6, 16, 10, 8, 6, 16, 5, 4, 11, 20, 5, 4, 7, 6, 12, 6, 13, 6, 6, 3, 7, 9, 6, 3, 9, 6, 4, 18, 9, 6, 2, 9, 11, 15, 2, 9, 10, 9, 6, 14, 13, 9, 3, 7, 10, 16, 3, 7, 8, 9, 6, 14, 8, 9, 3, 7, 11, 16, 3, 7, 7, 4, 11, 12, 7, 10, 11, 6, 4, 8, 6, 16, 4, 8, 3, 8, 7, 16, 3, 8, 17, 3, 4, 21, 17, 10, 4, 7, 3, 3, 4, 21, 3, 10, 4, 7, 10, 1, 8, 18, 14, 1, 4, 9, 10, 10, 4, 9, 2, 5, 16, 8, 2, 5, 8, 4, 10, 9, 8, 4, 3, 6, 18, 12, 3, 10, 18, 4, 4, 10, 16, 12, 4, 14, 16, 4, 15, 4, 8, 20, 19, 4, 4, 10, 15, 14, 4, 10, 7, 2, 9, 6, 10, 2, 3, 6, 15, 4, 8, 20, 19, 4, 4, 10, 15, 14, 4, 10, 1, 4, 8, 20, 1, 4, 4, 10, 5, 14, 4, 10, 11, 8, 8, 14, 15, 8, 4, 7, 11, 15, 4, 7, 5, 8, 8, 14, 5, 8, 4, 7, 9, 15, 4, 7, 10, 13, 5, 8, 10, 17, 5, 4, 4, 13, 7, 9, 4, 16, 7, 3, 0, 13, 24, 10, 0, 18, 24, 5, 4, 2, 8, 11, 8, 2, 4, 11, 10, 2, 8, 16, 14, 2, 4, 8, 10, 10, 4, 8, 0, 2, 24, 6, 0, 2, 12, 3, 12, 5, 12, 3, 6, 0, 12, 9, 6, 3, 12, 3, 1, 2, 12, 12, 1, 2, 6, 6, 7, 8, 6, 6, 18, 5, 6, 9, 18, 8, 6, 3, 4, 3, 8, 10, 4, 3, 4, 5, 8, 8, 4, 5, 6, 21, 18, 3, 6, 22, 18, 1, 1, 10, 18, 2, 1, 11, 18, 1, 1, 10, 22, 3, 1, 11, 22, 1, 2, 8, 12, 9, 2, 11, 12, 3, 12, 8, 12, 6, 18, 8, 6, 3, 12, 11, 6, 3, 0, 8, 12, 6, 0, 8, 6, 3, 6, 11, 6, 3, 10, 15, 6, 9, 12, 15, 2, 9, 7, 13, 9, 6, 7, 15, 9, 2, 9, 8, 7, 12, 9, 14, 7, 6, 4, 13, 9, 6, 7, 13, 3, 6, 6, 15, 18, 4, 12, 15, 6, 4, 5, 4, 4, 16, 7, 4, 2, 16, 10, 15, 6, 9, 12, 15, 2, 9, 8, 15, 6, 9, 10, 15, 2, 9, 9, 11, 12, 10, 15, 11, 6, 5, 9, 16, 6, 5, 3, 6, 14, 6, 3, 8, 14, 2, 4, 2, 17, 8, 4, 6, 17, 4, 6, 2, 12, 21, 6, 9, 12, 7, 8, 1, 9, 9, 8, 4, 9, 3, 0, 7, 24, 3, 12, 7, 12, 3, 11, 6, 9, 10, 11, 11, 9, 5, 2, 11, 18, 3, 2, 12, 18, 1, 8, 16, 9, 4, 8, 18, 9, 2, 0, 0, 9, 6, 0, 2, 9, 2, 0, 11, 24, 6, 0, 13, 24, 2, 2, 9, 20, 6, 2, 12, 20, 3, 4, 5, 16, 12, 12, 5, 8, 6, 4, 11, 8, 6, 10, 2, 4, 15, 10, 7, 4, 5, 7, 3, 10, 4, 7, 5, 10, 2, 9, 15, 6, 8, 9, 19, 6, 4, 17, 0, 7, 10, 17, 5, 7, 5, 0, 0, 7, 10, 0, 5, 7, 5, 16, 1, 6, 12, 19, 1, 3, 6, 16, 7, 3, 6, 1, 0, 19, 8, 1, 4, 19, 4, 12, 2, 9, 4, 12, 4, 9, 2, 3, 2, 9, 4, 3, 4, 9, 2, 12, 2, 10, 6, 12, 4, 10, 2, 3, 4, 18, 2, 12, 4, 9, 2, 12, 1, 4, 9, 12, 1, 2, 9, 8, 1, 4, 9, 10, 1, 2, 9, 10, 5, 8, 10, 14, 5, 4, 5, 10, 10, 4, 5, 6, 4, 12, 13, 10, 4, 4, 13, 13, 5, 6, 6, 13, 5, 3, 6, 1, 5, 12, 3, 7, 5, 6, 3, 7, 5, 10, 6, 7, 7, 10, 2, 2, 0, 21, 5, 9, 0, 7, 5, 0, 8, 9, 9, 0, 11, 9, 3, 9, 6, 6, 9, 11, 6, 2, 9, 0, 3, 6, 7, 3, 3, 3, 7, 9, 18, 12, 6, 15, 18, 6, 3, 9, 21, 6, 3, 2, 8, 20, 6, 2, 8, 10, 3, 12, 11, 10, 3, 13, 2, 10, 4, 13, 4, 10, 2, 4, 5, 5, 18, 4, 11, 5, 6, 20, 4, 4, 9, 20, 4, 2, 9, 8, 6, 8, 14, 8, 13, 8, 7, 0, 1, 24, 6, 12, 1, 12, 3, 0, 4, 12, 3, 0, 4, 4, 9, 2, 4, 2, 9, 3, 6, 18, 3, 3, 7, 18, 1, 3, 17, 16, 6, 3, 19, 16, 2, 13, 6, 6, 9, 13, 9, 6, 3, 5, 6, 14, 6, 5, 6, 7, 3, 12, 9, 7, 3, 13, 5, 8, 10, 17, 5, 4, 5, 13, 10, 4, 5, 2, 2, 20, 3, 2, 3, 20, 1, 9, 2, 9, 6, 12, 2, 3, 6, 8, 6, 6, 9, 10, 6, 2, 9, 12, 3, 4, 11, 12, 3, 2, 11, 8, 3, 4, 11, 10, 3, 2, 11, 8, 3, 8, 10, 12, 3, 4, 5, 8, 8, 4, 5, 11, 1, 2, 18, 12, 1, 1, 18, 9, 2, 9, 6, 12, 2, 3, 6, 0, 2, 19, 3, 0, 3, 19, 1, 9, 14, 9, 6, 9, 16, 9, 2, 1, 8, 18, 5, 7, 8, 6, 5, 12, 0, 6, 9, 14, 0, 2, 9, 6, 0, 6, 9, 8, 0, 2, 9, 13, 6, 4, 15, 13, 11, 4, 5, 1, 5, 18, 3, 1, 6, 18, 1, 9, 7, 14, 6, 9, 9, 14, 2, 2, 16, 18, 3, 2, 17, 18, 1, 15, 17, 9, 6, 15, 19, 9, 2, 0, 8, 12, 6, 0, 8, 6, 3, 6, 11, 6, 3, 9, 13, 7, 8, 9, 17, 7, 4, 2, 17, 20, 3, 2, 18, 20, 1, 15, 17, 9, 6, 15, 19, 9, 2, 4, 0, 15, 4, 4, 2, 15, 2, 17, 2, 6, 6, 17, 5, 6, 3, 0, 3, 6, 9, 0, 6, 6, 3, 15, 17, 9, 6, 15, 19, 9, 2, 0, 17, 9, 6, 0, 19, 9, 2, 9, 18, 12, 6, 15, 18, 6, 3, 9, 21, 6, 3, 3, 15, 6, 9, 3, 18, 6, 3, 16, 13, 8, 10, 20, 13, 4, 5, 16, 18, 4, 5, 0, 14, 24, 4, 8, 14, 8, 4, 13, 18, 6, 6, 13, 18, 3, 6, 0, 13, 8, 10, 0, 13, 4, 5, 4, 18, 4, 5, 0, 14, 24, 6, 0, 17, 24, 3, 5, 2, 12, 8, 5, 2, 6, 4, 11, 6, 6, 4, 8, 9, 9, 6, 11, 9, 3, 6, 4, 3, 16, 4, 4, 5, 16, 2, 10, 2, 4, 10, 10, 7, 4, 5, 8, 4, 5, 8, 8, 8, 5, 4, 11, 5, 9, 12, 11, 9, 9, 4, 4, 5, 9, 12, 4, 9, 9, 4, 14, 6, 6, 9, 14, 9, 6, 3, 2, 4, 20, 12, 2, 8, 20, 4, 4, 4, 17, 16, 4, 12, 17, 8, 8, 7, 7, 6, 8, 10, 7, 3, 1, 9, 23, 2, 1, 10, 23, 1, 7, 0, 6, 9, 9, 0, 2, 9, 13, 3, 4, 9, 13, 3, 2, 9, 8, 1, 6, 13, 10, 1, 2, 13, 4, 22, 18, 2, 4, 23, 18, 1, 3, 10, 9, 6, 6, 10, 3, 6, 14, 0, 2, 24, 14, 0, 1, 24, 8, 0, 2, 24, 9, 0, 1, 24, 3, 2, 18, 10, 9, 2, 6, 10, 4, 13, 15, 6, 9, 13, 5, 6, 3, 21, 18, 3, 9, 21, 6, 3, 9, 1, 4, 11, 11, 1, 2, 11, 9, 7, 10, 4, 9, 7, 5, 4, 7, 0, 10, 18, 12, 0, 5, 18, 12, 1, 6, 16, 14, 1, 2, 16, 6, 1, 6, 16, 8, 1, 2, 16, 18, 2, 6, 6, 18, 5, 6, 3, 3, 5, 18, 2, 3, 6, 18, 1, 18, 2, 6, 6, 18, 5, 6, 3, 0, 2, 6, 6, 0, 5, 6, 3, 13, 11, 11, 6, 13, 13, 11, 2, 5, 7, 10, 4, 10, 7, 5, 4, 11, 9, 10, 7, 11, 9, 5, 7, 3, 9, 10, 7, 8, 9, 5, 7, 16, 4, 6, 6, 16, 4, 3, 6, 5, 6, 10, 8, 5, 6, 5, 4, 10, 10, 5, 4, 7, 21, 16, 3, 7, 21, 8, 3, 1, 21, 16, 3, 9, 21, 8, 3, 2, 5, 22, 14, 13, 5, 11, 7, 2, 12, 11, 7, 3, 10, 8, 10, 3, 10, 4, 5, 7, 15, 4, 5, 17, 0, 6, 12, 20, 0, 3, 6, 17, 6, 3, 6, 5, 2, 6, 18, 7, 2, 2, 18, 13, 0, 6, 9, 15, 0, 2, 9, 0, 12, 7, 9, 0, 15, 7, 3, 15, 13, 8, 10, 19, 13, 4, 5, 15, 18, 4, 5, 1, 0, 6, 12, 1, 0, 3, 6, 4, 6, 3, 6, 12, 1, 3, 12, 12, 7, 3, 6, 1, 13, 8, 10, 1, 13, 4, 5, 5, 18, 4, 5, 3, 21, 19, 2, 3, 22, 19, 1, 6, 3, 4, 13, 8, 3, 2, 13, 5, 10, 18, 3, 5, 11, 18, 1, 9, 3, 5, 12, 9, 7, 5, 4, 11, 2, 4, 15, 11, 7, 4, 5, 4, 1, 16, 4, 4, 3, 16, 2, 6, 0, 18, 3, 6, 1, 18, 1, 5, 1, 10, 8, 5, 1, 5, 4, 10, 5, 5, 4, 11, 18, 12, 6, 17, 18, 6, 3, 11, 21, 6, 3, 5, 15, 12, 3, 11, 15, 6, 3, 1, 10, 22, 4, 1, 10, 11, 4, 7, 9, 9, 6, 10, 9, 3, 6, 6, 11, 12, 5, 10, 11, 4, 5, 6, 7, 10, 7, 11, 7, 5, 7, 11, 2, 8, 10, 11, 2, 4, 10, 5, 2, 8, 10, 9, 2, 4, 10, 6, 4, 18, 6, 15, 4, 9, 3, 6, 7, 9, 3, 0, 5, 10, 9, 0, 8, 10, 3, 2, 7, 21, 6, 2, 9, 21, 2, 0, 4, 22, 16, 0, 4, 11, 8, 11, 12, 11, 8, 9, 0, 6, 22, 9, 11, 6, 11, 9, 1, 3, 12, 9, 7, 3, 6, 12, 0, 12, 18, 18, 0, 6, 9, 12, 9, 6, 9, 0, 0, 12, 18, 0, 0, 6, 9, 6, 9, 6, 9, 1, 1, 22, 4, 12, 1, 11, 2, 1, 3, 11, 2, 3, 0, 18, 4, 3, 2, 18, 2, 2, 5, 22, 6, 2, 7, 22, 2, 5, 0, 6, 9, 5, 3, 6, 3, 10, 14, 6, 9, 12, 14, 2, 9, 8, 14, 6, 9, 10, 14, 2, 9, 5, 18, 18, 3, 5, 19, 18, 1, 6, 0, 6, 13, 9, 0, 3, 13, 7, 4, 12, 4, 7, 4, 6, 4, 5, 2, 12, 6, 9, 2, 4, 6, 4, 1, 18, 3, 4, 2, 18, 1, 0, 8, 6, 12, 0, 12, 6, 4, 9, 15, 6, 9, 11, 15, 2, 9, 9, 10, 6, 13, 11, 10, 2, 13, 6, 17, 18, 2, 6, 18, 18, 1, 9, 4, 6, 9, 11, 4, 2, 9, 10, 0, 6, 9, 12, 0, 2, 9, 5, 6, 10, 8, 5, 6, 5, 4, 10, 10, 5, 4, 14, 9, 5, 8, 14, 13, 5, 4, 5, 9, 5, 8, 5, 13, 5, 4, 14, 11, 9, 6, 14, 13, 9, 2, 0, 2, 23, 15, 0, 7, 23, 5, 16, 0, 8, 12, 16, 6, 8, 6, 4, 15, 6, 9, 4, 18, 6, 3, 8, 18, 9, 4, 8, 20, 9, 2, 0, 17, 18, 3, 0, 18, 18, 1, 13, 11, 11, 6, 13, 13, 11, 2, 0, 11, 11, 6, 0, 13, 11, 2, 0, 9, 24, 6, 12, 9, 12, 3, 0, 12, 12, 3, 6, 16, 8, 8, 6, 20, 8, 4, 10, 16, 14, 6, 10, 18, 14, 2, 1, 1, 21, 3, 1, 2, 21, 1, 0, 2, 24, 3, 0, 2, 12, 3, 2, 15, 8, 5, 6, 15, 4, 5, 2, 11, 21, 3, 9, 11, 7, 3, 1, 18, 12, 6, 1, 18, 6, 3, 7, 21, 6, 3, 10, 14, 4, 10, 10, 19, 4, 5, 7, 7, 4, 10, 7, 12, 4, 5, 9, 8, 6, 12, 9, 12, 6, 4, 7, 1, 9, 6, 10, 1, 3, 6, 3, 14, 19, 2, 3, 15, 19, 1, 7, 7, 10, 10, 7, 7, 5, 5, 12, 12, 5, 5, 3, 12, 18, 12, 3, 12, 9, 12, 8, 0, 6, 12, 10, 0, 2, 12, 3, 0, 17, 9, 3, 3, 17, 3, 6, 0, 12, 11, 10, 0, 4, 11, 1, 0, 6, 13, 4, 0, 3, 13, 5, 8, 16, 6, 5, 11, 16, 3, 8, 8, 5, 12, 8, 14, 5, 6, 3, 21, 18, 3, 9, 21, 6, 3, 0, 0, 6, 6, 3, 0, 3, 6, 2, 0, 20, 3, 2, 1, 20, 1, 4, 6, 15, 10, 9, 6, 5, 10, 9, 6, 6, 9, 11, 6, 2, 9, 9, 0, 6, 9, 11, 0, 2, 9, 14, 0, 6, 9, 16, 0, 2, 9, 7, 16, 9, 6, 7, 18, 9, 2, 14, 0, 6, 9, 16, 0, 2, 9, 4, 0, 6, 9, 6, 0, 2, 9, 17, 1, 6, 16, 19, 1, 2, 16, 1, 1, 6, 16, 3, 1, 2, 16, 14, 13, 6, 9, 14, 16, 6, 3, 0, 0, 6, 9, 0, 3, 6, 3, 9, 5, 6, 6, 9, 5, 3, 6, 3, 10, 9, 6, 6, 10, 3, 6, 14, 7, 3, 16, 14, 15, 3, 8, 4, 10, 14, 12, 4, 10, 7, 6, 11, 16, 7, 6, 7, 6, 12, 6, 7, 8, 12, 2, 7, 2, 4, 20, 9, 2, 2, 20, 14, 13, 6, 9, 14, 16, 6, 3, 10, 6, 4, 9, 12, 6, 2, 9, 14, 13, 6, 9, 14, 16, 6, 3, 5, 20, 14, 4, 5, 22, 14, 2, 4, 4, 16, 12, 4, 10, 16, 6, 9, 6, 6, 9, 11, 6, 2, 9, 3, 0, 21, 4, 3, 2, 21, 2, 4, 13, 6, 9, 4, 16, 6, 3, 16, 16, 5, 8, 16, 20, 5, 4, 4, 0, 16, 16, 4, 0, 8, 8, 12, 8, 8, 8, 6, 6, 14, 6, 13, 6, 7, 3, 6, 9, 7, 3, 10, 5, 4, 15, 10, 10, 4, 5, 9, 15, 12, 8, 15, 15, 6, 4, 9, 19, 6, 4, 6, 7, 12, 4, 12, 7, 6, 4, 5, 6, 14, 6, 12, 6, 7, 3, 5, 9, 7, 3, 3, 6, 18, 10, 3, 6, 9, 5, 12, 11, 9, 5, 6, 0, 18, 21, 12, 0, 6, 21, 0, 0, 24, 21, 8, 0, 8, 21, 6, 18, 18, 3, 6, 19, 18, 1, 0, 15, 9, 6, 0, 17, 9, 2, 4, 3, 19, 2, 4, 4, 19, 1, 0, 3, 24, 2, 0, 4, 24, 1, 15, 14, 9, 4, 15, 16, 9, 2, 0, 14, 9, 4, 0, 16, 9, 2, 6, 15, 18, 2, 6, 16, 18, 1, 3, 17, 18, 3, 3, 18, 18, 1, 12, 0, 3, 23, 13, 0, 1, 23, 6, 0, 8, 6, 6, 3, 8, 3, 6, 16, 18, 3, 6, 17, 18, 1, 9, 0, 3, 23, 10, 0, 1, 23, 10, 7, 4, 10, 10, 12, 4, 5, 7, 8, 10, 12, 7, 12, 10, 4, 14, 9, 6, 14, 17, 9, 3, 7, 14, 16, 3, 7, 2, 0, 10, 9, 2, 3, 10, 3, 11, 1, 5, 12, 11, 7, 5, 6, 1, 4, 12, 10, 1, 4, 6, 5, 7, 9, 6, 5, 15, 1, 9, 4, 15, 3, 9, 2, 1, 2, 8, 10, 1, 2, 4, 5, 5, 7, 4, 5, 10, 1, 5, 12, 10, 5, 5, 4, 4, 0, 14, 24, 11, 0, 7, 24, 7, 17, 10, 4, 7, 19, 10, 2, 10, 14, 4, 10, 10, 19, 4, 5, 13, 15, 6, 9, 15, 15, 2, 9, 3, 21, 18, 3, 3, 22, 18, 1, 13, 15, 6, 9, 15, 15, 2, 9, 5, 15, 6, 9, 7, 15, 2, 9, 10, 6, 4, 18, 12, 6, 2, 9, 10, 15, 2, 9, 7, 3, 6, 11, 9, 3, 2, 11, 15, 1, 9, 4, 15, 3, 9, 2, 5, 4, 14, 8, 5, 8, 14, 4, 8, 1, 15, 9, 8, 4, 15, 3, 7, 2, 8, 10, 7, 2, 4, 5, 11, 7, 4, 5, 12, 2, 6, 12, 12, 2, 3, 12, 6, 2, 6, 12, 9, 2, 3, 12, 7, 7, 12, 4, 7, 7, 6, 4, 6, 3, 12, 10, 10, 3, 4, 10, 5, 6, 16, 6, 13, 6, 8, 3, 5, 9, 8, 3, 3, 1, 18, 9, 9, 1, 6, 9, 3, 8, 18, 5, 9, 8, 6, 5, 0, 0, 24, 22, 0, 0, 12, 11, 12, 11, 12, 11, 14, 16, 9, 6, 14, 18, 9, 2, 0, 16, 24, 8, 0, 20, 24, 4, 1, 19, 22, 4, 12, 19, 11, 2, 1, 21, 11, 2, 1, 16, 9, 6, 1, 18, 9, 2, 7, 8, 10, 4, 7, 8, 5, 4, 9, 15, 6, 9, 11, 15, 2, 9, 10, 18, 12, 6, 16, 18, 6, 3, 10, 21, 6, 3, 2, 18, 12, 6, 2, 18, 6, 3, 8, 21, 6, 3, 8, 3, 16, 9, 8, 6, 16, 3, 0, 5, 10, 6, 0, 7, 10, 2, 5, 5, 18, 3, 5, 6, 18, 1, 2, 6, 9, 6, 2, 9, 9, 3, 14, 2, 10, 9, 14, 5, 10, 3, 3, 6, 18, 3, 3, 7, 18, 1, 9, 2, 15, 6, 9, 4, 15, 2, 4, 8, 15, 6, 4, 10, 15, 2, 0, 5, 24, 4, 12, 5, 12, 2, 0, 7, 12, 2, 7, 8, 6, 12, 9, 8, 2, 12, 11, 0, 6, 9, 13, 0, 2, 9, 0, 12, 6, 12, 0, 12, 3, 6, 3, 18, 3, 6, 14, 12, 10, 6, 14, 14, 10, 2, 2, 7, 18, 9, 2, 10, 18, 3, 11, 14, 10, 9, 11, 17, 10, 3, 7, 6, 10, 8, 7, 6, 5, 4, 12, 10, 5, 4, 6, 6, 14, 6, 13, 6, 7, 3, 6, 9, 7, 3, 4, 13, 9, 7, 7, 13, 3, 7, 14, 10, 6, 12, 17, 10, 3, 6, 14, 16, 3, 6, 4, 10, 6, 12, 4, 10, 3, 6, 7, 16, 3, 6, 13, 9, 8, 6, 13, 9, 4, 6, 8, 3, 4, 14, 10, 3, 2, 14, 17, 0, 3, 18, 18, 0, 1, 18, 4, 12, 16, 12, 12, 12, 8, 12, 15, 0, 6, 14, 17, 0, 2, 14, 3, 0, 6, 14, 5, 0, 2, 14, 12, 2, 12, 20, 16, 2, 4, 20, 0, 2, 12, 20, 4, 2, 4, 20, 16, 0, 6, 17, 18, 0, 2, 17, 2, 0, 6, 17, 4, 0, 2, 17, 15, 6, 9, 6, 15, 8, 9, 2, 0, 6, 9, 6, 0, 8, 9, 2, 18, 1, 6, 13, 20, 1, 2, 13, 0, 1, 6, 13, 2, 1, 2, 13, 16, 0, 4, 9, 16, 0, 2, 9, 5, 10, 12, 7, 9, 10, 4, 7, 12, 9, 12, 6, 12, 11, 12, 2, 0, 9, 12, 6, 0, 11, 12, 2, 5, 7, 14, 9, 5, 10, 14, 3, 0, 15, 20, 3, 0, 16, 20, 1, 8, 10, 8, 10, 12, 10, 4, 5, 8, 15, 4, 5, 5, 4, 13, 9, 5, 7, 13, 3, 10, 2, 6, 18, 10, 8, 6, 6, 6, 0, 6, 9, 8, 0, 2, 9, 6, 9, 12, 4, 6, 11, 12, 2, 3, 2, 15, 12, 3, 6, 15, 4, 12, 0, 12, 5, 16, 0, 4, 5, 0, 15, 18, 3, 6, 15, 6, 3, 0, 14, 24, 5, 8, 14, 8, 5, 5, 1, 3, 18, 6, 1, 1, 18, 10, 0, 4, 14, 10, 0, 2, 14, 9, 3, 4, 9, 11, 3, 2, 9, 8, 2, 12, 6, 14, 2, 6, 3, 8, 5, 6, 3, 0, 4, 17, 4, 0, 6, 17, 2, 16, 16, 5, 8, 16, 20, 5, 4, 3, 16, 5, 8, 3, 20, 5, 4, 6, 18, 18, 2, 6, 19, 18, 1, 0, 0, 12, 5, 4, 0, 4, 5, 14, 3, 6, 12, 17, 3, 3, 6, 14, 9, 3, 6, 0, 12, 6, 12, 2, 12, 2, 12, 2, 3, 21, 3, 2, 4, 21, 1, 4, 3, 6, 12, 4, 3, 3, 6, 7, 9, 3, 6, 12, 8, 12, 6, 18, 8, 6, 3, 12, 11, 6, 3, 0, 15, 16, 9, 8, 15, 8, 9, 6, 13, 18, 5, 6, 13, 9, 5, 1, 6, 15, 6, 6, 6, 5, 6, 11, 9, 9, 6, 14, 9, 3, 6, 3, 0, 15, 11, 8, 0, 5, 11, 15, 3, 3, 18, 15, 9, 3, 6, 6, 3, 3, 18, 6, 9, 3, 6, 9, 5, 10, 8, 14, 5, 5, 4, 9, 9, 5, 4, 4, 4, 16, 8, 4, 4, 8, 4, 12, 8, 8, 4, 7, 7, 12, 3, 7, 7, 6, 3, 5, 0, 9, 13, 8, 0, 3, 13, 11, 0, 6, 9, 13, 0, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 8, 1, 10, 9, 8, 4, 10, 3, 0, 2, 18, 2, 0, 3, 18, 1, 10, 13, 14, 6, 17, 13, 7, 3, 10, 16, 7, 3, 0, 13, 14, 6, 0, 13, 7, 3, 7, 16, 7, 3, 20, 2, 3, 21, 21, 2, 1, 21, 0, 9, 5, 12, 0, 13, 5, 4, 12, 6, 12, 6, 12, 8, 12, 2, 1, 8, 20, 3, 1, 9, 20, 1, 5, 7, 19, 3, 5, 8, 19, 1, 1, 12, 9, 6, 1, 14, 9, 2, 6, 10, 14, 12, 6, 14, 14, 4, 5, 6, 14, 18, 5, 12, 14, 6, 11, 12, 9, 7, 14, 12, 3, 7, 1, 15, 18, 4, 1, 17, 18, 2, 11, 14, 6, 9, 11, 17, 6, 3, 0, 8, 18, 4, 0, 8, 9, 2, 9, 10, 9, 2, 3, 10, 20, 6, 13, 10, 10, 3, 3, 13, 10, 3, 1, 10, 20, 6, 1, 10, 10, 3, 11, 13, 10, 3, 0, 9, 24, 2, 0, 9, 12, 2, 1, 12, 20, 8, 1, 12, 10, 4, 11, 16, 10, 4, 11, 12, 9, 7, 14, 12, 3, 7, 4, 12, 9, 7, 7, 12, 3, 7, 12, 12, 8, 5, 12, 12, 4, 5, 4, 12, 8, 5, 8, 12, 4, 5, 13, 10, 4, 10, 13, 10, 2, 10, 1, 15, 20, 2, 11, 15, 10, 2, 9, 10, 6, 6, 9, 10, 3, 6, 0, 1, 21, 3, 7, 1, 7, 3, 6, 4, 13, 9, 6, 7, 13, 3, 6, 5, 12, 5, 10, 5, 4, 5, 10, 10, 10, 6, 10, 12, 10, 2, 6, 12, 5, 8, 6, 16, 5, 4, 13, 0, 6, 9, 15, 0, 2, 9, 2, 10, 18, 6, 8, 10, 6, 6, 11, 2, 9, 4, 11, 4, 9, 2, 1, 20, 21, 3, 8, 20, 7, 3, 1, 10, 22, 2, 1, 11, 22, 1, 0, 17, 18, 3, 0, 18, 18, 1, 13, 0, 6, 9, 15, 0, 2, 9, 5, 0, 6, 9, 7, 0, 2, 9, 18, 2, 6, 20, 20, 2, 2, 20, 0, 2, 6, 20, 2, 2, 2, 20, 11, 7, 6, 14, 14, 7, 3, 7, 11, 14, 3, 7, 0, 1, 4, 9, 2, 1, 2, 9, 12, 14, 9, 4, 12, 16, 9, 2, 1, 13, 9, 4, 1, 15, 9, 2, 7, 6, 15, 6, 7, 8, 15, 2, 8, 2, 3, 18, 8, 8, 3, 6, 6, 6, 12, 6, 12, 6, 6, 3, 6, 9, 6, 3, 2, 19, 20, 4, 2, 19, 10, 2, 12, 21, 10, 2, 14, 15, 6, 9, 14, 18, 6, 3, 3, 5, 18, 14, 3, 5, 9, 7, 12, 12, 9, 7, 15, 6, 4, 18, 17, 6, 2, 9, 15, 15, 2, 9, 5, 6, 4, 18, 5, 6, 2, 9, 7, 15, 2, 9, 11, 0, 6, 9, 13, 0, 2, 9, 7, 0, 6, 9, 9, 0, 2, 9, 11, 5, 6, 9, 13, 5, 2, 9, 9, 5, 6, 6, 12, 5, 3, 6, 4, 1, 16, 6, 12, 1, 8, 3, 4, 4, 8, 3, 9, 13, 6, 11, 11, 13, 2, 11, 17, 1, 6, 12, 20, 1, 3, 6, 17, 7, 3, 6, 1, 17, 18, 3, 1, 18, 18, 1, 7, 13, 10, 8, 7, 17, 10, 4, 6, 18, 10, 6, 6, 20, 10, 2, 9, 14, 9, 4, 9, 16, 9, 2, 1, 1, 6, 12, 1, 1, 3, 6, 4, 7, 3, 6, 19, 4, 5, 12, 19, 8, 5, 4, 0, 0, 8, 8, 4, 0, 4, 8, 3, 5, 19, 3, 3, 6, 19, 1, 1, 5, 12, 6, 1, 5, 6, 3, 7, 8, 6, 3, 2, 1, 21, 8, 9, 1, 7, 8, 4, 1, 16, 8, 4, 5, 16, 4, 6, 0, 18, 3, 6, 1, 18, 1, 4, 4, 10, 14, 4, 11, 10, 7, 15, 6, 4, 10, 15, 11, 4, 5, 3, 18, 18, 3, 9, 18, 6, 3, 8, 18, 12, 6, 12, 18, 4, 6, 3, 15, 6, 9, 6, 15, 3, 9, 15, 7, 6, 8, 15, 11, 6, 4, 3, 7, 6, 8, 3, 11, 6, 4, 5, 9, 18, 6, 14, 9, 9, 3, 5, 12, 9, 3, 1, 13, 12, 6, 1, 15, 12, 2, 14, 15, 10, 6, 14, 17, 10, 2, 0, 15, 10, 6, 0, 17, 10, 2, 15, 13, 6, 9, 15, 16, 6, 3, 3, 13, 6, 9, 3, 16, 6, 3, 9, 5, 8, 8, 9, 5, 4, 8, 1, 18, 12, 6, 1, 18, 6, 3, 7, 21, 6, 3, 13, 19, 10, 4, 13, 21, 10, 2, 1, 19, 10, 4, 1, 21, 10, 2, 6, 19, 18, 3, 6, 20, 18, 1, 8, 14, 4, 10, 8, 19, 4, 5, 0, 0, 24, 6, 0, 2, 24, 2, 0, 1, 6, 9, 0, 4, 6, 3, 4, 9, 20, 6, 14, 9, 10, 3, 4, 12, 10, 3, 1, 15, 19, 8, 1, 19, 19, 4, 14, 0, 10, 6, 14, 2, 10, 2, 1, 10, 21, 14, 8, 10, 7, 14, 10, 10, 8, 8, 10, 10, 4, 8, 6, 8, 10, 4, 11, 8, 5, 4, 10, 5, 4, 9, 10, 5, 2, 9, 7, 5, 6, 10, 9, 5, 2, 10, 14, 4, 4, 13, 14, 4, 2, 13, 6, 4, 4, 13, 8, 4, 2, 13, 8, 7, 9, 6, 11, 7, 3, 6, 3, 6, 16, 6, 3, 6, 8, 3, 11, 9, 8, 3, 5, 4, 16, 14, 13, 4, 8, 7, 5, 11, 8, 7, 0, 0, 24, 4, 0, 0, 12, 2, 12, 2, 12, 2, 9, 1, 9, 6, 12, 1, 3, 6, 4, 1, 14, 4, 11, 1, 7, 4, 10, 14, 7, 9, 10, 17, 7, 3, 8, 3, 8, 10, 8, 3, 4, 5, 12, 8, 4, 5, 7, 3, 12, 5, 11, 3, 4, 5, 8, 2, 4, 13, 10, 2, 2, 13, 11, 2, 3, 19, 12, 2, 1, 19, 7, 7, 9, 6, 10, 7, 3, 6, 4, 22, 20, 2, 4, 22, 10, 2, 0, 16, 24, 4, 0, 16, 12, 2, 12, 18, 12, 2, 7, 3, 12, 5, 11, 3, 4, 5, 1, 10, 8, 14, 1, 10, 4, 7, 5, 17, 4, 7, 11, 16, 6, 6, 11, 19, 6, 3, 6, 0, 10, 24, 6, 0, 5, 12, 11, 12, 5, 12, 7, 5, 14, 14, 14, 5, 7, 7, 7, 12, 7, 7, 7, 8, 10, 8, 7, 8, 5, 4, 12, 12, 5, 4, 9, 1, 9, 6, 12, 1, 3, 6, 0, 6, 24, 3, 12, 6, 12, 3, 7, 3, 12, 5, 11, 3, 4, 5, 1, 13, 22, 4, 1, 13, 11, 2, 12, 15, 11, 2, 9, 12, 12, 6, 9, 14, 12, 2, 0, 5, 9, 6, 0, 7, 9, 2, 1, 5, 23, 6, 1, 7, 23, 2, 1, 6, 19, 12, 1, 10, 19, 4, 9, 1, 6, 21, 9, 8, 6, 7, 3, 19, 18, 3, 9, 19, 6, 3, 9, 14, 6, 9, 11, 14, 2, 9, 9, 6, 4, 12, 11, 6, 2, 12, 16, 0, 6, 9, 18, 0, 2, 9, 2, 0, 6, 9, 4, 0, 2, 9, 13, 1, 4, 22, 15, 1, 2, 11, 13, 12, 2, 11, 1, 8, 8, 12, 1, 14, 8, 6, 14, 7, 7, 9, 14, 10, 7, 3, 3, 12, 18, 4, 3, 12, 9, 2, 12, 14, 9, 2, 13, 1, 4, 22, 15, 1, 2, 11, 13, 12, 2, 11, 7, 1, 4, 22, 7, 1, 2, 11, 9, 12, 2, 11, 4, 7, 20, 4, 14, 7, 10, 2, 4, 9, 10, 2, 9, 10, 6, 7, 12, 10, 3, 7, 7, 7, 10, 4, 7, 7, 5, 4, 0, 3, 4, 15, 0, 8, 4, 5, 15, 0, 8, 12, 19, 0, 4, 6, 15, 6, 4, 6, 1, 0, 8, 12, 1, 0, 4, 6, 5, 6, 4, 6, 14, 5, 6, 16, 16, 5, 2, 16, 4, 5, 6, 16, 6, 5, 2, 16, 15, 0, 6, 16, 17, 0, 2, 16, 3, 0, 6, 16, 5, 0, 2, 16, 0, 2, 24, 3, 0, 3, 24, 1, 7, 1, 10, 4, 7, 3, 10, 2, 1, 0, 23, 8, 1, 4, 23, 4, 1, 17, 19, 3, 1, 18, 19, 1, 6, 18, 18, 2, 6, 19, 18, 1, 1, 17, 9, 6, 1, 19, 9, 2, 15, 15, 6, 9, 15, 18, 6, 3, 3, 15, 6, 9, 3, 18, 6, 3, 4, 14, 20, 6, 4, 17, 20, 3, 0, 10, 6, 14, 0, 10, 3, 7, 3, 17, 3, 7, 6, 18, 18, 3, 6, 19, 18, 1, 4, 12, 9, 7, 7, 12, 3, 7, 6, 10, 18, 5, 12, 10, 6, 5, 0, 10, 18, 5, 6, 10, 6, 5, 3, 2, 18, 9, 9, 2, 6, 9, 4, 6, 10, 10, 4, 6, 5, 5, 9, 11, 5, 5, 20, 14, 4, 9, 20, 14, 2, 9, 0, 14, 4, 9, 2, 14, 2, 9, 11, 1, 4, 20, 13, 1, 2, 10, 11, 11, 2, 10, 6, 21, 12, 3, 12, 21, 6, 3, 11, 1, 4, 20, 13, 1, 2, 10, 11, 11, 2, 10, 1, 16, 10, 8, 1, 16, 5, 4, 6, 20, 5, 4, 11, 1, 4, 20, 13, 1, 2, 10, 11, 11, 2, 10, 1, 0, 3, 19, 2, 0, 1, 19, 11, 1, 4, 20, 13, 1, 2, 10, 11, 11, 2, 10, 0, 1, 6, 9, 2, 1, 2, 9, 3, 7, 19, 4, 3, 9, 19, 2, 7, 14, 9, 6, 7, 16, 9, 2, 17, 1, 7, 6, 17, 4, 7, 3, 5, 0, 14, 8, 5, 4, 14, 4, 16, 1, 8, 6, 16, 4, 8, 3, 0, 1, 8, 6, 0, 4, 8, 3, 6, 0, 18, 4, 15, 0, 9, 2, 6, 2, 9, 2, 0, 14, 9, 6, 0, 16, 9, 2, 3, 7, 18, 8, 9, 7, 6, 8, 2, 11, 6, 9, 4, 11, 2, 9, 10, 5, 6, 9, 12, 5, 2, 9, 10, 6, 4, 18, 10, 6, 2, 9, 12, 15, 2, 9, 11, 1, 4, 20, 13, 1, 2, 10, 11, 11, 2, 10, 9, 1, 4, 20, 9, 1, 2, 10, 11, 11, 2, 10, 5, 9, 18, 6, 14, 9, 9, 3, 5, 12, 9, 3, 6, 4, 6, 9, 8, 4, 2, 9, 10, 16, 8, 6, 10, 16, 4, 6, 0, 0, 18, 8, 0, 0, 9, 4, 9, 4, 9, 4, 6, 5, 14, 12, 13, 5, 7, 6, 6, 11, 7, 6, 4, 3, 15, 7, 9, 3, 5, 7, 14, 12, 10, 6, 14, 14, 10, 2, 0, 11, 4, 10, 0, 16, 4, 5, 1, 10, 22, 3, 1, 11, 22, 1, 8, 9, 6, 10, 10, 9, 2, 10, 13, 2, 6, 12, 16, 2, 3, 6, 13, 8, 3, 6, 10, 6, 4, 18, 10, 6, 2, 9, 12, 15, 2, 9, 7, 8, 10, 16, 12, 8, 5, 8, 7, 16, 5, 8, 8, 1, 8, 12, 8, 1, 4, 6, 12, 7, 4, 6, 7, 1, 12, 14, 13, 1, 6, 7, 7, 8, 6, 7, 2, 14, 12, 6, 2, 16, 12, 2, 11, 16, 6, 6, 11, 19, 6, 3, 7, 16, 6, 6, 7, 19, 6, 3, 13, 4, 4, 10, 13, 4, 2, 10, 0, 19, 19, 3, 0, 20, 19, 1, 12, 8, 6, 8, 12, 12, 6, 4, 8, 1, 8, 22, 8, 12, 8, 11, 12, 8, 6, 8, 12, 12, 6, 4, 6, 8, 6, 8, 6, 12, 6, 4, 14, 5, 6, 9, 14, 8, 6, 3, 0, 6, 24, 4, 0, 8, 24, 2, 14, 12, 10, 6, 14, 14, 10, 2, 0, 12, 10, 6, 0, 14, 10, 2, 4, 6, 19, 3, 4, 7, 19, 1, 1, 6, 19, 3, 1, 7, 19, 1, 4, 0, 16, 9, 4, 3, 16, 3, 0, 1, 24, 5, 8, 1, 8, 5, 3, 6, 6, 15, 3, 11, 6, 5, 9, 6, 6, 9, 11, 6, 2, 9, 0, 17, 18, 3, 0, 18, 18, 1, 6, 22, 18, 2, 6, 23, 18, 1, 2, 12, 6, 9, 2, 15, 6, 3, 18, 12, 6, 9, 18, 15, 6, 3, 0, 12, 6, 9, 0, 15, 6, 3, 11, 14, 4, 10, 11, 19, 4, 5, 9, 6, 6, 16, 9, 14, 6, 8, 7, 7, 10, 10, 7, 12, 10, 5, 1, 3, 6, 13, 3, 3, 2, 13, 18, 1, 6, 13, 18, 1, 3, 13, 5, 1, 6, 9, 7, 1, 2, 9, 18, 2, 6, 11, 18, 2, 3, 11, 0, 2, 6, 11, 3, 2, 3, 11, 9, 12, 15, 6, 9, 14, 15, 2, 2, 2, 20, 3, 2, 3, 20, 1, 10, 6, 4, 9, 10, 6, 2, 9, 5, 6, 12, 14, 5, 6, 6, 7, 11, 13, 6, 7, 9, 0, 6, 9, 11, 0, 2, 9, 7, 0, 9, 6, 10, 0, 3, 6, 10, 6, 6, 9, 12, 6, 2, 9, 4, 1, 12, 20, 4, 1, 6, 10, 10, 11, 6, 10, 6, 7, 18, 3, 6, 7, 9, 3, 0, 7, 18, 3, 9, 7, 9, 3, 3, 20, 18, 3, 9, 20, 6, 3, 9, 6, 6, 9, 11, 6, 2, 9, 6, 2, 12, 15, 10, 2, 4, 15, 2, 3, 18, 3, 2, 4, 18, 1, 19, 4, 4, 18, 21, 4, 2, 9, 19, 13, 2, 9, 0, 1, 19, 3, 0, 2, 19, 1, 5, 0, 15, 4, 5, 2, 15, 2, 5, 2, 14, 5, 12, 2, 7, 5, 1, 2, 22, 14, 1, 2, 11, 14, 8, 15, 6, 9, 10, 15, 2, 9, 6, 17, 18, 3, 6, 18, 18, 1, 9, 6, 3, 18, 9, 12, 3, 6, 2, 0, 20, 3, 2, 1, 20, 1, 5, 4, 5, 12, 5, 8, 5, 4, 8, 6, 12, 5, 12, 6, 4, 5, 9, 12, 6, 12, 9, 12, 3, 6, 12, 18, 3, 6, 14, 14, 8, 10, 18, 14, 4, 5, 14, 19, 4, 5, 2, 14, 8, 10, 2, 14, 4, 5, 6, 19, 4, 5, 10, 18, 12, 6, 16, 18, 6, 3, 10, 21, 6, 3, 1, 3, 6, 9, 1, 6, 6, 3, 11, 3, 3, 20, 12, 3, 1, 20, 4, 6, 14, 6, 4, 6, 7, 3, 11, 9, 7, 3, 6, 5, 12, 13, 10, 5, 4, 13, 5, 4, 4, 15, 5, 9, 4, 5, 9, 16, 15, 4, 14, 16, 5, 4, 7, 8, 6, 14, 7, 8, 3, 7, 10, 15, 3, 7, 7, 6, 10, 6, 7, 8, 10, 2, 2, 5, 18, 3, 2, 6, 18, 1, 5, 1, 15, 8, 5, 5, 15, 4, 7, 1, 8, 18, 7, 10, 8, 9, 0, 10, 24, 3, 0, 11, 24, 1, 0, 2, 6, 13, 2, 2, 2, 13, 16, 0, 8, 10, 20, 0, 4, 5, 16, 5, 4, 5, 5, 1, 10, 9, 5, 4, 10, 3, 5, 6, 18, 3, 5, 7, 18, 1, 0, 1, 24, 3, 0, 2, 24, 1, 11, 4, 6, 11, 13, 4, 2, 11, 0, 0, 8, 10, 0, 0, 4, 5, 4, 5, 4, 5, 4, 16, 18, 3, 4, 17, 18, 1, 2, 16, 18, 3, 2, 17, 18, 1, 3, 0, 18, 10, 12, 0, 9, 5, 3, 5, 9, 5, 2, 3, 20, 21, 12, 3, 10, 21, 6, 7, 14, 3, 6, 7, 7, 3, 0, 9, 12, 6, 0, 9, 6, 3, 6, 12, 6, 3, 3, 14, 21, 4, 10, 14, 7, 4, 0, 14, 21, 4, 7, 14, 7, 4, 5, 21, 18, 3, 11, 21, 6, 3, 1, 21, 18, 3, 7, 21, 6, 3, 19, 4, 4, 18, 21, 4, 2, 9, 19, 13, 2, 9, 3, 7, 18, 3, 3, 8, 18, 1, 19, 4, 4, 18, 21, 4, 2, 9, 19, 13, 2, 9, 7, 15, 10, 6, 7, 17, 10, 2, 9, 13, 11, 9, 9, 16, 11, 3, 0, 6, 4, 10, 0, 11, 4, 5, 15, 16, 9, 6, 15, 18, 9, 2, 1, 5, 4, 18, 1, 5, 2, 9, 3, 14, 2, 9, 9, 8, 8, 10, 13, 8, 4, 5, 9, 13, 4, 5, 7, 8, 8, 10, 7, 8, 4, 5, 11, 13, 4, 5, 9, 8, 12, 5, 13, 8, 4, 5, 7, 8, 9, 7, 10, 8, 3, 7, 9, 8, 12, 5, 13, 8, 4, 5, 7, 6, 9, 7, 10, 6, 3, 7, 9, 8, 12, 5, 13, 8, 4, 5, 10, 5, 4, 18, 10, 11, 4, 6, 5, 5, 14, 12, 5, 11, 14, 6, 0, 1, 11, 4, 0, 3, 11, 2, 9, 10, 6, 10, 11, 10, 2, 10, 2, 17, 11, 6, 2, 19, 11, 2, 15, 16, 9, 6, 15, 18, 9, 2, 1, 10, 18, 2, 1, 11, 18, 1, 6, 4, 12, 13, 10, 4, 4, 13, 0, 18, 18, 3, 0, 19, 18, 1, 6, 18, 18, 3, 6, 19, 18, 1, 0, 16, 9, 6, 0, 18, 9, 2, 13, 15, 9, 6, 13, 17, 9, 2, 2, 15, 9, 6, 2, 17, 9, 2, 13, 1, 6, 16, 13, 1, 3, 16, 5, 1, 6, 16, 8, 1, 3, 16, 11, 5, 6, 10, 13, 5, 2, 10, 7, 5, 6, 10, 9, 5, 2, 10, 10, 0, 6, 24, 12, 0, 2, 24, 3, 4, 4, 20, 3, 4, 2, 10, 5, 14, 2, 10, 14, 0, 6, 9, 16, 0, 2, 9, 4, 0, 6, 9, 6, 0, 2, 9, 4, 5, 18, 5, 10, 5, 6, 5, 5, 6, 6, 9, 7, 6, 2, 9, 7, 2, 15, 8, 12, 2, 5, 8, 2, 2, 15, 8, 7, 2, 5, 8, 10, 0, 4, 9, 10, 0, 2, 9, 3, 4, 6, 12, 3, 4, 3, 6, 6, 10, 3, 6, 16, 0, 8, 18, 16, 0, 4, 18, 0, 0, 8, 18, 4, 0, 4, 18, 0, 7, 24, 6, 0, 9, 24, 2, 4, 7, 14, 3, 11, 7, 7, 3, 10, 8, 8, 15, 10, 8, 4, 15, 7, 0, 10, 14, 12, 0, 5, 14, 13, 10, 8, 10, 17, 10, 4, 5, 13, 15, 4, 5, 3, 0, 4, 9, 5, 0, 2, 9, 16, 1, 6, 8, 16, 1, 3, 8, 2, 1, 6, 8, 5, 1, 3, 8, 3, 6, 18, 12, 3, 10, 18, 4, 4, 12, 16, 4, 4, 14, 16, 2, 4, 9, 16, 15, 4, 14, 16, 5, 3, 10, 8, 10, 3, 10, 4, 5, 7, 15, 4, 5, 8, 18, 16, 6, 16, 18, 8, 3, 8, 21, 8, 3, 2, 16, 12, 5, 6, 16, 4, 5, 14, 14, 9, 4, 14, 16, 9, 2, 7, 14, 9, 6, 7, 16, 9, 2, 4, 10, 16, 12, 4, 14, 16, 4, 0, 13, 19, 6, 0, 15, 19, 2, 10, 13, 9, 6, 10, 15, 9, 2, 5, 0, 3, 23, 6, 0, 1, 23, 0, 8, 24, 6, 0, 10, 24, 2, 0, 5, 5, 12, 0, 9, 5, 4, 3, 0, 19, 18, 3, 9, 19, 9, 9, 11, 6, 12, 9, 11, 3, 6, 12, 17, 3, 6, 0, 5, 24, 8, 12, 5, 12, 4, 0, 9, 12, 4, 6, 18, 9, 4, 6, 20, 9, 2, 8, 8, 10, 6, 8, 10, 10, 2, 2, 7, 20, 3, 2, 8, 20, 1, 12, 0, 7, 20, 12, 10, 7, 10, 5, 0, 7, 20, 5, 10, 7, 10, 14, 2, 2, 18, 14, 11, 2, 9, 5, 8, 10, 12, 10, 8, 5, 12, 6, 9, 12, 8, 12, 9, 6, 4, 6, 13, 6, 4, 7, 7, 3, 14, 7, 14, 3, 7, 11, 2, 12, 16, 17, 2, 6, 8, 11, 10, 6, 8, 7, 0, 6, 9, 9, 0, 2, 9, 13, 14, 9, 4, 13, 16, 9, 2, 0, 12, 22, 4, 0, 12, 11, 2, 11, 14, 11, 2, 1, 12, 22, 6, 12, 12, 11, 3, 1, 15, 11, 3, 6, 6, 9, 6, 9, 6, 3, 6, 10, 0, 4, 9, 10, 0, 2, 9, 3, 8, 18, 7, 9, 8, 6, 7, 0, 6, 24, 6, 0, 8, 24, 2, 0, 11, 24, 10, 8, 11, 8, 10, 3, 3, 18, 21, 9, 3, 6, 21, 7, 12, 4, 10, 9, 12, 2, 10, 10, 16, 10, 8, 15, 16, 5, 4, 10, 20, 5, 4, 8, 6, 6, 9, 10, 6, 2, 9, 12, 10, 6, 12, 15, 10, 3, 6, 12, 16, 3, 6, 6, 10, 6, 12, 6, 10, 3, 6, 9, 16, 3, 6, 16, 12, 6, 12, 19, 12, 3, 6, 16, 18, 3, 6, 2, 12, 6, 12, 2, 12, 3, 6, 5, 18, 3, 6, 10, 15, 6, 9, 12, 15, 2, 9, 8, 15, 6, 9, 10, 15, 2, 9, 14, 20, 10, 4, 14, 20, 5, 4, 0, 20, 10, 4, 5, 20, 5, 4, 11, 17, 9, 6, 11, 19, 9, 2, 3, 2, 14, 4, 3, 4, 14, 2, 10, 1, 10, 4, 10, 3, 10, 2, 0, 15, 10, 4, 5, 15, 5, 4, 19, 2, 3, 19, 20, 2, 1, 19, 4, 12, 9, 8, 7, 12, 3, 8, 4, 7, 5, 12, 4, 11, 5, 4, 0, 1, 24, 3, 8, 1, 8, 3, 6, 8, 12, 4, 6, 10, 12, 2, 19, 3, 4, 10, 19, 3, 2, 10, 0, 6, 9, 6, 3, 6, 3, 6, 18, 0, 6, 22, 20, 0, 2, 22, 0, 0, 6, 22, 2, 0, 2, 22, 5, 15, 19, 3, 5, 16, 19, 1, 10, 7, 4, 15, 10, 12, 4, 5, 9, 6, 6, 9, 11, 6, 2, 9, 0, 21, 18, 3, 0, 22, 18, 1, 7, 3, 10, 15, 7, 8, 10, 5, 1, 7, 18, 3, 1, 8, 18, 1, 8, 2, 9, 6, 11, 2, 3, 6, 0, 10, 24, 14, 0, 17, 24, 7, 13, 9, 8, 10, 17, 9, 4, 5, 13, 14, 4, 5, 10, 5, 4, 9, 12, 5, 2, 9, 13, 9, 8, 10, 17, 9, 4, 5, 13, 14, 4, 5, 7, 11, 10, 10, 7, 11, 5, 5, 12, 16, 5, 5, 4, 13, 18, 4, 13, 13, 9, 2, 4, 15, 9, 2, 0, 0, 19, 2, 0, 1, 19, 1, 0, 18, 24, 6, 8, 18, 8, 6, 6, 4, 8, 16, 6, 12, 8, 8, 7, 8, 10, 4, 7, 10, 10, 2, 0, 3, 6, 9, 0, 6, 6, 3, 13, 15, 7, 9, 13, 18, 7, 3, 3, 18, 12, 6, 3, 18, 6, 3, 9, 21, 6, 3, 12, 14, 6, 9, 12, 17, 6, 3, 2, 15, 15, 8, 2, 19, 15, 4, 9, 6, 6, 16, 9, 14, 6, 8, 6, 6, 7, 12, 6, 10, 7, 4, 14, 6, 6, 9, 14, 9, 6, 3, 5, 14, 6, 9, 5, 17, 6, 3, 10, 8, 6, 9, 12, 8, 2, 9, 6, 6, 4, 18, 6, 6, 2, 9, 8, 15, 2, 9, 14, 9, 6, 12, 17, 9, 3, 6, 14, 15, 3, 6, 4, 9, 6, 12, 4, 9, 3, 6, 7, 15, 3, 6, 14, 15, 9, 6, 14, 17, 9, 2, 0, 20, 18, 4, 0, 20, 9, 2, 9, 22, 9, 2, 13, 18, 9, 6, 13, 20, 9, 2, 2, 18, 9, 6, 2, 20, 9, 2, 6, 16, 18, 3, 6, 17, 18, 1, 0, 16, 18, 3, 0, 17, 18, 1, 19, 2, 4, 22, 21, 2, 2, 11, 19, 13, 2, 11, 1, 2, 4, 22, 1, 2, 2, 11, 3, 13, 2, 11, 15, 0, 2, 24, 15, 0, 1, 24, 3, 20, 16, 4, 11, 20, 8, 4, 11, 6, 4, 18, 13, 6, 2, 9, 11, 15, 2, 9, 7, 9, 10, 14, 7, 9, 5, 7, 12, 16, 5, 7, 14, 6, 6, 9, 14, 9, 6, 3, 3, 6, 7, 9, 3, 9, 7, 3, 20, 4, 4, 20, 22, 4, 2, 10, 20, 14, 2, 10, 7, 6, 6, 9, 7, 9, 6, 3, 7, 0, 10, 14, 12, 0, 5, 7, 7, 7, 5, 7, 2, 1, 18, 6, 11, 1, 9, 6, 15, 0, 2, 24, 15, 0, 1, 24, 7, 0, 2, 24, 8, 0, 1, 24, 13, 12, 6, 7, 13, 12, 3, 7, 5, 12, 6, 7, 8, 12, 3, 7, 3, 5, 18, 19, 9, 5, 6, 19, 5, 6, 9, 6, 8, 6, 3, 6, 9, 5, 9, 6, 12, 5, 3, 6, 3, 16, 10, 8, 3, 16, 5, 4, 8, 20, 5, 4, 19, 8, 5, 15, 19, 13, 5, 5, 0, 8, 5, 15, 0, 13, 5, 5, 20, 4, 4, 20, 22, 4, 2, 10, 20, 14, 2, 10, 0, 4, 4, 20, 0, 4, 2, 10, 2, 14, 2, 10, 7, 7, 10, 4, 7, 7, 5, 4, 4, 19, 14, 4, 11, 19, 7, 4, 10, 11, 12, 3, 10, 11, 6, 3, 0, 1, 24, 3, 0, 2, 24, 1, 7, 2, 14, 20, 14, 2, 7, 10, 7, 12, 7, 10, 0, 13, 6, 9, 2, 13, 2, 9, 13, 0, 4, 19, 13, 0, 2, 19, 1, 11, 14, 3, 8, 11, 7, 3, 7, 1, 16, 20, 15, 1, 8, 10, 7, 11, 8, 10, 0, 10, 21, 9, 7, 10, 7, 9, 6, 19, 15, 5, 11, 19, 5, 5, 8, 10, 6, 6, 11, 10, 3, 6, 7, 1, 16, 20, 15, 1, 8, 10, 7, 11, 8, 10, 1, 1, 16, 20, 1, 1, 8, 10, 9, 11, 8, 10, 16, 4, 3, 12, 16, 10, 3, 6, 5, 4, 3, 12, 5, 10, 3, 6, 7, 6, 10, 8, 12, 6, 5, 4, 7, 10, 5, 4, 4, 9, 6, 6, 4, 12, 6, 3, 6, 5, 12, 4, 6, 7, 12, 2, 9, 2, 5, 15, 9, 7, 5, 5, 15, 0, 9, 6, 15, 2, 9, 2, 6, 0, 11, 10, 6, 5, 11, 5, 12, 7, 4, 12, 12, 13, 4, 6, 7, 2, 9, 4, 7, 4, 9, 2, 6, 0, 13, 6, 6, 2, 13, 2, 10, 6, 4, 18, 10, 6, 2, 9, 12, 15, 2, 9, 10, 8, 6, 9, 12, 8, 2, 9, 3, 18, 10, 6, 3, 20, 10, 2, 4, 14, 20, 3, 4, 15, 20, 1, 2, 15, 9, 6, 2, 17, 9, 2, 13, 0, 4, 19, 13, 0, 2, 19, 7, 0, 4, 19, 9, 0, 2, 19, 1, 4, 22, 2, 1, 5, 22, 1, 0, 0, 9, 6, 0, 2, 9, 2, 0, 0, 24, 18, 0, 9, 24, 9, 3, 2, 16, 8, 3, 6, 16, 4, 3, 6, 18, 6, 3, 8, 18, 2, 3, 1, 6, 10, 5, 1, 2, 10, 13, 0, 9, 6, 16, 0, 3, 6, 2, 0, 9, 6, 5, 0, 3, 6, 10, 2, 4, 15, 10, 7, 4, 5, 6, 0, 7, 10, 6, 5, 7, 5, 2, 2, 20, 4, 12, 2, 10, 2, 2, 4, 10, 2, 2, 11, 19, 3, 2, 12, 19, 1, 10, 8, 6, 9, 12, 8, 2, 9, 8, 8, 6, 9, 10, 8, 2, 9, 13, 8, 4, 9, 13, 8, 2, 9, 3, 11, 9, 9, 6, 11, 3, 9, 3, 9, 18, 5, 9, 9, 6, 5, 2, 4, 2, 20, 2, 14, 2, 10, 14, 17, 8, 6, 14, 20, 8, 3, 3, 21, 18, 2, 3, 22, 18, 1, 5, 4, 15, 6, 10, 4, 5, 6, 2, 15, 12, 6, 2, 17, 12, 2, 17, 8, 6, 9, 17, 11, 6, 3, 2, 12, 20, 4, 2, 12, 10, 2, 12, 14, 10, 2, 0, 17, 24, 6, 0, 19, 24, 2, 7, 16, 9, 4, 7, 18, 9, 2, 15, 1, 4, 22, 17, 1, 2, 11, 15, 12, 2, 11, 5, 1, 4, 22, 5, 1, 2, 11, 7, 12, 2, 11, 11, 13, 8, 9, 11, 16, 8, 3, 6, 1, 6, 9, 8, 1, 2, 9, 11, 4, 3, 18, 11, 10, 3, 6, 5, 8, 12, 6, 5, 8, 6, 3, 11, 11, 6, 3, 15, 7, 5, 8, 15, 11, 5, 4, 4, 7, 5, 8, 4, 11, 5, 4, 12, 6, 6, 12, 15, 6, 3, 6, 12, 12, 3, 6, 6, 6, 6, 12, 6, 6, 3, 6, 9, 12, 3, 6, 5, 9, 14, 8, 12, 9, 7, 4, 5, 13, 7, 4, 9, 1, 3, 14, 9, 8, 3, 7, 12, 6, 6, 12, 12, 10, 6, 4, 4, 5, 4, 18, 4, 5, 2, 9, 6, 14, 2, 9, 4, 6, 16, 18, 4, 12, 16, 6, 5, 4, 7, 20, 5, 14, 7, 10, 14, 8, 8, 12, 14, 14, 8, 6, 9, 10, 6, 14, 9, 10, 3, 7, 12, 17, 3, 7, 9, 5, 9, 6, 12, 5, 3, 6, 9, 4, 3, 18, 10, 4, 1, 18, 1, 4, 22, 14, 12, 4, 11, 7, 1, 11, 11, 7, 2, 7, 18, 2, 2, 8, 18, 1, 12, 6, 6, 12, 12, 10, 6, 4, 6, 5, 9, 7, 9, 5, 3, 7, 12, 7, 4, 12, 12, 13, 4, 6, 8, 7, 4, 12, 8, 13, 4, 6, 7, 2, 10, 22, 7, 13, 10, 11, 0, 1, 3, 20, 1, 1, 1, 20, 4, 13, 18, 4, 13, 13, 9, 2, 4, 15, 9, 2, 2, 13, 18, 4, 2, 13, 9, 2, 11, 15, 9, 2, 15, 15, 9, 6, 15, 17, 9, 2, 0, 15, 9, 6, 0, 17, 9, 2, 6, 0, 18, 24, 15, 0, 9, 12, 6, 12, 9, 12, 6, 6, 6, 12, 6, 10, 6, 4, 8, 7, 10, 4, 8, 9, 10, 2, 1, 9, 18, 6, 1, 9, 9, 3, 10, 12, 9, 3, 6, 6, 18, 3, 6, 7, 18, 1, 7, 7, 9, 8, 10, 7, 3, 8, 10, 12, 6, 12, 12, 12, 2, 12, 3, 14, 18, 3, 3, 15, 18, 1, 15, 17, 9, 7, 18, 17, 3, 7, 1, 12, 10, 6, 1, 14, 10, 2, 15, 17, 9, 7, 18, 17, 3, 7, 10, 3, 3, 19, 11, 3, 1, 19, 15, 17, 9, 7, 18, 17, 3, 7, 6, 1, 11, 9, 6, 4, 11, 3, 15, 17, 9, 7, 18, 17, 3, 7, 6, 5, 11, 6, 6, 8, 11, 3, 16, 7, 8, 5, 16, 7, 4, 5, 2, 4, 20, 19, 12, 4, 10, 19, 2, 1, 21, 6, 9, 1, 7, 6, 6, 5, 12, 14, 6, 5, 6, 7, 12, 12, 6, 7, 9, 0, 6, 9, 11, 0, 2, 9, 2, 11, 8, 5, 6, 11, 4, 5, 16, 7, 8, 5, 16, 7, 4, 5, 0, 7, 8, 5, 4, 7, 4, 5, 15, 17, 9, 7, 18, 17, 3, 7, 8, 6, 8, 10, 8, 6, 4, 5, 12, 11, 4, 5, 15, 15, 9, 9, 18, 15, 3, 9, 0, 15, 9, 9, 3, 15, 3, 9, 12, 10, 9, 7, 15, 10, 3, 7, 3, 10, 9, 7, 6, 10, 3, 7, 13, 15, 10, 8, 18, 15, 5, 4, 13, 19, 5, 4, 0, 1, 6, 12, 0, 1, 3, 6, 3, 7, 3, 6, 10, 0, 6, 12, 13, 0, 3, 6, 10, 6, 3, 6, 7, 0, 10, 12, 7, 0, 5, 6, 12, 6, 5, 6, 4, 1, 16, 8, 4, 1, 8, 8, 0, 21, 19, 3, 0, 22, 19, 1, 6, 9, 18, 4, 15, 9, 9, 2, 6, 11, 9, 2, 3, 4, 9, 6, 3, 6, 9, 2, 9, 1, 6, 15, 9, 6, 6, 5, 5, 9, 6, 6, 8, 9, 3, 6, 5, 1, 14, 9, 5, 4, 14, 3, 3, 0, 8, 20, 3, 0, 4, 10, 7, 10, 4, 10, 5, 0, 7, 9, 5, 3, 7, 3, 6, 6, 12, 5, 10, 6, 4, 5, 0, 1, 8, 14, 4, 1, 4, 14, 2, 12, 22, 4, 2, 14, 22, 2, 8, 17, 6, 6, 8, 20, 6, 3, 18, 1, 6, 7, 18, 1, 3, 7, 0, 0, 6, 6, 3, 0, 3, 6, 4, 6, 17, 18, 4, 12, 17, 6, 6, 0, 12, 6, 6, 0, 6, 3, 12, 3, 6, 3, 4, 7, 18, 4, 13, 7, 9, 2, 4, 9, 9, 2, 4, 12, 10, 6, 4, 14, 10, 2, 7, 9, 10, 12, 12, 9, 5, 6, 7, 15, 5, 6, 0, 1, 24, 3, 8, 1, 8, 3, 13, 11, 6, 6, 13, 11, 3, 6, 5, 11, 6, 6, 8, 11, 3, 6, 3, 10, 19, 3, 3, 11, 19, 1, 0, 2, 6, 9, 0, 5, 6, 3, 14, 16, 10, 6, 14, 18, 10, 2, 0, 16, 10, 6, 0, 18, 10, 2, 14, 13, 9, 6, 14, 15, 9, 2, 0, 16, 18, 3, 0, 17, 18, 1, 6, 16, 18, 3, 6, 17, 18, 1, 0, 18, 9, 6, 0, 20, 9, 2, 14, 13, 9, 6, 14, 15, 9, 2, 6, 2, 6, 9, 8, 2, 2, 9, 15, 8, 4, 12, 15, 8, 2, 12, 8, 13, 8, 8, 8, 17, 8, 4, 4, 20, 18, 3, 10, 20, 6, 3, 5, 8, 4, 12, 7, 8, 2, 12, 7, 7, 12, 3, 7, 7, 6, 3, 10, 6, 4, 9, 12, 6, 2, 9, 5, 20, 18, 3, 11, 20, 6, 3, 1, 20, 18, 3, 7, 20, 6, 3, 18, 1, 6, 20, 21, 1, 3, 10, 18, 11, 3, 10, 0, 1, 6, 20, 0, 1, 3, 10, 3, 11, 3, 10, 13, 3, 4, 18, 15, 3, 2, 9, 13, 12, 2, 9, 0, 2, 6, 12, 0, 6, 6, 4, 12, 9, 12, 6, 18, 9, 6, 3, 12, 12, 6, 3, 7, 3, 4, 18, 7, 3, 2, 9, 9, 12, 2, 9, 14, 0, 6, 9, 16, 0, 2, 9, 0, 9, 12, 6, 0, 9, 6, 3, 6, 12, 6, 3, 14, 4, 8, 20, 18, 4, 4, 10, 14, 14, 4, 10, 2, 4, 8, 20, 2, 4, 4, 10, 6, 14, 4, 10, 14, 13, 9, 6, 14, 15, 9, 2, 1, 13, 9, 6, 1, 15, 9, 2, 3, 15, 18, 3, 9, 15, 6, 3, 5, 13, 9, 6, 5, 15, 9, 2, 5, 0, 18, 3, 5, 1, 18, 1, 8, 2, 6, 7, 11, 2, 3, 7, 9, 1, 9, 6, 12, 1, 3, 6, 6, 1, 9, 6, 9, 1, 3, 6, 5, 6, 14, 6, 12, 6, 7, 3, 5, 9, 7, 3, 8, 2, 6, 13, 10, 2, 2, 13, 6, 11, 12, 6, 12, 11, 6, 3, 6, 14, 6, 3, 3, 1, 18, 15, 9, 1, 6, 15, 13, 0, 6, 7, 13, 0, 3, 7, 3, 3, 16, 6, 3, 6, 16, 3, 12, 1, 3, 12, 12, 7, 3, 6, 7, 7, 6, 9, 9, 7, 2, 9, 13, 0, 4, 24, 13, 0, 2, 24, 7, 0, 4, 24, 9, 0, 2, 24, 11, 9, 5, 12, 11, 13, 5, 4, 7, 15, 9, 6, 7, 17, 9, 2, 5, 7, 18, 6, 5, 9, 18, 2, 8, 9, 5, 12, 8, 13, 5, 4, 4, 17, 17, 6, 4, 19, 17, 2, 0, 3, 18, 14, 0, 3, 9, 7, 9, 10, 9, 7, 0, 1, 24, 2, 0, 2, 24, 1, 0, 15, 18, 3, 0, 16, 18, 1, 9, 0, 6, 9, 11, 0, 2, 9, 3, 3, 14, 12, 3, 9, 14, 6, 12, 1, 3, 12, 12, 7, 3, 6, 8, 0, 6, 9, 10, 0, 2, 9, 10, 6, 6, 10, 12, 6, 2, 10, 5, 0, 6, 9, 7, 0, 2, 9, 2, 0, 21, 7, 9, 0, 7, 7, 6, 11, 12, 5, 10, 11, 4, 5, 8, 7, 9, 8, 11, 7, 3, 8, 9, 6, 6, 18, 9, 6, 3, 9, 12, 15, 3, 9, 15, 14, 8, 10, 19, 14, 4, 5, 15, 19, 4, 5, 1, 14, 8, 10, 1, 14, 4, 5, 5, 19, 4, 5, 11, 0, 8, 10, 15, 0, 4, 5, 11, 5, 4, 5, 5, 0, 8, 10, 5, 0, 4, 5, 9, 5, 4, 5, 6, 1, 12, 5, 6, 1, 6, 5, 1, 12, 18, 2, 10, 12, 9, 2, 2, 8, 20, 6, 12, 8, 10, 3, 2, 11, 10, 3, 7, 6, 9, 7, 10, 6, 3, 7, 10, 5, 8, 16, 14, 5, 4, 8, 10, 13, 4, 8, 3, 9, 16, 8, 3, 9, 8, 4, 11, 13, 8, 4, 7, 8, 10, 4, 7, 8, 5, 4, 7, 12, 10, 8, 7, 12, 5, 4, 12, 16, 5, 4, 9, 19, 15, 4, 14, 19, 5, 4, 1, 0, 18, 9, 7, 0, 6, 9, 13, 4, 10, 8, 18, 4, 5, 4, 13, 8, 5, 4, 3, 16, 18, 4, 9, 16, 6, 4, 8, 7, 10, 12, 13, 7, 5, 6, 8, 13, 5, 6, 6, 7, 10, 12, 6, 7, 5, 6, 11, 13, 5, 6, 4, 6, 18, 7, 10, 6, 6, 7, 0, 17, 18, 3, 0, 18, 18, 1, 3, 17, 18, 3, 3, 18, 18, 1, 2, 4, 6, 10, 4, 4, 2, 10, 16, 0, 8, 24, 16, 0, 4, 24, 4, 0, 8, 15, 8, 0, 4, 15, 16, 0, 8, 24, 16, 0, 4, 24, 1, 4, 18, 9, 7, 4, 6, 9, 15, 12, 9, 6, 15, 14, 9, 2, 3, 9, 18, 6, 3, 9, 9, 3, 12, 12, 9, 3, 18, 5, 6, 9, 18, 8, 6, 3, 0, 5, 6, 9, 0, 8, 6, 3, 4, 7, 18, 4, 13, 7, 9, 2, 4, 9, 9, 2, 2, 1, 12, 20, 2, 1, 6, 10, 8, 11, 6, 10, 17, 0, 6, 23, 17, 0, 3, 23, 1, 6, 2, 18, 1, 15, 2, 9, 8, 8, 10, 6, 8, 10, 10, 2, 0, 6, 20, 6, 0, 6, 10, 3, 10, 9, 10, 3, 11, 12, 12, 5, 15, 12, 4, 5, 0, 4, 3, 19, 1, 4, 1, 19, 19, 1, 3, 18, 20, 1, 1, 18, 2, 1, 3, 18, 3, 1, 1, 18, 3, 10, 18, 3, 9, 10, 6, 3, 4, 4, 10, 9, 9, 4, 5, 9, 7, 13, 14, 7, 7, 13, 7, 7, 3, 13, 14, 7, 10, 13, 7, 7, 8, 15, 9, 6, 11, 15, 3, 6, 4, 14, 8, 10, 4, 14, 4, 5, 8, 19, 4, 5, 10, 14, 4, 10, 10, 19, 4, 5, 3, 8, 5, 16, 3, 16, 5, 8, 15, 10, 9, 6, 15, 12, 9, 2, 0, 10, 9, 6, 0, 12, 9, 2, 6, 7, 12, 9, 6, 10, 12, 3, 9, 10, 5, 8, 9, 14, 5, 4, 12, 1, 3, 12, 12, 7, 3, 6, 8, 15, 6, 9, 10, 15, 2, 9, 16, 6, 7, 6, 16, 9, 7, 3, 8, 1, 4, 22, 10, 1, 2, 22, 6, 6, 14, 3, 6, 6, 7, 3, 0, 18, 19, 3, 0, 19, 19, 1, 17, 0, 6, 24, 17, 0, 3, 24, 0, 13, 15, 6, 5, 13, 5, 6, 9, 6, 10, 14, 14, 6, 5, 7, 9, 13, 5, 7, 1, 6, 8, 10, 1, 6, 4, 5, 5, 11, 4, 5, 7, 6, 12, 5, 7, 6, 6, 5, 7, 7, 9, 6, 10, 7, 3, 6, 7, 8, 14, 14, 14, 8, 7, 7, 7, 15, 7, 7, 3, 8, 14, 14, 3, 8, 7, 7, 10, 15, 7, 7, 9, 8, 13, 4, 9, 10, 13, 2, 3, 2, 6, 12, 3, 2, 3, 6, 6, 8, 3, 6, 6, 10, 17, 6, 6, 13, 17, 3, 1, 10, 17, 6, 1, 13, 17, 3, 16, 7, 8, 9, 16, 10, 8, 3, 0, 7, 8, 9, 0, 10, 8, 3, 0, 9, 24, 10, 12, 9, 12, 5, 0, 14, 12, 5, 3, 2, 15, 8, 8, 2, 5, 8, 4, 2, 18, 8, 10, 2, 6, 8, 0, 1, 18, 4, 0, 1, 9, 2, 9, 3, 9, 2, 20, 2, 3, 18, 21, 2, 1, 18, 1, 3, 3, 19, 2, 3, 1, 19, 18, 8, 6, 16, 20, 8, 2, 16, 0, 8, 6, 16, 2, 8, 2, 16, 8, 18, 11, 6, 8, 20, 11, 2, 4, 6, 12, 5, 8, 6, 4, 5, 7, 6, 12, 5, 11, 6, 4, 5, 6, 3, 9, 6, 9, 3, 3, 6, 7, 6, 12, 5, 7, 6, 6, 5, 9, 8, 6, 7, 12, 8, 3, 7, 8, 2, 9, 6, 11, 2, 3, 6, 8, 14, 6, 9, 8, 17, 6, 3, 8, 2, 9, 6, 11, 2, 3, 6, 4, 3, 16, 20, 4, 3, 8, 10, 12, 13, 8, 10, 7, 6, 10, 12, 12, 6, 5, 6, 7, 12, 5, 6, 0, 2, 7, 12, 0, 6, 7, 4, 12, 17, 11, 6, 12, 19, 11, 2, 4, 7, 12, 8, 4, 7, 6, 4, 10, 11, 6, 4, 8, 11, 8, 10, 12, 11, 4, 5, 8, 16, 4, 5, 9, 1, 4, 9, 11, 1, 2, 9, 14, 0, 3, 22, 15, 0, 1, 22, 7, 0, 3, 22, 8, 0, 1, 22, 4, 7, 18, 4, 13, 7, 9, 2, 4, 9, 9, 2, 10, 2, 4, 15, 10, 7, 4, 5, 12, 1, 3, 12, 12, 7, 3, 6, 0, 0, 18, 13, 9, 0, 9, 13, 16, 0, 3, 24, 17, 0, 1, 24, 5, 0, 3, 24, 6, 0, 1, 24, 10, 15, 5, 8, 10, 19, 5, 4, 2, 18, 18, 2, 2, 19, 18, 1, 2, 8, 20, 3, 2, 9, 20, 1, 7, 6, 9, 6, 7, 8, 9, 2, 3, 2, 19, 10, 3, 7, 19, 5, 2, 7, 19, 3, 2, 8, 19, 1, 15, 6, 9, 4, 15, 8, 9, 2, 2, 2, 18, 8, 8, 2, 6, 8, 10, 9, 14, 4, 10, 9, 7, 4, 4, 4, 6, 16, 7, 4, 3, 16, 15, 8, 9, 16, 18, 8, 3, 16, 0, 8, 9, 16, 3, 8, 3, 16, 18, 0, 6, 14, 20, 0, 2, 14, 0, 0, 6, 14, 2, 0, 2, 14, 15, 0, 6, 22, 17, 0, 2, 22, 3, 0, 6, 22, 5, 0, 2, 22, 12, 2, 12, 20, 16, 2, 4, 20, 0, 2, 12, 20, 4, 2, 4, 20, 11, 6, 4, 9, 11, 6, 2, 9, 9, 0, 6, 16, 12, 0, 3, 16, 12, 1, 3, 12, 12, 7, 3, 6, 3, 4, 18, 6, 3, 4, 9, 3, 12, 7, 9, 3, 5, 5, 16, 8, 13, 5, 8, 4, 5, 9, 8, 4, 0, 13, 10, 6, 0, 15, 10, 2, 8, 14, 9, 6, 8, 16, 9, 2, 6, 2, 9, 6, 9, 2, 3, 6, 14, 1, 10, 8, 19, 1, 5, 4, 14, 5, 5, 4, 9, 1, 3, 12, 9, 7, 3, 6, 6, 4, 12, 9, 6, 7, 12, 3, 6, 5, 12, 6, 10, 5, 4, 6, 1, 1, 8, 5, 5, 1, 4, 5, 12, 12, 6, 8, 12, 16, 6, 4, 3, 12, 12, 6, 3, 14, 12, 2, 9, 18, 12, 6, 15, 18, 6, 3, 9, 21, 6, 3, 4, 13, 6, 6, 4, 16, 6, 3, 11, 3, 7, 18, 11, 12, 7, 9, 3, 9, 18, 3, 9, 9, 6, 3, 5, 3, 19, 2, 5, 4, 19, 1, 4, 2, 12, 6, 4, 2, 6, 3, 10, 5, 6, 3, 9, 6, 6, 9, 11, 6, 2, 9, 8, 6, 6, 9, 10, 6, 2, 9, 16, 9, 5, 15, 16, 14, 5, 5, 3, 9, 5, 15, 3, 14, 5, 5, 6, 6, 14, 6, 13, 6, 7, 3, 6, 9, 7, 3, 8, 6, 3, 14, 8, 13, 3, 7, 0, 16, 24, 5, 8, 16, 8, 5, 0, 20, 20, 3, 10, 20, 10, 3, 5, 10, 18, 2, 5, 11, 18, 1, 0, 6, 6, 10, 2, 6, 2, 10, 2, 1, 20, 3, 2, 2, 20, 1, 9, 13, 6, 11, 11, 13, 2, 11, 9, 15, 6, 8, 9, 19, 6, 4, 9, 12, 6, 9, 9, 15, 6, 3, 5, 11, 18, 2, 5, 12, 18, 1, 2, 6, 15, 6, 2, 8, 15, 2, 6, 0, 18, 3, 6, 1, 18, 1, 5, 0, 3, 18, 6, 0, 1, 18, 18, 3, 6, 10, 20, 3, 2, 10, 0, 3, 6, 10, 2, 3, 2, 10, 10, 5, 8, 9, 10, 5, 4, 9, 6, 5, 8, 9, 10, 5, 4, 9, 3, 2, 20, 3, 3, 3, 20, 1, 5, 2, 13, 4, 5, 4, 13, 2, 17, 0, 7, 14, 17, 7, 7, 7, 0, 0, 7, 14, 0, 7, 7, 7, 9, 11, 10, 6, 9, 11, 5, 6, 5, 11, 10, 6, 10, 11, 5, 6, 11, 6, 3, 18, 11, 12, 3, 6, 0, 16, 18, 3, 0, 17, 18, 1, 6, 16, 18, 3, 6, 17, 18, 1, 4, 6, 9, 10, 4, 11, 9, 5, 9, 7, 15, 4, 9, 9, 15, 2, 5, 6, 12, 6, 5, 6, 6, 3, 11, 9, 6, 3, 6, 1, 12, 9, 6, 4, 12, 3, 7, 9, 6, 12, 7, 9, 3, 6, 10, 15, 3, 6, 11, 5, 13, 6, 11, 7, 13, 2, 1, 11, 22, 13, 12, 11, 11, 13, 18, 8, 6, 6, 18, 11, 6, 3, 0, 8, 6, 6, 0, 11, 6, 3, 0, 6, 24, 3, 0, 7, 24, 1, 0, 5, 10, 6, 0, 7, 10, 2, 6, 7, 18, 3, 6, 8, 18, 1, 0, 0, 10, 6, 0, 2, 10, 2, 19, 0, 3, 19, 20, 0, 1, 19, 4, 6, 12, 16, 4, 6, 6, 8, 10, 14, 6, 8, 19, 6, 4, 18, 21, 6, 2, 9, 19, 15, 2, 9, 1, 6, 4, 18, 1, 6, 2, 9, 3, 15, 2, 9, 3, 21, 18, 3, 3, 22, 18, 1, 0, 19, 9, 4, 0, 21, 9, 2, 12, 18, 12, 6, 18, 18, 6, 3, 12, 21, 6, 3, 7, 18, 9, 4, 7, 20, 9, 2, 12, 16, 10, 8, 17, 16, 5, 4, 12, 20, 5, 4, 2, 16, 10, 8, 2, 16, 5, 4, 7, 20, 5, 4, 14, 0, 10, 12, 19, 0, 5, 6, 14, 6, 5, 6, 0, 0, 10, 12, 0, 0, 5, 6, 5, 6, 5, 6, 15, 14, 9, 6, 15, 16, 9, 2, 0, 14, 9, 6, 0, 16, 9, 2, 14, 14, 10, 6, 14, 16, 10, 2, 0, 14, 10, 6, 0, 16, 10, 2, 5, 18, 18, 2, 5, 19, 18, 1, 0, 18, 18, 3, 0, 19, 18, 1, 3, 5, 18, 12, 12, 5, 9, 6, 3, 11, 9, 6, 5, 3, 7, 9, 5, 6, 7, 3, 4, 0, 19, 15, 4, 5, 19, 5, 3, 0, 16, 4, 3, 2, 16, 2, 4, 12, 16, 12, 4, 12, 8, 12, 4, 3, 12, 15, 10, 3, 6, 15, 16, 4, 2, 19, 16, 4, 1, 19, 6, 4, 2, 19, 7, 4, 1, 19, 13, 14, 8, 10, 17, 14, 4, 5, 13, 19, 4, 5, 3, 14, 8, 10, 3, 14, 4, 5, 7, 19, 4, 5, 12, 6, 3, 18, 12, 12, 3, 6, 5, 11, 12, 6, 5, 11, 6, 3, 11, 14, 6, 3, 10, 5, 8, 10, 14, 5, 4, 5, 10, 10, 4, 5, 6, 4, 12, 10, 6, 4, 6, 5, 12, 9, 6, 5, 6, 8, 18, 10, 15, 8, 9, 5, 6, 13, 9, 5, 0, 8, 18, 10, 0, 8, 9, 5, 9, 13, 9, 5, 12, 6, 3, 18, 12, 12, 3, 6, 0, 14, 18, 3, 0, 15, 18, 1, 12, 6, 3, 18, 12, 12, 3, 6, 9, 6, 3, 18, 9, 12, 3, 6, 6, 14, 18, 3, 6, 15, 18, 1, 0, 5, 18, 3, 0, 6, 18, 1, 2, 5, 22, 3, 2, 6, 22, 1, 0, 0, 21, 10, 7, 0, 7, 10, 6, 3, 18, 17, 12, 3, 6, 17, 0, 3, 18, 17, 6, 3, 6, 17, 0, 12, 24, 11, 8, 12, 8, 11, 4, 10, 16, 6, 4, 13, 16, 3, 12, 8, 6, 8, 12, 12, 6, 4, 6, 14, 8, 7, 10, 14, 4, 7, 15, 10, 6, 14, 18, 10, 3, 7, 15, 17, 3, 7, 3, 10, 6, 14, 3, 10, 3, 7, 6, 17, 3, 7, 6, 12, 18, 2, 6, 13, 18, 1, 5, 8, 10, 6, 5, 10, 10, 2, 12, 11, 9, 4, 12, 13, 9, 2, 0, 11, 9, 6, 0, 13, 9, 2, 11, 2, 3, 18, 12, 2, 1, 18, 10, 2, 3, 18, 11, 2, 1, 18, 9, 12, 6, 10, 11, 12, 2, 10, 1, 10, 6, 9, 1, 13, 6, 3, 6, 9, 16, 6, 14, 9, 8, 3, 6, 12, 8, 3, 1, 8, 9, 6, 1, 10, 9, 2, 7, 7, 16, 6, 7, 9, 16, 2, 0, 0, 18, 3, 0, 1, 18, 1, 10, 0, 6, 9, 12, 0, 2, 9, 9, 5, 6, 6, 12, 5, 3, 6, 10, 6, 4, 18, 12, 6, 2, 9, 10, 15, 2, 9, 8, 0, 6, 9, 10, 0, 2, 9, 9, 1, 6, 9, 9, 4, 6, 3, 1, 0, 18, 9, 1, 3, 18, 3, 0, 3, 24, 3, 0, 4, 24, 1, 6, 14, 9, 4, 6, 16, 9, 2, 8, 9, 8, 10, 12, 9, 4, 5, 8, 14, 4, 5, 5, 2, 13, 9, 5, 5, 13, 3, 4, 4, 16, 9, 4, 7, 16, 3, 4, 4, 14, 9, 4, 7, 14, 3, 8, 5, 9, 6, 8, 7, 9, 2, 1, 7, 16, 6, 1, 9, 16, 2, 10, 5, 13, 9, 10, 8, 13, 3, 1, 5, 13, 9, 1, 8, 13, 3, 0, 4, 24, 6, 12, 4, 12, 3, 0, 7, 12, 3, 1, 14, 10, 9, 1, 17, 10, 3, 5, 17, 18, 3, 5, 18, 18, 1, 0, 16, 18, 3, 0, 17, 18, 1, 9, 17, 9, 6, 9, 19, 9, 2, 1, 20, 22, 4, 1, 20, 11, 2, 12, 22, 11, 2, 8, 14, 8, 6, 8, 17, 8, 3, 8, 6, 8, 15, 8, 11, 8, 5, 5, 4, 18, 3, 5, 5, 18, 1, 9, 3, 5, 10, 9, 8, 5, 5, 6, 8, 12, 3, 6, 8, 6, 3, 2, 6, 18, 6, 2, 6, 9, 3, 11, 9, 9, 3, 10, 6, 4, 18, 12, 6, 2, 9, 10, 15, 2, 9, 7, 5, 6, 6, 10, 5, 3, 6, 14, 5, 2, 18, 14, 14, 2, 9, 8, 5, 2, 18, 8, 14, 2, 9, 9, 2, 10, 6, 9, 2, 5, 6, 3, 1, 18, 12, 12, 1, 9, 12, 5, 2, 17, 22, 5, 13, 17, 11, 4, 0, 12, 6, 4, 2, 12, 2, 6, 9, 16, 6, 14, 9, 8, 3, 6, 12, 8, 3, 9, 0, 5, 18, 9, 9, 5, 9, 12, 0, 6, 9, 14, 0, 2, 9, 6, 0, 6, 9, 8, 0, 2, 9, 9, 1, 6, 12, 11, 1, 2, 12, 5, 9, 13, 4, 5, 11, 13, 2, 5, 8, 19, 3, 5, 9, 19, 1, 9, 9, 6, 8, 9, 13, 6, 4, 11, 9, 4, 15, 11, 14, 4, 5, 2, 0, 6, 14, 2, 0, 3, 7, 5, 7, 3, 7, 15, 1, 6, 14, 18, 1, 3, 7, 15, 8, 3, 7, 3, 1, 6, 14, 3, 1, 3, 7, 6, 8, 3, 7, 3, 20, 18, 4, 12, 20, 9, 2, 3, 22, 9, 2, 5, 0, 4, 20, 5, 0, 2, 10, 7, 10, 2, 10, 16, 8, 8, 12, 20, 8, 4, 6, 16, 14, 4, 6, 0, 8, 8, 12, 0, 8, 4, 6, 4, 14, 4, 6, 13, 13, 10, 8, 18, 13, 5, 4, 13, 17, 5, 4, 1, 13, 10, 8, 1, 13, 5, 4, 6, 17, 5, 4, 15, 8, 4, 15, 15, 13, 4, 5, 5, 8, 4, 15, 5, 13, 4, 5, 6, 11, 16, 12, 6, 15, 16, 4, 2, 11, 16, 12, 2, 15, 16, 4, 14, 12, 7, 9, 14, 15, 7, 3, 10, 1, 3, 21, 10, 8, 3, 7, 13, 11, 9, 4, 13, 13, 9, 2, 3, 10, 17, 9, 3, 13, 17, 3, 13, 8, 8, 15, 13, 13, 8, 5, 3, 8, 8, 15, 3, 13, 8, 5, 11, 14, 10, 8, 16, 14, 5, 4, 11, 18, 5, 4, 0, 18, 22, 6, 0, 18, 11, 3, 11, 21, 11, 3, 0, 16, 24, 4, 0, 16, 12, 4, 6, 20, 12, 3, 12, 20, 6, 3, 18, 12, 6, 12, 21, 12, 3, 6, 18, 18, 3, 6, 0, 12, 6, 12, 0, 12, 3, 6, 3, 18, 3, 6, 15, 17, 9, 6, 15, 19, 9, 2, 1, 6, 22, 10, 1, 6, 11, 5, 12, 11, 11, 5, 15, 17, 9, 6, 15, 19, 9, 2, 0, 18, 18, 2, 0, 19, 18, 1, 3, 15, 19, 3, 3, 16, 19, 1, 0, 13, 18, 3, 0, 14, 18, 1, 15, 17, 9, 6, 15, 19, 9, 2, 0, 17, 9, 6, 0, 19, 9, 2, 12, 17, 9, 6, 12, 19, 9, 2, 3, 17, 9, 6, 3, 19, 9, 2, 16, 2, 3, 20, 17, 2, 1, 20, 0, 13, 24, 8, 0, 17, 24, 4, 9, 1, 6, 22, 12, 1, 3, 11, 9, 12, 3, 11}; +const int eye_window_w=20; +const int eye_window_h=20; +const int eye_n_stages=24; +const uint8_t eye_stages_array[]={6, 12, 9, 16, 23, 27, 28, 36, 47, 48, 55, 32, 30, 44, 53, 51, 44, 72, 66, 69, 59, 88, 58, 93}; +const int16_t eye_stages_thresh_array[]={-372, -321, -351, -329, -311, -330, -296, -313, -329, -286, -292, -288, -300, -265, -268, -284, -320, -286, -278, -266, -270, -250, -259, -250}; +const int16_t eye_tree_thresh_array[]={531, -189, -66, -187, -220, 139, -889, 49, -73, 91, -374, 118, 32, 83, -48, -3, 0, -33, -483, -140, -88, -89, -117, -46, -92, -7, 0, 814, -147, -317, 0, 1, -76, 0, -75, -53, 0, 0, -13, 7, -103, 5, -30, -122, -514, 21, -33, -67, -8, -6, -20, -78, -50, 235, -39, -12, -17, -55, 0, -10, -289, 377, -36, 0, -12, -10, -196, 357, -69, -118, 10, -98, -134, -62, -1, 3, -43, -30, -437, 66, -84, 69, -23, 0, 32, -10, -91, -31, -4, 78, 23, -39, 45, -71, 125, -90, 0, -28, -28, -57, -196, 0, 4, -10, 0, 0, 1076, -96, -16, 0, -32, -6, -1, 0, 53, -53, 12, -24, -9, 64, 0, -114, 528, 99, -10, -14, 0, -66, -18, -89, -11, -18, 116, 340, -50, -19, -3, -80, 4, -106, -5, -204, -12, 19, 0, 0, -54, 9, -51, -11, 81, 19, -28, -53, -5, 11, 1, -59, -545, -41, -32, -58, -24, 44, 0, -23, -91, -20, 0, -2, 6, -49, 43, -126, 46, -50, -24, -4, -30, 11, 0, -20, 306, 82, 181, -3, -10, 0, -150, 12, -10, -57, 3, -29, -78, -20, -11, -101, 82, 7, 5, -44, 0, 15, -418, -212, -174, 1, 99, -97, -28, -2, 21, -54, -27, -17, -44, 1, -10, 5, -20, 108, -13, -12, 125, -39, 0, 20, 1, -35, 3, 4, -97, 0, 100, -583, -82, 0, -11, 0, -28, -153, -65, -12, 4, -6, 17, -44, -17, 30, 33, -136, 80, 90, -17, -3, 3, 37, -16, 0, -12, -90, -30, 3, -19, -62, 20, -7, -50, -53, -5, 24, 2, -7, -2, -24, -13, -249, -396, 16, -37, -19, -17, -39, -71, -27, 1, -9, -30, -21, -19, 6, -19, -5, 9, -1, 20, -37, -28, 4, -154, -27, 2, -17, -282, 25, 43, -257, 14, -32, -14, -38, 0, 7, -22, 30, -63, 117, 0, 214, -354, -172, 0, 21, -3, 0, 20, -6, 11, 9, -3, 8, 46, -4, 13, 0, -16, -6, 57, 672, 3, -7, -6, 7, -553, -16, -11, -5, -14, 170, -37, 25, -4, 47, -36, 2, 5, -44, 5, 9, 11, -27, -197, 62, -24, 27, -32, 15, -4, 14, 26, 0, -15, 15, -100, 193, 27, -5, -20, 14, 8, 120, -3, -443, -73, 25, -6, 3, 0, -85, -25, 44, 0, 0, 5, -3, 4, -4, -4, 31, -572, 8, -11, 21, -5, -15, 24, -21, 20, -2, 21, -60, -169, 3, -229, 4, 11, -30, -6, 18, 9, -347, -20, -8, -42, -55, -345, 10, 64, 265, 1, 5, -23, -605, -67, 12, -149, 0, -15, -16, 81, 3, -4, 64, -4, -449, -37, 60, -5, -17, 14, -15, 15, -8, -9, 4, 7, 24, -113, 192, -32, -52, 96, 65, 32, 23, 9, 18, -6, 10, 9, 23, 12, -355, 21, -81, 15, 42, -82, -21, -8, -1, 0, -1, 26, 45, -4, 9, -45, -1, 94, -9, -3, 6, 3, -84, -84, 88, 26, -36, -38, -8, -7, -55, -79, -13, 1, -31, -34, 113, -224, 10, 0, 20, -427, -2, 13, 21, -10, -11, -97, 82, -88, 11, 11, 13, -14, 7, -1, 0, -1, 82, 150, 5, -62, 19, 0, -14, 4, 0, 560, -48, 16, -1, -19, -1, 42, -3, 5, 70, 10, 5, 19, -25, -13, 13, -23, 0, -16, 5, -4, -13, 101, -31, 32, -44, -14, -127, 4, 13, -114, -94, -16, 12, -44, -74, 2, 44, -1, -14, -80, -44, -17, 6, 64, -45, 36, -3, -12, 25, 84, 408, -26, -249, -12, -40, -338, 20, 25, -13, -10, 3, -156, 0, 6, 5, 40, -6, 8, -14, 1, -2, -1, 28, 52, -6, 497, -205, 128, 7, -23, 0, -809, 0, 0, 41, -29, 993, 2, 14, 0, -2, -27, -108, 40, 132, -11, -45, 25, 356, 4, -3, -56, -310, -11, -16, 71, 90, -11, -41, -28, -15, -13, -32, 0, -13, -3, -2, -1, 5, -211, -62, 282, 5, -10, -6, -6, -27, -57, -9, 81, 10, -2, -71, -8, 10, -229, -6, -46, 95, -9, -118, -59, -21, 20, -17, 0, 1, -3, 0, -15, -164, 0, 0, 298, 41, 9, -14, -5, -39, -39, -39, -17, -39, -37, -35, -36, -58, 106, 0, 0, 28, -50, -15, 11, -31, 1, 13, -68, -26, 1, 61, 1, -1, 1, 33, -93, 0, -52, -4, 4, -183, 33, -47, 345, 58, 6, 40, -37, -1, 807, -29, 35, 36, 234, 15, -5, 4, -7, 44, 0, -22, -12, 26, 48, 55, -10, 6, 10, -31, 20, -11, 12, 12, 914, -391, 0, 0, -26, -4, -121, -53, -5, -14, -6, -25, -136, -93, -353, -8, 160, 14, 2, 2, -89, -13, 9, -1, 14, -89, 0, -6, 31, 15, 24, -7, 67, 19, -127, 2, 48, -30, -220, 63, 6, -1, 11, -269, 5, 3, 97, 112, -1, -5, -38, 31, 0, -6, 17, 0, -32, 700, -6, -43, -23, -76, -3, 43, 144, 3, 378, -12, -354, 0, -149, 10, -18, -21, 18, 59, 0, -24, -24, -45, -240, -18, -38, 5, 20, -31, -1594, -410, 3, -14, 34, 9, 30, 13, -320, 0, -39, -291, 1, -1, -16, 13, -22, -1, -5, -1, -29, -69, 122, 11, -7, 20, 336, -1, -7, -20, -34, -445, -39, -111, -26, -49, -687, -54, 314, 20, 13, -7, -1, 1, -1, 322, -3, 98, -6, -3, 1, 8, 109, -8, 23, 0, 0, 17, -8, 89, -60, -14, 7, -5, -16, -79, 53, -2, -54, 14, 25, 6, 1, -6, 14, -19, -47, -112, -216, -1222, -1, 0, 0, 8, -28, 33, 0, 6, -1, -126, -2, -48, 29, -8, 14, -551, -9, 17, -30, 2, 0, 27, 0, -832, 38, -9, 0, 61, 3, -17, 2, -68, -1, 1, -82, -59, -86, 86, 4, 0, -148, -37, -8, -93, 104, -10, -15, -68, 2, -150, 5, -34, 265, 124, 10, -28, -4, 0, -1, -7, -54, -7, -26, 0, 89, -112, 0, 287, -294, -441, 5, 279, -27, -2, -238, -25, -55, 5, 0, -317, 3, 4, -3, 341, -37, -1, 31, -510, 54, -27, -11, 3, -205, 30, -2, -7, -1, -290, -218, -82, 4, 0, 62, -852, 6, -216, -88, 0, 0, 0, -49, -72, -25, -3, -1, -69, 19, -42, -90, -28, -2, -9, -115, 8, -1, -68, 490, -1, -74, -1, 1, 3, 1764, 2, 0, -226}; +const int16_t eye_alpha1_array[]={-197, 146, 154, 164, 138, -59, 182, -72, 136, -44, 157, -31, 43, -32, 98, -163, -88, -162, 173, 171, 184, 170, 179, 151, 88, -203, -79, -135, 107, 122, -98, -67, 119, 75, 118, 106, -71, -69, 113, -41, 104, 21, 142, 91, 100, -112, 102, 107, -189, -194, 107, 120, 84, -94, -184, 91, 100, -150, -67, -200, 106, -33, 93, -76, 91, -139, 106, -99, 135, 91, 38, 143, 118, -189, -116, 24, 104, 103, 158, -33, -182, 32, -155, -68, -20, 94, -175, 60, -153, -40, -25, -155, -26, 80, -48, 93, 54, 101, 77, -195, 123, -64, 17, 109, -49, 77, -59, 49, 141, -61, 104, -147, 74, -50, -24, 120, -34, -199, 79, 16, -45, 116, -134, -38, 84, 121, -77, 58, 103, -175, -178, 64, 15, 16, -181, 131, 68, -172, 13, 144, -128, 45, 100, -30, -44, -59, 110, 18, 92, 72, 12, -27, -205, 47, 70, 23, -99, 96, 77, 94, 117, 114, 71, -38, -58, 116, -160, 67, -62, -109, -30, 71, 10, -160, 10, 51, 131, -185, 75, 11, 51, 75, -29, -26, -70, 62, -137, -53, 93, -33, -145, -124, -20, 114, -170, 44, -153, 59, -22, 12, -38, -148, -35, -26, 106, 84, 66, -88, -108, 81, 79, -153, -31, 86, -156, 64, 140, 21, 59, 15, -171, -18, -108, 41, -15, -155, -42, 11, -28, 103, 16, -24, -150, -38, -14, 38, 55, -43, -177, 48, 120, -194, 78, 67, -44, 91, 12, -163, 41, 8, 6, 85, -26, -63, 98, -160, 23, -18, 51, -71, 93, 100, 32, 18, 55, 93, -88, -158, -149, -152, -174, -24, 20, 60, -114, 111, 46, 120, 70, -31, 91, -105, -186, 141, -146, -118, -24, 58, -145, 89, -154, -26, 72, 59, 16, -97, -19, 36, 69, -39, -151, 65, 11, 63, -170, 6, -20, 71, -88, 61, -151, 47, -84, 25, 75, -37, -175, -37, -44, -17, 129, 116, -67, 19, -126, -54, -23, 65, -40, -38, 75, 12, -32, 63, 13, -55, 62, 72, 10, -125, -72, -183, -186, -79, 75, -170, -158, 57, -138, -16, -193, 23, 62, -30, -125, -55, -38, 109, 18, 12, -43, -202, -178, -27, 79, 20, -223, -29, 61, -60, -80, -70, -143, 10, 42, -27, -45, -138, 62, 17, -34, -73, -148, 101, 70, 5, -145, -38, -39, -161, 65, -25, 48, -38, 12, 46, -27, 69, -179, -23, 176, 24, 61, -29, -152, -118, -18, -189, -35, -140, -21, 53, -211, 21, 39, -52, -44, -152, 48, 8, -60, 59, 99, 46, -192, -184, -86, -30, -17, -19, 18, -43, 90, 110, 59, -34, -160, 42, -121, 46, -17, 14, -120, -31, 51, -221, 75, 8, 62, 55, 11, 38, -22, 44, 68, 11, -28, -39, 29, -10, -137, 59, -22, -31, -21, 9, -42, -31, 66, -27, -35, -19, -28, -94, -27, -136, -34, 22, 40, -175, 72, -94, -82, -83, -22, 18, 66, -21, 49, -81, -25, 116, -90, 25, 14, 80, 69, 10, -25, -134, 63, 68, 40, 104, 46, 74, -54, -116, 67, -25, 73, -28, -48, -19, 51, 45, 10, -31, 131, -129, 95, -44, -112, -32, -22, -21, -113, -28, -96, 19, -84, -15, -15, -90, 58, -14, -78, 98, -28, -51, -55, 111, -12, -97, 124, -91, 13, 115, -24, -20, -29, 17, -16, -181, 35, -33, 97, -79, 66, -14, 37, 85, -18, 118, -70, 57, 99, 61, -72, 8, 61, 99, 78, -35, 42, -161, -47, -6, -76, 67, -151, 41, -147, 15, -18, 100, 9, 45, -113, -13, 14, -9, 72, -130, -122, 103, -180, 7, -13, 23, 34, -17, 75, -42, -23, 16, 5, 65, 5, 69, -27, -76, -69, -14, 17, 52, -24, 72, -22, -29, 60, 45, 116, -60, 20, -10, 44, 13, -29, -10, 17, 87, 30, 52, -28, -25, 38, 131, -23, 7, -33, -128, -203, 78, 53, -168, -21, 16, 37, 126, 71, -148, -127, 88, 38, 58, -113, 35, -76, -41, -136, -200, -9, -24, 29, 45, 46, 64, 35, 102, -48, 12, -111, 168, 101, 15, -132, 38, -161, -14, 48, -139, -172, -110, -27, 61, -22, 11, -140, -28, 62, -161, 50, -23, 12, -23, 16, 33, 41, 156, -256, 256, 72, -256, 222, 116, 34, 82, -33, -31, 30, -16, 140, 61, -32, 76, 15, 12, 182, -89, 23, -13, 16, 45, 26, -16, 135, 20, -89, 59, 30, -164, 11, 106, 13, 11, 21, -14, 115, 46, -7, -228, -18, 18, 13, 8, 79, -33, 74, 8, 41, -111, 97, -40, -10, -13, 28, 17, 16, 50, 21, -121, -12, -26, -3, -189, -32, -42, 86, 57, 66, 48, 51, 61, -125, 79, -126, 83, -173, 57, 29, -29, -38, 25, -81, -97, -24, 56, 9, 75, 58, -129, 11, -22, -19, -90, -20, 10, 49, -53, 10, 40, -142, -10, 17, 45, 7, -118, -24, 29, -8, -16, -86, 37, -131, 5, 60, 49, -24, -80, -169, 8, 55, 62, -122, -153, 62, -35, -19, -24, -70, 58, 122, -57, 70, -11, 60, 38, -14, 9, -44, 79, -81, 62, -194, -116, 37, -25, 8, 23, -170, -147, 22, 66, -28, 9, -9, -25, -196, -34, 64, -102, 10, -66, 61, -18, 128, 63, 81, -69, 70, -89, 8, 9, 63, -21, -4, -63, 73, 32, 60, -66, -181, -149, -152, 33, -145, 29, -8, -13, -19, 50, -73, 17, 42, 6, 35, 7, 67, 39, 14, -23, 15, 75, -16, -43, 16, -25, 49, 9, -112, 50, 5, 25, 29, 121, -65, 49, 113, -34, -13, -51, 26, 72, -21, 50, -143, 127, 43, -165, 64, -22, 29, -12, -138, 6, -30, -15, -88, 51, -80, 51, -9, -72, -27, 127, 43, 22, 63, 17, -21, 7, -40, -177, -22, 54, 38, -8, 12, 55, -19, -173, 58, 14, 49, -175, 96, 7, -17, 46, -214, 106, -50, 62, -73, 74, 54, 67, 5, 138, -33, -242, -18, -21, -33, -164, 36, 40, -85, 43, -149, 36, 70, 33, -6, -61, -34, -14, -96, -95, 20, -9, 49, 33, -77, 56, -99, -24, -61, 143, 14, -15, 60, 13, -100, -79, -11, -209, 9, -91, 64, -18, -161, -17, -92, 36, 55, 115, -173, -111, -6, 46, -51, 171, -19, 63, -74, -56, -29, 40, 31, -89, 33, 44, -72, 100, -8, -145, -116, 40, -36, 42, 69, 10, 41, -109, -4, 40, 49, 20, 25, -18, -7, 29, -43, 116}; +const int16_t eye_alpha2_array[]={174, -125, -80, -39, -52, 123, -151, 151, -58, 162, -43, 190, -167, 211, -53, 33, 58, 33, -128, -91, -46, -70, -50, -56, -98, 40, 90, 90, -100, -64, 81, 83, -38, -64, -33, -45, 68, 61, -36, 109, -46, -204, -30, -98, -76, 49, -59, -58, 32, 22, -45, -36, -55, 62, 16, -42, -30, 22, 54, 20, -35, 129, -35, 52, -39, 26, -87, 61, -44, -57, -167, -37, -27, 14, 24, -140, -31, -41, -18, 95, 13, -79, 20, 37, 145, -34, 13, -45, 19, 76, 107, 18, 107, -86, 137, -41, -72, -33, -52, 25, -33, 62, -168, -33, 74, -50, 60, -72, -24, 55, -32, 24, -43, 70, 103, -22, 78, 14, -38, -185, 59, -46, 41, 108, -44, -18, 40, -52, -34, 20, 12, -41, -170, -137, 14, -22, -45, 18, -142, -18, 22, -57, -25, 108, 57, 42, -25, -147, -29, -31, -206, 86, 11, -45, -32, -109, 22, -63, -57, -45, -33, -26, -39, 102, 55, -32, 21, -37, 42, 23, 77, -31, -189, 12, -183, -49, -15, 12, -30, -178, -40, -29, 77, 104, 31, -34, 16, 41, -23, 64, 13, 14, 103, -16, 12, -43, 14, -30, 92, -161, 48, 11, 50, 64, -42, -53, -40, 35, 34, -42, -34, 22, 98, -25, 12, -36, -15, -113, -35, -126, 11, 113, 17, -46, 136, 13, 49, -147, 59, -15, -114, 77, 11, 45, 125, -48, -30, 42, 10, -38, -14, 8, -22, -23, 39, -19, -151, 8, -38, -192, -183, -18, 136, 53, -37, 30, -141, 142, -53, 35, -19, -28, -61, -112, -36, -21, 23, 12, 11, 10, 8, 77, -90, -30, 14, -17, -36, -15, -24, 53, -19, 17, 9, -13, 12, 12, 66, -26, 12, -21, 11, 59, -25, -29, -108, 15, 85, -43, -23, 50, 10, -24, -124, -24, 9, -186, 76, -75, 53, -49, 31, -63, 28, -127, -33, 85, 25, 79, 54, 126, -19, -23, 41, -138, 15, 36, 91, -36, 53, 68, -27, -183, 61, -34, -133, 32, -29, -27, -188, 45, 61, 22, 24, 46, -56, 21, 13, -51, 17, 158, 13, -113, -47, 94, 27, 47, 74, -26, -164, -185, 60, 11, 10, 93, -29, -119, 9, 84, -45, 63, 47, 42, 28, -148, -64, 100, 69, 12, -33, -180, 56, 34, 9, -20, -34, -205, 10, 48, 49, 9, -27, 77, -35, 55, -164, -35, 62, -30, 10, 79, -10, -73, -28, 62, 12, 13, 99, 10, 48, 12, 81, -31, 8, -143, -69, 51, 54, 12, -40, -175, 28, -35, -14, -45, 6, 8, 18, 57, 80, 104, -88, 39, -21, -14, -27, 67, 11, -42, 12, -36, 93, -114, 12, 52, -32, 7, -21, -198, -29, -35, -139, -38, 65, -36, -20, -120, 52, 40, -56, 137, 11, -26, 78, 45, 82, -174, 106, 103, -51, 93, 76, 124, 74, 18, 81, 18, 58, -122, -45, 9, -25, 20, 19, 22, 81, -103, -30, 79, -38, 22, 65, -13, 20, -55, -103, -20, -19, -152, 60, 11, -24, -23, -40, -16, -35, -20, 28, 13, -24, 53, -19, 55, 36, 75, -27, -30, -139, 164, -28, 29, -37, 122, 34, 119, 94, 132, 23, 100, 31, -104, 28, 143, 133, 27, -41, 123, 27, -23, 79, 39, 36, -19, 150, 23, -18, 27, -146, -21, 80, 92, 56, -94, 98, 9, -59, 58, -17, 21, -26, 122, -44, -42, 145, -23, 33, -38, -16, -29, 33, -131, -33, -20, -18, 48, -40, 10, 34, 156, 18, -20, 10, -32, 9, -77, 75, -12, -125, -28, 13, 95, -94, 148, -15, 9, 9, -12, 7, -135, 84, -55, -35, 85, -17, 31, 54, -92, -207, -17, -215, -19, 58, 16, 17, 93, -73, -25, 50, -17, 54, 42, -23, -27, -10, 19, -73, 122, -25, -82, 37, 136, -69, -14, -38, -67, 83, 81, -50, -11, 88, -212, 52, 23, -1, -20, -32, 12, 92, -181, -42, -6, -19, 9, 12, -17, -36, -23, 14, -37, 19, 35, 10, 6, 182, 55, -46, -31, -29, -23, -44, -12, 38, -110, 10, -8, -11, -83, 9, -32, 8, 98, -25, 10, 5, 11, 49, -26, 52, -99, 9, 44, -20, 6, -26, 50, -86, 51, -68, -32, -27, -16, 0, 0, -39, 11, 0, -22, -66, -24, 67, 53, -59, 105, -10, -24, 49, -24, -107, -161, -10, 18, -63, 144, -93, -29, -51, 77, -10, -63, 14, -23, -47, 7, -110, -12, -97, -110, -63, 88, -10, -27, 170, 6, 72, -77, -100, -130, -16, 37, -17, -122, -29, 11, -14, 31, 117, 89, -42, -78, -71, -27, -63, 8, 109, 43, 236, 7, 33, 25, -39, -49, -39, -42, -31, -33, 26, -29, 13, -16, 6, -32, -68, 65, 42, -56, 21, 15, 73, -24, -148, -20, -25, 11, -105, 63, 72, 14, 60, -124, -26, 24, -159, -31, 10, 159, -78, -28, -226, 8, 73, -42, 153, 76, 16, -33, 8, -178, -22, -26, 65, 15, 6, -116, -21, -21, 11, 5, -18, 67, 99, 74, 20, -20, -1, 22, -25, 80, -22, -32, 93, -137, 28, -17, 16, -20, 7, 7, -28, 50, -101, -40, 4, 6, -41, -15, 40, -121, 126, 40, 5, 28, -17, 10, -84, 17, -18, 61, -7, -14, -10, 14, -13, 11, -110, -94, -15, 56, 176, 16, -13, -32, -18, 15, 4, 5, 5, -25, 8, -30, 153, 59, 45, -20, 12, -57, -22, -142, -30, -118, -14, -28, -72, 45, -62, -13, 63, 24, -62, 46, -24, -115, 8, -19, -184, -38, -32, -30, 41, -44, -23, 46, 92, 30, -61, -17, 104, -29, 17, -15, -33, 10, -22, 61, -48, 147, 12, -158, 41, 90, 16, -25, 15, -22, 136, 18, 63, -10, -28, -70, -24, -86, 62, -176, 30, 7, 61, -33, -32, 129, -102, -22, 67, 8, -23, -91, -24, 6, -13, -228, 69, -25, 6, -13, 26, -37, 27, -26, -35, -11, -110, -11, 42, 5, 68, 70, 45, 10, -29, -28, 11, -27, 7, -28, -13, -28, 128, 15, 25, 63, 10, 10, -44, 104, -21, -36, 13, -19, 10, 38, 16, -6, -71, 63, -16, -79, 8, 12, 93, 4, -85, 10, -14, 58, 7, 71, 10, -27, -17, -10, 4, 8, 130, -21, 17, -5, 44, -16, 13, 16, 29, -21, -28, 8, -27, -22, 13, -10, 105, 7, 6, -23, 26, -21, -14, -81, -21, 7, 204, -21, -18, -53, -38, 55, 146, -32, 20, -7}; +const int8_t eye_num_rectangles_array[]={2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 2, 2, 3, 3, 3, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 2, 2, 2, 3, 3, 3, 2, 3, 3, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; +const int8_t eye_weights_array[]={-1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, 2, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 2, -1, 2, -1, 3, -1, 2, 2, -1, 2, 2, -1, 2, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, 2, -1, 2, -1, 3, -1, 3, -1, 2, 2, -1, 3, -1, 3, -1, 2, -1, 3, -1, 3, -1, 3, -1, 2, -1, 2, -1, 3, -1, 2, -1, 2}; +const int8_t eye_rectangles_array[]={0, 8, 20, 12, 0, 14, 20, 6, 9, 1, 4, 15, 9, 6, 4, 5, 6, 10, 9, 2, 9, 10, 3, 2, 7, 0, 10, 9, 7, 3, 10, 3, 12, 2, 2, 18, 12, 8, 2, 6, 8, 6, 8, 6, 8, 9, 8, 3, 2, 0, 17, 18, 2, 6, 17, 6, 10, 10, 1, 8, 10, 14, 1, 4, 7, 10, 9, 2, 10, 10, 3, 2, 5, 1, 6, 6, 5, 3, 6, 2, 3, 1, 15, 9, 3, 4, 15, 3, 6, 3, 9, 6, 6, 5, 9, 2, 8, 17, 6, 3, 10, 17, 2, 3, 9, 10, 9, 1, 12, 10, 3, 1, 1, 7, 6, 11, 3, 7, 2, 11, 9, 18, 3, 1, 10, 18, 1, 1, 16, 16, 1, 2, 16, 17, 1, 1, 9, 17, 6, 3, 11, 17, 2, 3, 8, 0, 5, 18, 8, 6, 5, 6, 6, 7, 9, 7, 9, 7, 3, 7, 14, 6, 6, 10, 16, 6, 2, 10, 9, 8, 9, 5, 12, 8, 3, 5, 3, 7, 9, 6, 6, 7, 3, 6, 1, 7, 6, 6, 3, 7, 2, 6, 16, 0, 4, 18, 16, 6, 4, 6, 0, 17, 3, 3, 0, 18, 3, 1, 16, 0, 2, 1, 17, 0, 1, 1, 0, 8, 20, 12, 0, 14, 20, 6, 6, 6, 9, 8, 9, 6, 3, 8, 5, 3, 12, 9, 5, 6, 12, 3, 4, 16, 1, 2, 4, 17, 1, 1, 18, 10, 2, 1, 19, 10, 1, 1, 9, 8, 6, 5, 11, 8, 2, 5, 0, 0, 2, 1, 1, 0, 1, 1, 6, 8, 6, 6, 8, 8, 2, 6, 11, 7, 6, 7, 13, 7, 2, 7, 19, 14, 1, 2, 19, 15, 1, 1, 6, 17, 1, 2, 6, 18, 1, 1, 14, 7, 2, 7, 15, 7, 1, 7, 6, 8, 2, 4, 7, 8, 1, 4, 5, 8, 12, 6, 5, 10, 12, 2, 2, 17, 1, 3, 2, 18, 1, 1, 6, 7, 3, 6, 7, 7, 1, 6, 6, 7, 9, 12, 9, 7, 3, 12, 6, 2, 11, 12, 6, 6, 11, 4, 1, 12, 5, 8, 1, 16, 5, 4, 14, 7, 6, 7, 16, 7, 2, 7, 10, 8, 6, 6, 12, 8, 2, 6, 16, 18, 4, 2, 16, 19, 4, 1, 18, 17, 2, 3, 18, 18, 2, 1, 9, 7, 3, 7, 10, 7, 1, 7, 5, 6, 6, 8, 7, 6, 2, 8, 2, 6, 6, 11, 4, 6, 2, 11, 8, 10, 12, 8, 8, 14, 12, 4, 7, 17, 6, 3, 9, 17, 2, 3, 10, 9, 3, 3, 11, 9, 1, 3, 8, 8, 3, 6, 9, 8, 1, 6, 7, 0, 6, 5, 9, 0, 2, 5, 6, 17, 1, 3, 6, 18, 1, 1, 0, 18, 4, 2, 0, 19, 4, 1, 4, 1, 11, 9, 4, 4, 11, 3, 3, 1, 14, 9, 3, 4, 14, 3, 0, 9, 6, 4, 2, 9, 2, 4, 18, 13, 1, 2, 18, 14, 1, 1, 13, 5, 3, 11, 14, 5, 1, 11, 0, 18, 8, 2, 0, 18, 4, 1, 4, 19, 4, 1, 5, 8, 12, 5, 9, 8, 4, 5, 4, 7, 11, 10, 4, 12, 11, 5, 14, 9, 6, 4, 16, 9, 2, 4, 0, 7, 6, 8, 3, 7, 3, 8, 0, 16, 3, 3, 0, 17, 3, 1, 7, 11, 12, 1, 11, 11, 4, 1, 4, 8, 9, 4, 7, 8, 3, 4, 5, 16, 6, 4, 7, 16, 2, 4, 18, 17, 1, 3, 18, 18, 1, 1, 18, 17, 1, 3, 18, 18, 1, 1, 4, 9, 4, 10, 4, 9, 2, 5, 6, 14, 2, 5, 4, 8, 6, 4, 6, 8, 2, 4, 10, 2, 2, 18, 10, 8, 2, 6, 0, 5, 8, 6, 0, 5, 4, 3, 4, 8, 4, 3, 6, 0, 6, 5, 8, 0, 2, 5, 18, 0, 2, 14, 18, 7, 2, 7, 8, 18, 4, 2, 10, 18, 2, 2, 1, 17, 6, 3, 1, 18, 6, 1, 11, 8, 3, 5, 12, 8, 1, 5, 11, 8, 3, 4, 12, 8, 1, 4, 11, 0, 6, 5, 13, 0, 2, 5, 1, 7, 6, 7, 3, 7, 2, 7, 0, 13, 1, 3, 0, 14, 1, 1, 3, 2, 9, 6, 3, 4, 9, 2, 8, 6, 9, 2, 8, 7, 9, 1, 0, 14, 3, 6, 0, 16, 3, 2, 1, 11, 6, 4, 3, 11, 2, 4, 6, 9, 9, 3, 9, 9, 3, 3, 6, 0, 9, 6, 6, 2, 9, 2, 8, 5, 6, 6, 8, 7, 6, 2, 1, 12, 2, 1, 2, 12, 1, 1, 10, 10, 6, 2, 12, 10, 2, 2, 13, 8, 6, 6, 15, 8, 2, 6, 6, 16, 6, 4, 8, 16, 2, 4, 8, 0, 9, 9, 8, 3, 9, 3, 18, 17, 1, 3, 18, 18, 1, 1, 18, 17, 1, 3, 18, 18, 1, 1, 7, 10, 3, 3, 8, 10, 1, 3, 9, 14, 2, 2, 9, 14, 1, 1, 10, 15, 1, 1, 9, 14, 2, 2, 9, 14, 1, 1, 10, 15, 1, 1, 0, 8, 19, 12, 0, 14, 19, 6, 7, 6, 9, 14, 10, 6, 3, 14, 13, 8, 3, 4, 14, 8, 1, 4, 4, 17, 1, 3, 4, 18, 1, 1, 4, 9, 6, 3, 6, 9, 2, 3, 2, 18, 5, 2, 2, 19, 5, 1, 7, 8, 2, 2, 7, 8, 1, 1, 8, 9, 1, 1, 7, 8, 2, 2, 7, 8, 1, 1, 8, 9, 1, 1, 5, 10, 13, 2, 5, 11, 13, 1, 10, 8, 1, 9, 10, 11, 1, 3, 15, 8, 2, 12, 15, 8, 1, 6, 16, 14, 1, 6, 4, 0, 3, 5, 5, 0, 1, 5, 12, 6, 3, 7, 13, 6, 1, 7, 7, 16, 6, 4, 9, 16, 2, 4, 9, 16, 2, 1, 10, 16, 1, 1, 6, 10, 9, 2, 9, 10, 3, 2, 0, 6, 15, 14, 0, 13, 15, 7, 9, 1, 5, 6, 9, 3, 5, 2, 3, 9, 3, 4, 4, 9, 1, 4, 5, 7, 3, 6, 6, 7, 1, 6, 17, 16, 1, 2, 17, 17, 1, 1, 9, 8, 6, 12, 11, 8, 2, 12, 6, 10, 6, 1, 8, 10, 2, 1, 7, 17, 9, 3, 10, 17, 3, 3, 14, 18, 6, 2, 14, 19, 6, 1, 9, 5, 3, 14, 10, 5, 1, 14, 8, 16, 9, 4, 11, 16, 3, 4, 0, 0, 4, 14, 0, 7, 4, 7, 8, 1, 6, 3, 10, 1, 2, 3, 6, 8, 3, 4, 7, 8, 1, 4, 4, 8, 3, 4, 5, 8, 1, 4, 5, 1, 6, 5, 7, 1, 2, 5, 1, 18, 1, 2, 1, 19, 1, 1, 7, 0, 6, 6, 7, 2, 6, 2, 0, 18, 4, 2, 0, 19, 4, 1, 12, 3, 8, 12, 12, 7, 8, 4, 12, 9, 3, 4, 13, 9, 1, 4, 12, 8, 3, 5, 13, 8, 1, 5, 16, 0, 2, 1, 17, 0, 1, 1, 5, 17, 1, 3, 5, 18, 1, 1, 10, 2, 3, 6, 10, 4, 3, 2, 4, 17, 2, 3, 4, 18, 2, 1, 12, 7, 1, 9, 12, 10, 1, 3, 7, 6, 3, 9, 8, 6, 1, 9, 17, 13, 3, 6, 17, 15, 3, 2, 7, 7, 3, 8, 8, 7, 1, 8, 5, 0, 3, 5, 6, 0, 1, 5, 4, 6, 9, 8, 7, 6, 3, 8, 2, 9, 3, 3, 3, 9, 1, 3, 16, 18, 4, 2, 16, 19, 4, 1, 17, 10, 3, 10, 17, 15, 3, 5, 8, 9, 6, 4, 10, 9, 2, 4, 5, 2, 10, 12, 5, 6, 10, 4, 6, 9, 6, 3, 8, 9, 2, 3, 11, 7, 3, 7, 12, 7, 1, 7, 12, 8, 6, 4, 14, 8, 2, 4, 14, 8, 6, 5, 16, 8, 2, 5, 12, 12, 2, 4, 12, 14, 2, 2, 3, 15, 1, 2, 3, 16, 1, 1, 12, 7, 3, 4, 13, 7, 1, 4, 10, 0, 6, 6, 12, 0, 2, 6, 10, 6, 3, 8, 11, 6, 1, 8, 16, 17, 1, 2, 16, 18, 1, 1, 16, 16, 1, 3, 16, 17, 1, 1, 11, 11, 1, 2, 11, 12, 1, 1, 3, 7, 6, 9, 5, 7, 2, 9, 4, 18, 9, 1, 7, 18, 3, 1, 0, 11, 4, 9, 0, 14, 4, 3, 9, 17, 6, 3, 11, 17, 2, 3, 7, 8, 6, 12, 9, 8, 2, 12, 6, 8, 3, 4, 7, 8, 1, 4, 3, 17, 1, 3, 3, 18, 1, 1, 11, 9, 6, 4, 13, 9, 2, 4, 6, 1, 3, 2, 7, 1, 1, 2, 1, 0, 2, 1, 2, 0, 1, 1, 1, 0, 2, 14, 1, 0, 1, 7, 2, 7, 1, 7, 5, 5, 11, 8, 5, 9, 11, 4, 9, 3, 5, 6, 9, 5, 5, 2, 7, 9, 5, 10, 7, 14, 5, 5, 15, 10, 2, 2, 16, 10, 1, 2, 0, 18, 8, 2, 0, 19, 8, 1, 7, 17, 1, 3, 7, 18, 1, 1, 7, 2, 11, 6, 7, 4, 11, 2, 8, 3, 9, 3, 8, 4, 9, 1, 0, 9, 2, 2, 0, 10, 2, 1, 0, 5, 3, 6, 0, 7, 3, 2, 6, 7, 2, 2, 6, 7, 1, 1, 7, 8, 1, 1, 7, 6, 3, 6, 8, 6, 1, 6, 12, 1, 6, 4, 14, 1, 2, 4, 9, 11, 6, 8, 11, 11, 2, 8, 17, 15, 3, 3, 17, 16, 3, 1, 6, 6, 3, 9, 6, 9, 3, 3, 0, 5, 8, 6, 0, 5, 4, 3, 4, 8, 4, 3, 0, 6, 1, 3, 0, 7, 1, 1, 17, 0, 2, 6, 18, 0, 1, 6, 10, 17, 6, 3, 12, 17, 2, 3, 13, 15, 2, 2, 13, 15, 1, 1, 14, 16, 1, 1, 4, 0, 12, 3, 4, 1, 12, 1, 5, 3, 10, 9, 5, 6, 10, 3, 7, 7, 9, 7, 10, 7, 3, 7, 5, 8, 9, 6, 8, 8, 3, 6, 0, 16, 6, 2, 0, 17, 6, 1, 12, 6, 7, 14, 12, 13, 7, 7, 13, 7, 6, 8, 15, 7, 2, 8, 2, 10, 6, 3, 4, 10, 2, 3, 18, 17, 1, 3, 18, 18, 1, 1, 7, 1, 6, 2, 7, 2, 6, 1, 6, 0, 6, 4, 6, 2, 6, 2, 8, 18, 6, 2, 10, 18, 2, 2, 7, 6, 5, 2, 7, 7, 5, 1, 6, 7, 3, 6, 7, 7, 1, 6, 18, 18, 2, 2, 18, 18, 1, 1, 19, 19, 1, 1, 16, 8, 3, 7, 17, 8, 1, 7, 0, 16, 2, 3, 0, 17, 2, 1, 5, 19, 6, 1, 7, 19, 2, 1, 9, 5, 6, 6, 9, 7, 6, 2, 0, 10, 2, 4, 0, 12, 2, 2, 0, 9, 4, 3, 2, 9, 2, 3, 1, 10, 6, 9, 3, 10, 2, 9, 9, 0, 6, 2, 11, 0, 2, 2, 14, 1, 2, 1, 15, 1, 1, 1, 0, 8, 1, 4, 0, 10, 1, 2, 15, 6, 2, 2, 15, 6, 1, 1, 16, 7, 1, 1, 7, 5, 3, 6, 8, 5, 1, 6, 19, 17, 1, 3, 19, 18, 1, 1, 7, 10, 3, 1, 8, 10, 1, 1, 12, 1, 6, 6, 14, 1, 2, 6, 15, 5, 2, 1, 16, 5, 1, 1, 8, 2, 7, 4, 8, 4, 7, 2, 4, 0, 14, 15, 4, 5, 14, 5, 7, 8, 6, 6, 9, 8, 2, 6, 11, 17, 1, 3, 11, 18, 1, 1, 12, 16, 2, 4, 12, 16, 1, 2, 13, 18, 1, 2, 10, 13, 2, 1, 11, 13, 1, 1, 11, 8, 3, 3, 12, 8, 1, 3, 2, 0, 6, 8, 4, 0, 2, 8, 3, 5, 6, 6, 3, 5, 3, 3, 6, 8, 3, 3, 10, 8, 3, 3, 11, 8, 1, 3, 5, 17, 4, 2, 5, 18, 4, 1, 8, 16, 5, 2, 8, 17, 5, 1, 0, 4, 3, 3, 0, 5, 3, 1, 6, 3, 6, 2, 8, 3, 2, 2, 4, 4, 9, 3, 7, 4, 3, 3, 0, 13, 1, 4, 0, 15, 1, 2, 0, 17, 8, 3, 0, 18, 8, 1, 6, 1, 11, 6, 6, 3, 11, 2, 4, 10, 6, 2, 6, 10, 2, 2, 10, 8, 1, 12, 10, 14, 1, 6, 5, 8, 3, 4, 6, 8, 1, 4, 0, 17, 1, 3, 0, 18, 1, 1, 0, 17, 1, 3, 0, 18, 1, 1, 13, 8, 3, 4, 14, 8, 1, 4, 1, 5, 5, 4, 1, 7, 5, 2, 18, 14, 1, 2, 18, 15, 1, 1, 13, 8, 2, 4, 14, 8, 1, 4, 10, 6, 6, 8, 12, 6, 2, 8, 8, 6, 6, 10, 10, 6, 2, 10, 17, 16, 1, 3, 17, 17, 1, 1, 1, 7, 2, 10, 2, 7, 1, 10, 5, 9, 6, 3, 7, 9, 2, 3, 0, 8, 5, 12, 0, 14, 5, 6, 0, 11, 1, 3, 0, 12, 1, 1, 6, 16, 6, 4, 8, 16, 2, 4, 0, 6, 2, 6, 0, 8, 2, 2, 11, 18, 2, 1, 12, 18, 1, 1, 5, 1, 9, 2, 5, 2, 9, 1, 0, 0, 1, 2, 0, 1, 1, 1, 15, 9, 3, 3, 16, 9, 1, 3, 18, 16, 1, 3, 18, 17, 1, 1, 11, 10, 6, 1, 13, 10, 2, 1, 1, 3, 4, 4, 3, 3, 2, 4, 11, 2, 1, 18, 11, 8, 1, 6, 9, 1, 5, 12, 9, 5, 5, 4, 12, 0, 8, 1, 16, 0, 4, 1, 8, 6, 3, 10, 9, 6, 1, 10, 19, 2, 1, 6, 19, 4, 1, 2, 18, 6, 2, 2, 18, 7, 2, 1, 7, 7, 3, 4, 8, 7, 1, 4, 5, 0, 6, 5, 7, 0, 2, 5, 0, 3, 7, 3, 0, 4, 7, 1, 1, 6, 2, 1, 2, 6, 1, 1, 4, 8, 2, 10, 4, 8, 1, 5, 5, 13, 1, 5, 2, 18, 18, 2, 2, 18, 9, 1, 11, 19, 9, 1, 2, 7, 4, 4, 2, 7, 2, 2, 4, 9, 2, 2, 17, 3, 3, 4, 18, 3, 1, 4, 16, 9, 2, 8, 16, 9, 1, 4, 17, 13, 1, 4, 15, 7, 1, 6, 15, 9, 1, 2, 14, 2, 2, 2, 14, 3, 2, 1, 17, 0, 2, 3, 17, 1, 2, 1, 16, 18, 2, 2, 16, 18, 1, 1, 17, 19, 1, 1, 10, 4, 4, 3, 10, 5, 4, 1, 0, 2, 8, 6, 4, 2, 4, 6, 7, 14, 6, 6, 7, 16, 6, 2, 11, 15, 2, 2, 11, 16, 2, 1, 7, 1, 9, 4, 10, 1, 3, 4, 9, 7, 3, 7, 10, 7, 1, 7, 6, 17, 2, 2, 6, 17, 1, 1, 7, 18, 1, 1, 4, 6, 3, 9, 5, 6, 1, 9, 0, 10, 19, 10, 0, 15, 19, 5, 5, 17, 6, 1, 7, 17, 2, 1, 0, 12, 6, 3, 3, 12, 3, 3, 2, 5, 18, 5, 8, 5, 6, 5, 1, 15, 6, 4, 1, 17, 6, 2, 14, 10, 6, 6, 16, 10, 2, 6, 0, 14, 4, 3, 0, 15, 4, 1, 1, 7, 6, 11, 3, 7, 2, 11, 13, 17, 7, 2, 13, 18, 7, 1, 0, 14, 2, 3, 0, 15, 2, 1, 0, 0, 6, 2, 3, 0, 3, 2, 0, 1, 6, 3, 3, 1, 3, 3, 0, 8, 2, 6, 0, 10, 2, 2, 1, 2, 6, 14, 1, 2, 3, 7, 4, 9, 3, 7, 17, 5, 2, 2, 17, 5, 1, 1, 18, 6, 1, 1, 11, 10, 9, 4, 14, 10, 3, 4, 2, 9, 12, 4, 6, 9, 4, 4, 7, 10, 12, 2, 11, 10, 4, 2, 2, 13, 1, 2, 2, 14, 1, 1, 16, 7, 4, 3, 16, 8, 4, 1, 19, 16, 1, 3, 19, 17, 1, 1, 18, 11, 1, 2, 18, 12, 1, 1, 12, 7, 8, 2, 12, 7, 4, 1, 16, 8, 4, 1, 14, 9, 2, 4, 15, 9, 1, 4, 14, 2, 6, 4, 14, 2, 3, 2, 17, 4, 3, 2, 14, 0, 6, 1, 17, 0, 3, 1, 3, 12, 2, 1, 4, 12, 1, 1, 17, 2, 3, 1, 18, 2, 1, 1, 1, 16, 18, 2, 7, 16, 6, 2, 2, 19, 8, 1, 6, 19, 4, 1, 1, 17, 4, 3, 1, 18, 4, 1, 19, 13, 1, 2, 19, 14, 1, 1, 9, 16, 10, 4, 9, 16, 5, 2, 14, 18, 5, 2, 12, 9, 2, 4, 12, 9, 1, 2, 13, 11, 1, 2, 19, 11, 1, 9, 19, 14, 1, 3, 6, 6, 14, 14, 6, 13, 14, 7, 2, 17, 4, 2, 2, 18, 4, 1, 0, 2, 1, 3, 0, 3, 1, 1, 0, 12, 1, 3, 0, 13, 1, 1, 15, 15, 4, 4, 15, 17, 4, 2, 2, 5, 18, 7, 8, 5, 6, 7, 1, 16, 5, 3, 1, 17, 5, 1, 0, 4, 2, 3, 0, 5, 2, 1, 0, 6, 2, 6, 1, 6, 1, 6, 16, 14, 4, 3, 16, 15, 4, 1, 0, 0, 10, 6, 0, 0, 5, 3, 5, 3, 5, 3, 2, 2, 3, 6, 3, 2, 1, 6, 2, 0, 3, 10, 3, 0, 1, 10, 5, 5, 2, 2, 5, 6, 2, 1, 12, 6, 4, 4, 12, 8, 4, 2, 13, 5, 7, 3, 13, 6, 7, 1, 10, 13, 1, 2, 10, 14, 1, 1, 16, 16, 4, 2, 18, 16, 2, 2, 16, 12, 4, 7, 18, 12, 2, 7, 16, 17, 1, 3, 16, 18, 1, 1, 19, 9, 1, 3, 19, 10, 1, 1, 18, 7, 2, 6, 19, 7, 1, 6, 8, 1, 3, 4, 9, 1, 1, 4, 14, 0, 6, 9, 16, 0, 2, 9, 4, 2, 10, 2, 9, 2, 5, 2, 2, 12, 8, 4, 2, 12, 4, 2, 6, 14, 4, 2, 0, 4, 7, 3, 0, 5, 7, 1, 14, 14, 3, 3, 15, 14, 1, 3, 0, 3, 4, 3, 2, 3, 2, 3, 1, 0, 2, 7, 2, 0, 1, 7, 15, 16, 4, 4, 15, 18, 4, 2, 5, 8, 12, 4, 5, 10, 12, 2, 3, 17, 1, 2, 3, 18, 1, 1, 6, 1, 3, 4, 7, 1, 1, 4, 6, 2, 3, 4, 7, 2, 1, 4, 6, 8, 9, 12, 9, 8, 3, 12, 8, 1, 8, 6, 8, 3, 8, 2, 14, 2, 6, 3, 17, 2, 3, 3, 0, 6, 1, 3, 0, 7, 1, 1, 10, 0, 10, 2, 15, 0, 5, 2, 11, 0, 3, 2, 12, 0, 1, 2, 3, 19, 10, 1, 8, 19, 5, 1, 0, 4, 7, 16, 0, 12, 7, 8, 2, 16, 1, 3, 2, 17, 1, 1, 7, 8, 12, 6, 11, 8, 4, 6, 14, 9, 6, 7, 16, 9, 2, 7, 12, 17, 6, 1, 14, 17, 2, 1, 16, 1, 3, 1, 17, 1, 1, 1, 0, 17, 8, 2, 0, 17, 4, 1, 4, 18, 4, 1, 17, 0, 2, 1, 18, 0, 1, 1, 4, 15, 6, 5, 6, 15, 2, 5, 7, 2, 8, 2, 7, 3, 8, 1, 4, 1, 8, 4, 4, 3, 8, 2, 5, 19, 2, 1, 6, 19, 1, 1, 5, 19, 2, 1, 6, 19, 1, 1, 16, 17, 1, 3, 16, 18, 1, 1, 0, 11, 2, 3, 1, 11, 1, 3, 0, 19, 4, 1, 2, 19, 2, 1, 0, 18, 4, 2, 2, 18, 2, 2, 2, 17, 1, 3, 2, 18, 1, 1, 5, 7, 11, 2, 5, 8, 11, 1, 9, 2, 4, 10, 9, 7, 4, 5, 0, 2, 4, 3, 0, 3, 4, 1, 10, 19, 10, 1, 15, 19, 5, 1, 11, 17, 8, 3, 15, 17, 4, 3, 8, 19, 3, 1, 9, 19, 1, 1, 14, 0, 3, 4, 15, 0, 1, 4, 10, 6, 4, 3, 10, 7, 4, 1, 0, 8, 3, 2, 0, 9, 3, 1, 7, 12, 3, 6, 7, 14, 3, 2, 1, 18, 1, 2, 1, 19, 1, 1, 0, 12, 4, 4, 2, 12, 2, 4, 1, 8, 6, 7, 3, 8, 2, 7, 0, 8, 4, 5, 2, 8, 2, 5, 19, 16, 1, 3, 19, 17, 1, 1, 1, 5, 18, 6, 7, 5, 6, 6, 2, 15, 4, 2, 2, 16, 4, 1, 18, 6, 2, 11, 19, 6, 1, 11, 0, 12, 2, 6, 0, 14, 2, 2, 12, 5, 3, 2, 12, 6, 3, 1, 1, 3, 2, 3, 1, 4, 2, 1, 16, 14, 4, 4, 16, 16, 4, 2, 6, 8, 12, 5, 10, 8, 4, 5, 13, 7, 2, 7, 14, 7, 1, 7, 1, 8, 2, 6, 2, 8, 1, 6, 15, 0, 3, 7, 16, 0, 1, 7, 4, 2, 6, 2, 6, 2, 2, 2, 0, 9, 20, 9, 0, 12, 20, 3, 10, 14, 2, 2, 10, 15, 2, 1, 6, 5, 10, 4, 6, 7, 10, 2, 6, 1, 5, 9, 6, 4, 5, 3, 16, 18, 2, 2, 16, 18, 1, 1, 17, 19, 1, 1, 0, 14, 2, 4, 0, 16, 2, 2, 10, 8, 2, 5, 11, 8, 1, 5, 3, 7, 12, 7, 7, 7, 4, 7, 0, 0, 6, 6, 3, 0, 3, 6, 1, 0, 4, 4, 3, 0, 2, 4, 0, 0, 6, 8, 2, 0, 2, 8, 0, 0, 2, 1, 1, 0, 1, 1, 0, 0, 3, 3, 0, 1, 3, 1, 5, 4, 2, 4, 5, 6, 2, 2, 2, 10, 9, 1, 5, 10, 3, 1, 1, 17, 1, 3, 1, 18, 1, 1, 0, 17, 2, 3, 0, 18, 2, 1, 0, 15, 16, 3, 8, 15, 8, 3, 0, 5, 4, 1, 2, 5, 2, 1, 1, 0, 6, 20, 3, 0, 2, 20, 2, 5, 4, 6, 2, 5, 2, 3, 4, 8, 2, 3, 9, 16, 6, 3, 11, 16, 2, 3, 11, 17, 6, 1, 14, 17, 3, 1, 3, 17, 15, 2, 8, 17, 5, 2, 18, 0, 2, 3, 18, 1, 2, 1, 13, 1, 7, 4, 13, 3, 7, 2, 13, 6, 4, 4, 13, 6, 2, 2, 15, 8, 2, 2, 17, 6, 3, 4, 17, 8, 3, 2, 14, 9, 2, 2, 15, 9, 1, 2, 17, 17, 1, 3, 17, 18, 1, 1, 3, 19, 8, 1, 7, 19, 4, 1, 0, 9, 3, 6, 0, 12, 3, 3, 4, 7, 15, 5, 9, 7, 5, 5, 6, 9, 9, 5, 9, 9, 3, 5, 8, 1, 6, 2, 10, 1, 2, 2, 4, 0, 12, 2, 10, 0, 6, 2, 7, 0, 10, 3, 12, 0, 5, 3, 5, 0, 9, 6, 5, 2, 9, 2, 8, 3, 6, 4, 8, 5, 6, 2, 17, 4, 2, 3, 17, 5, 2, 1, 5, 2, 4, 3, 5, 3, 4, 1, 5, 9, 2, 6, 6, 9, 1, 6, 14, 10, 2, 6, 15, 10, 1, 6, 7, 4, 3, 3, 7, 5, 3, 1, 12, 4, 8, 2, 12, 4, 4, 1, 16, 5, 4, 1, 15, 8, 1, 6, 15, 10, 1, 2, 4, 17, 11, 3, 4, 18, 11, 1, 3, 0, 16, 20, 3, 10, 16, 10, 12, 4, 4, 6, 12, 6, 4, 2, 11, 0, 6, 6, 13, 0, 2, 6, 13, 1, 6, 4, 13, 1, 3, 2, 16, 3, 3, 2, 11, 0, 6, 4, 13, 0, 2, 4, 8, 6, 6, 9, 10, 6, 2, 9, 7, 0, 3, 4, 8, 0, 1, 4, 0, 17, 14, 2, 0, 17, 7, 1, 7, 18, 7, 1, 6, 18, 2, 2, 6, 18, 1, 1, 7, 19, 1, 1, 18, 17, 1, 3, 18, 18, 1, 1, 17, 18, 2, 2, 17, 18, 1, 1, 18, 19, 1, 1, 5, 7, 1, 9, 5, 10, 1, 3, 5, 3, 6, 4, 7, 3, 2, 4, 1, 9, 6, 2, 1, 9, 3, 1, 4, 10, 3, 1, 6, 9, 2, 3, 7, 9, 1, 3, 6, 8, 6, 12, 8, 8, 2, 12, 4, 18, 2, 2, 4, 18, 1, 1, 5, 19, 1, 1, 9, 1, 6, 6, 9, 3, 6, 2, 6, 17, 6, 2, 6, 18, 6, 1, 3, 18, 16, 2, 3, 19, 16, 1, 3, 0, 3, 11, 4, 0, 1, 11, 13, 18, 3, 1, 14, 18, 1, 1, 6, 0, 9, 6, 6, 2, 9, 2, 1, 2, 12, 4, 1, 2, 6, 2, 7, 4, 6, 2, 3, 3, 6, 4, 5, 3, 2, 4, 12, 0, 8, 1, 16, 0, 4, 1, 9, 0, 6, 2, 11, 0, 2, 2, 3, 3, 12, 1, 9, 3, 6, 1, 2, 7, 6, 2, 2, 7, 3, 1, 5, 8, 3, 1, 0, 8, 4, 6, 0, 10, 4, 2, 9, 6, 3, 7, 10, 6, 1, 7, 9, 6, 6, 13, 11, 6, 2, 13, 11, 12, 6, 1, 13, 12, 2, 1, 18, 9, 2, 6, 18, 12, 2, 3, 17, 2, 3, 9, 18, 2, 1, 9, 13, 8, 4, 6, 13, 8, 2, 3, 15, 11, 2, 3, 4, 2, 12, 6, 10, 2, 6, 6, 4, 14, 16, 6, 12, 14, 8, 6, 6, 19, 10, 1, 11, 19, 5, 1, 6, 17, 1, 3, 6, 18, 1, 1, 4, 14, 10, 3, 4, 15, 10, 1, 6, 0, 12, 12, 6, 4, 12, 4, 5, 7, 4, 2, 5, 7, 2, 1, 7, 8, 2, 1, 17, 5, 3, 2, 18, 5, 1, 2, 8, 13, 6, 3, 8, 14, 6, 1, 8, 13, 5, 3, 8, 14, 5, 1, 13, 2, 1, 18, 13, 11, 1, 9, 6, 10, 9, 2, 9, 10, 3, 2, 11, 0, 7, 4, 11, 2, 7, 2, 1, 0, 6, 8, 3, 0, 2, 8, 9, 15, 3, 3, 9, 16, 3, 1, 9, 17, 9, 3, 9, 18, 9, 1, 12, 12, 3, 3, 12, 13, 3, 1, 4, 1, 3, 5, 5, 1, 1, 5, 10, 14, 2, 3, 10, 15, 2, 1, 18, 17, 2, 2, 18, 17, 1, 1, 19, 18, 1, 1, 18, 18, 2, 2, 18, 18, 1, 1, 19, 19, 1, 1, 18, 18, 2, 2, 18, 18, 1, 1, 19, 19, 1, 1, 4, 10, 9, 1, 7, 10, 3, 1, 3, 9, 6, 5, 5, 9, 2, 5, 18, 8, 1, 12, 18, 14, 1, 6, 0, 2, 8, 6, 0, 2, 4, 3, 4, 5, 4, 3, 9, 4, 3, 3, 9, 5, 3, 1, 3, 18, 2, 2, 3, 18, 1, 1, 4, 19, 1, 1, 6, 4, 4, 3, 6, 5, 4, 1, 16, 7, 4, 2, 16, 7, 2, 1, 18, 8, 2, 1, 5, 17, 1, 3, 5, 18, 1, 1, 2, 0, 15, 20, 2, 10, 15, 10, 8, 11, 6, 4, 8, 11, 3, 2, 11, 13, 3, 2, 8, 16, 4, 3, 8, 17, 4, 1, 8, 18, 2, 2, 8, 18, 1, 1, 9, 19, 1, 1, 2, 16, 13, 3, 2, 17, 13, 1, 16, 16, 2, 2, 16, 16, 1, 1, 17, 17, 1, 1, 8, 1, 6, 3, 10, 1, 2, 3, 16, 7, 2, 2, 16, 7, 1, 1, 17, 8, 1, 1, 14, 7, 4, 2, 14, 7, 2, 1, 16, 8, 2, 1, 4, 0, 14, 1, 11, 0, 7, 1, 10, 4, 8, 2, 10, 4, 4, 1, 14, 5, 4, 1, 8, 2, 3, 2, 9, 2, 1, 2, 12, 11, 6, 3, 12, 12, 6, 1, 1, 5, 1, 4, 1, 7, 1, 2, 1, 1, 1, 18, 1, 7, 1, 6, 11, 13, 3, 2, 11, 14, 3, 1, 0, 1, 12, 2, 0, 1, 6, 1, 6, 2, 6, 1, 10, 18, 2, 2, 10, 18, 1, 1, 11, 19, 1, 1, 4, 5, 4, 4, 4, 5, 2, 2, 6, 7, 2, 2, 6, 7, 1, 3, 6, 8, 1, 1, 14, 10, 6, 2, 16, 10, 2, 2, 16, 8, 3, 6, 17, 8, 1, 6, 4, 10, 6, 2, 6, 10, 2, 2, 6, 5, 3, 7, 7, 5, 1, 7, 0, 13, 6, 6, 0, 16, 6, 3, 12, 5, 1, 9, 12, 8, 1, 3, 5, 9, 3, 3, 6, 9, 1, 3, 7, 5, 6, 13, 9, 5, 2, 13, 19, 8, 1, 10, 19, 13, 1, 5, 11, 18, 6, 1, 13, 18, 2, 1, 9, 7, 6, 12, 11, 7, 2, 12, 12, 7, 6, 6, 14, 7, 2, 6, 15, 8, 3, 4, 16, 8, 1, 4, 6, 11, 4, 2, 6, 12, 4, 1, 1, 6, 6, 8, 3, 6, 2, 8, 11, 15, 6, 5, 13, 15, 2, 5, 15, 17, 4, 2, 15, 18, 4, 1, 13, 11, 6, 1, 15, 11, 2, 1, 5, 18, 2, 2, 5, 18, 1, 1, 6, 19, 1, 1, 4, 8, 4, 4, 4, 8, 2, 2, 6, 10, 2, 2, 11, 7, 9, 3, 11, 8, 9, 1, 0, 3, 10, 4, 0, 3, 5, 2, 5, 5, 5, 2, 7, 18, 6, 1, 9, 18, 2, 1, 0, 8, 3, 3, 0, 9, 3, 1, 0, 0, 6, 8, 0, 0, 3, 4, 3, 4, 3, 4, 7, 6, 3, 8, 8, 6, 1, 8, 13, 7, 7, 3, 13, 8, 7, 1, 3, 3, 2, 2, 3, 4, 2, 1, 0, 3, 3, 3, 0, 4, 3, 1, 9, 3, 5, 2, 9, 4, 5, 1, 6, 5, 9, 4, 9, 5, 3, 4, 3, 10, 12, 3, 7, 10, 4, 3, 8, 7, 3, 6, 9, 7, 1, 6, 5, 5, 6, 5, 8, 5, 3, 5, 0, 5, 2, 3, 0, 6, 2, 1, 9, 7, 3, 4, 10, 7, 1, 4, 1, 0, 6, 15, 3, 0, 2, 15, 15, 1, 3, 5, 16, 1, 1, 5, 9, 2, 3, 10, 10, 2, 1, 10, 8, 8, 6, 12, 10, 8, 2, 12, 16, 4, 3, 4, 16, 6, 3, 2, 16, 7, 2, 2, 16, 7, 1, 1, 17, 8, 1, 1, 13, 0, 6, 9, 13, 3, 6, 3, 7, 17, 1, 3, 7, 18, 1, 1, 12, 1, 4, 2, 12, 2, 4, 1, 17, 3, 1, 3, 17, 4, 1, 1, 0, 16, 9, 3, 0, 17, 9, 1, 3, 6, 2, 4, 3, 6, 1, 2, 4, 8, 1, 2, 13, 18, 3, 1, 14, 18, 1, 1, 0, 18, 4, 2, 2, 18, 2, 2, 1, 19, 2, 1, 2, 19, 1, 1, 0, 18, 4, 2, 0, 19, 4, 1, 2, 17, 1, 3, 2, 18, 1, 1, 4, 8, 3, 5, 5, 8, 1, 5, 2, 1, 6, 7, 4, 1, 2, 7, 3, 6, 2, 8, 3, 6, 1, 4, 4, 10, 1, 4, 4, 5, 11, 10, 4, 10, 11, 5, 0, 13, 20, 2, 10, 13, 10, 2, 1, 13, 16, 3, 9, 13, 8, 3, 16, 4, 4, 4, 16, 4, 2, 2, 18, 6, 2, 2, 16, 0, 4, 12, 16, 0, 2, 6, 18, 6, 2, 6, 14, 15, 3, 1, 15, 15, 1, 1, 3, 4, 12, 10, 3, 9, 12, 5, 9, 18, 2, 2, 9, 18, 1, 1, 10, 19, 1, 1, 9, 18, 2, 2, 9, 18, 1, 1, 10, 19, 1, 1, 13, 4, 2, 14, 13, 4, 1, 7, 14, 11, 1, 7, 4, 2, 6, 4, 7, 2, 3, 4, 0, 0, 18, 20, 0, 0, 9, 10, 9, 10, 9, 10, 15, 11, 1, 2, 15, 12, 1, 1, 16, 10, 2, 4, 16, 10, 1, 2, 17, 12, 1, 2, 18, 17, 2, 2, 18, 17, 1, 1, 19, 18, 1, 1, 9, 17, 1, 2, 9, 18, 1, 1, 8, 4, 9, 6, 11, 4, 3, 6, 6, 9, 9, 10, 9, 9, 3, 10, 5, 0, 5, 4, 5, 2, 5, 2, 5, 7, 11, 4, 5, 9, 11, 2, 2, 4, 2, 14, 3, 4, 1, 14, 8, 6, 3, 5, 9, 6, 1, 5, 8, 4, 3, 9, 9, 4, 1, 9, 0, 8, 20, 6, 0, 10, 20, 2, 14, 16, 6, 1, 17, 16, 3, 1, 17, 18, 2, 2, 17, 19, 2, 1, 8, 17, 6, 3, 10, 17, 2, 3, 4, 1, 9, 15, 7, 1, 3, 15, 11, 5, 3, 12, 12, 5, 1, 12, 0, 15, 4, 3, 0, 16, 4, 1, 0, 0, 15, 1, 5, 0, 5, 1, 6, 0, 6, 4, 8, 0, 2, 4, 2, 0, 9, 3, 5, 0, 3, 3, 13, 6, 3, 7, 14, 6, 1, 7, 7, 6, 4, 2, 7, 7, 4, 1, 6, 18, 6, 1, 8, 18, 2, 1, 18, 6, 2, 2, 18, 7, 2, 1, 6, 4, 7, 3, 6, 5, 7, 1, 12, 7, 3, 1, 13, 7, 1, 1, 15, 1, 2, 10, 15, 1, 1, 5, 16, 6, 1, 5, 0, 18, 2, 2, 0, 19, 2, 1, 19, 4, 1, 8, 19, 8, 1, 4, 1, 17, 1, 3, 1, 18, 1, 1, 0, 15, 6, 4, 0, 15, 3, 2, 3, 17, 3, 2, 19, 0, 1, 18, 19, 6, 1, 6, 10, 2, 6, 2, 12, 2, 2, 2, 2, 8, 12, 2, 6, 8, 4, 2, 16, 0, 4, 1, 18, 0, 2, 1, 8, 4, 2, 6, 8, 7, 2, 3, 14, 5, 2, 10, 15, 5, 1, 10, 13, 4, 2, 2, 13, 5, 2, 1, 11, 1, 3, 6, 11, 3, 3, 2, 6, 9, 12, 2, 10, 9, 4, 2, 9, 16, 4, 2, 9, 17, 4, 1, 5, 14, 15, 4, 5, 16, 15, 2, 18, 16, 2, 2, 18, 17, 2, 1, 16, 18, 2, 2, 16, 18, 1, 1, 17, 19, 1, 1, 6, 4, 3, 8, 7, 4, 1, 8, 5, 9, 3, 1, 6, 9, 1, 1, 0, 8, 1, 6, 0, 10, 1, 2, 11, 2, 9, 6, 14, 2, 3, 6, 12, 2, 6, 4, 14, 2, 2, 4, 1, 7, 2, 4, 1, 9, 2, 2, 13, 1, 6, 4, 13, 3, 6, 2, 4, 10, 2, 10, 4, 10, 1, 5, 5, 15, 1, 5, 2, 16, 9, 3, 5, 16, 3, 3, 1, 2, 3, 9, 2, 2, 1, 9, 19, 7, 1, 4, 19, 9, 1, 2, 14, 11, 6, 8, 14, 11, 3, 4, 17, 15, 3, 4, 15, 12, 4, 6, 15, 12, 2, 3, 17, 15, 2, 3, 16, 15, 2, 2, 16, 15, 1, 1, 17, 16, 1, 1, 17, 16, 2, 2, 17, 16, 1, 1, 18, 17, 1, 1, 17, 16, 2, 2, 17, 16, 1, 1, 18, 17, 1, 1, 2, 3, 2, 2, 2, 3, 1, 1, 3, 4, 1, 1, 10, 10, 3, 3, 11, 10, 1, 3, 5, 9, 7, 8, 5, 13, 7, 4, 7, 16, 2, 2, 7, 16, 1, 1, 8, 17, 1, 1, 7, 16, 2, 2, 7, 16, 1, 1, 8, 17, 1, 1, 9, 8, 10, 3, 14, 8, 5, 3, 6, 7, 4, 8, 6, 7, 2, 4, 8, 11, 2, 4, 1, 6, 4, 3, 1, 7, 4, 1, 6, 10, 6, 10, 8, 10, 2, 10, 4, 6, 3, 6, 5, 6, 1, 6, 3, 10, 4, 4, 3, 10, 2, 2, 5, 12, 2, 2, 3, 10, 4, 4, 3, 10, 2, 2, 5, 12, 2, 2, 3, 10, 4, 4, 3, 10, 2, 2, 5, 12, 2, 2, 14, 8, 2, 6, 15, 8, 1, 6, 3, 10, 4, 4, 3, 10, 2, 2, 5, 12, 2, 2, 3, 10, 4, 4, 3, 10, 2, 2, 5, 12, 2, 2, 12, 4, 3, 9, 13, 4, 1, 9, 12, 3, 1, 12, 12, 7, 1, 4, 2, 0, 18, 1, 8, 0, 6, 1, 10, 0, 10, 6, 10, 0, 5, 3, 15, 3, 5, 3, 18, 16, 2, 2, 18, 17, 2, 1, 3, 5, 4, 2, 3, 5, 2, 1, 5, 6, 2, 1, 11, 8, 3, 3, 12, 8, 1, 3, 11, 7, 3, 5, 12, 7, 1, 5, 3, 19, 15, 1, 8, 19, 5, 1, 8, 13, 3, 2, 8, 14, 3, 1, 2, 12, 8, 4, 2, 12, 4, 2, 6, 14, 4, 2, 16, 16, 2, 2, 16, 16, 1, 1, 17, 17, 1, 1, 7, 0, 3, 2, 8, 0, 1, 2, 6, 7, 2, 5, 7, 7, 1, 5, 18, 0, 2, 17, 19, 0, 1, 17, 16, 16, 1, 3, 16, 17, 1, 1, 14, 8, 3, 7, 15, 8, 1, 7, 10, 17, 2, 2, 10, 17, 1, 1, 11, 18, 1, 1, 4, 9, 1, 3, 4, 10, 1, 1, 18, 10, 2, 3, 18, 11, 2, 1, 12, 1, 3, 10, 13, 1, 1, 10, 8, 12, 9, 1, 11, 12, 3, 1, 5, 18, 2, 2, 5, 18, 1, 1, 6, 19, 1, 1, 19, 6, 1, 9, 19, 9, 1, 3, 4, 7, 2, 4, 4, 7, 1, 2, 5, 9, 1, 2, 1, 4, 6, 14, 3, 4, 2, 14, 10, 5, 9, 3, 13, 5, 3, 3, 18, 7, 2, 6, 18, 9, 2, 2, 5, 6, 2, 7, 6, 6, 1, 7, 10, 4, 6, 8, 13, 4, 3, 8, 0, 8, 2, 9, 0, 11, 2, 3, 0, 7, 5, 3, 0, 8, 5, 1, 8, 1, 7, 2, 8, 2, 7, 1, 7, 5, 3, 5, 8, 5, 1, 5, 19, 2, 1, 2, 19, 3, 1, 1, 6, 7, 10, 11, 11, 7, 5, 11, 9, 19, 6, 1, 11, 19, 2, 1, 3, 0, 12, 1, 7, 0, 4, 1, 4, 1, 6, 5, 6, 1, 2, 5, 6, 12, 12, 6, 10, 12, 4, 6, 16, 13, 2, 3, 16, 14, 2, 1, 7, 14, 4, 2, 7, 15, 4, 1, 7, 14, 2, 2, 7, 15, 2, 1, 3, 10, 2, 4, 3, 10, 1, 2, 4, 12, 1, 2, 0, 3, 2, 6, 0, 5, 2, 2, 1, 10, 2, 2, 1, 10, 1, 1, 2, 11, 1, 1, 16, 4, 4, 3, 16, 5, 4, 1, 5, 10, 2, 4, 5, 10, 1, 2, 6, 12, 1, 2, 5, 11, 13, 2, 5, 12, 13, 1, 10, 2, 3, 11, 11, 2, 1, 11, 10, 2, 4, 4, 10, 4, 4, 2, 8, 8, 6, 2, 10, 8, 2, 2, 11, 2, 3, 3, 12, 2, 1, 3, 6, 18, 14, 2, 6, 18, 7, 1, 13, 19, 7, 1, 17, 7, 1, 12, 17, 11, 1, 4, 10, 5, 10, 3, 10, 6, 10, 1, 6, 1, 3, 3, 7, 1, 1, 3, 13, 8, 3, 1, 14, 8, 1, 1, 10, 14, 2, 6, 10, 16, 2, 2, 4, 1, 12, 14, 8, 1, 4, 14, 14, 1, 6, 14, 16, 1, 2, 14, 3, 16, 2, 2, 3, 16, 1, 1, 4, 17, 1, 1, 0, 16, 2, 2, 0, 17, 2, 1, 15, 6, 4, 6, 15, 6, 2, 3, 17, 9, 2, 3, 12, 5, 2, 2, 12, 6, 2, 1, 7, 6, 6, 13, 9, 6, 2, 13, 1, 9, 6, 5, 3, 9, 2, 5, 0, 5, 3, 4, 0, 7, 3, 2, 4, 1, 16, 2, 4, 1, 8, 1, 12, 2, 8, 1, 1, 18, 4, 2, 1, 18, 2, 1, 3, 19, 2, 1, 7, 7, 3, 4, 8, 7, 1, 4, 3, 4, 9, 3, 6, 4, 3, 3, 4, 6, 6, 10, 6, 6, 2, 10, 9, 0, 8, 10, 13, 0, 4, 10, 8, 0, 8, 1, 12, 0, 4, 1, 6, 2, 8, 16, 6, 2, 4, 8, 10, 10, 4, 8, 14, 10, 2, 10, 14, 10, 1, 5, 15, 15, 1, 5, 12, 11, 1, 2, 12, 12, 1, 1, 16, 0, 3, 8, 17, 0, 1, 8, 14, 0, 6, 10, 17, 0, 3, 10, 16, 0, 3, 5, 17, 0, 1, 5, 4, 5, 11, 2, 4, 6, 11, 1, 1, 0, 2, 1, 2, 0, 1, 1, 0, 0, 2, 3, 0, 1, 2, 1, 11, 6, 6, 11, 13, 6, 2, 11, 14, 0, 3, 1, 15, 0, 1, 1, 19, 7, 1, 2, 19, 8, 1, 1, 17, 0, 3, 9, 18, 0, 1, 9, 12, 7, 3, 4, 13, 7, 1, 4, 0, 1, 14, 2, 0, 1, 7, 1, 7, 2, 7, 1, 3, 1, 3, 2, 4, 1, 1, 2, 4, 0, 15, 2, 9, 0, 5, 2, 10, 2, 6, 1, 12, 2, 2, 1, 9, 4, 6, 11, 11, 4, 2, 11, 2, 16, 2, 4, 2, 18, 2, 2, 6, 17, 6, 3, 8, 17, 2, 3, 7, 9, 6, 2, 9, 9, 2, 2, 6, 8, 9, 2, 9, 8, 3, 2, 6, 6, 2, 10, 6, 6, 1, 5, 7, 11, 1, 5, 0, 11, 2, 3, 0, 12, 2, 1, 11, 15, 4, 1, 13, 15, 2, 1, 6, 17, 1, 2, 6, 18, 1, 1, 0, 0, 6, 20, 2, 0, 2, 20, 3, 10, 2, 2, 4, 10, 1, 2, 4, 7, 3, 5, 5, 7, 1, 5, 3, 12, 6, 2, 5, 12, 2, 2, 6, 15, 7, 4, 6, 17, 7, 2, 17, 16, 2, 2, 17, 16, 1, 1, 18, 17, 1, 1, 15, 1, 3, 16, 16, 1, 1, 16, 6, 16, 6, 3, 8, 16, 2, 3, 15, 14, 3, 2, 15, 15, 3, 1, 12, 16, 1, 2, 12, 17, 1, 1, 0, 2, 4, 4, 0, 2, 2, 2, 2, 4, 2, 2, 1, 1, 6, 4, 1, 1, 3, 2, 4, 3, 3, 2, 1, 18, 1, 2, 1, 19, 1, 1, 4, 7, 2, 3, 4, 8, 2, 1, 1, 0, 9, 14, 1, 7, 9, 7, 4, 9, 2, 6, 4, 9, 1, 3, 5, 12, 1, 3, 3, 9, 4, 3, 5, 9, 2, 3, 0, 9, 2, 4, 0, 11, 2, 2, 16, 6, 3, 10, 17, 6, 1, 10, 16, 11, 2, 1, 17, 11, 1, 1, 5, 7, 4, 4, 5, 9, 4, 2, 10, 11, 9, 2, 13, 11, 3, 2, 15, 10, 2, 2, 15, 10, 1, 1, 16, 11, 1, 1, 10, 6, 6, 14, 10, 13, 6, 7, 14, 7, 3, 5, 15, 7, 1, 5, 6, 11, 12, 3, 10, 11, 4, 3, 17, 16, 1, 2, 17, 17, 1, 1, 8, 5, 5, 4, 8, 7, 5, 2, 11, 6, 4, 2, 11, 7, 4, 1, 3, 4, 8, 2, 3, 4, 4, 1, 7, 5, 4, 1, 0, 8, 6, 6, 2, 8, 2, 6, 7, 4, 6, 2, 7, 5, 6, 1, 7, 3, 6, 3, 9, 3, 2, 3, 2, 17, 3, 3, 2, 18, 3, 1, 3, 10, 6, 1, 5, 10, 2, 1, 7, 2, 6, 2, 9, 2, 2, 2, 4, 11, 9, 1, 7, 11, 3, 1, 7, 7, 11, 12, 7, 13, 11, 6, 3, 2, 3, 4, 4, 2, 1, 4, 9, 7, 9, 3, 12, 7, 3, 3, 15, 11, 2, 6, 15, 11, 1, 3, 16, 14, 1, 3, 0, 5, 5, 3, 0, 6, 5, 1, 8, 1, 6, 12, 10, 1, 2, 12, 3, 7, 15, 13, 8, 7, 5, 13, 0, 9, 9, 9, 0, 12, 9, 3, 16, 0, 3, 8, 17, 0, 1, 8, 16, 2, 4, 2, 18, 2, 2, 2, 13, 0, 6, 5, 16, 0, 3, 5, 15, 1, 3, 2, 16, 1, 1, 2, 11, 8, 3, 2, 12, 8, 1, 2, 1, 8, 2, 12, 1, 8, 1, 6, 2, 14, 1, 6, 0, 1, 6, 12, 2, 1, 2, 12, 19, 17, 1, 3, 19, 18, 1, 1, 11, 3, 3, 10, 12, 3, 1, 10, 8, 1, 9, 8, 11, 1, 3, 8, 18, 16, 2, 2, 18, 16, 1, 1, 19, 17, 1, 1, 18, 16, 2, 2, 18, 16, 1, 1, 19, 17, 1, 1, 6, 13, 2, 6, 6, 15, 2, 2, 9, 14, 2, 2, 9, 15, 2, 1, 14, 10, 2, 4, 14, 10, 1, 2, 15, 12, 1, 2, 0, 15, 2, 2, 0, 15, 1, 1, 1, 16, 1, 1, 6, 7, 2, 2, 6, 7, 1, 1, 7, 8, 1, 1, 11, 18, 2, 2, 11, 18, 1, 1, 12, 19, 1, 1, 0, 0, 6, 4, 0, 0, 3, 2, 3, 2, 3, 2, 4, 1, 6, 6, 6, 1, 2, 6, 15, 13, 5, 4, 15, 15, 5, 2, 7, 17, 6, 1, 9, 17, 2, 1, 16, 19, 4, 1, 18, 19, 2, 1, 16, 16, 4, 4, 18, 16, 2, 4, 7, 8, 9, 4, 10, 8, 3, 4, 16, 18, 2, 2, 16, 18, 1, 1, 17, 19, 1, 1, 2, 9, 2, 4, 2, 9, 1, 2, 3, 11, 1, 2, 0, 3, 8, 4, 0, 3, 4, 2, 4, 5, 4, 2, 0, 1, 8, 1, 4, 1, 4, 1, 0, 5, 8, 9, 4, 5, 4, 9, 7, 18, 6, 2, 9, 18, 2, 2, 0, 4, 1, 12, 0, 8, 1, 4, 19, 13, 1, 6, 19, 15, 1, 2, 2, 8, 6, 8, 4, 8, 2, 8, 0, 0, 9, 17, 3, 0, 3, 17, 7, 9, 6, 8, 9, 9, 2, 8, 5, 10, 9, 4, 8, 10, 3, 4, 5, 0, 8, 3, 5, 1, 8, 1, 16, 6, 4, 4, 16, 6, 2, 2, 18, 8, 2, 2, 17, 4, 2, 8, 17, 4, 1, 4, 18, 8, 1, 4, 2, 16, 1, 3, 2, 17, 1, 1, 2, 16, 1, 3, 2, 17, 1, 1, 11, 0, 1, 3, 11, 1, 1, 1, 11, 2, 9, 7, 14, 2, 3, 7, 10, 2, 3, 6, 11, 2, 1, 6, 5, 9, 15, 2, 5, 10, 15, 1, 8, 16, 6, 2, 8, 17, 6, 1, 9, 16, 10, 2, 9, 16, 5, 1, 14, 17, 5, 1, 9, 17, 2, 2, 9, 17, 1, 1, 10, 18, 1, 1, 10, 15, 6, 4, 10, 15, 3, 2, 13, 17, 3, 2, 4, 5, 15, 12, 9, 5, 5, 12, 11, 13, 2, 3, 11, 14, 2, 1, 8, 13, 7, 3, 8, 14, 7, 1, 1, 12, 1, 2, 1, 13, 1, 1, 16, 18, 2, 2, 16, 18, 1, 1, 17, 19, 1, 1, 1, 19, 18, 1, 7, 19, 6, 1, 1, 17, 6, 1, 4, 17, 3, 1, 1, 3, 1, 12, 1, 9, 1, 6, 0, 9, 3, 6, 0, 11, 3, 2, 5, 4, 3, 10, 6, 4, 1, 10, 6, 17, 2, 1, 7, 17, 1, 1, 1, 0, 6, 12, 3, 0, 2, 12, 4, 7, 9, 2, 7, 7, 3, 2, 6, 11, 9, 1, 9, 11, 3, 1, 17, 10, 2, 10, 17, 15, 2, 5, 4, 10, 2, 10, 4, 10, 1, 5, 5, 15, 1, 5, 12, 3, 3, 12, 13, 3, 1, 12, 15, 3, 4, 6, 15, 3, 2, 3, 17, 6, 2, 3, 12, 8, 3, 3, 13, 8, 1, 3, 4, 14, 2, 4, 4, 16, 2, 2, 6, 16, 1, 3, 6, 17, 1, 1, 1, 1, 2, 3, 2, 1, 1, 3, 0, 2, 4, 1, 2, 2, 2, 1, 8, 17, 12, 3, 12, 17, 4, 3, 9, 16, 6, 4, 11, 16, 2, 4, 4, 6, 3, 6, 4, 9, 3, 3, 6, 2, 12, 9, 6, 5, 12, 3, 6, 0, 14, 20, 6, 0, 7, 10, 13, 10, 7, 10, 15, 16, 2, 2, 15, 16, 1, 1, 16, 17, 1, 1, 15, 16, 2, 2, 15, 16, 1, 1, 16, 17, 1, 1, 19, 8, 1, 3, 19, 9, 1, 1, 13, 4, 1, 2, 13, 5, 1, 1, 0, 4, 4, 2, 0, 5, 4, 1, 19, 5, 1, 6, 19, 7, 1, 2, 16, 0, 2, 1, 17, 0, 1, 1, 13, 1, 1, 3, 13, 2, 1, 1, 17, 17, 1, 3, 17, 18, 1, 1, 5, 4, 8, 8, 5, 4, 4, 4, 9, 8, 4, 4, 1, 2, 2, 2, 1, 2, 1, 1, 2, 3, 1, 1, 0, 0, 8, 6, 0, 0, 4, 3, 4, 3, 4, 3, 6, 3, 4, 2, 6, 4, 4, 1, 1, 0, 3, 3, 1, 1, 3, 1, 6, 1, 7, 2, 6, 2, 7, 1, 2, 6, 12, 6, 6, 6, 4, 6, 1, 16, 9, 2, 4, 16, 3, 2, 7, 15, 6, 4, 9, 15, 2, 4, 6, 15, 12, 1, 12, 15, 6, 1, 17, 17, 1, 3, 17, 18, 1, 1, 17, 15, 2, 2, 17, 15, 1, 1, 18, 16, 1, 1, 3, 13, 3, 3, 3, 14, 3, 1, 10, 17, 1, 3, 10, 18, 1, 1, 4, 0, 14, 8, 11, 0, 7, 8, 2, 0, 12, 2, 6, 0, 4, 2, 2, 0, 4, 3, 4, 0, 2, 3, 13, 1, 1, 2, 13, 2, 1, 1, 7, 5, 3, 6, 8, 5, 1, 6, 18, 2, 2, 2, 18, 2, 1, 1, 19, 3, 1, 1, 15, 1, 2, 14, 16, 1, 1, 14, 15, 6, 2, 2, 15, 6, 1, 1, 16, 7, 1, 1, 3, 1, 6, 3, 5, 1, 2, 3, 7, 16, 2, 2, 7, 16, 1, 1, 8, 17, 1, 1, 5, 17, 2, 2, 5, 17, 1, 1, 6, 18, 1, 1, 9, 10, 6, 10, 11, 10, 2, 10, 10, 17, 6, 3, 12, 17, 2, 3, 14, 5, 2, 10, 14, 10, 2, 5, 11, 12, 6, 2, 11, 13, 6, 1, 8, 1, 1, 3, 8, 2, 1, 1, 12, 15, 2, 2, 12, 15, 1, 1, 13, 16, 1, 1, 6, 8, 6, 4, 6, 8, 3, 2, 9, 10, 3, 2, 7, 5, 3, 5, 8, 5, 1, 5, 0, 5, 7, 3, 0, 6, 7, 1, 7, 9, 6, 6, 9, 9, 2, 6, 5, 7, 8, 8, 5, 11, 8, 4, 4, 9, 2, 6, 4, 9, 1, 3, 5, 12, 1, 3, 10, 11, 6, 1, 12, 11, 2, 1, 13, 6, 6, 11, 15, 6, 2, 11, 8, 17, 2, 2, 8, 17, 1, 1, 9, 18, 1, 1, 4, 12, 12, 1, 8, 12, 4, 1, 11, 17, 3, 2, 11, 18, 3, 1, 8, 17, 6, 1, 10, 17, 2, 1, 4, 1, 14, 6, 4, 3, 14, 2, 14, 2, 2, 12, 14, 8, 2, 6, 12, 13, 3, 2, 12, 14, 3, 1, 6, 1, 6, 1, 8, 1, 2, 1, 10, 6, 6, 1, 12, 6, 2, 1, 3, 19, 2, 1, 4, 19, 1, 1, 18, 16, 2, 2, 18, 16, 1, 1, 19, 17, 1, 1, 16, 11, 3, 7, 17, 11, 1, 7, 19, 5, 1, 6, 19, 8, 1, 3, 9, 8, 4, 3, 9, 9, 4, 1, 16, 8, 4, 4, 16, 8, 2, 2, 18, 10, 2, 2, 2, 8, 2, 2, 2, 8, 1, 1, 3, 9, 1, 1, 3, 5, 6, 4, 3, 5, 3, 2, 6, 7, 3, 2, 2, 3, 8, 16, 2, 3, 4, 8, 6, 11, 4, 8, 17, 17, 1, 3, 17, 18, 1, 1, 7, 2, 8, 11, 11, 2, 4, 11, 13, 3, 6, 14, 16, 3, 3, 14, 0, 9, 18, 2, 6, 9, 6, 2, 6, 10, 14, 3, 6, 11, 14, 1, 10, 9, 9, 3, 13, 9, 3, 3, 3, 5, 4, 6, 3, 5, 2, 3, 5, 8, 2, 3, 3, 7, 3, 7, 4, 7, 1, 7, 2, 8, 11, 6, 2, 10, 11, 2, 8, 9, 6, 3, 8, 10, 6, 1, 3, 3, 3, 11, 4, 3, 1, 11, 0, 19, 6, 1, 3, 19, 3, 1, 18, 18, 1, 2, 18, 19, 1, 1, 8, 0, 12, 6, 8, 0, 6, 3, 14, 3, 6, 3, 19, 5, 1, 3, 19, 6, 1, 1, 5, 8, 2, 1, 6, 8, 1, 1, 13, 11, 2, 1, 14, 11, 1, 1, 3, 6, 15, 13, 8, 6, 5, 13, 4, 3, 6, 2, 6, 3, 2, 2, 0, 18, 1, 2, 0, 19, 1, 1, 7, 8, 2, 6, 8, 8, 1, 6, 3, 0, 6, 19, 5, 0, 2, 19, 3, 1, 6, 5, 5, 1, 2, 5, 17, 14, 3, 6, 17, 16, 3, 2, 17, 13, 2, 6, 18, 13, 1, 6, 17, 18, 2, 2, 18, 18, 1, 2, 11, 14, 9, 4, 14, 14, 3, 4, 15, 8, 4, 6, 15, 8, 2, 3, 17, 11, 2, 3, 1, 16, 1, 3, 1, 17, 1, 1, 7, 0, 3, 14, 8, 0, 1, 14, 12, 0, 2, 1, 13, 0, 1, 1, 7, 9, 6, 5, 10, 9, 3, 5, 15, 5, 4, 9, 17, 5, 2, 9, 11, 0, 6, 6, 13, 0, 2, 6, 16, 15, 2, 2, 16, 15, 1, 1, 17, 16, 1, 1, 16, 15, 2, 2, 16, 15, 1, 1, 17, 16, 1, 1, 13, 2, 2, 18, 13, 11, 2, 9, 8, 4, 8, 10, 8, 9, 8, 5, 8, 3, 2, 3, 8, 4, 2, 1, 11, 1, 6, 9, 11, 4, 6, 3, 15, 4, 5, 6, 15, 6, 5, 2, 12, 18, 2, 2, 12, 18, 1, 1, 13, 19, 1, 1, 1, 17, 1, 3, 1, 18, 1, 1, 12, 19, 2, 1, 13, 19, 1, 1, 8, 10, 6, 6, 10, 10, 2, 6, 14, 2, 6, 5, 16, 2, 2, 5, 9, 5, 2, 6, 9, 7, 2, 2, 1, 15, 2, 2, 2, 15, 1, 2, 18, 17, 1, 3, 18, 18, 1, 1, 10, 14, 4, 6, 10, 16, 4, 2, 9, 7, 3, 2, 10, 7, 1, 2, 6, 9, 6, 2, 6, 9, 3, 1, 9, 10, 3, 1, 0, 2, 1, 12, 0, 6, 1, 4, 4, 0, 15, 1, 9, 0, 5, 1, 9, 0, 8, 2, 9, 0, 4, 1, 13, 1, 4, 1, 12, 2, 8, 1, 16, 2, 4, 1, 7, 1, 10, 6, 7, 3, 10, 2, 18, 6, 2, 3, 18, 7, 2, 1, 4, 12, 2, 2, 4, 12, 1, 1, 5, 13, 1, 1, 6, 6, 6, 2, 8, 6, 2, 2, 0, 9, 9, 6, 3, 9, 3, 6, 17, 18, 2, 2, 18, 18, 1, 2, 11, 2, 6, 16, 13, 2, 2, 16, 2, 4, 15, 13, 7, 4, 5, 13, 16, 2, 3, 10, 17, 2, 1, 10, 6, 10, 2, 1, 7, 10, 1, 1, 1, 1, 18, 16, 10, 1, 9, 16, 14, 4, 3, 15, 15, 4, 1, 15, 19, 13, 1, 2, 19, 14, 1, 1, 2, 6, 5, 8, 2, 10, 5, 4}; diff --git a/src/openmv/src/omv/img/clahe.c b/src/openmv/src/omv/img/clahe.c new file mode 100755 index 0000000..aed241e --- /dev/null +++ b/src/openmv/src/omv/img/clahe.c @@ -0,0 +1,419 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" +#define BYTE_IMAGE + +/* + * ANSI C code from the article + * "Contrast Limited Adaptive Histogram Equalization" + * by Karel Zuiderveld, karel@cv.ruu.nl + * in "Graphics Gems IV", Academic Press, 1994 + * + * + * These functions implement Contrast Limited Adaptive Histogram Equalization. + * The main routine (CLAHE) expects an input image that is stored contiguously in + * memory; the CLAHE output image overwrites the original input image and has the + * same minimum and maximum values (which must be provided by the user). + * This implementation assumes that the X- and Y image resolutions are an integer + * multiple of the X- and Y sizes of the contextual regions. A check on various other + * error conditions is performed. + * + * #define the symbol BYTE_IMAGE to make this implementation suitable for + * 8-bit images. The maximum number of contextual regions can be redefined + * by changing uiMAX_REG_X and/or uiMAX_REG_Y; the use of more than 256 + * contextual regions is not recommended. + * + * The code is ANSI-C and is also C++ compliant. + * + * Author: Karel Zuiderveld, Computer Vision Research Group, + * Utrecht, The Netherlands (karel@cv.ruu.nl) + */ + +#ifdef BYTE_IMAGE +typedef unsigned char kz_pixel_t; /* for 8 bit-per-pixel images */ +#define uiNR_OF_GREY (256) +#else +typedef unsigned short kz_pixel_t; /* for 12 bit-per-pixel images (default) */ +# define uiNR_OF_GREY (4096) +#endif + +/******** Prototype of CLAHE function. Put this in a separate include file. *****/ +int CLAHE(kz_pixel_t* pImage, unsigned int uiXRes, unsigned int uiYRes, kz_pixel_t Min, + kz_pixel_t Max, unsigned int uiNrX, unsigned int uiNrY, + unsigned int uiNrBins, float fCliplimit); + +/*********************** Local prototypes ************************/ +static void ClipHistogram (unsigned long*, unsigned int, unsigned long); +static void MakeHistogram (kz_pixel_t*, unsigned int, unsigned int, unsigned int, + unsigned long*, unsigned int, kz_pixel_t*); +static void MapHistogram (unsigned long*, kz_pixel_t, kz_pixel_t, + unsigned int, unsigned long); +static void MakeLut (kz_pixel_t*, kz_pixel_t, kz_pixel_t, unsigned int); +static void Interpolate (kz_pixel_t*, int, unsigned long*, unsigned long*, + unsigned long*, unsigned long*, unsigned int, unsigned int, kz_pixel_t*); + +/************** Start of actual code **************/ +const unsigned int uiMAX_REG_X = 16; /* max. # contextual regions in x-direction */ +const unsigned int uiMAX_REG_Y = 16; /* max. # contextual regions in y-direction */ + +/************************** main function CLAHE ******************/ +int CLAHE (kz_pixel_t* pImage, unsigned int uiXRes, unsigned int uiYRes, + kz_pixel_t Min, kz_pixel_t Max, unsigned int uiNrX, unsigned int uiNrY, + unsigned int uiNrBins, float fCliplimit) +/* pImage - Pointer to the input/output image + * uiXRes - Image resolution in the X direction + * uiYRes - Image resolution in the Y direction + * Min - Minimum greyvalue of input image (also becomes minimum of output image) + * Max - Maximum greyvalue of input image (also becomes maximum of output image) + * uiNrX - Number of contextial regions in the X direction (min 2, max uiMAX_REG_X) + * uiNrY - Number of contextial regions in the Y direction (min 2, max uiMAX_REG_Y) + * uiNrBins - Number of greybins for histogram ("dynamic range") + * float fCliplimit - Normalized cliplimit (higher values give more contrast) + * The number of "effective" greylevels in the output image is set by uiNrBins; selecting + * a small value (eg. 128) speeds up processing and still produce an output image of + * good quality. The output image will have the same minimum and maximum value as the input + * image. A clip limit smaller than 1 results in standard (non-contrast limited) AHE. + */ +{ + unsigned int uiX, uiY; /* counters */ + unsigned int uiXSize, uiYSize, uiSubX, uiSubY; /* size of context. reg. and subimages */ + unsigned int uiXL, uiXR, uiYU, uiYB; /* auxiliary variables interpolation routine */ + unsigned long ulClipLimit, ulNrPixels;/* clip limit and region pixel count */ + kz_pixel_t* pImPointer; /* pointer to image */ + kz_pixel_t aLUT[uiNR_OF_GREY]; /* lookup table used for scaling of input image */ + unsigned long* pulHist, *pulMapArray; /* pointer to histogram and mappings*/ + unsigned long* pulLU, *pulLB, *pulRU, *pulRB; /* auxiliary pointers interpolation */ + + if (uiNrX > uiMAX_REG_X) return -1; /* # of regions x-direction too large */ + if (uiNrY > uiMAX_REG_Y) return -2; /* # of regions y-direction too large */ + if (uiXRes % uiNrX) return -3; /* x-resolution no multiple of uiNrX */ + if (uiYRes % uiNrY) return -4; /* y-resolution no multiple of uiNrY */ + if (Max >= uiNR_OF_GREY) return -5; /* maximum too large */ + if (Min >= Max) return -6; /* minimum equal or larger than maximum */ + if (uiNrX < 2 || uiNrY < 2) return -7;/* at least 4 contextual regions required */ + if (fCliplimit == 1.0) return 0; /* is OK, immediately returns original image. */ + if (uiNrBins == 0) uiNrBins = 128; /* default value when not specified */ + + pulMapArray=(unsigned long *)fb_alloc(sizeof(unsigned long)*uiNrX*uiNrY*uiNrBins); + if (pulMapArray == 0) return -8; /* Not enough memory! (try reducing uiNrBins) */ + + uiXSize = uiXRes/uiNrX; uiYSize = uiYRes/uiNrY; /* Actual size of contextual regions */ + ulNrPixels = (unsigned long)uiXSize * (unsigned long)uiYSize; + + if(fCliplimit > 0.0) { /* Calculate actual cliplimit */ + ulClipLimit = (unsigned long) (fCliplimit * (uiXSize * uiYSize) / uiNrBins); + ulClipLimit = (ulClipLimit < 1UL) ? 1UL : ulClipLimit; + } + else ulClipLimit = 1UL<<14; /* Large value, do not clip (AHE) */ + MakeLut(aLUT, Min, Max, uiNrBins); /* Make lookup table for mapping of greyvalues */ + /* Calculate greylevel mappings for each contextual region */ + for (uiY = 0, pImPointer = pImage; uiY < uiNrY; uiY++) { + for (uiX = 0; uiX < uiNrX; uiX++, pImPointer += uiXSize) { + pulHist = &pulMapArray[uiNrBins * (uiY * uiNrX + uiX)]; + MakeHistogram(pImPointer,uiXRes,uiXSize,uiYSize,pulHist,uiNrBins,aLUT); + ClipHistogram(pulHist, uiNrBins, ulClipLimit); + MapHistogram(pulHist, Min, Max, uiNrBins, ulNrPixels); + } + pImPointer += (uiYSize - 1) * uiXRes; /* skip lines, set pointer */ + } + + /* Interpolate greylevel mappings to get CLAHE image */ + for (pImPointer = pImage, uiY = 0; uiY <= uiNrY; uiY++) { + if (uiY == 0) { /* special case: top row */ + uiSubY = uiYSize >> 1; uiYU = 0; uiYB = 0; + } + else { + if (uiY == uiNrY) { /* special case: bottom row */ + uiSubY = (uiYSize+1) >> 1; uiYU = uiNrY-1; uiYB = uiYU; + } + else { /* default values */ + uiSubY = uiYSize; uiYU = uiY - 1; uiYB = uiYU + 1; + } + } + for (uiX = 0; uiX <= uiNrX; uiX++) { + if (uiX == 0) { /* special case: left column */ + uiSubX = uiXSize >> 1; uiXL = 0; uiXR = 0; + } + else { + if (uiX == uiNrX) { /* special case: right column */ + uiSubX = (uiXSize+1) >> 1; uiXL = uiNrX - 1; uiXR = uiXL; + } + else { /* default values */ + uiSubX = uiXSize; uiXL = uiX - 1; uiXR = uiXL + 1; + } + } + + pulLU = &pulMapArray[uiNrBins * (uiYU * uiNrX + uiXL)]; + pulRU = &pulMapArray[uiNrBins * (uiYU * uiNrX + uiXR)]; + pulLB = &pulMapArray[uiNrBins * (uiYB * uiNrX + uiXL)]; + pulRB = &pulMapArray[uiNrBins * (uiYB * uiNrX + uiXR)]; + Interpolate(pImPointer,uiXRes,pulLU,pulRU,pulLB,pulRB,uiSubX,uiSubY,aLUT); + pImPointer += uiSubX; /* set pointer on next matrix */ + } + pImPointer += (uiSubY - 1) * uiXRes; + } + fb_free(); /* free space for histograms */ + return 0; /* return status OK */ +} + +void ClipHistogram (unsigned long* pulHistogram, unsigned int + uiNrGreylevels, unsigned long ulClipLimit) +/* This function performs clipping of the histogram and redistribution of bins. + * The histogram is clipped and the number of excess pixels is counted. Afterwards + * the excess pixels are equally redistributed across the whole histogram (providing + * the bin count is smaller than the cliplimit). + */ +{ + unsigned long* pulBinPointer, *pulEndPointer, *pulHisto; + unsigned long ulNrExcess, ulUpper, ulBinIncr, ulStepSize, i; + long lBinExcess; + + ulNrExcess = 0; pulBinPointer = pulHistogram; + for (i = 0; i < uiNrGreylevels; i++) { /* calculate total number of excess pixels */ + lBinExcess = (long) pulBinPointer[i] - (long) ulClipLimit; + if (lBinExcess > 0) ulNrExcess += lBinExcess; /* excess in current bin */ + }; + + /* Second part: clip histogram and redistribute excess pixels in each bin */ + ulBinIncr = ulNrExcess / uiNrGreylevels; /* average binincrement */ + ulUpper = ulClipLimit - ulBinIncr; /* Bins larger than ulUpper set to cliplimit */ + + for (i = 0; i < uiNrGreylevels; i++) { + if (pulHistogram[i] > ulClipLimit) pulHistogram[i] = ulClipLimit; /* clip bin */ + else { + if (pulHistogram[i] > ulUpper) { /* high bin count */ + ulNrExcess -= pulHistogram[i] - ulUpper; pulHistogram[i]=ulClipLimit; + } + else { /* low bin count */ + ulNrExcess -= ulBinIncr; pulHistogram[i] += ulBinIncr; + } + } + } + + while (ulNrExcess) { /* Redistribute remaining excess */ + pulEndPointer = &pulHistogram[uiNrGreylevels]; pulHisto = pulHistogram; + + while (ulNrExcess && pulHisto < pulEndPointer) { + ulStepSize = uiNrGreylevels / ulNrExcess; + if (ulStepSize < 1) ulStepSize = 1; /* stepsize at least 1 */ + for (pulBinPointer=pulHisto; pulBinPointer < pulEndPointer && ulNrExcess; + pulBinPointer += ulStepSize) { + if (*pulBinPointer < ulClipLimit) { + (*pulBinPointer)++; ulNrExcess--; /* reduce excess */ + } + } + pulHisto++; /* restart redistributing on other bin location */ + } + } +} + +void MakeHistogram (kz_pixel_t* pImage, unsigned int uiXRes, + unsigned int uiSizeX, unsigned int uiSizeY, + unsigned long* pulHistogram, + unsigned int uiNrGreylevels, kz_pixel_t* pLookupTable) +/* This function classifies the greylevels present in the array image into + * a greylevel histogram. The pLookupTable specifies the relationship + * between the greyvalue of the pixel (typically between 0 and 4095) and + * the corresponding bin in the histogram (usually containing only 128 bins). + */ +{ + kz_pixel_t* pImagePointer; + unsigned int i; + + for (i = 0; i < uiNrGreylevels; i++) pulHistogram[i] = 0L; /* clear histogram */ + + for (i = 0; i < uiSizeY; i++) { + pImagePointer = &pImage[uiSizeX]; + while (pImage < pImagePointer) pulHistogram[pLookupTable[*pImage++]]++; + pImagePointer += uiXRes; + pImage = &pImagePointer[-(int)uiSizeX]; /* go to bdeginning of next row */ + } +} + +void MapHistogram (unsigned long* pulHistogram, kz_pixel_t Min, kz_pixel_t Max, + unsigned int uiNrGreylevels, unsigned long ulNrOfPixels) +/* This function calculates the equalized lookup table (mapping) by + * cumulating the input histogram. Note: lookup table is rescaled in range [Min..Max]. + */ +{ + unsigned int i; unsigned long ulSum = 0; + const float fScale = ((float)(Max - Min)) / ulNrOfPixels; + const unsigned long ulMin = (unsigned long) Min; + + for (i = 0; i < uiNrGreylevels; i++) { + ulSum += pulHistogram[i]; pulHistogram[i]=(unsigned long)(ulMin+ulSum*fScale); + if (pulHistogram[i] > Max) pulHistogram[i] = Max; + } +} + +void MakeLut (kz_pixel_t * pLUT, kz_pixel_t Min, kz_pixel_t Max, unsigned int uiNrBins) +/* To speed up histogram clipping, the input image [Min,Max] is scaled down to + * [0,uiNrBins-1]. This function calculates the LUT. + */ +{ + int i; + const kz_pixel_t BinSize = (kz_pixel_t) (1 + (Max - Min) / uiNrBins); + + for (i = Min; i <= Max; i++) pLUT[i] = (i - Min) / BinSize; +} + +void Interpolate (kz_pixel_t * pImage, int uiXRes, unsigned long * pulMapLU, + unsigned long * pulMapRU, unsigned long * pulMapLB, unsigned long * pulMapRB, + unsigned int uiXSize, unsigned int uiYSize, kz_pixel_t * pLUT) +/* pImage - pointer to input/output image + * uiXRes - resolution of image in x-direction + * pulMap* - mappings of greylevels from histograms + * uiXSize - uiXSize of image submatrix + * uiYSize - uiYSize of image submatrix + * pLUT - lookup table containing mapping greyvalues to bins + * This function calculates the new greylevel assignments of pixels within a submatrix + * of the image with size uiXSize and uiYSize. This is done by a bilinear interpolation + * between four different mappings in order to eliminate boundary artifacts. + * It uses a division; since division is often an expensive operation, I added code to + * perform a logical shift instead when feasible. + */ +{ + const unsigned int uiIncr = uiXRes-uiXSize; /* Pointer increment after processing row */ + kz_pixel_t GreyValue; unsigned int uiNum = uiXSize*uiYSize; /* Normalization factor */ + + unsigned int uiXCoef, uiYCoef, uiXInvCoef, uiYInvCoef, uiShift = 0; + + if (uiNum & (uiNum - 1)) /* If uiNum is not a power of two, use division */ + for (uiYCoef = 0, uiYInvCoef = uiYSize; uiYCoef < uiYSize; + uiYCoef++, uiYInvCoef--,pImage+=uiIncr) { + for (uiXCoef = 0, uiXInvCoef = uiXSize; uiXCoef < uiXSize; + uiXCoef++, uiXInvCoef--) { + GreyValue = pLUT[*pImage]; /* get histogram bin value */ + *pImage++ = (kz_pixel_t ) ((uiYInvCoef * (uiXInvCoef*pulMapLU[GreyValue] + + uiXCoef * pulMapRU[GreyValue]) + + uiYCoef * (uiXInvCoef * pulMapLB[GreyValue] + + uiXCoef * pulMapRB[GreyValue])) / uiNum); + } + } + else { /* avoid the division and use a right shift instead */ + while (uiNum >>= 1) uiShift++; /* Calculate 2log of uiNum */ + for (uiYCoef = 0, uiYInvCoef = uiYSize; uiYCoef < uiYSize; + uiYCoef++, uiYInvCoef--,pImage+=uiIncr) { + for (uiXCoef = 0, uiXInvCoef = uiXSize; uiXCoef < uiXSize; + uiXCoef++, uiXInvCoef--) { + GreyValue = pLUT[*pImage]; /* get histogram bin value */ + *pImage++ = (kz_pixel_t)((uiYInvCoef* (uiXInvCoef * pulMapLU[GreyValue] + + uiXCoef * pulMapRU[GreyValue]) + + uiYCoef * (uiXInvCoef * pulMapLB[GreyValue] + + uiXCoef * pulMapRB[GreyValue])) >> uiShift); + } + } + } +} + +void imlib_clahe_histeq(image_t *img, float clip_limit, image_t *mask) +{ + int xTileSize = IM_MAX(uiMAX_REG_X >> (10 - IM_MIN(IM_LOG2_32(img->w), 10)), 2); + int yTileSize = IM_MAX(uiMAX_REG_Y >> (10 - IM_MIN(IM_LOG2_32(img->h), 10)), 2); + int pImageW = img->w + ((img->w % xTileSize) ? (xTileSize - (img->w % xTileSize)) : 0); + int pImageH = img->h + ((img->h % yTileSize) ? (yTileSize - (img->h % yTileSize)) : 0); + int xOffset = (pImageW - img->w) / 2; + int yOffset = (pImageH - img->h) / 2; + + image_t temp; + temp.w = img->w; + temp.h = img->h; + temp.bpp = img->bpp; + temp.data = fb_alloc0(pImageW * pImageH * sizeof(kz_pixel_t)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset, + COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x))); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset, + IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset, + COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))); + } + } + break; + } + default: { + break; + } + } + + CLAHE((kz_pixel_t *) temp.data, + pImageW, pImageH, + COLOR_GRAYSCALE_MIN, COLOR_GRAYSCALE_MAX, + xTileSize, yTileSize, + COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1, + clip_limit); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, + COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset))); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, + IMAGE_GET_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *clahe_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&temp, y + yOffset); + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, + imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(clahe_row_ptr, x + xOffset), + COLOR_RGB565_TO_U(pixel), + COLOR_RGB565_TO_V(pixel))); + } + } + break; + } + default: { + break; + } + } + + fb_free(); +} diff --git a/src/openmv/src/omv/img/collections.c b/src/openmv/src/omv/img/collections.c new file mode 100755 index 0000000..fcfcc3b --- /dev/null +++ b/src/openmv/src/omv/img/collections.c @@ -0,0 +1,523 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" +#define CHAR_BITS (sizeof(char) * 8) +#define CHAR_MASK (CHAR_BITS - 1) +#define CHAR_SHIFT IM_LOG2(CHAR_MASK) + +//////////// +// bitmap // +//////////// + +void bitmap_alloc(bitmap_t *ptr, size_t size) +{ + ptr->size = size; + ptr->data = (char *) fb_alloc0(((size + CHAR_MASK) >> CHAR_SHIFT) * sizeof(char)); +} + +void bitmap_free(bitmap_t *ptr) +{ + if (ptr->data) { + fb_free(); + } +} + +void bitmap_clear(bitmap_t *ptr) +{ + memset(ptr->data, 0, ((ptr->size + CHAR_MASK) >> CHAR_SHIFT) * sizeof(char)); +} + +void bitmap_bit_set(bitmap_t *ptr, size_t index) +{ + ptr->data[index >> CHAR_SHIFT] |= 1 << (index & CHAR_MASK); +} + +bool bitmap_bit_get(bitmap_t *ptr, size_t index) +{ + return (ptr->data[index >> CHAR_SHIFT] >> (index & CHAR_MASK)) & 1; +} + +////////// +// lifo // +////////// + +void lifo_alloc(lifo_t *ptr, size_t size, size_t data_len) +{ + ptr->len = 0; + ptr->size = size; + ptr->data_len = data_len; + ptr->data = (char *) fb_alloc(size * data_len); +} + +void lifo_alloc_all(lifo_t *ptr, size_t *size, size_t data_len) +{ + uint32_t tmp_size; + ptr->data = (char *) fb_alloc_all(&tmp_size); + ptr->data_len = data_len; + ptr->size = tmp_size / data_len; + ptr->len = 0; + *size = ptr->size; +} + +void lifo_free(lifo_t *ptr) +{ + if (ptr->data) { + fb_free(); + } +} + +void lifo_clear(lifo_t *ptr) +{ + ptr->len = 0; +} + +size_t lifo_size(lifo_t *ptr) +{ + return ptr->len; +} + +bool lifo_is_not_empty(lifo_t *ptr) +{ + return ptr->len; +} + +bool lifo_is_not_full(lifo_t *ptr) +{ + return ptr->len != ptr->size; +} + +void lifo_enqueue(lifo_t *ptr, void *data) +{ + memcpy(ptr->data + (ptr->len * ptr->data_len), data, ptr->data_len); + + ptr->len += 1; +} + +void lifo_dequeue(lifo_t *ptr, void *data) +{ + if (data) { + memcpy(data, ptr->data + ((ptr->len - 1) * ptr->data_len), ptr->data_len); + } + + ptr->len -= 1; +} + +void lifo_poke(lifo_t *ptr, void *data) +{ + memcpy(ptr->data + (ptr->len * ptr->data_len), data, ptr->data_len); +} + +void lifo_peek(lifo_t *ptr, void *data) +{ + memcpy(data, ptr->data + ((ptr->len - 1) * ptr->data_len), ptr->data_len); +} + +////////// +// fifo // +////////// + +void fifo_alloc(fifo_t *ptr, size_t size, size_t data_len) +{ + ptr->head_ptr = 0; + ptr->tail_ptr = 0; + ptr->len = 0; + ptr->size = size; + ptr->data_len = data_len; + ptr->data = (char *) fb_alloc(size * data_len); +} + +void fifo_alloc_all(fifo_t *ptr, size_t *size, size_t data_len) +{ + uint32_t tmp_size; + ptr->data = (char *) fb_alloc_all(&tmp_size); + ptr->data_len = data_len; + ptr->size = tmp_size / data_len; + ptr->len = 0; + ptr->tail_ptr = 0; + ptr->head_ptr = 0; + *size = ptr->size; +} + +void fifo_free(fifo_t *ptr) +{ + if (ptr->data) { + fb_free(); + } +} + +void fifo_clear(fifo_t *ptr) +{ + ptr->head_ptr = 0; + ptr->tail_ptr = 0; + ptr->len = 0; +} + +size_t fifo_size(fifo_t *ptr) +{ + return ptr->len; +} + +bool fifo_is_not_empty(fifo_t *ptr) +{ + return ptr->len; +} + +bool fifo_is_not_full(fifo_t *ptr) +{ + return ptr->len != ptr->size; +} + +void fifo_enqueue(fifo_t *ptr, void *data) +{ + memcpy(ptr->data + (ptr->head_ptr * ptr->data_len), data, ptr->data_len); + + size_t temp = ptr->head_ptr + 1; + + if (temp == ptr->size) { + temp = 0; + } + + ptr->head_ptr = temp; + ptr->len += 1; +} + +void fifo_dequeue(fifo_t *ptr, void *data) +{ + if (data) { + memcpy(data, ptr->data + (ptr->tail_ptr * ptr->data_len), ptr->data_len); + } + + size_t temp = ptr->tail_ptr + 1; + + if (temp == ptr->size) { + temp = 0; + } + + ptr->tail_ptr = temp; + ptr->len -= 1; +} + +void fifo_poke(fifo_t *ptr, void *data) +{ + memcpy(ptr->data + (ptr->head_ptr * ptr->data_len), data, ptr->data_len); +} + +void fifo_peek(fifo_t *ptr, void *data) +{ + memcpy(data, ptr->data + (ptr->tail_ptr * ptr->data_len), ptr->data_len); +} + +////////// +// list // +////////// + +void list_init(list_t *ptr, size_t data_len) +{ + ptr->head_ptr = NULL; + ptr->tail_ptr = NULL; + ptr->size = 0; + ptr->data_len = data_len; +} + +void list_copy(list_t *dst, list_t *src) +{ + memcpy(dst, src, sizeof(list_t)); +} + +void list_free(list_t *ptr) +{ + for (list_lnk_t *i = ptr->head_ptr; i; ) { + list_lnk_t *j = i->next_ptr; + xfree(i); + i = j; + } +} + +void list_clear(list_t *ptr) +{ + list_free(ptr); + + ptr->head_ptr = NULL; + ptr->tail_ptr = NULL; + ptr->size = 0; +} + +size_t list_size(list_t *ptr) +{ + return ptr->size; +} + +void list_push_front(list_t *ptr, void *data) +{ + list_lnk_t *tmp = (list_lnk_t *) xalloc(sizeof(list_lnk_t) + ptr->data_len); + memcpy(tmp->data, data, ptr->data_len); + + if (ptr->size++) { + tmp->next_ptr = ptr->head_ptr; + tmp->prev_ptr = NULL; + ptr->head_ptr->prev_ptr = tmp; + ptr->head_ptr = tmp; + } else { + tmp->next_ptr = NULL; + tmp->prev_ptr = NULL; + ptr->head_ptr = tmp; + ptr->tail_ptr = tmp; + } +} + +void list_push_back(list_t *ptr, void *data) +{ + list_lnk_t *tmp = (list_lnk_t *) xalloc(sizeof(list_lnk_t) + ptr->data_len); + memcpy(tmp->data, data, ptr->data_len); + + if (ptr->size++) { + tmp->next_ptr = NULL; + tmp->prev_ptr = ptr->tail_ptr; + ptr->tail_ptr->next_ptr = tmp; + ptr->tail_ptr = tmp; + } else { + tmp->next_ptr = NULL; + tmp->prev_ptr = NULL; + ptr->head_ptr = tmp; + ptr->tail_ptr = tmp; + } +} + +void list_pop_front(list_t *ptr, void *data) +{ + list_lnk_t *tmp = ptr->head_ptr; + + if (data) { + memcpy(data, tmp->data, ptr->data_len); + } + + if (tmp->next_ptr) { + tmp->next_ptr->prev_ptr = NULL; + } + ptr->head_ptr = tmp->next_ptr; + ptr->size -= 1; + xfree(tmp); +} + +void list_pop_back(list_t *ptr, void *data) +{ + list_lnk_t *tmp = ptr->tail_ptr; + + if (data) { + memcpy(data, tmp->data, ptr->data_len); + } + + tmp->prev_ptr->next_ptr = NULL; + ptr->tail_ptr = tmp->prev_ptr; + ptr->size -= 1; + xfree(tmp); +} + +void list_get_front(list_t *ptr, void *data) +{ + memcpy(data, ptr->head_ptr->data, ptr->data_len); +} + +void list_get_back(list_t *ptr, void *data) +{ + memcpy(data, ptr->tail_ptr->data, ptr->data_len); +} + +void list_set_front(list_t *ptr, void *data) +{ + memcpy(ptr->head_ptr->data, data, ptr->data_len); +} + +void list_set_back(list_t *ptr, void *data) +{ + memcpy(ptr->tail_ptr->data, data, ptr->data_len); +} + +void list_insert(list_t *ptr, void *data, size_t index) +{ + if (index == 0) { + list_push_front(ptr, data); + } else if (index >= ptr->size) { + list_push_back(ptr, data); + } else if (index < (ptr->size >> 1)) { + + list_lnk_t *i = ptr->head_ptr; + + while (index) { + i = i->next_ptr; + index -= 1; + } + + list_lnk_t *tmp = (list_lnk_t *) xalloc(sizeof(list_lnk_t) + ptr->data_len); + memcpy(tmp->data, data, ptr->data_len); + + tmp->next_ptr = i; + tmp->prev_ptr = i->prev_ptr; + i->prev_ptr->next_ptr = tmp; + i->prev_ptr = tmp; + ptr->size += 1; + + } else { + + list_lnk_t *i = ptr->tail_ptr; + index = ptr->size - index - 1; + + while (index) { + i = i->prev_ptr; + index -= 1; + } + + list_lnk_t *tmp = (list_lnk_t *) xalloc(sizeof(list_lnk_t) + ptr->data_len); + memcpy(tmp->data, data, ptr->data_len); + + tmp->next_ptr = i; + tmp->prev_ptr = i->prev_ptr; + i->prev_ptr->next_ptr = tmp; + i->prev_ptr = tmp; + ptr->size += 1; + } +} + +void list_remove(list_t *ptr, void *data, size_t index) +{ + if (index == 0) { + list_pop_front(ptr, data); + } else if (index >= (ptr->size - 1)) { + list_pop_back(ptr, data); + } else if (index < (ptr->size >> 1)) { + + list_lnk_t *i = ptr->head_ptr; + + while (index) { + i = i->next_ptr; + index -= 1; + } + + if (data) { + memcpy(data, i->data, ptr->data_len); + } + + i->prev_ptr->next_ptr = i->next_ptr; + i->next_ptr->prev_ptr = i->prev_ptr; + ptr->size -= 1; + xfree(i); + + } else { + + list_lnk_t *i = ptr->tail_ptr; + index = ptr->size - index - 1; + + while (index) { + i = i->prev_ptr; + index -= 1; + } + + if (data) { + memcpy(data, i->data, ptr->data_len); + } + + i->prev_ptr->next_ptr = i->next_ptr; + i->next_ptr->prev_ptr = i->prev_ptr; + ptr->size -= 1; + xfree(i); + } +} + +void list_get(list_t *ptr, void *data, size_t index) +{ + if (index == 0) { + list_get_front(ptr, data); + } else if (index >= (ptr->size - 1)) { + list_get_back(ptr, data); + } else if (index < (ptr->size >> 1)) { + + list_lnk_t *i = ptr->head_ptr; + + while (index) { + i = i->next_ptr; + index -= 1; + } + + memcpy(data, i->data, ptr->data_len); + + } else { + + list_lnk_t *i = ptr->tail_ptr; + index = ptr->size - index - 1; + + while (index) { + i = i->prev_ptr; + index -= 1; + } + + memcpy(data, i->data, ptr->data_len); + } +} + +void list_set(list_t *ptr, void *data, size_t index) +{ + if (index == 0) { + list_set_front(ptr, data); + } else if (index >= (ptr->size - 1)) { + list_set_back(ptr, data); + } else if (index < (ptr->size >> 1)) { + + list_lnk_t *i = ptr->head_ptr; + + while (index) { + i = i->next_ptr; + index -= 1; + } + + memcpy(i->data, data, ptr->data_len); + + } else { + + list_lnk_t *i = ptr->tail_ptr; + index = ptr->size - index - 1; + + while (index) { + i = i->prev_ptr; + index -= 1; + } + + memcpy(i->data, data, ptr->data_len); + } +} + +////////////// +// iterator // +////////////// + +list_lnk_t *iterator_start_from_head(list_t *ptr) +{ + return ptr->head_ptr; +} + +list_lnk_t *iterator_start_from_tail(list_t *ptr) +{ + return ptr->tail_ptr; +} + +list_lnk_t *iterator_next(list_lnk_t *lnk) +{ + return lnk->next_ptr; +} + +list_lnk_t *iterator_prev(list_lnk_t *lnk) +{ + return lnk->prev_ptr; +} + +void iterator_get(list_t *ptr, list_lnk_t *lnk, void *data) +{ + memcpy(data, lnk->data, ptr->data_len); +} + +void iterator_set(list_t *ptr, list_lnk_t *lnk, void *data) +{ + memcpy(lnk->data, data, ptr->data_len); +} diff --git a/src/openmv/src/omv/img/collections.h b/src/openmv/src/omv/img/collections.h new file mode 100755 index 0000000..c6f4d19 --- /dev/null +++ b/src/openmv/src/omv/img/collections.h @@ -0,0 +1,123 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#ifndef __COLLECTIONS_H__ +#define __COLLECTIONS_H__ +#include +#include + +//////////// +// bitmap // +//////////// + +typedef struct bitmap +{ + size_t size; + char *data; +} +bitmap_t; + +void bitmap_alloc(bitmap_t *ptr, size_t size); +void bitmap_free(bitmap_t *ptr); +void bitmap_clear(bitmap_t *ptr); +void bitmap_bit_set(bitmap_t *ptr, size_t index); +bool bitmap_bit_get(bitmap_t *ptr, size_t index); +#define BITMAP_COMPUTE_ROW_INDEX(image, y) (((image)->w)*(y)) +#define BITMAP_COMPUTE_INDEX(row_index, x) ((row_index)+(x)) + +////////// +// lifo // +////////// + +typedef struct lifo +{ + size_t len, size, data_len; + char *data; +} +lifo_t; + +void lifo_alloc(lifo_t *ptr, size_t size, size_t data_len); +void lifo_alloc_all(lifo_t *ptr, size_t *size, size_t data_len); +void lifo_free(lifo_t *ptr); +void lifo_clear(lifo_t *ptr); +size_t lifo_size(lifo_t *ptr); +bool lifo_is_not_empty(lifo_t *ptr); +bool lifo_is_not_full(lifo_t *ptr); +void lifo_enqueue(lifo_t *ptr, void *data); +void lifo_dequeue(lifo_t *ptr, void *data); +void lifo_poke(lifo_t *ptr, void *data); +void lifo_peek(lifo_t *ptr, void *data); + +////////// +// fifo // +////////// + +typedef struct fifo +{ + size_t head_ptr, tail_ptr, len, size, data_len; + char *data; +} +fifo_t; + +void fifo_alloc(fifo_t *ptr, size_t size, size_t data_len); +void fifo_alloc_all(fifo_t *ptr, size_t *size, size_t data_len); +void fifo_free(fifo_t *ptr); +void fifo_clear(fifo_t *ptr); +size_t fifo_size(fifo_t *ptr); +bool fifo_is_not_empty(fifo_t *ptr); +bool fifo_is_not_full(fifo_t *ptr); +void fifo_enqueue(fifo_t *ptr, void *data); +void fifo_dequeue(fifo_t *ptr, void *data); +void fifo_poke(fifo_t *ptr, void *data); +void fifo_peek(fifo_t *ptr, void *data); + +////////// +// list // +////////// + +typedef struct list_lnk +{ + struct list_lnk *next_ptr, *prev_ptr; + char data[]; +} +list_lnk_t; + +typedef struct list +{ + list_lnk_t *head_ptr, *tail_ptr; + size_t size, data_len; +} +list_t; + +void list_init(list_t *ptr, size_t data_len); +void list_copy(list_t *dst, list_t *src); +void list_free(list_t *ptr); +void list_clear(list_t *ptr); +size_t list_size(list_t *ptr); +void list_push_front(list_t *ptr, void *data); +void list_push_back(list_t *ptr, void *data); +void list_pop_front(list_t *ptr, void *data); +void list_pop_back(list_t *ptr, void *data); +void list_get_front(list_t *ptr, void *data); +void list_get_back(list_t *ptr, void *data); +void list_set_front(list_t *ptr, void *data); +void list_set_back(list_t *ptr, void *data); +void list_insert(list_t *ptr, void *data, size_t index); +void list_remove(list_t *ptr, void *data, size_t index); +void list_get(list_t *ptr, void *data, size_t index); +void list_set(list_t *ptr, void *data, size_t index); + +////////////// +// iterator // +////////////// + +list_lnk_t *iterator_start_from_head(list_t *ptr); +list_lnk_t *iterator_start_from_tail(list_t *ptr); +list_lnk_t *iterator_next(list_lnk_t *lnk); +list_lnk_t *iterator_prev(list_lnk_t *lnk); +void iterator_get(list_t *ptr, list_lnk_t *lnk, void *data); +void iterator_set(list_t *ptr, list_lnk_t *lnk, void *data); + +#endif /* __COLLECTIONS_H__ */ diff --git a/src/openmv/src/omv/img/dmtx.c b/src/openmv/src/omv/img/dmtx.c new file mode 100755 index 0000000..1a94db2 --- /dev/null +++ b/src/openmv/src/omv/img/dmtx.c @@ -0,0 +1,6390 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include "imlib.h" +#ifdef IMLIB_ENABLE_DATAMATRICES +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define perror(str) +#define fprintf(stream, format, ...) +#define fputc(character, stream) +#define snprintf(s, c, format, ...) 0 +#define free(ptr) ({ umm_free(ptr); }) +#define malloc(size) ({ void *_r = umm_malloc(size); if(!_r) fb_alloc_fail(); _r; }) +#define realloc(ptr, size) ({ void *_r = umm_realloc((ptr), (size)); if(!_r) fb_alloc_fail(); _r; }) +#define calloc(num, item_size) ({ void *_r = umm_calloc((num), (item_size)); if(!_r) fb_alloc_fail(); _r; }) +#define assert(expression) +#define double float +#undef DBL_MIN +#define DBL_MIN FLT_MIN +#undef DBL_MAX +#define DBL_MAX FLT_MAX +#define sqrt(x) fast_sqrtf(x) +#define sqrtf(x) fast_sqrtf(x) +#define floor(x) fast_floorf(x) +#define floorf(x) fast_floorf(x) +#define ceil(x) fast_ceilf(x) +#define ceilf(x) fast_ceilf(x) +#define round(x) fast_roundf(x) +#define roundf(x) fast_roundf(x) +#define atan(x) fast_atanf(x) +#define atanf(x) fast_atanf(x) +#define atan2(y, x) fast_atan2f((y), (x)) +#define atan2f(y, x) fast_atan2f((y), (x)) +#define exp(x) fast_expf(x) +#define expf(x) fast_expf(x) +#define cbrt(x) fast_cbrtf(x) +#define cbrtf(x) fast_cbrtf(x) +#define fabs(x) fast_fabsf(x) +#define fabsf(x) fast_fabsf(x) +#define log(x) fast_log(x) +#define logf(x) fast_log(x) +#undef log2 +#define log2(x) fast_log2(x) +#undef log2f +#define log2f(x) fast_log2(x) +#define cos(x) cosf(x) +#define sin(x) sinf(x) +#define acos(x) acosf(x) +#define asin(x) asinf(x) + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtx.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtx.h + * \brief Main libdmtx header + */ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif + +#define DmtxVersion "0.7.5" + +#define DmtxUndefined -1 + +#define DmtxPassFail unsigned int +#define DmtxPass 1 +#define DmtxFail 0 + +#define DmtxBoolean unsigned int +#define DmtxTrue 1 +#define DmtxFalse 0 + +#define DmtxFormatMatrix 0 +#define DmtxFormatMosaic 1 + +#define DmtxSymbolSquareCount 24 +#define DmtxSymbolRectCount 6 + +#define DmtxModuleOff 0x00 +#define DmtxModuleOnRed 0x01 +#define DmtxModuleOnGreen 0x02 +#define DmtxModuleOnBlue 0x04 +#define DmtxModuleOnRGB 0x07 /* OnRed | OnGreen | OnBlue */ +#define DmtxModuleOn 0x07 +#define DmtxModuleUnsure 0x08 +#define DmtxModuleAssigned 0x10 +#define DmtxModuleVisited 0x20 +#define DmtxModuleData 0x40 + +#define DMTX_CHECK_BOUNDS(l,i) (assert((i) >= 0 && (i) < (l)->length && (l)->length <= (l)->capacity)) + +typedef enum { + DmtxSchemeAutoFast = -2, + DmtxSchemeAutoBest = -1, + DmtxSchemeAscii = 0, + DmtxSchemeC40, + DmtxSchemeText, + DmtxSchemeX12, + DmtxSchemeEdifact, + DmtxSchemeBase256 +} DmtxScheme; + +typedef enum { + DmtxSymbolRectAuto = -3, + DmtxSymbolSquareAuto = -2, + DmtxSymbolShapeAuto = -1, + DmtxSymbol10x10 = 0, + DmtxSymbol12x12, + DmtxSymbol14x14, + DmtxSymbol16x16, + DmtxSymbol18x18, + DmtxSymbol20x20, + DmtxSymbol22x22, + DmtxSymbol24x24, + DmtxSymbol26x26, + DmtxSymbol32x32, + DmtxSymbol36x36, + DmtxSymbol40x40, + DmtxSymbol44x44, + DmtxSymbol48x48, + DmtxSymbol52x52, + DmtxSymbol64x64, + DmtxSymbol72x72, + DmtxSymbol80x80, + DmtxSymbol88x88, + DmtxSymbol96x96, + DmtxSymbol104x104, + DmtxSymbol120x120, + DmtxSymbol132x132, + DmtxSymbol144x144, + DmtxSymbol8x18, + DmtxSymbol8x32, + DmtxSymbol12x26, + DmtxSymbol12x36, + DmtxSymbol16x36, + DmtxSymbol16x48 +} DmtxSymbolSize; + +typedef enum { + DmtxDirNone = 0x00, + DmtxDirUp = 0x01 << 0, + DmtxDirLeft = 0x01 << 1, + DmtxDirDown = 0x01 << 2, + DmtxDirRight = 0x01 << 3, + DmtxDirHorizontal = DmtxDirLeft | DmtxDirRight, + DmtxDirVertical = DmtxDirUp | DmtxDirDown, + DmtxDirRightUp = DmtxDirRight | DmtxDirUp, + DmtxDirLeftDown = DmtxDirLeft | DmtxDirDown +} DmtxDirection; + +typedef enum { + DmtxSymAttribSymbolRows, + DmtxSymAttribSymbolCols, + DmtxSymAttribDataRegionRows, + DmtxSymAttribDataRegionCols, + DmtxSymAttribHorizDataRegions, + DmtxSymAttribVertDataRegions, + DmtxSymAttribMappingMatrixRows, + DmtxSymAttribMappingMatrixCols, + DmtxSymAttribInterleavedBlocks, + DmtxSymAttribBlockErrorWords, + DmtxSymAttribBlockMaxCorrectable, + DmtxSymAttribSymbolDataWords, + DmtxSymAttribSymbolErrorWords, + DmtxSymAttribSymbolMaxCorrectable +} DmtxSymAttribute; + +typedef enum { + /* Encoding properties */ + DmtxPropScheme = 100, + DmtxPropSizeRequest, + DmtxPropMarginSize, + DmtxPropModuleSize, + /* Decoding properties */ + DmtxPropEdgeMin = 200, + DmtxPropEdgeMax, + DmtxPropScanGap, + DmtxPropSquareDevn, + DmtxPropSymbolSize, + DmtxPropEdgeThresh, + /* Image properties */ + DmtxPropWidth = 300, + DmtxPropHeight, + DmtxPropPixelPacking, + DmtxPropBitsPerPixel, + DmtxPropBytesPerPixel, + DmtxPropRowPadBytes, + DmtxPropRowSizeBytes, + DmtxPropImageFlip, + DmtxPropChannelCount, + /* Image modifiers */ + DmtxPropXmin = 400, + DmtxPropXmax, + DmtxPropYmin, + DmtxPropYmax, + DmtxPropScale +} DmtxProperty; + +typedef enum { + /* Custom format */ + DmtxPackCustom = 100, + /* 1 bpp */ + DmtxPack1bppK = 200, + /* 8 bpp grayscale */ + DmtxPack8bppK = 300, + /* 16 bpp formats */ + DmtxPack16bppRGB = 400, + DmtxPack16bppRGBX, + DmtxPack16bppXRGB, + DmtxPack16bppBGR, + DmtxPack16bppBGRX, + DmtxPack16bppXBGR, + DmtxPack16bppYCbCr, + /* 24 bpp formats */ + DmtxPack24bppRGB = 500, + DmtxPack24bppBGR, + DmtxPack24bppYCbCr, + /* 32 bpp formats */ + DmtxPack32bppRGBX = 600, + DmtxPack32bppXRGB, + DmtxPack32bppBGRX, + DmtxPack32bppXBGR, + DmtxPack32bppCMYK +} DmtxPackOrder; + +typedef enum { + DmtxFlipNone = 0x00, + DmtxFlipX = 0x01 << 0, + DmtxFlipY = 0x01 << 1 +} DmtxFlip; + +typedef double DmtxMatrix3[3][3]; + +/** + * @struct DmtxPixelLoc + * @brief DmtxPixelLoc + */ +typedef struct DmtxPixelLoc_struct { + int X; + int Y; +} DmtxPixelLoc; + +/** + * @struct DmtxVector2 + * @brief DmtxVector2 + */ +typedef struct DmtxVector2_struct { + double X; + double Y; +} DmtxVector2; + +/** + * @struct DmtxRay2 + * @brief DmtxRay2 + */ +typedef struct DmtxRay2_struct { + double tMin; + double tMax; + DmtxVector2 p; + DmtxVector2 v; +} DmtxRay2; + +typedef unsigned char DmtxByte; + +/** + * @struct DmtxByteList + * @brief DmtxByteList + * Use signed int for length fields instead of size_t to play nicely with RS + * arithmetic + */ +typedef struct DmtxByteList_struct DmtxByteList; +struct DmtxByteList_struct +{ + int length; + int capacity; + DmtxByte *b; +}; + +/** + * @struct DmtxImage + * @brief DmtxImage + */ +typedef struct DmtxImage_struct { + int width; + int height; + int pixelPacking; + int bitsPerPixel; + int bytesPerPixel; + int rowPadBytes; + int rowSizeBytes; + int imageFlip; + int channelCount; + int channelStart[4]; + int bitsPerChannel[4]; + unsigned char *pxl; +} DmtxImage; + +/** + * @struct DmtxPointFlow + * @brief DmtxPointFlow + */ +typedef struct DmtxPointFlow_struct { + int plane; + int arrive; + int depart; + int mag; + DmtxPixelLoc loc; +} DmtxPointFlow; + +/** + * @struct DmtxBestLine + * @brief DmtxBestLine + */ +typedef struct DmtxBestLine_struct { + int angle; + int hOffset; + int mag; + int stepBeg; + int stepPos; + int stepNeg; + int distSq; + double devn; + DmtxPixelLoc locBeg; + DmtxPixelLoc locPos; + DmtxPixelLoc locNeg; +} DmtxBestLine; + +/** + * @struct DmtxRegion + * @brief DmtxRegion + */ +typedef struct DmtxRegion_struct { + + /* Trail blazing values */ + int jumpToPos; /* */ + int jumpToNeg; /* */ + int stepsTotal; /* */ + DmtxPixelLoc finalPos; /* */ + DmtxPixelLoc finalNeg; /* */ + DmtxPixelLoc boundMin; /* */ + DmtxPixelLoc boundMax; /* */ + DmtxPointFlow flowBegin; /* */ + + /* Orientation values */ + int polarity; /* */ + int stepR; + int stepT; + DmtxPixelLoc locR; /* remove if stepR works above */ + DmtxPixelLoc locT; /* remove if stepT works above */ + + /* Region fitting values */ + int leftKnown; /* known == 1; unknown == 0 */ + int leftAngle; /* hough angle of left edge */ + DmtxPixelLoc leftLoc; /* known (arbitrary) location on left edge */ + DmtxBestLine leftLine; /* */ + int bottomKnown; /* known == 1; unknown == 0 */ + int bottomAngle; /* hough angle of bottom edge */ + DmtxPixelLoc bottomLoc; /* known (arbitrary) location on bottom edge */ + DmtxBestLine bottomLine; /* */ + int topKnown; /* known == 1; unknown == 0 */ + int topAngle; /* hough angle of top edge */ + DmtxPixelLoc topLoc; /* known (arbitrary) location on top edge */ + int rightKnown; /* known == 1; unknown == 0 */ + int rightAngle; /* hough angle of right edge */ + DmtxPixelLoc rightLoc; /* known (arbitrary) location on right edge */ + + /* Region calibration values */ + int onColor; /* */ + int offColor; /* */ + int sizeIdx; /* Index of arrays that store Data Matrix constants */ + int symbolRows; /* Number of total rows in symbol including alignment patterns */ + int symbolCols; /* Number of total columns in symbol including alignment patterns */ + int mappingRows; /* Number of data rows in symbol */ + int mappingCols; /* Number of data columns in symbol */ + + /* Transform values */ + DmtxMatrix3 raw2fit; /* 3x3 transformation from raw image to fitted barcode grid */ + DmtxMatrix3 fit2raw; /* 3x3 transformation from fitted barcode grid to raw image */ +} DmtxRegion; + +/** + * @struct DmtxMessage + * @brief DmtxMessage + */ +typedef struct DmtxMessage_struct { + size_t arraySize; /* mappingRows * mappingCols */ + size_t codeSize; /* Size of encoded data (data words + error words) */ + size_t outputSize; /* Size of buffer used to hold decoded data */ + int outputIdx; /* Internal index used to store output progress */ + int padCount; + unsigned char *array; /* Pointer to internal representation of Data Matrix modules */ + unsigned char *code; /* Pointer to internal storage of code words (data and error) */ + unsigned char *output; /* Pointer to internal storage of decoded output */ +} DmtxMessage; + +/** + * @struct DmtxScanGrid + * @brief DmtxScanGrid + */ +typedef struct DmtxScanGrid_struct { + /* set once */ + int minExtent; /* Smallest cross size used in scan */ + int maxExtent; /* Size of bounding grid region (2^N - 1) */ + int xOffset; /* Offset to obtain image X coordinate */ + int yOffset; /* Offset to obtain image Y coordinate */ + int xMin; /* Minimum X in image coordinate system */ + int xMax; /* Maximum X in image coordinate system */ + int yMin; /* Minimum Y in image coordinate system */ + int yMax; /* Maximum Y in image coordinate system */ + + /* reset for each level */ + int total; /* Total number of crosses at this size */ + int extent; /* Length/width of cross in pixels */ + int jumpSize; /* Distance in pixels between cross centers */ + int pixelTotal; /* Total pixel count within an individual cross path */ + int startPos; /* X and Y coordinate of first cross center in pattern */ + + /* reset for each cross */ + int pixelCount; /* Progress (pixel count) within current cross pattern */ + int xCenter; /* X center of current cross pattern */ + int yCenter; /* Y center of current cross pattern */ +} DmtxScanGrid; + +/** + * @struct DmtxDecode + * @brief DmtxDecode + */ +typedef struct DmtxDecode_struct { + /* Options */ + int edgeMin; + int edgeMax; + int scanGap; + double squareDevn; + int sizeIdxExpected; + int edgeThresh; + + /* Image modifiers */ + int xMin; + int xMax; + int yMin; + int yMax; + int scale; + + /* Internals */ +/* int cacheComplete; */ + unsigned char *cache; + DmtxImage *image; + DmtxScanGrid grid; +} DmtxDecode; + +/* dmtxdecode.c */ +extern DmtxDecode *dmtxDecodeCreate(DmtxImage *img, int scale); +extern DmtxPassFail dmtxDecodeDestroy(DmtxDecode **dec); +extern DmtxPassFail dmtxDecodeSetProp(DmtxDecode *dec, int prop, int value); +extern int dmtxDecodeGetProp(DmtxDecode *dec, int prop); +extern /*@exposed@*/ unsigned char *dmtxDecodeGetCache(DmtxDecode *dec, int x, int y); +extern DmtxPassFail dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, /*@out@*/ int *value); +extern DmtxMessage *dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix); +extern DmtxMessage *dmtxDecodeMosaicRegion(DmtxDecode *dec, DmtxRegion *reg, int fix); + +/* dmtxregion.c */ +extern DmtxRegion *dmtxRegionCreate(DmtxRegion *reg); +extern DmtxPassFail dmtxRegionDestroy(DmtxRegion **reg); +extern DmtxRegion *dmtxRegionFindNext(DmtxDecode *dec, int max_iterations, int *current_iterations); +extern DmtxRegion *dmtxRegionScanPixel(DmtxDecode *dec, int x, int y); +extern DmtxPassFail dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00, + DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01); +extern DmtxPassFail dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg); + +/* dmtxmessage.c */ +extern DmtxMessage *dmtxMessageCreate(int sizeIdx, int symbolFormat); +extern DmtxPassFail dmtxMessageDestroy(DmtxMessage **msg); + +/* dmtximage.c */ +extern DmtxImage *dmtxImageCreate(unsigned char *pxl, int width, int height, int pack); +extern DmtxPassFail dmtxImageDestroy(DmtxImage **img); +extern DmtxPassFail dmtxImageSetChannel(DmtxImage *img, int channelStart, int bitsPerChannel); +extern DmtxPassFail dmtxImageSetProp(DmtxImage *img, int prop, int value); +extern int dmtxImageGetProp(DmtxImage *img, int prop); +extern int dmtxImageGetByteOffset(DmtxImage *img, int x, int y); +extern DmtxPassFail dmtxImageGetPixelValue(DmtxImage *img, int x, int y, int channel, /*@out@*/ int *value); +extern DmtxPassFail dmtxImageSetPixelValue(DmtxImage *img, int x, int y, int channel, int value); +extern DmtxBoolean dmtxImageContainsInt(DmtxImage *img, int margin, int x, int y); +extern DmtxBoolean dmtxImageContainsFloat(DmtxImage *img, double x, double y); + +/* dmtxvector2.c */ +extern DmtxVector2 *dmtxVector2AddTo(DmtxVector2 *v1, const DmtxVector2 *v2); +extern DmtxVector2 *dmtxVector2Add(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2); +extern DmtxVector2 *dmtxVector2SubFrom(DmtxVector2 *v1, const DmtxVector2 *v2); +extern DmtxVector2 *dmtxVector2Sub(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2); +extern DmtxVector2 *dmtxVector2ScaleBy(DmtxVector2 *v, double s); +extern DmtxVector2 *dmtxVector2Scale(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v, double s); +extern double dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2); +extern double dmtxVector2Norm(DmtxVector2 *v); +extern double dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2); +extern double dmtxVector2Mag(const DmtxVector2 *v); +extern double dmtxDistanceFromRay2(const DmtxRay2 *r, const DmtxVector2 *q); +extern double dmtxDistanceAlongRay2(const DmtxRay2 *r, const DmtxVector2 *q); +extern DmtxPassFail dmtxRay2Intersect(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1); +extern DmtxPassFail dmtxPointAlongRay2(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *r, double t); + +/* dmtxmatrix3.c */ +extern void dmtxMatrix3Copy(/*@out@*/ DmtxMatrix3 m0, DmtxMatrix3 m1); +extern void dmtxMatrix3Identity(/*@out@*/ DmtxMatrix3 m); +extern void dmtxMatrix3Translate(/*@out@*/ DmtxMatrix3 m, double tx, double ty); +extern void dmtxMatrix3Rotate(/*@out@*/ DmtxMatrix3 m, double angle); +extern void dmtxMatrix3Scale(/*@out@*/ DmtxMatrix3 m, double sx, double sy); +extern void dmtxMatrix3Shear(/*@out@*/ DmtxMatrix3 m, double shx, double shy); +extern void dmtxMatrix3LineSkewTop(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz); +extern void dmtxMatrix3LineSkewTopInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz); +extern void dmtxMatrix3LineSkewSide(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz); +extern void dmtxMatrix3LineSkewSideInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz); +extern void dmtxMatrix3Multiply(/*@out@*/ DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1); +extern void dmtxMatrix3MultiplyBy(DmtxMatrix3 m0, DmtxMatrix3 m1); +extern int dmtxMatrix3VMultiply(/*@out@*/ DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m); +extern int dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m); +extern void dmtxMatrix3Print(DmtxMatrix3 m); + +/* dmtxsymbol.c */ +extern int dmtxSymbolModuleStatus(DmtxMessage *mapping, int sizeIdx, int row, int col); +extern int dmtxGetSymbolAttribute(int attribute, int sizeIdx); +extern int dmtxGetBlockDataSize(int sizeIdx, int blockIdx); + +/* dmtxbytelist.c */ +extern DmtxByteList dmtxByteListBuild(DmtxByte *storage, int capacity); +extern void dmtxByteListInit(DmtxByteList *list, int length, DmtxByte value, DmtxPassFail *passFail); +extern void dmtxByteListClear(DmtxByteList *list); +extern DmtxBoolean dmtxByteListHasCapacity(DmtxByteList *list); +extern void dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail); +extern void dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail); +extern DmtxByte dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail); +extern void dmtxByteListPrint(DmtxByteList *list, char *prefix); + +extern char *dmtxVersion(void); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxstatic.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxstatic.h + * \brief Static header + */ + +#define DmtxAlmostZero 0.000001 +#define DmtxAlmostInfinity -1 + +#define DmtxValueC40Latch 230 +#define DmtxValueTextLatch 239 +#define DmtxValueX12Latch 238 +#define DmtxValueEdifactLatch 240 +#define DmtxValueBase256Latch 231 + +#define DmtxValueCTXUnlatch 254 +#define DmtxValueEdifactUnlatch 31 + +#define DmtxValueAsciiPad 129 +#define DmtxValueAsciiUpperShift 235 +#define DmtxValueCTXShift1 0 +#define DmtxValueCTXShift2 1 +#define DmtxValueCTXShift3 2 +#define DmtxValueFNC1 232 +#define DmtxValueStructuredAppend 233 +#define DmtxValue05Macro 236 +#define DmtxValue06Macro 237 +#define DmtxValueECI 241 + +#define DmtxC40TextBasicSet 0 +#define DmtxC40TextShift1 1 +#define DmtxC40TextShift2 2 +#define DmtxC40TextShift3 3 + +#define DmtxUnlatchExplicit 0 +#define DmtxUnlatchImplicit 1 + +#define DmtxChannelValid 0x00 +#define DmtxChannelUnsupportedChar 0x01 << 0 +#define DmtxChannelCannotUnlatch 0x01 << 1 + +#undef min +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) + +#undef max +#define max(X,Y) (((X) > (Y)) ? (X) : (Y)) + +typedef enum { + DmtxRangeGood, + DmtxRangeBad, + DmtxRangeEnd +} DmtxRange; + +typedef enum { + DmtxEdgeTop = 0x01 << 0, + DmtxEdgeBottom = 0x01 << 1, + DmtxEdgeLeft = 0x01 << 2, + DmtxEdgeRight = 0x01 << 3 +} DmtxEdge; + +typedef enum { + DmtxMaskBit8 = 0x01 << 0, + DmtxMaskBit7 = 0x01 << 1, + DmtxMaskBit6 = 0x01 << 2, + DmtxMaskBit5 = 0x01 << 3, + DmtxMaskBit4 = 0x01 << 4, + DmtxMaskBit3 = 0x01 << 5, + DmtxMaskBit2 = 0x01 << 6, + DmtxMaskBit1 = 0x01 << 7 +} DmtxMaskBit; + +/** + * @struct DmtxFollow + * @brief DmtxFollow + */ +typedef struct DmtxFollow_struct { + unsigned char *ptr; + unsigned char neighbor; + int step; + DmtxPixelLoc loc; +} DmtxFollow; + +/** + * @struct DmtxBresLine + * @brief DmtxBresLine + */ +typedef struct DmtxBresLine_struct { + int xStep; + int yStep; + int xDelta; + int yDelta; + int steep; + int xOut; + int yOut; + int travel; + int outward; + int error; + DmtxPixelLoc loc; + DmtxPixelLoc loc0; + DmtxPixelLoc loc1; +} DmtxBresLine; + +typedef struct C40TextState_struct { + int shift; + DmtxBoolean upperShift; +} C40TextState; + +/* dmtxregion.c */ +static double RightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle); +static DmtxPointFlow MatrixRegionSeekEdge(DmtxDecode *dec, DmtxPixelLoc loc0); +static DmtxPassFail MatrixRegionOrientation(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin); +static long DistanceSquared(DmtxPixelLoc a, DmtxPixelLoc b); +static int ReadModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx, int colorPlane); + +static DmtxPassFail MatrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg); +static int CountJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir); +static DmtxPointFlow GetPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive); +static DmtxPointFlow FindStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign); +static DmtxFollow FollowSeek(DmtxDecode *dec, DmtxRegion *reg, int seek); +static DmtxFollow FollowSeekLoc(DmtxDecode *dec, DmtxPixelLoc loc); +static DmtxFollow FollowStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign); +static DmtxFollow FollowStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign); +static DmtxPassFail TrailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal); +static int TrailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir); +static int TrailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask); +static DmtxBestLine FindBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir, int houghAvoid); +static DmtxBestLine FindBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid); +static DmtxPassFail FindTravelLimits(DmtxDecode *dec, DmtxRegion *reg, DmtxBestLine *line); +static DmtxPassFail MatrixRegionAlignCalibEdge(DmtxDecode *dec, DmtxRegion *reg, int whichEdge); +static DmtxBresLine BresLineInit(DmtxPixelLoc loc0, DmtxPixelLoc loc1, DmtxPixelLoc locInside); +static DmtxPassFail BresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward); +static DmtxPassFail BresLineStep(DmtxBresLine *line, int travel, int outward); +/*static void WriteDiagnosticImage(DmtxDecode *dec, DmtxRegion *reg, char *imagePath);*/ + +/* dmtxdecode.c */ +static void TallyModuleJumps(DmtxDecode *dec, DmtxRegion *reg, int tally[][24], int xOrigin, int yOrigin, int mapWidth, int mapHeight, DmtxDirection dir); +static DmtxPassFail PopulateArrayFromMatrix(DmtxDecode *dec, DmtxRegion *reg, DmtxMessage *msg); + +/* dmtxdecodescheme.c */ +static void DecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart); +static int GetEncodationScheme(unsigned char cw); +static void PushOutputWord(DmtxMessage *msg, int value); +static void PushOutputC40TextWord(DmtxMessage *msg, C40TextState *state, int value); +static void PushOutputMacroHeader(DmtxMessage *msg, int macroType); +static void PushOutputMacroTrailer(DmtxMessage *msg); +static unsigned char *DecodeSchemeAscii(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd); +static unsigned char *DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxScheme encScheme); +static unsigned char *DecodeSchemeX12(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd); +static unsigned char *DecodeSchemeEdifact(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd); +static unsigned char *DecodeSchemeBase256(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd); + +/* dmtxplacemod.c */ +static int ModulePlacementEcc200(unsigned char *modules, unsigned char *codewords, int sizeIdx, int moduleOnColor); +static void PatternShapeStandard(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int moduleOnColor); +static void PatternShapeSpecial1(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor); +static void PatternShapeSpecial2(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor); +static void PatternShapeSpecial3(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor); +static void PatternShapeSpecial4(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor); +static void PlaceModule(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, + unsigned char *codeword, int mask, int moduleOnColor); + +/* dmtxreedsol.c */ +static DmtxPassFail RsDecode(unsigned char *code, int sizeIdx, int fix); +static DmtxBoolean RsComputeSyndromes(DmtxByteList *syn, const DmtxByteList *rec, int blockErrorWords); +static DmtxBoolean RsFindErrorLocatorPoly(DmtxByteList *elp, const DmtxByteList *syn, int errorWordCount, int maxCorrectable); +static DmtxBoolean RsFindErrorLocations(DmtxByteList *loc, const DmtxByteList *elp); +static DmtxPassFail RsRepairErrors(DmtxByteList *rec, const DmtxByteList *loc, const DmtxByteList *elp, const DmtxByteList *syn); + +/* dmtxscangrid.c */ +static DmtxScanGrid InitScanGrid(DmtxDecode *dec); +static int PopGridLocation(DmtxScanGrid *grid, /*@out@*/ DmtxPixelLoc *locPtr); +static int GetGridCoordinates(DmtxScanGrid *grid, /*@out@*/ DmtxPixelLoc *locPtr); +static void SetDerivedFields(DmtxScanGrid *grid); + +/* dmtximage.c */ +static int GetBitsPerPixel(int pack); + +/* dmtxencodebase256.c */ +static unsigned char UnRandomize255State(unsigned char value, int idx); + +static const int dmtxNeighborNone = 8; +static const int dmtxPatternX[] = { -1, 0, 1, 1, 1, 0, -1, -1 }; +static const int dmtxPatternY[] = { -1, -1, -1, 0, 1, 1, 1, 0 }; +static const DmtxPointFlow dmtxBlankEdge = { 0, 0, 0, DmtxUndefined, { -1, -1 } }; + +/*@ +charint @*/ + +static int rHvX[] = + { 256, 256, 256, 256, 255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 248, + 247, 246, 245, 243, 242, 241, 239, 237, 236, 234, 232, 230, 228, 226, 224, + 222, 219, 217, 215, 212, 210, 207, 204, 202, 199, 196, 193, 190, 187, 184, + 181, 178, 175, 171, 168, 165, 161, 158, 154, 150, 147, 143, 139, 136, 132, + 128, 124, 120, 116, 112, 108, 104, 100, 96, 92, 88, 83, 79, 75, 71, + 66, 62, 58, 53, 49, 44, 40, 36, 31, 27, 22, 18, 13, 9, 4, + 0, -4, -9, -13, -18, -22, -27, -31, -36, -40, -44, -49, -53, -58, -62, + -66, -71, -75, -79, -83, -88, -92, -96, -100, -104, -108, -112, -116, -120, -124, + -128, -132, -136, -139, -143, -147, -150, -154, -158, -161, -165, -168, -171, -175, -178, + -181, -184, -187, -190, -193, -196, -199, -202, -204, -207, -210, -212, -215, -217, -219, + -222, -224, -226, -228, -230, -232, -234, -236, -237, -239, -241, -242, -243, -245, -246, + -247, -248, -249, -250, -251, -252, -253, -254, -254, -255, -255, -255, -256, -256, -256 }; + +static int rHvY[] = + { 0, 4, 9, 13, 18, 22, 27, 31, 36, 40, 44, 49, 53, 58, 62, + 66, 71, 75, 79, 83, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, + 128, 132, 136, 139, 143, 147, 150, 154, 158, 161, 165, 168, 171, 175, 178, + 181, 184, 187, 190, 193, 196, 199, 202, 204, 207, 210, 212, 215, 217, 219, + 222, 224, 226, 228, 230, 232, 234, 236, 237, 239, 241, 242, 243, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 254, 255, 255, 255, 256, 256, 256, + 256, 256, 256, 256, 255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 248, + 247, 246, 245, 243, 242, 241, 239, 237, 236, 234, 232, 230, 228, 226, 224, + 222, 219, 217, 215, 212, 210, 207, 204, 202, 199, 196, 193, 190, 187, 184, + 181, 178, 175, 171, 168, 165, 161, 158, 154, 150, 147, 143, 139, 136, 132, + 128, 124, 120, 116, 112, 108, 104, 100, 96, 92, 88, 83, 79, 75, 71, + 66, 62, 58, 53, 49, 44, 40, 36, 31, 27, 22, 18, 13, 9, 4 }; + +/*@ -charint @*/ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtx.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtx.c + * \brief Main libdmtx source file + */ + +#ifndef CALLBACK_POINT_PLOT +#define CALLBACK_POINT_PLOT(a,b,c,d) +#endif + +#ifndef CALLBACK_POINT_XFRM +#define CALLBACK_POINT_XFRM(a,b,c,d) +#endif + +#ifndef CALLBACK_MODULE +#define CALLBACK_MODULE(a,b,c,d,e) +#endif + +#ifndef CALLBACK_MATRIX +#define CALLBACK_MATRIX(a) +#endif + +#ifndef CALLBACK_FINAL +#define CALLBACK_FINAL(a,b) +#endif + +extern char * +dmtxVersion(void) +{ + return DmtxVersion; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxencodebase256.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2011 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxencodebase256.c + * \brief Base 256 encoding rules + */ + +/** + * \brief Unrandomize 255 state + * \param value + * \param idx + * \return Unrandomized value + */ +static unsigned char +UnRandomize255State(unsigned char value, int idx) +{ + int pseudoRandom; + int tmp; + + pseudoRandom = ((149 * idx) % 255) + 1; + tmp = value - pseudoRandom; + if(tmp < 0) + tmp += 256; + + assert(tmp >= 0 && tmp < 256); + + return (unsigned char)tmp; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxdecode.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * Copyright 2009 Mackenzie Straight. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxdecode.c + * \brief Decode regions + */ + +/** + * \brief Initialize decode struct with default values + * \param img + * \return Initialized DmtxDecode struct + */ +extern DmtxDecode * +dmtxDecodeCreate(DmtxImage *img, int scale) +{ + DmtxDecode *dec; + int width, height; + + dec = (DmtxDecode *)calloc(1, sizeof(DmtxDecode)); + if(dec == NULL) + return NULL; + + width = dmtxImageGetProp(img, DmtxPropWidth) / scale; + height = dmtxImageGetProp(img, DmtxPropHeight) / scale; + + dec->edgeMin = DmtxUndefined; + dec->edgeMax = DmtxUndefined; + dec->scanGap = 1; + dec->squareDevn = cos(50 * (M_PI/180)); + dec->sizeIdxExpected = DmtxSymbolShapeAuto; + dec->edgeThresh = 10; + + dec->xMin = 0; + dec->xMax = width - 1; + dec->yMin = 0; + dec->yMax = height - 1; + dec->scale = scale; + + dec->cache = (unsigned char *)calloc(width * height, sizeof(unsigned char)); + if(dec->cache == NULL) { + free(dec); + return NULL; + } + + dec->image = img; + dec->grid = InitScanGrid(dec); + + return dec; +} + +/** + * \brief Deinitialize decode struct + * \param dec + * \return void + */ +extern DmtxPassFail +dmtxDecodeDestroy(DmtxDecode **dec) +{ + if(dec == NULL || *dec == NULL) + return DmtxFail; + + if((*dec)->cache != NULL) + free((*dec)->cache); + + free(*dec); + + *dec = NULL; + + return DmtxPass; +} + +/** + * \brief Set decoding behavior property + * \param dec + * \param prop + * \param value + * \return DmtxPass | DmtxFail + */ +extern DmtxPassFail +dmtxDecodeSetProp(DmtxDecode *dec, int prop, int value) +{ + switch(prop) { + case DmtxPropEdgeMin: + dec->edgeMin = value; + break; + case DmtxPropEdgeMax: + dec->edgeMax = value; + break; + case DmtxPropScanGap: + dec->scanGap = value; /* XXX Should this be scaled? */ + break; + case DmtxPropSquareDevn: + dec->squareDevn = cos(value * (M_PI/180.0)); + break; + case DmtxPropSymbolSize: + dec->sizeIdxExpected = value; + break; + case DmtxPropEdgeThresh: + dec->edgeThresh = value; + break; + /* Min and Max values arrive unscaled */ + case DmtxPropXmin: + dec->xMin = value / dec->scale; + break; + case DmtxPropXmax: + dec->xMax = value / dec->scale; + break; + case DmtxPropYmin: + dec->yMin = value / dec->scale; + break; + case DmtxPropYmax: + dec->yMax = value / dec->scale; + break; + default: + break; + } + + if(dec->squareDevn <= 0.0 || dec->squareDevn >= 1.0) + return DmtxFail; + + if(dec->scanGap < 1) + return DmtxFail; + + if(dec->edgeThresh < 1 || dec->edgeThresh > 100) + return DmtxFail; + + /* Reinitialize scangrid in case any inputs changed */ + dec->grid = InitScanGrid(dec); + + return DmtxPass; +} + +/** + * \brief Get decoding behavior property + * \param dec + * \param prop + * \return value + */ +extern int +dmtxDecodeGetProp(DmtxDecode *dec, int prop) +{ + switch(prop) { + case DmtxPropEdgeMin: + return dec->edgeMin; + case DmtxPropEdgeMax: + return dec->edgeMax; + case DmtxPropScanGap: + return dec->scanGap; + case DmtxPropSquareDevn: + return (int)(acos(dec->squareDevn) * 180.0/M_PI); + case DmtxPropSymbolSize: + return dec->sizeIdxExpected; + case DmtxPropEdgeThresh: + return dec->edgeThresh; + case DmtxPropXmin: + return dec->xMin; + case DmtxPropXmax: + return dec->xMax; + case DmtxPropYmin: + return dec->yMin; + case DmtxPropYmax: + return dec->yMax; + case DmtxPropScale: + return dec->scale; + case DmtxPropWidth: + return dmtxImageGetProp(dec->image, DmtxPropWidth) / dec->scale; + case DmtxPropHeight: + return dmtxImageGetProp(dec->image, DmtxPropHeight) / dec->scale; + default: + break; + } + + return DmtxUndefined; +} + +/** + * \brief Returns xxx + * \param img + * \param Scaled x coordinate + * \param Scaled y coordinate + * \return Scaled pixel offset + */ +extern unsigned char * +dmtxDecodeGetCache(DmtxDecode *dec, int x, int y) +{ + int width, height; + + assert(dec != NULL); + +/* if(dec.cacheComplete == DmtxFalse) + CacheImage(); */ + + width = dmtxDecodeGetProp(dec, DmtxPropWidth); + height = dmtxDecodeGetProp(dec, DmtxPropHeight); + + if(x < 0 || x >= width || y < 0 || y >= height) + return NULL; + + return &(dec->cache[y * width + x]); +} + +/** + * + * + */ +extern DmtxPassFail +dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, int *value) +{ + int xUnscaled, yUnscaled; + DmtxPassFail err; + + xUnscaled = x * dec->scale; + yUnscaled = y * dec->scale; + +/* Remove spherical lens distortion */ +/* int width, height; + double radiusPow2, radiusPow4; + double factor; + DmtxVector2 pointShifted; + DmtxVector2 correctedPoint; + + width = dmtxImageGetProp(img, DmtxPropWidth); + height = dmtxImageGetProp(img, DmtxPropHeight); + + pointShifted.X = point.X - width/2.0; + pointShifted.Y = point.Y - height/2.0; + + radiusPow2 = pointShifted.X * pointShifted.X + pointShifted.Y * pointShifted.Y; + radiusPow4 = radiusPow2 * radiusPow2; + + factor = 1 + (k1 * radiusPow2) + (k2 * radiusPow4); + + correctedPoint.X = pointShifted.X * factor + width/2.0; + correctedPoint.Y = pointShifted.Y * factor + height/2.0; + + return correctedPoint; */ + + err = dmtxImageGetPixelValue(dec->image, xUnscaled, yUnscaled, channel, value); + + return err; +} + +/** + * \brief Fill the region covered by the quadrilateral given by (p0,p1,p2,p3) in the cache. + */ +static void +CacheFillQuad(DmtxDecode *dec, DmtxPixelLoc p0, DmtxPixelLoc p1, DmtxPixelLoc p2, DmtxPixelLoc p3) +{ + DmtxBresLine lines[4]; + DmtxPixelLoc pEmpty = { 0, 0 }; + unsigned char *cache; + int *scanlineMin, *scanlineMax; + int minY, maxY, sizeY, posY, posX; + int i, idx; + + lines[0] = BresLineInit(p0, p1, pEmpty); + lines[1] = BresLineInit(p1, p2, pEmpty); + lines[2] = BresLineInit(p2, p3, pEmpty); + lines[3] = BresLineInit(p3, p0, pEmpty); + + minY = dec->yMax; + maxY = 0; + + minY = min(minY, p0.Y); maxY = max(maxY, p0.Y); + minY = min(minY, p1.Y); maxY = max(maxY, p1.Y); + minY = min(minY, p2.Y); maxY = max(maxY, p2.Y); + minY = min(minY, p3.Y); maxY = max(maxY, p3.Y); + + sizeY = maxY - minY + 1; + + scanlineMin = (int *)malloc(sizeY * sizeof(int)); + scanlineMax = (int *)calloc(sizeY, sizeof(int)); + + assert(scanlineMin); /* XXX handle this better */ + assert(scanlineMax); /* XXX handle this better */ + + for(i = 0; i < sizeY; i++) + scanlineMin[i] = dec->xMax; + + for(i = 0; i < 4; i++) { + while(lines[i].loc.X != lines[i].loc1.X || lines[i].loc.Y != lines[i].loc1.Y) { + idx = lines[i].loc.Y - minY; + scanlineMin[idx] = min(scanlineMin[idx], lines[i].loc.X); + scanlineMax[idx] = max(scanlineMax[idx], lines[i].loc.X); + BresLineStep(lines + i, 1, 0); + } + } + + for(posY = minY; posY < maxY && posY < dec->yMax; posY++) { + idx = posY - minY; + for(posX = scanlineMin[idx]; posX < scanlineMax[idx] && posX < dec->xMax; posX++) { + cache = dmtxDecodeGetCache(dec, posX, posY); + if(cache != NULL) + *cache |= 0x80; + } + } + + free(scanlineMin); + free(scanlineMax); +} + +/** + * \brief Convert fitted Data Matrix region into a decoded message + * \param dec + * \param reg + * \param fix + * \return Decoded message + */ +extern DmtxMessage * +dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix) +{ + DmtxMessage *msg; + DmtxVector2 topLeft, topRight, bottomLeft, bottomRight; + DmtxPixelLoc pxTopLeft, pxTopRight, pxBottomLeft, pxBottomRight; + + msg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMatrix); + if(msg == NULL) + return NULL; + + if(PopulateArrayFromMatrix(dec, reg, msg) != DmtxPass) { + dmtxMessageDestroy(&msg); + return NULL; + } + + /* maybe place remaining logic into new dmtxDecodePopulatedArray() + function so other people can pass in their own arrays */ + + ModulePlacementEcc200(msg->array, msg->code, + reg->sizeIdx, DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue); + + if(RsDecode(msg->code, reg->sizeIdx, fix) == DmtxFail) + { + dmtxMessageDestroy(&msg); + return NULL; + } + + topLeft.X = bottomLeft.X = topLeft.Y = topRight.Y = -0.1; + topRight.X = bottomRight.X = bottomLeft.Y = bottomRight.Y = 1.1; + + dmtxMatrix3VMultiplyBy(&topLeft, reg->fit2raw); + dmtxMatrix3VMultiplyBy(&topRight, reg->fit2raw); + dmtxMatrix3VMultiplyBy(&bottomLeft, reg->fit2raw); + dmtxMatrix3VMultiplyBy(&bottomRight, reg->fit2raw); + + pxTopLeft.X = (int)(0.5 + topLeft.X); + pxTopLeft.Y = (int)(0.5 + topLeft.Y); + pxBottomLeft.X = (int)(0.5 + bottomLeft.X); + pxBottomLeft.Y = (int)(0.5 + bottomLeft.Y); + pxTopRight.X = (int)(0.5 + topRight.X); + pxTopRight.Y = (int)(0.5 + topRight.Y); + pxBottomRight.X = (int)(0.5 + bottomRight.X); + pxBottomRight.Y = (int)(0.5 + bottomRight.Y); + + CacheFillQuad(dec, pxTopLeft, pxTopRight, pxBottomRight, pxBottomLeft); + + DecodeDataStream(msg, reg->sizeIdx, NULL); + + return msg; +} + +/** + * \brief Convert fitted Data Mosaic region into a decoded message + * \param dec + * \param reg + * \param fix + * \return Decoded message + */ +extern DmtxMessage * +dmtxDecodeMosaicRegion(DmtxDecode *dec, DmtxRegion *reg, int fix) +{ + int offset; + int colorPlane; + DmtxMessage *oMsg, *rMsg, *gMsg, *bMsg; + + colorPlane = reg->flowBegin.plane; + + /** + * Consider performing a color cube fit here to identify exact RGB of + * all 6 "cube-like" corners based on pixels located within region. Then + * force each sample pixel to the "cube-like" corner based o which one + * is nearest "sqrt(dr^2+dg^2+db^2)" (except sqrt is unnecessary). + * colorPlane = reg->flowBegin.plane; + * + * To find RGB values of primary colors, perform something like a + * histogram except instead of going from black to color N, go from + * (127,127,127) to color. Use color bins along with distance to + * identify value. An additional method will be required to get actual + * RGB instead of just a plane in 3D. */ + + reg->flowBegin.plane = 0; /* kind of a hack */ + rMsg = dmtxDecodeMatrixRegion(dec, reg, fix); + + reg->flowBegin.plane = 1; /* kind of a hack */ + gMsg = dmtxDecodeMatrixRegion(dec, reg, fix); + + reg->flowBegin.plane = 2; /* kind of a hack */ + bMsg = dmtxDecodeMatrixRegion(dec, reg, fix); + + reg->flowBegin.plane = colorPlane; + + oMsg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMosaic); + + if(oMsg == NULL || rMsg == NULL || gMsg == NULL || bMsg == NULL) { + dmtxMessageDestroy(&oMsg); + dmtxMessageDestroy(&rMsg); + dmtxMessageDestroy(&gMsg); + dmtxMessageDestroy(&bMsg); + return NULL; + } + + offset = 0; + memcpy(oMsg->output + offset, rMsg->output, rMsg->outputIdx); + offset += rMsg->outputIdx; + memcpy(oMsg->output + offset, gMsg->output, gMsg->outputIdx); + offset += gMsg->outputIdx; + memcpy(oMsg->output + offset, bMsg->output, bMsg->outputIdx); + offset += bMsg->outputIdx; + + oMsg->outputIdx = offset; + + dmtxMessageDestroy(&rMsg); + dmtxMessageDestroy(&gMsg); + dmtxMessageDestroy(&bMsg); + + return oMsg; +} + +/** + * + * + */ +extern unsigned char * +dmtxDecodeCreateDiagnostic(DmtxDecode *dec, int *totalBytes, int *headerBytes, int style) +{ + int i, row, col; + int width, height; + int widthDigits, heightDigits; + int count, channelCount; + int rgb[3]; + double shade; + unsigned char *pnm, *output, *cache; + + width = dmtxDecodeGetProp(dec, DmtxPropWidth); + height = dmtxDecodeGetProp(dec, DmtxPropHeight); + channelCount = dmtxImageGetProp(dec->image, DmtxPropChannelCount); + + //style = 1; /* this doesn't mean anything yet , deleted for compile*/ + + /* Count width digits */ + for(widthDigits = 0, i = width; i > 0; i /= 10) + widthDigits++; + + /* Count height digits */ + for(heightDigits = 0, i = height; i > 0; i /= 10) + heightDigits++; + + *headerBytes = widthDigits + heightDigits + 9; + *totalBytes = *headerBytes + width * height * 3; + + pnm = (unsigned char *)malloc(*totalBytes); + if(pnm == NULL) + return NULL; + +#ifdef _VISUALC_ + count = sprintf_s((char *)pnm, *headerBytes + 1, "P6\n%d %d\n255\n", width, height); +#else + count = snprintf((char *)pnm, *headerBytes + 1, "P6\n%d %d\n255\n", width, height); +#endif + + if(count != *headerBytes) { + free(pnm); + return NULL; + } + + output = pnm + (*headerBytes); + for(row = height - 1; row >= 0; row--) { + for(col = 0; col < width; col++) { + cache = dmtxDecodeGetCache(dec, col, row); + if(cache == NULL) { + rgb[0] = 0; + rgb[1] = 0; + rgb[2] = 128; + } + else if(*cache & 0x40) { + rgb[0] = 255; + rgb[1] = 0; + rgb[2] = 0; + } + else { + shade = (*cache & 0x80) ? 0.0 : 0.7; + for(i = 0; i < 3; i++) { + if(i < channelCount) + dmtxDecodeGetPixelValue(dec, col, row, i, &rgb[i]); + else + dmtxDecodeGetPixelValue(dec, col, row, 0, &rgb[i]); + + rgb[i] += (int)(shade * (double)(255 - rgb[i]) + 0.5); + if(rgb[i] > 255) + rgb[i] = 255; + } + } + *(output++) = (unsigned char)rgb[0]; + *(output++) = (unsigned char)rgb[1]; + *(output++) = (unsigned char)rgb[2]; + } + } + assert(output == pnm + *totalBytes); + + return pnm; +} + +/** + * \brief Increment counters used to determine module values + * \param img + * \param reg + * \param tally + * \param xOrigin + * \param yOrigin + * \param mapWidth + * \param mapHeight + * \param dir + * \return void + */ +static void +TallyModuleJumps(DmtxDecode *dec, DmtxRegion *reg, int tally[][24], int xOrigin, int yOrigin, int mapWidth, int mapHeight, DmtxDirection dir) +{ + int extent, weight; + int travelStep; + int symbolRow, symbolCol; + int mapRow, mapCol; + int lineStart, lineStop; + int travelStart, travelStop; + int *line, *travel; + int jumpThreshold; + int darkOnLight; + int color; + int statusPrev, statusModule; + int tPrev, tModule; + + assert(dir == DmtxDirUp || dir == DmtxDirLeft || dir == DmtxDirDown || dir == DmtxDirRight); + + travelStep = (dir == DmtxDirUp || dir == DmtxDirRight) ? 1 : -1; + + /* Abstract row and column progress using pointers to allow grid + traversal in all 4 directions using same logic */ + + if((dir & DmtxDirHorizontal) != 0x00) { + line = &symbolRow; + travel = &symbolCol; + extent = mapWidth; + lineStart = yOrigin; + lineStop = yOrigin + mapHeight; + travelStart = (travelStep == 1) ? xOrigin - 1 : xOrigin + mapWidth; + travelStop = (travelStep == 1) ? xOrigin + mapWidth : xOrigin - 1; + } + else { + assert(dir & DmtxDirVertical); + line = &symbolCol; + travel = &symbolRow; + extent = mapHeight; + lineStart = xOrigin; + lineStop = xOrigin + mapWidth; + travelStart = (travelStep == 1) ? yOrigin - 1: yOrigin + mapHeight; + travelStop = (travelStep == 1) ? yOrigin + mapHeight : yOrigin - 1; + } + + + darkOnLight = (int)(reg->offColor > reg->onColor); + jumpThreshold = abs((int)(0.4 * (reg->offColor - reg->onColor) + 0.5)); + + assert(jumpThreshold >= 0); + + for(*line = lineStart; *line < lineStop; (*line)++) { + + /* Capture tModule for each leading border module as normal but + decide status based on predictable barcode border pattern */ + + *travel = travelStart; + color = ReadModuleColor(dec, reg, symbolRow, symbolCol, reg->sizeIdx, reg->flowBegin.plane); + tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; + + statusModule = (travelStep == 1 || (*line & 0x01) == 0) ? DmtxModuleOnRGB : DmtxModuleOff; + + weight = extent; + + while((*travel += travelStep) != travelStop) { + + tPrev = tModule; + statusPrev = statusModule; + + /* For normal data-bearing modules capture color and decide + module status based on comparison to previous "known" module */ + + color = ReadModuleColor(dec, reg, symbolRow, symbolCol, reg->sizeIdx, reg->flowBegin.plane); + tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; + + if(statusPrev == DmtxModuleOnRGB) { + if(tModule < tPrev - jumpThreshold) + statusModule = DmtxModuleOff; + else + statusModule = DmtxModuleOnRGB; + } + else if(statusPrev == DmtxModuleOff) { + if(tModule > tPrev + jumpThreshold) + statusModule = DmtxModuleOnRGB; + else + statusModule = DmtxModuleOff; + } + + mapRow = symbolRow - yOrigin; + mapCol = symbolCol - xOrigin; + assert(mapRow < 24 && mapCol < 24); + + if(statusModule == DmtxModuleOnRGB) + tally[mapRow][mapCol] += (2 * weight); + + weight--; + } + + assert(weight == 0); + } +} + +/** + * \brief Populate array with codeword values based on module colors + * \param msg + * \param img + * \param reg + * \return DmtxPass | DmtxFail + */ +static DmtxPassFail +PopulateArrayFromMatrix(DmtxDecode *dec, DmtxRegion *reg, DmtxMessage *msg) +{ + int weightFactor; + int mapWidth, mapHeight; + int xRegionTotal, yRegionTotal; + int xRegionCount, yRegionCount; + int xOrigin, yOrigin; + int mapCol, mapRow; + int colTmp, rowTmp, idx; + int *tally_temp = malloc(sizeof(int) * 24 * 24); int (*tally)[24] = (int (*)[24]) tally_temp; // [24][24]; /* Large enough to map largest single region */ + +/* memset(msg->array, 0x00, msg->arraySize); */ + + /* Capture number of regions present in barcode */ + xRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribHorizDataRegions, reg->sizeIdx); + yRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, reg->sizeIdx); + + /* Capture region dimensions (not including border modules) */ + mapWidth = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, reg->sizeIdx); + mapHeight = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, reg->sizeIdx); + + weightFactor = 2 * (mapHeight + mapWidth + 2); + assert(weightFactor > 0); + + /* Tally module changes for each region in each direction */ + for(yRegionCount = 0; yRegionCount < yRegionTotal; yRegionCount++) { + + /* Y location of mapping region origin in symbol coordinates */ + yOrigin = yRegionCount * (mapHeight + 2) + 1; + + for(xRegionCount = 0; xRegionCount < xRegionTotal; xRegionCount++) { + + /* X location of mapping region origin in symbol coordinates */ + xOrigin = xRegionCount * (mapWidth + 2) + 1; + + memset(tally, 0x00, 24 * 24 * sizeof(int)); + TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirUp); + TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirLeft); + TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirDown); + TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirRight); + + /* Decide module status based on final tallies */ + for(mapRow = 0; mapRow < mapHeight; mapRow++) { + for(mapCol = 0; mapCol < mapWidth; mapCol++) { + + rowTmp = (yRegionCount * mapHeight) + mapRow; + rowTmp = yRegionTotal * mapHeight - rowTmp - 1; + colTmp = (xRegionCount * mapWidth) + mapCol; + idx = (rowTmp * xRegionTotal * mapWidth) + colTmp; + + if(tally[mapRow][mapCol]/(double)weightFactor >= 0.5) + msg->array[idx] = DmtxModuleOnRGB; + else + msg->array[idx] = DmtxModuleOff; + + msg->array[idx] |= DmtxModuleAssigned; + } + } + } + } + + free(tally_temp); + + return DmtxPass; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxdecodescheme.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxdecodescheme.c + */ + +/** + * \brief Translate encoded data stream into final output + * \param msg + * \param sizeIdx + * \param outputStart + * \return void + */ +static void +DecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart) +{ + DmtxBoolean macro = DmtxFalse; + DmtxScheme encScheme; + unsigned char *ptr, *dataEnd; + + msg->output = (outputStart == NULL) ? msg->output : outputStart; + msg->outputIdx = 0; + + ptr = msg->code; + dataEnd = ptr + dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); + + /* Print macro header if first codeword triggers it */ + if(*ptr == DmtxValue05Macro || *ptr == DmtxValue06Macro) { + PushOutputMacroHeader(msg, *ptr); + macro = DmtxTrue; + } + + while(ptr < dataEnd) { + + encScheme = GetEncodationScheme(*ptr); + if(encScheme != DmtxSchemeAscii) + ptr++; + + switch(encScheme) { + case DmtxSchemeAscii: + ptr = DecodeSchemeAscii(msg, ptr, dataEnd); + break; + case DmtxSchemeC40: + case DmtxSchemeText: + ptr = DecodeSchemeC40Text(msg, ptr, dataEnd, encScheme); + break; + case DmtxSchemeX12: + ptr = DecodeSchemeX12(msg, ptr, dataEnd); + break; + case DmtxSchemeEdifact: + ptr = DecodeSchemeEdifact(msg, ptr, dataEnd); + break; + case DmtxSchemeBase256: + ptr = DecodeSchemeBase256(msg, ptr, dataEnd); + break; + default: + /* error */ + break; + } + } + + /* Print macro trailer if required */ + if(macro == DmtxTrue) + PushOutputMacroTrailer(msg); +} + +/** + * \brief Determine next encodation scheme + * \param encScheme + * \param cw + * \return Pointer to next undecoded codeword + */ +static int +GetEncodationScheme(unsigned char cw) +{ + DmtxScheme encScheme; + + switch(cw) { + case DmtxValueC40Latch: + encScheme = DmtxSchemeC40; + break; + case DmtxValueTextLatch: + encScheme = DmtxSchemeText; + break; + case DmtxValueX12Latch: + encScheme = DmtxSchemeX12; + break; + case DmtxValueEdifactLatch: + encScheme = DmtxSchemeEdifact; + break; + case DmtxValueBase256Latch: + encScheme = DmtxSchemeBase256; + break; + default: + encScheme = DmtxSchemeAscii; + break; + } + + return encScheme; +} + +/** + * + * + */ +static void +PushOutputWord(DmtxMessage *msg, int value) +{ + assert(value >= 0 && value < 256); + + msg->output[msg->outputIdx++] = (unsigned char)value; +} + +/** + * + * + */ +static void +PushOutputC40TextWord(DmtxMessage *msg, C40TextState *state, int value) +{ + assert(value >= 0 && value < 256); + + msg->output[msg->outputIdx] = (unsigned char)value; + + if(state->upperShift == DmtxTrue) { + assert(value < 128); + msg->output[msg->outputIdx] += 128; + } + + msg->outputIdx++; + + state->shift = DmtxC40TextBasicSet; + state->upperShift = DmtxFalse; +} + +/** + * + * + */ +static void +PushOutputMacroHeader(DmtxMessage *msg, int macroType) +{ + PushOutputWord(msg, '['); + PushOutputWord(msg, ')'); + PushOutputWord(msg, '>'); + PushOutputWord(msg, 30); /* ASCII RS */ + PushOutputWord(msg, '0'); + + assert(macroType == DmtxValue05Macro || macroType == DmtxValue06Macro); + if(macroType == DmtxValue05Macro) + PushOutputWord(msg, '5'); + else + PushOutputWord(msg, '6'); + + PushOutputWord(msg, 29); /* ASCII GS */ +} + +/** + * + * + */ +static void +PushOutputMacroTrailer(DmtxMessage *msg) +{ + PushOutputWord(msg, 30); /* ASCII RS */ + PushOutputWord(msg, 4); /* ASCII EOT */ +} + +/** + * \brief Decode stream assuming standard ASCII encodation + * \param msg + * \param ptr + * \param dataEnd + * \return Pointer to next undecoded codeword + */ +static unsigned char * +DecodeSchemeAscii(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd) +{ + int upperShift; + int codeword, digits; + + upperShift = DmtxFalse; + + while(ptr < dataEnd) { + + codeword = (int)(*ptr); + + if(GetEncodationScheme(*ptr) != DmtxSchemeAscii) + return ptr; + else + ptr++; + + if(upperShift == DmtxTrue) { + PushOutputWord(msg, codeword + 127); + upperShift = DmtxFalse; + } + else if(codeword == DmtxValueAsciiUpperShift) { + upperShift = DmtxTrue; + } + else if(codeword == DmtxValueAsciiPad) { + assert(dataEnd >= ptr); + assert(dataEnd - ptr <= INT_MAX); + msg->padCount = (int)(dataEnd - ptr); + return dataEnd; + } + else if(codeword <= 128) { + PushOutputWord(msg, codeword - 1); + } + else if(codeword <= 229) { + digits = codeword - 130; + PushOutputWord(msg, digits/10 + '0'); + PushOutputWord(msg, digits - (digits/10)*10 + '0'); + } + } + + return ptr; +} + +/** + * \brief Decode stream assuming C40 or Text encodation + * \param msg + * \param ptr + * \param dataEnd + * \param encScheme + * \return Pointer to next undecoded codeword + */ +static unsigned char * +DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxScheme encScheme) +{ + int i; + int packed; + int c40Values[3]; + C40TextState state; + + state.shift = DmtxC40TextBasicSet; + state.upperShift = DmtxFalse; + + assert(encScheme == DmtxSchemeC40 || encScheme == DmtxSchemeText); + + /* Unlatch is implied if only one codeword remains */ + if(dataEnd - ptr < 2) + return ptr; + + while(ptr < dataEnd) { + + /* FIXME Also check that ptr+1 is safe to access */ + packed = (*ptr << 8) | *(ptr+1); + c40Values[0] = ((packed - 1)/1600); + c40Values[1] = ((packed - 1)/40) % 40; + c40Values[2] = (packed - 1) % 40; + ptr += 2; + + for(i = 0; i < 3; i++) { + if(state.shift == DmtxC40TextBasicSet) { /* Basic set */ + if(c40Values[i] <= 2) { + state.shift = c40Values[i] + 1; + } + else if(c40Values[i] == 3) { + PushOutputC40TextWord(msg, &state, ' '); + } + else if(c40Values[i] <= 13) { + PushOutputC40TextWord(msg, &state, c40Values[i] - 13 + '9'); /* 0-9 */ + } + else if(c40Values[i] <= 39) { + if(encScheme == DmtxSchemeC40) { + PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'Z'); /* A-Z */ + } + else if(encScheme == DmtxSchemeText) { + PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'z'); /* a-z */ + } + } + } + else if(state.shift == DmtxC40TextShift1) { /* Shift 1 set */ + PushOutputC40TextWord(msg, &state, c40Values[i]); /* ASCII 0 - 31 */ + } + else if(state.shift == DmtxC40TextShift2) { /* Shift 2 set */ + if(c40Values[i] <= 14) { + PushOutputC40TextWord(msg, &state, c40Values[i] + 33); /* ASCII 33 - 47 */ + } + else if(c40Values[i] <= 21) { + PushOutputC40TextWord(msg, &state, c40Values[i] + 43); /* ASCII 58 - 64 */ + } + else if(c40Values[i] <= 26) { + PushOutputC40TextWord(msg, &state, c40Values[i] + 69); /* ASCII 91 - 95 */ + } + else if(c40Values[i] == 27) { + PushOutputC40TextWord(msg, &state, 0x1d); /* FNC1 -- XXX depends on position? */ + } + else if(c40Values[i] == 30) { + state.upperShift = DmtxTrue; + state.shift = DmtxC40TextBasicSet; + } + } + else if(state.shift == DmtxC40TextShift3) { /* Shift 3 set */ + if(encScheme == DmtxSchemeC40) { + PushOutputC40TextWord(msg, &state, c40Values[i] + 96); + } + else if(encScheme == DmtxSchemeText) { + if(c40Values[i] == 0) + PushOutputC40TextWord(msg, &state, c40Values[i] + 96); + else if(c40Values[i] <= 26) + PushOutputC40TextWord(msg, &state, c40Values[i] - 26 + 'Z'); /* A-Z */ + else + PushOutputC40TextWord(msg, &state, c40Values[i] - 31 + 127); /* { | } ~ DEL */ + } + } + } + + /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */ + if(*ptr == DmtxValueCTXUnlatch) + return ptr + 1; + + /* Unlatch is implied if only one codeword remains */ + if(dataEnd - ptr < 2) + return ptr; + } + + return ptr; +} + +/** + * \brief Decode stream assuming X12 encodation + * \param msg + * \param ptr + * \param dataEnd + * \return Pointer to next undecoded codeword + */ +static unsigned char * +DecodeSchemeX12(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd) +{ + int i; + int packed; + int x12Values[3]; + + /* Unlatch is implied if only one codeword remains */ + if(dataEnd - ptr < 2) + return ptr; + + while(ptr < dataEnd) { + + /* FIXME Also check that ptr+1 is safe to access */ + packed = (*ptr << 8) | *(ptr+1); + x12Values[0] = ((packed - 1)/1600); + x12Values[1] = ((packed - 1)/40) % 40; + x12Values[2] = (packed - 1) % 40; + ptr += 2; + + for(i = 0; i < 3; i++) { + if(x12Values[i] == 0) + PushOutputWord(msg, 13); + else if(x12Values[i] == 1) + PushOutputWord(msg, 42); + else if(x12Values[i] == 2) + PushOutputWord(msg, 62); + else if(x12Values[i] == 3) + PushOutputWord(msg, 32); + else if(x12Values[i] <= 13) + PushOutputWord(msg, x12Values[i] + 44); + else if(x12Values[i] <= 90) + PushOutputWord(msg, x12Values[i] + 51); + } + + /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */ + if(*ptr == DmtxValueCTXUnlatch) + return ptr + 1; + + /* Unlatch is implied if only one codeword remains */ + if(dataEnd - ptr < 2) + return ptr; + } + + return ptr; +} + +/** + * \brief Decode stream assuming EDIFACT encodation + * \param msg + * \param ptr + * \param dataEnd + * \return Pointer to next undecoded codeword + */ +static unsigned char * +DecodeSchemeEdifact(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd) +{ + int i; + unsigned char unpacked[4]; + + /* Unlatch is implied if fewer than 3 codewords remain */ + if(dataEnd - ptr < 3) + return ptr; + + while(ptr < dataEnd) { + + /* FIXME Also check that ptr+2 is safe to access -- shouldn't be a + problem because I'm guessing you can guarantee there will always + be at least 3 error codewords */ + unpacked[0] = (*ptr & 0xfc) >> 2; + unpacked[1] = (*ptr & 0x03) << 4 | (*(ptr+1) & 0xf0) >> 4; + unpacked[2] = (*(ptr+1) & 0x0f) << 2 | (*(ptr+2) & 0xc0) >> 6; + unpacked[3] = *(ptr+2) & 0x3f; + + for(i = 0; i < 4; i++) { + + /* Advance input ptr (4th value comes from already-read 3rd byte) */ + if(i < 3) + ptr++; + + /* Test for unlatch condition */ + if(unpacked[i] == DmtxValueEdifactUnlatch) { + assert(msg->output[msg->outputIdx] == 0); /* XXX dirty why? */ + return ptr; + } + + PushOutputWord(msg, unpacked[i] ^ (((unpacked[i] & 0x20) ^ 0x20) << 1)); + } + + /* Unlatch is implied if fewer than 3 codewords remain */ + if(dataEnd - ptr < 3) + return ptr; + } + + return ptr; + +/* XXX the following version should be safer, but requires testing before replacing the old version + int bits = 0; + int bitCount = 0; + int value; + + while(ptr < dataEnd) { + + if(bitCount < 6) { + bits = (bits << 8) | *(ptr++); + bitCount += 8; + } + + value = bits >> (bitCount - 6); + bits -= (value << (bitCount - 6)); + bitCount -= 6; + + if(value == 0x1f) { + assert(bits == 0); // should be padded with zero-value bits + return ptr; + } + PushOutputWord(msg, value ^ (((value & 0x20) ^ 0x20) << 1)); + + // Unlatch implied if just completed triplet and 1 or 2 words are left + if(bitCount == 0 && dataEnd - ptr - 1 > 0 && dataEnd - ptr - 1 < 3) + return ptr; + } + + assert(bits == 0); // should be padded with zero-value bits + assert(bitCount == 0); // should be padded with zero-value bits + return ptr; +*/ +} + +/** + * \brief Decode stream assuming Base 256 encodation + * \param msg + * \param ptr + * \param dataEnd + * \return Pointer to next undecoded codeword + */ +static unsigned char * +DecodeSchemeBase256(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd) +{ + int d0, d1; + int idx; + unsigned char *ptrEnd; + + /* Find positional index used for unrandomizing */ + assert(ptr + 1 >= msg->code); + assert(ptr + 1 - msg->code <= INT_MAX); + idx = (int)(ptr + 1 - msg->code); + + d0 = UnRandomize255State(*(ptr++), idx++); + if(d0 == 0) { + ptrEnd = dataEnd; + } + else if(d0 <= 249) { + ptrEnd = ptr + d0; + } + else { + d1 = UnRandomize255State(*(ptr++), idx++); + ptrEnd = ptr + (d0 - 249) * 250 + d1; + } + + if(ptrEnd > dataEnd) + fb_alloc_fail(); // exit(40); /* XXX needs cleaner error handling */ + + while(ptr < ptrEnd) + PushOutputWord(msg, UnRandomize255State(*(ptr++), idx++)); + + return ptr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxmessage.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxmessage.c + * \brief Data message handling + */ + +/** + * \brief Allocate memory for message + * \param sizeIdx + * \param symbolFormat DmtxFormatMatrix | DmtxFormatMosaic + * \return Address of allocated memory + */ +extern DmtxMessage * +dmtxMessageCreate(int sizeIdx, int symbolFormat) +{ + DmtxMessage *message; + int mappingRows, mappingCols; + + assert(symbolFormat == DmtxFormatMatrix || symbolFormat == DmtxFormatMosaic); + + mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx); + mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx); + + message = (DmtxMessage *)calloc(1, sizeof(DmtxMessage)); + if(message == NULL) + return NULL; + + message->arraySize = sizeof(unsigned char) * mappingRows * mappingCols; + + message->array = (unsigned char *)calloc(1, message->arraySize); + if(message->array == NULL) { + perror("Calloc failed"); + dmtxMessageDestroy(&message); + return NULL; + } + + message->codeSize = sizeof(unsigned char) * + dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx) + + dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx); + + if(symbolFormat == DmtxFormatMosaic) + message->codeSize *= 3; + + message->code = (unsigned char *)calloc(message->codeSize, sizeof(unsigned char)); + if(message->code == NULL) { + perror("Calloc failed"); + dmtxMessageDestroy(&message); + return NULL; + } + + /* XXX not sure if this is the right place or even the right approach. + Trying to allocate memory for the decoded data stream and will + initially assume that decoded data will not be larger than 2x encoded data */ + message->outputSize = sizeof(unsigned char) * message->codeSize * 10; + message->output = (unsigned char *)calloc(message->outputSize, sizeof(unsigned char)); + if(message->output == NULL) { + perror("Calloc failed"); + dmtxMessageDestroy(&message); + return NULL; + } + + return message; +} + +/** + * \brief Free memory previously allocated for message + * \param message + * \return void + */ +extern DmtxPassFail +dmtxMessageDestroy(DmtxMessage **msg) +{ + if(msg == NULL || *msg == NULL) + return DmtxFail; + + if((*msg)->array != NULL) + free((*msg)->array); + + if((*msg)->code != NULL) + free((*msg)->code); + + if((*msg)->output != NULL) + free((*msg)->output); + + free(*msg); + + *msg = NULL; + + return DmtxPass; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxregion.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxregion.c + * \brief Detect barcode regions + */ + +#define DMTX_HOUGH_RES 180 + +/** + * \brief Create copy of existing region struct + * \param None + * \return Initialized DmtxRegion struct + */ +extern DmtxRegion * +dmtxRegionCreate(DmtxRegion *reg) +{ + DmtxRegion *regCopy; + + regCopy = (DmtxRegion *)malloc(sizeof(DmtxRegion)); + if(regCopy == NULL) + return NULL; + + memcpy(regCopy, reg, sizeof(DmtxRegion)); + + return regCopy; +} + +/** + * \brief Destroy region struct + * \param reg + * \return void + */ +extern DmtxPassFail +dmtxRegionDestroy(DmtxRegion **reg) +{ + if(reg == NULL || *reg == NULL) + return DmtxFail; + + free(*reg); + + *reg = NULL; + + return DmtxPass; +} + +/** + * \brief Find next barcode region + * \param dec Pointer to DmtxDecode information struct + * \return Detected region (if found) + */ +extern DmtxRegion * +dmtxRegionFindNext(DmtxDecode *dec, int max_iterations, int *current_iterations) +{ + int locStatus; + DmtxPixelLoc loc; + DmtxRegion *reg; + + /* Continue until we find a region or run out of chances */ + for(; *current_iterations < max_iterations; *current_iterations += 1) { + locStatus = PopGridLocation(&(dec->grid), &loc); + if(locStatus == DmtxRangeEnd) + break; + + /* Scan location for presence of valid barcode region */ + reg = dmtxRegionScanPixel(dec, loc.X, loc.Y); + if(reg != NULL) + return reg; + } + + return NULL; +} + +/** + * \brief Scan individual pixel for presence of barcode edge + * \param dec Pointer to DmtxDecode information struct + * \param loc Pixel location + * \return Detected region (if any) + */ +extern DmtxRegion * +dmtxRegionScanPixel(DmtxDecode *dec, int x, int y) +{ + unsigned char *cache; + DmtxRegion reg; + DmtxPointFlow flowBegin; + DmtxPixelLoc loc; + + loc.X = x; + loc.Y = y; + + cache = dmtxDecodeGetCache(dec, loc.X, loc.Y); + if(cache == NULL) + return NULL; + + if((int)(*cache & 0x80) != 0x00) + return NULL; + + /* Test for presence of any reasonable edge at this location */ + flowBegin = MatrixRegionSeekEdge(dec, loc); + if(flowBegin.mag < (int)(dec->edgeThresh * 7.65 + 0.5)) + return NULL; + + memset(®, 0x00, sizeof(DmtxRegion)); + + /* Determine barcode orientation */ + if(MatrixRegionOrientation(dec, ®, flowBegin) == DmtxFail) + return NULL; + if(dmtxRegionUpdateXfrms(dec, ®) == DmtxFail) + return NULL; + + /* Define top edge */ + if(MatrixRegionAlignCalibEdge(dec, ®, DmtxEdgeTop) == DmtxFail) + return NULL; + if(dmtxRegionUpdateXfrms(dec, ®) == DmtxFail) + return NULL; + + /* Define right edge */ + if(MatrixRegionAlignCalibEdge(dec, ®, DmtxEdgeRight) == DmtxFail) + return NULL; + if(dmtxRegionUpdateXfrms(dec, ®) == DmtxFail) + return NULL; + + CALLBACK_MATRIX(®); + + /* Calculate the best fitting symbol size */ + if(MatrixRegionFindSize(dec, ®) == DmtxFail) + return NULL; + + /* Found a valid matrix region */ + return dmtxRegionCreate(®); +} + +/** + * + * + */ +static DmtxPointFlow +MatrixRegionSeekEdge(DmtxDecode *dec, DmtxPixelLoc loc) +{ + int i; + int strongIdx; + int channelCount; + DmtxPointFlow flow, flowPlane[3]; + DmtxPointFlow flowPos, flowPosBack; + DmtxPointFlow flowNeg, flowNegBack; + + channelCount = dec->image->channelCount; + + /* Find whether red, green, or blue shows the strongest edge */ + strongIdx = 0; + for(i = 0; i < channelCount; i++) { + flowPlane[i] = GetPointFlow(dec, i, loc, dmtxNeighborNone); + if(i > 0 && flowPlane[i].mag > flowPlane[strongIdx].mag) + strongIdx = i; + } + + if(flowPlane[strongIdx].mag < 10) + return dmtxBlankEdge; + + flow = flowPlane[strongIdx]; + + flowPos = FindStrongestNeighbor(dec, flow, +1); + flowNeg = FindStrongestNeighbor(dec, flow, -1); + if(flowPos.mag != 0 && flowNeg.mag != 0) { + flowPosBack = FindStrongestNeighbor(dec, flowPos, -1); + flowNegBack = FindStrongestNeighbor(dec, flowNeg, +1); + if(flowPos.arrive == (flowPosBack.arrive+4)%8 && + flowNeg.arrive == (flowNegBack.arrive+4)%8) { + flow.arrive = dmtxNeighborNone; + CALLBACK_POINT_PLOT(flow.loc, 1, 1, 1); + return flow; + } + } + + return dmtxBlankEdge; +} + +/** + * + * + */ +static DmtxPassFail +MatrixRegionOrientation(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow begin) +{ + int cross; + int minArea; + int scale; + int symbolShape; + int maxDiagonal; + DmtxPassFail err; + DmtxBestLine line1x, line2x; + DmtxBestLine line2n, line2p; + DmtxFollow fTmp; + + if(dec->sizeIdxExpected == DmtxSymbolSquareAuto || + (dec->sizeIdxExpected >= DmtxSymbol10x10 && + dec->sizeIdxExpected <= DmtxSymbol144x144)) + symbolShape = DmtxSymbolSquareAuto; + else if(dec->sizeIdxExpected == DmtxSymbolRectAuto || + (dec->sizeIdxExpected >= DmtxSymbol8x18 && + dec->sizeIdxExpected <= DmtxSymbol16x48)) + symbolShape = DmtxSymbolRectAuto; + else + symbolShape = DmtxSymbolShapeAuto; + + if(dec->edgeMax != DmtxUndefined) { + if(symbolShape == DmtxSymbolRectAuto) + maxDiagonal = (int)(1.23 * dec->edgeMax + 0.5); /* sqrt(5/4) + 10% */ + else + maxDiagonal = (int)(1.56 * dec->edgeMax + 0.5); /* sqrt(2) + 10% */ + } + else { + maxDiagonal = DmtxUndefined; + } + + /* Follow to end in both directions */ + err = TrailBlazeContinuous(dec, reg, begin, maxDiagonal); + if(err == DmtxFail || reg->stepsTotal < 40) { + TrailClear(dec, reg, 0x40); + return DmtxFail; + } + + /* Filter out region candidates that are smaller than expected */ + if(dec->edgeMin != DmtxUndefined) { + scale = dmtxDecodeGetProp(dec, DmtxPropScale); + + if(symbolShape == DmtxSymbolSquareAuto) + minArea = (dec->edgeMin * dec->edgeMin)/(scale * scale); + else + minArea = (2 * dec->edgeMin * dec->edgeMin)/(scale * scale); + + if((reg->boundMax.X - reg->boundMin.X) * (reg->boundMax.Y - reg->boundMin.Y) < minArea) { + TrailClear(dec, reg, 0x40); + return DmtxFail; + } + } + + line1x = FindBestSolidLine(dec, reg, 0, 0, +1, DmtxUndefined); + if(line1x.mag < 5) { + TrailClear(dec, reg, 0x40); + return DmtxFail; + } + + err = FindTravelLimits(dec, reg, &line1x); + if(line1x.distSq < 100 || line1x.devn * 10 >= sqrt((double)line1x.distSq)) { + TrailClear(dec, reg, 0x40); + return DmtxFail; + } + assert(line1x.stepPos >= line1x.stepNeg); + + fTmp = FollowSeek(dec, reg, line1x.stepPos + 5); + line2p = FindBestSolidLine(dec, reg, fTmp.step, line1x.stepNeg, +1, line1x.angle); + + fTmp = FollowSeek(dec, reg, line1x.stepNeg - 5); + line2n = FindBestSolidLine(dec, reg, fTmp.step, line1x.stepPos, -1, line1x.angle); + if(max(line2p.mag, line2n.mag) < 5) + return DmtxFail; + + if(line2p.mag > line2n.mag) { + line2x = line2p; + err = FindTravelLimits(dec, reg, &line2x); + if(line2x.distSq < 100 || line2x.devn * 10 >= sqrt((double)line2x.distSq)) + return DmtxFail; + + cross = ((line1x.locPos.X - line1x.locNeg.X) * (line2x.locPos.Y - line2x.locNeg.Y)) - + ((line1x.locPos.Y - line1x.locNeg.Y) * (line2x.locPos.X - line2x.locNeg.X)); + if(cross > 0) { + /* Condition 2 */ + reg->polarity = +1; + reg->locR = line2x.locPos; + reg->stepR = line2x.stepPos; + reg->locT = line1x.locNeg; + reg->stepT = line1x.stepNeg; + reg->leftLoc = line1x.locBeg; + reg->leftAngle = line1x.angle; + reg->bottomLoc = line2x.locBeg; + reg->bottomAngle = line2x.angle; + reg->leftLine = line1x; + reg->bottomLine = line2x; + } + else { + /* Condition 3 */ + reg->polarity = -1; + reg->locR = line1x.locNeg; + reg->stepR = line1x.stepNeg; + reg->locT = line2x.locPos; + reg->stepT = line2x.stepPos; + reg->leftLoc = line2x.locBeg; + reg->leftAngle = line2x.angle; + reg->bottomLoc = line1x.locBeg; + reg->bottomAngle = line1x.angle; + reg->leftLine = line2x; + reg->bottomLine = line1x; + } + } + else { + line2x = line2n; + err = FindTravelLimits(dec, reg, &line2x); + if(line2x.distSq < 100 || line2x.devn / sqrt((double)line2x.distSq) >= 0.1) + return DmtxFail; + + cross = ((line1x.locNeg.X - line1x.locPos.X) * (line2x.locNeg.Y - line2x.locPos.Y)) - + ((line1x.locNeg.Y - line1x.locPos.Y) * (line2x.locNeg.X - line2x.locPos.X)); + if(cross > 0) { + /* Condition 1 */ + reg->polarity = -1; + reg->locR = line2x.locNeg; + reg->stepR = line2x.stepNeg; + reg->locT = line1x.locPos; + reg->stepT = line1x.stepPos; + reg->leftLoc = line1x.locBeg; + reg->leftAngle = line1x.angle; + reg->bottomLoc = line2x.locBeg; + reg->bottomAngle = line2x.angle; + reg->leftLine = line1x; + reg->bottomLine = line2x; + } + else { + /* Condition 4 */ + reg->polarity = +1; + reg->locR = line1x.locPos; + reg->stepR = line1x.stepPos; + reg->locT = line2x.locNeg; + reg->stepT = line2x.stepNeg; + reg->leftLoc = line2x.locBeg; + reg->leftAngle = line2x.angle; + reg->bottomLoc = line1x.locBeg; + reg->bottomAngle = line1x.angle; + reg->leftLine = line2x; + reg->bottomLine = line1x; + } + } +/* CALLBACK_POINT_PLOT(reg->locR, 2, 1, 1); + CALLBACK_POINT_PLOT(reg->locT, 2, 1, 1); */ + + reg->leftKnown = reg->bottomKnown = 1; + + return DmtxPass; +} + +/** + * + * + */ +static long +DistanceSquared(DmtxPixelLoc a, DmtxPixelLoc b) +{ + long xDelta, yDelta; + + xDelta = a.X - b.X; + yDelta = a.Y - b.Y; + + return (xDelta * xDelta) + (yDelta * yDelta); +} + +/** + * + * + */ +extern DmtxPassFail +dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00, + DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01) +{ + double xMax, yMax; + double tx, ty, phi, shx, scx, scy, skx, sky; + double dimOT, dimOR, dimTX, dimRX, ratio; + DmtxVector2 vOT, vOR, vTX, vRX, vTmp; + DmtxMatrix3 m, mtxy, mphi, mshx, mscx, mscy, mscxy, msky, mskx; + + xMax = (double)(dmtxDecodeGetProp(dec, DmtxPropWidth) - 1); + yMax = (double)(dmtxDecodeGetProp(dec, DmtxPropHeight) - 1); + + if(p00.X < 0.0 || p00.Y < 0.0 || p00.X > xMax || p00.Y > yMax || + p01.X < 0.0 || p01.Y < 0.0 || p01.X > xMax || p01.Y > yMax || + p10.X < 0.0 || p10.Y < 0.0 || p10.X > xMax || p10.Y > yMax) + return DmtxFail; + + dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &p01, &p00)); /* XXX could use MagSquared() */ + dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &p10, &p00)); + dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTX, &p11, &p01)); + dimRX = dmtxVector2Mag(dmtxVector2Sub(&vRX, &p11, &p10)); + + /* Verify that sides are reasonably long */ + if(dimOT <= 8.0 || dimOR <= 8.0 || dimTX <= 8.0 || dimRX <= 8.0) + return DmtxFail; + + /* Verify that the 4 corners define a reasonably fat quadrilateral */ + ratio = dimOT / dimRX; + if(ratio <= 0.5 || ratio >= 2.0) + return DmtxFail; + + ratio = dimOR / dimTX; + if(ratio <= 0.5 || ratio >= 2.0) + return DmtxFail; + + /* Verify this is not a bowtie shape */ + if(dmtxVector2Cross(&vOR, &vRX) <= 0.0 || + dmtxVector2Cross(&vOT, &vTX) >= 0.0) + return DmtxFail; + + if(RightAngleTrueness(p00, p10, p11, M_PI_2) <= dec->squareDevn) + return DmtxFail; + if(RightAngleTrueness(p10, p11, p01, M_PI_2) <= dec->squareDevn) + return DmtxFail; + + /* Calculate values needed for transformations */ + tx = -1 * p00.X; + ty = -1 * p00.Y; + dmtxMatrix3Translate(mtxy, tx, ty); + + phi = atan2(vOT.X, vOT.Y); + dmtxMatrix3Rotate(mphi, phi); + dmtxMatrix3Multiply(m, mtxy, mphi); + + dmtxMatrix3VMultiply(&vTmp, &p10, m); + shx = -vTmp.Y / vTmp.X; + dmtxMatrix3Shear(mshx, 0.0, shx); + dmtxMatrix3MultiplyBy(m, mshx); + + scx = 1.0/vTmp.X; + dmtxMatrix3Scale(mscx, scx, 1.0); + dmtxMatrix3MultiplyBy(m, mscx); + + dmtxMatrix3VMultiply(&vTmp, &p11, m); + scy = 1.0/vTmp.Y; + dmtxMatrix3Scale(mscy, 1.0, scy); + dmtxMatrix3MultiplyBy(m, mscy); + + dmtxMatrix3VMultiply(&vTmp, &p11, m); + skx = vTmp.X; + dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0); + dmtxMatrix3MultiplyBy(m, mskx); + + dmtxMatrix3VMultiply(&vTmp, &p01, m); + sky = vTmp.Y; + dmtxMatrix3LineSkewTop(msky, sky, 1.0, 1.0); + dmtxMatrix3Multiply(reg->raw2fit, m, msky); + + /* Create inverse matrix by reverse (avoid straight matrix inversion) */ + dmtxMatrix3LineSkewTopInv(msky, sky, 1.0, 1.0); + dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0); + dmtxMatrix3Multiply(m, msky, mskx); + + dmtxMatrix3Scale(mscxy, 1.0/scx, 1.0/scy); + dmtxMatrix3MultiplyBy(m, mscxy); + + dmtxMatrix3Shear(mshx, 0.0, -shx); + dmtxMatrix3MultiplyBy(m, mshx); + + dmtxMatrix3Rotate(mphi, -phi); + dmtxMatrix3MultiplyBy(m, mphi); + + dmtxMatrix3Translate(mtxy, -tx, -ty); + dmtxMatrix3Multiply(reg->fit2raw, m, mtxy); + + return DmtxPass; +} + +/** + * + * + */ +extern DmtxPassFail +dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg) +{ + double radians; + DmtxRay2 rLeft, rBottom, rTop, rRight; + DmtxVector2 p00, p10, p11, p01; + + assert(reg->leftKnown != 0 && reg->bottomKnown != 0); + + /* Build ray representing left edge */ + rLeft.p.X = (double)reg->leftLoc.X; + rLeft.p.Y = (double)reg->leftLoc.Y; + radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES); + rLeft.v.X = cos(radians); + rLeft.v.Y = sin(radians); + rLeft.tMin = 0.0; + rLeft.tMax = dmtxVector2Norm(&rLeft.v); + + /* Build ray representing bottom edge */ + rBottom.p.X = (double)reg->bottomLoc.X; + rBottom.p.Y = (double)reg->bottomLoc.Y; + radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES); + rBottom.v.X = cos(radians); + rBottom.v.Y = sin(radians); + rBottom.tMin = 0.0; + rBottom.tMax = dmtxVector2Norm(&rBottom.v); + + /* Build ray representing top edge */ + if(reg->topKnown != 0) { + rTop.p.X = (double)reg->topLoc.X; + rTop.p.Y = (double)reg->topLoc.Y; + radians = reg->topAngle * (M_PI/DMTX_HOUGH_RES); + rTop.v.X = cos(radians); + rTop.v.Y = sin(radians); + rTop.tMin = 0.0; + rTop.tMax = dmtxVector2Norm(&rTop.v); + } + else { + rTop.p.X = (double)reg->locT.X; + rTop.p.Y = (double)reg->locT.Y; + radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES); + rTop.v.X = cos(radians); + rTop.v.Y = sin(radians); + rTop.tMin = 0.0; + rTop.tMax = rBottom.tMax; + } + + /* Build ray representing right edge */ + if(reg->rightKnown != 0) { + rRight.p.X = (double)reg->rightLoc.X; + rRight.p.Y = (double)reg->rightLoc.Y; + radians = reg->rightAngle * (M_PI/DMTX_HOUGH_RES); + rRight.v.X = cos(radians); + rRight.v.Y = sin(radians); + rRight.tMin = 0.0; + rRight.tMax = dmtxVector2Norm(&rRight.v); + } + else { + rRight.p.X = (double)reg->locR.X; + rRight.p.Y = (double)reg->locR.Y; + radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES); + rRight.v.X = cos(radians); + rRight.v.Y = sin(radians); + rRight.tMin = 0.0; + rRight.tMax = rLeft.tMax; + } + + /* Calculate 4 corners, real or imagined */ + if(dmtxRay2Intersect(&p00, &rLeft, &rBottom) == DmtxFail) + return DmtxFail; + + if(dmtxRay2Intersect(&p10, &rBottom, &rRight) == DmtxFail) + return DmtxFail; + + if(dmtxRay2Intersect(&p11, &rRight, &rTop) == DmtxFail) + return DmtxFail; + + if(dmtxRay2Intersect(&p01, &rTop, &rLeft) == DmtxFail) + return DmtxFail; + + if(dmtxRegionUpdateCorners(dec, reg, p00, p10, p11, p01) != DmtxPass) + return DmtxFail; + + return DmtxPass; +} + +/** + * + * + */ +static double +RightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle) +{ + DmtxVector2 vA, vB; + DmtxMatrix3 m; + + dmtxVector2Norm(dmtxVector2Sub(&vA, &c0, &c1)); + dmtxVector2Norm(dmtxVector2Sub(&vB, &c2, &c1)); + + dmtxMatrix3Rotate(m, angle); + dmtxMatrix3VMultiplyBy(&vB, m); + + return dmtxVector2Dot(&vA, &vB); +} + +/** + * \brief Read color of Data Matrix module location + * \param dec + * \param reg + * \param symbolRow + * \param symbolCol + * \param sizeIdx + * \return Averaged module color + */ +static int +ReadModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol, + int sizeIdx, int colorPlane) +{ + int err; + int i; + int symbolRows, symbolCols; + int color, colorTmp; + double sampleX[] = { 0.5, 0.4, 0.5, 0.6, 0.5 }; + double sampleY[] = { 0.5, 0.5, 0.4, 0.5, 0.6 }; + DmtxVector2 p; + + symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); + symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); + + color = 0; + for(i = 0; i < 5; i++) { + + p.X = (1.0/symbolCols) * (symbolCol + sampleX[i]); + p.Y = (1.0/symbolRows) * (symbolRow + sampleY[i]); + + dmtxMatrix3VMultiplyBy(&p, reg->fit2raw); + + err = dmtxDecodeGetPixelValue(dec, (int)(p.X + 0.5), (int)(p.Y + 0.5), + colorPlane, &colorTmp); + color += colorTmp; + } + + return color/5; +} + +/** + * \brief Determine barcode size, expressed in modules + * \param image + * \param reg + * \return DmtxPass | DmtxFail + */ +static DmtxPassFail +MatrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg) +{ + int row, col; + int sizeIdxBeg, sizeIdxEnd; + int sizeIdx, bestSizeIdx; + int symbolRows, symbolCols; + int jumpCount, errors; + int color; + int colorOnAvg, bestColorOnAvg; + int colorOffAvg, bestColorOffAvg; + int contrast, bestContrast; + DmtxImage *img; + + img = dec->image; + bestSizeIdx = DmtxUndefined; + bestContrast = 0; + bestColorOnAvg = bestColorOffAvg = 0; + + if(dec->sizeIdxExpected == DmtxSymbolShapeAuto) { + sizeIdxBeg = 0; + sizeIdxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount; + } + else if(dec->sizeIdxExpected == DmtxSymbolSquareAuto) { + sizeIdxBeg = 0; + sizeIdxEnd = DmtxSymbolSquareCount; + } + else if(dec->sizeIdxExpected == DmtxSymbolRectAuto) { + sizeIdxBeg = DmtxSymbolSquareCount; + sizeIdxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount; + } + else { + sizeIdxBeg = dec->sizeIdxExpected; + sizeIdxEnd = dec->sizeIdxExpected + 1; + } + + /* Test each barcode size to find best contrast in calibration modules */ + for(sizeIdx = sizeIdxBeg; sizeIdx < sizeIdxEnd; sizeIdx++) { + + symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); + symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); + colorOnAvg = colorOffAvg = 0; + + /* Sum module colors along horizontal calibration bar */ + row = symbolRows - 1; + for(col = 0; col < symbolCols; col++) { + color = ReadModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane); + if((col & 0x01) != 0x00) + colorOffAvg += color; + else + colorOnAvg += color; + } + + /* Sum module colors along vertical calibration bar */ + col = symbolCols - 1; + for(row = 0; row < symbolRows; row++) { + color = ReadModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane); + if((row & 0x01) != 0x00) + colorOffAvg += color; + else + colorOnAvg += color; + } + + colorOnAvg = (colorOnAvg * 2)/(symbolRows + symbolCols); + colorOffAvg = (colorOffAvg * 2)/(symbolRows + symbolCols); + + contrast = abs(colorOnAvg - colorOffAvg); + if(contrast < 20) + continue; + + if(contrast > bestContrast) { + bestContrast = contrast; + bestSizeIdx = sizeIdx; + bestColorOnAvg = colorOnAvg; + bestColorOffAvg = colorOffAvg; + } + } + + /* If no sizes produced acceptable contrast then call it quits */ + if(bestSizeIdx == DmtxUndefined || bestContrast < 20) + return DmtxFail; + + reg->sizeIdx = bestSizeIdx; + reg->onColor = bestColorOnAvg; + reg->offColor = bestColorOffAvg; + + reg->symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, reg->sizeIdx); + reg->symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, reg->sizeIdx); + reg->mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, reg->sizeIdx); + reg->mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, reg->sizeIdx); + + /* Tally jumps on horizontal calibration bar to verify sizeIdx */ + jumpCount = CountJumpTally(dec, reg, 0, reg->symbolRows - 1, DmtxDirRight); + errors = abs(1 + jumpCount - reg->symbolCols); + if(jumpCount < 0 || errors > 2) + return DmtxFail; + + /* Tally jumps on vertical calibration bar to verify sizeIdx */ + jumpCount = CountJumpTally(dec, reg, reg->symbolCols - 1, 0, DmtxDirUp); + errors = abs(1 + jumpCount - reg->symbolRows); + if(jumpCount < 0 || errors > 2) + return DmtxFail; + + /* Tally jumps on horizontal finder bar to verify sizeIdx */ + errors = CountJumpTally(dec, reg, 0, 0, DmtxDirRight); + if(jumpCount < 0 || errors > 2) + return DmtxFail; + + /* Tally jumps on vertical finder bar to verify sizeIdx */ + errors = CountJumpTally(dec, reg, 0, 0, DmtxDirUp); + if(errors < 0 || errors > 2) + return DmtxFail; + + /* Tally jumps on surrounding whitespace, else fail */ + errors = CountJumpTally(dec, reg, 0, -1, DmtxDirRight); + if(errors < 0 || errors > 2) + return DmtxFail; + + errors = CountJumpTally(dec, reg, -1, 0, DmtxDirUp); + if(errors < 0 || errors > 2) + return DmtxFail; + + errors = CountJumpTally(dec, reg, 0, reg->symbolRows, DmtxDirRight); + if(errors < 0 || errors > 2) + return DmtxFail; + + errors = CountJumpTally(dec, reg, reg->symbolCols, 0, DmtxDirUp); + if(errors < 0 || errors > 2) + return DmtxFail; + + return DmtxPass; +} + +/** + * \brief Count the number of number of transitions between light and dark + * \param img + * \param reg + * \param xStart + * \param yStart + * \param dir + * \return Jump count + */ +static int +CountJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir) +{ + int x, xInc = 0; + int y, yInc = 0; + int state = DmtxModuleOn; + int jumpCount = 0; + int jumpThreshold; + int tModule, tPrev; + int darkOnLight; + int color; + + assert(xStart == 0 || yStart == 0); + assert(dir == DmtxDirRight || dir == DmtxDirUp); + + if(dir == DmtxDirRight) + xInc = 1; + else + yInc = 1; + + if(xStart == -1 || xStart == reg->symbolCols || + yStart == -1 || yStart == reg->symbolRows) + state = DmtxModuleOff; + + darkOnLight = (int)(reg->offColor > reg->onColor); + jumpThreshold = abs((int)(0.4 * (reg->onColor - reg->offColor) + 0.5)); + color = ReadModuleColor(dec, reg, yStart, xStart, reg->sizeIdx, reg->flowBegin.plane); + tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; + + for(x = xStart + xInc, y = yStart + yInc; + (dir == DmtxDirRight && x < reg->symbolCols) || + (dir == DmtxDirUp && y < reg->symbolRows); + x += xInc, y += yInc) { + + tPrev = tModule; + color = ReadModuleColor(dec, reg, y, x, reg->sizeIdx, reg->flowBegin.plane); + tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; + + if(state == DmtxModuleOff) { + if(tModule > tPrev + jumpThreshold) { + jumpCount++; + state = DmtxModuleOn; + } + } + else { + if(tModule < tPrev - jumpThreshold) { + jumpCount++; + state = DmtxModuleOff; + } + } + } + + return jumpCount; +} + +/** + * + * + */ +static DmtxPointFlow +GetPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive) +{ + static const int coefficient[] = { 0, 1, 2, 1, 0, -1, -2, -1 }; + int err; + int patternIdx, coefficientIdx; + int compass, compassMax; + int mag[4] = { 0 }; + int xAdjust, yAdjust; + int color, colorPattern[8]; + DmtxPointFlow flow; + + for(patternIdx = 0; patternIdx < 8; patternIdx++) { + xAdjust = loc.X + dmtxPatternX[patternIdx]; + yAdjust = loc.Y + dmtxPatternY[patternIdx]; + err = dmtxDecodeGetPixelValue(dec, xAdjust, yAdjust, colorPlane, + &colorPattern[patternIdx]); + if(err == DmtxFail) + return dmtxBlankEdge; + } + + /* Calculate this pixel's flow intensity for each direction (-45, 0, 45, 90) */ + compassMax = 0; + for(compass = 0; compass < 4; compass++) { + + /* Add portion from each position in the convolution matrix pattern */ + for(patternIdx = 0; patternIdx < 8; patternIdx++) { + + coefficientIdx = (patternIdx - compass + 8) % 8; + if(coefficient[coefficientIdx] == 0) + continue; + + color = colorPattern[patternIdx]; + + switch(coefficient[coefficientIdx]) { + case 2: + mag[compass] += color; + /* Fall through */ + case 1: + mag[compass] += color; + break; + case -2: + mag[compass] -= color; + /* Fall through */ + case -1: + mag[compass] -= color; + break; + } + } + + /* Identify strongest compass flow */ + if(compass != 0 && abs(mag[compass]) > abs(mag[compassMax])) + compassMax = compass; + } + + /* Convert signed compass direction into unique flow directions (0-7) */ + flow.plane = colorPlane; + flow.arrive = arrive; + flow.depart = (mag[compassMax] > 0) ? compassMax + 4 : compassMax; + flow.mag = abs(mag[compassMax]); + flow.loc = loc; + + return flow; +} + +/** + * + * + */ +static DmtxPointFlow +FindStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign) +{ + int i; + int strongIdx; + int attempt, attemptDiff; + int occupied; + unsigned char *cache; + DmtxPixelLoc loc; + DmtxPointFlow flow[8]; + + attempt = (sign < 0) ? center.depart : (center.depart+4)%8; + + occupied = 0; + strongIdx = DmtxUndefined; + for(i = 0; i < 8; i++) { + + loc.X = center.loc.X + dmtxPatternX[i]; + loc.Y = center.loc.Y + dmtxPatternY[i]; + + cache = dmtxDecodeGetCache(dec, loc.X, loc.Y); + if(cache == NULL) + continue; + + if((int)(*cache & 0x80) != 0x00) { + if(++occupied > 2) + return dmtxBlankEdge; + else + continue; + } + + attemptDiff = abs(attempt - i); + if(attemptDiff > 4) + attemptDiff = 8 - attemptDiff; + if(attemptDiff > 1) + continue; + + flow[i] = GetPointFlow(dec, center.plane, loc, i); + + if(strongIdx == DmtxUndefined || flow[i].mag > flow[strongIdx].mag || + (flow[i].mag == flow[strongIdx].mag && ((i & 0x01) != 0))) { + strongIdx = i; + } + } + + return (strongIdx == DmtxUndefined) ? dmtxBlankEdge : flow[strongIdx]; +} + +/** + * + * + */ +static DmtxFollow +FollowSeek(DmtxDecode *dec, DmtxRegion *reg, int seek) +{ + int i; + int sign; + DmtxFollow follow; + + follow.loc = reg->flowBegin.loc; + follow.step = 0; + follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y); + assert(follow.ptr != NULL); + follow.neighbor = *follow.ptr; + + sign = (seek > 0) ? +1 : -1; + for(i = 0; i != seek; i += sign) { + follow = FollowStep(dec, reg, follow, sign); + assert(follow.ptr != NULL); + assert(abs(follow.step) <= reg->stepsTotal); + } + + return follow; +} + +/** + * + * + */ +static DmtxFollow +FollowSeekLoc(DmtxDecode *dec, DmtxPixelLoc loc) +{ + DmtxFollow follow; + + follow.loc = loc; + follow.step = 0; + follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y); + assert(follow.ptr != NULL); + follow.neighbor = *follow.ptr; + + return follow; +} + + +/** + * + * + */ +static DmtxFollow +FollowStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign) +{ + int patternIdx; + int stepMod; + int factor; + DmtxFollow follow; + + assert(abs(sign) == 1); + assert((int)(followBeg.neighbor & 0x40) != 0x00); + + factor = reg->stepsTotal + 1; + if(sign > 0) + stepMod = (factor + (followBeg.step % factor)) % factor; + else + stepMod = (factor - (followBeg.step % factor)) % factor; + + /* End of positive trail -- magic jump */ + if(sign > 0 && stepMod == reg->jumpToNeg) { + follow.loc = reg->finalNeg; + } + /* End of negative trail -- magic jump */ + else if(sign < 0 && stepMod == reg->jumpToPos) { + follow.loc = reg->finalPos; + } + /* Trail in progress -- normal jump */ + else { + patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3); + follow.loc.X = followBeg.loc.X + dmtxPatternX[patternIdx]; + follow.loc.Y = followBeg.loc.Y + dmtxPatternY[patternIdx]; + } + + follow.step = followBeg.step + sign; + follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y); + assert(follow.ptr != NULL); + follow.neighbor = *follow.ptr; + + return follow; +} + +/** + * + * + */ +static DmtxFollow +FollowStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign) +{ + int patternIdx; + DmtxFollow follow; + + assert(abs(sign) == 1); + assert((int)(followBeg.neighbor & 0x40) != 0x00); + + patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3); + follow.loc.X = followBeg.loc.X + dmtxPatternX[patternIdx]; + follow.loc.Y = followBeg.loc.Y + dmtxPatternY[patternIdx]; + + follow.step = followBeg.step + sign; + follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y); + assert(follow.ptr != NULL); + follow.neighbor = *follow.ptr; + + return follow; +} + +/** + * vaiiiooo + * -------- + * 0x80 v = visited bit + * 0x40 a = assigned bit + * 0x38 u = 3 bits points upstream 0-7 + * 0x07 d = 3 bits points downstream 0-7 + */ +static DmtxPassFail +TrailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal) +{ + int posAssigns, negAssigns, clears; + int sign; + int steps; + unsigned char *cache, *cacheNext, *cacheBeg; + DmtxPointFlow flow, flowNext; + DmtxPixelLoc boundMin, boundMax; + + boundMin = boundMax = flowBegin.loc; + cacheBeg = dmtxDecodeGetCache(dec, flowBegin.loc.X, flowBegin.loc.Y); + if(cacheBeg == NULL) + return DmtxFail; + *cacheBeg = (0x80 | 0x40); /* Mark location as visited and assigned */ + + reg->flowBegin = flowBegin; + + posAssigns = negAssigns = 0; + for(sign = 1; sign >= -1; sign -= 2) { + + flow = flowBegin; + cache = cacheBeg; + + for(steps = 0; ; steps++) { + + if(maxDiagonal != DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || + boundMax.Y - boundMin.Y > maxDiagonal)) + break; + + /* Find the strongest eligible neighbor */ + flowNext = FindStrongestNeighbor(dec, flow, sign); + if(flowNext.mag < 50) + break; + + /* Get the neighbor's cache location */ + cacheNext = dmtxDecodeGetCache(dec, flowNext.loc.X, flowNext.loc.Y); + if(cacheNext == NULL) + break; + assert(!(*cacheNext & 0x80)); + + /* Mark departure from current location. If flowing downstream + * (sign < 0) then departure vector here is the arrival vector + * of the next location. Upstream flow uses the opposite rule. */ + *cache |= (sign < 0) ? flowNext.arrive : flowNext.arrive << 3; + + /* Mark known direction for next location */ + /* If testing downstream (sign < 0) then next upstream is opposite of next arrival */ + /* If testing upstream (sign > 0) then next downstream is opposite of next arrival */ + *cacheNext = (sign < 0) ? (((flowNext.arrive + 4)%8) << 3) : ((flowNext.arrive + 4)%8); + *cacheNext |= (0x80 | 0x40); /* Mark location as visited and assigned */ + if(sign > 0) + posAssigns++; + else + negAssigns++; + cache = cacheNext; + flow = flowNext; + + if(flow.loc.X > boundMax.X) + boundMax.X = flow.loc.X; + else if(flow.loc.X < boundMin.X) + boundMin.X = flow.loc.X; + if(flow.loc.Y > boundMax.Y) + boundMax.Y = flow.loc.Y; + else if(flow.loc.Y < boundMin.Y) + boundMin.Y = flow.loc.Y; + +/* CALLBACK_POINT_PLOT(flow.loc, (sign > 0) ? 2 : 3, 1, 2); */ + } + + if(sign > 0) { + reg->finalPos = flow.loc; + reg->jumpToNeg = steps; + } + else { + reg->finalNeg = flow.loc; + reg->jumpToPos = steps; + } + } + reg->stepsTotal = reg->jumpToPos + reg->jumpToNeg; + reg->boundMin = boundMin; + reg->boundMax = boundMax; + + /* Clear "visited" bit from trail */ + clears = TrailClear(dec, reg, 0x80); + assert(posAssigns + negAssigns == clears - 1); + + /* XXX clean this up ... redundant test above */ + if(maxDiagonal != DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || + boundMax.Y - boundMin.Y > maxDiagonal)) + return DmtxFail; + + return DmtxPass; +} + +/** + * recives bresline, and follows strongest neighbor unless it involves + * ratcheting bresline inward or backward (although back + outward is allowed). + * + */ +static int +TrailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir) +{ + unsigned char *beforeCache, *afterCache; + DmtxBoolean onEdge; + int distSq, distSqMax; + int travel, outward; + int xDiff, yDiff; + int steps; + int stepDir, dirMap[] = { 0, 1, 2, 7, 8, 3, 6, 5, 4 }; + DmtxPassFail err; + DmtxPixelLoc beforeStep, afterStep; + DmtxPointFlow flow, flowNext; + DmtxPixelLoc loc0; + int xStep, yStep; + + loc0 = line.loc; + flow = GetPointFlow(dec, reg->flowBegin.plane, loc0, dmtxNeighborNone); + distSqMax = (line.xDelta * line.xDelta) + (line.yDelta * line.yDelta); + steps = 0; + onEdge = DmtxTrue; + + beforeStep = loc0; + beforeCache = dmtxDecodeGetCache(dec, loc0.X, loc0.Y); + if(beforeCache == NULL) + return DmtxFail; + else + *beforeCache = 0x00; /* probably should just overwrite one direction */ + + do { + if(onEdge == DmtxTrue) { + flowNext = FindStrongestNeighbor(dec, flow, streamDir); + if(flowNext.mag == DmtxUndefined) + break; + + err = BresLineGetStep(line, flowNext.loc, &travel, &outward); + if(flowNext.mag < 50 || outward < 0 || (outward == 0 && travel < 0)) { + onEdge = DmtxFalse; + } + else { + BresLineStep(&line, travel, outward); + flow = flowNext; + } + } + + if(onEdge == DmtxFalse) { + BresLineStep(&line, 1, 0); + flow = GetPointFlow(dec, reg->flowBegin.plane, line.loc, dmtxNeighborNone); + if(flow.mag > 50) + onEdge = DmtxTrue; + } + + afterStep = line.loc; + afterCache = dmtxDecodeGetCache(dec, afterStep.X, afterStep.Y); + if(afterCache == NULL) + break; + + /* Determine step direction using pure magic */ + xStep = afterStep.X - beforeStep.X; + yStep = afterStep.Y - beforeStep.Y; + assert(abs(xStep) <= 1 && abs(yStep) <= 1); + stepDir = dirMap[3 * yStep + xStep + 4]; + assert(stepDir != 8); + + if(streamDir < 0) { + *beforeCache |= (0x40 | stepDir); + *afterCache = (((stepDir + 4)%8) << 3); + } + else { + *beforeCache |= (0x40 | (stepDir << 3)); + *afterCache = ((stepDir + 4)%8); + } + + /* Guaranteed to have taken one step since top of loop */ + xDiff = line.loc.X - loc0.X; + yDiff = line.loc.Y - loc0.Y; + distSq = (xDiff * xDiff) + (yDiff * yDiff); + + beforeStep = line.loc; + beforeCache = afterCache; + steps++; + + } while(distSq < distSqMax); + + return steps; +} + +/** + * + * + */ +static int +TrailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask) +{ + int clears; + DmtxFollow follow; + + assert((clearMask | 0xff) == 0xff); + + /* Clear "visited" bit from trail */ + clears = 0; + follow = FollowSeek(dec, reg, 0); + while(abs(follow.step) <= reg->stepsTotal) { + assert((int)(*follow.ptr & clearMask) != 0x00); + *follow.ptr &= (clearMask ^ 0xff); + follow = FollowStep(dec, reg, follow, +1); + clears++; + } + + return clears; +} + +/** + * + * + */ +static DmtxBestLine +FindBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir, int houghAvoid) +{ + int *hough_temp = calloc(3 * DMTX_HOUGH_RES, sizeof(int)); int (*hough)[DMTX_HOUGH_RES] = (int (*)[DMTX_HOUGH_RES]) hough_temp; // [3][DMTX_HOUGH_RES] = { { 0 } }; + int houghMin, houghMax; + char *houghTest = malloc(DMTX_HOUGH_RES); // [DMTX_HOUGH_RES]; + int i; + int step; + int sign; + int tripSteps; + int angleBest; + int hOffset, hOffsetBest; + int xDiff, yDiff; + int dH; + DmtxRay2 rH; + DmtxFollow follow; + DmtxBestLine line; + DmtxPixelLoc rHp; + + memset(&line, 0x00, sizeof(DmtxBestLine)); + memset(&rH, 0x00, sizeof(DmtxRay2)); + angleBest = 0; + hOffset = hOffsetBest = 0; + + /* Always follow path flowing away from the trail start */ + if(step0 != 0) { + if(step0 > 0) { + sign = +1; + tripSteps = (step1 - step0 + reg->stepsTotal) % reg->stepsTotal; + } + else { + sign = -1; + tripSteps = (step0 - step1 + reg->stepsTotal) % reg->stepsTotal; + } + if(tripSteps == 0) + tripSteps = reg->stepsTotal; + } + else if(step1 != 0) { + sign = (step1 > 0) ? +1 : -1; + tripSteps = abs(step1); + } + else if(step1 == 0) { + sign = +1; + tripSteps = reg->stepsTotal; + } + assert(sign == streamDir); + + follow = FollowSeek(dec, reg, step0); + rHp = follow.loc; + + line.stepBeg = line.stepPos = line.stepNeg = step0; + line.locBeg = follow.loc; + line.locPos = follow.loc; + line.locNeg = follow.loc; + + /* Predetermine which angles to test */ + for(i = 0; i < DMTX_HOUGH_RES; i++) { + if(houghAvoid == DmtxUndefined) { + houghTest[i] = 1; + } + else { + houghMin = (houghAvoid + DMTX_HOUGH_RES/6) % DMTX_HOUGH_RES; + houghMax = (houghAvoid - DMTX_HOUGH_RES/6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES; + if(houghMin > houghMax) + houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0; + else + houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0; + } + } + + /* Test each angle for steps along path */ + for(step = 0; step < tripSteps; step++) { + + xDiff = follow.loc.X - rHp.X; + yDiff = follow.loc.Y - rHp.Y; + + /* Increment Hough accumulator */ + for(i = 0; i < DMTX_HOUGH_RES; i++) { + + if((int)houghTest[i] == 0) + continue; + + dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff); + if(dH >= -384 && dH <= 384) { + + if(dH > 128) + hOffset = 2; + else if(dH >= -128) + hOffset = 1; + else + hOffset = 0; + + hough[hOffset][i]++; + + /* New angle takes over lead */ + if(hough[hOffset][i] > hough[hOffsetBest][angleBest]) { + angleBest = i; + hOffsetBest = hOffset; + } + } + } + +/* CALLBACK_POINT_PLOT(follow.loc, (sign > 1) ? 4 : 3, 1, 2); */ + + follow = FollowStep(dec, reg, follow, sign); + } + + line.angle = angleBest; + line.hOffset = hOffsetBest; + line.mag = hough[hOffsetBest][angleBest]; + + free(houghTest); + free(hough_temp); + + return line; +} + +/** + * + * + */ +static DmtxBestLine +FindBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid) +{ + int *hough_temp = calloc(3 * DMTX_HOUGH_RES, sizeof(int)); int (*hough)[DMTX_HOUGH_RES] = (int (*)[DMTX_HOUGH_RES]) hough_temp; // [3][DMTX_HOUGH_RES] = { { 0 } }; + int houghMin, houghMax; + char *houghTest = malloc(DMTX_HOUGH_RES); // [DMTX_HOUGH_RES]; + int i; + int step; + int angleBest; + int hOffset, hOffsetBest; + int xDiff, yDiff; + int dH; + DmtxRay2 rH; + DmtxBestLine line; + DmtxPixelLoc rHp; + DmtxFollow follow; + + memset(&line, 0x00, sizeof(DmtxBestLine)); + memset(&rH, 0x00, sizeof(DmtxRay2)); + angleBest = 0; + hOffset = hOffsetBest = 0; + + follow = FollowSeekLoc(dec, loc0); + rHp = line.locBeg = line.locPos = line.locNeg = follow.loc; + line.stepBeg = line.stepPos = line.stepNeg = 0; + + /* Predetermine which angles to test */ + for(i = 0; i < DMTX_HOUGH_RES; i++) { + if(houghAvoid == DmtxUndefined) { + houghTest[i] = 1; + } + else { + houghMin = (houghAvoid + DMTX_HOUGH_RES/6) % DMTX_HOUGH_RES; + houghMax = (houghAvoid - DMTX_HOUGH_RES/6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES; + if(houghMin > houghMax) + houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0; + else + houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0; + } + } + + /* Test each angle for steps along path */ + for(step = 0; step < tripSteps; step++) { + + xDiff = follow.loc.X - rHp.X; + yDiff = follow.loc.Y - rHp.Y; + + /* Increment Hough accumulator */ + for(i = 0; i < DMTX_HOUGH_RES; i++) { + + if((int)houghTest[i] == 0) + continue; + + dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff); + if(dH >= -384 && dH <= 384) { + if(dH > 128) + hOffset = 2; + else if(dH >= -128) + hOffset = 1; + else + hOffset = 0; + + hough[hOffset][i]++; + + /* New angle takes over lead */ + if(hough[hOffset][i] > hough[hOffsetBest][angleBest]) { + angleBest = i; + hOffsetBest = hOffset; + } + } + } + +/* CALLBACK_POINT_PLOT(follow.loc, (sign > 1) ? 4 : 3, 1, 2); */ + + follow = FollowStep2(dec, follow, sign); + } + + line.angle = angleBest; + line.hOffset = hOffsetBest; + line.mag = hough[hOffsetBest][angleBest]; + + free(houghTest); + free(hough_temp); + + return line; +} + +/** + * + * + */ +static DmtxPassFail +FindTravelLimits(DmtxDecode *dec, DmtxRegion *reg, DmtxBestLine *line) +{ + int i; + int distSq, distSqMax; + int xDiff, yDiff; + int posRunning, negRunning; + int posTravel, negTravel; + int posWander, posWanderMin, posWanderMax, posWanderMinLock, posWanderMaxLock; + int negWander, negWanderMin, negWanderMax, negWanderMinLock, negWanderMaxLock; + int cosAngle, sinAngle; + DmtxFollow followPos, followNeg; + DmtxPixelLoc loc0, posMax, negMax; + + /* line->stepBeg is already known to sit on the best Hough line */ + followPos = followNeg = FollowSeek(dec, reg, line->stepBeg); + loc0 = followPos.loc; + + cosAngle = rHvX[line->angle]; + sinAngle = rHvY[line->angle]; + + distSqMax = 0; + posMax = negMax = followPos.loc; + + posTravel = negTravel = 0; + posWander = posWanderMin = posWanderMax = posWanderMinLock = posWanderMaxLock = 0; + negWander = negWanderMin = negWanderMax = negWanderMinLock = negWanderMaxLock = 0; + + for(i = 0; i < reg->stepsTotal/2; i++) { + + posRunning = (int)(i < 10 || abs(posWander) < abs(posTravel)); + negRunning = (int)(i < 10 || abs(negWander) < abs(negTravel)); + + if(posRunning != 0) { + xDiff = followPos.loc.X - loc0.X; + yDiff = followPos.loc.Y - loc0.Y; + posTravel = (cosAngle * xDiff) + (sinAngle * yDiff); + posWander = (cosAngle * yDiff) - (sinAngle * xDiff); + + if(posWander >= -3*256 && posWander <= 3*256) { + distSq = DistanceSquared(followPos.loc, negMax); + if(distSq > distSqMax) { + posMax = followPos.loc; + distSqMax = distSq; + line->stepPos = followPos.step; + line->locPos = followPos.loc; + posWanderMinLock = posWanderMin; + posWanderMaxLock = posWanderMax; + } + } + else { + posWanderMin = min(posWanderMin, posWander); + posWanderMax = max(posWanderMax, posWander); + } + } + else if(!negRunning) { + break; + } + + if(negRunning != 0) { + xDiff = followNeg.loc.X - loc0.X; + yDiff = followNeg.loc.Y - loc0.Y; + negTravel = (cosAngle * xDiff) + (sinAngle * yDiff); + negWander = (cosAngle * yDiff) - (sinAngle * xDiff); + + if(negWander >= -3*256 && negWander < 3*256) { + distSq = DistanceSquared(followNeg.loc, posMax); + if(distSq > distSqMax) { + negMax = followNeg.loc; + distSqMax = distSq; + line->stepNeg = followNeg.step; + line->locNeg = followNeg.loc; + negWanderMinLock = negWanderMin; + negWanderMaxLock = negWanderMax; + } + } + else { + negWanderMin = min(negWanderMin, negWander); + negWanderMax = max(negWanderMax, negWander); + } + } + else if(!posRunning) { + break; + } + +/* CALLBACK_POINT_PLOT(followPos.loc, 2, 1, 2); + CALLBACK_POINT_PLOT(followNeg.loc, 4, 1, 2); */ + + followPos = FollowStep(dec, reg, followPos, +1); + followNeg = FollowStep(dec, reg, followNeg, -1); + } + line->devn = max(posWanderMaxLock - posWanderMinLock, negWanderMaxLock - negWanderMinLock)/256; + line->distSq = distSqMax; + +/* CALLBACK_POINT_PLOT(posMax, 2, 1, 1); + CALLBACK_POINT_PLOT(negMax, 2, 1, 1); */ + + return DmtxPass; +} + +/** + * + * + */ +static DmtxPassFail +MatrixRegionAlignCalibEdge(DmtxDecode *dec, DmtxRegion *reg, int edgeLoc) +{ + int streamDir; + int steps; + int avoidAngle; + int symbolShape; + DmtxVector2 pTmp; + DmtxPixelLoc loc0, loc1, locOrigin; + DmtxBresLine line; + DmtxFollow follow; + DmtxBestLine bestLine; + + /* Determine pixel coordinates of origin */ + pTmp.X = 0.0; + pTmp.Y = 0.0; + dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw); + locOrigin.X = (int)(pTmp.X + 0.5); + locOrigin.Y = (int)(pTmp.Y + 0.5); + + if(dec->sizeIdxExpected == DmtxSymbolSquareAuto || + (dec->sizeIdxExpected >= DmtxSymbol10x10 && + dec->sizeIdxExpected <= DmtxSymbol144x144)) + symbolShape = DmtxSymbolSquareAuto; + else if(dec->sizeIdxExpected == DmtxSymbolRectAuto || + (dec->sizeIdxExpected >= DmtxSymbol8x18 && + dec->sizeIdxExpected <= DmtxSymbol16x48)) + symbolShape = DmtxSymbolRectAuto; + else + symbolShape = DmtxSymbolShapeAuto; + + /* Determine end locations of test line */ + if(edgeLoc == DmtxEdgeTop) { + streamDir = reg->polarity * -1; + avoidAngle = reg->leftLine.angle; + follow = FollowSeekLoc(dec, reg->locT); + pTmp.X = 0.8; + pTmp.Y = (symbolShape == DmtxSymbolRectAuto) ? 0.2 : 0.6; + } + else { + assert(edgeLoc == DmtxEdgeRight); + streamDir = reg->polarity; + avoidAngle = reg->bottomLine.angle; + follow = FollowSeekLoc(dec, reg->locR); + pTmp.X = (symbolShape == DmtxSymbolSquareAuto) ? 0.7 : 0.9; + pTmp.Y = 0.8; + } + + dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw); + loc1.X = (int)(pTmp.X + 0.5); + loc1.Y = (int)(pTmp.Y + 0.5); + + loc0 = follow.loc; + line = BresLineInit(loc0, loc1, locOrigin); + steps = TrailBlazeGapped(dec, reg, line, streamDir); + + bestLine = FindBestSolidLine2(dec, loc0, steps, streamDir, avoidAngle); + if(bestLine.mag < 5) { + ; + } + + if(edgeLoc == DmtxEdgeTop) { + reg->topKnown = 1; + reg->topAngle = bestLine.angle; + reg->topLoc = bestLine.locBeg; + } + else { + reg->rightKnown = 1; + reg->rightAngle = bestLine.angle; + reg->rightLoc = bestLine.locBeg; + } + + return DmtxPass; +} + +/** + * + * + */ +static DmtxBresLine +BresLineInit(DmtxPixelLoc loc0, DmtxPixelLoc loc1, DmtxPixelLoc locInside) +{ + int cp; + DmtxBresLine line; + DmtxPixelLoc *locBeg, *locEnd; + + /* XXX Verify that loc0 and loc1 are inbounds */ + + /* Values that stay the same after initialization */ + line.loc0 = loc0; + line.loc1 = loc1; + line.xStep = (loc0.X < loc1.X) ? +1 : -1; + line.yStep = (loc0.Y < loc1.Y) ? +1 : -1; + line.xDelta = abs(loc1.X - loc0.X); + line.yDelta = abs(loc1.Y - loc0.Y); + line.steep = (int)(line.yDelta > line.xDelta); + + /* Take cross product to determine outward step */ + if(line.steep != 0) { + /* Point first vector up to get correct sign */ + if(loc0.Y < loc1.Y) { + locBeg = &loc0; + locEnd = &loc1; + } + else { + locBeg = &loc1; + locEnd = &loc0; + } + cp = (((locEnd->X - locBeg->X) * (locInside.Y - locEnd->Y)) - + ((locEnd->Y - locBeg->Y) * (locInside.X - locEnd->X))); + + line.xOut = (cp > 0) ? +1 : -1; + line.yOut = 0; + } + else { + /* Point first vector left to get correct sign */ + if(loc0.X > loc1.X) { + locBeg = &loc0; + locEnd = &loc1; + } + else { + locBeg = &loc1; + locEnd = &loc0; + } + cp = (((locEnd->X - locBeg->X) * (locInside.Y - locEnd->Y)) - + ((locEnd->Y - locBeg->Y) * (locInside.X - locEnd->X))); + + line.xOut = 0; + line.yOut = (cp > 0) ? +1 : -1; + } + + /* Values that change while stepping through line */ + line.loc = loc0; + line.travel = 0; + line.outward = 0; + line.error = (line.steep) ? line.yDelta/2 : line.xDelta/2; + +/* CALLBACK_POINT_PLOT(loc0, 3, 1, 1); + CALLBACK_POINT_PLOT(loc1, 3, 1, 1); */ + + return line; +} + +/** + * + * + */ +static DmtxPassFail +BresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward) +{ + /* Determine necessary step along and outward from Bresenham line */ + if(line.steep != 0) { + *travel = (line.yStep > 0) ? target.Y - line.loc.Y : line.loc.Y - target.Y; + BresLineStep(&line, *travel, 0); + *outward = (line.xOut > 0) ? target.X - line.loc.X : line.loc.X - target.X; + assert(line.yOut == 0); + } + else { + *travel = (line.xStep > 0) ? target.X - line.loc.X : line.loc.X - target.X; + BresLineStep(&line, *travel, 0); + *outward = (line.yOut > 0) ? target.Y - line.loc.Y : line.loc.Y - target.Y; + assert(line.xOut == 0); + } + + return DmtxPass; +} + +/** + * + * + */ +static DmtxPassFail +BresLineStep(DmtxBresLine *line, int travel, int outward) +{ + int i; + DmtxBresLine lineNew; + + lineNew = *line; + + assert(abs(travel) < 2); + assert(abs(outward) >= 0); + + /* Perform forward step */ + if(travel > 0) { + lineNew.travel++; + if(lineNew.steep != 0) { + lineNew.loc.Y += lineNew.yStep; + lineNew.error -= lineNew.xDelta; + if(lineNew.error < 0) { + lineNew.loc.X += lineNew.xStep; + lineNew.error += lineNew.yDelta; + } + } + else { + lineNew.loc.X += lineNew.xStep; + lineNew.error -= lineNew.yDelta; + if(lineNew.error < 0) { + lineNew.loc.Y += lineNew.yStep; + lineNew.error += lineNew.xDelta; + } + } + } + else if(travel < 0) { + lineNew.travel--; + if(lineNew.steep != 0) { + lineNew.loc.Y -= lineNew.yStep; + lineNew.error += lineNew.xDelta; + if(lineNew.error >= lineNew.yDelta) { + lineNew.loc.X -= lineNew.xStep; + lineNew.error -= lineNew.yDelta; + } + } + else { + lineNew.loc.X -= lineNew.xStep; + lineNew.error += lineNew.yDelta; + if(lineNew.error >= lineNew.xDelta) { + lineNew.loc.Y -= lineNew.yStep; + lineNew.error -= lineNew.xDelta; + } + } + } + + for(i = 0; i < outward; i++) { + /* Outward steps */ + lineNew.outward++; + lineNew.loc.X += lineNew.xOut; + lineNew.loc.Y += lineNew.yOut; + } + + *line = lineNew; + + return DmtxPass; +} + +/** + * + * + */ +#ifdef NOTDEFINED +static void +WriteDiagnosticImage(DmtxDecode *dec, DmtxRegion *reg, char *imagePath) +{ + int row, col; + int width, height; + unsigned char *cache; + int rgb[3]; + FILE *fp; + DmtxVector2 p; + DmtxImage *img; + + assert(reg != NULL); + + fp = fopen(imagePath, "wb"); + if(fp == NULL) { + exit(3); + } + + width = dmtxDecodeGetProp(dec, DmtxPropWidth); + height = dmtxDecodeGetProp(dec->image, DmtxPropHeight); + + img = dmtxImageCreate(NULL, width, height, DmtxPack24bppRGB); + + /* Populate image */ + for(row = 0; row < height; row++) { + for(col = 0; col < width; col++) { + + cache = dmtxDecodeGetCache(dec, col, row); + if(cache == NULL) { + rgb[0] = 0; + rgb[1] = 0; + rgb[2] = 128; + } + else { + dmtxDecodeGetPixelValue(dec, col, row, 0, &rgb[0]); + dmtxDecodeGetPixelValue(dec, col, row, 1, &rgb[1]); + dmtxDecodeGetPixelValue(dec, col, row, 2, &rgb[2]); + + p.X = col; + p.Y = row; + dmtxMatrix3VMultiplyBy(&p, reg->raw2fit); + + if(p.X < 0.0 || p.X > 1.0 || p.Y < 0.0 || p.Y > 1.0) { + rgb[0] = 0; + rgb[1] = 0; + rgb[2] = 128; + } + else if(p.X + p.Y > 1.0) { + rgb[0] += (0.4 * (255 - rgb[0])); + rgb[1] += (0.4 * (255 - rgb[1])); + rgb[2] += (0.4 * (255 - rgb[2])); + } + } + + dmtxImageSetRgb(img, col, row, rgb); + } + } + + /* Write additional markers */ + rgb[0] = 255; + rgb[1] = 0; + rgb[2] = 0; + dmtxImageSetRgb(img, reg->topLoc.X, reg->topLoc.Y, rgb); + dmtxImageSetRgb(img, reg->rightLoc.X, reg->rightLoc.Y, rgb); + + /* Write image to PNM file */ + fprintf(fp, "P6\n%d %d\n255\n", width, height); + for(row = height - 1; row >= 0; row--) { + for(col = 0; col < width; col++) { + dmtxImageGetRgb(img, col, row, rgb); + fwrite(rgb, sizeof(char), 3, fp); + } + } + + dmtxImageDestroy(&img); + + fclose(fp); +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxsymbol.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxsymbol.c + * \brief Data Matrix symbol attributes + */ + +/** + * \brief Retrieve property based on symbol size + * \param attribute + * \param sizeIdx + * \return Attribute value + */ +extern int +dmtxGetSymbolAttribute(int attribute, int sizeIdx) +{ + static const int symbolRows[] = { 10, 12, 14, 16, 18, 20, 22, 24, 26, + 32, 36, 40, 44, 48, 52, + 64, 72, 80, 88, 96, 104, + 120, 132, 144, + 8, 8, 12, 12, 16, 16 }; + + static const int symbolCols[] = { 10, 12, 14, 16, 18, 20, 22, 24, 26, + 32, 36, 40, 44, 48, 52, + 64, 72, 80, 88, 96, 104, + 120, 132, 144, + 18, 32, 26, 36, 36, 48 }; + + static const int dataRegionRows[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24, + 14, 16, 18, 20, 22, 24, + 14, 16, 18, 20, 22, 24, + 18, 20, 22, + 6, 6, 10, 10, 14, 14 }; + + static const int dataRegionCols[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24, + 14, 16, 18, 20, 22, 24, + 14, 16, 18, 20, 22, 24, + 18, 20, 22, + 16, 14, 24, 16, 16, 22 }; + + static const int horizDataRegions[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, + 6, 6, 6, + 1, 2, 1, 2, 2, 2 }; + + static const int interleavedBlocks[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, + 2, 4, 4, 4, 4, 6, + 6, 8, 10, + 1, 1, 1, 1, 1, 1 }; + + static const int symbolDataWords[] = { 3, 5, 8, 12, 18, 22, 30, 36, 44, + 62, 86, 114, 144, 174, 204, + 280, 368, 456, 576, 696, 816, + 1050, 1304, 1558, + 5, 10, 16, 22, 32, 49 }; + + static const int blockErrorWords[] = { 5, 7, 10, 12, 14, 18, 20, 24, 28, + 36, 42, 48, 56, 68, 42, + 56, 36, 48, 56, 68, 56, + 68, 62, 62, + 7, 11, 14, 18, 24, 28 }; + + static const int blockMaxCorrectable[] = { 2, 3, 5, 6, 7, 9, 10, 12, 14, + 18, 21, 24, 28, 34, 21, + 28, 18, 24, 28, 34, 28, + 34, 31, 31, + 3, 5, 7, 9, 12, 14 }; + + if(sizeIdx < 0 || sizeIdx >= DmtxSymbolSquareCount + DmtxSymbolRectCount) + return DmtxUndefined; + + switch(attribute) { + case DmtxSymAttribSymbolRows: + return symbolRows[sizeIdx]; + case DmtxSymAttribSymbolCols: + return symbolCols[sizeIdx]; + case DmtxSymAttribDataRegionRows: + return dataRegionRows[sizeIdx]; + case DmtxSymAttribDataRegionCols: + return dataRegionCols[sizeIdx]; + case DmtxSymAttribHorizDataRegions: + return horizDataRegions[sizeIdx]; + case DmtxSymAttribVertDataRegions: + return (sizeIdx < DmtxSymbolSquareCount) ? horizDataRegions[sizeIdx] : 1; + case DmtxSymAttribMappingMatrixRows: + return dataRegionRows[sizeIdx] * + dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, sizeIdx); + case DmtxSymAttribMappingMatrixCols: + return dataRegionCols[sizeIdx] * horizDataRegions[sizeIdx]; + case DmtxSymAttribInterleavedBlocks: + return interleavedBlocks[sizeIdx]; + case DmtxSymAttribBlockErrorWords: + return blockErrorWords[sizeIdx]; + case DmtxSymAttribBlockMaxCorrectable: + return blockMaxCorrectable[sizeIdx]; + case DmtxSymAttribSymbolDataWords: + return symbolDataWords[sizeIdx]; + case DmtxSymAttribSymbolErrorWords: + return blockErrorWords[sizeIdx] * interleavedBlocks[sizeIdx]; + case DmtxSymAttribSymbolMaxCorrectable: + return blockMaxCorrectable[sizeIdx] * interleavedBlocks[sizeIdx]; + } + + return DmtxUndefined; +} + +/** + * \brief Retrieve data size for a specific symbol size and block number + * \param sizeIdx + * \param blockIdx + * \return Attribute value + */ +extern int +dmtxGetBlockDataSize(int sizeIdx, int blockIdx) +{ + int symbolDataWords; + int interleavedBlocks; + int count; + + symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); + interleavedBlocks = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx); + + if(symbolDataWords < 1 || interleavedBlocks < 1) + return DmtxUndefined; + + count = (int)(symbolDataWords/interleavedBlocks); + + return (sizeIdx == DmtxSymbol144x144 && blockIdx < 8) ? count + 1 : count; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxplacemod.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxplacemod.c + * \brief Data Matrix module placement + */ + +/** + * receives symbol row and col and returns status + * DmtxModuleOn / !DmtxModuleOn (DmtxModuleOff) + * DmtxModuleAssigned + * DmtxModuleVisited + * DmtxModuleData / !DmtxModuleData (DmtxModuleAlignment) + * row and col are expressed in symbol coordinates, so (0,0) is the intersection of the "L" + */ +int +dmtxSymbolModuleStatus(DmtxMessage *message, int sizeIdx, int symbolRow, int symbolCol) +{ + int symbolRowReverse; + int mappingRow, mappingCol; + int dataRegionRows, dataRegionCols; + int symbolRows, mappingCols; + + dataRegionRows = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, sizeIdx); + dataRegionCols = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, sizeIdx); + symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); + mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx); + + symbolRowReverse = symbolRows - symbolRow - 1; + mappingRow = symbolRowReverse - 1 - 2 * (symbolRowReverse / (dataRegionRows+2)); + mappingCol = symbolCol - 1 - 2 * (symbolCol / (dataRegionCols+2)); + + /* Solid portion of alignment patterns */ + if(symbolRow % (dataRegionRows+2) == 0 || + symbolCol % (dataRegionCols+2) == 0) + return (DmtxModuleOnRGB | (!DmtxModuleData)); + + /* Horinzontal calibration bars */ + if((symbolRow+1) % (dataRegionRows+2) == 0) + return (((symbolCol & 0x01) ? 0 : DmtxModuleOnRGB) | (!DmtxModuleData)); + + /* Vertical calibration bars */ + if((symbolCol+1) % (dataRegionCols+2) == 0) + return (((symbolRow & 0x01) ? 0 : DmtxModuleOnRGB) | (!DmtxModuleData)); + + /* Data modules */ + return (message->array[mappingRow * mappingCols + mappingCol] | DmtxModuleData); +} + +/** + * \brief Logical relationship between bit and module locations + * \param modules + * \param codewords + * \param sizeIdx + * \param moduleOnColor + * \return Number of codewords read + */ +static int +ModulePlacementEcc200(unsigned char *modules, unsigned char *codewords, int sizeIdx, int moduleOnColor) +{ + int row, col, chr; + int mappingRows, mappingCols; + + assert(moduleOnColor & (DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue)); + + mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx); + mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx); + + /* Start in the nominal location for the 8th bit of the first character */ + chr = 0; + row = 4; + col = 0; + + do { + /* Repeatedly first check for one of the special corner cases */ + if((row == mappingRows) && (col == 0)) + PatternShapeSpecial1(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor); + else if((row == mappingRows-2) && (col == 0) && (mappingCols%4 != 0)) + PatternShapeSpecial2(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor); + else if((row == mappingRows-2) && (col == 0) && (mappingCols%8 == 4)) + PatternShapeSpecial3(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor); + else if((row == mappingRows+4) && (col == 2) && (mappingCols%8 == 0)) + PatternShapeSpecial4(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor); + + /* Sweep upward diagonally, inserting successive characters */ + do { + if((row < mappingRows) && (col >= 0) && + !(modules[row*mappingCols+col] & DmtxModuleVisited)) + PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor); + row -= 2; + col += 2; + } while ((row >= 0) && (col < mappingCols)); + row += 1; + col += 3; + + /* Sweep downward diagonally, inserting successive characters */ + do { + if((row >= 0) && (col < mappingCols) && + !(modules[row*mappingCols+col] & DmtxModuleVisited)) + PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor); + row += 2; + col -= 2; + } while ((row < mappingRows) && (col >= 0)); + row += 3; + col += 1; + /* ... until the entire modules array is scanned */ + } while ((row < mappingRows) || (col < mappingCols)); + + /* If lower righthand corner is untouched then fill in the fixed pattern */ + if(!(modules[mappingRows * mappingCols - 1] & + DmtxModuleVisited)) { + + modules[mappingRows * mappingCols - 1] |= moduleOnColor; + modules[(mappingRows * mappingCols) - mappingCols - 2] |= moduleOnColor; + } /* XXX should this fixed pattern also be used in reading somehow? */ + + /* XXX compare that chr == region->dataSize here */ + return chr; /* XXX number of codewords read off */ +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param row + * \param col + * \param codeword + * \param moduleOnColor + * \return void + */ +static void +PatternShapeStandard(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int moduleOnColor) +{ + PlaceModule(modules, mappingRows, mappingCols, row-2, col-2, codeword, DmtxMaskBit1, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row-2, col-1, codeword, DmtxMaskBit2, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row-1, col-2, codeword, DmtxMaskBit3, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row-1, col-1, codeword, DmtxMaskBit4, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row-1, col, codeword, DmtxMaskBit5, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row, col-2, codeword, DmtxMaskBit6, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row, col-1, codeword, DmtxMaskBit7, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, row, col, codeword, DmtxMaskBit8, moduleOnColor); +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param codeword + * \param moduleOnColor + * \return void + */ +static void +PatternShapeSpecial1(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor) +{ + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit1, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 1, codeword, DmtxMaskBit2, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 2, codeword, DmtxMaskBit3, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit6, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 2, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 3, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor); +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param codeword + * \param moduleOnColor + * \return void + */ +static void +PatternShapeSpecial2(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor) +{ + PlaceModule(modules, mappingRows, mappingCols, mappingRows-3, 0, codeword, DmtxMaskBit1, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-2, 0, codeword, DmtxMaskBit2, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit3, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-4, codeword, DmtxMaskBit4, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-3, codeword, DmtxMaskBit5, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit6, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor); +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param codeword + * \param moduleOnColor + * \return void + */ +static void +PatternShapeSpecial3(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor) +{ + PlaceModule(modules, mappingRows, mappingCols, mappingRows-3, 0, codeword, DmtxMaskBit1, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-2, 0, codeword, DmtxMaskBit2, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit3, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit6, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 2, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 3, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor); +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param codeword + * \param moduleOnColor + * \return void + */ +static void +PatternShapeSpecial4(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor) +{ + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit1, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, mappingCols-1, codeword, DmtxMaskBit2, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-3, codeword, DmtxMaskBit3, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-3, codeword, DmtxMaskBit6, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-2, codeword, DmtxMaskBit7, moduleOnColor); + PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor); +} + +/** + * \brief XXX + * \param modules + * \param mappingRows + * \param mappingCols + * \param row + * \param col + * \param codeword + * \param mask + * \param moduleOnColor + * \return void + */ +static void +PlaceModule(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int mask, int moduleOnColor) +{ + if(row < 0) { + row += mappingRows; + col += 4 - ((mappingRows+4)%8); + } + if(col < 0) { + col += mappingCols; + row += 4 - ((mappingCols+4)%8); + } + + /* If module has already been assigned then we are decoding the pattern into codewords */ + if((modules[row*mappingCols+col] & DmtxModuleAssigned) != 0) { + if((modules[row*mappingCols+col] & moduleOnColor) != 0) + *codeword |= mask; + else + *codeword &= (0xff ^ mask); + } + /* Otherwise we are encoding the codewords into a pattern */ + else { + if((*codeword & mask) != 0x00) + modules[row*mappingCols+col] |= moduleOnColor; + + modules[row*mappingCols+col] |= DmtxModuleAssigned; + } + + modules[row*mappingCols+col] |= DmtxModuleVisited; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxreedsol.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2011 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * --------------------------------------------------------- + * Portions of this file were derived from the Reed-Solomon + * encoder/decoder released by Simon Rockliff in June 1991. + * --------------------------------------------------------- + * + * Contact: Mike Laughton + * + * \file dmtxreedsol.c + */ + +/** + * TODO: + * o try doxygen using using the JavaDoc style and JAVADOC_AUTOBRIEF = YES + * o switch doxygen to simplified syntax, and using "\file" instead of "@file" + */ + +#define NN 255 +#define MAX_ERROR_WORD_COUNT 68 + +/* GF add (a + b) */ +#define GfAdd(a,b) \ + ((a) ^ (b)) + +/* GF multiply (a * b) */ +#define GfMult(a,b) \ + (((a) == 0 || (b) == 0) ? 0 : antilog301[(log301[(a)] + log301[(b)]) % NN]) + +/* GF multiply by antilog (a * alpha**b) */ +#define GfMultAntilog(a,b) \ + (((a) == 0) ? 0 : antilog301[(log301[(a)] + (b)) % NN]) + +/* GF(256) log values using primitive polynomial 301 */ +static DmtxByte log301[] = + { 255, 0, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, + 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234, + 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162, + 244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91, + 6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, + 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, + 245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, + 57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, + 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, + 42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113, + 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66, + 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170, + 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, + 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131, + 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70, + 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150 }; + +/* GF(256) antilog values using primitive polynomial 301 */ +static DmtxByte antilog301[] = + { 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228, + 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184, + 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, + 141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, + 246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82, + 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, + 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, + 217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, + 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, + 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, + 214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, + 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206, + 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, + 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74, + 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151, + 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 0 }; + +/** + * Decode xyz. + * More detailed description. + * \param code + * \param sizeIdx + * \param fix + * \return Function success (DmtxPass|DmtxFail) + */ +#undef CHKPASS +#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; } +static DmtxPassFail +RsDecode(unsigned char *code, int sizeIdx, int fix) +{ + int i; + int blockStride, blockIdx; + int blockDataWords, blockErrorWords, blockTotalWords, blockMaxCorrectable; + int symbolDataWords, symbolErrorWords, symbolTotalWords; + DmtxBoolean error, repairable; + DmtxPassFail passFail; + unsigned char *word; + DmtxByte elpStorage[MAX_ERROR_WORD_COUNT]; + DmtxByte synStorage[MAX_ERROR_WORD_COUNT+1]; + DmtxByte recStorage[NN]; + DmtxByte locStorage[NN]; + DmtxByteList elp = dmtxByteListBuild(elpStorage, sizeof(elpStorage)); + DmtxByteList syn = dmtxByteListBuild(synStorage, sizeof(synStorage)); + DmtxByteList rec = dmtxByteListBuild(recStorage, sizeof(recStorage)); + DmtxByteList loc = dmtxByteListBuild(locStorage, sizeof(locStorage)); + + blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx); + blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx); + blockMaxCorrectable = dmtxGetSymbolAttribute(DmtxSymAttribBlockMaxCorrectable, sizeIdx); + symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx); + symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx); + symbolTotalWords = symbolDataWords + symbolErrorWords; + + /* For each interleaved block */ + for(blockIdx = 0; blockIdx < blockStride; blockIdx++) + { + /* Data word count depends on blockIdx due to special case at 144x144 */ + blockDataWords = dmtxGetBlockDataSize(sizeIdx, blockIdx); + blockTotalWords = blockErrorWords + blockDataWords; + + /* Populate received list (rec) with data and error codewords */ + dmtxByteListInit(&rec, 0, 0, &passFail); CHKPASS; + + /* Start with final error word and work backward */ + word = code + symbolTotalWords + blockIdx - blockStride; + for(i = 0; i < blockErrorWords; i++) + { + dmtxByteListPush(&rec, *word, &passFail); CHKPASS; + word -= blockStride; + } + + /* Start with final data word and work backward */ + word = code + blockIdx + (blockStride * (blockDataWords - 1)); + for(i = 0; i < blockDataWords; i++) + { + dmtxByteListPush(&rec, *word, &passFail); CHKPASS; + word -= blockStride; + } + + /* Compute syndromes (syn) */ + error = RsComputeSyndromes(&syn, &rec, blockErrorWords); + + /* Error(s) detected: Attempt repair */ + if(error) + { + /* Find error locator polynomial (elp) */ + repairable = RsFindErrorLocatorPoly(&elp, &syn, blockErrorWords, blockMaxCorrectable); + if(!repairable) + return DmtxFail; + + /* Find error positions (loc) */ + repairable = RsFindErrorLocations(&loc, &elp); + if(!repairable) + return DmtxFail; + + /* Find error values and repair */ + RsRepairErrors(&rec, &loc, &elp, &syn); + } + + /* + * Overwrite output with correct/corrected values + */ + + /* Start with first data word and work forward */ + word = code + blockIdx; + for(i = 0; i < blockDataWords; i++) + { + *word = dmtxByteListPop(&rec, &passFail); CHKPASS; + word += blockStride; + } + + /* Start with first error word and work forward */ + word = code + symbolDataWords + blockIdx; + for(i = 0; i < blockErrorWords; i++) + { + *word = dmtxByteListPop(&rec, &passFail); CHKPASS; + word += blockStride; + } + } + + return DmtxPass; +} + +/** + * Populate generator polynomial. + * Assume we have received bits grouped into mm-bit symbols in rec[i], + * i=0..(nn-1), and rec[i] is index form (ie as powers of alpha). We first + * compute the 2*tt syndromes by substituting alpha**i into rec(X) and + * evaluating, storing the syndromes in syn[i], i=1..2tt (leave syn[0] zero). + * \param syn + * \param rec + * \param blockErrorWords + * \return Are error(s) present? (DmtxPass|DmtxFail) + */ +/* XXX this CHKPASS isn't doing what we want ... really need a error reporting strategy */ +#undef CHKPASS +#define CHKPASS { if(passFail == DmtxFail) return DmtxTrue; } +static DmtxBoolean +RsComputeSyndromes(DmtxByteList *syn, const DmtxByteList *rec, int blockErrorWords) +{ + int i, j; + DmtxPassFail passFail; + DmtxBoolean error = DmtxFalse; + + /* Initialize all coefficients to 0 */ + dmtxByteListInit(syn, blockErrorWords + 1, 0, &passFail); CHKPASS; + + for(i = 1; i < syn->length; i++) + { + /* Calculate syndrome at i */ + for(j = 0; j < rec->length; j++) /* alternatively: j < blockTotalWords */ + syn->b[i] = GfAdd(syn->b[i], GfMultAntilog(rec->b[j], i*j)); + + /* Non-zero syndrome indicates presence of error(s) */ + if(syn->b[i] != 0) + error = DmtxTrue; + } + + return error; +} + +/** + * Find the error location polynomial using Berlekamp-Massey. + * More detailed description. + * \param elpOut + * \param syn + * \param errorWordCount + * \param maxCorrectable + * \return Is block repairable? (DmtxTrue|DmtxFalse) + */ +/* XXX this CHKPASS isn't doing what we want ... really need a error reporting strategy */ +#undef CHKPASS +#define CHKPASS { if(passFail == DmtxFail) { free(elpStorage_temp); return DmtxFalse; } } +static DmtxBoolean +RsFindErrorLocatorPoly(DmtxByteList *elpOut, const DmtxByteList *syn, int errorWordCount, int maxCorrectable) +{ + int i, iNext, j; + int m, mCmp, lambda; + DmtxByte disTmp, disStorage[MAX_ERROR_WORD_COUNT+1]; + DmtxByte *elpStorage_temp = malloc(sizeof(DmtxByte) * (MAX_ERROR_WORD_COUNT+2) * MAX_ERROR_WORD_COUNT); DmtxByte (*elpStorage)[MAX_ERROR_WORD_COUNT] = (DmtxByte (*)[MAX_ERROR_WORD_COUNT]) elpStorage_temp; // [MAX_ERROR_WORD_COUNT+2][MAX_ERROR_WORD_COUNT]; + DmtxByteList dis, elp[MAX_ERROR_WORD_COUNT+2]; + DmtxPassFail passFail; + + dis = dmtxByteListBuild(disStorage, sizeof(disStorage)); + dmtxByteListInit(&dis, 0, 0, &passFail); CHKPASS; + + for(i = 0; i < MAX_ERROR_WORD_COUNT + 2; i++) + { + elp[i] = dmtxByteListBuild(elpStorage[i], sizeof(elpStorage[i])); + dmtxByteListInit(&elp[i], 0, 0, &passFail); CHKPASS; + } + + /* iNext = 0 */ + dmtxByteListPush(&elp[0], 1, &passFail); CHKPASS; + dmtxByteListPush(&dis, 1, &passFail); CHKPASS; + + /* iNext = 1 */ + dmtxByteListPush(&elp[1], 1, &passFail); CHKPASS; + dmtxByteListPush(&dis, syn->b[1], &passFail); CHKPASS; + + for(iNext = 2, i = 1; /* explicit break */; i = iNext++) + { + if(dis.b[i] == 0) + { + /* Simple case: Copy directly from previous iteration */ + dmtxByteListCopy(&elp[iNext], &elp[i], &passFail); CHKPASS; + } + else + { + /* Find earlier iteration (m) that provides maximal (m - lambda) */ + for(m = 0, mCmp = 1; mCmp < i; mCmp++) + if(dis.b[mCmp] != 0 && (mCmp - elp[mCmp].length) >= (m - elp[m].length)) + m = mCmp; + + /* Calculate error location polynomial elp[i] (set 1st term) */ + for(lambda = elp[m].length - 1, j = 0; j <= lambda; j++) + elp[iNext].b[j+i-m] = antilog301[(NN - log301[dis.b[m]] + + log301[dis.b[i]] + log301[elp[m].b[j]]) % NN]; + + /* Calculate error location polynomial elp[i] (add 2nd term) */ + for(lambda = elp[i].length - 1, j = 0; j <= lambda; j++) + elp[iNext].b[j] = GfAdd(elp[iNext].b[j], elp[i].b[j]); + + elp[iNext].length = max(elp[i].length, elp[m].length + i - m); + } + + lambda = elp[iNext].length - 1; + if(i == errorWordCount || i >= lambda + maxCorrectable) + break; + + /* Calculate discrepancy dis.b[i] */ + for(disTmp = syn->b[iNext], j = 1; j <= lambda; j++) + disTmp = GfAdd(disTmp, GfMult(syn->b[iNext-j], elp[iNext].b[j])); + + assert(dis.length == iNext); + dmtxByteListPush(&dis, disTmp, &passFail); CHKPASS; + } + + dmtxByteListCopy(elpOut, &elp[iNext], &passFail); CHKPASS; + + free(elpStorage_temp); + + return (lambda <= maxCorrectable) ? DmtxTrue : DmtxFalse; +} + +/** + * Find roots of the error locator polynomial (Chien Search). + * If the degree of elp is <= tt, we substitute alpha**i, i=1..n into the elp + * to get the roots, hence the inverse roots, the error location numbers. + * If the number of errors located does not equal the degree of the elp, we + * have more than tt errors and cannot correct them. + * \param loc + * \param elp + * \return Is block repairable? (DmtxTrue|DmtxFalse) + */ +#undef CHKPASS +#define CHKPASS { if(passFail == DmtxFail) return DmtxFalse; } +static DmtxBoolean +RsFindErrorLocations(DmtxByteList *loc, const DmtxByteList *elp) +{ + int i, j; + int lambda = elp->length - 1; + DmtxPassFail passFail; + DmtxByte q, regStorage[MAX_ERROR_WORD_COUNT]; + DmtxByteList reg = dmtxByteListBuild(regStorage, sizeof(regStorage)); + + dmtxByteListCopy(®, elp, &passFail); CHKPASS; + dmtxByteListInit(loc, 0, 0, &passFail); CHKPASS; + + for(i = 1; i <= NN; i++) + { + for(q = 1, j = 1; j <= lambda; j++) + { + reg.b[j] = GfMultAntilog(reg.b[j], j); + q = GfAdd(q, reg.b[j]); + } + + if(q == 0) + { + dmtxByteListPush(loc, NN - i, &passFail); CHKPASS; + } + } + + return (loc->length == lambda) ? DmtxTrue : DmtxFalse; +} + +/** + * Find the error values and repair. + * Solve for the error value at the error location and correct the error. The + * procedure is that found in Lin and Costello. + * For the cases where the number of errors is known to be too large to + * correct, the information symbols as received are output (the advantage of + * systematic encoding is that hopefully some of the information symbols will + * be okay and that if we are in luck, the errors are in the parity part of + * the transmitted codeword). + * \param rec + * \param loc + * \param elp + * \param syn + */ +#undef CHKPASS +#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; } +static DmtxPassFail +RsRepairErrors(DmtxByteList *rec, const DmtxByteList *loc, const DmtxByteList *elp, const DmtxByteList *syn) +{ + int i, j, q; + int lambda = elp->length - 1; + DmtxPassFail passFail; + DmtxByte zVal, root, err; + DmtxByte zStorage[MAX_ERROR_WORD_COUNT+1]; + DmtxByteList z = dmtxByteListBuild(zStorage, sizeof(zStorage)); + + /* Form polynomial z(x) */ + dmtxByteListPush(&z, 1, &passFail); CHKPASS; + for(i = 1; i <= lambda; i++) + { + for(zVal = GfAdd(syn->b[i], elp->b[i]), j = 1; j < i; j++) + zVal= GfAdd(zVal, GfMult(elp->b[i-j], syn->b[j])); + dmtxByteListPush(&z, zVal, &passFail); CHKPASS; + } + + for(i = 0; i < lambda; i++) + { + /* Calculate numerator of error term */ + root = NN - loc->b[i]; + + for(err = 1, j = 1; j <= lambda; j++) + err = GfAdd(err, GfMultAntilog(z.b[j], j * root)); + + if(err == 0) + continue; + + /* Calculate denominator of error term */ + for(q = 0, j = 0; j < lambda; j++) + { + if(j != i) + q += log301[1 ^ antilog301[(loc->b[j] + root) % NN]]; + } + q %= NN; + + err = GfMultAntilog(err, NN - q); + rec->b[loc->b[i]] = GfAdd(rec->b[loc->b[i]], err); + } + + return DmtxPass; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxscangrid.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxscangrid.c + * \brief Scan grid tracking + */ + +/** + * \brief Initialize scan grid pattern + * \param dec + * \return Initialized grid + */ +static DmtxScanGrid +InitScanGrid(DmtxDecode *dec) +{ + int scale, smallestFeature; + int xExtent, yExtent, maxExtent; + int extent; + DmtxScanGrid grid; + + memset(&grid, 0x00, sizeof(DmtxScanGrid)); + + scale = dmtxDecodeGetProp(dec, DmtxPropScale); + smallestFeature = dmtxDecodeGetProp(dec, DmtxPropScanGap) / scale; + + grid.xMin = dmtxDecodeGetProp(dec, DmtxPropXmin); + grid.xMax = dmtxDecodeGetProp(dec, DmtxPropXmax); + grid.yMin = dmtxDecodeGetProp(dec, DmtxPropYmin); + grid.yMax = dmtxDecodeGetProp(dec, DmtxPropYmax); + + /* Values that get set once */ + xExtent = grid.xMax - grid.xMin; + yExtent = grid.yMax - grid.yMin; + maxExtent = (xExtent > yExtent) ? xExtent : yExtent; + + assert(maxExtent > 1); + + for(extent = 1; extent < maxExtent; extent = ((extent + 1) * 2) - 1) + if(extent <= smallestFeature) + grid.minExtent = extent; + + grid.maxExtent = extent; + + grid.xOffset = (grid.xMin + grid.xMax - grid.maxExtent) / 2; + grid.yOffset = (grid.yMin + grid.yMax - grid.maxExtent) / 2; + + /* Values that get reset for every level */ + grid.total = 1; + grid.extent = grid.maxExtent; + + SetDerivedFields(&grid); + + return grid; +} + +/** + * \brief Return the next good location (which may be the current location), + * and advance grid progress one position beyond that. If no good + * locations remain then return DmtxRangeEnd. + * \param grid + * \return void + */ +static int +PopGridLocation(DmtxScanGrid *grid, DmtxPixelLoc *locPtr) +{ + int locStatus; + + do { + locStatus = GetGridCoordinates(grid, locPtr); + + /* Always leave grid pointing at next available location */ + grid->pixelCount++; + + } while(locStatus == DmtxRangeBad); + + return locStatus; +} + +/** + * \brief Extract current grid position in pixel coordinates and return + * whether location is good, bad, or end + * \param grid + * \return Pixel location + */ +static int +GetGridCoordinates(DmtxScanGrid *grid, DmtxPixelLoc *locPtr) +{ + int count, half, quarter; + DmtxPixelLoc loc; + + /* Initially pixelCount may fall beyond acceptable limits. Update grid + * state before testing coordinates */ + + /* Jump to next cross pattern horizontally if current column is done */ + if(grid->pixelCount >= grid->pixelTotal) { + grid->pixelCount = 0; + grid->xCenter += grid->jumpSize; + } + + /* Jump to next cross pattern vertically if current row is done */ + if(grid->xCenter > grid->maxExtent) { + grid->xCenter = grid->startPos; + grid->yCenter += grid->jumpSize; + } + + /* Increment level when vertical step goes too far */ + if(grid->yCenter > grid->maxExtent) { + grid->total *= 4; + grid->extent /= 2; + SetDerivedFields(grid); + } + + if(grid->extent == 0 || grid->extent < grid->minExtent) { + locPtr->X = locPtr->Y = -1; + return DmtxRangeEnd; + } + + count = grid->pixelCount; + + assert(count < grid->pixelTotal); + + if(count == grid->pixelTotal - 1) { + /* center pixel */ + loc.X = grid->xCenter; + loc.Y = grid->yCenter; + } + else { + half = grid->pixelTotal / 2; + quarter = half / 2; + + /* horizontal portion */ + if(count < half) { + loc.X = grid->xCenter + ((count < quarter) ? (count - quarter) : (half - count)); + loc.Y = grid->yCenter; + } + /* vertical portion */ + else { + count -= half; + loc.X = grid->xCenter; + loc.Y = grid->yCenter + ((count < quarter) ? (count - quarter) : (half - count)); + } + } + + loc.X += grid->xOffset; + loc.Y += grid->yOffset; + + *locPtr = loc; + + if(loc.X < grid->xMin || loc.X > grid->xMax || + loc.Y < grid->yMin || loc.Y > grid->yMax) + return DmtxRangeBad; + + return DmtxRangeGood; +} + +/** + * \brief Update derived fields based on current state + * \param grid + * \return void + */ +static void +SetDerivedFields(DmtxScanGrid *grid) +{ + grid->jumpSize = grid->extent + 1; + grid->pixelTotal = 2 * grid->extent - 1; + grid->startPos = grid->extent / 2; + grid->pixelCount = 0; + grid->xCenter = grid->yCenter = grid->startPos; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtximage.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtximage.c + * \brief Image handling + */ + +/** + * libdmtx stores image data as a large one-dimensional array of packed pixels, + * reading from the array when scanning barcodes and writing to it when creating + * a barcode. Beyond this interaction the calling program is responsible for + * populating and dispatching pixels between the image array and the outside + * world, whether that means loading an image from a file, acquiring camera + * input, displaying output to a screen, saving to disk, etc... + * + * By default, libdmtx treats the first pixel of an image array as the top-left + * corner of the physical image, with the final pixel landing at the bottom- + * right. However, if mapping a pixel buffer this way produces an inverted + * image the calling program can specify DmtxFlipY at image creation time to + * remove the inversion. This has a negligible effect on performance since it + * only modifies the pixel mapping math, and does not alter any pixel data. + * + * Regardless of how an image is stored internally, all libdmtx functions + * consider coordinate (0,0) to mathematically represent the bottom-left pixel + * location of an image using a right-handed coordinate system. + * + * (0,HEIGHT-1) (WIDTH-1,HEIGHT-1) + * + * array pos = 0,1,2,3,...-----------+ + * | | + * | | + * | libdmtx | + * | image | + * | coordinates | + * | | + * | | + * +---------...,N-2,N-1,N = array pos + * + * (0,0) (WIDTH-1,0) + * + * Notes: + * - OpenGL pixel arrays obtained with glReadPixels() are stored + * bottom-to-top; use DmtxFlipY + * - Many popular image formats (e.g., PNG, GIF) store rows + * top-to-bottom; use DmtxFlipNone + */ + +/** + * \brief XXX + * \param XXX + * \return XXX + */ +extern DmtxImage * +dmtxImageCreate(unsigned char *pxl, int width, int height, int pack) +{ + DmtxPassFail err; + DmtxImage *img; + + if(pxl == NULL || width < 1 || height < 1) + return NULL; + + img = (DmtxImage *)calloc(1, sizeof(DmtxImage)); + if(img == NULL) + return NULL; + + img->pxl = pxl; + img->width = width; + img->height = height; + img->pixelPacking = pack; + img->bitsPerPixel = GetBitsPerPixel(pack); + img->bytesPerPixel = img->bitsPerPixel/8; + img->rowPadBytes = 0; + img->rowSizeBytes = img->width * img->bytesPerPixel + img->rowPadBytes; + img->imageFlip = DmtxFlipNone; + + /* Leave channelStart[] and bitsPerChannel[] with zeros from calloc */ + img->channelCount = 0; + + switch(pack) { + case DmtxPackCustom: + break; + case DmtxPack1bppK: + err = dmtxImageSetChannel(img, 0, 1); + return NULL; /* unsupported packing order */ +/* break; */ + case DmtxPack8bppK: + err = dmtxImageSetChannel(img, 0, 8); + break; + case DmtxPack16bppRGB: + case DmtxPack16bppBGR: + case DmtxPack16bppYCbCr: + err = dmtxImageSetChannel(img, 0, 5); + err = dmtxImageSetChannel(img, 5, 5); + err = dmtxImageSetChannel(img, 10, 5); + break; + case DmtxPack24bppRGB: + case DmtxPack24bppBGR: + case DmtxPack24bppYCbCr: + case DmtxPack32bppRGBX: + case DmtxPack32bppBGRX: + err = dmtxImageSetChannel(img, 0, 8); + err = dmtxImageSetChannel(img, 8, 8); + err = dmtxImageSetChannel(img, 16, 8); + break; + case DmtxPack16bppRGBX: + case DmtxPack16bppBGRX: + err = dmtxImageSetChannel(img, 0, 5); + err = dmtxImageSetChannel(img, 5, 5); + err = dmtxImageSetChannel(img, 10, 5); + break; + case DmtxPack16bppXRGB: + case DmtxPack16bppXBGR: + err = dmtxImageSetChannel(img, 1, 5); + err = dmtxImageSetChannel(img, 6, 5); + err = dmtxImageSetChannel(img, 11, 5); + break; + case DmtxPack32bppXRGB: + case DmtxPack32bppXBGR: + err = dmtxImageSetChannel(img, 8, 8); + err = dmtxImageSetChannel(img, 16, 8); + err = dmtxImageSetChannel(img, 24, 8); + break; + case DmtxPack32bppCMYK: + err = dmtxImageSetChannel(img, 0, 8); + err = dmtxImageSetChannel(img, 8, 8); + err = dmtxImageSetChannel(img, 16, 8); + err = dmtxImageSetChannel(img, 24, 8); + break; + default: + return NULL; + } + + return img; +} + +/** + * \brief Free libdmtx image memory + * \param img pointer to img location + * \return DmtxFail | DmtxPass + */ +extern DmtxPassFail +dmtxImageDestroy(DmtxImage **img) +{ + if(img == NULL || *img == NULL) + return DmtxFail; + + free(*img); + + *img = NULL; + + return DmtxPass; +} + +/** + * + * + */ +extern DmtxPassFail +dmtxImageSetChannel(DmtxImage *img, int channelStart, int bitsPerChannel) +{ + if(img->channelCount >= 4) /* IMAGE_MAX_CHANNEL */ + return DmtxFail; + + /* New channel extends beyond pixel data */ +/* if(channelStart + bitsPerChannel > img->bitsPerPixel) + return DmtxFail; */ + + img->bitsPerChannel[img->channelCount] = bitsPerChannel; + img->channelStart[img->channelCount] = channelStart; + (img->channelCount)++; + + return DmtxPass; +} + +/** + * \brief Set image property + * \param img pointer to image + * \return image width + */ +extern DmtxPassFail +dmtxImageSetProp(DmtxImage *img, int prop, int value) +{ + if(img == NULL) + return DmtxFail; + + switch(prop) { + case DmtxPropRowPadBytes: + img->rowPadBytes = value; + img->rowSizeBytes = img->width * (img->bitsPerPixel/8) + img->rowPadBytes; + break; + case DmtxPropImageFlip: + img->imageFlip = value; + break; + default: + break; + } + + return DmtxPass; +} + +/** + * \brief Get image width + * \param img pointer to image + * \return image width + */ +extern int +dmtxImageGetProp(DmtxImage *img, int prop) +{ + if(img == NULL) + return DmtxUndefined; + + switch(prop) { + case DmtxPropWidth: + return img->width; + case DmtxPropHeight: + return img->height; + case DmtxPropPixelPacking: + return img->pixelPacking; + case DmtxPropBitsPerPixel: + return img->bitsPerPixel; + case DmtxPropBytesPerPixel: + return img->bytesPerPixel; + case DmtxPropRowPadBytes: + return img->rowPadBytes; + case DmtxPropRowSizeBytes: + return img->rowSizeBytes; + case DmtxPropImageFlip: + return img->imageFlip; + case DmtxPropChannelCount: + return img->channelCount; + default: + break; + } + + return DmtxUndefined; +} + +/** + * \brief Returns pixel offset for image + * \param img + * \param x coordinate + * \param y coordinate + * \return pixel byte offset + */ +extern int +dmtxImageGetByteOffset(DmtxImage *img, int x, int y) +{ + assert(img != NULL); + assert(!(img->imageFlip & DmtxFlipX)); /* DmtxFlipX is not an option */ + + if(dmtxImageContainsInt(img, 0, x, y) == DmtxFalse) + return DmtxUndefined; + + if(img->imageFlip & DmtxFlipY) + return (y * img->rowSizeBytes + x * img->bytesPerPixel); + + return ((img->height - y - 1) * img->rowSizeBytes + x * img->bytesPerPixel); +} + +/** + * + * + */ +extern DmtxPassFail +dmtxImageGetPixelValue(DmtxImage *img, int x, int y, int channel, int *value) +{ + int offset; +/* unsigned char *pixelPtr; + int pixelValue; + int mask; + int bitShift; */ + + assert(img != NULL); + assert(channel < img->channelCount); + + offset = dmtxImageGetByteOffset(img, x, y); + if(offset == DmtxUndefined) + return DmtxFail; + + switch(img->bitsPerChannel[channel]) { + case 1: +/* assert(img->bitsPerPixel == 1); + mask = 0x01 << (7 - offset%8); + *value = (img->pxl[offset/8] & mask) ? 255 : 0; */ + break; + case 5: + /* XXX might be expensive if we want to scale perfect 0-255 range */ +/* assert(img->bitsPerPixel == 16); + pixelPtr = img->pxl + (offset * (img->bitsPerPixel/8)); + pixelValue = (*pixelPtr << 8) | (*(pixelPtr+1)); + bitShift = img->bitsPerPixel - 5 - img->channelStart[channel]; + mask = 0x1f << bitShift; + *value = (((pixelValue & mask) >> bitShift) << 3); */ + break; + case 8: + assert(img->channelStart[channel] % 8 == 0); + assert(img->bitsPerPixel % 8 == 0); + *value = img->pxl[offset + channel]; + break; + } + + return DmtxPass; +} + +/** + * + * + */ +extern DmtxPassFail +dmtxImageSetPixelValue(DmtxImage *img, int x, int y, int channel, int value) +{ + int offset; +/* unsigned char *pixelPtr; */ +/* int pixelValue; */ +/* int mask; */ +/* int bitShift; */ + + assert(img != NULL); + assert(channel < img->channelCount); + + offset = dmtxImageGetByteOffset(img, x, y); + if(offset == DmtxUndefined) + return DmtxFail; + + switch(img->bitsPerChannel[channel]) { + case 1: +/* assert(img->bitsPerPixel == 1); + mask = 0x01 << (7 - offset%8); + *value = (img->pxl[offset/8] & mask) ? 255 : 0; */ + break; + case 5: + /* XXX might be expensive if we want to scale perfect 0-255 range */ +/* assert(img->bitsPerPixel == 16); + pixelPtr = img->pxl + (offset * (img->bitsPerPixel/8)); + pixelValue = (*pixelPtr << 8) | (*(pixelPtr+1)); + bitShift = img->bitsPerPixel - 5 - img->channelStart[channel]; + mask = 0x1f << bitShift; + *value = (((pixelValue & mask) >> bitShift) << 3); */ + break; + case 8: + assert(img->channelStart[channel] % 8 == 0); + assert(img->bitsPerPixel % 8 == 0); + img->pxl[offset + channel] = value; + break; + } + + return DmtxPass; +} + +/** + * \brief Test whether image contains a coordinate expressed in integers + * \param img + * \param margin width + * \param x coordinate + * \param y coordinate + * \return DmtxTrue | DmtxFalse + */ +extern DmtxBoolean +dmtxImageContainsInt(DmtxImage *img, int margin, int x, int y) +{ + assert(img != NULL); + + if(x - margin >= 0 && x + margin < img->width && + y - margin >= 0 && y + margin < img->height) + return DmtxTrue; + + return DmtxFalse; +} + +/** + * \brief Test whether image contains a coordinate expressed in floating points + * \param img + * \param x coordinate + * \param y coordinate + * \return DmtxTrue | DmtxFalse + */ +extern DmtxBoolean +dmtxImageContainsFloat(DmtxImage *img, double x, double y) +{ + assert(img != NULL); + + if(x >= 0.0 && x < (double)img->width && y >= 0.0 && y < (double)img->height) + return DmtxTrue; + + return DmtxFalse; +} + +/** + * + * + */ +static int +GetBitsPerPixel(int pack) +{ + switch(pack) { + case DmtxPack1bppK: + return 1; + case DmtxPack8bppK: + return 8; + case DmtxPack16bppRGB: + case DmtxPack16bppRGBX: + case DmtxPack16bppXRGB: + case DmtxPack16bppBGR: + case DmtxPack16bppBGRX: + case DmtxPack16bppXBGR: + case DmtxPack16bppYCbCr: + return 16; + case DmtxPack24bppRGB: + case DmtxPack24bppBGR: + case DmtxPack24bppYCbCr: + return 24; + case DmtxPack32bppRGBX: + case DmtxPack32bppXRGB: + case DmtxPack32bppBGRX: + case DmtxPack32bppXBGR: + case DmtxPack32bppCMYK: + return 32; + default: + break; + } + + return DmtxUndefined; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxbytelist.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2010 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file file.c + */ + +/** + * + * + */ +extern DmtxByteList +dmtxByteListBuild(DmtxByte *storage, int capacity) +{ + DmtxByteList list; + + list.b = storage; + list.capacity = capacity; + list.length = 0; + + return list; +} + +/** + * + * + */ +extern void +dmtxByteListInit(DmtxByteList *list, int length, DmtxByte value, DmtxPassFail *passFail) +{ + if(length > list->capacity) + { + *passFail = DmtxFail; + } + else + { + list->length = length; + memset(list->b, value, sizeof(DmtxByte) * list->capacity); + *passFail = DmtxPass; + } +} + +/** + * + * + */ +extern void +dmtxByteListClear(DmtxByteList *list) +{ + memset(list->b, 0x00, sizeof(DmtxByte) * list->capacity); + list->length = 0; +} + +/** + * + * + */ +extern DmtxBoolean +dmtxByteListHasCapacity(DmtxByteList *list) +{ + return (list->length < list->capacity) ? DmtxTrue : DmtxFalse; +} + +/** + * + * + */ +extern void +dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail) +{ + int length; + + if(dst->capacity < src->length) + { + *passFail = DmtxFail; /* dst must be large enough to hold src data */ + } + else + { + /* Copy as many bytes as dst can hold or src can provide (smaller of two) */ + length = (dst->capacity < src->capacity) ? dst->capacity : src->capacity; + + dst->length = src->length; + memcpy(dst->b, src->b, sizeof(unsigned char) * length); + *passFail = DmtxPass; + } +} + +/** + * + * + */ +extern void +dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail) +{ + if(list->length >= list->capacity) + { + *passFail = DmtxFail; + } + else + { + list->b[list->length++] = value; + *passFail = DmtxPass; + } +} + +/** + * + * + */ +extern DmtxByte +dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail) +{ + *passFail = (list->length > 0) ? DmtxPass : DmtxFail; + + return list->b[--(list->length)]; +} + +/** + * + * + */ +extern void +dmtxByteListPrint(DmtxByteList *list, char *prefix) +{ + int i; + + if(prefix != NULL) + fprintf(stdout, "%s", prefix); + + for(i = 0; i < list->length; i++) + fprintf(stdout, " %d", list->b[i]); + + fputc('\n', stdout); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxvector2.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +* libdmtx - Data Matrix Encoding/Decoding Library +* Copyright 2008, 2009 Mike Laughton. All rights reserved. +* +* See LICENSE file in the main project directory for full +* terms of use and distribution. +* +* Contact: Mike Laughton +* +* \file dmtxvector2.c +* \brief 2D Vector math +*/ + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2AddTo(DmtxVector2 *v1, const DmtxVector2 *v2) +{ + v1->X += v2->X; + v1->Y += v2->Y; + + return v1; +} + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2Add(DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2) +{ + *vOut = *v1; + + return dmtxVector2AddTo(vOut, v2); +} + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2SubFrom(DmtxVector2 *v1, const DmtxVector2 *v2) +{ + v1->X -= v2->X; + v1->Y -= v2->Y; + + return v1; +} + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2Sub(DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2) +{ + *vOut = *v1; + + return dmtxVector2SubFrom(vOut, v2); +} + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2ScaleBy(DmtxVector2 *v, double s) +{ + v->X *= s; + v->Y *= s; + + return v; +} + +/** +* +* +*/ +extern DmtxVector2 * +dmtxVector2Scale(DmtxVector2 *vOut, const DmtxVector2 *v, double s) +{ + *vOut = *v; + + return dmtxVector2ScaleBy(vOut, s); +} + +/** +* +* +*/ +extern double +dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2) +{ + return (v1->X * v2->Y) - (v1->Y * v2->X); +} + +/** +* +* +*/ +extern double +dmtxVector2Norm(DmtxVector2 *v) +{ + double mag; + + mag = dmtxVector2Mag(v); + + if(mag <= DmtxAlmostZero) + return -1.0; /* XXX this doesn't look clean */ + + dmtxVector2ScaleBy(v, 1/mag); + + return mag; +} + +/** +* +* +*/ +extern double +dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2) +{ + return (v1->X * v2->X) + (v1->Y * v2->Y); +} + +/** +* +* +*/ +extern double +dmtxVector2Mag(const DmtxVector2 *v) +{ + return sqrt(v->X * v->X + v->Y * v->Y); +} + +/** +* +* +*/ +extern double +dmtxDistanceFromRay2(const DmtxRay2 *r, const DmtxVector2 *q) +{ + DmtxVector2 vSubTmp; + + /* Assumes that v is a unit vector */ + assert(fabs(1.0 - dmtxVector2Mag(&(r->v))) <= DmtxAlmostZero); + + return dmtxVector2Cross(&(r->v), dmtxVector2Sub(&vSubTmp, q, &(r->p))); +} + +/** +* +* +*/ +extern double +dmtxDistanceAlongRay2(const DmtxRay2 *r, const DmtxVector2 *q) +{ + DmtxVector2 vSubTmp; + +#ifdef DEBUG + /* Assumes that v is a unit vector */ + if(fabs(1.0 - dmtxVector2Mag(&(r->v))) > DmtxAlmostZero) { + ; /* XXX big error goes here */ + } +#endif + + return dmtxVector2Dot(dmtxVector2Sub(&vSubTmp, q, &(r->p)), &(r->v)); +} + +/** +* +* +*/ +extern DmtxPassFail +dmtxRay2Intersect(DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1) +{ + double numer, denom; + DmtxVector2 w; + + denom = dmtxVector2Cross(&(p1->v), &(p0->v)); + if(fabs(denom) <= DmtxAlmostZero) + return DmtxFail; + + dmtxVector2Sub(&w, &(p1->p), &(p0->p)); + numer = dmtxVector2Cross(&(p1->v), &w); + + return dmtxPointAlongRay2(point, p0, numer/denom); +} + +/** +* +* +*/ +extern DmtxPassFail +dmtxPointAlongRay2(DmtxVector2 *point, const DmtxRay2 *r, double t) +{ + DmtxVector2 vTmp; + + /* Ray should always have unit length of 1 */ + assert(fabs(1.0 - dmtxVector2Mag(&(r->v))) <= DmtxAlmostZero); + + dmtxVector2Scale(&vTmp, &(r->v), t); + dmtxVector2Add(point, &(r->p), &vTmp); + + return DmtxPass; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "dmtxmatrix3.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * libdmtx - Data Matrix Encoding/Decoding Library + * Copyright 2008, 2009 Mike Laughton. All rights reserved. + * + * See LICENSE file in the main project directory for full + * terms of use and distribution. + * + * Contact: Mike Laughton + * + * \file dmtxmatrix3.c + * \brief 2D Matrix (3x3) math + */ + +/** + * \brief Copy matrix contents + * \param m0 Copy target + * \param m1 Copy source + * \return void + */ +extern void +dmtxMatrix3Copy(DmtxMatrix3 m0, DmtxMatrix3 m1) +{ + memcpy(m0, m1, sizeof(DmtxMatrix3)); +} + +/** + * \brief Generate identity transformation matrix + * \param m Generated matrix + * \return void + * + * | 1 0 0 | + * m = | 0 1 0 | + * | 0 0 1 | + * + * Transform "m" + * (doesn't change anything) + * |\ + * (0,1) x----o +--+ \ (0,1) x----o + * | | | \ | | + * | | | / | | + * +----* +--+ / +----* + * (0,0) (1,0) |/ (0,0) (1,0) + * + */ +extern void +dmtxMatrix3Identity(DmtxMatrix3 m) +{ + static DmtxMatrix3 tmp = { {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1} }; + dmtxMatrix3Copy(m, tmp); +} + +/** + * \brief Generate translate transformation matrix + * \param m Generated matrix + * \param tx + * \param ty + * \return void + * + * | 1 0 0 | + * m = | 0 1 0 | + * | tx ty 1 | + * + * Transform "m" + * _____ (tx,1+ty) x----o (1+tx,1+ty) + * \ | | | + * (0,1) x----o / | (0,1) +-|--+ | + * | | / /\| | +----* (1+tx,ty) + * | | \ / | | + * +----* ` +----+ + * (0,0) (1,0) (0,0) (1,0) + * + */ +void dmtxMatrix3Translate(DmtxMatrix3 m, double tx, double ty) +{ + dmtxMatrix3Identity(m); + m[2][0] = tx; + m[2][1] = ty; +} + +/** + * \brief Generate rotate transformation + * \param m Generated matrix + * \param angle + * \return void + * + * | cos(a) sin(a) 0 | + * m = | -sin(a) cos(a) 0 | + * | 0 0 1 | + * o + * Transform "m" / ` + * ___ / ` + * (0,1) x----o |/ \ x * (cos(a),sin(a)) + * | | '-- | ` / + * | | ___/ ` / a + * +----* `+ - - - - - - + * (0,0) (1,0) (0,0) + * + */ +extern void +dmtxMatrix3Rotate(DmtxMatrix3 m, double angle) +{ + double sinAngle, cosAngle; + + sinAngle = sin(angle); + cosAngle = cos(angle); + + dmtxMatrix3Identity(m); + m[0][0] = cosAngle; + m[0][1] = sinAngle; + m[1][0] = -sinAngle; + m[1][1] = cosAngle; +} + +/** + * \brief Generate scale transformation matrix + * \param m Generated matrix + * \param sx + * \param sy + * \return void + * + * | sx 0 0 | + * m = | 0 sy 0 | + * | 0 0 1 | + * + * Transform "m" + * _____ (0,sy) x-------o (sx,sy) + * \ | | | + * (0,1) x----o / | (0,1) +----+ | + * | | / /\| | | | + * | | \ / | | | + * +----* ` +----+--* + * (0,0) (1,0) (0,0) (sx,0) + * + */ +extern void +dmtxMatrix3Scale(DmtxMatrix3 m, double sx, double sy) +{ + dmtxMatrix3Identity(m); + m[0][0] = sx; + m[1][1] = sy; +} + +/** + * \brief Generate shear transformation matrix + * \param m Generated matrix + * \param shx + * \param shy + * \return void + * + * | 0 shy 0 | + * m = | shx 0 0 | + * | 0 0 1 | + */ +extern void +dmtxMatrix3Shear(DmtxMatrix3 m, double shx, double shy) +{ + dmtxMatrix3Identity(m); + m[1][0] = shx; + m[0][1] = shy; +} + +/** + * \brief Generate top line skew transformation + * \param m + * \param b0 + * \param b1 + * \param sz + * \return void + * + * | b1/b0 0 (b1-b0)/(sz*b0) | + * m = | 0 sz/b0 0 | + * | 0 0 1 | + * + * (sz,b1) o + * /| Transform "m" + * / | + * / | +--+ + * / | | | + * (0,b0) x | | | + * | | +-+ +-+ + * (0,sz) +----+ \ / (0,sz) x----o + * | | \ / | | + * | | \/ | | + * +----+ +----+ + * (0,0) (sz,0) (0,0) (sz,0) + * + */ +extern void +dmtxMatrix3LineSkewTop(DmtxMatrix3 m, double b0, double b1, double sz) +{ + assert(b0 >= DmtxAlmostZero); + + dmtxMatrix3Identity(m); + m[0][0] = b1/b0; + m[1][1] = sz/b0; + m[0][2] = (b1 - b0)/(sz*b0); +} + +/** + * \brief Generate top line skew transformation (inverse) + * \param m + * \param b0 + * \param b1 + * \param sz + * \return void + */ +extern void +dmtxMatrix3LineSkewTopInv(DmtxMatrix3 m, double b0, double b1, double sz) +{ + assert(b1 >= DmtxAlmostZero); + + dmtxMatrix3Identity(m); + m[0][0] = b0/b1; + m[1][1] = b0/sz; + m[0][2] = (b0 - b1)/(sz*b1); +} + +/** + * \brief Generate side line skew transformation + * \param m + * \param b0 + * \param b1 + * \param sz + * \return void + */ +extern void +dmtxMatrix3LineSkewSide(DmtxMatrix3 m, double b0, double b1, double sz) +{ + assert(b0 >= DmtxAlmostZero); + + dmtxMatrix3Identity(m); + m[0][0] = sz/b0; + m[1][1] = b1/b0; + m[1][2] = (b1 - b0)/(sz*b0); +} + +/** + * \brief Generate side line skew transformation (inverse) + * \param m + * \param b0 + * \param b1 + * \param sz + * \return void + */ +extern void +dmtxMatrix3LineSkewSideInv(DmtxMatrix3 m, double b0, double b1, double sz) +{ + assert(b1 >= DmtxAlmostZero); + + dmtxMatrix3Identity(m); + m[0][0] = b0/sz; + m[1][1] = b0/b1; + m[1][2] = (b0 - b1)/(sz*b1); +} + +/** + * \brief Multiply two matrices to create a third + * \param mOut + * \param m0 + * \param m1 + * \return void + */ +extern void +dmtxMatrix3Multiply(DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1) +{ + int i, j, k; + double val; + + for(i = 0; i < 3; i++) { + for(j = 0; j < 3; j++) { + val = 0.0; + for(k = 0; k < 3; k++) { + val += m0[i][k] * m1[k][j]; + } + mOut[i][j] = val; + } + } +} + +/** + * \brief Multiply two matrices in place + * \param m0 + * \param m1 + * \return void + */ +extern void +dmtxMatrix3MultiplyBy(DmtxMatrix3 m0, DmtxMatrix3 m1) +{ + DmtxMatrix3 mTmp; + + dmtxMatrix3Copy(mTmp, m0); + dmtxMatrix3Multiply(m0, mTmp, m1); +} + +/** + * \brief Multiply vector and matrix + * \param vOut Vector (output) + * \param vIn Vector (input) + * \param m Matrix to be multiplied + * \return DmtxPass | DmtxFail + */ +extern int +dmtxMatrix3VMultiply(DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m) +{ + double w; + + w = vIn->X*m[0][2] + vIn->Y*m[1][2] + m[2][2]; + if(fabs(w) <= DmtxAlmostZero) { + vOut->X = FLT_MAX; + vOut->Y = FLT_MAX; + return DmtxFail; + } + + vOut->X = (vIn->X*m[0][0] + vIn->Y*m[1][0] + m[2][0])/w; + vOut->Y = (vIn->X*m[0][1] + vIn->Y*m[1][1] + m[2][1])/w; + + return DmtxPass; +} + +/** + * \brief Multiply vector and matrix in place + * \param v Vector (input and output) + * \param m Matrix to be multiplied + * \return DmtxPass | DmtxFail + */ +extern int +dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m) +{ + int success; + DmtxVector2 vOut; + + success = dmtxMatrix3VMultiply(&vOut, v, m); + *v = vOut; + + return success; +} + +/** + * \brief Print matrix contents to STDOUT + * \param m + * \return void + */ +extern void +dmtxMatrix3Print(DmtxMatrix3 m) +{ + fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[0][0], m[0][1], m[0][2]); + fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[1][0], m[1][1], m[1][2]); + fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[2][0], m[2][1], m[2][2]); + fprintf(stdout, "\n"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void imlib_find_datamatrices(list_t *out, image_t *ptr, rectangle_t *roi, int effort) +{ + uint8_t *grayscale_image = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->data : fb_alloc(roi->w * roi->h); + umm_init_x(fb_avail()); + + DmtxImage *image = dmtxImageCreate(grayscale_image, + (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->w : roi->w, + (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->h : roi->h, + DmtxPack8bppK); + DmtxDecode *decode = dmtxDecodeCreate(image, 1); + dmtxDecodeSetProp(decode, DmtxPropXmin, (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->x : 0); + dmtxDecodeSetProp(decode, DmtxPropYmin, (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->y : 0); + dmtxDecodeSetProp(decode, DmtxPropXmax, ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->x : 0) + (roi->w - 1)); + dmtxDecodeSetProp(decode, DmtxPropYmax, ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->y : 0) + (roi->h - 1)); + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + list_init(out, sizeof(find_datamatrices_list_lnk_data_t)); + + int max_iterations = effort; + int current_iterations = 0; + for (DmtxRegion *region = dmtxRegionFindNext(decode, max_iterations, ¤t_iterations); region; region = dmtxRegionFindNext(decode, max_iterations, ¤t_iterations)) { + DmtxMessage *message = dmtxDecodeMatrixRegion(decode, region, DmtxUndefined); + + if (message) { + find_datamatrices_list_lnk_data_t lnk_data; + + DmtxVector2 p[4]; + + p[0].X = p[0].Y = p[1].Y = p[3].X = 0.0; + p[1].X = p[3].Y = p[2].X = p[2].Y = 1.0; + + dmtxMatrix3VMultiplyBy(&p[0], region->fit2raw); + dmtxMatrix3VMultiplyBy(&p[1], region->fit2raw); + dmtxMatrix3VMultiplyBy(&p[2], region->fit2raw); + dmtxMatrix3VMultiplyBy(&p[3], region->fit2raw); + + int height = dmtxDecodeGetProp(decode, DmtxPropHeight); + + rectangle_init(&(lnk_data.rect), + fast_roundf(p[0].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x), + height - 1 - fast_roundf(p[0].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y), + 0, + 0); + + for (size_t k = 1, l = (sizeof(p) / sizeof(p[0])); k < l; k++) { + rectangle_t temp; + rectangle_init(&temp, + fast_roundf(p[k].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x), + height - 1 - fast_roundf(p[k].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y), + 0, + 0); + rectangle_united(&(lnk_data.rect), &temp); + } + + // Add corners... + lnk_data.corners[0].x = fast_roundf(p[3].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x); // top-left + lnk_data.corners[0].y = height - 1 - fast_roundf(p[3].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y); // top-left + lnk_data.corners[1].x = fast_roundf(p[2].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x); // top-right + lnk_data.corners[1].y = height - 1 - fast_roundf(p[2].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y); // top-right + lnk_data.corners[2].x = fast_roundf(p[1].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x); // bottom-right + lnk_data.corners[2].y = height - 1 - fast_roundf(p[1].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y); // bottom-right + lnk_data.corners[3].x = fast_roundf(p[0].X) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x); // bottom-left + lnk_data.corners[3].y = height - 1 - fast_roundf(p[0].Y) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y); // bottom-left + + // Payload is NOT already null terminated. + lnk_data.payload_len = message->outputIdx; + lnk_data.payload = xalloc(message->outputIdx); + memcpy(lnk_data.payload, message->output, message->outputIdx); + + int rotate = fast_roundf((((2 * M_PI) + fast_atan2f(p[1].Y - p[0].Y, p[1].X - p[0].X)) * 180) / M_PI); + if(rotate >= 360) rotate -= 360; + + lnk_data.rotation = rotate; + lnk_data.rows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, region->sizeIdx); + lnk_data.columns = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, region->sizeIdx); + lnk_data.capacity = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, region->sizeIdx); + lnk_data.padding = message->padCount; + + list_push_back(out, &lnk_data); + + dmtxMessageDestroy(&message); + } + + dmtxRegionDestroy(®ion); + } + + dmtxDecodeDestroy(&decode); + dmtxImageDestroy(&image); + + fb_free(); // umm_init_x(); + if (ptr->bpp != IMAGE_BPP_GRAYSCALE) fb_free(); // grayscale_image; +} + +#pragma GCC diagnostic pop +#endif //IMLIB_ENABLE_DATAMATRICES diff --git a/src/openmv/src/omv/img/draw.c b/src/openmv/src/omv/img/draw.c new file mode 100755 index 0000000..d9ccdc0 --- /dev/null +++ b/src/openmv/src/omv/img/draw.c @@ -0,0 +1,367 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "font.h" +#include "imlib.h" + +// Get pixel (handles boundary check and image type check). +int imlib_get_pixel(image_t *img, int x, int y) +{ + if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) { + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + return IMAGE_GET_BINARY_PIXEL(img, x, y); + } + case IMAGE_BPP_GRAYSCALE: { + return IMAGE_GET_GRAYSCALE_PIXEL(img, x, y); + } + case IMAGE_BPP_RGB565: { + return IMAGE_GET_RGB565_PIXEL(img, x, y); + } + default: { + return -1; + } + } + } + + return -1; +} + +// Set pixel (handles boundary check and image type check). +void imlib_set_pixel(image_t *img, int x, int y, int p) +{ + if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) { + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + IMAGE_PUT_BINARY_PIXEL(img, x, y, p); + break; + } + case IMAGE_BPP_GRAYSCALE: { + IMAGE_PUT_GRAYSCALE_PIXEL(img, x, y, p); + break; + } + case IMAGE_BPP_RGB565: { + IMAGE_PUT_RGB565_PIXEL(img, x, y, p); + break; + } + default: { + break; + } + } + } +} + +// https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles +static void point_fill(image_t *img, int cx, int cy, int r0, int r1, int c) +{ + for (int y = r0; y <= r1; y++) { + for (int x = r0; x <= r1; x++) { + if (((x * x) + (y * y)) <= (r0 * r0)) { + imlib_set_pixel(img, cx + x, cy + y, c); + } + } + } +} + +// https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C +void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness) +{ + if (thickness > 0) { + int thickness0 = (thickness - 0) / 2; + int thickness1 = (thickness - 1) / 2; + int dx = abs(x1 - x0), sx = (x0 < x1) ? 1 : -1; + int dy = abs(y1 - y0), sy = (y0 < y1) ? 1 : -1; + int err = ((dx > dy) ? dx : -dy) / 2; + + for (;;) { + point_fill(img, x0, y0, -thickness0, thickness1, c); + if ((x0 == x1) && (y0 == y1)) break; + int e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + } +} + +static void xLine(image_t *img, int x1, int x2, int y, int c) +{ + while (x1 <= x2) imlib_set_pixel(img, x1++, y, c); +} + +static void yLine(image_t *img, int x, int y1, int y2, int c) +{ + while (y1 <= y2) imlib_set_pixel(img, x, y1++, c); +} + +void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill) +{ + if (fill) { + + for (int y = ry, yy = ry + rh; y < yy; y++) { + for (int x = rx, xx = rx + rw; x < xx; x++) { + imlib_set_pixel(img, x, y, c); + } + } + + } else if (thickness > 0) { + int thickness0 = (thickness - 0) / 2; + int thickness1 = (thickness - 1) / 2; + + for (int i = rx - thickness0, j = rx + rw + thickness1, k = ry + rh - 1; i < j; i++) { + yLine(img, i, ry - thickness0, ry + thickness1, c); + yLine(img, i, k - thickness0, k + thickness1, c); + } + + for (int i = ry - thickness0, j = ry + rh + thickness1, k = rx + rw - 1; i < j; i++) { + xLine(img, rx - thickness0, rx + thickness1, i, c); + xLine(img, k - thickness0, k + thickness1, i, c); + } + } +} + +// https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm +void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill) +{ + if (fill) { + point_fill(img, cx, cy, -r, r, c); + } else if (thickness > 0) { + int thickness0 = (thickness - 0) / 2; + int thickness1 = (thickness - 1) / 2; + + int xo = r + thickness0; + int xi = IM_MAX(r - thickness1, 0); + int xi_tmp = xi; + int y = 0; + int erro = 1 - xo; + int erri = 1 - xi; + + while(xo >= y) { + xLine(img, cx + xi, cx + xo, cy + y, c); + yLine(img, cx + y, cy + xi, cy + xo, c); + xLine(img, cx - xo, cx - xi, cy + y, c); + yLine(img, cx - y, cy + xi, cy + xo, c); + xLine(img, cx - xo, cx - xi, cy - y, c); + yLine(img, cx - y, cy - xo, cy - xi, c); + xLine(img, cx + xi, cx + xo, cy - y, c); + yLine(img, cx + y, cy - xo, cy - xi, c); + + y++; + + if (erro < 0) { + erro += 2 * y + 1; + } else { + xo--; + erro += 2 * (y - xo + 1); + } + + if (y > xi_tmp) { + xi = y; + } else { + if (erri < 0) { + erri += 2 * y + 1; + } else { + xi--; + erri += 2 * (y - xi + 1); + } + } + } + } +} + +void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale, int x_spacing, int y_spacing, bool mono_space) +{ + const int anchor = x_off; + + for(char ch, last = '\0'; (ch = *str); str++, last = ch) { + + if ((last == '\r') && (ch == '\n')) { // handle "\r\n" strings + continue; + } + + if ((ch == '\n') || (ch == '\r')) { // handle '\n' or '\r' strings + x_off = anchor; + y_off += (font[0].h * scale) + y_spacing; // newline height == space height + continue; + } + + if ((ch < ' ') || (ch > '~')) { // handle unknown characters + imlib_draw_rectangle(img, + x_off + ((scale * 3) / 2), + y_off + ((scale * 3) / 2), + (font[0].w * scale) - (((scale * 3) / 2) * 2), + (font[0].h * scale) - (((scale * 3) / 2) * 2), + c, scale, false); + continue; + } + + const glyph_t *g = &font[ch - ' ']; + + if (!mono_space) { + // Find the first pixel set and offset to that. + bool exit = false; + + for (int x = 0, xx = g->w; x < xx; x++) { + for (int y = 0, yy = g->h; y < yy; y++) { + if (g->data[y] & (1 << (g->w - 1 - x))) { + x_off -= x * scale; + exit = true; + break; + } + } + + if (exit) break; + } + } + + for (int y = 0, yy = g->h * scale; y < yy; y++) { + for (int x = 0, xx = g->w * scale; x < xx; x++) { + if (g->data[y / scale] & (1 << (g->w - 1 - (x / scale)))) { + imlib_set_pixel(img, (x_off + x), (y_off + y), c); + } + } + } + + if (mono_space) { + x_off += (g->w * scale) + x_spacing; + } else { + // Find the last pixel set and offset to that. + bool exit = false; + + for (int x = g->w - 1; x >= 0; x--) { + for (int y = g->h - 1; y >= 0; y--) { + if (g->data[y] & (1 << (g->w - 1 - x))) { + x_off += ((x + 2) * scale) + x_spacing; + exit = true; + break; + } + } + + if (exit) break; + } + + if (!exit) x_off += scale * 3; // space char + } + } +} + +void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float x_scale, float y_scale, image_t *mask) +{ + float over_xscale = IM_DIV(1.0, x_scale), over_yscale = IM_DIV(1.0f, y_scale); + + for (int y = 0, yy = fast_roundf(other->h * y_scale); y < yy; y++) { + int other_y = fast_roundf(y * over_yscale); + + for (int x = 0, xx = fast_roundf(other->w * x_scale); x < xx; x++) { + int other_x = fast_roundf(x * over_xscale); + + if (mask && (!image_get_mask_pixel(mask, other_x, other_y))) continue; + imlib_set_pixel(img, x_off + x, y_off + y, imlib_get_pixel(other, other_x, other_y)); + } + } +} + +#ifdef IMLIB_ENABLE_FLOOD_FILL +void imlib_flood_fill(image_t *img, int x, int y, + float seed_threshold, float floating_threshold, + int c, bool invert, bool clear_background, image_t *mask) +{ + if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) { + image_t out; + out.w = img->w; + out.h = img->h; + out.bpp = IMAGE_BPP_BINARY; + out.data = fb_alloc0(image_size(&out)); + + if (mask) { + for (int y = 0, yy = out.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + if (image_get_mask_pixel(mask, x, y)) IMAGE_SET_BINARY_PIXEL_FAST(row_ptr, x); + } + } + } + + int color_seed_threshold = 0; + int color_floating_threshold = 0; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + color_seed_threshold = fast_roundf(seed_threshold * COLOR_BINARY_MAX); + color_floating_threshold = fast_roundf(floating_threshold * COLOR_BINARY_MAX); + break; + } + case IMAGE_BPP_GRAYSCALE: { + color_seed_threshold = fast_roundf(seed_threshold * COLOR_GRAYSCALE_MAX); + color_floating_threshold = fast_roundf(floating_threshold * COLOR_GRAYSCALE_MAX); + break; + } + case IMAGE_BPP_RGB565: { + color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(seed_threshold * COLOR_R5_MAX), + fast_roundf(seed_threshold * COLOR_G6_MAX), + fast_roundf(seed_threshold * COLOR_B5_MAX)); + color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(floating_threshold * COLOR_R5_MAX), + fast_roundf(floating_threshold * COLOR_G6_MAX), + fast_roundf(floating_threshold * COLOR_B5_MAX)); + break; + } + default: { + break; + } + } + + imlib_flood_fill_int(&out, img, x, y, color_seed_threshold, color_floating_threshold, NULL, NULL); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = out.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, c); + } else if (clear_background) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = out.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, c); + } else if (clear_background) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = out.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(out_row_ptr, x) ^ invert) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, c); + } else if (clear_background) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + default: { + break; + } + } + + fb_free(); + } +} +#endif // IMLIB_ENABLE_FLOOD_FILL diff --git a/src/openmv/src/omv/img/edge.c b/src/openmv/src/omv/img/edge.c new file mode 100755 index 0000000..78415f5 --- /dev/null +++ b/src/openmv/src/omv/img/edge.c @@ -0,0 +1,155 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Edge Detection. + * + */ +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#ifdef IMLIB_ENABLE_BINARY_OPS + +typedef struct gvec { + uint16_t t; + uint16_t g; +} gvec_t; + +void imlib_edge_simple(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh) +{ + imlib_morph(src, 1, kernel_high_pass_3, 1.0f, 0.0f, false, 0, false, NULL); + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + color_thresholds_list_lnk_data_t lnk_data; + lnk_data.LMin=low_thresh; + lnk_data.LMax=high_thresh; + list_push_back(&thresholds, &lnk_data); + imlib_binary(src, src, &thresholds, false, false, NULL); + list_free(&thresholds); + imlib_erode(src, 1, 2, NULL); +} + +void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh) +{ + int w = src->w; + + gvec_t *gm = fb_alloc0(roi->w*roi->h*sizeof*gm); + + //1. Noise Reduction with a Gaussian filter + imlib_sepconv3(src, kernel_gauss_3, 1.0f/16.0f, 0.0f); + + //2. Finding Image Gradients + for (int gy=1, y=roi->y+1; yy+roi->h-1; y++, gy++) { + for (int gx=1, x=roi->x+1; xx+roi->w-1; x++, gx++) { + int vx=0, vy=0; + // sobel kernel in the horizontal direction + vx = src->data [(y-1)*w+x-1] + - src->data [(y-1)*w+x+1] + + (src->data[(y+0)*w+x-1]<<1) + - (src->data[(y+0)*w+x+1]<<1) + + src->data [(y+1)*w+x-1] + - src->data [(y+1)*w+x+1]; + + // sobel kernel in the vertical direction + vy = src->data [(y-1)*w+x-1] + + (src->data[(y-1)*w+x+0]<<1) + + src->data [(y-1)*w+x+1] + - src->data [(y+1)*w+x-1] + - (src->data[(y+1)*w+x+0]<<1) + - src->data [(y+1)*w+x+1]; + + // Find magnitude + int g = (int) fast_sqrtf(vx*vx + vy*vy); + // Find the direction and round angle to 0, 45, 90 or 135 + int t = (int) fast_fabsf((atan2f(vy, vx)*180.0f/M_PI)); + if (t < 22) { + t = 0; + } else if (t < 67) { + t = 45; + } else if (t < 112) { + t = 90; + } else if (t < 160) { + t = 135; + } else if (t <= 180) { + t = 0; + } + + gm[gy*roi->w+gx].t = t; + gm[gy*roi->w+gx].g = g; + } + } + + // 3. Hysteresis Thresholding + // 4. Non-maximum Suppression and output + for (int gy=0, y=roi->y; yy+roi->h; y++, gy++) { + for (int gx=0, x=roi->x; xx+roi->w; x++, gx++) { + int i = y*w+x; + gvec_t *va=NULL, *vb=NULL, *vc = &gm[gy*roi->w+gx]; + + // Clear the borders + if (y == (roi->y) || y == (roi->y+roi->h-1) || + x == (roi->x) || x == (roi->x+roi->w-1)) { + src->data[i] = 0; + continue; + } + + if (vc->g < low_thresh) { + // Not an edge + src->data[i] = 0; + continue; + // Check if strong or weak edge + } else if (vc->g >= high_thresh || + gm[(gy-1)*roi->w+(gx-1)].g >= high_thresh || + gm[(gy-1)*roi->w+(gx+0)].g >= high_thresh || + gm[(gy-1)*roi->w+(gx+1)].g >= high_thresh || + gm[(gy+0)*roi->w+(gx-1)].g >= high_thresh || + gm[(gy+0)*roi->w+(gx+1)].g >= high_thresh || + gm[(gy+1)*roi->w+(gx-1)].g >= high_thresh || + gm[(gy+1)*roi->w+(gx+0)].g >= high_thresh || + gm[(gy+1)*roi->w+(gx+1)].g >= high_thresh) { + vc->g = vc->g; + } else { // Not an edge + src->data[i] = 0; + continue; + } + + switch (vc->t) { + case 0: { + va = &gm[(gy+0)*roi->w+(gx-1)]; + vb = &gm[(gy+0)*roi->w+(gx+1)]; + break; + } + + case 45: { + va = &gm[(gy+1)*roi->w+(gx-1)]; + vb = &gm[(gy-1)*roi->w+(gx+1)]; + break; + } + + case 90: { + va = &gm[(gy+1)*roi->w+(gx+0)]; + vb = &gm[(gy-1)*roi->w+(gx+0)]; + break; + } + + case 135: { + va = &gm[(gy+1)*roi->w+(gx+1)]; + vb = &gm[(gy-1)*roi->w+(gx-1)]; + break; + } + } + + if (!(vc->g > va->g && vc->g > vb->g)) { + src->data[i] = 0; + } else { + src->data[i] = 255; + } + } + } + + fb_free(); +} +#endif diff --git a/src/openmv/src/omv/img/eye.c b/src/openmv/src/omv/img/eye.c new file mode 100755 index 0000000..56a1a35 --- /dev/null +++ b/src/openmv/src/omv/img/eye.c @@ -0,0 +1,136 @@ +/* +* This file is part of the OpenMV project. +* Copyright (c) 2013/2014 Ibrahim Abdelkader +* This work is licensed under the MIT license, see the file LICENSE for details. +* +* Pupil localization using image gradients. +* See Fabian Timm's paper. +* +*/ +#include "imlib.h" +#include "xalloc.h" +#include "fmath.h" + +static void find_gradients(image_t *src, array_t *gradients, int x_off, int y_off, int box_w, int box_h) +{ + for (int y=y_off; yw; + // sobel_kernel + vx = src->data[(y+0)*w+x+0] + - src->data[(y+0)*w+x+2] + + (src->data[(y+1)*w+x+0]<<1) + - (src->data[(y+1)*w+x+2]<<1) + + src->data[(y+2)*w+x+0] + - src->data[(y+2)*w+x+2]; + + // sobel_kernel + vy = src->data[(y+0)*w+x+0] + + (src->data[(y+0)*w+x+1]<<1) + + src->data[(y+0)*w+x+2] + - src->data[(y+2)*w+x+0] + - (src->data[(y+2)*w+x+1]<<1) + - src->data[(y+2)*w+x+2]; + + float m = fast_sqrtf(vx*vx+vy*vy); + if (m>200) { + vec_t *v = xalloc(sizeof(vec_t)); + v->m = m; + v->x = vx/m; + v->y = vy/m; + v->cx = x+1; + v->cy = y+1; + array_push_back(gradients, v); + } + } + } +} + +// TODO use the gradients median not average +static void filter_gradients(array_t *gradients) +{ + float total_m=0.0f; + for (int i=0; im; + } + + float avg_m = total_m/array_length(gradients); + + for (int i=0; im-avg_m) * (v->m-avg_m); + if (fast_sqrtf(diff)>100) { + array_erase(gradients, i); + } + } +} + +static void find_iris(image_t *src, array_t *gradients, int x_off, int y_off, int box_w, int box_h, point_t *e) +{ + int max_x=0; + int max_y=0; + float max_dot = 0.0f; + + for (int y=y_off; ycx, y-v->cy}; + + // normalize d vector + float m = fast_sqrtf(d.x*d.x+d.y*d.y); + d.x = d.x/m; + d.y = d.y/m; + + // compute the dot product d.g + float t = (d.x*v->x)+(d.y*v->y); + + // d,g should point the same direction + if (t>0.0) { + // dark centres are more likely to be pupils than + // bright centres, so we use the grayscale value as weight. + sum_dot += t*t*(255-src->data[y*src->w+x]); + } + } + sum_dot=sum_dot/array_length(gradients); + + if (sum_dot > max_dot) { + max_dot = sum_dot; + max_x = x; + max_y = y; + } + } + } + + e->x = max_x; + e->y = max_y; +} + +// This function should be called on an ROI detected with the eye Haar cascade. +void imlib_find_iris(image_t *src, point_t *iris, rectangle_t *roi) +{ + array_t *iris_gradients; + array_alloc(&iris_gradients, xfree); + + // Tune these offsets to skip eyebrows and reduce window size + int box_w = roi->w-((int)(0.15f*roi->w)); + int box_h = roi->h-((int)(0.40f*roi->h)); + int x_off = roi->x+((int)(0.15f*roi->w)); + int y_off = roi->y+((int)(0.40f*roi->h)); + + // find gradients with strong magnitudes + find_gradients(src, iris_gradients, x_off, y_off, box_w, box_h); + + // filter gradients + filter_gradients(iris_gradients); + + // search for iriss + find_iris(src, iris_gradients, x_off, y_off, box_w, box_h, iris); + + array_free(iris_gradients); +} diff --git a/src/openmv/src/omv/img/fast.c b/src/openmv/src/omv/img/fast.c new file mode 100755 index 0000000..7616a83 --- /dev/null +++ b/src/openmv/src/omv/img/fast.c @@ -0,0 +1,6040 @@ +#include +#include "imlib.h" +#include "xalloc.h" +#include "fb_alloc.h" +#include "gc.h" + +#ifdef IMLIB_ENABLE_FAST + +#define MAX_ROW (480) +#define MAX_CORNERS (2000) +#define Compare(X, Y) ((X)>=(Y)) + +typedef struct { + uint16_t x; + uint16_t y; + uint16_t score; +} corner_t; + +static int pixel[16]; +static corner_t *fast9_detect(image_t *image, rectangle_t *roi, int *n_corners, int b); +static void fast9_score(image_t *image, corner_t *corners, int num_corners, int b); +static void nonmax_suppression(corner_t *corners, int num_corners, array_t *keypoints); + +static kp_t *alloc_keypoint(uint16_t x, uint16_t y, uint16_t score) +{ + // Note must set keypoint descriptor to zeros + kp_t *kpt = xalloc0(sizeof*kpt); + kpt->x = x; + kpt->y = y; + kpt->score = score; + return kpt; +} + +static void make_offsets(int pixel[], int row_stride) +{ + pixel[0] = 0 + row_stride * 3; + pixel[1] = 1 + row_stride * 3; + pixel[2] = 2 + row_stride * 2; + pixel[3] = 3 + row_stride * 1; + pixel[4] = 3 + row_stride * 0; + pixel[5] = 3 + row_stride * -1; + pixel[6] = 2 + row_stride * -2; + pixel[7] = 1 + row_stride * -3; + pixel[8] = 0 + row_stride * -3; + pixel[9] = -1 + row_stride * -3; + pixel[10] = -2 + row_stride * -2; + pixel[11] = -3 + row_stride * -1; + pixel[12] = -3 + row_stride * 0; + pixel[13] = -3 + row_stride * 1; + pixel[14] = -2 + row_stride * 2; + pixel[15] = -1 + row_stride * 3; +} + +void fast_detect(image_t *image, array_t *keypoints, int threshold, rectangle_t *roi) +{ + int num_corners=0; + make_offsets(pixel, image->w); + + // Find corners + corner_t *corners = fast9_detect(image, roi, &num_corners, threshold); + if (num_corners) { + // Score corners + fast9_score(image, corners, num_corners, threshold); + // Non-max suppression + nonmax_suppression(corners, num_corners, keypoints); + } + + // Free corners; + fb_free(); +} + +static void nonmax_suppression(corner_t *corners, int num_corners, array_t *keypoints) +{ + gc_info_t info; + + int last_row; + int16_t row_start[MAX_ROW+1]; + const int sz = num_corners; + + /* Point above points (roughly) to the pixel above + the one of interest, if there is a feature there.*/ + int point_above = 0; + int point_below = 0; + + /* Find where each row begins (the corners are output in raster scan order). + A beginning of -1 signifies that there are no corners on that row. */ + last_row = corners[sz-1].y; + + for(int i=0; iy != prev_row) { + row_start[c->y] = i; + prev_row = c->y; + } + } + + for(int i=0; i 0) { + if (corners[i-1].x == pos.x-1 && corners[i-1].y == pos.y && Compare(corners[i-1].score, score)) { + goto nonmax; + } + } + + /*Check right*/ + if (i < (sz - 1)) { + if (corners[i+1].x == pos.x+1 && corners[i+1].y == pos.y && Compare(corners[i+1].score, score)) { + goto nonmax; + } + } + + /*Check above (if there is a valid row above)*/ + if (pos.y != 0 && row_start[pos.y - 1] != -1) { + /*Make sure that current point_above is one row above.*/ + if(corners[point_above].y < pos.y - 1) + point_above = row_start[pos.y-1]; + + /*Make point_above point to the first of the pixels above the current point, if it exists.*/ + for (; corners[point_above].y < pos.y && corners[point_above].x < pos.x - 1; point_above++) { + + } + + for (int j=point_above; corners[j].y < pos.y && corners[j].x <= pos.x + 1; j++) { + int x = corners[j].x; + if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(corners[j].score, score)) + goto nonmax; + } + } + + /*Check below (if there is anything below)*/ + if (pos.y != last_row && row_start[pos.y + 1] != -1 && point_below < sz) /*Nothing below*/ { + if (corners[point_below].y < pos.y + 1) + point_below = row_start[pos.y+1]; + + /* Make point below point to one of the pixels belowthe current point, if it exists.*/ + for (; point_below < sz && corners[point_below].y == pos.y+1 && corners[point_below].x < pos.x - 1; point_below++) { + } + + for (int j=point_below; j < sz && corners[j].y == pos.y+1 && corners[j].x <= pos.x + 1; j++) { + int x = corners[j].x; + if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(corners[j].score, score)) + goto nonmax; + } + } + + gc_info(&info); + #define MIN_MEM (10*1024) + // Allocate keypoints until we're almost out of memory + if (info.free < MIN_MEM) { + // Try collecting memory + gc_collect(); + // If it didn't work break + gc_info(&info); + if (info.free < MIN_MEM) { + break; + } + } + + #undef MIN_MEM + array_push_back(keypoints, alloc_keypoint(pos.x, pos.y, pos.score)); + nonmax: + ; + } +} + +static int fast9_corner_score(const byte* p, int bstart) +{ + int bmin = bstart; + int bmax = 255; + int b = (bmax + bmin)/2; + + /*Compute the score using binary search*/ + for(;;) + { + int cb = *p + b; + int c_b= *p - b; + + + if( p[pixel[0]] > cb) + if( p[pixel[1]] > cb) + if( p[pixel[2]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[7]] < c_b) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[14]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[6]] < c_b) + if( p[pixel[15]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[5]] < c_b) + if( p[pixel[14]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[12]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[14]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[6]] < c_b) + goto is_a_corner; + else + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[12]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[6]] < c_b) + goto is_a_corner; + else + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[4]] < c_b) + if( p[pixel[13]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[11]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + goto is_a_corner; + else + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[11]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + goto is_a_corner; + else + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[3]] < c_b) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[10]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + goto is_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[10]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + goto is_a_corner; + else + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[2]] < c_b) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[9]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[3]] < c_b) + goto is_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[9]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[3]] < c_b) + goto is_a_corner; + else + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[1]] < c_b) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[2]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[8]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[3]] < c_b) + if( p[pixel[2]] < c_b) + goto is_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[2]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[8]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[3]] < c_b) + if( p[pixel[2]] < c_b) + goto is_a_corner; + else + if( p[pixel[11]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[0]] < c_b) + if( p[pixel[1]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[2]] > cb) + goto is_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[2]] < c_b) + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[1]] < c_b) + if( p[pixel[2]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[3]] > cb) + goto is_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[2]] < c_b) + if( p[pixel[3]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + goto is_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[3]] < c_b) + if( p[pixel[4]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + goto is_a_corner; + else + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[11]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[4]] < c_b) + if( p[pixel[5]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[6]] > cb) + goto is_a_corner; + else + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[14]] < c_b) + if( p[pixel[12]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[6]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[5]] < c_b) + if( p[pixel[6]] > cb) + if( p[pixel[15]] < c_b) + if( p[pixel[13]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[6]] < c_b) + if( p[pixel[7]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[6]] > cb) + goto is_a_corner; + else + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + goto is_a_corner; + else + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + goto is_a_corner; + else + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[9]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[3]] > cb) + goto is_a_corner; + else + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[8]] > cb) + if( p[pixel[7]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[10]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[2]] > cb) + goto is_a_corner; + else + if( p[pixel[11]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[2]] < c_b) + if( p[pixel[3]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[7]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[7]] > cb) + if( p[pixel[8]] > cb) + if( p[pixel[9]] > cb) + if( p[pixel[6]] > cb) + if( p[pixel[5]] > cb) + if( p[pixel[4]] > cb) + if( p[pixel[3]] > cb) + if( p[pixel[2]] > cb) + if( p[pixel[1]] > cb) + goto is_a_corner; + else + if( p[pixel[10]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] > cb) + if( p[pixel[11]] > cb) + if( p[pixel[12]] > cb) + if( p[pixel[13]] > cb) + if( p[pixel[14]] > cb) + if( p[pixel[15]] > cb) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else if( p[pixel[7]] < c_b) + if( p[pixel[8]] < c_b) + if( p[pixel[9]] < c_b) + if( p[pixel[6]] < c_b) + if( p[pixel[5]] < c_b) + if( p[pixel[4]] < c_b) + if( p[pixel[3]] < c_b) + if( p[pixel[2]] < c_b) + if( p[pixel[1]] < c_b) + goto is_a_corner; + else + if( p[pixel[10]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + if( p[pixel[10]] < c_b) + if( p[pixel[11]] < c_b) + if( p[pixel[12]] < c_b) + if( p[pixel[13]] < c_b) + if( p[pixel[14]] < c_b) + if( p[pixel[15]] < c_b) + goto is_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + else + goto is_not_a_corner; + + is_a_corner: + bmin=b; + goto end_if; + + is_not_a_corner: + bmax=b; + goto end_if; + + end_if: + + if(bmin == bmax - 1 || bmin == bmax) + return bmin; + b = (bmin + bmax) / 2; + } +} + +static void fast9_score(image_t *image, corner_t *corners, int num_corners, int b) +{ + for (int i=0; iscore = fast9_corner_score(image->pixels + c->y*image->w + c->x, b); + } +} + +static corner_t *fast9_detect(image_t *image, rectangle_t *roi, int *n_corners, int b) +{ + int num_corners = 0; + // Try to alloc MAX_CORNERS or the actual max corners we can alloc. + int max_corners = IM_MIN(MAX_CORNERS, (fb_avail() / sizeof(corner_t))); + corner_t *corners = (corner_t*) fb_alloc(max_corners * sizeof(corner_t)); + + for(int y=roi->y+3; yy+roi->h-3; y++) { + for(int x=roi->x+3; xx+roi->w-3; x++) { + const uint8_t *p = image->pixels+(y * image->w + x); + int cb = *p + b; + int c_b= *p - b; + if(p[pixel[0]] > cb) + if(p[pixel[1]] > cb) + if(p[pixel[2]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + if(p[pixel[15]] > cb) + {} + else + continue; + else if(p[pixel[7]] < c_b) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else if(p[pixel[14]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else if(p[pixel[6]] < c_b) + if(p[pixel[15]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[5]] < c_b) + if(p[pixel[14]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[12]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[14]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[6]] < c_b) + {} + else + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[12]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[6]] < c_b) + {} + else + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[4]] < c_b) + if(p[pixel[13]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[11]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + {} + else + if(p[pixel[14]] < c_b) + {} + else + continue; + else + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[11]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + {} + else + if(p[pixel[14]] < c_b) + {} + else + continue; + else + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[3]] < c_b) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[10]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + {} + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[10]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + {} + else + if(p[pixel[13]] < c_b) + {} + else + continue; + else + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[2]] < c_b) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[9]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[3]] < c_b) + {} + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[9]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[3]] < c_b) + {} + else + if(p[pixel[12]] < c_b) + {} + else + continue; + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[1]] < c_b) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[2]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[8]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[3]] < c_b) + if(p[pixel[2]] < c_b) + {} + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[2]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[8]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[3]] < c_b) + if(p[pixel[2]] < c_b) + {} + else + if(p[pixel[11]] < c_b) + {} + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[0]] < c_b) + if(p[pixel[1]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[2]] > cb) + {} + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[2]] < c_b) + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[1]] < c_b) + if(p[pixel[2]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[3]] > cb) + {} + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[2]] < c_b) + if(p[pixel[3]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + {} + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[3]] < c_b) + if(p[pixel[4]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + {} + else + if(p[pixel[14]] > cb) + {} + else + continue; + else + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[11]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[4]] < c_b) + if(p[pixel[5]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[6]] > cb) + {} + else + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[14]] < c_b) + if(p[pixel[12]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[6]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[5]] < c_b) + if(p[pixel[6]] > cb) + if(p[pixel[15]] < c_b) + if(p[pixel[13]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[6]] < c_b) + if(p[pixel[7]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + if(p[pixel[15]] < c_b) + {} + else + continue; + else + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[13]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[6]] > cb) + {} + else + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + {} + else + if(p[pixel[14]] > cb) + {} + else + continue; + else + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + {} + else + if(p[pixel[13]] > cb) + {} + else + continue; + else + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[9]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[3]] > cb) + {} + else + if(p[pixel[12]] > cb) + {} + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[8]] > cb) + if(p[pixel[7]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[10]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[2]] > cb) + {} + else + if(p[pixel[11]] > cb) + {} + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[2]] < c_b) + if(p[pixel[3]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[7]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[7]] > cb) + if(p[pixel[8]] > cb) + if(p[pixel[9]] > cb) + if(p[pixel[6]] > cb) + if(p[pixel[5]] > cb) + if(p[pixel[4]] > cb) + if(p[pixel[3]] > cb) + if(p[pixel[2]] > cb) + if(p[pixel[1]] > cb) + {} + else + if(p[pixel[10]] > cb) + {} + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + {} + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] > cb) + if(p[pixel[11]] > cb) + if(p[pixel[12]] > cb) + if(p[pixel[13]] > cb) + if(p[pixel[14]] > cb) + if(p[pixel[15]] > cb) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else if(p[pixel[7]] < c_b) + if(p[pixel[8]] < c_b) + if(p[pixel[9]] < c_b) + if(p[pixel[6]] < c_b) + if(p[pixel[5]] < c_b) + if(p[pixel[4]] < c_b) + if(p[pixel[3]] < c_b) + if(p[pixel[2]] < c_b) + if(p[pixel[1]] < c_b) + {} + else + if(p[pixel[10]] < c_b) + {} + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + {} + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + if(p[pixel[10]] < c_b) + if(p[pixel[11]] < c_b) + if(p[pixel[12]] < c_b) + if(p[pixel[13]] < c_b) + if(p[pixel[14]] < c_b) + if(p[pixel[15]] < c_b) + {} + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + else + continue; + + // Add corner + corners[num_corners].x = x; + corners[num_corners].y = y; + + if (++num_corners == max_corners) { + goto done; + } + } + } + +done: + *n_corners = num_corners; + return corners; +} +#endif //IMLIB_ENABLE_FAST diff --git a/src/openmv/src/omv/img/fft.c b/src/openmv/src/omv/img/fft.c new file mode 100755 index 0000000..2fe7874 --- /dev/null +++ b/src/openmv/src/omv/img/fft.c @@ -0,0 +1,792 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * FFT LIB - can do 1024 point real FFTs and 512 point complex FFTs + * + */ +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "common.h" +#include "fft.h" +// http://processors.wiki.ti.com/index.php/Efficient_FFT_Computation_of_Real_Input + +const static float fft_cos_table[512] = { + 1.000000f, 0.999981f, 0.999925f, 0.999831f, 0.999699f, 0.999529f, 0.999322f, 0.999078f, + 0.998795f, 0.998476f, 0.998118f, 0.997723f, 0.997290f, 0.996820f, 0.996313f, 0.995767f, + 0.995185f, 0.994565f, 0.993907f, 0.993212f, 0.992480f, 0.991710f, 0.990903f, 0.990058f, + 0.989177f, 0.988258f, 0.987301f, 0.986308f, 0.985278f, 0.984210f, 0.983105f, 0.981964f, + 0.980785f, 0.979570f, 0.978317f, 0.977028f, 0.975702f, 0.974339f, 0.972940f, 0.971504f, + 0.970031f, 0.968522f, 0.966976f, 0.965394f, 0.963776f, 0.962121f, 0.960431f, 0.958703f, + 0.956940f, 0.955141f, 0.953306f, 0.951435f, 0.949528f, 0.947586f, 0.945607f, 0.943593f, + 0.941544f, 0.939459f, 0.937339f, 0.935184f, 0.932993f, 0.930767f, 0.928506f, 0.926210f, + 0.923880f, 0.921514f, 0.919114f, 0.916679f, 0.914210f, 0.911706f, 0.909168f, 0.906596f, + 0.903989f, 0.901349f, 0.898674f, 0.895966f, 0.893224f, 0.890449f, 0.887640f, 0.884797f, + 0.881921f, 0.879012f, 0.876070f, 0.873095f, 0.870087f, 0.867046f, 0.863973f, 0.860867f, + 0.857729f, 0.854558f, 0.851355f, 0.848120f, 0.844854f, 0.841555f, 0.838225f, 0.834863f, + 0.831470f, 0.828045f, 0.824589f, 0.821103f, 0.817585f, 0.814036f, 0.810457f, 0.806848f, + 0.803208f, 0.799537f, 0.795837f, 0.792107f, 0.788346f, 0.784557f, 0.780737f, 0.776888f, + 0.773010f, 0.769103f, 0.765167f, 0.761202f, 0.757209f, 0.753187f, 0.749136f, 0.745058f, + 0.740951f, 0.736817f, 0.732654f, 0.728464f, 0.724247f, 0.720003f, 0.715731f, 0.711432f, + 0.707107f, 0.702755f, 0.698376f, 0.693971f, 0.689541f, 0.685084f, 0.680601f, 0.676093f, + 0.671559f, 0.667000f, 0.662416f, 0.657807f, 0.653173f, 0.648514f, 0.643832f, 0.639124f, + 0.634393f, 0.629638f, 0.624859f, 0.620057f, 0.615232f, 0.610383f, 0.605511f, 0.600616f, + 0.595699f, 0.590760f, 0.585798f, 0.580814f, 0.575808f, 0.570781f, 0.565732f, 0.560662f, + 0.555570f, 0.550458f, 0.545325f, 0.540171f, 0.534998f, 0.529804f, 0.524590f, 0.519356f, + 0.514103f, 0.508830f, 0.503538f, 0.498228f, 0.492898f, 0.487550f, 0.482184f, 0.476799f, + 0.471397f, 0.465976f, 0.460539f, 0.455084f, 0.449611f, 0.444122f, 0.438616f, 0.433094f, + 0.427555f, 0.422000f, 0.416430f, 0.410843f, 0.405241f, 0.399624f, 0.393992f, 0.388345f, + 0.382683f, 0.377007f, 0.371317f, 0.365613f, 0.359895f, 0.354164f, 0.348419f, 0.342661f, + 0.336890f, 0.331106f, 0.325310f, 0.319502f, 0.313682f, 0.307850f, 0.302006f, 0.296151f, + 0.290285f, 0.284408f, 0.278520f, 0.272621f, 0.266713f, 0.260794f, 0.254866f, 0.248928f, + 0.242980f, 0.237024f, 0.231058f, 0.225084f, 0.219101f, 0.213110f, 0.207111f, 0.201105f, + 0.195090f, 0.189069f, 0.183040f, 0.177004f, 0.170962f, 0.164913f, 0.158858f, 0.152797f, + 0.146730f, 0.140658f, 0.134581f, 0.128498f, 0.122411f, 0.116319f, 0.110222f, 0.104122f, + 0.098017f, 0.091909f, 0.085797f, 0.079682f, 0.073565f, 0.067444f, 0.061321f, 0.055195f, + 0.049068f, 0.042938f, 0.036807f, 0.030675f, 0.024541f, 0.018407f, 0.012272f, 0.006136f, + 0.000000f, -0.006136f, -0.012272f, -0.018407f, -0.024541f, -0.030675f, -0.036807f, -0.042938f, + -0.049068f, -0.055195f, -0.061321f, -0.067444f, -0.073565f, -0.079682f, -0.085797f, -0.091909f, + -0.098017f, -0.104122f, -0.110222f, -0.116319f, -0.122411f, -0.128498f, -0.134581f, -0.140658f, + -0.146730f, -0.152797f, -0.158858f, -0.164913f, -0.170962f, -0.177004f, -0.183040f, -0.189069f, + -0.195090f, -0.201105f, -0.207111f, -0.213110f, -0.219101f, -0.225084f, -0.231058f, -0.237024f, + -0.242980f, -0.248928f, -0.254866f, -0.260794f, -0.266713f, -0.272621f, -0.278520f, -0.284408f, + -0.290285f, -0.296151f, -0.302006f, -0.307850f, -0.313682f, -0.319502f, -0.325310f, -0.331106f, + -0.336890f, -0.342661f, -0.348419f, -0.354164f, -0.359895f, -0.365613f, -0.371317f, -0.377007f, + -0.382683f, -0.388345f, -0.393992f, -0.399624f, -0.405241f, -0.410843f, -0.416430f, -0.422000f, + -0.427555f, -0.433094f, -0.438616f, -0.444122f, -0.449611f, -0.455084f, -0.460539f, -0.465976f, + -0.471397f, -0.476799f, -0.482184f, -0.487550f, -0.492898f, -0.498228f, -0.503538f, -0.508830f, + -0.514103f, -0.519356f, -0.524590f, -0.529804f, -0.534998f, -0.540171f, -0.545325f, -0.550458f, + -0.555570f, -0.560662f, -0.565732f, -0.570781f, -0.575808f, -0.580814f, -0.585798f, -0.590760f, + -0.595699f, -0.600616f, -0.605511f, -0.610383f, -0.615232f, -0.620057f, -0.624859f, -0.629638f, + -0.634393f, -0.639124f, -0.643832f, -0.648514f, -0.653173f, -0.657807f, -0.662416f, -0.667000f, + -0.671559f, -0.676093f, -0.680601f, -0.685084f, -0.689541f, -0.693971f, -0.698376f, -0.702755f, + -0.707107f, -0.711432f, -0.715731f, -0.720003f, -0.724247f, -0.728464f, -0.732654f, -0.736817f, + -0.740951f, -0.745058f, -0.749136f, -0.753187f, -0.757209f, -0.761202f, -0.765167f, -0.769103f, + -0.773010f, -0.776888f, -0.780737f, -0.784557f, -0.788346f, -0.792107f, -0.795837f, -0.799537f, + -0.803208f, -0.806848f, -0.810457f, -0.814036f, -0.817585f, -0.821103f, -0.824589f, -0.828045f, + -0.831470f, -0.834863f, -0.838225f, -0.841555f, -0.844854f, -0.848120f, -0.851355f, -0.854558f, + -0.857729f, -0.860867f, -0.863973f, -0.867046f, -0.870087f, -0.873095f, -0.876070f, -0.879012f, + -0.881921f, -0.884797f, -0.887640f, -0.890449f, -0.893224f, -0.895966f, -0.898674f, -0.901349f, + -0.903989f, -0.906596f, -0.909168f, -0.911706f, -0.914210f, -0.916679f, -0.919114f, -0.921514f, + -0.923880f, -0.926210f, -0.928506f, -0.930767f, -0.932993f, -0.935184f, -0.937339f, -0.939459f, + -0.941544f, -0.943593f, -0.945607f, -0.947586f, -0.949528f, -0.951435f, -0.953306f, -0.955141f, + -0.956940f, -0.958703f, -0.960431f, -0.962121f, -0.963776f, -0.965394f, -0.966976f, -0.968522f, + -0.970031f, -0.971504f, -0.972940f, -0.974339f, -0.975702f, -0.977028f, -0.978317f, -0.979570f, + -0.980785f, -0.981964f, -0.983105f, -0.984210f, -0.985278f, -0.986308f, -0.987301f, -0.988258f, + -0.989177f, -0.990058f, -0.990903f, -0.991710f, -0.992480f, -0.993212f, -0.993907f, -0.994565f, + -0.995185f, -0.995767f, -0.996313f, -0.996820f, -0.997290f, -0.997723f, -0.998118f, -0.998476f, + -0.998795f, -0.999078f, -0.999322f, -0.999529f, -0.999699f, -0.999831f, -0.999925f, -0.999981f +}; + +ALWAYS_INLINE static float get_cos(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return fft_cos_table[k << (9 - N_pow2)]; +} + +ALWAYS_INLINE static float get_ai(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (-get_cos(k, N_pow2)); +} + +ALWAYS_INLINE static float get_bi(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (+get_cos(k, N_pow2)); +} + +ALWAYS_INLINE static float get_a_star_i(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (+get_cos(k, N_pow2)); +} + +ALWAYS_INLINE static float get_b_star_i(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (-get_cos(k, N_pow2)); +} + +//// For samples 0 to (n/2)-1 --- Note: clog2(n/2) = N_pow2 +//ALWAYS_INLINE static float get_hann_l_side(int k, int N_pow2) +//{ +// return 0.5 * (1 - get_cos(k, N_pow2)); +//} + +//// For samples (n/2) to n-1 --- Note: clog2(n/2) = N_pow2 +//ALWAYS_INLINE static float get_hann_r_side(int k, int N_pow2) +//{ +// return 0.5 * (1 - get_cos((2 << N_pow2) - k - 1, N_pow2)); +//} + +const static float fft_sin_table[512] = { + 0.000000f, 0.006136f, 0.012272f, 0.018407f, 0.024541f, 0.030675f, 0.036807f, 0.042938f, + 0.049068f, 0.055195f, 0.061321f, 0.067444f, 0.073565f, 0.079682f, 0.085797f, 0.091909f, + 0.098017f, 0.104122f, 0.110222f, 0.116319f, 0.122411f, 0.128498f, 0.134581f, 0.140658f, + 0.146730f, 0.152797f, 0.158858f, 0.164913f, 0.170962f, 0.177004f, 0.183040f, 0.189069f, + 0.195090f, 0.201105f, 0.207111f, 0.213110f, 0.219101f, 0.225084f, 0.231058f, 0.237024f, + 0.242980f, 0.248928f, 0.254866f, 0.260794f, 0.266713f, 0.272621f, 0.278520f, 0.284408f, + 0.290285f, 0.296151f, 0.302006f, 0.307850f, 0.313682f, 0.319502f, 0.325310f, 0.331106f, + 0.336890f, 0.342661f, 0.348419f, 0.354164f, 0.359895f, 0.365613f, 0.371317f, 0.377007f, + 0.382683f, 0.388345f, 0.393992f, 0.399624f, 0.405241f, 0.410843f, 0.416430f, 0.422000f, + 0.427555f, 0.433094f, 0.438616f, 0.444122f, 0.449611f, 0.455084f, 0.460539f, 0.465976f, + 0.471397f, 0.476799f, 0.482184f, 0.487550f, 0.492898f, 0.498228f, 0.503538f, 0.508830f, + 0.514103f, 0.519356f, 0.524590f, 0.529804f, 0.534998f, 0.540171f, 0.545325f, 0.550458f, + 0.555570f, 0.560662f, 0.565732f, 0.570781f, 0.575808f, 0.580814f, 0.585798f, 0.590760f, + 0.595699f, 0.600616f, 0.605511f, 0.610383f, 0.615232f, 0.620057f, 0.624859f, 0.629638f, + 0.634393f, 0.639124f, 0.643832f, 0.648514f, 0.653173f, 0.657807f, 0.662416f, 0.667000f, + 0.671559f, 0.676093f, 0.680601f, 0.685084f, 0.689541f, 0.693971f, 0.698376f, 0.702755f, + 0.707107f, 0.711432f, 0.715731f, 0.720003f, 0.724247f, 0.728464f, 0.732654f, 0.736817f, + 0.740951f, 0.745058f, 0.749136f, 0.753187f, 0.757209f, 0.761202f, 0.765167f, 0.769103f, + 0.773010f, 0.776888f, 0.780737f, 0.784557f, 0.788346f, 0.792107f, 0.795837f, 0.799537f, + 0.803208f, 0.806848f, 0.810457f, 0.814036f, 0.817585f, 0.821103f, 0.824589f, 0.828045f, + 0.831470f, 0.834863f, 0.838225f, 0.841555f, 0.844854f, 0.848120f, 0.851355f, 0.854558f, + 0.857729f, 0.860867f, 0.863973f, 0.867046f, 0.870087f, 0.873095f, 0.876070f, 0.879012f, + 0.881921f, 0.884797f, 0.887640f, 0.890449f, 0.893224f, 0.895966f, 0.898674f, 0.901349f, + 0.903989f, 0.906596f, 0.909168f, 0.911706f, 0.914210f, 0.916679f, 0.919114f, 0.921514f, + 0.923880f, 0.926210f, 0.928506f, 0.930767f, 0.932993f, 0.935184f, 0.937339f, 0.939459f, + 0.941544f, 0.943593f, 0.945607f, 0.947586f, 0.949528f, 0.951435f, 0.953306f, 0.955141f, + 0.956940f, 0.958703f, 0.960431f, 0.962121f, 0.963776f, 0.965394f, 0.966976f, 0.968522f, + 0.970031f, 0.971504f, 0.972940f, 0.974339f, 0.975702f, 0.977028f, 0.978317f, 0.979570f, + 0.980785f, 0.981964f, 0.983105f, 0.984210f, 0.985278f, 0.986308f, 0.987301f, 0.988258f, + 0.989177f, 0.990058f, 0.990903f, 0.991710f, 0.992480f, 0.993212f, 0.993907f, 0.994565f, + 0.995185f, 0.995767f, 0.996313f, 0.996820f, 0.997290f, 0.997723f, 0.998118f, 0.998476f, + 0.998795f, 0.999078f, 0.999322f, 0.999529f, 0.999699f, 0.999831f, 0.999925f, 0.999981f, + 1.000000f, 0.999981f, 0.999925f, 0.999831f, 0.999699f, 0.999529f, 0.999322f, 0.999078f, + 0.998795f, 0.998476f, 0.998118f, 0.997723f, 0.997290f, 0.996820f, 0.996313f, 0.995767f, + 0.995185f, 0.994565f, 0.993907f, 0.993212f, 0.992480f, 0.991710f, 0.990903f, 0.990058f, + 0.989177f, 0.988258f, 0.987301f, 0.986308f, 0.985278f, 0.984210f, 0.983105f, 0.981964f, + 0.980785f, 0.979570f, 0.978317f, 0.977028f, 0.975702f, 0.974339f, 0.972940f, 0.971504f, + 0.970031f, 0.968522f, 0.966976f, 0.965394f, 0.963776f, 0.962121f, 0.960431f, 0.958703f, + 0.956940f, 0.955141f, 0.953306f, 0.951435f, 0.949528f, 0.947586f, 0.945607f, 0.943593f, + 0.941544f, 0.939459f, 0.937339f, 0.935184f, 0.932993f, 0.930767f, 0.928506f, 0.926210f, + 0.923880f, 0.921514f, 0.919114f, 0.916679f, 0.914210f, 0.911706f, 0.909168f, 0.906596f, + 0.903989f, 0.901349f, 0.898674f, 0.895966f, 0.893224f, 0.890449f, 0.887640f, 0.884797f, + 0.881921f, 0.879012f, 0.876070f, 0.873095f, 0.870087f, 0.867046f, 0.863973f, 0.860867f, + 0.857729f, 0.854558f, 0.851355f, 0.848120f, 0.844854f, 0.841555f, 0.838225f, 0.834863f, + 0.831470f, 0.828045f, 0.824589f, 0.821103f, 0.817585f, 0.814036f, 0.810457f, 0.806848f, + 0.803208f, 0.799537f, 0.795837f, 0.792107f, 0.788346f, 0.784557f, 0.780737f, 0.776888f, + 0.773010f, 0.769103f, 0.765167f, 0.761202f, 0.757209f, 0.753187f, 0.749136f, 0.745058f, + 0.740951f, 0.736817f, 0.732654f, 0.728464f, 0.724247f, 0.720003f, 0.715731f, 0.711432f, + 0.707107f, 0.702755f, 0.698376f, 0.693971f, 0.689541f, 0.685084f, 0.680601f, 0.676093f, + 0.671559f, 0.667000f, 0.662416f, 0.657807f, 0.653173f, 0.648514f, 0.643832f, 0.639124f, + 0.634393f, 0.629638f, 0.624859f, 0.620057f, 0.615232f, 0.610383f, 0.605511f, 0.600616f, + 0.595699f, 0.590760f, 0.585798f, 0.580814f, 0.575808f, 0.570781f, 0.565732f, 0.560662f, + 0.555570f, 0.550458f, 0.545325f, 0.540171f, 0.534998f, 0.529804f, 0.524590f, 0.519356f, + 0.514103f, 0.508830f, 0.503538f, 0.498228f, 0.492898f, 0.487550f, 0.482184f, 0.476799f, + 0.471397f, 0.465976f, 0.460539f, 0.455084f, 0.449611f, 0.444122f, 0.438616f, 0.433094f, + 0.427555f, 0.422000f, 0.416430f, 0.410843f, 0.405241f, 0.399624f, 0.393992f, 0.388345f, + 0.382683f, 0.377007f, 0.371317f, 0.365613f, 0.359895f, 0.354164f, 0.348419f, 0.342661f, + 0.336890f, 0.331106f, 0.325310f, 0.319502f, 0.313682f, 0.307850f, 0.302006f, 0.296151f, + 0.290285f, 0.284408f, 0.278520f, 0.272621f, 0.266713f, 0.260794f, 0.254866f, 0.248928f, + 0.242980f, 0.237024f, 0.231058f, 0.225084f, 0.219101f, 0.213110f, 0.207111f, 0.201105f, + 0.195090f, 0.189069f, 0.183040f, 0.177004f, 0.170962f, 0.164913f, 0.158858f, 0.152797f, + 0.146730f, 0.140658f, 0.134581f, 0.128498f, 0.122411f, 0.116319f, 0.110222f, 0.104122f, + 0.098017f, 0.091909f, 0.085797f, 0.079682f, 0.073565f, 0.067444f, 0.061321f, 0.055195f, + 0.049068f, 0.042938f, 0.036807f, 0.030675f, 0.024541f, 0.018407f, 0.012272f, 0.006136f +}; + +ALWAYS_INLINE static float get_sin(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return fft_sin_table[k << (9 - N_pow2)]; +} + +ALWAYS_INLINE static float get_ar(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (1 - get_sin(k, N_pow2)); +} + +ALWAYS_INLINE static float get_br(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (1 + get_sin(k, N_pow2)); +} + +ALWAYS_INLINE static float get_a_star_r(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (1 - get_sin(k, N_pow2)); +} + +ALWAYS_INLINE static float get_b_star_r(int k, int N_pow2) // N=512 -> N=pow2=9 +{ + return 0.5 * (1 + get_sin(k, N_pow2)); +} + +/////////////////////////////////////////////////////////////////////////////// + +// You give the FFT N real and imaginary pairs where each pair is an even/odd +// real value from 2N data. The FFT will then output N real and imaginary pairs +// and you can use the below function to unpack that into 2N real and imaginary +// pairs the FFT would normally output with 2N data. + +// Unpack 2N data from N point fft +// in = N real and complex floats +// out = 2N real and complex floats +static void unpack_fft(float *in, float *out, int N_pow2) +{ + for (int k = 0, l = 2 << N_pow2, m = l << 1; k < l; k += 2) { + int k_r = k+0; + int k_i = k+1; + int N_k_r = ((!k)?0:(l-k))+0; + int N_k_i = ((!k)?0:(l-k))+1; + int N2_K_r = ((!k)?0:(m-k))+0; + int N2_K_i = ((!k)?0:(m-k))+1; + int k_2 = k >> 1; + // real + out[k_r] = (in[k_r] * get_ar(k_2, N_pow2)) - + (in[k_i] * get_ai(k_2, N_pow2)) + + (in[N_k_r] * get_br(k_2, N_pow2)) + + (in[N_k_i] * get_bi(k_2, N_pow2)); + // imaginary + out[k_i] = (in[k_i] * get_ar(k_2, N_pow2)) + + (in[k_r] * get_ai(k_2, N_pow2)) + + (in[N_k_r] * get_bi(k_2, N_pow2)) - + (in[N_k_i] * get_br(k_2, N_pow2)); + if (k > 0) { + // real conj + out[N2_K_r] = out[k_r]; + // imaginary conj + out[N2_K_i] = -out[k_i]; + } + } + out[(2 << N_pow2)+0] = in[0+0] - in[0+1]; + out[(2 << N_pow2)+1] = 0; +} + +// The IFFT takes N real and imaginary pairs to generate N real and imaginary +// outputs with the imaginary part set to zero. To be more efficent this function +// packs 2N data into an N IFFT so that the N real and imaginary outputs have +// even/odd real values. + +// Pack 2N data to N point fft +// in = 2N real and complex floats +// out = N real and complex floats +static void pack_fft(float *in, float *out, int N_pow2) +{ + for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { + int k_r = k+0; + int k_i = k+1; + int N_k_r = (l-k)+0; + int N_k_i = (l-k)+1; + int k_2 = k >> 1; + // real + out[k_r] = (in[k_r] * get_a_star_r(k_2, N_pow2)) - + (in[k_i] * get_a_star_i(k_2, N_pow2)) + + (in[N_k_r] * get_b_star_r(k_2, N_pow2)) + + (in[N_k_i] * get_b_star_i(k_2, N_pow2)); + // imaginary + out[k_i] = (in[k_i] * get_a_star_r(k_2, N_pow2)) + + (in[k_r] * get_a_star_i(k_2, N_pow2)) + + (in[N_k_r] * get_b_star_i(k_2, N_pow2)) - + (in[N_k_i] * get_b_star_r(k_2, N_pow2)); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +ALWAYS_INLINE static int int_flog2(int x) // floor log 2 +{ + return 31 - __builtin_clz(x); +} + +ALWAYS_INLINE static int int_clog2(int x) // ceiling log 2 +{ + int y = int_flog2(x); + return (x - (1 << y)) ? (y + 1) : y; +} + +/////////////////////////////////////////////////////////////////////////////// + +// Input even numbered index +// Output even numbered index + +static inline uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + + int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ + return(result); +} + + +ALWAYS_INLINE static int bit_reverse(int index, int N_pow2) +{ + return __RBIT(index) >> (30 - N_pow2); +} + +ALWAYS_INLINE static void swap(float *a, float *b) +{ + float tmp = *b; + *b = *a; + *a = tmp; +} + +//ALWAYS_INLINE static float get_hann(int k, int N_pow2) +//{ +// if (k < (1 << N_pow2)) { +// return get_hann_l_side(k, N_pow2); +// } else { +// return get_hann_r_side(k, N_pow2); +// } +//} + +// Copies 2N real pairs (or pad with zero) from in to out while bit reversing +// their indexes. + +static void prepare_real_input(uint8_t *in, int in_len, float *out, int N_pow2) +{ + for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { + int m = bit_reverse(k, N_pow2); + out[m+0] = ((k+0) < in_len) ? in[k+0] : 0; + out[m+1] = ((k+1) < in_len) ? in[k+1] : 0; +// // Apply Hann Window (this is working on real numbers) +// out[m+0] *= get_hann(k+0, N_pow2); +// out[m+1] *= get_hann(k+1, N_pow2); + } +} + +static void prepare_real_input_again(float *in, int in_len, float *out, int N_pow2) +{ + for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { + int m = bit_reverse(k, N_pow2); + out[m+0] = ((k+0) < in_len) ? in[(k*2)+0] : 0; + out[m+1] = ((k+1) < in_len) ? in[(k*2)+2] : 0; +// // Apply Hann Window (this is working on real numbers) +// out[m+0] *= get_hann(k+0, N_pow2); +// out[m+1] *= get_hann(k+1, N_pow2); + } +} + +//// This works on complex numbers... +//static void apply_hann_window(float *inout, int N_pow2, int stride) +//{ +// for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { +// inout[(k*stride)+0] *= get_hann(k>>1, N_pow2-1); +// inout[(k*stride)+1] *= get_hann(k>>1, N_pow2-1); +// } +//} + +// Copies N complex pairs from in to out while bit reversing their indexes. The +// in and out arrays may be the same. + +static void prepare_complex_input(float *in, float *out, int N_pow2, int stride) +{ + if(in == out) { + for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { + int m = bit_reverse(k, N_pow2); + if (k < m) { + swap(out+(m*stride)+0, in+(k*stride)+0); + swap(out+(m*stride)+1, in+(k*stride)+1); + } + } + } else { + for (int k = 0, l = 2 << N_pow2; k < l; k += 2) { + int m = bit_reverse(k, N_pow2); + out[(m*stride)+0] = in[(k*stride)+0]; + out[(m*stride)+1] = in[(k*stride)+1]; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// Performs the fft in place. +static void do_fft(float *inout, int N_pow2, int stride) +{ + int N = 2 << N_pow2; + for (int N_pow2_i = 1; N_pow2_i <= N_pow2; N_pow2_i++) { + int N_mul2 = 2 << N_pow2_i; + int N_div2 = 1 << N_pow2_i; + for (int i = 0; i < N; i += N_mul2) { + for (int j = i, k = 0, l = i + N_div2, m = N >> N_pow2_i; j < l; j += 2, k += m) { + int x0_r = (j*stride)+0; + int x0_i = (j*stride)+1; + int x1_r = ((j+N_div2)*stride)+0; + int x1_i = ((j+N_div2)*stride)+1; + float tmp_r = (inout[x1_r] * get_cos(k, N_pow2)) + + (inout[x1_i] * get_sin(k, N_pow2)); + float tmp_i = (inout[x1_i] * get_cos(k, N_pow2)) - + (inout[x1_r] * get_sin(k, N_pow2)); + inout[x1_r] = inout[x0_r] - tmp_r; + inout[x1_i] = inout[x0_i] - tmp_i; + inout[x0_r] += tmp_r; + inout[x0_i] += tmp_i; + } + } + } +} + +// Performs the ifft in place. +static void do_ifft(float *inout, int N_pow2, int stride) +{ + int N = 2 << N_pow2; + for (int N_pow2_i = 1; N_pow2_i <= N_pow2; N_pow2_i++) { + int N_mul2 = 2 << N_pow2_i; + int N_div2 = 1 << N_pow2_i; + for (int i = 0; i < N; i += N_mul2) { + for (int j = i, k = 0, l = i + N_div2, m = N >> N_pow2_i; j < l; j += 2, k += m) { + int x0_r = (j*stride)+0; + int x0_i = (j*stride)+1; + int x1_r = ((j+N_div2)*stride)+0; + int x1_i = ((j+N_div2)*stride)+1; + float tmp_r = (inout[x1_r] * get_cos(k, N_pow2)) - + (inout[x1_i] * get_sin(k, N_pow2)); + float tmp_i = (inout[x1_i] * get_cos(k, N_pow2)) + + (inout[x1_r] * get_sin(k, N_pow2)); + inout[x1_r] = inout[x0_r] - tmp_r; + inout[x1_i] = inout[x0_i] - tmp_i; + inout[x0_r] += tmp_r; + inout[x0_i] += tmp_i; + } + } + } + + float div = 1.0 / (N >> 1); + for (int i = 0; i < N; i += 2) { + inout[(i*stride)+0] *= div; + inout[(i*stride)+1] *= div; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void fft1d_alloc(fft1d_controller_t *controller, uint8_t *buf, int len) +{ + controller->d_pointer = buf; + controller->d_len = len; + controller->pow2 = int_clog2(len); + controller->data = fb_alloc((2 << controller->pow2) * sizeof(float)); +} + +void fft1d_dealloc() +{ + fb_free(); +} + +void fft1d_run(fft1d_controller_t *controller) +{ + // We can speed up the FFT by packing data into both the real and imaginary + // values. This results in having to do an FFT of half the size normally. + + float *h_buffer = fb_alloc((1 << controller->pow2) * sizeof(float)); + prepare_real_input(controller->d_pointer, controller->d_len, + h_buffer, controller->pow2 - 1); + do_fft(h_buffer, controller->pow2 - 1, 1); + unpack_fft(h_buffer, controller->data, controller->pow2 - 1); + fb_free(); +} + +void ifft1d_run(fft1d_controller_t *controller) +{ + // We can speed up the FFT by packing data into both the real and imaginary + // values. This results in having to do an FFT of half the size normally. + + float *h_buffer = fb_alloc((1 << controller->pow2) * sizeof(float)); + pack_fft(controller->data, h_buffer, controller->pow2 - 1); + prepare_complex_input(h_buffer, h_buffer, + controller->pow2 - 1, 1); + do_ifft(h_buffer, controller->pow2 - 1, 1); + memset(controller->data, 0, (2 << controller->pow2) * sizeof(float)); + memcpy(controller->data, h_buffer, (1 << controller->pow2) * sizeof(float)); + fb_free(); +} + +void fft1d_mag(fft1d_controller_t *controller) +{ + for (int i = 0, j = 2 << controller->pow2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_sqrtf((tmp_r*tmp_r)+(tmp_i*tmp_i)); + controller->data[i + 1] = 0; + } +} + +void fft1d_phase(fft1d_controller_t *controller) +{ + for (int i = 0, j = 2 << controller->pow2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = tmp_r ? fast_atan2f(tmp_i, tmp_r) : ((tmp_i < 0) ? (M_PI*1.5) : (M_PI*0.5)); + controller->data[i + 1] = 0; + } +} + +void fft1d_log(fft1d_controller_t *controller) +{ + for (int i = 0, j = 2 << controller->pow2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_log(fast_sqrtf((tmp_r*tmp_r)+(tmp_i*tmp_i))); + controller->data[i + 1] = tmp_r ? fast_atan2f(tmp_i, tmp_r) : ((tmp_i < 0) ? (M_PI*1.5) : (M_PI*0.5)); + } +} + +void fft1d_exp(fft1d_controller_t *controller) +{ + for (int i = 0, j = 2 << controller->pow2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_expf(tmp_r) * cosf(tmp_i); + controller->data[i + 1] = fast_expf(tmp_r) * sinf(tmp_i); + } +} + +void fft1d_swap(fft1d_controller_t *controller) +{ + for (int i = 0, j = ((1 << controller->pow2) / 2) * 2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = controller->data[j + i + 0]; + controller->data[i + 1] = controller->data[j + i + 1]; + controller->data[j + i + 0] = tmp_r; + controller->data[j + i + 1] = tmp_i; + } +} + +void fft1d_run_again(fft1d_controller_t *controller) +{ + // We can speed up the FFT by packing data into both the real and imaginary + // values. This results in having to do an FFT of half the size normally. + + float *h_buffer = fb_alloc((1 << controller->pow2) * sizeof(float)); + prepare_real_input_again(controller->data, 1 << controller->pow2, + h_buffer, controller->pow2 - 1); + do_fft(h_buffer, controller->pow2 - 1, 1); + unpack_fft(h_buffer, controller->data, controller->pow2 - 1); + fb_free(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void fft2d_alloc(fft2d_controller_t *controller, image_t *img, rectangle_t *r) +{ + controller->img = img; + if (!rectangle_subimg(controller->img, r, &controller->r)) ff_no_intersection(NULL); + + controller->w_pow2 = int_clog2(controller->r.w); + controller->h_pow2 = int_clog2(controller->r.h); + + controller->data = + fb_alloc0(2 * (1 << controller->w_pow2) * (1 << controller->h_pow2) * sizeof(float)); +} + +void fft2d_dealloc() +{ + fb_free(); +} + +// RGB565 to YUV conversion +extern const int8_t yuv_table[196608]; + +void fft2d_run(fft2d_controller_t *controller) +{ + // This section copies image data into the fft buffer. It takes care of + // extracting the grey channel from RGB images if necessary. The code + // also handles dealing with a rect less than the image size. + for (int i = 0; i < controller->r.h; i++) { + // Get image data into buffer. + uint8_t *tmp = fb_alloc(controller->r.w * sizeof(uint8_t)); + for (int j = 0; j < controller->r.w; j++) { + if (IM_IS_GS(controller->img)) { + tmp[j] = IM_GET_GS_PIXEL(controller->img, + controller->r.x + j, controller->r.y + i); + } else { + tmp[j] = yuv_table[IM_GET_RGB565_PIXEL(controller->img, + controller->r.x + j, controller->r.y + i)*3]; + } + } + // Do FFT on image data and copy to main buffer. + fft1d_controller_t fft1d_controller_i; + fft1d_alloc(&fft1d_controller_i, tmp, controller->r.w); + fft1d_run(&fft1d_controller_i); + memcpy(controller->data + (i * (2 << controller->w_pow2)), + fft1d_controller_i.data, (2 << fft1d_controller_i.pow2) * sizeof(float)); + fft1d_dealloc(); + // Free image data buffer. + fb_free(); + } + + // The above operates on the rows and this fft operates on the columns. To + // avoid having to transpose the array the fft takes a stride input. + for (int i = 0, ii = 2 << controller->w_pow2; i < ii; i += 2) { + float *p = controller->data + i; +// apply_hann_window(p, controller->h_pow2, (1 << controller->w_pow2)); + prepare_complex_input(p, p, controller->h_pow2, (1 << controller->w_pow2)); + do_fft(p, controller->h_pow2, (1 << controller->w_pow2)); + } +} + +void ifft2d_run(fft2d_controller_t *controller) +{ + // Do columns... + for (int i = 0, ii = 2 << controller->w_pow2; i < ii; i += 2) { + float *p = controller->data + i; + prepare_complex_input(p, p, controller->h_pow2, (1 << controller->w_pow2)); + do_ifft(p, controller->h_pow2, (1 << controller->w_pow2)); + } + + // Do rows... + for (int i = 0, ii = 1 << controller->h_pow2; i < ii; i++) { + fft1d_controller_t fft1d_controller_i; + fft1d_controller_i.pow2 = controller->w_pow2; + fft1d_controller_i.data = controller->data + (i * (2 << controller->w_pow2)); + ifft1d_run(&fft1d_controller_i); + } +} + +void fft2d_mag(fft2d_controller_t *controller) +{ + for (int i = 0, j = (1 << controller->h_pow2) * (1 << controller->w_pow2) * 2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_sqrtf((tmp_r*tmp_r)+(tmp_i*tmp_i)); + controller->data[i + 1] = 0; + } +} + +void fft2d_phase(fft2d_controller_t *controller) +{ + for (int i = 0, j = (1 << controller->h_pow2) * (1 << controller->w_pow2) * 2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = tmp_r ? fast_atan2f(tmp_i, tmp_r) : ((tmp_i < 0) ? (M_PI*1.5) : (M_PI*0.5)); + controller->data[i + 1] = 0; + } +} + +void fft2d_log(fft2d_controller_t *controller) +{ + for (int i = 0, j = (1 << controller->h_pow2) * (1 << controller->w_pow2) * 2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_log(fast_sqrtf((tmp_r*tmp_r)+(tmp_i*tmp_i))); + controller->data[i + 1] = tmp_r ? fast_atan2f(tmp_i, tmp_r) : ((tmp_i < 0) ? (M_PI*1.5) : (M_PI*0.5)); + } +} + +void fft2d_exp(fft2d_controller_t *controller) +{ + for (int i = 0, j = (1 << controller->h_pow2) * (1 << controller->w_pow2) * 2; i < j; i += 2) { + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = fast_expf(tmp_r) * cosf(tmp_i); + controller->data[i + 1] = fast_expf(tmp_r) * sinf(tmp_i); + } +} + +void fft2d_swap(fft2d_controller_t *controller) +{ + // Do rows... + for (int i = 0, ii = 1 << controller->h_pow2; i < ii; i++) { + fft1d_controller_t fft1d_controller_i; + fft1d_controller_i.pow2 = controller->w_pow2; + fft1d_controller_i.data = controller->data + (i * (2 << controller->w_pow2)); + fft1d_swap(&fft1d_controller_i); + } + + // Do columns... + for (int x = 0, xx = 2 << controller->w_pow2; x < xx; x += 2) { + for (int y = 0, yy = (1 << controller->h_pow2) / 2; y < yy; y++) { + int i = (y * (2 << controller->w_pow2)) + x; + int j = yy * (2 << controller->w_pow2); + float tmp_r = controller->data[i + 0]; + float tmp_i = controller->data[i + 1]; + controller->data[i + 0] = controller->data[j + i + 0]; + controller->data[i + 1] = controller->data[j + i + 1]; + controller->data[j + i + 0] = tmp_r; + controller->data[j + i + 1] = tmp_i; + } + } +} + +void fft2d_linpolar(fft2d_controller_t *controller) +{ + int w = 1 << controller->w_pow2; + int h = 1 << controller->h_pow2; + int s = h * w * 2 * sizeof(float); + float *tmp = fb_alloc(s); + memcpy(tmp, controller->data, s); + memset(controller->data, 0, s); + + float w_2 = w / 2.0f; + float h_2 = h / 2.0f; + float rho_scale = fast_sqrtf((w_2 * w_2) + (h_2 * h_2)) / h; + float theta_scale = 360.0f / w; + + for (int y = 0; y < h; y++) { + float *row_ptr = controller->data + (y * w * 2); + float rho = y * rho_scale; + for (int x = 0; x < w; x++) { + int sourceX, sourceY; + int theta = 630 - fast_roundf(x * theta_scale); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf((rho * cos_table[theta]) + w_2); + sourceY = fast_roundf((rho * sin_table[theta]) + h_2); + if ((0 <= sourceX) && (sourceX < w) && (0 <= sourceY) && (sourceY < h)) { + float *ptr = tmp + (sourceY * w * 2); + row_ptr[(x * 2) + 0] = ptr[(sourceX * 2) + 0]; + row_ptr[(x * 2) + 1] = ptr[(sourceX * 2) + 1]; + } + } + } + + fb_free(); +} + +void fft2d_logpolar(fft2d_controller_t *controller) +{ + int w = 1 << controller->w_pow2; + int h = 1 << controller->h_pow2; + int s = h * w * 2 * sizeof(float); + float *tmp = fb_alloc(s); + memcpy(tmp, controller->data, s); + memset(controller->data, 0, s); + + float w_2 = w / 2.0f; + float h_2 = h / 2.0f; + float rho_scale = fast_log(fast_sqrtf((w_2 * w_2) + (h_2 * h_2))) / h; + float theta_scale = 360.0f / w; + + for (int y = 0; y < h; y++) { + float *row_ptr = controller->data + (y * w * 2); + float rho = y * rho_scale; + for (int x = 0; x < w; x++) { + int sourceX, sourceY; + int theta = 630 - fast_roundf(x * theta_scale); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf((fast_expf(rho) * cos_table[theta]) + w_2); + sourceY = fast_roundf((fast_expf(rho) * sin_table[theta]) + h_2); + if ((0 <= sourceX) && (sourceX < w) && (0 <= sourceY) && (sourceY < h)) { + float *ptr = tmp + (sourceY * w * 2); + row_ptr[(x * 2) + 0] = ptr[(sourceX * 2) + 0]; + row_ptr[(x * 2) + 1] = ptr[(sourceX * 2) + 1]; + } + } + } + + fb_free(); +} + +void fft2d_run_again(fft2d_controller_t *controller) +{ + for (int i = 0, ii = 1 << controller->h_pow2; i < ii; i++) { + fft1d_controller_t fft1d_controller_i; + fft1d_controller_i.pow2 = controller->w_pow2; + fft1d_controller_i.data = controller->data + (i * (2 << controller->w_pow2)); + fft1d_run_again(&fft1d_controller_i); + } + + // The above operates on the rows and this fft operates on the columns. To + // avoid having to transpose the array the fft takes a stride input. + for (int i = 0, ii = 2 << controller->w_pow2; i < ii; i += 2) { + float *p = controller->data + i; +// apply_hann_window(p, controller->h_pow2, (1 << controller->w_pow2)); + prepare_complex_input(p, p, controller->h_pow2, (1 << controller->w_pow2)); + do_fft(p, controller->h_pow2, (1 << controller->w_pow2)); + } +} diff --git a/src/openmv/src/omv/img/fft.h b/src/openmv/src/omv/img/fft.h new file mode 100755 index 0000000..e67210d --- /dev/null +++ b/src/openmv/src/omv/img/fft.h @@ -0,0 +1,48 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * FFT LIB - can do 1024 point real FFTs and 512 point complex FFTs + * + */ +#ifndef __FFT_H__ +#define __FFT_H__ +#include +#include "imlib.h" +typedef struct fft1d_controller { + uint8_t *d_pointer; + int d_len; + int pow2; + float *data; +} fft1d_controller_t; +void fft1d_alloc(fft1d_controller_t *controller, uint8_t *buf, int len); +void fft1d_dealloc(); +void fft1d_run(fft1d_controller_t *controller); +void ifft1d_run(fft1d_controller_t *controller); +void fft1d_mag(fft1d_controller_t *controller); +void fft1d_phase(fft1d_controller_t *controller); +void fft1d_log(fft1d_controller_t *controller); +void fft1d_exp(fft1d_controller_t *controller); +void fft1d_swap(fft1d_controller_t *controller); // a.k.a MATLAB fftshift +void fft1d_run_again(fft1d_controller_t *controller); // Do FFT again on real mag/phase of the FFT. +typedef struct fft2d_controller { + image_t *img; + rectangle_t r; + int w_pow2, h_pow2; + float *data; +} fft2d_controller_t; +void fft2d_alloc(fft2d_controller_t *controller, image_t *img, rectangle_t *r); +void fft2d_dealloc(); +void fft2d_run(fft2d_controller_t *controller); +void ifft2d_run(fft2d_controller_t *controller); +void fft2d_mag(fft2d_controller_t *controller); +void fft2d_phase(fft2d_controller_t *controller); +void fft2d_log(fft2d_controller_t *controller); +void fft2d_exp(fft2d_controller_t *controller); +void fft2d_swap(fft2d_controller_t *controller); // a.k.a MATLAB fftshift +void fft2d_linpolar(fft2d_controller_t *controller); +void fft2d_logpolar(fft2d_controller_t *controller); +void fft2d_run_again(fft2d_controller_t *controller); // Do FFT again on real mag/phase of the FFT. +// END +#endif /* __FFT_H__ */ diff --git a/src/openmv/src/omv/img/filter.c b/src/openmv/src/omv/img/filter.c new file mode 100755 index 0000000..b5b2e30 --- /dev/null +++ b/src/openmv/src/omv/img/filter.c @@ -0,0 +1,1595 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "fsort.h" +#include "imlib.h" + +void imlib_histeq(image_t *img, image_t *mask) +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + int a = img->w * img->h; + float s = (COLOR_BINARY_MAX - COLOR_BINARY_MIN) / ((float) a); + uint32_t *hist = fb_alloc0((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(uint32_t)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + hist[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) - COLOR_BINARY_MIN] += 1; + } + } + + for (int i = 0, sum = 0, ii = COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1; i < ii; i++) { + sum += hist[i]; + hist[i] = sum; + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, + fast_roundf((s * hist[pixel - COLOR_BINARY_MIN]) + COLOR_BINARY_MIN)); + } + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + int a = img->w * img->h; + float s = (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / ((float) a); + uint32_t *hist = fb_alloc0((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(uint32_t)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + hist[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x) - COLOR_GRAYSCALE_MIN] += 1; + } + } + + for (int i = 0, sum = 0, ii = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1; i < ii; i++) { + sum += hist[i]; + hist[i] = sum; + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, + fast_roundf((s * hist[pixel - COLOR_GRAYSCALE_MIN]) + COLOR_GRAYSCALE_MIN)); + } + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + int a = img->w * img->h; + float s = (COLOR_Y_MAX - COLOR_Y_MIN) / ((float) a); + uint32_t *hist = fb_alloc0((COLOR_Y_MAX - COLOR_Y_MIN + 1) * sizeof(uint32_t)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + hist[COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) - COLOR_Y_MIN] += 1; + } + } + + for (int i = 0, sum = 0, ii = COLOR_Y_MAX - COLOR_Y_MIN + 1; i < ii; i++) { + sum += hist[i]; + hist[i] = sum; + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) continue; + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, + imlib_yuv_to_rgb(fast_roundf(s * hist[COLOR_RGB565_TO_Y(pixel) - COLOR_Y_MIN]), + COLOR_RGB565_TO_U(pixel), + COLOR_RGB565_TO_V(pixel))); + } + } + + fb_free(); + break; + } + default: { + break; + } + } +} + +// ksize == 0 -> 1x1 kernel +// ksize == 1 -> 3x3 kernel +// ... +// ksize == n -> ((n*2)+1)x((n*2)+1) kernel + +#ifdef IMLIB_ENABLE_MEAN +void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + float over_n = 1.0f / (((ksize*2)+1)*((ksize*2)+1)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + int pixel = fast_roundf(acc * over_n); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + int pixel = fast_roundf(acc * over_n); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int r_acc = 0, g_acc = 0, b_acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + r_acc += COLOR_RGB565_TO_R5(pixel); + g_acc += COLOR_RGB565_TO_G6(pixel); + b_acc += COLOR_RGB565_TO_B5(pixel); + } + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(r_acc * over_n), + fast_roundf(g_acc * over_n), + fast_roundf(b_acc * over_n)); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + default: { + break; + } + } +} +#endif // IMLIB_ENABLE_MEAN + +#ifdef IMLIB_ENABLE_MEDIAN +void imlib_median_filter(image_t *img, const int ksize, float percentile, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + int n = ((ksize*2)+1)*((ksize*2)+1), int_percentile = fast_roundf(percentile * (n - 1)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + int *data = fb_alloc(n*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int *data_ptr = data; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + *data_ptr++ = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + fsort(data, n); + + int pixel = data[int_percentile]; + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + int *data = fb_alloc(n*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int *data_ptr = data; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + *data_ptr++ = IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + fsort(data, n); + + int pixel = data[int_percentile]; + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + int *r_data = fb_alloc(n*sizeof(int)); + int *g_data = fb_alloc(n*sizeof(int)); + int *b_data = fb_alloc(n*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int *r_data_ptr = r_data, *g_data_ptr = g_data, *b_data_ptr = b_data; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + *r_data_ptr++ = COLOR_RGB565_TO_R5(pixel); + *g_data_ptr++ = COLOR_RGB565_TO_G6(pixel); + *b_data_ptr++ = COLOR_RGB565_TO_B5(pixel); + } + } + + fsort(r_data, n); + fsort(g_data, n); + fsort(b_data, n); + + int pixel = COLOR_R5_G6_B5_TO_RGB565(r_data[int_percentile], + g_data[int_percentile], + b_data[int_percentile]); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + fb_free(); + fb_free(); + break; + } + default: { + break; + } + } +} +#endif // IMLIB_ENABLE_MEDIAN + +#ifdef IMLIB_ENABLE_MODE +void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + int *bins = fb_alloc((COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + memset(bins, 0, (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)*sizeof(int)); + + int mcount = 0, mode = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + bins[pixel]++; + + if (bins[pixel] > mcount) { + mcount = bins[pixel]; + mode = pixel; + } + } + } + + int pixel = mode; + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + int *bins = fb_alloc((COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + memset(bins, 0, (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)*sizeof(int)); + + int mcount = 0, mode = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + bins[pixel]++; + + if (bins[pixel] > mcount) { + mcount = bins[pixel]; + mode = pixel; + } + } + } + + int pixel = mode; + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + int *r_bins = fb_alloc((COLOR_R5_MAX-COLOR_R5_MIN+1)*sizeof(int)); + int *g_bins = fb_alloc((COLOR_G6_MAX-COLOR_G6_MIN+1)*sizeof(int)); + int *b_bins = fb_alloc((COLOR_B5_MAX-COLOR_B5_MIN+1)*sizeof(int)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + memset(r_bins, 0, (COLOR_R5_MAX-COLOR_R5_MIN+1)*sizeof(int)); + memset(g_bins, 0, (COLOR_G6_MAX-COLOR_G6_MIN+1)*sizeof(int)); + memset(b_bins, 0, (COLOR_B5_MAX-COLOR_B5_MIN+1)*sizeof(int)); + + int r_mcount = 0, r_mode = 0; + int g_mcount = 0, g_mode = 0; + int b_mcount = 0, b_mode = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + int r_pixel = COLOR_RGB565_TO_R5(pixel); + int g_pixel = COLOR_RGB565_TO_G6(pixel); + int b_pixel = COLOR_RGB565_TO_B5(pixel); + r_bins[r_pixel]++; + g_bins[g_pixel]++; + b_bins[b_pixel]++; + + if (r_bins[r_pixel] > r_mcount) { + r_mcount = r_bins[r_pixel]; + r_mode = r_pixel; + } + + if (g_bins[g_pixel] > g_mcount) { + g_mcount = g_bins[g_pixel]; + g_mode = g_pixel; + } + + if (b_bins[b_pixel] > b_mcount) { + b_mcount = b_bins[b_pixel]; + b_mode = b_pixel; + } + } + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(r_mode, g_mode, b_mode); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + fb_free(); + fb_free(); + break; + } + default: { + break; + } + } +} +#endif // IMLIB_ENABLE_MODE + +#ifdef IMLIB_ENABLE_MIDPOINT +void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + float max_bias = bias, min_bias = 1.0f - bias; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int min = COLOR_BINARY_MAX, max = COLOR_BINARY_MIN; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + min = IM_MIN(min, pixel); + max = IM_MAX(max, pixel); + } + } + + int pixel = fast_roundf((min*min_bias)+(max*max_bias)); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int min = COLOR_GRAYSCALE_MAX, max = COLOR_GRAYSCALE_MIN; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + min = IM_MIN(min, pixel); + max = IM_MAX(max, pixel); + } + } + + int pixel = fast_roundf((min*min_bias)+(max*max_bias)); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int r_min = COLOR_R5_MAX, r_max = COLOR_R5_MIN; + int g_min = COLOR_G6_MAX, g_max = COLOR_G6_MIN; + int b_min = COLOR_B5_MAX, b_max = COLOR_B5_MIN; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + int r_pixel = COLOR_RGB565_TO_R5(pixel); + int g_pixel = COLOR_RGB565_TO_G6(pixel); + int b_pixel = COLOR_RGB565_TO_B5(pixel); + r_min = IM_MIN(r_min, r_pixel); + r_max = IM_MAX(r_max, r_pixel); + g_min = IM_MIN(g_min, g_pixel); + g_max = IM_MAX(g_max, g_pixel); + b_min = IM_MIN(b_min, b_pixel); + b_max = IM_MAX(b_max, b_pixel); + } + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf((r_min*min_bias)+(r_max*max_bias)), + fast_roundf((g_min*min_bias)+(g_max*max_bias)), + fast_roundf((b_min*min_bias)+(b_max*max_bias))); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + default: { + break; + } + } +} +#endif // IMLIB_ENABLE_MIDPOINT + +// http://www.fmwconcepts.com/imagemagick/digital_image_filtering.pdf + +void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, const int b, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int acc = 0, ptr = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += krn[ptr++] * IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + int pixel = IM_MAX(IM_MIN(fast_roundf(acc * m) + b, COLOR_BINARY_MAX), COLOR_BINARY_MIN); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int acc = 0, ptr = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + acc += krn[ptr++] * IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + } + } + + int pixel = IM_MAX(IM_MIN(fast_roundf(acc * m) + b, COLOR_GRAYSCALE_MAX), COLOR_GRAYSCALE_MIN); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int r_acc = 0, g_acc = 0, b_acc = 0, ptr = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + r_acc += krn[ptr] * COLOR_RGB565_TO_R5(pixel); + g_acc += krn[ptr] * COLOR_RGB565_TO_G6(pixel); + b_acc += krn[ptr++] * COLOR_RGB565_TO_B5(pixel); + } + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(IM_MAX(IM_MIN(fast_roundf(r_acc * m) + b, COLOR_R5_MAX), COLOR_R5_MIN), + IM_MAX(IM_MIN(fast_roundf(g_acc * m) + b, COLOR_G6_MAX), COLOR_G6_MIN), + IM_MAX(IM_MIN(fast_roundf(b_acc * m) + b, COLOR_B5_MAX), COLOR_B5_MIN)); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + break; + } + default: { + break; + } + } +} + +#ifdef IMLIB_ENABLE_BILATERAL +static float gaussian(float x, float sigma) +{ + return fast_expf((x * x) / (-2.0f * sigma * sigma)) / (fabsf(sigma) * 2.506628f); // sqrt(2 * PI) +} + +static float distance(int x, int y) +{ + return fast_sqrtf((x * x) + (y * y)); +} + +void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, float space_sigma, bool threshold, int offset, bool invert, image_t *mask) +{ + int brows = ksize + 1; + image_t buf; + buf.w = img->w; + buf.h = brows; + buf.bpp = img->bpp; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows); + float *gi_lut = fb_alloc((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(float)); + + float max_color = IM_DIV(1.0f, COLOR_BINARY_MAX - COLOR_BINARY_MIN); + for (int i = COLOR_BINARY_MIN; i <= COLOR_BINARY_MAX; i++) { + gi_lut[i] = gaussian(i * max_color, color_sigma); + } + + int n = (ksize * 2) + 1; + float *gs_lut = fb_alloc(n * n * sizeof(float)); + + float max_space = IM_DIV(1.0f, distance(ksize, ksize)); + for (int y = -ksize; y <= ksize; y++) { + for (int x = -ksize; x <= ksize; x++) { + gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y) * max_space, space_sigma); + } + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int this_pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); + float i_acc = 0, w_acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + float w = gi_lut[abs(this_pixel - pixel)] * gs_lut[(n * (j + ksize)) + (k + ksize)]; + i_acc += pixel * w; + w_acc += w; + } + } + + int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_BINARY_MAX)); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_BINARY_MAX; + } else { + pixel = COLOR_BINARY_MIN; + } + } + + IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_BINARY_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows); + float *gi_lut = fb_alloc((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(float)); + + float max_color = IM_DIV(1.0f, COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN); + for (int i = COLOR_GRAYSCALE_MIN; i <= COLOR_GRAYSCALE_MAX; i++) { + gi_lut[i] = gaussian(i * max_color, color_sigma); + } + + int n = (ksize * 2) + 1; + float *gs_lut = fb_alloc(n * n * sizeof(float)); + + float max_space = IM_DIV(1.0f, distance(ksize, ksize)); + for (int y = -ksize; y <= ksize; y++) { + for (int x = -ksize; x <= ksize; x++) { + gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y) * max_space, space_sigma); + } + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int this_pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + float i_acc = 0, w_acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + float w = gi_lut[abs(this_pixel - pixel)] * gs_lut[(n * (j + ksize)) + (k + ksize)]; + i_acc += pixel * w; + w_acc += w; + } + } + + int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_GRAYSCALE_MAX)); + + if (threshold) { + if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { + pixel = COLOR_GRAYSCALE_BINARY_MAX; + } else { + pixel = COLOR_GRAYSCALE_BINARY_MIN; + } + } + + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows); + float *r_gi_lut = fb_alloc((COLOR_R5_MAX - COLOR_R5_MIN + 1) * sizeof(float)); + float *g_gi_lut = fb_alloc((COLOR_G6_MAX - COLOR_G6_MIN + 1) * sizeof(float)); + float *b_gi_lut = fb_alloc((COLOR_B5_MAX - COLOR_B5_MIN + 1) * sizeof(float)); + + float r_max_color = IM_DIV(1.0f, COLOR_R5_MAX - COLOR_R5_MIN); + for (int i = COLOR_R5_MIN; i <= COLOR_R5_MAX; i++) { + r_gi_lut[i] = gaussian(i * r_max_color, color_sigma); + } + + float g_max_color = IM_DIV(1.0f, COLOR_G6_MAX - COLOR_G6_MIN); + for (int i = COLOR_G6_MIN; i <= COLOR_G6_MAX; i++) { + g_gi_lut[i] = gaussian(i * g_max_color, color_sigma); + } + + float b_max_color = IM_DIV(1.0f, COLOR_B5_MAX - COLOR_B5_MIN); + for (int i = COLOR_B5_MIN; i <= COLOR_B5_MAX; i++) { + b_gi_lut[i] = gaussian(i * b_max_color, color_sigma); + } + + int n = (ksize * 2) + 1; + float *gs_lut = fb_alloc(n * n * sizeof(float)); + + float max_space = IM_DIV(1.0f, distance(ksize, ksize)); + for (int y = -ksize; y <= ksize; y++) { + for (int x = -ksize; x <= ksize; x++) { + gs_lut[(n * (y + ksize)) + (x + ksize)] = gaussian(distance(x, y) * max_space, space_sigma); + } + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = img->w; x < xx; x++) { + if (mask && (!image_get_mask_pixel(mask, x, y))) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + } + + int this_pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + int r_this_pixel = COLOR_RGB565_TO_R5(this_pixel); + int g_this_pixel = COLOR_RGB565_TO_G6(this_pixel); + int b_this_pixel = COLOR_RGB565_TO_B5(this_pixel); + float r_i_acc = 0, r_w_acc = 0; + float g_i_acc = 0, g_w_acc = 0; + float b_i_acc = 0, b_w_acc = 0; + + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, + IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); + + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1))); + int r_pixel = COLOR_RGB565_TO_R5(pixel); + int g_pixel = COLOR_RGB565_TO_G6(pixel); + int b_pixel = COLOR_RGB565_TO_B5(pixel); + float gs = gs_lut[(n * (j + ksize)) + (k + ksize)]; + float r_w = r_gi_lut[abs(r_this_pixel - r_pixel)] * gs; + float g_w = g_gi_lut[abs(g_this_pixel - g_pixel)] * gs; + float b_w = b_gi_lut[abs(b_this_pixel - b_pixel)] * gs; + r_i_acc += r_pixel * r_w; + r_w_acc += r_w; + g_i_acc += g_pixel * g_w; + g_w_acc += g_w; + b_i_acc += b_pixel * b_w; + b_w_acc += b_w; + } + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(IM_MIN(IM_DIV(r_i_acc, r_w_acc), COLOR_R5_MAX)), + fast_roundf(IM_MIN(IM_DIV(g_i_acc, g_w_acc), COLOR_G6_MAX)), + fast_roundf(IM_MIN(IM_DIV(b_i_acc, b_w_acc), COLOR_B5_MAX))); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = img->h - ksize, yy = img->h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(img)); + } + + fb_free(); + fb_free(); + fb_free(); + fb_free(); + fb_free(); + break; + } + default: { + break; + } + } +} +#endif // IMLIB_ENABLE_BILATERAL + +#ifdef IMLIB_ENABLE_CARTOON +typedef struct imlib_cartoon_filter_mean_state { + int r_acc, g_acc, b_acc, pixels; +} imlib_cartoon_filter_mean_state_t; + +static void imlib_cartoon_filter_mean(image_t *img, int line, int l, int r, void *data) +{ + imlib_cartoon_filter_mean_state_t *state = (imlib_cartoon_filter_mean_state_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + state->g_acc += IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, i); + state->pixels += 1; + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + state->g_acc += IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, i); + state->pixels += 1; + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, i); + state->r_acc += COLOR_RGB565_TO_R5(pixel); + state->g_acc += COLOR_RGB565_TO_G6(pixel); + state->b_acc += COLOR_RGB565_TO_B5(pixel); + state->pixels += 1; + } + break; + } + default: { + break; + } + } +} + +typedef struct imlib_cartoon_filter_fill_state { + int mean; +} imlib_cartoon_filter_fill_state_t; + +static void imlib_cartoon_filter_fill(image_t *img, int line, int l, int r, void *data) +{ + imlib_cartoon_filter_fill_state_t *state = (imlib_cartoon_filter_fill_state_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, i, state->mean); + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, i, state->mean); + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = l; i <= r; i++) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, i, state->mean); + } + break; + } + default: { + break; + } + } +} + +void imlib_cartoon_filter(image_t *img, float seed_threshold, float floating_threshold, image_t *mask) +{ + image_t mean_image, fill_image; + + mean_image.w = img->w; + mean_image.h = img->h; + mean_image.bpp = IMAGE_BPP_BINARY; + mean_image.data = fb_alloc0(image_size(&mean_image)); + + fill_image.w = img->w; + fill_image.h = img->h; + fill_image.bpp = IMAGE_BPP_BINARY; + fill_image.data = fb_alloc0(image_size(&fill_image)); + + if (mask) { + for (int y = 0, yy = fill_image.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&fill_image, y); + for (int x = 0, xx = fill_image.w; x < xx; x++) { + if (image_get_mask_pixel(mask, x, y)) IMAGE_SET_BINARY_PIXEL_FAST(row_ptr, x); + } + } + } + + int color_seed_threshold = 0; + int color_floating_threshold = 0; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + color_seed_threshold = fast_roundf(seed_threshold * COLOR_BINARY_MAX); + color_floating_threshold = fast_roundf(floating_threshold * COLOR_BINARY_MAX); + break; + } + case IMAGE_BPP_GRAYSCALE: { + color_seed_threshold = fast_roundf(seed_threshold * COLOR_GRAYSCALE_MAX); + color_floating_threshold = fast_roundf(floating_threshold * COLOR_GRAYSCALE_MAX); + break; + } + case IMAGE_BPP_RGB565: { + color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(seed_threshold * COLOR_R5_MAX), + fast_roundf(seed_threshold * COLOR_G6_MAX), + fast_roundf(seed_threshold * COLOR_B5_MAX)); + color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(floating_threshold * COLOR_R5_MAX), + fast_roundf(floating_threshold * COLOR_G6_MAX), + fast_roundf(floating_threshold * COLOR_B5_MAX)); + break; + } + default: { + break; + } + } + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&mean_image, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (!IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) { + + imlib_cartoon_filter_mean_state_t mean_state; + memset(&mean_state, 0, sizeof(imlib_cartoon_filter_mean_state_t)); + imlib_flood_fill_int(&mean_image, img, x, y, color_seed_threshold, color_floating_threshold, + imlib_cartoon_filter_mean, &mean_state); + + imlib_cartoon_filter_fill_state_t fill_state; + memset(&fill_state, 0, sizeof(imlib_cartoon_filter_fill_state_t)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + fill_state.mean = mean_state.g_acc / mean_state.pixels; + break; + } + case IMAGE_BPP_GRAYSCALE: { + fill_state.mean = mean_state.g_acc / mean_state.pixels; + break; + } + case IMAGE_BPP_RGB565: { + fill_state.mean = COLOR_R5_G6_B5_TO_RGB565(mean_state.r_acc / mean_state.pixels, + mean_state.g_acc / mean_state.pixels, + mean_state.b_acc / mean_state.pixels); + break; + } + default: { + break; + } + } + + imlib_flood_fill_int(&fill_image, img, x, y, color_seed_threshold, color_floating_threshold, + imlib_cartoon_filter_fill, &fill_state); + } + } + } + + fb_free(); + fb_free(); +} +#endif // IMLIB_ENABLE_CARTOON diff --git a/src/openmv/src/omv/img/fmath.c b/src/openmv/src/omv/img/fmath.c new file mode 100755 index 0000000..c787e82 --- /dev/null +++ b/src/openmv/src/omv/img/fmath.c @@ -0,0 +1,201 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Fast approximate math functions. + * + */ +#include "fmath.h" +#include "common.h" + +#define M_PI 3.14159265f +#define M_PI_2 1.57079632f +#define M_PI_4 0.78539816f + +const float __atanf_lut[4] = { + -0.0443265554792128f, //p7 + -0.3258083974640975f, //p3 + +0.1555786518463281f, //p5 + +0.9997878412794807f //p1 +}; + +float ALWAYS_INLINE fast_sqrtf(float x) +{ +#if 0 + asm volatile ( + "vsqrt.f32 %[r], %[x]\n" + : [r] "=t" (x) + : [x] "t" (x)); +#endif + return x; +} + +int ALWAYS_INLINE fast_floorf(float x) +{ + int i = 0; +#if 0 + asm volatile ( + "vcvt.S32.f32 %[r], %[x]\n" + : [r] "=t" (i) + : [x] "t" (x)); +#endif + return i; +} + +int ALWAYS_INLINE fast_ceilf(float x) +{ + int i = 0; +#if 0 + x += 0.9999f; + asm volatile ( + "vcvt.S32.f32 %[r], %[x]\n" + : [r] "=t" (i) + : [x] "t" (x)); +#endif + return i; +} + +int ALWAYS_INLINE fast_roundf(float x) +{ + int i = 0; +#if 0 + asm volatile ( + "vcvtr.s32.f32 %[r], %[x]\n" + : [r] "=t" (i) + : [x] "t" (x)); +#endif + return i; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +typedef union{ + uint32_t l; + struct { + uint32_t m : 20; + uint32_t e : 11; + uint32_t s : 1; + }; +}exp_t; + +float fast_expf(float x) +{ + exp_t e; + e.l = (uint32_t)(1512775 * x + 1072632447); + // IEEE binary32 format + e.e = (e.e -1023 + 127) &0xFF; // rebase + + uint32_t packed = (e.s << 31) | (e.e << 23) | e.m <<3; + return *((float*)&packed); +} +#pragma GCC diagnostic pop + +/* + * From Hackers Delight: + * This is a very approximate but very fast version of acbrt. It is just eight + * integer instructions (shift rights and adds), plus instructions to load the constant. + * 1/3 is approximated as 1/4 + 1/16 + 1/64 + 1/256 + ... + 1/65536. + * The constant 0x2a511cd0 balances the relative error at +-0.0321. + */ +float fast_cbrtf(float x) +{ + union {int ix; float x;} v; + v.x = x; // x can be viewed as int. + v.ix = v.ix/4 + v.ix/16; // Approximate divide by 3. + v.ix = v.ix + v.ix/16; + v.ix = v.ix + v.ix/256; + v.ix = 0x2a511cd0 + v.ix; // Initial guess. + return v.x; +} + +float ALWAYS_INLINE fast_fabsf(float x) +{ +#if 0 + asm volatile ( + "vabs.f32 %[r], %[x]\n" + : [r] "=t" (x) + : [x] "t" (x)); +#endif + return x; +} + +inline float fast_atanf(float xx) +{ + float x, y, z; + int sign; + + x = xx; + + /* make argument positive and save the sign */ + if( xx < 0.0f ) + { + sign = -1; + x = -xx; + } + else + { + sign = 1; + x = xx; + } + /* range reduction */ + if( x > 2.414213562373095f ) /* tan 3pi/8 */ + { + y = M_PI_2; + x = -( 1.0f/x ); + } + + else if( x > 0.4142135623730950f ) /* tan pi/8 */ + { + y = M_PI_4; + x = (x-1.0f)/(x+1.0f); + } + else + y = 0.0f; + + z = x * x; + y += + ((( 8.05374449538e-2f * z + - 1.38776856032E-1f) * z + + 1.99777106478E-1f) * z + - 3.33329491539E-1f) * z * x + x; + + if( sign < 0 ) + y = -y; + + return( y ); +} + +float fast_atan2f(float y, float x) +{ + if(x > 0 && y >= 0) + return fast_atanf(y/x); + + if(x < 0 && y >= 0) + return M_PI - fast_atanf(-y/x); + + if(x < 0 && y < 0) + return M_PI + fast_atanf(y/x); + + if(x > 0 && y < 0) + return 2*M_PI - fast_atanf(-y/x); + + return (y == 0) ? 0 : ((y > 0) ? M_PI : -M_PI); +} + + +float fast_log2(float x) +{ + union { float f; uint32_t i; } vx = { x }; + union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 }; + float y = vx.i; + y *= 1.1920928955078125e-7f; + + return y - 124.22551499f - 1.498030302f * mx.f + - 1.72587999f / (0.3520887068f + mx.f); +} + +float fast_log(float x) +{ + return 0.69314718f * fast_log2 (x); +} diff --git a/src/openmv/src/omv/img/fmath.h b/src/openmv/src/omv/img/fmath.h new file mode 100755 index 0000000..195c476 --- /dev/null +++ b/src/openmv/src/omv/img/fmath.h @@ -0,0 +1,25 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Fast approximate math functions. + * + */ +#ifndef __FMATH_H__ +#define __FMATH_H__ +#include +float fast_sqrtf(float x); +int fast_floorf(float x); +int fast_ceilf(float x); +int fast_roundf(float x); +float fast_atanf(float x); +float fast_atan2f(float y, float x); +float fast_expf(float x); +float fast_cbrtf(float d); +float fast_fabsf(float d); +float fast_log(float x); +float fast_log2(float x); +extern const float cos_table[360]; +extern const float sin_table[360]; +#endif // __FMATH_H__ diff --git a/src/openmv/src/omv/img/font.c b/src/openmv/src/omv/img/font.c new file mode 100755 index 0000000..9e8a38d --- /dev/null +++ b/src/openmv/src/omv/img/font.c @@ -0,0 +1,1074 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Font data. + * + * Size: 8 Style: Normal + * Included characters: + * !"#$%&'()*+,-./0123456789:;<=>?\x0040ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + * Antialiasing: yes + * Type: monospaced + * Encoding: ASMO-708 + * Unicode bom: no + * + * Preset name: Monochrome + * Data block size: 8 bit(s), uint8_t + * RLE compression enabled: no + * Conversion type: Monochrome, Diffuse Dither 128 + * Bits per pixel: 1 + * + * Preprocess: + * main scan direction: top_to_bottom + * line scan direction: forward + * inverse: yes + */ +#include "font.h" +const glyph_t font[95] = { + // character: ' ' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '!' + {8, 10, {0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00}}, + // character: '"' + {8, 10, {0x00, + 0x00, + 0x18, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '#' + {8, 10, {0x00, + 0x00, + 0x24, + 0x7c, + 0x24, + 0x48, + 0x7c, + 0x48, + 0x00, + 0x00}}, + // character: '$' + {8, 10, {0x00, + 0x00, + 0x08, + 0x1c, + 0x20, + 0x18, + 0x04, + 0x38, + 0x08, + 0x00}}, + // character: '%' + {8, 10, {0x00, + 0x00, + 0x24, + 0x58, + 0x28, + 0x14, + 0x1a, + 0x24, + 0x00, + 0x00}}, + // character: '&' + {8, 10, {0x00, + 0x00, + 0x10, + 0x28, + 0x30, + 0x34, + 0x2c, + 0x1c, + 0x00, + 0x00}}, + // character: ''' + {8, 10, {0x00, + 0x00, + 0x10, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '(' + {8, 10, {0x00, + 0x00, + 0x08, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x08, + 0x00}}, + // character: ')' + {8, 10, {0x00, + 0x00, + 0x20, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x20, + 0x00}}, + // character: '*' + {8, 10, {0x00, + 0x00, + 0x10, + 0x38, + 0x28, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '+' + {8, 10, {0x00, + 0x00, + 0x00, + 0x10, + 0x10, + 0x7c, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: ',' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x20, + 0x00}}, + // character: '-' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '.' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00}}, + // character: '/' + {8, 10, {0x00, + 0x00, + 0x08, + 0x08, + 0x10, + 0x10, + 0x10, + 0x20, + 0x20, + 0x00}}, + // character: '0' + {8, 10, {0x00, + 0x00, + 0x18, + 0x24, + 0x24, + 0x24, + 0x24, + 0x18, + 0x00, + 0x00}}, + // character: '1' + {8, 10, {0x00, + 0x00, + 0x08, + 0x18, + 0x08, + 0x08, + 0x08, + 0x08, + 0x00, + 0x00}}, + // character: '2' + {8, 10, {0x00, + 0x00, + 0x18, + 0x24, + 0x04, + 0x08, + 0x10, + 0x3c, + 0x00, + 0x00}}, + // character: '3' + {8, 10, {0x00, + 0x00, + 0x38, + 0x04, + 0x18, + 0x04, + 0x04, + 0x38, + 0x00, + 0x00}}, + // character: '4' + {8, 10, {0x00, + 0x00, + 0x08, + 0x18, + 0x28, + 0x3c, + 0x08, + 0x08, + 0x00, + 0x00}}, + // character: '5' + {8, 10, {0x00, + 0x00, + 0x1c, + 0x10, + 0x18, + 0x04, + 0x04, + 0x18, + 0x00, + 0x00}}, + // character: '6' + {8, 10, {0x00, + 0x00, + 0x0c, + 0x10, + 0x38, + 0x24, + 0x24, + 0x18, + 0x00, + 0x00}}, + // character: '7' + {8, 10, {0x00, + 0x00, + 0x38, + 0x08, + 0x08, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: '8' + {8, 10, {0x00, + 0x00, + 0x18, + 0x24, + 0x18, + 0x24, + 0x24, + 0x18, + 0x00, + 0x00}}, + // character: '9' + {8, 10, {0x00, + 0x00, + 0x18, + 0x24, + 0x24, + 0x3c, + 0x08, + 0x30, + 0x00, + 0x00}}, + // character: ':' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00}}, + // character: ';' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x10, + 0x20, + 0x00}}, + // character: '<' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x40, + 0x38, + 0x00, + 0x00, + 0x00}}, + // character: '=' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x3c, + 0x00, + 0x3c, + 0x00, + 0x00, + 0x00}}, + // character: '>' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x08, + 0x30, + 0x00, + 0x00, + 0x00}}, + // character: '?' + {8, 10, {0x00, + 0x00, + 0x18, + 0x08, + 0x08, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00}}, + // character: '\x0040' + {8, 10, {0x00, + 0x00, + 0x38, + 0x44, + 0x9a, + 0xaa, + 0xaa, + 0xb4, + 0x40, + 0x38}}, + // character: 'A' + {8, 10, {0x00, + 0x00, + 0x10, + 0x28, + 0x28, + 0x28, + 0x7c, + 0x44, + 0x00, + 0x00}}, + // character: 'B' + {8, 10, {0x00, + 0x00, + 0x38, + 0x24, + 0x38, + 0x24, + 0x24, + 0x38, + 0x00, + 0x00}}, + // character: 'C' + {8, 10, {0x00, + 0x00, + 0x1c, + 0x20, + 0x20, + 0x20, + 0x20, + 0x1c, + 0x00, + 0x00}}, + // character: 'D' + {8, 10, {0x00, + 0x00, + 0x78, + 0x44, + 0x44, + 0x44, + 0x44, + 0x78, + 0x00, + 0x00}}, + // character: 'E' + {8, 10, {0x00, + 0x00, + 0x3c, + 0x20, + 0x38, + 0x20, + 0x20, + 0x3c, + 0x00, + 0x00}}, + // character: 'F' + {8, 10, {0x00, + 0x00, + 0x38, + 0x20, + 0x30, + 0x20, + 0x20, + 0x20, + 0x00, + 0x00}}, + // character: 'G' + {8, 10, {0x00, + 0x00, + 0x1c, + 0x20, + 0x20, + 0x24, + 0x24, + 0x1c, + 0x00, + 0x00}}, + // character: 'H' + {8, 10, {0x00, + 0x00, + 0x44, + 0x44, + 0x7c, + 0x44, + 0x44, + 0x44, + 0x00, + 0x00}}, + // character: 'I' + {8, 10, {0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'J' + {8, 10, {0x00, + 0x00, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x30, + 0x00, + 0x00}}, + // character: 'K' + {8, 10, {0x00, + 0x00, + 0x24, + 0x28, + 0x30, + 0x30, + 0x28, + 0x24, + 0x00, + 0x00}}, + // character: 'L' + {8, 10, {0x00, + 0x00, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x38, + 0x00, + 0x00}}, + // character: 'M' + {8, 10, {0x00, + 0x00, + 0x44, + 0x6c, + 0x6c, + 0x54, + 0x54, + 0x44, + 0x00, + 0x00}}, + // character: 'N' + {8, 10, {0x00, + 0x00, + 0x42, + 0x62, + 0x52, + 0x4a, + 0x46, + 0x42, + 0x00, + 0x00}}, + // character: 'O' + {8, 10, {0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x44, + 0x44, + 0x38, + 0x00, + 0x00}}, + // character: 'P' + {8, 10, {0x00, + 0x00, + 0x38, + 0x24, + 0x24, + 0x38, + 0x20, + 0x20, + 0x00, + 0x00}}, + // character: 'Q' + {8, 10, {0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x44, + 0x44, + 0x38, + 0x10, + 0x08}}, + // character: 'R' + {8, 10, {0x00, + 0x00, + 0x38, + 0x24, + 0x24, + 0x38, + 0x28, + 0x24, + 0x00, + 0x00}}, + // character: 'S' + {8, 10, {0x00, + 0x00, + 0x18, + 0x20, + 0x20, + 0x18, + 0x08, + 0x30, + 0x00, + 0x00}}, + // character: 'T' + {8, 10, {0x00, + 0x00, + 0x38, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'U' + {8, 10, {0x00, + 0x00, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x38, + 0x00, + 0x00}}, + // character: 'V' + {8, 10, {0x00, + 0x00, + 0x44, + 0x44, + 0x28, + 0x28, + 0x28, + 0x10, + 0x00, + 0x00}}, + // character: 'W' + {8, 10, {0x00, + 0x00, + 0x82, + 0x92, + 0xaa, + 0xaa, + 0xaa, + 0x44, + 0x00, + 0x00}}, + // character: 'X' + {8, 10, {0x00, + 0x00, + 0x44, + 0x28, + 0x10, + 0x10, + 0x28, + 0x44, + 0x00, + 0x00}}, + // character: 'Y' + {8, 10, {0x00, + 0x00, + 0x44, + 0x28, + 0x28, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'Z' + {8, 10, {0x00, + 0x00, + 0x3c, + 0x04, + 0x08, + 0x10, + 0x20, + 0x3c, + 0x00, + 0x00}}, + // character: '[' + {8, 10, {0x00, + 0x00, + 0x18, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x18, + 0x00}}, + // character: '\' + {8, 10, {0x00, + 0x00, + 0x20, + 0x20, + 0x10, + 0x10, + 0x10, + 0x08, + 0x08, + 0x00}}, + // character: ']' + {8, 10, {0x00, + 0x00, + 0x30, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x30, + 0x00}}, + // character: '^' + {8, 10, {0x00, + 0x00, + 0x10, + 0x28, + 0x28, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: '_' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x78, + 0x00}}, + // character: '`' + {8, 10, {0x00, + 0x10, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}}, + // character: 'a' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x08, + 0x18, + 0x38, + 0x00, + 0x00}}, + // character: 'b' + {8, 10, {0x00, + 0x00, + 0x20, + 0x20, + 0x38, + 0x24, + 0x24, + 0x38, + 0x00, + 0x00}}, + // character: 'c' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x20, + 0x20, + 0x18, + 0x00, + 0x00}}, + // character: 'd' + {8, 10, {0x00, + 0x00, + 0x04, + 0x04, + 0x1c, + 0x24, + 0x24, + 0x1c, + 0x00, + 0x00}}, + // character: 'e' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x38, + 0x20, + 0x18, + 0x00, + 0x00}}, + // character: 'f' + {8, 10, {0x00, + 0x00, + 0x08, + 0x10, + 0x18, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'g' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x1c, + 0x24, + 0x1c, + 0x04, + 0x38, + 0x00}}, + // character: 'h' + {8, 10, {0x00, + 0x00, + 0x20, + 0x20, + 0x38, + 0x24, + 0x24, + 0x24, + 0x00, + 0x00}}, + // character: 'i' + {8, 10, {0x00, + 0x00, + 0x10, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'j' + {8, 10, {0x00, + 0x00, + 0x10, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x20, + 0x00}}, + // character: 'k' + {8, 10, {0x00, + 0x00, + 0x20, + 0x20, + 0x28, + 0x30, + 0x30, + 0x28, + 0x00, + 0x00}}, + // character: 'l' + {8, 10, {0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x08, + 0x00, + 0x00}}, + // character: 'm' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0xec, + 0x92, + 0x92, + 0x92, + 0x00, + 0x00}}, + // character: 'n' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x24, + 0x24, + 0x24, + 0x00, + 0x00}}, + // character: 'o' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x24, + 0x24, + 0x18, + 0x00, + 0x00}}, + // character: 'p' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x24, + 0x24, + 0x38, + 0x20, + 0x00}}, + // character: 'q' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x1c, + 0x24, + 0x24, + 0x1c, + 0x04, + 0x00}}, + // character: 'r' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 's' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x20, + 0x18, + 0x30, + 0x00, + 0x00}}, + // character: 't' + {8, 10, {0x00, + 0x00, + 0x00, + 0x10, + 0x18, + 0x10, + 0x10, + 0x08, + 0x00, + 0x00}}, + // character: 'u' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x24, + 0x24, + 0x24, + 0x1c, + 0x00, + 0x00}}, + // character: 'v' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x28, + 0x28, + 0x10, + 0x10, + 0x00, + 0x00}}, + // character: 'w' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x54, + 0x54, + 0x54, + 0x28, + 0x00, + 0x00}}, + // character: 'x' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x28, + 0x10, + 0x10, + 0x28, + 0x00, + 0x00}}, + // character: 'y' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x28, + 0x28, + 0x10, + 0x10, + 0x20, + 0x00}}, + // character: 'z' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x08, + 0x10, + 0x18, + 0x00, + 0x00}}, + // character: '{' + {8, 10, {0x00, + 0x00, + 0x08, + 0x10, + 0x10, + 0x20, + 0x10, + 0x10, + 0x08, + 0x00}}, + // character: '|' + {8, 10, {0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00}}, + // character: '}' + {8, 10, {0x00, + 0x00, + 0x20, + 0x10, + 0x10, + 0x08, + 0x10, + 0x10, + 0x20, + 0x00}}, + // character: '~' + {8, 10, {0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x28, + 0x50, + 0x00, + 0x00, + 0x00}} +}; diff --git a/src/openmv/src/omv/img/font.h b/src/openmv/src/omv/img/font.h new file mode 100755 index 0000000..d271438 --- /dev/null +++ b/src/openmv/src/omv/img/font.h @@ -0,0 +1,18 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Font data. + * + */ +#ifndef __FONT_H__ +#define __FONT_H__ +#include +typedef struct { + int w; + int h; + uint8_t data[10]; +} glyph_t; +extern const glyph_t font[95]; +#endif // __FONT_H__ diff --git a/src/openmv/src/omv/img/fsort.c b/src/openmv/src/omv/img/fsort.c new file mode 100755 index 0000000..2c6824f --- /dev/null +++ b/src/openmv/src/omv/img/fsort.c @@ -0,0 +1,309 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Fast 9 and 25 bin sort. + * + */ +#include +#include "fsort.h" + +// http://pages.ripco.net/~jgamble/nw.html + +static void cmpswp(int *a, int *b) +{ + if ((*b) < (*a)) { + int tmp = *a; + *a = *b; + *b = tmp; + } +} + +// Network for N=9, using Best Known Arrangement. + +// There are 25 comparators in this network, +// grouped into 9 parallel operations. + +// [[0,1],[3,4],[6,7]] +// [[1,2],[4,5],[7,8]] +// [[0,1],[3,4],[6,7],[2,5]] +// [[0,3],[1,4],[5,8]] +// [[3,6],[4,7],[2,5]] +// [[0,3],[1,4],[5,7],[2,6]] +// [[1,3],[4,6]] +// [[2,4],[5,6]] +// [[2,3]] + +// This is graphed in 17 columns. + +static void fsort9(int *data) +{ + cmpswp(data+0, data+1); + cmpswp(data+3, data+4); + cmpswp(data+6, data+7); + + cmpswp(data+1, data+2); + cmpswp(data+4, data+5); + cmpswp(data+7, data+8); + + cmpswp(data+0, data+1); + cmpswp(data+3, data+4); + cmpswp(data+6, data+7); + cmpswp(data+2, data+5); + + cmpswp(data+0, data+3); + cmpswp(data+1, data+4); + cmpswp(data+5, data+8); + + cmpswp(data+3, data+6); + cmpswp(data+4, data+7); + cmpswp(data+2, data+5); + + cmpswp(data+0, data+3); + cmpswp(data+1, data+4); + cmpswp(data+5, data+7); + cmpswp(data+2, data+6); + + cmpswp(data+1, data+3); + cmpswp(data+4, data+6); + + cmpswp(data+2, data+4); + cmpswp(data+5, data+6); + + cmpswp(data+2, data+3); +} + +// Network for N=25, using Bose-Nelson Algorithm. + +// There are 154 comparators in this network, +// grouped into 27 parallel operations. + +// [[1,2],[4,5],[7,8],[10,11],[13,14],[16,17],[19,20],[21,22],[23,24]] +// [[0,2],[3,5],[6,8],[9,11],[12,14],[15,17],[18,20],[21,23],[22,24]] +// [[0,1],[3,4],[2,5],[6,7],[9,10],[8,11],[12,13],[15,16],[14,17],[18,19],[22,23],[20,24]] +// [[0,3],[1,4],[6,9],[7,10],[5,11],[12,15],[13,16],[18,22],[19,23],[17,24]] +// [[2,4],[1,3],[8,10],[7,9],[0,6],[14,16],[13,15],[18,21],[20,23],[11,24]] +// [[2,3],[8,9],[1,7],[4,10],[14,15],[19,21],[20,22],[16,23]] +// [[2,8],[1,6],[3,9],[5,10],[20,21],[12,19],[15,22],[17,23]] +// [[2,7],[4,9],[12,18],[13,20],[14,21],[16,22],[10,23]] +// [[2,6],[5,9],[4,7],[14,20],[13,18],[17,22],[11,23]] +// [[3,6],[5,8],[14,19],[16,20],[17,21],[0,13],[9,22]] +// [[5,7],[4,6],[14,18],[15,19],[17,20],[0,12],[8,21],[10,22]] +// [[5,6],[15,18],[17,19],[1,14],[7,20],[11,22]] +// [[16,18],[2,15],[1,12],[6,19],[8,20],[11,21]] +// [[17,18],[2,14],[3,16],[7,19],[10,20]] +// [[2,13],[4,17],[5,18],[8,19],[11,20]] +// [[2,12],[5,17],[4,16],[3,13],[9,19]] +// [[5,16],[3,12],[4,14],[10,19]] +// [[5,15],[4,12],[11,19],[9,16],[10,17]] +// [[5,14],[8,15],[11,18],[10,16]] +// [[5,13],[7,14],[11,17]] +// [[5,12],[6,13],[8,14],[11,16]] +// [[6,12],[8,13],[10,14],[11,15]] +// [[7,12],[9,13],[11,14]] +// [[8,12],[11,13]] +// [[9,12]] +// [[10,12]] +// [[11,12]] + +// This is graphed in 89 columns. + +static void fsort25(int *data) +{ + cmpswp(data+1, data+2); + cmpswp(data+4, data+5); + cmpswp(data+7, data+8); + cmpswp(data+10, data+11); + cmpswp(data+13, data+14); + cmpswp(data+16, data+17); + cmpswp(data+19, data+20); + cmpswp(data+21, data+22); + cmpswp(data+23, data+24); + + cmpswp(data+0, data+2); + cmpswp(data+3, data+5); + cmpswp(data+6, data+8); + cmpswp(data+9, data+11); + cmpswp(data+12, data+14); + cmpswp(data+15, data+17); + cmpswp(data+18, data+20); + cmpswp(data+21, data+23); + cmpswp(data+22, data+24); + + cmpswp(data+0, data+1); + cmpswp(data+3, data+4); + cmpswp(data+2, data+5); + cmpswp(data+6, data+7); + cmpswp(data+9, data+10); + cmpswp(data+8, data+11); + cmpswp(data+12, data+13); + cmpswp(data+15, data+16); + cmpswp(data+14, data+17); + cmpswp(data+18, data+19); + cmpswp(data+22, data+23); + cmpswp(data+20, data+24); + + cmpswp(data+0, data+3); + cmpswp(data+1, data+4); + cmpswp(data+6, data+9); + cmpswp(data+7, data+10); + cmpswp(data+5, data+11); + cmpswp(data+12, data+15); + cmpswp(data+13, data+16); + cmpswp(data+18, data+22); + cmpswp(data+19, data+23); + cmpswp(data+17, data+24); + + cmpswp(data+2, data+4); + cmpswp(data+1, data+3); + cmpswp(data+8, data+10); + cmpswp(data+7, data+9); + cmpswp(data+0, data+6); + cmpswp(data+14, data+16); + cmpswp(data+13, data+15); + cmpswp(data+18, data+21); + cmpswp(data+20, data+23); + cmpswp(data+11, data+24); + + cmpswp(data+2, data+3); + cmpswp(data+8, data+9); + cmpswp(data+1, data+7); + cmpswp(data+4, data+10); + cmpswp(data+14, data+15); + cmpswp(data+19, data+21); + cmpswp(data+20, data+22); + cmpswp(data+16, data+23); + + cmpswp(data+2, data+8); + cmpswp(data+1, data+6); + cmpswp(data+3, data+9); + cmpswp(data+5, data+10); + cmpswp(data+20, data+21); + cmpswp(data+12, data+19); + cmpswp(data+15, data+22); + cmpswp(data+17, data+23); + + cmpswp(data+2, data+7); + cmpswp(data+4, data+9); + cmpswp(data+12, data+18); + cmpswp(data+13, data+20); + cmpswp(data+14, data+21); + cmpswp(data+16, data+22); + cmpswp(data+10, data+23); + + cmpswp(data+2, data+6); + cmpswp(data+5, data+9); + cmpswp(data+4, data+7); + cmpswp(data+14, data+20); + cmpswp(data+13, data+18); + cmpswp(data+17, data+22); + cmpswp(data+11, data+23); + + cmpswp(data+3, data+6); + cmpswp(data+5, data+8); + cmpswp(data+14, data+19); + cmpswp(data+16, data+20); + cmpswp(data+17, data+21); + cmpswp(data+0, data+13); + cmpswp(data+9, data+22); + + cmpswp(data+5, data+7); + cmpswp(data+4, data+6); + cmpswp(data+14, data+18); + cmpswp(data+15, data+19); + cmpswp(data+17, data+20); + cmpswp(data+0, data+12); + cmpswp(data+8, data+21); + cmpswp(data+10, data+22); + + cmpswp(data+5, data+6); + cmpswp(data+15, data+18); + cmpswp(data+17, data+19); + cmpswp(data+1, data+14); + cmpswp(data+7, data+20); + cmpswp(data+11, data+22); + + cmpswp(data+16, data+18); + cmpswp(data+2, data+15); + cmpswp(data+1, data+12); + cmpswp(data+6, data+19); + cmpswp(data+8, data+20); + cmpswp(data+11, data+21); + + cmpswp(data+17, data+18); + cmpswp(data+2, data+14); + cmpswp(data+3, data+16); + cmpswp(data+7, data+19); + cmpswp(data+10, data+20); + + cmpswp(data+2, data+13); + cmpswp(data+4, data+17); + cmpswp(data+5, data+18); + cmpswp(data+8, data+19); + cmpswp(data+11, data+20); + + cmpswp(data+2, data+12); + cmpswp(data+5, data+17); + cmpswp(data+4, data+16); + cmpswp(data+3, data+13); + cmpswp(data+9, data+19); + + cmpswp(data+5, data+16); + cmpswp(data+3, data+12); + cmpswp(data+4, data+14); + cmpswp(data+10, data+19); + + cmpswp(data+5, data+15); + cmpswp(data+4, data+12); + cmpswp(data+11, data+19); + cmpswp(data+9, data+16); + cmpswp(data+10, data+17); + + cmpswp(data+5, data+14); + cmpswp(data+8, data+15); + cmpswp(data+11, data+18); + cmpswp(data+10, data+16); + + cmpswp(data+5, data+13); + cmpswp(data+7, data+14); + cmpswp(data+11, data+17); + + cmpswp(data+5, data+12); + cmpswp(data+6, data+13); + cmpswp(data+8, data+14); + cmpswp(data+11, data+16); + + cmpswp(data+6, data+12); + cmpswp(data+8, data+13); + cmpswp(data+10, data+14); + cmpswp(data+11, data+15); + + cmpswp(data+7, data+12); + cmpswp(data+9, data+13); + cmpswp(data+11, data+14); + + cmpswp(data+8, data+12); + cmpswp(data+11, data+13); + + cmpswp(data+9, data+12); + + cmpswp(data+10, data+12); + + cmpswp(data+11, data+12); +} + +static int fsort_compare(const void *a, const void *b) +{ + return (*((int *) a)) - (*((int *) b)); +} + +void fsort(int *data, int n) +{ + switch(n) { + case 1: return; + case 9: fsort9(data); return; + case 25: fsort25(data); return; + default: qsort(data, n, sizeof(int), fsort_compare); + } +} diff --git a/src/openmv/src/omv/img/fsort.h b/src/openmv/src/omv/img/fsort.h new file mode 100755 index 0000000..76dbf9f --- /dev/null +++ b/src/openmv/src/omv/img/fsort.h @@ -0,0 +1,13 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Fast 9 and 25 bin sort. + * + */ +#ifndef __FSORT_H__ +#define __FSORT_H__ +#include +void fsort(int *data, int n); +#endif /* __FSORT_H__ */ diff --git a/src/openmv/src/omv/img/gif.c b/src/openmv/src/omv/img/gif.c new file mode 100755 index 0000000..46c1d60 --- /dev/null +++ b/src/openmv/src/omv/img/gif.c @@ -0,0 +1,116 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * A super simple GIF encoder. + * + */ +#include +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "imlib.h" +#define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!) + +void gif_open(FIL *fp, int width, int height, bool color, bool loop) +{ + file_buffer_on(fp); + + write_data(fp, "GIF89a", 6); + write_word(fp, width); + write_word(fp, height); + write_data(fp, (uint8_t []) {0xF6, 0x00, 0x00}, 3); + + if (color) { + for (int i=0; i<128; i++) { + int red = ((((i & 0x60) >> 5) * 255) + 1.5) / 3; + int green = ((((i & 0x1C) >> 2) * 255) + 3.5) / 7; + int blue = (((i & 0x3) * 255) + 1.5) / 3; + write_data(fp, (uint8_t []) {red, green, blue}, 3); + } + } else { + for (int i=0; i<128; i++) { + int gray = ((i * 255) + 63.5) / 127; + write_data(fp, (uint8_t []) {gray, gray, gray}, 3); + } + } + + if (loop) { + write_data(fp, (uint8_t []) {'!', 0xFF, 0x0B}, 3); + write_data(fp, "NETSCAPE2.0", 11); + write_data(fp, (uint8_t []) {0x03, 0x01, 0x00, 0x00, 0x00}, 5); + } + + file_buffer_off(fp); +} + +void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) +{ + file_buffer_on(fp); + + if (delay) { + write_data(fp, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4); + write_word(fp, delay); + write_word(fp, 0); // end + } + + write_byte(fp, 0x2C); + write_long(fp, 0); + write_word(fp, img->w); + write_word(fp, img->h); + write_data(fp, (uint8_t []) {0x00, 0x07}, 2); // 7-bits + + int bytes = img->h * img->w; + int blocks = (bytes + BLOCK_SIZE - 1) / BLOCK_SIZE; + + if (IM_IS_GS(img)) { + for (int y=0; ypixels[(y*BLOCK_SIZE)+x]>>1); + } + } + } else if (IM_IS_RGB565(img)) { + for (int y=0; ypixels)[(y*BLOCK_SIZE)+x]; + int red = IM_R565(pixel)>>3; + int green = IM_G565(pixel)>>3; + int blue = IM_B565(pixel)>>3; + write_byte(fp, (red<<5) | (green<<2) | blue); + } + } + } else if (IM_IS_BAYER(img)) { + for (int y=0; yw; + int y_offs = (y*BLOCK_SIZE) / img->w; + if (x_offs > 0 && y_offs > 0 && x_offs < img->w-1 && y_offs < img->h-1) { + COLOR_BAYER_TO_RGB565(img, x_offs, y_offs, r, g, b); + } + r >>=3; g >>=3; b >>=3; + write_byte(fp, (r<<5) | (g<<2) | b); + } + } + } + + + write_data(fp, (uint8_t []) {0x01, 0x81, 0x00}, 3); // end code + + file_buffer_off(fp); +} + +void gif_close(FIL *fp) +{ + write_byte(fp, ';'); + file_close(fp); +} diff --git a/src/openmv/src/omv/img/haar.c b/src/openmv/src/omv/img/haar.c new file mode 100755 index 0000000..abee8a3 --- /dev/null +++ b/src/openmv/src/omv/img/haar.c @@ -0,0 +1,292 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Viola-Jones object detector implementation. + * Original Author: Francesco Comaschi (f.comaschi@tue.nl) + * + */ +#include +#include "ff.h" +#include "ff_wrapper.h" +#include "xalloc.h" +#include "imlib.h" +// built-in cascades +#include "cascade.h" + +static int eval_weak_classifier(cascade_t *cascade, point_t pt, int t_idx, int w_idx, int r_idx) +{ + int32_t sumw=0; + mw_image_t *sum = cascade->sum; + + /* The node threshold is multiplied by the standard deviation of the sub window */ + int32_t t = cascade->tree_thresh_array[t_idx] * cascade->std; + + for (int i=0; inum_rectangles_array[t_idx]; i++) { + int x = cascade->rectangles_array[r_idx + (i<<2) + 0]; + int y = cascade->rectangles_array[r_idx + (i<<2) + 1]; + int w = cascade->rectangles_array[r_idx + (i<<2) + 2]; + int h = cascade->rectangles_array[r_idx + (i<<2) + 3]; + // Lookup the feature + sumw += imlib_integral_mw_lookup(sum, pt.x+x, y, w, h) * (cascade->weights_array[w_idx + i]<<12); + } + + if (sumw >= t) { + return cascade->alpha2_array[t_idx]; + } + + return cascade->alpha1_array[t_idx]; +} + +static int run_cascade_classifier(cascade_t* cascade, point_t pt) +{ + int win_w = cascade->window.w; + int win_h = cascade->window.h; + uint32_t n = (win_w * win_h); + uint32_t i_s = imlib_integral_mw_lookup (cascade->sum, pt.x, 0, win_w, win_h); + uint32_t i_sq = imlib_integral_mw_lookup(cascade->ssq, pt.x, 0, win_w, win_h); + uint32_t m = i_s/n; + uint32_t v = i_sq/n-(m*m); + + // Skip homogeneous regions. + if (v<(50*50)) { + return 0; + } + + cascade->std = fast_sqrtf(i_sq*n-(i_s*i_s)); + for (int i=0, w_idx=0, r_idx=0, t_idx=0; in_stages; i++) { + int stage_sum = 0; + for (int j=0; jstages_array[i]; j++, t_idx++) { + // Send the shifted window to a haar filter + stage_sum += eval_weak_classifier(cascade, pt, t_idx, w_idx, r_idx); + w_idx += cascade->num_rectangles_array[t_idx]; + r_idx += cascade->num_rectangles_array[t_idx] * 4; + } + // If the sum is below the stage threshold, no objects were detected + if (stage_sum < (cascade->threshold * cascade->stages_thresh_array[i])) { + return 0; + } + } + return 1; +} + +array_t *imlib_detect_objects(image_t *image, cascade_t *cascade, rectangle_t *roi) +{ + // Integral images + mw_image_t sum; + mw_image_t ssq; + + // Detected objects array + array_t *objects; + + // Allocate the objects array + array_alloc(&objects, xfree); + + // Set cascade image pointers + cascade->img = image; + cascade->sum = ∑ + cascade->ssq = &ssq; + + // Set scanning step. + // Viola and Jones achieved best results using a scaling factor + // of 1.25 and a scanning factor proportional to the current scale. + // Start with a step of 5% of the image width and reduce at each scaling step + cascade->step = (roi->w*50)/1000; + + // Make sure step is less than window height + 1 + if (cascade->step > cascade->window.h) { + cascade->step = cascade->window.h; + } + + // Allocate integral images + imlib_integral_mw_alloc(&sum, roi->w, cascade->window.h+1); + imlib_integral_mw_alloc(&ssq, roi->w, cascade->window.h+1); + + // Iterate over the image pyramid + for(float factor=1.0f; ; factor *= cascade->scale_factor) { + // Set the scaled width and height + int szw = roi->w/factor; + int szh = roi->h/factor; + + // Break if scaled image is smaller than feature size + if (szw < cascade->window.w || szh < cascade->window.h) { + break; + } + + // Set the integral images scale + imlib_integral_mw_scale(roi, &sum, szw, szh); + imlib_integral_mw_scale(roi, &ssq, szw, szh); + + // Compute new scaled integral images + imlib_integral_mw_ss(image, &sum, &ssq, roi); + + // Scale the scanning step + cascade->step = cascade->step/factor; + cascade->step = (cascade->step == 0) ? 1 : cascade->step; + + // Process image at the current scale + // When filter window shifts to borders, some margin need to be kept + int y2 = szh - cascade->window.h; + int x2 = szw - cascade->window.w; + + // Shift the filter window over the image. + for (int y=0; ystep) { + for (int x=0; xstep) { + point_t p = {x, y}; + // If an object is detected, record the coordinates of the filter window + if (run_cascade_classifier(cascade, p) > 0) { + array_push_back(objects, + rectangle_alloc(fast_roundf(x*factor) + roi->x, fast_roundf(y*factor) + roi->y, + fast_roundf(cascade->window.w*factor), fast_roundf(cascade->window.h*factor))); + } + } + + // If not last line, shift integral images + if ((y+cascade->step) < y2) { + imlib_integral_mw_shift_ss(image, &sum, &ssq, roi, cascade->step); + } + } + } + + imlib_integral_mw_free(&ssq); + imlib_integral_mw_free(&sum); + + if (array_length(objects) > 1) { + // Merge objects detected at different scales + objects = rectangle_merge(objects); + } + + return objects; +} + +int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) +{ + int i; + FIL fp; + FRESULT res=FR_OK; + + file_read_open(&fp, path); + file_buffer_on(&fp); + + /* read detection window size */ + read_data(&fp, &cascade->window, sizeof(cascade->window)); + + /* read num stages */ + read_data(&fp, &cascade->n_stages, sizeof(cascade->n_stages)); + + cascade->stages_array = xalloc (sizeof(*cascade->stages_array) * cascade->n_stages); + cascade->stages_thresh_array = xalloc (sizeof(*cascade->stages_thresh_array) * cascade->n_stages); + if (cascade->stages_array == NULL || + cascade->stages_thresh_array == NULL) { + res = 20; + goto error; + } + + /* read num features in each stages */ + read_data(&fp, cascade->stages_array, sizeof(uint8_t) * cascade->n_stages); + + /* sum num of features in each stages*/ + for (i=0, cascade->n_features=0; in_stages; i++) { + cascade->n_features += cascade->stages_array[i]; + } + + /* alloc features thresh array, alpha1, alpha 2,rects weights and rects*/ + cascade->tree_thresh_array = xalloc (sizeof(*cascade->tree_thresh_array) * cascade->n_features); + cascade->alpha1_array = xalloc (sizeof(*cascade->alpha1_array) * cascade->n_features); + cascade->alpha2_array = xalloc (sizeof(*cascade->alpha2_array) * cascade->n_features); + cascade->num_rectangles_array = xalloc (sizeof(*cascade->num_rectangles_array) * cascade->n_features); + + if (cascade->tree_thresh_array == NULL || + cascade->alpha1_array == NULL || + cascade->alpha2_array == NULL || + cascade->num_rectangles_array == NULL) { + res = 20; + goto error; + } + + /* read stages thresholds */ + read_data(&fp, cascade->stages_thresh_array, sizeof(int16_t)*cascade->n_stages); + + /* read features thresholds */ + read_data(&fp, cascade->tree_thresh_array, sizeof(*cascade->tree_thresh_array)*cascade->n_features); + + /* read alpha 1 */ + read_data(&fp, cascade->alpha1_array, sizeof(*cascade->alpha1_array)*cascade->n_features); + + /* read alpha 2 */ + read_data(&fp, cascade->alpha2_array, sizeof(*cascade->alpha2_array)*cascade->n_features); + + /* read num rectangles per feature*/ + read_data(&fp, cascade->num_rectangles_array, sizeof(*cascade->num_rectangles_array)*cascade->n_features); + + /* sum num of recatngles per feature*/ + for (i=0, cascade->n_rectangles=0; in_features; i++) { + cascade->n_rectangles += cascade->num_rectangles_array[i]; + } + + cascade->weights_array = xalloc (sizeof(*cascade->weights_array) * cascade->n_rectangles); + cascade->rectangles_array = xalloc (sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4); + + if (cascade->weights_array == NULL || + cascade->rectangles_array == NULL) { + res = 20; + goto error; + } + + /* read rectangles weights */ + read_data(&fp, cascade->weights_array, sizeof(*cascade->weights_array)*cascade->n_rectangles); + + /* read rectangles num rectangles * 4 points */ + read_data(&fp, cascade->rectangles_array, sizeof(*cascade->rectangles_array)*cascade->n_rectangles *4); + +error: + file_buffer_off(&fp); + file_close(&fp); + return res; +} + +int imlib_load_cascade(cascade_t *cascade, const char *path) +{ + // built-in cascade + if (strcmp(path, "frontalface") == 0) { + cascade->window.w = frontalface_window_w; + cascade->window.h = frontalface_window_h; + cascade->n_stages = frontalface_n_stages; + cascade->stages_array = (uint8_t *)frontalface_stages_array; + cascade->stages_thresh_array = (int16_t *)frontalface_stages_thresh_array; + cascade->tree_thresh_array = (int16_t *)frontalface_tree_thresh_array; + cascade->alpha1_array = (int16_t *)frontalface_alpha1_array; + cascade->alpha2_array = (int16_t *)frontalface_alpha2_array; + cascade->num_rectangles_array= (int8_t *)frontalface_num_rectangles_array; + cascade->weights_array = (int8_t *)frontalface_weights_array; + cascade->rectangles_array = (int8_t *)frontalface_rectangles_array; + } else if (strcmp(path, "eye") == 0) { + cascade->window.w = eye_window_w; + cascade->window.h = eye_window_h; + cascade->n_stages = eye_n_stages; + cascade->stages_array = (uint8_t *)eye_stages_array; + cascade->stages_thresh_array = (int16_t *)eye_stages_thresh_array; + cascade->tree_thresh_array = (int16_t *)eye_tree_thresh_array; + cascade->alpha1_array = (int16_t *)eye_alpha1_array; + cascade->alpha2_array = (int16_t *)eye_alpha2_array; + cascade->num_rectangles_array= (int8_t *)eye_num_rectangles_array; + cascade->weights_array = (int8_t *)eye_weights_array; + cascade->rectangles_array = (int8_t *)eye_rectangles_array; + } else { + // xml cascade + return imlib_load_cascade_from_file(cascade, path); + } + + int i; + // sum the number of features in all stages + for (i=0, cascade->n_features=0; in_stages; i++) { + cascade->n_features += cascade->stages_array[i]; + } + + // sum the number of recatngles in all features + for (i=0, cascade->n_rectangles=0; in_features; i++) { + cascade->n_rectangles += cascade->num_rectangles_array[i]; + } + return FR_OK; +} diff --git a/src/openmv/src/omv/img/hog.c b/src/openmv/src/omv/img/hog.c new file mode 100755 index 0000000..df1374f --- /dev/null +++ b/src/openmv/src/omv/img/hog.c @@ -0,0 +1,133 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * HoG. + * See Histograms of Oriented Gradients (Navneet Dalal and Bill Triggs) + */ +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#include "xalloc.h" + +#ifdef IMLIB_ENABLE_HOG +#define N_BINS (9) +typedef struct bin { + int d; + int m; +} bin_t; + +int bin_array_comp(const void *obj0, const void *obj1) +{ + const bin_t *b0 = obj0; + const bin_t *b1 = obj1; + if (b0->m < b1->m) + return -1; + if (b0->m > b1->m) + return 1; + + return 0; +} + +void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size) +{ + int s = src->w; + int w = roi->x+roi->w-1; + int h = roi->y+roi->h-1; + + int block_size = cell_size * 2; + int x_cells = (roi->w/cell_size); + int y_cells = (roi->h/cell_size); + + // TODO: Assert row->w/h >= cell_size *2; + float *hog = fb_alloc0(x_cells * y_cells * N_BINS * sizeof*hog); + + //2. Finding Image Gradients + for (int y=roi->y, hog_index=0; yx; x 0 && (y+cy) < h && (x+cx) > 0 && (x+cx) < w) { + // Find horizontal/vertical direction + int vx = src->data[(y+cy+0)*s+(x+cx+1)] - src->data[(y+cy-0)*s+(x+cx-1)]; + int vy = src->data[(y+cy+1)*s+(x+cx+0)] - src->data[(y+cy-1)*s+(x+cx-0)]; + // Find magnitude + float m = fast_sqrtf(vx*vx + vy*vy); + if(((int) m) > 1) { + k += m*m; + // Find and quantize gradient degree + // TODO atan2f is swapped for visualization + int t = ((int) fast_fabsf((atan2f(vx, vy)*180.0f/M_PI))) / 20; + t = (t == 9)? 0 : t; + + // hog[((cy/cell_size) * x_cells + (cx/cell_size)) * N_BINS + t] += m; + hog[hog_index + (((cy/8)*2+(cx/8)) * N_BINS) + t] += m; + } + } + } + } + + // Normalize the last block + //k = sqrtf(k); + for (int i=hog_index; i<(hog_index+(N_BINS*4)); i++) { + hog[i] = hog[i]/k; + } + + hog_index += (N_BINS*4); + } + } + + memset(src->pixels, 0, src->w*src->h); + + array_t *gds; + bin_t bins[9]; + array_alloc(&gds, NULL); + + for (int i=0; i 255) { + m = 255; + } else if (m < 0) { + m = 0; + } + bin_t *bin = array_at(gds, (i%N_BINS)); + bin->m = m; + bin->d = ((i%N_BINS)*20); + } + + array_sort(gds, bin_array_comp); + + int x1 = (x+bx) * cell_size + l; + int y1 = (y+by) * cell_size + l; + for (int i=0; id]; + int y2 = l * sin_table[bin->d]; + imlib_draw_line(src, (x1 - x2), (y1 + y2), (x1 + x2), (y1 - y2), bin->m, 1); + } + + hog_index += N_BINS; + } + } + } + } + + xfree(gds); + fb_free(); +} +#endif // IMLIB_ENABLE_HOG diff --git a/src/openmv/src/omv/img/hough.c b/src/openmv/src/omv/img/hough.c new file mode 100755 index 0000000..c66b657 --- /dev/null +++ b/src/openmv/src/omv/img/hough.c @@ -0,0 +1,801 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +#ifdef IMLIB_ENABLE_FIND_LINES +void imlib_find_lines(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int theta_margin, unsigned int rho_margin) +{ + int r_diag_len, r_diag_len_div, theta_size, r_size, hough_divide = 1; // divides theta and rho accumulators + + for (;;) { // shrink to fit... + r_diag_len = fast_roundf(fast_sqrtf((roi->w * roi->w) + (roi->h * roi->h))); + r_diag_len_div = (r_diag_len + hough_divide - 1) / hough_divide; + theta_size = 1 + ((180 + hough_divide - 1) / hough_divide) + 1; // left & right padding + r_size = (r_diag_len_div * 2) + 1; // -r_diag_len to +r_diag_len + if ((sizeof(uint32_t) * theta_size * r_size) <= fb_avail()) break; + hough_divide = hough_divide << 1; // powers of 2... + if (hough_divide > 4) fb_alloc_fail(); // support 1, 2, 4 + } + + uint32_t *acc = fb_alloc0(sizeof(uint32_t) * theta_size * r_size); + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (theta < 0) theta += 180; + int rho = (fast_roundf(((x - roi->x) * cos_table[theta]) + + ((y - roi->y) * sin_table[theta])) / hough_divide) + r_diag_len_div; + int acc_index = (rho * theta_size) + ((theta / hough_divide) + 1); // add offset + + int acc_value = acc[acc_index] + fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + acc[acc_index] = acc_value; + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ptr->w; + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (theta < 0) theta += 180; + int rho = (fast_roundf(((x - roi->x) * cos_table[theta]) + + ((y - roi->y) * sin_table[theta])) / hough_divide) + r_diag_len_div; + int acc_index = (rho * theta_size) + ((theta / hough_divide) + 1); // add offset + + int acc_value = acc[acc_index] + fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + acc[acc_index] = acc_value; + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ptr->w; + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (theta < 0) theta += 180; + int rho = (fast_roundf(((x - roi->x) * cos_table[theta]) + + ((y - roi->y) * sin_table[theta])) / hough_divide) + r_diag_len_div; + int acc_index = (rho * theta_size) + ((theta / hough_divide) + 1); // add offset + + int acc_value = acc[acc_index] + fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + acc[acc_index] = acc_value; + } + } + break; + } + default: { + break; + } + } + + list_init(out, sizeof(find_lines_list_lnk_data_t)); + + for (int y = 1, yy = r_size - 1; y < yy; y++) { + uint32_t *row_ptr = acc + (theta_size * y); + + for (int x = 1, xx = theta_size - 1; x < xx; x++) { + if ((row_ptr[x] >= threshold) + && (row_ptr[x] >= row_ptr[x-theta_size-1]) + && (row_ptr[x] >= row_ptr[x-theta_size]) + && (row_ptr[x] >= row_ptr[x-theta_size+1]) + && (row_ptr[x] >= row_ptr[x-1]) + && (row_ptr[x] >= row_ptr[x+1]) + && (row_ptr[x] >= row_ptr[x+theta_size-1]) + && (row_ptr[x] >= row_ptr[x+theta_size]) + && (row_ptr[x] >= row_ptr[x+theta_size+1])) { + + find_lines_list_lnk_data_t lnk_line; + memset(&lnk_line, 0, sizeof(find_lines_list_lnk_data_t)); + + lnk_line.magnitude = row_ptr[x]; + lnk_line.theta = (x - 1) * hough_divide; // remove offset + lnk_line.rho = (y - r_diag_len_div) * hough_divide; + + list_push_back(out, &lnk_line); + } + } + } + + fb_free(); // acc + + for (;;) { // Merge overlapping. + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(find_lines_list_lnk_data_t)); + + while (list_size(out)) { + find_lines_list_lnk_data_t lnk_line; + list_pop_front(out, &lnk_line); + + for (size_t k = 0, l = list_size(out); k < l; k++) { + find_lines_list_lnk_data_t tmp_line; + list_pop_front(out, &tmp_line); + + int theta_0_temp = lnk_line.theta; + int theta_1_temp = tmp_line.theta; + int rho_0_temp = lnk_line.rho; + int rho_1_temp = tmp_line.rho; + + if (rho_0_temp < 0) { + rho_0_temp = -rho_0_temp; + theta_0_temp += 180; + } + + if (rho_1_temp < 0) { + rho_1_temp = -rho_1_temp; + theta_1_temp += 180; + } + + int theta_diff = abs(theta_0_temp - theta_1_temp); + int theta_diff_2 = (theta_diff >= 180) ? (360 - theta_diff) : theta_diff; + + bool theta_merge = theta_diff_2 < theta_margin; + bool rho_merge = abs(rho_0_temp - rho_1_temp) < rho_margin; + + if (theta_merge && rho_merge) { + uint32_t magnitude = lnk_line.magnitude + tmp_line.magnitude; + float sin_mean = ((sin_table[theta_0_temp] * lnk_line.magnitude) + + (sin_table[theta_1_temp] * tmp_line.magnitude)) / magnitude; + float cos_mean = ((cos_table[theta_0_temp] * lnk_line.magnitude) + + (cos_table[theta_1_temp] * tmp_line.magnitude)) / magnitude; + + lnk_line.theta = fast_roundf(fast_atan2f(sin_mean, cos_mean) * 57.295780) % 360; // * (180 / PI) + if (lnk_line.theta < 0) lnk_line.theta += 360; + lnk_line.rho = fast_roundf(((rho_0_temp * lnk_line.magnitude) + (rho_1_temp * tmp_line.magnitude)) / magnitude); + lnk_line.magnitude = magnitude / 2; + + if (lnk_line.theta >= 180) { + lnk_line.rho = -lnk_line.rho; + lnk_line.theta -= 180; + } + + merge_occured = true; + } else { + list_push_back(out, &tmp_line); + } + } + + list_push_back(&out_temp, &lnk_line); + } + + list_copy(out, &out_temp); + + if (!merge_occured) { + break; + } + } + + for (size_t i = 0, j = list_size(out); i < j; i++) { + find_lines_list_lnk_data_t lnk_line; + list_pop_front(out, &lnk_line); + + if ((45 <= lnk_line.theta) && (lnk_line.theta < 135)) { + // y = (r - x cos(t)) / sin(t) + lnk_line.line.x1 = 0; + lnk_line.line.y1 = fast_roundf((lnk_line.rho - (lnk_line.line.x1 * cos_table[lnk_line.theta])) / sin_table[lnk_line.theta]); + lnk_line.line.x2 = roi->w - 1; + lnk_line.line.y2 = fast_roundf((lnk_line.rho - (lnk_line.line.x2 * cos_table[lnk_line.theta])) / sin_table[lnk_line.theta]); + } else { + // x = (r - y sin(t)) / cos(t); + lnk_line.line.y1 = 0; + lnk_line.line.x1 = fast_roundf((lnk_line.rho - (lnk_line.line.y1 * sin_table[lnk_line.theta])) / cos_table[lnk_line.theta]); + lnk_line.line.y2 = roi->h - 1; + lnk_line.line.x2 = fast_roundf((lnk_line.rho - (lnk_line.line.y2 * sin_table[lnk_line.theta])) / cos_table[lnk_line.theta]); + } + + if(lb_clip_line(&lnk_line.line, 0, 0, roi->w, roi->h)) { + lnk_line.line.x1 += roi->x; + lnk_line.line.y1 += roi->y; + lnk_line.line.x2 += roi->x; + lnk_line.line.y2 += roi->y; + + // Move rho too. + lnk_line.rho += fast_roundf((roi->x * cos_table[lnk_line.theta]) + (roi->y * sin_table[lnk_line.theta])); + list_push_back(out, &lnk_line); + } + } +} +#endif //IMLIB_ENABLE_FIND_LINES + +#ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS +// Note this function is not used anymore, see lsd.c +void imlib_find_line_segments(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int theta_margin, unsigned int rho_margin, + uint32_t segment_threshold) +{ + const unsigned int max_theta_diff = 15; + const unsigned int max_gap_pixels = 5; + + list_t temp_out; + imlib_find_lines(&temp_out, ptr, roi, x_stride, y_stride, threshold, theta_margin, rho_margin); + list_init(out, sizeof(find_lines_list_lnk_data_t)); + + const int r_diag_len = fast_roundf(fast_sqrtf((roi->w * roi->w) + (roi->h * roi->h))) * 2; + int *theta_buffer = fb_alloc(sizeof(int) * r_diag_len); + uint32_t *mag_buffer = fb_alloc(sizeof(uint32_t) * r_diag_len); + point_t *point_buffer = fb_alloc(sizeof(point_t) * r_diag_len); + + for (size_t i = 0; list_size(&temp_out); i++) { + find_lines_list_lnk_data_t lnk_data; + list_pop_front(&temp_out, &lnk_data); + + list_t line_out; + list_init(&line_out, sizeof(find_lines_list_lnk_data_t)); + + for (int k = -2; k <= 2; k += 2) { + line_t l; + + if (abs(lnk_data.line.x2 - lnk_data.line.x1) >= abs(lnk_data.line.y2 - lnk_data.line.y1)) { + // the line is more horizontal than vertical + l.x1 = lnk_data.line.x1; + l.y1 = lnk_data.line.y1 + k; + l.x2 = lnk_data.line.x2; + l.y2 = lnk_data.line.y2 + k; + } else { + // the line is more vertical than horizontal + l.x1 = lnk_data.line.x1 + k; + l.y1 = lnk_data.line.y1; + l.x2 = lnk_data.line.x2 + k; + l.y2 = lnk_data.line.y2; + } + + if(!lb_clip_line(&l, 0, 0, ptr->w, ptr->h)) { + continue; + } + + find_lines_list_lnk_data_t tmp_line; + tmp_line.magnitude = lnk_data.magnitude; + tmp_line.theta = lnk_data.theta; + tmp_line.rho = lnk_data.rho; + + size_t index = trace_line(ptr, &l, theta_buffer, mag_buffer, point_buffer); + unsigned int max_gap = 0; + + for (size_t j = 0; j < index; j++) { + int theta_diff = abs(tmp_line.theta - theta_buffer[j]); + int theta_diff_2 = (theta_diff >= 90) ? (180 - theta_diff) : theta_diff; + bool ok = (mag_buffer[j] >= segment_threshold) && (theta_diff_2 <= max_theta_diff); + + if (!max_gap) { + if (ok) { + max_gap = max_gap_pixels + 1; // (start) auto connect segments max_gap_pixels px apart... + tmp_line.line.x1 = point_buffer[j].x; + tmp_line.line.y1 = point_buffer[j].y; + tmp_line.line.x2 = point_buffer[j].x; + tmp_line.line.y2 = point_buffer[j].y; + } + } else { + if (ok) { + max_gap = max_gap_pixels + 1; // (reset) auto connect segments max_gap_pixels px apart... + tmp_line.line.x2 = point_buffer[j].x; + tmp_line.line.y2 = point_buffer[j].y; + } else if (!--max_gap) { + list_push_back(&line_out, &tmp_line); + } + } + } + + if (max_gap) { + list_push_back(&line_out, &tmp_line); + } + } + + merge_alot(&line_out, max_gap_pixels + 1, max_theta_diff); + + while (list_size(&line_out)) { + find_lines_list_lnk_data_t lnk_line; + list_pop_front(&line_out, &lnk_line); + list_push_back(out, &lnk_line); + } + } + + merge_alot(out, max_gap_pixels + 1, max_theta_diff); + + fb_free(); // point_buffer + fb_free(); // mag_buffer + fb_free(); // theta_buffer +} +#endif //IMLIB_ENABLE_FIND_LINE_SEGMENTS + +#ifdef IMLIB_ENABLE_FIND_CIRCLES +void imlib_find_circles(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int x_margin, unsigned int y_margin, unsigned int r_margin, + unsigned int r_min, unsigned int r_max, unsigned int r_step) +{ + uint16_t *theta_acc = fb_alloc0(sizeof(uint16_t) * roi->w * roi->h); + uint16_t *magnitude_acc = fb_alloc0(sizeof(uint16_t) * roi->w * roi->h); + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 360; // * (180 / PI) + if (theta < 0) theta += 360; + int magnitude = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + int index = (roi->w * (y - roi->y)) + (x - roi->x); + + theta_acc[index] = theta; + magnitude_acc[index] = magnitude; + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x - 1); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + 1); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ptr->w; + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 360; // * (180 / PI) + if (theta < 0) theta += 360; + int magnitude = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + int index = (roi->w * (y - roi->y)) + (x - roi->x); + + theta_acc[index] = theta; + magnitude_acc[index] = magnitude; + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y + 1, yy = roi->y + roi->h - 1; y < yy; y += y_stride) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride) + 1, xx = roi->x + roi->w - 1; x < xx; x += x_stride) { + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + row_ptr -= ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x - 1)); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + 1)); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + row_ptr -= ptr->w; + + int theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 360; // * (180 / PI) + if (theta < 0) theta += 360; + int magnitude = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + int index = (roi->w * (y - roi->y)) + (x - roi->x); + + theta_acc[index] = theta; + magnitude_acc[index] = magnitude; + } + } + break; + } + default: { + break; + } + } + + // Theta Direction (% 180) + // + // 0,0 X_MAX + // + // 090 + // 000 000 + // 090 + // + // Y_MAX + + // Theta Direction (% 360) + // + // 0,0 X_MAX + // + // 090 + // 000 180 + // 270 + // + // Y_MAX + + list_init(out, sizeof(find_circles_list_lnk_data_t)); + + for (int r = r_min, rr = r_max; r < rr; r += r_step) { // ignore r = 0/1 + int a_size, b_size, hough_divide = 1; // divides a and b accumulators + int w_size = roi->w - (2 * r); + int h_size = roi->h - (2 * r); + + for (;;) { // shrink to fit... + a_size = 1 + ((w_size + hough_divide - 1) / hough_divide) + 1; // left & right padding + b_size = 1 + ((h_size + hough_divide - 1) / hough_divide) + 1; // top & bottom padding + if ((sizeof(uint32_t) * a_size * b_size) <= fb_avail()) break; + hough_divide = hough_divide << 1; // powers of 2... + if (hough_divide > 4) fb_alloc_fail(); // support 1, 2, 4 + } + + uint32_t *acc = fb_alloc0(sizeof(uint32_t) * a_size * b_size); + + for (int y = 0, yy = roi->h; y < yy; y++) { + for (int x = 0, xx = roi->w; x < xx; x++) { + int index = (roi->w * y) + x; + int theta = theta_acc[index]; + int magnitude = magnitude_acc[index]; + if (!magnitude) continue; + + // We have to do the below step twice because the gradient may be pointing inside or outside the circle. + // Only graidents pointing inside of the circle sum up to produce a large magnitude. + + for (;;) { // Hi to lo edge direction + int a = fast_roundf(x + (r * cos_table[theta])) - r; + if ((a < 0) || (w_size <= a)) break; // circle doesn't fit in the window + int b = fast_roundf(y + (r * sin_table[theta])) - r; + if ((b < 0) || (h_size <= b)) break; // circle doesn't fit in the window + int acc_index = (((b / hough_divide) + 1) * a_size) + ((a / hough_divide) + 1); // add offset + + int acc_value = acc[acc_index] += magnitude; + acc[acc_index] = acc_value; + break; + } + + for (;;) { // Lo to hi edge direction + int a = fast_roundf(x + (r * cos_table[(theta + 180) % 360])) - r; + if ((a < 0) || (w_size <= a)) break; // circle doesn't fit in the window + int b = fast_roundf(y + (r * sin_table[(theta + 180) % 360])) - r; + if ((b < 0) || (h_size <= b)) break; // circle doesn't fit in the window + int acc_index = (((b / hough_divide) + 1) * a_size) + ((a / hough_divide) + 1); // add offset + + int acc_value = acc[acc_index] += magnitude; + acc[acc_index] = acc_value; + break; + } + } + } + + for (int y = 1, yy = b_size - 1; y < yy; y++) { + uint32_t *row_ptr = acc + (a_size * y); + + for (int x = 1, xx = a_size - 1; x < xx; x++) { + if ((row_ptr[x] >= threshold) + && (row_ptr[x] >= row_ptr[x-a_size-1]) + && (row_ptr[x] >= row_ptr[x-a_size]) + && (row_ptr[x] >= row_ptr[x-a_size+1]) + && (row_ptr[x] >= row_ptr[x-1]) + && (row_ptr[x] >= row_ptr[x+1]) + && (row_ptr[x] >= row_ptr[x+a_size-1]) + && (row_ptr[x] >= row_ptr[x+a_size]) + && (row_ptr[x] >= row_ptr[x+a_size+1])) { + + find_circles_list_lnk_data_t lnk_data; + lnk_data.magnitude = row_ptr[x]; + lnk_data.p.x = ((x - 1) * hough_divide) + r + roi->x; // remove offset + lnk_data.p.y = ((y - 1) * hough_divide) + r + roi->y; // remove offset + lnk_data.r = r; + + list_push_back(out, &lnk_data); + } + } + } + + fb_free(); // acc + } + + fb_free(); // magnitude_acc + fb_free(); // theta_acc + + for (;;) { // Merge overlapping. + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(find_circles_list_lnk_data_t)); + + while (list_size(out)) { + find_circles_list_lnk_data_t lnk_data; + list_pop_front(out, &lnk_data); + + for (size_t k = 0, l = list_size(out); k < l; k++) { + find_circles_list_lnk_data_t tmp_data; + list_pop_front(out, &tmp_data); + + bool x_diff_ok = abs(lnk_data.p.x - tmp_data.p.x) < x_margin; + bool y_diff_ok = abs(lnk_data.p.y - tmp_data.p.y) < y_margin; + bool r_diff_ok = abs(lnk_data.r - tmp_data.r) < r_margin; + + if (x_diff_ok && y_diff_ok && r_diff_ok) { + uint32_t magnitude = lnk_data.magnitude + tmp_data.magnitude; + lnk_data.p.x = ((lnk_data.p.x * lnk_data.magnitude) + (tmp_data.p.x * tmp_data.magnitude)) / magnitude; + lnk_data.p.y = ((lnk_data.p.y * lnk_data.magnitude) + (tmp_data.p.y * tmp_data.magnitude)) / magnitude; + lnk_data.r = ((lnk_data.r * lnk_data.magnitude) + (tmp_data.r * tmp_data.magnitude)) / magnitude; + lnk_data.magnitude = magnitude / 2; + merge_occured = true; + } else { + list_push_back(out, &tmp_data); + } + } + + list_push_back(&out_temp, &lnk_data); + } + + list_copy(out, &out_temp); + + if (!merge_occured) { + break; + } + } +} +#endif //IMLIB_ENABLE_FIND_CIRCLES diff --git a/src/openmv/src/omv/img/imlib.c b/src/openmv/src/omv/img/imlib.c new file mode 100755 index 0000000..d1e87b7 --- /dev/null +++ b/src/openmv/src/omv/img/imlib.c @@ -0,0 +1,898 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Image library. + * + */ +#include +#include +#include "font.h" +#include "array.h" +#include "ff_wrapper.h" +#include "imlib.h" +#include "common.h" +#include "omv_boardconfig.h" + +///////////////// +// Point Stuff // +///////////////// + +void point_init(point_t *ptr, int x, int y) +{ + ptr->x = x; + ptr->y = y; +} + +void point_copy(point_t *dst, point_t *src) +{ + memcpy(dst, src, sizeof(point_t)); +} + +bool point_equal_fast(point_t *ptr0, point_t *ptr1) +{ + return !memcmp(ptr0, ptr1, sizeof(point_t)); +} + +int point_quadrance(point_t *ptr0, point_t *ptr1) +{ + int delta_x = ptr0->x - ptr1->x; + int delta_y = ptr0->y - ptr1->y; + return (delta_x * delta_x) + (delta_y * delta_y); +} + +//////////////// +// Line Stuff // +//////////////// + +// http://www.skytopia.com/project/articles/compsci/clipping.html +bool lb_clip_line(line_t *l, int x, int y, int w, int h) // line is drawn if this returns true +{ + int xdelta = l->x2 - l->x1, ydelta = l->y2 - l->y1, p[4], q[4]; + float umin = 0, umax = 1; + + p[0] = -(xdelta); + p[1] = +(xdelta); + p[2] = -(ydelta); + p[3] = +(ydelta); + + q[0] = l->x1 - (x); + q[1] = (x + w - 1) - l->x1; + q[2] = l->y1 - (y); + q[3] = (y + h - 1) - l->y1; + + for (int i = 0; i < 4; i++) { + if (p[i]) { + float u = ((float) q[i]) / ((float) p[i]); + + if (p[i] < 0) { // outside to inside + if (u > umax) return false; + if (u > umin) umin = u; + } + + if (p[i] > 0) { // inside to outside + if (u < umin) return false; + if (u < umax) umax = u; + } + + } else if (q[i] < 0) { + return false; + } + } + + if (umax < umin) return false; + + int x1_c = l->x1 + (xdelta * umin); + int y1_c = l->y1 + (ydelta * umin); + int x2_c = l->x1 + (xdelta * umax); + int y2_c = l->y1 + (ydelta * umax); + l->x1 = x1_c; + l->y1 = y1_c; + l->x2 = x2_c; + l->y2 = y2_c; + + return true; +} + +///////////////////// +// Rectangle Stuff // +///////////////////// + +void rectangle_init(rectangle_t *ptr, int x, int y, int w, int h) +{ + ptr->x = x; + ptr->y = y; + ptr->w = w; + ptr->h = h; +} + +void rectangle_copy(rectangle_t *dst, rectangle_t *src) +{ + memcpy(dst, src, sizeof(rectangle_t)); +} + +bool rectangle_equal_fast(rectangle_t *ptr0, rectangle_t *ptr1) +{ + return !memcmp(ptr0, ptr1, sizeof(rectangle_t)); +} + +bool rectangle_overlap(rectangle_t *ptr0, rectangle_t *ptr1) +{ + int x0 = ptr0->x; + int y0 = ptr0->y; + int w0 = ptr0->w; + int h0 = ptr0->h; + int x1 = ptr1->x; + int y1 = ptr1->y; + int w1 = ptr1->w; + int h1 = ptr1->h; + return (x0 < (x1 + w1)) && (y0 < (y1 + h1)) && (x1 < (x0 + w0)) && (y1 < (y0 + h0)); +} + +void rectangle_intersected(rectangle_t *dst, rectangle_t *src) +{ + int leftX = IM_MAX(dst->x, src->x); + int topY = IM_MAX(dst->y, src->y); + int rightX = IM_MIN(dst->x + dst->w, src->x + src->w); + int bottomY = IM_MIN(dst->y + dst->h, src->y + src->h); + dst->x = leftX; + dst->y = topY; + dst->w = rightX - leftX; + dst->h = bottomY - topY; +} + +void rectangle_united(rectangle_t *dst, rectangle_t *src) +{ + int leftX = IM_MIN(dst->x, src->x); + int topY = IM_MIN(dst->y, src->y); + int rightX = IM_MAX(dst->x + dst->w, src->x + src->w); + int bottomY = IM_MAX(dst->y + dst->h, src->y + src->h); + dst->x = leftX; + dst->y = topY; + dst->w = rightX - leftX; + dst->h = bottomY - topY; +} + +///////////////// +// Image Stuff // +///////////////// + +void image_init(image_t *ptr, int w, int h, int bpp, void *data) +{ + ptr->w = w; + ptr->h = h; + ptr->bpp = bpp; + ptr->data = data; +} + +void image_copy(image_t *dst, image_t *src) +{ + memcpy(dst, src, sizeof(image_t)); +} + +size_t image_size(image_t *ptr) +{ + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + return IMAGE_BINARY_LINE_LEN_BYTES(ptr) * ptr->h; + } + case IMAGE_BPP_GRAYSCALE: { + return IMAGE_GRAYSCALE_LINE_LEN_BYTES(ptr) * ptr->h; + } + case IMAGE_BPP_RGB565: { + return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h; + } + case IMAGE_BPP_BAYER: { + return ptr->w * ptr->h; + } + default: { // JPEG + return ptr->bpp; + } + } +} + +bool image_get_mask_pixel(image_t *ptr, int x, int y) +{ + if ((0 <= x) && (x < ptr->w) && (0 <= y) && (y < ptr->h)) { + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + return IMAGE_GET_BINARY_PIXEL(ptr, x, y); + } + case IMAGE_BPP_GRAYSCALE: { + return COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL(ptr, x, y)); + } + case IMAGE_BPP_RGB565: { + return COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL(ptr, x, y)); + } + default: { + return false; + } + } + } + + return false; +} + +// Gamma uncompress +extern const float xyz_table[256]; + +const int8_t kernel_gauss_3[3*3] = { + 1, 2, 1, + 2, 4, 2, + 1, 2, 1, +}; + +const int8_t kernel_gauss_5[5*5] = { + 1, 4, 6, 4, 1, + 4, 16, 24, 16, 4, + 6, 24, 36, 24, 6, + 4, 16, 24, 16, 4, + 1, 4, 6, 4, 1 +}; + +const int kernel_laplacian_3[3*3] = { + -1, -1, -1, + -1, 8, -1, + -1, -1, -1 +}; + +const int kernel_high_pass_3[3*3] = { + -1, -1, -1, + -1, +8, -1, + -1, -1, -1 +}; + +// USE THE LUT FOR RGB->LAB CONVERSION - NOT THIS FUNCTION! +void imlib_rgb_to_lab(simple_color_t *rgb, simple_color_t *lab) +{ + // https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation + // https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions + + float r_lin = xyz_table[rgb->red]; + float g_lin = xyz_table[rgb->green]; + float b_lin = xyz_table[rgb->blue]; + + float x = ((r_lin * 0.4124f) + (g_lin * 0.3576f) + (b_lin * 0.1805f)) / 095.047f; + float y = ((r_lin * 0.2126f) + (g_lin * 0.7152f) + (b_lin * 0.0722f)) / 100.000f; + float z = ((r_lin * 0.0193f) + (g_lin * 0.1192f) + (b_lin * 0.9505f)) / 108.883f; + + x = (x>0.008856f) ? fast_cbrtf(x) : ((x * 7.787037f) + 0.137931f); + y = (y>0.008856f) ? fast_cbrtf(y) : ((y * 7.787037f) + 0.137931f); + z = (z>0.008856f) ? fast_cbrtf(z) : ((z * 7.787037f) + 0.137931f); + + lab->L = ((int8_t) fast_roundf(116 * y)) - 16; + lab->A = ((int8_t) fast_roundf(500 * (x-y))); + lab->B = ((int8_t) fast_roundf(200 * (y-z))); +} + +void imlib_lab_to_rgb(simple_color_t *lab, simple_color_t *rgb) +{ + // https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions + // https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation + + float x = ((lab->L + 16) * 0.008621f) + (lab->A * 0.002f); + float y = ((lab->L + 16) * 0.008621f); + float z = ((lab->L + 16) * 0.008621f) - (lab->B * 0.005f); + + x = ((x>0.206897f) ? (x*x*x) : ((0.128419f * x) - 0.017713f)) * 095.047f; + y = ((y>0.206897f) ? (y*y*y) : ((0.128419f * y) - 0.017713f)) * 100.000f; + z = ((z>0.206897f) ? (z*z*z) : ((0.128419f * z) - 0.017713f)) * 108.883f; + + float r_lin = ((x * +3.2406f) + (y * -1.5372f) + (z * -0.4986f)) / 100.0f; + float g_lin = ((x * -0.9689f) + (y * +1.8758f) + (z * +0.0415f)) / 100.0f; + float b_lin = ((x * +0.0557f) + (y * -0.2040f) + (z * +1.0570f)) / 100.0f; + + r_lin = (r_lin>0.0031308f) ? ((1.055f*powf(r_lin, 0.416666f))-0.055f) : (r_lin*12.92f); + g_lin = (g_lin>0.0031308f) ? ((1.055f*powf(g_lin, 0.416666f))-0.055f) : (g_lin*12.92f); + b_lin = (b_lin>0.0031308f) ? ((1.055f*powf(b_lin, 0.416666f))-0.055f) : (b_lin*12.92f); + + rgb->red = IM_MAX(IM_MIN(fast_roundf(r_lin * 255), 255), 0); + rgb->green = IM_MAX(IM_MIN(fast_roundf(g_lin * 255), 255), 0); + rgb->blue = IM_MAX(IM_MIN(fast_roundf(b_lin * 255), 255), 0); +} + +void imlib_rgb_to_grayscale(simple_color_t *rgb, simple_color_t *grayscale) +{ + float r_lin = xyz_table[rgb->red]; + float g_lin = xyz_table[rgb->green]; + float b_lin = xyz_table[rgb->blue]; + float y = ((r_lin * 0.2126f) + (g_lin * 0.7152f) + (b_lin * 0.0722f)) / 100.0f; + y = (y>0.0031308f) ? ((1.055f*powf(y, 0.416666f))-0.055f) : (y*12.92f); + grayscale->G = IM_MAX(IM_MIN(fast_roundf(y * 255), 255), 0); +} + +// Just copy settings back. +void imlib_grayscale_to_rgb(simple_color_t *grayscale, simple_color_t *rgb) +{ + rgb->red = grayscale->G; + rgb->green = grayscale->G; + rgb->blue = grayscale->G; +} + +ALWAYS_INLINE uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v) +{ + uint32_t r = IM_MAX(IM_MIN(y + ((91881*v)>>16), 255), 0); + uint32_t g = IM_MAX(IM_MIN(y - (((22554*u)+(46802*v))>>16), 255), 0); + uint32_t b = IM_MAX(IM_MIN(y + ((116130*u)>>16), 255), 0); + return IM_RGB565(IM_R825(r), IM_G826(g), IM_B825(b)); +} + +void imlib_bayer_to_rgb565(image_t *img, int w, int h, int xoffs, int yoffs, uint16_t *rgbbuf) +{ + int r, g, b; + for (int y=yoffs; y> 2; + + g = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y+1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x-1, y) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x+1, y)) >> 2; + + b = IM_GET_RAW_PIXEL(img, x, y); + } else { // Odd col + r = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y+1)) >> 1; + + b = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x-1, y) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x+1, y)) >> 1; + + g = IM_GET_RAW_PIXEL(img, x, y); + } + } else { // Odd row + if ((x % 2) == 0) { // Even Col + r = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x-1, y) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x+1, y)) >> 1; + + g = IM_GET_RAW_PIXEL(img, x, y); + + b = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y+1)) >> 1; + } else { // Odd col + r = IM_GET_RAW_PIXEL(img, x, y); + + g = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y+1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x-1, y) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x+1, y)) >> 2; + + b = (IM_GET_RAW_PIXEL_CHECK_BOUNDS_XY(img, x-1, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_XY(img, x+1, y-1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_XY(img, x-1, y+1) + + IM_GET_RAW_PIXEL_CHECK_BOUNDS_XY(img, x+1, y+1)) >> 2; + } + + } + r = IM_R825(r); + g = IM_G826(g); + b = IM_B825(b); + *rgbbuf++ = IM_RGB565(r, g, b); + } + } +} +//////////////////////////////////////////////////////////////////////////////// + +static save_image_format_t imblib_parse_extension(image_t *img, const char *path) +{ + size_t l = strlen(path); + const char *p = path + l; + if (l >= 5) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'e') || (p[-2] == 'E')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == 'j') || (p[-4] == 'J')) + && ((p[-5] == '.') || (p[-5] == '.'))) { + // Will convert to JPG if not. + return FORMAT_JPG; + } + } + if (l >= 4) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'j') || (p[-3] == 'J')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + // Will convert to JPG if not. + return FORMAT_JPG; + } else if (((p[-1] == 'p') || (p[-1] == 'P')) + && ((p[-2] == 'm') || (p[-2] == 'M')) + && ((p[-3] == 'b') || (p[-3] == 'B')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (IM_IS_JPEG(img) || IM_IS_BAYER(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Image is not BMP!")); + } + return FORMAT_BMP; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_RGB565(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Image is not PPM!")); + } + return FORMAT_PNM; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'g') || (p[-2] == 'G')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_GS(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Image is not PGM!")); + } + return FORMAT_PNM; + } else if (((p[-1] == 'w') || (p[-1] == 'W')) + && ((p[-2] == 'a') || (p[-2] == 'A')) + && ((p[-3] == 'r') || (p[-3] == 'R')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_BAYER(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Image is not BAYER!")); + } + return FORMAT_RAW; + } + + } + return FORMAT_DONT_CARE; +} + +bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) +{ + file_read_open(fp, path); + char magic[2]; + read_data(fp, &magic, 2); + file_close(fp); + + bool vflipped = false; + if ((magic[0]=='P') + && ((magic[1]=='2') || (magic[1]=='3') + || (magic[1]=='5') || (magic[1]=='6'))) { // PPM + rs->format = FORMAT_PNM; + file_read_open(fp, path); + file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER! + ppm_read_geometry(fp, img, path, &rs->ppm_rs); + } else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP + rs->format = FORMAT_BMP; + file_read_open(fp, path); + file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER! + vflipped = bmp_read_geometry(fp, img, path, &rs->bmp_rs); + } else { + ff_unsupported_format(NULL); + } + imblib_parse_extension(img, path); // Enforce extension! + return vflipped; +} + +static void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs) +{ + switch (rs->format) { + case FORMAT_BMP: + bmp_read_pixels(fp, img, line_start, line_end, &rs->bmp_rs); + break; + case FORMAT_PNM: + ppm_read_pixels(fp, img, line_start, line_end, &rs->ppm_rs); + break; + default: // won't happen + break; + } +} + +void imlib_image_operation(image_t *img, const char *path, image_t *other, int scalar, line_op_t op, void *data) +{ + if (path) { + uint32_t size = fb_avail() / 2; + void *alloc = fb_alloc(size); // We have to do this before the read. + // This code reads a window of an image in at a time and then executes + // the line operation on each line in that window before moving to the + // next window. The vflipped part is here because BMP files can be saved + // vertically flipped resulting in us reading the image backwards. + FIL fp; + image_t temp; + img_read_settings_t rs; + bool vflipped = imlib_read_geometry(&fp, &temp, path, &rs); + if (!IM_EQUAL(img, &temp)) { + ff_not_equal(&fp); + } + // When processing vertically flipped images the read function will fill + // the window up from the bottom. The read function assumes that the + // window is equal to an image in size. However, since this is not the + // case we shrink the window size to how many lines we're buffering. + temp.pixels = alloc; + temp.h = (size / (temp.w * temp.bpp)); // round down + // This should never happen unless someone forgot to free. + if ((!temp.pixels) || (!temp.h)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, + "Not enough memory available!")); + } + for (int i=0; ih; i+=temp.h) { // goes past end + int can_do = IM_MIN(temp.h, img->h-i); + imlib_read_pixels(&fp, &temp, 0, can_do, &rs); + for (int j=0; jh-i-can_do)+j, temp.pixels+(temp.w*temp.bpp*j), data, true); + } + } + } + file_buffer_off(&fp); + file_close(&fp); + fb_free(); + } else if (other) { + if (!IM_EQUAL(img, other)) { + ff_not_equal(NULL); + } + switch (img->bpp) { + case IMAGE_BPP_BINARY: { + for (int i=0, ii=img->h; ih; ih; ibpp) { + case IMAGE_BPP_BINARY: { + uint32_t *row_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img)); + + for (int i=0, ii=img->w; ih; iw; ih; iw; ih; ipixels, img->w * img->h); + file_close(&fp); + break; + } + case FORMAT_JPG: + jpeg_write(img, path, quality); + break; + case FORMAT_DONT_CARE: + // Path doesn't have an extension. + if (IM_IS_JPEG(img)) { + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg"); + jpeg_write(img, new_path, quality); + fb_free(); + } else if (IM_IS_BAYER(img)) { + FIL fp; + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".raw"); + file_write_open(&fp, new_path); + write_data(&fp, img->pixels, img->w * img->h); + file_close(&fp); + fb_free(); + } else { // RGB or GS, save as BMP. + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp"); + bmp_write_subimg(img, new_path, roi); + fb_free(); + } + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// A simple algorithm for correcting lens distortion. +// See http://www.tannerhelland.com/4743/simple-algorithm-correcting-lens-distortion/ +void imlib_lens_corr(image_t *img, float strength, float zoom) +{ + zoom = 1 / zoom; + int halfWidth = img->w / 2; + int halfHeight = img->h / 2; + float lens_corr_radius = strength / fast_sqrtf((img->w * img->w) + (img->h * img->h)); + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + // Create a temp copy of the image to pull pixels from. + uint32_t *tmp = fb_alloc(((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + memcpy(tmp, img->data, ((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + memset(img->data, 0, ((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * img->h); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + int newY = y - halfHeight; + int newY2 = newY * newY; + float zoomedY = newY * zoom; + + for (int x = 0, xx = img->w; x < xx; x++) { + int newX = x - halfWidth; + int newX2 = newX * newX; + float zoomedX = newX * zoom; + + float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); + float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); + int sourceX = halfWidth + fast_roundf(theta * zoomedX); + int sourceY = halfHeight + fast_roundf(theta * zoomedY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint32_t *ptr = tmp + (((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * sourceY); + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(ptr, sourceX); + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + case IMAGE_BPP_GRAYSCALE: { + // Create a temp copy of the image to pull pixels from. + uint8_t *tmp = fb_alloc(img->w * img->h * sizeof(uint8_t)); + memcpy(tmp, img->data, img->w * img->h * sizeof(uint8_t)); + memset(img->data, 0, img->w * img->h * sizeof(uint8_t)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + int newY = y - halfHeight; + int newY2 = newY * newY; + float zoomedY = newY * zoom; + + for (int x = 0, xx = img->w; x < xx; x++) { + int newX = x - halfWidth; + int newX2 = newX * newX; + float zoomedX = newX * zoom; + + float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); + float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); + int sourceX = halfWidth + fast_roundf(theta * zoomedX); + int sourceY = halfHeight + fast_roundf(theta * zoomedY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint8_t *ptr = tmp + (img->w * sourceY); + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(ptr, sourceX); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + case IMAGE_BPP_RGB565: { + // Create a temp copy of the image to pull pixels from. + uint16_t *tmp = fb_alloc(img->w * img->h * sizeof(uint16_t)); + memcpy(tmp, img->data, img->w * img->h * sizeof(uint16_t)); + memset(img->data, 0, img->w * img->h * sizeof(uint16_t)); + + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + int newY = y - halfHeight; + int newY2 = newY * newY; + float zoomedY = newY * zoom; + + for (int x = 0, xx = img->w; x < xx; x++) { + int newX = x - halfWidth; + int newX2 = newX * newX; + float zoomedX = newX * zoom; + + float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); + float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); + int sourceX = halfWidth + fast_roundf(theta * zoomedX); + int sourceY = halfHeight + fast_roundf(theta * zoomedY); + + if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { + uint16_t *ptr = tmp + (img->w * sourceY); + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(ptr, sourceX); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + + fb_free(); + break; + } + default: { + break; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +int imlib_image_mean(image_t *src, int *r_mean, int *g_mean, int *b_mean) +{ + int r_s = 0; + int g_s = 0; + int b_s = 0; + int n = src->w * src->h; + + switch(src->bpp) { + case IMAGE_BPP_BINARY: { + // Can't run this on a binary image. + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int i=0; ipixels[i]; + } + *r_mean = r_s/n; + *g_mean = r_s/n; + *b_mean = r_s/n; + break; + } + case IMAGE_BPP_RGB565: { + for (int i=0; ipixels)[i]; + r_s += COLOR_RGB565_TO_R8(p); + g_s += COLOR_RGB565_TO_G8(p); + b_s += COLOR_RGB565_TO_B8(p); + } + *r_mean = r_s/n; + *g_mean = g_s/n; + *b_mean = b_s/n; + break; + } + default: { + break; + } + } + + return 0; +} + +#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ + ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) + +#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ + ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) + +#define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ + ((int64_t)(ARG3) << 32U) ) >> 32U)) + +/*hutu:should rewrite*/ +#define __SMLAD(ARG1,ARG2,ARG3) (ARG3) + +// One pass standard deviation. +int imlib_image_std(image_t *src) +{ + int w=src->w; + int h=src->h; + int n=w*h; + uint8_t *data=src->pixels; + + uint32_t s=0, sq=0; + for (int i=0; iw * 2 * sizeof(*buffer)); + + // NOTE: This doesn't deal with borders right now. Adding if + // statements in the inner loop will slow it down significantly. + for (int y=0; yh-ksize; y++) { + for (int x=0; xw-ksize; x+=ksize) { + for (int k=0; kw) + x+k] = acc; + } + } + if (y > 0) { + // flush buffer + for (int x=0; xw-ksize; x++) { + int acc = 0; + acc = __SMLAD(krn[0], buffer[((y-1)%2) * img->w + x + 0], acc); + acc = __SMLAD(krn[1], buffer[((y-1)%2) * img->w + x + 1], acc); + acc = __SMLAD(krn[2], buffer[((y-1)%2) * img->w + x + 2], acc); + acc = (acc * m) + b; // scale, offset, and clamp + acc = IM_MAX(IM_MIN(acc, IM_MAX_GS), 0); + IM_SET_GS_PIXEL(img, (x+1), (y), acc); + } + } + } + fb_free(); +} diff --git a/src/openmv/src/omv/img/imlib.h b/src/openmv/src/omv/img/imlib.h new file mode 100755 index 0000000..c8a120f --- /dev/null +++ b/src/openmv/src/omv/img/imlib.h @@ -0,0 +1,1371 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#ifndef __IMLIB_H__ +#define __IMLIB_H__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fb_alloc.h" +#include "umm_malloc.h" +#include "xalloc.h" +#include "array.h" +#include "fmath.h" +#include "collections.h" +#include "imlib_config.h" + +#define IM_LOG2_2(x) (((x) & 0x2ULL) ? ( 2 ) : 1) // NO ({ ... }) ! +#define IM_LOG2_4(x) (((x) & 0xCULL) ? ( 2 + IM_LOG2_2((x) >> 2)) : IM_LOG2_2(x)) // NO ({ ... }) ! +#define IM_LOG2_8(x) (((x) & 0xF0ULL) ? ( 4 + IM_LOG2_4((x) >> 4)) : IM_LOG2_4(x)) // NO ({ ... }) ! +#define IM_LOG2_16(x) (((x) & 0xFF00ULL) ? ( 8 + IM_LOG2_8((x) >> 8)) : IM_LOG2_8(x)) // NO ({ ... }) ! +#define IM_LOG2_32(x) (((x) & 0xFFFF0000ULL) ? (16 + IM_LOG2_16((x) >> 16)) : IM_LOG2_16(x)) // NO ({ ... }) ! +#define IM_LOG2(x) (((x) & 0xFFFFFFFF00000000ULL) ? (32 + IM_LOG2_32((x) >> 32)) : IM_LOG2_32(x)) // NO ({ ... }) ! + +#define IM_MAX(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) +#define IM_MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) +#define IM_DIV(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; }) +#define IM_MOD(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; }) + +#define INT8_T_BITS (sizeof(int8_t) * 8) +#define INT8_T_MASK (INT8_T_BITS - 1) +#define INT8_T_SHIFT IM_LOG2(INT8_T_MASK) + +#define INT16_T_BITS (sizeof(int16_t) * 8) +#define INT16_T_MASK (INT16_T_BITS - 1) +#define INT16_T_SHIFT IM_LOG2(INT16_T_MASK) + +#define INT32_T_BITS (sizeof(int32_t) * 8) +#define INT32_T_MASK (INT32_T_BITS - 1) +#define INT32_T_SHIFT IM_LOG2(INT32_T_MASK) + +#define INT64_T_BITS (sizeof(int64_t) * 8) +#define INT64_T_MASK (INT64_T_BITS - 1) +#define INT64_T_SHIFT IM_LOG2(INT64_T_MASK) + +#define UINT8_T_BITS (sizeof(uint8_t) * 8) +#define UINT8_T_MASK (UINT8_T_BITS - 1) +#define UINT8_T_SHIFT IM_LOG2(UINT8_T_MASK) + +#define UINT16_T_BITS (sizeof(uint16_t) * 8) +#define UINT16_T_MASK (UINT16_T_BITS - 1) +#define UINT16_T_SHIFT IM_LOG2(UINT16_T_MASK) + +#define UINT32_T_BITS (sizeof(uint32_t) * 8) +#define UINT32_T_MASK (UINT32_T_BITS - 1) +#define UINT32_T_SHIFT IM_LOG2(UINT32_T_MASK) + +#define UINT64_T_BITS (sizeof(uint64_t) * 8) +#define UINT64_T_MASK (UINT64_T_BITS - 1) +#define UINT64_T_SHIFT IM_LOG2(UINT64_T_MASK) + +#define IM_DEG2RAD(x) (((x)*M_PI)/180) +#define IM_RAD2DEG(x) (((x)*180)/M_PI) + +///////////////// +// Point Stuff // +///////////////// + +typedef struct point { + int16_t x; + int16_t y; +} point_t; + +void point_init(point_t *ptr, int x, int y); +void point_copy(point_t *dst, point_t *src); +bool point_equal_fast(point_t *ptr0, point_t *ptr1); +int point_quadrance(point_t *ptr0, point_t *ptr1); + +//////////////// +// Line Stuff // +//////////////// + +typedef struct line { + int16_t x1; + int16_t y1; + int16_t x2; + int16_t y2; +} line_t; + +bool lb_clip_line(line_t *l, int x, int y, int w, int h); + +///////////////////// +// Rectangle Stuff // +///////////////////// + +typedef struct rectangle { + int16_t x; + int16_t y; + int16_t w; + int16_t h; +} rectangle_t; + +void rectangle_init(rectangle_t *ptr, int x, int y, int w, int h); +void rectangle_copy(rectangle_t *dst, rectangle_t *src); +bool rectangle_equal_fast(rectangle_t *ptr0, rectangle_t *ptr1); +bool rectangle_overlap(rectangle_t *ptr0, rectangle_t *ptr1); +void rectangle_intersected(rectangle_t *dst, rectangle_t *src); +void rectangle_united(rectangle_t *dst, rectangle_t *src); + +///////////////// +// Color Stuff // +///////////////// + +typedef struct color_thresholds_list_lnk_data +{ + uint8_t LMin, LMax; // or grayscale + int8_t AMin, AMax; + int8_t BMin, BMax; +} +color_thresholds_list_lnk_data_t; + +#define COLOR_THRESHOLD_BINARY(pixel, threshold, invert) \ +({ \ + __typeof__ (pixel) _pixel = (pixel); \ + __typeof__ (threshold) _threshold = (threshold); \ + __typeof__ (invert) _invert = (invert); \ + ((_threshold->LMin <= _pixel) && (_pixel <= _threshold->LMax)) ^ _invert; \ +}) + +#define COLOR_THRESHOLD_GRAYSCALE(pixel, threshold, invert) \ +({ \ + __typeof__ (pixel) _pixel = (pixel); \ + __typeof__ (threshold) _threshold = (threshold); \ + __typeof__ (invert) _invert = (invert); \ + ((_threshold->LMin <= _pixel) && (_pixel <= _threshold->LMax)) ^ _invert; \ +}) + +#define COLOR_THRESHOLD_RGB565(pixel, threshold, invert) \ +({ \ + __typeof__ (pixel) _pixel = (pixel); \ + __typeof__ (threshold) _threshold = (threshold); \ + __typeof__ (invert) _invert = (invert); \ + uint8_t _l = COLOR_RGB565_TO_L(_pixel); \ + int8_t _a = COLOR_RGB565_TO_A(_pixel); \ + int8_t _b = COLOR_RGB565_TO_B(_pixel); \ + ((_threshold->LMin <= _l) && (_l <= _threshold->LMax) && \ + (_threshold->AMin <= _a) && (_a <= _threshold->AMax) && \ + (_threshold->BMin <= _b) && (_b <= _threshold->BMax)) ^ _invert; \ +}) + +#define COLOR_BOUND_BINARY(pixel0, pixel1, threshold) \ +({ \ + __typeof__ (pixel0) _pixel0 = (pixel0); \ + __typeof__ (pixel1) _pixel1 = (pixel1); \ + __typeof__ (threshold) _threshold = (threshold); \ + (abs(_pixel0 - _pixel1) <= _threshold); \ +}) + +#define COLOR_BOUND_GRAYSCALE(pixel0, pixel1, threshold) \ +({ \ + __typeof__ (pixel0) _pixel0 = (pixel0); \ + __typeof__ (pixel1) _pixel1 = (pixel1); \ + __typeof__ (threshold) _threshold = (threshold); \ + (abs(_pixel0 - _pixel1) <= _threshold); \ +}) + +#define COLOR_BOUND_RGB565(pixel0, pixel1, threshold) \ +({ \ + __typeof__ (pixel0) _pixel0 = (pixel0); \ + __typeof__ (pixel1) _pixel1 = (pixel1); \ + __typeof__ (threshold) _threshold = (threshold); \ + (abs(COLOR_RGB565_TO_R5(_pixel0) - COLOR_RGB565_TO_R5(_pixel1)) <= COLOR_RGB565_TO_R5(_threshold)) && \ + (abs(COLOR_RGB565_TO_G6(_pixel0) - COLOR_RGB565_TO_G6(_pixel1)) <= COLOR_RGB565_TO_G6(_threshold)) && \ + (abs(COLOR_RGB565_TO_B5(_pixel0) - COLOR_RGB565_TO_B5(_pixel1)) <= COLOR_RGB565_TO_B5(_threshold)); \ +}) + +#define COLOR_BINARY_MIN 0 +#define COLOR_BINARY_MAX 1 +#define COLOR_GRAYSCALE_BINARY_MIN 0x00 +#define COLOR_GRAYSCALE_BINARY_MAX 0xFF +#define COLOR_RGB565_BINARY_MIN 0x0000 +#define COLOR_RGB565_BINARY_MAX 0xFFFF + +#define COLOR_GRAYSCALE_MIN 0 +#define COLOR_GRAYSCALE_MAX 255 + +#define COLOR_R5_MIN 0 +#define COLOR_R5_MAX 31 +#define COLOR_G6_MIN 0 +#define COLOR_G6_MAX 63 +#define COLOR_B5_MIN 0 +#define COLOR_B5_MAX 31 + +#define COLOR_R8_MIN 0 +#define COLOR_R8_MAX 255 +#define COLOR_G8_MIN 0 +#define COLOR_G8_MAX 255 +#define COLOR_B8_MIN 0 +#define COLOR_B8_MAX 255 + +#define COLOR_L_MIN 0 +#define COLOR_L_MAX 100 +#define COLOR_A_MIN -128 +#define COLOR_A_MAX 127 +#define COLOR_B_MIN -128 +#define COLOR_B_MAX 127 + +#define COLOR_Y_MIN -128 +#define COLOR_Y_MAX 127 +#define COLOR_U_MIN -128 +#define COLOR_U_MAX 127 +#define COLOR_V_MIN -128 +#define COLOR_V_MAX 127 + +extern const uint8_t rb528_table[32]; +extern const uint8_t g628_table[64]; + +#define COLOR_R5_TO_R8(color) rb528_table[color] +#define COLOR_G6_TO_G8(color) g628_table[color] +#define COLOR_B5_TO_B8(color) rb528_table[color] + +extern const uint8_t rb825_table[256]; +extern const uint8_t g826_table[256]; + +#define COLOR_R8_TO_R5(color) rb825_table[color] +#define COLOR_G8_TO_G6(color) g826_table[color] +#define COLOR_B8_TO_B5(color) rb825_table[color] + +// RGB565 Stuff // + +#define COLOR_RGB565_TO_R5(pixel) (((pixel) >> 3) & 0x1F) +#define COLOR_RGB565_TO_G6(pixel) \ +({ \ + __typeof__ (pixel) _pixel = (pixel); \ + ((_pixel & 0x07) << 3) | (_pixel >> 13); \ +}) +#define COLOR_RGB565_TO_B5(pixel) (((pixel) >> 8) & 0x1F) +#define COLOR_RGB565_TO_R8(pixel) COLOR_R5_TO_R8(COLOR_RGB565_TO_R5(pixel)) +#define COLOR_RGB565_TO_G8(pixel) COLOR_G6_TO_G8(COLOR_RGB565_TO_G6(pixel)) +#define COLOR_RGB565_TO_B8(pixel) COLOR_B5_TO_B8(COLOR_RGB565_TO_B5(pixel)) + +#define COLOR_R5_G6_B5_TO_RGB565(r5, g6, b5) \ +({ \ + __typeof__ (r5) _r5 = (r5); \ + __typeof__ (g6) _g6 = (g6); \ + __typeof__ (b5) _b5 = (b5); \ + (_r5 << 3) | (_g6 >> 3) | ((_g6 & 0x7) << 13) | (_b5 << 8); \ +}) + +#define COLOR_R8_G8_B8_TO_RGB565(r8, g8, b8) COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(r8), COLOR_G8_TO_G6(g8), COLOR_B8_TO_B5(b8)) + +extern const int8_t lab_table[196608]; +extern const int8_t yuv_table[196608]; + +#define COLOR_RGB565_TO_L(pixel) lab_table[(pixel) * 3] +#define COLOR_RGB565_TO_A(pixel) lab_table[((pixel) * 3) + 1] +#define COLOR_RGB565_TO_B(pixel) lab_table[((pixel) * 3) + 2] +#define COLOR_RGB565_TO_Y(pixel) yuv_table[(pixel) * 3] +#define COLOR_RGB565_TO_U(pixel) yuv_table[((pixel) * 3) + 1] +#define COLOR_RGB565_TO_V(pixel) yuv_table[((pixel) * 3) + 2] + +// https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions +// https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation + +#define COLOR_LAB_TO_RGB565(l, a, b) \ +({ \ + __typeof__ (l) _l = (l); \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + float _x = ((_l + 16) * 0.008621f) + (_a * 0.002f); \ + float _y = ((_l + 16) * 0.008621f); \ + float _z = ((_l + 16) * 0.008621f) - (_b * 0.005f); \ + _x = ((_x > 0.206897f) ? (_x * _x * _x) : ((0.128419f * _x) - 0.017713f)) * 095.047f; \ + _y = ((_y > 0.206897f) ? (_y * _y * _y) : ((0.128419f * _y) - 0.017713f)) * 100.000f; \ + _z = ((_z > 0.206897f) ? (_z * _z * _z) : ((0.128419f * _z) - 0.017713f)) * 108.883f; \ + float _r_lin = ((_x * +3.2406f) + (_y * -1.5372f) + (_z * -0.4986f)) / 100.0f; \ + float _g_lin = ((_x * -0.9689f) + (_y * +1.8758f) + (_z * +0.0415f)) / 100.0f; \ + float _b_lin = ((_x * +0.0557f) + (_y * -0.2040f) + (_z * +1.0570f)) / 100.0f; \ + _r_lin = (_r_lin > 0.0031308f) ? ((1.055f * powf(_r_lin, 0.416666f)) - 0.055f) : (_r_lin * 12.92f); \ + _g_lin = (_g_lin > 0.0031308f) ? ((1.055f * powf(_g_lin, 0.416666f)) - 0.055f) : (_g_lin * 12.92f); \ + _b_lin = (_b_lin > 0.0031308f) ? ((1.055f * powf(_b_lin, 0.416666f)) - 0.055f) : (_b_lin * 12.92f); \ + unsigned int _rgb565_r = IM_MAX(IM_MIN(roundf(_r_lin * COLOR_R5_MAX), COLOR_R5_MAX), COLOR_R5_MIN); \ + unsigned int _rgb565_g = IM_MAX(IM_MIN(roundf(_g_lin * COLOR_G6_MAX), COLOR_G6_MAX), COLOR_G6_MIN); \ + unsigned int _rgb565_b = IM_MAX(IM_MIN(roundf(_b_lin * COLOR_B5_MAX), COLOR_B5_MAX), COLOR_B5_MIN); \ + COLOR_R5_G6_B5_TO_RGB565(_rgb565_r, _rgb565_g, _rgb565_b); \ +}) + +// https://en.wikipedia.org/wiki/YCbCr -> JPEG Conversion + +#define COLOR_YUV_TO_RGB565(y, u, v) \ +({ \ + __typeof__ (y) _y = (y); \ + __typeof__ (u) _u = (u); \ + __typeof__ (v) _v = (v); \ + unsigned int _r = IM_MAX(IM_MIN(128 + _y + ((((uint32_t) ((1.402000 * 65536) + 0.5)) * _v) >> 16), COLOR_R8_MAX), COLOR_R8_MIN); \ + unsigned int _g = IM_MAX(IM_MIN(128 + _y - (((((uint32_t) ((0.344136 * 65536) + 0.5)) * _u) + (((uint32_t) ((0.714136 * 65536) + 0.5)) * _v)) >> 16), COLOR_G8_MAX), COLOR_G8_MIN); \ + unsigned int _b = IM_MAX(IM_MIN(128 + _y + ((((uint32_t) ((1.772000 * 65536) + 0.5)) * _u) >> 16), COLOR_B8_MAX), COLOR_B8_MIN); \ + COLOR_R8_G8_B8_TO_RGB565(_r, _g, _b); \ +}) + +#define COLOR_BAYER_TO_RGB565(img, x, y, r, g, b) \ +({ \ + __typeof__ (x) __x = (x); \ + __typeof__ (y) __y = (y); \ + if ((__y % 2) == 0) { \ + if ((__x % 2) == 0) { \ + r = (IM_GET_RAW_PIXEL(img, __x-1, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x-1, __y+1) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y+1)) >> 2; \ + \ + g = (IM_GET_RAW_PIXEL(img, __x, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x, __y+1) + \ + IM_GET_RAW_PIXEL(img, __x-1, __y) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y)) >> 2; \ + \ + b = IM_GET_RAW_PIXEL(img, __x, __y); \ + } else { \ + r = (IM_GET_RAW_PIXEL(img, __x, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x, __y+1)) >> 1; \ + \ + b = (IM_GET_RAW_PIXEL(img, __x-1, __y) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y)) >> 1; \ + \ + g = IM_GET_RAW_PIXEL(img, __x, __y); \ + } \ + } else { \ + if ((__x % 2) == 0) { \ + r = (IM_GET_RAW_PIXEL(img, __x-1, __y) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y)) >> 1; \ + \ + g = IM_GET_RAW_PIXEL(img, __x, __y); \ + \ + b = (IM_GET_RAW_PIXEL(img, __x, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x, __y+1)) >> 1; \ + } else { \ + r = IM_GET_RAW_PIXEL(img, __x, __y); \ + \ + g = (IM_GET_RAW_PIXEL(img, __x, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x, __y+1) + \ + IM_GET_RAW_PIXEL(img, __x-1, __y) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y)) >> 2; \ + \ + b = (IM_GET_RAW_PIXEL(img, __x-1, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y-1) + \ + IM_GET_RAW_PIXEL(img, __x-1, __y+1) + \ + IM_GET_RAW_PIXEL(img, __x+1, __y+1)) >> 2; \ + } \ + } \ + r = IM_R825(r); \ + g = IM_G826(g); \ + b = IM_B825(b); \ +}) + +#define COLOR_BINARY_TO_GRAYSCALE(pixel) ((pixel) * COLOR_GRAYSCALE_MAX) +#define COLOR_BINARY_TO_RGB565(pixel) COLOR_YUV_TO_RGB565((pixel) * 127, 0, 0) +#define COLOR_RGB565_TO_BINARY(pixel) (COLOR_RGB565_TO_Y(pixel) > (((COLOR_Y_MAX - COLOR_Y_MIN) / 2) + COLOR_Y_MIN)) +#define COLOR_RGB565_TO_GRAYSCALE(pixel) (COLOR_RGB565_TO_Y(pixel) + 128) +#define COLOR_GRAYSCALE_TO_BINARY(pixel) ((pixel) > (((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / 2) + COLOR_GRAYSCALE_MIN)) +#define COLOR_GRAYSCALE_TO_RGB565(pixel) COLOR_YUV_TO_RGB565((pixel) - 128, 0, 0) + +///////////////// +// Image Stuff // +///////////////// + +typedef enum image_bpp +{ + IMAGE_BPP_BINARY, // BPP = 0 + IMAGE_BPP_GRAYSCALE, // BPP = 1 + IMAGE_BPP_RGB565, // BPP = 2 + IMAGE_BPP_BAYER, // BPP = 3 + IMAGE_BPP_JPEG // BPP > 3 +} +image_bpp_t; + +typedef struct image { + int w; + int h; + int bpp; + union { + uint8_t *pixels; + uint8_t *data; + }; +} image_t; + +void image_init(image_t *ptr, int w, int h, int bpp, void *data); +void image_copy(image_t *dst, image_t *src); +size_t image_size(image_t *ptr); +bool image_get_mask_pixel(image_t *ptr, int x, int y); + +#define IMAGE_IS_MUTABLE(image) \ +({ \ + __typeof__ (image) _image = (image); \ + (_image->bpp == IMAGE_BPP_BINARY) || \ + (_image->bpp == IMAGE_BPP_GRAYSCALE) || \ + (_image->bpp == IMAGE_BPP_RGB565); \ +}) + +#define IMAGE_IS_MUTABLE_BAYER(image) \ +({ \ + __typeof__ (image) _image = (image); \ + (_image->bpp == IMAGE_BPP_BINARY) || \ + (_image->bpp == IMAGE_BPP_GRAYSCALE) || \ + (_image->bpp == IMAGE_BPP_RGB565) || \ + (_image->bpp == IMAGE_BPP_BAYER); \ +}) + +#define IMAGE_BINARY_LINE_LEN(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT) +#define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t)) + +#define IMAGE_GRAYSCALE_LINE_LEN(image) ((image)->w) +#define IMAGE_GRAYSCALE_LINE_LEN_BYTES(image) (IMAGE_GRAYSCALE_LINE_LEN(image) * sizeof(uint8_t)) + +#define IMAGE_RGB565_LINE_LEN(image) ((image)->w) +#define IMAGE_RGB565_LINE_LEN_BYTES(image) (IMAGE_RGB565_LINE_LEN(image) * sizeof(uint16_t)) + +#define IMAGE_GET_BINARY_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + (((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] >> (_x & UINT32_T_MASK)) & 1; \ +}) + +#define IMAGE_PUT_BINARY_PIXEL(image, x, y, v) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + __typeof__ (v) _v = (v); \ + size_t _i = (((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT); \ + size_t _j = _x & UINT32_T_MASK; \ + ((uint32_t *) _image->data)[_i] = (((uint32_t *) _image->data)[_i] & (~(1 << _j))) | ((_v & 1) << _j); \ +}) + +#define IMAGE_CLEAR_BINARY_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] &= ~(1 << (_x & UINT32_T_MASK)); \ +}) + +#define IMAGE_SET_BINARY_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] |= 1 << (_x & UINT32_T_MASK); \ +}) + +#define IMAGE_GET_GRAYSCALE_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint8_t *) _image->data)[(_image->w * _y) + _x]; \ +}) + +#define IMAGE_PUT_GRAYSCALE_PIXEL(image, x, y, v) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + __typeof__ (v) _v = (v); \ + ((uint8_t *) _image->data)[(_image->w * _y) + _x] = _v; \ +}) + +#define IMAGE_GET_RGB565_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint16_t *) _image->data)[(_image->w * _y) + _x]; \ +}) + +#define IMAGE_PUT_RGB565_PIXEL(image, x, y, v) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + __typeof__ (v) _v = (v); \ + ((uint16_t *) _image->data)[(_image->w * _y) + _x] = _v; \ +}) + +#ifdef __arm__ + #define IMAGE_REV_RGB565_PIXEL(pixel) \ + ({ \ + __typeof__ (pixel) _pixel = (pixel); \ + __REV16(_pixel); \ + }) +#else + #define IMAGE_REV_RGB565_PIXEL(pixel) \ + ({ \ + __typeof__ (pixel) _pixel = (pixel); \ + ((_pixel >> 8) | (_pixel << 8)) & 0xFFFF; \ + }) +#endif + +#define IMAGE_COMPUTE_TARGET_SIZE_SCALE_FACTOR(target_size, source_rect) \ +__typeof__ (target_size) _target_size = (target_size); \ +__typeof__ (source_rect) _source_rect = (source_rect); \ +int IMAGE_X_SOURCE_OFFSET = _source_rect->p.x; \ +int IMAGE_Y_SOURCE_OFFSET = _source_rect->p.y; \ +int IMAGE_X_TARGET_OFFSET = 0; \ +int IMAGE_Y_TARGET_OFFSET = 0; \ +float IMAGE_X_RATIO = ((float) _source_rect->s.w) / ((float) _target_size->w); \ +float IMAGE_Y_RATIO = ((float) _source_rect->s.h) / ((float) _target_size->h); \ +({ 0; }) + +#define IMAGE_COMPUTE_TARGET_RECT_SCALE_FACTOR(target_rect, source_rect) \ +__typeof__ (target_rect) _target_rect = (target_rect); \ +__typeof__ (source_rect) _source_rect = (source_rect); \ +int IMAGE_X_SOURCE_OFFSET = _source_rect->p.x; \ +int IMAGE_Y_SOURCE_OFFSET = _source_rect->p.y; \ +int IMAGE_X_TARGET_OFFSET = _target_rect->p.x; \ +int IMAGE_Y_TARGET_OFFSET = _target_rect->p.y; \ +float IMAGE_X_RATIO = ((float) _source_rect->s.w) / ((float) _target_rect->s.w); \ +float IMAGE_Y_RATIO = ((float) _source_rect->s.h) / ((float) _target_rect->s.h); \ +({ 0; }) + +#define IMAGE_GET_SCALED_BINARY_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + IMAGE_GET_BINARY_PIXEL(_image, ((size_t) ((IMAGE_X_RATIO * (_x - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET, ((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET); \ +}) + +#define IMAGE_GET_SCALED_GRAYSCALE_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + IMAGE_GET_GRAYSCALE_PIXEL(_image, ((size_t) ((IMAGE_X_RATIO * (_x - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET, ((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET); \ +}) + +#define IMAGE_GET_SCALED_RGB565_PIXEL(image, x, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + IMAGE_GET_RGB565_PIXEL(_image, ((size_t) ((IMAGE_X_RATIO * (_x - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET, ((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET); \ +}) + +// Fast Stuff // + +#define IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint32_t *) _image->data) + (((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y); \ +}) + +#define IMAGE_INC_BINARY_PIXEL_ROW_PTR(row_ptr, image) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (image) _image = (image); \ + _row_ptr + ((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT); \ +}) + +#define IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + (_row_ptr[_x >> UINT32_T_SHIFT] >> (_x & UINT32_T_MASK)) & 1; \ +}) + +#define IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, v) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + __typeof__ (v) _v = (v); \ + size_t _i = _x >> UINT32_T_SHIFT; \ + size_t _j = _x & UINT32_T_MASK; \ + _row_ptr[_i] = (_row_ptr[_i] & (~(1 << _j))) | ((_v & 1) << _j); \ +}) + +#define IMAGE_CLEAR_BINARY_PIXEL_FAST(row_ptr, x) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + _row_ptr[_x >> UINT32_T_SHIFT] &= ~(1 << (_x & UINT32_T_MASK)); \ +}) + +#define IMAGE_SET_BINARY_PIXEL_FAST(row_ptr, x) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + _row_ptr[_x >> UINT32_T_SHIFT] |= 1 << (_x & UINT32_T_MASK); \ +}) + +#define IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint8_t *) _image->data) + (_image->w * _y); \ +}) + +#define IMAGE_INC_GRAYSCALE_PIXEL_ROW_PTR(row_ptr, image) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (image) _image = (image); \ + row_ptr + _image->w; \ +}) + +#define IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + _row_ptr[_x]; \ +}) + +#define IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, v) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + __typeof__ (v) _v = (v); \ + _row_ptr[_x] = _v; \ +}) + +#define IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint16_t *) _image->data) + (_image->w * _y); \ +}) + +#define IMAGE_INC_RGB565_PIXEL_ROW_PTR(row_ptr, image) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (image) _image = (image); \ + row_ptr + _image->w; \ +}) + +#define IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + _row_ptr[_x]; \ +}) + +#define IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, v) \ +({ \ + __typeof__ (row_ptr) _row_ptr = (row_ptr); \ + __typeof__ (x) _x = (x); \ + __typeof__ (v) _v = (v); \ + _row_ptr[_x] = _v; \ +}) + +#define IMAGE_COMPUTE_SCALED_BINARY_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint32_t *) _image->data) + (((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * (((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET)); \ +}) + +#define IMAGE_GET_SCALED_BINARY_PIXEL_FAST(row_ptr, x) IMAGE_GET_BINARY_PIXEL_FAST((row_ptr), ((size_t) ((IMAGE_X_RATIO * ((x) - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET) + +#define IMAGE_COMPUTE_SCALED_GRAYSCALE_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint8_t *) _image->data) + (_image->w * (((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET)); \ +}) + +#define IMAGE_GET_SCALED_GRAYSCALE_PIXEL_FAST(row_ptr, x) IMAGE_GET_GRAYSCALE_PIXEL_FAST((row_ptr), ((size_t) ((IMAGE_X_RATIO * ((x) - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET) + +#define IMAGE_COMPUTE_SCALED_RGB565_PIXEL_ROW_PTR(image, y) \ +({ \ + __typeof__ (image) _image = (image); \ + __typeof__ (y) _y = (y); \ + ((uint16_t *) _image->data) + (_image->w * (((size_t) ((IMAGE_Y_RATIO * (_y - IMAGE_Y_TARGET_OFFSET)) + 0.5)) + IMAGE_Y_SOURCE_OFFSET)); \ +}) + +#define IMAGE_GET_SCALED_RGB565_PIXEL_FAST(row_ptr, x) IMAGE_GET_RGB565_PIXEL_FAST((row_ptr), ((size_t) ((IMAGE_X_RATIO * ((x) - IMAGE_X_TARGET_OFFSET)) + 0.5)) + IMAGE_X_SOURCE_OFFSET) + +// Old Image Macros - Will be refactor and removed. But, only after making sure through testing new macros work. + +#if 0 /*hutu*/ +#define IM_SWAP16(x) __REV16(x) // Swap bottom two chars in short. +#define IM_SWAP32(x) __REV32(x) // Swap bottom two shorts in long. +#else +#define IM_SWAP16(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) +#define IM_SWAP32(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24)) +#endif +// RGB565 to RGB888 conversion. +extern const uint8_t rb528_table[32]; +extern const uint8_t g628_table[64]; + +#define IM_R528(p) \ + ({ __typeof__ (p) _p = (p); \ + rb528_table[_p]; }) + +#define IM_G628(p) \ + ({ __typeof__ (p) _p = (p); \ + g628_table[_p]; }) + +#define IM_B528(p) \ + ({ __typeof__ (p) _p = (p); \ + rb528_table[_p]; }) + +// RGB888 to RGB565 conversion. +extern const uint8_t rb825_table[256]; +extern const uint8_t g826_table[256]; + +#define IM_R825(p) \ + ({ __typeof__ (p) _p = (p); \ + rb825_table[_p]; }) + +#define IM_G826(p) \ + ({ __typeof__ (p) _p = (p); \ + g826_table[_p]; }) + +#define IM_B825(p) \ + ({ __typeof__ (p) _p = (p); \ + rb825_table[_p]; }) + +// Split RGB565 values (note the RGB565 value is byte reversed). + +#define IM_R565(p) \ + ({ __typeof__ (p) _p = (p); \ + ((_p)>>3)&0x1F; }) + +#define IM_G565(p) \ + ({ __typeof__ (p) _p = (p); \ + (((_p)&0x07)<<3)|((_p)>>13); }) + +#define IM_B565(p) \ + ({ __typeof__ (p) _p = (p); \ + ((_p)>>8)&0x1F; }) + +// Merge RGB565 values (note the RGB565 value is byte reversed). + +#define IM_RGB565(r, g, b) \ + ({ __typeof__ (r) _r = (r); \ + __typeof__ (g) _g = (g); \ + __typeof__ (b) _b = (b); \ + ((_r)<<3)|((_g)>>3)|((_g)<<13)|((_b)<<8); }) + +// Image kernels +extern const int8_t kernel_gauss_3[9]; +extern const int8_t kernel_gauss_5[25]; +extern const int kernel_laplacian_3[9]; +extern const int kernel_high_pass_3[9]; + +#define IM_RGB5652L(p) \ + ({ __typeof__ (p) _p = (p); \ + lab_table[_p * 3]; }) + +#define IM_RGB5652A(p) \ + ({ __typeof__ (p) _p = (p); \ + lab_table[(_p * 3) + 1]; }) + +#define IM_RGB5652B(p) \ + ({ __typeof__ (p) _p = (p); \ + lab_table[(_p * 3) + 2]; }) + +// Grayscale maxes +#define IM_MAX_GS (255) + +// RGB565 maxes +#define IM_MAX_R5 (31) +#define IM_MAX_G6 (63) +#define IM_MAX_B5 (31) + +// Grayscale histogram +#define IM_G_HIST_SIZE (256) +#define IM_G_HIST_OFFSET (0) + +// LAB histogram +#define IM_L_HIST_SIZE (256) +#define IM_L_HIST_OFFSET (0) +#define IM_A_HIST_SIZE (256) +#define IM_A_HIST_OFFSET (256) +#define IM_B_HIST_SIZE (256) +#define IM_B_HIST_OFFSET (512) + +#define IM_IS_BINARY(img) \ + ({ __typeof__ (img) _img = (img); \ + _img->bpp == 0; }) + +#define IM_IS_GS(img) \ + ({ __typeof__ (img) _img = (img); \ + _img->bpp == 1; }) + +#define IM_IS_RGB565(img) \ + ({ __typeof__ (img) _img = (img); \ + _img->bpp == 2; }) + +#define IM_IS_BAYER(img) \ + ({ __typeof__ (img) _img = (img); \ + _img->bpp == 3; }) + +#define IM_IS_JPEG(img) \ + ({ __typeof__ (img) _img = (img); \ + _img->bpp >= 4; }) + +#define IM_IS_MUTABLE(img) \ + ({ __typeof__ (img) _img = (img); \ + (_img->bpp == 1 || _img->bpp == 2); }) + +#define IM_X_INSIDE(img, x) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + (0<=_x)&&(_x<_img->w); }) + +#define IM_Y_INSIDE(img, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (y) _y = (y); \ + (0<=_y)&&(_y<_img->h); }) + +#define IM_GET_GS_PIXEL(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_GET_RAW_PIXEL(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_GET_RAW_PIXEL_CHECK_BOUNDS_X(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x = (_x < 0) ? 0 : (_x >= img->w) ? (img->w -1): _x; \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_GET_RAW_PIXEL_CHECK_BOUNDS_Y(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _y = (_y < 0) ? 0 : (_y >= img->h) ? (img->h -1): _y; \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_GET_RAW_PIXEL_CHECK_BOUNDS_XY(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + _x = (_x < 0) ? 0 : (_x >= img->w) ? (img->w -1): _x; \ + _y = (_y < 0) ? 0 : (_y >= img->h) ? (img->h -1): _y; \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_GET_RGB565_PIXEL(img, x, y) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + ((uint16_t*)_img->pixels)[(_y*_img->w)+_x]; }) + +#define IM_SET_GS_PIXEL(img, x, y, p) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + __typeof__ (p) _p = (p); \ + ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]=_p; }) + +#define IM_SET_RGB565_PIXEL(img, x, y, p) \ + ({ __typeof__ (img) _img = (img); \ + __typeof__ (x) _x = (x); \ + __typeof__ (y) _y = (y); \ + __typeof__ (p) _p = (p); \ + ((uint16_t*)_img->pixels)[(_y*_img->w)+_x]=_p; }) + +#define IM_EQUAL(img0, img1) \ + ({ __typeof__ (img0) _img0 = (img0); \ + __typeof__ (img1) _img1 = (img1); \ + (_img0->w==_img1->w)&&(_img0->h==_img1->h)&&(_img0->bpp==_img1->bpp); }) + +#define IM_TO_GS_PIXEL(img, x, y) \ + (img->bpp == 1 ? img->pixels[((y)*img->w)+(x)] : (yuv_table[((uint16_t*)img->pixels)[((y)*img->w)+(x)] * 3] + 128)) + +typedef struct simple_color { + uint8_t G; // Gray + union { + int8_t L; // LAB L + uint8_t red; // RGB888 Red + }; + union { + int8_t A; // LAB A + uint8_t green; // RGB888 Green + }; + union { + int8_t B; // LAB B + uint8_t blue; // RGB888 Blue + }; +} simple_color_t; + +typedef struct integral_image { + int w; + int h; + uint32_t *data; +} i_image_t; + +typedef struct { + int w; + int h; + int y_offs; + int x_ratio; + int y_ratio; + uint32_t **data; + uint32_t **swap; +} mw_image_t; + +typedef struct _vector { + float x; + float y; + float m; + uint16_t cx,cy; +} vec_t; + +typedef struct cluster { + int x, y, w, h; + array_t *points; +} cluster_t; + +// Return the distance between a cluster centroid and some object. +typedef float (*cluster_dist_t)(int cx, int cy, void *obj); + +/* Keypoint */ +typedef struct kp { + uint16_t x; + uint16_t y; + uint16_t score; + uint16_t octave; + uint16_t angle; + uint16_t matched; + uint8_t desc[32]; +} kp_t; + +typedef struct size { + int w; + int h; +} wsize_t; + +/* Haar cascade struct */ +typedef struct cascade { + int std; // Image standard deviation. + int step; // Image scanning factor. + float threshold; // Detection threshold. + float scale_factor; // Image scaling factor. + int n_stages; // Number of stages in the cascade. + int n_features; // Number of features in the cascade. + int n_rectangles; // Number of rectangles in the cascade. + struct size window; // Detection window size. + struct image *img; // Grayscale image. + mw_image_t *sum; // Integral image. + mw_image_t *ssq; // Squared integral image. + uint8_t *stages_array; // Number of features per stage. + int16_t *stages_thresh_array; // Stages thresholds. + int16_t *tree_thresh_array; // Features threshold (1 per feature). + int16_t *alpha1_array; // Alpha1 array (1 per feature). + int16_t *alpha2_array; // Alpha2 array (1 per feature). + int8_t *num_rectangles_array; // Number of rectangles per features (1 per feature). + int8_t *weights_array; // Rectangles weights (1 per rectangle). + int8_t *rectangles_array; // Rectangles array. +} cascade_t; + +typedef struct bmp_read_settings { + int32_t bmp_w; + int32_t bmp_h; + uint16_t bmp_bpp; + uint32_t bmp_fmt; + uint32_t bmp_row_bytes; +} bmp_read_settings_t; + +typedef struct ppm_read_settings { + uint8_t read_int_c; + bool read_int_c_valid; + uint8_t ppm_fmt; +} ppm_read_settings_t; + +typedef enum save_image_format { + FORMAT_DONT_CARE, + FORMAT_BMP, + FORMAT_PNM, + FORMAT_JPG, + FORMAT_RAW, +} save_image_format_t; + +typedef struct img_read_settings { + union + { + bmp_read_settings_t bmp_rs; + ppm_read_settings_t ppm_rs; + }; + save_image_format_t format; +} img_read_settings_t; + +typedef void (*line_op_t)(image_t*, int, void*, void*, bool); +typedef void (*flood_fill_call_back_t)(image_t *, int, int, int, void *); + +typedef enum descriptor_type { + DESC_LBP, + DESC_ORB, +} descriptor_t; + +typedef enum edge_detector_type { + EDGE_CANNY, + EDGE_SIMPLE, +} edge_detector_t; + +typedef enum template_match { + SEARCH_EX, // Exhaustive search + SEARCH_DS, // Diamond search +} template_match_t; + +typedef enum jpeg_subsample { + JPEG_SUBSAMPLE_1x1 = 0x11, // 1x1 chroma subsampling (No subsampling) + JPEG_SUBSAMPLE_2x1 = 0x21, // 2x2 chroma subsampling + JPEG_SUBSAMPLE_2x2 = 0x22, // 2x2 chroma subsampling +} jpeg_subsample_t; + +typedef enum corner_detector_type { + CORNER_FAST, + CORNER_AGAST +} corner_detector_t; + +typedef struct histogram { + int LBinCount; + float *LBins; + int ABinCount; + float *ABins; + int BBinCount; + float *BBins; +} histogram_t; + +typedef struct percentile { + uint8_t LValue; + int8_t AValue; + int8_t BValue; +} percentile_t; + +typedef struct threshold { + uint8_t LValue; + int8_t AValue; + int8_t BValue; +} threshold_t; + +typedef struct statistics { + uint8_t LMean, LMedian, LMode, LSTDev, LMin, LMax, LLQ, LUQ; + int8_t AMean, AMedian, AMode, ASTDev, AMin, AMax, ALQ, AUQ; + int8_t BMean, BMedian, BMode, BSTDev, BMin, BMax, BLQ, BUQ; +} statistics_t; + +typedef struct find_blobs_list_lnk_data { + rectangle_t rect; + uint32_t pixels; + point_t centroid; + float rotation; + uint16_t code, count; +} find_blobs_list_lnk_data_t; + +typedef struct find_lines_list_lnk_data { + line_t line; + uint32_t magnitude; + int16_t theta, rho; +} find_lines_list_lnk_data_t; + +typedef struct find_circles_list_lnk_data { + point_t p; + uint32_t r, magnitude; +} find_circles_list_lnk_data_t; + +typedef struct find_rects_list_lnk_data { + point_t corners[4]; + rectangle_t rect; + uint32_t magnitude; +} find_rects_list_lnk_data_t; + +typedef struct find_qrcodes_list_lnk_data { + point_t corners[4]; + rectangle_t rect; + size_t payload_len; + char *payload; + uint8_t version, ecc_level, mask, data_type; + uint32_t eci; +} find_qrcodes_list_lnk_data_t; + +typedef enum apriltag_families { + TAG16H5 = 1, + TAG25H7 = 2, + TAG25H9 = 4, + TAG36H10 = 8, + TAG36H11 = 16, + ARTOOLKIT = 32 +} apriltag_families_t; + +typedef struct find_apriltags_list_lnk_data { + point_t corners[4]; + rectangle_t rect; + uint16_t id; + uint8_t family, hamming; + point_t centroid; + float goodness, decision_margin; + float x_translation, y_translation, z_translation; + float x_rotation, y_rotation, z_rotation; +} find_apriltags_list_lnk_data_t; + +typedef struct find_datamatrices_list_lnk_data { + point_t corners[4]; + rectangle_t rect; + size_t payload_len; + char *payload; + uint16_t rotation; + uint8_t rows, columns; + uint16_t capacity, padding; +} find_datamatrices_list_lnk_data_t; + +typedef enum barcodes { + BARCODE_EAN2, + BARCODE_EAN5, + BARCODE_EAN8, + BARCODE_UPCE, + BARCODE_ISBN10, + BARCODE_UPCA, + BARCODE_EAN13, + BARCODE_ISBN13, + BARCODE_I25, + BARCODE_DATABAR, + BARCODE_DATABAR_EXP, + BARCODE_CODABAR, + BARCODE_CODE39, + BARCODE_PDF417, + BARCODE_CODE93, + BARCODE_CODE128 +} barcodes_t; + +typedef struct find_barcodes_list_lnk_data { + point_t corners[4]; + rectangle_t rect; + size_t payload_len; + char *payload; + uint16_t type, rotation; + int quality; +} find_barcodes_list_lnk_data_t; + +/* Color space functions */ +void imlib_rgb_to_lab(simple_color_t *rgb, simple_color_t *lab); +void imlib_lab_to_rgb(simple_color_t *lab, simple_color_t *rgb); +void imlib_rgb_to_grayscale(simple_color_t *rgb, simple_color_t *grayscale); +void imlib_grayscale_to_rgb(simple_color_t *grayscale, simple_color_t *rgb); +uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v); +void imlib_bayer_to_rgb565(image_t *img, int w, int h, int xoffs, int yoffs, uint16_t *rgbbuf); + +/* Image file functions */ +void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs); +void ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, ppm_read_settings_t *rs); +void ppm_read(image_t *img, const char *path); +void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r); +bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs); +void bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, bmp_read_settings_t *rs); +void bmp_read(image_t *img, const char *path); +void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r); +bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc); +void jpeg_read_geometry(FIL *fp, image_t *img, const char *path); +void jpeg_read_pixels(FIL *fp, image_t *img); +void jpeg_read(image_t *img, const char *path); +void jpeg_write(image_t *img, const char *path, int quality); +bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs); +void imlib_image_operation(image_t *img, const char *path, image_t *other, int scalar, line_op_t op, void *data); +void imlib_load_image(image_t *img, const char *path); +void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int quality); + +/* GIF functions */ +void gif_open(FIL *fp, int width, int height, bool color, bool loop); +void gif_add_frame(FIL *fp, image_t *img, uint16_t delay); +void gif_close(FIL *fp); + +/* MJPEG functions */ +void mjpeg_open(FIL *fp, int width, int height); +void mjpeg_add_frame(FIL *fp, uint32_t *frames, uint32_t *bytes, image_t *img, int quality); +void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps); + +/* Point functions */ +point_t *point_alloc(int16_t x, int16_t y); +bool point_equal(point_t *p1, point_t *p2); +float point_distance(point_t *p1, point_t *p2); + +/* Rectangle functions */ +rectangle_t *rectangle_alloc(int16_t x, int16_t y, int16_t w, int16_t h); +bool rectangle_equal(rectangle_t *r1, rectangle_t *r2); +bool rectangle_intersects(rectangle_t *r1, rectangle_t *r2); +bool rectangle_subimg(image_t *img, rectangle_t *r, rectangle_t *r_out); +array_t *rectangle_merge(array_t *rectangles); +void rectangle_expand(rectangle_t *r, int x, int y); + +/* Separable 2D convolution */ +void imlib_sepconv3(image_t *img, const int8_t *krn, const float m, const int b); + +/* Image Statistics */ +int imlib_image_mean(image_t *src, int *r_mean, int *g_mean, int *b_mean); +int imlib_image_std(image_t *src); // grayscale only + +/* Template Matching */ +void imlib_midpoint_pool(image_t *img_i, image_t *img_o, int x_div, int y_div, const int bias); +void imlib_mean_pool(image_t *img_i, image_t *img_o, int x_div, int y_div); +float imlib_template_match_ds(image_t *image, image_t *template, rectangle_t *r); +float imlib_template_match_ex(image_t *image, image_t *template, rectangle_t *roi, int step, rectangle_t *r); + +/* Clustering functions */ +array_t *cluster_kmeans(array_t *points, int k, cluster_dist_t dist_func); + +/* Integral image functions */ +void imlib_integral_image_alloc(struct integral_image *sum, int w, int h); +void imlib_integral_image_free(struct integral_image *sum); +void imlib_integral_image(struct image *src, struct integral_image *sum); +void imlib_integral_image_sq(struct image *src, struct integral_image *sum); +void imlib_integral_image_scaled(struct image *src, struct integral_image *sum); +uint32_t imlib_integral_lookup(struct integral_image *src, int x, int y, int w, int h); + +// Integral moving window +void imlib_integral_mw_alloc(mw_image_t *sum, int w, int h); +void imlib_integral_mw_free(mw_image_t *sum); +void imlib_integral_mw_scale(rectangle_t *roi, mw_image_t *sum, int w, int h); +void imlib_integral_mw(image_t *src, mw_image_t *sum); +void imlib_integral_mw_sq(image_t *src, mw_image_t *sum); +void imlib_integral_mw_shift(image_t *src, mw_image_t *sum, int n); +void imlib_integral_mw_shift_sq(image_t *src, mw_image_t *sum, int n); +void imlib_integral_mw_ss(image_t *src, mw_image_t *sum, mw_image_t *ssq, rectangle_t *roi); +void imlib_integral_mw_shift_ss(image_t *src, mw_image_t *sum, mw_image_t *ssq, rectangle_t *roi, int n); +long imlib_integral_mw_lookup(mw_image_t *sum, int x, int y, int w, int h); + +/* Haar/VJ */ +int imlib_load_cascade(struct cascade* cascade, const char *path); +array_t *imlib_detect_objects(struct image *image, struct cascade *cascade, struct rectangle *roi); + +/* Corner detectors */ +void fast_detect(image_t *image, array_t *keypoints, int threshold, rectangle_t *roi); +void agast_detect(image_t *image, array_t *keypoints, int threshold, rectangle_t *roi); + +/* ORB descriptor */ +array_t *orb_find_keypoints(image_t *image, bool normalized, int threshold, + float scale_factor, int max_keypoints, corner_detector_t corner_detector, rectangle_t *roi); +int orb_match_keypoints(array_t *kpts1, array_t *kpts2, int *match, int threshold, rectangle_t *r, point_t *c, int *angle); +int orb_filter_keypoints(array_t *kpts, rectangle_t *r, point_t *c); +int orb_save_descriptor(FIL *fp, array_t *kpts); +int orb_load_descriptor(FIL *fp, array_t *kpts); +float orb_cluster_dist(int cx, int cy, void *kp); + +/* LBP Operator */ +uint8_t *imlib_lbp_desc(image_t *image, rectangle_t *roi); +int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1); +int imlib_lbp_desc_save(FIL *fp, uint8_t *desc); +int imlib_lbp_desc_load(FIL *fp, uint8_t **desc); + +/* Iris detector */ +void imlib_find_iris(image_t *src, point_t *iris, rectangle_t *roi); + +// Image filter functions +void im_filter_bw(uint8_t *src, uint8_t *dst, int size, int bpp, void *args); +void im_filter_skin(uint8_t *src, uint8_t *dst, int size, int bpp, void *args); + +// Edge detection +void imlib_edge_simple(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh); +void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh); + +// HoG +void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size); + +// Helper Functions +void imlib_flood_fill_int(image_t *out, image_t *img, int x, int y, + int seed_threshold, int floating_threshold, + flood_fill_call_back_t cb, void *data); +// Drawing Functions +int imlib_get_pixel(image_t *img, int x, int y); +void imlib_set_pixel(image_t *img, int x, int y, int p); +void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness); +void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill); +void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill); +void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale, int x_spacing, int y_spacing, bool mono_space); +void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float x_scale, float y_scale, image_t *mask); +void imlib_flood_fill(image_t *img, int x, int y, + float seed_threshold, float floating_threshold, + int c, bool invert, bool clear_background, image_t *mask); +// Binary Functions +void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask); +void imlib_invert(image_t *img); +void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_nand(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_or(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_nor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask); +void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask); +void imlib_open(image_t *img, int ksize, int threshold, image_t *mask); +void imlib_close(image_t *img, int ksize, int threshold, image_t *mask); +void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask); +void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask); +// Math Functions +void imlib_negate(image_t *img); +void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip, image_t *mask); +void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_sub(image_t *img, const char *path, image_t *other, int scalar, bool reverse, image_t *mask); +void imlib_mul(image_t *img, const char *path, image_t *other, int scalar, bool invert, image_t *mask); +void imlib_div(image_t *img, const char *path, image_t *other, int scalar, bool invert, image_t *mask); +void imlib_min(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_max(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_difference(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); +void imlib_blend(image_t *img, const char *path, image_t *other, int scalar, float alpha, image_t *mask); +// Filtering Functions +void imlib_histeq(image_t *img, image_t *mask); +void imlib_clahe_histeq(image_t *img, float clip_limit, image_t *mask); +void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask); +void imlib_median_filter(image_t *img, const int ksize, float percentile, bool threshold, int offset, bool invert, image_t *mask); +void imlib_mode_filter(image_t *img, const int ksize, bool threshold, int offset, bool invert, image_t *mask); +void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool threshold, int offset, bool invert, image_t *mask); +void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, const int b, bool threshold, int offset, bool invert, image_t *mask); +void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, float space_sigma, bool threshold, int offset, bool invert, image_t *mask); +void imlib_cartoon_filter(image_t *img, float seed_threshold, float floating_threshold, image_t *mask); +// Image Correction +void imlib_logpolar_int(image_t *dst, image_t *src, rectangle_t *roi, bool linear, bool reverse); // helper/internal +void imlib_logpolar(image_t *img, bool linear, bool reverse); +void imlib_remove_shadows(image_t *img, const char *path, image_t *other, int scalar, bool single); +void imlib_chrominvar(image_t *img); +void imlib_illuminvar(image_t *img); +// Lens/Rotation Correction +void imlib_lens_corr(image_t *img, float strength, float zoom); +void imlib_rotation_corr(image_t *img, float x_rotation, float y_rotation, + float z_rotation, float x_translation, float y_translation, + float zoom); +// Statistics +void imlib_get_similarity(image_t *img, const char *path, image_t *other, int scalar, float *avg, float *std, float *min, float *max); +void imlib_get_histogram(histogram_t *out, image_t *ptr, rectangle_t *roi, list_t *thresholds, bool invert); +void imlib_get_percentile(percentile_t *out, image_bpp_t bpp, histogram_t *ptr, float percentile); +void imlib_get_threshold(threshold_t *out, image_bpp_t bpp, histogram_t *ptr); +void imlib_get_statistics(statistics_t *out, image_bpp_t bpp, histogram_t *ptr); +bool imlib_get_regression(find_lines_list_lnk_data_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + list_t *thresholds, bool invert, unsigned int area_threshold, unsigned int pixels_threshold, bool robust); +// Color Tracking +void imlib_find_blobs(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + list_t *thresholds, bool invert, unsigned int area_threshold, unsigned int pixels_threshold, + bool merge, int margin, + bool (*threshold_cb)(void*,find_blobs_list_lnk_data_t*), void *threshold_cb_arg, + bool (*merge_cb)(void*,find_blobs_list_lnk_data_t*,find_blobs_list_lnk_data_t*), void *merge_cb_arg); +// Shape Detection +size_t trace_line(image_t *ptr, line_t *l, int *theta_buffer, uint32_t *mag_buffer, point_t *point_buffer); // helper/internal +void merge_alot(list_t *out, int threshold, int theta_threshold); // helper/internal +void imlib_find_lines(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int theta_margin, unsigned int rho_margin); +void imlib_lsd_find_line_segments(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int merge_distance, unsigned int max_theta_diff); +void imlib_find_line_segments(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int theta_margin, unsigned int rho_margin, + uint32_t segment_threshold); +void imlib_find_circles(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + uint32_t threshold, unsigned int x_margin, unsigned int y_margin, unsigned int r_margin, + unsigned int r_min, unsigned int r_max, unsigned int r_step); +void imlib_find_rects(list_t *out, image_t *ptr, rectangle_t *roi, + uint32_t threshold); +// 1/2D Bar Codes +void imlib_find_qrcodes(list_t *out, image_t *ptr, rectangle_t *roi); +void imlib_find_apriltags(list_t *out, image_t *ptr, rectangle_t *roi, apriltag_families_t families, + float fx, float fy, float cx, float cy); +void imlib_find_datamatrices(list_t *out, image_t *ptr, rectangle_t *roi, int effort); +void imlib_find_barcodes(list_t *out, image_t *ptr, rectangle_t *roi); +// Template Matching +void imlib_phasecorrelate(image_t *img0, image_t *img1, rectangle_t *roi0, rectangle_t *roi1, bool logpolar, bool fix_rotation_scale, + float *x_translation, float *y_translation, float *rotation, float *scale, float *response); + +array_t *imlib_selective_search(image_t *src, float t, int min_size, float a1, float a2, float a3); +#endif //__IMLIB_H__ diff --git a/src/openmv/src/omv/img/integral.c b/src/openmv/src/omv/img/integral.c new file mode 100755 index 0000000..840c57a --- /dev/null +++ b/src/openmv/src/omv/img/integral.c @@ -0,0 +1,115 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Integral image. + * + */ +#include +#include +#include "imlib.h" +#include "fb_alloc.h" + +void imlib_integral_image_alloc(i_image_t *sum, int w, int h) +{ + sum->w = w; + sum->h = h; + sum->data = fb_alloc(w * h * sizeof(*sum->data)); +} + +void imlib_integral_image_free(i_image_t *sum) +{ + // 1 allocation + fb_free(); +} + +void imlib_integral_image(image_t *src, i_image_t *sum) +{ + typeof(*src->data) *img_data = src->data; + typeof(*sum->data) *sum_data = sum->data; + + // Compute first column to avoid branching + for (int s=0, x=0; xw; x++) { + /* sum of the current row (integer) */ + s += img_data[x]; + sum_data[x] = s; + } + + for (int y=1; yh; y++) { + /* loop over the number of columns */ + for (int s=0, x=0; xw; x++) { + /* sum of the current row (integer) */ + s += img_data[y*src->w+x]; + sum_data[y*src->w+x] = s+sum_data[(y-1)*src->w+x]; + } + } +} + +void imlib_integral_image_scaled(image_t *src, i_image_t *sum) +{ + typeof(*src->data) *img_data = src->data; + typeof(*sum->data) *sum_data = sum->data; + + int x_ratio = (int)((src->w<<16)/sum->w) +1; + int y_ratio = (int)((src->h<<16)/sum->h) +1; + + // Compute first column to avoid branching + for (int s=0, x=0; xw; x++) { + int sx = (x*x_ratio)>>16; + /* sum of the current row (integer) */ + s += img_data[sx]; + sum_data[x] = s; + } + + for (int y=1; yh; y++) { + int sy = (y*y_ratio)>>16; + /* loop over the number of columns */ + for (int s=0, x=0; xw; x++) { + int sx = (x*x_ratio)>>16; + + /* sum of the current row (integer) */ + s += img_data[sy*src->w+sx]; + sum_data[y*sum->w+x] = s+sum_data[(y-1)*sum->w+x]; + } + } +} + +void imlib_integral_image_sq(image_t *src, i_image_t *sum) +{ + typeof(*src->data) *img_data = src->data; + typeof(*sum->data) *sum_data = sum->data; + + // Compute first column to avoid branching + for (uint32_t s=0, x=0; xw; x++) { + /* sum of the current row (integer) */ + s += img_data[x] * img_data[x]; + sum_data[x] = s; + } + + for (uint32_t y=1; yh; y++) { + /* loop over the number of columns */ + for (uint32_t s=0, x=0; xw; x++) { + /* sum of the current row (integer) */ + s += img_data[y*src->w+x] * img_data[y*src->w+x]; + sum_data[y*src->w+x] = s+sum_data[(y-1)*src->w+x]; + } + } + +} + +uint32_t imlib_integral_lookup(i_image_t *sum, int x, int y, int w, int h) +{ +#define PIXEL_AT(x,y)\ + (sum->data[((y)-1)*sum->w+((x)-1)]) + if (x==0 && y==0) { + return PIXEL_AT(w,h); + } else if (y==0) { + return PIXEL_AT(w+x, h) - PIXEL_AT(x, h); + } else if (x==0) { + return PIXEL_AT(w, h+y) - PIXEL_AT(w, y); + } else { + return PIXEL_AT(w+x, h+y) + PIXEL_AT(x, y) - PIXEL_AT(w+x, y) - PIXEL_AT(x, h+y); + } +#undef PIXEL_AT +} diff --git a/src/openmv/src/omv/img/integral_mw.c b/src/openmv/src/omv/img/integral_mw.c new file mode 100755 index 0000000..aa13e77 --- /dev/null +++ b/src/openmv/src/omv/img/integral_mw.c @@ -0,0 +1,310 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * An integral image using a moving window. + * + * The high level steps are: + * 1) Start with an array of pointers[n] where n = feature height. + * 2) Compute the first n lines of the integral image. + * 3) Do some processing with the integral image. + * 4) Call integral_mw_image_shift(n) + * + * This will shift the pointers by n and calculate n new lines, example: + * Assuming feature height is 4: + * mw_i_image[0] -> mem[0] + * mw_i_image[1] -> mem[1] + * mw_i_image[2] -> mem[2] + * mw_i_image[3] -> mem[3] + * + * After shifting by 1 line, it looks like this: + * mw_i_image[0] -> mem[1] + * mw_i_image[1] -> mem[2] + * mw_i_image[2] -> mem[3] + * mw_i_image[3] -> mem[0] + * Line 3 will be computed as normal using line 2 which now + * points to the last integral image line computed initially. + * + * After shifting by second line, it looks like this: + * mw_i_image[0] -> mem[2] + * mw_i_image[1] -> mem[3] + * mw_i_image[2] -> mem[0] + * mw_i_image[3] -> mem[1] + * Line 3 will be computed as usual using line 2 which now + * points to the last integral image line computed in the previous shift. + * + * Notes: + * The mw integral must Not be shifted more than image_height - feature_height, s_lines + * must be < feature_height-1 to keep at least one row for integral image calculations. + * + * This only requires (image_width * (feature_height+1) * 4) bytes. Assuming a 24x24 + * feature, the required memory is 320*25*4 (i.e. ~32KBs) instead of 320*240*4 (300KBs). + * + * Functions without a suffix compute/shift summed images, _sq suffix compute/shift + * summed squared images, and _ss compute/shift both summed and squared in a single pass. + */ +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" + +// This macro swaps two pointers. +#define SWAP_PTRS(a, b) \ + ({ __typeof__ (a) _t;\ + (_t) = ( a); \ + ( a) = ( b); \ + ( b) = (_t); }) + +void imlib_integral_mw_alloc(mw_image_t *sum, int w, int h) +{ + sum->w = w; + sum->h = h; + sum->y_offs = 0; + sum->x_ratio = (1<<16)+1; + sum->y_ratio = (1<<16)+1; + sum->data = fb_alloc(h * sizeof(*sum->data)); + // swap is used when shifting the image pointers + // to avoid overwriting the image rows in sum->data + sum->swap = fb_alloc(h * sizeof(*sum->data)); + + for (int i=0; idata[i] = fb_alloc(w * sizeof(**sum->data)); + } +} + +void imlib_integral_mw_free(mw_image_t *sum) +{ + for (int i=0; ih; i++) { + fb_free(); // Free h lines + } + fb_free(); // Free data + fb_free(); // Free swap +} + +void imlib_integral_mw_scale(rectangle_t *roi, mw_image_t *sum, int w, int h) +{ + // Set new width + // Note: height doesn't change + sum->w = w; + // Reset y offset + sum->y_offs = 0; + // Set scaling ratios + sum->x_ratio = (int)((roi->w<<16)/w)+1; + sum->y_ratio = (int)((roi->h<<16)/h)+1; +} + +void imlib_integral_mw(image_t *src, mw_image_t *sum) +{ + // Image pointers + typeof(*sum->data) *sum_data = sum->data; + + // Compute the first row to avoid branching + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, 0); + sum_data[0][x] = s; + } + + // Compute the remaining rows + for (int sy, y=1; yh; y++) { + // Y offset + sy = (y*sum->y_ratio)>>16; + + // Sum the current row + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy); + sum_data[y][x] = s + sum_data[y-1][x]; + } + } + + sum->y_offs = sum->h; +} + +void imlib_integral_mw_sq(image_t *src, mw_image_t *sum) +{ + // Image pointers + typeof(*sum->data) *sum_data = sum->data; + + // Compute the first row to avoid branching + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, 0) * IM_TO_GS_PIXEL(src, sx, 0); + sum_data[0][x] = s; + } + + // Compute the remaining rows + for (int sy, y=1; yh; y++) { + // Y offset + sy = (y*sum->y_ratio)>>16; + + // Sum the current row + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy) * IM_TO_GS_PIXEL(src, sx, sy); + sum_data[y][x] = s + sum_data[y-1][x]; + } + } + + sum->y_offs = sum->h; +} + +void imlib_integral_mw_shift(image_t *src, mw_image_t *sum, int n) +{ + // Shift integral image rows by n lines + for (int y=0; yh; y++) { + sum->swap[y] = sum->data[(y+n) % sum->h]; + } + + // Swap the data and swap pointers + SWAP_PTRS(sum->data, sum->swap); + + // Pointer to the current sum data + typeof(*sum->data) *sum_data = sum->data; + + // Compute the last n lines + for (int sy, y=(sum->h - n); yh; y++, sum->y_offs++) { + // Y offset + sy = (sum->y_offs*sum->y_ratio)>>16; + + // Sum the current row + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy); + sum_data[y][x] = s + sum_data[y-1][x]; + } + } +} + +void imlib_integral_mw_shift_sq(image_t *src, mw_image_t *sum, int n) +{ + // Shift integral image rows by n lines + for (int y=0; yh; y++) { + sum->swap[y] = sum->data[(y+n) % sum->h]; + } + + // Swap data and swap pointers + SWAP_PTRS(sum->data, sum->swap); + + // Pointer to the current sum data + typeof(*sum->data) *sum_data = sum->data; + + // Compute the last n lines + for (int sy, y=(sum->h - n); yh; y++, sum->y_offs++) { + // The y offset is set to the last line + 1 + sy = (sum->y_offs*sum->y_ratio)>>16; + + // Sum the current row + for (int sx, s=0, x=0; xw; x++) { + // X offset + sx = (x*sum->x_ratio)>>16; + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy) * IM_TO_GS_PIXEL(src, sx, sy); + sum_data[y][x] = (s + sum_data[y-1][x]); + } + } +} + +void imlib_integral_mw_ss(image_t *src, mw_image_t *sum, mw_image_t *ssq, rectangle_t *roi) +{ + // Image data pointers + typeof(*sum->data) *sum_data = sum->data; + typeof(*sum->data) *ssq_data = ssq->data; + + // Compute the first row to avoid branching + for (int sx, s=0, sq=0, x=0; xw; x++) { + // X offset + sx = roi->x+((x*sum->x_ratio)>>16); + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, roi->y); + sq += IM_TO_GS_PIXEL(src, sx, roi->y) * IM_TO_GS_PIXEL(src, sx, roi->y); + + sum_data[0][x] = s; + ssq_data[0][x] = sq; + } + + // Compute the last n lines + for (int sy, y=1; yh; y++) { + // Y offset + sy = roi->y+((y*sum->y_ratio)>>16); + + // Sum the current row + for (int sx, s=0, sq=0, x=0; xw; x++) { + // X offset + sx = roi->x+((x*sum->x_ratio)>>16); + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy); + sq += IM_TO_GS_PIXEL(src, sx, sy) * IM_TO_GS_PIXEL(src, sx, sy); + + sum_data[y][x] = s + sum_data[y-1][x]; + ssq_data[y][x] = sq + ssq_data[y-1][x]; + } + } + + sum->y_offs = sum->h; + ssq->y_offs = sum->h; +} + +void imlib_integral_mw_shift_ss(image_t *src, mw_image_t *sum, mw_image_t *ssq, rectangle_t *roi, int n) +{ + // Shift integral image rows by n lines + for (int y=0; yh; y++) { + sum->swap[y] = sum->data[(y+n) % sum->h]; + ssq->swap[y] = ssq->data[(y+n) % ssq->h]; + } + + // Swap the data and swap pointers + SWAP_PTRS(sum->data, sum->swap); + SWAP_PTRS(ssq->data, ssq->swap); + + // Pointer to the current sum and ssq data + typeof(*sum->data) *sum_data = sum->data; + typeof(*ssq->data) *ssq_data = ssq->data; + + // Compute the last n lines + for (int sy, y=(sum->h - n); yh; y++, sum->y_offs++, ssq->y_offs++) { + // The y offset is set to the last line + 1 + sy = roi->y+((sum->y_offs*sum->y_ratio)>>16); + + // Sum of the current row + for (int sx, s=0, sq=0, x=0; xw; x++) { + // X offset + sx = roi->x+((x*sum->x_ratio)>>16); + + // Accumulate row data + s += IM_TO_GS_PIXEL(src, sx, sy); + sq += IM_TO_GS_PIXEL(src, sx, sy) * IM_TO_GS_PIXEL(src, sx, sy); + + sum_data[y][x] = s + sum_data[y-1][x]; + ssq_data[y][x] = sq + ssq_data[y-1][x]; + } + } +} + +long imlib_integral_mw_lookup(mw_image_t *sum, int x, int y, int w, int h) +{ +#define PIXEL_AT(x,y)\ + (sum->data[(y)][x]) + return PIXEL_AT(w+x, h+y) + PIXEL_AT(x, y) - PIXEL_AT(w+x, y) - PIXEL_AT(x, h+y); +#undef PIXEL_AT +} diff --git a/src/openmv/src/omv/img/invariant_tab.c b/src/openmv/src/omv/img/invariant_tab.c new file mode 100755 index 0000000..b03643b --- /dev/null +++ b/src/openmv/src/omv/img/invariant_tab.c @@ -0,0 +1,4101 @@ +#include +#ifdef IMLIB_ENABLE_INVARIANT_TABLE +const uint16_t invariant_table[65536] = { + 0xAA52, 0x483C, 0xE51D, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, 0x6B5A, 0x083C, 0xA525, 0x8316, 0x020F, 0x610F, 0xA107, 0xAA52, + 0x2B5A, 0xC943, 0x8525, 0x6316, 0x020F, 0x610F, 0xA107, 0xAA52, 0xEB61, 0x8943, 0x462D, 0x441E, 0xE20E, 0x420F, 0x8107, 0xAA52, + 0xCB69, 0x2A4B, 0xE62C, 0x241E, 0xC316, 0x420F, 0x8107, 0xAA52, 0x8C69, 0xEA52, 0xA734, 0xE51D, 0xA316, 0x220F, 0x810F, 0xAA52, + 0x6C71, 0xAA52, 0x6734, 0xA525, 0x8316, 0x020F, 0x610F, 0xAA52, 0x2C71, 0x6B5A, 0x283C, 0x6525, 0x6416, 0xE20E, 0x610F, 0xAA52, + 0x0C79, 0x2B62, 0xE843, 0x462D, 0x241E, 0xC316, 0x410F, 0xAA52, 0xEC78, 0xEB61, 0xA943, 0x062D, 0x041E, 0xC316, 0x420F, 0xAA52, + 0xCC80, 0xCB69, 0x694B, 0xC72C, 0xE51D, 0xA316, 0x220F, 0xAA52, 0xCC80, 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x8316, 0x220F, 0xAA52, + 0xAC80, 0x6C71, 0xEA52, 0x6834, 0x8525, 0x441E, 0x020F, 0xAA52, 0xAC88, 0x4C71, 0xCA52, 0x283C, 0x6625, 0x241E, 0xE216, 0xAA52, + 0x8C88, 0x4C71, 0x8A5A, 0xE83B, 0x262D, 0x041E, 0xC316, 0xAA52, 0x8C88, 0x2C79, 0x6B5A, 0xC943, 0x062D, 0xE51D, 0xA316, 0xAA52, + 0x6C90, 0x0C79, 0x4B5A, 0x8943, 0xC72C, 0xC525, 0x8316, 0xAA52, 0x6C90, 0xEC78, 0x0B62, 0x694B, 0xA734, 0xA525, 0x6316, 0x8107, + 0x6C90, 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0x420F, 0x4C90, 0xCC80, 0xCB61, 0x0A4B, 0x483C, 0x4625, 0x241E, 0x220F, + 0x4B98, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0x041E, 0xE20E, 0x4B98, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xE51D, 0xC316, + 0x4B98, 0xAC88, 0x8C69, 0xAA52, 0xC843, 0xE72C, 0xC525, 0xA316, 0x2B98, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0xA525, 0x8316, + 0x2B98, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x8525, 0x6416, 0x2BA0, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x241E, + 0x2BA0, 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0x041E, 0x2BA0, 0x6C90, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xE41D, + 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0xC51D, 0x2AA8, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0xA525, + 0x0AA8, 0x4C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x0AA8, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, + 0x8B5A, 0x283C, 0xC525, 0xA316, 0x020F, 0x610F, 0x8107, 0xAA52, 0x4B5A, 0xE83B, 0x8525, 0x8316, 0x020F, 0x420F, 0x810F, 0xAA52, + 0x2B62, 0xA943, 0x4625, 0x6416, 0xE20E, 0x420F, 0x810F, 0xAA52, 0xEB61, 0x494B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0xAA52, + 0xAC69, 0x0A4B, 0xC72C, 0x041E, 0xA316, 0x220F, 0x610F, 0xAA52, 0x6C71, 0xCA52, 0x8734, 0xC525, 0x8316, 0x020F, 0x610F, 0xC007, + 0x4C71, 0x8B5A, 0x483C, 0x8525, 0x6416, 0xE20E, 0x420F, 0xC007, 0x2C79, 0x4B5A, 0xE83B, 0x4625, 0x441E, 0xC316, 0x420F, 0xA107, + 0x0C79, 0x0B62, 0xA943, 0x062D, 0x041E, 0xA316, 0x220F, 0xA107, 0xEC80, 0xEB61, 0x6943, 0xE72C, 0xE51D, 0x8316, 0x020F, 0x8107, + 0xCC80, 0xAC69, 0x494B, 0xA734, 0xC525, 0x6316, 0x020F, 0x810F, 0xAC80, 0x8C69, 0x0A4B, 0x6734, 0x8525, 0x441E, 0xE216, 0x610F, + 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x6625, 0x241E, 0xC316, 0x610F, 0x8C88, 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0xA316, 0x420F, + 0x8C88, 0x2C79, 0x6B5A, 0xC943, 0x062D, 0xE51D, 0x8316, 0x220F, 0x6C88, 0x0C79, 0x4B5A, 0xA943, 0xC72C, 0xC525, 0x6316, 0x220F, + 0x6C90, 0x0C79, 0x2B62, 0x6943, 0xA734, 0x8525, 0x441E, 0x020F, 0x6C90, 0xEC80, 0x0B62, 0x494B, 0x8734, 0x6525, 0x241E, 0xE216, + 0x4C90, 0xCC80, 0xEB61, 0x2A4B, 0x4834, 0x4625, 0x041E, 0xC316, 0x4C90, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x262D, 0xE41D, 0xA316, + 0x4B98, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xC51D, 0x8316, 0x4B98, 0xAC88, 0x8C69, 0xAA52, 0xE843, 0xE72C, 0xA525, 0x6316, + 0x4B98, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x6416, 0x2B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x441E, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x4625, 0x241E, 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0x041E, + 0x2BA0, 0x6C90, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xE51D, 0x2BA0, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xC525, + 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0xA525, 0x2AA8, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, + 0x0AA8, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x0AA8, 0x4C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x462D, + 0x6B5A, 0x083C, 0xA525, 0x8316, 0x020F, 0x420F, 0x610F, 0xA107, 0x2B62, 0xC943, 0x6625, 0x6416, 0xE20E, 0x420F, 0x610F, 0xA107, + 0x0B62, 0x8943, 0x262D, 0x441E, 0xE316, 0x220F, 0x610F, 0xA107, 0xCB69, 0x2A4B, 0xE62C, 0x041E, 0xC316, 0x220F, 0x610F, 0x8107, + 0x8C69, 0xEA52, 0xA734, 0xE51D, 0xA316, 0x020F, 0x410F, 0x8107, 0x6C71, 0xAA52, 0x6734, 0xA525, 0x6316, 0xE20E, 0x420F, 0x810F, + 0x2C71, 0x6B5A, 0x283C, 0x6625, 0x441E, 0xC316, 0x220F, 0x810F, 0x0C79, 0x2B62, 0xC943, 0x262D, 0x241E, 0xA316, 0x220F, 0x610F, + 0xEC78, 0xEB61, 0x8943, 0xE62C, 0xE41D, 0x8316, 0x020F, 0x610F, 0xCC80, 0xCB69, 0x494B, 0xA734, 0xC525, 0x6316, 0xE20E, 0x410F, + 0xCC80, 0x8C69, 0x0A4B, 0x8734, 0x8525, 0x441E, 0xC316, 0x420F, 0xAC80, 0x6C71, 0xEA52, 0x483C, 0x6625, 0x241E, 0xC316, 0x220F, + 0x8C88, 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0xA316, 0x220F, 0x8C88, 0x2C71, 0x8B5A, 0xE843, 0x062D, 0xE51D, 0x8316, 0x020F, + 0x8C88, 0x2C79, 0x4B5A, 0xA943, 0xE72C, 0xC525, 0x6416, 0xE20E, 0x6C90, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x441E, 0xE316, + 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x8734, 0x6625, 0x241E, 0xC316, 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0x041E, 0xA316, + 0x4C90, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x262D, 0xE51D, 0x8316, 0x4B90, 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x6316, + 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xE843, 0xC72C, 0xA525, 0x6416, 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x441E, + 0x2B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x241E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x462D, 0x041E, + 0x2BA0, 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x262D, 0xE51D, 0x2BA0, 0x6C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xC525, + 0x2BA0, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, + 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6625, 0x2AA8, 0x4C90, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x4625, + 0x0AA8, 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0x0AA8, 0x4B90, 0xCC80, 0x8C69, 0x8B5A, 0x694B, 0x483C, 0x062D, + 0x4B5A, 0xC943, 0x6525, 0x6416, 0xE216, 0x220F, 0x610F, 0x810F, 0x0B62, 0x8943, 0x462D, 0x441E, 0xC316, 0x220F, 0x610F, 0x810F, + 0xEB61, 0x494B, 0x062D, 0x241E, 0xC316, 0x020F, 0x410F, 0x810F, 0xAC69, 0x0A4B, 0xC734, 0xE51D, 0xA316, 0x020F, 0x420F, 0x610F, + 0x6C71, 0xCA52, 0x8734, 0xA525, 0x8316, 0xE20E, 0x220F, 0x610F, 0x4C71, 0x8B5A, 0x283C, 0x8525, 0x441E, 0xC316, 0x220F, 0x610F, + 0x2C79, 0x4B5A, 0xE83B, 0x462D, 0x241E, 0xA316, 0x020F, 0x410F, 0x0C79, 0x0B62, 0xA943, 0x062D, 0xE41D, 0x8316, 0xE20E, 0x420F, + 0xEC80, 0xCB69, 0x694B, 0xC734, 0xC525, 0x6316, 0xE316, 0x220F, 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x441E, 0xC316, 0x220F, + 0xAC80, 0x8C71, 0xEA52, 0x483C, 0x6625, 0x241E, 0xA316, 0x020F, 0xAC88, 0x6C71, 0xCA52, 0x083C, 0x262D, 0x041E, 0x8316, 0x020F, + 0x8C88, 0x4C71, 0x8B5A, 0xE83B, 0x062D, 0xC51D, 0x6316, 0xE216, 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xC316, + 0x6C90, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x8734, 0x6625, 0x041E, 0xA316, + 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0xE41D, 0x8316, 0x4C90, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xC51D, 0x6316, + 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x441E, 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0x241E, + 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x241E, 0x4B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0x041E, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xE51D, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xC525, + 0x2BA0, 0x6C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0xA525, 0x2BA0, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0xE83B, 0xC72C, 0x8525, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x6525, 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x4625, + 0x2AA0, 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x6734, 0x462D, 0x2AA8, 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x262D, + 0x0AA8, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x694B, 0x283C, 0x062D, 0x0AA8, 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, + 0x2B62, 0xA943, 0x462D, 0x441E, 0xC316, 0x220F, 0x420F, 0x610F, 0xEB61, 0x694B, 0x062D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, + 0xCB69, 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0x8C69, 0xEA52, 0x8734, 0xC525, 0x8316, 0xE216, 0x220F, 0x610F, + 0x6C71, 0xAA52, 0x483C, 0x8525, 0x6416, 0xC316, 0x220F, 0x410F, 0x2C71, 0x4B5A, 0x083C, 0x4625, 0x241E, 0xA316, 0x020F, 0x420F, + 0x0C79, 0x2B62, 0xC943, 0x062D, 0x041E, 0x8316, 0xE20E, 0x220F, 0xEC78, 0xEB61, 0x6943, 0xC72C, 0xC525, 0x6316, 0xC316, 0x220F, + 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0xA525, 0x441E, 0xC316, 0x020F, 0xCC80, 0x8C69, 0x0A53, 0x6834, 0x6625, 0x241E, 0xA316, 0x020F, + 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE216, 0x8C88, 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xC51D, 0x6416, 0xC316, + 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xC316, 0x6C88, 0x0C79, 0x2B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, + 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x8734, 0x6625, 0x041E, 0x8316, 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x6316, + 0x4C90, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xC525, 0x441E, 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x441E, + 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0x241E, 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x041E, + 0x4B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x462D, 0xE51D, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x4834, 0x262D, 0xC525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x494B, 0x283C, 0x062D, 0xA525, 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x083C, 0xE72C, 0x8525, + 0x2BA0, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0xA734, 0x6625, + 0x2AA0, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x462D, 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x262D, + 0x2AA8, 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0x062D, 0x0AA8, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xE72C, + 0x0AA8, 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xC72C, 0x0AA8, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, + 0x0B62, 0x8943, 0x262D, 0x241E, 0xA316, 0x020F, 0x420F, 0x610F, 0xCB69, 0x494B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x220F, 0x610F, + 0xAC69, 0x0A4B, 0xA734, 0xC51D, 0x8316, 0xE216, 0x220F, 0x410F, 0x6C71, 0xAA52, 0x6734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, + 0x4C71, 0x6B5A, 0x283C, 0x6625, 0x441E, 0xA316, 0x020F, 0x420F, 0x2C79, 0x2B5A, 0xE843, 0x262D, 0x041E, 0x8316, 0xE20E, 0x220F, + 0x0C79, 0x0B62, 0x8943, 0xE72C, 0xE51D, 0x6316, 0xC316, 0x220F, 0xEC80, 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, + 0xCC80, 0x8C69, 0x0A4B, 0x6734, 0x6525, 0x241E, 0xA316, 0xE20E, 0xAC80, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE316, + 0xAC88, 0x4C71, 0xAA52, 0xE83B, 0x062D, 0xC51D, 0x6416, 0xC316, 0x8C88, 0x2C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xA316, + 0x8C88, 0x0C79, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x8734, 0x4625, 0x041E, 0x8316, + 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x6416, 0x6C90, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xC525, 0x441E, + 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x241E, 0x4B90, 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6525, 0x041E, + 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC51D, + 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x294B, 0x283C, 0xE62C, 0xA525, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x8525, 0x2BA0, 0x6C90, 0x0C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x6625, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x462D, 0x2BA0, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, + 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x2AA0, 0x4C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x483C, 0xE62C, + 0x2AA8, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x0AA8, 0x4B98, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, + 0x0AA8, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xE83B, 0xA734, 0x0AA8, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x8734, + 0xEB61, 0x494B, 0x062D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x410F, 0xCC69, 0x0A4B, 0xC734, 0xE51D, 0x8316, 0xE216, 0x220F, 0x420F, + 0x8C69, 0xEA52, 0x8734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, 0x6C71, 0x8A5A, 0x483C, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, + 0x2C71, 0x4B5A, 0x083C, 0x462D, 0x241E, 0xA316, 0xE20E, 0x220F, 0x0C79, 0x0B62, 0xA943, 0x062D, 0xE51D, 0x8316, 0xC316, 0x020F, + 0xEC78, 0xEB61, 0x694B, 0xC734, 0xC525, 0x441E, 0xC316, 0x020F, 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE20E, + 0xAC80, 0x8C71, 0xEA52, 0x483C, 0x462D, 0x041E, 0x8316, 0xC316, 0xAC88, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x6416, 0xC316, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xA316, 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, + 0x6C88, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x4625, 0xE41D, 0x6316, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x441E, + 0x6C90, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x241E, + 0x4C90, 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0x041E, 0x4B98, 0xAC88, 0x8C71, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, + 0x2B98, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x4625, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, + 0x2BA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x262D, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0x062D, + 0x2AA0, 0x4C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x2AA0, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, + 0x2AA8, 0x4B90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x0AA8, 0x4B98, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC843, 0x8734, + 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, + 0xCB69, 0x2A4B, 0xC72C, 0xE51D, 0x8316, 0xE316, 0x020F, 0x420F, 0xAC69, 0xEA52, 0x8734, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, + 0x8C71, 0xAA52, 0x6834, 0x8525, 0x441E, 0xC316, 0x020F, 0x220F, 0x4C71, 0x6B5A, 0x083C, 0x4625, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x2C79, 0x2B62, 0xC943, 0x062D, 0xE41D, 0x8316, 0xC316, 0x020F, 0x0C79, 0xEB61, 0x8943, 0xC72C, 0xC525, 0x6416, 0xC316, 0x020F, + 0xEC80, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE20E, 0xCC80, 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xC316, + 0xAC80, 0x6C71, 0xCA52, 0x083C, 0x262D, 0xE51D, 0x6416, 0xC316, 0xAC88, 0x4C71, 0x8B5A, 0xC843, 0xE72C, 0xA525, 0x441E, 0xA316, + 0x8C88, 0x2C79, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x8316, 0x8C88, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x6625, 0xE41D, 0x6416, + 0x6C90, 0xEC78, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x6C90, 0xEC80, 0xCB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE41D, + 0x4B98, 0xAC80, 0x8C71, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC51D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xA525, + 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x8525, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x462D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0x2BA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xE72C, 0x2AA0, 0x4C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, + 0x2AA0, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0x083C, 0xA734, 0x2AA8, 0x4B90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2AA8, 0x4B98, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, + 0x0AA8, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0x09A8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, + 0xCC69, 0x0A4B, 0xA734, 0xC525, 0x6316, 0xC316, 0x020F, 0x220F, 0x8C69, 0xCA52, 0x6734, 0xA525, 0x441E, 0xA316, 0x020F, 0x220F, + 0x6C71, 0x8A5A, 0x483C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x4C71, 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, + 0x0C79, 0x0B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x020F, 0xEC78, 0xEB61, 0x694B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, + 0xCC80, 0xAC69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0xCC80, 0x8C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xC316, + 0xAC88, 0x4C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x441E, 0xA316, 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0x8316, + 0x8C88, 0x0C79, 0x2B5A, 0x6943, 0x8734, 0x6625, 0x041E, 0x6416, 0x6C88, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC51D, 0x441E, + 0x6C90, 0xEC80, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0xCC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x4C90, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC51D, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0xA525, 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6525, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, + 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2BA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xE72C, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x2AA0, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x2AA8, 0x4B98, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xC943, 0x6734, + 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0x0AA8, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x0AA8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x283C, 0x09A8, 0x2B98, 0x8C88, 0x2C79, 0xCB61, 0x8A5A, 0x494B, 0x083C, + 0xAC69, 0xEA52, 0x8734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x8C71, 0xAA52, 0x483C, 0x8525, 0x241E, 0xA316, 0xE216, 0x220F, + 0x6C71, 0x8B5A, 0x283C, 0x4625, 0x041E, 0x8316, 0xE316, 0x020F, 0x2C79, 0x4B5A, 0xC943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, + 0x0C79, 0x0B62, 0x8943, 0xC72C, 0xC525, 0x441E, 0xA316, 0xE20E, 0xEC78, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE316, + 0xCC80, 0x8C69, 0x0A53, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0xAC80, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xAC88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x6316, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0xCC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xE51D, + 0x4C90, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6834, 0x262D, 0xA525, + 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2BA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x4C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, + 0x2AA0, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, + 0x0AA8, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0x0AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x09A8, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE83B, + 0xAC69, 0xCA52, 0x6734, 0x8525, 0x441E, 0xA316, 0xE216, 0x020F, 0x6C71, 0x8A5A, 0x283C, 0x6625, 0x241E, 0x8316, 0xE316, 0x020F, + 0x4C71, 0x6B5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, 0x2C79, 0x2B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xA316, 0xE20E, + 0x0C79, 0xEB61, 0x694B, 0xA734, 0xA525, 0x241E, 0x8316, 0xE316, 0xEC80, 0xAC69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, + 0xCC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xAC80, 0x4C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, + 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, 0x8C88, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x4625, 0xE51D, 0x441E, + 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6C90, 0xEC80, 0xEB61, 0x0A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE41D, 0x4C90, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC51D, + 0x4C90, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x4C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x4B90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, + 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0x2AA8, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, + 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x0AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC843, 0x09A8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, + 0x8C69, 0xAA52, 0x483C, 0x6525, 0x241E, 0x8316, 0xC316, 0x020F, 0x6C71, 0x8B5A, 0x083C, 0x462D, 0x041E, 0x8316, 0xC316, 0x020F, + 0x4C71, 0x4B5A, 0xE843, 0x062D, 0xE51D, 0x6416, 0xC316, 0xE20E, 0x2C79, 0x0B62, 0x8943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, + 0xEC78, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x4625, 0xE41D, 0x6416, 0xA316, + 0xCC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xAC88, 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0x8525, 0x241E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x6416, 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x262D, 0xC525, 0x441E, + 0x6C88, 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0x083C, 0xC72C, 0x8525, 0x041E, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x4C90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, + 0x4C90, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, + 0x4B98, 0x8C88, 0x2C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, + 0x2AA0, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x0AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x09A8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0xA943, + 0x8C71, 0xAA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0xE20E, 0x6C71, 0x6B5A, 0xE83B, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE20E, + 0x2C71, 0x2B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE216, 0x0C79, 0xEB61, 0x6943, 0xA734, 0xA525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x6316, 0xC316, 0xCC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, + 0xAC80, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6416, + 0x8C88, 0x2C79, 0x2B62, 0x694B, 0x8734, 0x462D, 0xE51D, 0x441E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0xEC80, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xE843, 0xA734, 0x6625, 0xE51D, + 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x4834, 0x062D, 0xA525, + 0x4B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x2AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, + 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x09A8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, + 0x6C71, 0x8B5A, 0x083C, 0x462D, 0x041E, 0x6316, 0xA316, 0xE20E, 0x4C71, 0x4B5A, 0xE843, 0x062D, 0xE51D, 0x441E, 0xA316, 0xE216, + 0x2C71, 0x2B62, 0xA943, 0xE72C, 0xA525, 0x441E, 0x8316, 0xC316, 0x0C79, 0xEB61, 0x694B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0xAC69, 0x0A4B, 0x6834, 0x4625, 0xE41D, 0x6416, 0xA316, 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, + 0xAC80, 0x6C71, 0x8A5A, 0xC843, 0xE72C, 0x8525, 0x041E, 0x6316, 0xAC88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x8C88, 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, + 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, + 0x4C90, 0xAC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x4C90, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x283C, 0xE62C, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x6C88, 0x0C79, 0xCB69, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x2AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE83B, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, + 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, 0x09A8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, + 0x6C71, 0x6B5A, 0x083C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE316, 0x4C71, 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xC316, + 0x2C79, 0x0B62, 0x8943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6316, 0xA316, + 0xEC80, 0xAC69, 0x0A53, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xCC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xAC80, 0x4C71, 0x8B5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6416, 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x0C79, 0x0B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C88, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x4625, 0xE51D, 0x6C90, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0x4C90, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, + 0x2AA0, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, + 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x09A8, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x6C71, 0x6B5A, 0xE83B, 0x062D, 0xC51D, 0x441E, 0xA316, 0xC316, 0x4C71, 0x2B62, 0xA943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0x0B62, 0x6943, 0xA734, 0x8525, 0x241E, 0x6316, 0xC316, 0x0C79, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0xE41D, 0x6416, 0xA316, + 0xEC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x441E, 0x8316, 0xCC80, 0x6C71, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x6316, + 0xAC80, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8C88, 0x2C79, 0x2B62, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6C88, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, + 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0x2BA0, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, 0x0AA8, 0x2B98, 0x8C88, 0xEC80, 0x8C71, 0x2B62, 0xCA52, 0x694B, + 0x0AA8, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x6C71, 0x4B5A, 0xC943, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x4C71, 0x2B62, 0x8943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0xEB61, 0x694B, 0x8734, 0x8525, 0x041E, 0x6416, 0xA316, 0x0C79, 0xCB69, 0x0A4B, 0x4834, 0x462D, 0xE51D, 0x441E, 0x8316, + 0xEC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0x6C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x241E, + 0x8C88, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C88, 0xEC80, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xC51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, + 0x4C90, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, 0x4B90, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x4B98, 0x6C88, 0x0C79, 0xCC69, 0xAA52, 0x694B, 0x283C, 0xC734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4B90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB61, 0x8A5A, 0x494B, 0xE83B, + 0x2AA0, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, + 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x6C71, 0x4B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x4C71, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, + 0x2C79, 0xEB61, 0x494B, 0x8734, 0x6625, 0xE41D, 0x6416, 0xA316, 0x0C79, 0xAC69, 0x0A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, + 0xEC80, 0x8C69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x6316, 0xCC80, 0x6C71, 0x8B5A, 0xC943, 0xC734, 0x6525, 0xE41D, 0x441E, + 0xAC80, 0x2C71, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xC525, 0x241E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x6C90, 0xEC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x6C90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6525, + 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, 0x4B90, 0x8C88, 0x2C71, 0x0B62, 0x0A53, 0xC843, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x2AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, + 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, + 0x6C71, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x6316, 0xA316, 0x4C71, 0x0B62, 0x6943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0xEB61, 0x494B, 0x6734, 0x4625, 0xE51D, 0x441E, 0x8316, 0xEC78, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xEC80, 0x8C71, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0xCC80, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC88, 0x2C79, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x4834, 0x062D, 0x8525, 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x4B90, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A53, 0xA943, 0x6834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x0A4B, 0xC943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xEA52, 0x8943, + 0x2AA0, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x0AA8, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x294B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x6C71, 0x2B5A, 0x8943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C71, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE41D, 0x441E, 0x8316, + 0x2C79, 0xEB61, 0x2A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0x8316, 0xEC78, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0x6C71, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x041E, 0x441E, 0xCC80, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xC51D, 0x241E, + 0xAC88, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xA525, 0x041E, 0x8C88, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, + 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x4625, + 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4B98, 0x6C88, 0x0C79, 0xAC69, 0x8A5A, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4B90, 0xAC88, 0x2C79, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x2AA0, 0x2B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xAC69, 0x4B5A, 0xEA52, + 0x4C71, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0x8316, 0x2C71, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xEC78, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x6416, + 0xCC80, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, + 0xAC88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x8C88, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xAC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4C90, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x4B90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x6C88, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2B98, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xCA52, 0x694B, + 0x2AA0, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xEA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, + 0x4C71, 0x2B62, 0x6943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x2C71, 0xEB61, 0x494B, 0x6734, 0x462D, 0xC51D, 0x241E, 0x8316, + 0x0C79, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x6316, 0xEC78, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x441E, + 0xCC80, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x241E, + 0xAC88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x4625, 0xC51D, + 0x8C88, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0xE62C, 0x8525, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8A5A, 0x694B, 0x083C, 0xA734, 0x4B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x4B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2B98, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x4C71, 0x2B62, 0x694B, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C71, 0xEB61, 0x2A4B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC78, 0x8C69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, + 0xCC80, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xCC80, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, + 0xAC88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0x8C88, 0xEC78, 0xCB69, 0xEA52, 0xE843, 0xA734, 0x462D, 0xC525, + 0x8C88, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xAC88, 0x4C71, 0x0B62, 0x0A4B, 0xC843, 0x8734, 0x262D, + 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x4B90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A53, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2B98, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x294B, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, + 0x4C71, 0x0B62, 0x694B, 0x8734, 0x4625, 0xC51D, 0x241E, 0x6316, 0x2C71, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6416, + 0x2C79, 0xCB69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC78, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0xAC88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x262D, 0xA525, + 0x8C88, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xAC80, 0x4C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x6C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x2B98, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x294B, 0xE843, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xEA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x0AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, + 0x4C71, 0x0B62, 0x494B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, 0x2C71, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0x2C79, 0xCC69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, 0xEC78, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x241E, + 0xEC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, + 0xAC80, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4C90, 0x8C88, 0x2C79, 0xCB61, 0xAA52, 0x8943, 0x283C, 0xC72C, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x4B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A52, 0x2A4B, 0x2AA0, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x0AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x6C71, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6416, 0x2C71, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x2C79, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0xE41D, 0x441E, 0x0C79, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC525, 0x241E, + 0xEC80, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, + 0xAC80, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0x8525, + 0x8C88, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x262D, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B5A, 0xEA52, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0x2B98, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x294B, 0xE843, 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xCA52, 0x6943, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, + 0x0AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x0AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, + 0x6C71, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x041E, 0x6416, 0x4C71, 0xEB61, 0x0A53, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0x2C79, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x241E, 0x0C79, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xEC80, 0x6C71, 0x4B5A, 0x694B, 0x6834, 0x062D, 0xA525, 0x041E, 0xCC80, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, + 0xAC80, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x062D, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, + 0x4B98, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, + 0x2AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x0AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x4C71, 0xCB61, 0xEA52, 0x083C, 0xE62C, 0x8525, 0xE41D, 0x441E, + 0x2C79, 0xAC69, 0xCA52, 0xE843, 0xC734, 0x6625, 0xE51D, 0x241E, 0x0C79, 0x8C69, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, + 0xEC80, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xCC80, 0x2C71, 0x0B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, + 0xAC80, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x262D, 0xA525, 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x8C88, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x6C88, 0xCC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x4C90, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, + 0x4B98, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x4B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, + 0x2B98, 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x2B5A, 0xEA52, 0x6943, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, 0x4C71, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, + 0x2C79, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xC525, 0x241E, 0x0C79, 0x8C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC80, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE51D, 0xCC80, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xAC80, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6525, + 0x8C88, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0x8734, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4B98, 0x6C88, 0xEC80, 0x8C71, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC843, + 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x2BA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, + 0x2AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x0B62, 0x0A4B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, 0x4C71, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6625, 0xE51D, 0x241E, + 0x2C79, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0x0C79, 0x8C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xEC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x6525, 0xE51D, 0xCC80, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xC525, + 0xAC80, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0x8525, 0xAC88, 0xEC78, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xCC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x8C88, 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x6C90, 0xAC80, 0x2C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x4B90, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA0, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x4C71, 0xCB69, 0x4B5A, + 0x6C71, 0x0B62, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x4C71, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, + 0x2C79, 0xAC69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xA525, 0x041E, 0x0C79, 0x8C71, 0x6B5A, 0x6943, 0x6734, 0x062D, 0x8525, 0xE41D, + 0xEC80, 0x4C71, 0x2B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xCC80, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xA525, + 0xAC80, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0xAC88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x8C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, 0x8C88, 0xCC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4C90, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE843, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x6943, + 0x2B98, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2BA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x2AA0, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xCB69, 0x4B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x4C71, 0xCB69, 0x4B5A, + 0x6C71, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x4C71, 0xCB69, 0xCA52, 0xE843, 0xC734, 0x4625, 0xC525, 0x041E, + 0x2C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0x0C79, 0x8C71, 0x6B5A, 0x6943, 0x4834, 0x062D, 0x8525, 0xE51D, + 0xEC78, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xC72C, 0x6625, 0xC525, 0xCC80, 0x2C79, 0x0B62, 0xEA52, 0xE83B, 0xA734, 0x262D, 0xA525, + 0xAC80, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0xAC88, 0xEC78, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x8C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x8C88, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0xE62C, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0xAC88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x4C90, 0x6C88, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x4B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2B98, 0x4B90, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2B98, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xCA52, 0x2BA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x2BA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA0, 0x2BA0, 0x4C90, 0xAC88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, + 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x4C71, 0xCB69, 0x4B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, + 0xEA52, 0x8734, 0x041E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, 0xAA52, 0x483C, 0xC51D, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0x6B5A, 0x083C, 0xA525, 0x8316, 0x020F, 0x610F, 0xA107, 0xAA52, 0x2B62, 0xA943, 0x6625, 0x6416, 0x020F, 0x410F, 0xA107, 0xAA52, + 0xEB61, 0x694B, 0x262D, 0x441E, 0xE316, 0x420F, 0xA107, 0xAA52, 0xAC69, 0x2A4B, 0xE72C, 0x041E, 0xC316, 0x220F, 0x8107, 0xAA52, + 0x8C71, 0xEA52, 0xA734, 0xC51D, 0xA316, 0x220F, 0x810F, 0xAA52, 0x4C71, 0x8A5A, 0x483C, 0xA525, 0x6316, 0x020F, 0x610F, 0xAA52, + 0x2C79, 0x4B5A, 0x083C, 0x6625, 0x441E, 0xE216, 0x610F, 0xAA52, 0x0C79, 0x2B62, 0xC943, 0x262D, 0x241E, 0xC316, 0x410F, 0xAA52, + 0xEC78, 0xEB61, 0x8943, 0xE62C, 0x041E, 0xA316, 0x420F, 0xAA52, 0xCC80, 0xCB69, 0x694B, 0xC734, 0xC51D, 0x8316, 0x220F, 0xAA52, + 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0xA525, 0x6316, 0x020F, 0xAA52, 0xAC80, 0x8C71, 0xEA52, 0x4834, 0x6525, 0x441E, 0x020F, 0xAA52, + 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x4625, 0x241E, 0xE316, 0xAA52, 0x8C88, 0x4C71, 0x8A5A, 0xE83B, 0x262D, 0x041E, 0xC316, 0xAA52, + 0x8C88, 0x2C79, 0x6B5A, 0xC943, 0xE62C, 0xE51D, 0xA316, 0xAA52, 0x6C90, 0x0C79, 0x4B5A, 0x8943, 0xC734, 0xC525, 0x8316, 0xAA52, + 0x6C90, 0x0C79, 0x2B62, 0x694B, 0xA734, 0x8525, 0x6416, 0xAA52, 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6525, 0x441E, 0x410F, + 0x4C90, 0xCC80, 0xEB61, 0x0A4B, 0x483C, 0x462D, 0x241E, 0x220F, 0x4B90, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x262D, 0x041E, 0xE20E, + 0x4B98, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xE51D, 0xC316, 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xE72C, 0xC525, 0xA316, + 0x4B98, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0xA525, 0x8316, 0x2B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6525, 0x441E, + 0x2BA0, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x241E, 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0x041E, + 0x2BA0, 0x6C88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xE51D, 0x2AA0, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xC525, + 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xC734, 0xA525, 0x2AA8, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, + 0xAA52, 0x6834, 0xE51D, 0xA316, 0x220F, 0x610F, 0x8107, 0xAA52, 0x8B5A, 0x283C, 0xA525, 0x8316, 0x020F, 0x410F, 0x8107, 0xAA52, + 0x4B5A, 0xE83B, 0x8525, 0x6316, 0x020F, 0x420F, 0x810F, 0xAA52, 0x0B62, 0x8943, 0x462D, 0x441E, 0xE216, 0x420F, 0x810F, 0xAA52, + 0xCB69, 0x494B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0xAA52, 0x8C69, 0x0A53, 0xC734, 0xE51D, 0xA316, 0x020F, 0x610F, 0xAA52, + 0x6C71, 0xAA52, 0x6734, 0xA525, 0x8316, 0x020F, 0x410F, 0xAA52, 0x4C71, 0x6B5A, 0x283C, 0x6525, 0x441E, 0xE316, 0x420F, 0xAA52, + 0x0C79, 0x4B5A, 0xE83B, 0x462D, 0x241E, 0xC316, 0x220F, 0xAA52, 0x0C79, 0x0B62, 0xA943, 0x062D, 0x041E, 0xA316, 0x220F, 0xC007, + 0xEC80, 0xEB61, 0x694B, 0xC734, 0xC51D, 0x8316, 0x020F, 0xA107, 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0xA525, 0x6416, 0xE20E, 0x8107, + 0xAC80, 0x8C69, 0x0A53, 0x6834, 0x8525, 0x441E, 0xC316, 0x810F, 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x4625, 0x241E, 0xC316, 0x610F, + 0x8C88, 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0xA316, 0x420F, 0x8C88, 0x2C71, 0x6B5A, 0xC943, 0xE62C, 0xC51D, 0x8316, 0x220F, + 0x6C88, 0x0C79, 0x4B5A, 0xA943, 0xC734, 0xA525, 0x6416, 0x220F, 0x6C90, 0x0C79, 0x2B62, 0x6943, 0xA734, 0x8525, 0x441E, 0x020F, + 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6625, 0x241E, 0xE216, 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0x041E, 0xC316, + 0x4C90, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0xA316, 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xC525, 0x8316, + 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0xA525, 0x6316, 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x441E, + 0x2B98, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x241E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0x041E, + 0x2BA0, 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x262D, 0xE41D, 0x2BA0, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xC51D, + 0x2BA0, 0x6C90, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, + 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6525, 0x2AA8, 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x4625, + 0x8A52, 0x283C, 0xC525, 0x8316, 0x020F, 0x420F, 0x810F, 0xA107, 0x6B5A, 0xE83B, 0x8525, 0x6316, 0x020F, 0x420F, 0x610F, 0xA107, + 0x2B62, 0xC943, 0x6625, 0x441E, 0xE216, 0x220F, 0x610F, 0xA107, 0xEB61, 0x694B, 0x262D, 0x241E, 0xC316, 0x220F, 0x610F, 0xA107, + 0xAC69, 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x610F, 0x8107, 0x8C69, 0xEA52, 0x8734, 0xC525, 0x8316, 0x020F, 0x420F, 0x8107, + 0x4C71, 0x8A52, 0x483C, 0x8525, 0x6416, 0xE216, 0x420F, 0x810F, 0x2C79, 0x4B5A, 0x083C, 0x4625, 0x241E, 0xC316, 0x220F, 0x610F, + 0x0C79, 0x2B62, 0xC943, 0x062D, 0x041E, 0xA316, 0x020F, 0x610F, 0xEC78, 0xEB61, 0x8943, 0xE72C, 0xE51D, 0x8316, 0x020F, 0x610F, + 0xCC80, 0xCB69, 0x494B, 0xA734, 0xA525, 0x6416, 0xE216, 0x420F, 0xCC80, 0xAC69, 0x0A4B, 0x6734, 0x8525, 0x441E, 0xC316, 0x420F, + 0xAC80, 0x6C71, 0xEA52, 0x283C, 0x4625, 0x241E, 0xA316, 0x220F, 0xAC88, 0x4C71, 0xAA52, 0x083C, 0x262D, 0xE41D, 0x8316, 0x020F, + 0x8C88, 0x4C71, 0x8B5A, 0xC843, 0x062D, 0xC51D, 0x6316, 0x020F, 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x6416, 0xE20E, + 0x6C90, 0x0C79, 0x2B62, 0x6943, 0xA734, 0x8525, 0x441E, 0xC316, 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6625, 0x241E, 0xC316, + 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0x041E, 0xA316, 0x4C90, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xE51D, 0x8316, + 0x4B90, 0xCC80, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xC525, 0x6316, 0x4B98, 0xAC80, 0xAC69, 0xAA52, 0xE843, 0xC72C, 0xA525, 0x441E, + 0x4B98, 0xAC88, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x241E, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x241E, + 0x2B98, 0x8C88, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x462D, 0x041E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x262D, 0xE51D, + 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x2BA0, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6625, + 0x2AA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x8734, 0x462D, 0x2AA8, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x262D, + 0x6B5A, 0x083C, 0xA525, 0x6316, 0xE20E, 0x420F, 0x610F, 0x8107, 0x4B5A, 0xC943, 0x6625, 0x441E, 0xE316, 0x220F, 0x610F, 0x810F, + 0x0B62, 0x8943, 0x262D, 0x241E, 0xC316, 0x220F, 0x410F, 0x810F, 0xCB69, 0x494B, 0xE62C, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, + 0xAC69, 0xEA52, 0xA734, 0xC51D, 0x8316, 0xE20E, 0x420F, 0x610F, 0x6C71, 0xAA52, 0x6734, 0xA525, 0x6416, 0xE316, 0x220F, 0x610F, + 0x4C71, 0x6B5A, 0x283C, 0x6625, 0x441E, 0xC316, 0x020F, 0x610F, 0x0C79, 0x2B62, 0xC843, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, + 0xEC78, 0x0B62, 0x8943, 0xE72C, 0xE51D, 0x8316, 0xE216, 0x420F, 0xEC80, 0xCB69, 0x494B, 0xA734, 0xA525, 0x6416, 0xC316, 0x220F, + 0xCC80, 0xAC69, 0x2A4B, 0x6734, 0x8525, 0x241E, 0xA316, 0x220F, 0xAC80, 0x8C71, 0xEA52, 0x483C, 0x4625, 0x041E, 0xA316, 0x020F, + 0xAC88, 0x6C71, 0xAA52, 0x083C, 0x262D, 0xE51D, 0x8316, 0xE20E, 0x8C88, 0x4C71, 0x8B5A, 0xC843, 0xE62C, 0xC525, 0x6416, 0xE316, + 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC734, 0xA525, 0x441E, 0xC316, 0x6C88, 0x0C79, 0x2B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, + 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x4625, 0x041E, 0x8316, 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x8316, + 0x4C90, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xC525, 0x6416, 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0x083C, 0xE72C, 0xA525, 0x441E, + 0x4B98, 0xAC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x241E, 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x041E, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0x041E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xE51D, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xC525, 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0xA525, + 0x2BA0, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x6625, + 0x2AA0, 0x6C90, 0x0C79, 0xCB61, 0xCA52, 0xC943, 0x8734, 0x4625, 0x2AA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x6734, 0x262D, + 0x2AA8, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0x062D, 0x0AA8, 0x4C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0x062D, + 0x4B5A, 0xE843, 0x6525, 0x6416, 0xE316, 0x220F, 0x410F, 0x610F, 0x2B62, 0xA943, 0x462D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, + 0xEB61, 0x694B, 0x062D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0xAC69, 0x0A4B, 0xC734, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x610F, + 0x8C71, 0xCA52, 0x8734, 0xA525, 0x6316, 0xE316, 0x220F, 0x610F, 0x4C71, 0x8A5A, 0x483C, 0x6525, 0x441E, 0xC316, 0x020F, 0x420F, + 0x2C79, 0x4B5A, 0xE83B, 0x462D, 0x041E, 0xA316, 0x020F, 0x420F, 0x0C79, 0x0B62, 0xA943, 0xE62C, 0xE51D, 0x8316, 0xE216, 0x220F, + 0xEC80, 0xEB61, 0x694B, 0xC734, 0xA525, 0x6416, 0xC316, 0x220F, 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0x020F, + 0xAC80, 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xE20E, 0xAC88, 0x6C71, 0xCA52, 0x083C, 0x262D, 0xE51D, 0x6316, 0xE316, + 0x8C88, 0x4C71, 0x8A5A, 0xC843, 0xE62C, 0xC525, 0x441E, 0xC316, 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC734, 0xA525, 0x241E, 0xA316, + 0x8C88, 0x0C79, 0x4B5A, 0x8943, 0xA734, 0x6525, 0x041E, 0x8316, 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE41D, 0x8316, + 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x6416, 0x6C90, 0xCC80, 0xCB69, 0x0A53, 0x083C, 0x062D, 0xA525, 0x441E, + 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x241E, 0x4B90, 0xAC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6525, 0x041E, + 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x4625, 0xE41D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xE51D, + 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xC525, 0x2B98, 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x283C, 0x062D, 0xA525, + 0x2B98, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x8525, 0x2BA0, 0x6C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xC734, 0x6625, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0xA734, 0x4625, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x462D, + 0x2AA0, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x6834, 0x262D, 0x2AA0, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0x062D, + 0x2AA8, 0x4C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x0AA8, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, + 0x2B62, 0xA943, 0x462D, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x0B62, 0x6943, 0x062D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, + 0xCB69, 0x294B, 0xE72C, 0xE41D, 0x8316, 0xE20E, 0x220F, 0x610F, 0x8C69, 0xEA52, 0xA734, 0xC525, 0x6316, 0xE316, 0x220F, 0x420F, + 0x6C71, 0xAA52, 0x4834, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x4C71, 0x6B5A, 0x083C, 0x4625, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x0C79, 0x2B62, 0xC943, 0x062D, 0xE41D, 0x8316, 0xE216, 0x220F, 0xEC78, 0xEB61, 0x8943, 0xC734, 0xC525, 0x6416, 0xC316, 0x020F, + 0xCC80, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0xA316, 0x020F, 0xCC80, 0x8C69, 0x0A4B, 0x483C, 0x6625, 0x041E, 0x8316, 0xE216, + 0xAC80, 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6316, 0xC316, 0xAC88, 0x4C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x441E, 0xC316, + 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xA316, 0x8C88, 0x0C79, 0x4B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0x8316, + 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x6316, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, + 0x6C90, 0xCC80, 0xCB69, 0xEA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x241E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0x041E, 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xC525, 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x294B, 0x283C, 0xE72C, 0x8525, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x6625, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x462D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0x2BA0, 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x483C, 0x062D, + 0x2AA0, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xE62C, 0x2AA0, 0x4C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC72C, + 0x2AA8, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0x083C, 0xA734, 0x0AA8, 0x4B90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xE83B, 0xA734, + 0x0B62, 0x8943, 0x262D, 0x241E, 0xA316, 0x020F, 0x220F, 0x410F, 0xEB61, 0x494B, 0xE62C, 0xE41D, 0x8316, 0xE20E, 0x220F, 0x420F, + 0xAC69, 0x0A4B, 0xC734, 0xC51D, 0x8316, 0xE316, 0x220F, 0x420F, 0x8C69, 0xCA52, 0x6734, 0xA525, 0x441E, 0xC316, 0x020F, 0x420F, + 0x4C71, 0x8B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x2C79, 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xE316, 0x220F, + 0x0C79, 0x0B62, 0xA943, 0xE72C, 0xC51D, 0x6416, 0xC316, 0x020F, 0xEC80, 0xCB69, 0x494B, 0xA734, 0x8525, 0x441E, 0xA316, 0xE20E, + 0xCC80, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE316, 0xAC80, 0x8C71, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6316, 0xC316, + 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x441E, 0xA316, 0x8C88, 0x4C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x8316, 0x6C88, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x6416, + 0x6C90, 0xEC78, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x6C90, 0xEC80, 0xCB61, 0x0A53, 0x083C, 0xE62C, 0xA525, 0x241E, + 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x8525, 0x041E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE41D, + 0x4B98, 0xAC80, 0x8C69, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC51D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xC525, + 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x8525, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x6625, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0xA734, 0x462D, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x262D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x6834, 0x062D, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x6943, 0x483C, 0xE62C, 0x2AA0, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, + 0x2AA0, 0x4C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x2AA8, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, + 0x2AA8, 0x4B90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x0AA8, 0x4B98, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6734, + 0xEB61, 0x694B, 0x062D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, 0xCB69, 0x2A4B, 0xC734, 0xC51D, 0x6316, 0xC316, 0x020F, 0x420F, + 0xAC69, 0xEA52, 0x8734, 0xA525, 0x6416, 0xC316, 0x020F, 0x220F, 0x6C71, 0xAA52, 0x483C, 0x6525, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x4C71, 0x6B5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xE316, 0x020F, 0x0C79, 0x2B62, 0xA943, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, + 0xEC78, 0xEB61, 0x6943, 0xC734, 0xA525, 0x441E, 0xA316, 0xE20E, 0xCC80, 0xAC69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE316, + 0xCC80, 0x8C69, 0xEA52, 0x283C, 0x462D, 0xE51D, 0x6416, 0xC316, 0xAC80, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x6316, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x6C90, 0xEC78, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xC525, 0x441E, + 0x6C90, 0xEC80, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xA525, 0x241E, 0x6C90, 0xCC80, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6525, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x4B90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xC525, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, 0x4B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xE72C, + 0x2BA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x2AA0, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x2AA8, 0x4B90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x6734, + 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, + 0xEB61, 0x494B, 0xE72C, 0xE51D, 0x8316, 0xC316, 0x020F, 0x220F, 0xAC69, 0x0A4B, 0xA734, 0xA525, 0x6416, 0xC316, 0x020F, 0x220F, + 0x8C69, 0xCA52, 0x6734, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x4C71, 0x8B5A, 0x283C, 0x4625, 0x241E, 0x8316, 0xE316, 0x020F, + 0x2C79, 0x4B5A, 0xE843, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x0C79, 0x0B62, 0x8943, 0xC72C, 0xC525, 0x441E, 0xA316, 0xE20E, + 0xEC78, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE316, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, + 0xAC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xAC88, 0x4C71, 0x8A5A, 0xC843, 0xE72C, 0xA525, 0x241E, 0x8316, + 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6316, 0x8C88, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x462D, 0xE51D, 0x441E, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6C90, 0xEC80, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0x241E, + 0x6C90, 0xCC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6525, 0x041E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xE51D, + 0x4C90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2AA0, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, + 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x0AA8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x283C, + 0xCB69, 0x2A4B, 0xA734, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, 0xAC69, 0xEA52, 0x8734, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x6C71, 0xAA52, 0x483C, 0x6625, 0x241E, 0xA316, 0xE216, 0x020F, 0x4C71, 0x6B5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, + 0x2C79, 0x2B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xA316, 0xE20E, 0x0C79, 0xEB61, 0x6943, 0xA734, 0xA525, 0x241E, 0xA316, 0xE216, + 0xEC80, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0xCC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, + 0xAC80, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC88, 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, + 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x6416, 0x8C88, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x441E, + 0x6C90, 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0xE62C, 0xA525, 0x241E, 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6525, 0x041E, + 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x4C90, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xC525, + 0x4B90, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, + 0x2BA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, + 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, + 0x0AA8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB61, 0x8A5A, 0x494B, 0xE83B, + 0xCC69, 0x0A4B, 0x8734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x8C69, 0xCA52, 0x6834, 0x8525, 0x241E, 0xA316, 0xE316, 0x020F, + 0x6C71, 0x8A5A, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, 0x4C71, 0x4B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xC316, 0xE20E, + 0x0C79, 0x0B62, 0x8943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, 0xEC78, 0xEB61, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x4625, 0xE41D, 0x6416, 0xA316, 0xCC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xAC88, 0x4C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x241E, 0x8316, 0x8C88, 0x2C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x6416, + 0x8C88, 0x0C79, 0x2B62, 0x694B, 0x6734, 0x262D, 0xC51D, 0x441E, 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0x083C, 0xC72C, 0x8525, 0x041E, 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x4625, 0xE51D, + 0x4C90, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xAC80, 0x8C71, 0x6B5A, 0x8943, 0x6834, 0x062D, 0xA525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x2BA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2AA0, 0x4B90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, + 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0x2AA8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x0AA8, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC843, + 0xAC69, 0xEA52, 0x8734, 0x8525, 0x441E, 0xA316, 0xE316, 0x020F, 0x8C69, 0xAA52, 0x483C, 0x6625, 0x241E, 0x8316, 0xC316, 0x020F, + 0x6C71, 0x8B5A, 0x083C, 0x262D, 0x041E, 0x6316, 0xC316, 0xE20E, 0x2C71, 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE216, + 0x0C79, 0x0B62, 0x8943, 0xA734, 0xA525, 0x241E, 0x8316, 0xC316, 0xEC78, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x6316, 0xC316, + 0xCC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xAC80, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6416, 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xE51D, 0x441E, + 0x8C88, 0x0C79, 0x0B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6C90, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xCC80, 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, + 0x4C90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x4C90, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, + 0x4B98, 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, + 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, + 0x2BA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE843, 0x8734, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x6943, 0x083C, + 0x2AA8, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, + 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0xAC69, 0xCA52, 0x6834, 0x6525, 0x241E, 0x8316, 0xC316, 0x020F, 0x6C71, 0x8A5A, 0x283C, 0x462D, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x4C71, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xA316, 0xE216, 0x2C79, 0x2B62, 0xA943, 0xC72C, 0xA525, 0x441E, 0x8316, 0xC316, + 0x0C79, 0xEB61, 0x694B, 0xA734, 0x8525, 0x041E, 0x8316, 0xC316, 0xEC80, 0xAC69, 0x0A4B, 0x4834, 0x462D, 0xE51D, 0x6416, 0xA316, + 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, 0xAC80, 0x4C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6316, + 0xAC88, 0x2C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xA525, + 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0x4B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x083C, 0xC72C, 0x6625, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x083C, 0xC734, 0x2BA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0xA734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x4B98, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, + 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x8C69, 0xCA52, 0x483C, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, 0x6C71, 0x8B5A, 0x083C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, + 0x4C71, 0x4B5A, 0xC943, 0x062D, 0xC525, 0x441E, 0xA316, 0xE316, 0x2C79, 0x0B62, 0x8943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xEC80, 0xAC69, 0x0A53, 0x483C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xCC80, 0x8C71, 0xCA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC80, 0x4C71, 0x8B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6416, + 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xC51D, 0x441E, 0x8C88, 0x0C79, 0x0B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x6C88, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xE51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x4C90, 0xAC80, 0x8C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, + 0x4C90, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x6C90, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE843, 0x8734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4B90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0x2AA0, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, + 0x0AA8, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x8C69, 0xAA52, 0x283C, 0x462D, 0x041E, 0x6416, 0xA316, 0xE216, 0x6C71, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x441E, 0xA316, 0xE316, + 0x4C71, 0x4B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0x8316, 0xC316, 0x2C79, 0x0B62, 0x6943, 0xA734, 0x8525, 0x041E, 0x6316, 0xC316, + 0xEC78, 0xCB69, 0x2A4B, 0x6734, 0x4625, 0xE51D, 0x6416, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0x6C71, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6316, 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0x8C88, 0x2C79, 0x2B62, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, + 0x6C88, 0xEC78, 0xCB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x8525, + 0x4C90, 0xAC88, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4B98, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x2AA0, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, + 0x8C69, 0x8A5A, 0x083C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE316, 0x6C71, 0x6B5A, 0xE843, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x4C71, 0x2B62, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0xEB61, 0x694B, 0x8734, 0x6525, 0x041E, 0x6416, 0xA316, + 0xEC78, 0xCB69, 0x0A4B, 0x483C, 0x462D, 0xE51D, 0x441E, 0x8316, 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xCC80, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6416, 0xAC88, 0x2C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x8C88, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE41D, + 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xC51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x4B90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x8C71, 0x8B5A, 0x083C, 0x062D, 0xC51D, 0x441E, 0x8316, 0xC316, 0x4C71, 0x4B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C71, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, 0x0C79, 0xEB61, 0x494B, 0x6734, 0x6625, 0xE51D, 0x441E, 0xA316, + 0xEC78, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x041E, 0x6316, + 0xAC80, 0x4C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC88, 0x2C79, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x8C88, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0xA525, + 0x6C90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4C90, 0xAC88, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4B90, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4B98, 0x6C88, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x083C, 0xC734, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0xEA52, 0xA943, 0x4834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, + 0x0AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x0AA8, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x6C71, 0x6B5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x4C71, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x6316, 0xA316, + 0x2C71, 0x0B62, 0x6943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, 0x0C79, 0xEB61, 0x2A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0x8316, + 0xEC78, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0x8C71, 0xAA52, 0xE843, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, 0xAC88, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xA525, 0x241E, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE72C, 0x8525, 0xE41D, 0x8C88, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x6625, 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4B90, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE62C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x6C88, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x6C71, 0x6B5A, 0xC843, 0xE62C, 0xA525, 0x241E, 0x8316, 0xA316, 0x4C71, 0x2B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE41D, 0x441E, 0xA316, 0x0C79, 0xCB69, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x8316, + 0xEC78, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6316, 0xCC80, 0x6C71, 0xAA52, 0xC943, 0xC734, 0x6525, 0xE41D, 0x441E, + 0xAC80, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6525, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x083C, 0xA734, 0x4B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA8, 0x2B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, + 0x6C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, 0x4C71, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x0B62, 0x494B, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, 0x0C79, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, + 0xEC80, 0x8C69, 0xCA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, 0xCC80, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC80, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x241E, 0xAC88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x8C88, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x8734, + 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC843, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x294B, 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x6C71, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x4C71, 0x2B62, 0x6943, 0x8734, 0x6625, 0xE41D, 0x441E, 0x8316, + 0x2C79, 0xEB61, 0x494B, 0x6734, 0x462D, 0xC51D, 0x441E, 0x8316, 0x0C79, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xEC80, 0x8C69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x441E, 0xCC80, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xAC80, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0xAC88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x8C88, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x6C90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4C90, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xEA52, + 0x6C71, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x441E, 0x8316, 0x4C71, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C79, 0xEB61, 0x2A4B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6316, 0x0C79, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x6525, 0xE51D, 0x441E, 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, + 0xAC80, 0x2C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0xAC88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, + 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x8C88, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x062D, 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xCA52, 0x6943, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, + 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x0AA8, 0x2BA0, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, + 0x6C71, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x4C71, 0x0B62, 0x494B, 0x6734, 0x4625, 0xC51D, 0x241E, 0x8316, + 0x2C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, 0x0C79, 0xAC69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, + 0xEC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x241E, + 0xAC80, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC88, 0x0C79, 0xEB61, 0x0A53, 0xE83B, 0xC734, 0x4625, 0xC525, + 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xAC80, 0x6C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x6C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2B98, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x294B, 0xE843, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2AA0, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x6C71, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x4C71, 0x0B62, 0x494B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x2C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0x0C79, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0xE41D, 0x441E, + 0xEC80, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xCC80, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC80, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x8C88, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x294B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2AA0, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x6C71, 0x2B62, 0x6943, 0x8734, 0x4625, 0xE51D, 0x241E, 0x6316, 0x4C71, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6416, + 0x2C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x441E, 0x0C79, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, + 0xEC80, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x062D, 0xA525, 0x041E, + 0xAC80, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x462D, 0xA525, + 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4B98, 0x6C90, 0xEC80, 0x8C71, 0x2B5A, 0xEA52, 0xA943, 0x483C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE843, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x0AA8, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0xAA52, + 0x6C71, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x041E, 0x6416, + 0x2C79, 0xCB69, 0x0A53, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, 0x0C79, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x241E, + 0xEC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, + 0xAC80, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0xAC88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x8525, 0x8C88, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8A52, 0x694B, 0x083C, 0xA734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A53, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x2B62, 0xAA52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x6C71, 0x2B62, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x2C79, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, 0x0C79, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, + 0xEC78, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE51D, + 0xAC80, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0xAC88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0x8525, + 0x8C88, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6625, 0x8C88, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x4B90, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE843, 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A52, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, + 0x6C71, 0x2B62, 0x494B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0x2C79, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x0C79, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xEC78, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x4C71, 0x2B62, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0xAC80, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xC525, 0xAC88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0xCC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x6C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x6C88, 0xEC80, 0x8C71, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0xEB61, 0x0A4B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x441E, + 0x2C79, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6625, 0xE51D, 0x241E, 0x0C79, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, + 0xEC78, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0x8525, 0xE41D, 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xC51D, + 0xAC80, 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC80, 0x8C69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, 0x8C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, 0x6C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x6C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x4834, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA8, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x2AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x2B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x4C71, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, + 0x2C71, 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xC525, 0x241E, 0x0C79, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC78, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE51D, 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC525, + 0xCC80, 0x2C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, 0xAC88, 0x0C79, 0xCC69, 0xAA52, 0x8943, 0x4834, 0xE62C, 0x6525, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x8C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C88, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x6C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC843, + 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x6943, 0x2B98, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA8, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x6C71, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, 0x4C71, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x6625, 0xE51D, 0x241E, + 0x2C71, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x4625, 0xC525, 0x041E, 0x0C79, 0x8C69, 0x8A5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC78, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xCC80, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, 0xAC88, 0x0C79, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x8C88, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xE83B, 0x8734, 0x062D, + 0x6C88, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2B98, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0xEB61, 0x8B5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xCB69, 0x4B5A, + 0x6C71, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x4C71, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6625, 0xC51D, 0x241E, + 0x2C71, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x041E, 0x0C79, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0x8525, 0xE41D, + 0xEC78, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xCC80, 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0xCC80, 0x2C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x062D, 0x8525, 0xAC88, 0x0C79, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x6C88, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xC943, 0x4834, + 0x4C90, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B90, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x6B5A, 0x0A53, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2B98, 0x4B90, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x294B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2BA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA8, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x4C71, 0xCB69, 0x4B5A, + 0x0A4B, 0xC734, 0x241E, 0xC316, 0x420F, 0x810F, 0xC007, 0xAA52, 0xCA52, 0x8734, 0xE41D, 0xC316, 0x220F, 0x610F, 0xC007, 0xAA52, + 0x8A5A, 0x483C, 0xC525, 0xA316, 0x220F, 0x610F, 0xC007, 0xAA52, 0x4B5A, 0xE83B, 0x8525, 0x8316, 0x020F, 0x610F, 0xA107, 0xAA52, + 0x0B62, 0xA943, 0x4625, 0x441E, 0xE20E, 0x420F, 0xA107, 0xAA52, 0xCB69, 0x694B, 0x062D, 0x241E, 0xC316, 0x420F, 0xA107, 0xAA52, + 0xAC69, 0x0A4B, 0xC734, 0xE41D, 0xA316, 0x220F, 0xA107, 0xAA52, 0x6C71, 0xCA52, 0x8734, 0xC525, 0x8316, 0x020F, 0x8107, 0xAA52, + 0x4C71, 0x8A5A, 0x483C, 0x8525, 0x6416, 0xE20E, 0x810F, 0xAA52, 0x2C79, 0x4B5A, 0x083C, 0x4625, 0x441E, 0xE316, 0x610F, 0xAA52, + 0x0C79, 0x2B62, 0xC943, 0x262D, 0x041E, 0xC316, 0x410F, 0xAA52, 0xEC78, 0xEB61, 0x8943, 0xE72C, 0xE51D, 0xA316, 0x420F, 0xAA52, + 0xCC80, 0xCB69, 0x494B, 0xA734, 0xC525, 0x8316, 0x220F, 0xAA52, 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x6416, 0x020F, 0xAA52, + 0xAC80, 0x8C69, 0xEA52, 0x483C, 0x6625, 0x441E, 0xE20E, 0xAA52, 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x241E, 0xE316, 0xAA52, + 0x8C88, 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0x041E, 0xC316, 0xAA52, 0x8C88, 0x2C79, 0x6B5A, 0xC943, 0xE72C, 0xC51D, 0xA316, 0xAA52, + 0x6C90, 0x0C79, 0x4B5A, 0x8943, 0xC734, 0xA525, 0x8316, 0xAA52, 0x6C90, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x8525, 0x6416, 0xAA52, + 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6625, 0x441E, 0x410F, 0x4C90, 0xEC80, 0xEB61, 0x0A4B, 0x483C, 0x462D, 0x241E, 0x220F, + 0x4C90, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x262D, 0x041E, 0xE20E, 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE62C, 0xC51D, 0xC316, + 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0xA525, 0xA316, 0x4B98, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x6316, + 0x2B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x441E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0x241E, + 0x2BA0, 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x262D, 0x041E, 0x2BA0, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xE51D, + 0x2BA0, 0x6C90, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xC525, 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xC734, 0xA525, + 0xEA52, 0x8734, 0x041E, 0xC316, 0x220F, 0x610F, 0x8107, 0xAA52, 0xAA52, 0x4834, 0xC51D, 0xA316, 0x020F, 0x610F, 0x8107, 0xAA52, + 0x6B5A, 0x283C, 0xA525, 0x8316, 0x020F, 0x410F, 0x8107, 0xAA52, 0x2B62, 0xC943, 0x6625, 0x6416, 0xE20E, 0x420F, 0x810F, 0xAA52, + 0xEB61, 0x8943, 0x262D, 0x241E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xCC69, 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x220F, 0x610F, 0xAA52, + 0x8C69, 0xEA52, 0xA734, 0xC51D, 0x8316, 0x020F, 0x610F, 0xAA52, 0x4C71, 0xAA52, 0x4834, 0x8525, 0x6416, 0xE20E, 0x420F, 0xAA52, + 0x2C71, 0x6B5A, 0x083C, 0x6625, 0x441E, 0xC316, 0x420F, 0xAA52, 0x0C79, 0x2B5A, 0xC843, 0x262D, 0x041E, 0xA316, 0x220F, 0xAA52, + 0xEC78, 0x0B62, 0xA943, 0xE62C, 0xE51D, 0x8316, 0x020F, 0xAA52, 0xEC80, 0xEB61, 0x694B, 0xC734, 0xC525, 0x8316, 0x020F, 0xAA52, + 0xCC80, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x441E, 0xE216, 0xA107, 0xAC80, 0x8C69, 0x0A53, 0x483C, 0x6625, 0x241E, 0xC316, 0x8107, + 0xAC88, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0xA316, 0x610F, 0x8C88, 0x4C71, 0xAA52, 0xE83B, 0x062D, 0xE41D, 0xA316, 0x410F, + 0x8C88, 0x2C71, 0x6B5A, 0xC943, 0xE72C, 0xC525, 0x8316, 0x220F, 0x6C88, 0x2C79, 0x4B5A, 0x8943, 0xC734, 0xA525, 0x6416, 0x220F, + 0x6C90, 0x0C79, 0x2B62, 0x6943, 0x8734, 0x8525, 0x441E, 0x020F, 0x6C90, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6625, 0x241E, 0xE216, + 0x6C90, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0x041E, 0xC316, 0x4C90, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x062D, 0xE51D, 0xA316, + 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE62C, 0xC525, 0x8316, 0x4B98, 0xAC80, 0xAC69, 0xAA52, 0xC843, 0xC72C, 0xA525, 0x6316, + 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x441E, 0x2B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x241E, + 0x2B98, 0x8C88, 0x6C71, 0x4B5A, 0x694B, 0x6834, 0x462D, 0x041E, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x262D, 0xE51D, + 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x2BA0, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xC734, 0x8525, 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0xA734, 0x6625, + 0xCA52, 0x6734, 0xE51D, 0xA316, 0x020F, 0x410F, 0x810F, 0xA107, 0x8B5A, 0x283C, 0xA525, 0x8316, 0x020F, 0x420F, 0x810F, 0xA107, + 0x4B5A, 0xE83B, 0x8525, 0x6316, 0xE20E, 0x420F, 0x610F, 0xA107, 0x0B62, 0xA943, 0x462D, 0x441E, 0xC316, 0x220F, 0x610F, 0xA107, + 0xCB61, 0x694B, 0x062D, 0x041E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAC69, 0x0A4B, 0xC734, 0xE51D, 0xA316, 0x020F, 0x410F, 0x8107, + 0x6C71, 0xCA52, 0x8734, 0xA525, 0x6316, 0xE20E, 0x420F, 0x8107, 0x4C71, 0x8B5A, 0x283C, 0x6625, 0x441E, 0xC316, 0x220F, 0x810F, + 0x2C79, 0x4B5A, 0xE83B, 0x462D, 0x241E, 0xA316, 0x220F, 0x610F, 0x0C79, 0x2B62, 0xA943, 0x062D, 0xE41D, 0x8316, 0x020F, 0x610F, + 0xEC78, 0xEB61, 0x6943, 0xC734, 0xC525, 0x6316, 0xE20E, 0x610F, 0xCC80, 0xCB69, 0x494B, 0x8734, 0xA525, 0x441E, 0xE316, 0x420F, + 0xCC80, 0xAC69, 0x0A4B, 0x6834, 0x6625, 0x241E, 0xC316, 0x420F, 0xAC80, 0x8C71, 0xEA52, 0x283C, 0x462D, 0x041E, 0xA316, 0x220F, + 0x8C88, 0x6C71, 0xAA52, 0x083C, 0x262D, 0xE51D, 0x8316, 0x020F, 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE62C, 0xC525, 0x6316, 0x020F, + 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC734, 0xA525, 0x441E, 0xE216, 0x6C90, 0x0C79, 0x2B5A, 0x6943, 0x8734, 0x8525, 0x241E, 0xC316, + 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x6625, 0x041E, 0xA316, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xE41D, 0xA316, + 0x4C90, 0xEC80, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xC51D, 0x8316, 0x4C90, 0xCC80, 0xCC69, 0xEA52, 0x083C, 0xE72C, 0xA525, 0x6416, + 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x8525, 0x441E, 0x4B98, 0xAC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x6525, 0x241E, + 0x4B98, 0xAC88, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0x2B98, 0x8C88, 0x6C71, 0x6B5A, 0x694B, 0x6834, 0x262D, 0xE41D, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xE51D, 0x2BA0, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0xC525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0xA525, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x8525, + 0x2AA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x6625, 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x462D, + 0xAA52, 0x483C, 0xC525, 0x8316, 0x020F, 0x420F, 0x610F, 0x8107, 0x6B5A, 0x083C, 0x8525, 0x6316, 0xE20E, 0x220F, 0x610F, 0x8107, + 0x2B62, 0xC943, 0x6625, 0x441E, 0xC316, 0x220F, 0x610F, 0x810F, 0xEB61, 0x6943, 0x262D, 0x241E, 0xC316, 0x020F, 0x410F, 0x810F, + 0xCC69, 0x2A4B, 0xE72C, 0xE51D, 0xA316, 0x020F, 0x420F, 0x610F, 0x8C69, 0xEA52, 0x8734, 0xC525, 0x6316, 0xE216, 0x220F, 0x610F, + 0x6C71, 0xAA52, 0x483C, 0x8525, 0x441E, 0xC316, 0x220F, 0x610F, 0x2C79, 0x6B5A, 0x083C, 0x462D, 0x241E, 0xA316, 0x020F, 0x410F, + 0x0C79, 0x2B62, 0xC943, 0x062D, 0xE41D, 0x8316, 0xE20E, 0x420F, 0xEC78, 0xEB61, 0x8943, 0xC72C, 0xC525, 0x6316, 0xE316, 0x220F, + 0xCC80, 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xC316, 0x220F, 0xCC80, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x241E, 0xA316, 0x020F, + 0xAC80, 0x8C71, 0xEA52, 0x283C, 0x462D, 0x041E, 0x8316, 0x020F, 0xAC88, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xE51D, 0x6316, 0xE216, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xC316, 0x8C88, 0x2C79, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x441E, 0xC316, + 0x6C88, 0x0C79, 0x2B5A, 0x6943, 0x8734, 0x6625, 0x041E, 0xA316, 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0x041E, 0x8316, + 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x6316, 0x6C90, 0xEC80, 0xCB61, 0x0A53, 0x283C, 0x062D, 0xC525, 0x6416, + 0x4C90, 0xCC80, 0xCC69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x441E, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x241E, + 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x6625, 0x041E, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x462D, 0xE41D, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x4834, 0x262D, 0xC51D, 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xA525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0xA525, 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, + 0x2BA0, 0x6C88, 0x2C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x6625, 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x462D, + 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x6734, 0x262D, 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0x062D, + 0x6B5A, 0x083C, 0x8525, 0x6316, 0xE216, 0x220F, 0x610F, 0x810F, 0x4B5A, 0xC843, 0x6625, 0x441E, 0xC316, 0x220F, 0x410F, 0x610F, + 0x0B62, 0xA943, 0x262D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, 0xCB69, 0x494B, 0xE62C, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, + 0xAC69, 0x0A4B, 0xA734, 0xC525, 0x8316, 0xE216, 0x220F, 0x610F, 0x6C71, 0xCA52, 0x6734, 0x8525, 0x441E, 0xC316, 0x220F, 0x410F, + 0x4C71, 0x8B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0x020F, 0x420F, 0x2C79, 0x4B5A, 0xC843, 0x062D, 0x041E, 0x8316, 0xE20E, 0x220F, + 0x0C79, 0x0B62, 0x8943, 0xE72C, 0xC525, 0x6416, 0xC316, 0x220F, 0xEC80, 0xEB61, 0x494B, 0xA734, 0xA525, 0x441E, 0xC316, 0x020F, + 0xCC80, 0xAC69, 0x2A4B, 0x6734, 0x6525, 0x241E, 0xA316, 0x020F, 0xAC80, 0x8C69, 0xEA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE216, + 0xAC88, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x6416, 0xC316, 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xC316, + 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xA316, 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6625, 0x041E, 0x8316, + 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x462D, 0xE51D, 0x6316, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x283C, 0x262D, 0xC525, 0x6416, + 0x6C90, 0xEC80, 0xCB61, 0x0A53, 0x083C, 0xE62C, 0xA525, 0x441E, 0x4C90, 0xCC80, 0xCB69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x241E, + 0x4B90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0x041E, 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x4625, 0xE51D, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC51D, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xC525, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x8525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, 0x2BA0, 0x6C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x4625, + 0x2BA0, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x262D, 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x6834, 0x062D, + 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0x062D, 0x2AA0, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x494B, 0x283C, 0xE72C, + 0x4B5A, 0xE83B, 0x6525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x2B62, 0xA943, 0x462D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, + 0xEB61, 0x6943, 0x062D, 0x041E, 0xA316, 0x020F, 0x220F, 0x610F, 0xAC69, 0x2A4B, 0xC734, 0xE51D, 0x8316, 0xE216, 0x220F, 0x410F, + 0x8C69, 0xEA52, 0x8734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, 0x4C71, 0xAA52, 0x483C, 0x6625, 0x241E, 0xA316, 0x020F, 0x420F, + 0x2C71, 0x6B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xE20E, 0x220F, 0x0C79, 0x2B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x020F, + 0xEC78, 0xEB61, 0x694B, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, 0xCC80, 0xCC69, 0x2A4B, 0x6734, 0x6525, 0x241E, 0x8316, 0xE20E, + 0xCC80, 0x8C69, 0xEA52, 0x483C, 0x462D, 0x041E, 0x8316, 0xE316, 0xAC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC51D, 0x6416, 0xC316, + 0x8C88, 0x4C71, 0x8A5A, 0xC843, 0xE72C, 0xA525, 0x441E, 0xA316, 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xA734, 0x8525, 0x241E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6625, 0x041E, 0x8316, 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x462D, 0xE51D, 0x6416, + 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0x6C90, 0xEC80, 0xCB61, 0xEA52, 0x083C, 0xE72C, 0xA525, 0x241E, + 0x4C90, 0xCC80, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x8525, 0x041E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE41D, + 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xC525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B5A, 0x294B, 0x283C, 0xE72C, 0x8525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0xA734, 0x4625, + 0x2BA0, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xE72C, + 0x2AA0, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x2AA8, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, + 0x2B5A, 0xC943, 0x4625, 0x241E, 0xA316, 0x020F, 0x220F, 0x610F, 0x0B62, 0x8943, 0x062D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x410F, + 0xCB69, 0x494B, 0xE72C, 0xE51D, 0x8316, 0xE216, 0x220F, 0x420F, 0xAC69, 0x0A53, 0xA734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, + 0x6C71, 0xAA52, 0x4834, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, 0x4C71, 0x6B5A, 0x083C, 0x462D, 0x041E, 0x8316, 0xE216, 0x220F, + 0x2C79, 0x4B5A, 0xC943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0xEC78, 0x0B62, 0x8943, 0xC734, 0xA525, 0x441E, 0xA316, 0x020F, + 0xEC80, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE216, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, + 0xAC80, 0x8C71, 0xCA52, 0x083C, 0x262D, 0xC51D, 0x6416, 0xC316, 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x441E, 0xA316, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x8316, 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6625, 0xE41D, 0x6316, + 0x6C88, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC51D, 0x441E, 0x6C90, 0xEC78, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x441E, + 0x6C90, 0xEC80, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x241E, 0x4C90, 0xCC80, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xC525, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6525, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x462D, 0x2BA0, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x2BA0, 0x6C90, 0x0C79, 0xCC69, 0xAA52, 0x6943, 0x483C, 0xE62C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2AA0, 0x4C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x2AA8, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, + 0x0B62, 0x8943, 0x262D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x420F, 0xEB61, 0x494B, 0xE62C, 0xE51D, 0x8316, 0xE316, 0x020F, 0x420F, + 0xCC69, 0x2A4B, 0xC734, 0xC525, 0x6316, 0xC316, 0x020F, 0x420F, 0x8C69, 0xCA52, 0x6734, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, + 0x4C71, 0x8A5A, 0x283C, 0x4625, 0x241E, 0x8316, 0xE216, 0x220F, 0x2C71, 0x4B5A, 0xE83B, 0x262D, 0xE41D, 0x6316, 0xC316, 0x020F, + 0x0C79, 0x0B62, 0xA943, 0xE72C, 0xC525, 0x441E, 0xA316, 0x020F, 0xEC78, 0xEB61, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE216, + 0xCC80, 0xAC69, 0x0A4B, 0x6834, 0x4625, 0x041E, 0x6316, 0xC316, 0xAC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0xA316, 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x6416, 0x6C88, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x441E, + 0x6C90, 0xEC78, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0xEC80, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xCC80, 0xCC69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xE51D, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC51D, + 0x4B90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xC734, + 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, 0x2AA0, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, + 0x2AA8, 0x4C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A53, 0xC943, 0x6734, 0x2AA8, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, + 0x0B62, 0x6943, 0x062D, 0xE41D, 0x8316, 0xE316, 0x020F, 0x420F, 0xCB69, 0x294B, 0xC734, 0xC525, 0x6316, 0xC316, 0x020F, 0x220F, + 0xAC69, 0x0A53, 0x8734, 0xA525, 0x441E, 0xC316, 0x020F, 0x220F, 0x6C71, 0xAA52, 0x483C, 0x6625, 0x241E, 0xA316, 0xE216, 0x220F, + 0x4C71, 0x6B5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, 0x2C79, 0x2B5A, 0xC943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x020F, + 0x0C79, 0x0B62, 0x8943, 0xA734, 0xA525, 0x241E, 0xA316, 0xE216, 0xEC80, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, + 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xAC80, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xA525, 0x441E, 0xA316, + 0xAC88, 0x4C71, 0x8B5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x8316, 0x8C88, 0x2C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x6416, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x262D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xCC80, 0xCB69, 0xCA52, 0xE83B, 0xA734, 0x6625, 0xE51D, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x4C90, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A53, 0xE843, 0x8734, 0x462D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2AA0, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, + 0x2AA8, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0xEB61, 0x494B, 0xE72C, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xCC69, 0x0A4B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x8C69, 0xEA52, 0x6734, 0x8525, 0x441E, 0xA316, 0xE216, 0x220F, 0x6C71, 0xAA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x4C71, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, 0x0C79, 0x2B62, 0xA943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, + 0xEC78, 0xEB61, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x462D, 0xE51D, 0x6416, 0xA316, + 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xAC88, 0x6C71, 0xAA52, 0xC843, 0xE72C, 0x8525, 0x241E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x6416, 0x8C88, 0x2C79, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xC51D, 0x441E, + 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C90, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x4C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x4B90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0x0A53, 0xC843, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x4834, 0x062D, 0x2B98, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x2AA0, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, + 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0x0AA8, 0x4B98, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, + 0xCB61, 0x294B, 0xC734, 0xC525, 0x6416, 0xA316, 0xE20E, 0x220F, 0xAC69, 0x0A53, 0x8734, 0x8525, 0x441E, 0xA316, 0xE216, 0x020F, + 0x8C69, 0xCA52, 0x4834, 0x6625, 0x241E, 0x8316, 0xE316, 0x020F, 0x4C71, 0x8B5A, 0x083C, 0x262D, 0x041E, 0x6316, 0xC316, 0x020F, + 0x2C79, 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE20E, 0x0C79, 0x0B62, 0x8943, 0xA734, 0xA525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0xCB69, 0x294B, 0x6734, 0x6625, 0x041E, 0x6316, 0xC316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xAC80, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC88, 0x4C71, 0x8B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, + 0x8C88, 0x2C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x241E, + 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x4C90, 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x6734, 0x262D, 0xA525, + 0x4C90, 0xAC80, 0x8C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x2B98, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xC734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4B90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x6943, 0x083C, + 0x2AA8, 0x4B98, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0xCB69, 0x2A4B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, 0xAC69, 0xEA52, 0x6734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, + 0x6C71, 0xAA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, 0x4C71, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xA316, 0xE20E, + 0x2C79, 0x2B62, 0xA943, 0xE72C, 0xA525, 0x441E, 0xA316, 0xE316, 0x0C79, 0xEB61, 0x694B, 0x8734, 0x8525, 0x041E, 0x8316, 0xC316, + 0xEC80, 0xCB69, 0x2A4B, 0x4834, 0x462D, 0xE51D, 0x6416, 0xA316, 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, + 0xAC80, 0x6C71, 0xAA52, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6316, 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0x8C88, 0x2C79, 0x2B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6525, 0xE41D, 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x4B90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xA734, 0x4625, + 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, 0x2B98, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, + 0x2B98, 0x6C90, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0xA734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A53, 0xA943, 0x6834, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA8, 0x4B98, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, 0x0AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0xCC69, 0x0A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, 0x8C69, 0xCA52, 0x483C, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, + 0x6C71, 0x8A5A, 0x083C, 0x262D, 0xE41D, 0x6416, 0xA316, 0xE20E, 0x4C71, 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE316, + 0x0C79, 0x0B62, 0x8943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, 0xEC78, 0xEB61, 0x494B, 0x6734, 0x6625, 0x041E, 0x6416, 0xA316, + 0xCC80, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xCC80, 0x8C71, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x4C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE41D, 0x6416, 0x8C88, 0x2C71, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x0C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C88, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6525, + 0x4B98, 0xAC88, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0x4B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE62C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2B98, 0x6C90, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A53, 0xA943, 0x6834, 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2AA0, 0x4B98, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, + 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, + 0xAC69, 0xEA52, 0x6734, 0x6525, 0x241E, 0x8316, 0xC316, 0xE20E, 0x8C69, 0xAA52, 0x283C, 0x462D, 0x041E, 0x6316, 0xA316, 0xE20E, + 0x6C71, 0x8B5A, 0x083C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xE316, 0x2C71, 0x4B5A, 0xA943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x6943, 0xA734, 0x8525, 0x041E, 0x6316, 0xC316, 0xEC78, 0xCB69, 0x2A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xC525, 0x241E, 0x8316, 0xAC80, 0x6C71, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x4625, 0xE51D, 0x441E, 0x8C88, 0x2C79, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x6C88, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0xA525, + 0x4C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, + 0x2B98, 0x6C88, 0x0C79, 0xAC69, 0x8A5A, 0x694B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, 0x2BA0, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xA943, 0x6834, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4B90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0xAC69, 0xCA52, 0x4834, 0x6625, 0x041E, 0x6316, 0xC316, 0xE216, 0x8C71, 0xAA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE316, + 0x4C71, 0x6B5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0xA316, 0xC316, 0x2C79, 0x2B62, 0xA943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xEC78, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, + 0xCC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xAC80, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x6625, 0xE41D, 0x441E, + 0xAC88, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x6C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x4C90, 0xAC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4C90, 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6834, 0x062D, + 0x4B98, 0x8C88, 0x0C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0xA734, 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x4C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x0AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, + 0xAC69, 0xCA52, 0x483C, 0x462D, 0x041E, 0x6416, 0xA316, 0xE316, 0x6C71, 0x8A5A, 0x083C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xC316, + 0x4C71, 0x6B5A, 0xC943, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, + 0x0C79, 0xEB61, 0x494B, 0x6734, 0x4625, 0xE51D, 0x441E, 0xA316, 0xEC80, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0xAC80, 0x4C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6525, + 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4B90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2AA0, 0x4B98, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A53, 0xA943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x8C69, 0xAA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xC316, 0x6C71, 0x8B5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x4C71, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C79, 0x0B62, 0x6943, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, + 0x0C79, 0xCB69, 0x2A4B, 0x4834, 0x462D, 0xC51D, 0x441E, 0x8316, 0xEC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0x6C71, 0xAA52, 0xC843, 0xC734, 0x8525, 0x041E, 0x441E, 0xAC80, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0xEC78, 0xCB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x8525, 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x6625, + 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC843, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A53, 0xA943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x0AA8, 0x2B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x8C69, 0xAA52, 0x083C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, 0x6C71, 0x6B5A, 0xC843, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x4C71, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, 0xA316, 0x2C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xEC80, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x6416, + 0xCC80, 0x6C71, 0x8A5A, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0x041E, 0x8C88, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xA734, 0x462D, + 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x294B, 0xE843, 0x2BA0, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0x0AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x8C69, 0x8A5A, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, 0x6C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, + 0x4C71, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C79, 0xEB61, 0x494B, 0x6734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0xEC78, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xEC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, 0xAC88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, + 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE41D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, + 0x6C88, 0xEC80, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x4C90, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4B98, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xCA52, 0x6943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x0AA8, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x8C69, 0x8B5A, 0xE83B, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x6C71, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x4C71, 0x2B62, 0x8943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x0C79, 0xEB61, 0x294B, 0x6834, 0x462D, 0xC525, 0x241E, 0x8316, + 0xEC78, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xCC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x6525, 0xE41D, 0x441E, + 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC88, 0x2C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0xEC78, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x462D, 0xC525, + 0x6C88, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6525, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2AA8, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x8C69, 0x8B5A, 0xC843, 0xE72C, 0xA525, 0x241E, 0x6416, 0xA316, 0x6C71, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x441E, 0x8316, + 0x4C71, 0x2B62, 0x694B, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x0C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, + 0xEC78, 0xAC69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x6416, 0xCC80, 0x8C71, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x241E, 0xAC88, 0x2C79, 0x2B62, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C88, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4C90, 0xAC88, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, + 0x4C90, 0x8C88, 0x2C71, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x2C79, 0xCB61, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC843, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A53, 0xA943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2AA8, 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x8C71, 0x6B5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6416, 0xA316, 0x6C71, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, + 0x4C71, 0x0B62, 0x694B, 0x6734, 0x462D, 0xC51D, 0x241E, 0x8316, 0x0C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6416, + 0xEC78, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0xE41D, 0x441E, 0xCC80, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xCC80, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x8C88, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C88, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x6C90, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x4B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x0AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x8C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x441E, 0x8316, 0x4C71, 0x2B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C71, 0x0B62, 0x494B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, 0x0C79, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC78, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, 0xCC80, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, + 0xCC80, 0x4C71, 0x4B5A, 0x694B, 0x4834, 0x062D, 0xA525, 0x041E, 0xAC88, 0x2C79, 0x0B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x462D, 0xA525, 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C88, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x8C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0xE41D, 0x441E, 0x8316, 0x4C71, 0x2B62, 0x6943, 0x8734, 0x4625, 0xC51D, 0x241E, 0x6316, + 0x2C71, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6416, 0x0C79, 0xCB69, 0x0A53, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, + 0xEC78, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x241E, 0xCC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x6C88, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x4625, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE843, 0x2B98, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x8C71, 0x4B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x4C71, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x2C71, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x041E, 0x6416, 0x0C79, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, + 0xEC78, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0xAC88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x6C88, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x8C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xC51D, 0x241E, 0x6316, 0x4C71, 0x2B62, 0x494B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6416, + 0x2C71, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x441E, 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, + 0xEC78, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x062D, 0xA525, 0x041E, + 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x6C88, 0xCC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x6C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, + 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x6B5A, 0x0A53, 0xA943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x2B62, 0xAA52, + 0x8C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x2B62, 0x494B, 0x4834, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, 0x0C79, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, + 0xEC78, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x4834, 0x062D, 0x8525, 0xE41D, + 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xC72C, 0x6625, 0xC51D, 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, 0x8C88, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, + 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, + 0x4B98, 0x6C88, 0xEC80, 0x8C71, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x294B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, + 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x8C71, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x6C71, 0x0B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0xEB61, 0x0A4B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x441E, 0x0C79, 0xAC69, 0xCA52, 0xE843, 0xC734, 0x6625, 0xC51D, 0x241E, + 0xEC78, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x462D, + 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0xE62C, + 0x6C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, + 0x8C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, 0x0C79, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, + 0xEC78, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xEC80, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x6525, 0xE51D, + 0xCC80, 0x2C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x462D, 0xC525, 0xAC88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0x8C88, 0xEC78, 0xAC69, 0x8A52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xE843, 0x8734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x6C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC843, 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x294B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA8, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, + 0x8C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0xE51D, 0x441E, + 0x4C71, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x241E, 0x0C79, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x041E, + 0xEC78, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x062D, 0x8525, 0xE41D, 0xEC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, + 0xCC80, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, 0xAC80, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x4625, 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x6C90, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2B98, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x8C69, 0x2B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, + 0x4C71, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0x2C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0x0C79, 0x8C69, 0x6B5A, 0x6943, 0x6834, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x4C71, 0x4B5A, 0x294B, 0x283C, 0xC72C, 0x6625, 0xC525, + 0xCC80, 0x2C71, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x262D, 0xA525, 0xAC80, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6834, 0x062D, 0x6525, + 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x4625, 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x4C90, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x8B5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2B98, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C71, 0xEB61, 0x6B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x8C69, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x241E, 0x6C71, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x241E, + 0x4C71, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x4625, 0xC525, 0x041E, 0x2C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0x0C79, 0x8C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xCC80, 0x2C71, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0x8525, 0xAC80, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0xE62C, 0x6625, + 0xAC88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x8C88, 0xEC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, 0x6C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x4C90, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2B98, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x2A4B, 0x062D, 0x441E, 0xE216, 0x420F, 0x810F, 0xAA52, 0xAA52, 0xEA52, 0xC734, 0x041E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xAA52, + 0xCA52, 0x8734, 0xE51D, 0xA316, 0x220F, 0x610F, 0xAA52, 0xAA52, 0x6B5A, 0x483C, 0xA525, 0x8316, 0x020F, 0x610F, 0xAA52, 0xAA52, + 0x2B62, 0xE83B, 0x6525, 0x6416, 0x020F, 0x610F, 0xE007, 0xAA52, 0xEB61, 0xA943, 0x462D, 0x441E, 0xE216, 0x420F, 0xC007, 0xAA52, + 0xCB69, 0x694B, 0xE62C, 0x041E, 0xC316, 0x220F, 0xA107, 0xAA52, 0x8C69, 0x0A4B, 0xA734, 0xC51D, 0xA316, 0x220F, 0xA107, 0xAA52, + 0x6C71, 0xCA52, 0x6734, 0xA525, 0x8316, 0x020F, 0x8107, 0xAA52, 0x4C71, 0x8A5A, 0x283C, 0x6525, 0x441E, 0xE20E, 0x810F, 0xAA52, + 0x2C79, 0x6B5A, 0xE83B, 0x462D, 0x241E, 0xC316, 0x610F, 0xAA52, 0x0C79, 0x2B62, 0xC943, 0x062D, 0x041E, 0xC316, 0x610F, 0xAA52, + 0xEC80, 0x0B62, 0x8943, 0xC72C, 0xE51D, 0x8316, 0x420F, 0xAA52, 0xCC80, 0xCB61, 0x494B, 0xA734, 0xA525, 0x8316, 0x220F, 0xAA52, + 0xCC80, 0xAC69, 0x2A4B, 0x6734, 0x8525, 0x6416, 0x020F, 0xAA52, 0xAC80, 0x8C69, 0xEA52, 0x483C, 0x6625, 0x241E, 0xE20E, 0xAA52, + 0x8C88, 0x6C71, 0xCA52, 0x083C, 0x262D, 0x041E, 0xC316, 0xAA52, 0x8C88, 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xE51D, 0xA316, 0xAA52, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xE72C, 0xC525, 0xA316, 0xAA52, 0x6C88, 0x2C79, 0x4B5A, 0x8943, 0xC734, 0xA525, 0x8316, 0xAA52, + 0x6C90, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x8525, 0x441E, 0xAA52, 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x6625, 0x241E, 0x610F, + 0x4C90, 0xEC78, 0xEB61, 0x0A4B, 0x483C, 0x262D, 0x041E, 0x220F, 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0x283C, 0x062D, 0xE41D, 0xE20E, + 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE62C, 0xC51D, 0xC316, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0xA525, 0x8316, + 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x6316, 0x2B98, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x441E, + 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x6834, 0x462D, 0x241E, 0x2BA0, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x262D, 0x041E, + 0x2BA0, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0x062D, 0xC51D, 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xE72C, 0xA525, + 0x0A4B, 0xC72C, 0x241E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, 0xCA52, 0xA734, 0xE41D, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0xAA52, 0x6834, 0xC525, 0xA316, 0x020F, 0x610F, 0x8107, 0xAA52, 0x4B5A, 0x083C, 0x8525, 0x6316, 0x020F, 0x420F, 0x8107, 0xAA52, + 0x0B62, 0xC943, 0x4625, 0x441E, 0xE216, 0x420F, 0x810F, 0xAA52, 0xEB61, 0x8943, 0x062D, 0x241E, 0xC316, 0x220F, 0x810F, 0xAA52, + 0xAC69, 0x2A4B, 0xC72C, 0xE51D, 0xA316, 0x020F, 0x610F, 0xAA52, 0x6C71, 0xEA52, 0x8734, 0xA525, 0x8316, 0x020F, 0x610F, 0xAA52, + 0x4C71, 0xAA52, 0x483C, 0x8525, 0x441E, 0xE216, 0x420F, 0xAA52, 0x2C79, 0x6B5A, 0x083C, 0x462D, 0x241E, 0xC316, 0x420F, 0xAA52, + 0x0C79, 0x4B5A, 0xC943, 0x062D, 0x041E, 0xA316, 0x220F, 0xAA52, 0xEC78, 0x0B62, 0x8943, 0xE72C, 0xE51D, 0x8316, 0x020F, 0xAA52, + 0xCC80, 0xEB61, 0x494B, 0xA734, 0xA525, 0x6416, 0x020F, 0xAA52, 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x8525, 0x441E, 0xE216, 0xAA52, + 0xAC80, 0xAC69, 0xEA52, 0x483C, 0x6625, 0x241E, 0xC316, 0xA107, 0xAC88, 0x8C71, 0xCA52, 0x283C, 0x262D, 0x041E, 0xA316, 0x810F, + 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xE51D, 0x8316, 0x610F, 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xC525, 0x6316, 0x420F, + 0x6C88, 0x2C71, 0x4B5A, 0x8943, 0xA734, 0xA525, 0x6416, 0x220F, 0x6C90, 0x2C79, 0x2B62, 0x694B, 0x8734, 0x8525, 0x441E, 0x020F, + 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x4625, 0x241E, 0xE316, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0x041E, 0xC316, + 0x4C90, 0xEC80, 0xCB61, 0x0A53, 0x283C, 0x062D, 0xE51D, 0xA316, 0x4B90, 0xCC80, 0xCB69, 0xCA52, 0xE83B, 0xE72C, 0xC525, 0x8316, + 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC843, 0xC734, 0xA525, 0x6416, 0x4B98, 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x6525, 0x441E, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0x241E, 0x2B98, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x6834, 0x262D, 0x041E, + 0x2B98, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xE51D, 0x2BA0, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE62C, 0xC525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC72C, 0xA525, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x8525, + 0xEA52, 0xA734, 0x041E, 0xC316, 0x220F, 0x610F, 0x810F, 0xC107, 0xAA52, 0x6734, 0xC51D, 0xA316, 0x020F, 0x410F, 0x810F, 0xA107, + 0x8B5A, 0x483C, 0xA525, 0x8316, 0x020F, 0x420F, 0x810F, 0xA107, 0x2B5A, 0xE83B, 0x6625, 0x6416, 0xE216, 0x220F, 0x610F, 0xA107, + 0x0B62, 0xA943, 0x262D, 0x241E, 0xC316, 0x220F, 0x610F, 0xA107, 0xCB69, 0x694B, 0xE62C, 0x041E, 0xA316, 0x020F, 0x610F, 0xA107, + 0x8C69, 0x0A4B, 0xA734, 0xC525, 0x8316, 0x020F, 0x420F, 0xA107, 0x6C71, 0xCA52, 0x6834, 0x8525, 0x6416, 0xE316, 0x420F, 0x8107, + 0x4C71, 0x8A5A, 0x283C, 0x6625, 0x241E, 0xC316, 0x220F, 0x810F, 0x0C79, 0x4B5A, 0xE83B, 0x262D, 0x041E, 0xA316, 0x020F, 0x610F, + 0x0C79, 0x2B62, 0xA943, 0xE62C, 0xE51D, 0x8316, 0x020F, 0x610F, 0xEC80, 0x0B62, 0x6943, 0xC734, 0xC525, 0x6416, 0xE216, 0x610F, + 0xCC80, 0xCB69, 0x294B, 0x8734, 0x8525, 0x441E, 0xC316, 0x420F, 0xAC80, 0xAC69, 0x0A4B, 0x483C, 0x6625, 0x241E, 0xA316, 0x220F, + 0xAC88, 0x8C69, 0xCA52, 0x283C, 0x262D, 0x041E, 0xA316, 0x220F, 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xE51D, 0x8316, 0x020F, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x6416, 0x020F, 0x8C88, 0x2C71, 0x6B5A, 0xA943, 0xA734, 0x8525, 0x441E, 0xE216, + 0x6C90, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6525, 0x241E, 0xC316, 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6734, 0x4625, 0x041E, 0xA316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x8316, 0x4C90, 0xEC78, 0xEB61, 0x0A53, 0x283C, 0x062D, 0xC525, 0x8316, + 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x6416, 0x4B98, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x8525, 0x441E, + 0x4B98, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x6625, 0x241E, 0x4B98, 0xAC80, 0x8C71, 0x8B5A, 0x8943, 0x8734, 0x4625, 0x041E, + 0x2B98, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x6834, 0x262D, 0xE51D, 0x2B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xC51D, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0xA525, 0x2BA0, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x8525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0xA734, 0x6525, 0x2BA0, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x6625, + 0xCA52, 0x8734, 0xE51D, 0xA316, 0x020F, 0x420F, 0x610F, 0x8107, 0x8B5A, 0x483C, 0xA525, 0x8316, 0xE20E, 0x420F, 0x610F, 0x8107, + 0x4B5A, 0x083C, 0x8525, 0x6416, 0xE216, 0x220F, 0x610F, 0x8107, 0x0B62, 0xC943, 0x462D, 0x241E, 0xC316, 0x220F, 0x410F, 0x810F, + 0xEB61, 0x6943, 0x062D, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, 0xAC69, 0x2A4B, 0xC734, 0xC51D, 0x8316, 0xE20E, 0x420F, 0x610F, + 0x6C71, 0xEA52, 0x8734, 0xA525, 0x6416, 0xE316, 0x220F, 0x610F, 0x4C71, 0xAA52, 0x283C, 0x6625, 0x241E, 0xC316, 0x020F, 0x610F, + 0x2C79, 0x6B5A, 0xE83B, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, 0x0C79, 0x2B62, 0xA943, 0xE62C, 0xE51D, 0x8316, 0xE216, 0x420F, + 0xEC78, 0x0B62, 0x6943, 0xC734, 0xA525, 0x6416, 0xC316, 0x220F, 0xCC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0xC316, 0x220F, + 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x6625, 0x041E, 0xA316, 0x020F, 0xAC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE41D, 0x8316, 0xE20E, + 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x6416, 0xE216, 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xC316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0x6C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6625, 0x041E, 0xA316, + 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x462D, 0xE41D, 0x8316, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x6316, + 0x6C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xA525, 0x441E, 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x241E, + 0x4B90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6525, 0x241E, 0x4B98, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x4625, 0x041E, + 0x4B98, 0xAC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x462D, 0xE51D, 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xC525, + 0x2B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x8525, + 0x2BA0, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0xA734, 0x6625, + 0x2BA0, 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x462D, 0x2AA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x6734, 0x262D, + 0xAA52, 0x6834, 0xC525, 0x8316, 0xE20E, 0x220F, 0x610F, 0x810F, 0x6B5A, 0x283C, 0x8525, 0x6416, 0xE316, 0x220F, 0x410F, 0x810F, + 0x2B62, 0xE83B, 0x6625, 0x441E, 0xC316, 0x220F, 0x420F, 0x610F, 0xEB61, 0x8943, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, + 0xCB69, 0x494B, 0xE72C, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x610F, 0x8C69, 0x0A4B, 0x8734, 0xA525, 0x6416, 0xC316, 0x220F, 0x410F, + 0x6C71, 0xCA52, 0x483C, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x2C71, 0x8B5A, 0x083C, 0x462D, 0x041E, 0xA316, 0xE20E, 0x420F, + 0x0C79, 0x4B5A, 0xC943, 0x062D, 0xE51D, 0x6316, 0xE316, 0x220F, 0xEC78, 0x0B62, 0x8943, 0xC734, 0xA525, 0x441E, 0xC316, 0x220F, + 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x241E, 0xA316, 0x020F, 0xCC80, 0xCC69, 0x0A4B, 0x6834, 0x6625, 0x041E, 0x8316, 0xE20E, + 0xAC80, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6316, 0xE316, 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x441E, 0xC316, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x441E, 0xA316, 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x8525, 0x241E, 0xA316, + 0x6C88, 0x2C79, 0x4B5A, 0x694B, 0x8734, 0x4625, 0x041E, 0x8316, 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xE51D, 0x6416, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0x6C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0xA525, 0x241E, + 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x8525, 0x241E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0x041E, + 0x4B98, 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xE51D, 0x4B98, 0xAC80, 0x8C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, + 0x4B98, 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x2B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x8525, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, + 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x462D, 0x2BA0, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0x8A52, 0x6943, 0x483C, 0xE62C, + 0x8B5A, 0x283C, 0x8525, 0x6416, 0xE316, 0x220F, 0x420F, 0x610F, 0x4B5A, 0xE83B, 0x6625, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, + 0x0B62, 0xA943, 0x262D, 0x241E, 0xA316, 0x020F, 0x420F, 0x610F, 0xCB69, 0x694B, 0xE62C, 0xE41D, 0x8316, 0xE20E, 0x220F, 0x410F, + 0xAC69, 0x2A4B, 0xA734, 0xC525, 0x6316, 0xC316, 0x220F, 0x420F, 0x6C71, 0xEA52, 0x6734, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, + 0x4C71, 0xAA52, 0x283C, 0x4625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x2C79, 0x4B5A, 0xC843, 0x062D, 0xE51D, 0x6316, 0xC316, 0x220F, + 0x0C79, 0x2B62, 0x8943, 0xC72C, 0xC525, 0x441E, 0xC316, 0x020F, 0xEC80, 0xEB61, 0x694B, 0xA734, 0x8525, 0x241E, 0xA316, 0xE20E, + 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE216, 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6316, 0xC316, + 0xAC88, 0x8C71, 0xCA52, 0xE83B, 0x062D, 0xC525, 0x441E, 0xA316, 0x8C88, 0x6C71, 0x8A5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0xA316, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x8316, 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x4625, 0xE41D, 0x6316, + 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x441E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x241E, 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x6525, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x4625, 0xE51D, 0x4B98, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xC51D, + 0x4B98, 0xAC80, 0x8C71, 0x6B5A, 0x6943, 0x4834, 0x062D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, + 0x4B98, 0xAC88, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xE72C, 0x8525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, + 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC843, 0xA734, 0x462D, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2BA0, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xE72C, 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xC734, + 0x6B5A, 0x083C, 0x6625, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x2B62, 0xC943, 0x462D, 0x241E, 0xA316, 0x020F, 0x220F, 0x410F, + 0xEB61, 0x8943, 0x062D, 0x041E, 0x8316, 0xE20E, 0x220F, 0x420F, 0xCC69, 0x494B, 0xC734, 0xC51D, 0x6316, 0xC316, 0x020F, 0x420F, + 0x8C69, 0x0A53, 0x8734, 0xA525, 0x441E, 0xC316, 0x020F, 0x420F, 0x6C71, 0xAA52, 0x483C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x2C71, 0x6B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xE316, 0x220F, 0x0C79, 0x2B5A, 0xA943, 0xE72C, 0xC525, 0x6416, 0xC316, 0x020F, + 0xEC78, 0x0B62, 0x6943, 0xA734, 0x8525, 0x241E, 0xA316, 0xE20E, 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE316, + 0xCC80, 0xAC69, 0x0A53, 0x483C, 0x262D, 0xE51D, 0x6416, 0xC316, 0xAC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xAC88, 0x6C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x241E, 0x8316, 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xE51D, 0x6416, 0x6C88, 0x0C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x8525, 0x041E, + 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xE41D, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0x2BA0, 0x8C88, 0x0C79, 0xCB61, 0xCA52, 0x8943, 0x4834, 0x062D, + 0x2BA0, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x283C, 0xC734, + 0x2AA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, + 0x4B5A, 0xE843, 0x462D, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x0B62, 0xA943, 0x062D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, + 0xEB61, 0x694B, 0xE72C, 0xE51D, 0x8316, 0xC316, 0x020F, 0x420F, 0xAC69, 0x0A4B, 0xA734, 0xA525, 0x441E, 0xC316, 0x020F, 0x220F, + 0x6C71, 0xCA52, 0x4834, 0x6525, 0x241E, 0xA316, 0xE20E, 0x220F, 0x4C71, 0x8A5A, 0x083C, 0x462D, 0x041E, 0x8316, 0xC316, 0x020F, + 0x2C79, 0x4B5A, 0xC943, 0x062D, 0xC51D, 0x6416, 0xC316, 0x020F, 0x0C79, 0x0B62, 0x8943, 0xC734, 0xA525, 0x241E, 0xA316, 0xE20E, + 0xEC80, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x8316, 0xC316, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x462D, 0xE51D, 0x6416, 0xC316, + 0xAC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xAC88, 0x6C71, 0xAA52, 0xC843, 0xE72C, 0xA525, 0x241E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x6316, 0x8C88, 0x2C71, 0x4B5A, 0x6943, 0x8734, 0x462D, 0xE51D, 0x441E, + 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0xA525, 0x241E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6525, 0x041E, 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6525, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, 0x2B98, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE843, 0x8734, 0x462D, + 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, + 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2BA0, 0x6C90, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0xA734, + 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A53, 0xC943, 0x6734, + 0x2B62, 0xA943, 0x262D, 0x041E, 0x8316, 0xE216, 0x020F, 0x420F, 0xEB61, 0x8943, 0xE62C, 0xE51D, 0x8316, 0xC316, 0x020F, 0x220F, + 0xCB69, 0x494B, 0xC734, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, 0x8C69, 0xEA52, 0x6734, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x6C71, 0xAA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xE316, 0x020F, 0x2C71, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, + 0x0C79, 0x2B5A, 0xA943, 0xE72C, 0xA525, 0x441E, 0xA316, 0xE20E, 0xEC78, 0xEB61, 0x694B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xCC80, 0xCB69, 0x2A4B, 0x4834, 0x4625, 0xE41D, 0x6416, 0xC316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x441E, 0xA316, + 0xAC80, 0x8C71, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6316, + 0x8C88, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x441E, 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x241E, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0xA525, 0x041E, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6525, 0x041E, + 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, + 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A53, 0xC843, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x4834, 0x062D, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, + 0x2BA0, 0x6C90, 0x0C79, 0xAC69, 0x8A5A, 0x694B, 0x083C, 0xC734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x0B62, 0x8943, 0x062D, 0xE41D, 0x8316, 0xC316, 0x020F, 0x220F, 0xEB61, 0x694B, 0xC72C, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x8C71, 0xCA52, 0x4834, 0x6625, 0x241E, 0x8316, 0xE316, 0x020F, + 0x4C71, 0x8A5A, 0x083C, 0x262D, 0x041E, 0x6316, 0xC316, 0x020F, 0x2C79, 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE20E, + 0x0C79, 0x2B62, 0x8943, 0xA734, 0xA525, 0x241E, 0x8316, 0xE316, 0xEC80, 0xEB61, 0x494B, 0x6734, 0x6625, 0x041E, 0x6316, 0xC316, + 0xCC80, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xAC80, 0x8C69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x441E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xC72C, 0x6525, 0x041E, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xE51D, + 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0xA525, + 0x4B90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2BA0, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0xA734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2AA8, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, + 0xEB61, 0x6943, 0xE72C, 0xC51D, 0x6416, 0xC316, 0x020F, 0x220F, 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0xAC69, 0x0A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE316, 0x020F, 0x6C71, 0xCA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x4C71, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xA316, 0xE20E, 0x2C79, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE316, + 0x0C79, 0x0B62, 0x694B, 0x8734, 0x8525, 0x041E, 0x8316, 0xC316, 0xEC80, 0xCB69, 0x2A4B, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xAC80, 0x6C71, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x041E, 0x6316, + 0xAC88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x6416, 0x8C88, 0x2C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x441E, + 0x8C88, 0x2C79, 0x2B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x6625, 0xE51D, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, + 0x4C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0xA525, 0x4C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0x8C88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x2BA0, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xA943, 0x6834, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2AA0, 0x4C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2AA8, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, + 0xEB61, 0x694B, 0xC734, 0xC525, 0x441E, 0xA316, 0xE20E, 0x020F, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x441E, 0xA316, 0xE316, 0x020F, + 0x8C69, 0xEA52, 0x6834, 0x6625, 0x241E, 0x8316, 0xC316, 0x020F, 0x6C71, 0xAA52, 0x083C, 0x262D, 0xE41D, 0x6316, 0xC316, 0xE20E, + 0x2C71, 0x6B5A, 0xC843, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE216, 0x0C79, 0x2B62, 0x8943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xCC80, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC525, 0x441E, 0x8316, + 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC88, 0x6C71, 0x8A5A, 0xC943, 0xA734, 0x6525, 0x041E, 0x6416, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x441E, 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x241E, + 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xCC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0xA525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0x4B90, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x6625, + 0x4B98, 0xAC80, 0x4C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x262D, + 0x4B98, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x6C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A53, 0xA943, 0x4834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2AA8, 0x4B98, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xE843, + 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE316, 0x020F, 0xAC69, 0x0A4B, 0x6734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, + 0x8C69, 0xCA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0xE20E, 0x4C71, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x441E, 0xA316, 0xE216, + 0x2C79, 0x4B5A, 0xA943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x0B62, 0x694B, 0xA734, 0x8525, 0x041E, 0x6316, 0xC316, + 0xEC78, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xE51D, 0x441E, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xAC80, 0x8C71, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x041E, 0x6416, 0xAC88, 0x4C71, 0x6B5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x441E, + 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, + 0x6C88, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x283C, + 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2AA0, 0x4B90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xC943, + 0xCB69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, 0xAC69, 0xEA52, 0x6834, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, + 0x6C71, 0xAA52, 0x283C, 0x462D, 0xE41D, 0x6416, 0xA316, 0xE216, 0x4C71, 0x6B5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x2C79, 0x2B5A, 0x8943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x0B62, 0x494B, 0x8734, 0x6625, 0xE41D, 0x6416, 0xA316, + 0xEC80, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x8316, 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x041E, 0x6316, + 0xAC80, 0x6C71, 0x8A5A, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE41D, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x6C90, 0xEC80, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x062D, 0x8525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, + 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, + 0x2AA8, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA8, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, + 0xCB69, 0x0A4B, 0x8734, 0x6525, 0x241E, 0x8316, 0xC316, 0xE20E, 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x6416, 0xA316, 0xE216, + 0x6C71, 0xAA52, 0x083C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xE316, 0x4C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, 0xEC78, 0xEB61, 0x494B, 0x6734, 0x462D, 0xE51D, 0x441E, 0xA316, + 0xEC80, 0xCC69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0x8C69, 0xAA52, 0xE843, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xA525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x8C88, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6525, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x4B90, 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x483C, 0xE62C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC72C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x6C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x4834, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, + 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA8, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0xAC69, 0x0A53, 0x6734, 0x6625, 0x041E, 0x6316, 0xA316, 0xE216, 0x8C69, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xC316, + 0x6C71, 0x8A5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x4C71, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xCC80, 0x8C71, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x8C88, 0x2C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x0C79, 0x0B62, 0x2A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, + 0x6C90, 0xEC80, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x8525, + 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4B98, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0xAC69, 0xEA52, 0x483C, 0x4625, 0xE41D, 0x6416, 0xA316, 0xC316, 0x8C69, 0xAA52, 0x083C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0x6C71, 0x8B5A, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C71, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x0C79, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE51D, 0x441E, 0x8316, 0xEC78, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0xAC80, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, + 0xAC88, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x294B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C88, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0xAC69, 0xEA52, 0x283C, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x8C71, 0xAA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x4C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, 0x2C79, 0x2B62, 0x8943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, + 0x0C79, 0x0B62, 0x494B, 0x6834, 0x462D, 0xC51D, 0x441E, 0x8316, 0xEC78, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, + 0xAC88, 0x4C71, 0x4B5A, 0x694B, 0x4834, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, + 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x062D, + 0x4B98, 0xAC88, 0x2C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, + 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A53, 0xA943, + 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA8, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, + 0xAC69, 0xCA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, 0x6C71, 0x8A5A, 0xE83B, 0x062D, 0xA525, 0x241E, 0x8316, 0xA316, + 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C79, 0x2B62, 0x6943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xEC80, 0xCC69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0xAC88, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0x041E, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x4C90, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC843, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x6943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0xAC69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xA316, 0x6C71, 0x8B5A, 0xE843, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, + 0x4C71, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C79, 0x2B62, 0x694B, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6316, 0xEC80, 0xAC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xAC80, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0x8C88, 0x0C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x4625, 0xC525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2AA8, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x8C69, 0xAA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x6C71, 0x8B5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6416, 0xA316, + 0x4C71, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x2C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xC525, 0x241E, 0x8316, + 0x0C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, + 0xCC80, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC80, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x041E, + 0xAC88, 0x2C79, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, + 0x8C88, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0xE62C, 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA8, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x8C69, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x041E, 0x6416, 0xA316, 0x6C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x441E, 0x8316, + 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C79, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0xCB69, 0x0A53, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, 0xEC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x241E, 0xAC80, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, + 0xAC88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC525, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xEC80, 0x8C69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B5A, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC843, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2AA8, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA8, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x8C69, 0xAA52, 0xE843, 0xE72C, 0x8525, 0x041E, 0x6416, 0x8316, 0x6C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0xE41D, 0x441E, 0x8316, + 0x4C71, 0x2B5A, 0x6943, 0x8734, 0x4625, 0xC51D, 0x241E, 0x8316, 0x2C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x041E, 0x6416, + 0x0C79, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, 0xEC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC80, 0x4C71, 0x2B62, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0xAC88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xC525, 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x4C90, 0xAC88, 0x2C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4C90, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x6943, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA8, 0x2B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x8C69, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x6C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x4C71, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, 0x2C79, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, 0xEC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xCC80, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0xA525, 0x041E, 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, + 0xAC88, 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, + 0x4B98, 0x6C88, 0xEC80, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x6B5A, 0x0A53, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0x8C69, 0x8B5A, 0xC943, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, 0x6C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x241E, 0x6316, + 0x4C71, 0x2B62, 0x494B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6416, 0x2C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0x0C79, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, 0xEC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC80, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC525, + 0xAC88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, + 0x8C88, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x294B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, + 0x8C69, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x6316, 0x6C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x4C71, 0x2B62, 0x494B, 0x4834, 0x262D, 0xA525, 0x041E, 0x6416, 0x2C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0xE41D, 0x441E, + 0x0C79, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xC51D, 0x241E, 0xEC80, 0x8C69, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xAC80, 0x2C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xAC88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0x8525, 0x8C88, 0x0C79, 0xCC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xCC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC88, 0x2C79, 0xCB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4C90, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x6B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x4B5A, 0xCA52, 0x2AA8, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x8C69, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, 0x6C71, 0x4B5A, 0x6943, 0x6734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x2C79, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, + 0x0C79, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0xEC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, 0xAC80, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, + 0xAC88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0xEC78, 0xAC69, 0x8A52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xCA52, 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x8C69, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xC525, 0x241E, 0x6416, 0x6C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0x8525, 0x041E, 0x441E, 0x2C79, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x241E, + 0x0C79, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x041E, 0xEC80, 0x8C71, 0x6B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE41D, + 0xCC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xAC80, 0x2C79, 0x0B62, 0xEA52, 0xE83B, 0xA734, 0x262D, 0xA525, + 0xAC88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x4625, + 0x8C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC843, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A52, + 0x8C69, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x6C71, 0x4B5A, 0x494B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, 0x2C79, 0xCB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, + 0x0C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC80, 0x8C71, 0x6B5A, 0x6943, 0x4834, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x4625, 0xC525, 0xAC80, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6834, 0xE62C, 0x6525, 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4C90, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, + 0x8C69, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x2C79, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x241E, + 0x0C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x6525, 0xE51D, + 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x462D, 0xC525, 0xAC80, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x8C88, 0xEC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xC843, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, + 0x8C69, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x441E, + 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x2C79, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x462D, 0xC525, 0x041E, + 0x0C79, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0x8525, 0xE41D, 0xEC80, 0x6C71, 0x6B5A, 0x494B, 0x483C, 0xE72C, 0x6625, 0xC51D, + 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0x083C, 0xA734, 0x462D, 0xA525, 0xAC80, 0x2C79, 0xEB61, 0xCA52, 0xC943, 0x6734, 0x062D, 0x8525, + 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2B98, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0x8C69, 0x0B62, 0xAA52, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C71, 0xEB61, 0x6B5A, + 0x8C69, 0x6B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x2B62, 0x294B, 0x283C, 0x062D, 0x8525, 0xE51D, 0x241E, + 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, 0x241E, 0x2C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x041E, + 0x0C79, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC525, + 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, 0xAC80, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x6525, + 0xAC88, 0x0C79, 0xCC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x4625, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x6C88, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2B98, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, + 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, 0x2AA0, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x6C71, 0xEB61, 0x6B5A, + 0x694B, 0x262D, 0x441E, 0xE20E, 0x420F, 0x8107, 0xAA52, 0xAA52, 0x2A4B, 0xE62C, 0x241E, 0xE316, 0x420F, 0x810F, 0xAA52, 0xAA52, + 0xEA52, 0xC734, 0x041E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xAA52, 0xAA52, 0x6734, 0xC51D, 0xA316, 0x220F, 0x610F, 0xAA52, 0xAA52, + 0x6B5A, 0x283C, 0xA525, 0x8316, 0x020F, 0x610F, 0xAA52, 0xAA52, 0x2B62, 0xE843, 0x6625, 0x441E, 0xE20E, 0x410F, 0xAA52, 0xAA52, + 0xEB61, 0x8943, 0x262D, 0x241E, 0xC316, 0x420F, 0xAA52, 0xAA52, 0xAC69, 0x494B, 0xE72C, 0xE41D, 0xA316, 0x220F, 0xAA52, 0xAA52, + 0x8C71, 0x0A4B, 0xA734, 0xC525, 0x8316, 0x020F, 0xAA52, 0xAA52, 0x4C71, 0xCA52, 0x6834, 0x8525, 0x6316, 0x020F, 0xA107, 0xAA52, + 0x2C71, 0x8A5A, 0x283C, 0x6625, 0x441E, 0xE216, 0x8107, 0xAA52, 0x0C79, 0x6B5A, 0xE83B, 0x262D, 0x241E, 0xC316, 0x810F, 0xAA52, + 0x0C79, 0x2B62, 0xA943, 0xE62C, 0xE41D, 0xA316, 0x610F, 0xAA52, 0xEC80, 0x0B62, 0x8943, 0xC734, 0xC525, 0x8316, 0x420F, 0xAA52, + 0xCC80, 0xEB61, 0x494B, 0x8734, 0xA525, 0x6316, 0x220F, 0xAA52, 0xCC80, 0xCC69, 0x2A4B, 0x6734, 0x8525, 0x441E, 0x020F, 0xAA52, + 0xAC80, 0x8C69, 0xEA52, 0x283C, 0x4625, 0x241E, 0xE20E, 0xAA52, 0xAC88, 0x8C71, 0xCA52, 0x083C, 0x262D, 0x041E, 0xC316, 0xAA52, + 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xE51D, 0xA316, 0xAA52, 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xE72C, 0xC525, 0x8316, 0xAA52, + 0x6C88, 0x2C71, 0x4B5A, 0x8943, 0xA734, 0xA525, 0x6316, 0xAA52, 0x6C90, 0x2C79, 0x2B62, 0x694B, 0x8734, 0x8525, 0x441E, 0xAA52, + 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x4625, 0x241E, 0x810F, 0x6C90, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0x041E, 0x220F, + 0x4C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0x062D, 0xE51D, 0xE216, 0x4B98, 0xCC80, 0xCB69, 0xCA52, 0xE83B, 0xE72C, 0xC525, 0xA316, + 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0xA525, 0x8316, 0x4B98, 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x6416, + 0x4B98, 0xAC80, 0x8C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x441E, 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x4834, 0x262D, 0x041E, + 0x2B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xE41D, 0x2BA0, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE62C, 0xC51D, + 0x494B, 0x062D, 0x441E, 0xE316, 0x420F, 0x610F, 0xA107, 0xAA52, 0x0A53, 0xC72C, 0x041E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0xCA52, 0x8734, 0xE51D, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, 0x8B5A, 0x483C, 0xA525, 0x8316, 0x020F, 0x410F, 0x8107, 0xAA52, + 0x4B5A, 0x083C, 0x8525, 0x6416, 0xE20E, 0x420F, 0x8107, 0xAA52, 0x0B62, 0xA943, 0x462D, 0x241E, 0xC316, 0x220F, 0x810F, 0xAA52, + 0xCB69, 0x6943, 0x062D, 0x041E, 0xA316, 0x220F, 0x610F, 0xAA52, 0x8C69, 0x2A4B, 0xA734, 0xC51D, 0x8316, 0x020F, 0x610F, 0xAA52, + 0x6C71, 0xEA52, 0x6734, 0xA525, 0x6416, 0xE20E, 0x610F, 0xAA52, 0x4C71, 0xAA52, 0x283C, 0x6625, 0x441E, 0xC316, 0x420F, 0xAA52, + 0x2C79, 0x6B5A, 0x083C, 0x262D, 0x241E, 0xC316, 0x220F, 0xAA52, 0x0C79, 0x4B5A, 0xC943, 0x062D, 0xE41D, 0xA316, 0x220F, 0xAA52, + 0xEC78, 0x0B62, 0x8943, 0xC72C, 0xC525, 0x8316, 0x020F, 0xAA52, 0xCC80, 0xEB61, 0x494B, 0xA734, 0xA525, 0x6416, 0xE20E, 0xAA52, + 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x8525, 0x441E, 0xE316, 0xAA52, 0xAC80, 0xAC69, 0xEA52, 0x483C, 0x4625, 0x241E, 0xC316, 0xAA52, + 0xAC88, 0x8C69, 0xCA52, 0x083C, 0x262D, 0x041E, 0xA316, 0xA107, 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC51D, 0x8316, 0x610F, + 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x6316, 0x420F, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x441E, 0x220F, + 0x6C90, 0x2C79, 0x2B5A, 0x694B, 0x8734, 0x6625, 0x241E, 0x020F, 0x6C90, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x462D, 0x041E, 0xE316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xE41D, 0xC316, 0x4C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0x062D, 0xC51D, 0xA316, + 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x8316, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x6416, + 0x4B98, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x6525, 0x441E, 0x4B98, 0xAC80, 0x8C69, 0x8B5A, 0x8943, 0x8734, 0x4625, 0x241E, + 0x2B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x6834, 0x262D, 0x041E, 0x2B98, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xE51D, + 0x2BA0, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE62C, 0xC525, 0x2BA0, 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xC72C, 0xA525, + 0x2A4B, 0xE72C, 0x241E, 0xC316, 0x220F, 0x610F, 0x8107, 0xC007, 0xEA52, 0xA734, 0xE41D, 0xA316, 0x220F, 0x610F, 0x810F, 0xC007, + 0xAA52, 0x6734, 0xC525, 0x8316, 0x020F, 0x420F, 0x810F, 0xC007, 0x6B5A, 0x283C, 0x8525, 0x6316, 0xE20E, 0x420F, 0x810F, 0xC007, + 0x2B62, 0xE843, 0x4625, 0x441E, 0xC316, 0x220F, 0x610F, 0xA107, 0xEB61, 0x8943, 0x062D, 0x041E, 0xC316, 0x220F, 0x610F, 0xA107, + 0xAC69, 0x494B, 0xC72C, 0xE51D, 0x8316, 0x020F, 0x410F, 0xA107, 0x8C71, 0x0A53, 0x8734, 0xA525, 0x6316, 0xE20E, 0x420F, 0xA107, + 0x4C71, 0xCA52, 0x483C, 0x8525, 0x441E, 0xC316, 0x220F, 0x8107, 0x2C71, 0x8B5A, 0x083C, 0x462D, 0x241E, 0xA316, 0x220F, 0x8107, + 0x0C79, 0x4B5A, 0xC843, 0x062D, 0x041E, 0x8316, 0x020F, 0x810F, 0x0C79, 0x2B62, 0xA943, 0xE72C, 0xC51D, 0x8316, 0xE20E, 0x610F, + 0xEC80, 0xEB61, 0x694B, 0xA734, 0xA525, 0x441E, 0xE316, 0x610F, 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x8525, 0x241E, 0xC316, 0x420F, + 0xAC80, 0xAC69, 0x0A4B, 0x483C, 0x4625, 0x041E, 0xA316, 0x220F, 0xAC88, 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE41D, 0x8316, 0x220F, + 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC51D, 0x6316, 0x020F, 0x8C88, 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x6416, 0xE20E, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x441E, 0xE316, 0x6C88, 0x2C79, 0x4B5A, 0x6943, 0x8734, 0x6625, 0x241E, 0xC316, + 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x462D, 0x041E, 0xA316, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xE51D, 0x8316, + 0x6C90, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0x062D, 0xC525, 0x6316, 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x6416, + 0x4B90, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x8525, 0x441E, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x241E, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x462D, 0x041E, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x4834, 0x262D, 0xE51D, + 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xC525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0xA525, + 0x2BA0, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0xA734, 0x6525, + 0xEA52, 0xC734, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0xA107, 0xAA52, 0x8734, 0xC51D, 0x8316, 0x020F, 0x420F, 0x610F, 0x8107, + 0x8B5A, 0x483C, 0xA525, 0x6316, 0xE20E, 0x220F, 0x610F, 0x8107, 0x4B5A, 0xE83B, 0x6625, 0x441E, 0xC316, 0x220F, 0x610F, 0x8107, + 0x0B62, 0xA943, 0x262D, 0x241E, 0xA316, 0x020F, 0x410F, 0x810F, 0xCB69, 0x694B, 0xE72C, 0xE41D, 0x8316, 0x020F, 0x420F, 0x810F, + 0x8C69, 0x2A4B, 0xA734, 0xC525, 0x6316, 0xE216, 0x220F, 0x610F, 0x6C71, 0xCA52, 0x6834, 0x8525, 0x441E, 0xC316, 0x220F, 0x610F, + 0x4C71, 0x8A5A, 0x283C, 0x4625, 0x241E, 0xA316, 0x020F, 0x410F, 0x2C79, 0x6B5A, 0xE83B, 0x062D, 0xE41D, 0x8316, 0xE20E, 0x420F, + 0x0C79, 0x2B62, 0xA943, 0xE72C, 0xC525, 0x6316, 0xE316, 0x220F, 0xEC78, 0x0B62, 0x6943, 0xA734, 0xA525, 0x441E, 0xC316, 0x220F, + 0xCC80, 0xCB61, 0x2A4B, 0x6734, 0x6525, 0x241E, 0xA316, 0x020F, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x462D, 0x041E, 0x8316, 0x020F, + 0xAC80, 0x8C69, 0xEA52, 0x083C, 0x262D, 0xE51D, 0x6316, 0xE20E, 0xAC88, 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x6416, 0xE316, + 0x8C88, 0x6C71, 0x8B5A, 0xC943, 0xC734, 0xA525, 0x441E, 0xC316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, + 0x6C88, 0x2C79, 0x4B5A, 0x694B, 0x8734, 0x4625, 0x041E, 0x8316, 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xE51D, 0x8316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x6416, 0x6C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xA525, 0x441E, + 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x8525, 0x241E, 0x4C90, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0x041E, + 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x4625, 0x041E, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xE51D, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xC525, 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, + 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x8525, 0x2B98, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6525, + 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0xA734, 0x4625, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x462D, + 0xCA52, 0x8734, 0xE51D, 0x8316, 0x020F, 0x420F, 0x610F, 0x810F, 0x8A5A, 0x483C, 0xA525, 0x6316, 0xE216, 0x220F, 0x610F, 0x810F, + 0x6B5A, 0x083C, 0x8525, 0x441E, 0xC316, 0x220F, 0x410F, 0x810F, 0x2B62, 0xC943, 0x462D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, + 0xEB61, 0x8943, 0x062D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0xAC69, 0x294B, 0xC734, 0xC525, 0x6316, 0xE216, 0x220F, 0x610F, + 0x8C71, 0xEA52, 0x8734, 0x8525, 0x441E, 0xC316, 0x020F, 0x410F, 0x4C71, 0xAA52, 0x283C, 0x4625, 0x241E, 0xA316, 0x020F, 0x420F, + 0x2C79, 0x6B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xC51D, 0x6416, 0xC316, 0x220F, + 0xEC78, 0x0B62, 0x8943, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, 0xCC80, 0xEB61, 0x494B, 0x8734, 0x6525, 0x241E, 0xA316, 0x020F, + 0xCC80, 0xCC69, 0x0A4B, 0x483C, 0x462D, 0x041E, 0x8316, 0xE216, 0xAC80, 0xAC69, 0xEA52, 0x083C, 0x262D, 0xE51D, 0x6416, 0xC316, + 0xAC88, 0x8C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x441E, 0xC316, 0x8C88, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x241E, 0xA316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x8316, 0x8C88, 0x2C79, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xE51D, 0x6316, + 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC51D, 0x6416, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x441E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x241E, 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x6525, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0x041E, 0x4B98, 0xCC80, 0xAC69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x262D, 0xC525, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6525, + 0x2B98, 0x8C88, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, 0x2BA0, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x462D, + 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, + 0xAA52, 0x6734, 0xA525, 0x6316, 0xE216, 0x220F, 0x410F, 0x610F, 0x6B5A, 0x283C, 0x8525, 0x441E, 0xC316, 0x220F, 0x420F, 0x610F, + 0x4B5A, 0xE83B, 0x6625, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, 0x0B62, 0xA943, 0x062D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x610F, + 0xCB69, 0x494B, 0xC72C, 0xE51D, 0x8316, 0xE216, 0x220F, 0x410F, 0x8C69, 0x0A4B, 0x8734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, + 0x6C71, 0xCA52, 0x483C, 0x6625, 0x241E, 0xA316, 0x020F, 0x220F, 0x2C71, 0x8B5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, + 0x0C79, 0x4B5A, 0xC943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x020F, 0x0C79, 0x2B62, 0x8943, 0xC734, 0xA525, 0x441E, 0xA316, 0x020F, + 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE20E, 0xCC80, 0xCB69, 0x2A4B, 0x4834, 0x4625, 0x041E, 0x8316, 0xC316, + 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x6416, 0xC316, 0xAC88, 0x8C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x441E, 0xA316, + 0x8C88, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x241E, 0x8316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x8316, + 0x8C88, 0x2C79, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xE51D, 0x6416, 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE62C, 0xA525, 0x241E, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x8525, 0x041E, + 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x6625, 0x041E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4B90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC72C, 0x6525, + 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0x0A53, 0xC843, 0x8734, 0x462D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xA943, 0x8734, 0x262D, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, + 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x2BA0, 0x6C90, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x283C, 0xE72C, + 0x8B5A, 0x483C, 0x8525, 0x6416, 0xC316, 0x020F, 0x420F, 0x610F, 0x4B5A, 0x083C, 0x6625, 0x441E, 0xC316, 0x020F, 0x220F, 0x610F, + 0x2B62, 0xC943, 0x262D, 0x241E, 0xA316, 0xE20E, 0x220F, 0x410F, 0xEB61, 0x6943, 0xE62C, 0xE51D, 0x8316, 0xE216, 0x220F, 0x420F, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, 0x8C71, 0xEA52, 0x6734, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, + 0x4C71, 0xAA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE216, 0x220F, 0x2C79, 0x6B5A, 0xC843, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, + 0x0C79, 0x2B62, 0xA943, 0xC734, 0xA525, 0x441E, 0xA316, 0x020F, 0xEC78, 0x0B62, 0x694B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE216, + 0xCC80, 0xCB69, 0x2A4B, 0x6834, 0x4625, 0x041E, 0x6316, 0xC316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xAC80, 0x8C69, 0xCA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0xA316, 0xAC88, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x6316, 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xC51D, 0x441E, + 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE62C, 0x8525, 0x241E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6525, 0x041E, 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xE51D, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6834, 0x262D, 0xA525, + 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0xAC88, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2BA0, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0x062D, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, + 0x2BA0, 0x6C90, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xC734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, + 0x6B5A, 0x083C, 0x6625, 0x441E, 0xA316, 0x020F, 0x220F, 0x420F, 0x2B62, 0xC843, 0x462D, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, + 0x0B62, 0x8943, 0x062D, 0xE41D, 0x8316, 0xE316, 0x220F, 0x420F, 0xCB69, 0x494B, 0xC734, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, + 0x8C69, 0x0A4B, 0x8734, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x6C71, 0xCA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xE316, 0x220F, + 0x4C71, 0x8B5A, 0xE83B, 0x262D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xA525, 0x441E, 0xA316, 0xE20E, + 0xEC78, 0x0B62, 0x6943, 0xA734, 0x8525, 0x241E, 0x8316, 0xE316, 0xEC80, 0xEB61, 0x2A4B, 0x6734, 0x4625, 0x041E, 0x6316, 0xC316, + 0xCC80, 0xAC69, 0x0A53, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xAC80, 0x8C69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x8316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x6416, + 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x441E, 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE41D, + 0x6C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC51D, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, + 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x4834, 0x062D, 0xA525, 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x4625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0x062D, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, + 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x2BA0, 0x6C90, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2AA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x8734, + 0x4B5A, 0xE83B, 0x462D, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x0B62, 0xA943, 0x062D, 0x041E, 0x8316, 0xE316, 0x020F, 0x420F, + 0xEB61, 0x6943, 0xE72C, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x8C71, 0xEA52, 0x6834, 0x6625, 0x241E, 0x8316, 0xE216, 0x020F, 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0x6316, 0xC316, 0x020F, + 0x2C79, 0x6B5A, 0xC843, 0x062D, 0xC525, 0x441E, 0xA316, 0xE20E, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0xE316, + 0xEC78, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6316, 0xC316, 0xCC80, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xE51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, 0xAC88, 0x8C71, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x041E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x6416, 0x8C88, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x441E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x083C, 0xC734, + 0x2BA0, 0x6C90, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0xEA52, 0xA943, 0x4834, + 0x2B62, 0xC943, 0x262D, 0x041E, 0x8316, 0xE316, 0x020F, 0x220F, 0x0B62, 0x8943, 0xE62C, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, + 0xCB69, 0x494B, 0xC734, 0xC525, 0x6416, 0xC316, 0xE20E, 0x220F, 0xAC69, 0x0A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE216, 0x020F, + 0x6C71, 0xCA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, 0x4C71, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xA316, 0xE20E, + 0x2C79, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, 0xEC78, 0x0B62, 0x694B, 0x8734, 0x6525, 0x041E, 0x8316, 0xC316, + 0xEC80, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xE51D, 0x6416, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xC525, 0x441E, 0x8316, + 0xAC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x8316, 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE41D, 0x6416, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x441E, 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x6C88, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x483C, 0x062D, 0x8525, 0x4C90, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x4625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x2BA0, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x8734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, + 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2B62, 0xA943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xEB61, 0x6943, 0xE72C, 0xC525, 0x6416, 0xA316, 0xE20E, 0x220F, + 0xCB69, 0x294B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, 0x8C69, 0xEA52, 0x6834, 0x6625, 0x241E, 0x8316, 0xC316, 0x020F, + 0x6C71, 0xAA52, 0x283C, 0x262D, 0xE41D, 0x6316, 0xC316, 0xE20E, 0x2C71, 0x6B5A, 0xC843, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE216, + 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xEC78, 0xEB61, 0x494B, 0x6734, 0x4625, 0xE41D, 0x6416, 0xA316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x441E, 0xA316, 0xCC80, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x8316, + 0xAC80, 0x6C71, 0xAA52, 0xC943, 0xC734, 0x6525, 0x041E, 0x6416, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x441E, + 0x8C88, 0x2C71, 0x4B5A, 0x494B, 0x4834, 0x262D, 0xA525, 0x241E, 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x4C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0x062D, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x6834, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, + 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x0B62, 0x8943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0xE20E, 0x220F, 0xCB61, 0x494B, 0xC734, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, + 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, 0x8C71, 0xCA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x4C71, 0x8A5A, 0x083C, 0x062D, 0xE51D, 0x441E, 0xA316, 0xE216, 0x2C79, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x6943, 0xA734, 0x6525, 0x041E, 0x6316, 0xC316, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, 0xAC80, 0x8C69, 0xAA52, 0xE843, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x283C, 0x062D, 0x8525, 0x041E, 0x6C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6525, 0xE51D, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x062D, 0x8525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4B98, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x062D, 0x4B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, + 0x2AA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0x083C, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0xEB61, 0x6943, 0xC72C, 0xC525, 0x441E, 0xA316, 0xE216, 0x020F, 0xCB69, 0x2A4B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, + 0xAC69, 0x0A53, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, 0x6C71, 0xAA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, + 0x4C71, 0x6B5A, 0xE843, 0xE62C, 0xC525, 0x441E, 0x8316, 0xC316, 0x2C79, 0x4B5A, 0x8943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x494B, 0x8734, 0x6625, 0xE41D, 0x6416, 0xA316, 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6316, 0xAC80, 0x6C71, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x8C88, 0x2C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x062D, + 0x4B98, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE62C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC72C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x6C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2AA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0x083C, + 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0xEB61, 0x694B, 0xC734, 0xA525, 0x441E, 0x8316, 0xC316, 0x020F, 0xCC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, + 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xA316, 0xE20E, 0x6C71, 0xAA52, 0x083C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xE316, + 0x2C71, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, + 0xEC78, 0xEB61, 0x294B, 0x6834, 0x462D, 0xE51D, 0x441E, 0xA316, 0xCC80, 0xCC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xCC80, 0x8C69, 0xAA52, 0xE843, 0xC72C, 0x8525, 0x041E, 0x6416, 0xAC80, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x4625, 0xC51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xA525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x294B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0x0C79, 0xCB61, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, 0x6C90, 0xCC80, 0xAC69, 0x8B5A, 0x8943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0x062D, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0x083C, 0x2AA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, + 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0xEB61, 0x494B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x6316, 0xA316, 0xE216, + 0x8C69, 0xCA52, 0x283C, 0x462D, 0xE51D, 0x6416, 0xA316, 0xE316, 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x2C71, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0x6316, 0xC316, 0x0C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE41D, 0x6416, 0xA316, + 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xCC80, 0xAC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, + 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x4B90, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xCC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xCB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4B98, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0xCB69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE216, 0xAC69, 0xEA52, 0x4834, 0x4625, 0x041E, 0x6416, 0xA316, 0xE316, + 0x8C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xC316, 0x4C71, 0x8B5A, 0xC843, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, 0x0C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x8316, + 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x441E, 0xAC88, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x241E, + 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x8C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, + 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x4625, + 0x4C90, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x2B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x2B98, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4B90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x6416, 0xA316, 0xE316, 0xAC69, 0xEA52, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xC316, + 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x4C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x6316, 0xA316, + 0x2C79, 0x2B62, 0x8943, 0x8734, 0x6625, 0xE41D, 0x441E, 0xA316, 0x0C79, 0xEB61, 0x294B, 0x4834, 0x262D, 0xC525, 0x241E, 0x8316, + 0xEC80, 0xCB69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0xCC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x6625, 0xE51D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x8525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x694B, + 0xCB69, 0x0A4B, 0x6834, 0x4625, 0xE41D, 0x6416, 0xA316, 0xC316, 0x8C69, 0xCA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xA525, 0x241E, 0x8316, 0xC316, 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x2B62, 0x694B, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, 0x0C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, + 0xEC80, 0xAC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xC51D, 0x441E, + 0xAC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC88, 0x4C71, 0x2B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x283C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0xE62C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, + 0x2B98, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x0A53, 0x8943, 0x2AA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0xAC69, 0xEA52, 0x483C, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, + 0x6C71, 0x8A5A, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, 0x4C71, 0x4B5A, 0x8943, 0xA734, 0x6525, 0x041E, 0x441E, 0xA316, + 0x2C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xC51D, 0x441E, 0x8316, 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, 0xCC80, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, + 0xAC80, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0x0C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xC525, 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4C90, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x4C90, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0xA943, + 0x2AA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x494B, + 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, 0x8C69, 0xAA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, + 0x6C71, 0x8B5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6416, 0xA316, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6316, 0xEC78, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x241E, + 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0x041E, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0xE62C, + 0x4B90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2AA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xA316, 0x8C69, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x6416, 0xA316, + 0x6C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x441E, 0x8316, 0x2C71, 0x2B62, 0x6943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6416, 0xEC78, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C88, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x4834, 0xE62C, 0x8525, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x4B90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, + 0x2AA0, 0x4B98, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0xAC69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x8C69, 0x8A52, 0xE843, 0xE72C, 0x8525, 0x041E, 0x6416, 0xA316, + 0x6C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0xE41D, 0x441E, 0x8316, 0x2C71, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x6834, 0x062D, 0x8525, 0x041E, + 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xA525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C88, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0xE62C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x2B98, 0x6C88, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x6B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0xAC69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0xA316, 0x8C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x441E, 0x8316, + 0x6C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C71, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, 0xEC78, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, + 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xAC80, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, + 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC525, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B90, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x494B, 0x083C, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x2A4B, 0xE843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8B5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB61, 0x6B5A, 0xEA52, + 0xAC69, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x041E, 0x6416, 0x8316, 0x8C71, 0x8B5A, 0xC943, 0xC734, 0x6525, 0xE41D, 0x441E, 0x8316, + 0x6C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xC51D, 0x241E, 0x6316, 0x2C71, 0x0B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x041E, 0x6416, + 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0xE41D, 0x441E, 0xEC78, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xC51D, 0x241E, + 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0xAC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x6525, 0xE51D, + 0xAC88, 0x2C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0xE62C, 0x6525, 0x6C88, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x4B90, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xEB61, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0xAC69, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x8C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6316, 0x2C71, 0x0B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x0C79, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, 0xEC78, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xCC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, + 0xAC88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x6C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B90, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xAC69, 0xAA52, 0xC843, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, 0x8C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xC51D, 0x241E, 0x6316, + 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x241E, 0x6416, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6625, 0xE51D, 0x241E, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0x8525, 0xE41D, 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC525, + 0xAC88, 0x2C79, 0x0B62, 0xEA52, 0xE83B, 0xA734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x4625, 0x6C88, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xA734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE843, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xAC69, 0x4B5A, 0xCA52, + 0xAC69, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE51D, 0x241E, 0x6316, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xC525, 0x241E, 0x6416, + 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x441E, + 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE51D, 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xAC88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x4834, 0xE62C, 0x6625, + 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x6C88, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC734, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0xAC69, 0x8A5A, 0xC943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x4C71, 0x2B5A, 0x494B, 0x4834, 0x262D, 0xA525, 0x041E, 0x441E, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xC525, 0x241E, 0xEC78, 0xAC69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x6525, 0xE51D, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0xAC88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, 0x4C90, 0xAC88, 0x0C79, 0xCB69, 0x8B5A, 0x294B, 0xE843, 0x6734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, 0x4B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0xAC69, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC525, 0x241E, 0x6416, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x2C71, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x6625, 0xE51D, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x041E, 0xEC78, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0x8525, 0xE41D, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, + 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xC72C, 0x4625, + 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C88, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8A52, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xC843, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x0B62, 0xAA52, + 0xAC69, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x041E, 0x441E, 0x8C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE51D, 0x441E, 0x2C71, 0xEB61, 0x0A53, 0x083C, 0xC72C, 0x6625, 0xC51D, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC78, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC525, 0xAC80, 0x4C71, 0x0B62, 0x0A53, 0xE83B, 0x8734, 0x262D, 0xA525, + 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0xE62C, 0x6525, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x6943, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C88, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC734, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, + 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, + 0xAC69, 0x8B5A, 0x8943, 0x8734, 0x462D, 0xA525, 0x041E, 0x441E, 0x8C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, + 0x6C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x2C71, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x4625, 0xC525, 0x041E, + 0x0C79, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC78, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x4625, 0xC525, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0x8525, + 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE72C, 0x6625, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6834, 0xE72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE843, 0x6734, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, + 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE843, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x0B62, 0x8A5A, 0x2AA0, 0x4B98, 0x6C90, 0xAC80, 0x2C79, 0x8C69, 0x0B62, 0x8B5A, + 0xAC69, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, 0x8C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x241E, + 0x6C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x2C71, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x041E, + 0x0C79, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0x8525, 0xE41D, 0xEC78, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x6625, 0xC51D, + 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x462D, 0xA525, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x694B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x8C88, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x8734, + 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0xEB61, 0xAA52, 0x294B, 0xC943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0xA943, + 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2B98, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52, 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0x8C69, 0x0B62, 0x8A5A, 0x2AA0, 0x4B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x0B62, 0x8B5A, + 0xA943, 0x6625, 0x6316, 0x020F, 0x410F, 0x8107, 0xAA52, 0xAA52, 0x494B, 0x262D, 0x441E, 0xE20E, 0x420F, 0x8107, 0xAA52, 0xAA52, + 0x2A4B, 0xE62C, 0x241E, 0xC316, 0x420F, 0x810F, 0xAA52, 0xAA52, 0xCA52, 0xA734, 0xE41D, 0xA316, 0x220F, 0x810F, 0xAA52, 0xAA52, + 0x8A5A, 0x6834, 0xC525, 0x8316, 0x020F, 0x610F, 0xAA52, 0xAA52, 0x4B5A, 0x083C, 0x8525, 0x6316, 0x020F, 0x610F, 0xAA52, 0xAA52, + 0x0B62, 0xC943, 0x462D, 0x441E, 0xE216, 0x420F, 0xAA52, 0xAA52, 0xCB69, 0x8943, 0x062D, 0x041E, 0xC316, 0x420F, 0xAA52, 0xAA52, + 0xAC69, 0x494B, 0xC734, 0xE51D, 0xA316, 0x220F, 0xAA52, 0xAA52, 0x6C71, 0x0A53, 0x8734, 0xA525, 0x8316, 0x020F, 0xAA52, 0xAA52, + 0x4C71, 0xCA52, 0x483C, 0x8525, 0x6416, 0x020F, 0xAA52, 0xAA52, 0x2C71, 0x8A5A, 0x083C, 0x4625, 0x441E, 0xE316, 0xAA52, 0xAA52, + 0x0C79, 0x6B5A, 0xE843, 0x262D, 0x041E, 0xC316, 0xA107, 0xAA52, 0x0C79, 0x2B62, 0xA943, 0xE72C, 0xE51D, 0xA316, 0x610F, 0xAA52, + 0xEC80, 0x0B62, 0x6943, 0xC734, 0xC525, 0x8316, 0x410F, 0xAA52, 0xCC80, 0xEB61, 0x494B, 0x8734, 0xA525, 0x6416, 0x220F, 0xAA52, + 0xCC80, 0xCB69, 0x0A4B, 0x6834, 0x6625, 0x441E, 0x020F, 0xAA52, 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x462D, 0x241E, 0xE20E, 0xAA52, + 0xAC88, 0x8C69, 0xCA52, 0x083C, 0x262D, 0x041E, 0xC316, 0xAA52, 0x8C88, 0x6C71, 0xAA52, 0xE843, 0x062D, 0xE51D, 0xA316, 0xAA52, + 0x8C88, 0x4C71, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x8316, 0xAA52, 0x8C88, 0x4C71, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x6316, 0xAA52, + 0x6C90, 0x2C79, 0x2B5A, 0x694B, 0x8734, 0x6525, 0x441E, 0xAA52, 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x4625, 0x241E, 0x8107, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x262D, 0x041E, 0x220F, 0x4C90, 0xEC78, 0xEB61, 0xEA52, 0x083C, 0x062D, 0xE51D, 0xE316, + 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xE83B, 0xE72C, 0xC525, 0xA316, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xC734, 0xA525, 0x8316, + 0x4B98, 0xCC80, 0xAC69, 0x8A52, 0xA943, 0xA734, 0x8525, 0x6416, 0x4B98, 0xAC80, 0x8C69, 0x6B5A, 0x8943, 0x6734, 0x6625, 0x241E, + 0x2B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x262D, 0x041E, 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xE51D, + 0x6943, 0x462D, 0x441E, 0xE20E, 0x420F, 0x810F, 0xA107, 0xAA52, 0x2A4B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0x0A53, 0xC734, 0x041E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, 0xAA52, 0x8734, 0xC51D, 0xA316, 0x020F, 0x610F, 0xA107, 0xAA52, + 0x6B5A, 0x283C, 0xA525, 0x6316, 0x020F, 0x420F, 0xA107, 0xAA52, 0x2B62, 0xE83B, 0x6625, 0x441E, 0xE216, 0x420F, 0x8107, 0xAA52, + 0xEB61, 0xA943, 0x262D, 0x241E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xAC69, 0x494B, 0xE72C, 0xE51D, 0xA316, 0x020F, 0x810F, 0xAA52, + 0x8C69, 0x0A4B, 0xA734, 0xC525, 0x8316, 0x020F, 0x610F, 0xAA52, 0x6C71, 0xEA52, 0x6834, 0x8525, 0x6416, 0xE216, 0x610F, 0xAA52, + 0x4C71, 0xAA52, 0x283C, 0x6625, 0x241E, 0xC316, 0x420F, 0xAA52, 0x2C79, 0x6B5A, 0xE83B, 0x262D, 0x041E, 0xA316, 0x220F, 0xAA52, + 0x0C79, 0x4B5A, 0xA943, 0xE62C, 0xE51D, 0x8316, 0x220F, 0xAA52, 0xEC78, 0x0B62, 0x8943, 0xC734, 0xC525, 0x6316, 0x020F, 0xAA52, + 0xCC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0xE20E, 0xAA52, 0xCC80, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x241E, 0xE316, 0xAA52, + 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x462D, 0x041E, 0xC316, 0xAA52, 0xAC88, 0x8C69, 0xCA52, 0x083C, 0x262D, 0xE41D, 0xA316, 0xAA52, + 0x8C88, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xC51D, 0x8316, 0x810F, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC72C, 0xA525, 0x6316, 0x420F, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x441E, 0x220F, 0x6C90, 0x2C79, 0x4B5A, 0x694B, 0x8734, 0x6625, 0x241E, 0x020F, + 0x6C90, 0x0C79, 0x2B62, 0x494B, 0x6834, 0x462D, 0x041E, 0xE316, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x262D, 0xE41D, 0xC316, + 0x6C90, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0x062D, 0xC51D, 0xA316, 0x4C90, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x6316, + 0x4B90, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x441E, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6525, 0x241E, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x4625, 0x241E, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xE41D, + 0x2B98, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xC51D, 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE62C, 0xA525, + 0x494B, 0x262D, 0x441E, 0xC316, 0x220F, 0x610F, 0x8107, 0xAA52, 0x0A4B, 0xE72C, 0x041E, 0xC316, 0x220F, 0x610F, 0x8107, 0xAA52, + 0xCA52, 0xA734, 0xE51D, 0xA316, 0x020F, 0x410F, 0x8107, 0xAA52, 0x8A5A, 0x6834, 0xA525, 0x8316, 0x020F, 0x420F, 0x810F, 0xE007, + 0x4B5A, 0x083C, 0x8525, 0x6416, 0xE216, 0x220F, 0x610F, 0xC007, 0x0B62, 0xC943, 0x462D, 0x241E, 0xC316, 0x220F, 0x610F, 0xC007, + 0xCB61, 0x8943, 0x062D, 0x041E, 0xA316, 0x020F, 0x610F, 0xC007, 0xAC69, 0x2A4B, 0xA734, 0xC525, 0x8316, 0xE20E, 0x420F, 0xA107, + 0x6C71, 0xEA52, 0x8734, 0xA525, 0x6416, 0xE316, 0x420F, 0xA107, 0x4C71, 0xCA52, 0x483C, 0x6625, 0x241E, 0xC316, 0x220F, 0xA107, + 0x2C71, 0x8B5A, 0x083C, 0x262D, 0x041E, 0xA316, 0x220F, 0x8107, 0x0C79, 0x4B5A, 0xC943, 0x062D, 0xE51D, 0x8316, 0x020F, 0x810F, + 0xEC78, 0x2B62, 0x8943, 0xC734, 0xC525, 0x6416, 0xE20E, 0x610F, 0xEC80, 0x0B62, 0x694B, 0xA734, 0x8525, 0x441E, 0xC316, 0x610F, + 0xCC80, 0xCB61, 0x2A4B, 0x6734, 0x6625, 0x241E, 0xC316, 0x420F, 0xCC80, 0xAC69, 0x0A4B, 0x483C, 0x462D, 0x041E, 0xA316, 0x220F, + 0xAC80, 0x8C69, 0xCA52, 0x083C, 0x262D, 0xE51D, 0x8316, 0x220F, 0xAC88, 0x8C71, 0xAA52, 0xE83B, 0xE62C, 0xC525, 0x6316, 0x020F, + 0x8C88, 0x6C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x441E, 0xE20E, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x441E, 0xE316, + 0x6C88, 0x2C71, 0x4B5A, 0x694B, 0x8734, 0x6625, 0x241E, 0xC316, 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x6834, 0x462D, 0x041E, 0xA316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x262D, 0xE51D, 0x8316, 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0x062D, 0xC525, 0x6316, + 0x4C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x441E, 0x4C90, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x241E, + 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x241E, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x462D, 0x041E, + 0x4B98, 0xAC80, 0x8C71, 0x6B5A, 0x694B, 0x4834, 0x262D, 0xE51D, 0x2B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xC525, + 0x2B98, 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xE72C, 0xA525, 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xC734, 0x8525, + 0x2A4B, 0xE62C, 0x241E, 0xC316, 0x220F, 0x410F, 0x810F, 0xA107, 0xEA52, 0xA734, 0xE41D, 0xA316, 0x020F, 0x420F, 0x610F, 0xA107, + 0xAA52, 0x8734, 0xC525, 0x8316, 0x020F, 0x420F, 0x610F, 0x8107, 0x6B5A, 0x283C, 0x8525, 0x6416, 0xE216, 0x220F, 0x610F, 0x8107, + 0x2B62, 0xE83B, 0x4625, 0x241E, 0xC316, 0x220F, 0x610F, 0x8107, 0xEB61, 0xA943, 0x062D, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, + 0xCC69, 0x494B, 0xC72C, 0xE51D, 0x8316, 0xE20E, 0x420F, 0x610F, 0x8C69, 0x0A4B, 0x8734, 0xA525, 0x6416, 0xC316, 0x220F, 0x610F, + 0x6C71, 0xCA52, 0x483C, 0x6625, 0x241E, 0xA316, 0x020F, 0x610F, 0x4C71, 0x8A5A, 0x083C, 0x262D, 0x041E, 0xA316, 0x020F, 0x410F, + 0x2C79, 0x6B5A, 0xC843, 0x062D, 0xE51D, 0x8316, 0xE20E, 0x420F, 0x0C79, 0x2B62, 0xA943, 0xC72C, 0xC525, 0x6416, 0xC316, 0x220F, + 0xEC80, 0x0B62, 0x694B, 0xA734, 0x8525, 0x441E, 0xC316, 0x220F, 0xCC80, 0xEB61, 0x2A4B, 0x6734, 0x6625, 0x241E, 0xA316, 0x020F, + 0xCC80, 0xCC69, 0x0A4B, 0x483C, 0x462D, 0x041E, 0x8316, 0x020F, 0xAC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC51D, 0x6316, 0xE216, + 0xAC88, 0x8C71, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x441E, 0xC316, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xC316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0x241E, 0xA316, 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x041E, 0x8316, + 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xE51D, 0x6316, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x6416, + 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0xA525, 0x441E, 0x4C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x241E, + 0x4C90, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0x041E, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x4625, 0xE41D, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xE51D, 0x4B98, 0xAC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xC525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x8525, + 0x2B98, 0x8C88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xC734, 0x6625, 0x2BA0, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0xA734, 0x4625, + 0x0A53, 0xC734, 0xE41D, 0xA316, 0x020F, 0x420F, 0x610F, 0x810F, 0xCA52, 0x8734, 0xC525, 0x8316, 0xE20E, 0x220F, 0x610F, 0x810F, + 0x8B5A, 0x483C, 0xA525, 0x6316, 0xE216, 0x220F, 0x610F, 0x810F, 0x4B5A, 0x083C, 0x6625, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, + 0x0B62, 0xA943, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0xCB69, 0x6943, 0xE72C, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x610F, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x6416, 0xC316, 0x220F, 0x410F, 0x6C71, 0xEA52, 0x6834, 0x6525, 0x241E, 0xA316, 0x020F, 0x420F, + 0x4C71, 0xAA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE20E, 0x420F, 0x2C79, 0x6B5A, 0xE83B, 0x062D, 0xE51D, 0x6316, 0xE316, 0x220F, + 0x0C79, 0x4B5A, 0xA943, 0xC72C, 0xC525, 0x441E, 0xC316, 0x220F, 0xEC78, 0x0B62, 0x6943, 0xA734, 0x8525, 0x241E, 0xA316, 0x020F, + 0xCC80, 0xEB61, 0x294B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE20E, 0xCC80, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xE51D, 0x6316, 0xE316, + 0xAC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x6416, 0xC316, 0xAC88, 0x8C69, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x441E, 0xA316, + 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xA316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0x8316, + 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xE51D, 0x6316, 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE62C, 0xA525, 0x441E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0x083C, 0xC72C, 0x8525, 0x241E, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x6525, 0x041E, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xC943, 0x8734, 0x4625, 0xE41D, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x462D, 0xE51D, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x4834, 0x262D, 0xC525, + 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x283C, 0x062D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0x0A4B, 0xE843, 0xA734, 0x4625, + 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x462D, 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, + 0xCA52, 0x8734, 0xC51D, 0x8316, 0xE20E, 0x220F, 0x410F, 0x610F, 0xAA52, 0x6834, 0xA525, 0x6416, 0xE316, 0x220F, 0x420F, 0x610F, + 0x6B5A, 0x283C, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x2B62, 0xC843, 0x462D, 0x241E, 0xA316, 0x020F, 0x420F, 0x610F, + 0xEB61, 0x8943, 0x062D, 0xE41D, 0x8316, 0xE20E, 0x220F, 0x410F, 0xAC69, 0x494B, 0xC734, 0xC525, 0x6416, 0xC316, 0x220F, 0x420F, + 0x8C69, 0x0A53, 0x6734, 0x8525, 0x441E, 0xA316, 0x020F, 0x420F, 0x4C71, 0xAA52, 0x283C, 0x4625, 0x041E, 0x8316, 0xE20E, 0x220F, + 0x2C71, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x6316, 0xC316, 0x220F, 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xC525, 0x441E, 0xC316, 0x020F, + 0xEC78, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0xE20E, 0xEC80, 0xEB61, 0x494B, 0x6734, 0x6625, 0x041E, 0x8316, 0xE216, + 0xCC80, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xE51D, 0x6316, 0xC316, 0xAC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xAC88, 0x8C69, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0xA316, 0x8C88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xE41D, 0x6316, 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC51D, 0x441E, + 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE62C, 0xA525, 0x241E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x041E, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xE41D, + 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC51D, 0x4C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xC525, + 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x6943, 0x483C, 0x062D, 0xA525, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, + 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC843, 0x8734, 0x462D, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x8734, 0x262D, + 0x2BA0, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x6834, 0x062D, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, + 0xAA52, 0x6734, 0xA525, 0x6316, 0xE316, 0x220F, 0x420F, 0x610F, 0x8B5A, 0x283C, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, + 0x4B5A, 0x083C, 0x4625, 0x241E, 0xA316, 0x020F, 0x220F, 0x410F, 0x0B62, 0xA943, 0x062D, 0x041E, 0x8316, 0xE20E, 0x220F, 0x420F, + 0xCB69, 0x694B, 0xC72C, 0xC51D, 0x6316, 0xC316, 0x020F, 0x420F, 0xAC69, 0x2A4B, 0x8734, 0xA525, 0x441E, 0xA316, 0x020F, 0x220F, + 0x6C71, 0xCA52, 0x483C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x4C71, 0x8A5A, 0x083C, 0x262D, 0xE41D, 0x6316, 0xC316, 0x020F, + 0x2C79, 0x6B5A, 0xC943, 0xE72C, 0xC525, 0x441E, 0xC316, 0x020F, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0xE20E, + 0xEC78, 0x0B62, 0x494B, 0x8734, 0x6625, 0x041E, 0x8316, 0xC316, 0xCC80, 0xCB69, 0x2A4B, 0x483C, 0x462D, 0xE51D, 0x6416, 0xC316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xAC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x8316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x6416, + 0x8C88, 0x2C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC525, 0x441E, 0x6C88, 0x2C79, 0x2B62, 0x294B, 0x283C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6525, 0x041E, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, + 0x4C90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0xA525, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x8C88, 0x2C71, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, + 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xE72C, 0x2BA0, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x494B, 0x283C, 0xC734, + 0x8A5A, 0x483C, 0x8525, 0x441E, 0xC316, 0x020F, 0x220F, 0x410F, 0x4B5A, 0x083C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, + 0x2B62, 0xC943, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, 0xEB61, 0x8943, 0xE72C, 0xE51D, 0x6316, 0xC316, 0x020F, 0x420F, + 0xAC69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, 0x220F, 0x8C69, 0xEA52, 0x6734, 0x6525, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x4C71, 0xAA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xC316, 0x020F, 0x2C79, 0x6B5A, 0xC843, 0x062D, 0xC525, 0x441E, 0xA316, 0x020F, + 0x0C79, 0x2B5A, 0x8943, 0xC734, 0xA525, 0x241E, 0xA316, 0xE216, 0xEC78, 0x0B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x8316, 0xC316, + 0xCC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0xE51D, 0x6416, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xAC80, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x241E, 0x8316, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x6316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x6625, 0xE51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, + 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0x8525, + 0x4B90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x8C88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x4834, 0xE62C, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x283C, 0xC734, + 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x6B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x4B5A, 0xE83B, 0x462D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, + 0x0B62, 0xA943, 0x062D, 0xE41D, 0x8316, 0xC316, 0x020F, 0x220F, 0xCB69, 0x694B, 0xC734, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, + 0xAC69, 0x0A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE20E, 0x220F, 0x6C71, 0xCA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x4C71, 0x8A5A, 0x083C, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, 0x2C79, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, + 0x0C79, 0x2B62, 0x6943, 0xA734, 0x8525, 0x041E, 0x8316, 0xC316, 0xEC80, 0xEB61, 0x294B, 0x6834, 0x462D, 0xE51D, 0x6416, 0xA316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x441E, 0xA316, 0xAC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, + 0xAC88, 0x8C71, 0xAA52, 0xC943, 0xA734, 0x6525, 0x041E, 0x6416, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x494B, 0x283C, 0x062D, 0xA525, 0x041E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x8525, 0xE41D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x6625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6625, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x4B98, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, + 0x2BA0, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0xA734, + 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x4B5A, 0x083C, 0x4625, 0x241E, 0x8316, 0xE216, 0x020F, 0x220F, 0x2B62, 0xC943, 0x262D, 0xE41D, 0x8316, 0xC316, 0x020F, 0x220F, + 0xEB61, 0x8943, 0xE72C, 0xC51D, 0x6416, 0xC316, 0x020F, 0x220F, 0xCC69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x8C69, 0xEA52, 0x6734, 0x6625, 0x241E, 0x8316, 0xE316, 0x020F, 0x6C71, 0xAA52, 0x283C, 0x262D, 0xE41D, 0x6316, 0xC316, 0x020F, + 0x2C71, 0x6B5A, 0xC843, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE216, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0x0B62, 0x494B, 0x6734, 0x6625, 0xE41D, 0x6416, 0xA316, 0xCC80, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0x041E, 0x6316, + 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE41D, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xC525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, 0x4C90, 0xCC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4B98, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x294B, 0xE83B, 0x8734, 0x2BA0, 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0xA943, 0x483C, + 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, 0x220F, 0x0B62, 0xA943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, + 0xEB61, 0x694B, 0xC734, 0xC525, 0x441E, 0xA316, 0xE20E, 0x220F, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE316, 0x020F, + 0x8C71, 0xEA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0x020F, 0x4C71, 0x8A5A, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE20E, + 0x2C79, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x2B62, 0x6943, 0x8734, 0x6625, 0x041E, 0x6316, 0xC316, + 0xEC80, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xE51D, 0x441E, 0xA316, 0xCC80, 0xCB69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xCC80, 0x8C69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x6316, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE41D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, + 0x6C90, 0xCC80, 0xAC69, 0x8B5A, 0x8943, 0x483C, 0xE62C, 0x8525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, + 0x4B90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x4834, 0xE62C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xA734, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x6C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x283C, + 0x2B62, 0xC943, 0x062D, 0xE51D, 0x6316, 0xC316, 0xE20E, 0x220F, 0x0B62, 0x8943, 0xE72C, 0xC525, 0x441E, 0xA316, 0xE20E, 0x020F, + 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE316, 0x020F, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE20E, 0x4C71, 0x8B5A, 0xE83B, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE316, + 0x2C79, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE51D, 0x6416, 0xA316, + 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x441E, 0x8316, 0xCC80, 0xAC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x241E, 0x6316, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE41D, 0x441E, 0xAC88, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x4834, 0x062D, 0xA525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, + 0x6C88, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0xA734, 0x462D, 0xC525, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x6625, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xA734, 0x462D, + 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x4834, 0xE72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC72C, + 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x083C, 0x2AA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0x083C, + 0x2B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xA316, 0xE216, 0x020F, 0xEB61, 0x694B, 0xC734, 0xA525, 0x441E, 0xA316, 0xE316, 0x020F, + 0xCB69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE316, 0x2C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x2B62, 0x8943, 0xA734, 0x6625, 0x041E, 0x6416, 0xA316, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, + 0xCC80, 0xCB69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0x8C69, 0xCA52, 0xE843, 0xC734, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, 0xAC88, 0x4C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x241E, + 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x462D, 0xC525, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0x062D, 0x8525, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x4B90, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0x083C, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0x2BA0, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, 0x2AA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, + 0x0B62, 0x8943, 0xE72C, 0xC525, 0x441E, 0xA316, 0xE316, 0x020F, 0xEB61, 0x494B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, + 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, 0x8C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, + 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x2C79, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, 0xC316, + 0x0C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0xE51D, 0x441E, 0xA316, 0xEC80, 0xEB61, 0x2A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, + 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xCC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0x083C, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x6734, 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x4834, + 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE843, 0x2AA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x0B62, 0x6943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xCB69, 0x294B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, + 0xAC69, 0x0A4B, 0x6834, 0x4625, 0x041E, 0x6416, 0xA316, 0xE216, 0x6C71, 0xCA52, 0x083C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xC316, + 0x4C71, 0x8B5A, 0xC843, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, + 0x0C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x8316, 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x441E, 0xAC80, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6525, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x283C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x6734, + 0x2B98, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, + 0x2BA0, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0xEB61, 0x694B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xCB69, 0x2A4B, 0x8734, 0x6625, 0x041E, 0x6316, 0xA316, 0xE216, + 0xAC69, 0xEA52, 0x483C, 0x462D, 0xE51D, 0x6416, 0xA316, 0xC316, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, + 0x4C71, 0x6B5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6316, 0xA316, 0x2C79, 0x2B62, 0x6943, 0x8734, 0x6625, 0xE51D, 0x441E, 0xA316, + 0x0C79, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xEC80, 0xCB69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0xAC88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x6625, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x294B, 0x083C, 0xA734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xE843, 0x8734, 0x062D, + 0x4B90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0xE62C, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, + 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2AA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0x0A53, 0x8943, + 0xEB61, 0x494B, 0x8734, 0x8525, 0x041E, 0x6316, 0xA316, 0xE316, 0xAC69, 0x0A4B, 0x6834, 0x4625, 0xE41D, 0x6416, 0xA316, 0xC316, + 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x6C71, 0x8A5A, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x4C71, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, 0x0C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x8316, + 0xEC78, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A52, 0x494B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x294B, 0xE83B, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x4C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2AA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2AA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0xEB61, 0x294B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xC316, 0xAC69, 0x0A53, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xC316, + 0x8C69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0x8316, 0xC316, 0x6C71, 0x8B5A, 0xC843, 0xE72C, 0xA525, 0x041E, 0x6316, 0xA316, + 0x2C71, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x8316, + 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC88, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x8C88, 0x0C79, 0xCB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0x8525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, + 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x694B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0x0A53, 0x8943, + 0x2AA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2AA0, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0xCB69, 0x2A4B, 0x6734, 0x4625, 0xE41D, 0x441E, 0xA316, 0xC316, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0x8C69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, 0xA316, 0x4C71, 0x6B5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x0C79, 0x0B62, 0x294B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, + 0xEC78, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x441E, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE41D, + 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x4C90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0xE62C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2AA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0xCB69, 0x0A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xA316, + 0x8C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x6316, 0xA316, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x441E, 0x8316, + 0x2C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC51D, 0x441E, 0x8316, 0x0C79, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xE72C, 0x8525, 0xE41D, 0x441E, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0xA525, 0x041E, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0xC525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C88, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x294B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, 0x4C90, 0xAC88, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, + 0x2AA0, 0x4B90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x294B, + 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xA316, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, + 0x6C71, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0xA316, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C79, 0x2B62, 0x494B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6316, 0x0C79, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0xEC80, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE83B, 0xA734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C88, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0xE62C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC734, 0x4B90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x283C, 0xA734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A52, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x494B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0xCB69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x6316, 0xA316, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x6416, 0xA316, + 0x6C71, 0x8A5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0x2C79, 0x0B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6416, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, + 0xEC80, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x4625, 0xC51D, 0x241E, 0xCC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xAC88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x4B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xE843, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2AA0, 0x4B98, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0xCB69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x8C69, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0x8316, + 0x6C71, 0x8B5A, 0xC943, 0xC734, 0x6525, 0xE41D, 0x441E, 0x8316, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x2C79, 0x0B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x041E, 0x6416, 0x0C79, 0xCB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, + 0xEC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x6C71, 0x6B5A, 0x8943, 0x6834, 0x062D, 0xA525, 0x041E, + 0xAC80, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0xAC88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC72C, + 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4B90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A4B, + 0xCC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0x8316, 0x8C69, 0xAA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x441E, 0x8316, + 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6416, + 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, + 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x041E, 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE51D, + 0xAC80, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC525, 0xAC88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCC69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x294B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x441E, 0x8316, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, + 0x6C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, 0x4C71, 0x2B62, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x6416, + 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x441E, 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, + 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, + 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0xAC88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6834, 0x062D, 0x6525, 0x8C88, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, 0x4625, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x294B, 0xE83B, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xA734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x8C69, 0x8A5A, 0xC943, 0xC734, 0x6625, 0xE51D, 0x441E, 0x6316, + 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x041E, 0x441E, + 0x2C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, 0x0C79, 0xCB69, 0xCA52, 0xC843, 0xA734, 0x4625, 0xC525, 0x241E, + 0xEC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, + 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, 0xAC88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, + 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x6834, 0xE72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC734, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, 0x8316, 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, + 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0x041E, 0x441E, + 0x2C79, 0xEB61, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x241E, 0x0C79, 0xCC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x041E, + 0xEC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x062D, 0x8525, 0xE41D, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC525, + 0xAC80, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4625, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x6C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x294B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xEA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0xAC69, 0xAA52, 0xE843, 0xC734, 0x6525, 0xE51D, 0x241E, 0x6316, 0x8C69, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xC525, 0x241E, 0x6416, + 0x6C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x2B62, 0x294B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, + 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0x0C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC80, 0x8C69, 0x8B5A, 0x6943, 0x4834, 0x062D, 0x8525, 0xE51D, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xAC80, 0x4C71, 0x0B62, 0x0A53, 0xE843, 0x8734, 0x262D, 0x8525, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x6625, + 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x6943, 0x283C, 0xC734, 0x462D, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xA734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2AA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B5A, 0xAA52, + 0xAC69, 0xAA52, 0xC943, 0xC734, 0x6625, 0xE51D, 0x241E, 0x6416, 0x8C69, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x6C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, + 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x4625, 0xC525, 0x241E, 0x0C79, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xCC80, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xC734, 0x462D, 0xA525, + 0xAC80, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, 0xAC88, 0x0C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x8C88, 0x0C79, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6834, 0xE72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, + 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xC525, 0x241E, 0x6416, 0x8C69, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xA525, 0x041E, 0x441E, + 0x6C71, 0x4B5A, 0x694B, 0x4834, 0x062D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, 0x241E, + 0x2C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x462D, 0xC525, 0x041E, 0x0C79, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0xE41D, + 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6625, 0xC525, 0xCC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0xAC80, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x8525, 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4625, + 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, + 0xAC69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xC525, 0x241E, 0x441E, 0x8C69, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x6C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x241E, 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, 0x241E, + 0x2C79, 0xEB61, 0xCA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x041E, 0x0C79, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, 0xE51D, + 0xEC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC525, 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, + 0xAC80, 0x2C71, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x6525, 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, 0x462D, + 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0xA734, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0x8A52, 0x494B, 0xE83B, 0x8734, 0x6C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x294B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C88, 0xCC80, 0x2C79, 0xAC69, 0x0B62, 0x8A5A, + 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x041E, 0x441E, 0x8C69, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x6C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE51D, 0x241E, 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC525, 0x041E, + 0x2C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x041E, 0x0C79, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, + 0xEC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x4625, 0xC525, 0xCC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x8525, + 0xAC80, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0xE62C, 0x6625, 0xAC88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x062D, 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x6C88, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC734, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, 0x6C90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x483C, + 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4C90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x6C71, 0x0B62, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52, + 0x2BA0, 0x4B98, 0x6C88, 0xCC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x2AA0, 0x4B98, 0x6C90, 0xCC80, 0x2C79, 0x8C69, 0x0B62, 0x8B5A, + 0xC843, 0x8525, 0x8316, 0x020F, 0x610F, 0x8107, 0xAA52, 0xAA52, 0x8943, 0x4625, 0x6416, 0x020F, 0x410F, 0x8107, 0xAA52, 0xAA52, + 0x494B, 0x262D, 0x441E, 0xE216, 0x420F, 0x8107, 0xAA52, 0xAA52, 0x0A4B, 0xE72C, 0x041E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xAA52, + 0xCA52, 0x8734, 0xE51D, 0xA316, 0x220F, 0x810F, 0xAA52, 0xAA52, 0x8B5A, 0x483C, 0xA525, 0x8316, 0x020F, 0x610F, 0xAA52, 0xAA52, + 0x4B5A, 0x083C, 0x6625, 0x6416, 0xE20E, 0x610F, 0xAA52, 0xAA52, 0x0B62, 0xA943, 0x262D, 0x241E, 0xC316, 0x420F, 0xAA52, 0xAA52, + 0xCB69, 0x6943, 0xE62C, 0x041E, 0xA316, 0x220F, 0xAA52, 0xAA52, 0xAC69, 0x2A4B, 0xA734, 0xC51D, 0x8316, 0x220F, 0xAA52, 0xAA52, + 0x6C71, 0x0A53, 0x8734, 0xA525, 0x6316, 0x020F, 0xAA52, 0xAA52, 0x4C71, 0xCA52, 0x483C, 0x6525, 0x441E, 0xE20E, 0xAA52, 0xAA52, + 0x2C71, 0x8A5A, 0x083C, 0x462D, 0x241E, 0xC316, 0xAA52, 0xAA52, 0x0C79, 0x6B5A, 0xC843, 0x062D, 0x041E, 0xC316, 0xAA52, 0xAA52, + 0x0C79, 0x2B5A, 0xA943, 0xE72C, 0xE51D, 0xA316, 0x8107, 0xAA52, 0xEC78, 0x0B62, 0x6943, 0xA734, 0xA525, 0x8316, 0x610F, 0xAA52, + 0xCC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x6416, 0x220F, 0xAA52, 0xCC80, 0xCB69, 0x0A4B, 0x4834, 0x6625, 0x441E, 0x020F, 0xAA52, + 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x462D, 0x241E, 0xE20E, 0xAA52, 0xAC88, 0x8C69, 0xCA52, 0x083C, 0x062D, 0x041E, 0xC316, 0xAA52, + 0x8C88, 0x6C71, 0xAA52, 0xC843, 0xE62C, 0xC51D, 0xA316, 0xAA52, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0xA525, 0x8316, 0xAA52, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x6316, 0xAA52, 0x6C88, 0x2C71, 0x4B5A, 0x694B, 0x8734, 0x6625, 0x441E, 0xAA52, + 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x462D, 0x241E, 0xC007, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0x262D, 0x041E, 0x020F, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0x083C, 0x062D, 0xE51D, 0xE316, 0x4C90, 0xEC78, 0xCB69, 0xCA52, 0xE83B, 0xE72C, 0xC525, 0xA316, + 0x4C90, 0xEC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0xA525, 0x8316, 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6525, 0x441E, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x4625, 0x241E, 0x4B98, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x262D, 0x041E, + 0xA943, 0x6625, 0x6316, 0x020F, 0x420F, 0x810F, 0xA107, 0xAA52, 0x694B, 0x262D, 0x441E, 0xE216, 0x420F, 0x810F, 0xA107, 0xAA52, + 0x2A4B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0xA107, 0xAA52, 0xEA52, 0xA734, 0xE41D, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0xAA52, 0x6734, 0xC525, 0x8316, 0x020F, 0x610F, 0xA107, 0xAA52, 0x6B5A, 0x283C, 0x8525, 0x6416, 0xE20E, 0x420F, 0xA107, 0xAA52, + 0x2B62, 0xE843, 0x462D, 0x441E, 0xC316, 0x220F, 0x8107, 0xAA52, 0xEB61, 0x8943, 0x062D, 0x041E, 0xA316, 0x220F, 0x810F, 0xAA52, + 0xAC69, 0x494B, 0xC734, 0xC51D, 0x8316, 0x020F, 0x810F, 0xAA52, 0x8C69, 0x0A4B, 0x8734, 0xA525, 0x6316, 0xE20E, 0x610F, 0xAA52, + 0x6C71, 0xCA52, 0x483C, 0x6525, 0x441E, 0xE316, 0x610F, 0xAA52, 0x4C71, 0xAA52, 0x283C, 0x462D, 0x241E, 0xC316, 0x420F, 0xAA52, + 0x2C79, 0x6B5A, 0xE83B, 0x062D, 0x041E, 0xA316, 0x220F, 0xAA52, 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xC51D, 0x8316, 0x220F, 0xAA52, + 0xEC78, 0x2B62, 0x8943, 0xA734, 0xA525, 0x6416, 0x020F, 0xAA52, 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0xE20E, 0xAA52, + 0xCC80, 0xCB69, 0x2A4B, 0x4834, 0x6625, 0x241E, 0xC316, 0xAA52, 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x462D, 0x041E, 0xC316, 0xAA52, + 0xAC80, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xE51D, 0xA316, 0xAA52, 0xAC88, 0x8C71, 0xAA52, 0xE843, 0xE62C, 0xC525, 0x8316, 0xA107, + 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0xA525, 0x6416, 0x420F, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x441E, 0x220F, + 0x6C88, 0x2C71, 0x4B5A, 0x694B, 0x8734, 0x6625, 0x241E, 0x020F, 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x462D, 0x041E, 0xE316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x262D, 0xE51D, 0xA316, 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xC525, 0x8316, + 0x4C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0xA525, 0x6316, 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x441E, + 0x4B98, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x241E, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x462D, 0x041E, + 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xE51D, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xC525, + 0x8943, 0x462D, 0x441E, 0xE216, 0x420F, 0x610F, 0xA107, 0xAA52, 0x494B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0x8107, 0xAA52, + 0x0A4B, 0xE72C, 0x041E, 0xA316, 0x220F, 0x610F, 0x8107, 0xAA52, 0xCA52, 0x8734, 0xC51D, 0x8316, 0x020F, 0x420F, 0x810F, 0xAA52, + 0x8B5A, 0x483C, 0xA525, 0x6316, 0xE20E, 0x420F, 0x810F, 0xAA52, 0x4B5A, 0x083C, 0x6625, 0x441E, 0xC316, 0x220F, 0x610F, 0xAA52, + 0x0B62, 0xA943, 0x262D, 0x241E, 0xA316, 0x220F, 0x610F, 0xAA52, 0xCB69, 0x694B, 0xE72C, 0xE51D, 0x8316, 0x020F, 0x610F, 0xAA52, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x6316, 0xE20E, 0x420F, 0xAA52, 0x6C71, 0xEA52, 0x6734, 0x8525, 0x441E, 0xC316, 0x420F, 0xC007, + 0x4C71, 0xAA52, 0x283C, 0x4625, 0x241E, 0xA316, 0x220F, 0xA107, 0x2C71, 0x8B5A, 0xE83B, 0x262D, 0x041E, 0xA316, 0x020F, 0xA107, + 0x0C79, 0x4B5A, 0xC943, 0xE62C, 0xC51D, 0x8316, 0x020F, 0x8107, 0x0C79, 0x2B62, 0x8943, 0xC734, 0xA525, 0x6416, 0xE216, 0x610F, + 0xEC80, 0x0B62, 0x694B, 0x8734, 0x8525, 0x441E, 0xC316, 0x610F, 0xCC80, 0xEB61, 0x2A4B, 0x6734, 0x6625, 0x241E, 0xC316, 0x420F, + 0xCC80, 0xCC69, 0x0A53, 0x283C, 0x262D, 0x041E, 0xA316, 0x220F, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xE51D, 0x8316, 0x220F, + 0xAC88, 0x8C69, 0xAA52, 0xE83B, 0xE72C, 0xC525, 0x6416, 0x020F, 0x8C88, 0x6C71, 0x8A5A, 0xA943, 0xC734, 0xA525, 0x441E, 0xE20E, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6525, 0x241E, 0xC316, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x041E, 0xC316, + 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xE41D, 0xA316, 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xE51D, 0x8316, + 0x6C90, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0xC525, 0x6316, 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC72C, 0xA525, 0x441E, + 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x241E, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x041E, + 0x4B98, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x462D, 0x041E, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xE51D, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0x062D, 0xC525, 0x2B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xE72C, 0xA525, + 0x694B, 0x262D, 0x241E, 0xC316, 0x220F, 0x410F, 0x810F, 0xA107, 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, 0xA107, + 0xEA52, 0xA734, 0xE51D, 0xA316, 0x020F, 0x420F, 0x610F, 0xA107, 0xAA52, 0x6834, 0xA525, 0x6316, 0xE20E, 0x220F, 0x610F, 0x8107, + 0x4B5A, 0x083C, 0x6525, 0x441E, 0xC316, 0x220F, 0x610F, 0x8107, 0x2B62, 0xC943, 0x262D, 0x241E, 0xA316, 0x020F, 0x410F, 0x810F, + 0xEB61, 0x8943, 0xE62C, 0xE41D, 0x8316, 0x020F, 0x420F, 0x810F, 0xAC69, 0x494B, 0xA734, 0xC525, 0x6316, 0xE316, 0x220F, 0x610F, + 0x8C71, 0x0A53, 0x6734, 0x8525, 0x441E, 0xC316, 0x220F, 0x610F, 0x6C71, 0xCA52, 0x283C, 0x4625, 0x241E, 0xA316, 0x020F, 0x610F, + 0x2C71, 0x8A5A, 0x083C, 0x262D, 0x041E, 0x8316, 0xE20E, 0x420F, 0x2C79, 0x6B5A, 0xC943, 0xE62C, 0xC51D, 0x6316, 0xE216, 0x420F, + 0x0C79, 0x2B62, 0x8943, 0xC734, 0xA525, 0x441E, 0xC316, 0x220F, 0xEC78, 0x0B62, 0x694B, 0x8734, 0x8525, 0x241E, 0xA316, 0x220F, + 0xCC80, 0xEB61, 0x2A4B, 0x6834, 0x4625, 0x041E, 0xA316, 0x020F, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xE51D, 0x8316, 0xE20E, + 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x6416, 0xE316, 0xAC88, 0x8C69, 0xAA52, 0xE843, 0xE72C, 0xA525, 0x441E, 0xC316, + 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xA316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0xA316, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xE41D, 0x8316, 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC51D, 0x6316, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0xA525, 0x441E, + 0x6C90, 0xEC78, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x241E, 0x4C90, 0xEC80, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6625, 0x041E, + 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xE51D, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x262D, 0xC51D, + 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xC525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0x083C, 0xC72C, 0x8525, 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x6625, + 0x2A4B, 0xE62C, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0x8107, 0xEA52, 0xC734, 0xE51D, 0x8316, 0x020F, 0x420F, 0x610F, 0x810F, + 0xCA52, 0x8734, 0xC525, 0x8316, 0xE20E, 0x220F, 0x610F, 0x810F, 0x6B5A, 0x283C, 0x8525, 0x441E, 0xC316, 0x220F, 0x410F, 0x810F, + 0x2B5A, 0xE83B, 0x4625, 0x241E, 0xA316, 0x020F, 0x420F, 0x610F, 0x0B62, 0xA943, 0x062D, 0x041E, 0x8316, 0xE20E, 0x420F, 0x610F, + 0xCB69, 0x694B, 0xC734, 0xC525, 0x6316, 0xE316, 0x220F, 0x610F, 0x8C69, 0x0A4B, 0x8734, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, + 0x6C71, 0xCA52, 0x483C, 0x6625, 0x241E, 0xA316, 0x020F, 0x420F, 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, + 0x2C79, 0x6B5A, 0xC943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x220F, 0x0C79, 0x4B5A, 0xA943, 0xC734, 0xA525, 0x441E, 0xC316, 0x020F, + 0xEC78, 0x0B62, 0x694B, 0x8734, 0x8525, 0x241E, 0xA316, 0x020F, 0xCC80, 0xEB61, 0x2A4B, 0x6834, 0x4625, 0x041E, 0x8316, 0xE216, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xE51D, 0x6316, 0xC316, 0xAC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xC316, + 0xAC88, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x241E, 0xA316, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x8316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0x041E, 0x8316, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xE51D, 0x6416, + 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xC525, 0x441E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x283C, 0xE62C, 0xA525, 0x241E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC72C, 0x8525, 0x241E, 0x6C90, 0xEC78, 0xCB61, 0xCA52, 0xC843, 0xA734, 0x6625, 0x041E, + 0x4C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x4625, 0xE51D, 0x4C90, 0xCC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x262D, 0xC51D, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0xA525, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE62C, 0xA525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xE72C, 0x8525, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x2A4B, 0xE83B, 0xC734, 0x6625, + 0x2B98, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0xA734, 0x4625, 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, + 0x0A4B, 0xC734, 0xE41D, 0x8316, 0xE20E, 0x220F, 0x610F, 0x610F, 0xCA52, 0x8734, 0xC525, 0x8316, 0xE216, 0x220F, 0x410F, 0x610F, + 0x8A5A, 0x4834, 0xA525, 0x6416, 0xC316, 0x220F, 0x420F, 0x610F, 0x4B5A, 0x083C, 0x6625, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, + 0x0B62, 0xC943, 0x262D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x610F, 0xEB61, 0x6943, 0xE72C, 0xE51D, 0x8316, 0xE316, 0x220F, 0x410F, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x441E, 0xC316, 0x020F, 0x420F, 0x6C71, 0xEA52, 0x4834, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, + 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, 0x2C79, 0x6B5A, 0xE843, 0x062D, 0xC51D, 0x6416, 0xC316, 0x020F, + 0x0C79, 0x4B5A, 0xA943, 0xC734, 0xA525, 0x441E, 0xA316, 0x020F, 0xEC78, 0x2B62, 0x6943, 0x8734, 0x8525, 0x241E, 0x8316, 0xE20E, + 0xEC80, 0xEB61, 0x2A4B, 0x6834, 0x4625, 0x041E, 0x6316, 0xC316, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC51D, 0x6416, 0xC316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x441E, 0xA316, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x241E, 0x8316, + 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x8316, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x6416, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC525, 0x441E, 0x8C88, 0x2C79, 0x2B62, 0x294B, 0x283C, 0x062D, 0xA525, 0x241E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x241E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6525, 0x041E, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, 0x6C90, 0xEC80, 0xCC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC51D, + 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x4B90, 0xCC80, 0x8C69, 0x8B5A, 0x694B, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xCC80, 0x8C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, + 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xC943, 0x8734, 0x262D, + 0x2B98, 0x8C88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x262D, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x6834, 0x062D, + 0xEA52, 0xA734, 0xC51D, 0x8316, 0xE216, 0x220F, 0x420F, 0x610F, 0xAA52, 0x6734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, 0x610F, + 0x6B5A, 0x283C, 0x6525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x2B62, 0xE83B, 0x462D, 0x041E, 0xA316, 0xE20E, 0x220F, 0x410F, + 0xEB61, 0x8943, 0x062D, 0xE51D, 0x8316, 0xE316, 0x220F, 0x420F, 0xCB69, 0x494B, 0xC734, 0xA525, 0x6416, 0xC316, 0x020F, 0x420F, + 0x8C69, 0x0A4B, 0x6734, 0x8525, 0x241E, 0xA316, 0xE20E, 0x220F, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE316, 0x220F, + 0x4C71, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, 0x2C79, 0x4B5A, 0xA943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE20E, + 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0xE216, 0xEC78, 0x0B62, 0x494B, 0x6734, 0x4625, 0x041E, 0x6316, 0xC316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0xA316, + 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0x8525, 0x241E, 0x8316, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x6316, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xE51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x4834, 0x262D, 0xC525, 0x441E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x6625, 0xE51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC51D, + 0x6C90, 0xEC80, 0xCC69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xC525, 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x4834, 0x062D, 0xA525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE62C, 0x8525, 0x4B98, 0xCC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xC72C, 0x6625, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x4625, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE843, 0xA734, 0x462D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x2B98, 0x8C88, 0x2C71, 0x0B62, 0xCA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, + 0xCA52, 0x6734, 0xA525, 0x6416, 0xC316, 0x020F, 0x220F, 0x410F, 0x8B5A, 0x483C, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, 0x420F, + 0x4B5A, 0x083C, 0x4625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x0B62, 0xA943, 0x062D, 0xE41D, 0x8316, 0xE316, 0x020F, 0x420F, + 0xEB61, 0x694B, 0xC72C, 0xC525, 0x6416, 0xC316, 0x020F, 0x220F, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0x6C71, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xE316, 0x020F, 0x4C71, 0xAA52, 0x083C, 0x062D, 0xE51D, 0x6416, 0xC316, 0x020F, + 0x2C79, 0x6B5A, 0xC943, 0xE72C, 0xA525, 0x441E, 0xA316, 0xE20E, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, + 0xEC78, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE41D, 0x6316, 0xC316, 0xCC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x8316, 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0x041E, 0x6316, + 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xE41D, 0x6416, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6525, 0xE41D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x4625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0xA525, + 0x4C90, 0xCC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6625, + 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4B98, 0xAC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2B98, 0x8C88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE62C, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC72C, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x694B, 0x283C, 0xC734, 0x2BA0, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, + 0xAA52, 0x483C, 0x8525, 0x441E, 0xA316, 0x020F, 0x220F, 0x420F, 0x6B5A, 0x083C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, + 0x2B5A, 0xE843, 0x262D, 0x041E, 0x8316, 0xE316, 0x020F, 0x420F, 0xEB61, 0x8943, 0xE62C, 0xC51D, 0x6316, 0xC316, 0x020F, 0x220F, + 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x8C69, 0x0A4B, 0x6734, 0x6625, 0x241E, 0x8316, 0xE316, 0x020F, + 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE41D, 0x6316, 0xC316, 0x020F, 0x2C71, 0x8B5A, 0xE843, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE20E, + 0x0C79, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x0B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x6316, 0xC316, + 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0xA316, 0xCC80, 0xCB69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xAC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x6316, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x6416, + 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x441E, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x4625, 0xC51D, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, 0x4C90, 0xCC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, + 0x4B98, 0xAC80, 0x6C71, 0x2B5A, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x8734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x8C88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, + 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, + 0x8B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0xE216, 0x220F, 0x420F, 0x4B5A, 0xE83B, 0x462D, 0x041E, 0x8316, 0xE316, 0x020F, 0x220F, + 0x2B62, 0xC943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xEB61, 0x6943, 0xC734, 0xC525, 0x441E, 0xA316, 0xE20E, 0x220F, + 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xE316, 0x020F, 0x8C71, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x4C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE20E, 0x2C79, 0x6B5A, 0xA943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x2B62, 0x6943, 0x8734, 0x6525, 0x041E, 0x6316, 0xC316, 0xEC78, 0x0B62, 0x494B, 0x6834, 0x462D, 0xE51D, 0x441E, 0xA316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xC525, 0x241E, 0x8316, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6316, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE41D, 0x441E, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x4834, 0x062D, 0xA525, 0x241E, 0x8C88, 0x2C71, 0x2B62, 0x294B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x462D, 0xC525, + 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x283C, 0xE72C, 0x6525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x6625, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x462D, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x4834, 0xE72C, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x2B98, 0x8C88, 0x2C79, 0xCB61, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, + 0x2BA0, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, 0x2BA0, 0x6C90, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xA943, 0x4834, + 0x6B5A, 0x083C, 0x4625, 0x041E, 0x8316, 0xE316, 0x020F, 0x220F, 0x2B5A, 0xC843, 0x262D, 0xE41D, 0x8316, 0xC316, 0x020F, 0x220F, + 0x0B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0xE20E, 0x220F, 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, + 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0x020F, 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE20E, + 0x4C71, 0x8B5A, 0xE83B, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE316, 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x041E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x494B, 0x6734, 0x4625, 0xE51D, 0x6416, 0xA316, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x8316, + 0xCC80, 0xCC69, 0xEA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x6316, 0xCC80, 0x8C69, 0xAA52, 0xC843, 0xC734, 0x6525, 0x041E, 0x6416, + 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC51D, 0x441E, 0x8C88, 0x4C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xA525, 0x241E, + 0x8C88, 0x4C71, 0x2B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, + 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0x083C, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2BA0, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6734, + 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, 0x220F, 0x2B62, 0xA943, 0x062D, 0xE51D, 0x6416, 0xC316, 0xE20E, 0x220F, + 0xEB61, 0x8943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, 0xCC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, + 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x6316, 0xC316, 0xE20E, 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE216, + 0x2C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x0C79, 0x2B62, 0x6943, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, + 0xEC78, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC51D, 0x441E, 0x8316, 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x6416, 0xAC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, + 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0x041E, + 0x8C88, 0x2C79, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6525, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x4625, 0xC525, + 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0xE72C, 0x6525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4B90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B5A, 0xC843, 0x062D, 0xE51D, 0x6416, 0xA316, 0xE20E, 0x020F, 0x0B62, 0x8943, 0xE72C, 0xC525, 0x441E, 0xA316, 0xE216, 0x020F, + 0xEB61, 0x694B, 0xA734, 0xA525, 0x241E, 0x8316, 0xC316, 0x020F, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x8C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, 0x4C71, 0x8A5A, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x6316, 0xC316, 0x0C79, 0x0B62, 0x694B, 0x6734, 0x4625, 0xE51D, 0x441E, 0xA316, + 0xEC78, 0xEB61, 0x2A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xCC80, 0xCC69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE51D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0xC525, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC843, 0x8734, 0x062D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0xE62C, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xC943, 0x4834, + 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2B62, 0xC943, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE216, 0x020F, 0x0B62, 0x8943, 0xC734, 0xA525, 0x441E, 0x8316, 0xC316, 0x020F, + 0xCB69, 0x494B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xAC69, 0x0A53, 0x4834, 0x4625, 0x041E, 0x6416, 0xA316, 0xE216, + 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xC316, 0x4C71, 0x8B5A, 0xC943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C79, 0x4B5A, 0x8943, 0xA734, 0x6625, 0x041E, 0x6416, 0xA316, 0x0C79, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x441E, 0x8316, + 0xEC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x6525, 0xE41D, 0x441E, + 0xAC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC51D, 0x241E, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x462D, 0xA525, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x262D, + 0x4B90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0xE62C, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xCB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xC943, 0x483C, 0x2B98, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2BA0, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, + 0x2B62, 0xA943, 0xE72C, 0xC525, 0x441E, 0xA316, 0xC316, 0x020F, 0xEB61, 0x694B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, + 0xCB69, 0x2A4B, 0x8734, 0x6625, 0x041E, 0x6316, 0xC316, 0xE216, 0x8C69, 0xEA52, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xE316, + 0x6C71, 0xAA52, 0xE83B, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, 0xA316, + 0x0C79, 0x2B62, 0x6943, 0x8734, 0x4625, 0xE51D, 0x441E, 0xA316, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xA525, 0x241E, 0x8316, + 0xEC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, 0xAC88, 0x4C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x041E, + 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x6625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xC943, 0x483C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x0B62, 0x8943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xEB61, 0x494B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE216, + 0xCC69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x6416, 0xA316, 0xE316, 0x8C69, 0xCA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0x6C71, 0x8A5A, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C71, 0x4B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, + 0x0C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC51D, 0x441E, 0x8316, 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE41D, 0x441E, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC51D, 0x241E, + 0xAC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE41D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x6C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0xEC78, 0xAC69, 0x8A52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE72C, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x0B62, 0x6943, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE216, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xE316, + 0xAC69, 0x0A4B, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xC316, 0x8C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, + 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0x8525, 0x041E, 0x6316, 0xA316, 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0x0B62, 0x494B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xEC78, 0xCB69, 0x0A53, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x041E, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xC72C, 0x6625, 0xE51D, + 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xA525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0x8525, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC72C, 0x4625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x294B, 0x083C, 0xA734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x4C90, 0xAC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x4B90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x283C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, + 0x0B62, 0x694B, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, 0xE316, 0xCB69, 0x2A4B, 0x6734, 0x6625, 0xE41D, 0x6416, 0xA316, 0xC316, + 0xAC69, 0xEA52, 0x483C, 0x262D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xA316, + 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C79, 0x2B5A, 0x6943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, + 0x0C79, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x241E, 0x6316, 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, + 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6834, 0x062D, 0x8525, + 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x4B98, 0xAC88, 0x2C79, 0xCB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xC843, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xC316, 0xCB69, 0x0A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, + 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xC316, 0x6C71, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x041E, 0x6316, 0xA316, + 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE41D, 0x441E, 0x8316, 0x2C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC525, 0x241E, 0x8316, + 0x0C79, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC80, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC80, 0x6C71, 0x6B5A, 0x6943, 0x4834, 0x062D, 0x8525, 0x041E, + 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x062D, 0x8525, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x4625, 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x694B, + 0xEB61, 0x494B, 0x8734, 0x6625, 0xE41D, 0x441E, 0x8316, 0xC316, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0xAC69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x6C71, 0x8A5A, 0xC843, 0xC72C, 0x8525, 0x041E, 0x6416, 0xA316, + 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C79, 0x2B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, 0xEC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, + 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC525, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C88, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x6734, 0xE62C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC72C, + 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xCB61, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE843, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, + 0xEB61, 0x2A4B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, 0xCC69, 0xEA52, 0x283C, 0x262D, 0xC525, 0x241E, 0x8316, 0xA316, + 0x8C69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x241E, 0x6416, 0xA316, 0x6C71, 0x8B5A, 0xC943, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, + 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC51D, 0x241E, 0x8316, 0x0C79, 0x0B62, 0x294B, 0x483C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC78, 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, 0xCC80, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xCC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x041E, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0x083C, 0xA734, 0x462D, 0xC525, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2AA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xC51D, 0x441E, 0x8316, 0xA316, 0xAC69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, + 0x8C69, 0xAA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, 0x8316, 0x6C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C71, 0x4B5A, 0x694B, 0x6734, 0x262D, 0xC525, 0x241E, 0x6316, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, + 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x6943, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC80, 0x4C71, 0x4B5A, 0x294B, 0x283C, 0xC72C, 0x6625, 0xC525, + 0xAC88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x4C90, 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC734, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x294B, 0x2AA0, 0x4B90, 0x8C88, 0x0C79, 0x8C71, 0x0B62, 0xAA52, 0x2A4B, + 0xEB61, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, 0xA316, 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0xA316, + 0x8C69, 0xAA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x6C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C71, 0x2B62, 0x694B, 0x6834, 0x262D, 0xA525, 0x241E, 0x6416, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x441E, + 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0xCC80, 0x8C69, 0x8A52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xAC80, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x6525, + 0x8C88, 0x0C79, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xC72C, 0x4625, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE843, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x4C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0x8B5A, 0x0A4B, + 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x6416, 0xA316, 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x6416, 0x8316, + 0x8C69, 0xAA52, 0xC843, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x2C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x041E, 0x441E, 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, + 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x041E, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, + 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xA734, 0x4C90, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x8734, + 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A52, 0x494B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x6C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0x8316, 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x441E, 0x8316, + 0x8C69, 0x8A5A, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x2C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x241E, + 0xEC78, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x041E, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC525, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, + 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xA943, 0x6834, 0xE72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x294B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2AA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0xCB69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x041E, 0x441E, 0x8316, 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, 0x8316, + 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x6625, 0xC51D, 0x241E, 0x6316, 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x6416, + 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, + 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0xAC88, 0x4C71, 0x0B62, 0x0A53, 0xE843, 0x8734, 0x262D, 0x8525, + 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6834, 0x062D, 0x6625, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x462D, + 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, + 0xCB69, 0xEA52, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, 0x8316, 0xAC69, 0xAA52, 0xC843, 0xC734, 0x6525, 0xE51D, 0x441E, 0x6316, + 0x8C69, 0x8B5A, 0xA943, 0xA734, 0x4625, 0xC525, 0x241E, 0x6416, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, + 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x241E, + 0xEC78, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6625, 0xC51D, + 0xAC80, 0x4C71, 0x2B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE72C, + 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC734, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x083C, 0xA734, + 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4C90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x283C, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A53, + 0x2BA0, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, 0x6316, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6416, + 0x8C71, 0x8B5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x2C79, 0x0B62, 0x2A4B, 0x083C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x0C79, 0xCB69, 0xEA52, 0xC843, 0xA734, 0x462D, 0xC525, 0x041E, + 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, 0xE51D, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC525, + 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4625, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x694B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xA943, 0x4834, 0xE72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE83B, 0x6734, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xCB69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE51D, 0x241E, 0x6316, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0x6416, + 0x8C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x2B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x441E, + 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x6625, 0xC51D, 0x241E, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x262D, 0xA525, 0x041E, + 0xEC78, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0xC525, + 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0x8525, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x6525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, 0x462D, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x6834, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x0A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4B90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xCC69, 0x4B5A, 0xCA52, + 0xCB69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, 0x6416, 0xAC69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, 0x441E, + 0x8C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x2B62, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, + 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0x041E, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xEC78, 0xAC69, 0x8B5A, 0x8943, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xCC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x462D, 0xA525, + 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xE843, 0x8734, 0x262D, 0x8525, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x6625, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x462D, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x062D, + 0x8C88, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE72C, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x483C, 0xC734, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0xA734, 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4C90, 0xAC88, 0x2C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, 0x483C, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, + 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x294B, 0xC943, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x494B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x294B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4C90, 0x8C88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52, + 0xCB69, 0xCA52, 0xE843, 0xC734, 0x6625, 0xC51D, 0x241E, 0x6416, 0xAC69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, 0x441E, + 0x8C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x4C71, 0x2B62, 0x294B, 0x283C, 0xE72C, 0x6525, 0xE51D, 0x241E, + 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x041E, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0x8525, 0xE41D, + 0xEC78, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6625, 0xC51D, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x283C, 0xA734, 0x262D, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x8C88, 0xEC80, 0x8C71, 0x2B5A, 0x0A4B, 0xA943, 0x4834, 0xE72C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4C90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE843, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, + 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B5A, 0xAA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0xAA52, + 0xCB69, 0xCA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0x441E, 0xAC69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x8C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0x8525, 0xE41D, 0x241E, 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0x241E, + 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xA525, 0x041E, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0xE51D, + 0xEC78, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6625, 0xC525, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x262D, 0xA525, + 0xCC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x6525, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xC72C, 0x4625, + 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE843, 0x8734, 0x062D, + 0x8C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6834, + 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x283C, 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, + 0x4B90, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, + 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x494B, + 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A52, 0x2A4B, + 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4C90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x2C71, 0xAC69, 0x2B62, 0x8A5A, + 0x083C, 0xA525, 0xA316, 0x220F, 0x610F, 0xA107, 0xAA52, 0xAA52, 0xC943, 0x8525, 0x8316, 0x020F, 0x610F, 0xA107, 0xAA52, 0xAA52, + 0x8943, 0x4625, 0x6416, 0xE20E, 0x410F, 0x8107, 0xAA52, 0xAA52, 0x494B, 0x062D, 0x241E, 0xE316, 0x420F, 0x8107, 0xAA52, 0xAA52, + 0xEA52, 0xC734, 0x041E, 0xC316, 0x220F, 0x810F, 0xAA52, 0xAA52, 0xAA52, 0x8734, 0xC525, 0x8316, 0x220F, 0x610F, 0xAA52, 0xAA52, + 0x6B5A, 0x283C, 0x8525, 0x6316, 0x020F, 0x610F, 0xAA52, 0xAA52, 0x2B62, 0xE83B, 0x4625, 0x441E, 0xE216, 0x410F, 0xAA52, 0xAA52, + 0xEB61, 0xA943, 0x262D, 0x041E, 0xC316, 0x420F, 0xAA52, 0xAA52, 0xCB69, 0x694B, 0xE72C, 0xE51D, 0xA316, 0x220F, 0xAA52, 0xAA52, + 0xAC69, 0x2A4B, 0xA734, 0xC525, 0x8316, 0x220F, 0xAA52, 0xAA52, 0x6C71, 0xEA52, 0x6734, 0x8525, 0x6416, 0x020F, 0xAA52, 0xAA52, + 0x4C71, 0xCA52, 0x283C, 0x6625, 0x441E, 0xE216, 0xAA52, 0xAA52, 0x2C71, 0x8A5A, 0x083C, 0x262D, 0x241E, 0xC316, 0xAA52, 0xAA52, + 0x2C79, 0x6B5A, 0xC943, 0x062D, 0xE41D, 0xA316, 0xAA52, 0xAA52, 0x0C79, 0x4B5A, 0xA943, 0xC72C, 0xC51D, 0x8316, 0xAA52, 0xAA52, + 0xEC78, 0x0B62, 0x694B, 0xA734, 0xA525, 0x6316, 0x610F, 0xAA52, 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0x420F, 0xAA52, + 0xCC80, 0xCB69, 0x0A4B, 0x483C, 0x6625, 0x241E, 0x220F, 0xAA52, 0xAC80, 0xAC69, 0xEA52, 0x283C, 0x262D, 0x041E, 0xE20E, 0xAA52, + 0xAC88, 0x8C69, 0xCA52, 0xE83B, 0x062D, 0xE51D, 0xC316, 0xAA52, 0xAC88, 0x8C71, 0xAA52, 0xC943, 0xE72C, 0xC525, 0xA316, 0xAA52, + 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0xA525, 0x8316, 0xAA52, 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x8525, 0x6416, 0xAA52, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x6625, 0x441E, 0xAA52, 0x6C90, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x462D, 0x241E, 0x8107, + 0x6C90, 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x041E, 0x020F, 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xC51D, 0xC316, + 0x6C90, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0xA525, 0xA316, 0x4C90, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x6316, + 0x4B90, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x441E, 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x462D, 0x241E, + 0xE83B, 0x8525, 0x8316, 0x020F, 0x410F, 0x810F, 0xC007, 0xAA52, 0xA943, 0x6625, 0x6416, 0xE20E, 0x420F, 0x810F, 0xC007, 0xAA52, + 0x694B, 0x262D, 0x441E, 0xE316, 0x420F, 0x610F, 0xC007, 0xAA52, 0x2A4B, 0xE72C, 0x041E, 0xC316, 0x220F, 0x610F, 0xC007, 0xAA52, + 0xCA52, 0xA734, 0xE51D, 0xA316, 0x020F, 0x610F, 0xA107, 0xAA52, 0x8A5A, 0x4834, 0xA525, 0x6316, 0x020F, 0x410F, 0xA107, 0xAA52, + 0x4B5A, 0x083C, 0x6625, 0x441E, 0xE216, 0x420F, 0xA107, 0xAA52, 0x0B62, 0xC943, 0x262D, 0x241E, 0xC316, 0x220F, 0xA107, 0xAA52, + 0xEB61, 0x8943, 0xE62C, 0xE41D, 0xA316, 0x220F, 0x8107, 0xAA52, 0xAC69, 0x494B, 0xA734, 0xC525, 0x8316, 0x020F, 0x810F, 0xAA52, + 0x8C69, 0x0A4B, 0x8734, 0x8525, 0x6416, 0xE20E, 0x610F, 0xAA52, 0x6C71, 0xCA52, 0x483C, 0x6625, 0x441E, 0xC316, 0x610F, 0xAA52, + 0x4C71, 0xAA52, 0x083C, 0x262D, 0x041E, 0xA316, 0x420F, 0xAA52, 0x2C79, 0x6B5A, 0xC843, 0x062D, 0xE51D, 0xA316, 0x220F, 0xAA52, + 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xC525, 0x8316, 0x220F, 0xAA52, 0xEC78, 0x2B62, 0x8943, 0xA734, 0xA525, 0x6416, 0x020F, 0xAA52, + 0xEC80, 0xEB61, 0x494B, 0x8734, 0x8525, 0x441E, 0xE20E, 0xAA52, 0xCC80, 0xCB61, 0x2A4B, 0x483C, 0x4625, 0x241E, 0xC316, 0xAA52, + 0xCC80, 0xCC69, 0xEA52, 0x283C, 0x262D, 0x041E, 0xA316, 0xAA52, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xE51D, 0xA316, 0xAA52, + 0xAC88, 0x8C69, 0xAA52, 0xC843, 0xE72C, 0xC525, 0x8316, 0xAA52, 0x8C88, 0x6C71, 0x8B5A, 0xA943, 0xC734, 0xA525, 0x6416, 0x610F, + 0x8C88, 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x6525, 0x441E, 0x220F, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x241E, 0x020F, + 0x6C88, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x262D, 0x041E, 0xC316, 0x6C90, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xE51D, 0xA316, + 0x6C90, 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xE62C, 0xC525, 0x8316, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC72C, 0xA525, 0x6316, + 0x4C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x8525, 0x441E, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x241E, + 0x4B98, 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x462D, 0x041E, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xE51D, + 0xC943, 0x6525, 0x6316, 0xE20E, 0x420F, 0x610F, 0xA107, 0xAA52, 0x8943, 0x462D, 0x441E, 0xE316, 0x220F, 0x610F, 0xA107, 0xAA52, + 0x494B, 0x062D, 0x241E, 0xC316, 0x220F, 0x610F, 0x8107, 0xAA52, 0x0A53, 0xC734, 0xE41D, 0xA316, 0x020F, 0x410F, 0x8107, 0xAA52, + 0xAA52, 0x8734, 0xC525, 0x8316, 0x020F, 0x420F, 0x810F, 0xAA52, 0x6B5A, 0x283C, 0x8525, 0x6416, 0xE216, 0x220F, 0x810F, 0xAA52, + 0x2B62, 0xE83B, 0x462D, 0x241E, 0xC316, 0x220F, 0x610F, 0xAA52, 0xEB61, 0xA943, 0x062D, 0x041E, 0xA316, 0x020F, 0x610F, 0xAA52, + 0xCB69, 0x694B, 0xC734, 0xC51D, 0x8316, 0xE20E, 0x410F, 0xAA52, 0x8C69, 0x2A4B, 0x8734, 0xA525, 0x6416, 0xE316, 0x420F, 0xAA52, + 0x6C71, 0xEA52, 0x4834, 0x6525, 0x441E, 0xC316, 0x220F, 0xAA52, 0x4C71, 0xAA52, 0x283C, 0x462D, 0x041E, 0xA316, 0x220F, 0xAA52, + 0x2C79, 0x8B5A, 0xE83B, 0x062D, 0xE51D, 0x8316, 0x020F, 0xC007, 0x0C79, 0x4B5A, 0xA943, 0xE72C, 0xC525, 0x6316, 0xE20E, 0xA107, + 0x0C79, 0x2B62, 0x8943, 0xA734, 0xA525, 0x441E, 0xE216, 0x810F, 0xEC78, 0x0B62, 0x494B, 0x8734, 0x8525, 0x241E, 0xC316, 0x610F, + 0xCC80, 0xEB61, 0x2A4B, 0x4834, 0x4625, 0x041E, 0xA316, 0x420F, 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x262D, 0xE41D, 0x8316, 0x420F, + 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xC51D, 0x8316, 0x220F, 0xAC88, 0x8C69, 0xAA52, 0xE843, 0xE72C, 0xA525, 0x6416, 0x020F, + 0x8C88, 0x6C71, 0x8A5A, 0xA943, 0xC734, 0x8525, 0x441E, 0xE20E, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x241E, 0xC316, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x4625, 0x041E, 0xC316, 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0xE41D, 0xA316, + 0x6C90, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xC51D, 0x8316, 0x6C90, 0x0C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, 0x6416, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x441E, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x6525, 0x241E, + 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x6625, 0x041E, 0x4B90, 0xCC80, 0xAC69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xE51D, + 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x262D, 0xC51D, 0x4B98, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0x062D, 0xA525, + 0x8943, 0x462D, 0x441E, 0xC316, 0x220F, 0x610F, 0x810F, 0xA107, 0x494B, 0x062D, 0x241E, 0xC316, 0x220F, 0x410F, 0x810F, 0xA107, + 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, 0xA107, 0xCA52, 0x8734, 0xC525, 0x8316, 0xE20E, 0x420F, 0x610F, 0xA107, + 0x8A5A, 0x483C, 0x8525, 0x6416, 0xE316, 0x220F, 0x610F, 0x8107, 0x4B5A, 0x083C, 0x6625, 0x241E, 0xC316, 0x220F, 0x610F, 0x8107, + 0x0B62, 0xC943, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, 0x810F, 0xCB69, 0x6943, 0xC72C, 0xC51D, 0x8316, 0xE20E, 0x420F, 0x810F, + 0xAC69, 0x2A4B, 0xA734, 0xA525, 0x6416, 0xC316, 0x220F, 0x610F, 0x8C71, 0xEA52, 0x6834, 0x6525, 0x241E, 0xA316, 0x020F, 0x610F, + 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0xA316, 0x020F, 0x410F, 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xE51D, 0x8316, 0xE20E, 0x420F, + 0x2C79, 0x4B5A, 0xA943, 0xE72C, 0xC525, 0x6416, 0xC316, 0x220F, 0x0C79, 0x2B62, 0x8943, 0xA734, 0x8525, 0x441E, 0xC316, 0x220F, + 0xEC78, 0x0B62, 0x494B, 0x8734, 0x6625, 0x241E, 0xA316, 0x020F, 0xEC80, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0x041E, 0x8316, 0x020F, + 0xCC80, 0xCB69, 0x0A53, 0x283C, 0x262D, 0xE51D, 0x6316, 0xE20E, 0xAC80, 0xAC69, 0xCA52, 0x083C, 0x062D, 0xC525, 0x6416, 0xE316, + 0xAC80, 0x8C69, 0xAA52, 0xC843, 0xC72C, 0xA525, 0x441E, 0xC316, 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x8525, 0x241E, 0xA316, + 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0x8316, 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6734, 0x462D, 0xE51D, 0x8316, + 0x8C88, 0x2C71, 0x2B62, 0x494B, 0x483C, 0x262D, 0xC51D, 0x6416, 0x6C90, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x441E, + 0x6C90, 0x0C79, 0x0B62, 0x0A53, 0x083C, 0xE72C, 0xA525, 0x241E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE843, 0xA734, 0x8525, 0x241E, + 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x6625, 0x041E, 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4C90, 0xCC80, 0xAC69, 0x8B5A, 0x8943, 0x6834, 0x262D, 0xC525, 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x8525, + 0x694B, 0x262D, 0x241E, 0xC316, 0x020F, 0x420F, 0x610F, 0x8107, 0x2A4B, 0xE72C, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, 0x8107, + 0xEA52, 0xA734, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x610F, 0x810F, 0xAA52, 0x6734, 0xA525, 0x6416, 0xE316, 0x220F, 0x610F, 0x810F, + 0x6B5A, 0x283C, 0x6625, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x2B62, 0xC843, 0x262D, 0x041E, 0xA316, 0x020F, 0x420F, 0x610F, + 0xEB61, 0x8943, 0xE62C, 0xE51D, 0x8316, 0xE216, 0x220F, 0x610F, 0xAC69, 0x494B, 0xA734, 0xA525, 0x6416, 0xC316, 0x220F, 0x410F, + 0x8C69, 0x0A4B, 0x6734, 0x8525, 0x241E, 0xA316, 0x020F, 0x420F, 0x6C71, 0xCA52, 0x283C, 0x462D, 0x041E, 0x8316, 0xE20E, 0x420F, + 0x4C71, 0x8A5A, 0x083C, 0x062D, 0xE51D, 0x6316, 0xE316, 0x220F, 0x2C79, 0x6B5A, 0xC943, 0xE72C, 0xC525, 0x441E, 0xC316, 0x220F, + 0x0C79, 0x2B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0x020F, 0xEC78, 0x0B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x8316, 0xE20E, + 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0xE41D, 0x8316, 0xE216, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC51D, 0x6416, 0xC316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xE62C, 0xA525, 0x441E, 0xA316, 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x241E, 0xA316, + 0xAC88, 0x6C71, 0x8A5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x8316, 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xE41D, 0x6316, + 0x8C88, 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xC51D, 0x6416, 0x8C88, 0x2C71, 0x2B62, 0x294B, 0x283C, 0x062D, 0xA525, 0x441E, + 0x6C90, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0xA525, 0x241E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x6625, 0x041E, 0x6C90, 0xEC78, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x462D, 0xE51D, + 0x4C90, 0xEC80, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x262D, 0xC525, 0x4C90, 0xCC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0x062D, 0xA525, + 0x4B98, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE62C, 0x8525, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x083C, 0xC72C, 0x8525, + 0x4B98, 0xAC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xC734, 0x6625, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xC843, 0xA734, 0x462D, + 0x494B, 0xE62C, 0x041E, 0xA316, 0x020F, 0x220F, 0x610F, 0x810F, 0x0A4B, 0xC734, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x410F, 0x610F, + 0xCA52, 0x8734, 0xC525, 0x6316, 0xE316, 0x220F, 0x420F, 0x610F, 0x8B5A, 0x483C, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, + 0x4B5A, 0xE83B, 0x462D, 0x241E, 0xA316, 0x020F, 0x220F, 0x610F, 0x0B62, 0xA943, 0x062D, 0xE41D, 0x8316, 0xE216, 0x220F, 0x410F, + 0xCB69, 0x694B, 0xC734, 0xC525, 0x6416, 0xC316, 0x020F, 0x420F, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x441E, 0xA316, 0x020F, 0x420F, + 0x6C71, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xE216, 0x220F, 0x4C71, 0xAA52, 0x083C, 0x262D, 0xE51D, 0x6316, 0xC316, 0x220F, + 0x2C79, 0x6B5A, 0xC943, 0xE72C, 0xC525, 0x441E, 0xC316, 0x020F, 0x0C79, 0x4B5A, 0x8943, 0xA734, 0x8525, 0x241E, 0xA316, 0xE20E, + 0xEC78, 0x0B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x8316, 0xE316, 0xEC80, 0xEB61, 0x2A4B, 0x483C, 0x462D, 0xE51D, 0x6316, 0xC316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0xA316, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x041E, 0x8316, 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0x041E, 0x6316, + 0x8C88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x462D, 0xE51D, 0x6416, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x262D, 0xC525, 0x441E, + 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0xA525, 0x241E, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC72C, 0x8525, 0x041E, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0x041E, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xC943, 0xA734, 0x4625, 0xE51D, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xC525, 0x4C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0xA525, + 0x4C90, 0xCC80, 0x8C69, 0x8B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x4B90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x8525, + 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x6625, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x262D, 0x2B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x2A4B, 0xC72C, 0xE51D, 0x8316, 0xE20E, 0x220F, 0x420F, 0x610F, 0xEA52, 0x8734, 0xC525, 0x6316, 0xE316, 0x220F, 0x420F, 0x610F, + 0xAA52, 0x6834, 0x8525, 0x441E, 0xC316, 0x020F, 0x420F, 0x610F, 0x6B5A, 0x083C, 0x6625, 0x241E, 0xA316, 0x020F, 0x220F, 0x410F, + 0x2B62, 0xC943, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, 0xEB61, 0x8943, 0xE72C, 0xC525, 0x6416, 0xC316, 0x020F, 0x420F, + 0xAC69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, 0x220F, 0x8C69, 0xEA52, 0x4834, 0x6625, 0x041E, 0x8316, 0xE216, 0x220F, + 0x6C71, 0xAA52, 0x083C, 0x262D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x4C71, 0x8B5A, 0xE843, 0xE62C, 0xC525, 0x441E, 0xA316, 0x020F, + 0x2C79, 0x4B5A, 0xA943, 0xC734, 0x8525, 0x241E, 0xA316, 0xE216, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x6625, 0x041E, 0x8316, 0xC316, + 0xEC80, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xE51D, 0x6416, 0xC316, 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0xA316, + 0xCC80, 0xAC69, 0xEA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x8316, 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x8525, 0x041E, 0x8316, + 0xAC88, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x6416, 0x8C88, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xC51D, 0x441E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, + 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6525, 0x041E, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x6625, 0xE51D, + 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0x062D, 0xA525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x8525, + 0x4B90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x6625, 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x4625, + 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x6834, 0x062D, 0x2B98, 0x8C88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0xEA52, 0xA734, 0xC525, 0x6316, 0xC316, 0x020F, 0x420F, 0x610F, 0xAA52, 0x6734, 0xA525, 0x441E, 0xC316, 0x020F, 0x220F, 0x410F, + 0x8B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xE216, 0x220F, 0x420F, + 0x0B62, 0xA943, 0xE62C, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0x020F, 0x220F, + 0xAC69, 0x0A4B, 0x6734, 0x6525, 0x241E, 0x8316, 0xE216, 0x220F, 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE41D, 0x6316, 0xC316, 0x020F, + 0x4C71, 0x8A5A, 0xE83B, 0x062D, 0xC525, 0x441E, 0xA316, 0xE20E, 0x2C79, 0x6B5A, 0xA943, 0xC734, 0xA525, 0x241E, 0x8316, 0xE316, + 0x0C79, 0x2B62, 0x6943, 0x8734, 0x6625, 0x041E, 0x8316, 0xC316, 0xEC78, 0x0B62, 0x494B, 0x6834, 0x462D, 0xE51D, 0x6416, 0xA316, + 0xCC80, 0xCB69, 0x0A4B, 0x283C, 0x062D, 0xC525, 0x441E, 0xA316, 0xCC80, 0xAC69, 0xEA52, 0xE83B, 0xE72C, 0x8525, 0x241E, 0x8316, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xC734, 0x6525, 0x041E, 0x6416, 0xAC88, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x441E, + 0x8C88, 0x6C71, 0x6B5A, 0x6943, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x241E, + 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, 0x6C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x6625, 0xE51D, + 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x462D, 0xC525, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0xA525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x6943, 0x483C, 0xE62C, 0x8525, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x4625, + 0x4B98, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4B98, 0xAC80, 0x6C71, 0x2B62, 0x0A53, 0xC943, 0x8734, 0x262D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC72C, 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0xAA52, 0x694B, 0x083C, 0xA734, + 0xCA52, 0x8734, 0xA525, 0x441E, 0xC316, 0x020F, 0x220F, 0x420F, 0xAA52, 0x483C, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x420F, + 0x6B5A, 0x083C, 0x4625, 0x241E, 0x8316, 0xE216, 0x220F, 0x420F, 0x2B62, 0xC943, 0x062D, 0xE51D, 0x8316, 0xC316, 0x020F, 0x220F, + 0xEB61, 0x8943, 0xC72C, 0xC525, 0x441E, 0xA316, 0x020F, 0x220F, 0xAC69, 0x2A4B, 0x8734, 0x8525, 0x241E, 0xA316, 0xE216, 0x020F, + 0x8C69, 0xEA52, 0x483C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, 0x4C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE20E, + 0x2C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xE316, 0x0C79, 0x4B5A, 0x8943, 0xA734, 0x6525, 0x041E, 0x8316, 0xC316, + 0x0C79, 0x0B62, 0x494B, 0x6734, 0x462D, 0xE51D, 0x6416, 0xA316, 0xEC80, 0xEB61, 0x2A4B, 0x283C, 0x262D, 0xC525, 0x441E, 0xA316, + 0xCC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x241E, 0x8316, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xC734, 0x6525, 0x041E, 0x6416, + 0xAC80, 0x8C71, 0x8A5A, 0xA943, 0x8734, 0x4625, 0xE51D, 0x441E, 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x241E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0x041E, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x6C90, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x462D, 0xC525, + 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xAC69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x6525, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x6625, + 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0x4B98, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xE843, 0x8734, 0x262D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x4834, 0xE62C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x2B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x283C, 0xC734, + 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0xA734, 0x2B98, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0xAA52, 0x6834, 0x8525, 0x441E, 0xA316, 0xE20E, 0x220F, 0x420F, 0x8B5A, 0x283C, 0x6625, 0x241E, 0xA316, 0xE216, 0x020F, 0x220F, + 0x4B5A, 0xE83B, 0x262D, 0x041E, 0x8316, 0xC316, 0x020F, 0x220F, 0x0B62, 0xA943, 0xE62C, 0xC51D, 0x6416, 0xC316, 0x020F, 0x220F, + 0xCB69, 0x494B, 0xA734, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, 0xAC69, 0x0A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0x020F, + 0x6C71, 0xCA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xC316, 0xE20E, 0x4C71, 0x8A5A, 0xE83B, 0xE62C, 0xA525, 0x441E, 0xA316, 0xE316, + 0x2C79, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x8316, 0xC316, 0x0C79, 0x2B62, 0x694B, 0x8734, 0x4625, 0xE41D, 0x6416, 0xA316, + 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x441E, 0x8316, 0xCC80, 0xCB69, 0x0A53, 0x083C, 0x062D, 0xA525, 0x241E, 0x8316, + 0xCC80, 0xAC69, 0xCA52, 0xE843, 0xC734, 0x6525, 0x041E, 0x6416, 0xAC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x4625, 0xE51D, 0x441E, + 0xAC88, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xC525, 0x241E, 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE41D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xC734, 0x6625, 0xC51D, + 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x462D, 0xC525, 0x6C90, 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCC69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x8525, 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x6625, + 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x4625, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4B90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC843, 0x8734, 0x262D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0x062D, + 0x4B98, 0xAC88, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x283C, 0xA734, 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0x083C, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0xAA52, 0x483C, 0x6625, 0x241E, 0xA316, 0xE316, 0x020F, 0x220F, 0x6B5A, 0x083C, 0x462D, 0x041E, 0x8316, 0xC316, 0x020F, 0x220F, + 0x2B62, 0xC943, 0x062D, 0xE51D, 0x6316, 0xC316, 0x020F, 0x220F, 0xEB61, 0x8943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE216, 0x020F, + 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0x020F, 0x8C69, 0xEA52, 0x483C, 0x462D, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x6C71, 0xAA52, 0x083C, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE216, 0x2C71, 0x6B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x0C79, 0x4B5A, 0x8943, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x462D, 0xC51D, 0x441E, 0xA316, + 0xEC80, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x8316, 0xCC80, 0xCC69, 0xEA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xAC80, 0x8C69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0xA525, 0x041E, 0x8C88, 0x4C71, 0x2B5A, 0x294B, 0x283C, 0xE72C, 0x8525, 0xE41D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x6C88, 0x0C79, 0xEB61, 0xEA52, 0xC843, 0x8734, 0x462D, 0xC525, + 0x6C90, 0x0C79, 0xCB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x483C, 0x062D, 0x8525, + 0x6C90, 0xEC80, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0x4C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, + 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6734, 0xE62C, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xE72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xC734, 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x2B98, 0x8C88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xE843, 0x6734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x6834, 0x2BA0, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A53, 0xA943, 0x483C, + 0x8B5A, 0x283C, 0x4625, 0x041E, 0x8316, 0xC316, 0x020F, 0x220F, 0x4B5A, 0xE83B, 0x262D, 0xE41D, 0x6316, 0xC316, 0xE20E, 0x220F, + 0x2B62, 0xA943, 0xE62C, 0xC525, 0x6416, 0xA316, 0xE20E, 0x020F, 0xEB61, 0x694B, 0xA734, 0xA525, 0x241E, 0x8316, 0xE316, 0x020F, + 0xAC69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x8316, 0xC316, 0xE20E, 0x8C71, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, + 0x4C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C79, 0x4B5A, 0xA943, 0xA734, 0x8525, 0x041E, 0x6316, 0xC316, + 0x0C79, 0x2B62, 0x694B, 0x6734, 0x4625, 0xE51D, 0x441E, 0xA316, 0xEC78, 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, + 0xCC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6316, 0xCC80, 0xAC69, 0xCA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xAC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC88, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x062D, 0xA525, 0x041E, + 0x8C88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0xE41D, 0x8C88, 0x2C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xE51D, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0xA734, 0x462D, 0xC525, 0x6C90, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x262D, 0xA525, + 0x6C90, 0xEC78, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x8525, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x6943, 0x283C, 0xE72C, 0x6625, + 0x6C90, 0xCC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4B98, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE62C, + 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xC734, + 0x4B98, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x4834, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x483C, 0x2BA0, 0x6C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x283C, + 0x6B5A, 0x083C, 0x262D, 0x041E, 0x6316, 0xC316, 0xE20E, 0x020F, 0x4B5A, 0xC943, 0x062D, 0xC51D, 0x6416, 0xA316, 0xE216, 0x020F, + 0x0B62, 0x8943, 0xC72C, 0xA525, 0x441E, 0xA316, 0xE316, 0x020F, 0xCB69, 0x494B, 0x8734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, + 0xAC69, 0x0A4B, 0x483C, 0x462D, 0xE41D, 0x6416, 0xA316, 0xE216, 0x6C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x441E, 0xA316, 0xC316, + 0x4C71, 0x8B5A, 0xC943, 0xC72C, 0xA525, 0x241E, 0x8316, 0xC316, 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x6625, 0xE41D, 0x6416, 0xA316, + 0x0C79, 0x0B62, 0x494B, 0x4834, 0x262D, 0xC525, 0x441E, 0x8316, 0xEC80, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, + 0xCC80, 0xAC69, 0xCA52, 0xE83B, 0xC734, 0x6525, 0xE41D, 0x441E, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC51D, 0x241E, + 0xAC80, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0x041E, + 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A53, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x6C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x8525, + 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x283C, 0xE72C, 0x6625, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, + 0x4C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x8734, 0x062D, + 0x4B90, 0xAC80, 0x4C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6734, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2BA0, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x283C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, + 0x6B5A, 0xE83B, 0x262D, 0xE51D, 0x6416, 0xA316, 0xE216, 0x020F, 0x2B62, 0xA943, 0xE62C, 0xC525, 0x441E, 0xA316, 0xE316, 0x020F, + 0x0B62, 0x6943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, 0x020F, 0xCB69, 0x2A4B, 0x8734, 0x6625, 0x041E, 0x6316, 0xC316, 0xE20E, + 0x8C69, 0xEA52, 0x283C, 0x262D, 0xE51D, 0x441E, 0xA316, 0xE316, 0x6C71, 0xAA52, 0xE83B, 0xE62C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x4C71, 0x6B5A, 0xA943, 0xC734, 0x8525, 0x041E, 0x6316, 0xA316, 0x0C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xE51D, 0x441E, 0x8316, + 0xEC78, 0x0B62, 0x2A4B, 0x483C, 0x062D, 0xA525, 0x241E, 0x8316, 0xEC80, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, + 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0xAC80, 0x8C69, 0x8A5A, 0x8943, 0x8734, 0x262D, 0xC525, 0x241E, + 0xAC88, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x041E, 0x8C88, 0x4C71, 0x2B5A, 0x2A4B, 0x283C, 0xE72C, 0x6625, 0xE51D, + 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x4625, 0xC525, 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, + 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0xA943, 0x6834, 0x062D, 0x8525, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x6943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, + 0x4C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x8734, 0x062D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, + 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC72C, 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x283C, 0xA734, + 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x494B, 0x083C, 0xA734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B5A, 0xC843, 0x062D, 0xC51D, 0x441E, 0xA316, 0xE316, 0x020F, 0x2B62, 0x8943, 0xC72C, 0xA525, 0x441E, 0x8316, 0xC316, 0xE20E, + 0xEB61, 0x694B, 0xA734, 0x8525, 0x241E, 0x8316, 0xC316, 0xE20E, 0xAC69, 0x0A4B, 0x6834, 0x4625, 0xE41D, 0x6416, 0xA316, 0xE316, + 0x8C69, 0xCA52, 0x283C, 0x262D, 0xC525, 0x441E, 0x8316, 0xC316, 0x4C71, 0x8A5A, 0xE843, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, + 0x2C71, 0x4B5A, 0x8943, 0xA734, 0x6625, 0xE41D, 0x6416, 0xA316, 0x0C79, 0x0B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x8316, + 0xEC78, 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xCC80, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6525, 0xE41D, 0x441E, + 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xAC80, 0x6C71, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x6625, 0xC525, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xE843, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x062D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x4B90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC72C, + 0x4B98, 0xAC88, 0x4C71, 0xEB61, 0xCA52, 0x6943, 0x283C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, + 0x2B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2B98, 0x6C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2BA0, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0x083C, + 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC943, + 0x4B5A, 0xC943, 0xE62C, 0xC525, 0x441E, 0x8316, 0xC316, 0xE20E, 0x0B62, 0x8943, 0xC734, 0xA525, 0x241E, 0x8316, 0xC316, 0xE20E, + 0xEB61, 0x494B, 0x8734, 0x6525, 0x041E, 0x6316, 0xA316, 0xE216, 0xAC69, 0x0A4B, 0x483C, 0x462D, 0xE51D, 0x441E, 0xA316, 0xC316, + 0x8C71, 0xCA52, 0x083C, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, 0x4C71, 0x8B5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, 0x0C79, 0x0B62, 0x294B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6316, + 0xEC78, 0xCB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0x041E, 0x6416, 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x262D, 0xA525, 0x241E, 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0x041E, + 0xAC88, 0x4C71, 0x2B5A, 0x2A4B, 0x283C, 0xC72C, 0x6625, 0xE51D, 0x8C88, 0x2C79, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xC525, + 0x8C88, 0x0C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x4834, 0x062D, 0x6525, + 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC72C, 0x4625, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x4B98, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, 0x083C, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, 0x2BA0, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x294B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B62, 0xA943, 0xE72C, 0xA525, 0x241E, 0x8316, 0xC316, 0xE216, 0x0B62, 0x694B, 0xA734, 0x8525, 0x041E, 0x6316, 0xA316, 0xE316, + 0xCB69, 0x2A4B, 0x6734, 0x6625, 0x041E, 0x6416, 0xA316, 0xC316, 0xAC69, 0xEA52, 0x283C, 0x262D, 0xC51D, 0x441E, 0x8316, 0xC316, + 0x6C71, 0xAA52, 0xE83B, 0xE72C, 0xA525, 0x241E, 0x6316, 0xA316, 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, + 0x2C79, 0x2B62, 0x694B, 0x6734, 0x462D, 0xC51D, 0x441E, 0x8316, 0x0C79, 0xEB61, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, + 0xEC80, 0xCB69, 0xEA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x441E, 0xCC80, 0xAC69, 0xAA52, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xAC80, 0x8C71, 0x8B5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x041E, 0xAC88, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x8525, 0xE51D, + 0x8C88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x4625, 0xC525, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x6C90, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, + 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x462D, 0x6C90, 0xCC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xCC80, 0x6C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0x062D, 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xE72C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x2B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0xA943, 0x283C, + 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, + 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2B62, 0x8943, 0xC734, 0x8525, 0x241E, 0x6316, 0xA316, 0xE316, 0xEB61, 0x494B, 0x8734, 0x6625, 0x041E, 0x6416, 0xA316, 0xC316, + 0xCB69, 0x2A4B, 0x6834, 0x462D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x8C69, 0xEA52, 0x283C, 0x062D, 0xC525, 0x241E, 0x8316, 0xC316, + 0x6C71, 0xAA52, 0xE843, 0xC72C, 0x8525, 0x041E, 0x6416, 0xA316, 0x4C71, 0x6B5A, 0x8943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x2C79, 0x2B62, 0x494B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6316, 0xEC78, 0xEB61, 0x0A4B, 0x083C, 0xE62C, 0x8525, 0x041E, 0x441E, + 0xEC80, 0xCC69, 0xCA52, 0xE843, 0xC734, 0x6625, 0xE51D, 0x241E, 0xCC80, 0x8C69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xAC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0xAC88, 0x4C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC51D, + 0x8C88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, 0x6C90, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x4625, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x062D, + 0x4C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x6834, 0xE72C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x483C, 0xC734, + 0x4B90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x6943, 0x083C, 0xA734, 0x4B98, 0xAC88, 0x2C79, 0xCB61, 0x8A52, 0x494B, 0xE83B, 0x8734, + 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xE843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, 0x2B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0x083C, 0x2B98, 0x6C90, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xC943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x4B5A, 0xEA52, 0x8943, + 0x2B62, 0x8943, 0xA734, 0x8525, 0x041E, 0x6416, 0xA316, 0xC316, 0xEB61, 0x494B, 0x8734, 0x6625, 0xE41D, 0x441E, 0xA316, 0xC316, + 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xE51D, 0x441E, 0x8316, 0xC316, 0x8C69, 0xCA52, 0x083C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, + 0x6C71, 0x8A5A, 0xC943, 0xC734, 0x8525, 0x041E, 0x6416, 0xA316, 0x2C71, 0x4B5A, 0x8943, 0x8734, 0x4625, 0xC51D, 0x441E, 0x8316, + 0x0C79, 0x0B62, 0x494B, 0x483C, 0x262D, 0xA525, 0x241E, 0x6416, 0xEC78, 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, + 0xCC80, 0xAC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, + 0xAC80, 0x6C71, 0x6B5A, 0x494B, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, + 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC843, 0x8734, 0x262D, 0xA525, 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, + 0x6C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x462D, + 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x4C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x4B98, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x494B, 0xE83B, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x2B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x0B62, 0x6943, 0xA734, 0x6525, 0x041E, 0x6416, 0xA316, 0xC316, 0xEB61, 0x2A4B, 0x6734, 0x4625, 0xE51D, 0x441E, 0x8316, 0xC316, + 0xCC69, 0x0A53, 0x483C, 0x262D, 0xC525, 0x241E, 0x8316, 0xA316, 0x8C69, 0xCA52, 0xE83B, 0xE72C, 0xA525, 0x041E, 0x6416, 0xA316, + 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C71, 0x4B5A, 0x6943, 0x6734, 0x462D, 0xC525, 0x241E, 0x6316, + 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0xEC78, 0xCB69, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x441E, + 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x462D, 0xC525, 0x241E, 0xCC80, 0x8C71, 0x8B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0x041E, + 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE72C, 0x6625, 0xC51D, 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x462D, 0xA525, + 0x8C88, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE62C, 0x6625, + 0x6C88, 0xEC78, 0xAC69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x6C90, 0xEC80, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC843, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x4834, 0xE72C, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0xA734, + 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x8734, 0x4B98, 0x8C88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x6834, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x8943, 0x083C, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x694B, 0xE83B, + 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xC943, + 0x2BA0, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x4C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x694B, + 0x0B62, 0x694B, 0x8734, 0x6625, 0xE41D, 0x441E, 0x8316, 0xC316, 0xEB61, 0x2A4B, 0x4834, 0x462D, 0xC51D, 0x441E, 0x8316, 0xA316, + 0xAC69, 0xEA52, 0x283C, 0x062D, 0xA525, 0x241E, 0x6316, 0xA316, 0x8C69, 0xAA52, 0xE83B, 0xC72C, 0x8525, 0x041E, 0x6416, 0x8316, + 0x4C71, 0x6B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, 0x2C79, 0x2B62, 0x694B, 0x6834, 0x262D, 0xA525, 0x241E, 0x6416, + 0x0C79, 0x0B62, 0x2A4B, 0x283C, 0xE62C, 0x8525, 0x041E, 0x441E, 0xEC78, 0xCB69, 0xCA52, 0xE843, 0xA734, 0x4625, 0xC51D, 0x241E, + 0xCC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x6B5A, 0x694B, 0x483C, 0xE62C, 0x8525, 0xE51D, + 0xAC80, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0xAC88, 0x2C71, 0x0B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0xA525, + 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x8525, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4625, + 0x6C90, 0xEC78, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xC943, 0x6734, 0xE72C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xEA52, 0x8943, 0x483C, 0xC734, + 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0xA734, 0x4C90, 0xAC88, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4B98, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xC943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0xA943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xEA52, 0x8943, 0x083C, + 0x2B98, 0x8C88, 0xEC78, 0x6C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x0B62, 0x494B, 0x8734, 0x4625, 0xE51D, 0x441E, 0x8316, 0xA316, 0xCB69, 0x0A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6316, 0xA316, + 0xAC69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x6416, 0xA316, 0x8C71, 0xAA52, 0xC943, 0xC734, 0x8525, 0xE41D, 0x441E, 0x8316, + 0x4C71, 0x6B5A, 0x8943, 0x8734, 0x4625, 0xC51D, 0x241E, 0x6316, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x6416, + 0x0C79, 0xEB61, 0x0A4B, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x441E, 0xEC80, 0xCC69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x241E, + 0xCC80, 0x8C69, 0x8A5A, 0x8943, 0x6734, 0x062D, 0xA525, 0x041E, 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xE72C, 0x6525, 0xE51D, + 0xAC88, 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, 0x8C88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, + 0x8C88, 0x0C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x6625, 0x8C88, 0x0C79, 0xCC69, 0x8A5A, 0x6943, 0x283C, 0xC734, 0x462D, + 0x6C90, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x8734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xE72C, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, + 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4B98, 0xAC88, 0x0C79, 0xCC69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A4B, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x2B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x2B98, 0x6C90, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2BA0, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x8943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x4C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x0B62, 0x494B, 0x6734, 0x462D, 0xC51D, 0x241E, 0x8316, 0xA316, 0xCB69, 0x0A4B, 0x283C, 0x262D, 0xC525, 0x241E, 0x6316, 0xA316, + 0xAC69, 0xCA52, 0x083C, 0xE62C, 0xA525, 0x041E, 0x6416, 0x8316, 0x6C71, 0x8A5A, 0xC943, 0xA734, 0x6625, 0xE51D, 0x441E, 0x8316, + 0x4C71, 0x4B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6316, 0x2C79, 0x2B62, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, + 0x0C79, 0xEB61, 0x0A53, 0x083C, 0xC72C, 0x6625, 0xE51D, 0x241E, 0xEC80, 0xAC69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x8C69, 0x8B5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, 0xAC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC525, + 0xAC88, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, 0x8C88, 0x2C79, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x8525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x6625, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x694B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xEC80, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC734, 0x4C90, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0xA734, + 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xCA52, 0x694B, 0xE83B, + 0x2B98, 0x6C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x294B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0xEB61, 0x2A4B, 0x6834, 0x262D, 0xC525, 0x241E, 0x6316, 0xA316, 0xCB69, 0x0A53, 0x283C, 0x062D, 0xA525, 0x041E, 0x6416, 0x8316, + 0xAC69, 0xCA52, 0xE83B, 0xE72C, 0x8525, 0x041E, 0x441E, 0x8316, 0x6C71, 0x8B5A, 0xA943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, + 0x4C71, 0x4B5A, 0x6943, 0x6734, 0x262D, 0xA525, 0x241E, 0x6416, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0x062D, 0x8525, 0xE41D, 0x441E, + 0x0C79, 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, + 0xCC80, 0x8C69, 0x6B5A, 0x6943, 0x483C, 0xE62C, 0x8525, 0xE51D, 0xAC80, 0x6C71, 0x4B5A, 0x294B, 0x083C, 0xC734, 0x4625, 0xC525, + 0xAC88, 0x4C71, 0x0B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0xA525, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x6734, 0x062D, 0x6525, + 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, 0x4625, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x2A4B, 0xE843, 0x8734, 0x062D, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0x0A53, 0xA943, 0x6834, 0xE72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xC734, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8A5A, 0x494B, 0xE83B, 0x6734, 0x4B90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE843, + 0x2B98, 0x6C88, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A53, 0x8943, 0x2BA0, 0x6C90, 0xCC80, 0x2C79, 0xCC69, 0x4B5A, 0xEA52, 0x6943, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B5A, 0xCA52, 0x494B, 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x0A4B, + 0xEB61, 0x2A4B, 0x483C, 0x262D, 0xC525, 0x241E, 0x6416, 0xA316, 0xCB69, 0xEA52, 0x083C, 0x062D, 0xA525, 0x041E, 0x441E, 0x8316, + 0xAC69, 0xCA52, 0xE83B, 0xC72C, 0x8525, 0xE41D, 0x441E, 0x8316, 0x6C71, 0x8B5A, 0xA943, 0x8734, 0x4625, 0xC525, 0x241E, 0x6316, + 0x4C71, 0x4B5A, 0x694B, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, 0x2C79, 0x0B62, 0x2A4B, 0x283C, 0xE72C, 0x8525, 0xE51D, 0x441E, + 0x0C79, 0xCB69, 0xEA52, 0xE83B, 0xA734, 0x4625, 0xC525, 0x241E, 0xEC80, 0xAC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0xA525, 0xE41D, + 0xCC80, 0x8C71, 0x6B5A, 0x694B, 0x483C, 0xE72C, 0x6625, 0xC51D, 0xAC80, 0x4C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, + 0xAC88, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x262D, 0x8525, 0x8C88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x6625, + 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x283C, 0xC734, 0x462D, 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x262D, + 0x6C90, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE62C, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x4C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0x083C, 0x8734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6734, 0x4B90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4B98, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x6943, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x694B, + 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8A5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0xEB61, 0x0A4B, 0x483C, 0x062D, 0xA525, 0x041E, 0x6416, 0x8316, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0x041E, 0x441E, 0x8316, + 0xAC69, 0xAA52, 0xC843, 0xC734, 0x6625, 0xE51D, 0x441E, 0x6316, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x462D, 0xC525, 0x241E, 0x6416, + 0x4C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0xA525, 0x041E, 0x441E, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xE72C, 0x6625, 0xE51D, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xC943, 0xA734, 0x462D, 0xA525, 0x041E, 0xEC80, 0xAC69, 0x8A5A, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x6625, 0xC525, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0xA734, 0x262D, 0xA525, + 0xAC88, 0x2C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x8525, 0x8C88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xE72C, 0x4625, + 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x694B, 0x083C, 0xA734, 0x262D, 0x6C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, + 0x6C90, 0xEC80, 0x8C71, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0xE72C, 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0xC734, + 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, 0x4C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x4834, 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x283C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x4B98, 0x6C88, 0xCC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xC943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2BA0, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x294B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0xEB61, 0x0A4B, 0x283C, 0x062D, 0xA525, 0x041E, 0x441E, 0x8316, 0xCB69, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, 0x8316, + 0xAC69, 0xAA52, 0xC943, 0xA734, 0x6625, 0xE51D, 0x241E, 0x6316, 0x6C71, 0x6B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x2B62, 0x494B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x441E, 0x2C79, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x6625, 0xC51D, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC80, 0x8C69, 0x8B5A, 0x8943, 0x4834, 0x062D, 0x8525, 0xE51D, + 0xCC80, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0xC525, 0xAC80, 0x4C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x8525, + 0xAC88, 0x2C79, 0x0B62, 0xCA52, 0xA943, 0x6734, 0x062D, 0x6625, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x8943, 0x283C, 0xC72C, 0x462D, + 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, 0x6C88, 0xEC78, 0x8C69, 0x4B5A, 0x2A4B, 0xC843, 0x6734, 0x062D, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC72C, 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, 0x4C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x294B, 0xE843, 0x6734, + 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, 0x4B90, 0x8C88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4B98, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x494B, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xAA52, 0x494B, + 0x2BA0, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0x0A53, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0xEB61, 0x0A4B, 0x283C, 0x062D, 0x8525, 0x041E, 0x441E, 0x8316, 0xCC69, 0xCA52, 0xE83B, 0xC72C, 0x6525, 0xE51D, 0x241E, 0x6316, + 0x8C69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0x6416, 0x6C71, 0x6B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x2B62, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, 0x2C79, 0xEB61, 0x0A53, 0xE83B, 0xC734, 0x4625, 0xC525, 0x241E, + 0x0C79, 0xCB69, 0xCA52, 0xA943, 0x8734, 0x262D, 0xA525, 0x041E, 0xEC80, 0x8C69, 0x8B5A, 0x6943, 0x483C, 0xE72C, 0x6525, 0xC51D, + 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xC734, 0x462D, 0xA525, 0xAC80, 0x4C71, 0x2B62, 0x0A53, 0xC843, 0x8734, 0x262D, 0x8525, + 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0xA943, 0x4834, 0xE62C, 0x6625, 0x8C88, 0x0C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x462D, + 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x062D, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE72C, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC734, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x6943, 0x283C, 0xA734, + 0x6C90, 0xAC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x8734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x4834, + 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x283C, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0xE83B, 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, + 0x2B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2BA0, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x2A4B, 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xEB61, 0x0A53, 0x083C, 0xE72C, 0x8525, 0xE41D, 0x441E, 0x6316, 0xCC69, 0xCA52, 0xE83B, 0xC734, 0x6625, 0xE51D, 0x241E, 0x6416, + 0x8C69, 0x8A5A, 0xA943, 0xA734, 0x462D, 0xC525, 0x241E, 0x6416, 0x6C71, 0x6B5A, 0x6943, 0x6834, 0x262D, 0xA525, 0x041E, 0x441E, + 0x4C71, 0x2B62, 0x2A4B, 0x283C, 0xE72C, 0x6525, 0xE51D, 0x241E, 0x2C79, 0xEB61, 0xEA52, 0xE83B, 0xA734, 0x462D, 0xC525, 0x041E, + 0x0C79, 0xCC69, 0xAA52, 0xA943, 0x6734, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x8C69, 0x6B5A, 0x694B, 0x283C, 0xE72C, 0x6625, 0xC525, + 0xCC80, 0x6C71, 0x4B5A, 0x2A4B, 0x083C, 0xA734, 0x462D, 0xA525, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x8734, 0x062D, 0x8525, + 0xAC88, 0x2C79, 0xEB61, 0xCA52, 0x8943, 0x483C, 0xE72C, 0x4625, 0x8C88, 0x0C79, 0xCB69, 0x8A5A, 0x694B, 0x283C, 0xA734, 0x262D, + 0x8C88, 0xEC78, 0xAC69, 0x6B5A, 0x2A4B, 0xE83B, 0x8734, 0x062D, 0x6C88, 0xEC80, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0xE72C, + 0x6C90, 0xCC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0xC734, 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x8734, + 0x6C90, 0xAC80, 0x2C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x6734, 0x4C90, 0xAC88, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x483C, + 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0x0A53, 0xA943, 0x283C, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xEA52, 0x8943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xCA52, 0x494B, 0xE83B, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, + 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0x0A4B, 0x8943, + 0x2B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x6943, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x494B, + 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0xAC69, 0x2B62, 0xAA52, 0x494B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x0A4B, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xEB61, 0xEA52, 0x083C, 0xE72C, 0x8525, 0xE51D, 0x241E, 0x6316, 0xAC69, 0xCA52, 0xC843, 0xA734, 0x6625, 0xC525, 0x241E, 0x6416, + 0x8C69, 0x8A5A, 0xA943, 0x8734, 0x462D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x4B5A, 0x694B, 0x483C, 0x062D, 0x8525, 0xE41D, 0x441E, + 0x4C71, 0x2B62, 0x2A4B, 0x083C, 0xE72C, 0x6625, 0xC51D, 0x241E, 0x2C79, 0xEB61, 0xEA52, 0xC843, 0xA734, 0x462D, 0xA525, 0x041E, + 0x0C79, 0xAC69, 0xAA52, 0x8943, 0x6734, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC72C, 0x4625, 0xC525, + 0xCC80, 0x6C71, 0x2B5A, 0x2A4B, 0xE83B, 0xA734, 0x262D, 0x8525, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xC943, 0x6734, 0x062D, 0x6625, + 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x483C, 0xC72C, 0x462D, 0x8C88, 0x0C79, 0xCC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x262D, + 0x8C88, 0xEC78, 0x8C69, 0x6B5A, 0x2A4B, 0xC843, 0x6734, 0xE62C, 0x6C88, 0xEC80, 0x8C71, 0x2B62, 0x0A53, 0xA943, 0x483C, 0xC72C, + 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x8943, 0x283C, 0xA734, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x694B, 0x083C, 0x8734, + 0x6C90, 0xAC80, 0x2C71, 0xCB69, 0x8B5A, 0x2A4B, 0xC843, 0x6834, 0x4C90, 0xAC88, 0x2C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x483C, + 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, 0x4B90, 0x8C88, 0x0C79, 0x8C69, 0x2B62, 0xCA52, 0x6943, 0x083C, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC843, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8A5A, 0x2A4B, 0xA943, + 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xEB61, 0x6B5A, 0x0A4B, 0xA943, 0x4B98, 0x6C90, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, + 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xEA52, 0x694B, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, + 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x2A4B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x0A4B, + 0x2BA0, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A53, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4C90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0xEB61, 0xEA52, 0xE83B, 0xC72C, 0x6625, 0xE51D, 0x241E, 0x6416, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x4625, 0xC525, 0x241E, 0x441E, + 0x8C69, 0x8B5A, 0x8943, 0x8734, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x4B5A, 0x494B, 0x483C, 0x062D, 0x8525, 0xE51D, 0x241E, + 0x4C71, 0x0B62, 0x2A4B, 0x083C, 0xC72C, 0x6625, 0xC525, 0x041E, 0x2C79, 0xEB61, 0xEA52, 0xC943, 0x8734, 0x262D, 0xA525, 0x041E, + 0x0C79, 0xAC69, 0xAA52, 0x8943, 0x6834, 0x062D, 0x8525, 0xE51D, 0xEC80, 0x8C69, 0x6B5A, 0x494B, 0x283C, 0xC734, 0x4625, 0xA525, + 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE83B, 0x8734, 0x262D, 0x8525, 0xAC80, 0x4C71, 0x0B62, 0xEA52, 0xA943, 0x6834, 0xE62C, 0x6625, + 0xAC88, 0x2C79, 0xEB61, 0xAA52, 0x8943, 0x283C, 0xC734, 0x462D, 0x8C88, 0x0C79, 0xAC69, 0x8B5A, 0x494B, 0x083C, 0xA734, 0x062D, + 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6734, 0xE72C, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0xA943, 0x483C, 0xC734, + 0x6C90, 0xCC80, 0x6C71, 0x0B62, 0xCA52, 0x6943, 0x083C, 0xA734, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0xAA52, 0x494B, 0xE83B, 0x8734, + 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x8B5A, 0x2A4B, 0xC943, 0x483C, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x6B5A, 0x0A4B, 0xA943, 0x283C, + 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x4B5A, 0xEA52, 0x8943, 0x083C, 0x4B90, 0x8C88, 0xEC78, 0x8C69, 0x2B62, 0xCA52, 0x694B, 0xE83B, + 0x4B98, 0x8C88, 0xEC78, 0x6C71, 0x0B62, 0xAA52, 0x494B, 0xC943, 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0xEB61, 0x8B5A, 0x2A4B, 0xA943, + 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB61, 0x6B5A, 0x0A4B, 0x8943, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCB69, 0x4B5A, 0xEA52, 0x6943, + 0x2B98, 0x6C90, 0xCC80, 0x2C79, 0xAC69, 0x4B5A, 0xCA52, 0x494B, 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xAA52, 0x494B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0xAA52, 0x2A4B, 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C71, 0x0B62, 0x8B5A, 0x0A4B, + 0x2BA0, 0x4C90, 0xAC88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xCB61, 0x6B5A, 0xEA52, + 0x2BA0, 0x4B90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xEC80, 0x4C71, 0xAC69, 0x2B5A, 0xAA52, + 0xEB61, 0xEA52, 0xE83B, 0xC734, 0x6625, 0xC51D, 0x241E, 0x6416, 0xAC69, 0xAA52, 0xC943, 0xA734, 0x462D, 0xC525, 0x041E, 0x441E, + 0x8C69, 0x8B5A, 0x8943, 0x6734, 0x262D, 0xA525, 0x041E, 0x441E, 0x6C71, 0x4B5A, 0x494B, 0x283C, 0xE62C, 0x8525, 0xE51D, 0x241E, + 0x4C71, 0x0B62, 0x0A4B, 0x083C, 0xC734, 0x4625, 0xC525, 0x041E, 0x2C79, 0xEB61, 0xCA52, 0xC943, 0x8734, 0x262D, 0xA525, 0xE41D, + 0x0C79, 0xAC69, 0x8A5A, 0x8943, 0x483C, 0xE62C, 0x6525, 0xC51D, 0xEC80, 0x8C71, 0x4B5A, 0x494B, 0x083C, 0xC734, 0x462D, 0xA525, + 0xCC80, 0x6C71, 0x2B62, 0x0A4B, 0xE843, 0x8734, 0x062D, 0x8525, 0xAC80, 0x4C71, 0x0B62, 0xCA52, 0xA943, 0x483C, 0xE72C, 0x6625, + 0xAC88, 0x2C79, 0xCB69, 0xAA52, 0x6943, 0x283C, 0xC734, 0x262D, 0x8C88, 0x0C79, 0xAC69, 0x6B5A, 0x494B, 0xE83B, 0x8734, 0x062D, + 0x8C88, 0xEC78, 0x8C69, 0x4B5A, 0x0A4B, 0xC943, 0x6834, 0xE72C, 0x6C88, 0xEC80, 0x6C71, 0x2B62, 0xEA52, 0x8943, 0x283C, 0xA734, + 0x6C90, 0xCC80, 0x4C71, 0x0B62, 0xCA52, 0x694B, 0x083C, 0x8734, 0x6C90, 0xCC80, 0x4C71, 0xEB61, 0x8A5A, 0x494B, 0xE83B, 0x6734, + 0x6C90, 0xAC80, 0x2C79, 0xCB69, 0x6B5A, 0x2A4B, 0xC943, 0x483C, 0x4C90, 0xAC88, 0x0C79, 0xAC69, 0x4B5A, 0xEA52, 0x8943, 0x283C, + 0x4C90, 0x8C88, 0x0C79, 0x8C69, 0x2B5A, 0xCA52, 0x6943, 0x083C, 0x4B90, 0x8C88, 0xEC78, 0x8C71, 0x2B62, 0xAA52, 0x494B, 0xE83B, + 0x4B98, 0x8C88, 0xEC80, 0x6C71, 0x0B62, 0x8A5A, 0x2A4B, 0xC943, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xEB61, 0x8B5A, 0x0A4B, 0xA943, + 0x4B98, 0x6C88, 0xCC80, 0x4C71, 0xCB69, 0x6B5A, 0xEA52, 0x8943, 0x4B98, 0x6C90, 0xCC80, 0x2C71, 0xCC69, 0x4B5A, 0xEA52, 0x694B, + 0x2B98, 0x6C90, 0xAC80, 0x2C79, 0xAC69, 0x2B62, 0xCA52, 0x494B, 0x2B98, 0x6C90, 0xAC80, 0x0C79, 0x8C69, 0x2B62, 0xAA52, 0x2A4B, + 0x2B98, 0x6C90, 0xAC88, 0x0C79, 0x8C69, 0x0B62, 0x8A5A, 0x0A4B, 0x2B98, 0x4C90, 0xAC88, 0x0C79, 0x6C71, 0xEB61, 0x8B5A, 0x0A53, + 0x2BA0, 0x4C90, 0x8C88, 0xEC78, 0x6C71, 0xEB61, 0x6B5A, 0xEA52, 0x2BA0, 0x4C90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, + 0x2BA0, 0x4B90, 0x8C88, 0xEC80, 0x4C71, 0xCB69, 0x4B5A, 0xCA52, 0x2BA0, 0x4B98, 0x8C88, 0xCC80, 0x4C71, 0xAC69, 0x2B62, 0xAA52 +}; +#endif //IMLIB_ENABLE_INVARIANT_TABLE diff --git a/src/openmv/src/omv/img/jpeg.c b/src/openmv/src/omv/img/jpeg.c new file mode 100755 index 0000000..1b9f605 --- /dev/null +++ b/src/openmv/src/omv/img/jpeg.c @@ -0,0 +1,1266 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Minimalistic JPEG baseline encoder. + * Ported from public domain JPEG writer by Jon Olick - http://jonolick.com + * + * DCT implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. + * + */ + +#include + +#include "xalloc.h" +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "imlib.h" +#include "omv_boardconfig.h" + +#define TIME_JPEG (0) + +#if defined(OMV_HARDWARE_JPEG) + +#define MCU_W (8) +#define MCU_H (8) +#define JPEG_444_GS_MCU_SIZE (64) +#define JPEG_444_YCBCR_MCU_SIZE (192) +#define JPEG_422_YCBCR_MCU_SIZE (256) +#define JPEG_420_YCBCR_MCU_SIZE (384) + +typedef struct _jpeg_enc { + int img_w; + int img_h; + int img_bpp; + int mcu_row; + int mcu_size; + int out_size; + int x_offset; + int y_offset; + bool overflow; + image_t *img; + union { + uint8_t *pixels8; + uint16_t *pixels16; + }; +} jpeg_enc_t; + +static uint8_t mcubuf[512]; +static jpeg_enc_t jpeg_enc; + +static uint8_t *get_mcu() +{ + uint8_t *Y0 = mcubuf; + uint8_t *CB = mcubuf + 64; + uint8_t *CR = mcubuf + 128; + + // Copy 8x8 MCUs + switch (jpeg_enc.img_bpp) { + case 0: + for (int y=jpeg_enc.y_offset; y<(jpeg_enc.y_offset + MCU_H); y++) { + for (int x=jpeg_enc.x_offset; x<(jpeg_enc.x_offset + MCU_W); x++) { + *Y0++ = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(jpeg_enc.img, x, y)) - 128; + } + } + break; + case 1: + for (int y=jpeg_enc.y_offset; y<(jpeg_enc.y_offset + MCU_H); y++) { + for (int x=jpeg_enc.x_offset; x<(jpeg_enc.x_offset + MCU_W); x++) { + *Y0++ = jpeg_enc.pixels8[y * jpeg_enc.img_w + x]; + } + } + break; + case 2: { + for (int y=jpeg_enc.y_offset, idx=0; y<(jpeg_enc.y_offset + MCU_H); y++) { + for (int x=jpeg_enc.x_offset; x<(jpeg_enc.x_offset + MCU_W); x++, idx++) { + int ofs = y * jpeg_enc.img_w + x; + Y0[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 0] - 128; + CB[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 1] - 128; + CR[idx] = yuv_table[jpeg_enc.pixels16[ofs] * 3 + 2] - 128; + } + } + break; + } + case 3: { + uint16_t rgbbuf[64]; + imlib_bayer_to_rgb565(jpeg_enc.img, 8, 8, jpeg_enc.x_offset, jpeg_enc.y_offset, rgbbuf); + for (int y=0, idx=0; y<8; y++) { + for (int x=0; x<8; x++, idx++) { + Y0[idx] = yuv_table[rgbbuf[idx] * 3 + 0] - 128; + CB[idx] = yuv_table[rgbbuf[idx] * 3 + 1] - 128; + CR[idx] = yuv_table[rgbbuf[idx] * 3 + 2] - 128; + } + } + break; + } + } + + jpeg_enc.x_offset += MCU_W; + if (jpeg_enc.x_offset == (jpeg_enc.mcu_row * MCU_W)) { + jpeg_enc.x_offset = 0; + jpeg_enc.y_offset += MCU_H; + } + return mcubuf; +} + +void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData) +{ + HAL_JPEG_Pause(hjpeg, JPEG_PAUSE_RESUME_INPUT); + if ((hjpeg->JpegOutCount+1024) > hjpeg->OutDataLength) { + jpeg_enc.overflow = true; + HAL_JPEG_Abort(hjpeg); + HAL_JPEG_ConfigInputBuffer(hjpeg, NULL, 0); + } else if (jpeg_enc.y_offset == jpeg_enc.img_h) { + HAL_JPEG_ConfigInputBuffer(hjpeg, NULL, 0); + } else { + HAL_JPEG_ConfigInputBuffer(hjpeg, get_mcu(), jpeg_enc.mcu_size); + } + HAL_JPEG_Resume(hjpeg, JPEG_PAUSE_RESUME_INPUT); +} + +void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength) +{ + jpeg_enc.out_size = OutDataLength; +} + +void HAL_JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg) +{ + printf("JPEG decode/encode error\n"); +} + +bool jpeg_compress(image_t *src, image_t *dst, int quality, bool realloc) +{ +#if (TIME_JPEG==1) + uint32_t start = HAL_GetTick(); +#endif + + // Init the HAL JPEG driver + JPEG_HandleTypeDef JPEG_Handle = {0}; + JPEG_Handle.Instance = JPEG; + HAL_JPEG_Init(&JPEG_Handle); + + jpeg_enc.img = src; + jpeg_enc.img_w = src->w; + jpeg_enc.img_h = src->h; + jpeg_enc.img_bpp = src->bpp; + jpeg_enc.mcu_row = src->w / MCU_W; + jpeg_enc.out_size = 0; + jpeg_enc.x_offset = 0; + jpeg_enc.y_offset = 0; + jpeg_enc.overflow = false; + jpeg_enc.pixels8 = (uint8_t *) src->pixels; + jpeg_enc.pixels16 = (uint16_t*) src->pixels; + + JPEG_ConfTypeDef JPEG_Info; + JPEG_Info.ImageWidth = src->w; + JPEG_Info.ImageHeight = src->h; + JPEG_Info.ImageQuality = quality; + + switch (src->bpp) { + case 0: + case 1: + jpeg_enc.mcu_size = JPEG_444_GS_MCU_SIZE; + JPEG_Info.ColorSpace = JPEG_GRAYSCALE_COLORSPACE; + JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING; + break; + case 2: + case 3: + jpeg_enc.mcu_size = JPEG_444_YCBCR_MCU_SIZE; + JPEG_Info.ColorSpace = JPEG_YCBCR_COLORSPACE; + JPEG_Info.ChromaSubsampling = JPEG_444_SUBSAMPLING; + break; + } + + if (HAL_JPEG_ConfigEncoding(&JPEG_Handle, &JPEG_Info) != HAL_OK) { + return true; + // Initialization error + //nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "JPEG config failed!!")); + } + + // NOTE: output buffer size is stored in dst->bpp + if (HAL_JPEG_Encode(&JPEG_Handle, get_mcu(), jpeg_enc.mcu_size, dst->pixels, dst->bpp, 100) != HAL_OK) { + return true; + // Initialization error + //nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "JPEG encode failed!!")); + } + + // Set output size + dst->bpp = jpeg_enc.out_size; + +#if (TIME_JPEG==1) + printf("time: %lums\n", HAL_GetTick() - start); +#endif + + HAL_JPEG_DeInit(&JPEG_Handle); + + return jpeg_enc.overflow; +} + +#else +// Software JPEG implementation. +#define FIX_0_382683433 ((int32_t) 98) +#define FIX_0_541196100 ((int32_t) 139) +#define FIX_0_707106781 ((int32_t) 181) +#define FIX_1_306562965 ((int32_t) 334) + +#define DESCALE(x, y) (x>>y) +#define MULTIPLY(x, y) DESCALE((x) * (y), 8) + +typedef struct { + int idx; + int length; + uint8_t *buf; + int bitc, bitb; + bool realloc; + bool overflow; +} jpeg_buf_t; + +// Quantization tables +static float fdtbl_Y[64], fdtbl_UV[64]; +static uint8_t YTable[64], UVTable[64]; + +// RGB565 to YUV table +extern const int8_t yuv_table[196608]; + +static const uint8_t s_jpeg_ZigZag[] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +static const uint8_t YQT[] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; + +static const uint8_t UVQT[] = { + 17,18,24,47,99,99,99,99, + 18,21,26,66,99,99,99,99, + 24,26,56,99,99,99,99,99, + 47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99 +}; + +static const float aasf[] = { + 1.0f, 1.387039845f, 1.306562965f, 1.175875602f, + 1.0f, 0.785694958f, 0.541196100f, 0.275899379f +}; + + +static const uint8_t std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; +static const uint8_t std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; +static const uint8_t std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; +static const uint8_t std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa +}; + +static const uint8_t std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; +static const uint8_t std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; +static const uint8_t std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; +static const uint8_t std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa +}; + +// Huffman tables +static const uint16_t YDC_HT[12][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; +static const uint16_t UVDC_HT[12][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; +static const uint16_t YAC_HT[256][2] = { + {0x000A, 0x0004},{0x0000, 0x0002},{0x0001, 0x0002},{0x0004, 0x0003},{0x000B, 0x0004},{0x001A, 0x0005},{0x0078, 0x0007},{0x00F8, 0x0008}, + {0x03F6, 0x000A},{0xFF82, 0x0010},{0xFF83, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x000C, 0x0004},{0x001B, 0x0005},{0x0079, 0x0007},{0x01F6, 0x0009},{0x07F6, 0x000B},{0xFF84, 0x0010},{0xFF85, 0x0010}, + {0xFF86, 0x0010},{0xFF87, 0x0010},{0xFF88, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x001C, 0x0005},{0x00F9, 0x0008},{0x03F7, 0x000A},{0x0FF4, 0x000C},{0xFF89, 0x0010},{0xFF8A, 0x0010},{0xFF8B, 0x0010}, + {0xFF8C, 0x0010},{0xFF8D, 0x0010},{0xFF8E, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x003A, 0x0006},{0x01F7, 0x0009},{0x0FF5, 0x000C},{0xFF8F, 0x0010},{0xFF90, 0x0010},{0xFF91, 0x0010},{0xFF92, 0x0010}, + {0xFF93, 0x0010},{0xFF94, 0x0010},{0xFF95, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x003B, 0x0006},{0x03F8, 0x000A},{0xFF96, 0x0010},{0xFF97, 0x0010},{0xFF98, 0x0010},{0xFF99, 0x0010},{0xFF9A, 0x0010}, + {0xFF9B, 0x0010},{0xFF9C, 0x0010},{0xFF9D, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x007A, 0x0007},{0x07F7, 0x000B},{0xFF9E, 0x0010},{0xFF9F, 0x0010},{0xFFA0, 0x0010},{0xFFA1, 0x0010},{0xFFA2, 0x0010}, + {0xFFA3, 0x0010},{0xFFA4, 0x0010},{0xFFA5, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x007B, 0x0007},{0x0FF6, 0x000C},{0xFFA6, 0x0010},{0xFFA7, 0x0010},{0xFFA8, 0x0010},{0xFFA9, 0x0010},{0xFFAA, 0x0010}, + {0xFFAB, 0x0010},{0xFFAC, 0x0010},{0xFFAD, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x00FA, 0x0008},{0x0FF7, 0x000C},{0xFFAE, 0x0010},{0xFFAF, 0x0010},{0xFFB0, 0x0010},{0xFFB1, 0x0010},{0xFFB2, 0x0010}, + {0xFFB3, 0x0010},{0xFFB4, 0x0010},{0xFFB5, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01F8, 0x0009},{0x7FC0, 0x000F},{0xFFB6, 0x0010},{0xFFB7, 0x0010},{0xFFB8, 0x0010},{0xFFB9, 0x0010},{0xFFBA, 0x0010}, + {0xFFBB, 0x0010},{0xFFBC, 0x0010},{0xFFBD, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01F9, 0x0009},{0xFFBE, 0x0010},{0xFFBF, 0x0010},{0xFFC0, 0x0010},{0xFFC1, 0x0010},{0xFFC2, 0x0010},{0xFFC3, 0x0010}, + {0xFFC4, 0x0010},{0xFFC5, 0x0010},{0xFFC6, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01FA, 0x0009},{0xFFC7, 0x0010},{0xFFC8, 0x0010},{0xFFC9, 0x0010},{0xFFCA, 0x0010},{0xFFCB, 0x0010},{0xFFCC, 0x0010}, + {0xFFCD, 0x0010},{0xFFCE, 0x0010},{0xFFCF, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x03F9, 0x000A},{0xFFD0, 0x0010},{0xFFD1, 0x0010},{0xFFD2, 0x0010},{0xFFD3, 0x0010},{0xFFD4, 0x0010},{0xFFD5, 0x0010}, + {0xFFD6, 0x0010},{0xFFD7, 0x0010},{0xFFD8, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x03FA, 0x000A},{0xFFD9, 0x0010},{0xFFDA, 0x0010},{0xFFDB, 0x0010},{0xFFDC, 0x0010},{0xFFDD, 0x0010},{0xFFDE, 0x0010}, + {0xFFDF, 0x0010},{0xFFE0, 0x0010},{0xFFE1, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x07F8, 0x000B},{0xFFE2, 0x0010},{0xFFE3, 0x0010},{0xFFE4, 0x0010},{0xFFE5, 0x0010},{0xFFE6, 0x0010},{0xFFE7, 0x0010}, + {0xFFE8, 0x0010},{0xFFE9, 0x0010},{0xFFEA, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0xFFEB, 0x0010},{0xFFEC, 0x0010},{0xFFED, 0x0010},{0xFFEE, 0x0010},{0xFFEF, 0x0010},{0xFFF0, 0x0010},{0xFFF1, 0x0010}, + {0xFFF2, 0x0010},{0xFFF3, 0x0010},{0xFFF4, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x07F9, 0x000B},{0xFFF5, 0x0010},{0xFFF6, 0x0010},{0xFFF7, 0x0010},{0xFFF8, 0x0010},{0xFFF9, 0x0010},{0xFFFA, 0x0010},{0xFFFB, 0x0010}, + {0xFFFC, 0x0010},{0xFFFD, 0x0010},{0xFFFE, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, +}; + +static const uint16_t UVAC_HT[256][2] = { + {0x0000, 0x0002},{0x0001, 0x0002},{0x0004, 0x0003},{0x000A, 0x0004},{0x0018, 0x0005},{0x0019, 0x0005},{0x0038, 0x0006},{0x0078, 0x0007}, + {0x01F4, 0x0009},{0x03F6, 0x000A},{0x0FF4, 0x000C},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x000B, 0x0004},{0x0039, 0x0006},{0x00F6, 0x0008},{0x01F5, 0x0009},{0x07F6, 0x000B},{0x0FF5, 0x000C},{0xFF88, 0x0010}, + {0xFF89, 0x0010},{0xFF8A, 0x0010},{0xFF8B, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x001A, 0x0005},{0x00F7, 0x0008},{0x03F7, 0x000A},{0x0FF6, 0x000C},{0x7FC2, 0x000F},{0xFF8C, 0x0010},{0xFF8D, 0x0010}, + {0xFF8E, 0x0010},{0xFF8F, 0x0010},{0xFF90, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x001B, 0x0005},{0x00F8, 0x0008},{0x03F8, 0x000A},{0x0FF7, 0x000C},{0xFF91, 0x0010},{0xFF92, 0x0010},{0xFF93, 0x0010}, + {0xFF94, 0x0010},{0xFF95, 0x0010},{0xFF96, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x003A, 0x0006},{0x01F6, 0x0009},{0xFF97, 0x0010},{0xFF98, 0x0010},{0xFF99, 0x0010},{0xFF9A, 0x0010},{0xFF9B, 0x0010}, + {0xFF9C, 0x0010},{0xFF9D, 0x0010},{0xFF9E, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x003B, 0x0006},{0x03F9, 0x000A},{0xFF9F, 0x0010},{0xFFA0, 0x0010},{0xFFA1, 0x0010},{0xFFA2, 0x0010},{0xFFA3, 0x0010}, + {0xFFA4, 0x0010},{0xFFA5, 0x0010},{0xFFA6, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x0079, 0x0007},{0x07F7, 0x000B},{0xFFA7, 0x0010},{0xFFA8, 0x0010},{0xFFA9, 0x0010},{0xFFAA, 0x0010},{0xFFAB, 0x0010}, + {0xFFAC, 0x0010},{0xFFAD, 0x0010},{0xFFAE, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x007A, 0x0007},{0x07F8, 0x000B},{0xFFAF, 0x0010},{0xFFB0, 0x0010},{0xFFB1, 0x0010},{0xFFB2, 0x0010},{0xFFB3, 0x0010}, + {0xFFB4, 0x0010},{0xFFB5, 0x0010},{0xFFB6, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x00F9, 0x0008},{0xFFB7, 0x0010},{0xFFB8, 0x0010},{0xFFB9, 0x0010},{0xFFBA, 0x0010},{0xFFBB, 0x0010},{0xFFBC, 0x0010}, + {0xFFBD, 0x0010},{0xFFBE, 0x0010},{0xFFBF, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01F7, 0x0009},{0xFFC0, 0x0010},{0xFFC1, 0x0010},{0xFFC2, 0x0010},{0xFFC3, 0x0010},{0xFFC4, 0x0010},{0xFFC5, 0x0010}, + {0xFFC6, 0x0010},{0xFFC7, 0x0010},{0xFFC8, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01F8, 0x0009},{0xFFC9, 0x0010},{0xFFCA, 0x0010},{0xFFCB, 0x0010},{0xFFCC, 0x0010},{0xFFCD, 0x0010},{0xFFCE, 0x0010}, + {0xFFCF, 0x0010},{0xFFD0, 0x0010},{0xFFD1, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01F9, 0x0009},{0xFFD2, 0x0010},{0xFFD3, 0x0010},{0xFFD4, 0x0010},{0xFFD5, 0x0010},{0xFFD6, 0x0010},{0xFFD7, 0x0010}, + {0xFFD8, 0x0010},{0xFFD9, 0x0010},{0xFFDA, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x01FA, 0x0009},{0xFFDB, 0x0010},{0xFFDC, 0x0010},{0xFFDD, 0x0010},{0xFFDE, 0x0010},{0xFFDF, 0x0010},{0xFFE0, 0x0010}, + {0xFFE1, 0x0010},{0xFFE2, 0x0010},{0xFFE3, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x07F9, 0x000B},{0xFFE4, 0x0010},{0xFFE5, 0x0010},{0xFFE6, 0x0010},{0xFFE7, 0x0010},{0xFFE8, 0x0010},{0xFFE9, 0x0010}, + {0xFFEA, 0x0010},{0xFFEB, 0x0010},{0xFFEC, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x0000, 0x0000},{0x3FE0, 0x000E},{0xFFED, 0x0010},{0xFFEE, 0x0010},{0xFFEF, 0x0010},{0xFFF0, 0x0010},{0xFFF1, 0x0010},{0xFFF2, 0x0010}, + {0xFFF3, 0x0010},{0xFFF4, 0x0010},{0xFFF5, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, + {0x03FA, 0x000A},{0x7FC3, 0x000F},{0xFFF6, 0x0010},{0xFFF7, 0x0010},{0xFFF8, 0x0010},{0xFFF9, 0x0010},{0xFFFA, 0x0010},{0xFFFB, 0x0010}, + {0xFFFC, 0x0010},{0xFFFD, 0x0010},{0xFFFE, 0x0010},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000},{0x0000, 0x0000}, +}; + +static void jpeg_put_char(jpeg_buf_t *jpeg_buf, char c) +{ + if ((jpeg_buf->idx+1) >= jpeg_buf->length) { + if (jpeg_buf->realloc == false) { + // Can't realloc buffer + jpeg_buf->overflow = true; + return; + } + jpeg_buf->length += 1024; + jpeg_buf->buf = xrealloc(jpeg_buf->buf, jpeg_buf->length); + } + + jpeg_buf->buf[jpeg_buf->idx++]=c; +} + +static void jpeg_put_bytes(jpeg_buf_t *jpeg_buf, const void *data, int size) +{ + if ((jpeg_buf->idx+size) >= jpeg_buf->length) { + if (jpeg_buf->realloc == false) { + // Can't realloc buffer + jpeg_buf->overflow = true; + return; + } + jpeg_buf->length += 1024; + jpeg_buf->buf = xrealloc(jpeg_buf->buf, jpeg_buf->length); + } + + memcpy(jpeg_buf->buf+jpeg_buf->idx, data, size); + jpeg_buf->idx += size; +} + +static void jpeg_writeBits(jpeg_buf_t *jpeg_buf, const uint16_t *bs) +{ + jpeg_buf->bitc += bs[1]; + jpeg_buf->bitb |= bs[0] << (24 - jpeg_buf->bitc); + + while (jpeg_buf->bitc > 7) { + uint8_t c = (jpeg_buf->bitb >> 16) & 255; + jpeg_put_char(jpeg_buf, c); + if(c == 255) { + jpeg_put_char(jpeg_buf, 0); + } + jpeg_buf->bitb <<= 8; + jpeg_buf->bitc -= 8; + } +} + +//Huffman-encoded magnitude value +static void jpeg_calcBits(int val, uint16_t bits[2]) { + int t1=val; + if (val<0) { + t1 = -val; + val = val-1; + } + bits[1] = 32-__builtin_clz(t1); + bits[0] = val & ((1<0; i--, p+=8, CDU+=8) { + t0 = CDU[0] + CDU[7]; + t1 = CDU[1] + CDU[6]; + t2 = CDU[2] + CDU[5]; + t3 = CDU[3] + CDU[4]; + + t7 = CDU[0] - CDU[7]; + t6 = CDU[1] - CDU[6]; + t5 = CDU[2] - CDU[5]; + t4 = CDU[3] - CDU[4]; + + // Even part + t10 = t0 + t3; + t13 = t0 - t3; + t11 = t1 + t2; + t12 = t1 - t2; + z1 = MULTIPLY(t12 + t13, FIX_0_707106781); // c4 + + p[0] = t10 + t11; + p[4] = t10 - t11; + p[2] = t13 + z1; + p[6] = t13 - z1; + + // Odd part + t10 = t4 + t5;// phase 2 + t11 = t5 + t6; + t12 = t6 + t7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = MULTIPLY(t10 - t12, FIX_0_382683433); // c6 + z2 = MULTIPLY(t10, FIX_0_541196100) + z5; // 1.306562965f-c6 + z4 = MULTIPLY(t12, FIX_1_306562965) + z5; // 1.306562965f+c6 + z3 = MULTIPLY(t11, FIX_0_707106781); // c4 + z11 = t7 + z3; // phase 5 + z13 = t7 - z3; + + p[5] = z13 + z2;// phase 6 + p[3] = z13 - z2; + p[1] = z11 + z4; + p[7] = z11 - z4; + } + + // DCT columns + for (int i=8, *p=DU; i>0; i--, p++) { + t0 = p[0] + p[56]; + t1 = p[8] + p[48]; + t2 = p[16] + p[40]; + t3 = p[24] + p[32]; + + t7 = p[0] - p[56]; + t6 = p[8] - p[48]; + t5 = p[16] - p[40]; + t4 = p[24] - p[32]; + + // Even part + t10 = t0 + t3; // phase 2 + t13 = t0 - t3; + t11 = t1 + t2; + t12 = t1 - t2; + z1 = MULTIPLY(t12 + t13, FIX_0_707106781); // c4 + + p[0] = t10 + t11; // phase 3 + p[32] = t10 - t11; + p[16] = t13 + z1; // phase 5 + p[48] = t13 - z1; + + // Odd part + t10 = t4 + t5; // phase 2 + t11 = t5 + t6; + t12 = t6 + t7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = MULTIPLY(t10 - t12, FIX_0_382683433); // c6 + z2 = MULTIPLY(t10, FIX_0_541196100) + z5; // 1.306562965f-c6 + z4 = MULTIPLY(t12, FIX_1_306562965) + z5; // 1.306562965f+c6 + z3 = MULTIPLY(t11, FIX_0_707106781); // c4 + z11 = t7 + z3; // phase 5 + z13 = t7 - z3; + + p[40] = z13 + z2;// phase 6 + p[24] = z13 - z2; + p[8] = z11 + z4; + p[56] = z11 - z4; + } + + // first non-zero element in reverse order + int end0pos = 0; + // Quantize/descale/zigzag the coefficients + for(int i=0; i<64; ++i) { + DUQ[s_jpeg_ZigZag[i]] = fast_roundf(DU[i]*fdtbl[i]); + if (s_jpeg_ZigZag[i] > end0pos && DUQ[s_jpeg_ZigZag[i]]) { + end0pos = s_jpeg_ZigZag[i]; + } + } + + // Encode DC + int diff = DUQ[0] - DC; + if (diff == 0) { + jpeg_writeBits(jpeg_buf, HTDC[0]); + } else { + uint16_t bits[2]; + jpeg_calcBits(diff, bits); + jpeg_writeBits(jpeg_buf, HTDC[bits[1]]); + jpeg_writeBits(jpeg_buf, bits); + } + + // Encode ACs + if(end0pos == 0) { + jpeg_writeBits(jpeg_buf, EOB); + return DUQ[0]; + } + + for(int i = 1; i <= end0pos; ++i) { + int startpos = i; + for (; DUQ[i]==0 && i<=end0pos ; ++i) { + } + int nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + for (int nrmarker=1; nrmarker <= lng; ++nrmarker) + jpeg_writeBits(jpeg_buf, M16zeroes); + nrzeroes &= 15; + } + uint16_t bits[2]; + jpeg_calcBits(DUQ[i], bits); + jpeg_writeBits(jpeg_buf, HTAC[(nrzeroes<<4)+bits[1]]); + jpeg_writeBits(jpeg_buf, bits); + } + if(end0pos != 63) { + jpeg_writeBits(jpeg_buf, EOB); + } + return DUQ[0]; +} + +static void jpeg_init(int quality) +{ + static int q =0; + + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + // If quality changed, update quantization matrix + if (q != quality) { + q = quality; + for(int i = 0; i < 64; ++i) { + int yti = (YQT[i]*quality+50)/100; + YTable[s_jpeg_ZigZag[i]] = yti < 1 ? 1 : yti > 255 ? 255 : yti; + int uvti = (UVQT[i]*quality+50)/100; + UVTable[s_jpeg_ZigZag[i]] = uvti < 1 ? 1 : uvti > 255 ? 255 : uvti; + } + + for(int r = 0, k = 0; r < 8; ++r) { + for(int c = 0; c < 8; ++c, ++k) { + fdtbl_Y[k] = 1.0f / (aasf[r] * aasf[c] * YTable [s_jpeg_ZigZag[k]] * 8.0f); + fdtbl_UV[k] = 1.0f / (aasf[r] * aasf[c] * UVTable[s_jpeg_ZigZag[k]] * 8.0f); + } + } + } +} + +static void jpeg_write_headers(jpeg_buf_t *jpeg_buf, int w, int h, int bpp, jpeg_subsample_t jpeg_subsample) +{ + // Number of components (1 or 3) + uint8_t nr_comp = (bpp == 1)? 1 : 3; + + // JPEG headers + uint8_t m_soi[] = { + 0xFF, 0xD8 // SOI + }; + + uint8_t m_app0[] = { + 0xFF, 0xE0, // APP0 + 0x00, 0x10, 'J', 'F', 'I', 'F', 0x00, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00 + }; + + uint8_t m_dqt[] = { + 0xFF, 0xDB, // DQT + (bpp*65+2)>>8, // Header length MSB + (bpp*65+2)&0xFF, // Header length LSB + }; + + uint8_t m_sof0[] = { + 0xFF, 0xC0, // SOF0 + (nr_comp*3+8)>>8, // Header length MSB + (nr_comp*3+8)&0xFF, // Header length LSB + 0x08, // Bits per sample + h>>8, h&0xFF, // Height + w>>8, w&0xFF, // Width + nr_comp, // Number of components + }; + + uint8_t m_dht[] = { + 0xFF, 0xC4, // DHT + (bpp*208+2)>>8, // Header length MSB + (bpp*208+2)&0xFF, // Header length LSB + }; + + uint8_t m_sos[] = { + 0xFF, 0xDA, // SOS + (nr_comp*2+6)>>8, // Header length MSB + (nr_comp*2+6)&0xFF, // Header length LSB + nr_comp, // Number of components + }; + + // Write SOI marker + jpeg_put_bytes(jpeg_buf, m_soi, sizeof(m_soi)); + // Write APP0 marker + jpeg_put_bytes(jpeg_buf, m_app0, sizeof(m_app0)); + + // Write DQT marker + jpeg_put_bytes(jpeg_buf, m_dqt, sizeof(m_dqt)); + // Write Y quantization table (index, table) + jpeg_put_char (jpeg_buf, 0); + jpeg_put_bytes(jpeg_buf, YTable, sizeof(YTable)); + + if (bpp > 1) { + // Write UV quantization table (index, table) + jpeg_put_char (jpeg_buf, 1); + jpeg_put_bytes(jpeg_buf, UVTable, sizeof(UVTable)); + } + + // Write SOF0 marker + jpeg_put_bytes(jpeg_buf, m_sof0, sizeof(m_sof0)); + for (int i=0; i0)}, 3); + + } + + // Write DHT marker + jpeg_put_bytes(jpeg_buf, m_dht, sizeof(m_dht)); + + // Write DHT-YDC + jpeg_put_char (jpeg_buf, 0x00); + jpeg_put_bytes(jpeg_buf, std_dc_luminance_nrcodes+1, sizeof(std_dc_luminance_nrcodes)-1); + jpeg_put_bytes(jpeg_buf, std_dc_luminance_values, sizeof(std_dc_luminance_values)); + + // Write DHT-YAC + jpeg_put_char (jpeg_buf, 0x10); + jpeg_put_bytes(jpeg_buf, std_ac_luminance_nrcodes+1, sizeof(std_ac_luminance_nrcodes)-1); + jpeg_put_bytes(jpeg_buf, std_ac_luminance_values, sizeof(std_ac_luminance_values)); + + if (bpp > 1) { + // Write DHT-UDC + jpeg_put_char (jpeg_buf, 0x01); + jpeg_put_bytes(jpeg_buf, std_dc_chrominance_nrcodes+1, sizeof(std_dc_chrominance_nrcodes)-1); + jpeg_put_bytes(jpeg_buf, std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + + // Write DHT-UAC + jpeg_put_char (jpeg_buf, 0x11); + jpeg_put_bytes(jpeg_buf, std_ac_chrominance_nrcodes+1, sizeof(std_ac_chrominance_nrcodes)-1); + jpeg_put_bytes(jpeg_buf, std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + } + + // Write SOS marker + jpeg_put_bytes(jpeg_buf, m_sos, sizeof(m_sos)); + for (int i=0; ipixels, + .length = dst->bpp, + .bitc = 0, + .bitb = 0, + .realloc = realloc, + .overflow = false, + }; + + // Initialize quantization tables + jpeg_init(quality); + + jpeg_subsample_t jpeg_subsample; + + if (quality >= 60) { + jpeg_subsample = JPEG_SUBSAMPLE_1x1; + } else if (quality > 35) { + jpeg_subsample = JPEG_SUBSAMPLE_2x1; + } else { // <= 35 + jpeg_subsample = JPEG_SUBSAMPLE_2x2; + } + + // Write JPEG headers + if (src->bpp == 3) { // BAYER + // Will be converted to RGB565 + jpeg_write_headers(&jpeg_buf, src->w, src->h, 2, jpeg_subsample); + } else { + jpeg_write_headers(&jpeg_buf, src->w, src->h, (src->bpp == 0) ? 1 : src->bpp, jpeg_subsample); + } + + // Encode 8x8 macroblocks + if (src->bpp == 0) { + int8_t YDU[64]; + + // Copy 8x8 MCUs + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=8) { + for (int r=y, idx=0; rbpp == 1) { + int8_t YDU[64]; + uint8_t *pixels = (uint8_t *)src->pixels; + + // Copy 8x8 MCUs + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=8) { + for (int r=y, idx=0; rw+x; + YDU[idx + 0] = pixels[ofs + 0] - 128; + YDU[idx + 1] = pixels[ofs + 1] - 128; + YDU[idx + 2] = pixels[ofs + 2] - 128; + YDU[idx + 3] = pixels[ofs + 3] - 128; + YDU[idx + 4] = pixels[ofs + 4] - 128; + YDU[idx + 5] = pixels[ofs + 5] - 128; + YDU[idx + 6] = pixels[ofs + 6] - 128; + YDU[idx + 7] = pixels[ofs + 7] - 128; + } + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + } else if (src->bpp == 2) {// TODO assuming RGB565 + switch (jpeg_subsample) { + case JPEG_SUBSAMPLE_1x1: { + int8_t YDU[64], UDU[64], VDU[64]; + uint16_t *pixels = (uint16_t *)src->pixels; + + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=8) { + for (int r=y, pos=0; rw+x; + YDU[pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 0]; + UDU[pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 1]; + VDU[pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 2]; + + YDU[pos + 1] = yuv_table[pixels[ofs + 1] * 3 + 0]; + UDU[pos + 1] = yuv_table[pixels[ofs + 1] * 3 + 1]; + VDU[pos + 1] = yuv_table[pixels[ofs + 1] * 3 + 2]; + + YDU[pos + 2] = yuv_table[pixels[ofs + 2] * 3 + 0]; + UDU[pos + 2] = yuv_table[pixels[ofs + 2] * 3 + 1]; + VDU[pos + 2] = yuv_table[pixels[ofs + 2] * 3 + 2]; + + YDU[pos + 3] = yuv_table[pixels[ofs + 3] * 3 + 0]; + UDU[pos + 3] = yuv_table[pixels[ofs + 3] * 3 + 1]; + VDU[pos + 3] = yuv_table[pixels[ofs + 3] * 3 + 2]; + + YDU[pos + 4] = yuv_table[pixels[ofs + 4] * 3 + 0]; + UDU[pos + 4] = yuv_table[pixels[ofs + 4] * 3 + 1]; + VDU[pos + 4] = yuv_table[pixels[ofs + 4] * 3 + 2]; + + YDU[pos + 5] = yuv_table[pixels[ofs + 5] * 3 + 0]; + UDU[pos + 5] = yuv_table[pixels[ofs + 5] * 3 + 1]; + VDU[pos + 5] = yuv_table[pixels[ofs + 5] * 3 + 2]; + + YDU[pos + 6] = yuv_table[pixels[ofs + 6] * 3 + 0]; + UDU[pos + 6] = yuv_table[pixels[ofs + 6] * 3 + 1]; + VDU[pos + 6] = yuv_table[pixels[ofs + 6] * 3 + 2]; + + YDU[pos + 7] = yuv_table[pixels[ofs + 7] * 3 + 0]; + UDU[pos + 7] = yuv_table[pixels[ofs + 7] * 3 + 1]; + VDU[pos + 7] = yuv_table[pixels[ofs + 7] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + case JPEG_SUBSAMPLE_2x1: { + int8_t YDU[128], UDU[64], VDU[64]; + uint16_t *pixels = (uint16_t *)src->pixels; + + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=16) { + for (int r=y, v_pos=0, uv_pos=0; rw+x; + YDU[v_pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 0]; + YDU[v_pos + 1] = yuv_table[pixels[ofs + 1] * 3 + 0]; + YDU[v_pos + 2] = yuv_table[pixels[ofs + 2] * 3 + 0]; + YDU[v_pos + 3] = yuv_table[pixels[ofs + 3] * 3 + 0]; + YDU[v_pos + 4] = yuv_table[pixels[ofs + 4] * 3 + 0]; + YDU[v_pos + 5] = yuv_table[pixels[ofs + 5] * 3 + 0]; + YDU[v_pos + 6] = yuv_table[pixels[ofs + 6] * 3 + 0]; + YDU[v_pos + 7] = yuv_table[pixels[ofs + 7] * 3 + 0]; + + YDU[v_pos + 0 + 64] = yuv_table[pixels[ofs + 8 + 0] * 3 + 0]; + YDU[v_pos + 1 + 64] = yuv_table[pixels[ofs + 8 + 1] * 3 + 0]; + YDU[v_pos + 2 + 64] = yuv_table[pixels[ofs + 8 + 2] * 3 + 0]; + YDU[v_pos + 3 + 64] = yuv_table[pixels[ofs + 8 + 3] * 3 + 0]; + YDU[v_pos + 4 + 64] = yuv_table[pixels[ofs + 8 + 4] * 3 + 0]; + YDU[v_pos + 5 + 64] = yuv_table[pixels[ofs + 8 + 5] * 3 + 0]; + YDU[v_pos + 6 + 64] = yuv_table[pixels[ofs + 8 + 6] * 3 + 0]; + YDU[v_pos + 7 + 64] = yuv_table[pixels[ofs + 8 + 7] * 3 + 0]; + + // Just toss the old UV pixels (could average for better quality) + UDU[uv_pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 1]; + UDU[uv_pos + 1] = yuv_table[pixels[ofs + 2] * 3 + 1]; + UDU[uv_pos + 2] = yuv_table[pixels[ofs + 4] * 3 + 1]; + UDU[uv_pos + 3] = yuv_table[pixels[ofs + 6] * 3 + 1]; + UDU[uv_pos + 4] = yuv_table[pixels[ofs + 8] * 3 + 1]; + UDU[uv_pos + 5] = yuv_table[pixels[ofs +10] * 3 + 1]; + UDU[uv_pos + 6] = yuv_table[pixels[ofs +12] * 3 + 1]; + UDU[uv_pos + 7] = yuv_table[pixels[ofs +14] * 3 + 1]; + + VDU[uv_pos + 0] = yuv_table[pixels[ofs + 0] * 3 + 2]; + VDU[uv_pos + 1] = yuv_table[pixels[ofs + 2] * 3 + 2]; + VDU[uv_pos + 2] = yuv_table[pixels[ofs + 4] * 3 + 2]; + VDU[uv_pos + 3] = yuv_table[pixels[ofs + 6] * 3 + 2]; + VDU[uv_pos + 4] = yuv_table[pixels[ofs + 8] * 3 + 2]; + VDU[uv_pos + 5] = yuv_table[pixels[ofs +10] * 3 + 2]; + VDU[uv_pos + 6] = yuv_table[pixels[ofs +12] * 3 + 2]; + VDU[uv_pos + 7] = yuv_table[pixels[ofs +14] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+64, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + case JPEG_SUBSAMPLE_2x2: { + int8_t YDU[256], UDU[64], VDU[64]; + uint16_t *pixels = (uint16_t *)src->pixels; + + for (int y=0; yh; y+=16) { + for (int x=0; xw; x+=16) { + for (int i=0, r=y, idx=0; rw+x; + YDU[idx + 0] = yuv_table[pixels[ofs + 0] * 3 + 0]; + YDU[idx + 1] = yuv_table[pixels[ofs + 1] * 3 + 0]; + YDU[idx + 2] = yuv_table[pixels[ofs + 2] * 3 + 0]; + YDU[idx + 3] = yuv_table[pixels[ofs + 3] * 3 + 0]; + YDU[idx + 4] = yuv_table[pixels[ofs + 4] * 3 + 0]; + YDU[idx + 5] = yuv_table[pixels[ofs + 5] * 3 + 0]; + YDU[idx + 6] = yuv_table[pixels[ofs + 6] * 3 + 0]; + YDU[idx + 7] = yuv_table[pixels[ofs + 7] * 3 + 0]; + + YDU[idx + 0 + 64] = yuv_table[pixels[ofs + 0 + 8] * 3 + 0]; + YDU[idx + 1 + 64] = yuv_table[pixels[ofs + 1 + 8] * 3 + 0]; + YDU[idx + 2 + 64] = yuv_table[pixels[ofs + 2 + 8] * 3 + 0]; + YDU[idx + 3 + 64] = yuv_table[pixels[ofs + 3 + 8] * 3 + 0]; + YDU[idx + 4 + 64] = yuv_table[pixels[ofs + 4 + 8] * 3 + 0]; + YDU[idx + 5 + 64] = yuv_table[pixels[ofs + 5 + 8] * 3 + 0]; + YDU[idx + 6 + 64] = yuv_table[pixels[ofs + 6 + 8] * 3 + 0]; + YDU[idx + 7 + 64] = yuv_table[pixels[ofs + 7 + 8] * 3 + 0]; + + ofs = (r+8)*src->w+x; + YDU[idx + 0 + 128] = yuv_table[pixels[ofs + 0] * 3 + 0]; + YDU[idx + 1 + 128] = yuv_table[pixels[ofs + 1] * 3 + 0]; + YDU[idx + 2 + 128] = yuv_table[pixels[ofs + 2] * 3 + 0]; + YDU[idx + 3 + 128] = yuv_table[pixels[ofs + 3] * 3 + 0]; + YDU[idx + 4 + 128] = yuv_table[pixels[ofs + 4] * 3 + 0]; + YDU[idx + 5 + 128] = yuv_table[pixels[ofs + 5] * 3 + 0]; + YDU[idx + 6 + 128] = yuv_table[pixels[ofs + 6] * 3 + 0]; + YDU[idx + 7 + 128] = yuv_table[pixels[ofs + 7] * 3 + 0]; + + YDU[idx + 0 + 192] = yuv_table[pixels[ofs + 0 + 8] * 3 + 0]; + YDU[idx + 1 + 192] = yuv_table[pixels[ofs + 1 + 8] * 3 + 0]; + YDU[idx + 2 + 192] = yuv_table[pixels[ofs + 2 + 8] * 3 + 0]; + YDU[idx + 3 + 192] = yuv_table[pixels[ofs + 3 + 8] * 3 + 0]; + YDU[idx + 4 + 192] = yuv_table[pixels[ofs + 4 + 8] * 3 + 0]; + YDU[idx + 5 + 192] = yuv_table[pixels[ofs + 5 + 8] * 3 + 0]; + YDU[idx + 6 + 192] = yuv_table[pixels[ofs + 6 + 8] * 3 + 0]; + YDU[idx + 7 + 192] = yuv_table[pixels[ofs + 7 + 8] * 3 + 0]; + + ofs = (y+i*2)*src->w+x; + // Just toss the odd U/V pixels (could average for better quality) + UDU[idx + 0] = yuv_table[pixels[ofs + 0] * 3 + 1]; + UDU[idx + 1] = yuv_table[pixels[ofs + 2] * 3 + 1]; + UDU[idx + 2] = yuv_table[pixels[ofs + 4] * 3 + 1]; + UDU[idx + 3] = yuv_table[pixels[ofs + 6] * 3 + 1]; + UDU[idx + 4] = yuv_table[pixels[ofs + 8] * 3 + 1]; + UDU[idx + 5] = yuv_table[pixels[ofs +10] * 3 + 1]; + UDU[idx + 6] = yuv_table[pixels[ofs +12] * 3 + 1]; + UDU[idx + 7] = yuv_table[pixels[ofs +14] * 3 + 1]; + + VDU[idx + 0] = yuv_table[pixels[ofs + 0] * 3 + 2]; + VDU[idx + 1] = yuv_table[pixels[ofs + 2] * 3 + 2]; + VDU[idx + 2] = yuv_table[pixels[ofs + 4] * 3 + 2]; + VDU[idx + 3] = yuv_table[pixels[ofs + 6] * 3 + 2]; + VDU[idx + 4] = yuv_table[pixels[ofs + 8] * 3 + 2]; + VDU[idx + 5] = yuv_table[pixels[ofs +10] * 3 + 2]; + VDU[idx + 6] = yuv_table[pixels[ofs +12] * 3 + 2]; + VDU[idx + 7] = yuv_table[pixels[ofs +14] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+64, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+128, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+192, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + } + } else if (src->bpp == 3) { //RAW/BAYER + switch (jpeg_subsample) { + case JPEG_SUBSAMPLE_1x1: { + int8_t YDU[64], UDU[64], VDU[64]; + uint16_t rgbbuf[64]; + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=8) { + imlib_bayer_to_rgb565(src, 8, 8, x, y, rgbbuf); + for (int r=0, idx=0; r<8; r++, idx+=8) { + YDU[idx + 0] = yuv_table[rgbbuf[idx + 0] * 3 + 0]; + UDU[idx + 0] = yuv_table[rgbbuf[idx + 0] * 3 + 1]; + VDU[idx + 0] = yuv_table[rgbbuf[idx + 0] * 3 + 2]; + + YDU[idx + 1] = yuv_table[rgbbuf[idx + 1] * 3 + 0]; + UDU[idx + 1] = yuv_table[rgbbuf[idx + 1] * 3 + 1]; + VDU[idx + 1] = yuv_table[rgbbuf[idx + 1] * 3 + 2]; + + YDU[idx + 2] = yuv_table[rgbbuf[idx + 2] * 3 + 0]; + UDU[idx + 2] = yuv_table[rgbbuf[idx + 2] * 3 + 1]; + VDU[idx + 2] = yuv_table[rgbbuf[idx + 2] * 3 + 2]; + + YDU[idx + 3] = yuv_table[rgbbuf[idx + 3] * 3 + 0]; + UDU[idx + 3] = yuv_table[rgbbuf[idx + 3] * 3 + 1]; + VDU[idx + 3] = yuv_table[rgbbuf[idx + 3] * 3 + 2]; + + YDU[idx + 4] = yuv_table[rgbbuf[idx + 4] * 3 + 0]; + UDU[idx + 4] = yuv_table[rgbbuf[idx + 4] * 3 + 1]; + VDU[idx + 4] = yuv_table[rgbbuf[idx + 4] * 3 + 2]; + + YDU[idx + 5] = yuv_table[rgbbuf[idx + 5] * 3 + 0]; + UDU[idx + 5] = yuv_table[rgbbuf[idx + 5] * 3 + 1]; + VDU[idx + 5] = yuv_table[rgbbuf[idx + 5] * 3 + 2]; + + YDU[idx + 6] = yuv_table[rgbbuf[idx + 6] * 3 + 0]; + UDU[idx + 6] = yuv_table[rgbbuf[idx + 6] * 3 + 1]; + VDU[idx + 6] = yuv_table[rgbbuf[idx + 6] * 3 + 2]; + + YDU[idx + 7] = yuv_table[rgbbuf[idx + 7] * 3 + 0]; + UDU[idx + 7] = yuv_table[rgbbuf[idx + 7] * 3 + 1]; + VDU[idx + 7] = yuv_table[rgbbuf[idx + 7] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + case JPEG_SUBSAMPLE_2x1: { + uint16_t rgbbuf[128]; + int8_t YDU[128], UDU[64], VDU[64]; + + for (int y=0; yh; y+=8) { + for (int x=0; xw; x+=16) { + imlib_bayer_to_rgb565(src, 16, 8, x, y, rgbbuf); + for (int r=0, idx=0, ofs=0; r<8; r++, idx+=8, ofs+=16) { + YDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 0]; + YDU[idx + 1] = yuv_table[rgbbuf[ofs + 1] * 3 + 0]; + YDU[idx + 2] = yuv_table[rgbbuf[ofs + 2] * 3 + 0]; + YDU[idx + 3] = yuv_table[rgbbuf[ofs + 3] * 3 + 0]; + YDU[idx + 4] = yuv_table[rgbbuf[ofs + 4] * 3 + 0]; + YDU[idx + 5] = yuv_table[rgbbuf[ofs + 5] * 3 + 0]; + YDU[idx + 6] = yuv_table[rgbbuf[ofs + 6] * 3 + 0]; + YDU[idx + 7] = yuv_table[rgbbuf[ofs + 7] * 3 + 0]; + + YDU[idx + 0 + 64] = yuv_table[rgbbuf[ofs + 8] * 3 + 0]; + YDU[idx + 1 + 64] = yuv_table[rgbbuf[ofs + 9] * 3 + 0]; + YDU[idx + 2 + 64] = yuv_table[rgbbuf[ofs +10] * 3 + 0]; + YDU[idx + 3 + 64] = yuv_table[rgbbuf[ofs +11] * 3 + 0]; + YDU[idx + 4 + 64] = yuv_table[rgbbuf[ofs +12] * 3 + 0]; + YDU[idx + 5 + 64] = yuv_table[rgbbuf[ofs +13] * 3 + 0]; + YDU[idx + 6 + 64] = yuv_table[rgbbuf[ofs +14] * 3 + 0]; + YDU[idx + 7 + 64] = yuv_table[rgbbuf[ofs +15] * 3 + 0]; + + // Just toss the old UV pixels (could average for better quality) + UDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 1]; + UDU[idx + 1] = yuv_table[rgbbuf[ofs + 2] * 3 + 1]; + UDU[idx + 2] = yuv_table[rgbbuf[ofs + 4] * 3 + 1]; + UDU[idx + 3] = yuv_table[rgbbuf[ofs + 6] * 3 + 1]; + UDU[idx + 4] = yuv_table[rgbbuf[ofs + 8] * 3 + 1]; + UDU[idx + 5] = yuv_table[rgbbuf[ofs +10] * 3 + 1]; + UDU[idx + 6] = yuv_table[rgbbuf[ofs +12] * 3 + 1]; + UDU[idx + 7] = yuv_table[rgbbuf[ofs +14] * 3 + 1]; + + VDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 2]; + VDU[idx + 1] = yuv_table[rgbbuf[ofs + 2] * 3 + 2]; + VDU[idx + 2] = yuv_table[rgbbuf[ofs + 4] * 3 + 2]; + VDU[idx + 3] = yuv_table[rgbbuf[ofs + 6] * 3 + 2]; + VDU[idx + 4] = yuv_table[rgbbuf[ofs + 8] * 3 + 2]; + VDU[idx + 5] = yuv_table[rgbbuf[ofs +10] * 3 + 2]; + VDU[idx + 6] = yuv_table[rgbbuf[ofs +12] * 3 + 2]; + VDU[idx + 7] = yuv_table[rgbbuf[ofs +14] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+64, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + case JPEG_SUBSAMPLE_2x2: { + uint16_t rgbbuf[256]; + int8_t YDU[256], UDU[64], VDU[64]; + + for (int y=0; yh; y+=16) { + for (int x=0; xw; x+=16) { + imlib_bayer_to_rgb565(src, 16, 16, x, y, rgbbuf); + for (int r=0, idx=0; r<8; r++, idx+=8) { + int ofs = r*16; + YDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 0]; + YDU[idx + 1] = yuv_table[rgbbuf[ofs + 1] * 3 + 0]; + YDU[idx + 2] = yuv_table[rgbbuf[ofs + 2] * 3 + 0]; + YDU[idx + 3] = yuv_table[rgbbuf[ofs + 3] * 3 + 0]; + YDU[idx + 4] = yuv_table[rgbbuf[ofs + 4] * 3 + 0]; + YDU[idx + 5] = yuv_table[rgbbuf[ofs + 5] * 3 + 0]; + YDU[idx + 6] = yuv_table[rgbbuf[ofs + 6] * 3 + 0]; + YDU[idx + 7] = yuv_table[rgbbuf[ofs + 7] * 3 + 0]; + + YDU[idx + 0 + 64] = yuv_table[rgbbuf[ofs + 8] * 3 + 0]; + YDU[idx + 1 + 64] = yuv_table[rgbbuf[ofs + 9] * 3 + 0]; + YDU[idx + 2 + 64] = yuv_table[rgbbuf[ofs +10] * 3 + 0]; + YDU[idx + 3 + 64] = yuv_table[rgbbuf[ofs +11] * 3 + 0]; + YDU[idx + 4 + 64] = yuv_table[rgbbuf[ofs +12] * 3 + 0]; + YDU[idx + 5 + 64] = yuv_table[rgbbuf[ofs +13] * 3 + 0]; + YDU[idx + 6 + 64] = yuv_table[rgbbuf[ofs +14] * 3 + 0]; + YDU[idx + 7 + 64] = yuv_table[rgbbuf[ofs +15] * 3 + 0]; + + ofs = (r+8)*16; + YDU[idx + 0 + 128] = yuv_table[rgbbuf[ofs + 0] * 3 + 0]; + YDU[idx + 1 + 128] = yuv_table[rgbbuf[ofs + 1] * 3 + 0]; + YDU[idx + 2 + 128] = yuv_table[rgbbuf[ofs + 2] * 3 + 0]; + YDU[idx + 3 + 128] = yuv_table[rgbbuf[ofs + 3] * 3 + 0]; + YDU[idx + 4 + 128] = yuv_table[rgbbuf[ofs + 4] * 3 + 0]; + YDU[idx + 5 + 128] = yuv_table[rgbbuf[ofs + 5] * 3 + 0]; + YDU[idx + 6 + 128] = yuv_table[rgbbuf[ofs + 6] * 3 + 0]; + YDU[idx + 7 + 128] = yuv_table[rgbbuf[ofs + 7] * 3 + 0]; + + YDU[idx + 0 + 192] = yuv_table[rgbbuf[ofs + 8] * 3 + 0]; + YDU[idx + 1 + 192] = yuv_table[rgbbuf[ofs + 9] * 3 + 0]; + YDU[idx + 2 + 192] = yuv_table[rgbbuf[ofs +10] * 3 + 0]; + YDU[idx + 3 + 192] = yuv_table[rgbbuf[ofs +11] * 3 + 0]; + YDU[idx + 4 + 192] = yuv_table[rgbbuf[ofs +12] * 3 + 0]; + YDU[idx + 5 + 192] = yuv_table[rgbbuf[ofs +13] * 3 + 0]; + YDU[idx + 6 + 192] = yuv_table[rgbbuf[ofs +14] * 3 + 0]; + YDU[idx + 7 + 192] = yuv_table[rgbbuf[ofs +15] * 3 + 0]; + + ofs = (r*2)*16; + // Just toss the odd U/V pixels (could average for better quality) + UDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 1]; + UDU[idx + 1] = yuv_table[rgbbuf[ofs + 2] * 3 + 1]; + UDU[idx + 2] = yuv_table[rgbbuf[ofs + 4] * 3 + 1]; + UDU[idx + 3] = yuv_table[rgbbuf[ofs + 6] * 3 + 1]; + UDU[idx + 4] = yuv_table[rgbbuf[ofs + 8] * 3 + 1]; + UDU[idx + 5] = yuv_table[rgbbuf[ofs +10] * 3 + 1]; + UDU[idx + 6] = yuv_table[rgbbuf[ofs +12] * 3 + 1]; + UDU[idx + 7] = yuv_table[rgbbuf[ofs +14] * 3 + 1]; + + VDU[idx + 0] = yuv_table[rgbbuf[ofs + 0] * 3 + 2]; + VDU[idx + 1] = yuv_table[rgbbuf[ofs + 2] * 3 + 2]; + VDU[idx + 2] = yuv_table[rgbbuf[ofs + 4] * 3 + 2]; + VDU[idx + 3] = yuv_table[rgbbuf[ofs + 6] * 3 + 2]; + VDU[idx + 4] = yuv_table[rgbbuf[ofs + 8] * 3 + 2]; + VDU[idx + 5] = yuv_table[rgbbuf[ofs +10] * 3 + 2]; + VDU[idx + 6] = yuv_table[rgbbuf[ofs +12] * 3 + 2]; + VDU[idx + 7] = yuv_table[rgbbuf[ofs +14] * 3 + 2]; + } + + DCY = jpeg_processDU(&jpeg_buf, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+64, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+128, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = jpeg_processDU(&jpeg_buf, YDU+192, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = jpeg_processDU(&jpeg_buf, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = jpeg_processDU(&jpeg_buf, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + if (jpeg_buf.overflow) { + goto jpeg_overflow; + } + } + break; + } + } + } + + + // Do the bit alignment of the EOI marker + static const uint16_t fillBits[] = {0x7F, 7}; + jpeg_writeBits(&jpeg_buf, fillBits); + + // EOI + jpeg_put_char(&jpeg_buf, 0xFF); + jpeg_put_char(&jpeg_buf, 0xD9); + + dst->bpp = jpeg_buf.idx; + dst->data = jpeg_buf.buf; + + #if (TIME_JPEG==1) + printf("time: %lums\n", HAL_GetTick() - start); + #endif + +jpeg_overflow: + return jpeg_buf.overflow; +} +#endif //defined OMV_HARDWARE_JPEG + +// This function inits the geometry values of an image. +void jpeg_read_geometry(FIL *fp, image_t *img, const char *path) +{ + for (;;) { + uint16_t header; + read_word(fp, &header); + header = IM_SWAP16(header); + if ((0xFFD0 <= header) && (header <= 0xFFD9)) { + continue; + } else if (((0xFFC0 <= header) && (header <= 0xFFCF)) + || ((0xFFDA <= header) && (header <= 0xFFDF)) + || ((0xFFE0 <= header) && (header <= 0xFFEF)) + || ((0xFFF0 <= header) && (header <= 0xFFFE))) + { + uint16_t size; + read_word(fp, &size); + size = IM_SWAP16(size); + if (((0xFFC0 <= header) && (header <= 0xFFC3)) + || ((0xFFC5 <= header) && (header <= 0xFFC7)) + || ((0xFFC9 <= header) && (header <= 0xFFCB)) + || ((0xFFCD <= header) && (header <= 0xFFCF))) + { + read_byte_ignore(fp); + uint16_t width; + read_word(fp, &width); + width = IM_SWAP16(width); + uint16_t height; + read_word(fp, &height); + height = IM_SWAP16(height); + img->w = width; + img->h = height; + img->bpp = f_size(fp); + return; + } else { + file_seek(fp, f_tell(fp) + size - 2); + } + } else { + ff_file_corrupted(fp); + } + } +} + +// This function reads the pixel values of an image. +void jpeg_read_pixels(FIL *fp, image_t *img) +{ + file_seek(fp, 0); + read_data(fp, img->pixels, img->bpp); +} + +void jpeg_read(image_t *img, const char *path) +{ + FIL fp; + file_read_open(&fp, path); + // Do not use file_buffer_on() here. + jpeg_read_geometry(&fp, img, path); + if (!img->pixels) img->pixels = xalloc(img->bpp); + jpeg_read_pixels(&fp, img); + // Do not use file_buffer_off() here. + file_close(&fp); +} + +void jpeg_write(image_t *img, const char *path, int quality) +{ + FIL fp; + file_write_open(&fp, path); + if (IM_IS_JPEG(img)) { + write_data(&fp, img->pixels, img->bpp); + } else { + uint32_t size; + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=img->w, .h=img->h, .bpp=size, .pixels=buffer }; + // When jpeg_compress needs more memory than in currently allocated it + // will try to realloc. MP will detect that the pointer is outside of + // the heap and return NULL which will cause an out of memory error. + jpeg_compress(img, &out, quality, false); + write_data(&fp, out.pixels, out.bpp); + fb_free(); + } + file_close(&fp); +} diff --git a/src/openmv/src/omv/img/kmeans.c b/src/openmv/src/omv/img/kmeans.c new file mode 100755 index 0000000..718e1e1 --- /dev/null +++ b/src/openmv/src/omv/img/kmeans.c @@ -0,0 +1,138 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Kmeans clustering. + * + */ +#include +#include +#include +#include "imlib.h" +#include "array.h" +#include "xalloc.h" + +extern uint32_t rng_randint(uint32_t min, uint32_t max); + +static cluster_t *cluster_alloc(int cx, int cy) +{ + cluster_t *c=NULL; + c = xalloc(sizeof(*c)); + if (c != NULL) { + c->x = cx; + c->y = cy; + c->w = 0; + c->h = 0; + array_alloc(&c->points, NULL); + } + return c; +} + +static void cluster_free(void *c) +{ + cluster_t *cl = c; + array_free(cl->points); + xfree(cl); +} + +static void cluster_reset(array_t *clusters, array_t *points) +{ + // Reset all clusters + for (int j=0; jpoints)) { + array_push_back(points, array_pop_back(cl->points)); + } + array_free(cl->points); + array_alloc(&cl->points, NULL); + } +} + +static int cluster_update(array_t *clusters) +{ + // Update clusters + for (int j=0; jx, cy = cl->y; + int cl_size = array_length(cl->points); + + // Sum all points in this cluster + for (int i=0; ipoints, i); + cl->x += p->x; + cl->y += p->y; + // Find out the max x and y while we're at it + if (p->x > cl->w) { + cl->w = p->x; + } + if (p->y > cl->h) { + cl->h = p->y; + } + } + + // Update centroid + cl->x = cl->x/cl_size; + cl->y = cl->y/cl_size; + // Update cluster size + cl->w = (cl->w - cl->x) * 2; + cl->h = (cl->h - cl->y) * 2; + if (cl->x == cx && cl->y == cy) { + // Cluster centroid did not change + return 0; + } + } + + return 1; +} + +static void cluster_points(array_t *clusters, array_t *points, cluster_dist_t dist_func) +{ + // Add objects to cluster + while (array_length(points)) { + float distance = FLT_MAX; + cluster_t *cl_nearest = NULL; + kp_t *p = array_pop_back(points); + + for (int j=0; jx, cl->y, p); + if (d < distance) { + distance = d; + cl_nearest = cl; + } + } + // Add pointer to point to cluster. + // Note: Objects in the cluster are not free'd + array_push_back(cl_nearest->points, p); + } +} + +array_t *cluster_kmeans(array_t *points, int k, cluster_dist_t dist_func) +{ + // Alloc clusters array + array_t *clusters=NULL; + array_alloc(&clusters, cluster_free); + + // Select K clusters randomly + for (int i=0; ix, p->y)); + } + + int cl_changed = 1; + do { + // Reset clusters + cluster_reset(clusters, points); + + // Add points to clusters + cluster_points(clusters, points, dist_func); + + // Update centroids + cl_changed = cluster_update(clusters); + + } while (cl_changed); + + return clusters; +} diff --git a/src/openmv/src/omv/img/lab_tab.c b/src/openmv/src/omv/img/lab_tab.c new file mode 100755 index 0000000..c65d229 --- /dev/null +++ b/src/openmv/src/omv/img/lab_tab.c @@ -0,0 +1,16387 @@ +#include +const int8_t lab_table[196608] = { + 0, 0, 0, 9, -19, 14, 23, -32, 31, 35, -42, 41, + 47, -52, 50, 58, -61, 59, 68, -70, 68, 79, -79, 76, + 0, 2, 1, 10, -16, 14, 23, -31, 31, 35, -42, 41, + 47, -52, 51, 58, -61, 59, 68, -70, 68, 79, -79, 76, + 1, 4, 2, 10, -14, 15, 23, -29, 31, 35, -40, 41, + 47, -51, 51, 58, -60, 59, 69, -69, 68, 79, -78, 76, + 2, 8, 3, 11, -9, 16, 24, -26, 31, 36, -39, 41, + 47, -50, 51, 58, -60, 59, 69, -69, 68, 79, -78, 76, + 3, 13, 5, 12, -5, 17, 24, -23, 32, 36, -37, 42, + 47, -49, 51, 58, -59, 60, 69, -68, 68, 79, -77, 76, + 4, 19, 7, 13, 0, 19, 24, -20, 33, 36, -35, 42, + 48, -47, 51, 58, -57, 60, 69, -67, 68, 79, -76, 77, + 6, 24, 9, 14, 5, 20, 25, -16, 33, 36, -32, 43, + 48, -45, 51, 59, -56, 60, 69, -66, 68, 79, -76, 77, + 8, 28, 13, 15, 10, 22, 26, -12, 34, 37, -28, 43, + 48, -42, 52, 59, -54, 60, 69, -64, 69, 80, -74, 77, + 10, 30, 16, 16, 14, 24, 27, -8, 35, 37, -25, 44, + 48, -40, 52, 59, -52, 61, 69, -63, 69, 80, -73, 77, + 12, 33, 19, 18, 18, 26, 27, -3, 36, 38, -22, 44, + 49, -37, 53, 59, -50, 61, 69, -61, 69, 80, -72, 77, + 14, 35, 22, 19, 22, 29, 28, 1, 37, 38, -18, 45, + 49, -34, 53, 60, -47, 61, 70, -59, 69, 80, -70, 77, + 16, 37, 25, 21, 25, 31, 29, 5, 39, 39, -14, 46, + 50, -31, 54, 60, -45, 62, 70, -57, 70, 80, -68, 78, + 19, 40, 29, 23, 29, 33, 30, 10, 40, 40, -10, 47, + 50, -27, 54, 60, -42, 62, 70, -54, 70, 81, -66, 78, + 21, 42, 31, 24, 32, 35, 32, 14, 41, 41, -6, 48, + 51, -24, 55, 61, -39, 63, 71, -52, 70, 81, -64, 78, + 22, 45, 34, 26, 35, 37, 33, 17, 43, 42, -2, 49, + 51, -20, 56, 61, -35, 63, 71, -49, 71, 81, -62, 79, + 24, 47, 37, 27, 38, 39, 34, 21, 44, 42, 2, 50, + 52, -16, 57, 62, -32, 64, 71, -46, 71, 81, -59, 79, + 26, 49, 39, 29, 41, 42, 35, 25, 46, 43, 7, 51, + 53, -12, 58, 62, -28, 65, 72, -43, 72, 82, -56, 80, + 28, 51, 42, 31, 44, 44, 37, 29, 47, 44, 10, 52, + 54, -8, 58, 63, -25, 65, 72, -40, 72, 82, -54, 80, + 30, 53, 44, 33, 47, 45, 38, 32, 49, 45, 14, 53, + 54, -5, 59, 63, -22, 66, 73, -37, 73, 83, -51, 80, + 32, 55, 46, 34, 49, 47, 39, 35, 50, 46, 18, 54, + 55, -1, 60, 64, -18, 67, 73, -34, 74, 83, -48, 81, + 34, 58, 48, 36, 52, 49, 41, 39, 52, 48, 22, 56, + 56, 3, 61, 65, -14, 68, 74, -30, 74, 83, -45, 82, + 36, 60, 50, 38, 54, 51, 42, 42, 53, 49, 25, 57, + 57, 7, 62, 66, -10, 68, 74, -27, 75, 84, -42, 82, + 38, 62, 52, 39, 57, 53, 44, 45, 55, 50, 29, 58, + 58, 11, 63, 66, -7, 69, 75, -23, 76, 84, -39, 83, + 39, 64, 54, 41, 59, 54, 45, 48, 56, 51, 32, 60, + 59, 14, 64, 67, -3, 70, 76, -20, 76, 85, -35, 83, + 41, 66, 55, 43, 61, 56, 47, 51, 58, 52, 35, 61, + 60, 18, 66, 68, 0, 71, 76, -16, 77, 85, -32, 84, + 43, 68, 57, 44, 64, 58, 48, 54, 59, 54, 39, 62, + 61, 22, 67, 69, 4, 72, 77, -12, 78, 86, -28, 85, + 45, 70, 59, 46, 66, 59, 50, 56, 61, 55, 42, 64, + 62, 25, 68, 70, 8, 73, 78, -9, 79, 87, -25, 85, + 46, 72, 61, 48, 68, 61, 51, 59, 62, 56, 45, 65, + 63, 29, 69, 70, 11, 74, 79, -5, 80, 87, -22, 86, + 48, 74, 62, 49, 70, 63, 53, 61, 64, 57, 48, 67, + 64, 32, 70, 71, 15, 75, 79, -2, 81, 88, -18, 87, + 50, 76, 64, 51, 73, 64, 54, 64, 66, 59, 52, 68, + 65, 35, 72, 72, 19, 76, 80, 2, 82, 89, -15, 88, + 52, 78, 66, 53, 75, 66, 56, 67, 67, 60, 54, 69, + 66, 39, 73, 73, 22, 77, 81, 5, 83, 89, -11, 88, + 53, 80, 67, 54, 77, 68, 57, 69, 69, 61, 57, 71, + 67, 42, 74, 74, 25, 79, 82, 9, 84, 90, -8, 89, + 0, 1, -3, 9, -18, 10, 23, -32, 27, 35, -42, 39, + 47, -52, 49, 58, -61, 58, 68, -70, 67, 79, -79, 75, + 1, 3, -2, 10, -15, 11, 23, -30, 28, 35, -41, 39, + 47, -51, 49, 58, -61, 58, 68, -70, 67, 79, -79, 76, + 1, 6, -1, 10, -13, 12, 23, -28, 28, 35, -40, 39, + 47, -51, 49, 58, -60, 58, 69, -69, 67, 79, -78, 76, + 2, 9, 0, 11, -8, 13, 24, -26, 28, 36, -38, 39, + 47, -50, 49, 58, -59, 58, 69, -69, 67, 79, -78, 76, + 3, 14, 2, 12, -4, 14, 24, -23, 29, 36, -36, 39, + 47, -48, 49, 58, -58, 58, 69, -68, 67, 79, -77, 76, + 4, 20, 4, 13, 1, 16, 25, -19, 29, 36, -34, 40, + 48, -47, 50, 58, -57, 59, 69, -67, 67, 79, -76, 76, + 6, 25, 6, 14, 5, 17, 25, -16, 30, 36, -31, 40, + 48, -45, 50, 59, -56, 59, 69, -66, 67, 79, -75, 76, + 8, 28, 10, 15, 10, 19, 26, -11, 31, 37, -28, 41, + 48, -42, 50, 59, -54, 59, 69, -64, 68, 80, -74, 76, + 10, 31, 13, 17, 14, 21, 27, -7, 32, 37, -25, 41, + 48, -40, 51, 59, -52, 59, 69, -63, 68, 80, -73, 76, + 12, 33, 16, 18, 18, 23, 27, -3, 33, 38, -21, 42, + 49, -37, 51, 59, -50, 60, 70, -61, 68, 80, -71, 76, + 14, 35, 19, 19, 22, 25, 28, 1, 34, 38, -18, 43, + 49, -34, 52, 60, -47, 60, 70, -59, 68, 80, -70, 77, + 16, 38, 22, 21, 25, 27, 29, 5, 35, 39, -14, 44, + 50, -31, 52, 60, -45, 61, 70, -57, 69, 80, -68, 77, + 19, 40, 25, 23, 29, 30, 31, 10, 37, 40, -9, 45, + 50, -27, 53, 60, -41, 61, 70, -54, 69, 81, -66, 77, + 21, 42, 28, 24, 32, 32, 32, 14, 38, 41, -5, 46, + 51, -23, 54, 61, -38, 62, 71, -52, 70, 81, -64, 78, + 23, 45, 31, 26, 35, 34, 33, 18, 40, 42, -2, 47, + 51, -20, 54, 61, -35, 62, 71, -49, 70, 81, -61, 78, + 24, 47, 33, 27, 38, 36, 34, 21, 41, 42, 2, 48, + 52, -16, 55, 62, -32, 63, 71, -46, 70, 81, -59, 78, + 27, 49, 36, 29, 41, 38, 35, 25, 43, 43, 7, 49, + 53, -12, 56, 62, -28, 63, 72, -43, 71, 82, -56, 79, + 28, 51, 38, 31, 44, 40, 37, 29, 44, 44, 11, 50, + 54, -8, 57, 63, -25, 64, 72, -40, 72, 82, -54, 79, + 30, 54, 41, 33, 47, 42, 38, 32, 46, 45, 14, 51, + 54, -5, 58, 63, -21, 65, 73, -37, 72, 83, -51, 80, + 32, 56, 43, 34, 49, 44, 39, 35, 47, 46, 18, 52, + 55, -1, 59, 64, -18, 66, 73, -33, 73, 83, -48, 80, + 34, 58, 45, 36, 52, 46, 41, 39, 49, 48, 22, 54, + 56, 3, 60, 65, -14, 67, 74, -30, 73, 83, -45, 81, + 36, 60, 47, 38, 54, 48, 42, 42, 51, 49, 25, 55, + 57, 7, 61, 66, -10, 67, 74, -26, 74, 84, -42, 81, + 38, 62, 49, 39, 57, 50, 44, 45, 52, 50, 29, 57, + 58, 11, 62, 66, -7, 68, 75, -23, 75, 84, -38, 82, + 39, 64, 51, 41, 59, 52, 45, 48, 54, 51, 32, 58, + 59, 14, 63, 67, -3, 69, 76, -20, 76, 85, -35, 83, + 41, 66, 53, 43, 61, 53, 47, 51, 56, 52, 36, 59, + 60, 18, 64, 68, 0, 70, 76, -16, 76, 85, -32, 83, + 43, 68, 55, 44, 64, 55, 48, 54, 57, 54, 39, 61, + 61, 22, 66, 69, 4, 71, 77, -12, 77, 86, -28, 84, + 45, 70, 56, 46, 66, 57, 50, 56, 59, 55, 42, 62, + 62, 25, 67, 70, 8, 72, 78, -9, 78, 87, -25, 85, + 46, 72, 58, 48, 68, 59, 51, 59, 61, 56, 45, 64, + 63, 29, 68, 70, 11, 73, 79, -5, 79, 87, -22, 85, + 48, 74, 60, 49, 70, 61, 53, 62, 62, 57, 48, 65, + 64, 32, 69, 71, 15, 74, 79, -2, 80, 88, -18, 86, + 50, 76, 62, 51, 73, 62, 54, 64, 64, 59, 52, 67, + 65, 36, 71, 72, 19, 75, 80, 2, 81, 89, -15, 87, + 52, 78, 64, 53, 75, 64, 56, 67, 66, 60, 54, 68, + 66, 39, 72, 73, 22, 76, 81, 5, 82, 89, -11, 88, + 53, 80, 65, 54, 77, 66, 57, 69, 67, 62, 57, 70, + 67, 42, 73, 74, 26, 78, 82, 9, 83, 90, -8, 89, + 0, 2, -6, 10, -16, 7, 23, -31, 24, 35, -41, 36, + 47, -52, 47, 58, -61, 57, 68, -70, 66, 79, -79, 75, + 1, 4, -6, 10, -14, 8, 23, -29, 24, 35, -41, 36, + 47, -51, 47, 58, -60, 57, 69, -69, 66, 79, -78, 75, + 1, 7, -5, 10, -11, 8, 23, -28, 24, 35, -40, 36, + 47, -50, 47, 58, -60, 57, 69, -69, 66, 79, -78, 75, + 2, 11, -4, 11, -7, 9, 24, -25, 25, 36, -38, 37, + 47, -49, 48, 58, -59, 57, 69, -68, 66, 79, -78, 75, + 3, 15, -2, 12, -3, 11, 24, -22, 25, 36, -36, 37, + 47, -48, 48, 58, -58, 57, 69, -68, 66, 79, -77, 75, + 5, 21, 0, 13, 2, 12, 25, -19, 26, 36, -34, 37, + 48, -46, 48, 58, -57, 57, 69, -67, 66, 79, -76, 75, + 6, 26, 3, 14, 6, 14, 25, -15, 27, 36, -31, 38, + 48, -44, 48, 59, -55, 58, 69, -66, 66, 79, -75, 75, + 8, 29, 6, 15, 11, 16, 26, -11, 28, 37, -28, 38, + 48, -42, 49, 59, -54, 58, 69, -64, 67, 80, -74, 75, + 11, 31, 10, 17, 15, 18, 27, -7, 29, 37, -24, 39, + 48, -39, 49, 59, -52, 58, 69, -62, 67, 80, -73, 75, + 13, 33, 13, 18, 19, 20, 28, -3, 30, 38, -21, 40, + 49, -37, 50, 59, -49, 59, 70, -61, 67, 80, -71, 76, + 15, 36, 16, 19, 22, 22, 28, 2, 31, 39, -17, 41, + 49, -34, 50, 60, -47, 59, 70, -59, 67, 80, -70, 76, + 17, 38, 19, 21, 26, 24, 29, 6, 32, 39, -13, 41, + 50, -30, 51, 60, -44, 59, 70, -57, 68, 80, -68, 76, + 19, 40, 22, 23, 29, 26, 31, 10, 34, 40, -9, 42, + 50, -27, 51, 60, -41, 60, 70, -54, 68, 81, -66, 77, + 21, 43, 25, 24, 33, 28, 32, 14, 35, 41, -5, 43, + 51, -23, 52, 61, -38, 60, 71, -51, 69, 81, -64, 77, + 23, 45, 27, 26, 36, 30, 33, 18, 37, 42, -1, 44, + 51, -20, 53, 61, -35, 61, 71, -49, 69, 81, -61, 77, + 24, 47, 30, 28, 38, 33, 34, 22, 38, 42, 3, 46, + 52, -16, 54, 62, -32, 62, 71, -46, 69, 81, -59, 78, + 27, 49, 32, 29, 42, 35, 35, 26, 40, 43, 7, 47, + 53, -12, 55, 62, -28, 62, 72, -43, 70, 82, -56, 78, + 28, 52, 35, 31, 44, 37, 37, 29, 42, 44, 11, 48, + 54, -8, 55, 63, -25, 63, 72, -40, 71, 82, -53, 79, + 30, 54, 37, 33, 47, 39, 38, 32, 43, 45, 14, 49, + 54, -4, 56, 63, -21, 64, 73, -37, 71, 83, -51, 79, + 32, 56, 39, 34, 49, 41, 39, 36, 45, 47, 18, 51, + 55, -1, 57, 64, -18, 64, 73, -33, 72, 83, -48, 79, + 34, 58, 42, 36, 52, 43, 41, 39, 47, 48, 22, 52, + 56, 4, 58, 65, -14, 65, 74, -30, 73, 83, -45, 80, + 36, 60, 44, 38, 55, 45, 42, 42, 48, 49, 26, 53, + 57, 7, 60, 66, -10, 66, 75, -26, 73, 84, -41, 81, + 38, 62, 46, 39, 57, 47, 44, 45, 50, 50, 29, 55, + 58, 11, 61, 66, -7, 67, 75, -23, 74, 84, -38, 81, + 39, 64, 48, 41, 59, 49, 45, 48, 52, 51, 32, 56, + 59, 14, 62, 67, -3, 68, 76, -20, 75, 85, -35, 82, + 41, 66, 50, 43, 62, 51, 47, 51, 53, 52, 36, 57, + 60, 18, 63, 68, 1, 69, 76, -16, 75, 85, -32, 83, + 43, 68, 52, 45, 64, 53, 48, 54, 55, 54, 39, 59, + 61, 22, 64, 69, 5, 70, 77, -12, 76, 86, -28, 83, + 45, 70, 54, 46, 66, 55, 50, 56, 57, 55, 42, 61, + 62, 25, 65, 70, 8, 71, 78, -9, 77, 87, -25, 84, + 46, 72, 56, 48, 68, 57, 51, 59, 59, 56, 45, 62, + 63, 29, 67, 70, 12, 72, 79, -5, 78, 87, -22, 85, + 48, 74, 58, 49, 71, 58, 53, 62, 60, 57, 48, 63, + 64, 32, 68, 71, 15, 73, 79, -2, 79, 88, -18, 85, + 50, 76, 60, 51, 73, 60, 54, 64, 62, 59, 52, 65, + 65, 36, 69, 72, 19, 74, 80, 2, 80, 89, -15, 86, + 52, 78, 61, 53, 75, 62, 56, 67, 64, 60, 55, 67, + 66, 39, 71, 73, 22, 75, 81, 6, 81, 89, -11, 87, + 53, 80, 63, 54, 77, 64, 57, 69, 65, 62, 57, 68, + 67, 42, 72, 74, 26, 77, 82, 9, 82, 90, -8, 88, + 1, 4, -12, 10, -14, 1, 23, -29, 19, 35, -41, 33, + 47, -51, 45, 58, -61, 55, 68, -69, 64, 79, -78, 73, + 1, 7, -11, 10, -12, 2, 23, -28, 19, 35, -40, 33, + 47, -50, 45, 58, -60, 55, 69, -69, 64, 79, -78, 73, + 2, 9, -11, 11, -9, 3, 24, -26, 20, 35, -39, 33, + 47, -50, 45, 58, -60, 55, 69, -69, 64, 79, -78, 73, + 3, 13, -9, 11, -5, 4, 24, -24, 20, 36, -37, 33, + 47, -49, 45, 58, -59, 55, 69, -68, 64, 79, -77, 74, + 4, 18, -8, 12, -1, 5, 24, -21, 21, 36, -35, 34, + 47, -47, 45, 58, -58, 55, 69, -67, 65, 79, -77, 74, + 5, 23, -5, 13, 3, 6, 25, -18, 21, 36, -33, 34, + 48, -46, 45, 58, -57, 55, 69, -66, 65, 79, -76, 74, + 7, 27, -3, 14, 7, 8, 25, -14, 22, 37, -30, 34, + 48, -44, 46, 59, -55, 56, 69, -65, 65, 79, -75, 74, + 9, 30, 1, 16, 12, 10, 26, -10, 23, 37, -27, 35, + 48, -41, 46, 59, -53, 56, 69, -64, 65, 80, -74, 74, + 11, 32, 4, 17, 16, 12, 27, -6, 24, 37, -24, 36, + 49, -39, 46, 59, -51, 56, 69, -62, 65, 80, -73, 74, + 13, 34, 7, 18, 19, 14, 28, -2, 25, 38, -20, 36, + 49, -36, 47, 59, -49, 57, 70, -60, 66, 80, -71, 74, + 15, 36, 10, 20, 23, 16, 28, 2, 27, 39, -17, 37, + 49, -33, 48, 60, -47, 57, 70, -58, 66, 80, -69, 75, + 17, 38, 13, 21, 26, 18, 29, 6, 28, 39, -13, 38, + 50, -30, 48, 60, -44, 57, 70, -56, 66, 80, -68, 75, + 19, 41, 16, 23, 30, 21, 31, 11, 30, 40, -9, 39, + 50, -26, 49, 60, -41, 58, 70, -54, 67, 81, -65, 75, + 21, 43, 19, 24, 33, 23, 32, 14, 31, 41, -5, 40, + 51, -23, 50, 61, -38, 58, 71, -51, 67, 81, -63, 76, + 23, 45, 22, 26, 36, 25, 33, 18, 33, 42, -1, 41, + 51, -19, 50, 61, -35, 59, 71, -49, 67, 81, -61, 76, + 25, 47, 24, 28, 39, 27, 34, 22, 34, 43, 3, 42, + 52, -16, 51, 62, -32, 60, 71, -46, 68, 81, -59, 76, + 27, 50, 27, 29, 42, 30, 36, 26, 36, 44, 7, 44, + 53, -12, 52, 62, -28, 60, 72, -42, 69, 82, -56, 77, + 29, 52, 30, 31, 44, 32, 37, 29, 38, 45, 11, 45, + 54, -8, 53, 63, -25, 61, 72, -39, 69, 82, -53, 77, + 30, 54, 32, 33, 47, 34, 38, 33, 39, 46, 15, 46, + 54, -4, 54, 64, -21, 62, 73, -36, 70, 83, -51, 78, + 32, 56, 34, 34, 50, 36, 39, 36, 41, 47, 18, 48, + 55, 0, 55, 64, -18, 63, 73, -33, 70, 83, -48, 78, + 34, 58, 37, 36, 52, 39, 41, 39, 43, 48, 22, 49, + 56, 4, 56, 65, -14, 64, 74, -29, 71, 83, -44, 79, + 36, 60, 39, 38, 55, 41, 42, 42, 45, 49, 26, 50, + 57, 7, 57, 66, -10, 64, 75, -26, 72, 84, -41, 79, + 38, 62, 41, 39, 57, 43, 44, 45, 47, 50, 29, 52, + 58, 11, 58, 66, -6, 65, 75, -23, 72, 84, -38, 80, + 39, 64, 44, 41, 59, 45, 45, 48, 48, 51, 33, 53, + 59, 15, 60, 67, -3, 66, 76, -19, 73, 85, -35, 81, + 41, 66, 46, 43, 62, 47, 47, 51, 50, 52, 36, 55, + 60, 18, 61, 68, 1, 67, 76, -16, 74, 85, -32, 81, + 43, 68, 48, 45, 64, 49, 48, 54, 52, 54, 39, 56, + 61, 22, 62, 69, 5, 68, 77, -12, 75, 86, -28, 82, + 45, 70, 50, 46, 66, 51, 50, 57, 54, 55, 43, 58, + 62, 25, 63, 70, 8, 69, 78, -9, 76, 87, -25, 83, + 46, 72, 52, 48, 69, 53, 51, 59, 56, 56, 46, 59, + 63, 29, 65, 70, 12, 70, 79, -5, 77, 87, -22, 84, + 48, 74, 54, 49, 71, 55, 53, 62, 57, 58, 49, 61, + 64, 32, 66, 71, 15, 71, 79, -2, 78, 88, -18, 84, + 50, 77, 56, 51, 73, 57, 54, 64, 59, 59, 52, 63, + 65, 36, 67, 72, 19, 73, 80, 2, 79, 89, -14, 85, + 52, 78, 58, 53, 75, 59, 56, 67, 61, 60, 55, 64, + 66, 39, 69, 73, 22, 74, 81, 6, 80, 89, -11, 86, + 53, 80, 60, 54, 77, 61, 57, 69, 63, 62, 57, 66, + 67, 42, 70, 74, 26, 75, 82, 9, 81, 90, -8, 87, + 1, 7, -18, 10, -11, -4, 23, -28, 14, 35, -40, 29, + 47, -50, 42, 58, -60, 53, 69, -69, 62, 79, -78, 72, + 1, 9, -17, 11, -9, -3, 23, -26, 15, 35, -39, 29, + 47, -50, 42, 58, -60, 53, 69, -69, 62, 79, -78, 72, + 2, 11, -16, 11, -6, -3, 24, -25, 15, 36, -38, 29, + 47, -49, 42, 58, -59, 53, 69, -68, 63, 79, -78, 72, + 3, 15, -15, 12, -3, -2, 24, -22, 15, 36, -36, 30, + 47, -48, 42, 58, -58, 53, 69, -68, 63, 79, -77, 72, + 4, 20, -13, 12, 1, -1, 24, -20, 16, 36, -34, 30, + 47, -47, 42, 58, -57, 53, 69, -67, 63, 79, -76, 72, + 5, 24, -11, 13, 5, 1, 25, -17, 17, 36, -32, 30, + 48, -45, 42, 58, -56, 53, 69, -66, 63, 79, -76, 72, + 7, 28, -9, 14, 8, 3, 25, -13, 17, 37, -30, 31, + 48, -43, 43, 59, -55, 53, 69, -65, 63, 79, -75, 72, + 9, 30, -5, 16, 13, 5, 26, -9, 19, 37, -26, 31, + 48, -41, 43, 59, -53, 54, 69, -63, 63, 80, -74, 73, + 11, 33, -2, 17, 16, 7, 27, -5, 20, 38, -23, 32, + 49, -38, 44, 59, -51, 54, 69, -62, 63, 80, -72, 73, + 13, 35, 1, 18, 20, 9, 28, -1, 21, 38, -20, 33, + 49, -36, 44, 59, -49, 54, 70, -60, 64, 80, -71, 73, + 15, 37, 4, 20, 23, 11, 29, 3, 22, 39, -16, 34, + 49, -33, 45, 60, -46, 55, 70, -58, 64, 80, -69, 73, + 17, 39, 7, 21, 27, 13, 30, 7, 24, 39, -12, 34, + 50, -30, 45, 60, -44, 55, 70, -56, 64, 80, -67, 73, + 19, 41, 11, 23, 30, 16, 31, 11, 25, 40, -8, 36, + 50, -26, 46, 60, -41, 56, 70, -53, 65, 81, -65, 74, + 21, 43, 13, 25, 33, 18, 32, 15, 27, 41, -4, 37, + 51, -22, 47, 61, -38, 56, 71, -51, 65, 81, -63, 74, + 23, 46, 16, 26, 36, 20, 33, 19, 28, 42, -1, 38, + 52, -19, 48, 61, -35, 57, 71, -48, 66, 81, -61, 74, + 25, 48, 19, 28, 39, 23, 34, 22, 30, 43, 3, 39, + 52, -15, 48, 62, -31, 57, 71, -45, 66, 81, -59, 75, + 27, 50, 22, 30, 42, 25, 36, 26, 32, 44, 8, 40, + 53, -11, 49, 62, -28, 58, 72, -42, 67, 82, -56, 75, + 29, 52, 25, 31, 45, 27, 37, 30, 34, 45, 11, 42, + 54, -8, 50, 63, -24, 59, 72, -39, 67, 82, -53, 76, + 30, 54, 27, 33, 47, 30, 38, 33, 35, 46, 15, 43, + 54, -4, 51, 64, -21, 60, 73, -36, 68, 83, -50, 76, + 32, 56, 30, 34, 50, 32, 40, 36, 37, 47, 19, 44, + 55, 0, 52, 64, -17, 60, 73, -33, 69, 83, -47, 77, + 34, 58, 32, 36, 53, 34, 41, 40, 39, 48, 23, 46, + 56, 4, 54, 65, -13, 61, 74, -29, 69, 83, -44, 77, + 36, 60, 35, 38, 55, 37, 42, 43, 41, 49, 26, 47, + 57, 8, 55, 66, -10, 62, 75, -26, 70, 84, -41, 78, + 38, 62, 37, 40, 57, 39, 44, 45, 43, 50, 29, 49, + 58, 11, 56, 66, -6, 63, 75, -23, 71, 84, -38, 79, + 39, 64, 39, 41, 60, 41, 45, 48, 45, 51, 33, 50, + 59, 15, 57, 67, -3, 64, 76, -19, 72, 85, -35, 79, + 41, 66, 42, 43, 62, 43, 47, 51, 47, 52, 36, 52, + 60, 18, 58, 68, 1, 65, 76, -16, 72, 85, -32, 80, + 43, 69, 44, 45, 64, 45, 48, 54, 49, 54, 40, 54, + 61, 22, 60, 69, 5, 66, 77, -12, 73, 86, -28, 81, + 45, 71, 46, 46, 67, 47, 50, 57, 50, 55, 43, 55, + 62, 26, 61, 70, 8, 67, 78, -8, 74, 87, -25, 81, + 46, 73, 48, 48, 69, 49, 51, 59, 52, 56, 46, 57, + 63, 29, 62, 71, 12, 68, 79, -5, 75, 87, -21, 82, + 48, 74, 50, 49, 71, 51, 53, 62, 54, 58, 49, 58, + 64, 32, 64, 71, 15, 70, 79, -1, 76, 88, -18, 83, + 50, 77, 53, 51, 73, 54, 54, 65, 56, 59, 52, 60, + 65, 36, 65, 72, 19, 71, 80, 2, 77, 89, -14, 84, + 52, 79, 55, 53, 75, 56, 56, 67, 58, 60, 55, 62, + 66, 39, 66, 73, 23, 72, 81, 6, 78, 89, -11, 85, + 53, 80, 57, 54, 77, 58, 57, 69, 60, 62, 58, 63, + 68, 42, 68, 74, 26, 73, 82, 9, 79, 90, -8, 85, + 1, 10, -24, 11, -8, -9, 23, -26, 9, 35, -38, 25, + 47, -50, 38, 58, -59, 50, 69, -69, 60, 79, -78, 70, + 2, 12, -23, 11, -6, -9, 24, -24, 10, 36, -38, 25, + 47, -49, 38, 58, -59, 50, 69, -68, 60, 79, -77, 70, + 2, 15, -22, 11, -4, -8, 24, -23, 10, 36, -37, 25, + 47, -48, 39, 58, -58, 50, 69, -68, 60, 79, -77, 70, + 3, 19, -21, 12, 0, -7, 24, -21, 11, 36, -35, 25, + 47, -47, 39, 58, -58, 50, 69, -67, 60, 79, -77, 70, + 4, 23, -19, 13, 3, -6, 25, -18, 11, 36, -33, 26, + 48, -46, 39, 58, -57, 50, 69, -67, 61, 79, -76, 70, + 6, 26, -17, 14, 6, -4, 25, -15, 12, 36, -31, 26, + 48, -44, 39, 58, -56, 50, 69, -66, 61, 79, -75, 70, + 7, 29, -14, 15, 10, -3, 26, -12, 13, 37, -29, 27, + 48, -43, 40, 59, -54, 51, 69, -64, 61, 79, -74, 71, + 9, 31, -10, 16, 14, -1, 26, -8, 14, 37, -25, 27, + 48, -40, 40, 59, -52, 51, 69, -63, 61, 80, -73, 71, + 11, 33, -7, 17, 18, 1, 27, -4, 15, 38, -22, 28, + 49, -38, 40, 59, -50, 51, 69, -61, 61, 80, -72, 71, + 13, 35, -4, 19, 21, 3, 28, 0, 16, 38, -19, 29, + 49, -35, 41, 59, -48, 52, 70, -60, 62, 80, -70, 71, + 15, 37, -1, 20, 24, 6, 29, 4, 17, 39, -15, 30, + 49, -32, 41, 60, -46, 52, 70, -58, 62, 80, -69, 71, + 17, 40, 2, 21, 28, 8, 30, 8, 19, 39, -12, 31, + 50, -29, 42, 60, -43, 53, 70, -56, 62, 80, -67, 72, + 19, 42, 5, 23, 31, 11, 31, 12, 21, 40, -8, 32, + 50, -25, 43, 60, -40, 53, 70, -53, 63, 81, -65, 72, + 21, 44, 8, 25, 34, 13, 32, 16, 22, 41, -4, 33, + 51, -22, 44, 61, -37, 54, 71, -51, 63, 81, -63, 72, + 23, 46, 11, 26, 37, 15, 33, 19, 24, 42, 0, 34, + 52, -18, 44, 61, -34, 54, 71, -48, 64, 81, -61, 73, + 25, 48, 14, 28, 40, 18, 34, 23, 26, 43, 4, 35, + 52, -15, 45, 62, -31, 55, 72, -45, 64, 81, -58, 73, + 27, 50, 17, 30, 43, 20, 36, 27, 28, 44, 8, 37, + 53, -11, 46, 62, -27, 56, 72, -42, 65, 82, -55, 74, + 29, 52, 19, 31, 45, 23, 37, 30, 29, 45, 12, 38, + 54, -7, 47, 63, -24, 56, 72, -39, 65, 82, -53, 74, + 31, 54, 22, 33, 48, 25, 38, 33, 31, 46, 15, 39, + 54, -3, 48, 64, -20, 57, 73, -36, 66, 83, -50, 75, + 32, 56, 25, 35, 50, 27, 40, 36, 33, 47, 19, 41, + 55, 0, 49, 64, -17, 58, 73, -33, 66, 83, -47, 75, + 34, 59, 27, 36, 53, 30, 41, 40, 35, 48, 23, 42, + 56, 4, 51, 65, -13, 59, 74, -29, 67, 83, -44, 76, + 36, 61, 30, 38, 55, 32, 42, 43, 37, 49, 26, 44, + 57, 8, 52, 66, -9, 60, 75, -26, 68, 84, -41, 76, + 38, 63, 32, 40, 58, 34, 44, 46, 39, 50, 30, 45, + 58, 12, 53, 66, -6, 61, 75, -22, 69, 84, -38, 77, + 40, 65, 35, 41, 60, 37, 45, 49, 41, 51, 33, 47, + 59, 15, 54, 67, -2, 62, 76, -19, 70, 85, -35, 78, + 41, 67, 37, 43, 62, 39, 47, 51, 43, 52, 36, 48, + 60, 19, 55, 68, 1, 63, 76, -15, 70, 85, -31, 78, + 43, 69, 40, 45, 65, 41, 48, 54, 45, 54, 40, 50, + 61, 22, 57, 69, 5, 64, 77, -12, 71, 86, -28, 79, + 45, 71, 42, 46, 67, 43, 50, 57, 47, 55, 43, 52, + 62, 26, 58, 70, 9, 65, 78, -8, 72, 87, -24, 80, + 47, 73, 44, 48, 69, 45, 51, 60, 49, 56, 46, 53, + 63, 29, 59, 71, 12, 66, 79, -5, 73, 87, -21, 80, + 48, 75, 46, 50, 71, 48, 53, 62, 51, 58, 49, 55, + 64, 32, 61, 71, 16, 67, 79, -1, 74, 88, -18, 81, + 50, 77, 49, 51, 73, 50, 54, 65, 53, 59, 52, 57, + 65, 36, 62, 72, 19, 68, 80, 3, 75, 89, -14, 82, + 52, 79, 51, 53, 75, 52, 56, 67, 54, 60, 55, 58, + 66, 39, 64, 73, 23, 70, 81, 6, 76, 89, -11, 83, + 53, 81, 53, 55, 77, 54, 57, 70, 56, 62, 58, 60, + 68, 42, 65, 74, 26, 71, 82, 9, 77, 90, -7, 84, + 2, 14, -29, 11, -4, -15, 24, -23, 5, 36, -37, 21, + 47, -49, 35, 58, -59, 47, 69, -68, 58, 79, -77, 68, + 2, 16, -28, 11, -2, -14, 24, -22, 5, 36, -36, 21, + 47, -48, 35, 58, -58, 47, 69, -68, 58, 79, -77, 68, + 3, 19, -27, 12, 0, -13, 24, -21, 5, 36, -35, 21, + 47, -47, 35, 58, -58, 47, 69, -67, 58, 79, -77, 68, + 4, 22, -26, 12, 2, -12, 24, -19, 6, 36, -34, 21, + 47, -46, 35, 58, -57, 47, 69, -67, 58, 79, -76, 68, + 5, 26, -24, 13, 5, -11, 25, -16, 6, 36, -32, 21, + 48, -45, 35, 58, -56, 47, 69, -66, 58, 79, -76, 68, + 6, 29, -22, 14, 8, -10, 25, -13, 7, 36, -30, 22, + 48, -43, 36, 59, -55, 47, 69, -65, 58, 79, -75, 68, + 8, 31, -19, 15, 12, -8, 26, -10, 8, 37, -27, 22, + 48, -42, 36, 59, -53, 48, 69, -64, 58, 80, -74, 68, + 10, 33, -16, 16, 16, -6, 26, -6, 9, 37, -24, 23, + 48, -39, 36, 59, -51, 48, 69, -62, 59, 80, -73, 69, + 12, 35, -13, 18, 19, -4, 27, -3, 10, 38, -21, 24, + 49, -37, 37, 59, -50, 48, 69, -61, 59, 80, -71, 69, + 14, 36, -10, 19, 22, -2, 28, 1, 11, 38, -18, 25, + 49, -34, 37, 59, -47, 49, 70, -59, 59, 80, -70, 69, + 16, 38, -7, 20, 25, 0, 29, 5, 13, 39, -14, 25, + 49, -31, 38, 60, -45, 49, 70, -57, 59, 80, -68, 69, + 17, 40, -4, 22, 28, 3, 30, 9, 14, 39, -11, 26, + 50, -28, 39, 60, -43, 50, 70, -55, 60, 80, -67, 70, + 20, 43, 0, 23, 32, 5, 31, 13, 16, 40, -7, 27, + 50, -25, 39, 61, -39, 50, 70, -53, 60, 81, -65, 70, + 21, 45, 3, 25, 35, 8, 32, 16, 17, 41, -3, 29, + 51, -21, 40, 61, -37, 51, 71, -50, 61, 81, -62, 70, + 23, 47, 6, 26, 37, 10, 33, 20, 19, 42, 1, 30, + 52, -18, 41, 61, -34, 51, 71, -47, 61, 81, -60, 71, + 25, 49, 8, 28, 40, 12, 34, 23, 21, 43, 4, 31, + 52, -14, 42, 62, -30, 52, 72, -45, 62, 81, -58, 71, + 27, 51, 12, 30, 43, 15, 36, 27, 23, 44, 9, 32, + 53, -10, 43, 62, -27, 53, 72, -41, 62, 82, -55, 71, + 29, 53, 14, 31, 46, 18, 37, 31, 25, 45, 12, 34, + 54, -7, 44, 63, -23, 53, 72, -38, 63, 82, -52, 72, + 31, 55, 17, 33, 48, 20, 38, 34, 27, 46, 16, 35, + 55, -3, 45, 64, -20, 54, 73, -35, 63, 83, -50, 72, + 32, 57, 20, 35, 51, 22, 40, 37, 29, 47, 19, 37, + 55, 1, 46, 64, -17, 55, 73, -32, 64, 83, -47, 73, + 34, 59, 23, 36, 53, 25, 41, 40, 31, 48, 23, 38, + 56, 5, 47, 65, -13, 56, 74, -29, 65, 84, -44, 74, + 36, 61, 25, 38, 56, 27, 43, 43, 33, 49, 27, 40, + 57, 8, 48, 66, -9, 57, 75, -25, 66, 84, -41, 74, + 38, 63, 28, 40, 58, 30, 44, 46, 35, 50, 30, 41, + 58, 12, 50, 66, -6, 58, 75, -22, 66, 84, -37, 75, + 40, 65, 30, 41, 60, 32, 45, 49, 37, 51, 33, 43, + 59, 15, 51, 67, -2, 59, 76, -19, 67, 85, -34, 75, + 41, 67, 32, 43, 62, 34, 47, 52, 38, 53, 37, 45, + 60, 19, 52, 68, 1, 60, 76, -15, 68, 86, -31, 76, + 43, 69, 35, 45, 65, 37, 48, 55, 41, 54, 40, 46, + 61, 23, 54, 69, 5, 61, 77, -11, 69, 86, -28, 77, + 45, 71, 37, 46, 67, 39, 50, 57, 43, 55, 43, 48, + 62, 26, 55, 70, 9, 62, 78, -8, 70, 87, -24, 78, + 47, 73, 40, 48, 69, 41, 51, 60, 45, 56, 46, 50, + 63, 29, 56, 71, 12, 63, 79, -4, 71, 87, -21, 78, + 48, 75, 42, 50, 71, 43, 53, 62, 47, 58, 49, 51, + 64, 33, 58, 71, 16, 65, 79, -1, 72, 88, -18, 79, + 50, 77, 45, 51, 74, 46, 54, 65, 49, 59, 52, 53, + 65, 36, 59, 73, 20, 66, 80, 3, 73, 89, -14, 80, + 52, 79, 47, 53, 76, 48, 56, 67, 51, 60, 55, 55, + 66, 40, 61, 73, 23, 67, 81, 6, 74, 89, -11, 81, + 53, 81, 49, 55, 78, 50, 57, 70, 53, 62, 58, 57, + 68, 43, 62, 74, 26, 68, 82, 10, 75, 90, -7, 82, + 3, 19, -34, 12, 0, -20, 24, -21, -1, 36, -35, 15, + 47, -47, 30, 58, -58, 43, 69, -67, 54, 79, -77, 65, + 3, 21, -33, 12, 2, -19, 24, -19, -1, 36, -34, 16, + 47, -47, 30, 58, -57, 43, 69, -67, 54, 79, -76, 65, + 4, 24, -33, 12, 3, -19, 24, -18, 0, 36, -33, 16, + 47, -46, 31, 58, -57, 43, 69, -67, 55, 79, -76, 65, + 5, 26, -31, 13, 6, -18, 25, -16, 0, 36, -32, 16, + 48, -45, 31, 58, -56, 43, 69, -66, 55, 79, -76, 65, + 6, 29, -29, 14, 8, -17, 25, -14, 1, 36, -30, 16, + 48, -44, 31, 58, -55, 43, 69, -65, 55, 79, -75, 65, + 7, 31, -27, 14, 11, -15, 25, -11, 1, 37, -28, 17, + 48, -42, 31, 59, -54, 44, 69, -64, 55, 79, -74, 66, + 9, 33, -24, 15, 14, -14, 26, -8, 2, 37, -26, 17, + 48, -40, 32, 59, -52, 44, 69, -63, 55, 80, -73, 66, + 11, 34, -21, 17, 18, -12, 27, -5, 3, 37, -23, 18, + 48, -38, 32, 59, -51, 44, 69, -62, 55, 80, -72, 66, + 12, 36, -18, 18, 21, -10, 27, -1, 4, 38, -20, 19, + 49, -36, 32, 59, -49, 44, 70, -60, 56, 80, -71, 66, + 14, 38, -15, 19, 24, -8, 28, 3, 6, 38, -17, 20, + 49, -33, 33, 60, -47, 45, 70, -58, 56, 80, -69, 66, + 16, 39, -12, 21, 27, -5, 29, 6, 7, 39, -13, 20, + 50, -30, 34, 60, -44, 45, 70, -57, 56, 80, -68, 67, + 18, 41, -9, 22, 30, -3, 30, 10, 9, 40, -10, 21, + 50, -27, 34, 60, -42, 46, 70, -54, 57, 80, -66, 67, + 20, 43, -6, 24, 33, 0, 31, 14, 10, 40, -6, 23, + 51, -24, 35, 61, -39, 46, 71, -52, 57, 81, -64, 67, + 22, 45, -3, 25, 36, 2, 32, 17, 12, 41, -2, 24, + 51, -20, 36, 61, -36, 47, 71, -49, 57, 81, -62, 68, + 24, 47, 0, 27, 38, 4, 33, 21, 14, 42, 2, 25, + 52, -17, 37, 61, -33, 48, 71, -47, 58, 81, -60, 68, + 25, 49, 3, 28, 41, 7, 35, 24, 15, 43, 5, 26, + 52, -13, 38, 62, -30, 48, 72, -44, 58, 82, -57, 68, + 27, 51, 6, 30, 44, 9, 36, 28, 18, 44, 9, 28, + 53, -10, 39, 63, -26, 49, 72, -41, 59, 82, -55, 69, + 29, 53, 8, 32, 46, 12, 37, 31, 19, 45, 13, 29, + 54, -6, 40, 63, -23, 50, 73, -38, 60, 82, -52, 69, + 31, 55, 11, 33, 49, 14, 39, 34, 21, 46, 17, 30, + 55, -2, 41, 64, -19, 51, 73, -35, 60, 83, -49, 70, + 33, 57, 14, 35, 51, 17, 40, 37, 23, 47, 20, 32, + 55, 1, 42, 64, -16, 51, 74, -32, 61, 83, -46, 70, + 35, 60, 17, 37, 54, 19, 41, 41, 26, 48, 24, 34, + 56, 5, 43, 65, -12, 52, 74, -28, 62, 84, -43, 71, + 36, 61, 19, 38, 56, 22, 43, 44, 27, 49, 27, 35, + 57, 9, 44, 66, -9, 53, 75, -25, 62, 84, -40, 72, + 38, 63, 22, 40, 58, 24, 44, 47, 29, 50, 31, 37, + 58, 12, 46, 66, -5, 54, 75, -22, 63, 85, -37, 72, + 40, 65, 25, 41, 61, 27, 46, 49, 32, 51, 34, 38, + 59, 16, 47, 67, -2, 55, 76, -18, 64, 85, -34, 73, + 41, 67, 27, 43, 63, 29, 47, 52, 34, 53, 37, 40, + 60, 19, 48, 68, 2, 56, 77, -15, 65, 86, -31, 74, + 43, 69, 30, 45, 65, 32, 49, 55, 36, 54, 41, 42, + 61, 23, 50, 69, 6, 58, 77, -11, 66, 86, -27, 74, + 45, 71, 32, 46, 67, 34, 50, 58, 38, 55, 44, 44, + 62, 27, 51, 70, 9, 59, 78, -8, 67, 87, -24, 75, + 47, 73, 35, 48, 69, 36, 51, 60, 40, 56, 47, 45, + 63, 30, 52, 71, 13, 60, 79, -4, 68, 87, -21, 76, + 48, 75, 37, 50, 71, 38, 53, 63, 42, 58, 49, 47, + 64, 33, 54, 72, 16, 61, 79, -1, 69, 88, -17, 77, + 50, 77, 40, 51, 74, 41, 54, 65, 44, 59, 53, 49, + 65, 37, 55, 73, 20, 62, 80, 3, 70, 89, -14, 78, + 52, 79, 42, 53, 76, 43, 56, 68, 46, 60, 55, 51, + 67, 40, 57, 73, 23, 64, 81, 7, 71, 89, -10, 78, + 54, 81, 44, 55, 78, 45, 57, 70, 48, 62, 58, 53, + 68, 43, 58, 74, 27, 65, 82, 10, 72, 90, -7, 79, + 4, 25, -39, 12, 4, -25, 24, -18, -6, 36, -33, 11, + 47, -46, 26, 58, -57, 39, 69, -66, 51, 79, -76, 62, + 4, 26, -38, 12, 5, -24, 24, -17, -6, 36, -32, 11, + 48, -45, 26, 58, -56, 39, 69, -66, 51, 79, -76, 62, + 5, 28, -37, 13, 7, -24, 25, -15, -5, 36, -31, 11, + 48, -45, 26, 58, -56, 40, 69, -66, 51, 79, -75, 63, + 5, 30, -36, 13, 9, -23, 25, -14, -5, 36, -30, 11, + 48, -44, 27, 58, -55, 40, 69, -65, 51, 79, -75, 63, + 6, 32, -34, 14, 11, -21, 25, -11, -4, 36, -28, 12, + 48, -42, 27, 59, -54, 40, 69, -64, 52, 79, -74, 63, + 8, 33, -32, 15, 14, -20, 26, -9, -4, 37, -26, 12, + 48, -41, 27, 59, -53, 40, 69, -64, 52, 80, -74, 63, + 9, 34, -29, 16, 16, -19, 26, -6, -3, 37, -24, 13, + 48, -39, 27, 59, -51, 40, 69, -62, 52, 80, -73, 63, + 11, 36, -26, 17, 19, -17, 27, -3, -2, 38, -21, 13, + 49, -37, 28, 59, -50, 41, 69, -61, 52, 80, -72, 63, + 13, 37, -23, 18, 22, -15, 28, 1, 0, 38, -18, 14, + 49, -35, 28, 59, -48, 41, 70, -59, 52, 80, -70, 63, + 15, 39, -20, 20, 25, -13, 28, 4, 1, 39, -15, 15, + 49, -32, 29, 60, -46, 41, 70, -58, 53, 80, -69, 64, + 16, 41, -17, 21, 28, -10, 29, 8, 2, 39, -12, 16, + 50, -29, 29, 60, -43, 42, 70, -56, 53, 80, -67, 64, + 18, 42, -14, 22, 31, -8, 30, 11, 4, 40, -9, 17, + 50, -26, 30, 60, -41, 42, 70, -54, 53, 80, -66, 64, + 20, 44, -11, 24, 34, -5, 31, 15, 5, 41, -5, 18, + 51, -23, 31, 61, -38, 43, 71, -51, 54, 81, -63, 64, + 22, 46, -8, 25, 37, -3, 32, 18, 7, 41, -1, 19, + 51, -19, 32, 61, -35, 43, 71, -49, 54, 81, -61, 65, + 24, 48, -5, 27, 39, -1, 34, 22, 9, 42, 3, 20, + 52, -16, 33, 62, -32, 44, 71, -46, 55, 81, -59, 65, + 26, 50, -3, 28, 42, 2, 35, 25, 11, 43, 6, 22, + 52, -13, 34, 62, -29, 45, 72, -44, 55, 82, -57, 66, + 28, 52, 1, 30, 44, 4, 36, 29, 13, 44, 10, 23, + 53, -9, 35, 63, -25, 46, 72, -40, 56, 82, -54, 66, + 29, 54, 3, 32, 47, 7, 37, 32, 15, 45, 14, 25, + 54, -5, 36, 63, -22, 46, 73, -37, 57, 82, -51, 67, + 31, 56, 6, 33, 49, 9, 39, 35, 17, 46, 17, 26, + 55, -2, 37, 64, -19, 47, 73, -34, 57, 83, -49, 67, + 33, 58, 9, 35, 52, 12, 40, 38, 19, 47, 21, 28, + 56, 2, 38, 64, -15, 48, 74, -31, 58, 83, -46, 68, + 35, 60, 12, 37, 54, 15, 41, 41, 21, 48, 25, 29, + 56, 6, 39, 65, -12, 49, 74, -28, 59, 84, -43, 68, + 37, 62, 14, 38, 57, 17, 43, 44, 23, 49, 28, 31, + 57, 9, 40, 66, -8, 50, 75, -24, 59, 84, -40, 69, + 38, 64, 17, 40, 59, 19, 44, 47, 25, 50, 31, 33, + 58, 13, 42, 67, -5, 51, 75, -21, 60, 85, -37, 70, + 40, 66, 20, 42, 61, 22, 46, 50, 27, 52, 34, 34, + 59, 16, 43, 67, -1, 52, 76, -18, 61, 85, -34, 70, + 42, 68, 22, 43, 63, 24, 47, 52, 29, 53, 38, 36, + 60, 20, 44, 68, 2, 53, 77, -14, 62, 86, -30, 71, + 44, 70, 25, 45, 66, 27, 49, 55, 31, 54, 41, 38, + 61, 24, 46, 69, 6, 54, 77, -11, 63, 86, -27, 72, + 45, 72, 27, 47, 68, 29, 50, 58, 33, 55, 44, 40, + 62, 27, 47, 70, 10, 55, 78, -7, 64, 87, -24, 73, + 47, 74, 30, 48, 70, 32, 52, 60, 35, 57, 47, 41, + 63, 30, 49, 71, 13, 57, 79, -4, 65, 87, -20, 73, + 49, 75, 32, 50, 72, 34, 53, 63, 37, 58, 50, 43, + 64, 33, 50, 72, 17, 58, 79, 0, 66, 88, -17, 74, + 50, 78, 35, 52, 74, 36, 55, 66, 40, 59, 53, 45, + 66, 37, 52, 73, 20, 59, 80, 3, 67, 89, -13, 75, + 52, 79, 37, 53, 76, 39, 56, 68, 42, 61, 56, 47, + 67, 40, 53, 74, 24, 60, 81, 7, 68, 89, -10, 76, + 54, 81, 40, 55, 78, 41, 57, 70, 44, 62, 59, 49, + 68, 43, 55, 75, 27, 62, 82, 10, 69, 90, -7, 77, + 4, 29, -43, 13, 8, -29, 25, -15, -11, 36, -31, 6, + 48, -44, 22, 58, -55, 36, 69, -66, 48, 79, -75, 59, + 5, 30, -42, 13, 9, -29, 25, -14, -10, 36, -30, 6, + 48, -44, 22, 58, -55, 36, 69, -65, 48, 79, -75, 60, + 5, 31, -41, 13, 10, -28, 25, -13, -10, 36, -29, 7, + 48, -43, 22, 58, -55, 36, 69, -65, 48, 79, -75, 60, + 6, 33, -40, 14, 12, -27, 25, -11, -10, 36, -28, 7, + 48, -42, 22, 59, -54, 36, 69, -64, 48, 79, -74, 60, + 7, 34, -38, 15, 14, -26, 26, -9, -9, 37, -26, 7, + 48, -41, 23, 59, -53, 36, 69, -64, 48, 79, -74, 60, + 9, 35, -36, 15, 16, -25, 26, -7, -8, 37, -25, 8, + 48, -40, 23, 59, -52, 36, 69, -63, 48, 80, -73, 60, + 10, 36, -33, 16, 19, -23, 27, -4, -8, 37, -22, 8, + 48, -38, 23, 59, -50, 36, 69, -62, 49, 80, -72, 60, + 12, 37, -30, 18, 22, -21, 27, -1, -6, 38, -20, 9, + 49, -36, 24, 59, -49, 37, 69, -60, 49, 80, -71, 60, + 14, 39, -28, 19, 24, -19, 28, 3, -5, 38, -17, 10, + 49, -33, 24, 59, -47, 37, 70, -59, 49, 80, -70, 60, + 15, 40, -25, 20, 27, -17, 29, 6, -4, 39, -14, 10, + 49, -31, 25, 60, -45, 38, 70, -57, 49, 80, -68, 61, + 17, 42, -22, 21, 29, -15, 30, 9, -3, 39, -11, 11, + 50, -28, 25, 60, -42, 38, 70, -55, 50, 80, -67, 61, + 19, 43, -19, 23, 32, -13, 31, 12, -1, 40, -7, 12, + 50, -25, 26, 60, -40, 38, 70, -53, 50, 81, -65, 61, + 21, 45, -16, 24, 35, -10, 32, 16, 1, 41, -3, 13, + 51, -22, 27, 61, -37, 39, 71, -50, 51, 81, -63, 62, + 22, 47, -13, 26, 38, -8, 33, 20, 2, 41, 0, 15, + 51, -18, 28, 61, -34, 40, 71, -48, 51, 81, -61, 62, + 24, 49, -10, 27, 40, -6, 34, 23, 4, 42, 4, 16, + 52, -15, 28, 62, -31, 40, 71, -45, 51, 81, -59, 62, + 26, 51, -7, 29, 43, -3, 35, 26, 6, 43, 7, 17, + 53, -12, 29, 62, -28, 41, 72, -43, 52, 82, -56, 63, + 28, 53, -4, 30, 45, 0, 36, 30, 8, 44, 11, 19, + 53, -8, 31, 63, -25, 42, 72, -40, 53, 82, -53, 63, + 30, 55, -2, 32, 48, 2, 38, 33, 10, 45, 15, 20, + 54, -4, 32, 63, -21, 43, 73, -37, 53, 82, -51, 64, + 31, 57, 1, 34, 50, 4, 39, 36, 12, 46, 18, 22, + 55, -1, 33, 64, -18, 43, 73, -34, 54, 83, -48, 64, + 33, 58, 4, 35, 52, 7, 40, 39, 14, 47, 21, 23, + 56, 3, 34, 64, -15, 44, 74, -31, 55, 83, -45, 65, + 35, 61, 7, 37, 55, 10, 42, 42, 16, 48, 25, 25, + 57, 7, 35, 65, -11, 45, 74, -27, 55, 84, -42, 65, + 37, 62, 10, 39, 57, 12, 43, 45, 18, 49, 28, 26, + 57, 10, 36, 66, -7, 46, 75, -24, 56, 84, -39, 66, + 38, 64, 12, 40, 59, 15, 44, 48, 20, 51, 32, 28, + 58, 13, 38, 67, -4, 47, 75, -21, 57, 85, -36, 67, + 40, 66, 15, 42, 61, 17, 46, 50, 22, 52, 35, 30, + 59, 17, 39, 67, -1, 48, 76, -17, 58, 85, -33, 67, + 42, 68, 17, 43, 64, 19, 47, 53, 24, 53, 38, 32, + 60, 20, 40, 68, 3, 50, 77, -14, 59, 86, -30, 68, + 44, 70, 20, 45, 66, 22, 49, 56, 27, 54, 41, 34, + 61, 24, 42, 69, 7, 51, 77, -10, 60, 86, -26, 69, + 45, 72, 23, 47, 68, 24, 50, 58, 29, 55, 44, 35, + 62, 27, 43, 70, 10, 52, 78, -7, 61, 87, -23, 70, + 47, 74, 25, 48, 70, 27, 52, 61, 31, 57, 47, 37, + 63, 31, 45, 71, 14, 53, 79, -3, 62, 87, -20, 71, + 49, 76, 28, 50, 72, 29, 53, 63, 33, 58, 50, 39, + 64, 34, 46, 72, 17, 54, 80, 0, 63, 88, -17, 71, + 51, 78, 30, 52, 74, 32, 55, 66, 35, 59, 53, 41, + 66, 37, 48, 73, 21, 56, 80, 4, 64, 89, -13, 72, + 52, 80, 33, 53, 76, 34, 56, 68, 37, 61, 56, 43, + 67, 41, 50, 74, 24, 57, 81, 7, 65, 89, -10, 73, + 54, 82, 35, 55, 78, 36, 58, 71, 40, 62, 59, 45, + 68, 44, 51, 75, 27, 58, 82, 11, 66, 90, -6, 74, + 6, 33, -47, 13, 12, -34, 25, -11, -15, 36, -29, 2, + 48, -43, 18, 58, -54, 32, 69, -65, 44, 79, -74, 56, + 6, 34, -46, 14, 13, -33, 25, -11, -15, 36, -28, 2, + 48, -42, 18, 59, -54, 32, 69, -64, 44, 79, -74, 56, + 6, 35, -45, 14, 14, -33, 25, -10, -15, 36, -27, 2, + 48, -41, 18, 59, -53, 32, 69, -64, 44, 79, -74, 56, + 7, 36, -44, 15, 15, -32, 26, -8, -14, 37, -26, 2, + 48, -40, 18, 59, -53, 32, 69, -63, 45, 79, -73, 57, + 8, 36, -42, 15, 17, -31, 26, -6, -14, 37, -24, 3, + 48, -39, 18, 59, -52, 32, 69, -63, 45, 80, -73, 57, + 10, 37, -40, 16, 19, -29, 26, -4, -13, 37, -23, 3, + 48, -38, 19, 59, -51, 32, 69, -62, 45, 80, -72, 57, + 11, 38, -37, 17, 21, -28, 27, -1, -12, 38, -20, 4, + 49, -36, 19, 59, -49, 33, 69, -61, 45, 80, -71, 57, + 13, 39, -35, 18, 24, -26, 28, 2, -11, 38, -18, 4, + 49, -34, 19, 59, -47, 33, 70, -59, 45, 80, -70, 57, + 14, 40, -32, 19, 26, -24, 28, 5, -10, 38, -15, 5, + 49, -32, 20, 60, -46, 33, 70, -58, 46, 80, -69, 57, + 16, 42, -29, 20, 29, -22, 29, 8, -9, 39, -12, 6, + 50, -29, 20, 60, -44, 34, 70, -56, 46, 80, -67, 57, + 17, 43, -27, 22, 31, -20, 30, 11, -7, 40, -9, 7, + 50, -27, 21, 60, -41, 34, 70, -54, 46, 80, -66, 58, + 19, 45, -24, 23, 34, -18, 31, 14, -6, 40, -6, 8, + 50, -24, 22, 60, -39, 35, 70, -52, 47, 81, -64, 58, + 21, 46, -21, 25, 36, -15, 32, 18, -4, 41, -2, 9, + 51, -20, 23, 61, -36, 35, 71, -50, 47, 81, -62, 58, + 23, 48, -18, 26, 39, -13, 33, 21, -3, 42, 1, 10, + 51, -17, 23, 61, -33, 36, 71, -47, 47, 81, -60, 59, + 24, 50, -15, 28, 41, -10, 34, 24, -1, 42, 5, 11, + 52, -14, 24, 62, -30, 36, 71, -45, 48, 81, -58, 59, + 26, 52, -12, 29, 44, -8, 35, 27, 1, 43, 8, 13, + 53, -11, 25, 62, -27, 37, 72, -42, 49, 82, -56, 60, + 28, 54, -9, 31, 46, -5, 37, 31, 3, 44, 12, 14, + 53, -7, 26, 63, -24, 38, 72, -39, 49, 82, -53, 60, + 30, 55, -6, 32, 48, -3, 38, 34, 5, 45, 15, 16, + 54, -4, 27, 63, -21, 39, 73, -36, 50, 82, -50, 61, + 32, 57, -4, 34, 51, 0, 39, 37, 7, 46, 19, 17, + 55, 0, 28, 64, -17, 40, 73, -33, 50, 83, -48, 61, + 33, 59, -1, 35, 53, 2, 40, 40, 9, 47, 22, 19, + 56, 3, 30, 65, -14, 41, 74, -30, 51, 83, -45, 62, + 35, 61, 2, 37, 55, 5, 42, 43, 11, 48, 26, 20, + 57, 7, 31, 65, -10, 42, 74, -26, 52, 84, -42, 62, + 37, 63, 5, 39, 58, 7, 43, 46, 13, 50, 29, 22, + 58, 11, 32, 66, -7, 43, 75, -23, 53, 84, -39, 63, + 39, 65, 7, 40, 60, 10, 45, 48, 16, 51, 32, 24, + 58, 14, 34, 67, -3, 44, 75, -20, 54, 85, -36, 64, + 40, 67, 10, 42, 62, 12, 46, 51, 18, 52, 36, 25, + 59, 18, 35, 67, 0, 45, 76, -17, 54, 85, -33, 64, + 42, 69, 13, 44, 64, 15, 47, 53, 20, 53, 39, 27, + 60, 21, 36, 68, 3, 46, 77, -13, 55, 86, -29, 65, + 44, 71, 15, 45, 66, 17, 49, 56, 22, 54, 42, 29, + 61, 25, 38, 69, 7, 47, 77, -10, 56, 86, -26, 66, + 46, 72, 18, 47, 68, 20, 50, 59, 24, 56, 45, 31, + 62, 28, 39, 70, 11, 48, 78, -6, 57, 87, -23, 67, + 47, 74, 20, 48, 71, 22, 52, 61, 26, 57, 48, 33, + 63, 31, 41, 71, 14, 49, 79, -3, 58, 88, -19, 68, + 49, 76, 23, 50, 73, 25, 53, 64, 29, 58, 51, 35, + 64, 34, 42, 72, 17, 51, 80, 1, 59, 88, -16, 68, + 51, 78, 26, 52, 75, 27, 55, 66, 31, 59, 54, 37, + 66, 38, 44, 73, 21, 52, 80, 4, 61, 89, -12, 69, + 52, 80, 28, 53, 77, 29, 56, 69, 33, 61, 57, 38, + 67, 41, 46, 74, 24, 53, 81, 8, 62, 90, -9, 70, + 54, 82, 30, 55, 79, 32, 58, 71, 35, 62, 59, 40, + 68, 44, 47, 75, 28, 55, 82, 11, 63, 90, -6, 71, + 7, 37, -50, 14, 16, -38, 25, -8, -20, 37, -26, -3, + 48, -41, 13, 59, -53, 28, 69, -63, 41, 79, -74, 53, + 7, 37, -50, 15, 16, -37, 25, -7, -20, 37, -25, -3, + 48, -40, 13, 59, -52, 28, 69, -63, 41, 79, -73, 53, + 8, 37, -49, 15, 17, -37, 26, -6, -19, 37, -25, -3, + 48, -40, 13, 59, -52, 28, 69, -63, 41, 79, -73, 53, + 9, 38, -47, 15, 19, -36, 26, -5, -19, 37, -23, -2, + 48, -39, 14, 59, -51, 28, 69, -62, 41, 80, -72, 53, + 9, 38, -46, 16, 20, -35, 26, -3, -18, 37, -22, -2, + 48, -38, 14, 59, -50, 28, 69, -61, 41, 80, -72, 53, + 11, 39, -44, 17, 22, -34, 27, -1, -18, 37, -20, -2, + 48, -36, 14, 59, -49, 28, 69, -61, 41, 80, -71, 53, + 12, 40, -41, 18, 24, -32, 27, 1, -17, 38, -18, -1, + 49, -35, 15, 59, -48, 28, 69, -59, 41, 80, -70, 54, + 13, 41, -39, 19, 26, -30, 28, 4, -16, 38, -16, 0, + 49, -32, 15, 59, -46, 29, 70, -58, 42, 80, -69, 54, + 15, 42, -36, 20, 28, -29, 29, 7, -15, 39, -13, 0, + 49, -30, 15, 60, -44, 29, 70, -57, 42, 80, -68, 54, + 16, 43, -34, 21, 30, -27, 29, 10, -13, 39, -10, 1, + 50, -28, 16, 60, -42, 30, 70, -55, 42, 80, -67, 54, + 18, 45, -31, 22, 33, -25, 30, 13, -12, 40, -7, 2, + 50, -25, 17, 60, -40, 30, 70, -53, 42, 80, -65, 54, + 20, 46, -28, 23, 35, -22, 31, 16, -11, 40, -4, 3, + 51, -22, 17, 61, -38, 31, 71, -51, 43, 81, -63, 55, + 22, 48, -25, 25, 38, -20, 32, 19, -9, 41, -1, 4, + 51, -19, 18, 61, -35, 31, 71, -49, 43, 81, -61, 55, + 23, 49, -23, 26, 40, -18, 33, 22, -7, 42, 3, 5, + 52, -16, 19, 61, -32, 32, 71, -46, 44, 81, -59, 55, + 25, 51, -20, 28, 42, -15, 34, 25, -5, 43, 6, 7, + 52, -13, 20, 62, -29, 32, 72, -44, 44, 81, -57, 56, + 27, 53, -17, 29, 45, -13, 35, 28, -4, 44, 9, 8, + 53, -10, 21, 62, -26, 33, 72, -41, 45, 82, -55, 56, + 28, 55, -14, 31, 47, -10, 37, 32, -2, 45, 13, 10, + 54, -6, 22, 63, -23, 34, 72, -38, 46, 82, -52, 57, + 30, 56, -11, 33, 49, -8, 38, 35, 0, 45, 17, 11, + 54, -3, 23, 63, -20, 35, 73, -35, 46, 83, -50, 57, + 32, 58, -9, 34, 52, -5, 39, 38, 2, 46, 20, 13, + 55, 1, 24, 64, -16, 36, 73, -32, 47, 83, -47, 58, + 34, 60, -6, 36, 54, -3, 41, 40, 4, 47, 23, 14, + 56, 4, 25, 65, -13, 37, 74, -29, 48, 83, -44, 58, + 35, 62, -3, 37, 56, 0, 42, 44, 7, 49, 27, 16, + 57, 8, 27, 65, -9, 38, 74, -26, 48, 84, -41, 59, + 37, 64, 0, 39, 58, 3, 43, 46, 9, 50, 30, 18, + 58, 12, 28, 66, -6, 39, 75, -23, 49, 84, -38, 60, + 39, 65, 3, 41, 60, 5, 45, 49, 11, 51, 33, 19, + 59, 15, 29, 67, -3, 40, 76, -19, 50, 85, -35, 60, + 41, 67, 5, 42, 63, 7, 46, 52, 13, 52, 36, 21, + 59, 18, 31, 68, 1, 41, 76, -16, 51, 85, -32, 61, + 42, 69, 8, 44, 65, 10, 47, 54, 15, 53, 39, 23, + 60, 22, 32, 68, 4, 42, 77, -13, 52, 86, -29, 62, + 44, 71, 11, 45, 67, 13, 49, 57, 18, 54, 43, 25, + 62, 25, 34, 69, 8, 43, 78, -9, 53, 86, -25, 63, + 46, 73, 13, 47, 69, 15, 50, 59, 20, 56, 46, 27, + 63, 29, 35, 70, 11, 44, 78, -6, 54, 87, -22, 64, + 47, 75, 16, 49, 71, 17, 52, 62, 22, 57, 48, 28, + 64, 32, 37, 71, 15, 46, 79, -2, 55, 88, -19, 64, + 49, 77, 18, 50, 73, 20, 53, 64, 24, 58, 51, 30, + 65, 35, 38, 72, 18, 47, 80, 1, 56, 88, -16, 65, + 51, 79, 21, 52, 75, 23, 55, 67, 26, 60, 54, 32, + 66, 38, 40, 73, 22, 48, 81, 5, 57, 89, -12, 66, + 52, 80, 23, 54, 77, 25, 56, 69, 29, 61, 57, 34, + 67, 41, 42, 74, 25, 50, 81, 8, 58, 90, -9, 67, + 54, 82, 26, 55, 79, 27, 58, 71, 31, 62, 60, 36, + 68, 44, 43, 75, 28, 51, 82, 11, 59, 90, -5, 68, + 8, 40, -54, 15, 20, -42, 26, -4, -25, 37, -23, -8, + 48, -38, 8, 59, -51, 23, 69, -62, 36, 80, -72, 49, + 9, 40, -53, 15, 20, -42, 26, -3, -25, 37, -22, -8, + 48, -38, 8, 59, -51, 23, 69, -62, 36, 80, -72, 49, + 9, 40, -52, 16, 21, -41, 26, -3, -25, 37, -22, -8, + 48, -37, 9, 59, -50, 23, 69, -61, 36, 80, -72, 49, + 10, 40, -51, 16, 22, -40, 26, -1, -24, 37, -21, -7, + 48, -36, 9, 59, -49, 23, 69, -61, 37, 80, -71, 49, + 11, 41, -49, 17, 23, -40, 27, 0, -24, 37, -19, -7, + 48, -35, 9, 59, -49, 23, 69, -60, 37, 80, -71, 49, + 12, 41, -48, 17, 25, -38, 27, 2, -23, 38, -18, -7, + 49, -34, 9, 59, -47, 24, 69, -59, 37, 80, -70, 49, + 13, 42, -46, 18, 27, -37, 28, 4, -22, 38, -16, -6, + 49, -32, 10, 59, -46, 24, 70, -58, 37, 80, -69, 50, + 14, 43, -43, 19, 29, -35, 28, 7, -21, 38, -13, -5, + 49, -30, 10, 60, -44, 24, 70, -57, 37, 80, -68, 50, + 16, 44, -41, 20, 31, -33, 29, 9, -20, 39, -11, -5, + 50, -28, 11, 60, -43, 25, 70, -55, 38, 80, -67, 50, + 17, 45, -39, 22, 33, -32, 30, 12, -19, 39, -8, -4, + 50, -26, 11, 60, -41, 25, 70, -54, 38, 80, -65, 50, + 19, 46, -36, 23, 35, -30, 31, 15, -17, 40, -5, -3, + 50, -23, 12, 60, -39, 25, 70, -52, 38, 81, -64, 51, + 20, 48, -33, 24, 37, -27, 31, 18, -16, 41, -2, -2, + 51, -21, 12, 61, -36, 26, 71, -50, 39, 81, -62, 51, + 22, 49, -30, 26, 39, -25, 33, 21, -14, 41, 1, -1, + 51, -18, 13, 61, -33, 27, 71, -47, 39, 81, -60, 51, + 24, 51, -28, 27, 42, -23, 34, 24, -12, 42, 4, 0, + 52, -15, 14, 62, -31, 27, 71, -45, 40, 81, -58, 52, + 25, 52, -25, 28, 44, -20, 35, 27, -11, 43, 8, 2, + 52, -11, 15, 62, -28, 28, 72, -43, 40, 82, -56, 52, + 27, 54, -22, 30, 46, -18, 36, 30, -9, 44, 11, 3, + 53, -8, 16, 62, -25, 29, 72, -40, 41, 82, -54, 52, + 29, 56, -19, 31, 48, -15, 37, 33, -7, 45, 15, 4, + 54, -5, 17, 63, -22, 29, 72, -37, 41, 82, -51, 53, + 31, 57, -17, 33, 50, -13, 38, 36, -5, 46, 18, 6, + 54, -1, 18, 64, -19, 30, 73, -34, 42, 83, -49, 53, + 32, 59, -14, 34, 53, -10, 40, 39, -3, 47, 21, 7, + 55, 2, 19, 64, -15, 31, 73, -31, 43, 83, -46, 54, + 34, 61, -11, 36, 55, -8, 41, 41, -1, 48, 24, 9, + 56, 5, 21, 65, -12, 32, 74, -28, 43, 83, -43, 55, + 36, 63, -8, 38, 57, -5, 42, 44, 1, 49, 28, 11, + 57, 9, 22, 66, -8, 33, 74, -25, 44, 84, -40, 55, + 37, 64, -5, 39, 59, -3, 44, 47, 4, 50, 31, 12, + 58, 12, 23, 66, -5, 34, 75, -22, 45, 84, -37, 56, + 39, 66, -3, 41, 61, 0, 45, 50, 6, 51, 34, 14, + 59, 16, 25, 67, -2, 35, 76, -18, 46, 85, -34, 57, + 41, 68, 0, 42, 63, 2, 46, 52, 8, 52, 37, 16, + 60, 19, 26, 68, 2, 36, 76, -15, 47, 85, -31, 57, + 42, 70, 2, 44, 65, 5, 48, 55, 10, 53, 40, 18, + 61, 22, 27, 68, 5, 37, 77, -12, 48, 86, -28, 58, + 44, 72, 5, 46, 68, 7, 49, 58, 12, 55, 43, 20, + 62, 26, 29, 69, 9, 39, 78, -8, 49, 86, -25, 59, + 46, 74, 8, 47, 70, 10, 51, 60, 15, 56, 46, 22, + 63, 29, 30, 70, 12, 40, 78, -5, 50, 87, -21, 60, + 48, 75, 10, 49, 72, 12, 52, 62, 17, 57, 49, 23, + 64, 32, 32, 71, 15, 41, 79, -2, 51, 88, -18, 61, + 49, 77, 13, 50, 74, 15, 53, 65, 19, 58, 52, 25, + 65, 36, 34, 72, 19, 42, 80, 2, 52, 88, -15, 61, + 51, 79, 16, 52, 76, 17, 55, 67, 21, 60, 55, 27, + 66, 39, 35, 73, 22, 44, 81, 5, 53, 89, -11, 62, + 53, 81, 18, 54, 78, 20, 57, 70, 23, 61, 58, 29, + 67, 42, 37, 74, 26, 45, 81, 9, 54, 90, -8, 63, + 54, 83, 21, 55, 80, 22, 58, 72, 26, 62, 60, 31, + 68, 45, 39, 75, 29, 47, 82, 12, 55, 90, -5, 64, + 9, 42, -57, 16, 23, -46, 26, -1, -29, 37, -20, -13, + 48, -36, 4, 59, -49, 19, 69, -61, 32, 80, -71, 46, + 10, 42, -56, 16, 24, -46, 26, 0, -29, 37, -20, -12, + 48, -36, 4, 59, -49, 19, 69, -60, 33, 80, -71, 46, + 10, 42, -55, 17, 24, -45, 27, 1, -29, 37, -19, -12, + 48, -35, 4, 59, -48, 19, 69, -60, 33, 80, -71, 46, + 11, 42, -54, 17, 25, -44, 27, 2, -29, 38, -18, -12, + 49, -34, 4, 59, -48, 19, 69, -59, 33, 80, -70, 46, + 12, 43, -53, 18, 26, -44, 27, 3, -28, 38, -17, -12, + 49, -33, 5, 59, -47, 19, 69, -59, 33, 80, -70, 46, + 13, 43, -51, 18, 28, -42, 28, 5, -27, 38, -15, -11, + 49, -32, 5, 59, -46, 19, 70, -58, 33, 80, -69, 46, + 14, 44, -49, 19, 29, -41, 28, 7, -26, 38, -13, -11, + 49, -30, 5, 59, -45, 20, 70, -57, 33, 80, -68, 46, + 15, 45, -47, 20, 31, -39, 29, 9, -25, 39, -11, -10, + 49, -28, 6, 60, -43, 20, 70, -55, 33, 80, -67, 46, + 17, 46, -45, 21, 33, -38, 29, 12, -24, 39, -9, -9, + 50, -26, 6, 60, -41, 20, 70, -54, 34, 80, -66, 46, + 18, 47, -43, 22, 35, -36, 30, 14, -23, 40, -6, -8, + 50, -24, 7, 60, -39, 21, 70, -52, 34, 80, -64, 47, + 19, 48, -40, 23, 37, -34, 31, 17, -22, 40, -3, -8, + 50, -22, 7, 61, -37, 21, 70, -51, 34, 81, -63, 47, + 21, 49, -38, 25, 39, -32, 32, 20, -20, 41, 0, -7, + 51, -19, 8, 61, -35, 22, 71, -49, 35, 81, -61, 47, + 23, 50, -35, 26, 41, -29, 33, 23, -19, 42, 3, -5, + 51, -16, 9, 61, -32, 22, 71, -46, 35, 81, -59, 48, + 24, 52, -32, 27, 43, -27, 34, 26, -17, 42, 6, -4, + 52, -13, 10, 62, -30, 23, 71, -44, 36, 81, -57, 48, + 26, 53, -29, 29, 45, -25, 35, 28, -15, 43, 9, -3, + 53, -10, 11, 62, -27, 24, 72, -42, 36, 82, -55, 48, + 27, 55, -27, 30, 47, -23, 36, 31, -13, 44, 12, -2, + 53, -7, 12, 63, -24, 24, 72, -39, 37, 82, -53, 49, + 29, 57, -24, 32, 49, -20, 37, 34, -11, 45, 16, 0, + 54, -3, 13, 63, -21, 25, 73, -36, 37, 82, -50, 49, + 31, 58, -21, 33, 52, -18, 39, 37, -9, 46, 19, 1, + 55, 0, 14, 64, -18, 26, 73, -33, 38, 83, -48, 50, + 33, 60, -18, 35, 54, -15, 40, 40, -7, 47, 22, 3, + 55, 3, 15, 64, -14, 27, 74, -30, 39, 83, -45, 50, + 34, 62, -16, 36, 56, -13, 41, 42, -5, 48, 25, 4, + 56, 6, 16, 65, -11, 28, 74, -27, 40, 83, -42, 51, + 36, 63, -13, 38, 58, -10, 43, 45, -3, 49, 29, 6, + 57, 10, 18, 66, -8, 29, 75, -24, 40, 84, -39, 52, + 38, 65, -10, 40, 60, -7, 44, 48, -1, 50, 32, 8, + 58, 13, 19, 66, -4, 30, 75, -21, 41, 84, -36, 52, + 39, 67, -7, 41, 62, -5, 45, 51, 1, 51, 35, 10, + 59, 17, 20, 67, -1, 31, 76, -18, 42, 85, -34, 53, + 41, 69, -5, 43, 64, -2, 47, 53, 3, 52, 38, 11, + 60, 20, 22, 68, 2, 32, 76, -14, 43, 85, -31, 54, + 43, 70, -2, 44, 66, 0, 48, 56, 5, 53, 41, 13, + 61, 23, 23, 69, 6, 33, 77, -11, 44, 86, -27, 55, + 44, 72, 1, 46, 68, 3, 49, 58, 8, 55, 44, 15, + 62, 27, 25, 69, 9, 35, 78, -8, 45, 87, -24, 55, + 46, 74, 3, 47, 70, 5, 51, 61, 10, 56, 47, 17, + 63, 30, 26, 70, 13, 36, 78, -4, 46, 87, -21, 56, + 48, 76, 6, 49, 72, 8, 52, 63, 12, 57, 50, 19, + 64, 33, 28, 71, 16, 37, 79, -1, 47, 88, -18, 57, + 49, 78, 8, 51, 74, 10, 54, 65, 14, 58, 52, 21, + 65, 36, 29, 72, 19, 38, 80, 2, 48, 88, -14, 58, + 51, 80, 11, 52, 76, 13, 55, 68, 17, 60, 55, 23, + 66, 40, 31, 73, 23, 40, 81, 6, 49, 89, -11, 59, + 53, 81, 14, 54, 78, 15, 57, 70, 19, 61, 58, 25, + 67, 43, 33, 74, 26, 41, 82, 9, 50, 90, -8, 60, + 54, 83, 16, 55, 80, 17, 58, 72, 21, 62, 61, 27, + 68, 46, 34, 75, 29, 43, 82, 13, 52, 90, -4, 61, + 11, 44, -60, 17, 26, -50, 27, 3, -34, 37, -17, -17, + 49, -34, 0, 59, -47, 15, 69, -59, 29, 80, -70, 42, + 11, 44, -59, 17, 27, -50, 27, 3, -34, 38, -17, -17, + 49, -33, 0, 59, -47, 15, 69, -59, 29, 80, -70, 42, + 12, 44, -59, 17, 27, -49, 27, 4, -33, 38, -16, -17, + 49, -33, 0, 59, -47, 15, 69, -58, 29, 80, -69, 42, + 12, 45, -58, 18, 28, -48, 27, 5, -33, 38, -15, -16, + 49, -32, 0, 59, -46, 15, 69, -58, 29, 80, -69, 42, + 13, 45, -56, 18, 29, -47, 28, 6, -32, 38, -14, -16, + 49, -31, 0, 59, -45, 15, 70, -57, 29, 80, -68, 42, + 14, 45, -55, 19, 30, -46, 28, 8, -32, 38, -12, -16, + 49, -30, 0, 59, -44, 15, 70, -56, 29, 80, -68, 42, + 15, 46, -53, 20, 32, -45, 29, 10, -31, 39, -11, -15, + 49, -28, 1, 60, -43, 15, 70, -55, 29, 80, -67, 42, + 16, 47, -51, 21, 33, -43, 29, 12, -30, 39, -8, -14, + 50, -26, 1, 60, -41, 16, 70, -54, 29, 80, -66, 43, + 17, 47, -49, 22, 35, -42, 30, 14, -29, 39, -6, -14, + 50, -24, 2, 60, -40, 16, 70, -53, 30, 80, -65, 43, + 19, 48, -47, 23, 37, -40, 31, 17, -28, 40, -4, -13, + 50, -22, 2, 60, -38, 17, 70, -51, 30, 81, -63, 43, + 20, 49, -44, 24, 39, -38, 31, 19, -26, 41, -1, -12, + 51, -20, 3, 61, -36, 17, 71, -49, 30, 81, -62, 43, + 22, 50, -42, 25, 40, -36, 32, 22, -25, 41, 2, -11, + 51, -17, 4, 61, -33, 18, 71, -47, 31, 81, -60, 44, + 23, 52, -39, 27, 43, -34, 33, 25, -23, 42, 5, -10, + 52, -14, 5, 61, -31, 18, 71, -45, 31, 81, -58, 44, + 25, 53, -36, 28, 45, -32, 34, 27, -21, 43, 8, -9, + 52, -12, 5, 62, -28, 19, 72, -43, 32, 81, -56, 44, + 26, 55, -34, 29, 46, -29, 35, 30, -20, 43, 11, -7, + 53, -9, 6, 62, -25, 20, 72, -40, 32, 82, -54, 45, + 28, 56, -31, 31, 48, -27, 36, 33, -18, 44, 14, -6, + 53, -6, 7, 63, -23, 20, 72, -38, 33, 82, -52, 45, + 30, 58, -28, 32, 51, -24, 38, 36, -16, 45, 17, -5, + 54, -2, 8, 63, -19, 21, 73, -35, 34, 82, -49, 46, + 31, 59, -26, 34, 53, -22, 39, 38, -14, 46, 20, -3, + 55, 1, 9, 64, -16, 22, 73, -32, 34, 83, -47, 46, + 33, 61, -23, 35, 55, -20, 40, 41, -12, 47, 23, -2, + 56, 4, 11, 64, -13, 23, 74, -29, 35, 83, -44, 47, + 35, 62, -20, 37, 57, -17, 41, 44, -10, 48, 26, 0, + 56, 8, 12, 65, -10, 24, 74, -26, 36, 84, -42, 47, + 36, 64, -17, 38, 59, -14, 43, 46, -8, 49, 30, 2, + 57, 11, 13, 66, -6, 25, 75, -23, 37, 84, -38, 48, + 38, 66, -15, 40, 61, -12, 44, 49, -6, 50, 33, 3, + 58, 14, 15, 66, -3, 26, 75, -20, 37, 85, -36, 49, + 40, 68, -12, 41, 63, -10, 45, 51, -4, 51, 36, 5, + 59, 18, 16, 67, 0, 27, 76, -17, 38, 85, -33, 50, + 41, 69, -9, 43, 65, -7, 47, 54, -1, 53, 39, 7, + 60, 21, 17, 68, 3, 28, 76, -14, 39, 86, -30, 50, + 43, 71, -7, 44, 67, -5, 48, 56, 1, 54, 42, 9, + 61, 24, 19, 69, 7, 29, 77, -10, 40, 86, -27, 51, + 45, 73, -4, 46, 69, -2, 50, 59, 3, 55, 45, 11, + 62, 28, 20, 70, 10, 31, 78, -7, 41, 87, -23, 52, + 46, 75, -1, 48, 71, 1, 51, 61, 5, 56, 48, 13, + 63, 31, 22, 70, 13, 32, 79, -4, 42, 87, -20, 53, + 48, 76, 1, 49, 73, 3, 52, 64, 8, 57, 50, 15, + 64, 34, 23, 71, 17, 33, 79, 0, 43, 88, -17, 54, + 50, 78, 4, 51, 75, 5, 54, 66, 10, 59, 53, 16, + 65, 37, 25, 72, 20, 34, 80, 3, 44, 88, -14, 54, + 51, 80, 6, 53, 77, 8, 55, 69, 12, 60, 56, 19, + 66, 40, 27, 73, 24, 36, 81, 7, 45, 89, -10, 55, + 53, 82, 9, 54, 79, 11, 57, 71, 14, 61, 59, 20, + 67, 43, 28, 74, 27, 37, 82, 10, 47, 90, -7, 56, + 55, 84, 11, 56, 81, 13, 58, 73, 17, 63, 61, 22, + 68, 46, 30, 75, 30, 39, 82, 13, 48, 91, -4, 57, + 12, 46, -63, 18, 30, -54, 27, 6, -38, 38, -14, -21, + 49, -31, -5, 59, -45, 10, 69, -57, 24, 80, -69, 38, + 12, 46, -62, 18, 30, -53, 27, 7, -38, 38, -14, -21, + 49, -31, -5, 59, -45, 10, 70, -57, 25, 80, -68, 38, + 13, 46, -62, 18, 31, -53, 28, 7, -37, 38, -13, -21, + 49, -30, -5, 59, -45, 11, 70, -57, 25, 80, -68, 38, + 13, 47, -61, 19, 31, -52, 28, 8, -37, 38, -12, -21, + 49, -30, -4, 59, -44, 11, 70, -56, 25, 80, -68, 38, + 14, 47, -60, 19, 32, -51, 28, 10, -36, 38, -11, -20, + 49, -29, -4, 60, -43, 11, 70, -56, 25, 80, -67, 38, + 15, 47, -58, 20, 33, -50, 29, 11, -36, 39, -10, -20, + 49, -28, -4, 60, -42, 11, 70, -55, 25, 80, -66, 38, + 16, 48, -57, 21, 34, -49, 29, 13, -35, 39, -8, -20, + 50, -26, -4, 60, -41, 11, 70, -54, 25, 80, -66, 39, + 17, 48, -54, 21, 36, -47, 30, 15, -34, 39, -6, -19, + 50, -24, -3, 60, -39, 12, 70, -52, 25, 80, -65, 39, + 18, 49, -52, 22, 37, -46, 30, 17, -33, 40, -4, -18, + 50, -22, -3, 60, -38, 12, 70, -51, 26, 80, -63, 39, + 20, 50, -50, 23, 39, -44, 31, 19, -32, 40, -1, -17, + 51, -20, -2, 61, -36, 12, 71, -50, 26, 81, -62, 39, + 21, 51, -48, 25, 41, -42, 32, 21, -31, 41, 1, -16, + 51, -18, -1, 61, -34, 13, 71, -48, 26, 81, -61, 40, + 22, 52, -46, 26, 42, -40, 33, 24, -29, 41, 4, -15, + 51, -16, -1, 61, -32, 13, 71, -46, 27, 81, -59, 40, + 24, 53, -43, 27, 44, -38, 34, 27, -27, 42, 7, -14, + 52, -13, 0, 62, -29, 14, 71, -44, 27, 81, -57, 40, + 25, 55, -41, 28, 46, -36, 35, 29, -26, 43, 10, -13, + 52, -10, 1, 62, -27, 15, 72, -41, 28, 82, -55, 41, + 27, 56, -38, 30, 48, -34, 36, 32, -24, 44, 12, -12, + 53, -7, 2, 62, -24, 15, 72, -39, 28, 82, -53, 41, + 28, 57, -35, 31, 50, -31, 37, 34, -22, 45, 15, -11, + 54, -4, 3, 63, -21, 16, 72, -37, 29, 82, -51, 41, + 30, 59, -33, 33, 52, -29, 38, 37, -20, 45, 19, -9, + 54, -1, 4, 63, -18, 17, 73, -34, 30, 83, -48, 42, + 32, 60, -30, 34, 54, -26, 39, 40, -18, 46, 22, -8, + 55, 3, 5, 64, -15, 18, 73, -31, 30, 83, -46, 43, + 33, 62, -27, 36, 56, -24, 40, 42, -16, 47, 25, -6, + 56, 6, 6, 65, -12, 19, 74, -28, 31, 83, -43, 43, + 35, 63, -25, 37, 58, -22, 42, 45, -14, 48, 28, -4, + 57, 9, 7, 65, -9, 20, 74, -25, 32, 84, -41, 44, + 37, 65, -22, 39, 60, -19, 43, 48, -12, 49, 31, -3, + 57, 12, 9, 66, -5, 21, 75, -22, 33, 84, -38, 44, + 38, 67, -19, 40, 62, -16, 44, 50, -10, 51, 34, -1, + 58, 16, 10, 67, -2, 22, 75, -19, 33, 85, -35, 45, + 40, 69, -17, 42, 64, -14, 46, 52, -8, 52, 37, 1, + 59, 19, 12, 67, 1, 23, 76, -16, 34, 85, -32, 46, + 42, 70, -14, 43, 66, -12, 47, 55, -6, 53, 40, 3, + 60, 22, 13, 68, 4, 24, 77, -13, 35, 86, -29, 47, + 43, 72, -11, 45, 67, -9, 48, 57, -4, 54, 43, 4, + 61, 25, 14, 69, 7, 25, 77, -10, 36, 86, -26, 47, + 45, 74, -9, 46, 70, -6, 50, 60, -1, 55, 46, 6, + 62, 28, 16, 70, 11, 26, 78, -6, 37, 87, -22, 48, + 47, 75, -6, 48, 72, -4, 51, 62, 1, 56, 48, 8, + 63, 32, 18, 71, 14, 28, 79, -3, 38, 87, -19, 49, + 48, 77, -3, 49, 73, -2, 53, 64, 3, 58, 51, 10, + 64, 35, 19, 71, 18, 29, 79, 1, 39, 88, -16, 50, + 50, 79, -1, 51, 75, 1, 54, 67, 5, 59, 54, 12, + 65, 38, 21, 72, 21, 30, 80, 4, 40, 89, -13, 51, + 52, 81, 2, 53, 77, 4, 56, 69, 8, 60, 57, 14, + 66, 41, 23, 73, 24, 32, 81, 7, 42, 89, -10, 52, + 53, 82, 4, 54, 79, 6, 57, 71, 10, 61, 59, 16, + 67, 44, 24, 74, 27, 33, 82, 11, 43, 90, -6, 53, + 55, 84, 7, 56, 81, 8, 58, 74, 12, 63, 62, 18, + 69, 47, 26, 75, 31, 35, 83, 14, 44, 91, -3, 54, + 14, 49, -66, 19, 33, -58, 28, 10, -43, 38, -11, -26, + 49, -29, -10, 59, -43, 6, 70, -56, 20, 80, -67, 34, + 14, 49, -66, 19, 34, -57, 28, 11, -42, 38, -10, -26, + 49, -28, -10, 59, -43, 6, 70, -55, 20, 80, -67, 34, + 14, 49, -65, 19, 34, -57, 28, 11, -42, 38, -10, -26, + 49, -28, -9, 60, -42, 6, 70, -55, 20, 80, -67, 34, + 15, 49, -64, 20, 35, -56, 29, 12, -42, 39, -9, -26, + 49, -27, -9, 60, -42, 6, 70, -54, 20, 80, -66, 34, + 15, 49, -63, 20, 35, -55, 29, 13, -41, 39, -8, -25, + 49, -26, -9, 60, -41, 6, 70, -54, 20, 80, -66, 34, + 16, 50, -62, 21, 36, -54, 29, 14, -40, 39, -6, -25, + 50, -25, -9, 60, -40, 6, 70, -53, 20, 80, -65, 34, + 17, 50, -60, 21, 37, -53, 30, 16, -40, 39, -5, -24, + 50, -23, -8, 60, -39, 7, 70, -52, 21, 80, -64, 34, + 18, 51, -58, 22, 39, -52, 30, 18, -39, 40, -3, -24, + 50, -22, -8, 60, -37, 7, 70, -51, 21, 80, -63, 35, + 19, 51, -57, 23, 40, -50, 31, 20, -38, 40, -1, -23, + 50, -20, -7, 60, -36, 7, 70, -49, 21, 81, -62, 35, + 21, 52, -54, 24, 41, -49, 32, 22, -37, 41, 1, -22, + 51, -18, -7, 61, -34, 8, 71, -48, 21, 81, -61, 35, + 22, 53, -52, 25, 43, -47, 32, 24, -35, 41, 4, -21, + 51, -16, -6, 61, -32, 8, 71, -46, 22, 81, -59, 35, + 23, 54, -50, 26, 44, -45, 33, 26, -34, 42, 6, -20, + 52, -13, -6, 61, -30, 9, 71, -44, 22, 81, -58, 36, + 25, 55, -47, 28, 46, -43, 34, 29, -32, 43, 9, -19, + 52, -10, -5, 62, -27, 9, 71, -42, 23, 81, -56, 36, + 26, 56, -45, 29, 48, -41, 35, 31, -31, 43, 12, -18, + 53, -8, -4, 62, -25, 10, 72, -40, 23, 82, -54, 36, + 28, 57, -43, 30, 50, -38, 36, 34, -29, 44, 14, -17, + 53, -5, -3, 63, -22, 11, 72, -38, 24, 82, -52, 37, + 29, 59, -40, 32, 51, -36, 37, 36, -27, 45, 17, -15, + 54, -2, -2, 63, -20, 11, 73, -35, 24, 82, -50, 37, + 31, 60, -37, 33, 53, -34, 38, 39, -25, 46, 21, -14, + 55, 1, -1, 64, -16, 12, 73, -32, 25, 83, -47, 38, + 32, 62, -35, 35, 55, -31, 40, 41, -23, 47, 23, -12, + 55, 4, 0, 64, -14, 13, 73, -30, 26, 83, -45, 38, + 34, 63, -32, 36, 57, -29, 41, 44, -21, 48, 26, -11, + 56, 7, 1, 65, -11, 14, 74, -27, 26, 83, -42, 39, + 35, 65, -30, 37, 59, -27, 42, 46, -19, 49, 29, -9, + 57, 10, 3, 65, -8, 15, 74, -24, 27, 84, -39, 39, + 37, 66, -27, 39, 61, -24, 43, 49, -17, 50, 32, -8, + 58, 14, 4, 66, -4, 16, 75, -21, 28, 84, -36, 40, + 39, 68, -24, 41, 63, -21, 45, 51, -15, 51, 35, -6, + 59, 17, 5, 67, -1, 17, 76, -18, 29, 85, -34, 41, + 40, 69, -22, 42, 65, -19, 46, 54, -13, 52, 38, -4, + 59, 20, 7, 68, 2, 18, 76, -15, 30, 85, -31, 42, + 42, 71, -19, 44, 67, -17, 47, 56, -11, 53, 41, -2, + 60, 23, 8, 68, 5, 19, 77, -12, 31, 86, -28, 42, + 44, 73, -16, 45, 68, -14, 49, 58, -9, 54, 44, -1, + 61, 26, 10, 69, 9, 20, 77, -8, 32, 86, -25, 43, + 45, 75, -14, 47, 71, -11, 50, 61, -6, 55, 47, 1, + 62, 30, 11, 70, 12, 22, 78, -5, 33, 87, -22, 44, + 47, 76, -11, 48, 72, -9, 52, 63, -4, 57, 49, 3, + 63, 33, 13, 71, 15, 23, 79, -2, 34, 87, -18, 45, + 49, 78, -8, 50, 74, -7, 53, 65, -2, 58, 52, 5, + 64, 36, 14, 72, 18, 24, 79, 1, 35, 88, -15, 46, + 50, 80, -6, 51, 76, -4, 54, 67, 0, 59, 55, 7, + 65, 39, 16, 72, 22, 26, 80, 5, 36, 89, -12, 47, + 52, 81, -3, 53, 78, -1, 56, 70, 3, 60, 58, 9, + 67, 42, 18, 73, 25, 27, 81, 8, 37, 89, -9, 48, + 53, 83, -1, 55, 80, 1, 57, 72, 5, 62, 60, 11, + 68, 45, 19, 74, 28, 29, 82, 11, 38, 90, -6, 49, + 55, 85, 2, 56, 82, 3, 59, 74, 7, 63, 63, 13, + 69, 48, 21, 75, 31, 30, 83, 15, 40, 91, -2, 50, + 15, 51, -69, 20, 36, -61, 29, 14, -47, 39, -7, -30, + 49, -26, -14, 60, -41, 1, 70, -54, 16, 80, -66, 30, + 15, 51, -69, 20, 37, -61, 29, 14, -46, 39, -7, -30, + 49, -25, -14, 60, -40, 1, 70, -53, 16, 80, -65, 30, + 16, 51, -68, 20, 37, -60, 29, 15, -46, 39, -7, -30, + 49, -25, -14, 60, -40, 2, 70, -53, 16, 80, -65, 30, + 16, 51, -67, 21, 38, -60, 29, 15, -46, 39, -6, -30, + 50, -24, -14, 60, -39, 2, 70, -53, 16, 80, -65, 30, + 17, 51, -66, 21, 38, -59, 29, 16, -45, 39, -5, -30, + 50, -23, -13, 60, -39, 2, 70, -52, 16, 80, -64, 30, + 17, 52, -65, 22, 39, -58, 30, 18, -45, 39, -4, -29, + 50, -22, -13, 60, -38, 2, 70, -51, 16, 80, -63, 30, + 18, 52, -64, 22, 40, -57, 30, 19, -44, 40, -2, -29, + 50, -21, -13, 60, -37, 2, 70, -50, 17, 80, -63, 30, + 19, 53, -62, 23, 41, -55, 31, 21, -43, 40, 0, -28, + 50, -19, -12, 60, -35, 3, 70, -49, 17, 81, -62, 31, + 20, 53, -60, 24, 42, -54, 31, 22, -42, 41, 2, -27, + 51, -18, -12, 61, -34, 3, 71, -48, 17, 81, -60, 31, + 21, 54, -58, 25, 44, -52, 32, 24, -41, 41, 4, -26, + 51, -16, -11, 61, -32, 3, 71, -46, 17, 81, -59, 31, + 23, 55, -56, 26, 45, -51, 33, 26, -39, 42, 6, -26, + 51, -13, -11, 61, -30, 4, 71, -45, 18, 81, -58, 31, + 24, 56, -54, 27, 46, -49, 34, 28, -38, 42, 8, -25, + 52, -11, -10, 62, -28, 4, 71, -43, 18, 81, -56, 32, + 25, 57, -51, 28, 48, -47, 35, 31, -36, 43, 11, -23, + 52, -8, -9, 62, -25, 5, 72, -41, 19, 82, -54, 32, + 27, 58, -49, 30, 50, -45, 36, 33, -35, 44, 14, -22, + 53, -6, -8, 62, -23, 6, 72, -38, 19, 82, -52, 32, + 28, 59, -47, 31, 51, -42, 37, 35, -33, 44, 16, -21, + 53, -3, -7, 63, -21, 6, 72, -36, 20, 82, -50, 33, + 30, 60, -44, 32, 53, -40, 38, 38, -32, 45, 19, -20, + 54, 0, -6, 63, -18, 7, 73, -34, 20, 82, -48, 33, + 31, 62, -41, 34, 55, -38, 39, 40, -29, 46, 22, -18, + 55, 3, -5, 64, -15, 8, 73, -31, 21, 83, -46, 34, + 33, 63, -39, 35, 57, -36, 40, 43, -28, 47, 25, -17, + 56, 6, -4, 64, -12, 9, 74, -28, 22, 83, -43, 34, + 34, 64, -36, 36, 58, -33, 41, 45, -26, 48, 28, -15, + 56, 9, -3, 65, -9, 10, 74, -26, 22, 84, -41, 35, + 36, 66, -34, 38, 60, -31, 42, 47, -24, 49, 31, -14, + 57, 12, -2, 66, -6, 11, 75, -23, 23, 84, -38, 36, + 38, 67, -31, 39, 62, -28, 44, 50, -21, 50, 34, -12, + 58, 15, 0, 66, -3, 12, 75, -20, 24, 84, -35, 36, + 39, 69, -28, 41, 64, -26, 45, 52, -19, 51, 36, -10, + 59, 18, 1, 67, 0, 13, 76, -17, 25, 85, -33, 37, + 41, 70, -26, 42, 66, -23, 46, 55, -17, 52, 39, -9, + 60, 21, 2, 68, 3, 14, 76, -14, 26, 85, -30, 38, + 42, 72, -23, 44, 68, -21, 48, 57, -15, 53, 42, -7, + 60, 24, 4, 68, 6, 15, 77, -11, 27, 86, -27, 38, + 44, 74, -21, 45, 69, -19, 49, 59, -13, 54, 45, -5, + 61, 27, 5, 69, 10, 16, 77, -7, 28, 86, -24, 39, + 46, 75, -18, 47, 71, -16, 50, 62, -11, 56, 48, -3, + 62, 31, 7, 70, 13, 18, 78, -4, 29, 87, -21, 40, + 47, 77, -15, 49, 73, -13, 52, 64, -9, 57, 50, -1, + 63, 34, 9, 71, 16, 19, 79, -1, 30, 88, -18, 41, + 49, 79, -13, 50, 75, -11, 53, 66, -6, 58, 53, 1, + 64, 36, 10, 72, 19, 20, 80, 2, 31, 88, -14, 42, + 50, 80, -10, 52, 77, -9, 55, 68, -4, 59, 56, 3, + 66, 39, 12, 73, 23, 22, 80, 6, 32, 89, -11, 43, + 52, 82, -8, 53, 79, -6, 56, 71, -2, 61, 58, 5, + 67, 43, 13, 74, 26, 23, 81, 9, 33, 89, -8, 44, + 54, 84, -5, 55, 81, -3, 58, 73, 1, 62, 61, 7, + 68, 46, 15, 75, 29, 24, 82, 12, 34, 90, -5, 45, + 55, 85, -3, 56, 82, -1, 59, 75, 3, 63, 63, 9, + 69, 48, 17, 75, 32, 26, 83, 15, 36, 91, -2, 46, + 16, 53, -72, 21, 39, -64, 29, 17, -50, 39, -4, -35, + 50, -23, -18, 60, -38, -3, 70, -52, 12, 80, -64, 26, + 16, 53, -71, 21, 40, -64, 29, 17, -50, 39, -4, -34, + 50, -23, -18, 60, -38, -3, 70, -52, 12, 80, -64, 26, + 17, 53, -71, 21, 40, -64, 29, 18, -50, 39, -3, -34, + 50, -22, -18, 60, -38, -3, 70, -51, 12, 80, -63, 26, + 17, 53, -70, 21, 40, -63, 30, 19, -50, 39, -3, -34, + 50, -22, -18, 60, -37, -2, 70, -51, 12, 80, -63, 26, + 18, 53, -69, 22, 41, -62, 30, 20, -49, 40, -2, -34, + 50, -21, -18, 60, -36, -2, 70, -50, 12, 80, -63, 26, + 18, 54, -68, 22, 42, -61, 30, 21, -48, 40, -1, -33, + 50, -20, -17, 60, -36, -2, 70, -49, 12, 80, -62, 26, + 19, 54, -67, 23, 42, -60, 31, 22, -48, 40, 1, -33, + 50, -18, -17, 60, -34, -2, 70, -48, 13, 81, -61, 27, + 20, 54, -65, 24, 43, -59, 31, 23, -47, 41, 3, -32, + 51, -17, -16, 61, -33, -2, 71, -47, 13, 81, -60, 27, + 21, 55, -63, 25, 45, -58, 32, 25, -46, 41, 4, -31, + 51, -15, -16, 61, -32, -1, 71, -46, 13, 81, -59, 27, + 22, 56, -62, 26, 46, -56, 33, 27, -45, 41, 6, -31, + 51, -13, -15, 61, -30, -1, 71, -44, 13, 81, -58, 27, + 23, 56, -60, 27, 47, -54, 33, 29, -43, 42, 8, -30, + 52, -11, -15, 61, -28, 0, 71, -43, 14, 81, -56, 27, + 25, 57, -58, 28, 48, -53, 34, 31, -42, 43, 11, -29, + 52, -9, -14, 62, -26, 0, 71, -41, 14, 81, -55, 28, + 26, 58, -55, 29, 50, -51, 35, 33, -41, 43, 13, -28, + 53, -6, -13, 62, -24, 1, 72, -39, 15, 82, -53, 28, + 27, 59, -53, 30, 51, -49, 36, 35, -39, 44, 16, -27, + 53, -4, -12, 63, -21, 2, 72, -37, 15, 82, -51, 29, + 29, 60, -51, 31, 53, -46, 37, 37, -37, 45, 18, -25, + 54, -1, -11, 63, -19, 2, 72, -35, 16, 82, -49, 29, + 30, 61, -48, 33, 55, -44, 38, 40, -36, 45, 21, -24, + 54, 1, -11, 63, -16, 3, 73, -32, 16, 83, -47, 29, + 32, 63, -45, 34, 56, -42, 39, 42, -34, 46, 24, -23, + 55, 4, -9, 64, -13, 4, 73, -29, 17, 83, -44, 30, + 33, 64, -43, 35, 58, -40, 40, 44, -32, 47, 27, -21, + 56, 7, -8, 65, -11, 5, 74, -27, 18, 83, -42, 31, + 35, 65, -41, 37, 60, -37, 42, 47, -30, 48, 29, -20, + 56, 10, -7, 65, -8, 6, 74, -24, 18, 84, -40, 31, + 36, 67, -38, 38, 61, -35, 43, 49, -28, 49, 32, -18, + 57, 13, -6, 66, -5, 7, 75, -21, 19, 84, -37, 32, + 38, 68, -35, 40, 63, -32, 44, 51, -26, 50, 35, -16, + 58, 16, -5, 67, -1, 8, 75, -18, 20, 85, -34, 32, + 40, 70, -33, 41, 65, -30, 45, 54, -24, 51, 38, -15, + 59, 19, -3, 67, 2, 9, 76, -15, 21, 85, -31, 33, + 41, 71, -30, 43, 67, -28, 47, 56, -22, 52, 40, -13, + 60, 22, -2, 68, 5, 10, 76, -12, 22, 85, -29, 34, + 43, 73, -28, 44, 69, -25, 48, 58, -20, 53, 43, -11, + 61, 25, 0, 69, 8, 11, 77, -9, 23, 86, -26, 35, + 44, 74, -25, 46, 70, -23, 49, 60, -17, 55, 46, -9, + 62, 28, 1, 69, 11, 12, 78, -6, 24, 86, -23, 35, + 46, 76, -22, 47, 72, -20, 51, 63, -15, 56, 49, -7, + 63, 32, 3, 70, 14, 13, 78, -3, 25, 87, -20, 36, + 48, 78, -20, 49, 74, -18, 52, 65, -13, 57, 51, -5, + 64, 35, 4, 71, 17, 15, 79, 0, 26, 88, -17, 37, + 49, 79, -17, 50, 76, -15, 53, 67, -11, 58, 54, -4, + 65, 37, 6, 72, 20, 16, 80, 3, 27, 88, -14, 38, + 51, 81, -15, 52, 78, -13, 55, 69, -9, 59, 56, -2, + 66, 40, 7, 73, 23, 17, 80, 6, 28, 89, -11, 39, + 52, 83, -12, 54, 80, -10, 56, 71, -6, 61, 59, 1, + 67, 44, 9, 74, 27, 19, 81, 10, 29, 90, -7, 40, + 54, 84, -9, 55, 81, -8, 58, 74, -4, 62, 62, 2, + 68, 46, 11, 75, 30, 20, 82, 13, 30, 90, -4, 41, + 55, 86, -7, 57, 83, -5, 59, 76, -2, 63, 64, 4, + 69, 49, 13, 76, 33, 22, 83, 16, 32, 91, -1, 42, + 17, 55, -75, 22, 42, -68, 30, 20, -54, 39, -1, -39, + 50, -20, -22, 60, -36, -7, 70, -50, 8, 80, -62, 22, + 18, 55, -74, 22, 42, -67, 30, 21, -54, 40, -1, -39, + 50, -20, -22, 60, -36, -7, 70, -50, 8, 80, -62, 22, + 18, 55, -74, 22, 43, -67, 30, 21, -54, 40, 0, -38, + 50, -19, -22, 60, -35, -7, 70, -49, 8, 80, -62, 22, + 18, 55, -73, 22, 43, -66, 30, 22, -53, 40, 1, -38, + 50, -19, -22, 60, -35, -7, 70, -49, 8, 80, -61, 22, + 19, 55, -72, 23, 44, -66, 31, 23, -53, 40, 1, -38, + 50, -18, -22, 60, -34, -6, 70, -48, 8, 81, -61, 22, + 20, 56, -71, 23, 44, -65, 31, 24, -52, 40, 2, -37, + 50, -17, -21, 61, -33, -6, 70, -47, 8, 81, -60, 22, + 20, 56, -70, 24, 45, -64, 31, 25, -52, 41, 4, -37, + 51, -16, -21, 61, -32, -6, 71, -46, 8, 81, -59, 23, + 21, 56, -68, 25, 46, -63, 32, 26, -51, 41, 5, -36, + 51, -14, -21, 61, -31, -6, 71, -45, 9, 81, -58, 23, + 22, 57, -67, 26, 47, -61, 33, 28, -50, 41, 7, -36, + 51, -13, -20, 61, -29, -5, 71, -44, 9, 81, -57, 23, + 23, 57, -65, 26, 48, -60, 33, 29, -49, 42, 9, -35, + 52, -11, -20, 61, -28, -5, 71, -43, 9, 81, -56, 23, + 24, 58, -63, 27, 49, -58, 34, 31, -47, 42, 11, -34, + 52, -9, -19, 62, -26, -4, 71, -41, 10, 81, -55, 24, + 25, 59, -61, 28, 50, -56, 35, 33, -46, 43, 13, -33, + 52, -7, -18, 62, -24, -4, 72, -39, 10, 82, -53, 24, + 27, 60, -59, 30, 52, -54, 36, 35, -45, 44, 16, -32, + 53, -4, -17, 62, -22, -3, 72, -37, 11, 82, -51, 24, + 28, 61, -57, 31, 53, -52, 37, 37, -43, 44, 18, -31, + 53, -2, -17, 63, -19, -3, 72, -35, 11, 82, -50, 25, + 30, 62, -54, 32, 55, -50, 38, 39, -41, 45, 20, -30, + 54, 1, -16, 63, -17, -2, 73, -33, 12, 82, -48, 25, + 31, 63, -52, 33, 56, -48, 39, 41, -40, 46, 23, -28, + 55, 3, -15, 64, -15, -1, 73, -31, 12, 83, -46, 26, + 32, 64, -49, 35, 58, -46, 40, 44, -38, 47, 26, -27, + 55, 6, -14, 64, -12, 0, 73, -28, 13, 83, -43, 26, + 34, 65, -47, 36, 59, -44, 41, 46, -36, 48, 28, -25, + 56, 9, -13, 65, -9, 1, 74, -25, 14, 83, -41, 27, + 35, 67, -45, 37, 61, -41, 42, 48, -34, 49, 31, -24, + 57, 12, -11, 65, -6, 1, 74, -23, 14, 84, -38, 27, + 37, 68, -42, 39, 63, -39, 43, 50, -32, 50, 34, -22, + 57, 15, -10, 66, -3, 2, 75, -20, 15, 84, -36, 28, + 39, 70, -39, 40, 64, -37, 44, 53, -30, 51, 37, -20, + 58, 18, -9, 67, 0, 3, 75, -17, 16, 85, -33, 29, + 40, 71, -37, 42, 66, -34, 46, 55, -28, 52, 39, -19, + 59, 21, -7, 67, 3, 5, 76, -14, 17, 85, -30, 29, + 42, 72, -34, 43, 68, -32, 47, 57, -26, 53, 42, -17, + 60, 24, -6, 68, 6, 6, 77, -11, 18, 86, -28, 30, + 43, 74, -32, 45, 70, -30, 48, 59, -24, 54, 44, -15, + 61, 27, -5, 69, 9, 7, 77, -8, 19, 86, -25, 31, + 45, 75, -29, 46, 71, -27, 50, 61, -22, 55, 47, -14, + 62, 30, -3, 70, 12, 8, 78, -5, 20, 87, -22, 32, + 46, 77, -27, 48, 73, -24, 51, 64, -19, 56, 50, -12, + 63, 33, -2, 70, 15, 9, 79, -2, 21, 87, -19, 32, + 48, 79, -24, 49, 75, -22, 52, 66, -17, 57, 52, -10, + 64, 36, 0, 71, 18, 11, 79, 1, 22, 88, -16, 33, + 49, 80, -22, 51, 77, -20, 54, 68, -15, 58, 55, -8, + 65, 38, 2, 72, 21, 12, 80, 4, 23, 88, -13, 34, + 51, 82, -19, 52, 78, -17, 55, 70, -13, 60, 57, -6, + 66, 41, 3, 73, 24, 13, 81, 7, 24, 89, -10, 35, + 53, 84, -16, 54, 80, -15, 57, 72, -10, 61, 60, -4, + 67, 44, 5, 74, 28, 15, 81, 11, 25, 90, -6, 36, + 54, 85, -14, 55, 82, -12, 58, 74, -8, 62, 63, -2, + 68, 47, 7, 75, 31, 16, 82, 14, 26, 90, -3, 37, + 56, 87, -11, 57, 84, -10, 59, 76, -6, 64, 65, 0, + 69, 50, 8, 76, 34, 18, 83, 17, 28, 91, 0, 38, + 19, 57, -78, 23, 45, -71, 31, 24, -58, 40, 3, -43, + 50, -17, -27, 60, -33, -12, 70, -47, 3, 81, -60, 18, + 19, 57, -77, 23, 45, -71, 31, 25, -58, 40, 3, -43, + 50, -17, -27, 60, -33, -12, 70, -47, 3, 81, -60, 18, + 19, 57, -77, 23, 46, -71, 31, 25, -58, 40, 3, -43, + 50, -16, -27, 60, -33, -11, 70, -47, 3, 81, -60, 18, + 20, 57, -76, 24, 46, -70, 31, 25, -58, 40, 4, -43, + 51, -16, -27, 61, -32, -11, 71, -46, 3, 81, -59, 18, + 20, 58, -76, 24, 46, -69, 31, 26, -57, 41, 5, -42, + 51, -15, -26, 61, -31, -11, 71, -46, 3, 81, -59, 18, + 21, 58, -75, 24, 47, -69, 32, 27, -57, 41, 6, -42, + 51, -14, -26, 61, -31, -11, 71, -45, 4, 81, -58, 18, + 21, 58, -73, 25, 48, -68, 32, 28, -56, 41, 7, -41, + 51, -13, -26, 61, -30, -11, 71, -44, 4, 81, -58, 18, + 22, 59, -72, 26, 49, -66, 33, 29, -55, 41, 9, -41, + 51, -11, -25, 61, -28, -10, 71, -43, 4, 81, -57, 18, + 23, 59, -70, 26, 49, -65, 33, 31, -54, 42, 10, -40, + 52, -10, -25, 61, -27, -10, 71, -42, 4, 81, -55, 19, + 24, 60, -69, 27, 50, -64, 34, 32, -53, 42, 12, -39, + 52, -8, -24, 62, -25, -10, 71, -40, 5, 81, -54, 19, + 25, 60, -67, 28, 51, -62, 35, 34, -52, 43, 14, -39, + 52, -6, -24, 62, -24, -9, 72, -39, 5, 82, -53, 19, + 26, 61, -65, 29, 53, -61, 35, 36, -51, 43, 16, -38, + 53, -4, -23, 62, -22, -9, 72, -37, 5, 82, -51, 19, + 28, 62, -63, 30, 54, -59, 36, 38, -49, 44, 18, -36, + 53, -2, -22, 63, -19, -8, 72, -35, 6, 82, -50, 20, + 29, 63, -61, 32, 55, -57, 37, 40, -48, 45, 20, -35, + 54, 1, -21, 63, -17, -7, 73, -33, 6, 82, -48, 20, + 30, 64, -59, 33, 57, -55, 38, 41, -46, 46, 23, -34, + 54, 3, -20, 64, -15, -7, 73, -31, 7, 83, -46, 21, + 32, 65, -56, 34, 58, -53, 39, 43, -44, 46, 25, -33, + 55, 5, -19, 64, -12, -6, 73, -29, 8, 83, -44, 21, + 33, 66, -54, 35, 60, -50, 40, 46, -42, 47, 28, -31, + 56, 8, -18, 65, -10, -5, 74, -26, 8, 83, -41, 22, + 35, 67, -51, 37, 61, -48, 41, 48, -41, 48, 30, -30, + 56, 11, -17, 65, -7, -4, 74, -24, 9, 84, -39, 22, + 36, 68, -49, 38, 63, -46, 42, 50, -39, 49, 33, -29, + 57, 14, -16, 66, -4, -3, 75, -21, 10, 84, -37, 23, + 37, 69, -47, 39, 64, -44, 44, 52, -37, 50, 35, -27, + 58, 17, -15, 66, -2, -2, 75, -18, 10, 84, -34, 23, + 39, 71, -44, 41, 66, -41, 45, 54, -35, 51, 38, -25, + 59, 20, -13, 67, 2, -1, 76, -15, 11, 85, -32, 24, + 41, 72, -41, 42, 67, -39, 46, 56, -33, 52, 41, -24, + 59, 22, -12, 68, 5, 0, 76, -13, 12, 85, -29, 25, + 42, 74, -39, 44, 69, -37, 47, 58, -31, 53, 43, -22, + 60, 25, -11, 68, 7, 1, 77, -10, 13, 86, -26, 26, + 44, 75, -37, 45, 71, -34, 49, 60, -29, 54, 46, -20, + 61, 28, -9, 69, 10, 2, 77, -7, 14, 86, -23, 26, + 45, 77, -34, 46, 72, -32, 50, 63, -26, 55, 48, -18, + 62, 31, -8, 70, 13, 3, 78, -4, 15, 87, -21, 27, + 47, 78, -31, 48, 74, -29, 51, 65, -24, 56, 51, -16, + 63, 34, -6, 71, 17, 5, 79, 0, 16, 87, -17, 28, + 48, 80, -29, 50, 76, -27, 53, 67, -22, 58, 54, -14, + 64, 37, -5, 71, 20, 6, 79, 3, 17, 88, -14, 29, + 50, 81, -26, 51, 78, -24, 54, 69, -20, 59, 56, -13, + 65, 40, -3, 72, 23, 7, 80, 6, 18, 89, -11, 30, + 51, 83, -24, 52, 79, -22, 55, 71, -18, 60, 58, -11, + 66, 42, -2, 73, 26, 9, 81, 9, 19, 89, -8, 31, + 53, 84, -21, 54, 81, -19, 57, 73, -15, 61, 61, -9, + 67, 46, 0, 74, 29, 10, 82, 12, 21, 90, -5, 32, + 55, 86, -19, 56, 83, -17, 58, 75, -13, 63, 64, -7, + 68, 48, 2, 75, 32, 12, 82, 15, 22, 91, -2, 33, + 56, 88, -16, 57, 85, -15, 60, 77, -11, 64, 66, -5, + 69, 51, 4, 76, 35, 13, 83, 18, 23, 91, 1, 34, + 20, 59, -81, 24, 48, -74, 31, 27, -62, 41, 6, -47, + 51, -14, -31, 61, -31, -16, 71, -45, -1, 81, -58, 14, + 20, 59, -80, 24, 48, -74, 31, 28, -62, 41, 6, -47, + 51, -14, -31, 61, -30, -16, 71, -45, -1, 81, -58, 14, + 21, 59, -80, 24, 48, -74, 32, 28, -62, 41, 7, -47, + 51, -13, -31, 61, -30, -16, 71, -45, -1, 81, -58, 14, + 21, 59, -79, 25, 49, -73, 32, 29, -61, 41, 7, -47, + 51, -13, -31, 61, -30, -15, 71, -44, -1, 81, -58, 14, + 21, 60, -79, 25, 49, -73, 32, 29, -61, 41, 8, -46, + 51, -12, -30, 61, -29, -15, 71, -44, -1, 81, -57, 14, + 22, 60, -78, 25, 50, -72, 32, 30, -60, 41, 9, -46, + 51, -11, -30, 61, -28, -15, 71, -43, 0, 81, -56, 14, + 23, 60, -77, 26, 50, -71, 33, 31, -60, 42, 10, -45, + 51, -10, -30, 61, -27, -15, 71, -42, 0, 81, -56, 14, + 23, 60, -75, 27, 51, -70, 33, 32, -59, 42, 12, -45, + 52, -9, -29, 61, -26, -14, 71, -41, 0, 81, -55, 14, + 24, 61, -74, 27, 52, -69, 34, 34, -58, 42, 13, -44, + 52, -7, -29, 62, -25, -14, 71, -40, 0, 81, -54, 15, + 25, 61, -72, 28, 53, -67, 35, 35, -57, 43, 15, -43, + 52, -6, -28, 62, -23, -14, 72, -38, 1, 82, -53, 15, + 26, 62, -70, 29, 54, -66, 35, 36, -56, 43, 16, -43, + 53, -4, -28, 62, -21, -13, 72, -37, 1, 82, -51, 15, + 27, 63, -69, 30, 55, -64, 36, 38, -54, 44, 18, -42, + 53, -2, -27, 63, -20, -13, 72, -35, 1, 82, -50, 15, + 29, 63, -66, 31, 56, -62, 37, 40, -53, 45, 21, -40, + 54, 1, -26, 63, -17, -12, 72, -33, 2, 82, -48, 16, + 30, 64, -64, 32, 57, -60, 38, 42, -51, 45, 23, -39, + 54, 3, -25, 63, -15, -11, 73, -31, 2, 82, -46, 16, + 31, 65, -62, 33, 58, -58, 39, 43, -50, 46, 25, -38, + 55, 5, -25, 64, -13, -11, 73, -29, 3, 83, -44, 17, + 32, 66, -60, 35, 60, -56, 40, 45, -48, 47, 27, -37, + 55, 7, -24, 64, -11, -10, 73, -27, 4, 83, -42, 17, + 34, 67, -58, 36, 61, -54, 41, 48, -46, 48, 30, -35, + 56, 10, -22, 65, -8, -9, 74, -24, 4, 83, -40, 18, + 35, 68, -55, 37, 63, -52, 42, 49, -45, 48, 32, -34, + 57, 13, -21, 65, -5, -8, 74, -22, 5, 84, -38, 18, + 37, 70, -53, 38, 64, -50, 43, 51, -43, 49, 35, -33, + 57, 16, -20, 66, -3, -7, 75, -20, 6, 84, -35, 19, + 38, 71, -51, 40, 65, -48, 44, 53, -41, 50, 37, -31, + 58, 18, -19, 66, 0, -6, 75, -17, 6, 84, -33, 19, + 40, 72, -48, 41, 67, -45, 45, 56, -39, 51, 40, -29, + 59, 21, -18, 67, 3, -5, 76, -14, 7, 85, -30, 20, + 41, 73, -45, 43, 69, -43, 47, 58, -37, 52, 42, -28, + 60, 24, -16, 68, 6, -4, 76, -11, 8, 85, -28, 21, + 43, 75, -43, 44, 70, -41, 48, 60, -35, 53, 45, -26, + 61, 27, -15, 69, 9, -3, 77, -8, 9, 86, -25, 22, + 44, 76, -41, 45, 72, -38, 49, 62, -33, 54, 47, -24, + 61, 29, -14, 69, 12, -2, 78, -5, 10, 86, -22, 22, + 45, 78, -38, 47, 73, -36, 50, 64, -31, 56, 50, -23, + 62, 32, -12, 70, 15, -1, 78, -3, 11, 87, -19, 23, + 47, 79, -35, 48, 75, -33, 52, 66, -28, 57, 52, -21, + 63, 35, -10, 71, 18, 1, 79, 1, 12, 88, -16, 24, + 49, 81, -33, 50, 77, -31, 53, 68, -26, 58, 55, -19, + 64, 38, -9, 72, 21, 2, 80, 4, 13, 88, -13, 25, + 50, 82, -31, 51, 79, -29, 54, 70, -24, 59, 57, -17, + 65, 41, -7, 72, 24, 3, 80, 7, 14, 89, -10, 26, + 52, 84, -28, 53, 80, -26, 56, 72, -22, 60, 59, -15, + 66, 44, -6, 73, 27, 4, 81, 10, 15, 89, -7, 27, + 53, 85, -25, 54, 82, -24, 57, 74, -19, 62, 62, -13, + 68, 47, -4, 74, 30, 6, 82, 13, 17, 90, -4, 28, + 55, 87, -23, 56, 84, -21, 59, 76, -17, 63, 64, -11, + 69, 49, -2, 75, 33, 7, 83, 16, 18, 91, -1, 29, + 56, 88, -20, 57, 85, -19, 60, 78, -15, 64, 67, -9, + 70, 52, -1, 76, 36, 9, 83, 19, 19, 91, 2, 30, + 21, 61, -83, 25, 51, -78, 32, 31, -66, 41, 9, -51, + 51, -11, -35, 61, -28, -20, 71, -43, -5, 81, -57, 10, + 22, 61, -83, 25, 51, -77, 32, 31, -65, 41, 10, -51, + 51, -11, -35, 61, -28, -20, 71, -43, -5, 81, -56, 10, + 22, 61, -83, 25, 51, -77, 32, 31, -65, 41, 10, -51, + 51, -10, -35, 61, -28, -20, 71, -42, -5, 81, -56, 10, + 22, 61, -82, 25, 51, -76, 33, 32, -65, 41, 10, -50, + 51, -10, -35, 61, -27, -20, 71, -42, -5, 81, -56, 10, + 23, 62, -81, 26, 52, -76, 33, 32, -64, 42, 11, -50, + 51, -9, -35, 61, -26, -19, 71, -41, -5, 81, -55, 10, + 23, 62, -81, 26, 52, -75, 33, 33, -64, 42, 12, -50, + 52, -8, -34, 61, -26, -19, 71, -41, -4, 81, -55, 10, + 24, 62, -80, 27, 53, -74, 33, 34, -63, 42, 13, -49, + 52, -7, -34, 62, -25, -19, 71, -40, -4, 81, -54, 10, + 24, 62, -78, 27, 53, -73, 34, 35, -62, 42, 14, -49, + 52, -6, -33, 62, -23, -19, 71, -39, -4, 81, -53, 10, + 25, 63, -77, 28, 54, -72, 35, 36, -61, 43, 16, -48, + 52, -4, -33, 62, -22, -18, 72, -38, -4, 82, -52, 11, + 26, 63, -75, 29, 55, -71, 35, 38, -60, 43, 17, -47, + 53, -3, -32, 62, -21, -18, 72, -36, -3, 82, -51, 11, + 27, 64, -74, 30, 56, -69, 36, 39, -59, 44, 19, -46, + 53, -1, -32, 62, -19, -17, 72, -35, -3, 82, -49, 11, + 28, 64, -72, 31, 57, -68, 37, 40, -58, 44, 21, -46, + 53, 1, -31, 63, -17, -17, 72, -33, -3, 82, -48, 12, + 29, 65, -70, 32, 58, -66, 37, 42, -57, 45, 23, -44, + 54, 3, -30, 63, -15, -16, 73, -31, -2, 82, -46, 12, + 31, 66, -68, 33, 59, -64, 38, 44, -55, 46, 25, -43, + 54, 5, -29, 64, -13, -16, 73, -29, -2, 83, -45, 12, + 32, 67, -66, 34, 60, -62, 39, 46, -54, 46, 27, -42, + 55, 7, -29, 64, -11, -15, 73, -27, -1, 83, -43, 13, + 33, 68, -64, 35, 61, -60, 40, 47, -52, 47, 29, -41, + 56, 10, -28, 64, -9, -14, 74, -25, -1, 83, -41, 13, + 34, 69, -61, 37, 63, -58, 41, 49, -50, 48, 32, -40, + 56, 12, -27, 65, -6, -13, 74, -23, 0, 84, -38, 14, + 36, 70, -59, 38, 64, -56, 42, 51, -49, 49, 34, -38, + 57, 15, -25, 66, -3, -12, 75, -20, 1, 84, -36, 14, + 37, 71, -57, 39, 65, -54, 43, 53, -47, 50, 36, -37, + 58, 17, -24, 66, -1, -11, 75, -18, 2, 84, -34, 15, + 39, 72, -54, 40, 67, -52, 44, 55, -45, 51, 39, -35, + 58, 20, -23, 67, 2, -11, 75, -15, 2, 85, -32, 16, + 40, 73, -52, 42, 69, -49, 46, 57, -43, 52, 41, -33, + 59, 23, -22, 67, 5, -9, 76, -12, 3, 85, -29, 16, + 42, 75, -49, 43, 70, -47, 47, 59, -41, 53, 44, -32, + 60, 26, -20, 68, 8, -8, 77, -10, 4, 86, -26, 17, + 43, 76, -47, 45, 72, -45, 48, 61, -39, 54, 46, -30, + 61, 28, -19, 69, 10, -7, 77, -7, 5, 86, -24, 18, + 44, 77, -45, 46, 73, -42, 49, 63, -37, 55, 49, -28, + 62, 31, -18, 69, 13, -6, 78, -4, 6, 87, -21, 18, + 46, 79, -42, 47, 75, -40, 51, 65, -35, 56, 51, -27, + 63, 34, -16, 70, 16, -5, 78, -1, 7, 87, -18, 19, + 48, 80, -39, 49, 76, -37, 52, 67, -32, 57, 54, -25, + 64, 37, -15, 71, 19, -4, 79, 2, 8, 88, -15, 20, + 49, 82, -37, 50, 78, -35, 53, 69, -30, 58, 56, -23, + 65, 39, -13, 72, 22, -2, 80, 5, 9, 88, -12, 21, + 51, 83, -35, 52, 80, -33, 55, 71, -28, 59, 58, -21, + 66, 42, -11, 73, 25, -1, 80, 8, 10, 89, -9, 22, + 52, 85, -32, 53, 81, -30, 56, 73, -26, 61, 61, -19, + 67, 45, -10, 74, 28, 0, 81, 11, 11, 89, -6, 23, + 54, 86, -29, 55, 83, -28, 58, 75, -24, 62, 63, -17, + 68, 48, -8, 75, 31, 2, 82, 14, 13, 90, -3, 24, + 55, 88, -27, 56, 85, -25, 59, 77, -21, 63, 65, -15, + 69, 50, -6, 75, 34, 3, 83, 17, 14, 91, 0, 25, + 57, 89, -25, 58, 86, -23, 60, 79, -19, 64, 68, -13, + 70, 53, -5, 76, 37, 5, 84, 20, 15, 91, 3, 26, + 23, 63, -86, 26, 53, -81, 33, 34, -69, 42, 12, -55, + 51, -8, -39, 61, -25, -24, 71, -41, -9, 81, -54, 6, + 23, 63, -86, 26, 53, -80, 33, 34, -69, 42, 13, -55, + 51, -8, -39, 61, -25, -24, 71, -40, -9, 81, -54, 6, + 23, 63, -85, 26, 53, -80, 33, 34, -69, 42, 13, -55, + 52, -7, -39, 61, -25, -24, 71, -40, -9, 81, -54, 6, + 23, 63, -85, 26, 54, -80, 33, 35, -68, 42, 14, -54, + 52, -7, -39, 61, -24, -24, 71, -40, -9, 81, -54, 6, + 24, 64, -84, 27, 54, -79, 34, 35, -68, 42, 14, -54, + 52, -6, -38, 62, -24, -23, 71, -39, -9, 81, -53, 6, + 24, 64, -83, 27, 54, -78, 34, 36, -67, 42, 15, -54, + 52, -5, -38, 62, -23, -23, 71, -38, -8, 81, -53, 6, + 25, 64, -82, 28, 55, -77, 34, 37, -67, 43, 16, -53, + 52, -4, -38, 62, -22, -23, 71, -38, -8, 81, -52, 6, + 25, 64, -81, 28, 56, -76, 35, 38, -66, 43, 17, -53, + 52, -3, -37, 62, -21, -23, 72, -37, -8, 82, -51, 6, + 26, 65, -80, 29, 56, -75, 35, 39, -65, 43, 19, -52, + 53, -2, -37, 62, -20, -22, 72, -35, -8, 82, -50, 7, + 27, 65, -78, 30, 57, -74, 36, 40, -64, 44, 20, -51, + 53, 0, -36, 62, -18, -22, 72, -34, -7, 82, -49, 7, + 28, 66, -77, 31, 58, -73, 36, 41, -63, 44, 22, -50, + 53, 1, -36, 63, -17, -21, 72, -33, -7, 82, -48, 7, + 29, 66, -75, 32, 59, -71, 37, 43, -62, 45, 23, -49, + 54, 3, -35, 63, -15, -21, 73, -31, -7, 82, -46, 8, + 30, 67, -73, 33, 60, -69, 38, 44, -60, 45, 25, -48, + 54, 5, -34, 63, -13, -20, 73, -29, -6, 83, -44, 8, + 31, 68, -71, 34, 61, -68, 39, 46, -59, 46, 27, -47, + 55, 7, -34, 64, -11, -20, 73, -27, -6, 83, -43, 8, + 33, 68, -69, 35, 62, -66, 40, 48, -57, 47, 29, -46, + 55, 9, -33, 64, -9, -19, 73, -25, -5, 83, -41, 9, + 34, 69, -67, 36, 63, -64, 41, 49, -56, 48, 31, -45, + 56, 12, -32, 65, -7, -18, 74, -23, -5, 83, -39, 9, + 35, 70, -65, 37, 64, -62, 42, 51, -54, 48, 34, -43, + 57, 14, -31, 65, -4, -17, 74, -21, -4, 84, -37, 10, + 36, 71, -63, 38, 66, -60, 43, 53, -52, 49, 36, -42, + 57, 17, -30, 66, -2, -16, 75, -19, -3, 84, -35, 10, + 38, 72, -60, 40, 67, -58, 44, 55, -51, 50, 38, -41, + 58, 19, -28, 66, 1, -16, 75, -16, -2, 84, -32, 11, + 39, 73, -58, 41, 68, -55, 45, 57, -49, 51, 40, -39, + 59, 22, -27, 67, 4, -15, 76, -14, -2, 85, -30, 12, + 41, 75, -56, 42, 70, -53, 46, 59, -47, 52, 43, -37, + 60, 25, -26, 68, 7, -13, 76, -11, -1, 85, -27, 12, + 42, 76, -53, 44, 71, -51, 47, 61, -45, 53, 45, -36, + 60, 27, -25, 68, 9, -12, 77, -8, 0, 86, -25, 13, + 44, 77, -51, 45, 73, -49, 49, 62, -43, 54, 48, -34, + 61, 30, -23, 69, 12, -11, 77, -5, 1, 86, -22, 14, + 45, 78, -49, 46, 74, -46, 50, 64, -41, 55, 50, -32, + 62, 32, -22, 70, 15, -10, 78, -3, 2, 87, -20, 15, + 46, 80, -46, 48, 76, -44, 51, 66, -39, 56, 52, -31, + 63, 35, -20, 70, 17, -9, 79, 0, 3, 87, -17, 15, + 48, 81, -43, 49, 77, -41, 52, 68, -36, 57, 55, -29, + 64, 38, -19, 71, 21, -8, 79, 3, 4, 88, -14, 16, + 49, 83, -41, 51, 79, -39, 54, 70, -34, 59, 57, -27, + 65, 41, -17, 72, 23, -6, 80, 6, 5, 88, -11, 17, + 51, 84, -39, 52, 81, -37, 55, 72, -32, 60, 59, -25, + 66, 43, -16, 73, 26, -5, 81, 9, 6, 89, -8, 18, + 52, 85, -36, 54, 82, -35, 56, 74, -30, 61, 62, -23, + 67, 46, -14, 74, 29, -4, 81, 12, 7, 90, -5, 19, + 54, 87, -34, 55, 84, -32, 58, 76, -28, 62, 64, -21, + 68, 49, -12, 75, 32, -2, 82, 15, 9, 90, -2, 20, + 56, 89, -31, 57, 86, -30, 59, 78, -25, 63, 66, -19, + 69, 51, -11, 76, 35, -1, 83, 18, 10, 91, 1, 21, + 57, 90, -29, 58, 87, -27, 61, 80, -23, 65, 69, -17, + 70, 54, -9, 77, 38, 1, 84, 21, 11, 92, 4, 22, + 24, 65, -89, 27, 56, -84, 34, 37, -73, 42, 16, -59, + 52, -5, -43, 62, -23, -28, 71, -38, -13, 81, -52, 2, + 24, 65, -89, 27, 56, -83, 34, 37, -72, 42, 16, -58, + 52, -5, -43, 62, -22, -28, 71, -38, -13, 81, -52, 2, + 24, 65, -88, 27, 56, -83, 34, 37, -72, 42, 16, -58, + 52, -4, -43, 62, -22, -28, 71, -38, -13, 81, -52, 2, + 24, 65, -88, 27, 56, -83, 34, 38, -72, 42, 17, -58, + 52, -4, -43, 62, -22, -28, 71, -37, -13, 81, -52, 2, + 25, 66, -87, 28, 56, -82, 34, 38, -71, 43, 17, -58, + 52, -3, -42, 62, -21, -27, 72, -37, -13, 81, -51, 2, + 25, 66, -86, 28, 57, -81, 35, 39, -71, 43, 18, -57, + 52, -2, -42, 62, -20, -27, 72, -36, -12, 82, -51, 2, + 26, 66, -85, 29, 57, -81, 35, 40, -70, 43, 19, -57, + 53, -2, -42, 62, -19, -27, 72, -35, -12, 82, -50, 2, + 27, 66, -84, 29, 58, -80, 35, 41, -69, 43, 20, -56, + 53, 0, -41, 62, -18, -27, 72, -34, -12, 82, -49, 3, + 27, 67, -83, 30, 58, -78, 36, 42, -69, 44, 21, -56, + 53, 1, -41, 63, -17, -26, 72, -33, -12, 82, -48, 3, + 28, 67, -82, 31, 59, -77, 36, 43, -68, 44, 23, -55, + 53, 2, -40, 63, -16, -26, 72, -32, -11, 82, -47, 3, + 29, 67, -80, 31, 60, -76, 37, 44, -67, 45, 24, -54, + 54, 4, -40, 63, -14, -25, 73, -31, -11, 82, -46, 3, + 30, 68, -78, 32, 61, -74, 38, 45, -65, 45, 26, -53, + 54, 6, -39, 63, -13, -25, 73, -29, -11, 82, -44, 4, + 31, 69, -76, 33, 62, -73, 39, 47, -64, 46, 28, -52, + 55, 8, -38, 64, -11, -24, 73, -27, -10, 83, -43, 4, + 32, 69, -75, 34, 63, -71, 39, 48, -63, 47, 30, -51, + 55, 10, -37, 64, -9, -24, 73, -25, -10, 83, -41, 4, + 33, 70, -73, 35, 64, -69, 40, 50, -61, 47, 32, -50, + 56, 12, -37, 65, -7, -23, 74, -23, -9, 83, -39, 5, + 34, 71, -71, 37, 65, -67, 41, 51, -60, 48, 34, -49, + 56, 14, -36, 65, -4, -22, 74, -21, -9, 84, -37, 5, + 36, 72, -68, 38, 66, -65, 42, 53, -58, 49, 36, -47, + 57, 16, -35, 66, -2, -21, 75, -19, -8, 84, -35, 6, + 37, 73, -66, 39, 67, -63, 43, 55, -56, 50, 38, -46, + 58, 19, -34, 66, 0, -20, 75, -17, -7, 84, -33, 6, + 38, 74, -64, 40, 69, -61, 44, 57, -54, 51, 40, -45, + 58, 21, -32, 67, 3, -20, 75, -14, -6, 85, -31, 7, + 40, 75, -62, 41, 70, -59, 45, 58, -53, 51, 42, -43, + 59, 24, -31, 67, 5, -19, 76, -12, -6, 85, -28, 8, + 41, 76, -59, 43, 71, -57, 47, 60, -51, 52, 45, -41, + 60, 26, -30, 68, 8, -18, 76, -9, -5, 85, -26, 8, + 43, 77, -57, 44, 73, -55, 48, 62, -49, 53, 47, -40, + 61, 29, -29, 69, 11, -16, 77, -7, -4, 86, -23, 9, + 44, 78, -55, 45, 74, -52, 49, 64, -47, 54, 49, -38, + 61, 31, -27, 69, 14, -15, 78, -4, -3, 86, -21, 10, + 45, 80, -52, 47, 76, -50, 50, 66, -45, 55, 51, -36, + 62, 34, -26, 70, 16, -14, 78, -1, -2, 87, -18, 11, + 47, 81, -50, 48, 77, -48, 51, 68, -43, 57, 54, -35, + 63, 37, -24, 71, 19, -13, 79, 2, -1, 87, -15, 11, + 48, 82, -47, 50, 79, -45, 53, 70, -40, 58, 56, -33, + 64, 39, -23, 72, 22, -12, 79, 5, 0, 88, -12, 12, + 50, 84, -45, 51, 80, -43, 54, 71, -38, 59, 58, -31, + 65, 42, -21, 72, 25, -10, 80, 8, 1, 89, -10, 13, + 51, 85, -43, 53, 82, -41, 55, 73, -36, 60, 61, -29, + 66, 45, -20, 73, 28, -9, 81, 10, 2, 89, -7, 14, + 53, 86, -40, 54, 83, -39, 57, 75, -34, 61, 63, -27, + 67, 47, -18, 74, 30, -8, 82, 13, 3, 90, -4, 15, + 54, 88, -38, 55, 85, -36, 58, 77, -32, 62, 65, -25, + 68, 50, -16, 75, 33, -6, 82, 16, 5, 90, -1, 16, + 56, 89, -35, 57, 86, -34, 60, 79, -30, 64, 68, -23, + 69, 53, -15, 76, 36, -5, 83, 19, 6, 91, 2, 17, + 57, 91, -33, 58, 88, -31, 61, 81, -27, 65, 70, -21, + 70, 55, -13, 77, 39, -3, 84, 22, 7, 92, 5, 18, + 25, 67, -92, 28, 58, -87, 34, 40, -76, 43, 19, -63, + 52, -1, -47, 62, -20, -32, 72, -35, -17, 82, -50, -3, + 25, 67, -92, 28, 59, -87, 35, 40, -76, 43, 20, -63, + 52, -1, -47, 62, -19, -32, 72, -35, -17, 82, -50, -3, + 25, 68, -91, 28, 59, -86, 35, 41, -76, 43, 20, -62, + 52, -1, -47, 62, -19, -32, 72, -35, -17, 82, -50, -3, + 26, 68, -91, 29, 59, -86, 35, 41, -76, 43, 20, -62, + 53, 0, -47, 62, -19, -32, 72, -35, -17, 82, -49, -3, + 26, 68, -90, 29, 59, -85, 35, 42, -75, 43, 21, -62, + 53, 0, -47, 62, -18, -32, 72, -34, -17, 82, -49, -2, + 27, 68, -89, 29, 59, -85, 35, 42, -75, 43, 22, -62, + 53, 1, -47, 62, -17, -32, 72, -33, -17, 82, -48, -2, + 27, 68, -89, 30, 60, -84, 36, 43, -74, 44, 22, -61, + 53, 2, -46, 62, -16, -31, 72, -33, -17, 82, -48, -2, + 28, 68, -87, 30, 60, -83, 36, 44, -73, 44, 24, -61, + 53, 3, -46, 63, -15, -31, 72, -32, -17, 82, -47, -2, + 28, 69, -86, 31, 61, -82, 37, 45, -72, 44, 25, -60, + 54, 4, -45, 63, -14, -31, 72, -31, -16, 82, -46, -2, + 29, 69, -85, 32, 62, -81, 37, 46, -72, 45, 26, -59, + 54, 5, -45, 63, -13, -30, 73, -29, -16, 82, -45, -1, + 30, 69, -84, 32, 62, -80, 38, 47, -71, 45, 27, -58, + 54, 7, -44, 63, -11, -30, 73, -28, -16, 82, -43, -1, + 31, 70, -82, 33, 63, -78, 39, 48, -69, 46, 29, -58, + 55, 9, -44, 64, -10, -29, 73, -27, -15, 83, -42, -1, + 32, 71, -80, 34, 64, -76, 39, 49, -68, 47, 31, -56, + 55, 11, -43, 64, -8, -29, 73, -25, -15, 83, -40, 0, + 33, 71, -78, 35, 65, -75, 40, 51, -67, 47, 32, -55, + 56, 12, -42, 65, -6, -28, 74, -23, -14, 83, -39, 0, + 34, 72, -77, 36, 66, -73, 41, 52, -65, 48, 34, -54, + 56, 14, -41, 65, -4, -27, 74, -21, -14, 83, -37, 0, + 35, 73, -75, 37, 67, -71, 42, 54, -64, 49, 36, -53, + 57, 16, -40, 65, -2, -27, 74, -19, -13, 84, -35, 1, + 37, 74, -72, 39, 68, -69, 43, 55, -62, 49, 38, -52, + 57, 19, -39, 66, 0, -26, 75, -17, -12, 84, -33, 1, + 38, 74, -70, 40, 69, -67, 44, 57, -60, 50, 40, -50, + 58, 21, -38, 66, 3, -25, 75, -15, -12, 84, -31, 2, + 39, 75, -68, 41, 70, -65, 45, 59, -59, 51, 42, -49, + 59, 23, -37, 67, 5, -24, 76, -12, -11, 85, -29, 3, + 40, 76, -66, 42, 72, -63, 46, 60, -57, 52, 44, -48, + 59, 26, -36, 68, 7, -23, 76, -10, -10, 85, -27, 3, + 42, 78, -64, 43, 73, -61, 47, 62, -55, 53, 47, -46, + 60, 28, -34, 68, 10, -22, 77, -7, -9, 86, -24, 4, + 43, 79, -61, 45, 74, -59, 48, 64, -53, 54, 49, -44, + 61, 31, -33, 69, 13, -21, 77, -5, -8, 86, -22, 5, + 45, 80, -59, 46, 76, -57, 50, 66, -51, 55, 51, -43, + 62, 33, -32, 70, 15, -20, 78, -2, -8, 87, -19, 5, + 46, 81, -57, 47, 77, -55, 51, 67, -49, 56, 53, -41, + 63, 36, -30, 70, 18, -19, 78, 1, -7, 87, -16, 6, + 47, 82, -54, 49, 78, -52, 52, 69, -47, 57, 55, -39, + 64, 38, -29, 71, 21, -18, 79, 3, -6, 88, -14, 7, + 49, 84, -52, 50, 80, -50, 53, 71, -45, 58, 58, -37, + 65, 41, -27, 72, 24, -16, 80, 6, -4, 88, -11, 8, + 50, 85, -49, 52, 81, -48, 55, 73, -43, 59, 60, -35, + 66, 44, -26, 73, 26, -15, 80, 9, -3, 89, -8, 9, + 52, 86, -47, 53, 83, -45, 56, 75, -41, 60, 62, -34, + 66, 46, -24, 73, 29, -14, 81, 12, -2, 89, -5, 10, + 53, 88, -45, 54, 84, -43, 57, 76, -39, 62, 64, -32, + 67, 49, -23, 74, 32, -12, 82, 15, -1, 90, -3, 11, + 55, 89, -42, 56, 86, -40, 59, 78, -36, 63, 67, -30, + 69, 51, -21, 75, 35, -11, 83, 18, 0, 91, 1, 12, + 56, 91, -40, 57, 88, -38, 60, 80, -34, 64, 69, -28, + 70, 54, -19, 76, 38, -9, 83, 21, 1, 91, 3, 13, + 58, 92, -37, 59, 89, -36, 61, 82, -32, 65, 71, -26, + 71, 56, -17, 77, 40, -8, 84, 24, 2, 92, 6, 14, + 26, 69, -94, 29, 61, -90, 35, 43, -80, 43, 23, -66, + 53, 2, -51, 62, -17, -36, 72, -33, -21, 82, -48, -7, + 26, 69, -94, 29, 61, -90, 35, 43, -79, 43, 23, -66, + 53, 2, -51, 62, -16, -36, 72, -33, -21, 82, -48, -7, + 27, 69, -94, 29, 61, -89, 35, 44, -79, 44, 23, -66, + 53, 2, -51, 62, -16, -36, 72, -32, -21, 82, -47, -7, + 27, 70, -93, 30, 61, -89, 36, 44, -79, 44, 23, -66, + 53, 3, -51, 62, -16, -36, 72, -32, -21, 82, -47, -6, + 27, 70, -93, 30, 61, -88, 36, 44, -79, 44, 24, -66, + 53, 3, -51, 63, -15, -36, 72, -32, -21, 82, -47, -6, + 28, 70, -92, 30, 62, -88, 36, 45, -78, 44, 25, -65, + 53, 4, -50, 63, -15, -36, 72, -31, -21, 82, -46, -6, + 28, 70, -91, 31, 62, -87, 37, 46, -77, 44, 25, -65, + 53, 5, -50, 63, -14, -35, 72, -30, -21, 82, -45, -6, + 29, 70, -90, 31, 63, -86, 37, 46, -77, 45, 26, -64, + 54, 6, -50, 63, -13, -35, 72, -29, -20, 82, -44, -6, + 29, 71, -89, 32, 63, -85, 37, 47, -76, 45, 28, -64, + 54, 7, -49, 63, -12, -35, 73, -28, -20, 82, -44, -6, + 30, 71, -88, 33, 64, -84, 38, 48, -75, 45, 29, -63, + 54, 8, -49, 63, -10, -34, 73, -27, -20, 83, -42, -5, + 31, 71, -87, 33, 64, -83, 39, 49, -74, 46, 30, -62, + 55, 10, -48, 64, -9, -34, 73, -26, -20, 83, -41, -5, + 32, 72, -85, 34, 65, -81, 39, 50, -73, 46, 31, -61, + 55, 11, -47, 64, -7, -33, 73, -24, -19, 83, -40, -5, + 33, 72, -83, 35, 66, -80, 40, 52, -72, 47, 33, -60, + 56, 13, -47, 64, -6, -33, 74, -23, -19, 83, -38, -4, + 34, 73, -82, 36, 67, -78, 41, 53, -70, 48, 35, -59, + 56, 15, -46, 65, -4, -32, 74, -21, -18, 83, -37, -4, + 35, 74, -80, 37, 68, -77, 42, 54, -69, 48, 36, -58, + 57, 17, -45, 65, -2, -31, 74, -19, -18, 84, -35, -4, + 36, 74, -78, 38, 69, -75, 43, 56, -67, 49, 38, -57, + 57, 19, -44, 66, 0, -31, 75, -17, -17, 84, -33, -3, + 37, 75, -76, 39, 70, -73, 44, 57, -66, 50, 40, -56, + 58, 21, -43, 66, 3, -30, 75, -15, -16, 84, -31, -2, + 39, 76, -74, 40, 71, -71, 45, 59, -64, 51, 42, -54, + 58, 23, -42, 67, 5, -29, 75, -13, -16, 85, -29, -2, + 40, 77, -72, 42, 72, -69, 46, 60, -62, 51, 44, -53, + 59, 25, -41, 67, 7, -28, 76, -10, -15, 85, -27, -1, + 41, 78, -70, 43, 73, -67, 47, 62, -61, 52, 46, -51, + 60, 28, -40, 68, 9, -27, 76, -8, -14, 85, -25, -1, + 43, 79, -67, 44, 74, -65, 48, 64, -59, 53, 48, -50, + 61, 30, -38, 69, 12, -26, 77, -5, -13, 86, -22, 0, + 44, 80, -65, 45, 76, -63, 49, 65, -57, 54, 51, -48, + 61, 33, -37, 69, 15, -25, 77, -3, -12, 86, -20, 1, + 45, 81, -63, 47, 77, -60, 50, 67, -55, 55, 53, -47, + 62, 35, -36, 70, 17, -24, 78, 0, -12, 87, -17, 1, + 47, 82, -60, 48, 78, -58, 51, 69, -53, 56, 55, -45, + 63, 37, -34, 71, 20, -23, 79, 2, -11, 87, -15, 2, + 48, 83, -58, 49, 80, -56, 52, 70, -51, 57, 57, -43, + 64, 40, -33, 71, 22, -22, 79, 5, -10, 88, -12, 3, + 49, 85, -56, 51, 81, -54, 54, 72, -49, 59, 59, -41, + 65, 43, -31, 72, 25, -20, 80, 8, -8, 88, -9, 4, + 51, 86, -53, 52, 83, -51, 55, 74, -47, 60, 61, -39, + 66, 45, -30, 73, 28, -19, 81, 11, -7, 89, -7, 5, + 52, 87, -51, 53, 84, -49, 56, 76, -45, 61, 63, -38, + 67, 47, -28, 74, 31, -18, 81, 13, -6, 90, -4, 6, + 54, 89, -49, 55, 85, -47, 58, 78, -43, 62, 65, -36, + 68, 50, -27, 75, 33, -16, 82, 16, -5, 90, -1, 7, + 55, 90, -46, 56, 87, -44, 59, 80, -40, 63, 68, -34, + 69, 53, -25, 75, 36, -15, 83, 19, -4, 91, 2, 8, + 57, 92, -44, 58, 89, -42, 60, 81, -38, 64, 70, -32, + 70, 55, -23, 76, 39, -13, 84, 22, -3, 91, 5, 9, + 58, 93, -41, 59, 90, -40, 62, 83, -36, 65, 72, -30, + 71, 57, -22, 77, 41, -12, 84, 25, -1, 92, 8, 10, + 28, 71, -97, 30, 63, -93, 36, 46, -83, 44, 26, -70, + 53, 5, -55, 63, -14, -40, 72, -30, -25, 82, -45, -11, + 28, 71, -97, 30, 63, -92, 36, 46, -83, 44, 26, -70, + 53, 5, -55, 63, -14, -40, 72, -30, -25, 82, -45, -10, + 28, 71, -97, 30, 63, -92, 36, 46, -83, 44, 26, -70, + 53, 5, -55, 63, -13, -40, 72, -30, -25, 82, -45, -10, + 28, 72, -96, 31, 64, -92, 36, 47, -82, 44, 27, -69, + 53, 6, -55, 63, -13, -40, 72, -29, -25, 82, -45, -10, + 28, 72, -96, 31, 64, -91, 37, 47, -82, 44, 27, -69, + 54, 6, -54, 63, -12, -40, 72, -29, -25, 82, -44, -10, + 29, 72, -95, 31, 64, -91, 37, 48, -81, 45, 28, -69, + 54, 7, -54, 63, -12, -39, 72, -28, -25, 82, -44, -10, + 29, 72, -94, 32, 64, -90, 37, 48, -81, 45, 28, -68, + 54, 8, -54, 63, -11, -39, 73, -28, -25, 82, -43, -10, + 30, 72, -93, 32, 65, -89, 38, 49, -80, 45, 29, -68, + 54, 9, -53, 63, -10, -39, 73, -27, -24, 82, -42, -10, + 30, 72, -92, 33, 65, -88, 38, 50, -79, 46, 30, -67, + 54, 10, -53, 64, -9, -39, 73, -26, -24, 83, -41, -10, + 31, 73, -91, 33, 66, -87, 39, 51, -78, 46, 31, -67, + 55, 11, -52, 64, -8, -38, 73, -25, -24, 83, -40, -9, + 32, 73, -90, 34, 66, -86, 39, 52, -77, 46, 33, -66, + 55, 12, -52, 64, -6, -38, 73, -23, -23, 83, -39, -9, + 33, 74, -88, 35, 67, -85, 40, 53, -76, 47, 34, -65, + 55, 14, -51, 64, -5, -37, 74, -22, -23, 83, -38, -9, + 34, 74, -86, 36, 68, -83, 41, 54, -75, 48, 36, -64, + 56, 16, -50, 65, -3, -37, 74, -20, -23, 83, -36, -8, + 35, 75, -85, 37, 69, -81, 42, 55, -74, 48, 37, -63, + 56, 17, -50, 65, -1, -36, 74, -19, -22, 84, -35, -8, + 36, 75, -83, 38, 69, -80, 42, 56, -72, 49, 39, -62, + 57, 19, -49, 66, 0, -35, 75, -17, -22, 84, -33, -7, + 37, 76, -81, 39, 70, -78, 43, 58, -71, 50, 41, -61, + 58, 21, -48, 66, 2, -35, 75, -15, -21, 84, -31, -7, + 38, 77, -79, 40, 71, -76, 44, 59, -69, 50, 43, -59, + 58, 23, -47, 67, 5, -34, 75, -13, -20, 85, -29, -6, + 39, 78, -77, 41, 72, -74, 45, 61, -68, 51, 44, -58, + 59, 25, -46, 67, 7, -33, 76, -11, -20, 85, -27, -6, + 41, 78, -75, 42, 74, -72, 46, 62, -66, 52, 46, -57, + 59, 27, -45, 68, 9, -32, 76, -8, -19, 85, -25, -5, + 42, 79, -73, 43, 75, -71, 47, 64, -64, 53, 48, -55, + 60, 30, -44, 68, 11, -31, 77, -6, -18, 86, -23, -5, + 43, 80, -71, 45, 76, -68, 48, 65, -62, 54, 50, -53, + 61, 32, -42, 69, 14, -30, 77, -4, -17, 86, -21, -4, + 44, 81, -69, 46, 77, -66, 49, 67, -61, 55, 52, -52, + 62, 34, -41, 69, 16, -29, 78, -1, -16, 87, -18, -3, + 46, 82, -66, 47, 78, -64, 51, 69, -59, 56, 54, -50, + 63, 37, -40, 70, 19, -28, 78, 1, -15, 87, -16, -2, + 47, 84, -64, 48, 80, -62, 52, 70, -57, 57, 56, -49, + 63, 39, -38, 71, 21, -27, 79, 4, -15, 88, -13, -2, + 48, 85, -62, 50, 81, -60, 53, 72, -55, 58, 58, -47, + 64, 41, -37, 72, 24, -26, 79, 6, -14, 88, -11, -1, + 50, 86, -59, 51, 82, -57, 54, 74, -53, 59, 61, -45, + 65, 44, -35, 72, 27, -24, 80, 9, -12, 89, -8, 0, + 51, 87, -57, 53, 84, -55, 55, 75, -51, 60, 63, -43, + 66, 46, -34, 73, 29, -23, 81, 12, -11, 89, -5, 1, + 53, 88, -55, 54, 85, -53, 57, 77, -49, 61, 65, -42, + 67, 49, -32, 74, 32, -22, 82, 15, -10, 90, -3, 2, + 54, 90, -52, 55, 87, -51, 58, 79, -46, 62, 67, -40, + 68, 51, -31, 75, 35, -20, 82, 17, -9, 90, 0, 3, + 56, 91, -50, 57, 88, -48, 59, 81, -44, 63, 69, -38, + 69, 54, -29, 76, 38, -19, 83, 21, -8, 91, 3, 4, + 57, 93, -48, 58, 90, -46, 61, 82, -42, 65, 71, -36, + 70, 56, -27, 77, 40, -17, 84, 23, -7, 92, 6, 5, + 59, 94, -45, 59, 91, -44, 62, 84, -40, 66, 73, -34, + 71, 59, -25, 78, 43, -16, 85, 26, -5, 92, 9, 6, + 29, 73, -100, 31, 65, -96, 37, 49, -86, 45, 29, -73, + 54, 8, -59, 63, -11, -44, 72, -28, -29, 82, -43, -14, + 29, 73, -100, 31, 66, -95, 37, 49, -86, 45, 29, -73, + 54, 8, -59, 63, -11, -44, 72, -27, -29, 82, -43, -14, + 29, 73, -99, 31, 66, -95, 37, 49, -86, 45, 29, -73, + 54, 8, -59, 63, -10, -44, 72, -27, -29, 82, -43, -14, + 29, 73, -99, 32, 66, -95, 37, 50, -85, 45, 30, -73, + 54, 9, -58, 63, -10, -44, 73, -27, -29, 82, -42, -14, + 30, 74, -98, 32, 66, -94, 38, 50, -85, 45, 30, -73, + 54, 9, -58, 63, -10, -44, 73, -26, -29, 82, -42, -14, + 30, 74, -98, 32, 66, -94, 38, 50, -85, 45, 31, -72, + 54, 10, -58, 63, -9, -43, 73, -26, -29, 82, -41, -14, + 30, 74, -97, 33, 67, -93, 38, 51, -84, 46, 31, -72, + 54, 11, -58, 64, -8, -43, 73, -25, -29, 83, -41, -14, + 31, 74, -96, 33, 67, -92, 39, 52, -83, 46, 32, -71, + 55, 12, -57, 64, -7, -43, 73, -24, -28, 83, -40, -14, + 32, 74, -95, 34, 67, -91, 39, 52, -83, 46, 33, -71, + 55, 13, -57, 64, -6, -42, 73, -23, -28, 83, -39, -13, + 32, 75, -94, 34, 68, -90, 39, 53, -82, 47, 34, -70, + 55, 14, -56, 64, -5, -42, 73, -22, -28, 83, -38, -13, + 33, 75, -93, 35, 68, -89, 40, 54, -81, 47, 35, -69, + 56, 15, -56, 64, -4, -42, 74, -21, -27, 83, -37, -13, + 34, 75, -91, 36, 69, -88, 41, 55, -80, 48, 37, -69, + 56, 16, -55, 65, -2, -41, 74, -20, -27, 83, -36, -13, + 35, 76, -90, 37, 70, -86, 41, 56, -78, 48, 38, -67, + 56, 18, -54, 65, -1, -40, 74, -18, -26, 84, -34, -12, + 36, 76, -88, 38, 71, -85, 42, 57, -77, 49, 40, -66, + 57, 20, -53, 65, 1, -40, 74, -16, -26, 84, -33, -12, + 37, 77, -86, 39, 71, -83, 43, 58, -76, 49, 41, -65, + 57, 22, -53, 66, 3, -39, 75, -15, -25, 84, -31, -11, + 38, 78, -84, 40, 72, -82, 44, 60, -74, 50, 43, -64, + 58, 23, -52, 66, 5, -38, 75, -13, -25, 84, -29, -11, + 39, 78, -82, 41, 73, -80, 45, 61, -73, 51, 45, -63, + 59, 26, -51, 67, 7, -38, 76, -11, -24, 85, -27, -10, + 40, 79, -81, 42, 74, -78, 46, 63, -71, 52, 46, -62, + 59, 28, -50, 67, 9, -37, 76, -9, -23, 85, -25, -10, + 41, 80, -79, 43, 75, -76, 47, 64, -70, 52, 48, -60, + 60, 30, -48, 68, 11, -36, 76, -6, -23, 85, -23, -9, + 42, 81, -77, 44, 76, -74, 48, 65, -68, 53, 50, -59, + 61, 32, -47, 68, 13, -35, 77, -4, -22, 86, -21, -9, + 44, 82, -74, 45, 77, -72, 49, 67, -66, 54, 52, -57, + 61, 34, -46, 69, 16, -34, 77, -2, -21, 86, -19, -8, + 45, 83, -72, 46, 79, -70, 50, 69, -64, 55, 54, -56, + 62, 36, -45, 70, 18, -33, 78, 1, -20, 87, -16, -7, + 46, 84, -70, 48, 80, -68, 51, 70, -62, 56, 56, -54, + 63, 39, -43, 70, 21, -32, 79, 3, -19, 87, -14, -6, + 48, 85, -68, 49, 81, -66, 52, 72, -60, 57, 58, -53, + 64, 41, -42, 71, 23, -31, 79, 6, -18, 88, -12, -6, + 49, 86, -66, 50, 82, -64, 53, 73, -59, 58, 60, -51, + 65, 43, -41, 72, 26, -29, 80, 8, -17, 88, -9, -5, + 50, 87, -63, 52, 84, -61, 55, 75, -56, 59, 62, -49, + 66, 46, -39, 73, 28, -28, 80, 11, -16, 89, -6, -4, + 52, 88, -61, 53, 85, -59, 56, 77, -54, 60, 64, -47, + 67, 48, -38, 73, 31, -27, 81, 14, -15, 89, -4, -3, + 53, 90, -59, 54, 86, -57, 57, 78, -52, 61, 66, -45, + 67, 50, -36, 74, 33, -26, 82, 16, -14, 90, -1, -2, + 55, 91, -56, 56, 88, -55, 58, 80, -50, 63, 68, -44, + 68, 53, -35, 75, 36, -24, 82, 19, -13, 91, 2, -1, + 56, 92, -54, 57, 89, -52, 60, 82, -48, 64, 70, -42, + 69, 55, -33, 76, 39, -23, 83, 22, -12, 91, 5, 0, + 58, 94, -51, 59, 91, -50, 61, 83, -46, 65, 72, -40, + 70, 58, -31, 77, 41, -21, 84, 25, -11, 92, 7, 1, + 59, 95, -49, 60, 92, -48, 62, 85, -44, 66, 74, -38, + 72, 60, -29, 78, 44, -20, 85, 27, -9, 93, 10, 2, + 30, 75, -103, 32, 68, -99, 38, 52, -90, 45, 32, -77, + 54, 11, -63, 63, -8, -48, 73, -25, -34, 82, -40, -19, + 30, 75, -102, 33, 68, -98, 38, 52, -89, 45, 32, -77, + 54, 12, -63, 63, -7, -48, 73, -24, -34, 82, -40, -19, + 30, 75, -102, 33, 68, -98, 38, 52, -89, 45, 33, -77, + 54, 12, -63, 63, -7, -48, 73, -24, -33, 83, -40, -19, + 30, 76, -102, 33, 68, -98, 38, 53, -89, 46, 33, -77, + 54, 12, -62, 64, -7, -48, 73, -24, -33, 83, -40, -19, + 31, 76, -101, 33, 68, -97, 38, 53, -89, 46, 33, -77, + 55, 13, -62, 64, -6, -48, 73, -23, -33, 83, -39, -18, + 31, 76, -101, 33, 69, -97, 39, 53, -88, 46, 34, -76, + 55, 13, -62, 64, -6, -48, 73, -23, -33, 83, -39, -18, + 32, 76, -100, 34, 69, -96, 39, 54, -88, 46, 35, -76, + 55, 14, -62, 64, -5, -47, 73, -22, -33, 83, -38, -18, + 32, 76, -99, 34, 69, -95, 39, 55, -87, 47, 35, -75, + 55, 15, -61, 64, -4, -47, 73, -21, -33, 83, -37, -18, + 33, 76, -98, 35, 70, -95, 40, 55, -86, 47, 36, -75, + 55, 16, -61, 64, -3, -47, 74, -20, -32, 83, -37, -18, + 33, 77, -97, 35, 70, -94, 40, 56, -85, 47, 37, -74, + 56, 17, -60, 65, -2, -46, 74, -19, -32, 83, -36, -18, + 34, 77, -96, 36, 71, -92, 41, 57, -84, 48, 38, -73, + 56, 18, -60, 65, -1, -46, 74, -18, -32, 83, -34, -17, + 35, 77, -95, 37, 71, -91, 42, 58, -83, 48, 40, -72, + 56, 19, -59, 65, 1, -45, 74, -17, -31, 84, -33, -17, + 36, 78, -93, 38, 72, -90, 42, 59, -82, 49, 41, -71, + 57, 21, -58, 66, 2, -45, 74, -15, -31, 84, -32, -16, + 37, 78, -91, 39, 73, -88, 43, 60, -81, 49, 42, -71, + 57, 23, -58, 66, 4, -44, 75, -14, -30, 84, -30, -16, + 38, 79, -90, 39, 73, -87, 44, 61, -80, 50, 44, -69, + 58, 24, -57, 66, 6, -43, 75, -12, -30, 84, -29, -16, + 39, 79, -88, 40, 74, -85, 45, 62, -78, 51, 45, -68, + 58, 26, -56, 67, 7, -43, 75, -10, -29, 85, -27, -15, + 40, 80, -86, 41, 75, -83, 46, 63, -77, 51, 47, -67, + 59, 28, -55, 67, 10, -42, 76, -8, -28, 85, -25, -15, + 41, 81, -84, 43, 76, -82, 46, 65, -75, 52, 49, -66, + 60, 30, -54, 68, 12, -41, 76, -6, -28, 85, -23, -14, + 42, 82, -82, 44, 77, -80, 47, 66, -74, 53, 51, -64, + 60, 32, -53, 68, 14, -40, 77, -4, -27, 86, -21, -14, + 43, 83, -80, 45, 78, -78, 48, 67, -72, 54, 52, -63, + 61, 34, -52, 69, 16, -39, 77, -2, -26, 86, -19, -13, + 45, 83, -78, 46, 79, -76, 50, 69, -70, 55, 54, -61, + 62, 36, -50, 70, 18, -38, 78, 1, -25, 87, -17, -12, + 46, 84, -76, 47, 80, -74, 51, 70, -68, 56, 56, -60, + 63, 38, -49, 70, 20, -37, 78, 3, -25, 87, -14, -11, + 47, 85, -74, 48, 81, -72, 52, 72, -66, 57, 58, -58, + 63, 41, -48, 71, 23, -36, 79, 5, -24, 87, -12, -11, + 48, 86, -72, 50, 83, -70, 53, 73, -65, 58, 60, -57, + 64, 43, -46, 71, 25, -35, 79, 8, -23, 88, -10, -10, + 50, 87, -70, 51, 84, -68, 54, 75, -63, 59, 62, -55, + 65, 45, -45, 72, 28, -34, 80, 10, -22, 88, -7, -9, + 51, 89, -67, 52, 85, -65, 55, 77, -61, 60, 64, -53, + 66, 48, -43, 73, 30, -32, 81, 13, -21, 89, -5, -8, + 52, 90, -65, 54, 86, -63, 56, 78, -59, 61, 66, -51, + 67, 50, -42, 74, 33, -31, 81, 15, -20, 90, -2, -7, + 54, 91, -63, 55, 88, -61, 58, 80, -57, 62, 68, -50, + 68, 52, -40, 75, 35, -30, 82, 18, -19, 90, 1, -6, + 55, 92, -60, 56, 89, -59, 59, 81, -55, 63, 70, -48, + 69, 54, -39, 75, 38, -29, 83, 21, -17, 91, 3, -5, + 57, 94, -58, 58, 91, -56, 60, 83, -52, 64, 72, -46, + 70, 57, -37, 76, 40, -27, 84, 24, -16, 91, 6, -4, + 58, 95, -56, 59, 92, -54, 61, 85, -50, 65, 74, -44, + 71, 59, -35, 77, 43, -26, 84, 26, -15, 92, 9, -3, + 59, 96, -53, 60, 93, -52, 63, 86, -48, 67, 76, -42, + 72, 61, -34, 78, 45, -24, 85, 29, -14, 93, 12, -2, + 31, 77, -105, 33, 70, -101, 39, 55, -93, 46, 35, -81, + 55, 14, -66, 64, -5, -52, 73, -22, -37, 83, -38, -23, + 31, 77, -105, 34, 70, -101, 39, 55, -93, 46, 36, -81, + 55, 15, -66, 64, -4, -52, 73, -22, -37, 83, -38, -23, + 31, 77, -105, 34, 70, -101, 39, 55, -92, 46, 36, -80, + 55, 15, -66, 64, -4, -52, 73, -22, -37, 83, -38, -22, + 32, 77, -104, 34, 71, -101, 39, 55, -92, 46, 36, -80, + 55, 15, -66, 64, -4, -52, 73, -21, -37, 83, -37, -22, + 32, 78, -104, 34, 71, -100, 39, 56, -92, 46, 36, -80, + 55, 16, -66, 64, -3, -52, 73, -21, -37, 83, -37, -22, + 32, 78, -103, 34, 71, -100, 40, 56, -91, 47, 37, -80, + 55, 16, -66, 64, -3, -51, 73, -20, -37, 83, -36, -22, + 33, 78, -103, 35, 71, -99, 40, 56, -91, 47, 38, -79, + 55, 17, -65, 64, -2, -51, 74, -20, -37, 83, -36, -22, + 33, 78, -102, 35, 71, -98, 40, 57, -90, 47, 38, -79, + 56, 18, -65, 65, -1, -51, 74, -19, -36, 83, -35, -22, + 34, 78, -101, 36, 72, -97, 41, 58, -89, 48, 39, -78, + 56, 19, -64, 65, 0, -50, 74, -18, -36, 83, -34, -22, + 34, 78, -100, 36, 72, -96, 41, 58, -89, 48, 40, -77, + 56, 20, -64, 65, 1, -50, 74, -17, -36, 83, -33, -21, + 35, 79, -99, 37, 73, -95, 42, 59, -88, 48, 41, -77, + 57, 21, -63, 65, 2, -50, 74, -16, -36, 84, -32, -21, + 36, 79, -97, 38, 73, -94, 42, 60, -87, 49, 42, -76, + 57, 22, -63, 66, 3, -49, 74, -14, -35, 84, -31, -21, + 37, 80, -96, 39, 74, -93, 43, 61, -85, 49, 44, -75, + 57, 24, -62, 66, 5, -49, 75, -13, -35, 84, -30, -20, + 38, 80, -94, 39, 75, -91, 44, 62, -84, 50, 45, -74, + 58, 25, -61, 66, 6, -48, 75, -11, -34, 84, -28, -20, + 38, 81, -93, 40, 75, -90, 44, 63, -83, 51, 46, -73, + 58, 27, -60, 67, 8, -47, 75, -10, -34, 85, -27, -20, + 39, 81, -91, 41, 76, -88, 45, 64, -82, 51, 48, -72, + 59, 28, -60, 67, 10, -47, 76, -8, -33, 85, -25, -19, + 41, 82, -89, 42, 77, -87, 46, 65, -80, 52, 49, -71, + 60, 30, -59, 68, 12, -46, 76, -6, -32, 85, -23, -18, + 42, 83, -87, 43, 78, -85, 47, 67, -79, 53, 51, -69, + 60, 32, -58, 68, 14, -45, 77, -4, -32, 86, -21, -18, + 43, 83, -86, 44, 79, -83, 48, 68, -77, 54, 53, -68, + 61, 34, -56, 69, 16, -44, 77, -2, -31, 86, -19, -17, + 44, 84, -84, 45, 80, -81, 49, 69, -75, 54, 54, -67, + 61, 36, -55, 69, 18, -43, 77, 0, -30, 86, -17, -17, + 45, 85, -82, 47, 81, -79, 50, 71, -74, 55, 56, -65, + 62, 38, -54, 70, 20, -42, 78, 2, -29, 87, -15, -16, + 46, 86, -79, 48, 82, -77, 51, 72, -72, 56, 58, -64, + 63, 40, -53, 70, 22, -41, 79, 5, -28, 87, -13, -15, + 48, 87, -77, 49, 83, -75, 52, 74, -70, 57, 60, -62, + 64, 42, -52, 71, 25, -40, 79, 7, -28, 88, -10, -15, + 49, 88, -75, 50, 84, -73, 53, 75, -68, 58, 62, -60, + 65, 45, -50, 72, 27, -39, 80, 9, -27, 88, -8, -14, + 50, 89, -73, 51, 85, -71, 54, 76, -66, 59, 63, -59, + 65, 47, -49, 73, 29, -38, 80, 12, -26, 89, -6, -13, + 52, 90, -71, 53, 87, -69, 56, 78, -64, 60, 65, -57, + 66, 49, -47, 73, 32, -36, 81, 15, -25, 89, -3, -12, + 53, 91, -69, 54, 88, -67, 57, 80, -62, 61, 67, -55, + 67, 51, -46, 74, 34, -35, 82, 17, -24, 90, 0, -11, + 54, 92, -66, 55, 89, -65, 58, 81, -60, 62, 69, -53, + 68, 54, -44, 75, 37, -34, 82, 20, -22, 90, 2, -10, + 56, 93, -64, 57, 90, -63, 59, 83, -58, 63, 71, -52, + 69, 56, -43, 76, 39, -33, 83, 22, -21, 91, 5, -9, + 57, 95, -62, 58, 92, -60, 61, 84, -56, 65, 73, -50, + 70, 58, -41, 77, 42, -31, 84, 25, -20, 92, 8, -8, + 58, 96, -59, 59, 93, -58, 62, 86, -54, 66, 75, -48, + 71, 60, -39, 77, 44, -30, 85, 28, -19, 92, 10, -7, + 60, 97, -57, 61, 94, -56, 63, 88, -52, 67, 77, -46, + 72, 63, -38, 78, 47, -28, 85, 30, -18, 93, 13, -6, + 32, 79, -108, 35, 72, -104, 40, 58, -96, 47, 38, -84, + 55, 18, -70, 64, -2, -56, 73, -19, -41, 83, -36, -26, + 32, 79, -108, 35, 72, -104, 40, 58, -96, 47, 39, -84, + 55, 18, -70, 64, -1, -56, 73, -19, -41, 83, -35, -26, + 33, 79, -107, 35, 73, -104, 40, 58, -95, 47, 39, -84, + 55, 18, -70, 64, -1, -56, 73, -19, -41, 83, -35, -26, + 33, 79, -107, 35, 73, -103, 40, 58, -95, 47, 39, -84, + 55, 18, -70, 64, -1, -55, 74, -18, -41, 83, -35, -26, + 33, 79, -107, 35, 73, -103, 40, 58, -95, 47, 39, -83, + 56, 19, -69, 64, 0, -55, 74, -18, -41, 83, -34, -26, + 33, 80, -106, 35, 73, -103, 40, 59, -94, 47, 40, -83, + 56, 19, -69, 65, 0, -55, 74, -18, -41, 83, -34, -26, + 34, 80, -105, 36, 73, -102, 41, 59, -94, 48, 40, -83, + 56, 20, -69, 65, 1, -55, 74, -17, -41, 83, -33, -26, + 34, 80, -105, 36, 74, -101, 41, 60, -93, 48, 41, -82, + 56, 21, -69, 65, 2, -55, 74, -16, -40, 83, -33, -26, + 35, 80, -104, 37, 74, -100, 41, 60, -93, 48, 42, -82, + 56, 22, -68, 65, 2, -54, 74, -15, -40, 84, -32, -25, + 35, 80, -103, 37, 74, -99, 42, 61, -92, 49, 43, -81, + 57, 23, -68, 65, 3, -54, 74, -14, -40, 84, -31, -25, + 36, 81, -102, 38, 75, -98, 42, 62, -91, 49, 44, -80, + 57, 24, -67, 66, 5, -53, 75, -13, -39, 84, -30, -25, + 37, 81, -100, 39, 75, -97, 43, 62, -90, 49, 45, -79, + 57, 25, -66, 66, 6, -53, 75, -12, -39, 84, -29, -25, + 38, 81, -99, 39, 76, -96, 44, 63, -89, 50, 46, -78, + 58, 26, -66, 66, 7, -52, 75, -10, -38, 84, -27, -24, + 38, 82, -97, 40, 76, -95, 44, 64, -88, 51, 47, -78, + 58, 28, -65, 67, 9, -52, 75, -9, -38, 85, -26, -24, + 39, 82, -96, 41, 77, -93, 45, 65, -86, 51, 49, -77, + 59, 29, -64, 67, 10, -51, 76, -7, -37, 85, -24, -23, + 40, 83, -94, 42, 78, -92, 46, 66, -85, 52, 50, -75, + 59, 31, -63, 67, 12, -50, 76, -6, -37, 85, -23, -23, + 41, 83, -92, 43, 79, -90, 47, 67, -83, 53, 52, -74, + 60, 33, -62, 68, 14, -49, 77, -4, -36, 86, -21, -22, + 42, 84, -91, 44, 80, -88, 48, 69, -82, 53, 53, -73, + 61, 35, -61, 68, 16, -49, 77, -2, -35, 86, -19, -22, + 44, 85, -89, 45, 80, -86, 49, 70, -81, 54, 55, -72, + 61, 36, -60, 69, 18, -48, 77, 0, -35, 86, -17, -21, + 45, 86, -87, 46, 81, -85, 50, 71, -79, 55, 56, -70, + 62, 38, -59, 70, 20, -47, 78, 2, -34, 87, -15, -21, + 46, 86, -85, 47, 82, -83, 51, 72, -77, 56, 58, -69, + 63, 40, -58, 70, 22, -46, 78, 5, -33, 87, -13, -20, + 47, 87, -83, 48, 83, -81, 52, 74, -75, 57, 60, -67, + 63, 42, -57, 71, 24, -45, 79, 7, -32, 88, -11, -19, + 48, 88, -81, 50, 84, -79, 53, 75, -74, 58, 62, -66, + 64, 44, -55, 71, 27, -44, 79, 9, -31, 88, -9, -18, + 50, 89, -79, 51, 85, -77, 54, 77, -72, 59, 63, -64, + 65, 46, -54, 72, 29, -43, 80, 11, -31, 88, -6, -18, + 51, 90, -77, 52, 87, -75, 55, 78, -70, 60, 65, -63, + 66, 49, -53, 73, 31, -42, 81, 14, -30, 89, -4, -17, + 52, 91, -74, 53, 88, -72, 56, 80, -68, 61, 67, -61, + 67, 51, -51, 74, 34, -40, 81, 16, -28, 90, -1, -16, + 54, 92, -72, 55, 89, -70, 57, 81, -66, 62, 69, -59, + 68, 53, -50, 74, 36, -39, 82, 19, -27, 90, 1, -15, + 55, 93, -70, 56, 90, -68, 59, 83, -64, 63, 71, -57, + 69, 55, -48, 75, 38, -38, 83, 21, -26, 91, 4, -14, + 56, 95, -68, 57, 92, -66, 60, 84, -62, 64, 72, -55, + 69, 57, -47, 76, 41, -36, 83, 24, -25, 91, 6, -13, + 58, 96, -65, 59, 93, -64, 61, 86, -60, 65, 75, -53, + 71, 60, -45, 77, 43, -35, 84, 27, -24, 92, 9, -12, + 59, 97, -63, 60, 94, -62, 62, 87, -58, 66, 76, -52, + 72, 62, -43, 78, 46, -33, 85, 29, -23, 93, 12, -11, + 60, 98, -61, 61, 96, -59, 64, 89, -56, 67, 78, -50, + 73, 64, -42, 79, 48, -32, 86, 32, -22, 93, 14, -10, + 1, -2, 1, 11, -22, 16, 25, -34, 32, 37, -44, 42, + 48, -53, 52, 59, -62, 60, 70, -71, 69, 80, -80, 77, + 1, 0, 2, 11, -19, 17, 25, -32, 32, 37, -43, 42, + 48, -53, 52, 59, -62, 60, 70, -71, 69, 80, -80, 77, + 2, 3, 3, 12, -16, 17, 25, -31, 33, 37, -42, 42, + 48, -52, 52, 59, -62, 60, 70, -71, 69, 80, -79, 77, + 3, 7, 4, 12, -12, 18, 25, -28, 33, 37, -40, 43, + 49, -51, 52, 59, -61, 61, 70, -70, 69, 80, -79, 77, + 4, 12, 6, 13, -7, 19, 26, -25, 33, 37, -38, 43, + 49, -50, 52, 60, -60, 61, 70, -69, 69, 80, -78, 77, + 5, 17, 8, 14, -3, 21, 26, -22, 34, 37, -36, 43, + 49, -48, 52, 60, -59, 61, 70, -68, 69, 81, -78, 78, + 7, 22, 10, 15, 2, 22, 26, -18, 35, 38, -34, 44, + 49, -46, 53, 60, -57, 61, 70, -67, 69, 81, -77, 78, + 9, 26, 14, 16, 7, 24, 27, -14, 36, 38, -30, 44, + 49, -44, 53, 60, -55, 61, 70, -66, 70, 81, -75, 78, + 11, 29, 17, 18, 11, 26, 28, -10, 36, 39, -27, 45, + 50, -41, 53, 60, -53, 62, 71, -64, 70, 81, -74, 78, + 13, 31, 20, 19, 15, 28, 29, -6, 37, 39, -24, 45, + 50, -39, 54, 61, -51, 62, 71, -62, 70, 81, -73, 78, + 15, 34, 23, 20, 19, 30, 30, -2, 38, 40, -20, 46, + 51, -36, 54, 61, -49, 62, 71, -60, 70, 81, -71, 78, + 17, 36, 26, 22, 23, 32, 30, 3, 40, 40, -16, 47, + 51, -33, 55, 61, -46, 63, 71, -58, 71, 81, -69, 79, + 19, 39, 29, 23, 27, 34, 32, 7, 41, 41, -12, 48, + 51, -29, 55, 62, -43, 63, 72, -56, 71, 82, -67, 79, + 21, 41, 32, 25, 30, 36, 33, 11, 42, 42, -8, 49, + 52, -26, 56, 62, -40, 64, 72, -53, 71, 82, -65, 79, + 23, 44, 34, 26, 33, 38, 34, 15, 43, 43, -4, 49, + 53, -22, 57, 62, -37, 64, 72, -51, 72, 82, -63, 80, + 25, 46, 37, 28, 36, 40, 35, 19, 45, 44, 0, 50, + 53, -18, 57, 63, -34, 65, 73, -48, 72, 83, -61, 80, + 27, 48, 39, 30, 40, 42, 36, 23, 46, 45, 4, 52, + 54, -14, 58, 63, -30, 65, 73, -45, 73, 83, -58, 80, + 29, 51, 42, 31, 42, 44, 38, 26, 48, 45, 8, 53, + 55, -11, 59, 64, -27, 66, 74, -42, 73, 83, -55, 81, + 30, 53, 44, 33, 45, 46, 39, 30, 49, 46, 12, 54, + 55, -7, 60, 65, -24, 67, 74, -39, 74, 84, -53, 81, + 32, 55, 46, 35, 48, 48, 40, 33, 50, 47, 16, 55, + 56, -3, 61, 65, -20, 68, 74, -35, 74, 84, -50, 82, + 34, 57, 48, 36, 51, 50, 42, 37, 52, 49, 20, 56, + 57, 1, 62, 66, -16, 68, 75, -32, 75, 85, -46, 82, + 36, 59, 50, 38, 53, 51, 43, 40, 54, 50, 23, 58, + 58, 5, 63, 67, -13, 69, 76, -28, 76, 85, -43, 83, + 38, 61, 52, 40, 56, 53, 44, 43, 55, 51, 27, 59, + 59, 8, 64, 67, -9, 70, 76, -25, 77, 85, -40, 84, + 39, 64, 54, 41, 58, 54, 46, 46, 57, 52, 30, 60, + 60, 12, 65, 68, -5, 71, 77, -22, 77, 86, -37, 84, + 41, 66, 55, 43, 60, 56, 47, 49, 58, 53, 33, 61, + 61, 16, 66, 69, -2, 72, 77, -18, 78, 87, -34, 85, + 43, 68, 57, 45, 63, 58, 49, 52, 60, 54, 37, 63, + 62, 20, 67, 70, 2, 73, 78, -14, 79, 87, -30, 85, + 45, 70, 59, 46, 65, 60, 50, 55, 61, 56, 40, 64, + 63, 23, 69, 71, 6, 74, 79, -11, 80, 88, -27, 86, + 46, 72, 61, 48, 67, 61, 52, 57, 63, 57, 43, 66, + 64, 26, 70, 71, 9, 75, 80, -7, 81, 88, -24, 87, + 48, 74, 62, 50, 70, 63, 53, 60, 64, 58, 46, 67, + 65, 30, 71, 72, 13, 76, 80, -4, 81, 89, -20, 88, + 50, 76, 64, 51, 72, 65, 55, 63, 66, 60, 50, 68, + 66, 33, 72, 73, 17, 77, 81, 0, 82, 90, -17, 88, + 52, 78, 66, 53, 74, 66, 56, 65, 67, 61, 53, 70, + 67, 37, 74, 74, 20, 78, 82, 3, 83, 90, -13, 89, + 53, 80, 67, 55, 76, 68, 58, 68, 69, 62, 55, 71, + 68, 40, 75, 75, 23, 79, 83, 7, 84, 91, -10, 90, + 1, 0, -2, 11, -20, 13, 25, -33, 29, 37, -43, 40, + 48, -53, 50, 59, -62, 59, 70, -71, 68, 80, -80, 76, + 1, 2, -1, 11, -18, 13, 25, -31, 29, 37, -42, 40, + 48, -53, 50, 59, -62, 59, 70, -71, 68, 80, -80, 77, + 2, 4, 0, 12, -15, 14, 25, -30, 29, 37, -41, 40, + 48, -52, 50, 59, -61, 59, 70, -70, 68, 80, -79, 77, + 3, 8, 1, 13, -11, 15, 25, -27, 30, 37, -40, 40, + 49, -51, 50, 59, -61, 59, 70, -70, 68, 80, -79, 77, + 4, 13, 3, 13, -6, 16, 26, -25, 30, 37, -38, 41, + 49, -50, 51, 60, -60, 60, 70, -69, 68, 80, -78, 77, + 5, 18, 5, 14, -2, 17, 26, -22, 31, 37, -36, 41, + 49, -48, 51, 60, -58, 60, 70, -68, 68, 81, -77, 77, + 7, 23, 7, 15, 3, 19, 27, -18, 31, 38, -33, 41, + 49, -46, 51, 60, -57, 60, 70, -67, 68, 81, -77, 77, + 9, 26, 11, 16, 7, 21, 27, -14, 32, 38, -30, 42, + 49, -44, 51, 60, -55, 60, 70, -65, 69, 81, -75, 77, + 11, 29, 14, 18, 12, 23, 28, -10, 33, 39, -27, 43, + 50, -41, 52, 60, -53, 60, 71, -64, 69, 81, -74, 77, + 13, 32, 17, 19, 16, 24, 29, -5, 34, 39, -23, 43, + 50, -38, 52, 61, -51, 61, 71, -62, 69, 81, -73, 77, + 15, 34, 20, 20, 20, 26, 30, -1, 35, 40, -20, 44, + 51, -36, 53, 61, -49, 61, 71, -60, 69, 81, -71, 78, + 17, 36, 23, 22, 23, 28, 31, 3, 36, 40, -16, 45, + 51, -32, 53, 61, -46, 62, 71, -58, 70, 81, -69, 78, + 19, 39, 26, 23, 27, 31, 32, 7, 38, 41, -12, 46, + 52, -29, 54, 62, -43, 62, 72, -56, 70, 82, -67, 78, + 21, 42, 29, 25, 30, 33, 33, 11, 39, 42, -8, 47, + 52, -25, 55, 62, -40, 63, 72, -53, 71, 82, -65, 79, + 23, 44, 31, 27, 34, 35, 34, 15, 41, 43, -4, 47, + 53, -22, 55, 62, -37, 63, 72, -51, 71, 82, -63, 79, + 25, 46, 34, 28, 37, 37, 35, 19, 42, 44, 0, 49, + 53, -18, 56, 63, -34, 64, 73, -48, 71, 83, -61, 79, + 27, 49, 36, 30, 40, 39, 36, 23, 44, 45, 4, 50, + 54, -14, 57, 64, -30, 64, 73, -45, 72, 83, -58, 80, + 29, 51, 39, 31, 43, 41, 38, 27, 45, 45, 8, 51, + 55, -10, 58, 64, -27, 65, 74, -42, 72, 83, -55, 80, + 30, 53, 41, 33, 45, 43, 39, 30, 46, 46, 12, 52, + 55, -7, 59, 65, -23, 66, 74, -38, 73, 84, -52, 81, + 32, 55, 43, 35, 48, 44, 40, 33, 48, 47, 16, 53, + 56, -3, 60, 65, -20, 67, 74, -35, 74, 84, -50, 81, + 34, 57, 45, 37, 51, 46, 42, 37, 50, 49, 20, 55, + 57, 1, 61, 66, -16, 67, 75, -32, 74, 85, -46, 82, + 36, 59, 47, 38, 53, 48, 43, 40, 51, 50, 23, 56, + 58, 5, 62, 67, -12, 68, 76, -28, 75, 85, -43, 82, + 38, 62, 49, 40, 56, 50, 44, 43, 53, 51, 27, 57, + 59, 8, 63, 67, -9, 69, 76, -25, 76, 86, -40, 83, + 39, 64, 51, 41, 58, 52, 46, 46, 54, 52, 30, 58, + 60, 12, 64, 68, -5, 70, 77, -22, 76, 86, -37, 83, + 41, 66, 53, 43, 60, 54, 47, 49, 56, 53, 33, 60, + 61, 16, 65, 69, -2, 71, 77, -18, 77, 87, -34, 84, + 43, 68, 55, 45, 63, 56, 49, 52, 58, 54, 37, 61, + 62, 20, 66, 70, 2, 72, 78, -14, 78, 87, -30, 85, + 45, 70, 56, 46, 65, 57, 50, 55, 59, 56, 40, 63, + 63, 23, 67, 71, 6, 73, 79, -11, 79, 88, -27, 86, + 46, 72, 58, 48, 67, 59, 52, 57, 61, 57, 43, 64, + 64, 26, 69, 71, 9, 74, 80, -7, 80, 88, -24, 86, + 48, 74, 60, 50, 70, 61, 53, 60, 62, 58, 46, 65, + 65, 30, 70, 72, 13, 75, 80, -4, 81, 89, -20, 87, + 50, 76, 62, 51, 72, 63, 55, 63, 64, 60, 50, 67, + 66, 34, 71, 73, 17, 76, 81, 0, 82, 90, -17, 88, + 52, 78, 64, 53, 74, 64, 56, 65, 66, 61, 53, 68, + 67, 37, 72, 74, 20, 77, 82, 3, 83, 90, -13, 89, + 53, 80, 65, 55, 76, 66, 58, 68, 67, 62, 56, 70, + 68, 40, 74, 75, 23, 78, 83, 7, 83, 91, -10, 89, + 1, 1, -5, 11, -19, 9, 25, -32, 26, 37, -43, 38, + 48, -53, 48, 59, -62, 58, 70, -71, 67, 80, -80, 76, + 2, 3, -5, 12, -16, 10, 25, -31, 26, 37, -42, 38, + 48, -52, 48, 59, -62, 58, 70, -71, 67, 80, -79, 76, + 2, 5, -4, 12, -14, 11, 25, -29, 26, 37, -41, 38, + 49, -52, 49, 59, -61, 58, 70, -70, 67, 80, -79, 76, + 3, 9, -2, 13, -10, 11, 25, -27, 26, 37, -39, 38, + 49, -51, 49, 59, -60, 58, 70, -70, 67, 80, -79, 76, + 4, 14, -1, 13, -5, 13, 26, -24, 27, 37, -38, 38, + 49, -49, 49, 60, -59, 58, 70, -69, 67, 80, -78, 76, + 5, 19, 1, 14, -1, 14, 26, -21, 27, 38, -35, 39, + 49, -48, 49, 60, -58, 58, 70, -68, 67, 81, -77, 76, + 7, 23, 4, 15, 3, 15, 27, -17, 28, 38, -33, 39, + 49, -46, 49, 60, -57, 59, 70, -67, 67, 81, -76, 76, + 9, 27, 7, 16, 8, 17, 27, -13, 29, 38, -30, 40, + 49, -43, 50, 60, -55, 59, 70, -65, 68, 81, -75, 76, + 11, 29, 10, 18, 12, 19, 28, -9, 30, 39, -26, 40, + 50, -41, 50, 60, -53, 59, 71, -64, 68, 81, -74, 77, + 13, 32, 13, 19, 16, 21, 29, -5, 31, 39, -23, 41, + 50, -38, 51, 61, -51, 60, 71, -62, 68, 81, -73, 77, + 15, 34, 16, 20, 20, 23, 30, -1, 32, 40, -19, 42, + 51, -35, 51, 61, -48, 60, 71, -60, 68, 81, -71, 77, + 17, 37, 19, 22, 23, 25, 31, 3, 33, 40, -16, 43, + 51, -32, 52, 61, -46, 60, 71, -58, 69, 81, -69, 77, + 19, 39, 22, 24, 27, 27, 32, 8, 35, 41, -11, 43, + 52, -29, 52, 62, -43, 61, 72, -55, 69, 82, -67, 78, + 21, 42, 25, 25, 31, 29, 33, 12, 36, 42, -8, 44, + 52, -25, 53, 62, -40, 61, 72, -53, 70, 82, -65, 78, + 23, 44, 27, 27, 34, 31, 34, 15, 38, 43, -4, 45, + 53, -22, 54, 62, -37, 62, 72, -50, 70, 82, -63, 78, + 25, 46, 30, 28, 37, 33, 35, 19, 39, 44, 0, 46, + 53, -18, 55, 63, -34, 63, 73, -48, 70, 83, -60, 79, + 27, 49, 33, 30, 40, 35, 36, 23, 41, 45, 5, 48, + 54, -14, 55, 64, -30, 63, 73, -44, 71, 83, -58, 79, + 29, 51, 35, 32, 43, 37, 38, 27, 42, 46, 8, 49, + 55, -10, 56, 64, -27, 64, 74, -41, 72, 83, -55, 79, + 30, 53, 37, 33, 45, 39, 39, 30, 44, 46, 12, 50, + 55, -7, 57, 65, -23, 65, 74, -38, 72, 84, -52, 80, + 32, 55, 39, 35, 48, 41, 40, 34, 46, 48, 16, 51, + 56, -3, 58, 65, -20, 65, 75, -35, 73, 84, -49, 80, + 34, 58, 42, 37, 51, 43, 42, 37, 47, 49, 20, 53, + 57, 1, 59, 66, -16, 66, 75, -32, 73, 85, -46, 81, + 36, 60, 44, 38, 53, 45, 43, 40, 49, 50, 23, 54, + 58, 5, 60, 67, -12, 67, 76, -28, 74, 85, -43, 82, + 38, 62, 46, 40, 56, 47, 44, 43, 51, 51, 27, 55, + 59, 9, 61, 67, -9, 68, 76, -25, 75, 86, -40, 82, + 39, 64, 48, 41, 58, 49, 46, 46, 52, 52, 30, 57, + 60, 12, 63, 68, -5, 69, 77, -21, 76, 86, -37, 83, + 41, 66, 50, 43, 61, 51, 47, 49, 54, 53, 34, 58, + 61, 16, 64, 69, -2, 70, 77, -18, 76, 87, -34, 83, + 43, 68, 52, 45, 63, 53, 49, 52, 56, 55, 37, 60, + 62, 20, 65, 70, 2, 71, 78, -14, 77, 87, -30, 84, + 45, 70, 54, 46, 65, 55, 50, 55, 57, 56, 40, 61, + 63, 23, 66, 71, 6, 72, 79, -11, 78, 88, -27, 85, + 47, 72, 56, 48, 68, 57, 52, 58, 59, 57, 43, 62, + 64, 27, 67, 71, 9, 73, 80, -7, 79, 88, -24, 86, + 48, 74, 58, 50, 70, 58, 53, 60, 61, 58, 47, 64, + 65, 30, 69, 72, 13, 74, 80, -4, 80, 89, -20, 86, + 50, 76, 60, 51, 72, 60, 55, 63, 62, 60, 50, 66, + 66, 34, 70, 73, 17, 75, 81, 0, 81, 90, -17, 87, + 52, 78, 61, 53, 74, 62, 56, 65, 64, 61, 53, 67, + 67, 37, 71, 74, 20, 76, 82, 3, 82, 90, -13, 88, + 53, 80, 63, 55, 76, 64, 58, 68, 66, 62, 56, 68, + 68, 40, 72, 75, 24, 77, 83, 7, 83, 91, -10, 89, + 1, 3, -11, 11, -17, 4, 25, -31, 21, 37, -42, 34, + 48, -52, 46, 59, -62, 56, 70, -71, 65, 80, -79, 74, + 2, 5, -10, 12, -14, 4, 25, -29, 21, 37, -41, 34, + 48, -52, 46, 59, -61, 56, 70, -70, 65, 80, -79, 75, + 2, 7, -9, 12, -11, 5, 25, -28, 21, 37, -40, 34, + 49, -51, 46, 59, -61, 56, 70, -70, 65, 80, -79, 75, + 3, 11, -8, 13, -8, 6, 25, -26, 22, 37, -39, 35, + 49, -50, 46, 59, -60, 56, 70, -69, 66, 80, -78, 75, + 4, 16, -6, 14, -4, 7, 26, -23, 22, 37, -37, 35, + 49, -49, 46, 60, -59, 56, 70, -69, 66, 80, -78, 75, + 6, 21, -4, 14, 0, 8, 26, -20, 23, 38, -35, 35, + 49, -47, 47, 60, -58, 57, 70, -68, 66, 81, -77, 75, + 7, 25, -2, 15, 4, 10, 27, -16, 24, 38, -32, 36, + 49, -45, 47, 60, -56, 57, 70, -66, 66, 81, -76, 75, + 9, 27, 2, 17, 9, 12, 27, -12, 25, 38, -29, 36, + 50, -43, 47, 60, -55, 57, 70, -65, 66, 81, -75, 75, + 11, 30, 5, 18, 13, 13, 28, -8, 26, 39, -26, 37, + 50, -40, 48, 60, -53, 57, 71, -63, 66, 81, -74, 75, + 13, 32, 8, 19, 17, 15, 29, -4, 27, 39, -22, 38, + 50, -38, 48, 61, -51, 58, 71, -62, 67, 81, -72, 75, + 15, 35, 11, 21, 20, 17, 30, 0, 28, 40, -19, 38, + 51, -35, 49, 61, -48, 58, 71, -60, 67, 81, -71, 76, + 17, 37, 13, 22, 24, 19, 31, 4, 29, 40, -15, 39, + 51, -32, 49, 61, -46, 58, 71, -58, 67, 82, -69, 76, + 19, 40, 17, 24, 28, 22, 32, 8, 31, 41, -11, 40, + 52, -28, 50, 62, -43, 59, 72, -55, 68, 82, -67, 76, + 21, 42, 19, 25, 31, 24, 33, 12, 32, 42, -7, 41, + 52, -25, 51, 62, -40, 60, 72, -53, 68, 82, -65, 77, + 23, 44, 22, 27, 34, 26, 34, 16, 34, 43, -3, 42, + 53, -21, 51, 62, -37, 60, 72, -50, 69, 82, -63, 77, + 25, 47, 24, 28, 37, 28, 35, 20, 35, 44, 1, 43, + 53, -18, 52, 63, -33, 61, 73, -47, 69, 83, -60, 77, + 27, 49, 27, 30, 40, 31, 36, 24, 37, 45, 5, 45, + 54, -14, 53, 64, -30, 61, 73, -44, 70, 83, -57, 78, + 29, 51, 30, 32, 43, 33, 38, 27, 39, 46, 9, 46, + 55, -10, 54, 64, -26, 62, 74, -41, 70, 83, -55, 78, + 31, 53, 32, 33, 46, 35, 39, 30, 40, 47, 12, 47, + 55, -6, 55, 65, -23, 63, 74, -38, 71, 84, -52, 79, + 32, 55, 35, 35, 48, 37, 40, 34, 42, 48, 16, 48, + 56, -3, 56, 65, -20, 64, 75, -35, 71, 84, -49, 79, + 34, 58, 37, 37, 51, 39, 42, 37, 44, 49, 20, 50, + 57, 1, 57, 66, -16, 64, 75, -31, 72, 85, -46, 80, + 36, 60, 39, 38, 54, 41, 43, 40, 45, 50, 24, 51, + 58, 5, 58, 67, -12, 65, 76, -28, 73, 85, -43, 80, + 38, 62, 42, 40, 56, 43, 44, 43, 47, 51, 27, 53, + 59, 9, 59, 67, -9, 66, 76, -25, 73, 86, -40, 81, + 40, 64, 44, 41, 58, 45, 46, 46, 49, 52, 30, 54, + 60, 12, 60, 68, -5, 67, 77, -21, 74, 86, -37, 82, + 41, 66, 46, 43, 61, 47, 47, 49, 51, 53, 34, 55, + 61, 16, 62, 69, -1, 68, 77, -18, 75, 87, -34, 82, + 43, 68, 48, 45, 63, 49, 49, 52, 53, 55, 37, 57, + 62, 20, 63, 70, 3, 69, 78, -14, 76, 87, -30, 83, + 45, 70, 50, 46, 65, 51, 50, 55, 54, 56, 41, 59, + 63, 23, 64, 71, 6, 70, 79, -11, 77, 88, -27, 84, + 47, 72, 52, 48, 68, 53, 52, 58, 56, 57, 44, 60, + 64, 27, 65, 71, 10, 71, 80, -7, 78, 88, -23, 84, + 48, 74, 54, 50, 70, 55, 53, 60, 58, 58, 47, 61, + 65, 30, 67, 72, 13, 72, 80, -4, 78, 89, -20, 85, + 50, 76, 56, 51, 72, 57, 55, 63, 60, 60, 50, 63, + 66, 34, 68, 73, 17, 73, 81, 0, 79, 90, -16, 86, + 52, 78, 58, 53, 74, 59, 56, 66, 61, 61, 53, 65, + 67, 37, 69, 74, 20, 75, 82, 4, 80, 90, -13, 87, + 53, 80, 60, 55, 76, 61, 58, 68, 63, 62, 56, 66, + 68, 40, 71, 75, 24, 76, 83, 7, 81, 91, -10, 88, + 2, 5, -17, 12, -14, -2, 25, -29, 16, 37, -41, 31, + 48, -52, 43, 59, -61, 54, 70, -70, 64, 80, -79, 73, + 2, 7, -16, 12, -11, -1, 25, -28, 17, 37, -40, 31, + 49, -51, 43, 59, -61, 54, 70, -70, 64, 80, -79, 73, + 3, 10, -15, 12, -9, -1, 25, -27, 17, 37, -39, 31, + 49, -50, 43, 59, -60, 54, 70, -70, 64, 80, -79, 73, + 4, 14, -14, 13, -6, 0, 25, -24, 17, 37, -38, 31, + 49, -49, 43, 60, -59, 54, 70, -69, 64, 80, -78, 73, + 5, 18, -12, 14, -2, 2, 26, -22, 18, 37, -36, 31, + 49, -48, 44, 60, -59, 54, 70, -68, 64, 81, -78, 73, + 6, 22, -10, 15, 2, 3, 26, -19, 18, 38, -34, 32, + 49, -47, 44, 60, -57, 54, 70, -67, 64, 81, -77, 73, + 8, 26, -7, 16, 6, 4, 27, -15, 19, 38, -31, 32, + 49, -45, 44, 60, -56, 55, 70, -66, 64, 81, -76, 73, + 10, 28, -4, 17, 10, 6, 27, -11, 20, 38, -28, 33, + 50, -42, 45, 60, -54, 55, 70, -65, 64, 81, -75, 74, + 12, 31, -1, 18, 14, 8, 28, -8, 21, 39, -25, 33, + 50, -40, 45, 60, -52, 55, 71, -63, 65, 81, -73, 74, + 14, 33, 2, 19, 18, 10, 29, -4, 22, 39, -22, 34, + 50, -37, 45, 61, -50, 56, 71, -61, 65, 81, -72, 74, + 15, 35, 5, 21, 21, 12, 30, 0, 24, 40, -18, 35, + 51, -34, 46, 61, -48, 56, 71, -60, 65, 81, -70, 74, + 17, 38, 8, 22, 25, 14, 31, 4, 25, 41, -15, 36, + 51, -31, 47, 61, -45, 56, 71, -57, 66, 82, -69, 75, + 19, 40, 11, 24, 28, 17, 32, 9, 26, 41, -10, 37, + 52, -28, 47, 62, -42, 57, 72, -55, 66, 82, -67, 75, + 21, 42, 14, 25, 31, 19, 33, 13, 28, 42, -7, 38, + 52, -24, 48, 62, -39, 57, 72, -52, 66, 82, -65, 75, + 23, 45, 17, 27, 34, 21, 34, 16, 29, 43, -3, 39, + 53, -21, 49, 63, -36, 58, 72, -50, 67, 82, -62, 76, + 25, 47, 19, 28, 37, 23, 35, 20, 31, 44, 1, 40, + 53, -17, 50, 63, -33, 59, 73, -47, 67, 83, -60, 76, + 27, 49, 22, 30, 41, 26, 37, 24, 33, 45, 5, 41, + 54, -13, 51, 64, -30, 59, 73, -44, 68, 83, -57, 76, + 29, 51, 25, 32, 43, 28, 38, 27, 35, 46, 9, 43, + 55, -10, 51, 64, -26, 60, 74, -41, 68, 83, -55, 77, + 31, 54, 27, 33, 46, 30, 39, 31, 36, 47, 13, 44, + 56, -6, 52, 65, -23, 61, 74, -38, 69, 84, -52, 77, + 32, 56, 30, 35, 49, 32, 40, 34, 38, 48, 16, 45, + 56, -2, 53, 65, -19, 62, 75, -35, 70, 84, -49, 78, + 34, 58, 33, 37, 51, 35, 42, 38, 40, 49, 20, 47, + 57, 2, 55, 66, -15, 62, 75, -31, 70, 85, -46, 78, + 36, 60, 35, 38, 54, 37, 43, 41, 42, 50, 24, 48, + 58, 5, 56, 67, -12, 63, 76, -28, 71, 85, -43, 79, + 38, 62, 37, 40, 56, 39, 45, 44, 44, 51, 27, 50, + 59, 9, 57, 67, -8, 64, 76, -24, 72, 86, -40, 80, + 40, 64, 39, 42, 59, 41, 46, 47, 45, 52, 31, 51, + 60, 13, 58, 68, -5, 65, 77, -21, 72, 86, -37, 80, + 41, 66, 42, 43, 61, 43, 47, 49, 47, 53, 34, 53, + 61, 16, 59, 69, -1, 66, 78, -18, 73, 87, -33, 81, + 43, 68, 44, 45, 63, 46, 49, 53, 49, 55, 38, 54, + 62, 20, 60, 70, 3, 67, 78, -14, 74, 87, -30, 82, + 45, 70, 46, 47, 66, 48, 50, 55, 51, 56, 41, 56, + 63, 23, 62, 71, 6, 68, 79, -10, 75, 88, -27, 82, + 47, 72, 48, 48, 68, 50, 52, 58, 53, 57, 44, 57, + 64, 27, 63, 71, 10, 69, 80, -7, 76, 88, -23, 83, + 48, 74, 51, 50, 70, 52, 53, 60, 55, 58, 47, 59, + 65, 30, 64, 72, 13, 70, 80, -4, 77, 89, -20, 84, + 50, 76, 53, 52, 72, 54, 55, 63, 57, 60, 50, 61, + 66, 34, 66, 73, 17, 72, 81, 0, 78, 90, -16, 85, + 52, 78, 55, 53, 74, 56, 56, 66, 58, 61, 53, 62, + 67, 37, 67, 74, 20, 73, 82, 4, 79, 90, -13, 85, + 53, 80, 57, 55, 77, 58, 58, 68, 60, 62, 56, 64, + 68, 40, 68, 75, 24, 74, 83, 7, 80, 91, -10, 86, + 2, 9, -22, 12, -10, -7, 25, -27, 12, 37, -40, 27, + 49, -51, 40, 59, -61, 51, 70, -70, 61, 80, -79, 71, + 3, 11, -22, 12, -8, -6, 25, -26, 12, 37, -39, 27, + 49, -50, 40, 59, -60, 51, 70, -69, 61, 80, -79, 71, + 3, 13, -21, 13, -6, -6, 25, -25, 12, 37, -38, 27, + 49, -50, 40, 59, -60, 51, 70, -69, 62, 80, -78, 71, + 4, 17, -19, 13, -3, -5, 26, -23, 12, 37, -37, 27, + 49, -49, 40, 60, -59, 51, 70, -68, 62, 80, -78, 71, + 5, 21, -18, 14, 0, -4, 26, -20, 13, 37, -35, 27, + 49, -47, 40, 60, -58, 52, 70, -68, 62, 81, -77, 71, + 6, 24, -15, 15, 4, -2, 26, -17, 14, 38, -33, 28, + 49, -46, 41, 60, -57, 52, 70, -67, 62, 81, -76, 72, + 8, 27, -13, 16, 7, -1, 27, -14, 14, 38, -30, 28, + 49, -44, 41, 60, -55, 52, 70, -66, 62, 81, -76, 72, + 10, 30, -9, 17, 11, 1, 28, -10, 15, 38, -27, 29, + 50, -42, 41, 60, -54, 52, 70, -64, 62, 81, -74, 72, + 12, 32, -6, 18, 15, 3, 28, -7, 17, 39, -24, 30, + 50, -39, 42, 60, -52, 53, 71, -63, 62, 81, -73, 72, + 14, 34, -3, 20, 19, 5, 29, -3, 18, 39, -21, 30, + 50, -37, 42, 61, -50, 53, 71, -61, 63, 81, -72, 72, + 16, 36, -1, 21, 22, 7, 30, 1, 19, 40, -18, 31, + 51, -34, 43, 61, -47, 53, 71, -59, 63, 81, -70, 73, + 18, 38, 2, 22, 25, 9, 31, 5, 20, 41, -14, 32, + 51, -31, 43, 61, -45, 54, 71, -57, 63, 82, -68, 73, + 20, 41, 6, 24, 29, 12, 32, 9, 22, 41, -10, 33, + 52, -27, 44, 62, -42, 54, 72, -54, 64, 82, -66, 73, + 21, 43, 8, 25, 32, 14, 33, 13, 23, 42, -6, 34, + 52, -24, 45, 62, -39, 55, 72, -52, 64, 82, -64, 73, + 23, 45, 11, 27, 35, 16, 34, 17, 25, 43, -2, 35, + 53, -20, 46, 63, -36, 55, 72, -49, 65, 82, -62, 74, + 25, 47, 14, 28, 38, 18, 35, 20, 27, 44, 1, 36, + 53, -17, 46, 63, -33, 56, 73, -47, 65, 83, -60, 74, + 27, 50, 17, 30, 41, 21, 37, 24, 29, 45, 6, 38, + 54, -13, 47, 64, -29, 57, 73, -44, 66, 83, -57, 75, + 29, 52, 20, 32, 44, 23, 38, 28, 30, 46, 9, 39, + 55, -9, 48, 64, -26, 57, 74, -41, 66, 83, -54, 75, + 31, 54, 22, 33, 46, 25, 39, 31, 32, 47, 13, 40, + 56, -6, 49, 65, -22, 58, 74, -38, 67, 84, -52, 76, + 33, 56, 25, 35, 49, 28, 40, 34, 34, 48, 17, 42, + 56, -2, 50, 65, -19, 59, 75, -34, 68, 84, -49, 76, + 34, 58, 28, 37, 52, 30, 42, 38, 36, 49, 21, 43, + 57, 2, 52, 66, -15, 60, 75, -31, 68, 85, -46, 77, + 36, 60, 30, 38, 54, 33, 43, 41, 38, 50, 24, 45, + 58, 6, 53, 67, -12, 61, 76, -28, 69, 85, -43, 77, + 38, 62, 33, 40, 56, 35, 45, 44, 40, 51, 28, 46, + 59, 9, 54, 67, -8, 62, 76, -24, 70, 86, -40, 78, + 40, 64, 35, 42, 59, 37, 46, 47, 41, 52, 31, 48, + 60, 13, 55, 68, -4, 63, 77, -21, 70, 86, -36, 78, + 41, 66, 37, 43, 61, 39, 47, 50, 43, 53, 34, 49, + 61, 16, 56, 69, -1, 64, 78, -17, 71, 87, -33, 79, + 43, 68, 40, 45, 64, 42, 49, 53, 45, 55, 38, 51, + 62, 20, 58, 70, 3, 65, 78, -14, 72, 87, -30, 80, + 45, 70, 42, 47, 66, 44, 50, 55, 47, 56, 41, 52, + 63, 24, 59, 71, 6, 66, 79, -10, 73, 88, -26, 81, + 47, 72, 44, 48, 68, 46, 52, 58, 49, 57, 44, 54, + 64, 27, 60, 72, 10, 67, 80, -7, 74, 88, -23, 81, + 48, 74, 46, 50, 70, 48, 53, 61, 51, 58, 47, 56, + 65, 30, 62, 72, 13, 68, 80, -3, 75, 89, -20, 82, + 50, 76, 49, 52, 73, 50, 55, 63, 53, 60, 50, 57, + 66, 34, 63, 73, 17, 69, 81, 1, 76, 90, -16, 83, + 52, 78, 51, 53, 75, 52, 56, 66, 55, 61, 53, 59, + 67, 37, 64, 74, 21, 70, 82, 4, 77, 90, -13, 84, + 53, 80, 53, 55, 77, 54, 58, 68, 57, 62, 56, 61, + 68, 40, 66, 75, 24, 72, 83, 7, 78, 91, -9, 85, + 3, 12, -28, 13, -7, -12, 25, -25, 7, 37, -38, 22, + 49, -50, 36, 59, -60, 48, 70, -69, 59, 80, -78, 69, + 3, 15, -27, 13, -5, -12, 25, -24, 7, 37, -38, 22, + 49, -49, 36, 59, -59, 48, 70, -69, 59, 80, -78, 69, + 4, 17, -26, 13, -3, -11, 26, -23, 7, 37, -37, 23, + 49, -49, 36, 60, -59, 48, 70, -69, 59, 80, -78, 69, + 5, 20, -24, 14, -1, -10, 26, -21, 8, 37, -35, 23, + 49, -48, 37, 60, -58, 48, 70, -68, 59, 81, -77, 69, + 6, 24, -23, 14, 2, -9, 26, -18, 8, 38, -34, 23, + 49, -46, 37, 60, -57, 49, 70, -67, 59, 81, -77, 69, + 7, 26, -21, 15, 6, -8, 27, -16, 9, 38, -32, 24, + 49, -45, 37, 60, -56, 49, 70, -66, 59, 81, -76, 69, + 9, 29, -18, 16, 9, -6, 27, -13, 10, 38, -29, 24, + 49, -43, 37, 60, -55, 49, 70, -65, 60, 81, -75, 70, + 11, 31, -15, 17, 13, -4, 28, -9, 11, 39, -26, 25, + 50, -41, 38, 60, -53, 49, 71, -64, 60, 81, -74, 70, + 12, 33, -12, 19, 16, -2, 28, -5, 12, 39, -23, 25, + 50, -38, 38, 60, -51, 50, 71, -62, 60, 81, -73, 70, + 14, 35, -9, 20, 20, 0, 29, -2, 13, 40, -20, 26, + 50, -36, 39, 61, -49, 50, 71, -60, 60, 81, -71, 70, + 16, 37, -6, 21, 23, 2, 30, 2, 14, 40, -17, 27, + 51, -33, 39, 61, -47, 50, 71, -59, 61, 81, -70, 70, + 18, 39, -3, 23, 26, 4, 31, 6, 16, 41, -13, 28, + 51, -30, 40, 61, -44, 51, 71, -57, 61, 82, -68, 71, + 20, 42, 0, 24, 30, 6, 32, 10, 17, 42, -9, 29, + 52, -27, 41, 62, -41, 51, 72, -54, 61, 82, -66, 71, + 22, 44, 3, 26, 33, 9, 33, 14, 19, 42, -5, 30, + 52, -23, 41, 62, -38, 52, 72, -52, 62, 82, -64, 71, + 24, 46, 6, 27, 36, 11, 34, 18, 20, 43, -2, 31, + 53, -20, 42, 63, -35, 53, 72, -49, 62, 82, -62, 72, + 25, 48, 9, 29, 38, 13, 35, 21, 22, 44, 2, 32, + 53, -16, 43, 63, -32, 53, 73, -46, 63, 83, -59, 72, + 27, 50, 12, 30, 42, 16, 37, 25, 24, 45, 6, 34, + 54, -12, 44, 64, -29, 54, 73, -43, 63, 83, -57, 73, + 29, 52, 15, 32, 44, 18, 38, 28, 26, 46, 10, 35, + 55, -9, 45, 64, -25, 55, 74, -40, 64, 83, -54, 73, + 31, 54, 17, 34, 47, 21, 39, 32, 28, 47, 14, 36, + 56, -5, 46, 65, -22, 55, 74, -37, 64, 84, -51, 74, + 33, 56, 20, 35, 49, 23, 40, 35, 29, 48, 17, 38, + 56, -2, 47, 65, -19, 56, 75, -34, 65, 84, -49, 74, + 35, 59, 23, 37, 52, 26, 42, 38, 32, 49, 21, 39, + 57, 3, 48, 66, -15, 57, 75, -30, 66, 85, -45, 75, + 36, 61, 25, 38, 54, 28, 43, 41, 33, 50, 25, 41, + 58, 6, 49, 67, -11, 58, 76, -27, 67, 85, -42, 75, + 38, 63, 28, 40, 57, 30, 45, 44, 35, 51, 28, 42, + 59, 10, 51, 68, -8, 59, 76, -24, 67, 86, -39, 76, + 40, 65, 30, 42, 59, 32, 46, 47, 37, 52, 31, 44, + 60, 13, 52, 68, -4, 60, 77, -21, 68, 86, -36, 76, + 41, 67, 33, 43, 61, 35, 47, 50, 39, 53, 35, 45, + 61, 17, 53, 69, -1, 61, 78, -17, 69, 87, -33, 77, + 43, 69, 35, 45, 64, 37, 49, 53, 41, 55, 38, 47, + 62, 21, 55, 70, 3, 62, 78, -13, 70, 87, -29, 78, + 45, 71, 38, 47, 66, 39, 50, 56, 43, 56, 41, 49, + 63, 24, 56, 71, 7, 63, 79, -10, 71, 88, -26, 79, + 47, 73, 40, 48, 68, 41, 52, 58, 45, 57, 44, 50, + 64, 27, 57, 72, 10, 64, 80, -7, 72, 88, -23, 79, + 48, 75, 42, 50, 70, 44, 53, 61, 47, 58, 47, 52, + 65, 31, 59, 72, 14, 65, 80, -3, 73, 89, -20, 80, + 50, 77, 45, 52, 73, 46, 55, 64, 49, 60, 51, 54, + 66, 34, 60, 73, 18, 67, 81, 1, 74, 90, -16, 81, + 52, 79, 47, 53, 75, 48, 56, 66, 51, 61, 53, 56, + 67, 38, 61, 74, 21, 68, 82, 4, 75, 90, -13, 82, + 54, 80, 49, 55, 77, 50, 58, 69, 53, 62, 56, 57, + 68, 41, 63, 75, 24, 69, 83, 8, 76, 91, -9, 83, + 4, 18, -33, 13, -3, -18, 25, -23, 1, 37, -37, 17, + 49, -49, 32, 60, -59, 44, 70, -68, 56, 80, -78, 66, + 4, 20, -32, 13, -1, -17, 26, -21, 1, 37, -36, 18, + 49, -48, 32, 60, -58, 45, 70, -68, 56, 80, -77, 66, + 5, 22, -31, 14, 0, -17, 26, -20, 2, 37, -35, 18, + 49, -47, 32, 60, -58, 45, 70, -68, 56, 80, -77, 67, + 5, 24, -30, 14, 3, -16, 26, -18, 2, 38, -34, 18, + 49, -46, 32, 60, -57, 45, 70, -67, 56, 81, -77, 67, + 6, 27, -28, 15, 5, -15, 26, -16, 3, 38, -32, 18, + 49, -45, 33, 60, -56, 45, 70, -66, 56, 81, -76, 67, + 8, 29, -26, 16, 8, -13, 27, -14, 3, 38, -30, 19, + 49, -44, 33, 60, -55, 45, 70, -66, 56, 81, -75, 67, + 9, 30, -23, 17, 11, -12, 27, -11, 4, 38, -28, 19, + 50, -42, 33, 60, -54, 45, 70, -64, 56, 81, -75, 67, + 11, 32, -20, 18, 15, -10, 28, -7, 5, 39, -25, 20, + 50, -40, 34, 60, -52, 46, 71, -63, 57, 81, -73, 67, + 13, 34, -17, 19, 18, -8, 29, -4, 6, 39, -22, 20, + 50, -37, 34, 61, -50, 46, 71, -62, 57, 81, -72, 67, + 15, 36, -15, 20, 21, -6, 29, 0, 7, 40, -19, 21, + 50, -35, 34, 61, -48, 46, 71, -60, 57, 81, -71, 67, + 16, 38, -12, 21, 24, -4, 30, 4, 9, 40, -15, 22, + 51, -32, 35, 61, -46, 47, 71, -58, 57, 81, -69, 68, + 18, 40, -9, 23, 27, -2, 31, 7, 10, 41, -12, 23, + 51, -29, 36, 61, -43, 47, 71, -56, 58, 82, -67, 68, + 20, 42, -6, 24, 31, 1, 32, 11, 12, 42, -8, 24, + 52, -26, 36, 62, -40, 48, 72, -53, 58, 82, -65, 68, + 22, 44, -3, 26, 34, 3, 33, 15, 13, 42, -4, 25, + 52, -22, 37, 62, -38, 48, 72, -51, 59, 82, -63, 69, + 24, 46, 0, 27, 37, 5, 34, 18, 15, 43, -1, 26, + 53, -19, 38, 63, -35, 49, 72, -48, 59, 82, -61, 69, + 26, 48, 3, 29, 39, 8, 36, 22, 17, 44, 3, 27, + 54, -16, 39, 63, -32, 50, 73, -46, 60, 83, -59, 69, + 28, 51, 6, 31, 42, 10, 37, 26, 19, 45, 7, 29, + 54, -12, 40, 64, -28, 50, 73, -43, 60, 83, -56, 70, + 29, 53, 9, 32, 45, 13, 38, 29, 21, 46, 11, 30, + 55, -8, 41, 64, -25, 51, 74, -40, 61, 83, -54, 70, + 31, 55, 11, 34, 47, 15, 39, 32, 22, 47, 14, 32, + 56, -5, 42, 65, -21, 52, 74, -37, 61, 84, -51, 71, + 33, 57, 14, 35, 50, 17, 41, 35, 24, 48, 18, 33, + 57, -1, 43, 65, -18, 53, 75, -34, 62, 84, -48, 71, + 35, 59, 17, 37, 53, 20, 42, 39, 26, 49, 22, 35, + 57, 3, 44, 66, -14, 54, 75, -30, 63, 85, -45, 72, + 37, 61, 20, 39, 55, 22, 43, 42, 28, 50, 25, 36, + 58, 7, 45, 67, -11, 55, 76, -27, 64, 85, -42, 73, + 38, 63, 22, 40, 57, 25, 45, 45, 30, 51, 28, 38, + 59, 10, 47, 68, -7, 56, 76, -23, 64, 86, -39, 73, + 40, 65, 25, 42, 60, 27, 46, 48, 32, 52, 32, 39, + 60, 14, 48, 68, -4, 57, 77, -20, 65, 86, -36, 74, + 42, 67, 27, 43, 62, 29, 48, 50, 34, 53, 35, 41, + 61, 17, 49, 69, 0, 58, 78, -17, 66, 87, -33, 75, + 44, 69, 30, 45, 64, 32, 49, 53, 36, 55, 39, 43, + 62, 21, 51, 70, 4, 59, 78, -13, 67, 87, -29, 75, + 45, 71, 32, 47, 66, 34, 51, 56, 38, 56, 42, 45, + 63, 24, 52, 71, 7, 60, 79, -10, 68, 88, -26, 76, + 47, 73, 35, 48, 69, 36, 52, 59, 40, 57, 45, 46, + 64, 28, 53, 72, 11, 61, 80, -6, 69, 88, -23, 77, + 49, 75, 37, 50, 71, 39, 53, 61, 42, 58, 48, 48, + 65, 31, 55, 72, 14, 62, 80, -3, 70, 89, -19, 78, + 50, 77, 40, 52, 73, 41, 55, 64, 45, 60, 51, 50, + 66, 35, 56, 73, 18, 63, 81, 1, 71, 90, -16, 79, + 52, 79, 42, 53, 75, 43, 56, 66, 47, 61, 54, 51, + 67, 38, 58, 74, 21, 65, 82, 4, 72, 90, -12, 79, + 54, 81, 44, 55, 77, 45, 58, 69, 49, 62, 56, 53, + 68, 41, 59, 75, 25, 66, 83, 8, 73, 91, -9, 80, + 4, 23, -37, 14, 1, -22, 26, -20, -4, 37, -35, 13, + 49, -47, 28, 60, -58, 41, 70, -68, 53, 80, -77, 64, + 5, 24, -37, 14, 2, -22, 26, -19, -3, 37, -34, 13, + 49, -47, 28, 60, -57, 41, 70, -67, 53, 81, -77, 64, + 5, 26, -36, 14, 4, -21, 26, -18, -3, 38, -33, 13, + 49, -46, 28, 60, -57, 41, 70, -67, 53, 81, -77, 64, + 6, 28, -34, 15, 6, -21, 26, -16, -3, 38, -32, 13, + 49, -45, 28, 60, -56, 41, 70, -66, 53, 81, -76, 64, + 7, 29, -33, 15, 8, -19, 27, -14, -2, 38, -30, 14, + 49, -44, 28, 60, -55, 41, 70, -66, 53, 81, -76, 64, + 9, 31, -30, 16, 11, -18, 27, -11, -2, 38, -28, 14, + 49, -43, 29, 60, -54, 42, 70, -65, 53, 81, -75, 64, + 10, 32, -28, 17, 14, -17, 28, -9, -1, 38, -26, 15, + 50, -41, 29, 60, -53, 42, 70, -64, 53, 81, -74, 64, + 12, 34, -25, 18, 17, -15, 28, -5, 0, 39, -23, 15, + 50, -39, 30, 60, -51, 42, 71, -62, 54, 81, -73, 64, + 13, 36, -22, 19, 20, -13, 29, -2, 1, 39, -20, 16, + 50, -36, 30, 61, -49, 42, 71, -61, 54, 81, -72, 65, + 15, 37, -19, 20, 23, -11, 30, 1, 3, 40, -17, 17, + 51, -34, 30, 61, -47, 43, 71, -59, 54, 81, -70, 65, + 17, 39, -17, 22, 26, -9, 31, 5, 4, 40, -14, 18, + 51, -31, 31, 61, -45, 43, 71, -57, 54, 81, -69, 65, + 19, 41, -14, 23, 29, -7, 31, 8, 5, 41, -11, 18, + 51, -28, 32, 62, -43, 44, 72, -55, 55, 82, -67, 65, + 21, 43, -11, 25, 32, -4, 32, 12, 7, 42, -7, 20, + 52, -25, 32, 62, -40, 44, 72, -53, 55, 82, -65, 66, + 22, 45, -8, 26, 35, -2, 34, 16, 9, 43, -3, 21, + 52, -22, 33, 62, -37, 45, 72, -50, 56, 82, -63, 66, + 24, 47, -5, 28, 37, 0, 35, 19, 10, 43, 0, 22, + 53, -18, 34, 63, -34, 45, 73, -48, 56, 82, -61, 66, + 26, 49, -2, 29, 40, 3, 36, 23, 12, 44, 4, 23, + 54, -15, 35, 63, -31, 46, 73, -45, 57, 83, -58, 67, + 28, 51, 1, 31, 43, 5, 37, 27, 14, 45, 8, 25, + 54, -11, 36, 64, -27, 47, 73, -42, 57, 83, -56, 67, + 30, 53, 4, 32, 45, 8, 38, 30, 16, 46, 11, 26, + 55, -7, 37, 64, -24, 48, 74, -39, 58, 84, -53, 68, + 31, 55, 6, 34, 48, 10, 39, 33, 18, 47, 15, 27, + 56, -4, 38, 65, -21, 48, 74, -36, 58, 84, -50, 68, + 33, 57, 9, 35, 50, 12, 41, 36, 20, 48, 18, 29, + 57, 0, 39, 66, -17, 49, 75, -33, 59, 84, -48, 69, + 35, 60, 12, 37, 53, 15, 42, 39, 22, 49, 22, 30, + 58, 4, 40, 66, -14, 50, 75, -30, 60, 85, -44, 69, + 37, 61, 15, 39, 55, 18, 44, 42, 24, 50, 26, 32, + 58, 7, 42, 67, -10, 51, 76, -26, 61, 85, -41, 70, + 38, 63, 17, 40, 58, 20, 45, 45, 26, 51, 29, 34, + 59, 11, 43, 68, -7, 52, 76, -23, 61, 86, -38, 71, + 40, 65, 20, 42, 60, 22, 46, 48, 28, 52, 32, 35, + 60, 14, 44, 68, -3, 53, 77, -20, 62, 86, -35, 71, + 42, 67, 22, 44, 62, 25, 48, 51, 30, 54, 35, 37, + 61, 18, 45, 69, 0, 54, 78, -16, 63, 87, -32, 72, + 44, 69, 25, 45, 65, 27, 49, 54, 32, 55, 39, 39, + 62, 21, 47, 70, 4, 55, 78, -13, 64, 87, -29, 73, + 45, 71, 28, 47, 67, 30, 51, 56, 34, 56, 42, 40, + 63, 25, 48, 71, 8, 57, 79, -9, 65, 88, -25, 74, + 47, 73, 30, 48, 69, 32, 52, 59, 36, 57, 45, 42, + 64, 28, 50, 72, 11, 58, 80, -6, 66, 88, -22, 74, + 49, 75, 32, 50, 71, 34, 53, 61, 38, 59, 48, 44, + 65, 31, 51, 73, 14, 59, 81, -2, 67, 89, -19, 75, + 50, 77, 35, 52, 73, 37, 55, 64, 40, 60, 51, 46, + 66, 35, 53, 74, 18, 60, 81, 1, 68, 90, -15, 76, + 52, 79, 37, 53, 75, 39, 57, 67, 42, 61, 54, 48, + 67, 38, 54, 74, 22, 61, 82, 5, 69, 90, -12, 77, + 54, 81, 40, 55, 77, 41, 58, 69, 44, 62, 57, 49, + 69, 41, 56, 75, 25, 63, 83, 8, 70, 91, -9, 78, + 5, 27, -42, 14, 5, -27, 26, -17, -9, 37, -33, 8, + 49, -46, 24, 60, -57, 37, 70, -67, 49, 81, -76, 61, + 6, 28, -41, 14, 6, -27, 26, -16, -8, 38, -32, 8, + 49, -45, 24, 60, -56, 37, 70, -66, 49, 81, -76, 61, + 6, 29, -40, 15, 7, -26, 26, -15, -8, 38, -31, 9, + 49, -45, 24, 60, -56, 37, 70, -66, 49, 81, -76, 61, + 7, 31, -38, 15, 9, -25, 27, -13, -8, 38, -30, 9, + 49, -44, 24, 60, -55, 37, 70, -66, 50, 81, -75, 61, + 8, 32, -37, 16, 11, -24, 27, -11, -7, 38, -28, 9, + 49, -43, 24, 60, -54, 38, 70, -65, 50, 81, -75, 61, + 9, 33, -35, 17, 13, -23, 27, -9, -6, 38, -27, 10, + 50, -41, 25, 60, -53, 38, 70, -64, 50, 81, -74, 61, + 11, 34, -32, 18, 16, -22, 28, -6, -6, 39, -24, 10, + 50, -39, 25, 60, -52, 38, 71, -63, 50, 81, -73, 61, + 12, 36, -29, 19, 19, -20, 29, -3, -5, 39, -22, 11, + 50, -37, 25, 60, -50, 38, 71, -61, 50, 81, -72, 62, + 14, 37, -27, 20, 22, -18, 29, 0, -3, 40, -19, 11, + 50, -35, 26, 61, -48, 39, 71, -60, 50, 81, -71, 62, + 16, 39, -24, 21, 24, -16, 30, 3, -2, 40, -16, 12, + 51, -33, 26, 61, -46, 39, 71, -58, 51, 81, -69, 62, + 17, 41, -21, 22, 27, -14, 31, 7, -1, 41, -13, 13, + 51, -30, 27, 61, -44, 39, 71, -56, 51, 82, -68, 62, + 19, 42, -19, 23, 30, -12, 32, 10, 0, 41, -10, 14, + 52, -27, 28, 62, -42, 40, 72, -54, 51, 82, -66, 62, + 21, 44, -15, 25, 33, -9, 33, 14, 2, 42, -6, 15, + 52, -24, 28, 62, -39, 41, 72, -52, 52, 82, -64, 63, + 23, 46, -13, 26, 36, -7, 34, 17, 4, 43, -2, 16, + 53, -21, 29, 62, -36, 41, 72, -50, 52, 82, -62, 63, + 24, 48, -10, 28, 38, -5, 35, 20, 5, 43, 1, 17, + 53, -17, 30, 63, -33, 42, 73, -47, 53, 83, -60, 64, + 26, 50, -7, 29, 41, -2, 36, 24, 7, 44, 5, 19, + 54, -14, 31, 63, -30, 42, 73, -45, 53, 83, -58, 64, + 28, 52, -4, 31, 44, 0, 37, 27, 9, 45, 9, 20, + 55, -10, 32, 64, -27, 43, 73, -41, 54, 83, -55, 64, + 30, 54, -1, 33, 46, 3, 38, 31, 11, 46, 12, 21, + 55, -7, 33, 64, -23, 44, 74, -39, 55, 84, -52, 65, + 32, 56, 1, 34, 49, 5, 40, 34, 13, 47, 16, 23, + 56, -3, 34, 65, -20, 45, 74, -36, 55, 84, -50, 65, + 33, 58, 4, 36, 51, 8, 41, 37, 15, 48, 19, 24, + 57, 0, 35, 66, -17, 46, 75, -32, 56, 84, -47, 66, + 35, 60, 7, 37, 54, 10, 42, 40, 17, 49, 23, 26, + 58, 4, 36, 66, -13, 47, 75, -29, 57, 85, -44, 67, + 37, 62, 10, 39, 56, 13, 44, 43, 19, 50, 26, 28, + 58, 8, 38, 67, -10, 48, 76, -26, 57, 85, -41, 67, + 39, 64, 12, 41, 58, 15, 45, 46, 21, 51, 30, 29, + 59, 11, 39, 68, -6, 49, 77, -23, 58, 86, -38, 68, + 40, 66, 15, 42, 60, 17, 46, 49, 23, 53, 33, 31, + 60, 15, 40, 68, -3, 50, 77, -19, 59, 86, -35, 69, + 42, 68, 18, 44, 63, 20, 48, 51, 25, 54, 36, 33, + 61, 18, 42, 69, 1, 51, 78, -16, 60, 87, -32, 69, + 44, 70, 20, 45, 65, 23, 49, 54, 27, 55, 39, 34, + 62, 22, 43, 70, 5, 52, 78, -12, 61, 87, -28, 70, + 45, 72, 23, 47, 67, 25, 51, 57, 30, 56, 42, 36, + 63, 25, 44, 71, 8, 53, 79, -9, 62, 88, -25, 71, + 47, 74, 25, 49, 69, 27, 52, 59, 32, 57, 45, 38, + 64, 29, 46, 72, 11, 54, 80, -5, 63, 89, -22, 72, + 49, 75, 28, 50, 71, 30, 54, 62, 34, 59, 48, 40, + 65, 32, 47, 73, 15, 55, 81, -2, 64, 89, -19, 72, + 51, 78, 30, 52, 74, 32, 55, 65, 36, 60, 52, 42, + 66, 35, 49, 74, 19, 57, 81, 2, 65, 90, -15, 73, + 52, 79, 33, 54, 76, 34, 57, 67, 38, 61, 54, 43, + 68, 39, 50, 75, 22, 58, 82, 5, 66, 91, -12, 74, + 54, 81, 35, 55, 78, 37, 58, 69, 40, 63, 57, 45, + 69, 42, 52, 75, 25, 59, 83, 9, 67, 91, -8, 75, + 6, 31, -45, 15, 9, -31, 26, -14, -13, 38, -30, 4, + 49, -44, 19, 60, -55, 33, 70, -66, 46, 81, -76, 58, + 7, 32, -45, 15, 10, -31, 26, -13, -13, 38, -30, 4, + 49, -44, 20, 60, -55, 33, 70, -65, 46, 81, -75, 58, + 7, 32, -44, 15, 11, -30, 27, -12, -13, 38, -29, 4, + 49, -43, 20, 60, -55, 33, 70, -65, 46, 81, -75, 58, + 8, 33, -42, 16, 12, -30, 27, -10, -12, 38, -28, 4, + 49, -42, 20, 60, -54, 34, 70, -65, 46, 81, -75, 58, + 9, 34, -41, 16, 14, -29, 27, -9, -12, 38, -26, 5, + 49, -41, 20, 60, -53, 34, 70, -64, 46, 81, -74, 58, + 10, 35, -39, 17, 16, -27, 28, -6, -11, 39, -25, 5, + 50, -40, 20, 60, -52, 34, 71, -63, 46, 81, -73, 58, + 12, 36, -36, 18, 18, -26, 28, -4, -10, 39, -22, 5, + 50, -38, 21, 60, -51, 34, 71, -62, 47, 81, -72, 58, + 13, 37, -34, 19, 21, -24, 29, -1, -9, 39, -20, 6, + 50, -36, 21, 61, -49, 34, 71, -60, 47, 81, -71, 58, + 15, 39, -31, 20, 24, -23, 29, 2, -8, 40, -17, 7, + 50, -34, 22, 61, -47, 35, 71, -59, 47, 81, -70, 59, + 16, 40, -29, 21, 26, -21, 30, 5, -7, 40, -14, 8, + 51, -31, 22, 61, -45, 35, 71, -57, 47, 81, -69, 59, + 18, 42, -26, 23, 29, -19, 31, 8, -6, 41, -11, 8, + 51, -29, 23, 61, -43, 36, 71, -56, 48, 82, -67, 59, + 20, 44, -23, 24, 31, -17, 32, 11, -4, 41, -8, 9, + 52, -26, 23, 62, -41, 36, 72, -54, 48, 82, -66, 59, + 21, 46, -20, 25, 34, -14, 33, 15, -3, 42, -4, 11, + 52, -23, 24, 62, -38, 37, 72, -51, 48, 82, -63, 60, + 23, 47, -17, 27, 37, -12, 34, 18, -1, 43, -1, 12, + 53, -19, 25, 63, -35, 37, 72, -49, 49, 82, -61, 60, + 25, 49, -15, 28, 39, -10, 35, 22, 1, 44, 2, 13, + 53, -16, 26, 63, -32, 38, 73, -46, 49, 83, -59, 60, + 26, 51, -12, 30, 42, -7, 36, 25, 2, 44, 6, 14, + 54, -13, 27, 63, -29, 39, 73, -44, 50, 83, -57, 61, + 28, 53, -9, 31, 45, -5, 37, 28, 4, 45, 10, 16, + 55, -9, 28, 64, -26, 39, 73, -41, 51, 83, -54, 61, + 30, 55, -6, 33, 47, -2, 39, 32, 6, 46, 13, 17, + 55, -6, 29, 65, -23, 40, 74, -38, 51, 84, -52, 62, + 32, 57, -3, 34, 49, 0, 40, 35, 8, 47, 17, 18, + 56, -2, 30, 65, -19, 41, 74, -35, 52, 84, -49, 62, + 33, 59, -1, 36, 52, 3, 41, 38, 10, 48, 20, 20, + 57, 1, 31, 66, -16, 42, 75, -32, 52, 84, -47, 63, + 35, 61, 2, 38, 54, 5, 43, 41, 12, 49, 24, 22, + 58, 5, 32, 66, -12, 43, 75, -28, 53, 85, -43, 64, + 37, 63, 5, 39, 57, 8, 44, 44, 14, 50, 27, 23, + 59, 8, 34, 67, -9, 44, 76, -25, 54, 85, -40, 64, + 39, 64, 8, 41, 59, 10, 45, 46, 16, 52, 30, 25, + 59, 12, 35, 68, -6, 45, 77, -22, 55, 86, -37, 65, + 40, 66, 10, 42, 61, 13, 47, 49, 18, 53, 33, 27, + 60, 15, 36, 69, -2, 46, 77, -19, 56, 86, -34, 66, + 42, 68, 13, 44, 63, 15, 48, 52, 21, 54, 37, 28, + 61, 19, 37, 69, 1, 47, 78, -15, 57, 87, -31, 66, + 44, 70, 16, 46, 66, 18, 49, 55, 23, 55, 40, 30, + 62, 22, 39, 70, 5, 48, 79, -12, 58, 87, -28, 67, + 46, 72, 18, 47, 68, 20, 51, 57, 25, 56, 43, 32, + 63, 26, 40, 71, 9, 49, 79, -8, 59, 88, -25, 68, + 47, 74, 21, 49, 70, 23, 52, 60, 27, 58, 46, 34, + 64, 29, 42, 72, 12, 51, 80, -5, 59, 89, -21, 69, + 49, 76, 23, 50, 72, 25, 54, 62, 29, 59, 49, 35, + 65, 32, 43, 73, 15, 52, 81, -2, 60, 89, -18, 69, + 51, 78, 26, 52, 74, 27, 55, 65, 32, 60, 52, 37, + 67, 36, 45, 74, 19, 53, 81, 2, 62, 90, -14, 70, + 52, 80, 28, 54, 76, 30, 57, 67, 34, 61, 55, 39, + 68, 39, 47, 75, 22, 54, 82, 6, 63, 91, -11, 71, + 54, 82, 31, 55, 78, 32, 58, 70, 36, 63, 58, 41, + 69, 42, 48, 76, 26, 56, 83, 9, 64, 91, -8, 72, + 7, 34, -49, 15, 13, -36, 27, -11, -18, 38, -28, -1, + 49, -42, 15, 60, -54, 29, 70, -65, 42, 81, -75, 54, + 8, 35, -48, 16, 13, -35, 27, -10, -18, 38, -27, -1, + 49, -42, 15, 60, -54, 29, 70, -64, 42, 81, -74, 54, + 8, 35, -47, 16, 14, -35, 27, -9, -17, 38, -27, -1, + 49, -41, 15, 60, -53, 29, 70, -64, 42, 81, -74, 55, + 9, 36, -46, 17, 16, -34, 27, -7, -17, 38, -25, 0, + 49, -40, 16, 60, -53, 30, 70, -63, 42, 81, -74, 55, + 10, 36, -44, 17, 17, -33, 28, -6, -16, 38, -24, 0, + 50, -39, 16, 60, -52, 30, 70, -63, 43, 81, -73, 55, + 11, 37, -43, 18, 19, -32, 28, -4, -16, 39, -22, 0, + 50, -38, 16, 60, -51, 30, 71, -62, 43, 81, -72, 55, + 12, 38, -41, 19, 21, -31, 29, -2, -15, 39, -20, 1, + 50, -36, 16, 60, -49, 30, 71, -61, 43, 81, -72, 55, + 14, 39, -38, 20, 23, -29, 29, 1, -14, 39, -18, 2, + 50, -34, 17, 61, -48, 30, 71, -59, 43, 81, -70, 55, + 15, 41, -36, 21, 26, -27, 30, 4, -13, 40, -15, 2, + 51, -32, 17, 61, -46, 31, 71, -58, 43, 81, -69, 55, + 17, 42, -33, 22, 28, -25, 31, 7, -12, 40, -13, 3, + 51, -30, 18, 61, -44, 31, 71, -56, 44, 81, -68, 56, + 18, 43, -31, 23, 31, -23, 31, 10, -10, 41, -10, 4, + 51, -27, 18, 61, -42, 32, 72, -55, 44, 82, -66, 56, + 20, 45, -28, 24, 33, -21, 32, 13, -9, 42, -7, 5, + 52, -25, 19, 62, -40, 32, 72, -53, 44, 82, -65, 56, + 22, 47, -25, 26, 36, -19, 33, 17, -7, 42, -3, 6, + 52, -21, 20, 62, -37, 33, 72, -50, 45, 82, -63, 56, + 24, 48, -22, 27, 38, -17, 34, 20, -6, 43, 0, 7, + 53, -18, 21, 63, -34, 33, 72, -48, 45, 82, -61, 57, + 25, 50, -19, 28, 41, -14, 35, 23, -4, 44, 4, 8, + 53, -15, 21, 63, -31, 34, 73, -45, 46, 83, -59, 57, + 27, 52, -17, 30, 43, -12, 36, 26, -2, 45, 7, 10, + 54, -12, 22, 64, -28, 35, 73, -43, 46, 83, -56, 58, + 29, 54, -14, 32, 46, -9, 38, 30, 0, 46, 11, 11, + 55, -8, 23, 64, -25, 35, 74, -40, 47, 83, -54, 58, + 30, 56, -11, 33, 48, -7, 39, 33, 2, 46, 14, 12, + 55, -5, 25, 65, -22, 36, 74, -37, 48, 84, -51, 59, + 32, 57, -8, 35, 50, -4, 40, 35, 4, 47, 18, 14, + 56, -1, 26, 65, -19, 37, 74, -34, 48, 84, -49, 59, + 34, 59, -6, 36, 53, -2, 41, 38, 5, 48, 21, 15, + 57, 2, 27, 66, -15, 38, 75, -31, 49, 84, -46, 60, + 36, 61, -3, 38, 55, 1, 43, 42, 8, 50, 25, 17, + 58, 6, 28, 67, -12, 39, 76, -28, 50, 85, -43, 60, + 37, 63, 0, 39, 57, 3, 44, 44, 10, 51, 28, 19, + 59, 9, 29, 67, -8, 40, 76, -24, 51, 85, -40, 61, + 39, 65, 3, 41, 59, 6, 45, 47, 12, 52, 31, 20, + 60, 13, 31, 68, -5, 41, 77, -21, 51, 86, -37, 62, + 41, 67, 5, 42, 62, 8, 47, 50, 14, 53, 34, 22, + 60, 16, 32, 69, -1, 42, 77, -18, 52, 86, -34, 62, + 42, 69, 8, 44, 64, 10, 48, 52, 16, 54, 37, 24, + 61, 19, 33, 69, 2, 43, 78, -15, 53, 87, -31, 63, + 44, 71, 11, 46, 66, 13, 50, 55, 18, 55, 41, 26, + 62, 23, 35, 70, 6, 44, 79, -11, 54, 87, -27, 64, + 46, 73, 13, 47, 68, 15, 51, 58, 20, 56, 44, 27, + 63, 26, 36, 71, 9, 46, 79, -8, 55, 88, -24, 65, + 47, 74, 16, 49, 70, 18, 52, 60, 23, 58, 46, 29, + 64, 30, 38, 72, 12, 47, 80, -4, 56, 89, -21, 66, + 49, 76, 18, 50, 72, 20, 54, 63, 25, 59, 49, 31, + 65, 33, 39, 73, 16, 48, 81, -1, 57, 89, -18, 66, + 51, 78, 21, 52, 74, 23, 55, 65, 27, 60, 52, 33, + 67, 36, 41, 74, 20, 49, 82, 3, 58, 90, -14, 67, + 53, 80, 24, 54, 76, 25, 57, 68, 29, 61, 55, 35, + 68, 39, 43, 75, 23, 51, 82, 6, 59, 91, -11, 68, + 54, 82, 26, 55, 78, 27, 58, 70, 31, 63, 58, 37, + 69, 42, 44, 76, 26, 52, 83, 9, 60, 91, -7, 69, + 9, 37, -53, 16, 17, -40, 27, -7, -23, 38, -25, -6, + 49, -40, 10, 60, -52, 25, 70, -63, 38, 81, -74, 51, + 9, 37, -52, 17, 17, -40, 27, -6, -23, 38, -24, -6, + 49, -40, 10, 60, -52, 25, 70, -63, 38, 81, -73, 51, + 10, 38, -51, 17, 18, -39, 27, -5, -22, 38, -24, -6, + 50, -39, 10, 60, -52, 25, 70, -63, 38, 81, -73, 51, + 11, 38, -50, 17, 19, -39, 28, -4, -22, 39, -23, -5, + 50, -38, 11, 60, -51, 25, 71, -62, 38, 81, -73, 51, + 11, 39, -48, 18, 21, -38, 28, -2, -21, 39, -21, -5, + 50, -37, 11, 60, -50, 25, 71, -61, 38, 81, -72, 51, + 12, 39, -47, 19, 22, -37, 28, -1, -21, 39, -20, -5, + 50, -36, 11, 60, -49, 25, 71, -61, 38, 81, -71, 51, + 13, 40, -45, 19, 24, -35, 29, 1, -20, 39, -18, -4, + 50, -34, 11, 61, -48, 26, 71, -60, 39, 81, -70, 51, + 15, 41, -43, 20, 26, -34, 30, 4, -19, 40, -15, -4, + 51, -32, 12, 61, -46, 26, 71, -58, 39, 81, -69, 51, + 16, 43, -40, 21, 28, -32, 30, 7, -18, 40, -13, -3, + 51, -30, 12, 61, -44, 26, 71, -57, 39, 81, -68, 51, + 18, 44, -38, 22, 30, -30, 31, 9, -17, 41, -10, -2, + 51, -28, 13, 61, -42, 27, 71, -55, 39, 82, -67, 52, + 19, 45, -35, 24, 33, -28, 32, 12, -16, 41, -8, -1, + 52, -25, 13, 62, -40, 27, 72, -53, 40, 82, -65, 52, + 21, 46, -33, 25, 35, -26, 33, 15, -14, 42, -5, 0, + 52, -23, 14, 62, -38, 28, 72, -51, 40, 82, -64, 52, + 22, 48, -30, 26, 37, -24, 34, 19, -13, 43, -1, 1, + 53, -20, 15, 62, -35, 28, 72, -49, 41, 82, -62, 53, + 24, 50, -27, 28, 40, -22, 35, 22, -11, 43, 2, 2, + 53, -17, 16, 63, -33, 29, 73, -47, 41, 82, -60, 53, + 26, 51, -25, 29, 42, -19, 36, 25, -9, 44, 5, 3, + 54, -14, 17, 63, -30, 29, 73, -44, 42, 83, -58, 53, + 27, 53, -22, 30, 44, -17, 37, 28, -8, 45, 8, 4, + 54, -11, 18, 64, -27, 30, 73, -42, 42, 83, -55, 54, + 29, 55, -19, 32, 47, -15, 38, 31, -5, 46, 12, 6, + 55, -7, 19, 64, -24, 31, 74, -39, 43, 83, -53, 54, + 31, 57, -16, 33, 49, -12, 39, 34, -4, 47, 15, 7, + 56, -4, 20, 65, -21, 32, 74, -36, 43, 84, -50, 55, + 32, 58, -14, 35, 51, -10, 40, 37, -2, 48, 19, 9, + 56, 0, 21, 65, -17, 33, 75, -33, 44, 84, -48, 55, + 34, 60, -11, 36, 53, -7, 42, 39, 0, 49, 22, 10, + 57, 3, 22, 66, -14, 33, 75, -30, 45, 85, -45, 56, + 36, 62, -8, 38, 56, -5, 43, 43, 2, 50, 26, 12, + 58, 7, 23, 67, -11, 35, 76, -27, 46, 85, -42, 57, + 38, 64, -5, 40, 58, -2, 44, 45, 5, 51, 29, 14, + 59, 10, 25, 67, -7, 36, 76, -24, 46, 85, -39, 57, + 39, 66, -3, 41, 60, 0, 46, 48, 7, 52, 32, 15, + 60, 14, 26, 68, -4, 37, 77, -20, 47, 86, -36, 58, + 41, 68, 0, 43, 62, 3, 47, 51, 9, 53, 35, 17, + 61, 17, 27, 69, -1, 38, 77, -17, 48, 86, -33, 59, + 43, 69, 3, 44, 64, 5, 48, 53, 11, 54, 38, 19, + 61, 20, 29, 70, 3, 39, 78, -14, 49, 87, -30, 59, + 44, 71, 5, 46, 67, 8, 50, 56, 13, 55, 41, 21, + 63, 24, 30, 70, 7, 40, 79, -10, 50, 88, -27, 60, + 46, 73, 8, 48, 69, 10, 51, 59, 15, 57, 44, 23, + 64, 27, 32, 71, 10, 41, 79, -7, 51, 88, -23, 61, + 48, 75, 11, 49, 71, 13, 53, 61, 17, 58, 47, 24, + 65, 30, 33, 72, 13, 42, 80, -4, 52, 89, -20, 62, + 49, 77, 13, 51, 73, 15, 54, 63, 20, 59, 50, 26, + 66, 33, 35, 73, 16, 44, 81, 0, 53, 89, -17, 63, + 51, 79, 16, 52, 75, 18, 56, 66, 22, 60, 53, 28, + 67, 37, 36, 74, 20, 45, 82, 3, 54, 90, -13, 64, + 53, 81, 18, 54, 77, 20, 57, 68, 24, 62, 56, 30, + 68, 40, 38, 75, 23, 46, 82, 7, 55, 91, -10, 65, + 54, 82, 21, 56, 79, 22, 58, 71, 26, 63, 58, 32, + 69, 43, 39, 76, 27, 48, 83, 10, 56, 91, -7, 65, + 10, 40, -56, 17, 20, -44, 28, -3, -27, 38, -22, -11, + 50, -38, 6, 60, -51, 21, 70, -62, 34, 81, -72, 47, + 11, 40, -55, 17, 21, -44, 28, -3, -27, 39, -22, -10, + 50, -37, 6, 60, -50, 21, 71, -62, 34, 81, -72, 47, + 11, 40, -54, 18, 21, -43, 28, -2, -27, 39, -21, -10, + 50, -37, 6, 60, -50, 21, 71, -61, 34, 81, -72, 47, + 12, 41, -53, 18, 22, -43, 28, -1, -26, 39, -20, -10, + 50, -36, 6, 60, -49, 21, 71, -61, 34, 81, -71, 47, + 12, 41, -52, 19, 24, -42, 28, 1, -26, 39, -19, -10, + 50, -35, 6, 60, -48, 21, 71, -60, 34, 81, -71, 47, + 13, 42, -50, 19, 25, -41, 29, 2, -25, 39, -17, -9, + 50, -34, 7, 61, -47, 21, 71, -59, 35, 81, -70, 47, + 14, 42, -49, 20, 27, -40, 29, 4, -25, 40, -15, -9, + 50, -32, 7, 61, -46, 21, 71, -58, 35, 81, -69, 48, + 16, 43, -46, 21, 29, -38, 30, 7, -24, 40, -13, -8, + 51, -30, 8, 61, -45, 22, 71, -57, 35, 81, -68, 48, + 17, 44, -44, 22, 30, -36, 31, 9, -22, 40, -11, -7, + 51, -28, 8, 61, -43, 22, 71, -55, 35, 81, -67, 48, + 18, 45, -42, 23, 32, -35, 31, 12, -21, 41, -8, -7, + 51, -26, 9, 61, -41, 22, 71, -54, 36, 82, -66, 48, + 20, 47, -40, 24, 35, -33, 32, 14, -20, 41, -6, -6, + 52, -24, 9, 62, -39, 23, 72, -52, 36, 82, -64, 48, + 21, 48, -37, 25, 37, -31, 33, 17, -19, 42, -3, -5, + 52, -21, 10, 62, -37, 23, 72, -50, 36, 82, -63, 49, + 23, 50, -34, 27, 39, -28, 34, 20, -17, 43, 1, -4, + 53, -18, 11, 62, -34, 24, 72, -48, 37, 82, -61, 49, + 25, 51, -32, 28, 41, -26, 35, 23, -15, 43, 4, -3, + 53, -15, 11, 63, -31, 25, 73, -46, 37, 83, -59, 49, + 26, 53, -29, 29, 43, -24, 36, 26, -14, 44, 7, -1, + 54, -12, 12, 63, -29, 25, 73, -43, 38, 83, -57, 50, + 28, 54, -26, 31, 46, -22, 37, 29, -12, 45, 10, 0, + 54, -9, 13, 64, -26, 26, 73, -41, 38, 83, -55, 50, + 30, 56, -23, 32, 48, -19, 38, 32, -10, 46, 13, 1, + 55, -6, 14, 64, -23, 27, 74, -38, 39, 84, -52, 51, + 31, 58, -21, 34, 50, -17, 39, 35, -8, 47, 17, 3, + 56, -2, 15, 65, -20, 28, 74, -35, 40, 84, -49, 51, + 33, 59, -18, 35, 52, -14, 41, 38, -6, 48, 20, 4, + 56, 1, 16, 65, -16, 29, 75, -32, 40, 84, -47, 52, + 34, 61, -15, 37, 54, -12, 42, 40, -4, 49, 23, 6, + 57, 4, 18, 66, -13, 29, 75, -29, 41, 85, -44, 52, + 36, 63, -13, 38, 57, -9, 43, 44, -2, 50, 27, 8, + 58, 8, 19, 67, -10, 30, 76, -26, 42, 85, -41, 53, + 38, 65, -10, 40, 59, -7, 45, 46, 0, 51, 30, 9, + 59, 11, 20, 67, -6, 31, 76, -23, 43, 86, -38, 54, + 40, 66, -7, 41, 61, -4, 46, 49, 2, 52, 33, 11, + 60, 14, 22, 68, -3, 32, 77, -20, 43, 86, -35, 54, + 41, 68, -5, 43, 63, -2, 47, 51, 4, 53, 36, 13, + 61, 18, 23, 69, 0, 34, 77, -16, 44, 87, -32, 55, + 43, 70, -2, 45, 65, 0, 48, 54, 6, 54, 39, 14, + 62, 21, 24, 70, 4, 35, 78, -13, 45, 87, -29, 56, + 45, 72, 1, 46, 67, 3, 50, 57, 9, 56, 42, 16, + 63, 25, 26, 70, 7, 36, 79, -10, 46, 88, -26, 57, + 46, 74, 3, 48, 69, 6, 51, 59, 11, 57, 45, 18, + 64, 28, 27, 71, 11, 37, 79, -6, 47, 88, -23, 58, + 48, 76, 6, 49, 71, 8, 53, 62, 13, 58, 48, 20, + 65, 31, 29, 72, 14, 38, 80, -3, 48, 89, -20, 58, + 49, 77, 8, 51, 73, 10, 54, 64, 15, 59, 51, 22, + 66, 34, 30, 73, 17, 40, 81, 0, 49, 89, -16, 59, + 51, 79, 11, 53, 76, 13, 56, 67, 17, 61, 54, 24, + 67, 38, 32, 74, 21, 41, 82, 4, 50, 90, -13, 60, + 53, 81, 14, 54, 77, 15, 57, 69, 20, 62, 56, 26, + 68, 41, 34, 75, 24, 42, 82, 7, 52, 91, -10, 61, + 54, 83, 16, 56, 79, 18, 59, 71, 22, 63, 59, 28, + 69, 44, 35, 76, 27, 44, 83, 10, 53, 91, -6, 62, + 11, 42, -59, 18, 24, -48, 28, 0, -32, 39, -19, -15, + 50, -36, 1, 60, -49, 16, 71, -60, 30, 81, -71, 43, + 12, 42, -58, 18, 24, -48, 28, 1, -31, 39, -19, -15, + 50, -35, 2, 60, -49, 16, 71, -60, 30, 81, -71, 43, + 12, 42, -58, 18, 25, -47, 28, 1, -31, 39, -18, -15, + 50, -35, 2, 60, -48, 17, 71, -60, 30, 81, -71, 43, + 13, 43, -57, 19, 26, -47, 29, 2, -31, 39, -17, -14, + 50, -34, 2, 61, -47, 17, 71, -59, 30, 81, -70, 44, + 14, 43, -55, 19, 27, -46, 29, 4, -30, 39, -16, -14, + 50, -33, 2, 61, -47, 17, 71, -59, 31, 81, -70, 44, + 14, 44, -54, 20, 28, -45, 29, 5, -30, 40, -15, -14, + 50, -32, 2, 61, -46, 17, 71, -58, 31, 81, -69, 44, + 15, 44, -52, 21, 29, -44, 30, 7, -29, 40, -13, -13, + 51, -30, 3, 61, -44, 17, 71, -57, 31, 81, -68, 44, + 17, 45, -50, 22, 31, -42, 30, 9, -28, 40, -11, -13, + 51, -28, 3, 61, -43, 18, 71, -55, 31, 81, -67, 44, + 18, 46, -48, 23, 33, -40, 31, 12, -27, 41, -9, -12, + 51, -26, 4, 61, -41, 18, 71, -54, 31, 82, -66, 44, + 19, 47, -46, 24, 35, -39, 32, 14, -26, 41, -6, -11, + 52, -24, 4, 62, -39, 18, 72, -53, 32, 82, -65, 45, + 21, 48, -44, 25, 37, -37, 32, 17, -25, 42, -4, -10, + 52, -22, 5, 62, -37, 19, 72, -51, 32, 82, -63, 45, + 22, 50, -41, 26, 38, -35, 33, 19, -23, 42, -1, -9, + 52, -20, 5, 62, -35, 19, 72, -49, 32, 82, -62, 45, + 24, 51, -38, 27, 41, -33, 34, 22, -22, 43, 2, -8, + 53, -17, 6, 63, -33, 20, 72, -47, 33, 82, -60, 45, + 25, 52, -36, 28, 43, -31, 35, 25, -20, 44, 5, -7, + 53, -14, 7, 63, -30, 20, 73, -44, 33, 83, -58, 46, + 27, 54, -33, 30, 45, -28, 36, 28, -18, 45, 8, -6, + 54, -11, 8, 63, -27, 21, 73, -42, 34, 83, -56, 46, + 28, 55, -31, 31, 47, -26, 37, 30, -17, 45, 11, -5, + 55, -8, 9, 64, -25, 22, 73, -40, 34, 83, -54, 47, + 30, 57, -28, 33, 49, -24, 39, 33, -15, 46, 15, -3, + 55, -4, 10, 64, -21, 23, 74, -37, 35, 84, -51, 47, + 32, 59, -25, 34, 51, -21, 40, 36, -13, 47, 18, -2, + 56, -1, 11, 65, -18, 24, 74, -34, 36, 84, -49, 48, + 33, 60, -23, 36, 53, -19, 41, 39, -11, 48, 21, 0, + 57, 2, 12, 66, -15, 24, 75, -31, 36, 84, -46, 48, + 35, 62, -20, 37, 55, -17, 42, 42, -9, 49, 24, 1, + 57, 5, 13, 66, -12, 25, 75, -28, 37, 85, -43, 49, + 37, 64, -17, 39, 58, -14, 43, 45, -7, 50, 28, 3, + 58, 9, 15, 67, -9, 26, 76, -25, 38, 85, -40, 50, + 38, 66, -14, 40, 60, -11, 45, 47, -5, 51, 31, 5, + 59, 12, 16, 68, -5, 27, 76, -22, 39, 86, -37, 50, + 40, 67, -12, 42, 62, -9, 46, 50, -3, 52, 34, 6, + 60, 15, 17, 68, -2, 28, 77, -19, 40, 86, -35, 51, + 41, 69, -9, 43, 64, -7, 47, 52, 0, 53, 37, 8, + 61, 19, 19, 69, 1, 29, 78, -16, 40, 87, -32, 52, + 43, 71, -7, 45, 66, -4, 49, 55, 2, 54, 40, 10, + 62, 22, 20, 70, 4, 31, 78, -12, 41, 87, -29, 52, + 45, 73, -4, 46, 68, -1, 50, 57, 4, 56, 43, 12, + 63, 25, 22, 71, 8, 32, 79, -9, 42, 88, -25, 53, + 46, 74, -1, 48, 70, 1, 52, 60, 6, 57, 46, 14, + 64, 29, 23, 71, 11, 33, 80, -6, 43, 88, -22, 54, + 48, 76, 1, 50, 72, 3, 53, 62, 8, 58, 48, 16, + 65, 32, 25, 72, 15, 34, 80, -2, 44, 89, -19, 55, + 50, 78, 4, 51, 74, 6, 54, 65, 10, 59, 51, 17, + 66, 35, 26, 73, 18, 36, 81, 1, 45, 89, -16, 56, + 51, 80, 7, 53, 76, 8, 56, 67, 13, 61, 54, 19, + 67, 38, 28, 74, 21, 37, 82, 5, 47, 90, -12, 57, + 53, 82, 9, 54, 78, 11, 57, 69, 15, 62, 57, 21, + 68, 41, 30, 75, 25, 38, 83, 8, 48, 91, -9, 58, + 55, 83, 12, 56, 80, 13, 59, 72, 17, 63, 60, 23, + 69, 44, 31, 76, 28, 40, 83, 11, 49, 92, -6, 59, + 13, 44, -62, 19, 27, -52, 29, 3, -36, 39, -16, -19, + 50, -33, -3, 61, -47, 12, 71, -59, 26, 81, -70, 40, + 13, 45, -61, 19, 27, -52, 29, 4, -36, 39, -16, -19, + 50, -33, -3, 61, -47, 12, 71, -59, 26, 81, -70, 40, + 13, 45, -61, 19, 28, -51, 29, 5, -35, 39, -15, -19, + 50, -32, -3, 61, -46, 12, 71, -58, 26, 81, -69, 40, + 14, 45, -60, 20, 29, -50, 29, 6, -35, 39, -14, -19, + 50, -32, -2, 61, -46, 12, 71, -58, 26, 81, -69, 40, + 15, 45, -59, 20, 30, -50, 29, 7, -35, 40, -13, -18, + 50, -31, -2, 61, -45, 13, 71, -57, 27, 81, -69, 40, + 15, 46, -57, 21, 31, -49, 30, 8, -34, 40, -12, -18, + 51, -29, -2, 61, -44, 13, 71, -56, 27, 81, -68, 40, + 16, 46, -56, 21, 32, -48, 30, 10, -33, 40, -10, -18, + 51, -28, -2, 61, -43, 13, 71, -55, 27, 81, -67, 40, + 18, 47, -54, 22, 34, -46, 31, 12, -32, 41, -8, -17, + 51, -26, -1, 61, -41, 13, 71, -54, 27, 82, -66, 40, + 19, 48, -52, 23, 35, -45, 31, 14, -31, 41, -6, -16, + 51, -24, -1, 62, -40, 14, 72, -53, 27, 82, -65, 41, + 20, 49, -50, 24, 37, -43, 32, 16, -30, 42, -4, -15, + 52, -22, 0, 62, -38, 14, 72, -51, 28, 82, -64, 41, + 21, 50, -48, 25, 39, -41, 33, 19, -29, 42, -1, -15, + 52, -20, 0, 62, -36, 15, 72, -49, 28, 82, -62, 41, + 23, 51, -45, 26, 40, -39, 34, 21, -28, 43, 1, -14, + 53, -18, 1, 62, -34, 15, 72, -48, 28, 82, -60, 41, + 24, 53, -43, 28, 42, -37, 35, 24, -26, 43, 4, -13, + 53, -15, 2, 63, -31, 16, 73, -45, 29, 83, -59, 42, + 26, 54, -40, 29, 44, -35, 36, 27, -24, 44, 7, -11, + 54, -12, 3, 63, -29, 16, 73, -43, 29, 83, -57, 42, + 27, 55, -38, 30, 46, -33, 37, 29, -23, 45, 10, -10, + 54, -9, 4, 64, -26, 17, 73, -41, 30, 83, -55, 43, + 29, 57, -35, 32, 48, -31, 38, 32, -21, 46, 13, -9, + 55, -6, 5, 64, -23, 18, 74, -38, 30, 83, -52, 43, + 30, 58, -32, 33, 51, -28, 39, 35, -19, 47, 16, -7, + 55, -3, 6, 65, -20, 19, 74, -36, 31, 84, -50, 44, + 32, 60, -30, 35, 53, -26, 40, 38, -17, 47, 19, -6, + 56, 0, 7, 65, -17, 19, 74, -33, 32, 84, -48, 44, + 34, 61, -27, 36, 54, -23, 41, 40, -15, 48, 22, -5, + 57, 3, 8, 66, -14, 20, 75, -30, 32, 84, -45, 45, + 35, 63, -24, 37, 56, -21, 42, 43, -13, 49, 25, -3, + 58, 7, 9, 66, -11, 21, 75, -27, 33, 85, -42, 45, + 37, 65, -22, 39, 59, -18, 44, 46, -11, 50, 29, -1, + 58, 10, 10, 67, -8, 22, 76, -24, 34, 85, -39, 46, + 39, 66, -19, 41, 61, -16, 45, 48, -9, 51, 32, 0, + 59, 13, 12, 68, -4, 23, 76, -21, 35, 86, -37, 46, + 40, 68, -16, 42, 63, -14, 46, 51, -7, 52, 35, 2, + 60, 16, 13, 68, -1, 24, 77, -18, 36, 86, -34, 47, + 42, 70, -14, 44, 65, -11, 48, 53, -5, 54, 38, 4, + 61, 20, 14, 69, 2, 25, 78, -15, 37, 87, -31, 48, + 43, 71, -11, 45, 67, -9, 49, 56, -3, 55, 41, 5, + 62, 23, 16, 70, 5, 26, 78, -12, 37, 87, -28, 49, + 45, 73, -8, 47, 69, -6, 50, 58, 0, 56, 44, 7, + 63, 26, 17, 71, 9, 28, 79, -8, 39, 88, -24, 50, + 47, 75, -6, 48, 71, -4, 52, 61, 2, 57, 47, 9, + 64, 29, 19, 72, 12, 29, 80, -5, 40, 88, -21, 50, + 48, 77, -3, 50, 73, -1, 53, 63, 4, 58, 49, 11, + 65, 33, 20, 72, 15, 30, 80, -2, 41, 89, -18, 51, + 50, 79, -1, 51, 75, 1, 55, 65, 6, 59, 52, 13, + 66, 36, 22, 73, 19, 32, 81, 2, 42, 90, -15, 52, + 52, 80, 2, 53, 77, 4, 56, 68, 8, 61, 55, 15, + 67, 39, 24, 74, 22, 33, 82, 5, 43, 90, -12, 53, + 53, 82, 5, 55, 79, 6, 58, 70, 11, 62, 58, 17, + 68, 42, 25, 75, 25, 34, 83, 9, 44, 91, -8, 54, + 55, 84, 7, 56, 80, 9, 59, 72, 13, 63, 60, 19, + 69, 45, 27, 76, 28, 36, 83, 12, 45, 92, -5, 55, + 14, 47, -65, 20, 31, -56, 29, 7, -41, 40, -13, -24, + 50, -30, -8, 61, -45, 7, 71, -57, 22, 81, -68, 35, + 14, 47, -65, 20, 31, -56, 29, 8, -40, 40, -13, -24, + 50, -30, -8, 61, -44, 8, 71, -57, 22, 81, -68, 35, + 15, 47, -64, 20, 31, -55, 29, 8, -40, 40, -12, -24, + 50, -30, -7, 61, -44, 8, 71, -56, 22, 81, -68, 35, + 15, 48, -63, 21, 32, -55, 30, 9, -40, 40, -11, -24, + 51, -29, -7, 61, -43, 8, 71, -56, 22, 81, -67, 36, + 16, 48, -62, 21, 33, -54, 30, 10, -39, 40, -10, -23, + 51, -28, -7, 61, -43, 8, 71, -55, 22, 81, -67, 36, + 17, 48, -61, 22, 34, -53, 30, 12, -39, 40, -9, -23, + 51, -27, -7, 61, -42, 8, 71, -54, 22, 81, -66, 36, + 17, 49, -60, 22, 35, -52, 31, 13, -38, 41, -7, -22, + 51, -26, -6, 61, -40, 8, 71, -54, 22, 82, -66, 36, + 19, 49, -58, 23, 36, -50, 31, 15, -37, 41, -5, -22, + 51, -24, -6, 62, -39, 9, 72, -52, 23, 82, -64, 36, + 20, 50, -56, 24, 38, -49, 32, 17, -36, 41, -3, -21, + 52, -22, -6, 62, -37, 9, 72, -51, 23, 82, -63, 36, + 21, 51, -54, 25, 39, -47, 33, 19, -35, 42, -1, -20, + 52, -20, -5, 62, -36, 9, 72, -49, 23, 82, -62, 37, + 22, 52, -52, 26, 41, -46, 33, 21, -34, 42, 1, -20, + 52, -18, -4, 62, -34, 10, 72, -48, 24, 82, -61, 37, + 23, 53, -50, 27, 43, -44, 34, 24, -32, 43, 4, -19, + 53, -15, -4, 63, -32, 10, 72, -46, 24, 82, -59, 37, + 25, 54, -47, 28, 45, -42, 35, 26, -31, 44, 7, -17, + 53, -13, -3, 63, -29, 11, 73, -44, 24, 83, -57, 38, + 26, 55, -45, 30, 46, -40, 36, 29, -29, 44, 9, -16, + 54, -10, -2, 63, -27, 12, 73, -42, 25, 83, -55, 38, + 28, 57, -42, 31, 48, -37, 37, 31, -28, 45, 12, -15, + 54, -7, -1, 64, -24, 12, 73, -39, 25, 83, -53, 38, + 29, 58, -40, 32, 50, -35, 38, 34, -26, 46, 15, -14, + 55, -4, 0, 64, -22, 13, 74, -37, 26, 83, -51, 39, + 31, 60, -37, 34, 52, -33, 39, 37, -24, 47, 18, -12, + 56, -1, 1, 65, -18, 14, 74, -34, 27, 84, -49, 39, + 33, 61, -34, 35, 54, -31, 40, 39, -22, 48, 21, -11, + 56, 2, 2, 65, -16, 15, 75, -32, 27, 84, -46, 40, + 34, 63, -32, 36, 56, -28, 42, 42, -20, 49, 24, -10, + 57, 5, 3, 66, -13, 16, 75, -29, 28, 85, -44, 40, + 36, 64, -29, 38, 58, -26, 43, 44, -18, 50, 27, -8, + 58, 8, 4, 67, -10, 16, 76, -26, 29, 85, -41, 41, + 37, 66, -26, 39, 60, -23, 44, 47, -16, 51, 30, -6, + 59, 11, 6, 67, -6, 18, 76, -23, 30, 85, -38, 42, + 39, 67, -24, 41, 62, -21, 45, 49, -14, 52, 33, -5, + 60, 15, 7, 68, -3, 19, 77, -20, 30, 86, -35, 42, + 41, 69, -21, 42, 64, -19, 47, 52, -12, 53, 36, -3, + 60, 18, 8, 69, 0, 20, 77, -17, 31, 86, -33, 43, + 42, 71, -19, 44, 66, -16, 48, 54, -10, 54, 39, -1, + 61, 21, 10, 69, 3, 21, 78, -14, 32, 87, -30, 44, + 44, 72, -16, 45, 68, -14, 49, 57, -8, 55, 42, 1, + 62, 24, 11, 70, 6, 22, 78, -11, 33, 87, -27, 44, + 45, 74, -13, 47, 70, -11, 51, 59, -5, 56, 45, 3, + 63, 27, 13, 71, 10, 23, 79, -7, 34, 88, -23, 45, + 47, 76, -11, 49, 72, -9, 52, 62, -3, 57, 47, 4, + 64, 30, 14, 72, 13, 24, 80, -4, 35, 89, -20, 46, + 49, 78, -8, 50, 73, -6, 53, 64, -1, 59, 50, 6, + 65, 33, 16, 73, 16, 26, 81, -1, 36, 89, -17, 47, + 50, 79, -6, 52, 75, -4, 55, 66, 1, 60, 53, 8, + 66, 36, 17, 73, 19, 27, 81, 3, 37, 90, -14, 48, + 52, 81, -3, 53, 77, -1, 56, 69, 3, 61, 56, 10, + 67, 40, 19, 74, 23, 28, 82, 6, 38, 90, -11, 49, + 54, 83, -1, 55, 79, 1, 58, 71, 6, 62, 58, 12, + 68, 43, 21, 75, 26, 30, 83, 9, 40, 91, -8, 50, + 55, 85, 2, 56, 81, 4, 59, 73, 8, 64, 61, 14, + 69, 46, 22, 76, 29, 31, 84, 13, 41, 92, -4, 51, + 15, 49, -68, 21, 34, -59, 30, 11, -45, 40, -10, -28, + 51, -28, -12, 61, -43, 3, 71, -55, 18, 81, -67, 32, + 16, 49, -68, 21, 34, -59, 30, 11, -44, 40, -9, -28, + 51, -27, -12, 61, -42, 3, 71, -55, 18, 81, -67, 32, + 16, 49, -67, 21, 34, -59, 30, 12, -44, 40, -9, -28, + 51, -27, -12, 61, -42, 3, 71, -55, 18, 81, -66, 32, + 16, 50, -66, 21, 35, -58, 30, 13, -44, 40, -8, -28, + 51, -26, -12, 61, -41, 4, 71, -54, 18, 81, -66, 32, + 17, 50, -66, 22, 36, -57, 31, 14, -43, 40, -7, -28, + 51, -25, -11, 61, -40, 4, 71, -54, 18, 81, -66, 32, + 18, 50, -64, 22, 37, -57, 31, 15, -43, 41, -6, -27, + 51, -24, -11, 61, -40, 4, 71, -53, 18, 82, -65, 32, + 19, 51, -63, 23, 38, -56, 31, 16, -42, 41, -5, -27, + 51, -23, -11, 61, -38, 4, 72, -52, 18, 82, -64, 32, + 20, 51, -61, 24, 39, -54, 32, 18, -41, 41, -3, -26, + 52, -21, -10, 62, -37, 4, 72, -51, 19, 82, -63, 32, + 21, 52, -59, 25, 40, -53, 32, 20, -40, 42, -1, -25, + 52, -20, -10, 62, -35, 5, 72, -49, 19, 82, -62, 32, + 22, 53, -58, 26, 42, -51, 33, 22, -39, 42, 1, -25, + 52, -18, -9, 62, -34, 5, 72, -48, 19, 82, -61, 33, + 23, 54, -56, 27, 43, -50, 34, 24, -38, 43, 3, -24, + 53, -16, -9, 62, -32, 6, 72, -46, 19, 82, -59, 33, + 24, 55, -53, 28, 45, -48, 35, 26, -36, 43, 6, -23, + 53, -13, -8, 63, -30, 6, 73, -44, 20, 82, -58, 33, + 26, 56, -51, 29, 46, -46, 36, 28, -35, 44, 9, -22, + 54, -11, -7, 63, -27, 7, 73, -42, 20, 83, -56, 34, + 27, 57, -49, 30, 48, -44, 37, 31, -33, 45, 11, -21, + 54, -8, -6, 64, -25, 7, 73, -40, 21, 83, -54, 34, + 28, 58, -46, 31, 50, -42, 37, 33, -32, 45, 14, -19, + 55, -5, -6, 64, -23, 8, 73, -38, 21, 83, -52, 34, + 30, 59, -44, 33, 51, -39, 38, 36, -30, 46, 17, -18, + 55, -3, -5, 64, -20, 9, 74, -36, 22, 84, -50, 35, + 32, 61, -41, 34, 53, -37, 40, 38, -28, 47, 20, -17, + 56, 0, -3, 65, -17, 10, 74, -33, 23, 84, -47, 35, + 33, 62, -39, 35, 55, -35, 41, 41, -26, 48, 23, -15, + 57, 3, -2, 66, -14, 10, 75, -30, 23, 84, -45, 36, + 35, 64, -36, 37, 57, -33, 42, 43, -25, 49, 25, -14, + 57, 6, -1, 66, -11, 11, 75, -28, 24, 85, -43, 37, + 36, 65, -34, 38, 59, -30, 43, 46, -23, 50, 28, -12, + 58, 9, 0, 67, -8, 12, 76, -25, 25, 85, -40, 37, + 38, 67, -31, 40, 61, -28, 44, 48, -20, 51, 31, -11, + 59, 13, 1, 67, -5, 13, 76, -22, 26, 86, -37, 38, + 39, 68, -28, 41, 63, -25, 46, 51, -18, 52, 34, -9, + 60, 16, 3, 68, -2, 14, 77, -19, 26, 86, -34, 38, + 41, 70, -26, 43, 65, -23, 47, 53, -16, 53, 37, -7, + 61, 19, 4, 69, 1, 15, 77, -16, 27, 86, -32, 39, + 42, 72, -23, 44, 67, -20, 48, 55, -14, 54, 40, -6, + 61, 22, 5, 69, 4, 17, 78, -13, 28, 87, -29, 40, + 44, 73, -21, 46, 68, -18, 50, 58, -12, 55, 43, -4, + 62, 25, 7, 70, 7, 18, 79, -10, 29, 87, -26, 41, + 46, 75, -18, 47, 70, -15, 51, 60, -10, 56, 46, -2, + 63, 28, 8, 71, 11, 19, 79, -6, 30, 88, -23, 42, + 47, 77, -15, 49, 72, -13, 52, 62, -8, 58, 48, 0, + 64, 31, 10, 72, 14, 20, 80, -3, 31, 89, -20, 42, + 49, 78, -13, 50, 74, -11, 54, 65, -6, 59, 51, 2, + 65, 34, 11, 73, 17, 22, 81, 0, 32, 89, -16, 43, + 50, 80, -10, 52, 76, -8, 55, 67, -3, 60, 54, 4, + 66, 37, 13, 74, 20, 23, 81, 3, 33, 90, -13, 44, + 52, 82, -7, 53, 78, -6, 57, 69, -1, 61, 57, 6, + 67, 41, 15, 75, 24, 24, 82, 7, 34, 91, -10, 45, + 54, 84, -5, 55, 80, -3, 58, 72, 1, 62, 59, 8, + 69, 44, 16, 75, 27, 26, 83, 10, 36, 91, -7, 46, + 55, 85, -2, 57, 82, -1, 59, 74, 3, 64, 62, 10, + 70, 46, 18, 76, 30, 27, 84, 13, 37, 92, -4, 47, + 17, 51, -71, 22, 37, -63, 30, 14, -48, 40, -7, -33, + 51, -25, -16, 61, -40, -1, 71, -53, 14, 81, -65, 28, + 17, 52, -71, 22, 37, -63, 31, 15, -48, 40, -6, -32, + 51, -25, -16, 61, -40, -1, 71, -53, 14, 81, -65, 28, + 17, 52, -70, 22, 37, -62, 31, 15, -48, 41, -6, -32, + 51, -24, -16, 61, -40, -1, 71, -53, 14, 82, -65, 28, + 18, 52, -70, 22, 38, -62, 31, 16, -48, 41, -5, -32, + 51, -24, -16, 61, -39, -1, 71, -52, 14, 82, -64, 28, + 18, 52, -69, 23, 39, -61, 31, 17, -47, 41, -4, -32, + 51, -23, -16, 61, -38, 0, 71, -52, 14, 82, -64, 28, + 19, 52, -68, 23, 39, -60, 31, 18, -47, 41, -3, -31, + 51, -22, -15, 62, -37, 0, 72, -51, 14, 82, -63, 28, + 20, 53, -66, 24, 40, -59, 32, 19, -46, 41, -2, -31, + 52, -21, -15, 62, -36, 0, 72, -50, 14, 82, -63, 28, + 21, 53, -65, 25, 41, -58, 32, 21, -45, 42, 0, -30, + 52, -19, -15, 62, -35, 0, 72, -49, 15, 82, -62, 28, + 22, 54, -63, 25, 43, -56, 33, 22, -44, 42, 2, -30, + 52, -17, -14, 62, -33, 1, 72, -48, 15, 82, -60, 29, + 23, 55, -61, 26, 44, -55, 34, 24, -43, 43, 4, -29, + 53, -15, -14, 62, -32, 1, 72, -46, 15, 82, -59, 29, + 24, 56, -59, 27, 45, -53, 34, 26, -42, 43, 6, -28, + 53, -13, -13, 63, -30, 2, 72, -45, 15, 82, -58, 29, + 25, 56, -57, 28, 47, -52, 35, 28, -41, 44, 8, -27, + 53, -11, -12, 63, -28, 2, 73, -43, 16, 83, -56, 29, + 26, 57, -55, 30, 48, -50, 36, 31, -39, 44, 11, -26, + 54, -9, -11, 63, -26, 3, 73, -41, 16, 83, -54, 30, + 28, 59, -52, 31, 50, -48, 37, 33, -38, 45, 13, -25, + 54, -6, -11, 64, -23, 3, 73, -39, 17, 83, -53, 30, + 29, 60, -50, 32, 51, -46, 38, 35, -36, 46, 16, -24, + 55, -4, -10, 64, -21, 4, 74, -36, 17, 83, -51, 31, + 30, 61, -48, 33, 53, -44, 39, 37, -34, 47, 19, -22, + 55, -1, -9, 65, -18, 5, 74, -34, 18, 84, -49, 31, + 32, 62, -45, 35, 55, -41, 40, 40, -32, 47, 22, -21, + 56, 2, -8, 65, -15, 5, 74, -31, 19, 84, -46, 32, + 34, 64, -43, 36, 57, -39, 41, 42, -31, 48, 24, -20, + 57, 5, -7, 66, -13, 6, 75, -29, 19, 84, -44, 32, + 35, 65, -40, 37, 58, -37, 42, 45, -29, 49, 27, -18, + 58, 8, -6, 66, -10, 7, 75, -26, 20, 85, -41, 33, + 37, 66, -38, 39, 60, -34, 43, 47, -27, 50, 30, -17, + 58, 11, -4, 67, -7, 8, 76, -23, 21, 85, -39, 33, + 38, 68, -35, 40, 62, -32, 45, 49, -25, 51, 33, -15, + 59, 14, -3, 68, -4, 9, 76, -20, 22, 86, -36, 34, + 40, 70, -32, 42, 64, -30, 46, 52, -23, 52, 36, -13, + 60, 17, -2, 68, -1, 10, 77, -17, 22, 86, -33, 35, + 41, 71, -30, 43, 66, -27, 47, 54, -21, 53, 38, -12, + 61, 20, 0, 69, 2, 11, 77, -14, 23, 87, -31, 35, + 43, 73, -27, 45, 68, -25, 49, 56, -19, 54, 41, -10, + 62, 23, 1, 70, 5, 12, 78, -11, 24, 87, -28, 36, + 44, 74, -25, 46, 69, -22, 50, 59, -17, 55, 44, -8, + 63, 26, 2, 70, 9, 14, 79, -8, 25, 88, -25, 37, + 46, 76, -22, 48, 71, -20, 51, 61, -14, 57, 47, -6, + 64, 29, 4, 71, 12, 15, 79, -5, 26, 88, -22, 38, + 48, 77, -20, 49, 73, -17, 53, 63, -12, 58, 49, -4, + 65, 32, 6, 72, 15, 16, 80, -2, 27, 89, -19, 39, + 49, 79, -17, 51, 75, -15, 54, 66, -10, 59, 52, -2, + 66, 35, 7, 73, 18, 17, 81, 1, 28, 89, -16, 39, + 51, 81, -15, 52, 77, -13, 55, 68, -8, 60, 55, -1, + 67, 38, 9, 74, 21, 19, 81, 4, 29, 90, -13, 40, + 52, 83, -12, 54, 79, -10, 57, 70, -5, 61, 57, 1, + 68, 42, 10, 75, 25, 20, 82, 8, 31, 91, -9, 41, + 54, 84, -9, 55, 81, -8, 58, 72, -3, 63, 60, 3, + 69, 44, 12, 76, 28, 22, 83, 11, 32, 91, -6, 42, + 56, 86, -7, 57, 82, -5, 60, 74, -1, 64, 62, 5, + 70, 47, 14, 76, 31, 23, 84, 14, 33, 92, -3, 43, + 18, 54, -74, 23, 40, -66, 31, 18, -52, 41, -4, -37, + 51, -22, -20, 61, -38, -5, 71, -51, 9, 82, -64, 24, + 18, 54, -74, 23, 40, -66, 31, 18, -52, 41, -3, -37, + 51, -22, -20, 61, -38, -5, 71, -51, 10, 82, -64, 24, + 18, 54, -73, 23, 40, -66, 31, 18, -52, 41, -3, -36, + 51, -22, -20, 61, -37, -5, 71, -51, 10, 82, -63, 24, + 19, 54, -73, 23, 41, -65, 31, 19, -52, 41, -2, -36, + 51, -21, -20, 62, -37, -5, 72, -50, 10, 82, -63, 24, + 19, 54, -72, 24, 41, -64, 32, 20, -51, 41, -1, -36, + 52, -20, -20, 62, -36, -5, 72, -50, 10, 82, -62, 24, + 20, 55, -71, 24, 42, -64, 32, 21, -51, 41, 0, -35, + 52, -19, -20, 62, -35, -4, 72, -49, 10, 82, -62, 24, + 21, 55, -69, 25, 43, -63, 33, 22, -50, 42, 1, -35, + 52, -18, -19, 62, -34, -4, 72, -48, 10, 82, -61, 24, + 22, 55, -68, 25, 44, -61, 33, 24, -49, 42, 3, -34, + 52, -16, -19, 62, -33, -4, 72, -47, 10, 82, -60, 24, + 22, 56, -66, 26, 45, -60, 34, 25, -48, 43, 5, -34, + 53, -15, -18, 62, -31, -4, 72, -46, 11, 82, -59, 25, + 23, 57, -65, 27, 46, -59, 34, 27, -47, 43, 6, -33, + 53, -13, -18, 63, -30, -3, 72, -44, 11, 82, -58, 25, + 25, 57, -63, 28, 47, -57, 35, 29, -46, 44, 8, -32, + 53, -11, -17, 63, -28, -3, 73, -43, 11, 83, -56, 25, + 26, 58, -61, 29, 49, -55, 36, 31, -45, 44, 11, -31, + 54, -9, -16, 63, -26, -2, 73, -41, 12, 83, -55, 25, + 27, 59, -58, 30, 50, -53, 37, 33, -43, 45, 13, -30, + 54, -7, -16, 64, -24, -2, 73, -39, 12, 83, -53, 26, + 28, 60, -56, 31, 52, -52, 37, 35, -42, 45, 15, -29, + 55, -4, -15, 64, -21, -1, 73, -37, 13, 83, -51, 26, + 30, 61, -54, 32, 53, -50, 38, 37, -40, 46, 18, -28, + 55, -2, -14, 64, -19, 0, 74, -35, 13, 84, -49, 27, + 31, 62, -52, 34, 55, -48, 39, 39, -38, 47, 20, -27, + 56, 1, -13, 65, -17, 0, 74, -33, 14, 84, -47, 27, + 33, 64, -49, 35, 56, -45, 41, 42, -37, 48, 23, -25, + 56, 4, -12, 65, -14, 1, 75, -30, 14, 84, -45, 28, + 34, 65, -47, 36, 58, -43, 42, 44, -35, 49, 26, -24, + 57, 7, -11, 66, -11, 2, 75, -27, 15, 85, -43, 28, + 36, 66, -44, 38, 60, -41, 43, 46, -33, 50, 29, -22, + 58, 10, -10, 66, -8, 3, 76, -25, 16, 85, -40, 29, + 37, 68, -42, 39, 61, -39, 44, 48, -31, 50, 31, -21, + 59, 12, -9, 67, -5, 4, 76, -22, 17, 85, -38, 29, + 39, 69, -39, 41, 63, -36, 45, 51, -29, 52, 34, -19, + 59, 16, -7, 68, -2, 5, 77, -19, 17, 86, -35, 30, + 40, 71, -37, 42, 65, -34, 46, 53, -27, 52, 37, -18, + 60, 19, -6, 68, 1, 6, 77, -16, 18, 86, -32, 31, + 42, 72, -34, 43, 67, -31, 48, 55, -25, 54, 40, -16, + 61, 21, -5, 69, 4, 7, 78, -13, 19, 87, -29, 31, + 43, 74, -32, 45, 69, -29, 49, 58, -23, 55, 42, -14, + 62, 24, -3, 70, 7, 8, 78, -10, 20, 87, -27, 32, + 45, 75, -29, 46, 70, -27, 50, 60, -21, 56, 45, -12, + 63, 27, -2, 71, 10, 9, 79, -7, 21, 88, -24, 33, + 46, 77, -26, 48, 72, -24, 52, 62, -18, 57, 48, -10, + 64, 31, 0, 71, 13, 11, 80, -4, 22, 88, -21, 34, + 48, 78, -24, 49, 74, -22, 53, 64, -16, 58, 50, -9, + 65, 34, 1, 72, 16, 12, 80, -1, 23, 89, -18, 35, + 50, 80, -21, 51, 76, -19, 54, 66, -14, 59, 53, -7, + 66, 36, 3, 73, 19, 13, 81, 2, 24, 89, -15, 36, + 51, 82, -19, 52, 78, -17, 56, 69, -12, 60, 56, -5, + 67, 39, 4, 74, 22, 15, 82, 5, 25, 90, -12, 36, + 53, 83, -16, 54, 80, -14, 57, 71, -10, 62, 58, -3, + 68, 42, 6, 75, 26, 16, 82, 9, 27, 91, -8, 38, + 54, 85, -14, 56, 81, -12, 58, 73, -7, 63, 61, -1, + 69, 45, 8, 76, 29, 17, 83, 12, 28, 91, -5, 38, + 56, 87, -11, 57, 83, -9, 60, 75, -5, 64, 63, 1, + 70, 48, 9, 77, 32, 19, 84, 15, 29, 92, -2, 39, + 19, 56, -77, 24, 43, -70, 32, 21, -57, 41, 0, -41, + 52, -19, -25, 62, -35, -10, 72, -49, 5, 82, -62, 19, + 19, 56, -77, 24, 43, -70, 32, 22, -56, 41, 0, -41, + 52, -19, -25, 62, -35, -10, 72, -49, 5, 82, -62, 19, + 20, 56, -76, 24, 43, -69, 32, 22, -56, 41, 1, -41, + 52, -18, -25, 62, -35, -10, 72, -49, 5, 82, -61, 19, + 20, 56, -76, 24, 44, -69, 32, 23, -56, 42, 2, -41, + 52, -18, -25, 62, -34, -9, 72, -48, 5, 82, -61, 19, + 21, 57, -75, 25, 44, -68, 32, 23, -55, 42, 2, -40, + 52, -17, -24, 62, -33, -9, 72, -47, 5, 82, -60, 20, + 21, 57, -74, 25, 45, -67, 33, 24, -55, 42, 3, -40, + 52, -16, -24, 62, -33, -9, 72, -47, 5, 82, -60, 20, + 22, 57, -73, 26, 46, -67, 33, 25, -54, 42, 5, -40, + 52, -15, -24, 62, -32, -9, 72, -46, 6, 82, -59, 20, + 23, 58, -71, 26, 47, -65, 34, 27, -53, 43, 6, -39, + 53, -14, -23, 62, -30, -9, 72, -45, 6, 82, -58, 20, + 24, 58, -70, 27, 48, -64, 34, 28, -52, 43, 8, -38, + 53, -12, -23, 63, -29, -8, 72, -44, 6, 82, -57, 20, + 25, 59, -68, 28, 49, -63, 35, 30, -51, 43, 9, -38, + 53, -10, -22, 63, -27, -8, 73, -42, 6, 83, -56, 20, + 26, 59, -67, 29, 50, -61, 36, 31, -50, 44, 11, -37, + 54, -9, -22, 63, -26, -7, 73, -41, 7, 83, -55, 21, + 27, 60, -65, 30, 51, -60, 36, 33, -49, 45, 13, -36, + 54, -7, -21, 63, -24, -7, 73, -39, 7, 83, -53, 21, + 28, 61, -62, 31, 52, -58, 37, 35, -48, 45, 16, -35, + 54, -4, -20, 64, -21, -6, 73, -37, 8, 83, -51, 21, + 29, 62, -60, 32, 54, -56, 38, 37, -46, 46, 18, -34, + 55, -2, -20, 64, -19, -6, 74, -35, 8, 83, -50, 22, + 31, 63, -58, 33, 55, -54, 39, 39, -45, 47, 20, -33, + 55, 1, -19, 65, -17, -5, 74, -33, 9, 84, -48, 22, + 32, 64, -56, 34, 57, -52, 40, 41, -43, 47, 23, -31, + 56, 3, -18, 65, -15, -4, 74, -31, 9, 84, -46, 23, + 33, 65, -53, 36, 58, -50, 41, 44, -41, 48, 25, -30, + 57, 6, -17, 66, -12, -3, 75, -28, 10, 84, -43, 23, + 35, 66, -51, 37, 60, -47, 42, 46, -39, 49, 28, -29, + 57, 9, -16, 66, -9, -3, 75, -26, 11, 85, -41, 24, + 36, 68, -49, 38, 61, -45, 43, 48, -38, 50, 31, -27, + 58, 11, -14, 67, -6, -2, 76, -23, 11, 85, -39, 24, + 38, 69, -46, 40, 63, -43, 44, 50, -36, 51, 33, -26, + 59, 14, -13, 67, -4, -1, 76, -20, 12, 85, -36, 25, + 39, 70, -44, 41, 65, -41, 46, 52, -34, 52, 36, -24, + 60, 17, -12, 68, -1, 0, 77, -17, 13, 86, -33, 26, + 41, 72, -41, 43, 66, -38, 47, 55, -32, 53, 39, -22, + 60, 20, -11, 69, 2, 1, 77, -15, 14, 86, -31, 26, + 42, 73, -39, 44, 68, -36, 48, 57, -30, 54, 41, -21, + 61, 23, -9, 69, 5, 2, 78, -12, 15, 87, -28, 27, + 44, 75, -36, 45, 70, -34, 49, 59, -28, 55, 44, -19, + 62, 26, -8, 70, 8, 4, 78, -9, 16, 87, -25, 28, + 45, 76, -34, 47, 72, -31, 51, 61, -26, 56, 46, -17, + 63, 29, -7, 71, 11, 5, 79, -6, 16, 88, -23, 29, + 47, 78, -31, 48, 73, -29, 52, 63, -23, 57, 49, -15, + 64, 32, -5, 72, 15, 6, 80, -3, 18, 88, -19, 29, + 48, 79, -29, 50, 75, -26, 53, 65, -21, 58, 52, -13, + 65, 35, -3, 72, 17, 7, 80, 0, 19, 89, -16, 30, + 50, 81, -26, 51, 77, -24, 55, 68, -19, 59, 54, -12, + 66, 38, -2, 73, 20, 9, 81, 3, 20, 90, -13, 31, + 51, 82, -24, 53, 79, -22, 56, 70, -17, 61, 57, -10, + 67, 40, 0, 74, 23, 10, 82, 6, 21, 90, -10, 32, + 53, 84, -21, 54, 81, -19, 57, 72, -14, 62, 59, -8, + 68, 44, 1, 75, 27, 11, 83, 10, 22, 91, -7, 33, + 55, 86, -18, 56, 82, -17, 59, 74, -12, 63, 62, -6, + 69, 46, 3, 76, 30, 13, 83, 13, 23, 92, -4, 34, + 56, 87, -16, 57, 84, -14, 60, 76, -10, 64, 64, -4, + 70, 49, 5, 77, 33, 14, 84, 16, 24, 92, -1, 35, + 20, 58, -80, 25, 46, -73, 32, 25, -60, 42, 3, -45, + 52, -16, -29, 62, -33, -14, 72, -47, 1, 82, -60, 15, + 21, 58, -80, 25, 46, -73, 33, 25, -60, 42, 4, -45, + 52, -16, -29, 62, -32, -14, 72, -47, 1, 82, -60, 15, + 21, 58, -79, 25, 46, -73, 33, 25, -60, 42, 4, -45, + 52, -16, -29, 62, -32, -14, 72, -46, 1, 82, -59, 15, + 21, 58, -79, 25, 47, -72, 33, 26, -60, 42, 5, -45, + 52, -15, -29, 62, -32, -14, 72, -46, 1, 82, -59, 15, + 22, 59, -78, 26, 47, -72, 33, 27, -59, 42, 5, -44, + 52, -14, -29, 62, -31, -13, 72, -45, 1, 82, -59, 16, + 22, 59, -77, 26, 48, -71, 33, 27, -59, 42, 6, -44, + 52, -13, -28, 62, -30, -13, 72, -45, 1, 82, -58, 16, + 23, 59, -76, 27, 48, -70, 34, 28, -58, 43, 7, -44, + 53, -12, -28, 62, -29, -13, 72, -44, 2, 82, -57, 16, + 24, 60, -75, 27, 49, -69, 34, 30, -57, 43, 9, -43, + 53, -11, -28, 63, -28, -13, 72, -43, 2, 82, -56, 16, + 25, 60, -73, 28, 50, -68, 35, 31, -56, 43, 10, -42, + 53, -9, -27, 63, -27, -12, 73, -42, 2, 83, -55, 16, + 25, 61, -72, 29, 51, -66, 35, 32, -55, 44, 12, -42, + 54, -8, -27, 63, -25, -12, 73, -40, 2, 83, -54, 17, + 26, 61, -70, 30, 52, -65, 36, 34, -54, 44, 14, -41, + 54, -6, -26, 63, -23, -11, 73, -39, 3, 83, -53, 17, + 28, 62, -68, 31, 53, -63, 37, 36, -53, 45, 16, -40, + 54, -4, -25, 64, -22, -11, 73, -37, 3, 83, -51, 17, + 29, 63, -66, 32, 54, -61, 38, 38, -51, 46, 18, -39, + 55, -2, -24, 64, -19, -10, 74, -35, 4, 83, -50, 18, + 30, 64, -64, 33, 56, -60, 39, 39, -50, 46, 20, -38, + 55, 0, -24, 64, -17, -10, 74, -33, 4, 84, -48, 18, + 31, 65, -62, 34, 57, -58, 39, 41, -49, 47, 22, -37, + 56, 3, -23, 65, -15, -9, 74, -31, 5, 84, -46, 18, + 33, 66, -60, 35, 58, -56, 40, 43, -47, 48, 25, -35, + 56, 5, -22, 65, -13, -8, 75, -29, 5, 84, -44, 19, + 34, 67, -57, 36, 60, -53, 41, 45, -45, 49, 27, -34, + 57, 8, -21, 66, -10, -7, 75, -26, 6, 85, -42, 19, + 35, 68, -55, 38, 61, -51, 43, 47, -43, 49, 30, -33, + 58, 11, -20, 66, -7, -7, 75, -24, 7, 85, -40, 20, + 37, 69, -53, 39, 63, -49, 44, 50, -42, 50, 32, -31, + 58, 13, -19, 67, -5, -6, 76, -22, 7, 85, -37, 20, + 38, 70, -50, 40, 64, -47, 45, 52, -40, 51, 35, -30, + 59, 16, -17, 68, -2, -5, 76, -19, 8, 86, -35, 21, + 40, 72, -48, 42, 66, -45, 46, 54, -38, 52, 38, -28, + 60, 19, -16, 68, 1, -4, 77, -16, 9, 86, -32, 22, + 41, 73, -45, 43, 68, -42, 47, 56, -36, 53, 40, -26, + 61, 22, -15, 69, 4, -3, 77, -13, 10, 87, -29, 22, + 43, 74, -43, 44, 69, -40, 48, 58, -34, 54, 43, -25, + 62, 24, -14, 70, 7, -2, 78, -10, 11, 87, -27, 23, + 44, 76, -40, 46, 71, -38, 50, 60, -32, 55, 45, -23, + 62, 27, -12, 70, 10, -1, 79, -8, 11, 87, -24, 24, + 46, 77, -38, 47, 73, -36, 51, 62, -30, 56, 48, -21, + 63, 30, -11, 71, 12, 1, 79, -5, 12, 88, -21, 25, + 47, 79, -35, 49, 74, -33, 52, 64, -27, 58, 50, -19, + 64, 33, -9, 72, 16, 2, 80, -1, 14, 89, -18, 26, + 49, 80, -33, 50, 76, -31, 54, 67, -25, 59, 53, -18, + 65, 36, -8, 73, 19, 3, 81, 2, 15, 89, -15, 26, + 50, 82, -30, 52, 78, -28, 55, 69, -23, 60, 55, -16, + 66, 39, -6, 73, 22, 4, 81, 5, 16, 90, -12, 27, + 52, 83, -28, 53, 80, -26, 56, 71, -21, 61, 58, -14, + 67, 42, -5, 74, 25, 6, 82, 8, 17, 90, -9, 28, + 53, 85, -25, 55, 81, -23, 58, 73, -19, 62, 60, -12, + 68, 45, -3, 75, 28, 7, 83, 11, 18, 91, -6, 29, + 55, 87, -23, 56, 83, -21, 59, 75, -17, 63, 63, -10, + 69, 47, -1, 76, 31, 9, 84, 14, 19, 92, -3, 30, + 56, 88, -20, 58, 85, -19, 60, 77, -14, 65, 65, -8, + 70, 50, 1, 77, 34, 10, 84, 17, 20, 92, 0, 31, + 22, 60, -83, 26, 49, -76, 33, 28, -64, 42, 7, -49, + 52, -13, -33, 62, -30, -18, 72, -45, -3, 82, -58, 11, + 22, 60, -83, 26, 49, -76, 33, 28, -64, 42, 7, -49, + 52, -13, -33, 62, -30, -18, 72, -44, -3, 82, -58, 11, + 22, 60, -82, 26, 49, -76, 33, 29, -63, 42, 7, -49, + 52, -13, -33, 62, -29, -18, 72, -44, -3, 82, -58, 11, + 22, 61, -82, 26, 49, -75, 34, 29, -63, 43, 8, -49, + 53, -12, -33, 62, -29, -18, 72, -44, -3, 82, -57, 12, + 23, 61, -81, 27, 50, -75, 34, 30, -63, 43, 9, -48, + 53, -11, -33, 62, -28, -17, 72, -43, -3, 82, -57, 12, + 23, 61, -80, 27, 50, -74, 34, 30, -62, 43, 9, -48, + 53, -11, -32, 63, -28, -17, 72, -43, -3, 82, -56, 12, + 24, 61, -79, 27, 51, -73, 34, 31, -62, 43, 10, -47, + 53, -10, -32, 63, -27, -17, 72, -42, -2, 82, -55, 12, + 25, 62, -78, 28, 51, -72, 35, 33, -61, 44, 12, -47, + 53, -8, -32, 63, -25, -17, 73, -41, -2, 83, -54, 12, + 26, 62, -76, 29, 52, -71, 35, 34, -60, 44, 13, -46, + 54, -7, -31, 63, -24, -16, 73, -39, -2, 83, -53, 12, + 26, 62, -75, 30, 53, -70, 36, 35, -59, 44, 15, -46, + 54, -5, -31, 63, -23, -16, 73, -38, -2, 83, -52, 13, + 27, 63, -73, 30, 54, -68, 37, 37, -58, 45, 16, -45, + 54, -4, -30, 64, -21, -16, 73, -37, -1, 83, -51, 13, + 28, 64, -72, 31, 55, -67, 37, 38, -57, 45, 18, -44, + 55, -2, -29, 64, -19, -15, 73, -35, -1, 83, -50, 13, + 30, 65, -69, 32, 56, -65, 38, 40, -55, 46, 20, -43, + 55, 1, -29, 64, -17, -14, 74, -33, 0, 84, -48, 14, + 31, 65, -67, 33, 57, -63, 39, 42, -54, 47, 23, -42, + 56, 3, -28, 65, -15, -14, 74, -31, 0, 84, -46, 14, + 32, 66, -65, 34, 59, -61, 40, 43, -52, 47, 25, -41, + 56, 5, -27, 65, -13, -13, 74, -29, 1, 84, -44, 14, + 33, 67, -63, 36, 60, -59, 41, 45, -51, 48, 27, -39, + 57, 7, -26, 66, -11, -12, 75, -27, 1, 84, -43, 15, + 35, 68, -61, 37, 62, -57, 42, 47, -49, 49, 29, -38, + 57, 10, -25, 66, -8, -12, 75, -25, 2, 85, -40, 15, + 36, 69, -59, 38, 63, -55, 43, 49, -47, 50, 32, -37, + 58, 12, -24, 67, -6, -11, 76, -22, 3, 85, -38, 16, + 37, 70, -56, 39, 64, -53, 44, 51, -46, 51, 34, -35, + 59, 15, -23, 67, -3, -10, 76, -20, 3, 85, -36, 16, + 39, 72, -54, 41, 66, -51, 45, 53, -44, 52, 36, -34, + 59, 18, -22, 68, 0, -9, 77, -17, 4, 86, -33, 17, + 40, 73, -52, 42, 68, -49, 46, 55, -42, 53, 39, -32, + 60, 21, -20, 68, 3, -8, 77, -14, 5, 86, -31, 18, + 42, 74, -49, 43, 69, -46, 48, 57, -40, 54, 42, -31, + 61, 23, -19, 69, 5, -7, 78, -12, 6, 87, -28, 18, + 43, 76, -47, 45, 71, -44, 49, 59, -38, 55, 44, -29, + 62, 26, -18, 70, 8, -6, 78, -9, 7, 87, -26, 19, + 45, 77, -44, 46, 72, -42, 50, 61, -36, 56, 46, -27, + 63, 29, -16, 70, 11, -5, 79, -6, 7, 88, -23, 20, + 46, 78, -42, 48, 74, -40, 51, 63, -34, 57, 49, -25, + 64, 31, -15, 71, 14, -3, 79, -3, 8, 88, -20, 21, + 48, 80, -39, 49, 76, -37, 53, 66, -32, 58, 52, -24, + 65, 35, -13, 72, 17, -2, 80, 0, 10, 89, -17, 22, + 49, 81, -37, 51, 77, -35, 54, 68, -29, 59, 54, -22, + 66, 37, -12, 73, 20, -1, 81, 3, 11, 89, -14, 23, + 51, 83, -34, 52, 79, -32, 55, 70, -27, 60, 56, -20, + 66, 40, -10, 74, 23, 0, 81, 6, 12, 90, -11, 23, + 52, 84, -32, 53, 80, -30, 57, 72, -25, 61, 59, -18, + 67, 43, -9, 74, 26, 2, 82, 9, 13, 90, -8, 24, + 54, 86, -29, 55, 82, -27, 58, 74, -23, 63, 61, -16, + 69, 46, -7, 75, 29, 3, 83, 12, 14, 91, -5, 25, + 55, 87, -27, 56, 84, -25, 59, 76, -21, 64, 64, -14, + 70, 48, -5, 76, 32, 5, 84, 15, 15, 92, -2, 26, + 57, 89, -24, 58, 86, -23, 61, 78, -19, 65, 66, -12, + 71, 51, -4, 77, 35, 6, 84, 18, 16, 92, 1, 27, + 23, 62, -86, 27, 51, -79, 34, 31, -67, 43, 10, -53, + 53, -10, -37, 62, -27, -22, 72, -42, -7, 82, -56, 7, + 23, 62, -85, 27, 51, -79, 34, 31, -67, 43, 10, -53, + 53, -10, -37, 63, -27, -22, 72, -42, -7, 82, -56, 7, + 23, 62, -85, 27, 52, -79, 34, 32, -67, 43, 11, -53, + 53, -10, -37, 63, -27, -22, 72, -42, -7, 82, -56, 8, + 24, 63, -84, 27, 52, -78, 34, 32, -67, 43, 11, -52, + 53, -9, -37, 63, -26, -22, 72, -41, -7, 82, -55, 8, + 24, 63, -84, 27, 52, -78, 35, 33, -66, 43, 12, -52, + 53, -9, -37, 63, -26, -22, 72, -41, -7, 82, -55, 8, + 24, 63, -83, 28, 53, -77, 35, 33, -66, 43, 13, -52, + 53, -8, -36, 63, -25, -21, 73, -40, -7, 83, -54, 8, + 25, 63, -82, 28, 53, -76, 35, 34, -65, 44, 13, -51, + 53, -7, -36, 63, -24, -21, 73, -39, -6, 83, -54, 8, + 26, 64, -81, 29, 54, -75, 36, 35, -64, 44, 15, -51, + 54, -5, -36, 63, -23, -21, 73, -38, -6, 83, -53, 8, + 27, 64, -79, 30, 55, -74, 36, 36, -64, 44, 16, -50, + 54, -4, -35, 63, -22, -20, 73, -37, -6, 83, -52, 8, + 27, 64, -78, 30, 55, -73, 37, 38, -63, 45, 18, -49, + 54, -3, -35, 64, -20, -20, 73, -36, -6, 83, -50, 9, + 28, 65, -76, 31, 56, -72, 37, 39, -62, 45, 19, -49, + 55, -1, -34, 64, -19, -20, 73, -35, -5, 83, -49, 9, + 29, 65, -75, 32, 57, -70, 38, 40, -60, 46, 21, -48, + 55, 1, -33, 64, -17, -19, 74, -33, -5, 83, -48, 9, + 30, 66, -73, 33, 58, -68, 39, 42, -59, 46, 23, -47, + 55, 3, -33, 65, -15, -18, 74, -31, -4, 84, -46, 10, + 32, 67, -71, 34, 59, -67, 40, 44, -58, 47, 25, -46, + 56, 5, -32, 65, -13, -18, 74, -29, -4, 84, -45, 10, + 33, 68, -69, 35, 61, -65, 41, 45, -56, 48, 27, -45, + 56, 7, -31, 65, -11, -17, 75, -27, -3, 84, -43, 10, + 34, 69, -67, 36, 62, -63, 41, 47, -55, 49, 29, -43, + 57, 9, -30, 66, -9, -16, 75, -25, -3, 85, -41, 11, + 35, 70, -65, 38, 63, -61, 43, 49, -53, 49, 31, -42, + 58, 12, -29, 66, -6, -16, 75, -23, -2, 85, -39, 11, + 37, 71, -62, 39, 65, -59, 44, 51, -51, 50, 34, -41, + 58, 14, -28, 67, -4, -15, 76, -21, -2, 85, -36, 12, + 38, 72, -60, 40, 66, -57, 45, 53, -50, 51, 36, -39, + 59, 17, -27, 67, -1, -14, 76, -18, -1, 86, -34, 13, + 39, 73, -58, 41, 67, -55, 46, 55, -48, 52, 38, -38, + 60, 19, -26, 68, 1, -13, 77, -16, 0, 86, -32, 13, + 41, 74, -55, 43, 69, -52, 47, 57, -46, 53, 41, -36, + 61, 22, -24, 69, 4, -12, 77, -13, 1, 86, -29, 14, + 42, 76, -53, 44, 70, -50, 48, 59, -44, 54, 43, -35, + 61, 25, -23, 69, 7, -11, 78, -10, 2, 87, -27, 15, + 44, 77, -51, 45, 72, -48, 49, 61, -42, 55, 46, -33, + 62, 28, -22, 70, 10, -10, 78, -8, 3, 87, -24, 15, + 45, 78, -48, 47, 73, -46, 50, 63, -40, 56, 48, -31, + 63, 30, -20, 71, 12, -9, 79, -5, 3, 88, -21, 16, + 46, 79, -46, 48, 75, -44, 52, 65, -38, 57, 50, -30, + 64, 33, -19, 71, 15, -8, 80, -2, 4, 88, -19, 17, + 48, 81, -43, 50, 77, -41, 53, 67, -36, 58, 53, -28, + 65, 36, -17, 72, 18, -6, 80, 1, 5, 89, -16, 18, + 50, 82, -41, 51, 78, -39, 54, 69, -34, 59, 55, -26, + 66, 39, -16, 73, 21, -5, 81, 4, 7, 89, -13, 19, + 51, 84, -39, 52, 80, -36, 56, 71, -31, 60, 58, -24, + 67, 41, -14, 74, 24, -4, 82, 7, 8, 90, -10, 19, + 52, 85, -36, 54, 81, -34, 57, 73, -29, 61, 60, -22, + 68, 44, -13, 75, 27, -2, 82, 10, 9, 91, -7, 20, + 54, 87, -33, 55, 83, -32, 58, 75, -27, 63, 63, -20, + 69, 47, -11, 76, 30, -1, 83, 13, 10, 91, -4, 21, + 56, 88, -31, 57, 85, -29, 60, 77, -25, 64, 65, -18, + 70, 49, -9, 77, 33, 0, 84, 16, 11, 92, -1, 22, + 57, 90, -29, 58, 87, -27, 61, 79, -23, 65, 67, -16, + 71, 52, -8, 77, 36, 2, 85, 19, 12, 93, 2, 23, + 24, 64, -88, 28, 54, -83, 35, 34, -71, 43, 13, -57, + 53, -7, -41, 63, -25, -26, 73, -40, -11, 82, -54, 3, + 24, 64, -88, 28, 54, -82, 35, 35, -71, 43, 13, -57, + 53, -7, -41, 63, -24, -26, 73, -40, -11, 83, -54, 4, + 24, 64, -88, 28, 54, -82, 35, 35, -71, 43, 14, -56, + 53, -7, -41, 63, -24, -26, 73, -40, -11, 83, -54, 4, + 25, 65, -87, 28, 54, -82, 35, 35, -70, 44, 14, -56, + 53, -6, -41, 63, -24, -26, 73, -39, -11, 83, -53, 4, + 25, 65, -87, 28, 55, -81, 35, 36, -70, 44, 15, -56, + 53, -6, -41, 63, -23, -26, 73, -39, -11, 83, -53, 4, + 26, 65, -86, 29, 55, -80, 36, 36, -69, 44, 16, -56, + 54, -5, -40, 63, -22, -25, 73, -38, -11, 83, -52, 4, + 26, 65, -85, 29, 56, -80, 36, 37, -69, 44, 16, -55, + 54, -4, -40, 63, -22, -25, 73, -37, -10, 83, -52, 4, + 27, 65, -84, 30, 56, -79, 36, 38, -68, 45, 18, -55, + 54, -3, -40, 64, -20, -25, 73, -36, -10, 83, -51, 4, + 28, 66, -83, 31, 57, -77, 37, 39, -67, 45, 19, -54, + 54, -1, -39, 64, -19, -24, 73, -35, -10, 83, -50, 4, + 28, 66, -81, 31, 58, -76, 37, 40, -66, 45, 20, -53, + 55, 0, -39, 64, -18, -24, 73, -34, -10, 83, -49, 5, + 29, 67, -80, 32, 58, -75, 38, 42, -65, 46, 22, -52, + 55, 2, -38, 64, -16, -24, 74, -32, -9, 83, -47, 5, + 30, 67, -78, 33, 59, -74, 39, 43, -64, 46, 23, -52, + 55, 3, -37, 65, -15, -23, 74, -31, -9, 84, -46, 5, + 31, 68, -76, 34, 60, -72, 39, 45, -63, 47, 25, -51, + 56, 5, -37, 65, -13, -22, 74, -29, -8, 84, -44, 6, + 32, 69, -74, 35, 61, -70, 40, 46, -61, 48, 27, -50, + 56, 7, -36, 65, -11, -22, 75, -27, -8, 84, -43, 6, + 33, 69, -72, 36, 62, -69, 41, 48, -60, 48, 29, -48, + 57, 9, -35, 66, -9, -21, 75, -25, -7, 84, -41, 7, + 35, 70, -70, 37, 64, -67, 42, 49, -58, 49, 31, -47, + 57, 12, -34, 66, -7, -20, 75, -23, -7, 85, -39, 7, + 36, 71, -68, 38, 65, -65, 43, 51, -57, 50, 34, -46, + 58, 14, -33, 67, -4, -20, 76, -21, -6, 85, -37, 8, + 37, 72, -66, 39, 66, -63, 44, 53, -55, 51, 36, -45, + 59, 16, -32, 67, -2, -19, 76, -19, -6, 85, -35, 8, + 39, 73, -64, 41, 67, -61, 45, 55, -53, 51, 38, -43, + 59, 19, -31, 68, 1, -18, 77, -16, -5, 86, -33, 9, + 40, 74, -62, 42, 69, -59, 46, 56, -52, 52, 40, -42, + 60, 21, -30, 68, 3, -17, 77, -14, -4, 86, -30, 9, + 41, 76, -59, 43, 70, -56, 47, 59, -50, 53, 43, -40, + 61, 24, -28, 69, 6, -16, 78, -11, -3, 87, -28, 10, + 43, 77, -57, 44, 72, -54, 48, 60, -48, 54, 45, -39, + 62, 27, -27, 70, 9, -15, 78, -9, -2, 87, -25, 11, + 44, 78, -55, 46, 73, -52, 50, 62, -46, 55, 47, -37, + 62, 29, -26, 70, 11, -14, 79, -6, -1, 87, -23, 11, + 46, 79, -52, 47, 75, -50, 51, 64, -44, 56, 49, -35, + 63, 32, -24, 71, 14, -13, 79, -3, -1, 88, -20, 12, + 47, 81, -50, 48, 76, -48, 52, 66, -42, 57, 52, -34, + 64, 34, -23, 72, 17, -12, 80, -1, 0, 88, -17, 13, + 49, 82, -47, 50, 78, -45, 53, 68, -40, 58, 54, -32, + 65, 37, -21, 73, 20, -10, 80, 3, 1, 89, -14, 14, + 50, 83, -45, 51, 79, -43, 55, 70, -38, 60, 57, -30, + 66, 40, -20, 73, 23, -9, 81, 5, 3, 90, -12, 15, + 51, 85, -43, 53, 81, -40, 56, 72, -35, 61, 59, -28, + 67, 42, -18, 74, 25, -8, 82, 8, 4, 90, -9, 16, + 53, 86, -40, 54, 82, -38, 57, 74, -33, 62, 61, -26, + 68, 45, -17, 75, 28, -6, 83, 11, 5, 91, -6, 16, + 55, 88, -37, 56, 84, -36, 59, 76, -31, 63, 64, -24, + 69, 48, -15, 76, 31, -5, 83, 14, 6, 91, -3, 18, + 56, 89, -35, 57, 86, -33, 60, 78, -29, 64, 66, -22, + 70, 51, -13, 77, 34, -4, 84, 17, 7, 92, 0, 19, + 57, 91, -33, 59, 87, -31, 61, 80, -27, 65, 68, -20, + 71, 53, -12, 78, 37, -2, 85, 20, 8, 93, 3, 20, + 25, 67, -91, 29, 57, -86, 35, 38, -75, 44, 17, -61, + 53, -4, -46, 63, -22, -30, 73, -37, -16, 83, -52, -1, + 26, 67, -91, 29, 57, -86, 36, 38, -75, 44, 17, -61, + 54, -4, -45, 63, -21, -30, 73, -37, -16, 83, -51, -1, + 26, 67, -91, 29, 57, -85, 36, 38, -74, 44, 17, -61, + 54, -3, -45, 63, -21, -30, 73, -37, -16, 83, -51, -1, + 26, 67, -90, 29, 57, -85, 36, 39, -74, 44, 18, -60, + 54, -3, -45, 63, -21, -30, 73, -36, -15, 83, -51, -1, + 26, 67, -90, 30, 57, -84, 36, 39, -74, 44, 18, -60, + 54, -2, -45, 63, -20, -30, 73, -36, -15, 83, -50, -1, + 27, 67, -89, 30, 58, -84, 36, 40, -73, 45, 19, -60, + 54, -1, -45, 64, -19, -30, 73, -35, -15, 83, -50, -1, + 27, 67, -88, 30, 58, -83, 37, 40, -73, 45, 20, -59, + 54, -1, -44, 64, -19, -30, 73, -35, -15, 83, -49, 0, + 28, 68, -87, 31, 59, -82, 37, 41, -72, 45, 21, -59, + 54, 1, -44, 64, -17, -29, 73, -34, -15, 83, -48, 0, + 29, 68, -86, 32, 59, -81, 38, 42, -71, 46, 22, -58, + 55, 2, -43, 64, -16, -29, 74, -33, -14, 83, -47, 0, + 29, 68, -85, 32, 60, -80, 38, 43, -70, 46, 23, -58, + 55, 3, -43, 64, -15, -28, 74, -31, -14, 83, -46, 0, + 30, 69, -83, 33, 61, -79, 39, 44, -69, 46, 25, -57, + 55, 5, -42, 65, -14, -28, 74, -30, -14, 84, -45, 1, + 31, 69, -82, 34, 62, -77, 39, 46, -68, 47, 26, -56, + 56, 6, -42, 65, -12, -28, 74, -29, -13, 84, -44, 1, + 32, 70, -80, 35, 63, -76, 40, 47, -67, 48, 28, -55, + 56, 8, -41, 65, -10, -27, 75, -27, -13, 84, -42, 1, + 33, 71, -78, 36, 63, -74, 41, 49, -65, 48, 30, -54, + 57, 10, -40, 66, -8, -26, 75, -25, -12, 84, -41, 2, + 34, 71, -76, 37, 64, -72, 42, 50, -64, 49, 32, -53, + 57, 12, -39, 66, -6, -26, 75, -23, -12, 85, -39, 2, + 36, 72, -74, 38, 66, -71, 43, 52, -63, 49, 34, -52, + 58, 14, -38, 66, -4, -25, 75, -21, -11, 85, -37, 3, + 37, 73, -72, 39, 67, -69, 44, 53, -61, 50, 36, -50, + 58, 17, -37, 67, -2, -24, 76, -19, -11, 85, -35, 3, + 38, 74, -70, 40, 68, -67, 45, 55, -59, 51, 38, -49, + 59, 19, -36, 68, 0, -23, 76, -17, -10, 86, -33, 4, + 39, 75, -68, 41, 69, -65, 46, 57, -58, 52, 40, -48, + 60, 21, -35, 68, 3, -22, 77, -14, -9, 86, -31, 4, + 41, 76, -66, 42, 71, -63, 47, 58, -56, 53, 42, -46, + 60, 23, -34, 69, 5, -22, 77, -12, -9, 86, -28, 5, + 42, 77, -63, 44, 72, -60, 48, 60, -54, 54, 45, -45, + 61, 26, -33, 69, 8, -20, 78, -9, -8, 87, -26, 6, + 43, 78, -61, 45, 73, -58, 49, 62, -52, 55, 47, -43, + 62, 29, -32, 70, 11, -19, 78, -7, -7, 87, -23, 6, + 45, 79, -59, 46, 75, -56, 50, 64, -50, 56, 49, -41, + 63, 31, -30, 71, 13, -18, 79, -4, -6, 88, -21, 7, + 46, 81, -57, 48, 76, -54, 51, 66, -48, 57, 51, -40, + 64, 34, -29, 71, 16, -17, 79, -2, -5, 88, -18, 8, + 48, 82, -54, 49, 78, -52, 52, 68, -46, 58, 53, -38, + 64, 36, -28, 72, 18, -16, 80, 1, -4, 89, -16, 8, + 49, 83, -52, 50, 79, -49, 54, 70, -44, 59, 56, -36, + 65, 39, -26, 73, 22, -15, 81, 4, -3, 89, -13, 9, + 50, 85, -49, 52, 81, -47, 55, 71, -42, 60, 58, -34, + 66, 41, -24, 74, 24, -14, 81, 7, -2, 90, -10, 10, + 52, 86, -47, 53, 82, -45, 56, 73, -40, 61, 60, -33, + 67, 44, -23, 74, 27, -12, 82, 10, -1, 90, -7, 11, + 53, 87, -45, 55, 84, -43, 58, 75, -38, 62, 62, -31, + 68, 47, -21, 75, 30, -11, 83, 13, 0, 91, -5, 12, + 55, 89, -42, 56, 85, -40, 59, 77, -36, 63, 65, -29, + 69, 49, -20, 76, 33, -9, 84, 16, 1, 92, -1, 13, + 56, 90, -40, 58, 87, -38, 60, 79, -33, 65, 67, -27, + 70, 52, -18, 77, 35, -8, 84, 19, 3, 92, 1, 14, + 58, 92, -37, 59, 88, -35, 62, 81, -31, 66, 69, -25, + 71, 54, -16, 78, 38, -7, 85, 21, 4, 93, 4, 15, + 27, 69, -94, 30, 59, -89, 36, 41, -78, 44, 20, -65, + 54, -1, -49, 63, -19, -34, 73, -35, -20, 83, -49, -5, + 27, 69, -94, 30, 59, -89, 36, 41, -78, 45, 20, -64, + 54, -1, -49, 63, -19, -34, 73, -35, -20, 83, -49, -5, + 27, 69, -94, 30, 59, -88, 36, 41, -78, 45, 20, -64, + 54, 0, -49, 64, -18, -34, 73, -34, -19, 83, -49, -5, + 27, 69, -93, 30, 60, -88, 37, 42, -77, 45, 21, -64, + 54, 0, -49, 64, -18, -34, 73, -34, -19, 83, -49, -5, + 27, 69, -93, 30, 60, -88, 37, 42, -77, 45, 21, -64, + 54, 1, -49, 64, -17, -34, 73, -33, -19, 83, -48, -5, + 28, 69, -92, 31, 60, -87, 37, 42, -77, 45, 22, -63, + 54, 1, -49, 64, -17, -34, 73, -33, -19, 83, -48, -4, + 28, 69, -91, 31, 60, -86, 37, 43, -76, 45, 23, -63, + 55, 2, -48, 64, -16, -33, 73, -32, -19, 83, -47, -4, + 29, 70, -90, 32, 61, -85, 38, 44, -75, 46, 24, -62, + 55, 3, -48, 64, -15, -33, 74, -31, -19, 83, -46, -4, + 30, 70, -89, 32, 62, -84, 38, 45, -75, 46, 25, -62, + 55, 5, -47, 64, -14, -33, 74, -30, -18, 84, -45, -4, + 30, 70, -88, 33, 62, -83, 39, 46, -74, 46, 26, -61, + 55, 6, -47, 65, -13, -32, 74, -29, -18, 84, -44, -4, + 31, 71, -86, 34, 63, -82, 39, 47, -73, 47, 28, -60, + 56, 7, -46, 65, -11, -32, 74, -28, -18, 84, -43, -3, + 32, 71, -85, 35, 64, -81, 40, 48, -72, 47, 29, -60, + 56, 9, -46, 65, -10, -32, 74, -26, -17, 84, -42, -3, + 33, 72, -83, 36, 65, -79, 41, 49, -70, 48, 31, -59, + 57, 11, -45, 66, -8, -31, 75, -25, -17, 84, -40, -3, + 34, 72, -81, 36, 65, -77, 42, 51, -69, 49, 32, -58, + 57, 12, -44, 66, -6, -30, 75, -23, -16, 85, -39, -2, + 35, 73, -80, 37, 66, -76, 42, 52, -68, 49, 34, -57, + 58, 14, -43, 66, -4, -30, 75, -21, -16, 85, -37, -2, + 36, 74, -78, 38, 67, -74, 43, 54, -66, 50, 36, -55, + 58, 16, -42, 67, -2, -29, 76, -19, -15, 85, -35, -1, + 38, 75, -76, 40, 69, -72, 44, 55, -65, 51, 38, -54, + 59, 19, -41, 67, 0, -28, 76, -17, -15, 85, -33, -1, + 39, 76, -74, 41, 70, -70, 45, 57, -63, 52, 40, -53, + 59, 21, -40, 68, 3, -27, 77, -15, -14, 86, -31, 0, + 40, 76, -71, 42, 71, -68, 46, 59, -61, 52, 42, -51, + 60, 23, -39, 68, 5, -26, 77, -13, -13, 86, -29, 0, + 41, 77, -69, 43, 72, -66, 47, 60, -60, 53, 44, -50, + 61, 25, -38, 69, 7, -26, 77, -10, -13, 87, -27, 1, + 43, 79, -67, 44, 73, -64, 48, 62, -58, 54, 46, -48, + 62, 28, -37, 70, 10, -24, 78, -7, -12, 87, -24, 2, + 44, 80, -65, 46, 75, -62, 49, 64, -56, 55, 48, -47, + 62, 30, -36, 70, 12, -23, 79, -5, -11, 87, -22, 2, + 45, 81, -63, 47, 76, -60, 51, 65, -54, 56, 51, -45, + 63, 33, -34, 71, 15, -22, 79, -2, -10, 88, -19, 3, + 47, 82, -60, 48, 77, -58, 52, 67, -52, 57, 53, -44, + 64, 35, -33, 72, 17, -21, 80, 0, -9, 88, -17, 4, + 48, 83, -58, 49, 79, -56, 53, 69, -50, 58, 55, -42, + 65, 38, -32, 72, 20, -20, 80, 3, -8, 89, -14, 5, + 50, 85, -55, 51, 80, -53, 54, 71, -48, 59, 57, -40, + 66, 40, -30, 73, 23, -19, 81, 6, -7, 89, -11, 5, + 51, 86, -53, 52, 82, -51, 55, 73, -46, 60, 59, -38, + 67, 43, -28, 74, 26, -18, 82, 8, -6, 90, -9, 6, + 52, 87, -51, 54, 83, -49, 57, 74, -44, 61, 62, -37, + 68, 45, -27, 75, 28, -16, 82, 11, -5, 91, -6, 7, + 54, 88, -48, 55, 85, -47, 58, 76, -42, 62, 64, -35, + 69, 48, -25, 75, 31, -15, 83, 14, -4, 91, -3, 8, + 55, 90, -46, 57, 86, -44, 59, 78, -40, 64, 66, -33, + 70, 51, -24, 76, 34, -13, 84, 17, -3, 92, 0, 9, + 57, 91, -44, 58, 88, -42, 61, 80, -37, 65, 68, -31, + 71, 53, -22, 77, 37, -12, 84, 20, -1, 92, 3, 10, + 58, 93, -41, 59, 89, -39, 62, 82, -35, 66, 70, -29, + 72, 56, -20, 78, 39, -11, 85, 23, 0, 93, 6, 11, + 28, 71, -97, 31, 61, -92, 37, 44, -81, 45, 23, -68, + 54, 2, -53, 64, -16, -38, 73, -32, -24, 83, -47, -9, + 28, 71, -97, 31, 62, -92, 37, 44, -81, 45, 23, -68, + 54, 3, -53, 64, -16, -38, 73, -32, -23, 83, -47, -9, + 28, 71, -96, 31, 62, -91, 37, 44, -81, 45, 24, -68, + 54, 3, -53, 64, -15, -38, 73, -32, -23, 83, -47, -9, + 28, 71, -96, 31, 62, -91, 37, 44, -81, 45, 24, -68, + 55, 3, -53, 64, -15, -38, 73, -31, -23, 83, -46, -9, + 29, 71, -95, 31, 62, -90, 38, 45, -80, 46, 24, -67, + 55, 4, -53, 64, -15, -38, 74, -31, -23, 83, -46, -8, + 29, 71, -95, 32, 62, -90, 38, 45, -80, 46, 25, -67, + 55, 4, -52, 64, -14, -38, 74, -30, -23, 83, -46, -8, + 29, 71, -94, 32, 63, -89, 38, 46, -79, 46, 26, -67, + 55, 5, -52, 64, -13, -37, 74, -30, -23, 83, -45, -8, + 30, 72, -93, 33, 63, -88, 39, 47, -79, 46, 27, -66, + 55, 6, -52, 65, -12, -37, 74, -29, -23, 84, -44, -8, + 31, 72, -92, 33, 64, -87, 39, 47, -78, 47, 28, -66, + 56, 7, -51, 65, -11, -37, 74, -28, -22, 84, -43, -8, + 31, 72, -91, 34, 64, -86, 40, 48, -77, 47, 29, -65, + 56, 9, -51, 65, -10, -36, 74, -27, -22, 84, -42, -8, + 32, 73, -89, 35, 65, -85, 40, 49, -76, 47, 30, -64, + 56, 10, -50, 65, -9, -36, 74, -25, -22, 84, -41, -7, + 33, 73, -88, 35, 66, -84, 41, 50, -75, 48, 32, -63, + 57, 11, -49, 66, -7, -35, 75, -24, -21, 84, -40, -7, + 34, 74, -86, 36, 67, -82, 42, 52, -74, 49, 33, -62, + 57, 13, -49, 66, -5, -35, 75, -22, -21, 85, -38, -7, + 35, 74, -85, 37, 67, -81, 42, 53, -73, 49, 35, -61, + 58, 15, -48, 66, -4, -34, 75, -21, -20, 85, -37, -6, + 36, 75, -83, 38, 68, -79, 43, 54, -71, 50, 36, -60, + 58, 17, -47, 67, -2, -34, 76, -19, -20, 85, -35, -6, + 37, 75, -81, 39, 69, -78, 44, 56, -70, 50, 38, -59, + 59, 19, -46, 67, 0, -33, 76, -17, -19, 85, -33, -5, + 38, 76, -79, 40, 70, -76, 45, 57, -68, 51, 40, -58, + 59, 21, -45, 68, 2, -32, 76, -15, -19, 86, -31, -5, + 39, 77, -77, 41, 71, -74, 46, 59, -67, 52, 42, -57, + 60, 23, -44, 68, 5, -31, 77, -13, -18, 86, -29, -4, + 41, 78, -75, 43, 73, -72, 47, 60, -65, 53, 44, -55, + 60, 25, -43, 69, 7, -30, 77, -11, -17, 86, -27, -4, + 42, 79, -73, 44, 74, -70, 48, 62, -63, 54, 46, -54, + 61, 27, -42, 69, 9, -29, 78, -8, -16, 87, -25, -3, + 43, 80, -71, 45, 75, -68, 49, 64, -61, 55, 48, -52, + 62, 30, -41, 70, 12, -28, 78, -6, -16, 87, -23, -2, + 45, 81, -68, 46, 76, -66, 50, 65, -60, 56, 50, -51, + 63, 32, -39, 70, 14, -27, 79, -3, -15, 88, -20, -2, + 46, 82, -66, 47, 78, -64, 51, 67, -58, 56, 52, -49, + 63, 35, -38, 71, 17, -26, 79, -1, -14, 88, -18, -1, + 47, 83, -64, 49, 79, -62, 52, 69, -56, 57, 54, -48, + 64, 37, -37, 72, 19, -25, 80, 2, -13, 89, -15, 0, + 49, 84, -62, 50, 80, -59, 53, 70, -54, 58, 56, -46, + 65, 39, -35, 73, 22, -24, 80, 4, -12, 89, -13, 1, + 50, 86, -59, 51, 82, -57, 55, 72, -52, 60, 59, -44, + 66, 42, -34, 73, 25, -23, 81, 7, -11, 90, -10, 2, + 51, 87, -57, 53, 83, -55, 56, 74, -50, 61, 61, -42, + 67, 44, -32, 74, 27, -22, 82, 10, -10, 90, -7, 2, + 53, 88, -55, 54, 84, -53, 57, 76, -48, 62, 63, -41, + 68, 47, -31, 75, 30, -20, 82, 13, -9, 91, -5, 3, + 54, 89, -52, 55, 86, -50, 58, 77, -46, 63, 65, -39, + 69, 49, -29, 76, 32, -19, 83, 15, -8, 91, -2, 4, + 56, 91, -50, 57, 88, -48, 60, 79, -43, 64, 67, -37, + 70, 52, -28, 77, 35, -17, 84, 18, -6, 92, 1, 5, + 57, 92, -47, 58, 89, -46, 61, 81, -41, 65, 69, -35, + 71, 54, -26, 77, 38, -16, 85, 21, -5, 93, 4, 6, + 59, 94, -45, 60, 90, -43, 62, 83, -39, 66, 72, -33, + 72, 57, -24, 78, 41, -15, 85, 24, -4, 93, 7, 7, + 29, 73, -99, 32, 64, -95, 38, 47, -85, 46, 26, -72, + 55, 5, -57, 64, -13, -42, 74, -30, -27, 83, -45, -13, + 29, 73, -99, 32, 64, -94, 38, 47, -84, 46, 26, -72, + 55, 6, -57, 64, -13, -42, 74, -29, -27, 83, -45, -13, + 29, 73, -99, 32, 64, -94, 38, 47, -84, 46, 27, -71, + 55, 6, -57, 64, -13, -42, 74, -29, -27, 83, -45, -13, + 29, 73, -98, 32, 64, -94, 38, 47, -84, 46, 27, -71, + 55, 6, -57, 64, -12, -42, 74, -29, -27, 83, -44, -12, + 30, 73, -98, 32, 64, -93, 38, 48, -84, 46, 28, -71, + 55, 7, -56, 64, -12, -42, 74, -28, -27, 84, -44, -12, + 30, 73, -97, 33, 65, -93, 39, 48, -83, 46, 28, -71, + 55, 7, -56, 65, -11, -41, 74, -28, -27, 84, -43, -12, + 31, 73, -97, 33, 65, -92, 39, 49, -83, 47, 29, -70, + 55, 8, -56, 65, -10, -41, 74, -27, -27, 84, -43, -12, + 31, 73, -96, 34, 66, -91, 39, 49, -82, 47, 30, -70, + 56, 9, -55, 65, -9, -41, 74, -26, -26, 84, -42, -12, + 32, 74, -95, 34, 66, -90, 40, 50, -81, 47, 31, -69, + 56, 10, -55, 65, -8, -41, 74, -25, -26, 84, -41, -12, + 32, 74, -93, 35, 66, -89, 40, 51, -80, 48, 32, -68, + 56, 11, -54, 65, -7, -40, 75, -24, -26, 84, -40, -11, + 33, 74, -92, 36, 67, -88, 41, 52, -79, 48, 33, -68, + 57, 13, -54, 66, -6, -40, 75, -23, -26, 84, -39, -11, + 34, 75, -91, 36, 68, -87, 41, 53, -78, 49, 34, -67, + 57, 14, -53, 66, -5, -39, 75, -22, -25, 85, -38, -11, + 35, 75, -89, 37, 69, -85, 42, 54, -77, 49, 36, -66, + 57, 16, -52, 66, -3, -39, 75, -20, -25, 85, -36, -10, + 36, 76, -88, 38, 69, -84, 43, 55, -76, 50, 37, -65, + 58, 17, -52, 67, -1, -38, 76, -18, -24, 85, -35, -10, + 37, 76, -86, 39, 70, -83, 44, 57, -75, 50, 39, -64, + 58, 19, -51, 67, 1, -37, 76, -17, -24, 85, -33, -10, + 38, 77, -84, 40, 71, -81, 44, 58, -73, 51, 41, -63, + 59, 21, -50, 67, 2, -37, 76, -15, -23, 86, -31, -9, + 39, 78, -82, 41, 72, -79, 45, 59, -72, 52, 42, -62, + 60, 23, -49, 68, 5, -36, 77, -13, -22, 86, -29, -9, + 40, 79, -80, 42, 73, -77, 46, 61, -70, 53, 44, -60, + 60, 25, -48, 68, 7, -35, 77, -11, -22, 86, -27, -8, + 41, 80, -78, 43, 74, -75, 47, 62, -69, 53, 46, -59, + 61, 27, -47, 69, 9, -34, 78, -9, -21, 87, -25, -8, + 43, 80, -76, 44, 75, -74, 48, 64, -67, 54, 48, -58, + 62, 29, -46, 70, 11, -33, 78, -6, -20, 87, -23, -7, + 44, 81, -74, 46, 77, -71, 49, 65, -65, 55, 50, -56, + 62, 32, -45, 70, 14, -32, 79, -4, -19, 87, -21, -6, + 45, 82, -72, 47, 78, -69, 51, 67, -63, 56, 52, -55, + 63, 34, -43, 71, 16, -31, 79, -1, -19, 88, -18, -5, + 46, 83, -70, 48, 79, -67, 52, 69, -61, 57, 54, -53, + 64, 36, -42, 71, 18, -30, 80, 1, -18, 88, -16, -5, + 48, 85, -68, 49, 80, -65, 53, 70, -60, 58, 56, -51, + 65, 39, -41, 72, 21, -29, 80, 3, -17, 89, -14, -4, + 49, 86, -65, 51, 81, -63, 54, 72, -58, 59, 58, -50, + 65, 41, -39, 73, 23, -28, 81, 6, -16, 89, -11, -3, + 51, 87, -63, 52, 83, -61, 55, 74, -56, 60, 60, -48, + 66, 44, -38, 74, 26, -27, 81, 9, -15, 90, -8, -2, + 52, 88, -61, 53, 84, -59, 56, 75, -54, 61, 62, -46, + 67, 46, -36, 74, 29, -25, 82, 11, -14, 90, -6, -1, + 53, 89, -58, 55, 86, -56, 58, 77, -52, 62, 64, -44, + 68, 48, -35, 75, 31, -24, 83, 14, -13, 91, -3, -1, + 55, 91, -56, 56, 87, -54, 59, 79, -50, 63, 66, -43, + 69, 51, -33, 76, 34, -23, 83, 17, -12, 92, -1, 0, + 56, 92, -54, 57, 89, -52, 60, 81, -47, 64, 69, -41, + 70, 53, -32, 77, 37, -21, 84, 20, -10, 92, 3, 1, + 58, 93, -51, 59, 90, -49, 61, 82, -45, 66, 71, -39, + 71, 56, -30, 78, 39, -20, 85, 22, -9, 93, 5, 2, + 59, 95, -49, 60, 92, -47, 63, 84, -43, 67, 73, -37, + 72, 58, -28, 79, 42, -19, 86, 25, -8, 94, 8, 3, + 30, 75, -102, 33, 66, -98, 39, 50, -88, 46, 30, -76, + 55, 9, -61, 65, -10, -46, 74, -27, -32, 84, -42, -17, + 30, 75, -102, 33, 67, -98, 39, 50, -88, 46, 30, -75, + 55, 9, -61, 65, -10, -46, 74, -27, -32, 84, -42, -17, + 30, 75, -102, 33, 67, -97, 39, 50, -88, 47, 30, -75, + 55, 9, -61, 65, -9, -46, 74, -26, -32, 84, -42, -17, + 31, 75, -101, 33, 67, -97, 39, 50, -88, 47, 31, -75, + 56, 10, -61, 65, -9, -46, 74, -26, -32, 84, -42, -17, + 31, 75, -101, 34, 67, -97, 39, 51, -87, 47, 31, -75, + 56, 10, -60, 65, -9, -46, 74, -25, -31, 84, -41, -17, + 31, 75, -100, 34, 67, -96, 40, 51, -87, 47, 31, -75, + 56, 11, -60, 65, -8, -46, 74, -25, -31, 84, -41, -17, + 32, 75, -100, 34, 68, -95, 40, 52, -86, 47, 32, -74, + 56, 11, -60, 65, -7, -46, 74, -24, -31, 84, -40, -16, + 32, 76, -99, 35, 68, -95, 40, 52, -86, 48, 33, -74, + 56, 12, -60, 65, -6, -45, 75, -23, -31, 84, -39, -16, + 33, 76, -98, 35, 68, -94, 41, 53, -85, 48, 34, -73, + 57, 13, -59, 65, -5, -45, 75, -22, -31, 84, -38, -16, + 34, 76, -97, 36, 69, -93, 41, 54, -84, 48, 35, -72, + 57, 15, -59, 66, -4, -44, 75, -21, -30, 84, -37, -16, + 34, 76, -96, 37, 69, -92, 42, 55, -83, 49, 36, -72, + 57, 16, -58, 66, -3, -44, 75, -20, -30, 85, -36, -15, + 35, 77, -94, 37, 70, -91, 42, 56, -82, 49, 37, -71, + 58, 17, -57, 66, -2, -44, 75, -19, -30, 85, -35, -15, + 36, 77, -93, 38, 71, -89, 43, 57, -81, 50, 39, -70, + 58, 19, -57, 67, 0, -43, 76, -17, -29, 85, -34, -15, + 37, 78, -91, 39, 71, -88, 44, 58, -80, 50, 40, -69, + 58, 20, -56, 67, 2, -42, 76, -16, -29, 85, -32, -14, + 38, 78, -90, 40, 72, -86, 44, 59, -79, 51, 42, -68, + 59, 22, -55, 67, 3, -42, 76, -14, -28, 86, -31, -14, + 39, 79, -88, 41, 73, -85, 45, 60, -77, 52, 43, -67, + 59, 24, -54, 68, 5, -41, 77, -12, -27, 86, -29, -14, + 40, 80, -86, 42, 74, -83, 46, 62, -76, 52, 45, -66, + 60, 26, -53, 68, 7, -40, 77, -10, -27, 86, -27, -13, + 41, 80, -84, 43, 75, -81, 47, 63, -74, 53, 47, -64, + 61, 28, -52, 69, 9, -39, 77, -8, -26, 86, -25, -12, + 42, 81, -82, 44, 76, -79, 48, 64, -73, 54, 48, -63, + 61, 30, -51, 69, 11, -39, 78, -6, -25, 87, -23, -12, + 43, 82, -80, 45, 77, -77, 49, 66, -71, 55, 50, -62, + 62, 32, -50, 70, 13, -38, 78, -4, -25, 87, -21, -11, + 45, 83, -78, 46, 78, -75, 50, 67, -69, 56, 52, -60, + 63, 34, -49, 71, 16, -37, 79, -2, -24, 88, -19, -11, + 46, 84, -76, 47, 79, -73, 51, 69, -67, 57, 54, -59, + 63, 36, -48, 71, 18, -36, 79, 1, -23, 88, -16, -10, + 47, 85, -74, 49, 81, -71, 52, 70, -66, 57, 56, -57, + 64, 38, -46, 72, 21, -35, 80, 3, -22, 89, -14, -9, + 48, 86, -72, 50, 82, -69, 53, 72, -64, 58, 58, -56, + 65, 41, -45, 72, 23, -34, 80, 5, -21, 89, -12, -8, + 50, 87, -69, 51, 83, -67, 54, 74, -62, 59, 60, -54, + 66, 43, -44, 73, 25, -32, 81, 8, -20, 90, -9, -8, + 51, 88, -67, 53, 84, -65, 56, 75, -60, 60, 62, -52, + 67, 45, -42, 74, 28, -31, 82, 11, -19, 90, -7, -7, + 53, 90, -65, 54, 86, -63, 57, 77, -58, 62, 64, -50, + 68, 48, -41, 75, 31, -30, 82, 13, -18, 91, -4, -6, + 54, 91, -63, 55, 87, -61, 58, 79, -56, 63, 66, -49, + 69, 50, -39, 75, 33, -29, 83, 16, -17, 91, -1, -5, + 55, 92, -60, 56, 88, -58, 59, 80, -54, 64, 68, -47, + 70, 52, -38, 76, 36, -27, 84, 18, -16, 92, 1, -4, + 57, 93, -58, 58, 90, -56, 61, 82, -52, 65, 70, -45, + 71, 55, -36, 77, 38, -26, 84, 21, -15, 92, 4, -3, + 58, 95, -56, 59, 91, -54, 62, 84, -50, 66, 72, -43, + 72, 57, -34, 78, 41, -24, 85, 24, -14, 93, 7, -2, + 60, 96, -53, 61, 93, -52, 63, 85, -47, 67, 74, -41, + 73, 59, -33, 79, 43, -23, 86, 27, -12, 94, 9, -1, + 31, 77, -105, 34, 69, -101, 40, 53, -91, 47, 33, -79, + 56, 12, -65, 65, -7, -50, 74, -24, -36, 84, -40, -21, + 31, 77, -105, 34, 69, -100, 40, 53, -91, 47, 33, -79, + 56, 12, -65, 65, -7, -50, 74, -24, -36, 84, -40, -21, + 32, 77, -105, 34, 69, -100, 40, 53, -91, 47, 33, -79, + 56, 12, -64, 65, -6, -50, 74, -24, -35, 84, -39, -21, + 32, 77, -104, 34, 69, -100, 40, 53, -91, 47, 34, -79, + 56, 13, -64, 65, -6, -50, 74, -23, -35, 84, -39, -21, + 32, 77, -104, 35, 69, -100, 40, 53, -90, 47, 34, -78, + 56, 13, -64, 65, -6, -50, 74, -23, -35, 84, -39, -21, + 32, 77, -103, 35, 69, -99, 40, 54, -90, 48, 34, -78, + 56, 14, -64, 65, -5, -50, 75, -22, -35, 84, -38, -20, + 33, 77, -102, 35, 70, -98, 41, 54, -90, 48, 35, -78, + 57, 14, -64, 65, -4, -49, 75, -22, -35, 84, -38, -20, + 33, 77, -102, 36, 70, -98, 41, 55, -89, 48, 36, -77, + 57, 15, -63, 66, -4, -49, 75, -21, -35, 84, -37, -20, + 34, 78, -101, 36, 71, -97, 41, 56, -88, 48, 37, -77, + 57, 16, -63, 66, -3, -49, 75, -20, -34, 84, -36, -20, + 35, 78, -100, 37, 71, -96, 42, 56, -87, 49, 38, -76, + 57, 17, -62, 66, -2, -48, 75, -19, -34, 85, -35, -20, + 35, 78, -98, 37, 71, -95, 42, 57, -86, 49, 39, -75, + 58, 18, -62, 66, 0, -48, 75, -18, -34, 85, -34, -19, + 36, 79, -97, 38, 72, -94, 43, 58, -86, 50, 40, -74, + 58, 20, -61, 67, 1, -47, 76, -17, -33, 85, -33, -19, + 37, 79, -96, 39, 73, -92, 44, 59, -84, 50, 41, -74, + 58, 21, -60, 67, 3, -47, 76, -15, -33, 85, -31, -19, + 38, 80, -94, 40, 73, -91, 44, 60, -83, 51, 43, -73, + 59, 23, -60, 67, 4, -46, 76, -13, -32, 86, -30, -18, + 39, 80, -93, 41, 74, -89, 45, 61, -82, 51, 44, -72, + 59, 24, -59, 68, 6, -46, 77, -12, -32, 86, -29, -18, + 40, 81, -91, 42, 75, -88, 46, 62, -81, 52, 45, -71, + 60, 26, -58, 68, 7, -45, 77, -10, -31, 86, -27, -17, + 41, 81, -89, 43, 76, -86, 47, 64, -79, 53, 47, -69, + 60, 28, -57, 69, 10, -44, 77, -8, -31, 86, -25, -17, + 42, 82, -87, 44, 77, -84, 48, 65, -78, 54, 49, -68, + 61, 30, -56, 69, 11, -43, 78, -6, -30, 87, -23, -16, + 43, 83, -85, 45, 78, -83, 49, 66, -76, 54, 50, -67, + 62, 32, -55, 70, 13, -42, 78, -4, -29, 87, -21, -16, + 44, 84, -84, 46, 79, -81, 50, 68, -75, 55, 52, -65, + 62, 34, -54, 70, 16, -42, 79, -2, -29, 87, -19, -15, + 45, 85, -81, 47, 80, -79, 51, 69, -73, 56, 54, -64, + 63, 36, -53, 71, 18, -40, 79, 0, -28, 88, -17, -14, + 47, 86, -79, 48, 81, -77, 52, 71, -71, 57, 56, -62, + 64, 38, -51, 71, 20, -39, 80, 3, -27, 88, -15, -14, + 48, 86, -77, 49, 82, -75, 53, 72, -69, 58, 58, -61, + 65, 40, -50, 72, 22, -38, 80, 5, -26, 89, -12, -13, + 49, 87, -75, 50, 83, -73, 54, 74, -67, 59, 60, -59, + 65, 42, -49, 73, 25, -37, 81, 7, -25, 89, -10, -12, + 50, 88, -73, 52, 84, -71, 55, 75, -66, 60, 61, -58, + 66, 45, -48, 73, 27, -36, 81, 10, -24, 90, -8, -11, + 52, 90, -71, 53, 86, -68, 56, 77, -63, 61, 64, -56, + 67, 47, -46, 74, 30, -35, 82, 12, -23, 90, -5, -11, + 53, 91, -68, 54, 87, -66, 57, 78, -62, 62, 65, -54, + 68, 49, -45, 75, 32, -34, 83, 15, -22, 91, -2, -10, + 54, 92, -66, 56, 88, -64, 59, 80, -60, 63, 67, -52, + 69, 52, -43, 76, 35, -32, 83, 17, -21, 91, 0, -9, + 56, 93, -64, 57, 90, -62, 60, 81, -58, 64, 69, -51, + 70, 54, -42, 77, 37, -31, 84, 20, -20, 92, 3, -8, + 57, 94, -62, 58, 91, -60, 61, 83, -55, 65, 71, -49, + 71, 56, -40, 77, 40, -30, 85, 23, -19, 93, 6, -7, + 59, 96, -59, 60, 92, -58, 62, 85, -53, 66, 73, -47, + 72, 59, -38, 78, 42, -28, 85, 25, -17, 93, 8, -6, + 60, 97, -57, 61, 94, -55, 64, 86, -51, 67, 75, -45, + 73, 61, -37, 79, 45, -27, 86, 28, -16, 94, 11, -5, + 32, 79, -108, 35, 71, -103, 40, 55, -94, 48, 36, -82, + 56, 15, -68, 65, -4, -54, 75, -21, -39, 84, -37, -25, + 33, 79, -107, 35, 71, -103, 40, 55, -94, 48, 36, -82, + 56, 15, -68, 65, -4, -54, 75, -21, -39, 84, -37, -25, + 33, 79, -107, 35, 71, -103, 41, 56, -94, 48, 36, -82, + 56, 15, -68, 65, -4, -54, 75, -21, -39, 84, -37, -25, + 33, 79, -107, 35, 71, -103, 41, 56, -94, 48, 37, -82, + 57, 16, -68, 66, -3, -54, 75, -21, -39, 84, -37, -24, + 33, 79, -106, 36, 71, -102, 41, 56, -94, 48, 37, -82, + 57, 16, -68, 66, -3, -53, 75, -20, -39, 84, -36, -24, + 34, 79, -106, 36, 72, -102, 41, 56, -93, 48, 37, -81, + 57, 17, -68, 66, -2, -53, 75, -20, -39, 84, -36, -24, + 34, 79, -105, 36, 72, -101, 41, 57, -93, 48, 38, -81, + 57, 17, -67, 66, -2, -53, 75, -19, -39, 84, -35, -24, + 34, 79, -104, 37, 72, -100, 42, 57, -92, 49, 39, -81, + 57, 18, -67, 66, -1, -53, 75, -18, -38, 85, -35, -24, + 35, 80, -103, 37, 73, -100, 42, 58, -91, 49, 39, -80, + 57, 19, -66, 66, 0, -52, 75, -17, -38, 85, -34, -24, + 36, 80, -102, 38, 73, -99, 43, 59, -91, 49, 40, -79, + 58, 20, -66, 66, 1, -52, 75, -16, -38, 85, -33, -23, + 36, 80, -101, 38, 74, -98, 43, 59, -90, 50, 41, -79, + 58, 21, -65, 67, 2, -52, 76, -15, -38, 85, -32, -23, + 37, 80, -100, 39, 74, -97, 44, 60, -89, 50, 42, -78, + 58, 22, -65, 67, 4, -51, 76, -14, -37, 85, -31, -23, + 38, 81, -99, 40, 75, -95, 44, 61, -88, 51, 44, -77, + 59, 24, -64, 67, 5, -51, 76, -13, -37, 86, -29, -22, + 39, 81, -97, 41, 75, -94, 45, 62, -86, 51, 45, -76, + 59, 25, -63, 68, 7, -50, 77, -11, -36, 86, -28, -22, + 39, 82, -96, 41, 76, -93, 46, 63, -85, 52, 46, -75, + 60, 27, -63, 68, 8, -49, 77, -10, -36, 86, -26, -22, + 40, 82, -94, 42, 77, -91, 47, 64, -84, 53, 48, -74, + 60, 29, -62, 69, 10, -49, 77, -8, -35, 86, -25, -21, + 42, 83, -92, 43, 78, -89, 47, 66, -82, 53, 49, -73, + 61, 30, -61, 69, 12, -48, 78, -6, -34, 87, -23, -21, + 43, 84, -90, 44, 79, -88, 48, 67, -81, 54, 51, -72, + 62, 32, -60, 70, 14, -47, 78, -4, -34, 87, -21, -20, + 44, 84, -89, 45, 79, -86, 49, 68, -80, 55, 53, -70, + 62, 34, -59, 70, 16, -46, 78, -2, -33, 87, -19, -20, + 45, 85, -87, 46, 80, -84, 50, 69, -78, 56, 54, -69, + 63, 36, -58, 71, 18, -45, 79, 0, -32, 88, -17, -19, + 46, 86, -85, 48, 81, -82, 51, 71, -76, 57, 56, -67, + 64, 38, -56, 71, 20, -44, 79, 2, -32, 88, -15, -18, + 47, 87, -83, 49, 83, -80, 52, 72, -74, 57, 58, -66, + 64, 40, -55, 72, 22, -43, 80, 5, -31, 89, -13, -18, + 48, 88, -81, 50, 84, -78, 53, 74, -73, 58, 60, -65, + 65, 42, -54, 72, 24, -42, 80, 7, -30, 89, -11, -17, + 50, 89, -79, 51, 85, -76, 54, 75, -71, 59, 61, -63, + 66, 44, -53, 73, 27, -41, 81, 9, -29, 89, -8, -16, + 51, 90, -77, 52, 86, -74, 55, 77, -69, 60, 63, -61, + 67, 46, -51, 74, 29, -40, 82, 11, -28, 90, -6, -15, + 52, 91, -74, 54, 87, -72, 57, 78, -67, 61, 65, -60, + 68, 49, -50, 75, 32, -39, 82, 14, -27, 91, -3, -14, + 54, 92, -72, 55, 88, -70, 58, 80, -65, 62, 67, -58, + 68, 51, -48, 75, 34, -38, 83, 17, -26, 91, -1, -14, + 55, 93, -70, 56, 90, -68, 59, 81, -63, 63, 69, -56, + 69, 53, -47, 76, 36, -36, 84, 19, -25, 92, 2, -13, + 56, 94, -68, 57, 91, -66, 60, 83, -61, 64, 71, -54, + 70, 55, -45, 77, 39, -35, 84, 22, -24, 92, 4, -12, + 58, 96, -65, 59, 92, -63, 62, 85, -59, 66, 73, -52, + 71, 58, -44, 78, 41, -34, 85, 24, -23, 93, 7, -11, + 59, 97, -63, 60, 94, -61, 63, 86, -57, 67, 75, -51, + 72, 60, -42, 79, 44, -32, 86, 27, -21, 94, 10, -10, + 60, 98, -61, 61, 95, -59, 64, 88, -55, 68, 77, -49, + 73, 62, -40, 79, 46, -31, 86, 30, -20, 94, 12, -9, + 2, -3, 2, 13, -24, 18, 26, -35, 34, 38, -45, 43, + 50, -55, 53, 61, -64, 61, 71, -72, 70, 82, -81, 78, + 2, -1, 3, 13, -21, 19, 26, -34, 34, 38, -44, 43, + 50, -54, 53, 61, -63, 61, 71, -72, 70, 82, -81, 78, + 3, 1, 4, 13, -18, 19, 26, -32, 34, 38, -43, 44, + 50, -53, 53, 61, -63, 62, 71, -72, 70, 82, -80, 78, + 3, 5, 5, 14, -14, 20, 27, -30, 34, 38, -42, 44, + 50, -52, 53, 61, -62, 62, 71, -71, 70, 82, -80, 78, + 4, 10, 7, 15, -10, 21, 27, -27, 35, 39, -40, 44, + 50, -51, 53, 61, -61, 62, 71, -70, 70, 82, -79, 78, + 6, 16, 9, 15, -5, 22, 27, -24, 35, 39, -38, 44, + 50, -50, 53, 61, -60, 62, 71, -69, 70, 82, -79, 79, + 7, 20, 12, 16, -1, 24, 28, -21, 36, 39, -35, 45, + 50, -48, 54, 61, -58, 62, 71, -68, 70, 82, -78, 79, + 10, 24, 15, 18, 4, 25, 29, -16, 37, 40, -32, 45, + 51, -45, 54, 61, -57, 62, 72, -67, 71, 82, -77, 79, + 11, 27, 18, 19, 9, 27, 29, -12, 38, 40, -29, 46, + 51, -43, 54, 62, -55, 63, 72, -65, 71, 82, -75, 79, + 13, 30, 21, 20, 13, 29, 30, -8, 38, 41, -26, 46, + 51, -40, 55, 62, -53, 63, 72, -64, 71, 82, -74, 79, + 15, 32, 24, 21, 17, 31, 31, -4, 39, 41, -22, 47, + 52, -38, 55, 62, -50, 63, 72, -62, 71, 82, -72, 79, + 17, 35, 26, 23, 21, 33, 32, 0, 40, 42, -18, 48, + 52, -34, 56, 62, -48, 64, 73, -60, 72, 83, -71, 80, + 19, 38, 29, 24, 25, 35, 33, 5, 42, 42, -14, 49, + 53, -31, 56, 63, -45, 64, 73, -57, 72, 83, -69, 80, + 21, 40, 32, 26, 28, 37, 34, 9, 43, 43, -10, 49, + 53, -28, 57, 63, -42, 65, 73, -55, 72, 83, -67, 80, + 23, 43, 35, 27, 31, 39, 35, 13, 44, 44, -6, 50, + 54, -24, 58, 64, -39, 65, 73, -52, 73, 83, -64, 81, + 25, 45, 37, 29, 35, 40, 36, 16, 45, 45, -2, 51, + 54, -20, 58, 64, -36, 66, 74, -50, 73, 84, -62, 81, + 27, 48, 40, 30, 38, 43, 37, 21, 47, 46, 2, 52, + 55, -16, 59, 65, -32, 66, 74, -46, 74, 84, -59, 81, + 29, 50, 42, 32, 41, 44, 38, 24, 48, 47, 6, 53, + 56, -13, 60, 65, -29, 67, 75, -43, 74, 84, -57, 82, + 31, 52, 44, 34, 44, 46, 40, 28, 50, 47, 9, 55, + 57, -9, 61, 66, -26, 68, 75, -40, 75, 85, -54, 82, + 32, 54, 46, 35, 46, 48, 41, 31, 51, 48, 13, 56, + 57, -5, 62, 66, -22, 68, 76, -37, 75, 85, -51, 83, + 34, 57, 48, 37, 49, 50, 42, 35, 53, 50, 17, 57, + 58, -1, 63, 67, -18, 69, 76, -34, 76, 86, -48, 83, + 36, 59, 50, 39, 52, 51, 44, 38, 54, 51, 21, 58, + 59, 3, 64, 68, -15, 70, 77, -30, 77, 86, -45, 84, + 38, 61, 52, 40, 54, 53, 45, 41, 55, 52, 24, 59, + 60, 6, 65, 68, -11, 71, 77, -27, 77, 87, -42, 84, + 40, 63, 54, 42, 57, 55, 46, 44, 57, 53, 28, 61, + 61, 10, 66, 69, -7, 72, 78, -24, 78, 87, -39, 85, + 41, 65, 55, 43, 59, 56, 48, 47, 58, 54, 31, 62, + 62, 13, 67, 70, -4, 73, 79, -20, 79, 88, -36, 86, + 43, 67, 57, 45, 62, 58, 49, 50, 60, 55, 35, 63, + 63, 17, 68, 71, 0, 74, 79, -16, 80, 88, -32, 86, + 45, 69, 59, 47, 64, 60, 51, 53, 62, 56, 38, 65, + 64, 21, 69, 72, 4, 75, 80, -13, 80, 89, -29, 87, + 47, 71, 61, 48, 67, 61, 52, 56, 63, 58, 41, 66, + 65, 24, 70, 72, 7, 75, 81, -9, 81, 89, -26, 88, + 48, 73, 62, 50, 69, 63, 54, 58, 65, 59, 44, 67, + 66, 28, 72, 73, 11, 76, 81, -6, 82, 90, -22, 88, + 50, 76, 64, 52, 71, 65, 55, 61, 66, 60, 48, 69, + 67, 31, 73, 74, 15, 78, 82, -2, 83, 91, -19, 89, + 52, 78, 66, 53, 73, 66, 57, 64, 68, 62, 51, 70, + 68, 35, 74, 75, 18, 79, 83, 1, 84, 91, -15, 90, + 53, 80, 67, 55, 75, 68, 58, 66, 69, 63, 54, 72, + 69, 38, 75, 76, 21, 80, 84, 5, 85, 92, -12, 91, + 2, -2, -1, 13, -22, 15, 26, -34, 30, 38, -44, 41, + 50, -54, 51, 61, -63, 60, 71, -72, 69, 82, -81, 78, + 2, 0, 0, 13, -20, 16, 26, -33, 31, 38, -44, 41, + 50, -54, 51, 61, -63, 60, 71, -72, 69, 82, -81, 78, + 3, 2, 1, 14, -17, 16, 26, -31, 31, 38, -43, 41, + 50, -53, 51, 61, -63, 60, 71, -71, 69, 82, -80, 78, + 4, 6, 2, 14, -13, 17, 27, -29, 31, 38, -41, 42, + 50, -52, 52, 61, -62, 61, 71, -71, 69, 82, -80, 78, + 5, 11, 4, 15, -9, 18, 27, -27, 32, 39, -39, 42, + 50, -51, 52, 61, -61, 61, 71, -70, 69, 82, -79, 78, + 6, 16, 6, 16, -5, 19, 27, -23, 32, 39, -37, 42, + 50, -49, 52, 61, -60, 61, 71, -69, 69, 82, -79, 78, + 8, 21, 9, 16, 0, 21, 28, -20, 33, 39, -35, 43, + 51, -48, 52, 61, -58, 61, 71, -68, 69, 82, -78, 78, + 10, 24, 12, 18, 5, 22, 29, -16, 34, 40, -32, 43, + 51, -45, 53, 61, -56, 61, 72, -67, 70, 82, -76, 78, + 12, 27, 15, 19, 9, 24, 29, -12, 34, 40, -29, 44, + 51, -43, 53, 62, -55, 62, 72, -65, 70, 82, -75, 78, + 14, 30, 18, 20, 13, 26, 30, -8, 35, 41, -25, 44, + 51, -40, 53, 62, -52, 62, 72, -63, 70, 82, -74, 78, + 15, 33, 21, 21, 17, 28, 31, -4, 36, 41, -22, 45, + 52, -37, 54, 62, -50, 62, 72, -62, 70, 83, -72, 79, + 17, 35, 23, 23, 21, 29, 32, 0, 37, 42, -18, 46, + 52, -34, 54, 62, -48, 63, 73, -60, 71, 83, -71, 79, + 19, 38, 26, 24, 25, 32, 33, 5, 39, 42, -14, 47, + 53, -31, 55, 63, -45, 63, 73, -57, 71, 83, -69, 79, + 21, 41, 29, 26, 28, 33, 34, 9, 40, 43, -10, 47, + 53, -27, 56, 63, -42, 64, 73, -55, 72, 83, -66, 80, + 23, 43, 31, 27, 32, 35, 35, 13, 41, 44, -6, 48, + 54, -24, 56, 64, -39, 64, 73, -52, 72, 83, -64, 80, + 25, 45, 34, 29, 35, 37, 36, 17, 43, 45, -2, 49, + 54, -20, 57, 64, -36, 65, 74, -49, 72, 84, -62, 80, + 27, 48, 36, 30, 38, 39, 37, 21, 44, 46, 2, 51, + 55, -16, 58, 65, -32, 65, 74, -46, 73, 84, -59, 81, + 29, 50, 39, 32, 41, 41, 38, 24, 46, 47, 6, 52, + 56, -13, 59, 65, -29, 66, 75, -43, 73, 84, -57, 81, + 31, 52, 41, 34, 44, 43, 40, 28, 47, 48, 10, 53, + 57, -9, 60, 66, -25, 67, 75, -40, 74, 85, -54, 82, + 32, 54, 43, 35, 47, 45, 41, 31, 49, 48, 13, 54, + 57, -5, 60, 66, -22, 67, 76, -37, 75, 85, -51, 82, + 34, 57, 45, 37, 49, 47, 42, 35, 50, 50, 17, 55, + 58, -1, 62, 67, -18, 68, 76, -33, 75, 86, -48, 83, + 36, 59, 47, 39, 52, 49, 44, 38, 52, 51, 21, 57, + 59, 3, 63, 68, -14, 69, 77, -30, 76, 86, -45, 83, + 38, 61, 49, 40, 55, 50, 45, 41, 53, 52, 25, 58, + 60, 6, 64, 68, -11, 70, 77, -27, 77, 87, -42, 84, + 40, 63, 51, 42, 57, 52, 46, 44, 55, 53, 28, 59, + 61, 10, 65, 69, -7, 71, 78, -24, 77, 87, -39, 84, + 41, 65, 53, 43, 59, 54, 48, 47, 56, 54, 31, 60, + 62, 13, 66, 70, -4, 72, 79, -20, 78, 88, -36, 85, + 43, 68, 55, 45, 62, 56, 49, 50, 58, 55, 35, 62, + 63, 17, 67, 71, 0, 73, 79, -16, 79, 88, -32, 86, + 45, 70, 56, 47, 64, 57, 51, 53, 60, 57, 38, 63, + 64, 21, 68, 72, 4, 74, 80, -13, 80, 89, -29, 86, + 47, 72, 58, 48, 67, 59, 52, 56, 61, 58, 41, 65, + 65, 24, 69, 72, 7, 75, 81, -9, 81, 89, -26, 87, + 48, 74, 60, 50, 69, 61, 54, 59, 63, 59, 45, 66, + 66, 28, 70, 73, 11, 76, 81, -6, 81, 90, -22, 88, + 50, 76, 62, 52, 71, 63, 55, 61, 65, 60, 48, 67, + 67, 31, 72, 74, 15, 77, 82, -2, 82, 91, -19, 89, + 52, 78, 64, 53, 73, 64, 57, 64, 66, 62, 51, 69, + 68, 35, 73, 75, 18, 78, 83, 1, 83, 91, -15, 89, + 53, 80, 65, 55, 76, 66, 58, 67, 68, 63, 54, 70, + 69, 38, 74, 76, 21, 79, 84, 5, 84, 92, -12, 90, + 2, -1, -4, 13, -21, 12, 26, -34, 27, 38, -44, 39, + 50, -54, 50, 61, -63, 59, 71, -72, 68, 82, -81, 77, + 2, 1, -3, 13, -18, 12, 26, -32, 27, 38, -43, 39, + 50, -53, 50, 61, -63, 59, 71, -72, 68, 82, -80, 77, + 3, 4, -3, 14, -16, 13, 26, -31, 28, 38, -42, 39, + 50, -53, 50, 61, -62, 59, 71, -71, 68, 82, -80, 77, + 4, 8, -1, 14, -12, 14, 27, -28, 28, 38, -41, 39, + 50, -52, 50, 61, -62, 59, 71, -71, 68, 82, -80, 77, + 5, 12, 0, 15, -8, 14, 27, -26, 28, 39, -39, 40, + 50, -51, 50, 61, -61, 59, 71, -70, 68, 82, -79, 77, + 6, 17, 3, 16, -4, 16, 28, -23, 29, 39, -37, 40, + 50, -49, 50, 61, -59, 60, 71, -69, 68, 82, -78, 77, + 8, 21, 5, 17, 0, 17, 28, -20, 30, 39, -35, 40, + 51, -47, 51, 61, -58, 60, 72, -68, 69, 82, -78, 77, + 10, 25, 8, 18, 5, 19, 29, -15, 30, 40, -31, 41, + 51, -45, 51, 61, -56, 60, 72, -67, 69, 82, -76, 77, + 12, 28, 11, 19, 9, 20, 29, -11, 31, 40, -28, 42, + 51, -43, 51, 62, -54, 60, 72, -65, 69, 82, -75, 78, + 14, 30, 14, 20, 14, 22, 30, -7, 32, 41, -25, 42, + 51, -40, 52, 62, -52, 61, 72, -63, 69, 82, -74, 78, + 16, 33, 17, 21, 17, 24, 31, -3, 33, 41, -21, 43, + 52, -37, 52, 62, -50, 61, 72, -61, 70, 83, -72, 78, + 17, 36, 20, 23, 21, 26, 32, 1, 35, 42, -18, 44, + 52, -34, 53, 62, -48, 61, 73, -59, 70, 83, -70, 78, + 19, 38, 23, 24, 25, 28, 33, 5, 36, 42, -14, 45, + 53, -30, 53, 63, -45, 62, 73, -57, 70, 83, -68, 79, + 21, 41, 25, 26, 29, 30, 34, 9, 37, 43, -10, 45, + 53, -27, 54, 63, -42, 62, 73, -54, 71, 83, -66, 79, + 23, 43, 28, 27, 32, 32, 35, 13, 39, 44, -6, 46, + 54, -24, 55, 64, -39, 63, 73, -52, 71, 83, -64, 79, + 25, 45, 30, 29, 35, 34, 36, 17, 40, 45, -2, 47, + 54, -20, 56, 64, -36, 64, 74, -49, 71, 84, -62, 80, + 27, 48, 33, 31, 38, 36, 37, 21, 42, 46, 2, 49, + 55, -16, 56, 65, -32, 64, 74, -46, 72, 84, -59, 80, + 29, 50, 35, 32, 41, 38, 39, 25, 43, 47, 6, 50, + 56, -12, 57, 65, -29, 65, 75, -43, 73, 84, -57, 80, + 31, 52, 37, 34, 44, 40, 40, 28, 45, 48, 10, 51, + 57, -9, 58, 66, -25, 66, 75, -40, 73, 85, -54, 81, + 32, 55, 39, 35, 47, 42, 41, 31, 46, 49, 13, 52, + 57, -5, 59, 66, -22, 66, 76, -37, 74, 85, -51, 81, + 34, 57, 42, 37, 50, 44, 42, 35, 48, 50, 18, 53, + 58, -1, 60, 67, -18, 67, 76, -33, 74, 86, -48, 82, + 36, 59, 44, 39, 52, 46, 44, 38, 49, 51, 21, 55, + 59, 3, 61, 68, -14, 68, 77, -30, 75, 86, -45, 82, + 38, 61, 46, 40, 55, 48, 45, 41, 51, 52, 25, 56, + 60, 6, 62, 68, -11, 69, 77, -27, 76, 87, -42, 83, + 40, 63, 48, 42, 57, 49, 46, 44, 53, 53, 28, 57, + 61, 10, 63, 69, -7, 70, 78, -23, 76, 87, -39, 84, + 41, 65, 50, 43, 59, 51, 48, 47, 54, 54, 31, 59, + 62, 14, 64, 70, -4, 71, 79, -20, 77, 88, -36, 84, + 43, 68, 52, 45, 62, 53, 49, 50, 56, 55, 35, 60, + 63, 18, 66, 71, 0, 72, 79, -16, 78, 88, -32, 85, + 45, 70, 54, 47, 64, 55, 51, 53, 58, 57, 38, 62, + 64, 21, 67, 72, 4, 73, 80, -13, 79, 89, -29, 86, + 47, 72, 56, 48, 67, 57, 52, 56, 59, 58, 42, 63, + 65, 24, 68, 72, 7, 74, 81, -9, 80, 89, -26, 86, + 48, 74, 58, 50, 69, 59, 54, 59, 61, 59, 45, 64, + 66, 28, 69, 73, 11, 75, 81, -6, 81, 90, -22, 87, + 50, 76, 60, 52, 71, 61, 55, 62, 63, 60, 48, 66, + 67, 32, 71, 74, 15, 76, 82, -2, 82, 91, -18, 88, + 52, 78, 62, 53, 73, 62, 57, 64, 64, 62, 51, 67, + 68, 35, 72, 75, 18, 77, 83, 1, 82, 91, -15, 89, + 53, 80, 63, 55, 76, 64, 58, 67, 66, 63, 54, 69, + 69, 38, 73, 76, 21, 78, 84, 5, 83, 92, -12, 89, + 2, 1, -10, 13, -19, 6, 26, -32, 23, 38, -43, 36, + 50, -53, 47, 61, -63, 57, 71, -72, 67, 82, -81, 76, + 3, 3, -9, 13, -16, 7, 26, -31, 23, 38, -42, 36, + 50, -53, 47, 61, -62, 57, 71, -71, 67, 82, -80, 76, + 3, 6, -8, 14, -14, 7, 27, -30, 23, 38, -42, 36, + 50, -52, 47, 61, -62, 57, 71, -71, 67, 82, -80, 76, + 4, 10, -7, 14, -10, 8, 27, -27, 24, 39, -40, 36, + 50, -51, 48, 61, -61, 57, 71, -70, 67, 82, -79, 76, + 5, 14, -5, 15, -7, 9, 27, -25, 24, 39, -38, 36, + 50, -50, 48, 61, -60, 58, 71, -70, 67, 82, -79, 76, + 6, 19, -3, 16, -3, 10, 28, -22, 25, 39, -36, 37, + 50, -49, 48, 61, -59, 58, 71, -69, 67, 82, -78, 76, + 8, 22, -1, 17, 2, 11, 28, -19, 25, 39, -34, 37, + 51, -47, 48, 61, -58, 58, 72, -68, 67, 82, -77, 76, + 10, 26, 3, 18, 6, 13, 29, -15, 26, 40, -31, 38, + 51, -44, 49, 61, -56, 58, 72, -66, 67, 82, -76, 76, + 12, 28, 6, 19, 10, 15, 29, -11, 27, 40, -28, 38, + 51, -42, 49, 62, -54, 59, 72, -65, 67, 82, -75, 76, + 14, 31, 8, 20, 14, 17, 30, -7, 28, 41, -24, 39, + 51, -40, 49, 62, -52, 59, 72, -63, 68, 82, -74, 77, + 16, 34, 11, 22, 18, 19, 31, -3, 29, 41, -21, 40, + 52, -37, 50, 62, -50, 59, 72, -61, 68, 83, -72, 77, + 18, 36, 14, 23, 22, 20, 32, 1, 30, 42, -17, 41, + 52, -34, 50, 63, -47, 60, 73, -59, 68, 83, -70, 77, + 20, 39, 17, 24, 26, 23, 33, 6, 32, 42, -13, 41, + 53, -30, 51, 63, -44, 60, 73, -57, 69, 83, -68, 77, + 21, 41, 20, 26, 29, 25, 34, 10, 33, 43, -9, 42, + 53, -27, 52, 63, -41, 61, 73, -54, 69, 83, -66, 78, + 23, 43, 22, 27, 32, 27, 35, 13, 35, 44, -6, 43, + 54, -23, 53, 64, -38, 61, 74, -52, 70, 84, -64, 78, + 25, 46, 25, 29, 35, 29, 36, 17, 36, 45, -2, 44, + 55, -20, 53, 64, -35, 62, 74, -49, 70, 84, -62, 78, + 27, 48, 28, 31, 39, 31, 37, 21, 38, 46, 3, 46, + 55, -16, 54, 65, -32, 62, 74, -46, 71, 84, -59, 79, + 29, 50, 30, 32, 41, 33, 39, 25, 39, 47, 6, 47, + 56, -12, 55, 65, -28, 63, 75, -43, 71, 85, -56, 79, + 31, 53, 32, 34, 44, 35, 40, 28, 41, 48, 10, 48, + 57, -9, 56, 66, -25, 64, 75, -40, 72, 85, -54, 80, + 33, 55, 35, 35, 47, 37, 41, 32, 43, 49, 14, 49, + 57, -5, 57, 66, -22, 65, 76, -37, 72, 85, -51, 80, + 34, 57, 37, 37, 50, 40, 43, 35, 44, 50, 18, 51, + 58, -1, 58, 67, -18, 65, 76, -33, 73, 86, -48, 81, + 36, 59, 39, 39, 52, 42, 44, 38, 46, 51, 21, 52, + 59, 3, 59, 68, -14, 66, 77, -30, 74, 86, -45, 81, + 38, 61, 42, 40, 55, 44, 45, 42, 48, 52, 25, 53, + 60, 7, 60, 68, -11, 67, 77, -27, 74, 87, -42, 82, + 40, 63, 44, 42, 57, 46, 47, 45, 49, 53, 28, 55, + 61, 10, 61, 69, -7, 68, 78, -23, 75, 87, -39, 82, + 41, 65, 46, 43, 60, 48, 48, 47, 51, 54, 32, 56, + 62, 14, 62, 70, -4, 69, 79, -20, 76, 88, -35, 83, + 43, 68, 48, 45, 62, 50, 49, 51, 53, 55, 35, 58, + 63, 18, 64, 71, 0, 70, 79, -16, 77, 88, -32, 84, + 45, 70, 50, 47, 65, 52, 51, 53, 55, 57, 39, 59, + 64, 21, 65, 72, 4, 71, 80, -13, 77, 89, -29, 85, + 47, 72, 52, 48, 67, 54, 52, 56, 56, 58, 42, 61, + 65, 25, 66, 72, 7, 72, 81, -9, 78, 89, -25, 85, + 48, 74, 54, 50, 69, 55, 54, 59, 58, 59, 45, 62, + 66, 28, 67, 73, 11, 73, 81, -6, 79, 90, -22, 86, + 50, 76, 56, 52, 71, 58, 55, 62, 60, 60, 48, 64, + 67, 32, 69, 74, 15, 74, 82, -2, 80, 91, -18, 87, + 52, 78, 58, 53, 74, 59, 57, 64, 62, 62, 51, 65, + 68, 35, 70, 75, 18, 75, 83, 2, 81, 91, -15, 88, + 53, 80, 60, 55, 76, 61, 58, 67, 63, 63, 54, 67, + 69, 38, 71, 76, 22, 76, 84, 5, 82, 92, -12, 88, + 3, 4, -16, 13, -16, 1, 26, -31, 18, 38, -42, 32, + 50, -53, 45, 61, -62, 55, 71, -71, 65, 82, -80, 74, + 3, 6, -15, 14, -14, 1, 27, -30, 18, 38, -42, 32, + 50, -52, 45, 61, -62, 55, 71, -71, 65, 82, -80, 74, + 4, 8, -14, 14, -12, 2, 27, -28, 19, 38, -41, 32, + 50, -52, 45, 61, -61, 55, 71, -71, 65, 82, -80, 74, + 4, 12, -13, 15, -8, 3, 27, -26, 19, 39, -39, 33, + 50, -51, 45, 61, -61, 55, 71, -70, 65, 82, -79, 74, + 5, 17, -11, 15, -5, 4, 27, -24, 20, 39, -38, 33, + 50, -49, 45, 61, -60, 55, 71, -69, 65, 82, -79, 74, + 7, 20, -9, 16, -1, 5, 28, -21, 20, 39, -36, 33, + 50, -48, 45, 61, -59, 56, 71, -68, 65, 82, -78, 74, + 8, 23, -6, 17, 3, 6, 28, -18, 21, 39, -33, 34, + 51, -46, 46, 61, -57, 56, 72, -67, 65, 82, -77, 75, + 10, 27, -3, 18, 7, 8, 29, -14, 22, 40, -30, 34, + 51, -44, 46, 61, -55, 56, 72, -66, 66, 82, -76, 75, + 12, 29, 0, 19, 11, 10, 29, -10, 23, 40, -27, 35, + 51, -42, 46, 62, -54, 56, 72, -64, 66, 82, -75, 75, + 14, 32, 3, 20, 15, 11, 30, -6, 24, 41, -24, 36, + 52, -39, 47, 62, -52, 57, 72, -63, 66, 82, -73, 75, + 16, 34, 6, 22, 19, 13, 31, -2, 25, 41, -20, 36, + 52, -36, 47, 62, -49, 57, 72, -61, 66, 83, -72, 75, + 18, 37, 8, 23, 22, 15, 32, 2, 26, 42, -17, 37, + 52, -33, 48, 63, -47, 58, 73, -59, 67, 83, -70, 76, + 20, 39, 12, 25, 26, 18, 33, 6, 28, 43, -13, 38, + 53, -30, 49, 63, -44, 58, 73, -56, 67, 83, -68, 76, + 22, 42, 14, 26, 29, 20, 34, 10, 29, 43, -9, 39, + 53, -26, 49, 63, -41, 59, 73, -54, 67, 83, -66, 76, + 23, 44, 17, 27, 33, 22, 35, 14, 31, 44, -5, 40, + 54, -23, 50, 64, -38, 59, 74, -51, 68, 84, -64, 77, + 25, 46, 20, 29, 36, 24, 36, 18, 32, 45, -1, 41, + 55, -19, 51, 64, -35, 60, 74, -49, 68, 84, -61, 77, + 27, 49, 23, 31, 39, 27, 37, 22, 34, 46, 3, 43, + 55, -15, 52, 65, -31, 60, 74, -46, 69, 84, -59, 77, + 29, 51, 25, 32, 42, 29, 39, 25, 36, 47, 7, 44, + 56, -12, 53, 65, -28, 61, 75, -43, 69, 85, -56, 78, + 31, 53, 28, 34, 44, 31, 40, 29, 37, 48, 10, 45, + 57, -8, 53, 66, -25, 62, 75, -40, 70, 85, -54, 78, + 33, 55, 30, 35, 47, 33, 41, 32, 39, 49, 14, 46, + 57, -5, 54, 66, -21, 63, 76, -37, 71, 85, -51, 79, + 35, 57, 33, 37, 50, 35, 43, 36, 41, 50, 18, 48, + 58, 0, 56, 67, -17, 63, 76, -33, 71, 86, -48, 79, + 36, 60, 35, 39, 53, 38, 44, 39, 43, 51, 22, 49, + 59, 3, 57, 68, -14, 64, 77, -30, 72, 86, -45, 80, + 38, 62, 37, 40, 55, 40, 45, 42, 44, 52, 25, 50, + 60, 7, 58, 69, -10, 65, 77, -26, 73, 87, -42, 81, + 40, 64, 40, 42, 57, 42, 47, 45, 46, 53, 29, 52, + 61, 10, 59, 69, -7, 66, 78, -23, 73, 87, -38, 81, + 41, 66, 42, 44, 60, 44, 48, 48, 48, 54, 32, 53, + 62, 14, 60, 70, -3, 67, 79, -20, 74, 88, -35, 82, + 43, 68, 44, 45, 62, 46, 49, 51, 50, 55, 36, 55, + 63, 18, 61, 71, 1, 68, 79, -16, 75, 88, -32, 82, + 45, 70, 46, 47, 65, 48, 51, 54, 52, 57, 39, 56, + 64, 21, 62, 72, 4, 69, 80, -12, 76, 89, -28, 83, + 47, 72, 49, 48, 67, 50, 52, 56, 53, 58, 42, 58, + 65, 25, 64, 72, 8, 70, 81, -9, 77, 89, -25, 84, + 48, 74, 51, 50, 69, 52, 54, 59, 55, 59, 45, 59, + 66, 28, 65, 73, 11, 71, 81, -6, 78, 90, -22, 85, + 50, 76, 53, 52, 72, 54, 55, 62, 57, 60, 48, 61, + 67, 32, 66, 74, 15, 72, 82, -2, 79, 91, -18, 85, + 52, 78, 55, 53, 74, 56, 57, 64, 59, 62, 51, 63, + 68, 35, 68, 75, 18, 73, 83, 2, 80, 91, -15, 86, + 54, 80, 57, 55, 76, 58, 58, 67, 60, 63, 54, 64, + 69, 38, 69, 76, 22, 75, 84, 5, 81, 92, -12, 87, + 3, 7, -21, 14, -13, -5, 27, -29, 14, 38, -41, 28, + 50, -52, 41, 61, -62, 53, 71, -71, 63, 82, -80, 72, + 3, 9, -20, 14, -11, -4, 27, -28, 14, 38, -40, 28, + 50, -52, 41, 61, -61, 53, 71, -71, 63, 82, -80, 72, + 4, 11, -20, 14, -9, -4, 27, -27, 14, 39, -40, 29, + 50, -51, 42, 61, -61, 53, 71, -70, 63, 82, -79, 72, + 5, 15, -18, 15, -6, -3, 27, -25, 14, 39, -38, 29, + 50, -50, 42, 61, -60, 53, 71, -70, 63, 82, -79, 73, + 6, 19, -16, 15, -3, -2, 27, -22, 15, 39, -37, 29, + 50, -49, 42, 61, -59, 53, 71, -69, 63, 82, -78, 73, + 7, 22, -14, 16, 1, 0, 28, -20, 16, 39, -35, 29, + 50, -47, 42, 61, -58, 53, 71, -68, 63, 82, -78, 73, + 9, 25, -12, 17, 4, 1, 28, -16, 16, 39, -32, 30, + 51, -46, 42, 61, -57, 53, 72, -67, 63, 82, -77, 73, + 11, 28, -8, 18, 9, 3, 29, -13, 17, 40, -29, 31, + 51, -43, 43, 61, -55, 54, 72, -65, 63, 82, -76, 73, + 13, 30, -6, 19, 12, 4, 30, -9, 18, 40, -26, 31, + 51, -41, 43, 62, -53, 54, 72, -64, 64, 82, -74, 73, + 14, 33, -3, 21, 16, 6, 30, -5, 19, 41, -23, 32, + 52, -38, 44, 62, -51, 54, 72, -62, 64, 82, -73, 73, + 16, 35, 0, 22, 20, 8, 31, -1, 20, 41, -20, 33, + 52, -36, 44, 62, -49, 55, 72, -60, 64, 83, -71, 74, + 18, 37, 3, 23, 23, 10, 32, 3, 22, 42, -16, 33, + 52, -33, 45, 63, -46, 55, 73, -58, 65, 83, -70, 74, + 20, 40, 6, 25, 27, 13, 33, 7, 23, 43, -12, 34, + 53, -29, 45, 63, -43, 56, 73, -56, 65, 83, -68, 74, + 22, 42, 9, 26, 30, 15, 34, 11, 25, 43, -8, 35, + 53, -26, 46, 63, -41, 56, 73, -54, 65, 83, -66, 75, + 24, 44, 12, 28, 33, 17, 35, 14, 26, 44, -5, 36, + 54, -23, 47, 64, -38, 57, 74, -51, 66, 84, -63, 75, + 25, 47, 14, 29, 36, 19, 36, 18, 28, 45, -1, 38, + 55, -19, 48, 64, -35, 57, 74, -48, 66, 84, -61, 75, + 27, 49, 17, 31, 39, 22, 38, 22, 30, 46, 3, 39, + 55, -15, 49, 65, -31, 58, 74, -45, 67, 84, -58, 76, + 29, 51, 20, 32, 42, 24, 39, 26, 31, 47, 7, 40, + 56, -11, 50, 65, -28, 59, 75, -42, 67, 85, -56, 76, + 31, 53, 23, 34, 45, 26, 40, 29, 33, 48, 11, 41, + 57, -8, 51, 66, -24, 59, 75, -39, 68, 85, -53, 77, + 33, 55, 25, 35, 47, 28, 41, 32, 35, 49, 14, 43, + 57, -4, 52, 67, -21, 60, 76, -36, 69, 85, -50, 77, + 35, 58, 28, 37, 50, 31, 43, 36, 37, 50, 18, 44, + 58, 0, 53, 67, -17, 61, 76, -33, 69, 86, -47, 78, + 36, 60, 30, 39, 53, 33, 44, 39, 39, 51, 22, 46, + 59, 4, 54, 68, -14, 62, 77, -29, 70, 86, -44, 78, + 38, 62, 33, 40, 55, 35, 45, 42, 40, 52, 25, 47, + 60, 7, 55, 69, -10, 63, 77, -26, 71, 87, -41, 79, + 40, 64, 35, 42, 58, 37, 47, 45, 42, 53, 29, 49, + 61, 11, 56, 69, -7, 64, 78, -23, 71, 87, -38, 79, + 42, 66, 37, 44, 60, 40, 48, 48, 44, 54, 32, 50, + 62, 14, 57, 70, -3, 65, 79, -19, 72, 88, -35, 80, + 43, 68, 40, 45, 63, 42, 50, 51, 46, 55, 36, 52, + 63, 18, 59, 71, 1, 66, 79, -16, 73, 88, -32, 81, + 45, 70, 42, 47, 65, 44, 51, 54, 48, 57, 39, 53, + 64, 22, 60, 72, 4, 67, 80, -12, 74, 89, -28, 82, + 47, 72, 44, 49, 67, 46, 52, 56, 50, 58, 42, 55, + 65, 25, 61, 73, 8, 68, 81, -9, 75, 89, -25, 82, + 48, 74, 47, 50, 69, 48, 54, 59, 51, 59, 45, 56, + 66, 28, 62, 73, 11, 69, 81, -5, 76, 90, -22, 83, + 50, 76, 49, 52, 72, 50, 55, 62, 54, 60, 48, 58, + 67, 32, 64, 74, 15, 70, 82, -2, 77, 91, -18, 84, + 52, 78, 51, 53, 74, 52, 57, 65, 55, 62, 51, 60, + 68, 35, 65, 75, 19, 71, 83, 2, 78, 91, -15, 85, + 54, 80, 53, 55, 76, 54, 58, 67, 57, 63, 54, 61, + 69, 38, 66, 76, 22, 72, 84, 5, 79, 92, -11, 86, + 4, 11, -26, 14, -10, -10, 27, -27, 9, 38, -40, 24, + 50, -51, 38, 61, -61, 50, 71, -70, 60, 82, -79, 70, + 4, 13, -26, 14, -8, -9, 27, -26, 9, 39, -39, 24, + 50, -51, 38, 61, -61, 50, 71, -70, 60, 82, -79, 70, + 5, 15, -25, 15, -6, -9, 27, -25, 9, 39, -38, 24, + 50, -50, 38, 61, -60, 50, 71, -70, 60, 82, -79, 70, + 5, 19, -23, 15, -3, -8, 27, -23, 10, 39, -37, 25, + 50, -49, 38, 61, -59, 50, 71, -69, 60, 82, -78, 70, + 6, 22, -21, 16, 0, -7, 28, -21, 10, 39, -35, 25, + 50, -48, 38, 61, -59, 50, 71, -68, 61, 82, -78, 71, + 8, 24, -19, 17, 3, -6, 28, -18, 11, 39, -33, 25, + 51, -46, 39, 61, -57, 50, 72, -67, 61, 82, -77, 71, + 9, 26, -17, 17, 6, -4, 28, -15, 11, 40, -31, 26, + 51, -45, 39, 61, -56, 50, 72, -66, 61, 82, -76, 71, + 11, 29, -14, 19, 10, -3, 29, -11, 12, 40, -28, 26, + 51, -42, 39, 62, -54, 51, 72, -65, 61, 82, -75, 71, + 13, 31, -11, 20, 14, -1, 30, -8, 13, 40, -25, 27, + 51, -40, 40, 62, -53, 51, 72, -64, 61, 82, -74, 71, + 15, 34, -8, 21, 17, 1, 31, -4, 15, 41, -22, 28, + 52, -38, 40, 62, -50, 51, 72, -62, 62, 82, -73, 71, + 16, 36, -5, 22, 21, 3, 31, 0, 16, 41, -19, 28, + 52, -35, 41, 62, -48, 52, 72, -60, 62, 83, -71, 72, + 18, 38, -2, 23, 24, 5, 32, 3, 17, 42, -15, 29, + 52, -32, 41, 63, -46, 52, 73, -58, 62, 83, -69, 72, + 20, 41, 1, 25, 28, 8, 33, 8, 19, 43, -11, 30, + 53, -29, 42, 63, -43, 53, 73, -56, 63, 83, -67, 72, + 22, 43, 4, 26, 31, 10, 34, 11, 20, 43, -8, 31, + 54, -25, 43, 63, -40, 53, 73, -53, 63, 83, -65, 72, + 24, 45, 6, 28, 34, 12, 35, 15, 22, 44, -4, 32, + 54, -22, 44, 64, -37, 54, 74, -51, 63, 84, -63, 73, + 26, 47, 9, 29, 37, 14, 36, 19, 23, 45, 0, 34, + 55, -18, 44, 64, -34, 54, 74, -48, 64, 84, -61, 73, + 28, 49, 12, 31, 40, 17, 38, 23, 25, 46, 4, 35, + 55, -15, 45, 65, -31, 55, 74, -45, 64, 84, -58, 74, + 29, 52, 15, 33, 43, 19, 39, 26, 27, 47, 8, 36, + 56, -11, 46, 65, -27, 56, 75, -42, 65, 85, -56, 74, + 31, 54, 17, 34, 45, 21, 40, 29, 29, 48, 11, 38, + 57, -7, 47, 66, -24, 57, 75, -39, 66, 85, -53, 75, + 33, 56, 20, 36, 48, 24, 41, 33, 30, 49, 15, 39, + 58, -4, 48, 67, -21, 57, 76, -36, 66, 85, -50, 75, + 35, 58, 23, 37, 51, 26, 43, 36, 32, 50, 19, 40, + 58, 0, 49, 67, -17, 58, 76, -32, 67, 86, -47, 76, + 37, 60, 25, 39, 53, 28, 44, 39, 34, 51, 22, 42, + 59, 4, 51, 68, -13, 59, 77, -29, 68, 86, -44, 76, + 38, 62, 28, 41, 56, 31, 45, 42, 36, 52, 26, 43, + 60, 7, 52, 69, -10, 60, 77, -26, 68, 87, -41, 77, + 40, 64, 30, 42, 58, 33, 47, 45, 38, 53, 29, 45, + 61, 11, 53, 69, -6, 61, 78, -23, 69, 87, -38, 77, + 42, 66, 33, 44, 60, 35, 48, 48, 40, 54, 32, 46, + 62, 15, 54, 70, -3, 62, 79, -19, 70, 88, -35, 78, + 44, 68, 35, 45, 63, 37, 50, 51, 42, 56, 36, 48, + 63, 18, 55, 71, 1, 63, 79, -15, 71, 88, -31, 79, + 45, 70, 38, 47, 65, 40, 51, 54, 44, 57, 39, 50, + 64, 22, 57, 72, 5, 64, 80, -12, 72, 89, -28, 80, + 47, 72, 40, 49, 67, 42, 52, 57, 46, 58, 42, 51, + 65, 25, 58, 73, 8, 65, 81, -9, 73, 89, -25, 80, + 49, 74, 42, 50, 70, 44, 54, 59, 48, 59, 45, 53, + 66, 29, 59, 73, 12, 66, 81, -5, 74, 90, -22, 81, + 50, 76, 45, 52, 72, 46, 55, 62, 50, 60, 49, 55, + 67, 32, 61, 74, 15, 68, 82, -1, 75, 91, -18, 82, + 52, 78, 47, 54, 74, 48, 57, 65, 52, 62, 52, 56, + 68, 35, 62, 75, 19, 69, 83, 2, 76, 91, -14, 83, + 54, 80, 49, 55, 76, 50, 58, 67, 53, 63, 54, 58, + 69, 39, 64, 76, 22, 70, 84, 5, 77, 92, -11, 84, + 4, 16, -32, 15, -6, -15, 27, -25, 3, 39, -38, 19, + 50, -50, 34, 61, -60, 46, 71, -70, 57, 82, -79, 68, + 5, 18, -31, 15, -4, -15, 27, -23, 4, 39, -37, 19, + 50, -49, 34, 61, -60, 46, 71, -69, 57, 82, -79, 68, + 5, 20, -30, 15, -3, -14, 27, -22, 4, 39, -37, 20, + 50, -49, 34, 61, -59, 46, 71, -69, 57, 82, -78, 68, + 6, 22, -29, 16, 0, -14, 28, -20, 4, 39, -35, 20, + 50, -48, 34, 61, -59, 46, 71, -68, 57, 82, -78, 68, + 7, 25, -27, 16, 2, -13, 28, -18, 5, 39, -34, 20, + 50, -47, 34, 61, -58, 46, 71, -68, 57, 82, -77, 68, + 9, 26, -25, 17, 5, -11, 28, -16, 5, 39, -32, 20, + 51, -45, 34, 61, -57, 47, 72, -67, 58, 82, -77, 68, + 10, 28, -22, 18, 8, -10, 29, -13, 6, 40, -30, 21, + 51, -44, 35, 61, -55, 47, 72, -66, 58, 82, -76, 68, + 12, 31, -19, 19, 12, -8, 29, -9, 7, 40, -27, 22, + 51, -41, 35, 62, -53, 47, 72, -64, 58, 82, -75, 68, + 13, 33, -17, 20, 15, -7, 30, -6, 8, 41, -24, 22, + 51, -39, 36, 62, -52, 47, 72, -63, 58, 82, -73, 68, + 15, 35, -14, 21, 19, -5, 31, -3, 9, 41, -21, 23, + 52, -37, 36, 62, -50, 48, 72, -61, 58, 82, -72, 69, + 17, 37, -11, 22, 22, -3, 31, 1, 10, 42, -18, 24, + 52, -34, 37, 62, -47, 48, 72, -59, 59, 83, -70, 69, + 19, 39, -8, 24, 25, -1, 32, 5, 12, 42, -14, 25, + 53, -31, 37, 63, -45, 49, 73, -57, 59, 83, -69, 69, + 21, 41, -5, 25, 29, 2, 33, 9, 13, 43, -10, 26, + 53, -28, 38, 63, -42, 49, 73, -55, 59, 83, -67, 70, + 22, 44, -2, 27, 32, 4, 34, 12, 15, 44, -7, 27, + 54, -24, 39, 63, -39, 50, 73, -53, 60, 83, -65, 70, + 24, 46, 1, 28, 35, 6, 35, 16, 16, 44, -3, 28, + 54, -21, 39, 64, -37, 50, 74, -50, 60, 84, -63, 70, + 26, 48, 3, 29, 37, 9, 37, 20, 18, 45, 1, 29, + 55, -18, 40, 64, -33, 51, 74, -47, 61, 84, -60, 71, + 28, 50, 6, 31, 41, 11, 38, 23, 20, 46, 5, 30, + 55, -14, 41, 65, -30, 52, 74, -44, 61, 84, -58, 71, + 30, 52, 9, 33, 43, 13, 39, 27, 22, 47, 8, 32, + 56, -10, 42, 65, -27, 52, 75, -41, 62, 85, -55, 72, + 31, 54, 12, 34, 46, 16, 40, 30, 23, 48, 12, 33, + 57, -7, 43, 66, -23, 53, 75, -38, 63, 85, -52, 72, + 33, 56, 14, 36, 48, 18, 41, 33, 25, 49, 15, 34, + 58, -3, 44, 67, -20, 54, 76, -35, 63, 85, -50, 73, + 35, 59, 17, 38, 51, 21, 43, 37, 27, 50, 19, 36, + 58, 1, 45, 67, -16, 55, 76, -32, 64, 86, -47, 73, + 37, 61, 20, 39, 54, 23, 44, 40, 29, 51, 23, 37, + 59, 4, 47, 68, -13, 56, 77, -29, 65, 86, -44, 74, + 38, 63, 22, 41, 56, 25, 45, 43, 31, 52, 26, 39, + 60, 8, 48, 69, -9, 57, 78, -25, 65, 87, -41, 74, + 40, 65, 25, 42, 58, 28, 47, 46, 33, 53, 30, 40, + 61, 11, 49, 69, -6, 58, 78, -22, 66, 87, -38, 75, + 42, 66, 27, 44, 61, 30, 48, 49, 35, 54, 33, 42, + 62, 15, 50, 70, -2, 59, 79, -19, 67, 88, -34, 76, + 44, 69, 30, 46, 63, 32, 50, 52, 37, 56, 36, 44, + 63, 19, 52, 71, 2, 60, 79, -15, 68, 88, -31, 76, + 45, 71, 32, 47, 65, 35, 51, 54, 39, 57, 40, 45, + 64, 22, 53, 72, 5, 61, 80, -12, 69, 89, -28, 77, + 47, 73, 35, 49, 68, 37, 53, 57, 41, 58, 43, 47, + 65, 26, 54, 73, 8, 62, 81, -8, 70, 90, -24, 78, + 49, 75, 37, 50, 70, 39, 54, 60, 43, 59, 46, 49, + 66, 29, 56, 73, 12, 63, 81, -5, 71, 90, -21, 79, + 50, 77, 40, 52, 72, 41, 56, 63, 45, 61, 49, 51, + 67, 33, 57, 74, 16, 64, 82, -1, 72, 91, -17, 80, + 52, 79, 42, 54, 74, 44, 57, 65, 47, 62, 52, 52, + 68, 36, 59, 75, 19, 65, 83, 2, 73, 91, -14, 80, + 54, 80, 44, 55, 76, 46, 58, 67, 49, 63, 55, 54, + 69, 39, 60, 76, 22, 67, 84, 6, 74, 92, -11, 81, + 5, 21, -36, 15, -2, -20, 27, -22, -2, 39, -36, 15, + 50, -49, 30, 61, -59, 42, 71, -69, 54, 82, -78, 65, + 6, 22, -35, 15, -1, -20, 27, -21, -1, 39, -36, 15, + 50, -48, 30, 61, -59, 43, 71, -69, 54, 82, -78, 65, + 6, 24, -35, 16, 1, -19, 27, -20, -1, 39, -35, 15, + 50, -48, 30, 61, -58, 43, 71, -68, 54, 82, -78, 65, + 7, 26, -33, 16, 3, -18, 28, -18, -1, 39, -34, 15, + 50, -47, 30, 61, -58, 43, 71, -68, 54, 82, -77, 65, + 8, 27, -31, 17, 5, -17, 28, -16, 0, 39, -32, 16, + 51, -45, 30, 61, -57, 43, 72, -67, 54, 82, -77, 65, + 9, 29, -29, 17, 8, -16, 28, -14, 0, 40, -30, 16, + 51, -44, 30, 61, -56, 43, 72, -66, 55, 82, -76, 65, + 11, 30, -27, 18, 11, -15, 29, -11, 1, 40, -28, 16, + 51, -42, 31, 61, -54, 43, 72, -65, 55, 82, -75, 66, + 12, 32, -24, 19, 14, -13, 30, -8, 2, 40, -25, 17, + 51, -40, 31, 62, -53, 44, 72, -64, 55, 82, -74, 66, + 14, 34, -21, 20, 17, -11, 30, -4, 3, 41, -23, 18, + 52, -38, 32, 62, -51, 44, 72, -62, 55, 82, -73, 66, + 16, 36, -19, 21, 20, -10, 31, -1, 4, 41, -20, 18, + 52, -36, 32, 62, -49, 44, 72, -61, 55, 83, -71, 66, + 17, 38, -16, 23, 23, -8, 32, 2, 6, 42, -16, 19, + 52, -33, 33, 62, -47, 45, 73, -59, 56, 83, -70, 66, + 19, 40, -13, 24, 26, -6, 33, 6, 7, 42, -13, 20, + 53, -30, 33, 63, -44, 45, 73, -57, 56, 83, -68, 67, + 21, 42, -10, 25, 30, -3, 34, 10, 8, 43, -9, 21, + 53, -27, 34, 63, -41, 46, 73, -54, 56, 83, -66, 67, + 23, 44, -7, 27, 33, -1, 35, 13, 10, 44, -6, 22, + 54, -24, 35, 64, -39, 46, 73, -52, 57, 83, -64, 67, + 24, 46, -5, 28, 36, 1, 36, 17, 12, 44, -2, 23, + 54, -20, 36, 64, -36, 47, 74, -49, 57, 84, -62, 68, + 26, 48, -2, 30, 38, 4, 37, 20, 13, 45, 1, 25, + 55, -17, 36, 64, -33, 47, 74, -47, 58, 84, -60, 68, + 28, 51, 1, 31, 41, 6, 38, 24, 15, 46, 5, 26, + 56, -13, 37, 65, -29, 48, 75, -44, 58, 84, -57, 69, + 30, 53, 4, 33, 44, 8, 39, 28, 17, 47, 9, 27, + 56, -10, 38, 66, -26, 49, 75, -41, 59, 85, -55, 69, + 31, 55, 7, 34, 46, 11, 40, 31, 19, 48, 13, 29, + 57, -6, 39, 66, -23, 50, 75, -38, 60, 85, -52, 69, + 33, 57, 9, 36, 49, 13, 42, 34, 21, 49, 16, 30, + 58, -3, 40, 67, -20, 51, 76, -35, 60, 85, -49, 70, + 35, 59, 12, 38, 52, 16, 43, 37, 23, 50, 20, 32, + 59, 1, 42, 67, -16, 51, 76, -31, 61, 86, -46, 71, + 37, 61, 15, 39, 54, 18, 44, 40, 25, 51, 23, 33, + 59, 5, 43, 68, -12, 52, 77, -28, 62, 86, -43, 71, + 39, 63, 18, 41, 57, 20, 46, 43, 27, 52, 27, 35, + 60, 8, 44, 69, -9, 53, 78, -25, 63, 87, -40, 72, + 40, 65, 20, 42, 59, 23, 47, 46, 29, 53, 30, 36, + 61, 12, 45, 69, -5, 54, 78, -22, 63, 87, -37, 72, + 42, 67, 23, 44, 61, 25, 48, 49, 31, 54, 33, 38, + 62, 15, 47, 70, -2, 55, 79, -18, 64, 88, -34, 73, + 44, 69, 25, 46, 64, 28, 50, 52, 33, 56, 37, 40, + 63, 19, 48, 71, 2, 56, 79, -15, 65, 88, -31, 74, + 45, 71, 28, 47, 66, 30, 51, 55, 35, 57, 40, 41, + 64, 23, 49, 72, 5, 58, 80, -11, 66, 89, -27, 75, + 47, 73, 30, 49, 68, 32, 53, 57, 37, 58, 43, 43, + 65, 26, 51, 73, 9, 59, 81, -8, 67, 90, -24, 75, + 49, 75, 33, 50, 70, 34, 54, 60, 39, 59, 46, 45, + 66, 29, 52, 74, 12, 60, 82, -4, 68, 90, -21, 76, + 51, 77, 35, 52, 73, 37, 56, 63, 41, 61, 49, 47, + 67, 33, 54, 75, 16, 61, 82, -1, 69, 91, -17, 77, + 52, 79, 37, 54, 75, 39, 57, 65, 43, 62, 52, 48, + 68, 36, 55, 75, 19, 62, 83, 3, 70, 91, -14, 78, + 54, 81, 40, 55, 77, 41, 58, 68, 45, 63, 55, 50, + 69, 39, 57, 76, 23, 64, 84, 6, 71, 92, -11, 79, + 6, 25, -40, 16, 2, -25, 27, -19, -6, 39, -34, 10, + 50, -47, 25, 61, -58, 39, 71, -68, 51, 82, -78, 62, + 7, 26, -40, 16, 3, -24, 28, -18, -6, 39, -34, 10, + 50, -47, 26, 61, -58, 39, 71, -68, 51, 82, -77, 62, + 7, 27, -39, 16, 4, -24, 28, -17, -6, 39, -33, 11, + 50, -46, 26, 61, -57, 39, 71, -67, 51, 82, -77, 62, + 8, 28, -37, 17, 6, -23, 28, -16, -5, 39, -32, 11, + 51, -45, 26, 61, -57, 39, 72, -67, 51, 82, -77, 62, + 9, 29, -35, 17, 8, -22, 28, -14, -5, 39, -30, 11, + 51, -44, 26, 61, -56, 39, 72, -66, 51, 82, -76, 62, + 10, 31, -33, 18, 11, -21, 29, -11, -4, 40, -28, 11, + 51, -43, 26, 61, -55, 39, 72, -65, 51, 82, -75, 63, + 11, 32, -31, 19, 13, -20, 29, -9, -4, 40, -26, 12, + 51, -41, 27, 62, -53, 40, 72, -64, 51, 82, -74, 63, + 13, 34, -29, 20, 16, -18, 30, -6, -3, 40, -24, 13, + 51, -39, 27, 62, -52, 40, 72, -63, 52, 82, -73, 63, + 15, 36, -26, 21, 19, -16, 30, -3, -2, 41, -21, 13, + 52, -37, 27, 62, -50, 40, 72, -61, 52, 82, -72, 63, + 16, 38, -23, 22, 22, -14, 31, 1, 0, 41, -18, 14, + 52, -34, 28, 62, -48, 41, 72, -60, 52, 83, -71, 63, + 18, 39, -21, 23, 25, -13, 32, 4, 1, 42, -15, 15, + 52, -32, 29, 63, -46, 41, 73, -58, 52, 83, -69, 63, + 19, 41, -18, 24, 28, -11, 33, 7, 2, 42, -12, 16, + 53, -29, 29, 63, -43, 41, 73, -56, 53, 83, -68, 64, + 21, 43, -15, 26, 31, -8, 34, 11, 4, 43, -8, 17, + 53, -26, 30, 63, -41, 42, 73, -54, 53, 83, -66, 64, + 23, 45, -12, 27, 34, -6, 35, 15, 5, 44, -5, 18, + 54, -23, 31, 64, -38, 43, 73, -51, 54, 83, -64, 64, + 25, 47, -9, 29, 37, -4, 36, 18, 7, 45, -1, 19, + 54, -19, 31, 64, -35, 43, 74, -49, 54, 84, -61, 65, + 26, 49, -7, 30, 39, -1, 37, 21, 9, 45, 2, 20, + 55, -16, 32, 65, -32, 44, 74, -46, 55, 84, -59, 65, + 28, 51, -4, 32, 42, 1, 38, 25, 10, 46, 6, 22, + 56, -12, 33, 65, -29, 45, 75, -43, 55, 84, -57, 66, + 30, 53, -1, 33, 45, 4, 39, 28, 12, 47, 10, 23, + 56, -9, 34, 66, -25, 45, 75, -40, 56, 85, -54, 66, + 32, 55, 2, 35, 47, 6, 41, 32, 14, 48, 13, 24, + 57, -5, 35, 66, -22, 46, 75, -37, 56, 85, -51, 67, + 33, 57, 4, 36, 50, 8, 42, 35, 16, 49, 17, 26, + 58, -2, 36, 67, -19, 47, 76, -34, 57, 85, -49, 67, + 35, 60, 7, 38, 52, 11, 43, 38, 18, 50, 21, 27, + 59, 2, 38, 67, -15, 48, 77, -31, 58, 86, -46, 68, + 37, 61, 10, 39, 55, 13, 44, 41, 20, 51, 24, 29, + 59, 6, 39, 68, -12, 49, 77, -28, 59, 86, -43, 68, + 39, 63, 13, 41, 57, 16, 46, 44, 22, 52, 27, 30, + 60, 9, 40, 69, -8, 50, 78, -24, 59, 87, -40, 69, + 40, 65, 15, 43, 59, 18, 47, 47, 24, 53, 31, 32, + 61, 13, 41, 70, -5, 51, 78, -21, 60, 87, -37, 70, + 42, 67, 18, 44, 62, 20, 48, 50, 26, 55, 34, 34, + 62, 16, 43, 70, -1, 52, 79, -18, 61, 88, -34, 70, + 44, 69, 21, 46, 64, 23, 50, 53, 28, 56, 37, 35, + 63, 20, 44, 71, 2, 53, 80, -14, 62, 88, -30, 71, + 46, 71, 23, 47, 66, 25, 51, 55, 30, 57, 40, 37, + 64, 23, 45, 72, 6, 54, 80, -11, 63, 89, -27, 72, + 47, 73, 25, 49, 68, 28, 53, 58, 32, 58, 43, 39, + 65, 26, 47, 73, 9, 55, 81, -7, 64, 90, -24, 73, + 49, 75, 28, 50, 70, 30, 54, 60, 34, 59, 46, 41, + 66, 30, 48, 74, 13, 56, 82, -4, 65, 90, -20, 73, + 51, 77, 31, 52, 73, 32, 56, 63, 37, 61, 50, 42, + 67, 33, 50, 75, 16, 58, 82, 0, 66, 91, -17, 74, + 52, 79, 33, 54, 75, 35, 57, 66, 39, 62, 53, 44, + 68, 36, 51, 75, 20, 59, 83, 3, 67, 92, -14, 75, + 54, 81, 35, 55, 77, 37, 59, 68, 41, 63, 55, 46, + 69, 40, 53, 76, 23, 60, 84, 6, 68, 92, -10, 76, + 7, 29, -44, 16, 6, -29, 28, -16, -11, 39, -32, 6, + 50, -46, 21, 61, -57, 35, 71, -67, 47, 82, -77, 59, + 8, 30, -43, 16, 7, -29, 28, -15, -11, 39, -32, 6, + 50, -45, 21, 61, -56, 35, 71, -67, 47, 82, -77, 59, + 8, 30, -42, 17, 8, -28, 28, -14, -11, 39, -31, 6, + 51, -45, 21, 61, -56, 35, 72, -66, 47, 82, -76, 59, + 9, 31, -41, 17, 9, -28, 28, -13, -10, 39, -30, 6, + 51, -44, 22, 61, -55, 35, 72, -66, 48, 82, -76, 59, + 10, 32, -39, 18, 11, -27, 29, -11, -10, 40, -28, 7, + 51, -43, 22, 61, -54, 35, 72, -65, 48, 82, -75, 59, + 11, 33, -38, 18, 13, -26, 29, -9, -9, 40, -27, 7, + 51, -41, 22, 62, -53, 36, 72, -64, 48, 82, -75, 59, + 12, 34, -36, 19, 16, -24, 29, -7, -8, 40, -25, 7, + 51, -40, 22, 62, -52, 36, 72, -63, 48, 82, -74, 60, + 14, 36, -33, 20, 18, -23, 30, -4, -7, 41, -22, 8, + 51, -38, 23, 62, -50, 36, 72, -62, 48, 82, -73, 60, + 15, 37, -31, 21, 21, -21, 31, -1, -6, 41, -19, 9, + 52, -35, 23, 62, -49, 36, 72, -60, 48, 82, -71, 60, + 17, 39, -28, 22, 24, -19, 31, 2, -5, 41, -17, 9, + 52, -33, 24, 62, -47, 37, 72, -59, 49, 83, -70, 60, + 18, 41, -25, 23, 27, -17, 32, 6, -4, 42, -14, 10, + 52, -31, 24, 63, -45, 37, 73, -57, 49, 83, -69, 60, + 20, 43, -23, 25, 29, -15, 33, 9, -3, 43, -10, 11, + 53, -28, 25, 63, -42, 38, 73, -55, 49, 83, -67, 61, + 22, 45, -20, 26, 32, -13, 34, 13, -1, 43, -7, 12, + 53, -25, 26, 63, -40, 38, 73, -53, 50, 83, -65, 61, + 23, 46, -17, 27, 35, -11, 35, 16, 1, 44, -3, 13, + 54, -22, 26, 64, -37, 39, 74, -50, 50, 84, -63, 61, + 25, 48, -14, 29, 38, -9, 36, 19, 2, 45, 0, 14, + 54, -18, 27, 64, -34, 39, 74, -48, 51, 84, -61, 62, + 27, 50, -12, 30, 40, -6, 37, 23, 4, 46, 3, 16, + 55, -15, 28, 65, -31, 40, 74, -45, 51, 84, -59, 62, + 29, 52, -9, 32, 43, -4, 38, 26, 6, 46, 7, 17, + 56, -11, 29, 65, -28, 41, 75, -42, 52, 84, -56, 63, + 30, 54, -6, 33, 46, -1, 39, 29, 8, 47, 11, 18, + 56, -8, 30, 66, -25, 42, 75, -40, 52, 85, -53, 63, + 32, 56, -3, 35, 48, 1, 41, 32, 9, 48, 14, 20, + 57, -5, 31, 66, -21, 42, 76, -37, 53, 85, -51, 64, + 34, 58, 0, 36, 50, 3, 42, 35, 11, 49, 18, 21, + 58, -1, 32, 67, -18, 43, 76, -34, 54, 86, -48, 64, + 36, 60, 3, 38, 53, 6, 43, 39, 13, 50, 21, 23, + 59, 3, 34, 68, -14, 44, 77, -30, 55, 86, -45, 65, + 37, 62, 5, 40, 55, 8, 45, 42, 15, 51, 25, 24, + 60, 6, 35, 68, -11, 45, 77, -27, 55, 86, -42, 65, + 39, 64, 8, 41, 58, 11, 46, 45, 17, 52, 28, 26, + 60, 10, 36, 69, -8, 46, 78, -24, 56, 87, -39, 66, + 41, 66, 10, 43, 60, 13, 47, 47, 19, 54, 31, 28, + 61, 13, 37, 70, -4, 47, 78, -21, 57, 87, -36, 67, + 42, 68, 13, 44, 62, 16, 49, 50, 21, 55, 34, 29, + 62, 17, 39, 70, -1, 48, 79, -17, 58, 88, -33, 67, + 44, 70, 16, 46, 65, 18, 50, 53, 24, 56, 38, 31, + 63, 20, 40, 71, 3, 49, 80, -14, 59, 89, -30, 68, + 46, 72, 18, 48, 67, 21, 51, 56, 26, 57, 41, 33, + 64, 24, 42, 72, 6, 51, 80, -10, 60, 89, -26, 69, + 47, 74, 21, 49, 69, 23, 53, 58, 28, 58, 44, 35, + 65, 27, 43, 73, 10, 52, 81, -7, 61, 90, -23, 70, + 49, 76, 23, 51, 71, 25, 54, 61, 30, 59, 47, 36, + 66, 30, 44, 74, 13, 53, 82, -4, 62, 90, -20, 71, + 51, 78, 26, 52, 73, 28, 56, 64, 32, 61, 50, 38, + 67, 34, 46, 75, 17, 54, 82, 0, 63, 91, -16, 71, + 52, 80, 28, 54, 75, 30, 57, 66, 34, 62, 53, 40, + 68, 37, 47, 76, 20, 55, 83, 4, 64, 92, -13, 72, + 54, 81, 31, 55, 77, 32, 59, 68, 36, 63, 56, 42, + 70, 40, 49, 76, 24, 57, 84, 7, 65, 92, -10, 73, + 8, 32, -48, 17, 9, -34, 28, -13, -16, 39, -30, 1, + 51, -44, 17, 61, -55, 31, 72, -66, 44, 82, -76, 56, + 9, 32, -47, 17, 10, -33, 28, -12, -15, 39, -29, 1, + 51, -43, 17, 61, -55, 31, 72, -66, 44, 82, -76, 56, + 9, 33, -46, 17, 11, -33, 28, -11, -15, 39, -29, 1, + 51, -43, 17, 61, -55, 31, 72, -65, 44, 82, -75, 56, + 10, 33, -45, 18, 13, -32, 29, -10, -15, 40, -27, 2, + 51, -42, 17, 61, -54, 31, 72, -65, 44, 82, -75, 56, + 11, 34, -43, 18, 14, -31, 29, -8, -14, 40, -26, 2, + 51, -41, 18, 61, -53, 31, 72, -64, 44, 82, -74, 56, + 12, 35, -42, 19, 16, -30, 29, -6, -14, 40, -24, 2, + 51, -40, 18, 62, -52, 32, 72, -63, 44, 82, -74, 56, + 13, 36, -40, 20, 18, -29, 30, -4, -13, 40, -23, 3, + 51, -38, 18, 62, -51, 32, 72, -62, 44, 82, -73, 56, + 14, 38, -37, 21, 21, -27, 30, -1, -12, 41, -20, 3, + 52, -36, 19, 62, -49, 32, 72, -61, 45, 82, -72, 57, + 16, 39, -35, 22, 23, -26, 31, 2, -11, 41, -18, 4, + 52, -34, 19, 62, -48, 32, 72, -59, 45, 83, -71, 57, + 17, 41, -32, 23, 26, -24, 32, 4, -10, 42, -15, 5, + 52, -32, 20, 62, -46, 33, 73, -58, 45, 83, -69, 57, + 19, 42, -30, 24, 28, -22, 32, 7, -9, 42, -12, 6, + 53, -29, 20, 63, -44, 33, 73, -56, 45, 83, -68, 57, + 20, 44, -27, 25, 31, -20, 33, 11, -7, 43, -9, 7, + 53, -27, 21, 63, -41, 34, 73, -54, 46, 83, -66, 57, + 22, 46, -24, 26, 34, -18, 34, 14, -6, 43, -5, 8, + 54, -23, 21, 63, -38, 34, 73, -52, 46, 83, -64, 58, + 24, 48, -22, 28, 36, -15, 35, 17, -4, 44, -2, 9, + 54, -20, 22, 64, -36, 35, 74, -50, 47, 84, -62, 58, + 25, 49, -19, 29, 39, -13, 36, 21, -3, 45, 1, 10, + 55, -17, 23, 64, -33, 35, 74, -47, 47, 84, -60, 59, + 27, 51, -16, 31, 41, -11, 37, 24, -1, 46, 5, 11, + 55, -14, 24, 65, -30, 36, 74, -45, 48, 84, -58, 59, + 29, 53, -13, 32, 44, -8, 39, 27, 1, 47, 8, 13, + 56, -10, 25, 65, -27, 37, 75, -42, 48, 85, -55, 59, + 31, 55, -11, 34, 46, -6, 40, 30, 3, 48, 12, 14, + 57, -7, 26, 66, -24, 38, 75, -39, 49, 85, -53, 60, + 32, 57, -8, 35, 49, -4, 41, 33, 5, 48, 15, 15, + 57, -4, 27, 66, -21, 39, 76, -36, 50, 85, -50, 60, + 34, 59, -5, 37, 51, -1, 42, 36, 7, 49, 19, 17, + 58, 0, 28, 67, -17, 39, 76, -33, 50, 86, -48, 61, + 36, 61, -2, 38, 54, 1, 44, 40, 9, 51, 22, 18, + 59, 4, 29, 68, -14, 40, 77, -30, 51, 86, -44, 62, + 37, 63, 0, 40, 56, 4, 45, 42, 11, 52, 26, 20, + 60, 7, 31, 68, -10, 41, 77, -26, 52, 87, -42, 62, + 39, 65, 3, 41, 58, 6, 46, 45, 13, 53, 29, 22, + 61, 10, 32, 69, -7, 42, 78, -23, 53, 87, -39, 63, + 41, 66, 6, 43, 60, 8, 47, 48, 15, 54, 32, 23, + 61, 14, 33, 70, -4, 43, 78, -20, 53, 87, -36, 64, + 42, 68, 8, 44, 63, 11, 49, 51, 17, 55, 35, 25, + 62, 17, 35, 70, 0, 44, 79, -17, 54, 88, -33, 64, + 44, 70, 11, 46, 65, 14, 50, 54, 19, 56, 39, 27, + 63, 21, 36, 71, 4, 46, 80, -13, 55, 89, -29, 65, + 46, 72, 13, 48, 67, 16, 52, 56, 21, 57, 42, 29, + 64, 24, 37, 72, 7, 47, 80, -10, 56, 89, -26, 66, + 48, 74, 16, 49, 69, 18, 53, 59, 23, 58, 45, 30, + 65, 27, 39, 73, 10, 48, 81, -6, 57, 90, -23, 67, + 49, 76, 18, 51, 71, 21, 54, 61, 25, 60, 47, 32, + 66, 31, 40, 74, 14, 49, 82, -3, 58, 90, -20, 67, + 51, 78, 21, 53, 74, 23, 56, 64, 28, 61, 51, 34, + 67, 34, 42, 75, 17, 50, 83, 1, 59, 91, -16, 68, + 53, 80, 24, 54, 76, 26, 57, 66, 30, 62, 53, 36, + 69, 37, 44, 76, 21, 52, 83, 4, 60, 92, -13, 69, + 54, 82, 26, 56, 78, 28, 59, 69, 32, 63, 56, 38, + 70, 40, 45, 77, 24, 53, 84, 7, 61, 92, -9, 70, + 10, 35, -51, 18, 14, -38, 29, -9, -21, 40, -27, -4, + 51, -42, 12, 61, -54, 26, 72, -65, 40, 82, -75, 52, + 10, 35, -51, 18, 14, -38, 29, -9, -21, 40, -26, -4, + 51, -41, 12, 61, -53, 26, 72, -64, 40, 82, -75, 52, + 10, 36, -50, 18, 15, -38, 29, -8, -20, 40, -26, -4, + 51, -41, 12, 61, -53, 27, 72, -64, 40, 82, -74, 52, + 11, 36, -49, 18, 16, -37, 29, -7, -20, 40, -25, -3, + 51, -40, 12, 62, -52, 27, 72, -63, 40, 82, -74, 52, + 12, 37, -47, 19, 18, -36, 29, -5, -19, 40, -23, -3, + 51, -39, 13, 62, -52, 27, 72, -63, 40, 82, -73, 52, + 13, 38, -46, 20, 19, -35, 30, -3, -19, 40, -22, -3, + 51, -38, 13, 62, -50, 27, 72, -62, 40, 82, -73, 52, + 14, 39, -44, 20, 21, -34, 30, -1, -18, 41, -20, -2, + 52, -36, 13, 62, -49, 27, 72, -61, 40, 82, -72, 53, + 15, 40, -42, 21, 24, -32, 31, 1, -17, 41, -18, -2, + 52, -34, 14, 62, -48, 28, 72, -60, 40, 82, -71, 53, + 17, 41, -40, 22, 26, -31, 31, 4, -16, 41, -15, -1, + 52, -32, 14, 62, -46, 28, 72, -58, 41, 83, -69, 53, + 18, 43, -37, 23, 28, -29, 32, 7, -15, 42, -13, 0, + 52, -30, 15, 63, -44, 28, 73, -57, 41, 83, -68, 53, + 20, 44, -35, 24, 30, -27, 33, 10, -14, 42, -10, 1, + 53, -27, 15, 63, -42, 29, 73, -55, 41, 83, -67, 53, + 21, 46, -32, 26, 33, -25, 34, 13, -13, 43, -7, 1, + 53, -25, 16, 63, -40, 29, 73, -53, 42, 83, -65, 54, + 23, 47, -29, 27, 35, -23, 35, 16, -11, 44, -4, 3, + 54, -22, 17, 64, -37, 30, 73, -51, 42, 83, -63, 54, + 24, 49, -27, 28, 38, -21, 36, 19, -9, 44, 0, 4, + 54, -19, 17, 64, -35, 30, 74, -48, 43, 84, -61, 54, + 26, 51, -24, 30, 40, -18, 37, 22, -8, 45, 3, 5, + 55, -16, 18, 64, -32, 31, 74, -46, 43, 84, -59, 55, + 28, 52, -22, 31, 43, -16, 38, 25, -6, 46, 6, 6, + 55, -13, 19, 65, -29, 32, 74, -44, 44, 84, -57, 55, + 29, 54, -19, 33, 45, -14, 39, 29, -4, 47, 10, 7, + 56, -9, 20, 65, -26, 32, 75, -41, 44, 85, -54, 56, + 31, 56, -16, 34, 48, -11, 40, 32, -2, 48, 13, 9, + 57, -6, 21, 66, -23, 33, 75, -38, 45, 85, -52, 56, + 33, 58, -13, 35, 50, -9, 41, 35, -1, 49, 16, 10, + 57, -2, 22, 66, -20, 34, 76, -35, 45, 85, -49, 57, + 34, 60, -11, 37, 52, -7, 42, 37, 1, 50, 20, 12, + 58, 1, 23, 67, -16, 35, 76, -32, 46, 86, -47, 57, + 36, 62, -8, 39, 55, -4, 44, 41, 4, 51, 23, 13, + 59, 5, 25, 68, -13, 36, 77, -29, 47, 86, -44, 58, + 38, 64, -5, 40, 57, -2, 45, 43, 6, 52, 27, 15, + 60, 8, 26, 68, -9, 37, 77, -26, 48, 87, -41, 59, + 39, 65, -2, 42, 59, 1, 46, 46, 8, 53, 30, 17, + 61, 11, 27, 69, -6, 38, 78, -22, 49, 87, -38, 59, + 41, 67, 0, 43, 61, 3, 48, 49, 10, 54, 33, 18, + 62, 15, 28, 70, -3, 39, 78, -19, 49, 88, -35, 60, + 43, 69, 3, 45, 63, 6, 49, 51, 12, 55, 36, 20, + 62, 18, 30, 71, 1, 40, 79, -16, 50, 88, -32, 61, + 45, 71, 6, 46, 66, 8, 50, 54, 14, 56, 39, 22, + 64, 22, 31, 71, 4, 41, 80, -12, 51, 89, -28, 61, + 46, 73, 8, 48, 68, 11, 52, 57, 16, 57, 42, 24, + 64, 25, 33, 72, 8, 42, 80, -9, 52, 89, -25, 62, + 48, 75, 11, 49, 70, 13, 53, 59, 18, 59, 45, 25, + 65, 28, 34, 73, 11, 44, 81, -6, 53, 90, -22, 63, + 49, 77, 13, 51, 72, 15, 55, 62, 20, 60, 48, 27, + 66, 31, 36, 74, 14, 45, 82, -2, 54, 90, -19, 64, + 51, 79, 16, 53, 74, 18, 56, 65, 23, 61, 51, 29, + 68, 35, 37, 75, 18, 46, 83, 1, 55, 91, -15, 65, + 53, 80, 18, 54, 76, 20, 58, 67, 25, 62, 54, 31, + 69, 38, 39, 76, 21, 47, 83, 5, 56, 92, -12, 66, + 54, 82, 21, 56, 78, 23, 59, 69, 27, 64, 57, 33, + 70, 41, 40, 77, 25, 49, 84, 8, 57, 92, -9, 67, + 11, 38, -55, 18, 17, -42, 29, -6, -25, 40, -24, -8, + 51, -40, 8, 61, -52, 22, 72, -63, 36, 82, -74, 49, + 11, 38, -54, 18, 18, -42, 29, -5, -25, 40, -24, -8, + 51, -39, 8, 62, -52, 22, 72, -63, 36, 82, -73, 49, + 12, 38, -53, 19, 19, -42, 29, -5, -25, 40, -23, -8, + 51, -39, 8, 62, -51, 22, 72, -63, 36, 82, -73, 49, + 12, 39, -52, 19, 20, -41, 29, -3, -24, 40, -22, -8, + 51, -38, 8, 62, -51, 23, 72, -62, 36, 82, -73, 49, + 13, 39, -51, 20, 21, -40, 30, -2, -24, 40, -21, -8, + 51, -37, 8, 62, -50, 23, 72, -61, 36, 82, -72, 49, + 14, 40, -50, 20, 22, -39, 30, 0, -23, 41, -19, -7, + 52, -36, 9, 62, -49, 23, 72, -61, 36, 82, -72, 49, + 15, 41, -48, 21, 24, -38, 31, 2, -23, 41, -18, -7, + 52, -34, 9, 62, -48, 23, 72, -60, 36, 82, -71, 49, + 16, 42, -46, 22, 26, -36, 31, 4, -22, 41, -15, -6, + 52, -32, 9, 62, -46, 23, 72, -58, 37, 83, -70, 49, + 17, 43, -44, 23, 28, -35, 32, 6, -21, 42, -13, -5, + 52, -30, 10, 62, -45, 24, 73, -57, 37, 83, -68, 49, + 19, 44, -41, 24, 30, -33, 32, 9, -20, 42, -11, -5, + 53, -28, 10, 63, -43, 24, 73, -55, 37, 83, -67, 50, + 20, 46, -39, 25, 32, -31, 33, 12, -18, 43, -8, -4, + 53, -26, 11, 63, -41, 25, 73, -54, 37, 83, -66, 50, + 22, 47, -37, 26, 35, -30, 34, 15, -17, 43, -5, -3, + 53, -23, 12, 63, -38, 25, 73, -52, 38, 83, -64, 50, + 23, 49, -34, 27, 37, -27, 35, 18, -15, 44, -2, -2, + 54, -20, 12, 64, -36, 26, 74, -50, 38, 84, -62, 51, + 25, 50, -31, 29, 39, -25, 36, 21, -14, 45, 1, -1, + 54, -17, 13, 64, -33, 26, 74, -47, 39, 84, -60, 51, + 26, 52, -29, 30, 42, -23, 37, 24, -12, 45, 4, 0, + 55, -14, 14, 65, -31, 27, 74, -45, 39, 84, -58, 51, + 28, 53, -26, 31, 44, -21, 38, 27, -11, 46, 7, 2, + 56, -11, 15, 65, -28, 28, 75, -43, 40, 84, -56, 52, + 30, 55, -23, 33, 46, -18, 39, 30, -9, 47, 11, 3, + 56, -8, 16, 66, -25, 28, 75, -40, 40, 85, -54, 52, + 31, 57, -20, 34, 49, -16, 40, 33, -7, 48, 14, 4, + 57, -5, 17, 66, -22, 29, 75, -37, 41, 85, -51, 53, + 33, 59, -18, 36, 51, -14, 41, 36, -5, 49, 18, 6, + 58, -1, 18, 67, -19, 30, 76, -34, 42, 85, -49, 53, + 35, 61, -15, 37, 53, -11, 43, 38, -3, 50, 21, 7, + 58, 2, 19, 67, -15, 31, 76, -31, 42, 86, -46, 54, + 36, 62, -12, 39, 56, -9, 44, 42, -1, 51, 24, 9, + 59, 6, 20, 68, -12, 32, 77, -28, 43, 86, -43, 54, + 38, 64, -10, 40, 58, -6, 45, 44, 1, 52, 27, 11, + 60, 9, 22, 69, -9, 33, 77, -25, 44, 87, -40, 55, + 40, 66, -7, 42, 60, -4, 47, 47, 3, 53, 31, 12, + 61, 12, 23, 69, -5, 34, 78, -22, 45, 87, -37, 56, + 41, 68, -4, 43, 62, -1, 48, 50, 5, 54, 34, 14, + 62, 16, 24, 70, -2, 35, 79, -18, 46, 88, -34, 56, + 43, 70, -2, 45, 64, 1, 49, 52, 7, 55, 37, 15, + 63, 19, 26, 71, 1, 36, 79, -15, 47, 88, -31, 57, + 45, 72, 1, 47, 66, 4, 51, 55, 9, 56, 40, 17, + 64, 22, 27, 72, 5, 37, 80, -12, 48, 89, -28, 58, + 46, 73, 4, 48, 68, 6, 52, 58, 12, 58, 43, 19, + 65, 26, 29, 72, 8, 38, 81, -8, 48, 89, -25, 59, + 48, 75, 6, 50, 70, 8, 53, 60, 14, 59, 46, 21, + 66, 29, 30, 73, 12, 40, 81, -5, 49, 90, -22, 60, + 50, 77, 9, 51, 72, 11, 55, 62, 16, 60, 49, 23, + 67, 32, 32, 74, 15, 41, 82, -2, 50, 90, -18, 60, + 51, 79, 11, 53, 75, 13, 56, 65, 18, 61, 52, 25, + 68, 35, 33, 75, 19, 42, 83, 2, 52, 91, -15, 61, + 53, 81, 14, 54, 77, 16, 58, 68, 20, 62, 55, 27, + 69, 39, 35, 76, 22, 44, 83, 5, 53, 92, -12, 62, + 55, 83, 16, 56, 79, 18, 59, 70, 22, 64, 57, 28, + 70, 42, 36, 77, 25, 45, 84, 8, 54, 92, -8, 63, + 12, 40, -58, 19, 21, -46, 29, -3, -30, 40, -22, -13, + 51, -37, 3, 62, -50, 18, 72, -62, 32, 82, -73, 45, + 12, 41, -57, 19, 21, -46, 30, -2, -29, 40, -21, -13, + 51, -37, 4, 62, -50, 18, 72, -62, 32, 82, -72, 45, + 13, 41, -57, 19, 22, -46, 30, -1, -29, 40, -20, -13, + 51, -37, 4, 62, -50, 18, 72, -61, 32, 82, -72, 45, + 13, 41, -56, 20, 23, -45, 30, 0, -29, 40, -19, -12, + 51, -36, 4, 62, -49, 18, 72, -61, 32, 82, -72, 45, + 14, 42, -55, 20, 24, -44, 30, 1, -28, 41, -18, -12, + 52, -35, 4, 62, -48, 19, 72, -60, 32, 82, -71, 45, + 15, 42, -53, 21, 25, -43, 31, 3, -28, 41, -17, -12, + 52, -34, 4, 62, -47, 19, 72, -59, 32, 82, -70, 45, + 16, 43, -52, 22, 27, -42, 31, 4, -27, 41, -15, -11, + 52, -32, 5, 62, -46, 19, 72, -58, 32, 83, -70, 45, + 17, 44, -49, 22, 29, -41, 32, 7, -26, 42, -13, -11, + 52, -30, 5, 62, -45, 19, 72, -57, 33, 83, -68, 46, + 18, 45, -47, 23, 30, -39, 32, 9, -25, 42, -11, -10, + 52, -28, 5, 63, -43, 20, 73, -56, 33, 83, -67, 46, + 20, 46, -45, 24, 32, -37, 33, 11, -24, 42, -9, -9, + 53, -26, 6, 63, -41, 20, 73, -54, 33, 83, -66, 46, + 21, 47, -43, 25, 34, -36, 34, 14, -23, 43, -6, -8, + 53, -24, 7, 63, -39, 20, 73, -52, 34, 83, -65, 46, + 22, 49, -41, 27, 36, -34, 34, 17, -21, 44, -3, -7, + 54, -22, 7, 63, -37, 21, 73, -51, 34, 83, -63, 47, + 24, 50, -38, 28, 39, -32, 35, 20, -20, 44, 0, -6, + 54, -19, 8, 64, -34, 22, 74, -48, 34, 84, -61, 47, + 25, 52, -36, 29, 41, -30, 36, 22, -18, 45, 3, -5, + 55, -16, 9, 64, -32, 22, 74, -46, 35, 84, -59, 47, + 27, 53, -33, 30, 43, -27, 37, 25, -17, 46, 6, -4, + 55, -13, 10, 65, -29, 23, 74, -44, 35, 84, -57, 48, + 28, 55, -30, 32, 45, -25, 38, 28, -15, 46, 9, -3, + 56, -10, 11, 65, -27, 23, 75, -41, 36, 84, -55, 48, + 30, 56, -28, 33, 48, -23, 39, 31, -13, 47, 12, -1, + 56, -7, 12, 66, -23, 24, 75, -39, 37, 85, -53, 49, + 32, 58, -25, 35, 50, -20, 41, 34, -11, 48, 16, 0, + 57, -3, 13, 66, -20, 25, 75, -36, 37, 85, -50, 49, + 33, 60, -22, 36, 52, -18, 42, 37, -10, 49, 19, 1, + 58, 0, 14, 67, -17, 26, 76, -33, 38, 85, -48, 50, + 35, 61, -20, 38, 54, -16, 43, 40, -8, 50, 22, 3, + 58, 3, 15, 67, -14, 27, 76, -30, 39, 86, -45, 50, + 37, 63, -17, 39, 56, -13, 44, 43, -6, 51, 25, 4, + 59, 7, 16, 68, -11, 28, 77, -27, 39, 86, -42, 51, + 38, 65, -14, 41, 59, -11, 45, 45, -4, 52, 28, 6, + 60, 10, 17, 69, -8, 29, 77, -24, 40, 87, -39, 52, + 40, 67, -12, 42, 61, -8, 47, 48, -2, 53, 32, 8, + 61, 13, 19, 69, -4, 30, 78, -21, 41, 87, -36, 52, + 42, 69, -9, 44, 63, -6, 48, 50, 0, 54, 35, 9, + 62, 16, 20, 70, -1, 31, 79, -18, 42, 88, -33, 53, + 43, 70, -6, 45, 65, -4, 49, 53, 3, 55, 38, 11, + 63, 20, 21, 71, 2, 32, 79, -14, 43, 88, -30, 54, + 45, 72, -4, 47, 67, -1, 51, 56, 5, 57, 41, 13, + 64, 23, 23, 72, 6, 33, 80, -11, 44, 89, -27, 54, + 47, 74, -1, 48, 69, 1, 52, 58, 7, 58, 44, 15, + 65, 26, 24, 72, 9, 34, 81, -8, 45, 89, -24, 55, + 48, 76, 1, 50, 71, 4, 54, 61, 9, 59, 47, 17, + 66, 30, 26, 73, 12, 36, 81, -4, 46, 90, -21, 56, + 50, 78, 4, 51, 73, 6, 55, 63, 11, 60, 49, 18, + 67, 33, 27, 74, 16, 37, 82, -1, 47, 91, -18, 57, + 52, 80, 7, 53, 75, 9, 56, 66, 14, 61, 52, 20, + 68, 36, 29, 75, 19, 38, 83, 3, 48, 91, -14, 58, + 53, 81, 9, 55, 77, 11, 58, 68, 16, 63, 55, 22, + 69, 39, 31, 76, 23, 40, 84, 6, 49, 92, -11, 59, + 55, 83, 12, 56, 79, 14, 59, 70, 18, 64, 58, 24, + 70, 42, 32, 77, 26, 41, 84, 9, 50, 93, -8, 60, + 13, 43, -61, 20, 24, -50, 30, 1, -34, 40, -19, -17, + 51, -35, -1, 62, -49, 14, 72, -60, 28, 82, -71, 41, + 14, 43, -61, 20, 25, -50, 30, 1, -34, 41, -18, -17, + 51, -35, -1, 62, -48, 14, 72, -60, 28, 82, -71, 41, + 14, 43, -60, 20, 25, -49, 30, 2, -33, 41, -18, -17, + 52, -34, -1, 62, -48, 14, 72, -60, 28, 82, -71, 41, + 14, 44, -59, 21, 26, -49, 30, 3, -33, 41, -17, -17, + 52, -33, -1, 62, -47, 14, 72, -59, 28, 82, -70, 41, + 15, 44, -58, 21, 27, -48, 31, 4, -33, 41, -16, -16, + 52, -33, 0, 62, -46, 14, 72, -59, 28, 82, -70, 41, + 16, 45, -57, 22, 28, -47, 31, 6, -32, 41, -14, -16, + 52, -31, 0, 62, -45, 15, 72, -58, 28, 83, -69, 42, + 17, 45, -55, 22, 29, -46, 31, 7, -31, 42, -13, -16, + 52, -30, 0, 62, -44, 15, 72, -57, 29, 83, -68, 42, + 18, 46, -53, 23, 31, -45, 32, 9, -30, 42, -11, -15, + 52, -28, 1, 63, -43, 15, 73, -56, 29, 83, -67, 42, + 19, 47, -51, 24, 33, -43, 33, 11, -29, 42, -9, -14, + 53, -26, 1, 63, -41, 16, 73, -54, 29, 83, -66, 42, + 20, 48, -49, 25, 35, -42, 33, 14, -28, 43, -6, -14, + 53, -24, 2, 63, -40, 16, 73, -53, 29, 83, -65, 42, + 22, 49, -47, 26, 36, -40, 34, 16, -27, 43, -4, -13, + 53, -22, 2, 63, -38, 16, 73, -51, 30, 83, -64, 43, + 23, 50, -45, 27, 38, -38, 35, 19, -26, 44, -1, -12, + 54, -20, 3, 64, -35, 17, 73, -49, 30, 83, -62, 43, + 25, 52, -42, 28, 41, -36, 36, 22, -24, 44, 2, -11, + 54, -17, 4, 64, -33, 17, 74, -47, 30, 84, -60, 43, + 26, 53, -40, 30, 43, -34, 37, 24, -23, 45, 5, -10, + 55, -14, 4, 64, -30, 18, 74, -45, 31, 84, -58, 44, + 27, 54, -37, 31, 45, -32, 38, 27, -21, 46, 8, -9, + 55, -11, 5, 65, -28, 19, 74, -43, 31, 84, -56, 44, + 29, 56, -35, 32, 47, -30, 39, 30, -20, 47, 11, -7, + 56, -8, 6, 65, -25, 19, 75, -40, 32, 85, -54, 44, + 31, 58, -32, 34, 49, -27, 40, 33, -18, 48, 14, -6, + 57, -5, 7, 66, -22, 20, 75, -37, 33, 85, -52, 45, + 32, 59, -29, 35, 51, -25, 41, 35, -16, 48, 17, -5, + 57, -2, 8, 66, -19, 21, 76, -35, 33, 85, -49, 45, + 34, 61, -27, 36, 53, -23, 42, 38, -14, 49, 20, -3, + 58, 1, 9, 67, -16, 22, 76, -32, 34, 86, -47, 46, + 35, 62, -24, 38, 55, -20, 43, 41, -12, 50, 23, -2, + 59, 4, 11, 67, -13, 23, 77, -29, 35, 86, -44, 47, + 37, 64, -21, 39, 57, -18, 45, 44, -10, 51, 27, 0, + 60, 8, 12, 68, -10, 24, 77, -26, 35, 86, -41, 47, + 39, 66, -19, 41, 60, -15, 46, 46, -8, 52, 30, 2, + 60, 11, 13, 69, -6, 25, 78, -23, 36, 87, -38, 48, + 40, 68, -16, 42, 62, -13, 47, 49, -6, 53, 33, 3, + 61, 14, 14, 69, -3, 26, 78, -20, 37, 87, -36, 49, + 42, 69, -14, 44, 64, -11, 48, 51, -4, 54, 36, 5, + 62, 17, 16, 70, 0, 27, 79, -17, 38, 88, -33, 49, + 43, 71, -11, 45, 66, -8, 50, 54, -2, 55, 38, 7, + 63, 21, 17, 71, 3, 28, 79, -14, 39, 88, -30, 50, + 45, 73, -8, 47, 68, -5, 51, 57, 0, 57, 42, 9, + 64, 24, 19, 72, 7, 29, 80, -10, 40, 89, -26, 51, + 47, 75, -6, 49, 70, -3, 52, 59, 3, 58, 45, 10, + 65, 27, 20, 73, 10, 30, 81, -7, 41, 89, -23, 52, + 48, 76, -3, 50, 72, -1, 54, 61, 5, 59, 47, 12, + 66, 30, 22, 73, 13, 32, 81, -4, 42, 90, -20, 52, + 50, 78, -1, 52, 74, 2, 55, 64, 7, 60, 50, 14, + 67, 33, 23, 74, 16, 33, 82, 0, 43, 91, -17, 53, + 52, 80, 2, 53, 76, 4, 57, 66, 9, 62, 53, 16, + 68, 37, 25, 75, 20, 34, 83, 3, 44, 91, -13, 54, + 53, 82, 5, 55, 78, 7, 58, 69, 11, 63, 56, 18, + 69, 40, 26, 76, 23, 36, 84, 6, 45, 92, -10, 55, + 55, 84, 7, 56, 80, 9, 59, 71, 13, 64, 58, 20, + 70, 43, 28, 77, 26, 37, 84, 10, 46, 93, -7, 56, + 15, 46, -64, 21, 28, -54, 30, 5, -39, 41, -15, -22, + 52, -32, -6, 62, -46, 9, 72, -58, 23, 82, -70, 37, + 15, 46, -64, 21, 28, -54, 31, 5, -38, 41, -15, -22, + 52, -32, -6, 62, -46, 9, 72, -58, 23, 82, -70, 37, + 15, 46, -63, 21, 29, -54, 31, 6, -38, 41, -14, -22, + 52, -32, -6, 62, -46, 9, 72, -58, 23, 82, -69, 37, + 16, 46, -63, 22, 29, -53, 31, 7, -38, 41, -13, -22, + 52, -31, -5, 62, -45, 10, 72, -57, 24, 83, -69, 37, + 16, 47, -62, 22, 30, -52, 31, 8, -37, 41, -12, -21, + 52, -30, -5, 62, -44, 10, 72, -57, 24, 83, -68, 37, + 17, 47, -60, 22, 31, -51, 32, 9, -37, 42, -11, -21, + 52, -29, -5, 62, -43, 10, 72, -56, 24, 83, -68, 37, + 18, 48, -59, 23, 33, -50, 32, 11, -36, 42, -10, -20, + 52, -28, -5, 63, -42, 10, 73, -55, 24, 83, -67, 37, + 19, 48, -57, 24, 34, -49, 33, 13, -35, 42, -8, -20, + 53, -26, -4, 63, -41, 10, 73, -54, 24, 83, -66, 38, + 20, 49, -55, 25, 36, -48, 33, 14, -34, 43, -6, -19, + 53, -24, -4, 63, -39, 11, 73, -53, 25, 83, -65, 38, + 21, 50, -53, 26, 37, -46, 34, 17, -33, 43, -4, -18, + 53, -22, -3, 63, -38, 11, 73, -51, 25, 83, -63, 38, + 22, 51, -51, 27, 39, -44, 34, 19, -32, 44, -1, -18, + 54, -20, -3, 64, -36, 12, 73, -49, 25, 83, -62, 38, + 24, 52, -49, 28, 41, -43, 35, 21, -31, 44, 1, -17, + 54, -18, -2, 64, -34, 12, 74, -48, 26, 84, -61, 39, + 25, 53, -47, 29, 43, -41, 36, 24, -29, 45, 4, -16, + 55, -15, -1, 64, -31, 13, 74, -45, 26, 84, -59, 39, + 27, 55, -44, 30, 45, -39, 37, 26, -28, 45, 7, -15, + 55, -12, 0, 65, -29, 13, 74, -43, 26, 84, -57, 39, + 28, 56, -42, 31, 46, -37, 38, 29, -26, 46, 10, -13, + 56, -10, 0, 65, -26, 14, 75, -41, 27, 84, -55, 40, + 30, 57, -39, 33, 48, -34, 39, 32, -25, 47, 12, -12, + 56, -7, 1, 65, -24, 15, 75, -39, 28, 85, -53, 40, + 31, 59, -37, 34, 51, -32, 40, 34, -23, 48, 16, -11, + 57, -3, 2, 66, -21, 15, 75, -36, 28, 85, -50, 41, + 33, 61, -34, 36, 53, -30, 41, 37, -21, 49, 19, -9, + 57, 0, 3, 67, -18, 16, 76, -33, 29, 85, -48, 41, + 34, 62, -32, 37, 54, -27, 42, 40, -19, 50, 22, -8, + 58, 3, 5, 67, -15, 17, 76, -31, 29, 86, -46, 42, + 36, 64, -29, 38, 56, -25, 44, 42, -17, 50, 25, -7, + 59, 6, 6, 68, -12, 18, 77, -28, 30, 86, -43, 42, + 38, 65, -26, 40, 59, -23, 45, 45, -15, 52, 28, -5, + 60, 9, 7, 68, -8, 19, 77, -25, 31, 87, -40, 43, + 39, 67, -24, 41, 61, -20, 46, 48, -13, 53, 31, -3, + 61, 12, 8, 69, -5, 20, 78, -22, 32, 87, -37, 44, + 41, 69, -21, 43, 63, -18, 47, 50, -11, 54, 34, -2, + 61, 15, 10, 70, -2, 21, 78, -19, 33, 87, -34, 44, + 42, 70, -19, 44, 65, -16, 49, 53, -9, 55, 37, 0, + 62, 19, 11, 70, 1, 22, 79, -16, 34, 88, -32, 45, + 44, 72, -16, 46, 67, -13, 50, 55, -7, 56, 40, 2, + 63, 22, 12, 71, 4, 23, 79, -13, 34, 88, -29, 46, + 46, 74, -13, 47, 69, -10, 51, 58, -5, 57, 43, 4, + 64, 25, 14, 72, 8, 25, 80, -9, 35, 89, -25, 47, + 47, 76, -11, 49, 71, -8, 53, 60, -2, 58, 46, 5, + 65, 28, 15, 73, 11, 26, 81, -6, 36, 90, -22, 47, + 49, 77, -8, 50, 73, -6, 54, 62, 0, 59, 48, 7, + 66, 31, 17, 74, 14, 27, 82, -3, 37, 90, -19, 48, + 50, 79, -6, 52, 74, -3, 55, 65, 2, 60, 51, 9, + 67, 34, 18, 74, 17, 28, 82, 0, 39, 91, -16, 49, + 52, 81, -3, 54, 77, -1, 57, 67, 4, 62, 54, 11, + 68, 38, 20, 75, 21, 30, 83, 4, 40, 91, -13, 50, + 54, 83, 0, 55, 79, 2, 58, 69, 6, 63, 57, 13, + 69, 41, 22, 76, 24, 31, 84, 7, 41, 92, -10, 51, + 55, 84, 2, 57, 80, 4, 60, 72, 8, 64, 59, 15, + 70, 44, 23, 77, 27, 32, 85, 10, 42, 93, -6, 52, + 16, 48, -68, 22, 31, -58, 31, 8, -43, 41, -12, -26, + 52, -30, -10, 62, -44, 5, 72, -57, 19, 83, -68, 33, + 16, 48, -67, 22, 32, -58, 31, 9, -42, 41, -12, -26, + 52, -29, -10, 62, -44, 5, 72, -56, 19, 83, -68, 33, + 16, 48, -67, 22, 32, -57, 31, 9, -42, 41, -11, -26, + 52, -29, -10, 62, -43, 5, 72, -56, 19, 83, -68, 33, + 17, 48, -66, 22, 33, -57, 31, 10, -42, 42, -11, -26, + 52, -28, -10, 62, -43, 5, 72, -56, 20, 83, -67, 33, + 17, 49, -65, 23, 33, -56, 32, 11, -41, 42, -10, -26, + 52, -27, -9, 62, -42, 6, 73, -55, 20, 83, -67, 33, + 18, 49, -64, 23, 34, -55, 32, 12, -41, 42, -8, -25, + 52, -26, -9, 63, -41, 6, 73, -54, 20, 83, -66, 34, + 19, 50, -62, 24, 35, -54, 33, 13, -40, 42, -7, -25, + 53, -25, -9, 63, -40, 6, 73, -53, 20, 83, -65, 34, + 20, 50, -61, 25, 37, -53, 33, 15, -39, 43, -5, -24, + 53, -23, -8, 63, -39, 6, 73, -52, 20, 83, -64, 34, + 21, 51, -59, 25, 38, -51, 34, 17, -38, 43, -3, -23, + 53, -22, -8, 63, -37, 7, 73, -51, 21, 83, -63, 34, + 22, 52, -57, 26, 39, -50, 34, 19, -37, 43, -1, -23, + 54, -20, -7, 63, -36, 7, 73, -49, 21, 83, -62, 34, + 23, 53, -55, 27, 41, -48, 35, 21, -36, 44, 1, -22, + 54, -18, -7, 64, -34, 7, 73, -48, 21, 83, -61, 35, + 24, 54, -53, 28, 43, -47, 36, 23, -35, 44, 3, -21, + 54, -16, -6, 64, -32, 8, 74, -46, 22, 84, -59, 35, + 26, 55, -51, 30, 45, -45, 37, 26, -33, 45, 6, -20, + 55, -13, -5, 64, -29, 9, 74, -44, 22, 84, -57, 35, + 27, 56, -48, 31, 46, -43, 37, 28, -32, 46, 9, -19, + 55, -10, -5, 65, -27, 9, 74, -42, 22, 84, -56, 36, + 29, 58, -46, 32, 48, -41, 38, 31, -30, 47, 12, -18, + 56, -8, -4, 65, -25, 10, 75, -40, 23, 84, -54, 36, + 30, 59, -44, 33, 50, -39, 39, 33, -29, 47, 14, -17, + 56, -5, -3, 66, -22, 10, 75, -37, 24, 85, -52, 36, + 32, 60, -41, 35, 52, -36, 41, 36, -27, 48, 17, -15, + 57, -2, -2, 66, -19, 11, 75, -35, 24, 85, -49, 37, + 33, 62, -38, 36, 54, -34, 42, 39, -25, 49, 20, -14, + 58, 1, -1, 67, -16, 12, 76, -32, 25, 85, -47, 37, + 35, 63, -36, 37, 56, -32, 43, 41, -23, 50, 23, -12, + 58, 4, 0, 67, -13, 13, 76, -29, 25, 86, -44, 38, + 36, 65, -33, 39, 58, -30, 44, 44, -21, 51, 26, -11, + 59, 7, 1, 68, -10, 14, 77, -27, 26, 86, -42, 39, + 38, 66, -31, 40, 60, -27, 45, 46, -19, 52, 29, -9, + 60, 11, 3, 68, -7, 15, 77, -23, 27, 87, -39, 39, + 39, 68, -28, 42, 62, -25, 46, 49, -17, 53, 32, -8, + 61, 14, 4, 69, -4, 16, 78, -21, 28, 87, -36, 40, + 41, 70, -25, 43, 64, -22, 48, 51, -15, 54, 35, -6, + 62, 17, 5, 70, -1, 17, 78, -18, 29, 88, -34, 41, + 43, 71, -23, 45, 66, -20, 49, 54, -13, 55, 38, -4, + 62, 20, 7, 70, 2, 18, 79, -15, 30, 88, -31, 41, + 44, 73, -20, 46, 67, -18, 50, 56, -11, 56, 41, -3, + 63, 23, 8, 71, 5, 19, 80, -12, 30, 89, -28, 42, + 46, 75, -18, 48, 70, -15, 52, 59, -9, 57, 44, -1, + 64, 26, 10, 72, 9, 20, 80, -8, 32, 89, -24, 43, + 47, 76, -15, 49, 71, -13, 53, 61, -7, 58, 46, 1, + 65, 29, 11, 73, 12, 22, 81, -5, 33, 90, -21, 44, + 49, 78, -13, 51, 73, -10, 54, 63, -5, 59, 49, 3, + 66, 32, 13, 74, 15, 23, 82, -2, 34, 90, -18, 45, + 51, 80, -10, 52, 75, -8, 56, 65, -3, 61, 52, 5, + 67, 35, 14, 74, 18, 24, 82, 1, 35, 91, -15, 45, + 52, 82, -7, 54, 77, -5, 57, 68, 0, 62, 55, 7, + 68, 39, 16, 75, 22, 26, 83, 5, 36, 92, -12, 46, + 54, 83, -5, 55, 79, -3, 58, 70, 2, 63, 57, 9, + 69, 41, 17, 76, 25, 27, 84, 8, 37, 92, -9, 47, + 55, 85, -2, 57, 81, 0, 60, 72, 4, 64, 60, 11, + 70, 44, 19, 77, 28, 28, 85, 11, 38, 93, -6, 48, + 17, 50, -70, 22, 34, -61, 32, 11, -47, 42, -9, -31, + 52, -27, -14, 62, -42, 1, 72, -55, 15, 83, -67, 29, + 17, 50, -70, 23, 35, -61, 32, 12, -46, 42, -9, -30, + 52, -27, -14, 62, -42, 1, 73, -55, 15, 83, -67, 29, + 18, 50, -70, 23, 35, -61, 32, 12, -46, 42, -8, -30, + 52, -26, -14, 63, -41, 1, 73, -54, 15, 83, -66, 29, + 18, 51, -69, 23, 36, -60, 32, 13, -46, 42, -7, -30, + 52, -26, -14, 63, -41, 1, 73, -54, 16, 83, -66, 29, + 19, 51, -68, 24, 36, -60, 32, 14, -45, 42, -7, -30, + 53, -25, -14, 63, -40, 1, 73, -53, 16, 83, -65, 30, + 19, 51, -67, 24, 37, -59, 33, 15, -45, 42, -5, -29, + 53, -24, -13, 63, -39, 2, 73, -53, 16, 83, -65, 30, + 20, 52, -66, 25, 38, -58, 33, 16, -44, 43, -4, -29, + 53, -23, -13, 63, -38, 2, 73, -52, 16, 83, -64, 30, + 21, 52, -64, 25, 39, -56, 34, 18, -43, 43, -2, -28, + 53, -21, -13, 63, -37, 2, 73, -50, 16, 83, -63, 30, + 22, 53, -62, 26, 40, -55, 34, 20, -42, 43, -1, -28, + 53, -19, -12, 63, -35, 2, 73, -49, 16, 83, -62, 30, + 23, 54, -61, 27, 42, -54, 35, 22, -41, 44, 1, -27, + 54, -18, -12, 64, -34, 3, 73, -48, 17, 83, -61, 30, + 24, 55, -59, 28, 43, -52, 35, 24, -40, 44, 3, -26, + 54, -16, -11, 64, -32, 3, 74, -46, 17, 84, -59, 31, + 25, 56, -57, 29, 45, -51, 36, 26, -39, 45, 6, -25, + 55, -14, -10, 64, -30, 4, 74, -45, 17, 84, -58, 31, + 27, 57, -54, 30, 46, -49, 37, 28, -38, 45, 8, -24, + 55, -11, -10, 65, -28, 4, 74, -42, 18, 84, -56, 31, + 28, 58, -52, 31, 48, -47, 38, 30, -36, 46, 11, -23, + 56, -8, -9, 65, -25, 5, 75, -40, 18, 84, -54, 32, + 29, 59, -50, 32, 50, -45, 39, 33, -35, 47, 13, -22, + 56, -6, -8, 65, -23, 6, 75, -38, 19, 85, -52, 32, + 31, 60, -48, 34, 52, -43, 40, 35, -33, 48, 16, -21, + 57, -3, -7, 66, -20, 6, 75, -36, 19, 85, -50, 33, + 32, 62, -45, 35, 54, -40, 41, 38, -31, 48, 19, -19, + 57, 0, -6, 66, -17, 7, 76, -33, 20, 85, -48, 33, + 34, 63, -42, 36, 55, -38, 42, 40, -29, 49, 22, -18, + 58, 3, -5, 67, -15, 8, 76, -31, 21, 86, -46, 34, + 35, 64, -40, 38, 57, -36, 43, 43, -28, 50, 25, -17, + 59, 6, -4, 67, -12, 9, 76, -28, 21, 86, -43, 34, + 37, 66, -38, 39, 59, -34, 44, 45, -26, 51, 28, -15, + 59, 9, -3, 68, -9, 10, 77, -25, 22, 86, -41, 35, + 38, 68, -35, 41, 61, -31, 46, 48, -24, 52, 31, -14, + 60, 12, -2, 69, -6, 11, 78, -22, 23, 87, -38, 35, + 40, 69, -32, 42, 63, -29, 47, 50, -22, 53, 33, -12, + 61, 15, 0, 69, -3, 12, 78, -19, 24, 87, -35, 36, + 41, 71, -30, 43, 65, -27, 48, 52, -20, 54, 36, -10, + 62, 18, 1, 70, 0, 13, 79, -16, 25, 88, -32, 37, + 43, 72, -27, 45, 67, -24, 49, 55, -18, 55, 39, -9, + 63, 21, 2, 71, 3, 14, 79, -14, 26, 88, -30, 37, + 44, 74, -25, 46, 68, -22, 50, 57, -16, 56, 42, -7, + 63, 24, 4, 71, 6, 15, 80, -10, 26, 89, -27, 38, + 46, 76, -22, 48, 70, -19, 52, 60, -13, 57, 45, -5, + 65, 27, 5, 72, 10, 16, 80, -7, 28, 89, -24, 39, + 48, 77, -19, 49, 72, -17, 53, 62, -11, 59, 47, -3, + 65, 30, 7, 73, 13, 17, 81, -4, 29, 90, -21, 40, + 49, 79, -17, 51, 74, -15, 54, 64, -9, 60, 50, -1, + 66, 33, 8, 74, 16, 19, 82, -1, 30, 90, -18, 41, + 51, 80, -14, 52, 76, -12, 56, 66, -7, 61, 53, 0, + 67, 36, 10, 75, 19, 20, 82, 2, 31, 91, -14, 42, + 53, 82, -12, 54, 78, -9, 57, 69, -5, 62, 56, 2, + 69, 39, 12, 76, 23, 21, 83, 6, 32, 92, -11, 43, + 54, 84, -9, 56, 80, -7, 59, 71, -2, 63, 58, 4, + 70, 42, 13, 76, 26, 23, 84, 9, 33, 92, -8, 44, + 56, 86, -7, 57, 82, -5, 60, 73, 0, 65, 61, 6, + 71, 45, 15, 77, 29, 24, 85, 12, 34, 93, -5, 45, + 18, 52, -73, 23, 37, -65, 32, 15, -50, 42, -6, -35, + 52, -24, -18, 63, -40, -3, 73, -53, 11, 83, -65, 25, + 18, 53, -73, 24, 38, -65, 32, 15, -50, 42, -6, -35, + 53, -24, -18, 63, -39, -3, 73, -53, 11, 83, -65, 25, + 19, 53, -73, 24, 38, -64, 32, 16, -50, 42, -5, -34, + 53, -24, -18, 63, -39, -3, 73, -52, 11, 83, -65, 25, + 19, 53, -72, 24, 38, -64, 33, 16, -50, 42, -4, -34, + 53, -23, -18, 63, -38, -3, 73, -52, 11, 83, -64, 26, + 20, 53, -71, 24, 39, -63, 33, 17, -49, 43, -4, -34, + 53, -22, -18, 63, -38, -3, 73, -51, 12, 83, -64, 26, + 20, 53, -70, 25, 40, -62, 33, 18, -49, 43, -3, -34, + 53, -21, -18, 63, -37, -3, 73, -51, 12, 83, -63, 26, + 21, 54, -69, 25, 41, -61, 34, 19, -48, 43, -1, -33, + 53, -20, -17, 63, -36, -2, 73, -50, 12, 83, -62, 26, + 22, 54, -67, 26, 42, -60, 34, 21, -47, 43, 0, -32, + 53, -19, -17, 63, -35, -2, 73, -49, 12, 83, -61, 26, + 23, 55, -66, 27, 43, -59, 35, 23, -46, 44, 2, -32, + 54, -17, -16, 64, -33, -2, 73, -47, 12, 83, -60, 26, + 24, 56, -64, 28, 44, -57, 35, 24, -45, 44, 4, -31, + 54, -15, -16, 64, -32, -1, 74, -46, 13, 84, -59, 27, + 25, 57, -62, 29, 45, -56, 36, 26, -44, 45, 6, -30, + 54, -13, -15, 64, -30, -1, 74, -44, 13, 84, -58, 27, + 26, 57, -60, 30, 47, -54, 37, 28, -43, 45, 8, -29, + 55, -11, -15, 64, -28, 0, 74, -43, 13, 84, -56, 27, + 27, 58, -58, 31, 48, -52, 38, 30, -42, 46, 11, -28, + 55, -9, -14, 65, -26, 0, 74, -41, 14, 84, -55, 27, + 29, 59, -56, 32, 50, -51, 38, 33, -40, 46, 13, -27, + 56, -6, -13, 65, -24, 1, 75, -39, 14, 84, -53, 28, + 30, 61, -54, 33, 52, -49, 39, 35, -39, 47, 16, -26, + 56, -4, -12, 66, -21, 1, 75, -37, 15, 85, -51, 28, + 31, 62, -51, 34, 53, -47, 40, 37, -37, 48, 18, -25, + 57, -1, -11, 66, -19, 2, 75, -34, 15, 85, -49, 29, + 33, 63, -49, 36, 55, -44, 41, 39, -35, 49, 21, -24, + 58, 2, -10, 67, -16, 3, 76, -32, 16, 85, -47, 29, + 34, 64, -46, 37, 57, -42, 42, 42, -34, 50, 24, -22, + 58, 4, -9, 67, -13, 4, 76, -29, 17, 86, -44, 30, + 36, 66, -44, 38, 58, -40, 43, 44, -32, 50, 26, -21, + 59, 7, -8, 68, -10, 5, 77, -27, 17, 86, -42, 30, + 37, 67, -42, 40, 60, -38, 45, 46, -30, 51, 29, -19, + 60, 10, -7, 68, -8, 6, 77, -24, 18, 86, -40, 31, + 39, 69, -39, 41, 62, -35, 46, 49, -28, 52, 32, -18, + 60, 13, -6, 69, -4, 7, 78, -21, 19, 87, -37, 32, + 40, 70, -36, 42, 64, -33, 47, 51, -26, 53, 35, -16, + 61, 16, -4, 69, -1, 8, 78, -18, 20, 87, -34, 32, + 42, 72, -34, 44, 66, -31, 48, 54, -24, 54, 38, -15, + 62, 19, -3, 70, 2, 9, 79, -15, 21, 88, -31, 33, + 43, 73, -31, 45, 68, -28, 49, 56, -22, 55, 40, -13, + 63, 22, -2, 71, 5, 10, 79, -12, 22, 88, -29, 34, + 45, 75, -29, 47, 69, -26, 51, 58, -20, 56, 43, -11, + 64, 25, 0, 72, 8, 11, 80, -9, 22, 89, -26, 34, + 47, 76, -26, 48, 71, -24, 52, 61, -18, 58, 46, -9, + 65, 28, 1, 72, 11, 12, 81, -6, 24, 89, -22, 35, + 48, 78, -24, 50, 73, -21, 53, 63, -16, 59, 48, -8, + 66, 31, 3, 73, 14, 13, 81, -3, 25, 90, -20, 36, + 50, 80, -21, 51, 75, -19, 55, 65, -13, 60, 51, -6, + 67, 34, 4, 74, 17, 15, 82, 0, 26, 90, -17, 37, + 51, 81, -19, 53, 77, -16, 56, 67, -11, 61, 54, -4, + 68, 37, 6, 75, 20, 16, 83, 3, 27, 91, -14, 38, + 53, 83, -16, 54, 79, -14, 58, 70, -9, 62, 57, -2, + 69, 40, 7, 76, 24, 17, 83, 7, 28, 92, -10, 39, + 54, 85, -14, 56, 81, -11, 59, 72, -7, 64, 59, 0, + 70, 43, 9, 77, 27, 19, 84, 10, 29, 92, -7, 40, + 56, 86, -11, 57, 82, -9, 60, 74, -5, 65, 62, 2, + 71, 46, 11, 78, 30, 20, 85, 13, 30, 93, -4, 41, + 20, 55, -77, 24, 41, -69, 33, 19, -55, 42, -2, -39, + 53, -21, -23, 63, -37, -8, 73, -51, 7, 83, -63, 21, + 20, 55, -76, 25, 41, -68, 33, 19, -55, 43, -2, -39, + 53, -21, -23, 63, -37, -8, 73, -50, 7, 83, -63, 21, + 20, 55, -76, 25, 41, -68, 33, 19, -54, 43, -2, -39, + 53, -21, -23, 63, -36, -8, 73, -50, 7, 83, -63, 21, + 20, 55, -75, 25, 42, -68, 33, 20, -54, 43, -1, -39, + 53, -20, -23, 63, -36, -8, 73, -50, 7, 83, -62, 21, + 21, 56, -74, 25, 42, -67, 34, 21, -54, 43, 0, -38, + 53, -19, -23, 63, -35, -7, 73, -49, 7, 83, -62, 21, + 21, 56, -74, 26, 43, -66, 34, 22, -53, 43, 1, -38, + 53, -18, -22, 63, -34, -7, 73, -48, 7, 83, -61, 21, + 22, 56, -72, 26, 44, -65, 34, 23, -52, 43, 2, -38, + 54, -17, -22, 63, -33, -7, 73, -48, 7, 83, -61, 21, + 23, 57, -71, 27, 45, -64, 35, 24, -52, 44, 4, -37, + 54, -16, -22, 64, -32, -7, 73, -46, 8, 83, -60, 22, + 24, 57, -69, 28, 46, -63, 35, 26, -51, 44, 5, -36, + 54, -14, -21, 64, -31, -6, 74, -45, 8, 84, -59, 22, + 25, 58, -68, 29, 47, -62, 36, 27, -50, 45, 7, -36, + 54, -13, -21, 64, -29, -6, 74, -44, 8, 84, -57, 22, + 26, 59, -66, 29, 48, -60, 37, 29, -49, 45, 9, -35, + 55, -11, -20, 64, -28, -6, 74, -42, 9, 84, -56, 22, + 27, 59, -64, 30, 49, -59, 37, 31, -48, 46, 11, -34, + 55, -9, -19, 65, -26, -5, 74, -41, 9, 84, -55, 23, + 28, 60, -62, 32, 51, -57, 38, 33, -46, 46, 13, -33, + 56, -6, -19, 65, -24, -4, 75, -39, 9, 84, -53, 23, + 29, 61, -60, 33, 52, -55, 39, 35, -45, 47, 16, -32, + 56, -4, -18, 65, -21, -4, 75, -37, 10, 85, -51, 23, + 31, 62, -58, 34, 54, -53, 40, 37, -43, 48, 18, -31, + 57, -2, -17, 66, -19, -3, 75, -35, 10, 85, -49, 24, + 32, 63, -56, 35, 55, -51, 41, 39, -42, 48, 20, -30, + 57, 1, -16, 66, -17, -3, 76, -33, 11, 85, -47, 24, + 34, 65, -53, 36, 57, -49, 42, 42, -40, 49, 23, -28, + 58, 4, -15, 67, -14, -2, 76, -30, 12, 86, -45, 25, + 35, 66, -51, 37, 58, -47, 43, 44, -38, 50, 26, -27, + 58, 6, -14, 67, -11, -1, 76, -28, 12, 86, -43, 25, + 36, 67, -49, 39, 60, -45, 44, 46, -36, 51, 28, -26, + 59, 9, -13, 68, -9, 0, 77, -25, 13, 86, -40, 26, + 38, 69, -46, 40, 62, -42, 45, 48, -35, 52, 31, -24, + 60, 12, -12, 68, -6, 1, 77, -22, 14, 87, -38, 26, + 39, 70, -43, 42, 64, -40, 46, 51, -33, 53, 34, -22, + 61, 15, -10, 69, -3, 2, 78, -19, 14, 87, -35, 27, + 41, 71, -41, 43, 65, -38, 47, 53, -31, 54, 36, -21, + 61, 18, -9, 70, 0, 3, 78, -17, 15, 87, -33, 28, + 42, 73, -39, 44, 67, -35, 49, 55, -29, 55, 39, -19, + 62, 21, -8, 70, 3, 4, 79, -14, 16, 88, -30, 29, + 44, 74, -36, 46, 69, -33, 50, 57, -27, 56, 42, -18, + 63, 24, -7, 71, 6, 5, 79, -11, 17, 88, -27, 29, + 45, 76, -34, 47, 71, -31, 51, 59, -25, 57, 44, -16, + 64, 27, -5, 72, 9, 6, 80, -8, 18, 89, -24, 30, + 47, 78, -31, 49, 73, -28, 53, 62, -22, 58, 47, -14, + 65, 30, -4, 73, 12, 7, 81, -5, 19, 90, -21, 31, + 48, 79, -28, 50, 74, -26, 54, 64, -20, 59, 50, -12, + 66, 33, -2, 73, 15, 9, 81, -2, 20, 90, -18, 32, + 50, 81, -26, 52, 76, -24, 55, 66, -18, 60, 52, -10, + 67, 35, -1, 74, 18, 10, 82, 1, 21, 91, -15, 33, + 52, 82, -24, 53, 78, -21, 56, 68, -16, 61, 55, -9, + 68, 38, 1, 75, 21, 11, 83, 4, 22, 91, -12, 33, + 53, 84, -21, 55, 80, -19, 58, 71, -14, 63, 58, -7, + 69, 41, 3, 76, 25, 13, 84, 8, 23, 92, -9, 35, + 55, 86, -18, 56, 82, -16, 59, 73, -12, 64, 60, -5, + 70, 44, 4, 77, 28, 14, 84, 11, 24, 93, -6, 35, + 56, 87, -16, 58, 83, -14, 61, 75, -9, 65, 63, -3, + 71, 47, 6, 78, 31, 15, 85, 14, 26, 93, -3, 36, + 21, 57, -80, 25, 44, -72, 34, 22, -58, 43, 1, -43, + 53, -18, -27, 63, -35, -12, 73, -49, 3, 83, -61, 17, + 21, 57, -79, 26, 44, -72, 34, 22, -58, 43, 1, -43, + 53, -18, -27, 63, -34, -12, 73, -48, 3, 83, -61, 17, + 21, 57, -79, 26, 44, -71, 34, 23, -58, 43, 2, -43, + 53, -18, -27, 63, -34, -12, 73, -48, 3, 83, -61, 17, + 22, 57, -78, 26, 44, -71, 34, 23, -58, 43, 2, -43, + 53, -17, -27, 63, -33, -12, 73, -48, 3, 83, -61, 17, + 22, 58, -77, 26, 45, -70, 34, 24, -57, 43, 3, -42, + 54, -16, -27, 63, -33, -12, 73, -47, 3, 83, -60, 17, + 23, 58, -77, 27, 45, -70, 35, 25, -57, 44, 4, -42, + 54, -16, -26, 64, -32, -11, 73, -46, 3, 83, -60, 17, + 23, 58, -76, 27, 46, -69, 35, 26, -56, 44, 5, -42, + 54, -15, -26, 64, -31, -11, 73, -46, 3, 83, -59, 18, + 24, 59, -74, 28, 47, -68, 35, 27, -55, 44, 6, -41, + 54, -13, -26, 64, -30, -11, 74, -44, 4, 84, -58, 18, + 25, 59, -73, 29, 48, -66, 36, 28, -55, 45, 8, -40, + 54, -12, -25, 64, -29, -10, 74, -43, 4, 84, -57, 18, + 26, 60, -71, 29, 49, -65, 36, 30, -54, 45, 10, -40, + 55, -10, -25, 64, -27, -10, 74, -42, 4, 84, -56, 18, + 27, 60, -70, 30, 50, -64, 37, 32, -53, 46, 11, -39, + 55, -8, -24, 65, -25, -10, 74, -41, 4, 84, -54, 18, + 28, 61, -68, 31, 51, -62, 38, 33, -51, 46, 13, -38, + 55, -6, -23, 65, -24, -9, 74, -39, 5, 84, -53, 19, + 29, 62, -66, 32, 53, -60, 39, 35, -50, 47, 16, -37, + 56, -4, -23, 65, -21, -9, 75, -37, 5, 85, -51, 19, + 30, 63, -64, 33, 54, -59, 39, 37, -49, 47, 18, -36, + 56, -2, -22, 66, -19, -8, 75, -35, 6, 85, -50, 20, + 31, 64, -62, 34, 55, -57, 40, 39, -47, 48, 20, -35, + 57, 0, -21, 66, -17, -7, 75, -33, 6, 85, -48, 20, + 33, 65, -59, 35, 57, -55, 41, 41, -46, 49, 22, -34, + 57, 3, -20, 67, -15, -7, 76, -31, 7, 85, -46, 20, + 34, 66, -57, 37, 58, -53, 42, 43, -44, 50, 25, -32, + 58, 6, -19, 67, -12, -6, 76, -28, 8, 86, -44, 21, + 36, 67, -55, 38, 60, -51, 43, 45, -42, 50, 28, -31, + 59, 8, -18, 68, -10, -5, 77, -26, 8, 86, -41, 21, + 37, 69, -52, 39, 62, -49, 44, 48, -40, 51, 30, -30, + 59, 11, -17, 68, -7, -4, 77, -24, 9, 86, -39, 22, + 38, 70, -50, 41, 63, -46, 45, 50, -39, 52, 33, -28, + 60, 14, -16, 69, -4, -3, 77, -21, 10, 87, -37, 23, + 40, 71, -47, 42, 65, -44, 47, 52, -37, 53, 35, -27, + 61, 17, -15, 69, -1, -2, 78, -18, 10, 87, -34, 23, + 41, 73, -45, 43, 67, -42, 48, 54, -35, 54, 38, -25, + 62, 19, -13, 70, 2, -1, 79, -15, 11, 88, -31, 24, + 43, 74, -43, 45, 68, -40, 49, 56, -33, 55, 40, -23, + 63, 22, -12, 71, 4, 0, 79, -12, 12, 88, -29, 25, + 44, 75, -40, 46, 70, -37, 50, 58, -31, 56, 43, -22, + 63, 25, -11, 71, 7, 1, 80, -10, 13, 89, -26, 25, + 46, 77, -38, 48, 72, -35, 51, 61, -29, 57, 46, -20, + 64, 28, -9, 72, 10, 2, 80, -7, 14, 89, -23, 26, + 47, 79, -35, 49, 74, -32, 53, 63, -27, 58, 48, -18, + 65, 31, -8, 73, 14, 3, 81, -3, 15, 90, -20, 27, + 49, 80, -33, 50, 75, -30, 54, 65, -24, 59, 51, -16, + 66, 34, -6, 74, 17, 5, 82, -1, 16, 90, -17, 28, + 50, 82, -30, 52, 77, -28, 55, 67, -22, 60, 53, -15, + 67, 37, -5, 74, 19, 6, 82, 2, 17, 91, -14, 29, + 52, 83, -28, 53, 79, -25, 57, 69, -20, 62, 56, -13, + 68, 39, -3, 75, 22, 7, 83, 5, 18, 91, -11, 30, + 54, 85, -25, 55, 81, -23, 58, 72, -18, 63, 59, -11, + 69, 43, -2, 76, 26, 9, 84, 9, 19, 92, -8, 31, + 55, 86, -23, 56, 82, -20, 59, 74, -16, 64, 61, -9, + 70, 45, 0, 77, 29, 10, 85, 12, 20, 93, -5, 32, + 57, 88, -20, 58, 84, -18, 61, 76, -14, 65, 63, -7, + 71, 48, 2, 78, 32, 11, 85, 15, 22, 93, -2, 33, + 22, 59, -82, 26, 46, -75, 34, 25, -62, 43, 4, -47, + 54, -16, -31, 63, -32, -16, 73, -46, -1, 83, -60, 13, + 22, 59, -82, 26, 47, -75, 34, 26, -62, 43, 4, -47, + 54, -15, -31, 63, -32, -16, 73, -46, -1, 83, -59, 13, + 22, 59, -82, 27, 47, -75, 34, 26, -62, 44, 5, -47, + 54, -15, -31, 64, -31, -16, 73, -46, -1, 83, -59, 13, + 23, 60, -81, 27, 47, -74, 35, 26, -61, 44, 5, -47, + 54, -14, -31, 64, -31, -16, 73, -45, -1, 83, -59, 13, + 23, 60, -80, 27, 48, -74, 35, 27, -61, 44, 6, -46, + 54, -14, -31, 64, -30, -16, 73, -45, -1, 83, -58, 13, + 24, 60, -80, 28, 48, -73, 35, 28, -61, 44, 7, -46, + 54, -13, -30, 64, -30, -15, 74, -44, -1, 84, -58, 13, + 24, 60, -79, 28, 49, -72, 36, 29, -60, 44, 8, -46, + 54, -12, -30, 64, -29, -15, 74, -43, -1, 84, -57, 14, + 25, 61, -77, 29, 49, -71, 36, 30, -59, 45, 9, -45, + 54, -10, -30, 64, -27, -15, 74, -42, 0, 84, -56, 14, + 26, 61, -76, 29, 50, -70, 36, 31, -58, 45, 11, -44, + 55, -9, -29, 64, -26, -15, 74, -41, 0, 84, -55, 14, + 27, 62, -74, 30, 51, -69, 37, 33, -57, 45, 12, -44, + 55, -8, -29, 65, -25, -14, 74, -40, 0, 84, -54, 14, + 28, 62, -73, 31, 52, -67, 38, 34, -56, 46, 14, -43, + 55, -6, -28, 65, -23, -14, 74, -39, 0, 84, -53, 15, + 29, 63, -71, 32, 53, -66, 38, 36, -55, 46, 16, -42, + 56, -4, -28, 65, -21, -13, 75, -37, 1, 84, -51, 15, + 30, 64, -69, 33, 55, -64, 39, 38, -54, 47, 18, -41, + 56, -2, -27, 66, -19, -13, 75, -35, 1, 85, -50, 15, + 31, 65, -67, 34, 56, -62, 40, 39, -52, 48, 20, -40, + 57, 0, -26, 66, -17, -12, 75, -33, 2, 85, -48, 16, + 32, 66, -65, 35, 57, -60, 41, 41, -51, 48, 22, -39, + 57, 3, -25, 66, -15, -11, 76, -31, 2, 85, -46, 16, + 33, 67, -63, 36, 59, -59, 42, 43, -50, 49, 24, -38, + 58, 5, -24, 67, -13, -11, 76, -29, 3, 85, -44, 16, + 35, 68, -61, 37, 60, -56, 43, 45, -48, 50, 27, -36, + 58, 8, -23, 67, -10, -10, 76, -27, 4, 86, -42, 17, + 36, 69, -58, 39, 62, -54, 44, 47, -46, 51, 29, -35, + 59, 10, -22, 68, -8, -9, 77, -24, 4, 86, -40, 18, + 37, 70, -56, 40, 63, -52, 45, 49, -44, 52, 32, -34, + 60, 13, -21, 68, -5, -8, 77, -22, 5, 87, -38, 18, + 39, 71, -54, 41, 65, -50, 46, 51, -43, 52, 34, -32, + 60, 15, -20, 69, -3, -7, 78, -19, 6, 87, -35, 19, + 40, 73, -51, 43, 66, -48, 47, 54, -41, 53, 37, -31, + 61, 18, -19, 70, 0, -6, 78, -16, 6, 87, -33, 19, + 42, 74, -49, 44, 68, -46, 48, 56, -39, 54, 39, -29, + 62, 21, -17, 70, 3, -5, 79, -14, 7, 88, -30, 20, + 43, 75, -47, 45, 70, -44, 49, 58, -37, 55, 42, -28, + 63, 24, -16, 71, 6, -4, 79, -11, 8, 88, -27, 21, + 45, 77, -44, 47, 71, -41, 51, 60, -35, 56, 44, -26, + 64, 27, -15, 71, 9, -3, 80, -8, 9, 89, -25, 21, + 46, 78, -42, 48, 73, -39, 52, 62, -33, 57, 47, -24, + 64, 29, -14, 72, 12, -2, 80, -5, 10, 89, -22, 22, + 48, 80, -39, 49, 75, -37, 53, 64, -31, 59, 50, -22, + 65, 32, -12, 73, 15, -1, 81, -2, 11, 90, -19, 23, + 49, 81, -37, 51, 76, -34, 54, 66, -29, 60, 52, -21, + 66, 35, -10, 74, 18, 1, 82, 1, 12, 90, -16, 24, + 51, 82, -34, 52, 78, -32, 56, 68, -27, 61, 55, -19, + 67, 38, -9, 75, 21, 2, 82, 4, 13, 91, -13, 25, + 52, 84, -32, 54, 80, -30, 57, 70, -24, 62, 57, -17, + 68, 41, -7, 75, 24, 3, 83, 7, 14, 91, -10, 26, + 54, 86, -29, 55, 82, -27, 58, 73, -22, 63, 60, -15, + 69, 44, -6, 76, 27, 5, 84, 10, 15, 92, -7, 27, + 55, 87, -27, 57, 83, -25, 60, 75, -20, 64, 62, -13, + 70, 46, -4, 77, 30, 6, 85, 13, 16, 93, -4, 28, + 57, 89, -24, 58, 85, -22, 61, 77, -18, 66, 64, -11, + 71, 49, -2, 78, 33, 7, 85, 16, 18, 93, -1, 29, + 23, 61, -85, 27, 49, -78, 35, 28, -66, 44, 7, -51, + 54, -13, -35, 64, -29, -20, 73, -44, -5, 83, -58, 9, + 23, 61, -85, 27, 49, -78, 35, 29, -66, 44, 8, -51, + 54, -12, -35, 64, -29, -20, 74, -44, -5, 84, -57, 9, + 24, 62, -84, 28, 49, -78, 35, 29, -65, 44, 8, -51, + 54, -12, -35, 64, -29, -20, 74, -44, -5, 84, -57, 9, + 24, 62, -84, 28, 50, -77, 35, 30, -65, 44, 8, -51, + 54, -11, -35, 64, -28, -20, 74, -43, -5, 84, -57, 9, + 24, 62, -83, 28, 50, -77, 36, 30, -65, 44, 9, -50, + 54, -11, -35, 64, -28, -20, 74, -43, -5, 84, -56, 9, + 25, 62, -83, 29, 51, -76, 36, 31, -64, 45, 10, -50, + 54, -10, -34, 64, -27, -19, 74, -42, -5, 84, -56, 10, + 25, 62, -82, 29, 51, -75, 36, 32, -64, 45, 11, -50, + 55, -9, -34, 64, -26, -19, 74, -41, -5, 84, -55, 10, + 26, 63, -80, 30, 52, -74, 37, 33, -63, 45, 12, -49, + 55, -8, -34, 64, -25, -19, 74, -40, -4, 84, -54, 10, + 27, 63, -79, 30, 53, -73, 37, 34, -62, 46, 14, -48, + 55, -6, -33, 65, -24, -19, 74, -39, -4, 84, -53, 10, + 28, 64, -78, 31, 54, -72, 38, 35, -61, 46, 15, -48, + 55, -5, -33, 65, -22, -18, 74, -38, -4, 84, -52, 10, + 28, 64, -76, 32, 54, -71, 38, 37, -60, 46, 17, -47, + 56, -3, -32, 65, -21, -18, 75, -37, -4, 84, -51, 11, + 29, 65, -74, 33, 55, -69, 39, 38, -59, 47, 18, -46, + 56, -2, -32, 65, -19, -17, 75, -35, -3, 85, -50, 11, + 31, 66, -72, 34, 57, -68, 40, 40, -58, 48, 20, -45, + 57, 1, -31, 66, -17, -17, 75, -33, -3, 85, -48, 11, + 32, 66, -71, 35, 58, -66, 41, 42, -56, 48, 22, -44, + 57, 3, -30, 66, -15, -16, 75, -31, -2, 85, -46, 12, + 33, 67, -69, 36, 59, -64, 41, 43, -55, 49, 24, -43, + 58, 5, -29, 67, -13, -15, 76, -29, -2, 85, -44, 12, + 34, 68, -67, 37, 60, -62, 42, 45, -53, 49, 27, -42, + 58, 7, -28, 67, -11, -15, 76, -27, -1, 86, -43, 13, + 36, 69, -64, 38, 62, -60, 43, 47, -52, 50, 29, -40, + 59, 10, -27, 68, -8, -14, 77, -25, 0, 86, -40, 13, + 37, 70, -62, 39, 63, -58, 44, 49, -50, 51, 31, -39, + 59, 12, -26, 68, -6, -13, 77, -23, 0, 86, -38, 14, + 38, 71, -60, 40, 65, -56, 45, 51, -48, 52, 34, -38, + 60, 15, -25, 69, -3, -12, 77, -20, 1, 87, -36, 14, + 39, 73, -58, 42, 66, -54, 46, 53, -47, 53, 36, -36, + 61, 17, -24, 69, -1, -11, 78, -18, 2, 87, -34, 15, + 41, 74, -55, 43, 68, -52, 48, 55, -45, 54, 39, -35, + 62, 20, -23, 70, 2, -10, 78, -15, 2, 88, -31, 15, + 42, 75, -53, 44, 69, -50, 49, 57, -43, 55, 41, -33, + 62, 23, -22, 70, 5, -9, 79, -12, 3, 88, -29, 16, + 44, 76, -51, 46, 71, -47, 50, 59, -41, 56, 43, -32, + 63, 25, -20, 71, 8, -8, 79, -10, 4, 88, -26, 17, + 45, 78, -48, 47, 72, -45, 51, 61, -39, 57, 46, -30, + 64, 28, -19, 72, 10, -7, 80, -7, 5, 89, -23, 18, + 47, 79, -46, 48, 74, -43, 52, 63, -37, 58, 48, -28, + 65, 31, -18, 72, 13, -6, 81, -4, 6, 89, -21, 18, + 48, 81, -43, 50, 76, -41, 54, 65, -35, 59, 51, -26, + 66, 34, -16, 73, 16, -5, 81, -1, 7, 90, -18, 19, + 50, 82, -41, 51, 77, -38, 55, 67, -33, 60, 53, -25, + 67, 36, -15, 74, 19, -4, 82, 2, 8, 90, -15, 20, + 51, 83, -38, 53, 79, -36, 56, 69, -31, 61, 56, -23, + 68, 39, -13, 75, 22, -2, 83, 5, 9, 91, -12, 21, + 53, 85, -36, 54, 81, -34, 57, 71, -29, 62, 58, -21, + 69, 42, -12, 76, 25, -1, 83, 8, 10, 92, -9, 22, + 54, 87, -33, 56, 83, -31, 59, 74, -26, 63, 61, -19, + 70, 45, -10, 77, 28, 0, 84, 11, 11, 92, -6, 23, + 56, 88, -31, 57, 84, -29, 60, 75, -24, 65, 63, -17, + 71, 47, -8, 77, 31, 2, 85, 14, 12, 93, -3, 24, + 57, 90, -28, 58, 86, -26, 61, 77, -22, 66, 65, -15, + 72, 50, -7, 78, 34, 3, 86, 17, 14, 94, 0, 25, + 24, 63, -88, 28, 52, -81, 36, 32, -69, 44, 11, -55, + 54, -10, -39, 64, -27, -24, 74, -42, -9, 84, -56, 5, + 25, 64, -88, 28, 52, -81, 36, 32, -69, 44, 11, -55, + 54, -9, -39, 64, -26, -24, 74, -42, -9, 84, -55, 5, + 25, 64, -87, 29, 52, -81, 36, 32, -69, 45, 11, -55, + 54, -9, -39, 64, -26, -24, 74, -41, -9, 84, -55, 5, + 25, 64, -87, 29, 52, -80, 36, 33, -69, 45, 12, -54, + 54, -8, -39, 64, -26, -24, 74, -41, -9, 84, -55, 5, + 25, 64, -86, 29, 53, -80, 36, 33, -68, 45, 12, -54, + 55, -8, -39, 64, -25, -24, 74, -40, -9, 84, -54, 5, + 26, 64, -85, 29, 53, -79, 36, 34, -68, 45, 13, -54, + 55, -7, -38, 64, -24, -23, 74, -40, -9, 84, -54, 6, + 26, 64, -85, 30, 54, -79, 37, 35, -67, 45, 14, -53, + 55, -6, -38, 65, -24, -23, 74, -39, -9, 84, -53, 6, + 27, 65, -83, 31, 54, -78, 37, 36, -66, 46, 15, -53, + 55, -5, -38, 65, -22, -23, 74, -38, -8, 84, -52, 6, + 28, 65, -82, 31, 55, -76, 38, 37, -66, 46, 16, -52, + 55, -4, -37, 65, -21, -23, 74, -37, -8, 84, -51, 6, + 29, 66, -81, 32, 56, -75, 38, 38, -65, 46, 18, -52, + 56, -2, -37, 65, -20, -22, 75, -36, -8, 84, -50, 6, + 29, 66, -79, 33, 57, -74, 39, 39, -64, 47, 19, -51, + 56, -1, -36, 65, -19, -22, 75, -34, -8, 85, -49, 7, + 30, 67, -78, 33, 58, -73, 40, 41, -63, 47, 21, -50, + 56, 1, -36, 66, -17, -21, 75, -33, -7, 85, -48, 7, + 31, 67, -76, 34, 59, -71, 40, 42, -61, 48, 23, -49, + 57, 3, -35, 66, -15, -21, 75, -31, -7, 85, -46, 7, + 33, 68, -74, 35, 60, -69, 41, 44, -60, 49, 25, -48, + 57, 5, -34, 66, -13, -20, 76, -29, -6, 85, -44, 8, + 34, 69, -72, 36, 61, -68, 42, 45, -59, 49, 27, -47, + 58, 7, -33, 67, -11, -19, 76, -27, -6, 86, -43, 8, + 35, 70, -70, 37, 62, -66, 43, 47, -57, 50, 29, -46, + 58, 9, -32, 67, -9, -19, 76, -25, -5, 86, -41, 9, + 36, 71, -68, 39, 64, -64, 44, 49, -56, 51, 31, -44, + 59, 12, -31, 68, -6, -18, 77, -23, -4, 86, -39, 9, + 37, 72, -66, 40, 65, -62, 45, 51, -54, 52, 33, -43, + 60, 14, -30, 68, -4, -17, 77, -21, -4, 87, -37, 10, + 39, 73, -64, 41, 66, -60, 46, 53, -52, 52, 36, -42, + 60, 17, -29, 69, -2, -16, 78, -18, -3, 87, -34, 10, + 40, 74, -61, 42, 68, -58, 47, 55, -51, 53, 38, -40, + 61, 19, -28, 69, 1, -15, 78, -16, -2, 87, -32, 11, + 42, 75, -59, 44, 69, -56, 48, 57, -49, 54, 40, -39, + 62, 22, -27, 70, 4, -14, 79, -13, -2, 88, -30, 12, + 43, 76, -57, 45, 71, -54, 49, 59, -47, 55, 43, -37, + 63, 24, -26, 71, 6, -13, 79, -11, -1, 88, -27, 12, + 44, 78, -54, 46, 72, -51, 50, 61, -45, 56, 45, -36, + 63, 27, -24, 71, 9, -12, 80, -8, 0, 89, -25, 13, + 46, 79, -52, 47, 74, -49, 51, 62, -43, 57, 47, -34, + 64, 30, -23, 72, 12, -11, 80, -5, 1, 89, -22, 14, + 47, 80, -50, 49, 75, -47, 53, 64, -41, 58, 50, -32, + 65, 32, -22, 73, 15, -10, 81, -3, 2, 90, -19, 14, + 49, 82, -47, 50, 77, -45, 54, 67, -39, 59, 52, -31, + 66, 35, -20, 73, 18, -9, 82, 0, 3, 90, -16, 15, + 50, 83, -45, 52, 79, -42, 55, 69, -37, 60, 55, -29, + 67, 38, -19, 74, 20, -8, 82, 3, 4, 91, -14, 16, + 52, 84, -42, 53, 80, -40, 56, 70, -35, 61, 57, -27, + 68, 40, -17, 75, 23, -6, 83, 6, 5, 91, -11, 17, + 53, 86, -40, 54, 82, -38, 58, 72, -33, 62, 59, -25, + 69, 43, -16, 76, 26, -5, 83, 9, 6, 92, -8, 18, + 55, 88, -37, 56, 84, -35, 59, 75, -30, 64, 62, -23, + 70, 46, -14, 77, 29, -4, 84, 12, 7, 92, -5, 19, + 56, 89, -35, 57, 85, -33, 60, 77, -28, 65, 64, -21, + 71, 49, -12, 78, 32, -2, 85, 15, 8, 93, -2, 20, + 58, 90, -33, 59, 87, -31, 62, 78, -26, 66, 66, -19, + 72, 51, -11, 78, 35, -1, 86, 18, 10, 94, 1, 21, + 26, 66, -91, 29, 55, -85, 36, 35, -73, 45, 14, -59, + 55, -6, -44, 64, -24, -29, 74, -39, -14, 84, -53, 1, + 26, 66, -91, 29, 55, -85, 37, 35, -73, 45, 14, -59, + 55, -6, -44, 64, -23, -28, 74, -39, -14, 84, -53, 1, + 26, 66, -90, 30, 55, -84, 37, 36, -73, 45, 15, -59, + 55, -6, -43, 64, -23, -28, 74, -39, -14, 84, -53, 1, + 26, 66, -90, 30, 55, -84, 37, 36, -72, 45, 15, -59, + 55, -5, -43, 64, -23, -28, 74, -38, -14, 84, -53, 1, + 27, 66, -89, 30, 56, -83, 37, 36, -72, 45, 16, -58, + 55, -5, -43, 65, -22, -28, 74, -38, -14, 84, -52, 1, + 27, 66, -89, 31, 56, -83, 37, 37, -72, 46, 16, -58, + 55, -4, -43, 65, -22, -28, 74, -37, -13, 84, -52, 1, + 28, 67, -88, 31, 56, -82, 38, 38, -71, 46, 17, -58, + 55, -3, -43, 65, -21, -28, 74, -36, -13, 84, -51, 1, + 28, 67, -87, 32, 57, -81, 38, 39, -70, 46, 18, -57, + 56, -2, -42, 65, -20, -27, 75, -35, -13, 84, -50, 2, + 29, 67, -86, 32, 58, -80, 39, 40, -70, 47, 20, -56, + 56, -1, -42, 65, -18, -27, 75, -34, -13, 84, -49, 2, + 30, 68, -84, 33, 58, -79, 39, 41, -69, 47, 21, -56, + 56, 1, -41, 65, -17, -27, 75, -33, -12, 85, -48, 2, + 30, 68, -83, 33, 59, -78, 40, 42, -68, 47, 22, -55, + 57, 2, -41, 66, -16, -26, 75, -32, -12, 85, -47, 2, + 31, 69, -81, 34, 60, -76, 40, 43, -67, 48, 24, -54, + 57, 4, -40, 66, -14, -26, 75, -30, -12, 85, -46, 3, + 32, 69, -79, 35, 61, -75, 41, 45, -65, 49, 26, -53, + 57, 6, -39, 66, -12, -25, 76, -29, -11, 85, -44, 3, + 33, 70, -78, 36, 62, -73, 42, 46, -64, 49, 28, -52, + 58, 8, -38, 67, -10, -25, 76, -27, -11, 86, -42, 3, + 35, 71, -76, 37, 63, -72, 43, 48, -63, 50, 29, -51, + 58, 10, -38, 67, -9, -24, 76, -25, -10, 86, -41, 4, + 36, 72, -74, 38, 64, -70, 43, 49, -61, 50, 31, -50, + 59, 12, -37, 68, -6, -23, 77, -23, -10, 86, -39, 4, + 37, 73, -72, 39, 66, -68, 44, 51, -60, 51, 34, -49, + 59, 14, -36, 68, -4, -22, 77, -21, -9, 86, -37, 5, + 38, 74, -70, 40, 67, -66, 45, 53, -58, 52, 36, -48, + 60, 16, -35, 69, -2, -22, 77, -19, -8, 87, -35, 5, + 39, 75, -68, 42, 68, -64, 46, 55, -57, 53, 38, -46, + 61, 19, -34, 69, 1, -21, 78, -16, -8, 87, -33, 6, + 41, 76, -66, 43, 69, -62, 47, 57, -55, 54, 40, -45, + 61, 21, -33, 70, 3, -20, 78, -14, -7, 87, -30, 6, + 42, 77, -63, 44, 71, -60, 49, 59, -53, 55, 42, -43, + 62, 24, -31, 70, 6, -19, 79, -11, -6, 88, -28, 7, + 44, 78, -61, 45, 72, -58, 50, 60, -51, 56, 45, -42, + 63, 26, -30, 71, 8, -18, 79, -9, -5, 88, -25, 8, + 45, 79, -59, 47, 74, -56, 51, 62, -49, 56, 47, -40, + 64, 29, -29, 72, 11, -17, 80, -6, -4, 89, -23, 8, + 46, 80, -56, 48, 75, -54, 52, 64, -47, 57, 49, -39, + 65, 31, -28, 72, 14, -16, 80, -4, -4, 89, -20, 9, + 48, 82, -54, 49, 77, -51, 53, 66, -45, 58, 51, -37, + 65, 34, -26, 73, 16, -15, 81, -1, -3, 90, -18, 10, + 49, 83, -51, 51, 78, -49, 54, 68, -43, 60, 54, -35, + 66, 37, -25, 74, 19, -13, 82, 2, -2, 90, -15, 11, + 51, 84, -49, 52, 80, -47, 56, 70, -41, 61, 56, -33, + 67, 39, -23, 75, 22, -12, 82, 5, -1, 91, -12, 12, + 52, 86, -47, 53, 81, -44, 57, 72, -39, 62, 58, -32, + 68, 42, -22, 75, 25, -11, 83, 8, 1, 91, -9, 13, + 53, 87, -44, 55, 83, -42, 58, 74, -37, 63, 61, -30, + 69, 44, -20, 76, 28, -10, 84, 10, 2, 92, -7, 14, + 55, 89, -42, 56, 85, -40, 60, 76, -35, 64, 63, -28, + 70, 47, -18, 77, 31, -8, 85, 14, 3, 93, -3, 15, + 56, 90, -39, 58, 86, -37, 61, 78, -33, 65, 65, -26, + 71, 50, -17, 78, 33, -7, 85, 16, 4, 93, -1, 16, + 58, 91, -37, 59, 88, -35, 62, 80, -31, 66, 68, -24, + 72, 52, -15, 79, 36, -5, 86, 19, 5, 94, 2, 17, + 27, 68, -94, 30, 57, -88, 37, 38, -77, 46, 17, -63, + 55, -3, -47, 65, -21, -32, 74, -37, -18, 84, -51, -3, + 27, 68, -93, 30, 57, -88, 37, 38, -76, 46, 18, -63, + 55, -3, -47, 65, -21, -32, 74, -36, -18, 84, -51, -3, + 27, 68, -93, 31, 57, -87, 37, 39, -76, 46, 18, -62, + 55, -3, -47, 65, -20, -32, 74, -36, -18, 84, -51, -3, + 27, 68, -93, 31, 58, -87, 38, 39, -76, 46, 18, -62, + 55, -2, -47, 65, -20, -32, 74, -36, -18, 84, -50, -3, + 28, 68, -92, 31, 58, -86, 38, 39, -76, 46, 19, -62, + 55, -2, -47, 65, -19, -32, 74, -35, -17, 84, -50, -3, + 28, 68, -91, 31, 58, -86, 38, 40, -75, 46, 20, -62, + 56, -1, -47, 65, -19, -32, 75, -35, -17, 84, -49, -3, + 29, 69, -91, 32, 59, -85, 38, 41, -75, 46, 20, -61, + 56, 0, -46, 65, -18, -32, 75, -34, -17, 84, -49, -3, + 29, 69, -90, 32, 59, -84, 39, 42, -74, 47, 21, -61, + 56, 1, -46, 65, -17, -31, 75, -33, -17, 85, -48, -2, + 30, 69, -88, 33, 60, -83, 39, 42, -73, 47, 22, -60, + 56, 2, -46, 66, -16, -31, 75, -32, -17, 85, -47, -2, + 31, 70, -87, 34, 61, -82, 40, 43, -72, 48, 24, -60, + 57, 3, -45, 66, -15, -31, 75, -31, -16, 85, -46, -2, + 31, 70, -86, 34, 61, -81, 40, 45, -71, 48, 25, -59, + 57, 5, -45, 66, -13, -30, 75, -30, -16, 85, -45, -2, + 32, 71, -84, 35, 62, -80, 41, 46, -70, 48, 27, -58, + 57, 6, -44, 66, -12, -30, 76, -28, -16, 85, -44, -1, + 33, 71, -83, 36, 63, -78, 42, 47, -69, 49, 28, -57, + 58, 8, -43, 67, -10, -29, 76, -27, -15, 85, -42, -1, + 34, 72, -81, 37, 64, -77, 42, 49, -68, 50, 30, -56, + 58, 10, -42, 67, -8, -29, 76, -25, -15, 86, -40, -1, + 35, 73, -79, 38, 65, -75, 43, 50, -66, 50, 32, -55, + 59, 12, -42, 67, -6, -28, 77, -23, -14, 86, -39, 0, + 36, 73, -77, 39, 66, -73, 44, 52, -65, 51, 34, -54, + 59, 14, -41, 68, -4, -27, 77, -21, -14, 86, -37, 0, + 38, 74, -75, 40, 67, -71, 45, 53, -63, 52, 36, -53, + 60, 16, -40, 68, -2, -26, 77, -19, -13, 87, -35, 1, + 39, 75, -73, 41, 68, -70, 46, 55, -62, 52, 38, -51, + 60, 19, -39, 69, 0, -26, 78, -17, -12, 87, -33, 1, + 40, 76, -71, 42, 70, -68, 47, 57, -60, 53, 40, -50, + 61, 21, -38, 69, 3, -25, 78, -15, -12, 87, -31, 2, + 41, 77, -69, 43, 71, -66, 48, 58, -59, 54, 42, -49, + 62, 23, -37, 70, 5, -24, 79, -12, -11, 88, -29, 3, + 43, 78, -67, 45, 72, -64, 49, 60, -57, 55, 44, -47, + 63, 26, -35, 71, 8, -23, 79, -10, -10, 88, -26, 3, + 44, 79, -65, 46, 74, -62, 50, 62, -55, 56, 46, -46, + 63, 28, -34, 71, 10, -22, 80, -7, -9, 89, -24, 4, + 45, 80, -62, 47, 75, -59, 51, 64, -53, 57, 49, -44, + 64, 31, -33, 72, 13, -21, 80, -5, -8, 89, -21, 5, + 47, 82, -60, 49, 77, -57, 52, 66, -51, 58, 51, -42, + 65, 33, -32, 73, 15, -20, 81, -2, -7, 89, -19, 5, + 48, 83, -58, 50, 78, -55, 53, 67, -49, 59, 53, -41, + 66, 35, -30, 73, 18, -19, 81, 1, -7, 90, -16, 6, + 50, 84, -55, 51, 80, -53, 55, 69, -47, 60, 55, -39, + 67, 38, -29, 74, 21, -17, 82, 4, -5, 91, -13, 7, + 51, 85, -53, 53, 81, -51, 56, 71, -45, 61, 58, -37, + 68, 41, -27, 75, 24, -16, 83, 6, -4, 91, -11, 8, + 52, 87, -51, 54, 83, -48, 57, 73, -43, 62, 60, -36, + 68, 43, -26, 76, 26, -15, 83, 9, -3, 92, -8, 9, + 54, 88, -48, 55, 84, -46, 58, 75, -41, 63, 62, -34, + 69, 46, -24, 76, 29, -14, 84, 12, -2, 92, -5, 10, + 55, 90, -46, 57, 86, -44, 60, 77, -39, 64, 64, -32, + 70, 49, -22, 77, 32, -12, 85, 15, -1, 93, -2, 11, + 57, 91, -43, 58, 87, -41, 61, 79, -37, 66, 67, -30, + 71, 51, -21, 78, 35, -11, 85, 18, 0, 93, 1, 12, + 58, 92, -41, 60, 89, -39, 62, 81, -35, 67, 69, -28, + 72, 54, -19, 79, 37, -9, 86, 21, 1, 94, 3, 13, + 28, 70, -96, 31, 60, -91, 38, 41, -80, 46, 21, -66, + 56, 0, -51, 65, -18, -36, 75, -34, -22, 84, -49, -7, + 28, 70, -96, 31, 60, -91, 38, 41, -80, 46, 21, -66, + 56, 0, -51, 65, -18, -36, 75, -34, -22, 84, -49, -7, + 28, 70, -96, 32, 60, -90, 38, 42, -80, 46, 21, -66, + 56, 0, -51, 65, -18, -36, 75, -34, -22, 84, -49, -7, + 29, 70, -95, 32, 60, -90, 38, 42, -79, 46, 21, -66, + 56, 1, -51, 65, -17, -36, 75, -33, -21, 84, -48, -7, + 29, 70, -95, 32, 60, -90, 38, 42, -79, 47, 22, -66, + 56, 1, -51, 65, -17, -36, 75, -33, -21, 84, -48, -7, + 29, 70, -94, 32, 61, -89, 39, 43, -78, 47, 23, -65, + 56, 2, -50, 65, -16, -36, 75, -32, -21, 85, -47, -7, + 30, 71, -93, 33, 61, -88, 39, 43, -78, 47, 23, -65, + 56, 3, -50, 65, -15, -36, 75, -32, -21, 85, -47, -6, + 30, 71, -92, 33, 62, -87, 39, 44, -77, 47, 24, -64, + 56, 4, -50, 66, -14, -35, 75, -31, -21, 85, -46, -6, + 31, 71, -91, 34, 62, -86, 40, 45, -76, 48, 25, -64, + 57, 5, -49, 66, -13, -35, 75, -30, -21, 85, -45, -6, + 32, 72, -90, 34, 63, -85, 40, 46, -76, 48, 26, -63, + 57, 6, -49, 66, -12, -35, 75, -29, -20, 85, -44, -6, + 32, 72, -89, 35, 63, -84, 41, 47, -75, 48, 28, -62, + 57, 8, -48, 66, -11, -34, 76, -27, -20, 85, -43, -6, + 33, 72, -88, 36, 64, -83, 42, 48, -74, 49, 29, -62, + 58, 9, -48, 67, -9, -34, 76, -26, -20, 85, -42, -5, + 34, 73, -86, 37, 65, -81, 42, 50, -72, 50, 31, -61, + 58, 11, -47, 67, -8, -33, 76, -24, -19, 86, -40, -5, + 35, 74, -84, 38, 66, -80, 43, 51, -71, 50, 32, -60, + 59, 13, -46, 67, -6, -32, 76, -23, -19, 86, -38, -4, + 36, 74, -83, 39, 67, -78, 44, 52, -70, 51, 34, -59, + 59, 14, -45, 68, -4, -32, 77, -21, -18, 86, -37, -4, + 37, 75, -81, 40, 68, -77, 45, 54, -69, 51, 36, -58, + 60, 16, -45, 68, -2, -31, 77, -19, -18, 86, -35, -4, + 38, 76, -79, 41, 69, -75, 46, 55, -67, 52, 38, -56, + 60, 19, -44, 69, 0, -30, 78, -17, -17, 87, -33, -3, + 40, 77, -77, 42, 70, -73, 46, 57, -66, 53, 40, -55, + 61, 21, -43, 69, 2, -30, 78, -15, -16, 87, -31, -3, + 41, 78, -75, 43, 71, -71, 47, 58, -64, 54, 42, -54, + 61, 23, -42, 70, 5, -29, 78, -13, -16, 87, -29, -2, + 42, 79, -73, 44, 73, -69, 48, 60, -62, 54, 44, -53, + 62, 25, -40, 70, 7, -28, 79, -10, -15, 88, -27, -1, + 43, 80, -70, 45, 74, -67, 50, 62, -60, 55, 46, -51, + 63, 28, -39, 71, 10, -27, 79, -8, -14, 88, -24, -1, + 45, 81, -68, 47, 75, -65, 51, 64, -59, 56, 48, -49, + 64, 30, -38, 71, 12, -26, 80, -5, -13, 89, -22, 0, + 46, 82, -66, 48, 77, -63, 52, 65, -57, 57, 50, -48, + 64, 32, -37, 72, 14, -25, 80, -3, -12, 89, -20, 1, + 47, 83, -64, 49, 78, -61, 53, 67, -55, 58, 52, -46, + 65, 35, -35, 73, 17, -24, 81, 0, -11, 90, -17, 1, + 49, 84, -62, 50, 79, -59, 54, 69, -53, 59, 54, -45, + 66, 37, -34, 73, 20, -23, 82, 2, -10, 90, -15, 2, + 50, 85, -59, 52, 81, -57, 55, 71, -51, 60, 57, -43, + 67, 40, -33, 74, 22, -21, 82, 5, -9, 91, -12, 3, + 52, 87, -57, 53, 82, -54, 56, 73, -49, 61, 59, -41, + 68, 42, -31, 75, 25, -20, 83, 8, -8, 91, -9, 4, + 53, 88, -54, 54, 84, -52, 58, 74, -47, 62, 61, -39, + 69, 45, -30, 76, 28, -19, 83, 10, -7, 92, -7, 5, + 54, 89, -52, 56, 85, -50, 59, 76, -45, 64, 63, -38, + 70, 47, -28, 77, 30, -18, 84, 13, -6, 92, -4, 6, + 56, 91, -50, 57, 87, -47, 60, 78, -43, 65, 66, -36, + 71, 50, -26, 78, 33, -16, 85, 16, -5, 93, -1, 7, + 57, 92, -47, 59, 88, -45, 61, 80, -41, 66, 68, -34, + 72, 52, -25, 78, 36, -15, 86, 19, -4, 94, 2, 8, + 59, 93, -45, 60, 90, -43, 63, 82, -39, 67, 70, -32, + 73, 55, -23, 79, 39, -13, 86, 22, -3, 94, 5, 9, + 29, 72, -99, 32, 62, -94, 39, 44, -83, 47, 24, -70, + 56, 3, -55, 65, -15, -40, 75, -32, -26, 85, -47, -11, + 29, 72, -99, 32, 62, -93, 39, 44, -83, 47, 24, -70, + 56, 3, -55, 65, -15, -40, 75, -31, -26, 85, -46, -11, + 29, 72, -99, 33, 62, -93, 39, 44, -83, 47, 24, -70, + 56, 3, -55, 65, -15, -40, 75, -31, -25, 85, -46, -11, + 30, 72, -98, 33, 63, -93, 39, 45, -83, 47, 25, -69, + 56, 4, -55, 65, -14, -40, 75, -31, -25, 85, -46, -11, + 30, 72, -98, 33, 63, -92, 39, 45, -82, 47, 25, -69, + 56, 4, -55, 66, -14, -40, 75, -30, -25, 85, -46, -11, + 30, 72, -97, 33, 63, -92, 39, 46, -82, 47, 26, -69, + 56, 5, -54, 66, -13, -40, 75, -30, -25, 85, -45, -10, + 31, 73, -96, 34, 63, -91, 40, 46, -81, 48, 26, -69, + 57, 6, -54, 66, -13, -39, 75, -29, -25, 85, -44, -10, + 31, 73, -95, 34, 64, -90, 40, 47, -81, 48, 27, -68, + 57, 7, -54, 66, -12, -39, 75, -28, -25, 85, -44, -10, + 32, 73, -94, 35, 64, -90, 41, 48, -80, 48, 28, -67, + 57, 8, -53, 66, -11, -39, 76, -27, -24, 85, -43, -10, + 33, 73, -93, 35, 65, -89, 41, 49, -79, 49, 29, -67, + 57, 9, -53, 66, -9, -38, 76, -26, -24, 85, -42, -10, + 33, 74, -92, 36, 66, -87, 42, 50, -78, 49, 30, -66, + 58, 10, -52, 67, -8, -38, 76, -25, -24, 85, -41, -9, + 34, 74, -91, 37, 66, -86, 42, 51, -77, 49, 32, -65, + 58, 12, -52, 67, -7, -38, 76, -24, -23, 86, -39, -9, + 35, 75, -89, 38, 67, -85, 43, 52, -76, 50, 33, -64, + 59, 13, -51, 67, -5, -37, 76, -22, -23, 86, -38, -9, + 36, 75, -87, 38, 68, -83, 44, 53, -75, 51, 35, -63, + 59, 15, -50, 68, -3, -36, 77, -20, -22, 86, -36, -8, + 37, 76, -86, 39, 69, -82, 44, 54, -74, 51, 36, -62, + 59, 17, -49, 68, -2, -36, 77, -19, -22, 86, -35, -8, + 38, 77, -84, 40, 70, -80, 45, 56, -72, 52, 38, -61, + 60, 19, -48, 69, 0, -35, 77, -17, -21, 87, -33, -7, + 39, 77, -82, 41, 71, -78, 46, 57, -71, 53, 40, -60, + 61, 21, -47, 69, 2, -34, 78, -15, -21, 87, -31, -7, + 40, 78, -80, 42, 72, -77, 47, 59, -69, 53, 42, -59, + 61, 23, -46, 69, 5, -33, 78, -13, -20, 87, -29, -6, + 42, 79, -78, 44, 73, -75, 48, 60, -68, 54, 44, -58, + 62, 25, -45, 70, 7, -33, 79, -11, -19, 88, -27, -6, + 43, 80, -76, 45, 74, -73, 49, 62, -66, 55, 46, -56, + 62, 27, -44, 71, 9, -32, 79, -8, -19, 88, -25, -5, + 44, 81, -74, 46, 76, -71, 50, 64, -64, 56, 48, -55, + 63, 30, -43, 71, 11, -31, 80, -6, -18, 89, -23, -5, + 45, 82, -72, 47, 77, -69, 51, 65, -62, 57, 50, -53, + 64, 32, -42, 72, 14, -30, 80, -4, -17, 89, -20, -4, + 47, 83, -70, 48, 78, -67, 52, 67, -61, 58, 52, -52, + 65, 34, -41, 72, 16, -29, 81, -1, -16, 89, -18, -3, + 48, 84, -67, 50, 79, -65, 53, 69, -59, 59, 54, -50, + 66, 36, -39, 73, 19, -28, 81, 1, -15, 90, -16, -2, + 49, 85, -65, 51, 81, -63, 54, 70, -57, 60, 56, -49, + 66, 39, -38, 74, 21, -27, 82, 4, -14, 90, -13, -2, + 51, 87, -63, 52, 82, -60, 56, 72, -55, 61, 58, -47, + 67, 41, -36, 75, 24, -25, 82, 7, -13, 91, -10, -1, + 52, 88, -61, 54, 83, -58, 57, 74, -53, 62, 60, -45, + 68, 44, -35, 75, 27, -24, 83, 9, -12, 91, -8, 0, + 53, 89, -58, 55, 85, -56, 58, 76, -51, 63, 63, -43, + 69, 46, -34, 76, 29, -23, 84, 12, -11, 92, -5, 1, + 55, 90, -56, 56, 86, -54, 59, 77, -49, 64, 65, -42, + 70, 49, -32, 77, 32, -22, 84, 15, -10, 93, -3, 2, + 56, 92, -53, 58, 88, -51, 61, 79, -47, 65, 67, -40, + 71, 51, -30, 78, 35, -20, 85, 18, -9, 93, 0, 3, + 58, 93, -51, 59, 89, -49, 62, 81, -45, 66, 69, -38, + 72, 54, -29, 79, 37, -19, 86, 20, -8, 94, 3, 4, + 59, 94, -49, 60, 91, -47, 63, 83, -42, 67, 71, -36, + 73, 56, -27, 79, 40, -17, 87, 23, -7, 94, 6, 5, + 30, 74, -102, 33, 65, -97, 40, 47, -87, 47, 27, -74, + 56, 6, -59, 66, -12, -45, 75, -29, -30, 85, -44, -15, + 31, 74, -102, 34, 65, -97, 40, 48, -87, 47, 27, -74, + 57, 7, -59, 66, -12, -44, 75, -28, -30, 85, -44, -15, + 31, 74, -102, 34, 65, -97, 40, 48, -86, 48, 28, -74, + 57, 7, -59, 66, -12, -44, 75, -28, -30, 85, -44, -15, + 31, 74, -101, 34, 65, -96, 40, 48, -86, 48, 28, -73, + 57, 7, -59, 66, -11, -44, 75, -28, -30, 85, -43, -15, + 31, 74, -101, 34, 65, -96, 40, 48, -86, 48, 28, -73, + 57, 8, -59, 66, -11, -44, 75, -27, -30, 85, -43, -15, + 32, 75, -100, 34, 66, -95, 40, 49, -85, 48, 29, -73, + 57, 8, -58, 66, -10, -44, 75, -27, -29, 85, -42, -15, + 32, 75, -99, 35, 66, -95, 41, 49, -85, 48, 30, -73, + 57, 9, -58, 66, -9, -44, 76, -26, -29, 85, -42, -15, + 32, 75, -98, 35, 66, -94, 41, 50, -84, 49, 30, -72, + 57, 10, -58, 66, -9, -43, 76, -25, -29, 85, -41, -14, + 33, 75, -98, 36, 67, -93, 41, 51, -84, 49, 31, -71, + 58, 11, -57, 67, -8, -43, 76, -24, -29, 85, -40, -14, + 34, 76, -96, 36, 67, -92, 42, 52, -83, 49, 32, -71, + 58, 12, -57, 67, -6, -43, 76, -23, -28, 86, -39, -14, + 34, 76, -95, 37, 68, -91, 42, 52, -82, 50, 34, -70, + 58, 13, -56, 67, -5, -42, 76, -22, -28, 86, -38, -14, + 35, 76, -94, 38, 69, -90, 43, 53, -81, 50, 35, -69, + 59, 15, -56, 67, -4, -42, 76, -21, -28, 86, -37, -13, + 36, 77, -92, 39, 69, -88, 44, 55, -80, 51, 36, -68, + 59, 16, -55, 68, -2, -41, 77, -19, -27, 86, -36, -13, + 37, 77, -91, 39, 70, -87, 44, 56, -79, 51, 38, -68, + 59, 18, -54, 68, -1, -41, 77, -18, -27, 86, -34, -13, + 38, 78, -89, 40, 71, -85, 45, 57, -77, 52, 39, -67, + 60, 20, -54, 68, 1, -40, 77, -16, -26, 87, -33, -12, + 39, 79, -88, 41, 72, -84, 46, 58, -76, 52, 41, -65, + 60, 21, -53, 69, 3, -39, 78, -15, -26, 87, -31, -12, + 40, 79, -86, 42, 73, -82, 47, 60, -75, 53, 43, -64, + 61, 23, -52, 69, 5, -39, 78, -12, -25, 87, -29, -11, + 41, 80, -84, 43, 74, -80, 48, 61, -73, 54, 44, -63, + 62, 25, -51, 70, 7, -38, 78, -10, -24, 88, -27, -11, + 42, 81, -82, 44, 75, -79, 49, 63, -72, 55, 46, -62, + 62, 27, -50, 70, 9, -37, 79, -8, -24, 88, -25, -10, + 43, 82, -80, 45, 76, -77, 50, 64, -70, 55, 48, -60, + 63, 29, -49, 71, 11, -36, 79, -6, -23, 88, -23, -10, + 45, 83, -78, 47, 77, -75, 51, 66, -68, 56, 50, -59, + 64, 32, -47, 72, 14, -35, 80, -4, -22, 89, -21, -9, + 46, 84, -76, 48, 78, -73, 52, 67, -66, 57, 52, -57, + 64, 34, -46, 72, 16, -34, 80, -1, -21, 89, -18, -8, + 47, 85, -74, 49, 80, -71, 53, 69, -65, 58, 54, -56, + 65, 36, -45, 73, 18, -33, 81, 1, -21, 90, -16, -8, + 49, 86, -71, 50, 81, -69, 54, 70, -63, 59, 56, -54, + 66, 38, -44, 73, 21, -32, 81, 3, -20, 90, -14, -7, + 50, 87, -69, 51, 82, -67, 55, 72, -61, 60, 58, -53, + 67, 41, -42, 74, 23, -31, 82, 6, -19, 91, -11, -6, + 51, 88, -67, 53, 84, -64, 56, 74, -59, 61, 60, -51, + 68, 43, -41, 75, 26, -30, 83, 9, -18, 91, -9, -5, + 53, 89, -65, 54, 85, -62, 57, 75, -57, 62, 62, -49, + 69, 46, -39, 76, 28, -28, 83, 11, -17, 92, -6, -4, + 54, 90, -62, 55, 86, -60, 59, 77, -55, 63, 64, -48, + 69, 48, -38, 76, 31, -27, 84, 14, -16, 92, -4, -3, + 55, 92, -60, 57, 88, -58, 60, 79, -53, 64, 66, -46, + 70, 50, -36, 77, 33, -26, 85, 16, -15, 93, -1, -3, + 57, 93, -58, 58, 89, -56, 61, 81, -51, 66, 68, -44, + 71, 53, -35, 78, 36, -24, 85, 19, -13, 93, 2, -1, + 58, 94, -55, 59, 91, -53, 62, 82, -49, 67, 70, -42, + 72, 55, -33, 79, 39, -23, 86, 22, -12, 94, 5, 0, + 60, 96, -53, 61, 92, -51, 64, 84, -47, 68, 72, -40, + 73, 58, -32, 80, 41, -22, 87, 25, -11, 95, 7, 1, + 32, 76, -105, 34, 67, -100, 40, 50, -90, 48, 30, -77, + 57, 10, -63, 66, -9, -48, 75, -26, -34, 85, -42, -19, + 32, 76, -104, 35, 67, -100, 40, 50, -90, 48, 30, -77, + 57, 10, -63, 66, -9, -48, 75, -26, -34, 85, -41, -19, + 32, 76, -104, 35, 67, -99, 41, 51, -90, 48, 31, -77, + 57, 10, -63, 66, -9, -48, 75, -26, -34, 85, -41, -19, + 32, 76, -104, 35, 68, -99, 41, 51, -89, 48, 31, -77, + 57, 10, -63, 66, -8, -48, 76, -25, -34, 85, -41, -19, + 32, 76, -103, 35, 68, -99, 41, 51, -89, 48, 31, -77, + 57, 11, -62, 66, -8, -48, 76, -25, -33, 85, -41, -19, + 33, 76, -103, 35, 68, -98, 41, 52, -89, 49, 32, -76, + 57, 11, -62, 66, -7, -48, 76, -24, -33, 85, -40, -19, + 33, 77, -102, 36, 68, -98, 41, 52, -88, 49, 33, -76, + 58, 12, -62, 67, -7, -48, 76, -24, -33, 85, -40, -19, + 34, 77, -101, 36, 69, -97, 42, 53, -88, 49, 33, -75, + 58, 13, -61, 67, -6, -47, 76, -23, -33, 86, -39, -18, + 34, 77, -100, 37, 69, -96, 42, 53, -87, 49, 34, -75, + 58, 14, -61, 67, -5, -47, 76, -22, -33, 86, -38, -18, + 35, 77, -99, 37, 70, -95, 43, 54, -86, 50, 35, -74, + 58, 15, -61, 67, -4, -47, 76, -21, -32, 86, -37, -18, + 35, 78, -98, 38, 70, -94, 43, 55, -85, 50, 36, -74, + 59, 16, -60, 67, -3, -46, 77, -20, -32, 86, -36, -18, + 36, 78, -97, 39, 71, -93, 44, 56, -84, 51, 37, -73, + 59, 17, -59, 68, -1, -46, 77, -19, -32, 86, -35, -17, + 37, 79, -95, 39, 71, -91, 44, 57, -83, 51, 39, -72, + 59, 19, -59, 68, 0, -45, 77, -17, -31, 86, -33, -17, + 38, 79, -94, 40, 72, -90, 45, 58, -82, 52, 40, -71, + 60, 20, -58, 68, 2, -44, 77, -16, -31, 87, -32, -17, + 39, 80, -92, 41, 73, -89, 46, 59, -81, 52, 42, -70, + 60, 22, -57, 69, 3, -44, 78, -14, -30, 87, -30, -16, + 40, 80, -91, 42, 74, -87, 47, 60, -80, 53, 43, -69, + 61, 24, -56, 69, 5, -43, 78, -12, -30, 87, -29, -16, + 41, 81, -89, 43, 75, -85, 47, 62, -78, 54, 45, -68, + 61, 26, -55, 70, 7, -42, 78, -10, -29, 88, -27, -15, + 42, 82, -87, 44, 76, -84, 48, 63, -77, 54, 47, -67, + 62, 28, -54, 70, 9, -42, 79, -8, -28, 88, -25, -15, + 43, 82, -85, 45, 77, -82, 49, 64, -75, 55, 48, -65, + 63, 30, -53, 71, 11, -41, 79, -6, -28, 88, -23, -14, + 44, 83, -83, 46, 78, -80, 50, 66, -74, 56, 50, -64, + 63, 32, -52, 71, 13, -40, 80, -4, -27, 89, -21, -13, + 45, 84, -81, 47, 79, -78, 51, 67, -72, 57, 52, -63, + 64, 34, -51, 72, 16, -39, 80, -2, -26, 89, -19, -13, + 47, 85, -79, 48, 80, -76, 52, 69, -70, 58, 54, -61, + 65, 36, -50, 72, 18, -38, 81, 0, -25, 89, -17, -12, + 48, 86, -77, 50, 81, -74, 53, 70, -68, 59, 56, -60, + 66, 38, -49, 73, 20, -37, 81, 3, -24, 90, -14, -11, + 49, 87, -75, 51, 82, -72, 54, 72, -67, 60, 58, -58, + 66, 40, -47, 74, 23, -36, 82, 5, -24, 90, -12, -11, + 50, 88, -73, 52, 84, -70, 55, 74, -65, 61, 60, -57, + 67, 42, -46, 74, 25, -35, 82, 7, -23, 91, -10, -10, + 52, 89, -70, 53, 85, -68, 57, 75, -63, 62, 62, -55, + 68, 45, -45, 75, 28, -33, 83, 10, -22, 91, -7, -9, + 53, 90, -68, 55, 86, -66, 58, 77, -61, 63, 64, -53, + 69, 47, -43, 76, 30, -32, 84, 13, -21, 92, -5, -8, + 54, 92, -66, 56, 88, -64, 59, 79, -59, 64, 66, -51, + 70, 49, -42, 77, 33, -31, 84, 15, -20, 92, -2, -7, + 56, 93, -64, 57, 89, -62, 60, 80, -57, 65, 68, -50, + 71, 52, -40, 77, 35, -30, 85, 18, -18, 93, 1, -6, + 57, 94, -61, 59, 90, -59, 62, 82, -55, 66, 70, -48, + 72, 54, -39, 78, 38, -28, 86, 21, -17, 94, 3, -5, + 59, 95, -59, 60, 92, -57, 63, 84, -53, 67, 72, -46, + 73, 57, -37, 79, 40, -27, 86, 23, -16, 94, 6, -4, + 60, 97, -57, 61, 93, -55, 64, 85, -51, 68, 74, -44, + 74, 59, -35, 80, 43, -26, 87, 26, -15, 95, 9, -3, + 33, 78, -107, 35, 69, -103, 41, 53, -93, 49, 33, -81, + 57, 13, -66, 66, -6, -52, 76, -23, -38, 85, -39, -23, + 33, 78, -107, 36, 70, -102, 41, 53, -93, 49, 33, -81, + 58, 13, -66, 67, -6, -52, 76, -23, -38, 85, -39, -23, + 33, 78, -107, 36, 70, -102, 41, 53, -93, 49, 34, -81, + 58, 13, -66, 67, -6, -52, 76, -23, -37, 85, -39, -23, + 33, 78, -106, 36, 70, -102, 42, 54, -93, 49, 34, -80, + 58, 13, -66, 67, -5, -52, 76, -23, -37, 85, -39, -23, + 33, 78, -106, 36, 70, -102, 42, 54, -92, 49, 34, -80, + 58, 14, -66, 67, -5, -52, 76, -22, -37, 85, -38, -23, + 34, 78, -106, 36, 70, -101, 42, 54, -92, 49, 35, -80, + 58, 14, -66, 67, -5, -51, 76, -22, -37, 86, -38, -22, + 34, 79, -105, 37, 71, -100, 42, 55, -91, 49, 35, -79, + 58, 15, -65, 67, -4, -51, 76, -21, -37, 86, -37, -22, + 35, 79, -104, 37, 71, -100, 43, 55, -91, 50, 36, -79, + 58, 16, -65, 67, -3, -51, 76, -20, -37, 86, -36, -22, + 35, 79, -103, 38, 71, -99, 43, 56, -90, 50, 37, -78, + 59, 17, -65, 67, -2, -51, 76, -19, -36, 86, -36, -22, + 36, 79, -102, 38, 72, -98, 43, 57, -89, 50, 38, -78, + 59, 18, -64, 68, -1, -50, 77, -18, -36, 86, -35, -22, + 36, 80, -101, 39, 72, -97, 44, 57, -88, 51, 39, -77, + 59, 19, -64, 68, 0, -50, 77, -17, -36, 86, -34, -21, + 37, 80, -100, 39, 73, -96, 44, 58, -88, 51, 40, -76, + 59, 20, -63, 68, 1, -49, 77, -16, -35, 86, -33, -21, + 38, 80, -98, 40, 73, -95, 45, 59, -86, 52, 41, -76, + 60, 22, -62, 68, 3, -49, 77, -15, -35, 87, -31, -21, + 39, 81, -97, 41, 74, -93, 46, 60, -85, 52, 43, -75, + 60, 23, -62, 69, 4, -48, 78, -13, -35, 87, -30, -20, + 40, 81, -95, 42, 75, -92, 46, 61, -84, 53, 44, -74, + 61, 25, -61, 69, 6, -48, 78, -12, -34, 87, -28, -20, + 41, 82, -94, 43, 76, -90, 47, 63, -83, 54, 45, -73, + 61, 26, -60, 70, 8, -47, 78, -10, -33, 87, -27, -20, + 42, 83, -92, 44, 77, -89, 48, 64, -81, 54, 47, -71, + 62, 28, -59, 70, 10, -46, 79, -8, -33, 88, -25, -19, + 43, 83, -90, 45, 77, -87, 49, 65, -80, 55, 49, -70, + 62, 30, -58, 71, 11, -45, 79, -6, -32, 88, -23, -18, + 44, 84, -88, 46, 78, -85, 50, 66, -79, 56, 50, -69, + 63, 32, -57, 71, 13, -45, 79, -4, -32, 88, -21, -18, + 45, 85, -87, 47, 79, -84, 51, 68, -77, 56, 52, -68, + 64, 34, -56, 72, 15, -44, 80, -2, -31, 89, -19, -17, + 46, 86, -84, 48, 81, -82, 52, 69, -75, 57, 54, -66, + 64, 36, -55, 72, 18, -43, 80, 0, -30, 89, -17, -17, + 47, 87, -83, 49, 82, -80, 53, 71, -74, 58, 56, -65, + 65, 38, -54, 73, 20, -42, 81, 2, -29, 90, -15, -16, + 49, 88, -80, 50, 83, -78, 54, 72, -72, 59, 58, -63, + 66, 40, -52, 73, 22, -41, 81, 5, -28, 90, -13, -15, + 50, 89, -78, 51, 84, -76, 55, 74, -70, 60, 59, -62, + 67, 42, -51, 74, 24, -40, 82, 7, -27, 91, -10, -15, + 51, 90, -76, 53, 85, -74, 56, 75, -68, 61, 61, -60, + 67, 44, -50, 75, 27, -39, 83, 9, -27, 91, -8, -14, + 52, 91, -74, 54, 86, -72, 57, 77, -66, 62, 63, -59, + 68, 47, -48, 76, 29, -37, 83, 12, -25, 92, -5, -13, + 54, 92, -72, 55, 88, -70, 58, 78, -64, 63, 65, -57, + 69, 49, -47, 76, 32, -36, 84, 14, -24, 92, -3, -12, + 55, 93, -70, 56, 89, -68, 59, 80, -63, 64, 67, -55, + 70, 51, -46, 77, 34, -35, 84, 17, -23, 93, 0, -11, + 56, 94, -68, 58, 90, -65, 61, 81, -61, 65, 69, -53, + 71, 53, -44, 78, 37, -34, 85, 19, -22, 93, 2, -10, + 58, 95, -65, 59, 92, -63, 62, 83, -58, 66, 71, -52, + 72, 56, -42, 79, 39, -32, 86, 22, -21, 94, 5, -9, + 59, 97, -63, 60, 93, -61, 63, 85, -56, 67, 73, -50, + 73, 58, -41, 79, 42, -31, 87, 25, -20, 94, 8, -8, + 60, 98, -61, 62, 94, -59, 64, 86, -54, 68, 75, -48, + 74, 60, -39, 80, 44, -29, 87, 27, -19, 95, 10, -7, + 2, -5, 3, 15, -26, 21, 28, -36, 35, 39, -46, 44, + 51, -56, 54, 62, -65, 62, 72, -73, 71, 83, -82, 79, + 3, -3, 4, 15, -23, 22, 28, -35, 35, 40, -45, 45, + 51, -55, 54, 62, -64, 63, 72, -73, 71, 83, -82, 79, + 3, 0, 5, 15, -21, 22, 28, -34, 35, 40, -44, 45, + 51, -55, 54, 62, -64, 63, 72, -73, 71, 83, -82, 79, + 4, 4, 6, 16, -17, 23, 28, -31, 36, 40, -43, 45, + 51, -54, 54, 62, -63, 63, 72, -72, 71, 83, -81, 79, + 5, 8, 8, 17, -13, 24, 28, -29, 36, 40, -41, 45, + 51, -52, 54, 62, -62, 63, 73, -71, 71, 83, -80, 79, + 7, 14, 10, 17, -9, 25, 29, -26, 36, 40, -39, 45, + 52, -51, 54, 62, -61, 63, 73, -71, 71, 83, -80, 80, + 8, 18, 13, 18, -4, 26, 29, -23, 37, 41, -37, 46, + 52, -49, 55, 62, -60, 63, 73, -69, 71, 83, -79, 80, + 10, 22, 16, 19, 1, 27, 30, -18, 38, 41, -34, 46, + 52, -47, 55, 63, -58, 63, 73, -68, 72, 83, -78, 80, + 12, 25, 19, 20, 5, 29, 31, -15, 39, 41, -31, 47, + 52, -45, 55, 63, -56, 64, 73, -67, 72, 83, -77, 80, + 14, 28, 22, 21, 10, 30, 31, -11, 39, 42, -28, 47, + 53, -42, 56, 63, -54, 64, 73, -65, 72, 84, -75, 80, + 16, 31, 24, 23, 14, 32, 32, -7, 40, 42, -24, 48, + 53, -39, 56, 63, -52, 64, 74, -63, 72, 84, -74, 80, + 18, 34, 27, 24, 18, 34, 33, -2, 41, 43, -20, 49, + 54, -36, 57, 64, -49, 65, 74, -61, 73, 84, -72, 81, + 20, 37, 30, 25, 22, 36, 34, 2, 42, 44, -16, 50, + 54, -33, 57, 64, -46, 65, 74, -59, 73, 84, -70, 81, + 22, 39, 32, 27, 25, 38, 35, 6, 44, 44, -12, 50, + 55, -29, 58, 64, -44, 66, 74, -56, 73, 84, -68, 81, + 23, 42, 35, 28, 29, 39, 36, 10, 45, 45, -9, 51, + 55, -26, 59, 65, -41, 66, 75, -54, 74, 85, -66, 82, + 25, 44, 37, 30, 32, 41, 37, 14, 46, 46, -5, 52, + 56, -23, 59, 65, -38, 67, 75, -51, 74, 85, -64, 82, + 27, 47, 40, 31, 36, 43, 38, 18, 47, 47, 0, 53, + 56, -18, 60, 66, -34, 67, 75, -48, 75, 85, -61, 82, + 29, 49, 42, 33, 39, 45, 39, 22, 49, 48, 3, 54, + 57, -15, 61, 66, -31, 68, 76, -45, 75, 86, -58, 83, + 31, 52, 44, 34, 42, 47, 41, 26, 50, 49, 7, 55, + 58, -11, 62, 67, -27, 69, 76, -42, 76, 86, -56, 83, + 33, 54, 46, 36, 44, 48, 42, 29, 51, 50, 11, 56, + 58, -8, 63, 68, -24, 69, 77, -39, 76, 86, -53, 84, + 35, 56, 49, 38, 48, 50, 43, 33, 53, 51, 15, 58, + 59, -3, 64, 68, -20, 70, 77, -35, 77, 87, -50, 84, + 36, 58, 50, 39, 50, 52, 45, 36, 54, 52, 19, 59, + 60, 0, 65, 69, -17, 71, 78, -32, 78, 87, -47, 85, + 38, 61, 52, 41, 53, 53, 46, 39, 56, 53, 22, 60, + 61, 4, 66, 70, -13, 72, 78, -29, 78, 88, -44, 85, + 40, 63, 54, 42, 55, 55, 47, 42, 57, 54, 26, 61, + 62, 8, 67, 70, -10, 72, 79, -26, 79, 88, -41, 86, + 41, 65, 55, 44, 58, 56, 48, 45, 59, 55, 29, 62, + 63, 11, 68, 71, -6, 73, 80, -22, 80, 89, -38, 86, + 43, 67, 57, 46, 61, 58, 50, 49, 60, 56, 33, 64, + 64, 15, 69, 72, -2, 74, 80, -18, 80, 89, -34, 87, + 45, 69, 59, 47, 63, 60, 51, 51, 62, 57, 36, 65, + 65, 19, 70, 73, 2, 75, 81, -15, 81, 90, -31, 88, + 47, 71, 61, 49, 65, 61, 53, 54, 63, 58, 39, 66, + 66, 22, 71, 73, 5, 76, 82, -11, 82, 90, -28, 88, + 48, 73, 62, 50, 68, 63, 54, 57, 65, 60, 43, 68, + 67, 26, 72, 74, 9, 77, 82, -8, 83, 91, -24, 89, + 50, 75, 64, 52, 70, 65, 56, 60, 66, 61, 46, 69, + 68, 29, 73, 75, 12, 78, 83, -4, 84, 92, -21, 90, + 52, 77, 66, 54, 72, 66, 57, 63, 68, 62, 49, 71, + 69, 33, 75, 76, 16, 79, 84, -1, 85, 92, -17, 91, + 54, 79, 67, 55, 74, 68, 59, 65, 69, 64, 52, 72, + 70, 36, 76, 77, 19, 80, 85, 3, 86, 93, -14, 91, + 3, -4, 0, 15, -24, 18, 28, -36, 32, 40, -46, 42, + 51, -55, 52, 62, -65, 61, 72, -73, 70, 83, -82, 79, + 3, -2, 1, 15, -22, 18, 28, -34, 32, 40, -45, 43, + 51, -55, 52, 62, -64, 61, 72, -73, 70, 83, -82, 79, + 4, 1, 2, 16, -20, 19, 28, -33, 32, 40, -44, 43, + 51, -54, 53, 62, -64, 62, 72, -73, 70, 83, -81, 79, + 4, 5, 3, 16, -16, 20, 28, -31, 33, 40, -43, 43, + 51, -53, 53, 62, -63, 62, 72, -72, 70, 83, -81, 79, + 5, 9, 5, 17, -12, 20, 29, -28, 33, 40, -41, 43, + 51, -52, 53, 62, -62, 62, 73, -71, 70, 83, -80, 79, + 7, 15, 7, 17, -8, 21, 29, -25, 33, 40, -39, 43, + 52, -51, 53, 62, -61, 62, 73, -70, 70, 83, -80, 79, + 8, 18, 10, 18, -4, 23, 29, -22, 34, 41, -37, 44, + 52, -49, 53, 62, -60, 62, 73, -69, 71, 83, -79, 79, + 10, 22, 13, 19, 1, 24, 30, -18, 35, 41, -33, 44, + 52, -47, 54, 63, -58, 62, 73, -68, 71, 83, -78, 79, + 12, 26, 16, 20, 6, 26, 31, -14, 36, 41, -30, 45, + 52, -44, 54, 63, -56, 63, 73, -66, 71, 83, -76, 79, + 14, 29, 18, 21, 10, 27, 31, -10, 36, 42, -27, 45, + 53, -42, 54, 63, -54, 63, 73, -65, 71, 84, -75, 79, + 16, 31, 21, 23, 14, 29, 32, -6, 37, 42, -24, 46, + 53, -39, 55, 63, -52, 63, 74, -63, 71, 84, -74, 80, + 18, 34, 24, 24, 18, 31, 33, -2, 38, 43, -20, 47, + 54, -36, 55, 64, -49, 64, 74, -61, 72, 84, -72, 80, + 20, 37, 27, 25, 22, 33, 34, 2, 40, 44, -16, 48, + 54, -33, 56, 64, -46, 64, 74, -58, 72, 84, -70, 80, + 22, 40, 29, 27, 26, 34, 35, 6, 41, 44, -12, 48, + 55, -29, 57, 64, -44, 65, 74, -56, 72, 84, -68, 81, + 23, 42, 32, 28, 29, 36, 36, 10, 42, 45, -8, 49, + 55, -26, 57, 65, -41, 65, 75, -54, 73, 85, -66, 81, + 25, 44, 34, 30, 32, 38, 37, 14, 43, 46, -5, 50, + 56, -22, 58, 65, -38, 66, 75, -51, 73, 85, -63, 81, + 27, 47, 37, 31, 36, 40, 38, 18, 45, 47, 0, 51, + 56, -18, 59, 66, -34, 66, 75, -48, 74, 85, -61, 82, + 29, 49, 39, 33, 39, 42, 39, 22, 46, 48, 4, 52, + 57, -15, 60, 66, -31, 67, 76, -45, 74, 86, -58, 82, + 31, 52, 41, 34, 42, 43, 41, 26, 48, 49, 7, 54, + 58, -11, 60, 67, -27, 68, 76, -42, 75, 86, -56, 83, + 33, 54, 43, 36, 45, 45, 42, 29, 49, 50, 11, 55, + 58, -7, 61, 68, -24, 68, 77, -39, 75, 86, -53, 83, + 35, 56, 45, 38, 48, 47, 43, 33, 51, 51, 15, 56, + 59, -3, 62, 68, -20, 69, 77, -35, 76, 87, -50, 84, + 36, 59, 47, 39, 50, 49, 45, 36, 52, 52, 19, 57, + 60, 0, 63, 69, -17, 70, 78, -32, 77, 87, -47, 84, + 38, 61, 49, 41, 53, 51, 46, 39, 54, 53, 22, 58, + 61, 4, 64, 70, -13, 71, 78, -29, 77, 88, -44, 85, + 40, 63, 51, 42, 55, 52, 47, 42, 55, 54, 26, 60, + 62, 8, 65, 70, -9, 72, 79, -25, 78, 88, -41, 85, + 41, 65, 53, 44, 58, 54, 49, 45, 57, 55, 29, 61, + 63, 11, 66, 71, -6, 72, 80, -22, 79, 89, -38, 86, + 43, 67, 55, 46, 61, 56, 50, 49, 59, 56, 33, 62, + 64, 15, 68, 72, -2, 73, 80, -18, 80, 89, -34, 86, + 45, 69, 57, 47, 63, 58, 51, 52, 60, 57, 36, 64, + 65, 19, 69, 73, 2, 74, 81, -15, 80, 90, -31, 87, + 47, 71, 58, 49, 65, 59, 53, 54, 62, 58, 39, 65, + 66, 22, 70, 73, 5, 75, 82, -11, 81, 90, -27, 88, + 48, 73, 60, 50, 68, 61, 54, 57, 63, 60, 43, 66, + 67, 26, 71, 74, 9, 76, 82, -8, 82, 91, -24, 89, + 50, 75, 62, 52, 70, 63, 56, 60, 65, 61, 46, 68, + 68, 29, 72, 75, 12, 77, 83, -4, 83, 92, -20, 89, + 52, 77, 64, 54, 72, 65, 57, 63, 66, 62, 49, 69, + 69, 33, 73, 76, 16, 78, 84, -1, 84, 92, -17, 90, + 54, 79, 65, 55, 74, 66, 59, 65, 68, 64, 52, 71, + 70, 36, 75, 77, 19, 79, 85, 3, 85, 93, -14, 91, + 3, -2, -3, 15, -23, 14, 28, -35, 29, 40, -45, 40, + 51, -55, 51, 62, -64, 60, 72, -73, 69, 83, -82, 78, + 3, 0, -2, 15, -21, 15, 28, -34, 29, 40, -44, 40, + 51, -55, 51, 62, -64, 60, 72, -73, 69, 83, -82, 78, + 4, 2, -1, 16, -18, 15, 28, -32, 29, 40, -44, 41, + 51, -54, 51, 62, -63, 60, 72, -72, 69, 83, -81, 78, + 5, 6, 0, 16, -15, 16, 28, -30, 29, 40, -42, 41, + 51, -53, 51, 62, -63, 60, 72, -72, 69, 83, -81, 78, + 6, 11, 2, 17, -11, 17, 29, -28, 30, 40, -41, 41, + 52, -52, 51, 62, -62, 61, 73, -71, 69, 83, -80, 78, + 7, 15, 4, 17, -7, 18, 29, -25, 30, 40, -39, 41, + 52, -50, 52, 62, -61, 61, 73, -70, 69, 83, -80, 78, + 9, 19, 6, 18, -3, 19, 29, -22, 31, 41, -36, 42, + 52, -49, 52, 62, -59, 61, 73, -69, 70, 83, -79, 78, + 11, 23, 9, 19, 2, 21, 30, -18, 32, 41, -33, 42, + 52, -46, 52, 63, -58, 61, 73, -68, 70, 83, -78, 78, + 12, 26, 12, 20, 6, 22, 31, -14, 33, 41, -30, 43, + 52, -44, 53, 63, -56, 61, 73, -66, 70, 83, -76, 79, + 14, 29, 15, 21, 10, 24, 31, -10, 34, 42, -27, 43, + 53, -42, 53, 63, -54, 62, 73, -65, 70, 84, -75, 79, + 16, 32, 18, 23, 14, 25, 32, -6, 35, 42, -24, 44, + 53, -39, 53, 63, -52, 62, 74, -63, 71, 84, -73, 79, + 18, 34, 20, 24, 18, 27, 33, -2, 36, 43, -20, 45, + 54, -36, 54, 64, -49, 63, 74, -61, 71, 84, -72, 79, + 20, 37, 23, 25, 22, 29, 34, 3, 37, 44, -16, 46, + 54, -32, 55, 64, -46, 63, 74, -58, 71, 84, -70, 80, + 22, 40, 26, 27, 26, 31, 35, 7, 38, 44, -12, 47, + 55, -29, 55, 65, -43, 63, 74, -56, 72, 84, -68, 80, + 23, 42, 28, 28, 29, 33, 36, 11, 40, 45, -8, 47, + 55, -26, 56, 65, -40, 64, 75, -53, 72, 85, -66, 80, + 25, 45, 30, 30, 32, 34, 37, 14, 41, 46, -4, 48, + 56, -22, 57, 65, -37, 65, 75, -51, 72, 85, -63, 81, + 27, 47, 33, 31, 36, 37, 38, 19, 42, 47, 0, 50, + 56, -18, 57, 66, -34, 65, 76, -48, 73, 85, -61, 81, + 29, 50, 35, 33, 39, 38, 39, 22, 44, 48, 4, 51, + 57, -15, 58, 66, -31, 66, 76, -45, 73, 86, -58, 81, + 31, 52, 37, 34, 42, 40, 41, 26, 45, 49, 7, 52, + 58, -11, 59, 67, -27, 67, 76, -42, 74, 86, -55, 82, + 33, 54, 40, 36, 45, 42, 42, 29, 47, 50, 11, 53, + 58, -7, 60, 68, -24, 67, 77, -39, 75, 86, -53, 82, + 35, 56, 42, 38, 48, 44, 43, 33, 49, 51, 15, 54, + 59, -3, 61, 68, -20, 68, 77, -35, 75, 87, -50, 83, + 36, 59, 44, 39, 50, 46, 45, 36, 50, 52, 19, 55, + 60, 1, 62, 69, -16, 69, 78, -32, 76, 87, -47, 83, + 38, 61, 46, 41, 53, 48, 46, 39, 52, 53, 22, 57, + 61, 4, 63, 70, -13, 70, 78, -29, 77, 88, -44, 84, + 40, 63, 48, 42, 56, 50, 47, 42, 53, 54, 26, 58, + 62, 8, 64, 70, -9, 70, 79, -25, 77, 88, -41, 84, + 41, 65, 50, 44, 58, 52, 49, 45, 55, 55, 29, 59, + 63, 11, 65, 71, -6, 71, 80, -22, 78, 89, -37, 85, + 43, 67, 52, 46, 61, 54, 50, 49, 57, 56, 33, 61, + 64, 15, 66, 72, -2, 72, 80, -18, 79, 89, -34, 86, + 45, 69, 54, 47, 63, 55, 51, 52, 58, 57, 36, 62, + 65, 19, 67, 73, 2, 73, 81, -15, 80, 90, -31, 86, + 47, 71, 56, 49, 65, 57, 53, 54, 60, 59, 40, 64, + 66, 22, 69, 73, 5, 74, 82, -11, 80, 90, -27, 87, + 48, 73, 58, 50, 68, 59, 54, 57, 61, 60, 43, 65, + 67, 26, 70, 74, 9, 75, 82, -8, 81, 91, -24, 88, + 50, 75, 60, 52, 70, 61, 56, 60, 63, 61, 46, 66, + 68, 29, 71, 75, 13, 76, 83, -4, 82, 92, -20, 89, + 52, 77, 62, 54, 72, 63, 57, 63, 65, 62, 49, 68, + 69, 33, 72, 76, 16, 77, 84, -1, 83, 92, -17, 89, + 54, 79, 63, 55, 75, 64, 59, 65, 66, 64, 52, 69, + 70, 36, 74, 77, 19, 79, 85, 3, 84, 93, -14, 90, + 3, 0, -9, 15, -21, 9, 28, -34, 24, 40, -45, 37, + 51, -55, 49, 62, -64, 58, 72, -73, 68, 83, -82, 77, + 3, 2, -8, 15, -19, 9, 28, -33, 25, 40, -44, 37, + 51, -54, 49, 62, -64, 58, 72, -72, 68, 83, -81, 77, + 4, 4, -7, 16, -17, 10, 28, -31, 25, 40, -43, 37, + 51, -54, 49, 62, -63, 59, 72, -72, 68, 83, -81, 77, + 5, 8, -6, 16, -13, 10, 28, -29, 25, 40, -42, 38, + 51, -53, 49, 62, -62, 59, 73, -72, 68, 83, -81, 77, + 6, 13, -4, 17, -10, 11, 29, -27, 26, 40, -40, 38, + 52, -51, 49, 62, -61, 59, 73, -71, 68, 83, -80, 77, + 7, 17, -2, 18, -6, 12, 29, -24, 26, 40, -38, 38, + 52, -50, 49, 62, -60, 59, 73, -70, 68, 83, -79, 77, + 9, 20, 1, 18, -2, 14, 29, -21, 27, 41, -36, 39, + 52, -48, 49, 63, -59, 59, 73, -69, 68, 83, -78, 77, + 11, 24, 4, 19, 3, 15, 30, -17, 28, 41, -33, 39, + 52, -46, 50, 63, -57, 59, 73, -67, 68, 83, -77, 77, + 13, 27, 6, 20, 7, 17, 31, -13, 29, 41, -30, 40, + 52, -44, 50, 63, -55, 60, 73, -66, 69, 83, -76, 77, + 14, 30, 9, 22, 11, 18, 31, -9, 30, 42, -26, 40, + 53, -41, 51, 63, -53, 60, 73, -64, 69, 84, -75, 78, + 16, 32, 12, 23, 15, 20, 32, -5, 31, 42, -23, 41, + 53, -38, 51, 63, -51, 60, 74, -63, 69, 84, -73, 78, + 18, 35, 14, 24, 19, 22, 33, -1, 32, 43, -20, 42, + 54, -35, 52, 64, -49, 61, 74, -61, 69, 84, -72, 78, + 20, 38, 17, 26, 23, 24, 34, 3, 33, 44, -15, 43, + 54, -32, 52, 64, -46, 61, 74, -58, 70, 84, -70, 78, + 22, 40, 20, 27, 26, 26, 35, 7, 34, 44, -12, 44, + 55, -29, 53, 65, -43, 62, 74, -56, 70, 84, -68, 79, + 24, 43, 23, 28, 30, 28, 36, 11, 36, 45, -8, 45, + 55, -25, 54, 65, -40, 62, 75, -53, 71, 85, -65, 79, + 25, 45, 25, 30, 33, 30, 37, 15, 37, 46, -4, 46, + 56, -22, 54, 65, -37, 63, 75, -51, 71, 85, -63, 79, + 27, 48, 28, 31, 36, 32, 38, 19, 39, 47, 0, 47, + 56, -18, 55, 66, -34, 63, 76, -48, 72, 85, -60, 80, + 29, 50, 30, 33, 39, 34, 40, 23, 40, 48, 4, 48, + 57, -14, 56, 66, -30, 64, 76, -45, 72, 86, -58, 80, + 31, 52, 33, 34, 42, 36, 41, 26, 42, 49, 8, 49, + 58, -11, 57, 67, -27, 65, 76, -42, 73, 86, -55, 81, + 33, 54, 35, 36, 45, 38, 42, 30, 43, 50, 11, 50, + 58, -7, 58, 68, -24, 66, 77, -39, 73, 86, -53, 81, + 35, 57, 37, 38, 48, 40, 43, 33, 45, 51, 16, 52, + 59, -3, 59, 68, -20, 66, 77, -35, 74, 87, -49, 82, + 36, 59, 40, 39, 51, 42, 45, 36, 47, 52, 19, 53, + 60, 1, 60, 69, -16, 67, 78, -32, 75, 87, -46, 82, + 38, 61, 42, 41, 53, 44, 46, 40, 48, 53, 23, 54, + 61, 4, 61, 70, -13, 68, 78, -29, 75, 88, -43, 83, + 40, 63, 44, 42, 56, 46, 47, 43, 50, 54, 26, 55, + 62, 8, 62, 70, -9, 69, 79, -25, 76, 88, -40, 83, + 42, 65, 46, 44, 58, 48, 49, 46, 52, 55, 30, 57, + 63, 12, 63, 71, -6, 70, 80, -22, 77, 89, -37, 84, + 43, 67, 48, 46, 61, 50, 50, 49, 54, 56, 33, 58, + 64, 16, 64, 72, -2, 71, 80, -18, 78, 89, -34, 85, + 45, 69, 50, 47, 63, 52, 51, 52, 55, 57, 36, 60, + 65, 19, 66, 73, 2, 72, 81, -15, 78, 90, -31, 85, + 47, 71, 52, 49, 66, 54, 53, 54, 57, 59, 40, 61, + 66, 22, 67, 73, 5, 73, 82, -11, 79, 90, -27, 86, + 48, 73, 54, 50, 68, 56, 54, 57, 59, 60, 43, 63, + 67, 26, 68, 74, 9, 74, 82, -8, 80, 91, -24, 87, + 50, 76, 56, 52, 70, 58, 56, 60, 60, 61, 46, 64, + 68, 30, 69, 75, 13, 75, 83, -4, 81, 92, -20, 88, + 52, 78, 58, 54, 72, 60, 57, 63, 62, 62, 49, 66, + 69, 33, 70, 76, 16, 76, 84, -1, 82, 92, -17, 88, + 54, 79, 60, 55, 75, 61, 59, 65, 64, 64, 52, 67, + 70, 36, 72, 77, 19, 77, 85, 3, 83, 93, -14, 89, + 3, 2, -14, 15, -19, 4, 28, -32, 20, 40, -44, 34, + 51, -54, 46, 62, -63, 56, 72, -72, 66, 83, -81, 75, + 4, 4, -14, 16, -17, 4, 28, -31, 20, 40, -43, 34, + 51, -54, 46, 62, -63, 56, 72, -72, 66, 83, -81, 75, + 4, 7, -13, 16, -15, 5, 28, -30, 21, 40, -42, 34, + 51, -53, 46, 62, -63, 56, 72, -72, 66, 83, -81, 75, + 5, 10, -11, 16, -11, 5, 28, -28, 21, 40, -41, 34, + 51, -52, 46, 62, -62, 57, 73, -71, 66, 83, -80, 75, + 6, 15, -10, 17, -8, 6, 29, -26, 21, 40, -39, 35, + 52, -51, 46, 62, -61, 57, 73, -70, 66, 83, -80, 75, + 8, 18, -8, 18, -4, 7, 29, -23, 22, 40, -37, 35, + 52, -49, 47, 62, -60, 57, 73, -70, 66, 83, -79, 76, + 9, 21, -5, 19, -1, 8, 30, -20, 23, 41, -35, 35, + 52, -48, 47, 63, -59, 57, 73, -69, 66, 83, -78, 76, + 11, 25, -2, 20, 4, 10, 30, -16, 23, 41, -32, 36, + 52, -45, 47, 63, -57, 57, 73, -67, 67, 83, -77, 76, + 13, 28, 1, 21, 8, 12, 31, -12, 24, 42, -29, 36, + 53, -43, 48, 63, -55, 58, 73, -66, 67, 83, -76, 76, + 15, 30, 3, 22, 12, 13, 32, -9, 25, 42, -26, 37, + 53, -41, 48, 63, -53, 58, 73, -64, 67, 84, -74, 76, + 16, 33, 6, 23, 16, 15, 32, -5, 26, 43, -22, 38, + 53, -38, 49, 63, -51, 58, 74, -62, 67, 84, -73, 76, + 18, 35, 9, 24, 19, 17, 33, -1, 28, 43, -19, 39, + 54, -35, 49, 64, -48, 59, 74, -60, 68, 84, -71, 77, + 20, 38, 12, 26, 23, 19, 34, 4, 29, 44, -15, 39, + 54, -32, 50, 64, -46, 59, 74, -58, 68, 84, -69, 77, + 22, 41, 15, 27, 27, 21, 35, 8, 30, 44, -11, 40, + 55, -28, 50, 65, -43, 60, 74, -55, 69, 84, -67, 77, + 24, 43, 17, 28, 30, 23, 36, 11, 32, 45, -7, 41, + 55, -25, 51, 65, -40, 60, 75, -53, 69, 85, -65, 78, + 26, 45, 20, 30, 33, 25, 37, 15, 33, 46, -4, 42, + 56, -22, 52, 65, -37, 61, 75, -50, 69, 85, -63, 78, + 28, 48, 23, 32, 37, 27, 38, 19, 35, 47, 1, 44, + 56, -18, 53, 66, -33, 61, 76, -47, 70, 85, -60, 78, + 29, 50, 25, 33, 40, 30, 40, 23, 37, 48, 4, 45, + 57, -14, 54, 66, -30, 62, 76, -44, 70, 86, -58, 79, + 31, 52, 28, 35, 42, 32, 41, 26, 38, 49, 8, 46, + 58, -10, 54, 67, -27, 63, 76, -41, 71, 86, -55, 79, + 33, 54, 30, 36, 45, 34, 42, 30, 40, 50, 12, 47, + 59, -7, 55, 68, -23, 64, 77, -38, 72, 86, -52, 80, + 35, 57, 33, 38, 48, 36, 43, 34, 42, 51, 16, 49, + 59, -3, 57, 68, -19, 64, 77, -35, 72, 87, -49, 80, + 36, 59, 35, 39, 51, 38, 45, 37, 43, 52, 19, 50, + 60, 1, 58, 69, -16, 65, 78, -32, 73, 87, -46, 81, + 38, 61, 38, 41, 53, 40, 46, 40, 45, 53, 23, 51, + 61, 5, 59, 70, -12, 66, 79, -28, 74, 88, -43, 81, + 40, 63, 40, 42, 56, 42, 47, 43, 47, 54, 26, 53, + 62, 8, 60, 70, -9, 67, 79, -25, 74, 88, -40, 82, + 42, 65, 42, 44, 58, 44, 49, 46, 48, 55, 30, 54, + 63, 12, 61, 71, -5, 68, 80, -22, 75, 89, -37, 83, + 43, 68, 44, 46, 61, 46, 50, 49, 50, 56, 33, 56, + 64, 16, 62, 72, -1, 69, 80, -18, 76, 89, -34, 83, + 45, 70, 47, 47, 63, 48, 52, 52, 52, 57, 37, 57, + 65, 19, 63, 73, 2, 70, 81, -14, 77, 90, -30, 84, + 47, 72, 49, 49, 66, 50, 53, 55, 54, 59, 40, 59, + 66, 23, 64, 73, 6, 71, 82, -11, 78, 90, -27, 85, + 49, 74, 51, 50, 68, 52, 54, 57, 55, 60, 43, 60, + 67, 26, 66, 74, 9, 72, 82, -8, 78, 91, -24, 85, + 50, 76, 53, 52, 70, 54, 56, 60, 57, 61, 46, 62, + 68, 30, 67, 75, 13, 73, 83, -4, 79, 92, -20, 86, + 52, 78, 55, 54, 73, 56, 57, 63, 59, 62, 49, 63, + 69, 33, 68, 76, 16, 74, 84, 0, 80, 92, -17, 87, + 54, 80, 57, 55, 75, 58, 59, 65, 61, 64, 52, 65, + 70, 36, 70, 77, 20, 75, 85, 3, 81, 93, -13, 88, + 4, 5, -20, 16, -16, -2, 28, -31, 16, 40, -43, 30, + 51, -53, 43, 62, -63, 54, 72, -72, 64, 83, -81, 74, + 4, 7, -19, 16, -14, -1, 28, -30, 16, 40, -42, 30, + 51, -53, 43, 62, -63, 54, 72, -72, 64, 83, -81, 74, + 5, 10, -18, 16, -12, -1, 28, -28, 16, 40, -41, 30, + 51, -52, 43, 62, -62, 54, 73, -71, 64, 83, -80, 74, + 6, 14, -17, 17, -9, 0, 29, -27, 16, 40, -40, 30, + 52, -51, 43, 62, -61, 54, 73, -71, 64, 83, -80, 74, + 7, 17, -15, 17, -6, 1, 29, -24, 17, 40, -38, 31, + 52, -50, 43, 62, -60, 54, 73, -70, 64, 83, -79, 74, + 8, 20, -13, 18, -3, 2, 29, -22, 17, 41, -36, 31, + 52, -49, 44, 62, -59, 54, 73, -69, 64, 83, -79, 74, + 10, 23, -10, 19, 1, 3, 30, -19, 18, 41, -34, 32, + 52, -47, 44, 63, -58, 55, 73, -68, 64, 83, -78, 74, + 11, 26, -7, 20, 5, 5, 30, -15, 19, 41, -31, 32, + 52, -45, 44, 63, -56, 55, 73, -67, 65, 83, -77, 74, + 13, 29, -5, 21, 9, 6, 31, -11, 20, 42, -28, 33, + 53, -43, 45, 63, -55, 55, 73, -65, 65, 83, -76, 74, + 15, 31, -2, 22, 13, 8, 32, -8, 21, 42, -25, 33, + 53, -40, 45, 63, -53, 55, 73, -64, 65, 84, -74, 74, + 17, 34, 1, 23, 16, 10, 32, -4, 22, 43, -22, 34, + 53, -37, 46, 64, -50, 56, 74, -62, 65, 84, -73, 75, + 18, 36, 4, 24, 20, 12, 33, 0, 23, 43, -18, 35, + 54, -35, 46, 64, -48, 56, 74, -60, 66, 84, -71, 75, + 20, 39, 7, 26, 24, 14, 34, 4, 25, 44, -14, 36, + 54, -31, 47, 64, -45, 57, 74, -57, 66, 84, -69, 75, + 22, 41, 9, 27, 27, 16, 35, 8, 26, 45, -11, 37, + 55, -28, 47, 65, -42, 57, 74, -55, 66, 84, -67, 76, + 24, 43, 12, 29, 31, 18, 36, 12, 27, 45, -7, 38, + 55, -25, 48, 65, -39, 58, 75, -53, 67, 85, -65, 76, + 26, 46, 15, 30, 34, 20, 37, 16, 29, 46, -3, 39, + 56, -21, 49, 65, -36, 58, 75, -50, 67, 85, -63, 76, + 28, 48, 18, 32, 37, 23, 39, 20, 31, 47, 1, 40, + 56, -17, 50, 66, -33, 59, 76, -47, 68, 85, -60, 77, + 29, 50, 20, 33, 40, 25, 40, 23, 32, 48, 5, 41, + 57, -14, 51, 67, -30, 60, 76, -44, 68, 86, -57, 77, + 31, 53, 23, 35, 43, 27, 41, 27, 34, 49, 8, 42, + 58, -10, 52, 67, -26, 60, 76, -41, 69, 86, -55, 78, + 33, 55, 25, 36, 46, 29, 42, 30, 36, 50, 12, 44, + 59, -6, 53, 68, -23, 61, 77, -38, 70, 86, -52, 78, + 35, 57, 28, 38, 49, 32, 43, 34, 38, 51, 16, 45, + 59, -2, 54, 68, -19, 62, 77, -35, 70, 87, -49, 79, + 37, 59, 31, 39, 51, 34, 45, 37, 39, 52, 20, 47, + 60, 1, 55, 69, -16, 63, 78, -31, 71, 87, -46, 79, + 38, 61, 33, 41, 54, 36, 46, 40, 41, 53, 23, 48, + 61, 5, 56, 70, -12, 64, 79, -28, 72, 88, -43, 80, + 40, 63, 35, 43, 56, 38, 47, 43, 43, 54, 27, 49, + 62, 8, 57, 70, -9, 65, 79, -25, 72, 88, -40, 80, + 42, 65, 38, 44, 59, 40, 49, 46, 45, 55, 30, 51, + 63, 12, 58, 71, -5, 66, 80, -21, 73, 89, -37, 81, + 44, 68, 40, 46, 61, 42, 50, 49, 47, 56, 34, 52, + 64, 16, 59, 72, -1, 67, 80, -18, 74, 89, -33, 82, + 45, 70, 42, 47, 64, 44, 52, 52, 48, 57, 37, 54, + 65, 19, 61, 73, 2, 68, 81, -14, 75, 90, -30, 82, + 47, 72, 45, 49, 66, 46, 53, 55, 50, 59, 40, 55, + 66, 23, 62, 74, 6, 69, 82, -11, 76, 91, -27, 83, + 49, 74, 47, 51, 68, 49, 54, 58, 52, 60, 43, 57, + 67, 26, 63, 74, 9, 70, 82, -7, 77, 91, -24, 84, + 50, 76, 49, 52, 71, 51, 56, 60, 54, 61, 47, 59, + 68, 30, 65, 75, 13, 71, 83, -4, 78, 92, -20, 85, + 52, 78, 51, 54, 73, 53, 57, 63, 56, 62, 50, 60, + 69, 33, 66, 76, 16, 72, 84, 0, 79, 92, -17, 86, + 54, 80, 53, 55, 75, 55, 59, 66, 58, 64, 52, 62, + 70, 36, 67, 77, 20, 73, 85, 3, 79, 93, -13, 86, + 4, 9, -25, 16, -13, -7, 28, -29, 11, 40, -41, 26, + 51, -52, 39, 62, -62, 51, 72, -71, 61, 83, -81, 71, + 5, 11, -24, 16, -11, -6, 28, -28, 11, 40, -41, 26, + 51, -52, 39, 62, -62, 51, 73, -71, 62, 83, -80, 72, + 5, 14, -23, 17, -9, -6, 28, -27, 11, 40, -40, 26, + 51, -51, 40, 62, -61, 51, 73, -71, 62, 83, -80, 72, + 6, 17, -22, 17, -7, -5, 29, -25, 12, 40, -39, 26, + 52, -50, 40, 62, -61, 51, 73, -70, 62, 83, -80, 72, + 7, 20, -20, 18, -4, -4, 29, -23, 12, 40, -37, 27, + 52, -49, 40, 62, -60, 51, 73, -70, 62, 83, -79, 72, + 9, 22, -18, 18, -1, -3, 29, -20, 13, 41, -35, 27, + 52, -48, 40, 62, -59, 52, 73, -69, 62, 83, -78, 72, + 10, 24, -16, 19, 3, -2, 30, -17, 13, 41, -33, 27, + 52, -46, 40, 63, -57, 52, 73, -68, 62, 83, -77, 72, + 12, 27, -13, 20, 7, 0, 30, -14, 14, 41, -30, 28, + 52, -44, 41, 63, -56, 52, 73, -66, 62, 83, -76, 72, + 13, 30, -10, 21, 10, 1, 31, -10, 15, 42, -27, 29, + 53, -42, 41, 63, -54, 52, 73, -65, 62, 84, -75, 72, + 15, 32, -7, 22, 14, 3, 32, -6, 16, 42, -24, 29, + 53, -39, 42, 63, -52, 53, 73, -63, 63, 84, -74, 72, + 17, 35, -5, 23, 18, 5, 33, -3, 17, 43, -21, 30, + 53, -37, 42, 64, -50, 53, 74, -61, 63, 84, -72, 73, + 19, 37, -2, 25, 21, 7, 33, 1, 19, 43, -18, 31, + 54, -34, 43, 64, -47, 53, 74, -59, 63, 84, -71, 73, + 21, 40, 1, 26, 25, 9, 34, 5, 20, 44, -14, 32, + 54, -30, 43, 64, -45, 54, 74, -57, 64, 84, -69, 73, + 22, 42, 4, 27, 28, 11, 35, 9, 22, 45, -10, 33, + 55, -27, 44, 65, -42, 54, 75, -55, 64, 85, -67, 74, + 24, 44, 7, 29, 31, 13, 36, 13, 23, 45, -6, 34, + 55, -24, 45, 65, -39, 55, 75, -52, 65, 85, -65, 74, + 26, 46, 10, 30, 34, 15, 37, 16, 25, 46, -3, 35, + 56, -21, 46, 66, -36, 56, 75, -50, 65, 85, -62, 74, + 28, 49, 13, 32, 38, 18, 39, 20, 26, 47, 2, 36, + 57, -17, 47, 66, -32, 56, 76, -47, 66, 85, -60, 75, + 30, 51, 15, 33, 40, 20, 40, 24, 28, 48, 5, 37, + 57, -13, 47, 67, -29, 57, 76, -44, 66, 86, -57, 75, + 31, 53, 18, 35, 43, 22, 41, 27, 30, 49, 9, 39, + 58, -10, 48, 67, -26, 58, 76, -41, 67, 86, -55, 76, + 33, 55, 20, 36, 46, 24, 42, 31, 31, 50, 13, 40, + 59, -6, 49, 68, -23, 58, 77, -38, 67, 87, -52, 76, + 35, 58, 23, 38, 49, 27, 44, 34, 33, 51, 17, 42, + 59, -2, 51, 68, -19, 59, 77, -34, 68, 87, -49, 77, + 37, 60, 26, 40, 51, 29, 45, 37, 35, 52, 20, 43, + 60, 2, 52, 69, -15, 60, 78, -31, 69, 87, -46, 77, + 38, 62, 28, 41, 54, 31, 46, 40, 37, 53, 24, 44, + 61, 5, 53, 70, -12, 61, 79, -28, 69, 88, -43, 78, + 40, 64, 31, 43, 56, 33, 47, 43, 39, 54, 27, 46, + 62, 9, 54, 70, -8, 62, 79, -24, 70, 88, -40, 78, + 42, 66, 33, 44, 59, 36, 49, 46, 41, 55, 30, 47, + 63, 12, 55, 71, -5, 63, 80, -21, 71, 89, -37, 79, + 44, 68, 36, 46, 62, 38, 50, 50, 43, 56, 34, 49, + 64, 16, 56, 72, -1, 64, 80, -17, 72, 89, -33, 80, + 45, 70, 38, 47, 64, 40, 52, 52, 45, 58, 37, 50, + 65, 20, 58, 73, 3, 65, 81, -14, 73, 90, -30, 81, + 47, 72, 40, 49, 66, 42, 53, 55, 46, 59, 40, 52, + 66, 23, 59, 74, 6, 66, 82, -11, 74, 91, -27, 81, + 49, 74, 42, 51, 68, 44, 54, 58, 48, 60, 43, 54, + 67, 26, 60, 74, 9, 67, 82, -7, 74, 91, -23, 82, + 50, 76, 45, 52, 71, 47, 56, 61, 50, 61, 47, 55, + 68, 30, 62, 75, 13, 68, 83, -3, 75, 92, -20, 83, + 52, 78, 47, 54, 73, 49, 57, 63, 52, 62, 50, 57, + 69, 33, 63, 76, 17, 70, 84, 0, 76, 92, -16, 84, + 54, 80, 49, 55, 75, 51, 59, 66, 54, 64, 53, 59, + 70, 37, 64, 77, 20, 71, 85, 3, 77, 93, -13, 85, + 5, 14, -30, 16, -9, -12, 28, -26, 5, 40, -40, 21, + 51, -51, 35, 62, -61, 47, 73, -71, 58, 83, -80, 69, + 6, 16, -30, 17, -7, -12, 29, -25, 6, 40, -39, 21, + 51, -51, 35, 62, -61, 47, 73, -70, 58, 83, -80, 69, + 6, 18, -29, 17, -6, -12, 29, -24, 6, 40, -38, 21, + 52, -50, 35, 62, -61, 48, 73, -70, 59, 83, -79, 69, + 7, 20, -27, 17, -4, -11, 29, -23, 6, 40, -37, 22, + 52, -49, 36, 62, -60, 48, 73, -70, 59, 83, -79, 69, + 8, 22, -26, 18, -1, -10, 29, -20, 7, 41, -35, 22, + 52, -48, 36, 62, -59, 48, 73, -69, 59, 83, -78, 69, + 9, 24, -23, 19, 2, -9, 30, -18, 7, 41, -34, 22, + 52, -47, 36, 63, -58, 48, 73, -68, 59, 83, -78, 69, + 11, 27, -21, 19, 5, -8, 30, -15, 8, 41, -31, 23, + 52, -45, 36, 63, -57, 48, 73, -67, 59, 83, -77, 69, + 12, 29, -18, 20, 9, -6, 31, -12, 9, 41, -29, 23, + 52, -43, 37, 63, -55, 48, 73, -66, 59, 83, -76, 70, + 14, 31, -16, 21, 12, -4, 31, -8, 10, 42, -26, 24, + 53, -41, 37, 63, -53, 49, 73, -64, 59, 84, -75, 70, + 16, 33, -13, 22, 16, -3, 32, -5, 11, 42, -23, 25, + 53, -38, 38, 63, -51, 49, 73, -63, 60, 84, -73, 70, + 17, 36, -10, 24, 19, -1, 33, -1, 12, 43, -20, 25, + 53, -36, 38, 64, -49, 49, 74, -61, 60, 84, -72, 70, + 19, 38, -8, 25, 22, 1, 34, 2, 13, 43, -16, 26, + 54, -33, 39, 64, -47, 50, 74, -59, 60, 84, -70, 70, + 21, 40, -5, 26, 26, 3, 35, 6, 15, 44, -13, 27, + 54, -30, 39, 64, -44, 50, 74, -56, 61, 84, -68, 71, + 23, 43, -2, 28, 29, 5, 35, 10, 16, 45, -9, 28, + 55, -26, 40, 65, -41, 51, 75, -54, 61, 85, -66, 71, + 24, 45, 1, 29, 32, 8, 36, 14, 18, 45, -5, 29, + 55, -23, 41, 65, -38, 52, 75, -52, 62, 85, -64, 71, + 26, 47, 4, 30, 35, 10, 38, 17, 19, 46, -2, 30, + 56, -20, 42, 66, -35, 52, 75, -49, 62, 85, -62, 72, + 28, 49, 7, 32, 38, 12, 39, 21, 21, 47, 2, 32, + 57, -16, 43, 66, -32, 53, 76, -46, 63, 85, -59, 72, + 30, 52, 9, 33, 41, 14, 40, 25, 23, 48, 6, 33, + 57, -12, 43, 67, -29, 54, 76, -43, 63, 86, -57, 73, + 31, 54, 12, 35, 44, 17, 41, 28, 25, 49, 10, 34, + 58, -9, 44, 67, -25, 54, 77, -40, 64, 86, -54, 73, + 33, 56, 15, 36, 47, 19, 42, 31, 26, 50, 13, 35, + 59, -5, 45, 68, -22, 55, 77, -37, 64, 87, -51, 74, + 35, 58, 18, 38, 49, 21, 44, 35, 28, 51, 17, 37, + 60, -1, 47, 68, -18, 56, 78, -34, 65, 87, -48, 74, + 37, 60, 20, 40, 52, 24, 45, 38, 30, 52, 21, 38, + 60, 2, 48, 69, -15, 57, 78, -31, 66, 87, -45, 75, + 39, 62, 23, 41, 54, 26, 46, 41, 32, 53, 24, 40, + 61, 6, 49, 70, -11, 58, 79, -27, 67, 88, -42, 75, + 40, 64, 25, 43, 57, 28, 48, 44, 34, 54, 27, 41, + 62, 9, 50, 70, -8, 59, 79, -24, 67, 88, -39, 76, + 42, 66, 28, 44, 59, 30, 49, 47, 36, 55, 31, 43, + 63, 13, 51, 71, -4, 60, 80, -21, 68, 89, -36, 77, + 44, 68, 30, 46, 62, 33, 50, 50, 38, 56, 34, 45, + 64, 17, 53, 72, -1, 61, 80, -17, 69, 89, -33, 77, + 45, 70, 33, 48, 64, 35, 52, 53, 40, 58, 38, 46, + 65, 20, 54, 73, 3, 62, 81, -14, 70, 90, -30, 78, + 47, 72, 35, 49, 66, 37, 53, 55, 42, 59, 41, 48, + 66, 23, 55, 74, 6, 63, 82, -10, 71, 91, -26, 79, + 49, 74, 37, 51, 69, 39, 54, 58, 44, 60, 44, 49, + 67, 27, 57, 74, 10, 64, 83, -7, 72, 91, -23, 80, + 51, 76, 40, 52, 71, 42, 56, 61, 46, 61, 47, 51, + 68, 30, 58, 75, 14, 65, 83, -3, 73, 92, -19, 80, + 52, 78, 42, 54, 73, 44, 57, 64, 48, 63, 50, 53, + 69, 34, 59, 76, 17, 66, 84, 0, 74, 92, -16, 81, + 54, 80, 44, 56, 75, 46, 59, 66, 50, 64, 53, 55, + 70, 37, 61, 77, 20, 68, 85, 4, 75, 93, -13, 82, + 6, 19, -35, 17, -5, -17, 29, -24, 1, 40, -38, 17, + 52, -50, 31, 62, -60, 44, 73, -70, 55, 83, -79, 66, + 6, 20, -34, 17, -4, -17, 29, -23, 1, 40, -37, 17, + 52, -50, 31, 62, -60, 44, 73, -70, 55, 83, -79, 66, + 7, 22, -33, 17, -3, -16, 29, -22, 1, 40, -37, 17, + 52, -49, 31, 62, -60, 44, 73, -69, 56, 83, -79, 66, + 8, 23, -32, 18, -1, -16, 29, -20, 1, 40, -35, 17, + 52, -48, 32, 62, -59, 44, 73, -69, 56, 83, -78, 66, + 9, 25, -30, 18, 2, -15, 29, -18, 2, 41, -34, 17, + 52, -47, 32, 62, -58, 44, 73, -68, 56, 83, -78, 67, + 10, 27, -28, 19, 4, -14, 30, -16, 2, 41, -32, 18, + 52, -46, 32, 63, -57, 45, 73, -67, 56, 83, -77, 67, + 11, 28, -26, 20, 7, -13, 30, -13, 3, 41, -30, 18, + 52, -44, 32, 63, -56, 45, 73, -66, 56, 83, -76, 67, + 13, 31, -23, 21, 11, -11, 31, -10, 4, 42, -27, 19, + 53, -42, 33, 63, -54, 45, 73, -65, 56, 83, -75, 67, + 14, 33, -21, 22, 14, -9, 31, -7, 5, 42, -25, 19, + 53, -40, 33, 63, -52, 45, 73, -63, 56, 84, -74, 67, + 16, 35, -18, 23, 17, -8, 32, -4, 6, 42, -22, 20, + 53, -37, 34, 63, -50, 46, 74, -62, 57, 84, -73, 67, + 18, 37, -15, 24, 20, -6, 33, 0, 7, 43, -19, 21, + 54, -35, 34, 64, -48, 46, 74, -60, 57, 84, -71, 68, + 19, 39, -13, 25, 24, -4, 34, 3, 9, 44, -15, 22, + 54, -32, 35, 64, -46, 46, 74, -58, 57, 84, -70, 68, + 21, 41, -10, 27, 27, -2, 35, 7, 10, 44, -12, 23, + 54, -29, 35, 64, -43, 47, 74, -56, 58, 84, -68, 68, + 23, 44, -7, 28, 30, 0, 36, 11, 12, 45, -8, 24, + 55, -26, 36, 65, -40, 48, 75, -54, 58, 85, -66, 68, + 25, 46, -4, 29, 33, 3, 37, 15, 13, 46, -4, 25, + 55, -22, 37, 65, -38, 48, 75, -51, 59, 85, -64, 69, + 26, 48, -1, 31, 36, 5, 38, 18, 15, 46, -1, 26, + 56, -19, 38, 66, -35, 49, 75, -49, 59, 85, -61, 69, + 28, 50, 2, 32, 39, 7, 39, 22, 16, 47, 3, 27, + 57, -15, 39, 66, -31, 50, 76, -45, 60, 86, -59, 70, + 30, 52, 4, 34, 42, 10, 40, 25, 18, 48, 7, 29, + 57, -12, 40, 67, -28, 50, 76, -43, 60, 86, -56, 70, + 32, 54, 7, 35, 44, 12, 41, 29, 20, 49, 10, 30, + 58, -8, 41, 67, -25, 51, 77, -40, 61, 86, -54, 71, + 33, 56, 10, 37, 47, 14, 42, 32, 22, 50, 14, 31, + 59, -5, 42, 68, -22, 52, 77, -37, 61, 87, -51, 71, + 35, 58, 13, 38, 50, 17, 44, 35, 24, 51, 18, 33, + 60, -1, 43, 69, -18, 53, 78, -33, 62, 87, -48, 72, + 37, 61, 15, 40, 52, 19, 45, 38, 26, 52, 21, 34, + 60, 3, 44, 69, -14, 54, 78, -30, 63, 87, -45, 72, + 39, 63, 18, 41, 55, 21, 46, 41, 28, 53, 25, 36, + 61, 6, 45, 70, -11, 54, 79, -27, 64, 88, -42, 73, + 40, 64, 20, 43, 57, 23, 48, 44, 29, 54, 28, 37, + 62, 10, 46, 71, -7, 55, 79, -24, 64, 88, -39, 74, + 42, 66, 23, 44, 60, 26, 49, 47, 31, 55, 31, 39, + 63, 13, 48, 71, -4, 56, 80, -20, 65, 89, -36, 74, + 44, 69, 25, 46, 62, 28, 50, 50, 34, 57, 35, 41, + 64, 17, 49, 72, 0, 58, 81, -17, 66, 90, -32, 75, + 46, 71, 28, 48, 65, 31, 52, 53, 35, 58, 38, 42, + 65, 20, 50, 73, 3, 59, 81, -13, 67, 90, -29, 76, + 47, 73, 30, 49, 67, 33, 53, 56, 37, 59, 41, 44, + 66, 24, 52, 74, 7, 60, 82, -10, 68, 91, -26, 76, + 49, 74, 33, 51, 69, 35, 55, 58, 39, 60, 44, 46, + 67, 27, 53, 75, 10, 61, 83, -6, 69, 91, -23, 77, + 51, 77, 35, 53, 71, 37, 56, 61, 42, 61, 47, 47, + 68, 31, 55, 75, 14, 62, 83, -3, 70, 92, -19, 78, + 52, 79, 38, 54, 74, 40, 58, 64, 44, 63, 50, 49, + 69, 34, 56, 76, 17, 63, 84, 1, 71, 93, -16, 79, + 54, 80, 40, 56, 76, 42, 59, 66, 45, 64, 53, 51, + 70, 37, 57, 77, 21, 64, 85, 4, 72, 93, -13, 80, + 7, 23, -39, 17, -2, -22, 29, -21, -4, 40, -36, 12, + 52, -49, 27, 62, -59, 40, 73, -69, 52, 83, -79, 63, + 7, 24, -38, 18, -1, -22, 29, -20, -4, 40, -35, 12, + 52, -48, 27, 62, -59, 40, 73, -69, 52, 83, -78, 64, + 8, 25, -37, 18, 1, -21, 29, -19, -4, 40, -35, 12, + 52, -48, 27, 62, -59, 40, 73, -69, 52, 83, -78, 64, + 9, 26, -36, 18, 2, -20, 29, -18, -3, 41, -33, 13, + 52, -47, 28, 62, -58, 41, 73, -68, 52, 83, -78, 64, + 10, 27, -34, 19, 5, -20, 30, -16, -3, 41, -32, 13, + 52, -46, 28, 63, -57, 41, 73, -67, 53, 83, -77, 64, + 11, 29, -32, 19, 7, -19, 30, -14, -2, 41, -30, 13, + 52, -44, 28, 63, -56, 41, 73, -66, 53, 83, -76, 64, + 12, 31, -30, 20, 10, -17, 31, -11, -2, 41, -28, 14, + 52, -43, 28, 63, -55, 41, 73, -65, 53, 83, -76, 64, + 14, 32, -28, 21, 13, -16, 31, -8, -1, 42, -26, 14, + 53, -41, 29, 63, -53, 41, 73, -64, 53, 84, -75, 64, + 15, 34, -25, 22, 16, -14, 32, -5, 0, 42, -23, 15, + 53, -39, 29, 63, -51, 42, 73, -63, 53, 84, -73, 64, + 17, 36, -23, 23, 19, -13, 32, -2, 1, 43, -20, 16, + 53, -36, 30, 64, -49, 42, 74, -61, 54, 84, -72, 65, + 18, 38, -20, 24, 22, -11, 33, 1, 3, 43, -17, 16, + 54, -34, 30, 64, -47, 42, 74, -59, 54, 84, -71, 65, + 20, 40, -17, 25, 25, -9, 34, 5, 4, 44, -14, 17, + 54, -31, 31, 64, -45, 43, 74, -57, 54, 84, -69, 65, + 22, 42, -14, 27, 28, -7, 35, 9, 5, 44, -10, 18, + 55, -28, 31, 64, -42, 43, 74, -55, 55, 84, -67, 65, + 23, 44, -12, 28, 31, -4, 36, 12, 7, 45, -7, 19, + 55, -25, 32, 65, -40, 44, 75, -53, 55, 85, -65, 66, + 25, 47, -9, 29, 34, -2, 37, 16, 8, 46, -3, 20, + 56, -21, 33, 65, -37, 45, 75, -50, 55, 85, -63, 66, + 27, 49, -6, 31, 37, 0, 38, 19, 10, 47, 0, 22, + 56, -18, 34, 66, -34, 45, 75, -48, 56, 85, -61, 66, + 29, 51, -3, 32, 40, 2, 39, 23, 12, 47, 4, 23, + 57, -14, 35, 66, -30, 46, 76, -45, 57, 86, -58, 67, + 30, 53, -1, 34, 43, 5, 40, 26, 13, 48, 8, 24, + 57, -11, 36, 67, -27, 47, 76, -42, 57, 86, -56, 67, + 32, 55, 2, 35, 45, 7, 41, 29, 15, 49, 11, 26, + 58, -8, 37, 67, -24, 47, 77, -39, 58, 86, -53, 68, + 34, 57, 5, 37, 48, 9, 43, 33, 17, 50, 15, 27, + 59, -4, 38, 68, -21, 48, 77, -36, 58, 87, -50, 68, + 36, 59, 8, 38, 51, 12, 44, 36, 19, 51, 18, 29, + 60, 0, 39, 69, -17, 49, 78, -33, 59, 87, -47, 69, + 37, 61, 10, 40, 53, 14, 45, 39, 21, 52, 22, 30, + 61, 3, 40, 69, -14, 50, 78, -30, 60, 88, -44, 70, + 39, 63, 13, 42, 55, 16, 46, 42, 23, 53, 25, 32, + 61, 7, 41, 70, -10, 51, 79, -26, 61, 88, -42, 70, + 41, 65, 15, 43, 58, 19, 48, 45, 25, 54, 28, 33, + 62, 10, 43, 71, -7, 52, 79, -23, 61, 88, -39, 71, + 42, 67, 18, 45, 60, 21, 49, 48, 27, 55, 32, 35, + 63, 14, 44, 71, -4, 53, 80, -20, 62, 89, -35, 71, + 44, 69, 21, 46, 63, 24, 51, 51, 29, 57, 35, 36, + 64, 18, 45, 72, 0, 54, 81, -16, 63, 90, -32, 72, + 46, 71, 23, 48, 65, 26, 52, 54, 31, 58, 38, 38, + 65, 21, 47, 73, 4, 55, 81, -13, 64, 90, -29, 73, + 47, 73, 26, 49, 67, 28, 53, 56, 33, 59, 42, 40, + 66, 24, 48, 74, 7, 56, 82, -9, 65, 91, -26, 74, + 49, 75, 28, 51, 69, 30, 55, 59, 35, 60, 45, 41, + 67, 28, 49, 75, 11, 57, 83, -6, 66, 91, -22, 75, + 51, 77, 31, 53, 72, 33, 56, 62, 37, 61, 48, 43, + 68, 31, 51, 76, 14, 59, 83, -2, 67, 92, -19, 75, + 52, 79, 33, 54, 74, 35, 58, 64, 39, 63, 51, 45, + 69, 34, 52, 76, 18, 60, 84, 1, 68, 93, -15, 76, + 54, 81, 35, 56, 76, 37, 59, 67, 41, 64, 54, 47, + 70, 38, 54, 77, 21, 61, 85, 4, 69, 93, -12, 77, + 8, 27, -43, 18, 2, -27, 29, -18, -9, 40, -34, 8, + 52, -47, 23, 62, -58, 37, 73, -68, 49, 83, -78, 60, + 8, 27, -42, 18, 3, -26, 29, -18, -9, 41, -33, 8, + 52, -47, 23, 62, -58, 37, 73, -68, 49, 83, -78, 61, + 9, 28, -41, 18, 4, -26, 29, -17, -8, 41, -33, 8, + 52, -46, 23, 63, -57, 37, 73, -68, 49, 83, -77, 61, + 10, 29, -40, 19, 6, -25, 30, -15, -8, 41, -31, 8, + 52, -45, 23, 63, -57, 37, 73, -67, 49, 83, -77, 61, + 11, 30, -38, 19, 8, -24, 30, -13, -8, 41, -30, 8, + 52, -44, 24, 63, -56, 37, 73, -66, 49, 83, -76, 61, + 12, 31, -37, 20, 10, -23, 30, -11, -7, 41, -28, 9, + 52, -43, 24, 63, -55, 37, 73, -66, 49, 83, -76, 61, + 13, 33, -35, 21, 12, -22, 31, -9, -6, 42, -27, 9, + 53, -41, 24, 63, -54, 37, 73, -65, 49, 83, -75, 61, + 14, 34, -32, 22, 15, -20, 31, -6, -5, 42, -24, 10, + 53, -39, 25, 63, -52, 38, 73, -63, 50, 84, -74, 61, + 16, 36, -30, 22, 18, -19, 32, -3, -4, 42, -21, 10, + 53, -37, 25, 63, -50, 38, 73, -62, 50, 84, -73, 61, + 17, 38, -27, 23, 21, -17, 33, 0, -3, 43, -19, 11, + 53, -35, 25, 64, -48, 38, 74, -60, 50, 84, -71, 62, + 19, 40, -25, 25, 24, -16, 33, 3, -2, 43, -16, 12, + 54, -32, 26, 64, -46, 39, 74, -59, 50, 84, -70, 62, + 20, 41, -22, 26, 26, -14, 34, 6, -1, 44, -13, 13, + 54, -30, 27, 64, -44, 39, 74, -57, 51, 84, -68, 62, + 22, 44, -19, 27, 30, -11, 35, 10, 1, 45, -9, 14, + 55, -27, 27, 65, -41, 40, 74, -54, 51, 84, -66, 62, + 24, 46, -17, 28, 32, -9, 36, 13, 2, 45, -6, 15, + 55, -24, 28, 65, -39, 40, 75, -52, 52, 85, -64, 63, + 25, 47, -14, 30, 35, -7, 37, 17, 4, 46, -2, 16, + 56, -20, 29, 65, -36, 41, 75, -50, 52, 85, -62, 63, + 27, 49, -11, 31, 38, -5, 38, 20, 5, 47, 1, 17, + 56, -17, 30, 66, -33, 41, 75, -47, 53, 85, -60, 63, + 29, 52, -8, 33, 41, -2, 39, 24, 7, 48, 5, 18, + 57, -14, 31, 66, -30, 42, 76, -44, 53, 86, -58, 64, + 31, 54, -6, 34, 43, 0, 40, 27, 9, 48, 8, 20, + 58, -10, 32, 67, -27, 43, 76, -41, 54, 86, -55, 64, + 32, 56, -3, 36, 46, 2, 42, 30, 11, 49, 12, 21, + 58, -7, 33, 67, -23, 44, 77, -38, 54, 86, -53, 65, + 34, 57, 0, 37, 48, 4, 43, 33, 12, 50, 15, 23, + 59, -3, 34, 68, -20, 45, 77, -36, 55, 87, -50, 65, + 36, 60, 3, 39, 51, 7, 44, 37, 15, 51, 19, 24, + 60, 1, 35, 69, -16, 46, 78, -32, 56, 87, -47, 66, + 37, 62, 5, 40, 54, 9, 45, 40, 16, 52, 23, 26, + 61, 4, 36, 69, -13, 46, 78, -29, 57, 88, -44, 67, + 39, 64, 8, 42, 56, 12, 47, 43, 18, 53, 26, 27, + 61, 7, 37, 70, -10, 47, 79, -26, 57, 88, -41, 67, + 41, 65, 11, 43, 58, 14, 48, 46, 20, 54, 29, 29, + 62, 11, 39, 71, -6, 48, 79, -23, 58, 89, -38, 68, + 42, 67, 13, 45, 61, 16, 49, 48, 22, 55, 32, 30, + 63, 14, 40, 71, -3, 49, 80, -19, 59, 89, -35, 69, + 44, 70, 16, 46, 63, 19, 51, 51, 25, 57, 36, 32, + 64, 18, 41, 72, 1, 51, 81, -16, 60, 90, -31, 69, + 46, 71, 18, 48, 65, 21, 52, 54, 27, 58, 39, 34, + 65, 21, 43, 73, 4, 52, 81, -12, 61, 90, -28, 70, + 47, 73, 21, 50, 68, 24, 53, 57, 29, 59, 42, 36, + 66, 25, 44, 74, 8, 53, 82, -9, 62, 91, -25, 71, + 49, 75, 23, 51, 70, 26, 55, 59, 31, 60, 45, 37, + 67, 28, 45, 75, 11, 54, 83, -6, 63, 91, -22, 72, + 51, 77, 26, 53, 72, 28, 56, 62, 33, 62, 48, 39, + 68, 32, 47, 76, 15, 55, 83, -2, 64, 92, -18, 73, + 53, 79, 28, 54, 74, 31, 58, 65, 35, 63, 51, 41, + 69, 35, 48, 76, 18, 56, 84, 1, 65, 93, -15, 73, + 54, 81, 31, 56, 76, 33, 59, 67, 37, 64, 54, 43, + 70, 38, 50, 77, 21, 58, 85, 5, 66, 93, -12, 74, + 9, 30, -46, 18, 6, -31, 30, -15, -14, 41, -32, 3, + 52, -45, 19, 63, -57, 33, 73, -67, 45, 83, -77, 57, + 9, 30, -46, 19, 7, -31, 30, -15, -13, 41, -31, 3, + 52, -45, 19, 63, -56, 33, 73, -67, 45, 83, -77, 57, + 10, 31, -45, 19, 8, -30, 30, -14, -13, 41, -30, 3, + 52, -44, 19, 63, -56, 33, 73, -67, 45, 83, -77, 57, + 11, 32, -44, 19, 9, -29, 30, -12, -13, 41, -29, 4, + 52, -44, 19, 63, -55, 33, 73, -66, 45, 83, -76, 57, + 11, 32, -42, 20, 11, -29, 30, -11, -12, 41, -28, 4, + 52, -43, 19, 63, -55, 33, 73, -65, 46, 83, -76, 58, + 12, 34, -41, 20, 13, -28, 31, -9, -12, 41, -26, 4, + 52, -41, 20, 63, -54, 33, 73, -65, 46, 83, -75, 58, + 14, 35, -39, 21, 15, -27, 31, -7, -11, 42, -25, 5, + 53, -40, 20, 63, -52, 33, 73, -64, 46, 84, -74, 58, + 15, 36, -36, 22, 17, -25, 32, -4, -10, 42, -22, 5, + 53, -38, 20, 63, -51, 34, 73, -62, 46, 84, -73, 58, + 16, 38, -34, 23, 20, -24, 32, -1, -9, 43, -20, 6, + 53, -36, 21, 63, -49, 34, 74, -61, 46, 84, -72, 58, + 18, 39, -32, 24, 23, -22, 33, 2, -8, 43, -17, 7, + 54, -34, 21, 64, -47, 34, 74, -59, 47, 84, -71, 58, + 19, 41, -29, 25, 25, -20, 34, 5, -7, 43, -14, 7, + 54, -31, 22, 64, -45, 35, 74, -58, 47, 84, -69, 59, + 21, 43, -27, 26, 28, -18, 34, 8, -6, 44, -11, 8, + 54, -28, 22, 64, -43, 35, 74, -56, 47, 84, -67, 59, + 22, 45, -24, 27, 31, -16, 35, 12, -4, 45, -8, 9, + 55, -25, 23, 65, -40, 36, 75, -53, 48, 85, -66, 59, + 24, 47, -21, 29, 34, -14, 36, 15, -3, 45, -4, 10, + 55, -22, 24, 65, -38, 36, 75, -51, 48, 85, -64, 60, + 26, 49, -19, 30, 36, -12, 37, 18, -1, 46, -1, 11, + 56, -19, 25, 65, -35, 37, 75, -49, 49, 85, -62, 60, + 27, 50, -16, 31, 39, -10, 38, 21, 1, 47, 2, 13, + 56, -16, 26, 66, -32, 38, 76, -46, 49, 85, -59, 60, + 29, 53, -13, 33, 42, -7, 39, 25, 2, 48, 6, 14, + 57, -13, 27, 66, -29, 38, 76, -43, 50, 86, -57, 61, + 31, 54, -10, 34, 44, -5, 41, 28, 4, 49, 9, 15, + 58, -9, 27, 67, -26, 39, 76, -41, 50, 86, -54, 61, + 32, 56, -8, 36, 47, -3, 42, 31, 6, 49, 13, 17, + 58, -6, 29, 68, -23, 40, 77, -38, 51, 86, -52, 62, + 34, 58, -5, 37, 49, 0, 43, 34, 8, 50, 16, 18, + 59, -2, 30, 68, -19, 41, 77, -35, 52, 87, -49, 62, + 36, 60, -2, 39, 52, 2, 44, 38, 10, 51, 20, 20, + 60, 1, 31, 69, -16, 42, 78, -31, 52, 87, -46, 63, + 38, 62, 1, 40, 54, 5, 46, 40, 12, 52, 23, 21, + 61, 5, 32, 69, -12, 43, 78, -28, 53, 88, -43, 64, + 39, 64, 3, 42, 57, 7, 47, 43, 14, 53, 27, 23, + 62, 8, 33, 70, -9, 44, 79, -25, 54, 88, -40, 64, + 41, 66, 6, 43, 59, 9, 48, 46, 16, 55, 30, 24, + 62, 12, 34, 71, -6, 45, 79, -22, 55, 89, -37, 65, + 43, 68, 8, 45, 61, 12, 49, 49, 18, 56, 33, 26, + 63, 15, 36, 71, -2, 46, 80, -19, 56, 89, -34, 65, + 44, 70, 11, 47, 64, 14, 51, 52, 20, 57, 36, 28, + 64, 19, 37, 72, 1, 47, 81, -15, 56, 90, -31, 66, + 46, 72, 14, 48, 66, 17, 52, 55, 22, 58, 40, 30, + 65, 22, 39, 73, 5, 48, 81, -12, 57, 90, -28, 67, + 48, 74, 16, 50, 68, 19, 54, 57, 24, 59, 43, 31, + 66, 25, 40, 74, 8, 49, 82, -8, 58, 91, -25, 68, + 49, 76, 19, 51, 70, 21, 55, 60, 26, 60, 45, 33, + 67, 29, 41, 75, 12, 50, 83, -5, 59, 91, -21, 69, + 51, 78, 21, 53, 73, 24, 56, 63, 28, 62, 49, 35, + 68, 32, 43, 76, 15, 52, 84, -1, 60, 92, -18, 70, + 53, 80, 24, 54, 75, 26, 58, 65, 30, 63, 52, 37, + 69, 35, 44, 77, 19, 53, 84, 2, 61, 93, -15, 70, + 54, 81, 26, 56, 77, 28, 59, 67, 32, 64, 54, 38, + 70, 38, 46, 77, 22, 54, 85, 5, 62, 93, -11, 71, + 10, 33, -50, 19, 10, -36, 30, -12, -19, 41, -29, -2, + 52, -43, 14, 63, -55, 28, 73, -66, 41, 83, -76, 53, + 11, 33, -50, 19, 11, -35, 30, -11, -18, 41, -28, -2, + 52, -43, 14, 63, -55, 28, 73, -66, 41, 83, -76, 54, + 11, 34, -49, 20, 11, -35, 30, -10, -18, 41, -28, -2, + 52, -42, 14, 63, -54, 28, 73, -65, 41, 83, -75, 54, + 12, 34, -48, 20, 13, -34, 30, -9, -18, 41, -27, -1, + 52, -42, 14, 63, -54, 28, 73, -65, 41, 83, -75, 54, + 13, 35, -47, 20, 14, -34, 31, -8, -17, 41, -25, -1, + 52, -41, 15, 63, -53, 29, 73, -64, 41, 83, -74, 54, + 13, 36, -45, 21, 16, -33, 31, -6, -17, 42, -24, -1, + 53, -39, 15, 63, -52, 29, 73, -63, 42, 83, -74, 54, + 14, 37, -43, 22, 18, -32, 31, -4, -16, 42, -22, 0, + 53, -38, 15, 63, -51, 29, 73, -62, 42, 84, -73, 54, + 16, 39, -41, 23, 20, -30, 32, -1, -15, 42, -20, 0, + 53, -36, 15, 63, -49, 29, 74, -61, 42, 84, -72, 54, + 17, 40, -39, 23, 23, -29, 33, 1, -14, 43, -17, 1, + 53, -34, 16, 64, -48, 30, 74, -60, 42, 84, -71, 54, + 18, 41, -37, 24, 25, -27, 33, 4, -13, 43, -15, 2, + 54, -32, 16, 64, -46, 30, 74, -58, 43, 84, -70, 55, + 20, 43, -34, 25, 27, -25, 34, 7, -12, 44, -12, 2, + 54, -29, 17, 64, -44, 30, 74, -56, 43, 84, -68, 55, + 21, 45, -32, 27, 30, -23, 35, 10, -11, 44, -9, 3, + 54, -27, 18, 64, -42, 31, 74, -55, 43, 84, -67, 55, + 23, 46, -29, 28, 33, -21, 36, 14, -9, 45, -6, 4, + 55, -24, 18, 65, -39, 31, 75, -52, 44, 85, -65, 55, + 25, 48, -26, 29, 35, -19, 37, 17, -8, 46, -3, 5, + 55, -21, 19, 65, -36, 32, 75, -50, 44, 85, -63, 56, + 26, 50, -24, 30, 38, -17, 38, 20, -6, 46, 0, 6, + 56, -18, 20, 66, -34, 33, 75, -48, 45, 85, -61, 56, + 28, 52, -21, 32, 40, -15, 39, 23, -5, 47, 4, 8, + 57, -15, 21, 66, -31, 33, 76, -45, 45, 85, -59, 57, + 30, 54, -18, 33, 43, -12, 40, 26, -3, 48, 7, 9, + 57, -11, 22, 67, -28, 34, 76, -42, 46, 86, -56, 57, + 31, 55, -16, 35, 46, -10, 41, 29, -1, 49, 11, 10, + 58, -8, 23, 67, -25, 35, 76, -40, 46, 86, -54, 58, + 33, 57, -13, 36, 48, -8, 42, 32, 1, 50, 14, 12, + 59, -5, 24, 68, -22, 35, 77, -37, 47, 86, -51, 58, + 34, 59, -10, 38, 50, -6, 43, 35, 3, 51, 17, 13, + 59, -1, 25, 68, -18, 36, 77, -34, 48, 87, -48, 59, + 36, 61, -7, 39, 53, -3, 45, 39, 5, 52, 21, 15, + 60, 2, 26, 69, -15, 37, 78, -31, 48, 87, -45, 59, + 38, 63, -5, 41, 55, -1, 46, 41, 7, 53, 24, 16, + 61, 6, 27, 70, -11, 38, 78, -27, 49, 88, -43, 60, + 40, 65, -2, 42, 57, 2, 47, 44, 9, 54, 27, 18, + 62, 9, 29, 70, -8, 39, 79, -24, 50, 88, -40, 60, + 41, 67, 0, 44, 60, 4, 48, 47, 11, 55, 31, 19, + 63, 12, 30, 71, -5, 40, 80, -21, 51, 89, -37, 61, + 43, 69, 3, 45, 62, 6, 50, 50, 13, 56, 34, 21, + 63, 16, 31, 72, -2, 41, 80, -18, 51, 89, -34, 62, + 45, 71, 6, 47, 64, 9, 51, 53, 15, 57, 37, 23, + 64, 20, 33, 72, 2, 42, 81, -14, 52, 90, -30, 63, + 46, 73, 8, 48, 67, 11, 52, 55, 17, 58, 40, 25, + 65, 23, 34, 73, 6, 44, 81, -11, 53, 90, -27, 63, + 48, 74, 11, 50, 69, 14, 54, 58, 19, 59, 43, 26, + 66, 26, 35, 74, 9, 45, 82, -8, 54, 91, -24, 64, + 49, 76, 13, 51, 71, 16, 55, 60, 21, 60, 46, 28, + 67, 29, 37, 75, 12, 46, 83, -5, 55, 91, -21, 65, + 51, 78, 16, 53, 73, 19, 57, 63, 23, 62, 49, 30, + 68, 33, 38, 76, 16, 47, 84, -1, 56, 92, -17, 66, + 53, 80, 19, 55, 75, 21, 58, 66, 25, 63, 52, 32, + 69, 36, 40, 77, 19, 49, 84, 3, 58, 93, -14, 67, + 54, 82, 21, 56, 77, 23, 59, 68, 27, 64, 55, 34, + 71, 39, 41, 78, 22, 50, 85, 6, 59, 93, -11, 68, + 11, 36, -54, 20, 14, -40, 30, -9, -23, 41, -26, -6, + 52, -41, 10, 63, -54, 24, 73, -65, 37, 83, -75, 50, + 12, 36, -53, 20, 14, -40, 30, -8, -23, 41, -26, -6, + 52, -41, 10, 63, -53, 24, 73, -64, 37, 83, -75, 50, + 12, 37, -52, 20, 15, -39, 31, -7, -23, 41, -25, -6, + 52, -40, 10, 63, -53, 24, 73, -64, 37, 83, -74, 50, + 13, 37, -51, 21, 16, -39, 31, -6, -22, 42, -24, -6, + 53, -40, 10, 63, -52, 24, 73, -63, 38, 83, -74, 50, + 14, 38, -50, 21, 17, -38, 31, -5, -22, 42, -23, -6, + 53, -39, 10, 63, -51, 24, 73, -63, 38, 84, -73, 50, + 14, 39, -49, 22, 19, -37, 31, -3, -21, 42, -22, -5, + 53, -37, 10, 63, -50, 25, 73, -62, 38, 84, -73, 50, + 15, 39, -47, 22, 21, -36, 32, -1, -21, 42, -20, -5, + 53, -36, 11, 63, -49, 25, 73, -61, 38, 84, -72, 51, + 17, 41, -45, 23, 23, -34, 32, 1, -20, 43, -18, -4, + 53, -34, 11, 64, -48, 25, 74, -60, 38, 84, -71, 51, + 18, 42, -43, 24, 25, -33, 33, 4, -19, 43, -15, -4, + 54, -32, 12, 64, -46, 25, 74, -58, 38, 84, -70, 51, + 19, 43, -41, 25, 27, -31, 34, 6, -18, 43, -13, -3, + 54, -30, 12, 64, -44, 26, 74, -57, 39, 84, -69, 51, + 21, 45, -38, 26, 29, -30, 34, 9, -17, 44, -10, -2, + 54, -28, 13, 64, -42, 26, 74, -55, 39, 84, -67, 51, + 22, 46, -36, 27, 32, -28, 35, 12, -15, 44, -8, -1, + 55, -25, 13, 65, -40, 27, 74, -53, 39, 84, -66, 52, + 24, 48, -33, 28, 34, -26, 36, 15, -14, 45, -4, 0, + 55, -22, 14, 65, -38, 27, 75, -51, 40, 85, -64, 52, + 25, 49, -31, 30, 37, -24, 37, 18, -12, 46, -1, 1, + 56, -20, 15, 65, -35, 28, 75, -49, 40, 85, -62, 52, + 27, 51, -28, 31, 39, -22, 38, 21, -11, 47, 2, 2, + 56, -17, 16, 66, -33, 28, 75, -47, 41, 85, -60, 53, + 28, 53, -26, 32, 42, -20, 39, 24, -9, 47, 5, 3, + 57, -14, 16, 66, -30, 29, 76, -44, 41, 86, -58, 53, + 30, 55, -23, 34, 44, -17, 40, 28, -7, 48, 9, 5, + 57, -10, 17, 67, -27, 30, 76, -41, 42, 86, -55, 54, + 32, 56, -20, 35, 47, -15, 41, 31, -6, 49, 12, 6, + 58, -7, 18, 67, -24, 31, 77, -39, 42, 86, -53, 54, + 33, 58, -18, 36, 49, -13, 42, 33, -4, 50, 15, 7, + 59, -4, 19, 68, -21, 31, 77, -36, 43, 87, -50, 55, + 35, 60, -15, 38, 51, -10, 43, 36, -2, 51, 18, 9, + 59, 0, 21, 68, -17, 32, 77, -33, 44, 87, -48, 55, + 37, 62, -12, 39, 54, -8, 45, 40, 0, 52, 22, 10, + 60, 3, 22, 69, -14, 33, 78, -30, 45, 87, -45, 56, + 38, 64, -9, 41, 56, -5, 46, 42, 2, 53, 25, 12, + 61, 7, 23, 70, -11, 34, 79, -27, 45, 88, -42, 56, + 40, 66, -7, 42, 58, -3, 47, 45, 4, 54, 28, 13, + 62, 10, 24, 70, -7, 35, 79, -24, 46, 88, -39, 57, + 41, 67, -4, 44, 60, -1, 48, 48, 6, 55, 31, 15, + 63, 13, 26, 71, -4, 36, 80, -20, 47, 89, -36, 58, + 43, 69, -2, 45, 63, 2, 50, 50, 8, 56, 35, 17, + 64, 17, 27, 72, -1, 37, 80, -17, 48, 89, -33, 58, + 45, 71, 1, 47, 65, 4, 51, 53, 10, 57, 38, 19, + 65, 20, 28, 73, 3, 39, 81, -14, 49, 90, -30, 59, + 46, 73, 4, 49, 67, 7, 53, 56, 12, 58, 41, 20, + 66, 24, 30, 73, 6, 40, 82, -10, 50, 90, -27, 60, + 48, 75, 6, 50, 69, 9, 54, 58, 14, 59, 44, 22, + 66, 27, 31, 74, 10, 41, 82, -7, 51, 91, -23, 61, + 50, 77, 9, 52, 71, 11, 55, 61, 16, 61, 47, 24, + 67, 30, 33, 75, 13, 42, 83, -4, 52, 92, -20, 62, + 51, 79, 11, 53, 74, 14, 57, 64, 19, 62, 50, 26, + 69, 33, 34, 76, 17, 43, 84, 0, 53, 92, -17, 63, + 53, 81, 14, 55, 76, 16, 58, 66, 21, 63, 53, 28, + 70, 37, 36, 77, 20, 45, 84, 3, 54, 93, -14, 63, + 55, 82, 16, 56, 78, 19, 60, 68, 23, 64, 55, 29, + 71, 40, 37, 78, 23, 46, 85, 6, 55, 93, -10, 64, + 13, 39, -57, 20, 17, -44, 31, -5, -27, 41, -24, -11, + 52, -39, 5, 63, -52, 20, 73, -63, 33, 83, -74, 46, + 13, 39, -56, 21, 18, -44, 31, -5, -27, 42, -23, -11, + 53, -39, 5, 63, -52, 20, 73, -63, 34, 83, -74, 46, + 13, 39, -56, 21, 18, -43, 31, -4, -27, 42, -23, -11, + 53, -38, 6, 63, -51, 20, 73, -63, 34, 83, -73, 47, + 14, 40, -55, 21, 19, -43, 31, -3, -27, 42, -22, -10, + 53, -37, 6, 63, -51, 20, 73, -62, 34, 84, -73, 47, + 15, 40, -54, 22, 20, -42, 32, -2, -26, 42, -20, -10, + 53, -37, 6, 63, -50, 20, 73, -61, 34, 84, -72, 47, + 15, 41, -52, 22, 22, -41, 32, 0, -26, 42, -19, -10, + 53, -35, 6, 63, -49, 21, 73, -61, 34, 84, -72, 47, + 16, 42, -51, 23, 23, -40, 32, 2, -25, 43, -17, -9, + 53, -34, 6, 63, -48, 21, 74, -60, 34, 84, -71, 47, + 17, 43, -49, 24, 25, -39, 33, 4, -24, 43, -15, -9, + 53, -32, 7, 64, -46, 21, 74, -58, 34, 84, -70, 47, + 19, 44, -47, 25, 27, -37, 33, 6, -23, 43, -13, -8, + 54, -30, 7, 64, -45, 21, 74, -57, 35, 84, -69, 47, + 20, 45, -45, 25, 29, -36, 34, 9, -22, 44, -11, -7, + 54, -28, 8, 64, -43, 22, 74, -56, 35, 84, -67, 48, + 21, 46, -43, 26, 32, -34, 35, 11, -21, 44, -8, -7, + 54, -26, 8, 64, -41, 22, 74, -54, 35, 84, -66, 48, + 23, 48, -40, 28, 34, -32, 35, 14, -20, 45, -6, -6, + 55, -24, 9, 65, -39, 23, 75, -52, 36, 85, -65, 48, + 24, 49, -38, 29, 36, -30, 36, 17, -18, 45, -2, -5, + 55, -21, 10, 65, -36, 23, 75, -50, 36, 85, -63, 48, + 26, 51, -35, 30, 38, -28, 37, 20, -17, 46, 1, -4, + 56, -18, 10, 65, -34, 24, 75, -48, 36, 85, -61, 49, + 27, 52, -33, 31, 41, -26, 38, 23, -15, 47, 4, -3, + 56, -15, 11, 66, -31, 24, 75, -46, 37, 85, -59, 49, + 29, 54, -30, 33, 43, -24, 39, 26, -14, 47, 7, -1, + 57, -12, 12, 66, -29, 25, 76, -43, 37, 86, -57, 50, + 30, 56, -27, 34, 46, -22, 40, 29, -12, 48, 10, 0, + 58, -9, 13, 67, -25, 26, 76, -40, 38, 86, -54, 50, + 32, 58, -25, 35, 48, -19, 41, 32, -10, 49, 13, 1, + 58, -6, 14, 67, -22, 27, 77, -38, 39, 86, -52, 51, + 34, 59, -22, 37, 50, -17, 43, 35, -8, 50, 16, 3, + 59, -2, 15, 68, -19, 27, 77, -35, 39, 87, -49, 51, + 35, 61, -19, 38, 52, -15, 44, 37, -7, 51, 20, 4, + 60, 1, 16, 68, -16, 28, 78, -32, 40, 87, -47, 52, + 37, 63, -17, 40, 55, -12, 45, 41, -4, 52, 23, 6, + 60, 4, 18, 69, -13, 29, 78, -29, 41, 87, -44, 52, + 39, 65, -14, 41, 57, -10, 46, 43, -2, 53, 26, 7, + 61, 8, 19, 70, -10, 30, 79, -26, 42, 88, -41, 53, + 40, 66, -11, 43, 59, -8, 47, 46, -1, 54, 29, 9, + 62, 11, 20, 70, -6, 31, 79, -23, 42, 88, -38, 54, + 42, 68, -9, 44, 61, -5, 49, 49, 1, 55, 32, 11, + 63, 14, 21, 71, -3, 32, 80, -20, 43, 89, -35, 54, + 43, 70, -6, 46, 63, -3, 50, 51, 4, 56, 35, 12, + 64, 17, 23, 72, 0, 33, 80, -16, 44, 89, -32, 55, + 45, 72, -3, 47, 66, 0, 51, 54, 6, 57, 39, 14, + 65, 21, 24, 73, 4, 35, 81, -13, 45, 90, -29, 56, + 47, 74, -1, 49, 68, 2, 53, 57, 8, 58, 42, 16, + 66, 24, 26, 73, 7, 36, 82, -10, 46, 90, -26, 57, + 48, 76, 2, 50, 70, 4, 54, 59, 10, 60, 45, 18, + 67, 27, 27, 74, 10, 37, 82, -6, 47, 91, -23, 57, + 50, 77, 4, 52, 72, 7, 55, 62, 12, 61, 47, 19, + 68, 31, 28, 75, 14, 38, 83, -3, 48, 92, -20, 58, + 52, 79, 7, 53, 74, 9, 57, 64, 14, 62, 51, 21, + 69, 34, 30, 76, 17, 39, 84, 0, 49, 92, -16, 59, + 53, 81, 9, 55, 76, 12, 58, 67, 16, 63, 53, 23, + 70, 37, 32, 77, 20, 41, 85, 4, 50, 93, -13, 60, + 55, 83, 12, 56, 78, 14, 60, 69, 19, 65, 56, 25, + 71, 40, 33, 78, 24, 42, 85, 7, 51, 94, -10, 61, + 14, 41, -60, 21, 21, -48, 31, -2, -32, 42, -21, -15, + 53, -37, 1, 63, -50, 16, 73, -62, 30, 84, -73, 43, + 14, 41, -60, 21, 21, -48, 31, -1, -32, 42, -20, -15, + 53, -36, 1, 63, -50, 16, 73, -61, 30, 84, -72, 43, + 14, 42, -59, 22, 22, -47, 31, -1, -31, 42, -20, -15, + 53, -36, 1, 63, -49, 16, 73, -61, 30, 84, -72, 43, + 15, 42, -58, 22, 23, -47, 32, 0, -31, 42, -19, -15, + 53, -35, 1, 63, -49, 16, 73, -61, 30, 84, -72, 43, + 16, 43, -57, 22, 24, -46, 32, 1, -31, 42, -18, -14, + 53, -34, 2, 63, -48, 16, 73, -60, 30, 84, -71, 43, + 16, 43, -56, 23, 25, -45, 32, 3, -30, 43, -17, -14, + 53, -33, 2, 63, -47, 16, 74, -59, 30, 84, -70, 43, + 17, 44, -54, 24, 26, -44, 33, 5, -29, 43, -15, -14, + 53, -32, 2, 64, -46, 17, 74, -58, 30, 84, -70, 43, + 18, 45, -52, 24, 28, -43, 33, 7, -28, 43, -13, -13, + 54, -30, 3, 64, -44, 17, 74, -57, 30, 84, -69, 43, + 19, 46, -51, 25, 30, -41, 34, 9, -28, 44, -11, -12, + 54, -28, 3, 64, -43, 17, 74, -56, 31, 84, -68, 44, + 21, 47, -49, 26, 32, -40, 34, 11, -27, 44, -9, -12, + 54, -26, 3, 64, -41, 18, 74, -54, 31, 84, -66, 44, + 22, 48, -46, 27, 34, -38, 35, 14, -25, 44, -6, -11, + 55, -24, 4, 65, -39, 18, 74, -53, 31, 84, -65, 44, + 23, 49, -44, 28, 36, -36, 36, 16, -24, 45, -4, -10, + 55, -22, 5, 65, -37, 18, 75, -51, 32, 85, -63, 44, + 25, 51, -42, 29, 38, -34, 37, 19, -23, 46, -1, -9, + 56, -19, 5, 65, -35, 19, 75, -49, 32, 85, -62, 45, + 26, 52, -39, 30, 40, -32, 38, 22, -21, 46, 2, -8, + 56, -16, 6, 66, -32, 20, 75, -47, 33, 85, -60, 45, + 28, 54, -37, 32, 42, -30, 39, 25, -20, 47, 5, -7, + 57, -14, 7, 66, -30, 20, 76, -44, 33, 85, -58, 46, + 29, 55, -34, 33, 44, -28, 39, 27, -18, 48, 8, -6, + 57, -11, 8, 66, -27, 21, 76, -42, 34, 86, -56, 46, + 31, 57, -32, 34, 47, -26, 41, 30, -16, 49, 12, -4, + 58, -7, 9, 67, -24, 22, 76, -39, 34, 86, -53, 46, + 32, 59, -29, 36, 49, -24, 42, 33, -15, 49, 15, -3, + 58, -4, 10, 67, -21, 22, 77, -37, 35, 86, -51, 47, + 34, 60, -26, 37, 51, -22, 43, 36, -13, 50, 18, -2, + 59, -1, 11, 68, -18, 23, 77, -34, 35, 87, -48, 47, + 36, 62, -24, 39, 53, -19, 44, 39, -11, 51, 21, 0, + 60, 2, 12, 69, -15, 24, 78, -31, 36, 87, -46, 48, + 37, 64, -21, 40, 56, -17, 45, 42, -9, 52, 24, 1, + 61, 6, 13, 69, -12, 25, 78, -28, 37, 88, -43, 49, + 39, 66, -18, 42, 58, -14, 46, 44, -7, 53, 27, 3, + 61, 9, 15, 70, -9, 26, 79, -25, 38, 88, -40, 49, + 40, 67, -16, 43, 60, -12, 48, 47, -5, 54, 30, 5, + 62, 12, 16, 71, -5, 27, 79, -22, 38, 88, -37, 50, + 42, 69, -13, 44, 62, -10, 49, 50, -3, 55, 33, 6, + 63, 15, 17, 71, -2, 28, 80, -19, 39, 89, -34, 51, + 44, 71, -11, 46, 64, -7, 50, 52, -1, 56, 36, 8, + 64, 18, 18, 72, 1, 29, 80, -16, 40, 89, -32, 51, + 45, 73, -8, 48, 66, -5, 52, 55, 1, 58, 40, 10, + 65, 22, 20, 73, 5, 30, 81, -12, 41, 90, -28, 52, + 47, 74, -5, 49, 69, -2, 53, 57, 3, 59, 43, 11, + 66, 25, 21, 74, 8, 32, 82, -9, 42, 91, -25, 53, + 49, 76, -3, 50, 71, 0, 54, 60, 5, 60, 45, 13, + 67, 28, 23, 74, 11, 33, 82, -6, 43, 91, -22, 54, + 50, 78, 0, 52, 73, 2, 56, 62, 8, 61, 48, 15, + 68, 31, 24, 75, 14, 34, 83, -2, 44, 92, -19, 55, + 52, 80, 2, 54, 75, 5, 57, 65, 10, 62, 51, 17, + 69, 35, 26, 76, 18, 35, 84, 1, 45, 92, -15, 56, + 53, 82, 5, 55, 77, 7, 59, 67, 12, 63, 54, 19, + 70, 38, 27, 77, 21, 37, 85, 4, 46, 93, -12, 56, + 55, 83, 7, 57, 79, 10, 60, 70, 14, 65, 57, 21, + 71, 41, 29, 78, 24, 38, 85, 8, 48, 94, -9, 57, + 15, 44, -64, 22, 24, -52, 32, 2, -36, 42, -18, -20, + 53, -34, -4, 63, -48, 11, 73, -60, 25, 84, -71, 39, + 15, 44, -63, 22, 25, -52, 32, 2, -36, 42, -17, -20, + 53, -34, -4, 63, -48, 11, 73, -60, 25, 84, -71, 39, + 16, 44, -63, 22, 25, -51, 32, 3, -36, 42, -17, -20, + 53, -33, -4, 63, -47, 11, 73, -59, 25, 84, -71, 39, + 16, 45, -62, 23, 26, -51, 32, 4, -36, 42, -16, -20, + 53, -33, -3, 63, -47, 11, 74, -59, 25, 84, -70, 39, + 17, 45, -61, 23, 27, -50, 32, 5, -35, 43, -15, -19, + 53, -32, -3, 64, -46, 12, 74, -58, 25, 84, -70, 39, + 17, 46, -60, 24, 28, -49, 33, 6, -35, 43, -13, -19, + 53, -31, -3, 64, -45, 12, 74, -57, 26, 84, -69, 39, + 18, 46, -58, 24, 29, -48, 33, 8, -34, 43, -12, -19, + 54, -29, -3, 64, -44, 12, 74, -57, 26, 84, -68, 39, + 19, 47, -57, 25, 31, -47, 34, 10, -33, 44, -10, -18, + 54, -28, -2, 64, -42, 12, 74, -55, 26, 84, -67, 39, + 20, 48, -55, 26, 33, -46, 34, 12, -32, 44, -8, -17, + 54, -26, -2, 64, -41, 13, 74, -54, 26, 84, -66, 39, + 22, 49, -53, 27, 34, -44, 35, 14, -31, 44, -6, -17, + 55, -24, -1, 64, -39, 13, 74, -53, 26, 84, -65, 40, + 23, 50, -51, 28, 36, -43, 36, 16, -30, 45, -4, -16, + 55, -22, -1, 65, -37, 13, 75, -51, 27, 85, -64, 40, + 24, 51, -49, 29, 38, -41, 36, 19, -29, 45, -1, -15, + 55, -20, 0, 65, -35, 14, 75, -49, 27, 85, -62, 40, + 26, 53, -46, 30, 40, -39, 37, 21, -28, 46, 2, -14, + 56, -17, 1, 65, -33, 14, 75, -47, 28, 85, -60, 41, + 27, 54, -44, 31, 42, -37, 38, 24, -26, 47, 4, -13, + 56, -14, 1, 66, -31, 15, 75, -45, 28, 85, -58, 41, + 28, 55, -42, 32, 44, -35, 39, 27, -25, 47, 7, -12, + 57, -12, 2, 66, -28, 16, 76, -43, 29, 86, -56, 41, + 30, 57, -39, 33, 46, -33, 40, 29, -23, 48, 10, -11, + 57, -9, 3, 67, -26, 16, 76, -41, 29, 86, -54, 42, + 31, 58, -36, 35, 48, -31, 41, 32, -21, 49, 13, -9, + 58, -6, 4, 67, -23, 17, 77, -38, 30, 86, -52, 42, + 33, 60, -34, 36, 51, -29, 42, 35, -20, 50, 16, -8, + 59, -3, 5, 68, -20, 18, 77, -35, 30, 86, -50, 43, + 34, 62, -31, 38, 53, -26, 43, 37, -18, 51, 19, -7, + 59, 0, 6, 68, -17, 19, 77, -33, 31, 87, -47, 43, + 36, 63, -29, 39, 55, -24, 44, 40, -16, 51, 22, -5, + 60, 3, 7, 69, -14, 20, 78, -30, 32, 87, -45, 44, + 38, 65, -26, 40, 57, -22, 46, 43, -14, 53, 26, -3, + 61, 7, 9, 69, -10, 21, 78, -27, 33, 88, -42, 44, + 39, 67, -23, 42, 59, -19, 47, 46, -12, 53, 29, -2, + 62, 10, 10, 70, -7, 22, 79, -24, 33, 88, -39, 45, + 41, 68, -21, 43, 61, -17, 48, 48, -10, 54, 32, 0, + 62, 13, 11, 71, -4, 23, 79, -21, 34, 89, -36, 46, + 42, 70, -18, 45, 63, -15, 49, 51, -8, 56, 35, 1, + 63, 16, 12, 71, -1, 24, 80, -18, 35, 89, -33, 46, + 44, 72, -16, 46, 65, -12, 51, 53, -6, 57, 37, 3, + 64, 20, 14, 72, 2, 25, 81, -15, 36, 90, -31, 47, + 46, 74, -13, 48, 67, -10, 52, 56, -4, 58, 41, 5, + 65, 23, 15, 73, 6, 26, 81, -11, 37, 90, -27, 48, + 47, 75, -10, 49, 69, -7, 53, 58, -2, 59, 44, 7, + 66, 26, 17, 74, 9, 27, 82, -8, 38, 91, -24, 49, + 49, 77, -8, 51, 71, -5, 55, 61, 0, 60, 46, 8, + 67, 29, 18, 74, 12, 28, 83, -5, 39, 91, -21, 50, + 50, 79, -5, 52, 73, -3, 56, 63, 3, 61, 49, 10, + 68, 32, 19, 75, 15, 29, 83, -2, 40, 92, -18, 50, + 52, 81, -3, 54, 76, 0, 57, 66, 5, 62, 52, 12, + 69, 36, 21, 76, 19, 31, 84, 2, 41, 92, -15, 51, + 54, 82, 0, 55, 77, 2, 59, 68, 7, 64, 55, 14, + 70, 39, 23, 77, 22, 32, 85, 5, 42, 93, -12, 52, + 55, 84, 2, 57, 79, 5, 60, 70, 9, 65, 57, 16, + 71, 42, 24, 78, 25, 34, 86, 8, 43, 94, -8, 53, + 16, 46, -67, 23, 28, -56, 32, 5, -41, 43, -15, -24, + 53, -32, -8, 63, -46, 7, 74, -58, 21, 84, -70, 35, + 17, 47, -66, 23, 28, -55, 32, 6, -40, 43, -14, -24, + 53, -31, -8, 64, -46, 7, 74, -58, 21, 84, -69, 35, + 17, 47, -66, 23, 29, -55, 33, 6, -40, 43, -14, -24, + 53, -31, -8, 64, -45, 7, 74, -58, 21, 84, -69, 35, + 17, 47, -65, 24, 29, -55, 33, 7, -40, 43, -13, -24, + 53, -30, -8, 64, -45, 7, 74, -57, 21, 84, -69, 35, + 18, 47, -64, 24, 30, -54, 33, 8, -39, 43, -12, -24, + 54, -29, -8, 64, -44, 7, 74, -57, 21, 84, -68, 35, + 18, 48, -63, 24, 31, -53, 33, 9, -39, 43, -11, -23, + 54, -28, -7, 64, -43, 8, 74, -56, 22, 84, -68, 35, + 19, 49, -62, 25, 32, -52, 34, 11, -38, 43, -9, -23, + 54, -27, -7, 64, -42, 8, 74, -55, 22, 84, -67, 35, + 20, 49, -60, 26, 34, -51, 34, 13, -37, 44, -7, -22, + 54, -26, -7, 64, -41, 8, 74, -54, 22, 84, -66, 35, + 21, 50, -58, 27, 35, -50, 35, 15, -36, 44, -6, -22, + 54, -24, -6, 64, -39, 8, 74, -52, 22, 84, -65, 36, + 22, 51, -57, 27, 37, -48, 35, 17, -36, 45, -4, -21, + 55, -22, -6, 65, -37, 9, 75, -51, 22, 85, -64, 36, + 24, 52, -55, 28, 38, -47, 36, 19, -34, 45, -1, -20, + 55, -20, -5, 65, -36, 9, 75, -50, 23, 85, -62, 36, + 25, 53, -53, 29, 40, -45, 37, 21, -33, 46, 1, -19, + 55, -18, -4, 65, -34, 10, 75, -48, 23, 85, -61, 36, + 26, 54, -50, 30, 42, -43, 38, 24, -32, 46, 4, -18, + 56, -15, -4, 66, -31, 10, 75, -46, 24, 85, -59, 37, + 28, 56, -48, 32, 44, -41, 38, 26, -30, 47, 6, -17, + 56, -13, -3, 66, -29, 11, 76, -44, 24, 85, -57, 37, + 29, 57, -46, 33, 46, -39, 39, 28, -29, 48, 9, -16, + 57, -10, -2, 66, -27, 11, 76, -42, 25, 86, -55, 38, + 30, 58, -43, 34, 48, -37, 40, 31, -27, 48, 12, -15, + 58, -7, -1, 67, -24, 12, 76, -39, 25, 86, -53, 38, + 32, 60, -40, 35, 50, -35, 41, 34, -26, 49, 15, -14, + 58, -4, 0, 67, -21, 13, 77, -36, 26, 86, -51, 38, + 33, 61, -38, 37, 52, -33, 42, 36, -24, 50, 18, -12, + 59, -1, 1, 68, -18, 14, 77, -34, 26, 87, -49, 39, + 35, 63, -36, 38, 54, -31, 44, 39, -22, 51, 21, -11, + 59, 2, 2, 68, -15, 15, 77, -31, 27, 87, -46, 39, + 36, 64, -33, 39, 56, -29, 45, 41, -20, 52, 24, -9, + 60, 5, 3, 69, -13, 15, 78, -29, 28, 87, -44, 40, + 38, 66, -30, 41, 58, -26, 46, 44, -18, 53, 27, -8, + 61, 8, 4, 70, -9, 16, 78, -25, 29, 88, -41, 41, + 40, 68, -28, 42, 60, -24, 47, 47, -16, 54, 30, -6, + 62, 11, 5, 70, -6, 17, 79, -23, 29, 88, -38, 41, + 41, 69, -25, 44, 62, -21, 48, 49, -14, 55, 33, -5, + 63, 14, 7, 71, -3, 18, 80, -20, 30, 89, -35, 42, + 43, 71, -23, 45, 64, -19, 50, 52, -12, 56, 36, -3, + 63, 18, 8, 72, 0, 19, 80, -17, 31, 89, -33, 43, + 44, 72, -20, 46, 66, -17, 51, 54, -10, 57, 39, -1, + 64, 21, 9, 72, 3, 21, 81, -14, 32, 90, -30, 43, + 46, 74, -17, 48, 68, -14, 52, 57, -8, 58, 42, 0, + 65, 24, 11, 73, 7, 22, 81, -10, 33, 90, -26, 44, + 48, 76, -15, 50, 70, -12, 53, 59, -6, 59, 44, 2, + 66, 27, 12, 74, 10, 23, 82, -7, 34, 91, -23, 45, + 49, 78, -12, 51, 72, -10, 55, 62, -4, 60, 47, 4, + 67, 30, 14, 75, 13, 24, 83, -4, 35, 91, -20, 46, + 51, 79, -10, 53, 74, -7, 56, 64, -2, 61, 50, 6, + 68, 33, 15, 75, 16, 25, 83, -1, 36, 92, -17, 47, + 52, 81, -7, 54, 76, -5, 58, 67, 1, 63, 53, 8, + 69, 36, 17, 76, 20, 27, 84, 3, 37, 93, -14, 48, + 54, 83, -5, 56, 78, -2, 59, 69, 3, 64, 56, 10, + 70, 39, 19, 77, 23, 28, 85, 6, 38, 93, -11, 49, + 55, 85, -2, 57, 80, 0, 60, 71, 5, 65, 58, 12, + 71, 42, 20, 78, 26, 29, 86, 9, 39, 94, -8, 50, + 17, 49, -70, 24, 31, -59, 33, 9, -45, 43, -11, -29, + 53, -29, -12, 64, -44, 3, 74, -56, 17, 84, -68, 31, + 18, 49, -69, 24, 31, -59, 33, 9, -44, 43, -11, -28, + 54, -29, -12, 64, -43, 3, 74, -56, 17, 84, -68, 31, + 18, 49, -69, 24, 32, -59, 33, 10, -44, 43, -11, -28, + 54, -28, -12, 64, -43, 3, 74, -56, 17, 84, -68, 31, + 18, 49, -68, 24, 32, -58, 33, 10, -44, 43, -10, -28, + 54, -28, -12, 64, -42, 3, 74, -55, 17, 84, -67, 31, + 19, 50, -67, 25, 33, -58, 33, 11, -43, 43, -9, -28, + 54, -27, -12, 64, -42, 3, 74, -55, 17, 84, -67, 31, + 20, 50, -66, 25, 34, -57, 34, 12, -43, 44, -8, -27, + 54, -26, -12, 64, -41, 3, 74, -54, 18, 84, -66, 31, + 20, 51, -65, 26, 35, -56, 34, 14, -42, 44, -7, -27, + 54, -25, -11, 64, -40, 4, 74, -53, 18, 84, -65, 31, + 21, 51, -63, 26, 36, -55, 35, 16, -41, 44, -5, -26, + 54, -23, -11, 64, -39, 4, 74, -52, 18, 84, -64, 32, + 22, 52, -62, 27, 38, -54, 35, 17, -41, 45, -3, -26, + 55, -22, -10, 65, -37, 4, 74, -51, 18, 84, -63, 32, + 23, 53, -60, 28, 39, -52, 36, 19, -40, 45, -1, -25, + 55, -20, -10, 65, -36, 5, 75, -49, 18, 85, -62, 32, + 24, 54, -58, 29, 41, -51, 36, 21, -39, 45, 1, -24, + 55, -18, -9, 65, -34, 5, 75, -48, 19, 85, -61, 32, + 25, 55, -56, 30, 42, -49, 37, 23, -37, 46, 3, -24, + 56, -16, -9, 65, -32, 6, 75, -46, 19, 85, -59, 33, + 27, 56, -54, 31, 44, -47, 38, 26, -36, 47, 6, -22, + 56, -13, -8, 66, -30, 6, 75, -44, 20, 85, -58, 33, + 28, 57, -52, 32, 46, -45, 39, 28, -35, 47, 8, -21, + 57, -11, -7, 66, -27, 7, 76, -42, 20, 86, -56, 33, + 30, 58, -49, 33, 48, -43, 40, 30, -33, 48, 11, -20, + 57, -8, -6, 67, -25, 7, 76, -40, 21, 86, -54, 34, + 31, 60, -47, 34, 49, -41, 41, 33, -32, 49, 14, -19, + 58, -5, -5, 67, -22, 8, 76, -38, 21, 86, -52, 34, + 32, 61, -45, 36, 52, -39, 42, 36, -30, 49, 17, -18, + 58, -2, -4, 68, -20, 9, 77, -35, 22, 86, -50, 35, + 34, 63, -42, 37, 53, -37, 43, 38, -28, 50, 20, -17, + 59, 0, -3, 68, -17, 10, 77, -33, 22, 87, -47, 35, + 35, 64, -40, 38, 55, -35, 44, 40, -26, 51, 22, -15, + 60, 3, -2, 69, -14, 10, 78, -30, 23, 87, -45, 36, + 37, 65, -37, 40, 57, -33, 45, 43, -25, 52, 25, -14, + 60, 6, -1, 69, -11, 11, 78, -27, 24, 87, -43, 36, + 39, 67, -35, 41, 59, -30, 46, 46, -22, 53, 28, -12, + 61, 10, 0, 70, -8, 12, 79, -24, 25, 88, -40, 37, + 40, 69, -32, 43, 61, -28, 47, 48, -21, 54, 31, -11, + 62, 13, 1, 70, -5, 13, 79, -21, 25, 88, -37, 38, + 42, 70, -30, 44, 63, -26, 49, 50, -19, 55, 34, -9, + 63, 16, 2, 71, -2, 14, 80, -18, 26, 89, -34, 38, + 43, 72, -27, 45, 65, -23, 50, 53, -17, 56, 37, -7, + 64, 19, 4, 72, 1, 15, 80, -16, 27, 89, -32, 39, + 45, 73, -25, 47, 67, -21, 51, 55, -15, 57, 40, -6, + 64, 22, 5, 72, 4, 16, 81, -13, 28, 90, -29, 40, + 46, 75, -22, 48, 69, -19, 52, 58, -12, 58, 43, -4, + 65, 25, 7, 73, 8, 18, 82, -9, 29, 90, -25, 41, + 48, 77, -19, 50, 71, -16, 54, 60, -10, 59, 45, -2, + 66, 28, 8, 74, 11, 19, 82, -6, 30, 91, -22, 41, + 49, 78, -17, 51, 73, -14, 55, 63, -8, 60, 48, 0, + 67, 31, 10, 75, 14, 20, 83, -3, 31, 91, -19, 42, + 51, 80, -14, 53, 75, -12, 56, 65, -6, 62, 51, 1, + 68, 34, 11, 76, 17, 21, 83, 0, 32, 92, -16, 43, + 53, 82, -12, 54, 77, -9, 58, 67, -4, 63, 54, 4, + 69, 37, 13, 77, 21, 23, 84, 4, 33, 93, -13, 44, + 54, 84, -9, 56, 79, -7, 59, 70, -2, 64, 56, 5, + 70, 40, 14, 77, 24, 24, 85, 7, 34, 93, -10, 45, + 56, 85, -7, 57, 81, -4, 61, 72, 0, 65, 59, 7, + 71, 43, 16, 78, 27, 25, 86, 10, 35, 94, -7, 46, + 19, 51, -73, 25, 34, -63, 33, 12, -49, 43, -8, -33, + 54, -26, -17, 64, -41, -1, 74, -55, 13, 84, -67, 27, + 19, 51, -72, 25, 34, -63, 33, 13, -48, 43, -8, -33, + 54, -26, -16, 64, -41, -1, 74, -54, 13, 84, -66, 27, + 19, 51, -72, 25, 35, -62, 34, 13, -48, 43, -8, -32, + 54, -26, -16, 64, -41, -1, 74, -54, 13, 84, -66, 27, + 20, 52, -71, 25, 35, -62, 34, 14, -48, 44, -7, -32, + 54, -25, -16, 64, -40, -1, 74, -54, 13, 84, -66, 27, + 20, 52, -70, 26, 36, -61, 34, 15, -47, 44, -6, -32, + 54, -24, -16, 64, -40, -1, 74, -53, 13, 84, -65, 27, + 21, 52, -69, 26, 37, -60, 34, 16, -47, 44, -5, -32, + 54, -23, -16, 64, -39, -1, 74, -52, 13, 84, -65, 27, + 21, 53, -68, 27, 38, -60, 35, 17, -46, 44, -4, -31, + 54, -22, -15, 64, -38, -1, 74, -51, 14, 84, -64, 28, + 22, 53, -67, 27, 39, -58, 35, 18, -45, 45, -2, -31, + 55, -21, -15, 65, -36, 0, 74, -50, 14, 85, -63, 28, + 23, 54, -65, 28, 40, -57, 36, 20, -45, 45, 0, -30, + 55, -19, -15, 65, -35, 0, 75, -49, 14, 85, -62, 28, + 24, 55, -64, 29, 41, -56, 36, 22, -44, 45, 1, -29, + 55, -17, -14, 65, -34, 0, 75, -48, 14, 85, -61, 28, + 25, 56, -62, 30, 43, -54, 37, 24, -43, 46, 3, -29, + 56, -16, -13, 65, -32, 1, 75, -46, 15, 85, -59, 28, + 26, 57, -60, 31, 44, -53, 38, 26, -41, 46, 6, -28, + 56, -14, -13, 66, -30, 1, 75, -45, 15, 85, -58, 29, + 28, 58, -58, 32, 46, -51, 38, 28, -40, 47, 8, -27, + 56, -11, -12, 66, -28, 2, 76, -43, 16, 85, -56, 29, + 29, 59, -56, 33, 48, -49, 39, 30, -39, 48, 11, -26, + 57, -9, -11, 66, -26, 3, 76, -41, 16, 86, -54, 29, + 30, 60, -53, 34, 49, -47, 40, 32, -37, 48, 13, -25, + 57, -6, -11, 67, -23, 3, 76, -38, 17, 86, -53, 30, + 32, 61, -51, 35, 51, -45, 41, 35, -36, 49, 16, -23, + 58, -4, -10, 67, -21, 4, 77, -36, 17, 86, -51, 30, + 33, 63, -48, 36, 53, -43, 42, 37, -34, 50, 19, -22, + 59, -1, -9, 68, -18, 5, 77, -34, 18, 87, -48, 31, + 34, 64, -46, 38, 55, -41, 43, 40, -32, 51, 21, -21, + 59, 2, -8, 68, -15, 5, 77, -31, 18, 87, -46, 31, + 36, 65, -44, 39, 57, -39, 44, 42, -31, 51, 24, -19, + 60, 5, -7, 69, -13, 6, 78, -29, 19, 87, -44, 32, + 37, 67, -41, 40, 59, -37, 45, 44, -29, 52, 27, -18, + 61, 8, -6, 69, -10, 7, 78, -26, 20, 88, -41, 32, + 39, 68, -39, 42, 61, -34, 47, 47, -27, 53, 30, -16, + 61, 11, -4, 70, -7, 8, 79, -23, 21, 88, -38, 33, + 40, 70, -36, 43, 62, -32, 48, 49, -25, 54, 33, -15, + 62, 14, -3, 71, -4, 9, 79, -20, 21, 88, -36, 34, + 42, 71, -34, 44, 64, -30, 49, 52, -23, 55, 35, -13, + 63, 17, -2, 71, -1, 10, 80, -17, 22, 89, -33, 34, + 43, 73, -31, 46, 66, -28, 50, 54, -21, 56, 38, -12, + 64, 20, 0, 72, 2, 11, 80, -14, 23, 89, -30, 35, + 45, 74, -29, 47, 68, -25, 51, 56, -19, 57, 41, -10, + 65, 23, 1, 73, 5, 12, 81, -11, 24, 90, -28, 36, + 47, 76, -26, 49, 70, -23, 53, 59, -17, 58, 44, -8, + 66, 26, 2, 73, 9, 14, 82, -8, 25, 90, -24, 37, + 48, 78, -24, 50, 72, -21, 54, 61, -15, 60, 47, -6, + 67, 29, 4, 74, 12, 15, 82, -5, 26, 91, -21, 37, + 50, 79, -21, 52, 74, -18, 55, 63, -13, 61, 49, -5, + 67, 32, 5, 75, 15, 16, 83, -2, 27, 92, -19, 38, + 51, 81, -19, 53, 76, -16, 57, 66, -11, 62, 52, -3, + 68, 35, 7, 76, 18, 17, 84, 1, 28, 92, -16, 39, + 53, 83, -16, 55, 78, -13, 58, 68, -8, 63, 55, -1, + 70, 38, 9, 77, 21, 19, 84, 5, 29, 93, -12, 40, + 54, 84, -13, 56, 80, -11, 59, 70, -6, 64, 57, 1, + 71, 41, 10, 78, 24, 20, 85, 8, 30, 93, -9, 41, + 56, 86, -11, 58, 81, -9, 61, 73, -4, 65, 60, 3, + 72, 44, 12, 78, 28, 21, 86, 11, 31, 94, -6, 42, + 20, 54, -76, 26, 38, -67, 34, 16, -53, 44, -5, -37, + 54, -23, -21, 64, -39, -6, 74, -52, 8, 84, -65, 23, + 20, 54, -76, 26, 38, -67, 34, 16, -53, 44, -4, -37, + 54, -23, -21, 64, -39, -6, 74, -52, 9, 84, -64, 23, + 20, 54, -75, 26, 38, -66, 34, 17, -52, 44, -4, -37, + 54, -23, -21, 64, -38, -6, 74, -52, 9, 84, -64, 23, + 21, 54, -75, 26, 39, -66, 34, 17, -52, 44, -3, -37, + 54, -22, -21, 64, -38, -6, 74, -51, 9, 84, -64, 23, + 21, 55, -74, 26, 39, -65, 35, 18, -52, 44, -3, -37, + 54, -21, -21, 64, -37, -6, 74, -51, 9, 84, -63, 23, + 22, 55, -73, 27, 40, -64, 35, 19, -51, 44, -2, -36, + 55, -20, -20, 65, -36, -5, 74, -50, 9, 84, -63, 23, + 22, 55, -72, 27, 41, -64, 35, 20, -51, 45, 0, -36, + 55, -19, -20, 65, -35, -5, 75, -49, 9, 85, -62, 23, + 23, 56, -70, 28, 42, -62, 36, 22, -50, 45, 1, -35, + 55, -18, -20, 65, -34, -5, 75, -48, 9, 85, -61, 23, + 24, 56, -69, 29, 43, -61, 36, 23, -49, 45, 3, -35, + 55, -16, -19, 65, -33, -5, 75, -47, 10, 85, -60, 24, + 25, 57, -67, 30, 44, -60, 37, 25, -48, 46, 4, -34, + 56, -15, -19, 65, -31, -4, 75, -46, 10, 85, -59, 24, + 26, 58, -66, 30, 45, -59, 38, 26, -47, 46, 6, -33, + 56, -13, -18, 66, -30, -4, 75, -44, 10, 85, -58, 24, + 27, 59, -64, 31, 47, -57, 38, 28, -46, 47, 8, -32, + 56, -11, -18, 66, -28, -3, 75, -43, 11, 85, -56, 24, + 28, 60, -62, 32, 48, -55, 39, 31, -45, 47, 11, -31, + 57, -9, -17, 66, -26, -3, 76, -41, 11, 86, -54, 25, + 30, 61, -60, 33, 50, -54, 40, 33, -43, 48, 13, -30, + 57, -6, -16, 67, -23, -2, 76, -39, 12, 86, -53, 25, + 31, 62, -58, 34, 51, -52, 41, 35, -42, 49, 15, -29, + 58, -4, -15, 67, -21, -1, 76, -37, 12, 86, -51, 25, + 32, 63, -55, 36, 53, -50, 42, 37, -40, 49, 18, -28, + 58, -1, -14, 67, -19, -1, 77, -34, 13, 86, -49, 26, + 34, 64, -53, 37, 55, -48, 43, 39, -39, 50, 21, -27, + 59, 1, -13, 68, -16, 0, 77, -32, 13, 87, -47, 26, + 35, 65, -51, 38, 57, -46, 44, 42, -37, 51, 23, -25, + 60, 4, -12, 68, -13, 1, 78, -30, 14, 87, -45, 27, + 37, 67, -48, 39, 58, -44, 45, 44, -35, 52, 26, -24, + 60, 7, -11, 69, -11, 2, 78, -27, 14, 87, -42, 27, + 38, 68, -46, 41, 60, -41, 46, 46, -33, 53, 29, -23, + 61, 10, -10, 70, -8, 2, 78, -24, 15, 88, -40, 28, + 40, 70, -43, 42, 62, -39, 47, 49, -31, 54, 32, -21, + 62, 13, -9, 70, -5, 4, 79, -21, 16, 88, -37, 29, + 41, 71, -41, 43, 64, -37, 48, 51, -30, 55, 34, -20, + 62, 16, -8, 71, -2, 4, 79, -19, 17, 89, -35, 29, + 42, 72, -38, 45, 66, -35, 49, 53, -28, 56, 37, -18, + 63, 19, -6, 71, 1, 5, 80, -16, 18, 89, -32, 30, + 44, 74, -36, 46, 67, -32, 51, 55, -26, 57, 40, -16, + 64, 21, -5, 72, 4, 7, 81, -13, 19, 90, -29, 31, + 45, 75, -34, 48, 69, -30, 52, 58, -24, 58, 42, -15, + 65, 24, -4, 73, 7, 8, 81, -10, 19, 90, -26, 31, + 47, 77, -31, 49, 71, -28, 53, 60, -21, 59, 45, -13, + 66, 28, -2, 74, 10, 9, 82, -7, 20, 91, -23, 32, + 49, 79, -28, 51, 73, -25, 54, 62, -19, 60, 48, -11, + 67, 30, -1, 74, 13, 10, 82, -4, 21, 91, -20, 33, + 50, 80, -26, 52, 75, -23, 56, 65, -17, 61, 50, -9, + 68, 33, 1, 75, 16, 11, 83, -1, 22, 92, -17, 34, + 52, 82, -23, 53, 77, -21, 57, 67, -15, 62, 53, -8, + 69, 36, 2, 76, 19, 13, 84, 2, 23, 92, -14, 35, + 53, 84, -21, 55, 79, -18, 58, 69, -13, 63, 56, -6, + 70, 39, 4, 77, 23, 14, 85, 6, 25, 93, -11, 36, + 55, 85, -18, 56, 81, -16, 60, 71, -11, 65, 58, -4, + 71, 42, 5, 78, 26, 15, 85, 9, 26, 94, -8, 37, + 56, 87, -16, 58, 82, -13, 61, 73, -9, 66, 61, -2, + 72, 45, 7, 79, 29, 17, 86, 12, 27, 94, -5, 38, + 21, 56, -79, 26, 41, -70, 35, 19, -57, 44, -2, -41, + 54, -21, -25, 64, -36, -10, 74, -50, 4, 84, -63, 19, + 21, 56, -79, 27, 41, -70, 35, 20, -56, 44, -1, -41, + 54, -20, -25, 64, -36, -10, 74, -50, 4, 84, -63, 19, + 22, 56, -78, 27, 41, -70, 35, 20, -56, 44, -1, -41, + 55, -20, -25, 64, -36, -10, 74, -50, 5, 84, -62, 19, + 22, 56, -78, 27, 41, -69, 35, 21, -56, 44, 0, -41, + 55, -19, -25, 65, -35, -10, 74, -49, 5, 84, -62, 19, + 22, 57, -77, 27, 42, -69, 35, 21, -56, 45, 0, -41, + 55, -19, -25, 65, -35, -10, 74, -49, 5, 85, -62, 19, + 23, 57, -76, 28, 43, -68, 36, 22, -55, 45, 1, -40, + 55, -18, -24, 65, -34, -10, 75, -48, 5, 85, -61, 19, + 23, 57, -75, 28, 43, -67, 36, 23, -54, 45, 2, -40, + 55, -17, -24, 65, -33, -9, 75, -47, 5, 85, -60, 19, + 24, 58, -74, 29, 44, -66, 36, 25, -54, 45, 4, -39, + 55, -15, -24, 65, -32, -9, 75, -46, 5, 85, -59, 19, + 25, 58, -72, 30, 45, -65, 37, 26, -53, 46, 5, -39, + 56, -14, -23, 65, -30, -9, 75, -45, 6, 85, -58, 20, + 26, 59, -71, 30, 46, -64, 37, 27, -52, 46, 7, -38, + 56, -12, -23, 66, -29, -8, 75, -44, 6, 85, -57, 20, + 27, 60, -69, 31, 48, -62, 38, 29, -51, 47, 9, -37, + 56, -11, -22, 66, -27, -8, 75, -42, 6, 85, -56, 20, + 28, 60, -67, 32, 49, -61, 39, 31, -50, 47, 11, -36, + 57, -9, -22, 66, -26, -7, 76, -41, 7, 85, -55, 20, + 29, 61, -65, 33, 50, -59, 40, 33, -48, 48, 13, -35, + 57, -6, -21, 66, -24, -7, 76, -39, 7, 86, -53, 21, + 30, 62, -63, 34, 52, -57, 40, 35, -47, 48, 15, -34, + 58, -4, -20, 67, -21, -6, 76, -37, 8, 86, -51, 21, + 32, 63, -61, 35, 53, -56, 41, 37, -46, 49, 18, -33, + 58, -2, -19, 67, -19, -6, 77, -35, 8, 86, -49, 22, + 33, 64, -59, 36, 55, -54, 42, 39, -44, 50, 20, -32, + 59, 1, -19, 68, -17, -5, 77, -33, 9, 86, -48, 22, + 34, 66, -57, 37, 57, -52, 43, 41, -43, 51, 23, -31, + 59, 3, -17, 68, -14, -4, 77, -30, 9, 87, -45, 23, + 36, 67, -54, 39, 58, -50, 44, 43, -41, 51, 25, -30, + 60, 6, -16, 69, -12, -3, 78, -28, 10, 87, -43, 23, + 37, 68, -52, 40, 60, -48, 45, 45, -39, 52, 28, -28, + 60, 9, -15, 69, -9, -2, 78, -25, 10, 88, -41, 24, + 38, 69, -50, 41, 62, -45, 46, 48, -38, 53, 30, -27, + 61, 11, -14, 70, -6, -2, 79, -23, 11, 88, -39, 24, + 40, 71, -47, 43, 63, -43, 47, 50, -36, 54, 33, -25, + 62, 14, -13, 70, -3, -1, 79, -20, 12, 88, -36, 25, + 41, 72, -45, 44, 65, -41, 49, 52, -34, 55, 36, -24, + 63, 17, -12, 71, -1, 0, 80, -17, 13, 89, -33, 25, + 43, 74, -42, 45, 67, -39, 50, 54, -32, 56, 38, -22, + 63, 20, -11, 72, 2, 1, 80, -15, 14, 89, -31, 26, + 44, 75, -40, 47, 69, -37, 51, 57, -30, 57, 41, -21, + 64, 23, -9, 72, 5, 2, 81, -12, 14, 90, -28, 27, + 46, 77, -38, 48, 70, -34, 52, 59, -28, 58, 43, -19, + 65, 26, -8, 73, 8, 4, 81, -9, 15, 90, -25, 28, + 47, 78, -35, 50, 72, -32, 53, 61, -26, 59, 46, -17, + 66, 29, -6, 74, 11, 5, 82, -6, 16, 91, -22, 28, + 49, 80, -32, 51, 74, -29, 55, 63, -24, 60, 49, -15, + 67, 32, -5, 75, 14, 6, 83, -3, 17, 91, -19, 29, + 50, 81, -30, 52, 76, -27, 56, 66, -22, 61, 51, -14, + 68, 35, -4, 75, 17, 7, 83, 0, 18, 92, -16, 30, + 52, 83, -28, 54, 78, -25, 57, 68, -20, 62, 54, -12, + 69, 37, -2, 76, 20, 8, 84, 3, 19, 92, -13, 31, + 54, 84, -25, 55, 80, -22, 59, 70, -17, 64, 57, -10, + 70, 40, 0, 77, 24, 10, 85, 7, 21, 93, -10, 32, + 55, 86, -22, 57, 81, -20, 60, 72, -15, 65, 59, -8, + 71, 43, 1, 78, 27, 11, 85, 10, 22, 94, -7, 33, + 57, 88, -20, 58, 83, -18, 61, 74, -13, 66, 62, -6, + 72, 46, 3, 79, 30, 13, 86, 13, 23, 94, -4, 34, + 22, 58, -82, 27, 43, -73, 35, 23, -60, 45, 2, -45, + 55, -18, -29, 65, -34, -14, 74, -48, 0, 85, -61, 15, + 22, 58, -81, 27, 44, -73, 35, 23, -60, 45, 2, -45, + 55, -17, -29, 65, -34, -14, 75, -48, 0, 85, -61, 15, + 23, 58, -81, 28, 44, -73, 36, 23, -60, 45, 2, -45, + 55, -17, -29, 65, -33, -14, 75, -48, 1, 85, -61, 15, + 23, 59, -81, 28, 44, -72, 36, 24, -60, 45, 3, -45, + 55, -17, -29, 65, -33, -14, 75, -47, 1, 85, -60, 15, + 23, 59, -80, 28, 45, -72, 36, 24, -59, 45, 4, -45, + 55, -16, -29, 65, -32, -14, 75, -47, 1, 85, -60, 15, + 24, 59, -79, 29, 45, -71, 36, 25, -59, 45, 4, -44, + 55, -15, -29, 65, -32, -14, 75, -46, 1, 85, -59, 15, + 24, 59, -78, 29, 46, -70, 37, 26, -58, 46, 5, -44, + 55, -14, -28, 65, -31, -13, 75, -45, 1, 85, -59, 15, + 25, 60, -77, 30, 47, -69, 37, 27, -57, 46, 7, -43, + 56, -13, -28, 65, -29, -13, 75, -44, 1, 85, -58, 16, + 26, 60, -75, 30, 48, -68, 37, 29, -57, 46, 8, -43, + 56, -11, -27, 66, -28, -13, 75, -43, 2, 85, -57, 16, + 27, 61, -74, 31, 49, -67, 38, 30, -56, 47, 10, -42, + 56, -10, -27, 66, -27, -12, 75, -42, 2, 85, -56, 16, + 28, 62, -72, 32, 50, -66, 39, 32, -55, 47, 11, -41, + 57, -8, -26, 66, -25, -12, 76, -40, 2, 85, -54, 16, + 29, 62, -71, 33, 51, -64, 39, 33, -54, 48, 13, -40, + 57, -6, -26, 66, -23, -11, 76, -39, 3, 86, -53, 17, + 30, 63, -69, 34, 52, -63, 40, 35, -52, 48, 16, -39, + 57, -4, -25, 67, -21, -11, 76, -37, 3, 86, -51, 17, + 31, 64, -67, 35, 54, -61, 41, 37, -51, 49, 18, -38, + 58, -2, -24, 67, -19, -10, 76, -35, 3, 86, -50, 17, + 32, 65, -65, 36, 55, -59, 42, 39, -50, 49, 20, -37, + 58, 0, -23, 67, -17, -10, 77, -33, 4, 86, -48, 18, + 34, 66, -63, 37, 57, -58, 43, 41, -48, 50, 22, -36, + 59, 3, -23, 68, -15, -9, 77, -31, 5, 87, -46, 18, + 35, 67, -60, 38, 58, -55, 44, 43, -47, 51, 25, -35, + 60, 5, -22, 68, -12, -8, 78, -29, 5, 87, -44, 19, + 36, 68, -58, 39, 60, -53, 45, 45, -45, 52, 27, -34, + 60, 8, -21, 69, -10, -7, 78, -26, 6, 87, -42, 19, + 38, 69, -56, 40, 61, -51, 46, 47, -43, 52, 30, -32, + 61, 10, -20, 69, -7, -7, 78, -24, 6, 88, -39, 20, + 39, 71, -54, 42, 63, -49, 47, 49, -42, 53, 32, -31, + 61, 13, -18, 70, -5, -6, 79, -21, 7, 88, -37, 20, + 41, 72, -51, 43, 65, -47, 48, 52, -40, 54, 35, -29, + 62, 16, -17, 71, -2, -5, 79, -18, 8, 88, -34, 21, + 42, 73, -49, 44, 66, -45, 49, 54, -38, 55, 37, -28, + 63, 19, -16, 71, 1, -4, 80, -16, 9, 89, -32, 22, + 43, 75, -46, 46, 68, -43, 50, 56, -36, 56, 40, -26, + 64, 22, -15, 72, 4, -3, 80, -13, 10, 89, -29, 22, + 45, 76, -44, 47, 70, -41, 51, 58, -34, 57, 42, -25, + 65, 24, -13, 73, 7, -2, 81, -10, 10, 90, -27, 23, + 46, 78, -42, 48, 72, -38, 52, 60, -32, 58, 45, -23, + 65, 27, -12, 73, 9, -1, 81, -8, 11, 90, -24, 24, + 48, 79, -39, 50, 73, -36, 54, 62, -30, 59, 48, -21, + 66, 30, -11, 74, 13, 1, 82, -4, 12, 91, -21, 25, + 49, 81, -37, 51, 75, -34, 55, 65, -28, 60, 50, -19, + 67, 33, -9, 75, 16, 2, 83, -1, 13, 91, -18, 25, + 51, 82, -34, 53, 77, -31, 56, 67, -26, 61, 53, -18, + 68, 36, -8, 76, 19, 3, 83, 2, 14, 92, -15, 26, + 52, 84, -32, 54, 79, -29, 58, 69, -24, 63, 55, -16, + 69, 38, -6, 76, 21, 4, 84, 4, 15, 93, -12, 27, + 54, 85, -29, 56, 81, -26, 59, 71, -21, 64, 58, -14, + 70, 42, -4, 77, 25, 6, 85, 8, 17, 93, -9, 28, + 55, 87, -27, 57, 82, -24, 60, 73, -19, 65, 60, -12, + 71, 44, -3, 78, 28, 7, 86, 11, 18, 94, -6, 29, + 57, 88, -24, 58, 84, -22, 62, 75, -17, 66, 63, -10, + 72, 47, -1, 79, 31, 9, 86, 14, 19, 94, -3, 30, + 23, 60, -85, 28, 46, -77, 36, 26, -64, 45, 5, -49, + 55, -15, -33, 65, -31, -18, 75, -46, -4, 85, -59, 11, + 24, 61, -84, 28, 46, -76, 36, 26, -64, 45, 5, -49, + 55, -15, -33, 65, -31, -18, 75, -46, -4, 85, -59, 11, + 24, 61, -84, 29, 47, -76, 36, 26, -64, 45, 5, -49, + 55, -14, -33, 65, -31, -18, 75, -45, -3, 85, -59, 11, + 24, 61, -83, 29, 47, -76, 36, 27, -63, 45, 6, -49, + 55, -14, -33, 65, -30, -18, 75, -45, -3, 85, -58, 11, + 25, 61, -83, 29, 47, -75, 37, 27, -63, 46, 7, -48, + 55, -13, -33, 65, -30, -18, 75, -44, -3, 85, -58, 11, + 25, 61, -82, 29, 48, -75, 37, 28, -62, 46, 7, -48, + 56, -12, -33, 65, -29, -18, 75, -44, -3, 85, -57, 11, + 26, 62, -81, 30, 49, -74, 37, 29, -62, 46, 8, -48, + 56, -11, -32, 65, -28, -17, 75, -43, -3, 85, -57, 11, + 26, 62, -80, 31, 49, -73, 38, 30, -61, 46, 10, -47, + 56, -10, -32, 66, -27, -17, 75, -42, -3, 85, -56, 12, + 27, 62, -79, 31, 50, -72, 38, 31, -60, 47, 11, -47, + 56, -9, -31, 66, -26, -17, 75, -41, -2, 85, -55, 12, + 28, 63, -77, 32, 51, -71, 39, 33, -59, 47, 13, -46, + 57, -7, -31, 66, -24, -16, 76, -40, -2, 85, -54, 12, + 29, 63, -76, 33, 52, -69, 39, 34, -59, 48, 14, -45, + 57, -6, -30, 66, -23, -16, 76, -38, -2, 86, -53, 12, + 30, 64, -74, 33, 53, -68, 40, 36, -57, 48, 16, -44, + 57, -4, -30, 67, -21, -15, 76, -37, -1, 86, -51, 13, + 31, 65, -72, 34, 55, -66, 41, 38, -56, 49, 18, -43, + 58, -2, -29, 67, -19, -15, 76, -35, -1, 86, -50, 13, + 32, 66, -70, 35, 56, -65, 41, 39, -55, 49, 20, -42, + 58, 0, -28, 67, -17, -14, 77, -33, -1, 86, -48, 13, + 33, 67, -68, 36, 57, -63, 42, 41, -54, 50, 22, -41, + 59, 2, -28, 68, -15, -14, 77, -31, 0, 87, -46, 14, + 34, 68, -66, 37, 58, -61, 43, 43, -52, 50, 24, -40, + 59, 5, -27, 68, -13, -13, 77, -29, 1, 87, -44, 14, + 36, 69, -64, 39, 60, -59, 44, 45, -50, 51, 27, -39, + 60, 7, -26, 69, -10, -12, 78, -27, 1, 87, -42, 15, + 37, 70, -62, 40, 61, -57, 45, 47, -49, 52, 29, -38, + 60, 10, -25, 69, -8, -11, 78, -25, 2, 87, -40, 15, + 38, 71, -60, 41, 63, -55, 46, 49, -47, 53, 31, -36, + 61, 12, -24, 70, -6, -11, 79, -22, 2, 88, -38, 16, + 40, 72, -57, 42, 65, -53, 47, 51, -46, 54, 34, -35, + 62, 15, -23, 70, -3, -10, 79, -20, 3, 88, -36, 16, + 41, 73, -55, 44, 66, -51, 48, 53, -44, 55, 36, -33, + 63, 18, -21, 71, 0, -9, 80, -17, 4, 89, -33, 17, + 42, 75, -53, 45, 68, -49, 49, 55, -42, 56, 39, -32, + 63, 20, -20, 71, 3, -8, 80, -14, 5, 89, -30, 18, + 44, 76, -50, 46, 69, -47, 50, 57, -40, 57, 41, -30, + 64, 23, -19, 72, 5, -7, 81, -12, 6, 90, -28, 18, + 45, 77, -48, 47, 71, -45, 52, 59, -38, 57, 44, -29, + 65, 26, -18, 73, 8, -6, 81, -9, 6, 90, -25, 19, + 47, 79, -46, 49, 73, -42, 53, 61, -36, 58, 46, -27, + 66, 28, -16, 73, 11, -5, 82, -6, 7, 90, -23, 20, + 48, 80, -43, 50, 75, -40, 54, 64, -34, 60, 49, -25, + 67, 32, -15, 74, 14, -3, 82, -3, 8, 91, -20, 21, + 50, 82, -41, 52, 76, -38, 55, 66, -32, 61, 51, -24, + 68, 34, -13, 75, 17, -2, 83, 0, 9, 92, -17, 22, + 51, 83, -38, 53, 78, -35, 57, 68, -30, 62, 54, -22, + 68, 37, -12, 76, 20, -1, 84, 3, 10, 92, -14, 22, + 53, 85, -36, 54, 80, -33, 58, 70, -28, 63, 56, -20, + 69, 40, -10, 77, 23, 0, 84, 6, 11, 93, -11, 23, + 54, 86, -33, 56, 81, -31, 59, 72, -25, 64, 59, -18, + 70, 43, -9, 77, 26, 2, 85, 9, 13, 93, -8, 24, + 56, 88, -31, 57, 83, -28, 61, 74, -23, 65, 61, -16, + 71, 45, -7, 78, 29, 3, 86, 12, 14, 94, -5, 25, + 57, 89, -28, 59, 85, -26, 62, 76, -21, 66, 64, -14, + 72, 48, -5, 79, 32, 4, 87, 15, 15, 95, -2, 26, + 25, 63, -87, 29, 49, -80, 37, 29, -68, 46, 8, -53, + 55, -12, -37, 65, -29, -22, 75, -44, -8, 85, -57, 7, + 25, 63, -87, 29, 49, -80, 37, 29, -67, 46, 8, -53, + 56, -12, -37, 65, -28, -22, 75, -43, -8, 85, -57, 7, + 25, 63, -87, 29, 49, -79, 37, 30, -67, 46, 9, -53, + 56, -11, -37, 65, -28, -22, 75, -43, -7, 85, -57, 7, + 25, 63, -86, 30, 50, -79, 37, 30, -67, 46, 9, -53, + 56, -11, -37, 65, -28, -22, 75, -43, -7, 85, -56, 7, + 26, 63, -86, 30, 50, -78, 37, 31, -67, 46, 10, -52, + 56, -10, -37, 65, -27, -22, 75, -42, -7, 85, -56, 7, + 26, 63, -85, 30, 51, -78, 37, 31, -66, 46, 10, -52, + 56, -9, -37, 66, -26, -22, 75, -42, -7, 85, -55, 7, + 27, 64, -84, 31, 51, -77, 38, 32, -66, 46, 11, -52, + 56, -8, -36, 66, -26, -21, 75, -41, -7, 85, -55, 7, + 27, 64, -83, 31, 52, -76, 38, 33, -65, 47, 13, -51, + 56, -7, -36, 66, -25, -21, 75, -40, -7, 85, -54, 8, + 28, 64, -82, 32, 53, -75, 39, 34, -64, 47, 14, -50, + 57, -6, -35, 66, -23, -21, 76, -39, -6, 85, -53, 8, + 29, 65, -80, 33, 53, -74, 39, 35, -63, 48, 15, -50, + 57, -5, -35, 66, -22, -20, 76, -38, -6, 86, -52, 8, + 30, 65, -79, 33, 54, -73, 40, 37, -62, 48, 17, -49, + 57, -3, -34, 67, -21, -20, 76, -36, -6, 86, -51, 8, + 31, 66, -77, 34, 55, -71, 40, 38, -61, 48, 18, -48, + 58, -1, -34, 67, -19, -20, 76, -35, -5, 86, -49, 9, + 32, 67, -75, 35, 57, -70, 41, 40, -60, 49, 20, -47, + 58, 1, -33, 67, -17, -19, 77, -33, -5, 86, -48, 9, + 33, 68, -74, 36, 58, -68, 42, 42, -59, 50, 22, -46, + 59, 3, -32, 68, -15, -18, 77, -31, -5, 86, -46, 9, + 34, 68, -72, 37, 59, -67, 43, 43, -57, 50, 24, -45, + 59, 5, -32, 68, -13, -18, 77, -29, -4, 87, -44, 10, + 35, 69, -70, 38, 60, -65, 44, 45, -56, 51, 26, -44, + 60, 7, -31, 68, -11, -17, 78, -27, -3, 87, -43, 10, + 36, 70, -68, 39, 62, -63, 45, 47, -54, 52, 29, -43, + 60, 9, -30, 69, -9, -16, 78, -25, -3, 87, -41, 11, + 38, 71, -66, 40, 63, -61, 46, 49, -53, 52, 31, -42, + 61, 12, -29, 69, -6, -15, 78, -23, -2, 88, -38, 11, + 39, 72, -63, 42, 65, -59, 46, 51, -51, 53, 33, -40, + 61, 14, -28, 70, -4, -15, 79, -20, -2, 88, -36, 12, + 40, 74, -61, 43, 66, -57, 48, 53, -49, 54, 36, -39, + 62, 17, -27, 70, -1, -14, 79, -18, -1, 88, -34, 12, + 42, 75, -59, 44, 68, -55, 49, 55, -47, 55, 38, -37, + 63, 20, -25, 71, 2, -13, 80, -15, 0, 89, -31, 13, + 43, 76, -56, 45, 69, -53, 50, 57, -46, 56, 41, -36, + 64, 22, -24, 72, 4, -12, 80, -13, 1, 89, -29, 14, + 44, 77, -54, 47, 71, -51, 51, 59, -44, 57, 43, -34, + 64, 25, -23, 72, 7, -11, 81, -10, 2, 90, -27, 14, + 46, 79, -52, 48, 72, -48, 52, 61, -42, 58, 45, -33, + 65, 27, -22, 73, 10, -10, 81, -7, 2, 90, -24, 15, + 47, 80, -50, 49, 74, -46, 53, 63, -40, 59, 48, -31, + 66, 30, -20, 74, 12, -9, 82, -5, 3, 91, -21, 16, + 49, 81, -47, 51, 76, -44, 55, 65, -38, 60, 50, -29, + 67, 33, -19, 74, 15, -7, 83, -2, 4, 91, -18, 17, + 50, 83, -45, 52, 77, -42, 56, 67, -36, 61, 53, -28, + 68, 36, -17, 75, 18, -6, 83, 1, 5, 92, -16, 18, + 52, 84, -42, 53, 79, -39, 57, 69, -34, 62, 55, -26, + 69, 38, -16, 76, 21, -5, 84, 4, 6, 92, -13, 18, + 53, 86, -40, 55, 81, -37, 58, 71, -32, 63, 57, -24, + 70, 41, -14, 77, 24, -4, 84, 7, 8, 93, -10, 19, + 55, 87, -37, 56, 82, -35, 60, 73, -30, 64, 60, -22, + 71, 44, -13, 78, 27, -2, 85, 10, 9, 94, -7, 20, + 56, 89, -35, 58, 84, -32, 61, 75, -27, 66, 62, -20, + 72, 47, -11, 79, 30, -1, 86, 13, 10, 94, -4, 21, + 58, 90, -32, 59, 86, -30, 62, 77, -25, 67, 65, -18, + 73, 49, -9, 79, 33, 0, 87, 16, 11, 95, -1, 22, + 26, 65, -91, 30, 52, -83, 37, 33, -71, 46, 12, -57, + 56, -8, -42, 66, -26, -27, 75, -41, -12, 85, -55, 3, + 26, 65, -90, 30, 52, -83, 38, 33, -71, 46, 12, -57, + 56, -8, -42, 66, -25, -27, 75, -41, -12, 85, -55, 3, + 26, 65, -90, 31, 52, -83, 38, 33, -71, 46, 12, -57, + 56, -8, -42, 66, -25, -27, 75, -40, -12, 85, -54, 3, + 27, 65, -89, 31, 53, -82, 38, 33, -71, 46, 13, -57, + 56, -7, -41, 66, -25, -26, 75, -40, -12, 85, -54, 3, + 27, 65, -89, 31, 53, -82, 38, 34, -70, 47, 13, -57, + 56, -7, -41, 66, -24, -26, 75, -40, -12, 85, -54, 3, + 27, 66, -88, 31, 53, -81, 38, 35, -70, 47, 14, -56, + 56, -6, -41, 66, -24, -26, 75, -39, -12, 85, -53, 3, + 28, 66, -87, 32, 54, -81, 39, 35, -70, 47, 15, -56, + 57, -5, -41, 66, -23, -26, 76, -38, -11, 85, -53, 3, + 28, 66, -86, 32, 55, -80, 39, 36, -69, 47, 16, -55, + 57, -4, -40, 66, -22, -26, 76, -37, -11, 86, -52, 3, + 29, 67, -85, 33, 55, -79, 39, 37, -68, 48, 17, -55, + 57, -3, -40, 66, -21, -25, 76, -36, -11, 86, -51, 3, + 30, 67, -84, 34, 56, -78, 40, 38, -67, 48, 18, -54, + 57, -2, -39, 67, -19, -25, 76, -35, -11, 86, -50, 4, + 31, 68, -82, 34, 57, -77, 41, 40, -66, 48, 20, -53, + 58, 0, -39, 67, -18, -24, 76, -34, -10, 86, -49, 4, + 32, 68, -81, 35, 58, -75, 41, 41, -65, 49, 21, -53, + 58, 1, -38, 67, -16, -24, 77, -32, -10, 86, -47, 4, + 33, 69, -79, 36, 59, -74, 42, 43, -64, 50, 23, -52, + 58, 3, -37, 68, -14, -23, 77, -31, -9, 86, -46, 5, + 34, 70, -77, 37, 60, -72, 43, 44, -63, 50, 25, -51, + 59, 5, -37, 68, -13, -23, 77, -29, -9, 87, -44, 5, + 35, 70, -76, 38, 61, -71, 43, 46, -61, 51, 27, -50, + 59, 7, -36, 68, -11, -22, 77, -27, -8, 87, -42, 5, + 36, 71, -74, 39, 62, -69, 44, 47, -60, 51, 29, -49, + 60, 9, -35, 69, -9, -22, 78, -25, -8, 87, -41, 6, + 37, 72, -72, 40, 64, -67, 45, 49, -58, 52, 31, -47, + 61, 12, -34, 69, -6, -21, 78, -23, -7, 88, -39, 6, + 38, 73, -70, 41, 65, -65, 46, 51, -57, 53, 33, -46, + 61, 14, -33, 70, -4, -20, 79, -21, -7, 88, -37, 7, + 40, 74, -67, 42, 66, -63, 47, 53, -55, 54, 36, -45, + 62, 16, -32, 70, -2, -19, 79, -18, -6, 88, -34, 7, + 41, 75, -65, 43, 68, -61, 48, 55, -54, 55, 38, -43, + 62, 19, -31, 71, 1, -18, 79, -16, -5, 89, -32, 8, + 42, 76, -63, 45, 69, -59, 49, 57, -52, 55, 40, -42, + 63, 22, -30, 71, 4, -17, 80, -13, -4, 89, -30, 9, + 44, 78, -61, 46, 71, -57, 50, 59, -50, 56, 42, -40, + 64, 24, -29, 72, 6, -16, 80, -11, -4, 89, -27, 9, + 45, 79, -58, 47, 72, -55, 51, 61, -48, 57, 45, -39, + 65, 27, -27, 73, 9, -15, 81, -8, -3, 90, -25, 10, + 46, 80, -56, 48, 74, -53, 52, 62, -46, 58, 47, -37, + 65, 29, -26, 73, 11, -14, 82, -6, -2, 90, -22, 11, + 48, 81, -54, 50, 75, -51, 54, 64, -44, 59, 49, -36, + 66, 32, -25, 74, 14, -13, 82, -3, -1, 91, -20, 12, + 49, 83, -51, 51, 77, -48, 55, 66, -42, 60, 52, -34, + 67, 35, -23, 75, 17, -12, 83, 0, 0, 91, -17, 12, + 51, 84, -49, 53, 79, -46, 56, 68, -40, 61, 54, -32, + 68, 37, -22, 75, 20, -11, 83, 3, 1, 92, -14, 13, + 52, 85, -47, 54, 80, -44, 57, 70, -38, 62, 57, -30, + 69, 40, -20, 76, 23, -9, 84, 6, 2, 92, -11, 14, + 54, 87, -44, 55, 82, -42, 59, 72, -36, 64, 59, -29, + 70, 42, -19, 77, 25, -8, 85, 8, 3, 93, -9, 15, + 55, 88, -42, 57, 84, -39, 60, 74, -34, 65, 61, -27, + 71, 45, -17, 78, 29, -7, 85, 12, 4, 94, -5, 16, + 57, 90, -39, 58, 85, -37, 61, 76, -32, 66, 64, -25, + 72, 48, -16, 79, 31, -5, 86, 14, 5, 94, -3, 17, + 58, 91, -37, 60, 87, -35, 63, 78, -30, 67, 66, -23, + 73, 50, -14, 80, 34, -4, 87, 17, 7, 95, 0, 18, + 27, 67, -93, 31, 55, -86, 38, 36, -75, 47, 15, -61, + 56, -5, -46, 66, -23, -31, 75, -39, -16, 85, -53, -1, + 27, 67, -93, 31, 55, -86, 38, 36, -75, 47, 15, -61, + 56, -5, -46, 66, -23, -31, 75, -38, -16, 85, -53, -1, + 27, 67, -93, 31, 55, -86, 38, 36, -75, 47, 15, -61, + 56, -5, -45, 66, -23, -31, 76, -38, -16, 85, -52, -1, + 28, 67, -92, 32, 55, -86, 38, 36, -74, 47, 16, -60, + 56, -4, -45, 66, -22, -30, 76, -38, -16, 85, -52, -1, + 28, 67, -92, 32, 56, -85, 39, 37, -74, 47, 16, -60, + 57, -4, -45, 66, -22, -30, 76, -37, -16, 85, -52, -1, + 28, 68, -91, 32, 56, -85, 39, 37, -74, 47, 17, -60, + 57, -3, -45, 66, -21, -30, 76, -37, -16, 86, -51, -1, + 29, 68, -90, 33, 56, -84, 39, 38, -73, 48, 18, -60, + 57, -2, -45, 66, -20, -30, 76, -36, -15, 86, -50, -1, + 29, 68, -89, 33, 57, -83, 40, 39, -72, 48, 19, -59, + 57, -1, -44, 67, -19, -30, 76, -35, -15, 86, -50, -1, + 30, 69, -88, 34, 58, -82, 40, 40, -72, 48, 20, -58, + 57, 0, -44, 67, -18, -29, 76, -34, -15, 86, -49, 0, + 31, 69, -87, 34, 58, -81, 41, 41, -71, 49, 21, -58, + 58, 1, -43, 67, -17, -29, 76, -33, -15, 86, -48, 0, + 32, 69, -86, 35, 59, -80, 41, 42, -70, 49, 23, -57, + 58, 2, -43, 67, -15, -28, 77, -32, -14, 86, -47, 0, + 32, 70, -84, 36, 60, -79, 42, 43, -69, 49, 24, -56, + 58, 4, -42, 68, -14, -28, 77, -30, -14, 86, -45, 0, + 34, 71, -82, 37, 61, -77, 42, 45, -68, 50, 26, -55, + 59, 6, -41, 68, -12, -27, 77, -29, -13, 87, -44, 1, + 34, 71, -81, 38, 62, -76, 43, 46, -66, 51, 28, -54, + 59, 8, -41, 68, -10, -27, 77, -27, -13, 87, -42, 1, + 36, 72, -79, 39, 63, -74, 44, 48, -65, 51, 29, -53, + 60, 10, -40, 69, -8, -26, 78, -25, -12, 87, -41, 2, + 37, 73, -77, 39, 64, -72, 45, 49, -64, 52, 31, -52, + 60, 12, -39, 69, -6, -26, 78, -23, -12, 87, -39, 2, + 38, 74, -75, 41, 66, -70, 46, 51, -62, 53, 33, -51, + 61, 14, -38, 69, -4, -25, 78, -21, -11, 88, -37, 2, + 39, 75, -73, 42, 67, -69, 47, 53, -61, 53, 35, -50, + 61, 16, -37, 70, -2, -24, 79, -19, -11, 88, -35, 3, + 40, 76, -71, 43, 68, -67, 48, 55, -59, 54, 38, -49, + 62, 18, -36, 70, 0, -23, 79, -17, -10, 88, -33, 4, + 42, 77, -69, 44, 69, -65, 49, 56, -57, 55, 40, -47, + 63, 21, -35, 71, 3, -22, 80, -14, -9, 89, -31, 4, + 43, 78, -67, 45, 71, -63, 50, 58, -56, 56, 42, -46, + 64, 23, -34, 72, 5, -21, 80, -12, -8, 89, -28, 5, + 44, 79, -64, 46, 72, -61, 51, 60, -54, 57, 44, -44, + 64, 26, -33, 72, 8, -20, 81, -9, -8, 90, -26, 5, + 46, 80, -62, 48, 74, -59, 52, 62, -52, 58, 46, -43, + 65, 28, -31, 73, 10, -19, 81, -7, -7, 90, -23, 6, + 47, 81, -60, 49, 75, -57, 53, 64, -50, 59, 49, -41, + 66, 31, -30, 74, 13, -18, 82, -4, -6, 91, -21, 7, + 48, 82, -58, 50, 77, -54, 54, 66, -48, 60, 51, -40, + 67, 33, -29, 74, 16, -17, 82, -2, -5, 91, -18, 8, + 50, 84, -55, 52, 78, -52, 55, 68, -46, 61, 53, -38, + 68, 36, -27, 75, 19, -16, 83, 1, -4, 92, -15, 8, + 51, 85, -53, 53, 80, -50, 57, 70, -44, 62, 56, -36, + 68, 39, -26, 76, 21, -15, 84, 4, -3, 92, -13, 9, + 53, 86, -51, 54, 81, -48, 58, 72, -42, 63, 58, -34, + 69, 41, -24, 76, 24, -13, 84, 7, -2, 93, -10, 10, + 54, 88, -48, 56, 83, -46, 59, 73, -40, 64, 60, -33, + 70, 44, -23, 77, 27, -12, 85, 10, -1, 93, -7, 11, + 56, 89, -46, 57, 85, -43, 60, 76, -38, 65, 63, -31, + 71, 47, -21, 78, 30, -11, 86, 13, 0, 94, -4, 12, + 57, 91, -43, 59, 86, -41, 62, 77, -36, 66, 65, -29, + 72, 49, -20, 79, 33, -9, 86, 16, 1, 94, -1, 13, + 58, 92, -41, 60, 88, -39, 63, 79, -34, 67, 67, -27, + 73, 52, -18, 80, 35, -8, 87, 18, 3, 95, 1, 14, + 28, 69, -96, 32, 57, -89, 39, 39, -78, 47, 18, -65, + 57, -2, -49, 66, -20, -35, 76, -36, -20, 86, -51, -5, + 28, 69, -96, 32, 57, -89, 39, 39, -78, 47, 18, -64, + 57, -2, -49, 66, -20, -34, 76, -36, -20, 86, -50, -5, + 29, 69, -95, 32, 58, -89, 39, 39, -78, 47, 18, -64, + 57, -2, -49, 66, -20, -34, 76, -36, -20, 86, -50, -5, + 29, 69, -95, 33, 58, -89, 39, 39, -78, 48, 19, -64, + 57, -2, -49, 66, -19, -34, 76, -35, -20, 86, -50, -5, + 29, 69, -95, 33, 58, -88, 39, 40, -77, 48, 19, -64, + 57, -1, -49, 66, -19, -34, 76, -35, -20, 86, -49, -5, + 29, 70, -94, 33, 58, -88, 40, 40, -77, 48, 20, -64, + 57, 0, -49, 67, -18, -34, 76, -34, -19, 86, -49, -5, + 30, 70, -93, 34, 59, -87, 40, 41, -76, 48, 21, -63, + 57, 0, -48, 67, -17, -34, 76, -34, -19, 86, -48, -5, + 30, 70, -92, 34, 59, -86, 40, 42, -76, 48, 22, -63, + 58, 2, -48, 67, -16, -33, 76, -33, -19, 86, -47, -5, + 31, 71, -91, 35, 60, -85, 41, 43, -75, 49, 23, -62, + 58, 3, -48, 67, -15, -33, 76, -32, -19, 86, -47, -4, + 32, 71, -90, 35, 61, -84, 41, 44, -74, 49, 24, -62, + 58, 4, -47, 67, -14, -33, 77, -31, -18, 86, -46, -4, + 33, 71, -89, 36, 61, -83, 42, 45, -73, 50, 25, -61, + 58, 5, -47, 68, -13, -32, 77, -29, -18, 86, -45, -4, + 33, 72, -87, 37, 62, -82, 42, 46, -72, 50, 27, -60, + 59, 7, -46, 68, -11, -32, 77, -28, -18, 87, -43, -4, + 34, 72, -86, 37, 63, -80, 43, 47, -71, 51, 28, -59, + 59, 8, -45, 68, -10, -31, 77, -26, -17, 87, -42, -3, + 35, 73, -84, 38, 64, -79, 44, 49, -70, 51, 30, -58, + 60, 10, -45, 69, -8, -31, 78, -25, -17, 87, -40, -3, + 36, 74, -82, 39, 65, -77, 45, 50, -69, 52, 32, -57, + 60, 12, -44, 69, -6, -30, 78, -23, -16, 87, -39, -2, + 37, 74, -80, 40, 66, -76, 45, 52, -67, 52, 34, -56, + 61, 14, -43, 69, -4, -29, 78, -21, -16, 88, -37, -2, + 39, 75, -78, 41, 67, -74, 46, 53, -66, 53, 36, -55, + 61, 16, -42, 70, -2, -29, 79, -19, -15, 88, -35, -1, + 40, 76, -76, 42, 69, -72, 47, 55, -64, 54, 38, -54, + 62, 18, -41, 70, 0, -28, 79, -17, -15, 88, -33, -1, + 41, 77, -74, 43, 70, -70, 48, 57, -63, 55, 40, -52, + 62, 21, -40, 71, 2, -27, 79, -15, -14, 89, -31, 0, + 42, 78, -72, 45, 71, -69, 49, 58, -61, 55, 42, -51, + 63, 23, -39, 71, 5, -26, 80, -12, -13, 89, -29, 0, + 44, 79, -70, 46, 73, -66, 50, 60, -59, 56, 44, -50, + 64, 25, -38, 72, 7, -25, 80, -10, -12, 89, -26, 1, + 45, 80, -68, 47, 74, -64, 51, 62, -58, 57, 46, -48, + 65, 28, -37, 73, 10, -24, 81, -7, -12, 90, -24, 2, + 46, 81, -66, 48, 75, -62, 52, 64, -56, 58, 48, -47, + 65, 30, -35, 73, 12, -23, 81, -5, -11, 90, -22, 2, + 47, 83, -64, 49, 77, -60, 53, 65, -54, 59, 50, -45, + 66, 33, -34, 74, 15, -22, 82, -2, -10, 91, -19, 3, + 49, 84, -61, 51, 78, -58, 55, 67, -52, 60, 52, -44, + 67, 35, -33, 74, 17, -21, 83, 0, -9, 91, -17, 4, + 50, 85, -59, 52, 80, -56, 56, 69, -50, 61, 55, -42, + 68, 38, -31, 75, 20, -20, 83, 3, -8, 92, -14, 5, + 52, 86, -57, 53, 81, -54, 57, 71, -48, 62, 57, -40, + 69, 40, -30, 76, 23, -19, 84, 6, -7, 92, -11, 5, + 53, 88, -54, 55, 83, -52, 58, 73, -46, 63, 59, -38, + 70, 43, -28, 77, 26, -17, 84, 8, -6, 93, -9, 6, + 54, 89, -52, 56, 84, -49, 59, 75, -44, 64, 61, -37, + 70, 45, -27, 78, 28, -16, 85, 11, -5, 93, -6, 7, + 56, 90, -49, 58, 86, -47, 61, 77, -42, 65, 64, -35, + 72, 48, -25, 78, 31, -15, 86, 14, -4, 94, -3, 8, + 57, 92, -47, 59, 87, -45, 62, 79, -40, 67, 66, -33, + 72, 50, -24, 79, 34, -13, 87, 17, -3, 95, 0, 9, + 59, 93, -45, 60, 89, -42, 63, 80, -38, 68, 68, -31, + 73, 53, -22, 80, 36, -12, 87, 20, -1, 95, 3, 10, + 29, 71, -99, 33, 60, -92, 40, 42, -82, 48, 21, -68, + 57, 1, -53, 67, -17, -38, 76, -34, -24, 86, -48, -9, + 29, 71, -98, 33, 60, -92, 40, 42, -81, 48, 21, -68, + 57, 1, -53, 67, -17, -38, 76, -33, -24, 86, -48, -9, + 30, 71, -98, 33, 60, -92, 40, 42, -81, 48, 22, -68, + 57, 1, -53, 67, -17, -38, 76, -33, -24, 86, -48, -9, + 30, 71, -98, 34, 60, -92, 40, 42, -81, 48, 22, -68, + 57, 1, -53, 67, -17, -38, 76, -33, -24, 86, -48, -9, + 30, 72, -97, 34, 61, -91, 40, 43, -81, 48, 22, -68, + 57, 2, -53, 67, -16, -38, 76, -32, -23, 86, -47, -9, + 31, 72, -97, 34, 61, -91, 40, 43, -80, 48, 23, -67, + 58, 3, -52, 67, -15, -38, 76, -32, -23, 86, -47, -9, + 31, 72, -96, 34, 61, -90, 41, 44, -80, 49, 24, -67, + 58, 3, -52, 67, -15, -38, 76, -31, -23, 86, -46, -9, + 32, 72, -95, 35, 62, -89, 41, 45, -79, 49, 25, -66, + 58, 4, -52, 67, -14, -37, 77, -30, -23, 86, -45, -8, + 32, 72, -94, 35, 62, -88, 41, 45, -78, 49, 26, -66, + 58, 5, -51, 67, -13, -37, 77, -29, -23, 86, -44, -8, + 33, 73, -93, 36, 63, -87, 42, 46, -78, 50, 27, -65, + 59, 7, -51, 68, -12, -37, 77, -28, -22, 86, -44, -8, + 33, 73, -92, 37, 64, -86, 42, 47, -77, 50, 28, -64, + 59, 8, -50, 68, -10, -36, 77, -27, -22, 87, -42, -8, + 34, 74, -90, 37, 64, -85, 43, 48, -76, 50, 29, -64, + 59, 9, -50, 68, -9, -36, 77, -26, -22, 87, -41, -7, + 35, 74, -89, 38, 65, -84, 44, 50, -75, 51, 31, -63, + 60, 11, -49, 68, -7, -35, 78, -24, -21, 87, -40, -7, + 36, 75, -87, 39, 66, -82, 44, 51, -73, 52, 32, -62, + 60, 13, -48, 69, -6, -35, 78, -22, -21, 87, -38, -7, + 37, 75, -85, 40, 67, -81, 45, 52, -72, 52, 34, -61, + 61, 14, -48, 69, -4, -34, 78, -21, -20, 88, -37, -6, + 38, 76, -84, 41, 68, -79, 46, 54, -71, 53, 36, -60, + 61, 16, -47, 70, -2, -33, 79, -19, -20, 88, -35, -6, + 39, 77, -82, 42, 69, -77, 47, 55, -69, 54, 38, -59, + 62, 19, -46, 70, 0, -33, 79, -17, -19, 88, -33, -5, + 40, 78, -80, 43, 70, -76, 48, 57, -68, 54, 40, -57, + 62, 21, -45, 71, 2, -32, 79, -15, -18, 88, -31, -5, + 42, 79, -78, 44, 72, -74, 49, 58, -66, 55, 42, -56, + 63, 23, -44, 71, 4, -31, 80, -13, -18, 89, -29, -4, + 43, 80, -76, 45, 73, -72, 50, 60, -65, 56, 44, -55, + 63, 25, -43, 72, 7, -30, 80, -11, -17, 89, -27, -4, + 44, 81, -74, 46, 74, -70, 51, 62, -63, 57, 46, -53, + 64, 27, -42, 72, 9, -29, 81, -8, -16, 90, -25, -3, + 45, 82, -72, 48, 75, -68, 52, 64, -61, 58, 48, -52, + 65, 30, -40, 73, 12, -28, 81, -6, -15, 90, -22, -2, + 47, 83, -69, 49, 77, -66, 53, 65, -60, 58, 50, -50, + 66, 32, -39, 73, 14, -27, 82, -3, -15, 90, -20, -2, + 48, 84, -67, 50, 78, -64, 54, 67, -58, 59, 52, -49, + 66, 34, -38, 74, 17, -26, 82, -1, -14, 91, -18, -1, + 49, 85, -65, 51, 79, -62, 55, 69, -56, 60, 54, -47, + 67, 37, -37, 75, 19, -25, 83, 2, -13, 91, -15, 0, + 51, 86, -63, 53, 81, -60, 56, 71, -54, 61, 56, -46, + 68, 39, -35, 76, 22, -24, 83, 5, -12, 92, -12, 1, + 52, 88, -60, 54, 82, -58, 57, 72, -52, 62, 59, -44, + 69, 42, -34, 76, 24, -23, 84, 7, -11, 92, -10, 2, + 53, 89, -58, 55, 84, -55, 59, 74, -50, 63, 61, -42, + 70, 44, -32, 77, 27, -21, 85, 10, -10, 93, -7, 2, + 55, 90, -56, 56, 85, -53, 60, 76, -48, 65, 63, -41, + 71, 47, -31, 78, 30, -20, 85, 13, -9, 94, -5, 3, + 56, 92, -53, 58, 87, -51, 61, 78, -46, 66, 65, -39, + 72, 49, -29, 79, 33, -19, 86, 16, -8, 94, -2, 4, + 58, 93, -51, 59, 88, -49, 62, 80, -44, 67, 67, -37, + 73, 52, -28, 79, 35, -17, 87, 18, -6, 95, 1, 5, + 59, 94, -49, 61, 90, -46, 64, 82, -42, 68, 69, -35, + 74, 54, -26, 80, 38, -16, 88, 21, -5, 95, 4, 6, + 31, 73, -102, 34, 63, -96, 40, 45, -85, 48, 25, -72, + 58, 4, -57, 67, -14, -43, 76, -31, -28, 86, -46, -13, + 31, 73, -101, 34, 63, -95, 41, 45, -85, 49, 25, -72, + 58, 4, -57, 67, -14, -43, 76, -30, -28, 86, -46, -13, + 31, 74, -101, 34, 63, -95, 41, 45, -85, 49, 25, -72, + 58, 4, -57, 67, -14, -43, 76, -30, -28, 86, -45, -13, + 31, 74, -101, 35, 63, -95, 41, 46, -85, 49, 25, -72, + 58, 5, -57, 67, -13, -42, 76, -30, -28, 86, -45, -13, + 31, 74, -100, 35, 63, -95, 41, 46, -84, 49, 26, -72, + 58, 5, -57, 67, -13, -42, 76, -29, -28, 86, -45, -13, + 32, 74, -100, 35, 64, -94, 41, 46, -84, 49, 26, -71, + 58, 6, -57, 67, -12, -42, 77, -29, -28, 86, -44, -13, + 32, 74, -99, 36, 64, -93, 42, 47, -84, 49, 27, -71, + 58, 7, -56, 67, -12, -42, 77, -28, -28, 86, -44, -13, + 33, 74, -98, 36, 64, -93, 42, 48, -83, 50, 28, -70, + 58, 8, -56, 68, -11, -42, 77, -27, -27, 86, -43, -13, + 33, 75, -97, 36, 65, -92, 42, 48, -82, 50, 29, -70, + 59, 9, -56, 68, -10, -41, 77, -26, -27, 87, -42, -13, + 34, 75, -96, 37, 65, -91, 43, 49, -81, 50, 30, -69, + 59, 10, -55, 68, -9, -41, 77, -25, -27, 87, -41, -12, + 35, 75, -95, 38, 66, -90, 43, 50, -81, 51, 31, -69, + 59, 11, -55, 68, -7, -41, 77, -24, -26, 87, -40, -12, + 35, 76, -94, 38, 67, -89, 44, 51, -80, 51, 32, -68, + 60, 12, -54, 69, -6, -40, 78, -23, -26, 87, -39, -12, + 36, 76, -92, 39, 68, -87, 45, 52, -78, 52, 34, -67, + 60, 14, -53, 69, -4, -40, 78, -21, -26, 87, -37, -11, + 37, 77, -91, 40, 68, -86, 45, 54, -77, 52, 35, -66, + 61, 16, -53, 69, -3, -39, 78, -20, -25, 88, -36, -11, + 38, 77, -89, 41, 69, -85, 46, 55, -76, 53, 37, -65, + 61, 17, -52, 70, -1, -38, 78, -18, -25, 88, -34, -11, + 39, 78, -87, 42, 70, -83, 47, 56, -75, 53, 38, -64, + 61, 19, -51, 70, 1, -38, 79, -17, -24, 88, -33, -10, + 40, 79, -85, 43, 71, -81, 48, 58, -73, 54, 40, -63, + 62, 21, -50, 70, 3, -37, 79, -14, -23, 88, -31, -10, + 41, 80, -84, 44, 72, -80, 48, 59, -72, 55, 42, -62, + 63, 23, -49, 71, 5, -36, 80, -13, -23, 89, -29, -9, + 42, 80, -82, 45, 73, -78, 49, 61, -70, 56, 44, -60, + 63, 25, -48, 71, 7, -35, 80, -11, -22, 89, -27, -9, + 44, 81, -80, 46, 75, -76, 50, 62, -69, 56, 46, -59, + 64, 27, -47, 72, 9, -34, 80, -8, -21, 89, -25, -8, + 45, 82, -78, 47, 76, -74, 51, 64, -67, 57, 48, -58, + 65, 30, -46, 73, 11, -33, 81, -6, -21, 90, -23, -7, + 46, 83, -75, 48, 77, -72, 52, 66, -65, 58, 50, -56, + 65, 32, -45, 73, 14, -33, 81, -4, -20, 90, -20, -7, + 47, 84, -73, 49, 78, -70, 53, 67, -64, 59, 52, -55, + 66, 34, -44, 74, 16, -32, 82, -1, -19, 91, -18, -6, + 49, 85, -71, 51, 80, -68, 54, 69, -62, 60, 54, -53, + 67, 36, -42, 74, 19, -30, 82, 1, -18, 91, -16, -5, + 50, 87, -69, 52, 81, -66, 55, 70, -60, 61, 56, -52, + 68, 39, -41, 75, 21, -29, 83, 4, -17, 92, -13, -5, + 51, 88, -67, 53, 82, -64, 57, 72, -58, 62, 58, -50, + 69, 41, -39, 76, 24, -28, 84, 6, -16, 92, -11, -4, + 53, 89, -64, 54, 84, -62, 58, 74, -56, 63, 60, -48, + 69, 43, -38, 77, 26, -27, 84, 9, -15, 93, -8, -3, + 54, 90, -62, 56, 85, -60, 59, 76, -54, 64, 62, -47, + 70, 46, -37, 77, 29, -26, 85, 12, -14, 93, -6, -2, + 55, 91, -60, 57, 87, -57, 60, 77, -52, 65, 64, -45, + 71, 48, -35, 78, 31, -25, 86, 14, -13, 94, -3, -1, + 57, 93, -58, 58, 88, -55, 62, 79, -50, 66, 67, -43, + 72, 51, -34, 79, 34, -23, 86, 17, -12, 94, 0, 0, + 58, 94, -55, 60, 90, -53, 63, 81, -48, 67, 69, -41, + 73, 53, -32, 80, 37, -22, 87, 20, -11, 95, 3, 1, + 60, 95, -53, 61, 91, -51, 64, 83, -46, 68, 71, -39, + 74, 56, -30, 81, 39, -20, 88, 23, -10, 96, 5, 2, + 32, 75, -104, 35, 65, -99, 41, 48, -88, 49, 28, -76, + 58, 7, -61, 67, -11, -47, 77, -28, -32, 86, -43, -17, + 32, 75, -104, 35, 65, -98, 41, 48, -88, 49, 28, -76, + 58, 7, -61, 67, -11, -46, 77, -28, -32, 86, -43, -17, + 32, 76, -104, 35, 65, -98, 41, 48, -88, 49, 28, -75, + 58, 8, -61, 67, -11, -46, 77, -28, -32, 86, -43, -17, + 32, 76, -103, 36, 65, -98, 42, 48, -88, 49, 28, -75, + 58, 8, -61, 67, -11, -46, 77, -27, -32, 86, -43, -17, + 32, 76, -103, 36, 66, -97, 42, 49, -88, 49, 29, -75, + 58, 8, -61, 68, -10, -46, 77, -27, -32, 86, -42, -17, + 33, 76, -102, 36, 66, -97, 42, 49, -87, 50, 29, -75, + 59, 9, -60, 68, -10, -46, 77, -26, -32, 86, -42, -17, + 33, 76, -102, 36, 66, -96, 42, 50, -87, 50, 30, -74, + 59, 10, -60, 68, -9, -46, 77, -26, -31, 87, -41, -17, + 34, 76, -101, 37, 67, -96, 43, 50, -86, 50, 31, -74, + 59, 10, -60, 68, -8, -45, 77, -25, -31, 87, -41, -17, + 34, 77, -100, 37, 67, -95, 43, 51, -85, 50, 32, -73, + 59, 11, -59, 68, -7, -45, 77, -24, -31, 87, -40, -16, + 35, 77, -99, 38, 68, -94, 43, 52, -85, 51, 33, -73, + 59, 12, -59, 68, -6, -45, 77, -23, -31, 87, -39, -16, + 36, 77, -98, 39, 68, -93, 44, 53, -84, 51, 34, -72, + 60, 14, -58, 69, -5, -44, 78, -22, -30, 87, -38, -16, + 36, 78, -97, 39, 69, -92, 45, 54, -83, 52, 35, -71, + 60, 15, -58, 69, -4, -44, 78, -21, -30, 87, -37, -16, + 37, 78, -95, 40, 70, -90, 45, 55, -82, 52, 36, -70, + 61, 17, -57, 69, -2, -43, 78, -19, -29, 88, -35, -15, + 38, 79, -94, 41, 70, -89, 46, 56, -81, 53, 38, -70, + 61, 18, -56, 70, 0, -43, 78, -18, -29, 88, -34, -15, + 39, 79, -92, 42, 71, -88, 47, 57, -80, 53, 39, -69, + 61, 20, -56, 70, 1, -42, 79, -16, -28, 88, -32, -14, + 40, 80, -91, 42, 72, -86, 47, 58, -78, 54, 41, -68, + 62, 21, -55, 70, 3, -42, 79, -14, -28, 88, -31, -14, + 41, 81, -89, 44, 73, -85, 48, 60, -77, 55, 43, -66, + 62, 23, -54, 71, 5, -41, 79, -12, -27, 89, -29, -13, + 42, 81, -87, 44, 74, -83, 49, 61, -75, 55, 44, -65, + 63, 25, -53, 71, 7, -40, 80, -10, -27, 89, -27, -13, + 43, 82, -85, 45, 75, -81, 50, 63, -74, 56, 46, -64, + 64, 27, -52, 72, 9, -39, 80, -8, -26, 89, -25, -12, + 44, 83, -83, 47, 76, -79, 51, 64, -72, 57, 48, -63, + 64, 29, -51, 72, 11, -38, 81, -6, -25, 90, -23, -12, + 46, 84, -81, 48, 78, -77, 52, 66, -71, 58, 50, -61, + 65, 32, -50, 73, 14, -37, 81, -4, -24, 90, -21, -11, + 47, 85, -79, 49, 79, -76, 53, 67, -69, 59, 52, -60, + 66, 34, -49, 73, 16, -36, 82, -2, -24, 90, -19, -11, + 48, 86, -77, 50, 80, -74, 54, 69, -67, 59, 54, -58, + 66, 36, -47, 74, 18, -35, 82, 1, -23, 91, -16, -10, + 49, 87, -75, 51, 81, -72, 55, 70, -66, 60, 56, -57, + 67, 38, -46, 75, 20, -34, 83, 3, -22, 91, -14, -9, + 51, 88, -73, 52, 82, -70, 56, 72, -64, 61, 58, -55, + 68, 40, -45, 75, 23, -33, 83, 5, -21, 92, -12, -8, + 52, 89, -70, 54, 84, -67, 57, 74, -62, 62, 60, -54, + 69, 43, -43, 76, 25, -32, 84, 8, -20, 92, -9, -7, + 53, 90, -68, 55, 85, -65, 58, 75, -60, 63, 62, -52, + 70, 45, -42, 77, 28, -31, 85, 11, -19, 93, -7, -7, + 55, 91, -66, 56, 87, -63, 59, 77, -58, 64, 64, -50, + 71, 47, -40, 78, 30, -30, 85, 13, -18, 93, -4, -6, + 56, 93, -64, 57, 88, -61, 61, 79, -56, 65, 66, -49, + 71, 50, -39, 78, 33, -28, 86, 16, -17, 94, -1, -5, + 57, 94, -61, 59, 89, -59, 62, 81, -54, 67, 68, -47, + 73, 52, -37, 79, 36, -27, 87, 19, -16, 95, 1, -4, + 59, 95, -59, 60, 91, -57, 63, 82, -52, 68, 70, -45, + 73, 55, -36, 80, 38, -26, 87, 21, -15, 95, 4, -3, + 60, 96, -57, 62, 92, -54, 64, 84, -50, 69, 72, -43, + 74, 57, -34, 81, 41, -24, 88, 24, -14, 96, 7, -2, + 33, 77, -107, 36, 67, -101, 42, 51, -92, 50, 31, -79, + 59, 10, -65, 68, -8, -50, 77, -25, -36, 86, -41, -21, + 33, 77, -107, 36, 68, -101, 42, 51, -92, 50, 31, -79, + 59, 10, -65, 68, -8, -50, 77, -25, -36, 87, -41, -21, + 33, 77, -106, 36, 68, -101, 42, 51, -91, 50, 31, -79, + 59, 11, -65, 68, -8, -50, 77, -25, -36, 87, -41, -21, + 33, 78, -106, 37, 68, -101, 42, 51, -91, 50, 31, -79, + 59, 11, -64, 68, -8, -50, 77, -25, -36, 87, -40, -21, + 34, 78, -106, 37, 68, -100, 43, 52, -91, 50, 32, -78, + 59, 11, -64, 68, -7, -50, 77, -24, -35, 87, -40, -21, + 34, 78, -105, 37, 68, -100, 43, 52, -90, 50, 32, -78, + 59, 12, -64, 68, -7, -50, 77, -24, -35, 87, -40, -21, + 34, 78, -105, 37, 69, -99, 43, 52, -90, 50, 33, -78, + 59, 13, -64, 68, -6, -49, 77, -23, -35, 87, -39, -21, + 35, 78, -104, 38, 69, -99, 43, 53, -89, 51, 34, -77, + 59, 13, -63, 68, -5, -49, 77, -22, -35, 87, -38, -20, + 35, 78, -103, 38, 69, -98, 44, 54, -89, 51, 35, -77, + 60, 14, -63, 68, -4, -49, 78, -21, -35, 87, -37, -20, + 36, 79, -102, 39, 70, -97, 44, 54, -88, 51, 35, -76, + 60, 15, -62, 69, -3, -48, 78, -20, -34, 87, -37, -20, + 37, 79, -101, 39, 70, -96, 45, 55, -87, 52, 37, -76, + 60, 16, -62, 69, -2, -48, 78, -19, -34, 87, -36, -20, + 37, 79, -100, 40, 71, -95, 45, 56, -86, 52, 38, -75, + 61, 18, -61, 69, -1, -48, 78, -18, -34, 88, -34, -19, + 38, 80, -98, 41, 72, -94, 46, 57, -85, 53, 39, -74, + 61, 19, -61, 70, 1, -47, 78, -17, -33, 88, -33, -19, + 39, 80, -97, 42, 72, -92, 47, 58, -84, 53, 40, -73, + 61, 21, -60, 70, 2, -47, 79, -15, -33, 88, -32, -19, + 40, 81, -95, 42, 73, -91, 47, 59, -83, 54, 42, -72, + 62, 22, -59, 70, 4, -46, 79, -14, -32, 88, -30, -18, + 41, 82, -94, 43, 74, -89, 48, 61, -82, 54, 43, -71, + 62, 24, -58, 71, 5, -45, 79, -12, -32, 89, -29, -18, + 42, 82, -92, 44, 75, -88, 49, 62, -80, 55, 45, -70, + 63, 26, -58, 71, 7, -45, 80, -10, -31, 89, -27, -17, + 43, 83, -90, 45, 76, -86, 50, 63, -79, 56, 47, -69, + 63, 28, -57, 72, 9, -44, 80, -8, -31, 89, -25, -17, + 44, 84, -88, 46, 77, -85, 50, 65, -77, 57, 48, -68, + 64, 29, -56, 72, 11, -43, 81, -6, -30, 90, -23, -16, + 45, 84, -86, 47, 78, -83, 51, 66, -76, 57, 50, -66, + 65, 31, -55, 73, 13, -42, 81, -4, -29, 90, -21, -16, + 46, 85, -84, 48, 79, -81, 52, 68, -74, 58, 52, -65, + 65, 34, -53, 73, 16, -41, 81, -2, -28, 90, -19, -15, + 47, 86, -82, 49, 80, -79, 53, 69, -73, 59, 54, -64, + 66, 36, -52, 74, 18, -40, 82, 0, -28, 91, -17, -14, + 49, 87, -80, 51, 81, -77, 54, 71, -71, 60, 56, -62, + 67, 38, -51, 74, 20, -39, 82, 2, -27, 91, -15, -14, + 50, 88, -78, 52, 83, -75, 55, 72, -69, 61, 57, -61, + 68, 40, -50, 75, 22, -38, 83, 5, -26, 92, -12, -13, + 51, 89, -76, 53, 84, -73, 56, 74, -67, 62, 59, -59, + 68, 42, -49, 76, 25, -37, 84, 7, -25, 92, -10, -12, + 53, 90, -74, 54, 85, -71, 58, 75, -65, 63, 61, -57, + 69, 45, -47, 76, 27, -36, 84, 10, -24, 93, -7, -11, + 54, 91, -72, 55, 87, -69, 59, 77, -64, 64, 63, -56, + 70, 47, -46, 77, 30, -35, 85, 12, -23, 93, -5, -10, + 55, 93, -70, 57, 88, -67, 60, 79, -62, 65, 65, -54, + 71, 49, -44, 78, 32, -34, 85, 15, -22, 94, -2, -10, + 56, 94, -67, 58, 89, -65, 61, 80, -60, 66, 67, -52, + 72, 51, -43, 79, 34, -32, 86, 17, -21, 94, 0, -9, + 58, 95, -65, 59, 91, -62, 62, 82, -58, 67, 69, -51, + 73, 54, -41, 80, 37, -31, 87, 20, -20, 95, 3, -8, + 59, 96, -63, 61, 92, -60, 64, 84, -56, 68, 71, -49, + 74, 56, -40, 80, 40, -30, 88, 23, -19, 95, 6, -7, + 61, 98, -60, 62, 93, -58, 65, 85, -54, 69, 73, -47, + 75, 58, -38, 81, 42, -28, 88, 25, -17, 96, 8, -6, + 3, -7, 5, 16, -27, 23, 29, -37, 36, 41, -47, 46, + 52, -57, 55, 63, -66, 64, 74, -74, 72, 84, -83, 80, + 4, -5, 6, 17, -25, 24, 29, -36, 36, 41, -47, 46, + 53, -56, 55, 63, -65, 64, 74, -74, 72, 84, -83, 80, + 4, -2, 6, 17, -22, 24, 29, -35, 37, 41, -46, 46, + 53, -56, 55, 63, -65, 64, 74, -74, 72, 84, -83, 80, + 5, 2, 8, 17, -19, 25, 30, -33, 37, 41, -44, 46, + 53, -55, 55, 63, -64, 64, 74, -73, 72, 84, -82, 80, + 6, 6, 10, 18, -15, 25, 30, -31, 37, 41, -43, 46, + 53, -54, 55, 63, -63, 64, 74, -73, 72, 84, -82, 80, + 8, 11, 12, 19, -11, 26, 30, -28, 38, 42, -41, 47, + 53, -52, 56, 64, -62, 64, 74, -72, 72, 84, -81, 80, + 9, 16, 14, 19, -7, 27, 31, -25, 38, 42, -38, 47, + 53, -51, 56, 64, -61, 64, 74, -71, 72, 84, -80, 81, + 11, 20, 17, 20, -2, 29, 31, -21, 39, 42, -36, 47, + 53, -48, 56, 64, -59, 64, 74, -69, 73, 84, -79, 81, + 13, 23, 20, 21, 3, 30, 32, -17, 40, 43, -33, 48, + 54, -46, 56, 64, -57, 65, 74, -68, 73, 85, -78, 81, + 15, 27, 22, 22, 7, 32, 33, -13, 40, 43, -29, 48, + 54, -44, 57, 64, -56, 65, 75, -66, 73, 85, -76, 81, + 16, 30, 25, 24, 11, 33, 33, -9, 41, 44, -26, 49, + 54, -41, 57, 65, -53, 65, 75, -64, 73, 85, -75, 81, + 18, 32, 28, 25, 15, 35, 34, -5, 42, 44, -23, 50, + 55, -38, 58, 65, -51, 66, 75, -62, 74, 85, -73, 82, + 20, 36, 30, 26, 19, 37, 35, 0, 43, 45, -18, 50, + 55, -35, 58, 65, -48, 66, 75, -60, 74, 85, -71, 82, + 22, 38, 33, 28, 23, 38, 36, 4, 44, 46, -15, 51, + 56, -31, 59, 66, -45, 67, 76, -58, 74, 86, -69, 82, + 24, 41, 35, 29, 27, 40, 37, 8, 46, 46, -11, 52, + 56, -28, 60, 66, -42, 67, 76, -55, 75, 86, -67, 82, + 26, 43, 38, 30, 30, 42, 38, 12, 47, 47, -7, 53, + 57, -25, 60, 67, -39, 68, 76, -53, 75, 86, -65, 83, + 28, 46, 40, 32, 34, 44, 39, 16, 48, 48, -3, 54, + 58, -21, 61, 67, -36, 68, 77, -50, 76, 87, -62, 83, + 29, 49, 42, 34, 37, 45, 40, 20, 49, 49, 1, 55, + 58, -17, 62, 68, -33, 69, 77, -47, 76, 87, -60, 84, + 31, 51, 44, 35, 40, 47, 42, 23, 51, 50, 5, 56, + 59, -13, 63, 68, -29, 69, 78, -44, 77, 87, -57, 84, + 33, 53, 46, 36, 43, 49, 43, 27, 52, 51, 9, 57, + 60, -10, 63, 69, -26, 70, 78, -41, 77, 88, -55, 85, + 35, 56, 49, 38, 46, 50, 44, 31, 54, 52, 13, 58, + 60, -6, 64, 69, -22, 71, 79, -37, 78, 88, -51, 85, + 36, 58, 50, 40, 49, 52, 45, 34, 55, 53, 16, 59, + 61, -2, 65, 70, -19, 72, 79, -34, 78, 88, -48, 86, + 38, 60, 52, 41, 51, 53, 47, 37, 56, 54, 20, 61, + 62, 2, 66, 71, -15, 72, 80, -31, 79, 89, -46, 86, + 40, 62, 54, 43, 54, 55, 48, 40, 58, 55, 24, 62, + 63, 5, 67, 71, -12, 73, 80, -27, 80, 89, -42, 87, + 42, 64, 56, 44, 57, 57, 49, 43, 59, 56, 27, 63, + 64, 9, 68, 72, -8, 74, 81, -24, 80, 90, -39, 87, + 43, 67, 57, 46, 59, 58, 51, 47, 61, 57, 31, 64, + 65, 13, 69, 73, -4, 75, 81, -20, 81, 90, -36, 88, + 45, 69, 59, 48, 62, 60, 52, 50, 62, 58, 34, 66, + 66, 17, 70, 74, -1, 76, 82, -17, 82, 91, -33, 89, + 47, 71, 61, 49, 64, 62, 53, 53, 64, 59, 37, 67, + 67, 20, 72, 74, 3, 77, 83, -13, 83, 92, -29, 89, + 49, 73, 62, 51, 66, 63, 55, 55, 65, 60, 41, 68, + 68, 23, 73, 75, 6, 78, 83, -10, 84, 92, -26, 90, + 50, 75, 64, 52, 69, 65, 56, 58, 67, 62, 44, 70, + 69, 27, 74, 76, 10, 79, 84, -6, 85, 93, -22, 91, + 52, 77, 66, 54, 71, 67, 58, 61, 68, 63, 47, 71, + 70, 31, 75, 77, 14, 80, 85, -3, 85, 93, -19, 91, + 54, 79, 67, 56, 73, 68, 59, 64, 70, 64, 50, 72, + 71, 34, 76, 78, 17, 81, 86, 1, 86, 94, -16, 92, + 4, -6, 2, 17, -26, 20, 29, -37, 33, 41, -47, 44, + 52, -57, 54, 63, -66, 62, 74, -74, 71, 84, -83, 80, + 4, -4, 3, 17, -24, 20, 29, -36, 33, 41, -46, 44, + 53, -56, 54, 63, -65, 63, 74, -74, 71, 84, -83, 80, + 5, -1, 3, 17, -21, 21, 29, -34, 34, 41, -45, 44, + 53, -56, 54, 63, -65, 63, 74, -74, 71, 84, -82, 80, + 5, 3, 5, 18, -18, 21, 30, -32, 34, 41, -44, 44, + 53, -55, 54, 63, -64, 63, 74, -73, 71, 84, -82, 80, + 6, 7, 6, 18, -14, 22, 30, -30, 34, 41, -42, 44, + 53, -53, 54, 63, -63, 63, 74, -72, 71, 84, -81, 80, + 8, 12, 9, 19, -10, 23, 30, -27, 35, 42, -40, 45, + 53, -52, 54, 64, -62, 63, 74, -72, 71, 84, -81, 80, + 9, 16, 11, 20, -6, 24, 31, -24, 35, 42, -38, 45, + 53, -50, 54, 64, -61, 63, 74, -71, 72, 84, -80, 80, + 11, 20, 14, 20, -1, 26, 31, -20, 36, 42, -35, 45, + 53, -48, 55, 64, -59, 63, 74, -69, 72, 84, -79, 80, + 13, 24, 17, 21, 3, 27, 32, -16, 37, 43, -32, 46, + 54, -46, 55, 64, -57, 64, 74, -68, 72, 85, -78, 80, + 15, 27, 19, 23, 7, 28, 33, -13, 38, 43, -29, 47, + 54, -43, 55, 64, -55, 64, 75, -66, 72, 85, -76, 80, + 16, 30, 22, 24, 11, 30, 33, -9, 39, 44, -26, 47, + 54, -41, 56, 65, -53, 64, 75, -64, 72, 85, -75, 81, + 18, 33, 24, 25, 15, 32, 34, -5, 39, 44, -22, 48, + 55, -38, 56, 65, -51, 65, 75, -62, 73, 85, -73, 81, + 20, 36, 27, 26, 20, 33, 35, 0, 41, 45, -18, 49, + 55, -34, 57, 65, -48, 65, 75, -60, 73, 85, -71, 81, + 22, 39, 30, 28, 23, 35, 36, 4, 42, 46, -14, 49, + 56, -31, 58, 66, -45, 66, 76, -58, 73, 86, -69, 82, + 24, 41, 32, 29, 27, 37, 37, 8, 43, 46, -11, 50, + 56, -28, 58, 66, -42, 66, 76, -55, 74, 86, -67, 82, + 26, 44, 34, 30, 30, 39, 38, 12, 44, 47, -7, 51, + 57, -24, 59, 67, -39, 67, 76, -53, 74, 86, -65, 82, + 28, 46, 37, 32, 34, 40, 39, 16, 46, 48, -3, 52, + 58, -20, 60, 67, -36, 67, 77, -50, 75, 87, -62, 83, + 29, 49, 39, 34, 37, 42, 40, 20, 47, 49, 1, 53, + 58, -17, 61, 68, -33, 68, 77, -47, 75, 87, -60, 83, + 31, 51, 41, 35, 40, 44, 42, 23, 48, 50, 5, 54, + 59, -13, 61, 68, -29, 68, 78, -44, 76, 87, -57, 83, + 33, 53, 43, 37, 43, 46, 43, 27, 50, 51, 9, 55, + 60, -10, 62, 69, -26, 69, 78, -41, 76, 88, -54, 84, + 35, 56, 45, 38, 46, 48, 44, 31, 51, 52, 13, 57, + 60, -5, 63, 69, -22, 70, 79, -37, 77, 88, -51, 84, + 37, 58, 47, 40, 49, 49, 45, 34, 53, 53, 17, 58, + 61, -2, 64, 70, -19, 71, 79, -34, 78, 88, -48, 85, + 38, 60, 49, 41, 51, 51, 47, 37, 54, 54, 20, 59, + 62, 2, 65, 71, -15, 72, 80, -31, 78, 89, -45, 85, + 40, 62, 51, 43, 54, 53, 48, 40, 56, 55, 24, 60, + 63, 5, 66, 71, -12, 72, 80, -27, 79, 89, -42, 86, + 42, 64, 53, 44, 57, 54, 49, 44, 57, 56, 27, 62, + 64, 9, 67, 72, -8, 73, 81, -24, 80, 90, -39, 87, + 44, 67, 55, 46, 59, 56, 51, 47, 59, 57, 31, 63, + 65, 13, 68, 73, -4, 74, 81, -20, 81, 90, -36, 87, + 45, 69, 57, 48, 62, 58, 52, 50, 60, 58, 34, 64, + 66, 17, 69, 74, -1, 75, 82, -17, 81, 91, -33, 88, + 47, 71, 58, 49, 64, 60, 53, 53, 62, 59, 37, 66, + 67, 20, 70, 74, 3, 76, 83, -13, 82, 92, -29, 89, + 49, 73, 60, 51, 67, 61, 55, 55, 63, 60, 41, 67, + 68, 23, 72, 75, 6, 77, 83, -10, 83, 92, -26, 89, + 50, 75, 62, 52, 69, 63, 56, 58, 65, 62, 44, 68, + 69, 27, 73, 76, 10, 78, 84, -6, 84, 93, -22, 90, + 52, 77, 64, 54, 71, 65, 58, 61, 67, 63, 47, 70, + 70, 31, 74, 77, 14, 79, 85, -3, 85, 93, -19, 91, + 54, 79, 65, 56, 74, 66, 59, 64, 68, 64, 50, 71, + 71, 34, 75, 78, 17, 80, 86, 1, 86, 94, -16, 92, + 4, -4, -2, 17, -25, 16, 29, -36, 30, 41, -47, 42, + 53, -56, 52, 63, -65, 61, 74, -74, 70, 84, -83, 79, + 4, -2, -1, 17, -23, 17, 29, -35, 30, 41, -46, 42, + 53, -56, 52, 63, -65, 61, 74, -74, 70, 84, -83, 79, + 5, 0, 0, 17, -20, 17, 29, -34, 31, 41, -45, 42, + 53, -55, 52, 63, -65, 61, 74, -73, 70, 84, -82, 79, + 6, 4, 1, 18, -17, 18, 30, -32, 31, 41, -44, 42, + 53, -54, 52, 63, -64, 62, 74, -73, 70, 84, -82, 79, + 7, 9, 3, 18, -14, 19, 30, -29, 31, 41, -42, 42, + 53, -53, 53, 64, -63, 62, 74, -72, 70, 84, -81, 79, + 8, 13, 5, 19, -10, 20, 30, -27, 32, 42, -40, 43, + 53, -52, 53, 64, -62, 62, 74, -71, 71, 84, -81, 79, + 9, 17, 8, 20, -6, 21, 31, -24, 32, 42, -38, 43, + 53, -50, 53, 64, -61, 62, 74, -70, 71, 84, -80, 79, + 11, 21, 10, 21, -1, 22, 31, -20, 33, 42, -35, 43, + 53, -48, 53, 64, -59, 62, 74, -69, 71, 85, -79, 79, + 13, 24, 13, 22, 4, 23, 32, -16, 34, 43, -32, 44, + 54, -46, 54, 64, -57, 63, 74, -68, 71, 85, -77, 80, + 15, 27, 16, 23, 8, 25, 33, -12, 35, 43, -29, 45, + 54, -43, 54, 64, -55, 63, 75, -66, 71, 85, -76, 80, + 17, 30, 18, 24, 12, 26, 33, -8, 36, 44, -26, 45, + 54, -40, 55, 65, -53, 63, 75, -64, 72, 85, -75, 80, + 18, 33, 21, 25, 16, 28, 34, -4, 37, 44, -22, 46, + 55, -38, 55, 65, -51, 64, 75, -62, 72, 85, -73, 80, + 20, 36, 24, 26, 20, 30, 35, 0, 38, 45, -18, 47, + 55, -34, 56, 65, -48, 64, 75, -60, 72, 85, -71, 81, + 22, 39, 26, 28, 24, 32, 36, 4, 39, 46, -14, 48, + 56, -31, 56, 66, -45, 64, 76, -57, 73, 86, -69, 81, + 24, 41, 28, 29, 27, 33, 37, 8, 40, 46, -10, 48, + 56, -28, 57, 66, -42, 65, 76, -55, 73, 86, -67, 81, + 26, 44, 31, 31, 30, 35, 38, 12, 42, 47, -7, 49, + 57, -24, 58, 67, -39, 66, 76, -52, 73, 86, -65, 81, + 28, 46, 33, 32, 34, 37, 39, 16, 43, 48, -2, 50, + 58, -20, 58, 67, -36, 66, 77, -49, 74, 87, -62, 82, + 29, 49, 36, 34, 37, 39, 40, 20, 45, 49, 1, 52, + 58, -17, 59, 68, -32, 67, 77, -47, 74, 87, -60, 82, + 31, 51, 38, 35, 40, 41, 42, 24, 46, 50, 5, 53, + 59, -13, 60, 68, -29, 67, 78, -44, 75, 87, -57, 83, + 33, 53, 40, 37, 43, 43, 43, 27, 48, 51, 9, 54, + 60, -9, 61, 69, -26, 68, 78, -41, 76, 88, -54, 83, + 35, 56, 42, 38, 46, 45, 44, 31, 49, 52, 13, 55, + 60, -5, 62, 69, -22, 69, 79, -37, 76, 88, -51, 84, + 37, 58, 44, 40, 49, 47, 45, 34, 51, 53, 17, 56, + 61, -2, 63, 70, -18, 70, 79, -34, 77, 88, -48, 84, + 38, 60, 46, 41, 52, 48, 47, 37, 52, 54, 20, 57, + 62, 2, 64, 71, -15, 70, 80, -31, 77, 89, -45, 85, + 40, 62, 48, 43, 54, 50, 48, 41, 54, 55, 24, 59, + 63, 6, 65, 71, -11, 71, 80, -27, 78, 89, -42, 85, + 42, 64, 50, 44, 57, 52, 49, 44, 55, 56, 27, 60, + 64, 9, 66, 72, -8, 72, 81, -24, 79, 90, -39, 86, + 44, 67, 52, 46, 59, 54, 51, 47, 57, 57, 31, 61, + 65, 13, 67, 73, -4, 73, 81, -20, 80, 90, -36, 87, + 45, 69, 54, 48, 62, 56, 52, 50, 59, 58, 34, 63, + 66, 17, 68, 74, 0, 74, 82, -17, 80, 91, -32, 87, + 47, 71, 56, 49, 64, 57, 53, 53, 60, 59, 38, 64, + 67, 20, 69, 74, 3, 75, 83, -13, 81, 92, -29, 88, + 49, 73, 58, 51, 67, 59, 55, 55, 62, 60, 41, 65, + 68, 24, 70, 75, 7, 76, 83, -10, 82, 92, -26, 89, + 50, 75, 60, 52, 69, 61, 56, 58, 63, 62, 44, 67, + 69, 27, 72, 76, 10, 77, 84, -6, 83, 93, -22, 89, + 52, 77, 62, 54, 71, 63, 58, 61, 65, 63, 47, 68, + 70, 31, 73, 77, 14, 78, 85, -3, 84, 93, -19, 90, + 54, 79, 63, 56, 74, 64, 59, 64, 67, 64, 50, 70, + 71, 34, 74, 78, 17, 79, 86, 1, 85, 94, -16, 91, + 4, -2, -7, 17, -23, 11, 29, -35, 26, 41, -46, 39, + 53, -56, 50, 63, -65, 60, 74, -74, 69, 84, -83, 78, + 4, 0, -6, 17, -21, 11, 29, -34, 26, 41, -45, 39, + 53, -55, 50, 63, -65, 60, 74, -74, 69, 84, -82, 78, + 5, 2, -6, 17, -19, 12, 30, -33, 27, 41, -44, 39, + 53, -55, 50, 63, -64, 60, 74, -73, 69, 84, -82, 78, + 6, 6, -4, 18, -16, 12, 30, -31, 27, 41, -43, 39, + 53, -54, 50, 63, -64, 60, 74, -73, 69, 84, -82, 78, + 7, 10, -3, 18, -12, 13, 30, -29, 27, 42, -41, 39, + 53, -53, 50, 64, -63, 60, 74, -72, 69, 84, -81, 78, + 8, 14, 0, 19, -8, 14, 30, -26, 28, 42, -39, 40, + 53, -51, 50, 64, -62, 60, 74, -71, 69, 84, -80, 78, + 10, 18, 2, 20, -4, 15, 31, -23, 28, 42, -37, 40, + 53, -50, 51, 64, -60, 60, 74, -70, 69, 84, -80, 78, + 12, 22, 5, 21, 0, 17, 31, -19, 29, 42, -34, 41, + 54, -47, 51, 64, -59, 61, 74, -69, 69, 85, -78, 78, + 13, 25, 7, 22, 4, 18, 32, -15, 30, 43, -31, 41, + 54, -45, 51, 64, -57, 61, 74, -67, 70, 85, -77, 78, + 15, 28, 10, 23, 8, 20, 33, -12, 31, 43, -28, 42, + 54, -43, 52, 64, -55, 61, 75, -66, 70, 85, -76, 79, + 17, 31, 12, 24, 12, 21, 33, -8, 32, 44, -25, 42, + 54, -40, 52, 65, -53, 61, 75, -64, 70, 85, -74, 79, + 18, 34, 15, 25, 16, 23, 34, -4, 33, 44, -22, 43, + 55, -37, 53, 65, -50, 62, 75, -62, 70, 85, -73, 79, + 20, 37, 18, 27, 20, 25, 35, 1, 34, 45, -18, 44, + 55, -34, 53, 65, -47, 62, 75, -60, 71, 85, -71, 79, + 22, 39, 20, 28, 24, 27, 36, 5, 36, 46, -14, 45, + 56, -31, 54, 66, -45, 63, 76, -57, 71, 86, -69, 80, + 24, 42, 23, 29, 27, 29, 37, 9, 37, 46, -10, 46, + 56, -27, 55, 66, -42, 63, 76, -55, 72, 86, -67, 80, + 26, 44, 25, 31, 31, 31, 38, 12, 38, 47, -6, 47, + 57, -24, 55, 67, -39, 64, 76, -52, 72, 86, -65, 80, + 28, 47, 28, 32, 34, 33, 39, 17, 40, 48, -2, 48, + 58, -20, 56, 67, -35, 64, 77, -49, 73, 87, -62, 81, + 29, 49, 31, 34, 37, 35, 40, 20, 41, 49, 2, 49, + 58, -16, 57, 68, -32, 65, 77, -46, 73, 87, -59, 81, + 31, 51, 33, 35, 40, 37, 42, 24, 43, 50, 5, 50, + 59, -13, 58, 68, -29, 66, 78, -43, 74, 87, -57, 82, + 33, 54, 35, 37, 43, 39, 43, 27, 44, 51, 9, 51, + 60, -9, 59, 69, -26, 66, 78, -40, 74, 88, -54, 82, + 35, 56, 38, 38, 46, 41, 44, 31, 46, 52, 13, 52, + 60, -5, 60, 69, -22, 67, 79, -37, 75, 88, -51, 83, + 37, 58, 40, 40, 49, 43, 45, 34, 47, 53, 17, 54, + 61, -1, 61, 70, -18, 68, 79, -34, 75, 88, -48, 83, + 38, 60, 42, 41, 52, 45, 47, 38, 49, 54, 20, 55, + 62, 2, 62, 71, -15, 69, 80, -30, 76, 89, -45, 84, + 40, 62, 44, 43, 54, 46, 48, 41, 51, 55, 24, 56, + 63, 6, 63, 71, -11, 70, 80, -27, 77, 89, -42, 84, + 42, 65, 46, 44, 57, 48, 49, 44, 52, 56, 27, 58, + 64, 9, 64, 72, -8, 71, 81, -24, 78, 90, -39, 85, + 44, 67, 48, 46, 60, 50, 51, 47, 54, 57, 31, 59, + 65, 13, 65, 73, -4, 72, 81, -20, 78, 90, -36, 86, + 45, 69, 50, 48, 62, 52, 52, 50, 56, 58, 34, 60, + 66, 17, 66, 74, 0, 73, 82, -17, 79, 91, -32, 86, + 47, 71, 52, 49, 64, 54, 53, 53, 57, 59, 38, 62, + 67, 20, 67, 74, 3, 73, 83, -13, 80, 92, -29, 87, + 49, 73, 54, 51, 67, 56, 55, 56, 59, 61, 41, 63, + 68, 24, 69, 75, 7, 74, 83, -10, 81, 92, -26, 88, + 50, 75, 57, 53, 69, 58, 56, 59, 61, 62, 44, 65, + 69, 27, 70, 76, 11, 76, 84, -6, 82, 93, -22, 88, + 52, 77, 58, 54, 72, 60, 58, 61, 62, 63, 47, 66, + 70, 31, 71, 77, 14, 77, 85, -3, 83, 93, -19, 89, + 54, 79, 60, 56, 74, 62, 59, 64, 64, 64, 50, 68, + 71, 34, 72, 78, 17, 78, 86, 1, 84, 94, -16, 90, + 4, 0, -13, 17, -21, 6, 29, -34, 22, 41, -45, 35, + 53, -55, 47, 63, -65, 58, 74, -74, 67, 84, -82, 76, + 5, 2, -12, 17, -19, 6, 30, -33, 22, 41, -44, 35, + 53, -55, 47, 63, -64, 58, 74, -73, 67, 84, -82, 76, + 5, 5, -11, 18, -17, 7, 30, -32, 22, 41, -43, 36, + 53, -54, 47, 63, -64, 58, 74, -73, 67, 84, -82, 76, + 6, 9, -10, 18, -14, 7, 30, -30, 23, 41, -42, 36, + 53, -53, 48, 63, -63, 58, 74, -72, 67, 84, -81, 76, + 7, 12, -8, 18, -11, 8, 30, -28, 23, 42, -41, 36, + 53, -52, 48, 64, -62, 58, 74, -72, 67, 84, -81, 77, + 9, 16, -6, 19, -7, 9, 31, -25, 24, 42, -39, 36, + 53, -51, 48, 64, -61, 58, 74, -71, 67, 84, -80, 77, + 10, 19, -4, 20, -3, 10, 31, -22, 24, 42, -37, 37, + 53, -49, 48, 64, -60, 58, 74, -70, 68, 84, -79, 77, + 12, 23, -1, 21, 1, 12, 32, -18, 25, 42, -34, 37, + 54, -47, 49, 64, -58, 59, 74, -68, 68, 85, -78, 77, + 13, 26, 2, 22, 5, 13, 32, -15, 26, 43, -31, 38, + 54, -45, 49, 64, -56, 59, 74, -67, 68, 85, -77, 77, + 15, 29, 4, 23, 9, 15, 33, -11, 27, 43, -28, 38, + 54, -42, 49, 64, -54, 59, 75, -65, 68, 85, -76, 77, + 17, 31, 7, 24, 13, 16, 34, -7, 28, 44, -25, 39, + 55, -40, 50, 65, -52, 59, 75, -64, 69, 85, -74, 77, + 19, 34, 10, 25, 17, 18, 34, -3, 29, 44, -21, 40, + 55, -37, 50, 65, -50, 60, 75, -62, 69, 85, -73, 78, + 21, 37, 13, 27, 21, 20, 35, 1, 30, 45, -17, 41, + 55, -33, 51, 65, -47, 60, 75, -59, 69, 85, -71, 78, + 22, 40, 15, 28, 24, 22, 36, 5, 32, 46, -13, 42, + 56, -30, 52, 66, -44, 61, 76, -57, 70, 86, -69, 78, + 24, 42, 18, 29, 28, 24, 37, 9, 33, 46, -10, 43, + 56, -27, 52, 66, -42, 61, 76, -55, 70, 86, -67, 79, + 26, 44, 20, 31, 31, 26, 38, 13, 34, 47, -6, 44, + 57, -24, 53, 67, -39, 62, 76, -52, 70, 86, -64, 79, + 28, 47, 23, 32, 35, 28, 39, 17, 36, 48, -2, 45, + 58, -20, 54, 67, -35, 63, 77, -49, 71, 87, -62, 79, + 30, 49, 26, 34, 38, 30, 41, 21, 38, 49, 2, 46, + 58, -16, 55, 68, -32, 63, 77, -46, 71, 87, -59, 80, + 31, 52, 28, 35, 41, 32, 42, 24, 39, 50, 6, 47, + 59, -13, 56, 68, -29, 64, 78, -43, 72, 87, -57, 80, + 33, 54, 30, 37, 44, 34, 43, 28, 41, 51, 9, 48, + 60, -9, 56, 69, -25, 65, 78, -40, 73, 88, -54, 81, + 35, 56, 33, 38, 47, 37, 44, 31, 42, 52, 14, 50, + 60, -5, 58, 69, -21, 65, 79, -37, 73, 88, -51, 81, + 37, 58, 35, 40, 49, 39, 45, 35, 44, 53, 17, 51, + 61, -1, 58, 70, -18, 66, 79, -33, 74, 88, -48, 82, + 38, 61, 38, 41, 52, 41, 47, 38, 46, 54, 21, 52, + 62, 2, 60, 71, -15, 67, 80, -30, 75, 89, -45, 82, + 40, 63, 40, 43, 55, 43, 48, 41, 47, 55, 24, 53, + 63, 6, 61, 71, -11, 68, 80, -27, 75, 89, -42, 83, + 42, 65, 42, 44, 57, 45, 49, 44, 49, 56, 28, 55, + 64, 10, 62, 72, -8, 69, 81, -24, 76, 90, -39, 84, + 44, 67, 45, 46, 60, 47, 51, 47, 51, 57, 31, 56, + 65, 14, 63, 73, -4, 70, 81, -20, 77, 90, -35, 84, + 45, 69, 47, 48, 62, 49, 52, 50, 53, 58, 35, 58, + 66, 17, 64, 74, 0, 71, 82, -16, 78, 91, -32, 85, + 47, 71, 49, 49, 65, 51, 54, 53, 54, 59, 38, 59, + 67, 20, 65, 74, 3, 72, 83, -13, 78, 92, -29, 86, + 49, 73, 51, 51, 67, 53, 55, 56, 56, 61, 41, 61, + 68, 24, 66, 75, 7, 73, 83, -10, 79, 92, -26, 86, + 50, 75, 53, 53, 69, 55, 56, 59, 58, 62, 44, 62, + 69, 28, 68, 76, 11, 74, 84, -6, 80, 93, -22, 87, + 52, 77, 55, 54, 72, 57, 58, 61, 60, 63, 47, 64, + 70, 31, 69, 77, 14, 75, 85, -2, 81, 93, -19, 88, + 54, 79, 57, 56, 74, 59, 59, 64, 61, 64, 50, 65, + 71, 34, 70, 78, 18, 76, 86, 1, 82, 94, -15, 89, + 5, 3, -18, 17, -18, 1, 30, -32, 17, 41, -44, 32, + 53, -55, 44, 63, -64, 55, 74, -73, 65, 84, -82, 75, + 5, 5, -18, 17, -16, 1, 30, -31, 18, 41, -43, 32, + 53, -54, 44, 63, -64, 55, 74, -73, 65, 84, -82, 75, + 6, 8, -17, 18, -14, 1, 30, -30, 18, 41, -43, 32, + 53, -54, 44, 63, -63, 55, 74, -72, 65, 84, -81, 75, + 7, 11, -15, 18, -12, 2, 30, -28, 18, 41, -41, 32, + 53, -53, 45, 64, -63, 55, 74, -72, 65, 84, -81, 75, + 8, 15, -14, 19, -9, 3, 30, -26, 19, 42, -40, 32, + 53, -51, 45, 64, -62, 55, 74, -71, 65, 84, -80, 75, + 9, 18, -11, 19, -5, 4, 31, -24, 19, 42, -38, 33, + 53, -50, 45, 64, -61, 56, 74, -70, 65, 84, -80, 75, + 10, 21, -9, 20, -2, 5, 31, -21, 20, 42, -36, 33, + 53, -48, 45, 64, -59, 56, 74, -69, 66, 84, -79, 75, + 12, 24, -6, 21, 3, 7, 32, -17, 21, 43, -33, 34, + 54, -46, 46, 64, -58, 56, 74, -68, 66, 85, -78, 75, + 14, 27, -4, 22, 6, 8, 32, -14, 22, 43, -30, 34, + 54, -44, 46, 64, -56, 56, 74, -67, 66, 85, -77, 75, + 15, 29, -1, 23, 10, 10, 33, -10, 22, 43, -27, 35, + 54, -42, 46, 65, -54, 57, 75, -65, 66, 85, -75, 76, + 17, 32, 2, 24, 14, 11, 34, -6, 24, 44, -24, 35, + 55, -39, 47, 65, -52, 57, 75, -63, 67, 85, -74, 76, + 19, 35, 4, 25, 18, 13, 34, -2, 25, 44, -20, 36, + 55, -36, 47, 65, -50, 57, 75, -61, 67, 85, -72, 76, + 21, 38, 7, 27, 22, 15, 35, 2, 26, 45, -16, 37, + 55, -33, 48, 65, -47, 58, 75, -59, 67, 85, -70, 76, + 23, 40, 10, 28, 25, 17, 36, 6, 27, 46, -13, 38, + 56, -30, 49, 66, -44, 58, 76, -57, 68, 86, -68, 77, + 24, 42, 13, 29, 28, 19, 37, 10, 29, 46, -9, 39, + 56, -26, 49, 66, -41, 59, 76, -54, 68, 86, -66, 77, + 26, 45, 15, 31, 32, 21, 38, 13, 30, 47, -5, 40, + 57, -23, 50, 67, -38, 60, 76, -52, 68, 86, -64, 77, + 28, 47, 18, 32, 35, 24, 39, 17, 32, 48, -1, 41, + 58, -19, 51, 67, -35, 60, 77, -49, 69, 87, -61, 78, + 30, 50, 21, 34, 38, 26, 41, 21, 33, 49, 2, 42, + 58, -16, 52, 68, -32, 61, 77, -46, 70, 87, -59, 78, + 31, 52, 23, 35, 41, 28, 42, 25, 35, 50, 6, 44, + 59, -12, 53, 68, -28, 62, 78, -43, 70, 87, -56, 79, + 33, 54, 26, 37, 44, 30, 43, 28, 37, 51, 10, 45, + 60, -9, 54, 69, -25, 62, 78, -40, 71, 88, -54, 79, + 35, 57, 28, 38, 47, 32, 44, 32, 39, 52, 14, 46, + 61, -4, 55, 69, -21, 63, 79, -36, 71, 88, -51, 80, + 37, 59, 31, 40, 50, 34, 46, 35, 40, 53, 17, 48, + 61, -1, 56, 70, -18, 64, 79, -33, 72, 89, -48, 80, + 38, 61, 33, 42, 52, 36, 47, 38, 42, 54, 21, 49, + 62, 3, 57, 71, -14, 65, 80, -30, 73, 89, -45, 81, + 40, 63, 35, 43, 55, 38, 48, 41, 44, 55, 24, 50, + 63, 6, 58, 71, -11, 66, 80, -27, 73, 89, -42, 81, + 42, 65, 38, 45, 57, 41, 49, 44, 45, 56, 28, 52, + 64, 10, 59, 72, -7, 67, 81, -23, 74, 90, -39, 82, + 44, 67, 40, 46, 60, 43, 51, 48, 47, 57, 32, 53, + 65, 14, 60, 73, -3, 68, 81, -20, 75, 90, -35, 83, + 45, 69, 42, 48, 62, 45, 52, 50, 49, 58, 35, 55, + 66, 17, 61, 74, 0, 69, 82, -16, 76, 91, -32, 83, + 47, 71, 45, 49, 65, 47, 54, 53, 51, 59, 38, 56, + 67, 21, 63, 75, 4, 70, 83, -13, 77, 92, -29, 84, + 49, 73, 47, 51, 67, 49, 55, 56, 53, 61, 41, 58, + 68, 24, 64, 75, 7, 71, 83, -9, 77, 92, -26, 85, + 51, 76, 49, 53, 70, 51, 56, 59, 55, 62, 45, 59, + 69, 28, 65, 76, 11, 72, 84, -6, 78, 93, -22, 86, + 52, 77, 51, 54, 72, 53, 58, 62, 56, 63, 48, 61, + 70, 31, 67, 77, 14, 73, 85, -2, 79, 93, -19, 86, + 54, 79, 53, 56, 74, 55, 59, 64, 58, 64, 51, 62, + 71, 34, 68, 78, 18, 74, 86, 1, 80, 94, -15, 87, + 5, 7, -23, 18, -15, -4, 30, -31, 13, 41, -43, 28, + 53, -54, 41, 63, -63, 52, 74, -73, 63, 84, -82, 73, + 6, 9, -23, 18, -14, -4, 30, -30, 13, 41, -42, 28, + 53, -53, 41, 63, -63, 52, 74, -72, 63, 84, -81, 73, + 6, 12, -22, 18, -12, -4, 30, -28, 13, 41, -41, 28, + 53, -53, 41, 63, -63, 52, 74, -72, 63, 84, -81, 73, + 7, 14, -20, 18, -9, -3, 30, -27, 14, 42, -40, 28, + 53, -52, 41, 64, -62, 53, 74, -71, 63, 84, -81, 73, + 8, 17, -19, 19, -7, -2, 30, -25, 14, 42, -39, 28, + 53, -51, 41, 64, -61, 53, 74, -71, 63, 84, -80, 73, + 10, 20, -17, 20, -3, -1, 31, -22, 15, 42, -37, 29, + 53, -49, 42, 64, -60, 53, 74, -70, 63, 84, -79, 73, + 11, 22, -14, 20, 0, 0, 31, -19, 15, 42, -35, 29, + 53, -48, 42, 64, -59, 53, 74, -69, 63, 84, -79, 73, + 13, 25, -12, 21, 4, 1, 32, -16, 16, 43, -32, 30, + 54, -46, 42, 64, -57, 53, 74, -68, 63, 85, -77, 73, + 14, 28, -9, 22, 8, 3, 32, -12, 17, 43, -29, 30, + 54, -43, 43, 64, -55, 54, 74, -66, 64, 85, -76, 73, + 16, 31, -6, 23, 11, 5, 33, -9, 18, 43, -26, 31, + 54, -41, 43, 65, -53, 54, 75, -65, 64, 85, -75, 74, + 17, 33, -4, 24, 15, 6, 34, -5, 19, 44, -23, 32, + 55, -38, 44, 65, -51, 54, 75, -63, 64, 85, -74, 74, + 19, 36, -1, 26, 19, 8, 35, -1, 20, 45, -20, 32, + 55, -36, 44, 65, -49, 55, 75, -61, 65, 85, -72, 74, + 21, 38, 2, 27, 22, 10, 36, 3, 22, 45, -16, 33, + 56, -32, 45, 66, -46, 55, 75, -58, 65, 85, -70, 74, + 23, 41, 5, 28, 26, 12, 36, 7, 23, 46, -12, 34, + 56, -29, 45, 66, -44, 56, 76, -56, 65, 86, -68, 75, + 24, 43, 7, 30, 29, 14, 37, 10, 24, 47, -9, 35, + 57, -26, 46, 66, -41, 56, 76, -54, 66, 86, -66, 75, + 26, 45, 10, 31, 32, 16, 38, 14, 26, 47, -5, 36, + 57, -23, 47, 67, -38, 57, 76, -51, 66, 86, -64, 75, + 28, 48, 13, 33, 36, 19, 40, 18, 28, 48, -1, 37, + 58, -19, 48, 67, -34, 57, 77, -48, 67, 87, -61, 76, + 30, 50, 16, 34, 39, 21, 41, 22, 29, 49, 3, 39, + 58, -15, 49, 68, -31, 58, 77, -45, 67, 87, -59, 76, + 32, 52, 18, 35, 42, 23, 42, 25, 31, 50, 7, 40, + 59, -12, 50, 68, -28, 59, 78, -43, 68, 87, -56, 77, + 33, 55, 21, 37, 44, 25, 43, 28, 32, 51, 10, 41, + 60, -8, 51, 69, -25, 60, 78, -40, 68, 88, -53, 77, + 35, 57, 23, 39, 47, 28, 44, 32, 34, 52, 14, 43, + 61, -4, 52, 70, -21, 60, 79, -36, 69, 88, -50, 78, + 37, 59, 26, 40, 50, 30, 46, 35, 36, 53, 18, 44, + 61, -1, 53, 70, -17, 61, 79, -33, 70, 89, -47, 78, + 39, 61, 28, 42, 53, 32, 47, 38, 38, 54, 21, 45, + 62, 3, 54, 71, -14, 62, 80, -30, 70, 89, -45, 79, + 40, 63, 31, 43, 55, 34, 48, 42, 40, 55, 25, 47, + 63, 7, 55, 71, -10, 63, 80, -26, 71, 89, -41, 79, + 42, 65, 33, 45, 58, 36, 49, 45, 41, 56, 28, 48, + 64, 10, 56, 72, -7, 64, 81, -23, 72, 90, -38, 80, + 44, 68, 36, 46, 60, 38, 51, 48, 43, 57, 32, 50, + 65, 14, 57, 73, -3, 65, 82, -19, 73, 91, -35, 81, + 45, 70, 38, 48, 63, 41, 52, 51, 45, 58, 35, 51, + 66, 18, 59, 74, 0, 66, 82, -16, 74, 91, -32, 82, + 47, 72, 40, 49, 65, 43, 54, 53, 47, 59, 38, 53, + 67, 21, 60, 75, 4, 67, 83, -13, 74, 92, -29, 82, + 49, 74, 42, 51, 67, 45, 55, 56, 49, 61, 41, 54, + 68, 24, 61, 75, 7, 68, 84, -9, 75, 92, -25, 83, + 51, 76, 45, 53, 70, 47, 57, 59, 51, 62, 45, 56, + 69, 28, 62, 76, 11, 69, 84, -5, 76, 93, -22, 84, + 52, 78, 47, 54, 72, 49, 58, 62, 53, 63, 48, 58, + 70, 31, 64, 77, 15, 70, 85, -2, 77, 93, -18, 85, + 54, 80, 49, 56, 74, 51, 59, 64, 54, 64, 51, 59, + 71, 35, 65, 78, 18, 71, 86, 1, 78, 94, -15, 85, + 6, 12, -29, 18, -11, -10, 30, -28, 7, 41, -41, 23, + 53, -53, 37, 63, -63, 49, 74, -72, 60, 84, -81, 70, + 7, 14, -28, 18, -10, -10, 30, -27, 8, 41, -41, 23, + 53, -52, 37, 64, -62, 49, 74, -72, 60, 84, -81, 70, + 7, 16, -27, 18, -9, -9, 30, -26, 8, 42, -40, 23, + 53, -52, 37, 64, -62, 49, 74, -71, 60, 84, -81, 70, + 8, 18, -26, 19, -6, -9, 30, -25, 8, 42, -39, 23, + 53, -51, 37, 64, -61, 49, 74, -71, 60, 84, -80, 70, + 9, 20, -24, 19, -4, -8, 31, -23, 9, 42, -37, 24, + 53, -50, 37, 64, -60, 49, 74, -70, 60, 84, -80, 70, + 10, 22, -22, 20, -1, -7, 31, -20, 9, 42, -35, 24, + 53, -48, 38, 64, -59, 49, 74, -69, 60, 84, -79, 70, + 11, 24, -20, 21, 2, -6, 31, -18, 10, 42, -33, 24, + 54, -47, 38, 64, -58, 50, 74, -68, 60, 85, -78, 71, + 13, 27, -17, 22, 6, -4, 32, -14, 11, 43, -31, 25, + 54, -45, 38, 64, -56, 50, 74, -67, 61, 85, -77, 71, + 15, 30, -15, 23, 9, -3, 33, -11, 12, 43, -28, 26, + 54, -42, 39, 64, -55, 50, 75, -65, 61, 85, -76, 71, + 16, 32, -12, 24, 13, -1, 33, -7, 13, 44, -25, 26, + 54, -40, 39, 65, -53, 50, 75, -64, 61, 85, -74, 71, + 18, 34, -10, 25, 16, 1, 34, -4, 14, 44, -22, 27, + 55, -38, 40, 65, -51, 51, 75, -62, 61, 85, -73, 71, + 19, 37, -7, 26, 20, 2, 35, 0, 15, 45, -19, 28, + 55, -35, 40, 65, -48, 51, 75, -60, 62, 85, -71, 72, + 21, 39, -4, 27, 24, 5, 36, 4, 16, 45, -15, 29, + 56, -31, 41, 66, -45, 52, 75, -58, 62, 86, -69, 72, + 23, 42, -1, 28, 27, 7, 37, 8, 18, 46, -11, 30, + 56, -28, 41, 66, -43, 52, 76, -56, 62, 86, -68, 72, + 25, 44, 1, 30, 30, 9, 38, 11, 19, 47, -8, 31, + 57, -25, 42, 66, -40, 53, 76, -53, 63, 86, -65, 73, + 26, 46, 4, 31, 33, 11, 39, 15, 21, 47, -4, 32, + 57, -22, 43, 67, -37, 53, 76, -51, 63, 86, -63, 73, + 28, 49, 7, 33, 36, 13, 40, 19, 22, 48, 0, 33, + 58, -18, 44, 67, -34, 54, 77, -48, 64, 87, -61, 73, + 30, 51, 10, 34, 39, 15, 41, 22, 24, 49, 4, 34, + 58, -15, 45, 68, -31, 55, 77, -45, 64, 87, -58, 74, + 32, 53, 12, 36, 42, 18, 42, 26, 26, 50, 7, 35, + 59, -11, 46, 68, -27, 55, 78, -42, 65, 87, -56, 74, + 33, 55, 15, 37, 45, 20, 43, 29, 27, 51, 11, 37, + 60, -8, 47, 69, -24, 56, 78, -39, 66, 88, -53, 75, + 35, 57, 18, 39, 48, 22, 45, 33, 29, 52, 15, 38, + 61, -4, 48, 70, -20, 57, 79, -36, 66, 88, -50, 75, + 37, 59, 20, 40, 50, 24, 46, 36, 31, 53, 18, 40, + 61, 0, 49, 70, -17, 58, 79, -32, 67, 89, -47, 76, + 39, 62, 23, 42, 53, 27, 47, 39, 33, 54, 22, 41, + 62, 4, 50, 71, -13, 59, 80, -29, 68, 89, -44, 76, + 40, 64, 25, 43, 56, 29, 48, 42, 35, 55, 25, 42, + 63, 7, 51, 72, -10, 60, 80, -26, 68, 89, -41, 77, + 42, 66, 28, 45, 58, 31, 50, 45, 37, 56, 29, 44, + 64, 11, 52, 72, -7, 61, 81, -23, 69, 90, -38, 78, + 44, 68, 30, 46, 61, 33, 51, 48, 39, 57, 32, 46, + 65, 14, 54, 73, -3, 62, 82, -19, 70, 91, -35, 78, + 46, 70, 33, 48, 63, 36, 52, 51, 41, 58, 36, 47, + 66, 18, 55, 74, 1, 63, 82, -16, 71, 91, -31, 79, + 47, 72, 35, 50, 65, 38, 54, 54, 42, 60, 39, 49, + 67, 21, 56, 75, 4, 64, 83, -12, 72, 92, -28, 80, + 49, 74, 37, 51, 68, 40, 55, 56, 44, 61, 42, 50, + 68, 25, 57, 75, 8, 65, 84, -9, 73, 92, -25, 81, + 51, 76, 40, 53, 70, 42, 57, 59, 46, 62, 45, 52, + 69, 28, 59, 76, 12, 66, 84, -5, 74, 93, -21, 81, + 52, 78, 42, 54, 72, 44, 58, 62, 48, 63, 48, 54, + 70, 32, 60, 77, 15, 67, 85, -2, 75, 94, -18, 82, + 54, 80, 44, 56, 74, 46, 59, 65, 50, 64, 51, 55, + 71, 35, 62, 78, 18, 68, 86, 2, 76, 94, -15, 83, + 7, 17, -33, 18, -8, -15, 30, -26, 3, 42, -40, 19, + 53, -51, 33, 64, -62, 45, 74, -71, 57, 84, -80, 68, + 7, 18, -32, 19, -7, -15, 30, -25, 3, 42, -39, 19, + 53, -51, 33, 64, -61, 46, 74, -71, 57, 84, -80, 68, + 8, 19, -32, 19, -5, -14, 30, -24, 3, 42, -38, 19, + 53, -50, 33, 64, -61, 46, 74, -71, 57, 84, -80, 68, + 9, 21, -30, 19, -3, -14, 31, -22, 3, 42, -37, 19, + 53, -49, 33, 64, -60, 46, 74, -70, 57, 84, -79, 68, + 10, 22, -29, 20, -1, -13, 31, -20, 4, 42, -36, 19, + 53, -48, 33, 64, -59, 46, 74, -69, 57, 84, -79, 68, + 11, 24, -27, 20, 2, -12, 31, -18, 4, 42, -34, 20, + 53, -47, 34, 64, -58, 46, 74, -69, 57, 84, -78, 68, + 12, 26, -25, 21, 4, -11, 32, -16, 5, 43, -32, 20, + 54, -46, 34, 64, -57, 46, 74, -68, 57, 85, -77, 68, + 14, 29, -22, 22, 8, -9, 32, -12, 6, 43, -29, 21, + 54, -43, 34, 64, -55, 46, 74, -66, 58, 85, -76, 68, + 15, 31, -20, 23, 11, -8, 33, -9, 7, 43, -27, 21, + 54, -41, 35, 64, -54, 47, 75, -65, 58, 85, -75, 68, + 17, 33, -17, 24, 15, -6, 33, -6, 8, 44, -24, 22, + 54, -39, 35, 65, -52, 47, 75, -63, 58, 85, -74, 69, + 18, 36, -15, 25, 18, -4, 34, -3, 9, 44, -21, 23, + 55, -37, 36, 65, -50, 47, 75, -62, 58, 85, -72, 69, + 20, 38, -12, 26, 21, -2, 35, 1, 10, 45, -18, 23, + 55, -34, 36, 65, -48, 48, 75, -60, 59, 85, -71, 69, + 22, 40, -9, 27, 25, 0, 36, 5, 12, 45, -14, 24, + 56, -31, 37, 66, -45, 48, 76, -57, 59, 86, -69, 69, + 23, 42, -6, 29, 28, 2, 37, 9, 13, 46, -10, 25, + 56, -28, 38, 66, -42, 49, 76, -55, 59, 86, -67, 70, + 25, 45, -4, 30, 31, 4, 38, 12, 14, 47, -7, 26, + 57, -24, 38, 66, -39, 49, 76, -53, 60, 86, -65, 70, + 27, 47, -1, 31, 34, 6, 39, 16, 16, 48, -3, 27, + 57, -21, 39, 67, -36, 50, 76, -50, 60, 86, -63, 70, + 29, 49, 2, 33, 37, 8, 40, 20, 18, 48, 1, 29, + 58, -17, 40, 67, -33, 51, 77, -47, 61, 87, -60, 71, + 30, 51, 5, 34, 40, 10, 41, 23, 19, 49, 4, 30, + 59, -14, 41, 68, -30, 51, 77, -44, 61, 87, -58, 71, + 32, 53, 7, 36, 43, 13, 42, 26, 21, 50, 8, 31, + 59, -10, 42, 68, -27, 52, 78, -42, 62, 87, -55, 72, + 34, 56, 10, 37, 45, 15, 43, 30, 23, 51, 12, 33, + 60, -7, 43, 69, -24, 53, 78, -39, 63, 88, -53, 72, + 36, 58, 13, 39, 48, 17, 45, 33, 25, 52, 15, 34, + 61, -3, 44, 70, -20, 54, 79, -35, 63, 88, -49, 73, + 37, 60, 15, 40, 51, 20, 46, 36, 27, 53, 19, 35, + 62, 1, 45, 70, -16, 55, 79, -32, 64, 89, -47, 73, + 39, 62, 18, 42, 54, 22, 47, 39, 28, 54, 22, 37, + 62, 4, 46, 71, -13, 56, 80, -29, 65, 89, -44, 74, + 41, 64, 20, 43, 56, 24, 48, 42, 30, 55, 26, 38, + 63, 8, 47, 72, -10, 57, 80, -26, 66, 90, -41, 75, + 42, 66, 23, 45, 58, 26, 50, 45, 32, 56, 29, 40, + 64, 11, 49, 72, -6, 58, 81, -22, 66, 90, -38, 75, + 44, 68, 26, 47, 61, 29, 51, 49, 34, 57, 33, 42, + 65, 15, 50, 73, -2, 59, 82, -19, 67, 91, -34, 76, + 46, 70, 28, 48, 63, 31, 52, 51, 36, 59, 36, 43, + 66, 18, 51, 74, 1, 60, 82, -15, 68, 91, -31, 77, + 47, 72, 30, 50, 66, 33, 54, 54, 38, 60, 39, 45, + 67, 22, 53, 75, 5, 61, 83, -12, 69, 92, -28, 77, + 49, 74, 33, 51, 68, 35, 55, 57, 40, 61, 42, 46, + 68, 25, 54, 75, 8, 62, 84, -9, 70, 92, -25, 78, + 51, 76, 35, 53, 70, 38, 57, 60, 42, 62, 46, 48, + 69, 29, 55, 76, 12, 63, 84, -5, 71, 93, -21, 79, + 52, 78, 38, 54, 73, 40, 58, 62, 44, 63, 48, 50, + 70, 32, 57, 77, 15, 64, 85, -1, 72, 94, -18, 80, + 54, 80, 40, 56, 75, 42, 59, 65, 46, 65, 51, 51, + 71, 35, 58, 78, 19, 65, 86, 2, 73, 94, -14, 81, + 8, 21, -37, 19, -4, -20, 30, -23, -2, 42, -38, 14, + 53, -50, 29, 64, -61, 42, 74, -70, 54, 84, -80, 65, + 8, 21, -37, 19, -3, -19, 30, -22, -2, 42, -37, 14, + 53, -50, 29, 64, -60, 42, 74, -70, 54, 84, -80, 65, + 9, 22, -36, 19, -2, -19, 31, -22, -2, 42, -36, 14, + 53, -49, 29, 64, -60, 42, 74, -70, 54, 84, -79, 65, + 10, 24, -34, 20, 0, -18, 31, -20, -1, 42, -35, 15, + 53, -48, 29, 64, -59, 42, 74, -69, 54, 84, -79, 65, + 10, 25, -33, 20, 2, -18, 31, -18, -1, 42, -34, 15, + 53, -47, 29, 64, -58, 42, 74, -69, 54, 84, -78, 65, + 12, 27, -31, 21, 4, -17, 31, -16, 0, 42, -32, 15, + 54, -46, 30, 64, -57, 42, 74, -68, 54, 85, -78, 65, + 13, 29, -29, 21, 7, -15, 32, -14, 0, 43, -30, 16, + 54, -44, 30, 64, -56, 43, 74, -67, 54, 85, -77, 65, + 14, 31, -27, 22, 10, -14, 32, -11, 1, 43, -28, 16, + 54, -42, 30, 64, -54, 43, 75, -65, 54, 85, -76, 65, + 16, 33, -24, 23, 13, -13, 33, -8, 2, 43, -25, 17, + 54, -40, 31, 65, -53, 43, 75, -64, 55, 85, -75, 66, + 17, 35, -22, 24, 16, -11, 34, -4, 3, 44, -22, 17, + 55, -38, 31, 65, -51, 44, 75, -62, 55, 85, -73, 66, + 19, 37, -19, 25, 19, -9, 34, -1, 4, 44, -19, 18, + 55, -35, 32, 65, -49, 44, 75, -61, 55, 85, -72, 66, + 20, 39, -17, 26, 22, -7, 35, 2, 5, 45, -16, 19, + 55, -33, 32, 65, -47, 44, 75, -59, 56, 85, -70, 66, + 22, 41, -14, 28, 26, -5, 36, 6, 7, 46, -13, 20, + 56, -30, 33, 66, -44, 45, 76, -57, 56, 86, -68, 67, + 24, 43, -11, 29, 29, -3, 37, 10, 8, 46, -9, 21, + 56, -27, 34, 66, -41, 45, 76, -54, 56, 86, -66, 67, + 25, 46, -9, 30, 32, -1, 38, 13, 10, 47, -6, 22, + 57, -23, 34, 67, -39, 46, 76, -52, 57, 86, -64, 67, + 27, 48, -6, 32, 35, 1, 39, 17, 11, 48, -2, 23, + 57, -20, 35, 67, -36, 47, 77, -49, 57, 86, -62, 68, + 29, 50, -3, 33, 38, 3, 40, 21, 13, 49, 2, 24, + 58, -17, 36, 67, -32, 47, 77, -47, 58, 87, -60, 68, + 30, 52, 0, 35, 41, 6, 41, 24, 15, 49, 5, 26, + 59, -13, 37, 68, -29, 48, 77, -44, 58, 87, -57, 69, + 32, 54, 2, 36, 43, 8, 42, 27, 16, 50, 9, 27, + 59, -10, 38, 68, -26, 49, 78, -41, 59, 87, -55, 69, + 34, 56, 5, 37, 46, 10, 43, 30, 18, 51, 12, 28, + 60, -6, 39, 69, -23, 50, 78, -38, 60, 88, -52, 70, + 36, 58, 8, 39, 49, 13, 45, 34, 20, 52, 16, 30, + 61, -2, 40, 70, -19, 50, 79, -35, 60, 88, -49, 70, + 37, 60, 11, 41, 52, 15, 46, 37, 22, 53, 20, 31, + 62, 1, 41, 70, -16, 51, 79, -31, 61, 89, -46, 71, + 39, 62, 13, 42, 54, 17, 47, 40, 24, 54, 23, 33, + 62, 5, 43, 71, -12, 52, 80, -28, 62, 89, -43, 71, + 41, 64, 16, 44, 56, 19, 49, 43, 26, 55, 26, 34, + 63, 8, 44, 72, -9, 53, 80, -25, 63, 90, -40, 72, + 42, 66, 18, 45, 59, 22, 50, 46, 28, 56, 30, 36, + 64, 12, 45, 72, -6, 54, 81, -22, 63, 90, -37, 73, + 44, 69, 21, 47, 61, 24, 51, 49, 30, 57, 33, 37, + 65, 15, 46, 73, -2, 55, 82, -18, 64, 91, -34, 73, + 46, 71, 23, 48, 64, 26, 53, 52, 32, 59, 36, 39, + 66, 19, 48, 74, 2, 56, 82, -15, 65, 91, -31, 74, + 47, 73, 26, 50, 66, 29, 54, 55, 34, 60, 39, 41, + 67, 22, 49, 75, 5, 57, 83, -11, 66, 92, -28, 75, + 49, 74, 28, 51, 68, 31, 55, 57, 36, 61, 43, 42, + 68, 25, 50, 76, 8, 59, 84, -8, 67, 92, -24, 76, + 51, 77, 31, 53, 71, 33, 57, 60, 38, 62, 46, 44, + 69, 29, 52, 76, 12, 60, 84, -4, 68, 93, -21, 76, + 53, 79, 33, 55, 73, 36, 58, 63, 40, 63, 49, 46, + 70, 32, 53, 77, 16, 61, 85, -1, 69, 94, -17, 77, + 54, 80, 35, 56, 75, 38, 60, 65, 42, 65, 52, 48, + 71, 36, 55, 78, 19, 62, 86, 2, 70, 94, -14, 78, + 9, 24, -41, 19, -1, -24, 31, -21, -7, 42, -36, 10, + 53, -49, 25, 64, -59, 38, 74, -69, 50, 84, -79, 62, + 9, 25, -41, 19, 0, -24, 31, -20, -7, 42, -35, 10, + 53, -48, 25, 64, -59, 38, 74, -69, 50, 84, -79, 62, + 10, 25, -40, 20, 1, -24, 31, -19, -6, 42, -34, 10, + 53, -48, 25, 64, -59, 38, 74, -69, 50, 84, -79, 62, + 10, 26, -39, 20, 3, -23, 31, -17, -6, 42, -33, 10, + 53, -47, 25, 64, -58, 38, 74, -68, 50, 84, -78, 62, + 11, 28, -37, 21, 5, -22, 31, -16, -6, 42, -32, 10, + 53, -46, 25, 64, -57, 39, 74, -68, 51, 85, -78, 62, + 12, 29, -35, 21, 7, -21, 32, -14, -5, 43, -30, 11, + 54, -44, 26, 64, -56, 39, 74, -67, 51, 85, -77, 62, + 13, 31, -34, 22, 9, -20, 32, -11, -4, 43, -28, 11, + 54, -43, 26, 64, -55, 39, 74, -66, 51, 85, -76, 62, + 15, 33, -31, 23, 12, -19, 33, -8, -3, 43, -26, 12, + 54, -41, 26, 64, -53, 39, 75, -65, 51, 85, -75, 62, + 16, 34, -29, 24, 15, -17, 33, -6, -3, 44, -24, 12, + 54, -39, 27, 65, -52, 39, 75, -63, 51, 85, -74, 63, + 18, 36, -27, 25, 18, -16, 34, -3, -2, 44, -21, 13, + 55, -37, 27, 65, -50, 40, 75, -62, 52, 85, -73, 63, + 19, 38, -24, 26, 21, -14, 35, 1, 0, 45, -18, 14, + 55, -34, 28, 65, -48, 40, 75, -60, 52, 85, -71, 63, + 21, 40, -22, 27, 24, -12, 35, 4, 1, 45, -15, 15, + 55, -32, 28, 65, -46, 41, 75, -58, 52, 85, -70, 63, + 22, 43, -19, 28, 27, -10, 36, 8, 2, 46, -11, 16, + 56, -29, 29, 66, -43, 41, 76, -56, 53, 86, -68, 64, + 24, 45, -16, 29, 30, -8, 37, 11, 4, 46, -8, 16, + 56, -26, 30, 66, -40, 42, 76, -54, 53, 86, -66, 64, + 26, 47, -13, 31, 33, -6, 38, 14, 5, 47, -5, 18, + 57, -22, 30, 67, -38, 42, 76, -51, 53, 86, -64, 64, + 27, 49, -11, 32, 36, -4, 39, 18, 7, 48, -1, 19, + 57, -19, 31, 67, -35, 43, 77, -49, 54, 86, -62, 65, + 29, 51, -8, 33, 39, -1, 40, 22, 8, 49, 3, 20, + 58, -16, 32, 68, -32, 44, 77, -46, 55, 87, -59, 65, + 31, 53, -5, 35, 42, 1, 41, 25, 10, 49, 6, 21, + 59, -12, 33, 68, -29, 44, 77, -43, 55, 87, -57, 66, + 32, 55, -2, 36, 44, 3, 42, 28, 12, 50, 10, 23, + 59, -9, 34, 69, -25, 45, 78, -40, 56, 87, -54, 66, + 34, 57, 0, 38, 47, 5, 44, 31, 14, 51, 13, 24, + 60, -5, 35, 69, -22, 46, 78, -37, 56, 88, -51, 67, + 36, 59, 3, 39, 50, 8, 45, 35, 16, 52, 17, 25, + 61, -2, 36, 70, -18, 47, 79, -34, 57, 88, -48, 67, + 38, 61, 6, 41, 52, 10, 46, 38, 17, 53, 20, 27, + 62, 2, 37, 70, -15, 48, 79, -31, 58, 89, -46, 68, + 39, 63, 8, 42, 55, 12, 47, 41, 19, 54, 24, 28, + 62, 5, 39, 71, -12, 49, 80, -28, 59, 89, -43, 68, + 41, 65, 11, 44, 57, 15, 49, 44, 21, 55, 27, 30, + 63, 9, 40, 72, -8, 50, 80, -25, 59, 90, -40, 69, + 43, 67, 13, 45, 59, 17, 50, 46, 23, 56, 30, 31, + 64, 12, 41, 72, -5, 51, 81, -21, 60, 90, -37, 70, + 44, 69, 16, 47, 62, 19, 51, 50, 25, 58, 34, 33, + 65, 16, 42, 73, -1, 52, 82, -18, 61, 91, -33, 70, + 46, 71, 19, 48, 64, 22, 53, 52, 27, 59, 37, 35, + 66, 19, 44, 74, 2, 53, 82, -14, 62, 91, -30, 71, + 48, 73, 21, 50, 66, 24, 54, 55, 29, 60, 40, 37, + 67, 23, 45, 75, 6, 54, 83, -11, 63, 92, -27, 72, + 49, 75, 23, 51, 69, 26, 55, 58, 31, 61, 43, 38, + 68, 26, 46, 76, 9, 55, 84, -8, 64, 92, -24, 73, + 51, 77, 26, 53, 71, 29, 57, 61, 34, 62, 46, 40, + 69, 30, 48, 77, 13, 56, 85, -4, 65, 93, -20, 74, + 53, 79, 29, 55, 73, 31, 58, 63, 36, 64, 49, 42, + 70, 33, 49, 77, 16, 57, 85, -1, 66, 94, -17, 74, + 54, 81, 31, 56, 75, 33, 60, 66, 38, 65, 52, 43, + 71, 36, 51, 78, 19, 59, 86, 3, 67, 94, -14, 75, + 10, 27, -45, 20, 3, -29, 31, -18, -11, 42, -34, 5, + 53, -47, 21, 64, -58, 34, 74, -68, 47, 84, -78, 59, + 10, 28, -44, 20, 4, -28, 31, -17, -11, 42, -33, 5, + 53, -46, 21, 64, -58, 34, 74, -68, 47, 84, -78, 59, + 11, 28, -44, 20, 5, -28, 31, -16, -11, 42, -32, 5, + 53, -46, 21, 64, -57, 34, 74, -68, 47, 84, -78, 59, + 11, 29, -42, 21, 6, -27, 31, -15, -11, 42, -31, 6, + 53, -45, 21, 64, -57, 35, 74, -67, 47, 85, -77, 59, + 12, 30, -41, 21, 8, -27, 32, -13, -10, 43, -30, 6, + 54, -44, 21, 64, -56, 35, 74, -67, 47, 85, -77, 59, + 13, 32, -40, 22, 10, -26, 32, -11, -10, 43, -28, 6, + 54, -43, 21, 64, -55, 35, 74, -66, 47, 85, -76, 59, + 14, 33, -38, 22, 12, -25, 32, -9, -9, 43, -27, 7, + 54, -41, 22, 64, -54, 35, 74, -65, 47, 85, -75, 59, + 16, 35, -35, 23, 15, -23, 33, -6, -8, 43, -24, 7, + 54, -39, 22, 65, -52, 35, 75, -64, 48, 85, -74, 59, + 17, 36, -33, 24, 17, -22, 34, -4, -7, 44, -22, 8, + 55, -38, 22, 65, -51, 36, 75, -62, 48, 85, -73, 59, + 18, 38, -31, 25, 20, -20, 34, -1, -6, 44, -19, 8, + 55, -35, 23, 65, -49, 36, 75, -61, 48, 85, -72, 60, + 20, 40, -29, 26, 23, -19, 35, 2, -5, 45, -16, 9, + 55, -33, 23, 65, -47, 36, 75, -59, 48, 85, -70, 60, + 21, 42, -26, 27, 26, -17, 36, 6, -4, 45, -13, 10, + 56, -30, 24, 66, -45, 37, 75, -57, 49, 86, -69, 60, + 23, 44, -23, 28, 29, -15, 37, 9, -2, 46, -10, 11, + 56, -27, 25, 66, -42, 37, 76, -55, 49, 86, -67, 61, + 24, 46, -21, 30, 32, -13, 37, 12, -1, 47, -7, 12, + 57, -24, 25, 66, -39, 38, 76, -53, 50, 86, -65, 61, + 26, 48, -18, 31, 34, -11, 38, 16, 0, 47, -3, 13, + 57, -21, 26, 67, -37, 38, 76, -50, 50, 86, -63, 61, + 28, 50, -16, 32, 37, -9, 39, 19, 2, 48, 0, 14, + 58, -18, 27, 67, -34, 39, 77, -48, 51, 87, -61, 62, + 29, 52, -13, 34, 40, -6, 40, 23, 4, 49, 4, 16, + 58, -15, 28, 68, -31, 40, 77, -45, 51, 87, -58, 62, + 31, 54, -10, 35, 43, -4, 42, 26, 5, 50, 7, 17, + 59, -11, 29, 68, -28, 41, 78, -42, 52, 87, -56, 63, + 33, 56, -7, 36, 45, -2, 43, 29, 7, 51, 11, 18, + 60, -8, 30, 69, -25, 41, 78, -40, 52, 88, -53, 63, + 34, 58, -5, 38, 48, 0, 44, 32, 9, 51, 14, 19, + 60, -5, 31, 69, -21, 42, 78, -37, 53, 88, -51, 64, + 36, 60, -2, 39, 50, 3, 45, 35, 11, 52, 18, 21, + 61, -1, 32, 70, -18, 43, 79, -33, 54, 88, -48, 64, + 38, 62, 1, 41, 53, 5, 46, 38, 13, 53, 21, 23, + 62, 3, 33, 70, -14, 44, 79, -30, 54, 89, -45, 65, + 39, 64, 3, 42, 55, 8, 48, 41, 15, 54, 24, 24, + 63, 6, 34, 71, -11, 45, 80, -27, 55, 89, -42, 65, + 41, 66, 6, 44, 58, 10, 49, 44, 17, 55, 28, 26, + 63, 9, 36, 72, -8, 46, 81, -24, 56, 90, -39, 66, + 43, 67, 9, 45, 60, 12, 50, 47, 19, 57, 31, 27, + 64, 13, 37, 73, -4, 47, 81, -21, 57, 90, -36, 67, + 45, 70, 11, 47, 62, 15, 52, 50, 21, 58, 34, 29, + 65, 17, 38, 73, -1, 48, 82, -17, 58, 91, -33, 67, + 46, 71, 14, 49, 65, 17, 53, 53, 23, 59, 37, 31, + 66, 20, 40, 74, 3, 49, 82, -14, 59, 91, -30, 68, + 48, 73, 16, 50, 67, 19, 54, 56, 25, 60, 41, 32, + 67, 23, 41, 75, 6, 50, 83, -10, 59, 92, -27, 69, + 49, 75, 19, 52, 69, 22, 56, 58, 27, 61, 44, 34, + 68, 26, 42, 76, 9, 51, 84, -7, 60, 92, -23, 70, + 51, 77, 22, 53, 72, 24, 57, 61, 29, 62, 47, 36, + 69, 30, 44, 77, 13, 53, 85, -3, 62, 93, -20, 71, + 53, 79, 24, 55, 74, 26, 58, 64, 31, 64, 50, 38, + 70, 33, 46, 77, 16, 54, 85, 0, 63, 94, -17, 71, + 54, 81, 26, 56, 76, 29, 60, 66, 33, 65, 53, 39, + 71, 36, 47, 78, 20, 55, 86, 3, 64, 94, -13, 72, + 11, 31, -49, 20, 7, -34, 31, -14, -17, 42, -31, 0, + 53, -45, 16, 64, -57, 30, 74, -67, 43, 84, -77, 55, + 11, 31, -48, 21, 8, -33, 31, -13, -16, 42, -30, 0, + 54, -44, 16, 64, -56, 30, 74, -67, 43, 85, -77, 55, + 12, 32, -48, 21, 8, -33, 32, -13, -16, 42, -30, 0, + 54, -44, 16, 64, -56, 30, 74, -67, 43, 85, -77, 55, + 12, 32, -47, 21, 10, -32, 32, -11, -16, 43, -29, 1, + 54, -43, 16, 64, -55, 30, 74, -66, 43, 85, -76, 55, + 13, 33, -45, 22, 11, -32, 32, -10, -15, 43, -27, 1, + 54, -42, 16, 64, -54, 30, 74, -65, 43, 85, -76, 55, + 14, 34, -44, 22, 13, -31, 32, -8, -15, 43, -26, 1, + 54, -41, 17, 64, -53, 30, 74, -65, 43, 85, -75, 55, + 15, 36, -42, 23, 15, -30, 33, -6, -14, 43, -24, 2, + 54, -40, 17, 64, -52, 31, 75, -64, 43, 85, -74, 55, + 16, 37, -40, 24, 18, -28, 33, -4, -13, 44, -22, 2, + 54, -38, 17, 65, -51, 31, 75, -62, 44, 85, -73, 56, + 18, 38, -38, 24, 20, -27, 34, -1, -12, 44, -20, 3, + 55, -36, 18, 65, -49, 31, 75, -61, 44, 85, -72, 56, + 19, 40, -36, 25, 22, -25, 34, 2, -11, 44, -17, 3, + 55, -34, 18, 65, -47, 32, 75, -60, 44, 85, -71, 56, + 20, 42, -34, 26, 25, -24, 35, 5, -10, 45, -14, 4, + 55, -31, 19, 65, -45, 32, 75, -58, 44, 85, -69, 56, + 22, 43, -31, 27, 28, -22, 36, 8, -9, 45, -12, 5, + 56, -29, 19, 66, -43, 32, 76, -56, 45, 86, -68, 56, + 23, 45, -28, 29, 31, -20, 37, 11, -8, 46, -8, 6, + 56, -26, 20, 66, -41, 33, 76, -54, 45, 86, -66, 57, + 25, 47, -26, 30, 33, -18, 38, 14, -6, 47, -5, 7, + 57, -23, 21, 66, -38, 33, 76, -52, 46, 86, -64, 57, + 26, 49, -23, 31, 36, -16, 39, 17, -5, 47, -2, 8, + 57, -20, 21, 67, -36, 34, 76, -49, 46, 86, -62, 58, + 28, 51, -21, 32, 38, -14, 40, 20, -3, 48, 1, 9, + 58, -17, 22, 67, -33, 35, 77, -47, 46, 87, -60, 58, + 30, 53, -18, 34, 41, -11, 41, 24, -1, 49, 5, 11, + 58, -13, 23, 68, -30, 35, 77, -44, 47, 87, -57, 58, + 31, 55, -15, 35, 44, -9, 42, 27, 0, 50, 8, 12, + 59, -10, 24, 68, -27, 36, 78, -41, 48, 87, -55, 59, + 33, 57, -13, 37, 46, -7, 43, 30, 2, 51, 12, 13, + 60, -7, 25, 69, -24, 37, 78, -39, 48, 88, -53, 59, + 35, 58, -10, 38, 49, -5, 44, 33, 4, 52, 15, 14, + 60, -4, 26, 69, -20, 38, 78, -36, 49, 88, -50, 60, + 37, 61, -7, 40, 51, -2, 45, 36, 6, 53, 19, 16, + 61, 0, 28, 70, -17, 39, 79, -32, 50, 88, -47, 61, + 38, 62, -4, 41, 54, 0, 47, 39, 8, 54, 22, 18, + 62, 4, 29, 71, -14, 40, 80, -29, 50, 89, -44, 61, + 40, 64, -2, 43, 56, 2, 48, 42, 10, 55, 25, 19, + 63, 7, 30, 71, -10, 41, 80, -26, 51, 89, -41, 62, + 41, 66, 1, 44, 58, 5, 49, 45, 12, 56, 28, 21, + 64, 10, 31, 72, -7, 42, 81, -23, 52, 90, -39, 62, + 43, 68, 3, 46, 61, 7, 50, 48, 14, 57, 32, 22, + 64, 14, 32, 73, -4, 43, 81, -20, 53, 90, -36, 63, + 45, 70, 6, 47, 63, 10, 52, 51, 16, 58, 35, 24, + 65, 17, 34, 73, 0, 44, 82, -16, 54, 91, -32, 64, + 46, 72, 9, 49, 65, 12, 53, 54, 18, 59, 38, 26, + 66, 21, 35, 74, 3, 45, 83, -13, 55, 91, -29, 65, + 48, 74, 11, 50, 68, 14, 54, 56, 20, 60, 41, 27, + 67, 24, 37, 75, 7, 46, 83, -10, 56, 92, -26, 65, + 50, 76, 14, 52, 70, 16, 56, 59, 22, 61, 44, 29, + 68, 27, 38, 76, 10, 47, 84, -7, 57, 92, -23, 66, + 51, 78, 16, 53, 72, 19, 57, 62, 24, 63, 47, 31, + 69, 31, 40, 77, 14, 48, 85, -3, 58, 93, -19, 67, + 53, 80, 19, 55, 74, 21, 59, 64, 26, 64, 50, 33, + 70, 34, 41, 78, 17, 50, 85, 0, 59, 94, -16, 68, + 55, 82, 21, 56, 76, 24, 60, 67, 28, 65, 53, 35, + 71, 37, 42, 78, 20, 51, 86, 4, 60, 94, -13, 69, + 12, 34, -52, 21, 11, -38, 32, -11, -21, 43, -28, -4, + 54, -43, 12, 64, -55, 26, 74, -66, 39, 85, -76, 51, + 13, 34, -52, 21, 11, -38, 32, -10, -21, 43, -28, -4, + 54, -42, 12, 64, -55, 26, 74, -66, 39, 85, -76, 52, + 13, 34, -51, 21, 12, -37, 32, -10, -21, 43, -27, -4, + 54, -42, 12, 64, -54, 26, 74, -65, 39, 85, -76, 52, + 13, 35, -50, 22, 13, -37, 32, -9, -20, 43, -26, -4, + 54, -41, 12, 64, -54, 26, 74, -65, 39, 85, -75, 52, + 14, 36, -49, 22, 14, -36, 32, -7, -20, 43, -25, -4, + 54, -40, 12, 64, -53, 26, 74, -64, 39, 85, -75, 52, + 15, 37, -48, 23, 16, -35, 33, -6, -19, 43, -24, -3, + 54, -39, 12, 64, -52, 26, 75, -63, 39, 85, -74, 52, + 16, 38, -46, 23, 18, -34, 33, -4, -19, 44, -22, -3, + 54, -38, 13, 65, -51, 27, 75, -62, 40, 85, -73, 52, + 17, 39, -44, 24, 20, -33, 34, -1, -18, 44, -20, -2, + 55, -36, 13, 65, -49, 27, 75, -61, 40, 85, -72, 52, + 18, 40, -42, 25, 22, -31, 34, 1, -17, 44, -18, -2, + 55, -34, 13, 65, -48, 27, 75, -60, 40, 85, -71, 52, + 20, 42, -40, 26, 25, -30, 35, 4, -16, 45, -15, -1, + 55, -32, 14, 65, -46, 28, 75, -58, 40, 85, -70, 53, + 21, 43, -38, 27, 27, -28, 35, 7, -15, 45, -13, 0, + 55, -30, 14, 66, -44, 28, 75, -57, 41, 85, -68, 53, + 22, 45, -35, 28, 29, -26, 36, 9, -14, 46, -10, 1, + 56, -27, 15, 66, -42, 28, 76, -55, 41, 86, -67, 53, + 24, 47, -33, 29, 32, -24, 37, 13, -12, 46, -7, 2, + 56, -24, 16, 66, -39, 29, 76, -53, 41, 86, -65, 53, + 25, 48, -30, 30, 35, -22, 38, 16, -11, 47, -4, 3, + 57, -22, 16, 67, -37, 29, 76, -51, 42, 86, -63, 54, + 27, 50, -28, 32, 37, -20, 39, 19, -9, 48, 0, 4, + 57, -19, 17, 67, -34, 30, 77, -48, 42, 86, -61, 54, + 28, 52, -25, 33, 40, -18, 40, 22, -8, 48, 3, 5, + 58, -16, 18, 67, -32, 31, 77, -46, 43, 87, -59, 55, + 30, 54, -22, 34, 42, -16, 41, 25, -6, 49, 6, 6, + 59, -12, 19, 68, -28, 31, 77, -43, 43, 87, -57, 55, + 32, 56, -20, 36, 45, -14, 42, 28, -4, 50, 10, 7, + 59, -9, 20, 68, -26, 32, 78, -40, 44, 87, -54, 55, + 33, 58, -17, 37, 47, -12, 43, 31, -3, 51, 13, 9, + 60, -6, 21, 69, -23, 33, 78, -38, 45, 88, -52, 56, + 35, 59, -15, 38, 50, -9, 44, 34, -1, 52, 16, 10, + 61, -3, 22, 69, -19, 34, 79, -35, 45, 88, -49, 56, + 37, 61, -12, 40, 52, -7, 46, 37, 1, 53, 20, 12, + 61, 1, 23, 70, -16, 35, 79, -32, 46, 89, -46, 57, + 38, 63, -9, 41, 55, -5, 47, 40, 3, 54, 23, 13, + 62, 4, 24, 71, -13, 36, 80, -29, 47, 89, -44, 58, + 40, 65, -7, 43, 57, -2, 48, 43, 5, 55, 26, 15, + 63, 8, 26, 71, -9, 37, 80, -26, 47, 89, -41, 58, + 42, 67, -4, 44, 59, 0, 49, 46, 7, 56, 29, 16, + 64, 11, 27, 72, -6, 38, 81, -22, 48, 90, -38, 59, + 43, 69, -1, 46, 61, 2, 50, 49, 9, 57, 32, 18, + 65, 14, 28, 73, -3, 39, 81, -19, 49, 90, -35, 60, + 45, 71, 1, 47, 64, 5, 52, 52, 11, 58, 36, 20, + 66, 18, 30, 74, 1, 40, 82, -16, 50, 91, -32, 60, + 47, 73, 4, 49, 66, 7, 53, 54, 13, 59, 39, 21, + 66, 21, 31, 74, 4, 41, 83, -12, 51, 91, -28, 61, + 48, 75, 6, 50, 68, 10, 55, 57, 15, 60, 42, 23, + 67, 25, 32, 75, 7, 42, 83, -9, 52, 92, -25, 62, + 50, 76, 9, 52, 70, 12, 56, 59, 17, 61, 45, 25, + 68, 28, 34, 76, 11, 43, 84, -6, 53, 93, -22, 63, + 52, 78, 12, 54, 73, 14, 57, 62, 20, 63, 48, 27, + 69, 31, 35, 77, 14, 45, 85, -2, 54, 93, -19, 64, + 53, 80, 14, 55, 75, 17, 59, 65, 22, 64, 51, 28, + 70, 34, 37, 78, 18, 46, 85, 1, 55, 94, -15, 65, + 55, 82, 17, 57, 77, 19, 60, 67, 24, 65, 54, 30, + 71, 38, 38, 79, 21, 47, 86, 4, 56, 94, -12, 65, + 13, 37, -56, 22, 14, -42, 32, -8, -25, 43, -26, -9, + 54, -41, 7, 64, -53, 22, 74, -64, 35, 85, -75, 48, + 14, 37, -55, 22, 15, -42, 32, -7, -25, 43, -25, -9, + 54, -40, 7, 64, -53, 22, 74, -64, 35, 85, -75, 48, + 14, 37, -55, 22, 15, -41, 32, -7, -25, 43, -25, -9, + 54, -40, 7, 64, -53, 22, 74, -64, 35, 85, -75, 48, + 14, 38, -54, 22, 16, -41, 33, -5, -25, 43, -24, -8, + 54, -39, 8, 64, -52, 22, 75, -63, 35, 85, -74, 48, + 15, 38, -53, 23, 18, -40, 33, -4, -24, 43, -23, -8, + 54, -38, 8, 64, -51, 22, 75, -63, 35, 85, -74, 48, + 16, 39, -51, 23, 19, -39, 33, -3, -24, 44, -21, -8, + 54, -37, 8, 65, -50, 22, 75, -62, 36, 85, -73, 48, + 17, 40, -50, 24, 21, -38, 34, -1, -23, 44, -20, -7, + 54, -36, 8, 65, -49, 22, 75, -61, 36, 85, -72, 48, + 18, 41, -48, 25, 23, -37, 34, 1, -22, 44, -18, -7, + 55, -34, 9, 65, -48, 23, 75, -60, 36, 85, -71, 49, + 19, 42, -46, 26, 25, -36, 35, 4, -21, 45, -15, -6, + 55, -32, 9, 65, -46, 23, 75, -59, 36, 85, -70, 49, + 20, 44, -44, 26, 27, -34, 35, 6, -20, 45, -13, -5, + 55, -30, 10, 65, -45, 23, 75, -57, 36, 85, -69, 49, + 22, 45, -42, 27, 29, -33, 36, 9, -19, 45, -11, -5, + 56, -28, 10, 66, -43, 24, 76, -56, 37, 86, -67, 49, + 23, 47, -40, 28, 31, -31, 37, 12, -18, 46, -8, -4, + 56, -26, 11, 66, -41, 24, 76, -54, 37, 86, -66, 50, + 25, 48, -37, 30, 34, -29, 37, 15, -17, 47, -5, -3, + 57, -23, 11, 66, -38, 25, 76, -52, 38, 86, -64, 50, + 26, 50, -35, 31, 36, -27, 38, 18, -15, 47, -2, -2, + 57, -20, 12, 67, -36, 25, 76, -49, 38, 86, -62, 50, + 27, 52, -32, 32, 39, -25, 39, 20, -14, 48, 1, -1, + 58, -17, 13, 67, -33, 26, 77, -47, 38, 86, -60, 51, + 29, 53, -30, 33, 41, -23, 40, 23, -12, 49, 4, 0, + 58, -14, 14, 67, -30, 27, 77, -45, 39, 87, -58, 51, + 31, 55, -27, 35, 44, -21, 41, 27, -10, 49, 8, 2, + 59, -11, 15, 68, -27, 27, 77, -42, 40, 87, -56, 51, + 32, 57, -24, 36, 46, -18, 42, 30, -9, 50, 11, 3, + 59, -8, 16, 68, -24, 28, 78, -39, 40, 87, -53, 52, + 34, 59, -22, 37, 48, -16, 43, 32, -7, 51, 14, 4, + 60, -5, 17, 69, -21, 29, 78, -37, 41, 88, -51, 52, + 35, 60, -19, 39, 51, -14, 45, 35, -5, 52, 17, 6, + 61, -1, 18, 70, -18, 30, 79, -34, 41, 88, -48, 53, + 37, 62, -16, 40, 53, -11, 46, 39, -3, 53, 21, 7, + 61, 2, 19, 70, -15, 31, 79, -31, 42, 89, -45, 54, + 39, 64, -14, 42, 56, -9, 47, 41, -1, 54, 24, 9, + 62, 5, 20, 71, -12, 32, 80, -28, 43, 89, -43, 54, + 40, 66, -11, 43, 58, -7, 48, 44, 1, 55, 27, 10, + 63, 9, 21, 71, -9, 33, 80, -25, 44, 89, -40, 55, + 42, 68, -9, 45, 60, -5, 49, 47, 3, 56, 30, 12, + 64, 12, 23, 72, -5, 34, 81, -22, 45, 90, -37, 56, + 43, 69, -6, 46, 62, -2, 51, 49, 4, 57, 33, 13, + 65, 15, 24, 73, -2, 35, 81, -18, 45, 90, -34, 56, + 45, 72, -3, 48, 65, 0, 52, 52, 7, 58, 37, 15, + 66, 19, 25, 74, 2, 36, 82, -15, 46, 91, -31, 57, + 47, 73, -1, 49, 67, 3, 53, 55, 9, 59, 40, 17, + 67, 22, 27, 74, 5, 37, 83, -12, 47, 92, -28, 58, + 48, 75, 2, 51, 69, 5, 55, 58, 11, 60, 43, 19, + 68, 25, 28, 75, 8, 38, 83, -8, 48, 92, -25, 59, + 50, 77, 4, 52, 71, 7, 56, 60, 13, 62, 45, 20, + 68, 28, 30, 76, 11, 39, 84, -5, 49, 93, -22, 59, + 52, 79, 7, 54, 73, 10, 58, 63, 15, 63, 49, 22, + 70, 32, 31, 77, 15, 41, 85, -2, 50, 93, -18, 60, + 53, 81, 10, 55, 75, 12, 59, 65, 17, 64, 51, 24, + 71, 35, 33, 78, 18, 42, 86, 2, 51, 94, -15, 61, + 55, 83, 12, 57, 77, 15, 60, 68, 19, 65, 54, 26, + 72, 38, 34, 79, 22, 43, 86, 5, 52, 95, -12, 62, + 14, 39, -59, 22, 18, -46, 33, -4, -30, 43, -23, -13, + 54, -39, 3, 64, -52, 18, 75, -63, 31, 85, -74, 44, + 15, 40, -59, 23, 18, -46, 33, -4, -29, 43, -22, -13, + 54, -38, 3, 64, -51, 18, 75, -63, 31, 85, -74, 44, + 15, 40, -58, 23, 19, -45, 33, -3, -29, 43, -22, -13, + 54, -38, 3, 64, -51, 18, 75, -62, 31, 85, -73, 44, + 16, 40, -57, 23, 20, -45, 33, -2, -29, 43, -21, -13, + 54, -37, 3, 65, -50, 18, 75, -62, 31, 85, -73, 44, + 16, 41, -56, 24, 21, -44, 33, -1, -29, 44, -20, -12, + 54, -36, 3, 65, -50, 18, 75, -61, 31, 85, -72, 45, + 17, 42, -55, 24, 22, -43, 34, 0, -28, 44, -19, -12, + 55, -35, 4, 65, -49, 18, 75, -61, 32, 85, -72, 45, + 18, 42, -54, 25, 24, -42, 34, 2, -27, 44, -17, -12, + 55, -34, 4, 65, -48, 18, 75, -60, 32, 85, -71, 45, + 19, 43, -52, 25, 25, -41, 34, 4, -27, 44, -15, -11, + 55, -32, 4, 65, -46, 19, 75, -58, 32, 85, -70, 45, + 20, 45, -50, 26, 27, -40, 35, 6, -26, 45, -13, -11, + 55, -30, 5, 65, -45, 19, 75, -57, 32, 85, -69, 45, + 21, 46, -48, 27, 29, -38, 36, 9, -25, 45, -11, -10, + 56, -28, 5, 66, -43, 19, 75, -56, 33, 85, -68, 45, + 22, 47, -46, 28, 31, -37, 36, 11, -24, 46, -9, -9, + 56, -26, 6, 66, -41, 20, 76, -54, 33, 86, -66, 46, + 24, 48, -44, 29, 33, -35, 37, 14, -22, 46, -6, -8, + 56, -24, 6, 66, -39, 20, 76, -52, 33, 86, -65, 46, + 25, 50, -41, 30, 36, -33, 38, 17, -21, 47, -3, -7, + 57, -21, 7, 66, -37, 21, 76, -50, 34, 86, -63, 46, + 27, 51, -39, 31, 38, -31, 39, 19, -20, 47, 0, -6, + 57, -18, 8, 67, -34, 21, 76, -48, 34, 86, -61, 47, + 28, 53, -36, 32, 40, -29, 40, 22, -18, 48, 3, -5, + 58, -16, 9, 67, -32, 22, 77, -46, 35, 87, -59, 47, + 29, 54, -34, 34, 43, -27, 40, 25, -17, 49, 6, -4, + 58, -13, 9, 68, -29, 23, 77, -44, 35, 87, -57, 47, + 31, 56, -31, 35, 45, -25, 42, 28, -15, 50, 9, -3, + 59, -10, 11, 68, -26, 23, 78, -41, 36, 87, -55, 48, + 33, 58, -29, 36, 47, -23, 43, 31, -13, 50, 12, -1, + 59, -6, 11, 69, -23, 24, 78, -38, 36, 88, -52, 48, + 34, 60, -26, 38, 50, -21, 44, 34, -12, 51, 15, 0, + 60, -3, 12, 69, -20, 25, 78, -36, 37, 88, -50, 49, + 36, 61, -24, 39, 52, -18, 45, 37, -10, 52, 19, 1, + 61, 0, 14, 70, -17, 26, 79, -33, 38, 88, -48, 49, + 37, 63, -21, 41, 54, -16, 46, 40, -8, 53, 22, 3, + 62, 3, 15, 70, -14, 27, 79, -30, 38, 89, -45, 50, + 39, 65, -18, 42, 56, -14, 47, 42, -6, 54, 25, 4, + 62, 7, 16, 71, -11, 28, 80, -27, 39, 89, -42, 51, + 41, 67, -16, 43, 59, -11, 48, 45, -4, 55, 28, 6, + 63, 10, 17, 72, -8, 29, 80, -24, 40, 90, -39, 51, + 42, 68, -13, 45, 61, -9, 50, 48, -2, 56, 31, 7, + 64, 13, 18, 72, -4, 30, 81, -21, 41, 90, -36, 52, + 44, 70, -11, 46, 63, -7, 51, 50, 0, 57, 34, 9, + 65, 16, 20, 73, -1, 31, 82, -18, 42, 91, -33, 53, + 46, 72, -8, 48, 65, -4, 52, 53, 2, 58, 38, 11, + 66, 20, 21, 74, 2, 32, 82, -14, 43, 91, -30, 53, + 47, 74, -5, 49, 67, -2, 54, 56, 4, 59, 40, 13, + 67, 23, 23, 75, 6, 33, 83, -11, 43, 92, -27, 54, + 49, 76, -3, 51, 69, 0, 55, 58, 6, 61, 43, 14, + 68, 26, 24, 75, 9, 34, 83, -8, 44, 92, -24, 55, + 50, 78, 0, 52, 72, 3, 56, 61, 8, 62, 46, 16, + 69, 29, 25, 76, 12, 35, 84, -5, 45, 93, -21, 56, + 52, 80, 3, 54, 74, 5, 58, 63, 11, 63, 49, 18, + 70, 33, 27, 77, 16, 37, 85, -1, 47, 93, -17, 57, + 54, 81, 5, 55, 76, 8, 59, 66, 13, 64, 52, 20, + 71, 36, 29, 78, 19, 38, 86, 2, 48, 94, -14, 58, + 55, 83, 7, 57, 78, 10, 60, 68, 15, 65, 55, 22, + 72, 39, 30, 79, 22, 39, 86, 6, 49, 95, -11, 59, + 16, 42, -63, 23, 22, -50, 33, -1, -34, 43, -20, -18, + 54, -36, -2, 65, -49, 13, 75, -61, 27, 85, -72, 40, + 16, 43, -62, 23, 22, -50, 33, 0, -34, 44, -19, -18, + 54, -36, -2, 65, -49, 13, 75, -61, 27, 85, -72, 40, + 16, 43, -62, 24, 23, -50, 33, 0, -34, 44, -19, -18, + 54, -35, -2, 65, -49, 13, 75, -61, 27, 85, -72, 40, + 17, 43, -61, 24, 23, -49, 33, 1, -34, 44, -18, -18, + 54, -35, -2, 65, -48, 13, 75, -60, 27, 85, -71, 40, + 17, 44, -60, 24, 24, -48, 34, 2, -33, 44, -17, -17, + 55, -34, -1, 65, -48, 13, 75, -60, 27, 85, -71, 40, + 18, 44, -59, 25, 25, -48, 34, 4, -33, 44, -16, -17, + 55, -33, -1, 65, -47, 13, 75, -59, 27, 85, -70, 40, + 19, 45, -58, 25, 27, -47, 34, 5, -32, 44, -14, -17, + 55, -31, -1, 65, -46, 14, 75, -58, 27, 85, -70, 41, + 20, 46, -56, 26, 28, -46, 35, 7, -31, 45, -12, -16, + 55, -30, 0, 65, -44, 14, 75, -57, 28, 85, -69, 41, + 21, 47, -54, 27, 30, -44, 35, 9, -30, 45, -10, -15, + 55, -28, 0, 65, -43, 14, 75, -56, 28, 85, -68, 41, + 22, 48, -52, 28, 32, -43, 36, 11, -30, 46, -8, -15, + 56, -26, 0, 66, -41, 15, 76, -54, 28, 86, -66, 41, + 23, 49, -50, 29, 34, -41, 37, 14, -28, 46, -6, -14, + 56, -24, 1, 66, -39, 15, 76, -53, 28, 86, -65, 41, + 24, 50, -48, 30, 36, -40, 37, 16, -27, 47, -4, -13, + 56, -22, 2, 66, -37, 16, 76, -51, 29, 86, -64, 42, + 26, 52, -46, 31, 38, -38, 38, 19, -26, 47, -1, -12, + 57, -19, 2, 67, -35, 16, 76, -49, 29, 86, -62, 42, + 27, 53, -43, 32, 40, -36, 39, 22, -25, 48, 2, -11, + 57, -17, 3, 67, -33, 17, 77, -47, 30, 86, -60, 42, + 29, 55, -41, 33, 42, -34, 40, 24, -23, 48, 5, -10, + 58, -14, 4, 67, -30, 17, 77, -45, 30, 87, -58, 43, + 30, 56, -39, 34, 44, -32, 41, 27, -22, 49, 8, -9, + 58, -11, 5, 68, -28, 18, 77, -42, 31, 87, -56, 43, + 32, 58, -36, 36, 47, -30, 42, 30, -20, 50, 11, -8, + 59, -8, 6, 68, -25, 19, 78, -40, 31, 87, -54, 44, + 33, 59, -33, 37, 49, -28, 43, 33, -18, 51, 14, -6, + 60, -5, 7, 69, -22, 19, 78, -37, 32, 88, -51, 44, + 35, 61, -31, 38, 51, -26, 44, 35, -16, 52, 17, -5, + 60, -2, 8, 69, -19, 20, 78, -34, 33, 88, -49, 45, + 36, 63, -29, 39, 53, -23, 45, 38, -15, 52, 20, -4, + 61, 1, 9, 70, -16, 21, 79, -32, 33, 88, -46, 45, + 38, 64, -26, 41, 56, -21, 46, 41, -13, 53, 23, -2, + 62, 5, 10, 71, -13, 22, 79, -29, 34, 89, -44, 46, + 39, 66, -23, 42, 58, -19, 48, 44, -11, 54, 26, -1, + 63, 8, 11, 71, -9, 23, 80, -26, 35, 89, -41, 47, + 41, 68, -21, 44, 60, -16, 49, 46, -9, 55, 29, 1, + 63, 11, 12, 72, -6, 24, 81, -23, 36, 90, -38, 47, + 43, 69, -18, 45, 62, -14, 50, 49, -7, 56, 32, 3, + 64, 14, 14, 72, -3, 25, 81, -20, 36, 90, -35, 48, + 44, 71, -16, 47, 64, -12, 51, 51, -5, 57, 35, 4, + 65, 17, 15, 73, 0, 26, 82, -17, 37, 91, -32, 49, + 46, 73, -13, 48, 66, -9, 53, 54, -3, 59, 39, 6, + 66, 21, 16, 74, 4, 27, 82, -13, 38, 91, -29, 49, + 47, 75, -10, 50, 68, -7, 54, 57, -1, 60, 41, 8, + 67, 24, 18, 75, 7, 28, 83, -10, 39, 92, -26, 50, + 49, 77, -8, 51, 70, -5, 55, 59, 1, 61, 44, 9, + 68, 27, 19, 75, 10, 30, 84, -7, 40, 92, -23, 51, + 51, 78, -5, 53, 72, -2, 56, 62, 3, 62, 47, 11, + 69, 30, 21, 76, 13, 31, 84, -4, 41, 93, -20, 52, + 52, 80, -3, 54, 75, 0, 58, 64, 6, 63, 50, 13, + 70, 34, 22, 77, 17, 32, 85, 0, 42, 94, -17, 53, + 54, 82, 0, 56, 77, 3, 59, 67, 8, 64, 53, 15, + 71, 37, 24, 78, 20, 33, 86, 3, 43, 94, -13, 54, + 55, 84, 2, 57, 78, 5, 61, 69, 10, 66, 56, 17, + 72, 40, 25, 79, 23, 35, 87, 6, 44, 95, -10, 55, + 17, 45, -66, 24, 25, -54, 34, 3, -39, 44, -17, -22, + 55, -34, -6, 65, -47, 9, 75, -60, 23, 85, -71, 36, + 17, 45, -65, 24, 25, -54, 34, 3, -38, 44, -16, -22, + 55, -33, -6, 65, -47, 9, 75, -59, 23, 85, -71, 36, + 17, 45, -65, 24, 26, -53, 34, 4, -38, 44, -16, -22, + 55, -33, -6, 65, -47, 9, 75, -59, 23, 85, -70, 36, + 18, 46, -64, 25, 27, -53, 34, 5, -38, 44, -15, -22, + 55, -32, -6, 65, -46, 9, 75, -59, 23, 85, -70, 36, + 18, 46, -63, 25, 27, -52, 34, 6, -37, 44, -14, -22, + 55, -31, -6, 65, -46, 9, 75, -58, 23, 85, -70, 37, + 19, 47, -62, 25, 28, -52, 34, 7, -37, 44, -13, -21, + 55, -30, -5, 65, -45, 9, 75, -57, 23, 85, -69, 37, + 20, 47, -61, 26, 30, -51, 35, 8, -36, 45, -12, -21, + 55, -29, -5, 65, -44, 10, 75, -56, 23, 85, -68, 37, + 21, 48, -59, 27, 31, -49, 35, 10, -36, 45, -10, -20, + 55, -28, -5, 65, -42, 10, 75, -55, 24, 85, -67, 37, + 22, 49, -58, 27, 33, -48, 36, 12, -35, 45, -8, -20, + 56, -26, -4, 66, -41, 10, 76, -54, 24, 86, -66, 37, + 23, 50, -56, 28, 34, -47, 36, 14, -34, 46, -6, -19, + 56, -24, -4, 66, -39, 11, 76, -53, 24, 86, -65, 37, + 24, 51, -54, 29, 36, -45, 37, 16, -33, 46, -4, -18, + 56, -22, -3, 66, -38, 11, 76, -51, 24, 86, -64, 38, + 25, 52, -52, 30, 38, -44, 38, 18, -32, 47, -1, -17, + 57, -20, -3, 66, -36, 11, 76, -49, 25, 86, -62, 38, + 26, 53, -50, 31, 40, -42, 39, 21, -30, 47, 1, -16, + 57, -17, -2, 67, -33, 12, 76, -47, 25, 86, -60, 38, + 28, 55, -47, 32, 42, -40, 39, 24, -29, 48, 4, -16, + 58, -15, -1, 67, -31, 13, 77, -45, 26, 87, -59, 39, + 29, 56, -45, 33, 44, -38, 40, 26, -27, 49, 7, -14, + 58, -12, 0, 68, -29, 13, 77, -43, 26, 87, -57, 39, + 31, 57, -43, 35, 46, -36, 41, 29, -26, 49, 9, -13, + 59, -9, 0, 68, -26, 14, 77, -41, 27, 87, -55, 39, + 32, 59, -40, 36, 48, -34, 42, 32, -24, 50, 13, -12, + 59, -6, 1, 68, -23, 15, 78, -38, 27, 87, -52, 40, + 34, 61, -38, 37, 50, -32, 43, 34, -23, 51, 16, -11, + 60, -3, 2, 69, -20, 15, 78, -36, 28, 88, -50, 40, + 35, 62, -35, 39, 52, -30, 44, 37, -21, 52, 19, -9, + 61, 0, 3, 69, -18, 16, 79, -33, 29, 88, -48, 41, + 37, 64, -33, 40, 54, -28, 45, 39, -19, 53, 21, -8, + 61, 3, 4, 70, -15, 17, 79, -31, 29, 88, -45, 42, + 38, 65, -30, 41, 57, -25, 47, 42, -17, 54, 25, -6, + 62, 6, 6, 71, -11, 18, 80, -27, 30, 89, -43, 42, + 40, 67, -27, 43, 59, -23, 48, 45, -15, 55, 28, -5, + 63, 9, 7, 71, -8, 19, 80, -25, 31, 89, -40, 43, + 41, 69, -25, 44, 61, -21, 49, 47, -13, 56, 31, -3, + 64, 12, 8, 72, -5, 20, 81, -22, 32, 90, -37, 43, + 43, 70, -23, 46, 63, -18, 50, 50, -11, 57, 34, -2, + 64, 15, 9, 73, -2, 21, 81, -19, 32, 90, -34, 44, + 44, 72, -20, 47, 65, -16, 51, 52, -9, 58, 36, 0, + 65, 18, 11, 73, 1, 22, 82, -16, 33, 91, -32, 45, + 46, 74, -17, 49, 67, -14, 53, 55, -7, 59, 40, 2, + 66, 22, 12, 74, 5, 23, 82, -12, 34, 91, -28, 46, + 48, 76, -15, 50, 69, -11, 54, 58, -5, 60, 42, 3, + 67, 25, 14, 75, 8, 24, 83, -9, 35, 92, -25, 46, + 49, 77, -12, 51, 71, -9, 55, 60, -3, 61, 45, 5, + 68, 28, 15, 76, 11, 25, 84, -6, 36, 92, -22, 47, + 51, 79, -10, 53, 73, -7, 57, 62, -1, 62, 48, 7, + 69, 31, 16, 76, 14, 27, 84, -3, 37, 93, -19, 48, + 53, 81, -7, 54, 75, -4, 58, 65, 1, 63, 51, 9, + 70, 34, 18, 77, 17, 28, 85, 1, 38, 94, -16, 49, + 54, 83, -5, 56, 77, -2, 59, 67, 3, 65, 54, 11, + 71, 37, 20, 78, 21, 29, 86, 4, 39, 94, -13, 50, + 56, 84, -2, 57, 79, 1, 61, 70, 6, 66, 56, 12, + 72, 40, 21, 79, 24, 31, 87, 7, 41, 95, -10, 51, + 18, 47, -69, 25, 28, -58, 34, 6, -43, 44, -14, -27, + 55, -31, -10, 65, -45, 5, 75, -58, 19, 85, -69, 33, + 18, 48, -69, 25, 29, -57, 34, 6, -42, 44, -13, -26, + 55, -31, -10, 65, -45, 5, 75, -58, 19, 85, -69, 33, + 18, 48, -68, 25, 29, -57, 34, 7, -42, 44, -13, -26, + 55, -30, -10, 65, -45, 5, 75, -57, 19, 85, -69, 33, + 19, 48, -67, 25, 30, -57, 34, 8, -42, 44, -12, -26, + 55, -30, -10, 65, -44, 5, 75, -57, 19, 85, -69, 33, + 19, 48, -67, 26, 30, -56, 35, 9, -42, 45, -11, -26, + 55, -29, -10, 65, -44, 5, 75, -56, 19, 85, -68, 33, + 20, 49, -66, 26, 31, -55, 35, 10, -41, 45, -10, -25, + 55, -28, -10, 65, -43, 5, 75, -56, 19, 85, -68, 33, + 21, 49, -64, 27, 32, -54, 35, 11, -40, 45, -9, -25, + 55, -27, -9, 65, -42, 5, 75, -55, 19, 85, -67, 33, + 22, 50, -63, 27, 34, -53, 36, 13, -40, 45, -7, -25, + 56, -25, -9, 66, -40, 6, 76, -54, 20, 86, -66, 33, + 23, 51, -61, 28, 35, -52, 36, 15, -39, 46, -5, -24, + 56, -24, -8, 66, -39, 6, 76, -52, 20, 86, -65, 33, + 24, 52, -60, 29, 37, -51, 37, 17, -38, 46, -4, -23, + 56, -22, -8, 66, -37, 6, 76, -51, 20, 86, -64, 34, + 25, 53, -58, 30, 38, -49, 38, 19, -37, 47, -1, -23, + 57, -20, -7, 66, -36, 7, 76, -50, 20, 86, -62, 34, + 26, 54, -56, 31, 40, -48, 38, 21, -36, 47, 1, -22, + 57, -18, -7, 67, -34, 7, 76, -48, 21, 86, -61, 34, + 27, 55, -53, 32, 42, -46, 39, 23, -34, 48, 4, -21, + 57, -15, -6, 67, -31, 8, 77, -46, 21, 86, -59, 35, + 28, 56, -51, 33, 44, -44, 40, 26, -33, 48, 6, -20, + 58, -13, -5, 67, -29, 8, 77, -44, 22, 87, -57, 35, + 30, 58, -49, 34, 46, -42, 41, 28, -32, 49, 9, -19, + 58, -10, -5, 68, -27, 9, 77, -42, 22, 87, -56, 35, + 31, 59, -47, 35, 48, -40, 42, 30, -30, 50, 11, -18, + 59, -8, -4, 68, -24, 10, 78, -40, 23, 87, -54, 36, + 33, 60, -44, 36, 50, -38, 43, 33, -28, 51, 14, -16, + 60, -5, -3, 69, -22, 10, 78, -37, 23, 88, -51, 36, + 34, 62, -42, 38, 52, -36, 44, 36, -27, 51, 17, -15, + 60, -2, -2, 69, -19, 11, 78, -34, 24, 88, -49, 37, + 36, 63, -39, 39, 54, -34, 45, 38, -25, 52, 20, -14, + 61, 1, -1, 70, -16, 12, 79, -32, 25, 88, -47, 37, + 37, 65, -37, 40, 56, -32, 46, 41, -23, 53, 23, -12, + 61, 4, 0, 70, -13, 13, 79, -29, 25, 89, -44, 38, + 39, 67, -34, 42, 58, -29, 47, 44, -21, 54, 26, -11, + 62, 7, 2, 71, -10, 14, 80, -26, 26, 89, -41, 38, + 40, 68, -32, 43, 60, -27, 48, 46, -19, 55, 29, -9, + 63, 10, 3, 71, -7, 15, 80, -23, 27, 89, -39, 39, + 42, 70, -29, 44, 62, -25, 49, 49, -18, 56, 32, -8, + 64, 13, 4, 72, -4, 16, 81, -20, 28, 90, -36, 40, + 43, 71, -27, 46, 64, -23, 51, 51, -16, 57, 35, -6, + 65, 16, 5, 73, -1, 17, 81, -18, 28, 90, -33, 40, + 45, 73, -24, 47, 66, -21, 52, 53, -14, 58, 38, -4, + 65, 20, 6, 73, 2, 18, 82, -15, 29, 91, -31, 41, + 46, 75, -22, 49, 68, -18, 53, 56, -11, 59, 41, -3, + 66, 23, 8, 74, 6, 19, 83, -11, 30, 91, -27, 42, + 48, 76, -19, 50, 70, -16, 54, 59, -9, 60, 43, -1, + 67, 26, 9, 75, 9, 20, 83, -8, 31, 92, -24, 43, + 50, 78, -17, 52, 72, -13, 56, 61, -7, 61, 46, 1, + 68, 29, 11, 76, 12, 21, 84, -5, 32, 92, -21, 43, + 51, 80, -14, 53, 74, -11, 57, 63, -5, 62, 49, 3, + 69, 32, 12, 77, 15, 23, 85, -2, 33, 93, -18, 44, + 53, 82, -11, 55, 76, -8, 58, 66, -3, 64, 52, 5, + 70, 35, 14, 77, 18, 24, 85, 2, 34, 94, -15, 45, + 54, 83, -9, 56, 78, -6, 60, 68, -1, 65, 55, 6, + 71, 38, 15, 78, 21, 25, 86, 5, 36, 94, -12, 46, + 56, 85, -6, 58, 80, -4, 61, 70, 1, 66, 57, 8, + 72, 41, 17, 79, 25, 27, 87, 8, 37, 95, -9, 47, + 19, 50, -72, 26, 31, -61, 35, 9, -47, 45, -11, -31, + 55, -28, -15, 65, -43, 0, 75, -56, 15, 85, -68, 29, + 19, 50, -72, 26, 32, -61, 35, 10, -46, 45, -10, -31, + 55, -28, -14, 65, -43, 1, 75, -56, 15, 85, -68, 29, + 20, 50, -71, 26, 32, -61, 35, 10, -46, 45, -10, -30, + 55, -28, -14, 65, -43, 1, 75, -56, 15, 85, -67, 29, + 20, 50, -71, 26, 33, -60, 35, 11, -46, 45, -9, -30, + 55, -27, -14, 65, -42, 1, 75, -55, 15, 85, -67, 29, + 20, 51, -70, 27, 33, -60, 35, 12, -46, 45, -8, -30, + 55, -26, -14, 65, -41, 1, 75, -54, 15, 85, -67, 29, + 21, 51, -69, 27, 34, -59, 36, 13, -45, 45, -7, -30, + 56, -25, -14, 66, -41, 1, 75, -54, 15, 85, -66, 29, + 22, 52, -68, 27, 35, -58, 36, 14, -44, 45, -6, -29, + 56, -24, -14, 66, -40, 1, 76, -53, 15, 86, -65, 29, + 23, 52, -66, 28, 36, -57, 36, 16, -44, 46, -4, -29, + 56, -23, -13, 66, -38, 2, 76, -52, 16, 86, -64, 29, + 23, 53, -65, 29, 38, -56, 37, 17, -43, 46, -3, -28, + 56, -21, -13, 66, -37, 2, 76, -51, 16, 86, -63, 30, + 24, 54, -63, 30, 39, -55, 37, 19, -42, 47, -1, -27, + 56, -20, -12, 66, -35, 2, 76, -49, 16, 86, -62, 30, + 25, 55, -61, 30, 41, -53, 38, 21, -41, 47, 1, -27, + 57, -18, -12, 67, -34, 3, 76, -48, 16, 86, -61, 30, + 27, 56, -59, 31, 42, -52, 39, 23, -40, 47, 3, -26, + 57, -16, -11, 67, -32, 3, 76, -46, 17, 86, -59, 30, + 28, 57, -57, 32, 44, -50, 39, 25, -38, 48, 6, -25, + 58, -13, -10, 67, -30, 4, 77, -44, 17, 87, -58, 31, + 29, 58, -55, 33, 46, -48, 40, 28, -37, 49, 8, -24, + 58, -11, -10, 68, -28, 4, 77, -42, 18, 87, -56, 31, + 30, 59, -53, 34, 48, -46, 41, 30, -36, 49, 11, -23, + 59, -8, -9, 68, -25, 5, 77, -40, 18, 87, -54, 31, + 32, 60, -51, 36, 49, -44, 42, 32, -34, 50, 13, -22, + 59, -6, -8, 68, -23, 6, 78, -38, 19, 87, -52, 32, + 33, 62, -48, 37, 51, -42, 43, 35, -33, 51, 16, -20, + 60, -3, -7, 69, -20, 6, 78, -35, 19, 88, -50, 32, + 35, 63, -46, 38, 53, -40, 44, 37, -31, 52, 19, -19, + 60, 0, -6, 69, -17, 7, 79, -33, 20, 88, -48, 33, + 36, 65, -43, 39, 55, -38, 45, 40, -29, 52, 22, -18, + 61, 3, -5, 70, -15, 8, 79, -31, 21, 88, -45, 33, + 38, 66, -41, 41, 57, -36, 46, 42, -28, 53, 24, -17, + 62, 6, -4, 70, -12, 9, 79, -28, 21, 89, -43, 34, + 39, 68, -38, 42, 59, -34, 47, 45, -26, 54, 28, -15, + 62, 9, -3, 71, -9, 10, 80, -25, 22, 89, -40, 35, + 41, 69, -36, 43, 61, -31, 48, 47, -24, 55, 30, -13, + 63, 12, -2, 72, -6, 11, 80, -22, 23, 90, -38, 35, + 42, 71, -33, 45, 63, -29, 50, 50, -22, 56, 33, -12, + 64, 15, 0, 72, -3, 12, 81, -19, 24, 90, -35, 36, + 44, 72, -31, 46, 65, -27, 51, 52, -20, 57, 36, -10, + 65, 18, 1, 73, 0, 13, 81, -16, 24, 90, -32, 37, + 45, 74, -29, 48, 67, -25, 52, 55, -18, 58, 39, -9, + 66, 21, 2, 74, 3, 14, 82, -13, 25, 91, -30, 37, + 47, 76, -26, 49, 69, -22, 53, 57, -16, 59, 42, -7, + 67, 24, 4, 74, 7, 15, 83, -10, 26, 92, -26, 38, + 48, 77, -23, 51, 71, -20, 55, 60, -14, 60, 44, -5, + 67, 27, 5, 75, 10, 16, 83, -7, 27, 92, -23, 39, + 50, 79, -21, 52, 73, -18, 56, 62, -12, 61, 47, -3, + 68, 30, 7, 76, 13, 17, 84, -4, 28, 93, -20, 40, + 51, 81, -18, 53, 75, -15, 57, 64, -10, 63, 50, -2, + 69, 33, 8, 77, 16, 19, 85, -1, 29, 93, -18, 41, + 53, 82, -16, 55, 77, -13, 59, 67, -7, 64, 53, 0, + 70, 36, 10, 78, 19, 20, 85, 3, 31, 94, -14, 42, + 55, 84, -13, 56, 79, -10, 60, 69, -5, 65, 55, 2, + 71, 39, 11, 78, 22, 21, 86, 6, 32, 94, -11, 42, + 56, 86, -11, 58, 81, -8, 61, 71, -3, 66, 58, 4, + 72, 42, 13, 79, 25, 23, 87, 9, 33, 95, -8, 43, + 20, 52, -75, 26, 35, -65, 35, 13, -51, 45, -7, -35, + 55, -25, -19, 65, -41, -4, 75, -54, 10, 85, -66, 24, + 21, 53, -75, 27, 35, -65, 35, 14, -51, 45, -7, -35, + 55, -25, -19, 65, -40, -4, 75, -54, 10, 85, -66, 24, + 21, 53, -75, 27, 36, -65, 35, 14, -51, 45, -6, -35, + 55, -25, -19, 65, -40, -4, 75, -53, 10, 85, -66, 24, + 21, 53, -74, 27, 36, -64, 36, 15, -50, 45, -6, -35, + 56, -24, -19, 66, -39, -4, 75, -53, 10, 86, -65, 24, + 22, 53, -73, 27, 37, -64, 36, 15, -50, 45, -5, -35, + 56, -23, -19, 66, -39, -4, 76, -52, 11, 86, -65, 25, + 22, 54, -72, 28, 37, -63, 36, 16, -49, 46, -4, -34, + 56, -23, -18, 66, -38, -4, 76, -52, 11, 86, -64, 25, + 23, 54, -71, 28, 38, -62, 36, 18, -49, 46, -3, -34, + 56, -21, -18, 66, -37, -3, 76, -51, 11, 86, -64, 25, + 24, 55, -70, 29, 39, -61, 37, 19, -48, 46, -1, -33, + 56, -20, -18, 66, -36, -3, 76, -50, 11, 86, -63, 25, + 24, 55, -68, 30, 41, -60, 37, 20, -47, 47, 0, -33, + 57, -19, -17, 66, -35, -3, 76, -49, 11, 86, -62, 25, + 25, 56, -67, 30, 42, -59, 38, 22, -46, 47, 2, -32, + 57, -17, -17, 67, -33, -2, 76, -47, 12, 86, -60, 25, + 26, 57, -65, 31, 43, -57, 39, 24, -45, 47, 4, -31, + 57, -15, -16, 67, -31, -2, 76, -46, 12, 86, -59, 26, + 27, 58, -63, 32, 45, -56, 39, 26, -44, 48, 6, -31, + 58, -13, -16, 67, -30, -2, 77, -44, 12, 86, -58, 26, + 29, 59, -61, 33, 46, -54, 40, 28, -43, 48, 8, -30, + 58, -11, -15, 67, -28, -1, 77, -42, 13, 87, -56, 26, + 30, 60, -59, 34, 48, -53, 41, 30, -42, 49, 11, -29, + 58, -9, -14, 68, -25, 0, 77, -40, 13, 87, -54, 27, + 31, 61, -57, 35, 50, -51, 42, 32, -40, 50, 13, -28, + 59, -6, -14, 68, -23, 0, 78, -38, 14, 87, -53, 27, + 32, 62, -55, 36, 51, -49, 42, 35, -39, 50, 16, -27, + 59, -4, -13, 69, -21, 1, 78, -36, 14, 87, -51, 27, + 34, 64, -52, 38, 53, -47, 44, 37, -37, 51, 18, -25, + 60, -1, -12, 69, -18, 2, 78, -34, 15, 88, -48, 28, + 35, 65, -50, 39, 55, -45, 44, 39, -36, 52, 21, -24, + 61, 2, -11, 70, -16, 2, 79, -31, 15, 88, -46, 28, + 37, 66, -48, 40, 57, -43, 45, 42, -34, 53, 24, -23, + 61, 5, -10, 70, -13, 3, 79, -29, 16, 89, -44, 29, + 38, 67, -46, 41, 59, -41, 47, 44, -32, 54, 26, -21, + 62, 7, -9, 71, -10, 4, 80, -26, 17, 89, -42, 30, + 40, 69, -43, 43, 61, -38, 48, 47, -30, 55, 29, -20, + 63, 11, -7, 71, -7, 5, 80, -23, 18, 89, -39, 30, + 41, 71, -41, 44, 63, -36, 49, 49, -28, 55, 32, -18, + 63, 13, -6, 72, -4, 6, 81, -21, 18, 90, -36, 31, + 43, 72, -38, 45, 64, -34, 50, 51, -27, 56, 35, -17, + 64, 16, -5, 72, -1, 7, 81, -18, 19, 90, -34, 32, + 44, 74, -36, 47, 66, -32, 51, 54, -25, 57, 37, -15, + 65, 19, -4, 73, 2, 8, 82, -15, 20, 91, -31, 32, + 46, 75, -33, 48, 68, -30, 52, 56, -23, 58, 40, -14, + 66, 22, -2, 74, 5, 9, 82, -12, 21, 91, -28, 33, + 47, 77, -31, 50, 70, -27, 54, 58, -21, 60, 43, -12, + 67, 25, -1, 75, 8, 10, 83, -9, 22, 92, -25, 34, + 49, 78, -28, 51, 72, -25, 55, 61, -19, 61, 46, -10, + 68, 28, 0, 75, 11, 12, 83, -6, 23, 92, -22, 35, + 50, 80, -26, 52, 74, -22, 56, 63, -16, 62, 48, -8, + 69, 31, 2, 76, 14, 13, 84, -3, 24, 93, -19, 35, + 52, 82, -23, 54, 76, -20, 57, 65, -14, 63, 51, -6, + 70, 34, 3, 77, 17, 14, 85, 0, 25, 93, -16, 36, + 53, 83, -20, 55, 78, -18, 59, 68, -12, 64, 54, -4, + 71, 37, 5, 78, 20, 15, 86, 4, 26, 94, -13, 37, + 55, 85, -18, 57, 80, -15, 60, 70, -10, 65, 56, -3, + 72, 40, 7, 79, 23, 17, 86, 7, 27, 95, -10, 38, + 56, 87, -16, 58, 81, -13, 62, 72, -8, 66, 59, -1, + 73, 43, 8, 80, 26, 18, 87, 10, 28, 95, -7, 39, + 22, 55, -78, 27, 38, -69, 36, 17, -55, 45, -4, -39, + 56, -23, -23, 66, -38, -8, 76, -52, 6, 86, -64, 20, + 22, 55, -78, 27, 38, -68, 36, 17, -55, 45, -4, -39, + 56, -22, -23, 66, -38, -8, 76, -52, 6, 86, -64, 20, + 22, 55, -78, 28, 39, -68, 36, 17, -54, 46, -3, -39, + 56, -22, -23, 66, -38, -8, 76, -51, 6, 86, -64, 20, + 22, 55, -77, 28, 39, -68, 36, 18, -54, 46, -3, -39, + 56, -21, -23, 66, -37, -8, 76, -51, 6, 86, -64, 21, + 23, 56, -76, 28, 40, -67, 36, 19, -54, 46, -2, -39, + 56, -21, -23, 66, -37, -8, 76, -50, 7, 86, -63, 21, + 23, 56, -75, 29, 40, -66, 37, 19, -53, 46, -1, -38, + 56, -20, -23, 66, -36, -8, 76, -50, 7, 86, -63, 21, + 24, 56, -74, 29, 41, -66, 37, 21, -53, 46, 0, -38, + 56, -19, -22, 66, -35, -7, 76, -49, 7, 86, -62, 21, + 25, 57, -73, 30, 42, -65, 37, 22, -52, 47, 1, -37, + 57, -18, -22, 66, -34, -7, 76, -48, 7, 86, -61, 21, + 25, 57, -72, 30, 43, -64, 38, 23, -51, 47, 3, -37, + 57, -16, -21, 67, -32, -7, 76, -47, 7, 86, -60, 21, + 26, 58, -70, 31, 44, -62, 38, 25, -50, 47, 5, -36, + 57, -15, -21, 67, -31, -6, 76, -45, 8, 86, -59, 22, + 27, 59, -69, 32, 46, -61, 39, 26, -49, 48, 6, -35, + 57, -13, -20, 67, -29, -6, 77, -44, 8, 86, -58, 22, + 28, 60, -67, 33, 47, -60, 40, 28, -48, 48, 8, -35, + 58, -11, -20, 67, -28, -6, 77, -43, 8, 87, -56, 22, + 30, 61, -65, 34, 48, -58, 40, 30, -47, 49, 11, -34, + 58, -9, -19, 68, -26, -5, 77, -41, 9, 87, -55, 22, + 31, 62, -63, 35, 50, -56, 41, 32, -46, 49, 13, -33, + 59, -6, -18, 68, -23, -4, 77, -39, 9, 87, -53, 23, + 32, 63, -61, 36, 52, -55, 42, 34, -44, 50, 15, -32, + 59, -4, -18, 68, -21, -4, 78, -37, 10, 87, -51, 23, + 33, 64, -59, 37, 53, -53, 43, 37, -43, 51, 18, -31, + 60, -2, -17, 69, -19, -3, 78, -35, 10, 88, -49, 24, + 35, 65, -56, 38, 55, -51, 44, 39, -41, 52, 20, -29, + 60, 1, -16, 69, -16, -2, 78, -32, 11, 88, -47, 24, + 36, 66, -54, 39, 57, -49, 45, 41, -40, 52, 23, -28, + 61, 4, -15, 70, -14, -2, 79, -30, 11, 88, -45, 25, + 37, 67, -52, 40, 58, -47, 46, 43, -38, 53, 25, -27, + 62, 6, -14, 70, -11, -1, 79, -27, 12, 89, -43, 25, + 39, 69, -50, 42, 60, -45, 47, 46, -36, 54, 28, -25, + 62, 9, -13, 71, -9, 0, 80, -25, 13, 89, -40, 26, + 40, 70, -47, 43, 62, -42, 48, 48, -34, 55, 31, -24, + 63, 12, -12, 71, -5, 1, 80, -22, 14, 89, -38, 26, + 42, 72, -45, 44, 64, -40, 49, 50, -33, 56, 34, -22, + 64, 15, -10, 72, -3, 2, 81, -19, 14, 90, -35, 27, + 43, 73, -42, 46, 66, -38, 50, 53, -31, 57, 36, -21, + 64, 18, -9, 73, 0, 3, 81, -17, 15, 90, -32, 28, + 45, 75, -40, 47, 67, -36, 52, 55, -29, 58, 39, -19, + 65, 21, -8, 73, 3, 4, 82, -14, 16, 91, -30, 28, + 46, 76, -37, 48, 69, -34, 53, 57, -27, 59, 41, -18, + 66, 23, -7, 74, 6, 5, 82, -11, 17, 91, -27, 29, + 48, 78, -35, 50, 71, -31, 54, 60, -25, 60, 44, -16, + 67, 27, -5, 75, 9, 6, 83, -8, 18, 92, -24, 30, + 49, 79, -32, 51, 73, -29, 55, 62, -23, 61, 47, -14, + 68, 30, -4, 76, 12, 7, 84, -5, 19, 92, -21, 31, + 51, 81, -30, 53, 75, -27, 57, 64, -21, 62, 49, -12, + 69, 32, -2, 76, 15, 9, 84, -2, 20, 93, -18, 32, + 52, 82, -27, 54, 77, -24, 58, 66, -19, 63, 52, -11, + 70, 35, -1, 77, 18, 10, 85, 1, 21, 93, -15, 32, + 54, 84, -25, 56, 79, -22, 59, 69, -16, 64, 55, -9, + 71, 38, 1, 78, 22, 11, 86, 5, 22, 94, -12, 33, + 55, 86, -22, 57, 80, -19, 60, 71, -14, 65, 57, -7, + 72, 41, 2, 79, 24, 13, 86, 8, 23, 95, -9, 34, + 57, 87, -20, 58, 82, -17, 62, 73, -12, 67, 60, -5, + 73, 44, 4, 80, 27, 14, 87, 11, 24, 95, -6, 35, + 23, 57, -81, 28, 41, -72, 36, 20, -59, 46, -1, -43, + 56, -20, -27, 66, -36, -12, 76, -50, 2, 86, -63, 16, + 23, 57, -81, 28, 41, -72, 37, 20, -58, 46, -1, -43, + 56, -20, -27, 66, -36, -12, 76, -50, 2, 86, -62, 17, + 23, 57, -81, 28, 41, -71, 37, 20, -58, 46, 0, -43, + 56, -19, -27, 66, -35, -12, 76, -49, 2, 86, -62, 17, + 23, 58, -80, 29, 42, -71, 37, 21, -58, 46, 0, -43, + 56, -19, -27, 66, -35, -12, 76, -49, 2, 86, -62, 17, + 24, 58, -79, 29, 42, -71, 37, 22, -57, 46, 1, -43, + 56, -18, -27, 66, -34, -12, 76, -48, 3, 86, -61, 17, + 24, 58, -78, 29, 43, -70, 37, 23, -57, 46, 2, -42, + 56, -17, -27, 66, -33, -12, 76, -48, 3, 86, -61, 17, + 25, 58, -78, 30, 44, -69, 38, 24, -56, 47, 3, -42, + 57, -16, -26, 66, -33, -12, 76, -47, 3, 86, -60, 17, + 26, 59, -76, 30, 45, -68, 38, 25, -56, 47, 4, -41, + 57, -15, -26, 67, -31, -11, 76, -46, 3, 86, -59, 17, + 26, 59, -75, 31, 46, -67, 39, 26, -55, 47, 6, -41, + 57, -14, -26, 67, -30, -11, 76, -45, 3, 86, -58, 17, + 27, 60, -74, 32, 47, -66, 39, 28, -54, 48, 7, -40, + 57, -12, -25, 67, -29, -11, 77, -44, 4, 86, -57, 18, + 28, 61, -72, 33, 48, -65, 40, 29, -53, 48, 9, -39, + 58, -10, -25, 67, -27, -10, 77, -42, 4, 87, -56, 18, + 29, 61, -70, 33, 49, -63, 40, 31, -52, 49, 11, -39, + 58, -9, -24, 68, -26, -10, 77, -41, 4, 87, -55, 18, + 30, 62, -68, 34, 51, -62, 41, 33, -51, 49, 13, -38, + 59, -6, -23, 68, -23, -9, 77, -39, 5, 87, -53, 19, + 31, 63, -66, 35, 52, -60, 42, 35, -50, 50, 15, -37, + 59, -4, -23, 68, -21, -9, 78, -37, 5, 87, -51, 19, + 33, 64, -64, 36, 53, -58, 43, 37, -48, 50, 17, -36, + 59, -2, -22, 69, -19, -8, 78, -35, 6, 88, -50, 19, + 34, 65, -62, 37, 55, -57, 43, 39, -47, 51, 20, -35, + 60, 0, -21, 69, -17, -7, 78, -33, 6, 88, -48, 20, + 35, 67, -60, 39, 57, -55, 44, 41, -45, 52, 22, -33, + 61, 3, -20, 70, -14, -7, 79, -31, 7, 88, -45, 20, + 37, 68, -58, 40, 58, -53, 45, 43, -44, 53, 25, -32, + 61, 6, -19, 70, -12, -6, 79, -28, 7, 88, -43, 21, + 38, 69, -56, 41, 60, -51, 46, 45, -42, 53, 27, -31, + 62, 8, -18, 71, -10, -5, 79, -26, 8, 89, -41, 21, + 39, 70, -53, 42, 62, -49, 47, 47, -40, 54, 30, -30, + 62, 11, -17, 71, -7, -4, 80, -23, 9, 89, -39, 22, + 41, 72, -51, 44, 63, -46, 49, 50, -38, 55, 33, -28, + 63, 14, -16, 72, -4, -3, 80, -20, 10, 90, -36, 22, + 42, 73, -48, 45, 65, -44, 50, 52, -37, 56, 35, -26, + 64, 17, -14, 72, -1, -2, 81, -18, 10, 90, -34, 23, + 44, 74, -46, 46, 67, -42, 51, 54, -35, 57, 38, -25, + 65, 19, -13, 73, 2, -1, 81, -15, 11, 90, -31, 24, + 45, 76, -44, 47, 69, -40, 52, 56, -33, 58, 40, -23, + 66, 22, -12, 74, 4, 0, 82, -12, 12, 91, -29, 24, + 46, 77, -41, 49, 70, -38, 53, 58, -31, 59, 43, -22, + 66, 25, -11, 74, 7, 1, 83, -10, 13, 91, -26, 25, + 48, 79, -39, 50, 72, -35, 54, 61, -29, 60, 46, -20, + 67, 28, -9, 75, 11, 2, 83, -6, 14, 92, -23, 26, + 49, 80, -36, 52, 74, -33, 56, 63, -27, 61, 48, -18, + 68, 31, -8, 76, 13, 3, 84, -3, 15, 92, -20, 27, + 51, 82, -34, 53, 76, -31, 57, 65, -25, 62, 51, -17, + 69, 34, -6, 77, 16, 5, 84, -1, 16, 93, -17, 28, + 52, 83, -32, 54, 78, -28, 58, 67, -23, 63, 53, -15, + 70, 36, -5, 77, 19, 6, 85, 2, 17, 94, -14, 29, + 54, 85, -29, 56, 80, -26, 59, 70, -21, 65, 56, -13, + 71, 39, -3, 78, 23, 7, 86, 6, 18, 94, -11, 30, + 56, 87, -26, 57, 81, -24, 61, 72, -18, 66, 58, -11, + 72, 42, -2, 79, 26, 8, 87, 9, 19, 95, -8, 30, + 57, 88, -24, 59, 83, -21, 62, 74, -16, 67, 61, -9, + 73, 45, 0, 80, 28, 10, 87, 12, 20, 95, -5, 31, + 24, 59, -84, 29, 44, -75, 37, 23, -62, 46, 2, -47, + 56, -17, -31, 66, -33, -16, 76, -48, -2, 86, -61, 13, + 24, 59, -84, 29, 44, -75, 37, 23, -62, 46, 3, -47, + 56, -17, -31, 66, -33, -16, 76, -47, -2, 86, -60, 13, + 24, 60, -83, 29, 44, -75, 37, 24, -62, 46, 3, -47, + 56, -16, -31, 66, -33, -16, 76, -47, -2, 86, -60, 13, + 24, 60, -83, 30, 45, -74, 37, 24, -62, 47, 3, -47, + 57, -16, -31, 66, -32, -16, 76, -47, -2, 86, -60, 13, + 25, 60, -82, 30, 45, -74, 38, 25, -61, 47, 4, -47, + 57, -15, -31, 66, -32, -16, 76, -46, -1, 86, -59, 13, + 25, 60, -81, 30, 46, -73, 38, 26, -61, 47, 5, -46, + 57, -14, -31, 67, -31, -16, 76, -46, -1, 86, -59, 13, + 26, 61, -81, 31, 46, -73, 38, 26, -60, 47, 6, -46, + 57, -14, -30, 67, -30, -16, 76, -45, -1, 86, -58, 13, + 27, 61, -79, 31, 47, -72, 39, 28, -59, 47, 7, -45, + 57, -12, -30, 67, -29, -15, 76, -44, -1, 86, -57, 13, + 27, 61, -78, 32, 48, -71, 39, 29, -59, 48, 9, -45, + 57, -11, -30, 67, -28, -15, 77, -43, -1, 86, -56, 13, + 28, 62, -77, 33, 49, -69, 40, 30, -58, 48, 10, -44, + 58, -10, -29, 67, -26, -15, 77, -41, 0, 87, -55, 14, + 29, 63, -75, 33, 50, -68, 40, 32, -57, 49, 12, -43, + 58, -8, -29, 68, -25, -14, 77, -40, 0, 87, -54, 14, + 30, 63, -74, 34, 51, -67, 41, 33, -56, 49, 13, -43, + 58, -6, -28, 68, -23, -14, 77, -39, 0, 87, -53, 14, + 31, 64, -72, 35, 53, -65, 42, 35, -55, 50, 16, -42, + 59, -4, -27, 68, -21, -13, 78, -37, 1, 87, -51, 15, + 32, 65, -70, 36, 54, -64, 42, 37, -53, 50, 18, -41, + 59, -2, -27, 68, -19, -13, 78, -35, 1, 87, -50, 15, + 33, 66, -68, 37, 55, -62, 43, 39, -52, 51, 20, -40, + 60, 0, -26, 69, -17, -12, 78, -33, 2, 88, -48, 15, + 35, 67, -66, 38, 57, -60, 44, 41, -51, 51, 22, -39, + 60, 2, -25, 69, -15, -11, 78, -31, 2, 88, -46, 16, + 36, 68, -64, 39, 58, -58, 45, 43, -49, 52, 24, -37, + 61, 5, -24, 70, -13, -11, 79, -29, 3, 88, -44, 16, + 37, 69, -62, 40, 60, -56, 46, 45, -48, 53, 27, -36, + 61, 7, -23, 70, -10, -10, 79, -27, 3, 89, -42, 17, + 38, 70, -59, 41, 62, -54, 47, 47, -46, 54, 29, -35, + 62, 10, -22, 71, -8, -9, 80, -24, 4, 89, -40, 17, + 40, 72, -57, 43, 63, -53, 48, 49, -44, 55, 31, -34, + 63, 13, -21, 71, -5, -8, 80, -22, 5, 89, -37, 18, + 41, 73, -55, 44, 65, -50, 49, 51, -42, 56, 34, -32, + 64, 16, -20, 72, -2, -7, 81, -19, 6, 90, -35, 19, + 43, 74, -52, 45, 67, -48, 50, 53, -41, 56, 37, -31, + 64, 18, -19, 72, 0, -6, 81, -16, 6, 90, -32, 19, + 44, 76, -50, 47, 68, -46, 51, 55, -39, 57, 39, -29, + 65, 21, -17, 73, 3, -5, 82, -14, 7, 91, -30, 20, + 45, 77, -48, 48, 70, -44, 52, 58, -37, 58, 42, -28, + 66, 24, -16, 74, 6, -4, 82, -11, 8, 91, -27, 21, + 47, 78, -45, 49, 72, -42, 53, 60, -35, 59, 44, -26, + 67, 26, -15, 74, 9, -3, 83, -8, 9, 92, -25, 21, + 48, 80, -43, 51, 73, -39, 55, 62, -33, 60, 47, -24, + 68, 29, -13, 75, 12, -2, 83, -5, 10, 92, -22, 22, + 50, 81, -40, 52, 75, -37, 56, 64, -31, 61, 49, -22, + 68, 32, -12, 76, 15, -1, 84, -2, 11, 93, -19, 23, + 51, 83, -38, 53, 77, -35, 57, 66, -29, 63, 52, -21, + 69, 35, -10, 77, 18, 0, 85, 1, 12, 93, -16, 24, + 53, 84, -36, 55, 79, -33, 58, 68, -27, 64, 54, -19, + 70, 38, -9, 77, 21, 2, 85, 4, 13, 94, -13, 25, + 54, 86, -33, 56, 81, -30, 60, 71, -25, 65, 57, -17, + 71, 41, -7, 78, 24, 3, 86, 7, 14, 94, -10, 26, + 56, 87, -31, 58, 82, -28, 61, 73, -23, 66, 59, -15, + 72, 43, -6, 79, 27, 4, 87, 10, 15, 95, -7, 27, + 57, 89, -28, 59, 84, -26, 62, 75, -21, 67, 62, -13, + 73, 46, -4, 80, 30, 6, 87, 13, 16, 96, -4, 28, + 25, 62, -87, 30, 47, -78, 38, 26, -66, 47, 5, -51, + 57, -14, -35, 66, -31, -20, 76, -45, -6, 86, -59, 9, + 25, 62, -87, 30, 47, -78, 38, 27, -66, 47, 6, -51, + 57, -14, -35, 66, -30, -20, 76, -45, -6, 86, -59, 9, + 25, 62, -86, 30, 47, -78, 38, 27, -65, 47, 6, -51, + 57, -14, -35, 67, -30, -20, 76, -45, -6, 86, -58, 9, + 26, 62, -86, 30, 47, -78, 38, 27, -65, 47, 7, -51, + 57, -13, -35, 67, -30, -20, 76, -44, -6, 86, -58, 9, + 26, 62, -85, 31, 48, -77, 38, 28, -65, 47, 7, -50, + 57, -12, -35, 67, -29, -20, 76, -44, -5, 86, -58, 9, + 26, 62, -84, 31, 48, -77, 39, 29, -64, 47, 8, -50, + 57, -12, -35, 67, -28, -20, 76, -43, -5, 86, -57, 9, + 27, 63, -84, 32, 49, -76, 39, 29, -64, 48, 9, -50, + 57, -11, -34, 67, -28, -20, 77, -43, -5, 86, -56, 9, + 28, 63, -82, 32, 50, -75, 39, 31, -63, 48, 10, -49, + 58, -10, -34, 67, -27, -19, 77, -42, -5, 87, -55, 9, + 28, 64, -81, 33, 51, -74, 40, 32, -62, 48, 11, -49, + 58, -8, -34, 67, -25, -19, 77, -41, -5, 87, -55, 10, + 29, 64, -80, 33, 51, -73, 40, 33, -62, 49, 13, -48, + 58, -7, -33, 68, -24, -19, 77, -39, -4, 87, -54, 10, + 30, 65, -78, 34, 52, -72, 41, 34, -61, 49, 14, -47, + 58, -5, -33, 68, -23, -18, 77, -38, -4, 87, -52, 10, + 31, 65, -77, 35, 54, -70, 41, 36, -60, 50, 16, -47, + 59, -4, -32, 68, -21, -18, 77, -37, -4, 87, -51, 10, + 32, 66, -75, 36, 55, -69, 42, 38, -58, 50, 18, -46, + 59, -2, -31, 68, -19, -17, 78, -35, -3, 87, -49, 11, + 33, 67, -73, 37, 56, -67, 43, 39, -57, 51, 20, -45, + 60, 0, -31, 69, -17, -17, 78, -33, -3, 88, -48, 11, + 34, 68, -71, 38, 57, -66, 44, 41, -56, 51, 22, -44, + 60, 2, -30, 69, -15, -16, 78, -31, -2, 88, -46, 11, + 35, 69, -70, 39, 59, -64, 44, 43, -55, 52, 24, -43, + 61, 5, -29, 70, -13, -15, 79, -29, -2, 88, -44, 12, + 37, 70, -67, 40, 60, -62, 45, 45, -53, 53, 26, -41, + 61, 7, -28, 70, -11, -15, 79, -27, -1, 88, -42, 12, + 38, 71, -65, 41, 62, -60, 46, 47, -51, 53, 29, -40, + 62, 9, -27, 70, -8, -14, 79, -25, -1, 89, -40, 13, + 39, 72, -63, 42, 63, -58, 47, 49, -50, 54, 31, -39, + 62, 12, -26, 71, -6, -13, 80, -22, 0, 89, -38, 13, + 40, 73, -61, 43, 65, -56, 48, 51, -48, 55, 33, -38, + 63, 14, -25, 72, -3, -12, 80, -20, 1, 89, -36, 14, + 42, 74, -58, 45, 66, -54, 49, 53, -46, 56, 36, -36, + 64, 17, -24, 72, -1, -11, 81, -17, 2, 90, -33, 15, + 43, 76, -56, 46, 68, -52, 50, 55, -45, 57, 38, -35, + 65, 20, -23, 73, 2, -10, 81, -15, 2, 90, -31, 15, + 45, 77, -54, 47, 70, -50, 52, 57, -43, 58, 41, -33, + 65, 22, -21, 73, 5, -9, 82, -12, 3, 91, -28, 16, + 46, 78, -52, 48, 71, -48, 53, 59, -41, 59, 43, -32, + 66, 25, -20, 74, 7, -8, 82, -10, 4, 91, -26, 17, + 47, 79, -49, 50, 73, -46, 54, 61, -39, 60, 46, -30, + 67, 28, -19, 75, 10, -7, 83, -7, 5, 92, -23, 17, + 49, 81, -47, 51, 75, -43, 55, 63, -37, 61, 48, -28, + 68, 31, -17, 75, 13, -6, 84, -4, 6, 92, -20, 18, + 50, 82, -44, 52, 76, -41, 56, 65, -35, 62, 51, -26, + 69, 33, -16, 76, 16, -5, 84, -1, 7, 93, -18, 19, + 52, 84, -42, 54, 78, -39, 58, 67, -33, 63, 53, -25, + 70, 36, -15, 77, 19, -4, 85, 2, 8, 93, -15, 20, + 53, 85, -40, 55, 80, -37, 59, 69, -31, 64, 56, -23, + 70, 39, -13, 78, 22, -2, 85, 5, 9, 94, -12, 21, + 55, 87, -37, 57, 82, -34, 60, 72, -29, 65, 58, -21, + 72, 42, -11, 79, 25, -1, 86, 8, 10, 95, -9, 22, + 56, 88, -35, 58, 83, -32, 61, 74, -27, 66, 61, -19, + 72, 44, -10, 79, 28, 0, 87, 11, 11, 95, -6, 23, + 58, 90, -32, 59, 85, -30, 63, 76, -25, 67, 63, -17, + 73, 47, -8, 80, 31, 2, 88, 14, 12, 96, -3, 24, + 26, 64, -90, 31, 50, -82, 38, 30, -70, 47, 9, -55, + 57, -11, -40, 67, -28, -25, 76, -43, -10, 86, -56, 4, + 26, 64, -90, 31, 50, -82, 39, 30, -70, 47, 9, -55, + 57, -11, -40, 67, -27, -25, 76, -43, -10, 86, -56, 4, + 27, 64, -89, 31, 50, -82, 39, 30, -69, 47, 10, -55, + 57, -10, -40, 67, -27, -25, 76, -42, -10, 86, -56, 4, + 27, 64, -89, 31, 51, -81, 39, 31, -69, 48, 10, -55, + 57, -10, -40, 67, -27, -25, 77, -42, -10, 86, -56, 4, + 27, 64, -88, 32, 51, -81, 39, 31, -69, 48, 11, -55, + 57, -9, -39, 67, -26, -24, 77, -41, -10, 86, -55, 5, + 28, 65, -88, 32, 51, -80, 39, 32, -68, 48, 11, -54, + 58, -8, -39, 67, -26, -24, 77, -41, -10, 87, -55, 5, + 28, 65, -87, 32, 52, -80, 40, 33, -68, 48, 12, -54, + 58, -8, -39, 67, -25, -24, 77, -40, -10, 87, -54, 5, + 29, 65, -86, 33, 53, -79, 40, 34, -67, 48, 13, -53, + 58, -6, -38, 67, -24, -24, 77, -39, -9, 87, -53, 5, + 29, 66, -85, 34, 53, -78, 40, 35, -66, 49, 15, -53, + 58, -5, -38, 68, -23, -23, 77, -38, -9, 87, -52, 5, + 30, 66, -83, 34, 54, -77, 41, 36, -66, 49, 16, -52, + 58, -4, -38, 68, -21, -23, 77, -37, -9, 87, -51, 5, + 31, 67, -82, 35, 55, -75, 41, 37, -65, 50, 17, -52, + 59, -2, -37, 68, -20, -23, 77, -36, -9, 87, -50, 6, + 32, 67, -81, 36, 56, -74, 42, 39, -64, 50, 19, -51, + 59, -1, -36, 68, -18, -22, 78, -34, -8, 87, -49, 6, + 33, 68, -79, 37, 57, -73, 43, 40, -63, 51, 21, -50, + 60, 1, -36, 69, -17, -22, 78, -33, -8, 88, -47, 6, + 34, 69, -77, 37, 58, -71, 43, 42, -61, 51, 23, -49, + 60, 3, -35, 69, -15, -21, 78, -31, -7, 88, -46, 7, + 35, 70, -75, 38, 60, -70, 44, 43, -60, 52, 25, -48, + 60, 5, -34, 69, -13, -21, 79, -29, -7, 88, -44, 7, + 36, 70, -73, 39, 61, -68, 45, 45, -59, 52, 27, -47, + 61, 7, -33, 70, -11, -20, 79, -27, -6, 88, -42, 7, + 37, 72, -71, 41, 62, -66, 46, 47, -57, 53, 29, -46, + 62, 10, -32, 70, -8, -19, 79, -25, -6, 89, -40, 8, + 39, 72, -69, 42, 64, -64, 47, 49, -56, 54, 31, -45, + 62, 12, -32, 71, -6, -18, 80, -23, -5, 89, -38, 9, + 40, 74, -67, 43, 65, -62, 48, 51, -54, 55, 33, -43, + 63, 14, -31, 71, -4, -18, 80, -20, -4, 89, -36, 9, + 41, 75, -65, 44, 66, -61, 49, 53, -53, 55, 35, -42, + 63, 17, -30, 72, -1, -17, 81, -18, -4, 90, -34, 10, + 43, 76, -63, 45, 68, -58, 50, 55, -51, 56, 38, -40, + 64, 19, -28, 72, 1, -16, 81, -15, -3, 90, -32, 10, + 44, 77, -60, 46, 70, -56, 51, 57, -49, 57, 40, -39, + 65, 22, -27, 73, 4, -15, 82, -13, -2, 91, -29, 11, + 45, 78, -58, 48, 71, -54, 52, 59, -47, 58, 43, -38, + 66, 24, -26, 74, 7, -14, 82, -10, -1, 91, -27, 12, + 47, 80, -56, 49, 73, -52, 53, 61, -45, 59, 45, -36, + 66, 27, -25, 74, 9, -13, 83, -8, 0, 91, -24, 12, + 48, 81, -54, 50, 74, -50, 54, 63, -44, 60, 47, -34, + 67, 30, -23, 75, 12, -12, 83, -5, 0, 92, -22, 13, + 49, 82, -51, 52, 76, -48, 56, 65, -41, 61, 50, -33, + 68, 32, -22, 76, 15, -10, 84, -2, 1, 92, -19, 14, + 51, 84, -49, 53, 78, -45, 57, 67, -39, 62, 52, -31, + 69, 35, -20, 76, 18, -9, 84, 1, 2, 93, -16, 15, + 52, 85, -46, 54, 79, -43, 58, 69, -37, 63, 55, -29, + 70, 38, -19, 77, 20, -8, 85, 3, 3, 93, -13, 16, + 54, 86, -44, 56, 81, -41, 59, 71, -36, 64, 57, -28, + 71, 40, -18, 78, 23, -7, 86, 6, 4, 94, -11, 16, + 55, 88, -41, 57, 83, -39, 61, 73, -33, 65, 60, -26, + 72, 43, -16, 79, 26, -5, 86, 9, 6, 95, -7, 17, + 57, 89, -39, 58, 84, -36, 62, 75, -31, 67, 62, -24, + 73, 46, -14, 80, 29, -4, 87, 12, 7, 95, -5, 18, + 58, 91, -37, 60, 86, -34, 63, 77, -29, 68, 64, -22, + 74, 48, -13, 80, 32, -3, 88, 15, 8, 96, -2, 19, + 27, 66, -93, 32, 53, -85, 39, 33, -73, 48, 12, -59, + 57, -8, -44, 67, -25, -29, 77, -40, -14, 86, -54, 0, + 28, 66, -93, 32, 53, -85, 39, 33, -73, 48, 12, -59, + 58, -8, -44, 67, -25, -29, 77, -40, -14, 87, -54, 0, + 28, 66, -92, 32, 53, -85, 39, 33, -73, 48, 13, -59, + 58, -7, -44, 67, -25, -29, 77, -40, -14, 87, -54, 0, + 28, 66, -92, 32, 53, -84, 39, 34, -73, 48, 13, -59, + 58, -7, -43, 67, -24, -29, 77, -40, -14, 87, -54, 1, + 28, 67, -91, 33, 54, -84, 40, 34, -72, 48, 14, -58, + 58, -6, -43, 67, -24, -28, 77, -39, -14, 87, -53, 1, + 29, 67, -91, 33, 54, -83, 40, 35, -72, 48, 14, -58, + 58, -6, -43, 67, -23, -28, 77, -38, -14, 87, -53, 1, + 29, 67, -90, 33, 54, -83, 40, 36, -71, 49, 15, -58, + 58, -5, -43, 68, -22, -28, 77, -38, -14, 87, -52, 1, + 30, 67, -89, 34, 55, -82, 41, 37, -71, 49, 16, -57, + 58, -4, -42, 68, -21, -28, 77, -37, -13, 87, -51, 1, + 30, 68, -88, 34, 56, -81, 41, 38, -70, 49, 17, -57, + 59, -3, -42, 68, -20, -27, 77, -36, -13, 87, -50, 1, + 31, 68, -86, 35, 57, -80, 42, 39, -69, 50, 19, -56, + 59, -1, -41, 68, -19, -27, 78, -35, -13, 87, -49, 2, + 32, 69, -85, 36, 57, -79, 42, 40, -68, 50, 20, -55, + 59, 0, -41, 68, -18, -27, 78, -34, -12, 87, -48, 2, + 33, 69, -84, 36, 58, -78, 43, 41, -67, 50, 22, -55, + 60, 2, -40, 69, -16, -26, 78, -32, -12, 88, -47, 2, + 34, 70, -82, 37, 59, -76, 43, 43, -66, 51, 23, -54, + 60, 4, -40, 69, -14, -26, 78, -30, -12, 88, -46, 2, + 35, 71, -80, 38, 60, -75, 44, 44, -65, 52, 25, -53, + 60, 5, -39, 69, -12, -25, 79, -29, -11, 88, -44, 3, + 36, 71, -79, 39, 62, -73, 45, 46, -64, 52, 27, -52, + 61, 7, -38, 70, -11, -24, 79, -27, -11, 88, -42, 3, + 37, 72, -77, 40, 63, -72, 46, 47, -62, 53, 29, -51, + 61, 9, -37, 70, -9, -24, 79, -25, -10, 89, -41, 4, + 38, 73, -75, 41, 64, -70, 47, 49, -61, 54, 31, -50, + 62, 12, -36, 71, -6, -23, 80, -23, -10, 89, -39, 4, + 39, 74, -73, 42, 65, -68, 47, 51, -59, 54, 33, -48, + 62, 14, -35, 71, -4, -22, 80, -21, -9, 89, -37, 5, + 40, 75, -71, 43, 67, -66, 48, 53, -58, 55, 35, -47, + 63, 16, -34, 72, -2, -21, 80, -19, -8, 90, -35, 5, + 42, 76, -69, 44, 68, -64, 49, 54, -56, 56, 37, -46, + 64, 18, -33, 72, 1, -21, 81, -16, -8, 90, -32, 6, + 43, 77, -66, 46, 70, -62, 50, 57, -54, 57, 40, -44, + 64, 21, -32, 73, 3, -20, 81, -14, -7, 90, -30, 6, + 44, 78, -64, 47, 71, -60, 51, 58, -53, 58, 42, -43, + 65, 24, -31, 73, 6, -19, 82, -11, -6, 91, -28, 7, + 46, 80, -62, 48, 73, -58, 52, 60, -51, 58, 44, -41, + 66, 26, -30, 74, 8, -18, 82, -9, -5, 91, -25, 8, + 47, 81, -60, 49, 74, -56, 54, 62, -49, 59, 47, -40, + 67, 29, -29, 75, 11, -17, 83, -6, -4, 92, -23, 8, + 48, 82, -57, 51, 76, -54, 55, 64, -47, 60, 49, -38, + 67, 31, -27, 75, 14, -16, 83, -4, -3, 92, -20, 9, + 50, 84, -55, 52, 77, -52, 56, 66, -45, 61, 51, -37, + 68, 34, -26, 76, 16, -14, 84, -1, -2, 93, -17, 10, + 51, 85, -53, 53, 79, -49, 57, 68, -43, 62, 54, -35, + 69, 37, -24, 77, 19, -13, 85, 2, -1, 93, -15, 11, + 53, 86, -50, 55, 80, -47, 58, 70, -41, 64, 56, -33, + 70, 39, -23, 77, 22, -12, 85, 5, -1, 94, -12, 12, + 54, 88, -48, 56, 82, -45, 59, 72, -39, 65, 58, -32, + 71, 42, -22, 78, 25, -11, 86, 8, 1, 94, -9, 13, + 56, 89, -45, 57, 84, -43, 61, 74, -37, 66, 61, -30, + 72, 45, -20, 79, 28, -9, 87, 11, 2, 95, -6, 14, + 57, 90, -43, 59, 85, -40, 62, 76, -35, 67, 63, -28, + 73, 47, -18, 80, 30, -8, 87, 14, 3, 95, -3, 14, + 58, 92, -41, 60, 87, -38, 63, 78, -33, 68, 65, -26, + 74, 50, -17, 81, 33, -7, 88, 16, 4, 96, -1, 15, + 28, 68, -95, 33, 55, -88, 40, 36, -77, 48, 15, -63, + 58, -5, -48, 67, -22, -33, 77, -38, -18, 87, -52, -4, + 29, 68, -95, 33, 55, -88, 40, 36, -77, 48, 16, -63, + 58, -5, -47, 67, -22, -33, 77, -38, -18, 87, -52, -3, + 29, 68, -95, 33, 56, -88, 40, 37, -76, 49, 16, -63, + 58, -4, -47, 67, -22, -33, 77, -37, -18, 87, -52, -3, + 29, 68, -95, 33, 56, -87, 40, 37, -76, 49, 16, -62, + 58, -4, -47, 68, -21, -32, 77, -37, -18, 87, -52, -3, + 29, 69, -94, 34, 56, -87, 40, 37, -76, 49, 17, -62, + 58, -3, -47, 68, -21, -32, 77, -37, -18, 87, -51, -3, + 30, 69, -93, 34, 56, -87, 41, 38, -75, 49, 17, -62, + 58, -3, -47, 68, -20, -32, 77, -36, -18, 87, -51, -3, + 30, 69, -93, 34, 57, -86, 41, 39, -75, 49, 18, -61, + 58, -2, -47, 68, -20, -32, 77, -35, -17, 87, -50, -3, + 31, 69, -92, 35, 58, -85, 41, 39, -74, 49, 19, -61, + 59, -1, -46, 68, -19, -32, 77, -34, -17, 87, -49, -3, + 31, 70, -91, 35, 58, -84, 42, 40, -74, 50, 20, -60, + 59, 0, -46, 68, -18, -31, 78, -34, -17, 87, -48, -3, + 32, 70, -89, 36, 59, -83, 42, 41, -73, 50, 21, -60, + 59, 1, -45, 68, -16, -31, 78, -32, -17, 87, -47, -2, + 33, 71, -88, 36, 60, -82, 43, 42, -72, 51, 23, -59, + 60, 3, -45, 69, -15, -31, 78, -31, -16, 88, -46, -2, + 34, 71, -87, 37, 60, -81, 43, 44, -71, 51, 24, -58, + 60, 4, -44, 69, -14, -30, 78, -30, -16, 88, -45, -2, + 35, 72, -85, 38, 62, -79, 44, 45, -70, 52, 26, -58, + 60, 6, -44, 69, -12, -30, 78, -28, -16, 88, -44, -1, + 36, 72, -84, 39, 62, -78, 45, 47, -69, 52, 28, -57, + 61, 8, -43, 70, -10, -29, 79, -27, -15, 88, -42, -1, + 37, 73, -82, 40, 64, -77, 45, 48, -67, 53, 29, -56, + 61, 10, -42, 70, -8, -28, 79, -25, -15, 88, -41, -1, + 38, 74, -80, 41, 65, -75, 46, 49, -66, 53, 31, -55, + 62, 12, -41, 70, -6, -28, 79, -23, -14, 89, -39, 0, + 39, 75, -78, 42, 66, -73, 47, 51, -65, 54, 33, -53, + 62, 14, -40, 71, -4, -27, 80, -21, -13, 89, -37, 0, + 40, 76, -76, 43, 67, -71, 48, 53, -63, 55, 35, -52, + 63, 16, -39, 71, -2, -26, 80, -19, -13, 89, -35, 1, + 41, 77, -74, 44, 68, -70, 49, 55, -62, 55, 37, -51, + 63, 18, -38, 72, 0, -25, 81, -17, -12, 90, -33, 1, + 42, 78, -72, 45, 70, -68, 50, 56, -60, 56, 39, -50, + 64, 20, -37, 72, 2, -25, 81, -15, -12, 90, -31, 2, + 44, 79, -70, 46, 71, -66, 51, 58, -58, 57, 42, -48, + 65, 23, -36, 73, 5, -24, 81, -12, -11, 90, -28, 3, + 45, 80, -68, 47, 73, -64, 52, 60, -57, 58, 44, -47, + 66, 25, -35, 74, 8, -23, 82, -10, -10, 91, -26, 3, + 46, 81, -66, 49, 74, -62, 53, 62, -55, 59, 46, -45, + 66, 28, -34, 74, 10, -22, 82, -7, -9, 91, -24, 4, + 48, 82, -63, 50, 75, -60, 54, 64, -53, 60, 48, -44, + 67, 30, -33, 75, 13, -21, 83, -5, -8, 92, -21, 5, + 49, 83, -61, 51, 77, -58, 55, 66, -51, 61, 50, -42, + 68, 33, -31, 75, 15, -20, 84, -2, -7, 92, -19, 5, + 50, 85, -59, 53, 79, -55, 56, 68, -49, 62, 53, -41, + 69, 36, -30, 76, 18, -18, 84, 1, -6, 93, -16, 6, + 52, 86, -56, 54, 80, -53, 58, 69, -47, 63, 55, -39, + 70, 38, -28, 77, 21, -17, 85, 4, -5, 93, -13, 7, + 53, 87, -54, 55, 82, -51, 59, 71, -45, 64, 57, -37, + 70, 41, -27, 78, 23, -16, 85, 6, -4, 94, -11, 8, + 55, 89, -52, 56, 83, -49, 60, 73, -43, 65, 60, -36, + 71, 43, -26, 78, 26, -15, 86, 9, -3, 94, -8, 9, + 56, 90, -49, 58, 85, -46, 61, 75, -41, 66, 62, -34, + 72, 46, -24, 79, 29, -13, 87, 12, -2, 95, -5, 10, + 57, 91, -47, 59, 86, -44, 62, 77, -39, 67, 64, -32, + 73, 48, -22, 80, 32, -12, 88, 15, -1, 96, -2, 11, + 59, 93, -45, 61, 88, -42, 64, 79, -37, 68, 66, -30, + 74, 51, -21, 81, 34, -11, 88, 18, 0, 96, 1, 12, + 30, 70, -98, 34, 58, -91, 41, 39, -80, 49, 19, -66, + 58, -2, -51, 68, -20, -37, 77, -35, -22, 87, -50, -7, + 30, 70, -98, 34, 58, -91, 41, 39, -80, 49, 19, -66, + 58, -2, -51, 68, -19, -37, 77, -35, -22, 87, -50, -7, + 30, 70, -98, 34, 58, -91, 41, 40, -80, 49, 19, -66, + 58, -1, -51, 68, -19, -36, 77, -35, -22, 87, -50, -7, + 30, 71, -97, 34, 58, -91, 41, 40, -79, 49, 19, -66, + 58, -1, -51, 68, -19, -36, 77, -35, -22, 87, -49, -7, + 30, 71, -97, 34, 59, -90, 41, 40, -79, 49, 20, -66, + 59, 0, -51, 68, -18, -36, 77, -34, -22, 87, -49, -7, + 31, 71, -96, 35, 59, -90, 41, 41, -79, 49, 20, -65, + 59, 0, -51, 68, -18, -36, 77, -34, -22, 87, -48, -7, + 31, 71, -96, 35, 59, -89, 42, 41, -78, 50, 21, -65, + 59, 1, -50, 68, -17, -36, 78, -33, -21, 87, -48, -7, + 32, 71, -95, 36, 60, -88, 42, 42, -78, 50, 22, -65, + 59, 2, -50, 68, -16, -35, 78, -32, -21, 87, -47, -7, + 32, 72, -94, 36, 61, -87, 42, 43, -77, 50, 23, -64, + 59, 3, -50, 69, -15, -35, 78, -31, -21, 87, -46, -6, + 33, 72, -92, 37, 61, -86, 43, 44, -76, 51, 24, -63, + 60, 4, -49, 69, -14, -35, 78, -30, -21, 88, -45, -6, + 34, 73, -91, 37, 62, -85, 43, 45, -75, 51, 26, -63, + 60, 5, -49, 69, -13, -34, 78, -29, -20, 88, -44, -6, + 35, 73, -90, 38, 63, -84, 44, 46, -74, 51, 27, -62, + 60, 7, -48, 69, -11, -34, 78, -28, -20, 88, -43, -6, + 35, 74, -88, 39, 64, -83, 45, 48, -73, 52, 29, -61, + 61, 9, -47, 70, -9, -33, 79, -26, -19, 88, -42, -5, + 36, 74, -87, 40, 65, -81, 45, 49, -72, 53, 30, -60, + 61, 10, -47, 70, -8, -33, 79, -24, -19, 88, -40, -5, + 37, 75, -85, 40, 66, -80, 46, 50, -71, 53, 32, -59, + 62, 12, -46, 70, -6, -32, 79, -23, -19, 89, -39, -5, + 38, 76, -83, 41, 67, -78, 47, 52, -70, 54, 33, -58, + 62, 14, -45, 71, -4, -32, 80, -21, -18, 89, -37, -4, + 40, 76, -81, 42, 68, -77, 48, 53, -68, 54, 36, -57, + 63, 16, -44, 71, -2, -31, 80, -19, -17, 89, -35, -4, + 41, 77, -80, 43, 69, -75, 48, 55, -67, 55, 37, -56, + 63, 18, -43, 72, 0, -30, 80, -17, -17, 90, -33, -3, + 42, 78, -78, 45, 70, -73, 49, 57, -65, 56, 39, -55, + 64, 20, -42, 72, 2, -29, 81, -15, -16, 90, -31, -3, + 43, 79, -76, 46, 71, -71, 50, 58, -64, 57, 41, -54, + 64, 23, -41, 73, 4, -29, 81, -13, -15, 90, -29, -2, + 44, 80, -73, 47, 73, -69, 51, 60, -62, 58, 44, -52, + 65, 25, -40, 73, 7, -28, 82, -10, -15, 91, -27, -1, + 46, 81, -71, 48, 74, -67, 52, 62, -60, 58, 46, -51, + 66, 27, -39, 74, 9, -27, 82, -8, -14, 91, -24, -1, + 47, 82, -69, 49, 76, -65, 53, 64, -59, 59, 48, -49, + 67, 30, -38, 74, 12, -26, 83, -5, -13, 92, -22, 0, + 48, 83, -67, 50, 77, -63, 54, 65, -57, 60, 50, -48, + 67, 32, -36, 75, 14, -25, 83, -3, -12, 92, -20, 1, + 49, 85, -65, 52, 78, -61, 56, 67, -55, 61, 52, -46, + 68, 34, -35, 76, 17, -24, 84, 0, -11, 92, -17, 1, + 51, 86, -62, 53, 80, -59, 57, 69, -53, 62, 54, -44, + 69, 37, -34, 76, 20, -22, 84, 2, -10, 93, -14, 2, + 52, 87, -60, 54, 81, -57, 58, 71, -51, 63, 57, -43, + 70, 40, -32, 77, 22, -21, 85, 5, -9, 93, -12, 3, + 54, 88, -58, 56, 83, -55, 59, 73, -49, 64, 59, -41, + 71, 42, -31, 78, 25, -20, 86, 8, -8, 94, -9, 4, + 55, 90, -56, 57, 84, -53, 60, 75, -47, 65, 61, -39, + 72, 44, -30, 79, 27, -19, 86, 10, -7, 95, -7, 5, + 57, 91, -53, 58, 86, -50, 62, 77, -45, 66, 63, -37, + 73, 47, -28, 80, 30, -17, 87, 13, -6, 95, -4, 6, + 58, 93, -51, 60, 88, -48, 63, 78, -43, 67, 66, -36, + 74, 50, -26, 80, 33, -16, 88, 16, -5, 96, -1, 7, + 59, 94, -49, 61, 89, -46, 64, 80, -41, 69, 68, -34, + 75, 52, -25, 81, 36, -15, 88, 19, -4, 96, 2, 8, + 31, 73, -101, 35, 61, -95, 41, 42, -84, 50, 22, -70, + 59, 2, -56, 68, -16, -41, 77, -33, -26, 87, -48, -12, + 31, 73, -101, 35, 61, -94, 41, 43, -84, 50, 22, -70, + 59, 2, -55, 68, -16, -41, 78, -32, -26, 87, -47, -12, + 31, 73, -101, 35, 61, -94, 42, 43, -83, 50, 22, -70, + 59, 2, -55, 68, -16, -41, 78, -32, -26, 87, -47, -12, + 31, 73, -100, 35, 61, -94, 42, 43, -83, 50, 23, -70, + 59, 3, -55, 68, -16, -41, 78, -32, -26, 87, -47, -12, + 32, 73, -100, 36, 61, -93, 42, 44, -83, 50, 23, -70, + 59, 3, -55, 68, -15, -40, 78, -31, -26, 87, -46, -11, + 32, 73, -99, 36, 62, -93, 42, 44, -83, 50, 24, -69, + 59, 4, -55, 68, -15, -40, 78, -31, -26, 87, -46, -11, + 32, 73, -99, 36, 62, -92, 42, 45, -82, 50, 25, -69, + 59, 4, -55, 69, -14, -40, 78, -30, -26, 87, -45, -11, + 33, 74, -98, 37, 63, -92, 43, 45, -81, 51, 25, -69, + 60, 5, -54, 69, -13, -40, 78, -29, -25, 88, -45, -11, + 33, 74, -97, 37, 63, -91, 43, 46, -81, 51, 26, -68, + 60, 6, -54, 69, -12, -40, 78, -28, -25, 88, -44, -11, + 34, 74, -96, 38, 64, -90, 44, 47, -80, 51, 27, -68, + 60, 7, -53, 69, -11, -39, 78, -27, -25, 88, -43, -11, + 35, 75, -95, 38, 64, -89, 44, 48, -79, 52, 29, -67, + 60, 9, -53, 69, -10, -39, 79, -26, -25, 88, -42, -10, + 36, 75, -93, 39, 65, -88, 45, 49, -78, 52, 30, -66, + 61, 10, -52, 70, -8, -38, 79, -25, -24, 88, -41, -10, + 36, 76, -92, 40, 66, -86, 45, 50, -77, 53, 31, -65, + 61, 12, -52, 70, -7, -38, 79, -23, -24, 88, -39, -10, + 37, 76, -90, 40, 67, -85, 46, 51, -76, 53, 33, -64, + 62, 13, -51, 70, -5, -37, 79, -22, -23, 89, -38, -9, + 38, 77, -89, 41, 68, -84, 47, 53, -75, 54, 34, -64, + 62, 15, -50, 71, -3, -37, 80, -20, -23, 89, -36, -9, + 39, 78, -87, 42, 69, -82, 47, 54, -74, 54, 36, -63, + 63, 17, -49, 71, -2, -36, 80, -19, -22, 89, -35, -8, + 40, 78, -85, 43, 70, -80, 48, 56, -72, 55, 38, -61, + 63, 19, -48, 72, 1, -35, 80, -17, -22, 90, -33, -8, + 41, 79, -83, 44, 71, -79, 49, 57, -71, 56, 40, -60, + 64, 21, -48, 72, 3, -34, 81, -15, -21, 90, -31, -7, + 43, 80, -81, 45, 72, -77, 50, 59, -69, 56, 42, -59, + 64, 23, -47, 72, 5, -34, 81, -13, -21, 90, -29, -7, + 44, 81, -79, 46, 73, -75, 51, 60, -68, 57, 44, -58, + 65, 25, -46, 73, 7, -33, 82, -10, -20, 91, -27, -6, + 45, 82, -77, 48, 75, -73, 52, 62, -66, 58, 46, -56, + 66, 27, -44, 74, 9, -32, 82, -8, -19, 91, -25, -6, + 46, 83, -75, 49, 76, -71, 53, 64, -64, 59, 48, -55, + 66, 29, -43, 74, 12, -31, 82, -6, -18, 91, -22, -5, + 48, 84, -73, 50, 77, -69, 54, 65, -63, 60, 50, -53, + 67, 32, -42, 75, 14, -30, 83, -3, -17, 92, -20, -4, + 49, 85, -71, 51, 79, -68, 55, 67, -61, 61, 52, -52, + 68, 34, -41, 75, 16, -29, 84, -1, -17, 92, -18, -4, + 50, 86, -69, 52, 80, -66, 56, 69, -59, 62, 54, -50, + 69, 36, -40, 76, 19, -28, 84, 1, -16, 93, -15, -3, + 52, 87, -66, 54, 81, -63, 57, 71, -57, 63, 56, -49, + 69, 39, -38, 77, 22, -27, 85, 4, -15, 93, -13, -2, + 53, 89, -64, 55, 83, -61, 58, 72, -55, 64, 58, -47, + 70, 41, -37, 78, 24, -26, 85, 7, -14, 94, -10, -1, + 54, 90, -62, 56, 84, -59, 60, 74, -53, 65, 60, -45, + 71, 44, -35, 78, 27, -24, 86, 9, -13, 94, -8, 0, + 56, 91, -60, 57, 86, -57, 61, 76, -52, 66, 63, -44, + 72, 46, -34, 79, 29, -23, 87, 12, -12, 95, -5, 0, + 57, 92, -57, 59, 87, -55, 62, 78, -49, 67, 65, -42, + 73, 49, -32, 80, 32, -22, 87, 15, -11, 95, -2, 1, + 58, 94, -55, 60, 89, -52, 63, 80, -47, 68, 67, -40, + 74, 51, -31, 81, 35, -20, 88, 18, -9, 96, 1, 2, + 60, 95, -53, 61, 90, -50, 64, 82, -45, 69, 69, -38, + 75, 54, -29, 81, 37, -19, 89, 20, -8, 97, 3, 3, + 32, 75, -104, 36, 63, -98, 42, 45, -87, 50, 25, -74, + 59, 5, -59, 68, -14, -45, 78, -30, -30, 87, -45, -16, + 32, 75, -104, 36, 63, -97, 42, 46, -87, 50, 25, -74, + 59, 5, -59, 68, -13, -45, 78, -30, -30, 87, -45, -16, + 32, 75, -103, 36, 63, -97, 42, 46, -87, 50, 26, -74, + 59, 5, -59, 69, -13, -45, 78, -30, -30, 87, -45, -15, + 32, 75, -103, 36, 64, -97, 42, 46, -86, 50, 26, -74, + 59, 6, -59, 69, -13, -44, 78, -29, -30, 87, -45, -15, + 33, 75, -103, 36, 64, -96, 43, 46, -86, 51, 26, -73, + 60, 6, -59, 69, -12, -44, 78, -29, -30, 88, -44, -15, + 33, 75, -102, 37, 64, -96, 43, 47, -86, 51, 27, -73, + 60, 7, -59, 69, -12, -44, 78, -28, -30, 88, -44, -15, + 33, 75, -101, 37, 64, -95, 43, 47, -85, 51, 28, -73, + 60, 7, -58, 69, -11, -44, 78, -28, -30, 88, -43, -15, + 34, 76, -101, 38, 65, -95, 44, 48, -85, 51, 28, -72, + 60, 8, -58, 69, -10, -44, 78, -27, -29, 88, -42, -15, + 34, 76, -100, 38, 65, -94, 44, 49, -84, 51, 29, -72, + 60, 9, -58, 69, -9, -43, 78, -26, -29, 88, -42, -15, + 35, 76, -99, 38, 66, -93, 44, 50, -83, 52, 30, -71, + 61, 10, -57, 69, -8, -43, 79, -25, -29, 88, -41, -14, + 36, 77, -98, 39, 67, -92, 45, 50, -83, 52, 31, -70, + 61, 11, -57, 70, -7, -43, 79, -24, -28, 88, -40, -14, + 36, 77, -96, 40, 67, -91, 45, 51, -82, 53, 33, -70, + 61, 13, -56, 70, -6, -42, 79, -23, -28, 88, -38, -14, + 37, 78, -95, 41, 68, -90, 46, 53, -81, 53, 34, -69, + 62, 14, -55, 70, -4, -42, 79, -21, -28, 89, -37, -14, + 38, 78, -93, 41, 69, -88, 47, 54, -80, 54, 35, -68, + 62, 16, -55, 71, -3, -41, 80, -20, -27, 89, -36, -13, + 39, 79, -92, 42, 70, -87, 47, 55, -78, 54, 37, -67, + 62, 17, -54, 71, -1, -40, 80, -18, -27, 89, -34, -13, + 40, 79, -90, 43, 71, -85, 48, 56, -77, 55, 38, -66, + 63, 19, -53, 71, 1, -40, 80, -16, -26, 89, -33, -12, + 41, 80, -88, 44, 72, -84, 49, 58, -76, 56, 40, -65, + 63, 21, -52, 72, 3, -39, 81, -14, -26, 90, -31, -12, + 42, 81, -87, 45, 73, -82, 50, 59, -74, 56, 42, -64, + 64, 23, -51, 72, 5, -38, 81, -13, -25, 90, -29, -11, + 43, 82, -85, 46, 74, -80, 51, 61, -73, 57, 44, -63, + 65, 25, -50, 73, 7, -38, 81, -11, -24, 90, -27, -11, + 44, 82, -83, 47, 75, -79, 51, 62, -71, 58, 46, -61, + 65, 27, -49, 73, 9, -37, 82, -8, -24, 91, -25, -10, + 46, 83, -81, 48, 76, -77, 53, 64, -70, 59, 48, -60, + 66, 29, -48, 74, 11, -36, 82, -6, -23, 91, -23, -10, + 47, 84, -79, 49, 78, -75, 53, 66, -68, 59, 50, -59, + 67, 31, -47, 74, 14, -35, 83, -4, -22, 92, -21, -9, + 48, 85, -77, 50, 79, -73, 54, 67, -66, 60, 52, -57, + 67, 34, -46, 75, 16, -34, 83, -2, -21, 92, -18, -8, + 49, 86, -75, 52, 80, -71, 56, 69, -65, 61, 54, -56, + 68, 36, -45, 76, 18, -33, 84, 1, -20, 92, -16, -8, + 51, 87, -72, 53, 81, -69, 57, 70, -63, 62, 56, -54, + 69, 38, -43, 76, 21, -32, 84, 3, -20, 93, -14, -7, + 52, 89, -70, 54, 83, -67, 58, 72, -61, 63, 58, -52, + 70, 41, -42, 77, 23, -31, 85, 6, -19, 93, -11, -6, + 53, 90, -68, 55, 84, -65, 59, 74, -59, 64, 60, -51, + 71, 43, -41, 78, 26, -29, 86, 8, -18, 94, -9, -5, + 55, 91, -66, 57, 86, -63, 60, 76, -57, 65, 62, -49, + 71, 45, -39, 79, 28, -28, 86, 11, -17, 94, -6, -4, + 56, 92, -64, 58, 87, -61, 61, 77, -55, 66, 64, -48, + 72, 48, -38, 79, 31, -27, 87, 14, -16, 95, -4, -3, + 57, 94, -61, 59, 89, -58, 62, 79, -53, 67, 66, -46, + 73, 50, -36, 80, 34, -26, 88, 17, -14, 96, -1, -2, + 59, 95, -59, 61, 90, -56, 64, 81, -51, 68, 68, -44, + 74, 53, -35, 81, 36, -24, 88, 19, -13, 96, 2, -1, + 60, 96, -57, 62, 91, -54, 65, 83, -49, 69, 70, -42, + 75, 55, -33, 82, 39, -23, 89, 22, -12, 97, 5, 0, + 33, 77, -107, 37, 66, -100, 43, 48, -90, 51, 28, -77, + 60, 8, -63, 69, -11, -48, 78, -27, -34, 88, -43, -19, + 33, 77, -106, 37, 66, -100, 43, 48, -90, 51, 28, -77, + 60, 8, -63, 69, -10, -48, 78, -27, -34, 88, -43, -19, + 33, 77, -106, 37, 66, -100, 43, 49, -90, 51, 29, -77, + 60, 8, -63, 69, -10, -48, 78, -27, -34, 88, -42, -19, + 34, 77, -106, 37, 66, -100, 43, 49, -90, 51, 29, -77, + 60, 9, -63, 69, -10, -48, 78, -27, -34, 88, -42, -19, + 34, 77, -105, 37, 66, -99, 43, 49, -89, 51, 29, -77, + 60, 9, -62, 69, -9, -48, 78, -26, -34, 88, -42, -19, + 34, 77, -105, 38, 66, -99, 44, 50, -89, 51, 30, -77, + 60, 9, -62, 69, -9, -48, 78, -26, -34, 88, -41, -19, + 34, 77, -104, 38, 67, -98, 44, 50, -89, 51, 30, -76, + 60, 10, -62, 69, -8, -48, 78, -25, -33, 88, -41, -19, + 35, 78, -103, 38, 67, -98, 44, 51, -88, 52, 31, -76, + 60, 11, -62, 69, -7, -47, 79, -24, -33, 88, -40, -19, + 35, 78, -102, 39, 68, -97, 45, 51, -87, 52, 32, -75, + 61, 12, -61, 70, -7, -47, 79, -23, -33, 88, -39, -18, + 36, 78, -101, 39, 68, -96, 45, 52, -87, 52, 33, -75, + 61, 13, -61, 70, -6, -47, 79, -23, -33, 88, -38, -18, + 37, 78, -100, 40, 69, -95, 45, 53, -86, 53, 34, -74, + 61, 14, -60, 70, -4, -46, 79, -21, -32, 89, -37, -18, + 37, 79, -99, 41, 69, -94, 46, 54, -85, 53, 35, -73, + 62, 15, -60, 70, -3, -46, 79, -20, -32, 89, -36, -18, + 38, 79, -98, 41, 70, -93, 47, 55, -84, 54, 37, -72, + 62, 17, -59, 71, -2, -45, 80, -19, -31, 89, -35, -17, + 39, 80, -96, 42, 71, -91, 47, 56, -83, 54, 38, -72, + 62, 18, -58, 71, 0, -45, 80, -17, -31, 89, -34, -17, + 40, 80, -95, 43, 72, -90, 48, 57, -82, 55, 39, -71, + 63, 20, -58, 71, 1, -44, 80, -16, -31, 89, -32, -17, + 41, 81, -93, 44, 73, -89, 49, 59, -81, 55, 41, -70, + 63, 21, -57, 72, 3, -44, 80, -14, -30, 90, -31, -16, + 42, 82, -91, 45, 74, -87, 50, 60, -79, 56, 43, -69, + 64, 23, -56, 72, 5, -43, 81, -12, -29, 90, -29, -16, + 43, 82, -90, 46, 75, -85, 50, 61, -78, 57, 44, -67, + 64, 25, -55, 73, 7, -42, 81, -10, -29, 90, -27, -15, + 44, 83, -88, 47, 76, -84, 51, 63, -76, 57, 46, -66, + 65, 27, -54, 73, 9, -41, 82, -8, -28, 91, -25, -15, + 45, 84, -86, 48, 77, -82, 52, 64, -75, 58, 48, -65, + 66, 29, -53, 74, 11, -41, 82, -6, -28, 91, -23, -14, + 46, 85, -84, 49, 78, -80, 53, 66, -73, 59, 50, -64, + 66, 31, -52, 74, 13, -40, 83, -4, -27, 91, -21, -13, + 48, 86, -82, 50, 79, -78, 54, 67, -72, 60, 52, -62, + 67, 33, -51, 75, 16, -39, 83, -2, -26, 92, -19, -13, + 49, 87, -80, 51, 80, -77, 55, 69, -70, 61, 53, -61, + 68, 36, -50, 75, 18, -38, 84, 0, -25, 92, -17, -12, + 50, 88, -78, 52, 82, -75, 56, 70, -68, 62, 55, -59, + 68, 38, -48, 76, 20, -37, 84, 3, -24, 93, -14, -11, + 51, 89, -76, 53, 83, -73, 57, 72, -67, 62, 57, -58, + 69, 40, -47, 77, 22, -36, 85, 5, -23, 93, -12, -11, + 53, 90, -74, 55, 84, -70, 58, 74, -65, 63, 59, -56, + 70, 42, -46, 77, 25, -34, 85, 8, -22, 94, -9, -10, + 54, 91, -72, 56, 86, -68, 59, 75, -63, 64, 61, -55, + 71, 45, -44, 78, 27, -33, 86, 10, -21, 94, -7, -9, + 55, 92, -69, 57, 87, -66, 60, 77, -61, 65, 63, -53, + 72, 47, -43, 79, 30, -32, 86, 13, -20, 95, -5, -8, + 56, 93, -67, 58, 88, -64, 62, 79, -59, 66, 65, -51, + 73, 49, -42, 80, 32, -31, 87, 15, -19, 95, -2, -7, + 58, 95, -65, 60, 90, -62, 63, 81, -57, 68, 68, -49, + 74, 52, -40, 80, 35, -29, 88, 18, -18, 96, 1, -6, + 59, 96, -63, 61, 91, -60, 64, 82, -55, 69, 70, -48, + 75, 54, -38, 81, 38, -28, 88, 21, -17, 96, 3, -5, + 61, 97, -60, 62, 93, -58, 65, 84, -53, 70, 72, -46, + 75, 56, -37, 82, 40, -27, 89, 23, -16, 97, 6, -4, + 5, -9, 7, 18, -28, 25, 31, -39, 37, 42, -48, 47, + 54, -58, 56, 65, -67, 65, 75, -76, 73, 85, -84, 81, + 5, -7, 7, 18, -26, 26, 31, -38, 38, 42, -48, 47, + 54, -58, 56, 65, -67, 65, 75, -75, 73, 85, -84, 81, + 6, -5, 8, 19, -24, 26, 31, -36, 38, 43, -47, 47, + 54, -57, 56, 65, -66, 65, 75, -75, 73, 85, -84, 81, + 6, -1, 10, 19, -21, 26, 31, -34, 38, 43, -46, 47, + 54, -56, 56, 65, -65, 65, 75, -75, 73, 85, -83, 81, + 7, 4, 11, 20, -17, 27, 31, -32, 38, 43, -44, 47, + 54, -55, 56, 65, -65, 65, 75, -74, 73, 85, -83, 81, + 9, 9, 13, 20, -13, 28, 32, -30, 39, 43, -42, 48, + 54, -54, 57, 65, -64, 65, 75, -73, 73, 86, -82, 81, + 10, 13, 16, 21, -9, 29, 32, -26, 39, 43, -40, 48, + 55, -52, 57, 65, -62, 65, 76, -72, 74, 86, -81, 82, + 12, 17, 18, 22, -4, 30, 33, -23, 40, 44, -37, 48, + 55, -50, 57, 65, -61, 65, 76, -71, 74, 86, -80, 82, + 14, 21, 21, 23, 0, 32, 33, -19, 41, 44, -34, 49, + 55, -48, 57, 65, -59, 66, 76, -69, 74, 86, -79, 82, + 15, 25, 23, 24, 4, 33, 34, -15, 41, 44, -31, 49, + 55, -45, 58, 66, -57, 66, 76, -68, 74, 86, -78, 82, + 17, 28, 26, 25, 8, 34, 35, -11, 42, 45, -28, 50, + 56, -43, 58, 66, -55, 66, 76, -66, 74, 86, -76, 82, + 19, 31, 28, 26, 13, 36, 35, -7, 43, 45, -25, 51, + 56, -40, 59, 66, -52, 67, 77, -64, 75, 86, -75, 83, + 21, 34, 31, 27, 17, 38, 36, -3, 44, 46, -21, 51, + 57, -36, 59, 67, -50, 67, 77, -62, 75, 87, -73, 83, + 22, 37, 33, 29, 21, 39, 37, 1, 45, 47, -17, 52, + 57, -33, 60, 67, -47, 68, 77, -60, 75, 87, -71, 83, + 24, 40, 36, 30, 24, 41, 38, 5, 46, 47, -13, 53, + 58, -30, 60, 67, -44, 68, 77, -57, 76, 87, -69, 83, + 26, 42, 38, 31, 28, 42, 39, 9, 47, 48, -9, 54, + 58, -26, 61, 68, -41, 69, 78, -55, 76, 87, -66, 84, + 28, 45, 40, 33, 32, 44, 40, 14, 49, 49, -5, 55, + 59, -23, 62, 68, -38, 69, 78, -52, 77, 88, -64, 84, + 30, 48, 43, 34, 35, 46, 41, 17, 50, 50, -1, 56, + 59, -19, 63, 69, -35, 70, 79, -49, 77, 88, -61, 85, + 31, 50, 45, 36, 38, 47, 42, 21, 51, 51, 3, 57, + 60, -15, 63, 69, -31, 70, 79, -46, 78, 88, -59, 85, + 33, 52, 47, 37, 41, 49, 44, 25, 53, 52, 6, 58, + 61, -12, 64, 70, -28, 71, 79, -43, 78, 89, -56, 85, + 35, 55, 49, 39, 44, 51, 45, 28, 54, 53, 11, 59, + 61, -8, 65, 70, -24, 72, 80, -39, 79, 89, -53, 86, + 37, 57, 51, 40, 47, 52, 46, 32, 55, 54, 14, 60, + 62, -4, 66, 71, -21, 72, 80, -36, 79, 90, -50, 86, + 38, 59, 52, 42, 50, 54, 47, 35, 57, 55, 18, 61, + 63, 0, 67, 72, -17, 73, 81, -33, 80, 90, -47, 87, + 40, 62, 54, 43, 53, 55, 49, 38, 58, 56, 21, 62, + 64, 3, 68, 72, -14, 74, 82, -30, 81, 90, -44, 88, + 42, 64, 56, 45, 55, 57, 50, 41, 60, 57, 25, 64, + 65, 7, 69, 73, -10, 75, 82, -27, 81, 91, -41, 88, + 44, 66, 57, 47, 58, 59, 51, 45, 61, 58, 29, 65, + 66, 11, 70, 74, -6, 76, 83, -23, 82, 92, -38, 89, + 45, 68, 59, 48, 61, 60, 53, 48, 63, 59, 32, 66, + 67, 14, 71, 75, -3, 77, 83, -19, 83, 92, -34, 89, + 47, 70, 61, 50, 63, 62, 54, 51, 64, 60, 35, 67, + 68, 18, 72, 75, 1, 78, 84, -16, 84, 93, -31, 90, + 49, 72, 62, 51, 65, 63, 55, 54, 65, 61, 39, 69, + 68, 21, 73, 76, 4, 79, 85, -13, 85, 93, -28, 91, + 51, 75, 64, 53, 68, 65, 57, 57, 67, 63, 42, 70, + 70, 25, 75, 77, 8, 80, 85, -9, 85, 94, -24, 92, + 52, 77, 66, 54, 70, 67, 58, 59, 69, 64, 45, 71, + 71, 28, 76, 78, 12, 81, 86, -5, 86, 94, -21, 92, + 54, 79, 67, 56, 72, 68, 60, 62, 70, 65, 48, 73, + 72, 32, 77, 79, 15, 82, 87, -2, 87, 95, -18, 93, + 5, -8, 4, 18, -27, 22, 31, -38, 35, 42, -48, 45, + 54, -58, 55, 65, -67, 64, 75, -76, 72, 85, -84, 81, + 5, -6, 4, 18, -25, 22, 31, -37, 35, 42, -47, 45, + 54, -57, 55, 65, -66, 64, 75, -75, 72, 85, -84, 81, + 6, -4, 5, 19, -23, 23, 31, -36, 35, 43, -47, 45, + 54, -57, 55, 65, -66, 64, 75, -75, 72, 85, -84, 81, + 7, 0, 7, 19, -20, 23, 31, -34, 35, 43, -45, 45, + 54, -56, 55, 65, -65, 64, 75, -74, 73, 85, -83, 81, + 8, 5, 8, 20, -17, 24, 31, -32, 36, 43, -44, 46, + 54, -55, 55, 65, -64, 64, 75, -74, 73, 85, -83, 81, + 9, 9, 10, 20, -13, 25, 32, -29, 36, 43, -42, 46, + 54, -53, 55, 65, -63, 64, 76, -73, 73, 86, -82, 81, + 10, 14, 12, 21, -9, 26, 32, -26, 37, 43, -40, 46, + 55, -52, 56, 65, -62, 64, 76, -72, 73, 86, -81, 81, + 12, 18, 15, 22, -4, 27, 33, -22, 37, 44, -37, 47, + 55, -50, 56, 65, -60, 64, 76, -71, 73, 86, -80, 81, + 14, 22, 18, 23, 0, 28, 33, -19, 38, 44, -34, 47, + 55, -47, 56, 65, -59, 65, 76, -69, 73, 86, -79, 81, + 15, 25, 20, 24, 5, 30, 34, -15, 39, 45, -31, 48, + 55, -45, 57, 66, -57, 65, 76, -68, 73, 86, -77, 81, + 17, 28, 23, 25, 9, 31, 35, -11, 40, 45, -28, 48, + 56, -42, 57, 66, -55, 65, 76, -66, 74, 86, -76, 82, + 19, 31, 25, 26, 13, 33, 35, -7, 41, 46, -24, 49, + 56, -40, 57, 66, -52, 66, 77, -64, 74, 86, -74, 82, + 21, 34, 28, 27, 17, 34, 36, -2, 42, 46, -20, 50, + 57, -36, 58, 67, -49, 66, 77, -62, 74, 87, -72, 82, + 22, 37, 30, 29, 21, 36, 37, 2, 43, 47, -17, 50, + 57, -33, 59, 67, -47, 67, 77, -59, 75, 87, -71, 82, + 24, 40, 33, 30, 25, 38, 38, 6, 44, 47, -13, 51, + 58, -30, 59, 67, -44, 67, 77, -57, 75, 87, -68, 83, + 26, 42, 35, 31, 28, 39, 39, 9, 45, 48, -9, 52, + 58, -26, 60, 68, -41, 68, 78, -55, 75, 87, -66, 83, + 28, 45, 37, 33, 32, 41, 40, 14, 46, 49, -5, 53, + 59, -22, 61, 68, -38, 68, 78, -52, 76, 88, -64, 84, + 30, 48, 39, 34, 35, 43, 41, 17, 48, 50, -1, 54, + 59, -19, 61, 69, -34, 69, 79, -49, 76, 88, -61, 84, + 31, 50, 41, 36, 38, 44, 42, 21, 49, 51, 3, 55, + 60, -15, 62, 69, -31, 69, 79, -46, 77, 88, -59, 84, + 33, 52, 43, 37, 41, 46, 44, 25, 50, 52, 7, 56, + 61, -12, 63, 70, -28, 70, 79, -43, 78, 89, -56, 85, + 35, 55, 46, 39, 44, 48, 45, 29, 52, 53, 11, 57, + 62, -8, 64, 71, -24, 71, 80, -39, 78, 89, -53, 85, + 37, 57, 47, 40, 47, 50, 46, 32, 53, 54, 14, 59, + 62, -4, 65, 71, -21, 72, 80, -36, 79, 90, -50, 86, + 38, 59, 49, 42, 50, 51, 47, 35, 55, 55, 18, 60, + 63, 0, 66, 72, -17, 72, 81, -33, 79, 90, -47, 86, + 40, 62, 51, 43, 53, 53, 49, 38, 56, 56, 21, 61, + 64, 3, 67, 72, -14, 73, 82, -30, 80, 90, -44, 87, + 42, 64, 53, 45, 55, 55, 50, 42, 58, 57, 25, 62, + 65, 7, 68, 73, -10, 74, 82, -26, 81, 91, -41, 87, + 44, 66, 55, 47, 58, 56, 51, 45, 59, 58, 29, 64, + 66, 11, 69, 74, -6, 75, 83, -23, 82, 92, -38, 88, + 45, 68, 57, 48, 61, 58, 53, 48, 61, 59, 32, 65, + 67, 14, 70, 75, -3, 76, 83, -19, 82, 92, -34, 89, + 47, 70, 58, 50, 63, 60, 54, 51, 62, 60, 35, 66, + 68, 18, 71, 75, 1, 77, 84, -16, 83, 93, -31, 89, + 49, 72, 60, 51, 65, 61, 55, 54, 64, 61, 39, 67, + 68, 21, 72, 76, 4, 78, 85, -13, 84, 93, -28, 90, + 51, 75, 62, 53, 68, 63, 57, 57, 65, 63, 42, 69, + 70, 25, 74, 77, 8, 79, 85, -9, 85, 94, -24, 91, + 52, 77, 64, 54, 70, 65, 58, 59, 67, 64, 45, 70, + 71, 28, 75, 78, 12, 80, 86, -5, 86, 94, -21, 92, + 54, 79, 65, 56, 73, 67, 60, 62, 68, 65, 48, 72, + 72, 32, 76, 79, 15, 81, 87, -2, 86, 95, -18, 92, + 5, -7, 0, 18, -26, 18, 31, -38, 32, 42, -48, 43, + 54, -57, 53, 65, -67, 62, 75, -75, 71, 85, -84, 80, + 5, -5, 1, 19, -24, 19, 31, -36, 32, 42, -47, 43, + 54, -57, 53, 65, -66, 63, 75, -75, 72, 85, -84, 80, + 6, -2, 2, 19, -22, 19, 31, -35, 32, 43, -46, 43, + 54, -56, 53, 65, -66, 63, 75, -75, 72, 85, -83, 80, + 7, 2, 3, 19, -19, 20, 31, -33, 32, 43, -45, 43, + 54, -56, 54, 65, -65, 63, 75, -74, 72, 85, -83, 80, + 8, 6, 5, 20, -16, 20, 31, -31, 33, 43, -43, 44, + 54, -54, 54, 65, -64, 63, 75, -74, 72, 85, -82, 80, + 9, 10, 7, 20, -12, 21, 32, -29, 33, 43, -42, 44, + 54, -53, 54, 65, -63, 63, 76, -73, 72, 86, -82, 80, + 10, 14, 9, 21, -8, 22, 32, -26, 34, 43, -39, 44, + 55, -51, 54, 65, -62, 63, 76, -72, 72, 86, -81, 80, + 12, 18, 12, 22, -3, 23, 33, -22, 35, 44, -37, 45, + 55, -49, 54, 65, -60, 63, 76, -70, 72, 86, -80, 80, + 14, 22, 14, 23, 1, 25, 33, -18, 35, 44, -34, 45, + 55, -47, 55, 65, -58, 64, 76, -69, 72, 86, -79, 81, + 15, 25, 17, 24, 5, 26, 34, -14, 36, 45, -31, 46, + 55, -45, 55, 66, -57, 64, 76, -68, 73, 86, -77, 81, + 17, 28, 19, 25, 9, 28, 35, -11, 37, 45, -27, 46, + 56, -42, 56, 66, -54, 64, 76, -66, 73, 86, -76, 81, + 19, 31, 21, 26, 13, 29, 35, -7, 38, 46, -24, 47, + 56, -39, 56, 66, -52, 65, 77, -64, 73, 86, -74, 81, + 21, 35, 24, 27, 18, 31, 36, -2, 39, 46, -20, 48, + 57, -36, 57, 67, -49, 65, 77, -62, 74, 87, -72, 82, + 23, 37, 27, 29, 21, 32, 37, 2, 40, 47, -16, 49, + 57, -33, 57, 67, -47, 66, 77, -59, 74, 87, -70, 82, + 24, 40, 29, 30, 25, 34, 38, 6, 41, 48, -13, 49, + 58, -30, 58, 67, -44, 66, 77, -57, 74, 87, -68, 82, + 26, 43, 31, 31, 28, 36, 39, 10, 43, 48, -9, 50, + 58, -26, 59, 68, -41, 67, 78, -54, 75, 87, -66, 82, + 28, 45, 34, 33, 32, 38, 40, 14, 44, 49, -5, 51, + 59, -22, 59, 68, -37, 67, 78, -51, 75, 88, -64, 83, + 30, 48, 36, 34, 35, 40, 41, 18, 45, 50, -1, 52, + 59, -19, 60, 69, -34, 68, 79, -49, 76, 88, -61, 83, + 31, 50, 38, 36, 38, 41, 43, 21, 47, 51, 3, 53, + 60, -15, 61, 69, -31, 68, 79, -46, 76, 88, -59, 84, + 33, 53, 40, 37, 41, 43, 44, 25, 48, 52, 7, 55, + 61, -12, 62, 70, -28, 69, 79, -43, 77, 89, -56, 84, + 35, 55, 42, 39, 45, 45, 45, 29, 50, 53, 11, 56, + 62, -7, 63, 71, -24, 70, 80, -39, 77, 89, -53, 85, + 37, 57, 44, 40, 47, 47, 46, 32, 51, 54, 14, 57, + 62, -4, 64, 71, -20, 71, 80, -36, 78, 90, -50, 85, + 38, 60, 46, 42, 50, 49, 47, 35, 53, 55, 18, 58, + 63, 0, 65, 72, -17, 71, 81, -33, 79, 90, -47, 86, + 40, 62, 48, 43, 53, 50, 49, 39, 54, 56, 22, 59, + 64, 3, 66, 72, -13, 72, 82, -30, 79, 90, -44, 86, + 42, 64, 50, 45, 55, 52, 50, 42, 56, 57, 25, 61, + 65, 7, 67, 73, -10, 73, 82, -26, 80, 91, -41, 87, + 44, 66, 52, 47, 58, 54, 51, 45, 57, 58, 29, 62, + 66, 11, 68, 74, -6, 74, 83, -23, 81, 92, -37, 88, + 45, 68, 54, 48, 61, 56, 53, 48, 59, 59, 32, 63, + 67, 15, 69, 75, -3, 75, 83, -19, 81, 92, -34, 88, + 47, 70, 56, 50, 63, 58, 54, 51, 61, 60, 35, 65, + 68, 18, 70, 75, 1, 76, 84, -16, 82, 93, -31, 89, + 49, 72, 58, 51, 65, 59, 55, 54, 62, 61, 39, 66, + 69, 21, 71, 76, 4, 77, 85, -12, 83, 93, -28, 89, + 51, 75, 60, 53, 68, 61, 57, 57, 64, 63, 42, 68, + 70, 25, 72, 77, 8, 78, 85, -9, 84, 94, -24, 90, + 52, 77, 62, 54, 70, 63, 58, 60, 65, 64, 45, 69, + 71, 29, 74, 78, 12, 79, 86, -5, 85, 94, -21, 91, + 54, 79, 63, 56, 73, 65, 60, 62, 67, 65, 48, 70, + 72, 32, 75, 79, 15, 80, 87, -2, 86, 95, -18, 92, + 5, -5, -6, 18, -24, 13, 31, -37, 28, 42, -47, 40, + 54, -57, 51, 65, -66, 61, 75, -75, 70, 85, -84, 79, + 6, -3, -5, 19, -23, 13, 31, -36, 28, 43, -46, 40, + 54, -57, 51, 65, -66, 61, 75, -75, 70, 85, -83, 79, + 6, 0, -4, 19, -21, 14, 31, -34, 28, 43, -46, 40, + 54, -56, 51, 65, -65, 61, 75, -75, 70, 85, -83, 79, + 7, 4, -3, 19, -18, 14, 31, -32, 29, 43, -44, 40, + 54, -55, 51, 65, -65, 61, 75, -74, 70, 85, -83, 79, + 8, 8, -1, 20, -15, 15, 32, -30, 29, 43, -43, 41, + 54, -54, 52, 65, -64, 61, 75, -73, 70, 85, -82, 79, + 9, 12, 1, 20, -11, 16, 32, -28, 29, 43, -41, 41, + 54, -53, 52, 65, -63, 61, 76, -73, 70, 86, -82, 79, + 11, 15, 3, 21, -7, 17, 32, -25, 30, 43, -39, 41, + 55, -51, 52, 65, -62, 61, 76, -72, 71, 86, -81, 79, + 12, 19, 6, 22, -2, 18, 33, -21, 31, 44, -36, 42, + 55, -49, 52, 65, -60, 62, 76, -70, 71, 86, -80, 79, + 14, 23, 8, 23, 2, 20, 33, -18, 31, 44, -33, 42, + 55, -47, 53, 66, -58, 62, 76, -69, 71, 86, -78, 79, + 16, 26, 11, 24, 6, 21, 34, -14, 32, 45, -30, 43, + 55, -44, 53, 66, -56, 62, 76, -67, 71, 86, -77, 80, + 17, 29, 13, 25, 10, 23, 35, -10, 33, 45, -27, 44, + 56, -42, 53, 66, -54, 63, 76, -66, 72, 86, -76, 80, + 19, 32, 16, 26, 14, 24, 35, -6, 34, 46, -24, 44, + 56, -39, 54, 66, -52, 63, 77, -64, 72, 86, -74, 80, + 21, 35, 19, 27, 18, 26, 36, -2, 35, 46, -20, 45, + 57, -36, 55, 67, -49, 63, 77, -61, 72, 87, -72, 80, + 23, 38, 21, 29, 22, 28, 37, 2, 37, 47, -16, 46, + 57, -33, 55, 67, -46, 64, 77, -59, 73, 87, -70, 81, + 24, 40, 23, 30, 25, 30, 38, 6, 38, 48, -12, 47, + 58, -29, 56, 67, -44, 64, 77, -57, 73, 87, -68, 81, + 26, 43, 26, 31, 29, 31, 39, 10, 39, 48, -9, 48, + 58, -26, 56, 68, -41, 65, 78, -54, 73, 87, -66, 81, + 28, 46, 29, 33, 32, 34, 40, 14, 41, 49, -4, 49, + 59, -22, 57, 68, -37, 65, 78, -51, 74, 88, -63, 82, + 30, 48, 31, 34, 36, 35, 41, 18, 42, 50, -1, 50, + 59, -18, 58, 69, -34, 66, 79, -48, 74, 88, -61, 82, + 32, 50, 33, 36, 39, 37, 43, 22, 44, 51, 3, 51, + 60, -15, 59, 69, -31, 67, 79, -46, 75, 88, -58, 83, + 33, 53, 35, 37, 42, 39, 44, 25, 45, 52, 7, 52, + 61, -11, 60, 70, -27, 67, 79, -43, 75, 89, -56, 83, + 35, 55, 38, 39, 45, 41, 45, 29, 47, 53, 11, 53, + 62, -7, 61, 71, -24, 68, 80, -39, 76, 89, -53, 84, + 37, 58, 40, 40, 48, 43, 46, 32, 48, 54, 15, 54, + 62, -4, 62, 71, -20, 69, 80, -36, 77, 90, -50, 84, + 39, 60, 42, 42, 50, 45, 47, 36, 50, 55, 18, 56, + 63, 0, 63, 72, -17, 70, 81, -33, 77, 90, -47, 85, + 40, 62, 44, 43, 53, 47, 49, 39, 51, 56, 22, 57, + 64, 4, 64, 72, -13, 71, 82, -29, 78, 91, -44, 85, + 42, 64, 46, 45, 55, 49, 50, 42, 53, 57, 25, 58, + 65, 7, 65, 73, -10, 71, 82, -26, 79, 91, -41, 86, + 44, 66, 49, 47, 58, 51, 51, 45, 55, 58, 29, 60, + 66, 11, 66, 74, -6, 72, 83, -22, 79, 92, -37, 86, + 45, 68, 51, 48, 61, 53, 53, 48, 56, 59, 32, 61, + 67, 15, 67, 75, -2, 73, 83, -19, 80, 92, -34, 87, + 47, 70, 53, 50, 63, 54, 54, 51, 58, 60, 36, 62, + 68, 18, 68, 75, 1, 74, 84, -16, 81, 93, -31, 88, + 49, 73, 55, 51, 66, 56, 55, 54, 59, 61, 39, 64, + 69, 22, 69, 76, 5, 75, 85, -12, 82, 93, -28, 88, + 51, 75, 57, 53, 68, 58, 57, 57, 61, 63, 42, 65, + 70, 25, 71, 77, 8, 76, 86, -8, 83, 94, -24, 89, + 52, 77, 59, 54, 70, 60, 58, 60, 63, 64, 45, 67, + 71, 29, 72, 78, 12, 77, 86, -5, 84, 94, -21, 90, + 54, 79, 60, 56, 73, 62, 60, 62, 64, 65, 48, 68, + 72, 32, 73, 79, 15, 78, 87, -2, 85, 95, -18, 91, + 6, -2, -11, 19, -22, 8, 31, -35, 24, 43, -46, 37, + 54, -56, 49, 65, -66, 59, 75, -75, 69, 85, -83, 77, + 6, 0, -10, 19, -21, 8, 31, -34, 24, 43, -46, 37, + 54, -56, 49, 65, -65, 59, 75, -75, 69, 85, -83, 77, + 7, 2, -10, 19, -19, 9, 31, -33, 24, 43, -45, 37, + 54, -55, 49, 65, -65, 59, 75, -74, 69, 85, -83, 77, + 7, 6, -8, 19, -16, 9, 31, -31, 24, 43, -44, 37, + 54, -55, 49, 65, -64, 59, 75, -74, 69, 85, -82, 78, + 8, 10, -6, 20, -13, 10, 32, -29, 25, 43, -42, 38, + 54, -53, 49, 65, -63, 59, 75, -73, 69, 85, -82, 78, + 10, 13, -4, 21, -10, 11, 32, -27, 25, 43, -40, 38, + 54, -52, 49, 65, -62, 59, 76, -72, 69, 86, -81, 78, + 11, 17, -2, 21, -6, 12, 32, -24, 26, 43, -38, 38, + 55, -51, 49, 65, -61, 59, 76, -71, 69, 86, -80, 78, + 13, 20, 0, 22, -1, 13, 33, -20, 27, 44, -35, 39, + 55, -48, 50, 65, -60, 60, 76, -70, 69, 86, -79, 78, + 14, 24, 3, 23, 3, 15, 33, -17, 27, 44, -33, 39, + 55, -46, 50, 66, -58, 60, 76, -69, 69, 86, -78, 78, + 16, 27, 5, 24, 7, 16, 34, -13, 28, 45, -30, 40, + 55, -44, 51, 66, -56, 60, 76, -67, 70, 86, -77, 78, + 17, 30, 8, 25, 11, 18, 35, -9, 29, 45, -26, 40, + 56, -41, 51, 66, -54, 61, 76, -65, 70, 86, -75, 79, + 19, 33, 10, 26, 14, 19, 36, -6, 30, 46, -23, 41, + 56, -39, 52, 66, -52, 61, 77, -63, 70, 86, -74, 79, + 21, 36, 13, 28, 19, 21, 36, -1, 32, 46, -19, 42, + 57, -35, 52, 67, -49, 61, 77, -61, 71, 87, -72, 79, + 23, 38, 16, 29, 22, 23, 37, 3, 33, 47, -16, 43, + 57, -32, 53, 67, -46, 62, 77, -59, 71, 87, -70, 79, + 24, 41, 18, 30, 26, 25, 38, 7, 34, 48, -12, 44, + 58, -29, 53, 67, -43, 62, 77, -56, 71, 87, -68, 80, + 26, 43, 21, 32, 29, 27, 39, 10, 35, 48, -8, 45, + 58, -26, 54, 68, -40, 63, 78, -54, 72, 87, -66, 80, + 28, 46, 24, 33, 33, 29, 40, 15, 37, 49, -4, 46, + 59, -22, 55, 68, -37, 64, 78, -51, 72, 88, -63, 80, + 30, 48, 26, 34, 36, 31, 42, 18, 39, 50, 0, 47, + 59, -18, 56, 69, -34, 64, 79, -48, 73, 88, -61, 81, + 32, 51, 28, 36, 39, 33, 43, 22, 40, 51, 3, 48, + 60, -15, 57, 69, -31, 65, 79, -45, 73, 88, -58, 81, + 33, 53, 31, 37, 42, 35, 44, 25, 42, 52, 7, 49, + 61, -11, 57, 70, -27, 66, 79, -42, 74, 89, -56, 82, + 35, 56, 33, 39, 45, 37, 45, 29, 43, 53, 11, 50, + 62, -7, 58, 71, -23, 66, 80, -39, 74, 89, -52, 82, + 37, 58, 36, 40, 48, 39, 46, 33, 45, 54, 15, 52, + 62, -3, 59, 71, -20, 67, 81, -36, 75, 90, -50, 83, + 39, 60, 38, 42, 50, 41, 48, 36, 46, 55, 18, 53, + 63, 0, 60, 72, -17, 68, 81, -33, 76, 90, -47, 83, + 40, 62, 40, 43, 53, 43, 49, 39, 48, 56, 22, 54, + 64, 4, 61, 72, -13, 69, 82, -29, 76, 91, -44, 84, + 42, 64, 42, 45, 56, 45, 50, 42, 50, 57, 25, 56, + 65, 7, 63, 73, -10, 70, 82, -26, 77, 91, -41, 84, + 44, 67, 45, 47, 59, 47, 52, 45, 52, 58, 29, 57, + 66, 11, 64, 74, -6, 71, 83, -22, 78, 92, -37, 85, + 46, 69, 47, 48, 61, 49, 53, 48, 53, 59, 33, 59, + 67, 15, 65, 75, -2, 72, 83, -19, 79, 92, -34, 86, + 47, 71, 49, 50, 63, 51, 54, 51, 55, 60, 36, 60, + 68, 18, 66, 76, 1, 73, 84, -16, 80, 93, -31, 87, + 49, 73, 51, 51, 66, 53, 56, 54, 57, 61, 39, 61, + 69, 22, 67, 76, 5, 74, 85, -12, 80, 93, -28, 87, + 51, 75, 53, 53, 68, 55, 57, 57, 58, 63, 42, 63, + 70, 26, 69, 77, 9, 75, 86, -8, 81, 94, -24, 88, + 52, 77, 55, 54, 71, 57, 58, 60, 60, 64, 46, 64, + 71, 29, 70, 78, 12, 76, 86, -5, 82, 94, -21, 89, + 54, 79, 57, 56, 73, 59, 60, 62, 62, 65, 49, 66, + 72, 32, 71, 79, 15, 77, 87, -2, 83, 95, -17, 90, + 6, 1, -17, 19, -20, 3, 31, -34, 19, 43, -45, 33, + 54, -56, 46, 65, -65, 56, 75, -74, 67, 85, -83, 76, + 6, 3, -16, 19, -18, 3, 31, -33, 20, 43, -45, 33, + 54, -55, 46, 65, -65, 56, 75, -74, 67, 85, -83, 76, + 7, 5, -15, 19, -17, 4, 31, -32, 20, 43, -44, 34, + 54, -55, 46, 65, -64, 57, 75, -74, 67, 85, -83, 76, + 8, 9, -13, 20, -14, 4, 31, -30, 20, 43, -43, 34, + 54, -54, 46, 65, -64, 57, 75, -73, 67, 85, -82, 76, + 9, 12, -12, 20, -11, 5, 32, -28, 21, 43, -41, 34, + 54, -53, 46, 65, -63, 57, 76, -73, 67, 86, -82, 76, + 10, 15, -10, 21, -8, 6, 32, -26, 21, 43, -39, 34, + 54, -51, 46, 65, -62, 57, 76, -72, 67, 86, -81, 76, + 11, 18, -8, 21, -4, 7, 33, -23, 22, 44, -37, 35, + 55, -50, 47, 65, -61, 57, 76, -71, 67, 86, -80, 76, + 13, 22, -5, 22, 0, 8, 33, -19, 22, 44, -35, 35, + 55, -48, 47, 65, -59, 57, 76, -70, 67, 86, -79, 76, + 15, 25, -3, 23, 4, 10, 34, -16, 23, 44, -32, 36, + 55, -46, 47, 66, -57, 58, 76, -68, 67, 86, -78, 77, + 16, 28, 0, 24, 8, 11, 34, -12, 24, 45, -29, 36, + 56, -43, 48, 66, -55, 58, 76, -67, 68, 86, -77, 77, + 18, 30, 2, 25, 11, 13, 35, -9, 25, 45, -26, 37, + 56, -41, 48, 66, -53, 58, 76, -65, 68, 86, -75, 77, + 19, 33, 5, 26, 15, 15, 36, -5, 26, 46, -22, 38, + 56, -38, 49, 66, -51, 59, 77, -63, 68, 86, -74, 77, + 21, 36, 8, 28, 19, 17, 37, 0, 27, 46, -19, 39, + 57, -35, 49, 67, -48, 59, 77, -61, 69, 87, -72, 77, + 23, 39, 11, 29, 23, 18, 37, 3, 29, 47, -15, 39, + 57, -32, 50, 67, -46, 60, 77, -58, 69, 87, -70, 78, + 25, 41, 13, 30, 26, 20, 38, 7, 30, 48, -11, 40, + 58, -28, 51, 67, -43, 60, 78, -56, 69, 87, -68, 78, + 26, 44, 16, 32, 30, 22, 39, 11, 31, 48, -8, 41, + 58, -25, 51, 68, -40, 61, 78, -54, 70, 87, -66, 78, + 28, 46, 19, 33, 33, 25, 41, 15, 33, 49, -4, 42, + 59, -21, 52, 68, -37, 61, 78, -51, 70, 88, -63, 79, + 30, 49, 21, 35, 36, 27, 42, 19, 35, 50, 0, 44, + 59, -18, 53, 69, -33, 62, 79, -48, 71, 88, -60, 79, + 32, 51, 23, 36, 39, 29, 43, 22, 36, 51, 4, 45, + 60, -14, 54, 69, -30, 63, 79, -45, 71, 88, -58, 80, + 33, 53, 26, 37, 42, 31, 44, 26, 38, 52, 8, 46, + 61, -11, 55, 70, -27, 63, 80, -42, 72, 89, -55, 80, + 35, 56, 29, 39, 45, 33, 45, 30, 39, 53, 12, 47, + 62, -7, 56, 71, -23, 64, 80, -39, 73, 89, -52, 81, + 37, 58, 31, 41, 48, 35, 46, 33, 41, 54, 15, 49, + 62, -3, 57, 71, -20, 65, 81, -35, 73, 90, -49, 81, + 39, 60, 33, 42, 51, 37, 48, 36, 43, 55, 19, 50, + 63, 1, 58, 72, -16, 66, 81, -32, 74, 90, -46, 82, + 40, 62, 36, 44, 53, 39, 49, 39, 44, 56, 22, 51, + 64, 4, 59, 73, -13, 67, 82, -29, 75, 91, -44, 82, + 42, 64, 38, 45, 56, 41, 50, 42, 46, 57, 26, 53, + 65, 8, 60, 73, -9, 67, 82, -26, 75, 91, -40, 83, + 44, 67, 40, 47, 59, 43, 52, 46, 48, 58, 29, 54, + 66, 12, 61, 74, -5, 68, 83, -22, 76, 92, -37, 84, + 46, 69, 43, 48, 61, 45, 53, 49, 50, 59, 33, 56, + 67, 15, 62, 75, -2, 69, 83, -19, 77, 92, -34, 84, + 47, 71, 45, 50, 64, 47, 54, 51, 51, 60, 36, 57, + 68, 19, 64, 76, 2, 70, 84, -15, 78, 93, -31, 85, + 49, 73, 47, 51, 66, 49, 56, 54, 53, 61, 39, 58, + 69, 22, 65, 76, 5, 71, 85, -12, 79, 93, -27, 86, + 51, 75, 49, 53, 69, 51, 57, 57, 55, 63, 43, 60, + 70, 26, 66, 77, 9, 73, 86, -8, 80, 94, -24, 87, + 52, 77, 51, 55, 71, 53, 58, 60, 57, 64, 46, 62, + 71, 29, 67, 78, 12, 74, 86, -5, 80, 95, -20, 87, + 54, 79, 53, 56, 73, 55, 60, 63, 59, 65, 49, 63, + 72, 32, 69, 79, 16, 75, 87, -1, 81, 95, -17, 88, + 7, 5, -22, 19, -17, -2, 31, -32, 15, 43, -44, 29, + 54, -55, 42, 65, -65, 54, 75, -74, 64, 85, -83, 74, + 7, 7, -21, 19, -16, -2, 31, -31, 15, 43, -44, 29, + 54, -54, 42, 65, -64, 54, 75, -74, 64, 85, -82, 74, + 8, 9, -20, 20, -14, -1, 31, -30, 15, 43, -43, 30, + 54, -54, 43, 65, -64, 54, 75, -73, 64, 85, -82, 74, + 8, 12, -19, 20, -12, -1, 32, -29, 16, 43, -42, 30, + 54, -53, 43, 65, -63, 54, 75, -73, 64, 85, -82, 74, + 9, 14, -17, 20, -9, 0, 32, -27, 16, 43, -40, 30, + 54, -52, 43, 65, -62, 54, 76, -72, 65, 86, -81, 74, + 11, 17, -15, 21, -6, 1, 32, -24, 16, 43, -38, 30, + 55, -51, 43, 65, -61, 54, 76, -71, 65, 86, -81, 74, + 12, 20, -13, 22, -3, 2, 33, -21, 17, 44, -36, 31, + 55, -49, 43, 65, -60, 54, 76, -70, 65, 86, -80, 74, + 13, 23, -10, 23, 1, 3, 33, -18, 18, 44, -34, 31, + 55, -47, 44, 65, -58, 55, 76, -69, 65, 86, -79, 74, + 15, 26, -8, 23, 5, 5, 34, -15, 19, 44, -31, 32, + 55, -45, 44, 66, -57, 55, 76, -68, 65, 86, -77, 75, + 16, 29, -5, 24, 9, 6, 34, -11, 20, 45, -28, 32, + 56, -43, 44, 66, -55, 55, 76, -66, 65, 86, -76, 75, + 18, 31, -3, 25, 12, 8, 35, -8, 21, 45, -25, 33, + 56, -40, 45, 66, -53, 56, 76, -64, 66, 86, -75, 75, + 20, 34, 0, 27, 16, 10, 36, -4, 22, 46, -22, 34, + 56, -37, 45, 66, -51, 56, 77, -63, 66, 86, -73, 75, + 21, 37, 3, 28, 20, 12, 37, 0, 23, 46, -18, 35, + 57, -34, 46, 67, -48, 56, 77, -60, 66, 87, -71, 76, + 23, 39, 5, 29, 24, 13, 38, 4, 24, 47, -14, 36, + 57, -31, 47, 67, -45, 57, 77, -58, 67, 87, -69, 76, + 25, 42, 8, 30, 27, 15, 38, 8, 26, 48, -11, 37, + 58, -28, 47, 68, -42, 57, 78, -56, 67, 87, -67, 76, + 27, 44, 10, 32, 30, 17, 39, 12, 27, 48, -7, 38, + 58, -25, 48, 68, -40, 58, 78, -53, 68, 87, -65, 77, + 28, 47, 13, 33, 34, 20, 41, 16, 29, 49, -3, 39, + 59, -21, 49, 68, -36, 59, 78, -50, 68, 88, -63, 77, + 30, 49, 16, 35, 37, 22, 42, 19, 30, 50, 1, 40, + 60, -17, 50, 69, -33, 59, 79, -48, 69, 88, -60, 77, + 32, 51, 18, 36, 40, 24, 43, 23, 32, 51, 4, 41, + 60, -14, 51, 69, -30, 60, 79, -45, 69, 88, -58, 78, + 34, 54, 21, 38, 43, 26, 44, 26, 33, 52, 8, 42, + 61, -10, 52, 70, -27, 61, 80, -42, 70, 89, -55, 78, + 35, 56, 24, 39, 46, 28, 45, 30, 35, 53, 12, 44, + 62, -6, 53, 71, -23, 62, 80, -38, 70, 89, -52, 79, + 37, 58, 26, 41, 48, 30, 46, 33, 37, 54, 16, 45, + 62, -3, 54, 71, -19, 62, 81, -35, 71, 90, -49, 79, + 39, 60, 29, 42, 51, 32, 48, 36, 39, 55, 19, 46, + 63, 1, 55, 72, -16, 63, 81, -32, 72, 90, -46, 80, + 40, 63, 31, 44, 54, 35, 49, 40, 40, 56, 23, 48, + 64, 4, 56, 73, -13, 64, 82, -29, 72, 91, -43, 80, + 42, 65, 33, 45, 56, 37, 50, 43, 42, 57, 26, 49, + 65, 8, 57, 73, -9, 65, 82, -25, 73, 91, -40, 81, + 44, 67, 36, 47, 59, 39, 52, 46, 44, 58, 30, 51, + 66, 12, 58, 74, -5, 66, 83, -22, 74, 92, -37, 82, + 46, 69, 38, 48, 61, 41, 53, 49, 46, 59, 33, 52, + 67, 15, 59, 75, -2, 67, 84, -18, 75, 92, -34, 82, + 47, 71, 40, 50, 64, 43, 54, 52, 48, 60, 36, 54, + 68, 19, 61, 76, 2, 68, 84, -15, 76, 93, -30, 83, + 49, 73, 43, 51, 66, 45, 56, 54, 49, 61, 39, 55, + 69, 22, 62, 76, 5, 69, 85, -12, 76, 93, -27, 84, + 51, 75, 45, 53, 69, 47, 57, 58, 51, 63, 43, 57, + 70, 26, 63, 77, 9, 70, 86, -8, 77, 94, -24, 85, + 52, 77, 47, 55, 71, 49, 59, 60, 53, 64, 46, 58, + 71, 29, 65, 78, 12, 71, 86, -5, 78, 95, -20, 85, + 54, 79, 49, 56, 73, 51, 60, 63, 55, 65, 49, 60, + 72, 33, 66, 79, 16, 72, 87, -1, 79, 95, -17, 86, + 7, 10, -27, 19, -14, -8, 31, -30, 10, 43, -43, 25, + 54, -54, 38, 65, -64, 50, 75, -73, 61, 85, -82, 71, + 8, 11, -26, 20, -13, -7, 31, -29, 10, 43, -42, 25, + 54, -53, 38, 65, -63, 50, 75, -73, 61, 85, -82, 71, + 8, 13, -25, 20, -11, -7, 32, -28, 10, 43, -41, 25, + 54, -53, 39, 65, -63, 50, 75, -73, 61, 85, -82, 71, + 9, 15, -24, 20, -9, -6, 32, -26, 10, 43, -40, 25, + 54, -52, 39, 65, -62, 50, 76, -72, 62, 86, -81, 71, + 10, 17, -22, 21, -6, -6, 32, -25, 11, 43, -39, 25, + 54, -51, 39, 65, -62, 51, 76, -72, 62, 86, -81, 72, + 11, 19, -21, 21, -4, -5, 32, -22, 11, 44, -37, 26, + 55, -50, 39, 65, -60, 51, 76, -71, 62, 86, -80, 72, + 12, 22, -19, 22, 0, -4, 33, -20, 12, 44, -35, 26, + 55, -48, 39, 65, -59, 51, 76, -70, 62, 86, -79, 72, + 14, 25, -16, 23, 3, -2, 33, -16, 13, 44, -32, 27, + 55, -46, 40, 65, -58, 51, 76, -68, 62, 86, -78, 72, + 15, 28, -14, 24, 7, -1, 34, -13, 13, 44, -30, 27, + 55, -44, 40, 66, -56, 52, 76, -67, 62, 86, -77, 72, + 17, 30, -11, 25, 10, 1, 35, -10, 14, 45, -27, 28, + 56, -42, 41, 66, -54, 52, 76, -66, 63, 86, -76, 72, + 18, 33, -9, 26, 14, 2, 35, -6, 15, 45, -24, 28, + 56, -39, 41, 66, -52, 52, 76, -64, 63, 86, -74, 72, + 20, 35, -6, 27, 17, 4, 36, -3, 17, 46, -21, 29, + 56, -37, 42, 66, -50, 53, 77, -62, 63, 87, -73, 73, + 22, 38, -3, 28, 21, 6, 37, 1, 18, 47, -17, 30, + 57, -33, 42, 67, -47, 53, 77, -60, 64, 87, -71, 73, + 23, 40, -1, 29, 25, 8, 38, 5, 19, 47, -13, 31, + 57, -30, 43, 67, -45, 54, 77, -58, 64, 87, -69, 73, + 25, 43, 2, 31, 28, 10, 39, 9, 21, 48, -10, 32, + 58, -27, 44, 68, -42, 54, 78, -55, 64, 87, -67, 74, + 27, 45, 5, 32, 31, 12, 40, 12, 22, 49, -6, 33, + 58, -24, 44, 68, -39, 55, 78, -53, 65, 88, -65, 74, + 29, 48, 8, 33, 34, 14, 41, 16, 24, 49, -2, 34, + 59, -20, 45, 69, -36, 55, 78, -50, 65, 88, -62, 74, + 30, 50, 10, 35, 37, 16, 42, 20, 25, 50, 1, 35, + 60, -17, 46, 69, -32, 56, 79, -47, 66, 88, -60, 75, + 32, 52, 13, 36, 40, 18, 43, 23, 27, 51, 5, 37, + 60, -13, 47, 70, -29, 57, 79, -44, 66, 89, -57, 75, + 34, 54, 15, 38, 43, 21, 44, 27, 29, 52, 9, 38, + 61, -10, 48, 70, -26, 57, 80, -41, 67, 89, -55, 76, + 36, 57, 18, 39, 46, 23, 45, 31, 30, 53, 13, 39, + 62, -6, 49, 71, -22, 58, 80, -38, 68, 89, -52, 76, + 37, 59, 21, 41, 49, 25, 47, 34, 32, 54, 16, 41, + 63, -2, 50, 71, -19, 59, 81, -35, 68, 90, -49, 77, + 39, 61, 23, 42, 52, 27, 48, 37, 34, 55, 20, 42, + 63, 1, 51, 72, -16, 60, 81, -32, 69, 90, -46, 77, + 41, 63, 26, 44, 54, 29, 49, 40, 36, 56, 23, 43, + 64, 5, 52, 73, -12, 61, 82, -28, 70, 91, -43, 78, + 42, 65, 28, 45, 57, 32, 50, 43, 37, 57, 26, 45, + 65, 8, 53, 73, -9, 62, 82, -25, 70, 91, -40, 79, + 44, 67, 31, 47, 59, 34, 52, 46, 39, 58, 30, 47, + 66, 12, 55, 74, -5, 63, 83, -21, 71, 92, -36, 79, + 46, 69, 33, 48, 62, 36, 53, 49, 41, 59, 33, 48, + 67, 16, 56, 75, -1, 64, 84, -18, 72, 92, -33, 80, + 47, 71, 35, 50, 64, 38, 54, 52, 43, 60, 37, 50, + 68, 19, 57, 76, 2, 65, 84, -15, 73, 93, -30, 81, + 49, 73, 38, 51, 66, 40, 56, 55, 45, 62, 40, 51, + 69, 23, 58, 76, 6, 66, 85, -11, 74, 93, -27, 82, + 51, 76, 40, 53, 69, 43, 57, 58, 47, 63, 43, 53, + 70, 26, 60, 77, 9, 67, 86, -8, 75, 94, -23, 82, + 52, 78, 42, 55, 71, 45, 59, 60, 49, 64, 46, 54, + 71, 30, 61, 78, 13, 68, 86, -4, 76, 95, -20, 83, + 54, 79, 45, 56, 73, 47, 60, 63, 51, 65, 49, 56, + 72, 33, 62, 79, 16, 69, 87, -1, 77, 95, -17, 84, + 8, 14, -31, 20, -11, -13, 32, -28, 5, 43, -41, 20, + 54, -53, 35, 65, -63, 47, 75, -73, 58, 85, -82, 69, + 9, 15, -31, 20, -9, -12, 32, -27, 5, 43, -40, 20, + 54, -52, 35, 65, -63, 47, 75, -72, 59, 85, -81, 69, + 9, 16, -30, 20, -8, -12, 32, -26, 5, 43, -40, 21, + 54, -52, 35, 65, -62, 47, 76, -72, 59, 86, -81, 69, + 10, 18, -28, 21, -6, -11, 32, -24, 6, 43, -39, 21, + 54, -51, 35, 65, -61, 47, 76, -71, 59, 86, -81, 69, + 11, 20, -27, 21, -4, -11, 32, -23, 6, 43, -37, 21, + 55, -50, 35, 65, -61, 47, 76, -71, 59, 86, -80, 69, + 12, 22, -25, 22, -1, -10, 33, -20, 6, 44, -36, 21, + 55, -49, 35, 65, -60, 47, 76, -70, 59, 86, -79, 69, + 13, 24, -23, 22, 2, -9, 33, -18, 7, 44, -34, 22, + 55, -47, 36, 65, -58, 48, 76, -69, 59, 86, -79, 69, + 14, 27, -21, 23, 5, -7, 34, -15, 8, 44, -31, 22, + 55, -45, 36, 66, -57, 48, 76, -68, 59, 86, -78, 69, + 16, 29, -19, 24, 9, -6, 34, -12, 9, 45, -29, 23, + 55, -43, 36, 66, -55, 48, 76, -66, 59, 86, -76, 70, + 17, 32, -16, 25, 12, -4, 35, -8, 10, 45, -26, 24, + 56, -41, 37, 66, -53, 49, 76, -65, 60, 86, -75, 70, + 19, 34, -14, 26, 15, -3, 35, -5, 11, 46, -23, 24, + 56, -38, 37, 66, -51, 49, 77, -63, 60, 86, -74, 70, + 20, 36, -11, 27, 19, -1, 36, -1, 12, 46, -20, 25, + 56, -36, 38, 67, -49, 49, 77, -61, 60, 87, -72, 70, + 22, 39, -8, 28, 22, 1, 37, 3, 13, 47, -16, 26, + 57, -32, 38, 67, -46, 50, 77, -59, 61, 87, -70, 71, + 24, 41, -6, 30, 26, 3, 38, 6, 15, 47, -13, 27, + 57, -29, 39, 67, -44, 50, 77, -57, 61, 87, -68, 71, + 25, 44, -3, 31, 29, 5, 39, 10, 16, 48, -9, 28, + 58, -26, 40, 68, -41, 51, 78, -55, 61, 87, -66, 71, + 27, 46, 0, 32, 32, 7, 40, 13, 17, 49, -5, 29, + 58, -23, 41, 68, -38, 51, 78, -52, 62, 88, -64, 72, + 29, 48, 3, 34, 35, 9, 41, 17, 19, 50, -1, 30, + 59, -19, 41, 69, -35, 52, 78, -49, 62, 88, -62, 72, + 31, 50, 5, 35, 38, 11, 42, 21, 21, 50, 2, 31, + 60, -16, 42, 69, -32, 53, 79, -46, 63, 88, -59, 72, + 32, 53, 8, 36, 41, 14, 43, 24, 22, 51, 6, 32, + 60, -13, 43, 70, -29, 53, 79, -44, 64, 89, -57, 73, + 34, 55, 10, 38, 44, 16, 44, 27, 24, 52, 9, 34, + 61, -9, 44, 70, -25, 54, 80, -41, 64, 89, -54, 73, + 36, 57, 13, 39, 47, 18, 45, 31, 26, 53, 13, 35, + 62, -5, 45, 71, -22, 55, 80, -37, 65, 89, -51, 74, + 37, 59, 16, 41, 49, 20, 47, 34, 28, 54, 17, 37, + 63, -2, 46, 71, -18, 56, 81, -34, 66, 90, -48, 75, + 39, 61, 18, 42, 52, 23, 48, 37, 29, 55, 20, 38, + 63, 2, 47, 72, -15, 57, 81, -31, 66, 90, -45, 75, + 41, 63, 21, 44, 55, 25, 49, 41, 31, 56, 24, 39, + 64, 5, 49, 73, -12, 58, 82, -28, 67, 91, -42, 76, + 42, 65, 23, 45, 57, 27, 50, 43, 33, 57, 27, 41, + 65, 9, 50, 73, -8, 59, 82, -25, 68, 91, -39, 76, + 44, 68, 26, 47, 60, 29, 52, 47, 35, 58, 31, 43, + 66, 13, 51, 74, -4, 60, 83, -21, 69, 92, -36, 77, + 46, 70, 28, 49, 62, 32, 53, 50, 37, 59, 34, 44, + 67, 16, 52, 75, -1, 61, 84, -18, 69, 92, -33, 78, + 48, 72, 31, 50, 64, 34, 54, 52, 39, 60, 37, 46, + 68, 20, 54, 76, 3, 62, 84, -14, 70, 93, -30, 78, + 49, 74, 33, 52, 67, 36, 56, 55, 41, 62, 40, 47, + 69, 23, 55, 76, 6, 63, 85, -11, 71, 93, -27, 79, + 51, 76, 36, 53, 69, 38, 57, 58, 43, 63, 44, 49, + 70, 27, 56, 77, 10, 64, 86, -7, 72, 94, -23, 80, + 53, 78, 38, 55, 72, 40, 59, 61, 45, 64, 47, 51, + 71, 30, 58, 78, 13, 65, 86, -4, 73, 95, -20, 81, + 54, 80, 40, 56, 74, 43, 60, 63, 47, 65, 50, 52, + 72, 33, 59, 79, 16, 66, 87, -1, 74, 95, -16, 82, + 9, 17, -36, 20, -7, -17, 32, -25, 0, 43, -39, 16, + 54, -51, 31, 65, -62, 43, 76, -72, 55, 86, -81, 66, + 9, 18, -35, 20, -6, -17, 32, -24, 0, 43, -39, 16, + 54, -51, 31, 65, -62, 43, 76, -72, 55, 86, -81, 66, + 10, 19, -34, 21, -5, -17, 32, -24, 0, 43, -38, 16, + 54, -50, 31, 65, -61, 44, 76, -71, 55, 86, -80, 66, + 11, 21, -33, 21, -3, -16, 32, -22, 1, 43, -37, 16, + 55, -50, 31, 65, -60, 44, 76, -71, 56, 86, -80, 66, + 11, 22, -31, 21, -1, -15, 33, -20, 1, 44, -36, 17, + 55, -49, 31, 65, -60, 44, 76, -70, 56, 86, -79, 66, + 12, 24, -30, 22, 1, -15, 33, -18, 2, 44, -34, 17, + 55, -47, 31, 65, -59, 44, 76, -69, 56, 86, -79, 66, + 14, 26, -28, 23, 4, -13, 33, -16, 2, 44, -32, 17, + 55, -46, 32, 65, -57, 44, 76, -68, 56, 86, -78, 67, + 15, 29, -26, 23, 7, -12, 34, -13, 3, 44, -30, 18, + 55, -44, 32, 66, -56, 44, 76, -67, 56, 86, -77, 67, + 16, 31, -23, 24, 10, -11, 34, -10, 4, 45, -27, 19, + 56, -42, 32, 66, -54, 45, 76, -66, 56, 86, -76, 67, + 18, 33, -21, 25, 14, -9, 35, -7, 5, 45, -24, 19, + 56, -40, 33, 66, -52, 45, 76, -64, 57, 86, -75, 67, + 19, 35, -19, 26, 17, -8, 36, -3, 6, 46, -21, 20, + 56, -37, 33, 66, -50, 45, 77, -63, 57, 86, -73, 67, + 21, 38, -16, 27, 20, -6, 36, 0, 7, 46, -18, 21, + 57, -35, 34, 67, -48, 46, 77, -61, 57, 87, -72, 68, + 22, 40, -13, 29, 24, -4, 37, 4, 9, 47, -15, 22, + 57, -32, 35, 67, -46, 46, 77, -58, 58, 87, -70, 68, + 24, 42, -11, 30, 27, -2, 38, 7, 10, 47, -11, 23, + 57, -29, 35, 67, -43, 47, 77, -56, 58, 87, -68, 68, + 26, 44, -8, 31, 30, 0, 39, 11, 11, 48, -8, 23, + 58, -25, 36, 68, -40, 47, 78, -54, 58, 87, -66, 69, + 27, 47, -5, 32, 33, 2, 40, 14, 13, 49, -5, 25, + 59, -22, 37, 68, -38, 48, 78, -52, 59, 88, -64, 69, + 29, 49, -2, 34, 36, 4, 41, 18, 14, 50, -1, 26, + 59, -19, 38, 69, -34, 49, 78, -49, 59, 88, -61, 69, + 31, 51, 0, 35, 39, 7, 42, 22, 16, 50, 3, 27, + 60, -15, 39, 69, -31, 49, 79, -46, 60, 88, -59, 70, + 32, 53, 3, 37, 42, 9, 43, 25, 18, 51, 6, 28, + 60, -12, 39, 70, -28, 50, 79, -43, 61, 89, -56, 70, + 34, 55, 5, 38, 44, 11, 44, 28, 19, 52, 10, 30, + 61, -8, 40, 70, -25, 51, 80, -40, 61, 89, -54, 71, + 36, 58, 8, 40, 47, 13, 46, 32, 21, 53, 14, 31, + 62, -5, 42, 71, -21, 52, 80, -37, 62, 89, -51, 71, + 38, 60, 11, 41, 50, 16, 47, 35, 23, 54, 17, 32, + 63, -1, 43, 71, -18, 53, 81, -34, 63, 90, -48, 72, + 39, 62, 13, 43, 53, 18, 48, 38, 25, 55, 21, 34, + 63, 2, 44, 72, -14, 53, 81, -31, 63, 90, -45, 72, + 41, 64, 16, 44, 55, 20, 49, 41, 27, 56, 24, 35, + 64, 6, 45, 73, -11, 54, 82, -27, 64, 91, -42, 73, + 43, 66, 18, 46, 57, 22, 51, 44, 29, 57, 27, 37, + 65, 9, 46, 73, -8, 55, 82, -24, 65, 91, -39, 74, + 44, 68, 21, 47, 60, 25, 52, 47, 31, 58, 31, 39, + 66, 13, 47, 74, -4, 56, 83, -21, 66, 92, -36, 74, + 46, 70, 24, 49, 63, 27, 53, 50, 33, 59, 34, 40, + 67, 17, 49, 75, 0, 57, 84, -17, 66, 92, -33, 75, + 48, 72, 26, 50, 65, 29, 55, 53, 35, 61, 37, 42, + 68, 20, 50, 76, 3, 58, 84, -14, 67, 93, -29, 76, + 49, 74, 28, 52, 67, 31, 56, 56, 36, 62, 41, 43, + 69, 23, 51, 77, 6, 60, 85, -11, 68, 93, -26, 77, + 51, 76, 31, 53, 70, 34, 57, 59, 39, 63, 44, 45, + 70, 27, 53, 77, 10, 61, 86, -7, 69, 94, -23, 77, + 53, 78, 33, 55, 72, 36, 59, 61, 41, 64, 47, 47, + 71, 30, 54, 78, 13, 62, 86, -4, 70, 95, -19, 78, + 54, 80, 36, 56, 74, 38, 60, 64, 42, 65, 50, 48, + 72, 33, 56, 79, 17, 63, 87, 0, 71, 95, -16, 79, + 10, 21, -40, 21, -4, -22, 32, -23, -5, 43, -37, 12, + 54, -50, 27, 65, -61, 40, 76, -71, 52, 86, -80, 63, + 10, 22, -39, 21, -3, -22, 32, -22, -4, 43, -37, 12, + 55, -50, 27, 65, -60, 40, 76, -71, 52, 86, -80, 63, + 11, 23, -38, 21, -2, -21, 32, -21, -4, 43, -36, 12, + 55, -49, 27, 65, -60, 40, 76, -70, 52, 86, -80, 63, + 11, 24, -37, 21, 0, -21, 33, -20, -4, 44, -35, 12, + 55, -48, 27, 65, -59, 40, 76, -70, 52, 86, -79, 63, + 12, 25, -36, 22, 2, -20, 33, -18, -3, 44, -34, 12, + 55, -47, 27, 65, -59, 40, 76, -69, 52, 86, -79, 63, + 13, 27, -34, 22, 4, -19, 33, -16, -3, 44, -32, 13, + 55, -46, 27, 65, -58, 40, 76, -68, 53, 86, -78, 63, + 14, 29, -32, 23, 7, -18, 33, -14, -2, 44, -30, 13, + 55, -45, 28, 66, -56, 40, 76, -67, 53, 86, -77, 64, + 16, 31, -30, 24, 10, -17, 34, -11, -2, 45, -28, 14, + 55, -43, 28, 66, -55, 41, 76, -66, 53, 86, -76, 64, + 17, 33, -28, 25, 13, -16, 35, -8, -1, 45, -26, 14, + 56, -41, 28, 66, -53, 41, 76, -65, 53, 86, -75, 64, + 18, 35, -26, 26, 15, -14, 35, -5, 0, 45, -23, 15, + 56, -38, 29, 66, -51, 41, 76, -63, 53, 86, -74, 64, + 20, 37, -23, 27, 19, -12, 36, -2, 1, 46, -20, 15, + 56, -36, 29, 66, -49, 42, 77, -62, 54, 86, -72, 64, + 21, 39, -21, 28, 22, -11, 37, 1, 2, 46, -17, 16, + 57, -34, 30, 67, -47, 42, 77, -60, 54, 87, -71, 65, + 23, 41, -18, 29, 25, -9, 37, 5, 4, 47, -14, 17, + 57, -30, 31, 67, -45, 43, 77, -58, 54, 87, -69, 65, + 24, 43, -15, 30, 28, -7, 38, 9, 5, 48, -10, 18, + 58, -28, 31, 67, -42, 43, 77, -56, 55, 87, -67, 65, + 26, 45, -13, 31, 31, -5, 39, 12, 7, 48, -7, 19, + 58, -25, 32, 68, -40, 44, 78, -53, 55, 87, -65, 66, + 28, 48, -10, 33, 34, -3, 40, 15, 8, 49, -4, 20, + 59, -21, 33, 68, -37, 44, 78, -51, 56, 88, -63, 66, + 29, 50, -7, 34, 37, 0, 41, 19, 10, 50, 0, 21, + 59, -18, 34, 69, -33, 45, 79, -48, 56, 88, -61, 66, + 31, 52, -5, 35, 40, 2, 42, 22, 11, 51, 4, 23, + 60, -14, 35, 69, -30, 46, 79, -45, 57, 88, -58, 67, + 33, 54, -2, 37, 42, 4, 43, 26, 13, 51, 7, 24, + 61, -11, 35, 70, -27, 46, 79, -42, 57, 89, -56, 67, + 34, 56, 1, 38, 45, 6, 44, 29, 15, 52, 11, 25, + 61, -8, 36, 70, -24, 47, 80, -40, 58, 89, -53, 68, + 36, 58, 3, 40, 48, 9, 46, 33, 17, 53, 15, 27, + 62, -4, 38, 71, -21, 48, 80, -36, 59, 89, -50, 68, + 38, 60, 6, 41, 51, 11, 47, 36, 19, 54, 18, 28, + 63, 0, 39, 72, -17, 49, 81, -33, 59, 90, -47, 69, + 39, 62, 9, 43, 53, 13, 48, 39, 20, 55, 21, 30, + 64, 3, 40, 72, -14, 50, 81, -30, 60, 90, -44, 70, + 41, 64, 11, 44, 56, 15, 49, 42, 22, 56, 25, 31, + 64, 7, 41, 73, -11, 51, 82, -27, 61, 91, -42, 70, + 43, 66, 14, 46, 58, 18, 51, 45, 24, 57, 28, 33, + 65, 10, 42, 74, -7, 52, 82, -24, 62, 91, -39, 71, + 45, 69, 16, 47, 61, 20, 52, 48, 26, 58, 32, 34, + 66, 14, 44, 74, -3, 53, 83, -20, 62, 92, -35, 72, + 46, 71, 19, 49, 63, 22, 53, 51, 28, 60, 35, 36, + 67, 17, 45, 75, 0, 54, 84, -17, 63, 92, -32, 72, + 48, 72, 21, 50, 65, 25, 55, 53, 30, 61, 38, 37, + 68, 21, 46, 76, 3, 55, 84, -14, 64, 93, -29, 73, + 49, 74, 24, 52, 68, 27, 56, 56, 32, 62, 41, 39, + 69, 24, 47, 77, 7, 56, 85, -10, 65, 93, -26, 74, + 51, 77, 26, 53, 70, 29, 58, 59, 34, 63, 44, 41, + 70, 27, 49, 78, 11, 57, 86, -6, 66, 94, -22, 75, + 53, 78, 29, 55, 72, 31, 59, 62, 36, 64, 47, 43, + 71, 31, 50, 78, 14, 59, 86, -3, 67, 95, -19, 75, + 54, 80, 31, 57, 74, 34, 60, 64, 38, 65, 50, 44, + 72, 34, 52, 79, 17, 60, 87, 0, 68, 95, -16, 76, + 11, 25, -43, 21, 0, -27, 32, -20, -9, 43, -35, 7, + 55, -48, 22, 65, -59, 36, 76, -70, 49, 86, -79, 60, + 11, 25, -43, 21, 1, -26, 32, -19, -9, 44, -35, 7, + 55, -48, 22, 65, -59, 36, 76, -70, 49, 86, -79, 60, + 12, 26, -42, 22, 2, -26, 33, -18, -9, 44, -34, 7, + 55, -47, 23, 65, -59, 36, 76, -69, 49, 86, -79, 60, + 12, 27, -41, 22, 3, -25, 33, -17, -9, 44, -33, 8, + 55, -47, 23, 65, -58, 36, 76, -69, 49, 86, -78, 60, + 13, 28, -40, 22, 5, -25, 33, -15, -8, 44, -32, 8, + 55, -46, 23, 65, -57, 36, 76, -68, 49, 86, -78, 60, + 14, 29, -38, 23, 7, -24, 33, -14, -8, 44, -30, 8, + 55, -45, 23, 65, -56, 36, 76, -67, 49, 86, -77, 60, + 15, 31, -37, 23, 9, -23, 34, -11, -7, 44, -29, 9, + 55, -43, 23, 66, -55, 37, 76, -66, 49, 86, -76, 60, + 16, 33, -34, 24, 12, -21, 34, -9, -6, 45, -26, 9, + 56, -41, 24, 66, -54, 37, 76, -65, 49, 86, -75, 61, + 17, 35, -32, 25, 15, -20, 35, -6, -5, 45, -24, 10, + 56, -39, 24, 66, -52, 37, 76, -64, 50, 86, -74, 61, + 19, 36, -30, 26, 17, -19, 35, -3, -4, 46, -21, 10, + 56, -37, 25, 66, -50, 38, 77, -62, 50, 86, -73, 61, + 20, 38, -28, 27, 20, -17, 36, 0, -3, 46, -19, 11, + 56, -35, 25, 67, -48, 38, 77, -61, 50, 87, -72, 61, + 22, 40, -25, 28, 23, -15, 37, 3, -2, 46, -16, 12, + 57, -32, 26, 67, -46, 38, 77, -59, 51, 87, -70, 62, + 23, 43, -23, 29, 26, -13, 38, 7, -1, 47, -12, 13, + 57, -29, 26, 67, -44, 39, 77, -57, 51, 87, -68, 62, + 25, 45, -20, 30, 29, -11, 38, 10, 1, 48, -9, 14, + 58, -26, 27, 68, -41, 39, 78, -55, 51, 87, -66, 62, + 26, 47, -18, 32, 32, -9, 39, 13, 2, 48, -6, 15, + 58, -23, 28, 68, -39, 40, 78, -52, 52, 87, -64, 63, + 28, 49, -15, 33, 35, -7, 40, 17, 3, 49, -2, 16, + 59, -20, 29, 68, -36, 41, 78, -50, 52, 88, -62, 63, + 30, 51, -12, 34, 38, -5, 41, 20, 5, 50, 1, 17, + 59, -17, 30, 69, -33, 41, 79, -47, 53, 88, -60, 63, + 31, 53, -9, 36, 41, -3, 42, 23, 7, 51, 5, 18, + 60, -13, 30, 69, -30, 42, 79, -44, 53, 88, -58, 64, + 33, 55, -7, 37, 43, -1, 44, 27, 8, 52, 8, 20, + 61, -10, 31, 70, -27, 43, 79, -42, 54, 89, -55, 64, + 35, 57, -4, 38, 46, 1, 45, 30, 10, 52, 12, 21, + 61, -7, 32, 70, -23, 43, 80, -39, 55, 89, -53, 65, + 36, 59, -1, 40, 49, 4, 46, 33, 12, 53, 15, 22, + 62, -3, 34, 71, -20, 44, 80, -36, 55, 90, -50, 65, + 38, 61, 1, 41, 51, 6, 47, 36, 14, 54, 19, 24, + 63, 0, 35, 72, -17, 45, 81, -33, 56, 90, -47, 66, + 40, 63, 4, 43, 54, 8, 48, 39, 16, 55, 22, 25, + 64, 4, 36, 72, -13, 46, 81, -29, 57, 90, -44, 67, + 41, 65, 6, 44, 56, 11, 50, 42, 18, 56, 25, 27, + 64, 7, 37, 73, -10, 47, 82, -26, 57, 91, -41, 67, + 43, 67, 9, 46, 59, 13, 51, 45, 20, 57, 29, 28, + 65, 11, 38, 74, -7, 48, 82, -23, 58, 91, -38, 68, + 45, 69, 12, 48, 61, 15, 52, 48, 22, 59, 32, 30, + 66, 14, 40, 74, -3, 49, 83, -20, 59, 92, -35, 69, + 46, 71, 14, 49, 64, 18, 54, 51, 24, 60, 35, 32, + 67, 18, 41, 75, 1, 50, 84, -16, 60, 92, -32, 69, + 48, 73, 17, 50, 66, 20, 55, 54, 26, 61, 38, 33, + 68, 21, 42, 76, 4, 51, 84, -13, 61, 93, -28, 70, + 50, 75, 19, 52, 68, 22, 56, 56, 28, 62, 42, 35, + 69, 24, 44, 77, 7, 52, 85, -10, 62, 93, -25, 71, + 51, 77, 22, 54, 70, 25, 58, 59, 30, 63, 45, 37, + 70, 28, 45, 78, 11, 54, 86, -6, 63, 94, -22, 72, + 53, 79, 24, 55, 73, 27, 59, 62, 32, 64, 48, 38, + 71, 31, 47, 78, 14, 55, 87, -3, 64, 95, -19, 73, + 55, 81, 26, 57, 75, 29, 60, 64, 34, 66, 51, 40, + 72, 34, 48, 79, 18, 56, 87, 1, 65, 95, -15, 73, + 12, 28, -48, 22, 4, -32, 33, -16, -14, 44, -33, 2, + 55, -46, 18, 65, -58, 31, 76, -69, 45, 86, -78, 56, + 12, 29, -47, 22, 5, -31, 33, -16, -14, 44, -32, 2, + 55, -46, 18, 65, -58, 32, 76, -68, 45, 86, -78, 56, + 13, 29, -46, 22, 6, -31, 33, -15, -14, 44, -32, 2, + 55, -46, 18, 65, -57, 32, 76, -68, 45, 86, -78, 56, + 13, 30, -45, 22, 7, -30, 33, -14, -14, 44, -31, 2, + 55, -45, 18, 65, -57, 32, 76, -68, 45, 86, -77, 57, + 14, 31, -44, 23, 8, -30, 33, -12, -13, 44, -29, 3, + 55, -44, 18, 65, -56, 32, 76, -67, 45, 86, -77, 57, + 15, 32, -43, 23, 10, -29, 34, -11, -13, 44, -28, 3, + 55, -43, 18, 66, -55, 32, 76, -66, 45, 86, -76, 57, + 16, 34, -41, 24, 12, -28, 34, -9, -12, 45, -26, 3, + 55, -41, 19, 66, -54, 32, 76, -65, 45, 86, -75, 57, + 17, 35, -39, 25, 15, -27, 35, -6, -11, 45, -24, 4, + 56, -39, 19, 66, -52, 33, 76, -64, 45, 86, -74, 57, + 18, 37, -37, 26, 17, -25, 35, -4, -10, 45, -22, 5, + 56, -38, 19, 66, -51, 33, 76, -63, 46, 86, -73, 57, + 19, 38, -35, 26, 20, -24, 36, -1, -10, 46, -19, 5, + 56, -35, 20, 66, -49, 33, 77, -61, 46, 86, -72, 57, + 21, 40, -33, 27, 23, -22, 36, 2, -8, 46, -17, 6, + 57, -33, 20, 67, -47, 34, 77, -60, 46, 87, -71, 58, + 22, 42, -30, 28, 25, -21, 37, 5, -7, 47, -14, 7, + 57, -31, 21, 67, -45, 34, 77, -58, 47, 87, -69, 58, + 24, 44, -28, 30, 28, -19, 38, 9, -6, 47, -10, 8, + 57, -28, 22, 67, -42, 34, 77, -56, 47, 87, -67, 58, + 25, 46, -25, 31, 31, -17, 39, 12, -5, 48, -7, 9, + 58, -25, 22, 68, -40, 35, 78, -54, 47, 87, -66, 59, + 27, 48, -23, 32, 34, -15, 40, 15, -3, 49, -4, 10, + 58, -22, 23, 68, -37, 36, 78, -51, 48, 88, -64, 59, + 28, 50, -20, 33, 36, -13, 41, 18, -2, 49, -1, 11, + 59, -19, 24, 68, -35, 36, 78, -49, 48, 88, -62, 59, + 30, 52, -17, 35, 39, -10, 42, 22, 0, 50, 3, 12, + 60, -16, 25, 69, -31, 37, 79, -46, 49, 88, -59, 60, + 32, 54, -15, 36, 42, -8, 43, 25, 2, 51, 6, 13, + 60, -12, 26, 69, -29, 38, 79, -44, 49, 88, -57, 60, + 33, 56, -12, 37, 44, -6, 44, 28, 3, 52, 9, 15, + 61, -9, 27, 70, -26, 38, 79, -41, 50, 89, -54, 61, + 35, 58, -10, 39, 47, -4, 45, 31, 5, 53, 13, 16, + 61, -6, 28, 70, -22, 39, 80, -38, 51, 89, -52, 61, + 37, 60, -7, 40, 50, -1, 46, 34, 7, 54, 16, 17, + 62, -2, 29, 71, -19, 40, 80, -35, 51, 90, -49, 62, + 38, 62, -4, 42, 52, 1, 47, 37, 9, 55, 20, 19, + 63, 1, 30, 72, -16, 41, 81, -32, 52, 90, -46, 62, + 40, 64, -2, 43, 55, 3, 49, 40, 11, 56, 23, 20, + 64, 5, 31, 72, -12, 42, 81, -29, 53, 90, -43, 63, + 42, 66, 1, 45, 57, 5, 50, 43, 13, 57, 26, 22, + 65, 8, 32, 73, -9, 43, 82, -26, 54, 91, -40, 64, + 43, 68, 3, 46, 59, 8, 51, 46, 15, 58, 29, 23, + 65, 11, 34, 74, -6, 44, 83, -22, 54, 91, -37, 64, + 45, 70, 6, 48, 62, 10, 52, 49, 17, 59, 33, 25, + 66, 15, 35, 74, -2, 45, 83, -19, 55, 92, -34, 65, + 47, 72, 9, 49, 64, 12, 54, 52, 19, 60, 36, 27, + 67, 18, 36, 75, 1, 46, 84, -16, 56, 92, -31, 66, + 48, 73, 11, 51, 66, 15, 55, 54, 21, 61, 39, 28, + 68, 22, 38, 76, 5, 47, 84, -12, 57, 93, -28, 67, + 50, 75, 14, 52, 69, 17, 56, 57, 23, 62, 42, 30, + 69, 25, 39, 77, 8, 48, 85, -9, 58, 94, -25, 67, + 52, 77, 16, 54, 71, 20, 58, 60, 25, 63, 46, 32, + 70, 29, 41, 78, 12, 50, 86, -5, 59, 94, -21, 68, + 53, 79, 19, 55, 73, 22, 59, 63, 27, 64, 48, 34, + 71, 32, 42, 79, 15, 51, 87, -2, 60, 95, -18, 69, + 55, 81, 21, 57, 75, 24, 60, 65, 29, 66, 51, 35, + 72, 35, 44, 79, 18, 52, 87, 1, 61, 95, -15, 70, + 13, 31, -51, 22, 8, -36, 33, -13, -19, 44, -30, -2, + 55, -45, 13, 65, -56, 27, 76, -67, 41, 86, -77, 53, + 13, 32, -51, 23, 8, -36, 33, -13, -19, 44, -30, -2, + 55, -44, 13, 65, -56, 28, 76, -67, 41, 86, -77, 53, + 14, 32, -50, 23, 9, -35, 33, -12, -18, 44, -29, -2, + 55, -44, 14, 65, -56, 28, 76, -67, 41, 86, -77, 53, + 14, 33, -49, 23, 10, -35, 33, -11, -18, 44, -28, -2, + 55, -43, 14, 66, -55, 28, 76, -66, 41, 86, -76, 53, + 15, 34, -48, 23, 12, -34, 34, -10, -18, 44, -27, -2, + 55, -42, 14, 66, -54, 28, 76, -66, 41, 86, -76, 53, + 16, 35, -47, 24, 13, -33, 34, -8, -17, 45, -26, -1, + 55, -41, 14, 66, -53, 28, 76, -65, 41, 86, -75, 53, + 17, 36, -45, 25, 15, -32, 34, -6, -17, 45, -24, -1, + 56, -40, 14, 66, -52, 28, 76, -64, 41, 86, -75, 53, + 18, 37, -43, 25, 17, -31, 35, -4, -16, 45, -22, 0, + 56, -38, 15, 66, -51, 29, 76, -63, 42, 86, -73, 54, + 19, 39, -41, 26, 20, -30, 35, -1, -15, 46, -20, 0, + 56, -36, 15, 66, -49, 29, 77, -62, 42, 86, -72, 54, + 20, 40, -39, 27, 22, -28, 36, 1, -14, 46, -17, 1, + 56, -34, 16, 66, -48, 29, 77, -60, 42, 87, -71, 54, + 21, 42, -37, 28, 25, -27, 37, 4, -13, 46, -15, 2, + 57, -32, 16, 67, -46, 30, 77, -59, 42, 87, -70, 54, + 23, 44, -35, 29, 27, -25, 37, 7, -12, 47, -12, 2, + 57, -29, 17, 67, -44, 30, 77, -57, 43, 87, -68, 54, + 24, 46, -32, 30, 30, -23, 38, 10, -10, 48, -9, 3, + 58, -26, 17, 67, -41, 31, 77, -55, 43, 87, -66, 55, + 26, 47, -30, 31, 33, -21, 39, 13, -9, 48, -6, 4, + 58, -24, 18, 68, -39, 31, 78, -53, 44, 87, -65, 55, + 27, 49, -27, 32, 35, -19, 40, 16, -8, 49, -3, 5, + 59, -21, 19, 68, -36, 32, 78, -50, 44, 88, -63, 56, + 29, 51, -25, 34, 38, -17, 41, 19, -6, 49, 0, 6, + 59, -18, 20, 69, -34, 32, 78, -48, 45, 88, -61, 56, + 31, 53, -22, 35, 41, -15, 42, 23, -5, 50, 4, 8, + 60, -14, 21, 69, -30, 33, 79, -45, 45, 88, -58, 56, + 32, 55, -19, 36, 43, -13, 43, 26, -3, 51, 7, 9, + 60, -11, 22, 70, -28, 34, 79, -43, 46, 89, -56, 57, + 34, 57, -17, 38, 46, -11, 44, 29, -1, 52, 11, 10, + 61, -8, 23, 70, -25, 34, 80, -40, 46, 89, -53, 57, + 35, 59, -14, 39, 48, -9, 45, 32, 1, 53, 14, 11, + 62, -5, 24, 71, -21, 35, 80, -37, 47, 89, -51, 58, + 37, 61, -11, 41, 51, -6, 46, 35, 3, 54, 18, 13, + 62, -1, 25, 71, -18, 36, 81, -34, 48, 90, -48, 58, + 39, 63, -9, 42, 53, -4, 48, 38, 4, 55, 21, 14, + 63, 2, 26, 72, -15, 37, 81, -31, 48, 90, -45, 59, + 40, 64, -6, 43, 55, -2, 49, 41, 6, 56, 24, 16, + 64, 6, 27, 72, -12, 38, 82, -28, 49, 91, -43, 60, + 42, 66, -4, 45, 58, 1, 50, 44, 8, 57, 27, 17, + 65, 9, 28, 73, -8, 39, 82, -25, 50, 91, -40, 60, + 43, 68, -1, 46, 60, 3, 51, 47, 10, 58, 30, 19, + 66, 12, 29, 74, -5, 40, 83, -22, 51, 91, -37, 61, + 45, 70, 2, 48, 63, 6, 53, 50, 12, 59, 34, 21, + 67, 16, 31, 75, -1, 41, 83, -18, 52, 92, -33, 62, + 47, 72, 4, 49, 65, 8, 54, 52, 14, 60, 37, 22, + 67, 19, 32, 75, 2, 42, 84, -15, 53, 93, -30, 62, + 48, 74, 7, 51, 67, 10, 55, 55, 16, 61, 40, 24, + 68, 22, 34, 76, 5, 43, 85, -12, 53, 93, -27, 63, + 50, 76, 9, 52, 69, 12, 56, 58, 18, 62, 43, 26, + 69, 26, 35, 77, 9, 44, 85, -8, 54, 94, -24, 64, + 52, 78, 12, 54, 72, 15, 58, 61, 20, 63, 46, 28, + 70, 29, 37, 78, 12, 46, 86, -5, 56, 94, -21, 65, + 53, 80, 14, 55, 74, 17, 59, 63, 22, 65, 49, 29, + 71, 32, 38, 79, 16, 47, 87, -2, 57, 95, -17, 66, + 55, 82, 17, 57, 76, 20, 61, 66, 24, 66, 52, 31, + 72, 35, 39, 79, 19, 48, 87, 2, 58, 96, -14, 67, + 14, 34, -55, 23, 11, -40, 33, -10, -23, 44, -28, -7, + 55, -43, 9, 66, -55, 23, 76, -66, 37, 86, -76, 49, + 14, 35, -54, 23, 12, -40, 34, -10, -23, 44, -27, -7, + 55, -42, 9, 66, -54, 23, 76, -66, 37, 86, -76, 49, + 15, 35, -54, 23, 12, -39, 34, -9, -23, 44, -27, -7, + 55, -42, 9, 66, -54, 24, 76, -66, 37, 86, -76, 50, + 15, 36, -53, 24, 14, -39, 34, -8, -23, 44, -26, -6, + 55, -41, 9, 66, -54, 24, 76, -65, 37, 86, -75, 50, + 16, 36, -52, 24, 15, -38, 34, -7, -22, 45, -25, -6, + 55, -40, 10, 66, -53, 24, 76, -64, 37, 86, -75, 50, + 17, 37, -50, 24, 16, -37, 34, -5, -22, 45, -23, -6, + 56, -39, 10, 66, -52, 24, 76, -64, 38, 86, -74, 50, + 17, 38, -49, 25, 18, -36, 35, -3, -21, 45, -22, -5, + 56, -38, 10, 66, -51, 24, 76, -63, 38, 86, -73, 50, + 19, 40, -47, 26, 20, -35, 35, -1, -20, 45, -20, -5, + 56, -36, 10, 66, -49, 24, 77, -62, 38, 86, -72, 50, + 20, 41, -45, 27, 22, -34, 36, 1, -19, 46, -18, -4, + 56, -34, 11, 66, -48, 25, 77, -60, 38, 86, -71, 50, + 21, 42, -43, 27, 24, -33, 36, 4, -19, 46, -15, -4, + 57, -32, 11, 67, -46, 25, 77, -59, 38, 87, -70, 50, + 22, 44, -41, 28, 27, -31, 37, 6, -17, 47, -13, -3, + 57, -30, 12, 67, -44, 25, 77, -57, 39, 87, -69, 51, + 23, 45, -39, 29, 29, -29, 38, 9, -16, 47, -10, -2, + 57, -28, 12, 67, -42, 26, 77, -56, 39, 87, -67, 51, + 25, 47, -36, 30, 32, -27, 39, 12, -15, 48, -7, -1, + 58, -25, 13, 68, -40, 26, 78, -54, 39, 87, -65, 51, + 26, 49, -34, 32, 34, -26, 39, 15, -14, 48, -4, 0, + 58, -22, 14, 68, -37, 27, 78, -52, 40, 87, -64, 52, + 28, 50, -32, 33, 37, -24, 40, 18, -12, 49, -1, 1, + 59, -19, 15, 68, -35, 28, 78, -49, 40, 88, -62, 52, + 29, 52, -29, 34, 39, -22, 41, 21, -11, 50, 2, 2, + 59, -16, 15, 69, -32, 28, 78, -47, 41, 88, -60, 52, + 31, 54, -26, 35, 42, -19, 42, 24, -9, 51, 5, 3, + 60, -13, 16, 69, -29, 29, 79, -44, 41, 88, -57, 53, + 33, 56, -24, 37, 44, -17, 43, 27, -7, 51, 9, 4, + 60, -10, 17, 70, -26, 30, 79, -42, 42, 89, -55, 53, + 34, 58, -21, 38, 47, -15, 44, 30, -6, 52, 12, 6, + 61, -7, 18, 70, -23, 30, 80, -39, 43, 89, -53, 54, + 36, 60, -19, 39, 49, -13, 45, 33, -4, 53, 15, 7, + 62, -4, 19, 71, -20, 31, 80, -36, 43, 89, -50, 54, + 37, 62, -16, 41, 52, -11, 47, 36, -2, 54, 19, 9, + 63, 0, 21, 71, -17, 32, 81, -33, 44, 90, -47, 55, + 39, 63, -13, 42, 54, -8, 48, 39, 0, 55, 22, 10, + 63, 3, 22, 72, -14, 33, 81, -30, 45, 90, -45, 56, + 41, 65, -11, 44, 56, -6, 49, 42, 2, 56, 25, 12, + 64, 7, 23, 73, -11, 34, 82, -27, 45, 91, -42, 56, + 42, 67, -8, 45, 59, -4, 50, 45, 4, 57, 28, 13, + 65, 10, 24, 73, -7, 35, 82, -24, 46, 91, -39, 57, + 44, 69, -6, 47, 61, -2, 51, 48, 6, 58, 31, 15, + 66, 13, 25, 74, -4, 36, 83, -21, 47, 92, -36, 58, + 45, 71, -3, 48, 63, 1, 53, 51, 8, 59, 35, 16, + 67, 17, 27, 75, 0, 37, 83, -17, 48, 92, -33, 58, + 47, 73, 0, 50, 65, 3, 54, 53, 10, 60, 38, 18, + 68, 20, 28, 75, 3, 38, 84, -14, 49, 93, -30, 59, + 49, 75, 2, 51, 68, 6, 55, 56, 12, 61, 41, 20, + 68, 23, 29, 76, 6, 39, 85, -11, 50, 93, -27, 60, + 50, 76, 5, 53, 70, 8, 57, 58, 14, 62, 44, 21, + 69, 26, 31, 77, 9, 41, 85, -8, 51, 94, -24, 61, + 52, 79, 7, 54, 72, 10, 58, 61, 16, 64, 47, 23, + 70, 30, 32, 78, 13, 42, 86, -4, 52, 94, -20, 62, + 54, 80, 10, 56, 74, 13, 59, 64, 18, 65, 50, 25, + 71, 33, 34, 79, 16, 43, 87, -1, 53, 95, -17, 62, + 55, 82, 12, 57, 76, 15, 61, 66, 20, 66, 52, 27, + 72, 36, 35, 80, 19, 44, 88, 2, 54, 96, -14, 63, + 15, 37, -58, 24, 15, -44, 34, -7, -28, 44, -25, -11, + 55, -40, 5, 66, -53, 19, 76, -65, 33, 86, -75, 46, + 15, 38, -57, 24, 15, -44, 34, -6, -27, 45, -25, -11, + 55, -40, 5, 66, -53, 19, 76, -64, 33, 86, -75, 46, + 16, 38, -57, 24, 16, -43, 34, -6, -27, 45, -24, -11, + 55, -40, 5, 66, -52, 19, 76, -64, 33, 86, -75, 46, + 16, 38, -56, 24, 17, -43, 34, -5, -27, 45, -23, -11, + 56, -39, 5, 66, -52, 20, 76, -64, 33, 86, -74, 46, + 17, 39, -55, 25, 18, -42, 34, -4, -27, 45, -22, -10, + 56, -38, 5, 66, -51, 20, 76, -63, 34, 86, -74, 46, + 17, 40, -54, 25, 19, -41, 35, -2, -26, 45, -21, -10, + 56, -37, 6, 66, -50, 20, 76, -62, 34, 86, -73, 46, + 18, 41, -53, 26, 21, -41, 35, -1, -25, 45, -19, -10, + 56, -36, 6, 66, -49, 20, 76, -61, 34, 86, -72, 46, + 19, 42, -51, 26, 23, -39, 36, 2, -25, 46, -17, -9, + 56, -34, 6, 66, -48, 20, 77, -60, 34, 86, -71, 46, + 20, 43, -49, 27, 25, -38, 36, 4, -24, 46, -15, -9, + 56, -32, 7, 67, -46, 21, 77, -59, 34, 87, -70, 47, + 22, 44, -47, 28, 27, -37, 37, 6, -23, 46, -13, -8, + 57, -30, 7, 67, -45, 21, 77, -58, 35, 87, -69, 47, + 23, 46, -45, 29, 29, -35, 37, 9, -22, 47, -11, -7, + 57, -28, 8, 67, -43, 21, 77, -56, 35, 87, -68, 47, + 24, 47, -43, 30, 31, -34, 38, 11, -21, 47, -8, -7, + 57, -26, 8, 67, -41, 22, 77, -54, 35, 87, -66, 47, + 26, 49, -40, 31, 34, -32, 39, 14, -19, 48, -5, -6, + 58, -23, 9, 68, -38, 22, 78, -52, 36, 87, -64, 48, + 27, 50, -38, 32, 36, -30, 40, 17, -18, 49, -2, -5, + 58, -21, 10, 68, -36, 23, 78, -50, 36, 88, -63, 48, + 28, 52, -36, 33, 38, -28, 41, 20, -17, 49, 1, -4, + 59, -18, 10, 68, -34, 24, 78, -48, 36, 88, -61, 48, + 30, 54, -33, 34, 41, -26, 41, 23, -15, 50, 3, -2, + 59, -15, 11, 69, -31, 24, 79, -46, 37, 88, -59, 49, + 31, 55, -31, 36, 43, -24, 43, 26, -13, 51, 7, -1, + 60, -12, 12, 69, -28, 25, 79, -43, 38, 88, -56, 49, + 33, 57, -28, 37, 46, -22, 44, 29, -12, 52, 10, 0, + 61, -9, 13, 70, -25, 26, 79, -41, 38, 89, -54, 50, + 34, 59, -26, 38, 48, -20, 45, 32, -10, 52, 13, 1, + 61, -6, 14, 70, -22, 26, 80, -38, 39, 89, -52, 50, + 36, 61, -23, 40, 50, -18, 46, 34, -8, 53, 16, 3, + 62, -2, 15, 71, -19, 27, 80, -35, 39, 89, -49, 51, + 38, 63, -20, 41, 53, -15, 47, 38, -6, 54, 20, 4, + 63, 1, 16, 71, -16, 28, 81, -32, 40, 90, -46, 51, + 39, 64, -18, 43, 55, -13, 48, 40, -5, 55, 23, 6, + 63, 4, 17, 72, -13, 29, 81, -29, 41, 90, -44, 52, + 41, 66, -15, 44, 57, -11, 49, 43, -3, 56, 26, 7, + 64, 8, 19, 73, -10, 30, 82, -26, 42, 91, -41, 53, + 42, 68, -13, 45, 59, -8, 50, 46, -1, 57, 29, 9, + 65, 11, 20, 73, -6, 31, 82, -23, 42, 91, -38, 53, + 44, 70, -10, 47, 62, -6, 52, 48, 1, 58, 32, 10, + 66, 14, 21, 74, -3, 32, 83, -20, 43, 92, -35, 54, + 46, 72, -7, 48, 64, -4, 53, 51, 3, 59, 35, 12, + 67, 18, 23, 75, 0, 33, 84, -17, 44, 92, -32, 55, + 47, 74, -5, 50, 66, -1, 54, 54, 5, 60, 38, 14, + 68, 21, 24, 76, 4, 34, 84, -13, 45, 93, -29, 56, + 49, 75, -3, 51, 68, 1, 56, 57, 7, 61, 41, 15, + 69, 24, 25, 76, 7, 35, 85, -10, 46, 93, -26, 56, + 50, 77, 0, 53, 70, 3, 57, 59, 9, 62, 44, 17, + 70, 27, 27, 77, 10, 37, 85, -7, 47, 94, -23, 57, + 52, 79, 3, 54, 73, 6, 58, 62, 12, 64, 47, 19, + 71, 31, 28, 78, 14, 38, 86, -3, 48, 94, -19, 58, + 54, 81, 5, 56, 75, 8, 60, 64, 14, 65, 50, 21, + 72, 34, 30, 79, 17, 39, 87, 0, 49, 95, -16, 59, + 55, 83, 8, 57, 77, 11, 61, 67, 16, 66, 53, 23, + 73, 37, 31, 80, 20, 40, 88, 3, 50, 96, -13, 60, + 16, 40, -62, 24, 19, -48, 34, -3, -32, 45, -22, -16, + 56, -38, 0, 66, -51, 15, 76, -63, 29, 86, -74, 42, + 17, 41, -61, 25, 19, -48, 34, -3, -32, 45, -21, -16, + 56, -37, 0, 66, -51, 15, 76, -63, 29, 86, -73, 42, + 17, 41, -61, 25, 20, -48, 35, -2, -32, 45, -21, -16, + 56, -37, 0, 66, -50, 15, 76, -62, 29, 86, -73, 42, + 17, 41, -60, 25, 21, -47, 35, -1, -32, 45, -20, -16, + 56, -36, 0, 66, -50, 15, 76, -62, 29, 86, -73, 42, + 18, 42, -59, 25, 21, -47, 35, 0, -31, 45, -19, -15, + 56, -36, 1, 66, -49, 15, 76, -61, 29, 86, -72, 42, + 19, 43, -58, 26, 23, -46, 35, 1, -31, 45, -18, -15, + 56, -35, 1, 66, -48, 15, 77, -61, 29, 86, -72, 42, + 19, 43, -57, 26, 24, -45, 36, 3, -30, 46, -17, -15, + 56, -33, 1, 66, -47, 15, 77, -60, 29, 86, -71, 42, + 20, 44, -55, 27, 26, -44, 36, 5, -29, 46, -15, -14, + 56, -32, 1, 67, -46, 16, 77, -59, 30, 87, -70, 42, + 21, 45, -53, 28, 28, -43, 37, 7, -29, 46, -13, -14, + 57, -30, 2, 67, -44, 16, 77, -57, 30, 87, -69, 43, + 22, 47, -51, 29, 29, -41, 37, 9, -28, 47, -11, -13, + 57, -28, 2, 67, -43, 16, 77, -56, 30, 87, -68, 43, + 24, 48, -50, 29, 31, -40, 38, 11, -27, 47, -8, -12, + 57, -26, 3, 67, -41, 17, 77, -55, 30, 87, -66, 43, + 25, 49, -47, 30, 33, -38, 38, 14, -26, 48, -6, -11, + 58, -24, 3, 67, -39, 17, 78, -53, 31, 87, -65, 43, + 26, 51, -45, 31, 36, -37, 39, 16, -24, 48, -3, -10, + 58, -21, 4, 68, -37, 18, 78, -51, 31, 87, -63, 44, + 28, 52, -43, 33, 38, -35, 40, 19, -23, 49, 0, -9, + 59, -19, 5, 68, -34, 18, 78, -49, 32, 88, -61, 44, + 29, 54, -41, 34, 40, -33, 41, 22, -22, 50, 2, -8, + 59, -16, 6, 69, -32, 19, 78, -47, 32, 88, -60, 44, + 30, 55, -38, 35, 42, -31, 42, 24, -20, 50, 5, -7, + 60, -13, 6, 69, -29, 20, 79, -44, 33, 88, -58, 45, + 32, 57, -35, 36, 45, -29, 43, 28, -18, 51, 9, -6, + 60, -10, 7, 69, -27, 20, 79, -42, 33, 88, -55, 45, + 33, 58, -33, 37, 47, -27, 44, 30, -17, 52, 12, -5, + 61, -7, 8, 70, -24, 21, 80, -39, 34, 89, -53, 46, + 35, 60, -31, 39, 49, -25, 45, 33, -15, 53, 15, -4, + 61, -4, 9, 70, -21, 22, 80, -37, 34, 89, -51, 46, + 36, 62, -28, 40, 52, -22, 46, 36, -13, 53, 18, -2, + 62, -1, 10, 71, -18, 23, 80, -34, 35, 90, -48, 47, + 38, 64, -25, 42, 54, -20, 47, 39, -11, 54, 21, -1, + 63, 3, 12, 72, -15, 24, 81, -31, 36, 90, -45, 47, + 40, 65, -23, 43, 56, -18, 48, 42, -10, 55, 24, 1, + 64, 6, 13, 72, -12, 24, 81, -28, 37, 90, -43, 48, + 41, 67, -20, 44, 58, -16, 49, 44, -8, 56, 27, 2, + 64, 9, 14, 73, -8, 25, 82, -25, 37, 91, -40, 49, + 43, 69, -18, 46, 60, -13, 51, 47, -6, 57, 30, 4, + 65, 12, 15, 74, -5, 26, 82, -22, 38, 91, -37, 49, + 44, 71, -15, 47, 63, -11, 52, 50, -4, 58, 33, 5, + 66, 15, 16, 74, -2, 27, 83, -19, 39, 92, -34, 50, + 46, 73, -13, 49, 65, -9, 53, 52, -2, 59, 37, 7, + 67, 19, 18, 75, 1, 29, 84, -16, 40, 92, -31, 51, + 48, 74, -10, 50, 67, -6, 55, 55, 0, 61, 39, 9, + 68, 22, 19, 76, 5, 30, 84, -12, 41, 93, -28, 51, + 49, 76, -8, 52, 69, -4, 56, 57, 2, 62, 42, 11, + 69, 25, 21, 76, 8, 31, 85, -9, 42, 93, -25, 52, + 51, 78, -5, 53, 71, -2, 57, 60, 4, 63, 45, 12, + 70, 28, 22, 77, 11, 32, 86, -6, 43, 94, -22, 53, + 52, 80, -2, 55, 74, 1, 59, 63, 7, 64, 48, 14, + 71, 31, 24, 78, 15, 33, 86, -3, 44, 95, -19, 54, + 54, 82, 0, 56, 76, 3, 60, 65, 9, 65, 51, 16, + 72, 35, 25, 79, 18, 35, 87, 1, 45, 95, -15, 55, + 56, 83, 3, 58, 78, 5, 61, 67, 11, 66, 54, 18, + 73, 38, 27, 80, 21, 36, 88, 4, 46, 96, -12, 56, + 17, 43, -65, 25, 22, -52, 35, 0, -37, 45, -19, -20, + 56, -35, -4, 66, -49, 11, 76, -61, 25, 86, -72, 38, + 18, 43, -64, 25, 23, -52, 35, 1, -36, 45, -19, -20, + 56, -35, -4, 66, -49, 11, 76, -61, 25, 86, -72, 38, + 18, 44, -64, 25, 23, -52, 35, 1, -36, 45, -18, -20, + 56, -35, -4, 66, -48, 11, 76, -61, 25, 86, -72, 38, + 18, 44, -63, 26, 24, -51, 35, 2, -36, 45, -17, -20, + 56, -34, -4, 66, -48, 11, 76, -60, 25, 86, -71, 38, + 19, 44, -62, 26, 25, -51, 35, 3, -35, 46, -16, -20, + 56, -33, -4, 66, -47, 11, 77, -60, 25, 86, -71, 38, + 19, 45, -61, 26, 26, -50, 36, 4, -35, 46, -15, -19, + 56, -32, -3, 66, -46, 11, 77, -59, 25, 86, -70, 38, + 20, 46, -60, 27, 27, -49, 36, 6, -34, 46, -14, -19, + 56, -31, -3, 67, -45, 11, 77, -58, 25, 87, -70, 38, + 21, 47, -59, 28, 29, -48, 37, 7, -34, 46, -12, -18, + 57, -29, -3, 67, -44, 12, 77, -57, 26, 87, -69, 39, + 22, 47, -57, 28, 30, -47, 37, 9, -33, 47, -10, -18, + 57, -28, -2, 67, -43, 12, 77, -56, 26, 87, -68, 39, + 23, 49, -55, 29, 32, -45, 38, 11, -32, 47, -8, -17, + 57, -26, -2, 67, -41, 12, 77, -55, 26, 87, -66, 39, + 24, 50, -53, 30, 34, -44, 38, 14, -31, 48, -6, -16, + 58, -24, -1, 67, -39, 13, 77, -53, 27, 87, -65, 39, + 25, 51, -51, 31, 36, -42, 39, 16, -30, 48, -4, -16, + 58, -22, -1, 68, -37, 13, 78, -51, 27, 87, -64, 40, + 27, 52, -49, 32, 38, -41, 40, 19, -29, 49, -1, -15, + 58, -19, 0, 68, -35, 14, 78, -49, 27, 88, -62, 40, + 28, 54, -47, 33, 40, -39, 40, 21, -27, 49, 2, -14, + 59, -17, 1, 68, -33, 14, 78, -47, 28, 88, -60, 40, + 30, 55, -45, 34, 42, -37, 41, 24, -26, 50, 4, -13, + 59, -14, 1, 69, -31, 15, 79, -45, 28, 88, -58, 41, + 31, 57, -42, 35, 44, -35, 42, 26, -24, 50, 7, -12, + 60, -12, 2, 69, -28, 15, 79, -43, 29, 88, -56, 41, + 32, 58, -40, 37, 46, -33, 43, 29, -23, 51, 10, -10, + 60, -8, 3, 70, -25, 16, 79, -41, 29, 89, -54, 41, + 34, 60, -37, 38, 49, -31, 44, 32, -21, 52, 13, -9, + 61, -6, 4, 70, -22, 17, 80, -38, 30, 89, -52, 42, + 35, 61, -35, 39, 51, -29, 45, 35, -19, 53, 16, -8, + 62, -3, 5, 71, -20, 18, 80, -36, 30, 89, -50, 42, + 37, 63, -32, 40, 53, -27, 46, 37, -18, 54, 19, -7, + 62, 0, 6, 71, -17, 18, 80, -33, 31, 90, -47, 43, + 39, 65, -30, 42, 55, -24, 47, 40, -16, 55, 22, -5, + 63, 4, 7, 72, -13, 19, 81, -30, 32, 90, -44, 44, + 40, 66, -27, 43, 57, -22, 49, 43, -14, 56, 25, -4, + 64, 7, 8, 72, -10, 20, 81, -27, 33, 90, -42, 44, + 42, 68, -25, 45, 59, -20, 50, 45, -12, 57, 28, -2, + 65, 10, 10, 73, -7, 21, 82, -24, 33, 91, -39, 45, + 43, 70, -22, 46, 61, -18, 51, 48, -10, 57, 31, -1, + 65, 13, 11, 74, -4, 22, 83, -21, 34, 91, -36, 46, + 45, 71, -20, 47, 64, -15, 52, 51, -8, 58, 34, 1, + 66, 16, 12, 74, -1, 23, 83, -18, 35, 92, -33, 46, + 46, 73, -17, 49, 66, -13, 54, 53, -6, 60, 38, 3, + 67, 20, 14, 75, 2, 25, 84, -15, 36, 92, -30, 47, + 48, 75, -14, 50, 68, -11, 55, 56, -4, 61, 40, 5, + 68, 23, 15, 76, 6, 26, 84, -12, 37, 93, -27, 48, + 49, 77, -12, 52, 70, -8, 56, 58, -2, 62, 43, 6, + 69, 26, 16, 77, 9, 27, 85, -8, 38, 93, -24, 49, + 51, 79, -10, 53, 72, -6, 57, 61, 0, 63, 46, 8, + 70, 29, 18, 77, 12, 28, 86, -5, 39, 94, -21, 49, + 53, 81, -7, 55, 74, -4, 59, 63, 2, 64, 49, 10, + 71, 32, 19, 78, 15, 29, 86, -2, 40, 95, -18, 50, + 54, 82, -4, 56, 76, -1, 60, 66, 4, 65, 52, 12, + 72, 35, 21, 79, 19, 31, 87, 1, 41, 95, -15, 51, + 56, 84, -2, 58, 78, 1, 61, 68, 6, 66, 55, 13, + 73, 38, 22, 80, 22, 32, 88, 4, 42, 96, -12, 52, + 19, 46, -68, 26, 25, -56, 35, 3, -41, 45, -16, -25, + 56, -33, -8, 66, -47, 6, 77, -60, 21, 86, -71, 34, + 19, 46, -68, 26, 26, -56, 35, 4, -40, 46, -16, -24, + 56, -33, -8, 66, -47, 6, 77, -59, 21, 86, -71, 34, + 19, 46, -67, 26, 26, -55, 35, 4, -40, 46, -15, -24, + 56, -32, -8, 66, -46, 7, 77, -59, 21, 86, -70, 34, + 19, 46, -67, 26, 27, -55, 36, 5, -40, 46, -14, -24, + 56, -32, -8, 66, -46, 7, 77, -59, 21, 86, -70, 34, + 20, 47, -66, 27, 28, -54, 36, 6, -40, 46, -14, -24, + 56, -31, -8, 66, -45, 7, 77, -58, 21, 86, -70, 34, + 20, 47, -65, 27, 29, -54, 36, 7, -39, 46, -13, -24, + 57, -30, -8, 67, -44, 7, 77, -57, 21, 87, -69, 34, + 21, 48, -64, 28, 30, -53, 37, 9, -39, 46, -11, -23, + 57, -29, -7, 67, -43, 7, 77, -57, 22, 87, -68, 35, + 22, 49, -62, 28, 31, -52, 37, 10, -38, 47, -10, -23, + 57, -27, -7, 67, -42, 7, 77, -56, 22, 87, -67, 35, + 23, 50, -60, 29, 33, -51, 37, 12, -37, 47, -8, -22, + 57, -26, -7, 67, -41, 8, 77, -54, 22, 87, -66, 35, + 24, 51, -59, 30, 34, -49, 38, 14, -36, 47, -6, -21, + 57, -24, -6, 67, -39, 8, 77, -53, 22, 87, -65, 35, + 25, 52, -57, 31, 36, -48, 39, 16, -35, 48, -4, -21, + 58, -22, -6, 68, -37, 9, 78, -52, 23, 87, -64, 35, + 26, 53, -55, 31, 38, -46, 39, 18, -34, 48, -2, -20, + 58, -20, -5, 68, -36, 9, 78, -50, 23, 87, -62, 36, + 28, 54, -53, 33, 40, -45, 40, 21, -33, 49, 1, -19, + 59, -17, -4, 68, -33, 10, 78, -48, 23, 88, -61, 36, + 29, 55, -51, 34, 42, -43, 41, 23, -31, 49, 4, -18, + 59, -15, -4, 69, -31, 10, 78, -46, 24, 88, -59, 36, + 30, 57, -49, 35, 44, -41, 42, 26, -30, 50, 6, -17, + 60, -12, -3, 69, -29, 11, 79, -44, 24, 88, -57, 37, + 31, 58, -46, 36, 46, -39, 43, 28, -29, 51, 9, -16, + 60, -10, -2, 69, -26, 11, 79, -42, 25, 88, -55, 37, + 33, 60, -44, 37, 48, -37, 44, 31, -27, 52, 12, -15, + 61, -7, -1, 70, -24, 12, 79, -39, 25, 89, -53, 38, + 34, 61, -41, 38, 50, -35, 45, 34, -25, 52, 15, -13, + 61, -4, 0, 70, -21, 13, 80, -37, 26, 89, -51, 38, + 36, 63, -39, 40, 52, -33, 46, 36, -24, 53, 18, -12, + 62, -1, 1, 71, -18, 14, 80, -34, 27, 89, -48, 39, + 37, 64, -37, 41, 54, -31, 47, 39, -22, 54, 21, -11, + 63, 2, 2, 71, -15, 14, 81, -32, 27, 90, -46, 39, + 39, 66, -34, 42, 56, -29, 48, 42, -20, 55, 24, -9, + 63, 5, 3, 72, -12, 15, 81, -29, 28, 90, -43, 40, + 40, 67, -31, 44, 58, -26, 49, 44, -18, 56, 27, -8, + 64, 8, 4, 73, -9, 16, 82, -26, 29, 91, -41, 40, + 42, 69, -29, 45, 60, -24, 50, 47, -16, 57, 30, -6, + 65, 11, 5, 73, -6, 17, 82, -23, 29, 91, -38, 41, + 43, 71, -27, 46, 63, -22, 51, 49, -15, 58, 33, -5, + 66, 14, 7, 74, -3, 18, 83, -20, 30, 91, -35, 42, + 45, 72, -24, 48, 65, -20, 52, 52, -13, 59, 35, -3, + 66, 17, 8, 74, 0, 19, 83, -17, 31, 92, -32, 42, + 47, 74, -21, 49, 67, -17, 54, 54, -10, 60, 39, -1, + 67, 21, 9, 75, 3, 20, 84, -14, 32, 92, -29, 43, + 48, 76, -19, 51, 69, -15, 55, 57, -8, 61, 41, 0, + 68, 24, 11, 76, 7, 22, 85, -11, 33, 93, -26, 44, + 50, 78, -16, 52, 71, -13, 56, 59, -6, 62, 44, 2, + 69, 27, 12, 77, 10, 23, 85, -8, 34, 94, -23, 45, + 51, 79, -14, 54, 73, -10, 58, 62, -4, 63, 47, 4, + 70, 30, 14, 78, 13, 24, 86, -4, 35, 94, -20, 46, + 53, 81, -11, 55, 75, -8, 59, 64, -2, 64, 50, 6, + 71, 33, 15, 78, 16, 25, 87, -1, 36, 95, -17, 47, + 54, 83, -9, 57, 77, -6, 60, 67, 0, 65, 53, 7, + 72, 36, 17, 79, 19, 27, 87, 2, 37, 95, -14, 48, + 56, 85, -6, 58, 79, -3, 62, 69, 2, 67, 55, 9, + 73, 39, 18, 80, 22, 28, 88, 5, 38, 96, -11, 48, + 20, 48, -71, 27, 29, -60, 36, 7, -45, 46, -13, -29, + 56, -30, -13, 66, -45, 2, 77, -58, 17, 86, -69, 30, + 20, 48, -71, 27, 29, -59, 36, 7, -44, 46, -13, -29, + 56, -30, -13, 66, -45, 2, 77, -58, 17, 86, -69, 30, + 20, 49, -70, 27, 29, -59, 36, 8, -44, 46, -12, -29, + 56, -30, -12, 66, -44, 2, 77, -57, 17, 87, -69, 30, + 20, 49, -70, 27, 30, -59, 36, 8, -44, 46, -12, -28, + 57, -29, -12, 67, -44, 3, 77, -57, 17, 87, -68, 30, + 21, 49, -69, 27, 31, -58, 36, 9, -44, 46, -11, -28, + 57, -28, -12, 67, -43, 3, 77, -56, 17, 87, -68, 31, + 21, 50, -68, 28, 32, -57, 37, 10, -43, 46, -10, -28, + 57, -27, -12, 67, -42, 3, 77, -56, 17, 87, -67, 31, + 22, 50, -67, 28, 33, -57, 37, 11, -43, 47, -8, -27, + 57, -26, -12, 67, -41, 3, 77, -55, 18, 87, -67, 31, + 23, 51, -65, 29, 34, -55, 37, 13, -42, 47, -7, -27, + 57, -25, -11, 67, -40, 3, 77, -54, 18, 87, -66, 31, + 24, 52, -64, 30, 35, -54, 38, 15, -41, 47, -5, -26, + 57, -23, -11, 67, -39, 4, 77, -53, 18, 87, -65, 31, + 25, 53, -62, 30, 37, -53, 38, 17, -40, 48, -3, -26, + 58, -22, -10, 68, -37, 4, 78, -51, 18, 87, -64, 31, + 26, 54, -61, 31, 38, -52, 39, 19, -39, 48, -1, -25, + 58, -20, -10, 68, -36, 4, 78, -50, 19, 87, -62, 32, + 27, 55, -59, 32, 40, -50, 40, 21, -38, 49, 1, -24, + 58, -18, -9, 68, -34, 5, 78, -48, 19, 88, -61, 32, + 28, 56, -57, 33, 42, -49, 40, 23, -37, 49, 3, -23, + 59, -15, -9, 68, -32, 5, 78, -46, 19, 88, -59, 32, + 29, 57, -55, 34, 44, -47, 41, 25, -36, 50, 6, -22, + 59, -13, -8, 69, -29, 6, 79, -45, 20, 88, -58, 33, + 31, 58, -52, 35, 46, -45, 42, 28, -34, 50, 8, -21, + 60, -11, -7, 69, -27, 7, 79, -42, 20, 88, -56, 33, + 32, 60, -50, 36, 47, -43, 43, 30, -33, 51, 11, -20, + 60, -8, -6, 70, -25, 7, 79, -40, 21, 89, -54, 33, + 34, 61, -48, 38, 50, -41, 44, 33, -31, 52, 14, -19, + 61, -5, -5, 70, -22, 8, 80, -38, 21, 89, -52, 34, + 35, 62, -45, 39, 52, -39, 45, 35, -30, 53, 17, -18, + 61, -2, -4, 70, -19, 9, 80, -35, 22, 89, -49, 34, + 36, 64, -43, 40, 54, -37, 46, 38, -28, 53, 19, -16, + 62, 0, -3, 71, -17, 9, 80, -33, 23, 89, -47, 35, + 38, 65, -41, 41, 55, -35, 47, 40, -26, 54, 22, -15, + 63, 3, -2, 72, -14, 10, 81, -30, 23, 90, -45, 35, + 39, 67, -38, 43, 58, -33, 48, 43, -24, 55, 25, -14, + 64, 7, -1, 72, -11, 11, 81, -27, 24, 90, -42, 36, + 41, 69, -36, 44, 60, -31, 49, 45, -23, 56, 28, -12, + 64, 10, 0, 73, -8, 12, 82, -25, 25, 91, -39, 37, + 42, 70, -33, 45, 62, -29, 50, 48, -21, 57, 31, -11, + 65, 13, 1, 73, -5, 13, 82, -22, 26, 91, -37, 37, + 44, 72, -31, 47, 64, -26, 52, 50, -19, 58, 34, -9, + 66, 16, 2, 74, -2, 14, 83, -19, 26, 92, -34, 38, + 45, 73, -28, 48, 66, -24, 53, 53, -17, 59, 37, -7, + 67, 19, 4, 75, 1, 15, 83, -16, 27, 92, -31, 39, + 47, 75, -26, 50, 68, -22, 54, 55, -15, 60, 40, -6, + 68, 22, 5, 75, 5, 16, 84, -13, 28, 93, -28, 40, + 49, 77, -23, 51, 70, -19, 55, 58, -13, 61, 42, -4, + 68, 25, 7, 76, 8, 18, 85, -10, 29, 93, -25, 40, + 50, 78, -21, 52, 72, -17, 57, 60, -11, 62, 45, -2, + 69, 28, 8, 77, 11, 19, 85, -7, 30, 94, -22, 41, + 52, 80, -18, 54, 74, -15, 58, 63, -9, 63, 48, -1, + 70, 31, 9, 78, 14, 20, 86, -4, 31, 94, -19, 42, + 53, 82, -15, 55, 76, -12, 59, 65, -6, 65, 51, 1, + 71, 34, 11, 79, 17, 21, 87, 0, 32, 95, -16, 43, + 55, 84, -13, 57, 78, -10, 60, 67, -4, 66, 54, 3, + 72, 37, 13, 79, 20, 22, 87, 3, 33, 95, -13, 44, + 56, 85, -11, 58, 80, -8, 62, 70, -2, 67, 56, 5, + 73, 40, 14, 80, 23, 24, 88, 6, 34, 96, -10, 45, + 21, 51, -74, 27, 32, -64, 36, 11, -49, 46, -10, -33, + 57, -27, -17, 67, -42, -2, 77, -56, 12, 87, -67, 26, + 21, 51, -74, 28, 33, -63, 36, 11, -49, 46, -9, -33, + 57, -27, -17, 67, -42, -2, 77, -56, 12, 87, -67, 26, + 21, 51, -74, 28, 33, -63, 37, 11, -49, 46, -9, -33, + 57, -27, -17, 67, -42, -2, 77, -55, 13, 87, -67, 26, + 22, 52, -73, 28, 33, -63, 37, 12, -48, 47, -8, -33, + 57, -26, -17, 67, -41, -2, 77, -55, 13, 87, -67, 26, + 22, 52, -72, 28, 34, -62, 37, 13, -48, 47, -7, -33, + 57, -26, -17, 67, -41, -2, 77, -54, 13, 87, -66, 26, + 23, 52, -72, 29, 35, -61, 37, 14, -48, 47, -6, -32, + 57, -25, -17, 67, -40, -2, 77, -54, 13, 87, -66, 26, + 23, 53, -71, 29, 36, -61, 38, 15, -47, 47, -5, -32, + 57, -24, -16, 67, -39, -2, 77, -53, 13, 87, -65, 26, + 24, 53, -69, 30, 37, -60, 38, 16, -46, 47, -4, -31, + 57, -22, -16, 67, -38, -1, 77, -52, 13, 87, -64, 27, + 25, 54, -68, 30, 38, -59, 39, 18, -46, 48, -2, -31, + 58, -21, -16, 68, -36, -1, 78, -51, 13, 87, -63, 27, + 26, 55, -66, 31, 40, -57, 39, 20, -45, 48, 0, -30, + 58, -19, -15, 68, -35, -1, 78, -49, 14, 87, -62, 27, + 27, 56, -65, 32, 41, -56, 40, 21, -44, 49, 1, -30, + 58, -17, -15, 68, -33, 0, 78, -48, 14, 88, -61, 27, + 28, 57, -63, 33, 43, -55, 40, 23, -43, 49, 3, -29, + 59, -15, -14, 68, -32, 0, 78, -46, 14, 88, -59, 28, + 29, 58, -61, 34, 44, -53, 41, 26, -41, 50, 6, -28, + 59, -13, -13, 69, -29, 1, 78, -45, 15, 88, -58, 28, + 30, 59, -59, 35, 46, -51, 42, 28, -40, 50, 8, -27, + 60, -11, -13, 69, -27, 1, 79, -43, 15, 88, -56, 28, + 31, 60, -57, 36, 48, -50, 43, 30, -39, 51, 11, -26, + 60, -8, -12, 69, -25, 2, 79, -41, 16, 88, -54, 29, + 33, 61, -55, 37, 49, -48, 43, 32, -37, 51, 13, -25, + 61, -6, -11, 70, -23, 3, 79, -39, 16, 89, -52, 29, + 34, 63, -52, 38, 52, -46, 44, 35, -36, 52, 16, -24, + 61, -3, -10, 70, -20, 3, 80, -36, 17, 89, -50, 30, + 36, 64, -50, 39, 53, -44, 45, 37, -34, 53, 19, -22, + 62, 0, -9, 71, -18, 4, 80, -34, 17, 89, -48, 30, + 37, 65, -48, 41, 55, -42, 46, 40, -33, 54, 21, -21, + 62, 2, -8, 71, -15, 5, 81, -31, 18, 90, -46, 31, + 38, 67, -45, 42, 57, -40, 47, 42, -31, 55, 24, -20, + 63, 5, -7, 72, -12, 6, 81, -29, 19, 90, -43, 31, + 40, 68, -43, 43, 59, -37, 49, 45, -29, 56, 27, -18, + 64, 8, -6, 72, -9, 7, 81, -26, 20, 90, -41, 32, + 41, 70, -40, 44, 61, -35, 50, 47, -27, 56, 30, -17, + 64, 11, -5, 73, -6, 8, 82, -23, 20, 91, -38, 32, + 43, 71, -38, 46, 63, -33, 51, 49, -25, 57, 33, -15, + 65, 14, -4, 74, -3, 9, 82, -20, 21, 91, -36, 33, + 44, 73, -35, 47, 65, -31, 52, 52, -24, 58, 35, -14, + 66, 17, -2, 74, 0, 10, 83, -18, 22, 92, -33, 34, + 46, 75, -33, 48, 67, -29, 53, 54, -22, 59, 38, -12, + 67, 20, -1, 75, 3, 11, 84, -15, 23, 92, -30, 34, + 47, 76, -30, 50, 69, -26, 54, 57, -20, 60, 41, -10, + 68, 23, 0, 76, 6, 12, 84, -11, 24, 93, -27, 35, + 49, 78, -28, 51, 71, -24, 56, 59, -18, 61, 44, -9, + 69, 26, 2, 76, 9, 13, 85, -8, 25, 93, -24, 36, + 50, 79, -25, 53, 73, -22, 57, 61, -16, 62, 46, -7, + 70, 29, 3, 77, 12, 14, 85, -5, 26, 94, -21, 37, + 52, 81, -23, 54, 75, -20, 58, 64, -14, 64, 49, -5, + 70, 32, 5, 78, 15, 15, 86, -2, 27, 94, -18, 38, + 54, 83, -20, 56, 77, -17, 59, 66, -11, 65, 52, -3, + 71, 35, 6, 79, 18, 17, 87, 1, 28, 95, -15, 39, + 55, 85, -18, 57, 79, -15, 61, 68, -9, 66, 55, -2, + 72, 38, 8, 80, 21, 18, 88, 4, 29, 96, -12, 39, + 57, 86, -15, 59, 80, -12, 62, 71, -7, 67, 57, 0, + 73, 41, 9, 80, 24, 19, 88, 7, 30, 96, -9, 40, + 22, 53, -77, 28, 35, -67, 37, 14, -53, 47, -7, -37, + 57, -25, -21, 67, -40, -6, 77, -54, 8, 87, -66, 22, + 22, 54, -77, 28, 36, -67, 37, 14, -53, 47, -6, -37, + 57, -24, -21, 67, -40, -6, 77, -54, 8, 87, -66, 22, + 22, 54, -77, 29, 36, -67, 37, 15, -53, 47, -6, -37, + 57, -24, -21, 67, -39, -6, 77, -53, 9, 87, -65, 22, + 23, 54, -76, 29, 37, -66, 37, 15, -52, 47, -5, -37, + 57, -24, -21, 67, -39, -6, 77, -53, 9, 87, -65, 22, + 23, 54, -76, 29, 37, -66, 38, 16, -52, 47, -4, -37, + 57, -23, -21, 67, -38, -6, 77, -52, 9, 87, -65, 22, + 24, 55, -75, 29, 38, -65, 38, 17, -51, 47, -4, -36, + 57, -22, -21, 67, -38, -6, 77, -52, 9, 87, -64, 22, + 24, 55, -74, 30, 39, -64, 38, 18, -51, 47, -2, -36, + 58, -21, -20, 67, -37, -6, 77, -51, 9, 87, -63, 23, + 25, 56, -72, 31, 40, -63, 39, 19, -50, 48, -1, -35, + 58, -20, -20, 68, -36, -5, 78, -50, 9, 87, -62, 23, + 26, 56, -71, 31, 41, -62, 39, 21, -49, 48, 1, -35, + 58, -18, -20, 68, -34, -5, 78, -49, 9, 87, -61, 23, + 27, 57, -70, 32, 42, -61, 40, 22, -49, 49, 2, -34, + 58, -17, -19, 68, -33, -5, 78, -48, 10, 87, -60, 23, + 28, 58, -68, 33, 43, -60, 40, 24, -48, 49, 4, -34, + 59, -15, -19, 68, -31, -4, 78, -46, 10, 88, -59, 23, + 29, 59, -66, 33, 45, -58, 41, 26, -47, 49, 6, -33, + 59, -13, -18, 68, -30, -4, 78, -45, 10, 88, -58, 24, + 30, 60, -64, 34, 46, -57, 41, 28, -45, 50, 8, -32, + 59, -11, -17, 69, -27, -3, 79, -43, 11, 88, -56, 24, + 31, 61, -62, 35, 48, -55, 42, 30, -44, 51, 10, -31, + 60, -9, -17, 69, -25, -3, 79, -41, 11, 88, -55, 24, + 32, 62, -60, 36, 50, -53, 43, 32, -43, 51, 13, -30, + 60, -6, -16, 70, -23, -2, 79, -39, 12, 89, -53, 25, + 33, 63, -58, 37, 51, -52, 44, 34, -41, 52, 15, -29, + 61, -4, -15, 70, -21, -2, 80, -37, 12, 89, -51, 25, + 35, 64, -56, 39, 53, -50, 45, 37, -40, 53, 18, -28, + 61, -1, -14, 70, -18, -1, 80, -35, 13, 89, -49, 26, + 36, 65, -54, 40, 55, -48, 46, 39, -38, 53, 20, -27, + 62, 1, -13, 71, -16, 0, 80, -32, 13, 89, -47, 26, + 38, 67, -51, 41, 57, -46, 47, 41, -37, 54, 23, -25, + 63, 4, -12, 71, -13, 1, 81, -30, 14, 90, -44, 27, + 39, 68, -49, 42, 59, -44, 48, 44, -35, 55, 26, -24, + 63, 7, -11, 72, -11, 2, 81, -27, 15, 90, -42, 27, + 40, 70, -47, 44, 61, -42, 49, 46, -33, 56, 29, -22, + 64, 10, -10, 73, -8, 3, 82, -24, 16, 91, -39, 28, + 42, 71, -44, 45, 62, -39, 50, 48, -31, 57, 31, -21, + 65, 13, -9, 73, -5, 3, 82, -22, 16, 91, -37, 28, + 43, 73, -42, 46, 64, -37, 51, 51, -30, 58, 34, -19, + 65, 16, -8, 74, -2, 4, 83, -19, 17, 91, -34, 29, + 45, 74, -39, 47, 66, -35, 52, 53, -28, 59, 37, -18, + 66, 18, -6, 74, 1, 5, 83, -16, 18, 92, -32, 30, + 46, 76, -37, 49, 68, -33, 53, 55, -26, 60, 39, -16, + 67, 21, -5, 75, 4, 6, 84, -13, 19, 92, -29, 31, + 48, 77, -34, 50, 70, -30, 55, 58, -24, 61, 42, -15, + 68, 25, -4, 76, 7, 8, 84, -10, 20, 93, -26, 31, + 49, 79, -32, 52, 72, -28, 56, 60, -22, 62, 45, -13, + 69, 27, -2, 77, 10, 9, 85, -7, 21, 93, -23, 32, + 51, 80, -30, 53, 74, -26, 57, 62, -20, 63, 48, -11, + 70, 30, -1, 77, 13, 10, 86, -4, 22, 94, -20, 33, + 52, 82, -27, 54, 76, -24, 58, 65, -18, 64, 50, -10, + 71, 33, 1, 78, 16, 11, 86, -1, 23, 94, -17, 34, + 54, 84, -24, 56, 78, -21, 60, 67, -15, 65, 53, -8, + 72, 36, 2, 79, 19, 13, 87, 2, 24, 95, -14, 35, + 55, 85, -22, 57, 79, -19, 61, 69, -13, 66, 56, -6, + 73, 39, 4, 80, 22, 14, 88, 5, 25, 96, -11, 36, + 57, 87, -20, 59, 81, -17, 62, 71, -11, 67, 58, -4, + 74, 42, 5, 81, 25, 15, 88, 8, 26, 96, -8, 37, + 23, 56, -80, 29, 39, -70, 38, 17, -57, 47, -3, -41, + 57, -22, -26, 67, -38, -10, 77, -52, 4, 87, -64, 18, + 23, 56, -80, 29, 39, -70, 38, 17, -57, 47, -3, -41, + 57, -22, -25, 67, -37, -10, 77, -52, 4, 87, -64, 18, + 23, 56, -80, 29, 39, -70, 38, 18, -56, 47, -3, -41, + 57, -21, -25, 67, -37, -10, 77, -51, 5, 87, -64, 18, + 24, 56, -79, 30, 39, -70, 38, 18, -56, 47, -2, -41, + 57, -21, -25, 67, -37, -10, 77, -51, 5, 87, -63, 18, + 24, 56, -79, 30, 40, -69, 38, 19, -56, 47, -1, -41, + 58, -20, -25, 67, -36, -10, 77, -50, 5, 87, -63, 18, + 25, 57, -78, 30, 41, -68, 38, 20, -55, 48, -1, -40, + 58, -19, -25, 67, -35, -10, 78, -50, 5, 87, -62, 19, + 25, 57, -77, 31, 41, -68, 39, 21, -55, 48, 0, -40, + 58, -18, -24, 68, -34, -10, 78, -49, 5, 87, -62, 19, + 26, 58, -76, 31, 42, -67, 39, 22, -54, 48, 2, -40, + 58, -17, -24, 68, -33, -9, 78, -48, 5, 87, -61, 19, + 27, 58, -74, 32, 43, -66, 40, 24, -53, 49, 3, -39, + 58, -16, -24, 68, -32, -9, 78, -47, 5, 87, -60, 19, + 28, 59, -73, 33, 45, -65, 40, 25, -52, 49, 5, -38, + 59, -14, -23, 68, -31, -9, 78, -46, 6, 88, -59, 19, + 28, 60, -71, 33, 46, -63, 41, 27, -52, 49, 7, -38, + 59, -13, -23, 68, -29, -8, 78, -44, 6, 88, -57, 20, + 29, 60, -70, 34, 47, -62, 41, 28, -51, 50, 8, -37, + 59, -11, -22, 69, -27, -8, 79, -43, 6, 88, -56, 20, + 31, 61, -68, 35, 49, -60, 42, 30, -49, 50, 11, -36, + 60, -9, -21, 69, -25, -7, 79, -41, 7, 88, -55, 20, + 32, 62, -66, 36, 50, -59, 43, 32, -48, 51, 13, -35, + 60, -6, -21, 69, -23, -7, 79, -39, 7, 88, -53, 21, + 33, 63, -64, 37, 52, -57, 43, 34, -47, 52, 15, -34, + 61, -4, -20, 70, -21, -6, 79, -37, 8, 89, -51, 21, + 34, 65, -62, 38, 53, -56, 44, 36, -45, 52, 17, -33, + 61, -2, -19, 70, -19, -6, 80, -35, 8, 89, -49, 21, + 35, 66, -60, 39, 55, -54, 45, 39, -44, 53, 20, -32, + 62, 1, -18, 71, -17, -5, 80, -33, 9, 89, -47, 22, + 37, 67, -57, 40, 57, -52, 46, 41, -42, 54, 22, -31, + 62, 3, -17, 71, -14, -4, 80, -31, 9, 90, -45, 22, + 38, 68, -55, 41, 58, -50, 47, 43, -41, 54, 25, -29, + 63, 6, -16, 72, -12, -3, 81, -28, 10, 90, -43, 23, + 39, 70, -53, 43, 60, -48, 48, 45, -39, 55, 27, -28, + 64, 9, -15, 72, -9, -2, 81, -26, 11, 90, -41, 23, + 41, 71, -50, 44, 62, -45, 49, 48, -37, 56, 30, -27, + 64, 12, -14, 73, -6, -2, 82, -23, 12, 91, -38, 24, + 42, 72, -48, 45, 64, -43, 50, 50, -35, 57, 33, -25, + 65, 14, -13, 73, -3, -1, 82, -20, 12, 91, -36, 25, + 44, 74, -46, 47, 66, -41, 51, 52, -34, 58, 35, -24, + 66, 17, -12, 74, -1, 0, 83, -18, 13, 92, -33, 25, + 45, 75, -44, 48, 67, -39, 53, 54, -32, 59, 38, -22, + 66, 20, -11, 75, 2, 1, 83, -15, 14, 92, -30, 26, + 47, 77, -41, 49, 69, -37, 54, 57, -30, 60, 41, -21, + 67, 23, -9, 75, 5, 2, 84, -12, 15, 92, -28, 27, + 48, 78, -38, 51, 71, -35, 55, 59, -28, 61, 44, -19, + 68, 26, -8, 76, 8, 4, 85, -9, 16, 93, -25, 28, + 50, 80, -36, 52, 73, -32, 56, 61, -26, 62, 46, -17, + 69, 29, -6, 77, 11, 5, 85, -6, 17, 94, -22, 28, + 51, 81, -34, 53, 75, -30, 57, 63, -24, 63, 49, -15, + 70, 31, -5, 77, 14, 6, 86, -3, 18, 94, -19, 29, + 53, 83, -31, 55, 77, -28, 59, 66, -22, 64, 51, -14, + 71, 34, -4, 78, 17, 7, 86, 0, 19, 95, -16, 30, + 54, 85, -29, 56, 79, -25, 60, 68, -20, 65, 54, -12, + 72, 37, -2, 79, 20, 9, 87, 3, 20, 95, -13, 31, + 56, 86, -26, 58, 80, -23, 61, 70, -18, 66, 57, -10, + 73, 40, 0, 80, 23, 10, 88, 6, 21, 96, -10, 32, + 57, 88, -24, 59, 82, -21, 63, 72, -16, 68, 59, -8, + 74, 43, 1, 81, 26, 11, 89, 9, 22, 96, -7, 33, + 24, 58, -83, 30, 41, -74, 38, 20, -60, 47, 0, -45, + 58, -19, -30, 67, -35, -15, 77, -50, 0, 87, -62, 14, + 24, 58, -83, 30, 42, -74, 38, 21, -60, 48, 0, -45, + 58, -19, -29, 67, -35, -14, 77, -49, 0, 87, -62, 14, + 25, 58, -83, 30, 42, -73, 38, 21, -60, 48, 0, -45, + 58, -19, -29, 67, -35, -14, 78, -49, 1, 87, -62, 14, + 25, 58, -82, 30, 42, -73, 39, 22, -60, 48, 1, -45, + 58, -18, -29, 68, -34, -14, 78, -49, 1, 87, -61, 14, + 25, 59, -82, 31, 43, -72, 39, 22, -59, 48, 2, -45, + 58, -17, -29, 68, -34, -14, 78, -48, 1, 87, -61, 15, + 26, 59, -81, 31, 43, -72, 39, 23, -59, 48, 2, -44, + 58, -17, -29, 68, -33, -14, 78, -48, 1, 87, -60, 15, + 26, 59, -80, 32, 44, -71, 39, 24, -58, 48, 3, -44, + 58, -16, -29, 68, -32, -14, 78, -47, 1, 87, -60, 15, + 27, 60, -79, 32, 45, -70, 40, 25, -58, 49, 5, -43, + 58, -14, -28, 68, -31, -13, 78, -46, 1, 88, -59, 15, + 28, 60, -78, 33, 46, -69, 40, 26, -57, 49, 6, -43, + 59, -13, -28, 68, -30, -13, 78, -45, 2, 88, -58, 15, + 28, 61, -76, 33, 47, -68, 41, 28, -56, 49, 8, -42, + 59, -12, -27, 68, -28, -13, 78, -44, 2, 88, -57, 15, + 29, 62, -75, 34, 48, -67, 41, 29, -55, 50, 9, -42, + 59, -10, -27, 69, -27, -12, 79, -42, 2, 88, -56, 16, + 30, 62, -73, 35, 49, -66, 42, 31, -54, 50, 11, -41, + 60, -8, -26, 69, -25, -12, 79, -41, 2, 88, -54, 16, + 31, 63, -71, 36, 51, -64, 42, 33, -53, 51, 13, -40, + 60, -6, -26, 69, -23, -11, 79, -39, 3, 88, -53, 16, + 32, 64, -69, 37, 52, -63, 43, 35, -52, 51, 15, -39, + 60, -4, -25, 70, -21, -11, 79, -37, 3, 89, -51, 17, + 34, 65, -68, 38, 54, -61, 44, 36, -51, 52, 17, -38, + 61, -2, -24, 70, -19, -10, 80, -36, 4, 89, -50, 17, + 35, 66, -66, 39, 55, -59, 45, 38, -49, 53, 19, -37, + 61, 0, -23, 70, -17, -10, 80, -34, 4, 89, -48, 17, + 36, 67, -63, 40, 57, -57, 46, 41, -48, 53, 22, -36, + 62, 3, -22, 71, -15, -9, 80, -31, 5, 89, -46, 18, + 37, 69, -61, 41, 58, -55, 47, 43, -46, 54, 24, -35, + 63, 5, -21, 71, -12, -8, 81, -29, 5, 90, -44, 18, + 39, 70, -59, 42, 60, -54, 48, 45, -45, 55, 27, -33, + 63, 8, -20, 72, -10, -7, 81, -27, 6, 90, -41, 19, + 40, 71, -57, 43, 62, -52, 49, 47, -43, 56, 29, -32, + 64, 10, -19, 72, -7, -7, 81, -24, 7, 90, -39, 19, + 41, 72, -54, 45, 63, -49, 50, 49, -41, 56, 32, -31, + 65, 13, -18, 73, -4, -6, 82, -21, 8, 91, -37, 20, + 43, 74, -52, 46, 65, -47, 51, 51, -39, 57, 34, -29, + 65, 16, -17, 74, -2, -5, 82, -19, 8, 91, -34, 21, + 44, 75, -50, 47, 67, -45, 52, 54, -38, 58, 37, -28, + 66, 19, -16, 74, 1, -4, 83, -16, 9, 92, -32, 21, + 46, 76, -47, 48, 69, -43, 53, 56, -36, 59, 40, -26, + 67, 21, -15, 75, 4, -3, 83, -14, 10, 92, -29, 22, + 47, 78, -45, 50, 70, -41, 54, 58, -34, 60, 42, -25, + 68, 24, -13, 75, 7, -2, 84, -11, 11, 93, -27, 23, + 49, 79, -42, 51, 72, -39, 55, 60, -32, 61, 45, -23, + 68, 27, -12, 76, 10, 0, 85, -8, 12, 93, -24, 24, + 50, 81, -40, 52, 74, -36, 57, 62, -30, 62, 47, -21, + 69, 30, -11, 77, 13, 1, 85, -5, 13, 94, -21, 24, + 52, 82, -38, 54, 76, -34, 58, 65, -28, 63, 50, -20, + 70, 33, -9, 78, 15, 2, 86, -2, 14, 94, -18, 25, + 53, 84, -35, 55, 78, -32, 59, 67, -26, 64, 52, -18, + 71, 35, -8, 78, 18, 3, 87, 1, 15, 95, -15, 26, + 55, 86, -33, 57, 80, -30, 60, 69, -24, 66, 55, -16, + 72, 39, -6, 79, 22, 4, 87, 4, 16, 95, -12, 27, + 56, 87, -30, 58, 81, -27, 62, 71, -22, 67, 58, -14, + 73, 41, -5, 80, 25, 6, 88, 7, 17, 96, -9, 28, + 57, 89, -28, 59, 83, -25, 63, 73, -20, 68, 60, -12, + 74, 44, -3, 81, 27, 7, 89, 10, 18, 97, -6, 29, + 25, 60, -86, 31, 44, -77, 39, 24, -64, 48, 3, -49, + 58, -16, -34, 68, -33, -19, 78, -47, -4, 87, -60, 10, + 26, 60, -86, 31, 45, -77, 39, 24, -64, 48, 3, -49, + 58, -16, -33, 68, -32, -18, 78, -47, -4, 87, -60, 10, + 26, 61, -86, 31, 45, -77, 39, 24, -64, 48, 4, -49, + 58, -16, -33, 68, -32, -18, 78, -47, -3, 87, -60, 10, + 26, 61, -85, 31, 45, -76, 39, 25, -63, 48, 4, -49, + 58, -15, -33, 68, -32, -18, 78, -47, -3, 87, -60, 11, + 26, 61, -85, 32, 46, -76, 39, 25, -63, 48, 5, -49, + 58, -15, -33, 68, -31, -18, 78, -46, -3, 87, -59, 11, + 27, 61, -84, 32, 46, -75, 40, 26, -63, 49, 5, -48, + 58, -14, -33, 68, -30, -18, 78, -46, -3, 87, -59, 11, + 27, 62, -83, 32, 47, -75, 40, 27, -62, 49, 6, -48, + 59, -13, -33, 68, -30, -18, 78, -45, -3, 88, -58, 11, + 28, 62, -82, 33, 48, -74, 40, 28, -61, 49, 8, -47, + 59, -12, -32, 68, -29, -17, 78, -44, -3, 88, -57, 11, + 29, 62, -81, 33, 48, -73, 41, 29, -61, 49, 9, -47, + 59, -11, -32, 68, -27, -17, 78, -43, -2, 88, -56, 11, + 29, 63, -79, 34, 49, -72, 41, 30, -60, 50, 10, -46, + 59, -9, -31, 69, -26, -17, 79, -42, -2, 88, -55, 11, + 30, 64, -78, 35, 50, -70, 42, 32, -59, 50, 12, -46, + 60, -8, -31, 69, -25, -16, 79, -40, -2, 88, -54, 12, + 31, 64, -76, 36, 52, -69, 42, 33, -58, 51, 14, -45, + 60, -6, -30, 69, -23, -16, 79, -39, -2, 88, -53, 12, + 32, 65, -75, 36, 53, -68, 43, 35, -57, 51, 16, -44, + 60, -4, -30, 70, -21, -15, 79, -37, -1, 89, -51, 12, + 33, 66, -73, 37, 54, -66, 44, 37, -56, 52, 18, -43, + 61, -2, -29, 70, -19, -15, 79, -35, -1, 89, -50, 13, + 34, 67, -71, 38, 56, -65, 44, 39, -55, 52, 20, -42, + 61, 0, -28, 70, -17, -14, 80, -34, 0, 89, -48, 13, + 35, 68, -69, 39, 57, -63, 45, 41, -53, 53, 22, -41, + 62, 2, -27, 71, -15, -14, 80, -32, 0, 89, -46, 14, + 37, 69, -67, 40, 59, -61, 46, 43, -52, 54, 24, -40, + 62, 5, -26, 71, -13, -13, 80, -29, 1, 90, -44, 14, + 38, 70, -65, 41, 60, -59, 47, 45, -50, 54, 26, -39, + 63, 7, -25, 72, -10, -12, 81, -27, 2, 90, -42, 15, + 39, 71, -63, 43, 62, -57, 48, 47, -49, 55, 29, -37, + 63, 10, -24, 72, -8, -11, 81, -25, 2, 90, -40, 15, + 41, 72, -61, 44, 63, -55, 49, 49, -47, 56, 31, -36, + 64, 12, -23, 73, -6, -11, 82, -23, 3, 91, -38, 16, + 42, 74, -58, 45, 65, -53, 50, 51, -45, 57, 34, -35, + 65, 15, -22, 73, -3, -10, 82, -20, 4, 91, -35, 16, + 43, 75, -56, 46, 67, -51, 51, 53, -43, 58, 36, -33, + 66, 18, -21, 74, 0, -9, 83, -17, 4, 91, -33, 17, + 45, 76, -54, 47, 68, -49, 52, 55, -42, 59, 39, -32, + 66, 20, -20, 74, 3, -8, 83, -15, 5, 92, -30, 18, + 46, 78, -51, 49, 70, -47, 53, 57, -40, 60, 41, -30, + 67, 23, -19, 75, 5, -7, 84, -12, 6, 92, -28, 18, + 47, 79, -49, 50, 72, -45, 54, 59, -38, 60, 43, -29, + 68, 26, -17, 76, 8, -6, 84, -9, 7, 93, -25, 19, + 49, 81, -46, 51, 74, -43, 56, 62, -36, 62, 46, -27, + 69, 29, -16, 76, 11, -4, 85, -6, 8, 93, -22, 20, + 50, 82, -44, 53, 75, -40, 57, 64, -34, 63, 49, -25, + 70, 31, -15, 77, 14, -3, 85, -3, 9, 94, -20, 21, + 52, 83, -42, 54, 77, -38, 58, 66, -32, 64, 51, -24, + 70, 34, -13, 78, 17, -2, 86, -1, 10, 94, -17, 21, + 53, 85, -39, 55, 79, -36, 59, 68, -30, 65, 54, -22, + 71, 37, -12, 79, 20, -1, 87, 2, 11, 95, -14, 22, + 55, 87, -37, 57, 81, -34, 61, 70, -28, 66, 56, -20, + 72, 40, -10, 80, 23, 0, 87, 5, 12, 96, -11, 23, + 56, 88, -34, 58, 82, -31, 62, 72, -26, 67, 59, -18, + 73, 42, -9, 80, 26, 2, 88, 8, 13, 96, -8, 24, + 58, 90, -32, 60, 84, -29, 63, 74, -24, 68, 61, -16, + 74, 45, -7, 81, 29, 3, 89, 11, 14, 97, -5, 25, + 27, 63, -89, 32, 48, -81, 40, 27, -68, 48, 7, -54, + 58, -13, -38, 68, -30, -23, 78, -45, -8, 87, -58, 6, + 27, 63, -89, 32, 48, -81, 40, 27, -68, 49, 7, -53, + 58, -13, -38, 68, -29, -23, 78, -45, -8, 87, -58, 6, + 27, 63, -89, 32, 48, -80, 40, 28, -68, 49, 7, -53, + 58, -12, -38, 68, -29, -23, 78, -44, -8, 88, -58, 6, + 27, 63, -88, 32, 48, -80, 40, 28, -67, 49, 8, -53, + 58, -12, -38, 68, -29, -23, 78, -44, -8, 88, -57, 6, + 28, 63, -88, 33, 49, -79, 40, 29, -67, 49, 8, -53, + 59, -11, -37, 68, -28, -23, 78, -44, -8, 88, -57, 6, + 28, 64, -87, 33, 49, -79, 40, 29, -67, 49, 9, -53, + 59, -11, -37, 68, -28, -22, 78, -43, -8, 88, -56, 6, + 28, 64, -86, 33, 50, -78, 41, 30, -66, 49, 10, -52, + 59, -10, -37, 68, -27, -22, 78, -42, -7, 88, -56, 6, + 29, 64, -85, 34, 50, -77, 41, 31, -66, 50, 11, -52, + 59, -9, -37, 69, -26, -22, 78, -41, -7, 88, -55, 7, + 30, 65, -84, 34, 51, -76, 41, 32, -65, 50, 12, -51, + 59, -8, -36, 69, -25, -22, 79, -40, -7, 88, -54, 7, + 30, 65, -83, 35, 52, -75, 42, 33, -64, 50, 13, -51, + 60, -6, -36, 69, -23, -21, 79, -39, -7, 88, -53, 7, + 31, 66, -82, 36, 53, -74, 42, 35, -63, 51, 15, -50, + 60, -5, -35, 69, -22, -21, 79, -38, -6, 88, -52, 7, + 32, 66, -80, 36, 54, -73, 43, 36, -62, 51, 16, -49, + 60, -3, -35, 70, -21, -20, 79, -37, -6, 89, -51, 8, + 33, 67, -78, 37, 55, -72, 44, 38, -61, 52, 18, -48, + 61, -1, -34, 70, -19, -20, 79, -35, -6, 89, -49, 8, + 34, 68, -77, 38, 57, -70, 44, 40, -60, 52, 20, -47, + 61, 1, -33, 70, -17, -19, 80, -33, -5, 89, -48, 8, + 35, 69, -75, 39, 58, -69, 45, 41, -59, 53, 22, -46, + 62, 3, -33, 71, -15, -19, 80, -31, -5, 89, -46, 9, + 36, 70, -73, 40, 59, -67, 46, 43, -57, 53, 24, -45, + 62, 5, -32, 71, -13, -18, 80, -30, -4, 89, -44, 9, + 38, 71, -71, 41, 61, -65, 47, 45, -56, 54, 27, -44, + 63, 7, -31, 71, -11, -17, 81, -27, -4, 90, -42, 10, + 39, 72, -69, 42, 62, -63, 48, 47, -54, 55, 29, -43, + 63, 9, -30, 72, -8, -17, 81, -25, -3, 90, -40, 10, + 40, 73, -67, 43, 64, -62, 49, 49, -53, 56, 31, -42, + 64, 12, -29, 72, -6, -16, 81, -23, -2, 90, -38, 11, + 41, 74, -65, 44, 65, -60, 50, 51, -51, 56, 33, -41, + 64, 14, -28, 73, -4, -15, 82, -21, -2, 91, -36, 11, + 43, 75, -62, 46, 67, -58, 51, 53, -50, 57, 36, -39, + 65, 17, -27, 73, -1, -14, 82, -18, -1, 91, -33, 12, + 44, 77, -60, 47, 68, -56, 52, 55, -48, 58, 38, -38, + 66, 20, -26, 74, 2, -13, 83, -16, 0, 92, -31, 12, + 45, 78, -58, 48, 70, -54, 53, 57, -46, 59, 40, -36, + 67, 22, -24, 75, 4, -12, 83, -13, 1, 92, -29, 13, + 47, 79, -56, 49, 71, -51, 54, 59, -44, 60, 43, -35, + 67, 25, -23, 75, 7, -11, 84, -10, 2, 92, -26, 14, + 48, 80, -53, 51, 73, -49, 55, 61, -42, 61, 45, -33, + 68, 27, -22, 76, 10, -10, 84, -8, 2, 93, -24, 15, + 50, 82, -51, 52, 75, -47, 56, 63, -40, 62, 48, -31, + 69, 30, -20, 77, 13, -9, 85, -5, 3, 93, -21, 15, + 51, 83, -49, 53, 77, -45, 57, 65, -39, 63, 50, -30, + 70, 33, -19, 77, 16, -8, 86, -2, 4, 94, -18, 16, + 52, 85, -46, 55, 78, -43, 58, 67, -37, 64, 53, -28, + 71, 36, -18, 78, 18, -7, 86, 1, 5, 95, -15, 17, + 54, 86, -44, 56, 80, -41, 60, 69, -35, 65, 55, -26, + 72, 38, -16, 79, 21, -5, 87, 4, 6, 95, -13, 18, + 55, 88, -41, 57, 82, -38, 61, 71, -32, 66, 58, -25, + 73, 41, -15, 80, 24, -4, 88, 7, 7, 96, -9, 19, + 57, 89, -39, 59, 83, -36, 62, 73, -30, 67, 60, -23, + 74, 44, -13, 81, 27, -3, 88, 10, 9, 96, -7, 20, + 58, 91, -37, 60, 85, -34, 64, 75, -28, 68, 62, -21, + 75, 46, -12, 81, 30, -2, 89, 13, 10, 97, -4, 21, + 28, 65, -92, 33, 50, -84, 40, 30, -72, 49, 10, -57, + 59, -10, -42, 68, -27, -27, 78, -43, -12, 88, -56, 2, + 28, 65, -92, 33, 51, -84, 40, 31, -71, 49, 10, -57, + 59, -10, -42, 68, -27, -27, 78, -42, -12, 88, -56, 2, + 28, 65, -92, 33, 51, -83, 40, 31, -71, 49, 10, -57, + 59, -10, -42, 68, -27, -27, 78, -42, -12, 88, -56, 2, + 28, 65, -91, 33, 51, -83, 41, 31, -71, 49, 11, -57, + 59, -9, -42, 68, -26, -27, 78, -42, -12, 88, -55, 2, + 29, 66, -91, 33, 51, -83, 41, 32, -71, 49, 11, -57, + 59, -9, -41, 68, -26, -27, 78, -41, -12, 88, -55, 2, + 29, 66, -90, 34, 52, -82, 41, 32, -70, 50, 12, -56, + 59, -8, -41, 69, -25, -26, 78, -41, -11, 88, -54, 2, + 29, 66, -89, 34, 52, -82, 41, 33, -70, 50, 13, -56, + 59, -7, -41, 69, -24, -26, 79, -40, -11, 88, -54, 3, + 30, 66, -88, 35, 53, -81, 42, 34, -69, 50, 14, -55, + 59, -6, -40, 69, -23, -26, 79, -39, -11, 88, -53, 3, + 31, 67, -87, 35, 54, -80, 42, 35, -68, 50, 15, -55, + 60, -5, -40, 69, -22, -26, 79, -38, -11, 88, -52, 3, + 31, 67, -86, 36, 55, -79, 42, 36, -68, 51, 16, -54, + 60, -4, -40, 69, -21, -25, 79, -37, -11, 88, -51, 3, + 32, 68, -85, 36, 55, -78, 43, 37, -67, 51, 18, -54, + 60, -2, -39, 70, -20, -25, 79, -36, -10, 89, -50, 3, + 33, 68, -83, 37, 56, -77, 44, 39, -66, 52, 19, -53, + 61, -1, -39, 70, -18, -24, 79, -34, -10, 89, -49, 4, + 34, 69, -82, 38, 58, -75, 44, 40, -65, 52, 21, -52, + 61, 1, -38, 70, -16, -24, 80, -33, -9, 89, -47, 4, + 35, 70, -80, 39, 59, -74, 45, 42, -64, 53, 23, -51, + 61, 3, -37, 70, -15, -23, 80, -31, -9, 89, -46, 4, + 36, 71, -78, 40, 60, -72, 46, 43, -62, 53, 25, -50, + 62, 5, -37, 71, -13, -23, 80, -29, -9, 89, -44, 5, + 37, 71, -76, 41, 61, -71, 46, 45, -61, 54, 26, -49, + 62, 7, -36, 71, -11, -22, 81, -28, -8, 90, -42, 5, + 38, 72, -74, 42, 63, -69, 47, 47, -60, 55, 29, -48, + 63, 9, -35, 72, -8, -21, 81, -25, -7, 90, -40, 6, + 39, 73, -72, 43, 64, -67, 48, 49, -58, 55, 31, -47, + 64, 12, -34, 72, -6, -21, 81, -23, -7, 90, -38, 6, + 41, 74, -70, 44, 65, -65, 49, 51, -57, 56, 33, -46, + 64, 14, -33, 73, -4, -20, 82, -21, -6, 91, -36, 7, + 42, 75, -68, 45, 67, -63, 50, 52, -55, 57, 35, -44, + 65, 16, -32, 73, -2, -19, 82, -19, -6, 91, -34, 7, + 43, 77, -66, 46, 68, -61, 51, 55, -53, 58, 38, -43, + 65, 19, -31, 74, 1, -18, 83, -16, -5, 91, -32, 8, + 45, 78, -64, 47, 70, -59, 52, 57, -52, 58, 40, -42, + 66, 21, -30, 74, 4, -17, 83, -14, -4, 92, -30, 9, + 46, 79, -62, 49, 71, -57, 53, 58, -50, 59, 42, -40, + 67, 24, -28, 75, 6, -16, 84, -11, -3, 92, -27, 9, + 47, 80, -59, 50, 73, -55, 54, 60, -48, 60, 44, -39, + 68, 26, -27, 76, 9, -15, 84, -9, -2, 93, -25, 10, + 49, 82, -57, 51, 74, -53, 55, 62, -46, 61, 47, -37, + 68, 29, -26, 76, 11, -14, 85, -6, -2, 93, -22, 11, + 50, 83, -55, 52, 76, -51, 57, 65, -44, 62, 49, -35, + 69, 32, -24, 77, 14, -13, 85, -3, -1, 94, -19, 12, + 51, 84, -52, 54, 78, -49, 58, 67, -42, 63, 52, -34, + 70, 34, -23, 78, 17, -12, 86, -1, 0, 94, -17, 12, + 53, 86, -50, 55, 79, -47, 59, 68, -41, 64, 54, -32, + 71, 37, -22, 78, 20, -11, 86, 2, 1, 95, -14, 13, + 54, 87, -48, 56, 81, -44, 60, 70, -39, 65, 56, -30, + 72, 40, -20, 79, 22, -9, 87, 5, 2, 95, -11, 14, + 56, 89, -45, 58, 83, -42, 61, 73, -36, 66, 59, -29, + 73, 42, -19, 80, 26, -8, 88, 8, 4, 96, -8, 15, + 57, 90, -43, 59, 84, -40, 63, 75, -34, 68, 61, -27, + 74, 45, -17, 81, 28, -7, 89, 11, 5, 96, -5, 16, + 59, 92, -41, 60, 86, -38, 64, 77, -32, 69, 63, -25, + 75, 48, -16, 82, 31, -5, 89, 14, 6, 97, -3, 17, + 29, 67, -95, 34, 53, -87, 41, 34, -75, 49, 13, -61, + 59, -7, -46, 69, -24, -31, 78, -40, -16, 88, -54, -2, + 29, 67, -95, 34, 53, -87, 41, 34, -75, 50, 13, -61, + 59, -7, -46, 69, -24, -31, 78, -40, -16, 88, -54, -2, + 29, 67, -94, 34, 53, -87, 41, 34, -75, 50, 13, -61, + 59, -7, -46, 69, -24, -31, 78, -40, -16, 88, -54, -2, + 29, 67, -94, 34, 54, -86, 41, 34, -74, 50, 14, -61, + 59, -6, -45, 69, -23, -31, 79, -39, -16, 88, -53, -2, + 30, 68, -94, 34, 54, -86, 41, 35, -74, 50, 14, -60, + 59, -6, -45, 69, -23, -30, 79, -39, -16, 88, -53, -2, + 30, 68, -93, 35, 54, -85, 42, 35, -74, 50, 15, -60, + 59, -5, -45, 69, -22, -30, 79, -38, -15, 88, -52, -1, + 30, 68, -92, 35, 55, -85, 42, 36, -73, 50, 16, -60, + 60, -4, -45, 69, -22, -30, 79, -38, -15, 88, -52, -1, + 31, 68, -91, 35, 56, -84, 42, 37, -73, 51, 17, -59, + 60, -3, -44, 69, -21, -30, 79, -37, -15, 88, -51, -1, + 32, 69, -90, 36, 56, -83, 43, 38, -72, 51, 18, -59, + 60, -2, -44, 69, -20, -29, 79, -36, -15, 88, -50, -1, + 32, 69, -89, 37, 57, -82, 43, 39, -71, 51, 19, -58, + 60, -1, -44, 70, -18, -29, 79, -35, -15, 89, -49, -1, + 33, 70, -88, 37, 58, -81, 44, 40, -70, 52, 20, -57, + 61, 0, -43, 70, -17, -29, 79, -34, -14, 89, -48, 0, + 34, 70, -86, 38, 59, -80, 44, 41, -69, 52, 22, -57, + 61, 2, -42, 70, -16, -28, 80, -32, -14, 89, -47, 0, + 35, 71, -85, 39, 60, -78, 45, 43, -68, 53, 24, -56, + 61, 4, -42, 70, -14, -28, 80, -31, -13, 89, -45, 0, + 36, 72, -83, 39, 61, -77, 45, 44, -67, 53, 25, -55, + 62, 6, -41, 71, -12, -27, 80, -29, -13, 89, -44, 1, + 37, 72, -81, 40, 62, -76, 46, 46, -66, 54, 27, -54, + 62, 7, -40, 71, -11, -27, 80, -27, -13, 90, -42, 1, + 38, 73, -80, 41, 63, -74, 47, 47, -65, 54, 29, -53, + 63, 9, -40, 72, -9, -26, 81, -26, -12, 90, -41, 1, + 39, 74, -78, 42, 64, -72, 48, 49, -63, 55, 31, -52, + 63, 12, -39, 72, -6, -25, 81, -23, -11, 90, -39, 2, + 40, 75, -76, 43, 66, -71, 49, 51, -62, 56, 33, -51, + 64, 14, -38, 72, -4, -25, 82, -21, -11, 90, -37, 2, + 41, 76, -74, 44, 67, -69, 50, 53, -60, 56, 35, -50, + 64, 16, -37, 73, -2, -24, 82, -19, -10, 91, -35, 3, + 43, 77, -72, 45, 68, -67, 50, 54, -59, 57, 37, -48, + 65, 18, -36, 73, 0, -23, 82, -17, -10, 91, -33, 3, + 44, 78, -70, 47, 70, -65, 52, 56, -57, 58, 39, -47, + 66, 21, -35, 74, 3, -22, 83, -15, -9, 92, -30, 4, + 45, 79, -67, 48, 71, -63, 53, 58, -55, 59, 42, -45, + 66, 23, -34, 75, 5, -21, 83, -12, -8, 92, -28, 5, + 46, 80, -65, 49, 73, -61, 54, 60, -54, 60, 44, -44, + 67, 26, -32, 75, 8, -20, 84, -10, -7, 92, -26, 5, + 48, 82, -63, 50, 74, -59, 55, 62, -52, 61, 46, -43, + 68, 28, -31, 76, 10, -19, 84, -7, -6, 93, -23, 6, + 49, 83, -61, 51, 76, -57, 56, 64, -50, 62, 48, -41, + 69, 31, -30, 76, 13, -18, 85, -5, -6, 93, -21, 7, + 51, 84, -58, 53, 77, -55, 57, 66, -48, 63, 51, -39, + 70, 33, -28, 77, 16, -17, 86, -2, -5, 94, -18, 8, + 52, 86, -56, 54, 79, -53, 58, 68, -46, 64, 53, -38, + 70, 36, -27, 78, 19, -16, 86, 1, -4, 94, -15, 8, + 53, 87, -54, 55, 81, -50, 59, 70, -44, 65, 55, -36, + 71, 38, -26, 79, 21, -15, 87, 4, -3, 95, -13, 9, + 55, 88, -52, 57, 82, -48, 60, 72, -43, 66, 58, -34, + 72, 41, -24, 79, 24, -13, 87, 6, -2, 95, -10, 10, + 56, 90, -49, 58, 84, -46, 62, 74, -40, 67, 60, -32, + 73, 44, -23, 80, 27, -12, 88, 9, 0, 96, -7, 11, + 58, 91, -47, 60, 86, -44, 63, 76, -38, 68, 62, -31, + 74, 46, -21, 81, 30, -11, 89, 12, 1, 97, -4, 12, + 59, 93, -44, 61, 87, -42, 64, 78, -36, 69, 65, -29, + 75, 49, -20, 82, 32, -9, 89, 15, 2, 97, -1, 13, + 30, 69, -98, 35, 56, -90, 42, 37, -78, 50, 16, -65, + 59, -4, -50, 69, -22, -35, 79, -38, -20, 88, -52, -6, + 30, 69, -97, 35, 56, -90, 42, 37, -78, 50, 16, -65, + 60, -4, -49, 69, -21, -35, 79, -38, -20, 88, -52, -6, + 30, 69, -97, 35, 56, -90, 42, 37, -78, 50, 16, -64, + 60, -4, -49, 69, -21, -35, 79, -37, -20, 88, -51, -6, + 30, 70, -97, 35, 56, -89, 42, 37, -78, 50, 17, -64, + 60, -3, -49, 69, -21, -34, 79, -37, -20, 88, -51, -5, + 31, 70, -96, 35, 57, -89, 42, 38, -78, 50, 17, -64, + 60, -3, -49, 69, -20, -34, 79, -37, -19, 88, -51, -5, + 31, 70, -96, 35, 57, -88, 42, 38, -77, 51, 18, -64, + 60, -2, -49, 69, -20, -34, 79, -36, -19, 88, -50, -5, + 32, 70, -95, 36, 57, -88, 43, 39, -77, 51, 19, -63, + 60, -1, -49, 69, -19, -34, 79, -35, -19, 88, -50, -5, + 32, 70, -94, 36, 58, -87, 43, 40, -76, 51, 20, -63, + 60, 0, -48, 70, -18, -34, 79, -34, -19, 89, -49, -5, + 33, 71, -93, 37, 59, -86, 43, 41, -75, 51, 21, -62, + 61, 1, -48, 70, -17, -33, 79, -34, -19, 89, -48, -5, + 33, 71, -92, 37, 59, -85, 44, 42, -75, 52, 22, -62, + 61, 2, -47, 70, -16, -33, 79, -33, -18, 89, -47, -5, + 34, 72, -91, 38, 60, -84, 44, 43, -74, 52, 23, -61, + 61, 3, -47, 70, -15, -33, 80, -31, -18, 89, -46, -4, + 35, 72, -89, 39, 61, -83, 45, 44, -73, 53, 24, -60, + 61, 5, -46, 70, -13, -32, 80, -30, -18, 89, -45, -4, + 36, 73, -88, 39, 62, -82, 45, 45, -72, 53, 26, -60, + 62, 6, -46, 71, -12, -32, 80, -28, -17, 89, -43, -4, + 37, 73, -86, 40, 63, -80, 46, 47, -71, 54, 28, -59, + 62, 8, -45, 71, -10, -31, 80, -27, -17, 90, -42, -3, + 38, 74, -85, 41, 64, -79, 47, 48, -70, 54, 29, -58, + 63, 10, -44, 71, -8, -31, 81, -25, -16, 90, -40, -3, + 39, 75, -83, 42, 65, -78, 48, 50, -68, 55, 31, -57, + 63, 12, -43, 72, -6, -30, 81, -24, -16, 90, -39, -2, + 40, 76, -81, 43, 66, -76, 48, 51, -67, 55, 33, -56, + 64, 14, -43, 72, -4, -29, 81, -21, -15, 90, -37, -2, + 41, 77, -79, 44, 68, -74, 49, 53, -66, 56, 35, -55, + 64, 16, -42, 73, -2, -28, 82, -19, -15, 91, -35, -1, + 42, 78, -77, 45, 69, -72, 50, 55, -64, 57, 37, -53, + 65, 18, -41, 73, 0, -28, 82, -17, -14, 91, -33, -1, + 43, 79, -75, 46, 70, -71, 51, 56, -63, 58, 39, -52, + 65, 20, -40, 74, 2, -27, 83, -15, -13, 91, -31, 0, + 45, 80, -73, 47, 72, -69, 52, 58, -61, 58, 41, -51, + 66, 23, -39, 74, 5, -26, 83, -13, -13, 92, -29, 0, + 46, 81, -71, 48, 73, -67, 53, 60, -59, 59, 44, -49, + 67, 25, -37, 75, 7, -25, 84, -10, -12, 92, -26, 1, + 47, 82, -69, 50, 74, -65, 54, 62, -58, 60, 46, -48, + 68, 27, -36, 75, 10, -24, 84, -8, -11, 93, -24, 2, + 48, 83, -67, 51, 76, -63, 55, 64, -56, 61, 48, -46, + 68, 30, -35, 76, 12, -23, 85, -6, -10, 93, -22, 2, + 50, 84, -65, 52, 77, -61, 56, 65, -54, 62, 50, -45, + 69, 32, -34, 77, 15, -22, 85, -3, -9, 93, -19, 3, + 51, 86, -62, 53, 79, -58, 57, 67, -52, 63, 52, -43, + 70, 35, -32, 77, 18, -21, 86, 0, -8, 94, -16, 4, + 52, 87, -60, 55, 80, -56, 59, 69, -50, 64, 55, -42, + 71, 37, -31, 78, 20, -20, 86, 2, -7, 95, -14, 5, + 54, 88, -58, 56, 82, -54, 60, 71, -48, 65, 57, -40, + 72, 40, -30, 79, 23, -19, 87, 5, -7, 95, -11, 5, + 55, 89, -55, 57, 83, -52, 61, 73, -46, 66, 59, -38, + 72, 42, -28, 80, 25, -17, 88, 8, -6, 96, -9, 6, + 57, 91, -53, 59, 85, -50, 62, 75, -44, 67, 62, -36, + 73, 45, -27, 80, 28, -16, 88, 11, -4, 96, -6, 7, + 58, 92, -51, 60, 87, -48, 63, 77, -42, 68, 64, -35, + 74, 48, -25, 81, 31, -15, 89, 14, -3, 97, -3, 8, + 59, 94, -48, 61, 88, -45, 65, 79, -40, 69, 66, -33, + 75, 50, -24, 82, 34, -13, 90, 16, -2, 97, 0, 9, + 31, 72, -101, 36, 59, -93, 42, 40, -82, 51, 20, -69, + 60, -1, -54, 69, -18, -39, 79, -35, -24, 88, -49, -10, + 31, 72, -100, 36, 59, -93, 42, 40, -82, 51, 20, -69, + 60, 0, -54, 69, -18, -39, 79, -35, -24, 88, -49, -10, + 31, 72, -100, 36, 59, -93, 43, 40, -82, 51, 20, -68, + 60, 0, -54, 69, -18, -39, 79, -35, -24, 88, -49, -10, + 32, 72, -100, 36, 59, -93, 43, 41, -82, 51, 20, -68, + 60, 0, -53, 69, -18, -39, 79, -34, -24, 88, -49, -10, + 32, 72, -99, 36, 59, -92, 43, 41, -81, 51, 21, -68, + 60, 1, -53, 69, -17, -39, 79, -34, -24, 88, -48, -10, + 32, 72, -99, 36, 60, -92, 43, 42, -81, 51, 21, -68, + 60, 1, -53, 70, -17, -39, 79, -33, -24, 89, -48, -10, + 33, 72, -98, 37, 60, -91, 43, 42, -81, 51, 22, -67, + 61, 2, -53, 70, -16, -38, 79, -33, -23, 89, -47, -9, + 33, 73, -97, 37, 61, -91, 44, 43, -80, 52, 23, -67, + 61, 3, -52, 70, -15, -38, 79, -32, -23, 89, -46, -9, + 34, 73, -96, 38, 61, -90, 44, 44, -79, 52, 24, -66, + 61, 4, -52, 70, -14, -38, 80, -31, -23, 89, -46, -9, + 34, 73, -95, 38, 62, -89, 44, 45, -79, 52, 25, -66, + 61, 5, -52, 70, -13, -37, 80, -30, -23, 89, -45, -9, + 35, 74, -94, 39, 63, -88, 45, 46, -78, 53, 26, -65, + 62, 6, -51, 71, -12, -37, 80, -29, -22, 89, -44, -9, + 36, 74, -93, 39, 63, -87, 46, 47, -77, 53, 27, -65, + 62, 8, -51, 71, -11, -37, 80, -28, -22, 89, -42, -8, + 37, 75, -91, 40, 64, -85, 46, 48, -76, 54, 29, -64, + 62, 9, -50, 71, -9, -36, 80, -26, -22, 90, -41, -8, + 38, 76, -90, 41, 65, -84, 47, 49, -75, 54, 31, -63, + 63, 11, -49, 71, -7, -35, 81, -24, -21, 90, -40, -8, + 39, 76, -88, 42, 66, -83, 47, 51, -74, 55, 32, -62, + 63, 13, -49, 72, -6, -35, 81, -23, -21, 90, -38, -7, + 39, 77, -87, 43, 67, -81, 48, 52, -72, 55, 34, -61, + 64, 14, -48, 72, -4, -34, 81, -21, -20, 90, -37, -7, + 41, 78, -85, 44, 68, -80, 49, 54, -71, 56, 36, -60, + 64, 16, -47, 73, -2, -34, 82, -19, -20, 91, -35, -6, + 42, 79, -83, 45, 70, -78, 50, 55, -70, 57, 38, -59, + 65, 18, -46, 73, 0, -33, 82, -17, -19, 91, -33, -6, + 43, 79, -81, 46, 71, -76, 51, 57, -68, 57, 39, -58, + 65, 20, -45, 74, 2, -32, 82, -15, -18, 91, -31, -5, + 44, 80, -79, 47, 72, -75, 52, 58, -67, 58, 41, -56, + 66, 23, -44, 74, 5, -31, 83, -13, -18, 92, -29, -5, + 45, 81, -77, 48, 73, -73, 53, 60, -65, 59, 44, -55, + 67, 25, -43, 75, 7, -30, 83, -11, -17, 92, -27, -4, + 46, 82, -75, 49, 75, -71, 54, 62, -63, 60, 46, -54, + 67, 27, -42, 75, 9, -29, 84, -8, -16, 92, -24, -3, + 48, 83, -73, 50, 76, -69, 55, 64, -62, 61, 48, -52, + 68, 30, -41, 76, 12, -28, 84, -6, -15, 93, -22, -3, + 49, 85, -71, 51, 77, -67, 56, 65, -60, 61, 50, -51, + 69, 32, -39, 76, 14, -27, 85, -4, -15, 93, -20, -2, + 50, 86, -69, 53, 79, -65, 57, 67, -58, 62, 52, -49, + 69, 34, -38, 77, 17, -26, 85, -1, -14, 94, -17, -1, + 52, 87, -66, 54, 80, -63, 58, 69, -56, 63, 54, -48, + 70, 37, -37, 78, 19, -25, 86, 2, -13, 94, -15, -1, + 53, 88, -64, 55, 82, -61, 59, 71, -54, 64, 56, -46, + 71, 39, -35, 78, 22, -24, 87, 4, -12, 95, -12, 0, + 54, 89, -62, 56, 83, -59, 60, 73, -53, 65, 58, -44, + 72, 42, -34, 79, 24, -23, 87, 7, -11, 95, -10, 1, + 56, 91, -60, 58, 85, -56, 61, 74, -51, 66, 61, -43, + 73, 44, -33, 80, 27, -22, 88, 9, -10, 96, -7, 2, + 57, 92, -57, 59, 86, -54, 63, 77, -49, 68, 63, -41, + 74, 47, -31, 81, 30, -20, 89, 12, -9, 96, -4, 3, + 59, 93, -55, 60, 88, -52, 64, 78, -47, 69, 65, -39, + 75, 49, -30, 82, 33, -19, 89, 15, -8, 97, -1, 4, + 60, 95, -53, 62, 89, -50, 65, 80, -45, 70, 67, -37, + 76, 52, -28, 82, 35, -18, 90, 18, -7, 98, 1, 5, + 32, 74, -103, 36, 61, -96, 43, 43, -85, 51, 23, -72, + 60, 2, -57, 70, -16, -43, 79, -32, -28, 89, -47, -14, + 32, 74, -103, 37, 61, -96, 43, 43, -85, 51, 23, -72, + 60, 3, -57, 70, -15, -43, 79, -32, -28, 89, -47, -14, + 33, 74, -103, 37, 61, -96, 43, 43, -85, 51, 23, -72, + 60, 3, -57, 70, -15, -43, 79, -32, -28, 89, -47, -14, + 33, 74, -103, 37, 62, -96, 43, 44, -85, 51, 23, -72, + 61, 3, -57, 70, -15, -43, 79, -32, -28, 89, -46, -14, + 33, 74, -102, 37, 62, -95, 44, 44, -85, 52, 24, -72, + 61, 4, -57, 70, -14, -42, 79, -31, -28, 89, -46, -14, + 33, 74, -102, 37, 62, -95, 44, 44, -84, 52, 24, -71, + 61, 4, -57, 70, -14, -42, 79, -31, -28, 89, -45, -13, + 34, 74, -101, 38, 63, -94, 44, 45, -84, 52, 25, -71, + 61, 5, -56, 70, -13, -42, 80, -30, -27, 89, -45, -13, + 34, 75, -100, 38, 63, -94, 44, 46, -83, 52, 26, -71, + 61, 6, -56, 70, -12, -42, 80, -29, -27, 89, -44, -13, + 35, 75, -99, 39, 64, -93, 45, 46, -83, 53, 27, -70, + 61, 7, -56, 70, -11, -42, 80, -28, -27, 89, -43, -13, + 35, 75, -98, 39, 64, -92, 45, 47, -82, 53, 28, -69, + 62, 8, -55, 71, -10, -41, 80, -27, -27, 89, -42, -13, + 36, 76, -97, 40, 65, -91, 46, 48, -81, 53, 29, -69, + 62, 9, -55, 71, -9, -41, 80, -26, -26, 89, -41, -12, + 37, 76, -96, 40, 66, -90, 46, 49, -80, 54, 30, -68, + 62, 10, -54, 71, -8, -40, 80, -25, -26, 90, -40, -12, + 38, 77, -94, 41, 66, -89, 47, 50, -79, 54, 32, -67, + 63, 12, -54, 71, -6, -40, 81, -24, -26, 90, -39, -12, + 38, 77, -93, 42, 67, -87, 47, 52, -78, 55, 33, -67, + 63, 13, -53, 72, -5, -39, 81, -22, -25, 90, -38, -11, + 39, 78, -91, 43, 68, -86, 48, 53, -77, 55, 35, -66, + 63, 15, -52, 72, -3, -39, 81, -21, -25, 90, -36, -11, + 40, 79, -90, 43, 69, -85, 49, 54, -76, 56, 36, -65, + 64, 17, -52, 72, -2, -38, 82, -19, -24, 91, -35, -11, + 41, 79, -88, 44, 70, -83, 50, 56, -74, 56, 38, -63, + 65, 19, -51, 73, 1, -37, 82, -17, -24, 91, -33, -10, + 42, 80, -86, 45, 71, -81, 50, 57, -73, 57, 40, -62, + 65, 21, -50, 73, 2, -37, 82, -15, -23, 91, -31, -10, + 44, 81, -84, 46, 73, -80, 51, 59, -72, 58, 42, -61, + 66, 23, -49, 74, 5, -36, 83, -13, -22, 91, -29, -9, + 45, 82, -83, 47, 74, -78, 52, 60, -70, 59, 43, -60, + 66, 25, -48, 74, 7, -35, 83, -11, -22, 92, -27, -9, + 46, 83, -80, 49, 75, -76, 53, 62, -69, 59, 46, -59, + 67, 27, -47, 75, 9, -34, 84, -9, -21, 92, -25, -8, + 47, 84, -78, 50, 76, -74, 54, 64, -67, 60, 48, -57, + 68, 29, -46, 75, 11, -33, 84, -6, -20, 93, -23, -7, + 48, 85, -76, 51, 78, -72, 55, 65, -65, 61, 50, -56, + 68, 31, -44, 76, 14, -32, 85, -4, -19, 93, -20, -7, + 50, 86, -74, 52, 79, -70, 56, 67, -64, 62, 52, -54, + 69, 34, -43, 77, 16, -31, 85, -2, -19, 93, -18, -6, + 51, 87, -72, 53, 80, -69, 57, 69, -62, 63, 54, -53, + 70, 36, -42, 77, 18, -30, 86, 1, -18, 94, -16, -5, + 52, 88, -70, 54, 82, -66, 58, 71, -60, 64, 56, -51, + 71, 39, -41, 78, 21, -29, 86, 3, -17, 94, -13, -4, + 54, 89, -68, 56, 83, -64, 59, 72, -58, 65, 58, -50, + 71, 41, -39, 79, 24, -28, 87, 6, -16, 95, -11, -4, + 55, 91, -66, 57, 85, -62, 61, 74, -56, 66, 60, -48, + 72, 43, -38, 79, 26, -27, 87, 8, -15, 95, -8, -3, + 56, 92, -63, 58, 86, -60, 62, 76, -54, 67, 62, -46, + 73, 46, -36, 80, 29, -26, 88, 11, -14, 96, -6, -2, + 58, 93, -61, 60, 88, -58, 63, 78, -52, 68, 64, -45, + 74, 48, -35, 81, 31, -24, 89, 14, -13, 97, -3, -1, + 59, 95, -59, 61, 89, -56, 64, 80, -50, 69, 67, -43, + 75, 51, -33, 82, 34, -23, 89, 17, -12, 97, 0, 0, + 60, 96, -56, 62, 91, -54, 65, 81, -48, 70, 69, -41, + 76, 53, -32, 83, 36, -22, 90, 19, -10, 98, 3, 1, + 33, 76, -106, 37, 64, -99, 44, 46, -89, 52, 26, -76, + 61, 5, -61, 70, -13, -47, 80, -30, -32, 89, -45, -18, + 34, 76, -106, 38, 64, -99, 44, 46, -89, 52, 26, -76, + 61, 6, -61, 70, -13, -47, 80, -30, -32, 89, -44, -18, + 34, 76, -106, 38, 64, -99, 44, 46, -88, 52, 26, -75, + 61, 6, -61, 70, -12, -46, 80, -29, -32, 89, -44, -18, + 34, 76, -105, 38, 64, -99, 44, 46, -88, 52, 26, -75, + 61, 6, -61, 70, -12, -46, 80, -29, -32, 89, -44, -17, + 34, 76, -105, 38, 64, -98, 44, 47, -88, 52, 27, -75, + 61, 7, -61, 70, -12, -46, 80, -29, -31, 89, -44, -17, + 34, 76, -104, 38, 65, -98, 45, 47, -88, 52, 27, -75, + 61, 7, -60, 70, -11, -46, 80, -28, -31, 89, -43, -17, + 35, 76, -104, 39, 65, -97, 45, 48, -87, 53, 28, -74, + 61, 8, -60, 70, -11, -46, 80, -28, -31, 89, -43, -17, + 35, 77, -103, 39, 65, -97, 45, 48, -87, 53, 29, -74, + 62, 9, -60, 71, -10, -46, 80, -27, -31, 89, -42, -17, + 36, 77, -102, 39, 66, -96, 45, 49, -86, 53, 30, -74, + 62, 9, -59, 71, -9, -45, 80, -26, -31, 89, -41, -17, + 36, 77, -101, 40, 67, -95, 46, 50, -85, 53, 31, -73, + 62, 11, -59, 71, -8, -45, 80, -25, -30, 89, -40, -17, + 37, 78, -100, 41, 67, -94, 46, 51, -85, 54, 32, -72, + 62, 12, -59, 71, -7, -45, 81, -24, -30, 90, -39, -16, + 38, 78, -99, 41, 68, -93, 47, 52, -84, 54, 33, -72, + 63, 13, -58, 71, -5, -44, 81, -23, -30, 90, -38, -16, + 39, 79, -97, 42, 69, -92, 47, 53, -83, 55, 34, -71, + 63, 14, -57, 72, -4, -44, 81, -21, -29, 90, -37, -16, + 39, 79, -96, 43, 69, -91, 48, 54, -82, 55, 36, -70, + 63, 16, -57, 72, -2, -43, 81, -20, -29, 90, -35, -15, + 40, 80, -95, 43, 70, -89, 49, 55, -81, 56, 37, -69, + 64, 17, -56, 72, -1, -43, 82, -18, -28, 90, -34, -15, + 41, 80, -93, 44, 71, -88, 49, 56, -79, 56, 39, -68, + 64, 19, -55, 73, 1, -42, 82, -17, -28, 91, -32, -14, + 42, 81, -91, 45, 72, -86, 50, 58, -78, 57, 40, -67, + 65, 21, -54, 73, 3, -41, 82, -15, -27, 91, -31, -14, + 43, 82, -89, 46, 73, -85, 51, 59, -77, 58, 42, -66, + 65, 23, -53, 74, 5, -40, 83, -13, -27, 91, -29, -13, + 44, 83, -88, 47, 74, -83, 52, 61, -75, 58, 44, -65, + 66, 25, -53, 74, 7, -40, 83, -11, -26, 92, -27, -13, + 45, 83, -86, 48, 75, -81, 53, 62, -74, 59, 46, -64, + 67, 27, -52, 75, 9, -39, 83, -9, -25, 92, -25, -12, + 47, 84, -84, 49, 77, -79, 54, 64, -72, 60, 48, -62, + 67, 29, -50, 75, 11, -38, 84, -7, -25, 92, -23, -12, + 48, 85, -82, 50, 78, -78, 55, 65, -71, 61, 49, -61, + 68, 31, -49, 76, 13, -37, 84, -5, -24, 93, -21, -11, + 49, 86, -80, 51, 79, -76, 56, 67, -69, 61, 51, -60, + 69, 33, -48, 76, 16, -36, 85, -2, -23, 93, -19, -10, + 50, 87, -78, 52, 80, -74, 57, 69, -67, 62, 53, -58, + 69, 36, -47, 77, 18, -35, 85, 0, -22, 94, -16, -10, + 51, 88, -76, 54, 82, -72, 58, 70, -66, 63, 55, -57, + 70, 38, -46, 78, 20, -34, 86, 2, -22, 94, -14, -9, + 53, 90, -73, 55, 83, -70, 59, 72, -64, 64, 58, -55, + 71, 40, -44, 78, 23, -33, 86, 5, -20, 95, -11, -8, + 54, 91, -71, 56, 85, -68, 60, 74, -62, 65, 60, -53, + 72, 43, -43, 79, 25, -32, 87, 8, -20, 95, -9, -7, + 55, 92, -69, 57, 86, -66, 61, 76, -60, 66, 62, -52, + 73, 45, -42, 80, 28, -31, 88, 10, -19, 96, -7, -7, + 57, 93, -67, 59, 87, -64, 62, 77, -58, 67, 64, -50, + 73, 47, -40, 80, 30, -29, 88, 13, -18, 96, -4, -6, + 58, 94, -65, 60, 89, -62, 63, 79, -56, 68, 66, -48, + 74, 50, -39, 81, 33, -28, 89, 15, -16, 97, -1, -5, + 59, 96, -62, 61, 90, -59, 65, 81, -54, 69, 68, -47, + 75, 52, -37, 82, 35, -27, 90, 18, -15, 97, 1, -4, + 61, 97, -60, 63, 92, -57, 66, 83, -52, 70, 70, -45, + 76, 54, -36, 83, 38, -26, 90, 21, -14, 98, 4, -3, + 6, -12, 9, 20, -30, 27, 32, -40, 39, 44, -50, 48, + 55, -59, 57, 66, -68, 66, 76, -77, 74, 87, -85, 82, + 6, -10, 9, 20, -28, 27, 32, -39, 39, 44, -49, 48, + 55, -59, 57, 66, -68, 66, 77, -77, 74, 87, -85, 82, + 7, -8, 10, 20, -26, 28, 32, -38, 39, 44, -48, 48, + 55, -58, 57, 66, -67, 66, 77, -76, 74, 87, -85, 82, + 8, -4, 12, 21, -23, 28, 33, -36, 39, 44, -47, 48, + 55, -57, 57, 66, -67, 66, 77, -76, 74, 87, -84, 82, + 9, 1, 13, 21, -19, 29, 33, -34, 39, 44, -45, 48, + 56, -56, 57, 66, -66, 66, 77, -75, 74, 87, -84, 82, + 10, 6, 15, 22, -16, 30, 33, -31, 40, 44, -44, 49, + 56, -55, 58, 66, -65, 66, 77, -74, 74, 87, -83, 82, + 11, 10, 17, 22, -12, 31, 34, -28, 40, 45, -42, 49, + 56, -53, 58, 66, -63, 66, 77, -73, 75, 87, -82, 83, + 13, 15, 20, 23, -7, 32, 34, -25, 41, 45, -39, 49, + 56, -51, 58, 67, -62, 66, 77, -72, 75, 87, -81, 83, + 14, 19, 22, 24, -3, 33, 35, -21, 42, 45, -36, 50, + 56, -49, 59, 67, -60, 67, 77, -71, 75, 87, -80, 83, + 16, 22, 24, 25, 2, 34, 35, -17, 42, 46, -33, 50, + 57, -47, 59, 67, -58, 67, 77, -69, 75, 87, -79, 83, + 18, 26, 27, 26, 6, 35, 36, -13, 43, 46, -30, 51, + 57, -44, 59, 67, -56, 67, 78, -67, 75, 87, -77, 83, + 19, 29, 29, 27, 10, 37, 37, -10, 44, 47, -27, 52, + 57, -41, 60, 67, -54, 68, 78, -66, 76, 88, -76, 83, + 21, 33, 32, 28, 15, 38, 37, -5, 45, 47, -23, 52, + 58, -38, 60, 68, -51, 68, 78, -63, 76, 88, -74, 84, + 23, 36, 34, 30, 18, 40, 38, -1, 46, 48, -19, 53, + 58, -35, 61, 68, -49, 68, 78, -61, 76, 88, -72, 84, + 25, 38, 36, 31, 22, 41, 39, 3, 47, 49, -15, 54, + 59, -32, 61, 69, -46, 69, 79, -59, 77, 88, -70, 84, + 26, 41, 38, 32, 26, 43, 40, 7, 48, 49, -11, 55, + 59, -28, 62, 69, -43, 69, 79, -56, 77, 89, -68, 85, + 28, 44, 41, 34, 30, 45, 41, 11, 49, 50, -7, 56, + 60, -25, 63, 69, -39, 70, 79, -53, 78, 89, -65, 85, + 30, 47, 43, 35, 33, 46, 42, 15, 51, 51, -3, 57, + 61, -21, 63, 70, -36, 71, 80, -50, 78, 89, -63, 85, + 32, 49, 45, 36, 36, 48, 43, 19, 52, 52, 0, 58, + 61, -17, 64, 70, -33, 71, 80, -48, 79, 90, -60, 86, + 33, 51, 47, 38, 39, 49, 45, 22, 53, 53, 4, 59, + 62, -14, 65, 71, -30, 72, 81, -45, 79, 90, -58, 86, + 35, 54, 49, 39, 43, 51, 46, 26, 55, 54, 8, 60, + 63, -10, 66, 72, -26, 73, 81, -41, 80, 90, -55, 87, + 37, 56, 51, 41, 45, 52, 47, 30, 56, 55, 12, 61, + 63, -6, 67, 72, -23, 73, 82, -38, 80, 91, -52, 87, + 39, 59, 52, 42, 48, 54, 48, 33, 57, 56, 16, 62, + 64, -3, 68, 73, -19, 74, 82, -35, 81, 91, -49, 88, + 40, 61, 54, 44, 51, 56, 49, 36, 59, 57, 19, 63, + 65, 1, 69, 74, -16, 75, 83, -32, 82, 92, -46, 88, + 42, 63, 56, 45, 54, 57, 51, 40, 60, 58, 23, 64, + 66, 5, 70, 74, -12, 76, 83, -28, 82, 92, -43, 89, + 44, 65, 58, 47, 57, 59, 52, 43, 62, 59, 27, 66, + 67, 9, 71, 75, -8, 77, 84, -25, 83, 93, -39, 90, + 46, 68, 59, 49, 59, 60, 53, 46, 63, 60, 30, 67, + 68, 12, 72, 76, -5, 77, 84, -21, 84, 93, -36, 90, + 47, 70, 61, 50, 62, 62, 55, 49, 64, 61, 33, 68, + 68, 16, 73, 76, -1, 78, 85, -18, 85, 94, -33, 91, + 49, 72, 62, 52, 64, 64, 56, 52, 66, 62, 36, 69, + 69, 19, 74, 77, 2, 79, 86, -15, 85, 94, -30, 92, + 51, 74, 64, 53, 67, 65, 58, 55, 67, 63, 40, 71, + 70, 23, 75, 78, 6, 80, 87, -11, 86, 95, -26, 92, + 52, 76, 66, 55, 69, 67, 59, 58, 69, 65, 43, 72, + 71, 26, 76, 79, 10, 81, 87, -7, 87, 95, -23, 93, + 54, 78, 67, 56, 71, 68, 60, 60, 70, 66, 46, 73, + 72, 30, 77, 80, 13, 82, 88, -4, 88, 96, -20, 94, + 6, -11, 6, 20, -29, 24, 32, -39, 36, 44, -49, 46, + 55, -59, 56, 66, -68, 65, 76, -77, 73, 87, -85, 82, + 7, -9, 6, 20, -27, 24, 32, -38, 36, 44, -49, 46, + 55, -58, 56, 66, -67, 65, 77, -76, 73, 87, -85, 82, + 7, -6, 7, 20, -25, 25, 32, -37, 36, 44, -48, 46, + 55, -58, 56, 66, -67, 65, 77, -76, 73, 87, -85, 82, + 8, -3, 9, 21, -22, 25, 33, -35, 37, 44, -47, 47, + 55, -57, 56, 66, -66, 65, 77, -76, 74, 87, -84, 82, + 9, 2, 10, 21, -19, 26, 33, -33, 37, 44, -45, 47, + 56, -56, 56, 66, -66, 65, 77, -75, 74, 87, -84, 82, + 10, 7, 12, 22, -15, 26, 33, -31, 37, 44, -43, 47, + 56, -55, 56, 66, -65, 65, 77, -74, 74, 87, -83, 82, + 11, 11, 14, 22, -11, 27, 34, -28, 38, 45, -41, 47, + 56, -53, 57, 66, -63, 65, 77, -73, 74, 87, -82, 82, + 13, 15, 16, 23, -6, 28, 34, -24, 38, 45, -39, 48, + 56, -51, 57, 67, -62, 66, 77, -72, 74, 87, -81, 82, + 15, 19, 19, 24, -2, 30, 35, -21, 39, 45, -36, 48, + 56, -49, 57, 67, -60, 66, 77, -70, 74, 87, -80, 82, + 16, 23, 21, 25, 2, 31, 35, -17, 40, 46, -33, 49, + 57, -47, 58, 67, -58, 66, 77, -69, 74, 87, -79, 82, + 18, 26, 23, 26, 6, 32, 36, -13, 41, 46, -30, 49, + 57, -44, 58, 67, -56, 66, 78, -67, 75, 87, -77, 83, + 19, 29, 26, 27, 10, 34, 37, -9, 42, 47, -26, 50, + 57, -41, 58, 68, -54, 67, 78, -65, 75, 88, -76, 83, + 21, 33, 28, 28, 15, 35, 38, -5, 43, 47, -22, 51, + 58, -38, 59, 68, -51, 67, 78, -63, 75, 88, -74, 83, + 23, 36, 31, 30, 19, 37, 38, -1, 44, 48, -19, 51, + 58, -35, 60, 68, -48, 68, 78, -61, 76, 88, -72, 83, + 25, 39, 33, 31, 22, 38, 39, 3, 45, 49, -15, 52, + 59, -32, 60, 69, -46, 68, 79, -59, 76, 88, -70, 84, + 26, 41, 35, 32, 26, 40, 40, 7, 46, 49, -11, 53, + 59, -28, 61, 69, -43, 69, 79, -56, 76, 89, -68, 84, + 28, 44, 38, 34, 30, 42, 41, 11, 47, 50, -7, 54, + 60, -24, 62, 69, -39, 69, 79, -53, 77, 89, -65, 84, + 30, 47, 40, 35, 33, 43, 42, 15, 49, 51, -3, 55, + 61, -21, 62, 70, -36, 70, 80, -50, 77, 89, -63, 85, + 32, 49, 42, 36, 36, 45, 43, 19, 50, 52, 0, 56, + 61, -17, 63, 70, -33, 70, 80, -48, 78, 90, -60, 85, + 33, 51, 44, 38, 39, 46, 45, 22, 51, 53, 4, 57, + 62, -14, 64, 71, -30, 71, 81, -45, 78, 90, -58, 86, + 35, 54, 46, 39, 43, 48, 46, 26, 53, 54, 8, 58, + 63, -10, 65, 72, -26, 72, 81, -41, 79, 90, -55, 86, + 37, 56, 48, 41, 46, 50, 47, 30, 54, 55, 12, 59, + 63, -6, 66, 72, -23, 72, 82, -38, 80, 91, -52, 87, + 39, 59, 49, 42, 48, 52, 48, 33, 55, 56, 16, 60, + 64, -2, 67, 73, -19, 73, 82, -35, 80, 91, -49, 87, + 40, 61, 51, 44, 51, 53, 49, 36, 57, 57, 19, 62, + 65, 1, 68, 74, -16, 74, 83, -32, 81, 92, -46, 88, + 42, 63, 53, 45, 54, 55, 51, 40, 58, 58, 23, 63, + 66, 5, 69, 74, -12, 75, 83, -28, 82, 92, -43, 88, + 44, 66, 55, 47, 57, 57, 52, 43, 60, 59, 27, 64, + 67, 9, 70, 75, -8, 76, 84, -25, 82, 93, -39, 89, + 46, 68, 57, 49, 59, 58, 53, 46, 61, 60, 30, 65, + 68, 12, 71, 76, -5, 77, 84, -21, 83, 93, -36, 90, + 47, 70, 59, 50, 62, 60, 55, 49, 63, 61, 33, 67, + 69, 16, 72, 76, -1, 77, 85, -18, 84, 94, -33, 90, + 49, 72, 60, 52, 64, 62, 56, 52, 64, 62, 37, 68, + 69, 19, 73, 77, 2, 78, 86, -14, 85, 94, -30, 91, + 51, 74, 62, 53, 67, 63, 58, 55, 66, 63, 40, 69, + 71, 23, 74, 78, 6, 79, 87, -11, 86, 95, -26, 92, + 52, 76, 64, 55, 69, 65, 59, 58, 67, 65, 43, 71, + 71, 26, 75, 79, 10, 80, 87, -7, 86, 95, -23, 92, + 54, 78, 66, 56, 71, 67, 60, 61, 69, 66, 46, 72, + 72, 30, 76, 80, 13, 81, 88, -4, 87, 96, -20, 93, + 6, -10, 2, 20, -28, 20, 32, -39, 33, 44, -49, 44, + 55, -59, 54, 66, -68, 64, 76, -77, 73, 87, -85, 81, + 7, -8, 3, 20, -26, 21, 32, -38, 33, 44, -48, 44, + 55, -58, 55, 66, -67, 64, 77, -76, 73, 87, -85, 81, + 7, -5, 4, 20, -24, 21, 32, -37, 34, 44, -48, 45, + 55, -58, 55, 66, -67, 64, 77, -76, 73, 87, -84, 81, + 8, -1, 5, 21, -21, 21, 33, -35, 34, 44, -46, 45, + 55, -57, 55, 66, -66, 64, 77, -75, 73, 87, -84, 81, + 9, 3, 7, 21, -18, 22, 33, -33, 34, 44, -45, 45, + 56, -56, 55, 66, -65, 64, 77, -75, 73, 87, -83, 81, + 10, 7, 9, 22, -14, 23, 33, -30, 35, 44, -43, 45, + 56, -54, 55, 66, -64, 64, 77, -74, 73, 87, -83, 81, + 12, 12, 11, 22, -11, 24, 34, -27, 35, 45, -41, 45, + 56, -53, 55, 66, -63, 64, 77, -73, 73, 87, -82, 81, + 13, 16, 13, 23, -6, 25, 34, -24, 36, 45, -38, 46, + 56, -51, 56, 67, -61, 64, 77, -72, 73, 87, -81, 81, + 15, 20, 15, 24, -2, 26, 35, -20, 37, 45, -36, 46, + 56, -49, 56, 67, -60, 65, 77, -70, 73, 87, -80, 82, + 16, 23, 18, 25, 2, 27, 35, -17, 37, 46, -33, 47, + 57, -46, 56, 67, -58, 65, 77, -69, 74, 87, -79, 82, + 18, 27, 20, 26, 7, 29, 36, -13, 38, 46, -29, 47, + 57, -44, 57, 67, -56, 65, 78, -67, 74, 87, -77, 82, + 19, 30, 22, 27, 11, 30, 37, -9, 39, 47, -26, 48, + 57, -41, 57, 68, -54, 66, 78, -65, 74, 88, -76, 82, + 21, 33, 25, 28, 15, 32, 38, -5, 40, 47, -22, 49, + 58, -38, 58, 68, -51, 66, 78, -63, 75, 88, -74, 82, + 23, 36, 27, 30, 19, 33, 38, -1, 41, 48, -19, 50, + 58, -35, 58, 68, -48, 67, 78, -61, 75, 88, -72, 83, + 25, 39, 29, 31, 23, 35, 39, 3, 42, 49, -15, 50, + 59, -31, 59, 69, -46, 67, 79, -58, 75, 88, -70, 83, + 26, 41, 32, 32, 26, 37, 40, 7, 44, 49, -11, 51, + 59, -28, 60, 69, -43, 68, 79, -56, 76, 89, -68, 83, + 28, 44, 34, 34, 30, 39, 41, 12, 45, 50, -7, 52, + 60, -24, 60, 70, -39, 68, 79, -53, 76, 89, -65, 84, + 30, 47, 36, 35, 33, 40, 42, 15, 46, 51, -3, 53, + 61, -21, 61, 70, -36, 69, 80, -50, 77, 89, -63, 84, + 32, 49, 38, 36, 36, 42, 43, 19, 48, 52, 1, 54, + 61, -17, 62, 70, -33, 69, 80, -47, 77, 90, -60, 85, + 33, 52, 40, 38, 39, 44, 45, 23, 49, 53, 4, 55, + 62, -14, 63, 71, -30, 70, 81, -44, 78, 90, -57, 85, + 35, 54, 43, 40, 43, 46, 46, 27, 51, 54, 9, 57, + 63, -10, 64, 72, -26, 71, 81, -41, 78, 90, -54, 86, + 37, 57, 45, 41, 46, 47, 47, 30, 52, 55, 12, 58, + 63, -6, 65, 72, -22, 71, 82, -38, 79, 91, -52, 86, + 39, 59, 47, 42, 48, 49, 48, 33, 53, 56, 16, 59, + 64, -2, 65, 73, -19, 72, 82, -35, 79, 91, -49, 87, + 40, 61, 48, 44, 51, 51, 49, 37, 55, 57, 19, 60, + 65, 1, 66, 74, -16, 73, 83, -32, 80, 92, -46, 87, + 42, 63, 50, 45, 54, 53, 51, 40, 56, 58, 23, 61, + 66, 5, 67, 74, -12, 74, 83, -28, 81, 92, -43, 88, + 44, 66, 53, 47, 57, 55, 52, 43, 58, 59, 27, 63, + 67, 9, 69, 75, -8, 75, 84, -25, 82, 93, -39, 88, + 46, 68, 54, 49, 59, 56, 53, 46, 59, 60, 30, 64, + 68, 12, 70, 76, -5, 76, 84, -21, 82, 93, -36, 89, + 47, 70, 56, 50, 62, 58, 55, 49, 61, 61, 33, 65, + 69, 16, 71, 76, -1, 77, 85, -18, 83, 94, -33, 90, + 49, 72, 58, 52, 64, 60, 56, 52, 63, 62, 37, 67, + 69, 19, 72, 77, 2, 77, 86, -14, 84, 94, -30, 90, + 51, 74, 60, 53, 67, 62, 58, 55, 64, 63, 40, 68, + 71, 23, 73, 78, 6, 79, 87, -11, 85, 95, -26, 91, + 52, 76, 62, 55, 69, 63, 59, 58, 66, 65, 43, 69, + 72, 26, 74, 79, 10, 80, 87, -7, 86, 95, -23, 92, + 54, 78, 64, 56, 72, 65, 60, 61, 67, 66, 46, 71, + 73, 30, 75, 80, 13, 81, 88, -4, 86, 96, -20, 93, + 7, -8, -3, 20, -26, 15, 32, -38, 30, 44, -48, 41, + 55, -58, 52, 66, -67, 62, 77, -76, 71, 87, -85, 80, + 7, -6, -3, 20, -24, 15, 32, -37, 30, 44, -48, 42, + 55, -58, 52, 66, -67, 62, 77, -76, 71, 87, -84, 80, + 8, -3, -2, 20, -23, 16, 33, -36, 30, 44, -47, 42, + 55, -57, 52, 66, -67, 62, 77, -76, 71, 87, -84, 80, + 8, 1, -1, 21, -20, 16, 33, -34, 30, 44, -46, 42, + 55, -56, 53, 66, -66, 62, 77, -75, 71, 87, -84, 80, + 9, 5, 1, 21, -17, 17, 33, -32, 30, 44, -44, 42, + 56, -55, 53, 66, -65, 62, 77, -74, 71, 87, -83, 80, + 11, 9, 3, 22, -13, 18, 33, -30, 31, 45, -42, 42, + 56, -54, 53, 66, -64, 62, 77, -74, 72, 87, -83, 80, + 12, 13, 5, 22, -10, 19, 34, -27, 31, 45, -40, 43, + 56, -52, 53, 66, -63, 63, 77, -73, 72, 87, -82, 80, + 13, 17, 7, 23, -5, 20, 34, -23, 32, 45, -38, 43, + 56, -50, 53, 67, -61, 63, 77, -71, 72, 87, -81, 80, + 15, 20, 9, 24, -1, 21, 35, -20, 33, 46, -35, 44, + 56, -48, 54, 67, -60, 63, 77, -70, 72, 87, -80, 80, + 16, 24, 12, 25, 3, 22, 35, -16, 34, 46, -32, 44, + 57, -46, 54, 67, -58, 63, 77, -69, 72, 87, -78, 81, + 18, 27, 14, 26, 7, 24, 36, -12, 35, 46, -29, 45, + 57, -43, 55, 67, -56, 64, 78, -67, 73, 87, -77, 81, + 20, 30, 17, 27, 11, 25, 37, -8, 36, 47, -26, 45, + 57, -41, 55, 68, -53, 64, 78, -65, 73, 88, -75, 81, + 21, 34, 19, 29, 16, 27, 38, -4, 37, 47, -22, 46, + 58, -37, 56, 68, -51, 64, 78, -63, 73, 88, -73, 81, + 23, 36, 22, 30, 19, 29, 38, 0, 38, 48, -18, 47, + 58, -34, 56, 68, -48, 65, 78, -61, 74, 88, -72, 82, + 25, 39, 24, 31, 23, 31, 39, 4, 39, 49, -15, 48, + 59, -31, 57, 69, -45, 65, 79, -58, 74, 88, -70, 82, + 27, 42, 26, 32, 26, 32, 40, 8, 40, 49, -11, 49, + 59, -28, 58, 69, -42, 66, 79, -56, 74, 89, -67, 82, + 28, 45, 29, 34, 30, 34, 41, 12, 42, 50, -7, 50, + 60, -24, 58, 70, -39, 67, 79, -53, 75, 89, -65, 83, + 30, 47, 31, 35, 33, 36, 42, 16, 43, 51, -3, 51, + 61, -21, 59, 70, -36, 67, 80, -50, 75, 89, -62, 83, + 32, 49, 33, 37, 37, 38, 44, 19, 44, 52, 1, 52, + 61, -17, 60, 71, -33, 68, 80, -47, 76, 90, -60, 84, + 34, 52, 36, 38, 40, 40, 45, 23, 46, 53, 5, 53, + 62, -13, 61, 71, -29, 68, 81, -44, 76, 90, -57, 84, + 35, 54, 38, 40, 43, 42, 46, 27, 47, 54, 9, 54, + 63, -9, 62, 72, -26, 69, 81, -41, 77, 90, -54, 85, + 37, 57, 40, 41, 46, 44, 47, 30, 49, 55, 12, 55, + 63, -6, 63, 72, -22, 70, 82, -38, 78, 91, -51, 85, + 39, 59, 42, 42, 49, 46, 48, 33, 50, 56, 16, 57, + 64, -2, 64, 73, -19, 71, 82, -35, 78, 91, -49, 86, + 40, 61, 44, 44, 51, 47, 50, 37, 52, 57, 20, 58, + 65, 1, 65, 74, -15, 71, 83, -31, 79, 92, -46, 86, + 42, 63, 47, 45, 54, 49, 51, 40, 53, 58, 23, 59, + 66, 5, 66, 74, -12, 72, 83, -28, 80, 92, -43, 87, + 44, 66, 49, 47, 57, 51, 52, 43, 55, 59, 27, 60, + 67, 9, 67, 75, -8, 73, 84, -24, 80, 93, -39, 87, + 46, 68, 51, 49, 59, 53, 54, 46, 57, 60, 30, 62, + 68, 13, 68, 76, -4, 74, 84, -21, 81, 93, -36, 88, + 47, 70, 53, 50, 62, 55, 55, 49, 58, 61, 34, 63, + 69, 16, 69, 77, -1, 75, 85, -18, 82, 94, -33, 89, + 49, 72, 55, 52, 64, 57, 56, 52, 60, 62, 37, 64, + 69, 19, 70, 77, 3, 76, 86, -14, 83, 94, -30, 89, + 51, 74, 57, 53, 67, 59, 58, 55, 62, 63, 40, 66, + 71, 23, 71, 78, 6, 77, 87, -10, 84, 95, -26, 90, + 52, 76, 59, 55, 69, 60, 59, 58, 63, 65, 43, 67, + 72, 27, 72, 79, 10, 78, 87, -7, 84, 96, -23, 91, + 54, 78, 61, 56, 72, 62, 60, 61, 65, 66, 46, 69, + 73, 30, 74, 80, 13, 79, 88, -4, 85, 96, -19, 92, + 7, -5, -9, 20, -24, 10, 32, -37, 26, 44, -48, 38, + 55, -58, 50, 66, -67, 60, 77, -76, 70, 87, -84, 78, + 7, -3, -8, 20, -23, 11, 32, -36, 26, 44, -47, 38, + 55, -57, 50, 66, -67, 60, 77, -76, 70, 87, -84, 79, + 8, -1, -7, 21, -21, 11, 33, -35, 26, 44, -46, 39, + 55, -57, 50, 66, -66, 60, 77, -75, 70, 87, -84, 79, + 9, 3, -6, 21, -18, 11, 33, -33, 26, 44, -45, 39, + 56, -56, 50, 66, -65, 60, 77, -75, 70, 87, -84, 79, + 10, 7, -5, 21, -15, 12, 33, -31, 27, 44, -44, 39, + 56, -55, 50, 66, -65, 60, 77, -74, 70, 87, -83, 79, + 11, 10, -3, 22, -12, 13, 33, -29, 27, 45, -42, 39, + 56, -53, 51, 66, -64, 60, 77, -73, 70, 87, -82, 79, + 12, 14, -1, 23, -8, 14, 34, -26, 28, 45, -40, 40, + 56, -52, 51, 66, -62, 61, 77, -72, 70, 87, -82, 79, + 14, 18, 2, 23, -4, 15, 34, -22, 28, 45, -37, 40, + 56, -50, 51, 67, -61, 61, 77, -71, 70, 87, -80, 79, + 15, 21, 4, 24, 0, 16, 35, -19, 29, 46, -34, 41, + 56, -48, 51, 67, -59, 61, 77, -70, 71, 87, -79, 79, + 17, 25, 6, 25, 4, 18, 35, -15, 30, 46, -32, 41, + 57, -46, 52, 67, -57, 61, 77, -68, 71, 87, -78, 79, + 18, 28, 9, 26, 8, 19, 36, -12, 31, 46, -28, 42, + 57, -43, 52, 67, -55, 62, 78, -67, 71, 87, -77, 80, + 20, 31, 11, 27, 12, 21, 37, -8, 32, 47, -25, 42, + 57, -40, 53, 68, -53, 62, 78, -65, 71, 88, -75, 80, + 22, 34, 14, 29, 16, 23, 38, -4, 33, 48, -21, 43, + 58, -37, 53, 68, -50, 63, 78, -62, 72, 88, -73, 80, + 23, 37, 16, 30, 20, 24, 39, 0, 34, 48, -18, 44, + 58, -34, 54, 68, -48, 63, 78, -60, 72, 88, -71, 80, + 25, 39, 19, 31, 23, 26, 39, 4, 35, 49, -14, 45, + 59, -31, 55, 69, -45, 64, 79, -58, 72, 88, -69, 81, + 27, 42, 21, 32, 27, 28, 40, 8, 37, 49, -10, 46, + 59, -27, 55, 69, -42, 64, 79, -55, 73, 89, -67, 81, + 29, 45, 24, 34, 31, 30, 41, 12, 38, 50, -6, 47, + 60, -24, 56, 70, -39, 65, 79, -53, 73, 89, -65, 81, + 30, 47, 26, 35, 34, 32, 43, 16, 40, 51, -3, 48, + 61, -20, 57, 70, -36, 65, 80, -50, 74, 89, -62, 82, + 32, 50, 29, 37, 37, 34, 44, 20, 41, 52, 1, 49, + 61, -17, 58, 71, -32, 66, 80, -47, 74, 90, -60, 82, + 34, 52, 31, 38, 40, 36, 45, 23, 42, 53, 5, 50, + 62, -13, 58, 71, -29, 67, 81, -44, 75, 90, -57, 83, + 36, 55, 34, 40, 43, 38, 46, 27, 44, 54, 9, 51, + 63, -9, 59, 72, -25, 67, 81, -41, 75, 90, -54, 83, + 37, 57, 36, 41, 46, 40, 47, 30, 46, 55, 13, 53, + 63, -6, 60, 72, -22, 68, 82, -38, 76, 91, -51, 84, + 39, 59, 38, 43, 49, 42, 48, 34, 47, 56, 16, 54, + 64, -2, 61, 73, -19, 69, 82, -34, 77, 91, -48, 84, + 41, 61, 40, 44, 52, 44, 50, 37, 49, 57, 20, 55, + 65, 2, 62, 74, -15, 70, 83, -31, 77, 92, -45, 85, + 42, 63, 43, 46, 54, 46, 51, 40, 50, 58, 23, 56, + 66, 5, 63, 74, -12, 71, 83, -28, 78, 92, -42, 85, + 44, 66, 45, 47, 57, 48, 52, 44, 52, 59, 27, 58, + 67, 9, 65, 75, -8, 72, 84, -24, 79, 93, -39, 86, + 46, 68, 47, 49, 60, 50, 54, 47, 54, 60, 30, 59, + 68, 13, 66, 76, -4, 72, 85, -21, 80, 93, -36, 87, + 47, 70, 49, 50, 62, 51, 55, 49, 55, 61, 34, 61, + 69, 16, 67, 77, -1, 73, 85, -18, 80, 94, -33, 87, + 49, 72, 51, 52, 65, 53, 56, 52, 57, 62, 37, 62, + 70, 20, 68, 77, 3, 74, 86, -14, 81, 94, -29, 88, + 51, 74, 53, 53, 67, 55, 58, 55, 59, 63, 40, 64, + 71, 23, 69, 78, 7, 75, 87, -10, 82, 95, -26, 89, + 52, 76, 55, 55, 69, 57, 59, 58, 61, 65, 44, 65, + 72, 27, 70, 79, 10, 76, 87, -7, 83, 96, -23, 90, + 54, 78, 57, 56, 72, 59, 60, 61, 62, 66, 47, 66, + 73, 30, 72, 80, 13, 77, 88, -4, 84, 96, -19, 90, + 7, -2, -14, 20, -22, 5, 32, -35, 21, 44, -47, 35, + 55, -57, 47, 66, -66, 58, 77, -76, 68, 87, -84, 77, + 8, 0, -14, 21, -21, 5, 33, -35, 21, 44, -46, 35, + 55, -57, 47, 66, -66, 58, 77, -75, 68, 87, -84, 77, + 8, 2, -13, 21, -19, 6, 33, -33, 22, 44, -45, 35, + 55, -56, 47, 66, -66, 58, 77, -75, 68, 87, -84, 77, + 9, 6, -11, 21, -16, 6, 33, -32, 22, 44, -44, 35, + 56, -55, 47, 66, -65, 58, 77, -74, 68, 87, -83, 77, + 10, 9, -10, 22, -14, 7, 33, -30, 22, 44, -43, 36, + 56, -54, 48, 66, -64, 58, 77, -74, 68, 87, -83, 77, + 11, 12, -8, 22, -10, 8, 34, -27, 23, 45, -41, 36, + 56, -53, 48, 66, -63, 58, 77, -73, 68, 87, -82, 77, + 12, 16, -6, 23, -7, 9, 34, -25, 23, 45, -39, 36, + 56, -51, 48, 66, -62, 58, 77, -72, 68, 87, -81, 77, + 14, 19, -4, 24, -3, 10, 34, -21, 24, 45, -36, 37, + 56, -49, 48, 67, -60, 59, 77, -71, 68, 87, -80, 77, + 15, 22, -1, 24, 1, 11, 35, -18, 25, 46, -34, 37, + 57, -47, 49, 67, -59, 59, 77, -69, 69, 87, -79, 78, + 17, 26, 1, 25, 5, 13, 36, -15, 26, 46, -31, 38, + 57, -45, 49, 67, -57, 59, 77, -68, 69, 87, -78, 78, + 18, 29, 3, 26, 9, 14, 36, -11, 27, 46, -28, 38, + 57, -42, 49, 67, -55, 59, 78, -66, 69, 87, -76, 78, + 20, 31, 6, 27, 13, 16, 37, -7, 28, 47, -25, 39, + 58, -40, 50, 68, -53, 60, 78, -64, 69, 88, -75, 78, + 22, 35, 9, 29, 17, 18, 38, -3, 29, 48, -21, 40, + 58, -37, 51, 68, -50, 60, 78, -62, 70, 88, -73, 79, + 23, 37, 11, 30, 20, 20, 39, 1, 30, 48, -17, 41, + 58, -34, 51, 68, -47, 61, 78, -60, 70, 88, -71, 79, + 25, 40, 14, 31, 24, 21, 39, 5, 31, 49, -14, 42, + 59, -30, 52, 69, -45, 61, 79, -58, 71, 88, -69, 79, + 27, 43, 16, 32, 27, 23, 40, 9, 33, 50, -10, 43, + 59, -27, 53, 69, -42, 62, 79, -55, 71, 89, -67, 79, + 29, 45, 19, 34, 31, 25, 42, 13, 34, 50, -6, 44, + 60, -23, 53, 70, -38, 62, 79, -52, 71, 89, -64, 80, + 30, 48, 21, 35, 34, 27, 43, 16, 36, 51, -2, 45, + 61, -20, 54, 70, -35, 63, 80, -50, 72, 89, -62, 80, + 32, 50, 24, 37, 37, 29, 44, 20, 37, 52, 2, 46, + 61, -16, 55, 71, -32, 64, 80, -47, 72, 90, -59, 81, + 34, 52, 26, 38, 40, 31, 45, 24, 39, 53, 5, 47, + 62, -13, 56, 71, -29, 64, 81, -44, 73, 90, -57, 81, + 36, 55, 29, 40, 44, 34, 46, 27, 40, 54, 9, 48, + 63, -9, 57, 72, -25, 65, 81, -40, 74, 90, -54, 82, + 37, 57, 31, 41, 46, 36, 47, 31, 42, 55, 13, 50, + 63, -5, 58, 72, -22, 66, 82, -37, 74, 91, -51, 82, + 39, 59, 34, 43, 49, 38, 48, 34, 44, 56, 17, 51, + 64, -2, 59, 73, -18, 67, 82, -34, 75, 91, -48, 83, + 41, 62, 36, 44, 52, 40, 50, 37, 45, 57, 20, 52, + 65, 2, 60, 74, -15, 68, 83, -31, 76, 92, -45, 83, + 42, 64, 38, 46, 54, 42, 51, 40, 47, 58, 24, 53, + 66, 5, 61, 74, -11, 68, 83, -28, 76, 92, -42, 84, + 44, 66, 41, 47, 57, 44, 52, 44, 49, 59, 27, 55, + 67, 9, 62, 75, -8, 69, 84, -24, 77, 93, -39, 85, + 46, 68, 43, 49, 60, 46, 54, 47, 50, 60, 31, 56, + 68, 13, 63, 76, -4, 70, 85, -21, 78, 93, -36, 85, + 47, 70, 45, 50, 62, 48, 55, 50, 52, 61, 34, 58, + 69, 16, 64, 77, -1, 71, 85, -17, 79, 94, -32, 86, + 49, 72, 47, 52, 65, 50, 56, 53, 54, 62, 37, 59, + 70, 20, 66, 77, 3, 72, 86, -14, 79, 94, -29, 87, + 51, 75, 49, 53, 67, 52, 58, 56, 56, 63, 41, 61, + 71, 24, 67, 78, 7, 73, 87, -10, 80, 95, -26, 87, + 52, 77, 52, 55, 70, 54, 59, 58, 57, 65, 44, 62, + 72, 27, 68, 79, 10, 74, 87, -7, 81, 96, -22, 88, + 54, 79, 54, 56, 72, 56, 60, 61, 59, 66, 47, 64, + 73, 30, 69, 80, 14, 75, 88, -3, 82, 96, -19, 89, + 8, 2, -19, 21, -19, 0, 33, -34, 17, 44, -46, 31, + 55, -56, 44, 66, -66, 55, 77, -75, 66, 87, -84, 75, + 8, 4, -19, 21, -18, 0, 33, -33, 17, 44, -45, 31, + 55, -56, 44, 66, -65, 55, 77, -75, 66, 87, -83, 75, + 9, 6, -18, 21, -17, 1, 33, -32, 17, 44, -44, 31, + 56, -55, 44, 66, -65, 55, 77, -74, 66, 87, -83, 75, + 10, 8, -16, 21, -14, 1, 33, -30, 17, 44, -43, 31, + 56, -54, 44, 66, -64, 55, 77, -74, 66, 87, -83, 75, + 11, 11, -15, 22, -12, 2, 33, -28, 18, 45, -42, 32, + 56, -53, 44, 66, -64, 55, 77, -73, 66, 87, -82, 75, + 12, 14, -13, 22, -9, 3, 34, -26, 18, 45, -40, 32, + 56, -52, 45, 66, -63, 56, 77, -73, 66, 87, -82, 75, + 13, 17, -11, 23, -5, 4, 34, -23, 19, 45, -38, 32, + 56, -51, 45, 67, -61, 56, 77, -72, 66, 87, -81, 75, + 14, 21, -9, 24, -1, 5, 35, -20, 20, 45, -35, 33, + 56, -49, 45, 67, -60, 56, 77, -70, 66, 87, -80, 76, + 16, 24, -7, 25, 2, 6, 35, -17, 20, 46, -33, 33, + 57, -47, 45, 67, -58, 56, 77, -69, 66, 87, -79, 76, + 17, 27, -4, 26, 6, 8, 36, -13, 21, 46, -30, 34, + 57, -44, 46, 67, -56, 57, 77, -67, 67, 87, -77, 76, + 19, 30, -2, 27, 10, 9, 36, -10, 22, 47, -27, 35, + 57, -42, 46, 67, -54, 57, 78, -66, 67, 87, -76, 76, + 20, 32, 1, 28, 14, 11, 37, -6, 23, 47, -24, 35, + 58, -39, 47, 68, -52, 57, 78, -64, 67, 88, -74, 76, + 22, 35, 3, 29, 18, 13, 38, -2, 25, 48, -20, 36, + 58, -36, 47, 68, -49, 58, 78, -62, 68, 88, -73, 77, + 24, 38, 6, 30, 21, 15, 39, 2, 26, 48, -17, 37, + 58, -33, 48, 68, -47, 58, 78, -60, 68, 88, -71, 77, + 25, 41, 9, 31, 25, 17, 40, 5, 27, 49, -13, 38, + 59, -30, 49, 69, -44, 59, 79, -57, 68, 88, -69, 77, + 27, 43, 11, 33, 28, 19, 41, 9, 28, 50, -9, 39, + 59, -27, 49, 69, -41, 59, 79, -55, 69, 89, -67, 78, + 29, 46, 14, 34, 32, 21, 42, 13, 30, 50, -5, 40, + 60, -23, 50, 70, -38, 60, 79, -52, 69, 89, -64, 78, + 31, 48, 16, 35, 35, 23, 43, 17, 31, 51, -2, 41, + 61, -19, 51, 70, -35, 60, 80, -49, 70, 89, -62, 78, + 32, 51, 19, 37, 38, 25, 44, 20, 33, 52, 2, 42, + 61, -16, 52, 71, -32, 61, 80, -46, 70, 90, -59, 79, + 34, 53, 21, 38, 41, 27, 45, 24, 34, 53, 6, 43, + 62, -12, 53, 71, -28, 62, 81, -43, 71, 90, -57, 79, + 36, 55, 24, 40, 44, 29, 46, 28, 36, 54, 10, 45, + 63, -8, 54, 72, -25, 63, 81, -40, 72, 90, -54, 80, + 37, 58, 27, 41, 47, 31, 47, 31, 38, 55, 13, 46, + 64, -5, 55, 72, -21, 63, 82, -37, 72, 91, -51, 80, + 39, 60, 29, 43, 50, 33, 48, 34, 40, 56, 17, 47, + 64, -1, 56, 73, -18, 64, 82, -34, 73, 91, -48, 81, + 41, 62, 31, 44, 52, 35, 50, 38, 41, 57, 20, 49, + 65, 2, 57, 74, -15, 65, 83, -31, 73, 92, -45, 81, + 42, 64, 34, 46, 55, 37, 51, 41, 43, 58, 24, 50, + 66, 6, 58, 74, -11, 66, 83, -27, 74, 92, -42, 82, + 44, 66, 36, 47, 58, 40, 52, 44, 45, 59, 28, 52, + 67, 10, 59, 75, -7, 67, 84, -24, 75, 93, -39, 83, + 46, 68, 38, 49, 60, 42, 54, 47, 47, 60, 31, 53, + 68, 13, 60, 76, -4, 68, 85, -20, 76, 93, -35, 83, + 48, 70, 41, 50, 63, 44, 55, 50, 48, 61, 34, 54, + 69, 17, 62, 77, 0, 69, 85, -17, 77, 94, -32, 84, + 49, 73, 43, 52, 65, 46, 56, 53, 50, 62, 37, 56, + 70, 20, 63, 77, 3, 70, 86, -14, 77, 94, -29, 85, + 51, 75, 45, 53, 68, 48, 58, 56, 52, 64, 41, 58, + 71, 24, 64, 78, 7, 71, 87, -10, 78, 95, -25, 86, + 53, 77, 47, 55, 70, 50, 59, 59, 54, 65, 44, 59, + 72, 27, 65, 79, 10, 72, 87, -7, 79, 96, -22, 86, + 54, 79, 50, 56, 72, 52, 60, 61, 56, 66, 47, 61, + 73, 30, 67, 80, 14, 73, 88, -3, 80, 96, -19, 87, + 9, 7, -25, 21, -16, -5, 33, -32, 12, 44, -44, 26, + 55, -55, 40, 66, -65, 52, 77, -74, 63, 87, -83, 73, + 9, 8, -24, 21, -15, -5, 33, -31, 12, 44, -43, 27, + 56, -55, 40, 66, -65, 52, 77, -74, 63, 87, -83, 73, + 10, 10, -23, 21, -14, -5, 33, -30, 12, 44, -43, 27, + 56, -54, 40, 66, -64, 52, 77, -74, 63, 87, -83, 73, + 10, 12, -22, 22, -11, -4, 33, -28, 12, 44, -42, 27, + 56, -53, 40, 66, -64, 52, 77, -73, 63, 87, -82, 73, + 11, 14, -21, 22, -9, -4, 34, -27, 13, 45, -40, 27, + 56, -52, 40, 66, -63, 52, 77, -73, 63, 87, -82, 73, + 12, 17, -19, 23, -6, -3, 34, -24, 13, 45, -39, 27, + 56, -51, 41, 66, -62, 52, 77, -72, 63, 87, -81, 73, + 13, 20, -17, 23, -3, -2, 34, -22, 14, 45, -37, 28, + 56, -50, 41, 67, -61, 52, 77, -71, 63, 87, -80, 73, + 15, 23, -15, 24, 1, 0, 35, -19, 14, 45, -34, 28, + 56, -48, 41, 67, -59, 53, 77, -70, 63, 87, -79, 73, + 16, 25, -12, 25, 4, 1, 35, -15, 15, 46, -32, 29, + 57, -46, 42, 67, -57, 53, 77, -68, 64, 87, -78, 73, + 18, 28, -10, 26, 8, 2, 36, -12, 16, 46, -29, 29, + 57, -43, 42, 67, -56, 53, 78, -67, 64, 87, -77, 73, + 19, 31, -8, 27, 11, 4, 36, -9, 17, 47, -26, 30, + 57, -41, 42, 67, -54, 54, 78, -65, 64, 88, -76, 74, + 21, 33, -5, 28, 15, 5, 37, -5, 18, 47, -23, 31, + 58, -38, 43, 68, -51, 54, 78, -63, 64, 88, -74, 74, + 22, 36, -2, 29, 19, 7, 38, -1, 19, 48, -19, 32, + 58, -35, 44, 68, -49, 54, 78, -61, 65, 88, -72, 74, + 24, 39, 0, 30, 22, 9, 39, 3, 21, 48, -16, 33, + 59, -32, 44, 68, -46, 55, 79, -59, 65, 88, -70, 75, + 26, 41, 3, 32, 26, 11, 40, 6, 22, 49, -12, 33, + 59, -29, 45, 69, -43, 55, 79, -57, 66, 88, -68, 75, + 27, 44, 5, 33, 29, 13, 41, 10, 23, 50, -9, 34, + 60, -26, 46, 69, -41, 56, 79, -54, 66, 89, -66, 75, + 29, 46, 8, 34, 32, 15, 42, 14, 25, 51, -5, 36, + 60, -22, 46, 70, -37, 57, 80, -51, 66, 89, -64, 76, + 31, 49, 11, 36, 35, 17, 43, 18, 26, 51, -1, 37, + 61, -19, 47, 70, -34, 57, 80, -49, 67, 89, -61, 76, + 32, 51, 13, 37, 38, 19, 44, 21, 28, 52, 3, 38, + 61, -15, 48, 71, -31, 58, 80, -46, 68, 90, -59, 76, + 34, 53, 16, 38, 41, 21, 45, 25, 30, 53, 6, 39, + 62, -12, 49, 71, -28, 59, 81, -43, 68, 90, -56, 77, + 36, 56, 19, 40, 45, 24, 46, 28, 31, 54, 10, 40, + 63, -8, 50, 72, -24, 59, 81, -40, 69, 90, -53, 77, + 38, 58, 21, 41, 47, 26, 47, 32, 33, 55, 14, 42, + 64, -4, 51, 72, -21, 60, 82, -37, 69, 91, -50, 78, + 39, 60, 23, 43, 50, 28, 49, 35, 35, 56, 17, 43, + 64, -1, 52, 73, -18, 61, 82, -33, 70, 91, -48, 79, + 41, 62, 26, 44, 53, 30, 50, 38, 37, 57, 21, 44, + 65, 3, 53, 74, -14, 62, 83, -30, 71, 92, -45, 79, + 43, 64, 28, 46, 55, 32, 51, 41, 38, 58, 24, 46, + 66, 6, 54, 74, -11, 63, 83, -27, 71, 92, -42, 80, + 44, 67, 31, 47, 58, 35, 52, 44, 40, 59, 28, 47, + 67, 10, 56, 75, -7, 64, 84, -23, 72, 93, -38, 80, + 46, 69, 33, 49, 60, 37, 54, 47, 42, 60, 31, 49, + 68, 14, 57, 76, -3, 65, 85, -20, 73, 93, -35, 81, + 48, 71, 36, 50, 63, 39, 55, 50, 44, 61, 35, 50, + 69, 17, 58, 77, 0, 66, 85, -17, 74, 94, -32, 82, + 49, 73, 38, 52, 65, 41, 56, 53, 46, 62, 38, 52, + 70, 20, 59, 77, 3, 67, 86, -13, 75, 94, -29, 82, + 51, 75, 40, 54, 68, 43, 58, 56, 48, 64, 41, 54, + 71, 24, 61, 78, 7, 68, 87, -10, 76, 95, -25, 83, + 53, 77, 43, 55, 70, 45, 59, 59, 49, 65, 44, 55, + 72, 27, 62, 79, 11, 69, 87, -6, 77, 96, -22, 84, + 54, 79, 45, 57, 72, 47, 61, 62, 51, 66, 47, 57, + 73, 31, 63, 80, 14, 70, 88, -3, 78, 96, -19, 85, + 9, 11, -29, 21, -13, -10, 33, -30, 7, 44, -43, 22, + 56, -54, 36, 66, -64, 48, 77, -74, 60, 87, -83, 70, + 10, 12, -29, 21, -12, -10, 33, -29, 7, 44, -42, 22, + 56, -54, 36, 66, -64, 48, 77, -73, 60, 87, -82, 70, + 10, 13, -28, 22, -11, -10, 33, -28, 7, 44, -41, 22, + 56, -53, 36, 66, -63, 49, 77, -73, 60, 87, -82, 70, + 11, 15, -27, 22, -9, -9, 33, -26, 8, 45, -40, 23, + 56, -52, 37, 66, -63, 49, 77, -73, 60, 87, -82, 70, + 12, 17, -25, 22, -6, -8, 34, -25, 8, 45, -39, 23, + 56, -51, 37, 66, -62, 49, 77, -72, 60, 87, -81, 70, + 13, 19, -24, 23, -4, -8, 34, -22, 8, 45, -37, 23, + 56, -50, 37, 67, -61, 49, 77, -71, 60, 87, -81, 70, + 14, 22, -22, 24, -1, -7, 34, -20, 9, 45, -35, 24, + 56, -49, 37, 67, -60, 49, 77, -70, 60, 87, -80, 70, + 15, 24, -20, 24, 3, -5, 35, -17, 10, 46, -33, 24, + 56, -47, 38, 67, -58, 49, 77, -69, 61, 87, -79, 71, + 17, 27, -17, 25, 6, -4, 35, -14, 11, 46, -30, 25, + 57, -45, 38, 67, -57, 50, 77, -68, 61, 87, -78, 71, + 18, 30, -15, 26, 9, -3, 36, -11, 11, 46, -28, 25, + 57, -42, 38, 67, -55, 50, 78, -66, 61, 87, -76, 71, + 19, 32, -13, 27, 13, -1, 37, -7, 12, 47, -25, 26, + 57, -40, 39, 68, -53, 50, 78, -65, 61, 88, -75, 71, + 21, 35, -10, 28, 16, 1, 37, -4, 14, 47, -22, 27, + 58, -37, 39, 68, -51, 51, 78, -63, 62, 88, -73, 71, + 23, 37, -7, 29, 20, 2, 38, 0, 15, 48, -18, 27, + 58, -34, 40, 68, -48, 51, 78, -61, 62, 88, -72, 72, + 24, 40, -5, 31, 23, 4, 39, 4, 16, 49, -15, 28, + 59, -31, 41, 68, -46, 52, 79, -58, 62, 88, -70, 72, + 26, 42, -2, 32, 26, 6, 40, 7, 17, 49, -11, 29, + 59, -28, 41, 69, -43, 52, 79, -56, 63, 88, -68, 72, + 27, 45, 0, 33, 30, 8, 41, 11, 19, 50, -8, 30, + 60, -25, 42, 69, -40, 53, 79, -54, 63, 89, -66, 73, + 29, 47, 3, 34, 33, 10, 42, 15, 20, 51, -4, 31, + 60, -21, 43, 70, -37, 53, 80, -51, 64, 89, -63, 73, + 31, 49, 6, 36, 36, 12, 43, 18, 22, 51, 0, 33, + 61, -18, 44, 70, -34, 54, 80, -48, 64, 89, -61, 74, + 33, 52, 8, 37, 39, 15, 44, 22, 24, 52, 3, 34, + 61, -15, 45, 71, -31, 55, 80, -45, 65, 90, -58, 74, + 34, 54, 11, 39, 42, 17, 45, 25, 25, 53, 7, 35, + 62, -11, 45, 71, -27, 55, 81, -43, 65, 90, -56, 75, + 36, 56, 14, 40, 45, 19, 46, 29, 27, 54, 11, 36, + 63, -7, 47, 72, -24, 56, 81, -39, 66, 90, -53, 75, + 38, 58, 16, 42, 48, 21, 48, 32, 29, 55, 14, 38, + 64, -4, 48, 72, -20, 57, 82, -36, 67, 91, -50, 76, + 39, 61, 19, 43, 50, 23, 49, 35, 30, 56, 18, 39, + 64, 0, 49, 73, -17, 58, 82, -33, 67, 91, -47, 76, + 41, 63, 21, 44, 53, 25, 50, 38, 32, 57, 21, 41, + 65, 3, 50, 74, -14, 59, 83, -30, 68, 92, -44, 77, + 43, 65, 23, 46, 56, 28, 51, 42, 34, 58, 25, 42, + 66, 7, 51, 74, -10, 60, 83, -27, 69, 92, -41, 77, + 44, 67, 26, 48, 58, 30, 53, 45, 36, 59, 28, 44, + 67, 11, 52, 75, -6, 61, 84, -23, 70, 93, -38, 78, + 46, 69, 29, 49, 61, 32, 54, 48, 38, 60, 32, 45, + 68, 14, 53, 76, -3, 62, 85, -20, 70, 93, -35, 79, + 48, 71, 31, 51, 63, 34, 55, 51, 40, 61, 35, 47, + 69, 17, 55, 77, 0, 63, 85, -16, 71, 94, -32, 79, + 49, 73, 33, 52, 66, 36, 56, 53, 42, 62, 38, 48, + 70, 21, 56, 77, 4, 64, 86, -13, 72, 94, -28, 80, + 51, 75, 36, 54, 68, 39, 58, 56, 44, 64, 42, 50, + 71, 25, 57, 78, 8, 65, 87, -9, 73, 95, -25, 81, + 53, 77, 38, 55, 70, 41, 59, 59, 45, 65, 45, 51, + 72, 28, 59, 79, 11, 66, 87, -6, 74, 96, -22, 82, + 54, 79, 40, 57, 73, 43, 61, 62, 47, 66, 48, 53, + 73, 31, 60, 80, 14, 67, 88, -3, 75, 96, -18, 83, + 10, 14, -34, 22, -10, -15, 33, -27, 2, 44, -41, 18, + 56, -53, 32, 66, -63, 45, 77, -73, 57, 87, -82, 67, + 11, 15, -33, 22, -9, -15, 33, -26, 2, 45, -40, 18, + 56, -52, 32, 66, -63, 45, 77, -73, 57, 87, -82, 67, + 11, 16, -32, 22, -8, -15, 33, -26, 3, 45, -40, 18, + 56, -52, 32, 66, -62, 45, 77, -72, 57, 87, -82, 67, + 12, 18, -31, 22, -6, -14, 34, -24, 3, 45, -39, 18, + 56, -51, 33, 66, -62, 45, 77, -72, 57, 87, -81, 68, + 12, 20, -30, 23, -4, -13, 34, -22, 3, 45, -37, 19, + 56, -50, 33, 66, -61, 45, 77, -71, 57, 87, -81, 68, + 13, 22, -28, 23, -1, -12, 34, -20, 4, 45, -36, 19, + 56, -49, 33, 67, -60, 45, 77, -70, 57, 87, -80, 68, + 14, 24, -26, 24, 1, -12, 35, -18, 4, 45, -34, 19, + 56, -47, 33, 67, -59, 46, 77, -70, 57, 87, -79, 68, + 16, 26, -24, 25, 5, -10, 35, -15, 5, 46, -31, 20, + 57, -45, 34, 67, -57, 46, 77, -68, 58, 87, -78, 68, + 17, 29, -22, 25, 8, -9, 36, -12, 6, 46, -29, 20, + 57, -44, 34, 67, -56, 46, 77, -67, 58, 87, -77, 68, + 18, 31, -20, 26, 11, -8, 36, -9, 7, 46, -26, 21, + 57, -41, 34, 67, -54, 46, 78, -66, 58, 87, -76, 68, + 20, 34, -18, 27, 14, -6, 37, -6, 8, 47, -24, 22, + 57, -39, 35, 68, -52, 47, 78, -64, 58, 88, -74, 69, + 21, 36, -15, 28, 18, -4, 38, -3, 9, 47, -21, 22, + 58, -36, 35, 68, -50, 47, 78, -62, 59, 88, -73, 69, + 23, 39, -12, 30, 21, -2, 38, 1, 10, 48, -17, 23, + 58, -33, 36, 68, -47, 48, 78, -60, 59, 88, -71, 69, + 25, 41, -10, 31, 24, -1, 39, 5, 11, 49, -14, 24, + 59, -30, 37, 69, -45, 48, 79, -58, 59, 88, -69, 69, + 26, 43, -7, 32, 28, 1, 40, 8, 13, 49, -10, 25, + 59, -27, 37, 69, -42, 49, 79, -55, 60, 89, -67, 70, + 28, 45, -5, 33, 31, 3, 41, 12, 14, 50, -7, 26, + 60, -24, 38, 69, -39, 49, 79, -53, 60, 89, -65, 70, + 30, 48, -2, 35, 34, 6, 42, 16, 16, 51, -3, 27, + 60, -21, 39, 70, -36, 50, 80, -50, 61, 89, -63, 71, + 31, 50, 1, 36, 37, 8, 43, 19, 17, 52, 1, 28, + 61, -17, 40, 70, -33, 51, 80, -48, 61, 89, -60, 71, + 33, 52, 3, 37, 40, 10, 44, 23, 19, 52, 4, 30, + 62, -14, 41, 71, -30, 51, 80, -45, 62, 90, -58, 71, + 34, 54, 6, 39, 43, 12, 45, 26, 21, 53, 8, 31, + 62, -11, 42, 71, -27, 52, 81, -42, 62, 90, -55, 72, + 36, 57, 9, 40, 46, 14, 46, 30, 23, 54, 12, 32, + 63, -7, 43, 72, -23, 53, 81, -39, 63, 91, -52, 72, + 38, 59, 11, 42, 48, 16, 48, 33, 24, 55, 15, 34, + 64, -3, 44, 73, -20, 54, 82, -36, 64, 91, -50, 73, + 40, 61, 14, 43, 51, 19, 49, 36, 26, 56, 19, 35, + 65, 0, 45, 73, -17, 55, 82, -33, 64, 91, -47, 74, + 41, 63, 16, 45, 54, 21, 50, 39, 28, 57, 22, 36, + 65, 4, 46, 74, -13, 56, 83, -29, 65, 92, -44, 74, + 43, 65, 19, 46, 56, 23, 51, 42, 30, 58, 25, 38, + 66, 7, 47, 74, -10, 56, 83, -26, 66, 92, -41, 75, + 45, 67, 21, 48, 59, 25, 53, 45, 32, 59, 29, 40, + 67, 11, 49, 75, -6, 58, 84, -23, 67, 93, -37, 76, + 46, 69, 24, 49, 61, 28, 54, 48, 34, 60, 32, 41, + 68, 14, 50, 76, -3, 59, 85, -19, 68, 93, -34, 76, + 48, 71, 26, 51, 64, 30, 55, 51, 35, 61, 35, 43, + 69, 18, 51, 77, 1, 60, 85, -16, 68, 94, -31, 77, + 49, 73, 29, 52, 66, 32, 57, 54, 37, 63, 39, 44, + 70, 21, 52, 78, 4, 61, 86, -13, 69, 94, -28, 78, + 51, 76, 31, 54, 69, 34, 58, 57, 39, 64, 42, 46, + 71, 25, 54, 78, 8, 62, 87, -9, 70, 95, -24, 78, + 53, 78, 34, 55, 71, 36, 59, 60, 41, 65, 45, 48, + 72, 28, 55, 79, 11, 63, 87, -6, 71, 96, -21, 79, + 54, 80, 36, 57, 73, 39, 61, 62, 43, 66, 48, 49, + 73, 31, 56, 80, 15, 64, 88, -2, 72, 96, -18, 80, + 11, 18, -38, 22, -6, -20, 33, -25, -3, 45, -39, 13, + 56, -51, 28, 66, -62, 41, 77, -72, 54, 87, -81, 64, + 11, 19, -37, 22, -5, -20, 34, -24, -2, 45, -38, 14, + 56, -51, 28, 66, -62, 41, 77, -72, 54, 87, -81, 65, + 12, 20, -36, 22, -4, -19, 34, -23, -2, 45, -38, 14, + 56, -50, 28, 66, -61, 41, 77, -72, 54, 87, -81, 65, + 12, 21, -35, 23, -3, -19, 34, -22, -2, 45, -37, 14, + 56, -50, 29, 66, -61, 42, 77, -71, 54, 87, -80, 65, + 13, 23, -34, 23, -1, -18, 34, -20, -1, 45, -36, 14, + 56, -49, 29, 67, -60, 42, 77, -70, 54, 87, -80, 65, + 14, 24, -33, 24, 1, -17, 34, -18, -1, 45, -34, 14, + 56, -48, 29, 67, -59, 42, 77, -70, 54, 87, -79, 65, + 15, 26, -31, 24, 4, -16, 35, -16, 0, 46, -32, 15, + 56, -46, 29, 67, -58, 42, 77, -69, 54, 87, -78, 65, + 16, 29, -29, 25, 7, -15, 35, -13, 0, 46, -30, 15, + 57, -44, 30, 67, -56, 42, 77, -67, 54, 87, -77, 65, + 18, 31, -27, 26, 10, -14, 36, -10, 1, 46, -28, 16, + 57, -42, 30, 67, -55, 43, 78, -66, 54, 87, -76, 65, + 19, 33, -25, 27, 13, -12, 36, -7, 2, 47, -25, 16, + 57, -40, 30, 67, -53, 43, 78, -65, 55, 88, -75, 65, + 20, 35, -22, 28, 16, -11, 37, -4, 3, 47, -22, 17, + 58, -38, 31, 68, -51, 43, 78, -63, 55, 88, -74, 66, + 22, 37, -20, 29, 19, -9, 38, -1, 4, 48, -19, 18, + 58, -35, 31, 68, -49, 44, 78, -61, 55, 88, -72, 66, + 23, 40, -17, 30, 23, -7, 39, 3, 6, 48, -16, 19, + 58, -32, 32, 68, -46, 44, 78, -59, 56, 88, -70, 66, + 25, 42, -15, 31, 26, -5, 39, 6, 7, 49, -12, 20, + 59, -29, 33, 69, -44, 45, 79, -57, 56, 88, -69, 67, + 26, 44, -12, 32, 29, -3, 40, 10, 8, 49, -9, 21, + 59, -26, 33, 69, -41, 45, 79, -55, 57, 89, -67, 67, + 28, 46, -10, 33, 32, -2, 41, 13, 10, 50, -6, 22, + 60, -23, 34, 69, -39, 46, 79, -52, 57, 89, -65, 67, + 30, 49, -7, 35, 35, 1, 42, 17, 11, 51, -2, 23, + 60, -20, 35, 70, -35, 46, 80, -50, 58, 89, -62, 68, + 31, 51, -4, 36, 38, 3, 43, 20, 13, 52, 2, 24, + 61, -17, 36, 70, -32, 47, 80, -47, 58, 89, -60, 68, + 33, 53, -2, 38, 41, 5, 44, 23, 14, 52, 5, 25, + 62, -13, 37, 71, -29, 48, 80, -44, 59, 90, -57, 69, + 35, 55, 1, 39, 43, 7, 45, 27, 16, 53, 8, 27, + 62, -10, 38, 71, -26, 49, 81, -41, 59, 90, -55, 69, + 36, 58, 4, 40, 46, 9, 47, 30, 18, 54, 12, 28, + 63, -6, 39, 72, -22, 49, 81, -38, 60, 91, -52, 70, + 38, 60, 6, 42, 49, 12, 48, 34, 20, 55, 16, 29, + 64, -3, 40, 73, -19, 50, 82, -35, 61, 91, -49, 70, + 40, 62, 9, 43, 52, 14, 49, 37, 21, 56, 19, 31, + 65, 1, 41, 73, -16, 51, 82, -32, 61, 91, -46, 71, + 41, 64, 11, 45, 54, 16, 50, 40, 23, 57, 23, 32, + 65, 4, 42, 74, -13, 52, 83, -29, 62, 92, -43, 71, + 43, 66, 14, 46, 57, 18, 51, 43, 25, 58, 26, 34, + 66, 8, 43, 75, -9, 53, 84, -26, 63, 92, -40, 72, + 45, 68, 17, 48, 59, 21, 53, 46, 27, 59, 30, 35, + 67, 12, 45, 75, -5, 54, 84, -22, 64, 93, -37, 73, + 46, 70, 19, 49, 62, 23, 54, 49, 29, 60, 33, 37, + 68, 15, 46, 76, -2, 55, 85, -19, 64, 93, -34, 73, + 48, 72, 22, 51, 64, 25, 55, 52, 31, 61, 36, 39, + 69, 18, 47, 77, 1, 56, 85, -15, 65, 94, -31, 74, + 50, 74, 24, 52, 66, 27, 57, 54, 33, 63, 39, 40, + 70, 22, 49, 78, 5, 57, 86, -12, 66, 94, -28, 75, + 51, 76, 27, 54, 69, 30, 58, 57, 35, 64, 42, 42, + 71, 25, 50, 79, 8, 58, 87, -8, 67, 95, -24, 76, + 53, 78, 29, 55, 71, 32, 59, 60, 37, 65, 45, 44, + 72, 29, 51, 79, 12, 60, 88, -5, 68, 96, -21, 77, + 55, 80, 31, 57, 73, 34, 61, 63, 39, 66, 48, 45, + 73, 32, 53, 80, 15, 61, 88, -2, 69, 96, -18, 77, + 12, 22, -42, 23, -3, -24, 34, -22, -7, 45, -37, 9, + 56, -50, 24, 66, -61, 37, 77, -71, 50, 87, -80, 61, + 12, 22, -41, 23, -2, -24, 34, -21, -7, 45, -36, 9, + 56, -49, 24, 66, -60, 38, 77, -71, 50, 87, -80, 61, + 13, 23, -40, 23, -1, -24, 34, -20, -7, 45, -36, 9, + 56, -49, 24, 66, -60, 38, 77, -71, 50, 87, -80, 61, + 13, 24, -39, 23, 0, -23, 34, -19, -6, 45, -35, 9, + 56, -48, 24, 67, -59, 38, 77, -70, 50, 87, -80, 62, + 14, 25, -38, 24, 2, -23, 34, -18, -6, 45, -34, 10, + 56, -47, 25, 67, -59, 38, 77, -69, 50, 87, -79, 62, + 15, 27, -37, 24, 4, -22, 35, -16, -6, 45, -32, 10, + 56, -46, 25, 67, -58, 38, 77, -69, 51, 87, -78, 62, + 16, 29, -35, 25, 6, -21, 35, -14, -5, 46, -30, 10, + 57, -45, 25, 67, -57, 38, 77, -68, 51, 87, -78, 62, + 17, 31, -33, 25, 9, -20, 36, -11, -4, 46, -28, 11, + 57, -43, 25, 67, -55, 38, 77, -67, 51, 87, -77, 62, + 18, 33, -31, 26, 12, -18, 36, -8, -3, 46, -26, 11, + 57, -41, 26, 67, -54, 39, 78, -65, 51, 87, -76, 62, + 19, 35, -29, 27, 15, -17, 37, -6, -3, 47, -23, 12, + 57, -39, 26, 68, -52, 39, 78, -64, 51, 88, -74, 62, + 21, 37, -27, 28, 18, -15, 37, -3, -2, 47, -21, 13, + 58, -37, 27, 68, -50, 39, 78, -62, 52, 88, -73, 63, + 22, 39, -24, 29, 21, -14, 38, 1, 0, 48, -18, 13, + 58, -34, 27, 68, -48, 40, 78, -60, 52, 88, -72, 63, + 24, 41, -22, 30, 24, -12, 39, 4, 1, 48, -14, 14, + 59, -31, 28, 68, -45, 40, 78, -58, 52, 88, -70, 63, + 25, 43, -19, 31, 27, -10, 40, 8, 2, 49, -11, 15, + 59, -28, 29, 69, -43, 41, 79, -56, 53, 88, -68, 64, + 27, 45, -17, 33, 30, -8, 40, 11, 4, 50, -8, 16, + 59, -25, 29, 69, -40, 41, 79, -54, 53, 89, -66, 64, + 28, 47, -14, 34, 33, -6, 41, 14, 5, 50, -5, 17, + 60, -22, 30, 70, -38, 42, 79, -52, 54, 89, -64, 64, + 30, 50, -11, 35, 36, -4, 42, 18, 7, 51, -1, 19, + 61, -19, 31, 70, -34, 43, 80, -49, 54, 89, -61, 65, + 32, 52, -9, 36, 39, -2, 43, 21, 8, 52, 3, 20, + 61, -16, 32, 70, -31, 43, 80, -46, 55, 90, -59, 65, + 33, 54, -6, 38, 42, 0, 44, 24, 10, 53, 6, 21, + 62, -12, 33, 71, -28, 44, 81, -43, 55, 90, -57, 66, + 35, 56, -4, 39, 44, 2, 46, 28, 11, 53, 9, 22, + 62, -9, 34, 72, -25, 45, 81, -41, 56, 90, -54, 66, + 37, 58, -1, 41, 47, 5, 47, 31, 13, 54, 13, 24, + 63, -5, 35, 72, -22, 46, 82, -37, 57, 91, -51, 67, + 38, 60, 2, 42, 50, 7, 48, 34, 15, 55, 17, 25, + 64, -2, 36, 73, -19, 47, 82, -34, 57, 91, -48, 67, + 40, 62, 4, 43, 52, 9, 49, 37, 17, 56, 20, 26, + 65, 2, 37, 73, -15, 47, 82, -31, 58, 91, -46, 68, + 42, 64, 7, 45, 55, 11, 50, 40, 19, 57, 23, 28, + 65, 5, 38, 74, -12, 48, 83, -28, 59, 92, -43, 68, + 43, 66, 9, 46, 57, 14, 52, 43, 21, 58, 26, 29, + 66, 8, 39, 75, -9, 49, 84, -25, 59, 92, -40, 69, + 45, 68, 12, 48, 60, 16, 53, 46, 23, 59, 30, 31, + 67, 12, 41, 75, -5, 50, 84, -21, 60, 93, -36, 70, + 47, 70, 14, 49, 62, 18, 54, 49, 25, 61, 33, 33, + 68, 16, 42, 76, -1, 51, 85, -18, 61, 93, -33, 70, + 48, 72, 17, 51, 65, 21, 55, 52, 27, 62, 36, 34, + 69, 19, 43, 77, 2, 53, 85, -15, 62, 94, -30, 71, + 50, 74, 19, 52, 67, 23, 57, 55, 28, 63, 40, 36, + 70, 22, 45, 78, 5, 54, 86, -12, 63, 95, -27, 72, + 52, 76, 22, 54, 69, 25, 58, 58, 31, 64, 43, 38, + 71, 26, 46, 79, 9, 55, 87, -8, 64, 95, -24, 73, + 53, 78, 24, 56, 72, 27, 60, 60, 33, 65, 46, 39, + 72, 29, 48, 79, 12, 56, 88, -5, 65, 96, -20, 74, + 55, 80, 27, 57, 74, 30, 61, 63, 35, 66, 49, 41, + 73, 32, 49, 80, 16, 57, 88, -1, 66, 96, -17, 74, + 13, 25, -46, 23, 1, -29, 34, -19, -12, 45, -34, 4, + 56, -48, 19, 67, -59, 33, 77, -70, 46, 87, -79, 58, + 13, 26, -45, 23, 2, -29, 34, -18, -12, 45, -34, 4, + 56, -48, 19, 67, -59, 33, 77, -70, 46, 87, -79, 58, + 14, 27, -45, 23, 3, -29, 34, -17, -12, 45, -33, 4, + 56, -47, 20, 67, -59, 33, 77, -69, 46, 87, -79, 58, + 14, 28, -44, 24, 4, -28, 35, -16, -12, 45, -32, 4, + 56, -46, 20, 67, -58, 33, 77, -69, 46, 87, -79, 58, + 15, 29, -43, 24, 6, -28, 35, -15, -11, 45, -31, 5, + 56, -45, 20, 67, -57, 33, 77, -68, 46, 87, -78, 58, + 16, 30, -41, 25, 7, -27, 35, -13, -11, 46, -30, 5, + 57, -44, 20, 67, -56, 34, 77, -68, 47, 87, -77, 58, + 17, 31, -40, 25, 10, -26, 35, -11, -10, 46, -28, 5, + 57, -43, 20, 67, -55, 34, 77, -67, 47, 87, -77, 58, + 18, 33, -38, 26, 12, -25, 36, -8, -9, 46, -26, 6, + 57, -41, 21, 67, -54, 34, 78, -65, 47, 87, -76, 58, + 19, 35, -36, 27, 15, -23, 36, -6, -9, 47, -24, 6, + 57, -39, 21, 67, -52, 34, 78, -64, 47, 88, -75, 59, + 20, 37, -34, 28, 17, -22, 37, -3, -8, 47, -21, 7, + 58, -37, 22, 68, -51, 35, 78, -63, 47, 88, -73, 59, + 21, 39, -32, 28, 20, -21, 38, 0, -7, 47, -19, 8, + 58, -35, 22, 68, -49, 35, 78, -61, 48, 88, -72, 59, + 23, 40, -30, 29, 23, -19, 38, 3, -6, 48, -16, 8, + 58, -33, 23, 68, -47, 36, 78, -59, 48, 88, -71, 59, + 24, 43, -27, 31, 26, -17, 39, 6, -4, 49, -13, 9, + 59, -30, 23, 69, -44, 36, 79, -57, 48, 88, -69, 60, + 26, 45, -24, 32, 29, -15, 40, 9, -3, 49, -10, 10, + 59, -27, 24, 69, -42, 37, 79, -55, 49, 88, -67, 60, + 27, 47, -22, 33, 31, -13, 41, 12, -2, 50, -6, 11, + 60, -24, 25, 69, -39, 37, 79, -53, 49, 89, -65, 60, + 29, 49, -20, 34, 34, -11, 42, 16, 0, 50, -3, 12, + 60, -21, 25, 70, -36, 38, 79, -51, 50, 89, -63, 61, + 31, 51, -17, 35, 37, -9, 43, 19, 1, 51, 0, 14, + 61, -18, 26, 70, -33, 38, 80, -48, 50, 89, -61, 61, + 32, 53, -14, 37, 40, -7, 44, 22, 3, 52, 4, 15, + 61, -14, 27, 71, -30, 39, 80, -45, 51, 90, -58, 62, + 34, 55, -12, 38, 43, -5, 45, 26, 5, 53, 7, 16, + 62, -11, 28, 71, -27, 40, 81, -43, 51, 90, -56, 62, + 35, 57, -9, 39, 45, -3, 46, 29, 6, 54, 10, 17, + 63, -8, 29, 72, -24, 41, 81, -40, 52, 90, -53, 62, + 37, 59, -6, 41, 48, 0, 47, 32, 8, 55, 14, 19, + 63, -4, 30, 72, -21, 41, 82, -37, 53, 91, -50, 63, + 39, 61, -4, 42, 51, 2, 48, 35, 10, 56, 18, 20, + 64, -1, 31, 73, -18, 42, 82, -34, 53, 91, -48, 64, + 40, 63, -1, 44, 53, 4, 49, 38, 12, 56, 21, 22, + 65, 3, 33, 73, -14, 43, 83, -31, 54, 92, -45, 64, + 42, 65, 1, 45, 56, 6, 51, 41, 14, 57, 24, 23, + 66, 6, 34, 74, -11, 44, 83, -27, 55, 92, -42, 65, + 43, 67, 4, 47, 58, 8, 52, 44, 16, 58, 27, 25, + 66, 9, 35, 75, -8, 45, 84, -24, 56, 92, -39, 65, + 45, 69, 7, 48, 61, 11, 53, 47, 18, 60, 31, 26, + 67, 13, 36, 76, -4, 46, 84, -21, 57, 93, -36, 66, + 47, 71, 9, 50, 63, 13, 54, 50, 20, 61, 34, 28, + 68, 16, 38, 76, -1, 47, 85, -18, 57, 94, -33, 67, + 48, 73, 12, 51, 65, 15, 56, 53, 22, 62, 37, 30, + 69, 20, 39, 77, 3, 48, 86, -14, 58, 94, -30, 68, + 50, 75, 14, 53, 67, 18, 57, 55, 23, 63, 40, 31, + 70, 23, 40, 78, 6, 49, 86, -11, 59, 95, -27, 68, + 52, 77, 17, 54, 70, 20, 58, 58, 26, 64, 44, 33, + 71, 26, 42, 79, 10, 51, 87, -7, 60, 95, -23, 69, + 53, 79, 19, 56, 72, 22, 60, 61, 28, 65, 46, 35, + 72, 30, 43, 79, 13, 52, 88, -4, 61, 96, -20, 70, + 55, 81, 22, 57, 74, 25, 61, 63, 30, 66, 49, 36, + 73, 33, 45, 80, 16, 53, 88, -1, 62, 96, -17, 71, + 14, 29, -50, 24, 5, -34, 34, -16, -17, 45, -32, 0, + 56, -46, 15, 67, -58, 29, 77, -69, 42, 87, -78, 54, + 14, 29, -49, 24, 5, -33, 35, -15, -17, 45, -32, 0, + 56, -46, 15, 67, -58, 29, 77, -68, 42, 87, -78, 54, + 15, 30, -49, 24, 6, -33, 35, -14, -16, 45, -31, 0, + 56, -45, 15, 67, -57, 29, 77, -68, 43, 87, -78, 54, + 15, 31, -48, 24, 7, -33, 35, -13, -16, 46, -30, 0, + 56, -45, 15, 67, -57, 29, 77, -68, 43, 87, -78, 55, + 16, 31, -47, 25, 9, -32, 35, -12, -16, 46, -29, 0, + 57, -44, 16, 67, -56, 30, 77, -67, 43, 87, -77, 55, + 16, 33, -45, 25, 10, -31, 35, -10, -15, 46, -28, 1, + 57, -43, 16, 67, -55, 30, 77, -66, 43, 87, -77, 55, + 17, 34, -44, 26, 12, -30, 36, -9, -15, 46, -26, 1, + 57, -41, 16, 67, -54, 30, 78, -65, 43, 87, -76, 55, + 18, 35, -42, 26, 15, -29, 36, -6, -14, 46, -24, 1, + 57, -39, 17, 67, -52, 30, 78, -64, 43, 87, -75, 55, + 20, 37, -40, 27, 17, -28, 37, -4, -13, 47, -22, 2, + 57, -38, 17, 68, -51, 30, 78, -63, 43, 88, -74, 55, + 21, 39, -38, 28, 19, -27, 37, -1, -12, 47, -20, 3, + 58, -36, 17, 68, -49, 31, 78, -62, 44, 88, -73, 55, + 22, 40, -36, 29, 22, -25, 38, 2, -11, 48, -17, 3, + 58, -34, 18, 68, -47, 31, 78, -60, 44, 88, -71, 56, + 23, 42, -34, 30, 25, -24, 39, 4, -10, 48, -14, 4, + 58, -31, 18, 68, -45, 32, 78, -58, 44, 88, -70, 56, + 25, 44, -31, 31, 28, -22, 39, 8, -9, 49, -11, 5, + 59, -28, 19, 69, -43, 32, 79, -56, 45, 88, -68, 56, + 26, 46, -29, 32, 30, -20, 40, 11, -8, 49, -8, 6, + 59, -26, 20, 69, -41, 33, 79, -54, 45, 89, -66, 57, + 28, 48, -27, 33, 33, -18, 41, 14, -6, 50, -5, 7, + 60, -23, 20, 69, -38, 33, 79, -52, 46, 89, -64, 57, + 29, 50, -24, 34, 36, -16, 42, 17, -5, 51, -2, 8, + 60, -20, 21, 70, -35, 34, 80, -50, 46, 89, -62, 57, + 31, 52, -21, 36, 39, -14, 43, 21, -3, 51, 2, 9, + 61, -16, 22, 70, -32, 34, 80, -47, 47, 89, -60, 58, + 32, 54, -19, 37, 41, -12, 44, 24, -2, 52, 5, 10, + 61, -13, 23, 71, -29, 35, 80, -44, 47, 90, -57, 58, + 34, 56, -16, 38, 44, -10, 45, 27, 0, 53, 8, 12, + 62, -10, 24, 71, -26, 36, 81, -42, 48, 90, -55, 59, + 36, 58, -14, 40, 46, -8, 46, 30, 2, 54, 12, 13, + 63, -7, 25, 72, -23, 37, 81, -39, 48, 90, -53, 59, + 37, 60, -11, 41, 49, -5, 47, 33, 4, 55, 15, 14, + 63, -3, 26, 72, -20, 38, 82, -36, 49, 91, -50, 60, + 39, 62, -8, 43, 51, -3, 48, 36, 6, 56, 18, 16, + 64, 0, 27, 73, -17, 38, 82, -33, 50, 91, -47, 60, + 40, 64, -6, 44, 54, -1, 50, 39, 7, 57, 22, 17, + 65, 3, 28, 74, -14, 39, 83, -30, 50, 92, -44, 61, + 42, 66, -3, 45, 56, 2, 51, 42, 9, 58, 25, 19, + 66, 7, 30, 74, -10, 40, 83, -27, 51, 92, -41, 62, + 44, 68, -1, 47, 59, 4, 52, 45, 11, 59, 28, 20, + 67, 10, 31, 75, -7, 41, 84, -24, 52, 93, -39, 62, + 45, 70, 2, 48, 61, 6, 53, 48, 13, 60, 32, 22, + 67, 14, 32, 76, -3, 42, 84, -20, 53, 93, -35, 63, + 47, 72, 4, 50, 63, 9, 55, 51, 15, 61, 35, 24, + 68, 17, 33, 76, 0, 43, 85, -17, 54, 94, -32, 64, + 49, 73, 7, 51, 66, 11, 56, 53, 17, 62, 38, 25, + 69, 20, 35, 77, 3, 45, 86, -14, 55, 94, -29, 64, + 50, 75, 9, 53, 68, 13, 57, 56, 19, 63, 41, 27, + 70, 24, 36, 78, 7, 46, 86, -10, 56, 95, -26, 65, + 52, 77, 12, 54, 70, 16, 59, 59, 21, 64, 44, 29, + 71, 27, 38, 79, 10, 47, 87, -7, 57, 95, -23, 66, + 53, 79, 15, 56, 73, 18, 60, 61, 23, 65, 47, 30, + 72, 30, 39, 80, 13, 48, 88, -4, 58, 96, -19, 67, + 55, 81, 17, 57, 75, 20, 61, 64, 25, 67, 50, 32, + 73, 33, 41, 80, 17, 49, 88, 0, 59, 97, -16, 68, + 15, 32, -53, 24, 8, -38, 35, -13, -21, 46, -30, -5, + 56, -44, 11, 67, -56, 25, 77, -67, 39, 87, -77, 51, + 15, 32, -53, 24, 9, -38, 35, -12, -21, 46, -29, -5, + 56, -44, 11, 67, -56, 25, 77, -67, 39, 87, -77, 51, + 15, 33, -52, 25, 10, -37, 35, -11, -21, 46, -29, -5, + 57, -43, 11, 67, -56, 25, 77, -67, 39, 87, -77, 51, + 16, 33, -51, 25, 11, -37, 35, -10, -21, 46, -28, -4, + 57, -43, 11, 67, -55, 25, 77, -66, 39, 87, -77, 51, + 17, 34, -50, 25, 12, -36, 35, -9, -20, 46, -27, -4, + 57, -42, 11, 67, -54, 25, 77, -66, 39, 87, -76, 51, + 17, 35, -49, 26, 13, -35, 36, -8, -20, 46, -25, -4, + 57, -41, 12, 67, -53, 26, 78, -65, 39, 87, -75, 51, + 18, 36, -48, 26, 15, -35, 36, -6, -19, 46, -24, -3, + 57, -39, 12, 67, -52, 26, 78, -64, 39, 87, -75, 51, + 19, 38, -46, 27, 17, -33, 37, -4, -18, 47, -22, -3, + 57, -38, 12, 67, -51, 26, 78, -63, 39, 88, -74, 52, + 20, 39, -44, 28, 20, -32, 37, -1, -18, 47, -20, -2, + 58, -36, 13, 68, -49, 26, 78, -62, 40, 88, -73, 52, + 21, 41, -42, 28, 22, -31, 38, 1, -17, 47, -18, -2, + 58, -34, 13, 68, -48, 27, 78, -60, 40, 88, -72, 52, + 23, 42, -40, 29, 24, -29, 38, 4, -16, 48, -15, -1, + 58, -32, 14, 68, -46, 27, 78, -59, 40, 88, -70, 52, + 24, 44, -38, 30, 27, -28, 39, 6, -15, 48, -12, 0, + 59, -30, 14, 68, -44, 28, 79, -57, 41, 88, -69, 52, + 25, 46, -36, 31, 29, -26, 40, 10, -13, 49, -9, 1, + 59, -27, 15, 69, -42, 28, 79, -55, 41, 88, -67, 53, + 27, 48, -33, 32, 32, -24, 40, 13, -12, 50, -6, 2, + 59, -24, 16, 69, -39, 29, 79, -53, 41, 89, -65, 53, + 28, 49, -31, 34, 34, -22, 41, 16, -11, 50, -3, 3, + 60, -21, 16, 69, -37, 29, 79, -51, 42, 89, -63, 53, + 30, 51, -29, 35, 37, -21, 42, 19, -9, 51, 0, 4, + 60, -19, 17, 70, -34, 30, 80, -49, 42, 89, -61, 54, + 31, 53, -26, 36, 40, -18, 43, 22, -8, 52, 3, 5, + 61, -15, 18, 70, -31, 30, 80, -46, 43, 89, -59, 54, + 33, 55, -23, 37, 42, -16, 44, 25, -6, 52, 6, 6, + 62, -12, 19, 71, -28, 31, 80, -43, 43, 90, -57, 55, + 34, 57, -21, 39, 45, -14, 45, 28, -4, 53, 9, 7, + 62, -9, 20, 71, -25, 32, 81, -41, 44, 90, -54, 55, + 36, 59, -18, 40, 47, -12, 46, 31, -3, 54, 13, 9, + 63, -6, 21, 72, -22, 33, 81, -38, 45, 90, -52, 56, + 38, 61, -15, 41, 50, -10, 47, 34, -1, 55, 16, 10, + 64, -2, 22, 72, -19, 34, 82, -35, 45, 91, -49, 56, + 39, 63, -13, 43, 52, -7, 49, 37, 1, 56, 20, 11, + 64, 1, 23, 73, -16, 35, 82, -32, 46, 91, -46, 57, + 41, 65, -10, 44, 55, -5, 50, 40, 3, 57, 23, 13, + 65, 4, 24, 74, -13, 35, 83, -29, 47, 92, -43, 57, + 42, 66, -8, 46, 57, -3, 51, 43, 5, 58, 26, 14, + 66, 8, 25, 74, -9, 36, 83, -26, 48, 92, -41, 58, + 44, 68, -5, 47, 59, -1, 52, 46, 7, 59, 29, 16, + 67, 11, 27, 75, -6, 37, 84, -23, 48, 93, -38, 59, + 46, 70, -3, 49, 62, 2, 53, 49, 9, 60, 32, 18, + 68, 15, 28, 76, -3, 38, 84, -19, 49, 93, -35, 60, + 47, 72, 0, 50, 64, 4, 55, 51, 11, 61, 36, 19, + 68, 18, 29, 76, 1, 40, 85, -16, 50, 94, -32, 60, + 49, 74, 2, 51, 66, 6, 56, 54, 13, 62, 39, 21, + 69, 21, 31, 77, 4, 41, 86, -13, 51, 94, -28, 61, + 50, 76, 5, 53, 69, 8, 57, 57, 15, 63, 41, 23, + 70, 24, 32, 78, 7, 42, 86, -10, 52, 95, -25, 62, + 52, 78, 8, 55, 71, 11, 59, 60, 17, 64, 45, 24, + 71, 28, 34, 79, 11, 43, 87, -6, 53, 95, -22, 63, + 54, 80, 10, 56, 73, 13, 60, 62, 19, 66, 48, 26, + 72, 31, 35, 80, 14, 44, 88, -3, 54, 96, -19, 64, + 55, 82, 12, 57, 75, 16, 61, 65, 21, 67, 50, 28, + 73, 34, 36, 81, 17, 45, 89, 0, 55, 97, -16, 64, + 16, 35, -57, 25, 12, -42, 35, -9, -26, 46, -27, -9, + 57, -42, 7, 67, -55, 21, 77, -66, 35, 87, -76, 47, + 16, 35, -56, 25, 12, -42, 35, -9, -25, 46, -27, -9, + 57, -42, 7, 67, -54, 21, 77, -66, 35, 87, -76, 47, + 16, 36, -56, 25, 13, -41, 35, -8, -25, 46, -26, -9, + 57, -41, 7, 67, -54, 21, 77, -66, 35, 87, -76, 47, + 17, 36, -55, 25, 14, -41, 36, -7, -25, 46, -25, -9, + 57, -41, 7, 67, -53, 21, 77, -65, 35, 87, -75, 47, + 17, 37, -54, 26, 15, -40, 36, -6, -24, 46, -24, -9, + 57, -40, 7, 67, -53, 21, 78, -64, 35, 87, -75, 48, + 18, 38, -53, 26, 17, -40, 36, -5, -24, 46, -23, -8, + 57, -39, 7, 67, -52, 22, 78, -64, 35, 87, -74, 48, + 19, 39, -51, 27, 18, -39, 36, -3, -23, 47, -21, -8, + 57, -37, 8, 67, -51, 22, 78, -63, 35, 88, -74, 48, + 20, 40, -50, 27, 20, -38, 37, -1, -23, 47, -20, -7, + 58, -36, 8, 68, -49, 22, 78, -62, 36, 88, -73, 48, + 21, 41, -48, 28, 22, -36, 37, 1, -22, 47, -18, -7, + 58, -34, 8, 68, -48, 22, 78, -61, 36, 88, -72, 48, + 22, 43, -46, 29, 24, -35, 38, 4, -21, 48, -15, -6, + 58, -32, 9, 68, -46, 23, 78, -59, 36, 88, -70, 48, + 23, 44, -44, 30, 26, -34, 38, 6, -20, 48, -13, -5, + 58, -30, 9, 68, -45, 23, 78, -58, 36, 88, -69, 49, + 25, 46, -42, 31, 29, -32, 39, 9, -19, 49, -11, -5, + 59, -28, 10, 69, -43, 24, 79, -56, 37, 88, -68, 49, + 26, 47, -40, 32, 31, -30, 40, 12, -18, 49, -8, -4, + 59, -25, 11, 69, -40, 24, 79, -54, 37, 88, -66, 49, + 27, 49, -37, 33, 34, -29, 41, 14, -16, 50, -5, -3, + 60, -23, 11, 69, -38, 25, 79, -52, 38, 89, -64, 50, + 29, 51, -35, 34, 36, -27, 42, 17, -15, 50, -2, -2, + 60, -20, 12, 70, -35, 25, 79, -50, 38, 89, -62, 50, + 30, 52, -33, 35, 39, -25, 42, 20, -14, 51, 1, -1, + 61, -17, 13, 70, -33, 26, 80, -48, 38, 89, -60, 50, + 32, 54, -30, 36, 41, -23, 43, 23, -12, 52, 5, 0, + 61, -14, 14, 70, -30, 26, 80, -45, 39, 90, -58, 51, + 33, 56, -28, 38, 44, -21, 44, 26, -10, 53, 8, 2, + 62, -11, 15, 71, -27, 27, 81, -42, 40, 90, -56, 51, + 35, 58, -25, 39, 46, -19, 45, 29, -9, 53, 11, 3, + 62, -8, 16, 71, -24, 28, 81, -40, 40, 90, -53, 52, + 36, 60, -23, 40, 48, -17, 47, 32, -7, 54, 14, 4, + 63, -5, 17, 72, -21, 29, 81, -37, 41, 91, -51, 52, + 38, 62, -20, 42, 51, -14, 48, 35, -5, 55, 17, 6, + 64, -1, 18, 73, -18, 30, 82, -34, 42, 91, -48, 53, + 40, 64, -17, 43, 53, -12, 49, 38, -3, 56, 21, 7, + 65, 2, 19, 73, -15, 30, 82, -31, 42, 91, -45, 53, + 41, 65, -15, 44, 56, -10, 50, 41, -2, 57, 24, 9, + 65, 5, 20, 74, -12, 31, 83, -28, 43, 92, -43, 54, + 43, 67, -12, 46, 58, -8, 51, 44, 0, 58, 27, 10, + 66, 9, 21, 74, -9, 32, 83, -25, 44, 92, -40, 55, + 44, 69, -10, 47, 60, -5, 52, 47, 2, 59, 30, 12, + 67, 12, 22, 75, -5, 33, 84, -22, 45, 93, -37, 55, + 46, 71, -7, 49, 63, -3, 54, 50, 4, 60, 33, 13, + 68, 15, 24, 76, -2, 35, 85, -19, 46, 93, -34, 56, + 47, 73, -5, 50, 65, -1, 55, 52, 6, 61, 36, 15, + 69, 19, 25, 77, 1, 36, 85, -15, 46, 94, -31, 57, + 49, 75, -2, 52, 67, 2, 56, 55, 8, 62, 39, 17, + 70, 22, 26, 77, 5, 37, 86, -12, 47, 94, -28, 58, + 51, 77, 0, 53, 69, 4, 57, 57, 10, 63, 42, 18, + 70, 25, 28, 78, 8, 38, 86, -9, 48, 95, -25, 58, + 52, 79, 3, 55, 72, 6, 59, 60, 12, 65, 45, 20, + 71, 28, 29, 79, 12, 39, 87, -5, 49, 95, -21, 59, + 54, 80, 5, 56, 74, 9, 60, 63, 14, 66, 48, 22, + 72, 32, 31, 80, 15, 40, 88, -2, 50, 96, -18, 60, + 55, 82, 8, 58, 76, 11, 62, 65, 16, 67, 51, 24, + 73, 35, 32, 81, 18, 42, 89, 1, 51, 97, -15, 61, + 17, 38, -60, 26, 16, -46, 36, -6, -30, 46, -24, -14, + 57, -40, 2, 67, -53, 16, 77, -64, 30, 87, -75, 43, + 17, 38, -60, 26, 16, -46, 36, -5, -30, 46, -24, -14, + 57, -39, 2, 67, -52, 17, 78, -64, 31, 87, -75, 43, + 18, 39, -60, 26, 17, -46, 36, -5, -30, 46, -23, -14, + 57, -39, 2, 67, -52, 17, 78, -64, 31, 87, -74, 43, + 18, 39, -59, 26, 18, -45, 36, -4, -30, 46, -22, -14, + 57, -38, 2, 67, -51, 17, 78, -63, 31, 87, -74, 43, + 19, 40, -58, 26, 19, -45, 36, -3, -29, 47, -21, -13, + 57, -37, 2, 67, -51, 17, 78, -63, 31, 87, -74, 43, + 19, 41, -57, 27, 20, -44, 37, -1, -29, 47, -20, -13, + 57, -36, 3, 67, -50, 17, 78, -62, 31, 88, -73, 44, + 20, 41, -56, 27, 21, -43, 37, 0, -28, 47, -19, -13, + 57, -35, 3, 68, -49, 17, 78, -61, 31, 88, -72, 44, + 21, 43, -54, 28, 23, -42, 37, 2, -28, 47, -17, -12, + 58, -34, 3, 68, -47, 17, 78, -60, 31, 88, -71, 44, + 22, 44, -52, 29, 25, -41, 38, 4, -27, 48, -15, -12, + 58, -32, 4, 68, -46, 18, 78, -59, 32, 88, -70, 44, + 23, 45, -51, 30, 27, -40, 38, 6, -26, 48, -13, -11, + 58, -30, 4, 68, -45, 18, 78, -58, 32, 88, -69, 44, + 24, 46, -49, 30, 29, -38, 39, 9, -25, 48, -11, -10, + 59, -28, 5, 68, -43, 18, 79, -56, 32, 88, -68, 44, + 25, 48, -47, 31, 31, -37, 40, 11, -24, 49, -8, -10, + 59, -26, 5, 69, -41, 19, 79, -54, 32, 88, -66, 45, + 27, 49, -44, 32, 34, -35, 40, 14, -23, 49, -5, -9, + 59, -23, 6, 69, -39, 19, 79, -52, 33, 89, -65, 45, + 28, 51, -42, 33, 36, -33, 41, 17, -21, 50, -3, -8, + 60, -21, 7, 69, -36, 20, 79, -51, 33, 89, -63, 45, + 29, 52, -40, 34, 38, -32, 42, 19, -20, 51, 0, -7, + 60, -18, 7, 70, -34, 21, 80, -48, 34, 89, -61, 46, + 31, 54, -38, 36, 40, -30, 43, 22, -19, 51, 3, -6, + 61, -15, 8, 70, -31, 21, 80, -46, 34, 89, -59, 46, + 32, 56, -35, 37, 43, -28, 44, 25, -17, 52, 6, -4, + 61, -12, 9, 71, -28, 22, 80, -44, 35, 90, -57, 47, + 34, 58, -33, 38, 45, -26, 45, 28, -15, 53, 9, -3, + 62, -9, 10, 71, -26, 23, 81, -41, 35, 90, -55, 47, + 35, 59, -30, 39, 48, -24, 46, 31, -14, 54, 12, -2, + 63, -6, 11, 72, -23, 23, 81, -39, 36, 90, -52, 48, + 37, 61, -28, 41, 50, -22, 47, 34, -12, 54, 15, -1, + 63, -3, 12, 72, -20, 24, 82, -36, 37, 91, -50, 48, + 38, 63, -25, 42, 52, -19, 48, 37, -10, 55, 19, 1, + 64, 0, 13, 73, -17, 25, 82, -33, 37, 91, -47, 49, + 40, 65, -22, 43, 55, -17, 49, 40, -8, 56, 22, 2, + 65, 3, 14, 73, -14, 26, 82, -30, 38, 91, -44, 49, + 41, 66, -20, 45, 57, -15, 50, 42, -7, 57, 25, 4, + 65, 7, 15, 74, -11, 27, 83, -27, 39, 92, -42, 50, + 43, 68, -17, 46, 59, -13, 51, 45, -5, 58, 28, 5, + 66, 10, 16, 75, -7, 28, 84, -24, 40, 92, -39, 51, + 45, 70, -15, 48, 61, -10, 53, 48, -3, 59, 31, 7, + 67, 13, 18, 75, -4, 29, 84, -21, 40, 93, -36, 51, + 46, 72, -12, 49, 64, -8, 54, 51, -1, 60, 34, 8, + 68, 16, 19, 76, -1, 30, 85, -18, 41, 93, -33, 52, + 48, 74, -10, 51, 66, -6, 55, 53, 1, 61, 37, 10, + 69, 20, 20, 77, 2, 31, 85, -14, 42, 94, -30, 53, + 49, 76, -7, 52, 68, -3, 56, 56, 3, 62, 40, 12, + 70, 23, 22, 77, 6, 32, 86, -11, 43, 94, -27, 54, + 51, 77, -5, 53, 70, -1, 58, 58, 5, 63, 43, 13, + 71, 26, 23, 78, 9, 33, 87, -8, 44, 95, -24, 54, + 53, 79, -2, 55, 72, 1, 59, 61, 7, 65, 46, 15, + 72, 29, 25, 79, 12, 35, 87, -5, 45, 96, -20, 55, + 54, 81, 0, 56, 74, 4, 60, 63, 9, 66, 49, 17, + 73, 32, 26, 80, 16, 36, 88, -1, 46, 96, -17, 56, + 56, 83, 3, 58, 76, 6, 62, 66, 11, 67, 52, 19, + 74, 35, 28, 81, 19, 37, 89, 2, 47, 97, -14, 57, + 18, 41, -64, 26, 19, -50, 36, -3, -35, 46, -21, -18, + 57, -37, -2, 67, -51, 12, 78, -63, 27, 87, -74, 39, + 18, 41, -63, 26, 20, -50, 36, -2, -34, 46, -21, -18, + 57, -37, -2, 67, -50, 12, 78, -63, 27, 87, -73, 40, + 19, 42, -63, 27, 20, -50, 36, -2, -34, 47, -20, -18, + 57, -37, -2, 67, -50, 12, 78, -62, 27, 87, -73, 40, + 19, 42, -62, 27, 21, -49, 36, -1, -34, 47, -20, -18, + 57, -36, -2, 67, -49, 13, 78, -62, 27, 88, -73, 40, + 20, 42, -61, 27, 22, -49, 37, 0, -34, 47, -19, -18, + 57, -35, -2, 68, -49, 13, 78, -61, 27, 88, -72, 40, + 20, 43, -60, 28, 23, -48, 37, 2, -33, 47, -17, -17, + 58, -34, -2, 68, -48, 13, 78, -61, 27, 88, -72, 40, + 21, 44, -59, 28, 24, -47, 37, 3, -32, 47, -16, -17, + 58, -33, -1, 68, -47, 13, 78, -60, 27, 88, -71, 40, + 22, 45, -58, 29, 26, -46, 38, 5, -32, 48, -14, -16, + 58, -31, -1, 68, -46, 13, 78, -59, 27, 88, -70, 40, + 23, 46, -56, 29, 28, -45, 38, 7, -31, 48, -13, -16, + 58, -30, -1, 68, -44, 14, 78, -57, 28, 88, -69, 40, + 24, 47, -54, 30, 29, -44, 39, 9, -30, 48, -11, -15, + 58, -28, 0, 68, -43, 14, 78, -56, 28, 88, -68, 41, + 25, 48, -53, 31, 31, -43, 39, 11, -29, 49, -8, -15, + 59, -26, 0, 69, -41, 14, 79, -55, 28, 88, -67, 41, + 26, 50, -51, 32, 33, -41, 40, 13, -28, 49, -6, -14, + 59, -24, 1, 69, -39, 15, 79, -53, 28, 88, -65, 41, + 27, 51, -48, 33, 36, -39, 41, 16, -27, 50, -3, -13, + 60, -21, 2, 69, -37, 15, 79, -51, 29, 89, -63, 41, + 29, 52, -46, 34, 38, -38, 41, 19, -26, 50, -1, -12, + 60, -19, 2, 70, -35, 16, 79, -49, 29, 89, -62, 42, + 30, 54, -44, 35, 40, -36, 42, 21, -24, 51, 2, -11, + 60, -16, 3, 70, -32, 16, 80, -47, 30, 89, -60, 42, + 31, 55, -42, 36, 42, -34, 43, 24, -23, 52, 5, -10, + 61, -14, 4, 70, -30, 17, 80, -45, 30, 89, -58, 42, + 33, 57, -39, 37, 44, -32, 44, 27, -21, 52, 8, -9, + 62, -11, 5, 71, -27, 18, 80, -42, 31, 90, -56, 43, + 34, 59, -37, 39, 47, -30, 45, 30, -20, 53, 11, -8, + 62, -8, 6, 71, -24, 18, 81, -40, 31, 90, -53, 43, + 36, 60, -34, 40, 49, -28, 46, 32, -18, 54, 14, -6, + 63, -5, 7, 72, -22, 19, 81, -37, 32, 90, -51, 44, + 37, 62, -32, 41, 51, -26, 47, 35, -16, 55, 17, -5, + 63, -2, 8, 72, -19, 20, 82, -35, 33, 91, -49, 44, + 39, 64, -29, 42, 54, -23, 48, 38, -15, 56, 20, -4, + 64, 2, 9, 73, -15, 21, 82, -32, 33, 91, -46, 45, + 40, 66, -27, 44, 56, -21, 49, 41, -13, 57, 23, -2, + 65, 5, 10, 73, -12, 22, 83, -29, 34, 92, -43, 46, + 42, 67, -24, 45, 58, -19, 51, 43, -11, 57, 26, -1, + 66, 8, 11, 74, -9, 23, 83, -26, 35, 92, -41, 46, + 43, 69, -22, 46, 60, -17, 52, 46, -9, 58, 29, 1, + 66, 11, 12, 75, -6, 24, 84, -23, 36, 92, -38, 47, + 45, 71, -19, 48, 62, -15, 53, 49, -7, 59, 32, 2, + 67, 14, 13, 75, -3, 25, 84, -20, 36, 93, -35, 48, + 47, 73, -17, 49, 65, -12, 54, 52, -5, 61, 35, 4, + 68, 17, 15, 76, 0, 26, 85, -17, 37, 93, -32, 48, + 48, 75, -14, 51, 67, -10, 55, 54, -3, 62, 38, 6, + 69, 21, 16, 77, 3, 27, 85, -14, 38, 94, -29, 49, + 50, 76, -12, 52, 69, -8, 57, 57, -1, 63, 41, 7, + 70, 24, 18, 78, 7, 28, 86, -10, 39, 94, -26, 50, + 51, 78, -9, 54, 71, -5, 58, 59, 1, 64, 44, 9, + 71, 27, 19, 78, 10, 29, 87, -7, 40, 95, -23, 51, + 53, 80, -7, 55, 73, -3, 59, 62, 3, 65, 47, 11, + 72, 30, 21, 79, 13, 31, 87, -4, 41, 96, -20, 52, + 54, 82, -4, 57, 75, -1, 61, 64, 5, 66, 50, 13, + 73, 33, 22, 80, 16, 32, 88, -1, 42, 96, -17, 52, + 56, 84, -2, 58, 77, 2, 62, 67, 7, 67, 53, 14, + 74, 36, 24, 81, 20, 33, 89, 2, 43, 97, -14, 53, + 19, 44, -67, 27, 23, -54, 37, 1, -39, 47, -18, -23, + 57, -35, -7, 67, -49, 8, 78, -61, 23, 88, -72, 36, + 19, 44, -67, 27, 23, -54, 37, 1, -38, 47, -18, -22, + 57, -35, -6, 68, -48, 8, 78, -61, 23, 88, -72, 36, + 20, 44, -66, 27, 23, -54, 37, 2, -38, 47, -17, -22, + 57, -34, -6, 68, -48, 8, 78, -61, 23, 88, -72, 36, + 20, 45, -65, 27, 24, -53, 37, 2, -38, 47, -17, -22, + 58, -34, -6, 68, -47, 8, 78, -60, 23, 88, -71, 36, + 20, 45, -65, 28, 25, -53, 37, 3, -38, 47, -16, -22, + 58, -33, -6, 68, -47, 9, 78, -60, 23, 88, -71, 36, + 21, 46, -64, 28, 26, -52, 37, 5, -37, 47, -15, -22, + 58, -32, -6, 68, -46, 9, 78, -59, 23, 88, -70, 36, + 22, 46, -63, 29, 27, -51, 38, 6, -37, 48, -14, -21, + 58, -31, -6, 68, -45, 9, 78, -58, 23, 88, -70, 36, + 23, 47, -61, 29, 29, -50, 38, 8, -36, 48, -12, -21, + 58, -29, -5, 68, -44, 9, 78, -57, 23, 88, -69, 36, + 24, 48, -60, 30, 30, -49, 39, 9, -35, 48, -10, -20, + 58, -28, -5, 68, -42, 10, 78, -56, 24, 88, -68, 37, + 24, 49, -58, 31, 32, -48, 39, 11, -34, 49, -8, -20, + 59, -26, -4, 69, -41, 10, 79, -55, 24, 88, -67, 37, + 26, 50, -56, 31, 34, -47, 40, 13, -33, 49, -6, -19, + 59, -24, -4, 69, -39, 10, 79, -53, 24, 88, -65, 37, + 27, 51, -54, 32, 35, -45, 40, 16, -32, 49, -4, -18, + 59, -22, -3, 69, -37, 11, 79, -52, 25, 89, -64, 37, + 28, 53, -52, 33, 38, -43, 41, 18, -31, 50, -1, -17, + 60, -20, -3, 69, -35, 11, 79, -50, 25, 89, -62, 38, + 29, 54, -50, 34, 40, -42, 42, 21, -30, 51, 1, -16, + 60, -17, -2, 70, -33, 12, 80, -48, 25, 89, -60, 38, + 30, 56, -48, 35, 42, -40, 43, 23, -29, 51, 4, -15, + 61, -15, -1, 70, -31, 12, 80, -46, 26, 89, -59, 38, + 32, 57, -46, 37, 44, -38, 43, 26, -27, 52, 7, -14, + 61, -12, 0, 71, -28, 13, 80, -44, 26, 90, -57, 39, + 33, 59, -43, 38, 46, -36, 45, 29, -26, 53, 10, -13, + 62, -9, 1, 71, -26, 14, 81, -41, 27, 90, -54, 39, + 35, 60, -41, 39, 48, -34, 45, 31, -24, 53, 13, -12, + 62, -6, 1, 71, -23, 14, 81, -39, 27, 90, -52, 40, + 36, 62, -39, 40, 50, -32, 46, 34, -22, 54, 15, -11, + 63, -3, 2, 72, -20, 15, 81, -36, 28, 91, -50, 40, + 38, 63, -36, 41, 52, -30, 47, 36, -21, 55, 18, -9, + 64, 0, 3, 72, -17, 16, 82, -33, 29, 91, -48, 41, + 39, 65, -33, 43, 55, -28, 49, 39, -19, 56, 22, -8, + 64, 3, 5, 73, -14, 17, 82, -30, 29, 91, -45, 41, + 41, 67, -31, 44, 57, -26, 50, 42, -17, 57, 25, -6, + 65, 6, 6, 74, -11, 18, 83, -28, 30, 92, -42, 42, + 42, 68, -29, 45, 59, -23, 51, 45, -15, 58, 27, -5, + 66, 9, 7, 74, -8, 19, 83, -25, 31, 92, -40, 43, + 44, 70, -26, 47, 61, -21, 52, 47, -13, 59, 30, -3, + 67, 12, 8, 75, -5, 20, 84, -22, 32, 93, -37, 43, + 45, 72, -24, 48, 63, -19, 53, 50, -12, 60, 33, -2, + 67, 15, 9, 76, -2, 21, 84, -19, 33, 93, -34, 44, + 47, 74, -21, 50, 66, -17, 54, 53, -9, 61, 36, 0, + 68, 19, 11, 76, 1, 22, 85, -16, 34, 94, -31, 45, + 48, 75, -19, 51, 68, -14, 56, 55, -7, 62, 39, 1, + 69, 22, 12, 77, 4, 23, 86, -13, 34, 94, -28, 45, + 50, 77, -16, 53, 70, -12, 57, 57, -6, 63, 42, 3, + 70, 25, 13, 78, 8, 24, 86, -10, 35, 95, -25, 46, + 51, 79, -14, 54, 72, -10, 58, 60, -4, 64, 45, 5, + 71, 28, 15, 79, 11, 25, 87, -6, 36, 95, -22, 47, + 53, 81, -11, 55, 74, -7, 60, 63, -1, 65, 48, 7, + 72, 31, 16, 79, 14, 27, 88, -3, 37, 96, -19, 48, + 55, 82, -8, 57, 76, -5, 61, 65, 1, 66, 51, 8, + 73, 34, 18, 80, 17, 28, 88, 0, 38, 96, -16, 49, + 56, 84, -6, 58, 78, -3, 62, 67, 3, 67, 53, 10, + 74, 37, 19, 81, 20, 29, 89, 3, 39, 97, -13, 50, + 20, 46, -70, 28, 26, -58, 37, 4, -43, 47, -15, -27, + 58, -32, -11, 68, -47, 4, 78, -59, 19, 88, -71, 32, + 20, 47, -70, 28, 26, -58, 37, 5, -42, 47, -15, -27, + 58, -32, -11, 68, -46, 4, 78, -59, 19, 88, -70, 32, + 21, 47, -69, 28, 27, -57, 37, 5, -42, 47, -15, -27, + 58, -32, -11, 68, -46, 4, 78, -59, 19, 88, -70, 32, + 21, 47, -69, 28, 27, -57, 37, 6, -42, 47, -14, -26, + 58, -31, -10, 68, -45, 4, 78, -58, 19, 88, -70, 32, + 21, 48, -68, 29, 28, -56, 38, 7, -42, 47, -13, -26, + 58, -30, -10, 68, -45, 4, 78, -58, 19, 88, -69, 32, + 22, 48, -67, 29, 29, -56, 38, 8, -41, 48, -12, -26, + 58, -29, -10, 68, -44, 5, 78, -57, 19, 88, -69, 32, + 23, 49, -66, 29, 30, -55, 38, 9, -41, 48, -11, -25, + 58, -28, -10, 68, -43, 5, 78, -56, 19, 88, -68, 32, + 24, 49, -65, 30, 31, -54, 39, 11, -40, 48, -9, -25, + 58, -27, -9, 68, -42, 5, 78, -55, 19, 88, -67, 33, + 24, 50, -63, 31, 33, -53, 39, 12, -39, 49, -8, -24, + 59, -25, -9, 69, -41, 5, 79, -54, 20, 88, -66, 33, + 25, 51, -62, 31, 34, -52, 40, 14, -38, 49, -6, -24, + 59, -24, -9, 69, -39, 6, 79, -53, 20, 88, -65, 33, + 26, 52, -60, 32, 36, -50, 40, 16, -37, 49, -4, -23, + 59, -22, -8, 69, -37, 6, 79, -52, 20, 89, -64, 33, + 27, 53, -58, 33, 38, -49, 41, 18, -36, 50, -2, -22, + 60, -20, -7, 69, -36, 7, 79, -50, 21, 89, -62, 33, + 29, 55, -56, 34, 40, -47, 42, 21, -35, 50, 1, -21, + 60, -18, -7, 70, -33, 7, 79, -48, 21, 89, -61, 34, + 30, 56, -54, 35, 42, -46, 42, 23, -34, 51, 3, -21, + 60, -15, -6, 70, -31, 8, 80, -46, 21, 89, -59, 34, + 31, 57, -52, 36, 44, -44, 43, 25, -33, 52, 6, -20, + 61, -13, -5, 70, -29, 8, 80, -44, 22, 89, -57, 35, + 32, 59, -50, 37, 46, -42, 44, 28, -31, 52, 9, -19, + 61, -10, -5, 71, -27, 9, 80, -42, 22, 90, -55, 35, + 34, 60, -47, 38, 48, -40, 45, 30, -30, 53, 12, -17, + 62, -7, -4, 71, -24, 10, 81, -40, 23, 90, -53, 35, + 35, 62, -45, 39, 50, -38, 46, 33, -28, 54, 14, -16, + 63, -5, -3, 72, -21, 10, 81, -37, 24, 90, -51, 36, + 37, 63, -43, 41, 52, -36, 47, 35, -27, 54, 17, -15, + 63, -2, -2, 72, -19, 11, 81, -35, 24, 91, -49, 36, + 38, 65, -40, 42, 54, -34, 48, 38, -25, 55, 20, -14, + 64, 1, -1, 73, -16, 12, 82, -32, 25, 91, -47, 37, + 40, 66, -38, 43, 56, -32, 49, 41, -23, 56, 23, -12, + 65, 4, 0, 73, -13, 13, 82, -29, 26, 91, -44, 38, + 41, 68, -35, 45, 58, -30, 50, 43, -21, 57, 26, -11, + 65, 7, 2, 74, -10, 14, 83, -27, 26, 92, -41, 38, + 43, 69, -33, 46, 60, -28, 51, 46, -20, 58, 29, -9, + 66, 10, 3, 74, -7, 15, 83, -24, 27, 92, -39, 39, + 44, 71, -30, 47, 62, -26, 52, 48, -18, 59, 32, -8, + 67, 13, 4, 75, -4, 16, 84, -21, 28, 93, -36, 39, + 46, 73, -28, 49, 64, -23, 53, 51, -16, 60, 34, -6, + 68, 16, 5, 76, -1, 17, 84, -18, 29, 93, -33, 40, + 47, 75, -25, 50, 66, -21, 55, 54, -14, 61, 38, -4, + 68, 20, 7, 76, 2, 18, 85, -15, 30, 94, -30, 41, + 49, 76, -23, 51, 68, -19, 56, 56, -12, 62, 40, -3, + 69, 23, 8, 77, 5, 19, 86, -12, 30, 94, -27, 42, + 50, 78, -20, 53, 70, -16, 57, 58, -10, 63, 43, -1, + 70, 26, 9, 78, 9, 20, 86, -9, 31, 95, -24, 42, + 52, 80, -18, 54, 72, -14, 58, 61, -8, 64, 46, 1, + 71, 29, 11, 79, 12, 21, 87, -6, 32, 95, -21, 43, + 53, 82, -15, 56, 75, -12, 60, 63, -6, 65, 49, 2, + 72, 32, 12, 80, 15, 23, 88, -2, 34, 96, -18, 44, + 55, 83, -13, 57, 77, -9, 61, 66, -4, 66, 52, 4, + 73, 35, 14, 80, 18, 24, 88, 1, 35, 96, -15, 45, + 56, 85, -10, 59, 79, -7, 62, 68, -2, 68, 54, 6, + 74, 38, 15, 81, 21, 25, 89, 4, 36, 97, -12, 46, + 21, 49, -74, 28, 30, -62, 38, 8, -47, 47, -12, -31, + 58, -29, -15, 68, -44, 0, 78, -57, 14, 88, -69, 28, + 22, 49, -73, 29, 30, -62, 38, 8, -47, 48, -12, -31, + 58, -29, -15, 68, -44, 0, 78, -57, 14, 88, -69, 28, + 22, 50, -73, 29, 30, -61, 38, 9, -47, 48, -11, -31, + 58, -29, -15, 68, -43, 0, 78, -57, 14, 88, -68, 28, + 22, 50, -72, 29, 31, -61, 38, 9, -46, 48, -11, -31, + 58, -28, -15, 68, -43, 0, 78, -56, 14, 88, -68, 28, + 23, 50, -72, 29, 32, -61, 38, 10, -46, 48, -10, -31, + 58, -28, -15, 68, -42, 0, 78, -56, 14, 88, -68, 28, + 23, 51, -71, 30, 32, -60, 38, 11, -46, 48, -9, -30, + 58, -27, -15, 68, -42, 0, 78, -55, 15, 88, -67, 28, + 24, 51, -70, 30, 33, -59, 39, 12, -45, 48, -8, -30, + 58, -26, -14, 68, -41, 0, 78, -54, 15, 88, -66, 28, + 25, 52, -68, 31, 35, -58, 39, 14, -44, 49, -6, -30, + 59, -24, -14, 69, -40, 1, 79, -53, 15, 88, -65, 28, + 25, 53, -67, 31, 36, -57, 40, 15, -44, 49, -5, -29, + 59, -23, -14, 69, -38, 1, 79, -52, 15, 88, -65, 28, + 26, 54, -65, 32, 37, -56, 40, 17, -43, 49, -3, -28, + 59, -21, -13, 69, -37, 1, 79, -51, 15, 89, -63, 29, + 27, 54, -64, 33, 39, -55, 41, 19, -42, 50, -1, -28, + 60, -19, -13, 69, -35, 2, 79, -50, 16, 89, -62, 29, + 28, 55, -62, 34, 40, -53, 41, 21, -41, 50, 1, -27, + 60, -18, -12, 69, -34, 2, 79, -48, 16, 89, -61, 29, + 29, 57, -60, 35, 42, -52, 42, 23, -40, 51, 4, -26, + 60, -15, -11, 70, -31, 3, 80, -46, 17, 89, -59, 30, + 31, 58, -58, 36, 44, -50, 43, 25, -39, 51, 6, -25, + 61, -13, -11, 70, -29, 3, 80, -44, 17, 89, -58, 30, + 32, 59, -56, 37, 46, -48, 44, 28, -37, 52, 8, -24, + 61, -11, -10, 71, -27, 4, 80, -42, 17, 90, -56, 30, + 33, 60, -54, 38, 48, -47, 44, 30, -36, 53, 11, -23, + 62, -8, -9, 71, -25, 4, 81, -40, 18, 90, -54, 31, + 35, 62, -52, 39, 50, -45, 45, 33, -34, 53, 14, -22, + 62, -5, -8, 71, -22, 5, 81, -38, 18, 90, -52, 31, + 36, 63, -49, 40, 52, -43, 46, 35, -33, 54, 16, -21, + 63, -3, -7, 72, -20, 6, 81, -36, 19, 90, -50, 32, + 37, 65, -47, 41, 53, -41, 47, 37, -31, 55, 19, -20, + 63, 0, -6, 72, -17, 6, 82, -33, 20, 91, -47, 32, + 39, 66, -45, 42, 55, -39, 48, 40, -30, 56, 22, -18, + 64, 3, -5, 73, -14, 7, 82, -31, 20, 91, -45, 33, + 40, 68, -42, 44, 58, -37, 49, 42, -28, 56, 25, -17, + 65, 6, -4, 73, -11, 8, 83, -28, 21, 92, -42, 33, + 42, 69, -40, 45, 60, -35, 50, 45, -26, 57, 28, -15, + 66, 9, -3, 74, -8, 9, 83, -25, 22, 92, -40, 34, + 43, 71, -37, 46, 62, -32, 51, 47, -24, 58, 30, -14, + 66, 12, -2, 75, -6, 10, 84, -22, 23, 92, -37, 34, + 45, 72, -35, 48, 64, -30, 53, 50, -22, 59, 33, -12, + 67, 15, -1, 75, -3, 11, 84, -20, 23, 93, -35, 35, + 46, 74, -33, 49, 65, -28, 54, 52, -21, 60, 36, -11, + 68, 18, 0, 76, 0, 12, 85, -17, 24, 93, -32, 36, + 48, 76, -30, 50, 68, -26, 55, 55, -18, 61, 39, -9, + 69, 21, 2, 77, 4, 13, 85, -13, 25, 94, -29, 37, + 49, 77, -28, 52, 70, -23, 56, 57, -17, 62, 42, -8, + 70, 24, 3, 77, 7, 14, 86, -10, 26, 94, -26, 37, + 51, 79, -25, 53, 72, -21, 57, 60, -15, 63, 44, -6, + 70, 27, 5, 78, 10, 15, 86, -7, 27, 95, -23, 38, + 52, 81, -23, 55, 73, -19, 59, 62, -13, 64, 47, -4, + 71, 30, 6, 79, 13, 17, 87, -4, 28, 95, -20, 39, + 54, 82, -20, 56, 76, -16, 60, 65, -10, 66, 50, -2, + 72, 33, 8, 80, 16, 18, 88, -1, 29, 96, -17, 40, + 55, 84, -18, 57, 78, -14, 61, 67, -8, 67, 53, -1, + 73, 36, 9, 81, 19, 19, 89, 2, 30, 97, -14, 41, + 57, 86, -15, 59, 79, -12, 63, 69, -6, 68, 55, 1, + 74, 39, 11, 81, 22, 20, 89, 5, 31, 97, -11, 42, + 23, 52, -77, 29, 33, -65, 38, 11, -51, 48, -9, -35, + 58, -27, -20, 68, -42, -5, 78, -55, 10, 88, -67, 24, + 23, 52, -76, 29, 33, -65, 38, 12, -51, 48, -9, -35, + 58, -26, -19, 68, -42, -5, 78, -55, 10, 88, -67, 24, + 23, 52, -76, 30, 33, -65, 38, 12, -51, 48, -8, -35, + 58, -26, -19, 68, -41, -4, 78, -55, 10, 88, -67, 24, + 23, 52, -75, 30, 34, -65, 38, 13, -50, 48, -8, -35, + 58, -26, -19, 68, -41, -4, 78, -54, 10, 88, -66, 24, + 24, 53, -75, 30, 35, -64, 39, 13, -50, 48, -7, -35, + 58, -25, -19, 68, -40, -4, 78, -54, 10, 88, -66, 24, + 24, 53, -74, 30, 35, -63, 39, 14, -50, 48, -6, -34, + 59, -24, -19, 68, -39, -4, 79, -53, 11, 88, -65, 24, + 25, 54, -73, 31, 36, -63, 39, 15, -49, 49, -5, -34, + 59, -23, -19, 69, -39, -4, 79, -53, 11, 88, -65, 24, + 25, 54, -72, 31, 37, -62, 40, 17, -48, 49, -3, -34, + 59, -22, -18, 69, -37, -4, 79, -52, 11, 88, -64, 24, + 26, 55, -70, 32, 38, -61, 40, 18, -48, 49, -2, -33, + 59, -20, -18, 69, -36, -3, 79, -50, 11, 89, -63, 25, + 27, 56, -69, 33, 40, -60, 41, 20, -47, 50, 0, -33, + 60, -19, -17, 69, -35, -3, 79, -49, 11, 89, -62, 25, + 28, 56, -67, 33, 41, -58, 41, 21, -46, 50, 2, -32, + 60, -17, -17, 69, -33, -3, 79, -48, 12, 89, -61, 25, + 29, 57, -66, 34, 43, -57, 42, 23, -45, 51, 4, -31, + 60, -15, -16, 70, -32, -2, 80, -46, 12, 89, -59, 25, + 30, 59, -64, 35, 44, -56, 42, 25, -44, 51, 6, -30, + 61, -13, -16, 70, -29, -2, 80, -45, 13, 89, -58, 26, + 31, 60, -62, 36, 46, -54, 43, 28, -43, 52, 8, -29, + 61, -11, -15, 70, -27, -1, 80, -43, 13, 89, -56, 26, + 33, 61, -60, 37, 48, -52, 44, 30, -41, 52, 10, -28, + 61, -9, -14, 71, -25, 0, 80, -41, 13, 90, -54, 26, + 34, 62, -58, 38, 49, -51, 45, 32, -40, 53, 13, -27, + 62, -6, -13, 71, -23, 0, 81, -39, 14, 90, -53, 27, + 35, 63, -55, 39, 51, -49, 46, 34, -38, 54, 16, -26, + 63, -3, -12, 72, -20, 1, 81, -36, 14, 90, -50, 27, + 36, 65, -53, 40, 53, -47, 47, 37, -37, 54, 18, -25, + 63, -1, -12, 72, -18, 2, 81, -34, 15, 91, -48, 28, + 38, 66, -51, 42, 55, -45, 48, 39, -35, 55, 21, -24, + 64, 2, -11, 73, -15, 2, 82, -32, 16, 91, -46, 28, + 39, 67, -49, 43, 57, -43, 49, 41, -34, 56, 23, -22, + 64, 5, -10, 73, -13, 3, 82, -29, 16, 91, -44, 29, + 41, 69, -46, 44, 59, -41, 50, 44, -32, 57, 26, -21, + 65, 8, -8, 74, -10, 4, 83, -26, 17, 92, -41, 29, + 42, 70, -44, 45, 61, -39, 51, 46, -30, 58, 29, -20, + 66, 10, -7, 74, -7, 5, 83, -24, 18, 92, -39, 30, + 43, 72, -42, 47, 63, -36, 52, 49, -28, 59, 32, -18, + 66, 13, -6, 75, -4, 6, 84, -21, 19, 93, -36, 31, + 45, 73, -39, 48, 65, -34, 53, 51, -27, 59, 34, -17, + 67, 16, -5, 75, -1, 7, 84, -18, 19, 93, -34, 31, + 46, 75, -37, 49, 67, -32, 54, 53, -25, 60, 37, -15, + 68, 19, -4, 76, 2, 8, 85, -15, 20, 93, -31, 32, + 48, 77, -34, 51, 69, -30, 55, 56, -23, 61, 40, -13, + 69, 22, -2, 77, 5, 9, 85, -12, 21, 94, -28, 33, + 49, 78, -32, 52, 71, -28, 57, 58, -21, 62, 43, -12, + 70, 25, -1, 78, 8, 10, 86, -9, 22, 94, -25, 34, + 51, 80, -29, 53, 73, -25, 58, 61, -19, 64, 45, -10, + 71, 28, 0, 78, 11, 11, 87, -6, 23, 95, -22, 34, + 52, 81, -27, 55, 74, -23, 59, 63, -17, 65, 48, -8, + 72, 31, 2, 79, 14, 13, 87, -3, 24, 96, -19, 35, + 54, 83, -24, 56, 77, -21, 60, 65, -15, 66, 51, -6, + 73, 34, 3, 80, 17, 14, 88, 0, 25, 96, -16, 36, + 56, 85, -22, 58, 78, -18, 62, 68, -13, 67, 54, -5, + 73, 37, 5, 81, 20, 15, 89, 3, 26, 97, -13, 37, + 57, 87, -19, 59, 80, -16, 63, 70, -11, 68, 56, -3, + 74, 40, 6, 82, 23, 16, 89, 6, 27, 97, -10, 38, + 24, 54, -80, 30, 36, -69, 39, 14, -55, 48, -6, -39, + 58, -24, -24, 68, -39, -9, 78, -53, 6, 88, -65, 20, + 24, 54, -79, 30, 36, -69, 39, 15, -55, 48, -5, -39, + 59, -24, -24, 68, -39, -9, 78, -53, 6, 88, -65, 20, + 24, 54, -79, 30, 36, -68, 39, 15, -54, 48, -5, -39, + 59, -23, -23, 68, -39, -9, 79, -53, 6, 88, -65, 20, + 24, 55, -78, 31, 37, -68, 39, 16, -54, 49, -5, -39, + 59, -23, -23, 69, -38, -8, 79, -52, 6, 88, -65, 20, + 25, 55, -78, 31, 37, -68, 39, 16, -54, 49, -4, -39, + 59, -22, -23, 69, -38, -8, 79, -52, 6, 88, -64, 20, + 25, 55, -77, 31, 38, -67, 40, 17, -53, 49, -3, -39, + 59, -21, -23, 69, -37, -8, 79, -51, 7, 88, -64, 20, + 26, 56, -76, 32, 39, -66, 40, 18, -53, 49, -2, -38, + 59, -21, -23, 69, -36, -8, 79, -51, 7, 88, -63, 20, + 26, 56, -75, 32, 40, -65, 40, 20, -52, 49, -1, -38, + 59, -19, -22, 69, -35, -8, 79, -50, 7, 89, -62, 21, + 27, 57, -74, 33, 41, -64, 41, 21, -52, 50, 1, -37, + 60, -18, -22, 69, -34, -7, 79, -49, 7, 89, -61, 21, + 28, 58, -72, 33, 42, -63, 41, 22, -51, 50, 2, -37, + 60, -16, -21, 69, -33, -7, 79, -47, 7, 89, -60, 21, + 29, 58, -71, 34, 44, -62, 42, 24, -50, 50, 4, -36, + 60, -15, -21, 70, -31, -7, 79, -46, 8, 89, -59, 21, + 30, 59, -69, 35, 45, -61, 42, 26, -49, 51, 6, -35, + 60, -13, -20, 70, -29, -6, 80, -45, 8, 89, -58, 21, + 31, 60, -67, 36, 47, -59, 43, 28, -48, 51, 8, -34, + 61, -11, -20, 70, -27, -6, 80, -43, 9, 89, -56, 22, + 32, 61, -65, 37, 48, -58, 44, 30, -47, 52, 10, -33, + 61, -9, -19, 71, -25, -5, 80, -41, 9, 90, -55, 22, + 33, 62, -63, 38, 50, -56, 44, 32, -45, 53, 13, -32, + 62, -7, -18, 71, -23, -5, 81, -39, 9, 90, -53, 22, + 34, 64, -61, 39, 51, -54, 45, 34, -44, 53, 15, -31, + 62, -4, -18, 71, -21, -4, 81, -37, 10, 90, -51, 23, + 36, 65, -59, 40, 53, -52, 46, 36, -42, 54, 18, -30, + 63, -1, -17, 72, -19, -3, 81, -35, 11, 90, -49, 23, + 37, 66, -57, 41, 55, -51, 47, 39, -41, 55, 20, -29, + 63, 1, -16, 72, -16, -2, 82, -33, 11, 91, -47, 24, + 38, 67, -55, 42, 57, -49, 48, 41, -39, 55, 23, -28, + 64, 4, -15, 73, -14, -2, 82, -30, 12, 91, -45, 24, + 40, 69, -53, 43, 58, -47, 49, 43, -38, 56, 25, -27, + 65, 6, -14, 73, -11, -1, 82, -28, 12, 91, -42, 25, + 41, 70, -50, 45, 60, -45, 50, 46, -36, 57, 28, -25, + 65, 9, -13, 74, -8, 0, 83, -25, 13, 92, -40, 26, + 43, 72, -48, 46, 62, -43, 51, 48, -34, 58, 31, -24, + 66, 12, -11, 74, -5, 1, 83, -22, 14, 92, -37, 26, + 44, 73, -46, 47, 64, -41, 52, 50, -33, 59, 33, -22, + 67, 15, -10, 75, -3, 2, 84, -20, 15, 93, -35, 27, + 45, 75, -43, 48, 66, -38, 53, 52, -31, 60, 36, -21, + 67, 18, -9, 76, 0, 3, 84, -17, 15, 93, -32, 27, + 47, 76, -41, 50, 68, -36, 54, 55, -29, 61, 38, -19, + 68, 20, -8, 76, 3, 4, 85, -14, 16, 94, -30, 28, + 48, 78, -38, 51, 70, -34, 56, 57, -27, 62, 41, -17, + 69, 24, -6, 77, 6, 5, 86, -11, 17, 94, -27, 29, + 50, 79, -36, 52, 72, -32, 57, 60, -25, 63, 44, -16, + 70, 26, -5, 78, 9, 6, 86, -8, 18, 95, -24, 30, + 51, 81, -33, 54, 74, -30, 58, 62, -23, 64, 47, -14, + 71, 29, -4, 78, 12, 7, 87, -5, 19, 95, -21, 31, + 53, 82, -31, 55, 75, -27, 59, 64, -21, 65, 49, -13, + 72, 32, -2, 79, 15, 9, 87, -2, 20, 96, -18, 31, + 54, 84, -28, 57, 78, -25, 61, 66, -19, 66, 52, -11, + 73, 35, -1, 80, 18, 10, 88, 1, 21, 96, -15, 32, + 56, 86, -26, 58, 79, -23, 62, 69, -17, 67, 55, -9, + 74, 38, 1, 81, 21, 11, 89, 4, 22, 97, -12, 33, + 57, 87, -24, 59, 81, -20, 63, 71, -15, 68, 57, -7, + 75, 41, 2, 82, 24, 12, 90, 7, 23, 97, -9, 34, + 25, 57, -83, 31, 39, -72, 39, 18, -59, 49, -3, -43, + 59, -21, -28, 69, -37, -13, 79, -51, 2, 88, -64, 16, + 25, 57, -82, 31, 39, -72, 39, 18, -58, 49, -2, -43, + 59, -21, -28, 69, -37, -13, 79, -51, 2, 88, -63, 16, + 25, 57, -82, 31, 39, -72, 39, 18, -58, 49, -2, -43, + 59, -21, -27, 69, -36, -13, 79, -51, 2, 88, -63, 16, + 25, 57, -81, 31, 40, -71, 40, 19, -58, 49, -1, -43, + 59, -20, -27, 69, -36, -12, 79, -50, 2, 88, -63, 16, + 26, 57, -81, 32, 40, -71, 40, 20, -58, 49, -1, -43, + 59, -20, -27, 69, -35, -12, 79, -50, 2, 88, -62, 16, + 26, 58, -80, 32, 41, -70, 40, 20, -57, 49, 0, -42, + 59, -19, -27, 69, -35, -12, 79, -49, 3, 89, -62, 16, + 27, 58, -79, 32, 42, -70, 40, 21, -57, 49, 1, -42, + 59, -18, -27, 69, -34, -12, 79, -49, 3, 89, -61, 16, + 27, 59, -78, 33, 43, -69, 41, 23, -56, 50, 2, -42, + 60, -17, -26, 69, -33, -12, 79, -48, 3, 89, -60, 17, + 28, 59, -77, 33, 44, -68, 41, 24, -55, 50, 4, -41, + 60, -15, -26, 69, -32, -11, 79, -47, 3, 89, -60, 17, + 29, 60, -76, 34, 45, -67, 42, 25, -55, 50, 5, -41, + 60, -14, -25, 70, -30, -11, 79, -45, 4, 89, -59, 17, + 30, 61, -74, 35, 46, -66, 42, 27, -54, 51, 7, -40, + 60, -12, -25, 70, -29, -11, 80, -44, 4, 89, -57, 17, + 31, 61, -73, 36, 47, -64, 43, 28, -53, 51, 9, -39, + 61, -11, -24, 70, -27, -10, 80, -43, 4, 89, -56, 18, + 32, 62, -71, 36, 49, -63, 43, 30, -52, 52, 11, -38, + 61, -9, -24, 70, -25, -10, 80, -41, 5, 90, -54, 18, + 33, 63, -69, 37, 50, -61, 44, 32, -50, 52, 13, -37, + 62, -6, -23, 71, -23, -9, 80, -39, 5, 90, -53, 18, + 34, 64, -67, 38, 52, -60, 45, 34, -49, 53, 15, -36, + 62, -4, -22, 71, -21, -9, 81, -37, 5, 90, -51, 19, + 35, 65, -65, 39, 53, -58, 46, 36, -48, 54, 17, -35, + 63, -2, -22, 72, -19, -8, 81, -35, 6, 90, -49, 19, + 36, 67, -63, 40, 55, -56, 47, 38, -46, 54, 20, -34, + 63, 1, -21, 72, -17, -7, 81, -33, 7, 91, -47, 20, + 38, 68, -61, 41, 57, -55, 47, 40, -45, 55, 22, -33, + 64, 3, -20, 72, -14, -6, 82, -31, 7, 91, -45, 20, + 39, 69, -59, 43, 58, -53, 48, 43, -43, 56, 24, -32, + 64, 5, -19, 73, -12, -6, 82, -29, 8, 91, -43, 20, + 40, 70, -56, 44, 60, -51, 49, 45, -42, 57, 27, -31, + 65, 8, -18, 73, -9, -5, 83, -26, 8, 92, -41, 21, + 42, 72, -54, 45, 62, -49, 50, 47, -40, 57, 30, -29, + 66, 11, -17, 74, -7, -4, 83, -23, 9, 92, -38, 22, + 43, 73, -52, 46, 64, -47, 51, 49, -38, 58, 32, -28, + 66, 14, -16, 75, -4, -3, 84, -21, 10, 92, -36, 22, + 44, 74, -49, 48, 65, -45, 53, 52, -37, 59, 35, -26, + 67, 16, -14, 75, -1, -2, 84, -18, 11, 93, -34, 23, + 46, 76, -47, 49, 67, -42, 54, 54, -35, 60, 37, -25, + 68, 19, -13, 76, 2, -1, 85, -16, 11, 93, -31, 24, + 47, 77, -45, 50, 69, -40, 55, 56, -33, 61, 40, -23, + 69, 22, -12, 76, 4, 0, 85, -13, 12, 94, -28, 24, + 49, 79, -42, 52, 71, -38, 56, 59, -31, 62, 43, -22, + 69, 25, -10, 77, 8, 1, 86, -10, 13, 94, -25, 25, + 50, 80, -40, 53, 73, -36, 57, 61, -29, 63, 45, -20, + 70, 28, -9, 78, 10, 2, 86, -7, 14, 95, -23, 26, + 52, 82, -38, 54, 75, -34, 58, 63, -27, 64, 48, -18, + 71, 31, -8, 79, 13, 3, 87, -4, 15, 95, -20, 27, + 53, 83, -35, 56, 76, -31, 60, 65, -25, 65, 50, -17, + 72, 33, -6, 79, 16, 4, 88, -1, 16, 96, -17, 28, + 55, 85, -32, 57, 78, -29, 61, 68, -23, 66, 53, -15, + 73, 36, -5, 80, 20, 6, 88, 2, 17, 96, -14, 28, + 56, 87, -30, 58, 80, -27, 62, 70, -21, 67, 56, -13, + 74, 39, -3, 81, 22, 7, 89, 5, 18, 97, -11, 29, + 58, 88, -28, 60, 82, -24, 63, 72, -19, 68, 58, -11, + 75, 42, -2, 82, 25, 8, 90, 8, 19, 98, -8, 30, + 26, 59, -85, 32, 42, -76, 40, 21, -62, 49, 0, -47, + 59, -18, -32, 69, -35, -17, 79, -49, -2, 88, -62, 12, + 26, 59, -85, 32, 42, -75, 40, 21, -62, 49, 1, -47, + 59, -18, -32, 69, -34, -17, 79, -49, -2, 88, -62, 12, + 26, 59, -85, 32, 42, -75, 40, 22, -62, 49, 1, -47, + 59, -18, -31, 69, -34, -17, 79, -49, -2, 89, -61, 12, + 26, 59, -84, 32, 43, -75, 40, 22, -62, 49, 2, -47, + 59, -17, -31, 69, -34, -16, 79, -48, -2, 89, -61, 12, + 27, 60, -84, 32, 43, -74, 40, 23, -61, 50, 2, -47, + 59, -17, -31, 69, -33, -16, 79, -48, -1, 89, -61, 12, + 27, 60, -83, 33, 44, -74, 41, 23, -61, 50, 3, -46, + 60, -16, -31, 69, -32, -16, 79, -47, -1, 89, -60, 12, + 28, 60, -82, 33, 44, -73, 41, 24, -60, 50, 4, -46, + 60, -15, -31, 69, -32, -16, 79, -47, -1, 89, -59, 13, + 28, 61, -81, 34, 45, -72, 41, 25, -60, 50, 5, -46, + 60, -14, -30, 70, -30, -16, 79, -46, -1, 89, -59, 13, + 29, 61, -80, 34, 46, -71, 42, 27, -59, 51, 6, -45, + 60, -13, -30, 70, -29, -15, 80, -45, -1, 89, -58, 13, + 30, 62, -79, 35, 47, -70, 42, 28, -58, 51, 8, -44, + 60, -11, -29, 70, -28, -15, 80, -43, 0, 89, -57, 13, + 31, 63, -77, 36, 48, -69, 43, 29, -57, 51, 9, -44, + 61, -10, -29, 70, -27, -15, 80, -42, 0, 89, -56, 13, + 31, 63, -76, 36, 50, -68, 43, 31, -57, 52, 11, -43, + 61, -8, -28, 70, -25, -14, 80, -41, 0, 89, -54, 14, + 33, 64, -74, 37, 51, -67, 44, 33, -55, 52, 13, -42, + 61, -6, -28, 71, -23, -14, 80, -39, 1, 90, -53, 14, + 34, 65, -72, 38, 52, -65, 45, 34, -54, 53, 15, -41, + 62, -4, -27, 71, -21, -13, 81, -37, 1, 90, -51, 14, + 35, 66, -70, 39, 54, -64, 45, 36, -53, 53, 17, -40, + 62, -2, -26, 71, -19, -13, 81, -36, 1, 90, -50, 15, + 36, 67, -69, 40, 55, -62, 46, 38, -52, 54, 19, -39, + 63, 0, -26, 72, -17, -12, 81, -34, 2, 90, -48, 15, + 37, 68, -66, 41, 57, -60, 47, 40, -50, 55, 22, -38, + 63, 3, -25, 72, -15, -11, 82, -31, 3, 91, -46, 16, + 38, 69, -64, 42, 58, -58, 48, 42, -49, 55, 24, -37, + 64, 5, -24, 73, -13, -10, 82, -29, 3, 91, -44, 16, + 40, 70, -62, 43, 60, -56, 49, 44, -47, 56, 26, -36, + 65, 7, -23, 73, -10, -10, 82, -27, 4, 91, -42, 17, + 41, 72, -60, 44, 62, -55, 50, 47, -46, 57, 29, -35, + 65, 10, -22, 74, -8, -9, 83, -25, 4, 92, -40, 17, + 42, 73, -58, 46, 64, -52, 51, 49, -44, 58, 31, -33, + 66, 13, -21, 74, -5, -8, 83, -22, 5, 92, -37, 18, + 44, 74, -56, 47, 65, -50, 52, 51, -42, 59, 34, -32, + 67, 15, -20, 75, -2, -7, 84, -19, 6, 93, -35, 18, + 45, 76, -53, 48, 67, -48, 53, 53, -41, 59, 36, -30, + 67, 18, -18, 75, 0, -6, 84, -17, 7, 93, -32, 19, + 46, 77, -51, 49, 69, -46, 54, 55, -39, 60, 39, -29, + 68, 21, -17, 76, 3, -5, 85, -14, 7, 93, -30, 20, + 48, 78, -49, 50, 70, -44, 55, 57, -37, 61, 41, -27, + 69, 23, -16, 77, 6, -4, 85, -11, 8, 94, -27, 20, + 49, 80, -46, 52, 72, -42, 56, 60, -35, 62, 44, -26, + 70, 26, -15, 77, 9, -3, 86, -8, 9, 94, -24, 21, + 51, 81, -44, 53, 74, -40, 58, 62, -33, 63, 47, -24, + 70, 29, -13, 78, 12, -2, 86, -6, 10, 95, -21, 22, + 52, 83, -42, 55, 76, -38, 59, 64, -31, 64, 49, -22, + 71, 32, -12, 79, 15, -1, 87, -3, 11, 95, -19, 23, + 54, 84, -39, 56, 78, -35, 60, 66, -29, 65, 52, -21, + 72, 35, -10, 80, 18, 0, 88, 0, 12, 96, -16, 24, + 55, 86, -37, 57, 80, -33, 61, 69, -27, 67, 54, -19, + 73, 38, -9, 80, 21, 2, 88, 3, 13, 97, -13, 25, + 57, 88, -34, 59, 81, -31, 62, 71, -25, 68, 57, -17, + 74, 40, -7, 81, 24, 3, 89, 6, 14, 97, -10, 26, + 58, 89, -32, 60, 83, -29, 64, 73, -23, 69, 59, -15, + 75, 43, -6, 82, 26, 4, 90, 9, 15, 98, -7, 26, + 27, 62, -89, 33, 45, -79, 41, 25, -66, 50, 4, -52, + 59, -15, -36, 69, -32, -21, 79, -47, -6, 89, -60, 8, + 27, 62, -88, 33, 45, -79, 41, 25, -66, 50, 4, -52, + 60, -15, -36, 69, -31, -21, 79, -46, -6, 89, -59, 8, + 27, 62, -88, 33, 46, -79, 41, 25, -66, 50, 5, -51, + 60, -15, -36, 69, -31, -21, 79, -46, -6, 89, -59, 8, + 28, 62, -88, 33, 46, -79, 41, 26, -66, 50, 5, -51, + 60, -14, -36, 69, -31, -21, 79, -46, -6, 89, -59, 8, + 28, 62, -87, 33, 46, -78, 41, 26, -65, 50, 6, -51, + 60, -14, -36, 69, -30, -21, 79, -45, -6, 89, -58, 8, + 28, 62, -86, 34, 47, -78, 41, 27, -65, 50, 6, -51, + 60, -13, -35, 70, -30, -21, 79, -45, -6, 89, -58, 8, + 29, 63, -86, 34, 47, -77, 42, 28, -65, 50, 7, -50, + 60, -12, -35, 70, -29, -20, 79, -44, -6, 89, -57, 8, + 29, 63, -85, 35, 48, -76, 42, 29, -64, 51, 8, -50, + 60, -11, -35, 70, -28, -20, 80, -43, -5, 89, -57, 8, + 30, 64, -83, 35, 49, -75, 42, 30, -63, 51, 10, -49, + 61, -10, -34, 70, -27, -20, 80, -42, -5, 89, -56, 9, + 31, 64, -82, 36, 50, -74, 43, 31, -62, 51, 11, -49, + 61, -8, -34, 70, -25, -19, 80, -41, -5, 89, -55, 9, + 32, 65, -81, 36, 51, -73, 43, 32, -62, 52, 12, -48, + 61, -7, -33, 70, -24, -19, 80, -40, -5, 90, -54, 9, + 32, 65, -80, 37, 52, -72, 44, 34, -61, 52, 14, -47, + 61, -5, -33, 71, -23, -19, 80, -38, -4, 90, -52, 9, + 33, 66, -78, 38, 53, -70, 45, 36, -60, 53, 16, -47, + 62, -3, -32, 71, -21, -18, 81, -37, -4, 90, -51, 10, + 34, 67, -76, 39, 55, -69, 45, 37, -58, 53, 18, -46, + 62, -2, -32, 71, -19, -18, 81, -35, -3, 90, -49, 10, + 36, 68, -74, 40, 56, -68, 46, 39, -57, 54, 20, -45, + 63, 0, -31, 72, -17, -17, 81, -33, -3, 90, -48, 10, + 37, 69, -73, 41, 57, -66, 47, 41, -56, 54, 22, -44, + 63, 2, -30, 72, -15, -16, 81, -31, -2, 91, -46, 11, + 38, 70, -70, 42, 59, -64, 48, 43, -55, 55, 24, -43, + 64, 5, -29, 73, -13, -16, 82, -29, -2, 91, -44, 11, + 39, 71, -68, 43, 60, -62, 48, 45, -53, 56, 26, -41, + 64, 7, -28, 73, -10, -15, 82, -27, -1, 91, -42, 12, + 40, 72, -66, 44, 62, -61, 49, 47, -52, 57, 29, -40, + 65, 10, -27, 73, -8, -14, 83, -25, -1, 92, -40, 12, + 41, 73, -64, 45, 63, -59, 50, 49, -50, 57, 31, -39, + 65, 12, -26, 74, -6, -13, 83, -23, 0, 92, -38, 13, + 43, 75, -62, 46, 65, -57, 51, 51, -48, 58, 34, -38, + 66, 15, -25, 75, -3, -12, 84, -20, 1, 92, -35, 13, + 44, 76, -60, 47, 67, -55, 52, 53, -47, 59, 36, -36, + 67, 17, -24, 75, 0, -12, 84, -18, 1, 93, -33, 14, + 46, 77, -58, 49, 68, -53, 53, 55, -45, 60, 38, -35, + 68, 20, -23, 76, 2, -11, 84, -15, 2, 93, -31, 15, + 47, 78, -55, 50, 70, -51, 54, 57, -43, 61, 41, -33, + 68, 22, -22, 76, 5, -10, 85, -12, 3, 94, -28, 15, + 48, 80, -53, 51, 72, -49, 56, 59, -41, 62, 43, -32, + 69, 25, -21, 77, 8, -9, 85, -10, 4, 94, -26, 16, + 50, 81, -51, 52, 74, -46, 57, 61, -39, 63, 46, -30, + 70, 28, -19, 78, 11, -7, 86, -7, 5, 95, -23, 17, + 51, 83, -48, 54, 75, -44, 58, 63, -38, 64, 48, -29, + 71, 31, -18, 78, 13, -6, 87, -4, 6, 95, -20, 18, + 53, 84, -46, 55, 77, -42, 59, 66, -36, 65, 51, -27, + 72, 33, -16, 79, 16, -5, 87, -1, 7, 96, -17, 18, + 54, 86, -44, 56, 79, -40, 60, 68, -34, 66, 53, -25, + 72, 36, -15, 80, 19, -4, 88, 2, 8, 96, -15, 19, + 56, 87, -41, 58, 81, -37, 62, 70, -32, 67, 56, -23, + 73, 39, -13, 81, 22, -3, 89, 5, 9, 97, -11, 20, + 57, 89, -39, 59, 82, -35, 63, 72, -30, 68, 58, -22, + 74, 42, -12, 81, 25, -1, 89, 8, 10, 97, -9, 21, + 58, 90, -36, 60, 84, -33, 64, 74, -28, 69, 61, -20, + 75, 44, -10, 82, 28, 0, 90, 10, 11, 98, -6, 22, + 28, 64, -91, 34, 48, -83, 41, 28, -70, 50, 7, -55, + 60, -12, -40, 69, -29, -25, 79, -44, -10, 89, -58, 4, + 28, 64, -91, 34, 48, -82, 41, 28, -70, 50, 7, -55, + 60, -12, -40, 69, -29, -25, 79, -44, -10, 89, -57, 4, + 28, 64, -91, 34, 48, -82, 41, 28, -70, 50, 8, -55, + 60, -12, -40, 70, -29, -25, 79, -44, -10, 89, -57, 4, + 29, 64, -91, 34, 49, -82, 42, 29, -69, 50, 8, -55, + 60, -11, -40, 70, -28, -25, 79, -44, -10, 89, -57, 4, + 29, 64, -90, 34, 49, -81, 42, 29, -69, 51, 9, -55, + 60, -11, -39, 70, -28, -25, 80, -43, -10, 89, -56, 4, + 29, 65, -89, 35, 50, -81, 42, 30, -69, 51, 9, -54, + 60, -10, -39, 70, -27, -25, 80, -43, -10, 89, -56, 4, + 30, 65, -89, 35, 50, -80, 42, 31, -68, 51, 10, -54, + 60, -9, -39, 70, -26, -24, 80, -42, -10, 89, -55, 4, + 30, 65, -88, 35, 51, -79, 43, 32, -68, 51, 11, -54, + 61, -8, -39, 70, -25, -24, 80, -41, -9, 89, -55, 4, + 31, 66, -87, 36, 52, -79, 43, 33, -67, 51, 12, -53, + 61, -7, -38, 70, -24, -24, 80, -40, -9, 89, -54, 5, + 32, 66, -85, 36, 52, -78, 43, 34, -66, 52, 14, -53, + 61, -6, -38, 70, -23, -23, 80, -39, -9, 90, -53, 5, + 32, 67, -84, 37, 53, -77, 44, 35, -65, 52, 15, -52, + 61, -4, -37, 71, -22, -23, 80, -38, -9, 90, -52, 5, + 33, 67, -83, 38, 54, -75, 44, 36, -64, 53, 17, -51, + 62, -3, -37, 71, -20, -23, 81, -36, -8, 90, -50, 5, + 34, 68, -81, 39, 56, -74, 45, 38, -63, 53, 19, -50, + 62, -1, -36, 71, -18, -22, 81, -35, -8, 90, -49, 6, + 35, 69, -79, 39, 57, -73, 46, 40, -62, 54, 20, -50, + 63, 1, -36, 72, -17, -22, 81, -33, -7, 90, -47, 6, + 36, 70, -78, 40, 58, -71, 47, 41, -61, 54, 22, -49, + 63, 3, -35, 72, -15, -21, 81, -31, -7, 91, -46, 6, + 37, 71, -76, 41, 59, -70, 47, 43, -60, 55, 24, -48, + 63, 5, -34, 72, -13, -20, 82, -30, -6, 91, -44, 7, + 39, 72, -74, 42, 61, -68, 48, 45, -58, 56, 26, -47, + 64, 7, -33, 73, -11, -20, 82, -27, -6, 91, -42, 7, + 40, 73, -72, 43, 62, -66, 49, 47, -57, 56, 28, -45, + 65, 9, -32, 73, -8, -19, 82, -25, -5, 91, -40, 8, + 41, 74, -70, 44, 64, -64, 50, 49, -55, 57, 31, -44, + 65, 12, -31, 74, -6, -18, 83, -23, -5, 92, -38, 8, + 42, 75, -68, 45, 65, -63, 51, 50, -54, 58, 33, -43, + 66, 14, -30, 74, -4, -17, 83, -21, -4, 92, -36, 9, + 44, 76, -66, 47, 67, -60, 52, 53, -52, 59, 35, -42, + 66, 17, -29, 75, -1, -16, 84, -18, -3, 93, -34, 10, + 45, 77, -63, 48, 68, -59, 53, 55, -51, 59, 38, -40, + 67, 19, -28, 75, 1, -16, 84, -16, -2, 93, -31, 10, + 46, 78, -61, 49, 70, -57, 54, 57, -49, 60, 40, -39, + 68, 22, -27, 76, 4, -15, 85, -13, -2, 93, -29, 11, + 47, 80, -59, 50, 72, -55, 55, 59, -47, 61, 42, -37, + 69, 24, -26, 77, 7, -14, 85, -11, -1, 94, -27, 11, + 49, 81, -57, 51, 73, -53, 56, 61, -45, 62, 45, -36, + 69, 27, -24, 77, 9, -13, 86, -8, 0, 94, -24, 12, + 50, 83, -54, 53, 75, -50, 57, 63, -43, 63, 47, -34, + 70, 30, -23, 78, 12, -11, 86, -5, 1, 95, -21, 13, + 52, 84, -52, 54, 77, -48, 58, 65, -41, 64, 50, -33, + 71, 32, -22, 79, 15, -10, 87, -3, 2, 95, -19, 14, + 53, 85, -50, 55, 78, -46, 59, 67, -40, 65, 52, -31, + 72, 35, -20, 79, 18, -9, 88, 0, 3, 96, -16, 15, + 54, 87, -48, 57, 80, -44, 61, 69, -38, 66, 54, -29, + 73, 37, -19, 80, 20, -8, 88, 3, 4, 96, -13, 15, + 56, 88, -45, 58, 82, -41, 62, 71, -36, 67, 57, -27, + 74, 40, -17, 81, 23, -7, 89, 6, 5, 97, -10, 16, + 57, 90, -43, 59, 83, -39, 63, 73, -34, 68, 59, -26, + 75, 43, -16, 82, 26, -5, 90, 9, 6, 97, -7, 17, + 59, 91, -40, 61, 85, -37, 64, 75, -32, 69, 62, -24, + 76, 46, -14, 83, 29, -4, 90, 12, 7, 98, -5, 18, + 29, 66, -94, 34, 51, -86, 42, 31, -73, 51, 10, -59, + 60, -9, -44, 70, -26, -29, 80, -42, -14, 89, -56, 0, + 29, 66, -94, 35, 51, -85, 42, 31, -73, 51, 11, -59, + 60, -9, -44, 70, -26, -29, 80, -42, -14, 89, -55, 0, + 30, 66, -94, 35, 51, -85, 42, 31, -73, 51, 11, -59, + 60, -9, -44, 70, -26, -29, 80, -42, -14, 89, -55, 0, + 30, 66, -93, 35, 51, -85, 42, 32, -73, 51, 11, -59, + 60, -8, -44, 70, -26, -29, 80, -41, -14, 89, -55, 0, + 30, 66, -93, 35, 52, -85, 42, 32, -73, 51, 12, -59, + 61, -8, -43, 70, -25, -29, 80, -41, -14, 89, -54, 0, + 30, 67, -92, 35, 52, -84, 43, 33, -72, 51, 12, -58, + 61, -7, -43, 70, -24, -28, 80, -40, -14, 89, -54, 0, + 31, 67, -92, 36, 53, -83, 43, 34, -72, 51, 13, -58, + 61, -6, -43, 70, -24, -28, 80, -40, -13, 89, -53, 0, + 31, 67, -91, 36, 53, -83, 43, 34, -71, 52, 14, -57, + 61, -5, -43, 70, -23, -28, 80, -39, -13, 89, -53, 1, + 32, 68, -90, 37, 54, -82, 44, 35, -70, 52, 15, -57, + 61, -4, -42, 71, -22, -28, 80, -38, -13, 90, -52, 1, + 33, 68, -88, 37, 55, -81, 44, 36, -70, 52, 17, -56, + 62, -3, -42, 71, -21, -27, 80, -37, -13, 90, -51, 1, + 33, 69, -87, 38, 56, -80, 45, 38, -69, 53, 18, -56, + 62, -2, -41, 71, -19, -27, 81, -36, -12, 90, -50, 1, + 34, 69, -86, 39, 57, -79, 45, 39, -68, 53, 19, -55, + 62, 0, -41, 71, -18, -27, 81, -34, -12, 90, -49, 2, + 35, 70, -84, 39, 58, -77, 46, 40, -67, 54, 21, -54, + 63, 1, -40, 72, -16, -26, 81, -33, -12, 90, -47, 2, + 36, 71, -83, 40, 59, -76, 46, 42, -66, 54, 23, -53, + 63, 3, -39, 72, -14, -26, 81, -31, -11, 91, -46, 2, + 37, 72, -81, 41, 60, -75, 47, 43, -65, 55, 25, -52, + 63, 5, -39, 72, -13, -25, 82, -29, -11, 91, -44, 3, + 38, 72, -79, 42, 61, -73, 48, 45, -63, 55, 26, -51, + 64, 7, -38, 73, -11, -24, 82, -28, -10, 91, -42, 3, + 39, 73, -77, 43, 63, -71, 49, 47, -62, 56, 29, -50, + 64, 9, -37, 73, -8, -24, 82, -25, -10, 91, -40, 4, + 40, 74, -75, 44, 64, -70, 49, 49, -61, 57, 31, -49, + 65, 11, -36, 74, -6, -23, 83, -23, -9, 92, -39, 4, + 42, 75, -73, 45, 65, -68, 50, 50, -59, 57, 33, -48, + 65, 14, -35, 74, -4, -22, 83, -21, -9, 92, -37, 5, + 43, 76, -71, 46, 67, -66, 51, 52, -58, 58, 35, -47, + 66, 16, -34, 74, -2, -21, 83, -19, -8, 92, -35, 5, + 44, 78, -69, 47, 68, -64, 52, 54, -56, 59, 37, -45, + 67, 19, -33, 75, 1, -20, 84, -17, -7, 93, -32, 6, + 45, 79, -67, 48, 70, -62, 53, 56, -54, 60, 39, -44, + 67, 21, -32, 76, 3, -20, 84, -14, -6, 93, -30, 6, + 47, 80, -65, 50, 71, -60, 54, 58, -53, 61, 42, -43, + 68, 23, -31, 76, 6, -19, 85, -12, -6, 93, -28, 7, + 48, 81, -63, 51, 73, -58, 55, 60, -51, 61, 44, -41, + 69, 26, -30, 77, 8, -18, 85, -9, -5, 94, -25, 8, + 49, 82, -61, 52, 75, -56, 56, 62, -49, 62, 46, -40, + 70, 28, -28, 77, 11, -17, 86, -7, -4, 94, -23, 8, + 51, 84, -58, 53, 76, -54, 58, 64, -47, 63, 49, -38, + 71, 31, -27, 78, 14, -15, 87, -4, -3, 95, -20, 9, + 52, 85, -56, 55, 78, -52, 59, 66, -45, 64, 51, -37, + 71, 34, -26, 79, 16, -14, 87, -1, -2, 95, -17, 10, + 53, 86, -54, 56, 79, -50, 60, 68, -44, 65, 53, -35, + 72, 36, -24, 80, 19, -13, 88, 2, -1, 96, -15, 11, + 55, 88, -51, 57, 81, -48, 61, 70, -42, 66, 56, -33, + 73, 39, -23, 80, 22, -12, 88, 4, 0, 96, -12, 12, + 56, 89, -49, 59, 83, -45, 62, 72, -39, 68, 58, -31, + 74, 42, -21, 81, 25, -11, 89, 7, 1, 97, -9, 13, + 58, 91, -47, 60, 85, -43, 64, 74, -38, 69, 61, -30, + 75, 44, -20, 82, 27, -9, 90, 10, 2, 98, -6, 13, + 59, 92, -44, 61, 86, -41, 65, 76, -36, 70, 63, -28, + 76, 47, -18, 83, 30, -8, 90, 13, 3, 98, -3, 14, + 30, 68, -97, 35, 54, -89, 43, 34, -77, 51, 13, -63, + 61, -6, -48, 70, -24, -33, 80, -40, -18, 89, -53, -4, + 30, 68, -97, 35, 54, -89, 43, 34, -77, 51, 14, -63, + 61, -6, -48, 70, -23, -33, 80, -39, -18, 89, -53, -4, + 31, 68, -97, 35, 54, -88, 43, 34, -76, 51, 14, -63, + 61, -6, -47, 70, -23, -33, 80, -39, -18, 89, -53, -4, + 31, 68, -96, 36, 54, -88, 43, 35, -76, 51, 14, -62, + 61, -6, -47, 70, -23, -33, 80, -39, -18, 89, -53, -4, + 31, 69, -96, 36, 54, -88, 43, 35, -76, 52, 15, -62, + 61, -5, -47, 70, -22, -33, 80, -38, -18, 89, -52, -4, + 31, 69, -95, 36, 55, -87, 43, 36, -76, 52, 15, -62, + 61, -4, -47, 70, -22, -32, 80, -38, -18, 89, -52, -4, + 32, 69, -94, 37, 55, -87, 44, 36, -75, 52, 16, -62, + 61, -4, -47, 71, -21, -32, 80, -37, -17, 90, -51, -3, + 32, 69, -93, 37, 56, -86, 44, 37, -75, 52, 17, -61, + 61, -3, -46, 71, -20, -32, 80, -36, -17, 90, -50, -3, + 33, 70, -93, 37, 57, -85, 44, 38, -74, 52, 18, -61, + 62, -2, -46, 71, -19, -32, 80, -35, -17, 90, -50, -3, + 34, 70, -91, 38, 57, -84, 45, 39, -73, 53, 19, -60, + 62, 0, -46, 71, -18, -31, 81, -34, -17, 90, -49, -3, + 34, 71, -90, 39, 58, -83, 45, 40, -72, 53, 21, -59, + 62, 1, -45, 71, -17, -31, 81, -33, -16, 90, -48, -3, + 35, 71, -89, 39, 59, -82, 46, 41, -72, 54, 22, -59, + 63, 2, -45, 72, -15, -30, 81, -32, -16, 90, -47, -2, + 36, 72, -87, 40, 60, -81, 46, 43, -70, 54, 24, -58, + 63, 4, -44, 72, -14, -30, 81, -30, -16, 90, -45, -2, + 37, 73, -86, 41, 61, -79, 47, 44, -69, 55, 25, -57, + 63, 6, -43, 72, -12, -29, 82, -29, -15, 91, -44, -2, + 38, 73, -84, 42, 62, -78, 48, 46, -68, 55, 27, -56, + 64, 7, -43, 73, -10, -29, 82, -27, -15, 91, -42, -1, + 39, 74, -83, 43, 63, -77, 48, 47, -67, 56, 29, -55, + 64, 9, -42, 73, -9, -28, 82, -26, -14, 91, -41, -1, + 40, 75, -81, 44, 65, -75, 49, 49, -66, 56, 31, -54, + 65, 12, -41, 73, -6, -28, 83, -23, -14, 92, -39, 0, + 41, 76, -79, 45, 66, -73, 50, 51, -64, 57, 33, -53, + 65, 14, -40, 74, -4, -27, 83, -21, -13, 92, -37, 0, + 42, 77, -77, 46, 67, -72, 51, 52, -63, 58, 35, -52, + 66, 16, -39, 74, -2, -26, 83, -19, -12, 92, -35, 1, + 43, 78, -75, 47, 69, -70, 52, 54, -61, 58, 37, -51, + 66, 18, -38, 75, 0, -25, 84, -17, -12, 92, -33, 1, + 45, 79, -73, 48, 70, -68, 53, 56, -60, 59, 39, -49, + 67, 20, -37, 75, 3, -24, 84, -15, -11, 93, -30, 2, + 46, 80, -71, 49, 72, -66, 54, 58, -58, 60, 41, -48, + 68, 23, -36, 76, 5, -23, 85, -12, -10, 93, -28, 2, + 47, 81, -69, 50, 73, -64, 55, 60, -56, 61, 43, -47, + 68, 25, -35, 76, 7, -23, 85, -10, -10, 94, -26, 3, + 48, 82, -66, 51, 74, -62, 56, 62, -55, 62, 46, -45, + 69, 28, -34, 77, 10, -22, 86, -8, -9, 94, -24, 4, + 50, 84, -64, 52, 76, -60, 57, 64, -53, 63, 48, -44, + 70, 30, -32, 78, 12, -21, 86, -5, -8, 95, -21, 4, + 51, 85, -62, 54, 78, -58, 58, 66, -51, 64, 50, -42, + 71, 33, -31, 78, 15, -19, 87, -2, -7, 95, -18, 5, + 53, 86, -60, 55, 79, -56, 59, 68, -49, 65, 53, -40, + 72, 35, -30, 79, 18, -18, 87, 0, -6, 96, -16, 6, + 54, 88, -57, 56, 81, -54, 60, 70, -47, 66, 55, -39, + 72, 38, -28, 80, 21, -17, 88, 3, -5, 96, -13, 7, + 55, 89, -55, 58, 82, -52, 61, 71, -45, 67, 57, -37, + 73, 40, -27, 81, 23, -16, 89, 6, -4, 97, -11, 8, + 57, 90, -53, 59, 84, -49, 63, 74, -43, 68, 60, -35, + 74, 43, -25, 81, 26, -15, 89, 9, -3, 97, -8, 9, + 58, 92, -50, 60, 86, -47, 64, 75, -41, 69, 62, -34, + 75, 46, -24, 82, 29, -13, 90, 11, -2, 98, -5, 10, + 60, 93, -48, 62, 87, -45, 65, 77, -39, 70, 64, -32, + 76, 48, -22, 83, 32, -12, 91, 14, -1, 98, -2, 11, + 32, 71, -100, 36, 57, -92, 43, 37, -81, 52, 17, -67, + 61, -3, -52, 70, -21, -37, 80, -37, -22, 89, -51, -8, + 32, 71, -100, 36, 57, -92, 43, 38, -80, 52, 17, -67, + 61, -3, -52, 70, -20, -37, 80, -37, -22, 90, -51, -8, + 32, 71, -100, 36, 57, -92, 43, 38, -80, 52, 17, -67, + 61, -3, -52, 70, -20, -37, 80, -36, -22, 90, -51, -8, + 32, 71, -99, 37, 57, -92, 44, 38, -80, 52, 18, -66, + 61, -2, -52, 71, -20, -37, 80, -36, -22, 90, -50, -8, + 32, 71, -99, 37, 57, -91, 44, 39, -80, 52, 18, -66, + 61, -2, -51, 71, -19, -37, 80, -36, -22, 90, -50, -8, + 33, 71, -98, 37, 58, -91, 44, 39, -79, 52, 19, -66, + 61, -1, -51, 71, -19, -37, 80, -35, -22, 90, -49, -8, + 33, 71, -98, 38, 58, -90, 44, 40, -79, 52, 20, -66, + 62, 0, -51, 71, -18, -36, 80, -35, -22, 90, -49, -8, + 34, 72, -97, 38, 59, -89, 45, 40, -78, 53, 20, -65, + 62, 1, -51, 71, -17, -36, 81, -34, -21, 90, -48, -8, + 34, 72, -96, 38, 59, -89, 45, 41, -78, 53, 21, -65, + 62, 2, -50, 71, -16, -36, 81, -33, -21, 90, -47, -7, + 35, 73, -95, 39, 60, -88, 45, 42, -77, 53, 22, -64, + 62, 3, -50, 71, -15, -36, 81, -32, -21, 90, -46, -7, + 35, 73, -94, 39, 61, -87, 46, 43, -76, 54, 24, -64, + 63, 4, -49, 72, -14, -35, 81, -31, -21, 90, -45, -7, + 36, 73, -92, 40, 62, -86, 46, 44, -75, 54, 25, -63, + 63, 5, -49, 72, -13, -35, 81, -29, -20, 91, -44, -7, + 37, 74, -91, 41, 63, -84, 47, 46, -74, 55, 27, -62, + 63, 7, -48, 72, -11, -34, 82, -28, -20, 91, -43, -6, + 38, 75, -89, 42, 64, -83, 48, 47, -73, 55, 28, -61, + 64, 8, -48, 73, -9, -34, 82, -26, -20, 91, -41, -6, + 39, 75, -88, 42, 65, -82, 48, 48, -72, 56, 30, -60, + 64, 10, -47, 73, -8, -33, 82, -25, -19, 91, -40, -6, + 40, 76, -86, 43, 66, -80, 49, 50, -71, 56, 31, -59, + 65, 12, -46, 73, -6, -33, 82, -23, -19, 91, -38, -5, + 41, 77, -84, 44, 67, -79, 50, 52, -70, 57, 33, -58, + 65, 14, -45, 74, -4, -32, 83, -21, -18, 92, -36, -5, + 42, 78, -83, 45, 68, -77, 51, 53, -68, 58, 35, -57, + 66, 16, -44, 74, -2, -31, 83, -19, -17, 92, -35, -4, + 43, 79, -81, 46, 69, -75, 51, 55, -67, 58, 37, -56, + 66, 18, -43, 75, 0, -30, 84, -17, -17, 92, -33, -4, + 44, 80, -79, 47, 71, -74, 52, 56, -66, 59, 39, -55, + 67, 20, -42, 75, 2, -30, 84, -15, -16, 93, -31, -3, + 45, 81, -77, 48, 72, -72, 53, 58, -64, 60, 41, -53, + 68, 23, -41, 76, 5, -29, 84, -13, -15, 93, -28, -2, + 47, 82, -75, 50, 73, -70, 54, 60, -62, 61, 43, -52, + 68, 25, -40, 76, 7, -28, 85, -10, -15, 93, -26, -2, + 48, 83, -73, 51, 75, -68, 55, 62, -61, 61, 46, -51, + 69, 27, -39, 77, 10, -27, 85, -8, -14, 94, -24, -1, + 49, 84, -70, 52, 76, -66, 56, 64, -59, 62, 48, -49, + 70, 30, -38, 77, 12, -26, 86, -6, -13, 94, -22, -1, + 50, 85, -68, 53, 78, -64, 57, 65, -57, 63, 50, -48, + 70, 32, -37, 78, 14, -25, 86, -3, -12, 95, -19, 0, + 52, 86, -66, 54, 79, -62, 59, 67, -55, 64, 52, -46, + 71, 35, -35, 79, 17, -24, 87, 0, -11, 95, -17, 1, + 53, 88, -64, 56, 81, -60, 60, 69, -53, 65, 54, -45, + 72, 37, -34, 79, 20, -23, 88, 2, -10, 96, -14, 2, + 54, 89, -62, 57, 82, -58, 61, 71, -52, 66, 57, -43, + 73, 39, -33, 80, 22, -22, 88, 5, -9, 96, -12, 3, + 56, 90, -59, 58, 84, -56, 62, 73, -50, 67, 59, -42, + 74, 42, -31, 81, 25, -20, 89, 7, -8, 97, -9, 3, + 57, 92, -57, 59, 85, -53, 63, 75, -48, 68, 61, -40, + 75, 45, -30, 82, 28, -19, 90, 10, -7, 97, -6, 4, + 59, 93, -55, 61, 87, -51, 64, 77, -46, 69, 63, -38, + 76, 47, -28, 82, 30, -18, 90, 13, -6, 98, -3, 5, + 60, 94, -52, 62, 89, -49, 65, 79, -44, 70, 66, -36, + 76, 50, -27, 83, 33, -16, 91, 16, -5, 99, -1, 6, + 33, 73, -103, 37, 59, -95, 44, 40, -84, 52, 20, -70, + 62, 0, -56, 71, -18, -41, 80, -34, -26, 90, -49, -12, + 33, 73, -103, 37, 59, -95, 44, 41, -84, 52, 20, -70, + 62, 0, -56, 71, -18, -41, 80, -34, -26, 90, -48, -12, + 33, 73, -102, 37, 59, -95, 44, 41, -84, 52, 21, -70, + 62, 0, -55, 71, -17, -41, 80, -34, -26, 90, -48, -12, + 33, 73, -102, 38, 60, -95, 44, 41, -83, 53, 21, -70, + 62, 1, -55, 71, -17, -41, 81, -34, -26, 90, -48, -12, + 33, 73, -102, 38, 60, -94, 44, 41, -83, 53, 21, -70, + 62, 1, -55, 71, -17, -41, 81, -33, -26, 90, -48, -12, + 34, 73, -101, 38, 60, -94, 45, 42, -83, 53, 22, -70, + 62, 2, -55, 71, -16, -41, 81, -33, -26, 90, -47, -12, + 34, 74, -100, 38, 61, -93, 45, 42, -82, 53, 23, -69, + 62, 2, -55, 71, -15, -40, 81, -32, -26, 90, -47, -12, + 35, 74, -100, 39, 61, -93, 45, 43, -82, 53, 23, -69, + 62, 3, -54, 71, -15, -40, 81, -31, -25, 90, -46, -11, + 35, 74, -99, 39, 62, -92, 46, 44, -81, 54, 24, -68, + 62, 4, -54, 72, -14, -40, 81, -30, -25, 90, -45, -11, + 36, 74, -98, 40, 62, -91, 46, 45, -81, 54, 25, -68, + 63, 5, -54, 72, -13, -39, 81, -29, -25, 90, -44, -11, + 36, 75, -97, 40, 63, -90, 47, 46, -80, 54, 26, -67, + 63, 7, -53, 72, -11, -39, 81, -28, -25, 91, -43, -11, + 37, 75, -95, 41, 64, -89, 47, 47, -79, 55, 28, -67, + 63, 8, -53, 72, -10, -39, 82, -27, -24, 91, -42, -10, + 38, 76, -94, 42, 65, -88, 48, 48, -78, 55, 29, -66, + 64, 9, -52, 73, -9, -38, 82, -26, -24, 91, -41, -10, + 39, 77, -93, 42, 66, -86, 48, 49, -77, 56, 31, -65, + 64, 11, -51, 73, -7, -38, 82, -24, -23, 91, -39, -10, + 40, 77, -91, 43, 67, -85, 49, 51, -76, 56, 32, -64, + 65, 13, -51, 73, -5, -37, 82, -23, -23, 91, -38, -9, + 41, 78, -89, 44, 68, -84, 50, 52, -75, 57, 34, -63, + 65, 14, -50, 74, -4, -36, 83, -21, -22, 92, -36, -9, + 42, 79, -88, 45, 69, -82, 50, 54, -73, 57, 36, -62, + 66, 16, -49, 74, -2, -36, 83, -19, -22, 92, -35, -8, + 43, 79, -86, 46, 70, -81, 51, 55, -72, 58, 37, -61, + 66, 18, -48, 74, 0, -35, 83, -17, -21, 92, -33, -8, + 44, 80, -84, 47, 71, -79, 52, 57, -71, 59, 39, -60, + 67, 20, -47, 75, 2, -34, 84, -15, -21, 93, -31, -8, + 45, 81, -82, 48, 72, -77, 53, 58, -69, 59, 41, -59, + 67, 22, -46, 75, 4, -33, 84, -13, -20, 93, -29, -7, + 46, 82, -80, 49, 74, -75, 54, 60, -67, 60, 43, -57, + 68, 25, -45, 76, 7, -33, 85, -11, -19, 93, -27, -6, + 47, 83, -78, 50, 75, -73, 55, 62, -66, 61, 45, -56, + 69, 27, -44, 77, 9, -32, 85, -9, -19, 94, -25, -6, + 49, 84, -76, 51, 76, -72, 56, 64, -64, 62, 47, -55, + 69, 29, -43, 77, 11, -31, 86, -6, -18, 94, -22, -5, + 50, 85, -74, 52, 78, -70, 57, 65, -63, 63, 49, -53, + 70, 31, -42, 78, 14, -30, 86, -4, -17, 95, -20, -4, + 51, 86, -72, 54, 79, -68, 58, 67, -61, 64, 51, -52, + 71, 34, -41, 78, 16, -29, 87, -2, -16, 95, -18, -4, + 52, 88, -70, 55, 81, -66, 59, 69, -59, 65, 54, -50, + 72, 36, -39, 79, 19, -28, 87, 1, -15, 96, -15, -3, + 54, 89, -67, 56, 82, -64, 60, 71, -57, 66, 56, -49, + 72, 39, -38, 80, 21, -27, 88, 4, -14, 96, -13, -2, + 55, 90, -65, 57, 84, -62, 61, 72, -55, 66, 58, -47, + 73, 41, -37, 80, 24, -25, 88, 6, -13, 97, -10, -1, + 56, 91, -63, 58, 85, -60, 62, 74, -54, 67, 60, -45, + 74, 43, -35, 81, 26, -24, 89, 9, -12, 97, -8, 0, + 58, 93, -61, 60, 87, -57, 64, 76, -51, 69, 63, -44, + 75, 46, -34, 82, 29, -23, 90, 12, -11, 98, -5, 1, + 59, 94, -58, 61, 88, -55, 65, 78, -50, 70, 65, -42, + 76, 49, -32, 83, 32, -22, 90, 14, -10, 98, -2, 1, + 60, 95, -56, 62, 90, -53, 66, 80, -48, 71, 67, -40, + 77, 51, -31, 83, 34, -20, 91, 17, -9, 99, 1, 2, + 34, 75, -105, 38, 62, -98, 45, 43, -87, 53, 23, -74, + 62, 3, -59, 71, -15, -45, 81, -32, -30, 90, -46, -16, + 34, 75, -105, 38, 62, -98, 45, 44, -87, 53, 23, -74, + 62, 3, -59, 71, -15, -45, 81, -32, -30, 90, -46, -16, + 34, 75, -105, 38, 62, -98, 45, 44, -87, 53, 24, -74, + 62, 3, -59, 71, -15, -45, 81, -31, -30, 90, -46, -16, + 34, 75, -105, 38, 62, -98, 45, 44, -87, 53, 24, -74, + 62, 4, -59, 71, -14, -45, 81, -31, -30, 90, -46, -16, + 34, 75, -104, 39, 62, -97, 45, 44, -86, 53, 24, -73, + 62, 4, -59, 71, -14, -44, 81, -31, -30, 90, -45, -16, + 35, 75, -104, 39, 63, -97, 45, 45, -86, 53, 25, -73, + 62, 5, -59, 71, -13, -44, 81, -30, -30, 90, -45, -16, + 35, 76, -103, 39, 63, -96, 46, 45, -86, 54, 25, -73, + 62, 5, -58, 72, -13, -44, 81, -30, -29, 90, -44, -15, + 36, 76, -102, 40, 64, -96, 46, 46, -85, 54, 26, -72, + 63, 6, -58, 72, -12, -44, 81, -29, -29, 90, -44, -15, + 36, 76, -102, 40, 64, -95, 46, 47, -85, 54, 27, -72, + 63, 7, -58, 72, -11, -44, 81, -28, -29, 90, -43, -15, + 37, 76, -101, 41, 65, -94, 47, 48, -84, 54, 28, -71, + 63, 8, -57, 72, -10, -43, 81, -27, -29, 91, -42, -15, + 37, 77, -100, 41, 65, -93, 47, 48, -83, 55, 29, -71, + 63, 9, -57, 72, -9, -43, 82, -26, -28, 91, -41, -15, + 38, 77, -98, 42, 66, -92, 48, 49, -82, 55, 30, -70, + 64, 11, -56, 73, -8, -42, 82, -25, -28, 91, -40, -14, + 39, 78, -97, 42, 67, -91, 48, 51, -81, 56, 32, -69, + 64, 12, -56, 73, -6, -42, 82, -23, -28, 91, -39, -14, + 40, 78, -96, 43, 68, -90, 49, 52, -80, 56, 33, -69, + 65, 14, -55, 73, -5, -41, 82, -22, -27, 91, -37, -14, + 40, 79, -94, 44, 69, -88, 50, 53, -79, 57, 35, -68, + 65, 15, -54, 74, -3, -41, 83, -20, -27, 92, -36, -13, + 41, 80, -93, 45, 70, -87, 50, 54, -78, 57, 36, -67, + 65, 17, -54, 74, -1, -40, 83, -19, -26, 92, -34, -13, + 42, 80, -91, 46, 71, -85, 51, 56, -77, 58, 38, -66, + 66, 19, -53, 74, 1, -40, 83, -17, -26, 92, -33, -12, + 43, 81, -89, 47, 72, -84, 52, 57, -75, 58, 40, -65, + 66, 21, -52, 75, 3, -39, 84, -15, -25, 92, -31, -12, + 44, 82, -87, 48, 73, -82, 53, 59, -74, 59, 41, -63, + 67, 23, -51, 75, 4, -38, 84, -13, -24, 93, -29, -11, + 46, 83, -86, 49, 74, -81, 53, 60, -73, 60, 43, -62, + 68, 25, -50, 76, 7, -37, 84, -11, -24, 93, -27, -11, + 47, 84, -83, 50, 75, -79, 54, 62, -71, 61, 45, -61, + 68, 27, -49, 76, 9, -36, 85, -9, -23, 94, -25, -10, + 48, 85, -81, 51, 77, -77, 55, 64, -69, 61, 47, -60, + 69, 29, -48, 77, 11, -35, 85, -7, -22, 94, -23, -10, + 49, 86, -80, 52, 78, -75, 56, 65, -68, 62, 49, -58, + 70, 31, -47, 77, 13, -35, 86, -4, -22, 94, -21, -9, + 50, 87, -78, 53, 79, -73, 57, 67, -66, 63, 51, -57, + 70, 33, -46, 78, 16, -34, 86, -2, -21, 95, -18, -8, + 52, 88, -75, 54, 81, -71, 58, 69, -65, 64, 53, -55, + 71, 36, -44, 79, 18, -33, 87, 0, -20, 95, -16, -8, + 53, 89, -73, 55, 82, -69, 59, 71, -63, 65, 56, -54, + 72, 38, -43, 79, 21, -31, 87, 3, -19, 96, -13, -7, + 54, 90, -71, 57, 83, -67, 60, 72, -61, 66, 58, -52, + 73, 40, -42, 80, 23, -30, 88, 5, -18, 96, -11, -6, + 55, 91, -69, 58, 85, -65, 62, 74, -59, 67, 60, -51, + 73, 43, -40, 81, 26, -29, 89, 8, -17, 97, -9, -5, + 57, 93, -67, 59, 86, -63, 63, 76, -57, 68, 62, -49, + 74, 45, -39, 81, 28, -28, 89, 10, -16, 97, -6, -4, + 58, 94, -64, 60, 88, -61, 64, 78, -55, 69, 64, -47, + 75, 48, -37, 82, 31, -27, 90, 13, -15, 98, -3, -3, + 60, 95, -62, 62, 89, -59, 65, 79, -53, 70, 66, -46, + 76, 50, -36, 83, 33, -25, 91, 16, -14, 98, -1, -2, + 61, 97, -60, 63, 91, -57, 66, 81, -51, 71, 68, -44, + 77, 52, -35, 84, 36, -24, 91, 19, -13, 99, 2, -1, + 8, -15, 11, 21, -31, 29, 34, -41, 40, 45, -51, 49, + 57, -60, 58, 67, -69, 67, 78, -78, 75, 88, -86, 83, + 8, -13, 12, 22, -29, 29, 34, -40, 40, 45, -50, 49, + 57, -60, 58, 67, -69, 67, 78, -78, 75, 88, -86, 83, + 8, -11, 13, 22, -27, 29, 34, -39, 40, 45, -49, 49, + 57, -59, 58, 67, -68, 67, 78, -77, 75, 88, -86, 83, + 9, -7, 14, 22, -25, 30, 34, -37, 40, 45, -48, 49, + 57, -58, 58, 67, -68, 67, 78, -77, 75, 88, -85, 83, + 10, -2, 15, 23, -21, 30, 34, -35, 41, 46, -47, 50, + 57, -57, 59, 67, -67, 67, 78, -76, 75, 88, -85, 83, + 11, 3, 17, 23, -18, 31, 35, -33, 41, 46, -45, 50, + 57, -56, 59, 68, -66, 67, 78, -75, 76, 88, -84, 83, + 13, 7, 19, 24, -14, 32, 35, -30, 41, 46, -43, 50, + 57, -55, 59, 68, -65, 67, 78, -74, 76, 88, -83, 84, + 14, 12, 21, 24, -9, 33, 35, -27, 42, 46, -40, 51, + 57, -53, 59, 68, -63, 67, 78, -73, 76, 88, -82, 84, + 15, 16, 23, 25, -5, 34, 36, -23, 43, 47, -38, 51, + 58, -51, 60, 68, -61, 68, 78, -72, 76, 88, -81, 84, + 17, 20, 25, 26, -1, 35, 37, -19, 43, 47, -35, 51, + 58, -48, 60, 68, -60, 68, 79, -70, 76, 88, -80, 84, + 18, 24, 28, 27, 3, 36, 37, -16, 44, 48, -32, 52, + 58, -46, 60, 68, -58, 68, 79, -69, 76, 89, -79, 84, + 20, 27, 30, 28, 8, 38, 38, -12, 45, 48, -28, 53, + 59, -43, 61, 69, -55, 69, 79, -67, 77, 89, -77, 84, + 22, 31, 32, 29, 12, 39, 39, -7, 46, 49, -25, 53, + 59, -40, 61, 69, -53, 69, 79, -65, 77, 89, -75, 85, + 24, 34, 35, 31, 16, 41, 40, -3, 47, 49, -21, 54, + 60, -37, 62, 69, -50, 69, 80, -62, 77, 89, -73, 85, + 25, 37, 37, 32, 20, 42, 40, 1, 48, 50, -17, 55, + 60, -34, 62, 70, -47, 70, 80, -60, 78, 89, -71, 85, + 27, 40, 39, 33, 23, 44, 41, 5, 49, 51, -14, 56, + 60, -30, 63, 70, -45, 70, 80, -58, 78, 90, -69, 86, + 29, 43, 41, 34, 27, 45, 42, 9, 50, 51, -9, 56, + 61, -27, 64, 71, -41, 71, 81, -55, 79, 90, -67, 86, + 30, 45, 43, 36, 31, 47, 43, 13, 51, 52, -6, 57, + 62, -23, 64, 71, -38, 72, 81, -52, 79, 90, -64, 86, + 32, 48, 45, 37, 34, 48, 44, 16, 52, 53, -2, 58, + 62, -20, 65, 72, -35, 72, 81, -49, 80, 91, -62, 87, + 34, 50, 47, 39, 37, 50, 45, 20, 54, 54, 2, 59, + 63, -16, 66, 72, -32, 73, 82, -46, 80, 91, -59, 87, + 36, 53, 49, 40, 41, 51, 47, 24, 55, 55, 6, 60, + 64, -12, 67, 73, -28, 73, 82, -43, 81, 91, -56, 88, + 37, 55, 51, 42, 44, 53, 48, 28, 56, 56, 10, 61, + 64, -8, 68, 73, -25, 74, 83, -40, 81, 92, -53, 88, + 39, 58, 53, 43, 47, 54, 49, 31, 58, 57, 13, 63, + 65, -5, 69, 74, -21, 75, 83, -37, 82, 92, -51, 89, + 41, 60, 54, 44, 49, 56, 50, 34, 59, 58, 17, 64, + 66, -1, 69, 75, -18, 76, 84, -34, 82, 93, -48, 89, + 42, 62, 56, 46, 52, 57, 51, 38, 60, 59, 20, 65, + 67, 2, 70, 75, -14, 76, 84, -30, 83, 93, -45, 90, + 44, 65, 58, 48, 55, 59, 53, 41, 62, 60, 24, 66, + 68, 7, 71, 76, -10, 77, 85, -27, 84, 94, -41, 90, + 46, 67, 59, 49, 58, 61, 54, 44, 63, 61, 28, 67, + 69, 10, 72, 77, -7, 78, 86, -23, 85, 94, -38, 91, + 47, 69, 61, 51, 60, 62, 55, 47, 65, 62, 31, 69, + 69, 14, 73, 77, -3, 79, 86, -20, 85, 95, -35, 92, + 49, 71, 63, 52, 63, 64, 57, 50, 66, 63, 34, 70, + 70, 17, 75, 78, 0, 80, 87, -17, 86, 95, -32, 92, + 51, 73, 64, 54, 66, 66, 58, 53, 68, 64, 38, 71, + 71, 21, 76, 79, 4, 81, 88, -13, 87, 96, -28, 93, + 53, 76, 66, 55, 68, 67, 60, 56, 69, 65, 41, 72, + 72, 24, 77, 80, 7, 82, 88, -9, 88, 97, -25, 94, + 54, 78, 68, 57, 70, 69, 61, 59, 71, 66, 44, 74, + 73, 28, 78, 81, 11, 83, 89, -6, 89, 97, -22, 94, + 8, -14, 8, 21, -30, 26, 34, -41, 37, 45, -51, 47, + 57, -60, 57, 67, -69, 66, 78, -78, 74, 88, -86, 83, + 8, -12, 9, 22, -28, 26, 34, -40, 37, 45, -50, 47, + 57, -60, 57, 67, -69, 66, 78, -77, 74, 88, -86, 83, + 9, -10, 9, 22, -27, 26, 34, -39, 38, 45, -49, 48, + 57, -59, 57, 67, -68, 66, 78, -77, 75, 88, -86, 83, + 9, -5, 11, 22, -24, 27, 34, -37, 38, 45, -48, 48, + 57, -58, 57, 67, -67, 66, 78, -77, 75, 88, -85, 83, + 10, -1, 12, 23, -21, 27, 34, -35, 38, 46, -47, 48, + 57, -57, 57, 67, -67, 66, 78, -76, 75, 88, -85, 83, + 11, 4, 14, 23, -17, 28, 35, -33, 39, 46, -45, 48, + 57, -56, 58, 68, -66, 66, 78, -75, 75, 88, -84, 83, + 13, 8, 16, 24, -13, 29, 35, -30, 39, 46, -43, 48, + 57, -54, 58, 68, -65, 66, 78, -74, 75, 88, -83, 83, + 14, 13, 18, 24, -9, 30, 35, -26, 40, 46, -40, 49, + 57, -52, 58, 68, -63, 67, 78, -73, 75, 88, -82, 83, + 16, 17, 20, 25, -5, 31, 36, -23, 40, 47, -38, 49, + 58, -50, 58, 68, -61, 67, 78, -72, 75, 88, -81, 83, + 17, 21, 22, 26, 0, 32, 37, -19, 41, 47, -35, 50, + 58, -48, 59, 68, -59, 67, 79, -70, 75, 88, -80, 83, + 19, 24, 24, 27, 4, 33, 37, -15, 42, 48, -32, 50, + 58, -46, 59, 68, -57, 67, 79, -69, 76, 89, -78, 84, + 20, 27, 27, 28, 8, 35, 38, -12, 43, 48, -28, 51, + 59, -43, 60, 69, -55, 68, 79, -67, 76, 89, -77, 84, + 22, 31, 29, 29, 12, 36, 39, -7, 44, 49, -24, 52, + 59, -40, 60, 69, -53, 68, 79, -64, 76, 89, -75, 84, + 24, 34, 31, 31, 16, 37, 40, -3, 45, 49, -21, 52, + 60, -37, 61, 69, -50, 69, 80, -62, 77, 89, -73, 84, + 25, 37, 34, 32, 20, 39, 40, 1, 46, 50, -17, 53, + 60, -33, 61, 70, -47, 69, 80, -60, 77, 89, -71, 85, + 27, 40, 36, 33, 24, 40, 41, 5, 47, 51, -13, 54, + 61, -30, 62, 70, -44, 69, 80, -58, 77, 90, -69, 85, + 29, 43, 38, 35, 28, 42, 42, 9, 48, 51, -9, 55, + 61, -26, 63, 71, -41, 70, 81, -55, 78, 90, -67, 85, + 30, 45, 40, 36, 31, 44, 43, 13, 49, 52, -6, 56, + 62, -23, 63, 71, -38, 71, 81, -52, 78, 90, -64, 86, + 32, 48, 42, 37, 34, 45, 44, 17, 51, 53, -2, 57, + 62, -19, 64, 72, -35, 71, 81, -49, 79, 91, -62, 86, + 34, 50, 44, 39, 37, 47, 46, 20, 52, 54, 2, 58, + 63, -16, 65, 72, -32, 72, 82, -46, 79, 91, -59, 87, + 36, 53, 46, 40, 41, 49, 47, 24, 53, 55, 6, 59, + 64, -12, 66, 73, -28, 73, 82, -43, 80, 91, -56, 87, + 37, 55, 48, 42, 44, 50, 48, 28, 55, 56, 10, 60, + 64, -8, 67, 73, -24, 73, 83, -40, 81, 92, -53, 88, + 39, 58, 50, 43, 47, 52, 49, 31, 56, 57, 13, 61, + 65, -5, 67, 74, -21, 74, 83, -37, 81, 92, -50, 88, + 41, 60, 51, 44, 50, 54, 50, 34, 57, 58, 17, 62, + 66, -1, 68, 75, -18, 75, 84, -33, 82, 93, -48, 89, + 42, 62, 53, 46, 52, 55, 52, 38, 59, 59, 21, 63, + 67, 3, 69, 75, -14, 76, 84, -30, 82, 93, -45, 89, + 44, 65, 55, 48, 55, 57, 53, 41, 60, 60, 24, 65, + 68, 7, 70, 76, -10, 77, 85, -27, 83, 94, -41, 90, + 46, 67, 57, 49, 58, 59, 54, 44, 62, 61, 28, 66, + 69, 10, 71, 77, -7, 77, 86, -23, 84, 94, -38, 90, + 47, 69, 59, 51, 60, 60, 55, 47, 63, 62, 31, 67, + 69, 14, 72, 78, -3, 78, 86, -20, 85, 95, -35, 91, + 49, 71, 60, 52, 63, 62, 57, 50, 65, 63, 34, 69, + 70, 17, 74, 78, 0, 79, 87, -16, 85, 95, -32, 92, + 51, 74, 62, 54, 66, 64, 58, 53, 66, 64, 38, 70, + 71, 21, 75, 79, 4, 80, 88, -13, 86, 96, -28, 93, + 53, 76, 64, 55, 68, 65, 60, 56, 68, 65, 41, 71, + 72, 24, 76, 80, 8, 81, 88, -9, 87, 97, -25, 93, + 54, 78, 66, 57, 70, 67, 61, 59, 69, 66, 44, 73, + 73, 28, 77, 81, 11, 82, 89, -6, 88, 97, -21, 94, + 8, -13, 4, 21, -29, 22, 34, -40, 35, 45, -50, 46, + 57, -60, 56, 67, -69, 65, 78, -78, 74, 88, -86, 82, + 8, -11, 5, 22, -28, 22, 34, -39, 35, 45, -49, 46, + 57, -59, 56, 67, -68, 65, 78, -77, 74, 88, -86, 82, + 9, -8, 6, 22, -26, 23, 34, -38, 35, 45, -49, 46, + 57, -59, 56, 67, -68, 65, 78, -77, 74, 88, -85, 82, + 10, -4, 7, 22, -23, 23, 34, -36, 35, 46, -48, 46, + 57, -58, 56, 67, -67, 65, 78, -76, 74, 88, -85, 82, + 10, 0, 9, 23, -20, 24, 34, -34, 36, 46, -46, 46, + 57, -57, 56, 67, -67, 65, 78, -76, 74, 88, -85, 82, + 12, 4, 10, 23, -17, 24, 35, -32, 36, 46, -45, 46, + 57, -56, 56, 68, -66, 65, 78, -75, 74, 88, -84, 82, + 13, 9, 12, 24, -13, 25, 35, -29, 37, 46, -42, 47, + 57, -54, 56, 68, -64, 65, 78, -74, 74, 88, -83, 82, + 14, 13, 14, 25, -8, 26, 36, -26, 37, 46, -40, 47, + 57, -52, 57, 68, -63, 66, 78, -73, 74, 88, -82, 82, + 16, 17, 16, 25, -4, 27, 36, -22, 38, 47, -37, 48, + 58, -50, 57, 68, -61, 66, 78, -72, 74, 88, -81, 83, + 17, 21, 19, 26, 0, 29, 37, -19, 39, 47, -34, 48, + 58, -48, 57, 68, -59, 66, 79, -70, 75, 88, -80, 83, + 19, 24, 21, 27, 4, 30, 37, -15, 39, 48, -31, 49, + 58, -45, 58, 69, -57, 66, 79, -68, 75, 89, -78, 83, + 20, 28, 23, 28, 8, 31, 38, -11, 40, 48, -28, 49, + 59, -43, 58, 69, -55, 67, 79, -67, 75, 89, -77, 83, + 22, 31, 25, 29, 13, 33, 39, -7, 41, 49, -24, 50, + 59, -39, 59, 69, -52, 67, 79, -64, 76, 89, -75, 83, + 24, 34, 28, 31, 16, 34, 40, -3, 42, 49, -21, 51, + 60, -36, 59, 69, -50, 68, 80, -62, 76, 89, -73, 84, + 25, 37, 30, 32, 20, 36, 40, 1, 43, 50, -17, 51, + 60, -33, 60, 70, -47, 68, 80, -60, 76, 89, -71, 84, + 27, 40, 32, 33, 24, 37, 41, 5, 45, 51, -13, 52, + 61, -30, 61, 70, -44, 69, 80, -57, 77, 90, -69, 84, + 29, 43, 34, 35, 28, 39, 42, 9, 46, 51, -9, 53, + 61, -26, 61, 71, -41, 69, 81, -55, 77, 90, -66, 85, + 31, 46, 36, 36, 31, 41, 43, 13, 47, 52, -5, 54, + 62, -23, 62, 71, -38, 70, 81, -52, 78, 90, -64, 85, + 32, 48, 39, 37, 34, 43, 44, 17, 48, 53, -2, 55, + 62, -19, 63, 72, -35, 70, 81, -49, 78, 91, -62, 86, + 34, 51, 41, 39, 38, 44, 46, 20, 50, 54, 2, 56, + 63, -16, 64, 72, -31, 71, 82, -46, 79, 91, -59, 86, + 36, 53, 43, 40, 41, 46, 47, 24, 51, 55, 6, 57, + 64, -12, 64, 73, -28, 72, 82, -43, 79, 91, -56, 86, + 37, 56, 45, 42, 44, 48, 48, 28, 53, 56, 10, 59, + 64, -8, 65, 73, -24, 72, 83, -40, 80, 92, -53, 87, + 39, 58, 47, 43, 47, 50, 49, 31, 54, 57, 14, 60, + 65, -4, 66, 74, -21, 73, 83, -37, 80, 92, -50, 87, + 41, 60, 49, 45, 50, 51, 50, 34, 55, 58, 17, 61, + 66, -1, 67, 75, -18, 74, 84, -33, 81, 93, -47, 88, + 42, 62, 51, 46, 52, 53, 52, 38, 57, 59, 21, 62, + 67, 3, 68, 75, -14, 75, 84, -30, 82, 93, -44, 89, + 44, 65, 53, 48, 55, 55, 53, 41, 59, 60, 25, 63, + 68, 7, 69, 76, -10, 76, 85, -26, 82, 94, -41, 89, + 46, 67, 55, 49, 58, 57, 54, 44, 60, 61, 28, 65, + 69, 10, 70, 77, -7, 76, 86, -23, 83, 94, -38, 90, + 47, 69, 56, 51, 60, 58, 55, 47, 61, 62, 31, 66, + 69, 14, 71, 78, -3, 77, 86, -20, 84, 95, -35, 90, + 49, 71, 58, 52, 63, 60, 57, 50, 63, 63, 35, 67, + 70, 17, 72, 78, 0, 78, 87, -16, 85, 95, -32, 91, + 51, 74, 60, 54, 66, 62, 58, 53, 65, 64, 38, 69, + 71, 21, 74, 79, 4, 79, 88, -13, 86, 96, -28, 92, + 53, 76, 62, 55, 68, 63, 60, 56, 66, 65, 41, 70, + 72, 24, 75, 80, 8, 80, 88, -9, 86, 97, -25, 93, + 54, 78, 64, 57, 70, 65, 61, 59, 68, 66, 44, 71, + 73, 28, 76, 81, 11, 81, 89, -6, 87, 97, -21, 93, + 8, -11, -1, 22, -28, 17, 34, -39, 31, 45, -50, 43, + 57, -59, 54, 67, -68, 63, 78, -77, 72, 88, -86, 81, + 9, -9, 0, 22, -26, 17, 34, -38, 31, 45, -49, 43, + 57, -59, 54, 67, -68, 63, 78, -77, 72, 88, -86, 81, + 9, -6, 0, 22, -24, 18, 34, -37, 31, 45, -48, 43, + 57, -58, 54, 67, -68, 63, 78, -77, 72, 88, -85, 81, + 10, -2, 2, 22, -22, 18, 34, -36, 32, 46, -47, 43, + 57, -58, 54, 67, -67, 63, 78, -76, 72, 88, -85, 81, + 11, 2, 3, 23, -19, 19, 34, -34, 32, 46, -46, 43, + 57, -57, 54, 67, -66, 63, 78, -76, 73, 88, -84, 81, + 12, 6, 5, 23, -16, 20, 35, -31, 32, 46, -44, 44, + 57, -55, 54, 68, -65, 64, 78, -75, 73, 88, -84, 81, + 13, 10, 6, 24, -12, 20, 35, -29, 33, 46, -42, 44, + 57, -54, 54, 68, -64, 64, 78, -74, 73, 88, -83, 81, + 14, 14, 9, 25, -8, 22, 36, -25, 34, 46, -39, 44, + 57, -52, 55, 68, -62, 64, 78, -73, 73, 88, -82, 81, + 16, 18, 11, 25, -3, 23, 36, -22, 34, 47, -37, 45, + 58, -50, 55, 68, -61, 64, 78, -71, 73, 88, -81, 82, + 17, 22, 13, 26, 1, 24, 37, -18, 35, 47, -34, 45, + 58, -47, 55, 68, -59, 64, 79, -70, 73, 88, -80, 82, + 19, 25, 15, 27, 5, 25, 37, -15, 36, 48, -31, 46, + 58, -45, 56, 69, -57, 65, 79, -68, 74, 89, -78, 82, + 20, 28, 17, 28, 9, 27, 38, -11, 37, 48, -28, 47, + 59, -42, 56, 69, -55, 65, 79, -66, 74, 89, -77, 82, + 22, 32, 20, 30, 13, 28, 39, -6, 38, 49, -24, 47, + 59, -39, 57, 69, -52, 66, 79, -64, 74, 89, -75, 82, + 24, 35, 22, 31, 17, 30, 40, -3, 39, 49, -20, 48, + 60, -36, 57, 69, -50, 66, 80, -62, 75, 89, -73, 83, + 25, 38, 25, 32, 21, 32, 40, 1, 40, 50, -17, 49, + 60, -33, 58, 70, -47, 66, 80, -60, 75, 90, -71, 83, + 27, 40, 27, 33, 24, 33, 41, 5, 41, 51, -13, 50, + 61, -30, 59, 70, -44, 67, 80, -57, 75, 90, -69, 83, + 29, 43, 29, 35, 28, 35, 42, 10, 43, 51, -9, 51, + 61, -26, 59, 71, -41, 68, 81, -54, 76, 90, -66, 84, + 31, 46, 32, 36, 31, 37, 43, 13, 44, 52, -5, 52, + 62, -23, 60, 71, -38, 68, 81, -52, 76, 90, -64, 84, + 32, 48, 34, 37, 35, 39, 45, 17, 45, 53, -1, 53, + 62, -19, 61, 72, -35, 69, 81, -49, 77, 91, -61, 84, + 34, 51, 36, 39, 38, 40, 46, 21, 47, 54, 2, 54, + 63, -15, 62, 72, -31, 69, 82, -46, 77, 91, -59, 85, + 36, 53, 38, 40, 41, 42, 47, 25, 48, 55, 7, 55, + 64, -11, 63, 73, -28, 70, 82, -43, 78, 92, -56, 85, + 37, 56, 41, 42, 44, 44, 48, 28, 50, 56, 10, 56, + 64, -8, 63, 73, -24, 71, 83, -40, 79, 92, -53, 86, + 39, 58, 43, 43, 47, 46, 49, 31, 51, 57, 14, 57, + 65, -4, 64, 74, -21, 72, 83, -36, 79, 92, -50, 86, + 41, 60, 45, 45, 50, 48, 50, 35, 53, 58, 17, 59, + 66, -1, 65, 75, -17, 72, 84, -33, 80, 93, -47, 87, + 42, 63, 47, 46, 53, 50, 52, 38, 54, 59, 21, 60, + 67, 3, 66, 75, -14, 73, 84, -30, 80, 93, -44, 88, + 44, 65, 49, 48, 55, 52, 53, 41, 56, 60, 25, 61, + 68, 7, 68, 76, -10, 74, 85, -26, 81, 94, -41, 88, + 46, 67, 51, 49, 58, 53, 54, 44, 57, 61, 28, 62, + 69, 10, 69, 77, -7, 75, 86, -23, 82, 94, -38, 89, + 48, 69, 53, 51, 61, 55, 56, 47, 59, 62, 31, 64, + 70, 14, 70, 78, -3, 76, 86, -20, 83, 95, -35, 89, + 49, 71, 55, 52, 63, 57, 57, 50, 60, 63, 35, 65, + 70, 17, 71, 78, 0, 77, 87, -16, 83, 95, -31, 90, + 51, 74, 57, 54, 66, 59, 58, 54, 62, 64, 38, 67, + 71, 21, 72, 79, 4, 78, 88, -12, 84, 96, -28, 91, + 53, 76, 59, 55, 68, 61, 60, 56, 64, 65, 41, 68, + 72, 25, 73, 80, 8, 79, 88, -9, 85, 97, -25, 92, + 54, 78, 61, 57, 71, 62, 61, 59, 65, 67, 45, 69, + 73, 28, 74, 81, 11, 80, 89, -6, 86, 97, -21, 92, + 8, -8, -7, 22, -26, 12, 34, -38, 27, 45, -49, 40, + 57, -59, 51, 67, -68, 61, 78, -77, 71, 88, -85, 80, + 9, -6, -6, 22, -25, 13, 34, -37, 27, 45, -48, 40, + 57, -58, 51, 67, -68, 61, 78, -77, 71, 88, -85, 80, + 9, -4, -5, 22, -23, 13, 34, -36, 28, 45, -48, 40, + 57, -58, 51, 67, -67, 61, 78, -76, 71, 88, -85, 80, + 10, 0, -4, 22, -20, 13, 34, -35, 28, 46, -46, 40, + 57, -57, 51, 67, -67, 61, 78, -76, 71, 88, -85, 80, + 11, 4, -3, 23, -18, 14, 35, -33, 28, 46, -45, 40, + 57, -56, 52, 67, -66, 62, 78, -75, 71, 88, -84, 80, + 12, 7, -1, 23, -14, 15, 35, -30, 29, 46, -43, 41, + 57, -55, 52, 68, -65, 62, 78, -75, 71, 88, -83, 80, + 13, 11, 1, 24, -11, 16, 35, -28, 29, 46, -41, 41, + 57, -53, 52, 68, -64, 62, 78, -74, 71, 88, -83, 80, + 15, 15, 3, 25, -7, 17, 36, -24, 30, 47, -39, 42, + 58, -51, 52, 68, -62, 62, 78, -72, 71, 88, -82, 80, + 16, 19, 5, 26, -3, 18, 36, -21, 31, 47, -36, 42, + 58, -49, 53, 68, -61, 62, 78, -71, 72, 88, -81, 80, + 17, 22, 8, 26, 1, 19, 37, -18, 31, 47, -33, 42, + 58, -47, 53, 68, -59, 63, 79, -70, 72, 88, -79, 80, + 19, 26, 10, 27, 5, 21, 37, -14, 32, 48, -30, 43, + 58, -45, 53, 69, -57, 63, 79, -68, 72, 89, -78, 81, + 20, 29, 12, 28, 9, 22, 38, -10, 33, 48, -27, 44, + 59, -42, 54, 69, -55, 63, 79, -66, 72, 89, -76, 81, + 22, 32, 15, 30, 14, 24, 39, -6, 34, 49, -23, 45, + 59, -39, 55, 69, -52, 64, 79, -64, 73, 89, -74, 81, + 24, 35, 17, 31, 17, 26, 40, -2, 35, 49, -20, 45, + 60, -36, 55, 70, -49, 64, 80, -62, 73, 89, -73, 81, + 26, 38, 20, 32, 21, 27, 41, 2, 37, 50, -16, 46, + 60, -33, 56, 70, -47, 65, 80, -59, 73, 90, -71, 82, + 27, 41, 22, 33, 25, 29, 41, 6, 38, 51, -13, 47, + 61, -29, 56, 70, -44, 65, 80, -57, 74, 90, -69, 82, + 29, 44, 25, 35, 28, 31, 43, 10, 39, 51, -8, 48, + 61, -26, 57, 71, -40, 66, 81, -54, 74, 90, -66, 82, + 31, 46, 27, 36, 32, 33, 44, 14, 41, 52, -5, 49, + 62, -22, 58, 71, -37, 66, 81, -51, 75, 90, -64, 83, + 32, 49, 29, 37, 35, 35, 45, 17, 42, 53, -1, 50, + 62, -19, 59, 72, -34, 67, 81, -49, 75, 91, -61, 83, + 34, 51, 32, 39, 38, 36, 46, 21, 43, 54, 3, 51, + 63, -15, 59, 72, -31, 68, 82, -46, 76, 91, -59, 84, + 36, 54, 34, 40, 41, 39, 47, 25, 45, 55, 7, 52, + 64, -11, 60, 73, -27, 68, 82, -42, 76, 92, -56, 84, + 38, 56, 36, 42, 44, 40, 48, 28, 46, 56, 10, 54, + 65, -8, 61, 73, -24, 69, 83, -39, 77, 92, -53, 85, + 39, 58, 38, 43, 47, 42, 49, 32, 48, 57, 14, 55, + 65, -4, 62, 74, -21, 70, 83, -36, 78, 92, -50, 85, + 41, 61, 41, 45, 50, 44, 50, 35, 50, 58, 18, 56, + 66, 0, 63, 75, -17, 71, 84, -33, 78, 93, -47, 86, + 42, 63, 43, 46, 53, 46, 52, 38, 51, 59, 21, 57, + 67, 3, 64, 75, -14, 71, 84, -30, 79, 93, -44, 86, + 44, 65, 45, 48, 56, 48, 53, 42, 53, 60, 25, 59, + 68, 7, 65, 76, -10, 72, 85, -26, 80, 94, -41, 87, + 46, 67, 47, 49, 58, 50, 54, 45, 54, 61, 28, 60, + 69, 11, 67, 77, -6, 73, 86, -23, 81, 94, -38, 88, + 48, 69, 49, 51, 61, 52, 56, 48, 56, 62, 32, 61, + 70, 14, 68, 78, -3, 74, 86, -19, 81, 95, -34, 88, + 49, 71, 51, 52, 63, 54, 57, 51, 58, 63, 35, 63, + 70, 17, 69, 78, 1, 75, 87, -16, 82, 95, -31, 89, + 51, 74, 54, 54, 66, 56, 58, 54, 59, 64, 38, 64, + 71, 21, 70, 79, 4, 76, 88, -12, 83, 96, -28, 90, + 53, 76, 55, 55, 68, 58, 60, 56, 61, 65, 42, 66, + 72, 25, 71, 80, 8, 77, 88, -9, 84, 97, -24, 90, + 54, 78, 57, 57, 71, 59, 61, 59, 63, 67, 45, 67, + 73, 28, 72, 81, 11, 78, 89, -6, 85, 97, -21, 91, + 9, -5, -12, 22, -24, 7, 34, -37, 23, 45, -48, 36, + 57, -58, 48, 67, -68, 59, 78, -77, 69, 88, -85, 78, + 9, -3, -11, 22, -22, 8, 34, -36, 23, 45, -47, 37, + 57, -58, 49, 67, -67, 59, 78, -76, 69, 88, -85, 78, + 10, -1, -10, 22, -21, 8, 34, -35, 23, 46, -47, 37, + 57, -57, 49, 67, -67, 59, 78, -76, 69, 88, -85, 78, + 11, 3, -9, 23, -19, 8, 34, -33, 24, 46, -46, 37, + 57, -56, 49, 67, -66, 59, 78, -76, 69, 88, -84, 78, + 11, 6, -8, 23, -16, 9, 35, -32, 24, 46, -44, 37, + 57, -55, 49, 68, -65, 59, 78, -75, 69, 88, -84, 78, + 12, 9, -6, 24, -13, 10, 35, -29, 24, 46, -43, 37, + 57, -54, 49, 68, -64, 59, 78, -74, 69, 88, -83, 78, + 13, 13, -4, 24, -9, 11, 35, -27, 25, 46, -41, 38, + 57, -53, 49, 68, -63, 60, 78, -73, 69, 88, -82, 78, + 15, 17, -2, 25, -5, 12, 36, -23, 26, 47, -38, 38, + 58, -51, 50, 68, -62, 60, 78, -72, 70, 88, -81, 79, + 16, 20, 0, 26, -1, 13, 36, -20, 26, 47, -35, 39, + 58, -49, 50, 68, -60, 60, 79, -71, 70, 88, -80, 79, + 18, 23, 2, 27, 2, 14, 37, -17, 27, 47, -33, 39, + 58, -47, 50, 68, -58, 60, 79, -69, 70, 89, -79, 79, + 19, 27, 4, 28, 6, 16, 37, -13, 28, 48, -30, 40, + 58, -44, 51, 69, -56, 61, 79, -68, 70, 89, -78, 79, + 21, 30, 7, 29, 10, 17, 38, -9, 29, 48, -27, 40, + 59, -41, 51, 69, -54, 61, 79, -66, 71, 89, -76, 79, + 22, 33, 10, 30, 14, 19, 39, -5, 30, 49, -23, 41, + 59, -38, 52, 69, -51, 61, 79, -64, 71, 89, -74, 80, + 24, 36, 12, 31, 18, 21, 40, -1, 31, 49, -19, 42, + 60, -35, 52, 70, -49, 62, 80, -61, 71, 89, -72, 80, + 26, 38, 14, 32, 22, 23, 41, 2, 33, 50, -16, 43, + 60, -32, 53, 70, -46, 62, 80, -59, 72, 90, -70, 80, + 27, 41, 17, 33, 25, 24, 42, 6, 34, 51, -12, 44, + 61, -29, 54, 70, -43, 63, 80, -57, 72, 90, -68, 81, + 29, 44, 20, 35, 29, 26, 43, 10, 35, 52, -8, 45, + 61, -25, 54, 71, -40, 64, 81, -54, 73, 90, -66, 81, + 31, 47, 22, 36, 32, 28, 44, 14, 37, 52, -4, 46, + 62, -22, 55, 71, -37, 64, 81, -51, 73, 90, -63, 81, + 32, 49, 24, 37, 35, 30, 45, 18, 38, 53, -1, 47, + 62, -18, 56, 72, -34, 65, 81, -48, 73, 91, -61, 82, + 34, 51, 27, 39, 38, 32, 46, 21, 40, 54, 3, 48, + 63, -15, 57, 72, -31, 65, 82, -45, 74, 91, -58, 82, + 36, 54, 29, 40, 42, 34, 47, 25, 41, 55, 7, 49, + 64, -11, 58, 73, -27, 66, 82, -42, 75, 92, -55, 83, + 38, 56, 32, 42, 45, 36, 48, 29, 43, 56, 11, 50, + 65, -7, 59, 73, -24, 67, 83, -39, 75, 92, -53, 83, + 39, 59, 34, 43, 48, 38, 49, 32, 44, 57, 14, 52, + 65, -4, 60, 74, -20, 68, 83, -36, 76, 92, -50, 84, + 41, 61, 36, 45, 50, 40, 50, 35, 46, 58, 18, 53, + 66, 0, 61, 75, -17, 69, 84, -33, 77, 93, -47, 84, + 43, 63, 38, 46, 53, 42, 52, 38, 48, 59, 21, 54, + 67, 3, 62, 75, -13, 69, 84, -30, 77, 93, -44, 85, + 44, 65, 41, 48, 56, 44, 53, 42, 49, 60, 25, 56, + 68, 7, 63, 76, -10, 70, 85, -26, 78, 94, -41, 86, + 46, 67, 43, 49, 58, 46, 54, 45, 51, 61, 29, 57, + 69, 11, 64, 77, -6, 71, 86, -23, 79, 94, -37, 86, + 48, 70, 45, 51, 61, 48, 56, 48, 53, 62, 32, 58, + 70, 14, 65, 78, -3, 72, 86, -19, 80, 95, -34, 87, + 49, 72, 47, 52, 63, 50, 57, 51, 54, 63, 35, 60, + 70, 18, 66, 78, 1, 73, 87, -16, 80, 95, -31, 87, + 51, 74, 50, 54, 66, 52, 58, 54, 56, 64, 39, 61, + 72, 22, 68, 79, 5, 74, 88, -12, 81, 96, -28, 88, + 53, 76, 52, 55, 68, 54, 60, 57, 58, 65, 42, 63, + 72, 25, 69, 80, 8, 75, 88, -9, 82, 97, -24, 89, + 54, 78, 54, 57, 71, 56, 61, 59, 60, 67, 45, 64, + 73, 28, 70, 81, 11, 76, 89, -5, 83, 97, -21, 90, + 9, -1, -17, 22, -21, 2, 34, -35, 19, 45, -47, 33, + 57, -57, 45, 67, -67, 56, 78, -76, 67, 88, -85, 76, + 10, 1, -16, 22, -20, 3, 34, -35, 19, 46, -46, 33, + 57, -57, 45, 67, -67, 56, 78, -76, 67, 88, -85, 76, + 10, 3, -16, 23, -19, 3, 34, -34, 19, 46, -46, 33, + 57, -56, 45, 67, -66, 56, 78, -76, 67, 88, -84, 76, + 11, 5, -14, 23, -16, 3, 35, -32, 19, 46, -44, 33, + 57, -56, 46, 67, -66, 57, 78, -75, 67, 88, -84, 76, + 12, 8, -13, 23, -14, 4, 35, -30, 20, 46, -43, 33, + 57, -55, 46, 68, -65, 57, 78, -74, 67, 88, -83, 76, + 13, 11, -11, 24, -11, 5, 35, -28, 20, 46, -42, 34, + 57, -53, 46, 68, -64, 57, 78, -74, 67, 88, -83, 76, + 14, 15, -10, 24, -8, 6, 35, -25, 21, 46, -40, 34, + 57, -52, 46, 68, -63, 57, 78, -73, 67, 88, -82, 77, + 15, 18, -7, 25, -4, 7, 36, -22, 21, 47, -37, 34, + 58, -50, 47, 68, -61, 57, 78, -72, 67, 88, -81, 77, + 17, 21, -5, 26, 0, 8, 36, -19, 22, 47, -35, 35, + 58, -48, 47, 68, -60, 57, 79, -70, 68, 88, -80, 77, + 18, 25, -3, 27, 4, 10, 37, -16, 23, 47, -32, 35, + 58, -46, 47, 68, -58, 58, 79, -69, 68, 89, -79, 77, + 19, 28, -1, 28, 7, 11, 38, -12, 24, 48, -29, 36, + 58, -43, 48, 69, -56, 58, 79, -67, 68, 89, -77, 77, + 21, 30, 2, 29, 11, 12, 38, -9, 25, 48, -26, 37, + 59, -41, 48, 69, -54, 58, 79, -65, 68, 89, -76, 77, + 23, 34, 4, 30, 15, 14, 39, -4, 26, 49, -22, 38, + 59, -38, 49, 69, -51, 59, 79, -63, 69, 89, -74, 78, + 24, 36, 7, 31, 19, 16, 40, -1, 27, 50, -19, 38, + 60, -35, 49, 70, -48, 59, 80, -61, 69, 89, -72, 78, + 26, 39, 9, 32, 22, 18, 41, 3, 28, 50, -15, 39, + 60, -32, 50, 70, -46, 60, 80, -59, 69, 90, -70, 78, + 27, 42, 12, 33, 26, 20, 42, 7, 30, 51, -12, 40, + 61, -28, 51, 70, -43, 60, 80, -56, 70, 90, -68, 79, + 29, 45, 15, 35, 29, 22, 43, 11, 31, 52, -7, 41, + 61, -25, 51, 71, -40, 61, 81, -53, 70, 90, -66, 79, + 31, 47, 17, 36, 33, 24, 44, 15, 33, 52, -4, 42, + 62, -21, 52, 71, -37, 62, 81, -51, 71, 90, -63, 79, + 33, 49, 19, 38, 36, 26, 45, 18, 34, 53, 0, 43, + 62, -18, 53, 72, -34, 62, 81, -48, 71, 91, -61, 80, + 34, 52, 22, 39, 39, 28, 46, 22, 36, 54, 3, 45, + 63, -14, 54, 72, -30, 63, 82, -45, 72, 91, -58, 80, + 36, 54, 25, 41, 42, 30, 47, 26, 37, 55, 8, 46, + 64, -11, 55, 73, -27, 64, 82, -42, 73, 92, -55, 81, + 38, 57, 27, 42, 45, 32, 48, 29, 39, 56, 11, 47, + 65, -7, 56, 74, -23, 64, 83, -39, 73, 92, -52, 81, + 39, 59, 29, 43, 48, 34, 49, 32, 40, 57, 15, 48, + 65, -3, 57, 74, -20, 65, 83, -36, 74, 92, -50, 82, + 41, 61, 32, 45, 51, 36, 51, 36, 42, 58, 18, 50, + 66, 0, 58, 75, -17, 66, 84, -32, 74, 93, -47, 82, + 43, 63, 34, 46, 53, 38, 52, 39, 44, 59, 22, 51, + 67, 4, 59, 75, -13, 67, 84, -29, 75, 93, -44, 83, + 44, 66, 36, 48, 56, 40, 53, 42, 46, 60, 25, 52, + 68, 8, 60, 76, -9, 68, 85, -26, 76, 94, -40, 84, + 46, 68, 39, 49, 59, 42, 54, 45, 47, 61, 29, 54, + 69, 11, 61, 77, -6, 69, 86, -22, 77, 94, -37, 84, + 48, 70, 41, 51, 61, 44, 56, 48, 49, 62, 32, 55, + 70, 15, 62, 78, -2, 70, 86, -19, 78, 95, -34, 85, + 49, 72, 43, 52, 64, 46, 57, 51, 51, 63, 35, 57, + 71, 18, 64, 78, 1, 71, 87, -16, 78, 95, -31, 86, + 51, 74, 46, 54, 66, 48, 58, 54, 53, 64, 39, 58, + 72, 22, 65, 79, 5, 72, 88, -12, 79, 96, -27, 87, + 53, 76, 48, 55, 69, 50, 60, 57, 54, 65, 42, 60, + 73, 25, 66, 80, 8, 73, 88, -9, 80, 97, -24, 87, + 54, 78, 50, 57, 71, 52, 61, 60, 56, 67, 45, 61, + 74, 28, 67, 81, 12, 74, 89, -5, 81, 97, -21, 88, + 10, 3, -22, 22, -18, -3, 34, -33, 14, 46, -45, 28, + 57, -56, 41, 67, -66, 53, 78, -76, 64, 88, -84, 74, + 10, 5, -22, 23, -17, -3, 34, -33, 14, 46, -45, 28, + 57, -56, 42, 67, -66, 53, 78, -75, 64, 88, -84, 74, + 11, 6, -21, 23, -16, -3, 34, -32, 14, 46, -44, 28, + 57, -55, 42, 67, -65, 53, 78, -75, 64, 88, -84, 74, + 12, 9, -20, 23, -14, -2, 35, -30, 14, 46, -43, 29, + 57, -55, 42, 68, -65, 53, 78, -74, 64, 88, -83, 74, + 12, 11, -19, 24, -11, -1, 35, -28, 15, 46, -42, 29, + 57, -54, 42, 68, -64, 53, 78, -74, 64, 88, -83, 74, + 13, 14, -17, 24, -9, -1, 35, -26, 15, 46, -40, 29, + 57, -52, 42, 68, -63, 54, 78, -73, 64, 88, -82, 74, + 14, 17, -15, 25, -6, 0, 36, -24, 15, 46, -38, 29, + 57, -51, 42, 68, -62, 54, 78, -72, 64, 88, -81, 74, + 16, 20, -13, 25, -2, 1, 36, -21, 16, 47, -36, 30, + 58, -49, 43, 68, -60, 54, 78, -71, 65, 88, -80, 74, + 17, 23, -11, 26, 2, 3, 37, -18, 17, 47, -33, 30, + 58, -47, 43, 68, -59, 54, 79, -70, 65, 88, -79, 74, + 18, 26, -9, 27, 5, 4, 37, -14, 18, 48, -31, 31, + 58, -45, 43, 68, -57, 55, 79, -68, 65, 89, -78, 75, + 20, 29, -7, 28, 9, 5, 38, -11, 19, 48, -28, 32, + 59, -43, 44, 69, -55, 55, 79, -67, 65, 89, -77, 75, + 21, 32, -4, 29, 12, 7, 38, -7, 20, 48, -25, 32, + 59, -40, 44, 69, -53, 55, 79, -65, 66, 89, -75, 75, + 23, 35, -1, 30, 16, 9, 39, -3, 21, 49, -21, 33, + 59, -37, 45, 69, -50, 56, 79, -63, 66, 89, -73, 75, + 25, 37, 1, 31, 20, 11, 40, 0, 22, 50, -18, 34, + 60, -34, 46, 70, -48, 56, 80, -60, 66, 89, -72, 76, + 26, 40, 3, 32, 23, 12, 41, 4, 23, 50, -14, 35, + 60, -31, 46, 70, -45, 57, 80, -58, 67, 90, -70, 76, + 28, 42, 6, 34, 27, 14, 42, 8, 25, 51, -11, 36, + 61, -28, 47, 70, -42, 57, 80, -56, 67, 90, -68, 76, + 30, 45, 9, 35, 30, 16, 43, 12, 26, 52, -7, 37, + 61, -24, 48, 71, -39, 58, 81, -53, 68, 90, -65, 77, + 31, 48, 11, 36, 33, 18, 44, 15, 28, 52, -3, 38, + 62, -21, 49, 71, -36, 58, 81, -50, 68, 91, -63, 77, + 33, 50, 14, 38, 36, 20, 45, 19, 29, 53, 0, 39, + 63, -17, 49, 72, -33, 59, 81, -48, 69, 91, -60, 78, + 34, 52, 16, 39, 39, 22, 46, 22, 31, 54, 4, 40, + 63, -14, 50, 72, -30, 60, 82, -45, 69, 91, -58, 78, + 36, 55, 19, 41, 43, 25, 47, 26, 33, 55, 8, 42, + 64, -10, 51, 73, -26, 61, 82, -41, 70, 92, -55, 79, + 38, 57, 21, 42, 46, 27, 48, 30, 34, 56, 12, 43, + 65, -6, 52, 74, -23, 61, 83, -38, 70, 92, -52, 79, + 40, 59, 24, 43, 48, 29, 49, 33, 36, 57, 15, 44, + 65, -3, 53, 74, -20, 62, 83, -35, 71, 92, -49, 80, + 41, 61, 26, 45, 51, 31, 51, 36, 37, 58, 19, 46, + 66, 1, 54, 75, -16, 63, 84, -32, 72, 93, -46, 80, + 43, 64, 29, 46, 54, 33, 52, 39, 39, 59, 22, 47, + 67, 4, 55, 75, -13, 64, 84, -29, 73, 93, -43, 81, + 45, 66, 31, 48, 57, 35, 53, 43, 41, 60, 26, 48, + 68, 8, 57, 76, -9, 65, 85, -25, 73, 94, -40, 81, + 46, 68, 34, 49, 59, 37, 54, 46, 43, 61, 29, 50, + 69, 11, 58, 77, -5, 66, 86, -22, 74, 94, -37, 82, + 48, 70, 36, 51, 62, 39, 56, 48, 45, 62, 32, 51, + 70, 15, 59, 78, -2, 67, 86, -19, 75, 95, -34, 83, + 49, 72, 38, 52, 64, 41, 57, 51, 46, 63, 36, 53, + 71, 18, 60, 78, 1, 68, 87, -15, 76, 95, -31, 83, + 51, 74, 41, 54, 67, 44, 58, 54, 48, 64, 39, 54, + 72, 22, 62, 79, 5, 69, 88, -12, 77, 96, -27, 84, + 53, 76, 43, 55, 69, 46, 60, 57, 50, 66, 42, 56, + 73, 25, 63, 80, 9, 70, 88, -8, 78, 97, -24, 85, + 54, 78, 45, 57, 71, 48, 61, 60, 52, 67, 45, 57, + 74, 29, 64, 81, 12, 71, 89, -5, 78, 97, -21, 86, + 11, 7, -27, 23, -15, -8, 34, -31, 9, 46, -44, 24, + 57, -55, 38, 67, -65, 50, 78, -75, 61, 88, -84, 71, + 11, 9, -26, 23, -14, -8, 35, -31, 9, 46, -43, 24, + 57, -55, 38, 67, -65, 50, 78, -75, 61, 88, -84, 71, + 12, 10, -26, 23, -13, -8, 35, -30, 9, 46, -43, 24, + 57, -54, 38, 68, -65, 50, 78, -74, 61, 88, -83, 71, + 12, 12, -25, 23, -11, -7, 35, -28, 10, 46, -42, 24, + 57, -54, 38, 68, -64, 50, 78, -74, 61, 88, -83, 71, + 13, 14, -23, 24, -9, -6, 35, -27, 10, 46, -40, 25, + 57, -53, 38, 68, -63, 50, 78, -73, 61, 88, -82, 71, + 14, 16, -22, 24, -6, -6, 35, -25, 10, 46, -39, 25, + 57, -51, 38, 68, -62, 50, 78, -72, 62, 88, -82, 72, + 15, 19, -20, 25, -4, -5, 36, -22, 11, 47, -37, 25, + 58, -50, 39, 68, -61, 51, 78, -72, 62, 88, -81, 72, + 16, 22, -18, 26, 0, -4, 36, -19, 12, 47, -35, 26, + 58, -48, 39, 68, -60, 51, 79, -70, 62, 88, -80, 72, + 17, 25, -16, 26, 3, -2, 37, -16, 12, 47, -32, 26, + 58, -46, 39, 68, -58, 51, 79, -69, 62, 88, -79, 72, + 19, 27, -14, 27, 7, -1, 37, -13, 13, 48, -30, 27, + 58, -44, 40, 69, -56, 51, 79, -68, 62, 89, -78, 72, + 20, 30, -12, 28, 10, 1, 38, -10, 14, 48, -27, 27, + 59, -42, 40, 69, -54, 52, 79, -66, 63, 89, -76, 72, + 22, 33, -9, 29, 14, 2, 39, -6, 15, 49, -24, 28, + 59, -39, 41, 69, -52, 52, 79, -64, 63, 89, -75, 73, + 23, 36, -7, 30, 17, 4, 39, -2, 16, 49, -20, 29, + 59, -36, 41, 69, -50, 53, 80, -62, 63, 89, -73, 73, + 25, 38, -4, 31, 21, 6, 40, 1, 18, 50, -17, 30, + 60, -33, 42, 70, -47, 53, 80, -60, 64, 89, -71, 73, + 26, 41, -2, 33, 24, 7, 41, 5, 19, 50, -13, 31, + 60, -30, 43, 70, -45, 53, 80, -58, 64, 90, -69, 74, + 28, 43, 1, 34, 27, 9, 42, 8, 20, 51, -10, 32, + 61, -27, 43, 70, -42, 54, 80, -55, 64, 90, -67, 74, + 30, 46, 4, 35, 31, 12, 43, 13, 22, 52, -6, 33, + 61, -23, 44, 71, -39, 55, 81, -52, 65, 90, -65, 74, + 31, 48, 6, 37, 34, 14, 44, 16, 23, 53, -2, 34, + 62, -20, 45, 71, -36, 55, 81, -50, 65, 91, -62, 75, + 33, 51, 9, 38, 37, 16, 45, 20, 25, 53, 1, 35, + 63, -17, 46, 72, -32, 56, 82, -47, 66, 91, -60, 75, + 35, 53, 11, 39, 40, 18, 46, 23, 26, 54, 5, 36, + 63, -13, 47, 72, -29, 57, 82, -44, 67, 91, -57, 76, + 36, 55, 14, 41, 43, 20, 47, 27, 28, 55, 9, 38, + 64, -9, 48, 73, -26, 58, 82, -41, 67, 92, -54, 76, + 38, 58, 17, 42, 46, 22, 48, 30, 30, 56, 12, 39, + 65, -6, 49, 74, -22, 58, 83, -38, 68, 92, -52, 77, + 40, 60, 19, 44, 49, 24, 50, 33, 31, 57, 16, 40, + 65, -2, 50, 74, -19, 59, 83, -35, 68, 92, -49, 77, + 41, 62, 21, 45, 51, 26, 51, 36, 33, 58, 19, 42, + 66, 1, 51, 75, -16, 60, 84, -32, 69, 93, -46, 78, + 43, 64, 24, 46, 54, 28, 52, 40, 35, 59, 23, 43, + 67, 5, 52, 76, -12, 61, 85, -29, 70, 93, -43, 78, + 45, 66, 27, 48, 57, 31, 53, 43, 37, 60, 26, 45, + 68, 8, 53, 76, -8, 62, 85, -25, 71, 94, -40, 79, + 46, 68, 29, 50, 59, 33, 55, 46, 39, 61, 30, 46, + 69, 12, 54, 77, -5, 63, 86, -22, 71, 94, -37, 80, + 48, 70, 31, 51, 62, 35, 56, 49, 40, 62, 33, 48, + 70, 15, 56, 78, -2, 64, 86, -18, 72, 95, -33, 80, + 50, 72, 34, 52, 64, 37, 57, 52, 42, 63, 36, 49, + 71, 19, 57, 78, 2, 65, 87, -15, 73, 95, -30, 81, + 51, 75, 36, 54, 67, 39, 59, 55, 44, 64, 40, 51, + 72, 22, 58, 79, 6, 66, 88, -11, 74, 96, -27, 82, + 53, 77, 38, 56, 69, 41, 60, 58, 46, 66, 43, 52, + 73, 26, 60, 80, 9, 67, 88, -8, 75, 97, -23, 83, + 55, 79, 41, 57, 72, 43, 61, 60, 48, 67, 46, 54, + 74, 29, 61, 81, 12, 68, 89, -5, 76, 97, -20, 84, + 11, 11, -31, 23, -12, -13, 35, -29, 4, 46, -42, 20, + 57, -54, 34, 68, -64, 46, 78, -74, 58, 88, -83, 69, + 12, 12, -31, 23, -11, -13, 35, -28, 4, 46, -42, 20, + 57, -54, 34, 68, -64, 46, 78, -74, 58, 88, -83, 69, + 12, 13, -30, 23, -10, -12, 35, -27, 5, 46, -41, 20, + 57, -53, 34, 68, -64, 47, 78, -74, 58, 88, -83, 69, + 13, 15, -29, 24, -8, -12, 35, -26, 5, 46, -40, 20, + 57, -52, 34, 68, -63, 47, 78, -73, 58, 88, -82, 69, + 14, 17, -28, 24, -6, -11, 35, -25, 5, 46, -39, 20, + 57, -51, 34, 68, -62, 47, 78, -72, 58, 88, -82, 69, + 14, 19, -27, 25, -4, -10, 36, -23, 6, 46, -37, 21, + 57, -50, 35, 68, -61, 47, 78, -72, 59, 88, -81, 69, + 15, 21, -25, 25, -1, -10, 36, -20, 6, 47, -36, 21, + 58, -49, 35, 68, -60, 47, 78, -71, 59, 88, -80, 69, + 17, 24, -23, 26, 2, -8, 36, -17, 7, 47, -33, 21, + 58, -47, 35, 68, -59, 47, 79, -70, 59, 88, -79, 69, + 18, 27, -21, 27, 5, -7, 37, -15, 8, 47, -31, 22, + 58, -45, 36, 68, -57, 48, 79, -68, 59, 89, -78, 69, + 19, 29, -19, 28, 8, -6, 37, -11, 9, 48, -28, 23, + 58, -43, 36, 69, -55, 48, 79, -67, 59, 89, -77, 70, + 21, 32, -16, 28, 12, -4, 38, -8, 10, 48, -26, 23, + 59, -41, 36, 69, -54, 48, 79, -65, 60, 89, -76, 70, + 22, 34, -14, 29, 15, -3, 39, -5, 11, 49, -23, 24, + 59, -38, 37, 69, -51, 49, 79, -64, 60, 89, -74, 70, + 24, 37, -11, 31, 19, -1, 40, -1, 12, 49, -19, 25, + 60, -35, 38, 69, -49, 49, 80, -61, 60, 89, -72, 70, + 25, 39, -9, 32, 22, 1, 40, 2, 13, 50, -16, 26, + 60, -32, 38, 70, -46, 50, 80, -59, 61, 89, -71, 71, + 27, 42, -7, 33, 25, 3, 41, 6, 14, 50, -12, 27, + 60, -29, 39, 70, -44, 50, 80, -57, 61, 90, -69, 71, + 28, 44, -4, 34, 28, 5, 42, 9, 16, 51, -9, 28, + 61, -26, 40, 71, -41, 51, 80, -55, 61, 90, -67, 71, + 30, 47, -1, 35, 32, 7, 43, 13, 17, 52, -5, 29, + 62, -23, 40, 71, -38, 51, 81, -52, 62, 90, -64, 72, + 32, 49, 1, 37, 35, 9, 44, 17, 19, 53, -2, 30, + 62, -19, 41, 71, -35, 52, 81, -49, 62, 91, -62, 72, + 33, 51, 4, 38, 38, 11, 45, 20, 20, 53, 2, 31, + 63, -16, 42, 72, -32, 53, 82, -47, 63, 91, -59, 73, + 35, 53, 6, 39, 41, 13, 46, 24, 22, 54, 5, 32, + 63, -13, 43, 72, -29, 53, 82, -44, 64, 91, -57, 73, + 37, 56, 9, 41, 44, 15, 47, 27, 24, 55, 9, 34, + 64, -9, 44, 73, -25, 54, 83, -40, 64, 92, -54, 74, + 38, 58, 12, 42, 47, 17, 49, 31, 25, 56, 13, 35, + 65, -5, 45, 74, -22, 55, 83, -37, 65, 92, -51, 74, + 40, 60, 14, 44, 49, 19, 50, 34, 27, 57, 16, 36, + 66, -2, 46, 74, -19, 56, 83, -34, 66, 93, -48, 75, + 41, 62, 17, 45, 52, 22, 51, 37, 29, 58, 20, 38, + 66, 2, 47, 75, -15, 57, 84, -31, 66, 93, -46, 75, + 43, 64, 19, 47, 55, 24, 52, 40, 31, 59, 23, 39, + 67, 5, 48, 76, -12, 58, 85, -28, 67, 93, -43, 76, + 45, 67, 22, 48, 57, 26, 53, 43, 33, 60, 27, 41, + 68, 9, 50, 76, -8, 59, 85, -24, 68, 94, -39, 77, + 46, 69, 24, 50, 60, 28, 55, 46, 34, 61, 30, 42, + 69, 12, 51, 77, -5, 60, 86, -21, 69, 94, -36, 77, + 48, 71, 27, 51, 62, 30, 56, 49, 36, 62, 33, 44, + 70, 16, 52, 78, -1, 61, 86, -18, 69, 95, -33, 78, + 50, 73, 29, 53, 65, 32, 57, 52, 38, 63, 36, 45, + 71, 19, 53, 79, 2, 62, 87, -15, 70, 96, -30, 79, + 51, 75, 31, 54, 67, 35, 59, 55, 40, 65, 40, 47, + 72, 23, 55, 79, 6, 63, 88, -11, 71, 96, -26, 79, + 53, 77, 34, 56, 70, 37, 60, 58, 42, 66, 43, 48, + 73, 26, 56, 80, 9, 64, 88, -8, 72, 97, -23, 80, + 55, 79, 36, 57, 72, 39, 61, 61, 44, 67, 46, 50, + 74, 29, 57, 81, 13, 65, 89, -4, 73, 97, -20, 81, + 12, 15, -36, 23, -9, -18, 35, -27, 0, 46, -41, 15, + 57, -53, 30, 68, -63, 43, 78, -73, 55, 88, -82, 66, + 13, 16, -35, 24, -8, -17, 35, -26, 0, 46, -40, 15, + 57, -52, 30, 68, -63, 43, 78, -73, 55, 88, -82, 66, + 13, 17, -34, 24, -7, -17, 35, -25, 0, 46, -39, 16, + 57, -52, 30, 68, -63, 43, 78, -73, 55, 88, -82, 66, + 14, 18, -34, 24, -5, -17, 35, -24, 0, 46, -38, 16, + 57, -51, 30, 68, -62, 43, 78, -72, 55, 88, -82, 66, + 14, 20, -32, 25, -4, -16, 36, -22, 1, 46, -37, 16, + 57, -50, 30, 68, -61, 43, 78, -72, 55, 88, -81, 66, + 15, 22, -31, 25, -1, -15, 36, -20, 1, 47, -36, 16, + 58, -49, 31, 68, -60, 43, 78, -71, 55, 88, -80, 66, + 16, 24, -29, 26, 1, -14, 36, -18, 2, 47, -34, 17, + 58, -48, 31, 68, -59, 44, 78, -70, 55, 88, -80, 66, + 17, 26, -27, 26, 4, -13, 37, -15, 2, 47, -32, 17, + 58, -46, 31, 68, -58, 44, 79, -69, 56, 88, -79, 66, + 18, 28, -25, 27, 7, -12, 37, -13, 3, 48, -29, 18, + 58, -44, 32, 68, -56, 44, 79, -67, 56, 89, -78, 67, + 20, 31, -23, 28, 10, -11, 38, -10, 4, 48, -27, 18, + 59, -42, 32, 69, -54, 44, 79, -66, 56, 89, -76, 67, + 21, 33, -21, 29, 13, -9, 38, -7, 5, 48, -24, 19, + 59, -40, 32, 69, -53, 45, 79, -64, 56, 89, -75, 67, + 22, 35, -19, 30, 17, -8, 39, -3, 6, 49, -21, 20, + 59, -37, 33, 69, -51, 45, 79, -63, 57, 89, -74, 67, + 24, 38, -16, 31, 20, -6, 40, 0, 7, 49, -18, 20, + 60, -34, 34, 70, -48, 46, 80, -61, 57, 89, -72, 68, + 25, 40, -14, 32, 23, -4, 41, 4, 8, 50, -15, 21, + 60, -31, 34, 70, -46, 46, 80, -59, 57, 90, -70, 68, + 27, 43, -11, 33, 26, -2, 41, 7, 10, 51, -11, 22, + 61, -28, 35, 70, -43, 47, 80, -56, 58, 90, -68, 68, + 29, 45, -9, 34, 29, 0, 42, 11, 11, 51, -8, 23, + 61, -25, 36, 71, -40, 47, 81, -54, 58, 90, -66, 68, + 30, 48, -6, 36, 33, 2, 43, 14, 13, 52, -4, 24, + 62, -22, 37, 71, -37, 48, 81, -51, 59, 90, -64, 69, + 32, 50, -4, 37, 36, 4, 44, 18, 14, 53, -1, 26, + 62, -19, 37, 72, -34, 48, 81, -49, 59, 91, -61, 69, + 33, 52, -1, 38, 39, 6, 45, 21, 16, 54, 3, 27, + 63, -15, 38, 72, -31, 49, 82, -46, 60, 91, -59, 70, + 35, 54, 1, 40, 41, 8, 46, 24, 17, 54, 6, 28, + 63, -12, 39, 73, -28, 50, 82, -43, 60, 91, -56, 70, + 37, 57, 4, 41, 45, 10, 48, 28, 19, 55, 10, 29, + 64, -8, 40, 73, -24, 51, 83, -40, 61, 92, -53, 71, + 38, 59, 7, 43, 47, 13, 49, 31, 21, 56, 14, 31, + 65, -5, 41, 74, -21, 52, 83, -37, 62, 92, -51, 71, + 40, 61, 9, 44, 50, 15, 50, 35, 23, 57, 17, 32, + 66, -1, 42, 74, -18, 52, 84, -34, 62, 93, -48, 72, + 42, 63, 12, 45, 53, 17, 51, 38, 24, 58, 20, 33, + 66, 2, 43, 75, -15, 53, 84, -31, 63, 93, -45, 73, + 43, 65, 14, 47, 55, 19, 52, 41, 26, 59, 24, 35, + 67, 6, 45, 76, -11, 54, 85, -28, 64, 93, -42, 73, + 45, 67, 17, 48, 58, 21, 54, 44, 28, 60, 27, 36, + 68, 9, 46, 76, -8, 55, 85, -24, 65, 94, -39, 74, + 47, 69, 19, 50, 60, 24, 55, 47, 30, 61, 31, 38, + 69, 13, 47, 77, -4, 56, 86, -21, 66, 94, -36, 75, + 48, 71, 22, 51, 63, 26, 56, 50, 32, 62, 34, 40, + 70, 16, 48, 78, -1, 57, 86, -17, 66, 95, -33, 75, + 50, 73, 24, 53, 65, 28, 57, 52, 34, 63, 37, 41, + 71, 20, 50, 79, 3, 58, 87, -14, 67, 96, -30, 76, + 52, 75, 27, 54, 68, 30, 59, 56, 36, 65, 40, 43, + 72, 23, 51, 79, 6, 59, 88, -10, 68, 96, -26, 77, + 53, 77, 29, 56, 70, 32, 60, 58, 38, 66, 43, 44, + 73, 27, 52, 80, 10, 61, 89, -7, 69, 97, -23, 78, + 55, 79, 32, 57, 72, 35, 61, 61, 40, 67, 46, 46, + 74, 30, 54, 81, 13, 62, 89, -4, 70, 97, -20, 78, + 13, 19, -40, 24, -5, -22, 35, -24, -5, 46, -39, 11, + 57, -51, 26, 68, -62, 39, 78, -72, 52, 88, -82, 63, + 13, 19, -39, 24, -5, -22, 35, -23, -5, 46, -38, 11, + 57, -51, 26, 68, -62, 39, 78, -72, 52, 88, -81, 63, + 14, 20, -39, 24, -4, -22, 35, -23, -5, 46, -38, 11, + 57, -50, 26, 68, -61, 39, 78, -72, 52, 88, -81, 63, + 14, 21, -38, 25, -2, -21, 36, -21, -4, 46, -37, 11, + 57, -50, 26, 68, -61, 39, 78, -71, 52, 88, -81, 63, + 15, 23, -37, 25, -1, -21, 36, -20, -4, 47, -35, 12, + 58, -49, 26, 68, -60, 39, 78, -71, 52, 88, -80, 63, + 16, 24, -35, 25, 1, -20, 36, -18, -4, 47, -34, 12, + 58, -48, 27, 68, -59, 40, 78, -70, 52, 88, -80, 63, + 17, 26, -34, 26, 4, -19, 36, -16, -3, 47, -32, 12, + 58, -46, 27, 68, -58, 40, 79, -69, 52, 88, -79, 63, + 18, 28, -32, 27, 7, -18, 37, -13, -2, 47, -30, 13, + 58, -44, 27, 68, -57, 40, 79, -68, 52, 89, -78, 63, + 19, 30, -30, 27, 9, -17, 37, -11, -2, 48, -28, 13, + 58, -43, 28, 69, -55, 40, 79, -67, 53, 89, -77, 64, + 20, 33, -28, 28, 12, -15, 38, -8, -1, 48, -25, 14, + 59, -41, 28, 69, -53, 41, 79, -65, 53, 89, -76, 64, + 21, 35, -26, 29, 15, -14, 38, -5, 0, 49, -23, 14, + 59, -38, 28, 69, -52, 41, 79, -64, 53, 89, -74, 64, + 23, 37, -23, 30, 18, -12, 39, -2, 1, 49, -20, 15, + 59, -36, 29, 69, -49, 41, 79, -62, 53, 89, -73, 64, + 24, 39, -21, 31, 22, -10, 40, 2, 3, 50, -17, 16, + 60, -33, 30, 70, -47, 42, 80, -60, 54, 89, -71, 64, + 26, 42, -19, 32, 25, -9, 41, 5, 4, 50, -13, 17, + 60, -30, 30, 70, -45, 42, 80, -58, 54, 90, -69, 65, + 27, 44, -16, 33, 28, -7, 42, 8, 5, 51, -10, 18, + 61, -27, 31, 70, -42, 43, 80, -56, 55, 90, -67, 65, + 29, 46, -14, 35, 31, -5, 42, 12, 6, 51, -7, 19, + 61, -24, 32, 71, -39, 43, 81, -53, 55, 90, -65, 65, + 31, 48, -11, 36, 34, -3, 43, 16, 8, 52, -3, 20, + 62, -21, 33, 71, -36, 44, 81, -50, 56, 90, -63, 66, + 32, 51, -8, 37, 37, -1, 44, 19, 10, 53, 0, 21, + 62, -18, 33, 72, -33, 45, 81, -48, 56, 91, -61, 66, + 34, 53, -6, 39, 40, 1, 45, 22, 11, 54, 4, 22, + 63, -14, 34, 72, -30, 45, 82, -45, 57, 91, -58, 67, + 35, 55, -3, 40, 42, 3, 46, 25, 13, 55, 7, 24, + 64, -11, 35, 73, -27, 46, 82, -42, 57, 91, -56, 67, + 37, 57, 0, 41, 45, 6, 48, 29, 15, 55, 11, 25, + 64, -7, 36, 73, -24, 47, 83, -39, 58, 92, -53, 68, + 39, 59, 2, 43, 48, 8, 49, 32, 16, 56, 14, 26, + 65, -4, 37, 74, -21, 48, 83, -36, 59, 92, -50, 68, + 40, 61, 5, 44, 51, 10, 50, 35, 18, 57, 18, 28, + 66, -1, 38, 74, -17, 49, 84, -33, 59, 93, -47, 69, + 42, 63, 7, 45, 53, 12, 51, 38, 20, 58, 21, 29, + 67, 3, 40, 75, -14, 50, 84, -30, 60, 93, -44, 70, + 43, 65, 9, 47, 56, 14, 52, 41, 22, 59, 24, 31, + 67, 6, 41, 76, -11, 51, 85, -27, 61, 94, -42, 70, + 45, 68, 12, 49, 58, 17, 54, 45, 24, 60, 28, 32, + 68, 10, 42, 76, -7, 52, 85, -23, 62, 94, -38, 71, + 47, 70, 15, 50, 61, 19, 55, 47, 26, 61, 31, 34, + 69, 13, 43, 77, -4, 53, 86, -20, 62, 95, -35, 72, + 48, 72, 17, 51, 63, 21, 56, 50, 27, 62, 34, 35, + 70, 17, 44, 78, 0, 54, 87, -17, 63, 95, -32, 72, + 50, 74, 20, 53, 66, 23, 57, 53, 29, 64, 37, 37, + 71, 20, 46, 79, 3, 55, 87, -14, 64, 96, -29, 73, + 52, 76, 22, 54, 68, 26, 59, 56, 31, 65, 41, 39, + 72, 24, 47, 80, 7, 56, 88, -10, 65, 96, -26, 74, + 53, 78, 25, 56, 70, 28, 60, 59, 33, 66, 44, 40, + 73, 27, 49, 80, 10, 57, 89, -7, 66, 97, -22, 75, + 55, 80, 27, 57, 73, 30, 62, 61, 35, 67, 47, 42, + 74, 30, 50, 81, 14, 58, 89, -3, 67, 97, -19, 75, + 14, 23, -44, 24, -2, -27, 35, -21, -10, 46, -36, 6, + 57, -49, 21, 68, -61, 35, 78, -71, 48, 88, -81, 59, + 14, 23, -44, 25, -1, -27, 36, -20, -10, 46, -36, 6, + 57, -49, 21, 68, -60, 35, 78, -71, 48, 88, -80, 59, + 15, 24, -43, 25, 0, -27, 36, -20, -10, 47, -35, 6, + 58, -49, 21, 68, -60, 35, 78, -71, 48, 88, -80, 59, + 15, 25, -42, 25, 1, -26, 36, -18, -10, 47, -34, 6, + 58, -48, 21, 68, -59, 35, 78, -70, 48, 88, -80, 59, + 16, 26, -41, 25, 3, -26, 36, -17, -9, 47, -33, 7, + 58, -47, 22, 68, -59, 35, 78, -70, 48, 88, -79, 59, + 17, 27, -40, 26, 5, -25, 36, -15, -9, 47, -32, 7, + 58, -46, 22, 68, -58, 35, 79, -69, 48, 88, -79, 59, + 17, 29, -38, 26, 7, -24, 37, -13, -8, 47, -30, 7, + 58, -45, 22, 68, -57, 35, 79, -68, 48, 88, -78, 60, + 19, 31, -37, 27, 9, -23, 37, -11, -7, 48, -28, 8, + 58, -43, 22, 68, -55, 36, 79, -67, 48, 89, -77, 60, + 20, 33, -35, 28, 12, -22, 38, -8, -7, 48, -26, 8, + 59, -41, 23, 69, -54, 36, 79, -65, 49, 89, -76, 60, + 21, 35, -33, 29, 15, -20, 38, -6, -6, 48, -23, 9, + 59, -39, 23, 69, -52, 36, 79, -64, 49, 89, -75, 60, + 22, 37, -31, 29, 17, -19, 39, -3, -5, 49, -21, 10, + 59, -37, 24, 69, -50, 37, 79, -63, 49, 89, -73, 60, + 23, 39, -29, 30, 20, -17, 39, 0, -4, 49, -18, 10, + 59, -34, 24, 69, -48, 37, 80, -61, 49, 89, -72, 61, + 25, 41, -26, 32, 23, -16, 40, 4, -3, 50, -15, 11, + 60, -32, 25, 70, -46, 38, 80, -59, 50, 89, -70, 61, + 26, 43, -24, 33, 26, -14, 41, 7, -1, 50, -12, 12, + 60, -29, 26, 70, -43, 38, 80, -57, 50, 90, -68, 61, + 28, 45, -21, 34, 29, -12, 42, 10, 0, 51, -9, 13, + 61, -26, 26, 70, -41, 39, 80, -55, 51, 90, -66, 62, + 29, 47, -19, 35, 32, -10, 43, 13, 1, 52, -6, 14, + 61, -23, 27, 71, -38, 39, 81, -52, 51, 90, -64, 62, + 31, 50, -16, 36, 35, -8, 44, 17, 3, 52, -2, 15, + 62, -20, 28, 71, -35, 40, 81, -50, 52, 90, -62, 62, + 32, 52, -14, 38, 38, -6, 45, 20, 4, 53, 1, 16, + 62, -17, 29, 72, -32, 41, 81, -47, 52, 91, -60, 63, + 34, 54, -11, 39, 41, -4, 46, 23, 6, 54, 5, 17, + 63, -13, 30, 72, -29, 41, 82, -44, 53, 91, -57, 63, + 36, 56, -9, 40, 43, -2, 47, 26, 8, 55, 8, 19, + 64, -10, 31, 73, -26, 42, 82, -42, 53, 91, -55, 64, + 37, 58, -6, 42, 46, 0, 48, 30, 10, 56, 12, 20, + 64, -6, 32, 73, -23, 43, 83, -38, 54, 92, -52, 64, + 39, 60, -3, 43, 49, 3, 49, 33, 11, 57, 15, 22, + 65, -3, 33, 74, -20, 44, 83, -35, 55, 92, -49, 65, + 41, 62, -1, 44, 51, 5, 50, 36, 13, 57, 19, 23, + 66, 0, 34, 75, -16, 45, 84, -32, 55, 93, -47, 65, + 42, 64, 2, 46, 54, 7, 51, 39, 15, 58, 22, 24, + 67, 4, 35, 75, -13, 45, 84, -29, 56, 93, -44, 66, + 44, 66, 4, 47, 56, 9, 53, 42, 17, 59, 25, 26, + 67, 7, 36, 76, -10, 46, 85, -26, 57, 94, -41, 67, + 45, 68, 7, 49, 59, 12, 54, 45, 19, 61, 29, 27, + 68, 11, 38, 77, -6, 48, 85, -23, 58, 94, -38, 67, + 47, 70, 9, 50, 61, 14, 55, 48, 21, 62, 32, 29, + 69, 14, 39, 77, -3, 49, 86, -20, 59, 95, -35, 68, + 49, 72, 12, 52, 64, 16, 56, 51, 22, 63, 35, 31, + 70, 17, 40, 78, 0, 50, 87, -16, 59, 95, -32, 69, + 50, 74, 14, 53, 66, 18, 58, 54, 24, 64, 38, 32, + 71, 21, 41, 79, 4, 51, 87, -13, 60, 96, -28, 70, + 52, 76, 17, 55, 69, 21, 59, 57, 26, 65, 42, 34, + 72, 24, 43, 80, 7, 52, 88, -9, 61, 96, -25, 70, + 53, 78, 19, 56, 71, 23, 60, 59, 28, 66, 45, 36, + 73, 28, 44, 80, 11, 53, 89, -6, 62, 97, -22, 71, + 55, 80, 22, 58, 73, 25, 62, 62, 30, 67, 47, 37, + 74, 31, 46, 81, 14, 54, 89, -3, 63, 98, -19, 72, + 15, 26, -48, 25, 2, -32, 36, -18, -15, 47, -34, 2, + 58, -48, 17, 68, -59, 31, 78, -70, 44, 88, -80, 56, + 15, 26, -47, 25, 3, -31, 36, -17, -15, 47, -33, 2, + 58, -47, 17, 68, -59, 31, 78, -70, 44, 88, -79, 56, + 15, 27, -47, 25, 3, -31, 36, -17, -14, 47, -33, 2, + 58, -47, 17, 68, -59, 31, 78, -69, 44, 88, -79, 56, + 16, 28, -46, 26, 5, -31, 36, -16, -14, 47, -32, 2, + 58, -46, 17, 68, -58, 31, 78, -69, 44, 88, -79, 56, + 17, 29, -45, 26, 6, -30, 36, -14, -14, 47, -31, 2, + 58, -45, 17, 68, -57, 31, 79, -68, 44, 88, -78, 56, + 17, 30, -44, 26, 8, -29, 37, -13, -13, 47, -30, 2, + 58, -44, 18, 68, -56, 31, 79, -68, 44, 88, -78, 56, + 18, 32, -43, 27, 10, -28, 37, -11, -13, 47, -28, 3, + 58, -43, 18, 68, -55, 32, 79, -67, 45, 89, -77, 56, + 19, 33, -41, 28, 12, -27, 37, -8, -12, 48, -26, 3, + 58, -41, 18, 69, -54, 32, 79, -66, 45, 89, -76, 56, + 20, 35, -39, 28, 14, -26, 38, -6, -11, 48, -24, 4, + 59, -39, 19, 69, -52, 32, 79, -64, 45, 89, -75, 57, + 21, 37, -37, 29, 17, -25, 38, -4, -10, 48, -22, 4, + 59, -37, 19, 69, -51, 32, 79, -63, 45, 89, -74, 57, + 23, 39, -35, 30, 19, -23, 39, -1, -9, 49, -19, 5, + 59, -35, 20, 69, -49, 33, 79, -62, 45, 89, -72, 57, + 24, 40, -33, 31, 22, -22, 40, 2, -8, 49, -16, 6, + 60, -33, 20, 70, -47, 33, 80, -60, 46, 89, -71, 57, + 25, 43, -30, 32, 25, -20, 40, 5, -7, 50, -13, 7, + 60, -30, 21, 70, -45, 34, 80, -58, 46, 90, -69, 58, + 27, 45, -28, 33, 28, -18, 41, 8, -6, 51, -10, 8, + 60, -28, 21, 70, -42, 34, 80, -56, 47, 90, -68, 58, + 28, 47, -26, 34, 31, -17, 42, 12, -5, 51, -7, 9, + 61, -25, 22, 71, -40, 35, 80, -54, 47, 90, -66, 58, + 30, 49, -23, 35, 33, -15, 43, 15, -3, 52, -4, 10, + 61, -22, 23, 71, -37, 35, 81, -51, 47, 90, -64, 59, + 31, 51, -21, 37, 36, -13, 44, 18, -2, 53, -1, 11, + 62, -19, 24, 71, -34, 36, 81, -49, 48, 91, -61, 59, + 33, 53, -18, 38, 39, -11, 45, 21, 0, 53, 3, 12, + 63, -15, 25, 72, -31, 37, 82, -46, 49, 91, -59, 60, + 34, 55, -16, 39, 42, -9, 46, 24, 1, 54, 6, 13, + 63, -12, 26, 72, -28, 37, 82, -43, 49, 91, -57, 60, + 36, 57, -13, 40, 44, -7, 47, 28, 3, 55, 9, 14, + 64, -9, 26, 73, -25, 38, 82, -41, 50, 92, -54, 60, + 38, 59, -10, 42, 47, -4, 48, 31, 5, 56, 13, 16, + 65, -5, 28, 73, -22, 39, 83, -38, 50, 92, -51, 61, + 39, 61, -8, 43, 50, -2, 49, 34, 7, 57, 16, 17, + 65, -2, 29, 74, -19, 40, 83, -35, 51, 92, -49, 62, + 41, 63, -5, 45, 52, 0, 50, 37, 8, 58, 19, 19, + 66, 1, 30, 75, -16, 41, 84, -32, 52, 93, -46, 62, + 42, 65, -3, 46, 55, 2, 52, 40, 10, 59, 23, 20, + 67, 5, 31, 75, -12, 42, 84, -29, 53, 93, -43, 63, + 44, 67, 0, 47, 57, 5, 53, 43, 12, 60, 26, 21, + 68, 8, 32, 76, -9, 43, 85, -26, 53, 94, -40, 63, + 46, 69, 2, 49, 60, 7, 54, 46, 14, 61, 29, 23, + 68, 12, 33, 77, -5, 44, 85, -22, 54, 94, -37, 64, + 47, 71, 5, 50, 62, 9, 55, 49, 16, 62, 33, 25, + 69, 15, 35, 77, -2, 45, 86, -19, 55, 95, -34, 65, + 49, 73, 7, 52, 64, 11, 57, 52, 18, 63, 36, 26, + 70, 18, 36, 78, 1, 46, 87, -16, 56, 95, -31, 66, + 50, 75, 10, 53, 67, 14, 58, 54, 20, 64, 39, 28, + 71, 21, 37, 79, 4, 47, 87, -12, 57, 96, -28, 66, + 52, 77, 12, 55, 69, 16, 59, 57, 22, 65, 42, 30, + 72, 25, 39, 80, 8, 48, 88, -9, 58, 96, -24, 67, + 54, 79, 15, 56, 71, 18, 60, 60, 24, 66, 45, 31, + 73, 28, 40, 81, 11, 49, 89, -6, 59, 97, -21, 68, + 55, 81, 17, 58, 74, 21, 62, 62, 26, 67, 48, 33, + 74, 31, 42, 81, 15, 50, 89, -2, 60, 98, -18, 69, + 16, 29, -52, 25, 6, -36, 36, -15, -19, 47, -32, -3, + 58, -46, 13, 68, -58, 27, 78, -69, 40, 88, -79, 52, + 16, 30, -51, 26, 6, -36, 36, -14, -19, 47, -31, -3, + 58, -45, 13, 68, -57, 27, 78, -68, 40, 88, -78, 52, + 16, 30, -51, 26, 7, -35, 36, -14, -19, 47, -31, -3, + 58, -45, 13, 68, -57, 27, 79, -68, 40, 88, -78, 52, + 17, 31, -50, 26, 8, -35, 37, -13, -18, 47, -30, -2, + 58, -44, 13, 68, -56, 27, 79, -68, 40, 88, -78, 53, + 17, 32, -49, 26, 9, -34, 37, -12, -18, 47, -29, -2, + 58, -43, 13, 68, -56, 27, 79, -67, 41, 88, -77, 53, + 18, 33, -48, 27, 11, -34, 37, -10, -18, 47, -27, -2, + 58, -42, 13, 68, -55, 27, 79, -66, 41, 89, -77, 53, + 19, 34, -46, 27, 12, -33, 37, -8, -17, 48, -26, -2, + 58, -41, 14, 69, -54, 28, 79, -66, 41, 89, -76, 53, + 20, 36, -45, 28, 15, -32, 38, -6, -16, 48, -24, -1, + 59, -39, 14, 69, -52, 28, 79, -64, 41, 89, -75, 53, + 21, 37, -43, 29, 17, -30, 38, -4, -16, 48, -22, -1, + 59, -38, 14, 69, -51, 28, 79, -63, 41, 89, -74, 53, + 22, 39, -41, 29, 19, -29, 39, -1, -15, 49, -20, 0, + 59, -36, 15, 69, -49, 28, 79, -62, 41, 89, -73, 53, + 23, 40, -39, 30, 22, -28, 39, 1, -14, 49, -17, 1, + 59, -34, 15, 69, -48, 29, 80, -60, 42, 89, -72, 54, + 24, 42, -37, 31, 24, -26, 40, 4, -13, 50, -15, 1, + 60, -31, 16, 70, -46, 29, 80, -59, 42, 89, -70, 54, + 26, 44, -35, 32, 27, -25, 41, 7, -12, 50, -12, 2, + 60, -29, 17, 70, -43, 30, 80, -57, 42, 90, -68, 54, + 27, 46, -32, 33, 30, -23, 42, 10, -10, 51, -9, 3, + 61, -26, 17, 70, -41, 30, 80, -55, 43, 90, -67, 54, + 29, 48, -30, 34, 32, -21, 42, 13, -9, 51, -6, 4, + 61, -23, 18, 71, -39, 31, 81, -53, 43, 90, -65, 55, + 30, 50, -28, 36, 35, -19, 43, 16, -8, 52, -3, 5, + 62, -21, 19, 71, -36, 31, 81, -50, 44, 90, -63, 55, + 32, 52, -25, 37, 38, -17, 44, 20, -6, 53, 1, 6, + 62, -17, 20, 72, -33, 32, 81, -48, 44, 91, -60, 56, + 33, 54, -23, 38, 40, -15, 45, 23, -5, 53, 4, 8, + 63, -14, 20, 72, -30, 33, 82, -45, 45, 91, -58, 56, + 35, 56, -20, 39, 43, -13, 46, 26, -3, 54, 7, 9, + 63, -11, 21, 72, -27, 33, 82, -43, 45, 91, -56, 57, + 36, 58, -18, 41, 45, -11, 47, 29, -1, 55, 10, 10, + 64, -8, 22, 73, -24, 34, 82, -40, 46, 92, -53, 57, + 38, 60, -15, 42, 48, -9, 48, 32, 1, 56, 14, 11, + 65, -4, 23, 74, -21, 35, 83, -37, 47, 92, -51, 58, + 40, 62, -13, 43, 51, -7, 49, 35, 2, 57, 17, 13, + 65, -1, 24, 74, -18, 36, 83, -34, 47, 92, -48, 58, + 41, 64, -10, 45, 53, -4, 51, 38, 4, 58, 20, 14, + 66, 2, 26, 75, -15, 37, 84, -31, 48, 93, -45, 59, + 43, 66, -8, 46, 56, -2, 52, 41, 6, 59, 24, 16, + 67, 5, 27, 75, -12, 38, 84, -28, 49, 93, -42, 59, + 44, 68, -5, 48, 58, 0, 53, 44, 8, 60, 27, 17, + 68, 9, 28, 76, -8, 39, 85, -25, 50, 94, -40, 60, + 46, 70, -2, 49, 61, 2, 54, 47, 10, 61, 30, 19, + 69, 12, 29, 77, -5, 40, 86, -21, 51, 94, -36, 61, + 47, 72, 0, 51, 63, 5, 55, 50, 12, 62, 33, 20, + 69, 16, 31, 77, -1, 41, 86, -18, 51, 95, -33, 62, + 49, 73, 3, 52, 65, 7, 57, 52, 14, 63, 36, 22, + 70, 19, 32, 78, 2, 42, 87, -15, 52, 95, -30, 62, + 51, 75, 5, 53, 67, 9, 58, 55, 15, 64, 39, 24, + 71, 22, 33, 79, 5, 43, 87, -12, 53, 96, -27, 63, + 52, 77, 8, 55, 70, 12, 59, 58, 18, 65, 43, 25, + 72, 26, 35, 80, 9, 44, 88, -8, 54, 96, -24, 64, + 54, 79, 10, 56, 72, 14, 61, 60, 20, 66, 46, 27, + 73, 29, 36, 81, 12, 45, 89, -5, 55, 97, -21, 65, + 55, 81, 13, 58, 74, 16, 62, 63, 22, 67, 49, 29, + 74, 32, 38, 81, 15, 47, 90, -2, 56, 98, -18, 66, + 17, 32, -55, 26, 9, -40, 36, -12, -23, 47, -29, -7, + 58, -44, 9, 68, -56, 23, 79, -67, 36, 88, -77, 49, + 17, 33, -55, 26, 10, -40, 37, -11, -23, 47, -29, -7, + 58, -43, 9, 68, -56, 23, 79, -67, 37, 88, -77, 49, + 17, 33, -54, 26, 10, -39, 37, -11, -23, 47, -28, -7, + 58, -43, 9, 68, -55, 23, 79, -67, 37, 88, -77, 49, + 18, 34, -54, 27, 11, -39, 37, -10, -23, 47, -27, -7, + 58, -42, 9, 68, -55, 23, 79, -66, 37, 89, -77, 49, + 18, 35, -53, 27, 12, -38, 37, -9, -22, 48, -26, -7, + 58, -41, 9, 68, -54, 23, 79, -66, 37, 89, -76, 49, + 19, 36, -52, 27, 14, -38, 37, -7, -22, 48, -25, -6, + 58, -40, 9, 69, -53, 23, 79, -65, 37, 89, -76, 49, + 20, 37, -50, 28, 15, -37, 38, -6, -21, 48, -24, -6, + 59, -39, 9, 69, -52, 24, 79, -64, 37, 89, -75, 49, + 21, 38, -49, 29, 17, -36, 38, -3, -21, 48, -22, -5, + 59, -38, 10, 69, -51, 24, 79, -63, 37, 89, -74, 49, + 22, 39, -47, 29, 19, -35, 39, -1, -20, 49, -20, -5, + 59, -36, 10, 69, -50, 24, 79, -62, 37, 89, -73, 50, + 23, 41, -45, 30, 22, -34, 39, 1, -19, 49, -18, -4, + 59, -34, 11, 69, -48, 24, 79, -61, 38, 89, -72, 50, + 24, 42, -43, 31, 24, -32, 40, 3, -18, 49, -15, -4, + 60, -32, 11, 70, -46, 25, 80, -59, 38, 89, -70, 50, + 25, 44, -41, 32, 26, -31, 40, 6, -17, 50, -13, -3, + 60, -30, 12, 70, -44, 25, 80, -57, 38, 89, -69, 50, + 26, 46, -39, 33, 29, -29, 41, 9, -16, 50, -10, -2, + 60, -27, 12, 70, -42, 26, 80, -55, 39, 90, -67, 51, + 28, 48, -37, 34, 31, -27, 42, 12, -15, 51, -7, -1, + 61, -25, 13, 70, -40, 26, 80, -54, 39, 90, -66, 51, + 29, 49, -34, 35, 34, -26, 43, 15, -13, 52, -4, 0, + 61, -22, 14, 71, -37, 27, 81, -51, 40, 90, -64, 51, + 31, 51, -32, 36, 36, -24, 43, 18, -12, 52, -1, 1, + 62, -19, 14, 71, -35, 27, 81, -49, 40, 90, -62, 52, + 32, 53, -29, 37, 39, -22, 44, 21, -11, 53, 2, 2, + 62, -16, 15, 72, -32, 28, 81, -47, 41, 91, -59, 52, + 34, 55, -27, 38, 42, -20, 45, 24, -9, 54, 5, 3, + 63, -13, 16, 72, -29, 29, 82, -44, 41, 91, -57, 53, + 35, 57, -25, 40, 44, -18, 46, 27, -7, 54, 8, 4, + 63, -10, 17, 73, -26, 29, 82, -42, 42, 91, -55, 53, + 37, 59, -22, 41, 47, -16, 47, 30, -6, 55, 12, 6, + 64, -7, 18, 73, -23, 30, 83, -39, 42, 92, -53, 54, + 38, 61, -19, 42, 49, -13, 49, 33, -4, 56, 15, 7, + 65, -3, 19, 74, -20, 31, 83, -36, 43, 92, -50, 54, + 40, 63, -17, 44, 52, -11, 50, 36, -2, 57, 18, 8, + 66, 0, 20, 74, -17, 32, 83, -33, 44, 93, -47, 55, + 41, 65, -15, 45, 54, -9, 51, 39, 0, 58, 21, 10, + 66, 3, 21, 75, -14, 33, 84, -30, 44, 93, -44, 55, + 43, 66, -12, 46, 56, -7, 52, 42, 1, 59, 25, 11, + 67, 6, 23, 75, -11, 34, 84, -27, 45, 93, -42, 56, + 44, 68, -10, 48, 59, -5, 53, 45, 3, 60, 28, 13, + 68, 10, 24, 76, -7, 35, 85, -24, 46, 94, -39, 57, + 46, 70, -7, 49, 61, -2, 54, 48, 5, 61, 31, 15, + 69, 13, 25, 77, -4, 36, 86, -21, 47, 94, -36, 57, + 48, 72, -4, 51, 64, 0, 56, 50, 7, 62, 34, 16, + 70, 16, 26, 78, -1, 37, 86, -17, 48, 95, -33, 58, + 49, 74, -2, 52, 66, 2, 57, 53, 9, 63, 37, 18, + 70, 20, 28, 78, 3, 38, 87, -14, 49, 95, -30, 59, + 51, 76, 1, 54, 68, 5, 58, 56, 11, 64, 40, 19, + 71, 23, 29, 79, 6, 39, 87, -11, 50, 96, -27, 60, + 53, 78, 3, 55, 70, 7, 60, 59, 13, 65, 43, 21, + 72, 26, 31, 80, 9, 40, 88, -8, 51, 97, -23, 60, + 54, 80, 6, 57, 73, 9, 61, 61, 15, 66, 46, 23, + 73, 30, 32, 81, 13, 42, 89, -4, 52, 97, -20, 61, + 56, 82, 8, 58, 75, 12, 62, 64, 17, 68, 49, 25, + 74, 33, 33, 82, 16, 43, 90, -1, 53, 98, -17, 62, + 18, 36, -59, 27, 13, -45, 37, -8, -28, 47, -26, -12, + 58, -41, 4, 68, -54, 18, 79, -66, 32, 89, -76, 45, + 18, 36, -59, 27, 13, -44, 37, -8, -28, 47, -26, -12, + 58, -41, 4, 68, -54, 18, 79, -66, 32, 89, -76, 45, + 18, 36, -58, 27, 14, -44, 37, -7, -28, 48, -25, -12, + 58, -41, 4, 68, -53, 18, 79, -65, 32, 89, -76, 45, + 19, 37, -57, 27, 15, -44, 37, -6, -28, 48, -24, -12, + 58, -40, 4, 69, -53, 18, 79, -65, 32, 89, -75, 45, + 19, 38, -57, 28, 16, -43, 38, -5, -27, 48, -23, -11, + 58, -39, 4, 69, -52, 19, 79, -64, 32, 89, -75, 45, + 20, 39, -56, 28, 17, -42, 38, -4, -27, 48, -22, -11, + 59, -38, 4, 69, -51, 19, 79, -64, 33, 89, -74, 45, + 21, 39, -54, 29, 19, -42, 38, -2, -26, 48, -21, -11, + 59, -37, 5, 69, -50, 19, 79, -63, 33, 89, -74, 45, + 22, 41, -53, 29, 21, -40, 39, 0, -26, 49, -19, -10, + 59, -35, 5, 69, -49, 19, 79, -62, 33, 89, -73, 45, + 22, 42, -51, 30, 22, -39, 39, 2, -25, 49, -17, -10, + 59, -34, 5, 69, -48, 19, 79, -60, 33, 89, -72, 46, + 24, 43, -50, 31, 24, -38, 39, 4, -24, 49, -15, -9, + 60, -32, 6, 69, -46, 20, 80, -59, 33, 89, -70, 46, + 25, 45, -48, 31, 26, -37, 40, 6, -23, 50, -13, -9, + 60, -30, 6, 70, -44, 20, 80, -58, 34, 89, -69, 46, + 26, 46, -46, 32, 29, -35, 41, 9, -22, 50, -11, -8, + 60, -28, 7, 70, -43, 21, 80, -56, 34, 90, -68, 46, + 27, 48, -44, 33, 31, -34, 41, 11, -21, 51, -8, -7, + 61, -25, 8, 70, -40, 21, 80, -54, 34, 90, -66, 47, + 28, 49, -41, 34, 34, -32, 42, 14, -20, 51, -5, -6, + 61, -23, 8, 71, -38, 22, 80, -52, 35, 90, -64, 47, + 30, 51, -39, 35, 36, -30, 43, 17, -18, 52, -2, -5, + 61, -20, 9, 71, -36, 22, 81, -50, 35, 90, -63, 47, + 31, 53, -37, 36, 38, -29, 44, 20, -17, 52, 1, -4, + 62, -17, 10, 71, -33, 23, 81, -48, 36, 91, -61, 48, + 33, 55, -34, 38, 41, -26, 45, 23, -15, 53, 4, -3, + 63, -14, 11, 72, -30, 23, 81, -45, 36, 91, -58, 48, + 34, 56, -32, 39, 43, -25, 46, 26, -14, 54, 7, -2, + 63, -11, 11, 72, -28, 24, 82, -43, 37, 91, -56, 49, + 36, 58, -30, 40, 46, -23, 47, 29, -12, 55, 10, -1, + 64, -8, 12, 73, -25, 25, 82, -40, 37, 91, -54, 49, + 37, 60, -27, 41, 48, -20, 48, 31, -11, 55, 13, 1, + 64, -5, 13, 73, -22, 26, 83, -38, 38, 92, -51, 50, + 39, 62, -24, 43, 51, -18, 49, 35, -9, 56, 17, 2, + 65, -2, 15, 74, -19, 27, 83, -35, 39, 92, -49, 50, + 40, 64, -22, 44, 53, -16, 50, 37, -7, 57, 20, 4, + 66, 1, 16, 74, -16, 27, 84, -32, 39, 93, -46, 51, + 42, 66, -20, 45, 55, -14, 51, 40, -5, 58, 23, 5, + 66, 4, 17, 75, -13, 28, 84, -29, 40, 93, -43, 51, + 43, 67, -17, 47, 58, -12, 52, 43, -4, 59, 26, 6, + 67, 8, 18, 76, -10, 29, 85, -26, 41, 93, -41, 52, + 45, 69, -15, 48, 60, -10, 53, 46, -2, 60, 29, 8, + 68, 11, 19, 76, -6, 30, 85, -23, 42, 94, -38, 53, + 46, 71, -12, 50, 62, -7, 55, 49, 0, 61, 32, 10, + 69, 14, 20, 77, -3, 31, 86, -20, 43, 94, -35, 53, + 48, 73, -9, 51, 64, -5, 56, 51, 2, 62, 35, 11, + 70, 17, 22, 78, 0, 32, 86, -16, 43, 95, -32, 54, + 50, 75, -7, 52, 67, -3, 57, 54, 4, 63, 38, 13, + 71, 21, 23, 78, 4, 34, 87, -13, 44, 95, -29, 55, + 51, 77, -5, 54, 69, 0, 58, 56, 6, 64, 41, 14, + 72, 24, 24, 79, 7, 35, 88, -10, 45, 96, -26, 56, + 53, 79, -2, 55, 71, 2, 60, 59, 8, 66, 44, 16, + 73, 27, 26, 80, 10, 36, 88, -7, 46, 97, -22, 57, + 54, 81, 1, 57, 73, 4, 61, 62, 10, 67, 47, 18, + 73, 30, 27, 81, 14, 37, 89, -4, 47, 97, -19, 57, + 56, 82, 3, 58, 75, 7, 62, 64, 12, 68, 50, 20, + 74, 33, 29, 82, 17, 38, 90, 0, 48, 98, -16, 58, + 19, 39, -62, 27, 16, -48, 37, -5, -32, 48, -23, -16, + 58, -39, 0, 69, -52, 14, 79, -64, 28, 89, -75, 41, + 19, 39, -62, 28, 17, -48, 37, -5, -32, 48, -23, -16, + 58, -39, 0, 69, -52, 14, 79, -64, 28, 89, -75, 41, + 19, 39, -62, 28, 17, -48, 38, -4, -32, 48, -22, -16, + 58, -38, 0, 69, -52, 14, 79, -64, 28, 89, -74, 41, + 20, 40, -61, 28, 18, -48, 38, -3, -32, 48, -22, -16, + 59, -38, 0, 69, -51, 14, 79, -63, 28, 89, -74, 41, + 20, 40, -60, 28, 19, -47, 38, -2, -32, 48, -21, -16, + 59, -37, 0, 69, -50, 14, 79, -63, 29, 89, -74, 41, + 21, 41, -59, 29, 20, -46, 38, -1, -31, 48, -20, -15, + 59, -36, 0, 69, -50, 15, 79, -62, 29, 89, -73, 41, + 21, 42, -58, 29, 22, -46, 39, 0, -31, 49, -18, -15, + 59, -35, 0, 69, -49, 15, 79, -61, 29, 89, -72, 42, + 22, 43, -57, 30, 23, -45, 39, 2, -30, 49, -17, -15, + 59, -33, 1, 69, -47, 15, 79, -60, 29, 89, -71, 42, + 23, 44, -55, 30, 25, -43, 39, 4, -29, 49, -15, -14, + 59, -32, 1, 69, -46, 15, 80, -59, 29, 89, -70, 42, + 24, 45, -53, 31, 27, -42, 40, 6, -28, 50, -13, -13, + 60, -30, 2, 70, -44, 16, 80, -58, 29, 89, -69, 42, + 25, 47, -52, 32, 29, -41, 40, 8, -27, 50, -11, -13, + 60, -28, 2, 70, -43, 16, 80, -56, 30, 89, -68, 42, + 26, 48, -50, 33, 31, -40, 41, 11, -26, 50, -8, -12, + 60, -26, 3, 70, -41, 17, 80, -55, 30, 90, -67, 43, + 28, 50, -47, 34, 33, -38, 42, 14, -25, 51, -6, -11, + 61, -23, 3, 70, -39, 17, 80, -53, 31, 90, -65, 43, + 29, 51, -45, 35, 35, -36, 43, 16, -24, 51, -3, -10, + 61, -21, 4, 71, -37, 18, 81, -51, 31, 90, -63, 43, + 30, 53, -43, 36, 38, -35, 43, 19, -23, 52, 0, -9, + 62, -19, 5, 71, -34, 18, 81, -49, 31, 90, -61, 44, + 32, 54, -41, 37, 40, -33, 44, 21, -21, 53, 2, -8, + 62, -16, 5, 72, -32, 19, 81, -47, 32, 91, -60, 44, + 33, 56, -38, 38, 42, -31, 45, 25, -20, 53, 6, -7, + 63, -13, 6, 72, -29, 19, 82, -44, 32, 91, -57, 44, + 35, 58, -36, 39, 45, -29, 46, 27, -18, 54, 9, -6, + 63, -10, 7, 72, -26, 20, 82, -42, 33, 91, -55, 45, + 36, 59, -34, 40, 47, -27, 47, 30, -17, 55, 12, -5, + 64, -7, 8, 73, -24, 21, 82, -39, 34, 92, -53, 45, + 37, 61, -31, 42, 49, -25, 48, 33, -15, 56, 15, -4, + 64, -4, 9, 73, -21, 22, 83, -37, 34, 92, -50, 46, + 39, 63, -29, 43, 52, -23, 49, 36, -13, 57, 18, -2, + 65, -1, 10, 74, -17, 23, 83, -34, 35, 92, -48, 46, + 41, 65, -26, 44, 54, -20, 50, 39, -12, 58, 21, -1, + 66, 2, 11, 75, -15, 23, 84, -31, 36, 93, -45, 47, + 42, 67, -24, 46, 56, -18, 51, 41, -10, 58, 24, 1, + 67, 6, 13, 75, -12, 24, 84, -28, 36, 93, -42, 48, + 44, 68, -21, 47, 59, -16, 52, 44, -8, 59, 27, 2, + 67, 9, 14, 76, -8, 25, 85, -25, 37, 94, -40, 48, + 45, 70, -19, 48, 61, -14, 54, 47, -6, 60, 30, 4, + 68, 12, 15, 76, -5, 26, 85, -22, 38, 94, -37, 49, + 47, 72, -16, 50, 63, -11, 55, 50, -4, 61, 33, 5, + 69, 15, 16, 77, -2, 27, 86, -19, 39, 95, -34, 50, + 48, 74, -14, 51, 65, -9, 56, 52, -2, 62, 36, 7, + 70, 18, 18, 78, 1, 28, 86, -16, 40, 95, -31, 50, + 50, 76, -11, 53, 67, -7, 57, 55, 0, 63, 39, 9, + 71, 22, 19, 79, 4, 29, 87, -13, 41, 96, -28, 51, + 51, 77, -9, 54, 70, -5, 59, 57, 2, 64, 42, 10, + 72, 25, 20, 79, 8, 31, 88, -9, 42, 96, -25, 52, + 53, 79, -6, 56, 72, -2, 60, 60, 4, 66, 45, 12, + 73, 28, 22, 80, 11, 32, 88, -6, 43, 97, -22, 53, + 55, 81, -4, 57, 74, 0, 61, 63, 6, 67, 48, 14, + 74, 31, 23, 81, 14, 33, 89, -3, 44, 97, -19, 54, + 56, 83, -1, 59, 76, 2, 62, 65, 8, 68, 51, 16, + 75, 34, 25, 82, 17, 34, 90, 0, 45, 98, -15, 55, + 20, 42, -66, 28, 20, -52, 38, -2, -37, 48, -20, -21, + 59, -37, -5, 69, -50, 10, 79, -63, 24, 89, -73, 37, + 20, 42, -65, 28, 20, -52, 38, -1, -36, 48, -20, -21, + 59, -36, -5, 69, -50, 10, 79, -62, 24, 89, -73, 37, + 20, 42, -65, 28, 21, -52, 38, -1, -36, 48, -20, -20, + 59, -36, -5, 69, -50, 10, 79, -62, 24, 89, -73, 37, + 21, 43, -64, 29, 21, -51, 38, 0, -36, 48, -19, -20, + 59, -35, -4, 69, -49, 10, 79, -62, 24, 89, -73, 37, + 21, 43, -64, 29, 22, -51, 38, 1, -36, 48, -18, -20, + 59, -35, -4, 69, -48, 10, 79, -61, 25, 89, -72, 38, + 22, 44, -63, 29, 23, -50, 39, 2, -35, 49, -17, -20, + 59, -34, -4, 69, -48, 11, 79, -60, 25, 89, -72, 38, + 22, 44, -62, 30, 25, -49, 39, 3, -35, 49, -16, -19, + 59, -33, -4, 69, -47, 11, 79, -60, 25, 89, -71, 38, + 23, 45, -60, 30, 26, -48, 39, 5, -34, 49, -14, -19, + 59, -31, -3, 69, -45, 11, 80, -59, 25, 89, -70, 38, + 24, 46, -59, 31, 28, -47, 40, 7, -33, 49, -12, -18, + 60, -30, -3, 70, -44, 11, 80, -57, 25, 89, -69, 38, + 25, 47, -57, 32, 29, -46, 40, 9, -32, 50, -10, -18, + 60, -28, -3, 70, -43, 12, 80, -56, 26, 89, -68, 38, + 26, 49, -55, 32, 31, -45, 41, 11, -32, 50, -8, -17, + 60, -26, -2, 70, -41, 12, 80, -55, 26, 90, -67, 39, + 27, 50, -54, 33, 33, -44, 41, 13, -31, 51, -6, -16, + 61, -24, -2, 70, -39, 12, 80, -53, 26, 90, -65, 39, + 28, 51, -51, 34, 35, -42, 42, 16, -29, 51, -4, -15, + 61, -22, -1, 71, -37, 13, 80, -51, 27, 90, -64, 39, + 30, 53, -49, 35, 37, -40, 43, 18, -28, 52, -1, -15, + 61, -19, 0, 71, -35, 13, 81, -49, 27, 90, -62, 39, + 31, 54, -47, 36, 40, -39, 44, 21, -27, 52, 2, -14, + 62, -17, 1, 71, -33, 14, 81, -47, 27, 90, -60, 40, + 32, 56, -45, 37, 42, -37, 44, 23, -26, 53, 4, -13, + 62, -14, 1, 72, -30, 15, 81, -45, 28, 91, -58, 40, + 34, 58, -43, 39, 44, -35, 45, 26, -24, 54, 7, -11, + 63, -11, 2, 72, -28, 15, 82, -43, 28, 91, -56, 41, + 35, 59, -40, 40, 46, -33, 46, 29, -23, 54, 10, -10, + 63, -8, 3, 73, -25, 16, 82, -40, 29, 91, -54, 41, + 36, 61, -38, 41, 48, -31, 47, 32, -21, 55, 13, -9, + 64, -6, 4, 73, -22, 17, 82, -38, 30, 92, -52, 42, + 38, 62, -36, 42, 51, -29, 48, 34, -19, 56, 16, -8, + 65, -3, 5, 74, -19, 18, 83, -35, 30, 92, -49, 42, + 40, 64, -33, 43, 53, -27, 49, 37, -18, 57, 19, -6, + 65, 1, 6, 74, -16, 18, 83, -32, 31, 92, -47, 43, + 41, 66, -31, 45, 55, -25, 51, 40, -16, 58, 22, -5, + 66, 4, 7, 75, -13, 19, 84, -30, 32, 93, -44, 43, + 42, 68, -28, 46, 57, -23, 52, 43, -14, 59, 25, -4, + 67, 7, 8, 75, -10, 20, 84, -27, 32, 93, -41, 44, + 44, 69, -26, 47, 60, -20, 53, 45, -12, 60, 28, -2, + 68, 10, 9, 76, -7, 21, 85, -24, 33, 94, -39, 45, + 45, 71, -23, 49, 62, -18, 54, 48, -10, 60, 31, -1, + 68, 13, 11, 77, -4, 22, 85, -21, 34, 94, -36, 45, + 47, 73, -21, 50, 64, -16, 55, 51, -8, 62, 34, 1, + 69, 16, 12, 77, -1, 23, 86, -18, 35, 95, -33, 46, + 49, 75, -18, 52, 66, -14, 56, 53, -6, 63, 37, 3, + 70, 19, 13, 78, 2, 24, 87, -15, 36, 95, -30, 47, + 50, 76, -16, 53, 68, -11, 58, 56, -5, 64, 40, 4, + 71, 23, 15, 79, 5, 25, 87, -12, 37, 96, -27, 48, + 52, 78, -13, 54, 70, -9, 59, 58, -3, 65, 43, 6, + 72, 26, 16, 79, 9, 27, 88, -9, 38, 96, -24, 48, + 53, 80, -11, 56, 73, -7, 60, 61, 0, 66, 46, 8, + 73, 29, 18, 80, 12, 28, 89, -5, 39, 97, -21, 49, + 55, 82, -8, 57, 75, -4, 61, 63, 2, 67, 49, 10, + 74, 32, 19, 81, 15, 29, 89, -2, 40, 97, -18, 50, + 56, 84, -6, 59, 77, -2, 63, 66, 4, 68, 52, 11, + 75, 35, 21, 82, 18, 30, 90, 1, 41, 98, -15, 51, + 21, 44, -69, 29, 23, -56, 38, 2, -41, 48, -18, -25, + 59, -34, -9, 69, -48, 6, 79, -61, 20, 89, -72, 34, + 21, 45, -69, 29, 24, -56, 38, 2, -41, 48, -17, -25, + 59, -34, -9, 69, -48, 6, 79, -61, 20, 89, -72, 34, + 21, 45, -68, 29, 24, -56, 38, 2, -40, 48, -17, -25, + 59, -34, -9, 69, -48, 6, 79, -60, 20, 89, -72, 34, + 22, 45, -68, 29, 25, -55, 39, 3, -40, 49, -16, -24, + 59, -33, -9, 69, -47, 6, 79, -60, 21, 89, -71, 34, + 22, 46, -67, 30, 25, -55, 39, 4, -40, 49, -15, -24, + 59, -32, -8, 69, -46, 6, 79, -59, 21, 89, -71, 34, + 23, 46, -66, 30, 26, -54, 39, 5, -39, 49, -14, -24, + 59, -31, -8, 69, -46, 6, 79, -59, 21, 89, -70, 34, + 23, 47, -65, 30, 27, -53, 39, 6, -39, 49, -13, -23, + 59, -30, -8, 69, -45, 7, 80, -58, 21, 89, -69, 34, + 24, 48, -64, 31, 29, -52, 40, 8, -38, 49, -11, -23, + 60, -29, -8, 70, -44, 7, 80, -57, 21, 89, -69, 34, + 25, 49, -62, 32, 30, -51, 40, 10, -37, 50, -10, -22, + 60, -27, -7, 70, -42, 7, 80, -56, 21, 89, -68, 34, + 26, 50, -61, 32, 32, -50, 41, 11, -37, 50, -8, -22, + 60, -26, -7, 70, -41, 8, 80, -55, 22, 90, -67, 35, + 27, 51, -59, 33, 34, -49, 41, 13, -36, 51, -6, -21, + 60, -24, -6, 70, -39, 8, 80, -53, 22, 90, -65, 35, + 28, 52, -57, 34, 35, -48, 42, 16, -35, 51, -4, -21, + 61, -22, -6, 70, -37, 8, 80, -52, 22, 90, -64, 35, + 29, 53, -55, 35, 37, -46, 43, 18, -34, 52, -1, -20, + 61, -20, -5, 71, -35, 9, 81, -50, 23, 90, -62, 35, + 30, 55, -53, 36, 39, -44, 43, 20, -32, 52, 1, -19, + 62, -17, -4, 71, -33, 9, 81, -48, 23, 90, -61, 36, + 32, 56, -51, 37, 41, -43, 44, 23, -31, 53, 4, -18, + 62, -15, -4, 71, -31, 10, 81, -46, 23, 91, -59, 36, + 33, 57, -49, 38, 43, -41, 45, 25, -30, 53, 6, -17, + 63, -12, -3, 72, -29, 11, 82, -44, 24, 91, -57, 36, + 34, 59, -47, 39, 46, -39, 46, 28, -28, 54, 9, -16, + 63, -9, -2, 72, -26, 11, 82, -41, 25, 91, -55, 37, + 36, 61, -44, 40, 48, -37, 47, 31, -27, 55, 12, -15, + 64, -7, -1, 73, -23, 12, 82, -39, 25, 91, -53, 37, + 37, 62, -42, 41, 50, -35, 48, 33, -25, 55, 15, -13, + 64, -4, 0, 73, -21, 13, 83, -37, 26, 92, -51, 38, + 38, 64, -40, 42, 52, -33, 49, 36, -24, 56, 18, -12, + 65, -1, 1, 74, -18, 13, 83, -34, 26, 92, -48, 38, + 40, 65, -37, 44, 54, -31, 50, 39, -22, 57, 21, -11, + 66, 2, 2, 74, -15, 14, 84, -31, 27, 93, -46, 39, + 41, 67, -35, 45, 57, -29, 51, 41, -20, 58, 24, -9, + 66, 5, 3, 75, -12, 15, 84, -28, 28, 93, -43, 40, + 43, 69, -32, 46, 59, -27, 52, 44, -18, 59, 27, -8, + 67, 8, 4, 75, -9, 16, 84, -26, 28, 93, -40, 40, + 44, 70, -30, 48, 61, -25, 53, 46, -17, 60, 29, -6, + 68, 11, 5, 76, -6, 17, 85, -23, 29, 94, -38, 41, + 46, 72, -28, 49, 63, -23, 54, 49, -15, 61, 32, -5, + 69, 14, 7, 77, -3, 18, 86, -20, 30, 94, -35, 42, + 47, 74, -25, 51, 65, -20, 55, 52, -13, 62, 35, -3, + 69, 18, 8, 77, 0, 19, 86, -17, 31, 95, -32, 42, + 49, 76, -22, 52, 67, -18, 57, 54, -11, 63, 38, -2, + 70, 21, 9, 78, 3, 20, 87, -14, 32, 95, -29, 43, + 50, 77, -20, 53, 69, -16, 58, 57, -9, 64, 41, 0, + 71, 24, 11, 79, 6, 21, 87, -11, 33, 96, -26, 44, + 52, 79, -18, 55, 71, -14, 59, 59, -7, 65, 44, 2, + 72, 27, 12, 80, 10, 23, 88, -8, 34, 96, -23, 45, + 54, 81, -15, 56, 74, -11, 60, 62, -5, 66, 47, 4, + 73, 30, 14, 81, 13, 24, 89, -4, 35, 97, -20, 46, + 55, 83, -13, 58, 76, -9, 62, 64, -3, 67, 50, 5, + 74, 33, 15, 81, 16, 25, 89, -1, 36, 98, -17, 46, + 57, 84, -10, 59, 78, -7, 63, 67, -1, 68, 52, 7, + 75, 36, 16, 82, 19, 26, 90, 2, 37, 98, -14, 47, + 22, 47, -72, 30, 27, -60, 39, 5, -45, 49, -14, -29, + 59, -31, -14, 69, -46, 1, 79, -59, 16, 89, -70, 29, + 22, 48, -72, 30, 27, -60, 39, 6, -45, 49, -14, -29, + 59, -31, -13, 69, -45, 1, 79, -59, 16, 89, -70, 29, + 23, 48, -72, 30, 28, -60, 39, 6, -45, 49, -13, -29, + 59, -31, -13, 69, -45, 1, 79, -58, 16, 89, -70, 29, + 23, 48, -71, 30, 28, -59, 39, 7, -45, 49, -13, -29, + 59, -30, -13, 69, -45, 2, 79, -58, 16, 89, -69, 29, + 23, 48, -71, 30, 29, -59, 39, 7, -44, 49, -12, -29, + 59, -29, -13, 69, -44, 2, 80, -57, 16, 89, -69, 29, + 24, 49, -70, 31, 30, -58, 40, 8, -44, 49, -11, -28, + 60, -29, -13, 69, -43, 2, 80, -57, 16, 89, -68, 30, + 24, 50, -69, 31, 31, -58, 40, 10, -43, 50, -10, -28, + 60, -28, -13, 70, -42, 2, 80, -56, 16, 89, -68, 30, + 25, 50, -67, 32, 32, -57, 40, 11, -43, 50, -8, -28, + 60, -26, -12, 70, -41, 2, 80, -55, 17, 89, -67, 30, + 26, 51, -66, 32, 33, -56, 41, 13, -42, 50, -7, -27, + 60, -25, -12, 70, -40, 3, 80, -54, 17, 90, -66, 30, + 27, 52, -65, 33, 35, -54, 41, 14, -41, 50, -5, -27, + 60, -23, -11, 70, -39, 3, 80, -53, 17, 90, -65, 30, + 28, 53, -63, 34, 36, -53, 42, 16, -40, 51, -3, -26, + 61, -22, -11, 70, -37, 3, 80, -51, 17, 90, -64, 30, + 29, 54, -61, 34, 38, -52, 42, 18, -39, 51, -1, -25, + 61, -20, -10, 71, -35, 4, 81, -50, 18, 90, -62, 31, + 30, 55, -59, 35, 40, -50, 43, 21, -38, 52, 1, -24, + 62, -17, -10, 71, -33, 4, 81, -48, 18, 90, -61, 31, + 31, 57, -57, 36, 42, -49, 44, 23, -37, 52, 3, -23, + 62, -15, -9, 71, -31, 5, 81, -46, 19, 90, -59, 31, + 32, 58, -55, 37, 44, -47, 45, 25, -36, 53, 6, -23, + 62, -13, -8, 72, -29, 5, 81, -44, 19, 91, -57, 32, + 33, 59, -53, 38, 46, -46, 45, 27, -34, 54, 8, -22, + 63, -10, -8, 72, -27, 6, 82, -42, 19, 91, -56, 32, + 35, 61, -51, 40, 48, -44, 46, 30, -33, 54, 11, -20, + 63, -7, -7, 73, -24, 7, 82, -40, 20, 91, -53, 33, + 36, 62, -49, 41, 50, -42, 47, 33, -31, 55, 14, -19, + 64, -5, -6, 73, -22, 7, 82, -37, 21, 92, -51, 33, + 38, 64, -47, 42, 52, -40, 48, 35, -30, 56, 17, -18, + 65, -2, -5, 73, -19, 8, 83, -35, 21, 92, -49, 34, + 39, 65, -44, 43, 54, -38, 49, 38, -28, 57, 19, -17, + 65, 1, -4, 74, -16, 9, 83, -33, 22, 92, -47, 34, + 40, 67, -42, 44, 56, -36, 50, 40, -27, 57, 22, -15, + 66, 4, -3, 75, -13, 10, 84, -30, 23, 93, -44, 35, + 42, 68, -39, 46, 58, -34, 51, 43, -25, 58, 25, -14, + 67, 7, -2, 75, -10, 11, 84, -27, 23, 93, -42, 35, + 43, 70, -37, 47, 60, -32, 52, 45, -23, 59, 28, -13, + 67, 10, -1, 76, -8, 12, 85, -24, 24, 93, -39, 36, + 45, 72, -35, 48, 62, -29, 53, 48, -21, 60, 31, -11, + 68, 13, 1, 76, -5, 13, 85, -21, 25, 94, -37, 37, + 46, 73, -32, 49, 64, -27, 54, 50, -19, 61, 34, -10, + 69, 16, 2, 77, -2, 14, 86, -19, 26, 94, -34, 37, + 48, 75, -30, 51, 66, -25, 56, 53, -17, 62, 37, -8, + 70, 19, 3, 78, 2, 15, 86, -15, 27, 95, -31, 38, + 49, 77, -27, 52, 68, -23, 57, 55, -16, 63, 40, -6, + 71, 22, 5, 78, 5, 16, 87, -12, 27, 95, -28, 39, + 51, 78, -25, 54, 70, -21, 58, 58, -14, 64, 42, -5, + 71, 25, 6, 79, 8, 17, 87, -9, 28, 96, -25, 40, + 52, 80, -22, 55, 72, -18, 59, 60, -12, 65, 45, -3, + 72, 28, 7, 80, 11, 18, 88, -6, 29, 96, -22, 40, + 54, 82, -20, 56, 74, -16, 61, 63, -9, 66, 48, -1, + 73, 31, 9, 81, 14, 19, 89, -3, 30, 97, -19, 41, + 55, 84, -17, 58, 76, -14, 62, 65, -8, 67, 51, 1, + 74, 34, 10, 81, 17, 21, 90, 0, 31, 98, -16, 42, + 57, 85, -15, 59, 78, -11, 63, 67, -6, 68, 53, 2, + 75, 37, 12, 82, 20, 22, 90, 3, 33, 98, -13, 43, + 23, 50, -76, 30, 30, -64, 39, 9, -49, 49, -11, -34, + 59, -29, -18, 69, -44, -3, 79, -57, 12, 89, -69, 25, + 23, 50, -75, 30, 30, -64, 39, 9, -49, 49, -11, -33, + 59, -28, -18, 69, -43, -3, 80, -57, 12, 89, -68, 25, + 24, 50, -75, 31, 31, -63, 40, 9, -49, 49, -10, -33, + 60, -28, -17, 69, -43, -3, 80, -56, 12, 89, -68, 25, + 24, 51, -74, 31, 31, -63, 40, 10, -48, 49, -10, -33, + 60, -28, -17, 70, -43, -3, 80, -56, 12, 89, -68, 26, + 24, 51, -74, 31, 32, -62, 40, 11, -48, 50, -9, -33, + 60, -27, -17, 70, -42, -2, 80, -56, 12, 89, -67, 26, + 25, 51, -73, 31, 33, -62, 40, 12, -48, 50, -8, -33, + 60, -26, -17, 70, -41, -2, 80, -55, 12, 89, -67, 26, + 25, 52, -72, 32, 34, -61, 40, 13, -47, 50, -7, -32, + 60, -25, -17, 70, -40, -2, 80, -54, 12, 89, -66, 26, + 26, 53, -71, 32, 35, -60, 41, 14, -47, 50, -6, -32, + 60, -24, -16, 70, -39, -2, 80, -53, 13, 90, -65, 26, + 27, 53, -69, 33, 36, -59, 41, 16, -46, 51, -4, -31, + 60, -22, -16, 70, -38, -1, 80, -52, 13, 90, -64, 26, + 28, 54, -68, 34, 37, -58, 42, 17, -45, 51, -3, -31, + 61, -21, -16, 70, -37, -1, 80, -51, 13, 90, -63, 26, + 28, 55, -67, 34, 39, -57, 42, 19, -44, 51, -1, -30, + 61, -19, -15, 71, -35, -1, 81, -50, 13, 90, -62, 27, + 29, 56, -65, 35, 40, -56, 43, 21, -43, 52, 1, -29, + 61, -17, -14, 71, -33, 0, 81, -48, 14, 90, -61, 27, + 31, 57, -63, 36, 42, -54, 44, 23, -42, 52, 3, -28, + 62, -15, -14, 71, -31, 0, 81, -46, 14, 90, -59, 27, + 32, 58, -61, 37, 44, -53, 44, 25, -41, 53, 6, -28, + 62, -13, -13, 72, -29, 1, 81, -44, 15, 91, -58, 28, + 33, 60, -59, 38, 46, -51, 45, 27, -40, 53, 8, -27, + 63, -11, -12, 72, -27, 1, 82, -43, 15, 91, -56, 28, + 34, 61, -57, 39, 47, -49, 46, 30, -39, 54, 10, -26, + 63, -8, -12, 72, -25, 2, 82, -41, 16, 91, -54, 28, + 36, 62, -55, 40, 50, -48, 47, 32, -37, 55, 13, -24, + 64, -6, -11, 73, -22, 3, 82, -38, 16, 91, -52, 29, + 37, 64, -53, 41, 51, -46, 48, 34, -36, 55, 16, -23, + 64, -3, -10, 73, -20, 3, 83, -36, 17, 92, -50, 29, + 38, 65, -50, 42, 53, -44, 48, 37, -34, 56, 18, -22, + 65, 0, -9, 74, -17, 4, 83, -34, 17, 92, -48, 30, + 39, 66, -48, 43, 55, -42, 49, 39, -32, 57, 21, -21, + 65, 2, -8, 74, -15, 5, 83, -31, 18, 92, -46, 30, + 41, 68, -46, 45, 57, -40, 51, 42, -31, 58, 24, -19, + 66, 5, -7, 75, -12, 6, 84, -28, 19, 93, -43, 31, + 42, 70, -43, 46, 59, -38, 52, 44, -29, 59, 27, -18, + 67, 8, -6, 75, -9, 7, 84, -26, 19, 93, -40, 31, + 44, 71, -41, 47, 61, -36, 53, 47, -27, 59, 30, -17, + 67, 11, -5, 76, -6, 8, 85, -23, 20, 94, -38, 32, + 45, 73, -39, 48, 63, -34, 54, 49, -25, 60, 32, -15, + 68, 14, -3, 76, -3, 8, 85, -20, 21, 94, -35, 33, + 47, 74, -36, 50, 65, -31, 55, 52, -24, 61, 35, -14, + 69, 17, -2, 77, 0, 9, 86, -17, 22, 94, -33, 33, + 48, 76, -34, 51, 67, -29, 56, 54, -22, 62, 38, -12, + 70, 20, -1, 78, 3, 11, 86, -14, 23, 95, -30, 34, + 50, 78, -31, 53, 69, -27, 57, 57, -20, 63, 41, -10, + 71, 23, 0, 79, 6, 12, 87, -11, 24, 96, -27, 35, + 51, 79, -29, 54, 71, -25, 58, 59, -18, 64, 43, -9, + 72, 26, 2, 79, 9, 13, 88, -8, 24, 96, -24, 36, + 53, 81, -27, 55, 73, -23, 60, 61, -16, 65, 46, -7, + 72, 29, 3, 80, 12, 14, 88, -5, 25, 97, -21, 37, + 54, 83, -24, 57, 75, -20, 61, 64, -14, 67, 49, -5, + 73, 32, 5, 81, 15, 15, 89, -2, 27, 97, -18, 38, + 56, 84, -22, 58, 77, -18, 62, 66, -12, 68, 52, -4, + 74, 35, 6, 82, 18, 16, 90, 1, 28, 98, -15, 38, + 57, 86, -19, 60, 79, -16, 63, 68, -10, 69, 54, -2, + 75, 38, 8, 82, 21, 18, 90, 4, 29, 98, -12, 39, + 24, 52, -79, 31, 33, -67, 40, 12, -53, 50, -8, -38, + 60, -26, -22, 70, -41, -7, 80, -55, 8, 89, -67, 22, + 24, 53, -78, 31, 34, -67, 40, 12, -53, 50, -8, -37, + 60, -26, -22, 70, -41, -7, 80, -55, 8, 89, -67, 22, + 25, 53, -78, 31, 34, -67, 40, 13, -53, 50, -7, -37, + 60, -25, -22, 70, -41, -7, 80, -54, 8, 89, -67, 22, + 25, 53, -77, 32, 34, -66, 40, 13, -52, 50, -7, -37, + 60, -25, -21, 70, -40, -7, 80, -54, 8, 89, -66, 22, + 25, 53, -77, 32, 35, -66, 40, 14, -52, 50, -6, -37, + 60, -24, -21, 70, -40, -6, 80, -54, 8, 89, -66, 22, + 26, 54, -76, 32, 36, -65, 41, 15, -52, 50, -5, -37, + 60, -24, -21, 70, -39, -6, 80, -53, 8, 90, -65, 22, + 26, 54, -75, 33, 36, -65, 41, 16, -51, 50, -4, -36, + 60, -23, -21, 70, -38, -6, 80, -52, 8, 90, -65, 22, + 27, 55, -74, 33, 38, -64, 41, 17, -50, 51, -3, -36, + 61, -21, -20, 70, -37, -6, 80, -51, 9, 90, -64, 22, + 28, 56, -73, 34, 39, -63, 42, 18, -50, 51, -2, -35, + 61, -20, -20, 70, -36, -6, 80, -50, 9, 90, -63, 22, + 28, 56, -71, 34, 40, -62, 42, 20, -49, 51, 0, -35, + 61, -19, -20, 71, -34, -5, 80, -49, 9, 90, -62, 23, + 29, 57, -70, 35, 41, -61, 43, 22, -48, 52, 2, -34, + 61, -17, -19, 71, -33, -5, 81, -48, 9, 90, -61, 23, + 30, 58, -68, 36, 43, -59, 43, 23, -47, 52, 4, -33, + 62, -15, -19, 71, -31, -4, 81, -46, 10, 90, -59, 23, + 31, 59, -66, 37, 44, -58, 44, 25, -46, 53, 6, -33, + 62, -13, -18, 71, -29, -4, 81, -45, 10, 91, -58, 23, + 32, 60, -65, 37, 46, -57, 45, 27, -45, 53, 8, -32, + 62, -11, -17, 72, -27, -3, 81, -43, 11, 91, -56, 24, + 34, 61, -63, 38, 48, -55, 45, 29, -44, 54, 10, -31, + 63, -9, -17, 72, -25, -3, 82, -41, 11, 91, -54, 24, + 35, 63, -61, 39, 49, -53, 46, 32, -42, 54, 13, -30, + 63, -6, -16, 72, -23, -2, 82, -39, 12, 91, -53, 24, + 36, 64, -59, 41, 51, -51, 47, 34, -41, 55, 15, -29, + 64, -4, -15, 73, -21, -1, 82, -37, 12, 92, -51, 25, + 37, 65, -56, 42, 53, -50, 48, 36, -40, 56, 18, -27, + 64, -1, -14, 73, -18, -1, 83, -34, 13, 92, -49, 25, + 39, 67, -54, 43, 55, -48, 49, 39, -38, 56, 20, -26, + 65, 1, -13, 74, -16, 0, 83, -32, 13, 92, -46, 26, + 40, 68, -52, 44, 57, -46, 50, 41, -37, 57, 23, -25, + 66, 4, -12, 74, -13, 1, 84, -30, 14, 93, -44, 26, + 41, 69, -50, 45, 59, -44, 51, 44, -35, 58, 26, -24, + 66, 7, -11, 75, -10, 2, 84, -27, 15, 93, -42, 27, + 43, 71, -47, 46, 61, -42, 52, 46, -33, 59, 28, -22, + 67, 10, -10, 75, -8, 3, 84, -24, 15, 93, -39, 28, + 44, 72, -45, 48, 63, -40, 53, 48, -31, 60, 31, -21, + 68, 13, -9, 76, -5, 3, 85, -22, 16, 94, -37, 28, + 46, 74, -43, 49, 65, -38, 54, 51, -30, 61, 34, -19, + 68, 15, -8, 77, -2, 4, 85, -19, 17, 94, -34, 29, + 47, 75, -40, 50, 66, -36, 55, 53, -28, 62, 36, -18, + 69, 18, -6, 77, 1, 5, 86, -16, 18, 95, -32, 30, + 49, 77, -38, 52, 69, -33, 56, 55, -26, 63, 39, -16, + 70, 21, -5, 78, 4, 7, 87, -13, 19, 95, -29, 30, + 50, 79, -35, 53, 70, -31, 58, 58, -24, 64, 42, -15, + 71, 24, -4, 79, 7, 8, 87, -10, 20, 96, -26, 31, + 51, 80, -33, 54, 72, -29, 59, 60, -22, 65, 45, -13, + 72, 27, -2, 79, 10, 9, 88, -7, 21, 96, -23, 32, + 53, 82, -31, 56, 74, -27, 60, 62, -20, 66, 47, -11, + 73, 30, -1, 80, 13, 10, 88, -4, 21, 97, -20, 33, + 55, 84, -28, 57, 76, -24, 61, 65, -18, 67, 50, -10, + 74, 33, 1, 81, 16, 11, 89, -1, 23, 97, -17, 34, + 56, 85, -26, 58, 78, -22, 62, 67, -16, 68, 53, -8, + 75, 36, 2, 82, 19, 12, 90, 2, 24, 98, -14, 35, + 57, 87, -23, 60, 80, -20, 64, 69, -14, 69, 55, -6, + 75, 39, 4, 83, 22, 14, 90, 5, 25, 98, -11, 35, + 25, 55, -82, 32, 36, -71, 40, 15, -57, 50, -5, -41, + 60, -23, -26, 70, -39, -11, 80, -53, 4, 89, -65, 18, + 25, 55, -81, 32, 37, -71, 40, 15, -57, 50, -5, -41, + 60, -23, -26, 70, -39, -11, 80, -53, 4, 90, -65, 18, + 26, 55, -81, 32, 37, -70, 41, 16, -56, 50, -4, -41, + 60, -23, -26, 70, -38, -11, 80, -52, 4, 90, -65, 18, + 26, 55, -81, 32, 37, -70, 41, 16, -56, 50, -4, -41, + 60, -22, -25, 70, -38, -11, 80, -52, 4, 90, -64, 18, + 26, 56, -80, 33, 38, -69, 41, 17, -56, 50, -3, -41, + 60, -22, -25, 70, -37, -10, 80, -52, 4, 90, -64, 18, + 27, 56, -79, 33, 39, -69, 41, 18, -55, 50, -2, -41, + 60, -21, -25, 70, -37, -10, 80, -51, 4, 90, -63, 18, + 27, 57, -78, 33, 39, -68, 41, 19, -55, 51, -1, -40, + 61, -20, -25, 70, -36, -10, 80, -50, 5, 90, -63, 18, + 28, 57, -77, 34, 40, -67, 42, 20, -54, 51, 0, -40, + 61, -19, -24, 70, -35, -10, 80, -49, 5, 90, -62, 18, + 29, 58, -76, 34, 41, -67, 42, 21, -54, 51, 1, -39, + 61, -18, -24, 71, -34, -10, 81, -48, 5, 90, -61, 18, + 29, 58, -75, 35, 42, -66, 43, 23, -53, 52, 3, -39, + 61, -16, -24, 71, -32, -9, 81, -47, 5, 90, -60, 19, + 30, 59, -73, 36, 44, -64, 43, 24, -52, 52, 4, -38, + 62, -15, -23, 71, -31, -9, 81, -46, 6, 90, -59, 19, + 31, 60, -72, 36, 45, -63, 44, 26, -51, 52, 6, -37, + 62, -13, -23, 71, -29, -8, 81, -44, 6, 90, -58, 19, + 32, 61, -70, 37, 47, -62, 44, 28, -50, 53, 8, -37, + 62, -11, -22, 72, -27, -8, 81, -43, 6, 91, -56, 20, + 33, 62, -68, 38, 48, -60, 45, 30, -49, 53, 10, -36, + 63, -9, -21, 72, -25, -7, 82, -41, 7, 91, -55, 20, + 34, 63, -66, 39, 50, -59, 46, 32, -48, 54, 12, -35, + 63, -7, -21, 72, -23, -7, 82, -39, 7, 91, -53, 20, + 35, 64, -64, 40, 51, -57, 47, 34, -46, 55, 15, -34, + 64, -4, -20, 73, -21, -6, 82, -37, 8, 91, -51, 21, + 37, 66, -62, 41, 53, -55, 48, 36, -45, 55, 17, -33, + 64, -2, -19, 73, -19, -6, 83, -35, 8, 92, -49, 21, + 38, 67, -60, 42, 55, -53, 48, 38, -44, 56, 20, -32, + 65, 1, -18, 74, -17, -5, 83, -33, 9, 92, -47, 22, + 39, 68, -58, 43, 57, -52, 49, 40, -42, 57, 22, -30, + 65, 3, -17, 74, -14, -4, 83, -30, 9, 92, -45, 22, + 41, 69, -56, 44, 58, -50, 50, 43, -41, 57, 25, -29, + 66, 6, -16, 75, -12, -3, 84, -28, 10, 93, -43, 23, + 42, 71, -53, 46, 60, -48, 51, 45, -39, 58, 27, -28, + 67, 9, -15, 75, -9, -2, 84, -25, 11, 93, -40, 23, + 43, 72, -51, 47, 62, -46, 52, 47, -37, 59, 30, -26, + 67, 11, -14, 76, -6, -1, 85, -23, 11, 93, -38, 24, + 45, 74, -49, 48, 64, -44, 53, 50, -35, 60, 33, -25, + 68, 14, -13, 76, -3, -1, 85, -20, 12, 94, -35, 24, + 46, 75, -47, 49, 66, -42, 54, 52, -34, 61, 35, -24, + 69, 17, -12, 77, -1, 0, 86, -18, 13, 94, -33, 25, + 47, 77, -44, 51, 68, -40, 55, 54, -32, 62, 38, -22, + 69, 20, -10, 78, 2, 1, 86, -15, 14, 95, -30, 26, + 49, 78, -42, 52, 70, -37, 57, 57, -30, 63, 41, -20, + 70, 23, -9, 78, 5, 3, 87, -12, 15, 95, -27, 27, + 50, 80, -40, 53, 72, -35, 58, 59, -28, 64, 43, -19, + 71, 26, -8, 79, 8, 4, 87, -9, 16, 96, -25, 27, + 52, 81, -37, 55, 73, -33, 59, 61, -26, 65, 46, -17, + 72, 28, -6, 80, 11, 5, 88, -6, 17, 96, -22, 28, + 53, 83, -35, 56, 75, -31, 60, 63, -24, 66, 48, -16, + 73, 31, -5, 80, 14, 6, 89, -3, 18, 97, -19, 29, + 55, 85, -32, 57, 77, -28, 62, 66, -22, 67, 51, -14, + 74, 34, -3, 81, 17, 7, 89, 0, 19, 97, -16, 30, + 56, 86, -30, 59, 79, -26, 63, 68, -20, 68, 54, -12, + 75, 37, -2, 82, 20, 8, 90, 3, 20, 98, -13, 31, + 58, 88, -27, 60, 81, -24, 64, 70, -18, 69, 56, -10, + 76, 40, -1, 83, 23, 10, 91, 6, 21, 99, -10, 32, + 26, 57, -85, 33, 39, -74, 41, 18, -60, 50, -2, -45, + 60, -21, -30, 70, -36, -15, 80, -51, 0, 90, -63, 14, + 26, 57, -84, 33, 40, -74, 41, 19, -60, 50, -2, -45, + 60, -20, -30, 70, -36, -15, 80, -51, 0, 90, -63, 14, + 27, 58, -84, 33, 40, -74, 41, 19, -60, 50, -1, -45, + 60, -20, -30, 70, -36, -15, 80, -50, 0, 90, -63, 14, + 27, 58, -84, 33, 40, -73, 41, 19, -60, 51, -1, -45, + 61, -20, -29, 70, -35, -15, 80, -50, 0, 90, -63, 14, + 27, 58, -83, 33, 41, -73, 42, 20, -60, 51, 0, -45, + 61, -19, -29, 70, -35, -14, 80, -49, 0, 90, -62, 14, + 28, 58, -82, 34, 41, -72, 42, 21, -59, 51, 1, -44, + 61, -18, -29, 70, -34, -14, 80, -49, 0, 90, -62, 14, + 28, 59, -81, 34, 42, -72, 42, 22, -59, 51, 1, -44, + 61, -17, -29, 71, -33, -14, 80, -48, 1, 90, -61, 14, + 29, 59, -80, 35, 43, -71, 42, 23, -58, 51, 3, -44, + 61, -16, -28, 71, -32, -14, 81, -47, 1, 90, -60, 14, + 29, 60, -79, 35, 44, -70, 43, 24, -57, 52, 4, -43, + 61, -15, -28, 71, -31, -14, 81, -46, 1, 90, -59, 15, + 30, 61, -78, 36, 45, -69, 43, 25, -57, 52, 5, -43, + 62, -14, -28, 71, -30, -13, 81, -45, 1, 90, -58, 15, + 31, 61, -77, 36, 46, -68, 44, 27, -56, 52, 7, -42, + 62, -12, -27, 71, -29, -13, 81, -44, 2, 90, -57, 15, + 32, 62, -75, 37, 47, -67, 44, 28, -55, 53, 9, -41, + 62, -10, -27, 72, -27, -12, 81, -43, 2, 91, -56, 15, + 33, 63, -73, 38, 49, -65, 45, 30, -54, 53, 11, -40, + 63, -8, -26, 72, -25, -12, 82, -41, 2, 91, -54, 16, + 34, 64, -72, 39, 50, -64, 46, 32, -53, 54, 13, -40, + 63, -6, -25, 72, -23, -11, 82, -39, 3, 91, -53, 16, + 35, 65, -70, 40, 52, -62, 46, 34, -52, 54, 15, -39, + 63, -4, -25, 73, -21, -11, 82, -37, 3, 91, -51, 16, + 36, 66, -68, 41, 53, -61, 47, 36, -50, 55, 17, -38, + 64, -2, -24, 73, -19, -10, 82, -35, 4, 92, -50, 17, + 37, 67, -66, 42, 55, -59, 48, 38, -49, 56, 19, -37, + 64, 0, -23, 73, -17, -10, 83, -33, 4, 92, -47, 17, + 39, 68, -64, 43, 57, -57, 49, 40, -47, 56, 22, -36, + 65, 3, -22, 74, -15, -9, 83, -31, 5, 92, -46, 18, + 40, 70, -62, 44, 58, -55, 50, 42, -46, 57, 24, -34, + 66, 5, -21, 74, -12, -8, 83, -29, 5, 93, -43, 18, + 41, 71, -60, 45, 60, -54, 51, 44, -44, 58, 26, -33, + 66, 8, -20, 75, -10, -7, 84, -27, 6, 93, -41, 19, + 43, 72, -57, 46, 62, -52, 52, 47, -43, 59, 29, -32, + 67, 10, -19, 75, -7, -6, 84, -24, 7, 93, -39, 19, + 44, 74, -55, 47, 64, -50, 53, 49, -41, 60, 32, -30, + 68, 13, -18, 76, -4, -6, 85, -21, 7, 94, -36, 20, + 45, 75, -53, 49, 65, -48, 54, 51, -39, 60, 34, -29, + 68, 16, -17, 76, -2, -5, 85, -19, 8, 94, -34, 21, + 47, 76, -51, 50, 67, -46, 55, 53, -38, 61, 37, -28, + 69, 18, -16, 77, 1, -4, 86, -16, 9, 94, -32, 21, + 48, 78, -48, 51, 69, -44, 56, 56, -36, 62, 39, -26, + 70, 21, -15, 78, 4, -3, 86, -13, 10, 95, -29, 22, + 49, 79, -46, 52, 71, -41, 57, 58, -34, 63, 42, -24, + 71, 24, -13, 78, 7, -1, 87, -10, 11, 95, -26, 23, + 51, 81, -44, 54, 73, -39, 58, 60, -32, 64, 45, -23, + 71, 27, -12, 79, 10, 0, 88, -8, 12, 96, -23, 23, + 52, 82, -41, 55, 75, -37, 59, 62, -30, 65, 47, -21, + 72, 30, -11, 80, 13, 1, 88, -5, 13, 96, -21, 24, + 54, 84, -39, 56, 76, -35, 61, 65, -28, 66, 50, -20, + 73, 32, -9, 81, 15, 2, 89, -2, 14, 97, -18, 25, + 55, 86, -36, 58, 78, -32, 62, 67, -26, 67, 52, -18, + 74, 36, -8, 81, 19, 3, 89, 1, 15, 98, -15, 26, + 57, 87, -34, 59, 80, -30, 63, 69, -24, 68, 55, -16, + 75, 38, -6, 82, 21, 4, 90, 4, 16, 98, -12, 27, + 58, 89, -32, 60, 82, -28, 64, 71, -22, 69, 57, -14, + 76, 41, -5, 83, 24, 6, 91, 7, 17, 99, -9, 28, + 28, 60, -88, 34, 43, -78, 42, 22, -65, 51, 2, -50, + 61, -17, -34, 70, -34, -19, 80, -48, -4, 90, -61, 9, + 28, 60, -88, 34, 43, -78, 42, 22, -64, 51, 2, -50, + 61, -17, -34, 70, -33, -19, 80, -48, -4, 90, -61, 9, + 28, 60, -87, 34, 43, -77, 42, 23, -64, 51, 2, -50, + 61, -17, -34, 70, -33, -19, 80, -48, -4, 90, -61, 9, + 28, 60, -87, 34, 44, -77, 42, 23, -64, 51, 3, -49, + 61, -16, -34, 71, -33, -19, 80, -48, -4, 90, -60, 10, + 28, 61, -86, 34, 44, -77, 42, 24, -64, 51, 3, -49, + 61, -16, -34, 71, -32, -19, 80, -47, -4, 90, -60, 10, + 29, 61, -86, 35, 45, -76, 42, 24, -63, 51, 4, -49, + 61, -15, -34, 71, -32, -19, 81, -46, -4, 90, -60, 10, + 29, 61, -85, 35, 45, -76, 43, 25, -63, 52, 5, -49, + 61, -14, -33, 71, -31, -19, 81, -46, -4, 90, -59, 10, + 30, 62, -84, 35, 46, -75, 43, 26, -62, 52, 6, -48, + 61, -13, -33, 71, -30, -18, 81, -45, -4, 90, -58, 10, + 31, 62, -83, 36, 47, -74, 43, 27, -62, 52, 7, -48, + 62, -12, -33, 71, -29, -18, 81, -44, -3, 90, -57, 10, + 31, 63, -82, 36, 48, -73, 44, 28, -61, 52, 8, -47, + 62, -11, -32, 71, -27, -18, 81, -43, -3, 91, -56, 10, + 32, 64, -80, 37, 49, -72, 44, 30, -60, 53, 10, -46, + 62, -9, -32, 72, -26, -17, 81, -42, -3, 91, -55, 11, + 33, 64, -79, 38, 50, -71, 45, 31, -59, 53, 12, -46, + 63, -8, -31, 72, -25, -17, 82, -40, -3, 91, -54, 11, + 34, 65, -77, 39, 51, -69, 46, 33, -58, 54, 14, -45, + 63, -6, -30, 72, -23, -16, 82, -39, -2, 91, -52, 11, + 35, 66, -75, 39, 53, -68, 46, 35, -57, 54, 15, -44, + 63, -4, -30, 73, -21, -16, 82, -37, -2, 91, -51, 12, + 36, 67, -74, 40, 54, -66, 47, 37, -56, 55, 17, -43, + 64, -2, -29, 73, -19, -15, 82, -35, -1, 92, -49, 12, + 37, 68, -72, 41, 56, -65, 48, 38, -55, 55, 19, -42, + 64, 0, -28, 73, -17, -15, 83, -33, -1, 92, -48, 12, + 38, 69, -70, 42, 57, -63, 48, 41, -53, 56, 22, -41, + 65, 3, -27, 74, -15, -14, 83, -31, 0, 92, -46, 13, + 39, 70, -68, 43, 59, -61, 49, 42, -52, 57, 24, -40, + 65, 5, -27, 74, -13, -13, 83, -29, 0, 92, -44, 13, + 41, 71, -66, 44, 60, -60, 50, 44, -50, 57, 26, -39, + 66, 7, -26, 75, -10, -13, 84, -27, 1, 93, -42, 14, + 42, 72, -64, 45, 62, -58, 51, 46, -49, 58, 29, -38, + 67, 10, -25, 75, -8, -12, 84, -25, 2, 93, -40, 14, + 43, 74, -61, 47, 64, -56, 52, 49, -47, 59, 31, -36, + 67, 13, -24, 76, -5, -11, 85, -22, 2, 93, -37, 15, + 44, 75, -59, 48, 65, -54, 53, 51, -45, 60, 34, -35, + 68, 15, -23, 76, -3, -10, 85, -20, 3, 94, -35, 16, + 46, 76, -57, 49, 67, -52, 54, 53, -44, 61, 36, -33, + 69, 18, -21, 77, 0, -9, 86, -17, 4, 94, -32, 16, + 47, 78, -55, 50, 69, -50, 55, 55, -42, 62, 39, -32, + 69, 20, -20, 77, 3, -8, 86, -14, 5, 95, -30, 17, + 48, 79, -53, 51, 70, -48, 56, 57, -40, 63, 41, -31, + 70, 23, -19, 78, 5, -7, 87, -12, 5, 95, -27, 18, + 50, 81, -50, 53, 72, -46, 57, 60, -38, 64, 44, -29, + 71, 26, -18, 79, 8, -6, 87, -9, 6, 96, -25, 18, + 51, 82, -48, 54, 74, -44, 59, 62, -37, 64, 46, -27, + 72, 29, -16, 79, 11, -5, 88, -6, 7, 96, -22, 19, + 53, 84, -46, 55, 76, -41, 60, 64, -35, 65, 49, -26, + 73, 31, -15, 80, 14, -4, 88, -3, 8, 97, -19, 20, + 54, 85, -43, 57, 78, -39, 61, 66, -33, 66, 51, -24, + 73, 34, -14, 81, 17, -3, 89, 0, 9, 97, -17, 21, + 56, 87, -41, 58, 80, -37, 62, 68, -31, 68, 54, -22, + 74, 37, -12, 82, 20, -1, 90, 3, 10, 98, -13, 22, + 57, 88, -38, 59, 81, -35, 63, 70, -29, 69, 56, -21, + 75, 40, -11, 82, 23, 0, 90, 6, 11, 98, -11, 23, + 59, 90, -36, 61, 83, -33, 65, 72, -27, 70, 59, -19, + 76, 42, -9, 83, 26, 1, 91, 8, 12, 99, -8, 23, + 29, 62, -91, 34, 46, -81, 42, 25, -68, 51, 5, -54, + 61, -15, -38, 71, -31, -23, 81, -46, -8, 90, -59, 6, + 29, 62, -90, 34, 46, -81, 42, 25, -68, 51, 5, -53, + 61, -14, -38, 71, -31, -23, 81, -46, -8, 90, -59, 6, + 29, 63, -90, 35, 46, -81, 42, 26, -68, 51, 5, -53, + 61, -14, -38, 71, -31, -23, 81, -46, -8, 90, -59, 6, + 29, 63, -90, 35, 46, -80, 43, 26, -68, 52, 6, -53, + 61, -14, -38, 71, -30, -23, 81, -45, -8, 90, -58, 6, + 29, 63, -89, 35, 47, -80, 43, 27, -67, 52, 6, -53, + 61, -13, -38, 71, -30, -23, 81, -45, -8, 90, -58, 6, + 30, 63, -89, 35, 47, -79, 43, 27, -67, 52, 7, -53, + 61, -12, -37, 71, -29, -23, 81, -44, -8, 90, -58, 6, + 30, 64, -88, 36, 48, -79, 43, 28, -66, 52, 8, -52, + 62, -12, -37, 71, -28, -23, 81, -44, -8, 90, -57, 6, + 31, 64, -87, 36, 49, -78, 44, 29, -66, 52, 9, -52, + 62, -10, -37, 71, -27, -22, 81, -43, -8, 90, -56, 6, + 31, 64, -86, 37, 49, -77, 44, 30, -65, 53, 10, -51, + 62, -9, -36, 71, -26, -22, 81, -42, -7, 91, -55, 6, + 32, 65, -85, 37, 50, -76, 44, 31, -65, 53, 11, -51, + 62, -8, -36, 72, -25, -22, 81, -41, -7, 91, -54, 7, + 33, 66, -83, 38, 51, -75, 45, 33, -64, 53, 13, -50, + 63, -7, -36, 72, -24, -21, 82, -40, -7, 91, -53, 7, + 34, 66, -82, 38, 52, -74, 45, 34, -63, 54, 14, -50, + 63, -5, -35, 72, -22, -21, 82, -38, -6, 91, -52, 7, + 35, 67, -80, 39, 54, -73, 46, 36, -62, 54, 16, -49, + 63, -3, -34, 72, -21, -20, 82, -37, -6, 91, -51, 7, + 36, 68, -79, 40, 55, -71, 47, 37, -61, 55, 18, -48, + 64, -1, -34, 73, -19, -20, 82, -35, -6, 91, -49, 8, + 37, 69, -77, 41, 56, -70, 47, 39, -60, 55, 20, -47, + 64, 0, -33, 73, -17, -19, 83, -33, -5, 92, -48, 8, + 38, 70, -75, 42, 58, -69, 48, 41, -58, 56, 22, -46, + 65, 2, -32, 73, -15, -19, 83, -31, -5, 92, -46, 9, + 39, 71, -73, 43, 59, -67, 49, 43, -57, 57, 24, -45, + 65, 5, -31, 74, -13, -18, 83, -29, -4, 92, -44, 9, + 40, 72, -71, 44, 61, -65, 50, 44, -56, 57, 26, -44, + 66, 7, -31, 74, -11, -17, 84, -27, -4, 93, -42, 9, + 41, 73, -69, 45, 62, -63, 51, 46, -54, 58, 28, -43, + 66, 9, -30, 75, -8, -17, 84, -25, -3, 93, -40, 10, + 42, 74, -67, 46, 64, -62, 52, 48, -53, 59, 31, -42, + 67, 12, -29, 75, -6, -16, 84, -23, -2, 93, -38, 11, + 44, 75, -65, 47, 65, -60, 53, 51, -51, 59, 33, -40, + 68, 14, -28, 76, -3, -15, 85, -20, -2, 94, -36, 11, + 45, 77, -63, 48, 67, -58, 54, 53, -49, 60, 35, -39, + 68, 17, -27, 76, -1, -14, 85, -18, -1, 94, -33, 12, + 46, 78, -61, 50, 69, -56, 55, 55, -48, 61, 38, -37, + 69, 19, -25, 77, 2, -13, 86, -15, 0, 94, -31, 12, + 48, 79, -59, 51, 70, -54, 56, 57, -46, 62, 40, -36, + 70, 22, -24, 78, 4, -12, 86, -13, 1, 95, -29, 13, + 49, 80, -57, 52, 72, -52, 57, 59, -44, 63, 43, -35, + 70, 24, -23, 78, 7, -11, 87, -10, 1, 95, -26, 14, + 50, 82, -54, 53, 74, -50, 58, 61, -42, 64, 45, -33, + 71, 27, -22, 79, 10, -10, 87, -7, 2, 96, -23, 15, + 52, 83, -52, 55, 75, -47, 59, 63, -40, 65, 48, -31, + 72, 30, -20, 80, 13, -9, 88, -5, 3, 96, -21, 15, + 53, 85, -50, 56, 77, -45, 60, 65, -39, 66, 50, -30, + 73, 33, -19, 80, 15, -8, 89, -2, 4, 97, -18, 16, + 55, 86, -47, 57, 79, -43, 61, 67, -37, 67, 52, -28, + 74, 35, -18, 81, 18, -7, 89, 1, 5, 97, -15, 17, + 56, 88, -45, 59, 81, -41, 63, 69, -35, 68, 55, -26, + 75, 38, -16, 82, 21, -5, 90, 4, 6, 98, -12, 18, + 58, 89, -42, 60, 82, -39, 64, 72, -33, 69, 57, -25, + 76, 41, -15, 83, 24, -4, 91, 7, 7, 98, -9, 19, + 59, 91, -40, 61, 84, -37, 65, 74, -31, 70, 60, -23, + 76, 44, -13, 83, 27, -3, 91, 10, 8, 99, -7, 20, + 30, 65, -94, 35, 49, -84, 43, 28, -72, 52, 8, -57, + 61, -12, -42, 71, -28, -27, 81, -44, -12, 90, -57, 2, + 30, 65, -93, 35, 49, -84, 43, 29, -72, 52, 8, -57, + 61, -11, -42, 71, -28, -27, 81, -44, -12, 90, -57, 2, + 30, 65, -93, 35, 49, -84, 43, 29, -71, 52, 8, -57, + 62, -11, -42, 71, -28, -27, 81, -43, -12, 90, -57, 2, + 30, 65, -93, 36, 49, -84, 43, 29, -71, 52, 9, -57, + 62, -11, -42, 71, -28, -27, 81, -43, -12, 90, -56, 2, + 30, 65, -92, 36, 50, -83, 43, 30, -71, 52, 9, -57, + 62, -10, -42, 71, -27, -27, 81, -43, -12, 90, -56, 2, + 31, 65, -92, 36, 50, -83, 44, 30, -70, 52, 10, -56, + 62, -10, -41, 71, -26, -27, 81, -42, -12, 90, -56, 2, + 31, 66, -91, 36, 51, -82, 44, 31, -70, 53, 11, -56, + 62, -9, -41, 71, -26, -26, 81, -41, -12, 91, -55, 2, + 32, 66, -90, 37, 51, -81, 44, 32, -69, 53, 12, -56, + 62, -8, -41, 72, -25, -26, 81, -40, -11, 91, -54, 2, + 32, 67, -89, 37, 52, -81, 45, 33, -69, 53, 13, -55, + 62, -7, -40, 72, -24, -26, 81, -40, -11, 91, -53, 3, + 33, 67, -88, 38, 53, -80, 45, 34, -68, 53, 14, -55, + 63, -5, -40, 72, -23, -26, 82, -39, -11, 91, -52, 3, + 34, 68, -87, 39, 54, -79, 45, 35, -67, 54, 15, -54, + 63, -4, -39, 72, -21, -25, 82, -37, -11, 91, -51, 3, + 35, 68, -85, 39, 55, -78, 46, 36, -66, 54, 17, -53, + 63, -3, -39, 72, -20, -25, 82, -36, -10, 91, -50, 3, + 36, 69, -84, 40, 56, -76, 47, 38, -65, 55, 19, -53, + 64, -1, -38, 73, -18, -24, 82, -34, -10, 91, -49, 4, + 36, 70, -82, 41, 57, -75, 47, 40, -64, 55, 20, -52, + 64, 1, -38, 73, -17, -24, 82, -33, -10, 92, -47, 4, + 37, 71, -80, 42, 58, -74, 48, 41, -63, 56, 22, -51, + 64, 3, -37, 73, -15, -23, 83, -31, -9, 92, -46, 4, + 38, 71, -79, 42, 60, -72, 49, 43, -62, 56, 24, -50, + 65, 5, -36, 74, -13, -23, 83, -29, -9, 92, -44, 5, + 40, 72, -77, 44, 61, -70, 50, 45, -61, 57, 26, -49, + 65, 7, -35, 74, -11, -22, 83, -27, -8, 92, -42, 5, + 41, 73, -75, 44, 62, -69, 50, 47, -59, 58, 28, -48, + 66, 9, -34, 75, -9, -21, 84, -25, -7, 93, -40, 6, + 42, 74, -73, 46, 64, -67, 51, 48, -58, 58, 30, -47, + 67, 11, -34, 75, -6, -20, 84, -23, -7, 93, -38, 6, + 43, 76, -71, 47, 65, -65, 52, 50, -56, 59, 33, -45, + 67, 14, -33, 76, -4, -20, 85, -21, -6, 93, -36, 7, + 44, 77, -69, 48, 67, -63, 53, 52, -55, 60, 35, -44, + 68, 16, -32, 76, -1, -19, 85, -19, -6, 94, -34, 7, + 46, 78, -67, 49, 69, -61, 54, 54, -53, 61, 37, -43, + 68, 19, -30, 77, 1, -18, 85, -16, -5, 94, -32, 8, + 47, 79, -65, 50, 70, -60, 55, 56, -52, 61, 40, -41, + 69, 21, -29, 77, 4, -17, 86, -14, -4, 95, -29, 9, + 48, 80, -62, 51, 72, -58, 56, 58, -50, 62, 42, -40, + 70, 24, -28, 78, 6, -16, 86, -11, -3, 95, -27, 9, + 49, 82, -60, 52, 73, -56, 57, 60, -48, 63, 44, -38, + 71, 26, -27, 78, 9, -15, 87, -9, -2, 95, -25, 10, + 51, 83, -58, 54, 75, -53, 58, 62, -46, 64, 47, -37, + 71, 29, -26, 79, 12, -14, 88, -6, -1, 96, -22, 11, + 52, 84, -56, 55, 77, -51, 59, 64, -44, 65, 49, -35, + 72, 32, -24, 80, 14, -13, 88, -3, -1, 96, -19, 11, + 54, 86, -53, 56, 78, -49, 60, 66, -43, 66, 51, -34, + 73, 34, -23, 81, 17, -12, 89, -1, 0, 97, -17, 12, + 55, 87, -51, 57, 80, -47, 62, 68, -41, 67, 54, -32, + 74, 37, -22, 81, 20, -11, 89, 2, 1, 97, -14, 13, + 57, 89, -49, 59, 82, -45, 63, 71, -39, 68, 56, -30, + 75, 40, -20, 82, 23, -9, 90, 5, 2, 98, -11, 14, + 58, 90, -46, 60, 83, -43, 64, 73, -37, 69, 59, -29, + 76, 42, -19, 83, 25, -8, 91, 8, 3, 99, -8, 15, + 59, 92, -44, 62, 85, -40, 65, 75, -35, 70, 61, -27, + 77, 45, -17, 84, 28, -7, 91, 11, 5, 99, -5, 16, + 31, 67, -96, 36, 51, -87, 44, 31, -75, 52, 11, -61, + 62, -9, -46, 71, -26, -31, 81, -41, -16, 90, -55, -2, + 31, 67, -96, 36, 51, -87, 44, 32, -75, 52, 11, -61, + 62, -8, -46, 71, -25, -31, 81, -41, -16, 90, -55, -2, + 31, 67, -96, 36, 52, -87, 44, 32, -75, 52, 11, -61, + 62, -8, -46, 71, -25, -31, 81, -41, -16, 90, -55, -2, + 31, 67, -95, 36, 52, -87, 44, 32, -75, 52, 12, -61, + 62, -8, -46, 71, -25, -31, 81, -41, -16, 91, -54, -2, + 32, 67, -95, 37, 52, -86, 44, 33, -74, 53, 12, -60, + 62, -7, -45, 71, -24, -31, 81, -40, -16, 91, -54, -2, + 32, 68, -94, 37, 53, -86, 44, 33, -74, 53, 13, -60, + 62, -7, -45, 72, -24, -31, 81, -40, -16, 91, -53, -2, + 32, 68, -94, 37, 53, -85, 45, 34, -74, 53, 14, -60, + 62, -6, -45, 72, -23, -30, 81, -39, -16, 91, -53, -2, + 33, 68, -93, 38, 54, -85, 45, 35, -73, 53, 15, -59, + 63, -5, -45, 72, -22, -30, 82, -38, -15, 91, -52, -2, + 33, 69, -92, 38, 54, -84, 45, 36, -72, 54, 16, -59, + 63, -4, -44, 72, -21, -30, 82, -37, -15, 91, -51, -1, + 34, 69, -91, 39, 55, -83, 46, 37, -72, 54, 17, -58, + 63, -3, -44, 72, -20, -29, 82, -36, -15, 91, -50, -1, + 35, 70, -90, 39, 56, -82, 46, 38, -71, 54, 18, -58, + 63, -1, -43, 72, -19, -29, 82, -35, -15, 91, -49, -1, + 35, 70, -88, 40, 57, -81, 47, 39, -70, 55, 20, -57, + 64, 0, -43, 73, -18, -29, 82, -34, -14, 91, -48, -1, + 36, 71, -87, 41, 58, -80, 47, 41, -69, 55, 21, -56, + 64, 2, -42, 73, -16, -28, 82, -32, -14, 92, -47, 0, + 37, 72, -85, 41, 59, -78, 48, 42, -68, 56, 23, -55, + 64, 3, -42, 73, -14, -28, 83, -31, -13, 92, -45, 0, + 38, 72, -84, 42, 60, -77, 48, 44, -67, 56, 25, -55, + 65, 5, -41, 74, -13, -27, 83, -29, -13, 92, -44, 0, + 39, 73, -82, 43, 62, -76, 49, 45, -66, 57, 26, -54, + 65, 7, -40, 74, -11, -27, 83, -27, -13, 92, -42, 1, + 40, 74, -80, 44, 63, -74, 50, 47, -64, 57, 28, -53, + 66, 9, -39, 74, -8, -26, 84, -25, -12, 93, -40, 1, + 41, 75, -78, 45, 64, -72, 51, 49, -63, 58, 30, -52, + 66, 11, -38, 75, -6, -25, 84, -23, -11, 93, -39, 2, + 43, 76, -76, 46, 66, -71, 52, 50, -62, 59, 32, -50, + 67, 13, -37, 75, -4, -24, 84, -21, -11, 93, -37, 2, + 44, 77, -75, 47, 67, -69, 53, 52, -60, 59, 35, -49, + 67, 16, -37, 76, -2, -24, 85, -19, -10, 94, -35, 3, + 45, 78, -72, 48, 69, -67, 54, 54, -58, 60, 37, -48, + 68, 18, -35, 76, 0, -23, 85, -17, -9, 94, -32, 3, + 46, 79, -70, 49, 70, -65, 54, 56, -57, 61, 39, -47, + 69, 21, -34, 77, 3, -22, 86, -14, -9, 94, -30, 4, + 47, 81, -68, 51, 72, -63, 55, 58, -55, 62, 41, -45, + 69, 23, -33, 77, 5, -21, 86, -12, -8, 95, -28, 5, + 49, 82, -66, 52, 73, -61, 56, 60, -54, 63, 44, -44, + 70, 25, -32, 78, 8, -20, 87, -10, -7, 95, -26, 5, + 50, 83, -64, 53, 75, -59, 57, 62, -52, 64, 46, -42, + 71, 28, -31, 79, 10, -19, 87, -7, -6, 96, -23, 6, + 51, 84, -62, 54, 76, -57, 59, 64, -50, 65, 48, -41, + 72, 31, -30, 79, 13, -18, 88, -4, -5, 96, -20, 7, + 53, 86, -59, 55, 78, -55, 60, 66, -48, 65, 51, -39, + 73, 33, -28, 80, 16, -17, 88, -2, -4, 97, -18, 8, + 54, 87, -57, 57, 80, -53, 61, 68, -46, 66, 53, -38, + 73, 36, -27, 81, 18, -16, 89, 1, -4, 97, -15, 8, + 55, 88, -55, 58, 81, -51, 62, 70, -45, 67, 55, -36, + 74, 38, -26, 81, 21, -15, 90, 4, -3, 98, -13, 9, + 57, 90, -52, 59, 83, -49, 63, 72, -42, 69, 58, -34, + 75, 41, -24, 82, 24, -13, 90, 7, -1, 98, -10, 10, + 58, 91, -50, 61, 85, -47, 64, 74, -41, 70, 60, -33, + 76, 44, -23, 83, 27, -12, 91, 9, 0, 99, -7, 11, + 60, 93, -48, 62, 86, -44, 66, 76, -39, 71, 62, -31, + 77, 46, -21, 84, 29, -11, 92, 12, 1, 99, -4, 12, + 32, 69, -99, 37, 54, -91, 44, 35, -79, 53, 14, -65, + 62, -5, -50, 72, -23, -35, 81, -39, -21, 91, -53, -7, + 32, 69, -99, 37, 55, -91, 44, 35, -79, 53, 15, -65, + 62, -5, -50, 72, -22, -35, 81, -38, -20, 91, -52, -6, + 32, 70, -99, 37, 55, -91, 44, 35, -79, 53, 15, -65, + 62, -5, -50, 72, -22, -35, 81, -38, -20, 91, -52, -6, + 32, 70, -99, 37, 55, -90, 45, 36, -78, 53, 15, -65, + 62, -4, -50, 72, -22, -35, 81, -38, -20, 91, -52, -6, + 33, 70, -98, 38, 55, -90, 45, 36, -78, 53, 16, -65, + 63, -4, -50, 72, -21, -35, 81, -38, -20, 91, -52, -6, + 33, 70, -98, 38, 56, -89, 45, 37, -78, 53, 16, -64, + 63, -3, -49, 72, -21, -35, 82, -37, -20, 91, -51, -6, + 33, 70, -97, 38, 56, -89, 45, 37, -77, 54, 17, -64, + 63, -3, -49, 72, -20, -35, 82, -36, -20, 91, -51, -6, + 34, 71, -96, 39, 57, -88, 46, 38, -77, 54, 18, -63, + 63, -2, -49, 72, -19, -34, 82, -36, -20, 91, -50, -6, + 34, 71, -95, 39, 57, -87, 46, 39, -76, 54, 19, -63, + 63, -1, -48, 72, -18, -34, 82, -35, -20, 91, -49, -6, + 35, 71, -94, 40, 58, -87, 46, 40, -76, 54, 20, -62, + 63, 0, -48, 73, -17, -34, 82, -34, -19, 91, -48, -5, + 36, 72, -93, 40, 59, -86, 47, 41, -75, 55, 21, -62, + 64, 2, -48, 73, -16, -33, 82, -33, -19, 91, -47, -5, + 36, 72, -92, 41, 60, -85, 47, 42, -74, 55, 23, -61, + 64, 3, -47, 73, -15, -33, 82, -31, -19, 92, -46, -5, + 37, 73, -90, 42, 61, -83, 48, 43, -73, 56, 24, -60, + 64, 5, -46, 73, -13, -33, 83, -30, -18, 92, -45, -5, + 38, 74, -89, 42, 62, -82, 48, 45, -72, 56, 26, -60, + 65, 6, -46, 74, -12, -32, 83, -28, -18, 92, -43, -4, + 39, 74, -87, 43, 63, -81, 49, 46, -71, 57, 27, -59, + 65, 8, -45, 74, -10, -31, 83, -27, -17, 92, -42, -4, + 40, 75, -86, 44, 64, -79, 50, 48, -70, 57, 29, -58, + 66, 10, -44, 74, -8, -31, 84, -25, -17, 93, -40, -4, + 41, 76, -84, 45, 65, -78, 51, 49, -68, 58, 31, -57, + 66, 12, -44, 75, -6, -30, 84, -23, -16, 93, -38, -3, + 42, 77, -82, 46, 66, -76, 51, 51, -67, 58, 33, -56, + 67, 14, -43, 75, -4, -29, 84, -21, -16, 93, -37, -3, + 43, 78, -80, 47, 68, -75, 52, 53, -66, 59, 35, -55, + 67, 16, -42, 76, -2, -29, 85, -19, -15, 93, -35, -2, + 44, 79, -78, 48, 69, -73, 53, 54, -64, 60, 37, -53, + 68, 18, -41, 76, 0, -28, 85, -17, -15, 94, -33, -2, + 46, 80, -76, 49, 71, -71, 54, 56, -63, 61, 39, -52, + 69, 20, -40, 77, 3, -27, 86, -15, -14, 94, -30, -1, + 47, 81, -74, 50, 72, -69, 55, 58, -61, 61, 41, -51, + 69, 23, -39, 77, 5, -26, 86, -12, -13, 95, -28, 0, + 48, 82, -72, 51, 73, -67, 56, 60, -60, 62, 43, -49, + 70, 25, -38, 78, 7, -25, 86, -10, -12, 95, -26, 0, + 49, 83, -70, 52, 75, -65, 57, 62, -58, 63, 46, -48, + 71, 27, -36, 78, 10, -24, 87, -8, -12, 95, -24, 1, + 51, 85, -68, 53, 76, -63, 58, 64, -56, 64, 48, -47, + 71, 30, -35, 79, 12, -23, 87, -5, -11, 96, -21, 2, + 52, 86, -66, 55, 78, -61, 59, 66, -54, 65, 50, -45, + 72, 32, -34, 80, 15, -22, 88, -2, -10, 96, -19, 3, + 53, 87, -63, 56, 79, -59, 60, 68, -53, 66, 52, -44, + 73, 35, -33, 80, 18, -21, 89, 0, -9, 97, -16, 3, + 55, 88, -61, 57, 81, -57, 61, 69, -51, 67, 55, -42, + 74, 37, -31, 81, 20, -20, 89, 3, -8, 97, -14, 4, + 56, 90, -59, 58, 83, -55, 62, 71, -49, 68, 57, -40, + 75, 40, -30, 82, 23, -19, 90, 5, -7, 98, -11, 5, + 57, 91, -57, 60, 84, -53, 64, 73, -47, 69, 59, -39, + 75, 43, -28, 83, 26, -18, 90, 8, -6, 98, -8, 6, + 59, 93, -54, 61, 86, -51, 65, 75, -45, 70, 61, -37, + 76, 45, -27, 83, 28, -16, 91, 11, -5, 99, -5, 7, + 60, 94, -52, 62, 88, -49, 66, 77, -43, 71, 64, -35, + 77, 48, -26, 84, 31, -15, 92, 14, -4, 100, -3, 8, + 33, 72, -102, 38, 57, -94, 45, 38, -82, 53, 18, -69, + 63, -2, -54, 72, -20, -39, 82, -36, -24, 91, -50, -10, + 33, 72, -102, 38, 57, -94, 45, 38, -82, 53, 18, -69, + 63, -2, -54, 72, -20, -39, 82, -36, -24, 91, -50, -10, + 33, 72, -102, 38, 57, -94, 45, 38, -82, 53, 18, -68, + 63, -2, -54, 72, -19, -39, 82, -36, -24, 91, -50, -10, + 33, 72, -101, 38, 58, -93, 45, 39, -82, 54, 18, -68, + 63, -2, -54, 72, -19, -39, 82, -35, -24, 91, -50, -10, + 34, 72, -101, 39, 58, -93, 45, 39, -82, 54, 19, -68, + 63, -1, -53, 72, -19, -39, 82, -35, -24, 91, -49, -10, + 34, 72, -100, 39, 58, -93, 46, 39, -81, 54, 19, -68, + 63, -1, -53, 72, -18, -39, 82, -35, -24, 91, -49, -10, + 34, 72, -100, 39, 59, -92, 46, 40, -81, 54, 20, -68, + 63, 0, -53, 72, -18, -39, 82, -34, -24, 91, -48, -10, + 35, 73, -99, 40, 59, -91, 46, 41, -80, 54, 21, -67, + 63, 1, -53, 73, -17, -38, 82, -33, -24, 91, -48, -10, + 35, 73, -98, 40, 60, -91, 47, 42, -80, 55, 22, -67, + 64, 2, -52, 73, -16, -38, 82, -32, -23, 91, -47, -9, + 36, 73, -97, 40, 60, -90, 47, 42, -79, 55, 23, -66, + 64, 3, -52, 73, -15, -38, 82, -31, -23, 92, -46, -9, + 37, 74, -96, 41, 61, -89, 47, 43, -78, 55, 24, -66, + 64, 4, -51, 73, -14, -37, 83, -30, -23, 92, -45, -9, + 37, 74, -95, 42, 62, -88, 48, 45, -77, 56, 25, -65, + 64, 6, -51, 73, -12, -37, 83, -29, -22, 92, -44, -9, + 38, 75, -93, 42, 63, -87, 49, 46, -76, 56, 27, -64, + 65, 7, -50, 74, -11, -36, 83, -28, -22, 92, -43, -8, + 39, 76, -92, 43, 64, -85, 49, 47, -75, 57, 28, -63, + 65, 9, -50, 74, -9, -36, 83, -26, -22, 92, -41, -8, + 40, 76, -91, 44, 65, -84, 50, 48, -74, 57, 30, -62, + 66, 10, -49, 74, -8, -35, 84, -25, -21, 93, -40, -8, + 41, 77, -89, 45, 66, -83, 50, 50, -73, 58, 31, -62, + 66, 12, -48, 75, -6, -35, 84, -23, -21, 93, -38, -7, + 42, 78, -87, 46, 67, -81, 51, 52, -72, 58, 33, -60, + 67, 14, -47, 75, -4, -34, 84, -21, -20, 93, -36, -7, + 43, 79, -85, 46, 68, -80, 52, 53, -71, 59, 35, -59, + 67, 16, -47, 76, -2, -33, 85, -19, -20, 93, -35, -6, + 44, 80, -84, 47, 70, -78, 53, 55, -69, 60, 37, -58, + 68, 18, -46, 76, 0, -33, 85, -17, -19, 94, -33, -6, + 45, 80, -82, 48, 71, -76, 54, 56, -68, 60, 39, -57, + 68, 20, -45, 76, 2, -32, 85, -15, -18, 94, -31, -5, + 46, 82, -80, 50, 72, -74, 55, 58, -66, 61, 41, -56, + 69, 23, -44, 77, 5, -31, 86, -13, -18, 94, -29, -5, + 48, 83, -78, 51, 74, -73, 56, 60, -65, 62, 43, -55, + 70, 25, -43, 78, 7, -30, 86, -11, -17, 95, -26, -4, + 49, 84, -76, 52, 75, -71, 56, 62, -63, 63, 45, -53, + 70, 27, -41, 78, 9, -29, 87, -8, -16, 95, -24, -3, + 50, 85, -74, 53, 76, -69, 57, 63, -62, 64, 47, -52, + 71, 29, -40, 79, 12, -28, 87, -6, -15, 96, -22, -3, + 51, 86, -72, 54, 78, -67, 58, 65, -60, 64, 49, -50, + 72, 32, -39, 79, 14, -27, 88, -4, -15, 96, -20, -2, + 53, 87, -69, 55, 79, -65, 60, 67, -58, 65, 52, -49, + 72, 34, -38, 80, 17, -26, 88, -1, -14, 97, -17, -1, + 54, 88, -67, 56, 81, -63, 61, 69, -56, 66, 54, -47, + 73, 37, -37, 81, 19, -25, 89, 2, -13, 97, -15, -1, + 55, 90, -65, 58, 82, -61, 62, 71, -54, 67, 56, -46, + 74, 39, -35, 81, 22, -24, 89, 4, -12, 98, -12, 0, + 56, 91, -63, 59, 84, -59, 63, 73, -53, 68, 58, -44, + 75, 41, -34, 82, 24, -23, 90, 7, -11, 98, -10, 1, + 58, 92, -60, 60, 86, -57, 64, 75, -51, 69, 61, -42, + 76, 44, -32, 83, 27, -21, 91, 10, -10, 99, -7, 2, + 59, 94, -58, 62, 87, -55, 65, 77, -49, 70, 63, -41, + 77, 46, -31, 84, 30, -20, 91, 12, -9, 99, -4, 3, + 61, 95, -56, 63, 89, -53, 66, 78, -47, 71, 65, -39, + 78, 49, -29, 84, 32, -19, 92, 15, -8, 100, -1, 4, + 34, 74, -105, 39, 60, -97, 46, 41, -86, 54, 21, -72, + 63, 1, -58, 72, -17, -43, 82, -34, -28, 91, -48, -14, + 34, 74, -105, 39, 60, -97, 46, 41, -86, 54, 21, -72, + 63, 1, -57, 72, -17, -43, 82, -33, -28, 91, -48, -14, + 34, 74, -104, 39, 60, -97, 46, 41, -85, 54, 21, -72, + 63, 1, -57, 72, -17, -43, 82, -33, -28, 91, -48, -14, + 35, 74, -104, 39, 60, -96, 46, 42, -85, 54, 21, -72, + 63, 1, -57, 72, -16, -43, 82, -33, -28, 91, -47, -14, + 35, 74, -104, 39, 60, -96, 46, 42, -85, 54, 22, -72, + 63, 2, -57, 72, -16, -43, 82, -33, -28, 91, -47, -14, + 35, 74, -103, 40, 61, -96, 46, 42, -85, 54, 22, -71, + 63, 2, -57, 73, -15, -42, 82, -32, -28, 91, -47, -14, + 35, 74, -103, 40, 61, -95, 47, 43, -84, 55, 23, -71, + 64, 3, -57, 73, -15, -42, 82, -32, -28, 91, -46, -14, + 36, 75, -102, 40, 62, -94, 47, 44, -84, 55, 24, -71, + 64, 4, -56, 73, -14, -42, 82, -31, -27, 92, -45, -13, + 36, 75, -101, 41, 62, -94, 47, 44, -83, 55, 25, -70, + 64, 5, -56, 73, -13, -42, 82, -30, -27, 92, -45, -13, + 37, 75, -100, 41, 63, -93, 48, 45, -82, 55, 26, -70, + 64, 6, -56, 73, -12, -41, 83, -29, -27, 92, -44, -13, + 38, 76, -99, 42, 63, -92, 48, 46, -82, 56, 27, -69, + 65, 7, -55, 73, -11, -41, 83, -28, -27, 92, -43, -13, + 38, 76, -98, 42, 64, -91, 49, 47, -81, 56, 28, -69, + 65, 8, -55, 74, -10, -41, 83, -27, -26, 92, -42, -13, + 39, 77, -96, 43, 65, -90, 49, 48, -80, 57, 29, -68, + 65, 10, -54, 74, -8, -40, 83, -25, -26, 92, -40, -12, + 40, 77, -95, 44, 66, -89, 50, 50, -79, 57, 31, -67, + 66, 11, -53, 74, -7, -40, 84, -24, -25, 93, -39, -12, + 41, 78, -94, 45, 67, -87, 50, 51, -78, 58, 32, -66, + 66, 13, -53, 75, -5, -39, 84, -22, -25, 93, -38, -12, + 42, 79, -92, 45, 68, -86, 51, 52, -77, 58, 34, -65, + 66, 14, -52, 75, -4, -39, 84, -21, -25, 93, -36, -11, + 43, 80, -90, 46, 69, -84, 52, 54, -75, 59, 36, -64, + 67, 16, -51, 75, -2, -38, 84, -19, -24, 93, -34, -11, + 44, 80, -89, 47, 70, -83, 53, 55, -74, 59, 37, -63, + 67, 18, -50, 76, 0, -37, 85, -17, -23, 94, -33, -10, + 45, 81, -87, 48, 71, -81, 53, 57, -73, 60, 39, -62, + 68, 20, -49, 76, 2, -36, 85, -15, -23, 94, -31, -10, + 46, 82, -85, 49, 73, -80, 54, 58, -71, 61, 41, -61, + 69, 22, -48, 77, 4, -36, 86, -13, -22, 94, -29, -9, + 47, 83, -83, 50, 74, -78, 55, 60, -70, 62, 43, -60, + 69, 25, -47, 77, 7, -35, 86, -11, -21, 95, -27, -9, + 48, 84, -81, 51, 75, -76, 56, 62, -68, 62, 45, -58, + 70, 27, -46, 78, 9, -34, 86, -9, -21, 95, -25, -8, + 49, 85, -79, 52, 77, -74, 57, 63, -67, 63, 47, -57, + 71, 29, -45, 78, 11, -33, 87, -6, -20, 95, -23, -7, + 51, 86, -77, 53, 78, -73, 58, 65, -65, 64, 49, -56, + 71, 31, -44, 79, 13, -32, 87, -4, -19, 96, -20, -7, + 52, 87, -75, 54, 79, -71, 59, 67, -64, 65, 51, -54, + 72, 33, -43, 80, 16, -31, 88, -2, -18, 96, -18, -6, + 53, 89, -73, 56, 81, -69, 60, 69, -62, 66, 53, -53, + 73, 36, -42, 80, 18, -30, 89, 1, -17, 97, -15, -5, + 54, 90, -71, 57, 82, -67, 61, 71, -60, 67, 56, -51, + 74, 38, -40, 81, 21, -29, 89, 3, -17, 97, -13, -4, + 56, 91, -69, 58, 84, -65, 62, 72, -58, 68, 58, -50, + 74, 41, -39, 82, 23, -28, 90, 6, -16, 98, -11, -4, + 57, 92, -66, 59, 85, -63, 63, 74, -56, 69, 60, -48, + 75, 43, -38, 82, 26, -27, 90, 8, -15, 98, -8, -3, + 58, 94, -64, 61, 87, -60, 64, 76, -54, 70, 62, -46, + 76, 46, -36, 83, 29, -25, 91, 11, -14, 99, -5, -2, + 60, 95, -62, 62, 88, -58, 66, 78, -52, 71, 64, -45, + 77, 48, -35, 84, 31, -24, 92, 14, -13, 99, -3, -1, + 61, 96, -60, 63, 90, -56, 67, 80, -51, 72, 66, -43, + 78, 50, -33, 85, 34, -23, 92, 16, -11, 100, 0, 0 +}; diff --git a/src/openmv/src/omv/img/lbp.c b/src/openmv/src/omv/img/lbp.c new file mode 100755 index 0000000..db5f326 --- /dev/null +++ b/src/openmv/src/omv/img/lbp.c @@ -0,0 +1,118 @@ +/* +* This file is part of the OpenMV project. +* Copyright (c) 2013/2014 Ibrahim Abdelkader +* This work is licensed under the MIT license, see the file LICENSE for details. +* +* LBPu2â„8,2 Operator. +* Note: The distance function uses weights optimized for face recognition. +* Note: See Timo Ahonen's "Face Recognition with Local Binary Patterns" +* +*/ + +#include +#include +#include + +#include "imlib.h" +#include "xalloc.h" +#include "ff.h" + +#define LBP_HIST_SIZE (59) //58 uniform hist + 1 +#define LBP_NUM_REGIONS (7) //7x7 regions +#define LBP_DESC_SIZE (LBP_NUM_REGIONS*LBP_NUM_REGIONS*LBP_HIST_SIZE) + +const static int8_t lbp_weights [49]= { + 2, 1, 1, 1, 1, 1, 2, + 2, 4, 4, 1, 4, 4, 2, + 1, 1, 1, 0, 1, 1, 1, + 0, 1, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 2, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, +}; + +const static uint8_t uniform_tbl[256] = { + 0, 1, 2, 3, 4, 58, 5, 6, 7, 58, 58, 58, 8, 58, 9, 10, + 11, 58, 58, 58, 58, 58, 58, 58, 12, 58, 58, 58, 13, 58, 14, 15, + 16, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 17, 58, 58, 58, 58, 58, 58, 58, 18, 58, 58, 58, 19, 58, 20, 21, + 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 23, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 24, 58, 58, 58, 58, 58, 58, 58, 25, 58, 58, 58, 26, 58, 27, 28, + 29, 30, 58, 31, 58, 58, 58, 32, 58, 58, 58, 58, 58, 58, 58, 33, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 34, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 35, + 36, 37, 58, 38, 58, 58, 58, 39, 58, 58, 58, 58, 58, 58, 58, 40, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 41, + 42, 43, 58, 44, 58, 58, 58, 45, 58, 58, 58, 58, 58, 58, 58, 46, + 47, 48, 58, 49, 58, 58, 58, 50, 51, 52, 58, 53, 54, 55, 56, 57 +}; + +uint8_t *imlib_lbp_desc(image_t *image, rectangle_t *roi) +{ + int s = image->w; //stride + int RY = roi->h/LBP_NUM_REGIONS; + int RX = roi->w/LBP_NUM_REGIONS; + uint8_t *data = image->data; + uint8_t *desc = xalloc0(LBP_DESC_SIZE); + + for (int y=roi->y; y<(roi->y+image->h)-3; y++) { + int y_idx = (y-roi->y)/RY*LBP_NUM_REGIONS; + for (int x=roi->x; x<(roi->x+image->w)-3; x++) { + uint8_t lbp=0; + uint8_t p = data[(y+1)*s+x+1]; + int hist_idx = y_idx+(x-roi->x)/RX; + + lbp |= (data[(y+0)*s+x+0] >= p) << 0; + lbp |= (data[(y+0)*s+x+1] >= p) << 1; + lbp |= (data[(y+0)*s+x+2] >= p) << 2; + lbp |= (data[(y+1)*s+x+2] >= p) << 3; + lbp |= (data[(y+2)*s+x+2] >= p) << 4; + lbp |= (data[(y+2)*s+x+1] >= p) << 5; + lbp |= (data[(y+2)*s+x+0] >= p) << 6; + lbp |= (data[(y+1)*s+x+0] >= p) << 7; + + desc[hist_idx*LBP_HIST_SIZE+uniform_tbl[lbp]]++; + } + } + return desc; +} + +int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1) +{ + uint32_t sum = 0; + for (int i=0; i & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Line functions. + */ +static void pixel_magnitude(image_t *ptr, int x, int y, int *theta, uint32_t *mag) +{ + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + int pixel; // Sobel Algorithm Below + int x_acc = 0; + int y_acc = 0; + + if (y != 0) row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + if (y != 0) row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + if (y != (ptr->h - 1)) row_ptr += ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + if (y != (ptr->h - 1)) row_ptr -= ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT); + + *theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (*theta < 0) *theta += 180; + *mag = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + int pixel; // Sobel Algorithm Below... w/ Scharr... + int x_acc = 0; + int y_acc = 0; + + if (y != 0) row_ptr -= ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0)); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1)); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + if (y != 0) row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0)); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1)); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + if (y != (ptr->h - 1)) row_ptr += ptr->w; + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0)); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1)); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + if (y != (ptr->h - 1)) row_ptr -= ptr->w; + + *theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (*theta < 0) *theta += 180; + *mag = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + int pixel; // Sobel Algorithm Below... w/ Scharr... + int x_acc = 0; + int y_acc = 0; + + if (y != 0) row_ptr -= ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +1; // x[0,0] -> pixel * +1 + y_acc += pixel * +1; // y[0,0] -> pixel * +1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[0,1] -> pixel * 0 + y_acc += pixel * +2; // y[0,1] -> pixel * +2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -1; // x[0,2] -> pixel * -1 + y_acc += pixel * +1; // y[0,2] -> pixel * +1 + + if (y != 0) row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +2; // x[1,0] -> pixel * +2 + // y[1,0] -> pixel * 0 + + // pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[1,1] -> pixel * 0 + // y[1,1] -> pixel * 0 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -2; // x[1,2] -> pixel * -2 + // y[1,2] -> pixel * 0 + + if (y != (ptr->h - 1)) row_ptr += ptr->w; + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MAX(x - 1, 0))); + x_acc += pixel * +1; // x[2,0] -> pixel * +1 + y_acc += pixel * -1; // y[2,0] -> pixel * -1 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + // x[2,1] -> pixel * 0 + y_acc += pixel * -2; // y[2,1] -> pixel * -2 + + pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, IM_MIN(x + 1, ptr->w - 1))); + x_acc += pixel * -1; // x[2,2] -> pixel * -1 + y_acc += pixel * -1; // y[2,2] -> pixel * -1 + + if (y != (ptr->h - 1)) row_ptr -= ptr->w; + + *theta = fast_roundf((x_acc ? fast_atan2f(y_acc, x_acc) : 1.570796f) * 57.295780) % 180; // * (180 / PI) + if (*theta < 0) *theta += 180; + *mag = fast_roundf(fast_sqrtf((x_acc * x_acc) + (y_acc * y_acc))); + break; + } + default: { + break; + } + } +} + +// http://www.brackeen.com/vga/source/djgpp20/lines.c.html +// http://www.brackeen.com/vga/source/bc31/lines.c.html +static bool merge_line(line_t *big, line_t *small, unsigned int threshold) +{ + int dx = big->x2 - big->x1; // the horizontal distance of the line + int dy = big->y2 - big->y1; // the vertical distance of the line + int dxabs = abs(dx); + int dyabs = abs(dy); + int sdx = (dx < 0) ? -1 :((dx > 0) ? 1 : 0); + int sdy = (dy < 0) ? -1 :((dy > 0) ? 1 : 0); + int x = dyabs >> 1; // correct + int y = dxabs >> 1; // correct + int px = big->x1; + int py = big->y1; + + int x_diff_0 = (px - small->x1); + int y_diff_0 = (py - small->y1); + if (fast_roundf(fast_sqrtf((x_diff_0 * x_diff_0) + (y_diff_0 * y_diff_0))) <= threshold) return true; + int x_diff_1 = (px - small->x2); + int y_diff_1 = (py - small->y2); + if (fast_roundf(fast_sqrtf((x_diff_1 * x_diff_1) + (y_diff_1 * y_diff_1))) <= threshold) return true; + + if (dxabs >= dyabs) { // the line is more horizontal than vertical + for(int i = 0; i < dxabs; i++) { + y += dyabs; + + if (y >= dxabs) { + y -= dxabs; + py += sdy; + } + + px += sdx; + + x_diff_0 = (px - small->x1); + y_diff_0 = (py - small->y1); + if (fast_roundf(fast_sqrtf((x_diff_0 * x_diff_0) + (y_diff_0 * y_diff_0))) <= threshold) return true; + x_diff_1 = (px - small->x2); + y_diff_1 = (py - small->y2); + if (fast_roundf(fast_sqrtf((x_diff_1 * x_diff_1) + (y_diff_1 * y_diff_1))) <= threshold) return true; + } + } else { // the line is more vertical than horizontal + for(int i = 0; i < dyabs; i++) { + x += dxabs; + + if (x >= dyabs) { + x -= dyabs; + px += sdx; + } + + py += sdy; + + x_diff_0 = (px - small->x1); + y_diff_0 = (py - small->y1); + if (fast_roundf(fast_sqrtf((x_diff_0 * x_diff_0) + (y_diff_0 * y_diff_0))) <= threshold) return true; + x_diff_1 = (px - small->x2); + y_diff_1 = (py - small->y2); + if (fast_roundf(fast_sqrtf((x_diff_1 * x_diff_1) + (y_diff_1 * y_diff_1))) <= threshold) return true; + } + } + + return false; +} + +void merge_alot(list_t *out, int threshold, int theta_threshold) +{ + for (;;) { + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(find_lines_list_lnk_data_t)); + + while (list_size(out)) { + find_lines_list_lnk_data_t lnk_line; + list_pop_front(out, &lnk_line); + + for (size_t k = 0, l = list_size(out); k < l; k++) { + find_lines_list_lnk_data_t tmp_line; + list_pop_front(out, &tmp_line); + + int x_diff_0 = (lnk_line.line.x2 - lnk_line.line.x1); + int y_diff_0 = (lnk_line.line.y2 - lnk_line.line.y1); + int length_0 = fast_roundf(fast_sqrtf((x_diff_0 * x_diff_0) + (y_diff_0 * y_diff_0))); + + int x_diff_1 = (tmp_line.line.x2 - tmp_line.line.x1); + int y_diff_1 = (tmp_line.line.y2 - tmp_line.line.y1); + int length_1 = fast_roundf(fast_sqrtf((x_diff_1 * x_diff_1) + (y_diff_1 * y_diff_1))); + + int theta_diff = abs(lnk_line.theta - tmp_line.theta); + int theta_diff_2 = (theta_diff >= 90) ? (180 - theta_diff) : theta_diff; + + if ((theta_diff_2 <= theta_threshold) && merge_line((length_0 > length_1) ? + &lnk_line.line : &tmp_line.line, (length_0 <= length_1) ? &lnk_line.line : &tmp_line.line, threshold)) { + + if (abs(x_diff_0) >= abs(y_diff_0)) { // the line is more horizontal than vertical + if (x_diff_0 < 0) { // Make sure x slope is positive for the next part. + int temp_x = lnk_line.line.x1; + lnk_line.line.x1 = lnk_line.line.x2; + lnk_line.line.x2 = temp_x; + int temp_y = lnk_line.line.y1; + lnk_line.line.y1 = lnk_line.line.y2; + lnk_line.line.y2 = temp_y; + x_diff_0 = (lnk_line.line.x2 - lnk_line.line.x1); + y_diff_0 = (lnk_line.line.y2 - lnk_line.line.y1); + } + + if (x_diff_1 < 0) { // Make sure x slope is positive for the next part. + int temp_x = tmp_line.line.x1; + tmp_line.line.x1 = tmp_line.line.x2; + tmp_line.line.x2 = temp_x; + int temp_y = tmp_line.line.y1; + tmp_line.line.y1 = tmp_line.line.y2; + tmp_line.line.y2 = temp_y; + x_diff_1 = (tmp_line.line.x2 - tmp_line.line.x1); + y_diff_1 = (tmp_line.line.y2 - tmp_line.line.y1); + } + + if (length_0 > length_1) { + int x_min = IM_MIN(lnk_line.line.x1, tmp_line.line.x1); + int x_max = IM_MAX(lnk_line.line.x2, tmp_line.line.x2); + lnk_line.line.y1 = lnk_line.line.y1 - ((y_diff_0 * (lnk_line.line.x1 - x_min)) / x_diff_0); + lnk_line.line.x1 = x_min; + lnk_line.line.y2 = lnk_line.line.y2 + ((y_diff_0 * (x_max - lnk_line.line.x2)) / x_diff_0); + lnk_line.line.x2 = x_max; + } else { + int x_min = IM_MIN(tmp_line.line.x1, lnk_line.line.x1); + int x_max = IM_MAX(tmp_line.line.x2, lnk_line.line.x2); + lnk_line.line.y1 = tmp_line.line.y1 - ((y_diff_0 * (tmp_line.line.x1 - x_min)) / x_diff_0); + lnk_line.line.x1 = x_min; + lnk_line.line.y2 = tmp_line.line.y2 + ((y_diff_0 * (x_max - tmp_line.line.x2)) / x_diff_0); + lnk_line.line.x2 = x_max; + } + } else { // the line is more vertical than horizontal + if (y_diff_0 < 0) { // Make sure y slope is positive for the next part. + int temp_x = lnk_line.line.x1; + lnk_line.line.x1 = lnk_line.line.x2; + lnk_line.line.x2 = temp_x; + int temp_y = lnk_line.line.y1; + lnk_line.line.y1 = lnk_line.line.y2; + lnk_line.line.y2 = temp_y; + x_diff_0 = (lnk_line.line.x2 - lnk_line.line.x1); + y_diff_0 = (lnk_line.line.y2 - lnk_line.line.y1); + } + + if (y_diff_1 < 0) { // Make sure y slope is positive for the next part. + int temp_x = tmp_line.line.x1; + tmp_line.line.x1 = tmp_line.line.x2; + tmp_line.line.x2 = temp_x; + int temp_y = tmp_line.line.y1; + tmp_line.line.y1 = tmp_line.line.y2; + tmp_line.line.y2 = temp_y; + x_diff_1 = (tmp_line.line.x2 - tmp_line.line.x1); + y_diff_1 = (tmp_line.line.y2 - tmp_line.line.y1); + } + + if (length_0 > length_1) { + int y_min = IM_MIN(lnk_line.line.y1, tmp_line.line.y1); + int y_max = IM_MAX(lnk_line.line.y2, tmp_line.line.y2); + lnk_line.line.x1 = lnk_line.line.x1 - ((x_diff_0 * (lnk_line.line.y1 - y_min)) / y_diff_0); + lnk_line.line.y1 = y_min; + lnk_line.line.x2 = lnk_line.line.x2 + ((x_diff_0 * (y_max - lnk_line.line.y2)) / y_diff_0); + lnk_line.line.y2 = y_max; + } else { + int y_min = IM_MIN(tmp_line.line.y1, lnk_line.line.y1); + int y_max = IM_MAX(tmp_line.line.y2, lnk_line.line.y2); + lnk_line.line.x1 = tmp_line.line.x1 - ((x_diff_0 * (tmp_line.line.y1 - y_min)) / y_diff_0); + lnk_line.line.y1 = y_min; + lnk_line.line.x2 = tmp_line.line.x2 + ((x_diff_0 * (y_max - tmp_line.line.y2)) / y_diff_0); + lnk_line.line.y2 = y_max; + } + } + + merge_occured = true; + } else { + list_push_back(out, &tmp_line); + } + } + + list_push_back(&out_temp, &lnk_line); + } + + list_copy(out, &out_temp); + + if (!merge_occured) { + break; + } + } +} + +// http://www.brackeen.com/vga/source/djgpp20/lines.c.html +// http://www.brackeen.com/vga/source/bc31/lines.c.html +size_t trace_line(image_t *ptr, line_t *l, int *theta_buffer, uint32_t *mag_buffer, point_t *point_buffer) +{ + int dx = l->x2 - l->x1; // the horizontal distance of the line + int dy = l->y2 - l->y1; // the vertical distance of the line + int dxabs = abs(dx); + int dyabs = abs(dy); + int sdx = (dx < 0) ? -1 :((dx > 0) ? 1 : 0); + int sdy = (dy < 0) ? -1 :((dy > 0) ? 1 : 0); + int x = dyabs >> 1; // correct + int y = dxabs >> 1; // correct + int px = l->x1; + int py = l->y1; + + size_t index = 0; + + pixel_magnitude(ptr, px, py, theta_buffer + index, mag_buffer + index); + point_buffer[index++] = (point_t) {.x = px, .y = py}; + + if (dxabs >= dyabs) { // the line is more horizontal than vertical + for(int i = 0; i < dxabs; i++) { + y += dyabs; + + if (y >= dxabs) { + y -= dxabs; + py += sdy; + } + + px += sdx; + + pixel_magnitude(ptr, px, py, theta_buffer + index, mag_buffer + index); + point_buffer[index++] = (point_t) {.x = px, .y = py}; + } + } else { // the line is more vertical than horizontal + for(int i = 0; i < dyabs; i++) { + x += dxabs; + + if (x >= dyabs) { + x -= dyabs; + px += sdx; + } + + py += sdy; + + pixel_magnitude(ptr, px, py, theta_buffer + index, mag_buffer + index); + point_buffer[index++] = (point_t) {.x = px, .y = py}; + } + } + + return index; +} diff --git a/src/openmv/src/omv/img/lsd.c b/src/openmv/src/omv/img/lsd.c new file mode 100755 index 0000000..e75f183 --- /dev/null +++ b/src/openmv/src/omv/img/lsd.c @@ -0,0 +1,2713 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include +#include "imlib.h" + +#define PI 3.14159265358979f + +#ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define error(msg) fb_alloc_fail() +#define free(ptr) ({ umm_free(ptr); }) +#define malloc(size) ({ void *_r = umm_malloc(size); if(!_r) fb_alloc_fail(); _r; }) +#define realloc(ptr, size) ({ void *_r = umm_realloc((ptr), (size)); if(!_r) fb_alloc_fail(); _r; }) +#define calloc(num, item_size) ({ void *_r = umm_calloc((num), (item_size)); if(!_r) fb_alloc_fail(); _r; }) +#define double float +#undef DBL_MIN +#define DBL_MIN FLT_MIN +#undef DBL_MAX +#define DBL_MAX FLT_MAX +#undef DBL_EPSILON +#define DBL_EPSILON FLT_EPSILON +#define sqrt(x) fast_sqrtf(x) +#define floor(x) fast_floorf(x) +#define ceil(x) fast_ceilf(x) +#define round(x) fast_roundf(x) +#define atan(x) fast_atanf(x) +#define atan2(y, x) fast_atan2f((y), (x)) +#define exp(x) fast_expf(x) +#define fabs(x) fast_fabsf(x) +#define log(x) fast_log(x) +#define log10(x) log10f(x) +#define cos(x) cosf(x) +#define sin(x) sinf(x) +#define pow(x,y) powf((x),(y)) +#define sinh(x) sinhf(x) +#define radToDeg(x) ((x) * (180.0 / PI)) +#define degToRad(x) ((x) * (PI / 180.0)) + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "lsd.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*---------------------------------------------------------------------------- + + LSD - Line Segment Detector on digital images + + This code is part of the following publication and was subject + to peer review: + + "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, + Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, + Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd + http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd + + Copyright (c) 2007-2011 rafael grompone von gioi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + ----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** @file lsd.h + LSD module header + @author rafael grompone von gioi + */ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** LSD Full Interface + + @param n_out Pointer to an int where LSD will store the number of + line segments detected. + + @param img Pointer to input image data. It must be an array of + unsigned chars of size X x Y, and the pixel at coordinates + (x,y) is obtained by img[x+y*X]. + + @param X X size of the image: the number of columns. + + @param Y Y size of the image: the number of rows. + + @param scale When different from 1.0, LSD will scale the input image + by 'scale' factor by Gaussian filtering, before detecting + line segments. + Example: if scale=0.8, the input image will be subsampled + to 80% of its size, before the line segment detector + is applied. + Suggested value: 0.8 + + @param sigma_scale When scale!=1.0, the sigma of the Gaussian filter is: + sigma = sigma_scale / scale, if scale < 1.0 + sigma = sigma_scale, if scale >= 1.0 + Suggested value: 0.6 + + @param quant Bound to the quantization error on the gradient norm. + Example: if gray levels are quantized to integer steps, + the gradient (computed by finite differences) error + due to quantization will be bounded by 2.0, as the + worst case is when the error are 1 and -1, that + gives an error of 2.0. + Suggested value: 2.0 + + @param ang_th Gradient angle tolerance in the region growing + algorithm, in degrees. + Suggested value: 22.5 + + @param log_eps Detection threshold, accept if -log10(NFA) > log_eps. + The larger the value, the more strict the detector is, + and will result in less detections. + (Note that the 'minus sign' makes that this + behavior is opposite to the one of NFA.) + The value -log10(NFA) is equivalent but more + intuitive than NFA: + - -1.0 gives an average of 10 false detections on noise + - 0.0 gives an average of 1 false detections on noise + - 1.0 gives an average of 0.1 false detections on nose + - 2.0 gives an average of 0.01 false detections on noise + . + Suggested value: 0.0 + + @param density_th Minimal proportion of 'supporting' points in a rectangle. + Suggested value: 0.7 + + @param n_bins Number of bins used in the pseudo-ordering of gradient + modulus. + Suggested value: 1024 + + @param reg_img Optional output: if desired, LSD will return an + int image where each pixel indicates the line segment + to which it belongs. Unused pixels have the value '0', + while the used ones have the number of the line segment, + numbered 1,2,3,..., in the same order as in the + output list. If desired, a non NULL int** pointer must + be assigned, and LSD will make that the pointer point + to an int array of size reg_x x reg_y, where the pixel + value at (x,y) is obtained with (*reg_img)[x+y*reg_x]. + Note that the resulting image has the size of the image + used for the processing, that is, the size of the input + image scaled by the given factor 'scale'. If scale!=1 + this size differs from XxY and that is the reason why + its value is given by reg_x and reg_y. + Suggested value: NULL + + @param reg_x Pointer to an int where LSD will put the X size + 'reg_img' image, when asked for. + Suggested value: NULL + + @param reg_y Pointer to an int where LSD will put the Y size + 'reg_img' image, when asked for. + Suggested value: NULL + + @return A double array of size 7 x n_out, containing the list + of line segments detected. The array contains first + 7 values of line segment number 1, then the 7 values + of line segment number 2, and so on, and it finish + by the 7 values of line segment number n_out. + The seven values are: + - x1,y1,x2,y2,width,p,-log10(NFA) + . + for a line segment from coordinates (x1,y1) to (x2,y2), + a width 'width', an angle precision of p in (0,1) given + by angle_tolerance/180 degree, and NFA value 'NFA'. + If 'out' is the returned pointer, the 7 values of + line segment number 'n+1' are obtained with + 'out[7*n+0]' to 'out[7*n+6]'. + */ +double * LineSegmentDetection( int * n_out, + unsigned char * img, int X, int Y, + double scale, double sigma_scale, double quant, + double ang_th, double log_eps, double density_th, + int n_bins, + int ** reg_img, int * reg_x, int * reg_y ); + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale and Region output. + + @param n_out Pointer to an int where LSD will store the number of + line segments detected. + + @param img Pointer to input image data. It must be an array of + unsigned chars of size X x Y, and the pixel at coordinates + (x,y) is obtained by img[x+y*X]. + + @param X X size of the image: the number of columns. + + @param Y Y size of the image: the number of rows. + + @param scale When different from 1.0, LSD will scale the input image + by 'scale' factor by Gaussian filtering, before detecting + line segments. + Example: if scale=0.8, the input image will be subsampled + to 80% of its size, before the line segment detector + is applied. + Suggested value: 0.8 + + @param reg_img Optional output: if desired, LSD will return an + int image where each pixel indicates the line segment + to which it belongs. Unused pixels have the value '0', + while the used ones have the number of the line segment, + numbered 1,2,3,..., in the same order as in the + output list. If desired, a non NULL int** pointer must + be assigned, and LSD will make that the pointer point + to an int array of size reg_x x reg_y, where the pixel + value at (x,y) is obtained with (*reg_img)[x+y*reg_x]. + Note that the resulting image has the size of the image + used for the processing, that is, the size of the input + image scaled by the given factor 'scale'. If scale!=1 + this size differs from XxY and that is the reason why + its value is given by reg_x and reg_y. + Suggested value: NULL + + @param reg_x Pointer to an int where LSD will put the X size + 'reg_img' image, when asked for. + Suggested value: NULL + + @param reg_y Pointer to an int where LSD will put the Y size + 'reg_img' image, when asked for. + Suggested value: NULL + + @return A double array of size 7 x n_out, containing the list + of line segments detected. The array contains first + 7 values of line segment number 1, then the 7 values + of line segment number 2, and so on, and it finish + by the 7 values of line segment number n_out. + The seven values are: + - x1,y1,x2,y2,width,p,-log10(NFA) + . + for a line segment from coordinates (x1,y1) to (x2,y2), + a width 'width', an angle precision of p in (0,1) given + by angle_tolerance/180 degree, and NFA value 'NFA'. + If 'out' is the returned pointer, the 7 values of + line segment number 'n+1' are obtained with + 'out[7*n+0]' to 'out[7*n+6]'. + */ +double * lsd_scale_region( int * n_out, + unsigned char * img, int X, int Y, double scale, + int ** reg_img, int * reg_x, int * reg_y ); + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale + + @param n_out Pointer to an int where LSD will store the number of + line segments detected. + + @param img Pointer to input image data. It must be an array of + unsigned chars of size X x Y, and the pixel at coordinates + (x,y) is obtained by img[x+y*X]. + + @param X X size of the image: the number of columns. + + @param Y Y size of the image: the number of rows. + + @param scale When different from 1.0, LSD will scale the input image + by 'scale' factor by Gaussian filtering, before detecting + line segments. + Example: if scale=0.8, the input image will be subsampled + to 80% of its size, before the line segment detector + is applied. + Suggested value: 0.8 + + @return A double array of size 7 x n_out, containing the list + of line segments detected. The array contains first + 7 values of line segment number 1, then the 7 values + of line segment number 2, and so on, and it finish + by the 7 values of line segment number n_out. + The seven values are: + - x1,y1,x2,y2,width,p,-log10(NFA) + . + for a line segment from coordinates (x1,y1) to (x2,y2), + a width 'width', an angle precision of p in (0,1) given + by angle_tolerance/180 degree, and NFA value 'NFA'. + If 'out' is the returned pointer, the 7 values of + line segment number 'n+1' are obtained with + 'out[7*n+0]' to 'out[7*n+6]'. + */ +double * lsd_scale(int * n_out, unsigned char * img, int X, int Y, double scale); + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface + + @param n_out Pointer to an int where LSD will store the number of + line segments detected. + + @param img Pointer to input image data. It must be an array of + unsigned chars of size X x Y, and the pixel at coordinates + (x,y) is obtained by img[x+y*X]. + + @param X X size of the image: the number of columns. + + @param Y Y size of the image: the number of rows. + + @return A double array of size 7 x n_out, containing the list + of line segments detected. The array contains first + 7 values of line segment number 1, then the 7 values + of line segment number 2, and so on, and it finish + by the 7 values of line segment number n_out. + The seven values are: + - x1,y1,x2,y2,width,p,-log10(NFA) + . + for a line segment from coordinates (x1,y1) to (x2,y2), + a width 'width', an angle precision of p in (0,1) given + by angle_tolerance/180 degree, and NFA value 'NFA'. + If 'out' is the returned pointer, the 7 values of + line segment number 'n+1' are obtained with + 'out[7*n+0]' to 'out[7*n+6]'. + */ +double * lsd(int * n_out, unsigned char * img, int X, int Y); + +/*----------------------------------------------------------------------------*/ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "lsd.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*---------------------------------------------------------------------------- + + LSD - Line Segment Detector on digital images + + This code is part of the following publication and was subject + to peer review: + + "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, + Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, + Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd + http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd + + Copyright (c) 2007-2011 rafael grompone von gioi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + ----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** @file lsd.c + LSD module code + @author rafael grompone von gioi + */ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** @mainpage LSD code documentation + + This is an implementation of the Line Segment Detector described + in the paper: + + "LSD: A Fast Line Segment Detector with a False Detection Control" + by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, + and Gregory Randall, IEEE Transactions on Pattern Analysis and + Machine Intelligence, vol. 32, no. 4, pp. 722-732, April, 2010. + + and in more details in the CMLA Technical Report: + + "LSD: A Line Segment Detector, Technical Report", + by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, + Gregory Randall, CMLA, ENS Cachan, 2010. + + The version implemented here includes some further improvements + described in the following publication, of which this code is part: + + "LSD: a Line Segment Detector" by Rafael Grompone von Gioi, + Jeremie Jakubowicz, Jean-Michel Morel, and Gregory Randall, + Image Processing On Line, 2012. DOI:10.5201/ipol.2012.gjmr-lsd + http://dx.doi.org/10.5201/ipol.2012.gjmr-lsd + + The module's main function is lsd(). + + The source code is contained in two files: lsd.h and lsd.c. + + HISTORY: + - version 1.6 - nov 2011: + - changes in the interface, + - max_grad parameter removed, + - the factor 11 was added to the number of test + to consider the different precision values + tested, + - a minor bug corrected in the gradient sorting + code, + - the algorithm now also returns p and log_nfa + for each detection, + - a minor bug was corrected in the image scaling, + - the angle comparison in "isaligned" changed + from < to <=, + - "eps" variable renamed "log_eps", + - "lsd_scale_region" interface was added, + - minor changes to comments. + - version 1.5 - dec 2010: Changes in 'refine', -W option added, + and more comments added. + - version 1.4 - jul 2010: lsd_scale interface added and doxygen doc. + - version 1.3 - feb 2010: Multiple bug correction and improved code. + - version 1.2 - dec 2009: First full Ansi C Language version. + - version 1.1 - sep 2009: Systematic subsampling to scale 0.8 and + correction to partially handle "angle problem". + - version 1.0 - jan 2009: First complete Megawave2 and Ansi C Language + version. + + @author rafael grompone von gioi + */ +/*----------------------------------------------------------------------------*/ + +/** ln(10) */ +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif /* !M_LN10 */ + +/** PI */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* !M_PI */ + +#ifndef FALSE +#define FALSE 0 +#endif /* !FALSE */ + +#ifndef TRUE +#define TRUE 1 +#endif /* !TRUE */ + +/** Label for pixels with undefined gradient. */ +#define NOTDEF -512.0 // -1024.0 + +/** 3/2 pi */ +#define M_3_2_PI 4.71238898038 + +/** 2 pi */ +#define M_2__PI 6.28318530718 + +/** Label for pixels not used in yet. */ +#define NOTUSED 0 + +/** Label for pixels already used in detection. */ +#define USED 1 + +/*----------------------------------------------------------------------------*/ +/** Chained list of coordinates. + */ +struct coorlist +{ + int16_t x,y; + struct coorlist * next; +}; + +/*----------------------------------------------------------------------------*/ +/** A point (or pixel). + */ +struct lsd_point {int16_t x,y;}; + + +/*----------------------------------------------------------------------------*/ +/*------------------------- Miscellaneous functions --------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Fatal error, print a message to standard-error output and exit. + */ +//static void error(char * msg) +//{ +// fprintf(stderr,"LSD Error: %s\n",msg); +// exit(EXIT_FAILURE); +//} + +/*----------------------------------------------------------------------------*/ +/** Doubles relative error factor + */ +#define RELATIVE_ERROR_FACTOR 100.0 + +/*----------------------------------------------------------------------------*/ +/** Compare doubles by relative error. + + The resulting rounding error after floating point computations + depend on the specific operations done. The same number computed by + different algorithms could present different rounding errors. For a + useful comparison, an estimation of the relative rounding error + should be considered and compared to a factor times EPS. The factor + should be related to the cumulated rounding error in the chain of + computation. Here, as a simplification, a fixed factor is used. + */ +static int double_equal(double a, double b) +{ + double abs_diff,aa,bb,abs_max; + + /* trivial case */ + if( a == b ) return TRUE; + + abs_diff = fabs(a-b); + aa = fabs(a); + bb = fabs(b); + abs_max = aa > bb ? aa : bb; + + /* DBL_MIN is the smallest normalized number, thus, the smallest + number whose relative error is bounded by DBL_EPSILON. For + smaller numbers, the same quantization steps as for DBL_MIN + are used. Then, for smaller numbers, a meaningful "relative" + error should be computed by dividing the difference by DBL_MIN. */ + if( abs_max < DBL_MIN ) abs_max = DBL_MIN; + + /* equal if relative error <= factor x eps */ + return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); +} + +/*----------------------------------------------------------------------------*/ +/** Computes Euclidean distance between point (x1,y1) and point (x2,y2). + */ +static double dist(double x1, double y1, double x2, double y2) +{ + return sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------- 'list of n-tuple' data type ------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** 'list of n-tuple' data type + + The i-th component of the j-th n-tuple of an n-tuple list 'ntl' + is accessed with: + + ntl->values[ i + j * ntl->dim ] + + The dimension of the n-tuple (n) is: + + ntl->dim + + The number of n-tuples in the list is: + + ntl->size + + The maximum number of n-tuples that can be stored in the + list with the allocated memory at a given time is given by: + + ntl->max_size + */ +typedef struct ntuple_list_s +{ + unsigned int size; + unsigned int max_size; + unsigned int dim; + double * values; +} * ntuple_list; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in n-tuple 'in'. + */ +static void free_ntuple_list(ntuple_list in) +{ + if( in == NULL || in->values == NULL ) + error("free_ntuple_list: invalid n-tuple input."); + free( (void *) in->values ); + free( (void *) in ); +} + +/*----------------------------------------------------------------------------*/ +/** Create an n-tuple list and allocate memory for one element. + @param dim the dimension (n) of the n-tuple. + */ +static ntuple_list new_ntuple_list(unsigned int dim) +{ + ntuple_list n_tuple; + + /* check parameters */ + if( dim == 0 ) error("new_ntuple_list: 'dim' must be positive."); + + /* get memory for list structure */ + n_tuple = (ntuple_list) malloc( sizeof(struct ntuple_list_s) ); + if( n_tuple == NULL ) error("not enough memory."); + + /* initialize list */ + n_tuple->size = 0; + n_tuple->max_size = 1; + n_tuple->dim = dim; + + /* get memory for tuples */ + n_tuple->values = (double *) malloc( dim*n_tuple->max_size * sizeof(double) ); + if( n_tuple->values == NULL ) error("not enough memory."); + + return n_tuple; +} + +/*----------------------------------------------------------------------------*/ +/** Enlarge the allocated memory of an n-tuple list. + */ +static void enlarge_ntuple_list(ntuple_list n_tuple) +{ + /* check parameters */ + if( n_tuple == NULL || n_tuple->values == NULL || n_tuple->max_size == 0 ) + error("enlarge_ntuple_list: invalid n-tuple."); + + /* duplicate number of tuples */ + n_tuple->max_size *= 2; + + /* realloc memory */ + n_tuple->values = (double *) realloc( (void *) n_tuple->values, + n_tuple->dim * n_tuple->max_size * sizeof(double) ); + if( n_tuple->values == NULL ) error("not enough memory."); +} + +/*----------------------------------------------------------------------------*/ +/** Add a 7-tuple to an n-tuple list. + */ +static void add_7tuple( ntuple_list out, double v1, double v2, double v3, + double v4, double v5, double v6, double v7 ) +{ + /* check parameters */ + if( out == NULL ) error("add_7tuple: invalid n-tuple input."); + if( out->dim != 7 ) error("add_7tuple: the n-tuple must be a 7-tuple."); + + /* if needed, alloc more tuples to 'out' */ + if( out->size == out->max_size ) enlarge_ntuple_list(out); + if( out->values == NULL ) error("add_7tuple: invalid n-tuple input."); + + /* add new 7-tuple */ + out->values[ out->size * out->dim + 0 ] = v1; + out->values[ out->size * out->dim + 1 ] = v2; + out->values[ out->size * out->dim + 2 ] = v3; + out->values[ out->size * out->dim + 3 ] = v4; + out->values[ out->size * out->dim + 4 ] = v5; + out->values[ out->size * out->dim + 5 ] = v6; + out->values[ out->size * out->dim + 6 ] = v7; + + /* update number of tuples counter */ + out->size++; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- Image Data Types -----------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** char image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_char_s +{ + unsigned char * data; + unsigned int xsize,ysize; +} * image_char; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in image_char 'i'. + */ +static void free_image_char(image_char i) +{ + if( i == NULL || i->data == NULL ) + error("free_image_char: invalid input image."); + free( (void *) i->data ); + free( (void *) i ); +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_char of size 'xsize' times 'ysize'. + */ +static image_char new_image_char(unsigned int xsize, unsigned int ysize) +{ + image_char image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_char: invalid image size."); + + /* get memory */ + image = (image_char) malloc( sizeof(struct image_char_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (unsigned char *) calloc( (size_t) (xsize*ysize), + sizeof(unsigned char) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_double of size 'xsize' times 'ysize' + with the data pointed by 'data'. + */ +static image_char new_image_char_ptr( unsigned int xsize, + unsigned int ysize, unsigned char * data ) +{ + image_char image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) + error("new_image_char_ptr: invalid image size."); + if( data == NULL ) error("new_image_char_ptr: NULL data pointer."); + + /* get memory */ + image = (image_char) malloc( sizeof(struct image_char_s) ); + if( image == NULL ) error("not enough memory."); + + /* set image */ + image->xsize = xsize; + image->ysize = ysize; + image->data = data; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_char of size 'xsize' times 'ysize', + initialized to the value 'fill_value'. + */ +static image_char new_image_char_ini( unsigned int xsize, unsigned int ysize, + unsigned char fill_value ) +{ + image_char image = new_image_char(xsize,ysize); /* create image */ + unsigned int N = xsize*ysize; + unsigned int i; + + /* check parameters */ + if( image == NULL || image->data == NULL ) + error("new_image_char_ini: invalid image."); + + /* initialize */ + for(i=0; idata[i] = fill_value; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** int image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_int_s +{ + int16_t * data; + unsigned int xsize,ysize; +} * image_int; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in image_int 'i'. + */ +static void free_image_int(image_int i) +{ + if( i == NULL || i->data == NULL ) + error("free_image_int: invalid input image."); + free( (void *) i->data ); + free( (void *) i ); +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_int of size 'xsize' times 'ysize'. + */ +static image_int new_image_int(unsigned int xsize, unsigned int ysize) +{ + image_int image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_int: invalid image size."); + + /* get memory */ + image = (image_int) malloc( sizeof(struct image_int_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (int16_t *) calloc( (size_t) (xsize*ysize), sizeof(int16_t) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_int of size 'xsize' times 'ysize', + initialized to the value 'fill_value'. + */ +static image_int new_image_int_ini( unsigned int xsize, unsigned int ysize, + int fill_value ) +{ + image_int image = new_image_int(xsize,ysize); /* create image */ + unsigned int N = xsize*ysize; + unsigned int i; + + /* initialize */ + for(i=0; idata[i] = fill_value; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** double image data type + + The pixel value at (x,y) is accessed by: + + image->data[ x + y * image->xsize ] + + with x and y integer. + */ +typedef struct image_double_s +{ + double * data; + unsigned int xsize,ysize; +} * image_double; + +/*----------------------------------------------------------------------------*/ +/** Free memory used in image_double 'i'. + */ +static void free_image_double(image_double i) +{ + if( i == NULL || i->data == NULL ) + error("free_image_double: invalid input image."); + free( (void *) i->data ); + free( (void *) i ); +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_double of size 'xsize' times 'ysize'. + */ +static image_double new_image_double(unsigned int xsize, unsigned int ysize) +{ + image_double image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) error("new_image_double: invalid image size."); + + /* get memory */ + image = (image_double) malloc( sizeof(struct image_double_s) ); + if( image == NULL ) error("not enough memory."); + image->data = (double *) calloc( (size_t) (xsize*ysize), sizeof(double) ); + if( image->data == NULL ) error("not enough memory."); + + /* set image size */ + image->xsize = xsize; + image->ysize = ysize; + + return image; +} + +/*----------------------------------------------------------------------------*/ +/** Create a new image_double of size 'xsize' times 'ysize' + with the data pointed by 'data'. + */ +static image_double new_image_double_ptr( unsigned int xsize, + unsigned int ysize, double * data ) +{ + image_double image; + + /* check parameters */ + if( xsize == 0 || ysize == 0 ) + error("new_image_double_ptr: invalid image size."); + if( data == NULL ) error("new_image_double_ptr: NULL data pointer."); + + /* get memory */ + image = (image_double) malloc( sizeof(struct image_double_s) ); + if( image == NULL ) error("not enough memory."); + + /* set image */ + image->xsize = xsize; + image->ysize = ysize; + image->data = data; + + return image; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- Gaussian filter ------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Compute a Gaussian kernel of length 'kernel->dim', + standard deviation 'sigma', and centered at value 'mean'. + + For example, if mean=0.5, the Gaussian will be centered + in the middle point between values 'kernel->values[0]' + and 'kernel->values[1]'. + */ +static void gaussian_kernel(ntuple_list kernel, double sigma, double mean) +{ + double sum = 0.0; + double val; + unsigned int i; + + /* check parameters */ + if( kernel == NULL || kernel->values == NULL ) + error("gaussian_kernel: invalid n-tuple 'kernel'."); + if( sigma <= 0.0 ) error("gaussian_kernel: 'sigma' must be positive."); + + /* compute Gaussian kernel */ + if( kernel->max_size < 1 ) enlarge_ntuple_list(kernel); + kernel->size = 1; + for(i=0;idim;i++) + { + val = ( (double) i - mean ) / sigma; + kernel->values[i] = exp( -0.5 * val * val ); + sum += kernel->values[i]; + } + + /* normalization */ + if( sum >= 0.0 ) for(i=0;idim;i++) kernel->values[i] /= sum; +} + +/*----------------------------------------------------------------------------*/ +/** Scale the input image 'in' by a factor 'scale' by Gaussian sub-sampling. + + For example, scale=0.8 will give a result at 80% of the original size. + + The image is convolved with a Gaussian kernel + @f[ + G(x,y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2+y^2}{2\sigma^2}} + @f] + before the sub-sampling to prevent aliasing. + + The standard deviation sigma given by: + - sigma = sigma_scale / scale, if scale < 1.0 + - sigma = sigma_scale, if scale >= 1.0 + + To be able to sub-sample at non-integer steps, some interpolation + is needed. In this implementation, the interpolation is done by + the Gaussian kernel, so both operations (filtering and sampling) + are done at the same time. The Gaussian kernel is computed + centered on the coordinates of the required sample. In this way, + when applied, it gives directly the result of convolving the image + with the kernel and interpolated to that particular position. + + A fast algorithm is done using the separability of the Gaussian + kernel. Applying the 2D Gaussian kernel is equivalent to applying + first a horizontal 1D Gaussian kernel and then a vertical 1D + Gaussian kernel (or the other way round). The reason is that + @f[ + G(x,y) = G(x) * G(y) + @f] + where + @f[ + G(x) = \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{x^2}{2\sigma^2}}. + @f] + The algorithm first applies a combined Gaussian kernel and sampling + in the x axis, and then the combined Gaussian kernel and sampling + in the y axis. + */ +static image_double gaussian_sampler( image_double in, double scale, + double sigma_scale ) +{ + image_double aux,out; + ntuple_list kernel; + unsigned int N,M,h,n,x,y,i; + int xc,yc,j,double_x_size,double_y_size; + double sigma,xx,yy,sum,prec; + + /* check parameters */ + if( in == NULL || in->data == NULL || in->xsize == 0 || in->ysize == 0 ) + error("gaussian_sampler: invalid image."); + if( scale <= 0.0 ) error("gaussian_sampler: 'scale' must be positive."); + if( sigma_scale <= 0.0 ) + error("gaussian_sampler: 'sigma_scale' must be positive."); + + /* compute new image size and get memory for images */ + if( in->xsize * scale > (double) UINT_MAX || + in->ysize * scale > (double) UINT_MAX ) + error("gaussian_sampler: the output image size exceeds the handled size."); + N = (unsigned int) ceil( in->xsize * scale ); + M = (unsigned int) ceil( in->ysize * scale ); + aux = new_image_double(N,in->ysize); + out = new_image_double(N,M); + + /* sigma, kernel size and memory for the kernel */ + sigma = scale < 1.0 ? sigma_scale / scale : sigma_scale; + /* + The size of the kernel is selected to guarantee that the + the first discarded term is at least 10^prec times smaller + than the central value. For that, h should be larger than x, with + e^(-x^2/2sigma^2) = 1/10^prec. + Then, + x = sigma * sqrt( 2 * prec * ln(10) ). + */ + prec = 3.0; + h = (unsigned int) ceil( sigma * sqrt( 2.0 * prec * log(10.0) ) ); + n = 1+2*h; /* kernel size */ + kernel = new_ntuple_list(n); + + /* auxiliary double image size variables */ + double_x_size = (int) (2 * in->xsize); + double_y_size = (int) (2 * in->ysize); + + /* First subsampling: x axis */ + for(x=0;xxsize;x++) + { + /* + x is the coordinate in the new image. + xx is the corresponding x-value in the original size image. + xc is the integer value, the pixel coordinate of xx. + */ + xx = (double) x / scale; + /* coordinate (0.0,0.0) is in the center of pixel (0,0), + so the pixel with xc=0 get the values of xx from -0.5 to 0.5 */ + xc = (int) floor( xx + 0.5 ); + gaussian_kernel( kernel, sigma, (double) h + xx - (double) xc ); + /* the kernel must be computed for each x because the fine + offset xx-xc is different in each case */ + + for(y=0;yysize;y++) + { + sum = 0.0; + for(i=0;idim;i++) + { + j = xc - h + i; + + /* symmetry boundary condition */ + while( j < 0 ) j += double_x_size; + while( j >= double_x_size ) j -= double_x_size; + if( j >= (int) in->xsize ) j = double_x_size-1-j; + + sum += in->data[ j + y * in->xsize ] * kernel->values[i]; + } + aux->data[ x + y * aux->xsize ] = sum; + } + } + + /* Second subsampling: y axis */ + for(y=0;yysize;y++) + { + /* + y is the coordinate in the new image. + yy is the corresponding x-value in the original size image. + yc is the integer value, the pixel coordinate of xx. + */ + yy = (double) y / scale; + /* coordinate (0.0,0.0) is in the center of pixel (0,0), + so the pixel with yc=0 get the values of yy from -0.5 to 0.5 */ + yc = (int) floor( yy + 0.5 ); + gaussian_kernel( kernel, sigma, (double) h + yy - (double) yc ); + /* the kernel must be computed for each y because the fine + offset yy-yc is different in each case */ + + for(x=0;xxsize;x++) + { + sum = 0.0; + for(i=0;idim;i++) + { + j = yc - h + i; + + /* symmetry boundary condition */ + while( j < 0 ) j += double_y_size; + while( j >= double_y_size ) j -= double_y_size; + if( j >= (int) in->ysize ) j = double_y_size-1-j; + + sum += aux->data[ x + j * aux->xsize ] * kernel->values[i]; + } + out->data[ x + y * out->xsize ] = sum; + } + } + + /* free memory */ + free_ntuple_list(kernel); + free_image_double(aux); + + return out; +} + + +/*----------------------------------------------------------------------------*/ +/*--------------------------------- Gradient ---------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Computes the direction of the level line of 'in' at each point. + + The result is: + - an image_int with the angle at each pixel, or NOTDEF if not defined. + - the image_int 'modgrad' (a pointer is passed as argument) + with the gradient magnitude at each point. + - a list of pixels 'list_p' roughly ordered by decreasing + gradient magnitude. (The order is made by classifying points + into bins by gradient magnitude. The parameters 'n_bins' and + 'max_grad' specify the number of bins and the gradient modulus + at the highest bin. The pixels in the list would be in + decreasing gradient magnitude, up to a precision of the size of + the bins.) + - a pointer 'mem_p' to the memory used by 'list_p' to be able to + free the memory when it is not used anymore. + */ +static image_int ll_angle( image_char in, double threshold, + struct coorlist ** list_p, void ** mem_p, + image_int * modgrad, unsigned int n_bins ) +{ + image_int g; + unsigned int n,p,x,y,adr,i; + double com1,com2,gx,gy,norm,norm2; + /* the rest of the variables are used for pseudo-ordering + the gradient magnitude values */ + int list_count = 0; + struct coorlist * list; + struct coorlist ** range_l_s; /* array of pointers to start of bin list */ + struct coorlist ** range_l_e; /* array of pointers to end of bin list */ + struct coorlist * start; + struct coorlist * end; + double max_grad = 0.0; + + /* check parameters */ + if( in == NULL || in->data == NULL || in->xsize == 0 || in->ysize == 0 ) + error("ll_angle: invalid image."); + if( threshold < 0.0 ) error("ll_angle: 'threshold' must be positive."); + if( list_p == NULL ) error("ll_angle: NULL pointer 'list_p'."); + if( mem_p == NULL ) error("ll_angle: NULL pointer 'mem_p'."); + if( modgrad == NULL ) error("ll_angle: NULL pointer 'modgrad'."); + if( n_bins == 0 ) error("ll_angle: 'n_bins' must be positive."); + + /* image size shortcuts */ + n = in->ysize; + p = in->xsize; + + /* allocate output image */ + g = new_image_int(in->xsize,in->ysize); + + /* get memory for the image of gradient modulus */ + *modgrad = new_image_int(in->xsize,in->ysize); + + /* get memory for "ordered" list of pixels */ + list = (struct coorlist *) calloc( (size_t) (n*p), sizeof(struct coorlist) ); + *mem_p = (void *) list; + range_l_s = (struct coorlist **) calloc( (size_t) n_bins, + sizeof(struct coorlist *) ); + range_l_e = (struct coorlist **) calloc( (size_t) n_bins, + sizeof(struct coorlist *) ); + if( list == NULL || range_l_s == NULL || range_l_e == NULL ) + error("not enough memory."); + for(i=0;idata[(n-1)*p+x] = NOTDEF; + for(y=0;ydata[p*y+p-1] = NOTDEF; + + /* compute gradient on the remaining pixels */ + for(x=0;xdata[adr+p+1] - in->data[adr]; + com2 = in->data[adr+1] - in->data[adr+p]; + + gx = com1+com2; /* gradient x component */ + gy = com1-com2; /* gradient y component */ + norm2 = gx*gx+gy*gy; + norm = sqrt( norm2 / 4.0 ); /* gradient norm */ + + (*modgrad)->data[adr] = norm; /* store gradient norm */ + + if( norm <= threshold ) /* norm too small, gradient no defined */ + g->data[adr] = radToDeg(NOTDEF); /* gradient angle not defined */ + else + { + /* gradient angle computation */ + g->data[adr] = radToDeg(atan2(gx,-gy)); + + /* look for the maximum of the gradient */ + if( norm > max_grad ) max_grad = norm; + } + } + + /* compute histogram of gradient values */ + for(x=0;xdata[y*p+x]; + + /* store the point in the right bin according to its norm */ + i = (unsigned int) (norm * (double) n_bins / max_grad); + if( i >= n_bins ) i = n_bins-1; + if( range_l_e[i] == NULL ) + range_l_s[i] = range_l_e[i] = list+list_count++; + else + { + range_l_e[i]->next = list+list_count; + range_l_e[i] = list+list_count++; + } + range_l_e[i]->x = (int) x; + range_l_e[i]->y = (int) y; + range_l_e[i]->next = NULL; + } + + /* Make the list of pixels (almost) ordered by norm value. + It starts by the larger bin, so the list starts by the + pixels with the highest gradient value. Pixels would be ordered + by norm value, up to a precision given by max_grad/n_bins. + */ + for(i=n_bins-1; i>0 && range_l_s[i]==NULL; i--); + start = range_l_s[i]; + end = range_l_e[i]; + if( start != NULL ) + while(i>0) + { + --i; + if( range_l_s[i] != NULL ) + { + end->next = range_l_s[i]; + end = range_l_e[i]; + } + } + *list_p = start; + + /* free memory */ + free( (void *) range_l_s ); + free( (void *) range_l_e ); + + return g; +} + +/*----------------------------------------------------------------------------*/ +/** Is point (x,y) aligned to angle theta, up to precision 'prec'? + */ +static int isaligned( int x, int y, image_int angles, double theta, + double prec ) +{ + double a; + + /* check parameters */ + if( angles == NULL || angles->data == NULL ) + error("isaligned: invalid image 'angles'."); + if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) + error("isaligned: (x,y) out of the image."); + if( prec < 0.0 ) error("isaligned: 'prec' must be positive."); + + /* angle at pixel (x,y) */ + a = degToRad(angles->data[ x + y * angles->xsize ]); + + /* pixels whose level-line angle is not defined + are considered as NON-aligned */ + if( a == NOTDEF ) return FALSE; /* there is no need to call the function + 'double_equal' here because there is + no risk of problems related to the + comparison doubles, we are only + interested in the exact NOTDEF value */ + + /* it is assumed that 'theta' and 'a' are in the range [-pi,pi] */ + theta -= a; + if( theta < 0.0 ) theta = -theta; + if( theta > M_3_2_PI ) + { + theta -= M_2__PI; + if( theta < 0.0 ) theta = -theta; + } + + return theta <= prec; +} + +/*----------------------------------------------------------------------------*/ +/** Absolute value angle difference. + */ +static double angle_diff(double a, double b) +{ + a -= b; + while( a <= -M_PI ) a += M_2__PI; + while( a > M_PI ) a -= M_2__PI; + if( a < 0.0 ) a = -a; + return a; +} + +/*----------------------------------------------------------------------------*/ +/** Signed angle difference. + */ +static double angle_diff_signed(double a, double b) +{ + a -= b; + while( a <= -M_PI ) a += M_2__PI; + while( a > M_PI ) a -= M_2__PI; + return a; +} + + +/*----------------------------------------------------------------------------*/ +/*----------------------------- NFA computation ------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x using the Lanczos approximation. + See http://www.rskey.org/gamma.htm + + The formula used is + @f[ + \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) } + (x+5.5)^{x+0.5} e^{-(x+5.5)} + @f] + so + @f[ + \log\Gamma(x) = \log\left( \sum_{n=0}^{N} q_n x^n \right) + + (x+0.5) \log(x+5.5) - (x+5.5) - \sum_{n=0}^{N} \log(x+n) + @f] + and + q0 = 75122.6331530, + q1 = 80916.6278952, + q2 = 36308.2951477, + q3 = 8687.24529705, + q4 = 1168.92649479, + q5 = 83.8676043424, + q6 = 2.50662827511. + */ +static double log_gamma_lanczos(double x) +{ + static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, + 8687.24529705, 1168.92649479, 83.8676043424, + 2.50662827511 }; + double a = (x+0.5) * log(x+5.5) - (x+5.5); + double b = 0.0; + int n; + + for(n=0;n<7;n++) + { + a -= log( x + (double) n ); + b += q[n] * pow( x, (double) n ); + } + return a + log(b); +} + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x using Windschitl method. + See http://www.rskey.org/gamma.htm + + The formula used is + @f[ + \Gamma(x) = \sqrt{\frac{2\pi}{x}} \left( \frac{x}{e} + \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } \right)^x + @f] + so + @f[ + \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x + + 0.5x\log\left( x\sinh(1/x) + \frac{1}{810x^6} \right). + @f] + This formula is a good approximation when x > 15. + */ +static double log_gamma_windschitl(double x) +{ + return 0.918938533204673 + (x-0.5)*log(x) - x + + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) ); +} + +/*----------------------------------------------------------------------------*/ +/** Computes the natural logarithm of the absolute value of + the gamma function of x. When x>15 use log_gamma_windschitl(), + otherwise use log_gamma_lanczos(). + */ +#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) + +///*----------------------------------------------------------------------------*/ +///** Size of the table to store already computed inverse values. +// */ +//#define TABSIZE 100000 + +/*----------------------------------------------------------------------------*/ +/** Computes -log10(NFA). + + NFA stands for Number of False Alarms: + @f[ + \mathrm{NFA} = NT \cdot B(n,k,p) + @f] + + - NT - number of tests + - B(n,k,p) - tail of binomial distribution with parameters n,k and p: + @f[ + B(n,k,p) = \sum_{j=k}^n + \left(\begin{array}{c}n\\j\end{array}\right) + p^{j} (1-p)^{n-j} + @f] + + The value -log10(NFA) is equivalent but more intuitive than NFA: + - -1 corresponds to 10 mean false alarms + - 0 corresponds to 1 mean false alarm + - 1 corresponds to 0.1 mean false alarms + - 2 corresponds to 0.01 mean false alarms + - ... + + Used this way, the bigger the value, better the detection, + and a logarithmic scale is used. + + @param n,k,p binomial parameters. + @param logNT logarithm of Number of Tests + + The computation is based in the gamma function by the following + relation: + @f[ + \left(\begin{array}{c}n\\k\end{array}\right) + = \frac{ \Gamma(n+1) }{ \Gamma(k+1) \cdot \Gamma(n-k+1) }. + @f] + We use efficient algorithms to compute the logarithm of + the gamma function. + + To make the computation faster, not all the sum is computed, part + of the terms are neglected based on a bound to the error obtained + (an error of 10% in the result is accepted). + */ +static double nfa(int n, int k, double p, double logNT) +{ +// static double inv[TABSIZE]; /* table to keep computed inverse values */ + double tolerance = 0.1; /* an error of 10% in the result is accepted */ + double log1term,term,bin_term,mult_term,bin_tail,err,p_term; + int i; + + /* check parameters */ + if( n<0 || k<0 || k>n || p<=0.0 || p>=1.0 ) + error("nfa: wrong n, k or p values."); + + /* trivial cases */ + if( n==0 || k==0 ) return -logNT; + if( n==k ) return -logNT - (double) n * log10(p); + + /* probability term */ + p_term = p / (1.0-p); + + /* compute the first term of the series */ + /* + binomial_tail(n,k,p) = sum_{i=k}^n bincoef(n,i) * p^i * (1-p)^{n-i} + where bincoef(n,i) are the binomial coefficients. + But + bincoef(n,k) = gamma(n+1) / ( gamma(k+1) * gamma(n-k+1) ). + We use this to compute the first term. Actually the log of it. + */ + log1term = log_gamma( (double) n + 1.0 ) - log_gamma( (double) k + 1.0 ) + - log_gamma( (double) (n-k) + 1.0 ) + + (double) k * log(p) + (double) (n-k) * log(1.0-p); + term = exp(log1term); + + /* in some cases no more computations are needed */ + if( double_equal(term,0.0) ) /* the first term is almost zero */ + { + if( (double) k > (double) n * p ) /* at begin or end of the tail? */ + return -log1term / M_LN10 - logNT; /* end: use just the first term */ + else + return -logNT; /* begin: the tail is roughly 1 */ + } + + /* compute more terms if needed */ + bin_tail = term; + for(i=k+1;i<=n;i++) + { + /* + As + term_i = bincoef(n,i) * p^i * (1-p)^(n-i) + and + bincoef(n,i)/bincoef(n,i-1) = n-1+1 / i, + then, + term_i / term_i-1 = (n-i+1)/i * p/(1-p) + and + term_i = term_i-1 * (n-i+1)/i * p/(1-p). + 1/i is stored in a table as they are computed, + because divisions are expensive. + p/(1-p) is computed only once and stored in 'p_term'. + */ +// bin_term = (double) (n-i+1) * ( ii. + Then, the error on the binomial tail when truncated at + the i term can be bounded by a geometric series of form + term_i * sum mult_term_i^j. */ + err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) / + (1.0-mult_term) - 1.0 ); + + /* One wants an error at most of tolerance*final_result, or: + tolerance * abs(-log10(bin_tail)-logNT). + Now, the error that can be accepted on bin_tail is + given by tolerance*final_result divided by the derivative + of -log10(x) when x=bin_tail. that is: + tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail) + Finally, we truncate the tail if the error is less than: + tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */ + if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break; + } + } + return -log10(bin_tail) - logNT; +} + + +/*----------------------------------------------------------------------------*/ +/*--------------------------- Rectangle structure ----------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Rectangle structure: line segment with width. + */ +struct rect +{ + double x1,y1,x2,y2; /* first and second point of the line segment */ + double width; /* rectangle width */ + double x,y; /* center of the rectangle */ + double theta; /* angle */ + double dx,dy; /* (dx,dy) is vector oriented as the line segment */ + double prec; /* tolerance angle */ + double p; /* probability of a point with angle within 'prec' */ +}; + +/*----------------------------------------------------------------------------*/ +/** Copy one rectangle structure to another. + */ +static void rect_copy(struct rect * in, struct rect * out) +{ + /* check parameters */ + if( in == NULL || out == NULL ) error("rect_copy: invalid 'in' or 'out'."); + + /* copy values */ + out->x1 = in->x1; + out->y1 = in->y1; + out->x2 = in->x2; + out->y2 = in->y2; + out->width = in->width; + out->x = in->x; + out->y = in->y; + out->theta = in->theta; + out->dx = in->dx; + out->dy = in->dy; + out->prec = in->prec; + out->p = in->p; +} + +/*----------------------------------------------------------------------------*/ +/** Rectangle points iterator. + + The integer coordinates of pixels inside a rectangle are + iteratively explored. This structure keep track of the process and + functions ri_ini(), ri_inc(), ri_end(), and ri_del() are used in + the process. An example of how to use the iterator is as follows: + \code + + struct rect * rec = XXX; // some rectangle + rect_iter * i; + for( i=ri_ini(rec); !ri_end(i); ri_inc(i) ) + { + // your code, using 'i->x' and 'i->y' as coordinates + } + ri_del(i); // delete iterator + + \endcode + The pixels are explored 'column' by 'column', where we call + 'column' a set of pixels with the same x value that are inside the + rectangle. The following is an schematic representation of a + rectangle, the 'column' being explored is marked by colons, and + the current pixel being explored is 'x,y'. + \verbatim + + vx[1],vy[1] + * * + * * + * * + * ye + * : * + vx[0],vy[0] : * + * : * + * x,y * + * : * + * : vx[2],vy[2] + * : * + y ys * + ^ * * + | * * + | * * + +---> x vx[3],vy[3] + + \endverbatim + The first 'column' to be explored is the one with the smaller x + value. Each 'column' is explored starting from the pixel of the + 'column' (inside the rectangle) with the smallest y value. + + The four corners of the rectangle are stored in order that rotates + around the corners at the arrays 'vx[]' and 'vy[]'. The first + point is always the one with smaller x value. + + 'x' and 'y' are the coordinates of the pixel being explored. 'ys' + and 'ye' are the start and end values of the current column being + explored. So, 'ys' < 'ye'. + */ +typedef struct +{ + double vx[4]; /* rectangle's corner X coordinates in circular order */ + double vy[4]; /* rectangle's corner Y coordinates in circular order */ + double ys,ye; /* start and end Y values of current 'column' */ + int x,y; /* coordinates of currently explored pixel */ +} rect_iter; + +/*----------------------------------------------------------------------------*/ +/** Interpolate y value corresponding to 'x' value given, in + the line 'x1,y1' to 'x2,y2'; if 'x1=x2' return the smaller + of 'y1' and 'y2'. + + The following restrictions are required: + - x1 <= x2 + - x1 <= x + - x <= x2 + */ +static double inter_low(double x, double x1, double y1, double x2, double y2) +{ + /* check parameters */ +// if( x1 > x2 || x < x1 || x > x2 ) +// error("inter_low: unsuitable input, 'x1>x2' or 'xx2'."); + + /* interpolation */ + if( double_equal(x1,x2) && y1y2 ) return y2; +// return y1 + (x-x1) * (y2-y1) / (x2-x1); + double result = y1 + (x-x1) * (y2-y1) / (x2-x1); + if (isnan(result) || isinf(result)) return (y1y2) ? y2 : 0); + return result; +} + +/*----------------------------------------------------------------------------*/ +/** Interpolate y value corresponding to 'x' value given, in + the line 'x1,y1' to 'x2,y2'; if 'x1=x2' return the larger + of 'y1' and 'y2'. + + The following restrictions are required: + - x1 <= x2 + - x1 <= x + - x <= x2 + */ +static double inter_hi(double x, double x1, double y1, double x2, double y2) +{ + /* check parameters */ +// if( x1 > x2 || x < x1 || x > x2 ) +// error("inter_hi: unsuitable input, 'x1>x2' or 'xx2'."); + + /* interpolation */ + if( double_equal(x1,x2) && y1y2 ) return y1; +// return y1 + (x-x1) * (y2-y1) / (x2-x1); + double result = y1 + (x-x1) * (y2-y1) / (x2-x1); + if (isnan(result) || isinf(result)) return (y1y2) ? y1 : 0); + return result; +} + +/*----------------------------------------------------------------------------*/ +/** Free memory used by a rectangle iterator. + */ +static void ri_del(rect_iter * iter) +{ + if( iter == NULL ) error("ri_del: NULL iterator."); + free( (void *) iter ); +} + +/*----------------------------------------------------------------------------*/ +/** Check if the iterator finished the full iteration. + + See details in \ref rect_iter + */ +static int ri_end(rect_iter * i) +{ + /* check input */ + if( i == NULL ) error("ri_end: NULL iterator."); + + /* if the current x value is larger than the largest + x value in the rectangle (vx[2]), we know the full + exploration of the rectangle is finished. */ + return (double)(i->x) > i->vx[2]; +} + +/*----------------------------------------------------------------------------*/ +/** Increment a rectangle iterator. + + See details in \ref rect_iter + */ +static void ri_inc(rect_iter * i) +{ + /* check input */ + if( i == NULL ) error("ri_inc: NULL iterator."); + + /* if not at end of exploration, + increase y value for next pixel in the 'column' */ + if( !ri_end(i) ) i->y++; + + /* if the end of the current 'column' is reached, + and it is not the end of exploration, + advance to the next 'column' */ + while( (double) (i->y) > i->ye && !ri_end(i) ) + { + /* increase x, next 'column' */ + i->x++; + + /* if end of exploration, return */ + if( ri_end(i) ) return; + + /* update lower y limit (start) for the new 'column'. + + We need to interpolate the y value that corresponds to the + lower side of the rectangle. The first thing is to decide if + the corresponding side is + + vx[0],vy[0] to vx[3],vy[3] or + vx[3],vy[3] to vx[2],vy[2] + + Then, the side is interpolated for the x value of the + 'column'. But, if the side is vertical (as it could happen if + the rectangle is vertical and we are dealing with the first + or last 'columns') then we pick the lower value of the side + by using 'inter_low'. + */ + if( (double) i->x < i->vx[3] ) + i->ys = inter_low((double)i->x,i->vx[0],i->vy[0],i->vx[3],i->vy[3]); + else + i->ys = inter_low((double)i->x,i->vx[3],i->vy[3],i->vx[2],i->vy[2]); + + /* update upper y limit (end) for the new 'column'. + + We need to interpolate the y value that corresponds to the + upper side of the rectangle. The first thing is to decide if + the corresponding side is + + vx[0],vy[0] to vx[1],vy[1] or + vx[1],vy[1] to vx[2],vy[2] + + Then, the side is interpolated for the x value of the + 'column'. But, if the side is vertical (as it could happen if + the rectangle is vertical and we are dealing with the first + or last 'columns') then we pick the lower value of the side + by using 'inter_low'. + */ + if( (double)i->x < i->vx[1] ) + i->ye = inter_hi((double)i->x,i->vx[0],i->vy[0],i->vx[1],i->vy[1]); + else + i->ye = inter_hi((double)i->x,i->vx[1],i->vy[1],i->vx[2],i->vy[2]); + + /* new y */ + i->y = (int) ceil(i->ys); + } +} + +/*----------------------------------------------------------------------------*/ +/** Create and initialize a rectangle iterator. + + See details in \ref rect_iter + */ +static rect_iter * ri_ini(struct rect * r) +{ + double vx[4],vy[4]; + int n,offset; + rect_iter * i; + + /* check parameters */ + if( r == NULL ) error("ri_ini: invalid rectangle."); + + /* get memory */ + i = (rect_iter *) malloc(sizeof(rect_iter)); + if( i == NULL ) error("ri_ini: Not enough memory."); + + /* build list of rectangle corners ordered + in a circular way around the rectangle */ + vx[0] = r->x1 - r->dy * r->width / 2.0; + vy[0] = r->y1 + r->dx * r->width / 2.0; + vx[1] = r->x2 - r->dy * r->width / 2.0; + vy[1] = r->y2 + r->dx * r->width / 2.0; + vx[2] = r->x2 + r->dy * r->width / 2.0; + vy[2] = r->y2 - r->dx * r->width / 2.0; + vx[3] = r->x1 + r->dy * r->width / 2.0; + vy[3] = r->y1 - r->dx * r->width / 2.0; + + /* compute rotation of index of corners needed so that the first + point has the smaller x. + + if one side is vertical, thus two corners have the same smaller x + value, the one with the largest y value is selected as the first. + */ + if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0; + else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1; + else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2; + else offset = 3; + + /* apply rotation of index. */ + for(n=0; n<4; n++) + { + i->vx[n] = vx[(offset+n)%4]; + i->vy[n] = vy[(offset+n)%4]; + } + + /* Set an initial condition. + + The values are set to values that will cause 'ri_inc' (that will + be called immediately) to initialize correctly the first 'column' + and compute the limits 'ys' and 'ye'. + + 'y' is set to the integer value of vy[0], the starting corner. + + 'ys' and 'ye' are set to very small values, so 'ri_inc' will + notice that it needs to start a new 'column'. + + The smallest integer coordinate inside of the rectangle is + 'ceil(vx[0])'. The current 'x' value is set to that value minus + one, so 'ri_inc' (that will increase x by one) will advance to + the first 'column'. + */ + i->x = (int) ceil(i->vx[0]) - 1; + i->y = (int) ceil(i->vy[0]); + i->ys = i->ye = -DBL_MAX; + + /* advance to the first pixel */ + ri_inc(i); + + return i; +} + +/*----------------------------------------------------------------------------*/ +/** Compute a rectangle's NFA value. + */ +static double rect_nfa(struct rect * rec, image_int angles, double logNT) +{ + rect_iter * i; + int pts = 0; + int alg = 0; + + /* check parameters */ + if( rec == NULL ) error("rect_nfa: invalid rectangle."); + if( angles == NULL ) error("rect_nfa: invalid 'angles'."); + + /* compute the total number of pixels and of aligned points in 'rec' */ + for(i=ri_ini(rec); !ri_end(i); ri_inc(i)) /* rectangle iterator */ + if( i->x >= 0 && i->y >= 0 && + i->x < (int) angles->xsize && i->y < (int) angles->ysize ) + { + ++pts; /* total number of pixels counter */ + if( isaligned(i->x, i->y, angles, rec->theta, rec->prec) ) + ++alg; /* aligned points counter */ + } + ri_del(i); /* delete iterator */ + + return nfa(pts,alg,rec->p,logNT); /* compute NFA value */ +} + + +/*----------------------------------------------------------------------------*/ +/*---------------------------------- Regions ---------------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** Compute region's angle as the principal inertia axis of the region. + + The following is the region inertia matrix A: + @f[ + + A = \left(\begin{array}{cc} + Ixx & Ixy \\ + Ixy & Iyy \\ + \end{array}\right) + + @f] + where + + Ixx = sum_i G(i).(y_i - cx)^2 + + Iyy = sum_i G(i).(x_i - cy)^2 + + Ixy = - sum_i G(i).(x_i - cx).(y_i - cy) + + and + - G(i) is the gradient norm at pixel i, used as pixel's weight. + - x_i and y_i are the coordinates of pixel i. + - cx and cy are the coordinates of the center of th region. + + lambda1 and lambda2 are the eigenvalues of matrix A, + with lambda1 >= lambda2. They are found by solving the + characteristic polynomial: + + det( lambda I - A) = 0 + + that gives: + + lambda1 = ( Ixx + Iyy + sqrt( (Ixx-Iyy)^2 + 4.0*Ixy*Ixy) ) / 2 + + lambda2 = ( Ixx + Iyy - sqrt( (Ixx-Iyy)^2 + 4.0*Ixy*Ixy) ) / 2 + + To get the line segment direction we want to get the angle the + eigenvector associated to the smallest eigenvalue. We have + to solve for a,b in: + + a.Ixx + b.Ixy = a.lambda2 + + a.Ixy + b.Iyy = b.lambda2 + + We want the angle theta = atan(b/a). It can be computed with + any of the two equations: + + theta = atan( (lambda2-Ixx) / Ixy ) + + or + + theta = atan( Ixy / (lambda2-Iyy) ) + + When |Ixx| > |Iyy| we use the first, otherwise the second (just to + get better numeric precision). + */ +static double get_theta( struct lsd_point * reg, int reg_size, double x, double y, + image_int modgrad, double reg_angle, double prec ) +{ + double lambda,theta,weight; + double Ixx = 0.0; + double Iyy = 0.0; + double Ixy = 0.0; + int i; + + /* check parameters */ + if( reg == NULL ) error("get_theta: invalid region."); + if( reg_size <= 1 ) error("get_theta: region size <= 1."); + if( modgrad == NULL || modgrad->data == NULL ) + error("get_theta: invalid 'modgrad'."); + if( prec < 0.0 ) error("get_theta: 'prec' must be positive."); + + /* compute inertia matrix */ + for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; + Ixx += ( (double) reg[i].y - y ) * ( (double) reg[i].y - y ) * weight; + Iyy += ( (double) reg[i].x - x ) * ( (double) reg[i].x - x ) * weight; + Ixy -= ( (double) reg[i].x - x ) * ( (double) reg[i].y - y ) * weight; + } + if( double_equal(Ixx,0.0) && double_equal(Iyy,0.0) && double_equal(Ixy,0.0) ) + error("get_theta: null inertia matrix."); + + /* compute smallest eigenvalue */ + lambda = 0.5 * ( Ixx + Iyy - sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4.0*Ixy*Ixy ) ); + + /* compute angle */ + theta = fabs(Ixx)>fabs(Iyy) ? atan2(lambda-Ixx,Ixy) : atan2(Ixy,lambda-Iyy); + + /* The previous procedure doesn't cares about orientation, + so it could be wrong by 180 degrees. Here is corrected if necessary. */ + if( angle_diff(theta,reg_angle) > prec ) theta += M_PI; + + return theta; +} + +/*----------------------------------------------------------------------------*/ +/** Computes a rectangle that covers a region of points. + */ +static void region2rect( struct lsd_point * reg, int reg_size, + image_int modgrad, double reg_angle, + double prec, double p, struct rect * rec ) +{ + double x,y,dx,dy,l,w,theta,weight,sum,l_min,l_max,w_min,w_max; + int i; + + /* check parameters */ + if( reg == NULL ) error("region2rect: invalid region."); + if( reg_size <= 1 ) error("region2rect: region size <= 1."); + if( modgrad == NULL || modgrad->data == NULL ) + error("region2rect: invalid image 'modgrad'."); + if( rec == NULL ) error("region2rect: invalid 'rec'."); + + /* center of the region: + + It is computed as the weighted sum of the coordinates + of all the pixels in the region. The norm of the gradient + is used as the weight of a pixel. The sum is as follows: + cx = \sum_i G(i).x_i + cy = \sum_i G(i).y_i + where G(i) is the norm of the gradient of pixel i + and x_i,y_i are its coordinates. + */ + x = y = sum = 0.0; + for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; + x += (double) reg[i].x * weight; + y += (double) reg[i].y * weight; + sum += weight; + } + if( sum <= 0.0 ) error("region2rect: weights sum equal to zero."); + x /= sum; + y /= sum; + + /* theta */ + theta = get_theta(reg,reg_size,x,y,modgrad,reg_angle,prec); + + /* length and width: + + 'l' and 'w' are computed as the distance from the center of the + region to pixel i, projected along the rectangle axis (dx,dy) and + to the orthogonal axis (-dy,dx), respectively. + + The length of the rectangle goes from l_min to l_max, where l_min + and l_max are the minimum and maximum values of l in the region. + Analogously, the width is selected from w_min to w_max, where + w_min and w_max are the minimum and maximum of w for the pixels + in the region. + */ + dx = cos(theta); + dy = sin(theta); + l_min = l_max = w_min = w_max = 0.0; + for(i=0; i l_max ) l_max = l; + if( l < l_min ) l_min = l; + if( w > w_max ) w_max = w; + if( w < w_min ) w_min = w; + } + + /* store values */ + rec->x1 = x + l_min * dx; + rec->y1 = y + l_min * dy; + rec->x2 = x + l_max * dx; + rec->y2 = y + l_max * dy; + rec->width = w_max - w_min; + rec->x = x; + rec->y = y; + rec->theta = theta; + rec->dx = dx; + rec->dy = dy; + rec->prec = prec; + rec->p = p; + + /* we impose a minimal width of one pixel + + A sharp horizontal or vertical step would produce a perfectly + horizontal or vertical region. The width computed would be + zero. But that corresponds to a one pixels width transition in + the image. + */ + if( rec->width < 1.0 ) rec->width = 1.0; +} + +/*----------------------------------------------------------------------------*/ +/** Build a region of pixels that share the same angle, up to a + tolerance 'prec', starting at point (x,y). + */ +static void region_grow( int x, int y, image_int angles, struct lsd_point * reg, + int * reg_size, double * reg_angle, image_char used, + double prec ) +{ + double sumdx,sumdy; + int xx,yy,i; + + /* check parameters */ + if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) + error("region_grow: (x,y) out of the image."); + if( angles == NULL || angles->data == NULL ) + error("region_grow: invalid image 'angles'."); + if( reg == NULL ) error("region_grow: invalid 'reg'."); + if( reg_size == NULL ) error("region_grow: invalid pointer 'reg_size'."); + if( reg_angle == NULL ) error("region_grow: invalid pointer 'reg_angle'."); + if( used == NULL || used->data == NULL ) + error("region_grow: invalid image 'used'."); + + /* first point of the region */ + *reg_size = 1; + reg[0].x = x; + reg[0].y = y; + *reg_angle = degToRad(angles->data[x+y*angles->xsize]); /* region's angle */ + sumdx = cos(*reg_angle); + sumdy = sin(*reg_angle); + used->data[x+y*used->xsize] = USED; + + /* try neighbors as new region points */ + for(i=0; i<*reg_size; i++) + for(xx=reg[i].x-1; xx<=reg[i].x+1; xx++) + for(yy=reg[i].y-1; yy<=reg[i].y+1; yy++) + if( xx>=0 && yy>=0 && xx<(int)used->xsize && yy<(int)used->ysize && + used->data[xx+yy*used->xsize] != USED && + isaligned(xx,yy,angles,*reg_angle,prec) ) + { + /* add point */ + used->data[xx+yy*used->xsize] = USED; + reg[*reg_size].x = xx; + reg[*reg_size].y = yy; + ++(*reg_size); + + /* update region's angle */ + int16_t angle = angles->data[xx+yy*angles->xsize] % 360; + if (angle < 0) angle += 360; + sumdx += cos_table[angle]; + sumdy += sin_table[angle]; + *reg_angle = atan2(sumdy,sumdx); + } +} + +/*----------------------------------------------------------------------------*/ +/** Try some rectangles variations to improve NFA value. Only if the + rectangle is not meaningful (i.e., log_nfa <= log_eps). + */ +static double rect_improve( struct rect * rec, image_int angles, + double logNT, double log_eps ) +{ + struct rect r; + double log_nfa,log_nfa_new; + double delta = 0.5; + double delta_2 = delta / 2.0; + int n; + + log_nfa = rect_nfa(rec,angles,logNT); + + if( log_nfa > log_eps ) return log_nfa; + + /* try finer precisions */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + r.p /= 2.0; + r.prec = r.p * M_PI; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + log_nfa = log_nfa_new; + rect_copy(&r,rec); + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce width */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce one side of the rectangle */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.x1 += -r.dy * delta_2; + r.y1 += r.dx * delta_2; + r.x2 += -r.dy * delta_2; + r.y2 += r.dx * delta_2; + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try to reduce the other side of the rectangle */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + if( (r.width - delta) >= 0.5 ) + { + r.x1 -= -r.dy * delta_2; + r.y1 -= r.dx * delta_2; + r.x2 -= -r.dy * delta_2; + r.y2 -= r.dx * delta_2; + r.width -= delta; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + rect_copy(&r,rec); + log_nfa = log_nfa_new; + } + } + } + + if( log_nfa > log_eps ) return log_nfa; + + /* try even finer precisions */ + rect_copy(rec,&r); + for(n=0; n<5; n++) + { + r.p /= 2.0; + r.prec = r.p * M_PI; + log_nfa_new = rect_nfa(&r,angles,logNT); + if( log_nfa_new > log_nfa ) + { + log_nfa = log_nfa_new; + rect_copy(&r,rec); + } + } + + return log_nfa; +} + +/*----------------------------------------------------------------------------*/ +/** Reduce the region size, by elimination the points far from the + starting point, until that leads to rectangle with the right + density of region points or to discard the region if too small. + */ +static int reduce_region_radius( struct lsd_point * reg, int * reg_size, + image_int modgrad, double reg_angle, + double prec, double p, struct rect * rec, + image_char used, image_int angles, + double density_th ) +{ + double density,rad1,rad2,rad,xc,yc; + int i; + + /* check parameters */ + if( reg == NULL ) error("reduce_region_radius: invalid pointer 'reg'."); + if( reg_size == NULL ) + error("reduce_region_radius: invalid pointer 'reg_size'."); + if( prec < 0.0 ) error("reduce_region_radius: 'prec' must be positive."); + if( rec == NULL ) error("reduce_region_radius: invalid pointer 'rec'."); + if( used == NULL || used->data == NULL ) + error("reduce_region_radius: invalid image 'used'."); + if( angles == NULL || angles->data == NULL ) + error("reduce_region_radius: invalid image 'angles'."); + + /* compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /* if the density criterion is satisfied there is nothing to do */ + if( density >= density_th ) return TRUE; + + /* compute region's radius */ + xc = (double) reg[0].x; + yc = (double) reg[0].y; + rad1 = dist( xc, yc, rec->x1, rec->y1 ); + rad2 = dist( xc, yc, rec->x2, rec->y2 ); + rad = rad1 > rad2 ? rad1 : rad2; + + /* while the density criterion is not satisfied, remove farther pixels */ + while( density < density_th ) + { + rad *= 0.75; /* reduce region's radius to 75% of its value */ + + /* remove points from the region and update 'used' map */ + for(i=0; i<*reg_size; i++) + if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) > rad ) + { + /* point not kept, mark it as NOTUSED */ + used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; + /* remove point from the region */ + reg[i].x = reg[*reg_size-1].x; /* if i==*reg_size-1 copy itself */ + reg[i].y = reg[*reg_size-1].y; + --(*reg_size); + --i; /* to avoid skipping one point */ + } + + /* reject if the region is too small. + 2 is the minimal region size for 'region2rect' to work. */ + if( *reg_size < 2 ) return FALSE; + + /* re-compute rectangle */ + region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); + + /* re-compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + } + + /* if this point is reached, the density criterion is satisfied */ + return TRUE; +} + +/*----------------------------------------------------------------------------*/ +/** Refine a rectangle. + + For that, an estimation of the angle tolerance is performed by the + standard deviation of the angle at points near the region's + starting point. Then, a new region is grown starting from the same + point, but using the estimated angle tolerance. If this fails to + produce a rectangle with the right density of region points, + 'reduce_region_radius' is called to try to satisfy this condition. + */ +static int refine( struct lsd_point * reg, int * reg_size, image_int modgrad, + double reg_angle, double prec, double p, struct rect * rec, + image_char used, image_int angles, double density_th ) +{ + double angle,ang_d,mean_angle,tau,density,xc,yc,ang_c,sum,s_sum; + int i,n; + + /* check parameters */ + if( reg == NULL ) error("refine: invalid pointer 'reg'."); + if( reg_size == NULL ) error("refine: invalid pointer 'reg_size'."); + if( prec < 0.0 ) error("refine: 'prec' must be positive."); + if( rec == NULL ) error("refine: invalid pointer 'rec'."); + if( used == NULL || used->data == NULL ) + error("refine: invalid image 'used'."); + if( angles == NULL || angles->data == NULL ) + error("refine: invalid image 'angles'."); + + /* compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /* if the density criterion is satisfied there is nothing to do */ + if( density >= density_th ) return TRUE; + + /*------ First try: reduce angle tolerance ------*/ + + /* compute the new mean angle and tolerance */ + xc = (double) reg[0].x; + yc = (double) reg[0].y; + ang_c = degToRad(angles->data[ reg[0].x + reg[0].y * angles->xsize ]); + sum = s_sum = 0.0; + n = 0; + for(i=0; i<*reg_size; i++) + { + used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; + if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) < rec->width ) + { + angle = degToRad(angles->data[ reg[i].x + reg[i].y * angles->xsize ]); + ang_d = angle_diff_signed(angle,ang_c); + sum += ang_d; + s_sum += ang_d * ang_d; + ++n; + } + } + mean_angle = sum / (double) n; + tau = 2.0 * sqrt( (s_sum - 2.0 * mean_angle * sum) / (double) n + + mean_angle*mean_angle ); /* 2 * standard deviation */ + + /* find a new region from the same starting point and new angle tolerance */ + region_grow(reg[0].x,reg[0].y,angles,reg,reg_size,®_angle,used,tau); + + /* if the region is too small, reject */ + if( *reg_size < 2 ) return FALSE; + + /* re-compute rectangle */ + region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); + + /* re-compute region points density */ + density = (double) *reg_size / + ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); + + /*------ Second try: reduce region radius ------*/ + if( density < density_th ) + return reduce_region_radius( reg, reg_size, modgrad, reg_angle, prec, p, + rec, used, angles, density_th ); + + /* if this point is reached, the density criterion is satisfied */ + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ +/*-------------------------- Line Segment Detector ---------------------------*/ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/** LSD full interface. + */ +double * LineSegmentDetection( int * n_out, + unsigned char * img, int X, int Y, + double scale, double sigma_scale, double quant, + double ang_th, double log_eps, double density_th, + int n_bins, + int ** reg_img, int * reg_x, int * reg_y ) +{ + image_char image; + ntuple_list out = new_ntuple_list(7); + double * return_value; + image_int scaled_image,angles,modgrad; + image_char used; + image_int region = NULL; + struct coorlist * list_p; + void * mem_p; + struct rect rec; + struct lsd_point * reg; + int reg_size,min_reg_size,i; + unsigned int xsize,ysize; + double rho,reg_angle,prec,p,log_nfa,logNT; + int ls_count = 0; /* line segments are numbered 1,2,3,... */ + + + /* check parameters */ + if( img == NULL || X <= 0 || Y <= 0 ) error("invalid image input."); + if( scale <= 0.0 ) error("'scale' value must be positive."); + if( sigma_scale <= 0.0 ) error("'sigma_scale' value must be positive."); + if( quant < 0.0 ) error("'quant' value must be positive."); + if( ang_th <= 0.0 || ang_th >= 180.0 ) + error("'ang_th' value must be in the range (0,180)."); + if( density_th < 0.0 || density_th > 1.0 ) + error("'density_th' value must be in the range [0,1]."); + if( n_bins <= 0 ) error("'n_bins' value must be positive."); + + + /* angle tolerance */ + prec = M_PI * ang_th / 180.0; + p = ang_th / 180.0; + rho = quant / sin(prec); /* gradient magnitude threshold */ + + + /* load and scale image (if necessary) and compute angle at each pixel */ + image = new_image_char_ptr( (unsigned int) X, (unsigned int) Y, img ); +// if( scale != 1.0 ) +// { +// scaled_image = gaussian_sampler( image, scale, sigma_scale ); +// angles = ll_angle( scaled_image, rho, &list_p, &mem_p, +// &modgrad, (unsigned int) n_bins ); +// free_image_double(scaled_image); +// } +// else + angles = ll_angle( image, rho, &list_p, &mem_p, &modgrad, + (unsigned int) n_bins ); + xsize = angles->xsize; + ysize = angles->ysize; + + /* Number of Tests - NT + + The theoretical number of tests is Np.(XY)^(5/2) + where X and Y are number of columns and rows of the image. + Np corresponds to the number of angle precisions considered. + As the procedure 'rect_improve' tests 5 times to halve the + angle precision, and 5 more times after improving other factors, + 11 different precision values are potentially tested. Thus, + the number of tests is + 11 * (X*Y)^(5/2) + whose logarithm value is + log10(11) + 5/2 * (log10(X) + log10(Y)). + */ + logNT = 5.0 * ( log10( (double) xsize ) + log10( (double) ysize ) ) / 2.0 + + log10(11.0); + min_reg_size = (int) (-logNT/log10(p)); /* minimal number of points in region + that can give a meaningful event */ + + +// /* initialize some structures */ +// if( reg_img != NULL && reg_x != NULL && reg_y != NULL ) /* save region data */ +// region = new_image_int_ini(angles->xsize,angles->ysize,0); + used = new_image_char_ini(xsize,ysize,NOTUSED); + reg = (struct lsd_point *) calloc( (size_t) (xsize*ysize), sizeof(struct lsd_point) ); + if( reg == NULL ) error("not enough memory!"); + + + /* search for line segments */ + for(; list_p != NULL; list_p = list_p->next ) + if( used->data[ list_p->x + list_p->y * used->xsize ] == NOTUSED && + degToRad(angles->data[ list_p->x + list_p->y * angles->xsize ]) != NOTDEF ) + /* there is no risk of double comparison problems here + because we are only interested in the exact NOTDEF value */ + { + /* find the region of connected point and ~equal angle */ + region_grow( list_p->x, list_p->y, angles, reg, ®_size, + ®_angle, used, prec ); + + /* reject small regions */ + if( reg_size < min_reg_size ) continue; + + /* construct rectangular approximation for the region */ + region2rect(reg,reg_size,modgrad,reg_angle,prec,p,&rec); + + /* Check if the rectangle exceeds the minimal density of + region points. If not, try to improve the region. + The rectangle will be rejected if the final one does + not fulfill the minimal density condition. + This is an addition to the original LSD algorithm published in + "LSD: A Fast Line Segment Detector with a False Detection Control" + by R. Grompone von Gioi, J. Jakubowicz, J.M. Morel, and G. Randall. + The original algorithm is obtained with density_th = 0.0. + */ + if( !refine( reg, ®_size, modgrad, reg_angle, + prec, p, &rec, used, angles, density_th ) ) continue; + + /* compute NFA value */ + log_nfa = rect_improve(&rec,angles,logNT,log_eps); + if( log_nfa <= log_eps ) continue; + + /* A New Line Segment was found! */ + ++ls_count; /* increase line segment counter */ + + /* + The gradient was computed with a 2x2 mask, its value corresponds to + points with an offset of (0.5,0.5), that should be added to output. + The coordinates origin is at the center of pixel (0,0). + */ + rec.x1 += 0.5; rec.y1 += 0.5; + rec.x2 += 0.5; rec.y2 += 0.5; + + /* scale the result values if a subsampling was performed */ +// if( scale != 1.0 ) +// { +// rec.x1 /= scale; rec.y1 /= scale; +// rec.x2 /= scale; rec.y2 /= scale; +// rec.width /= scale; +// } + + /* add line segment found to output */ + add_7tuple( out, rec.x1, rec.y1, rec.x2, rec.y2, + rec.width, rec.p, log_nfa ); + +// /* add region number to 'region' image if needed */ +// if( region != NULL ) +// for(i=0; idata[ reg[i].x + reg[i].y * region->xsize ] = ls_count; + } + + + /* free memory */ + free( (void *) image ); /* only the char_image structure should be freed, + the data pointer was provided to this functions + and should not be destroyed. */ + free_image_int(angles); + free_image_int(modgrad); + free_image_char(used); + free( (void *) reg ); + free( (void *) mem_p ); + +// /* return the result */ +// if( reg_img != NULL && reg_x != NULL && reg_y != NULL ) +// { +// if( region == NULL ) error("'region' should be a valid image."); +// *reg_img = region->data; +// if( region->xsize > (unsigned int) INT_MAX || +// region->xsize > (unsigned int) INT_MAX ) +// error("region image to big to fit in INT sizes."); +// *reg_x = (int) (region->xsize); +// *reg_y = (int) (region->ysize); + +// /* free the 'region' structure. +// we cannot use the function 'free_image_int' because we need to keep +// the memory with the image data to be returned by this function. */ +// free( (void *) region ); +// } + if( out->size > (unsigned int) INT_MAX ) + error("too many detections to fit in an INT."); + *n_out = (int) (out->size); + + return_value = out->values; + free( (void *) out ); /* only the 'ntuple_list' structure must be freed, + but the 'values' pointer must be keep to return + as a result. */ + + return return_value; +} + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale and Region output. + */ +double * lsd_scale_region( int * n_out, + unsigned char * img, int X, int Y, double scale, + int ** reg_img, int * reg_x, int * reg_y ) +{ + /* LSD parameters */ + double sigma_scale = 0.6; /* Sigma for Gaussian filter is computed as + sigma = sigma_scale/scale. */ + double quant = 2.0; /* Bound to the quantization error on the + gradient norm. */ + double ang_th = 22.5; /* Gradient angle tolerance in degrees. */ + double log_eps = 0.0; /* Detection threshold: -log10(NFA) > log_eps */ + double density_th = 0.7; /* Minimal density of region points in rectangle. */ + int n_bins = 1024; /* Number of bins in pseudo-ordering of gradient + modulus. */ + + return LineSegmentDetection( n_out, img, X, Y, scale, sigma_scale, quant, + ang_th, log_eps, density_th, n_bins, + reg_img, reg_x, reg_y ); +} + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface with Scale. + */ +double * lsd_scale(int * n_out, unsigned char * img, int X, int Y, double scale) +{ + return lsd_scale_region(n_out,img,X,Y,scale,NULL,NULL,NULL); +} + +/*----------------------------------------------------------------------------*/ +/** LSD Simple Interface. + */ +double * lsd(int * n_out, unsigned char * img, int X, int Y) +{ + /* LSD parameters */ + double scale = 0.8; /* Scale the image by Gaussian filter to 'scale'. */ + + return lsd_scale(n_out,img,X,Y,scale); +} +/*----------------------------------------------------------------------------*/ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void imlib_lsd_find_line_segments(list_t *out, image_t *ptr, rectangle_t *roi, unsigned int merge_distance, unsigned int max_theta_diff) +{ + uint8_t *grayscale_image = fb_alloc(roi->w * roi->h); + uint8_t *grayscale_image_tmp = grayscale_image; + umm_init_x(fb_avail()); + + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + int n_ls; + double *ls = LineSegmentDetection(&n_ls, grayscale_image_tmp, roi->w, roi->h, 0.8, 0.6, 2.0, 22.5, 0.0, 0.7, 1024, NULL, NULL, NULL); + list_init(out, sizeof(find_lines_list_lnk_data_t)); + + for (int i = 0, j = n_ls; i < j; i++) { + find_lines_list_lnk_data_t lnk_line; + + lnk_line.line.x1 = fast_roundf(ls[(7*i)+0]); + lnk_line.line.y1 = fast_roundf(ls[(7*i)+1]); + lnk_line.line.x2 = fast_roundf(ls[(7*i)+2]); + lnk_line.line.y2 = fast_roundf(ls[(7*i)+3]); + + if(lb_clip_line(&lnk_line.line, 0, 0, roi->w, roi->h)) { + lnk_line.line.x1 += roi->x; + lnk_line.line.y1 += roi->y; + lnk_line.line.x2 += roi->x; + lnk_line.line.y2 += roi->y; + + int dx = lnk_line.line.x2 - lnk_line.line.x1, mdx = lnk_line.line.x1 + (dx/2); + int dy = lnk_line.line.y2 - lnk_line.line.y1, mdy = lnk_line.line.y1 + (dy/2); + float rotation = (dx ? fast_atan2f(dy, dx) : 1.570796f) + 1.570796f; // PI/2 + + lnk_line.theta = fast_roundf(rotation * 57.295780) % 180; // * (180 / PI) + if (lnk_line.theta < 0) lnk_line.theta += 180; + lnk_line.rho = fast_roundf((mdx * cos_table[lnk_line.theta]) + (mdy * sin_table[lnk_line.theta])); + + lnk_line.magnitude = fast_roundf(ls[(7*i)+6]); + + list_push_back(out, &lnk_line); + } + } + + if (merge_distance > 0) + { + merge_alot(out, merge_distance, max_theta_diff); + } + + fb_free(); // umm_init_x(); + fb_free(); // grayscale_image; +} + +#pragma GCC diagnostic pop +#endif //IMLIB_ENABLE_FIND_LINE_SEGMENTS diff --git a/src/openmv/src/omv/img/mathop.c b/src/openmv/src/omv/img/mathop.c new file mode 100755 index 0000000..ceccf7b --- /dev/null +++ b/src/openmv/src/omv/img/mathop.c @@ -0,0 +1,639 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +#ifdef IMLIB_ENABLE_MATH_OPS +void imlib_negate(image_t *img) +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, x); + int p = (COLOR_BINARY_MAX - COLOR_BINARY_MIN) - dataPixel; + IMAGE_PUT_BINARY_PIXEL_FAST(data, x, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, x); + int p = (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) - dataPixel; + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, x, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, x); + int r = (COLOR_R5_MAX - COLOR_R5_MIN) - COLOR_RGB565_TO_R5(dataPixel); + int g = (COLOR_G6_MAX - COLOR_G6_MIN) - COLOR_RGB565_TO_G6(dataPixel); + int b = (COLOR_B5_MAX - COLOR_B5_MIN) - COLOR_RGB565_TO_B5(dataPixel); + IMAGE_PUT_RGB565_PIXEL_FAST(data, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +typedef struct imlib_replace_line_op_state { + bool hmirror, vflip; + image_t *mask; +} imlib_replace_line_op_state_t; + +static void imlib_replace_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + bool hmirror = ((imlib_replace_line_op_state_t *) data)->hmirror; + bool vflip = ((imlib_replace_line_op_state_t *) data)->vflip; + image_t *mask = ((imlib_replace_line_op_state_t *) data)->mask; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + int v_line = vflip ? (img->h - line - 1) : line; + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, v_line); + for (int i = 0, j = img->w; i < j; i++) { + int h_i = hmirror ? (img->w - i - 1) : i; + + if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), h_i); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, pixel); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + int v_line = vflip ? (img->h - line - 1) : line; + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, v_line); + for (int i = 0, j = img->w; i < j; i++) { + int h_i = hmirror ? (img->w - i - 1) : i; + + if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), h_i); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, pixel); + } + } + break; + } + case IMAGE_BPP_RGB565: { + int v_line = vflip ? (img->h - line - 1) : line; + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, v_line); + for (int i = 0, j = img->w; i < j; i++) { + int h_i = hmirror ? (img->w - i - 1) : i; + + if ((!mask) || image_get_mask_pixel(mask, h_i, v_line)) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), h_i); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, pixel); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip, image_t *mask) +{ + imlib_replace_line_op_state_t state; + state.hmirror = hmirror; + state.vflip = vflip; + state.mask = mask; + imlib_image_operation(img, path, other, scalar, imlib_replace_line_op, &state); +} + +static void imlib_add_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = dataPixel + otherPixel; + p = IM_MIN(p, COLOR_BINARY_MAX); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = dataPixel + otherPixel; + p = IM_MIN(p, COLOR_GRAYSCALE_MAX); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int r = COLOR_RGB565_TO_R5(dataPixel) + COLOR_RGB565_TO_R5(otherPixel); + int g = COLOR_RGB565_TO_G6(dataPixel) + COLOR_RGB565_TO_G6(otherPixel); + int b = COLOR_RGB565_TO_B5(dataPixel) + COLOR_RGB565_TO_B5(otherPixel); + r = IM_MIN(r, COLOR_R5_MAX); + g = IM_MIN(g, COLOR_G6_MAX); + b = IM_MIN(b, COLOR_B5_MAX); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_add_line_op, mask); +} + +typedef struct imlib_sub_line_op_state { + bool reverse; + image_t *mask; +} imlib_sub_line_op_state_t; + +static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + bool reverse = ((imlib_sub_line_op_state_t *) data)->reverse; + image_t *mask = ((imlib_sub_line_op_state_t *) data)->mask; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = reverse ? (otherPixel - dataPixel) : (dataPixel - otherPixel); + p = IM_MAX(p, COLOR_BINARY_MIN); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = reverse ? (otherPixel - dataPixel) : (dataPixel - otherPixel); + p = IM_MAX(p, COLOR_GRAYSCALE_MIN); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int dR = COLOR_RGB565_TO_R5(dataPixel); + int dG = COLOR_RGB565_TO_G6(dataPixel); + int dB = COLOR_RGB565_TO_B5(dataPixel); + int oR = COLOR_RGB565_TO_R5(otherPixel); + int oG = COLOR_RGB565_TO_G6(otherPixel); + int oB = COLOR_RGB565_TO_B5(otherPixel); + int r = reverse ? (oR - dR) : (dR - oR); + int g = reverse ? (oG - dG) : (dG - oG); + int b = reverse ? (oB - dB) : (dB - oB); + r = IM_MAX(r, COLOR_R5_MIN); + g = IM_MAX(g, COLOR_G6_MIN); + b = IM_MAX(b, COLOR_B5_MIN); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_sub(image_t *img, const char *path, image_t *other, int scalar, bool reverse, image_t *mask) +{ + imlib_sub_line_op_state_t state; + state.reverse = reverse; + state.mask = mask; + imlib_image_operation(img, path, other, scalar, imlib_sub_line_op, &state); +} + +typedef struct imlib_mul_line_op_state { + bool invert; + image_t *mask; +} imlib_mul_line_op_state_t; + +static void imlib_mul_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + bool invert = ((imlib_mul_line_op_state_t *) data)->invert; + image_t *mask = ((imlib_mul_line_op_state_t *) data)->mask; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + float pScale = COLOR_BINARY_MAX - COLOR_BINARY_MIN; + float pDiv = 1 / pScale; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = invert ? (pScale - ((pScale - dataPixel) * (pScale - otherPixel) * pDiv)) + : (dataPixel * otherPixel * pDiv); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + float pScale = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN; + float pDiv = 1 / pScale; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = invert ? (pScale - ((pScale - dataPixel) * (pScale - otherPixel) * pDiv)) + : (dataPixel * otherPixel * pDiv); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + float rScale = COLOR_R5_MAX - COLOR_R5_MIN; + float gScale = COLOR_G6_MAX - COLOR_G6_MIN; + float bScale = COLOR_B5_MAX - COLOR_B5_MIN; + float rDiv = 1 / rScale; + float gDiv = 1 / gScale; + float bDiv = 1 / bScale; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int dR = COLOR_RGB565_TO_R5(dataPixel); + int dG = COLOR_RGB565_TO_G6(dataPixel); + int dB = COLOR_RGB565_TO_B5(dataPixel); + int oR = COLOR_RGB565_TO_R5(otherPixel); + int oG = COLOR_RGB565_TO_G6(otherPixel); + int oB = COLOR_RGB565_TO_B5(otherPixel); + int r = invert ? (rScale - ((rScale - dR) * (rScale - oR) * rDiv)) + : (dR * oR * rDiv); + int g = invert ? (gScale - ((gScale - dG) * (gScale - oG) * gDiv)) + : (dG * oG * gDiv); + int b = invert ? (bScale - ((bScale - dB) * (bScale - oB) * bDiv)) + : (dB * oB * bDiv); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_mul(image_t *img, const char *path, image_t *other, int scalar, bool invert, image_t *mask) +{ + imlib_mul_line_op_state_t state; + state.invert = invert; + state.mask = mask; + imlib_image_operation(img, path, other, scalar, imlib_mul_line_op, &state); +} + +typedef struct imlib_div_line_op_state { + bool invert; + image_t *mask; +} imlib_div_line_op_state_t; + +static void imlib_div_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + bool invert = ((imlib_div_line_op_state_t *) data)->invert; + image_t *mask = ((imlib_div_line_op_state_t *) data)->mask; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + int pScale = COLOR_BINARY_MAX - COLOR_BINARY_MIN; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = IM_DIV((invert?otherPixel:dataPixel) * pScale, (invert?dataPixel:otherPixel)); + p = IM_MIN(p, COLOR_BINARY_MAX); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + int pScale = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = IM_DIV((invert?otherPixel:dataPixel) * pScale, (invert?dataPixel:otherPixel)); + p = IM_MIN(p, COLOR_GRAYSCALE_MAX); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + int rScale = COLOR_R5_MAX - COLOR_R5_MIN; + int gScale = COLOR_G6_MAX - COLOR_G6_MIN; + int bScale = COLOR_B5_MAX - COLOR_B5_MIN; + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int dR = COLOR_RGB565_TO_R5(dataPixel); + int dG = COLOR_RGB565_TO_G6(dataPixel); + int dB = COLOR_RGB565_TO_B5(dataPixel); + int oR = COLOR_RGB565_TO_R5(otherPixel); + int oG = COLOR_RGB565_TO_G6(otherPixel); + int oB = COLOR_RGB565_TO_B5(otherPixel); + int r = IM_DIV((invert?oR:dR) * rScale, (invert?dR:oR)); + int g = IM_DIV((invert?oG:dG) * gScale, (invert?dG:oG)); + int b = IM_DIV((invert?oB:dB) * bScale, (invert?dB:oB)); + r = IM_MIN(r, COLOR_R5_MAX); + g = IM_MIN(g, COLOR_G6_MAX); + b = IM_MIN(b, COLOR_B5_MAX); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_div(image_t *img, const char *path, image_t *other, int scalar, bool invert, image_t *mask) +{ + imlib_div_line_op_state_t state; + state.invert = invert; + state.mask = mask; + imlib_image_operation(img, path, other, scalar, imlib_div_line_op, &state); +} + +static void imlib_min_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = IM_MIN(dataPixel, otherPixel); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = IM_MIN(dataPixel, otherPixel); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int r = IM_MIN(COLOR_RGB565_TO_R5(dataPixel), COLOR_RGB565_TO_R5(otherPixel)); + int g = IM_MIN(COLOR_RGB565_TO_G6(dataPixel), COLOR_RGB565_TO_G6(otherPixel)); + int b = IM_MIN(COLOR_RGB565_TO_B5(dataPixel), COLOR_RGB565_TO_B5(otherPixel)); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_min(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_min_line_op, mask); +} + +static void imlib_max_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = IM_MAX(dataPixel, otherPixel); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = IM_MAX(dataPixel, otherPixel); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int r = IM_MAX(COLOR_RGB565_TO_R5(dataPixel), COLOR_RGB565_TO_R5(otherPixel)); + int g = IM_MAX(COLOR_RGB565_TO_G6(dataPixel), COLOR_RGB565_TO_G6(otherPixel)); + int b = IM_MAX(COLOR_RGB565_TO_B5(dataPixel), COLOR_RGB565_TO_B5(otherPixel)); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_max(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar, imlib_max_line_op, mask); +} + +static void imlib_difference_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + image_t *mask = (image_t *) data; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = abs(dataPixel - otherPixel); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = abs(dataPixel - otherPixel); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int r = abs(COLOR_RGB565_TO_R5(dataPixel) - COLOR_RGB565_TO_R5(otherPixel)); + int g = abs(COLOR_RGB565_TO_G6(dataPixel) - COLOR_RGB565_TO_G6(otherPixel)); + int b = abs(COLOR_RGB565_TO_B5(dataPixel) - COLOR_RGB565_TO_B5(otherPixel)); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_difference(image_t *img, const char *path, image_t *other, int scalar, image_t *mask) +{ + imlib_image_operation(img, path, other, scalar,imlib_difference_line_op, mask); +} + +typedef struct imlib_blend_line_op_state { + float alpha; + image_t *mask; +} imlib_blend_line_op_t; + +static void imlib_blend_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + float alpha = ((imlib_blend_line_op_t *) data)->alpha, beta = 1 - alpha; + image_t *mask = ((imlib_blend_line_op_t *) data)->mask; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i); + int p = (dataPixel * alpha) + (otherPixel * beta); + IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i); + int p = (dataPixel * alpha) + (otherPixel * beta); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p); + } + } + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + for (int i = 0, j = img->w; i < j; i++) { + if ((!mask) || image_get_mask_pixel(mask, i, line)) { + int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i); + int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i); + int r = (COLOR_RGB565_TO_R5(dataPixel) * alpha) + (COLOR_RGB565_TO_R5(otherPixel) * beta); + int g = (COLOR_RGB565_TO_G6(dataPixel) * alpha) + (COLOR_RGB565_TO_G6(otherPixel) * beta); + int b = (COLOR_RGB565_TO_B5(dataPixel) * alpha) + (COLOR_RGB565_TO_B5(otherPixel) * beta); + IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); + } + } + break; + } + default: { + break; + } + } +} + +void imlib_blend(image_t *img, const char *path, image_t *other, int scalar, float alpha, image_t *mask) +{ + imlib_blend_line_op_t state; + state.alpha = alpha; + state.mask = mask; + imlib_image_operation(img, path, other, scalar, imlib_blend_line_op, &state); +} +#endif //IMLIB_ENABLE_MATH_OPS diff --git a/src/openmv/src/omv/img/mjpeg.c b/src/openmv/src/omv/img/mjpeg.c new file mode 100755 index 0000000..41418ad --- /dev/null +++ b/src/openmv/src/omv/img/mjpeg.c @@ -0,0 +1,149 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * A super simple MJPEG encoder. + * + */ +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "imlib.h" + +#define SIZE_OFFSET (1*4) +#define MICROS_OFFSET (8*4) +#define FRAMES_OFFSET (12*4) +#define RATE_0_OFFSET (19*4) +#define LENGTH_0_OFFSET (21*4) +#define RATE_1_OFFSET (33*4) +#define LENGTH_1_OFFSET (35*4) +#define MOVI_OFFSET (54*4) + +void mjpeg_open(FIL *fp, int width, int height) +{ + write_data(fp, "RIFF", 4); // FOURCC fcc; - 0 + write_long(fp, 0); // DWORD cb; size - updated on close - 1 + write_data(fp, "AVI ", 4); // FOURCC fcc; - 2 + + write_data(fp, "LIST", 4); // FOURCC fcc; - 3 + write_long(fp, 192); // DWORD cb; - 4 + write_data(fp, "hdrl", 4); // FOURCC fcc; - 5 + + write_data(fp, "avih", 4); // FOURCC fcc; - 6 + write_long(fp, 56); // DWORD cb; - 7 + write_long(fp, 0); // DWORD dwMicroSecPerFrame; micros - updated on close - 8 + write_long(fp, 0); // DWORD dwMaxBytesPerSec; updated on close - 9 + write_long(fp, 4); // DWORD dwPaddingGranularity; - 10 + write_long(fp, 0); // DWORD dwFlags; - 11 + write_long(fp, 0); // DWORD dwTotalFrames; frames - updated on close - 12 + write_long(fp, 0); // DWORD dwInitialFrames; - 13 + write_long(fp, 1); // DWORD dwStreams; - 14 + write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 15 + write_long(fp, width); // DWORD dwWidth; - 16 + write_long(fp, height); // DWORD dwHeight; - 17 + write_long(fp, 1000); // DWORD dwScale; - 18 + write_long(fp, 0); // DWORD dwRate; rate - updated on close - 19 + write_long(fp, 0); // DWORD dwStart; - 20 + write_long(fp, 0); // DWORD dwLength; length - updated on close - 21 + + write_data(fp, "LIST", 4); // FOURCC fcc; - 22 + write_long(fp, 116); // DWORD cb; - 23 + write_data(fp, "strl", 4); // FOURCC fcc; - 24 + + write_data(fp, "strh", 4); // FOURCC fcc; - 25 + write_long(fp, 56); // DWORD cb; - 26 + write_data(fp, "vids", 4); // FOURCC fccType; - 27 + write_data(fp, "MJPG", 4); // FOURCC fccHandler; - 28 + write_long(fp, 0); // DWORD dwFlags; - 29 + write_word(fp, 0); // WORD wPriority; - 30 + write_word(fp, 0); // WORD wLanguage; - 30.5 + write_long(fp, 0); // DWORD dwInitialFrames; - 31 + write_long(fp, 1000); // DWORD dwScale; - 32 + write_long(fp, 0); // DWORD dwRate; rate - updated on close - 33 + write_long(fp, 0); // DWORD dwStart; - 34 + write_long(fp, 0); // DWORD dwLength; length - updated on close - 35 + write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 36 + write_long(fp, 10000); // DWORD dwQuality; - 37 + write_long(fp, 0); // DWORD dwSampleSize; - 38 + write_word(fp, 0); // short int left; - 39 + write_word(fp, 0); // short int top; - 39.5 + write_word(fp, 0); // short int right; - 40 + write_word(fp, 0); // short int bottom; - 40.5 + + write_data(fp, "strf", 4); // FOURCC fcc; - 41 + write_long(fp, 40); // DWORD cb; - 42 + write_long(fp, 40); // DWORD biSize; - 43 + write_long(fp, width); // LONG biWidth; - 44 + write_long(fp, height); // LONG biHeight; - 45 + write_word(fp, 1); // WORD biPlanes; - 46 + write_word(fp, 24); // WORD biBitCount; - 46.5 + write_data(fp, "MJPG", 4); // DWORD biCompression; - 47 + write_long(fp, 0); // DWORD biSizeImage; - 48 + write_long(fp, 0); // LONG biXPelsPerMeter; - 49 + write_long(fp, 0); // LONG biYPelsPerMeter; - 50 + write_long(fp, 0); // DWORD biClrUsed; - 51 + write_long(fp, 0); // DWORD biClrImportant; - 52 + + write_data(fp, "LIST", 4); // FOURCC fcc; - 53 + write_long(fp, 0); // DWORD cb; movi - updated on close - 54 + write_data(fp, "movi", 4); // FOURCC fcc; - 55 +} + +void mjpeg_add_frame(FIL *fp, uint32_t *frames, uint32_t *bytes, image_t *img, int quality) +{ + write_data(fp, "00dc", 4); // FOURCC fcc; + *frames += 1; + if (IM_IS_JPEG(img)) { + int pad = (((img->bpp + 3) / 4) * 4) - img->bpp; + write_long(fp, img->bpp + pad); // DWORD cb; + write_data(fp, img->pixels, img->bpp + pad); // reading past okay + *bytes += img->bpp + pad; + } else { + uint32_t size; + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=img->w, .h=img->h, .bpp=size, .pixels=buffer }; + // When jpeg_compress needs more memory than in currently allocated it + // will try to realloc. MP will detect that the pointer is outside of + // the heap and return NULL which will cause an out of memory error. + jpeg_compress(img, &out, quality, true); + int pad = (((out.bpp + 3) / 4) * 4) - out.bpp; + write_long(fp, out.bpp + pad); // DWORD cb; + write_data(fp, out.pixels, out.bpp + pad); // reading past okay + *bytes += out.bpp + pad; + fb_free(); + } +} + +void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) +{ + // Needed + file_seek(fp, SIZE_OFFSET); + write_long(fp, 216 + (*frames * 8) + *bytes); + // Needed + file_seek(fp, MICROS_OFFSET); + write_long(fp, (!fast_roundf(fps)) ? 0 : + fast_roundf(1000000 / fps)); + write_long(fp, (!(*frames)) ? 0 : + fast_roundf((((*frames * 8) + *bytes) * fps) / *frames)); + // Needed + file_seek(fp, FRAMES_OFFSET); + write_long(fp, *frames); + // Probably not needed but writing it just in case. + file_seek(fp, RATE_0_OFFSET); + write_long(fp, fast_roundf(fps * 1000)); + // Probably not needed but writing it just in case. + file_seek(fp, LENGTH_0_OFFSET); + write_long(fp, (!fast_roundf(fps)) ? 0 : + fast_roundf((*frames * 1000) / fps)); + // Probably not needed but writing it just in case. + file_seek(fp, RATE_1_OFFSET); + write_long(fp, fast_roundf(fps * 1000)); + // Probably not needed but writing it just in case. + file_seek(fp, LENGTH_1_OFFSET); + write_long(fp, (!fast_roundf(fps)) ? 0 : + fast_roundf((*frames * 1000) / fps)); + // Needed + file_seek(fp, MOVI_OFFSET); + write_long(fp, 4 + (*frames * 8) + *bytes); + file_close(fp); +} diff --git a/src/openmv/src/omv/img/orb.c b/src/openmv/src/omv/img/orb.c new file mode 100755 index 0000000..c39ba7d --- /dev/null +++ b/src/openmv/src/omv/img/orb.c @@ -0,0 +1,803 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * ORB keypoints descriptor based on OpenCV code. + */ + +#include +#include +#include +#include +#include "fmath.h" +#include "ff.h" +#include "imlib.h" +#include "xalloc.h" +#include "fb_alloc.h" + +#define PATCH_SIZE (31) // 31x31 pixels +#define KDESC_SIZE (32) // 32 bytes +#define MAX_KP_DIST (KDESC_SIZE*8) + +typedef struct { + int x; + int y; +} sample_point_t; + +const static int u_max[] = { + 15, 15, 15, 15, 14, 14, 14, 13, + 13, 12, 11, 10, 9, 8, 6, 3, 0 +}; + +const static int sample_pattern[256*4] = { + 8,-3, 9,5/*mean (0), correlation (0)*/, + 4,2, 7,-12/*mean (1.12461e-05), correlation (0.0437584)*/, + -11,9, -8,2/*mean (3.37382e-05), correlation (0.0617409)*/, + 7,-12, 12,-13/*mean (5.62303e-05), correlation (0.0636977)*/, + 2,-13, 2,12/*mean (0.000134953), correlation (0.085099)*/, + 1,-7, 1,6/*mean (0.000528565), correlation (0.0857175)*/, + -2,-10, -2,-4/*mean (0.0188821), correlation (0.0985774)*/, + -13,-13, -11,-8/*mean (0.0363135), correlation (0.0899616)*/, + -13,-3, -12,-9/*mean (0.121806), correlation (0.099849)*/, + 10,4, 11,9/*mean (0.122065), correlation (0.093285)*/, + -13,-8, -8,-9/*mean (0.162787), correlation (0.0942748)*/, + -11,7, -9,12/*mean (0.21561), correlation (0.0974438)*/, + 7,7, 12,6/*mean (0.160583), correlation (0.130064)*/, + -4,-5, -3,0/*mean (0.228171), correlation (0.132998)*/, + -13,2, -12,-3/*mean (0.00997526), correlation (0.145926)*/, + -9,0, -7,5/*mean (0.198234), correlation (0.143636)*/, + 12,-6, 12,-1/*mean (0.0676226), correlation (0.16689)*/, + -3,6, -2,12/*mean (0.166847), correlation (0.171682)*/, + -6,-13, -4,-8/*mean (0.101215), correlation (0.179716)*/, + 11,-13, 12,-8/*mean (0.200641), correlation (0.192279)*/, + 4,7, 5,1/*mean (0.205106), correlation (0.186848)*/, + 5,-3, 10,-3/*mean (0.234908), correlation (0.192319)*/, + 3,-7, 6,12/*mean (0.0709964), correlation (0.210872)*/, + -8,-7, -6,-2/*mean (0.0939834), correlation (0.212589)*/, + -2,11, -1,-10/*mean (0.127778), correlation (0.20866)*/, + -13,12, -8,10/*mean (0.14783), correlation (0.206356)*/, + -7,3, -5,-3/*mean (0.182141), correlation (0.198942)*/, + -4,2, -3,7/*mean (0.188237), correlation (0.21384)*/, + -10,-12, -6,11/*mean (0.14865), correlation (0.23571)*/, + 5,-12, 6,-7/*mean (0.222312), correlation (0.23324)*/, + 5,-6, 7,-1/*mean (0.229082), correlation (0.23389)*/, + 1,0, 4,-5/*mean (0.241577), correlation (0.215286)*/, + 9,11, 11,-13/*mean (0.00338507), correlation (0.251373)*/, + 4,7, 4,12/*mean (0.131005), correlation (0.257622)*/, + 2,-1, 4,4/*mean (0.152755), correlation (0.255205)*/, + -4,-12, -2,7/*mean (0.182771), correlation (0.244867)*/, + -8,-5, -7,-10/*mean (0.186898), correlation (0.23901)*/, + 4,11, 9,12/*mean (0.226226), correlation (0.258255)*/, + 0,-8, 1,-13/*mean (0.0897886), correlation (0.274827)*/, + -13,-2, -8,2/*mean (0.148774), correlation (0.28065)*/, + -3,-2, -2,3/*mean (0.153048), correlation (0.283063)*/, + -6,9, -4,-9/*mean (0.169523), correlation (0.278248)*/, + 8,12, 10,7/*mean (0.225337), correlation (0.282851)*/, + 0,9, 1,3/*mean (0.226687), correlation (0.278734)*/, + 7,-5, 11,-10/*mean (0.00693882), correlation (0.305161)*/, + -13,-6, -11,0/*mean (0.0227283), correlation (0.300181)*/, + 10,7, 12,1/*mean (0.125517), correlation (0.31089)*/, + -6,-3, -6,12/*mean (0.131748), correlation (0.312779)*/, + 10,-9, 12,-4/*mean (0.144827), correlation (0.292797)*/, + -13,8, -8,-12/*mean (0.149202), correlation (0.308918)*/, + -13,0, -8,-4/*mean (0.160909), correlation (0.310013)*/, + 3,3, 7,8/*mean (0.177755), correlation (0.309394)*/, + 5,7, 10,-7/*mean (0.212337), correlation (0.310315)*/, + -1,7, 1,-12/*mean (0.214429), correlation (0.311933)*/, + 3,-10, 5,6/*mean (0.235807), correlation (0.313104)*/, + 2,-4, 3,-10/*mean (0.00494827), correlation (0.344948)*/, + -13,0, -13,5/*mean (0.0549145), correlation (0.344675)*/, + -13,-7, -12,12/*mean (0.103385), correlation (0.342715)*/, + -13,3, -11,8/*mean (0.134222), correlation (0.322922)*/, + -7,12, -4,7/*mean (0.153284), correlation (0.337061)*/, + 6,-10, 12,8/*mean (0.154881), correlation (0.329257)*/, + -9,-1, -7,-6/*mean (0.200967), correlation (0.33312)*/, + -2,-5, 0,12/*mean (0.201518), correlation (0.340635)*/, + -12,5, -7,5/*mean (0.207805), correlation (0.335631)*/, + 3,-10, 8,-13/*mean (0.224438), correlation (0.34504)*/, + -7,-7, -4,5/*mean (0.239361), correlation (0.338053)*/, + -3,-2, -1,-7/*mean (0.240744), correlation (0.344322)*/, + 2,9, 5,-11/*mean (0.242949), correlation (0.34145)*/, + -11,-13, -5,-13/*mean (0.244028), correlation (0.336861)*/, + -1,6, 0,-1/*mean (0.247571), correlation (0.343684)*/, + 5,-3, 5,2/*mean (0.000697256), correlation (0.357265)*/, + -4,-13, -4,12/*mean (0.00213675), correlation (0.373827)*/, + -9,-6, -9,6/*mean (0.0126856), correlation (0.373938)*/, + -12,-10, -8,-4/*mean (0.0152497), correlation (0.364237)*/, + 10,2, 12,-3/*mean (0.0299933), correlation (0.345292)*/, + 7,12, 12,12/*mean (0.0307242), correlation (0.366299)*/, + -7,-13, -6,5/*mean (0.0534975), correlation (0.368357)*/, + -4,9, -3,4/*mean (0.099865), correlation (0.372276)*/, + 7,-1, 12,2/*mean (0.117083), correlation (0.364529)*/, + -7,6, -5,1/*mean (0.126125), correlation (0.369606)*/, + -13,11, -12,5/*mean (0.130364), correlation (0.358502)*/, + -3,7, -2,-6/*mean (0.131691), correlation (0.375531)*/, + 7,-8, 12,-7/*mean (0.160166), correlation (0.379508)*/, + -13,-7, -11,-12/*mean (0.167848), correlation (0.353343)*/, + 1,-3, 12,12/*mean (0.183378), correlation (0.371916)*/, + 2,-6, 3,0/*mean (0.228711), correlation (0.371761)*/, + -4,3, -2,-13/*mean (0.247211), correlation (0.364063)*/, + -1,-13, 1,9/*mean (0.249325), correlation (0.378139)*/, + 7,1, 8,-6/*mean (0.000652272), correlation (0.411682)*/, + 1,-1, 3,12/*mean (0.00248538), correlation (0.392988)*/, + 9,1, 12,6/*mean (0.0206815), correlation (0.386106)*/, + -1,-9, -1,3/*mean (0.0364485), correlation (0.410752)*/, + -13,-13, -10,5/*mean (0.0376068), correlation (0.398374)*/, + 7,7, 10,12/*mean (0.0424202), correlation (0.405663)*/, + 12,-5, 12,9/*mean (0.0942645), correlation (0.410422)*/, + 6,3, 7,11/*mean (0.1074), correlation (0.413224)*/, + 5,-13, 6,10/*mean (0.109256), correlation (0.408646)*/, + 2,-12, 2,3/*mean (0.131691), correlation (0.416076)*/, + 3,8, 4,-6/*mean (0.165081), correlation (0.417569)*/, + 2,6, 12,-13/*mean (0.171874), correlation (0.408471)*/, + 9,-12, 10,3/*mean (0.175146), correlation (0.41296)*/, + -8,4, -7,9/*mean (0.183682), correlation (0.402956)*/, + -11,12, -4,-6/*mean (0.184672), correlation (0.416125)*/, + 1,12, 2,-8/*mean (0.191487), correlation (0.386696)*/, + 6,-9, 7,-4/*mean (0.192668), correlation (0.394771)*/, + 2,3, 3,-2/*mean (0.200157), correlation (0.408303)*/, + 6,3, 11,0/*mean (0.204588), correlation (0.411762)*/, + 3,-3, 8,-8/*mean (0.205904), correlation (0.416294)*/, + 7,8, 9,3/*mean (0.213237), correlation (0.409306)*/, + -11,-5, -6,-4/*mean (0.243444), correlation (0.395069)*/, + -10,11, -5,10/*mean (0.247672), correlation (0.413392)*/, + -5,-8, -3,12/*mean (0.24774), correlation (0.411416)*/, + -10,5, -9,0/*mean (0.00213675), correlation (0.454003)*/, + 8,-1, 12,-6/*mean (0.0293635), correlation (0.455368)*/, + 4,-6, 6,-11/*mean (0.0404971), correlation (0.457393)*/, + -10,12, -8,7/*mean (0.0481107), correlation (0.448364)*/, + 4,-2, 6,7/*mean (0.050641), correlation (0.455019)*/, + -2,0, -2,12/*mean (0.0525978), correlation (0.44338)*/, + -5,-8, -5,2/*mean (0.0629667), correlation (0.457096)*/, + 7,-6, 10,12/*mean (0.0653846), correlation (0.445623)*/, + -9,-13, -8,-8/*mean (0.0858749), correlation (0.449789)*/, + -5,-13, -5,-2/*mean (0.122402), correlation (0.450201)*/, + 8,-8, 9,-13/*mean (0.125416), correlation (0.453224)*/, + -9,-11, -9,0/*mean (0.130128), correlation (0.458724)*/, + 1,-8, 1,-2/*mean (0.132467), correlation (0.440133)*/, + 7,-4, 9,1/*mean (0.132692), correlation (0.454)*/, + -2,1, -1,-4/*mean (0.135695), correlation (0.455739)*/, + 11,-6, 12,-11/*mean (0.142904), correlation (0.446114)*/, + -12,-9, -6,4/*mean (0.146165), correlation (0.451473)*/, + 3,7, 7,12/*mean (0.147627), correlation (0.456643)*/, + 5,5, 10,8/*mean (0.152901), correlation (0.455036)*/, + 0,-4, 2,8/*mean (0.167083), correlation (0.459315)*/, + -9,12, -5,-13/*mean (0.173234), correlation (0.454706)*/, + 0,7, 2,12/*mean (0.18312), correlation (0.433855)*/, + -1,2, 1,7/*mean (0.185504), correlation (0.443838)*/, + 5,11, 7,-9/*mean (0.185706), correlation (0.451123)*/, + 3,5, 6,-8/*mean (0.188968), correlation (0.455808)*/, + -13,-4, -8,9/*mean (0.191667), correlation (0.459128)*/, + -5,9, -3,-3/*mean (0.193196), correlation (0.458364)*/, + -4,-7, -3,-12/*mean (0.196536), correlation (0.455782)*/, + 6,5, 8,0/*mean (0.1972), correlation (0.450481)*/, + -7,6, -6,12/*mean (0.199438), correlation (0.458156)*/, + -13,6, -5,-2/*mean (0.211224), correlation (0.449548)*/, + 1,-10, 3,10/*mean (0.211718), correlation (0.440606)*/, + 4,1, 8,-4/*mean (0.213034), correlation (0.443177)*/, + -2,-2, 2,-13/*mean (0.234334), correlation (0.455304)*/, + 2,-12, 12,12/*mean (0.235684), correlation (0.443436)*/, + -2,-13, 0,-6/*mean (0.237674), correlation (0.452525)*/, + 4,1, 9,3/*mean (0.23962), correlation (0.444824)*/, + -6,-10, -3,-5/*mean (0.248459), correlation (0.439621)*/, + -3,-13, -1,1/*mean (0.249505), correlation (0.456666)*/, + 7,5, 12,-11/*mean (0.00119208), correlation (0.495466)*/, + 4,-2, 5,-7/*mean (0.00372245), correlation (0.484214)*/, + -13,9, -9,-5/*mean (0.00741116), correlation (0.499854)*/, + 7,1, 8,6/*mean (0.0208952), correlation (0.499773)*/, + 7,-8, 7,6/*mean (0.0220085), correlation (0.501609)*/, + -7,-4, -7,1/*mean (0.0233806), correlation (0.496568)*/, + -8,11, -7,-8/*mean (0.0236505), correlation (0.489719)*/, + -13,6, -12,-8/*mean (0.0268781), correlation (0.503487)*/, + 2,4, 3,9/*mean (0.0323324), correlation (0.501938)*/, + 10,-5, 12,3/*mean (0.0399235), correlation (0.494029)*/, + -6,-5, -6,7/*mean (0.0420153), correlation (0.486579)*/, + 8,-3, 9,-8/*mean (0.0548021), correlation (0.484237)*/, + 2,-12, 2,8/*mean (0.0616622), correlation (0.496642)*/, + -11,-2, -10,3/*mean (0.0627755), correlation (0.498563)*/, + -12,-13, -7,-9/*mean (0.0829622), correlation (0.495491)*/, + -11,0, -10,-5/*mean (0.0843342), correlation (0.487146)*/, + 5,-3, 11,8/*mean (0.0929937), correlation (0.502315)*/, + -2,-13, -1,12/*mean (0.113327), correlation (0.48941)*/, + -1,-8, 0,9/*mean (0.132119), correlation (0.467268)*/, + -13,-11, -12,-5/*mean (0.136269), correlation (0.498771)*/, + -10,-2, -10,11/*mean (0.142173), correlation (0.498714)*/, + -3,9, -2,-13/*mean (0.144141), correlation (0.491973)*/, + 2,-3, 3,2/*mean (0.14892), correlation (0.500782)*/, + -9,-13, -4,0/*mean (0.150371), correlation (0.498211)*/, + -4,6, -3,-10/*mean (0.152159), correlation (0.495547)*/, + -4,12, -2,-7/*mean (0.156152), correlation (0.496925)*/, + -6,-11, -4,9/*mean (0.15749), correlation (0.499222)*/, + 6,-3, 6,11/*mean (0.159211), correlation (0.503821)*/, + -13,11, -5,5/*mean (0.162427), correlation (0.501907)*/, + 11,11, 12,6/*mean (0.16652), correlation (0.497632)*/, + 7,-5, 12,-2/*mean (0.169141), correlation (0.484474)*/, + -1,12, 0,7/*mean (0.169456), correlation (0.495339)*/, + -4,-8, -3,-2/*mean (0.171457), correlation (0.487251)*/, + -7,1, -6,7/*mean (0.175), correlation (0.500024)*/, + -13,-12, -8,-13/*mean (0.175866), correlation (0.497523)*/, + -7,-2, -6,-8/*mean (0.178273), correlation (0.501854)*/, + -8,5, -6,-9/*mean (0.181107), correlation (0.494888)*/, + -5,-1, -4,5/*mean (0.190227), correlation (0.482557)*/, + -13,7, -8,10/*mean (0.196739), correlation (0.496503)*/, + 1,5, 5,-13/*mean (0.19973), correlation (0.499759)*/, + 1,0, 10,-13/*mean (0.204465), correlation (0.49873)*/, + 9,12, 10,-1/*mean (0.209334), correlation (0.49063)*/, + 5,-8, 10,-9/*mean (0.211134), correlation (0.503011)*/, + -1,11, 1,-13/*mean (0.212), correlation (0.499414)*/, + -9,-3, -6,2/*mean (0.212168), correlation (0.480739)*/, + -1,-10, 1,12/*mean (0.212731), correlation (0.502523)*/, + -13,1, -8,-10/*mean (0.21327), correlation (0.489786)*/, + 8,-11, 10,-6/*mean (0.214159), correlation (0.488246)*/, + 2,-13, 3,-6/*mean (0.216993), correlation (0.50287)*/, + 7,-13, 12,-9/*mean (0.223639), correlation (0.470502)*/, + -10,-10, -5,-7/*mean (0.224089), correlation (0.500852)*/, + -10,-8, -8,-13/*mean (0.228666), correlation (0.502629)*/, + 4,-6, 8,5/*mean (0.22906), correlation (0.498305)*/, + 3,12, 8,-13/*mean (0.233378), correlation (0.503825)*/, + -4,2, -3,-3/*mean (0.234323), correlation (0.476692)*/, + 5,-13, 10,-12/*mean (0.236392), correlation (0.475462)*/, + 4,-13, 5,-1/*mean (0.236842), correlation (0.504132)*/, + -9,9, -4,3/*mean (0.236977), correlation (0.497739)*/, + 0,3, 3,-9/*mean (0.24314), correlation (0.499398)*/, + -12,1, -6,1/*mean (0.243297), correlation (0.489447)*/, + 3,2, 4,-8/*mean (0.00155196), correlation (0.553496)*/, + -10,-10, -10,9/*mean (0.00239541), correlation (0.54297)*/, + 8,-13, 12,12/*mean (0.0034413), correlation (0.544361)*/, + -8,-12, -6,-5/*mean (0.003565), correlation (0.551225)*/, + 2,2, 3,7/*mean (0.00835583), correlation (0.55285)*/, + 10,6, 11,-8/*mean (0.00885065), correlation (0.540913)*/, + 6,8, 8,-12/*mean (0.0101552), correlation (0.551085)*/, + -7,10, -6,5/*mean (0.0102227), correlation (0.533635)*/, + -3,-9, -3,9/*mean (0.0110211), correlation (0.543121)*/, + -1,-13, -1,5/*mean (0.0113473), correlation (0.550173)*/, + -3,-7, -3,4/*mean (0.0140913), correlation (0.554774)*/, + -8,-2, -8,3/*mean (0.017049), correlation (0.55461)*/, + 4,2, 12,12/*mean (0.01778), correlation (0.546921)*/, + 2,-5, 3,11/*mean (0.0224022), correlation (0.549667)*/, + 6,-9, 11,-13/*mean (0.029161), correlation (0.546295)*/, + 3,-1, 7,12/*mean (0.0303081), correlation (0.548599)*/, + 11,-1, 12,4/*mean (0.0355151), correlation (0.523943)*/, + -3,0, -3,6/*mean (0.0417904), correlation (0.543395)*/, + 4,-11, 4,12/*mean (0.0487292), correlation (0.542818)*/, + 2,-4, 2,1/*mean (0.0575124), correlation (0.554888)*/, + -10,-6, -8,1/*mean (0.0594242), correlation (0.544026)*/, + -13,7, -11,1/*mean (0.0597391), correlation (0.550524)*/, + -13,12, -11,-13/*mean (0.0608974), correlation (0.55383)*/, + 6,0, 11,-13/*mean (0.065126), correlation (0.552006)*/, + 0,-1, 1,4/*mean (0.074224), correlation (0.546372)*/, + -13,3, -9,-2/*mean (0.0808592), correlation (0.554875)*/, + -9,8, -6,-3/*mean (0.0883378), correlation (0.551178)*/, + -13,-6, -8,-2/*mean (0.0901035), correlation (0.548446)*/, + 5,-9, 8,10/*mean (0.0949843), correlation (0.554694)*/, + 2,7, 3,-9/*mean (0.0994152), correlation (0.550979)*/, + -1,-6, -1,-1/*mean (0.10045), correlation (0.552714)*/, + 9,5, 11,-2/*mean (0.100686), correlation (0.552594)*/, + 11,-3, 12,-8/*mean (0.101091), correlation (0.532394)*/, + 3,0, 3,5/*mean (0.101147), correlation (0.525576)*/, + -1,4, 0,10/*mean (0.105263), correlation (0.531498)*/, + 3,-6, 4,5/*mean (0.110785), correlation (0.540491)*/, + -13,0, -10,5/*mean (0.112798), correlation (0.536582)*/, + 5,8, 12,11/*mean (0.114181), correlation (0.555793)*/, + 8,9, 9,-6/*mean (0.117431), correlation (0.553763)*/, + 7,-4, 8,-12/*mean (0.118522), correlation (0.553452)*/, + -10,4, -10,9/*mean (0.12094), correlation (0.554785)*/, + 7,3, 12,4/*mean (0.122582), correlation (0.555825)*/, + 9,-7, 10,-2/*mean (0.124978), correlation (0.549846)*/, + 7,0, 12,-2/*mean (0.127002), correlation (0.537452)*/, + -1,-6, 0,-11/*mean (0.127148), correlation (0.547401)*/ +}; + +static int kpt_comp(const kp_t *kp1, const kp_t *kp2) +{ + // Descending order + return kp2->score - kp1->score; +} + +static int comp_angle(image_t *img, kp_t *kp, float *a, float *b) +{ + int step = img->w; + int half_k = 31/2; + int m_01 = 0, m_10 = 0; + uint8_t *center = img->pixels+(kp->y*img->w+kp->x); + + // Treat the center line differently, v=0 + for (int u = -half_k; u <= half_k; ++u) { + m_10 += u * center[u]; + } + + // Go line by line in the circular patch + for (int v = 1; v <= half_k; ++v) { + // Proceed over the two lines + int v_sum = 0; + int d = u_max[v]; + for (int u = -d; u <= d; ++u) { + int val_plus = center[u + v*step], val_minus = center[u - v*step]; + v_sum += (val_plus - val_minus); + m_10 += u * (val_plus + val_minus); + } + m_01 += v * v_sum; + } + + int angle = (int) (atan2f((float)m_01, (float)m_10) * (180.0f/M_PI)); + if (angle < 0) { + angle += 360; + } + + // Quantize angle to 15 degrees + angle = angle - (angle % 15); + + *a = cos_table[angle]; + *b = sin_table[angle]; + return angle; +} + +static void image_scale(image_t *src, image_t *dst) +{ + int x_ratio = (int)((src->w<<16)/dst->w) +1; + int y_ratio = (int)((src->h<<16)/dst->h) +1; + + for (int y=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++) { + int sx = (x*x_ratio)>>16; + dst->pixels[y*dst->w+x] = IM_TO_GS_PIXEL(src, sx, sy); + } + } +} + +array_t *orb_find_keypoints(image_t *img, bool normalized, int threshold, + float scale_factor, int max_keypoints, corner_detector_t corner_detector, rectangle_t *roi) +{ + array_t *kpts; + array_alloc(&kpts, xfree); + + int octave = 1; + int kpts_index = 0; + rectangle_t roi_scaled; + + for(float scale=1.0f; ; scale*=scale_factor, octave++) { + image_t img_scaled = { + .bpp = 1, + .w = (int) roundf(img->w/scale), + .h = (int) roundf(img->h/scale), + .pixels = NULL + }; + + // Add patch size to ROI + roi_scaled.x = (int) roundf(roi->x/scale) + (PATCH_SIZE); + roi_scaled.y = (int) roundf(roi->y/scale) + (PATCH_SIZE); + roi_scaled.w = (int) roundf(roi->w/scale) - (PATCH_SIZE*2); + roi_scaled.h = (int) roundf(roi->h/scale) - (PATCH_SIZE*2); + + if (roi_scaled.w <= (PATCH_SIZE*2) || + roi_scaled.h <= (PATCH_SIZE*2)) { + break; + } + + img_scaled.pixels = fb_alloc(img_scaled.w * img_scaled.h); + // Down scale image + image_scale(img, &img_scaled); + + // Gaussian smooth the image before extracting keypoints + imlib_sepconv3(&img_scaled, kernel_gauss_3, 1.0f/16.0f, 0.0f); + + // Find kpts + #ifdef IMLIB_ENABLE_FAST + if (corner_detector == CORNER_FAST) { + fast_detect(&img_scaled, kpts, threshold, &roi_scaled); + } + else + #endif + { + agast_detect(&img_scaled, kpts, threshold, &roi_scaled); + } + + for (int k=kpts_index; koctave = octave; + + int x, y; + float a, b; + sample_point_t *pattern = (sample_point_t*) sample_pattern; + kpt->angle = comp_angle(&img_scaled, kpt, &a, &b); + + #if 1 + #define GET_VALUE(idx) \ + (x = (int) roundf(pattern[idx].x*a - pattern[idx].y*b), \ + y = (int) roundf(pattern[idx].x*b + pattern[idx].y*a), \ + img_scaled.pixels[((kpt->y+y)*img_scaled.w)+(kpt->x+x)]) + #else + #define GET_VALUE(idx) \ + (img_scaled.pixels[((kpt->y+pattern[idx].y)*img_scaled.w)+(kpt->x+pattern[idx].x)]) + #endif + + for (int i=0; i t0 ) t0 = t1, u = 1; + if( t3 > t2 ) t2 = t3, v = 3; + k = t0 > t2 ? u : v; + val = k; + + t0 = GET_VALUE(4); t1 = GET_VALUE(5); + t2 = GET_VALUE(6); t3 = GET_VALUE(7); + u = 0, v = 2; + if( t1 > t0 ) t0 = t1, u = 1; + if( t3 > t2 ) t2 = t3, v = 3; + k = t0 > t2 ? u : v; + val |= k << 2; + + t0 = GET_VALUE(8); t1 = GET_VALUE(9); + t2 = GET_VALUE(10); t3 = GET_VALUE(11); + u = 0, v = 2; + if( t1 > t0 ) t0 = t1, u = 1; + if( t3 > t2 ) t2 = t3, v = 3; + k = t0 > t2 ? u : v; + val |= k << 4; + + t0 = GET_VALUE(12); t1 = GET_VALUE(13); + t2 = GET_VALUE(14); t3 = GET_VALUE(15); + u = 0, v = 2; + if( t1 > t0 ) t0 = t1, u = 1; + if( t3 > t2 ) t2 = t3, v = 3; + k = t0 > t2 ? u : v; + val |= k << 6; + + kpt->desc[i] = (uint8_t) val; + } + + kpt->x = (int)floorf(kpt->x * scale); + kpt->y = (int)floorf(kpt->y * scale); + } + + // Free current scale + fb_free(); + + if (normalized) { + break; + } + } + + // Sort keypoints by score and return top n keypoints + array_sort(kpts, (array_comp_t) kpt_comp); + if (array_length(kpts) > max_keypoints) { + array_resize(kpts, max_keypoints); + } + + return kpts; +} + +// This is a modifed popcount that counts every 2 different bits as 1. +// This is what should actually be used with wta_k == 3 or 4. +static inline uint32_t popcount(uint32_t i) +{ + i = i - ((i >> 1) & 0x55555555); + i = ((i & 0xAAAAAAAA)>>1) | (i & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; +} + +static kp_t *find_best_match(kp_t *kp1, array_t *kpts, int *dist_out1, int *dist_out2, int *index) +{ + kp_t *min_kp=NULL; + int min_dist1 = MAX_KP_DIST; + int min_dist2 = MAX_KP_DIST; + int kpts_size = array_length(kpts); + + for (int i=0; imatched == 0) { + for (int m=0; m<(KDESC_SIZE/4); m++) { + dist += popcount(((uint32_t*)(kp1->desc))[m] ^ ((uint32_t*)(kp2->desc))[m]); + } + + if (dist < min_dist1) { + *index = i; + min_kp = kp2; + min_dist2 = min_dist1; + min_dist1 = dist; + } + } + } + + *dist_out1 = min_dist1; + *dist_out2 = min_dist2; + return min_kp; +} + +int orb_match_keypoints(array_t *kpts1, array_t *kpts2, int *match, int threshold, rectangle_t *r, point_t *c, int *angle) +{ + int matches=0; + int cx = 0, cy = 0; + uint16_t angles[360]={0}; + int kpts1_size = array_length(kpts1); + + r->w = r->h = 0; + r->x = r->y = 20000; + + // Match keypoints and find "good matches" This runs 2/3 tests found in the RobustMatcher from the OpenCV programming cookbook. + // The first test is based on the distance ratio between the two best matches for a feature, to remove ambiguous matches. + // Second test is the symmetry test (corss-matching) both points in a match must be the best matching feature of each other. + for (int i=0; i threshold) { + continue; + } + + // Cross-match the keypoint in the first set + kp_t *kp2 = find_best_match(min_kp, kpts1, &min_dist1, &min_dist2, &kp_index1); + // Test the distance ratio between the best two matches + if ((min_dist1*100/min_dist2) > threshold) { + continue; + } + + // Cross-match test + if (kp1 == kp2) { + int x, y; + matches++; + min_kp->matched = 1; + cx += x = min_kp->x; + cy += y = min_kp->y; + rectangle_expand(r, x, y); + int angle = (int) abs(min_kp->angle-kp1->angle); + if (angle >= 0 && angle < 360) { + angles[angle]++; + } + *match++ = kp_index1; + *match++ = kp_index2; + } + } + + if (matches == 0) { + r->x = r->y = 0; + return 0; + } + + // Fix centroid x/y + c->x = cx/matches; + c->y = cy/matches; + + // Fix rectangle w/h + r->w = r->w - r->x; + r->h = r->h - r->y; + + int max_angle = 0; + for (int i=0; i<360; i++) { + if (angles[i] > max_angle) { + max_angle = angles[i]; + *angle = i; + } + } + + return matches; +} + +int orb_filter_keypoints(array_t *kpts, rectangle_t *r, point_t *c) +{ + int matches=0; + int cx = 0, cy = 0; + int kpts_size = array_length(kpts); + + r->w = r->h = 0; + r->x = r->y = 20000; + + float *kpts_dist = fb_alloc(kpts_size * sizeof(float)); + + // Find centroid + for (int i=0; imatched) { + matches ++; + cx += kp->x; + cy += kp->y; + } + } + + // Centroid + cx /= matches; + cy /= matches; + + // Find mean distance from centroid + float mdist = 0.0f; + for (int i=0; imatched) { + kpts_dist[i] = orb_cluster_dist(cx, cy, kp); + mdist += kpts_dist[i]; + } + } + // Mean distance from centroid + mdist /= matches; + + // Find variance + float var = 0.0f; + for (int i=0; imatched) { + float dist = kpts_dist[i]; + var += (mdist - dist) * (mdist - dist); + } + } + + // Find standard deviation + float stdist = fast_sqrtf(var/matches); + + // Reset centroid + matches = 0; + cx = cy = 0; + + // Remove outliers and get new centroid + for (int i=0; imatched) { + float dist = fabs(mdist - kpts_dist[i]); + if (dist > stdist) { + kp->matched = 0; + } else { + int x, y; + matches++; + cx += x = kp->x; + cy += y = kp->y; + rectangle_expand(r, x, y); + } + } + } + + // Fix centroid x/y + c->x = cx/matches; + c->y = cy/matches; + + // Fix rectangle w/h + r->w = r->w - r->x; + r->h = r->h - r->y; + + // Free distance array + fb_free(); + return matches; +} + +int orb_save_descriptor(FIL *fp, array_t *kpts) +{ + UINT bytes; + FRESULT res; + + int kpts_size = array_length(kpts); + + // Write the number of keypoints + res = f_write(fp, &kpts_size, sizeof(kpts_size), &bytes); + if (res != FR_OK || bytes != sizeof(kpts_size)) { + goto error; + } + + // Write keypoints + for (int i=0; ix, sizeof(kp->x), &bytes); + if (res != FR_OK || bytes != sizeof(kp->x)) { + goto error; + } + + // Write Y + res = f_write(fp, &kp->y, sizeof(kp->y), &bytes); + if (res != FR_OK || bytes != sizeof(kp->y)) { + goto error; + } + + // Write Score + res = f_write(fp, &kp->score, sizeof(kp->score), &bytes); + if (res != FR_OK || bytes != sizeof(kp->score)) { + goto error; + } + + // Write Octave + res = f_write(fp, &kp->octave, sizeof(kp->octave), &bytes); + if (res != FR_OK || bytes != sizeof(kp->octave)) { + goto error; + } + + // Write Angle + res = f_write(fp, &kp->angle, sizeof(kp->angle), &bytes); + if (res != FR_OK || bytes != sizeof(kp->angle)) { + goto error; + } + + // Write descriptor + res = f_write(fp, kp->desc, KDESC_SIZE, &bytes); + if (res != FR_OK || bytes != KDESC_SIZE) { + goto error; + } + } + +error: + return res; +} + +int orb_load_descriptor(FIL *fp, array_t *kpts) +{ + UINT bytes; + FRESULT res=FR_OK; + + int kpts_size=0; + + // Read number of keypoints + res = f_read(fp, &kpts_size, sizeof(kpts_size), &bytes); + if (res != FR_OK || bytes != sizeof(kpts_size)) { + goto error; + } + + // Read keypoints + for (int i=0; imatched = 0; + + // Read X + res = f_read(fp, &kp->x, sizeof(kp->x), &bytes); + if (res != FR_OK || bytes != sizeof(kp->x)) { + goto error; + } + + // Read Y + res = f_read(fp, &kp->y, sizeof(kp->y), &bytes); + if (res != FR_OK || bytes != sizeof(kp->y)) { + goto error; + } + + // Read Score + res = f_read(fp, &kp->score, sizeof(kp->score), &bytes); + if (res != FR_OK || bytes != sizeof(kp->score)) { + goto error; + } + + // Read Octave + res = f_read(fp, &kp->octave, sizeof(kp->octave), &bytes); + if (res != FR_OK || bytes != sizeof(kp->octave)) { + goto error; + } + + // Read Angle + res = f_read(fp, &kp->angle, sizeof(kp->angle), &bytes); + if (res != FR_OK || bytes != sizeof(kp->angle)) { + goto error; + } + + // Read descriptor + res = f_read(fp, kp->desc, KDESC_SIZE, &bytes); + if (res != FR_OK || bytes != KDESC_SIZE) { + goto error; + } + + // Add keypoint to array + array_push_back(kpts, kp); + } + +error: + return res; +} + +float orb_cluster_dist(int cx, int cy, void *kp_in) +{ + float sum=0.0f; + kp_t *kp = kp_in; + sum += (cx - kp->x) * (cx - kp->x); + sum += (cy - kp->y) * (cy - kp->y); + return fast_sqrtf(sum); + +} diff --git a/src/openmv/src/omv/img/phasecorrelation.c b/src/openmv/src/omv/img/phasecorrelation.c new file mode 100755 index 0000000..15025dc --- /dev/null +++ b/src/openmv/src/omv/img/phasecorrelation.c @@ -0,0 +1,487 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" +#include "fft.h" +#define alt_fast_exp(x, linear) ((linear) ? (x) : (fast_expf(x))) +#define alt_fast_log(x, linear) ((linear) ? (x) : (fast_log(x))) + +void imlib_logpolar_int(image_t *dst, image_t *src, rectangle_t *roi, bool linear, bool reverse) +{ + float w_2 = roi->w / 2.0f; + float h_2 = roi->h / 2.0f; + float rho_scale = alt_fast_log(fast_sqrtf((w_2 * w_2) + (h_2 * h_2)), linear) / roi->h; + float rho_scale_inv = 1.0 / rho_scale; + float theta_scale = 360.0f / roi->w; + float theta_scale_inv = 1.0 / theta_scale; + + switch (src->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(dst, y); + float rho = y * rho_scale; + for (int x = 0, xx = roi->w; x < xx; x++) { + int sourceX, sourceY; + + if (!reverse) { + int theta = 630 - fast_roundf(x * theta_scale); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf((alt_fast_exp(rho, linear) * cos_table[theta]) + w_2); + sourceY = fast_roundf((alt_fast_exp(rho, linear) * sin_table[theta]) + h_2); + } else { + float x_2 = x - w_2; + float y_2 = y - h_2; + float rho = alt_fast_log(fast_sqrtf((x_2 * x_2) + (y_2 * y_2)), linear); + int theta = 630 - (x_2 ? fast_roundf(fast_atan2f(y_2, x_2) * (180 / M_PI)) : ((y_2 < 0) ? 270 : 90)); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf(theta * theta_scale_inv); + sourceY = fast_roundf(rho * rho_scale_inv); + } + + if ((0 <= sourceX) && (sourceX < roi->w) && (0 <= sourceY) && (sourceY < roi->h)) { + uint32_t *ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(src, (sourceY + roi->y)); + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(ptr, (sourceX + roi->x)); + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(dst, y); + float rho = y * rho_scale; + for (int x = 0, xx = roi->w; x < xx; x++) { + int sourceX, sourceY; + + if (!reverse) { + int theta = 630 - fast_roundf(x * theta_scale); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf((alt_fast_exp(rho, linear) * cos_table[theta]) + w_2); + sourceY = fast_roundf((alt_fast_exp(rho, linear) * sin_table[theta]) + h_2); + } else { + float x_2 = x - w_2; + float y_2 = y - h_2; + float rho = alt_fast_log(fast_sqrtf((x_2 * x_2) + (y_2 * y_2)), linear); + int theta = 630 - (x_2 ? fast_roundf(fast_atan2f(y_2, x_2) * (180 / M_PI)) : ((y_2 < 0) ? 270 : 90)); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf(theta * theta_scale_inv); + sourceY = fast_roundf(rho * rho_scale_inv); + } + + if ((0 <= sourceX) && (sourceX < roi->w) && (0 <= sourceY) && (sourceY < roi->h)) { + uint8_t *ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(src, (sourceY + roi->y)); + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(ptr, (sourceX + roi->x)); + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(dst, y); + float rho = y * rho_scale; + for (int x = 0, xx = roi->w; x < xx; x++) { + int sourceX, sourceY; + + if (!reverse) { + int theta = 630 - fast_roundf(x * theta_scale); + if (theta >= 360) theta -= 360; + sourceX = fast_roundf((alt_fast_exp(rho, linear) * cos_table[theta]) + w_2); + sourceY = fast_roundf((alt_fast_exp(rho, linear) * sin_table[theta]) + h_2); + } else { + float x_2 = x - w_2; + float y_2 = y - h_2; + float rho = alt_fast_log(fast_sqrtf((x_2 * x_2) + (y_2 * y_2)), linear); + int theta = 630 - (x_2 ? fast_roundf(fast_atan2f(y_2, x_2) * (180 / M_PI)) : ((y_2 < 0) ? 270 : 90)); + if (theta >= 360) theta -= 360; + sourceX = IM_MIN(IM_MAX(fast_roundf(theta * theta_scale_inv), 0), (roi->w-1)); + sourceY = IM_MIN(IM_MAX(fast_roundf(rho * rho_scale_inv), 0), (roi->h-1)); + } + + if ((0 <= sourceX) && (sourceX < roi->w) && (0 <= sourceY) && (sourceY < roi->h)) { + uint16_t *ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(src, (sourceY + roi->y)); + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(ptr, (sourceX + roi->x)); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + break; + } + default: { + break; + } + } +} + +#if defined(IMLIB_ENABLE_LOGPOLAR) || defined(IMLIB_ENABLE_LINPOLAR) +void imlib_logpolar(image_t *img, bool linear, bool reverse) +{ + image_t img_2; + img_2.w = img->w; + img_2.h = img->h; + img_2.bpp = img->bpp; + img_2.data = fb_alloc(image_size(img)); + + rectangle_t rect; + rect.x = 0; + rect.y = 0; + rect.w = img->w; + rect.h = img->h; + + memcpy(img_2.data, img->data, image_size(img)); + memset(img->data, 0, image_size(img)); + imlib_logpolar_int(img, &img_2, &rect, linear, reverse); + fb_free(); +} +#endif //defined(IMLIB_ENABLE_LOGPOLAR) || defined(IMLIB_ENABLE_LINPOLAR) + +#ifdef IMLIB_ENABLE_FIND_DISPLACEMENT +// Note that both ROI widths and heights must be equal. +void imlib_phasecorrelate(image_t *img0, image_t *img1, rectangle_t *roi0, rectangle_t *roi1, bool logpolar, bool fix_rotation_scale, + float *x_translation, float *y_translation, float *rotation, float *scale, float *response) +{ + // Step 1 - Get Rotation/Scale Differences + if ((!logpolar) && fix_rotation_scale) { + fft2d_controller_t fft0, fft1; + + fft2d_alloc(&fft0, img0, roi0); + fft2d_alloc(&fft1, img1, roi1); + + fft2d_run(&fft0); + fft2d_run(&fft1); + + fft2d_mag(&fft0); + fft2d_mag(&fft1); + + fft2d_swap(&fft0); + fft2d_swap(&fft1); + + fft2d_logpolar(&fft0); + fft2d_logpolar(&fft1); + + fft2d_run_again(&fft0); + fft2d_run_again(&fft1); + + int w = (1 << fft0.w_pow2); + int h = (1 << fft0.h_pow2); + + for (int i = 0, j = h * w * 2; i < j; i += 2) { + float ga_r = fft0.data[i+0]; + float ga_i = fft0.data[i+1]; + float gb_r = fft1.data[i+0]; + float gb_i = -fft1.data[i+1]; // complex conjugate... + float hp_r = (ga_r * gb_r) - (ga_i * gb_i); // hadamard product + float hp_i = (ga_r * gb_i) + (ga_i * gb_r); // hadamard product + float mag = 1 / fast_sqrtf((hp_r*hp_r)+(hp_i*hp_i)); // magnitude + // Replace first fft with phase correlation... + fft0.data[i+0] = hp_r * mag; + fft0.data[i+1] = hp_i * mag; + } + + ifft2d_run(&fft0); + + float sum = 0; + float max = 0; + int off_x = 0; + int off_y = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + // Note that the output of the FFT is packed with real data in both + // the real and imaginary parts... (right side of the array is zero). + float f_r = fft0.data[(i * w * 2) + j]; + sum += f_r; + if (f_r > max) { + max = f_r; + off_x = j; + off_y = i; + } + } + } + + float tmp_response = max / sum; // normalize this to [0:1]. + + float f_sum = 0; + float f_off_x = 0; + float f_off_y = 0; + + for (int i = -2; i < 2; i++) { + for (int j = -2; j < 2; j++) { + + // Wrap around + int new_x = off_x + j; + if (new_x < 0) new_x += w; + if (new_x >= w) new_x -= w; + + // Wrap around + int new_y = off_y + i; + if (new_y < 0) new_y += h; + if (new_y >= h) new_y -= h; + + // Compute centroid. + float f_r = fft0.data[(new_y * w * 2) + new_x]; + f_off_x += (off_x + j) * f_r; // don't use new_x here + f_off_y += (off_y + i) * f_r; // don't use new_y here + f_sum += f_r; + } + } + + f_off_x /= f_sum; + f_off_y /= f_sum; + + // FFT Shift X + if (f_off_x >= (w/2.0f)) { + f_off_x = f_off_x - w; + } else { + f_off_x = f_off_x; + } + + // FFT Shift Y + if (f_off_y >= (h/2.0f)) { + f_off_y = -(f_off_y - h); + } else { + f_off_y = -f_off_y; + } + + if ((f_off_x < (-w/2.0f)) + || ((w/2.0f) <= f_off_x) + || (f_off_y < (-h/2.0f)) + || ((h/2.0f) <= f_off_y) + || isnanf(f_off_x) + || isinff(f_off_x) + || isnanf(f_off_y) + || isinff(f_off_y) + || isnanf(tmp_response) + || isinff(tmp_response)) { // Noise Filter + f_off_x = 0; + f_off_y = 0; + tmp_response = 0; + } + + fft2d_dealloc(); // fft1 + fft2d_dealloc(); // fft0 + + float w_2 = roi0->w / 2.0f; + float h_2 = roi0->h / 2.0f; + float rho_scale = fast_log(fast_sqrtf((w_2 * w_2) + (h_2 * h_2))) / roi0->h; + float theta_scale = (2 * M_PI) / roi0->w; + + *rotation = f_off_x * theta_scale; + *scale = (f_off_y * rho_scale) + 1; + } else { + *rotation = 0; + *scale = 0; + } + + image_t img0_fixed; + rectangle_t roi0_fixed; + + // Step 2 - Fix Rotation/Scale Differences + if ((!logpolar) && fix_rotation_scale) { + + img0_fixed.w = roi0->w; + img0_fixed.h = roi0->h; + img0_fixed.bpp = img0->bpp; + img0_fixed.data = fb_alloc(image_size(&img0_fixed)); + + roi0_fixed.x = 0; + roi0_fixed.y = 0; + roi0_fixed.w = roi0->w; + roi0_fixed.h = roi0->h; + + switch(img0->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi0->y, yy = roi0->y + roi0->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img0, y); + for (int x = roi0->x, xx = roi0->x + roi0->w; x < xx; x++) { + IMAGE_PUT_BINARY_PIXEL(&img0_fixed, x, y, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi0->y, yy = roi0->y + roi0->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img0, y); + for (int x = roi0->x, xx = roi0->x + roi0->w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL(&img0_fixed, x, y, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi0->y, yy = roi0->y + roi0->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img0, y); + for (int x = roi0->x, xx = roi0->x + roi0->w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL(&img0_fixed, x, y, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(img0_fixed.data, 0, image_size(&img0_fixed)); + break; + } + } + + imlib_rotation_corr(&img0_fixed, 0, 0, *rotation, 0, 0, *scale); + } else { + memcpy(&img0_fixed, img0, sizeof(image_t)); + memcpy(&roi0_fixed, roi0, sizeof(rectangle_t)); + } + + // Step 3 - Get Translation Differences + { + image_t img0alt, img1alt; + rectangle_t roi0alt, roi1alt; + + if (logpolar) { + img0alt.w = roi0_fixed.w; + img0alt.h = roi0_fixed.h; + img0alt.bpp = img0_fixed.bpp; + img0alt.data = fb_alloc0(image_size(&img0alt)); + imlib_logpolar_int(&img0alt, &img0_fixed, &roi0_fixed, false, false); + roi0alt.x = 0; + roi0alt.y = 0; + roi0alt.w = roi0_fixed.w; + roi0alt.h = roi0_fixed.h; + + img1alt.w = roi1->w; + img1alt.h = roi1->h; + img1alt.bpp = img1->bpp; + img1alt.data = fb_alloc0(image_size(&img1alt)); + imlib_logpolar_int(&img1alt, img1, roi1, false, false); + roi1alt.x = 0; + roi1alt.y = 0; + roi1alt.w = roi1->w; + roi1alt.h = roi1->h; + } + + fft2d_controller_t fft0, fft1; + + fft2d_alloc(&fft0, logpolar ? &img0alt : &img0_fixed, logpolar ? &roi0alt : &roi0_fixed); + fft2d_alloc(&fft1, logpolar ? &img1alt : img1, logpolar ? &roi1alt : roi1); + + fft2d_run(&fft0); + fft2d_run(&fft1); + + int w = (1 << fft0.w_pow2); + int h = (1 << fft0.h_pow2); + + for (int i = 0, j = h * w * 2; i < j; i += 2) { + float ga_r = fft0.data[i+0]; + float ga_i = fft0.data[i+1]; + float gb_r = fft1.data[i+0]; + float gb_i = -fft1.data[i+1]; // complex conjugate... + float hp_r = (ga_r * gb_r) - (ga_i * gb_i); // hadamard product + float hp_i = (ga_r * gb_i) + (ga_i * gb_r); // hadamard product + float mag = 1 / fast_sqrtf((hp_r*hp_r)+(hp_i*hp_i)); // magnitude + fft0.data[i+0] = hp_r * mag; + fft0.data[i+1] = hp_i * mag; + } + + ifft2d_run(&fft0); + + float sum = 0; + float max = 0; + int off_x = 0; + int off_y = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + // Note that the output of the FFT is packed with real data in both + // the real and imaginary parts... (right side of the array is zero). + float f_r = fft0.data[(i * w * 2) + j]; + sum += f_r; + if (f_r > max) { + max = f_r; + off_x = j; + off_y = i; + } + } + } + + *response = max / sum; // normalize this to [0:1]. + + float f_sum = 0; + float f_off_x = 0; + float f_off_y = 0; + + for (int i = -2; i < 2; i++) { + for (int j = -2; j < 2; j++) { + + // Wrap around + int new_x = off_x + j; + if (new_x < 0) new_x += w; + if (new_x >= w) new_x -= w; + + // Wrap around + int new_y = off_y + i; + if (new_y < 0) new_y += h; + if (new_y >= h) new_y -= h; + + // Compute centroid. + float f_r = fft0.data[(new_y * w * 2) + new_x]; + f_off_x += (off_x + j) * f_r; // don't use new_x here + f_off_y += (off_y + i) * f_r; // don't use new_y here + f_sum += f_r; + } + } + + f_off_x /= f_sum; + f_off_y /= f_sum; + + // FFT Shift X + if (f_off_x >= (w/2.0f)) { + *x_translation = f_off_x - w; + } else { + *x_translation = f_off_x; + } + + // FFT Shift Y + if (f_off_y >= (h/2.0f)) { + *y_translation = -(f_off_y - h); + } else { + *y_translation = -f_off_y; + } + + if ((*x_translation < (-w/2.0f)) + || ((w/2.0f) <= *x_translation) + || (*y_translation < (-h/2.0f)) + || ((h/2.0f) <= *y_translation) + || isnanf(*x_translation) + || isinff(*x_translation) + || isnanf(*y_translation) + || isinff(*y_translation) + || isnanf(*response) + || isinff(*response)) { // Noise Filter + *x_translation = 0; + *y_translation = 0; + *response = 0; + } + + fft2d_dealloc(); // fft1 + fft2d_dealloc(); // fft0 + + if (logpolar) { + fb_free(); // img1alt + fb_free(); // img0alt + + float w_2 = roi0->w / 2.0f; + float h_2 = roi0->h / 2.0f; + float rho_scale = fast_log(fast_sqrtf((w_2 * w_2) + (h_2 * h_2))) / roi0->h; + float theta_scale = (2 * M_PI) / roi0->w; + + *rotation = *x_translation * theta_scale; + *scale = (*y_translation * rho_scale) + 1; + *x_translation = 0; + *y_translation = 0; + } + } + + if ((!logpolar) && fix_rotation_scale) fb_free(); +} +#endif //IMLIB_ENABLE_FIND_DISPLACEMENT diff --git a/src/openmv/src/omv/img/point.c b/src/openmv/src/omv/img/point.c new file mode 100755 index 0000000..508216f --- /dev/null +++ b/src/openmv/src/omv/img/point.c @@ -0,0 +1,31 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Point functions. + * + */ +#include "imlib.h" +#include "xalloc.h" + +point_t *point_alloc(int16_t x, int16_t y) +{ + point_t *p = xalloc(sizeof(point_t)); + p->x = x; + p->y = y; + return p; +} + +bool point_equal(point_t *p1, point_t *p2) +{ + return ((p1->x==p2->x)&&(p1->y==p2->y)); +} + +float point_distance(point_t *p1, point_t *p2) +{ + float sum=0.0f; + sum += (p1->x - p2->x) * (p1->x - p2->x); + sum += (p1->y - p2->y) * (p1->y - p2->y); + return fast_sqrtf(sum); +} diff --git a/src/openmv/src/omv/img/pool.c b/src/openmv/src/omv/img/pool.c new file mode 100755 index 0000000..3b2c064 --- /dev/null +++ b/src/openmv/src/omv/img/pool.c @@ -0,0 +1,95 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Image pooling. + * + */ +#include "imlib.h" + +void imlib_midpoint_pool(image_t *img_i, image_t *img_o, int x_div, int y_div, const int bias) +{ + int min_bias = (256-bias); + int max_bias = bias; + if (IM_IS_GS(img_i)) { + for (int y = 0, yy = img_i->h / y_div; y < yy; y++) { + for (int x = 0, xx = img_i->w / x_div; x < xx; x++) { + int min = 255, max = 0; + for (int i = 0; i < y_div; i++) { + for (int j = 0; j < x_div; j++) { + const uint8_t pixel = IM_GET_GS_PIXEL(img_i, (x * x_div) + j, (y * y_div) + i); + min = IM_MIN(min, pixel); + max = IM_MAX(max, pixel); + } + } + IM_SET_GS_PIXEL(img_o, x, y, + ((min*min_bias)+(max*max_bias))>>8); + } + } + } else { + for (int y = 0, yy = img_i->h / y_div; y < yy; y++) { + for (int x = 0, xx = img_i->w / x_div; x < xx; x++) { + int r_min = 255, r_max = 0; + int g_min = 255, g_max = 0; + int b_min = 255, b_max = 0; + for (int i = 0; i < y_div; i++) { + for (int j = 0; j < x_div; j++) { + const uint16_t pixel = IM_GET_RGB565_PIXEL(img_i, (x * x_div) + j, (y * y_div) + i); + int red = IM_R565(pixel); + int green = IM_G565(pixel); + int blue = IM_B565(pixel); + r_min = IM_MIN(r_min, red); + r_max = IM_MAX(r_max, red); + g_min = IM_MIN(g_min, green); + g_max = IM_MAX(g_max, green); + b_min = IM_MIN(b_min, blue); + b_max = IM_MAX(b_max, blue); + } + } + IM_SET_RGB565_PIXEL(img_o, x, y, + IM_RGB565(((r_min*min_bias)+(r_max*max_bias))>>8, + ((g_min*min_bias)+(g_max*max_bias))>>8, + ((b_min*min_bias)+(b_max*max_bias))>>8)); + } + } + } +} + +void imlib_mean_pool(image_t *img_i, image_t *img_o, int x_div, int y_div) +{ + int n = x_div * y_div; + if (IM_IS_GS(img_i)) { + for (int y = 0, yy = img_i->h / y_div; y < yy; y++) { + for (int x = 0, xx = img_i->w / x_div; x < xx; x++) { + int acc = 0; + for (int i = 0; i < y_div; i++) { + for (int j = 0; j < x_div; j++) { + const uint8_t pixel = IM_GET_GS_PIXEL(img_i, (x * x_div) + j, (y * y_div) + i); + acc += pixel; + } + } + IM_SET_GS_PIXEL(img_o, x, y, + acc / n); + } + } + } else { + for (int y = 0, yy = img_i->h / y_div; y < yy; y++) { + for (int x = 0, xx = img_i->w / x_div; x < xx; x++) { + int r_acc = 0; + int g_acc = 0; + int b_acc = 0; + for (int i = 0; i < y_div; i++) { + for (int j = 0; j < x_div; j++) { + uint16_t pixel = IM_GET_RGB565_PIXEL(img_i, (x * x_div) + j, (y * y_div) + i); + r_acc += IM_R565(pixel); + g_acc += IM_G565(pixel); + b_acc += IM_B565(pixel); + } + } + IM_SET_RGB565_PIXEL(img_o, x, y, + IM_RGB565(r_acc / n, g_acc / n, b_acc / n)); + } + } + } +} diff --git a/src/openmv/src/omv/img/ppm.c b/src/openmv/src/omv/img/ppm.c new file mode 100755 index 0000000..ceb2e4f --- /dev/null +++ b/src/openmv/src/omv/img/ppm.c @@ -0,0 +1,163 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * PPM/PGM reader/writer. + * + */ +#include +#include +#include "ff_wrapper.h" +#include "xalloc.h" +#include "imlib.h" + +static void read_int_reset(ppm_read_settings_t *rs) +{ + rs->read_int_c_valid = false; +} + +static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs) +{ + enum { EAT_WHITESPACE, EAT_COMMENT, EAT_NUMBER } mode = EAT_WHITESPACE; + for(*i = 0;;) { + if (!rs->read_int_c_valid) { + if (file_tell_w_buf(fp) == file_size_w_buf(fp)) return; + read_byte(fp, &rs->read_int_c); + rs->read_int_c_valid = true; + } + if (mode == EAT_WHITESPACE) { + if (rs->read_int_c == '#') { + mode = EAT_COMMENT; + } else if (('0' <= rs->read_int_c) && (rs->read_int_c <= '9')) { + *i = rs->read_int_c - '0'; + mode = EAT_NUMBER; + } + } else if (mode == EAT_COMMENT) { + if ((rs->read_int_c == '\n') || (rs->read_int_c == '\r')) { + mode = EAT_WHITESPACE; + } + } else if (mode == EAT_NUMBER) { + if (('0' <= rs->read_int_c) && (rs->read_int_c <= '9')) { + *i = (*i * 10) + rs->read_int_c - '0'; + } else { + return; // read_int_c_valid==true on exit + } + } + rs->read_int_c_valid = false; + } +} + +// This function inits the geometry values of an image. +void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs) +{ + read_int_reset(rs); + read_byte_expect(fp, 'P'); + read_byte(fp, &rs->ppm_fmt); + if ((rs->ppm_fmt!='2') && (rs->ppm_fmt!='3') && (rs->ppm_fmt!='5') && (rs->ppm_fmt!='6')) ff_unsupported_format(fp); + img->bpp = ((rs->ppm_fmt == '2') || (rs->ppm_fmt == '5')) ? 1 : 2; + + read_int(fp, (uint32_t *) &img->w, rs); + read_int(fp, (uint32_t *) &img->h, rs); + if ((img->w == 0) || (img->h == 0)) ff_file_corrupted(fp); + + uint32_t max; + read_int(fp, &max, rs); + if (max != 255) ff_unsupported_format(fp); +} + +// This function reads the pixel values of an image. +void ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, ppm_read_settings_t *rs) +{ + if (rs->ppm_fmt == '2') { + for (int i = line_start; i < line_end; i++) { + for (int j = 0; j < img->w; j++) { + uint32_t pixel; + read_int(fp, &pixel, rs); + IM_SET_GS_PIXEL(img, j, i, pixel); + } + } + } else if (rs->ppm_fmt == '3') { + for (int i = line_start; i < line_end; i++) { + for (int j = 0; j < img->w; j++) { + uint32_t r, g, b; + read_int(fp, &r, rs); + read_int(fp, &g, rs); + read_int(fp, &b, rs); + IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r), + IM_G826(g), + IM_B825(b))); + } + } + } else if (rs->ppm_fmt == '5') { + read_data(fp, // Super Fast - Zoom, Zoom! + img->pixels + (line_start * img->w), + (line_end - line_start) * img->w); + } else if (rs->ppm_fmt == '6') { + for (int i = line_start; i < line_end; i++) { + for (int j = 0; j < img->w; j++) { + uint8_t r, g, b; + read_byte(fp, &r); + read_byte(fp, &g); + read_byte(fp, &b); + IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r), + IM_G826(g), + IM_B825(b))); + } + } + } +} + +void ppm_read(image_t *img, const char *path) +{ + FIL fp; + ppm_read_settings_t rs; + file_read_open(&fp, path); + file_buffer_on(&fp); + ppm_read_geometry(&fp, img, path, &rs); + if (!img->pixels) img->pixels = xalloc(img->w * img->h * img->bpp); + ppm_read_pixels(&fp, img, 0, img->h, &rs); + file_buffer_off(&fp); + file_close(&fp); +} + +void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r) +{ + rectangle_t rect; + if (!rectangle_subimg(img, r, &rect)) ff_no_intersection(NULL); + FIL fp; + file_write_open(&fp, path); + + file_buffer_on(&fp); + if (IM_IS_GS(img)) { + char buffer[20]; // exactly big enough for 5-digit w/h + int len = snprintf(buffer, 20, "P5\n%d %d\n255\n", rect.w, rect.h); + write_data(&fp, buffer, len); + if ((rect.x == 0) && (rect.w == img->w)) { + write_data(&fp, // Super Fast - Zoom, Zoom! + img->pixels + (rect.y * img->w), + rect.w * rect.h); + } else { + for (int i = 0; i < rect.h; i++) { + write_data(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w); + } + } + } else { + char buffer[20]; // exactly big enough for 5-digit w/h + int len = snprintf(buffer, 20, "P6\n%d %d\n255\n", rect.w, rect.h); + write_data(&fp, buffer, len); + for (int i = 0; i < rect.h; i++) { + for (int j = 0; j < rect.w; j++) { + int pixel = IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i)); + char buff[3]; + buff[0] = IM_R528(IM_R565(pixel)); + buff[1] = IM_G628(IM_G565(pixel)); + buff[2] = IM_B528(IM_B565(pixel)); + write_data(&fp, buff, 3); + } + } + } + file_buffer_off(&fp); + + file_close(&fp); +} diff --git a/src/openmv/src/omv/img/qrcode.c b/src/openmv/src/omv/img/qrcode.c new file mode 100755 index 0000000..dcc7a69 --- /dev/null +++ b/src/openmv/src/omv/img/qrcode.c @@ -0,0 +1,3014 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" +#ifdef IMLIB_ENABLE_QRCODES +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "quirc.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct quirc; + +/* Obtain the library version string. */ +const char *quirc_version(void); + +/* Construct a new QR-code recognizer. This function will return NULL + * if sufficient memory could not be allocated. + */ +struct quirc *quirc_new(void); + +/* Destroy a QR-code recognizer. */ +void quirc_destroy(struct quirc *q); + +/* Resize the QR-code recognizer. The size of an image must be + * specified before codes can be analyzed. + * + * This function returns 0 on success, or -1 if sufficient memory could + * not be allocated. + */ +int quirc_resize(struct quirc *q, int w, int h); + +/* These functions are used to process images for QR-code recognition. + * quirc_begin() must first be called to obtain access to a buffer into + * which the input image should be placed. Optionally, the current + * width and height may be returned. + * + * After filling the buffer, quirc_end() should be called to process + * the image for QR-code recognition. The locations and content of each + * code may be obtained using accessor functions described below. + */ +uint8_t *quirc_begin(struct quirc *q, int *w, int *h); +void quirc_end(struct quirc *q); + +/* This structure describes a location in the input image buffer. */ +struct quirc_point { + int x; + int y; +}; + +/* This enum describes the various decoder errors which may occur. */ +typedef enum { + QUIRC_SUCCESS = 0, + QUIRC_ERROR_INVALID_GRID_SIZE, + QUIRC_ERROR_INVALID_VERSION, + QUIRC_ERROR_FORMAT_ECC, + QUIRC_ERROR_DATA_ECC, + QUIRC_ERROR_UNKNOWN_DATA_TYPE, + QUIRC_ERROR_DATA_OVERFLOW, + QUIRC_ERROR_DATA_UNDERFLOW +} quirc_decode_error_t; + +/* Return a string error message for an error code. */ +const char *quirc_strerror(quirc_decode_error_t err); + +/* Limits on the maximum size of QR-codes and their content. */ +#define QUIRC_MAX_BITMAP 3917 +#define QUIRC_MAX_PAYLOAD 8896 + +/* QR-code ECC types. */ +#define QUIRC_ECC_LEVEL_M 0 +#define QUIRC_ECC_LEVEL_L 1 +#define QUIRC_ECC_LEVEL_H 2 +#define QUIRC_ECC_LEVEL_Q 3 + +/* QR-code data types. */ +#define QUIRC_DATA_TYPE_NUMERIC 1 +#define QUIRC_DATA_TYPE_ALPHA 2 +#define QUIRC_DATA_TYPE_BYTE 4 +#define QUIRC_DATA_TYPE_KANJI 8 + +/* Common character encodings */ +#define QUIRC_ECI_ISO_8859_1 1 +#define QUIRC_ECI_IBM437 2 +#define QUIRC_ECI_ISO_8859_2 4 +#define QUIRC_ECI_ISO_8859_3 5 +#define QUIRC_ECI_ISO_8859_4 6 +#define QUIRC_ECI_ISO_8859_5 7 +#define QUIRC_ECI_ISO_8859_6 8 +#define QUIRC_ECI_ISO_8859_7 9 +#define QUIRC_ECI_ISO_8859_8 10 +#define QUIRC_ECI_ISO_8859_9 11 +#define QUIRC_ECI_WINDOWS_874 13 +#define QUIRC_ECI_ISO_8859_13 15 +#define QUIRC_ECI_ISO_8859_15 17 +#define QUIRC_ECI_SHIFT_JIS 20 +#define QUIRC_ECI_UTF_8 26 + +/* This structure is used to return information about detected QR codes + * in the input image. + */ +struct quirc_code { + /* The four corners of the QR-code, from top left, clockwise */ + struct quirc_point corners[4]; + + /* The number of cells across in the QR-code. The cell bitmap + * is a bitmask giving the actual values of cells. If the cell + * at (x, y) is black, then the following bit is set: + * + * cell_bitmap[i >> 3] & (1 << (i & 7)) + * + * where i = (y * size) + x. + */ + int size; + uint8_t cell_bitmap[QUIRC_MAX_BITMAP]; +}; + +/* This structure holds the decoded QR-code data */ +struct quirc_data { + /* Various parameters of the QR-code. These can mostly be + * ignored if you only care about the data. + */ + int version; + int ecc_level; + int mask; + + /* This field is the highest-valued data type found in the QR + * code. + */ + int data_type; + + /* Data payload. For the Kanji datatype, payload is encoded as + * Shift-JIS. For all other datatypes, payload is ASCII text. + */ + uint8_t payload[QUIRC_MAX_PAYLOAD]; + int payload_len; + + /* ECI assignment number */ + uint32_t eci; +}; + +/* Return the number of QR-codes identified in the last processed + * image. + */ +int quirc_count(const struct quirc *q); + +/* Extract the QR-code specified by the given index. */ +void quirc_extract(const struct quirc *q, int index, + struct quirc_code *code); + +/* Decode a QR-code, returning the payload data. */ +quirc_decode_error_t quirc_decode(const struct quirc_code *code, + struct quirc_data *data); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "quirc_internal.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define QUIRC_PIXEL_WHITE 0 +#define QUIRC_PIXEL_BLACK 1 +#define QUIRC_PIXEL_REGION 2 + +#ifndef QUIRC_MAX_REGIONS +#define QUIRC_MAX_REGIONS 254 +#endif + +#define QUIRC_MAX_CAPSTONES 32 +#define QUIRC_MAX_GRIDS 8 + +#define QUIRC_PERSPECTIVE_PARAMS 8 + +#if QUIRC_MAX_REGIONS < UINT8_MAX +typedef uint8_t quirc_pixel_t; +#elif QUIRC_MAX_REGIONS < UINT16_MAX +typedef uint16_t quirc_pixel_t; +#else +#error "QUIRC_MAX_REGIONS > 65534 is not supported" +#endif + +struct quirc_region { + struct quirc_point seed; + int count; + int capstone; +}; + +struct quirc_capstone { + int ring; + int stone; + + struct quirc_point corners[4]; + struct quirc_point center; + float c[QUIRC_PERSPECTIVE_PARAMS]; + + int qr_grid; +}; + +struct quirc_grid { + /* Capstone indices */ + int caps[3]; + + /* Alignment pattern region and corner */ + int align_region; + struct quirc_point align; + + /* Timing pattern endpoints */ + struct quirc_point tpep[3]; + int hscan; + int vscan; + + /* Grid size and perspective transform */ + int grid_size; + float c[QUIRC_PERSPECTIVE_PARAMS]; +}; + +struct quirc { + uint8_t *image; + quirc_pixel_t *pixels; + int w; + int h; + + int num_regions; + struct quirc_region regions[QUIRC_MAX_REGIONS]; + + int num_capstones; + struct quirc_capstone capstones[QUIRC_MAX_CAPSTONES]; + + int num_grids; + struct quirc_grid grids[QUIRC_MAX_GRIDS]; +}; + +/************************************************************************ + * QR-code version information database + */ + +#define QUIRC_MAX_VERSION 40 +#define QUIRC_MAX_ALIGNMENT 7 + +struct quirc_rs_params { + uint8_t bs; /* Small block size */ + uint8_t dw; /* Small data words */ + uint8_t ns; /* Number of small blocks */ +}; + +struct quirc_version_info { + uint16_t data_bytes; + uint8_t apat[QUIRC_MAX_ALIGNMENT]; + struct quirc_rs_params ecc[4]; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "version_db.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1] = { + {0}, + { /* Version 1 */ + .data_bytes = 26, + .apat = {0}, + .ecc = { + {.bs = 26, .dw = 16, .ns = 1}, + {.bs = 26, .dw = 19, .ns = 1}, + {.bs = 26, .dw = 9, .ns = 1}, + {.bs = 26, .dw = 13, .ns = 1} + } + }, + { /* Version 2 */ + .data_bytes = 44, + .apat = {6, 18, 0}, + .ecc = { + {.bs = 44, .dw = 28, .ns = 1}, + {.bs = 44, .dw = 34, .ns = 1}, + {.bs = 44, .dw = 16, .ns = 1}, + {.bs = 44, .dw = 22, .ns = 1} + } + }, + { /* Version 3 */ + .data_bytes = 70, + .apat = {6, 22, 0}, + .ecc = { + {.bs = 70, .dw = 44, .ns = 1}, + {.bs = 70, .dw = 55, .ns = 1}, + {.bs = 35, .dw = 13, .ns = 2}, + {.bs = 35, .dw = 17, .ns = 2} + } + }, + { /* Version 4 */ + .data_bytes = 100, + .apat = {6, 26, 0}, + .ecc = { + {.bs = 50, .dw = 32, .ns = 2}, + {.bs = 100, .dw = 80, .ns = 1}, + {.bs = 25, .dw = 9, .ns = 4}, + {.bs = 50, .dw = 24, .ns = 2} + } + }, + { /* Version 5 */ + .data_bytes = 134, + .apat = {6, 30, 0}, + .ecc = { + {.bs = 67, .dw = 43, .ns = 2}, + {.bs = 134, .dw = 108, .ns = 1}, + {.bs = 33, .dw = 11, .ns = 2}, + {.bs = 33, .dw = 15, .ns = 2} + } + }, + { /* Version 6 */ + .data_bytes = 172, + .apat = {6, 34, 0}, + .ecc = { + {.bs = 43, .dw = 27, .ns = 4}, + {.bs = 86, .dw = 68, .ns = 2}, + {.bs = 43, .dw = 15, .ns = 4}, + {.bs = 43, .dw = 19, .ns = 4} + } + }, + { /* Version 7 */ + .data_bytes = 196, + .apat = {6, 22, 38, 0}, + .ecc = { + {.bs = 49, .dw = 31, .ns = 4}, + {.bs = 98, .dw = 78, .ns = 2}, + {.bs = 39, .dw = 13, .ns = 4}, + {.bs = 32, .dw = 14, .ns = 2} + } + }, + { /* Version 8 */ + .data_bytes = 242, + .apat = {6, 24, 42, 0}, + .ecc = { + {.bs = 60, .dw = 38, .ns = 2}, + {.bs = 121, .dw = 97, .ns = 2}, + {.bs = 40, .dw = 14, .ns = 4}, + {.bs = 40, .dw = 18, .ns = 4} + } + }, + { /* Version 9 */ + .data_bytes = 292, + .apat = {6, 26, 46, 0}, + .ecc = { + {.bs = 58, .dw = 36, .ns = 3}, + {.bs = 146, .dw = 116, .ns = 2}, + {.bs = 36, .dw = 12, .ns = 4}, + {.bs = 36, .dw = 16, .ns = 4} + } + }, + { /* Version 10 */ + .data_bytes = 346, + .apat = {6, 28, 50, 0}, + .ecc = { + {.bs = 69, .dw = 43, .ns = 4}, + {.bs = 86, .dw = 68, .ns = 2}, + {.bs = 43, .dw = 15, .ns = 6}, + {.bs = 43, .dw = 19, .ns = 6} + } + }, + { /* Version 11 */ + .data_bytes = 404, + .apat = {6, 30, 54, 0}, + .ecc = { + {.bs = 80, .dw = 50, .ns = 1}, + {.bs = 101, .dw = 81, .ns = 4}, + {.bs = 36, .dw = 12, .ns = 3}, + {.bs = 50, .dw = 22, .ns = 4} + } + }, + { /* Version 12 */ + .data_bytes = 466, + .apat = {6, 32, 58, 0}, + .ecc = { + {.bs = 58, .dw = 36, .ns = 6}, + {.bs = 116, .dw = 92, .ns = 2}, + {.bs = 42, .dw = 14, .ns = 7}, + {.bs = 46, .dw = 20, .ns = 4} + } + }, + { /* Version 13 */ + .data_bytes = 532, + .apat = {6, 34, 62, 0}, + .ecc = { + {.bs = 59, .dw = 37, .ns = 8}, + {.bs = 133, .dw = 107, .ns = 4}, + {.bs = 33, .dw = 11, .ns = 12}, + {.bs = 44, .dw = 20, .ns = 8} + } + }, + { /* Version 14 */ + .data_bytes = 581, + .apat = {6, 26, 46, 66, 0}, + .ecc = { + {.bs = 64, .dw = 40, .ns = 4}, + {.bs = 145, .dw = 115, .ns = 3}, + {.bs = 36, .dw = 12, .ns = 11}, + {.bs = 36, .dw = 16, .ns = 11} + } + }, + { /* Version 15 */ + .data_bytes = 655, + .apat = {6, 26, 48, 70, 0}, + .ecc = { + {.bs = 65, .dw = 41, .ns = 5}, + {.bs = 109, .dw = 87, .ns = 5}, + {.bs = 36, .dw = 12, .ns = 11}, + {.bs = 54, .dw = 24, .ns = 5} + } + }, + { /* Version 16 */ + .data_bytes = 733, + .apat = {6, 26, 50, 74, 0}, + .ecc = { + {.bs = 73, .dw = 45, .ns = 7}, + {.bs = 122, .dw = 98, .ns = 5}, + {.bs = 45, .dw = 15, .ns = 3}, + {.bs = 43, .dw = 19, .ns = 15} + } + }, + { /* Version 17 */ + .data_bytes = 815, + .apat = {6, 30, 54, 78, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 10}, + {.bs = 135, .dw = 107, .ns = 1}, + {.bs = 42, .dw = 14, .ns = 2}, + {.bs = 50, .dw = 22, .ns = 1} + } + }, + { /* Version 18 */ + .data_bytes = 901, + .apat = {6, 30, 56, 82, 0}, + .ecc = { + {.bs = 69, .dw = 43, .ns = 9}, + {.bs = 150, .dw = 120, .ns = 5}, + {.bs = 42, .dw = 14, .ns = 2}, + {.bs = 50, .dw = 22, .ns = 17} + } + }, + { /* Version 19 */ + .data_bytes = 991, + .apat = {6, 30, 58, 86, 0}, + .ecc = { + {.bs = 70, .dw = 44, .ns = 3}, + {.bs = 141, .dw = 113, .ns = 3}, + {.bs = 39, .dw = 13, .ns = 9}, + {.bs = 47, .dw = 21, .ns = 17} + } + }, + { /* Version 20 */ + .data_bytes = 1085, + .apat = {6, 34, 62, 90, 0}, + .ecc = { + {.bs = 67, .dw = 41, .ns = 3}, + {.bs = 135, .dw = 107, .ns = 3}, + {.bs = 43, .dw = 15, .ns = 15}, + {.bs = 54, .dw = 24, .ns = 15} + } + }, + { /* Version 21 */ + .data_bytes = 1156, + .apat = {6, 28, 50, 72, 92, 0}, + .ecc = { + {.bs = 68, .dw = 42, .ns = 17}, + {.bs = 144, .dw = 116, .ns = 4}, + {.bs = 46, .dw = 16, .ns = 19}, + {.bs = 50, .dw = 22, .ns = 17} + } + }, + { /* Version 22 */ + .data_bytes = 1258, + .apat = {6, 26, 50, 74, 98, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 17}, + {.bs = 139, .dw = 111, .ns = 2}, + {.bs = 37, .dw = 13, .ns = 34}, + {.bs = 54, .dw = 24, .ns = 7} + } + }, + { /* Version 23 */ + .data_bytes = 1364, + .apat = {6, 30, 54, 78, 102, 0}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 4}, + {.bs = 151, .dw = 121, .ns = 4}, + {.bs = 45, .dw = 15, .ns = 16}, + {.bs = 54, .dw = 24, .ns = 11} + } + }, + { /* Version 24 */ + .data_bytes = 1474, + .apat = {6, 28, 54, 80, 106, 0}, + .ecc = { + {.bs = 73, .dw = 45, .ns = 6}, + {.bs = 147, .dw = 117, .ns = 6}, + {.bs = 46, .dw = 16, .ns = 30}, + {.bs = 54, .dw = 24, .ns = 11} + } + }, + { /* Version 25 */ + .data_bytes = 1588, + .apat = {6, 32, 58, 84, 110, 0}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 8}, + {.bs = 132, .dw = 106, .ns = 8}, + {.bs = 45, .dw = 15, .ns = 22}, + {.bs = 54, .dw = 24, .ns = 7} + } + }, + { /* Version 26 */ + .data_bytes = 1706, + .apat = {6, 30, 58, 86, 114, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 19}, + {.bs = 142, .dw = 114, .ns = 10}, + {.bs = 46, .dw = 16, .ns = 33}, + {.bs = 50, .dw = 22, .ns = 28} + } + }, + { /* Version 27 */ + .data_bytes = 1828, + .apat = {6, 34, 62, 90, 118, 0}, + .ecc = { + {.bs = 73, .dw = 45, .ns = 22}, + {.bs = 152, .dw = 122, .ns = 8}, + {.bs = 45, .dw = 15, .ns = 12}, + {.bs = 53, .dw = 23, .ns = 8} + } + }, + { /* Version 28 */ + .data_bytes = 1921, + .apat = {6, 26, 50, 74, 98, 122, 0}, + .ecc = { + {.bs = 73, .dw = 45, .ns = 3}, + {.bs = 147, .dw = 117, .ns = 3}, + {.bs = 45, .dw = 15, .ns = 11}, + {.bs = 54, .dw = 24, .ns = 4} + } + }, + { /* Version 29 */ + .data_bytes = 2051, + .apat = {6, 30, 54, 78, 102, 126, 0}, + .ecc = { + {.bs = 73, .dw = 45, .ns = 21}, + {.bs = 146, .dw = 116, .ns = 7}, + {.bs = 45, .dw = 15, .ns = 19}, + {.bs = 53, .dw = 23, .ns = 1} + } + }, + { /* Version 30 */ + .data_bytes = 2185, + .apat = {6, 26, 52, 78, 104, 130, 0}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 19}, + {.bs = 145, .dw = 115, .ns = 5}, + {.bs = 45, .dw = 15, .ns = 23}, + {.bs = 54, .dw = 24, .ns = 15} + } + }, + { /* Version 31 */ + .data_bytes = 2323, + .apat = {6, 30, 56, 82, 108, 134, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 2}, + {.bs = 145, .dw = 115, .ns = 13}, + {.bs = 45, .dw = 15, .ns = 23}, + {.bs = 54, .dw = 24, .ns = 42} + } + }, + { /* Version 32 */ + .data_bytes = 2465, + .apat = {6, 34, 60, 86, 112, 138, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 10}, + {.bs = 145, .dw = 115, .ns = 17}, + {.bs = 45, .dw = 15, .ns = 19}, + {.bs = 54, .dw = 24, .ns = 10} + } + }, + { /* Version 33 */ + .data_bytes = 2611, + .apat = {6, 30, 58, 86, 114, 142, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 14}, + {.bs = 145, .dw = 115, .ns = 17}, + {.bs = 45, .dw = 15, .ns = 11}, + {.bs = 54, .dw = 24, .ns = 29} + } + }, + { /* Version 34 */ + .data_bytes = 2761, + .apat = {6, 34, 62, 90, 118, 146, 0}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 14}, + {.bs = 145, .dw = 115, .ns = 13}, + {.bs = 46, .dw = 16, .ns = 59}, + {.bs = 54, .dw = 24, .ns = 44} + } + }, + { /* Version 35 */ + .data_bytes = 2876, + .apat = {6, 30, 54, 78, 102, 126, 150}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 12}, + {.bs = 151, .dw = 121, .ns = 12}, + {.bs = 45, .dw = 15, .ns = 22}, + {.bs = 54, .dw = 24, .ns = 39} + } + }, + { /* Version 36 */ + .data_bytes = 3034, + .apat = {6, 24, 50, 76, 102, 128, 154}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 6}, + {.bs = 151, .dw = 121, .ns = 6}, + {.bs = 45, .dw = 15, .ns = 2}, + {.bs = 54, .dw = 24, .ns = 46} + } + }, + { /* Version 37 */ + .data_bytes = 3196, + .apat = {6, 28, 54, 80, 106, 132, 158}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 29}, + {.bs = 152, .dw = 122, .ns = 17}, + {.bs = 45, .dw = 15, .ns = 24}, + {.bs = 54, .dw = 24, .ns = 49} + } + }, + { /* Version 38 */ + .data_bytes = 3362, + .apat = {6, 32, 58, 84, 110, 136, 162}, + .ecc = { + {.bs = 74, .dw = 46, .ns = 13}, + {.bs = 152, .dw = 122, .ns = 4}, + {.bs = 45, .dw = 15, .ns = 42}, + {.bs = 54, .dw = 24, .ns = 48} + } + }, + { /* Version 39 */ + .data_bytes = 3532, + .apat = {6, 26, 54, 82, 110, 138, 166}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 40}, + {.bs = 147, .dw = 117, .ns = 20}, + {.bs = 45, .dw = 15, .ns = 10}, + {.bs = 54, .dw = 24, .ns = 43} + } + }, + { /* Version 40 */ + .data_bytes = 3706, + .apat = {6, 30, 58, 86, 114, 142, 170}, + .ecc = { + {.bs = 75, .dw = 47, .ns = 18}, + {.bs = 148, .dw = 118, .ns = 19}, + {.bs = 45, .dw = 15, .ns = 20}, + {.bs = 54, .dw = 24, .ns = 34} + } + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "indentify.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc - QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/************************************************************************ + * Linear algebra routines + */ + +static int line_intersect(const struct quirc_point *p0, + const struct quirc_point *p1, + const struct quirc_point *q0, + const struct quirc_point *q1, + struct quirc_point *r) +{ + /* (a, b) is perpendicular to line p */ + int a = -(p1->y - p0->y); + int b = p1->x - p0->x; + + /* (c, d) is perpendicular to line q */ + int c = -(q1->y - q0->y); + int d = q1->x - q0->x; + + /* e and f are dot products of the respective vectors with p and q */ + int e = a * p1->x + b * p1->y; + int f = c * q1->x + d * q1->y; + + /* Now we need to solve: + * [a b] [rx] [e] + * [c d] [ry] = [f] + * + * We do this by inverting the matrix and applying it to (e, f): + * [ d -b] [e] [rx] + * 1/det [-c a] [f] = [ry] + */ + int det = (a * d) - (b * c); + + if (!det) + return 0; + + r->x = (d * e - b * f) / det; + r->y = (-c * e + a * f) / det; + + return 1; +} + +static void perspective_setup(float *c, + const struct quirc_point *rect, + float w, float h) +{ + float x0 = rect[0].x; + float y0 = rect[0].y; + float x1 = rect[1].x; + float y1 = rect[1].y; + float x2 = rect[2].x; + float y2 = rect[2].y; + float x3 = rect[3].x; + float y3 = rect[3].y; + + float wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3)); + float hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1); + + c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) + + x1*(x3-x2)*y0) / wden; + c[1] = -(x0*(x2*y3+x1*(y2-y3)-x2*y1) - x1*x3*y2 + x2*x3*y1 + + (x1*x3-x2*x3)*y0) / hden; + c[2] = x0; + c[3] = (y0*(x1*(y3-y2)-x2*y3+x3*y2) + y1*(x2*y3-x3*y2) + + x0*y1*(y2-y3)) / wden; + c[4] = (x0*(y1*y3-y2*y3) + x1*y2*y3 - x2*y1*y3 + + y0*(x3*y2-x1*y2+(x2-x3)*y1)) / hden; + c[5] = y0; + c[6] = (x1*(y3-y2) + x0*(y2-y3) + (x2-x3)*y1 + (x3-x2)*y0) / wden; + c[7] = (-x2*y3 + x1*y3 + x3*y2 + x0*(y1-y2) - x3*y1 + (x2-x1)*y0) / + hden; +} + +static void perspective_map(const float *c, + float u, float v, struct quirc_point *ret) +{ + float den = c[6]*u + c[7]*v + 1.0; + float x = (c[0]*u + c[1]*v + c[2]) / den; + float y = (c[3]*u + c[4]*v + c[5]) / den; + + ret->x = fast_roundf(x); + ret->y = fast_roundf(y); +} + +static void perspective_unmap(const float *c, + const struct quirc_point *in, + float *u, float *v) +{ + float x = in->x; + float y = in->y; + float den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x + + c[0]*c[4] - c[1]*c[3]; + + *u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) / + den; + *v = (c[0]*(y-c[5]) - c[2]*c[6]*y + (c[5]*c[6]-c[3])*x + c[2]*c[3]) / + den; +} + +/************************************************************************ + * Span-based floodfill routine + */ + +typedef void (*span_func_t)(void *user_data, int y, int left, int right); + +typedef struct xylf +{ + int16_t x, y, l, r; +} +xylf_t; + +static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to, + span_func_t func, void *user_data, + int depth) +{ + (void) depth; // unused + + lifo_t lifo; + size_t lifo_len; + lifo_alloc_all(&lifo, &lifo_len, sizeof(xylf_t)); + + for(;;) { + int left = x; + int right = x; + int i; + quirc_pixel_t *row = q->pixels + y * q->w; + + while (left > 0 && row[left - 1] == from) + left--; + + while (right < q->w - 1 && row[right + 1] == from) + right++; + + /* Fill the extent */ + for (i = left; i <= right; i++) + row[i] = to; + + if (func) + func(user_data, y, left, right); + + for(;;) { + if (lifo_size(&lifo) < lifo_len) { + /* Seed new flood-fills */ + if (y > 0) { + row = q->pixels + (y - 1) * q->w; + + bool recurse = false; + for (i = left; i <= right; i++) + if (row[i] == from) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y - 1; + recurse = true; + break; + } + if (recurse) + break; + } + + if (y < q->h - 1) { + row = q->pixels + (y + 1) * q->w; + + bool recurse = false; + for (i = left; i <= right; i++) + if (row[i] == from) { + xylf_t context; + context.x = x; + context.y = y; + context.l = left; + context.r = right; + lifo_enqueue(&lifo, &context); + x = i; + y = y + 1; + recurse = true; + break; + } + if (recurse) + break; + } + } + + if (!lifo_size(&lifo)) { + lifo_free(&lifo); + return; + } + + xylf_t context; + lifo_dequeue(&lifo, &context); + x = context.x; + y = context.y; + left = context.l; + right = context.r; + } + } +} + +/************************************************************************ + * Adaptive thresholding + */ + +#define THRESHOLD_S_MIN 1 +#define THRESHOLD_S_DEN 8 +#define THRESHOLD_T 5 + +static void threshold(struct quirc *q) +{ + int x, y; + int avg_w = 0; + int avg_u = 0; + int threshold_s = q->w / THRESHOLD_S_DEN; + quirc_pixel_t *row = q->pixels; + + /* + * Ensure a sane, non-zero value for threshold_s. + * + * threshold_s can be zero if the image width is small. We need to avoid + * SIGFPE as it will be used as divisor. + */ + if (threshold_s < THRESHOLD_S_MIN) + threshold_s = THRESHOLD_S_MIN; + + for (y = 0; y < q->h; y++) { + int row_average[q->w]; + + memset(row_average, 0, sizeof(row_average)); + + for (x = 0; x < q->w; x++) { + int w, u; + + if (y & 1) { + w = x; + u = q->w - 1 - x; + } else { + w = q->w - 1 - x; + u = x; + } + + avg_w = (avg_w * (threshold_s - 1)) / + threshold_s + row[w]; + avg_u = (avg_u * (threshold_s - 1)) / + threshold_s + row[u]; + + row_average[w] += avg_w; + row_average[u] += avg_u; + } + + for (x = 0; x < q->w; x++) { + if (row[x] < row_average[x] * + (100 - THRESHOLD_T) / (200 * threshold_s)) + row[x] = QUIRC_PIXEL_BLACK; + else + row[x] = QUIRC_PIXEL_WHITE; + } + + row += q->w; + } +} + +static void area_count(void *user_data, int y, int left, int right) +{ + ((struct quirc_region *)user_data)->count += right - left + 1; +} + +static int region_code(struct quirc *q, int x, int y) +{ + int pixel; + struct quirc_region *box; + int region; + + if (x < 0 || y < 0 || x >= q->w || y >= q->h) + return -1; + + pixel = q->pixels[y * q->w + x]; + + if (pixel >= QUIRC_PIXEL_REGION) + return pixel; + + if (pixel == QUIRC_PIXEL_WHITE) + return -1; + + if (q->num_regions >= QUIRC_MAX_REGIONS) + return -1; + + region = q->num_regions; + box = &q->regions[q->num_regions++]; + + memset(box, 0, sizeof(*box)); + + box->seed.x = x; + box->seed.y = y; + box->capstone = -1; + + flood_fill_seed(q, x, y, pixel, region, area_count, box, 0); + + return region; +} + +struct polygon_score_data { + struct quirc_point ref; + + int scores[4]; + struct quirc_point *corners; +}; + +static void find_one_corner(void *user_data, int y, int left, int right) +{ + struct polygon_score_data *psd = + (struct polygon_score_data *)user_data; + int xs[2] = {left, right}; + int dy = y - psd->ref.y; + int i; + + for (i = 0; i < 2; i++) { + int dx = xs[i] - psd->ref.x; + int d = dx * dx + dy * dy; + + if (d > psd->scores[0]) { + psd->scores[0] = d; + psd->corners[0].x = xs[i]; + psd->corners[0].y = y; + } + } +} + +static void find_other_corners(void *user_data, int y, int left, int right) +{ + struct polygon_score_data *psd = + (struct polygon_score_data *)user_data; + int xs[2] = {left, right}; + int i; + + for (i = 0; i < 2; i++) { + int up = xs[i] * psd->ref.x + y * psd->ref.y; + int right = xs[i] * -psd->ref.y + y * psd->ref.x; + int scores[4] = {up, right, -up, -right}; + int j; + + for (j = 0; j < 4; j++) { + if (scores[j] > psd->scores[j]) { + psd->scores[j] = scores[j]; + psd->corners[j].x = xs[i]; + psd->corners[j].y = y; + } + } + } +} + +static void find_region_corners(struct quirc *q, + int rcode, const struct quirc_point *ref, + struct quirc_point *corners) +{ + struct quirc_region *region = &q->regions[rcode]; + struct polygon_score_data psd; + int i; + + memset(&psd, 0, sizeof(psd)); + psd.corners = corners; + + memcpy(&psd.ref, ref, sizeof(psd.ref)); + psd.scores[0] = -1; + flood_fill_seed(q, region->seed.x, region->seed.y, + rcode, QUIRC_PIXEL_BLACK, + find_one_corner, &psd, 0); + + psd.ref.x = psd.corners[0].x - psd.ref.x; + psd.ref.y = psd.corners[0].y - psd.ref.y; + + for (i = 0; i < 4; i++) + memcpy(&psd.corners[i], ®ion->seed, + sizeof(psd.corners[i])); + + i = region->seed.x * psd.ref.x + region->seed.y * psd.ref.y; + psd.scores[0] = i; + psd.scores[2] = -i; + i = region->seed.x * -psd.ref.y + region->seed.y * psd.ref.x; + psd.scores[1] = i; + psd.scores[3] = -i; + + flood_fill_seed(q, region->seed.x, region->seed.y, + QUIRC_PIXEL_BLACK, rcode, + find_other_corners, &psd, 0); +} + +static void record_capstone(struct quirc *q, int ring, int stone) +{ + struct quirc_region *stone_reg = &q->regions[stone]; + struct quirc_region *ring_reg = &q->regions[ring]; + struct quirc_capstone *capstone; + int cs_index; + + if (q->num_capstones >= QUIRC_MAX_CAPSTONES) + return; + + cs_index = q->num_capstones; + capstone = &q->capstones[q->num_capstones++]; + + memset(capstone, 0, sizeof(*capstone)); + + capstone->qr_grid = -1; + capstone->ring = ring; + capstone->stone = stone; + stone_reg->capstone = cs_index; + ring_reg->capstone = cs_index; + + /* Find the corners of the ring */ + find_region_corners(q, ring, &stone_reg->seed, capstone->corners); + + /* Set up the perspective transform and find the center */ + perspective_setup(capstone->c, capstone->corners, 7.0, 7.0); + perspective_map(capstone->c, 3.5, 3.5, &capstone->center); +} + +static void test_capstone(struct quirc *q, int x, int y, int *pb) +{ + int ring_right = region_code(q, x - pb[4], y); + int stone = region_code(q, x - pb[4] - pb[3] - pb[2], y); + int ring_left = region_code(q, x - pb[4] - pb[3] - + pb[2] - pb[1] - pb[0], + y); + struct quirc_region *stone_reg; + struct quirc_region *ring_reg; + int ratio; + + if (ring_left < 0 || ring_right < 0 || stone < 0) + return; + + /* Left and ring of ring should be connected */ + if (ring_left != ring_right) + return; + + /* Ring should be disconnected from stone */ + if (ring_left == stone) + return; + + stone_reg = &q->regions[stone]; + ring_reg = &q->regions[ring_left]; + + /* Already detected */ + if (stone_reg->capstone >= 0 || ring_reg->capstone >= 0) + return; + + /* Ratio should ideally be 37.5 */ + ratio = stone_reg->count * 100 / ring_reg->count; + if (ratio < 10 || ratio > 70) + return; + + record_capstone(q, ring_left, stone); +} + +static void finder_scan(struct quirc *q, int y) +{ + quirc_pixel_t *row = q->pixels + y * q->w; + int x; + int last_color = 0; + int run_length = 0; + int run_count = 0; + int pb[5]; + + memset(pb, 0, sizeof(pb)); + for (x = 0; x < q->w; x++) { + int color = row[x] ? 1 : 0; + + if (x && color != last_color) { + memmove(pb, pb + 1, sizeof(pb[0]) * 4); + pb[4] = run_length; + run_length = 0; + run_count++; + + if (!color && run_count >= 5) { + static int check[5] = {1, 1, 3, 1, 1}; + int avg, err; + int i; + int ok = 1; + + avg = (pb[0] + pb[1] + pb[3] + pb[4]) / 4; + err = avg * 3 / 4; + + for (i = 0; i < 5; i++) + if (pb[i] < check[i] * avg - err || + pb[i] > check[i] * avg + err) + ok = 0; + + if (ok) + test_capstone(q, x, y, pb); + } + } + + run_length++; + last_color = color; + } +} + +static void find_alignment_pattern(struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + struct quirc_capstone *c0 = &q->capstones[qr->caps[0]]; + struct quirc_capstone *c2 = &q->capstones[qr->caps[2]]; + struct quirc_point a; + struct quirc_point b; + struct quirc_point c; + int size_estimate; + int step_size = 1; + int dir = 0; + float u, v; + + /* Grab our previous estimate of the alignment pattern corner */ + memcpy(&b, &qr->align, sizeof(b)); + + /* Guess another two corners of the alignment pattern so that we + * can estimate its size. + */ + perspective_unmap(c0->c, &b, &u, &v); + perspective_map(c0->c, u, v + 1.0, &a); + perspective_unmap(c2->c, &b, &u, &v); + perspective_map(c2->c, u + 1.0, v, &c); + + size_estimate = abs((a.x - b.x) * -(c.y - b.y) + + (a.y - b.y) * (c.x - b.x)); + + /* Spiral outwards from the estimate point until we find something + * roughly the right size. Don't look too far from the estimate + * point. + */ + while (step_size * step_size < size_estimate * 100) { + static const int dx_map[] = {1, 0, -1, 0}; + static const int dy_map[] = {0, -1, 0, 1}; + int i; + + for (i = 0; i < step_size; i++) { + int code = region_code(q, b.x, b.y); + + if (code >= 0) { + struct quirc_region *reg = &q->regions[code]; + + if (reg->count >= size_estimate / 2 && + reg->count <= size_estimate * 2) { + qr->align_region = code; + return; + } + } + + b.x += dx_map[dir]; + b.y += dy_map[dir]; + } + + dir = (dir + 1) % 4; + if (!(dir & 1)) + step_size++; + } +} + +static void find_leftmost_to_line(void *user_data, int y, int left, int right) +{ + struct polygon_score_data *psd = + (struct polygon_score_data *)user_data; + int xs[2] = {left, right}; + int i; + + for (i = 0; i < 2; i++) { + int d = -psd->ref.y * xs[i] + psd->ref.x * y; + + if (d < psd->scores[0]) { + psd->scores[0] = d; + psd->corners[0].x = xs[i]; + psd->corners[0].y = y; + } + } +} + +/* Do a Bresenham scan from one point to another and count the number + * of black/white transitions. + */ +static int timing_scan(const struct quirc *q, + const struct quirc_point *p0, + const struct quirc_point *p1) +{ + int n = p1->x - p0->x; + int d = p1->y - p0->y; + int x = p0->x; + int y = p0->y; + int *dom, *nondom; + int dom_step; + int nondom_step; + int a = 0; + int i; + int run_length = 0; + int count = 0; + + if (p0->x < 0 || p0->y < 0 || p0->x >= q->w || p0->y >= q->h) + return -1; + if (p1->x < 0 || p1->y < 0 || p1->x >= q->w || p1->y >= q->h) + return -1; + + if (abs(n) > abs(d)) { + int swap = n; + + n = d; + d = swap; + + dom = &x; + nondom = &y; + } else { + dom = &y; + nondom = &x; + } + + if (n < 0) { + n = -n; + nondom_step = -1; + } else { + nondom_step = 1; + } + + if (d < 0) { + d = -d; + dom_step = -1; + } else { + dom_step = 1; + } + + x = p0->x; + y = p0->y; + for (i = 0; i <= d; i++) { + int pixel; + + if (y < 0 || y >= q->h || x < 0 || x >= q->w) + break; + + pixel = q->pixels[y * q->w + x]; + + if (pixel) { + if (run_length >= 2) + count++; + run_length = 0; + } else { + run_length++; + } + + a += n; + *dom += dom_step; + if (a >= d) { + *nondom += nondom_step; + a -= d; + } + } + + return count; +} + +/* Try the measure the timing pattern for a given QR code. This does + * not require the global perspective to have been set up, but it + * does require that the capstone corners have been set to their + * canonical rotation. + * + * For each capstone, we find a point in the middle of the ring band + * which is nearest the centre of the code. Using these points, we do + * a horizontal and a vertical timing scan. + */ +static int measure_timing_pattern(struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + int i; + int scan; + int ver; + int size; + + for (i = 0; i < 3; i++) { + static const float us[] = {6.5, 6.5, 0.5}; + static const float vs[] = {0.5, 6.5, 6.5}; + struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; + + perspective_map(cap->c, us[i], vs[i], &qr->tpep[i]); + } + + qr->hscan = timing_scan(q, &qr->tpep[1], &qr->tpep[2]); + qr->vscan = timing_scan(q, &qr->tpep[1], &qr->tpep[0]); + + scan = qr->hscan; + if (qr->vscan > scan) + scan = qr->vscan; + + /* If neither scan worked, we can't go any further. */ + if (scan < 0) + return -1; + + /* Choose the nearest allowable grid size */ + size = scan * 2 + 13; + ver = (size - 15) / 4; + qr->grid_size = ver * 4 + 17; + + return 0; +} + +/* Read a cell from a grid using the currently set perspective + * transform. Returns +/- 1 for black/white, 0 for cells which are + * out of image bounds. + */ +static int read_cell(const struct quirc *q, int index, int x, int y) +{ + const struct quirc_grid *qr = &q->grids[index]; + struct quirc_point p; + + perspective_map(qr->c, x + 0.5, y + 0.5, &p); + if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) + return 0; + + return q->pixels[p.y * q->w + p.x] ? 1 : -1; +} + +static int fitness_cell(const struct quirc *q, int index, int x, int y) +{ + const struct quirc_grid *qr = &q->grids[index]; + int score = 0; + int u, v; + + for (v = 0; v < 3; v++) + for (u = 0; u < 3; u++) { + static const float offsets[] = {0.3, 0.5, 0.7}; + struct quirc_point p; + + perspective_map(qr->c, x + offsets[u], + y + offsets[v], &p); + if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) + continue; + + if (q->pixels[p.y * q->w + p.x]) + score++; + else + score--; + } + + return score; +} + +static int fitness_ring(const struct quirc *q, int index, int cx, int cy, + int radius) +{ + int i; + int score = 0; + + for (i = 0; i < radius * 2; i++) { + score += fitness_cell(q, index, cx - radius + i, cy - radius); + score += fitness_cell(q, index, cx - radius, cy + radius - i); + score += fitness_cell(q, index, cx + radius, cy - radius + i); + score += fitness_cell(q, index, cx + radius - i, cy + radius); + } + + return score; +} + +static int fitness_apat(const struct quirc *q, int index, int cx, int cy) +{ + return fitness_cell(q, index, cx, cy) - + fitness_ring(q, index, cx, cy, 1) + + fitness_ring(q, index, cx, cy, 2); +} + +static int fitness_capstone(const struct quirc *q, int index, int x, int y) +{ + x += 3; + y += 3; + + return fitness_cell(q, index, x, y) + + fitness_ring(q, index, x, y, 1) - + fitness_ring(q, index, x, y, 2) + + fitness_ring(q, index, x, y, 3); +} + +/* Compute a fitness score for the currently configured perspective + * transform, using the features we expect to find by scanning the + * grid. + */ +static int fitness_all(const struct quirc *q, int index) +{ + const struct quirc_grid *qr = &q->grids[index]; + int version = (qr->grid_size - 17) / 4; + const struct quirc_version_info *info = &quirc_version_db[version]; + int score = 0; + int i, j; + int ap_count; + + /* Check the timing pattern */ + for (i = 0; i < qr->grid_size - 14; i++) { + int expect = (i & 1) ? 1 : -1; + + score += fitness_cell(q, index, i + 7, 6) * expect; + score += fitness_cell(q, index, 6, i + 7) * expect; + } + + /* Check capstones */ + score += fitness_capstone(q, index, 0, 0); + score += fitness_capstone(q, index, qr->grid_size - 7, 0); + score += fitness_capstone(q, index, 0, qr->grid_size - 7); + + if (version < 0 || version > QUIRC_MAX_VERSION) + return score; + + /* Check alignment patterns */ + ap_count = 0; + while ((ap_count < QUIRC_MAX_ALIGNMENT) && info->apat[ap_count]) + ap_count++; + + for (i = 1; i + 1 < ap_count; i++) { + score += fitness_apat(q, index, 6, info->apat[i]); + score += fitness_apat(q, index, info->apat[i], 6); + } + + for (i = 1; i < ap_count; i++) + for (j = 1; j < ap_count; j++) + score += fitness_apat(q, index, + info->apat[i], info->apat[j]); + + return score; +} + +static void jiggle_perspective(struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + int best = fitness_all(q, index); + int pass; + float adjustments[8]; + int i; + + for (i = 0; i < 8; i++) + adjustments[i] = qr->c[i] * 0.02; + + for (pass = 0; pass < 5; pass++) { + for (i = 0; i < 16; i++) { + int j = i >> 1; + int test; + float old = qr->c[j]; + float step = adjustments[j]; + float new; + + if (i & 1) + new = old + step; + else + new = old - step; + + qr->c[j] = new; + test = fitness_all(q, index); + + if (test > best) + best = test; + else + qr->c[j] = old; + } + + for (i = 0; i < 8; i++) + adjustments[i] *= 0.5; + } +} + +/* Once the capstones are in place and an alignment point has been + * chosen, we call this function to set up a grid-reading perspective + * transform. + */ +static void setup_qr_perspective(struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + struct quirc_point rect[4]; + + /* Set up the perspective map for reading the grid */ + memcpy(&rect[0], &q->capstones[qr->caps[1]].corners[0], + sizeof(rect[0])); + memcpy(&rect[1], &q->capstones[qr->caps[2]].corners[0], + sizeof(rect[0])); + memcpy(&rect[2], &qr->align, sizeof(rect[0])); + memcpy(&rect[3], &q->capstones[qr->caps[0]].corners[0], + sizeof(rect[0])); + perspective_setup(qr->c, rect, qr->grid_size - 7, qr->grid_size - 7); + + jiggle_perspective(q, index); +} + +/* Rotate the capstone with so that corner 0 is the leftmost with respect + * to the given reference line. + */ +static void rotate_capstone(struct quirc_capstone *cap, + const struct quirc_point *h0, + const struct quirc_point *hd) +{ + struct quirc_point copy[4]; + int j; + int best = 0; + int best_score = 0; + + for (j = 0; j < 4; j++) { + struct quirc_point *p = &cap->corners[j]; + int score = (p->x - h0->x) * -hd->y + + (p->y - h0->y) * hd->x; + + if (!j || score < best_score) { + best = j; + best_score = score; + } + } + + /* Rotate the capstone */ + for (j = 0; j < 4; j++) + memcpy(©[j], &cap->corners[(j + best) % 4], + sizeof(copy[j])); + memcpy(cap->corners, copy, sizeof(cap->corners)); + perspective_setup(cap->c, cap->corners, 7.0, 7.0); +} + +static void record_qr_grid(struct quirc *q, int a, int b, int c) +{ + struct quirc_point h0, hd; + int i; + int qr_index; + struct quirc_grid *qr; + + if (q->num_grids >= QUIRC_MAX_GRIDS) + return; + + /* Construct the hypotenuse line from A to C. B should be to + * the left of this line. + */ + memcpy(&h0, &q->capstones[a].center, sizeof(h0)); + hd.x = q->capstones[c].center.x - q->capstones[a].center.x; + hd.y = q->capstones[c].center.y - q->capstones[a].center.y; + + /* Make sure A-B-C is clockwise */ + if ((q->capstones[b].center.x - h0.x) * -hd.y + + (q->capstones[b].center.y - h0.y) * hd.x > 0) { + int swap = a; + + a = c; + c = swap; + hd.x = -hd.x; + hd.y = -hd.y; + } + + /* Record the grid and its components */ + qr_index = q->num_grids; + qr = &q->grids[q->num_grids++]; + + memset(qr, 0, sizeof(*qr)); + qr->caps[0] = a; + qr->caps[1] = b; + qr->caps[2] = c; + qr->align_region = -1; + + /* Rotate each capstone so that corner 0 is top-left with respect + * to the grid. + */ + for (i = 0; i < 3; i++) { + struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; + + rotate_capstone(cap, &h0, &hd); + cap->qr_grid = qr_index; + } + + /* Check the timing pattern. This doesn't require a perspective + * transform. + */ + if (measure_timing_pattern(q, qr_index) < 0) + goto fail; + + /* Make an estimate based for the alignment pattern based on extending + * lines from capstones A and C. + */ + if (!line_intersect(&q->capstones[a].corners[0], + &q->capstones[a].corners[1], + &q->capstones[c].corners[0], + &q->capstones[c].corners[3], + &qr->align)) + goto fail; + + /* On V2+ grids, we should use the alignment pattern. */ + if (qr->grid_size > 21) { + /* Try to find the actual location of the alignment pattern. */ + find_alignment_pattern(q, qr_index); + + /* Find the point of the alignment pattern closest to the + * top-left of the QR grid. + */ + if (qr->align_region >= 0) { + struct polygon_score_data psd; + struct quirc_region *reg = + &q->regions[qr->align_region]; + + /* Start from some point inside the alignment pattern */ + memcpy(&qr->align, ®->seed, sizeof(qr->align)); + + memcpy(&psd.ref, &hd, sizeof(psd.ref)); + psd.corners = &qr->align; + psd.scores[0] = -hd.y * qr->align.x + + hd.x * qr->align.y; + + flood_fill_seed(q, reg->seed.x, reg->seed.y, + qr->align_region, QUIRC_PIXEL_BLACK, + NULL, NULL, 0); + flood_fill_seed(q, reg->seed.x, reg->seed.y, + QUIRC_PIXEL_BLACK, qr->align_region, + find_leftmost_to_line, &psd, 0); + } + } + + setup_qr_perspective(q, qr_index); + return; + +fail: + /* We've been unable to complete setup for this grid. Undo what we've + * recorded and pretend it never happened. + */ + for (i = 0; i < 3; i++) + q->capstones[qr->caps[i]].qr_grid = -1; + q->num_grids--; +} + +struct neighbour { + int index; + float distance; +}; + +struct neighbour_list { + struct neighbour n[QUIRC_MAX_CAPSTONES]; + int count; +}; + +static void test_neighbours(struct quirc *q, int i, + const struct neighbour_list *hlist, + const struct neighbour_list *vlist) +{ + int j, k; + float best_score = 0.0; + int best_h = -1, best_v = -1; + + /* Test each possible grouping */ + for (j = 0; j < hlist->count; j++) + for (k = 0; k < vlist->count; k++) { + const struct neighbour *hn = &hlist->n[j]; + const struct neighbour *vn = &vlist->n[k]; + float score = fast_fabsf(1.0 - hn->distance / vn->distance); + + if (score > 2.5) + continue; + + if (best_h < 0 || score < best_score) { + best_h = hn->index; + best_v = vn->index; + best_score = score; + } + } + + if (best_h < 0 || best_v < 0) + return; + + record_qr_grid(q, best_h, i, best_v); +} + +static void test_grouping(struct quirc *q, int i) +{ + struct quirc_capstone *c1 = &q->capstones[i]; + int j; + struct neighbour_list hlist; + struct neighbour_list vlist; + + if (c1->qr_grid >= 0) + return; + + hlist.count = 0; + vlist.count = 0; + + /* Look for potential neighbours by examining the relative gradients + * from this capstone to others. + */ + for (j = 0; j < q->num_capstones; j++) { + struct quirc_capstone *c2 = &q->capstones[j]; + float u, v; + + if (i == j || c2->qr_grid >= 0) + continue; + + perspective_unmap(c1->c, &c2->center, &u, &v); + + u = fast_fabsf(u - 3.5); + v = fast_fabsf(v - 3.5); + + if (u < 0.2 * v) { + struct neighbour *n = &hlist.n[hlist.count++]; + + n->index = j; + n->distance = v; + } + + if (v < 0.2 * u) { + struct neighbour *n = &vlist.n[vlist.count++]; + + n->index = j; + n->distance = u; + } + } + + if (!(hlist.count && vlist.count)) + return; + + test_neighbours(q, i, &hlist, &vlist); +} + +static void pixels_setup(struct quirc *q) +{ + if (sizeof(*q->image) == sizeof(*q->pixels)) { + q->pixels = (quirc_pixel_t *)q->image; + } else { + int x, y; + for (y = 0; y < q->h; y++) { + for (x = 0; x < q->w; x++) { + q->pixels[y * q->w + x] = q->image[y * q->w + x]; + } + } + } +} + +uint8_t *quirc_begin(struct quirc *q, int *w, int *h) +{ + q->num_regions = QUIRC_PIXEL_REGION; + q->num_capstones = 0; + q->num_grids = 0; + + if (w) + *w = q->w; + if (h) + *h = q->h; + + return q->image; +} + +void quirc_end(struct quirc *q) +{ + int i; + + pixels_setup(q); + threshold(q); + + for (i = 0; i < q->h; i++) + finder_scan(q, i); + + for (i = 0; i < q->num_capstones; i++) + test_grouping(q, i); +} + +void quirc_extract(const struct quirc *q, int index, + struct quirc_code *code) +{ + const struct quirc_grid *qr = &q->grids[index]; + int y; + int i = 0; + + if (index < 0 || index > q->num_grids) + return; + + memset(code, 0, sizeof(*code)); + + perspective_map(qr->c, 0.0, 0.0, &code->corners[0]); + perspective_map(qr->c, qr->grid_size, 0.0, &code->corners[1]); + perspective_map(qr->c, qr->grid_size, qr->grid_size, + &code->corners[2]); + perspective_map(qr->c, 0.0, qr->grid_size, &code->corners[3]); + + code->size = qr->grid_size; + + for (y = 0; y < qr->grid_size; y++) { + int x; + + for (x = 0; x < qr->grid_size; x++) { + if (read_cell(q, index, x, y) > 0) + code->cell_bitmap[i >> 3] |= (1 << (i & 7)); + + i++; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "decode.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define MAX_POLY 64 + +/************************************************************************ + * Galois fields + */ + +struct galois_field { + int p; + const uint8_t *log; + const uint8_t *exp; +}; + +static const uint8_t gf16_exp[16] = { + 0x01, 0x02, 0x04, 0x08, 0x03, 0x06, 0x0c, 0x0b, + 0x05, 0x0a, 0x07, 0x0e, 0x0f, 0x0d, 0x09, 0x01 +}; + +static const uint8_t gf16_log[16] = { + 0x00, 0x0f, 0x01, 0x04, 0x02, 0x08, 0x05, 0x0a, + 0x03, 0x0e, 0x09, 0x07, 0x06, 0x0d, 0x0b, 0x0c +}; + +static const struct galois_field gf16 = { + .p = 15, + .log = gf16_log, + .exp = gf16_exp +}; + +static const uint8_t gf256_exp[256] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, + 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, + 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, + 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, + 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, + 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, + 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, + 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, + 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, + 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, + 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, + 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, + 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, + 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, + 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, + 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, + 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, + 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, + 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, + 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, + 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, + 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, + 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, + 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, + 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, + 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, + 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, + 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, + 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, + 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, + 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01 +}; + +static const uint8_t gf256_log[256] = { + 0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, + 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, + 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, + 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, + 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, + 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, + 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, + 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, + 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, + 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, + 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, + 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, + 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, + 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, + 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, + 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, + 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, + 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, + 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, + 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, + 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, + 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, + 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, + 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, + 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, + 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, + 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, + 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, + 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, + 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, + 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, + 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf +}; + +const static struct galois_field gf256 = { + .p = 255, + .log = gf256_log, + .exp = gf256_exp +}; + +/************************************************************************ + * Polynomial operations + */ + +static void poly_add(uint8_t *dst, const uint8_t *src, uint8_t c, + int shift, const struct galois_field *gf) +{ + int i; + int log_c = gf->log[c]; + + if (!c) + return; + + for (i = 0; i < MAX_POLY; i++) { + int p = i + shift; + uint8_t v = src[i]; + + if (p < 0 || p >= MAX_POLY) + continue; + if (!v) + continue; + + dst[p] ^= gf->exp[(gf->log[v] + log_c) % gf->p]; + } +} + +static uint8_t poly_eval(const uint8_t *s, uint8_t x, + const struct galois_field *gf) +{ + int i; + uint8_t sum = 0; + uint8_t log_x = gf->log[x]; + + if (!x) + return s[0]; + + for (i = 0; i < MAX_POLY; i++) { + uint8_t c = s[i]; + + if (!c) + continue; + + sum ^= gf->exp[(gf->log[c] + log_x * i) % gf->p]; + } + + return sum; +} + +/************************************************************************ + * Berlekamp-Massey algorithm for finding error locator polynomials. + */ + +static void berlekamp_massey(const uint8_t *s, int N, + const struct galois_field *gf, + uint8_t *sigma) +{ + uint8_t C[MAX_POLY]; + uint8_t B[MAX_POLY]; + int L = 0; + int m = 1; + uint8_t b = 1; + int n; + + memset(B, 0, sizeof(B)); + memset(C, 0, sizeof(C)); + B[0] = 1; + C[0] = 1; + + for (n = 0; n < N; n++) { + uint8_t d = s[n]; + uint8_t mult; + int i; + + for (i = 1; i <= L; i++) { + if (!(C[i] && s[n - i])) + continue; + + d ^= gf->exp[(gf->log[C[i]] + + gf->log[s[n - i]]) % + gf->p]; + } + + mult = gf->exp[(gf->p - gf->log[b] + gf->log[d]) % gf->p]; + + if (!d) { + m++; + } else if (L * 2 <= n) { + uint8_t T[MAX_POLY]; + + memcpy(T, C, sizeof(T)); + poly_add(C, B, mult, m, gf); + memcpy(B, T, sizeof(B)); + L = n + 1 - L; + b = d; + m = 1; + } else { + poly_add(C, B, mult, m, gf); + m++; + } + } + + memcpy(sigma, C, MAX_POLY); +} + +/************************************************************************ + * Code stream error correction + * + * Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1 + */ + +static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s) +{ + int nonzero = 0; + int i; + + memset(s, 0, MAX_POLY); + + for (i = 0; i < npar; i++) { + int j; + + for (j = 0; j < bs; j++) { + uint8_t c = data[bs - j - 1]; + + if (!c) + continue; + + s[i] ^= gf256_exp[((int)gf256_log[c] + + i * j) % 255]; + } + + if (s[i]) + nonzero = 1; + } + + return nonzero; +} + +static void eloc_poly(uint8_t *omega, + const uint8_t *s, const uint8_t *sigma, + int npar) +{ + int i; + + memset(omega, 0, MAX_POLY); + + for (i = 0; i < npar; i++) { + const uint8_t a = sigma[i]; + const uint8_t log_a = gf256_log[a]; + int j; + + if (!a) + continue; + + for (j = 0; j + 1 < MAX_POLY; j++) { + const uint8_t b = s[j + 1]; + + if (i + j >= npar) + break; + + if (!b) + continue; + + omega[i + j] ^= + gf256_exp[(log_a + gf256_log[b]) % 255]; + } + } +} + +static quirc_decode_error_t correct_block(uint8_t *data, + const struct quirc_rs_params *ecc) +{ + int npar = ecc->bs - ecc->dw; + uint8_t s[MAX_POLY]; + uint8_t sigma[MAX_POLY]; + uint8_t sigma_deriv[MAX_POLY]; + uint8_t omega[MAX_POLY]; + int i; + + /* Compute syndrome vector */ + if (!block_syndromes(data, ecc->bs, npar, s)) + return QUIRC_SUCCESS; + + berlekamp_massey(s, npar, &gf256, sigma); + + /* Compute derivative of sigma */ + memset(sigma_deriv, 0, MAX_POLY); + for (i = 0; i + 1 < MAX_POLY; i += 2) + sigma_deriv[i] = sigma[i + 1]; + + /* Compute error evaluator polynomial */ + eloc_poly(omega, s, sigma, npar - 1); + + /* Find error locations and magnitudes */ + for (i = 0; i < ecc->bs; i++) { + uint8_t xinv = gf256_exp[255 - i]; + + if (!poly_eval(sigma, xinv, &gf256)) { + uint8_t sd_x = poly_eval(sigma_deriv, xinv, &gf256); + uint8_t omega_x = poly_eval(omega, xinv, &gf256); + uint8_t error = gf256_exp[(255 - gf256_log[sd_x] + + gf256_log[omega_x]) % 255]; + + data[ecc->bs - i - 1] ^= error; + } + } + + if (block_syndromes(data, ecc->bs, npar, s)) + return QUIRC_ERROR_DATA_ECC; + + return QUIRC_SUCCESS; +} + +/************************************************************************ + * Format value error correction + * + * Generator polynomial for GF(2^4) is x^4 + x + 1 + */ + +#define FORMAT_MAX_ERROR 3 +#define FORMAT_SYNDROMES (FORMAT_MAX_ERROR * 2) +#define FORMAT_BITS 15 + +static int format_syndromes(uint16_t u, uint8_t *s) +{ + int i; + int nonzero = 0; + + memset(s, 0, MAX_POLY); + + for (i = 0; i < FORMAT_SYNDROMES; i++) { + int j; + + s[i] = 0; + for (j = 0; j < FORMAT_BITS; j++) + if (u & (1 << j)) + s[i] ^= gf16_exp[((i + 1) * j) % 15]; + + if (s[i]) + nonzero = 1; + } + + return nonzero; +} + +static quirc_decode_error_t correct_format(uint16_t *f_ret) +{ + uint16_t u = *f_ret; + int i; + uint8_t s[MAX_POLY]; + uint8_t sigma[MAX_POLY]; + + /* Evaluate U (received codeword) at each of alpha_1 .. alpha_6 + * to get S_1 .. S_6 (but we index them from 0). + */ + if (!format_syndromes(u, s)) + return QUIRC_SUCCESS; + + berlekamp_massey(s, FORMAT_SYNDROMES, &gf16, sigma); + + /* Now, find the roots of the polynomial */ + for (i = 0; i < 15; i++) + if (!poly_eval(sigma, gf16_exp[15 - i], &gf16)) + u ^= (1 << i); + + if (format_syndromes(u, s)) + return QUIRC_ERROR_FORMAT_ECC; + + *f_ret = u; + return QUIRC_SUCCESS; +} + +/************************************************************************ + * Decoder algorithm + */ + +struct datastream { + uint8_t raw[QUIRC_MAX_PAYLOAD]; + int data_bits; + int ptr; + + uint8_t data[QUIRC_MAX_PAYLOAD]; +}; + +static inline int grid_bit(const struct quirc_code *code, int x, int y) +{ + int p = y * code->size + x; + + return (code->cell_bitmap[p >> 3] >> (p & 7)) & 1; +} + +static quirc_decode_error_t read_format(const struct quirc_code *code, + struct quirc_data *data, int which) +{ + int i; + uint16_t format = 0; + uint16_t fdata; + quirc_decode_error_t err; + + if (which) { + for (i = 0; i < 7; i++) + format = (format << 1) | + grid_bit(code, 8, code->size - 1 - i); + for (i = 0; i < 8; i++) + format = (format << 1) | + grid_bit(code, code->size - 8 + i, 8); + } else { + static const int xs[15] = { + 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 4, 3, 2, 1, 0 + }; + static const int ys[15] = { + 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + for (i = 14; i >= 0; i--) + format = (format << 1) | grid_bit(code, xs[i], ys[i]); + } + + format ^= 0x5412; + + err = correct_format(&format); + if (err) + return err; + + fdata = format >> 10; + data->ecc_level = fdata >> 3; + data->mask = fdata & 7; + + return QUIRC_SUCCESS; +} + +static int mask_bit(int mask, int i, int j) +{ + switch (mask) { + case 0: return !((i + j) % 2); + case 1: return !(i % 2); + case 2: return !(j % 3); + case 3: return !((i + j) % 3); + case 4: return !(((i / 2) + (j / 3)) % 2); + case 5: return !((i * j) % 2 + (i * j) % 3); + case 6: return !(((i * j) % 2 + (i * j) % 3) % 2); + case 7: return !(((i * j) % 3 + (i + j) % 2) % 2); + } + + return 0; +} + +static int reserved_cell(int version, int i, int j) +{ + const struct quirc_version_info *ver = &quirc_version_db[version]; + int size = version * 4 + 17; + int ai = -1, aj = -1, a; + + /* Finder + format: top left */ + if (i < 9 && j < 9) + return 1; + + /* Finder + format: bottom left */ + if (i + 8 >= size && j < 9) + return 1; + + /* Finder + format: top right */ + if (i < 9 && j + 8 >= size) + return 1; + + /* Exclude timing patterns */ + if (i == 6 || j == 6) + return 1; + + /* Exclude version info, if it exists. Version info sits adjacent to + * the top-right and bottom-left finders in three rows, bounded by + * the timing pattern. + */ + if (version >= 7) { + if (i < 6 && j + 11 >= size) + return 1; + if (i + 11 >= size && j < 6) + return 1; + } + + /* Exclude alignment patterns */ + for (a = 0; a < QUIRC_MAX_ALIGNMENT && ver->apat[a]; a++) { + int p = ver->apat[a]; + + if (abs(p - i) < 3) + ai = a; + if (abs(p - j) < 3) + aj = a; + } + + if (ai >= 0 && aj >= 0) { + a--; + if (ai > 0 && ai < a) + return 1; + if (aj > 0 && aj < a) + return 1; + if (aj == a && ai == a) + return 1; + } + + return 0; +} + +static void read_bit(const struct quirc_code *code, + struct quirc_data *data, + struct datastream *ds, int i, int j) +{ + int bitpos = ds->data_bits & 7; + int bytepos = ds->data_bits >> 3; + int v = grid_bit(code, j, i); + + if (mask_bit(data->mask, i, j)) + v ^= 1; + + if (v) + ds->raw[bytepos] |= (0x80 >> bitpos); + + ds->data_bits++; +} + +static void read_data(const struct quirc_code *code, + struct quirc_data *data, + struct datastream *ds) +{ + int y = code->size - 1; + int x = code->size - 1; + int dir = -1; + + while (x > 0) { + if (x == 6) + x--; + + if (!reserved_cell(data->version, y, x)) + read_bit(code, data, ds, y, x); + + if (!reserved_cell(data->version, y, x - 1)) + read_bit(code, data, ds, y, x - 1); + + y += dir; + if (y < 0 || y >= code->size) { + dir = -dir; + x -= 2; + y += dir; + } + } +} + +static quirc_decode_error_t codestream_ecc(struct quirc_data *data, + struct datastream *ds) +{ + const struct quirc_version_info *ver = + &quirc_version_db[data->version]; + const struct quirc_rs_params *sb_ecc = &ver->ecc[data->ecc_level]; + struct quirc_rs_params lb_ecc; + const int lb_count = + (ver->data_bytes - sb_ecc->bs * sb_ecc->ns) / (sb_ecc->bs + 1); + const int bc = lb_count + sb_ecc->ns; + const int ecc_offset = sb_ecc->dw * bc + lb_count; + int dst_offset = 0; + int i; + + memcpy(&lb_ecc, sb_ecc, sizeof(lb_ecc)); + lb_ecc.dw++; + lb_ecc.bs++; + + for (i = 0; i < bc; i++) { + uint8_t *dst = ds->data + dst_offset; + const struct quirc_rs_params *ecc = + (i < sb_ecc->ns) ? sb_ecc : &lb_ecc; + const int num_ec = ecc->bs - ecc->dw; + quirc_decode_error_t err; + int j; + + for (j = 0; j < ecc->dw; j++) + dst[j] = ds->raw[j * bc + i]; + for (j = 0; j < num_ec; j++) + dst[ecc->dw + j] = ds->raw[ecc_offset + j * bc + i]; + + err = correct_block(dst, ecc); + if (err) + return err; + + dst_offset += ecc->dw; + } + + ds->data_bits = dst_offset * 8; + + return QUIRC_SUCCESS; +} + +static inline int bits_remaining(const struct datastream *ds) +{ + return ds->data_bits - ds->ptr; +} + +static int take_bits(struct datastream *ds, int len) +{ + int ret = 0; + + while (len && (ds->ptr < ds->data_bits)) { + uint8_t b = ds->data[ds->ptr >> 3]; + int bitpos = ds->ptr & 7; + + ret <<= 1; + if ((b << bitpos) & 0x80) + ret |= 1; + + ds->ptr++; + len--; + } + + return ret; +} + +static int numeric_tuple(struct quirc_data *data, + struct datastream *ds, + int bits, int digits) +{ + int tuple; + int i; + + if (bits_remaining(ds) < bits) + return -1; + + tuple = take_bits(ds, bits); + + for (i = digits - 1; i >= 0; i--) { + data->payload[data->payload_len + i] = tuple % 10 + '0'; + tuple /= 10; + } + + data->payload_len += digits; + return 0; +} + +static quirc_decode_error_t decode_numeric(struct quirc_data *data, + struct datastream *ds) +{ + int bits = 14; + int count; + + if (data->version < 10) + bits = 10; + else if (data->version < 27) + bits = 12; + + count = take_bits(ds, bits); + if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) + return QUIRC_ERROR_DATA_OVERFLOW; + + while (count >= 3) { + if (numeric_tuple(data, ds, 10, 3) < 0) + return QUIRC_ERROR_DATA_UNDERFLOW; + count -= 3; + } + + if (count >= 2) { + if (numeric_tuple(data, ds, 7, 2) < 0) + return QUIRC_ERROR_DATA_UNDERFLOW; + count -= 2; + } + + if (count) { + if (numeric_tuple(data, ds, 4, 1) < 0) + return QUIRC_ERROR_DATA_UNDERFLOW; + count--; + } + + return QUIRC_SUCCESS; +} + +static int alpha_tuple(struct quirc_data *data, + struct datastream *ds, + int bits, int digits) +{ + int tuple; + int i; + + if (bits_remaining(ds) < bits) + return -1; + + tuple = take_bits(ds, bits); + + for (i = 0; i < digits; i++) { + static const char *alpha_map = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + + data->payload[data->payload_len + digits - i - 1] = + alpha_map[tuple % 45]; + tuple /= 45; + } + + data->payload_len += digits; + return 0; +} + +static quirc_decode_error_t decode_alpha(struct quirc_data *data, + struct datastream *ds) +{ + int bits = 13; + int count; + + if (data->version < 10) + bits = 9; + else if (data->version < 27) + bits = 11; + + count = take_bits(ds, bits); + if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) + return QUIRC_ERROR_DATA_OVERFLOW; + + while (count >= 2) { + if (alpha_tuple(data, ds, 11, 2) < 0) + return QUIRC_ERROR_DATA_UNDERFLOW; + count -= 2; + } + + if (count) { + if (alpha_tuple(data, ds, 6, 1) < 0) + return QUIRC_ERROR_DATA_UNDERFLOW; + count--; + } + + return QUIRC_SUCCESS; +} + +static quirc_decode_error_t decode_byte(struct quirc_data *data, + struct datastream *ds) +{ + int bits = 16; + int count; + int i; + + if (data->version < 10) + bits = 8; + + count = take_bits(ds, bits); + if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) + return QUIRC_ERROR_DATA_OVERFLOW; + if (bits_remaining(ds) < count * 8) + return QUIRC_ERROR_DATA_UNDERFLOW; + + for (i = 0; i < count; i++) + data->payload[data->payload_len++] = take_bits(ds, 8); + + return QUIRC_SUCCESS; +} + +static quirc_decode_error_t decode_kanji(struct quirc_data *data, + struct datastream *ds) +{ + int bits = 12; + int count; + int i; + + if (data->version < 10) + bits = 8; + else if (data->version < 27) + bits = 10; + + count = take_bits(ds, bits); + if (data->payload_len + count * 2 + 1 > QUIRC_MAX_PAYLOAD) + return QUIRC_ERROR_DATA_OVERFLOW; + if (bits_remaining(ds) < count * 13) + return QUIRC_ERROR_DATA_UNDERFLOW; + + for (i = 0; i < count; i++) { + int d = take_bits(ds, 13); + int msB = d / 0xc0; + int lsB = d % 0xc0; + int intermediate = (msB << 8) | lsB; + uint16_t sjw; + + if (intermediate + 0x8140 <= 0x9ffc) { + /* bytes are in the range 0x8140 to 0x9FFC */ + sjw = intermediate + 0x8140; + } else { + /* bytes are in the range 0xE040 to 0xEBBF */ + sjw = intermediate + 0xc140; + } + + data->payload[data->payload_len++] = sjw >> 8; + data->payload[data->payload_len++] = sjw & 0xff; + } + + return QUIRC_SUCCESS; +} + +static quirc_decode_error_t decode_eci(struct quirc_data *data, + struct datastream *ds) +{ + if (bits_remaining(ds) < 8) + return QUIRC_ERROR_DATA_UNDERFLOW; + + data->eci = take_bits(ds, 8); + + if ((data->eci & 0xc0) == 0x80) { + if (bits_remaining(ds) < 8) + return QUIRC_ERROR_DATA_UNDERFLOW; + + data->eci = (data->eci << 8) | take_bits(ds, 8); + } else if ((data->eci & 0xe0) == 0xc0) { + if (bits_remaining(ds) < 16) + return QUIRC_ERROR_DATA_UNDERFLOW; + + data->eci = (data->eci << 16) | take_bits(ds, 16); + } + + return QUIRC_SUCCESS; +} + +static quirc_decode_error_t decode_payload(struct quirc_data *data, + struct datastream *ds) +{ + while (bits_remaining(ds) >= 4) { + quirc_decode_error_t err = QUIRC_SUCCESS; + int type = take_bits(ds, 4); + + switch (type) { + case QUIRC_DATA_TYPE_NUMERIC: + err = decode_numeric(data, ds); + break; + + case QUIRC_DATA_TYPE_ALPHA: + err = decode_alpha(data, ds); + break; + + case QUIRC_DATA_TYPE_BYTE: + err = decode_byte(data, ds); + break; + + case QUIRC_DATA_TYPE_KANJI: + err = decode_kanji(data, ds); + break; + + case 7: + err = decode_eci(data, ds); + break; + + default: + goto done; + } + + if (err) + return err; + + if (!(type & (type - 1)) && (type > data->data_type)) + data->data_type = type; + } + +done: + + /* Add nul terminator to all payloads */ + if (data->payload_len >= sizeof(data->payload)) + data->payload_len--; + data->payload[data->payload_len] = 0; + + return QUIRC_SUCCESS; +} + +quirc_decode_error_t quirc_decode(const struct quirc_code *code, + struct quirc_data *data) +{ + quirc_decode_error_t err; + struct datastream *ds = fb_alloc(sizeof(struct datastream)); + + if ((code->size - 17) % 4) + { fb_free(); return QUIRC_ERROR_INVALID_GRID_SIZE; } + + memset(data, 0, sizeof(*data)); + memset(ds, 0, sizeof(*ds)); + + data->version = (code->size - 17) / 4; + + if (data->version < 1 || + data->version > QUIRC_MAX_VERSION) + { fb_free(); return QUIRC_ERROR_INVALID_VERSION; } + + /* Read format information -- try both locations */ + err = read_format(code, data, 0); + if (err) + err = read_format(code, data, 1); + if (err) + { fb_free(); return err; } + + read_data(code, data, ds); + err = codestream_ecc(data, ds); + if (err) + { fb_free(); return err; } + + err = decode_payload(data, ds); + if (err) + { fb_free(); return err; } + + fb_free(); return QUIRC_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "quirc.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +const char *quirc_version(void) +{ + return "1.0"; +} + +struct quirc *quirc_new(void) +{ + struct quirc *q = fb_alloc(sizeof(*q)); + + if (!q) + return NULL; + + memset(q, 0, sizeof(*q)); + return q; +} + +void quirc_destroy(struct quirc *q) +{ + if (q->image) + if (q->image) fb_free(); + if (sizeof(*q->image) != sizeof(*q->pixels)) + if (q->pixels) fb_free(); + + if (q) fb_free(); +} + +int quirc_resize(struct quirc *q, int w, int h) +{ + if (q->image) fb_free(); + uint8_t *new_image = fb_alloc(w * h); + + if (!new_image) + return -1; + + if (sizeof(*q->image) != sizeof(*q->pixels)) { + size_t new_size = w * h * sizeof(quirc_pixel_t); + if (q->pixels) fb_free(); + quirc_pixel_t *new_pixels = fb_alloc(new_size); + if (!new_pixels) { + fb_free(); + return -1; + } + q->pixels = new_pixels; + } + + q->image = new_image; + q->w = w; + q->h = h; + + return 0; +} + +int quirc_count(const struct quirc *q) +{ + return q->num_grids; +} + +static const char *const error_table[] = { + [QUIRC_SUCCESS] = "Success", + [QUIRC_ERROR_INVALID_GRID_SIZE] = "Invalid grid size", + [QUIRC_ERROR_INVALID_VERSION] = "Invalid version", + [QUIRC_ERROR_FORMAT_ECC] = "Format data ECC failure", + [QUIRC_ERROR_DATA_ECC] = "ECC failure", + [QUIRC_ERROR_UNKNOWN_DATA_TYPE] = "Unknown data type", + [QUIRC_ERROR_DATA_OVERFLOW] = "Data overflow", + [QUIRC_ERROR_DATA_UNDERFLOW] = "Data underflow" +}; + +const char *quirc_strerror(quirc_decode_error_t err) +{ + if (err >= 0 && err < sizeof(error_table) / sizeof(error_table[0])) + return error_table[err]; + + return "Unknown error"; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void imlib_find_qrcodes(list_t *out, image_t *ptr, rectangle_t *roi) +{ + struct quirc *controller = quirc_new(); + quirc_resize(controller, roi->w, roi->h); + uint8_t *grayscale_image = quirc_begin(controller, NULL, NULL); + + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + quirc_end(controller); + list_init(out, sizeof(find_qrcodes_list_lnk_data_t)); + + for (int i = 0, j = quirc_count(controller); i < j; i++) { + struct quirc_code *code = fb_alloc(sizeof(struct quirc_code)); + struct quirc_data *data = fb_alloc(sizeof(struct quirc_data)); + quirc_extract(controller, i, code); + + if(quirc_decode(code, data) == QUIRC_SUCCESS) { + find_qrcodes_list_lnk_data_t lnk_data; + rectangle_init(&(lnk_data.rect), code->corners[0].x + roi->x, code->corners[0].y + roi->y, 0, 0); + + for (size_t k = 1, l = (sizeof(code->corners) / sizeof(code->corners[0])); k < l; k++) { + rectangle_t temp; + rectangle_init(&temp, code->corners[k].x + roi->x, code->corners[k].y + roi->y, 0, 0); + rectangle_united(&(lnk_data.rect), &temp); + } + + // Add corners... + lnk_data.corners[0].x = fast_roundf(code->corners[0].x) + roi->x; // top-left + lnk_data.corners[0].y = fast_roundf(code->corners[0].y) + roi->y; // top-left + lnk_data.corners[1].x = fast_roundf(code->corners[1].x) + roi->x; // top-right + lnk_data.corners[1].y = fast_roundf(code->corners[1].y) + roi->y; // top-right + lnk_data.corners[2].x = fast_roundf(code->corners[2].x) + roi->x; // bottom-right + lnk_data.corners[2].y = fast_roundf(code->corners[2].y) + roi->y; // bottom-right + lnk_data.corners[3].x = fast_roundf(code->corners[3].x) + roi->x; // bottom-left + lnk_data.corners[3].y = fast_roundf(code->corners[3].y) + roi->y; // bottom-left + + // Payload is already null terminated. + lnk_data.payload_len = data->payload_len; + lnk_data.payload = xalloc(data->payload_len); + memcpy(lnk_data.payload, data->payload, data->payload_len); + + lnk_data.version = data->version; + lnk_data.ecc_level = data->ecc_level; + lnk_data.mask = data->mask; + lnk_data.data_type = data->data_type; + lnk_data.eci = data->eci; + + list_push_back(out, &lnk_data); + } + + fb_free(); + fb_free(); + } + + quirc_destroy(controller); +} +#endif //IMLIB_ENABLE_QRCODES diff --git a/src/openmv/src/omv/img/qsort.c b/src/openmv/src/omv/img/qsort.c new file mode 100755 index 0000000..b2def63 --- /dev/null +++ b/src/openmv/src/omv/img/qsort.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 University 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 REGENTS 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 REGENTS 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 +#define min(a, b) (a) < (b) ? a : b +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + size_t i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static __inline void swapfunc(char *a, char *b, size_t n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static __inline char *med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int cmp_result, swaptype, swap_cnt; + size_t d, r; + char *a = (char *)aa; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (cmp_result = cmp(pb, a)) <= 0) { + if (cmp_result == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (cmp_result = cmp(pc, a)) >= 0) { + if (cmp_result == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/src/openmv/src/omv/img/rainbow_tab.c b/src/openmv/src/omv/img/rainbow_tab.c new file mode 100755 index 0000000..addcce2 --- /dev/null +++ b/src/openmv/src/omv/img/rainbow_tab.c @@ -0,0 +1,35 @@ +#include +const uint16_t rainbow_table[256] = { + 0x3F06, 0x3F06, 0x5F06, 0x7F06, 0x9F06, 0xBF06, 0xBF06, 0xDF06, + 0xFF06, 0x1F07, 0x3F07, 0x3F07, 0x5F07, 0x7F07, 0x9F07, 0xBF07, + 0xBF07, 0xDF07, 0xFF07, 0xFF07, 0xFE07, 0xFE07, 0xFD07, 0xFD07, + 0xFD07, 0xFC07, 0xFC07, 0xFB07, 0xFB07, 0xFB07, 0xFA07, 0xFA07, + 0xFA07, 0xF907, 0xF907, 0xF807, 0xF807, 0xF807, 0xF707, 0xF707, + 0xF607, 0xF607, 0xF607, 0xF507, 0xF507, 0xF407, 0xF407, 0xF407, + 0xF307, 0xF307, 0xF207, 0xF207, 0xF207, 0xF107, 0xF107, 0xF107, + 0xF007, 0xF007, 0xEF07, 0xEF07, 0xEF07, 0xEE07, 0xEE07, 0xED07, + 0xED07, 0xED07, 0xEC07, 0xEC07, 0xEB07, 0xEB07, 0xEB07, 0xEA07, + 0xEA07, 0xEA07, 0xE907, 0xE907, 0xE807, 0xE807, 0xE807, 0xE707, + 0xE707, 0xE607, 0xE607, 0xE607, 0xE507, 0xE507, 0xE407, 0xE407, + 0xE407, 0xE307, 0xE307, 0xE207, 0xE207, 0xE207, 0xE107, 0xE107, + 0xE107, 0xE007, 0xE007, 0xE00F, 0xE00F, 0xE00F, 0xE017, 0xE017, + 0xE01F, 0xE01F, 0xE01F, 0xE027, 0xE027, 0xE02F, 0xE02F, 0xE02F, + 0xE037, 0xE037, 0xE03F, 0xE03F, 0xE03F, 0xE047, 0xE047, 0xE047, + 0xE04F, 0xE04F, 0xE057, 0xE057, 0xE057, 0xE05F, 0xE05F, 0xE067, + 0xE067, 0xE067, 0xE06F, 0xE06F, 0xE077, 0xE077, 0xE077, 0xE07F, + 0xE07F, 0xE087, 0xE087, 0xE087, 0xE08F, 0xE08F, 0xE08F, 0xE097, + 0xE097, 0xE09F, 0xE09F, 0xE09F, 0xE0A7, 0xE0A7, 0xE0AF, 0xE0AF, + 0xE0AF, 0xE0B7, 0xE0B7, 0xE0BF, 0xE0BF, 0xE0BF, 0xE0C7, 0xE0C7, + 0xE0C7, 0xE0CF, 0xE0CF, 0xE0D7, 0xE0D7, 0xE0D7, 0xE0DF, 0xE0DF, + 0xE0E7, 0xE0E7, 0xE0E7, 0xE0EF, 0xE0EF, 0xE0F7, 0xE0F7, 0xE0F7, + 0xE0FF, 0xE0FF, 0xC0FF, 0xA0FF, 0x80FF, 0x80FF, 0x60FF, 0x40FF, + 0x20FF, 0x00FF, 0x00FF, 0xE0FE, 0xC0FE, 0xA0FE, 0x80FE, 0x80FE, + 0x60FE, 0x40FE, 0x20FE, 0x00FE, 0x00FE, 0xE0FD, 0xC0FD, 0xA0FD, + 0x80FD, 0x80FD, 0x60FD, 0x40FD, 0x20FD, 0x00FD, 0x00FD, 0xE0FC, + 0xC0FC, 0xA0FC, 0xA0FC, 0x80FC, 0x60FC, 0x40FC, 0x20FC, 0x20FC, + 0x00FC, 0xE0FB, 0xC0FB, 0xA0FB, 0xA0FB, 0x80FB, 0x60FB, 0x40FB, + 0x20FB, 0x20FB, 0x00FB, 0xE0FA, 0xC0FA, 0xA0FA, 0xA0FA, 0x80FA, + 0x60FA, 0x40FA, 0x20FA, 0x20FA, 0x00FA, 0xE0F9, 0xC0F9, 0xA0F9, + 0xA0F9, 0x80F9, 0x60F9, 0x40F9, 0x40F9, 0x20F9, 0x00F9, 0xE0F8, + 0xC0F8, 0xC0F8, 0xA0F8, 0x80F8, 0x60F8, 0x40F8, 0x40F8, 0x20F8 +}; diff --git a/src/openmv/src/omv/img/rectangle.c b/src/openmv/src/omv/img/rectangle.c new file mode 100755 index 0000000..569b92f --- /dev/null +++ b/src/openmv/src/omv/img/rectangle.c @@ -0,0 +1,123 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Rectangle functions. + * + */ +#include "imlib.h" +#include "array.h" +#include "xalloc.h" + +rectangle_t *rectangle_alloc(int16_t x, int16_t y, int16_t w, int16_t h) +{ + rectangle_t *r = xalloc(sizeof(rectangle_t)); + r->x = x; + r->y = y; + r->w = w; + r->h = h; + return r; +} + +bool rectangle_equal(rectangle_t *r1, rectangle_t *r2) +{ + return ((r1->x==r2->x)&&(r1->y==r2->y)&&(r1->w==r2->w)&&(r1->h==r2->h)); +} + +bool rectangle_intersects(rectangle_t *r1, rectangle_t *r2) +{ + return ((r1->x < (r2->x+r2->w)) && + (r1->y < (r2->y+r2->h)) && + ((r1->x+r1->w) > r2->x) && + ((r1->y+r1->h) > r2->y)); +} + +// Determine subimg even if it is going off the edge of the main image. +bool rectangle_subimg(image_t *img, rectangle_t *r, rectangle_t *r_out) +{ + rectangle_t r_img; + r_img.x = 0; + r_img.y = 0; + r_img.w = img->w; + r_img.h = img->h; + bool result = rectangle_intersects(&r_img, r); + if (result) { + int r_img_x2 = r_img.x + r_img.w; + int r_img_y2 = r_img.y + r_img.h; + int r_x2 = r->x + r->w; + int r_y2 = r->y + r->h; + r_out->x = IM_MAX(r_img.x, r->x); + r_out->y = IM_MAX(r_img.y, r->y); + r_out->w = IM_MIN(r_img_x2, r_x2) - r_out->x; + r_out->h = IM_MIN(r_img_y2, r_y2) - r_out->y; + } + return result; +} + +// This isn't for actually combining the rects standardly, but, to instead +// find the average rectangle between a bunch of overlapping rectangles. +static void rectangle_add(rectangle_t *r1, rectangle_t *r2) +{ + r1->x += r2->x; + r1->y += r2->y; + r1->w += r2->w; + r1->h += r2->h; +} + +// This isn't for actually combining the rects standardly, but, to instead +// find the average rectangle between a bunch of overlapping rectangles. +static void rectangle_div(rectangle_t *r, int c) +{ + r->x /= c; + r->y /= c; + r->w /= c; + r->h /= c; +} + +array_t *rectangle_merge(array_t *rectangles) +{ + array_t *objects; array_alloc(&objects, xfree); + array_t *overlap; array_alloc(&overlap, xfree); + /* merge overlaping detections */ + while (array_length(rectangles)) { + /* check for overlaping detections */ + rectangle_t *rect = (rectangle_t *) array_take(rectangles, 0); + for (int j=0; jx) { + r->x = x; + } + if (y < r->y) { + r->y = y; + } + if (x > r->w) { + r->w = x; + } + if (y > r->h) { + r->h = y; + } +} diff --git a/src/openmv/src/omv/img/rgb2rgb_tab.c b/src/openmv/src/omv/img/rgb2rgb_tab.c new file mode 100755 index 0000000..9b62579 --- /dev/null +++ b/src/openmv/src/omv/img/rgb2rgb_tab.c @@ -0,0 +1,85 @@ +#include +const uint8_t rb528_table[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, + 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, + 197, 206, 214, 222, 230, 239, 247, 255 +}; +const uint8_t g628_table[64] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 45, 49, 53, 57, 61, + 65, 69, 73, 77, 81, 85, 89, 93, + 97, 101, 105, 109, 113, 117, 121, 125, + 130, 134, 138, 142, 146, 150, 154, 158, + 162, 166, 170, 174, 178, 182, 186, 190, + 194, 198, 202, 206, 210, 215, 219, 223, + 227, 231, 235, 239, 243, 247, 251, 255 +}; +const uint8_t rb825_table[256] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 20, 20, 20, 20, 20, 20, 20, + 20, 21, 21, 21, 21, 21, 21, 21, + 21, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 24, 24, 24, 24, + 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 28, 28, 28, 28, 28, + 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 30, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 31 +}; +const uint8_t g826_table[256] = { + 0, 0, 0, 1, 1, 1, 1, 2, + 2, 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 11, 11, 12, + 12, 12, 12, 13, 13, 13, 13, 14, + 14, 14, 14, 15, 15, 15, 15, 16, + 16, 16, 16, 17, 17, 17, 17, 18, + 18, 18, 18, 19, 19, 19, 19, 20, + 20, 20, 20, 21, 21, 21, 21, 21, + 22, 22, 22, 22, 23, 23, 23, 23, + 24, 24, 24, 24, 25, 25, 25, 25, + 26, 26, 26, 26, 27, 27, 27, 27, + 28, 28, 28, 28, 29, 29, 29, 29, + 30, 30, 30, 30, 31, 31, 31, 31, + 32, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 37, + 38, 38, 38, 38, 39, 39, 39, 39, + 40, 40, 40, 40, 41, 41, 41, 41, + 42, 42, 42, 42, 42, 43, 43, 43, + 43, 44, 44, 44, 44, 45, 45, 45, + 45, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 49, 49, 49, + 49, 50, 50, 50, 50, 51, 51, 51, + 51, 52, 52, 52, 52, 53, 53, 53, + 53, 54, 54, 54, 54, 55, 55, 55, + 55, 56, 56, 56, 56, 57, 57, 57, + 57, 58, 58, 58, 58, 59, 59, 59, + 59, 60, 60, 60, 60, 61, 61, 61, + 61, 62, 62, 62, 62, 63, 63, 63 +}; diff --git a/src/openmv/src/omv/img/selective_search.c b/src/openmv/src/omv/img/selective_search.c new file mode 100755 index 0000000..1672cde --- /dev/null +++ b/src/openmv/src/omv/img/selective_search.c @@ -0,0 +1,446 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 + * Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Selective search. + */ +#include +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#include "xalloc.h" +#ifdef IMLIB_ENABLE_SELECTIVE_SEARCH + +#define THRESHOLD(size, c) (c/size) +typedef struct { + uint16_t y; + uint16_t h; + uint16_t x; + uint16_t w; +} region; + +typedef struct { + uint16_t p; + uint16_t rank; + uint16_t size; +} uni_elt; + +typedef struct { + int num; + uni_elt *elts; +} universe; + +typedef struct { + float w; + uint16_t a; + uint16_t b; +} edge; + +inline int min (int a, int b) { return (a < b) ? a : b; } +inline int max (int a, int b) { return (a > b) ? a : b; } +inline float minf (float a, float b) { return (a < b) ? a : b; } +inline float maxf (float a, float b) { return (a > b) ? a : b; } +extern uint32_t rng_randint(uint32_t min, uint32_t max); + +static universe *universe_create(int elements) +{ + universe * uni = (universe*) fb_alloc(sizeof(universe)); + uni->elts = (uni_elt*) fb_alloc(sizeof(uni_elt)*elements); + uni->num = elements; + for (int i=0; ielts[i].p = i; + uni->elts[i].rank = 0; + uni->elts[i].size = 1; + } + return uni; +} + +static int universe_size(universe * uni, int x) +{ + return uni->elts[x].size; +} + +static int universe_num_sets(universe * uni) +{ + return uni->num; +} + +static int universe_find(universe * uni, int x) +{ + int y = x; + while (y != uni->elts[y].p) { + y = uni->elts[y].p; + } + // Path compression + uni->elts[x].p = y; + return y; +} + +static void universe_join (universe * uni, int x, int y) +{ + if (uni->elts[x].rank > uni->elts[y].rank) { + uni->elts[y].p = x; + uni->elts[x].size += uni->elts[y].size; + } else { + uni->elts[x].p = y; + uni->elts[y].size += uni->elts[x].size; + if (uni->elts[x].rank == uni->elts[y].rank) { + uni->elts[y].rank++; + } + } + uni->num--; +} + +static int universe_get_id(universe * this, int x) +{ + return this->elts[x].rank; +} + +static void universe_set_id(universe * this, int x, int id) +{ + this->elts[x].rank = id; +} + +static inline float color_similarity (float * hist1, float * hist2) +{ + float sim = 0; + for (int i = 0; i < 75; ++i) { + sim += minf(hist1[i], hist2[i]); + } + return sim; +} + +static inline float size_similarity (int a, int b, int size) +{ + return 1.0f - (a + b)/size; +} + +static inline float fill_similarity (region * ra, region * rb, int a, int b, int size) +{ + int width = max(ra->w, rb->w) - min(ra->x, rb->x); + int height = max(ra->h, rb->h) - min(ra->y, rb->y); + return 1.0f - (width*height - a - b)/size; +} + +static inline float square(float x) { return x*x; }; + +static inline float diff(image_t *img, int x1, int y1, int x2, int y2) +{ + uint16_t p1 = IMAGE_GET_RGB565_PIXEL(img, x1, y1); + uint16_t p2 = IMAGE_GET_RGB565_PIXEL(img, x2, y2); + uint8_t r1 = COLOR_RGB565_TO_R8(p1); + uint8_t r2 = COLOR_RGB565_TO_R8(p2); + + uint8_t g1 = COLOR_RGB565_TO_G8(p1); + uint8_t g2 = COLOR_RGB565_TO_G8(p2); + + uint8_t b1 = COLOR_RGB565_TO_B8(p1); + uint8_t b2 = COLOR_RGB565_TO_B8(p2); + // dissimilarity measure between pixels + return sqrtf((r1-r2) * (r1-r2) + (g1-g2) * (g1-g2) + (b1-b2) * (b1-b2)); +} + +int comp (const void * elem1, const void * elem2) +{ + edge *f = (edge*) elem1; + edge *s = (edge*) elem2; + if (f->w > s->w) return 1; + if (f->w < s->w) return -1; + return 0; +} + +static void segment_graph(universe *u, int num_vertices, int num_edges, edge *edges, float c) +{ + qsort (edges, num_edges, sizeof(edge), comp); + + float *threshold = fb_alloc(num_vertices * sizeof(float)); + for (int i=0; ia); + int b = universe_find (u, pedge->b); + if (a != b) { + if ((pedge->w <= threshold[a]) && (pedge->w <= threshold[b])) { + universe_join (u, a, b); + a = universe_find (u, a); + threshold[a] = pedge->w + THRESHOLD(universe_size (u, a), c); + } + } + } + + // Free thresholds. + fb_free(); +} + +static void image_scale(image_t *src, image_t *dst) +{ + int x_ratio = (int)((src->w<<16)/dst->w) +1; + int y_ratio = (int)((src->h<<16)/dst->h) +1; + + for (int y=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++) { + int sx = (x*x_ratio)>>16; + ((uint16_t*)dst->pixels)[y*dst->w+x] = ((uint16_t*)src->pixels)[sy*src->w+sx]; + } + } +} + +array_t *imlib_selective_search(image_t *src, float t, int min_size, float a1, float a2, float a3) +{ + int i,j; + int num = 0; + int width=0, height=0; + image_t *img = NULL; + + if ((src->w * src->h) <= (80 * 60)) { + img = src; + width = src->w; + height = src->h; + } else { + // Down scale image + width = src->w / 4; + height = src->h / 4; + img = fb_alloc(sizeof(image_t)); + img->w = width; + img->h = height; + img->pixels = fb_alloc(width * height * 2); + image_scale(src, img); + } + + // Region proposals array + array_t *proposals; + array_alloc(&proposals, xfree); + + universe *u = universe_create (width * height); + edge *edges = (edge*) fb_alloc(width * height * sizeof(edge) * 4); + + for (int y=0; y 0)) { + edges[num].a = y * width + x; + edges[num].b = (y-1) * width + (x+1); + edges[num].w = diff(img, x, y, x+1, y-1); + num++; + } + } + } + + segment_graph(u, width * height, num, edges, t); + + for (i=0; iy = min(r->y, y); + r->h = max(r->h, y); + r->x = min(r->x, x); + r->w = max(r->w, x); + + uint16_t p = IMAGE_GET_RGB565_PIXEL(img, x, y); + int r_bin = min(COLOR_RGB565_TO_R8(p), 240)/10; + int g_bin = min(COLOR_RGB565_TO_G8(p), 240)/10; + int b_bin = min(COLOR_RGB565_TO_B8(p), 240)/10; + + histogram[75*component_id + 0 + r_bin]++; + histogram[75*component_id + 25 + g_bin]++; + histogram[75*component_id + 50 + b_bin]++; + counts[component_id]++; + } + } + + // Normalize histograms + for (i=0; i 1) { + int best_i = -1; + int best_j = -1; + float best_similarity = 0; + for (i=0; i best_similarity) { + best_similarity = similarity; + best_i = i; + best_j = j; + } + } + } + + if (best_i == -1) { + printf("failed to build tree\n"); + break; + } + + // update regions, histograms, counts, adjacency, similarity + regions[best_i].x = min(regions[best_i].x, regions[best_j].x); + regions[best_i].y = min(regions[best_i].y, regions[best_j].y); + regions[best_i].w = max(regions[best_i].w, regions[best_j].w); + regions[best_i].h = max(regions[best_i].h, regions[best_j].h); + + bool add = true; + for (i=0; ix && regions[best_i].y == r->y && + regions[best_i].w == r->w && regions[best_i].h == r->h) { + add = false; + break; + } + } + if (add) { + array_push_back(proposals, rectangle_alloc(regions[best_i].x, + regions[best_i].y, regions[best_i].w, regions[best_i].h)); + } + + + for (i=0; i<75; i++) { + histogram[75*best_i + i] = (counts[best_i] * histogram[75*best_i + i] + + counts[best_j] * histogram[75*best_j + i])/(counts[best_i] + counts[best_j]); + } + counts[best_i] += counts[best_j]; + + for (i=0; iw = r->w - r->x; + r->h = r->h - r->y; + if ((src->w * src->h) > (80 * 60)) { + r->x *=4; + r->y *=4; + r->w *=4; + r->h *=4; + } + } + fb_free_all(); + return proposals; +} +#endif //IMLIB_ENABLE_SELECTIVE_SEARCH diff --git a/src/openmv/src/omv/img/shadow_removal.c b/src/openmv/src/omv/img/shadow_removal.c new file mode 100755 index 0000000..b9e01fa --- /dev/null +++ b/src/openmv/src/omv/img/shadow_removal.c @@ -0,0 +1,513 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +#ifdef IMLIB_ENABLE_REMOVE_SHADOWS +// http://arma.sourceforge.net/shadows/ +// http://dx.doi.org/10.1016/j.patcog.2011.10.001 + +#define imlib_remove_shadows_kernel_rank 1 +#define imlib_remove_shadows_kernel_size ((imlib_remove_shadows_kernel_rank * 2) + 1) + +typedef struct imlib_remove_shadows_line_op_state { + uint16_t *img_lines[imlib_remove_shadows_kernel_size]; + uint16_t *other_lines[imlib_remove_shadows_kernel_size]; + uint16_t *out_lines[imlib_remove_shadows_kernel_size]; + int lines_processed; +} imlib_remove_shadows_line_op_state_t; + +static void imlib_remove_shadows_sub_sub_line_op(image_t *img, int line, void *data, bool vflipped) +{ + imlib_remove_shadows_line_op_state_t *state = (imlib_remove_shadows_line_op_state_t *) data; + + state->lines_processed += 1; + + if (state->lines_processed >= imlib_remove_shadows_kernel_size) { + int y = vflipped ? ((line - 1) + imlib_remove_shadows_kernel_size) : ((line + 1) - imlib_remove_shadows_kernel_size); + int index = y % imlib_remove_shadows_kernel_size; + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y), state->out_lines[index], img->w * sizeof(uint16_t)); + } +} + +static void imlib_remove_shadows_sub_line_op(image_t *img, int line, void *data, bool vflipped) +{ + imlib_remove_shadows_line_op_state_t *state = (imlib_remove_shadows_line_op_state_t *) data; + + if (state->lines_processed >= imlib_remove_shadows_kernel_rank) { + int y = vflipped ? (line + imlib_remove_shadows_kernel_rank) : (line - imlib_remove_shadows_kernel_rank); + int index = y % imlib_remove_shadows_kernel_size; + + for (int x = 0, xx = img->w; x < xx; x++) { + int img_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->img_lines[index], x); + int img_r = COLOR_RGB565_TO_R8(img_pixel); + int img_g = COLOR_RGB565_TO_G8(img_pixel); + int img_b = COLOR_RGB565_TO_B8(img_pixel); + float img_v = IM_MAX(IM_MAX(img_r, img_g), img_b); + int other_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->other_lines[index], x); + int other_r = COLOR_RGB565_TO_R8(other_pixel); + int other_g = COLOR_RGB565_TO_G8(other_pixel); + int other_b = COLOR_RGB565_TO_B8(other_pixel); + float other_v = IM_MAX(IM_MAX(other_r, other_g), other_b); + float ratio = img_v / other_v; + + if ((0.3f < ratio) && (ratio < 1.0f)) { + int minY = IM_MAX(y - imlib_remove_shadows_kernel_rank, 0); + int maxY = IM_MIN(y + imlib_remove_shadows_kernel_rank, img->h - 1); + int minX = IM_MAX(x - imlib_remove_shadows_kernel_rank, 0); + int maxX = IM_MIN(x + imlib_remove_shadows_kernel_rank, img->w - 1); + int windowArea = (maxX - minX + 1) * (maxY - minY + 1); + int hDiffSum = 0; + int sDiffSum = 0; + + for (int k_y = minY; k_y <= maxY; k_y++) { + int k_index = k_y % imlib_remove_shadows_kernel_size; + + for (int k_x = minX; k_x <= maxX; k_x++) { + int k_img_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->img_lines[k_index], k_x); + int k_img_r = COLOR_RGB565_TO_R8(k_img_pixel); + int k_img_g = COLOR_RGB565_TO_G8(k_img_pixel); + int k_img_b = COLOR_RGB565_TO_B8(k_img_pixel); + int k_img_cmax = IM_MAX(IM_MAX(k_img_r, k_img_g), k_img_b); + int k_img_cmin = IM_MAX(IM_MAX(k_img_r, k_img_g), k_img_b); + float k_img_cdel = k_img_cmax - k_img_cmin; + float k_img_h = 0; + float k_img_s = k_img_cmax ? (k_img_cdel / k_img_cmax) : 0; + int k_other_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->other_lines[k_index], k_x); + int k_other_r = COLOR_RGB565_TO_R8(k_other_pixel); + int k_other_g = COLOR_RGB565_TO_G8(k_other_pixel); + int k_other_b = COLOR_RGB565_TO_B8(k_other_pixel); + int k_other_cmax = IM_MAX(IM_MAX(k_other_r, k_other_g), k_other_b); + int k_other_cmin = IM_MAX(IM_MAX(k_other_r, k_other_g), k_other_b); + float k_other_cdel = k_other_cmax - k_other_cmin; + float k_other_h = 0; + float k_other_s = k_other_cmax ? (k_other_cdel / k_other_cmax) : 0; + + if (k_img_cdel) { + if (k_img_cmax == k_img_r) { + k_img_h = ((k_img_g - k_img_b) / k_img_cdel) + 0; + } else if (k_img_cmax == k_img_g) { + k_img_h = ((k_img_b - k_img_r) / k_img_cdel) + 2; + } else if (k_img_cmax == k_img_b) { + k_img_h = ((k_img_r - k_img_g) / k_img_cdel) + 4; + } + k_img_h *= 60; + if (k_img_h < 0) k_img_h += 360.0; + } + + if (k_other_cdel) { + if (k_other_cmax == k_other_r) { + k_other_h = ((k_other_g - k_other_b) / k_other_cdel) + 0; + } else if (k_other_cmax == k_other_g) { + k_other_h = ((k_other_b - k_other_r) / k_other_cdel) + 2; + } else if (k_other_cmax == k_other_b) { + k_other_h = ((k_other_r - k_other_g) / k_other_cdel) + 4; + } + k_other_h *= 60; + if (k_other_h < 0) k_other_h += 360.0; + } + + int hDiff = abs(k_img_h - k_other_h); + hDiffSum += (hDiff >= 90) ? (180 - hDiff) : hDiff; + sDiffSum += k_img_s - k_other_s; + } + } + + bool hIsShadow = (hDiffSum / windowArea) < 48; + bool sIsShadow = (sDiffSum / windowArea) < 40; + IMAGE_PUT_RGB565_PIXEL_FAST(state->out_lines[index], x, (hIsShadow && sIsShadow) ? other_pixel : img_pixel); + } else { + IMAGE_PUT_RGB565_PIXEL_FAST(state->out_lines[index], x, img_pixel); + } + } + } + + imlib_remove_shadows_sub_sub_line_op(img, line, data, vflipped); +} + +static void imlib_remove_shadows_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + imlib_remove_shadows_line_op_state_t *state = (imlib_remove_shadows_line_op_state_t *) data; + + memcpy(state->img_lines[line % imlib_remove_shadows_kernel_size], + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line), img->w * sizeof(uint16_t)); + + memcpy(state->other_lines[line % imlib_remove_shadows_kernel_size], + (uint16_t *) other, img->w * sizeof(uint16_t)); + + imlib_remove_shadows_sub_line_op(img, line, data, vflipped); + + if (state->lines_processed == img->h) { + for (int i = 0; i < imlib_remove_shadows_kernel_rank; i++) { + line += vflipped ? -1 : 1; + imlib_remove_shadows_sub_line_op(img, line, data, vflipped); + } + + for (int i = 0; i < imlib_remove_shadows_kernel_rank; i++) { + line += vflipped ? -1 : 1; + imlib_remove_shadows_sub_sub_line_op(img, line, data, vflipped); + } + } +} + +void imlib_remove_shadows(image_t *img, const char *path, image_t *other, int scalar, bool single) +{ + if (!single) { + imlib_remove_shadows_line_op_state_t state; + + for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) { + state.img_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); + state.other_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); + state.out_lines[i] = fb_alloc(img->w * sizeof(uint16_t)); + } + + state.lines_processed = 0; + + imlib_image_operation(img, path, other, scalar, imlib_remove_shadows_line_op, &state); + + for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) { + fb_free(); + fb_free(); + fb_free(); + } + } else { + + // Create Shadow Mask + + image_t temp_image; + temp_image.w = img->w; + temp_image.h = img->h; + temp_image.bpp = img->bpp; + temp_image.data = fb_alloc(image_size(img)); + + memcpy(temp_image.data, img->data, image_size(img)); + + rectangle_t r; + r.x = 0; + r.y = 0; + r.w = temp_image.w; + r.h = temp_image.h; + + histogram_t h; + h.LBinCount = COLOR_L_MAX - COLOR_L_MIN + 1; + h.ABinCount = COLOR_A_MAX - COLOR_A_MIN + 1; + h.BBinCount = COLOR_B_MAX - COLOR_B_MIN + 1; + h.LBins = fb_alloc(h.LBinCount * sizeof(float)); + h.ABins = fb_alloc(h.ABinCount * sizeof(float)); + h.BBins = fb_alloc(h.BBinCount * sizeof(float)); + imlib_get_histogram(&h, &temp_image, &r, NULL, false); + + statistics_t s; + imlib_get_statistics(&s, temp_image.bpp, &h); + + int sum = 0; + int mean = s.LMean * 0.8f; + + for (int y = 0, yy = temp_image.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y); + + for (int x = 0, xx = temp_image.w; x < xx; x++) { + sum += COLOR_RGB565_TO_L(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) < mean; + } + } + + if (sum > ((temp_image.w * temp_image.h) / 20)) { // Don't do anything if the image is mostly flat. + + threshold_t t; + imlib_get_threshold(&t, temp_image.bpp, &h); + + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + color_thresholds_list_lnk_data_t lnk_data; + lnk_data.LMin = COLOR_L_MIN; + lnk_data.AMin = COLOR_A_MIN; + lnk_data.BMin = COLOR_B_MIN; + lnk_data.LMax = t.LValue; + lnk_data.AMax = COLOR_A_MAX; + lnk_data.BMax = COLOR_B_MAX; + list_push_back(&thresholds, &lnk_data); + imlib_binary(&temp_image, &temp_image, &thresholds, false, false, NULL); + list_free(&thresholds); + + imlib_erode(&temp_image, 3, 30, NULL); + imlib_dilate(&temp_image, 1, 1, NULL); + + // Get Shadow Average + + image_t temp_image_2; + temp_image_2.w = temp_image.w; + temp_image_2.h = temp_image.h; + temp_image_2.bpp = temp_image.bpp; + temp_image_2.data = fb_alloc(image_size(&temp_image)); + + memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); + imlib_erode(&temp_image_2, 3, 48, NULL); + + int shadow_r_sum = 0; + int shadow_g_sum = 0; + int shadow_b_sum = 0; + int shadow_count = 0; + + for (int y = 0, yy = temp_image_2.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y); + uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + + for (int x = 0, xx = temp_image_2.w; x < xx; x++) { + if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); + int r = COLOR_RGB565_TO_R8(pixel); + int g = COLOR_RGB565_TO_G8(pixel); + int b = COLOR_RGB565_TO_R8(pixel); + shadow_r_sum += r; + shadow_g_sum += g; + shadow_b_sum += b; + shadow_count += 1; + } + } + } + + memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); + imlib_invert(&temp_image_2); + imlib_erode(&temp_image_2, 5, 120, NULL); + imlib_invert(&temp_image_2); + imlib_b_xor(&temp_image_2, NULL, &temp_image, 0, NULL); + imlib_erode(&temp_image_2, 2, 24, NULL); + + int not_shadow_r_sum = 0; + int not_shadow_g_sum = 0; + int not_shadow_b_sum = 0; + int not_shadow_count = 0; + + for (int y = 0, yy = temp_image_2.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y); + uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + + for (int x = 0, xx = temp_image_2.w; x < xx; x++) { + if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); + int r = COLOR_RGB565_TO_R8(pixel); + int g = COLOR_RGB565_TO_G8(pixel); + int b = COLOR_RGB565_TO_R8(pixel); + not_shadow_r_sum += r; + not_shadow_g_sum += g; + not_shadow_b_sum += b; + not_shadow_count += 1; + } + } + } + + // Fill in the umbra... (inner part of the shadow)... + + memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image)); + + imlib_mean_filter(&temp_image, 2, false, 0, false, NULL); + + if (shadow_count && not_shadow_count) { + + float shadow_r_average = ((float) shadow_r_sum) / ((float) shadow_count); + float shadow_g_average = ((float) shadow_g_sum) / ((float) shadow_count); + float shadow_b_average = ((float) shadow_b_sum) / ((float) shadow_count); + + float not_shadow_r_average = ((float) not_shadow_r_sum) / ((float) not_shadow_count); + float not_shadow_g_average = ((float) not_shadow_g_sum) / ((float) not_shadow_count); + float not_shadow_b_average = ((float) not_shadow_b_sum) / ((float) not_shadow_count); + + float diff_r = not_shadow_r_average - shadow_r_average; + float diff_g = not_shadow_g_average - shadow_g_average; + float diff_b = not_shadow_b_average - shadow_b_average; + + for (int y = 0; y < img->h; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y); + uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + + for (int x = 0; x < img->w; x++) { + float alpha = ((float) (COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) - COLOR_Y_MIN)) / ((float) (COLOR_Y_MAX - COLOR_Y_MIN)); + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x); + int r = COLOR_RGB565_TO_R8(pixel); + int g = COLOR_RGB565_TO_G8(pixel); + int b = COLOR_RGB565_TO_B8(pixel); + + int r_new = IM_MIN(IM_MAX(r + (diff_r * alpha), COLOR_R8_MIN), COLOR_R8_MAX); + int g_new = IM_MIN(IM_MAX(g + (diff_g * alpha), COLOR_G8_MIN), COLOR_G8_MAX); + int b_new = IM_MIN(IM_MAX(b + (diff_b * alpha), COLOR_B8_MIN), COLOR_B8_MAX); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x, COLOR_R8_G8_B8_TO_RGB565(r_new, g_new, b_new)); + } + } + } + + // Fill in the penumbra... (outer part of the shadow)... + + memcpy(temp_image.data, temp_image_2.data, image_size(&temp_image_2)); + + imlib_erode(&temp_image_2, 1, 8, NULL); + imlib_b_xor(&temp_image, NULL, &temp_image_2, 0, NULL); + imlib_dilate(&temp_image, 3, 0, NULL); + imlib_median_filter(img, 2, 12, false, 0, false, &temp_image); + + fb_free(); // temp_image_2 + } + + fb_free(); // BBins + fb_free(); // ABins + fb_free(); // LBins + + fb_free(); // temp_image + } +} + +#undef imlib_remove_shadows_kernel_size +#undef imlib_remove_shadows_kernel_rank +#endif //IMLIB_ENABLE_REMOVE_SHADOWS + +#ifdef IMLIB_ENABLE_CHROMINVAR +extern const float xyz_table[256]; + +void imlib_chrominvar(image_t *img) +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + break; + } + case IMAGE_BPP_GRAYSCALE: { + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)]; + float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)]; + float b_lin = xyz_table[COLOR_RGB565_TO_B8(pixel)]; + + float lin_sum = r_lin + g_lin + b_lin; + + float r_lin_div = 0.0f; + float g_lin_div = 0.0f; + float b_lin_div = 0.0f; + + if (lin_sum > 0.0f) { + lin_sum = 1.0f / lin_sum; + r_lin_div = r_lin * lin_sum; + g_lin_div = g_lin * lin_sum; + b_lin_div = b_lin * lin_sum; + } + + int r_lin_div_int = IM_MAX(IM_MIN(r_lin_div * 255.0f, COLOR_R8_MAX), COLOR_R8_MIN); + int g_lin_div_int = IM_MAX(IM_MIN(g_lin_div * 255.0f, COLOR_G8_MAX), COLOR_G8_MIN); + int b_lin_div_int = IM_MAX(IM_MIN(b_lin_div * 255.0f, COLOR_B8_MAX), COLOR_B8_MIN); + + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, COLOR_R8_G8_B8_TO_RGB565(r_lin_div_int, g_lin_div_int, b_lin_div_int)); + } + } + + break; + } + default: { + break; + } + } +} +#endif //IMLIB_ENABLE_CHROMINVAR + +#ifdef IMLIB_ENABLE_ILLUMINVAR +extern const uint16_t invariant_table[65536]; + +void imlib_illuminvar(image_t *img) // http://ai.stanford.edu/~alireza/publication/cic15.pdf +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + break; + } + case IMAGE_BPP_GRAYSCALE: { + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + for (int x = 0, xx = img->w; x < xx; x++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); +#ifdef IMLIB_ENABLE_INVARIANT_TABLE + int rgb565 = invariant_table[pixel]; +#else + float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)] + 1.0; + float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)] + 1.0; + float b_lin = xyz_table[COLOR_RGB565_TO_B8(pixel)] + 1.0; + + float r_lin_sharp = (r_lin * 0.9968f) + (g_lin * 0.0228f) + (b_lin * 0.0015f); + float g_lin_sharp = (r_lin * -0.0071f) + (g_lin * 0.9933f) + (b_lin * 0.0146f); + float b_lin_sharp = (r_lin * 0.0103f) + (g_lin * -0.0161f) + (b_lin * 0.9839f); + + float lin_sharp_avg = r_lin_sharp * g_lin_sharp * b_lin_sharp; + lin_sharp_avg = (lin_sharp_avg > 0.0f) ? fast_cbrtf(lin_sharp_avg) : 0.0f; + + float r_lin_sharp_div = 0.0f; + float g_lin_sharp_div = 0.0f; + float b_lin_sharp_div = 0.0f; + + if (lin_sharp_avg > 0.0f) { + lin_sharp_avg = 1.0f / lin_sharp_avg; + r_lin_sharp_div = r_lin_sharp * lin_sharp_avg; + g_lin_sharp_div = g_lin_sharp * lin_sharp_avg; + b_lin_sharp_div = b_lin_sharp * lin_sharp_avg; + } + + float r_lin_sharp_div_log = (r_lin_sharp_div > 0.0f) ? fast_log(r_lin_sharp_div) : 0.0f; + float g_lin_sharp_div_log = (g_lin_sharp_div > 0.0f) ? fast_log(g_lin_sharp_div) : 0.0f; + float b_lin_sharp_div_log = (b_lin_sharp_div > 0.0f) ? fast_log(b_lin_sharp_div) : 0.0f; + + float chi_x = (r_lin_sharp_div_log * 0.7071f) + (g_lin_sharp_div_log * -0.7071f) + (b_lin_sharp_div_log * 0.0000f); + float chi_y = (r_lin_sharp_div_log * 0.4082f) + (g_lin_sharp_div_log * 0.4082f) + (b_lin_sharp_div_log * -0.8164f); + + float e_t_x = 0.9326f; + float e_t_y = -0.3609f; + + float p_th_00 = e_t_x * e_t_x; + float p_th_01 = e_t_x * e_t_y; + float p_th_10 = e_t_y * e_t_x; + float p_th_11 = e_t_y * e_t_y; + + float x_th_x = (p_th_00 * chi_x) + (p_th_01 * chi_y); + float x_th_y = (p_th_10 * chi_x) + (p_th_11 * chi_y); + + float r_chi = (x_th_x * 0.7071f) + (x_th_y * 0.4082f); + float g_chi = (x_th_x * -0.7071f) + (x_th_y * 0.4082f); + float b_chi = (x_th_x * 0.0000f) + (x_th_y * -0.8164f); + + float r_chi_invariant = fast_expf(r_chi); + float g_chi_invariant = fast_expf(g_chi); + float b_chi_invariant = fast_expf(b_chi); + + float chi_invariant_sum = r_chi_invariant + g_chi_invariant + b_chi_invariant; + + float r_chi_invariant_m = 0.0f; + float g_chi_invariant_m = 0.0f; + float b_chi_invariant_m = 0.0f; + + if (chi_invariant_sum > 0.0f) { + chi_invariant_sum = 1.0f / chi_invariant_sum; + r_chi_invariant_m = r_chi_invariant * chi_invariant_sum; + g_chi_invariant_m = g_chi_invariant * chi_invariant_sum; + b_chi_invariant_m = b_chi_invariant * chi_invariant_sum; + } + + int r_chi_invariant_m_int = IM_MAX(IM_MIN(r_chi_invariant_m * 255.0f, COLOR_R8_MAX), COLOR_R8_MIN); + int g_chi_invariant_m_int = IM_MAX(IM_MIN(g_chi_invariant_m * 255.0f, COLOR_G8_MAX), COLOR_G8_MIN); + int b_chi_invariant_m_int = IM_MAX(IM_MIN(b_chi_invariant_m * 255.0f, COLOR_B8_MAX), COLOR_B8_MIN); + + int rgb565 = COLOR_R8_G8_B8_TO_RGB565(r_chi_invariant_m_int, g_chi_invariant_m_int, b_chi_invariant_m_int); +#endif + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, rgb565); + } + } + + break; + } + default: { + break; + } + } +} +#endif //IMLIB_ENABLE_ILLUMINVAR diff --git a/src/openmv/src/omv/img/sincos_tab.c b/src/openmv/src/omv/img/sincos_tab.c new file mode 100755 index 0000000..73cfd9a --- /dev/null +++ b/src/openmv/src/omv/img/sincos_tab.c @@ -0,0 +1,95 @@ +const float sin_table[360] = { + 0.000000f, 0.017452f, 0.034899f, 0.052336f, 0.069756f, 0.087156f, 0.104528f, 0.121869f, + 0.139173f, 0.156434f, 0.173648f, 0.190809f, 0.207912f, 0.224951f, 0.241922f, 0.258819f, + 0.275637f, 0.292372f, 0.309017f, 0.325568f, 0.342020f, 0.358368f, 0.374607f, 0.390731f, + 0.406737f, 0.422618f, 0.438371f, 0.453990f, 0.469472f, 0.484810f, 0.500000f, 0.515038f, + 0.529919f, 0.544639f, 0.559193f, 0.573576f, 0.587785f, 0.601815f, 0.615661f, 0.629320f, + 0.642788f, 0.656059f, 0.669131f, 0.681998f, 0.694658f, 0.707107f, 0.719340f, 0.731354f, + 0.743145f, 0.754710f, 0.766044f, 0.777146f, 0.788011f, 0.798636f, 0.809017f, 0.819152f, + 0.829038f, 0.838671f, 0.848048f, 0.857167f, 0.866025f, 0.874620f, 0.882948f, 0.891007f, + 0.898794f, 0.906308f, 0.913545f, 0.920505f, 0.927184f, 0.933580f, 0.939693f, 0.945519f, + 0.951057f, 0.956305f, 0.961262f, 0.965926f, 0.970296f, 0.974370f, 0.978148f, 0.981627f, + 0.984808f, 0.987688f, 0.990268f, 0.992546f, 0.994522f, 0.996195f, 0.997564f, 0.998630f, + 0.999391f, 0.999848f, 1.000000f, 0.999848f, 0.999391f, 0.998630f, 0.997564f, 0.996195f, + 0.994522f, 0.992546f, 0.990268f, 0.987688f, 0.984808f, 0.981627f, 0.978148f, 0.974370f, + 0.970296f, 0.965926f, 0.961262f, 0.956305f, 0.951057f, 0.945519f, 0.939693f, 0.933580f, + 0.927184f, 0.920505f, 0.913545f, 0.906308f, 0.898794f, 0.891007f, 0.882948f, 0.874620f, + 0.866025f, 0.857167f, 0.848048f, 0.838671f, 0.829038f, 0.819152f, 0.809017f, 0.798636f, + 0.788011f, 0.777146f, 0.766044f, 0.754710f, 0.743145f, 0.731354f, 0.719340f, 0.707107f, + 0.694658f, 0.681998f, 0.669131f, 0.656059f, 0.642788f, 0.629320f, 0.615661f, 0.601815f, + 0.587785f, 0.573576f, 0.559193f, 0.544639f, 0.529919f, 0.515038f, 0.500000f, 0.484810f, + 0.469472f, 0.453990f, 0.438371f, 0.422618f, 0.406737f, 0.390731f, 0.374607f, 0.358368f, + 0.342020f, 0.325568f, 0.309017f, 0.292372f, 0.275637f, 0.258819f, 0.241922f, 0.224951f, + 0.207912f, 0.190809f, 0.173648f, 0.156434f, 0.139173f, 0.121869f, 0.104528f, 0.087156f, + 0.069756f, 0.052336f, 0.034899f, 0.017452f, 0.000000f, -0.017452f, -0.034899f, -0.052336f, + -0.069756f, -0.087156f, -0.104528f, -0.121869f, -0.139173f, -0.156434f, -0.173648f, -0.190809f, + -0.207912f, -0.224951f, -0.241922f, -0.258819f, -0.275637f, -0.292372f, -0.309017f, -0.325568f, + -0.342020f, -0.358368f, -0.374607f, -0.390731f, -0.406737f, -0.422618f, -0.438371f, -0.453990f, + -0.469472f, -0.484810f, -0.500000f, -0.515038f, -0.529919f, -0.544639f, -0.559193f, -0.573576f, + -0.587785f, -0.601815f, -0.615661f, -0.629320f, -0.642788f, -0.656059f, -0.669131f, -0.681998f, + -0.694658f, -0.707107f, -0.719340f, -0.731354f, -0.743145f, -0.754710f, -0.766044f, -0.777146f, + -0.788011f, -0.798636f, -0.809017f, -0.819152f, -0.829038f, -0.838671f, -0.848048f, -0.857167f, + -0.866025f, -0.874620f, -0.882948f, -0.891007f, -0.898794f, -0.906308f, -0.913545f, -0.920505f, + -0.927184f, -0.933580f, -0.939693f, -0.945519f, -0.951057f, -0.956305f, -0.961262f, -0.965926f, + -0.970296f, -0.974370f, -0.978148f, -0.981627f, -0.984808f, -0.987688f, -0.990268f, -0.992546f, + -0.994522f, -0.996195f, -0.997564f, -0.998630f, -0.999391f, -0.999848f, -1.000000f, -0.999848f, + -0.999391f, -0.998630f, -0.997564f, -0.996195f, -0.994522f, -0.992546f, -0.990268f, -0.987688f, + -0.984808f, -0.981627f, -0.978148f, -0.974370f, -0.970296f, -0.965926f, -0.961262f, -0.956305f, + -0.951057f, -0.945519f, -0.939693f, -0.933580f, -0.927184f, -0.920505f, -0.913545f, -0.906308f, + -0.898794f, -0.891007f, -0.882948f, -0.874620f, -0.866025f, -0.857167f, -0.848048f, -0.838671f, + -0.829038f, -0.819152f, -0.809017f, -0.798636f, -0.788011f, -0.777146f, -0.766044f, -0.754710f, + -0.743145f, -0.731354f, -0.719340f, -0.707107f, -0.694658f, -0.681998f, -0.669131f, -0.656059f, + -0.642788f, -0.629320f, -0.615661f, -0.601815f, -0.587785f, -0.573576f, -0.559193f, -0.544639f, + -0.529919f, -0.515038f, -0.500000f, -0.484810f, -0.469472f, -0.453990f, -0.438371f, -0.422618f, + -0.406737f, -0.390731f, -0.374607f, -0.358368f, -0.342020f, -0.325568f, -0.309017f, -0.292372f, + -0.275637f, -0.258819f, -0.241922f, -0.224951f, -0.207912f, -0.190809f, -0.173648f, -0.156434f, + -0.139173f, -0.121869f, -0.104528f, -0.087156f, -0.069756f, -0.052336f, -0.034899f, -0.017452f +}; + +const float cos_table[360] = { + 1.000000f, 0.999848f, 0.999391f, 0.998630f, 0.997564f, 0.996195f, 0.994522f, 0.992546f, + 0.990268f, 0.987688f, 0.984808f, 0.981627f, 0.978148f, 0.974370f, 0.970296f, 0.965926f, + 0.961262f, 0.956305f, 0.951057f, 0.945519f, 0.939693f, 0.933580f, 0.927184f, 0.920505f, + 0.913545f, 0.906308f, 0.898794f, 0.891007f, 0.882948f, 0.874620f, 0.866025f, 0.857167f, + 0.848048f, 0.838671f, 0.829038f, 0.819152f, 0.809017f, 0.798636f, 0.788011f, 0.777146f, + 0.766044f, 0.754710f, 0.743145f, 0.731354f, 0.719340f, 0.707107f, 0.694658f, 0.681998f, + 0.669131f, 0.656059f, 0.642788f, 0.629320f, 0.615661f, 0.601815f, 0.587785f, 0.573576f, + 0.559193f, 0.544639f, 0.529919f, 0.515038f, 0.500000f, 0.484810f, 0.469472f, 0.453990f, + 0.438371f, 0.422618f, 0.406737f, 0.390731f, 0.374607f, 0.358368f, 0.342020f, 0.325568f, + 0.309017f, 0.292372f, 0.275637f, 0.258819f, 0.241922f, 0.224951f, 0.207912f, 0.190809f, + 0.173648f, 0.156434f, 0.139173f, 0.121869f, 0.104528f, 0.087156f, 0.069756f, 0.052336f, + 0.034899f, 0.017452f, 0.000000f, -0.017452f, -0.034899f, -0.052336f, -0.069756f, -0.087156f, + -0.104528f, -0.121869f, -0.139173f, -0.156434f, -0.173648f, -0.190809f, -0.207912f, -0.224951f, + -0.241922f, -0.258819f, -0.275637f, -0.292372f, -0.309017f, -0.325568f, -0.342020f, -0.358368f, + -0.374607f, -0.390731f, -0.406737f, -0.422618f, -0.438371f, -0.453990f, -0.469472f, -0.484810f, + -0.500000f, -0.515038f, -0.529919f, -0.544639f, -0.559193f, -0.573576f, -0.587785f, -0.601815f, + -0.615661f, -0.629320f, -0.642788f, -0.656059f, -0.669131f, -0.681998f, -0.694658f, -0.707107f, + -0.719340f, -0.731354f, -0.743145f, -0.754710f, -0.766044f, -0.777146f, -0.788011f, -0.798636f, + -0.809017f, -0.819152f, -0.829038f, -0.838671f, -0.848048f, -0.857167f, -0.866025f, -0.874620f, + -0.882948f, -0.891007f, -0.898794f, -0.906308f, -0.913545f, -0.920505f, -0.927184f, -0.933580f, + -0.939693f, -0.945519f, -0.951057f, -0.956305f, -0.961262f, -0.965926f, -0.970296f, -0.974370f, + -0.978148f, -0.981627f, -0.984808f, -0.987688f, -0.990268f, -0.992546f, -0.994522f, -0.996195f, + -0.997564f, -0.998630f, -0.999391f, -0.999848f, -1.000000f, -0.999848f, -0.999391f, -0.998630f, + -0.997564f, -0.996195f, -0.994522f, -0.992546f, -0.990268f, -0.987688f, -0.984808f, -0.981627f, + -0.978148f, -0.974370f, -0.970296f, -0.965926f, -0.961262f, -0.956305f, -0.951057f, -0.945519f, + -0.939693f, -0.933580f, -0.927184f, -0.920505f, -0.913545f, -0.906308f, -0.898794f, -0.891007f, + -0.882948f, -0.874620f, -0.866025f, -0.857167f, -0.848048f, -0.838671f, -0.829038f, -0.819152f, + -0.809017f, -0.798636f, -0.788011f, -0.777146f, -0.766044f, -0.754710f, -0.743145f, -0.731354f, + -0.719340f, -0.707107f, -0.694658f, -0.681998f, -0.669131f, -0.656059f, -0.642788f, -0.629320f, + -0.615661f, -0.601815f, -0.587785f, -0.573576f, -0.559193f, -0.544639f, -0.529919f, -0.515038f, + -0.500000f, -0.484810f, -0.469472f, -0.453990f, -0.438371f, -0.422618f, -0.406737f, -0.390731f, + -0.374607f, -0.358368f, -0.342020f, -0.325568f, -0.309017f, -0.292372f, -0.275637f, -0.258819f, + -0.241922f, -0.224951f, -0.207912f, -0.190809f, -0.173648f, -0.156434f, -0.139173f, -0.121869f, + -0.104528f, -0.087156f, -0.069756f, -0.052336f, -0.034899f, -0.017452f, -0.000000f, 0.017452f, + 0.034899f, 0.052336f, 0.069756f, 0.087156f, 0.104528f, 0.121869f, 0.139173f, 0.156434f, + 0.173648f, 0.190809f, 0.207912f, 0.224951f, 0.241922f, 0.258819f, 0.275637f, 0.292372f, + 0.309017f, 0.325568f, 0.342020f, 0.358368f, 0.374607f, 0.390731f, 0.406737f, 0.422618f, + 0.438371f, 0.453990f, 0.469472f, 0.484810f, 0.500000f, 0.515038f, 0.529919f, 0.544639f, + 0.559193f, 0.573576f, 0.587785f, 0.601815f, 0.615661f, 0.629320f, 0.642788f, 0.656059f, + 0.669131f, 0.681998f, 0.694658f, 0.707107f, 0.719340f, 0.731354f, 0.743145f, 0.754710f, + 0.766044f, 0.777146f, 0.788011f, 0.798636f, 0.809017f, 0.819152f, 0.829038f, 0.838671f, + 0.848048f, 0.857167f, 0.866025f, 0.874620f, 0.882948f, 0.891007f, 0.898794f, 0.906308f, + 0.913545f, 0.920505f, 0.927184f, 0.933580f, 0.939693f, 0.945519f, 0.951057f, 0.956305f, + 0.961262f, 0.965926f, 0.970296f, 0.974370f, 0.978148f, 0.981627f, 0.984808f, 0.987688f, + 0.990268f, 0.992546f, 0.994522f, 0.996195f, 0.997564f, 0.998630f, 0.999391f, 0.999848f +}; diff --git a/src/openmv/src/omv/img/stats.c b/src/openmv/src/omv/img/stats.c new file mode 100755 index 0000000..d96b3e0 --- /dev/null +++ b/src/openmv/src/omv/img/stats.c @@ -0,0 +1,1023 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "imlib.h" + +#ifdef IMLIB_ENABLE_GET_SIMILARITY +typedef struct imlib_similatiry_line_op_state { + int *sumBucketsOfX, *sumBucketsOfY, *sum2BucketsOfX, *sum2BucketsOfY, *sum2Buckets; + float similarity_sum, similarity_sum_2, similarity_min, similarity_max; + int lines_processed; +} imlib_similatiry_line_op_state_t; + +void imlib_similarity_line_op(image_t *img, int line, void *other, void *data, bool vflipped) +{ + imlib_similatiry_line_op_state_t *state = (imlib_similatiry_line_op_state_t *) data; vflipped = vflipped; + float c1 = 0, c2 = 0; + + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line); + uint32_t *other_row_ptr = (uint32_t *) other; + for (int x = 0, xx = (img->w + 7) / 8; x < xx; x++) { + for (int i = 0, ii = IM_MIN((img->w - (x * 8)), 8); i < ii; i++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x + i); + int other_pixel = IMAGE_GET_BINARY_PIXEL_FAST(other_row_ptr, x + i); + state->sumBucketsOfX[x] += pixel; + state->sumBucketsOfY[x] += other_pixel; + state->sum2BucketsOfX[x] += pixel * pixel; + state->sum2BucketsOfY[x] += other_pixel * other_pixel; + state->sum2Buckets[x] += pixel * other_pixel; + } + } + c1 = COLOR_BINARY_MAX * 0.01f; + c2 = COLOR_BINARY_MAX * 0.03f; + break; + } + case IMAGE_BPP_GRAYSCALE: { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line); + uint8_t *other_row_ptr = (uint8_t *) other; + for (int x = 0, xx = (img->w + 7) / 8; x < xx; x++) { + for (int i = 0, ii = IM_MIN((img->w - (x * 8)), 8); i < ii; i++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x + i); + int other_pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(other_row_ptr, x + i); + state->sumBucketsOfX[x] += pixel; + state->sumBucketsOfY[x] += other_pixel; + state->sum2BucketsOfX[x] += pixel * pixel; + state->sum2BucketsOfY[x] += other_pixel * other_pixel; + state->sum2Buckets[x] += pixel * other_pixel; + } + } + c1 = COLOR_GRAYSCALE_MAX * 0.01f; + c2 = COLOR_GRAYSCALE_MAX * 0.03f; + break; + } + case IMAGE_BPP_RGB565: { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line); + uint16_t *other_row_ptr = (uint16_t *) other; + for (int x = 0, xx = (img->w + 7) / 8; x < xx; x++) { + for (int i = 0, ii = IM_MIN((img->w - (x * 8)), 8); i < ii; i++) { + int pixel = COLOR_RGB565_TO_L(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x + i)); + int other_pixel = COLOR_RGB565_TO_L(IMAGE_GET_RGB565_PIXEL_FAST(other_row_ptr, x + i)); + state->sumBucketsOfX[x] += pixel; + state->sumBucketsOfY[x] += other_pixel; + state->sum2BucketsOfX[x] += pixel * pixel; + state->sum2BucketsOfY[x] += other_pixel * other_pixel; + state->sum2Buckets[x] += pixel * other_pixel; + } + } + c1 = COLOR_L_MAX * 0.01f; + c2 = COLOR_L_MAX * 0.03f; + break; + } + default: { + break; + } + } + + // https://en.wikipedia.org/wiki/Structural_similarity + if (((state->lines_processed + 1) == img->h) || (!((state->lines_processed + 1) % 8))) { + for (int x = 0, xx = (img->w + 7) / 8; x < xx; x++) { + int w = IM_MIN((img->w - (x * 8)), 8); + int h = IM_MIN((img->h - ((state->lines_processed / 8) * 8)), 8); + int size = w * h; + + int mx = state->sumBucketsOfX[x] / size; + int my = state->sumBucketsOfY[x] / size; + int vx = state->sum2BucketsOfX[x] - ((mx * state->sumBucketsOfX[x]) + (mx * state->sumBucketsOfX[x])) + (size * mx * mx); + int vy = state->sum2BucketsOfY[x] - ((my * state->sumBucketsOfY[x]) + (my * state->sumBucketsOfY[x])) + (size * my * my); + int vxy = state->sum2Buckets[x] - ((mx * state->sumBucketsOfY[x]) + (my * state->sumBucketsOfX[x])) + (size * mx * my); + + float ssim = ( ((2*mx*my) + c1) * ((2*vxy) + c2) ) / ( ((mx*mx) + (my*my) + c1) * (vx + vy + c2) ); + + state->similarity_sum += ssim; + state->similarity_sum_2 += ssim * ssim; + state->similarity_min = IM_MIN(state->similarity_min, ssim); + state->similarity_max = IM_MAX(state->similarity_max, ssim); + + state->sumBucketsOfX[x] = 0; + state->sumBucketsOfY[x] = 0; + state->sum2BucketsOfX[x] = 0; + state->sum2BucketsOfY[x] = 0; + state->sum2Buckets[x] = 0; + } + } + + state->lines_processed += 1; +} + +void imlib_get_similarity(image_t *img, const char *path, image_t *other, int scalar, float *avg, float *std, float *min, float *max) +{ + int h_blocks = (img->w + 7) / 8; + int v_blocks = (img->h + 7) / 8; + int blocks = h_blocks * v_blocks; + + int int_h_blocks = h_blocks * sizeof(int); + imlib_similatiry_line_op_state_t state; + state.sumBucketsOfX = fb_alloc0(int_h_blocks); + state.sumBucketsOfY = fb_alloc0(int_h_blocks); + state.sum2BucketsOfX = fb_alloc0(int_h_blocks); + state.sum2BucketsOfY = fb_alloc0(int_h_blocks); + state.sum2Buckets = fb_alloc0(int_h_blocks); + state.similarity_sum = 0.0f; + state.similarity_sum_2 = 0.0f; + state.similarity_min = FLT_MAX; + state.similarity_max = FLT_MIN; + state.lines_processed = 0; + + imlib_image_operation(img, path, other, scalar, imlib_similarity_line_op, &state); + *avg = state.similarity_sum / blocks; + *std = fast_sqrtf((state.similarity_sum_2 / blocks) - ((*avg) * (*avg))); + *min = state.similarity_min; + *max = state.similarity_max; + + fb_free(); + fb_free(); + fb_free(); + fb_free(); + fb_free(); +} +#endif //IMLIB_ENABLE_GET_SIMILARITY + +void imlib_get_histogram(histogram_t *out, image_t *ptr, rectangle_t *roi, list_t *thresholds, bool invert) +{ + switch(ptr->bpp) { + case IMAGE_BPP_BINARY: { + memset(out->LBins, 0, out->LBinCount * sizeof(uint32_t)); + + float mult = (out->LBinCount - 1) / ((float) (COLOR_BINARY_MAX - COLOR_BINARY_MIN)); + + if ((!thresholds) || (!list_size(thresholds))) { + // Fast histogram code when no color thresholds list... + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); + ((uint32_t *) out->LBins)[fast_roundf((pixel - COLOR_BINARY_MIN) * mult)]++; + } + } + } else { + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); + if (COLOR_THRESHOLD_BINARY(pixel, &lnk_data, invert)) { + ((uint32_t *) out->LBins)[fast_roundf((pixel - COLOR_BINARY_MIN) * mult)]++; + } + } + } + } + } + + float pixels = 1 / ((float) (roi->w * roi->h)); + + for (int i = 0, j = out->LBinCount; i < j; i++) { + out->LBins[i] = ((uint32_t *) out->LBins)[i] * pixels; + } + + break; + } + case IMAGE_BPP_GRAYSCALE: { + memset(out->LBins, 0, out->LBinCount * sizeof(uint32_t)); + + float mult = (out->LBinCount - 1) / ((float) (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN)); + + if ((!thresholds) || (!list_size(thresholds))) { + // Fast histogram code when no color thresholds list... + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + ((uint32_t *) out->LBins)[fast_roundf((pixel - COLOR_GRAYSCALE_MIN) * mult)]++; + } + } + } else { + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); + if (COLOR_THRESHOLD_GRAYSCALE(pixel, &lnk_data, invert)) { + ((uint32_t *) out->LBins)[fast_roundf((pixel - COLOR_GRAYSCALE_MIN) * mult)]++; + } + } + } + } + } + + float pixels = 1 / ((float) (roi->w * roi->h)); + + for (int i = 0, j = out->LBinCount; i < j; i++) { + out->LBins[i] = ((uint32_t *) out->LBins)[i] * pixels; + } + + break; + } + case IMAGE_BPP_RGB565: { + memset(out->LBins, 0, out->LBinCount * sizeof(uint32_t)); + memset(out->ABins, 0, out->ABinCount * sizeof(uint32_t)); + memset(out->BBins, 0, out->BBinCount * sizeof(uint32_t)); + + float l_mult = (out->LBinCount - 1) / ((float) (COLOR_L_MAX - COLOR_L_MIN)); + float a_mult = (out->ABinCount - 1) / ((float) (COLOR_A_MAX - COLOR_A_MIN)); + float b_mult = (out->BBinCount - 1) / ((float) (COLOR_B_MAX - COLOR_B_MIN)); + + if ((!thresholds) || (!list_size(thresholds))) { + // Fast histogram code when no color thresholds list... + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + ((uint32_t *) out->LBins)[fast_roundf((COLOR_RGB565_TO_L(pixel) - COLOR_L_MIN) * l_mult)]++; + ((uint32_t *) out->ABins)[fast_roundf((COLOR_RGB565_TO_A(pixel) - COLOR_A_MIN) * a_mult)]++; + ((uint32_t *) out->BBins)[fast_roundf((COLOR_RGB565_TO_B(pixel) - COLOR_B_MIN) * b_mult)]++; + } + } + } else { + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + if (COLOR_THRESHOLD_RGB565(pixel, &lnk_data, invert)) { + ((uint32_t *) out->LBins)[fast_roundf((COLOR_RGB565_TO_L(pixel) - COLOR_L_MIN) * l_mult)]++; + ((uint32_t *) out->ABins)[fast_roundf((COLOR_RGB565_TO_A(pixel) - COLOR_A_MIN) * a_mult)]++; + ((uint32_t *) out->BBins)[fast_roundf((COLOR_RGB565_TO_B(pixel) - COLOR_B_MIN) * b_mult)]++; + } + } + } + } + } + + float pixels = 1 / ((float) (roi->w * roi->h)); + + for (int i = 0, j = out->LBinCount; i < j; i++) { + out->LBins[i] = ((uint32_t *) out->LBins)[i] * pixels; + } + + for (int i = 0, j = out->ABinCount; i < j; i++) { + out->ABins[i] = ((uint32_t *) out->ABins)[i] * pixels; + } + + for (int i = 0, j = out->BBinCount; i < j; i++) { + out->BBins[i] = ((uint32_t *) out->BBins)[i] * pixels; + } + + break; + } + default: { + break; + } + } +} + +void imlib_get_percentile(percentile_t *out, image_bpp_t bpp, histogram_t *ptr, float percentile) +{ + memset(out, 0, sizeof(percentile_t)); + switch(bpp) { + case IMAGE_BPP_BINARY: { + float mult = (COLOR_BINARY_MAX - COLOR_BINARY_MIN) / ((float) (ptr->LBinCount - 1)); + float median_count = 0; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + if ((median_count < percentile) && (percentile <= (median_count + ptr->LBins[i]))) { + out->LValue = fast_roundf((i * mult) + COLOR_BINARY_MIN); + break; + } + + median_count += ptr->LBins[i]; + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + float mult = (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / ((float) (ptr->LBinCount - 1)); + float median_count = 0; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + if ((median_count < percentile) && (percentile <= (median_count + ptr->LBins[i]))) { + out->LValue = fast_roundf((i * mult) + COLOR_GRAYSCALE_MIN); + break; + } + + median_count += ptr->LBins[i]; + } + break; + } + case IMAGE_BPP_RGB565: { + { + float mult = (COLOR_L_MAX - COLOR_L_MIN) / ((float) (ptr->LBinCount - 1)); + float median_count = 0; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + if ((median_count < percentile) && (percentile <= (median_count + ptr->LBins[i]))) { + out->LValue = fast_roundf((i * mult) + COLOR_L_MIN); + break; + } + + median_count += ptr->LBins[i]; + } + } + { + float mult = (COLOR_A_MAX - COLOR_A_MIN) / ((float) (ptr->ABinCount - 1)); + float median_count = 0; + + for (int i = 0, j = ptr->ABinCount; i < j; i++) { + if ((median_count < percentile) && (percentile <= (median_count + ptr->ABins[i]))) { + out->AValue = fast_roundf((i * mult) + COLOR_A_MIN); + break; + } + + median_count += ptr->ABins[i]; + } + } + { + float mult = (COLOR_B_MAX - COLOR_B_MIN) / ((float) (ptr->BBinCount - 1)); + float median_count = 0; + + for (int i = 0, j = ptr->BBinCount; i < j; i++) { + if ((median_count < percentile) && (percentile <= (median_count + ptr->BBins[i]))) { + out->BValue = fast_roundf((i * mult) + COLOR_B_MIN); + break; + } + + median_count += ptr->BBins[i]; + } + } + break; + } + default: { + break; + } + } +} + +static int ostu(int bincount, float *bins) +{ + float cdf[bincount]; memset(cdf, 0, bincount * sizeof(float)); + float weighted_cdf[bincount]; memset(weighted_cdf, 0, bincount * sizeof(float)); + + cdf[0] = bins[0]; + weighted_cdf[0] = 0 * bins[0]; + + for (int i = 1; i < bincount; i++) { + cdf[i] = cdf[i - 1] + bins[i]; + weighted_cdf[i] = weighted_cdf[i - 1] + (i * bins[i]); + } + + float variance[bincount]; memset(variance, 0, bincount * sizeof(float)); + float max_variance = 0.0f; + int threshold = 0; + + for (int i = 0, ii = bincount - 1; i < ii; i++) { + + if ((cdf[i] != 0.0f) && (cdf[i] != 1.0f)) { + variance[i] = powf((cdf[i] * weighted_cdf[bincount - 1]) - weighted_cdf[i], 2.0f) / (cdf[i] * (1.0f - cdf[i])); + } else { + variance[i] = 0.0f; + } + + if (variance[i] > max_variance) { + max_variance = variance[i]; + threshold = i; + } + } + + return threshold; +} + +void imlib_get_threshold(threshold_t *out, image_bpp_t bpp, histogram_t *ptr) +{ + memset(out, 0, sizeof(threshold_t)); + switch(bpp) { + case IMAGE_BPP_BINARY: { + out->LValue = (ostu(ptr->LBinCount, ptr->LBins) * (COLOR_BINARY_MAX - COLOR_BINARY_MIN)) / (ptr->LBinCount - 1); + break; + } + case IMAGE_BPP_GRAYSCALE: { + out->LValue = (ostu(ptr->LBinCount, ptr->LBins) * (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN)) / (ptr->LBinCount - 1); + break; + } + case IMAGE_BPP_RGB565: { + out->LValue = (ostu(ptr->LBinCount, ptr->LBins) * (COLOR_L_MAX - COLOR_L_MIN)) / (ptr->LBinCount - 1); + out->AValue = (ostu(ptr->ABinCount, ptr->ABins) * (COLOR_A_MAX - COLOR_A_MIN)) / (ptr->ABinCount - 1); + out->BValue = (ostu(ptr->BBinCount, ptr->BBins) * (COLOR_B_MAX - COLOR_B_MIN)) / (ptr->BBinCount - 1); + break; + } + default: { + break; + } + } +} + +void imlib_get_statistics(statistics_t *out, image_bpp_t bpp, histogram_t *ptr) +{ + memset(out, 0, sizeof(statistics_t)); + switch(bpp) { + case IMAGE_BPP_BINARY: { + float mult = (COLOR_BINARY_MAX - COLOR_BINARY_MIN) / ((float) (ptr->LBinCount - 1)); + + float avg = 0; + float stdev = 0; + float median_count = 0; + float mode_count = 0; + bool min_flag = false; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + float value_f = (i * mult) + COLOR_BINARY_MIN; + int value = fast_roundf(value_f); + + avg += value_f * ptr->LBins[i]; + stdev += value_f * value_f * ptr->LBins[i]; + + if ((median_count < 0.25f) && (0.25f <= (median_count + ptr->LBins[i]))) { + out->LLQ = value; + } + + if ((median_count < 0.5f) && (0.5f <= (median_count + ptr->LBins[i]))) { + out->LMedian = value; + } + + if ((median_count < 0.75f) && (0.75f <= (median_count + ptr->LBins[i]))) { + out->LUQ = value; + } + + if (ptr->LBins[i] > mode_count) { + mode_count = ptr->LBins[i]; + out->LMode = value; + } + + if ((ptr->LBins[i] > 0.0f) && (!min_flag)) { + min_flag = true; + out->LMin = value; + } + + if (ptr->LBins[i] > 0.0f) { + out->LMax = value; + } + + median_count += ptr->LBins[i]; + } + + out->LMean = fast_roundf(avg); + out->LSTDev = fast_roundf(fast_sqrtf(stdev - (avg * avg))); + break; + } + case IMAGE_BPP_GRAYSCALE: { + float mult = (COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / ((float) (ptr->LBinCount - 1)); + + float avg = 0; + float stdev = 0; + float median_count = 0; + float mode_count = 0; + bool min_flag = false; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + float value_f = (i * mult) + COLOR_GRAYSCALE_MIN; + int value = fast_roundf(value_f); + + avg += value_f * ptr->LBins[i]; + stdev += value_f * value_f * ptr->LBins[i]; + + if ((median_count < 0.25f) && (0.25f <= (median_count + ptr->LBins[i]))) { + out->LLQ = value; + } + + if ((median_count < 0.5f) && (0.5f <= (median_count + ptr->LBins[i]))) { + out->LMedian = value; + } + + if ((median_count < 0.75f) && (0.75f <= (median_count + ptr->LBins[i]))) { + out->LUQ = value; + } + + if (ptr->LBins[i] > mode_count) { + mode_count = ptr->LBins[i]; + out->LMode = value; + } + + if ((ptr->LBins[i] > 0.0f) && (!min_flag)) { + min_flag = true; + out->LMin = value; + } + + if (ptr->LBins[i] > 0.0f) { + out->LMax = value; + } + + median_count += ptr->LBins[i]; + } + + out->LMean = fast_roundf(avg); + out->LSTDev = fast_roundf(fast_sqrtf(stdev - (avg * avg))); + break; + } + case IMAGE_BPP_RGB565: { + { + float mult = (COLOR_L_MAX - COLOR_L_MIN) / ((float) (ptr->LBinCount - 1)); + + float avg = 0; + float stdev = 0; + float median_count = 0; + float mode_count = 0; + bool min_flag = false; + + for (int i = 0, j = ptr->LBinCount; i < j; i++) { + float value_f = (i * mult) + COLOR_L_MIN; + int value = fast_roundf(value_f); + + avg += value_f * ptr->LBins[i]; + stdev += value_f * value_f * ptr->LBins[i]; + + if ((median_count < 0.25f) && (0.25f <= (median_count + ptr->LBins[i]))) { + out->LLQ = value; + } + + if ((median_count < 0.5f) && (0.5f <= (median_count + ptr->LBins[i]))) { + out->LMedian = value; + } + + if ((median_count < 0.75f) && (0.75f <= (median_count + ptr->LBins[i]))) { + out->LUQ = value; + } + + if (ptr->LBins[i] > mode_count) { + mode_count = ptr->LBins[i]; + out->LMode = value; + } + + if ((ptr->LBins[i] > 0.0f) && (!min_flag)) { + min_flag = true; + out->LMin = value; + } + + if (ptr->LBins[i] > 0.0f) { + out->LMax = value; + } + + median_count += ptr->LBins[i]; + } + + out->LMean = fast_roundf(avg); + out->LSTDev = fast_roundf(fast_sqrtf(stdev - (avg * avg))); + } + { + float mult = (COLOR_A_MAX - COLOR_A_MIN) / ((float) (ptr->ABinCount - 1)); + + float avg = 0; + float stdev = 0; + float median_count = 0; + float mode_count = 0; + bool min_flag = false; + + for (int i = 0, j = ptr->ABinCount; i < j; i++) { + float value_f = (i * mult) + COLOR_A_MIN; + int value = fast_roundf(value_f); + + avg += value_f * ptr->ABins[i]; + stdev += value_f * value_f * ptr->ABins[i]; + + if ((median_count < 0.25f) && (0.25f <= (median_count + ptr->ABins[i]))) { + out->ALQ = value; + } + + if ((median_count < 0.5f) && (0.5f <= (median_count + ptr->ABins[i]))) { + out->AMedian = value; + } + + if ((median_count < 0.75f) && (0.75f <= (median_count + ptr->ABins[i]))) { + out->AUQ = value; + } + + if (ptr->ABins[i] > mode_count) { + mode_count = ptr->ABins[i]; + out->AMode = value; + } + + if ((ptr->ABins[i] > 0.0f) && (!min_flag)) { + min_flag = true; + out->AMin = value; + } + + if (ptr->ABins[i] > 0.0f) { + out->AMax = value; + } + + median_count += ptr->ABins[i]; + } + + out->AMean = fast_roundf(avg); + out->ASTDev = fast_roundf(fast_sqrtf(stdev - (avg * avg))); + } + { + float mult = (COLOR_B_MAX - COLOR_B_MIN) / ((float) (ptr->BBinCount - 1)); + + float avg = 0; + float stdev = 0; + float median_count = 0; + float mode_count = 0; + bool min_flag = false; + + for (int i = 0, j = ptr->BBinCount; i < j; i++) { + float value_f = (i * mult) + COLOR_B_MIN; + int value = fast_roundf(value_f); + + avg += value_f * ptr->BBins[i]; + stdev += value_f * value_f * ptr->BBins[i]; + + if ((median_count < 0.25f) && (0.25f <= (median_count + ptr->BBins[i]))) { + out->BLQ = value; + } + + if ((median_count < 0.5f) && (0.5f <= (median_count + ptr->BBins[i]))) { + out->BMedian = value; + } + + if ((median_count < 0.75f) && (0.75f <= (median_count + ptr->BBins[i]))) { + out->BUQ = value; + } + + if (ptr->BBins[i] > mode_count) { + mode_count = ptr->BBins[i]; + out->BMode = value; + } + + if ((ptr->BBins[i] > 0.0f) && (!min_flag)) { + min_flag = true; + out->BMin = value; + } + + if (ptr->BBins[i] > 0.0f) { + out->BMax = value; + } + + median_count += ptr->BBins[i]; + } + + out->BMean = fast_roundf(avg); + out->BSTDev = fast_roundf(fast_sqrtf(stdev - (avg * avg))); + } + break; + } + default: { + break; + } + } +} + +static int get_median(int *array, int array_sum, int array_len) +{ + const int median_threshold = (array_sum + 1) / 2; + int median_count = 0; + + for (int i = 0; i < array_len; i++) { + if ((median_count < median_threshold) && (median_threshold <= (median_count + array[i]))) return i; + median_count += array[i]; + } + + return array_len - 1; +} + +static int get_median_l(long long *array, long long array_sum, int array_len) +{ + const long long median_threshold = (array_sum + 1) / 2; + long long median_count = 0; + + for (int i = 0; i < array_len; i++) { + if ((median_count < median_threshold) && (median_threshold <= (median_count + array[i]))) return i; + median_count += array[i]; + } + + return array_len - 1; +} + +bool imlib_get_regression(find_lines_list_lnk_data_t *out, image_t *ptr, rectangle_t *roi, unsigned int x_stride, unsigned int y_stride, + list_t *thresholds, bool invert, unsigned int area_threshold, unsigned int pixels_threshold, bool robust) +{ + bool result = false; + memset(out, 0, sizeof(find_lines_list_lnk_data_t)); + + if (!robust) { // Least Squares + int blob_x1 = roi->x + roi->w - 1; + int blob_y1 = roi->y + roi->h - 1; + int blob_x2 = roi->x; + int blob_y2 = roi->y; + int blob_pixels = 0; + int blob_cx = 0; + int blob_cy = 0; + long long blob_a = 0; + long long blob_b = 0; + long long blob_c = 0; + + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + blob_cx += x; + blob_cy += y; + blob_a += x*x; + blob_b += x*y; + blob_c += y*y; + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + blob_cx += x; + blob_cy += y; + blob_a += x*x; + blob_b += x*y; + blob_c += y*y; + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + blob_cx += x; + blob_cy += y; + blob_a += x*x; + blob_b += x*y; + blob_c += y*y; + } + } + } + break; + } + default: { + break; + } + } + } + + int w = blob_x2 - blob_x1; + int h = blob_y2 - blob_y1; + if (blob_pixels && ((w * h) >= area_threshold) && (blob_pixels >= pixels_threshold)) { + // http://www.cse.usf.edu/~r1k/MachineVisionBook/MachineVision.files/MachineVision_Chapter2.pdf + // https://www.strchr.com/standard_deviation_in_one_pass + // + // a = sigma(x*x) + (mx*sigma(x)) + (mx*sigma(x)) + (sigma()*mx*mx) + // b = sigma(x*y) + (mx*sigma(y)) + (my*sigma(x)) + (sigma()*mx*my) + // c = sigma(y*y) + (my*sigma(y)) + (my*sigma(y)) + (sigma()*my*my) + // + // blob_a = sigma(x*x) + // blob_b = sigma(x*y) + // blob_c = sigma(y*y) + // blob_cx = sigma(x) + // blob_cy = sigma(y) + // blob_pixels = sigma() + + int mx = blob_cx / blob_pixels; // x centroid + int my = blob_cy / blob_pixels; // y centroid + int small_blob_a = blob_a - ((mx * blob_cx) + (mx * blob_cx)) + (blob_pixels * mx * mx); + int small_blob_b = blob_b - ((mx * blob_cy) + (my * blob_cx)) + (blob_pixels * mx * my); + int small_blob_c = blob_c - ((my * blob_cy) + (my * blob_cy)) + (blob_pixels * my * my); + + float rotation = ((small_blob_a != small_blob_c) ? (fast_atan2f(2 * small_blob_b, small_blob_a - small_blob_c) / 2.0f) : 1.570796f) + 1.570796f; // PI/2 + + out->theta = fast_roundf(rotation * 57.295780) % 180; // * (180 / PI) + if (out->theta < 0) out->theta += 180; + out->rho = fast_roundf(((mx - roi->x) * cos_table[out->theta]) + ((my - roi->y) * sin_table[out->theta])); + + float part0 = (small_blob_a + small_blob_c) / 2.0f; + float f_b = (float) small_blob_b; + float f_a_c = (float) (small_blob_a - small_blob_c); + float part1 = fast_sqrtf((4 * f_b * f_b) + (f_a_c * f_a_c)) / 2.0f; + float p_add = fast_sqrtf(part0 + part1); + float p_sub = fast_sqrtf(part0 - part1); + float e_min = IM_MIN(p_add, p_sub); + float e_max = IM_MAX(p_add, p_sub); + out->magnitude = fast_roundf(e_max / e_min) - 1; // Circle -> [0, INF) -> Line + + if ((45 <= out->theta) && (out->theta < 135)) { + // y = (r - x cos(t)) / sin(t) + out->line.x1 = 0; + out->line.y1 = fast_roundf((out->rho - (out->line.x1 * cos_table[out->theta])) / sin_table[out->theta]); + out->line.x2 = roi->w - 1; + out->line.y2 = fast_roundf((out->rho - (out->line.x2 * cos_table[out->theta])) / sin_table[out->theta]); + } else { + // x = (r - y sin(t)) / cos(t); + out->line.y1 = 0; + out->line.x1 = fast_roundf((out->rho - (out->line.y1 * sin_table[out->theta])) / cos_table[out->theta]); + out->line.y2 = roi->h - 1; + out->line.x2 = fast_roundf((out->rho - (out->line.y2 * sin_table[out->theta])) / cos_table[out->theta]); + } + + if(lb_clip_line(&out->line, 0, 0, roi->w, roi->h)) { + out->line.x1 += roi->x; + out->line.y1 += roi->y; + out->line.x2 += roi->x; + out->line.y2 += roi->y; + // Move rho too. + out->rho += fast_roundf((roi->x * cos_table[out->theta]) + (roi->y * sin_table[out->theta])); + result = true; + } else { + memset(out, 0, sizeof(find_lines_list_lnk_data_t)); + } + } + } else { // Theil-Sen Estimator + int *x_histogram = fb_alloc0(ptr->w * sizeof(int)); // Not roi so we don't have to adjust, we can burn the RAM. + int *y_histogram = fb_alloc0(ptr->h * sizeof(int)); // Not roi so we don't have to adjust, we can burn the RAM. + + long long *x_delta_histogram = fb_alloc0((2 * ptr->w) * sizeof(long long)); // Not roi so we don't have to adjust, we can burn the RAM. + long long *y_delta_histogram = fb_alloc0((2 * ptr->h) * sizeof(long long)); // Not roi so we don't have to adjust, we can burn the RAM. + + uint32_t size; + point_t *points = (point_t *) fb_alloc_all(&size); + size_t points_max = size / sizeof(point_t); + size_t points_count = 0; + + if(points_max) { + int blob_x1 = roi->x + roi->w - 1; + int blob_y1 = roi->y + roi->h - 1; + int blob_x2 = roi->x; + int blob_y2 = roi->y; + int blob_pixels = 0; + + for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { + color_thresholds_list_lnk_data_t lnk_data; + iterator_get(thresholds, it, &lnk_data); + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + x_histogram[x]++; + y_histogram[y]++; + + if(points_count < points_max) { + point_init(&points[points_count], x, y); + points_count += 1; + } + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + x_histogram[x]++; + y_histogram[y]++; + + if(points_count < points_max) { + point_init(&points[points_count], x, y); + points_count += 1; + } + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y += y_stride) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x + (y % x_stride), xx = roi->x + roi->w; x < xx; x += x_stride) { + if (COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x), &lnk_data, invert)) { + blob_x1 = IM_MIN(blob_x1, x); + blob_y1 = IM_MIN(blob_y1, y); + blob_x2 = IM_MAX(blob_x2, x); + blob_y2 = IM_MAX(blob_y2, y); + blob_pixels += 1; + x_histogram[x]++; + y_histogram[y]++; + + if(points_count < points_max) { + point_init(&points[points_count], x, y); + points_count += 1; + } + } + } + } + break; + } + default: { + break; + } + } + } + + int w = blob_x2 - blob_x1; + int h = blob_y2 - blob_y1; + if (blob_pixels && ((w * h) >= area_threshold) && (blob_pixels >= pixels_threshold)) { + long long delta_sum = (points_count * (points_count - 1)) / 2; + + if (delta_sum) { + // The code below computes the average slope between all pairs of points. + // This is a N^2 operation that can easily blow up if the image is not threshold carefully... + + for(int i = 0; i < points_count; i++) { + point_t *p0 = &points[i]; + for(int j = i + 1; j < points_count; j++) { + point_t *p1 = &points[j]; + x_delta_histogram[p0->x - p1->x + ptr->w]++; // Note we allocated 1 extra above so we can do ptr->w instead of (ptr->w-1). + y_delta_histogram[p0->y - p1->y + ptr->h]++; // Note we allocated 1 extra above so we can do ptr->h instead of (ptr->h-1). + } + } + + int mx = get_median(x_histogram, blob_pixels, ptr->w); // Output doesn't need adjustment. + int my = get_median(y_histogram, blob_pixels, ptr->h); // Output doesn't need adjustment. + int mdx = get_median_l(x_delta_histogram, delta_sum, 2 * ptr->w) - ptr->w; // Fix offset. + int mdy = get_median_l(y_delta_histogram, delta_sum, 2 * ptr->h) - ptr->h; // Fix offset. + + float rotation = (mdx ? fast_atan2f(mdy, mdx) : 1.570796f) + 1.570796f; // PI/2 + + out->theta = fast_roundf(rotation * 57.295780) % 180; // * (180 / PI) + if (out->theta < 0) out->theta += 180; + out->rho = fast_roundf(((mx - roi->x) * cos_table[out->theta]) + ((my - roi->y) * sin_table[out->theta])); + + out->magnitude = fast_roundf(fast_sqrtf((mdx * mdx) + (mdy * mdy))); + + if ((45 <= out->theta) && (out->theta < 135)) { + // y = (r - x cos(t)) / sin(t) + out->line.x1 = 0; + out->line.y1 = fast_roundf((out->rho - (out->line.x1 * cos_table[out->theta])) / sin_table[out->theta]); + out->line.x2 = roi->w - 1; + out->line.y2 = fast_roundf((out->rho - (out->line.x2 * cos_table[out->theta])) / sin_table[out->theta]); + } else { + // x = (r - y sin(t)) / cos(t); + out->line.y1 = 0; + out->line.x1 = fast_roundf((out->rho - (out->line.y1 * sin_table[out->theta])) / cos_table[out->theta]); + out->line.y2 = roi->h - 1; + out->line.x2 = fast_roundf((out->rho - (out->line.y2 * sin_table[out->theta])) / cos_table[out->theta]); + } + + if(lb_clip_line(&out->line, 0, 0, roi->w, roi->h)) { + out->line.x1 += roi->x; + out->line.y1 += roi->y; + out->line.x2 += roi->x; + out->line.y2 += roi->y; + // Move rho too. + out->rho += fast_roundf((roi->x * cos_table[out->theta]) + (roi->y * sin_table[out->theta])); + result = true; + } else { + memset(out, 0, sizeof(find_lines_list_lnk_data_t)); + } + } + } + } + + fb_free(); // points + fb_free(); // y_delta_histogram + fb_free(); // x_delta_histogram + fb_free(); // y_histogram + fb_free(); // x_histogram + } + + return result; +} diff --git a/src/openmv/src/omv/img/template.c b/src/openmv/src/omv/img/template.c new file mode 100755 index 0000000..acc6664 --- /dev/null +++ b/src/openmv/src/omv/img/template.c @@ -0,0 +1,276 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Template matching with NCC (Normalized Cross Correlation) using exhaustive and diamond search. + * + * References: + * Briechle, Kai, and Uwe D. Hanebeck. "Template matching using fast normalized cross correlation." Aerospace + * Lewis, J. P. "Fast normalized cross-correlation." + * Zhu, Shan, and Kai-Kuang Ma. "A new diamond search algorithm for fast block-matching motion estimation." + * + */ +#include +#include +#include + +#include "imlib.h" +#include "xalloc.h" + +static void set_dsp(int cx, int cy, point_t *pts, bool sdsp, int step) +{ + if (sdsp) { + // Small DSP + // 4 + // 3 0 1 + // 2 + pts[0].x = cx; + pts[0].y = cy; + + pts[1].x = cx + step/2; + pts[1].y = cy; + + pts[2].x = cx; + pts[2].y = cy + step/2; + + pts[3].x = cx - step/2; + pts[3].y = cy; + + pts[4].x = cx; + pts[4].y = cy - step/2; + } else { + // Large DSP + // 7 + // 6 8 + // 5 0 1 + // 4 2 + // 3 + pts[0].x = cx; + pts[0].y = cy; + + pts[1].x = cx + step; + pts[1].y = cy; + + pts[2].x = cx + step/2; + pts[2].y = cy + step/2; + + pts[3].x = cx; + pts[3].y = cy + step; + + pts[4].x = cx - step/2; + pts[4].y = cy + step/2; + + pts[5].x = cx - step; + pts[5].y = cy; + + pts[6].x = cx - step/2; + pts[6].y = cy - step/2; + + pts[7].x = cx; + pts[7].y = cy - step; + + pts[8].x = cx + step/2; + pts[8].y = cy - step/2; + + } +} + +static float find_block_ncc(image_t *f, image_t *t, i_image_t *sum, int t_mean, uint32_t t_sumsq, int u, int v) +{ + int w = t->w; + int h = t->h; + + int num = 0; + uint32_t f_sumsq=0; + + if (u < 0) { + u = 0; + } + + if (v < 0) { + v = 0; + } + + if (u+w >= f->w) { + w = f->w - u; + } + + if (v+h >= f->h) { + h = f->h - v; + } + + // Find the mean of the current patch + uint32_t f_sum = imlib_integral_lookup(sum, u, v, w, h); + uint32_t f_mean = f_sum / (w*h); + + // Find the normalized sum of squares of the image + for (int y=v; ydata[y*f->w+x]-f_mean; + int b = (int)t->data[(y-v)*t->w+(x-u)]-t_mean; + num += a*b; + f_sumsq += a*a; + } + } + + // Find the normalized cross-correlation + return (num/(fast_sqrtf(f_sumsq) * fast_sqrtf(t_sumsq))); +} + +float imlib_template_match_ds(image_t *f, image_t *t, rectangle_t *r) +{ + point_t pts[9]; + + // Integral images + i_image_t sum; + imlib_integral_image_alloc(&sum, f->w, f->h); + imlib_integral_image(f, &sum); + + // Normalized sum of squares of the template + int t_mean = 0; + uint32_t t_sumsq=0; + imlib_image_mean(t, &t_mean, &t_mean, &t_mean); + for (int i=0; i < (t->w*t->h); i++) { + int c = (int)t->data[i]-t_mean; + t_sumsq += c*c; + } + + int px = 0; + int py = 0; + + // Initial center point + int cx = f->w/2 - t->w/2; + int cy = f->h/2 - t->h/2; + + // Max cross-correlation + float max_xc=-FLT_MAX; + + // Start with the Large Diamond Search Pattern (LDSP) 9 points. + bool sdsp = false; + + // Step size == template width + int step = t->w; + + while (step > 0) { + // Set the Diamond Search Pattern (DSP). + set_dsp(cx, cy, pts, sdsp, step); + + // Set the number of search blocks (5 or 9 for SDSP and LDSP respectively). + int num_pts = (sdsp == true)? 5: 9; + + // Find the block with the highest NCC + for (int i=0; i= f->w || pts[i].y >= f->h) { + continue; + } + float blk_xc = find_block_ncc(f, t, &sum, t_mean, t_sumsq, pts[i].x, pts[i].y); + if (blk_xc > max_xc) { + px = pts[i].x; + py = pts[i].y; + max_xc = blk_xc; + } + } + + // If the highest correlation is found at the center block and search is using + // LDSP then the highest correlation is found, if not then switch search to SDSP. + if (px == cx && py == cy) { + // Note instead of switching to the smaller pattern, the step size can be reduced + // each time the highest correlation is found at the center, and break on step == 0. + // This makes DS much more accurate, but slower. + step --; + } + + // Set the new search center to the block with highest correlation + cx = px; + cy = py; + } + + r->x = cx; + r->y = cy; + r->w = t->w; + r->h = t->h; + + if (cx < 0) r->x = 0; + if (cy < 0) r->y = 0; + + if (cx+t->w > f->w) { + r->w = f->w - cx; + } + + if (cy+t->h > f->h) { + r->h = f->h - cy; + } + + imlib_integral_image_free(&sum); + + //printf("max xc: %f\n", (double) max_xc); + return max_xc; +} + +/* The NCC can be optimized using integral images and rectangular basis functions. + * See Kai Briechle's paper "Template Matching using Fast Normalized Cross Correlation". + * + * NOTE: only the denominator is optimized. + * + */ +float imlib_template_match_ex(image_t *f, image_t *t, rectangle_t *roi, int step, rectangle_t *r) +{ + int den_b=0; + float corr=0.0f; + + // Integral images + i_image_t sum; + i_image_t sumsq; + + imlib_integral_image_alloc(&sum, f->w, f->h); + imlib_integral_image_alloc(&sumsq, f->w, f->h); + + imlib_integral_image(f, &sum); + imlib_integral_image_sq(f, &sumsq); + + // Normalized sum of squares of the template + int t_mean = 0; + imlib_image_mean(t, &t_mean, &t_mean, &t_mean); + + for (int i=0; i < (t->w*t->h); i++) { + int c = (int)t->data[i]-t_mean; + den_b += c*c; + } + + for (int v=roi->y; v<=(roi->y+roi->h-t->h); v+=step) { + for (int u=roi->x; u<=(roi->x+roi->w-t->w); u+=step) { + int num = 0; + // The mean of the current patch + uint32_t f_sum = imlib_integral_lookup(&sum, u, v, t->w, t->h); + uint32_t f_sumsq = imlib_integral_lookup(&sumsq, u, v, t->w, t->h); + uint32_t f_mean = f_sum / (float) (t->w*t->h); + + // Normalized sum of squares of the image + for (int y=v; y<(v+t->h); y++) { + for (int x=u; x<(u+t->w); x++) { + int a = (int)f->data[y*f->w+x]-f_mean; + int b = (int)t->data[(y-v)*t->w+(x-u)]-t_mean; + num += a*b; + } + } + + uint32_t den_a = f_sumsq - f_sum * (f_sum / (float) (t->w * t->h)); + + // Find normalized cross-correlation + float c = num/(fast_sqrtf(den_a) * fast_sqrtf(den_b)); + + if (c > corr) { + corr = c; + r->x = u; + r->y = v; + r->w = t->w; + r->h = t->h; + } + } + } + + imlib_integral_image_free(&sum); + imlib_integral_image_free(&sumsq); + return corr; +} diff --git a/src/openmv/src/omv/img/xyz_tab.c b/src/openmv/src/omv/img/xyz_tab.c new file mode 100755 index 0000000..763d2b4 --- /dev/null +++ b/src/openmv/src/omv/img/xyz_tab.c @@ -0,0 +1,34 @@ +const float xyz_table[256] = { + 0.000000f, 0.030353f, 0.060705f, 0.091058f, 0.121411f, 0.151763f, 0.182116f, 0.212469f, + 0.242822f, 0.273174f, 0.303527f, 0.334654f, 0.367651f, 0.402472f, 0.439144f, 0.477695f, + 0.518152f, 0.560539f, 0.604883f, 0.651209f, 0.699541f, 0.749903f, 0.802319f, 0.856813f, + 0.913406f, 0.972122f, 1.032982f, 1.096009f, 1.161225f, 1.228649f, 1.298303f, 1.370208f, + 1.444384f, 1.520851f, 1.599629f, 1.680738f, 1.764195f, 1.850022f, 1.938236f, 2.028856f, + 2.121901f, 2.217388f, 2.315337f, 2.415763f, 2.518686f, 2.624122f, 2.732089f, 2.842604f, + 2.955683f, 3.071344f, 3.189603f, 3.310477f, 3.433981f, 3.560131f, 3.688945f, 3.820437f, + 3.954624f, 4.091520f, 4.231141f, 4.373503f, 4.518620f, 4.666509f, 4.817182f, 4.970657f, + 5.126946f, 5.286065f, 5.448028f, 5.612849f, 5.780543f, 5.951124f, 6.124605f, 6.301002f, + 6.480327f, 6.662594f, 6.847817f, 7.036010f, 7.227185f, 7.421357f, 7.618538f, 7.818742f, + 8.021982f, 8.228271f, 8.437621f, 8.650046f, 8.865559f, 9.084171f, 9.305896f, 9.530747f, + 9.758735f, 9.989873f, 10.224173f, 10.461648f, 10.702310f, 10.946171f, 11.193243f, 11.443537f, + 11.697067f, 11.953843f, 12.213877f, 12.477182f, 12.743768f, 13.013648f, 13.286832f, 13.563333f, + 13.843162f, 14.126329f, 14.412847f, 14.702727f, 14.995979f, 15.292615f, 15.592646f, 15.896084f, + 16.202938f, 16.513219f, 16.826940f, 17.144110f, 17.464740f, 17.788842f, 18.116424f, 18.447499f, + 18.782077f, 19.120168f, 19.461783f, 19.806932f, 20.155625f, 20.507874f, 20.863687f, 21.223076f, + 21.586050f, 21.952620f, 22.322796f, 22.696587f, 23.074005f, 23.455058f, 23.839757f, 24.228112f, + 24.620133f, 25.015828f, 25.415209f, 25.818285f, 26.225066f, 26.635560f, 27.049779f, 27.467731f, + 27.889426f, 28.314874f, 28.744084f, 29.177065f, 29.613827f, 30.054379f, 30.498731f, 30.946892f, + 31.398871f, 31.854678f, 32.314321f, 32.777810f, 33.245154f, 33.716362f, 34.191442f, 34.670406f, + 35.153260f, 35.640014f, 36.130678f, 36.625260f, 37.123768f, 37.626212f, 38.132601f, 38.642943f, + 39.157248f, 39.675523f, 40.197778f, 40.724021f, 41.254261f, 41.788507f, 42.326767f, 42.869050f, + 43.415364f, 43.965717f, 44.520119f, 45.078578f, 45.641102f, 46.207700f, 46.778380f, 47.353150f, + 47.932018f, 48.514994f, 49.102085f, 49.693300f, 50.288646f, 50.888132f, 51.491767f, 52.099557f, + 52.711513f, 53.327640f, 53.947949f, 54.572446f, 55.201140f, 55.834039f, 56.471151f, 57.112483f, + 57.758044f, 58.407842f, 59.061884f, 59.720179f, 60.382734f, 61.049557f, 61.720656f, 62.396039f, + 63.075714f, 63.759687f, 64.447968f, 65.140564f, 65.837482f, 66.538730f, 67.244316f, 67.954247f, + 68.668531f, 69.387176f, 70.110189f, 70.837578f, 71.569350f, 72.305513f, 73.046074f, 73.791041f, + 74.540421f, 75.294222f, 76.052450f, 76.815115f, 77.582222f, 78.353779f, 79.129794f, 79.910274f, + 80.695226f, 81.484657f, 82.278575f, 83.076988f, 83.879901f, 84.687323f, 85.499261f, 86.315721f, + 87.136712f, 87.962240f, 88.792312f, 89.626935f, 90.466117f, 91.309865f, 92.158186f, 93.011086f, + 93.868573f, 94.730654f, 95.597335f, 96.468625f, 97.344529f, 98.225055f, 99.110210f, 100.000000f +}; diff --git a/src/openmv/src/omv/img/yuv_tab.c b/src/openmv/src/omv/img/yuv_tab.c new file mode 100755 index 0000000..42dc1b4 --- /dev/null +++ b/src/openmv/src/omv/img/yuv_tab.c @@ -0,0 +1,16387 @@ +#include +const int8_t yuv_table[196608] = { + -128, 0, 0, -110, -10, -13, -90, -21, -27, -72, -32, -40, + -52, -43, -54, -33, -53, -67, -15, -64, -81, 5, -75, -95, + -126, -1, 4, -107, -11, -9, -88, -22, -23, -69, -33, -36, + -50, -44, -50, -31, -55, -63, -12, -65, -77, 7, -76, -91, + -124, -2, 8, -105, -13, -5, -86, -24, -19, -67, -34, -32, + -47, -45, -46, -29, -56, -59, -10, -66, -73, 10, -77, -87, + -121, -4, 12, -102, -14, 0, -83, -25, -14, -64, -36, -28, + -45, -47, -41, -26, -57, -55, -7, -68, -68, 12, -79, -82, + -119, -5, 16, -100, -16, 3, -80, -27, -10, -62, -37, -24, + -42, -48, -37, -24, -59, -51, -5, -69, -64, 15, -80, -78, + -116, -6, 20, -97, -17, 7, -78, -28, -6, -59, -39, -20, + -40, -49, -33, -21, -60, -47, -2, -71, -60, 17, -82, -74, + -114, -8, 24, -95, -18, 11, -76, -29, -2, -57, -40, -16, + -38, -51, -29, -19, -61, -43, 0, -72, -56, 19, -83, -70, + -111, -9, 29, -92, -20, 15, -73, -31, 1, -54, -41, -11, + -35, -52, -25, -16, -63, -38, 3, -74, -52, 22, -84, -66, + -109, -11, 33, -90, -21, 19, -71, -32, 5, -52, -43, -7, + -32, -54, -21, -14, -64, -34, 5, -75, -48, 24, -86, -62, + -106, -12, 37, -88, -23, 23, -68, -34, 9, -49, -44, -3, + -30, -55, -17, -11, -66, -30, 8, -76, -44, 27, -87, -58, + -104, -13, 41, -85, -24, 27, -66, -35, 13, -47, -45, 0, + -28, -56, -13, -9, -67, -26, 10, -78, -40, 29, -89, -54, + -102, -15, 45, -83, -25, 31, -63, -36, 17, -45, -47, 4, + -25, -58, -9, -6, -68, -22, 12, -79, -36, 32, -90, -50, + -99, -16, 49, -80, -27, 36, -61, -38, 22, -42, -48, 8, + -23, -59, -4, -4, -70, -18, 15, -80, -31, 34, -91, -45, + -97, -18, 53, -78, -28, 40, -58, -39, 26, -40, -50, 12, + -20, -61, 0, -1, -71, -14, 17, -82, -27, 37, -93, -41, + -94, -19, 57, -75, -30, 44, -56, -40, 30, -37, -51, 16, + -18, -62, 3, 1, -73, -10, 20, -83, -23, 39, -94, -37, + -92, -20, 61, -73, -31, 48, -54, -42, 34, -35, -52, 20, + -15, -63, 7, 3, -74, -6, 22, -85, -19, 42, -95, -33, + -89, -22, 66, -70, -32, 52, -51, -43, 38, -32, -54, 25, + -13, -65, 11, 6, -75, -1, 25, -86, -15, 44, -97, -29, + -87, -23, 70, -68, -34, 56, -48, -45, 42, -30, -55, 29, + -10, -66, 15, 8, -77, 2, 27, -87, -11, 47, -98, -25, + -84, -24, 74, -65, -35, 60, -46, -46, 46, -27, -57, 33, + -8, -68, 19, 11, -78, 6, 30, -89, -7, 49, -100, -21, + -82, -26, 78, -63, -36, 64, -44, -47, 50, -25, -58, 37, + -6, -69, 23, 13, -79, 10, 32, -90, -3, 51, -101, -17, + -79, -27, 82, -60, -38, 69, -41, -49, 55, -22, -59, 41, + -3, -70, 28, 16, -81, 14, 35, -92, 1, 54, -103, -12, + -77, -29, 86, -58, -39, 73, -39, -50, 59, -20, -61, 45, + 0, -72, 32, 18, -82, 18, 37, -93, 5, 56, -104, -8, + -74, -30, 90, -56, -41, 77, -36, -52, 63, -17, -62, 49, + 2, -73, 36, 21, -84, 22, 39, -94, 9, 59, -105, -4, + -72, -31, 94, -53, -42, 81, -34, -53, 67, -15, -64, 53, + 4, -74, 40, 23, -85, 26, 42, -96, 13, 61, -107, 0, + -70, -33, 98, -51, -43, 85, -31, -54, 71, -13, -65, 57, + 7, -76, 44, 25, -86, 30, 44, -97, 17, 64, -108, 3, + -67, -34, 103, -48, -45, 89, -29, -56, 75, -10, -66, 62, + 9, -77, 48, 28, -88, 35, 47, -99, 21, 66, -109, 7, + -65, -36, 107, -46, -46, 93, -26, -57, 79, -8, -68, 66, + 12, -79, 52, 31, -89, 39, 49, -100, 25, 69, -111, 11, + -62, -37, 111, -43, -48, 97, -24, -58, 83, -5, -69, 70, + 14, -80, 56, 33, -91, 43, 52, -101, 29, 71, -112, 15, + -60, -38, 115, -41, -49, 101, -22, -60, 87, -3, -70, 74, + 17, -81, 60, 35, -92, 47, 54, -103, 33, 74, -114, 19, + -57, -40, 119, -38, -50, 106, -19, -61, 92, 0, -72, 78, + 19, -83, 65, 38, -93, 51, 57, -104, 38, 76, -115, 24, + -55, -41, 123, -36, -52, 110, -16, -63, 96, 2, -73, 82, + 22, -84, 69, 40, -95, 55, 59, -105, 42, 79, -116, 28, + -52, -43, 127, -33, -53, 114, -14, -64, 100, 5, -75, 86, + 24, -86, 73, 43, -96, 59, 62, -107, 46, 81, -118, 32, + -128, 4, 0, -109, -6, -14, -89, -17, -27, -71, -28, -41, + -51, -39, -55, -32, -49, -68, -14, -60, -81, 6, -71, -95, + -125, 2, 3, -106, -7, -10, -87, -18, -23, -68, -29, -37, + -49, -40, -51, -30, -51, -64, -11, -61, -77, 8, -72, -91, + -123, 1, 7, -104, -9, -6, -85, -20, -19, -66, -30, -33, + -46, -41, -47, -28, -52, -60, -9, -62, -73, 10, -73, -87, + -120, 0, 11, -101, -10, -1, -82, -21, -15, -63, -32, -28, + -44, -43, -42, -25, -53, -55, -6, -64, -69, 13, -75, -83, + -118, -1, 15, -99, -12, 2, -80, -23, -11, -61, -33, -24, + -41, -44, -38, -23, -55, -51, -4, -65, -65, 16, -76, -79, + -115, -2, 19, -97, -13, 6, -77, -24, -7, -58, -35, -20, + -39, -45, -34, -20, -56, -47, -1, -67, -61, 18, -78, -75, + -113, -4, 23, -94, -14, 10, -75, -25, -3, -56, -36, -16, + -37, -47, -30, -18, -57, -43, 1, -68, -57, 20, -79, -71, + -110, -5, 28, -91, -16, 14, -72, -27, 1, -53, -37, -12, + -34, -48, -26, -15, -59, -39, 4, -70, -52, 23, -80, -66, + -108, -7, 32, -89, -17, 18, -70, -28, 5, -51, -39, -8, + -32, -50, -22, -13, -60, -35, 6, -71, -48, 25, -82, -62, + -105, -8, 36, -87, -19, 22, -67, -30, 9, -49, -40, -4, + -29, -51, -18, -10, -62, -31, 8, -72, -44, 28, -83, -58, + -103, -9, 40, -84, -20, 26, -65, -31, 13, -46, -41, 0, + -27, -52, -14, -8, -63, -27, 11, -74, -40, 30, -85, -54, + -101, -11, 44, -82, -21, 30, -63, -32, 17, -44, -43, 3, + -24, -54, -10, -6, -64, -23, 13, -75, -36, 33, -86, -50, + -98, -12, 48, -79, -23, 35, -60, -34, 21, -41, -44, 8, + -22, -55, -5, -3, -66, -18, 16, -76, -32, 35, -87, -46, + -96, -14, 52, -77, -24, 39, -57, -35, 25, -39, -46, 12, + -19, -57, -1, -1, -67, -14, 18, -78, -28, 38, -89, -42, + -93, -15, 56, -74, -26, 43, -55, -36, 29, -36, -47, 16, + -17, -58, 2, 2, -69, -10, 21, -79, -24, 40, -90, -38, + -91, -16, 60, -72, -27, 47, -53, -38, 33, -34, -48, 20, + -15, -59, 6, 4, -70, -6, 23, -81, -20, 42, -91, -34, + -88, -18, 65, -69, -28, 51, -50, -39, 38, -31, -50, 24, + -12, -61, 10, 7, -71, -2, 26, -82, -15, 45, -93, -29, + -86, -19, 69, -67, -30, 55, -48, -41, 42, -29, -51, 28, + -9, -62, 14, 9, -73, 1, 28, -83, -11, 48, -94, -25, + -83, -20, 73, -65, -31, 59, -45, -42, 46, -26, -53, 32, + -7, -64, 18, 12, -74, 5, 31, -85, -7, 50, -96, -21, + -81, -22, 77, -62, -32, 63, -43, -43, 50, -24, -54, 36, + -5, -65, 22, 14, -75, 9, 33, -86, -3, 52, -97, -17, + -78, -23, 81, -59, -34, 68, -40, -45, 54, -21, -55, 41, + -2, -66, 27, 17, -77, 14, 36, -88, 0, 55, -99, -13, + -76, -25, 85, -57, -35, 72, -38, -46, 58, -19, -57, 45, + 0, -68, 31, 19, -78, 18, 38, -89, 4, 57, -100, -9, + -73, -26, 89, -55, -37, 76, -35, -48, 62, -17, -58, 49, + 3, -69, 35, 22, -80, 22, 40, -90, 8, 60, -101, -5, + -71, -27, 93, -52, -38, 80, -33, -49, 66, -14, -60, 53, + 5, -70, 39, 24, -81, 26, 43, -92, 12, 62, -103, -1, + -69, -29, 97, -50, -39, 84, -31, -50, 70, -12, -61, 57, + 8, -72, 43, 26, -82, 30, 45, -93, 16, 65, -104, 2, + -66, -30, 102, -47, -41, 88, -28, -52, 75, -9, -62, 61, + 10, -73, 47, 29, -84, 34, 48, -95, 21, 67, -105, 7, + -64, -32, 106, -45, -42, 92, -25, -53, 79, -7, -64, 65, + 13, -75, 51, 31, -85, 38, 50, -96, 25, 70, -107, 11, + -61, -33, 110, -42, -44, 96, -23, -54, 83, -4, -65, 69, + 15, -76, 55, 34, -87, 42, 53, -97, 29, 72, -108, 15, + -59, -34, 114, -40, -45, 100, -21, -56, 87, -2, -66, 73, + 17, -77, 59, 36, -88, 46, 55, -99, 33, 74, -110, 19, + -56, -36, 118, -37, -46, 105, -18, -57, 91, 1, -68, 78, + 20, -79, 64, 39, -89, 51, 58, -100, 37, 77, -111, 23, + -54, -37, 122, -35, -48, 109, -16, -59, 95, 3, -69, 82, + 23, -80, 68, 41, -91, 55, 60, -101, 41, 80, -112, 27, + -51, -39, 126, -33, -49, 113, -13, -60, 99, 6, -71, 86, + 25, -82, 72, 44, -92, 59, 63, -103, 45, 82, -114, 31, + -127, 8, -1, -108, -2, -14, -89, -13, -28, -70, -24, -41, + -50, -35, -55, -32, -45, -69, -13, -56, -82, 7, -67, -96, + -124, 6, 2, -105, -3, -10, -86, -14, -24, -67, -25, -37, + -48, -36, -51, -29, -47, -65, -10, -57, -78, 9, -68, -92, + -122, 5, 6, -103, -5, -6, -84, -16, -20, -65, -26, -33, + -46, -37, -47, -27, -48, -61, -8, -58, -74, 11, -69, -88, + -119, 3, 11, -100, -6, -2, -81, -17, -16, -62, -28, -29, + -43, -39, -43, -24, -49, -56, -5, -60, -70, 14, -71, -83, + -117, 2, 15, -98, -8, 1, -79, -19, -12, -60, -29, -25, + -40, -40, -39, -22, -51, -52, -3, -61, -66, 16, -72, -79, + -114, 1, 19, -96, -9, 5, -76, -20, -8, -57, -31, -21, + -38, -41, -35, -19, -52, -48, -1, -63, -62, 19, -74, -75, + -112, 0, 23, -93, -10, 9, -74, -21, -4, -55, -32, -17, + -36, -43, -31, -17, -53, -44, 2, -64, -58, 21, -75, -71, + -109, -1, 27, -91, -12, 14, -71, -23, 0, -52, -33, -12, + -33, -44, -26, -14, -55, -40, 5, -66, -53, 24, -76, -67, + -107, -3, 31, -88, -13, 18, -69, -24, 4, -50, -35, -8, + -31, -46, -22, -12, -56, -36, 7, -67, -49, 26, -78, -63, + -105, -4, 35, -86, -15, 22, -66, -26, 8, -48, -36, -4, + -28, -47, -18, -9, -58, -32, 9, -68, -45, 29, -79, -59, + -102, -5, 39, -83, -16, 26, -64, -27, 12, -45, -37, 0, + -26, -48, -14, -7, -59, -28, 12, -70, -41, 31, -81, -55, + -100, -7, 43, -81, -17, 30, -62, -28, 16, -43, -39, 3, + -23, -50, -10, -5, -60, -24, 14, -71, -37, 33, -82, -51, + -97, -8, 48, -78, -19, 34, -59, -30, 20, -40, -40, 7, + -21, -51, -6, -2, -62, -19, 17, -72, -33, 36, -83, -46, + -95, -10, 52, -76, -20, 38, -57, -31, 24, -38, -42, 11, + -18, -53, -2, 0, -63, -15, 19, -74, -29, 39, -85, -42, + -92, -11, 56, -74, -22, 42, -54, -32, 28, -35, -43, 15, + -16, -54, 1, 3, -65, -11, 22, -75, -25, 41, -86, -38, + -90, -12, 60, -71, -23, 46, -52, -34, 32, -33, -44, 19, + -14, -55, 5, 5, -66, -7, 24, -77, -21, 43, -87, -34, + -87, -14, 64, -68, -24, 51, -49, -35, 37, -30, -46, 24, + -11, -57, 10, 8, -67, -3, 27, -78, -16, 46, -89, -30, + -85, -15, 68, -66, -26, 55, -47, -37, 41, -28, -47, 28, + -9, -58, 14, 10, -69, 0, 29, -79, -12, 48, -90, -26, + -82, -16, 72, -64, -27, 59, -44, -38, 45, -25, -49, 32, + -6, -60, 18, 13, -70, 4, 31, -81, -8, 51, -92, -22, + -80, -18, 76, -61, -28, 63, -42, -39, 49, -23, -50, 36, + -4, -61, 22, 15, -71, 8, 34, -82, -4, 53, -93, -18, + -77, -19, 81, -59, -30, 67, -39, -41, 53, -20, -51, 40, + -1, -62, 26, 18, -73, 13, 37, -84, 0, 56, -95, -13, + -75, -21, 85, -56, -31, 71, -37, -42, 57, -18, -53, 44, + 1, -64, 30, 20, -74, 17, 39, -85, 3, 58, -96, -9, + -73, -22, 89, -54, -33, 75, -34, -44, 61, -16, -54, 48, + 4, -65, 34, 23, -76, 21, 41, -86, 7, 61, -97, -5, + -70, -23, 93, -51, -34, 79, -32, -45, 65, -13, -56, 52, + 6, -66, 38, 25, -77, 25, 44, -88, 11, 63, -99, -1, + -68, -25, 97, -49, -35, 83, -30, -46, 69, -11, -57, 56, + 9, -68, 42, 27, -78, 29, 46, -89, 15, 65, -100, 2, + -65, -26, 101, -46, -37, 88, -27, -48, 74, -8, -58, 61, + 11, -69, 47, 30, -80, 33, 49, -91, 20, 68, -101, 6, + -63, -28, 105, -44, -38, 92, -25, -49, 78, -6, -60, 65, + 14, -71, 51, 32, -81, 37, 51, -92, 24, 71, -103, 10, + -60, -29, 109, -42, -40, 96, -22, -50, 82, -3, -61, 69, + 16, -72, 55, 35, -83, 41, 54, -93, 28, 73, -104, 14, + -58, -30, 113, -39, -41, 100, -20, -52, 86, -1, -62, 73, + 18, -73, 59, 37, -84, 45, 56, -95, 32, 75, -106, 18, + -55, -32, 118, -36, -42, 104, -17, -53, 90, 2, -64, 77, + 21, -75, 63, 40, -85, 50, 59, -96, 36, 78, -107, 23, + -53, -33, 122, -34, -44, 108, -15, -55, 94, 4, -65, 81, + 23, -76, 67, 42, -87, 54, 61, -97, 40, 80, -108, 27, + -50, -35, 126, -32, -45, 112, -12, -56, 98, 7, -67, 85, + 26, -78, 71, 45, -88, 58, 63, -99, 44, 83, -110, 31, + -126, 12, -2, -107, 1, -15, -87, -9, -29, -69, -19, -42, + -49, -30, -56, -31, -41, -69, -12, -51, -83, 8, -62, -97, + -123, 11, 1, -104, 0, -11, -85, -10, -25, -66, -20, -38, + -47, -31, -52, -28, -42, -65, -9, -53, -79, 10, -64, -93, + -121, 9, 5, -102, 0, -7, -83, -11, -21, -64, -22, -34, + -45, -33, -48, -26, -43, -61, -7, -54, -75, 12, -65, -89, + -118, 8, 10, -99, -2, -2, -80, -13, -16, -61, -23, -30, + -42, -34, -43, -23, -45, -57, -4, -55, -70, 15, -66, -84, + -116, 6, 14, -97, -3, 1, -78, -14, -12, -59, -25, -26, + -39, -36, -39, -21, -46, -53, -2, -57, -66, 17, -68, -80, + -113, 5, 18, -95, -5, 5, -75, -15, -8, -56, -26, -22, + -37, -37, -35, -18, -48, -49, 0, -58, -62, 20, -69, -76, + -111, 4, 22, -92, -6, 9, -73, -17, -4, -54, -27, -18, + -35, -38, -31, -16, -49, -45, 3, -60, -58, 22, -70, -72, + -108, 2, 26, -90, -7, 13, -70, -18, 0, -51, -29, -13, + -32, -40, -27, -13, -50, -40, 6, -61, -54, 25, -72, -68, + -106, 1, 30, -87, -9, 17, -68, -20, 3, -49, -30, -9, + -30, -41, -23, -11, -52, -36, 8, -62, -50, 27, -73, -64, + -104, 0, 34, -85, -10, 21, -65, -21, 7, -47, -32, -5, + -27, -43, -19, -8, -53, -32, 10, -64, -46, 30, -75, -60, + -101, -1, 38, -82, -11, 25, -63, -22, 11, -44, -33, -1, + -25, -44, -15, -6, -55, -28, 13, -65, -42, 32, -76, -56, + -99, -2, 42, -80, -13, 29, -61, -24, 15, -42, -34, 2, + -22, -45, -11, -4, -56, -24, 15, -66, -38, 35, -77, -52, + -96, -4, 47, -77, -14, 34, -58, -25, 20, -39, -36, 6, + -20, -47, -6, -1, -57, -20, 18, -68, -33, 37, -79, -47, + -94, -5, 51, -75, -16, 38, -56, -27, 24, -37, -37, 10, + -17, -48, -2, 1, -59, -16, 20, -69, -29, 40, -80, -43, + -91, -6, 55, -72, -17, 42, -53, -28, 28, -34, -39, 14, + -15, -49, 1, 4, -60, -12, 23, -71, -25, 42, -82, -39, + -89, -8, 59, -70, -18, 46, -51, -29, 32, -32, -40, 18, + -13, -51, 5, 6, -61, -8, 25, -72, -21, 44, -83, -35, + -86, -9, 63, -67, -20, 50, -48, -31, 36, -29, -41, 23, + -10, -52, 9, 9, -63, -3, 28, -74, -17, 47, -84, -31, + -84, -11, 67, -65, -21, 54, -46, -32, 40, -27, -43, 27, + -7, -54, 13, 11, -64, 0, 30, -75, -13, 49, -86, -27, + -81, -12, 71, -63, -23, 58, -43, -34, 44, -24, -44, 31, + -5, -55, 17, 14, -66, 4, 32, -76, -9, 52, -87, -23, + -79, -13, 75, -60, -24, 62, -41, -35, 48, -22, -45, 35, + -3, -56, 21, 16, -67, 8, 35, -78, -5, 54, -89, -19, + -76, -15, 80, -58, -25, 67, -38, -36, 53, -19, -47, 39, + 0, -58, 26, 19, -69, 12, 38, -79, 0, 57, -90, -14, + -74, -16, 84, -55, -27, 71, -36, -38, 57, -17, -48, 43, + 2, -59, 30, 21, -70, 16, 40, -80, 3, 59, -91, -10, + -72, -18, 88, -53, -28, 75, -33, -39, 61, -15, -50, 47, + 5, -61, 34, 24, -71, 20, 42, -82, 7, 62, -93, -6, + -69, -19, 92, -50, -29, 79, -31, -40, 65, -12, -51, 51, + 7, -62, 38, 26, -73, 24, 45, -83, 11, 64, -94, -2, + -67, -20, 96, -48, -31, 83, -29, -42, 69, -10, -52, 55, + 10, -63, 42, 28, -74, 28, 47, -85, 15, 67, -95, 1, + -64, -22, 100, -45, -32, 87, -26, -43, 73, -7, -54, 60, + 12, -65, 46, 31, -75, 33, 50, -86, 19, 69, -97, 5, + -62, -23, 104, -43, -34, 91, -24, -45, 77, -5, -55, 64, + 15, -66, 50, 33, -77, 37, 52, -87, 23, 72, -98, 9, + -59, -24, 108, -40, -35, 95, -21, -46, 81, -2, -57, 68, + 17, -68, 54, 36, -78, 41, 55, -89, 27, 74, -100, 13, + -57, -26, 112, -38, -36, 99, -19, -47, 85, 0, -58, 72, + 19, -69, 58, 38, -79, 45, 57, -90, 31, 76, -101, 17, + -54, -27, 117, -35, -38, 104, -16, -49, 90, 3, -59, 76, + 22, -70, 63, 41, -81, 49, 60, -92, 36, 79, -103, 22, + -52, -29, 121, -33, -39, 108, -14, -50, 94, 5, -61, 80, + 25, -72, 67, 43, -82, 53, 62, -93, 40, 81, -104, 26, + -49, -30, 125, -31, -41, 112, -11, -52, 98, 8, -62, 84, + 27, -73, 71, 46, -84, 57, 64, -94, 44, 84, -105, 30, + -125, 16, -2, -106, 5, -16, -87, -5, -29, -68, -15, -43, + -48, -26, -57, -30, -37, -70, -11, -47, -83, 9, -58, -97, + -122, 15, 1, -104, 4, -12, -84, -6, -25, -65, -16, -39, + -46, -27, -53, -27, -38, -66, -8, -49, -79, 11, -60, -93, + -120, 13, 5, -101, 3, -8, -82, -7, -21, -63, -18, -35, + -44, -29, -49, -25, -39, -62, -6, -50, -75, 13, -61, -89, + -117, 12, 9, -98, 1, -3, -79, -9, -17, -60, -19, -30, + -41, -30, -44, -22, -41, -58, -3, -51, -71, 16, -62, -85, + -115, 10, 13, -96, 0, 0, -77, -10, -13, -58, -21, -26, + -39, -32, -40, -20, -42, -54, -1, -53, -67, 18, -64, -81, + -112, 9, 17, -94, -1, 4, -74, -11, -9, -56, -22, -22, + -36, -33, -36, -17, -44, -50, 1, -54, -63, 21, -65, -77, + -110, 8, 21, -91, -2, 8, -72, -13, -5, -53, -23, -18, + -34, -34, -32, -15, -45, -46, 4, -56, -59, 23, -66, -73, + -107, 6, 26, -89, -3, 12, -69, -14, 0, -50, -25, -14, + -31, -36, -28, -12, -46, -41, 6, -57, -54, 26, -68, -68, + -105, 5, 30, -86, -5, 16, -67, -16, 3, -48, -26, -10, + -29, -37, -24, -10, -48, -37, 9, -58, -50, 28, -69, -64, + -103, 4, 34, -84, -6, 20, -64, -17, 7, -46, -28, -6, + -26, -39, -20, -8, -49, -33, 11, -60, -46, 31, -71, -60, + -100, 2, 38, -81, -7, 24, -62, -18, 11, -43, -29, -2, + -24, -40, -16, -5, -51, -29, 14, -61, -42, 33, -72, -56, + -98, 1, 42, -79, -9, 28, -60, -20, 15, -41, -30, 1, + -22, -41, -12, -3, -52, -25, 16, -62, -38, 35, -73, -52, + -95, 0, 46, -76, -10, 33, -57, -21, 19, -38, -32, 6, + -19, -43, -7, 0, -53, -21, 19, -64, -34, 38, -75, -48, + -93, -1, 50, -74, -12, 37, -55, -23, 23, -36, -33, 10, + -16, -44, -3, 2, -55, -17, 21, -65, -30, 41, -76, -44, + -90, -2, 54, -72, -13, 41, -52, -24, 27, -33, -35, 14, + -14, -45, 0, 5, -56, -13, 24, -67, -26, 43, -78, -40, + -88, -4, 58, -69, -14, 45, -50, -25, 31, -31, -36, 18, + -12, -47, 4, 7, -57, -9, 26, -68, -22, 45, -79, -36, + -85, -5, 63, -66, -16, 49, -47, -27, 36, -28, -37, 22, + -9, -48, 8, 10, -59, -4, 29, -70, -17, 48, -80, -31, + -83, -7, 67, -64, -17, 53, -45, -28, 40, -26, -39, 26, + -7, -50, 12, 12, -60, 0, 31, -71, -13, 50, -82, -27, + -80, -8, 71, -62, -19, 57, -42, -30, 44, -24, -40, 30, + -4, -51, 16, 15, -62, 3, 33, -72, -9, 53, -83, -23, + -78, -9, 75, -59, -20, 61, -40, -31, 48, -21, -41, 34, + -2, -52, 20, 17, -63, 7, 36, -74, -5, 55, -85, -19, + -75, -11, 79, -57, -21, 66, -37, -32, 52, -18, -43, 39, + 1, -54, 25, 20, -65, 11, 38, -75, -1, 58, -86, -15, + -73, -12, 83, -54, -23, 70, -35, -34, 56, -16, -44, 43, + 3, -55, 29, 22, -66, 15, 41, -76, 2, 60, -87, -11, + -71, -14, 87, -52, -24, 74, -32, -35, 60, -14, -46, 47, + 6, -57, 33, 24, -67, 19, 43, -78, 6, 63, -89, -7, + -68, -15, 91, -49, -25, 78, -30, -36, 64, -11, -47, 51, + 8, -58, 37, 27, -69, 23, 46, -79, 10, 65, -90, -3, + -66, -16, 95, -47, -27, 82, -28, -38, 68, -9, -48, 55, + 10, -59, 41, 29, -70, 27, 48, -81, 14, 67, -91, 0, + -63, -18, 100, -44, -28, 86, -25, -39, 73, -6, -50, 59, + 13, -61, 45, 32, -71, 32, 51, -82, 19, 70, -93, 5, + -61, -19, 104, -42, -30, 90, -23, -41, 77, -4, -51, 63, + 16, -62, 49, 34, -73, 36, 53, -83, 23, 72, -94, 9, + -58, -20, 108, -40, -31, 94, -20, -42, 81, -1, -53, 67, + 18, -64, 53, 37, -74, 40, 56, -85, 27, 75, -96, 13, + -56, -22, 112, -37, -32, 98, -18, -43, 85, 1, -54, 71, + 20, -65, 57, 39, -75, 44, 58, -86, 31, 77, -97, 17, + -53, -23, 116, -34, -34, 103, -15, -45, 89, 4, -55, 76, + 23, -66, 62, 42, -77, 48, 61, -88, 35, 80, -99, 21, + -51, -25, 120, -32, -35, 107, -13, -46, 93, 6, -57, 80, + 25, -68, 66, 44, -78, 52, 63, -89, 39, 82, -100, 25, + -48, -26, 124, -30, -37, 111, -10, -48, 97, 8, -58, 84, + 28, -69, 70, 47, -80, 56, 65, -90, 43, 85, -101, 29, + -124, 20, -3, -105, 9, -16, -86, -1, -30, -67, -11, -43, + -48, -22, -57, -29, -33, -71, -10, -43, -84, 9, -54, -98, + -121, 19, 0, -103, 8, -12, -83, -2, -26, -64, -12, -39, + -45, -23, -53, -26, -34, -67, -8, -45, -80, 12, -56, -94, + -119, 17, 4, -100, 7, -8, -81, -3, -22, -62, -14, -35, + -43, -25, -49, -24, -35, -63, -5, -46, -76, 14, -57, -90, + -116, 16, 9, -98, 5, -4, -78, -5, -18, -59, -15, -31, + -40, -26, -45, -21, -37, -58, -2, -47, -72, 17, -58, -85, + -114, 14, 13, -95, 4, 0, -76, -6, -14, -57, -17, -27, + -38, -28, -41, -19, -38, -54, 0, -49, -68, 19, -60, -81, + -112, 13, 17, -93, 2, 3, -73, -7, -10, -55, -18, -23, + -35, -29, -37, -16, -40, -50, 2, -50, -64, 22, -61, -77, + -109, 12, 21, -90, 1, 7, -71, -9, -6, -52, -19, -19, + -33, -30, -33, -14, -41, -46, 5, -52, -60, 24, -62, -73, + -106, 10, 25, -88, 0, 12, -68, -10, -1, -50, -21, -14, + -30, -32, -28, -11, -42, -42, 7, -53, -55, 27, -64, -69, + -104, 9, 29, -85, -1, 16, -66, -12, 2, -47, -22, -10, + -28, -33, -24, -9, -44, -38, 10, -54, -51, 29, -65, -65, + -102, 8, 33, -83, -2, 20, -64, -13, 6, -45, -24, -6, + -25, -35, -20, -7, -45, -34, 12, -56, -47, 32, -67, -61, + -99, 6, 37, -81, -3, 24, -61, -14, 10, -42, -25, -2, + -23, -36, -16, -4, -47, -30, 15, -57, -43, 34, -68, -57, + -97, 5, 41, -78, -5, 28, -59, -16, 14, -40, -26, 1, + -21, -37, -12, -2, -48, -26, 17, -58, -39, 36, -69, -53, + -94, 3, 46, -75, -6, 32, -56, -17, 18, -37, -28, 5, + -18, -39, -8, 1, -49, -21, 20, -60, -35, 39, -71, -48, + -92, 2, 50, -73, -8, 36, -54, -19, 22, -35, -29, 9, + -16, -40, -4, 3, -51, -17, 22, -61, -31, 41, -72, -44, + -89, 1, 54, -71, -9, 40, -51, -20, 26, -33, -31, 13, + -13, -41, 0, 6, -52, -13, 24, -63, -27, 44, -74, -40, + -87, 0, 58, -68, -10, 44, -49, -21, 30, -30, -32, 17, + -11, -43, 3, 8, -53, -9, 27, -64, -23, 46, -75, -36, + -84, -1, 62, -66, -12, 49, -46, -23, 35, -27, -33, 22, + -8, -44, 8, 11, -55, -5, 30, -66, -18, 49, -76, -32, + -82, -3, 66, -63, -13, 53, -44, -24, 39, -25, -35, 26, + -6, -46, 12, 13, -56, -1, 32, -67, -14, 51, -78, -28, + -80, -4, 70, -61, -15, 57, -41, -26, 43, -23, -36, 30, + -3, -47, 16, 16, -58, 2, 34, -68, -10, 54, -79, -24, + -77, -5, 74, -58, -16, 61, -39, -27, 47, -20, -37, 34, + -1, -48, 20, 18, -59, 6, 37, -70, -6, 56, -81, -20, + -74, -7, 79, -56, -17, 65, -36, -28, 51, -18, -39, 38, + 2, -50, 24, 21, -61, 11, 39, -71, -2, 59, -82, -15, + -72, -8, 83, -53, -19, 69, -34, -30, 55, -15, -40, 42, + 4, -51, 28, 23, -62, 15, 42, -72, 1, 61, -83, -11, + -70, -10, 87, -51, -20, 73, -32, -31, 59, -13, -42, 46, + 7, -53, 32, 25, -63, 19, 44, -74, 5, 64, -85, -7, + -67, -11, 91, -49, -21, 77, -29, -32, 63, -10, -43, 50, + 9, -54, 36, 28, -65, 23, 47, -75, 9, 66, -86, -3, + -65, -12, 95, -46, -23, 81, -27, -34, 67, -8, -44, 54, + 11, -55, 40, 30, -66, 27, 49, -77, 13, 68, -87, 0, + -62, -14, 99, -43, -24, 86, -24, -35, 72, -5, -46, 59, + 14, -57, 45, 33, -67, 31, 52, -78, 18, 71, -89, 4, + -60, -15, 103, -41, -26, 90, -22, -37, 76, -3, -47, 63, + 16, -58, 49, 35, -69, 35, 54, -79, 22, 73, -90, 8, + -57, -16, 107, -39, -27, 94, -19, -38, 80, -1, -49, 67, + 19, -60, 53, 38, -70, 39, 56, -81, 26, 76, -92, 12, + -55, -18, 111, -36, -28, 98, -17, -39, 84, 2, -50, 71, + 21, -61, 57, 40, -71, 43, 59, -82, 30, 78, -93, 16, + -52, -19, 116, -34, -30, 102, -14, -41, 88, 5, -51, 75, + 24, -62, 61, 43, -73, 48, 62, -84, 34, 81, -95, 21, + -50, -21, 120, -31, -31, 106, -12, -42, 92, 7, -53, 79, + 26, -64, 65, 45, -74, 52, 64, -85, 38, 83, -96, 25, + -48, -22, 124, -29, -33, 110, -9, -44, 96, 9, -54, 83, + 29, -65, 69, 48, -76, 56, 66, -86, 42, 86, -97, 29, + -123, 24, -3, -104, 13, -17, -85, 2, -31, -66, -7, -44, + -47, -18, -58, -28, -29, -71, -9, -39, -85, 10, -50, -99, + -121, 23, 0, -102, 12, -13, -82, 1, -27, -64, -8, -40, + -44, -19, -54, -25, -30, -67, -7, -41, -81, 13, -52, -95, + -118, 21, 4, -99, 11, -9, -80, 0, -23, -61, -10, -36, + -42, -21, -50, -23, -31, -63, -4, -42, -77, 15, -53, -91, + -115, 20, 8, -97, 9, -4, -77, -1, -18, -58, -11, -32, + -39, -22, -45, -20, -33, -59, -2, -43, -72, 18, -54, -86, + -113, 18, 12, -94, 8, 0, -75, -2, -14, -56, -13, -28, + -37, -24, -41, -18, -34, -55, 1, -45, -68, 20, -56, -82, + -111, 17, 16, -92, 6, 3, -72, -3, -10, -54, -14, -24, + -34, -25, -37, -16, -36, -51, 3, -46, -64, 23, -57, -78, + -108, 16, 20, -89, 5, 7, -70, -5, -6, -51, -15, -20, + -32, -26, -33, -13, -37, -47, 6, -48, -60, 25, -58, -74, + -106, 14, 25, -87, 4, 11, -67, -6, -2, -49, -17, -15, + -29, -28, -29, -10, -38, -42, 8, -49, -56, 28, -60, -70, + -103, 13, 29, -84, 2, 15, -65, -8, 1, -46, -18, -11, + -27, -29, -25, -8, -40, -38, 11, -50, -52, 30, -61, -66, + -101, 12, 33, -82, 1, 19, -63, -9, 5, -44, -20, -7, + -24, -31, -21, -6, -41, -34, 13, -52, -48, 32, -63, -62, + -98, 10, 37, -80, 0, 23, -60, -10, 9, -41, -21, -3, + -22, -32, -17, -3, -43, -30, 15, -53, -44, 35, -64, -58, + -96, 9, 41, -77, -1, 27, -58, -12, 13, -39, -22, 0, + -20, -33, -13, -1, -44, -26, 18, -54, -40, 37, -65, -54, + -93, 7, 45, -75, -2, 32, -55, -13, 18, -36, -24, 4, + -17, -35, -8, 2, -45, -22, 21, -56, -35, 40, -67, -49, + -91, 6, 49, -72, -4, 36, -53, -15, 22, -34, -25, 8, + -15, -36, -4, 4, -47, -18, 23, -57, -31, 42, -68, -45, + -89, 5, 53, -70, -5, 40, -50, -16, 26, -32, -27, 12, + -12, -37, 0, 7, -48, -14, 25, -59, -27, 45, -70, -41, + -86, 3, 57, -67, -6, 44, -48, -17, 30, -29, -28, 16, + -10, -39, 3, 9, -49, -10, 28, -60, -23, 47, -71, -37, + -83, 2, 62, -65, -8, 48, -45, -19, 34, -27, -29, 21, + -7, -40, 7, 12, -51, -5, 30, -62, -19, 50, -72, -33, + -81, 0, 66, -62, -9, 52, -43, -20, 38, -24, -31, 25, + -5, -42, 11, 14, -52, -1, 33, -63, -15, 52, -74, -29, + -79, 0, 70, -60, -11, 56, -41, -22, 42, -22, -32, 29, + -2, -43, 15, 16, -54, 2, 35, -64, -11, 55, -75, -25, + -76, -1, 74, -57, -12, 60, -38, -23, 46, -19, -33, 33, + 0, -44, 19, 19, -55, 6, 38, -66, -7, 57, -77, -21, + -74, -3, 78, -55, -13, 65, -35, -24, 51, -17, -35, 37, + 3, -46, 24, 22, -57, 10, 40, -67, -2, 60, -78, -16, + -71, -4, 82, -52, -15, 69, -33, -26, 55, -14, -36, 41, + 5, -47, 28, 24, -58, 14, 43, -68, 1, 62, -79, -12, + -69, -6, 86, -50, -16, 73, -31, -27, 59, -12, -38, 45, + 8, -49, 32, 26, -59, 18, 45, -70, 5, 64, -81, -8, + -66, -7, 90, -48, -17, 77, -28, -28, 63, -9, -39, 49, + 10, -50, 36, 29, -61, 22, 47, -71, 9, 67, -82, -4, + -64, -8, 94, -45, -19, 81, -26, -30, 67, -7, -40, 53, + 12, -51, 40, 31, -62, 26, 50, -73, 13, 69, -83, 0, + -61, -10, 99, -43, -20, 85, -23, -31, 71, -4, -42, 58, + 15, -53, 44, 34, -63, 31, 53, -74, 17, 72, -85, 3, + -59, -11, 103, -40, -22, 89, -21, -33, 75, -2, -43, 62, + 17, -54, 48, 36, -65, 35, 55, -75, 21, 74, -86, 7, + -57, -12, 107, -38, -23, 93, -18, -34, 79, 0, -45, 66, + 20, -56, 52, 39, -66, 39, 57, -77, 25, 77, -88, 11, + -54, -14, 111, -35, -24, 97, -16, -35, 83, 3, -46, 70, + 22, -57, 56, 41, -67, 43, 60, -78, 29, 79, -89, 15, + -51, -15, 115, -33, -26, 102, -13, -37, 88, 5, -47, 74, + 25, -58, 61, 44, -69, 47, 62, -80, 34, 82, -91, 20, + -49, -17, 119, -30, -27, 106, -11, -38, 92, 8, -49, 78, + 27, -60, 65, 46, -70, 51, 65, -81, 38, 84, -92, 24, + -47, -18, 123, -28, -29, 110, -9, -40, 96, 10, -50, 82, + 30, -61, 69, 48, -72, 55, 67, -82, 42, 87, -93, 28, + -122, 29, -4, -103, 18, -18, -84, 7, -31, -65, -3, -45, + -46, -14, -59, -27, -24, -72, -8, -35, -85, 11, -46, -99, + -119, 27, 0, -101, 17, -14, -81, 6, -27, -63, -4, -41, + -43, -15, -55, -24, -26, -68, -6, -36, -81, 14, -47, -95, + -117, 26, 3, -98, 15, -10, -79, 4, -23, -60, -5, -37, + -41, -16, -51, -22, -27, -64, -3, -37, -77, 16, -48, -91, + -114, 24, 7, -96, 14, -5, -76, 3, -19, -57, -7, -32, + -38, -18, -46, -19, -28, -60, -1, -39, -73, 19, -50, -87, + -112, 23, 11, -93, 12, -1, -74, 1, -15, -55, -8, -28, + -36, -19, -42, -17, -30, -56, 2, -40, -69, 21, -51, -83, + -110, 22, 15, -91, 11, 2, -71, 0, -11, -53, -10, -24, + -33, -20, -38, -15, -31, -52, 4, -42, -65, 24, -53, -79, + -107, 20, 19, -88, 10, 6, -69, 0, -7, -50, -11, -20, + -31, -22, -34, -12, -32, -48, 7, -43, -61, 26, -54, -75, + -105, 19, 24, -86, 8, 10, -66, -2, -2, -48, -12, -16, + -28, -23, -30, -9, -34, -43, 9, -45, -56, 29, -55, -70, + -102, 17, 28, -83, 7, 14, -64, -3, 1, -45, -14, -12, + -26, -25, -26, -7, -35, -39, 12, -46, -52, 31, -57, -66, + -100, 16, 32, -81, 5, 18, -62, -5, 5, -43, -15, -8, + -23, -26, -22, -5, -37, -35, 14, -47, -48, 33, -58, -62, + -97, 15, 36, -79, 4, 22, -59, -6, 9, -40, -16, -4, + -21, -27, -18, -2, -38, -31, 17, -49, -44, 36, -60, -58, + -95, 13, 40, -76, 3, 26, -57, -7, 13, -38, -18, 0, + -19, -29, -14, 0, -39, -27, 19, -50, -40, 38, -61, -54, + -92, 12, 44, -74, 1, 31, -54, -9, 17, -35, -19, 4, + -16, -30, -9, 3, -41, -23, 22, -51, -36, 41, -62, -50, + -90, 10, 48, -71, 0, 35, -52, -10, 21, -33, -21, 8, + -14, -32, -5, 5, -42, -19, 24, -53, -32, 43, -64, -46, + -88, 9, 52, -69, -1, 39, -49, -11, 25, -31, -22, 12, + -11, -33, -1, 8, -44, -15, 26, -54, -28, 46, -65, -42, + -85, 8, 56, -66, -2, 43, -47, -13, 29, -28, -23, 16, + -9, -34, 2, 10, -45, -11, 29, -56, -24, 48, -66, -38, + -82, 6, 61, -64, -3, 47, -44, -14, 34, -25, -25, 20, + -6, -36, 6, 13, -46, -6, 31, -57, -19, 51, -68, -33, + -80, 5, 65, -61, -5, 51, -42, -16, 38, -23, -26, 24, + -4, -37, 10, 15, -48, -2, 34, -58, -15, 53, -69, -29, + -78, 4, 69, -59, -6, 55, -39, -17, 42, -21, -28, 28, + -1, -39, 14, 17, -49, 1, 36, -60, -11, 56, -71, -25, + -75, 2, 73, -56, -7, 59, -37, -18, 46, -18, -29, 32, + 1, -40, 18, 20, -50, 5, 39, -61, -7, 58, -72, -21, + -73, 1, 77, -54, -9, 64, -34, -20, 50, -16, -30, 37, + 4, -41, 23, 23, -52, 9, 41, -63, -3, 61, -74, -17, + -70, 0, 81, -51, -10, 68, -32, -21, 54, -13, -32, 41, + 6, -43, 27, 25, -53, 13, 44, -64, 0, 63, -75, -13, + -68, -1, 85, -49, -12, 72, -30, -23, 58, -11, -33, 45, + 9, -44, 31, 27, -55, 17, 46, -65, 4, 65, -76, -9, + -65, -2, 89, -47, -13, 76, -27, -24, 62, -8, -35, 49, + 11, -45, 35, 30, -56, 21, 49, -67, 8, 68, -78, -5, + -63, -4, 93, -44, -14, 80, -25, -25, 66, -6, -36, 53, + 13, -47, 39, 32, -57, 25, 51, -68, 12, 70, -79, -1, + -60, -5, 98, -42, -16, 84, -22, -27, 71, -3, -37, 57, + 16, -48, 43, 35, -59, 30, 54, -70, 17, 73, -80, 3, + -58, -7, 102, -39, -17, 88, -20, -28, 75, -1, -39, 61, + 18, -50, 47, 37, -60, 34, 56, -71, 21, 75, -82, 7, + -56, -8, 106, -37, -19, 92, -17, -29, 79, 1, -40, 65, + 21, -51, 51, 40, -62, 38, 58, -72, 25, 78, -83, 11, + -53, -9, 110, -34, -20, 96, -15, -31, 83, 4, -41, 69, + 23, -52, 55, 42, -63, 42, 61, -74, 29, 80, -85, 15, + -50, -11, 114, -32, -21, 101, -12, -32, 87, 7, -43, 74, + 26, -54, 60, 45, -64, 46, 63, -75, 33, 83, -86, 19, + -48, -12, 118, -29, -23, 105, -10, -34, 91, 9, -44, 78, + 28, -55, 64, 47, -66, 50, 66, -76, 37, 85, -87, 23, + -46, -14, 122, -27, -24, 109, -7, -35, 95, 11, -46, 82, + 31, -57, 68, 49, -67, 54, 68, -78, 41, 88, -89, 27, + -121, 33, -5, -102, 22, -18, -83, 11, -32, -64, 0, -45, + -45, -10, -59, -26, -20, -73, -7, -31, -86, 12, -42, -100, + -119, 31, -1, -100, 21, -14, -80, 10, -28, -62, 0, -41, + -42, -11, -55, -23, -22, -69, -5, -32, -82, 15, -43, -96, + -116, 30, 2, -97, 19, -10, -78, 8, -24, -59, -1, -37, + -40, -12, -51, -21, -23, -65, -2, -33, -78, 17, -44, -92, + -114, 28, 7, -95, 18, -6, -75, 7, -20, -57, -3, -33, + -37, -14, -47, -18, -24, -60, 0, -35, -74, 20, -46, -87, + -111, 27, 11, -92, 16, -2, -73, 5, -16, -54, -4, -29, + -35, -15, -43, -16, -26, -56, 3, -36, -70, 22, -47, -83, + -109, 26, 15, -90, 15, 1, -71, 4, -12, -52, -6, -25, + -32, -16, -39, -14, -27, -52, 5, -38, -66, 25, -49, -79, + -106, 24, 19, -88, 14, 5, -68, 3, -8, -49, -7, -21, + -30, -18, -35, -11, -28, -48, 8, -39, -62, 27, -50, -75, + -104, 23, 23, -85, 12, 10, -65, 1, -3, -47, -8, -16, + -27, -19, -30, -9, -30, -44, 10, -41, -57, 30, -51, -71, + -101, 21, 27, -82, 11, 14, -63, 0, 0, -44, -10, -12, + -25, -21, -26, -6, -31, -40, 13, -42, -53, 32, -53, -67, + -99, 20, 31, -80, 9, 18, -61, -1, 4, -42, -11, -8, + -23, -22, -22, -4, -33, -36, 15, -43, -49, 34, -54, -63, + -96, 19, 35, -78, 8, 22, -58, -2, 8, -40, -12, -4, + -20, -23, -18, -1, -34, -32, 17, -45, -45, 37, -56, -59, + -94, 17, 39, -75, 7, 26, -56, -3, 12, -37, -14, 0, + -18, -25, -14, 1, -35, -28, 20, -46, -41, 39, -57, -55, + -91, 16, 44, -73, 5, 30, -53, -5, 16, -34, -15, 3, + -15, -26, -10, 4, -37, -23, 23, -47, -37, 42, -58, -50, + -89, 14, 48, -70, 4, 34, -51, -6, 20, -32, -17, 7, + -13, -28, -6, 6, -38, -19, 25, -49, -33, 44, -60, -46, + -87, 13, 52, -68, 2, 38, -48, -7, 24, -30, -18, 11, + -10, -29, -2, 9, -40, -15, 27, -50, -29, 47, -61, -42, + -84, 12, 56, -65, 1, 42, -46, -9, 28, -27, -19, 15, + -8, -30, 1, 11, -41, -11, 30, -52, -25, 49, -62, -38, + -82, 10, 60, -63, 0, 47, -43, -10, 33, -25, -21, 20, + -5, -32, 6, 14, -42, -7, 32, -53, -20, 52, -64, -34, + -79, 9, 64, -60, -1, 51, -41, -12, 37, -22, -22, 24, + -3, -33, 10, 16, -44, -3, 35, -54, -16, 54, -65, -30, + -77, 8, 68, -58, -2, 55, -39, -13, 41, -20, -24, 28, + 0, -35, 14, 18, -45, 0, 37, -56, -12, 57, -67, -26, + -74, 6, 72, -56, -3, 59, -36, -14, 45, -17, -25, 32, + 2, -36, 18, 21, -46, 4, 40, -57, -8, 59, -68, -22, + -72, 5, 77, -53, -5, 63, -33, -16, 49, -15, -26, 36, + 5, -37, 22, 23, -48, 9, 42, -59, -4, 62, -70, -17, + -69, 3, 81, -50, -6, 67, -31, -17, 53, -12, -28, 40, + 7, -39, 26, 26, -49, 13, 45, -60, 0, 64, -71, -13, + -67, 2, 85, -48, -8, 71, -29, -19, 57, -10, -29, 44, + 9, -40, 30, 28, -51, 17, 47, -61, 3, 66, -72, -9, + -64, 1, 89, -46, -9, 75, -26, -20, 61, -8, -31, 48, + 12, -41, 34, 31, -52, 21, 49, -63, 7, 69, -74, -5, + -62, 0, 93, -43, -10, 79, -24, -21, 65, -5, -32, 52, + 14, -43, 38, 33, -53, 25, 52, -64, 11, 71, -75, -1, + -59, -1, 97, -41, -12, 84, -21, -23, 70, -2, -33, 57, + 17, -44, 43, 36, -55, 29, 54, -66, 16, 74, -76, 2, + -57, -3, 101, -38, -13, 88, -19, -24, 74, 0, -35, 61, + 19, -46, 47, 38, -56, 33, 57, -67, 20, 76, -78, 6, + -55, -4, 105, -36, -15, 92, -16, -25, 78, 2, -36, 65, + 22, -47, 51, 40, -58, 37, 59, -68, 24, 79, -79, 10, + -52, -5, 109, -33, -16, 96, -14, -27, 82, 5, -37, 69, + 24, -48, 55, 43, -59, 41, 62, -70, 28, 81, -81, 14, + -50, -7, 114, -31, -17, 100, -11, -28, 86, 7, -39, 73, + 27, -50, 59, 46, -60, 46, 64, -71, 32, 84, -82, 19, + -47, -8, 118, -28, -19, 104, -9, -30, 90, 10, -40, 77, + 29, -51, 63, 48, -62, 50, 67, -72, 36, 86, -83, 23, + -45, -10, 122, -26, -20, 108, -7, -31, 94, 12, -42, 81, + 32, -53, 67, 50, -63, 54, 69, -74, 40, 89, -85, 27, + -120, 37, -6, -101, 26, -19, -82, 15, -33, -63, 4, -46, + -44, -6, -60, -25, -16, -73, -6, -27, -87, 13, -38, -101, + -118, 35, -2, -99, 25, -15, -80, 14, -29, -61, 3, -42, + -41, -7, -56, -23, -18, -69, -4, -28, -83, 16, -39, -97, + -115, 34, 1, -96, 23, -11, -77, 12, -25, -58, 2, -38, + -39, -8, -52, -20, -19, -65, -1, -29, -79, 18, -40, -93, + -113, 32, 6, -94, 22, -6, -74, 11, -20, -56, 0, -34, + -36, -10, -47, -17, -20, -61, 1, -31, -74, 21, -42, -88, + -110, 31, 10, -91, 20, -2, -72, 9, -16, -53, 0, -30, + -34, -11, -43, -15, -22, -57, 4, -32, -70, 23, -43, -84, + -108, 30, 14, -89, 19, 1, -70, 8, -12, -51, -2, -26, + -31, -12, -39, -13, -23, -53, 6, -34, -66, 25, -45, -80, + -105, 28, 18, -87, 18, 5, -67, 7, -8, -48, -3, -22, + -29, -14, -35, -10, -24, -49, 8, -35, -62, 28, -46, -76, + -103, 27, 22, -84, 16, 9, -65, 5, -4, -46, -4, -17, + -26, -15, -31, -8, -26, -44, 11, -37, -58, 31, -47, -72, + -100, 25, 26, -82, 15, 13, -62, 4, 0, -43, -6, -13, + -24, -17, -27, -5, -27, -40, 14, -38, -54, 33, -49, -68, + -98, 24, 30, -79, 13, 17, -60, 2, 3, -41, -7, -9, + -22, -18, -23, -3, -29, -36, 16, -39, -50, 35, -50, -64, + -96, 23, 34, -77, 12, 21, -57, 1, 7, -39, -8, -5, + -19, -19, -19, 0, -30, -32, 18, -41, -46, 38, -52, -60, + -93, 21, 38, -74, 11, 25, -55, 0, 11, -36, -10, -1, + -17, -21, -15, 2, -31, -28, 21, -42, -42, 40, -53, -56, + -90, 20, 43, -72, 9, 30, -52, -1, 16, -34, -11, 2, + -14, -22, -10, 5, -33, -24, 23, -43, -37, 43, -54, -51, + -88, 18, 47, -69, 8, 34, -50, -2, 20, -31, -13, 6, + -12, -24, -6, 7, -34, -20, 26, -45, -33, 45, -56, -47, + -86, 17, 51, -67, 6, 38, -48, -3, 24, -29, -14, 10, + -9, -25, -2, 9, -36, -16, 28, -46, -29, 48, -57, -43, + -83, 16, 55, -65, 5, 42, -45, -5, 28, -26, -15, 14, + -7, -26, 1, 12, -37, -12, 31, -48, -25, 50, -58, -39, + -81, 14, 59, -62, 4, 46, -42, -6, 32, -24, -17, 19, + -4, -28, 5, 14, -38, -7, 33, -49, -21, 53, -60, -35, + -78, 13, 63, -59, 2, 50, -40, -8, 36, -21, -18, 23, + -2, -29, 9, 17, -40, -3, 36, -50, -17, 55, -61, -31, + -76, 12, 67, -57, 1, 54, -38, -9, 40, -19, -20, 27, + 0, -31, 13, 19, -41, 0, 38, -52, -13, 57, -63, -27, + -73, 10, 71, -55, 0, 58, -35, -10, 44, -16, -21, 31, + 3, -32, 17, 22, -42, 4, 40, -53, -9, 60, -64, -23, + -71, 9, 76, -52, -1, 63, -33, -12, 49, -14, -22, 35, + 6, -33, 22, 24, -44, 8, 43, -55, -4, 63, -66, -18, + -68, 7, 80, -50, -2, 67, -30, -13, 53, -11, -24, 39, + 8, -35, 26, 27, -45, 12, 46, -56, 0, 65, -67, -14, + -66, 6, 84, -47, -4, 71, -28, -15, 57, -9, -25, 43, + 10, -36, 30, 29, -47, 16, 48, -57, 3, 67, -68, -10, + -64, 5, 88, -45, -5, 75, -25, -16, 61, -7, -27, 47, + 13, -37, 34, 32, -48, 20, 50, -59, 7, 70, -70, -6, + -61, 3, 92, -42, -6, 79, -23, -17, 65, -4, -28, 51, + 15, -39, 38, 34, -49, 24, 53, -60, 11, 72, -71, -2, + -58, 2, 96, -40, -8, 83, -20, -19, 69, -2, -29, 56, + 18, -40, 42, 37, -51, 29, 55, -62, 15, 75, -72, 1, + -56, 0, 100, -37, -9, 87, -18, -20, 73, 1, -31, 60, + 20, -42, 46, 39, -52, 33, 58, -63, 19, 77, -74, 5, + -54, 0, 104, -35, -11, 91, -16, -21, 77, 3, -32, 64, + 23, -43, 50, 41, -54, 37, 60, -64, 23, 80, -75, 9, + -51, -1, 108, -33, -12, 95, -13, -23, 81, 6, -33, 68, + 25, -44, 54, 44, -55, 41, 63, -66, 27, 82, -77, 13, + -49, -3, 113, -30, -13, 100, -10, -24, 86, 8, -35, 72, + 28, -46, 59, 46, -56, 45, 65, -67, 32, 85, -78, 18, + -46, -4, 117, -27, -15, 104, -8, -26, 90, 11, -36, 76, + 30, -47, 63, 49, -58, 49, 68, -68, 36, 87, -79, 22, + -44, -6, 121, -25, -16, 108, -6, -27, 94, 13, -38, 80, + 32, -49, 67, 51, -59, 53, 70, -70, 40, 89, -81, 26, + -119, 41, -6, -100, 30, -20, -81, 19, -33, -62, 8, -47, + -43, -2, -61, -24, -12, -74, -5, -23, -87, 14, -34, -101, + -117, 39, -2, -98, 29, -16, -79, 18, -29, -60, 7, -43, + -40, -3, -57, -22, -14, -70, -3, -24, -83, 16, -35, -97, + -114, 38, 1, -96, 27, -12, -76, 16, -25, -57, 6, -39, + -38, -4, -53, -19, -15, -66, 0, -25, -79, 19, -36, -93, + -112, 36, 5, -93, 26, -7, -74, 15, -21, -55, 4, -34, + -35, -6, -48, -17, -16, -61, 2, -27, -75, 22, -38, -89, + -109, 35, 9, -91, 24, -3, -71, 13, -17, -52, 3, -30, + -33, -7, -44, -14, -18, -57, 5, -28, -71, 24, -39, -85, + -107, 34, 13, -88, 23, 0, -69, 12, -13, -50, 1, -26, + -31, -8, -40, -12, -19, -53, 7, -30, -67, 26, -41, -81, + -105, 32, 17, -86, 22, 4, -66, 11, -9, -48, 0, -22, + -28, -10, -36, -9, -20, -49, 9, -31, -63, 29, -42, -77, + -102, 31, 22, -83, 20, 8, -64, 9, -4, -45, 0, -18, + -25, -11, -32, -7, -22, -45, 12, -33, -58, 31, -43, -72, + -99, 29, 26, -81, 19, 12, -61, 8, 0, -42, -2, -14, + -23, -13, -28, -4, -23, -41, 14, -34, -54, 34, -45, -68, + -97, 28, 30, -78, 17, 16, -59, 6, 3, -40, -3, -10, + -21, -14, -24, -2, -25, -37, 17, -35, -50, 36, -46, -64, + -95, 27, 34, -76, 16, 20, -56, 5, 7, -38, -4, -6, + -18, -15, -20, 0, -26, -33, 19, -37, -46, 39, -48, -60, + -92, 25, 38, -73, 15, 24, -54, 4, 11, -35, -6, -2, + -16, -17, -16, 3, -27, -29, 22, -38, -42, 41, -49, -56, + -90, 24, 42, -71, 13, 29, -51, 2, 15, -33, -7, 2, + -13, -18, -11, 6, -29, -24, 24, -39, -38, 44, -50, -52, + -87, 22, 46, -68, 12, 33, -49, 1, 19, -30, -9, 6, + -11, -20, -7, 8, -30, -20, 27, -41, -34, 46, -52, -48, + -85, 21, 50, -66, 10, 37, -47, 0, 23, -28, -10, 10, + -8, -21, -3, 10, -32, -16, 29, -42, -30, 48, -53, -44, + -82, 20, 54, -64, 9, 41, -44, -1, 27, -25, -11, 14, + -6, -22, 0, 13, -33, -12, 32, -44, -26, 51, -54, -40, + -80, 18, 59, -61, 8, 45, -42, -2, 32, -23, -13, 18, + -3, -24, 4, 15, -34, -8, 34, -45, -21, 54, -56, -35, + -77, 17, 63, -59, 6, 49, -39, -4, 36, -20, -14, 22, + -1, -25, 8, 18, -36, -4, 37, -46, -17, 56, -57, -31, + -75, 16, 67, -56, 5, 53, -37, -5, 40, -18, -16, 26, + 1, -27, 12, 20, -37, 0, 39, -48, -13, 58, -59, -27, + -73, 14, 71, -54, 4, 57, -34, -6, 44, -16, -17, 30, + 4, -28, 16, 23, -38, 3, 41, -49, -9, 61, -60, -23, + -70, 13, 75, -51, 2, 62, -32, -8, 48, -13, -18, 35, + 6, -29, 21, 25, -40, 8, 44, -51, -5, 63, -62, -19, + -67, 11, 79, -49, 1, 66, -29, -9, 52, -10, -20, 39, + 9, -31, 25, 28, -41, 12, 46, -52, -1, 66, -63, -15, + -65, 10, 83, -46, 0, 70, -27, -11, 56, -8, -21, 43, + 11, -32, 29, 30, -43, 16, 49, -53, 2, 68, -64, -11, + -63, 9, 87, -44, -1, 74, -24, -12, 60, -6, -23, 47, + 14, -33, 33, 32, -44, 20, 51, -55, 6, 71, -66, -7, + -60, 7, 91, -41, -2, 78, -22, -13, 64, -3, -24, 51, + 16, -35, 37, 35, -45, 24, 54, -56, 10, 73, -67, -3, + -58, 6, 96, -39, -4, 82, -19, -15, 69, -1, -25, 55, + 19, -36, 41, 38, -47, 28, 56, -58, 15, 76, -68, 1, + -55, 4, 100, -36, -5, 86, -17, -16, 73, 2, -27, 59, + 21, -38, 45, 40, -48, 32, 59, -59, 19, 78, -70, 5, + -53, 3, 104, -34, -7, 90, -15, -17, 77, 4, -28, 63, + 24, -39, 49, 42, -50, 36, 61, -60, 23, 80, -71, 9, + -50, 2, 108, -32, -8, 94, -12, -19, 81, 7, -29, 67, + 26, -40, 53, 45, -51, 40, 63, -62, 27, 83, -73, 13, + -48, 0, 112, -29, -9, 99, -10, -20, 85, 9, -31, 72, + 29, -42, 58, 47, -52, 45, 66, -63, 31, 86, -74, 17, + -45, 0, 116, -27, -11, 103, -7, -22, 89, 12, -32, 76, + 31, -43, 62, 50, -54, 49, 69, -64, 35, 88, -75, 21, + -43, -2, 120, -24, -12, 107, -5, -23, 93, 14, -34, 80, + 33, -45, 66, 52, -55, 53, 71, -66, 39, 90, -77, 25, + -118, 45, -7, -99, 34, -20, -80, 23, -34, -61, 12, -47, + -42, 1, -61, -23, -8, -75, -4, -19, -88, 15, -30, -102, + -116, 43, -3, -97, 33, -16, -78, 22, -30, -59, 11, -43, + -40, 0, -57, -21, -10, -71, -2, -20, -84, 17, -31, -98, + -113, 42, 0, -95, 31, -12, -75, 20, -26, -57, 10, -39, + -37, 0, -53, -18, -11, -67, 0, -21, -80, 20, -32, -94, + -111, 40, 5, -92, 30, -8, -73, 19, -22, -54, 8, -35, + -34, -2, -49, -16, -12, -62, 3, -23, -76, 22, -34, -89, + -108, 39, 9, -90, 28, -4, -70, 17, -18, -51, 7, -31, + -32, -3, -45, -13, -14, -58, 6, -24, -72, 25, -35, -85, + -106, 38, 13, -87, 27, 0, -68, 16, -14, -49, 5, -27, + -30, -4, -41, -11, -15, -54, 8, -26, -68, 27, -37, -81, + -104, 36, 17, -85, 26, 3, -65, 15, -10, -47, 4, -23, + -27, -6, -37, -8, -16, -50, 10, -27, -64, 30, -38, -77, + -101, 35, 21, -82, 24, 8, -63, 13, -5, -44, 3, -18, + -25, -7, -32, -6, -18, -46, 13, -29, -59, 32, -39, -73, + -99, 33, 25, -80, 23, 12, -60, 12, -1, -42, 1, -14, + -22, -9, -28, -3, -19, -42, 15, -30, -55, 35, -41, -69, + -96, 32, 29, -77, 21, 16, -58, 10, 2, -39, 0, -10, + -20, -10, -24, -1, -21, -38, 18, -31, -51, 37, -42, -65, + -94, 31, 33, -75, 20, 20, -56, 9, 6, -37, 0, -6, + -17, -11, -20, 1, -22, -34, 20, -33, -47, 40, -44, -61, + -91, 29, 37, -73, 19, 24, -53, 8, 10, -34, -2, -2, + -15, -13, -16, 4, -23, -30, 23, -34, -43, 42, -45, -57, + -89, 28, 42, -70, 17, 28, -50, 6, 14, -32, -3, 1, + -12, -14, -12, 6, -25, -25, 25, -35, -39, 45, -46, -52, + -86, 26, 46, -67, 16, 32, -48, 5, 18, -29, -5, 5, + -10, -16, -8, 9, -26, -21, 28, -37, -35, 47, -48, -48, + -84, 25, 50, -65, 14, 36, -46, 4, 22, -27, -6, 9, + -8, -17, -4, 11, -28, -17, 30, -38, -31, 49, -49, -44, + -81, 24, 54, -63, 13, 40, -43, 2, 26, -25, -7, 13, + -5, -18, 0, 14, -29, -13, 32, -40, -27, 52, -50, -40, + -79, 22, 58, -60, 12, 45, -41, 1, 31, -22, -9, 18, + -2, -20, 4, 16, -30, -9, 35, -41, -22, 54, -52, -36, + -76, 21, 62, -58, 10, 49, -38, 0, 35, -19, -10, 22, + 0, -21, 8, 19, -32, -5, 37, -42, -18, 57, -53, -32, + -74, 20, 66, -55, 9, 53, -36, -1, 39, -17, -12, 26, + 2, -23, 12, 21, -33, -1, 40, -44, -14, 59, -55, -28, + -72, 18, 70, -53, 8, 57, -33, -2, 43, -15, -13, 30, + 5, -24, 16, 23, -34, 2, 42, -45, -10, 62, -56, -24, + -69, 17, 75, -50, 6, 61, -31, -4, 47, -12, -14, 34, + 7, -25, 20, 26, -36, 7, 45, -47, -6, 64, -58, -19, + -67, 15, 79, -48, 5, 65, -28, -5, 51, -10, -16, 38, + 10, -27, 24, 29, -37, 11, 47, -48, -2, 67, -59, -15, + -64, 14, 83, -45, 3, 69, -26, -7, 55, -7, -17, 42, + 12, -28, 28, 31, -39, 15, 50, -49, 1, 69, -60, -11, + -62, 13, 87, -43, 2, 73, -24, -8, 59, -5, -19, 46, + 15, -29, 32, 33, -40, 19, 52, -51, 5, 72, -62, -7, + -59, 11, 91, -41, 1, 77, -21, -9, 63, -2, -20, 50, + 17, -31, 36, 36, -41, 23, 55, -52, 9, 74, -63, -3, + -57, 10, 95, -38, 0, 82, -18, -11, 68, 0, -21, 55, + 20, -32, 41, 38, -43, 27, 57, -54, 14, 77, -64, 0, + -54, 8, 99, -35, -1, 86, -16, -12, 72, 3, -23, 59, + 22, -34, 45, 41, -44, 31, 60, -55, 18, 79, -66, 4, + -52, 7, 103, -33, -3, 90, -14, -13, 76, 5, -24, 63, + 24, -35, 49, 43, -46, 35, 62, -56, 22, 81, -67, 8, + -49, 6, 107, -31, -4, 94, -11, -15, 80, 7, -25, 67, + 27, -36, 53, 46, -47, 39, 64, -58, 26, 84, -69, 12, + -47, 4, 112, -28, -5, 98, -9, -16, 84, 10, -27, 71, + 30, -38, 57, 48, -48, 44, 67, -59, 30, 86, -70, 17, + -44, 3, 116, -26, -7, 102, -6, -18, 88, 13, -28, 75, + 32, -39, 61, 51, -50, 48, 69, -60, 34, 89, -71, 21, + -42, 1, 120, -23, -8, 106, -4, -19, 92, 15, -30, 79, + 34, -41, 65, 53, -51, 52, 72, -62, 38, 91, -73, 25, + -117, 49, -8, -98, 38, -21, -79, 27, -35, -60, 17, -48, + -41, 6, -62, -22, -4, -75, -3, -14, -89, 16, -25, -103, + -115, 48, -4, -96, 37, -17, -77, 26, -31, -58, 16, -44, + -39, 5, -58, -20, -5, -71, -1, -16, -85, 18, -27, -99, + -112, 46, 0, -94, 36, -13, -74, 25, -27, -55, 14, -40, + -36, 3, -54, -17, -6, -67, 1, -17, -81, 21, -28, -95, + -110, 45, 4, -91, 34, -8, -72, 23, -22, -53, 13, -36, + -33, 2, -49, -15, -8, -63, 4, -18, -76, 24, -29, -90, + -107, 43, 8, -89, 33, -4, -69, 22, -18, -50, 11, -32, + -31, 0, -45, -12, -9, -59, 7, -20, -72, 26, -31, -86, + -105, 42, 12, -86, 31, 0, -67, 21, -14, -48, 10, -28, + -29, 0, -41, -10, -11, -55, 9, -21, -68, 28, -32, -82, + -103, 41, 16, -84, 30, 3, -64, 19, -10, -46, 9, -24, + -26, -1, -37, -7, -12, -51, 11, -23, -64, 31, -33, -78, + -100, 39, 20, -81, 29, 7, -62, 18, -6, -43, 7, -19, + -24, -3, -33, -5, -13, -46, 14, -24, -60, 33, -35, -74, + -97, 38, 24, -79, 27, 11, -59, 16, -2, -41, 6, -15, + -21, -4, -29, -2, -15, -42, 16, -25, -56, 36, -36, -70, + -95, 37, 28, -76, 26, 15, -57, 15, 1, -38, 4, -11, + -19, -6, -25, 0, -16, -38, 19, -27, -52, 38, -38, -66, + -93, 35, 32, -74, 25, 19, -55, 14, 5, -36, 3, -7, + -16, -7, -21, 2, -18, -34, 21, -28, -48, 41, -39, -62, + -90, 34, 36, -72, 23, 23, -52, 12, 9, -33, 2, -3, + -14, -8, -17, 5, -19, -30, 24, -29, -44, 43, -40, -58, + -88, 32, 41, -69, 22, 28, -49, 11, 14, -31, 0, 0, + -11, -10, -12, 7, -20, -26, 26, -31, -39, 46, -42, -53, + -85, 31, 45, -66, 20, 32, -47, 9, 18, -28, 0, 4, + -9, -11, -8, 10, -22, -22, 29, -32, -35, 48, -43, -49, + -83, 30, 49, -64, 19, 36, -45, 8, 22, -26, -2, 8, + -7, -12, -4, 12, -23, -18, 31, -34, -31, 50, -45, -45, + -80, 28, 53, -62, 18, 40, -42, 7, 26, -23, -3, 12, + -4, -14, 0, 15, -24, -14, 33, -35, -27, 53, -46, -41, + -78, 27, 57, -59, 16, 44, -40, 5, 30, -21, -4, 17, + -1, -15, 3, 17, -26, -9, 36, -37, -23, 56, -47, -37, + -75, 25, 61, -57, 15, 48, -37, 4, 34, -18, -6, 21, + 1, -17, 7, 20, -27, -5, 39, -38, -19, 58, -49, -33, + -73, 24, 65, -54, 13, 52, -35, 2, 38, -16, -7, 25, + 3, -18, 11, 22, -29, -1, 41, -39, -15, 60, -50, -29, + -71, 23, 69, -52, 12, 56, -32, 1, 42, -14, -8, 29, + 6, -19, 15, 25, -30, 2, 43, -41, -11, 63, -52, -25, + -68, 21, 74, -49, 11, 61, -30, 0, 47, -11, -10, 33, + 8, -21, 20, 27, -32, 6, 46, -42, -6, 65, -53, -20, + -65, 20, 78, -47, 9, 65, -27, -1, 51, -9, -11, 37, + 11, -22, 24, 30, -33, 10, 48, -43, -2, 68, -54, -16, + -63, 18, 82, -44, 8, 69, -25, -2, 55, -6, -13, 41, + 13, -24, 28, 32, -34, 14, 51, -45, 1, 70, -56, -12, + -61, 17, 86, -42, 7, 73, -23, -3, 59, -4, -14, 45, + 16, -25, 32, 34, -36, 18, 53, -46, 5, 73, -57, -8, + -58, 16, 90, -40, 5, 77, -20, -5, 63, -1, -15, 49, + 18, -26, 36, 37, -37, 22, 56, -48, 9, 75, -58, -4, + -56, 14, 94, -37, 4, 81, -17, -6, 67, 1, -17, 54, + 21, -28, 40, 39, -38, 27, 58, -49, 13, 78, -60, 0, + -53, 13, 98, -34, 2, 85, -15, -8, 71, 4, -18, 58, + 23, -29, 44, 42, -40, 31, 61, -50, 17, 80, -61, 3, + -51, 12, 102, -32, 1, 89, -13, -9, 75, 6, -20, 62, + 25, -31, 48, 44, -41, 35, 63, -52, 21, 82, -63, 7, + -48, 10, 106, -30, 0, 93, -10, -10, 79, 8, -21, 66, + 28, -32, 52, 47, -42, 39, 65, -53, 25, 85, -64, 11, + -46, 9, 111, -27, -1, 98, -8, -12, 84, 11, -22, 70, + 31, -33, 57, 49, -44, 43, 68, -55, 30, 87, -66, 16, + -43, 7, 115, -25, -2, 102, -5, -13, 88, 14, -24, 74, + 33, -35, 61, 52, -45, 47, 71, -56, 34, 90, -67, 20, + -41, 6, 119, -22, -4, 106, -3, -15, 92, 16, -25, 78, + 35, -36, 65, 54, -47, 51, 73, -57, 38, 92, -68, 24, + -116, 53, -8, -98, 42, -22, -78, 31, -35, -59, 21, -49, + -40, 10, -63, -21, 0, -76, -2, -10, -89, 17, -21, -103, + -114, 52, -4, -95, 41, -18, -76, 30, -31, -57, 20, -45, + -38, 9, -59, -19, -1, -72, 0, -12, -85, 19, -23, -99, + -112, 50, 0, -93, 40, -14, -73, 29, -27, -55, 18, -41, + -35, 7, -55, -16, -2, -68, 2, -13, -81, 22, -24, -95, + -109, 49, 3, -90, 38, -9, -71, 27, -23, -52, 17, -36, + -33, 6, -50, -14, -4, -64, 5, -14, -77, 24, -25, -91, + -106, 47, 7, -88, 37, -5, -68, 26, -19, -49, 15, -32, + -30, 4, -46, -11, -5, -60, 7, -16, -73, 27, -27, -87, + -104, 46, 11, -85, 35, -1, -66, 25, -15, -47, 14, -28, + -28, 3, -42, -9, -7, -56, 10, -17, -69, 29, -28, -83, + -102, 45, 15, -83, 34, 2, -63, 23, -11, -45, 13, -24, + -25, 2, -38, -7, -8, -52, 12, -19, -65, 32, -29, -79, + -99, 43, 20, -80, 33, 6, -61, 22, -6, -42, 11, -20, + -23, 0, -34, -4, -9, -47, 15, -20, -60, 34, -31, -74, + -97, 42, 24, -78, 31, 10, -58, 20, -2, -40, 10, -16, + -20, 0, -30, -1, -11, -43, 17, -21, -56, 37, -32, -70, + -94, 41, 28, -75, 30, 14, -56, 19, 1, -37, 8, -12, + -18, -2, -26, 1, -12, -39, 20, -23, -52, 39, -34, -66, + -92, 39, 32, -73, 29, 18, -54, 18, 5, -35, 7, -8, + -15, -3, -22, 3, -14, -35, 22, -24, -48, 41, -35, -62, + -89, 38, 36, -71, 27, 22, -51, 16, 9, -32, 6, -4, + -13, -4, -18, 6, -15, -31, 24, -25, -44, 44, -36, -58, + -87, 36, 40, -68, 26, 27, -49, 15, 13, -30, 4, 0, + -10, -6, -13, 8, -16, -27, 27, -27, -40, 47, -38, -54, + -84, 35, 44, -66, 24, 31, -46, 13, 17, -27, 3, 4, + -8, -7, -9, 11, -18, -23, 30, -28, -36, 49, -39, -50, + -82, 34, 48, -63, 23, 35, -44, 12, 21, -25, 1, 8, + -6, -8, -5, 13, -19, -19, 32, -30, -32, 51, -41, -46, + -80, 32, 52, -61, 22, 39, -41, 11, 25, -23, 0, 12, + -3, -10, -1, 16, -20, -15, 34, -31, -28, 54, -42, -42, + -77, 31, 57, -58, 20, 43, -39, 9, 30, -20, 0, 16, + -1, -11, 2, 18, -22, -10, 37, -33, -23, 56, -43, -37, + -74, 29, 61, -56, 19, 47, -36, 8, 34, -18, -2, 20, + 2, -13, 6, 21, -23, -6, 39, -34, -19, 59, -45, -33, + -72, 28, 65, -53, 17, 51, -34, 6, 38, -15, -3, 24, + 4, -14, 10, 23, -25, -2, 42, -35, -15, 61, -46, -29, + -70, 27, 69, -51, 16, 55, -32, 5, 42, -13, -4, 28, + 7, -15, 14, 25, -26, 1, 44, -37, -11, 64, -48, -25, + -67, 25, 73, -48, 15, 60, -29, 4, 46, -10, -6, 33, + 9, -17, 19, 28, -28, 5, 47, -38, -7, 66, -49, -21, + -65, 24, 77, -46, 13, 64, -26, 2, 50, -8, -7, 37, + 12, -18, 23, 31, -29, 9, 49, -39, -3, 69, -50, -17, + -62, 22, 81, -43, 12, 68, -24, 1, 54, -5, -9, 41, + 14, -20, 27, 33, -30, 13, 52, -41, 0, 71, -52, -13, + -60, 21, 85, -41, 11, 72, -22, 0, 58, -3, -10, 45, + 17, -21, 31, 35, -32, 17, 54, -42, 4, 73, -53, -9, + -57, 20, 89, -39, 9, 76, -19, -1, 62, 0, -11, 49, + 19, -22, 35, 38, -33, 21, 56, -44, 8, 76, -54, -5, + -55, 18, 94, -36, 8, 80, -17, -2, 67, 2, -13, 53, + 22, -24, 39, 40, -34, 26, 59, -45, 13, 79, -56, 0, + -52, 17, 98, -34, 6, 84, -14, -4, 71, 5, -14, 57, + 24, -25, 43, 43, -36, 30, 62, -46, 17, 81, -57, 3, + -50, 16, 102, -31, 5, 88, -12, -5, 75, 7, -16, 61, + 26, -27, 47, 45, -37, 34, 64, -48, 21, 83, -59, 7, + -48, 14, 106, -29, 4, 92, -9, -6, 79, 9, -17, 65, + 29, -28, 51, 48, -38, 38, 66, -49, 25, 86, -60, 11, + -45, 13, 110, -26, 2, 97, -7, -8, 83, 12, -18, 70, + 31, -29, 56, 50, -40, 42, 69, -51, 29, 88, -62, 15, + -42, 11, 114, -24, 1, 101, -4, -9, 87, 14, -20, 74, + 34, -31, 60, 53, -41, 46, 71, -52, 33, 91, -63, 19, + -40, 10, 118, -21, 0, 105, -2, -11, 91, 17, -21, 78, + 36, -32, 64, 55, -43, 50, 74, -53, 37, 93, -64, 23, + -115, 57, -9, -97, 46, -22, -77, 35, -36, -58, 25, -49, + -39, 14, -63, -20, 3, -77, -2, -6, -90, 18, -17, -104, + -113, 56, -5, -94, 45, -18, -75, 34, -32, -56, 24, -45, + -37, 13, -59, -18, 2, -73, 1, -8, -86, 20, -19, -100, + -111, 54, -1, -92, 44, -14, -72, 33, -28, -54, 22, -41, + -34, 11, -55, -16, 1, -69, 3, -9, -82, 23, -20, -96, + -108, 53, 3, -89, 42, -10, -70, 31, -24, -51, 21, -37, + -32, 10, -51, -13, 0, -64, 6, -10, -78, 25, -21, -91, + -106, 51, 7, -87, 41, -6, -67, 30, -20, -49, 19, -33, + -29, 8, -47, -10, -1, -60, 8, -12, -74, 28, -23, -87, + -103, 50, 11, -84, 39, -2, -65, 29, -16, -46, 18, -29, + -27, 7, -43, -8, -3, -56, 11, -13, -70, 30, -24, -83, + -101, 49, 15, -82, 38, 1, -63, 27, -12, -44, 17, -25, + -24, 6, -39, -6, -4, -52, 13, -15, -66, 33, -25, -79, + -98, 47, 19, -79, 37, 6, -60, 26, -7, -41, 15, -20, + -22, 4, -34, -3, -5, -48, 16, -16, -61, 35, -27, -75, + -96, 46, 23, -77, 35, 10, -58, 24, -3, -39, 14, -16, + -19, 3, -30, -1, -7, -44, 18, -17, -57, 38, -28, -71, + -93, 45, 27, -74, 34, 14, -55, 23, 0, -36, 12, -12, + -17, 1, -26, 2, -8, -40, 21, -19, -53, 40, -30, -67, + -91, 43, 31, -72, 33, 18, -53, 22, 4, -34, 11, -8, + -15, 0, -22, 4, -10, -36, 23, -20, -49, 42, -31, -63, + -88, 42, 35, -70, 31, 22, -50, 20, 8, -32, 10, -4, + -12, 0, -18, 7, -11, -32, 25, -21, -45, 45, -32, -59, + -86, 40, 40, -67, 30, 26, -48, 19, 12, -29, 8, 0, + -9, -2, -14, 9, -12, -27, 28, -23, -41, 47, -34, -54, + -83, 39, 44, -65, 28, 30, -45, 17, 16, -26, 7, 3, + -7, -3, -10, 12, -14, -23, 30, -24, -37, 50, -35, -50, + -81, 38, 48, -62, 27, 34, -43, 16, 20, -24, 5, 7, + -5, -4, -6, 14, -15, -19, 33, -26, -33, 52, -37, -46, + -79, 36, 52, -60, 26, 38, -40, 15, 24, -22, 4, 11, + -2, -6, -2, 16, -16, -15, 35, -27, -29, 55, -38, -42, + -76, 35, 56, -57, 24, 43, -38, 13, 29, -19, 3, 16, + 0, -7, 2, 19, -18, -11, 38, -29, -24, 57, -39, -38, + -74, 33, 60, -55, 23, 47, -35, 12, 33, -17, 1, 20, + 3, -9, 6, 22, -19, -7, 40, -30, -20, 60, -41, -34, + -71, 32, 64, -52, 21, 51, -33, 10, 37, -14, 0, 24, + 5, -10, 10, 24, -21, -3, 43, -31, -16, 62, -42, -30, + -69, 31, 68, -50, 20, 55, -31, 9, 41, -12, 0, 28, + 8, -11, 14, 26, -22, 0, 45, -33, -12, 65, -44, -26, + -66, 29, 73, -47, 19, 59, -28, 8, 45, -9, -2, 32, + 10, -13, 18, 29, -24, 5, 48, -34, -8, 67, -45, -21, + -64, 28, 77, -45, 17, 63, -26, 6, 49, -7, -3, 36, + 13, -14, 22, 31, -25, 9, 50, -35, -4, 70, -46, -17, + -61, 26, 81, -42, 16, 67, -23, 5, 53, -4, -5, 40, + 15, -16, 26, 34, -26, 13, 53, -37, 0, 72, -48, -13, + -59, 25, 85, -40, 15, 71, -21, 4, 57, -2, -6, 44, + 17, -17, 30, 36, -28, 17, 55, -38, 3, 74, -49, -9, + -56, 24, 89, -38, 13, 75, -18, 2, 61, 0, -7, 48, + 20, -18, 34, 39, -29, 21, 57, -40, 7, 77, -50, -5, + -54, 22, 93, -35, 12, 80, -16, 1, 66, 3, -9, 53, + 23, -20, 39, 41, -30, 25, 60, -41, 12, 79, -52, -1, + -51, 21, 97, -33, 10, 84, -13, 0, 70, 6, -10, 57, + 25, -21, 43, 44, -32, 29, 62, -42, 16, 82, -53, 2, + -49, 20, 101, -30, 9, 88, -11, -1, 74, 8, -12, 61, + 27, -23, 47, 46, -33, 33, 65, -44, 20, 84, -55, 6, + -47, 18, 105, -28, 8, 92, -8, -2, 78, 10, -13, 65, + 30, -24, 51, 48, -34, 37, 67, -45, 24, 87, -56, 10, + -44, 17, 110, -25, 6, 96, -6, -4, 82, 13, -14, 69, + 32, -25, 55, 51, -36, 42, 70, -47, 28, 89, -58, 15, + -42, 15, 114, -23, 5, 100, -3, -5, 86, 15, -16, 73, + 35, -27, 59, 54, -37, 46, 72, -48, 32, 92, -59, 19, + -39, 14, 118, -20, 3, 104, -1, -7, 90, 18, -17, 77, + 37, -28, 63, 56, -39, 50, 75, -49, 36, 94, -60, 23, + -114, 61, -10, -96, 50, -23, -76, 39, -37, -58, 29, -50, + -38, 18, -64, -19, 7, -77, -1, -2, -91, 19, -13, -105, + -112, 60, -6, -93, 49, -19, -74, 38, -33, -55, 28, -46, + -36, 17, -60, -17, 6, -73, 2, -4, -87, 21, -15, -101, + -110, 58, -2, -91, 48, -15, -72, 37, -29, -53, 26, -42, + -33, 15, -56, -15, 5, -69, 4, -5, -83, 24, -16, -97, + -107, 57, 2, -88, 46, -10, -69, 35, -24, -50, 25, -38, + -31, 14, -51, -12, 3, -65, 7, -6, -78, 26, -17, -92, + -105, 55, 6, -86, 45, -6, -66, 34, -20, -48, 23, -34, + -28, 12, -47, -10, 2, -61, 9, -8, -74, 29, -19, -88, + -102, 54, 10, -83, 43, -2, -64, 33, -16, -45, 22, -30, + -26, 11, -43, -7, 0, -57, 12, -9, -70, 31, -20, -84, + -100, 53, 14, -81, 42, 1, -62, 31, -12, -43, 21, -26, + -24, 10, -39, -5, 0, -53, 14, -11, -66, 33, -21, -80, + -97, 51, 18, -78, 41, 5, -59, 30, -8, -40, 19, -21, + -21, 8, -35, -2, -1, -48, 17, -12, -62, 36, -23, -76, + -95, 50, 22, -76, 39, 9, -57, 28, -4, -38, 18, -17, + -18, 7, -31, 0, -3, -44, 19, -13, -58, 39, -24, -72, + -92, 49, 26, -74, 38, 13, -54, 27, 0, -35, 16, -13, + -16, 5, -27, 3, -4, -40, 22, -15, -54, 41, -26, -68, + -90, 47, 30, -71, 37, 17, -52, 26, 3, -33, 15, -9, + -14, 4, -23, 5, -6, -36, 24, -16, -50, 43, -27, -64, + -88, 46, 34, -69, 35, 21, -49, 24, 7, -31, 14, -5, + -11, 3, -19, 8, -7, -32, 26, -17, -46, 46, -28, -60, + -85, 44, 39, -66, 34, 26, -47, 23, 12, -28, 12, -1, + -9, 1, -14, 10, -8, -28, 29, -19, -41, 48, -30, -55, + -82, 43, 43, -64, 32, 30, -44, 21, 16, -26, 11, 2, + -6, 0, -10, 13, -10, -24, 31, -20, -37, 51, -31, -51, + -80, 42, 47, -61, 31, 34, -42, 20, 20, -23, 9, 6, + -4, 0, -6, 15, -11, -20, 34, -22, -33, 53, -33, -47, + -78, 40, 51, -59, 30, 38, -40, 19, 24, -21, 8, 10, + -1, -2, -2, 17, -12, -16, 36, -23, -29, 56, -34, -43, + -75, 39, 55, -56, 28, 42, -37, 17, 28, -18, 7, 15, + 1, -3, 1, 20, -14, -11, 39, -25, -25, 58, -35, -39, + -73, 37, 59, -54, 27, 46, -34, 16, 32, -16, 5, 19, + 4, -5, 5, 22, -15, -7, 41, -26, -21, 61, -37, -35, + -70, 36, 63, -51, 25, 50, -32, 14, 36, -13, 4, 23, + 6, -6, 9, 25, -17, -3, 44, -27, -17, 63, -38, -31, + -68, 35, 67, -49, 24, 54, -30, 13, 40, -11, 3, 27, + 8, -7, 13, 27, -18, 0, 46, -29, -13, 65, -40, -27, + -65, 33, 72, -46, 23, 59, -27, 12, 45, -8, 1, 31, + 11, -9, 18, 30, -20, 4, 49, -30, -8, 68, -41, -22, + -63, 32, 76, -44, 21, 63, -25, 10, 49, -6, 0, 35, + 14, -10, 22, 32, -21, 8, 51, -31, -4, 70, -42, -18, + -60, 30, 80, -42, 20, 67, -22, 9, 53, -3, -1, 39, + 16, -12, 26, 35, -22, 12, 54, -33, 0, 73, -44, -14, + -58, 29, 84, -39, 19, 71, -20, 8, 57, -1, -2, 43, + 18, -13, 30, 37, -24, 16, 56, -34, 3, 75, -45, -10, + -56, 28, 88, -37, 17, 75, -17, 6, 61, 1, -3, 47, + 21, -14, 34, 40, -25, 20, 58, -36, 7, 78, -46, -6, + -53, 26, 92, -34, 16, 79, -15, 5, 65, 4, -5, 52, + 23, -16, 38, 42, -26, 25, 61, -37, 11, 80, -48, -2, + -50, 25, 96, -32, 14, 83, -12, 3, 69, 6, -6, 56, + 26, -17, 42, 45, -28, 29, 63, -38, 15, 83, -49, 1, + -48, 24, 100, -29, 13, 87, -10, 2, 73, 9, -8, 60, + 28, -19, 46, 47, -29, 33, 66, -40, 19, 85, -51, 5, + -46, 22, 104, -27, 12, 91, -8, 1, 77, 11, -9, 64, + 31, -20, 50, 49, -30, 37, 68, -41, 23, 88, -52, 9, + -43, 21, 109, -24, 10, 96, -5, 0, 82, 14, -10, 68, + 33, -21, 55, 52, -32, 41, 71, -43, 28, 90, -54, 14, + -41, 19, 113, -22, 9, 100, -2, -1, 86, 16, -12, 72, + 36, -23, 59, 54, -33, 45, 73, -44, 32, 93, -55, 18, + -38, 18, 117, -19, 7, 104, 0, -3, 90, 19, -13, 76, + 38, -24, 63, 57, -35, 49, 76, -45, 36, 95, -56, 22, + -113, 66, -10, -95, 55, -24, -75, 44, -37, -57, 33, -51, + -37, 22, -65, -18, 12, -78, 0, 1, -91, 20, -9, -105, + -111, 64, -6, -92, 54, -20, -73, 43, -33, -54, 32, -47, + -35, 21, -61, -16, 10, -74, 3, 0, -87, 22, -10, -101, + -109, 63, -2, -90, 52, -16, -71, 41, -29, -52, 31, -43, + -32, 20, -57, -14, 9, -70, 5, 0, -83, 25, -11, -97, + -106, 61, 1, -87, 51, -11, -68, 40, -25, -49, 29, -38, + -30, 18, -52, -11, 8, -66, 8, -2, -79, 27, -13, -93, + -104, 60, 5, -85, 49, -7, -65, 38, -21, -47, 28, -34, + -27, 17, -48, -8, 6, -62, 10, -3, -75, 30, -14, -89, + -101, 59, 9, -82, 48, -3, -63, 37, -17, -44, 26, -30, + -25, 16, -44, -6, 5, -58, 13, -5, -71, 32, -16, -85, + -99, 57, 13, -80, 47, 0, -61, 36, -13, -42, 25, -26, + -22, 14, -40, -4, 4, -54, 15, -6, -67, 34, -17, -81, + -96, 56, 18, -77, 45, 4, -58, 34, -8, -39, 24, -22, + -20, 13, -36, -1, 2, -49, 18, -8, -62, 37, -18, -76, + -94, 54, 22, -75, 44, 8, -56, 33, -4, -37, 22, -18, + -17, 11, -32, 1, 1, -45, 20, -9, -58, 40, -20, -72, + -91, 53, 26, -73, 42, 12, -53, 31, 0, -34, 21, -14, + -15, 10, -28, 4, 0, -41, 23, -10, -54, 42, -21, -68, + -89, 52, 30, -70, 41, 16, -51, 30, 3, -32, 20, -10, + -13, 9, -24, 6, -1, -37, 25, -12, -50, 44, -23, -64, + -87, 50, 34, -68, 40, 20, -48, 29, 7, -30, 18, -6, + -10, 7, -20, 9, -2, -33, 27, -13, -46, 47, -24, -60, + -84, 49, 38, -65, 38, 25, -46, 27, 11, -27, 17, -1, + -8, 6, -15, 11, -4, -29, 30, -14, -42, 49, -25, -56, + -81, 47, 42, -63, 37, 29, -43, 26, 15, -25, 15, 2, + -5, 4, -11, 14, -5, -25, 32, -16, -38, 52, -27, -52, + -79, 46, 46, -60, 35, 33, -41, 25, 19, -22, 14, 6, + -3, 3, -7, 16, -7, -21, 35, -17, -34, 54, -28, -48, + -77, 45, 50, -58, 34, 37, -39, 23, 23, -20, 13, 10, + 0, 2, -3, 18, -8, -17, 37, -19, -30, 57, -29, -44, + -74, 43, 55, -55, 33, 41, -36, 22, 28, -17, 11, 14, + 2, 0, 0, 21, -9, -12, 40, -20, -25, 59, -31, -39, + -72, 42, 59, -53, 31, 45, -33, 20, 32, -15, 10, 18, + 5, 0, 4, 24, -11, -8, 42, -21, -21, 62, -32, -35, + -69, 41, 63, -50, 30, 49, -31, 19, 36, -12, 8, 22, + 7, -2, 8, 26, -12, -4, 45, -23, -17, 64, -34, -31, + -67, 39, 67, -48, 29, 53, -29, 18, 40, -10, 7, 26, + 10, -3, 12, 28, -13, 0, 47, -24, -13, 66, -35, -27, + -64, 38, 71, -45, 27, 58, -26, 16, 44, -7, 6, 31, + 12, -4, 17, 31, -15, 3, 50, -26, -9, 69, -37, -23, + -62, 36, 75, -43, 26, 62, -24, 15, 48, -5, 4, 35, + 15, -6, 21, 33, -16, 7, 52, -27, -5, 72, -38, -19, + -59, 35, 79, -41, 24, 66, -21, 13, 52, -2, 3, 39, + 17, -7, 25, 36, -18, 11, 55, -28, -1, 74, -39, -15, + -57, 34, 83, -38, 23, 70, -19, 12, 56, 0, 1, 43, + 19, -8, 29, 38, -19, 15, 57, -30, 2, 76, -41, -11, + -55, 32, 87, -36, 22, 74, -16, 11, 60, 2, 0, 47, + 22, -10, 33, 41, -20, 19, 59, -31, 6, 79, -42, -7, + -52, 31, 92, -33, 20, 78, -14, 9, 65, 5, 0, 51, + 24, -11, 37, 43, -22, 24, 62, -33, 11, 81, -43, -2, + -49, 29, 96, -31, 19, 82, -11, 8, 69, 7, -2, 55, + 27, -13, 41, 46, -23, 28, 64, -34, 15, 84, -45, 1, + -47, 28, 100, -28, 17, 86, -9, 7, 73, 10, -3, 59, + 29, -14, 45, 48, -25, 32, 67, -35, 19, 86, -46, 5, + -45, 27, 104, -26, 16, 90, -7, 5, 77, 12, -4, 63, + 32, -15, 49, 50, -26, 36, 69, -37, 23, 89, -48, 9, + -42, 25, 108, -23, 15, 95, -4, 4, 81, 15, -6, 68, + 34, -17, 54, 53, -27, 40, 72, -38, 27, 91, -49, 13, + -40, 24, 112, -21, 13, 99, -1, 2, 85, 17, -7, 72, + 37, -18, 58, 55, -29, 44, 74, -39, 31, 94, -50, 17, + -37, 22, 116, -18, 12, 103, 1, 1, 89, 20, -9, 76, + 39, -20, 62, 58, -30, 48, 77, -41, 35, 96, -52, 21, + -113, 70, -11, -94, 59, -24, -74, 48, -38, -56, 37, -51, + -36, 26, -65, -17, 16, -79, 1, 5, -92, 21, -5, -106, + -110, 68, -7, -91, 58, -20, -72, 47, -34, -53, 36, -47, + -34, 25, -61, -15, 14, -75, 4, 4, -88, 23, -6, -102, + -108, 67, -3, -89, 56, -16, -70, 45, -30, -51, 35, -43, + -31, 24, -57, -13, 13, -71, 6, 3, -84, 25, -7, -98, + -105, 65, 1, -86, 55, -12, -67, 44, -26, -48, 33, -39, + -29, 22, -53, -10, 12, -66, 9, 1, -80, 28, -9, -93, + -103, 64, 5, -84, 53, -8, -65, 42, -22, -46, 32, -35, + -26, 21, -49, -8, 10, -62, 11, 0, -76, 31, -10, -89, + -100, 63, 9, -81, 52, -4, -62, 41, -18, -43, 30, -31, + -24, 20, -45, -5, 9, -58, 14, -1, -72, 33, -12, -85, + -98, 61, 13, -79, 51, 0, -60, 40, -14, -41, 29, -27, + -22, 18, -41, -3, 8, -54, 16, -2, -68, 35, -13, -81, + -95, 60, 17, -76, 49, 4, -57, 38, -9, -38, 28, -22, + -19, 17, -36, 0, 6, -50, 19, -4, -63, 38, -14, -77, + -93, 58, 21, -74, 48, 8, -55, 37, -5, -36, 26, -18, + -16, 15, -32, 2, 5, -46, 21, -5, -59, 40, -16, -73, + -90, 57, 25, -72, 46, 12, -52, 35, -1, -33, 25, -14, + -14, 14, -28, 5, 3, -42, 23, -6, -55, 43, -17, -69, + -88, 56, 29, -69, 45, 16, -50, 34, 2, -31, 24, -10, + -12, 13, -24, 7, 2, -38, 26, -8, -51, 45, -19, -65, + -86, 54, 33, -67, 44, 20, -47, 33, 6, -29, 22, -6, + -9, 11, -20, 9, 1, -34, 28, -9, -47, 48, -20, -61, + -83, 53, 38, -64, 42, 24, -45, 31, 10, -26, 21, -2, + -7, 10, -16, 12, 0, -29, 31, -10, -43, 50, -21, -56, + -81, 51, 42, -62, 41, 28, -42, 30, 14, -24, 19, 1, + -4, 8, -12, 15, -1, -25, 33, -12, -39, 53, -23, -52, + -78, 50, 46, -59, 39, 32, -40, 29, 18, -21, 18, 5, + -2, 7, -8, 17, -3, -21, 36, -13, -35, 55, -24, -48, + -76, 49, 50, -57, 38, 36, -38, 27, 22, -19, 17, 9, + 1, 6, -4, 19, -4, -17, 38, -15, -31, 57, -25, -44, + -73, 47, 54, -54, 37, 41, -35, 26, 27, -16, 15, 14, + 3, 4, 0, 22, -5, -13, 41, -16, -26, 60, -27, -40, + -71, 46, 58, -52, 35, 45, -33, 24, 31, -14, 14, 18, + 6, 3, 4, 24, -7, -9, 43, -17, -22, 63, -28, -36, + -68, 45, 62, -50, 34, 49, -30, 23, 35, -11, 12, 22, + 8, 1, 8, 27, -8, -5, 46, -19, -18, 65, -30, -32, + -66, 43, 66, -47, 33, 53, -28, 22, 39, -9, 11, 26, + 10, 0, 12, 29, -9, -1, 48, -20, -14, 67, -31, -28, + -63, 42, 71, -44, 31, 57, -25, 20, 43, -6, 10, 30, + 13, 0, 16, 32, -11, 3, 51, -22, -10, 70, -33, -23, + -61, 40, 75, -42, 30, 61, -23, 19, 47, -4, 8, 34, + 15, -2, 20, 34, -12, 7, 53, -23, -6, 72, -34, -19, + -58, 39, 79, -40, 28, 65, -20, 17, 51, -1, 7, 38, + 18, -3, 24, 37, -14, 11, 55, -24, -2, 75, -35, -15, + -56, 38, 83, -37, 27, 69, -18, 16, 55, 1, 5, 42, + 20, -4, 28, 39, -15, 15, 58, -26, 1, 77, -37, -11, + -54, 36, 87, -35, 26, 73, -15, 15, 59, 3, 4, 46, + 23, -6, 32, 41, -16, 19, 60, -27, 5, 80, -38, -7, + -51, 35, 91, -32, 24, 78, -13, 13, 64, 6, 3, 51, + 25, -7, 37, 44, -18, 23, 63, -29, 10, 82, -39, -3, + -49, 33, 95, -30, 23, 82, -10, 12, 68, 8, 1, 55, + 28, -9, 41, 47, -19, 27, 65, -30, 14, 85, -41, 0, + -46, 32, 99, -27, 21, 86, -8, 11, 72, 11, 0, 59, + 30, -10, 45, 49, -21, 31, 68, -31, 18, 87, -42, 4, + -44, 31, 103, -25, 20, 90, -6, 9, 76, 13, 0, 63, + 33, -11, 49, 51, -22, 35, 70, -33, 22, 89, -44, 8, + -41, 29, 108, -22, 19, 94, -3, 8, 80, 16, -2, 67, + 35, -13, 53, 54, -23, 40, 73, -34, 26, 92, -45, 13, + -39, 28, 112, -20, 17, 98, -1, 6, 84, 18, -3, 71, + 38, -14, 57, 56, -25, 44, 75, -35, 30, 95, -46, 17, + -36, 26, 116, -18, 16, 102, 2, 5, 88, 21, -5, 75, + 40, -16, 61, 59, -26, 48, 78, -37, 34, 97, -48, 21, + -112, 74, -12, -93, 63, -25, -73, 52, -39, -55, 41, -52, + -35, 30, -66, -17, 20, -79, 2, 9, -93, 22, -1, -107, + -109, 72, -8, -90, 62, -21, -71, 51, -35, -52, 40, -48, + -33, 29, -62, -14, 18, -75, 5, 8, -89, 24, -2, -103, + -107, 71, -4, -88, 60, -17, -69, 49, -31, -50, 39, -44, + -31, 28, -58, -12, 17, -71, 7, 7, -85, 26, -3, -99, + -104, 69, 0, -85, 59, -12, -66, 48, -26, -47, 37, -40, + -28, 26, -53, -9, 16, -67, 10, 5, -80, 29, -5, -94, + -102, 68, 4, -83, 57, -8, -64, 46, -22, -45, 36, -36, + -25, 25, -49, -7, 14, -63, 12, 4, -76, 31, -6, -90, + -99, 67, 8, -81, 56, -4, -61, 45, -18, -42, 34, -32, + -23, 24, -45, -4, 13, -59, 15, 2, -72, 34, -8, -86, + -97, 65, 12, -78, 55, 0, -59, 44, -14, -40, 33, -28, + -21, 22, -41, -2, 12, -55, 17, 1, -68, 36, -9, -82, + -94, 64, 16, -76, 53, 3, -56, 42, -10, -37, 32, -23, + -18, 21, -37, 1, 10, -50, 20, 0, -64, 39, -10, -78, + -92, 62, 20, -73, 52, 7, -54, 41, -6, -35, 30, -19, + -16, 19, -33, 3, 9, -46, 22, -1, -60, 41, -12, -74, + -90, 61, 24, -71, 50, 11, -51, 39, -2, -33, 29, -15, + -13, 18, -29, 6, 7, -42, 24, -2, -56, 44, -13, -70, + -87, 60, 28, -68, 49, 15, -49, 38, 1, -30, 28, -11, + -11, 17, -25, 8, 6, -38, 27, -4, -52, 46, -15, -66, + -85, 58, 32, -66, 48, 19, -47, 37, 5, -28, 26, -7, + -8, 15, -21, 10, 5, -34, 29, -5, -48, 49, -16, -62, + -82, 57, 37, -63, 46, 24, -44, 35, 10, -25, 25, -3, + -6, 14, -16, 13, 3, -30, 32, -6, -43, 51, -17, -57, + -80, 55, 41, -61, 45, 28, -41, 34, 14, -23, 23, 0, + -3, 12, -12, 15, 2, -26, 34, -8, -39, 54, -19, -53, + -77, 54, 45, -58, 43, 32, -39, 33, 18, -20, 22, 4, + -1, 11, -8, 18, 0, -22, 37, -9, -35, 56, -20, -49, + -75, 53, 49, -56, 42, 36, -37, 31, 22, -18, 21, 8, + 1, 10, -4, 20, 0, -18, 39, -11, -31, 58, -21, -45, + -72, 51, 53, -53, 41, 40, -34, 30, 26, -15, 19, 13, + 4, 8, 0, 23, -1, -13, 42, -12, -27, 61, -23, -41, + -70, 50, 57, -51, 39, 44, -32, 28, 30, -13, 18, 17, + 7, 7, 3, 25, -3, -9, 44, -13, -23, 63, -24, -37, + -67, 49, 61, -49, 38, 48, -29, 27, 34, -10, 16, 21, + 9, 5, 7, 28, -4, -5, 47, -15, -19, 66, -26, -33, + -65, 47, 65, -46, 37, 52, -27, 26, 38, -8, 15, 25, + 11, 4, 11, 30, -5, -1, 49, -16, -15, 68, -27, -29, + -62, 46, 70, -44, 35, 57, -24, 24, 43, -5, 14, 29, + 14, 3, 16, 33, -7, 2, 52, -18, -10, 71, -29, -24, + -60, 44, 74, -41, 34, 61, -22, 23, 47, -3, 12, 33, + 16, 1, 20, 35, -8, 6, 54, -19, -6, 73, -30, -20, + -58, 43, 78, -39, 32, 65, -19, 21, 51, -1, 11, 37, + 19, 0, 24, 38, -10, 10, 56, -20, -2, 76, -31, -16, + -55, 42, 82, -36, 31, 69, -17, 20, 55, 2, 9, 41, + 21, 0, 28, 40, -11, 14, 59, -22, 1, 78, -33, -12, + -53, 40, 86, -34, 30, 73, -15, 19, 59, 4, 8, 45, + 24, -2, 32, 42, -12, 18, 61, -23, 5, 81, -34, -8, + -50, 39, 90, -31, 28, 77, -12, 17, 63, 7, 7, 50, + 26, -3, 36, 45, -14, 23, 64, -25, 9, 83, -35, -4, + -48, 37, 94, -29, 27, 81, -9, 16, 67, 9, 5, 54, + 29, -5, 40, 47, -15, 27, 66, -26, 13, 86, -37, 0, + -45, 36, 98, -26, 25, 85, -7, 15, 71, 12, 4, 58, + 31, -6, 44, 50, -17, 31, 69, -27, 17, 88, -38, 3, + -43, 35, 102, -24, 24, 89, -5, 13, 75, 14, 3, 62, + 33, -7, 48, 52, -18, 35, 71, -29, 21, 90, -40, 7, + -40, 33, 107, -21, 23, 94, -2, 12, 80, 17, 1, 66, + 36, -9, 53, 55, -19, 39, 74, -30, 26, 93, -41, 12, + -38, 32, 111, -19, 21, 98, 0, 10, 84, 19, 0, 70, + 39, -10, 57, 57, -21, 43, 76, -31, 30, 95, -42, 16, + -35, 30, 115, -17, 20, 102, 3, 9, 88, 22, -1, 74, + 41, -12, 61, 60, -22, 47, 78, -33, 34, 98, -44, 20, + -111, 78, -12, -92, 67, -26, -73, 56, -39, -54, 45, -53, + -34, 34, -67, -16, 24, -80, 3, 13, -93, 23, 2, -107, + -108, 76, -8, -90, 66, -22, -70, 55, -35, -51, 44, -49, + -32, 33, -63, -13, 22, -76, 6, 12, -89, 25, 1, -103, + -106, 75, -4, -87, 64, -18, -68, 53, -31, -49, 43, -45, + -30, 32, -59, -11, 21, -72, 8, 11, -85, 27, 0, -99, + -103, 73, 0, -84, 63, -13, -65, 52, -27, -46, 41, -40, + -27, 30, -54, -8, 20, -68, 11, 9, -81, 30, -1, -95, + -101, 72, 3, -82, 61, -9, -63, 50, -23, -44, 40, -36, + -25, 29, -50, -6, 18, -64, 13, 8, -77, 32, -2, -91, + -98, 71, 7, -80, 60, -5, -60, 49, -19, -42, 38, -32, + -22, 28, -46, -3, 17, -60, 15, 6, -73, 35, -4, -87, + -96, 69, 11, -77, 59, -1, -58, 48, -15, -39, 37, -28, + -20, 26, -42, -1, 16, -56, 18, 5, -69, 37, -5, -83, + -93, 68, 16, -75, 57, 2, -55, 46, -10, -36, 36, -24, + -17, 25, -38, 2, 14, -51, 21, 3, -64, 40, -6, -78, + -91, 66, 20, -72, 56, 6, -53, 45, -6, -34, 34, -20, + -15, 23, -34, 4, 13, -47, 23, 2, -60, 42, -8, -74, + -89, 65, 24, -70, 54, 10, -50, 43, -2, -32, 33, -16, + -12, 22, -30, 7, 11, -43, 25, 1, -56, 45, -9, -70, + -86, 64, 28, -67, 53, 14, -48, 42, 1, -29, 32, -12, + -10, 21, -26, 9, 10, -39, 28, 0, -52, 47, -11, -66, + -84, 62, 32, -65, 52, 18, -46, 41, 5, -27, 30, -8, + -7, 19, -22, 11, 9, -35, 30, -1, -48, 49, -12, -62, + -81, 61, 36, -62, 50, 23, -43, 39, 9, -24, 29, -3, + -5, 18, -17, 14, 7, -31, 33, -2, -44, 52, -13, -58, + -79, 59, 40, -60, 49, 27, -41, 38, 13, -22, 27, 0, + -2, 16, -13, 16, 6, -27, 35, -4, -40, 55, -15, -54, + -76, 58, 44, -58, 47, 31, -38, 37, 17, -19, 26, 4, + 0, 15, -9, 19, 4, -23, 38, -5, -36, 57, -16, -50, + -74, 57, 48, -55, 46, 35, -36, 35, 21, -17, 25, 8, + 2, 14, -5, 21, 3, -19, 40, -7, -32, 59, -17, -46, + -71, 55, 53, -52, 45, 39, -33, 34, 26, -14, 23, 12, + 5, 12, -1, 24, 2, -14, 43, -8, -27, 62, -19, -41, + -69, 54, 57, -50, 43, 43, -31, 32, 30, -12, 22, 16, + 7, 11, 2, 26, 0, -10, 45, -9, -23, 64, -20, -37, + -66, 53, 61, -48, 42, 47, -28, 31, 34, -10, 20, 20, + 10, 9, 6, 29, 0, -6, 47, -11, -19, 67, -22, -33, + -64, 51, 65, -45, 41, 51, -26, 30, 38, -7, 19, 24, + 12, 8, 10, 31, -1, -2, 50, -12, -15, 69, -23, -29, + -61, 50, 69, -43, 39, 56, -23, 28, 42, -4, 18, 29, + 15, 7, 15, 34, -3, 1, 52, -14, -11, 72, -25, -25, + -59, 48, 73, -40, 38, 60, -21, 27, 46, -2, 16, 33, + 17, 5, 19, 36, -4, 5, 55, -15, -7, 74, -26, -21, + -57, 47, 77, -38, 36, 64, -18, 25, 50, 0, 15, 37, + 20, 4, 23, 38, -6, 9, 57, -16, -3, 77, -27, -17, + -54, 46, 81, -35, 35, 68, -16, 24, 54, 3, 13, 41, + 22, 3, 27, 41, -7, 13, 60, -18, 0, 79, -29, -13, + -52, 44, 85, -33, 34, 72, -14, 23, 58, 5, 12, 45, + 24, 1, 31, 43, -8, 17, 62, -19, 4, 81, -30, -9, + -49, 43, 90, -30, 32, 76, -11, 21, 63, 8, 11, 49, + 27, 0, 35, 46, -10, 22, 65, -21, 9, 84, -31, -4, + -47, 41, 94, -28, 31, 80, -9, 20, 67, 10, 9, 53, + 30, -1, 39, 48, -11, 26, 67, -22, 13, 87, -33, 0, + -44, 40, 98, -26, 29, 84, -6, 19, 71, 13, 8, 57, + 32, -2, 43, 51, -13, 30, 70, -23, 17, 89, -34, 3, + -42, 39, 102, -23, 28, 88, -4, 17, 75, 15, 7, 61, + 34, -3, 47, 53, -14, 34, 72, -25, 21, 91, -36, 7, + -39, 37, 106, -20, 27, 93, -1, 16, 79, 18, 5, 66, + 37, -5, 52, 56, -15, 38, 75, -26, 25, 94, -37, 11, + -37, 36, 110, -18, 25, 97, 1, 14, 83, 20, 4, 70, + 39, -6, 56, 58, -17, 42, 77, -27, 29, 96, -38, 15, + -34, 34, 114, -16, 24, 101, 4, 13, 87, 22, 2, 74, + 42, -8, 60, 61, -18, 46, 79, -29, 33, 99, -40, 19, + -110, 82, -13, -91, 71, -26, -72, 60, -40, -53, 50, -54, + -33, 39, -67, -15, 28, -81, 4, 18, -94, 24, 7, -108, + -107, 81, -9, -89, 70, -22, -69, 59, -36, -50, 49, -50, + -31, 38, -63, -12, 27, -77, 7, 16, -90, 26, 5, -104, + -105, 79, -5, -86, 69, -18, -67, 58, -32, -48, 47, -46, + -29, 36, -59, -10, 26, -73, 9, 15, -86, 28, 4, -100, + -102, 78, 0, -83, 67, -14, -64, 56, -28, -45, 46, -41, + -26, 35, -55, -7, 24, -68, 12, 14, -82, 31, 3, -95, + -100, 76, 3, -81, 66, -10, -62, 55, -24, -43, 44, -37, + -24, 33, -51, -5, 23, -64, 14, 12, -78, 33, 1, -91, + -97, 75, 7, -79, 64, -6, -59, 54, -20, -40, 43, -33, + -21, 32, -47, -2, 21, -60, 16, 11, -74, 36, 0, -87, + -95, 74, 11, -76, 63, -2, -57, 52, -16, -38, 42, -29, + -19, 31, -43, 0, 20, -56, 19, 9, -70, 38, 0, -83, + -92, 72, 15, -74, 62, 2, -54, 51, -11, -35, 40, -25, + -16, 29, -38, 3, 19, -52, 22, 8, -65, 41, -2, -79, + -90, 71, 19, -71, 60, 6, -52, 49, -7, -33, 39, -21, + -14, 28, -34, 5, 17, -48, 24, 7, -61, 43, -3, -75, + -88, 70, 23, -69, 59, 10, -49, 48, -3, -31, 37, -17, + -11, 26, -30, 8, 16, -44, 26, 5, -57, 46, -5, -71, + -85, 68, 27, -66, 58, 14, -47, 47, 0, -28, 36, -13, + -9, 25, -26, 10, 14, -40, 29, 4, -53, 48, -6, -67, + -83, 67, 31, -64, 56, 18, -45, 45, 4, -26, 35, -9, + -6, 24, -22, 12, 13, -36, 31, 3, -49, 50, -7, -63, + -80, 65, 36, -61, 55, 22, -42, 44, 8, -23, 33, -4, + -4, 22, -18, 15, 12, -31, 34, 1, -45, 53, -9, -58, + -78, 64, 40, -59, 53, 26, -40, 42, 12, -21, 32, 0, + -1, 21, -14, 17, 10, -27, 36, 0, -41, 56, -10, -54, + -75, 63, 44, -57, 52, 30, -37, 41, 16, -18, 30, 3, + 1, 20, -10, 20, 9, -23, 39, -1, -37, 58, -12, -50, + -73, 61, 48, -54, 51, 34, -35, 40, 20, -16, 29, 7, + 3, 18, -6, 22, 8, -19, 41, -2, -33, 60, -13, -46, + -70, 60, 52, -51, 49, 39, -32, 38, 25, -13, 28, 11, + 6, 17, -1, 25, 6, -15, 44, -4, -28, 63, -14, -42, + -68, 58, 56, -49, 48, 43, -30, 37, 29, -11, 26, 15, + 8, 15, 2, 27, 5, -11, 46, -5, -24, 65, -16, -38, + -65, 57, 60, -47, 46, 47, -27, 35, 33, -8, 25, 19, + 11, 14, 6, 30, 3, -7, 48, -6, -20, 68, -17, -34, + -63, 56, 64, -44, 45, 51, -25, 34, 37, -6, 24, 23, + 13, 13, 10, 32, 2, -3, 51, -8, -16, 70, -19, -30, + -60, 54, 69, -42, 44, 55, -22, 33, 41, -3, 22, 28, + 16, 11, 14, 35, 0, 1, 54, -9, -12, 73, -20, -25, + -58, 53, 73, -39, 42, 59, -20, 31, 45, -1, 21, 32, + 18, 10, 18, 37, 0, 5, 56, -10, -8, 75, -21, -21, + -56, 51, 77, -37, 41, 63, -17, 30, 49, 1, 19, 36, + 21, 8, 22, 40, -1, 9, 58, -12, -4, 78, -23, -17, + -53, 50, 81, -34, 40, 67, -15, 29, 53, 4, 18, 40, + 23, 7, 26, 42, -3, 13, 61, -13, 0, 80, -24, -13, + -51, 49, 85, -32, 38, 71, -13, 27, 57, 6, 17, 44, + 26, 6, 30, 44, -4, 17, 63, -15, 3, 82, -25, -9, + -48, 47, 89, -29, 37, 76, -10, 26, 62, 9, 15, 48, + 28, 4, 35, 47, -5, 21, 66, -16, 8, 85, -27, -5, + -46, 46, 93, -27, 35, 80, -8, 24, 66, 11, 14, 52, + 31, 3, 39, 49, -7, 25, 68, -17, 12, 88, -28, -1, + -43, 45, 97, -25, 34, 84, -5, 23, 70, 14, 12, 56, + 33, 1, 43, 52, -8, 29, 71, -19, 16, 90, -30, 2, + -41, 43, 101, -22, 33, 88, -3, 22, 74, 16, 11, 60, + 35, 0, 47, 54, -9, 33, 73, -20, 20, 92, -31, 6, + -38, 42, 106, -19, 31, 92, 0, 20, 78, 19, 10, 65, + 38, 0, 51, 57, -11, 38, 76, -22, 24, 95, -33, 11, + -36, 40, 110, -17, 30, 96, 2, 19, 82, 21, 8, 69, + 40, -2, 55, 59, -12, 42, 78, -23, 28, 97, -34, 15, + -33, 39, 114, -15, 28, 100, 5, 17, 86, 23, 7, 73, + 43, -3, 59, 62, -14, 46, 80, -24, 32, 100, -35, 19, + -109, 86, -14, -90, 75, -27, -71, 64, -41, -52, 54, -54, + -32, 43, -68, -14, 32, -81, 5, 22, -95, 24, 11, -109, + -106, 85, -10, -88, 74, -23, -68, 63, -37, -49, 53, -50, + -30, 42, -64, -11, 31, -77, 7, 20, -91, 27, 9, -105, + -104, 83, -6, -85, 73, -19, -66, 62, -33, -47, 51, -46, + -28, 40, -60, -9, 30, -73, 10, 19, -87, 29, 8, -101, + -101, 82, -1, -83, 71, -14, -63, 60, -28, -44, 50, -42, + -25, 39, -55, -6, 28, -69, 13, 18, -82, 32, 7, -96, + -99, 80, 2, -80, 70, -10, -61, 59, -24, -42, 48, -38, + -23, 37, -51, -4, 27, -65, 15, 16, -78, 34, 5, -92, + -97, 79, 6, -78, 68, -6, -58, 58, -20, -40, 47, -34, + -20, 36, -47, -1, 25, -61, 17, 15, -74, 37, 4, -88, + -94, 78, 10, -75, 67, -2, -56, 56, -16, -37, 46, -30, + -18, 35, -43, 1, 24, -57, 20, 13, -70, 39, 3, -84, + -91, 76, 14, -73, 66, 1, -53, 55, -12, -34, 44, -25, + -15, 33, -39, 4, 23, -52, 22, 12, -66, 42, 1, -80, + -89, 75, 18, -70, 64, 5, -51, 53, -8, -32, 43, -21, + -13, 32, -35, 6, 21, -48, 25, 11, -62, 44, 0, -76, + -87, 74, 22, -68, 63, 9, -48, 52, -4, -30, 41, -17, + -10, 30, -31, 8, 20, -44, 27, 9, -58, 47, -1, -72, + -84, 72, 26, -65, 62, 13, -46, 51, 0, -27, 40, -13, + -8, 29, -27, 11, 18, -40, 30, 8, -54, 49, -2, -68, + -82, 71, 30, -63, 60, 17, -44, 49, 3, -25, 39, -9, + -6, 28, -23, 13, 17, -36, 32, 7, -50, 51, -3, -64, + -79, 69, 35, -60, 59, 22, -41, 48, 8, -22, 37, -5, + -3, 26, -18, 16, 16, -32, 35, 5, -45, 54, -5, -59, + -77, 68, 39, -58, 57, 26, -39, 46, 12, -20, 36, -1, + 0, 25, -14, 18, 14, -28, 37, 4, -41, 56, -6, -55, + -74, 67, 43, -56, 56, 30, -36, 45, 16, -17, 34, 2, + 2, 24, -10, 21, 13, -24, 39, 2, -37, 59, -8, -51, + -72, 65, 47, -53, 55, 34, -34, 44, 20, -15, 33, 6, + 4, 22, -6, 23, 12, -20, 42, 1, -33, 61, -9, -47, + -69, 64, 51, -51, 53, 38, -31, 42, 24, -12, 32, 11, + 7, 21, -2, 26, 10, -15, 45, 0, -29, 64, -10, -43, + -67, 62, 55, -48, 52, 42, -29, 41, 28, -10, 30, 15, + 9, 19, 1, 28, 9, -11, 47, -1, -25, 66, -12, -39, + -65, 61, 59, -46, 50, 46, -26, 39, 32, -8, 29, 19, + 12, 18, 5, 31, 7, -7, 49, -2, -21, 69, -13, -35, + -62, 60, 63, -43, 49, 50, -24, 38, 36, -5, 28, 23, + 14, 17, 9, 33, 6, -3, 52, -4, -17, 71, -15, -31, + -59, 58, 68, -41, 48, 55, -21, 37, 41, -3, 26, 27, + 17, 15, 14, 36, 4, 0, 54, -5, -12, 74, -16, -26, + -57, 57, 72, -38, 46, 59, -19, 35, 45, 0, 25, 31, + 19, 14, 18, 38, 3, 4, 57, -6, -8, 76, -17, -22, + -55, 55, 76, -36, 45, 63, -17, 34, 49, 2, 23, 35, + 22, 12, 22, 40, 2, 8, 59, -8, -4, 79, -19, -18, + -52, 54, 80, -33, 44, 67, -14, 33, 53, 5, 22, 39, + 24, 11, 26, 43, 0, 12, 62, -9, 0, 81, -20, -14, + -50, 53, 84, -31, 42, 71, -12, 31, 57, 7, 21, 43, + 26, 10, 30, 45, 0, 16, 64, -11, 3, 83, -21, -10, + -47, 51, 88, -28, 41, 75, -9, 30, 61, 10, 19, 48, + 29, 8, 34, 48, -1, 21, 67, -12, 7, 86, -23, -6, + -45, 50, 92, -26, 39, 79, -7, 28, 65, 12, 18, 52, + 32, 7, 38, 50, -3, 25, 69, -13, 11, 88, -24, -2, + -42, 49, 96, -24, 38, 83, -4, 27, 69, 15, 16, 56, + 34, 5, 42, 53, -4, 29, 71, -15, 15, 91, -26, 1, + -40, 47, 100, -21, 37, 87, -2, 26, 73, 17, 15, 60, + 36, 4, 46, 55, -5, 33, 74, -16, 19, 93, -27, 5, + -37, 46, 105, -19, 35, 92, 1, 24, 78, 20, 14, 64, + 39, 3, 51, 58, -7, 37, 77, -18, 24, 96, -29, 10, + -35, 44, 109, -16, 34, 96, 3, 23, 82, 22, 12, 68, + 41, 1, 55, 60, -8, 41, 79, -19, 28, 98, -30, 14, + -33, 43, 113, -14, 32, 100, 6, 21, 86, 24, 11, 72, + 44, 0, 59, 63, -10, 45, 81, -20, 32, 101, -31, 18, + -108, 90, -14, -89, 79, -28, -70, 68, -41, -51, 58, -55, + -32, 47, -69, -13, 36, -82, 6, 26, -95, 25, 15, -109, + -105, 89, -10, -87, 78, -24, -67, 67, -37, -49, 57, -51, + -29, 46, -65, -10, 35, -78, 8, 24, -91, 28, 13, -105, + -103, 87, -6, -84, 77, -20, -65, 66, -33, -46, 55, -47, + -27, 44, -61, -8, 34, -74, 11, 23, -87, 30, 12, -101, + -100, 86, -2, -82, 75, -15, -62, 64, -29, -43, 54, -42, + -24, 43, -56, -5, 32, -70, 13, 22, -83, 33, 11, -97, + -98, 84, 1, -79, 74, -11, -60, 63, -25, -41, 52, -38, + -22, 41, -52, -3, 31, -66, 16, 20, -79, 35, 9, -93, + -96, 83, 5, -77, 72, -7, -57, 62, -21, -39, 51, -34, + -19, 40, -48, -1, 29, -62, 18, 19, -75, 38, 8, -89, + -93, 82, 9, -74, 71, -3, -55, 60, -17, -36, 50, -30, + -17, 39, -44, 2, 28, -58, 21, 17, -71, 40, 7, -85, + -91, 80, 14, -72, 70, 0, -52, 59, -12, -34, 48, -26, + -14, 37, -40, 5, 27, -53, 23, 16, -66, 43, 5, -80, + -88, 79, 18, -69, 68, 4, -50, 57, -8, -31, 47, -22, + -12, 36, -36, 7, 25, -49, 26, 15, -62, 45, 4, -76, + -86, 78, 22, -67, 67, 8, -48, 56, -4, -29, 45, -18, + -9, 34, -32, 9, 24, -45, 28, 13, -58, 48, 2, -72, + -83, 76, 26, -65, 66, 12, -45, 55, 0, -26, 44, -14, + -7, 33, -28, 12, 22, -41, 31, 12, -54, 50, 1, -68, + -81, 75, 30, -62, 64, 16, -43, 53, 3, -24, 43, -10, + -5, 32, -24, 14, 21, -37, 33, 11, -50, 52, 0, -64, + -78, 73, 34, -59, 63, 21, -40, 52, 7, -21, 41, -5, + -2, 30, -19, 17, 20, -33, 36, 9, -46, 55, -1, -60, + -76, 72, 38, -57, 61, 25, -38, 50, 11, -19, 40, -1, + 0, 29, -15, 19, 18, -29, 38, 8, -42, 57, -2, -56, + -73, 71, 42, -55, 60, 29, -35, 49, 15, -17, 38, 2, + 3, 28, -11, 22, 17, -25, 40, 6, -38, 60, -4, -52, + -71, 69, 46, -52, 59, 33, -33, 48, 19, -14, 37, 6, + 5, 26, -7, 24, 16, -21, 43, 5, -34, 62, -5, -48, + -68, 68, 51, -50, 57, 37, -30, 46, 24, -11, 36, 10, + 8, 25, -3, 27, 14, -16, 45, 3, -29, 65, -6, -43, + -66, 66, 55, -47, 56, 41, -28, 45, 28, -9, 34, 14, + 10, 23, 0, 29, 13, -12, 48, 2, -25, 67, -8, -39, + -64, 65, 59, -45, 54, 45, -25, 43, 32, -7, 33, 18, + 13, 22, 4, 31, 11, -8, 50, 1, -21, 70, -9, -35, + -61, 64, 63, -42, 53, 49, -23, 42, 36, -4, 32, 22, + 15, 21, 8, 34, 10, -4, 53, 0, -17, 72, -11, -31, + -59, 62, 67, -40, 52, 54, -20, 41, 40, -2, 30, 27, + 18, 19, 13, 37, 8, 0, 55, -1, -13, 75, -12, -27, + -56, 61, 71, -37, 50, 58, -18, 39, 44, 1, 29, 31, + 20, 18, 17, 39, 7, 3, 58, -2, -9, 77, -13, -23, + -54, 59, 75, -35, 49, 62, -16, 38, 48, 3, 27, 35, + 23, 16, 21, 41, 6, 7, 60, -4, -5, 80, -15, -19, + -51, 58, 79, -33, 48, 66, -13, 37, 52, 6, 26, 39, + 25, 15, 25, 44, 4, 11, 63, -5, -1, 82, -16, -15, + -49, 57, 83, -30, 46, 70, -11, 35, 56, 8, 25, 43, + 27, 14, 29, 46, 3, 15, 65, -7, 2, 84, -17, -11, + -46, 55, 88, -27, 45, 74, -8, 34, 61, 11, 23, 47, + 30, 12, 33, 49, 2, 20, 68, -8, 7, 87, -19, -6, + -44, 54, 92, -25, 43, 78, -6, 32, 65, 13, 22, 51, + 32, 11, 37, 51, 0, 24, 70, -9, 11, 89, -20, -2, + -41, 53, 96, -23, 42, 82, -3, 31, 69, 15, 20, 55, + 35, 9, 41, 54, 0, 28, 72, -11, 15, 92, -22, 1, + -39, 51, 100, -20, 41, 86, -1, 30, 73, 18, 19, 59, + 37, 8, 45, 56, -1, 32, 75, -12, 19, 94, -23, 5, + -36, 50, 104, -18, 39, 91, 2, 28, 77, 21, 18, 64, + 40, 7, 50, 59, -3, 36, 77, -14, 23, 97, -25, 9, + -34, 48, 108, -15, 38, 95, 4, 27, 81, 23, 16, 68, + 42, 5, 54, 61, -4, 40, 80, -15, 27, 99, -26, 13, + -32, 47, 112, -13, 36, 99, 7, 25, 85, 25, 15, 72, + 45, 4, 58, 63, -6, 44, 82, -16, 31, 102, -27, 17, + -107, 94, -15, -88, 83, -28, -69, 72, -42, -50, 62, -55, + -31, 51, -69, -12, 40, -83, 7, 30, -96, 26, 19, -110, + -105, 93, -11, -86, 82, -24, -66, 71, -38, -48, 61, -51, + -28, 50, -65, -9, 39, -79, 9, 28, -92, 29, 17, -106, + -102, 91, -7, -83, 81, -20, -64, 70, -34, -45, 59, -47, + -26, 48, -61, -7, 38, -75, 12, 27, -88, 31, 16, -102, + -99, 90, -2, -81, 79, -16, -61, 68, -30, -43, 58, -43, + -23, 47, -57, -4, 36, -70, 14, 26, -84, 34, 15, -97, + -97, 88, 1, -78, 78, -12, -59, 67, -26, -40, 56, -39, + -21, 45, -53, -2, 35, -66, 17, 24, -80, 36, 13, -93, + -95, 87, 5, -76, 76, -8, -57, 66, -22, -38, 55, -35, + -18, 44, -49, 0, 33, -62, 19, 23, -76, 39, 12, -89, + -92, 86, 9, -74, 75, -4, -54, 64, -18, -35, 54, -31, + -16, 43, -45, 3, 32, -58, 22, 21, -72, 41, 11, -85, + -90, 84, 13, -71, 74, 0, -51, 63, -13, -33, 52, -26, + -13, 41, -40, 5, 31, -54, 24, 20, -67, 44, 9, -81, + -87, 83, 17, -68, 72, 4, -49, 61, -9, -30, 51, -22, + -11, 40, -36, 8, 29, -50, 27, 19, -63, 46, 8, -77, + -85, 82, 21, -66, 71, 8, -47, 60, -5, -28, 49, -18, + -9, 38, -32, 10, 28, -46, 29, 17, -59, 48, 6, -73, + -82, 80, 25, -64, 70, 12, -44, 59, -1, -25, 48, -14, + -6, 37, -28, 13, 26, -42, 31, 16, -55, 51, 5, -69, + -80, 79, 29, -61, 68, 16, -42, 57, 2, -23, 47, -10, + -4, 36, -24, 15, 25, -38, 34, 15, -51, 53, 4, -65, + -77, 77, 34, -59, 67, 20, -39, 56, 6, -20, 45, -6, + -1, 34, -20, 18, 24, -33, 37, 13, -47, 56, 2, -60, + -75, 76, 38, -56, 65, 24, -37, 54, 10, -18, 44, -2, + 1, 33, -16, 20, 22, -29, 39, 12, -43, 58, 1, -56, + -73, 75, 42, -54, 64, 28, -34, 53, 14, -16, 42, 1, + 4, 32, -12, 23, 21, -25, 41, 10, -39, 61, 0, -52, + -70, 73, 46, -51, 63, 32, -32, 52, 18, -13, 41, 5, + 6, 30, -8, 25, 20, -21, 44, 9, -35, 63, -1, -48, + -67, 72, 50, -49, 61, 37, -29, 50, 23, -11, 40, 10, + 9, 29, -3, 28, 18, -17, 46, 7, -30, 66, -2, -44, + -65, 70, 54, -46, 60, 41, -27, 49, 27, -8, 38, 14, + 11, 27, 0, 30, 17, -13, 49, 6, -26, 68, -4, -40, + -63, 69, 58, -44, 58, 45, -25, 47, 31, -6, 37, 18, + 14, 26, 4, 32, 15, -9, 51, 5, -22, 71, -5, -36, + -60, 68, 62, -42, 57, 49, -22, 46, 35, -3, 36, 22, + 16, 25, 8, 35, 14, -5, 54, 3, -18, 73, -7, -32, + -58, 66, 67, -39, 56, 53, -19, 45, 39, -1, 34, 26, + 19, 23, 12, 37, 12, 0, 56, 2, -14, 76, -8, -27, + -55, 65, 71, -36, 54, 57, -17, 43, 43, 2, 33, 30, + 21, 22, 16, 40, 11, 3, 59, 1, -10, 78, -9, -23, + -53, 63, 75, -34, 53, 61, -15, 42, 47, 4, 31, 34, + 23, 20, 20, 42, 10, 7, 61, 0, -6, 80, -11, -19, + -50, 62, 79, -32, 52, 65, -12, 41, 51, 6, 30, 38, + 26, 19, 24, 45, 8, 11, 63, -1, -2, 83, -12, -15, + -48, 61, 83, -29, 50, 69, -10, 39, 55, 9, 29, 42, + 28, 18, 28, 47, 7, 15, 66, -3, 1, 85, -13, -11, + -45, 59, 87, -27, 49, 74, -7, 38, 60, 12, 27, 47, + 31, 16, 33, 50, 6, 19, 69, -4, 6, 88, -15, -7, + -43, 58, 91, -24, 47, 78, -5, 36, 64, 14, 26, 51, + 33, 15, 37, 52, 4, 23, 71, -5, 10, 90, -16, -3, + -41, 57, 95, -22, 46, 82, -2, 35, 68, 16, 24, 55, + 36, 13, 41, 55, 3, 27, 73, -7, 14, 93, -18, 0, + -38, 55, 99, -19, 45, 86, 0, 34, 72, 19, 23, 59, + 38, 12, 45, 57, 2, 31, 76, -8, 18, 95, -19, 4, + -35, 54, 104, -17, 43, 90, 3, 32, 76, 21, 22, 63, + 41, 11, 49, 60, 0, 36, 78, -10, 22, 98, -21, 9, + -33, 52, 108, -14, 42, 94, 5, 31, 80, 24, 20, 67, + 43, 9, 53, 62, 0, 40, 81, -11, 26, 100, -22, 13, + -31, 51, 112, -12, 40, 98, 7, 29, 84, 26, 19, 71, + 46, 8, 57, 64, -2, 44, 83, -12, 30, 103, -23, 17, + -106, 98, -16, -87, 87, -29, -68, 76, -43, -49, 66, -56, + -30, 55, -70, -11, 44, -83, 8, 34, -97, 27, 23, -111, + -104, 97, -12, -85, 86, -25, -65, 75, -39, -47, 65, -52, + -27, 54, -66, -9, 43, -79, 10, 32, -93, 30, 21, -107, + -101, 95, -8, -82, 85, -21, -63, 74, -35, -44, 63, -48, + -25, 52, -62, -6, 42, -75, 13, 31, -89, 32, 20, -103, + -99, 94, -3, -80, 83, -16, -60, 72, -30, -42, 62, -44, + -22, 51, -57, -3, 40, -71, 15, 30, -84, 35, 19, -98, + -96, 92, 0, -77, 82, -12, -58, 71, -26, -39, 60, -40, + -20, 49, -53, -1, 39, -67, 18, 28, -80, 37, 17, -94, + -94, 91, 4, -75, 80, -8, -56, 70, -22, -37, 59, -36, + -17, 48, -49, 1, 37, -63, 20, 27, -76, 39, 16, -90, + -91, 90, 8, -73, 79, -4, -53, 68, -18, -34, 58, -32, + -15, 47, -45, 4, 36, -59, 22, 25, -72, 42, 15, -86, + -89, 88, 12, -70, 78, 0, -51, 67, -14, -32, 56, -27, + -12, 45, -41, 6, 35, -54, 25, 24, -68, 45, 13, -82, + -86, 87, 16, -68, 76, 3, -48, 65, -10, -29, 55, -23, + -10, 44, -37, 9, 33, -50, 28, 23, -64, 47, 12, -78, + -84, 86, 20, -65, 75, 7, -46, 64, -6, -27, 53, -19, + -8, 42, -33, 11, 32, -46, 30, 21, -60, 49, 10, -74, + -82, 84, 24, -63, 74, 11, -43, 63, -2, -25, 52, -15, + -5, 41, -29, 14, 30, -42, 32, 20, -56, 52, 9, -70, + -79, 83, 28, -60, 72, 15, -41, 61, 1, -22, 51, -11, + -3, 40, -25, 16, 29, -38, 35, 19, -52, 54, 8, -66, + -76, 81, 33, -58, 71, 20, -38, 60, 6, -20, 49, -7, + 0, 38, -20, 19, 28, -34, 37, 17, -47, 57, 6, -61, + -74, 80, 37, -55, 69, 24, -36, 58, 10, -17, 48, -3, + 2, 37, -16, 21, 26, -30, 40, 16, -43, 59, 5, -57, + -72, 79, 41, -53, 68, 28, -34, 57, 14, -15, 46, 0, + 5, 36, -12, 23, 25, -26, 42, 14, -39, 62, 3, -53, + -69, 77, 45, -50, 67, 32, -31, 56, 18, -12, 45, 4, + 7, 34, -8, 26, 24, -22, 45, 13, -35, 64, 2, -49, + -67, 76, 49, -48, 65, 36, -28, 54, 22, -10, 44, 9, + 10, 33, -4, 29, 22, -17, 47, 11, -31, 67, 1, -45, + -64, 74, 53, -45, 64, 40, -26, 53, 26, -7, 42, 13, + 12, 31, 0, 31, 21, -13, 50, 10, -27, 69, 0, -41, + -62, 73, 57, -43, 62, 44, -24, 51, 30, -5, 41, 17, + 15, 30, 3, 33, 19, -9, 52, 9, -23, 71, -1, -37, + -59, 72, 61, -41, 61, 48, -21, 50, 34, -2, 40, 21, + 17, 29, 7, 36, 18, -5, 54, 7, -19, 74, -3, -33, + -57, 70, 66, -38, 60, 53, -19, 49, 39, 0, 38, 25, + 20, 27, 12, 38, 16, -1, 57, 6, -14, 77, -4, -28, + -54, 69, 70, -36, 58, 57, -16, 47, 43, 3, 37, 29, + 22, 26, 16, 41, 15, 2, 60, 5, -10, 79, -5, -24, + -52, 67, 74, -33, 57, 61, -14, 46, 47, 5, 35, 33, + 24, 24, 20, 43, 14, 6, 62, 3, -6, 81, -7, -20, + -50, 66, 78, -31, 56, 65, -11, 45, 51, 7, 34, 37, + 27, 23, 24, 46, 12, 10, 64, 2, -2, 84, -8, -16, + -47, 65, 82, -28, 54, 69, -9, 43, 55, 10, 33, 41, + 29, 22, 28, 48, 11, 14, 67, 0, 1, 86, -9, -12, + -44, 63, 86, -26, 53, 73, -6, 42, 59, 12, 31, 46, + 32, 20, 32, 51, 10, 19, 69, 0, 5, 89, -11, -8, + -42, 62, 90, -23, 51, 77, -4, 40, 63, 15, 30, 50, + 34, 19, 36, 53, 8, 23, 72, -1, 9, 91, -12, -4, + -40, 61, 94, -21, 50, 81, -2, 39, 67, 17, 28, 54, + 37, 17, 40, 55, 7, 27, 74, -3, 13, 94, -14, 0, + -37, 59, 98, -18, 49, 85, 1, 38, 71, 20, 27, 58, + 39, 16, 44, 58, 6, 31, 77, -4, 17, 96, -15, 3, + -35, 58, 103, -16, 47, 90, 4, 36, 76, 22, 26, 62, + 42, 15, 49, 61, 4, 35, 79, -6, 22, 99, -17, 8, + -32, 56, 107, -13, 46, 94, 6, 35, 80, 25, 24, 66, + 44, 13, 53, 63, 3, 39, 82, -7, 26, 101, -18, 12, + -30, 55, 111, -11, 44, 98, 8, 33, 84, 27, 23, 70, + 47, 12, 57, 65, 1, 43, 84, -8, 30, 103, -19, 16, + -105, 103, -16, -86, 92, -30, -67, 81, -43, -48, 70, -57, + -29, 59, -71, -10, 49, -84, 9, 38, -97, 28, 27, -111, + -103, 101, -12, -84, 91, -26, -64, 80, -39, -46, 69, -53, + -26, 58, -67, -8, 47, -80, 11, 37, -93, 31, 26, -107, + -100, 100, -8, -81, 89, -22, -62, 78, -35, -43, 68, -49, + -24, 57, -63, -5, 46, -76, 14, 36, -89, 33, 25, -103, + -98, 98, -4, -79, 88, -17, -59, 77, -31, -41, 66, -44, + -21, 55, -58, -2, 45, -72, 16, 34, -85, 36, 23, -99, + -95, 97, 0, -76, 86, -13, -57, 75, -27, -38, 65, -40, + -19, 54, -54, 0, 43, -68, 19, 33, -81, 38, 22, -95, + -93, 96, 3, -74, 85, -9, -55, 74, -23, -36, 63, -36, + -16, 53, -50, 2, 42, -64, 21, 31, -77, 40, 20, -91, + -90, 94, 7, -72, 84, -5, -52, 73, -19, -33, 62, -32, + -14, 51, -46, 5, 41, -60, 24, 30, -73, 43, 19, -87, + -88, 93, 12, -69, 82, -1, -50, 71, -14, -31, 61, -28, + -11, 50, -42, 7, 39, -55, 26, 28, -68, 46, 18, -82, + -85, 91, 16, -66, 81, 2, -47, 70, -10, -28, 59, -24, + -9, 48, -38, 10, 38, -51, 29, 27, -64, 48, 16, -78, + -83, 90, 20, -64, 79, 6, -45, 68, -6, -26, 58, -20, + -7, 47, -34, 12, 36, -47, 31, 26, -60, 50, 15, -74, + -80, 89, 24, -62, 78, 10, -42, 67, -2, -24, 57, -16, + -4, 46, -30, 15, 35, -43, 33, 24, -56, 53, 13, -70, + -78, 87, 28, -59, 77, 14, -40, 66, 1, -21, 55, -12, + -2, 44, -26, 17, 34, -39, 36, 23, -52, 55, 12, -66, + -75, 86, 32, -57, 75, 19, -37, 64, 5, -18, 54, -7, + 1, 43, -21, 20, 32, -35, 38, 22, -48, 58, 11, -62, + -73, 84, 36, -54, 74, 23, -35, 63, 9, -16, 52, -3, + 3, 41, -17, 22, 31, -31, 41, 20, -44, 60, 9, -58, + -71, 83, 40, -52, 72, 27, -32, 62, 13, -14, 51, 0, + 6, 40, -13, 24, 29, -27, 43, 19, -40, 63, 8, -54, + -68, 82, 44, -49, 71, 31, -30, 60, 17, -11, 50, 4, + 8, 39, -9, 27, 28, -23, 46, 17, -36, 65, 7, -50, + -66, 80, 49, -47, 70, 35, -27, 59, 22, -9, 48, 8, + 11, 37, -5, 30, 27, -18, 48, 16, -31, 68, 5, -45, + -63, 79, 53, -44, 68, 39, -25, 57, 26, -6, 47, 12, + 13, 36, -1, 32, 25, -14, 51, 15, -27, 70, 4, -41, + -61, 78, 57, -42, 67, 43, -23, 56, 30, -4, 45, 16, + 16, 34, 2, 34, 24, -10, 53, 13, -23, 72, 2, -37, + -58, 76, 61, -40, 66, 47, -20, 55, 34, -1, 44, 20, + 18, 33, 6, 37, 23, -6, 56, 12, -19, 75, 1, -33, + -56, 75, 65, -37, 64, 52, -18, 53, 38, 1, 43, 25, + 21, 32, 11, 39, 21, -2, 58, 10, -15, 78, 0, -29, + -53, 73, 69, -35, 63, 56, -15, 52, 42, 4, 41, 29, + 23, 30, 15, 42, 20, 1, 61, 9, -11, 80, -1, -25, + -51, 72, 73, -32, 61, 60, -13, 50, 46, 6, 40, 33, + 25, 29, 19, 44, 18, 5, 63, 8, -7, 82, -2, -21, + -49, 71, 77, -30, 60, 64, -10, 49, 50, 8, 38, 37, + 28, 28, 23, 47, 17, 9, 65, 6, -3, 85, -4, -17, + -46, 69, 81, -27, 59, 68, -8, 48, 54, 11, 37, 41, + 30, 26, 27, 49, 16, 13, 68, 5, 0, 87, -5, -13, + -43, 68, 86, -25, 57, 72, -5, 46, 59, 14, 36, 45, + 33, 25, 31, 52, 14, 18, 70, 3, 5, 90, -6, -8, + -41, 66, 90, -22, 56, 76, -3, 45, 63, 16, 34, 49, + 35, 23, 35, 54, 13, 22, 73, 2, 9, 92, -8, -4, + -39, 65, 94, -20, 54, 80, 0, 44, 67, 18, 33, 53, + 38, 22, 39, 56, 11, 26, 75, 1, 13, 95, -9, 0, + -36, 64, 98, -17, 53, 84, 2, 42, 71, 21, 32, 57, + 40, 21, 43, 59, 10, 30, 78, 0, 17, 97, -11, 3, + -34, 62, 102, -15, 52, 89, 5, 41, 75, 23, 30, 62, + 43, 19, 48, 62, 9, 34, 80, -1, 21, 100, -12, 7, + -31, 61, 106, -12, 50, 93, 7, 39, 79, 26, 29, 66, + 45, 18, 52, 64, 7, 38, 83, -2, 25, 102, -13, 11, + -29, 59, 110, -10, 49, 97, 9, 38, 83, 28, 27, 70, + 48, 16, 56, 66, 6, 42, 85, -4, 29, 104, -15, 15, + -104, 107, -17, -85, 96, -30, -66, 85, -44, -47, 74, -58, + -28, 63, -71, -9, 53, -85, 10, 42, -98, 29, 31, -112, + -102, 105, -13, -83, 95, -26, -64, 84, -40, -45, 73, -54, + -25, 62, -67, -7, 51, -81, 12, 41, -94, 32, 30, -108, + -99, 104, -9, -81, 93, -22, -61, 82, -36, -42, 72, -50, + -23, 61, -63, -4, 50, -77, 15, 40, -90, 34, 29, -104, + -97, 102, -4, -78, 92, -18, -58, 81, -32, -40, 70, -45, + -20, 59, -59, -2, 49, -72, 17, 38, -86, 37, 27, -99, + -94, 101, 0, -75, 90, -14, -56, 79, -28, -37, 69, -41, + -18, 58, -55, 1, 47, -68, 20, 37, -82, 39, 26, -95, + -92, 100, 3, -73, 89, -10, -54, 78, -24, -35, 67, -37, + -16, 57, -51, 3, 46, -64, 22, 35, -78, 41, 24, -91, + -89, 98, 7, -71, 88, -6, -51, 77, -20, -33, 66, -33, + -13, 55, -47, 6, 45, -60, 24, 34, -74, 44, 23, -87, + -87, 97, 11, -68, 86, -1, -49, 75, -15, -30, 65, -29, + -10, 54, -42, 8, 43, -56, 27, 32, -69, 46, 22, -83, + -84, 95, 15, -66, 85, 2, -46, 74, -11, -27, 63, -25, + -8, 52, -38, 11, 42, -52, 30, 31, -65, 49, 20, -79, + -82, 94, 19, -63, 83, 6, -44, 72, -7, -25, 62, -21, + -6, 51, -34, 13, 40, -48, 32, 30, -61, 51, 19, -75, + -80, 93, 23, -61, 82, 10, -41, 71, -3, -23, 61, -17, + -3, 50, -30, 16, 39, -44, 34, 28, -57, 54, 17, -71, + -77, 91, 27, -58, 81, 14, -39, 70, 0, -20, 59, -13, + -1, 48, -26, 18, 38, -40, 37, 27, -53, 56, 16, -67, + -75, 90, 32, -56, 79, 18, -36, 68, 4, -18, 58, -8, + 2, 47, -22, 21, 36, -35, 39, 26, -49, 59, 15, -62, + -72, 88, 36, -53, 78, 22, -34, 67, 8, -15, 56, -4, + 4, 45, -18, 23, 35, -31, 42, 24, -45, 61, 13, -58, + -70, 87, 40, -51, 76, 26, -32, 66, 12, -13, 55, 0, + 7, 44, -14, 25, 33, -27, 44, 23, -41, 64, 12, -54, + -67, 86, 44, -49, 75, 30, -29, 64, 16, -10, 54, 3, + 9, 43, -10, 28, 32, -23, 47, 21, -37, 66, 11, -50, + -65, 84, 48, -46, 74, 35, -26, 63, 21, -8, 52, 7, + 12, 41, -5, 30, 31, -19, 49, 20, -32, 69, 9, -46, + -62, 83, 52, -43, 72, 39, -24, 61, 25, -5, 51, 11, + 14, 40, -1, 33, 29, -15, 52, 19, -28, 71, 8, -42, + -60, 82, 56, -41, 71, 43, -22, 60, 29, -3, 49, 15, + 16, 38, 2, 35, 28, -11, 54, 17, -24, 73, 6, -38, + -57, 80, 60, -39, 70, 47, -19, 59, 33, -1, 48, 19, + 19, 37, 6, 38, 27, -7, 56, 16, -20, 76, 5, -34, + -55, 79, 65, -36, 68, 51, -17, 57, 37, 2, 47, 24, + 22, 36, 10, 40, 25, -2, 59, 14, -16, 78, 3, -29, + -52, 77, 69, -34, 67, 55, -14, 56, 41, 5, 45, 28, + 24, 34, 14, 43, 24, 1, 62, 13, -12, 81, 2, -25, + -50, 76, 73, -31, 65, 59, -12, 54, 45, 7, 44, 32, + 26, 33, 18, 45, 22, 5, 64, 12, -8, 83, 1, -21, + -48, 75, 77, -29, 64, 63, -9, 53, 49, 9, 42, 36, + 29, 32, 22, 48, 21, 9, 66, 10, -4, 86, 0, -17, + -45, 73, 81, -26, 63, 67, -7, 52, 53, 12, 41, 40, + 31, 30, 26, 50, 20, 13, 69, 9, 0, 88, -1, -13, + -43, 72, 85, -24, 61, 72, -4, 50, 58, 14, 40, 44, + 34, 29, 31, 53, 18, 17, 71, 7, 4, 91, -2, -9, + -40, 70, 89, -21, 60, 76, -2, 49, 62, 17, 38, 48, + 36, 27, 35, 55, 17, 21, 74, 6, 8, 93, -4, -5, + -38, 69, 93, -19, 58, 80, 0, 48, 66, 19, 37, 52, + 39, 26, 39, 57, 15, 25, 76, 5, 12, 96, -5, -1, + -35, 68, 97, -17, 57, 84, 3, 46, 70, 22, 36, 56, + 41, 25, 43, 60, 14, 29, 79, 3, 16, 98, -7, 2, + -33, 66, 102, -14, 56, 88, 6, 45, 74, 24, 34, 61, + 44, 23, 47, 62, 13, 34, 81, 2, 20, 101, -8, 7, + -30, 65, 106, -11, 54, 92, 8, 43, 78, 27, 33, 65, + 46, 22, 51, 65, 11, 38, 84, 1, 24, 103, -9, 11, + -28, 63, 110, -9, 53, 96, 10, 42, 82, 29, 31, 69, + 48, 20, 55, 67, 10, 42, 86, 0, 28, 105, -11, 15, + -103, 111, -18, -84, 100, -31, -65, 89, -45, -46, 78, -58, + -27, 67, -72, -8, 57, -85, 11, 46, -99, 30, 35, -113, + -101, 109, -14, -82, 99, -27, -63, 88, -41, -44, 77, -54, + -24, 66, -68, -6, 55, -81, 13, 45, -95, 32, 34, -109, + -98, 108, -10, -80, 97, -23, -60, 86, -37, -41, 76, -50, + -22, 65, -64, -3, 54, -77, 15, 44, -91, 35, 33, -105, + -96, 106, -5, -77, 96, -18, -58, 85, -32, -39, 74, -46, + -19, 63, -59, -1, 53, -73, 18, 42, -86, 38, 31, -100, + -93, 105, -1, -75, 94, -14, -55, 83, -28, -36, 73, -42, + -17, 62, -55, 2, 51, -69, 21, 41, -82, 40, 30, -96, + -91, 104, 2, -72, 93, -10, -53, 82, -24, -34, 71, -38, + -15, 61, -51, 4, 50, -65, 23, 39, -78, 42, 28, -92, + -89, 102, 6, -70, 92, -6, -50, 81, -20, -32, 70, -34, + -12, 59, -47, 7, 49, -61, 25, 38, -74, 45, 27, -88, + -86, 101, 10, -67, 90, -2, -48, 79, -16, -29, 69, -29, + -10, 58, -43, 9, 47, -56, 28, 36, -70, 47, 26, -84, + -83, 99, 14, -65, 89, 1, -45, 78, -12, -27, 67, -25, + -7, 56, -39, 12, 46, -52, 30, 35, -66, 50, 24, -80, + -81, 98, 18, -62, 87, 5, -43, 76, -8, -24, 66, -21, + -5, 55, -35, 14, 44, -48, 33, 34, -62, 52, 23, -76, + -79, 97, 22, -60, 86, 9, -41, 75, -4, -22, 65, -17, + -2, 54, -31, 16, 43, -44, 35, 32, -58, 55, 21, -72, + -76, 95, 26, -57, 85, 13, -38, 74, 0, -19, 63, -13, + 0, 52, -27, 19, 42, -40, 38, 31, -54, 57, 20, -68, + -74, 94, 31, -55, 83, 18, -35, 72, 4, -17, 62, -9, + 3, 51, -22, 22, 40, -36, 40, 30, -49, 60, 19, -63, + -71, 92, 35, -52, 82, 22, -33, 71, 8, -14, 60, -5, + 5, 49, -18, 24, 39, -32, 43, 28, -45, 62, 17, -59, + -69, 91, 39, -50, 80, 26, -31, 70, 12, -12, 59, -1, + 8, 48, -14, 26, 37, -28, 45, 27, -41, 64, 16, -55, + -66, 90, 43, -48, 79, 30, -28, 68, 16, -9, 58, 2, + 10, 47, -10, 29, 36, -24, 47, 25, -37, 67, 15, -51, + -64, 88, 47, -45, 78, 34, -26, 67, 20, -7, 56, 7, + 13, 45, -6, 31, 35, -19, 50, 24, -33, 70, 13, -47, + -61, 87, 51, -43, 76, 38, -23, 65, 24, -4, 55, 11, + 15, 44, -2, 34, 33, -15, 53, 23, -29, 72, 12, -43, + -59, 86, 55, -40, 75, 42, -21, 64, 28, -2, 53, 15, + 17, 42, 1, 36, 32, -11, 55, 21, -25, 74, 10, -39, + -57, 84, 59, -38, 74, 46, -18, 63, 32, 0, 52, 19, + 20, 41, 5, 39, 31, -7, 57, 20, -21, 77, 9, -35, + -54, 83, 64, -35, 72, 51, -16, 61, 37, 3, 51, 23, + 22, 40, 10, 41, 29, -3, 60, 18, -16, 79, 7, -30, + -51, 81, 68, -33, 71, 55, -13, 60, 41, 5, 49, 27, + 25, 38, 14, 44, 28, 0, 62, 17, -12, 82, 6, -26, + -49, 80, 72, -30, 69, 59, -11, 58, 45, 8, 48, 31, + 27, 37, 18, 46, 26, 4, 65, 16, -8, 84, 5, -22, + -47, 79, 76, -28, 68, 63, -9, 57, 49, 10, 46, 35, + 30, 36, 22, 48, 25, 8, 67, 14, -4, 87, 3, -18, + -44, 77, 80, -26, 67, 67, -6, 56, 53, 13, 45, 39, + 32, 34, 26, 51, 24, 12, 70, 13, 0, 89, 2, -14, + -42, 76, 84, -23, 65, 71, -3, 54, 57, 15, 44, 44, + 35, 33, 30, 53, 22, 17, 72, 11, 3, 92, 1, -10, + -39, 74, 88, -20, 64, 75, -1, 53, 61, 18, 42, 48, + 37, 31, 34, 56, 21, 21, 75, 10, 7, 94, 0, -6, + -37, 73, 92, -18, 62, 79, 1, 52, 65, 20, 41, 52, + 39, 30, 38, 58, 19, 25, 77, 9, 11, 96, -1, -2, + -34, 72, 96, -16, 61, 83, 4, 50, 69, 23, 40, 56, + 42, 29, 42, 61, 18, 29, 79, 7, 15, 99, -3, 1, + -32, 70, 101, -13, 60, 88, 6, 49, 74, 25, 38, 60, + 45, 27, 47, 63, 17, 33, 82, 6, 20, 102, -4, 6, + -29, 69, 105, -11, 58, 92, 9, 47, 78, 28, 37, 64, + 47, 26, 51, 66, 15, 37, 85, 5, 24, 104, -5, 10, + -27, 67, 109, -8, 57, 96, 11, 46, 82, 30, 35, 68, + 49, 24, 55, 68, 14, 41, 87, 3, 28, 106, -7, 14, + -102, 115, -18, -83, 104, -32, -64, 93, -45, -45, 82, -59, + -26, 71, -73, -7, 61, -86, 12, 50, -99, 31, 39, -113, + -100, 113, -14, -81, 103, -28, -62, 92, -41, -43, 81, -55, + -24, 70, -69, -5, 59, -82, 14, 49, -95, 33, 38, -109, + -97, 112, -10, -79, 101, -24, -59, 90, -37, -41, 80, -51, + -21, 69, -65, -2, 58, -78, 16, 48, -91, 36, 37, -105, + -95, 110, -6, -76, 100, -19, -57, 89, -33, -38, 78, -46, + -18, 67, -60, 0, 57, -74, 19, 46, -87, 38, 35, -101, + -92, 109, -2, -74, 98, -15, -54, 87, -29, -35, 77, -42, + -16, 66, -56, 3, 55, -70, 21, 45, -83, 41, 34, -97, + -90, 108, 1, -71, 97, -11, -52, 86, -25, -33, 75, -38, + -14, 65, -52, 5, 54, -66, 24, 43, -79, 43, 32, -93, + -88, 106, 5, -69, 96, -7, -49, 85, -21, -31, 74, -34, + -11, 63, -48, 7, 53, -62, 26, 42, -75, 46, 31, -89, + -85, 105, 10, -66, 94, -3, -47, 83, -16, -28, 73, -30, + -9, 62, -44, 10, 51, -57, 29, 40, -70, 48, 30, -84, + -83, 103, 14, -64, 93, 0, -44, 82, -12, -26, 71, -26, + -6, 60, -40, 13, 50, -53, 31, 39, -66, 51, 28, -80, + -80, 102, 18, -61, 91, 4, -42, 80, -8, -23, 70, -22, + -4, 59, -36, 15, 48, -49, 34, 38, -62, 53, 27, -76, + -78, 101, 22, -59, 90, 8, -40, 79, -4, -21, 69, -18, + -1, 58, -32, 17, 47, -45, 36, 36, -58, 55, 25, -72, + -75, 99, 26, -57, 89, 12, -37, 78, 0, -18, 67, -14, + 1, 56, -28, 20, 46, -41, 39, 35, -54, 58, 24, -68, + -73, 98, 30, -54, 87, 17, -35, 76, 3, -16, 66, -9, + 4, 55, -23, 22, 44, -37, 41, 34, -50, 61, 23, -64, + -70, 96, 34, -52, 86, 21, -32, 75, 7, -13, 64, -5, + 6, 53, -19, 25, 43, -33, 44, 32, -46, 63, 21, -60, + -68, 95, 38, -49, 84, 25, -30, 74, 11, -11, 63, -1, + 8, 52, -15, 27, 41, -29, 46, 31, -42, 65, 20, -56, + -66, 94, 42, -47, 83, 29, -27, 72, 15, -9, 62, 2, + 11, 51, -11, 30, 40, -25, 48, 29, -38, 68, 19, -52, + -63, 92, 47, -44, 82, 33, -25, 71, 20, -6, 60, 6, + 13, 49, -7, 32, 39, -20, 51, 28, -33, 70, 17, -47, + -60, 91, 51, -42, 80, 37, -22, 69, 24, -3, 59, 10, + 16, 48, -3, 35, 37, -16, 53, 27, -29, 73, 16, -43, + -58, 90, 55, -39, 79, 41, -20, 68, 28, -1, 57, 14, + 18, 46, 0, 37, 36, -12, 56, 25, -25, 75, 14, -39, + -56, 88, 59, -37, 78, 45, -17, 67, 32, 1, 56, 18, + 21, 45, 4, 39, 35, -8, 58, 24, -21, 78, 13, -35, + -53, 87, 63, -34, 76, 50, -15, 65, 36, 4, 55, 23, + 23, 44, 9, 42, 33, -4, 61, 22, -17, 80, 11, -31, + -51, 85, 67, -32, 75, 54, -12, 64, 40, 6, 53, 27, + 26, 42, 13, 45, 32, 0, 63, 21, -13, 83, 10, -27, + -48, 84, 71, -29, 73, 58, -10, 62, 44, 9, 52, 31, + 28, 41, 17, 47, 30, 3, 66, 20, -9, 85, 9, -23, + -46, 83, 75, -27, 72, 62, -8, 61, 48, 11, 50, 35, + 31, 40, 21, 49, 29, 7, 68, 18, -5, 87, 7, -19, + -43, 81, 79, -25, 71, 66, -5, 60, 52, 14, 49, 39, + 33, 38, 25, 52, 28, 11, 71, 17, -1, 90, 6, -15, + -41, 80, 84, -22, 69, 70, -3, 58, 57, 16, 48, 43, + 36, 37, 29, 54, 26, 16, 73, 15, 3, 93, 5, -10, + -38, 78, 88, -20, 68, 74, 0, 57, 61, 19, 46, 47, + 38, 35, 33, 57, 25, 20, 76, 14, 7, 95, 3, -6, + -36, 77, 92, -17, 66, 78, 2, 56, 65, 21, 45, 51, + 40, 34, 37, 59, 23, 24, 78, 13, 11, 97, 2, -2, + -34, 76, 96, -15, 65, 82, 5, 54, 69, 23, 44, 55, + 43, 33, 41, 62, 22, 28, 80, 11, 15, 100, 0, 1, + -31, 74, 100, -12, 64, 87, 7, 53, 73, 26, 42, 60, + 45, 31, 46, 64, 21, 32, 83, 10, 19, 102, 0, 5, + -28, 73, 104, -10, 62, 91, 10, 51, 77, 29, 41, 64, + 48, 30, 50, 67, 19, 36, 85, 9, 23, 105, -1, 9, + -26, 71, 108, -7, 61, 95, 12, 50, 81, 31, 39, 68, + 50, 28, 54, 69, 18, 40, 88, 7, 27, 107, -3, 13, + -101, 119, -19, -82, 108, -32, -63, 97, -46, -44, 87, -60, + -25, 76, -73, -6, 65, -87, 13, 55, -100, 32, 44, -114, + -99, 118, -15, -80, 107, -28, -61, 96, -42, -42, 86, -56, + -23, 75, -69, -4, 64, -83, 15, 53, -96, 34, 42, -110, + -96, 116, -11, -78, 106, -24, -58, 95, -38, -40, 84, -52, + -20, 73, -65, -1, 63, -79, 17, 52, -92, 37, 41, -106, + -94, 115, -6, -75, 104, -20, -56, 93, -34, -37, 83, -47, + -17, 72, -61, 1, 61, -74, 20, 51, -88, 39, 40, -101, + -91, 113, -2, -73, 103, -16, -53, 92, -30, -34, 81, -43, + -15, 70, -57, 4, 60, -70, 22, 49, -84, 42, 38, -97, + -89, 112, 1, -70, 101, -12, -51, 91, -26, -32, 80, -39, + -13, 69, -53, 6, 58, -66, 25, 48, -80, 44, 37, -93, + -87, 111, 5, -68, 100, -8, -48, 89, -22, -30, 79, -35, + -10, 68, -49, 8, 57, -62, 27, 46, -76, 47, 36, -89, + -84, 109, 9, -65, 99, -3, -46, 88, -17, -27, 77, -31, + -8, 66, -44, 11, 56, -58, 30, 45, -71, 49, 34, -85, + -82, 108, 13, -63, 97, 0, -43, 86, -13, -25, 76, -27, + -5, 65, -40, 14, 54, -54, 32, 44, -67, 52, 33, -81, + -79, 107, 17, -60, 96, 4, -41, 85, -9, -22, 74, -23, + -3, 63, -36, 16, 53, -50, 35, 42, -63, 54, 31, -77, + -77, 105, 21, -58, 95, 8, -39, 84, -5, -20, 73, -19, + 0, 62, -32, 18, 51, -46, 37, 41, -59, 57, 30, -73, + -74, 104, 25, -56, 93, 12, -36, 82, -1, -17, 72, -15, + 2, 61, -28, 21, 50, -42, 40, 40, -55, 59, 29, -69, + -72, 102, 30, -53, 92, 16, -33, 81, 2, -15, 70, -10, + 5, 59, -24, 23, 49, -37, 42, 38, -51, 62, 27, -64, + -69, 101, 34, -50, 90, 20, -31, 79, 6, -12, 69, -6, + 7, 58, -20, 26, 47, -33, 45, 37, -47, 64, 26, -60, + -67, 100, 38, -48, 89, 24, -29, 78, 10, -10, 67, -2, + 9, 57, -16, 28, 46, -29, 47, 35, -43, 66, 24, -56, + -64, 98, 42, -46, 88, 28, -26, 77, 14, -8, 66, 1, + 12, 55, -12, 31, 45, -25, 49, 34, -39, 69, 23, -52, + -62, 97, 46, -43, 86, 33, -24, 75, 19, -5, 65, 5, + 15, 54, -7, 33, 43, -21, 52, 32, -34, 71, 22, -48, + -59, 95, 50, -41, 85, 37, -21, 74, 23, -2, 63, 9, + 17, 52, -3, 36, 42, -17, 54, 31, -30, 74, 20, -44, + -57, 94, 54, -38, 83, 41, -19, 72, 27, 0, 62, 13, + 19, 51, 0, 38, 40, -13, 57, 30, -26, 76, 19, -40, + -55, 93, 58, -36, 82, 45, -16, 71, 31, 2, 61, 17, + 22, 50, 4, 40, 39, -9, 59, 28, -22, 79, 17, -36, + -52, 91, 63, -33, 81, 49, -14, 70, 35, 5, 59, 22, + 24, 48, 8, 43, 37, -4, 62, 27, -18, 81, 16, -31, + -50, 90, 67, -31, 79, 53, -11, 68, 39, 7, 58, 26, + 27, 47, 12, 46, 36, 0, 64, 26, -14, 84, 15, -27, + -47, 88, 71, -28, 78, 57, -9, 67, 43, 10, 56, 30, + 29, 45, 16, 48, 35, 3, 67, 24, -10, 86, 13, -23, + -45, 87, 75, -26, 77, 61, -7, 66, 47, 12, 55, 34, + 32, 44, 20, 50, 33, 7, 69, 23, -6, 89, 12, -19, + -42, 86, 79, -24, 75, 65, -4, 64, 51, 15, 54, 38, + 34, 43, 24, 53, 32, 11, 72, 21, -2, 91, 11, -15, + -40, 84, 83, -21, 74, 70, -2, 63, 56, 17, 52, 42, + 37, 41, 29, 55, 31, 15, 74, 20, 2, 94, 9, -11, + -37, 83, 87, -18, 72, 74, 1, 61, 60, 20, 51, 46, + 39, 40, 33, 58, 29, 19, 77, 19, 6, 96, 8, -7, + -35, 82, 91, -16, 71, 78, 3, 60, 64, 22, 49, 50, + 41, 38, 37, 60, 28, 23, 79, 17, 10, 98, 6, -3, + -32, 80, 95, -14, 70, 82, 6, 59, 68, 24, 48, 54, + 44, 37, 41, 63, 27, 27, 81, 16, 14, 101, 5, 0, + -30, 79, 100, -11, 68, 86, 8, 57, 72, 27, 47, 59, + 47, 36, 45, 65, 25, 32, 84, 14, 18, 103, 3, 5, + -27, 77, 104, -9, 67, 90, 11, 56, 76, 30, 45, 63, + 49, 34, 49, 68, 24, 36, 86, 13, 22, 106, 2, 9, + -25, 76, 108, -6, 65, 94, 13, 54, 80, 32, 44, 67, + 51, 33, 53, 70, 22, 40, 89, 12, 26, 108, 1, 13, + -100, 123, -20, -82, 112, -33, -62, 101, -47, -43, 91, -60, + -24, 80, -74, -5, 69, -87, 14, 59, -101, 33, 48, -115, + -98, 122, -16, -79, 111, -29, -60, 100, -43, -41, 90, -56, + -22, 79, -70, -3, 68, -83, 16, 57, -97, 35, 46, -111, + -96, 120, -12, -77, 110, -25, -57, 99, -39, -39, 88, -52, + -19, 77, -66, 0, 67, -79, 18, 56, -93, 38, 45, -107, + -93, 119, -7, -74, 108, -20, -55, 97, -34, -36, 87, -48, + -17, 76, -62, 2, 65, -75, 21, 55, -88, 40, 44, -102, + -90, 117, -3, -72, 107, -16, -52, 96, -30, -34, 85, -44, + -14, 74, -58, 5, 64, -71, 23, 53, -84, 43, 42, -98, + -88, 116, 0, -69, 105, -12, -50, 95, -26, -31, 84, -40, + -12, 73, -54, 7, 62, -67, 26, 52, -80, 45, 41, -94, + -86, 115, 4, -67, 104, -8, -48, 93, -22, -29, 83, -36, + -9, 72, -50, 9, 61, -63, 28, 50, -76, 48, 40, -90, + -83, 113, 8, -64, 103, -4, -45, 92, -18, -26, 81, -31, + -7, 70, -45, 12, 60, -58, 31, 49, -72, 50, 38, -86, + -81, 112, 12, -62, 101, 0, -42, 90, -14, -24, 80, -27, + -4, 69, -41, 14, 58, -54, 33, 48, -68, 53, 37, -82, + -78, 111, 16, -59, 100, 3, -40, 89, -10, -21, 78, -23, + -2, 67, -37, 17, 57, -50, 36, 46, -64, 55, 35, -78, + -76, 109, 20, -57, 99, 7, -38, 88, -6, -19, 77, -19, + 0, 66, -33, 19, 55, -46, 38, 45, -60, 57, 34, -74, + -73, 108, 24, -55, 97, 11, -35, 86, -2, -16, 76, -15, + 3, 65, -29, 22, 54, -42, 40, 44, -56, 60, 33, -70, + -71, 106, 29, -52, 96, 16, -33, 85, 2, -14, 74, -11, + 6, 63, -25, 24, 53, -38, 43, 42, -51, 63, 31, -65, + -68, 105, 33, -50, 94, 20, -30, 83, 6, -11, 73, -7, + 8, 62, -21, 27, 51, -34, 46, 41, -47, 65, 30, -61, + -66, 104, 37, -47, 93, 24, -28, 82, 10, -9, 71, -3, + 10, 61, -17, 29, 50, -30, 48, 39, -43, 67, 28, -57, + -64, 102, 41, -45, 92, 28, -25, 81, 14, -7, 70, 0, + 13, 59, -13, 32, 49, -26, 50, 38, -39, 70, 27, -53, + -61, 101, 45, -42, 90, 32, -23, 79, 18, -4, 69, 5, + 15, 58, -8, 34, 47, -21, 53, 36, -35, 72, 26, -49, + -58, 99, 49, -40, 89, 36, -20, 78, 22, -2, 67, 9, + 18, 56, -4, 37, 46, -17, 55, 35, -31, 75, 24, -45, + -56, 98, 53, -37, 87, 40, -18, 76, 26, 1, 66, 13, + 20, 55, 0, 39, 44, -13, 58, 34, -27, 77, 23, -41, + -54, 97, 57, -35, 86, 44, -16, 75, 30, 3, 65, 17, + 23, 54, 3, 41, 43, -9, 60, 32, -23, 80, 21, -37, + -51, 95, 62, -32, 85, 49, -13, 74, 35, 6, 63, 21, + 25, 52, 7, 44, 41, -5, 63, 31, -18, 82, 20, -32, + -49, 94, 66, -30, 83, 53, -10, 72, 39, 8, 62, 25, + 28, 51, 11, 46, 40, -1, 65, 30, -14, 85, 19, -28, + -46, 92, 70, -27, 82, 57, -8, 71, 43, 11, 60, 29, + 30, 49, 15, 49, 39, 2, 68, 28, -10, 87, 17, -24, + -44, 91, 74, -25, 81, 61, -6, 70, 47, 13, 59, 33, + 32, 48, 19, 51, 37, 6, 70, 27, -6, 89, 16, -20, + -41, 90, 78, -23, 79, 65, -3, 68, 51, 16, 58, 37, + 35, 47, 23, 54, 36, 10, 72, 25, -2, 92, 15, -16, + -39, 88, 82, -20, 78, 69, -1, 67, 55, 18, 56, 42, + 38, 45, 28, 56, 35, 15, 75, 24, 1, 95, 13, -12, + -36, 87, 86, -18, 76, 73, 2, 65, 59, 21, 55, 46, + 40, 44, 32, 59, 33, 19, 78, 23, 5, 97, 12, -8, + -34, 86, 90, -15, 75, 77, 4, 64, 63, 23, 53, 50, + 42, 42, 36, 61, 32, 23, 80, 21, 9, 99, 10, -4, + -32, 84, 94, -13, 74, 81, 7, 63, 67, 25, 52, 54, + 45, 41, 40, 64, 31, 27, 82, 20, 13, 102, 9, 0, + -29, 83, 99, -10, 72, 86, 9, 61, 72, 28, 51, 58, + 47, 40, 44, 66, 29, 31, 85, 18, 18, 104, 7, 4, + -26, 81, 103, -8, 71, 90, 12, 60, 76, 30, 49, 62, + 50, 38, 48, 69, 28, 35, 87, 17, 22, 107, 6, 8, + -24, 80, 107, -5, 69, 94, 14, 58, 80, 33, 48, 66, + 52, 37, 52, 71, 26, 39, 90, 16, 26, 109, 5, 12, + -99, 127, -20, -81, 116, -34, -61, 105, -47, -42, 95, -61, + -23, 84, -75, -4, 73, -88, 14, 63, -101, 34, 52, -115, + -97, 126, -16, -78, 115, -30, -59, 104, -43, -40, 94, -57, + -21, 83, -71, -2, 72, -84, 17, 61, -97, 36, 50, -111, + -95, 124, -12, -76, 114, -26, -56, 103, -39, -38, 92, -53, + -18, 81, -67, 0, 71, -80, 19, 60, -93, 39, 49, -107, + -92, 123, -8, -73, 112, -21, -54, 101, -35, -35, 91, -48, + -16, 80, -62, 3, 69, -76, 22, 59, -89, 41, 48, -103, + -90, 121, -4, -71, 111, -17, -51, 100, -31, -33, 89, -44, + -13, 78, -58, 6, 68, -72, 24, 57, -85, 44, 46, -99, + -87, 120, 0, -68, 109, -13, -49, 99, -27, -30, 88, -40, + -11, 77, -54, 8, 66, -68, 27, 56, -81, 46, 45, -95, + -85, 119, 3, -66, 108, -9, -47, 97, -23, -28, 87, -36, + -8, 76, -50, 10, 65, -64, 29, 54, -77, 48, 44, -91, + -82, 117, 8, -63, 107, -5, -44, 96, -18, -25, 85, -32, + -6, 74, -46, 13, 64, -59, 32, 53, -72, 51, 42, -86, + -80, 116, 12, -61, 105, -1, -42, 94, -14, -23, 84, -28, + -3, 73, -42, 15, 62, -55, 34, 52, -68, 54, 41, -82, + -77, 115, 16, -59, 104, 2, -39, 93, -10, -20, 82, -24, + -1, 71, -38, 18, 61, -51, 37, 50, -64, 56, 39, -78, + -75, 113, 20, -56, 103, 6, -37, 92, -6, -18, 81, -20, + 1, 70, -34, 20, 59, -47, 39, 49, -60, 58, 38, -74, + -73, 112, 24, -54, 101, 10, -34, 90, -2, -16, 80, -16, + 4, 69, -30, 23, 58, -43, 41, 48, -56, 61, 37, -70, + -70, 110, 28, -51, 100, 15, -32, 89, 1, -13, 78, -11, + 6, 67, -25, 25, 57, -39, 44, 46, -52, 63, 35, -66, + -67, 109, 32, -49, 98, 19, -29, 87, 5, -10, 77, -7, + 9, 66, -21, 28, 55, -35, 46, 45, -48, 66, 34, -62, + -65, 108, 36, -46, 97, 23, -27, 86, 9, -8, 75, -3, + 11, 65, -17, 30, 54, -31, 49, 43, -44, 68, 32, -58, + -63, 106, 40, -44, 96, 27, -24, 85, 13, -6, 74, 0, + 14, 63, -13, 32, 53, -27, 51, 42, -40, 71, 31, -54, + -60, 105, 45, -41, 94, 31, -22, 83, 18, -3, 73, 4, + 16, 62, -9, 35, 51, -22, 54, 40, -35, 73, 30, -49, + -58, 103, 49, -39, 93, 35, -19, 82, 22, -1, 71, 8, + 19, 60, -5, 38, 50, -18, 56, 39, -31, 76, 28, -45, + -55, 102, 53, -36, 91, 39, -17, 80, 26, 2, 70, 12, + 21, 59, -1, 40, 48, -14, 59, 38, -27, 78, 27, -41, + -53, 101, 57, -34, 90, 43, -15, 79, 30, 4, 69, 16, + 24, 58, 2, 42, 47, -10, 61, 36, -23, 80, 25, -37, + -50, 99, 61, -31, 89, 48, -12, 78, 34, 7, 67, 21, + 26, 56, 7, 45, 45, -6, 64, 35, -19, 83, 24, -33, + -48, 98, 65, -29, 87, 52, -10, 76, 38, 9, 66, 25, + 29, 55, 11, 47, 44, -2, 66, 34, -15, 86, 23, -29, + -45, 96, 69, -27, 86, 56, -7, 75, 42, 12, 64, 29, + 31, 53, 15, 50, 43, 1, 69, 32, -11, 88, 21, -25, + -43, 95, 73, -24, 85, 60, -5, 74, 46, 14, 63, 33, + 33, 52, 19, 52, 41, 5, 71, 31, -7, 90, 20, -21, + -41, 94, 77, -22, 83, 64, -2, 72, 50, 16, 62, 37, + 36, 51, 23, 55, 40, 9, 73, 29, -3, 93, 19, -17, + -38, 92, 82, -19, 82, 68, 0, 71, 55, 19, 60, 41, + 38, 49, 27, 57, 39, 14, 76, 28, 1, 95, 17, -12, + -35, 91, 86, -17, 80, 72, 3, 69, 59, 21, 59, 45, + 41, 48, 31, 60, 37, 18, 78, 27, 5, 98, 16, -8, + -33, 90, 90, -14, 79, 76, 5, 68, 63, 24, 57, 49, + 43, 46, 35, 62, 36, 22, 81, 25, 9, 100, 14, -4, + -31, 88, 94, -12, 78, 80, 7, 67, 67, 26, 56, 53, + 46, 45, 39, 64, 35, 26, 83, 24, 13, 103, 13, 0, + -28, 87, 98, -9, 76, 85, 10, 65, 71, 29, 55, 58, + 48, 44, 44, 67, 33, 30, 86, 22, 17, 105, 11, 3, + -26, 85, 102, -7, 75, 89, 13, 64, 75, 31, 53, 62, + 51, 42, 48, 70, 32, 34, 88, 21, 21, 108, 10, 7, + -23, 84, 106, -4, 73, 93, 15, 62, 79, 34, 52, 66, + 53, 41, 52, 72, 30, 38, 91, 20, 25, 110, 9, 11, + -126, -1, -1, -107, -11, -15, -88, -22, -28, -69, -33, -42, + -50, -44, -56, -31, -54, -69, -12, -65, -82, 7, -76, -96, + -124, -2, 2, -105, -13, -11, -86, -24, -24, -67, -34, -38, + -47, -45, -52, -29, -56, -65, -10, -66, -78, 9, -77, -92, + -121, -4, 6, -103, -14, -7, -83, -25, -20, -64, -36, -34, + -45, -47, -48, -26, -57, -61, -7, -68, -74, 12, -79, -88, + -119, -5, 10, -100, -16, -2, -81, -27, -16, -62, -37, -29, + -42, -48, -43, -24, -59, -57, -5, -69, -70, 15, -80, -84, + -116, -6, 14, -98, -17, 1, -78, -28, -12, -59, -39, -25, + -40, -49, -39, -21, -60, -53, -2, -71, -66, 17, -82, -80, + -114, -8, 18, -95, -18, 5, -76, -29, -8, -57, -40, -21, + -38, -51, -35, -19, -61, -49, 0, -72, -62, 19, -83, -76, + -112, -9, 22, -93, -20, 9, -73, -31, -4, -55, -41, -17, + -35, -52, -31, -16, -63, -45, 2, -73, -58, 22, -84, -72, + -109, -11, 27, -90, -21, 13, -71, -32, 0, -52, -43, -13, + -32, -54, -27, -14, -64, -40, 5, -75, -53, 24, -86, -67, + -106, -12, 31, -88, -23, 17, -68, -33, 4, -49, -44, -9, + -30, -55, -23, -11, -66, -36, 7, -76, -49, 27, -87, -63, + -104, -13, 35, -85, -24, 21, -66, -35, 8, -47, -45, -5, + -28, -56, -19, -9, -67, -32, 10, -78, -45, 29, -89, -59, + -102, -15, 39, -83, -25, 25, -63, -36, 12, -45, -47, -1, + -25, -58, -15, -7, -68, -28, 12, -79, -41, 32, -90, -55, + -99, -16, 43, -80, -27, 29, -61, -38, 16, -42, -48, 2, + -23, -59, -11, -4, -70, -24, 15, -80, -37, 34, -91, -51, + -97, -18, 47, -78, -28, 34, -58, -39, 20, -40, -50, 7, + -20, -61, -6, -1, -71, -20, 17, -82, -33, 37, -93, -47, + -94, -19, 51, -75, -29, 38, -56, -40, 24, -37, -51, 11, + -18, -62, -2, 1, -73, -16, 20, -83, -29, 39, -94, -43, + -92, -20, 55, -73, -31, 42, -54, -42, 28, -35, -52, 15, + -15, -63, 1, 3, -74, -12, 22, -84, -25, 41, -95, -39, + -89, -22, 59, -71, -32, 46, -51, -43, 32, -32, -54, 19, + -13, -65, 5, 6, -75, -8, 25, -86, -21, 44, -97, -35, + -87, -23, 64, -68, -34, 50, -49, -45, 37, -30, -55, 23, + -10, -66, 9, 8, -77, -3, 27, -87, -16, 47, -98, -30, + -84, -24, 68, -66, -35, 54, -46, -46, 41, -27, -57, 27, + -8, -68, 13, 11, -78, 0, 30, -89, -12, 49, -100, -26, + -82, -26, 72, -63, -36, 58, -44, -47, 45, -25, -58, 31, + -6, -69, 17, 13, -79, 4, 32, -90, -8, 51, -101, -22, + -80, -27, 76, -61, -38, 62, -41, -49, 49, -23, -59, 35, + -3, -70, 21, 16, -81, 8, 34, -91, -4, 54, -102, -18, + -77, -29, 80, -58, -39, 67, -39, -50, 53, -20, -61, 40, + -1, -72, 26, 18, -82, 12, 37, -93, 0, 56, -104, -14, + -74, -30, 84, -56, -41, 71, -36, -52, 57, -17, -62, 44, + 2, -73, 30, 21, -84, 16, 39, -94, 3, 59, -105, -10, + -72, -31, 88, -53, -42, 75, -34, -53, 61, -15, -63, 48, + 4, -74, 34, 23, -85, 20, 42, -96, 7, 61, -107, -6, + -70, -33, 92, -51, -43, 79, -31, -54, 65, -13, -65, 52, + 7, -76, 38, 25, -86, 24, 44, -97, 11, 64, -108, -2, + -67, -34, 96, -48, -45, 83, -29, -56, 69, -10, -66, 56, + 9, -77, 42, 28, -88, 28, 47, -98, 15, 66, -109, 1, + -65, -36, 101, -46, -46, 87, -26, -57, 74, -8, -68, 60, + 12, -79, 46, 31, -89, 33, 49, -100, 20, 69, -111, 6, + -62, -37, 105, -43, -48, 91, -24, -58, 78, -5, -69, 64, + 14, -80, 50, 33, -91, 37, 52, -101, 24, 71, -112, 10, + -60, -38, 109, -41, -49, 95, -22, -60, 82, -3, -70, 68, + 17, -81, 54, 35, -92, 41, 54, -103, 28, 73, -113, 14, + -57, -40, 113, -39, -50, 99, -19, -61, 86, 0, -72, 72, + 19, -83, 58, 38, -93, 45, 56, -104, 32, 76, -115, 18, + -55, -41, 117, -36, -52, 104, -17, -63, 90, 2, -73, 77, + 22, -84, 63, 40, -95, 49, 59, -105, 36, 79, -116, 22, + -52, -43, 121, -34, -53, 108, -14, -64, 94, 5, -75, 81, + 24, -86, 67, 43, -96, 53, 62, -107, 40, 81, -118, 26, + -50, -44, 125, -31, -54, 112, -12, -65, 98, 7, -76, 85, + 26, -87, 71, 45, -98, 57, 64, -108, 44, 83, -119, 30, + -125, 2, -2, -106, -7, -15, -87, -18, -29, -68, -29, -42, + -49, -40, -56, -30, -50, -70, -11, -61, -83, 8, -72, -97, + -123, 1, 1, -104, -9, -11, -85, -20, -25, -66, -30, -38, + -47, -41, -52, -28, -52, -66, -9, -62, -79, 10, -73, -93, + -120, 0, 5, -102, -10, -7, -82, -21, -21, -64, -32, -34, + -44, -43, -48, -25, -53, -62, -7, -64, -75, 13, -75, -89, + -118, -1, 10, -99, -12, -3, -80, -23, -17, -61, -33, -30, + -41, -44, -44, -23, -55, -57, -4, -65, -71, 15, -76, -84, + -115, -2, 14, -97, -13, 0, -77, -24, -13, -58, -35, -26, + -39, -45, -40, -20, -56, -53, -1, -67, -67, 18, -78, -80, + -113, -4, 18, -94, -14, 4, -75, -25, -9, -56, -36, -22, + -37, -47, -36, -18, -57, -49, 1, -68, -63, 20, -79, -76, + -111, -5, 22, -92, -16, 8, -72, -27, -5, -54, -37, -18, + -34, -48, -32, -15, -59, -45, 3, -69, -59, 23, -80, -72, + -108, -7, 26, -89, -17, 13, -70, -28, 0, -51, -39, -13, + -32, -50, -27, -13, -60, -41, 6, -71, -54, 25, -82, -68, + -106, -8, 30, -87, -19, 17, -67, -29, 3, -49, -40, -9, + -29, -51, -23, -10, -62, -37, 8, -72, -50, 28, -83, -64, + -103, -9, 34, -84, -20, 21, -65, -31, 7, -46, -41, -5, + -27, -52, -19, -8, -63, -33, 11, -74, -46, 30, -85, -60, + -101, -11, 38, -82, -21, 25, -63, -32, 11, -44, -43, -1, + -24, -54, -15, -6, -64, -29, 13, -75, -42, 33, -86, -56, + -98, -12, 42, -80, -23, 29, -60, -34, 15, -41, -44, 2, + -22, -55, -11, -3, -66, -25, 16, -76, -38, 35, -87, -52, + -96, -14, 47, -77, -24, 33, -57, -35, 19, -39, -46, 6, + -19, -57, -7, -1, -67, -20, 18, -78, -34, 38, -89, -47, + -93, -15, 51, -74, -25, 37, -55, -36, 23, -36, -47, 10, + -17, -58, -3, 2, -69, -16, 21, -79, -30, 40, -90, -43, + -91, -16, 55, -72, -27, 41, -53, -38, 27, -34, -48, 14, + -15, -59, 0, 4, -70, -12, 23, -80, -26, 42, -91, -39, + -88, -18, 59, -70, -28, 45, -50, -39, 31, -32, -50, 18, + -12, -61, 4, 7, -71, -8, 25, -82, -22, 45, -93, -35, + -86, -19, 63, -67, -30, 50, -48, -41, 36, -29, -51, 23, + -9, -62, 9, 9, -73, -4, 28, -83, -17, 47, -94, -31, + -83, -20, 67, -65, -31, 54, -45, -42, 40, -26, -53, 27, + -7, -64, 13, 12, -74, 0, 30, -85, -13, 50, -96, -27, + -81, -22, 71, -62, -32, 58, -43, -43, 44, -24, -54, 31, + -5, -65, 17, 14, -75, 3, 33, -86, -9, 52, -97, -23, + -79, -23, 75, -60, -34, 62, -40, -45, 48, -22, -55, 35, + -2, -66, 21, 16, -77, 7, 35, -87, -5, 55, -98, -19, + -76, -25, 80, -57, -35, 66, -38, -46, 52, -19, -57, 39, + 0, -68, 25, 19, -78, 12, 38, -89, -1, 57, -100, -14, + -74, -26, 84, -55, -37, 70, -35, -48, 56, -17, -58, 43, + 3, -69, 29, 22, -80, 16, 40, -90, 2, 60, -101, -10, + -71, -27, 88, -52, -38, 74, -33, -49, 60, -14, -59, 47, + 5, -70, 33, 24, -81, 20, 43, -92, 6, 62, -103, -6, + -69, -29, 92, -50, -39, 78, -31, -50, 64, -12, -61, 51, + 8, -72, 37, 26, -82, 24, 45, -93, 10, 65, -104, -2, + -66, -30, 96, -48, -41, 82, -28, -52, 68, -9, -62, 55, + 10, -73, 41, 29, -84, 28, 48, -94, 14, 67, -105, 1, + -64, -32, 100, -45, -42, 87, -25, -53, 73, -7, -64, 60, + 13, -75, 46, 31, -85, 32, 50, -96, 19, 70, -107, 5, + -61, -33, 104, -42, -44, 91, -23, -54, 77, -4, -65, 64, + 15, -76, 50, 34, -87, 36, 53, -97, 23, 72, -108, 9, + -59, -34, 108, -40, -45, 95, -21, -56, 81, -2, -66, 68, + 17, -77, 54, 36, -88, 40, 55, -99, 27, 74, -109, 13, + -56, -36, 112, -38, -46, 99, -18, -57, 85, 0, -68, 72, + 20, -79, 58, 39, -89, 44, 57, -100, 31, 77, -111, 17, + -54, -37, 117, -35, -48, 103, -16, -59, 89, 3, -69, 76, + 23, -80, 62, 41, -91, 49, 60, -101, 35, 79, -112, 22, + -51, -39, 121, -33, -49, 107, -13, -60, 93, 6, -71, 80, + 25, -82, 66, 44, -92, 53, 62, -103, 39, 82, -114, 26, + -49, -40, 125, -30, -50, 111, -11, -61, 97, 8, -72, 84, + 27, -83, 70, 46, -94, 57, 65, -104, 43, 84, -115, 30, + -124, 6, -2, -106, -3, -16, -86, -14, -30, -67, -25, -43, + -48, -36, -57, -29, -46, -70, -10, -57, -84, 9, -68, -98, + -122, 5, 1, -103, -5, -12, -84, -16, -26, -65, -26, -39, + -46, -37, -53, -27, -48, -66, -8, -58, -80, 11, -69, -94, + -120, 3, 5, -101, -6, -8, -81, -17, -22, -63, -28, -35, + -43, -39, -49, -24, -49, -62, -6, -60, -76, 14, -71, -90, + -117, 2, 9, -98, -8, -3, -79, -19, -17, -60, -29, -31, + -41, -40, -44, -22, -51, -58, -3, -61, -71, 16, -72, -85, + -114, 1, 13, -96, -9, 0, -76, -20, -13, -58, -31, -27, + -38, -41, -40, -19, -52, -54, -1, -63, -67, 19, -74, -81, + -112, 0, 17, -93, -10, 4, -74, -21, -9, -55, -32, -23, + -36, -43, -36, -17, -53, -50, 2, -64, -63, 21, -75, -77, + -110, -1, 21, -91, -12, 8, -72, -23, -5, -53, -33, -19, + -33, -44, -32, -15, -55, -46, 4, -65, -59, 24, -76, -73, + -107, -3, 26, -88, -13, 12, -69, -24, -1, -50, -35, -14, + -31, -46, -28, -12, -56, -41, 7, -67, -55, 26, -78, -69, + -105, -4, 30, -86, -15, 16, -66, -25, 2, -48, -36, -10, + -28, -47, -24, -10, -58, -37, 9, -68, -51, 29, -79, -65, + -102, -5, 34, -83, -16, 20, -64, -27, 6, -45, -37, -6, + -26, -48, -20, -7, -59, -33, 12, -70, -47, 31, -81, -61, + -100, -7, 38, -81, -17, 24, -62, -28, 10, -43, -39, -2, + -23, -50, -16, -5, -60, -29, 14, -71, -43, 33, -82, -57, + -97, -8, 42, -79, -19, 28, -59, -30, 14, -40, -40, 1, + -21, -51, -12, -2, -62, -25, 16, -72, -39, 36, -83, -53, + -95, -10, 46, -76, -20, 33, -57, -31, 19, -38, -42, 5, + -18, -53, -7, 0, -63, -21, 19, -74, -34, 39, -85, -48, + -92, -11, 50, -74, -21, 37, -54, -32, 23, -35, -43, 9, + -16, -54, -3, 3, -65, -17, 22, -75, -30, 41, -86, -44, + -90, -12, 54, -71, -23, 41, -52, -34, 27, -33, -44, 13, + -14, -55, 0, 5, -66, -13, 24, -76, -26, 43, -87, -40, + -88, -14, 58, -69, -24, 45, -49, -35, 31, -31, -46, 17, + -11, -57, 4, 8, -67, -9, 26, -78, -22, 46, -89, -36, + -85, -15, 63, -66, -26, 49, -47, -37, 35, -28, -47, 22, + -9, -58, 8, 10, -69, -4, 29, -79, -18, 48, -90, -32, + -82, -16, 67, -64, -27, 53, -44, -38, 39, -26, -49, 26, + -6, -60, 12, 13, -70, 0, 31, -81, -14, 51, -92, -28, + -80, -18, 71, -61, -28, 57, -42, -39, 43, -23, -50, 30, + -4, -61, 16, 15, -71, 3, 34, -82, -10, 53, -93, -24, + -78, -19, 75, -59, -30, 61, -40, -41, 47, -21, -51, 34, + -1, -62, 20, 17, -73, 7, 36, -83, -6, 56, -94, -20, + -75, -21, 79, -56, -31, 66, -37, -42, 52, -18, -53, 38, + 1, -64, 25, 20, -74, 11, 39, -85, -1, 58, -96, -15, + -73, -22, 83, -54, -33, 70, -34, -44, 56, -16, -54, 42, + 4, -65, 29, 22, -76, 15, 41, -86, 2, 61, -97, -11, + -70, -23, 87, -51, -34, 74, -32, -45, 60, -13, -55, 46, + 6, -66, 33, 25, -77, 19, 44, -88, 6, 63, -99, -7, + -68, -25, 91, -49, -35, 78, -30, -46, 64, -11, -57, 50, + 8, -68, 37, 27, -78, 23, 46, -89, 10, 65, -100, -3, + -65, -26, 95, -47, -37, 82, -27, -48, 68, -8, -58, 54, + 11, -69, 41, 30, -80, 27, 48, -90, 14, 68, -101, 0, + -63, -28, 100, -44, -38, 86, -25, -49, 72, -6, -60, 59, + 14, -71, 45, 32, -81, 32, 51, -92, 18, 71, -103, 4, + -60, -29, 104, -42, -40, 90, -22, -50, 76, -3, -61, 63, + 16, -72, 49, 35, -83, 36, 54, -93, 22, 73, -104, 8, + -58, -30, 108, -39, -41, 94, -20, -52, 80, -1, -62, 67, + 18, -73, 53, 37, -84, 40, 56, -95, 26, 75, -105, 12, + -56, -32, 112, -37, -42, 98, -17, -53, 84, 1, -64, 71, + 21, -75, 57, 40, -85, 44, 58, -96, 30, 78, -107, 16, + -53, -33, 116, -34, -44, 103, -15, -55, 89, 4, -65, 75, + 23, -76, 62, 42, -87, 48, 61, -97, 35, 80, -108, 21, + -50, -35, 120, -32, -45, 107, -12, -56, 93, 6, -67, 79, + 26, -78, 66, 45, -88, 52, 63, -99, 39, 83, -110, 25, + -48, -36, 124, -29, -46, 111, -10, -57, 97, 9, -68, 83, + 28, -79, 70, 47, -90, 56, 66, -100, 43, 85, -111, 29, + -123, 11, -3, -105, 0, -17, -85, -10, -30, -66, -20, -44, + -47, -31, -58, -28, -42, -71, -9, -53, -84, 10, -64, -98, + -121, 9, 0, -102, 0, -13, -83, -11, -26, -64, -22, -40, + -45, -33, -54, -26, -43, -67, -7, -54, -80, 12, -65, -94, + -119, 8, 4, -100, -2, -9, -80, -13, -22, -62, -23, -36, + -42, -34, -50, -23, -45, -63, -5, -55, -76, 15, -66, -90, + -116, 6, 8, -97, -3, -4, -78, -14, -18, -59, -25, -31, + -40, -36, -45, -21, -46, -59, -2, -57, -72, 17, -68, -86, + -113, 5, 12, -95, -4, 0, -75, -15, -14, -56, -26, -27, + -37, -37, -41, -18, -48, -55, 0, -58, -68, 20, -69, -82, + -111, 4, 16, -92, -6, 3, -73, -17, -10, -54, -27, -23, + -35, -38, -37, -16, -49, -51, 3, -60, -64, 22, -70, -78, + -109, 2, 20, -90, -7, 7, -70, -18, -6, -52, -29, -19, + -32, -40, -33, -14, -50, -47, 5, -61, -60, 25, -72, -74, + -106, 1, 25, -87, -9, 11, -68, -20, -1, -49, -30, -15, + -30, -41, -29, -11, -52, -42, 8, -62, -55, 27, -73, -69, + -104, 0, 29, -85, -10, 15, -65, -21, 2, -47, -32, -11, + -27, -43, -25, -8, -53, -38, 10, -64, -51, 30, -75, -65, + -101, -1, 33, -82, -11, 19, -63, -22, 6, -44, -33, -7, + -25, -44, -21, -6, -54, -34, 13, -65, -47, 32, -76, -61, + -99, -2, 37, -80, -13, 23, -61, -24, 10, -42, -34, -3, + -22, -45, -17, -4, -56, -30, 15, -66, -43, 34, -77, -57, + -96, -4, 41, -78, -14, 27, -58, -25, 14, -39, -36, 0, + -20, -47, -13, -1, -57, -26, 17, -68, -39, 37, -79, -53, + -94, -5, 45, -75, -16, 32, -56, -27, 18, -37, -37, 5, + -17, -48, -8, 1, -59, -22, 20, -69, -35, 40, -80, -49, + -91, -6, 49, -73, -17, 36, -53, -28, 22, -34, -39, 9, + -15, -49, -4, 4, -60, -18, 23, -71, -31, 42, -82, -45, + -89, -8, 53, -70, -18, 40, -51, -29, 26, -32, -40, 13, + -13, -51, 0, 6, -61, -14, 25, -72, -27, 44, -83, -41, + -87, -9, 57, -68, -20, 44, -48, -31, 30, -30, -41, 17, + -10, -52, 3, 9, -63, -10, 27, -73, -23, 47, -84, -37, + -84, -11, 62, -65, -21, 48, -46, -32, 35, -27, -43, 21, + -8, -54, 7, 11, -64, -5, 30, -75, -18, 49, -86, -32, + -81, -12, 66, -63, -23, 52, -43, -33, 39, -25, -44, 25, + -5, -55, 11, 14, -66, -1, 32, -76, -14, 52, -87, -28, + -79, -13, 70, -60, -24, 56, -41, -35, 43, -22, -45, 29, + -3, -56, 15, 16, -67, 2, 35, -78, -10, 54, -88, -24, + -77, -15, 74, -58, -25, 60, -39, -36, 47, -20, -47, 33, + 0, -58, 19, 18, -68, 6, 37, -79, -6, 57, -90, -20, + -74, -16, 78, -55, -27, 65, -36, -38, 51, -17, -48, 38, + 2, -59, 24, 21, -70, 10, 40, -80, -2, 59, -91, -16, + -72, -18, 82, -53, -28, 69, -33, -39, 55, -15, -50, 42, + 5, -61, 28, 24, -71, 14, 42, -82, 1, 62, -93, -12, + -69, -19, 86, -50, -29, 73, -31, -40, 59, -12, -51, 46, + 7, -62, 32, 26, -73, 18, 45, -83, 5, 64, -94, -8, + -67, -20, 90, -48, -31, 77, -29, -42, 63, -10, -52, 50, + 10, -63, 36, 28, -74, 22, 47, -84, 9, 66, -95, -4, + -64, -22, 94, -46, -32, 81, -26, -43, 67, -7, -54, 54, + 12, -65, 40, 31, -75, 26, 49, -86, 13, 69, -97, 0, + -62, -23, 99, -43, -34, 85, -24, -45, 72, -5, -55, 58, + 15, -66, 44, 33, -77, 31, 52, -87, 18, 72, -98, 4, + -59, -24, 103, -41, -35, 89, -21, -46, 76, -2, -57, 62, + 17, -67, 48, 36, -78, 35, 55, -89, 22, 74, -100, 8, + -57, -26, 107, -38, -36, 93, -19, -47, 80, 0, -58, 66, + 19, -69, 52, 38, -79, 39, 57, -90, 26, 76, -101, 12, + -55, -27, 111, -36, -38, 97, -16, -49, 84, 2, -59, 70, + 22, -70, 56, 41, -81, 43, 59, -91, 30, 79, -102, 16, + -52, -29, 115, -33, -39, 102, -14, -50, 88, 5, -61, 75, + 24, -72, 61, 43, -82, 47, 62, -93, 34, 81, -104, 20, + -49, -30, 119, -31, -41, 106, -11, -52, 92, 7, -62, 79, + 27, -73, 65, 46, -84, 51, 64, -94, 38, 84, -105, 24, + -47, -31, 123, -28, -42, 110, -9, -53, 96, 10, -63, 83, + 29, -74, 69, 48, -85, 55, 67, -96, 42, 86, -107, 28, + -122, 15, -4, -104, 4, -17, -84, -6, -31, -65, -16, -44, + -46, -27, -58, -27, -38, -72, -9, -49, -85, 11, -60, -99, + -120, 13, 0, -101, 3, -13, -82, -7, -27, -63, -18, -40, + -44, -29, -54, -25, -39, -68, -6, -50, -81, 13, -61, -95, + -118, 12, 3, -99, 1, -9, -79, -9, -23, -61, -19, -36, + -41, -30, -50, -23, -41, -64, -4, -51, -77, 16, -62, -91, + -115, 10, 8, -96, 0, -5, -77, -10, -19, -58, -21, -32, + -39, -32, -46, -20, -42, -59, -1, -53, -73, 18, -64, -86, + -113, 9, 12, -94, 0, -1, -74, -11, -15, -56, -22, -28, + -36, -33, -42, -17, -44, -55, 1, -54, -69, 21, -65, -82, + -110, 8, 16, -91, -2, 2, -72, -13, -11, -53, -23, -24, + -34, -34, -38, -15, -45, -51, 4, -56, -65, 23, -66, -78, + -108, 6, 20, -89, -3, 6, -70, -14, -7, -51, -25, -20, + -31, -36, -34, -13, -46, -47, 6, -57, -61, 26, -68, -74, + -105, 5, 24, -86, -5, 11, -67, -16, -2, -48, -26, -15, + -29, -37, -29, -10, -48, -43, 9, -58, -56, 28, -69, -70, + -103, 4, 28, -84, -6, 15, -65, -17, 1, -46, -28, -11, + -26, -39, -25, -8, -49, -39, 11, -60, -52, 31, -71, -66, + -100, 2, 32, -81, -7, 19, -62, -18, 5, -43, -29, -7, + -24, -40, -21, -5, -50, -35, 14, -61, -48, 33, -72, -62, + -98, 1, 36, -79, -9, 23, -60, -20, 9, -41, -30, -3, + -22, -41, -17, -3, -52, -31, 16, -62, -44, 35, -73, -58, + -95, 0, 40, -77, -10, 27, -57, -21, 13, -39, -32, 0, + -19, -43, -13, 0, -53, -27, 18, -64, -40, 38, -75, -54, + -93, -1, 45, -74, -12, 31, -55, -23, 17, -36, -33, 4, + -16, -44, -9, 2, -55, -22, 21, -65, -36, 40, -76, -49, + -90, -2, 49, -72, -13, 35, -52, -24, 21, -33, -35, 8, + -14, -45, -5, 5, -56, -18, 23, -67, -32, 43, -78, -45, + -88, -4, 53, -69, -14, 39, -50, -25, 25, -31, -36, 12, + -12, -47, -1, 7, -57, -14, 26, -68, -28, 45, -79, -41, + -86, -5, 57, -67, -16, 43, -47, -27, 29, -29, -37, 16, + -9, -48, 2, 9, -59, -10, 28, -69, -24, 48, -80, -37, + -83, -7, 61, -64, -17, 48, -45, -28, 34, -26, -39, 21, + -7, -50, 7, 12, -60, -6, 31, -71, -19, 50, -82, -33, + -81, -8, 65, -62, -19, 52, -42, -29, 38, -24, -40, 25, + -4, -51, 11, 15, -62, -2, 33, -72, -15, 53, -83, -29, + -78, -9, 69, -59, -20, 56, -40, -31, 42, -21, -41, 29, + -2, -52, 15, 17, -63, 1, 36, -74, -11, 55, -84, -25, + -76, -11, 73, -57, -21, 60, -38, -32, 46, -19, -43, 33, + 1, -54, 19, 19, -64, 5, 38, -75, -7, 58, -86, -21, + -73, -12, 78, -54, -23, 64, -35, -34, 50, -16, -44, 37, + 3, -55, 23, 22, -66, 10, 41, -76, -3, 60, -87, -16, + -71, -14, 82, -52, -24, 68, -33, -35, 54, -14, -46, 41, + 6, -57, 27, 24, -67, 14, 43, -78, 0, 63, -89, -12, + -68, -15, 86, -49, -25, 72, -30, -36, 58, -11, -47, 45, + 8, -58, 31, 27, -69, 18, 46, -79, 4, 65, -90, -8, + -66, -16, 90, -47, -27, 76, -28, -38, 62, -9, -48, 49, + 10, -59, 35, 29, -70, 22, 48, -80, 8, 67, -91, -4, + -63, -18, 94, -45, -28, 80, -25, -39, 66, -7, -50, 53, + 13, -61, 39, 32, -71, 26, 50, -82, 12, 70, -93, 0, + -61, -19, 98, -42, -30, 85, -23, -41, 71, -4, -51, 58, + 16, -62, 44, 34, -73, 30, 53, -83, 17, 72, -94, 3, + -58, -20, 102, -40, -31, 89, -20, -42, 75, -1, -53, 62, + 18, -63, 48, 37, -74, 34, 55, -85, 21, 75, -96, 7, + -56, -22, 106, -37, -32, 93, -18, -43, 79, 1, -54, 66, + 20, -65, 52, 39, -75, 38, 58, -86, 25, 77, -97, 11, + -54, -23, 110, -35, -34, 97, -15, -45, 83, 3, -55, 70, + 23, -66, 56, 41, -77, 42, 60, -87, 29, 80, -98, 15, + -51, -25, 115, -32, -35, 101, -13, -46, 87, 6, -57, 74, + 25, -68, 60, 44, -78, 47, 63, -89, 33, 82, -100, 20, + -49, -26, 119, -30, -37, 105, -10, -48, 91, 8, -58, 78, + 28, -69, 64, 47, -80, 51, 65, -90, 37, 85, -101, 24, + -46, -27, 123, -27, -38, 109, -8, -49, 95, 11, -59, 82, + 30, -70, 68, 49, -81, 55, 68, -92, 41, 87, -103, 28, + -121, 19, -5, -103, 8, -18, -83, -2, -32, -65, -12, -45, + -45, -23, -59, -26, -34, -72, -8, -45, -86, 12, -56, -100, + -119, 17, -1, -100, 7, -14, -81, -3, -28, -62, -14, -41, + -43, -25, -55, -24, -35, -68, -5, -46, -82, 14, -57, -96, + -117, 16, 2, -98, 5, -10, -79, -5, -24, -60, -15, -37, + -40, -26, -51, -22, -37, -64, -3, -47, -78, 17, -58, -92, + -114, 14, 7, -95, 4, -5, -76, -6, -19, -57, -17, -33, + -38, -28, -46, -19, -38, -60, 0, -49, -73, 19, -60, -87, + -112, 13, 11, -93, 3, -1, -73, -7, -15, -55, -18, -29, + -35, -29, -42, -17, -40, -56, 2, -50, -69, 22, -61, -83, + -109, 12, 15, -90, 1, 2, -71, -9, -11, -52, -19, -25, + -33, -30, -38, -14, -41, -52, 5, -52, -65, 24, -62, -79, + -107, 10, 19, -88, 0, 6, -69, -10, -7, -50, -21, -21, + -31, -32, -34, -12, -42, -48, 7, -53, -61, 26, -64, -75, + -104, 9, 23, -85, -1, 10, -66, -12, -3, -47, -22, -16, + -28, -33, -30, -9, -44, -43, 10, -54, -57, 29, -65, -71, + -102, 8, 27, -83, -2, 14, -64, -13, 0, -45, -24, -12, + -25, -35, -26, -7, -45, -39, 12, -56, -53, 32, -67, -67, + -99, 6, 31, -81, -3, 18, -61, -14, 4, -42, -25, -8, + -23, -36, -22, -4, -46, -35, 15, -57, -49, 34, -68, -63, + -97, 5, 35, -78, -5, 22, -59, -16, 8, -40, -26, -4, + -21, -37, -18, -2, -48, -31, 17, -58, -45, 36, -69, -59, + -95, 3, 39, -76, -6, 26, -56, -17, 12, -38, -28, 0, + -18, -39, -14, 1, -49, -27, 19, -60, -41, 39, -71, -55, + -92, 2, 44, -73, -8, 31, -54, -19, 17, -35, -29, 3, + -16, -40, -9, 3, -51, -23, 22, -61, -36, 41, -72, -50, + -89, 1, 48, -71, -9, 35, -51, -20, 21, -33, -31, 7, + -13, -41, -5, 6, -52, -19, 24, -63, -32, 44, -74, -46, + -87, 0, 52, -68, -10, 39, -49, -21, 25, -30, -32, 11, + -11, -43, -1, 8, -53, -15, 27, -64, -28, 46, -75, -42, + -85, -1, 56, -66, -12, 43, -47, -23, 29, -28, -33, 15, + -8, -44, 2, 10, -55, -11, 29, -65, -24, 49, -76, -38, + -82, -3, 60, -63, -13, 47, -44, -24, 33, -25, -35, 20, + -6, -46, 6, 13, -56, -6, 32, -67, -20, 51, -78, -34, + -80, -4, 64, -61, -15, 51, -41, -25, 37, -23, -36, 24, + -3, -47, 10, 15, -58, -2, 34, -68, -16, 54, -79, -30, + -77, -5, 68, -58, -16, 55, -39, -27, 41, -20, -37, 28, + -1, -48, 14, 18, -59, 1, 37, -70, -12, 56, -80, -26, + -75, -7, 72, -56, -17, 59, -37, -28, 45, -18, -39, 32, + 1, -50, 18, 20, -60, 5, 39, -71, -8, 58, -82, -22, + -72, -8, 77, -53, -19, 64, -34, -30, 50, -15, -40, 36, + 4, -51, 23, 23, -62, 9, 42, -72, -3, 61, -83, -17, + -70, -10, 81, -51, -20, 68, -32, -31, 54, -13, -42, 40, + 7, -53, 27, 25, -63, 13, 44, -74, 0, 63, -85, -13, + -67, -11, 85, -49, -21, 72, -29, -32, 58, -10, -43, 44, + 9, -54, 31, 28, -65, 17, 47, -75, 4, 66, -86, -9, + -65, -12, 89, -46, -23, 76, -27, -34, 62, -8, -44, 48, + 11, -55, 35, 30, -66, 21, 49, -76, 8, 68, -87, -5, + -63, -14, 93, -44, -24, 80, -24, -35, 66, -6, -46, 52, + 14, -57, 39, 33, -67, 25, 51, -78, 12, 71, -89, -1, + -60, -15, 97, -41, -26, 84, -22, -37, 70, -3, -47, 57, + 16, -58, 43, 35, -69, 30, 54, -79, 16, 73, -90, 2, + -57, -16, 101, -39, -27, 88, -19, -38, 74, -1, -49, 61, + 19, -59, 47, 38, -70, 34, 56, -81, 20, 76, -92, 6, + -55, -18, 105, -36, -28, 92, -17, -39, 78, 2, -50, 65, + 21, -61, 51, 40, -71, 38, 59, -82, 24, 78, -93, 10, + -53, -19, 109, -34, -30, 96, -15, -41, 82, 4, -51, 69, + 24, -62, 55, 42, -73, 42, 61, -83, 28, 81, -94, 14, + -50, -21, 114, -31, -31, 101, -12, -42, 87, 7, -53, 73, + 26, -64, 60, 45, -74, 46, 64, -85, 33, 83, -96, 19, + -48, -22, 118, -29, -33, 105, -9, -44, 91, 9, -54, 77, + 29, -65, 64, 47, -76, 50, 66, -86, 37, 86, -97, 23, + -45, -23, 122, -26, -34, 109, -7, -45, 95, 12, -55, 81, + 31, -66, 68, 50, -77, 54, 69, -88, 41, 88, -99, 27, + -121, 23, -5, -102, 12, -19, -82, 1, -32, -64, -8, -46, + -44, -19, -60, -25, -30, -73, -7, -41, -86, 13, -52, -100, + -118, 21, -1, -99, 11, -15, -80, 0, -28, -61, -10, -42, + -42, -21, -56, -23, -31, -69, -4, -42, -82, 15, -53, -96, + -116, 20, 2, -97, 9, -11, -78, -1, -24, -59, -11, -38, + -39, -22, -52, -21, -33, -65, -2, -43, -78, 17, -54, -92, + -113, 18, 6, -94, 8, -6, -75, -2, -20, -56, -13, -33, + -37, -24, -47, -18, -34, -60, 1, -45, -74, 20, -56, -88, + -111, 17, 10, -92, 7, -2, -73, -3, -16, -54, -14, -29, + -34, -25, -43, -16, -36, -56, 3, -46, -70, 23, -57, -84, + -108, 16, 14, -90, 5, 1, -70, -5, -12, -51, -15, -25, + -32, -26, -39, -13, -37, -52, 6, -48, -66, 25, -58, -80, + -106, 14, 18, -87, 4, 5, -68, -6, -8, -49, -17, -21, + -30, -28, -35, -11, -38, -48, 8, -49, -62, 27, -60, -76, + -103, 13, 23, -84, 2, 9, -65, -8, -3, -46, -18, -17, + -27, -29, -31, -8, -40, -44, 11, -50, -57, 30, -61, -71, + -101, 12, 27, -82, 1, 13, -63, -9, 0, -44, -20, -13, + -25, -31, -27, -6, -41, -40, 13, -52, -53, 32, -63, -67, + -98, 10, 31, -80, 0, 17, -60, -10, 4, -42, -21, -9, + -22, -32, -23, -3, -42, -36, 15, -53, -49, 35, -64, -63, + -96, 9, 35, -77, -1, 21, -58, -12, 8, -39, -22, -5, + -20, -33, -19, -1, -44, -32, 18, -54, -45, 37, -65, -59, + -94, 7, 39, -75, -2, 25, -56, -13, 12, -37, -24, -1, + -17, -35, -15, 1, -45, -28, 20, -56, -41, 40, -67, -55, + -91, 6, 43, -72, -4, 30, -53, -15, 16, -34, -25, 3, + -15, -36, -10, 4, -47, -23, 23, -57, -37, 42, -68, -51, + -89, 5, 47, -70, -5, 34, -50, -16, 20, -32, -27, 7, + -12, -37, -6, 7, -48, -19, 25, -59, -33, 45, -70, -47, + -86, 3, 51, -67, -6, 38, -48, -17, 24, -29, -28, 11, + -10, -39, -2, 9, -49, -15, 28, -60, -29, 47, -71, -43, + -84, 2, 55, -65, -8, 42, -46, -19, 28, -27, -29, 15, + -7, -40, 1, 11, -51, -11, 30, -61, -25, 49, -72, -39, + -81, 0, 60, -62, -9, 46, -43, -20, 33, -24, -31, 19, + -5, -42, 5, 14, -52, -7, 33, -63, -20, 52, -74, -34, + -79, 0, 64, -60, -11, 50, -41, -21, 37, -22, -32, 23, + -2, -43, 9, 16, -54, -3, 35, -64, -16, 55, -75, -30, + -76, -1, 68, -58, -12, 54, -38, -23, 41, -19, -33, 27, + 0, -44, 13, 19, -55, 0, 38, -66, -12, 57, -76, -26, + -74, -3, 72, -55, -13, 58, -36, -24, 45, -17, -35, 31, + 2, -46, 17, 21, -56, 4, 40, -67, -8, 59, -78, -22, + -71, -4, 76, -52, -15, 63, -33, -26, 49, -14, -36, 36, + 5, -47, 22, 24, -58, 9, 43, -68, -4, 62, -79, -18, + -69, -6, 80, -50, -16, 67, -31, -27, 53, -12, -38, 40, + 7, -49, 26, 26, -59, 13, 45, -70, 0, 64, -81, -14, + -66, -7, 84, -48, -17, 71, -28, -28, 57, -10, -39, 44, + 10, -50, 30, 29, -61, 17, 47, -71, 3, 67, -82, -10, + -64, -8, 88, -45, -19, 75, -26, -30, 61, -7, -40, 48, + 12, -51, 34, 31, -62, 21, 50, -72, 7, 69, -83, -6, + -62, -10, 92, -43, -20, 79, -24, -31, 65, -5, -42, 52, + 15, -53, 38, 33, -63, 25, 52, -74, 11, 72, -85, -2, + -59, -11, 97, -40, -22, 83, -21, -33, 70, -2, -43, 56, + 17, -54, 42, 36, -65, 29, 55, -75, 16, 74, -86, 2, + -57, -12, 101, -38, -23, 87, -18, -34, 74, 0, -45, 60, + 20, -55, 46, 39, -66, 33, 57, -77, 20, 77, -88, 6, + -54, -14, 105, -35, -24, 91, -16, -35, 78, 3, -46, 64, + 22, -57, 50, 41, -67, 37, 60, -78, 24, 79, -89, 10, + -52, -15, 109, -33, -26, 95, -14, -37, 82, 5, -47, 68, + 25, -58, 54, 43, -69, 41, 62, -79, 28, 81, -90, 14, + -49, -17, 113, -30, -27, 100, -11, -38, 86, 8, -49, 73, + 27, -60, 59, 46, -70, 46, 65, -81, 32, 84, -92, 18, + -47, -18, 117, -28, -29, 104, -9, -40, 90, 10, -50, 77, + 30, -61, 63, 48, -72, 50, 67, -82, 36, 87, -93, 22, + -44, -19, 121, -26, -30, 108, -6, -41, 94, 13, -51, 81, + 32, -62, 67, 51, -73, 54, 70, -84, 40, 89, -95, 26, + -120, 27, -6, -101, 17, -19, -81, 6, -33, -63, -4, -47, + -43, -15, -60, -24, -25, -74, -6, -36, -87, 14, -47, -101, + -117, 26, -2, -98, 15, -15, -79, 4, -29, -60, -5, -43, + -41, -16, -56, -22, -27, -70, -3, -37, -83, 16, -48, -97, + -115, 24, 1, -96, 14, -11, -77, 3, -25, -58, -7, -39, + -38, -18, -52, -20, -28, -66, -1, -39, -79, 18, -50, -93, + -112, 23, 6, -93, 12, -7, -74, 1, -21, -55, -8, -34, + -36, -19, -48, -17, -30, -61, 2, -40, -75, 21, -51, -88, + -110, 22, 10, -91, 11, -3, -72, 0, -17, -53, -10, -30, + -33, -20, -44, -15, -31, -57, 4, -42, -71, 24, -53, -84, + -107, 20, 14, -88, 10, 0, -69, 0, -13, -50, -11, -26, + -31, -22, -40, -12, -32, -53, 7, -43, -67, 26, -54, -80, + -105, 19, 18, -86, 8, 4, -67, -2, -9, -48, -12, -22, + -29, -23, -36, -10, -34, -49, 9, -44, -63, 28, -55, -76, + -102, 17, 22, -83, 7, 9, -64, -3, -4, -45, -14, -18, + -26, -25, -31, -7, -35, -45, 12, -46, -58, 31, -57, -72, + -100, 16, 26, -81, 5, 13, -62, -4, 0, -43, -15, -14, + -23, -26, -27, -5, -37, -41, 14, -47, -54, 33, -58, -68, + -97, 15, 30, -79, 4, 17, -59, -6, 3, -40, -16, -10, + -21, -27, -23, -2, -38, -37, 16, -49, -50, 36, -60, -64, + -95, 13, 34, -76, 3, 21, -57, -7, 7, -38, -18, -6, + -19, -29, -19, 0, -39, -33, 19, -50, -46, 38, -61, -60, + -93, 12, 38, -74, 1, 25, -54, -9, 11, -36, -19, -2, + -16, -30, -15, 2, -41, -29, 21, -51, -42, 41, -62, -56, + -90, 10, 43, -71, 0, 29, -52, -10, 15, -33, -21, 2, + -14, -32, -11, 5, -42, -24, 24, -53, -38, 43, -64, -51, + -88, 9, 47, -69, 0, 33, -49, -11, 19, -31, -22, 6, + -11, -33, -7, 8, -44, -20, 26, -54, -34, 46, -65, -47, + -85, 8, 51, -66, -2, 37, -47, -13, 23, -28, -23, 10, + -9, -34, -3, 10, -45, -16, 29, -55, -30, 48, -66, -43, + -83, 6, 55, -64, -3, 41, -45, -14, 27, -26, -25, 14, + -6, -36, 0, 12, -46, -12, 31, -57, -26, 50, -68, -39, + -80, 5, 59, -61, -5, 46, -42, -16, 32, -23, -26, 18, + -4, -37, 5, 15, -48, -8, 34, -58, -21, 53, -69, -35, + -78, 4, 63, -59, -6, 50, -40, -17, 36, -21, -28, 22, + -1, -39, 9, 17, -49, -4, 36, -60, -17, 56, -71, -31, + -75, 2, 67, -57, -7, 54, -37, -18, 40, -18, -29, 26, + 1, -40, 13, 20, -50, 0, 39, -61, -13, 58, -72, -27, + -73, 1, 71, -54, -9, 58, -35, -20, 44, -16, -30, 30, + 3, -41, 17, 22, -52, 3, 41, -62, -9, 60, -73, -23, + -70, 0, 76, -51, -10, 62, -32, -21, 48, -13, -32, 35, + 6, -43, 21, 25, -53, 8, 44, -64, -5, 63, -75, -18, + -68, -1, 80, -49, -12, 66, -30, -23, 52, -11, -33, 39, + 8, -44, 25, 27, -55, 12, 46, -65, -1, 65, -76, -14, + -65, -2, 84, -47, -13, 70, -27, -24, 56, -8, -34, 43, + 11, -45, 29, 30, -56, 16, 48, -67, 2, 68, -78, -10, + -63, -4, 88, -44, -14, 74, -25, -25, 60, -6, -36, 47, + 13, -47, 33, 32, -57, 20, 51, -68, 6, 70, -79, -6, + -61, -5, 92, -42, -16, 78, -22, -27, 64, -4, -37, 51, + 16, -48, 37, 34, -59, 24, 53, -69, 10, 73, -80, -2, + -58, -7, 96, -39, -17, 83, -20, -28, 69, -1, -39, 55, + 18, -50, 42, 37, -60, 28, 56, -71, 15, 75, -82, 1, + -56, -8, 100, -37, -19, 87, -17, -29, 73, 1, -40, 59, + 21, -51, 46, 40, -62, 32, 58, -72, 19, 78, -83, 5, + -53, -9, 104, -34, -20, 91, -15, -31, 77, 4, -41, 63, + 23, -52, 50, 42, -63, 36, 61, -74, 23, 80, -84, 9, + -51, -11, 108, -32, -21, 95, -13, -32, 81, 6, -43, 67, + 26, -54, 54, 44, -64, 40, 63, -75, 27, 82, -86, 13, + -48, -12, 113, -29, -23, 99, -10, -34, 85, 9, -44, 72, + 28, -55, 58, 47, -66, 45, 66, -76, 31, 85, -87, 18, + -46, -14, 117, -27, -24, 103, -8, -35, 89, 11, -46, 76, + 31, -57, 62, 49, -67, 49, 68, -78, 35, 88, -89, 22, + -43, -15, 121, -25, -25, 107, -5, -36, 93, 14, -47, 80, + 33, -58, 66, 52, -69, 53, 71, -79, 39, 90, -90, 26, + -119, 31, -7, -100, 21, -20, -80, 10, -34, -62, 0, -47, + -42, -11, -61, -24, -21, -74, -5, -32, -88, 15, -43, -102, + -116, 30, -3, -97, 19, -16, -78, 8, -30, -59, -1, -43, + -40, -12, -57, -21, -23, -70, -2, -33, -84, 17, -44, -98, + -114, 28, 0, -95, 18, -12, -76, 7, -26, -57, -3, -39, + -38, -14, -53, -19, -24, -66, 0, -35, -80, 19, -46, -94, + -111, 27, 5, -92, 16, -7, -73, 5, -21, -54, -4, -35, + -35, -15, -48, -16, -26, -62, 3, -36, -75, 22, -47, -89, + -109, 26, 9, -90, 15, -3, -71, 4, -17, -52, -6, -31, + -32, -16, -44, -14, -27, -58, 5, -38, -71, 24, -49, -85, + -106, 24, 13, -88, 14, 0, -68, 3, -13, -49, -7, -27, + -30, -18, -40, -11, -28, -54, 8, -39, -67, 27, -50, -81, + -104, 23, 17, -85, 12, 4, -66, 1, -9, -47, -8, -23, + -28, -19, -36, -9, -30, -50, 10, -40, -63, 29, -51, -77, + -101, 21, 21, -83, 11, 8, -63, 0, -5, -44, -10, -18, + -25, -21, -32, -6, -31, -45, 13, -42, -59, 32, -53, -73, + -99, 20, 25, -80, 9, 12, -61, 0, -1, -42, -11, -14, + -23, -22, -28, -4, -33, -41, 15, -43, -55, 34, -54, -69, + -97, 19, 29, -78, 8, 16, -58, -2, 2, -40, -12, -10, + -20, -23, -24, -1, -34, -37, 17, -45, -51, 37, -56, -65, + -94, 17, 33, -75, 7, 20, -56, -3, 6, -37, -14, -6, + -18, -25, -20, 1, -35, -33, 20, -46, -47, 39, -57, -61, + -92, 16, 37, -73, 5, 24, -54, -5, 10, -35, -15, -2, + -15, -26, -16, 3, -37, -29, 22, -47, -43, 42, -58, -57, + -89, 14, 42, -70, 4, 29, -51, -6, 15, -32, -17, 1, + -13, -28, -11, 6, -38, -25, 25, -49, -38, 44, -60, -52, + -87, 13, 46, -68, 3, 33, -48, -7, 19, -30, -18, 5, + -10, -29, -7, 8, -40, -21, 27, -50, -34, 47, -61, -48, + -84, 12, 50, -65, 1, 37, -46, -9, 23, -27, -19, 9, + -8, -30, -3, 11, -41, -17, 30, -51, -30, 49, -62, -44, + -82, 10, 54, -63, 0, 41, -44, -10, 27, -25, -21, 13, + -6, -32, 0, 13, -42, -13, 32, -53, -26, 51, -64, -40, + -79, 9, 58, -60, -1, 45, -41, -12, 31, -22, -22, 18, + -3, -33, 4, 16, -44, -8, 35, -54, -22, 54, -65, -36, + -77, 8, 62, -58, -2, 49, -39, -13, 35, -20, -24, 22, + 0, -35, 8, 18, -45, -4, 37, -56, -18, 56, -67, -32, + -74, 6, 66, -56, -3, 53, -36, -14, 39, -17, -25, 26, + 2, -36, 12, 21, -46, 0, 40, -57, -14, 59, -68, -28, + -72, 5, 70, -53, -5, 57, -34, -16, 43, -15, -26, 30, + 4, -37, 16, 23, -48, 3, 42, -58, -10, 61, -69, -24, + -69, 3, 75, -51, -6, 62, -31, -17, 48, -12, -28, 34, + 7, -39, 21, 26, -49, 7, 45, -60, -5, 64, -71, -19, + -67, 2, 79, -48, -8, 66, -29, -19, 52, -10, -29, 38, + 9, -40, 25, 28, -51, 11, 47, -61, -1, 66, -72, -15, + -65, 1, 83, -46, -9, 70, -26, -20, 56, -8, -30, 42, + 12, -41, 29, 31, -52, 15, 49, -63, 2, 69, -74, -11, + -62, 0, 87, -43, -10, 74, -24, -21, 60, -5, -32, 46, + 14, -43, 33, 33, -53, 19, 52, -64, 6, 71, -75, -7, + -60, -1, 91, -41, -12, 78, -22, -23, 64, -3, -33, 50, + 17, -44, 37, 35, -55, 23, 54, -65, 10, 74, -76, -3, + -57, -3, 95, -38, -13, 82, -19, -24, 68, 0, -35, 55, + 19, -46, 41, 38, -56, 28, 57, -67, 14, 76, -78, 0, + -55, -4, 99, -36, -15, 86, -16, -25, 72, 2, -36, 59, + 22, -47, 45, 40, -58, 32, 59, -68, 18, 79, -79, 4, + -52, -5, 103, -33, -16, 90, -14, -27, 76, 5, -37, 63, + 24, -48, 49, 43, -59, 36, 62, -70, 22, 81, -80, 8, + -50, -7, 107, -31, -17, 94, -12, -28, 80, 7, -39, 67, + 26, -50, 53, 45, -60, 40, 64, -71, 26, 83, -82, 12, + -47, -8, 112, -28, -19, 99, -9, -30, 85, 10, -40, 71, + 29, -51, 58, 48, -62, 44, 67, -72, 31, 86, -83, 17, + -45, -10, 116, -26, -20, 103, -7, -31, 89, 12, -42, 75, + 32, -53, 62, 50, -63, 48, 69, -74, 35, 88, -85, 21, + -42, -11, 120, -24, -21, 107, -4, -32, 93, 15, -43, 79, + 34, -54, 66, 53, -65, 52, 71, -75, 39, 91, -86, 25, + -118, 35, -7, -99, 25, -21, -80, 14, -34, -61, 3, -48, + -41, -7, -62, -23, -17, -75, -4, -28, -88, 16, -39, -102, + -115, 34, -3, -97, 23, -17, -77, 12, -30, -58, 2, -44, + -39, -8, -58, -20, -19, -71, -1, -29, -84, 18, -40, -98, + -113, 32, 0, -94, 22, -13, -75, 11, -26, -56, 0, -40, + -37, -10, -54, -18, -20, -67, 1, -31, -80, 20, -42, -94, + -110, 31, 4, -91, 20, -8, -72, 9, -22, -53, 0, -35, + -34, -11, -49, -15, -22, -63, 4, -32, -76, 23, -43, -90, + -108, 30, 8, -89, 19, -4, -70, 8, -18, -51, -2, -31, + -32, -12, -45, -13, -23, -59, 6, -34, -72, 25, -45, -86, + -105, 28, 12, -87, 18, 0, -67, 7, -14, -49, -3, -27, + -29, -14, -41, -10, -24, -55, 8, -35, -68, 28, -46, -82, + -103, 27, 16, -84, 16, 3, -65, 5, -10, -46, -4, -23, + -27, -15, -37, -8, -26, -51, 11, -36, -64, 30, -47, -78, + -100, 25, 21, -82, 15, 7, -62, 4, -5, -43, -6, -19, + -24, -17, -33, -5, -27, -46, 14, -38, -59, 33, -49, -73, + -98, 24, 25, -79, 13, 11, -60, 3, -1, -41, -7, -15, + -22, -18, -29, -3, -29, -42, 16, -39, -55, 35, -50, -69, + -96, 23, 29, -77, 12, 15, -57, 1, 2, -39, -8, -11, + -19, -19, -25, 0, -30, -38, 18, -41, -51, 38, -52, -65, + -93, 21, 33, -74, 11, 19, -55, 0, 6, -36, -10, -7, + -17, -21, -21, 2, -31, -34, 21, -42, -47, 40, -53, -61, + -91, 20, 37, -72, 9, 23, -53, -1, 10, -34, -11, -3, + -14, -22, -17, 4, -33, -30, 23, -43, -43, 42, -54, -57, + -88, 18, 41, -69, 8, 28, -50, -2, 14, -31, -13, 1, + -12, -24, -12, 7, -34, -26, 26, -45, -39, 45, -56, -53, + -86, 17, 45, -67, 7, 32, -48, -3, 18, -29, -14, 5, + -9, -25, -8, 9, -36, -22, 28, -46, -35, 48, -57, -49, + -83, 16, 49, -65, 5, 36, -45, -5, 22, -26, -15, 9, + -7, -26, -4, 12, -37, -18, 31, -47, -31, 50, -58, -45, + -81, 14, 53, -62, 4, 40, -43, -6, 26, -24, -17, 13, + -5, -28, 0, 14, -38, -14, 33, -49, -27, 52, -60, -41, + -78, 13, 58, -59, 2, 44, -40, -8, 31, -21, -18, 17, + -2, -29, 3, 17, -40, -9, 36, -50, -22, 55, -61, -36, + -76, 12, 62, -57, 1, 48, -38, -9, 35, -19, -20, 21, + 0, -31, 7, 19, -41, -5, 38, -52, -18, 57, -63, -32, + -73, 10, 66, -55, 0, 52, -35, -10, 39, -17, -21, 25, + 3, -32, 11, 22, -42, -1, 40, -53, -14, 60, -64, -28, + -71, 9, 70, -52, -1, 56, -33, -12, 43, -14, -22, 29, + 5, -33, 15, 24, -44, 2, 43, -54, -10, 62, -65, -24, + -68, 7, 74, -50, -2, 61, -30, -13, 47, -11, -24, 34, + 8, -35, 20, 27, -45, 6, 45, -56, -6, 65, -67, -20, + -66, 6, 78, -47, -4, 65, -28, -15, 51, -9, -25, 38, + 10, -36, 24, 29, -47, 10, 48, -57, -2, 67, -68, -16, + -64, 5, 82, -45, -5, 69, -25, -16, 55, -7, -26, 42, + 13, -37, 28, 31, -48, 14, 50, -59, 1, 70, -70, -12, + -61, 3, 86, -42, -6, 73, -23, -17, 59, -4, -28, 46, + 15, -39, 32, 34, -49, 18, 53, -60, 5, 72, -71, -8, + -59, 2, 90, -40, -8, 77, -21, -19, 63, -2, -29, 50, + 17, -40, 36, 36, -51, 22, 55, -61, 9, 74, -72, -4, + -56, 0, 95, -37, -9, 81, -18, -20, 68, 1, -31, 54, + 20, -42, 40, 39, -52, 27, 58, -63, 14, 77, -74, 0, + -54, 0, 99, -35, -11, 85, -16, -21, 72, 3, -32, 58, + 23, -43, 44, 41, -54, 31, 60, -64, 18, 80, -75, 4, + -51, -1, 103, -33, -12, 89, -13, -23, 76, 6, -33, 62, + 25, -44, 48, 44, -55, 35, 63, -66, 22, 82, -76, 8, + -49, -3, 107, -30, -13, 93, -11, -24, 80, 8, -35, 66, + 27, -46, 52, 46, -56, 39, 65, -67, 26, 84, -78, 12, + -46, -4, 111, -27, -15, 98, -8, -26, 84, 11, -36, 71, + 30, -47, 57, 49, -58, 43, 68, -68, 30, 87, -79, 16, + -44, -6, 115, -25, -16, 102, -6, -27, 88, 13, -38, 75, + 32, -49, 61, 51, -59, 47, 70, -70, 34, 89, -81, 20, + -41, -7, 119, -23, -17, 106, -3, -28, 92, 15, -39, 79, + 35, -50, 65, 54, -61, 51, 72, -71, 38, 92, -82, 24, + -117, 39, -8, -98, 29, -21, -79, 18, -35, -60, 7, -48, + -40, -3, -62, -22, -13, -76, -3, -24, -89, 16, -35, -103, + -114, 38, -4, -96, 27, -17, -76, 16, -31, -57, 6, -44, + -38, -4, -58, -19, -15, -72, -1, -25, -85, 19, -36, -99, + -112, 36, 0, -93, 26, -13, -74, 15, -27, -55, 4, -40, + -36, -6, -54, -17, -16, -68, 2, -27, -81, 21, -38, -95, + -109, 35, 4, -91, 24, -9, -71, 13, -23, -52, 3, -36, + -33, -7, -50, -14, -18, -63, 5, -28, -77, 24, -39, -90, + -107, 34, 8, -88, 23, -5, -69, 12, -19, -50, 1, -32, + -31, -8, -46, -12, -19, -59, 7, -30, -73, 26, -41, -86, + -105, 32, 12, -86, 22, -1, -66, 11, -15, -48, 0, -28, + -28, -10, -42, -9, -20, -55, 9, -31, -69, 29, -42, -82, + -102, 31, 16, -83, 20, 2, -64, 9, -11, -45, 0, -24, + -26, -11, -38, -7, -22, -51, 12, -32, -65, 31, -43, -78, + -99, 29, 20, -81, 19, 7, -61, 8, -6, -43, -2, -19, + -23, -13, -33, -4, -23, -47, 14, -34, -60, 34, -45, -74, + -97, 28, 24, -78, 17, 11, -59, 7, -2, -40, -3, -15, + -21, -14, -29, -2, -25, -43, 17, -35, -56, 36, -46, -70, + -95, 27, 28, -76, 16, 15, -57, 5, 1, -38, -4, -11, + -18, -15, -25, 0, -26, -39, 19, -37, -52, 39, -48, -66, + -92, 25, 32, -74, 15, 19, -54, 4, 5, -35, -6, -7, + -16, -17, -21, 3, -27, -35, 22, -38, -48, 41, -49, -62, + -90, 24, 36, -71, 13, 23, -52, 2, 9, -33, -7, -3, + -14, -18, -17, 5, -29, -31, 24, -39, -44, 43, -50, -58, + -87, 22, 41, -68, 12, 27, -49, 1, 13, -30, -9, 0, + -11, -20, -13, 8, -30, -26, 27, -41, -40, 46, -52, -53, + -85, 21, 45, -66, 11, 31, -47, 0, 17, -28, -10, 4, + -9, -21, -9, 10, -32, -22, 29, -42, -36, 48, -53, -49, + -82, 20, 49, -64, 9, 35, -44, -1, 21, -25, -11, 8, + -6, -22, -5, 13, -33, -18, 31, -43, -32, 51, -54, -45, + -80, 18, 53, -61, 8, 39, -42, -2, 25, -23, -13, 12, + -4, -24, -1, 15, -34, -14, 34, -45, -28, 53, -56, -41, + -77, 17, 57, -59, 6, 44, -39, -4, 30, -20, -14, 17, + -1, -25, 3, 18, -36, -10, 37, -46, -23, 56, -57, -37, + -75, 16, 61, -56, 5, 48, -37, -5, 34, -18, -16, 21, + 1, -27, 7, 20, -37, -6, 39, -48, -19, 58, -59, -33, + -73, 14, 65, -54, 4, 52, -34, -6, 38, -16, -17, 25, + 4, -28, 11, 23, -38, -2, 41, -49, -15, 61, -60, -29, + -70, 13, 69, -51, 2, 56, -32, -8, 42, -13, -18, 29, + 6, -29, 15, 25, -40, 1, 44, -50, -11, 63, -61, -25, + -67, 11, 74, -49, 1, 60, -29, -9, 46, -11, -20, 33, + 9, -31, 19, 28, -41, 6, 46, -52, -7, 66, -63, -20, + -65, 10, 78, -46, 0, 64, -27, -11, 50, -8, -21, 37, + 11, -32, 23, 30, -43, 10, 49, -53, -3, 68, -64, -16, + -63, 9, 82, -44, -1, 68, -25, -12, 54, -6, -22, 41, + 14, -33, 27, 32, -44, 14, 51, -55, 0, 71, -66, -12, + -60, 7, 86, -42, -2, 72, -22, -13, 58, -3, -24, 45, + 16, -35, 31, 35, -45, 18, 54, -56, 4, 73, -67, -8, + -58, 6, 90, -39, -4, 76, -20, -15, 62, -1, -25, 49, + 18, -36, 35, 37, -47, 22, 56, -57, 8, 75, -68, -4, + -55, 4, 94, -36, -5, 81, -17, -16, 67, 2, -27, 54, + 21, -38, 40, 40, -48, 26, 59, -59, 13, 78, -70, 0, + -53, 3, 98, -34, -7, 85, -15, -17, 71, 4, -28, 58, + 23, -39, 44, 42, -50, 30, 61, -60, 17, 80, -71, 3, + -50, 2, 102, -32, -8, 89, -12, -19, 75, 7, -29, 62, + 26, -40, 48, 45, -51, 34, 63, -62, 21, 83, -72, 7, + -48, 0, 106, -29, -9, 93, -10, -20, 79, 9, -31, 66, + 28, -42, 52, 47, -52, 38, 66, -63, 25, 85, -74, 11, + -45, 0, 111, -27, -11, 97, -7, -22, 83, 12, -32, 70, + 31, -43, 56, 50, -54, 43, 69, -64, 29, 88, -75, 16, + -43, -2, 115, -24, -12, 101, -5, -23, 87, 14, -34, 74, + 33, -45, 60, 52, -55, 47, 71, -66, 33, 90, -77, 20, + -41, -3, 119, -22, -13, 105, -2, -24, 91, 16, -35, 78, + 36, -46, 64, 55, -57, 51, 73, -67, 37, 93, -78, 24, + -116, 43, -8, -97, 33, -22, -78, 22, -36, -59, 11, -49, + -40, 0, -63, -21, -9, -76, -2, -20, -90, 17, -31, -104, + -113, 42, -4, -95, 31, -18, -75, 20, -32, -57, 10, -45, + -37, 0, -59, -18, -11, -72, 0, -21, -86, 20, -32, -100, + -111, 40, 0, -92, 30, -14, -73, 19, -28, -54, 8, -41, + -35, -2, -55, -16, -12, -68, 3, -23, -82, 22, -34, -96, + -108, 39, 3, -90, 28, -9, -70, 17, -23, -51, 7, -37, + -32, -3, -50, -13, -14, -64, 5, -24, -77, 25, -35, -91, + -106, 38, 7, -87, 27, -5, -68, 16, -19, -49, 5, -33, + -30, -4, -46, -11, -15, -60, 8, -26, -73, 27, -37, -87, + -104, 36, 11, -85, 26, -1, -65, 15, -15, -47, 4, -29, + -27, -6, -42, -9, -16, -56, 10, -27, -69, 30, -38, -83, + -101, 35, 15, -82, 24, 2, -63, 13, -11, -44, 3, -25, + -25, -7, -38, -6, -18, -52, 13, -28, -65, 32, -39, -79, + -99, 33, 20, -80, 23, 6, -60, 12, -7, -42, 1, -20, + -22, -9, -34, -3, -19, -47, 15, -30, -61, 35, -41, -75, + -96, 32, 24, -77, 21, 10, -58, 11, -3, -39, 0, -16, + -20, -10, -30, -1, -21, -43, 18, -31, -57, 37, -42, -71, + -94, 31, 28, -75, 20, 14, -56, 9, 0, -37, 0, -12, + -17, -11, -26, 1, -22, -39, 20, -33, -53, 39, -44, -67, + -91, 29, 32, -73, 19, 18, -53, 8, 4, -34, -2, -8, + -15, -13, -22, 4, -23, -35, 23, -34, -49, 42, -45, -63, + -89, 28, 36, -70, 17, 22, -51, 6, 8, -32, -3, -4, + -13, -14, -18, 6, -25, -31, 25, -35, -45, 44, -46, -59, + -86, 26, 40, -68, 16, 27, -48, 5, 13, -29, -5, 0, + -10, -16, -13, 9, -26, -27, 28, -37, -40, 47, -48, -54, + -84, 25, 44, -65, 15, 31, -46, 4, 17, -27, -6, 3, + -8, -17, -9, 11, -28, -23, 30, -38, -36, 49, -49, -50, + -82, 24, 48, -63, 13, 35, -43, 2, 21, -25, -7, 7, + -5, -18, -5, 14, -29, -19, 32, -39, -32, 52, -50, -46, + -79, 22, 52, -60, 12, 39, -41, 1, 25, -22, -9, 11, + -3, -20, -1, 16, -30, -15, 35, -41, -28, 54, -52, -42, + -76, 21, 57, -58, 10, 43, -38, 0, 29, -19, -10, 16, + 0, -21, 2, 19, -32, -10, 37, -42, -24, 57, -53, -38, + -74, 20, 61, -55, 9, 47, -36, -1, 33, -17, -12, 20, + 2, -23, 6, 21, -33, -6, 40, -44, -20, 59, -55, -34, + -72, 18, 65, -53, 8, 51, -33, -2, 37, -15, -13, 24, + 5, -24, 10, 23, -34, -2, 42, -45, -16, 62, -56, -30, + -69, 17, 69, -50, 6, 55, -31, -4, 41, -12, -14, 28, + 7, -25, 14, 26, -36, 1, 45, -46, -12, 64, -57, -26, + -67, 15, 73, -48, 5, 60, -28, -5, 46, -10, -16, 32, + 10, -27, 19, 29, -37, 5, 47, -48, -7, 67, -59, -21, + -64, 14, 77, -45, 3, 64, -26, -7, 50, -7, -17, 36, + 12, -28, 23, 31, -39, 9, 50, -49, -3, 69, -60, -17, + -62, 13, 81, -43, 2, 68, -24, -8, 54, -5, -18, 40, + 15, -29, 27, 33, -40, 13, 52, -51, 0, 71, -62, -13, + -59, 11, 85, -41, 1, 72, -21, -9, 58, -2, -20, 44, + 17, -31, 31, 36, -41, 17, 54, -52, 4, 74, -63, -9, + -57, 10, 89, -38, 0, 76, -19, -11, 62, 0, -21, 48, + 19, -32, 35, 38, -43, 21, 57, -53, 8, 76, -64, -5, + -54, 8, 94, -36, -1, 80, -16, -12, 66, 3, -23, 53, + 22, -34, 39, 41, -44, 26, 60, -55, 12, 79, -66, -1, + -52, 7, 98, -33, -3, 84, -14, -13, 70, 5, -24, 57, + 24, -35, 43, 43, -46, 30, 62, -56, 16, 81, -67, 2, + -50, 6, 102, -31, -4, 88, -11, -15, 74, 7, -25, 61, + 27, -36, 47, 46, -47, 34, 64, -58, 20, 84, -68, 6, + -47, 4, 106, -28, -5, 92, -9, -16, 78, 10, -27, 65, + 29, -38, 51, 48, -48, 38, 67, -59, 24, 86, -70, 10, + -44, 3, 110, -26, -7, 97, -6, -18, 83, 13, -28, 69, + 32, -39, 56, 51, -50, 42, 69, -60, 29, 89, -71, 15, + -42, 1, 114, -23, -8, 101, -4, -19, 87, 15, -30, 73, + 34, -41, 60, 53, -51, 46, 72, -62, 33, 91, -73, 19, + -40, 0, 118, -21, -9, 105, -1, -20, 91, 17, -31, 77, + 37, -42, 64, 55, -53, 50, 74, -63, 37, 94, -74, 23, + -115, 48, -9, -96, 37, -23, -77, 26, -36, -58, 16, -50, + -39, 5, -64, -20, -5, -77, -1, -16, -90, 18, -27, -104, + -112, 46, -5, -94, 36, -19, -74, 25, -32, -56, 14, -46, + -36, 3, -60, -17, -6, -73, 1, -17, -86, 21, -28, -100, + -110, 45, -1, -91, 34, -15, -72, 23, -28, -53, 13, -42, + -34, 2, -56, -15, -8, -69, 4, -18, -82, 23, -29, -96, + -107, 43, 2, -89, 33, -10, -69, 22, -24, -50, 11, -37, + -31, 0, -51, -12, -9, -65, 6, -20, -78, 26, -31, -92, + -105, 42, 6, -86, 32, -6, -67, 21, -20, -48, 10, -33, + -29, 0, -47, -10, -11, -61, 9, -21, -74, 28, -32, -88, + -103, 41, 10, -84, 30, -2, -64, 19, -16, -46, 9, -29, + -26, -1, -43, -8, -12, -57, 11, -23, -70, 31, -33, -84, + -100, 39, 14, -81, 29, 1, -62, 18, -12, -43, 7, -25, + -24, -3, -39, -5, -13, -53, 14, -24, -66, 33, -35, -80, + -98, 38, 19, -79, 27, 5, -59, 16, -7, -41, 6, -21, + -21, -4, -35, -2, -15, -48, 16, -25, -61, 36, -36, -75, + -95, 37, 23, -76, 26, 9, -57, 15, -3, -38, 4, -17, + -19, -6, -31, 0, -16, -44, 19, -27, -57, 38, -38, -71, + -93, 35, 27, -74, 25, 13, -55, 14, 0, -36, 3, -13, + -16, -7, -27, 2, -17, -40, 21, -28, -53, 41, -39, -67, + -90, 34, 31, -72, 23, 17, -52, 12, 4, -33, 2, -9, + -14, -8, -23, 5, -19, -36, 24, -29, -49, 43, -40, -63, + -88, 32, 35, -69, 22, 21, -50, 11, 8, -31, 0, -5, + -12, -10, -19, 7, -20, -32, 26, -31, -45, 45, -42, -59, + -85, 31, 39, -66, 20, 26, -47, 9, 12, -28, 0, 0, + -9, -11, -14, 10, -22, -28, 29, -32, -41, 48, -43, -55, + -83, 30, 43, -64, 19, 30, -45, 8, 16, -26, -2, 3, + -7, -12, -10, 12, -23, -24, 31, -34, -37, 50, -45, -51, + -80, 28, 47, -62, 18, 34, -42, 7, 20, -24, -3, 7, + -4, -14, -6, 15, -24, -20, 33, -35, -33, 53, -46, -47, + -78, 27, 51, -59, 16, 38, -40, 5, 24, -21, -4, 11, + -2, -15, -2, 17, -26, -16, 36, -36, -29, 55, -47, -43, + -75, 25, 56, -57, 15, 42, -37, 4, 29, -18, -6, 15, + 1, -17, 1, 20, -27, -11, 38, -38, -24, 58, -49, -38, + -73, 24, 60, -54, 13, 46, -35, 3, 33, -16, -7, 19, + 3, -18, 5, 22, -29, -7, 41, -39, -20, 60, -50, -34, + -71, 23, 64, -52, 12, 50, -32, 1, 37, -14, -8, 23, + 6, -19, 9, 24, -30, -3, 43, -41, -16, 63, -51, -30, + -68, 21, 68, -49, 11, 54, -30, 0, 41, -11, -10, 27, + 8, -21, 13, 27, -31, 0, 46, -42, -12, 65, -53, -26, + -66, 20, 72, -47, 9, 59, -27, -1, 45, -9, -11, 32, + 11, -22, 18, 30, -33, 4, 48, -43, -8, 68, -54, -22, + -63, 18, 76, -44, 8, 63, -25, -2, 49, -6, -13, 36, + 13, -24, 22, 32, -34, 8, 51, -45, -4, 70, -56, -18, + -61, 17, 80, -42, 7, 67, -23, -3, 53, -4, -14, 40, + 16, -25, 26, 34, -36, 12, 53, -46, 0, 73, -57, -14, + -58, 16, 84, -40, 5, 71, -20, -5, 57, -1, -15, 44, + 18, -26, 30, 37, -37, 16, 56, -47, 3, 75, -58, -10, + -56, 14, 88, -37, 4, 75, -18, -6, 61, 1, -17, 48, + 20, -28, 34, 39, -38, 20, 58, -49, 7, 77, -60, -6, + -53, 13, 93, -34, 2, 79, -15, -8, 66, 4, -18, 52, + 23, -29, 38, 42, -40, 25, 61, -50, 12, 80, -61, -1, + -51, 12, 97, -32, 1, 83, -13, -9, 70, 6, -20, 56, + 25, -30, 42, 44, -41, 29, 63, -52, 16, 82, -63, 2, + -48, 10, 101, -30, 0, 87, -10, -10, 74, 8, -21, 60, + 28, -32, 46, 47, -42, 33, 65, -53, 20, 85, -64, 6, + -46, 9, 105, -27, -1, 91, -8, -12, 78, 11, -22, 64, + 30, -33, 50, 49, -44, 37, 68, -54, 24, 87, -65, 10, + -43, 7, 109, -25, -2, 96, -5, -13, 82, 14, -24, 69, + 33, -35, 55, 52, -45, 41, 70, -56, 28, 90, -67, 14, + -41, 6, 113, -22, -4, 100, -3, -15, 86, 16, -25, 73, + 35, -36, 59, 54, -47, 45, 73, -57, 32, 92, -68, 18, + -39, 5, 117, -20, -5, 104, 0, -16, 90, 18, -26, 77, + 38, -37, 63, 56, -48, 49, 75, -59, 36, 95, -70, 22, + -114, 52, -10, -95, 41, -23, -76, 30, -37, -57, 20, -50, + -38, 9, -64, -19, -1, -78, 0, -12, -91, 19, -23, -105, + -112, 50, -6, -93, 40, -19, -73, 29, -33, -55, 18, -46, + -35, 7, -60, -16, -2, -74, 2, -13, -87, 22, -24, -101, + -109, 49, -2, -90, 38, -15, -71, 27, -29, -52, 17, -42, + -33, 6, -56, -14, -4, -70, 5, -14, -83, 24, -25, -97, + -106, 47, 2, -88, 37, -11, -68, 26, -25, -50, 15, -38, + -30, 4, -52, -11, -5, -65, 7, -16, -79, 27, -27, -92, + -104, 46, 6, -85, 36, -7, -66, 25, -21, -47, 14, -34, + -28, 3, -48, -9, -7, -61, 10, -17, -75, 29, -28, -88, + -102, 45, 10, -83, 34, -3, -64, 23, -17, -45, 13, -30, + -25, 2, -44, -7, -8, -57, 12, -19, -71, 32, -29, -84, + -99, 43, 14, -81, 33, 0, -61, 22, -13, -42, 11, -26, + -23, 0, -40, -4, -9, -53, 15, -20, -67, 34, -31, -80, + -97, 42, 18, -78, 31, 5, -58, 20, -8, -40, 10, -21, + -20, 0, -35, -2, -11, -49, 17, -21, -62, 37, -32, -76, + -94, 41, 22, -75, 30, 9, -56, 19, -4, -37, 8, -17, + -18, -2, -31, 1, -12, -45, 20, -23, -58, 39, -34, -72, + -92, 39, 26, -73, 29, 13, -54, 18, 0, -35, 7, -13, + -16, -3, -27, 3, -13, -41, 22, -24, -54, 41, -35, -68, + -89, 38, 30, -71, 27, 17, -51, 16, 3, -32, 6, -9, + -13, -4, -23, 6, -15, -37, 24, -25, -50, 44, -36, -64, + -87, 36, 34, -68, 26, 21, -49, 15, 7, -30, 4, -5, + -11, -6, -19, 8, -16, -33, 27, -27, -46, 46, -38, -60, + -84, 35, 39, -66, 24, 25, -46, 13, 11, -27, 3, -1, + -8, -7, -15, 11, -18, -28, 30, -28, -42, 49, -39, -55, + -82, 34, 43, -63, 23, 29, -44, 12, 15, -25, 1, 2, + -6, -8, -11, 13, -19, -24, 32, -30, -38, 51, -41, -51, + -80, 32, 47, -61, 22, 33, -41, 11, 19, -23, 0, 6, + -3, -10, -7, 16, -20, -20, 34, -31, -34, 54, -42, -47, + -77, 31, 51, -58, 20, 37, -39, 9, 23, -20, 0, 10, + -1, -11, -3, 18, -22, -16, 37, -32, -30, 56, -43, -43, + -74, 29, 55, -56, 19, 42, -36, 8, 28, -18, -2, 15, + 2, -13, 1, 21, -23, -12, 39, -34, -25, 59, -45, -39, + -72, 28, 59, -53, 17, 46, -34, 7, 32, -15, -3, 19, + 4, -14, 5, 23, -25, -8, 42, -35, -21, 61, -46, -35, + -70, 27, 63, -51, 16, 50, -32, 5, 36, -13, -4, 23, + 7, -15, 9, 25, -26, -4, 44, -37, -17, 64, -47, -31, + -67, 25, 67, -49, 15, 54, -29, 4, 40, -10, -6, 27, + 9, -17, 13, 28, -27, 0, 47, -38, -13, 66, -49, -27, + -65, 24, 72, -46, 13, 58, -26, 2, 44, -8, -7, 31, + 12, -18, 17, 30, -29, 4, 49, -39, -9, 69, -50, -22, + -62, 22, 76, -43, 12, 62, -24, 1, 48, -5, -9, 35, + 14, -20, 21, 33, -30, 8, 52, -41, -5, 71, -52, -18, + -60, 21, 80, -41, 11, 66, -22, 0, 52, -3, -10, 39, + 16, -21, 25, 35, -32, 12, 54, -42, -1, 73, -53, -14, + -57, 20, 84, -39, 9, 70, -19, -1, 56, -1, -11, 43, + 19, -22, 29, 38, -33, 16, 56, -43, 2, 76, -54, -10, + -55, 18, 88, -36, 8, 74, -17, -2, 60, 2, -13, 47, + 21, -24, 33, 40, -34, 20, 59, -45, 6, 78, -56, -6, + -52, 17, 92, -34, 6, 79, -14, -4, 65, 5, -14, 52, + 24, -25, 38, 43, -36, 24, 62, -46, 11, 81, -57, -2, + -50, 16, 96, -31, 5, 83, -12, -5, 69, 7, -16, 56, + 26, -26, 42, 45, -37, 28, 64, -48, 15, 83, -59, 1, + -48, 14, 100, -29, 4, 87, -9, -6, 73, 9, -17, 60, + 29, -28, 46, 48, -38, 32, 66, -49, 19, 86, -60, 5, + -45, 13, 104, -26, 2, 91, -7, -8, 77, 12, -18, 64, + 31, -29, 50, 50, -40, 36, 69, -50, 23, 88, -61, 9, + -42, 11, 109, -24, 1, 95, -4, -9, 81, 14, -20, 68, + 34, -31, 54, 53, -41, 41, 71, -52, 27, 91, -63, 14, + -40, 10, 113, -21, 0, 99, -2, -11, 85, 17, -21, 72, + 36, -32, 58, 55, -43, 45, 74, -53, 31, 93, -64, 18, + -38, 9, 117, -19, -1, 103, 0, -12, 89, 19, -22, 76, + 39, -33, 62, 57, -44, 49, 76, -55, 35, 96, -66, 22, + -113, 56, -11, -94, 45, -24, -75, 34, -38, -56, 24, -51, + -37, 13, -65, -18, 2, -78, 1, -8, -92, 20, -19, -106, + -111, 54, -7, -92, 44, -20, -72, 33, -34, -54, 22, -47, + -34, 11, -61, -16, 1, -74, 3, -9, -88, 23, -20, -102, + -108, 53, -3, -89, 42, -16, -70, 31, -30, -51, 21, -43, + -32, 10, -57, -13, 0, -70, 6, -10, -84, 25, -21, -98, + -106, 51, 1, -87, 41, -11, -67, 30, -25, -49, 19, -39, + -29, 8, -52, -10, -1, -66, 8, -12, -79, 28, -23, -93, + -103, 50, 5, -84, 40, -7, -65, 29, -21, -46, 18, -35, + -27, 7, -48, -8, -3, -62, 11, -13, -75, 30, -24, -89, + -101, 49, 9, -82, 38, -3, -63, 27, -17, -44, 17, -31, + -24, 6, -44, -6, -4, -58, 13, -15, -71, 32, -25, -85, + -98, 47, 13, -80, 37, 0, -60, 26, -13, -41, 15, -27, + -22, 4, -40, -3, -5, -54, 15, -16, -67, 35, -27, -81, + -96, 46, 17, -77, 35, 4, -58, 24, -9, -39, 14, -22, + -19, 3, -36, -1, -7, -49, 18, -17, -63, 38, -28, -77, + -93, 45, 21, -75, 34, 8, -55, 23, -5, -36, 12, -18, + -17, 1, -32, 2, -8, -45, 21, -19, -59, 40, -30, -73, + -91, 43, 25, -72, 33, 12, -53, 22, -1, -34, 11, -14, + -15, 0, -28, 4, -9, -41, 23, -20, -55, 42, -31, -69, + -89, 42, 29, -70, 31, 16, -50, 20, 2, -32, 10, -10, + -12, 0, -24, 7, -11, -37, 25, -21, -51, 45, -32, -65, + -86, 40, 33, -67, 30, 20, -48, 19, 6, -29, 8, -6, + -10, -2, -20, 9, -12, -33, 28, -23, -47, 47, -34, -61, + -83, 39, 38, -65, 28, 25, -45, 17, 11, -27, 7, -2, + -7, -3, -15, 12, -14, -29, 30, -24, -42, 50, -35, -56, + -81, 38, 42, -62, 27, 29, -43, 16, 15, -24, 5, 1, + -5, -4, -11, 14, -15, -25, 33, -26, -38, 52, -37, -52, + -79, 36, 46, -60, 26, 33, -41, 15, 19, -22, 4, 5, + -2, -6, -7, 16, -16, -21, 35, -27, -34, 55, -38, -48, + -76, 35, 50, -57, 24, 37, -38, 13, 23, -19, 3, 9, + 0, -7, -3, 19, -18, -17, 38, -28, -30, 57, -39, -44, + -74, 33, 54, -55, 23, 41, -35, 12, 27, -17, 1, 14, + 3, -9, 0, 22, -19, -12, 40, -30, -26, 60, -41, -40, + -71, 32, 58, -52, 21, 45, -33, 11, 31, -14, 0, 18, + 5, -10, 4, 24, -21, -8, 43, -31, -22, 62, -42, -36, + -69, 31, 62, -50, 20, 49, -31, 9, 35, -12, 0, 22, + 8, -11, 8, 26, -22, -4, 45, -33, -18, 64, -43, -32, + -66, 29, 66, -48, 19, 53, -28, 8, 39, -9, -2, 26, + 10, -13, 12, 29, -23, 0, 47, -34, -14, 67, -45, -28, + -64, 28, 71, -45, 17, 58, -26, 6, 44, -7, -3, 30, + 13, -14, 17, 31, -25, 3, 50, -35, -9, 70, -46, -23, + -61, 26, 75, -43, 16, 62, -23, 5, 48, -4, -5, 34, + 15, -16, 21, 34, -26, 7, 53, -37, -5, 72, -48, -19, + -59, 25, 79, -40, 15, 66, -21, 4, 52, -2, -6, 38, + 17, -17, 25, 36, -28, 11, 55, -38, -1, 74, -49, -15, + -57, 24, 83, -38, 13, 70, -18, 2, 56, 0, -7, 42, + 20, -18, 29, 39, -29, 15, 57, -39, 2, 77, -50, -11, + -54, 22, 87, -35, 12, 74, -16, 1, 60, 3, -9, 46, + 22, -20, 33, 41, -30, 19, 60, -41, 6, 79, -52, -7, + -51, 21, 91, -33, 10, 78, -13, 0, 64, 5, -10, 51, + 25, -21, 37, 44, -32, 24, 62, -42, 10, 82, -53, -3, + -49, 20, 95, -30, 9, 82, -11, -1, 68, 8, -12, 55, + 27, -22, 41, 46, -33, 28, 65, -44, 14, 84, -55, 0, + -47, 18, 99, -28, 8, 86, -9, -2, 72, 10, -13, 59, + 30, -24, 45, 48, -34, 32, 67, -45, 18, 87, -56, 4, + -44, 17, 103, -25, 6, 90, -6, -4, 76, 13, -14, 63, + 32, -25, 49, 51, -36, 36, 70, -46, 22, 89, -57, 8, + -42, 15, 108, -23, 5, 95, -3, -5, 81, 15, -16, 67, + 35, -27, 54, 54, -37, 40, 72, -48, 27, 92, -59, 13, + -39, 14, 112, -20, 3, 99, -1, -7, 85, 18, -17, 71, + 37, -28, 58, 56, -39, 44, 75, -49, 31, 94, -60, 17, + -37, 13, 116, -18, 2, 103, 1, -8, 89, 20, -18, 75, + 40, -29, 62, 58, -40, 48, 77, -51, 35, 96, -62, 21, + -112, 60, -11, -93, 49, -25, -74, 38, -38, -55, 28, -52, + -36, 17, -66, -17, 6, -79, 2, -4, -92, 21, -15, -106, + -110, 58, -7, -91, 48, -21, -72, 37, -34, -53, 26, -48, + -33, 15, -62, -15, 5, -75, 4, -5, -88, 24, -16, -102, + -107, 57, -3, -89, 46, -17, -69, 35, -30, -50, 25, -44, + -31, 14, -58, -12, 3, -71, 7, -6, -84, 26, -17, -98, + -105, 55, 0, -86, 45, -12, -66, 34, -26, -48, 23, -39, + -28, 12, -53, -10, 2, -67, 9, -8, -80, 29, -19, -94, + -102, 54, 4, -83, 44, -8, -64, 33, -22, -45, 22, -35, + -26, 11, -49, -7, 0, -63, 12, -9, -76, 31, -20, -90, + -100, 53, 8, -81, 42, -4, -62, 31, -18, -43, 21, -31, + -24, 10, -45, -5, 0, -59, 14, -11, -72, 33, -21, -86, + -97, 51, 12, -79, 41, 0, -59, 30, -14, -41, 19, -27, + -21, 8, -41, -2, -1, -55, 16, -12, -68, 36, -23, -82, + -95, 50, 17, -76, 39, 3, -57, 28, -9, -38, 18, -23, + -18, 7, -37, 0, -3, -50, 19, -13, -63, 38, -24, -77, + -92, 49, 21, -74, 38, 7, -54, 27, -5, -35, 16, -19, + -16, 5, -33, 3, -4, -46, 21, -15, -59, 41, -26, -73, + -90, 47, 25, -71, 37, 11, -52, 26, -1, -33, 15, -15, + -14, 4, -29, 5, -5, -42, 24, -16, -55, 43, -27, -69, + -88, 46, 29, -69, 35, 15, -49, 24, 2, -31, 14, -11, + -11, 3, -25, 7, -7, -38, 26, -17, -51, 46, -28, -65, + -85, 44, 33, -66, 34, 19, -47, 23, 6, -28, 12, -7, + -9, 1, -21, 10, -8, -34, 29, -19, -47, 48, -30, -61, + -83, 43, 37, -64, 32, 24, -44, 21, 10, -26, 11, -2, + -6, 0, -16, 13, -10, -30, 31, -20, -43, 51, -31, -57, + -80, 42, 41, -61, 31, 28, -42, 20, 14, -23, 9, 1, + -4, 0, -12, 15, -11, -26, 34, -22, -39, 53, -33, -53, + -78, 40, 45, -59, 30, 32, -40, 19, 18, -21, 8, 5, + -1, -2, -8, 17, -12, -22, 36, -23, -35, 56, -34, -49, + -75, 39, 49, -57, 28, 36, -37, 17, 22, -18, 7, 9, + 1, -3, -4, 20, -14, -18, 39, -24, -31, 58, -35, -45, + -73, 37, 54, -54, 27, 40, -35, 16, 27, -16, 5, 13, + 4, -5, 0, 22, -15, -13, 41, -26, -26, 61, -37, -40, + -70, 36, 58, -51, 25, 44, -32, 15, 31, -13, 4, 17, + 6, -6, 3, 25, -17, -9, 44, -27, -22, 63, -38, -36, + -68, 35, 62, -49, 24, 48, -30, 13, 35, -11, 3, 21, + 8, -7, 7, 27, -18, -5, 46, -29, -18, 65, -39, -32, + -65, 33, 66, -47, 23, 52, -27, 12, 39, -9, 1, 25, + 11, -9, 11, 30, -19, -1, 48, -30, -14, 68, -41, -28, + -63, 32, 70, -44, 21, 57, -25, 10, 43, -6, 0, 30, + 14, -10, 16, 32, -21, 2, 51, -31, -10, 70, -42, -24, + -60, 30, 74, -42, 20, 61, -22, 9, 47, -3, -1, 34, + 16, -12, 20, 35, -22, 6, 53, -33, -6, 73, -44, -20, + -58, 29, 78, -39, 19, 65, -20, 8, 51, -1, -2, 38, + 18, -13, 24, 37, -24, 10, 56, -34, -2, 75, -45, -16, + -56, 28, 82, -37, 17, 69, -17, 6, 55, 1, -3, 42, + 21, -14, 28, 39, -25, 14, 58, -35, 1, 78, -46, -12, + -53, 26, 86, -34, 16, 73, -15, 5, 59, 4, -5, 46, + 23, -16, 32, 42, -26, 18, 61, -37, 5, 80, -48, -8, + -51, 25, 91, -32, 14, 77, -12, 3, 64, 6, -6, 50, + 26, -17, 36, 45, -28, 23, 63, -38, 10, 83, -49, -3, + -48, 24, 95, -29, 13, 81, -10, 2, 68, 9, -8, 54, + 28, -18, 40, 47, -29, 27, 66, -40, 14, 85, -51, 0, + -46, 22, 99, -27, 12, 85, -8, 1, 72, 11, -9, 58, + 31, -20, 44, 49, -30, 31, 68, -41, 18, 87, -52, 4, + -43, 21, 103, -25, 10, 89, -5, 0, 76, 14, -10, 62, + 33, -21, 48, 52, -32, 35, 71, -42, 22, 90, -53, 8, + -41, 19, 107, -22, 9, 94, -3, -1, 80, 16, -12, 67, + 36, -23, 53, 54, -33, 39, 73, -44, 26, 93, -55, 12, + -38, 18, 111, -19, 7, 98, 0, -3, 84, 19, -13, 71, + 38, -24, 57, 57, -35, 43, 76, -45, 30, 95, -56, 16, + -36, 17, 115, -17, 6, 102, 2, -4, 88, 21, -14, 75, + 40, -25, 61, 59, -36, 47, 78, -47, 34, 97, -58, 20, + -111, 64, -12, -92, 54, -25, -73, 43, -39, -54, 32, -53, + -35, 21, -66, -16, 11, -80, 3, 0, -93, 22, -10, -107, + -109, 63, -8, -90, 52, -21, -71, 41, -35, -52, 31, -49, + -32, 20, -62, -14, 9, -76, 5, 0, -89, 25, -11, -103, + -106, 61, -4, -88, 51, -17, -68, 40, -31, -49, 29, -45, + -30, 18, -58, -11, 8, -72, 8, -2, -85, 27, -13, -99, + -104, 60, 0, -85, 49, -13, -65, 38, -27, -47, 28, -40, + -27, 17, -54, -9, 6, -67, 10, -3, -81, 30, -14, -94, + -101, 59, 4, -82, 48, -9, -63, 37, -23, -44, 26, -36, + -25, 16, -50, -6, 5, -63, 13, -5, -77, 32, -16, -90, + -99, 57, 8, -80, 47, -5, -61, 36, -19, -42, 25, -32, + -23, 14, -46, -4, 4, -59, 15, -6, -73, 34, -17, -86, + -96, 56, 12, -78, 45, -1, -58, 34, -15, -40, 24, -28, + -20, 13, -42, -1, 2, -55, 17, -7, -69, 37, -18, -82, + -94, 54, 16, -75, 44, 3, -56, 33, -10, -37, 22, -24, + -17, 11, -37, 1, 1, -51, 20, -9, -64, 39, -20, -78, + -91, 53, 20, -73, 42, 7, -53, 32, -6, -34, 21, -20, + -15, 10, -33, 4, 0, -47, 23, -10, -60, 42, -21, -74, + -89, 52, 24, -70, 41, 11, -51, 30, -2, -32, 20, -16, + -13, 9, -29, 6, -1, -43, 25, -12, -56, 44, -23, -70, + -87, 50, 28, -68, 40, 15, -48, 29, 1, -30, 18, -12, + -10, 7, -25, 9, -2, -39, 27, -13, -52, 47, -24, -66, + -84, 49, 32, -65, 38, 19, -46, 27, 5, -27, 17, -8, + -8, 6, -21, 11, -4, -35, 30, -14, -48, 49, -25, -62, + -82, 47, 37, -63, 37, 23, -43, 26, 9, -25, 15, -3, + -5, 4, -17, 14, -5, -30, 32, -16, -44, 52, -27, -57, + -79, 46, 41, -60, 36, 27, -41, 25, 13, -22, 14, 0, + -3, 3, -13, 16, -7, -26, 35, -17, -40, 54, -28, -53, + -77, 45, 45, -58, 34, 31, -39, 23, 17, -20, 13, 4, + 0, 2, -9, 18, -8, -22, 37, -18, -36, 57, -29, -49, + -74, 43, 49, -56, 33, 35, -36, 22, 21, -17, 11, 8, + 2, 0, -5, 21, -9, -18, 40, -20, -32, 59, -31, -45, + -72, 42, 53, -53, 31, 40, -33, 20, 26, -15, 10, 12, + 5, 0, 0, 23, -11, -14, 42, -21, -27, 62, -32, -41, + -69, 41, 57, -50, 30, 44, -31, 19, 30, -12, 8, 16, + 7, -2, 3, 26, -12, -10, 45, -23, -23, 64, -34, -37, + -67, 39, 61, -48, 29, 48, -29, 18, 34, -10, 7, 20, + 9, -3, 7, 28, -13, -6, 47, -24, -19, 66, -35, -33, + -64, 38, 65, -46, 27, 52, -26, 16, 38, -8, 6, 24, + 12, -4, 11, 31, -15, -2, 49, -25, -15, 69, -36, -29, + -62, 36, 70, -43, 26, 56, -24, 15, 42, -5, 4, 29, + 15, -6, 15, 33, -16, 2, 52, -27, -11, 71, -38, -24, + -59, 35, 74, -41, 24, 60, -21, 13, 46, -2, 3, 33, + 17, -7, 19, 36, -18, 6, 55, -28, -7, 74, -39, -20, + -57, 34, 78, -38, 23, 64, -19, 12, 50, 0, 2, 37, + 19, -8, 23, 38, -19, 10, 57, -30, -3, 76, -41, -16, + -55, 32, 82, -36, 22, 68, -16, 11, 54, 2, 0, 41, + 22, -10, 27, 41, -20, 14, 59, -31, 0, 79, -42, -12, + -52, 31, 86, -33, 20, 72, -14, 9, 58, 5, 0, 45, + 24, -11, 31, 43, -22, 18, 62, -32, 4, 81, -43, -8, + -50, 29, 90, -31, 19, 77, -11, 8, 63, 7, -2, 49, + 27, -13, 36, 46, -23, 22, 64, -34, 9, 84, -45, -4, + -47, 28, 94, -28, 17, 81, -9, 7, 67, 10, -3, 53, + 29, -14, 40, 48, -25, 26, 67, -35, 13, 86, -46, 0, + -45, 27, 98, -26, 16, 85, -7, 5, 71, 12, -4, 57, + 32, -15, 44, 50, -26, 30, 69, -37, 17, 89, -47, 3, + -42, 25, 102, -24, 15, 89, -4, 4, 75, 15, -6, 61, + 34, -17, 48, 53, -27, 34, 72, -38, 21, 91, -49, 7, + -40, 24, 107, -21, 13, 93, -1, 2, 79, 17, -7, 66, + 37, -18, 52, 55, -29, 39, 74, -39, 25, 94, -50, 12, + -37, 22, 111, -18, 12, 97, 1, 1, 83, 20, -9, 70, + 39, -20, 56, 58, -30, 43, 77, -41, 29, 96, -52, 16, + -35, 21, 115, -16, 11, 101, 3, 0, 87, 22, -10, 74, + 41, -21, 60, 60, -32, 47, 79, -42, 33, 98, -53, 20, + -110, 68, -13, -91, 58, -26, -72, 47, -40, -53, 36, -53, + -34, 25, -67, -15, 15, -80, 4, 4, -94, 23, -6, -108, + -108, 67, -9, -89, 56, -22, -70, 45, -36, -51, 35, -49, + -31, 24, -63, -13, 13, -76, 6, 3, -90, 25, -7, -104, + -105, 65, -5, -87, 55, -18, -67, 44, -32, -48, 33, -45, + -29, 22, -59, -10, 12, -72, 8, 1, -86, 28, -9, -100, + -103, 64, 0, -84, 53, -13, -65, 42, -27, -46, 32, -41, + -26, 21, -54, -8, 10, -68, 11, 0, -81, 31, -10, -95, + -100, 63, 3, -82, 52, -9, -62, 41, -23, -43, 30, -37, + -24, 20, -50, -5, 9, -64, 14, -1, -77, 33, -12, -91, + -98, 61, 7, -79, 51, -5, -60, 40, -19, -41, 29, -33, + -22, 18, -46, -3, 8, -60, 16, -2, -73, 35, -13, -87, + -96, 60, 11, -77, 49, -1, -57, 38, -15, -39, 28, -29, + -19, 17, -42, 0, 6, -56, 18, -3, -69, 38, -14, -83, + -93, 58, 15, -74, 48, 2, -55, 37, -11, -36, 26, -24, + -17, 15, -38, 2, 5, -51, 21, -5, -65, 40, -16, -79, + -90, 57, 19, -72, 46, 6, -52, 36, -7, -34, 25, -20, + -14, 14, -34, 5, 3, -47, 23, -6, -61, 43, -17, -75, + -88, 56, 23, -69, 45, 10, -50, 34, -3, -31, 24, -16, + -12, 13, -30, 7, 2, -43, 26, -8, -57, 45, -19, -71, + -86, 54, 27, -67, 44, 14, -48, 33, 0, -29, 22, -12, + -9, 11, -26, 9, 1, -39, 28, -9, -53, 48, -20, -67, + -83, 53, 31, -64, 42, 18, -45, 31, 4, -26, 21, -8, + -7, 10, -22, 12, 0, -35, 31, -10, -49, 50, -21, -63, + -81, 51, 36, -62, 41, 23, -42, 30, 9, -24, 19, -4, + -4, 8, -17, 15, -1, -31, 33, -12, -44, 53, -23, -58, + -78, 50, 40, -59, 40, 27, -40, 29, 13, -21, 18, 0, + -2, 7, -13, 17, -3, -27, 36, -13, -40, 55, -24, -54, + -76, 49, 44, -57, 38, 31, -38, 27, 17, -19, 17, 3, + 1, 6, -9, 19, -4, -23, 38, -14, -36, 57, -25, -50, + -73, 47, 48, -55, 37, 35, -35, 26, 21, -16, 15, 7, + 3, 4, -5, 22, -5, -19, 40, -16, -32, 60, -27, -46, + -71, 46, 52, -52, 35, 39, -33, 24, 25, -14, 14, 12, + 6, 3, -1, 24, -7, -14, 43, -17, -28, 63, -28, -42, + -68, 45, 56, -50, 34, 43, -30, 23, 29, -11, 12, 16, + 8, 1, 2, 27, -8, -10, 46, -19, -24, 65, -30, -38, + -66, 43, 60, -47, 33, 47, -28, 22, 33, -9, 11, 20, + 10, 0, 6, 29, -9, -6, 48, -20, -20, 67, -31, -34, + -64, 42, 64, -45, 31, 51, -25, 20, 37, -7, 10, 24, + 13, 0, 10, 32, -11, -2, 50, -21, -16, 70, -32, -30, + -61, 40, 69, -42, 30, 56, -23, 19, 42, -4, 8, 28, + 15, -2, 15, 34, -12, 1, 53, -23, -11, 72, -34, -25, + -58, 39, 73, -40, 28, 60, -20, 17, 46, -2, 7, 32, + 18, -3, 19, 37, -14, 5, 55, -24, -7, 75, -35, -21, + -56, 38, 77, -37, 27, 64, -18, 16, 50, 1, 6, 36, + 20, -4, 23, 39, -15, 9, 58, -26, -3, 77, -37, -17, + -54, 36, 81, -35, 26, 68, -16, 15, 54, 3, 4, 40, + 23, -6, 27, 41, -16, 13, 60, -27, 0, 80, -38, -13, + -51, 35, 85, -33, 24, 72, -13, 13, 58, 6, 3, 44, + 25, -7, 31, 44, -18, 17, 63, -28, 4, 82, -39, -9, + -49, 33, 89, -30, 23, 76, -10, 12, 62, 8, 1, 49, + 28, -9, 35, 46, -19, 22, 65, -30, 8, 85, -41, -5, + -46, 32, 93, -27, 21, 80, -8, 11, 66, 11, 0, 53, + 30, -10, 39, 49, -21, 26, 68, -31, 12, 87, -42, -1, + -44, 31, 97, -25, 20, 84, -6, 9, 70, 13, 0, 57, + 32, -11, 43, 51, -22, 30, 70, -33, 16, 89, -43, 2, + -41, 29, 101, -23, 19, 88, -3, 8, 74, 16, -2, 61, + 35, -13, 47, 54, -23, 34, 72, -34, 20, 92, -45, 6, + -39, 28, 106, -20, 17, 93, -1, 6, 79, 18, -3, 65, + 38, -14, 52, 56, -25, 38, 75, -35, 25, 95, -46, 11, + -36, 26, 110, -18, 16, 97, 2, 5, 83, 21, -5, 69, + 40, -16, 56, 59, -26, 42, 78, -37, 29, 97, -48, 15, + -34, 25, 114, -15, 15, 101, 4, 4, 87, 23, -6, 73, + 42, -17, 60, 61, -28, 46, 80, -38, 33, 99, -49, 19, + -109, 72, -13, -90, 62, -27, -71, 51, -40, -52, 40, -54, + -33, 29, -68, -14, 19, -81, 5, 8, -94, 24, -2, -108, + -107, 71, -9, -88, 60, -23, -69, 49, -36, -50, 39, -50, + -31, 28, -64, -12, 17, -77, 7, 7, -90, 26, -3, -104, + -104, 69, -5, -86, 59, -19, -66, 48, -32, -48, 37, -46, + -28, 26, -60, -9, 16, -73, 9, 5, -86, 29, -5, -100, + -102, 68, -1, -83, 57, -14, -64, 46, -28, -45, 36, -41, + -25, 25, -55, -7, 14, -69, 12, 4, -82, 31, -6, -96, + -99, 67, 2, -81, 56, -10, -61, 45, -24, -42, 34, -37, + -23, 24, -51, -4, 13, -65, 14, 2, -78, 34, -8, -92, + -97, 65, 6, -78, 55, -6, -59, 44, -20, -40, 33, -33, + -21, 22, -47, -2, 12, -61, 17, 1, -74, 36, -9, -88, + -95, 64, 10, -76, 53, -2, -56, 42, -16, -38, 32, -29, + -18, 21, -43, 0, 10, -57, 19, 0, -70, 39, -10, -84, + -92, 62, 15, -73, 52, 1, -54, 41, -11, -35, 30, -25, + -16, 19, -39, 3, 9, -52, 22, -1, -65, 41, -12, -79, + -90, 61, 19, -71, 50, 5, -51, 40, -7, -33, 29, -21, + -13, 18, -35, 6, 7, -48, 24, -2, -61, 44, -13, -75, + -87, 60, 23, -68, 49, 9, -49, 38, -3, -30, 28, -17, + -11, 17, -31, 8, 6, -44, 27, -4, -57, 46, -15, -71, + -85, 58, 27, -66, 48, 13, -47, 37, 0, -28, 26, -13, + -8, 15, -27, 10, 5, -40, 29, -5, -53, 48, -16, -67, + -82, 57, 31, -64, 46, 17, -44, 35, 4, -25, 25, -9, + -6, 14, -23, 13, 3, -36, 32, -6, -49, 51, -17, -63, + -80, 55, 35, -61, 45, 22, -42, 34, 8, -23, 23, -4, + -3, 12, -18, 15, 2, -32, 34, -8, -45, 54, -19, -59, + -77, 54, 39, -59, 44, 26, -39, 33, 12, -20, 22, 0, + -1, 11, -14, 18, 0, -28, 37, -9, -41, 56, -20, -55, + -75, 53, 43, -56, 42, 30, -37, 31, 16, -18, 21, 3, + 1, 10, -10, 20, 0, -24, 39, -10, -37, 58, -21, -51, + -73, 51, 47, -54, 41, 34, -34, 30, 20, -16, 19, 7, + 4, 8, -6, 23, -1, -20, 41, -12, -33, 61, -23, -47, + -70, 50, 52, -51, 39, 38, -32, 28, 25, -13, 18, 11, + 6, 7, -2, 25, -3, -15, 44, -13, -28, 63, -24, -42, + -67, 49, 56, -49, 38, 42, -29, 27, 29, -10, 16, 15, + 9, 5, 1, 28, -4, -11, 46, -15, -24, 66, -26, -38, + -65, 47, 60, -46, 37, 46, -27, 26, 33, -8, 15, 19, + 11, 4, 5, 30, -5, -7, 49, -16, -20, 68, -27, -34, + -63, 46, 64, -44, 35, 50, -24, 24, 37, -6, 14, 23, + 14, 3, 9, 32, -7, -3, 51, -17, -16, 71, -28, -30, + -60, 44, 68, -41, 34, 55, -22, 23, 41, -3, 12, 28, + 16, 1, 14, 35, -8, 0, 54, -19, -12, 73, -30, -26, + -58, 43, 72, -39, 32, 59, -19, 21, 45, -1, 11, 32, + 19, 0, 18, 38, -10, 4, 56, -20, -8, 76, -31, -22, + -55, 42, 76, -36, 31, 63, -17, 20, 49, 2, 10, 36, + 21, 0, 22, 40, -11, 8, 59, -22, -4, 78, -33, -18, + -53, 40, 80, -34, 30, 67, -15, 19, 53, 4, 8, 40, + 24, -2, 26, 42, -12, 12, 61, -23, 0, 80, -34, -14, + -50, 39, 84, -32, 28, 71, -12, 17, 57, 7, 7, 44, + 26, -3, 30, 45, -14, 16, 64, -24, 3, 83, -35, -10, + -48, 37, 89, -29, 27, 75, -10, 16, 62, 9, 5, 48, + 29, -5, 34, 47, -15, 21, 66, -26, 8, 86, -37, -5, + -45, 36, 93, -27, 25, 79, -7, 15, 66, 12, 4, 52, + 31, -6, 38, 50, -17, 25, 69, -27, 12, 88, -38, -1, + -43, 35, 97, -24, 24, 83, -5, 13, 70, 14, 3, 56, + 33, -7, 42, 52, -18, 29, 71, -29, 16, 90, -39, 2, + -41, 33, 101, -22, 23, 87, -2, 12, 74, 16, 1, 60, + 36, -9, 46, 55, -19, 33, 73, -30, 20, 93, -41, 6, + -38, 32, 105, -19, 21, 92, 0, 10, 78, 19, 0, 65, + 38, -10, 51, 57, -21, 37, 76, -31, 24, 95, -42, 10, + -35, 30, 109, -17, 20, 96, 3, 9, 82, 22, -1, 69, + 41, -12, 55, 60, -22, 41, 78, -33, 28, 98, -44, 14, + -33, 29, 113, -14, 19, 100, 5, 8, 86, 24, -2, 73, + 43, -13, 59, 62, -24, 45, 81, -34, 32, 100, -45, 18, + -108, 76, -14, -90, 66, -27, -70, 55, -41, -51, 44, -54, + -32, 33, -68, -13, 23, -82, 6, 12, -95, 25, 1, -109, + -106, 75, -10, -87, 64, -23, -68, 53, -37, -49, 43, -50, + -30, 32, -64, -11, 21, -78, 8, 11, -91, 27, 0, -105, + -104, 73, -6, -85, 63, -19, -65, 52, -33, -47, 41, -46, + -27, 30, -60, -8, 20, -74, 10, 9, -87, 30, -1, -101, + -101, 72, -1, -82, 61, -15, -63, 50, -29, -44, 40, -42, + -25, 29, -56, -6, 18, -69, 13, 8, -83, 32, -2, -96, + -99, 71, 2, -80, 60, -11, -60, 49, -25, -42, 38, -38, + -22, 28, -52, -3, 17, -65, 15, 6, -79, 35, -4, -92, + -96, 69, 6, -77, 59, -7, -58, 48, -21, -39, 37, -34, + -20, 26, -48, -1, 16, -61, 18, 5, -75, 37, -5, -88, + -94, 68, 10, -75, 57, -3, -56, 46, -17, -37, 36, -30, + -17, 25, -44, 1, 14, -57, 20, 4, -71, 40, -6, -84, + -91, 66, 14, -72, 56, 1, -53, 45, -12, -34, 34, -25, + -15, 23, -39, 4, 13, -53, 23, 2, -66, 42, -8, -80, + -89, 65, 18, -70, 54, 5, -50, 44, -8, -32, 33, -21, + -12, 22, -35, 6, 11, -49, 25, 1, -62, 45, -9, -76, + -86, 64, 22, -67, 53, 9, -48, 42, -4, -29, 32, -17, + -10, 21, -31, 9, 10, -45, 28, 0, -58, 47, -11, -72, + -84, 62, 26, -65, 52, 13, -46, 41, 0, -27, 30, -13, + -8, 19, -27, 11, 9, -41, 30, -1, -54, 49, -12, -68, + -81, 61, 30, -63, 50, 17, -43, 39, 3, -25, 29, -9, + -5, 18, -23, 14, 7, -37, 32, -2, -50, 52, -13, -64, + -79, 59, 35, -60, 49, 21, -41, 38, 7, -22, 27, -5, + -2, 16, -19, 16, 6, -32, 35, -4, -46, 54, -15, -59, + -76, 58, 39, -58, 48, 25, -38, 37, 11, -19, 26, -1, + 0, 15, -15, 19, 4, -28, 38, -5, -42, 57, -16, -55, + -74, 57, 43, -55, 46, 29, -36, 35, 15, -17, 25, 2, + 2, 14, -11, 21, 3, -24, 40, -6, -38, 59, -17, -51, + -72, 55, 47, -53, 45, 33, -33, 34, 19, -15, 23, 6, + 5, 12, -7, 24, 2, -20, 42, -8, -34, 62, -19, -47, + -69, 54, 51, -50, 43, 38, -31, 32, 24, -12, 22, 11, + 7, 11, -2, 26, 0, -16, 45, -9, -29, 64, -20, -43, + -67, 53, 55, -48, 42, 42, -28, 31, 28, -10, 20, 15, + 10, 9, 1, 29, 0, -12, 47, -11, -25, 67, -22, -39, + -64, 51, 59, -45, 41, 46, -26, 30, 32, -7, 19, 19, + 12, 8, 5, 31, -1, -8, 50, -12, -21, 69, -23, -35, + -62, 50, 63, -43, 39, 50, -24, 28, 36, -5, 18, 23, + 15, 7, 9, 33, -3, -4, 52, -13, -17, 72, -24, -31, + -59, 48, 68, -40, 38, 54, -21, 27, 40, -2, 16, 27, + 17, 5, 13, 36, -4, 0, 55, -15, -13, 74, -26, -26, + -57, 47, 72, -38, 36, 58, -18, 25, 44, 0, 15, 31, + 20, 4, 17, 38, -6, 4, 57, -16, -9, 77, -27, -22, + -54, 46, 76, -35, 35, 62, -16, 24, 48, 3, 14, 35, + 22, 3, 21, 41, -7, 8, 60, -18, -5, 79, -29, -18, + -52, 44, 80, -33, 34, 66, -14, 23, 52, 5, 12, 39, + 24, 1, 25, 43, -8, 12, 62, -19, -1, 81, -30, -14, + -49, 43, 84, -31, 32, 70, -11, 21, 56, 7, 11, 43, + 27, 0, 29, 46, -10, 16, 64, -20, 2, 84, -31, -10, + -47, 41, 88, -28, 31, 75, -9, 20, 61, 10, 9, 48, + 30, -1, 34, 48, -11, 20, 67, -22, 7, 86, -33, -6, + -44, 40, 92, -26, 29, 79, -6, 19, 65, 13, 8, 52, + 32, -2, 38, 51, -13, 24, 69, -23, 11, 89, -34, -2, + -42, 39, 96, -23, 28, 83, -4, 17, 69, 15, 7, 56, + 34, -3, 42, 53, -14, 28, 72, -25, 15, 91, -35, 1, + -40, 37, 100, -21, 27, 87, -1, 16, 73, 17, 5, 60, + 37, -5, 46, 55, -15, 32, 74, -26, 19, 94, -37, 5, + -37, 36, 105, -18, 25, 91, 1, 14, 77, 20, 4, 64, + 39, -6, 50, 58, -17, 37, 77, -27, 23, 96, -38, 10, + -35, 34, 109, -16, 24, 95, 4, 13, 81, 22, 2, 68, + 42, -8, 54, 61, -18, 41, 79, -29, 27, 99, -40, 14, + -32, 33, 113, -13, 23, 99, 6, 12, 85, 25, 1, 72, + 44, -9, 58, 63, -20, 45, 82, -30, 31, 101, -41, 18, + -107, 81, -15, -89, 70, -28, -69, 59, -42, -50, 49, -55, + -31, 38, -69, -12, 27, -82, 7, 16, -96, 26, 5, -110, + -105, 79, -11, -86, 69, -24, -67, 58, -38, -48, 47, -51, + -29, 36, -65, -10, 26, -78, 9, 15, -92, 28, 4, -106, + -103, 78, -7, -84, 67, -20, -64, 56, -34, -46, 46, -47, + -26, 35, -61, -7, 24, -74, 11, 14, -88, 31, 3, -102, + -100, 76, -2, -81, 66, -15, -62, 55, -29, -43, 44, -43, + -24, 33, -57, -5, 23, -70, 14, 12, -83, 33, 1, -97, + -97, 75, 1, -79, 65, -11, -59, 54, -25, -41, 43, -39, + -21, 32, -53, -2, 21, -66, 16, 11, -79, 36, 0, -93, + -95, 74, 5, -76, 63, -7, -57, 52, -21, -38, 42, -35, + -19, 31, -49, 0, 20, -62, 19, 9, -75, 38, 0, -89, + -93, 72, 9, -74, 62, -3, -55, 51, -17, -36, 40, -31, + -16, 29, -45, 2, 19, -58, 21, 8, -71, 41, -2, -85, + -90, 71, 13, -71, 60, 0, -52, 49, -13, -33, 39, -26, + -14, 28, -40, 5, 17, -53, 24, 7, -67, 43, -3, -81, + -88, 70, 17, -69, 59, 4, -49, 48, -9, -31, 37, -22, + -11, 26, -36, 7, 16, -49, 26, 5, -63, 46, -5, -77, + -85, 68, 21, -66, 58, 8, -47, 47, -5, -28, 36, -18, + -9, 25, -32, 10, 15, -45, 29, 4, -59, 48, -6, -73, + -83, 67, 25, -64, 56, 12, -45, 45, -1, -26, 35, -14, + -7, 24, -28, 12, 13, -41, 31, 3, -55, 50, -7, -69, + -80, 65, 29, -62, 55, 16, -42, 44, 2, -23, 33, -10, + -4, 22, -24, 15, 12, -37, 33, 1, -51, 53, -9, -65, + -78, 64, 34, -59, 53, 21, -40, 42, 7, -21, 32, -6, + -1, 21, -20, 17, 10, -33, 36, 0, -46, 56, -10, -60, + -75, 63, 38, -57, 52, 25, -37, 41, 11, -18, 30, -2, + 1, 20, -16, 20, 9, -29, 39, -1, -42, 58, -12, -56, + -73, 61, 42, -54, 51, 29, -35, 40, 15, -16, 29, 1, + 3, 18, -12, 22, 8, -25, 41, -2, -38, 60, -13, -52, + -71, 60, 46, -52, 49, 33, -32, 38, 19, -14, 28, 5, + 6, 17, -8, 25, 6, -21, 43, -3, -34, 63, -14, -48, + -68, 58, 50, -49, 48, 37, -30, 37, 23, -11, 26, 10, + 8, 15, -3, 27, 5, -16, 46, -5, -30, 65, -16, -44, + -65, 57, 54, -47, 46, 41, -27, 36, 27, -9, 25, 14, + 11, 14, 0, 30, 3, -12, 48, -6, -26, 68, -17, -40, + -63, 56, 58, -44, 45, 45, -25, 34, 31, -6, 24, 18, + 13, 13, 4, 32, 2, -8, 51, -8, -22, 70, -18, -36, + -61, 54, 62, -42, 44, 49, -23, 33, 35, -4, 22, 22, + 16, 11, 8, 34, 1, -4, 53, -9, -18, 73, -20, -32, + -58, 53, 67, -39, 42, 54, -20, 31, 40, -1, 21, 26, + 18, 10, 12, 37, 0, 0, 56, -10, -13, 75, -21, -27, + -56, 51, 71, -37, 41, 58, -17, 30, 44, 1, 19, 30, + 21, 8, 16, 39, -1, 3, 58, -12, -9, 78, -23, -23, + -53, 50, 75, -34, 40, 62, -15, 29, 48, 4, 18, 34, + 23, 7, 20, 42, -3, 7, 61, -13, -5, 80, -24, -19, + -51, 49, 79, -32, 38, 66, -13, 27, 52, 6, 17, 38, + 25, 6, 24, 44, -4, 11, 63, -14, -1, 82, -25, -15, + -48, 47, 83, -30, 37, 70, -10, 26, 56, 9, 15, 42, + 28, 4, 28, 47, -5, 15, 65, -16, 2, 85, -27, -11, + -46, 46, 87, -27, 35, 74, -8, 24, 60, 11, 14, 47, + 31, 3, 33, 49, -7, 20, 68, -17, 6, 88, -28, -7, + -43, 45, 91, -25, 34, 78, -5, 23, 64, 14, 12, 51, + 33, 2, 37, 52, -8, 24, 71, -19, 10, 90, -30, -3, + -41, 43, 95, -22, 33, 82, -3, 22, 68, 16, 11, 55, + 35, 0, 41, 54, -9, 28, 73, -20, 14, 92, -31, 0, + -39, 42, 99, -20, 31, 86, 0, 20, 72, 18, 10, 59, + 38, 0, 45, 57, -11, 32, 75, -21, 18, 95, -32, 4, + -36, 40, 104, -17, 30, 91, 2, 19, 77, 21, 8, 63, + 40, -2, 49, 59, -12, 36, 78, -23, 23, 97, -34, 9, + -33, 39, 108, -15, 28, 95, 5, 17, 81, 23, 7, 67, + 43, -3, 53, 62, -14, 40, 80, -24, 27, 100, -35, 13, + -31, 38, 112, -12, 27, 99, 7, 16, 85, 26, 6, 71, + 45, -4, 57, 64, -15, 44, 83, -26, 31, 102, -37, 17, + -106, 85, -15, -88, 74, -29, -68, 63, -42, -49, 53, -56, + -30, 42, -70, -11, 31, -83, 7, 20, -96, 27, 9, -110, + -104, 83, -11, -85, 73, -25, -66, 62, -38, -47, 51, -52, + -28, 40, -66, -9, 30, -79, 10, 19, -92, 29, 8, -106, + -102, 82, -7, -83, 71, -21, -63, 60, -34, -45, 50, -48, + -25, 39, -62, -7, 28, -75, 12, 18, -88, 32, 7, -102, + -99, 80, -3, -80, 70, -16, -61, 59, -30, -42, 48, -43, + -23, 37, -57, -4, 27, -71, 15, 16, -84, 34, 5, -98, + -97, 79, 0, -78, 69, -12, -58, 58, -26, -40, 47, -39, + -20, 36, -53, -1, 25, -67, 17, 15, -80, 37, 4, -94, + -94, 78, 4, -75, 67, -8, -56, 56, -22, -37, 46, -35, + -18, 35, -49, 1, 24, -63, 20, 13, -76, 39, 3, -90, + -92, 76, 8, -73, 66, -4, -54, 55, -18, -35, 44, -31, + -15, 33, -45, 3, 23, -59, 22, 12, -72, 41, 1, -86, + -89, 75, 13, -70, 64, 0, -51, 53, -13, -32, 43, -27, + -13, 32, -41, 6, 21, -54, 25, 11, -67, 44, 0, -81, + -87, 74, 17, -68, 63, 3, -49, 52, -9, -30, 41, -23, + -10, 30, -37, 8, 20, -50, 27, 9, -63, 47, -1, -77, + -84, 72, 21, -66, 62, 7, -46, 51, -5, -27, 40, -19, + -8, 29, -33, 11, 19, -46, 30, 8, -59, 49, -2, -73, + -82, 71, 25, -63, 60, 11, -44, 49, -1, -25, 39, -15, + -6, 28, -29, 13, 17, -42, 32, 7, -55, 51, -3, -69, + -80, 69, 29, -61, 59, 15, -41, 48, 2, -23, 37, -11, + -3, 26, -25, 16, 16, -38, 34, 5, -51, 54, -5, -65, + -77, 68, 33, -58, 57, 20, -39, 46, 6, -20, 36, -6, + -1, 25, -20, 18, 14, -34, 37, 4, -47, 56, -6, -61, + -74, 67, 37, -56, 56, 24, -36, 45, 10, -17, 34, -2, + 2, 24, -16, 21, 13, -30, 39, 2, -43, 59, -8, -57, + -72, 65, 41, -53, 55, 28, -34, 44, 14, -15, 33, 1, + 4, 22, -12, 23, 12, -26, 42, 1, -39, 61, -9, -53, + -70, 64, 45, -51, 53, 32, -31, 42, 18, -13, 32, 5, + 7, 21, -8, 25, 10, -22, 44, 0, -35, 64, -10, -49, + -67, 62, 50, -48, 52, 36, -29, 41, 23, -10, 30, 9, + 9, 19, -4, 28, 9, -17, 47, -1, -30, 66, -12, -44, + -65, 61, 54, -46, 50, 40, -26, 40, 27, -8, 29, 13, + 12, 18, 0, 31, 7, -13, 49, -2, -26, 69, -13, -40, + -62, 60, 58, -43, 49, 44, -24, 38, 31, -5, 28, 17, + 14, 17, 3, 33, 6, -9, 52, -4, -22, 71, -14, -36, + -60, 58, 62, -41, 48, 48, -22, 37, 35, -3, 26, 21, + 17, 15, 7, 35, 5, -5, 54, -5, -18, 73, -16, -32, + -57, 57, 66, -38, 46, 53, -19, 35, 39, 0, 25, 26, + 19, 14, 12, 38, 3, -1, 57, -6, -14, 76, -17, -28, + -55, 55, 70, -36, 45, 57, -17, 34, 43, 2, 23, 30, + 22, 12, 16, 40, 2, 2, 59, -8, -10, 79, -19, -24, + -52, 54, 74, -34, 44, 61, -14, 33, 47, 5, 22, 34, + 24, 11, 20, 43, 0, 6, 62, -9, -6, 81, -20, -20, + -50, 53, 78, -31, 42, 65, -12, 31, 51, 7, 21, 38, + 26, 10, 24, 45, 0, 10, 64, -10, -2, 83, -21, -16, + -48, 51, 82, -29, 41, 69, -9, 30, 55, 9, 19, 42, + 29, 8, 28, 48, -1, 14, 66, -12, 1, 86, -23, -12, + -45, 50, 87, -26, 39, 73, -7, 28, 60, 12, 18, 46, + 31, 7, 32, 50, -3, 19, 69, -13, 6, 88, -24, -7, + -42, 49, 91, -24, 38, 77, -4, 27, 64, 14, 16, 50, + 34, 6, 36, 53, -4, 23, 71, -15, 10, 91, -26, -3, + -40, 47, 95, -21, 37, 81, -2, 26, 68, 17, 15, 54, + 36, 4, 40, 55, -5, 27, 74, -16, 14, 93, -27, 0, + -38, 46, 99, -19, 35, 85, 0, 24, 72, 19, 14, 58, + 39, 3, 44, 57, -7, 31, 76, -17, 18, 96, -28, 4, + -35, 44, 103, -16, 34, 90, 3, 23, 76, 22, 12, 63, + 41, 1, 49, 60, -8, 35, 79, -19, 22, 98, -30, 8, + -33, 43, 107, -14, 32, 94, 6, 21, 80, 24, 11, 67, + 44, 0, 53, 63, -10, 39, 81, -20, 26, 101, -31, 12, + -30, 42, 111, -11, 31, 98, 8, 20, 84, 27, 10, 71, + 46, 0, 57, 65, -11, 43, 84, -22, 30, 103, -33, 16, + -106, 89, -16, -87, 78, -29, -67, 67, -43, -49, 57, -57, + -29, 46, -70, -10, 35, -84, 8, 24, -97, 28, 13, -111, + -103, 87, -12, -84, 77, -25, -65, 66, -39, -46, 55, -53, + -27, 44, -66, -8, 34, -80, 11, 23, -93, 30, 12, -107, + -101, 86, -8, -82, 75, -21, -63, 64, -35, -44, 54, -49, + -24, 43, -62, -6, 32, -76, 13, 22, -89, 33, 11, -103, + -98, 84, -3, -79, 74, -17, -60, 63, -31, -41, 52, -44, + -22, 41, -58, -3, 31, -71, 16, 20, -85, 35, 9, -98, + -96, 83, 0, -77, 73, -13, -57, 62, -27, -39, 51, -40, + -19, 40, -54, -1, 29, -67, 18, 19, -81, 38, 8, -94, + -93, 82, 4, -74, 71, -9, -55, 60, -23, -36, 50, -36, + -17, 39, -50, 2, 28, -63, 21, 17, -77, 40, 7, -90, + -91, 80, 8, -72, 70, -5, -53, 59, -19, -34, 48, -32, + -15, 37, -46, 4, 27, -59, 23, 16, -73, 42, 5, -86, + -88, 79, 12, -69, 68, 0, -50, 57, -14, -31, 47, -28, + -12, 36, -41, 7, 25, -55, 26, 15, -68, 45, 4, -82, + -86, 78, 16, -67, 67, 3, -48, 56, -10, -29, 45, -24, + -9, 34, -37, 9, 24, -51, 28, 13, -64, 47, 2, -78, + -83, 76, 20, -65, 66, 7, -45, 55, -6, -26, 44, -20, + -7, 33, -33, 12, 23, -47, 30, 12, -60, 50, 1, -74, + -81, 75, 24, -62, 64, 11, -43, 53, -2, -24, 43, -16, + -5, 32, -29, 14, 21, -43, 33, 11, -56, 52, 0, -70, + -79, 73, 28, -60, 63, 15, -40, 52, 1, -22, 41, -12, + -2, 30, -25, 16, 20, -39, 35, 9, -52, 55, -1, -66, + -76, 72, 33, -57, 61, 19, -38, 50, 5, -19, 40, -7, + 0, 29, -21, 19, 18, -34, 38, 8, -48, 57, -2, -61, + -74, 71, 37, -55, 60, 23, -35, 49, 9, -17, 38, -3, + 3, 28, -17, 22, 17, -30, 40, 6, -44, 60, -4, -57, + -71, 69, 41, -52, 59, 27, -33, 48, 13, -14, 37, 0, + 5, 26, -13, 24, 16, -26, 43, 5, -40, 62, -5, -53, + -69, 68, 45, -50, 57, 31, -31, 46, 17, -12, 36, 4, + 8, 25, -9, 26, 14, -22, 45, 4, -36, 65, -6, -49, + -66, 66, 49, -47, 56, 36, -28, 45, 22, -9, 34, 8, + 10, 23, -4, 29, 13, -18, 48, 2, -31, 67, -8, -45, + -64, 65, 53, -45, 54, 40, -26, 44, 26, -7, 33, 12, + 13, 22, 0, 31, 11, -14, 50, 1, -27, 70, -9, -41, + -61, 64, 57, -42, 53, 44, -23, 42, 30, -4, 32, 16, + 15, 21, 3, 34, 10, -10, 53, 0, -23, 72, -10, -37, + -59, 62, 61, -40, 52, 48, -21, 41, 34, -2, 30, 20, + 17, 19, 7, 36, 9, -6, 55, -1, -19, 74, -12, -33, + -56, 61, 66, -37, 50, 52, -18, 39, 38, 1, 29, 25, + 20, 18, 11, 39, 7, -1, 58, -2, -15, 77, -13, -28, + -54, 59, 70, -35, 49, 56, -16, 38, 42, 3, 27, 29, + 23, 16, 15, 41, 6, 2, 60, -4, -11, 79, -15, -24, + -51, 58, 74, -33, 48, 60, -13, 37, 46, 6, 26, 33, + 25, 15, 19, 44, 4, 6, 62, -5, -7, 82, -16, -20, + -49, 57, 78, -30, 46, 64, -11, 35, 50, 8, 25, 37, + 27, 14, 23, 46, 3, 10, 65, -6, -3, 84, -17, -16, + -47, 55, 82, -28, 45, 68, -8, 34, 54, 10, 23, 41, + 30, 12, 27, 48, 2, 14, 67, -8, 0, 87, -19, -12, + -44, 54, 86, -25, 43, 73, -6, 32, 59, 13, 22, 45, + 32, 11, 32, 51, 0, 18, 70, -9, 5, 89, -20, -8, + -42, 53, 90, -23, 42, 77, -3, 31, 63, 15, 20, 49, + 35, 10, 36, 54, 0, 22, 72, -11, 9, 92, -22, -4, + -39, 51, 94, -20, 41, 81, -1, 30, 67, 18, 19, 53, + 37, 8, 40, 56, -1, 26, 75, -12, 13, 94, -23, 0, + -37, 50, 98, -18, 39, 85, 1, 28, 71, 20, 18, 57, + 40, 7, 44, 58, -3, 30, 77, -13, 17, 97, -24, 3, + -34, 48, 103, -15, 38, 89, 4, 27, 75, 23, 16, 62, + 42, 5, 48, 61, -4, 35, 80, -15, 21, 99, -26, 8, + -32, 47, 107, -13, 36, 93, 6, 25, 79, 25, 15, 66, + 45, 4, 52, 63, -6, 39, 82, -16, 25, 102, -27, 12, + -29, 46, 111, -10, 35, 97, 9, 24, 83, 28, 14, 70, + 47, 3, 56, 66, -7, 43, 85, -18, 29, 104, -29, 16, + -105, 93, -17, -86, 82, -30, -66, 71, -44, -48, 61, -57, + -28, 50, -71, -10, 39, -84, 9, 28, -98, 29, 17, -112, + -102, 91, -13, -83, 81, -26, -64, 70, -40, -45, 59, -53, + -26, 48, -67, -7, 38, -80, 12, 27, -94, 31, 16, -108, + -100, 90, -9, -81, 79, -22, -62, 68, -36, -43, 58, -49, + -24, 47, -63, -5, 36, -76, 14, 26, -90, 33, 15, -104, + -97, 88, -4, -78, 78, -17, -59, 67, -31, -40, 56, -45, + -21, 45, -58, -2, 35, -72, 17, 24, -85, 36, 13, -99, + -95, 87, 0, -76, 77, -13, -57, 66, -27, -38, 55, -41, + -18, 44, -54, 0, 33, -68, 19, 23, -81, 39, 12, -95, + -92, 86, 3, -74, 75, -9, -54, 64, -23, -35, 54, -37, + -16, 43, -50, 3, 32, -64, 22, 21, -77, 41, 11, -91, + -90, 84, 7, -71, 74, -5, -52, 63, -19, -33, 52, -33, + -14, 41, -46, 5, 31, -60, 24, 20, -73, 43, 9, -87, + -87, 83, 11, -68, 72, -1, -49, 61, -15, -30, 51, -28, + -11, 40, -42, 8, 29, -55, 27, 19, -69, 46, 8, -83, + -85, 82, 15, -66, 71, 2, -47, 60, -11, -28, 49, -24, + -9, 38, -38, 10, 28, -51, 29, 17, -65, 48, 6, -79, + -82, 80, 19, -64, 70, 6, -44, 59, -7, -26, 48, -20, + -6, 37, -34, 13, 27, -47, 31, 16, -61, 51, 5, -75, + -80, 79, 23, -61, 68, 10, -42, 57, -3, -23, 47, -16, + -4, 36, -30, 15, 25, -43, 34, 15, -57, 53, 4, -71, + -78, 77, 27, -59, 67, 14, -40, 56, 0, -21, 45, -12, + -1, 34, -26, 17, 24, -39, 36, 13, -53, 56, 2, -67, + -75, 76, 32, -56, 65, 19, -37, 54, 5, -18, 44, -8, + 1, 33, -21, 20, 22, -35, 39, 12, -48, 58, 1, -62, + -73, 75, 36, -54, 64, 23, -34, 53, 9, -16, 42, -4, + 4, 32, -17, 22, 21, -31, 41, 10, -44, 61, 0, -58, + -70, 73, 40, -51, 63, 27, -32, 52, 13, -13, 41, 0, + 6, 30, -13, 25, 20, -27, 44, 9, -40, 63, -1, -54, + -68, 72, 44, -49, 61, 31, -30, 50, 17, -11, 40, 3, + 8, 29, -9, 27, 18, -23, 46, 8, -36, 65, -2, -50, + -65, 70, 48, -46, 60, 35, -27, 49, 21, -8, 38, 8, + 11, 27, -5, 30, 17, -18, 49, 6, -32, 68, -4, -46, + -63, 69, 52, -44, 58, 39, -25, 48, 25, -6, 37, 12, + 14, 26, -1, 32, 15, -14, 51, 5, -28, 71, -5, -42, + -60, 68, 56, -42, 57, 43, -22, 46, 29, -3, 36, 16, + 16, 25, 2, 35, 14, -10, 54, 3, -24, 73, -6, -38, + -58, 66, 60, -39, 56, 47, -20, 45, 33, -1, 34, 20, + 18, 23, 6, 37, 13, -6, 56, 2, -20, 75, -8, -34, + -55, 65, 65, -36, 54, 52, -17, 43, 38, 2, 33, 24, + 21, 22, 11, 40, 11, -2, 59, 1, -15, 78, -9, -29, + -53, 63, 69, -34, 53, 56, -15, 42, 42, 4, 31, 28, + 23, 20, 15, 42, 10, 1, 61, 0, -11, 80, -11, -25, + -50, 62, 73, -32, 52, 60, -12, 41, 46, 6, 30, 32, + 26, 19, 19, 45, 8, 5, 63, -1, -7, 83, -12, -21, + -48, 61, 77, -29, 50, 64, -10, 39, 50, 9, 29, 36, + 28, 18, 23, 47, 7, 9, 66, -2, -3, 85, -13, -17, + -46, 59, 81, -27, 49, 68, -8, 38, 54, 11, 27, 40, + 31, 16, 27, 49, 6, 13, 68, -4, 0, 88, -15, -13, + -43, 58, 85, -24, 47, 72, -5, 36, 58, 14, 26, 45, + 33, 15, 31, 52, 4, 18, 71, -5, 4, 90, -16, -9, + -41, 57, 89, -22, 46, 76, -2, 35, 62, 16, 24, 49, + 36, 14, 35, 54, 3, 22, 73, -7, 8, 93, -18, -5, + -38, 55, 93, -19, 45, 80, 0, 34, 66, 19, 23, 53, + 38, 12, 39, 57, 2, 26, 76, -8, 12, 95, -19, -1, + -36, 54, 97, -17, 43, 84, 2, 32, 70, 21, 22, 57, + 40, 11, 43, 59, 0, 30, 78, -9, 16, 97, -20, 2, + -33, 52, 102, -14, 42, 89, 5, 31, 75, 24, 20, 61, + 43, 9, 48, 62, 0, 34, 81, -11, 21, 100, -22, 7, + -31, 51, 106, -12, 40, 93, 7, 29, 79, 26, 19, 65, + 46, 8, 52, 64, -2, 38, 83, -12, 25, 102, -23, 11, + -28, 50, 110, -10, 39, 97, 10, 28, 83, 29, 18, 69, + 48, 7, 56, 67, -3, 42, 86, -14, 29, 105, -25, 15, + -104, 97, -17, -85, 86, -31, -66, 75, -44, -47, 65, -58, + -27, 54, -72, -9, 43, -85, 10, 32, -98, 30, 21, -112, + -101, 95, -13, -83, 85, -27, -63, 74, -40, -44, 63, -54, + -25, 52, -68, -6, 42, -81, 13, 31, -94, 32, 20, -108, + -99, 94, -9, -80, 83, -23, -61, 72, -36, -42, 62, -50, + -23, 51, -64, -4, 40, -77, 15, 30, -90, 34, 19, -104, + -96, 92, -5, -77, 82, -18, -58, 71, -32, -39, 60, -45, + -20, 49, -59, -1, 39, -73, 18, 28, -86, 37, 17, -100, + -94, 91, -1, -75, 81, -14, -56, 70, -28, -37, 59, -41, + -18, 48, -55, 1, 37, -69, 20, 27, -82, 39, 16, -96, + -91, 90, 2, -73, 79, -10, -53, 68, -24, -34, 58, -37, + -15, 47, -51, 4, 36, -65, 22, 25, -78, 42, 15, -92, + -89, 88, 6, -70, 78, -6, -51, 67, -20, -32, 56, -33, + -13, 45, -47, 6, 35, -61, 25, 24, -74, 44, 13, -88, + -86, 87, 11, -68, 76, -2, -48, 65, -15, -29, 55, -29, + -10, 44, -43, 9, 33, -56, 28, 23, -69, 47, 12, -83, + -84, 86, 15, -65, 75, 1, -46, 64, -11, -27, 53, -25, + -8, 42, -39, 11, 32, -52, 30, 21, -65, 49, 10, -79, + -82, 84, 19, -63, 74, 5, -43, 63, -7, -25, 52, -21, + -5, 41, -35, 14, 31, -48, 32, 20, -61, 52, 9, -75, + -79, 83, 23, -60, 72, 9, -41, 61, -3, -22, 51, -17, + -3, 40, -31, 16, 29, -44, 35, 19, -57, 54, 8, -71, + -77, 81, 27, -58, 71, 13, -39, 60, 0, -20, 49, -13, + 0, 38, -27, 18, 28, -40, 37, 17, -53, 56, 6, -67, + -74, 80, 31, -55, 69, 18, -36, 58, 4, -17, 48, -8, + 2, 37, -22, 21, 26, -36, 40, 16, -49, 59, 5, -63, + -72, 79, 35, -53, 68, 22, -34, 57, 8, -15, 46, -4, + 5, 36, -18, 23, 25, -32, 42, 14, -45, 62, 3, -59, + -69, 77, 39, -51, 67, 26, -31, 56, 12, -12, 45, 0, + 7, 34, -14, 26, 24, -28, 45, 13, -41, 64, 2, -55, + -67, 76, 43, -48, 65, 30, -29, 54, 16, -10, 44, 3, + 9, 33, -10, 28, 22, -24, 47, 12, -37, 66, 1, -51, + -64, 74, 48, -45, 64, 34, -26, 53, 21, -7, 42, 7, + 12, 31, -6, 31, 21, -19, 50, 10, -32, 69, 0, -46, + -62, 73, 52, -43, 62, 38, -24, 52, 25, -5, 41, 11, + 14, 30, -2, 33, 19, -15, 52, 9, -28, 71, -1, -42, + -59, 72, 56, -41, 61, 42, -21, 50, 29, -3, 40, 15, + 17, 29, 1, 36, 18, -11, 54, 7, -24, 74, -2, -38, + -57, 70, 60, -38, 60, 46, -19, 49, 33, 0, 38, 19, + 19, 27, 5, 38, 17, -7, 57, 6, -20, 76, -4, -34, + -54, 69, 64, -36, 58, 51, -16, 47, 37, 3, 37, 24, + 22, 26, 10, 41, 15, -3, 60, 5, -16, 79, -5, -30, + -52, 67, 68, -33, 57, 55, -14, 46, 41, 5, 35, 28, + 24, 24, 14, 43, 14, 0, 62, 3, -12, 81, -7, -26, + -50, 66, 72, -31, 56, 59, -11, 45, 45, 7, 34, 32, + 27, 23, 18, 46, 12, 4, 64, 2, -8, 84, -8, -22, + -47, 65, 76, -28, 54, 63, -9, 43, 49, 10, 33, 36, + 29, 22, 22, 48, 11, 8, 67, 1, -4, 86, -9, -18, + -45, 63, 80, -26, 53, 67, -7, 42, 53, 12, 31, 40, + 32, 20, 26, 50, 10, 12, 69, 0, 0, 88, -11, -14, + -42, 62, 85, -23, 51, 71, -4, 40, 58, 15, 30, 44, + 34, 19, 30, 53, 8, 17, 72, -1, 4, 91, -12, -9, + -40, 61, 89, -21, 50, 75, -2, 39, 62, 17, 28, 48, + 37, 18, 34, 55, 7, 21, 74, -3, 8, 94, -14, -5, + -37, 59, 93, -19, 49, 79, 1, 38, 66, 20, 27, 52, + 39, 16, 38, 58, 6, 25, 77, -4, 12, 96, -15, -1, + -35, 58, 97, -16, 47, 83, 3, 36, 70, 22, 26, 56, + 41, 15, 42, 60, 4, 29, 79, -5, 16, 98, -16, 2, + -32, 56, 101, -13, 46, 88, 6, 35, 74, 25, 24, 61, + 44, 13, 47, 63, 3, 33, 82, -7, 20, 101, -18, 6, + -30, 55, 105, -11, 44, 92, 8, 33, 78, 27, 23, 65, + 46, 12, 51, 65, 1, 37, 84, -8, 24, 103, -19, 10, + -27, 54, 109, -9, 43, 96, 11, 32, 82, 29, 22, 69, + 49, 11, 55, 68, 0, 41, 86, -10, 28, 106, -21, 14, + -103, 101, -18, -84, 91, -31, -65, 80, -45, -46, 69, -59, + -26, 58, -72, -8, 48, -86, 11, 37, -99, 31, 26, -113, + -100, 100, -14, -81, 89, -27, -62, 78, -41, -43, 68, -55, + -24, 57, -68, -5, 46, -82, 14, 36, -95, 33, 25, -109, + -98, 98, -10, -79, 88, -23, -60, 77, -37, -41, 66, -51, + -22, 55, -64, -3, 45, -78, 16, 34, -91, 35, 23, -105, + -95, 97, -5, -76, 86, -19, -57, 75, -33, -38, 65, -46, + -19, 54, -60, 0, 43, -73, 19, 33, -87, 38, 22, -100, + -93, 96, -1, -74, 85, -15, -55, 74, -29, -36, 63, -42, + -16, 53, -56, 2, 42, -69, 21, 31, -83, 40, 20, -96, + -90, 94, 2, -72, 84, -11, -52, 73, -25, -33, 62, -38, + -14, 51, -52, 5, 41, -65, 23, 30, -79, 43, 19, -92, + -88, 93, 6, -69, 82, -7, -50, 71, -21, -31, 61, -34, + -12, 50, -48, 7, 39, -61, 26, 29, -75, 45, 18, -88, + -85, 91, 10, -67, 81, -2, -47, 70, -16, -28, 59, -30, + -9, 48, -43, 10, 38, -57, 29, 27, -70, 48, 16, -84, + -83, 90, 14, -64, 79, 1, -45, 69, -12, -26, 58, -26, + -7, 47, -39, 12, 36, -53, 31, 26, -66, 50, 15, -80, + -81, 89, 18, -62, 78, 5, -42, 67, -8, -24, 57, -22, + -4, 46, -35, 15, 35, -49, 33, 24, -62, 53, 13, -76, + -78, 87, 22, -59, 77, 9, -40, 66, -4, -21, 55, -18, + -2, 44, -31, 17, 34, -45, 36, 23, -58, 55, 12, -72, + -76, 86, 26, -57, 75, 13, -38, 64, 0, -19, 54, -14, + 1, 43, -27, 19, 32, -41, 38, 22, -54, 57, 11, -68, + -73, 84, 31, -54, 74, 17, -35, 63, 3, -16, 52, -9, + 3, 41, -23, 22, 31, -36, 41, 20, -50, 60, 9, -63, + -71, 83, 35, -52, 73, 21, -33, 62, 7, -14, 51, -5, + 6, 40, -19, 24, 29, -32, 43, 19, -46, 63, 8, -59, + -68, 82, 39, -49, 71, 25, -30, 60, 11, -11, 50, -1, + 8, 39, -15, 27, 28, -28, 46, 18, -42, 65, 7, -55, + -66, 80, 43, -47, 70, 29, -28, 59, 15, -9, 48, 2, + 10, 37, -11, 29, 27, -24, 48, 16, -38, 67, 5, -51, + -63, 79, 47, -44, 68, 34, -25, 57, 20, -6, 47, 6, + 13, 36, -6, 32, 25, -20, 51, 15, -33, 70, 4, -47, + -61, 78, 51, -42, 67, 38, -23, 56, 24, -4, 45, 10, + 16, 34, -2, 34, 24, -16, 53, 13, -29, 72, 2, -43, + -58, 76, 55, -40, 66, 42, -20, 55, 28, -1, 44, 14, + 18, 33, 1, 37, 23, -12, 55, 12, -25, 75, 1, -39, + -56, 75, 59, -37, 64, 46, -18, 53, 32, 1, 43, 18, + 20, 32, 5, 39, 21, -8, 58, 11, -21, 77, 0, -35, + -53, 73, 64, -35, 63, 50, -15, 52, 36, 4, 41, 23, + 23, 30, 9, 42, 20, -3, 61, 9, -17, 80, -1, -30, + -51, 72, 68, -32, 61, 54, -13, 50, 40, 6, 40, 27, + 25, 29, 13, 44, 18, 0, 63, 8, -13, 82, -2, -26, + -49, 71, 72, -30, 60, 58, -10, 49, 44, 8, 39, 31, + 28, 28, 17, 47, 17, 4, 65, 6, -9, 85, -4, -22, + -46, 69, 76, -27, 59, 62, -8, 48, 48, 11, 37, 35, + 30, 26, 21, 49, 16, 8, 68, 5, -5, 87, -5, -18, + -44, 68, 80, -25, 57, 66, -6, 46, 52, 13, 36, 39, + 33, 25, 25, 51, 14, 12, 70, 4, -1, 89, -6, -14, + -41, 66, 84, -22, 56, 71, -3, 45, 57, 16, 34, 43, + 35, 23, 30, 54, 13, 16, 73, 2, 3, 92, -8, -10, + -39, 65, 88, -20, 54, 75, -1, 44, 61, 18, 33, 47, + 38, 22, 34, 56, 11, 20, 75, 1, 7, 95, -9, -6, + -36, 64, 92, -18, 53, 79, 2, 42, 65, 21, 32, 51, + 40, 21, 38, 59, 10, 24, 78, 0, 11, 97, -10, -2, + -34, 62, 96, -15, 52, 83, 4, 41, 69, 23, 30, 55, + 42, 19, 42, 61, 9, 28, 80, -1, 15, 99, -12, 1, + -31, 61, 101, -12, 50, 87, 7, 39, 73, 26, 29, 60, + 45, 18, 46, 64, 7, 33, 83, -2, 19, 102, -13, 6, + -29, 59, 105, -10, 49, 91, 9, 38, 77, 28, 27, 64, + 47, 16, 50, 66, 6, 37, 85, -4, 23, 104, -15, 10, + -26, 58, 109, -8, 48, 95, 12, 37, 81, 31, 26, 68, + 50, 15, 54, 69, 4, 41, 87, -5, 27, 107, -16, 14, + -102, 105, -19, -83, 95, -32, -64, 84, -46, -45, 73, -59, + -25, 62, -73, -7, 52, -86, 12, 41, -100, 31, 30, -114, + -99, 104, -15, -81, 93, -28, -61, 82, -42, -42, 72, -55, + -23, 61, -69, -4, 50, -82, 15, 40, -96, 34, 29, -110, + -97, 102, -11, -78, 92, -24, -59, 81, -38, -40, 70, -51, + -21, 59, -65, -2, 49, -78, 17, 38, -92, 36, 27, -106, + -94, 101, -6, -75, 90, -19, -56, 79, -33, -37, 69, -47, + -18, 58, -61, 1, 47, -74, 20, 37, -87, 39, 26, -101, + -92, 100, -2, -73, 89, -15, -54, 78, -29, -35, 67, -43, + -16, 57, -57, 3, 46, -70, 22, 35, -83, 41, 24, -97, + -89, 98, 1, -71, 88, -11, -51, 77, -25, -33, 66, -39, + -13, 55, -53, 6, 45, -66, 24, 34, -79, 44, 23, -93, + -87, 97, 5, -68, 86, -7, -49, 75, -21, -30, 65, -35, + -11, 54, -49, 8, 43, -62, 27, 33, -75, 46, 22, -89, + -84, 95, 9, -66, 85, -3, -46, 74, -17, -27, 63, -30, + -8, 52, -44, 11, 42, -57, 29, 31, -71, 49, 20, -85, + -82, 94, 13, -63, 83, 0, -44, 73, -13, -25, 62, -26, + -6, 51, -40, 13, 40, -53, 32, 30, -67, 51, 19, -81, + -80, 93, 17, -61, 82, 4, -41, 71, -9, -23, 61, -22, + -3, 50, -36, 15, 39, -49, 34, 28, -63, 54, 17, -77, + -77, 91, 21, -58, 81, 8, -39, 70, -5, -20, 59, -18, + -1, 48, -32, 18, 38, -45, 37, 27, -59, 56, 16, -73, + -75, 90, 25, -56, 79, 12, -37, 68, -1, -18, 58, -14, + 1, 47, -28, 20, 36, -41, 39, 26, -55, 58, 15, -69, + -72, 88, 30, -53, 78, 17, -34, 67, 3, -15, 56, -10, + 4, 45, -24, 23, 35, -37, 42, 24, -50, 61, 13, -64, + -70, 87, 34, -51, 77, 21, -32, 66, 7, -13, 55, -6, + 7, 44, -20, 25, 33, -33, 44, 23, -46, 63, 12, -60, + -67, 86, 38, -49, 75, 25, -29, 64, 11, -10, 54, -2, + 9, 43, -16, 28, 32, -29, 47, 22, -42, 66, 11, -56, + -65, 84, 42, -46, 74, 29, -27, 63, 15, -8, 52, 1, + 11, 41, -12, 30, 31, -25, 49, 20, -38, 68, 9, -52, + -62, 83, 46, -44, 72, 33, -24, 61, 19, -5, 51, 6, + 14, 40, -7, 33, 29, -20, 52, 19, -34, 71, 8, -48, + -60, 82, 50, -41, 71, 37, -22, 60, 23, -3, 49, 10, + 16, 38, -3, 35, 28, -16, 54, 17, -30, 73, 6, -44, + -58, 80, 54, -39, 70, 41, -19, 59, 27, -1, 48, 14, + 19, 37, 0, 38, 27, -12, 56, 16, -26, 76, 5, -40, + -55, 79, 58, -36, 68, 45, -17, 57, 31, 2, 47, 18, + 21, 36, 4, 40, 25, -8, 59, 15, -22, 78, 4, -36, + -52, 77, 63, -34, 67, 50, -14, 56, 36, 5, 45, 22, + 24, 34, 8, 43, 24, -4, 61, 13, -17, 81, 2, -31, + -50, 76, 67, -31, 65, 54, -12, 54, 40, 7, 44, 26, + 26, 33, 12, 45, 22, 0, 64, 12, -13, 83, 1, -27, + -48, 75, 71, -29, 64, 58, -9, 53, 44, 9, 43, 30, + 29, 32, 16, 47, 21, 3, 66, 10, -9, 86, 0, -23, + -45, 73, 75, -26, 63, 62, -7, 52, 48, 12, 41, 34, + 31, 30, 20, 50, 20, 7, 69, 9, -5, 88, -1, -19, + -43, 72, 79, -24, 61, 66, -5, 50, 52, 14, 40, 38, + 33, 29, 24, 52, 18, 11, 71, 8, -1, 90, -2, -15, + -40, 70, 83, -21, 60, 70, -2, 49, 56, 17, 38, 43, + 36, 27, 29, 55, 17, 16, 74, 6, 2, 93, -4, -11, + -38, 69, 87, -19, 58, 74, 0, 48, 60, 19, 37, 47, + 39, 26, 33, 57, 15, 20, 76, 5, 6, 95, -5, -7, + -35, 68, 91, -17, 57, 78, 3, 46, 64, 22, 36, 51, + 41, 25, 37, 60, 14, 24, 79, 3, 10, 98, -6, -3, + -33, 66, 95, -14, 56, 82, 5, 45, 68, 24, 34, 55, + 43, 23, 41, 62, 13, 28, 81, 2, 14, 100, -8, 0, + -30, 65, 100, -12, 54, 87, 8, 43, 73, 27, 33, 59, + 46, 22, 45, 65, 11, 32, 84, 1, 19, 103, -9, 5, + -28, 63, 104, -9, 53, 91, 10, 42, 77, 29, 31, 63, + 48, 20, 49, 67, 10, 36, 86, 0, 23, 105, -11, 9, + -26, 62, 108, -7, 52, 95, 13, 41, 81, 31, 30, 67, + 51, 19, 53, 70, 8, 40, 88, -1, 27, 108, -12, 13, + -101, 109, -19, -82, 99, -33, -63, 88, -46, -44, 77, -60, + -25, 66, -74, -6, 56, -87, 13, 45, -100, 32, 34, -114, + -98, 108, -15, -80, 97, -29, -60, 86, -42, -42, 76, -56, + -22, 65, -70, -3, 54, -83, 15, 44, -96, 35, 33, -110, + -96, 106, -11, -77, 96, -25, -58, 85, -38, -39, 74, -52, + -20, 63, -66, -1, 53, -79, 18, 42, -92, 37, 31, -106, + -93, 105, -7, -75, 94, -20, -55, 83, -34, -36, 73, -47, + -17, 62, -61, 2, 51, -75, 21, 41, -88, 40, 30, -102, + -91, 104, -3, -72, 93, -16, -53, 82, -30, -34, 71, -43, + -15, 61, -57, 4, 50, -71, 23, 39, -84, 42, 28, -98, + -89, 102, 0, -70, 92, -12, -50, 81, -26, -32, 70, -39, + -12, 59, -53, 7, 49, -67, 25, 38, -80, 45, 27, -94, + -86, 101, 4, -67, 90, -8, -48, 79, -22, -29, 69, -35, + -10, 58, -49, 9, 47, -63, 28, 37, -76, 47, 26, -90, + -84, 99, 9, -65, 89, -4, -45, 78, -17, -27, 67, -31, + -7, 56, -45, 12, 46, -58, 30, 35, -71, 50, 24, -85, + -81, 98, 13, -62, 87, 0, -43, 77, -13, -24, 66, -27, + -5, 55, -41, 14, 44, -54, 33, 34, -67, 52, 23, -81, + -79, 97, 17, -60, 86, 3, -41, 75, -9, -22, 65, -23, + -2, 54, -37, 16, 43, -50, 35, 32, -63, 55, 21, -77, + -76, 95, 21, -58, 85, 7, -38, 74, -5, -19, 63, -19, + 0, 52, -33, 19, 42, -46, 38, 31, -59, 57, 20, -73, + -74, 94, 25, -55, 83, 11, -36, 72, -1, -17, 62, -15, + 2, 51, -29, 21, 40, -42, 40, 30, -55, 59, 19, -69, + -71, 92, 29, -52, 82, 16, -33, 71, 2, -14, 60, -10, + 5, 49, -24, 24, 39, -38, 43, 28, -51, 62, 17, -65, + -69, 91, 33, -50, 81, 20, -31, 70, 6, -12, 59, -6, + 7, 48, -20, 26, 37, -34, 45, 27, -47, 64, 16, -61, + -66, 90, 37, -48, 79, 24, -28, 68, 10, -10, 58, -2, + 10, 47, -16, 29, 36, -30, 47, 26, -43, 67, 15, -57, + -64, 88, 41, -45, 78, 28, -26, 67, 14, -7, 56, 1, + 12, 45, -12, 31, 35, -26, 50, 24, -39, 69, 13, -53, + -61, 87, 46, -43, 76, 32, -23, 65, 19, -4, 55, 5, + 15, 44, -8, 34, 33, -21, 53, 23, -34, 72, 12, -48, + -59, 86, 50, -40, 75, 36, -21, 64, 23, -2, 53, 9, + 17, 42, -4, 36, 32, -17, 55, 21, -30, 74, 10, -44, + -57, 84, 54, -38, 74, 40, -18, 63, 27, 0, 52, 13, + 20, 41, 0, 39, 31, -13, 57, 20, -26, 77, 9, -40, + -54, 83, 58, -35, 72, 44, -16, 61, 31, 3, 51, 17, + 22, 40, 3, 41, 29, -9, 60, 19, -22, 79, 8, -36, + -52, 81, 62, -33, 71, 49, -13, 60, 35, 5, 49, 22, + 25, 38, 8, 44, 28, -5, 62, 17, -18, 82, 6, -32, + -49, 80, 66, -30, 69, 53, -11, 58, 39, 8, 48, 26, + 27, 37, 12, 46, 26, -1, 65, 16, -14, 84, 5, -28, + -47, 79, 70, -28, 68, 57, -9, 57, 43, 10, 47, 30, + 30, 36, 16, 48, 25, 2, 67, 14, -10, 87, 3, -24, + -44, 77, 74, -26, 67, 61, -6, 56, 47, 13, 45, 34, + 32, 34, 20, 51, 24, 6, 70, 13, -6, 89, 2, -20, + -42, 76, 78, -23, 65, 65, -4, 54, 51, 15, 44, 38, + 34, 33, 24, 53, 22, 10, 72, 12, -2, 91, 1, -16, + -39, 74, 83, -20, 64, 69, -1, 53, 56, 18, 42, 42, + 37, 31, 28, 56, 21, 15, 75, 10, 2, 94, 0, -11, + -37, 73, 87, -18, 62, 73, 1, 52, 60, 20, 41, 46, + 39, 30, 32, 58, 19, 19, 77, 9, 6, 96, -1, -7, + -34, 72, 91, -16, 61, 77, 4, 50, 64, 22, 40, 50, + 42, 29, 36, 61, 18, 23, 79, 7, 10, 99, -2, -3, + -32, 70, 95, -13, 60, 81, 6, 49, 68, 25, 38, 54, + 44, 27, 40, 63, 17, 27, 82, 6, 14, 101, -4, 0, + -29, 69, 99, -11, 58, 86, 9, 47, 72, 28, 37, 59, + 47, 26, 45, 66, 15, 31, 84, 5, 18, 104, -5, 4, + -27, 67, 103, -8, 57, 90, 11, 46, 76, 30, 35, 63, + 49, 24, 49, 68, 14, 35, 87, 3, 22, 106, -7, 8, + -25, 66, 107, -6, 56, 94, 14, 45, 80, 32, 34, 67, + 52, 23, 53, 70, 12, 39, 89, 2, 26, 109, -8, 12, + -100, 113, -20, -81, 103, -33, -62, 92, -47, -43, 81, -60, + -24, 70, -74, -5, 60, -88, 14, 49, -101, 33, 38, -115, + -98, 112, -16, -79, 101, -29, -59, 90, -43, -41, 80, -56, + -21, 69, -70, -2, 58, -84, 16, 48, -97, 36, 37, -111, + -95, 110, -12, -76, 100, -25, -57, 89, -39, -38, 78, -52, + -19, 67, -66, 0, 57, -80, 19, 46, -93, 38, 35, -107, + -92, 109, -7, -74, 98, -21, -54, 87, -35, -36, 77, -48, + -16, 66, -62, 3, 55, -75, 21, 45, -89, 41, 34, -102, + -90, 108, -3, -71, 97, -17, -52, 86, -31, -33, 75, -44, + -14, 65, -58, 5, 54, -71, 24, 43, -85, 43, 32, -98, + -88, 106, 0, -69, 96, -13, -50, 85, -27, -31, 74, -40, + -11, 63, -54, 7, 53, -67, 26, 42, -81, 46, 31, -94, + -85, 105, 4, -66, 94, -9, -47, 83, -23, -28, 73, -36, + -9, 62, -50, 10, 51, -63, 29, 41, -77, 48, 30, -90, + -83, 103, 8, -64, 93, -4, -44, 82, -18, -26, 71, -31, + -6, 60, -45, 13, 50, -59, 31, 39, -72, 51, 28, -86, + -80, 102, 12, -61, 91, 0, -42, 81, -14, -23, 70, -27, + -4, 59, -41, 15, 48, -55, 34, 38, -68, 53, 27, -82, + -78, 101, 16, -59, 90, 3, -40, 79, -10, -21, 69, -23, + -1, 58, -37, 17, 47, -51, 36, 36, -64, 55, 25, -78, + -75, 99, 20, -57, 89, 7, -37, 78, -6, -18, 67, -19, + 1, 56, -33, 20, 46, -47, 38, 35, -60, 58, 24, -74, + -73, 98, 24, -54, 87, 11, -35, 76, -2, -16, 66, -15, + 3, 55, -29, 22, 44, -43, 41, 34, -56, 60, 23, -70, + -70, 96, 29, -52, 86, 15, -32, 75, 1, -13, 64, -11, + 6, 53, -25, 25, 43, -38, 44, 32, -52, 63, 21, -65, + -68, 95, 33, -49, 85, 19, -30, 74, 5, -11, 63, -7, + 8, 52, -21, 27, 41, -34, 46, 31, -48, 65, 20, -61, + -66, 94, 37, -47, 83, 23, -27, 72, 9, -9, 62, -3, + 11, 51, -17, 30, 40, -30, 48, 30, -44, 68, 19, -57, + -63, 92, 41, -44, 82, 27, -25, 71, 13, -6, 60, 0, + 13, 49, -13, 32, 39, -26, 51, 28, -40, 70, 17, -53, + -60, 91, 45, -42, 80, 32, -22, 69, 18, -4, 59, 5, + 16, 48, -8, 35, 37, -22, 53, 27, -35, 73, 16, -49, + -58, 90, 49, -39, 79, 36, -20, 68, 22, -1, 57, 9, + 18, 46, -4, 37, 36, -18, 56, 25, -31, 75, 14, -45, + -56, 88, 53, -37, 78, 40, -18, 67, 26, 1, 56, 13, + 21, 45, 0, 39, 35, -14, 58, 24, -27, 78, 13, -41, + -53, 87, 57, -35, 76, 44, -15, 65, 30, 4, 55, 17, + 23, 44, 3, 42, 33, -10, 61, 23, -23, 80, 12, -37, + -51, 85, 62, -32, 75, 48, -12, 64, 34, 6, 53, 21, + 26, 42, 7, 44, 32, -5, 63, 21, -19, 83, 10, -32, + -48, 84, 66, -29, 73, 52, -10, 62, 38, 9, 52, 25, + 28, 41, 11, 47, 30, -1, 66, 20, -15, 85, 9, -28, + -46, 83, 70, -27, 72, 56, -8, 61, 42, 11, 51, 29, + 30, 40, 15, 49, 29, 2, 68, 18, -11, 87, 7, -24, + -43, 81, 74, -25, 71, 60, -5, 60, 46, 14, 49, 33, + 33, 38, 19, 52, 28, 6, 70, 17, -7, 90, 6, -20, + -41, 80, 78, -22, 69, 64, -3, 58, 50, 16, 48, 37, + 35, 37, 23, 54, 26, 10, 73, 16, -3, 92, 5, -16, + -38, 78, 82, -20, 68, 69, 0, 57, 55, 19, 46, 42, + 38, 35, 28, 57, 25, 14, 76, 14, 1, 95, 3, -12, + -36, 77, 86, -17, 66, 73, 2, 56, 59, 21, 45, 46, + 40, 34, 32, 59, 23, 18, 78, 13, 5, 97, 2, -8, + -34, 76, 90, -15, 65, 77, 5, 54, 63, 23, 44, 50, + 43, 33, 36, 62, 22, 22, 80, 11, 9, 100, 1, -4, + -31, 74, 94, -12, 64, 81, 7, 53, 67, 26, 42, 54, + 45, 31, 40, 64, 21, 26, 83, 10, 13, 102, 0, 0, + -28, 73, 99, -10, 62, 85, 10, 51, 71, 28, 41, 58, + 48, 30, 44, 67, 19, 31, 85, 9, 17, 105, -1, 4, + -26, 71, 103, -7, 61, 89, 12, 50, 75, 31, 39, 62, + 50, 28, 48, 69, 18, 35, 88, 7, 21, 107, -3, 8, + -24, 70, 107, -5, 60, 93, 14, 49, 79, 33, 38, 66, + 53, 27, 52, 71, 16, 39, 90, 6, 25, 110, -4, 12, + -99, 118, -21, -80, 107, -34, -61, 96, -48, -42, 86, -61, + -23, 75, -75, -4, 64, -88, 15, 53, -102, 34, 42, -116, + -97, 116, -17, -78, 106, -30, -58, 95, -44, -40, 84, -57, + -20, 73, -71, -1, 63, -84, 17, 52, -98, 37, 41, -112, + -94, 115, -13, -75, 104, -26, -56, 93, -40, -37, 83, -53, + -18, 72, -67, 1, 61, -80, 20, 51, -94, 39, 40, -108, + -91, 113, -8, -73, 103, -22, -53, 92, -35, -34, 81, -49, + -15, 70, -63, 4, 60, -76, 22, 49, -89, 42, 38, -103, + -89, 112, -4, -70, 102, -18, -51, 91, -31, -32, 80, -45, + -13, 69, -59, 6, 58, -72, 25, 48, -85, 44, 37, -99, + -87, 111, 0, -68, 100, -14, -48, 89, -27, -30, 79, -41, + -10, 68, -55, 8, 57, -68, 27, 46, -81, 47, 36, -95, + -84, 109, 3, -65, 99, -10, -46, 88, -23, -27, 77, -37, + -8, 66, -51, 11, 56, -64, 30, 45, -77, 49, 34, -91, + -82, 108, 7, -63, 97, -5, -43, 86, -19, -25, 76, -32, + -5, 65, -46, 14, 54, -59, 32, 44, -73, 52, 33, -87, + -79, 107, 11, -60, 96, -1, -41, 85, -15, -22, 74, -28, + -3, 63, -42, 16, 53, -55, 35, 42, -69, 54, 31, -83, + -77, 105, 15, -58, 95, 2, -39, 84, -11, -20, 73, -24, + 0, 62, -38, 18, 52, -51, 37, 41, -65, 56, 30, -79, + -74, 104, 19, -56, 93, 6, -36, 82, -7, -17, 72, -20, + 2, 61, -34, 21, 50, -47, 39, 40, -61, 59, 29, -75, + -72, 102, 23, -53, 92, 10, -34, 81, -3, -15, 70, -16, + 4, 59, -30, 23, 49, -43, 42, 38, -57, 61, 27, -71, + -69, 101, 28, -51, 90, 14, -31, 79, 1, -12, 69, -12, + 7, 58, -26, 26, 47, -39, 45, 37, -52, 64, 26, -66, + -67, 100, 32, -48, 89, 18, -29, 78, 5, -10, 67, -8, + 9, 57, -22, 28, 46, -35, 47, 35, -48, 66, 24, -62, + -65, 98, 36, -46, 88, 22, -26, 77, 9, -8, 66, -4, + 12, 55, -18, 31, 45, -31, 49, 34, -44, 69, 23, -58, + -62, 97, 40, -43, 86, 26, -24, 75, 13, -5, 65, 0, + 14, 54, -14, 33, 43, -27, 52, 33, -40, 71, 22, -54, + -59, 95, 44, -41, 85, 31, -21, 74, 17, -2, 63, 4, + 17, 52, -9, 36, 42, -22, 54, 31, -36, 74, 20, -50, + -57, 94, 48, -38, 83, 35, -19, 73, 21, 0, 62, 8, + 19, 51, -5, 38, 40, -18, 57, 30, -32, 76, 19, -46, + -55, 93, 52, -36, 82, 39, -16, 71, 25, 2, 61, 12, + 22, 50, -1, 40, 39, -14, 59, 28, -28, 79, 18, -42, + -52, 91, 56, -33, 81, 43, -14, 70, 29, 5, 59, 16, + 24, 48, 2, 43, 38, -10, 62, 27, -24, 81, 16, -38, + -50, 90, 61, -31, 79, 47, -11, 68, 34, 7, 58, 20, + 27, 47, 6, 46, 36, -6, 64, 26, -19, 84, 15, -33, + -47, 88, 65, -28, 78, 51, -9, 67, 38, 10, 56, 24, + 29, 45, 10, 48, 35, -2, 67, 24, -15, 86, 13, -29, + -45, 87, 69, -26, 77, 55, -7, 66, 42, 12, 55, 28, + 32, 44, 14, 50, 33, 1, 69, 23, -11, 88, 12, -25, + -42, 86, 73, -24, 75, 59, -4, 64, 46, 15, 54, 32, + 34, 43, 18, 53, 32, 5, 71, 22, -7, 91, 11, -21, + -40, 84, 77, -21, 74, 63, -2, 63, 50, 17, 52, 36, + 36, 41, 22, 55, 31, 9, 74, 20, -3, 93, 9, -17, + -37, 83, 81, -19, 72, 68, 1, 61, 54, 20, 51, 41, + 39, 40, 27, 58, 29, 14, 77, 19, 0, 96, 8, -13, + -35, 82, 85, -16, 71, 72, 3, 60, 58, 22, 49, 45, + 41, 39, 31, 60, 28, 18, 79, 17, 4, 98, 6, -9, + -33, 80, 89, -14, 70, 76, 6, 59, 62, 24, 48, 49, + 44, 37, 35, 63, 27, 22, 81, 16, 8, 101, 5, -5, + -30, 79, 93, -11, 68, 80, 8, 57, 66, 27, 47, 53, + 46, 36, 39, 65, 25, 26, 84, 15, 12, 103, 4, -1, + -27, 77, 98, -9, 67, 84, 11, 56, 71, 29, 45, 57, + 49, 34, 43, 68, 24, 30, 86, 13, 17, 106, 2, 3, + -25, 76, 102, -6, 65, 88, 13, 54, 75, 32, 44, 61, + 51, 33, 47, 70, 22, 34, 89, 12, 21, 108, 1, 7, + -23, 75, 106, -4, 64, 92, 15, 53, 79, 34, 43, 65, + 54, 32, 51, 72, 21, 38, 91, 10, 25, 111, 0, 11, + -98, 122, -21, -79, 111, -35, -60, 100, -48, -41, 90, -62, + -22, 79, -76, -3, 68, -89, 16, 57, -102, 35, 46, -116, + -96, 120, -17, -77, 110, -31, -57, 99, -44, -39, 88, -58, + -19, 77, -72, -1, 67, -85, 18, 56, -98, 38, 45, -112, + -93, 119, -13, -74, 108, -27, -55, 97, -40, -36, 87, -54, + -17, 76, -68, 2, 65, -81, 21, 55, -94, 40, 44, -108, + -91, 117, -9, -72, 107, -22, -52, 96, -36, -34, 85, -49, + -14, 74, -63, 5, 64, -77, 23, 53, -90, 43, 42, -104, + -88, 116, -5, -69, 106, -18, -50, 95, -32, -31, 84, -45, + -12, 73, -59, 7, 62, -73, 26, 52, -86, 45, 41, -100, + -86, 115, -1, -67, 104, -14, -48, 93, -28, -29, 83, -41, + -9, 72, -55, 9, 61, -69, 28, 50, -82, 48, 40, -96, + -83, 113, 2, -65, 103, -10, -45, 92, -24, -26, 81, -37, + -7, 70, -51, 12, 60, -65, 31, 49, -78, 50, 38, -92, + -81, 112, 7, -62, 101, -6, -42, 90, -19, -24, 80, -33, + -4, 69, -47, 14, 58, -60, 33, 48, -73, 53, 37, -87, + -78, 111, 11, -59, 100, -2, -40, 89, -15, -21, 78, -29, + -2, 67, -43, 17, 57, -56, 36, 46, -69, 55, 35, -83, + -76, 109, 15, -57, 99, 1, -38, 88, -11, -19, 77, -25, + 0, 66, -39, 19, 56, -52, 38, 45, -65, 57, 34, -79, + -73, 108, 19, -55, 97, 5, -35, 86, -7, -17, 76, -21, + 3, 65, -35, 22, 54, -48, 40, 44, -61, 60, 33, -75, + -71, 106, 23, -52, 96, 9, -33, 85, -3, -14, 74, -17, + 5, 63, -31, 24, 53, -44, 43, 42, -57, 62, 31, -71, + -68, 105, 27, -50, 94, 14, -30, 83, 0, -11, 73, -12, + 8, 62, -26, 27, 51, -40, 45, 41, -53, 65, 30, -67, + -66, 104, 31, -47, 93, 18, -28, 82, 4, -9, 71, -8, + 10, 61, -22, 29, 50, -36, 48, 39, -49, 67, 28, -63, + -64, 102, 35, -45, 92, 22, -25, 81, 8, -7, 70, -4, + 13, 59, -18, 31, 49, -32, 50, 38, -45, 70, 27, -59, + -61, 101, 39, -42, 90, 26, -23, 79, 12, -4, 69, 0, + 15, 58, -14, 34, 47, -28, 53, 37, -41, 72, 26, -55, + -59, 99, 44, -40, 89, 30, -20, 78, 17, -2, 67, 3, + 18, 56, -10, 37, 46, -23, 55, 35, -36, 75, 24, -50, + -56, 98, 48, -37, 87, 34, -18, 77, 21, 1, 66, 7, + 20, 55, -6, 39, 44, -19, 58, 34, -32, 77, 23, -46, + -54, 97, 52, -35, 86, 38, -16, 75, 25, 3, 65, 11, + 23, 54, -2, 41, 43, -15, 60, 32, -28, 80, 22, -42, + -51, 95, 56, -33, 85, 42, -13, 74, 29, 6, 63, 15, + 25, 52, 1, 44, 42, -11, 63, 31, -24, 82, 20, -38, + -49, 94, 60, -30, 83, 47, -11, 72, 33, 8, 62, 20, + 28, 51, 6, 46, 40, -7, 65, 30, -20, 85, 19, -34, + -46, 92, 64, -27, 82, 51, -8, 71, 37, 11, 60, 24, + 30, 49, 10, 49, 39, -3, 68, 28, -16, 87, 17, -30, + -44, 91, 68, -25, 81, 55, -6, 70, 41, 13, 59, 28, + 32, 48, 14, 51, 37, 0, 70, 27, -12, 89, 16, -26, + -41, 90, 72, -23, 79, 59, -3, 68, 45, 15, 58, 32, + 35, 47, 18, 54, 36, 4, 72, 26, -8, 92, 15, -22, + -39, 88, 76, -20, 78, 63, -1, 67, 49, 18, 56, 36, + 37, 45, 22, 56, 35, 8, 75, 24, -4, 94, 13, -18, + -36, 87, 81, -18, 76, 67, 2, 65, 54, 21, 55, 40, + 40, 44, 26, 59, 33, 13, 77, 23, 0, 97, 12, -13, + -34, 86, 85, -15, 75, 71, 4, 64, 58, 23, 53, 44, + 42, 43, 30, 61, 32, 17, 80, 21, 4, 99, 10, -9, + -32, 84, 89, -13, 74, 75, 7, 63, 62, 25, 52, 48, + 45, 41, 34, 63, 31, 21, 82, 20, 8, 102, 9, -5, + -29, 83, 93, -10, 72, 79, 9, 61, 66, 28, 51, 52, + 47, 40, 38, 66, 29, 25, 85, 19, 12, 104, 8, -1, + -27, 81, 97, -8, 71, 84, 12, 60, 70, 30, 49, 57, + 50, 38, 43, 69, 28, 29, 87, 17, 16, 107, 6, 2, + -24, 80, 101, -5, 69, 88, 14, 58, 74, 33, 48, 61, + 52, 37, 47, 71, 26, 33, 90, 16, 20, 109, 5, 6, + -22, 79, 105, -3, 68, 92, 16, 57, 78, 35, 47, 65, + 55, 36, 51, 73, 25, 37, 92, 14, 24, 112, 3, 10, + -97, 126, -22, -78, 115, -35, -59, 104, -49, -40, 94, -63, + -21, 83, -76, -2, 72, -90, 17, 61, -103, 36, 50, -117, + -95, 124, -18, -76, 114, -31, -57, 103, -45, -38, 92, -59, + -18, 81, -72, 0, 71, -86, 19, 60, -99, 39, 49, -113, + -92, 123, -14, -74, 112, -27, -54, 101, -41, -35, 91, -55, + -16, 80, -68, 3, 69, -82, 22, 59, -95, 41, 48, -109, + -90, 121, -9, -71, 111, -23, -51, 100, -37, -33, 89, -50, + -13, 78, -64, 5, 68, -77, 24, 57, -91, 44, 46, -104, + -87, 120, -5, -68, 110, -19, -49, 99, -33, -30, 88, -46, + -11, 77, -60, 8, 66, -73, 27, 56, -87, 46, 45, -100, + -85, 119, -1, -66, 108, -15, -47, 97, -29, -28, 87, -42, + -9, 76, -56, 10, 65, -69, 29, 54, -83, 48, 44, -96, + -82, 117, 2, -64, 107, -11, -44, 96, -25, -25, 85, -38, + -6, 74, -52, 13, 64, -65, 31, 53, -79, 51, 42, -92, + -80, 116, 6, -61, 105, -6, -42, 94, -20, -23, 84, -34, + -3, 73, -47, 15, 62, -61, 34, 52, -74, 54, 41, -88, + -77, 115, 10, -59, 104, -2, -39, 93, -16, -20, 82, -30, + -1, 71, -43, 18, 61, -57, 37, 50, -70, 56, 39, -84, + -75, 113, 14, -56, 103, 1, -37, 92, -12, -18, 81, -26, + 1, 70, -39, 20, 60, -53, 39, 49, -66, 58, 38, -80, + -73, 112, 18, -54, 101, 5, -34, 90, -8, -16, 80, -22, + 4, 69, -35, 23, 58, -49, 41, 48, -62, 61, 37, -76, + -70, 110, 22, -51, 100, 9, -32, 89, -4, -13, 78, -18, + 6, 67, -31, 25, 57, -45, 44, 46, -58, 63, 35, -72, + -67, 109, 27, -49, 98, 13, -29, 87, 0, -11, 77, -13, + 9, 66, -27, 28, 55, -40, 46, 45, -54, 66, 34, -67, + -65, 108, 31, -46, 97, 17, -27, 86, 3, -8, 75, -9, + 11, 65, -23, 30, 54, -36, 49, 43, -50, 68, 32, -63, + -63, 106, 35, -44, 96, 21, -25, 85, 7, -6, 74, -5, + 14, 63, -19, 32, 53, -32, 51, 42, -46, 71, 31, -59, + -60, 105, 39, -42, 94, 25, -22, 83, 11, -3, 73, -1, + 16, 62, -15, 35, 51, -28, 54, 41, -42, 73, 30, -55, + -58, 103, 43, -39, 93, 30, -19, 82, 16, -1, 71, 2, + 19, 60, -10, 37, 50, -24, 56, 39, -37, 76, 28, -51, + -55, 102, 47, -36, 91, 34, -17, 81, 20, 2, 70, 6, + 21, 59, -6, 40, 48, -20, 59, 38, -33, 78, 27, -47, + -53, 101, 51, -34, 90, 38, -15, 79, 24, 4, 69, 10, + 23, 58, -2, 42, 47, -16, 61, 36, -29, 80, 26, -43, + -50, 99, 55, -32, 89, 42, -12, 78, 28, 7, 67, 14, + 26, 56, 1, 45, 46, -12, 63, 35, -25, 83, 24, -39, + -48, 98, 60, -29, 87, 46, -10, 76, 32, 9, 66, 19, + 29, 55, 5, 47, 44, -7, 66, 34, -21, 86, 23, -34, + -45, 96, 64, -27, 86, 50, -7, 75, 36, 12, 64, 23, + 31, 53, 9, 50, 43, -3, 69, 32, -17, 88, 21, -30, + -43, 95, 68, -24, 85, 54, -5, 74, 40, 14, 63, 27, + 33, 52, 13, 52, 41, 0, 71, 31, -13, 90, 20, -26, + -41, 94, 72, -22, 83, 58, -2, 72, 44, 16, 62, 31, + 36, 51, 17, 55, 40, 4, 73, 30, -9, 93, 19, -22, + -38, 92, 76, -19, 82, 62, 0, 71, 48, 19, 60, 35, + 38, 49, 21, 57, 39, 8, 76, 28, -5, 95, 17, -18, + -35, 91, 80, -17, 80, 67, 3, 69, 53, 21, 59, 39, + 41, 48, 26, 60, 37, 12, 78, 27, 0, 98, 16, -14, + -33, 90, 84, -14, 79, 71, 5, 68, 57, 24, 57, 43, + 43, 47, 30, 62, 36, 16, 81, 25, 3, 100, 14, -10, + -31, 88, 88, -12, 78, 75, 7, 67, 61, 26, 56, 47, + 46, 45, 34, 64, 35, 20, 83, 24, 7, 103, 13, -6, + -28, 87, 92, -10, 76, 79, 10, 65, 65, 29, 55, 51, + 48, 44, 38, 67, 33, 24, 86, 23, 11, 105, 12, -2, + -26, 85, 97, -7, 75, 83, 13, 64, 69, 31, 53, 56, + 51, 42, 42, 69, 32, 29, 88, 21, 15, 108, 10, 2, + -23, 84, 101, -4, 73, 87, 15, 62, 73, 34, 52, 60, + 53, 41, 46, 72, 30, 33, 91, 20, 19, 110, 9, 6, + -21, 83, 105, -2, 72, 91, 17, 61, 77, 36, 51, 64, + 55, 40, 50, 74, 29, 37, 93, 18, 23, 112, 7, 10, + -124, -2, -3, -105, -13, -16, -86, -24, -30, -67, -34, -43, + -47, -45, -57, -29, -56, -71, -10, -66, -84, 9, -77, -98, + -121, -4, 0, -103, -14, -12, -83, -25, -26, -64, -36, -39, + -45, -47, -53, -26, -57, -67, -8, -68, -80, 12, -79, -94, + -119, -5, 4, -100, -15, -8, -81, -26, -22, -62, -37, -35, + -43, -48, -49, -24, -59, -63, -5, -69, -76, 14, -80, -90, + -116, -6, 9, -98, -17, -4, -78, -28, -18, -59, -39, -31, + -40, -49, -45, -21, -60, -58, -2, -71, -72, 17, -82, -85, + -114, -8, 13, -95, -18, 0, -76, -29, -14, -57, -40, -27, + -38, -51, -41, -19, -61, -54, 0, -72, -68, 19, -83, -81, + -112, -9, 17, -93, -20, 3, -73, -31, -10, -55, -41, -23, + -35, -52, -37, -16, -63, -50, 2, -73, -64, 22, -84, -77, + -109, -10, 21, -90, -21, 7, -71, -32, -6, -52, -43, -19, + -33, -53, -33, -14, -64, -46, 5, -75, -60, 24, -86, -73, + -106, -12, 25, -88, -23, 12, -68, -33, -1, -50, -44, -14, + -30, -55, -28, -11, -66, -42, 7, -76, -55, 27, -87, -69, + -104, -13, 29, -85, -24, 16, -66, -35, 2, -47, -45, -10, + -28, -56, -24, -9, -67, -38, 10, -78, -51, 29, -88, -65, + -102, -15, 33, -83, -25, 20, -64, -36, 6, -45, -47, -6, + -25, -58, -20, -7, -68, -34, 12, -79, -47, 32, -90, -61, + -99, -16, 37, -81, -27, 24, -61, -38, 10, -42, -48, -2, + -23, -59, -16, -4, -70, -30, 15, -80, -43, 34, -91, -57, + -97, -17, 41, -78, -28, 28, -59, -39, 14, -40, -49, 1, + -21, -60, -12, -2, -71, -26, 17, -82, -39, 36, -93, -53, + -94, -19, 46, -75, -29, 32, -56, -40, 18, -37, -51, 5, + -18, -62, -8, 1, -73, -21, 20, -83, -35, 39, -94, -48, + -92, -20, 50, -73, -31, 36, -54, -42, 22, -35, -52, 9, + -16, -63, -4, 3, -74, -17, 22, -84, -31, 41, -95, -44, + -89, -22, 54, -71, -32, 40, -51, -43, 26, -32, -54, 13, + -13, -65, 0, 6, -75, -13, 24, -86, -27, 44, -97, -40, + -87, -23, 58, -68, -34, 44, -49, -44, 30, -30, -55, 17, + -11, -66, 3, 8, -77, -9, 27, -87, -23, 46, -98, -36, + -84, -24, 62, -66, -35, 49, -46, -46, 35, -27, -57, 22, + -8, -67, 8, 11, -78, -5, 30, -89, -18, 49, -100, -32, + -82, -26, 66, -63, -36, 53, -44, -47, 39, -25, -58, 26, + -6, -69, 12, 13, -79, -1, 32, -90, -14, 51, -101, -28, + -80, -27, 70, -61, -38, 57, -41, -49, 43, -23, -59, 30, + -3, -70, 16, 16, -81, 2, 34, -91, -10, 54, -102, -24, + -77, -28, 74, -58, -39, 61, -39, -50, 47, -20, -61, 34, + -1, -72, 20, 18, -82, 6, 37, -93, -6, 56, -104, -20, + -74, -30, 79, -56, -41, 65, -36, -52, 51, -18, -62, 38, + 2, -73, 24, 21, -84, 11, 39, -94, -2, 59, -105, -15, + -72, -31, 83, -53, -42, 69, -34, -53, 55, -15, -63, 42, + 4, -74, 28, 23, -85, 15, 42, -96, 1, 61, -107, -11, + -70, -33, 87, -51, -43, 73, -32, -54, 59, -13, -65, 46, + 7, -76, 32, 25, -86, 19, 44, -97, 5, 64, -108, -7, + -67, -34, 91, -49, -45, 77, -29, -56, 63, -10, -66, 50, + 9, -77, 36, 28, -88, 23, 47, -98, 9, 66, -109, -3, + -65, -35, 95, -46, -46, 81, -27, -57, 67, -8, -68, 54, + 11, -78, 40, 30, -89, 27, 49, -100, 13, 68, -111, 0, + -62, -37, 99, -43, -48, 86, -24, -58, 72, -5, -69, 59, + 14, -80, 45, 33, -91, 31, 52, -101, 18, 71, -112, 4, + -60, -38, 103, -41, -49, 90, -22, -60, 76, -3, -70, 63, + 16, -81, 49, 35, -92, 35, 54, -103, 22, 73, -113, 8, + -57, -40, 107, -39, -50, 94, -19, -61, 80, 0, -72, 67, + 19, -83, 53, 38, -93, 39, 56, -104, 26, 76, -115, 12, + -55, -41, 111, -36, -52, 98, -17, -62, 84, 2, -73, 71, + 21, -84, 57, 40, -95, 43, 59, -105, 30, 78, -116, 16, + -52, -42, 116, -34, -53, 102, -14, -64, 88, 5, -75, 75, + 24, -86, 61, 43, -96, 48, 62, -107, 34, 81, -118, 21, + -50, -44, 120, -31, -54, 106, -12, -65, 92, 7, -76, 79, + 26, -87, 65, 45, -97, 52, 64, -108, 38, 83, -119, 25, + -48, -45, 124, -29, -56, 110, -9, -67, 96, 9, -77, 83, + 29, -88, 69, 48, -99, 56, 66, -109, 42, 86, -120, 29, + -123, 1, -4, -104, -9, -17, -85, -20, -31, -66, -30, -44, + -47, -41, -58, -28, -52, -71, -9, -62, -85, 10, -73, -99, + -121, 0, 0, -102, -10, -13, -82, -21, -27, -64, -32, -40, + -44, -43, -54, -25, -53, -67, -7, -64, -81, 13, -75, -95, + -118, -1, 4, -99, -11, -9, -80, -22, -23, -61, -33, -36, + -42, -44, -50, -23, -55, -63, -4, -65, -77, 15, -76, -91, + -115, -2, 8, -97, -13, -4, -77, -24, -18, -58, -35, -32, + -39, -45, -45, -20, -56, -59, -2, -67, -72, 18, -78, -86, + -113, -4, 12, -94, -14, 0, -75, -25, -14, -56, -36, -28, + -37, -47, -41, -18, -57, -55, 1, -68, -68, 20, -79, -82, + -111, -5, 16, -92, -16, 3, -72, -27, -10, -54, -37, -24, + -34, -48, -37, -16, -59, -51, 3, -69, -64, 23, -80, -78, + -108, -6, 20, -89, -17, 7, -70, -28, -6, -51, -39, -20, + -32, -49, -33, -13, -60, -47, 6, -71, -60, 25, -82, -74, + -106, -8, 25, -87, -19, 11, -67, -29, -2, -49, -40, -15, + -29, -51, -29, -10, -62, -42, 8, -72, -56, 28, -83, -70, + -103, -9, 29, -84, -20, 15, -65, -31, 1, -46, -41, -11, + -27, -52, -25, -8, -63, -38, 11, -74, -52, 30, -84, -66, + -101, -11, 33, -82, -21, 19, -63, -32, 5, -44, -43, -7, + -24, -54, -21, -6, -64, -34, 13, -75, -48, 32, -86, -62, + -98, -12, 37, -80, -23, 23, -60, -34, 9, -41, -44, -3, + -22, -55, -17, -3, -66, -30, 16, -76, -44, 35, -87, -58, + -96, -13, 41, -77, -24, 27, -58, -35, 13, -39, -45, 0, + -20, -56, -13, -1, -67, -26, 18, -78, -40, 37, -89, -54, + -93, -15, 45, -75, -25, 32, -55, -36, 18, -36, -47, 4, + -17, -58, -8, 2, -69, -22, 21, -79, -35, 40, -90, -49, + -91, -16, 49, -72, -27, 36, -53, -38, 22, -34, -48, 8, + -15, -59, -4, 4, -70, -18, 23, -80, -31, 42, -91, -45, + -89, -18, 53, -70, -28, 40, -50, -39, 26, -32, -50, 12, + -12, -61, 0, 7, -71, -14, 25, -82, -27, 45, -93, -41, + -86, -19, 57, -67, -30, 44, -48, -40, 30, -29, -51, 16, + -10, -62, 3, 9, -73, -10, 28, -83, -23, 47, -94, -37, + -83, -20, 62, -65, -31, 48, -45, -42, 34, -26, -53, 21, + -7, -63, 7, 12, -74, -5, 30, -85, -19, 50, -96, -33, + -81, -22, 66, -62, -32, 52, -43, -43, 38, -24, -54, 25, + -5, -65, 11, 14, -75, -1, 33, -86, -15, 52, -97, -29, + -79, -23, 70, -60, -34, 56, -40, -45, 42, -22, -55, 29, + -2, -66, 15, 16, -77, 2, 35, -87, -11, 55, -98, -25, + -76, -24, 74, -57, -35, 60, -38, -46, 46, -19, -57, 33, + 0, -68, 19, 19, -78, 6, 38, -89, -7, 57, -100, -21, + -74, -26, 78, -55, -37, 65, -35, -48, 51, -17, -58, 37, + 3, -69, 24, 22, -80, 10, 40, -90, -2, 60, -101, -16, + -71, -27, 82, -52, -38, 69, -33, -49, 55, -14, -59, 41, + 5, -70, 28, 24, -81, 14, 43, -92, 1, 62, -103, -12, + -69, -29, 86, -50, -39, 73, -31, -50, 59, -12, -61, 45, + 8, -72, 32, 26, -82, 18, 45, -93, 5, 64, -104, -8, + -66, -30, 90, -48, -41, 77, -28, -52, 63, -9, -62, 49, + 10, -73, 36, 29, -84, 22, 47, -94, 9, 67, -105, -4, + -64, -31, 94, -45, -42, 81, -26, -53, 67, -7, -64, 53, + 12, -74, 40, 31, -85, 26, 50, -96, 13, 69, -107, 0, + -61, -33, 99, -43, -44, 85, -23, -54, 71, -4, -65, 58, + 15, -76, 44, 34, -87, 31, 53, -97, 17, 72, -108, 3, + -59, -34, 103, -40, -45, 89, -21, -56, 75, -2, -66, 62, + 17, -77, 48, 36, -88, 35, 55, -99, 21, 74, -109, 7, + -57, -36, 107, -38, -46, 93, -18, -57, 79, 0, -68, 66, + 20, -79, 52, 39, -89, 39, 57, -100, 25, 77, -111, 11, + -54, -37, 111, -35, -48, 97, -16, -58, 83, 3, -69, 70, + 22, -80, 56, 41, -91, 43, 60, -101, 29, 79, -112, 15, + -51, -38, 115, -33, -49, 102, -13, -60, 88, 6, -71, 74, + 25, -82, 61, 44, -92, 47, 62, -103, 34, 82, -114, 20, + -49, -40, 119, -30, -50, 106, -11, -61, 92, 8, -72, 78, + 27, -83, 65, 46, -93, 51, 65, -104, 38, 84, -115, 24, + -47, -41, 123, -28, -52, 110, -8, -63, 96, 10, -73, 82, + 30, -84, 69, 48, -95, 55, 67, -105, 42, 87, -116, 28, + -122, 5, -4, -103, -5, -18, -84, -16, -31, -65, -26, -45, + -46, -37, -59, -27, -48, -72, -8, -58, -85, 11, -69, -99, + -120, 4, 0, -101, -6, -14, -81, -17, -27, -63, -28, -41, + -43, -39, -55, -24, -49, -68, -6, -60, -81, 14, -71, -95, + -117, 2, 3, -98, -7, -10, -79, -18, -23, -60, -29, -37, + -41, -40, -51, -22, -51, -64, -3, -61, -77, 16, -72, -91, + -115, 1, 7, -96, -9, -5, -76, -20, -19, -58, -31, -32, + -38, -41, -46, -19, -52, -59, -1, -63, -73, 19, -74, -87, + -112, 0, 11, -93, -10, -1, -74, -21, -15, -55, -32, -28, + -36, -43, -42, -17, -53, -55, 2, -64, -69, 21, -75, -83, + -110, -1, 15, -91, -12, 2, -72, -23, -11, -53, -33, -24, + -33, -44, -38, -15, -55, -51, 4, -65, -65, 24, -76, -79, + -107, -2, 19, -89, -13, 6, -69, -24, -7, -50, -35, -20, + -31, -45, -34, -12, -56, -47, 7, -67, -61, 26, -78, -75, + -105, -4, 24, -86, -15, 10, -66, -25, -2, -48, -36, -16, + -28, -47, -30, -10, -58, -43, 9, -68, -56, 29, -79, -70, + -102, -5, 28, -83, -16, 14, -64, -27, 1, -45, -37, -12, + -26, -48, -26, -7, -59, -39, 12, -70, -52, 31, -80, -66, + -100, -7, 32, -81, -17, 18, -62, -28, 5, -43, -39, -8, + -24, -50, -22, -5, -60, -35, 14, -71, -48, 33, -82, -62, + -97, -8, 36, -79, -19, 22, -59, -30, 9, -41, -40, -4, + -21, -51, -18, -2, -62, -31, 16, -72, -44, 36, -83, -58, + -95, -9, 40, -76, -20, 26, -57, -31, 13, -38, -41, 0, + -19, -52, -14, 0, -63, -27, 19, -74, -40, 38, -85, -54, + -92, -11, 44, -74, -21, 31, -54, -32, 17, -35, -43, 4, + -16, -54, -9, 3, -65, -22, 21, -75, -36, 41, -86, -50, + -90, -12, 48, -71, -23, 35, -52, -34, 21, -33, -44, 8, + -14, -55, -5, 5, -66, -18, 24, -76, -32, 43, -87, -46, + -88, -14, 52, -69, -24, 39, -49, -35, 25, -31, -46, 12, + -11, -57, -1, 7, -67, -14, 26, -78, -28, 46, -89, -42, + -85, -15, 56, -66, -26, 43, -47, -36, 29, -28, -47, 16, + -9, -58, 2, 10, -69, -10, 29, -79, -24, 48, -90, -38, + -83, -16, 61, -64, -27, 47, -44, -38, 34, -26, -49, 20, + -6, -59, 6, 13, -70, -6, 31, -81, -19, 51, -92, -33, + -80, -18, 65, -61, -28, 51, -42, -39, 38, -23, -50, 24, + -4, -61, 10, 15, -71, -2, 34, -82, -15, 53, -93, -29, + -78, -19, 69, -59, -30, 55, -40, -41, 42, -21, -51, 28, + -1, -62, 14, 17, -73, 1, 36, -83, -11, 56, -94, -25, + -75, -20, 73, -57, -31, 59, -37, -42, 46, -18, -53, 32, + 1, -64, 18, 20, -74, 5, 39, -85, -7, 58, -96, -21, + -73, -22, 77, -54, -33, 64, -34, -44, 50, -16, -54, 37, + 4, -65, 23, 22, -76, 10, 41, -86, -3, 61, -97, -17, + -70, -23, 81, -51, -34, 68, -32, -45, 54, -13, -55, 41, + 6, -66, 27, 25, -77, 14, 44, -88, 0, 63, -99, -13, + -68, -25, 85, -49, -35, 72, -30, -46, 58, -11, -57, 45, + 8, -68, 31, 27, -78, 18, 46, -89, 4, 65, -100, -9, + -65, -26, 89, -47, -37, 76, -27, -48, 62, -9, -58, 49, + 11, -69, 35, 30, -80, 22, 48, -90, 8, 68, -101, -5, + -63, -27, 93, -44, -38, 80, -25, -49, 66, -6, -60, 53, + 13, -70, 39, 32, -81, 26, 51, -92, 12, 70, -103, -1, + -60, -29, 98, -42, -40, 84, -22, -50, 71, -3, -61, 57, + 16, -72, 43, 35, -83, 30, 53, -93, 17, 73, -104, 3, + -58, -30, 102, -39, -41, 88, -20, -52, 75, -1, -62, 61, + 18, -73, 47, 37, -84, 34, 56, -95, 21, 75, -105, 7, + -56, -32, 106, -37, -42, 92, -17, -53, 79, 1, -64, 65, + 21, -75, 51, 39, -85, 38, 58, -96, 25, 78, -107, 11, + -53, -33, 110, -34, -44, 96, -15, -54, 83, 4, -65, 69, + 23, -76, 55, 42, -87, 42, 61, -97, 29, 80, -108, 15, + -51, -34, 114, -32, -45, 101, -12, -56, 87, 6, -67, 74, + 26, -78, 60, 45, -88, 47, 63, -99, 33, 83, -110, 19, + -48, -36, 118, -29, -46, 105, -10, -57, 91, 9, -68, 78, + 28, -79, 64, 47, -89, 51, 66, -100, 37, 85, -111, 23, + -46, -37, 122, -27, -48, 109, -8, -59, 95, 11, -69, 82, + 31, -80, 68, 49, -91, 55, 68, -101, 41, 88, -112, 27, + -121, 9, -5, -102, 0, -18, -83, -11, -32, -64, -22, -45, + -45, -33, -59, -26, -43, -73, -7, -54, -86, 12, -65, -100, + -119, 8, -1, -100, -2, -14, -80, -13, -28, -62, -23, -41, + -42, -34, -55, -23, -45, -69, -5, -55, -82, 15, -66, -96, + -116, 7, 2, -97, -3, -10, -78, -14, -24, -59, -24, -37, + -40, -35, -51, -21, -46, -65, -2, -57, -78, 17, -68, -92, + -113, 5, 7, -95, -4, -6, -75, -15, -20, -57, -26, -33, + -37, -37, -47, -18, -48, -60, 0, -58, -74, 20, -69, -87, + -111, 4, 11, -92, -6, -2, -73, -17, -16, -54, -27, -29, + -35, -38, -43, -16, -49, -56, 3, -59, -70, 22, -70, -83, + -109, 2, 15, -90, -7, 1, -71, -18, -12, -52, -29, -25, + -32, -40, -39, -14, -50, -52, 5, -61, -66, 25, -72, -79, + -106, 1, 19, -88, -9, 5, -68, -19, -8, -49, -30, -21, + -30, -41, -35, -11, -52, -48, 8, -62, -62, 27, -73, -75, + -104, 0, 23, -85, -10, 10, -65, -21, -3, -47, -32, -16, + -27, -43, -30, -9, -53, -44, 10, -64, -57, 30, -75, -71, + -101, -1, 27, -82, -11, 14, -63, -22, 0, -44, -33, -12, + -25, -44, -26, -6, -54, -40, 13, -65, -53, 32, -76, -67, + -99, -2, 31, -80, -13, 18, -61, -24, 4, -42, -34, -8, + -23, -45, -22, -4, -56, -36, 15, -66, -49, 34, -77, -63, + -96, -3, 35, -78, -14, 22, -58, -25, 8, -39, -36, -4, + -20, -47, -18, -1, -57, -32, 17, -68, -45, 37, -79, -59, + -94, -5, 39, -75, -15, 26, -56, -26, 12, -37, -37, 0, + -18, -48, -14, 1, -59, -28, 20, -69, -41, 39, -80, -55, + -91, -6, 44, -73, -17, 30, -53, -28, 16, -34, -38, 3, + -15, -49, -10, 4, -60, -23, 23, -71, -37, 42, -82, -50, + -89, -8, 48, -70, -18, 34, -51, -29, 20, -32, -40, 7, + -13, -51, -6, 6, -61, -19, 25, -72, -33, 44, -83, -46, + -87, -9, 52, -68, -20, 38, -48, -31, 24, -30, -41, 11, + -10, -52, -2, 9, -63, -15, 27, -73, -29, 47, -84, -42, + -84, -10, 56, -65, -21, 42, -46, -32, 28, -27, -43, 15, + -8, -53, 1, 11, -64, -11, 30, -75, -25, 49, -86, -38, + -81, -12, 60, -63, -23, 47, -43, -33, 33, -25, -44, 20, + -5, -55, 6, 14, -66, -7, 32, -76, -20, 52, -87, -34, + -79, -13, 64, -60, -24, 51, -41, -35, 37, -22, -45, 24, + -3, -56, 10, 16, -67, -3, 35, -78, -16, 54, -88, -30, + -77, -15, 68, -58, -25, 55, -39, -36, 41, -20, -47, 28, + 0, -58, 14, 18, -68, 0, 37, -79, -12, 57, -90, -26, + -74, -16, 72, -56, -27, 59, -36, -38, 45, -17, -48, 32, + 2, -59, 18, 21, -70, 4, 40, -80, -8, 59, -91, -22, + -72, -17, 77, -53, -28, 63, -33, -39, 49, -15, -50, 36, + 5, -61, 22, 23, -71, 9, 42, -82, -4, 62, -93, -17, + -69, -19, 81, -50, -29, 67, -31, -40, 53, -12, -51, 40, + 7, -62, 26, 26, -73, 13, 45, -83, 0, 64, -94, -13, + -67, -20, 85, -48, -31, 71, -29, -42, 57, -10, -52, 44, + 9, -63, 30, 28, -74, 17, 47, -84, 3, 66, -95, -9, + -64, -22, 89, -46, -32, 75, -26, -43, 61, -8, -54, 48, + 12, -65, 34, 31, -75, 21, 49, -86, 7, 69, -97, -5, + -62, -23, 93, -43, -33, 79, -24, -44, 65, -5, -55, 52, + 14, -66, 38, 33, -77, 25, 52, -87, 11, 71, -98, -1, + -59, -24, 97, -41, -35, 84, -21, -46, 70, -2, -57, 57, + 17, -67, 43, 36, -78, 29, 55, -89, 16, 74, -100, 2, + -57, -26, 101, -38, -36, 88, -19, -47, 74, 0, -58, 61, + 19, -69, 47, 38, -79, 33, 57, -90, 20, 76, -101, 6, + -55, -27, 105, -36, -38, 92, -16, -49, 78, 2, -59, 65, + 22, -70, 51, 41, -81, 37, 59, -91, 24, 79, -102, 10, + -52, -28, 109, -33, -39, 96, -14, -50, 82, 5, -61, 69, + 24, -72, 55, 43, -82, 41, 62, -93, 28, 81, -104, 14, + -49, -30, 114, -31, -41, 100, -11, -52, 86, 7, -62, 73, + 27, -73, 59, 46, -84, 46, 64, -94, 32, 84, -105, 19, + -47, -31, 118, -28, -42, 104, -9, -53, 90, 10, -63, 77, + 29, -74, 63, 48, -85, 50, 67, -96, 36, 86, -107, 23, + -45, -33, 122, -26, -43, 108, -7, -54, 94, 12, -65, 81, + 32, -76, 67, 50, -86, 54, 69, -97, 40, 89, -108, 27, + -120, 13, -6, -101, 3, -19, -82, -7, -33, -63, -18, -46, + -44, -29, -60, -25, -39, -73, -6, -50, -87, 13, -61, -101, + -118, 12, -2, -99, 1, -15, -79, -9, -29, -61, -19, -42, + -41, -30, -56, -23, -41, -69, -4, -51, -83, 16, -62, -97, + -115, 11, 1, -96, 0, -11, -77, -10, -25, -58, -20, -38, + -39, -31, -52, -20, -42, -65, -1, -53, -79, 18, -64, -93, + -113, 9, 6, -94, 0, -6, -74, -11, -20, -56, -22, -34, + -36, -33, -47, -17, -44, -61, 1, -54, -74, 21, -65, -88, + -110, 8, 10, -91, -2, -2, -72, -13, -16, -53, -23, -30, + -34, -34, -43, -15, -45, -57, 4, -55, -70, 23, -66, -84, + -108, 6, 14, -89, -3, 1, -70, -14, -12, -51, -25, -26, + -31, -36, -39, -13, -46, -53, 6, -57, -66, 25, -68, -80, + -105, 5, 18, -87, -5, 5, -67, -15, -8, -48, -26, -22, + -29, -37, -35, -10, -48, -49, 8, -58, -62, 28, -69, -76, + -103, 4, 22, -84, -6, 9, -65, -17, -4, -46, -28, -17, + -26, -39, -31, -8, -49, -44, 11, -60, -58, 31, -71, -72, + -100, 2, 26, -82, -7, 13, -62, -18, 0, -43, -29, -13, + -24, -40, -27, -5, -50, -40, 14, -61, -54, 33, -72, -68, + -98, 1, 30, -79, -9, 17, -60, -20, 3, -41, -30, -9, + -22, -41, -23, -3, -52, -36, 16, -62, -50, 35, -73, -64, + -96, 0, 34, -77, -10, 21, -57, -21, 7, -39, -32, -5, + -19, -43, -19, 0, -53, -32, 18, -64, -46, 38, -75, -60, + -93, -1, 38, -74, -11, 25, -55, -22, 11, -36, -33, -1, + -17, -44, -15, 2, -55, -28, 21, -65, -42, 40, -76, -56, + -90, -2, 43, -72, -13, 30, -52, -24, 16, -34, -34, 2, + -14, -45, -10, 5, -56, -24, 23, -67, -37, 43, -78, -51, + -88, -4, 47, -69, -14, 34, -50, -25, 20, -31, -36, 6, + -12, -47, -6, 7, -57, -20, 26, -68, -33, 45, -79, -47, + -86, -5, 51, -67, -16, 38, -48, -27, 24, -29, -37, 10, + -9, -48, -2, 9, -59, -16, 28, -69, -29, 48, -80, -43, + -83, -6, 55, -64, -17, 42, -45, -28, 28, -26, -39, 14, + -7, -49, 1, 12, -60, -12, 31, -71, -25, 50, -82, -39, + -81, -8, 59, -62, -19, 46, -42, -29, 32, -24, -40, 19, + -4, -51, 5, 15, -62, -7, 33, -72, -21, 53, -83, -35, + -78, -9, 63, -59, -20, 50, -40, -31, 36, -21, -41, 23, + -2, -52, 9, 17, -63, -3, 36, -74, -17, 55, -84, -31, + -76, -11, 67, -57, -21, 54, -38, -32, 40, -19, -43, 27, + 1, -54, 13, 19, -64, 0, 38, -75, -13, 57, -86, -27, + -73, -12, 71, -55, -23, 58, -35, -34, 44, -16, -44, 31, + 3, -55, 17, 22, -66, 4, 40, -76, -9, 60, -87, -23, + -71, -13, 76, -52, -24, 63, -33, -35, 49, -14, -46, 35, + 6, -57, 22, 24, -67, 8, 43, -78, -4, 63, -89, -18, + -68, -15, 80, -50, -25, 67, -30, -36, 53, -11, -47, 39, + 8, -58, 26, 27, -69, 12, 46, -79, 0, 65, -90, -14, + -66, -16, 84, -47, -27, 71, -28, -38, 57, -9, -48, 43, + 10, -59, 30, 29, -70, 16, 48, -80, 3, 67, -91, -10, + -64, -18, 88, -45, -28, 75, -25, -39, 61, -7, -50, 47, + 13, -61, 34, 32, -71, 20, 50, -82, 7, 70, -93, -6, + -61, -19, 92, -42, -29, 79, -23, -40, 65, -4, -51, 51, + 15, -62, 38, 34, -73, 24, 53, -83, 11, 72, -94, -2, + -58, -20, 96, -40, -31, 83, -20, -42, 69, -2, -53, 56, + 18, -63, 42, 37, -74, 29, 55, -85, 15, 75, -96, 1, + -56, -22, 100, -37, -32, 87, -18, -43, 73, 1, -54, 60, + 20, -65, 46, 39, -75, 33, 58, -86, 19, 77, -97, 5, + -54, -23, 104, -35, -34, 91, -16, -45, 77, 3, -55, 64, + 23, -66, 50, 41, -77, 37, 60, -87, 23, 80, -98, 9, + -51, -24, 108, -32, -35, 95, -13, -46, 81, 6, -57, 68, + 25, -68, 54, 44, -78, 41, 63, -89, 27, 82, -100, 13, + -49, -26, 113, -30, -37, 100, -10, -48, 86, 8, -58, 72, + 28, -69, 59, 47, -80, 45, 65, -90, 32, 85, -101, 18, + -46, -27, 117, -27, -38, 104, -8, -49, 90, 11, -59, 76, + 30, -70, 63, 49, -81, 49, 68, -92, 36, 87, -103, 22, + -44, -29, 121, -25, -39, 108, -6, -50, 94, 13, -61, 80, + 33, -72, 67, 51, -82, 53, 70, -93, 40, 89, -104, 26, + -119, 17, -6, -100, 7, -20, -81, -3, -33, -62, -14, -47, + -43, -25, -61, -24, -35, -74, -5, -46, -87, 14, -57, -101, + -117, 16, -2, -98, 5, -16, -79, -5, -29, -60, -15, -43, + -40, -26, -57, -22, -37, -70, -3, -47, -83, 17, -58, -97, + -114, 15, 1, -96, 4, -12, -76, -6, -25, -57, -16, -39, + -38, -27, -53, -19, -38, -66, 0, -49, -79, 19, -60, -93, + -112, 13, 5, -93, 3, -7, -73, -7, -21, -55, -18, -34, + -35, -29, -48, -17, -40, -62, 2, -50, -75, 22, -61, -89, + -109, 12, 9, -90, 1, -3, -71, -9, -17, -52, -19, -30, + -33, -30, -44, -14, -41, -58, 5, -51, -71, 24, -62, -85, + -107, 10, 13, -88, 0, 0, -69, -10, -13, -50, -21, -26, + -31, -32, -40, -12, -42, -54, 7, -53, -67, 26, -64, -81, + -104, 9, 17, -86, -1, 4, -66, -11, -9, -48, -22, -22, + -28, -33, -36, -9, -44, -50, 9, -54, -63, 29, -65, -77, + -102, 8, 22, -83, -2, 8, -64, -13, -4, -45, -24, -18, + -25, -35, -32, -7, -45, -45, 12, -56, -58, 31, -67, -72, + -99, 6, 26, -81, -3, 12, -61, -14, 0, -42, -25, -14, + -23, -36, -28, -4, -46, -41, 14, -57, -54, 34, -68, -68, + -97, 5, 30, -78, -5, 16, -59, -16, 3, -40, -26, -10, + -21, -37, -24, -2, -48, -37, 17, -58, -50, 36, -69, -64, + -95, 4, 34, -76, -6, 20, -56, -17, 7, -38, -28, -6, + -18, -39, -20, 0, -49, -33, 19, -60, -46, 39, -71, -60, + -92, 2, 38, -73, -7, 24, -54, -18, 11, -35, -29, -2, + -16, -40, -16, 3, -51, -29, 22, -61, -42, 41, -72, -56, + -90, 1, 42, -71, -9, 29, -51, -20, 15, -33, -30, 2, + -13, -41, -11, 6, -52, -25, 24, -63, -38, 44, -74, -52, + -87, 0, 46, -68, -10, 33, -49, -21, 19, -30, -32, 6, + -11, -43, -7, 8, -53, -21, 27, -64, -34, 46, -75, -48, + -85, -1, 50, -66, -12, 37, -47, -23, 23, -28, -33, 10, + -8, -44, -3, 10, -55, -17, 29, -65, -30, 49, -76, -44, + -82, -2, 54, -64, -13, 41, -44, -24, 27, -25, -35, 14, + -6, -45, 0, 13, -56, -13, 32, -67, -26, 51, -78, -40, + -80, -4, 59, -61, -15, 45, -42, -25, 32, -23, -36, 18, + -3, -47, 4, 15, -58, -8, 34, -68, -21, 54, -79, -35, + -77, -5, 63, -58, -16, 49, -39, -27, 36, -20, -37, 22, + -1, -48, 8, 18, -59, -4, 37, -70, -17, 56, -80, -31, + -75, -7, 67, -56, -17, 53, -37, -28, 40, -18, -39, 26, + 1, -50, 12, 20, -60, 0, 39, -71, -13, 58, -82, -27, + -72, -8, 71, -54, -19, 57, -34, -30, 44, -16, -40, 30, + 4, -51, 16, 23, -62, 3, 41, -72, -9, 61, -83, -23, + -70, -9, 75, -51, -20, 62, -32, -31, 48, -13, -42, 35, + 7, -53, 21, 25, -63, 7, 44, -74, -5, 63, -85, -19, + -67, -11, 79, -49, -21, 66, -29, -32, 52, -10, -43, 39, + 9, -54, 25, 28, -65, 11, 46, -75, -1, 66, -86, -15, + -65, -12, 83, -46, -23, 70, -27, -34, 56, -8, -44, 43, + 11, -55, 29, 30, -66, 15, 49, -76, 2, 68, -87, -11, + -63, -14, 87, -44, -24, 74, -24, -35, 60, -6, -46, 47, + 14, -57, 33, 32, -67, 19, 51, -78, 6, 71, -89, -7, + -60, -15, 91, -41, -25, 78, -22, -36, 64, -3, -47, 51, + 16, -58, 37, 35, -69, 23, 54, -79, 10, 73, -90, -3, + -58, -16, 96, -39, -27, 82, -19, -38, 69, -1, -49, 55, + 19, -59, 41, 38, -70, 28, 56, -81, 15, 76, -92, 1, + -55, -18, 100, -36, -28, 86, -17, -39, 73, 2, -50, 59, + 21, -61, 45, 40, -71, 32, 59, -82, 19, 78, -93, 5, + -53, -19, 104, -34, -30, 90, -15, -41, 77, 4, -51, 63, + 24, -62, 49, 42, -73, 36, 61, -83, 23, 80, -94, 9, + -50, -20, 108, -32, -31, 94, -12, -42, 81, 7, -53, 67, + 26, -64, 53, 45, -74, 40, 64, -85, 27, 83, -96, 13, + -48, -22, 112, -29, -33, 99, -10, -44, 85, 9, -54, 72, + 29, -65, 58, 47, -76, 44, 66, -86, 31, 86, -97, 17, + -45, -23, 116, -26, -34, 103, -7, -45, 89, 12, -55, 76, + 31, -66, 62, 50, -77, 48, 69, -88, 35, 88, -99, 21, + -43, -25, 120, -24, -35, 107, -5, -46, 93, 14, -57, 80, + 33, -68, 66, 52, -78, 52, 71, -89, 39, 90, -100, 25, + -118, 21, -7, -99, 11, -20, -80, 0, -34, -61, -10, -47, + -42, -21, -61, -23, -31, -75, -4, -42, -88, 15, -53, -102, + -116, 20, -3, -97, 9, -16, -78, -1, -30, -59, -11, -43, + -40, -22, -57, -21, -33, -71, -2, -43, -84, 17, -54, -98, + -113, 19, 0, -95, 8, -12, -75, -2, -26, -56, -12, -39, + -37, -23, -53, -18, -34, -67, 0, -45, -80, 20, -56, -94, + -111, 17, 5, -92, 7, -8, -73, -3, -22, -54, -14, -35, + -34, -25, -49, -16, -36, -62, 3, -46, -76, 23, -57, -89, + -108, 16, 9, -90, 5, -4, -70, -5, -18, -51, -15, -31, + -32, -26, -45, -13, -37, -58, 6, -47, -72, 25, -58, -85, + -106, 14, 13, -87, 4, 0, -68, -6, -14, -49, -17, -27, + -30, -28, -41, -11, -38, -54, 8, -49, -68, 27, -60, -81, + -104, 13, 17, -85, 2, 3, -65, -7, -10, -47, -18, -23, + -27, -29, -37, -8, -40, -50, 10, -50, -64, 30, -61, -77, + -101, 12, 21, -82, 1, 8, -63, -9, -5, -44, -20, -18, + -25, -31, -32, -6, -41, -46, 13, -52, -59, 32, -63, -73, + -98, 10, 25, -80, 0, 12, -60, -10, -1, -42, -21, -14, + -22, -32, -28, -3, -42, -42, 15, -53, -55, 35, -64, -69, + -96, 9, 29, -77, -1, 16, -58, -12, 2, -39, -22, -10, + -20, -33, -24, -1, -44, -38, 18, -54, -51, 37, -65, -65, + -94, 8, 33, -75, -2, 20, -56, -13, 6, -37, -24, -6, + -17, -35, -20, 1, -45, -34, 20, -56, -47, 40, -67, -61, + -91, 6, 37, -73, -3, 24, -53, -14, 10, -34, -25, -2, + -15, -36, -16, 4, -47, -30, 23, -57, -43, 42, -68, -57, + -89, 5, 42, -70, -5, 28, -50, -16, 14, -32, -26, 1, + -12, -37, -12, 6, -48, -25, 25, -59, -39, 45, -70, -52, + -86, 3, 46, -67, -6, 32, -48, -17, 18, -29, -28, 5, + -10, -39, -8, 9, -49, -21, 28, -60, -35, 47, -71, -48, + -84, 2, 50, -65, -8, 36, -46, -19, 22, -27, -29, 9, + -8, -40, -4, 11, -51, -17, 30, -61, -31, 49, -72, -44, + -81, 1, 54, -63, -9, 40, -43, -20, 26, -25, -31, 13, + -5, -41, 0, 14, -52, -13, 32, -63, -27, 52, -74, -40, + -79, 0, 58, -60, -11, 45, -41, -21, 31, -22, -32, 18, + -2, -43, 4, 16, -54, -9, 35, -64, -22, 54, -75, -36, + -76, -1, 62, -58, -12, 49, -38, -23, 35, -19, -33, 22, + 0, -44, 8, 19, -55, -5, 38, -66, -18, 57, -76, -32, + -74, -3, 66, -55, -13, 53, -36, -24, 39, -17, -35, 26, + 2, -46, 12, 21, -56, -1, 40, -67, -14, 59, -78, -28, + -72, -4, 70, -53, -15, 57, -33, -26, 43, -15, -36, 30, + 5, -47, 16, 24, -58, 2, 42, -68, -10, 62, -79, -24, + -69, -5, 75, -50, -16, 61, -31, -27, 47, -12, -38, 34, + 7, -49, 20, 26, -59, 7, 45, -70, -6, 64, -81, -19, + -66, -7, 79, -48, -17, 65, -28, -28, 51, -10, -39, 38, + 10, -50, 24, 29, -61, 11, 47, -71, -2, 67, -82, -15, + -64, -8, 83, -45, -19, 69, -26, -30, 55, -7, -40, 42, + 12, -51, 28, 31, -62, 15, 50, -72, 1, 69, -83, -11, + -62, -10, 87, -43, -20, 73, -24, -31, 59, -5, -42, 46, + 15, -53, 32, 33, -63, 19, 52, -74, 5, 72, -85, -7, + -59, -11, 91, -41, -21, 77, -21, -32, 63, -2, -43, 50, + 17, -54, 36, 36, -65, 23, 55, -75, 9, 74, -86, -3, + -57, -12, 95, -38, -23, 82, -18, -34, 68, 0, -45, 55, + 20, -55, 41, 38, -66, 27, 57, -77, 14, 77, -88, 0, + -54, -14, 99, -35, -24, 86, -16, -35, 72, 3, -46, 59, + 22, -57, 45, 41, -67, 31, 60, -78, 18, 79, -89, 4, + -52, -15, 103, -33, -26, 90, -14, -37, 76, 5, -47, 63, + 24, -58, 49, 43, -69, 35, 62, -79, 22, 81, -90, 8, + -49, -16, 107, -31, -27, 94, -11, -38, 80, 7, -49, 67, + 27, -60, 53, 46, -70, 39, 64, -81, 26, 84, -92, 12, + -47, -18, 112, -28, -29, 98, -9, -40, 84, 10, -50, 71, + 30, -61, 57, 48, -72, 44, 67, -82, 30, 86, -93, 17, + -44, -19, 116, -26, -30, 102, -6, -41, 88, 13, -51, 75, + 32, -62, 61, 51, -73, 48, 70, -84, 34, 89, -95, 21, + -42, -21, 120, -23, -31, 106, -4, -42, 92, 15, -53, 79, + 34, -64, 65, 53, -74, 52, 72, -85, 38, 91, -96, 25, + -117, 26, -8, -98, 15, -21, -79, 4, -35, -60, -5, -48, + -41, -16, -62, -22, -27, -75, -3, -37, -89, 16, -48, -103, + -115, 25, -4, -96, 14, -17, -77, 3, -31, -58, -7, -44, + -38, -18, -58, -20, -28, -71, -1, -39, -85, 18, -50, -99, + -112, 23, 0, -94, 13, -13, -74, 2, -27, -55, -8, -40, + -36, -19, -54, -17, -30, -67, 1, -40, -81, 21, -51, -95, + -110, 22, 4, -91, 11, -8, -72, 0, -22, -53, -10, -36, + -33, -20, -49, -15, -31, -63, 4, -42, -76, 24, -53, -90, + -107, 20, 8, -89, 10, -4, -69, 0, -18, -50, -11, -32, + -31, -22, -45, -12, -32, -59, 7, -43, -72, 26, -54, -86, + -105, 19, 12, -86, 8, 0, -67, -2, -14, -48, -12, -28, + -29, -23, -41, -10, -34, -55, 9, -44, -68, 28, -55, -82, + -103, 18, 16, -84, 7, 3, -64, -3, -10, -46, -14, -24, + -26, -24, -37, -7, -35, -51, 11, -46, -64, 31, -57, -78, + -100, 16, 20, -81, 5, 7, -62, -4, -6, -43, -15, -19, + -24, -26, -33, -5, -37, -46, 14, -47, -60, 33, -58, -74, + -97, 15, 24, -79, 4, 11, -59, -6, -2, -41, -16, -15, + -21, -27, -29, -2, -38, -42, 16, -49, -56, 36, -59, -70, + -95, 13, 28, -76, 3, 15, -57, -7, 1, -38, -18, -11, + -19, -29, -25, 0, -39, -38, 19, -50, -52, 38, -61, -66, + -93, 12, 32, -74, 1, 19, -55, -9, 5, -36, -19, -7, + -16, -30, -21, 2, -41, -34, 21, -51, -48, 41, -62, -62, + -90, 11, 36, -71, 0, 23, -52, -10, 9, -33, -20, -3, + -14, -31, -17, 5, -42, -30, 24, -53, -44, 43, -64, -58, + -88, 9, 41, -69, 0, 28, -49, -11, 14, -31, -22, 0, + -11, -33, -12, 8, -44, -26, 26, -54, -39, 46, -65, -53, + -85, 8, 45, -66, -2, 32, -47, -13, 18, -28, -23, 4, + -9, -34, -8, 10, -45, -22, 29, -55, -35, 48, -66, -49, + -83, 6, 49, -64, -3, 36, -45, -14, 22, -26, -25, 8, + -6, -36, -4, 12, -46, -18, 31, -57, -31, 50, -68, -45, + -80, 5, 53, -62, -5, 40, -42, -15, 26, -23, -26, 12, + -4, -37, 0, 15, -48, -14, 33, -58, -27, 53, -69, -41, + -78, 4, 57, -59, -6, 44, -40, -17, 30, -21, -28, 17, + -1, -38, 3, 17, -49, -9, 36, -60, -23, 56, -71, -37, + -75, 2, 61, -57, -7, 48, -37, -18, 34, -18, -29, 21, + 1, -40, 7, 20, -50, -5, 39, -61, -19, 58, -72, -33, + -73, 1, 65, -54, -9, 52, -35, -20, 38, -16, -30, 25, + 3, -41, 11, 22, -52, -1, 41, -62, -15, 60, -73, -29, + -71, 0, 69, -52, -10, 56, -32, -21, 42, -14, -32, 29, + 6, -43, 15, 25, -53, 2, 43, -64, -11, 63, -75, -25, + -68, -1, 74, -49, -12, 61, -30, -23, 47, -11, -33, 33, + 8, -44, 20, 27, -55, 6, 46, -65, -6, 65, -76, -20, + -65, -2, 78, -47, -13, 65, -27, -24, 51, -9, -34, 37, + 11, -45, 24, 30, -56, 10, 48, -67, -2, 68, -78, -16, + -63, -4, 82, -44, -14, 69, -25, -25, 55, -6, -36, 41, + 13, -47, 28, 32, -57, 14, 51, -68, 1, 70, -79, -12, + -61, -5, 86, -42, -16, 73, -23, -27, 59, -4, -37, 45, + 16, -48, 32, 34, -59, 18, 53, -69, 5, 73, -80, -8, + -58, -6, 90, -40, -17, 77, -20, -28, 63, -1, -39, 49, + 18, -49, 36, 37, -60, 22, 56, -71, 9, 75, -82, -4, + -56, -8, 94, -37, -19, 81, -17, -29, 67, 1, -40, 54, + 21, -51, 40, 39, -62, 27, 58, -72, 13, 78, -83, 0, + -53, -9, 98, -34, -20, 85, -15, -31, 71, 4, -41, 58, + 23, -52, 44, 42, -63, 31, 61, -74, 17, 80, -84, 3, + -51, -11, 102, -32, -21, 89, -13, -32, 75, 6, -43, 62, + 25, -54, 48, 44, -64, 35, 63, -75, 21, 82, -86, 7, + -48, -12, 106, -30, -23, 93, -10, -33, 79, 9, -44, 66, + 28, -55, 52, 47, -66, 39, 65, -76, 25, 85, -87, 11, + -46, -13, 111, -27, -24, 98, -8, -35, 84, 11, -46, 70, + 31, -57, 57, 49, -67, 43, 68, -78, 30, 88, -89, 16, + -43, -15, 115, -25, -25, 102, -5, -36, 88, 14, -47, 74, + 33, -58, 61, 52, -68, 47, 71, -79, 34, 90, -90, 20, + -41, -16, 119, -22, -27, 106, -3, -38, 92, 16, -48, 78, + 35, -59, 65, 54, -70, 51, 73, -80, 38, 92, -91, 24, + -116, 30, -8, -97, 19, -22, -78, 8, -35, -59, -1, -49, + -40, -12, -63, -21, -23, -76, -2, -33, -89, 17, -44, -103, + -114, 29, -4, -95, 18, -18, -76, 7, -31, -57, -3, -45, + -38, -14, -59, -19, -24, -72, 0, -35, -85, 19, -46, -99, + -111, 27, 0, -93, 17, -14, -73, 6, -27, -55, -4, -41, + -35, -15, -55, -16, -26, -68, 2, -36, -81, 22, -47, -95, + -109, 26, 3, -90, 15, -9, -71, 4, -23, -52, -6, -36, + -32, -16, -50, -14, -27, -64, 5, -38, -77, 24, -49, -91, + -106, 24, 7, -88, 14, -5, -68, 3, -19, -49, -7, -32, + -30, -18, -46, -11, -28, -60, 7, -39, -73, 27, -50, -87, + -104, 23, 11, -85, 12, -1, -66, 1, -15, -47, -8, -28, + -28, -19, -42, -9, -30, -56, 10, -40, -69, 29, -51, -83, + -102, 22, 15, -83, 11, 2, -63, 0, -11, -45, -10, -24, + -25, -20, -38, -7, -31, -52, 12, -42, -65, 32, -53, -79, + -99, 20, 20, -80, 9, 6, -61, 0, -6, -42, -11, -20, + -23, -22, -34, -4, -33, -47, 15, -43, -60, 34, -54, -74, + -97, 19, 24, -78, 8, 10, -58, -2, -2, -40, -12, -16, + -20, -23, -30, -1, -34, -43, 17, -45, -56, 37, -55, -70, + -94, 17, 28, -75, 7, 14, -56, -3, 1, -37, -14, -12, + -18, -25, -26, 1, -35, -39, 20, -46, -52, 39, -57, -66, + -92, 16, 32, -73, 5, 18, -54, -5, 5, -35, -15, -8, + -15, -26, -22, 3, -37, -35, 22, -47, -48, 41, -58, -62, + -89, 15, 36, -71, 4, 22, -51, -6, 9, -32, -16, -4, + -13, -27, -18, 6, -38, -31, 25, -49, -44, 44, -60, -58, + -87, 13, 40, -68, 3, 27, -49, -7, 13, -30, -18, 0, + -10, -29, -13, 8, -40, -27, 27, -50, -40, 47, -61, -54, + -84, 12, 44, -66, 1, 31, -46, -9, 17, -27, -19, 4, + -8, -30, -9, 11, -41, -23, 30, -51, -36, 49, -62, -50, + -82, 10, 48, -63, 0, 35, -44, -10, 21, -25, -21, 8, + -6, -32, -5, 13, -42, -19, 32, -53, -32, 51, -64, -46, + -80, 9, 52, -61, -1, 39, -41, -11, 25, -23, -22, 12, + -3, -33, -1, 16, -44, -15, 34, -54, -28, 54, -65, -42, + -77, 8, 57, -58, -2, 43, -39, -13, 30, -20, -24, 16, + -1, -34, 2, 18, -45, -10, 37, -56, -23, 56, -67, -37, + -74, 6, 61, -56, -3, 47, -36, -14, 34, -17, -25, 20, + 2, -36, 6, 21, -46, -6, 39, -57, -19, 59, -68, -33, + -72, 5, 65, -53, -5, 51, -34, -16, 38, -15, -26, 24, + 4, -37, 10, 23, -48, -2, 42, -58, -15, 61, -69, -29, + -70, 4, 69, -51, -6, 55, -31, -17, 42, -13, -28, 28, + 7, -39, 14, 25, -49, 1, 44, -60, -11, 64, -71, -25, + -67, 2, 73, -48, -8, 60, -29, -19, 46, -10, -29, 33, + 9, -40, 19, 28, -51, 5, 47, -61, -7, 66, -72, -21, + -65, 1, 77, -46, -9, 64, -26, -20, 50, -8, -30, 37, + 12, -41, 23, 31, -52, 9, 49, -63, -3, 69, -74, -17, + -62, 0, 81, -43, -10, 68, -24, -21, 54, -5, -32, 41, + 14, -43, 27, 33, -53, 13, 52, -64, 0, 71, -75, -13, + -60, -1, 85, -41, -12, 72, -22, -23, 58, -3, -33, 45, + 17, -44, 31, 35, -55, 17, 54, -65, 4, 73, -76, -9, + -57, -2, 89, -39, -13, 76, -19, -24, 62, 0, -35, 49, + 19, -45, 35, 38, -56, 21, 57, -67, 8, 76, -78, -5, + -55, -4, 94, -36, -15, 80, -17, -25, 67, 2, -36, 53, + 22, -47, 39, 40, -58, 26, 59, -68, 13, 79, -79, 0, + -52, -5, 98, -34, -16, 84, -14, -27, 71, 5, -37, 57, + 24, -48, 43, 43, -59, 30, 62, -70, 17, 81, -80, 3, + -50, -7, 102, -31, -17, 88, -12, -28, 75, 7, -39, 61, + 26, -50, 47, 45, -60, 34, 64, -71, 21, 83, -82, 7, + -48, -8, 106, -29, -19, 92, -9, -29, 79, 9, -40, 65, + 29, -51, 51, 48, -62, 38, 66, -72, 25, 86, -83, 11, + -45, -9, 110, -26, -20, 97, -7, -31, 83, 12, -42, 70, + 31, -53, 56, 50, -63, 42, 69, -74, 29, 88, -85, 15, + -42, -11, 114, -24, -21, 101, -4, -32, 87, 15, -43, 74, + 34, -54, 60, 53, -64, 46, 71, -75, 33, 91, -86, 19, + -40, -12, 118, -21, -23, 105, -2, -34, 91, 17, -44, 78, + 36, -55, 64, 55, -66, 50, 74, -76, 37, 93, -87, 23, + -115, 34, -9, -97, 23, -22, -77, 12, -36, -58, 2, -49, + -39, -8, -63, -20, -19, -77, -1, -29, -90, 18, -40, -104, + -113, 33, -5, -94, 22, -18, -75, 11, -32, -56, 0, -45, + -37, -10, -59, -18, -20, -73, 1, -31, -86, 20, -42, -100, + -111, 31, -1, -92, 21, -14, -72, 10, -28, -54, 0, -41, + -34, -11, -55, -15, -22, -69, 3, -32, -82, 23, -43, -96, + -108, 30, 3, -89, 19, -10, -70, 8, -24, -51, -2, -37, + -32, -12, -51, -13, -23, -64, 6, -34, -78, 25, -45, -91, + -106, 28, 7, -87, 18, -6, -67, 7, -20, -49, -3, -33, + -29, -14, -47, -10, -24, -60, 8, -35, -74, 28, -46, -87, + -103, 27, 11, -84, 16, -2, -65, 5, -16, -46, -4, -29, + -27, -15, -43, -8, -26, -56, 11, -36, -70, 30, -47, -83, + -101, 26, 15, -82, 15, 1, -63, 4, -12, -44, -6, -25, + -24, -16, -39, -6, -27, -52, 13, -38, -66, 33, -49, -79, + -98, 24, 19, -79, 13, 6, -60, 3, -7, -41, -7, -20, + -22, -18, -34, -3, -29, -48, 16, -39, -61, 35, -50, -75, + -96, 23, 23, -77, 12, 10, -57, 1, -3, -39, -8, -16, + -19, -19, -30, -1, -30, -44, 18, -41, -57, 38, -51, -71, + -93, 21, 27, -74, 11, 14, -55, 0, 0, -36, -10, -12, + -17, -21, -26, 2, -31, -40, 21, -42, -53, 40, -53, -67, + -91, 20, 31, -72, 9, 18, -53, -1, 4, -34, -11, -8, + -15, -22, -22, 4, -33, -36, 23, -43, -49, 42, -54, -63, + -88, 19, 35, -70, 8, 22, -50, -2, 8, -32, -12, -4, + -12, -23, -18, 7, -34, -32, 25, -45, -45, 45, -56, -59, + -86, 17, 40, -67, 7, 26, -48, -3, 12, -29, -14, 0, + -9, -25, -14, 9, -36, -27, 28, -46, -41, 47, -57, -54, + -83, 16, 44, -65, 5, 30, -45, -5, 16, -26, -15, 3, + -7, -26, -10, 12, -37, -23, 31, -47, -37, 50, -58, -50, + -81, 14, 48, -62, 4, 34, -43, -6, 20, -24, -17, 7, + -5, -28, -6, 14, -38, -19, 33, -49, -33, 52, -60, -46, + -79, 13, 52, -60, 2, 38, -40, -7, 24, -22, -18, 11, + -2, -29, -2, 17, -40, -15, 35, -50, -29, 55, -61, -42, + -76, 12, 56, -57, 1, 43, -38, -9, 29, -19, -20, 16, + 0, -30, 2, 19, -41, -11, 38, -52, -24, 57, -63, -38, + -74, 10, 60, -55, 0, 47, -35, -10, 33, -17, -21, 20, + 3, -32, 6, 22, -42, -7, 40, -53, -20, 60, -64, -34, + -71, 9, 64, -52, -1, 51, -33, -12, 37, -14, -22, 24, + 5, -33, 10, 24, -44, -3, 43, -54, -16, 62, -65, -30, + -69, 8, 68, -50, -2, 55, -31, -13, 41, -12, -24, 28, + 8, -35, 14, 26, -45, 0, 45, -56, -12, 65, -67, -26, + -66, 6, 73, -47, -4, 59, -28, -15, 45, -9, -25, 32, + 10, -36, 18, 29, -47, 5, 48, -57, -8, 67, -68, -21, + -64, 5, 77, -45, -5, 63, -25, -16, 49, -7, -26, 36, + 13, -37, 22, 31, -48, 9, 50, -59, -4, 70, -70, -17, + -61, 3, 81, -42, -6, 67, -23, -17, 53, -4, -28, 40, + 15, -39, 26, 34, -49, 13, 53, -60, 0, 72, -71, -13, + -59, 2, 85, -40, -8, 71, -21, -19, 57, -2, -29, 44, + 17, -40, 30, 36, -51, 17, 55, -61, 3, 74, -72, -9, + -56, 1, 89, -38, -9, 75, -18, -20, 61, 0, -31, 48, + 20, -41, 34, 39, -52, 21, 57, -63, 7, 77, -74, -5, + -54, 0, 93, -35, -11, 80, -16, -21, 66, 3, -32, 53, + 23, -43, 39, 41, -54, 25, 60, -64, 12, 79, -75, -1, + -51, -1, 97, -33, -12, 84, -13, -23, 70, 6, -33, 57, + 25, -44, 43, 44, -55, 29, 62, -66, 16, 82, -76, 2, + -49, -3, 101, -30, -13, 88, -11, -24, 74, 8, -35, 61, + 27, -46, 47, 46, -56, 33, 65, -67, 20, 84, -78, 6, + -47, -4, 105, -28, -15, 92, -8, -25, 78, 10, -36, 65, + 30, -47, 51, 48, -58, 37, 67, -68, 24, 87, -79, 10, + -44, -5, 110, -25, -16, 96, -6, -27, 82, 13, -38, 69, + 32, -49, 55, 51, -59, 42, 70, -70, 28, 89, -81, 15, + -42, -7, 114, -23, -17, 100, -3, -28, 86, 15, -39, 73, + 35, -50, 59, 54, -60, 46, 72, -71, 32, 92, -82, 19, + -39, -8, 118, -20, -19, 104, -1, -30, 90, 18, -40, 77, + 37, -51, 63, 56, -62, 50, 75, -72, 36, 94, -83, 23, + -114, 38, -10, -96, 27, -23, -76, 16, -37, -58, 6, -50, + -38, -4, -64, -19, -15, -77, -1, -25, -91, 19, -36, -105, + -112, 37, -6, -93, 26, -19, -74, 15, -33, -55, 4, -46, + -36, -6, -60, -17, -16, -73, 2, -27, -87, 21, -38, -101, + -110, 35, -2, -91, 25, -15, -72, 14, -29, -53, 3, -42, + -33, -7, -56, -15, -18, -69, 4, -28, -83, 24, -39, -97, + -107, 34, 2, -88, 23, -10, -69, 12, -24, -50, 1, -38, + -31, -8, -51, -12, -19, -65, 7, -30, -78, 26, -41, -92, + -105, 32, 6, -86, 22, -6, -66, 11, -20, -48, 0, -34, + -28, -10, -47, -9, -20, -61, 9, -31, -74, 29, -42, -88, + -102, 31, 10, -83, 20, -2, -64, 9, -16, -45, 0, -30, + -26, -11, -43, -7, -22, -57, 12, -32, -70, 31, -43, -84, + -100, 30, 14, -81, 19, 1, -62, 8, -12, -43, -2, -26, + -23, -12, -39, -5, -23, -53, 14, -34, -66, 33, -45, -80, + -97, 28, 18, -78, 17, 5, -59, 7, -8, -40, -3, -21, + -21, -14, -35, -2, -25, -48, 17, -35, -62, 36, -46, -76, + -95, 27, 22, -76, 16, 9, -57, 5, -4, -38, -4, -17, + -18, -15, -31, 0, -26, -44, 19, -37, -58, 39, -47, -72, + -92, 25, 26, -74, 15, 13, -54, 4, 0, -35, -6, -13, + -16, -17, -27, 3, -27, -40, 22, -38, -54, 41, -49, -68, + -90, 24, 30, -71, 13, 17, -52, 2, 3, -33, -7, -9, + -14, -18, -23, 5, -29, -36, 24, -39, -50, 43, -50, -64, + -88, 23, 34, -69, 12, 21, -49, 1, 7, -31, -8, -5, + -11, -19, -19, 8, -30, -32, 26, -41, -46, 46, -52, -60, + -85, 21, 39, -66, 11, 26, -47, 0, 12, -28, -10, -1, + -9, -21, -14, 10, -32, -28, 29, -42, -41, 48, -53, -55, + -82, 20, 43, -64, 9, 30, -44, -1, 16, -26, -11, 2, + -6, -22, -10, 13, -33, -24, 31, -43, -37, 51, -54, -51, + -80, 18, 47, -61, 8, 34, -42, -2, 20, -23, -13, 6, + -4, -24, -6, 15, -34, -20, 34, -45, -33, 53, -56, -47, + -78, 17, 51, -59, 6, 38, -40, -3, 24, -21, -14, 10, + -1, -25, -2, 17, -36, -16, 36, -46, -29, 56, -57, -43, + -75, 16, 55, -56, 5, 42, -37, -5, 28, -18, -16, 15, + 1, -26, 1, 20, -37, -11, 39, -48, -25, 58, -59, -39, + -73, 14, 59, -54, 4, 46, -34, -6, 32, -16, -17, 19, + 4, -28, 5, 22, -38, -7, 41, -49, -21, 61, -60, -35, + -70, 13, 63, -51, 2, 50, -32, -8, 36, -13, -18, 23, + 6, -29, 9, 25, -40, -3, 44, -50, -17, 63, -61, -31, + -68, 12, 67, -49, 1, 54, -30, -9, 40, -11, -20, 27, + 8, -31, 13, 27, -41, 0, 46, -52, -13, 65, -63, -27, + -65, 10, 72, -46, 0, 59, -27, -11, 45, -8, -21, 31, + 11, -32, 18, 30, -43, 4, 49, -53, -8, 68, -64, -22, + -63, 9, 76, -44, -1, 63, -25, -12, 49, -6, -22, 35, + 14, -33, 22, 32, -44, 8, 51, -55, -4, 71, -66, -18, + -60, 7, 80, -42, -2, 67, -22, -13, 53, -3, -24, 39, + 16, -35, 26, 35, -45, 12, 54, -56, 0, 73, -67, -14, + -58, 6, 84, -39, -4, 71, -20, -15, 57, -1, -25, 43, + 18, -36, 30, 37, -47, 16, 56, -57, 3, 75, -68, -10, + -56, 5, 88, -37, -5, 75, -17, -16, 61, 1, -27, 47, + 21, -37, 34, 40, -48, 20, 58, -59, 7, 78, -70, -6, + -53, 3, 92, -34, -7, 79, -15, -17, 65, 4, -28, 52, + 23, -39, 38, 42, -50, 25, 61, -60, 11, 80, -71, -2, + -50, 2, 96, -32, -8, 83, -12, -19, 69, 6, -29, 56, + 26, -40, 42, 45, -51, 29, 63, -62, 15, 83, -72, 1, + -48, 0, 100, -29, -9, 87, -10, -20, 73, 9, -31, 60, + 28, -42, 46, 47, -52, 33, 66, -63, 19, 85, -74, 5, + -46, 0, 104, -27, -11, 91, -8, -21, 77, 11, -32, 64, + 31, -43, 50, 49, -54, 37, 68, -64, 23, 88, -75, 9, + -43, -1, 109, -24, -12, 96, -5, -23, 82, 14, -34, 68, + 33, -45, 55, 52, -55, 41, 71, -66, 28, 90, -77, 14, + -41, -3, 113, -22, -13, 100, -2, -24, 86, 16, -35, 72, + 36, -46, 59, 54, -56, 45, 73, -67, 32, 93, -78, 18, + -38, -4, 117, -19, -15, 104, 0, -26, 90, 19, -36, 76, + 38, -47, 63, 57, -58, 49, 76, -68, 36, 95, -79, 22, + -114, 42, -10, -95, 31, -24, -75, 20, -37, -57, 10, -51, + -37, 0, -65, -18, -11, -78, 0, -21, -91, 20, -32, -105, + -111, 41, -6, -92, 30, -20, -73, 19, -33, -54, 8, -47, + -35, -2, -61, -16, -12, -74, 3, -23, -87, 22, -34, -101, + -109, 39, -2, -90, 29, -16, -71, 18, -29, -52, 7, -43, + -32, -3, -57, -14, -14, -70, 5, -24, -83, 24, -35, -97, + -106, 38, 1, -87, 27, -11, -68, 16, -25, -49, 5, -38, + -30, -4, -52, -11, -15, -65, 8, -26, -79, 27, -37, -93, + -104, 36, 5, -85, 26, -7, -66, 15, -21, -47, 4, -34, + -27, -6, -48, -9, -16, -61, 10, -27, -75, 30, -38, -89, + -101, 35, 9, -83, 24, -3, -63, 13, -17, -44, 3, -30, + -25, -7, -44, -6, -18, -57, 13, -28, -71, 32, -39, -85, + -99, 34, 13, -80, 23, 0, -61, 12, -13, -42, 1, -26, + -23, -8, -40, -4, -19, -53, 15, -30, -67, 34, -41, -81, + -96, 32, 18, -77, 21, 4, -58, 11, -8, -39, 0, -22, + -20, -10, -36, -1, -21, -49, 18, -31, -62, 37, -42, -76, + -94, 31, 22, -75, 20, 8, -56, 9, -4, -37, 0, -18, + -17, -11, -32, 1, -22, -45, 20, -33, -58, 39, -43, -72, + -91, 29, 26, -73, 19, 12, -53, 8, 0, -34, -2, -14, + -15, -13, -28, 4, -23, -41, 22, -34, -54, 42, -45, -68, + -89, 28, 30, -70, 17, 16, -51, 6, 3, -32, -3, -10, + -13, -14, -24, 6, -25, -37, 25, -35, -50, 44, -46, -64, + -87, 27, 34, -68, 16, 20, -48, 5, 7, -30, -4, -6, + -10, -15, -20, 8, -26, -33, 27, -37, -46, 47, -48, -60, + -84, 25, 38, -65, 15, 25, -46, 4, 11, -27, -6, -1, + -8, -17, -15, 11, -28, -28, 30, -38, -42, 49, -49, -56, + -82, 24, 42, -63, 13, 29, -43, 2, 15, -25, -7, 2, + -5, -18, -11, 14, -29, -24, 32, -39, -38, 52, -50, -52, + -79, 22, 46, -60, 12, 33, -41, 1, 19, -22, -9, 6, + -3, -20, -7, 16, -30, -20, 35, -41, -34, 54, -52, -48, + -77, 21, 50, -58, 10, 37, -39, 0, 23, -20, -10, 10, + 0, -21, -3, 18, -32, -16, 37, -42, -30, 56, -53, -44, + -74, 20, 55, -55, 9, 41, -36, -1, 28, -17, -12, 14, + 2, -22, 0, 21, -33, -12, 40, -44, -25, 59, -55, -39, + -72, 18, 59, -53, 8, 45, -34, -2, 32, -15, -13, 18, + 5, -24, 4, 23, -34, -8, 42, -45, -21, 62, -56, -35, + -69, 17, 63, -51, 6, 49, -31, -4, 36, -12, -14, 22, + 7, -25, 8, 26, -36, -4, 45, -46, -17, 64, -57, -31, + -67, 16, 67, -48, 5, 53, -29, -5, 40, -10, -16, 26, + 9, -27, 12, 28, -37, 0, 47, -48, -13, 66, -59, -27, + -64, 14, 71, -45, 3, 58, -26, -7, 44, -7, -17, 31, + 12, -28, 17, 31, -39, 4, 50, -49, -9, 69, -60, -23, + -62, 13, 75, -43, 2, 62, -24, -8, 48, -5, -18, 35, + 14, -29, 21, 33, -40, 8, 52, -51, -5, 71, -62, -19, + -59, 11, 79, -41, 1, 66, -21, -9, 52, -2, -20, 39, + 17, -31, 25, 36, -41, 12, 54, -52, -1, 74, -63, -15, + -57, 10, 83, -38, 0, 70, -19, -11, 56, 0, -21, 43, + 19, -32, 29, 38, -43, 16, 57, -53, 2, 76, -64, -11, + -55, 9, 87, -36, -1, 74, -16, -12, 60, 2, -23, 47, + 22, -33, 33, 40, -44, 20, 59, -55, 6, 79, -66, -7, + -52, 7, 92, -33, -3, 78, -14, -13, 65, 5, -24, 51, + 24, -35, 37, 43, -46, 24, 62, -56, 11, 81, -67, -2, + -50, 6, 96, -31, -4, 82, -11, -15, 69, 7, -25, 55, + 27, -36, 41, 46, -47, 28, 64, -58, 15, 84, -68, 1, + -47, 4, 100, -28, -5, 86, -9, -16, 73, 10, -27, 59, + 29, -38, 45, 48, -48, 32, 67, -59, 19, 86, -70, 5, + -45, 3, 104, -26, -7, 90, -7, -17, 77, 12, -28, 63, + 32, -39, 49, 50, -50, 36, 69, -60, 23, 88, -71, 9, + -42, 2, 108, -23, -8, 95, -4, -19, 81, 15, -30, 68, + 34, -41, 54, 53, -51, 41, 72, -62, 27, 91, -73, 13, + -40, 0, 112, -21, -9, 99, -2, -20, 85, 17, -31, 72, + 37, -42, 58, 55, -52, 45, 74, -63, 31, 94, -74, 17, + -37, 0, 116, -19, -11, 103, 1, -22, 89, 20, -32, 76, + 39, -43, 62, 58, -54, 49, 77, -64, 35, 96, -75, 21, + -113, 46, -11, -94, 36, -24, -74, 25, -38, -56, 14, -52, + -36, 3, -65, -17, -6, -79, 1, -17, -92, 21, -28, -106, + -110, 45, -7, -91, 34, -20, -72, 23, -34, -53, 13, -48, + -34, 2, -61, -15, -8, -75, 4, -18, -88, 23, -29, -102, + -108, 44, -3, -89, 33, -16, -70, 22, -30, -51, 12, -44, + -31, 1, -57, -13, -9, -71, 6, -20, -84, 26, -31, -98, + -105, 42, 1, -86, 32, -12, -67, 21, -26, -48, 10, -39, + -29, 0, -53, -10, -11, -66, 9, -21, -80, 28, -32, -93, + -103, 41, 5, -84, 30, -8, -64, 19, -22, -46, 9, -35, + -26, -1, -49, -8, -12, -62, 11, -22, -76, 31, -33, -89, + -100, 39, 9, -81, 29, -4, -62, 18, -18, -43, 7, -31, + -24, -3, -45, -5, -13, -58, 14, -24, -72, 33, -35, -85, + -98, 38, 13, -79, 27, 0, -60, 17, -14, -41, 6, -27, + -22, -4, -41, -3, -15, -54, 16, -25, -68, 35, -36, -81, + -95, 37, 17, -76, 26, 4, -57, 15, -9, -38, 4, -23, + -19, -6, -36, 0, -16, -50, 19, -27, -63, 38, -38, -77, + -93, 35, 21, -74, 25, 8, -55, 14, -5, -36, 3, -19, + -16, -7, -32, 2, -17, -46, 21, -28, -59, 40, -39, -73, + -90, 34, 25, -72, 23, 12, -52, 12, -1, -33, 2, -15, + -14, -8, -28, 5, -19, -42, 23, -29, -55, 43, -40, -69, + -88, 33, 29, -69, 22, 16, -50, 11, 2, -31, 0, -11, + -12, -10, -24, 7, -20, -38, 26, -31, -51, 45, -42, -65, + -86, 31, 33, -67, 21, 20, -47, 10, 6, -29, 0, -7, + -9, -11, -20, 9, -22, -34, 28, -32, -47, 48, -43, -61, + -83, 30, 38, -64, 19, 24, -45, 8, 10, -26, -1, -2, + -7, -12, -16, 12, -23, -29, 31, -34, -43, 50, -45, -56, + -81, 28, 42, -62, 18, 28, -42, 7, 14, -24, -3, 1, + -4, -14, -12, 15, -24, -25, 33, -35, -39, 53, -46, -52, + -78, 27, 46, -59, 16, 32, -40, 5, 18, -21, -4, 5, + -2, -15, -8, 17, -26, -21, 36, -36, -35, 55, -47, -48, + -76, 26, 50, -57, 15, 36, -38, 4, 22, -19, -6, 9, + 1, -16, -4, 19, -27, -17, 38, -38, -31, 58, -49, -44, + -73, 24, 54, -54, 13, 41, -35, 3, 27, -16, -7, 13, + 3, -18, 0, 22, -29, -13, 41, -39, -26, 60, -50, -40, + -71, 23, 58, -52, 12, 45, -33, 1, 31, -14, -8, 17, + 6, -19, 4, 24, -30, -9, 43, -41, -22, 63, -51, -36, + -68, 21, 62, -49, 11, 49, -30, 0, 35, -11, -10, 21, + 8, -21, 8, 27, -31, -5, 46, -42, -18, 65, -53, -32, + -66, 20, 66, -47, 9, 53, -28, -1, 39, -9, -11, 25, + 10, -22, 12, 29, -33, -1, 48, -43, -14, 67, -54, -28, + -63, 19, 71, -44, 8, 57, -25, -2, 43, -6, -13, 30, + 13, -24, 16, 32, -34, 3, 51, -45, -10, 70, -56, -23, + -61, 17, 75, -42, 7, 61, -23, -3, 47, -4, -14, 34, + 16, -25, 20, 34, -36, 7, 53, -46, -6, 72, -57, -19, + -58, 16, 79, -40, 5, 65, -20, -5, 51, -1, -15, 38, + 18, -26, 24, 37, -37, 11, 55, -47, -2, 75, -58, -15, + -56, 14, 83, -37, 4, 69, -18, -6, 55, 1, -17, 42, + 20, -28, 28, 39, -38, 15, 58, -49, 1, 77, -60, -11, + -54, 13, 87, -35, 3, 73, -15, -7, 59, 3, -18, 46, + 23, -29, 32, 41, -40, 19, 60, -50, 5, 80, -61, -7, + -51, 12, 91, -32, 1, 78, -13, -9, 64, 6, -20, 50, + 25, -30, 37, 44, -41, 23, 63, -52, 10, 82, -63, -3, + -49, 10, 95, -30, 0, 82, -10, -10, 68, 8, -21, 54, + 28, -32, 41, 47, -42, 27, 65, -53, 14, 85, -64, 0, + -46, 9, 99, -27, -1, 86, -8, -12, 72, 11, -22, 58, + 30, -33, 45, 49, -44, 31, 68, -54, 18, 87, -65, 4, + -44, 8, 103, -25, -2, 90, -6, -13, 76, 13, -24, 62, + 33, -35, 49, 51, -45, 35, 70, -56, 22, 90, -67, 8, + -41, 6, 108, -22, -4, 94, -3, -15, 80, 16, -25, 67, + 35, -36, 53, 54, -47, 40, 73, -57, 26, 92, -68, 13, + -39, 5, 112, -20, -5, 98, -1, -16, 84, 18, -26, 71, + 38, -37, 57, 56, -48, 44, 75, -59, 30, 95, -70, 17, + -36, 3, 116, -17, -6, 102, 2, -17, 88, 21, -28, 75, + 40, -39, 61, 59, -49, 48, 78, -60, 34, 97, -71, 21, + -112, 50, -12, -93, 40, -25, -73, 29, -39, -55, 18, -52, + -35, 7, -66, -17, -2, -79, 2, -13, -93, 22, -24, -107, + -109, 49, -8, -90, 38, -21, -71, 27, -35, -52, 17, -48, + -33, 6, -62, -14, -4, -75, 5, -14, -89, 24, -25, -103, + -107, 48, -4, -88, 37, -17, -69, 26, -31, -50, 16, -44, + -31, 5, -58, -12, -5, -71, 7, -16, -85, 26, -27, -99, + -104, 46, 0, -85, 36, -12, -66, 25, -26, -47, 14, -40, + -28, 3, -53, -9, -7, -67, 10, -17, -80, 29, -28, -94, + -102, 45, 4, -83, 34, -8, -64, 23, -22, -45, 13, -36, + -25, 2, -49, -7, -8, -63, 12, -18, -76, 32, -29, -90, + -99, 43, 8, -81, 33, -4, -61, 22, -18, -42, 11, -32, + -23, 0, -45, -4, -9, -59, 15, -20, -72, 34, -31, -86, + -97, 42, 12, -78, 31, 0, -59, 21, -14, -40, 10, -28, + -21, 0, -41, -2, -11, -55, 17, -21, -68, 36, -32, -82, + -94, 41, 16, -75, 30, 3, -56, 19, -10, -37, 8, -23, + -18, -2, -37, 1, -12, -50, 20, -23, -64, 39, -34, -78, + -92, 39, 20, -73, 29, 7, -54, 18, -6, -35, 7, -19, + -16, -3, -33, 3, -13, -46, 22, -24, -60, 41, -35, -74, + -89, 38, 24, -71, 27, 11, -51, 16, -2, -33, 6, -15, + -13, -4, -29, 6, -15, -42, 24, -25, -56, 44, -36, -70, + -87, 37, 28, -68, 26, 15, -49, 15, 1, -30, 4, -11, + -11, -6, -25, 8, -16, -38, 27, -27, -52, 46, -38, -66, + -85, 35, 32, -66, 25, 19, -47, 14, 5, -28, 3, -7, + -8, -7, -21, 10, -18, -34, 29, -28, -48, 49, -39, -62, + -82, 34, 37, -63, 23, 24, -44, 12, 10, -25, 2, -3, + -6, -8, -16, 13, -19, -30, 32, -30, -43, 51, -41, -57, + -80, 32, 41, -61, 22, 28, -41, 11, 14, -23, 0, 0, + -3, -10, -12, 15, -20, -26, 34, -31, -39, 54, -42, -53, + -77, 31, 45, -58, 20, 32, -39, 9, 18, -20, 0, 4, + -1, -11, -8, 18, -22, -22, 37, -32, -35, 56, -43, -49, + -75, 30, 49, -56, 19, 36, -37, 8, 22, -18, -2, 8, + 1, -12, -4, 20, -23, -18, 39, -34, -31, 58, -45, -45, + -72, 28, 53, -53, 17, 40, -34, 7, 26, -15, -3, 13, + 4, -14, 0, 23, -25, -13, 42, -35, -27, 61, -46, -41, + -70, 27, 57, -51, 16, 44, -32, 5, 30, -13, -4, 17, + 7, -15, 3, 25, -26, -9, 44, -37, -23, 64, -47, -37, + -67, 25, 61, -49, 15, 48, -29, 4, 34, -10, -6, 21, + 9, -17, 7, 28, -27, -5, 47, -38, -19, 66, -49, -33, + -65, 24, 65, -46, 13, 52, -27, 2, 38, -8, -7, 25, + 11, -18, 11, 30, -29, -1, 49, -39, -15, 68, -50, -29, + -62, 23, 70, -43, 12, 57, -24, 1, 43, -5, -9, 29, + 14, -20, 16, 33, -30, 2, 52, -41, -10, 71, -52, -24, + -60, 21, 74, -41, 11, 61, -22, 0, 47, -3, -10, 33, + 16, -21, 20, 35, -32, 6, 54, -42, -6, 73, -53, -20, + -57, 20, 78, -39, 9, 65, -19, -1, 51, -1, -11, 37, + 19, -22, 24, 38, -33, 10, 56, -43, -2, 76, -54, -16, + -55, 18, 82, -36, 8, 69, -17, -2, 55, 2, -13, 41, + 21, -24, 28, 40, -34, 14, 59, -45, 1, 78, -56, -12, + -53, 17, 86, -34, 7, 73, -15, -3, 59, 4, -14, 45, + 24, -25, 32, 42, -36, 18, 61, -46, 5, 81, -57, -8, + -50, 16, 90, -31, 5, 77, -12, -5, 63, 7, -16, 50, + 26, -26, 36, 45, -37, 23, 64, -48, 9, 83, -59, -4, + -48, 14, 94, -29, 4, 81, -9, -6, 67, 9, -17, 54, + 29, -28, 40, 47, -38, 27, 66, -49, 13, 86, -60, 0, + -45, 13, 98, -26, 2, 85, -7, -8, 71, 12, -18, 58, + 31, -29, 44, 50, -40, 31, 69, -50, 17, 88, -61, 3, + -43, 12, 102, -24, 1, 89, -5, -9, 75, 14, -20, 62, + 33, -31, 48, 52, -41, 35, 71, -52, 21, 90, -63, 7, + -40, 10, 107, -21, 0, 94, -2, -11, 80, 17, -21, 66, + 36, -32, 53, 55, -43, 39, 74, -53, 26, 93, -64, 12, + -38, 9, 111, -19, -1, 98, 0, -12, 84, 19, -22, 70, + 39, -33, 57, 57, -44, 43, 76, -55, 30, 95, -66, 16, + -35, 7, 115, -17, -2, 102, 3, -13, 88, 22, -24, 74, + 41, -35, 61, 60, -45, 47, 79, -56, 34, 98, -67, 20, + -111, 54, -12, -92, 44, -26, -73, 33, -39, -54, 22, -53, + -34, 11, -67, -16, 1, -80, 3, -9, -93, 23, -20, -107, + -108, 53, -8, -90, 42, -22, -70, 31, -35, -51, 21, -49, + -32, 10, -63, -13, 0, -76, 6, -10, -89, 25, -21, -103, + -106, 52, -4, -87, 41, -18, -68, 30, -31, -49, 20, -45, + -30, 9, -59, -11, -1, -72, 8, -12, -85, 27, -23, -99, + -103, 50, 0, -84, 40, -13, -65, 29, -27, -46, 18, -40, + -27, 7, -54, -8, -3, -68, 11, -13, -81, 30, -24, -95, + -101, 49, 3, -82, 38, -9, -63, 27, -23, -44, 17, -36, + -25, 6, -50, -6, -4, -64, 13, -14, -77, 32, -25, -91, + -98, 47, 7, -80, 37, -5, -60, 26, -19, -41, 15, -32, + -22, 4, -46, -3, -5, -60, 15, -16, -73, 35, -27, -87, + -96, 46, 11, -77, 35, -1, -58, 25, -15, -39, 14, -28, + -20, 3, -42, -1, -7, -56, 18, -17, -69, 37, -28, -83, + -93, 45, 16, -75, 34, 2, -55, 23, -10, -36, 12, -24, + -17, 1, -38, 2, -8, -51, 21, -19, -64, 40, -30, -78, + -91, 43, 20, -72, 33, 6, -53, 22, -6, -34, 11, -20, + -15, 0, -34, 4, -9, -47, 23, -20, -60, 42, -31, -74, + -89, 42, 24, -70, 31, 10, -50, 20, -2, -32, 10, -16, + -12, 0, -30, 7, -11, -43, 25, -21, -56, 45, -32, -70, + -86, 41, 28, -67, 30, 14, -48, 19, 1, -29, 8, -12, + -10, -2, -26, 9, -12, -39, 28, -23, -52, 47, -34, -66, + -84, 39, 32, -65, 29, 18, -46, 18, 5, -27, 7, -8, + -7, -3, -22, 11, -14, -35, 30, -24, -48, 49, -35, -62, + -81, 38, 36, -62, 27, 23, -43, 16, 9, -24, 6, -3, + -5, -4, -17, 14, -15, -31, 33, -26, -44, 52, -37, -58, + -79, 36, 40, -60, 26, 27, -41, 15, 13, -22, 4, 0, + -2, -6, -13, 16, -16, -27, 35, -27, -40, 55, -38, -54, + -76, 35, 44, -58, 24, 31, -38, 13, 17, -19, 3, 4, + 0, -7, -9, 19, -18, -23, 38, -28, -36, 57, -39, -50, + -74, 34, 48, -55, 23, 35, -36, 12, 21, -17, 1, 8, + 2, -8, -5, 21, -19, -19, 40, -30, -32, 59, -41, -46, + -71, 32, 53, -52, 21, 39, -33, 11, 26, -14, 0, 12, + 5, -10, -1, 24, -21, -14, 43, -31, -27, 62, -42, -41, + -69, 31, 57, -50, 20, 43, -31, 9, 30, -12, 0, 16, + 7, -11, 2, 26, -22, -10, 45, -33, -23, 64, -43, -37, + -66, 29, 61, -48, 19, 47, -28, 8, 34, -10, -2, 20, + 10, -13, 6, 29, -23, -6, 47, -34, -19, 67, -45, -33, + -64, 28, 65, -45, 17, 51, -26, 6, 38, -7, -3, 24, + 12, -14, 10, 31, -25, -2, 50, -35, -15, 69, -46, -29, + -61, 27, 69, -43, 16, 56, -23, 5, 42, -4, -5, 29, + 15, -16, 15, 34, -26, 1, 53, -37, -11, 72, -48, -25, + -59, 25, 73, -40, 15, 60, -21, 4, 46, -2, -6, 33, + 17, -17, 19, 36, -28, 5, 55, -38, -7, 74, -49, -21, + -57, 24, 77, -38, 13, 64, -18, 2, 50, 0, -7, 37, + 20, -18, 23, 39, -29, 9, 57, -39, -3, 77, -50, -17, + -54, 22, 81, -35, 12, 68, -16, 1, 54, 3, -9, 41, + 22, -20, 27, 41, -30, 13, 60, -41, 0, 79, -52, -13, + -52, 21, 85, -33, 11, 72, -14, 0, 58, 5, -10, 45, + 25, -21, 31, 43, -32, 17, 62, -42, 4, 81, -53, -9, + -49, 20, 90, -30, 9, 76, -11, -1, 63, 8, -12, 49, + 27, -22, 35, 46, -33, 22, 65, -44, 9, 84, -55, -4, + -47, 18, 94, -28, 8, 80, -9, -2, 67, 10, -13, 53, + 30, -24, 39, 48, -34, 26, 67, -45, 13, 87, -56, 0, + -44, 17, 98, -26, 6, 84, -6, -4, 71, 13, -14, 57, + 32, -25, 43, 51, -36, 30, 70, -46, 17, 89, -57, 3, + -42, 16, 102, -23, 5, 88, -4, -5, 75, 15, -16, 61, + 34, -27, 47, 53, -37, 34, 72, -48, 21, 91, -59, 7, + -39, 14, 106, -20, 3, 93, -1, -7, 79, 18, -17, 66, + 37, -28, 52, 56, -39, 38, 75, -49, 25, 94, -60, 11, + -37, 13, 110, -18, 2, 97, 1, -8, 83, 20, -18, 70, + 39, -29, 56, 58, -40, 42, 77, -51, 29, 96, -62, 15, + -34, 11, 114, -16, 1, 101, 4, -9, 87, 22, -20, 74, + 42, -31, 60, 61, -41, 46, 79, -52, 33, 99, -63, 19, + -110, 58, -13, -91, 48, -26, -72, 37, -40, -53, 26, -53, + -33, 15, -67, -15, 5, -81, 4, -5, -94, 23, -16, -108, + -107, 57, -9, -89, 46, -22, -69, 35, -36, -50, 25, -49, + -31, 14, -63, -12, 3, -77, 6, -6, -90, 26, -17, -104, + -105, 56, -5, -86, 45, -18, -67, 34, -32, -48, 24, -45, + -29, 13, -59, -10, 2, -73, 9, -8, -86, 28, -19, -100, + -102, 54, 0, -84, 44, -14, -64, 33, -28, -45, 22, -41, + -26, 11, -55, -7, 0, -68, 12, -9, -82, 31, -20, -95, + -100, 53, 3, -81, 42, -10, -62, 31, -24, -43, 21, -37, + -24, 10, -51, -5, 0, -64, 14, -10, -78, 33, -21, -91, + -98, 51, 7, -79, 41, -6, -59, 30, -20, -41, 19, -33, + -21, 8, -47, -2, -1, -60, 16, -12, -74, 36, -23, -87, + -95, 50, 11, -76, 39, -2, -57, 29, -16, -38, 18, -29, + -19, 7, -43, 0, -3, -56, 19, -13, -70, 38, -24, -83, + -92, 49, 15, -74, 38, 2, -54, 27, -11, -36, 16, -24, + -16, 5, -38, 3, -4, -52, 21, -15, -65, 41, -26, -79, + -90, 47, 19, -71, 37, 6, -52, 26, -7, -33, 15, -20, + -14, 4, -34, 5, -5, -48, 24, -16, -61, 43, -27, -75, + -88, 46, 23, -69, 35, 10, -50, 24, -3, -31, 14, -16, + -11, 3, -30, 7, -7, -44, 26, -17, -57, 46, -28, -71, + -85, 45, 27, -66, 34, 14, -47, 23, 0, -28, 12, -12, + -9, 1, -26, 10, -8, -40, 29, -19, -53, 48, -30, -67, + -83, 43, 31, -64, 33, 18, -45, 22, 4, -26, 11, -8, + -7, 0, -22, 12, -10, -36, 31, -20, -49, 50, -31, -63, + -80, 42, 36, -61, 31, 22, -42, 20, 8, -23, 10, -4, + -4, 0, -18, 15, -11, -31, 34, -22, -45, 53, -33, -58, + -78, 40, 40, -59, 30, 26, -40, 19, 12, -21, 8, 0, + -1, -2, -14, 17, -12, -27, 36, -23, -41, 55, -34, -54, + -75, 39, 44, -57, 28, 30, -37, 17, 16, -18, 7, 3, + 1, -3, -10, 20, -14, -23, 38, -24, -37, 58, -35, -50, + -73, 38, 48, -54, 27, 34, -35, 16, 20, -16, 5, 7, + 3, -4, -6, 22, -15, -19, 41, -26, -33, 60, -37, -46, + -70, 36, 52, -52, 25, 39, -32, 15, 25, -13, 4, 12, + 6, -6, -1, 25, -17, -15, 44, -27, -28, 63, -38, -42, + -68, 35, 56, -49, 24, 43, -30, 13, 29, -11, 3, 16, + 8, -7, 2, 27, -18, -11, 46, -29, -24, 65, -39, -38, + -66, 33, 60, -47, 23, 47, -27, 12, 33, -9, 1, 20, + 11, -9, 6, 30, -19, -7, 48, -30, -20, 68, -41, -34, + -63, 32, 64, -44, 21, 51, -25, 10, 37, -6, 0, 24, + 13, -10, 10, 32, -21, -3, 51, -31, -16, 70, -42, -30, + -60, 31, 69, -42, 20, 55, -22, 9, 41, -4, -1, 28, + 16, -12, 14, 35, -22, 1, 53, -33, -12, 73, -44, -25, + -58, 29, 73, -39, 19, 59, -20, 8, 45, -1, -2, 32, + 18, -13, 18, 37, -24, 5, 56, -34, -8, 75, -45, -21, + -56, 28, 77, -37, 17, 63, -18, 6, 49, 1, -3, 36, + 21, -14, 22, 39, -25, 9, 58, -35, -4, 78, -46, -17, + -53, 26, 81, -34, 16, 67, -15, 5, 53, 4, -5, 40, + 23, -16, 26, 42, -26, 13, 61, -37, 0, 80, -48, -13, + -51, 25, 85, -32, 15, 71, -13, 4, 57, 6, -6, 44, + 25, -17, 30, 44, -28, 17, 63, -38, 3, 82, -49, -9, + -48, 24, 89, -29, 13, 76, -10, 2, 62, 9, -8, 49, + 28, -18, 35, 47, -29, 21, 66, -40, 8, 85, -51, -5, + -46, 22, 93, -27, 12, 80, -8, 1, 66, 11, -9, 53, + 31, -20, 39, 49, -30, 25, 68, -41, 12, 87, -52, -1, + -43, 21, 97, -25, 10, 84, -5, 0, 70, 14, -10, 57, + 33, -21, 43, 52, -32, 29, 70, -42, 16, 90, -53, 2, + -41, 20, 101, -22, 9, 88, -3, -1, 74, 16, -12, 61, + 35, -23, 47, 54, -33, 33, 73, -44, 20, 92, -55, 6, + -38, 18, 106, -20, 7, 92, 0, -3, 78, 19, -13, 65, + 38, -24, 51, 57, -35, 38, 76, -45, 24, 95, -56, 11, + -36, 17, 110, -17, 6, 96, 2, -4, 82, 21, -14, 69, + 40, -25, 55, 59, -36, 42, 78, -47, 28, 97, -58, 15, + -34, 15, 114, -15, 5, 100, 5, -5, 86, 23, -16, 73, + 43, -27, 59, 62, -37, 46, 80, -48, 32, 100, -59, 19, + -109, 63, -14, -90, 52, -27, -71, 41, -41, -52, 31, -54, + -32, 20, -68, -14, 9, -81, 5, 0, -95, 24, -11, -109, + -106, 62, -10, -88, 51, -23, -68, 40, -37, -49, 29, -50, + -30, 18, -64, -11, 8, -77, 8, -2, -91, 27, -13, -105, + -104, 60, -6, -85, 50, -19, -66, 39, -33, -47, 28, -46, + -28, 17, -60, -9, 6, -73, 10, -3, -87, 29, -14, -101, + -101, 59, -1, -82, 48, -14, -63, 37, -28, -44, 26, -42, + -25, 16, -56, -6, 5, -69, 13, -5, -82, 32, -16, -96, + -99, 57, 2, -80, 47, -10, -61, 36, -24, -42, 25, -38, + -23, 14, -52, -4, 4, -65, 15, -6, -78, 34, -17, -92, + -96, 56, 6, -78, 45, -6, -58, 34, -20, -40, 24, -34, + -20, 13, -48, -1, 2, -61, 17, -7, -74, 37, -18, -88, + -94, 55, 10, -75, 44, -2, -56, 33, -16, -37, 22, -30, + -18, 12, -44, 1, 1, -57, 20, -9, -70, 39, -20, -84, + -91, 53, 14, -73, 42, 1, -53, 32, -12, -34, 21, -25, + -15, 10, -39, 4, 0, -52, 22, -10, -66, 42, -21, -80, + -89, 52, 18, -70, 41, 5, -51, 30, -8, -32, 20, -21, + -13, 9, -35, 6, -1, -48, 25, -12, -62, 44, -22, -76, + -87, 50, 22, -68, 40, 9, -48, 29, -4, -30, 18, -17, + -10, 7, -31, 8, -2, -44, 27, -13, -58, 47, -24, -72, + -84, 49, 26, -65, 38, 13, -46, 27, 0, -27, 17, -13, + -8, 6, -27, 11, -4, -40, 30, -14, -54, 49, -25, -68, + -82, 48, 30, -63, 37, 17, -44, 26, 3, -25, 16, -9, + -6, 5, -23, 13, -5, -36, 32, -16, -50, 51, -27, -64, + -79, 46, 35, -60, 36, 22, -41, 25, 8, -22, 14, -5, + -3, 3, -19, 16, -7, -32, 35, -17, -45, 54, -28, -59, + -77, 45, 39, -58, 34, 26, -39, 23, 12, -20, 13, -1, + 0, 2, -15, 18, -8, -28, 37, -18, -41, 56, -29, -55, + -74, 43, 43, -56, 33, 30, -36, 22, 16, -17, 11, 2, + 2, 0, -11, 21, -9, -24, 40, -20, -37, 59, -31, -51, + -72, 42, 47, -53, 31, 34, -34, 21, 20, -15, 10, 6, + 4, 0, -7, 23, -11, -20, 42, -21, -33, 61, -32, -47, + -69, 41, 51, -51, 30, 38, -31, 19, 24, -12, 8, 11, + 7, -1, -2, 26, -12, -15, 45, -23, -29, 64, -34, -43, + -67, 39, 55, -48, 29, 42, -29, 18, 28, -10, 7, 15, + 9, -3, 1, 28, -13, -11, 47, -24, -25, 66, -35, -39, + -65, 38, 59, -46, 27, 46, -26, 16, 32, -8, 6, 19, + 12, -4, 5, 31, -15, -7, 49, -25, -21, 69, -36, -35, + -62, 37, 63, -43, 26, 50, -24, 15, 36, -5, 4, 23, + 14, -6, 9, 33, -16, -3, 52, -27, -17, 71, -38, -31, + -59, 35, 68, -41, 24, 55, -21, 13, 41, -2, 3, 27, + 17, -7, 13, 36, -18, 0, 54, -28, -12, 74, -39, -26, + -57, 34, 72, -38, 23, 59, -19, 12, 45, 0, 2, 31, + 19, -8, 17, 38, -19, 4, 57, -30, -8, 76, -41, -22, + -55, 32, 76, -36, 22, 63, -16, 11, 49, 2, 0, 35, + 22, -10, 21, 40, -20, 8, 59, -31, -4, 79, -42, -18, + -52, 31, 80, -33, 20, 67, -14, 9, 53, 5, 0, 39, + 24, -11, 25, 43, -22, 12, 62, -32, 0, 81, -43, -14, + -50, 30, 84, -31, 19, 71, -12, 8, 57, 7, -2, 43, + 26, -12, 29, 45, -23, 16, 64, -34, 3, 83, -45, -10, + -47, 28, 88, -28, 17, 75, -9, 7, 61, 10, -3, 48, + 29, -14, 34, 48, -25, 21, 67, -35, 7, 86, -46, -6, + -45, 27, 92, -26, 16, 79, -7, 5, 65, 12, -4, 52, + 32, -15, 38, 50, -26, 25, 69, -37, 11, 88, -47, -2, + -42, 25, 96, -24, 15, 83, -4, 4, 69, 15, -6, 56, + 34, -17, 42, 53, -27, 29, 72, -38, 15, 91, -49, 1, + -40, 24, 100, -21, 13, 87, -2, 3, 73, 17, -7, 60, + 36, -18, 46, 55, -29, 33, 74, -39, 19, 93, -50, 5, + -37, 23, 105, -19, 12, 92, 1, 1, 78, 20, -9, 64, + 39, -20, 50, 58, -30, 37, 77, -41, 24, 96, -52, 10, + -35, 21, 109, -16, 11, 96, 3, 0, 82, 22, -10, 68, + 41, -21, 54, 60, -31, 41, 79, -42, 28, 98, -53, 14, + -33, 20, 113, -14, 9, 100, 6, -1, 86, 24, -11, 72, + 44, -22, 58, 63, -33, 45, 81, -43, 32, 101, -54, 18, + -108, 67, -14, -89, 56, -28, -70, 45, -41, -51, 35, -55, + -32, 24, -69, -13, 13, -82, 6, 3, -95, 25, -7, -109, + -105, 66, -10, -87, 55, -24, -67, 44, -37, -49, 33, -51, + -29, 22, -65, -10, 12, -78, 8, 1, -91, 28, -9, -105, + -103, 64, -6, -84, 54, -20, -65, 43, -33, -46, 32, -47, + -27, 21, -61, -8, 10, -74, 11, 0, -87, 30, -10, -101, + -100, 63, -2, -82, 52, -15, -62, 41, -29, -43, 30, -42, + -24, 20, -56, -5, 9, -70, 14, -1, -83, 33, -12, -97, + -98, 61, 1, -79, 51, -11, -60, 40, -25, -41, 29, -38, + -22, 18, -52, -3, 8, -66, 16, -2, -79, 35, -13, -93, + -96, 60, 5, -77, 49, -7, -57, 38, -21, -39, 28, -34, + -19, 17, -48, 0, 6, -62, 18, -3, -75, 38, -14, -89, + -93, 59, 9, -74, 48, -3, -55, 37, -17, -36, 26, -30, + -17, 16, -44, 2, 5, -58, 21, -5, -71, 40, -16, -85, + -91, 57, 14, -72, 46, 0, -52, 36, -12, -34, 25, -26, + -14, 14, -40, 5, 3, -53, 23, -6, -66, 43, -17, -80, + -88, 56, 18, -69, 45, 4, -50, 34, -8, -31, 24, -22, + -12, 13, -36, 7, 2, -49, 26, -8, -62, 45, -18, -76, + -86, 54, 22, -67, 44, 8, -48, 33, -4, -29, 22, -18, + -9, 11, -32, 9, 1, -45, 28, -9, -58, 48, -20, -72, + -83, 53, 26, -65, 42, 12, -45, 31, 0, -26, 21, -14, + -7, 10, -28, 12, 0, -41, 31, -10, -54, 50, -21, -68, + -81, 52, 30, -62, 41, 16, -43, 30, 3, -24, 20, -10, + -5, 9, -24, 14, -1, -37, 33, -12, -50, 52, -23, -64, + -78, 50, 34, -59, 40, 21, -40, 29, 7, -21, 18, -5, + -2, 7, -19, 17, -3, -33, 36, -13, -46, 55, -24, -60, + -76, 49, 38, -57, 38, 25, -38, 27, 11, -19, 17, -1, + 0, 6, -15, 19, -4, -29, 38, -14, -42, 57, -25, -56, + -73, 47, 42, -55, 37, 29, -35, 26, 15, -17, 15, 2, + 3, 4, -11, 22, -5, -25, 40, -16, -38, 60, -27, -52, + -71, 46, 46, -52, 35, 33, -33, 25, 19, -14, 14, 6, + 5, 3, -7, 24, -7, -21, 43, -17, -34, 62, -28, -48, + -68, 45, 51, -50, 34, 37, -30, 23, 24, -11, 12, 10, + 8, 2, -3, 27, -8, -16, 46, -19, -29, 65, -30, -43, + -66, 43, 55, -47, 33, 41, -28, 22, 28, -9, 11, 14, + 10, 0, 0, 29, -9, -12, 48, -20, -25, 67, -31, -39, + -64, 42, 59, -45, 31, 45, -25, 20, 32, -7, 10, 18, + 13, 0, 4, 32, -11, -8, 50, -21, -21, 70, -32, -35, + -61, 41, 63, -42, 30, 49, -23, 19, 36, -4, 8, 22, + 15, -2, 8, 34, -12, -4, 53, -23, -17, 72, -34, -31, + -59, 39, 67, -40, 28, 54, -20, 17, 40, -2, 7, 27, + 18, -3, 13, 37, -14, 0, 55, -24, -13, 75, -35, -27, + -56, 38, 71, -37, 27, 58, -18, 16, 44, 1, 6, 31, + 20, -4, 17, 39, -15, 3, 58, -26, -9, 77, -37, -23, + -54, 36, 75, -35, 26, 62, -16, 15, 48, 3, 4, 35, + 23, -6, 21, 41, -16, 7, 60, -27, -5, 80, -38, -19, + -51, 35, 79, -33, 24, 66, -13, 13, 52, 6, 3, 39, + 25, -7, 25, 44, -18, 11, 63, -28, -1, 82, -39, -15, + -49, 34, 83, -30, 23, 70, -11, 12, 56, 8, 1, 43, + 27, -8, 29, 46, -19, 15, 65, -30, 2, 84, -41, -11, + -46, 32, 88, -27, 21, 74, -8, 11, 61, 11, 0, 47, + 30, -10, 33, 49, -21, 20, 68, -31, 7, 87, -42, -6, + -44, 31, 92, -25, 20, 78, -6, 9, 65, 13, 0, 51, + 32, -11, 37, 51, -22, 24, 70, -33, 11, 89, -43, -2, + -41, 29, 96, -23, 19, 82, -3, 8, 69, 15, -2, 55, + 35, -13, 41, 54, -23, 28, 72, -34, 15, 92, -45, 1, + -39, 28, 100, -20, 17, 86, -1, 7, 73, 18, -3, 59, + 37, -14, 45, 56, -25, 32, 75, -35, 19, 94, -46, 5, + -36, 27, 104, -18, 16, 91, 2, 5, 77, 21, -5, 64, + 40, -16, 50, 59, -26, 36, 77, -37, 23, 97, -48, 9, + -34, 25, 108, -15, 15, 95, 4, 4, 81, 23, -6, 68, + 42, -17, 54, 61, -27, 40, 80, -38, 27, 99, -49, 13, + -32, 24, 112, -13, 13, 99, 7, 2, 85, 25, -7, 72, + 45, -18, 58, 63, -29, 44, 82, -39, 31, 102, -50, 17, + -107, 71, -15, -88, 60, -28, -69, 49, -42, -50, 39, -55, + -31, 28, -69, -12, 17, -83, 7, 7, -96, 26, -3, -110, + -105, 70, -11, -86, 59, -24, -66, 48, -38, -48, 37, -51, + -28, 26, -65, -9, 16, -79, 9, 5, -92, 29, -5, -106, + -102, 68, -7, -83, 58, -20, -64, 47, -34, -45, 36, -47, + -26, 25, -61, -7, 14, -75, 12, 4, -88, 31, -6, -102, + -99, 67, -2, -81, 56, -16, -61, 45, -30, -43, 34, -43, + -23, 24, -57, -4, 13, -70, 14, 2, -84, 34, -8, -97, + -97, 65, 1, -78, 55, -12, -59, 44, -26, -40, 33, -39, + -21, 22, -53, -2, 12, -66, 17, 1, -80, 36, -9, -93, + -95, 64, 5, -76, 53, -8, -57, 42, -22, -38, 32, -35, + -18, 21, -49, 0, 10, -62, 19, 0, -76, 39, -10, -89, + -92, 63, 9, -73, 52, -4, -54, 41, -18, -35, 30, -31, + -16, 20, -45, 3, 9, -58, 22, -1, -72, 41, -12, -85, + -90, 61, 13, -71, 50, 0, -51, 40, -13, -33, 29, -26, + -13, 18, -40, 6, 7, -54, 24, -2, -67, 44, -13, -81, + -87, 60, 17, -68, 49, 4, -49, 38, -9, -30, 28, -22, + -11, 17, -36, 8, 6, -50, 27, -4, -63, 46, -14, -77, + -85, 58, 21, -66, 48, 8, -47, 37, -5, -28, 26, -18, + -8, 15, -32, 10, 5, -46, 29, -5, -59, 48, -16, -73, + -82, 57, 25, -64, 46, 12, -44, 35, -1, -25, 25, -14, + -6, 14, -28, 13, 3, -42, 31, -6, -55, 51, -17, -69, + -80, 56, 29, -61, 45, 16, -42, 34, 2, -23, 24, -10, + -4, 13, -24, 15, 2, -38, 34, -8, -51, 53, -19, -65, + -77, 54, 34, -59, 44, 20, -39, 33, 6, -20, 22, -6, + -1, 11, -20, 18, 0, -33, 37, -9, -47, 56, -20, -60, + -75, 53, 38, -56, 42, 24, -37, 31, 10, -18, 21, -2, + 1, 10, -16, 20, 0, -29, 39, -10, -43, 58, -21, -56, + -73, 51, 42, -54, 41, 28, -34, 30, 14, -16, 19, 1, + 4, 8, -12, 23, -1, -25, 41, -12, -39, 61, -23, -52, + -70, 50, 46, -51, 39, 32, -32, 29, 18, -13, 18, 5, + 6, 7, -8, 25, -3, -21, 44, -13, -35, 63, -24, -48, + -67, 49, 50, -49, 38, 37, -29, 27, 23, -11, 16, 10, + 9, 6, -3, 28, -4, -17, 46, -15, -30, 66, -26, -44, + -65, 47, 54, -46, 37, 41, -27, 26, 27, -8, 15, 14, + 11, 4, 0, 30, -5, -13, 49, -16, -26, 68, -27, -40, + -63, 46, 58, -44, 35, 45, -25, 24, 31, -6, 14, 18, + 14, 3, 4, 32, -7, -9, 51, -17, -22, 71, -28, -36, + -60, 45, 62, -42, 34, 49, -22, 23, 35, -3, 12, 22, + 16, 1, 8, 35, -8, -5, 54, -19, -18, 73, -30, -32, + -58, 43, 67, -39, 32, 53, -19, 21, 39, -1, 11, 26, + 19, 0, 12, 37, -10, 0, 56, -20, -14, 76, -31, -27, + -55, 42, 71, -36, 31, 57, -17, 20, 43, 2, 10, 30, + 21, 0, 16, 40, -11, 3, 59, -22, -10, 78, -33, -23, + -53, 40, 75, -34, 30, 61, -15, 19, 47, 4, 8, 34, + 23, -2, 20, 42, -12, 7, 61, -23, -6, 80, -34, -19, + -50, 39, 79, -32, 28, 65, -12, 17, 51, 7, 7, 38, + 26, -3, 24, 45, -14, 11, 63, -24, -2, 83, -35, -15, + -48, 38, 83, -29, 27, 69, -10, 16, 55, 9, 5, 42, + 28, -4, 28, 47, -15, 15, 66, -26, 1, 85, -37, -11, + -45, 36, 87, -27, 25, 74, -7, 15, 60, 12, 4, 47, + 31, -6, 33, 50, -17, 19, 69, -27, 6, 88, -38, -7, + -43, 35, 91, -24, 24, 78, -5, 13, 64, 14, 3, 51, + 33, -7, 37, 52, -18, 23, 71, -29, 10, 90, -39, -3, + -41, 33, 95, -22, 23, 82, -2, 12, 68, 16, 1, 55, + 36, -9, 41, 55, -19, 27, 73, -30, 14, 93, -41, 0, + -38, 32, 99, -19, 21, 86, 0, 11, 72, 19, 0, 59, + 38, -10, 45, 57, -21, 31, 76, -31, 18, 95, -42, 4, + -35, 31, 104, -17, 20, 90, 3, 9, 76, 21, -1, 63, + 41, -12, 49, 60, -22, 36, 78, -33, 22, 98, -44, 9, + -33, 29, 108, -14, 19, 94, 5, 8, 80, 24, -2, 67, + 43, -13, 53, 62, -23, 40, 81, -34, 26, 100, -45, 13, + -31, 28, 112, -12, 17, 98, 7, 6, 84, 26, -3, 71, + 46, -14, 57, 64, -25, 44, 83, -35, 30, 103, -46, 17, + -106, 75, -16, -87, 64, -29, -68, 53, -43, -49, 43, -56, + -30, 32, -70, -11, 21, -83, 8, 11, -97, 27, 0, -111, + -104, 74, -12, -85, 63, -25, -65, 52, -39, -47, 41, -52, + -27, 30, -66, -9, 20, -79, 10, 9, -93, 30, -1, -107, + -101, 72, -8, -82, 62, -21, -63, 51, -35, -44, 40, -48, + -25, 29, -62, -6, 18, -75, 13, 8, -89, 32, -2, -103, + -99, 71, -3, -80, 60, -16, -60, 49, -30, -42, 38, -44, + -22, 28, -57, -3, 17, -71, 15, 6, -84, 35, -4, -98, + -96, 69, 0, -77, 59, -12, -58, 48, -26, -39, 37, -40, + -20, 26, -53, -1, 16, -67, 18, 5, -80, 37, -5, -94, + -94, 68, 4, -75, 57, -8, -56, 46, -22, -37, 36, -36, + -17, 25, -49, 1, 14, -63, 20, 4, -76, 39, -6, -90, + -91, 67, 8, -73, 56, -4, -53, 45, -18, -34, 34, -32, + -15, 24, -45, 4, 13, -59, 23, 2, -72, 42, -8, -86, + -89, 65, 12, -70, 54, 0, -51, 44, -14, -32, 33, -27, + -12, 22, -41, 6, 11, -54, 25, 1, -68, 45, -9, -82, + -86, 64, 16, -68, 53, 3, -48, 42, -10, -29, 32, -23, + -10, 21, -37, 9, 10, -50, 28, 0, -64, 47, -10, -78, + -84, 62, 20, -65, 52, 7, -46, 41, -6, -27, 30, -19, + -8, 19, -33, 11, 9, -46, 30, -1, -60, 49, -12, -74, + -82, 61, 24, -63, 50, 11, -43, 39, -2, -25, 29, -15, + -5, 18, -29, 14, 7, -42, 32, -2, -56, 52, -13, -70, + -79, 60, 28, -60, 49, 15, -41, 38, 1, -22, 28, -11, + -3, 17, -25, 16, 6, -38, 35, -4, -52, 54, -15, -66, + -76, 58, 33, -58, 48, 20, -38, 37, 6, -19, 26, -7, + 0, 15, -20, 19, 4, -34, 37, -5, -47, 57, -16, -61, + -74, 57, 37, -55, 46, 24, -36, 35, 10, -17, 25, -3, + 2, 14, -16, 21, 3, -30, 40, -6, -43, 59, -17, -57, + -72, 55, 41, -53, 45, 28, -33, 34, 14, -15, 23, 0, + 5, 12, -12, 23, 2, -26, 42, -8, -39, 62, -19, -53, + -69, 54, 45, -50, 43, 32, -31, 33, 18, -12, 22, 4, + 7, 11, -8, 26, 0, -22, 45, -9, -35, 64, -20, -49, + -67, 53, 49, -48, 42, 36, -28, 31, 22, -10, 20, 9, + 10, 10, -4, 29, 0, -17, 47, -11, -31, 67, -22, -45, + -64, 51, 53, -45, 41, 40, -26, 30, 26, -7, 19, 13, + 12, 8, 0, 31, -1, -13, 50, -12, -27, 69, -23, -41, + -62, 50, 57, -43, 39, 44, -24, 28, 30, -5, 18, 17, + 15, 7, 3, 33, -3, -9, 52, -13, -23, 71, -24, -37, + -59, 49, 61, -41, 38, 48, -21, 27, 34, -2, 16, 21, + 17, 5, 7, 36, -4, -5, 55, -15, -19, 74, -26, -33, + -57, 47, 66, -38, 36, 53, -19, 25, 39, 0, 15, 25, + 20, 4, 12, 38, -6, -1, 57, -16, -14, 77, -27, -28, + -54, 46, 70, -36, 35, 57, -16, 24, 43, 3, 14, 29, + 22, 3, 16, 41, -7, 2, 60, -18, -10, 79, -29, -24, + -52, 44, 74, -33, 34, 61, -14, 23, 47, 5, 12, 33, + 24, 1, 20, 43, -8, 6, 62, -19, -6, 81, -30, -20, + -50, 43, 78, -31, 32, 65, -11, 21, 51, 7, 11, 37, + 27, 0, 24, 46, -10, 10, 64, -20, -2, 84, -31, -16, + -47, 42, 82, -28, 31, 69, -9, 20, 55, 10, 9, 41, + 29, 0, 28, 48, -11, 14, 67, -22, 1, 86, -33, -12, + -44, 40, 86, -26, 29, 73, -6, 19, 59, 13, 8, 46, + 32, -2, 32, 51, -13, 19, 69, -23, 5, 89, -34, -8, + -42, 39, 90, -23, 28, 77, -4, 17, 63, 15, 7, 50, + 34, -3, 36, 53, -14, 23, 72, -25, 9, 91, -35, -4, + -40, 37, 94, -21, 27, 81, -1, 16, 67, 17, 5, 54, + 37, -5, 40, 55, -15, 27, 74, -26, 13, 94, -37, 0, + -37, 36, 98, -18, 25, 85, 1, 15, 71, 20, 4, 58, + 39, -6, 44, 58, -17, 31, 77, -27, 17, 96, -38, 3, + -35, 35, 103, -16, 24, 90, 4, 13, 76, 22, 2, 62, + 42, -8, 49, 61, -18, 35, 79, -29, 22, 99, -40, 8, + -32, 33, 107, -13, 23, 94, 6, 12, 80, 25, 1, 66, + 44, -9, 53, 63, -19, 39, 82, -30, 26, 101, -41, 12, + -30, 32, 111, -11, 21, 98, 8, 10, 84, 27, 0, 70, + 47, -10, 57, 65, -21, 43, 84, -31, 30, 103, -42, 16, + -105, 79, -16, -86, 69, -30, -67, 58, -43, -48, 47, -57, + -29, 36, -71, -10, 26, -84, 9, 15, -97, 28, 4, -111, + -103, 78, -12, -84, 67, -26, -64, 56, -39, -46, 46, -53, + -26, 35, -67, -8, 24, -80, 11, 14, -93, 31, 3, -107, + -100, 77, -8, -81, 66, -22, -62, 55, -35, -43, 45, -49, + -24, 34, -63, -5, 23, -76, 14, 12, -89, 33, 1, -103, + -98, 75, -4, -79, 65, -17, -59, 54, -31, -41, 43, -44, + -21, 32, -58, -2, 21, -72, 16, 11, -85, 36, 0, -99, + -95, 74, 0, -76, 63, -13, -57, 52, -27, -38, 42, -40, + -19, 31, -54, 0, 20, -68, 19, 10, -81, 38, 0, -95, + -93, 72, 3, -74, 62, -9, -55, 51, -23, -36, 40, -36, + -16, 29, -50, 2, 19, -64, 21, 8, -77, 41, -2, -91, + -90, 71, 7, -72, 60, -5, -52, 50, -19, -33, 39, -32, + -14, 28, -46, 5, 17, -60, 24, 7, -73, 43, -3, -87, + -88, 70, 12, -69, 59, -1, -49, 48, -14, -31, 37, -28, + -11, 26, -42, 7, 16, -55, 26, 5, -68, 46, -5, -82, + -85, 68, 16, -66, 58, 2, -47, 47, -10, -28, 36, -24, + -9, 25, -38, 10, 15, -51, 29, 4, -64, 48, -6, -78, + -83, 67, 20, -64, 56, 6, -45, 45, -6, -26, 35, -20, + -7, 24, -34, 12, 13, -47, 31, 3, -60, 50, -7, -74, + -80, 66, 24, -62, 55, 10, -42, 44, -2, -24, 33, -16, + -4, 22, -30, 15, 12, -43, 33, 1, -56, 53, -9, -70, + -78, 64, 28, -59, 54, 14, -40, 43, 1, -21, 32, -12, + -2, 21, -26, 17, 10, -39, 36, 0, -52, 55, -10, -66, + -75, 63, 32, -57, 52, 19, -37, 41, 5, -18, 31, -7, + 1, 20, -21, 20, 9, -35, 38, -1, -48, 58, -12, -62, + -73, 61, 36, -54, 51, 23, -35, 40, 9, -16, 29, -3, + 3, 18, -17, 22, 8, -31, 41, -2, -44, 60, -13, -58, + -71, 60, 40, -52, 49, 27, -32, 38, 13, -14, 28, 0, + 6, 17, -13, 24, 6, -27, 43, -3, -40, 63, -14, -54, + -68, 59, 44, -49, 48, 31, -30, 37, 17, -11, 26, 4, + 8, 16, -9, 27, 5, -23, 46, -5, -36, 65, -16, -50, + -66, 57, 49, -47, 46, 35, -27, 36, 22, -9, 25, 8, + 11, 14, -5, 30, 3, -18, 48, -6, -31, 68, -17, -45, + -63, 56, 53, -44, 45, 39, -25, 34, 26, -6, 24, 12, + 13, 13, -1, 32, 2, -14, 51, -8, -27, 70, -18, -41, + -61, 54, 57, -42, 44, 43, -23, 33, 30, -4, 22, 16, + 16, 11, 2, 34, 1, -10, 53, -9, -23, 73, -20, -37, + -58, 53, 61, -40, 42, 47, -20, 31, 34, -1, 21, 20, + 18, 10, 6, 37, 0, -6, 56, -10, -19, 75, -21, -33, + -56, 52, 65, -37, 41, 52, -18, 30, 38, 1, 19, 25, + 21, 8, 11, 39, -1, -2, 58, -12, -15, 78, -23, -29, + -53, 50, 69, -34, 40, 56, -15, 29, 42, 4, 18, 29, + 23, 7, 15, 42, -3, 1, 61, -13, -11, 80, -24, -25, + -51, 49, 73, -32, 38, 60, -13, 27, 46, 6, 17, 33, + 25, 6, 19, 44, -4, 5, 63, -14, -7, 82, -25, -21, + -48, 47, 77, -30, 37, 64, -10, 26, 50, 8, 15, 37, + 28, 4, 23, 47, -5, 9, 65, -16, -3, 85, -27, -17, + -46, 46, 81, -27, 36, 68, -8, 25, 54, 11, 14, 41, + 30, 3, 27, 49, -7, 13, 68, -17, 0, 87, -28, -13, + -43, 45, 86, -25, 34, 72, -5, 23, 59, 14, 12, 45, + 33, 2, 31, 52, -8, 18, 70, -19, 5, 90, -30, -8, + -41, 43, 90, -22, 33, 76, -3, 22, 63, 16, 11, 49, + 35, 0, 35, 54, -9, 22, 73, -20, 9, 92, -31, -4, + -39, 42, 94, -20, 31, 80, 0, 20, 67, 18, 10, 53, + 38, 0, 39, 56, -11, 26, 75, -21, 13, 95, -32, 0, + -36, 41, 98, -17, 30, 84, 2, 19, 71, 21, 8, 57, + 40, -2, 43, 59, -12, 30, 78, -23, 17, 97, -34, 3, + -34, 39, 102, -15, 28, 89, 5, 17, 75, 23, 7, 62, + 43, -3, 48, 62, -14, 34, 80, -24, 21, 100, -35, 7, + -31, 38, 106, -12, 27, 93, 7, 16, 79, 26, 6, 66, + 45, -4, 52, 64, -15, 38, 83, -26, 25, 102, -37, 11, + -29, 36, 110, -10, 26, 97, 9, 15, 83, 28, 4, 70, + 48, -6, 56, 66, -16, 42, 85, -27, 29, 105, -38, 15, + -104, 83, -17, -85, 73, -30, -66, 62, -44, -47, 51, -58, + -28, 40, -71, -9, 30, -85, 10, 19, -98, 29, 8, -112, + -102, 82, -13, -83, 71, -26, -64, 60, -40, -45, 50, -54, + -25, 39, -67, -7, 28, -81, 12, 18, -94, 32, 7, -108, + -99, 81, -9, -81, 70, -22, -61, 59, -36, -42, 49, -50, + -23, 38, -63, -4, 27, -77, 15, 16, -90, 34, 5, -104, + -97, 79, -4, -78, 69, -18, -58, 58, -32, -40, 47, -45, + -20, 36, -59, -2, 25, -72, 17, 15, -86, 37, 4, -99, + -94, 78, 0, -75, 67, -14, -56, 56, -28, -37, 46, -41, + -18, 35, -55, 1, 24, -68, 20, 14, -82, 39, 3, -95, + -92, 76, 3, -73, 66, -10, -54, 55, -24, -35, 44, -37, + -16, 33, -51, 3, 23, -64, 22, 12, -78, 41, 1, -91, + -89, 75, 7, -71, 64, -6, -51, 54, -20, -32, 43, -33, + -13, 32, -47, 6, 21, -60, 24, 11, -74, 44, 0, -87, + -87, 74, 11, -68, 63, -1, -49, 52, -15, -30, 41, -29, + -10, 30, -42, 8, 20, -56, 27, 9, -69, 47, -1, -83, + -84, 72, 15, -66, 62, 2, -46, 51, -11, -27, 40, -25, + -8, 29, -38, 11, 19, -52, 30, 8, -65, 49, -2, -79, + -82, 71, 19, -63, 60, 6, -44, 49, -7, -25, 39, -21, + -6, 28, -34, 13, 17, -48, 32, 7, -61, 51, -3, -75, + -80, 70, 23, -61, 59, 10, -41, 48, -3, -23, 37, -17, + -3, 26, -30, 16, 16, -44, 34, 5, -57, 54, -5, -71, + -77, 68, 27, -58, 58, 14, -39, 47, 0, -20, 36, -13, + -1, 25, -26, 18, 14, -40, 37, 4, -53, 56, -6, -67, + -74, 67, 32, -56, 56, 18, -36, 45, 4, -18, 35, -8, + 2, 24, -22, 21, 13, -35, 39, 2, -49, 59, -8, -62, + -72, 65, 36, -53, 55, 22, -34, 44, 8, -15, 33, -4, + 4, 22, -18, 23, 12, -31, 42, 1, -45, 61, -9, -58, + -70, 64, 40, -51, 53, 26, -32, 42, 12, -13, 32, 0, + 7, 21, -14, 25, 10, -27, 44, 0, -41, 64, -10, -54, + -67, 63, 44, -49, 52, 30, -29, 41, 16, -10, 30, 3, + 9, 20, -10, 28, 9, -23, 47, -1, -37, 66, -12, -50, + -65, 61, 48, -46, 50, 35, -26, 40, 21, -8, 29, 7, + 12, 18, -5, 30, 7, -19, 49, -2, -32, 69, -13, -46, + -62, 60, 52, -43, 49, 39, -24, 38, 25, -5, 28, 11, + 14, 17, -1, 33, 6, -15, 52, -4, -28, 71, -14, -42, + -60, 58, 56, -41, 48, 43, -22, 37, 29, -3, 26, 15, + 16, 15, 2, 35, 5, -11, 54, -5, -24, 73, -16, -38, + -57, 57, 60, -39, 46, 47, -19, 35, 33, 0, 25, 19, + 19, 14, 6, 38, 3, -7, 56, -6, -20, 76, -17, -34, + -55, 56, 65, -36, 45, 51, -17, 34, 37, 2, 23, 24, + 22, 12, 10, 40, 2, -2, 59, -8, -16, 79, -19, -29, + -52, 54, 69, -34, 44, 55, -14, 33, 41, 5, 22, 28, + 24, 11, 14, 43, 0, 1, 62, -9, -12, 81, -20, -25, + -50, 53, 73, -31, 42, 59, -12, 31, 45, 7, 21, 32, + 26, 10, 18, 45, 0, 5, 64, -10, -8, 83, -21, -21, + -48, 51, 77, -29, 41, 63, -9, 30, 49, 9, 19, 36, + 29, 8, 22, 48, -1, 9, 66, -12, -4, 86, -23, -17, + -45, 50, 81, -26, 40, 67, -7, 29, 53, 12, 18, 40, + 31, 7, 26, 50, -3, 13, 69, -13, 0, 88, -24, -13, + -42, 49, 85, -24, 38, 72, -4, 27, 58, 14, 16, 44, + 34, 6, 31, 53, -4, 17, 71, -15, 4, 91, -26, -9, + -40, 47, 89, -21, 37, 76, -2, 26, 62, 17, 15, 48, + 36, 4, 35, 55, -5, 21, 74, -16, 8, 93, -27, -5, + -38, 46, 93, -19, 35, 80, 0, 24, 66, 19, 14, 52, + 39, 3, 39, 57, -7, 25, 76, -17, 12, 96, -28, -1, + -35, 45, 97, -17, 34, 84, 3, 23, 70, 22, 12, 56, + 41, 1, 43, 60, -8, 29, 79, -19, 16, 98, -30, 2, + -33, 43, 102, -14, 32, 88, 6, 21, 74, 24, 11, 61, + 44, 0, 47, 62, -10, 34, 81, -20, 20, 101, -31, 7, + -30, 42, 106, -11, 31, 92, 8, 20, 78, 27, 10, 65, + 46, 0, 51, 65, -11, 38, 84, -22, 24, 103, -33, 11, + -28, 40, 110, -9, 30, 96, 10, 19, 82, 29, 8, 69, + 48, -2, 55, 67, -12, 42, 86, -23, 28, 105, -34, 15, + -103, 87, -18, -84, 77, -31, -65, 66, -45, -46, 55, -58, + -27, 44, -72, -8, 34, -85, 11, 23, -99, 30, 12, -113, + -101, 86, -14, -82, 75, -27, -63, 64, -41, -44, 54, -54, + -24, 43, -68, -6, 32, -81, 13, 22, -95, 32, 11, -109, + -98, 85, -10, -80, 74, -23, -60, 63, -37, -41, 53, -50, + -22, 42, -64, -3, 31, -77, 15, 20, -91, 35, 9, -105, + -96, 83, -5, -77, 73, -18, -58, 62, -32, -39, 51, -46, + -19, 40, -59, -1, 29, -73, 18, 19, -86, 38, 8, -100, + -93, 82, -1, -75, 71, -14, -55, 60, -28, -36, 50, -42, + -17, 39, -55, 2, 28, -69, 21, 18, -82, 40, 7, -96, + -91, 80, 2, -72, 70, -10, -53, 59, -24, -34, 48, -38, + -15, 37, -51, 4, 27, -65, 23, 16, -78, 42, 5, -92, + -89, 79, 6, -70, 68, -6, -50, 58, -20, -32, 47, -34, + -12, 36, -47, 7, 25, -61, 25, 15, -74, 45, 4, -88, + -86, 78, 10, -67, 67, -2, -48, 56, -16, -29, 45, -29, + -10, 34, -43, 9, 24, -56, 28, 13, -70, 47, 2, -84, + -83, 76, 14, -65, 66, 1, -45, 55, -12, -26, 44, -25, + -7, 33, -39, 12, 23, -52, 30, 12, -66, 50, 1, -80, + -81, 75, 18, -62, 64, 5, -43, 53, -8, -24, 43, -21, + -5, 32, -35, 14, 21, -48, 33, 11, -62, 52, 0, -76, + -79, 74, 22, -60, 63, 9, -40, 52, -4, -22, 41, -17, + -2, 30, -31, 16, 20, -44, 35, 9, -58, 55, -1, -72, + -76, 72, 26, -57, 62, 13, -38, 51, 0, -19, 40, -13, + 0, 29, -27, 19, 18, -40, 38, 8, -54, 57, -2, -68, + -74, 71, 31, -55, 60, 18, -35, 49, 4, -17, 39, -9, + 3, 28, -22, 22, 17, -36, 40, 6, -49, 60, -4, -63, + -71, 69, 35, -52, 59, 22, -33, 48, 8, -14, 37, -5, + 5, 26, -18, 24, 16, -32, 43, 5, -45, 62, -5, -59, + -69, 68, 39, -50, 57, 26, -31, 46, 12, -12, 36, -1, + 8, 25, -14, 26, 14, -28, 45, 4, -41, 64, -6, -55, + -66, 67, 43, -48, 56, 30, -28, 45, 16, -9, 34, 2, + 10, 24, -10, 29, 13, -24, 47, 2, -37, 67, -8, -51, + -64, 65, 47, -45, 54, 34, -26, 44, 20, -7, 33, 7, + 13, 22, -6, 31, 11, -19, 50, 1, -33, 70, -9, -47, + -61, 64, 51, -43, 53, 38, -23, 42, 24, -4, 32, 11, + 15, 21, -2, 34, 10, -15, 53, 0, -29, 72, -10, -43, + -59, 62, 55, -40, 52, 42, -21, 41, 28, -2, 30, 15, + 17, 19, 1, 36, 9, -11, 55, -1, -25, 74, -12, -39, + -57, 61, 59, -38, 50, 46, -18, 39, 32, 0, 29, 19, + 20, 18, 5, 39, 7, -7, 57, -2, -21, 77, -13, -35, + -54, 60, 64, -35, 49, 51, -16, 38, 37, 3, 27, 23, + 22, 16, 10, 41, 6, -3, 60, -4, -16, 79, -15, -30, + -51, 58, 68, -33, 48, 55, -13, 37, 41, 5, 26, 27, + 25, 15, 14, 44, 4, 0, 62, -5, -12, 82, -16, -26, + -49, 57, 72, -30, 46, 59, -11, 35, 45, 8, 25, 31, + 27, 14, 18, 46, 3, 4, 65, -6, -8, 84, -17, -22, + -47, 55, 76, -28, 45, 63, -9, 34, 49, 10, 23, 35, + 30, 12, 22, 48, 2, 8, 67, -8, -4, 87, -19, -18, + -44, 54, 80, -25, 44, 67, -6, 33, 53, 13, 22, 39, + 32, 11, 26, 51, 0, 12, 70, -9, 0, 89, -20, -14, + -42, 53, 84, -23, 42, 71, -3, 31, 57, 15, 20, 44, + 35, 10, 30, 54, 0, 17, 72, -11, 3, 92, -22, -10, + -39, 51, 88, -20, 41, 75, -1, 30, 61, 18, 19, 48, + 37, 8, 34, 56, -1, 21, 75, -12, 7, 94, -23, -6, + -37, 50, 92, -18, 39, 79, 1, 28, 65, 20, 18, 52, + 40, 7, 38, 58, -3, 25, 77, -13, 11, 96, -24, -2, + -34, 49, 96, -16, 38, 83, 4, 27, 69, 23, 16, 56, + 42, 5, 42, 61, -4, 29, 79, -15, 15, 99, -26, 1, + -32, 47, 101, -13, 36, 88, 6, 25, 74, 25, 15, 60, + 45, 4, 47, 63, -6, 33, 82, -16, 20, 102, -27, 6, + -29, 46, 105, -11, 35, 92, 9, 24, 78, 28, 14, 64, + 47, 3, 51, 66, -7, 37, 85, -18, 24, 104, -29, 10, + -27, 44, 109, -8, 34, 96, 11, 23, 82, 30, 12, 68, + 49, 1, 55, 68, -8, 41, 87, -19, 28, 106, -30, 14, + -102, 91, -18, -83, 81, -32, -64, 70, -45, -45, 59, -59, + -26, 48, -73, -7, 38, -86, 12, 27, -99, 31, 16, -113, + -100, 90, -14, -81, 79, -28, -62, 68, -41, -43, 58, -55, + -24, 47, -69, -5, 36, -82, 14, 26, -95, 33, 15, -109, + -97, 89, -10, -79, 78, -24, -59, 67, -37, -41, 57, -51, + -21, 46, -65, -2, 35, -78, 16, 24, -91, 36, 13, -105, + -95, 87, -6, -76, 77, -19, -57, 66, -33, -38, 55, -46, + -18, 44, -60, 0, 33, -74, 19, 23, -87, 38, 12, -101, + -92, 86, -2, -74, 75, -15, -54, 64, -29, -35, 54, -42, + -16, 43, -56, 3, 32, -70, 21, 22, -83, 41, 11, -97, + -90, 84, 1, -71, 74, -11, -52, 63, -25, -33, 52, -38, + -14, 41, -52, 5, 31, -66, 24, 20, -79, 43, 9, -93, + -88, 83, 5, -69, 72, -7, -49, 62, -21, -31, 51, -34, + -11, 40, -48, 7, 29, -62, 26, 19, -75, 46, 8, -89, + -85, 82, 10, -66, 71, -3, -47, 60, -16, -28, 49, -30, + -9, 38, -44, 10, 28, -57, 29, 17, -70, 48, 6, -84, + -83, 80, 14, -64, 70, 0, -44, 59, -12, -26, 48, -26, + -6, 37, -40, 13, 27, -53, 31, 16, -66, 51, 5, -80, + -80, 79, 18, -61, 68, 4, -42, 57, -8, -23, 47, -22, + -4, 36, -36, 15, 25, -49, 34, 15, -62, 53, 4, -76, + -78, 78, 22, -59, 67, 8, -40, 56, -4, -21, 45, -18, + -1, 34, -32, 17, 24, -45, 36, 13, -58, 56, 2, -72, + -75, 76, 26, -57, 66, 12, -37, 55, 0, -18, 44, -14, + 1, 33, -28, 20, 22, -41, 39, 12, -54, 58, 1, -68, + -73, 75, 30, -54, 64, 17, -35, 53, 3, -16, 43, -9, + 4, 32, -23, 22, 21, -37, 41, 10, -50, 61, 0, -64, + -70, 73, 34, -51, 63, 21, -32, 52, 7, -13, 41, -5, + 6, 30, -19, 25, 20, -33, 44, 9, -46, 63, -1, -60, + -68, 72, 38, -49, 61, 25, -30, 50, 11, -11, 40, -1, + 8, 29, -15, 27, 18, -29, 46, 8, -42, 65, -2, -56, + -65, 71, 42, -47, 60, 29, -27, 49, 15, -9, 38, 2, + 11, 28, -11, 30, 17, -25, 48, 6, -38, 68, -4, -52, + -63, 69, 47, -44, 58, 33, -25, 48, 20, -6, 37, 6, + 14, 26, -7, 32, 15, -20, 51, 5, -33, 70, -5, -47, + -60, 68, 51, -42, 57, 37, -22, 46, 24, -3, 36, 10, + 16, 25, -3, 35, 14, -16, 53, 3, -29, 73, -6, -43, + -58, 66, 55, -39, 56, 41, -20, 45, 28, -1, 34, 14, + 18, 23, 0, 37, 13, -12, 56, 2, -25, 75, -8, -39, + -56, 65, 59, -37, 54, 45, -17, 43, 32, 1, 33, 18, + 21, 22, 4, 39, 11, -8, 58, 1, -21, 78, -9, -35, + -53, 64, 63, -34, 53, 50, -15, 42, 36, 4, 31, 23, + 23, 20, 9, 42, 10, -4, 61, 0, -17, 80, -11, -31, + -51, 62, 67, -32, 52, 54, -12, 41, 40, 6, 30, 27, + 26, 19, 13, 45, 8, 0, 63, -1, -13, 83, -12, -27, + -48, 61, 71, -29, 50, 58, -10, 39, 44, 9, 29, 31, + 28, 18, 17, 47, 7, 3, 66, -2, -9, 85, -13, -23, + -46, 59, 75, -27, 49, 62, -8, 38, 48, 11, 27, 35, + 31, 16, 21, 49, 6, 7, 68, -4, -5, 88, -15, -19, + -43, 58, 79, -25, 48, 66, -5, 37, 52, 14, 26, 39, + 33, 15, 25, 52, 4, 11, 71, -5, -1, 90, -16, -15, + -41, 57, 84, -22, 46, 70, -3, 35, 57, 16, 24, 43, + 36, 14, 29, 54, 3, 16, 73, -7, 3, 93, -18, -10, + -38, 55, 88, -19, 45, 74, 0, 34, 61, 19, 23, 47, + 38, 12, 33, 57, 2, 20, 76, -8, 7, 95, -19, -6, + -36, 54, 92, -17, 43, 78, 2, 32, 65, 21, 22, 51, + 40, 11, 37, 59, 0, 24, 78, -9, 11, 97, -20, -2, + -33, 53, 96, -15, 42, 82, 5, 31, 69, 23, 20, 55, + 43, 9, 41, 62, 0, 28, 80, -11, 15, 100, -22, 1, + -31, 51, 100, -12, 40, 87, 7, 29, 73, 26, 19, 60, + 46, 8, 46, 64, -2, 32, 83, -12, 19, 102, -23, 5, + -28, 50, 104, -10, 39, 91, 10, 28, 77, 29, 18, 64, + 48, 7, 50, 67, -3, 36, 85, -14, 23, 105, -25, 9, + -26, 48, 108, -7, 38, 95, 12, 27, 81, 31, 16, 68, + 50, 5, 54, 69, -4, 40, 88, -15, 27, 107, -26, 13, + -101, 95, -19, -83, 85, -32, -63, 74, -46, -44, 63, -59, + -25, 52, -73, -6, 42, -87, 13, 31, -100, 32, 20, -114, + -99, 94, -15, -80, 83, -28, -61, 72, -42, -42, 62, -55, + -23, 51, -69, -4, 40, -83, 15, 30, -96, 34, 19, -110, + -97, 93, -11, -78, 82, -24, -58, 71, -38, -40, 61, -51, + -20, 50, -65, -1, 39, -79, 17, 28, -92, 37, 17, -106, + -94, 91, -6, -75, 81, -20, -56, 70, -34, -37, 59, -47, + -18, 48, -61, 1, 37, -74, 20, 27, -88, 39, 16, -101, + -91, 90, -2, -73, 79, -16, -53, 68, -30, -35, 58, -43, + -15, 47, -57, 4, 36, -70, 22, 26, -84, 42, 15, -97, + -89, 88, 1, -70, 78, -12, -51, 67, -26, -32, 56, -39, + -13, 45, -53, 6, 35, -66, 25, 24, -80, 44, 13, -93, + -87, 87, 5, -68, 76, -8, -49, 66, -22, -30, 55, -35, + -10, 44, -49, 8, 33, -62, 27, 23, -76, 47, 12, -89, + -84, 86, 9, -65, 75, -3, -46, 64, -17, -27, 53, -30, + -8, 42, -44, 11, 32, -58, 30, 21, -71, 49, 10, -85, + -82, 84, 13, -63, 74, 0, -43, 63, -13, -25, 52, -26, + -5, 41, -40, 13, 31, -54, 32, 20, -67, 52, 9, -81, + -79, 83, 17, -60, 72, 4, -41, 61, -9, -22, 51, -22, + -3, 40, -36, 16, 29, -50, 35, 19, -63, 54, 8, -77, + -77, 82, 21, -58, 71, 8, -39, 60, -5, -20, 49, -18, + -1, 38, -32, 18, 28, -46, 37, 17, -59, 56, 6, -73, + -74, 80, 25, -56, 70, 12, -36, 59, -1, -17, 48, -14, + 2, 37, -28, 21, 26, -42, 39, 16, -55, 59, 5, -69, + -72, 79, 30, -53, 68, 16, -34, 57, 2, -15, 47, -10, + 5, 36, -24, 23, 25, -37, 42, 14, -51, 62, 3, -64, + -69, 77, 34, -51, 67, 20, -31, 56, 6, -12, 45, -6, + 7, 34, -20, 26, 24, -33, 45, 13, -47, 64, 2, -60, + -67, 76, 38, -48, 65, 24, -29, 54, 10, -10, 44, -2, + 9, 33, -16, 28, 22, -29, 47, 12, -43, 66, 1, -56, + -65, 75, 42, -46, 64, 28, -26, 53, 14, -8, 42, 1, + 12, 32, -12, 31, 21, -25, 49, 10, -39, 69, 0, -52, + -62, 73, 46, -43, 62, 33, -24, 52, 19, -5, 41, 6, + 14, 30, -7, 33, 19, -21, 52, 9, -34, 71, -1, -48, + -59, 72, 50, -41, 61, 37, -21, 50, 23, -3, 40, 10, + 17, 29, -3, 36, 18, -17, 54, 7, -30, 74, -2, -44, + -57, 70, 54, -38, 60, 41, -19, 49, 27, 0, 38, 14, + 19, 27, 0, 38, 17, -13, 57, 6, -26, 76, -4, -40, + -55, 69, 58, -36, 58, 45, -17, 47, 31, 2, 37, 18, + 22, 26, 4, 40, 15, -9, 59, 5, -22, 79, -5, -36, + -52, 68, 63, -33, 57, 49, -14, 46, 35, 5, 35, 22, + 24, 24, 8, 43, 14, -4, 62, 3, -18, 81, -7, -31, + -50, 66, 67, -31, 56, 53, -11, 45, 39, 7, 34, 26, + 27, 23, 12, 45, 12, 0, 64, 2, -14, 84, -8, -27, + -47, 65, 71, -28, 54, 57, -9, 43, 43, 10, 33, 30, + 29, 22, 16, 48, 11, 3, 67, 1, -10, 86, -9, -23, + -45, 63, 75, -26, 53, 61, -7, 42, 47, 12, 31, 34, + 31, 20, 20, 50, 10, 7, 69, 0, -6, 88, -11, -19, + -42, 62, 79, -24, 52, 65, -4, 41, 51, 14, 30, 38, + 34, 19, 24, 53, 8, 11, 71, -1, -2, 91, -12, -15, + -40, 61, 83, -21, 50, 70, -2, 39, 56, 17, 28, 43, + 37, 18, 29, 55, 7, 15, 74, -3, 2, 93, -14, -11, + -37, 59, 87, -19, 49, 74, 1, 38, 60, 20, 27, 47, + 39, 16, 33, 58, 6, 19, 77, -4, 6, 96, -15, -7, + -35, 58, 91, -16, 47, 78, 3, 36, 64, 22, 26, 51, + 41, 15, 37, 60, 4, 23, 79, -5, 10, 98, -16, -3, + -33, 57, 95, -14, 46, 82, 6, 35, 68, 24, 24, 55, + 44, 13, 41, 63, 3, 27, 81, -7, 14, 101, -18, 0, + -30, 55, 100, -11, 44, 86, 8, 33, 72, 27, 23, 59, + 46, 12, 45, 65, 1, 32, 84, -8, 18, 103, -19, 5, + -27, 54, 104, -9, 43, 90, 11, 32, 76, 29, 22, 63, + 49, 11, 49, 68, 0, 36, 86, -10, 22, 106, -21, 9, + -25, 52, 108, -6, 42, 94, 13, 31, 80, 32, 20, 67, + 51, 9, 53, 70, 0, 40, 89, -11, 26, 108, -22, 13, + -100, 100, -20, -82, 89, -33, -62, 78, -47, -43, 68, -60, + -24, 57, -74, -5, 46, -87, 14, 36, -101, 33, 25, -115, + -98, 99, -16, -79, 88, -29, -60, 77, -43, -41, 66, -56, + -22, 55, -70, -3, 45, -83, 16, 34, -97, 35, 23, -111, + -96, 97, -12, -77, 87, -25, -57, 76, -39, -39, 65, -52, + -19, 54, -66, 0, 43, -79, 18, 33, -93, 38, 22, -107, + -93, 96, -7, -74, 85, -20, -55, 74, -34, -36, 63, -48, + -17, 53, -62, 2, 42, -75, 21, 31, -88, 40, 20, -102, + -90, 94, -3, -72, 84, -16, -52, 73, -30, -34, 62, -44, + -14, 51, -58, 5, 41, -71, 23, 30, -84, 43, 19, -98, + -88, 93, 0, -69, 82, -12, -50, 71, -26, -31, 61, -40, + -12, 50, -54, 7, 39, -67, 26, 29, -80, 45, 18, -94, + -86, 92, 4, -67, 81, -8, -48, 70, -22, -29, 59, -36, + -9, 49, -50, 9, 38, -63, 28, 27, -76, 48, 16, -90, + -83, 90, 8, -64, 79, -4, -45, 69, -18, -26, 58, -31, + -7, 47, -45, 12, 36, -58, 31, 26, -72, 50, 15, -86, + -81, 89, 12, -62, 78, 0, -42, 67, -14, -24, 57, -27, + -4, 46, -41, 15, 35, -54, 33, 24, -68, 53, 14, -82, + -78, 87, 16, -59, 77, 3, -40, 66, -10, -21, 55, -23, + -2, 44, -37, 17, 34, -50, 36, 23, -64, 55, 12, -78, + -76, 86, 20, -57, 75, 7, -38, 64, -6, -19, 54, -19, + 1, 43, -33, 19, 32, -46, 38, 22, -60, 57, 11, -74, + -73, 85, 24, -55, 74, 11, -35, 63, -2, -16, 53, -15, + 3, 42, -29, 22, 31, -42, 40, 20, -56, 60, 9, -70, + -71, 83, 29, -52, 73, 16, -33, 62, 2, -14, 51, -11, + 6, 40, -25, 24, 29, -38, 43, 19, -51, 63, 8, -65, + -68, 82, 33, -50, 71, 20, -30, 60, 6, -11, 50, -7, + 8, 39, -21, 27, 28, -34, 46, 18, -47, 65, 7, -61, + -66, 80, 37, -47, 70, 24, -28, 59, 10, -9, 48, -3, + 10, 37, -17, 29, 27, -30, 48, 16, -43, 67, 5, -57, + -64, 79, 41, -45, 68, 28, -25, 58, 14, -7, 47, 0, + 13, 36, -13, 32, 25, -26, 50, 15, -39, 70, 4, -53, + -61, 78, 45, -42, 67, 32, -23, 56, 18, -4, 45, 5, + 15, 35, -8, 34, 24, -21, 53, 13, -35, 72, 2, -49, + -58, 76, 49, -40, 66, 36, -20, 55, 22, -2, 44, 9, + 18, 33, -4, 37, 23, -17, 55, 12, -31, 75, 1, -45, + -56, 75, 53, -37, 64, 40, -18, 53, 26, 1, 43, 13, + 20, 32, 0, 39, 21, -13, 58, 11, -27, 77, 0, -41, + -54, 74, 57, -35, 63, 44, -16, 52, 30, 3, 41, 17, + 23, 30, 3, 41, 20, -9, 60, 9, -23, 80, -1, -37, + -51, 72, 62, -32, 61, 49, -13, 50, 35, 6, 40, 21, + 25, 29, 7, 44, 18, -5, 63, 8, -18, 82, -2, -32, + -49, 71, 66, -30, 60, 53, -10, 49, 39, 8, 39, 25, + 28, 28, 11, 47, 17, -1, 65, 6, -14, 85, -4, -28, + -46, 69, 70, -27, 59, 57, -8, 48, 43, 11, 37, 29, + 30, 26, 15, 49, 16, 2, 68, 5, -10, 87, -5, -24, + -44, 68, 74, -25, 57, 61, -6, 46, 47, 13, 36, 33, + 33, 25, 19, 51, 14, 6, 70, 4, -6, 89, -6, -20, + -41, 67, 78, -23, 56, 65, -3, 45, 51, 16, 34, 37, + 35, 24, 23, 54, 13, 10, 72, 2, -2, 92, -8, -16, + -39, 65, 82, -20, 54, 69, -1, 44, 55, 18, 33, 42, + 38, 22, 28, 56, 11, 15, 75, 1, 1, 95, -9, -12, + -36, 64, 86, -18, 53, 73, 2, 42, 59, 21, 32, 46, + 40, 21, 32, 59, 10, 19, 78, 0, 5, 97, -10, -8, + -34, 62, 90, -15, 52, 77, 4, 41, 63, 23, 30, 50, + 42, 19, 36, 61, 9, 23, 80, -1, 9, 99, -12, -4, + -32, 61, 94, -13, 50, 81, 7, 40, 67, 25, 29, 54, + 45, 18, 40, 64, 7, 27, 82, -2, 13, 102, -13, 0, + -29, 60, 99, -10, 49, 86, 9, 38, 72, 28, 27, 58, + 47, 16, 44, 66, 6, 31, 85, -4, 18, 104, -15, 4, + -26, 58, 103, -8, 48, 90, 12, 37, 76, 30, 26, 62, + 50, 15, 48, 69, 5, 35, 87, -5, 22, 107, -16, 8, + -24, 57, 107, -5, 46, 94, 14, 35, 80, 33, 25, 66, + 52, 14, 52, 71, 3, 39, 90, -6, 26, 109, -17, 12, + -99, 104, -20, -81, 93, -34, -61, 82, -47, -42, 72, -61, + -23, 61, -75, -4, 50, -88, 14, 40, -101, 34, 29, -115, + -97, 103, -16, -78, 92, -30, -59, 81, -43, -40, 70, -57, + -21, 59, -71, -2, 49, -84, 17, 38, -97, 36, 27, -111, + -95, 101, -12, -76, 91, -26, -56, 80, -39, -38, 69, -53, + -18, 58, -67, 0, 47, -80, 19, 37, -93, 39, 26, -107, + -92, 100, -8, -73, 89, -21, -54, 78, -35, -35, 67, -48, + -16, 57, -62, 3, 46, -76, 22, 35, -89, 41, 24, -103, + -90, 98, -4, -71, 88, -17, -51, 77, -31, -33, 66, -44, + -13, 55, -58, 6, 45, -72, 24, 34, -85, 44, 23, -99, + -87, 97, 0, -68, 86, -13, -49, 75, -27, -30, 65, -40, + -11, 54, -54, 8, 43, -68, 27, 33, -81, 46, 22, -95, + -85, 96, 3, -66, 85, -9, -47, 74, -23, -28, 63, -36, + -8, 53, -50, 10, 42, -64, 29, 31, -77, 48, 20, -91, + -82, 94, 8, -63, 83, -5, -44, 73, -18, -25, 62, -32, + -6, 51, -46, 13, 40, -59, 32, 30, -72, 51, 19, -86, + -80, 93, 12, -61, 82, -1, -42, 71, -14, -23, 61, -28, + -3, 50, -42, 15, 39, -55, 34, 28, -68, 54, 18, -82, + -77, 91, 16, -58, 81, 2, -39, 70, -10, -20, 59, -24, + -1, 48, -38, 18, 38, -51, 37, 27, -64, 56, 16, -78, + -75, 90, 20, -56, 79, 6, -37, 68, -6, -18, 58, -20, + 1, 47, -34, 20, 36, -47, 39, 26, -60, 58, 15, -74, + -72, 89, 24, -54, 78, 10, -34, 67, -2, -16, 57, -16, + 4, 46, -30, 23, 35, -43, 41, 24, -56, 61, 13, -70, + -70, 87, 28, -51, 77, 15, -32, 66, 1, -13, 55, -11, + 7, 44, -25, 25, 33, -39, 44, 23, -52, 63, 12, -66, + -67, 86, 32, -49, 75, 19, -29, 64, 5, -10, 54, -7, + 9, 43, -21, 28, 32, -35, 46, 22, -48, 66, 11, -62, + -65, 84, 36, -46, 74, 23, -27, 63, 9, -8, 52, -3, + 11, 41, -17, 30, 31, -31, 49, 20, -44, 68, 9, -58, + -63, 83, 40, -44, 72, 27, -24, 62, 13, -6, 51, 0, + 14, 40, -13, 32, 29, -27, 51, 19, -40, 71, 8, -54, + -60, 82, 45, -41, 71, 31, -22, 60, 18, -3, 49, 4, + 16, 39, -9, 35, 28, -22, 54, 17, -35, 73, 6, -49, + -58, 80, 49, -39, 70, 35, -19, 59, 22, -1, 48, 8, + 19, 37, -5, 38, 27, -18, 56, 16, -31, 76, 5, -45, + -55, 79, 53, -36, 68, 39, -17, 57, 26, 2, 47, 12, + 21, 36, -1, 40, 25, -14, 59, 15, -27, 78, 4, -41, + -53, 78, 57, -34, 67, 43, -15, 56, 30, 4, 45, 16, + 24, 34, 2, 42, 24, -10, 61, 13, -23, 80, 2, -37, + -50, 76, 61, -31, 65, 48, -12, 54, 34, 7, 44, 21, + 26, 33, 7, 45, 22, -6, 64, 12, -19, 83, 1, -33, + -48, 75, 65, -29, 64, 52, -10, 53, 38, 9, 43, 25, + 29, 32, 11, 47, 21, -2, 66, 10, -15, 86, 0, -29, + -45, 73, 69, -27, 63, 56, -7, 52, 42, 12, 41, 29, + 31, 30, 15, 50, 20, 1, 69, 9, -11, 88, -1, -25, + -43, 72, 73, -24, 61, 60, -5, 50, 46, 14, 40, 33, + 33, 29, 19, 52, 18, 5, 71, 8, -7, 90, -2, -21, + -41, 71, 77, -22, 60, 64, -2, 49, 50, 16, 38, 37, + 36, 28, 23, 55, 17, 9, 73, 6, -3, 93, -4, -17, + -38, 69, 82, -19, 58, 68, 0, 48, 55, 19, 37, 41, + 38, 26, 27, 57, 15, 14, 76, 5, 1, 95, -5, -12, + -35, 68, 86, -17, 57, 72, 3, 46, 59, 22, 36, 45, + 41, 25, 31, 60, 14, 18, 78, 3, 5, 98, -6, -8, + -33, 66, 90, -14, 56, 76, 5, 45, 63, 24, 34, 49, + 43, 23, 35, 62, 13, 22, 81, 2, 9, 100, -8, -4, + -31, 65, 94, -12, 54, 80, 8, 44, 67, 26, 33, 53, + 46, 22, 39, 64, 11, 26, 83, 1, 13, 103, -9, 0, + -28, 64, 98, -9, 53, 85, 10, 42, 71, 29, 31, 58, + 48, 20, 44, 67, 10, 30, 86, 0, 17, 105, -11, 3, + -26, 62, 102, -7, 52, 89, 13, 41, 75, 31, 30, 62, + 51, 19, 48, 70, 9, 34, 88, -1, 21, 108, -12, 7, + -23, 61, 106, -4, 50, 93, 15, 39, 79, 34, 29, 66, + 53, 18, 52, 72, 7, 38, 91, -2, 25, 110, -13, 11, + -98, 108, -21, -80, 97, -34, -60, 86, -48, -42, 76, -62, + -22, 65, -75, -3, 54, -89, 15, 44, -102, 35, 33, -116, + -96, 107, -17, -77, 96, -30, -58, 85, -44, -39, 74, -58, + -20, 63, -71, -1, 53, -85, 18, 42, -98, 37, 31, -112, + -94, 105, -13, -75, 95, -26, -56, 84, -40, -37, 73, -54, + -17, 62, -67, 1, 51, -81, 20, 41, -94, 40, 30, -108, + -91, 104, -8, -72, 93, -22, -53, 82, -36, -34, 71, -49, + -15, 61, -63, 4, 50, -76, 23, 39, -90, 42, 28, -103, + -89, 102, -4, -70, 92, -18, -50, 81, -32, -32, 70, -45, + -12, 59, -59, 6, 49, -72, 25, 38, -86, 45, 27, -99, + -86, 101, 0, -67, 90, -14, -48, 79, -28, -29, 69, -41, + -10, 58, -55, 9, 47, -68, 28, 37, -82, 47, 26, -95, + -84, 100, 3, -65, 89, -10, -46, 78, -24, -27, 67, -37, + -8, 57, -51, 11, 46, -64, 30, 35, -78, 49, 24, -91, + -81, 98, 7, -62, 87, -5, -43, 77, -19, -24, 66, -33, + -5, 55, -46, 14, 44, -60, 33, 34, -73, 52, 23, -87, + -79, 97, 11, -60, 86, -1, -41, 75, -15, -22, 65, -29, + -2, 54, -42, 16, 43, -56, 35, 32, -69, 54, 22, -83, + -76, 95, 15, -58, 85, 2, -38, 74, -11, -19, 63, -25, + 0, 52, -38, 19, 42, -52, 38, 31, -65, 57, 20, -79, + -74, 94, 19, -55, 83, 6, -36, 72, -7, -17, 62, -21, + 2, 51, -34, 21, 40, -48, 40, 30, -61, 59, 19, -75, + -72, 93, 23, -53, 82, 10, -33, 71, -3, -15, 61, -17, + 5, 50, -30, 24, 39, -44, 42, 28, -57, 62, 17, -71, + -69, 91, 28, -50, 81, 14, -31, 70, 0, -12, 59, -12, + 7, 48, -26, 26, 37, -39, 45, 27, -53, 64, 16, -66, + -67, 90, 32, -48, 79, 18, -28, 68, 4, -10, 58, -8, + 10, 47, -22, 29, 36, -35, 47, 26, -49, 67, 15, -62, + -64, 88, 36, -45, 78, 22, -26, 67, 8, -7, 56, -4, + 12, 45, -18, 31, 35, -31, 50, 24, -45, 69, 13, -58, + -62, 87, 40, -43, 76, 26, -24, 66, 12, -5, 55, 0, + 15, 44, -14, 33, 33, -27, 52, 23, -41, 72, 12, -54, + -59, 86, 44, -40, 75, 31, -21, 64, 17, -2, 53, 3, + 17, 43, -9, 36, 32, -23, 55, 21, -36, 74, 10, -50, + -57, 84, 48, -38, 74, 35, -18, 63, 21, 0, 52, 7, + 20, 41, -5, 38, 31, -19, 57, 20, -32, 77, 9, -46, + -54, 83, 52, -35, 72, 39, -16, 61, 25, 3, 51, 11, + 22, 40, -1, 41, 29, -15, 60, 19, -28, 79, 8, -42, + -52, 82, 56, -33, 71, 43, -14, 60, 29, 5, 49, 15, + 24, 38, 2, 43, 28, -11, 62, 17, -24, 81, 6, -38, + -49, 80, 61, -30, 69, 47, -11, 58, 33, 8, 48, 20, + 27, 37, 6, 46, 26, -6, 65, 16, -20, 84, 5, -33, + -47, 79, 65, -28, 68, 51, -9, 57, 37, 10, 47, 24, + 30, 36, 10, 48, 25, -2, 67, 14, -16, 86, 3, -29, + -44, 77, 69, -26, 67, 55, -6, 56, 41, 13, 45, 28, + 32, 34, 14, 51, 24, 1, 70, 13, -12, 89, 2, -25, + -42, 76, 73, -23, 65, 59, -4, 54, 45, 15, 44, 32, + 34, 33, 18, 53, 22, 5, 72, 12, -8, 91, 1, -21, + -40, 75, 77, -21, 64, 63, -1, 53, 49, 17, 42, 36, + 37, 32, 22, 56, 21, 9, 74, 10, -4, 94, 0, -17, + -37, 73, 81, -18, 62, 68, 1, 52, 54, 20, 41, 40, + 39, 30, 27, 58, 19, 13, 77, 9, 0, 96, -1, -13, + -35, 72, 85, -16, 61, 72, 4, 50, 58, 22, 40, 44, + 42, 29, 31, 61, 18, 17, 79, 7, 4, 99, -2, -9, + -32, 70, 89, -13, 60, 76, 6, 49, 62, 25, 38, 48, + 44, 27, 35, 63, 17, 21, 82, 6, 8, 101, -4, -5, + -30, 69, 93, -11, 58, 80, 8, 48, 66, 27, 37, 52, + 47, 26, 39, 65, 15, 25, 84, 5, 12, 104, -5, -1, + -27, 68, 98, -8, 57, 84, 11, 46, 70, 30, 35, 57, + 49, 24, 43, 68, 14, 30, 87, 3, 16, 106, -7, 3, + -25, 66, 102, -6, 56, 88, 14, 45, 74, 32, 34, 61, + 52, 23, 47, 70, 13, 34, 89, 2, 20, 109, -8, 7, + -22, 65, 106, -3, 54, 92, 16, 43, 78, 35, 33, 65, + 54, 22, 51, 73, 11, 38, 92, 1, 24, 111, -9, 11, + -98, 112, -22, -79, 101, -35, -59, 90, -49, -41, 80, -62, + -21, 69, -76, -2, 58, -89, 16, 48, -103, 36, 37, -117, + -95, 111, -18, -76, 100, -31, -57, 89, -45, -38, 78, -58, + -19, 67, -72, 0, 57, -85, 19, 46, -99, 38, 35, -113, + -93, 109, -14, -74, 99, -27, -55, 88, -41, -36, 77, -54, + -16, 66, -68, 2, 55, -81, 21, 45, -95, 40, 34, -109, + -90, 108, -9, -71, 97, -22, -52, 86, -36, -33, 75, -50, + -14, 65, -63, 5, 54, -77, 24, 43, -90, 43, 32, -104, + -88, 106, -5, -69, 96, -18, -50, 85, -32, -31, 74, -46, + -11, 63, -59, 7, 53, -73, 26, 42, -86, 46, 31, -100, + -85, 105, -1, -67, 94, -14, -47, 83, -28, -28, 73, -42, + -9, 62, -55, 10, 51, -69, 29, 41, -82, 48, 30, -96, + -83, 104, 2, -64, 93, -10, -45, 82, -24, -26, 71, -38, + -7, 61, -51, 12, 50, -65, 31, 39, -78, 50, 28, -92, + -80, 102, 6, -61, 91, -6, -42, 81, -20, -23, 70, -33, + -4, 59, -47, 15, 48, -60, 34, 38, -74, 53, 27, -88, + -78, 101, 10, -59, 90, -2, -40, 79, -16, -21, 69, -29, + -2, 58, -43, 17, 47, -56, 36, 36, -70, 55, 26, -84, + -75, 99, 14, -57, 89, 1, -37, 78, -12, -19, 67, -25, + 1, 56, -39, 20, 46, -52, 38, 35, -66, 58, 24, -80, + -73, 98, 18, -54, 87, 5, -35, 76, -8, -16, 66, -21, + 3, 55, -35, 22, 44, -48, 41, 34, -62, 60, 23, -76, + -71, 97, 22, -52, 86, 9, -33, 75, -4, -14, 65, -17, + 6, 54, -31, 24, 43, -44, 43, 32, -58, 63, 21, -72, + -68, 95, 27, -49, 85, 14, -30, 74, 0, -11, 63, -13, + 8, 52, -26, 27, 41, -40, 46, 31, -53, 65, 20, -67, + -66, 94, 31, -47, 83, 18, -27, 72, 4, -9, 62, -9, + 11, 51, -22, 30, 40, -36, 48, 30, -49, 68, 19, -63, + -63, 92, 35, -44, 82, 22, -25, 71, 8, -6, 60, -5, + 13, 49, -18, 32, 39, -32, 51, 28, -45, 70, 17, -59, + -61, 91, 39, -42, 80, 26, -23, 70, 12, -4, 59, -1, + 16, 48, -14, 34, 37, -28, 53, 27, -41, 72, 16, -55, + -58, 90, 43, -39, 79, 30, -20, 68, 16, -1, 57, 3, + 18, 47, -10, 37, 36, -23, 56, 25, -37, 75, 14, -51, + -56, 88, 47, -37, 78, 34, -18, 67, 20, 1, 56, 7, + 21, 45, -6, 39, 35, -19, 58, 24, -33, 78, 13, -47, + -53, 87, 51, -35, 76, 38, -15, 65, 24, 4, 55, 11, + 23, 44, -2, 42, 33, -15, 61, 23, -29, 80, 12, -43, + -51, 86, 55, -32, 75, 42, -13, 64, 28, 6, 53, 15, + 25, 42, 1, 44, 32, -11, 63, 21, -25, 82, 10, -39, + -48, 84, 60, -29, 73, 47, -10, 62, 33, 9, 52, 19, + 28, 41, 6, 47, 30, -7, 66, 20, -20, 85, 9, -34, + -46, 83, 64, -27, 72, 51, -8, 61, 37, 11, 51, 23, + 30, 40, 10, 49, 29, -3, 68, 18, -16, 87, 7, -30, + -43, 81, 68, -25, 71, 55, -5, 60, 41, 13, 49, 27, + 33, 38, 14, 52, 28, 0, 70, 17, -12, 90, 6, -26, + -41, 80, 72, -22, 69, 59, -3, 58, 45, 16, 48, 31, + 35, 37, 18, 54, 26, 4, 73, 16, -8, 92, 5, -22, + -39, 79, 76, -20, 68, 63, -1, 57, 49, 18, 46, 35, + 38, 36, 22, 56, 25, 8, 75, 14, -4, 95, 3, -18, + -36, 77, 80, -17, 66, 67, 2, 56, 53, 21, 45, 40, + 40, 34, 26, 59, 23, 13, 78, 13, 0, 97, 2, -14, + -34, 76, 84, -15, 65, 71, 5, 54, 57, 23, 44, 44, + 43, 33, 30, 61, 22, 17, 80, 11, 3, 100, 1, -10, + -31, 74, 88, -12, 64, 75, 7, 53, 61, 26, 42, 48, + 45, 31, 34, 64, 21, 21, 83, 10, 7, 102, 0, -6, + -29, 73, 92, -10, 62, 79, 9, 52, 65, 28, 41, 52, + 47, 30, 38, 66, 19, 25, 85, 9, 11, 104, -1, -2, + -26, 72, 97, -7, 61, 84, 12, 50, 70, 31, 39, 56, + 50, 28, 43, 69, 18, 29, 88, 7, 16, 107, -3, 2, + -24, 70, 101, -5, 60, 88, 14, 49, 74, 33, 38, 60, + 53, 27, 47, 71, 17, 33, 90, 6, 20, 110, -4, 6, + -21, 69, 105, -3, 58, 92, 17, 47, 78, 36, 37, 64, + 55, 26, 51, 74, 15, 37, 93, 5, 24, 112, -5, 10, + -97, 116, -22, -78, 106, -36, -58, 95, -49, -40, 84, -63, + -20, 73, -77, -1, 63, -90, 17, 52, -104, 37, 41, -117, + -94, 115, -18, -75, 104, -32, -56, 93, -45, -37, 83, -59, + -18, 72, -73, 1, 61, -86, 20, 51, -100, 39, 40, -113, + -92, 114, -14, -73, 103, -28, -54, 92, -41, -35, 82, -55, + -15, 71, -69, 3, 60, -82, 22, 49, -96, 41, 38, -109, + -89, 112, -10, -70, 102, -23, -51, 91, -37, -32, 80, -50, + -13, 69, -64, 6, 58, -78, 25, 48, -91, 44, 37, -105, + -87, 111, -6, -68, 100, -19, -49, 89, -33, -30, 79, -46, + -10, 68, -60, 8, 57, -74, 27, 47, -87, 47, 36, -101, + -84, 109, -2, -66, 99, -15, -46, 88, -29, -27, 77, -42, + -8, 66, -56, 11, 56, -70, 30, 45, -83, 49, 34, -97, + -82, 108, 1, -63, 97, -11, -44, 87, -25, -25, 76, -38, + -6, 65, -52, 13, 54, -66, 32, 44, -79, 51, 33, -93, + -79, 107, 6, -60, 96, -7, -41, 85, -20, -22, 74, -34, + -3, 63, -48, 16, 53, -61, 35, 42, -75, 54, 31, -88, + -77, 105, 10, -58, 95, -3, -39, 84, -16, -20, 73, -30, + -1, 62, -44, 18, 52, -57, 37, 41, -71, 56, 30, -84, + -74, 104, 14, -56, 93, 0, -36, 82, -12, -17, 72, -26, + 2, 61, -40, 21, 50, -53, 39, 40, -67, 59, 29, -80, + -72, 103, 18, -53, 92, 4, -34, 81, -8, -15, 70, -22, + 4, 59, -36, 23, 49, -49, 42, 38, -63, 61, 27, -76, + -70, 101, 22, -51, 91, 8, -31, 80, -4, -13, 69, -18, + 7, 58, -32, 25, 47, -45, 44, 37, -59, 64, 26, -72, + -67, 100, 26, -48, 89, 13, -29, 78, 0, -10, 68, -13, + 9, 57, -27, 28, 46, -41, 47, 35, -54, 66, 24, -68, + -65, 98, 30, -46, 88, 17, -26, 77, 3, -8, 66, -9, + 12, 55, -23, 31, 45, -37, 49, 34, -50, 69, 23, -64, + -62, 97, 34, -43, 86, 21, -24, 75, 7, -5, 65, -5, + 14, 54, -19, 33, 43, -33, 52, 33, -46, 71, 22, -60, + -60, 96, 38, -41, 85, 25, -22, 74, 11, -3, 63, -1, + 17, 53, -15, 35, 42, -29, 54, 31, -42, 73, 20, -56, + -57, 94, 43, -38, 83, 29, -19, 73, 16, 0, 62, 2, + 19, 51, -11, 38, 40, -24, 57, 30, -38, 76, 19, -51, + -55, 93, 47, -36, 82, 33, -17, 71, 20, 2, 61, 6, + 22, 50, -7, 40, 39, -20, 59, 28, -34, 79, 18, -47, + -52, 91, 51, -34, 81, 37, -14, 70, 24, 5, 59, 10, + 24, 48, -3, 43, 38, -16, 62, 27, -30, 81, 16, -43, + -50, 90, 55, -31, 79, 41, -12, 68, 28, 7, 58, 14, + 26, 47, 0, 45, 36, -12, 64, 26, -26, 83, 15, -39, + -47, 89, 59, -28, 78, 46, -9, 67, 32, 10, 56, 19, + 29, 45, 5, 48, 35, -8, 67, 24, -21, 86, 13, -35, + -45, 87, 63, -26, 77, 50, -7, 66, 36, 12, 55, 23, + 31, 44, 9, 50, 33, -4, 69, 23, -17, 88, 12, -31, + -42, 86, 67, -24, 75, 54, -4, 64, 40, 15, 54, 27, + 34, 43, 13, 53, 32, 0, 71, 22, -13, 91, 11, -27, + -40, 84, 71, -21, 74, 58, -2, 63, 44, 17, 52, 31, + 36, 41, 17, 55, 31, 3, 74, 20, -9, 93, 9, -23, + -38, 83, 75, -19, 73, 62, 1, 62, 48, 19, 51, 35, + 39, 40, 21, 57, 29, 7, 76, 19, -5, 96, 8, -19, + -35, 82, 80, -16, 71, 66, 3, 60, 53, 22, 49, 39, + 41, 39, 25, 60, 28, 12, 79, 17, -1, 98, 6, -14, + -33, 80, 84, -14, 70, 70, 6, 59, 57, 24, 48, 43, + 44, 37, 29, 63, 27, 16, 81, 16, 2, 101, 5, -10, + -30, 79, 88, -11, 68, 74, 8, 57, 61, 27, 47, 47, + 46, 36, 33, 65, 25, 20, 84, 15, 6, 103, 4, -6, + -28, 78, 92, -9, 67, 78, 10, 56, 65, 29, 45, 51, + 49, 34, 37, 67, 24, 24, 86, 13, 10, 105, 2, -2, + -25, 76, 96, -6, 65, 83, 13, 54, 69, 32, 44, 56, + 51, 33, 42, 70, 22, 28, 89, 12, 15, 108, 1, 1, + -23, 75, 100, -4, 64, 87, 15, 53, 73, 34, 43, 60, + 54, 32, 46, 72, 21, 32, 91, 10, 19, 111, 0, 5, + -20, 73, 104, -2, 63, 91, 18, 52, 77, 37, 41, 64, + 56, 30, 50, 75, 20, 36, 94, 9, 23, 113, -1, 9, + -96, 120, -23, -77, 110, -36, -57, 99, -50, -39, 88, -64, + -19, 77, -77, -1, 67, -91, 18, 56, -104, 38, 45, -118, + -93, 119, -19, -74, 108, -32, -55, 97, -46, -36, 87, -60, + -17, 76, -73, 2, 65, -87, 21, 55, -100, 40, 44, -114, + -91, 118, -15, -72, 107, -28, -53, 96, -42, -34, 86, -56, + -15, 75, -69, 4, 64, -83, 23, 53, -96, 42, 42, -110, + -88, 116, -10, -69, 106, -24, -50, 95, -38, -31, 84, -51, + -12, 73, -65, 7, 62, -78, 26, 52, -92, 45, 41, -105, + -86, 115, -6, -67, 104, -20, -48, 93, -34, -29, 83, -47, + -9, 72, -61, 9, 61, -74, 28, 51, -88, 47, 40, -101, + -83, 113, -2, -65, 103, -16, -45, 92, -30, -26, 81, -43, + -7, 70, -57, 12, 60, -70, 30, 49, -84, 50, 38, -97, + -81, 112, 1, -62, 101, -12, -43, 91, -26, -24, 80, -39, + -5, 69, -53, 14, 58, -66, 33, 48, -80, 52, 37, -93, + -78, 111, 5, -60, 100, -7, -40, 89, -21, -21, 78, -35, + -2, 67, -48, 17, 57, -62, 36, 46, -75, 55, 35, -89, + -76, 109, 9, -57, 99, -3, -38, 88, -17, -19, 77, -31, + 0, 66, -44, 19, 56, -58, 38, 45, -71, 57, 34, -85, + -74, 108, 13, -55, 97, 0, -35, 86, -13, -17, 76, -27, + 3, 65, -40, 22, 54, -54, 40, 44, -67, 60, 33, -81, + -71, 107, 17, -52, 96, 4, -33, 85, -9, -14, 74, -23, + 5, 63, -36, 24, 53, -50, 43, 42, -63, 62, 31, -77, + -69, 105, 21, -50, 95, 8, -31, 84, -5, -12, 73, -19, + 8, 62, -32, 26, 51, -46, 45, 41, -59, 65, 30, -73, + -66, 104, 26, -47, 93, 12, -28, 82, -1, -9, 72, -14, + 10, 61, -28, 29, 50, -41, 48, 39, -55, 67, 28, -68, + -64, 102, 30, -45, 92, 16, -25, 81, 2, -7, 70, -10, + 13, 59, -24, 31, 49, -37, 50, 38, -51, 70, 27, -64, + -61, 101, 34, -42, 90, 20, -23, 79, 6, -4, 69, -6, + 15, 58, -20, 34, 47, -33, 53, 37, -47, 72, 26, -60, + -59, 100, 38, -40, 89, 24, -21, 78, 10, -2, 67, -2, + 17, 57, -16, 36, 46, -29, 55, 35, -43, 74, 24, -56, + -56, 98, 42, -37, 87, 29, -18, 77, 15, 1, 66, 1, + 20, 55, -11, 39, 44, -25, 58, 34, -38, 77, 23, -52, + -54, 97, 46, -35, 86, 33, -16, 75, 19, 3, 65, 5, + 23, 54, -7, 41, 43, -21, 60, 32, -34, 79, 22, -48, + -51, 95, 50, -33, 85, 37, -13, 74, 23, 6, 63, 9, + 25, 52, -3, 44, 42, -17, 62, 31, -30, 82, 20, -44, + -49, 94, 54, -30, 83, 41, -11, 72, 27, 8, 62, 13, + 27, 51, 0, 46, 40, -13, 65, 30, -26, 84, 19, -40, + -46, 93, 59, -28, 82, 45, -8, 71, 31, 11, 60, 18, + 30, 49, 4, 49, 39, -8, 68, 28, -22, 87, 17, -35, + -44, 91, 63, -25, 81, 49, -6, 70, 35, 13, 59, 22, + 32, 48, 8, 51, 37, -4, 70, 27, -18, 89, 16, -31, + -42, 90, 67, -23, 79, 53, -3, 68, 39, 15, 58, 26, + 35, 47, 12, 54, 36, 0, 72, 26, -14, 92, 15, -27, + -39, 88, 71, -20, 78, 57, -1, 67, 43, 18, 56, 30, + 37, 45, 16, 56, 35, 3, 75, 24, -10, 94, 13, -23, + -37, 87, 75, -18, 77, 61, 1, 66, 47, 20, 55, 34, + 40, 44, 20, 58, 33, 7, 77, 23, -6, 97, 12, -19, + -34, 86, 79, -15, 75, 66, 4, 64, 52, 23, 53, 38, + 42, 43, 25, 61, 32, 11, 80, 21, -1, 99, 10, -15, + -32, 84, 83, -13, 74, 70, 6, 63, 56, 25, 52, 42, + 45, 41, 29, 63, 31, 15, 82, 20, 2, 102, 9, -11, + -29, 83, 87, -10, 72, 74, 9, 61, 60, 28, 51, 46, + 47, 40, 33, 66, 29, 19, 85, 19, 6, 104, 8, -7, + -27, 82, 91, -8, 71, 78, 11, 60, 64, 30, 49, 50, + 49, 38, 37, 68, 28, 23, 87, 17, 10, 106, 6, -3, + -24, 80, 96, -5, 69, 82, 14, 58, 68, 33, 48, 55, + 52, 37, 41, 71, 26, 28, 90, 16, 14, 109, 5, 1, + -22, 79, 100, -3, 68, 86, 16, 57, 72, 35, 47, 59, + 55, 36, 45, 73, 25, 32, 92, 14, 18, 111, 3, 5, + -19, 77, 104, -1, 67, 90, 19, 56, 76, 38, 45, 63, + 57, 34, 49, 76, 24, 36, 94, 13, 22, 114, 2, 9, + -95, 124, -24, -76, 114, -37, -57, 103, -51, -38, 92, -64, + -18, 81, -78, 0, 71, -91, 19, 60, -105, 39, 49, -119, + -92, 123, -20, -74, 112, -33, -54, 101, -47, -35, 91, -60, + -16, 80, -74, 3, 69, -87, 22, 59, -101, 41, 48, -115, + -90, 122, -16, -71, 111, -29, -52, 100, -43, -33, 90, -56, + -14, 79, -70, 5, 68, -83, 24, 57, -97, 43, 46, -111, + -87, 120, -11, -68, 110, -24, -49, 99, -38, -30, 88, -52, + -11, 77, -66, 8, 66, -79, 27, 56, -92, 46, 45, -106, + -85, 119, -7, -66, 108, -20, -47, 97, -34, -28, 87, -48, + -9, 76, -62, 10, 65, -75, 29, 55, -88, 48, 44, -102, + -82, 117, -3, -64, 107, -16, -44, 96, -30, -26, 85, -44, + -6, 74, -58, 13, 64, -71, 31, 53, -84, 51, 42, -98, + -80, 116, 0, -61, 105, -12, -42, 95, -26, -23, 84, -40, + -4, 73, -54, 15, 62, -67, 34, 52, -80, 53, 41, -94, + -77, 115, 4, -59, 104, -8, -39, 93, -22, -20, 82, -35, + -1, 71, -49, 18, 61, -62, 36, 50, -76, 56, 39, -90, + -75, 113, 8, -56, 103, -4, -37, 92, -18, -18, 81, -31, + 1, 70, -45, 20, 60, -58, 39, 49, -72, 58, 38, -86, + -73, 112, 12, -54, 101, 0, -34, 90, -14, -16, 80, -27, + 4, 69, -41, 22, 58, -54, 41, 48, -68, 61, 37, -82, + -70, 111, 16, -51, 100, 3, -32, 89, -10, -13, 78, -23, + 6, 67, -37, 25, 57, -50, 44, 46, -64, 63, 35, -78, + -68, 109, 20, -49, 99, 7, -30, 88, -6, -11, 77, -19, + 8, 66, -33, 27, 55, -46, 46, 45, -60, 65, 34, -74, + -65, 108, 25, -46, 97, 12, -27, 86, -1, -8, 76, -15, + 11, 65, -29, 30, 54, -42, 49, 43, -55, 68, 32, -69, + -63, 106, 29, -44, 96, 16, -25, 85, 2, -6, 74, -11, + 14, 63, -25, 32, 53, -38, 51, 42, -51, 71, 31, -65, + -60, 105, 33, -42, 94, 20, -22, 83, 6, -3, 73, -7, + 16, 62, -21, 35, 51, -34, 54, 41, -47, 73, 30, -61, + -58, 104, 37, -39, 93, 24, -20, 82, 10, -1, 71, -3, + 18, 61, -17, 37, 50, -30, 56, 39, -43, 75, 28, -57, + -55, 102, 41, -36, 91, 28, -17, 81, 14, 2, 70, 1, + 21, 59, -12, 40, 48, -25, 59, 38, -39, 78, 27, -53, + -53, 101, 45, -34, 90, 32, -15, 79, 18, 4, 69, 5, + 23, 58, -8, 42, 47, -21, 61, 36, -35, 80, 26, -49, + -50, 99, 49, -32, 89, 36, -12, 78, 22, 6, 67, 9, + 26, 56, -4, 45, 46, -17, 63, 35, -31, 83, 24, -45, + -48, 98, 53, -29, 87, 40, -10, 76, 26, 9, 66, 13, + 28, 55, 0, 47, 44, -13, 66, 34, -27, 85, 23, -41, + -45, 97, 58, -27, 86, 45, -7, 75, 31, 12, 64, 17, + 31, 53, 3, 50, 43, -9, 68, 32, -22, 88, 21, -36, + -43, 95, 62, -24, 85, 49, -5, 74, 35, 14, 63, 21, + 33, 52, 7, 52, 41, -5, 71, 31, -18, 90, 20, -32, + -41, 94, 66, -22, 83, 53, -2, 72, 39, 16, 62, 25, + 36, 51, 11, 54, 40, -1, 73, 30, -14, 93, 19, -28, + -38, 92, 70, -19, 82, 57, 0, 71, 43, 19, 60, 29, + 38, 49, 15, 57, 39, 2, 76, 28, -10, 95, 17, -24, + -36, 91, 74, -17, 81, 61, 2, 70, 47, 21, 59, 33, + 40, 48, 19, 59, 37, 6, 78, 27, -6, 97, 16, -20, + -33, 90, 78, -14, 79, 65, 5, 68, 51, 24, 57, 38, + 43, 47, 24, 62, 36, 11, 81, 25, -2, 100, 14, -16, + -31, 88, 82, -12, 78, 69, 7, 67, 55, 26, 56, 42, + 46, 45, 28, 64, 35, 15, 83, 24, 1, 103, 13, -12, + -28, 87, 86, -10, 76, 73, 10, 65, 59, 29, 55, 46, + 48, 44, 32, 67, 33, 19, 86, 23, 5, 105, 12, -8, + -26, 86, 90, -7, 75, 77, 12, 64, 63, 31, 53, 50, + 50, 42, 36, 69, 32, 23, 88, 21, 9, 107, 10, -4, + -23, 84, 95, -4, 73, 82, 15, 62, 68, 34, 52, 54, + 53, 41, 40, 72, 30, 27, 91, 20, 14, 110, 9, 0, + -21, 83, 99, -2, 72, 86, 17, 61, 72, 36, 51, 58, + 55, 40, 44, 74, 29, 31, 93, 18, 18, 112, 7, 4, + -18, 81, 103, 0, 71, 90, 20, 60, 76, 38, 49, 62, + 58, 38, 48, 77, 28, 35, 95, 17, 22, 115, 6, 8, + -121, -3, -5, -102, -14, -18, -83, -25, -32, -65, -36, -45, + -45, -47, -59, -26, -57, -72, -8, -68, -86, 12, -79, -100, + -119, -5, -1, -100, -16, -14, -81, -26, -28, -62, -37, -41, + -43, -48, -55, -24, -58, -68, -5, -69, -82, 14, -80, -96, + -117, -6, 2, -97, -17, -10, -79, -28, -24, -60, -38, -37, + -40, -49, -51, -22, -60, -64, -3, -70, -78, 17, -81, -92, + -114, -8, 7, -95, -19, -6, -76, -29, -19, -57, -40, -33, + -38, -51, -46, -19, -61, -60, 0, -72, -73, 19, -83, -87, + -112, -9, 11, -92, -20, -2, -73, -31, -15, -55, -41, -29, + -35, -52, -42, -16, -63, -56, 2, -73, -69, 22, -84, -83, + -109, -10, 15, -90, -21, 1, -71, -32, -11, -52, -43, -25, + -33, -53, -38, -14, -64, -52, 5, -75, -65, 24, -86, -79, + -107, -12, 19, -87, -23, 5, -69, -33, -7, -50, -44, -21, + -30, -55, -34, -12, -65, -48, 7, -76, -61, 26, -87, -75, + -104, -13, 23, -85, -24, 10, -66, -35, -3, -47, -45, -16, + -28, -56, -30, -9, -67, -43, 10, -78, -57, 29, -88, -71, + -102, -15, 27, -82, -26, 14, -64, -36, 0, -45, -47, -12, + -25, -58, -26, -7, -68, -39, 12, -79, -53, 32, -90, -67, + -99, -16, 31, -80, -27, 18, -61, -37, 4, -42, -48, -8, + -23, -59, -22, -4, -70, -35, 15, -80, -49, 34, -91, -63, + -97, -17, 35, -78, -28, 22, -59, -39, 8, -40, -49, -4, + -21, -60, -18, -2, -71, -31, 17, -82, -45, 36, -93, -59, + -95, -19, 39, -75, -30, 26, -56, -40, 12, -38, -51, 0, + -18, -62, -14, 1, -72, -27, 19, -83, -41, 39, -94, -55, + -92, -20, 44, -72, -31, 30, -54, -42, 17, -35, -52, 3, + -16, -63, -9, 3, -74, -23, 22, -84, -36, 41, -95, -50, + -89, -22, 48, -70, -32, 34, -51, -43, 21, -33, -54, 7, + -13, -65, -5, 6, -75, -19, 24, -86, -32, 44, -97, -46, + -87, -23, 52, -68, -34, 38, -49, -44, 25, -30, -55, 11, + -11, -66, -1, 8, -77, -15, 27, -87, -28, 46, -98, -42, + -85, -24, 56, -65, -35, 42, -47, -46, 29, -28, -56, 15, + -8, -67, 2, 10, -78, -11, 29, -88, -24, 49, -99, -38, + -82, -26, 60, -63, -37, 47, -44, -47, 33, -25, -58, 20, + -6, -69, 6, 13, -79, -6, 32, -90, -20, 51, -101, -34, + -80, -27, 64, -60, -38, 51, -41, -49, 37, -23, -59, 24, + -3, -70, 10, 15, -81, -2, 34, -91, -16, 54, -102, -30, + -77, -28, 68, -58, -39, 55, -39, -50, 41, -20, -61, 28, + -1, -72, 14, 18, -82, 1, 37, -93, -12, 56, -104, -26, + -75, -30, 72, -55, -41, 59, -37, -51, 45, -18, -62, 32, + 1, -73, 18, 20, -83, 5, 39, -94, -8, 58, -105, -22, + -72, -31, 77, -53, -42, 63, -34, -53, 50, -15, -63, 36, + 4, -74, 23, 23, -85, 9, 42, -96, -3, 61, -107, -17, + -70, -33, 81, -50, -44, 67, -32, -54, 54, -13, -65, 40, + 7, -76, 27, 25, -86, 13, 44, -97, 0, 64, -108, -13, + -67, -34, 85, -48, -45, 71, -29, -56, 58, -10, -66, 44, + 9, -77, 31, 28, -88, 17, 47, -98, 4, 66, -109, -9, + -65, -35, 89, -46, -46, 75, -27, -57, 62, -8, -67, 48, + 11, -78, 35, 30, -89, 21, 49, -100, 8, 68, -111, -5, + -63, -37, 93, -43, -48, 79, -24, -58, 66, -6, -69, 52, + 14, -80, 39, 33, -90, 25, 51, -101, 12, 71, -112, -1, + -60, -38, 97, -40, -49, 84, -22, -60, 70, -3, -70, 57, + 16, -81, 43, 35, -92, 30, 54, -103, 16, 73, -113, 2, + -57, -40, 101, -38, -51, 88, -19, -61, 74, -1, -72, 61, + 19, -83, 47, 38, -93, 34, 56, -104, 20, 76, -115, 6, + -55, -41, 105, -36, -52, 92, -17, -62, 78, 2, -73, 65, + 21, -84, 51, 40, -95, 38, 59, -105, 24, 78, -116, 10, + -53, -42, 109, -33, -53, 96, -15, -64, 82, 4, -74, 69, + 24, -85, 55, 42, -96, 42, 61, -107, 28, 81, -117, 14, + -50, -44, 114, -31, -55, 100, -12, -65, 87, 7, -76, 73, + 26, -87, 60, 45, -97, 46, 64, -108, 33, 83, -119, 19, + -48, -45, 118, -28, -56, 104, -9, -67, 91, 9, -77, 77, + 29, -88, 64, 47, -99, 50, 66, -109, 37, 86, -120, 23, + -45, -47, 122, -26, -57, 108, -7, -68, 95, 12, -79, 81, + 31, -90, 68, 50, -100, 54, 69, -111, 41, 88, -122, 27, + -121, 0, -5, -101, -10, -19, -82, -21, -32, -64, -32, -46, + -44, -43, -60, -25, -53, -73, -7, -64, -86, 13, -75, -100, + -118, -1, -1, -99, -12, -15, -80, -22, -28, -61, -33, -42, + -42, -44, -56, -23, -54, -69, -4, -65, -82, 15, -76, -96, + -116, -2, 2, -96, -13, -11, -78, -24, -24, -59, -34, -38, + -39, -45, -52, -21, -56, -65, -2, -66, -78, 17, -77, -92, + -113, -4, 6, -94, -15, -6, -75, -25, -20, -56, -36, -33, + -37, -47, -47, -18, -57, -61, 1, -68, -74, 20, -79, -88, + -111, -5, 10, -91, -16, -2, -73, -27, -16, -54, -37, -29, + -34, -48, -43, -16, -59, -57, 3, -69, -70, 23, -80, -84, + -108, -6, 14, -89, -17, 1, -70, -28, -12, -51, -39, -25, + -32, -49, -39, -13, -60, -53, 6, -71, -66, 25, -82, -80, + -106, -8, 18, -87, -19, 5, -68, -29, -8, -49, -40, -21, + -30, -51, -35, -11, -61, -49, 8, -72, -62, 27, -83, -76, + -103, -9, 23, -84, -20, 9, -65, -31, -3, -46, -41, -17, + -27, -52, -31, -8, -63, -44, 11, -74, -57, 30, -84, -71, + -101, -11, 27, -81, -22, 13, -63, -32, 0, -44, -43, -13, + -24, -54, -27, -6, -64, -40, 13, -75, -53, 32, -86, -67, + -98, -12, 31, -79, -23, 17, -60, -33, 4, -41, -44, -9, + -22, -55, -23, -3, -66, -36, 15, -76, -49, 35, -87, -63, + -96, -13, 35, -77, -24, 21, -58, -35, 8, -39, -45, -5, + -20, -56, -19, -1, -67, -32, 18, -78, -45, 37, -89, -59, + -94, -15, 39, -74, -26, 25, -55, -36, 12, -37, -47, -1, + -17, -58, -15, 1, -68, -28, 20, -79, -41, 40, -90, -55, + -91, -16, 43, -72, -27, 30, -53, -38, 16, -34, -48, 3, + -15, -59, -10, 4, -70, -24, 23, -80, -37, 42, -91, -51, + -89, -18, 47, -69, -28, 34, -50, -39, 20, -32, -50, 7, + -12, -61, -6, 7, -71, -20, 25, -82, -33, 45, -93, -47, + -86, -19, 51, -67, -30, 38, -48, -40, 24, -29, -51, 11, + -10, -62, -2, 9, -73, -16, 28, -83, -29, 47, -94, -43, + -84, -20, 55, -64, -31, 42, -46, -42, 28, -27, -52, 15, + -7, -63, 1, 11, -74, -12, 30, -84, -25, 49, -95, -39, + -81, -22, 60, -62, -33, 46, -43, -43, 33, -24, -54, 19, + -5, -65, 5, 14, -75, -7, 33, -86, -20, 52, -97, -34, + -79, -23, 64, -59, -34, 50, -41, -45, 37, -22, -55, 23, + -2, -66, 9, 16, -77, -3, 35, -87, -16, 55, -98, -30, + -76, -24, 68, -57, -35, 54, -38, -46, 41, -19, -57, 27, + 0, -68, 13, 19, -78, 0, 38, -89, -12, 57, -100, -26, + -74, -26, 72, -55, -37, 58, -36, -47, 45, -17, -58, 31, + 2, -69, 17, 21, -79, 4, 40, -90, -8, 59, -101, -22, + -71, -27, 76, -52, -38, 63, -33, -49, 49, -14, -59, 36, + 5, -70, 22, 24, -81, 8, 43, -92, -4, 62, -103, -18, + -69, -29, 80, -49, -40, 67, -31, -50, 53, -12, -61, 40, + 7, -72, 26, 26, -82, 12, 45, -93, 0, 64, -104, -14, + -66, -30, 84, -47, -41, 71, -28, -52, 57, -9, -62, 44, + 10, -73, 30, 29, -84, 16, 47, -94, 3, 67, -105, -10, + -64, -31, 88, -45, -42, 75, -26, -53, 61, -7, -63, 48, + 12, -74, 34, 31, -85, 20, 50, -96, 7, 69, -107, -6, + -62, -33, 92, -42, -44, 79, -23, -54, 65, -5, -65, 52, + 15, -76, 38, 33, -86, 24, 52, -97, 11, 72, -108, -2, + -59, -34, 97, -40, -45, 83, -21, -56, 70, -2, -66, 56, + 17, -77, 42, 36, -88, 29, 55, -99, 16, 74, -109, 2, + -57, -36, 101, -37, -47, 87, -18, -57, 74, 0, -68, 60, + 20, -79, 46, 39, -89, 33, 57, -100, 20, 77, -111, 6, + -54, -37, 105, -35, -48, 91, -16, -58, 78, 3, -69, 64, + 22, -80, 50, 41, -91, 37, 60, -101, 24, 79, -112, 10, + -52, -38, 109, -32, -49, 95, -14, -60, 82, 5, -70, 68, + 25, -81, 54, 43, -92, 41, 62, -103, 28, 81, -113, 14, + -49, -40, 113, -30, -51, 100, -11, -61, 86, 8, -72, 73, + 27, -83, 59, 46, -93, 45, 65, -104, 32, 84, -115, 18, + -47, -41, 117, -27, -52, 104, -9, -63, 90, 10, -73, 77, + 30, -84, 63, 48, -95, 49, 67, -105, 36, 87, -116, 22, + -44, -43, 121, -25, -53, 108, -6, -64, 94, 13, -75, 81, + 32, -86, 67, 51, -96, 53, 70, -107, 40, 89, -118, 26, + -120, 4, -6, -100, -6, -20, -81, -17, -33, -63, -28, -46, + -43, -39, -60, -25, -49, -74, -6, -60, -87, 14, -71, -101, + -117, 2, -2, -98, -8, -16, -79, -18, -29, -60, -29, -42, + -41, -40, -56, -22, -50, -70, -3, -61, -83, 16, -72, -97, + -115, 1, 1, -95, -9, -12, -77, -20, -25, -58, -30, -38, + -39, -41, -52, -20, -52, -66, -1, -62, -79, 18, -73, -93, + -112, 0, 6, -93, -11, -7, -74, -21, -21, -55, -32, -34, + -36, -43, -48, -17, -53, -61, 2, -64, -75, 21, -75, -88, + -110, -1, 10, -90, -12, -3, -72, -23, -17, -53, -33, -30, + -33, -44, -44, -15, -55, -57, 4, -65, -71, 23, -76, -84, + -107, -2, 14, -88, -13, 0, -69, -24, -13, -50, -35, -26, + -31, -45, -40, -12, -56, -53, 7, -67, -67, 26, -78, -80, + -105, -4, 18, -86, -15, 4, -67, -25, -9, -48, -36, -22, + -29, -47, -36, -10, -57, -49, 9, -68, -63, 28, -79, -76, + -102, -5, 22, -83, -16, 8, -64, -27, -4, -45, -37, -17, + -26, -48, -31, -7, -59, -45, 12, -70, -58, 31, -80, -72, + -100, -7, 26, -81, -18, 12, -62, -28, 0, -43, -39, -13, + -24, -50, -27, -5, -60, -41, 14, -71, -54, 33, -82, -68, + -98, -8, 30, -78, -19, 16, -59, -29, 3, -41, -40, -9, + -21, -51, -23, -2, -62, -37, 16, -72, -50, 36, -83, -64, + -95, -9, 34, -76, -20, 20, -57, -31, 7, -38, -41, -5, + -19, -52, -19, 0, -63, -33, 19, -74, -46, 38, -85, -60, + -93, -11, 38, -73, -22, 24, -55, -32, 11, -36, -43, -1, + -16, -54, -15, 2, -64, -29, 21, -75, -42, 41, -86, -56, + -90, -12, 43, -71, -23, 29, -52, -34, 15, -33, -44, 2, + -14, -55, -11, 5, -66, -24, 24, -76, -38, 43, -87, -51, + -88, -14, 47, -68, -24, 33, -49, -35, 19, -31, -46, 6, + -11, -57, -7, 7, -67, -20, 26, -78, -34, 46, -89, -47, + -85, -15, 51, -66, -26, 37, -47, -36, 23, -28, -47, 10, + -9, -58, -3, 10, -69, -16, 29, -79, -30, 48, -90, -43, + -83, -16, 55, -63, -27, 41, -45, -38, 27, -26, -48, 14, + -7, -59, 0, 12, -70, -12, 31, -80, -26, 50, -91, -39, + -80, -18, 59, -61, -29, 45, -42, -39, 32, -23, -50, 19, + -4, -61, 5, 15, -71, -8, 34, -82, -21, 53, -93, -35, + -78, -19, 63, -58, -30, 49, -40, -41, 36, -21, -51, 23, + -1, -62, 9, 17, -73, -4, 36, -83, -17, 55, -94, -31, + -75, -20, 67, -56, -31, 53, -37, -42, 40, -18, -53, 27, + 1, -64, 13, 20, -74, 0, 38, -85, -13, 58, -96, -27, + -73, -22, 71, -54, -33, 57, -35, -43, 44, -16, -54, 31, + 3, -65, 17, 22, -75, 3, 41, -86, -9, 60, -97, -23, + -70, -23, 76, -51, -34, 62, -32, -45, 48, -13, -55, 35, + 6, -66, 21, 25, -77, 8, 44, -88, -5, 63, -99, -18, + -68, -25, 80, -49, -36, 66, -30, -46, 52, -11, -57, 39, + 8, -68, 25, 27, -78, 12, 46, -89, -1, 65, -100, -14, + -66, -26, 84, -46, -37, 70, -27, -48, 56, -9, -58, 43, + 11, -69, 29, 30, -80, 16, 48, -90, 2, 68, -101, -10, + -63, -27, 88, -44, -38, 74, -25, -49, 60, -6, -59, 47, + 13, -70, 33, 32, -81, 20, 51, -92, 6, 70, -103, -6, + -61, -29, 92, -41, -40, 78, -23, -50, 64, -4, -61, 51, + 16, -72, 37, 34, -82, 24, 53, -93, 10, 73, -104, -2, + -58, -30, 96, -39, -41, 82, -20, -52, 69, -1, -62, 56, + 18, -73, 42, 37, -84, 28, 56, -95, 15, 75, -105, 1, + -56, -32, 100, -36, -43, 86, -17, -53, 73, 1, -64, 60, + 21, -75, 46, 39, -85, 32, 58, -96, 19, 78, -107, 5, + -53, -33, 104, -34, -44, 90, -15, -54, 77, 4, -65, 64, + 23, -76, 50, 42, -87, 36, 61, -97, 23, 80, -108, 9, + -51, -34, 108, -31, -45, 94, -13, -56, 81, 6, -66, 68, + 25, -77, 54, 44, -88, 40, 63, -99, 27, 82, -109, 13, + -48, -36, 113, -29, -47, 99, -10, -57, 85, 9, -68, 72, + 28, -79, 58, 47, -89, 45, 66, -100, 31, 85, -111, 18, + -46, -37, 117, -26, -48, 103, -8, -59, 89, 11, -69, 76, + 31, -80, 62, 49, -91, 49, 68, -101, 35, 87, -112, 22, + -43, -39, 121, -24, -49, 107, -5, -60, 93, 14, -71, 80, + 33, -82, 66, 52, -92, 53, 70, -103, 39, 90, -114, 26, + -119, 8, -7, -99, -2, -20, -80, -13, -34, -62, -23, -47, + -42, -34, -61, -24, -45, -74, -5, -55, -88, 15, -66, -102, + -116, 7, -3, -97, -3, -16, -78, -14, -30, -59, -24, -43, + -40, -35, -57, -21, -46, -70, -2, -57, -84, 17, -68, -98, + -114, 5, 0, -94, -5, -12, -76, -15, -26, -57, -26, -39, + -38, -37, -53, -19, -47, -66, 0, -58, -80, 19, -69, -94, + -111, 4, 5, -92, -6, -8, -73, -17, -21, -54, -27, -35, + -35, -38, -48, -16, -49, -62, 3, -59, -75, 22, -70, -89, + -109, 2, 9, -89, -7, -4, -71, -18, -17, -52, -29, -31, + -32, -40, -44, -14, -50, -58, 5, -61, -71, 25, -72, -85, + -106, 1, 13, -87, -9, 0, -68, -19, -13, -49, -30, -27, + -30, -41, -40, -11, -52, -54, 8, -62, -67, 27, -73, -81, + -104, 0, 17, -85, -10, 3, -66, -21, -9, -47, -31, -23, + -28, -42, -36, -9, -53, -50, 10, -64, -63, 29, -74, -77, + -101, -1, 21, -82, -12, 8, -63, -22, -5, -44, -33, -18, + -25, -44, -32, -6, -54, -45, 13, -65, -59, 32, -76, -73, + -99, -2, 25, -80, -13, 12, -61, -24, -1, -42, -34, -14, + -23, -45, -28, -4, -56, -41, 15, -66, -55, 34, -77, -69, + -96, -3, 29, -77, -14, 16, -58, -25, 2, -40, -36, -10, + -20, -47, -24, -1, -57, -37, 17, -68, -51, 37, -79, -65, + -94, -5, 33, -75, -16, 20, -56, -26, 6, -37, -37, -6, + -18, -48, -20, 1, -58, -33, 20, -69, -47, 39, -80, -61, + -92, -6, 37, -72, -17, 24, -54, -28, 10, -35, -38, -2, + -15, -49, -16, 3, -60, -29, 22, -70, -43, 42, -81, -57, + -89, -8, 42, -70, -19, 28, -51, -29, 15, -32, -40, 1, + -13, -51, -11, 6, -61, -25, 25, -72, -38, 44, -83, -52, + -87, -9, 46, -67, -20, 32, -48, -31, 19, -30, -41, 5, + -10, -52, -7, 8, -63, -21, 27, -73, -34, 47, -84, -48, + -84, -10, 50, -65, -21, 36, -46, -32, 23, -27, -43, 9, + -8, -53, -3, 11, -64, -17, 30, -75, -30, 49, -86, -44, + -82, -12, 54, -62, -23, 40, -44, -33, 27, -25, -44, 13, + -6, -55, 0, 13, -65, -13, 32, -76, -26, 51, -87, -40, + -79, -13, 58, -60, -24, 45, -41, -35, 31, -22, -45, 18, + -3, -56, 4, 16, -67, -8, 35, -78, -22, 54, -88, -36, + -77, -15, 62, -57, -26, 49, -39, -36, 35, -20, -47, 22, + 0, -58, 8, 18, -68, -4, 37, -79, -18, 57, -90, -32, + -74, -16, 66, -55, -27, 53, -36, -37, 39, -17, -48, 26, + 2, -59, 12, 21, -70, 0, 40, -80, -14, 59, -91, -28, + -72, -17, 70, -53, -28, 57, -34, -39, 43, -15, -49, 30, + 4, -60, 16, 23, -71, 3, 42, -82, -10, 61, -92, -24, + -69, -19, 75, -50, -30, 61, -31, -40, 48, -12, -51, 34, + 7, -62, 21, 26, -72, 7, 45, -83, -5, 64, -94, -19, + -67, -20, 79, -48, -31, 65, -29, -42, 52, -10, -52, 38, + 9, -63, 25, 28, -74, 11, 47, -84, -1, 66, -95, -15, + -64, -22, 83, -45, -32, 69, -26, -43, 56, -8, -54, 42, + 12, -65, 29, 31, -75, 15, 49, -86, 2, 69, -97, -11, + -62, -23, 87, -43, -34, 73, -24, -44, 60, -5, -55, 46, + 14, -66, 33, 33, -77, 19, 52, -87, 6, 71, -98, -7, + -60, -24, 91, -40, -35, 77, -22, -46, 64, -3, -56, 50, + 17, -67, 37, 35, -78, 23, 54, -88, 10, 74, -99, -3, + -57, -26, 95, -38, -37, 82, -19, -47, 68, 0, -58, 55, + 19, -69, 41, 38, -79, 28, 57, -90, 14, 76, -101, 0, + -55, -27, 99, -35, -38, 86, -16, -49, 72, 2, -59, 59, + 22, -70, 45, 40, -81, 32, 59, -91, 18, 79, -102, 4, + -52, -28, 103, -33, -39, 90, -14, -50, 76, 5, -61, 63, + 24, -71, 49, 43, -82, 36, 62, -93, 22, 81, -104, 8, + -50, -30, 107, -30, -41, 94, -12, -51, 80, 7, -62, 67, + 26, -73, 53, 45, -83, 40, 64, -94, 26, 83, -105, 12, + -47, -31, 112, -28, -42, 98, -9, -53, 85, 10, -63, 71, + 29, -74, 58, 48, -85, 44, 67, -96, 31, 86, -107, 17, + -45, -33, 116, -25, -44, 102, -7, -54, 89, 12, -65, 75, + 32, -76, 62, 50, -86, 48, 69, -97, 35, 88, -108, 21, + -42, -34, 120, -23, -45, 106, -4, -56, 93, 15, -66, 79, + 34, -77, 66, 53, -88, 52, 72, -98, 39, 91, -109, 25, + -118, 12, -7, -98, 1, -21, -80, -9, -34, -61, -19, -48, + -41, -30, -62, -23, -41, -75, -4, -51, -88, 16, -62, -102, + -115, 11, -3, -96, 0, -17, -77, -10, -30, -58, -20, -44, + -39, -31, -58, -20, -42, -71, -1, -53, -84, 18, -64, -98, + -113, 9, 0, -94, -1, -13, -75, -11, -26, -56, -22, -40, + -37, -33, -54, -18, -43, -67, 1, -54, -80, 20, -65, -94, + -110, 8, 4, -91, -2, -9, -72, -13, -22, -53, -23, -35, + -34, -34, -49, -15, -45, -63, 4, -55, -76, 23, -66, -90, + -108, 6, 8, -88, -3, -5, -70, -14, -18, -51, -25, -31, + -32, -36, -45, -13, -46, -59, 6, -57, -72, 25, -68, -86, + -105, 5, 12, -86, -5, -1, -67, -15, -14, -48, -26, -27, + -29, -37, -41, -10, -48, -55, 8, -58, -68, 28, -69, -82, + -103, 4, 16, -84, -6, 2, -65, -17, -10, -46, -27, -23, + -27, -38, -37, -8, -49, -51, 11, -60, -64, 30, -70, -78, + -100, 2, 21, -81, -8, 7, -62, -18, -5, -43, -29, -19, + -24, -40, -33, -5, -50, -46, 14, -61, -59, 33, -72, -73, + -98, 1, 25, -79, -9, 11, -60, -20, -1, -41, -30, -15, + -22, -41, -29, -3, -52, -42, 16, -62, -55, 35, -73, -69, + -96, 0, 29, -76, -10, 15, -57, -21, 2, -39, -32, -11, + -19, -43, -25, 0, -53, -38, 18, -64, -51, 38, -75, -65, + -93, -1, 33, -74, -12, 19, -55, -22, 6, -36, -33, -7, + -17, -44, -21, 2, -54, -34, 21, -65, -47, 40, -76, -61, + -91, -2, 37, -71, -13, 23, -53, -24, 10, -34, -34, -3, + -14, -45, -17, 4, -56, -30, 23, -66, -43, 42, -77, -57, + -88, -4, 41, -69, -15, 27, -50, -25, 14, -31, -36, 1, + -12, -47, -12, 7, -57, -26, 26, -68, -39, 45, -79, -53, + -86, -5, 45, -66, -16, 31, -48, -27, 18, -29, -37, 5, + -9, -48, -8, 9, -59, -22, 28, -69, -35, 48, -80, -49, + -83, -6, 49, -64, -17, 35, -45, -28, 22, -26, -39, 9, + -7, -49, -4, 12, -60, -18, 31, -71, -31, 50, -82, -45, + -81, -8, 53, -62, -19, 39, -43, -29, 26, -24, -40, 13, + -5, -51, 0, 14, -61, -14, 33, -72, -27, 52, -83, -41, + -78, -9, 58, -59, -20, 44, -40, -31, 31, -21, -41, 17, + -2, -52, 3, 17, -63, -9, 36, -74, -22, 55, -84, -36, + -76, -11, 62, -56, -22, 48, -38, -32, 35, -19, -43, 21, + 0, -54, 7, 19, -64, -5, 38, -75, -18, 57, -86, -32, + -73, -12, 66, -54, -23, 52, -35, -33, 39, -17, -44, 25, + 3, -55, 11, 22, -66, -1, 40, -76, -14, 60, -87, -28, + -71, -13, 70, -52, -24, 56, -33, -35, 43, -14, -45, 29, + 5, -56, 15, 24, -67, 2, 43, -78, -10, 62, -88, -24, + -68, -15, 74, -49, -26, 60, -30, -36, 47, -11, -47, 34, + 8, -58, 20, 27, -68, 6, 46, -79, -6, 65, -90, -20, + -66, -16, 78, -47, -27, 64, -28, -38, 51, -9, -48, 38, + 10, -59, 24, 29, -70, 10, 48, -80, -2, 67, -91, -16, + -64, -18, 82, -44, -28, 68, -25, -39, 55, -7, -50, 42, + 13, -61, 28, 32, -71, 14, 50, -82, 1, 70, -93, -12, + -61, -19, 86, -42, -30, 72, -23, -40, 59, -4, -51, 46, + 15, -62, 32, 34, -73, 18, 53, -83, 5, 72, -94, -8, + -59, -20, 90, -39, -31, 76, -21, -42, 63, -2, -52, 50, + 18, -63, 36, 36, -74, 22, 55, -84, 9, 74, -95, -4, + -56, -22, 95, -37, -33, 81, -18, -43, 68, 1, -54, 54, + 20, -65, 40, 39, -75, 27, 58, -86, 14, 77, -97, 0, + -54, -23, 99, -34, -34, 85, -16, -45, 72, 3, -55, 58, + 23, -66, 44, 41, -77, 31, 60, -87, 18, 80, -98, 4, + -51, -24, 103, -32, -35, 89, -13, -46, 76, 6, -57, 62, + 25, -67, 48, 44, -78, 35, 63, -89, 22, 82, -100, 8, + -49, -26, 107, -30, -37, 93, -11, -47, 80, 8, -58, 66, + 27, -69, 52, 46, -79, 39, 65, -90, 26, 84, -101, 12, + -46, -27, 111, -27, -38, 97, -8, -49, 84, 11, -59, 71, + 30, -70, 57, 49, -81, 43, 68, -92, 30, 87, -103, 16, + -44, -29, 115, -24, -40, 101, -6, -50, 88, 13, -61, 75, + 32, -72, 61, 51, -82, 47, 70, -93, 34, 89, -104, 20, + -41, -30, 119, -22, -41, 105, -3, -52, 92, 15, -62, 79, + 35, -73, 65, 54, -84, 51, 72, -94, 38, 92, -105, 24, + -117, 16, -8, -97, 5, -22, -79, -5, -35, -60, -15, -48, + -40, -26, -62, -22, -37, -76, -3, -47, -89, 16, -58, -103, + -114, 15, -4, -95, 4, -18, -76, -6, -31, -57, -16, -44, + -38, -27, -58, -19, -38, -72, -1, -49, -85, 19, -60, -99, + -112, 13, 0, -93, 2, -14, -74, -7, -27, -55, -18, -40, + -36, -29, -54, -17, -39, -68, 2, -50, -81, 21, -61, -95, + -109, 12, 4, -90, 1, -9, -71, -9, -23, -52, -19, -36, + -33, -30, -50, -14, -41, -63, 5, -51, -77, 24, -62, -90, + -107, 10, 8, -88, 0, -5, -69, -10, -19, -50, -21, -32, + -31, -32, -46, -12, -42, -59, 7, -53, -73, 26, -64, -86, + -105, 9, 12, -85, -1, -1, -66, -11, -15, -48, -22, -28, + -28, -33, -42, -9, -44, -55, 9, -54, -69, 29, -65, -82, + -102, 8, 16, -83, -2, 2, -64, -13, -11, -45, -23, -24, + -26, -34, -38, -7, -45, -51, 12, -56, -65, 31, -66, -78, + -99, 6, 20, -80, -4, 6, -61, -14, -6, -43, -25, -19, + -23, -36, -33, -4, -46, -47, 14, -57, -60, 34, -68, -74, + -97, 5, 24, -78, -5, 10, -59, -16, -2, -40, -26, -15, + -21, -37, -29, -2, -48, -43, 17, -58, -56, 36, -69, -70, + -95, 4, 28, -75, -6, 14, -57, -17, 1, -38, -28, -11, + -18, -39, -25, 0, -49, -39, 19, -60, -52, 39, -71, -66, + -92, 2, 32, -73, -8, 18, -54, -18, 5, -35, -29, -7, + -16, -40, -21, 3, -50, -35, 22, -61, -48, 41, -72, -62, + -90, 1, 36, -71, -9, 22, -52, -20, 9, -33, -30, -3, + -14, -41, -17, 5, -52, -31, 24, -62, -44, 43, -73, -58, + -87, 0, 41, -68, -11, 27, -49, -21, 13, -30, -32, 0, + -11, -43, -13, 8, -53, -26, 27, -64, -40, 46, -75, -53, + -85, -1, 45, -65, -12, 31, -47, -23, 17, -28, -33, 4, + -8, -44, -9, 10, -55, -22, 29, -65, -36, 48, -76, -49, + -82, -2, 49, -63, -13, 35, -44, -24, 21, -25, -35, 8, + -6, -45, -5, 13, -56, -18, 31, -67, -32, 51, -78, -45, + -80, -4, 53, -61, -15, 39, -42, -25, 25, -23, -36, 12, + -4, -47, -1, 15, -57, -14, 34, -68, -28, 53, -79, -41, + -77, -5, 57, -58, -16, 43, -39, -27, 30, -20, -37, 17, + -1, -48, 3, 18, -59, -10, 37, -70, -23, 56, -80, -37, + -75, -7, 61, -56, -18, 47, -37, -28, 34, -18, -39, 21, + 1, -50, 7, 20, -60, -6, 39, -71, -19, 58, -82, -33, + -73, -8, 65, -53, -19, 51, -34, -29, 38, -16, -40, 25, + 4, -51, 11, 23, -62, -2, 41, -72, -15, 61, -83, -29, + -70, -9, 69, -51, -20, 55, -32, -31, 42, -13, -41, 29, + 6, -52, 15, 25, -63, 1, 44, -74, -11, 63, -84, -25, + -67, -11, 74, -48, -22, 60, -29, -32, 46, -11, -43, 33, + 9, -54, 19, 28, -64, 6, 46, -75, -7, 66, -86, -20, + -65, -12, 78, -46, -23, 64, -27, -34, 50, -8, -44, 37, + 11, -55, 23, 30, -66, 10, 49, -76, -3, 68, -87, -16, + -63, -14, 82, -43, -24, 68, -25, -35, 54, -6, -46, 41, + 14, -57, 27, 32, -67, 14, 51, -78, 0, 71, -89, -12, + -60, -15, 86, -41, -26, 72, -22, -36, 58, -3, -47, 45, + 16, -58, 31, 35, -69, 18, 54, -79, 4, 73, -90, -8, + -58, -16, 90, -39, -27, 76, -20, -38, 62, -1, -48, 49, + 18, -59, 35, 37, -70, 22, 56, -80, 8, 75, -91, -4, + -55, -18, 94, -36, -29, 80, -17, -39, 67, 2, -50, 54, + 21, -61, 40, 40, -71, 26, 59, -82, 13, 78, -93, 0, + -53, -19, 98, -33, -30, 84, -15, -41, 71, 4, -51, 58, + 24, -62, 44, 42, -73, 30, 61, -83, 17, 80, -94, 3, + -50, -20, 102, -31, -31, 88, -12, -42, 75, 7, -53, 62, + 26, -63, 48, 45, -74, 34, 63, -85, 21, 83, -96, 7, + -48, -22, 106, -29, -33, 92, -10, -43, 79, 9, -54, 66, + 28, -65, 52, 47, -75, 38, 66, -86, 25, 85, -97, 11, + -45, -23, 111, -26, -34, 97, -7, -45, 83, 12, -55, 70, + 31, -66, 56, 50, -77, 43, 69, -88, 29, 88, -99, 16, + -43, -25, 115, -24, -36, 101, -5, -46, 87, 14, -57, 74, + 33, -68, 60, 52, -78, 47, 71, -89, 33, 90, -100, 20, + -41, -26, 119, -21, -37, 105, -2, -48, 91, 16, -58, 78, + 36, -69, 64, 55, -80, 51, 73, -90, 37, 93, -101, 24, + -116, 20, -9, -96, 9, -22, -78, -1, -36, -59, -11, -49, + -40, -22, -63, -21, -33, -76, -2, -43, -90, 17, -54, -104, + -113, 19, -5, -94, 8, -18, -75, -2, -32, -57, -12, -45, + -37, -23, -59, -18, -34, -72, 0, -45, -86, 20, -56, -100, + -111, 17, -1, -92, 6, -14, -73, -3, -28, -54, -14, -41, + -35, -25, -55, -16, -35, -68, 3, -46, -82, 22, -57, -96, + -108, 16, 3, -89, 5, -10, -70, -5, -23, -51, -15, -37, + -32, -26, -50, -13, -37, -64, 5, -47, -77, 25, -58, -91, + -106, 14, 7, -87, 4, -6, -68, -6, -19, -49, -17, -33, + -30, -28, -46, -11, -38, -60, 8, -49, -73, 27, -60, -87, + -104, 13, 11, -84, 2, -2, -65, -7, -15, -47, -18, -29, + -27, -29, -42, -9, -40, -56, 10, -50, -69, 30, -61, -83, + -101, 12, 15, -82, 1, 1, -63, -9, -11, -44, -19, -25, + -25, -30, -38, -6, -41, -52, 13, -52, -65, 32, -62, -79, + -99, 10, 19, -79, 0, 6, -60, -10, -7, -42, -21, -20, + -22, -32, -34, -3, -42, -47, 15, -53, -61, 35, -64, -75, + -96, 9, 23, -77, -1, 10, -58, -12, -3, -39, -22, -16, + -20, -33, -30, -1, -44, -43, 18, -54, -57, 37, -65, -71, + -94, 8, 27, -74, -2, 14, -56, -13, 0, -37, -24, -12, + -17, -35, -26, 1, -45, -39, 20, -56, -53, 40, -67, -67, + -91, 6, 31, -72, -4, 18, -53, -14, 4, -34, -25, -8, + -15, -36, -22, 4, -46, -35, 23, -57, -49, 42, -68, -63, + -89, 5, 35, -70, -5, 22, -51, -16, 8, -32, -26, -4, + -13, -37, -18, 6, -48, -31, 25, -58, -45, 44, -69, -59, + -86, 3, 40, -67, -7, 26, -48, -17, 13, -29, -28, 0, + -10, -39, -13, 9, -49, -27, 28, -60, -40, 47, -71, -54, + -84, 2, 44, -65, -8, 30, -46, -19, 17, -27, -29, 3, + -8, -40, -9, 11, -51, -23, 30, -61, -36, 49, -72, -50, + -81, 1, 48, -62, -9, 34, -43, -20, 21, -25, -31, 7, + -5, -41, -5, 14, -52, -19, 32, -63, -32, 52, -74, -46, + -79, 0, 52, -60, -11, 38, -41, -21, 25, -22, -32, 11, + -3, -43, -1, 16, -53, -15, 35, -64, -28, 54, -75, -42, + -76, -1, 56, -57, -12, 43, -38, -23, 29, -19, -33, 16, + 0, -44, 2, 19, -55, -10, 37, -66, -24, 57, -76, -38, + -74, -3, 60, -55, -14, 47, -36, -24, 33, -17, -35, 20, + 2, -46, 6, 21, -56, -6, 40, -67, -20, 59, -78, -34, + -72, -4, 64, -52, -15, 51, -33, -25, 37, -15, -36, 24, + 5, -47, 10, 23, -58, -2, 42, -68, -16, 62, -79, -30, + -69, -5, 68, -50, -16, 55, -31, -27, 41, -12, -37, 28, + 7, -48, 14, 26, -59, 1, 45, -70, -12, 64, -80, -26, + -67, -7, 73, -47, -18, 59, -28, -28, 46, -10, -39, 32, + 10, -50, 19, 29, -60, 5, 47, -71, -7, 67, -82, -21, + -64, -8, 77, -45, -19, 63, -26, -30, 50, -7, -40, 36, + 12, -51, 23, 31, -62, 9, 50, -72, -3, 69, -83, -17, + -62, -10, 81, -42, -20, 67, -24, -31, 54, -5, -42, 40, + 15, -53, 27, 33, -63, 13, 52, -74, 0, 71, -85, -13, + -59, -11, 85, -40, -22, 71, -21, -32, 58, -2, -43, 44, + 17, -54, 31, 36, -65, 17, 55, -75, 4, 74, -86, -9, + -57, -12, 89, -38, -23, 75, -19, -34, 62, 0, -44, 48, + 19, -55, 35, 38, -66, 21, 57, -76, 8, 76, -87, -5, + -54, -14, 93, -35, -25, 80, -16, -35, 66, 3, -46, 53, + 22, -57, 39, 41, -67, 26, 60, -78, 12, 79, -89, -1, + -52, -15, 97, -33, -26, 84, -14, -37, 70, 5, -47, 57, + 24, -58, 43, 43, -69, 30, 62, -79, 16, 81, -90, 2, + -49, -16, 101, -30, -27, 88, -11, -38, 74, 7, -49, 61, + 27, -59, 47, 46, -70, 34, 64, -81, 20, 84, -92, 6, + -47, -18, 105, -28, -29, 92, -9, -39, 78, 10, -50, 65, + 29, -61, 51, 48, -71, 38, 67, -82, 24, 86, -93, 10, + -44, -19, 110, -25, -30, 96, -6, -41, 83, 13, -51, 69, + 32, -62, 56, 51, -73, 42, 69, -84, 29, 89, -95, 15, + -42, -21, 114, -23, -32, 100, -4, -42, 87, 15, -53, 73, + 34, -64, 60, 53, -74, 46, 72, -85, 33, 91, -96, 19, + -40, -22, 118, -20, -33, 104, -1, -44, 91, 17, -54, 77, + 37, -65, 64, 55, -76, 50, 74, -86, 37, 94, -97, 23, + -115, 25, -9, -95, 14, -23, -77, 3, -36, -58, -7, -50, + -39, -18, -64, -20, -28, -77, -1, -39, -90, 18, -50, -104, + -112, 23, -5, -93, 12, -19, -74, 2, -32, -56, -8, -46, + -36, -19, -60, -17, -29, -73, 1, -40, -86, 21, -51, -100, + -110, 22, -1, -91, 11, -15, -72, 0, -28, -53, -9, -42, + -34, -20, -56, -15, -31, -69, 4, -41, -82, 23, -52, -96, + -107, 20, 2, -88, 9, -11, -69, 0, -24, -50, -11, -37, + -31, -22, -51, -12, -32, -65, 7, -43, -78, 26, -54, -92, + -105, 19, 6, -86, 8, -7, -67, -2, -20, -48, -12, -33, + -29, -23, -47, -10, -34, -61, 9, -44, -74, 28, -55, -88, + -103, 18, 10, -83, 7, -3, -64, -3, -16, -46, -14, -29, + -26, -24, -43, -7, -35, -57, 11, -46, -70, 31, -57, -84, + -100, 16, 14, -81, 5, 0, -62, -4, -12, -43, -15, -25, + -24, -26, -39, -5, -36, -53, 14, -47, -66, 33, -58, -80, + -98, 15, 19, -78, 4, 5, -59, -6, -7, -41, -16, -21, + -21, -27, -35, -2, -38, -48, 16, -49, -61, 36, -59, -75, + -95, 13, 23, -76, 2, 9, -57, -7, -3, -38, -18, -17, + -19, -29, -31, 0, -39, -44, 19, -50, -57, 38, -61, -71, + -93, 12, 27, -73, 1, 13, -55, -8, 0, -36, -19, -13, + -16, -30, -27, 2, -41, -40, 21, -51, -53, 41, -62, -67, + -90, 11, 31, -71, 0, 17, -52, -10, 4, -33, -20, -9, + -14, -31, -23, 5, -42, -36, 24, -53, -49, 43, -64, -63, + -88, 9, 35, -69, -1, 21, -50, -11, 8, -31, -22, -5, + -12, -33, -19, 7, -43, -32, 26, -54, -45, 45, -65, -59, + -85, 8, 39, -66, -2, 25, -47, -13, 12, -28, -23, 0, + -9, -34, -14, 10, -45, -28, 29, -55, -41, 48, -66, -55, + -83, 6, 43, -63, -3, 29, -45, -14, 16, -26, -25, 3, + -7, -36, -10, 12, -46, -24, 31, -57, -37, 50, -68, -51, + -80, 5, 47, -61, -5, 33, -42, -15, 20, -24, -26, 7, + -4, -37, -6, 15, -48, -20, 33, -58, -33, 53, -69, -47, + -78, 4, 51, -59, -6, 37, -40, -17, 24, -21, -27, 11, + -2, -38, -2, 17, -49, -16, 36, -59, -29, 55, -70, -43, + -75, 2, 56, -56, -8, 42, -37, -18, 29, -18, -29, 15, + 1, -40, 1, 20, -50, -11, 39, -61, -24, 58, -72, -38, + -73, 1, 60, -54, -9, 46, -35, -20, 33, -16, -30, 19, + 3, -41, 5, 22, -52, -7, 41, -62, -20, 60, -73, -34, + -71, 0, 64, -51, -10, 50, -32, -21, 37, -14, -32, 23, + 6, -43, 9, 25, -53, -3, 43, -64, -16, 63, -75, -30, + -68, -1, 68, -49, -12, 54, -30, -22, 41, -11, -33, 27, + 8, -44, 13, 27, -54, 0, 46, -65, -12, 65, -76, -26, + -66, -2, 72, -46, -13, 58, -27, -24, 45, -9, -34, 32, + 11, -45, 18, 30, -56, 4, 48, -67, -8, 68, -78, -22, + -63, -4, 76, -44, -15, 62, -25, -25, 49, -6, -36, 36, + 13, -47, 22, 32, -57, 8, 51, -68, -4, 70, -79, -18, + -61, -5, 80, -41, -16, 66, -23, -27, 53, -4, -37, 40, + 16, -48, 26, 34, -59, 12, 53, -69, 0, 73, -80, -14, + -58, -6, 84, -39, -17, 70, -20, -28, 57, -1, -38, 44, + 18, -49, 30, 37, -60, 16, 56, -71, 3, 75, -82, -10, + -56, -8, 88, -37, -19, 74, -18, -29, 61, 1, -40, 48, + 20, -51, 34, 39, -61, 20, 58, -72, 7, 77, -83, -6, + -53, -9, 93, -34, -20, 79, -15, -31, 66, 4, -41, 52, + 23, -52, 38, 42, -63, 25, 61, -74, 12, 80, -84, -1, + -51, -11, 97, -31, -22, 83, -13, -32, 70, 6, -43, 56, + 25, -54, 42, 44, -64, 29, 63, -75, 16, 82, -86, 2, + -48, -12, 101, -29, -23, 87, -10, -33, 74, 8, -44, 60, + 28, -55, 46, 47, -66, 33, 65, -76, 20, 85, -87, 6, + -46, -13, 105, -27, -24, 91, -8, -35, 78, 11, -45, 64, + 30, -56, 50, 49, -67, 37, 68, -78, 24, 87, -88, 10, + -43, -15, 109, -24, -26, 95, -5, -36, 82, 14, -47, 69, + 33, -58, 55, 52, -68, 41, 70, -79, 28, 90, -90, 14, + -41, -16, 113, -22, -27, 99, -3, -38, 86, 16, -48, 73, + 35, -59, 59, 54, -70, 45, 73, -80, 32, 92, -91, 18, + -39, -18, 117, -19, -28, 103, 0, -39, 90, 18, -50, 77, + 38, -61, 63, 56, -71, 49, 75, -82, 36, 95, -93, 22, + -114, 29, -10, -95, 18, -24, -76, 7, -37, -57, -3, -51, + -38, -14, -64, -19, -24, -78, 0, -35, -91, 19, -46, -105, + -112, 27, -6, -92, 16, -20, -73, 6, -33, -55, -4, -47, + -35, -15, -60, -16, -25, -74, 2, -36, -87, 22, -47, -101, + -109, 26, -2, -90, 15, -16, -71, 4, -29, -52, -5, -43, + -33, -16, -56, -14, -27, -70, 5, -37, -83, 24, -48, -97, + -106, 24, 2, -87, 13, -11, -68, 3, -25, -50, -7, -38, + -30, -18, -52, -11, -28, -65, 7, -39, -79, 27, -50, -92, + -104, 23, 6, -85, 12, -7, -66, 1, -21, -47, -8, -34, + -28, -19, -48, -9, -30, -61, 10, -40, -75, 29, -51, -88, + -102, 22, 10, -82, 11, -3, -64, 0, -17, -45, -10, -30, + -25, -20, -44, -7, -31, -57, 12, -42, -71, 32, -53, -84, + -99, 20, 14, -80, 9, 0, -61, 0, -13, -42, -11, -26, + -23, -22, -40, -4, -32, -53, 15, -43, -67, 34, -54, -80, + -97, 19, 18, -77, 8, 4, -58, -2, -8, -40, -12, -22, + -20, -23, -35, -1, -34, -49, 17, -45, -62, 37, -55, -76, + -94, 17, 22, -75, 6, 8, -56, -3, -4, -37, -14, -18, + -18, -25, -31, 1, -35, -45, 20, -46, -58, 39, -57, -72, + -92, 16, 26, -72, 5, 12, -54, -4, 0, -35, -15, -14, + -15, -26, -27, 3, -37, -41, 22, -47, -54, 41, -58, -68, + -89, 15, 30, -70, 4, 16, -51, -6, 3, -32, -16, -10, + -13, -27, -23, 6, -38, -37, 24, -49, -50, 44, -60, -64, + -87, 13, 34, -68, 2, 20, -49, -7, 7, -30, -18, -6, + -11, -29, -19, 8, -39, -33, 27, -50, -46, 46, -61, -60, + -84, 12, 39, -65, 1, 25, -46, -9, 11, -27, -19, -1, + -8, -30, -15, 11, -41, -28, 30, -51, -42, 49, -62, -55, + -82, 10, 43, -63, 0, 29, -44, -10, 15, -25, -21, 2, + -6, -32, -11, 13, -42, -24, 32, -53, -38, 51, -64, -51, + -80, 9, 47, -60, -1, 33, -41, -11, 19, -23, -22, 6, + -3, -33, -7, 16, -44, -20, 34, -54, -34, 54, -65, -47, + -77, 8, 51, -58, -2, 37, -39, -13, 23, -20, -23, 10, + -1, -34, -3, 18, -45, -16, 37, -55, -30, 56, -66, -43, + -74, 6, 55, -55, -4, 41, -36, -14, 28, -18, -25, 14, + 2, -36, 1, 21, -46, -12, 39, -57, -25, 59, -68, -39, + -72, 5, 59, -53, -5, 45, -34, -16, 32, -15, -26, 18, + 4, -37, 5, 23, -48, -8, 42, -58, -21, 61, -69, -35, + -70, 4, 63, -50, -6, 49, -32, -17, 36, -13, -28, 22, + 7, -39, 9, 25, -49, -4, 44, -60, -17, 64, -71, -31, + -67, 2, 67, -48, -8, 53, -29, -18, 40, -10, -29, 26, + 9, -40, 13, 28, -50, 0, 47, -61, -13, 66, -72, -27, + -65, 1, 72, -45, -9, 58, -26, -20, 44, -8, -30, 31, + 12, -41, 17, 30, -52, 4, 49, -63, -9, 69, -74, -22, + -62, 0, 76, -43, -11, 62, -24, -21, 48, -5, -32, 35, + 14, -43, 21, 33, -53, 8, 52, -64, -5, 71, -75, -18, + -60, -1, 80, -40, -12, 66, -22, -23, 52, -3, -33, 39, + 16, -44, 25, 35, -55, 12, 54, -65, -1, 73, -76, -14, + -57, -2, 84, -38, -13, 70, -19, -24, 56, 0, -34, 43, + 19, -45, 29, 38, -56, 16, 56, -67, 2, 76, -78, -10, + -55, -4, 88, -36, -15, 74, -17, -25, 60, 2, -36, 47, + 21, -47, 33, 40, -57, 20, 59, -68, 6, 78, -79, -6, + -52, -5, 92, -33, -16, 78, -14, -27, 65, 5, -37, 51, + 24, -48, 38, 43, -59, 24, 62, -70, 11, 81, -80, -2, + -50, -7, 96, -31, -18, 82, -12, -28, 69, 7, -39, 55, + 26, -50, 42, 45, -60, 28, 64, -71, 15, 83, -82, 1, + -48, -8, 100, -28, -19, 86, -9, -29, 73, 9, -40, 59, + 29, -51, 46, 48, -62, 32, 66, -72, 19, 86, -83, 5, + -45, -9, 104, -26, -20, 90, -7, -31, 77, 12, -41, 63, + 31, -52, 50, 50, -63, 36, 69, -74, 23, 88, -84, 9, + -42, -11, 109, -23, -22, 95, -4, -32, 81, 14, -43, 68, + 34, -54, 54, 53, -64, 41, 71, -75, 27, 91, -86, 14, + -40, -12, 113, -21, -23, 99, -2, -34, 85, 17, -44, 72, + 36, -55, 58, 55, -66, 45, 74, -76, 31, 93, -87, 18, + -38, -14, 117, -18, -24, 103, 0, -35, 89, 19, -46, 76, + 39, -57, 62, 57, -67, 49, 76, -78, 35, 96, -89, 22, + -113, 33, -11, -94, 22, -24, -75, 11, -38, -56, 0, -51, + -37, -10, -65, -18, -20, -78, 1, -31, -92, 20, -42, -106, + -111, 31, -7, -91, 20, -20, -72, 10, -34, -54, 0, -47, + -34, -11, -61, -16, -21, -74, 3, -32, -88, 23, -43, -102, + -108, 30, -3, -89, 19, -16, -70, 8, -30, -51, -1, -43, + -32, -12, -57, -13, -23, -70, 6, -33, -84, 25, -44, -98, + -106, 28, 1, -86, 17, -12, -67, 7, -25, -49, -3, -39, + -29, -14, -52, -10, -24, -66, 8, -35, -79, 28, -46, -93, + -103, 27, 5, -84, 16, -8, -65, 5, -21, -46, -4, -35, + -27, -15, -48, -8, -26, -62, 11, -36, -75, 30, -47, -89, + -101, 26, 9, -81, 15, -4, -63, 4, -17, -44, -6, -31, + -24, -16, -44, -6, -27, -58, 13, -38, -71, 32, -49, -85, + -98, 24, 13, -79, 13, 0, -60, 3, -13, -41, -7, -27, + -22, -18, -40, -3, -28, -54, 16, -39, -67, 35, -50, -81, + -96, 23, 17, -76, 12, 4, -58, 1, -9, -39, -8, -22, + -19, -19, -36, -1, -30, -49, 18, -41, -63, 38, -51, -77, + -93, 21, 21, -74, 10, 8, -55, 0, -5, -36, -10, -18, + -17, -21, -32, 2, -31, -45, 21, -42, -59, 40, -53, -73, + -91, 20, 25, -72, 9, 12, -53, 0, -1, -34, -11, -14, + -15, -22, -28, 4, -33, -41, 23, -43, -55, 42, -54, -69, + -89, 19, 29, -69, 8, 16, -50, -2, 2, -32, -12, -10, + -12, -23, -24, 7, -34, -37, 25, -45, -51, 45, -56, -65, + -86, 17, 33, -67, 6, 20, -48, -3, 6, -29, -14, -6, + -10, -25, -20, 9, -35, -33, 28, -46, -47, 47, -57, -61, + -83, 16, 38, -64, 5, 24, -45, -5, 11, -26, -15, -2, + -7, -26, -15, 12, -37, -29, 30, -47, -42, 50, -58, -56, + -81, 14, 42, -62, 4, 28, -43, -6, 15, -24, -17, 1, + -5, -28, -11, 14, -38, -25, 33, -49, -38, 52, -60, -52, + -79, 13, 46, -59, 2, 32, -40, -7, 19, -22, -18, 5, + -2, -29, -7, 16, -40, -21, 35, -50, -34, 55, -61, -48, + -76, 12, 50, -57, 1, 36, -38, -9, 23, -19, -19, 9, + 0, -30, -3, 19, -41, -17, 38, -51, -30, 57, -62, -44, + -74, 10, 54, -54, 0, 41, -35, -10, 27, -17, -21, 14, + 3, -32, 0, 22, -42, -12, 40, -53, -26, 60, -64, -40, + -71, 9, 58, -52, -1, 45, -33, -12, 31, -14, -22, 18, + 5, -33, 4, 24, -44, -8, 43, -54, -22, 62, -65, -36, + -69, 8, 62, -49, -2, 49, -31, -13, 35, -12, -24, 22, + 8, -35, 8, 26, -45, -4, 45, -56, -18, 64, -67, -32, + -66, 6, 66, -47, -4, 53, -28, -14, 39, -9, -25, 26, + 10, -36, 12, 29, -46, 0, 48, -57, -14, 67, -68, -28, + -64, 5, 71, -44, -5, 57, -26, -16, 44, -7, -26, 30, + 13, -37, 17, 31, -48, 3, 50, -59, -9, 70, -70, -23, + -61, 3, 75, -42, -7, 61, -23, -17, 48, -4, -28, 34, + 15, -39, 21, 34, -49, 7, 53, -60, -5, 72, -71, -19, + -59, 2, 79, -40, -8, 65, -21, -19, 52, -2, -29, 38, + 17, -40, 25, 36, -51, 11, 55, -61, -1, 74, -72, -15, + -57, 1, 83, -37, -9, 69, -18, -20, 56, 0, -30, 42, + 20, -41, 29, 39, -52, 15, 57, -63, 2, 77, -74, -11, + -54, 0, 87, -35, -11, 73, -16, -21, 60, 3, -32, 46, + 22, -43, 33, 41, -53, 19, 60, -64, 6, 79, -75, -7, + -51, -1, 91, -32, -12, 78, -13, -23, 64, 6, -33, 51, + 25, -44, 37, 44, -55, 24, 62, -66, 10, 82, -76, -3, + -49, -3, 95, -30, -14, 82, -11, -24, 68, 8, -35, 55, + 27, -46, 41, 46, -56, 28, 65, -67, 14, 84, -78, 0, + -47, -4, 99, -27, -15, 86, -8, -25, 72, 10, -36, 59, + 30, -47, 45, 48, -58, 32, 67, -68, 18, 87, -79, 4, + -44, -5, 103, -25, -16, 90, -6, -27, 76, 13, -37, 63, + 32, -48, 49, 51, -59, 36, 70, -70, 22, 89, -80, 8, + -42, -7, 108, -22, -18, 94, -3, -28, 81, 15, -39, 67, + 35, -50, 54, 54, -60, 40, 72, -71, 27, 92, -82, 13, + -39, -8, 112, -20, -19, 98, -1, -30, 85, 18, -40, 71, + 37, -51, 58, 56, -62, 44, 75, -72, 31, 94, -83, 17, + -37, -10, 116, -17, -20, 102, 1, -31, 89, 20, -42, 75, + 40, -53, 62, 58, -63, 48, 77, -74, 35, 96, -85, 21, + -112, 37, -11, -93, 26, -25, -74, 15, -38, -55, 4, -52, + -36, -6, -66, -17, -16, -79, 2, -27, -92, 21, -38, -106, + -110, 35, -7, -90, 24, -21, -72, 14, -34, -53, 3, -48, + -33, -7, -62, -15, -17, -75, 4, -28, -88, 24, -39, -102, + -107, 34, -3, -88, 23, -17, -69, 12, -30, -50, 2, -44, + -31, -8, -58, -12, -19, -71, 7, -29, -84, 26, -40, -98, + -105, 32, 0, -85, 21, -13, -66, 11, -26, -48, 0, -39, + -28, -10, -53, -10, -20, -67, 9, -31, -80, 29, -42, -94, + -102, 31, 4, -83, 20, -9, -64, 9, -22, -45, 0, -35, + -26, -11, -49, -7, -22, -63, 12, -32, -76, 31, -43, -90, + -100, 30, 8, -80, 19, -5, -62, 8, -18, -43, -2, -31, + -24, -12, -45, -5, -23, -59, 14, -34, -72, 33, -45, -86, + -97, 28, 12, -78, 17, -1, -59, 7, -14, -41, -3, -27, + -21, -14, -41, -2, -24, -55, 16, -35, -68, 36, -46, -82, + -95, 27, 17, -75, 16, 3, -57, 5, -9, -38, -4, -23, + -18, -15, -37, 0, -26, -50, 19, -37, -63, 38, -47, -77, + -92, 25, 21, -73, 14, 7, -54, 4, -5, -35, -6, -19, + -16, -17, -33, 3, -27, -46, 22, -38, -59, 41, -49, -73, + -90, 24, 25, -71, 13, 11, -52, 3, -1, -33, -7, -15, + -14, -18, -29, 5, -29, -42, 24, -39, -55, 43, -50, -69, + -88, 23, 29, -68, 12, 15, -49, 1, 2, -31, -8, -11, + -11, -19, -25, 8, -30, -38, 26, -41, -51, 46, -52, -65, + -85, 21, 33, -66, 10, 19, -47, 0, 6, -28, -10, -7, + -9, -21, -21, 10, -31, -34, 29, -42, -47, 48, -53, -61, + -83, 20, 37, -63, 9, 23, -44, -1, 10, -26, -11, -2, + -6, -22, -16, 13, -33, -30, 31, -43, -43, 51, -54, -57, + -80, 18, 41, -61, 8, 27, -42, -2, 14, -23, -13, 1, + -4, -24, -12, 15, -34, -26, 34, -45, -39, 53, -56, -53, + -78, 17, 45, -58, 6, 31, -40, -3, 18, -21, -14, 5, + -1, -25, -8, 17, -36, -22, 36, -46, -35, 56, -57, -49, + -75, 16, 49, -56, 5, 35, -37, -5, 22, -18, -15, 9, + 1, -26, -4, 20, -37, -18, 39, -47, -31, 58, -58, -45, + -73, 14, 54, -53, 3, 40, -34, -6, 27, -16, -17, 13, + 4, -28, 0, 22, -38, -13, 41, -49, -26, 61, -60, -40, + -70, 13, 58, -51, 2, 44, -32, -8, 31, -13, -18, 17, + 6, -29, 3, 25, -40, -9, 44, -50, -22, 63, -61, -36, + -68, 12, 62, -48, 1, 48, -30, -9, 35, -11, -20, 21, + 8, -31, 7, 27, -41, -5, 46, -52, -18, 65, -63, -32, + -65, 10, 66, -46, 0, 52, -27, -10, 39, -9, -21, 25, + 11, -32, 11, 30, -42, -1, 48, -53, -14, 68, -64, -28, + -63, 9, 70, -43, -1, 56, -25, -12, 43, -6, -22, 30, + 14, -33, 16, 32, -44, 2, 51, -55, -10, 70, -66, -24, + -60, 7, 74, -41, -3, 60, -22, -13, 47, -3, -24, 34, + 16, -35, 20, 35, -45, 6, 53, -56, -6, 73, -67, -20, + -58, 6, 78, -39, -4, 64, -20, -15, 51, -1, -25, 38, + 18, -36, 24, 37, -47, 10, 56, -57, -2, 75, -68, -16, + -56, 5, 82, -36, -5, 68, -17, -16, 55, 1, -26, 42, + 21, -37, 28, 39, -48, 14, 58, -59, 1, 78, -70, -12, + -53, 3, 86, -34, -7, 72, -15, -17, 59, 4, -28, 46, + 23, -39, 32, 42, -49, 18, 61, -60, 5, 80, -71, -8, + -51, 2, 91, -31, -8, 77, -12, -19, 64, 6, -29, 50, + 26, -40, 36, 45, -51, 23, 63, -62, 10, 83, -72, -3, + -48, 0, 95, -29, -10, 81, -10, -20, 68, 9, -31, 54, + 28, -42, 40, 47, -52, 27, 66, -63, 14, 85, -74, 0, + -46, 0, 99, -26, -11, 85, -8, -21, 72, 11, -32, 58, + 31, -43, 44, 49, -54, 31, 68, -64, 18, 88, -75, 4, + -43, -1, 103, -24, -12, 89, -5, -23, 76, 14, -33, 62, + 33, -44, 48, 52, -55, 35, 71, -66, 22, 90, -76, 8, + -41, -3, 107, -21, -14, 93, -2, -24, 80, 16, -35, 67, + 36, -46, 53, 54, -56, 39, 73, -67, 26, 93, -78, 12, + -38, -4, 111, -19, -15, 97, 0, -26, 84, 19, -36, 71, + 38, -47, 57, 57, -58, 43, 76, -68, 30, 95, -79, 16, + -36, -6, 115, -16, -16, 101, 2, -27, 88, 21, -38, 75, + 40, -49, 61, 59, -59, 47, 78, -70, 34, 97, -81, 20, + -111, 41, -12, -92, 30, -26, -73, 19, -39, -54, 8, -52, + -35, -2, -66, -16, -12, -80, 3, -23, -93, 22, -34, -107, + -109, 39, -8, -89, 28, -22, -71, 18, -35, -52, 7, -48, + -32, -3, -62, -14, -13, -76, 5, -24, -89, 24, -35, -103, + -106, 38, -4, -87, 27, -18, -68, 16, -31, -49, 6, -44, + -30, -4, -58, -11, -15, -72, 7, -25, -85, 27, -36, -99, + -104, 36, 0, -84, 25, -13, -66, 15, -27, -47, 4, -40, + -27, -6, -54, -9, -16, -67, 10, -27, -81, 30, -38, -94, + -101, 35, 4, -82, 24, -9, -63, 13, -23, -44, 3, -36, + -25, -7, -50, -6, -18, -63, 13, -28, -77, 32, -39, -90, + -99, 34, 8, -80, 23, -5, -61, 12, -19, -42, 1, -32, + -23, -8, -46, -4, -19, -59, 15, -30, -73, 34, -41, -86, + -97, 32, 12, -77, 21, -1, -58, 11, -15, -40, 0, -28, + -20, -10, -42, -1, -20, -55, 17, -31, -69, 37, -42, -82, + -94, 31, 16, -74, 20, 2, -56, 9, -10, -37, 0, -23, + -18, -11, -37, 1, -22, -51, 20, -33, -64, 39, -43, -78, + -91, 29, 20, -72, 18, 6, -53, 8, -6, -35, -2, -19, + -15, -13, -33, 4, -23, -47, 22, -34, -60, 42, -45, -74, + -89, 28, 24, -70, 17, 10, -51, 7, -2, -32, -3, -15, + -13, -14, -29, 6, -25, -43, 25, -35, -56, 44, -46, -70, + -87, 27, 28, -67, 16, 14, -49, 5, 1, -30, -4, -11, + -10, -15, -25, 8, -26, -39, 27, -37, -52, 47, -48, -66, + -84, 25, 32, -65, 14, 18, -46, 4, 5, -27, -6, -7, + -8, -17, -21, 11, -27, -35, 30, -38, -48, 49, -49, -62, + -82, 24, 37, -62, 13, 23, -43, 2, 9, -25, -7, -3, + -5, -18, -17, 13, -29, -30, 32, -39, -44, 52, -50, -57, + -79, 22, 41, -60, 12, 27, -41, 1, 13, -22, -9, 0, + -3, -20, -13, 16, -30, -26, 35, -41, -40, 54, -52, -53, + -77, 21, 45, -57, 10, 31, -39, 0, 17, -20, -10, 4, + -1, -21, -9, 18, -32, -22, 37, -42, -36, 56, -53, -49, + -74, 20, 49, -55, 9, 35, -36, -1, 21, -17, -11, 8, + 2, -22, -5, 21, -33, -18, 39, -43, -32, 59, -54, -45, + -72, 18, 53, -52, 7, 39, -34, -2, 26, -15, -13, 13, + 5, -24, 0, 23, -34, -14, 42, -45, -27, 62, -56, -41, + -69, 17, 57, -50, 6, 43, -31, -4, 30, -12, -14, 17, + 7, -25, 3, 26, -36, -10, 45, -46, -23, 64, -57, -37, + -67, 16, 61, -48, 5, 47, -29, -5, 34, -10, -16, 21, + 9, -27, 7, 28, -37, -6, 47, -48, -19, 66, -59, -33, + -65, 14, 65, -45, 3, 51, -26, -6, 38, -8, -17, 25, + 12, -28, 11, 31, -38, -2, 49, -49, -15, 69, -60, -29, + -62, 13, 70, -42, 2, 56, -24, -8, 42, -5, -18, 29, + 14, -29, 15, 33, -40, 2, 52, -51, -11, 71, -62, -24, + -59, 11, 74, -40, 0, 60, -21, -9, 46, -3, -20, 33, + 17, -31, 19, 36, -41, 6, 54, -52, -7, 74, -63, -20, + -57, 10, 78, -38, 0, 64, -19, -11, 50, 0, -21, 37, + 19, -32, 23, 38, -43, 10, 57, -53, -3, 76, -64, -16, + -55, 9, 82, -35, -1, 68, -17, -12, 54, 2, -22, 41, + 22, -33, 27, 40, -44, 14, 59, -55, 0, 79, -66, -12, + -52, 7, 86, -33, -3, 72, -14, -13, 58, 5, -24, 45, + 24, -35, 31, 43, -45, 18, 62, -56, 4, 81, -67, -8, + -50, 6, 90, -30, -4, 76, -11, -15, 63, 7, -25, 50, + 27, -36, 36, 45, -47, 22, 64, -58, 9, 84, -68, -4, + -47, 4, 94, -28, -6, 80, -9, -16, 67, 10, -27, 54, + 29, -38, 40, 48, -48, 26, 67, -59, 13, 86, -70, 0, + -45, 3, 98, -25, -7, 84, -7, -17, 71, 12, -28, 58, + 31, -39, 44, 50, -50, 30, 69, -60, 17, 88, -71, 3, + -42, 2, 102, -23, -8, 88, -4, -19, 75, 15, -29, 62, + 34, -40, 48, 53, -51, 34, 71, -62, 21, 91, -72, 7, + -40, 0, 107, -20, -10, 93, -2, -20, 79, 17, -31, 66, + 37, -42, 52, 55, -52, 39, 74, -63, 25, 94, -74, 12, + -37, 0, 111, -18, -11, 97, 1, -22, 83, 20, -32, 70, + 39, -43, 56, 58, -54, 43, 77, -64, 29, 96, -75, 16, + -35, -2, 115, -16, -12, 101, 3, -23, 87, 22, -34, 74, + 41, -45, 60, 60, -55, 47, 79, -66, 33, 98, -77, 20, + -110, 45, -13, -91, 34, -26, -72, 23, -40, -53, 13, -53, + -34, 2, -67, -15, -8, -80, 4, -18, -94, 23, -29, -108, + -108, 44, -9, -88, 33, -22, -70, 22, -36, -51, 12, -49, + -31, 1, -63, -13, -9, -76, 6, -20, -90, 25, -31, -104, + -105, 42, -5, -86, 31, -18, -67, 21, -32, -48, 10, -45, + -29, 0, -59, -10, -10, -72, 8, -21, -86, 28, -32, -100, + -103, 41, 0, -83, 30, -14, -65, 19, -27, -46, 9, -41, + -26, -1, -55, -8, -12, -68, 11, -22, -81, 31, -33, -95, + -100, 39, 3, -81, 29, -10, -62, 18, -23, -43, 7, -37, + -24, -3, -51, -5, -13, -64, 14, -24, -77, 33, -35, -91, + -98, 38, 7, -79, 27, -6, -60, 17, -19, -41, 6, -33, + -22, -4, -47, -3, -15, -60, 16, -25, -73, 35, -36, -87, + -96, 37, 11, -76, 26, -2, -57, 15, -15, -39, 5, -29, + -19, -5, -43, 0, -16, -56, 18, -27, -69, 38, -37, -83, + -93, 35, 15, -73, 24, 2, -55, 14, -11, -36, 3, -24, + -17, -7, -38, 2, -17, -51, 21, -28, -65, 40, -39, -79, + -90, 34, 19, -71, 23, 6, -52, 12, -7, -33, 2, -20, + -14, -8, -34, 5, -19, -47, 23, -29, -61, 43, -40, -75, + -88, 33, 23, -69, 22, 10, -50, 11, -3, -31, 0, -16, + -12, -10, -30, 7, -20, -43, 26, -31, -57, 45, -42, -71, + -86, 31, 27, -66, 20, 14, -47, 10, 0, -29, 0, -12, + -9, -11, -26, 9, -21, -39, 28, -32, -53, 48, -43, -67, + -83, 30, 31, -64, 19, 18, -45, 8, 4, -26, -1, -8, + -7, -12, -22, 12, -23, -35, 31, -33, -49, 50, -44, -63, + -81, 28, 36, -61, 17, 22, -42, 7, 9, -24, -3, -4, + -4, -14, -18, 15, -24, -31, 33, -35, -44, 53, -46, -58, + -78, 27, 40, -59, 16, 26, -40, 5, 13, -21, -4, 0, + -2, -15, -14, 17, -26, -27, 36, -36, -40, 55, -47, -54, + -76, 26, 44, -56, 15, 30, -38, 4, 17, -19, -6, 3, + 1, -16, -10, 19, -27, -23, 38, -38, -36, 57, -49, -50, + -73, 24, 48, -54, 13, 34, -35, 3, 21, -16, -7, 7, + 3, -18, -6, 22, -28, -19, 40, -39, -32, 60, -50, -46, + -71, 23, 52, -51, 12, 39, -33, 1, 25, -14, -8, 12, + 6, -19, -1, 24, -30, -14, 43, -41, -28, 63, -51, -42, + -68, 21, 56, -49, 10, 43, -30, 0, 29, -11, -10, 16, + 8, -21, 2, 27, -31, -10, 46, -42, -24, 65, -53, -38, + -66, 20, 60, -47, 9, 47, -28, 0, 33, -9, -11, 20, + 10, -22, 6, 29, -33, -6, 48, -43, -20, 67, -54, -34, + -64, 19, 64, -44, 8, 51, -25, -2, 37, -7, -12, 24, + 13, -23, 10, 32, -34, -2, 50, -45, -16, 70, -55, -30, + -61, 17, 69, -41, 6, 55, -23, -3, 42, -4, -14, 28, + 15, -25, 14, 34, -35, 1, 53, -46, -11, 72, -57, -25, + -58, 16, 73, -39, 5, 59, -20, -5, 46, -2, -15, 32, + 18, -26, 18, 37, -37, 5, 55, -47, -7, 75, -58, -21, + -56, 14, 77, -37, 4, 63, -18, -6, 50, 1, -17, 36, + 20, -28, 22, 39, -38, 9, 58, -49, -3, 77, -60, -17, + -54, 13, 81, -34, 2, 67, -16, -7, 54, 3, -18, 40, + 23, -29, 26, 41, -40, 13, 60, -50, 0, 80, -61, -13, + -51, 12, 85, -32, 1, 71, -13, -9, 58, 6, -19, 44, + 25, -30, 30, 44, -41, 17, 63, -51, 4, 82, -62, -9, + -49, 10, 89, -29, 0, 76, -10, -10, 62, 8, -21, 49, + 28, -32, 35, 47, -42, 22, 65, -53, 8, 85, -64, -5, + -46, 9, 93, -27, -1, 80, -8, -12, 66, 11, -22, 53, + 30, -33, 39, 49, -44, 26, 68, -54, 12, 87, -65, -1, + -44, 8, 97, -24, -2, 84, -6, -13, 70, 13, -24, 57, + 33, -34, 43, 51, -45, 30, 70, -56, 16, 89, -67, 2, + -41, 6, 101, -22, -4, 88, -3, -14, 74, 16, -25, 61, + 35, -36, 47, 54, -46, 34, 72, -57, 20, 92, -68, 6, + -39, 5, 106, -19, -5, 92, -1, -16, 79, 18, -26, 65, + 38, -37, 51, 56, -48, 38, 75, -59, 25, 95, -70, 11, + -36, 3, 110, -17, -7, 96, 2, -17, 83, 21, -28, 69, + 40, -39, 55, 59, -49, 42, 78, -60, 29, 97, -71, 15, + -34, 2, 114, -15, -8, 100, 4, -19, 87, 23, -29, 73, + 42, -40, 59, 61, -51, 46, 80, -61, 33, 99, -72, 19, + -109, 49, -13, -90, 38, -27, -71, 27, -40, -52, 17, -54, + -33, 6, -68, -14, -4, -81, 5, -14, -94, 24, -25, -108, + -107, 48, -9, -87, 37, -23, -69, 26, -36, -50, 16, -50, + -31, 5, -64, -12, -5, -77, 7, -16, -90, 26, -27, -104, + -104, 46, -5, -85, 35, -19, -66, 25, -32, -48, 14, -46, + -28, 3, -60, -9, -6, -73, 9, -17, -86, 29, -28, -100, + -102, 45, -1, -82, 34, -15, -64, 23, -28, -45, 13, -41, + -25, 2, -55, -7, -8, -69, 12, -18, -82, 31, -29, -96, + -99, 43, 2, -80, 33, -11, -61, 22, -24, -42, 11, -37, + -23, 0, -51, -4, -9, -65, 14, -20, -78, 34, -31, -92, + -97, 42, 6, -78, 31, -7, -59, 21, -20, -40, 10, -33, + -21, 0, -47, -2, -11, -61, 17, -21, -74, 36, -32, -88, + -95, 41, 10, -75, 30, -3, -56, 19, -16, -38, 9, -29, + -18, -1, -43, 0, -12, -57, 19, -23, -70, 39, -33, -84, + -92, 39, 15, -73, 28, 1, -54, 18, -11, -35, 7, -25, + -16, -3, -39, 3, -13, -52, 22, -24, -65, 41, -35, -79, + -90, 38, 19, -70, 27, 5, -51, 16, -7, -33, 6, -21, + -13, -4, -35, 6, -15, -48, 24, -25, -61, 44, -36, -75, + -87, 37, 23, -68, 26, 9, -49, 15, -3, -30, 4, -17, + -11, -6, -31, 8, -16, -44, 27, -27, -57, 46, -38, -71, + -85, 35, 27, -65, 24, 13, -47, 14, 0, -28, 3, -13, + -8, -7, -27, 10, -17, -40, 29, -28, -53, 49, -39, -67, + -82, 34, 31, -63, 23, 17, -44, 12, 4, -25, 2, -9, + -6, -8, -23, 13, -19, -36, 32, -29, -49, 51, -40, -63, + -80, 32, 35, -60, 21, 21, -42, 11, 8, -23, 0, -4, + -3, -10, -18, 15, -20, -32, 34, -31, -45, 54, -42, -59, + -77, 31, 39, -58, 20, 25, -39, 9, 12, -20, 0, 0, + -1, -11, -14, 18, -22, -28, 37, -32, -41, 56, -43, -55, + -75, 30, 43, -56, 19, 29, -37, 8, 16, -18, -2, 3, + 1, -12, -10, 20, -23, -24, 39, -34, -37, 58, -45, -51, + -72, 28, 47, -53, 17, 33, -34, 7, 20, -16, -3, 7, + 4, -14, -6, 23, -24, -20, 41, -35, -33, 61, -46, -47, + -70, 27, 52, -50, 16, 38, -32, 5, 25, -13, -4, 11, + 7, -15, -2, 25, -26, -15, 44, -37, -28, 63, -47, -42, + -67, 25, 56, -48, 14, 42, -29, 4, 29, -10, -6, 15, + 9, -17, 1, 28, -27, -11, 46, -38, -24, 66, -49, -38, + -65, 24, 60, -46, 13, 46, -27, 3, 33, -8, -7, 19, + 11, -18, 5, 30, -29, -7, 49, -39, -20, 68, -50, -34, + -63, 23, 64, -43, 12, 50, -24, 1, 37, -6, -8, 23, + 14, -19, 9, 32, -30, -3, 51, -41, -16, 71, -51, -30, + -60, 21, 68, -41, 10, 54, -22, 0, 41, -3, -10, 28, + 16, -21, 14, 35, -31, 0, 54, -42, -12, 73, -53, -26, + -58, 20, 72, -38, 9, 58, -19, -1, 45, -1, -11, 32, + 19, -22, 18, 38, -33, 4, 56, -43, -8, 76, -54, -22, + -55, 18, 76, -36, 8, 62, -17, -2, 49, 2, -13, 36, + 21, -24, 22, 40, -34, 8, 59, -45, -4, 78, -56, -18, + -53, 17, 80, -33, 6, 66, -15, -3, 53, 4, -14, 40, + 24, -25, 26, 42, -36, 12, 61, -46, 0, 81, -57, -14, + -50, 16, 84, -31, 5, 70, -12, -5, 57, 7, -15, 44, + 26, -26, 30, 45, -37, 16, 64, -47, 3, 83, -58, -10, + -48, 14, 89, -28, 3, 75, -10, -6, 62, 9, -17, 48, + 29, -28, 34, 47, -38, 21, 66, -49, 8, 86, -60, -5, + -45, 13, 93, -26, 2, 79, -7, -8, 66, 12, -18, 52, + 31, -29, 38, 50, -40, 25, 69, -50, 12, 88, -61, -1, + -43, 12, 97, -24, 1, 83, -5, -9, 70, 14, -20, 56, + 33, -30, 42, 52, -41, 29, 71, -52, 16, 90, -63, 2, + -40, 10, 101, -21, 0, 87, -2, -10, 74, 16, -21, 60, + 36, -32, 46, 55, -42, 33, 73, -53, 20, 93, -64, 6, + -38, 9, 105, -18, -1, 91, 0, -12, 78, 19, -22, 65, + 39, -33, 51, 57, -44, 37, 76, -55, 24, 95, -66, 10, + -35, 7, 109, -16, -3, 95, 3, -13, 82, 22, -24, 69, + 41, -35, 55, 60, -45, 41, 78, -56, 28, 98, -67, 14, + -33, 6, 113, -14, -4, 99, 5, -15, 86, 24, -25, 73, + 43, -36, 59, 62, -47, 45, 81, -57, 32, 100, -68, 18, + -108, 53, -14, -89, 42, -28, -70, 31, -41, -51, 21, -54, + -32, 10, -68, -13, 0, -82, 6, -10, -95, 25, -21, -109, + -106, 52, -10, -87, 41, -24, -68, 30, -37, -49, 20, -50, + -30, 9, -64, -11, -1, -78, 8, -12, -91, 27, -23, -105, + -104, 50, -6, -84, 39, -20, -65, 29, -33, -47, 18, -46, + -27, 7, -60, -8, -2, -74, 10, -13, -87, 30, -24, -101, + -101, 49, -1, -81, 38, -15, -63, 27, -29, -44, 17, -42, + -25, 6, -56, -6, -4, -69, 13, -14, -83, 32, -25, -96, + -98, 47, 2, -79, 37, -11, -60, 26, -25, -42, 15, -38, + -22, 4, -52, -3, -5, -65, 15, -16, -79, 35, -27, -92, + -96, 46, 6, -77, 35, -7, -58, 25, -21, -39, 14, -34, + -20, 3, -48, -1, -7, -61, 18, -17, -75, 37, -28, -88, + -94, 45, 10, -74, 34, -3, -56, 23, -17, -37, 13, -30, + -17, 2, -44, 1, -8, -57, 20, -19, -71, 40, -29, -84, + -91, 43, 14, -72, 32, 0, -53, 22, -12, -34, 11, -25, + -15, 0, -39, 4, -9, -53, 23, -20, -66, 42, -31, -80, + -89, 42, 18, -69, 31, 4, -50, 20, -8, -32, 10, -21, + -12, 0, -35, 6, -11, -49, 25, -21, -62, 45, -32, -76, + -86, 41, 22, -67, 30, 8, -48, 19, -4, -29, 8, -17, + -10, -2, -31, 9, -12, -45, 28, -23, -58, 47, -34, -72, + -84, 39, 26, -64, 28, 12, -46, 18, 0, -27, 7, -13, + -8, -3, -27, 11, -13, -41, 30, -24, -54, 49, -35, -68, + -81, 38, 30, -62, 27, 16, -43, 16, 3, -24, 6, -9, + -5, -4, -23, 14, -15, -37, 32, -25, -50, 52, -36, -64, + -79, 36, 35, -59, 25, 21, -41, 15, 7, -22, 4, -5, + -2, -6, -19, 16, -16, -32, 35, -27, -46, 55, -38, -59, + -76, 35, 39, -57, 24, 25, -38, 13, 11, -19, 3, -1, + 0, -7, -15, 19, -18, -28, 38, -28, -42, 57, -39, -55, + -74, 34, 43, -55, 23, 29, -36, 12, 15, -17, 1, 2, + 2, -8, -11, 21, -19, -24, 40, -30, -38, 59, -41, -51, + -72, 32, 47, -52, 21, 33, -33, 11, 19, -15, 0, 6, + 5, -10, -7, 24, -20, -20, 42, -31, -34, 62, -42, -47, + -69, 31, 51, -50, 20, 37, -31, 9, 24, -12, 0, 11, + 7, -11, -2, 26, -22, -16, 45, -33, -29, 64, -43, -43, + -66, 29, 55, -47, 18, 41, -28, 8, 28, -10, -2, 15, + 10, -13, 1, 29, -23, -12, 47, -34, -25, 67, -45, -39, + -64, 28, 59, -45, 17, 45, -26, 7, 32, -7, -3, 19, + 12, -14, 5, 31, -25, -8, 50, -35, -21, 69, -46, -35, + -62, 27, 63, -42, 16, 49, -24, 5, 36, -5, -4, 23, + 15, -15, 9, 33, -26, -4, 52, -37, -17, 72, -47, -31, + -59, 25, 68, -40, 14, 54, -21, 4, 40, -2, -6, 27, + 17, -17, 13, 36, -27, 0, 55, -38, -13, 74, -49, -26, + -57, 24, 72, -37, 13, 58, -18, 2, 44, 0, -7, 31, + 20, -18, 17, 38, -29, 4, 57, -39, -9, 77, -50, -22, + -54, 22, 76, -35, 12, 62, -16, 1, 48, 3, -9, 35, + 22, -20, 21, 41, -30, 8, 60, -41, -5, 79, -52, -18, + -52, 21, 80, -32, 10, 66, -14, 0, 52, 5, -10, 39, + 24, -21, 25, 43, -32, 12, 62, -42, -1, 81, -53, -14, + -49, 20, 84, -30, 9, 70, -11, -1, 56, 7, -11, 43, + 27, -22, 29, 46, -33, 16, 64, -43, 2, 84, -54, -10, + -47, 18, 88, -27, 7, 74, -9, -2, 61, 10, -13, 48, + 30, -24, 34, 48, -34, 20, 67, -45, 7, 86, -56, -6, + -44, 17, 92, -25, 6, 78, -6, -4, 65, 13, -14, 52, + 32, -25, 38, 51, -36, 24, 70, -46, 11, 89, -57, -2, + -42, 16, 96, -23, 5, 82, -4, -5, 69, 15, -16, 56, + 34, -26, 42, 53, -37, 28, 72, -48, 15, 91, -59, 1, + -40, 14, 100, -20, 3, 86, -1, -6, 73, 17, -17, 60, + 37, -28, 46, 56, -38, 32, 74, -49, 19, 94, -60, 5, + -37, 13, 105, -18, 2, 91, 1, -8, 77, 20, -18, 64, + 39, -29, 50, 58, -40, 37, 77, -51, 23, 96, -62, 10, + -34, 11, 109, -15, 0, 95, 4, -9, 81, 22, -20, 68, + 42, -31, 54, 61, -41, 41, 79, -52, 27, 99, -63, 14, + -32, 10, 113, -13, 0, 99, 6, -11, 85, 25, -21, 72, + 44, -32, 58, 63, -43, 45, 82, -53, 31, 101, -64, 18, + -107, 57, -15, -88, 46, -28, -69, 35, -42, -50, 25, -55, + -31, 14, -69, -12, 3, -82, 6, -6, -96, 26, -17, -110, + -105, 56, -11, -86, 45, -24, -67, 34, -38, -48, 24, -51, + -29, 13, -65, -10, 2, -78, 9, -8, -92, 28, -19, -106, + -103, 54, -7, -83, 43, -20, -64, 33, -34, -46, 22, -47, + -26, 11, -61, -8, 1, -74, 11, -9, -88, 31, -20, -102, + -100, 53, -2, -81, 42, -16, -62, 31, -29, -43, 21, -43, + -24, 10, -56, -5, 0, -70, 14, -10, -83, 33, -21, -97, + -98, 51, 1, -78, 41, -12, -59, 30, -25, -41, 19, -39, + -21, 8, -52, -2, -1, -66, 16, -12, -79, 36, -23, -93, + -95, 50, 5, -76, 39, -8, -57, 29, -21, -38, 18, -35, + -19, 7, -48, 0, -3, -62, 19, -13, -75, 38, -24, -89, + -93, 49, 9, -73, 38, -4, -55, 27, -17, -36, 17, -31, + -16, 6, -44, 2, -4, -58, 21, -15, -71, 40, -25, -85, + -90, 47, 13, -71, 36, 0, -52, 26, -13, -33, 15, -26, + -14, 4, -40, 5, -5, -53, 24, -16, -67, 43, -27, -81, + -88, 46, 17, -68, 35, 4, -50, 24, -9, -31, 14, -22, + -11, 3, -36, 7, -7, -49, 26, -17, -63, 46, -28, -77, + -85, 45, 21, -66, 34, 8, -47, 23, -5, -28, 12, -18, + -9, 1, -32, 10, -8, -45, 29, -19, -59, 48, -30, -73, + -83, 43, 25, -64, 32, 12, -45, 22, -1, -26, 11, -14, + -7, 0, -28, 12, -9, -41, 31, -20, -55, 50, -31, -69, + -81, 42, 29, -61, 31, 16, -42, 20, 2, -24, 10, -10, + -4, 0, -24, 15, -11, -37, 33, -21, -51, 53, -32, -65, + -78, 40, 34, -58, 29, 20, -40, 19, 7, -21, 8, -6, + -2, -2, -19, 17, -12, -33, 36, -23, -46, 55, -34, -60, + -75, 39, 38, -56, 28, 24, -37, 17, 11, -19, 7, -2, + 1, -3, -15, 20, -14, -29, 38, -24, -42, 58, -35, -56, + -73, 38, 42, -54, 27, 28, -35, 16, 15, -16, 5, 1, + 3, -4, -11, 22, -15, -25, 41, -26, -38, 60, -37, -52, + -71, 36, 46, -51, 25, 32, -33, 15, 19, -14, 4, 5, + 6, -6, -7, 24, -16, -21, 43, -27, -34, 63, -38, -48, + -68, 35, 50, -49, 24, 37, -30, 13, 23, -11, 3, 10, + 8, -7, -3, 27, -18, -16, 46, -29, -30, 65, -39, -44, + -66, 33, 54, -46, 22, 41, -27, 12, 27, -9, 1, 14, + 11, -9, 0, 30, -19, -12, 48, -30, -26, 68, -41, -40, + -63, 32, 58, -44, 21, 45, -25, 11, 31, -6, 0, 18, + 13, -10, 4, 32, -21, -8, 51, -31, -22, 70, -42, -36, + -61, 31, 62, -41, 20, 49, -23, 9, 35, -4, 0, 22, + 16, -11, 8, 34, -22, -4, 53, -33, -18, 72, -43, -32, + -58, 29, 67, -39, 18, 53, -20, 8, 40, -1, -2, 26, + 18, -13, 13, 37, -23, 0, 56, -34, -13, 75, -45, -27, + -56, 28, 71, -36, 17, 57, -18, 6, 44, 1, -3, 30, + 21, -14, 17, 39, -25, 3, 58, -35, -9, 78, -46, -23, + -53, 26, 75, -34, 16, 61, -15, 5, 48, 4, -5, 34, + 23, -16, 21, 42, -26, 7, 61, -37, -5, 80, -48, -19, + -51, 25, 79, -32, 14, 65, -13, 4, 52, 6, -6, 38, + 25, -17, 25, 44, -28, 11, 63, -38, -1, 82, -49, -15, + -49, 24, 83, -29, 13, 69, -10, 2, 56, 8, -7, 42, + 28, -18, 29, 47, -29, 15, 65, -39, 2, 85, -50, -11, + -46, 22, 87, -26, 11, 74, -8, 1, 60, 11, -9, 47, + 30, -20, 33, 49, -30, 20, 68, -41, 6, 87, -52, -7, + -43, 21, 91, -24, 10, 78, -5, 0, 64, 13, -10, 51, + 33, -21, 37, 52, -32, 24, 70, -42, 10, 90, -53, -3, + -41, 20, 95, -22, 9, 82, -3, -1, 68, 16, -12, 55, + 35, -22, 41, 54, -33, 28, 73, -44, 14, 92, -55, 0, + -39, 18, 99, -19, 7, 86, -1, -2, 72, 18, -13, 59, + 38, -24, 45, 56, -34, 32, 75, -45, 18, 95, -56, 4, + -36, 17, 104, -17, 6, 90, 2, -4, 77, 21, -14, 63, + 40, -25, 50, 59, -36, 36, 78, -47, 23, 97, -58, 9, + -34, 15, 108, -14, 4, 94, 5, -5, 81, 23, -16, 67, + 43, -27, 54, 62, -37, 40, 80, -48, 27, 100, -59, 13, + -31, 14, 112, -12, 3, 98, 7, -7, 85, 26, -17, 71, + 45, -28, 58, 64, -39, 44, 83, -49, 31, 102, -60, 17, + -106, 62, -15, -87, 51, -29, -68, 40, -42, -49, 29, -56, + -30, 18, -70, -11, 8, -83, 7, -2, -96, 27, -13, -110, + -104, 60, -11, -85, 49, -25, -66, 39, -38, -47, 28, -52, + -28, 17, -66, -9, 7, -79, 10, -3, -92, 29, -14, -106, + -102, 59, -7, -82, 48, -21, -63, 37, -34, -45, 27, -48, + -25, 16, -62, -7, 5, -75, 12, -4, -88, 32, -15, -102, + -99, 57, -3, -80, 46, -17, -61, 36, -30, -42, 25, -43, + -23, 14, -57, -4, 4, -71, 15, -6, -84, 34, -17, -98, + -97, 56, 0, -77, 45, -13, -58, 34, -26, -40, 24, -39, + -20, 13, -53, -1, 2, -67, 17, -7, -80, 37, -18, -94, + -94, 55, 4, -75, 44, -9, -56, 33, -22, -37, 22, -35, + -18, 12, -49, 1, 1, -63, 20, -9, -76, 39, -20, -90, + -92, 53, 8, -72, 42, -5, -54, 32, -18, -35, 21, -31, + -15, 10, -45, 3, 0, -59, 22, -10, -72, 41, -21, -86, + -89, 52, 13, -70, 41, 0, -51, 30, -13, -32, 20, -27, + -13, 9, -41, 6, -1, -54, 25, -12, -67, 44, -22, -81, + -87, 50, 17, -67, 39, 3, -49, 29, -9, -30, 18, -23, + -10, 7, -37, 8, -2, -50, 27, -13, -63, 47, -24, -77, + -84, 49, 21, -65, 38, 7, -46, 28, -5, -27, 17, -19, + -8, 6, -33, 11, -4, -46, 30, -14, -59, 49, -25, -73, + -82, 48, 25, -63, 37, 11, -44, 26, -1, -25, 16, -15, + -6, 5, -29, 13, -5, -42, 32, -16, -55, 51, -27, -69, + -79, 46, 29, -60, 35, 15, -41, 25, 2, -23, 14, -11, + -3, 3, -25, 16, -6, -38, 34, -17, -51, 54, -28, -65, + -77, 45, 33, -57, 34, 19, -39, 23, 6, -20, 13, -6, + 0, 2, -20, 18, -8, -34, 37, -18, -47, 56, -29, -61, + -74, 43, 37, -55, 33, 23, -36, 22, 10, -17, 11, -2, + 2, 0, -16, 21, -9, -30, 39, -20, -43, 59, -31, -57, + -72, 42, 41, -53, 31, 27, -34, 21, 14, -15, 10, 1, + 4, 0, -12, 23, -11, -26, 42, -21, -39, 61, -32, -53, + -70, 41, 45, -50, 30, 31, -31, 19, 18, -13, 9, 5, + 7, -1, -8, 25, -12, -22, 44, -22, -35, 64, -33, -49, + -67, 39, 50, -48, 28, 36, -29, 18, 23, -10, 7, 9, + 9, -3, -4, 28, -13, -17, 47, -24, -30, 66, -35, -44, + -65, 38, 54, -45, 27, 40, -26, 16, 27, -8, 6, 13, + 12, -4, 0, 31, -15, -13, 49, -25, -26, 69, -36, -40, + -62, 37, 58, -43, 26, 44, -24, 15, 31, -5, 4, 17, + 14, -6, 3, 33, -16, -9, 52, -27, -22, 71, -38, -36, + -60, 35, 62, -40, 24, 48, -22, 14, 35, -3, 3, 21, + 17, -7, 7, 35, -17, -5, 54, -28, -18, 73, -39, -32, + -57, 34, 66, -38, 23, 52, -19, 12, 39, 0, 2, 26, + 19, -8, 12, 38, -19, -1, 57, -30, -14, 76, -41, -28, + -55, 32, 70, -35, 21, 56, -17, 11, 43, 2, 0, 30, + 22, -10, 16, 40, -20, 2, 59, -31, -10, 79, -42, -24, + -52, 31, 74, -33, 20, 60, -14, 9, 47, 5, 0, 34, + 24, -11, 20, 43, -22, 6, 62, -32, -6, 81, -43, -20, + -50, 30, 78, -31, 19, 64, -12, 8, 51, 7, -1, 38, + 26, -12, 24, 45, -23, 10, 64, -34, -2, 83, -45, -16, + -48, 28, 82, -28, 17, 68, -9, 7, 55, 9, -3, 42, + 29, -14, 28, 48, -24, 14, 66, -35, 1, 86, -46, -12, + -45, 27, 87, -25, 16, 73, -7, 5, 60, 12, -4, 46, + 31, -15, 32, 50, -26, 19, 69, -37, 6, 88, -47, -7, + -42, 25, 91, -23, 14, 77, -4, 4, 64, 15, -6, 50, + 34, -17, 36, 53, -27, 23, 71, -38, 10, 91, -49, -3, + -40, 24, 95, -21, 13, 81, -2, 3, 68, 17, -7, 54, + 36, -18, 40, 55, -29, 27, 74, -39, 14, 93, -50, 0, + -38, 23, 99, -18, 12, 85, 1, 1, 72, 19, -8, 58, + 39, -19, 44, 57, -30, 31, 76, -41, 18, 96, -51, 4, + -35, 21, 103, -16, 10, 89, 3, 0, 76, 22, -10, 63, + 41, -21, 49, 60, -31, 35, 79, -42, 22, 98, -53, 8, + -33, 20, 107, -13, 9, 93, 6, -1, 80, 24, -11, 67, + 44, -22, 53, 63, -33, 39, 81, -43, 26, 101, -54, 12, + -30, 18, 111, -11, 8, 97, 8, -2, 84, 27, -13, 71, + 46, -24, 57, 65, -34, 43, 84, -45, 30, 103, -56, 16, + -105, 66, -16, -86, 55, -30, -67, 44, -43, -49, 33, -57, + -29, 22, -70, -10, 12, -84, 8, 1, -97, 28, -9, -111, + -103, 64, -12, -84, 53, -26, -65, 43, -39, -46, 32, -53, + -27, 21, -66, -8, 11, -80, 11, 0, -93, 30, -10, -107, + -101, 63, -8, -81, 52, -22, -63, 41, -35, -44, 31, -49, + -24, 20, -62, -6, 9, -76, 13, 0, -89, 33, -11, -103, + -98, 61, -3, -79, 50, -17, -60, 40, -31, -41, 29, -44, + -22, 18, -58, -3, 8, -71, 16, -2, -85, 35, -13, -98, + -96, 60, 0, -76, 49, -13, -57, 38, -27, -39, 28, -40, + -19, 17, -54, -1, 6, -67, 18, -3, -81, 38, -14, -94, + -93, 59, 4, -74, 48, -9, -55, 37, -23, -36, 26, -36, + -17, 16, -50, 2, 5, -63, 21, -5, -77, 40, -16, -90, + -91, 57, 8, -71, 46, -5, -53, 36, -19, -34, 25, -32, + -15, 14, -46, 4, 4, -59, 23, -6, -73, 42, -17, -86, + -88, 56, 12, -69, 45, -1, -50, 34, -14, -31, 24, -28, + -12, 13, -41, 7, 2, -55, 26, -8, -68, 45, -18, -82, + -86, 54, 16, -66, 43, 2, -48, 33, -10, -29, 22, -24, + -9, 11, -37, 9, 1, -51, 28, -9, -64, 47, -20, -78, + -83, 53, 20, -64, 42, 6, -45, 32, -6, -26, 21, -20, + -7, 10, -33, 12, 0, -47, 31, -10, -60, 50, -21, -74, + -81, 52, 24, -62, 41, 10, -43, 30, -2, -24, 20, -16, + -5, 9, -29, 14, -1, -43, 33, -12, -56, 52, -23, -70, + -79, 50, 28, -59, 39, 14, -40, 29, 1, -22, 18, -12, + -2, 7, -25, 17, -2, -39, 35, -13, -52, 55, -24, -66, + -76, 49, 33, -57, 38, 19, -38, 27, 5, -19, 17, -7, + 0, 6, -21, 19, -4, -34, 38, -14, -48, 57, -25, -61, + -74, 47, 37, -54, 37, 23, -35, 26, 9, -17, 15, -3, + 3, 4, -17, 22, -5, -30, 40, -16, -44, 60, -27, -57, + -71, 46, 41, -52, 35, 27, -33, 25, 13, -14, 14, 0, + 5, 3, -13, 24, -7, -26, 43, -17, -40, 62, -28, -53, + -69, 45, 45, -49, 34, 31, -31, 23, 17, -12, 13, 4, + 8, 2, -9, 26, -8, -22, 45, -18, -36, 65, -29, -49, + -66, 43, 49, -47, 32, 35, -28, 22, 22, -9, 11, 8, + 10, 0, -4, 29, -9, -18, 48, -20, -31, 67, -31, -45, + -64, 42, 53, -44, 31, 39, -25, 20, 26, -7, 10, 12, + 13, 0, 0, 31, -11, -14, 50, -21, -27, 70, -32, -41, + -61, 41, 57, -42, 30, 43, -23, 19, 30, -4, 8, 16, + 15, -2, 3, 34, -12, -10, 53, -23, -23, 72, -34, -37, + -59, 39, 61, -39, 28, 47, -21, 18, 34, -2, 7, 20, + 17, -3, 7, 36, -13, -6, 55, -24, -19, 74, -35, -33, + -56, 38, 66, -37, 27, 52, -18, 16, 38, 1, 6, 25, + 20, -4, 11, 39, -15, -1, 58, -26, -15, 77, -37, -28, + -54, 36, 70, -34, 25, 56, -16, 15, 42, 3, 4, 29, + 23, -6, 15, 41, -16, 2, 60, -27, -11, 79, -38, -24, + -51, 35, 74, -32, 24, 60, -13, 13, 46, 6, 3, 33, + 25, -7, 19, 44, -18, 6, 63, -28, -7, 82, -39, -20, + -49, 34, 78, -30, 23, 64, -11, 12, 50, 8, 2, 37, + 27, -8, 23, 46, -19, 10, 65, -30, -3, 84, -41, -16, + -47, 32, 82, -27, 21, 68, -8, 11, 54, 10, 0, 41, + 30, -10, 27, 49, -20, 14, 67, -31, 0, 87, -42, -12, + -44, 31, 86, -25, 20, 72, -6, 9, 59, 13, 0, 45, + 32, -11, 32, 51, -22, 18, 70, -33, 5, 89, -43, -8, + -42, 29, 90, -22, 18, 76, -3, 8, 63, 15, -2, 49, + 35, -13, 36, 54, -23, 22, 72, -34, 9, 92, -45, -4, + -39, 28, 94, -20, 17, 80, -1, 7, 67, 18, -3, 53, + 37, -14, 40, 56, -25, 26, 75, -35, 13, 94, -46, 0, + -37, 27, 98, -17, 16, 84, 1, 5, 71, 20, -4, 57, + 40, -15, 44, 58, -26, 30, 77, -37, 17, 97, -47, 3, + -34, 25, 103, -15, 14, 89, 4, 4, 75, 23, -6, 62, + 42, -17, 48, 61, -27, 35, 80, -38, 21, 99, -49, 8, + -32, 24, 107, -12, 13, 93, 7, 2, 79, 25, -7, 66, + 45, -18, 52, 63, -29, 39, 82, -39, 25, 102, -50, 12, + -29, 22, 111, -10, 12, 97, 9, 1, 83, 28, -9, 70, + 47, -20, 56, 66, -30, 43, 85, -41, 29, 104, -52, 16, + -105, 70, -17, -85, 59, -30, -66, 48, -44, -48, 37, -57, + -28, 26, -71, -9, 16, -84, 9, 5, -98, 29, -5, -112, + -102, 68, -13, -83, 57, -26, -64, 47, -40, -45, 36, -53, + -26, 25, -67, -7, 15, -80, 12, 4, -94, 31, -6, -108, + -100, 67, -9, -80, 56, -22, -62, 45, -36, -43, 35, -49, + -23, 24, -63, -5, 13, -76, 14, 3, -90, 33, -7, -104, + -97, 65, -4, -78, 54, -18, -59, 44, -31, -40, 33, -45, + -21, 22, -58, -2, 12, -72, 17, 1, -85, 36, -9, -99, + -95, 64, 0, -75, 53, -14, -57, 42, -27, -38, 32, -41, + -18, 21, -54, 0, 10, -68, 19, 0, -81, 39, -10, -95, + -92, 63, 3, -73, 52, -10, -54, 41, -23, -35, 30, -37, + -16, 20, -50, 3, 9, -64, 22, -1, -77, 41, -12, -91, + -90, 61, 7, -71, 50, -6, -52, 40, -19, -33, 29, -33, + -14, 18, -46, 5, 8, -60, 24, -2, -73, 43, -13, -87, + -87, 60, 11, -68, 49, -1, -49, 38, -15, -30, 28, -28, + -11, 17, -42, 8, 6, -55, 27, -4, -69, 46, -14, -83, + -85, 58, 15, -65, 47, 2, -47, 37, -11, -28, 26, -24, + -9, 15, -38, 10, 5, -51, 29, -5, -65, 48, -16, -79, + -82, 57, 19, -63, 46, 6, -44, 36, -7, -26, 25, -20, + -6, 14, -34, 13, 3, -47, 31, -6, -61, 51, -17, -75, + -80, 56, 23, -61, 45, 10, -42, 34, -3, -23, 24, -16, + -4, 13, -30, 15, 2, -43, 34, -8, -57, 53, -19, -71, + -78, 54, 27, -58, 43, 14, -40, 33, 0, -21, 22, -12, + -1, 11, -26, 17, 1, -39, 36, -9, -53, 56, -20, -67, + -75, 53, 32, -56, 42, 18, -37, 31, 5, -18, 21, -8, + 1, 10, -21, 20, 0, -35, 39, -10, -48, 58, -21, -62, + -73, 51, 36, -53, 41, 22, -34, 30, 9, -16, 19, -4, + 4, 8, -17, 23, -1, -31, 41, -12, -44, 61, -23, -58, + -70, 50, 40, -51, 39, 26, -32, 29, 13, -13, 18, 0, + 6, 7, -13, 25, -3, -27, 44, -13, -40, 63, -24, -54, + -68, 49, 44, -48, 38, 30, -30, 27, 17, -11, 17, 3, + 9, 6, -9, 27, -4, -23, 46, -14, -36, 65, -25, -50, + -65, 47, 48, -46, 36, 35, -27, 26, 21, -8, 15, 8, + 11, 4, -5, 30, -5, -18, 49, -16, -32, 68, -27, -46, + -63, 46, 52, -43, 35, 39, -25, 24, 25, -6, 14, 12, + 14, 3, -1, 32, -7, -14, 51, -17, -28, 71, -28, -42, + -60, 45, 56, -41, 34, 43, -22, 23, 29, -3, 12, 16, + 16, 1, 2, 35, -8, -10, 54, -19, -24, 73, -30, -38, + -58, 43, 60, -39, 32, 47, -20, 22, 33, -1, 11, 20, + 18, 0, 6, 37, -9, -6, 56, -20, -20, 75, -31, -34, + -55, 42, 65, -36, 31, 51, -17, 20, 38, 2, 10, 24, + 21, 0, 11, 40, -11, -2, 59, -22, -15, 78, -33, -29, + -53, 40, 69, -33, 29, 55, -15, 19, 42, 4, 8, 28, + 23, -2, 15, 42, -12, 1, 61, -23, -11, 80, -34, -25, + -50, 39, 73, -31, 28, 59, -12, 17, 46, 6, 7, 32, + 26, -3, 19, 45, -14, 5, 63, -24, -7, 83, -35, -21, + -48, 38, 77, -29, 27, 63, -10, 16, 50, 9, 6, 36, + 28, -4, 23, 47, -15, 9, 66, -26, -3, 85, -37, -17, + -46, 36, 81, -26, 25, 67, -8, 15, 54, 11, 4, 40, + 31, -6, 27, 49, -16, 13, 68, -27, 0, 88, -38, -13, + -43, 35, 85, -24, 24, 72, -5, 13, 58, 14, 3, 45, + 33, -7, 31, 52, -18, 18, 71, -29, 4, 90, -39, -9, + -41, 33, 89, -21, 22, 76, -2, 12, 62, 16, 1, 49, + 36, -9, 35, 54, -19, 22, 73, -30, 8, 93, -41, -5, + -38, 32, 93, -19, 21, 80, 0, 11, 66, 19, 0, 53, + 38, -10, 39, 57, -21, 26, 76, -31, 12, 95, -42, -1, + -36, 31, 97, -16, 20, 84, 2, 9, 70, 21, 0, 57, + 40, -11, 43, 59, -22, 30, 78, -33, 16, 97, -43, 2, + -33, 29, 102, -14, 18, 88, 5, 8, 75, 24, -2, 61, + 43, -13, 48, 62, -23, 34, 81, -34, 21, 100, -45, 7, + -31, 28, 106, -11, 17, 92, 7, 6, 79, 26, -3, 65, + 46, -14, 52, 64, -25, 38, 83, -35, 25, 103, -46, 11, + -28, 26, 110, -9, 16, 96, 10, 5, 83, 29, -5, 69, + 48, -16, 56, 67, -26, 42, 86, -37, 29, 105, -48, 15, + -104, 74, -17, -84, 63, -31, -66, 52, -44, -47, 41, -58, + -27, 30, -72, -9, 20, -85, 10, 9, -98, 30, -1, -112, + -101, 72, -13, -82, 61, -27, -63, 51, -40, -44, 40, -54, + -25, 29, -68, -6, 19, -81, 13, 8, -94, 32, -2, -108, + -99, 71, -9, -80, 60, -23, -61, 49, -36, -42, 39, -50, + -23, 28, -64, -4, 17, -77, 15, 7, -90, 34, -3, -104, + -96, 69, -5, -77, 58, -19, -58, 48, -32, -39, 37, -45, + -20, 26, -59, -1, 16, -73, 18, 5, -86, 37, -5, -100, + -94, 68, -1, -74, 57, -15, -56, 46, -28, -37, 36, -41, + -17, 25, -55, 1, 14, -69, 20, 4, -82, 39, -6, -96, + -91, 67, 2, -72, 56, -11, -53, 45, -24, -34, 34, -37, + -15, 24, -51, 4, 13, -65, 22, 2, -78, 42, -8, -92, + -89, 65, 6, -70, 54, -7, -51, 44, -20, -32, 33, -33, + -13, 22, -47, 6, 12, -61, 25, 1, -74, 44, -9, -88, + -86, 64, 11, -67, 53, -2, -48, 42, -15, -29, 32, -29, + -10, 21, -43, 9, 10, -56, 28, 0, -69, 47, -10, -83, + -84, 62, 15, -65, 51, 1, -46, 41, -11, -27, 30, -25, + -8, 19, -39, 11, 9, -52, 30, -1, -65, 49, -12, -79, + -82, 61, 19, -62, 50, 5, -43, 40, -7, -25, 29, -21, + -5, 18, -35, 14, 7, -48, 32, -2, -61, 52, -13, -75, + -79, 60, 23, -60, 49, 9, -41, 38, -3, -22, 28, -17, + -3, 17, -31, 16, 6, -44, 35, -4, -57, 54, -15, -71, + -77, 58, 27, -57, 47, 13, -39, 37, 0, -20, 26, -13, + 0, 15, -27, 18, 5, -40, 37, -5, -53, 56, -16, -67, + -74, 57, 31, -55, 46, 17, -36, 35, 4, -17, 25, -8, + 2, 14, -22, 21, 3, -36, 40, -6, -49, 59, -17, -63, + -72, 55, 35, -52, 45, 21, -34, 34, 8, -15, 23, -4, + 5, 12, -18, 23, 2, -32, 42, -8, -45, 62, -19, -59, + -69, 54, 39, -50, 43, 25, -31, 33, 12, -12, 22, 0, + 7, 11, -14, 26, 0, -28, 45, -9, -41, 64, -20, -55, + -67, 53, 43, -48, 42, 29, -29, 31, 16, -10, 21, 3, + 9, 10, -10, 28, 0, -24, 47, -10, -37, 66, -21, -51, + -64, 51, 48, -45, 40, 34, -26, 30, 21, -7, 19, 7, + 12, 8, -6, 31, -1, -19, 50, -12, -32, 69, -23, -46, + -62, 50, 52, -42, 39, 38, -24, 28, 25, -5, 18, 11, + 14, 7, -2, 33, -3, -15, 52, -13, -28, 71, -24, -42, + -59, 49, 56, -40, 38, 42, -21, 27, 29, -2, 16, 15, + 17, 5, 1, 36, -4, -11, 54, -15, -24, 74, -26, -38, + -57, 47, 60, -38, 36, 46, -19, 26, 33, 0, 15, 19, + 19, 4, 5, 38, -5, -7, 57, -16, -20, 76, -27, -34, + -54, 46, 64, -35, 35, 50, -16, 24, 37, 3, 14, 24, + 22, 3, 10, 41, -7, -3, 60, -18, -16, 79, -29, -30, + -52, 44, 68, -33, 33, 54, -14, 23, 41, 5, 12, 28, + 24, 1, 14, 43, -8, 0, 62, -19, -12, 81, -30, -26, + -50, 43, 72, -30, 32, 58, -11, 21, 45, 7, 11, 32, + 27, 0, 18, 46, -10, 4, 64, -20, -8, 84, -31, -22, + -47, 42, 76, -28, 31, 62, -9, 20, 49, 10, 10, 36, + 29, 0, 22, 48, -11, 8, 67, -22, -4, 86, -33, -18, + -45, 40, 80, -25, 29, 66, -7, 19, 53, 12, 8, 40, + 32, -2, 26, 50, -12, 12, 69, -23, 0, 88, -34, -14, + -42, 39, 85, -23, 28, 71, -4, 17, 58, 15, 7, 44, + 34, -3, 30, 53, -14, 17, 72, -25, 4, 91, -35, -9, + -40, 37, 89, -20, 26, 75, -2, 16, 62, 17, 5, 48, + 37, -5, 34, 55, -15, 21, 74, -26, 8, 94, -37, -5, + -37, 36, 93, -18, 25, 79, 1, 15, 66, 20, 4, 52, + 39, -6, 38, 58, -17, 25, 77, -27, 12, 96, -38, -1, + -35, 35, 97, -16, 24, 83, 3, 13, 70, 22, 3, 56, + 41, -7, 42, 60, -18, 29, 79, -29, 16, 98, -39, 2, + -32, 33, 101, -13, 22, 87, 6, 12, 74, 25, 1, 61, + 44, -9, 47, 63, -19, 33, 82, -30, 20, 101, -41, 6, + -30, 32, 105, -10, 21, 91, 8, 10, 78, 27, 0, 65, + 46, -10, 51, 65, -21, 37, 84, -31, 24, 103, -42, 10, + -27, 30, 109, -8, 20, 95, 11, 9, 82, 30, -1, 69, + 49, -12, 55, 68, -22, 41, 86, -33, 28, 106, -44, 14, + -103, 78, -18, -83, 67, -32, -64, 56, -45, -46, 46, -59, + -26, 35, -72, -8, 24, -86, 11, 14, -99, 31, 3, -113, + -100, 77, -14, -81, 66, -28, -62, 55, -41, -43, 45, -55, + -24, 34, -68, -5, 23, -82, 14, 12, -95, 33, 1, -109, + -98, 75, -10, -78, 64, -24, -60, 54, -37, -41, 43, -51, + -22, 32, -64, -3, 22, -78, 16, 11, -91, 35, 0, -105, + -95, 74, -5, -76, 63, -19, -57, 52, -33, -38, 42, -46, + -19, 31, -60, 0, 20, -73, 19, 10, -87, 38, 0, -100, + -93, 72, -1, -73, 62, -15, -55, 51, -29, -36, 40, -42, + -16, 29, -56, 2, 19, -69, 21, 8, -83, 40, -2, -96, + -90, 71, 2, -71, 60, -11, -52, 50, -25, -33, 39, -38, + -14, 28, -52, 5, 17, -65, 23, 7, -79, 43, -3, -92, + -88, 70, 6, -69, 59, -7, -50, 48, -21, -31, 38, -34, + -12, 27, -48, 7, 16, -61, 26, 5, -75, 45, -4, -88, + -85, 68, 10, -66, 57, -3, -47, 47, -16, -28, 36, -30, + -9, 25, -43, 10, 15, -57, 29, 4, -70, 48, -6, -84, + -83, 67, 14, -64, 56, 0, -45, 45, -12, -26, 35, -26, + -7, 24, -39, 12, 13, -53, 31, 3, -66, 50, -7, -80, + -81, 66, 18, -61, 55, 4, -42, 44, -8, -24, 33, -22, + -4, 22, -35, 15, 12, -49, 33, 1, -62, 53, -9, -76, + -78, 64, 22, -59, 53, 8, -40, 43, -4, -21, 32, -18, + -2, 21, -31, 17, 11, -45, 36, 0, -58, 55, -10, -72, + -76, 63, 26, -56, 52, 12, -38, 41, 0, -19, 31, -14, + 1, 20, -27, 19, 9, -41, 38, 0, -54, 58, -11, -68, + -73, 61, 31, -54, 50, 17, -35, 40, 3, -16, 29, -9, + 3, 18, -23, 22, 8, -36, 41, -2, -50, 60, -13, -63, + -71, 60, 35, -51, 49, 21, -32, 38, 7, -14, 28, -5, + 6, 17, -19, 24, 6, -32, 43, -3, -46, 63, -14, -59, + -68, 59, 39, -49, 48, 25, -30, 37, 11, -11, 26, -1, + 8, 16, -15, 27, 5, -28, 46, -5, -42, 65, -16, -55, + -66, 57, 43, -46, 46, 29, -28, 36, 15, -9, 25, 2, + 10, 14, -11, 29, 4, -24, 48, -6, -38, 67, -17, -51, + -63, 56, 47, -44, 45, 33, -25, 34, 20, -6, 24, 6, + 13, 13, -6, 32, 2, -20, 51, -8, -33, 70, -18, -47, + -61, 54, 51, -41, 43, 37, -23, 33, 24, -4, 22, 10, + 16, 11, -2, 34, 1, -16, 53, -9, -29, 72, -20, -43, + -58, 53, 55, -39, 42, 41, -20, 32, 28, -1, 21, 14, + 18, 10, 1, 37, 0, -12, 55, -10, -25, 75, -21, -39, + -56, 52, 59, -37, 41, 45, -18, 30, 32, 1, 20, 18, + 20, 9, 5, 39, -1, -8, 58, -12, -21, 77, -22, -35, + -53, 50, 64, -34, 39, 50, -15, 29, 36, 4, 18, 23, + 23, 7, 9, 42, -2, -3, 61, -13, -17, 80, -24, -30, + -51, 49, 68, -32, 38, 54, -13, 27, 40, 6, 17, 27, + 25, 6, 13, 44, -4, 0, 63, -14, -13, 82, -25, -26, + -49, 47, 72, -29, 37, 58, -10, 26, 44, 8, 15, 31, + 28, 4, 17, 47, -5, 4, 65, -16, -9, 85, -27, -22, + -46, 46, 76, -27, 35, 62, -8, 25, 48, 11, 14, 35, + 30, 3, 21, 49, -7, 8, 68, -17, -5, 87, -28, -18, + -44, 45, 80, -24, 34, 66, -6, 23, 52, 13, 13, 39, + 33, 2, 25, 51, -8, 12, 70, -18, -1, 90, -29, -14, + -41, 43, 84, -22, 32, 70, -3, 22, 57, 16, 11, 43, + 35, 0, 30, 54, -9, 16, 73, -20, 3, 92, -31, -10, + -39, 42, 88, -19, 31, 74, -1, 20, 61, 18, 10, 47, + 38, 0, 34, 56, -11, 20, 75, -21, 7, 95, -32, -6, + -36, 41, 92, -17, 30, 78, 2, 19, 65, 21, 8, 51, + 40, -1, 38, 59, -12, 24, 78, -23, 11, 97, -34, -2, + -34, 39, 96, -15, 28, 82, 4, 18, 69, 23, 7, 55, + 42, -3, 42, 61, -13, 28, 80, -24, 15, 99, -35, 1, + -31, 38, 101, -12, 27, 87, 7, 16, 73, 26, 6, 60, + 45, -4, 46, 64, -15, 33, 83, -26, 19, 102, -37, 6, + -29, 36, 105, -9, 25, 91, 9, 15, 77, 28, 4, 64, + 48, -6, 50, 66, -16, 37, 85, -27, 23, 104, -38, 10, + -26, 35, 109, -7, 24, 95, 12, 13, 81, 31, 3, 68, + 50, -7, 54, 69, -18, 41, 87, -28, 27, 107, -39, 14, + -102, 82, -19, -82, 71, -32, -64, 60, -46, -45, 50, -59, + -25, 39, -73, -7, 28, -86, 12, 18, -100, 32, 7, -114, + -99, 81, -15, -80, 70, -28, -61, 59, -42, -42, 49, -55, + -23, 38, -69, -4, 27, -82, 15, 16, -96, 34, 5, -110, + -97, 79, -11, -78, 68, -24, -59, 58, -38, -40, 47, -51, + -21, 36, -65, -2, 26, -78, 17, 15, -92, 36, 4, -106, + -94, 78, -6, -75, 67, -20, -56, 56, -33, -37, 46, -47, + -18, 35, -61, 1, 24, -74, 20, 14, -87, 39, 3, -101, + -92, 76, -2, -72, 66, -16, -54, 55, -29, -35, 44, -43, + -16, 33, -57, 3, 23, -70, 22, 12, -83, 41, 1, -97, + -89, 75, 1, -70, 64, -12, -51, 54, -25, -33, 43, -39, + -13, 32, -53, 6, 21, -66, 24, 11, -79, 44, 0, -93, + -87, 74, 5, -68, 63, -8, -49, 52, -21, -30, 42, -35, + -11, 31, -49, 8, 20, -62, 27, 9, -75, 46, 0, -89, + -84, 72, 9, -65, 61, -3, -46, 51, -17, -27, 40, -30, + -8, 29, -44, 11, 19, -57, 29, 8, -71, 49, -2, -85, + -82, 71, 13, -63, 60, 0, -44, 49, -13, -25, 39, -26, + -6, 28, -40, 13, 17, -53, 32, 7, -67, 51, -3, -81, + -80, 70, 17, -60, 59, 4, -41, 48, -9, -23, 37, -22, + -3, 26, -36, 15, 16, -49, 34, 5, -63, 54, -5, -77, + -77, 68, 21, -58, 57, 8, -39, 47, -5, -20, 36, -18, + -1, 25, -32, 18, 15, -45, 37, 4, -59, 56, -6, -73, + -75, 67, 25, -55, 56, 12, -37, 45, -1, -18, 35, -14, + 1, 24, -28, 20, 13, -41, 39, 3, -55, 58, -7, -69, + -72, 65, 30, -53, 54, 16, -34, 44, 3, -15, 33, -10, + 4, 22, -24, 23, 12, -37, 42, 1, -50, 61, -9, -64, + -70, 64, 34, -50, 53, 20, -32, 42, 7, -13, 32, -6, + 7, 21, -20, 25, 10, -33, 44, 0, -46, 64, -10, -60, + -67, 63, 38, -48, 52, 24, -29, 41, 11, -10, 30, -2, + 9, 20, -16, 28, 9, -29, 47, -1, -42, 66, -12, -56, + -65, 61, 42, -46, 50, 28, -27, 40, 15, -8, 29, 1, + 11, 18, -12, 30, 8, -25, 49, -2, -38, 68, -13, -52, + -62, 60, 46, -43, 49, 33, -24, 38, 19, -5, 28, 6, + 14, 17, -7, 33, 6, -20, 52, -4, -34, 71, -14, -48, + -60, 58, 50, -41, 47, 37, -22, 37, 23, -3, 26, 10, + 16, 15, -3, 35, 5, -16, 54, -5, -30, 73, -16, -44, + -57, 57, 54, -38, 46, 41, -19, 36, 27, -1, 25, 14, + 19, 14, 0, 38, 3, -12, 56, -6, -26, 76, -17, -40, + -55, 56, 58, -36, 45, 45, -17, 34, 31, 2, 24, 18, + 21, 13, 4, 40, 2, -8, 59, -8, -22, 78, -18, -36, + -52, 54, 63, -33, 43, 49, -14, 33, 36, 5, 22, 22, + 24, 11, 8, 43, 1, -4, 61, -9, -17, 81, -20, -31, + -50, 53, 67, -31, 42, 53, -12, 31, 40, 7, 21, 26, + 26, 10, 12, 45, 0, 0, 64, -10, -13, 83, -21, -27, + -48, 51, 71, -28, 41, 57, -9, 30, 44, 9, 19, 30, + 29, 8, 16, 47, -1, 3, 66, -12, -9, 86, -23, -23, + -45, 50, 75, -26, 39, 61, -7, 29, 48, 12, 18, 34, + 31, 7, 20, 50, -3, 7, 69, -13, -5, 88, -24, -19, + -43, 49, 79, -23, 38, 65, -5, 27, 52, 14, 17, 38, + 33, 6, 24, 52, -4, 11, 71, -14, -1, 90, -25, -15, + -40, 47, 83, -21, 36, 70, -2, 26, 56, 17, 15, 43, + 36, 4, 29, 55, -5, 16, 74, -16, 2, 93, -27, -11, + -38, 46, 87, -18, 35, 74, 0, 24, 60, 19, 14, 47, + 39, 3, 33, 57, -7, 20, 76, -17, 6, 96, -28, -7, + -35, 45, 91, -16, 34, 78, 3, 23, 64, 22, 12, 51, + 41, 2, 37, 60, -8, 24, 79, -19, 10, 98, -30, -3, + -33, 43, 95, -14, 32, 82, 5, 22, 68, 24, 11, 55, + 43, 0, 41, 62, -9, 28, 81, -20, 14, 100, -31, 0, + -30, 42, 100, -11, 31, 86, 8, 20, 73, 27, 10, 59, + 46, 0, 45, 65, -11, 32, 84, -22, 19, 103, -33, 5, + -28, 40, 104, -9, 29, 90, 10, 19, 77, 29, 8, 63, + 48, -2, 49, 67, -12, 36, 86, -23, 23, 105, -34, 9, + -25, 39, 108, -6, 28, 94, 13, 17, 81, 31, 7, 67, + 51, -3, 53, 70, -14, 40, 88, -24, 27, 108, -35, 13, + -101, 86, -19, -81, 75, -33, -63, 64, -46, -44, 54, -60, + -25, 43, -74, -6, 32, -87, 13, 22, -100, 32, 11, -114, + -98, 85, -15, -79, 74, -29, -60, 63, -42, -41, 53, -56, + -22, 42, -70, -3, 31, -83, 15, 20, -96, 35, 9, -110, + -96, 83, -11, -77, 72, -25, -58, 62, -38, -39, 51, -52, + -20, 40, -66, -1, 30, -79, 18, 19, -92, 37, 8, -106, + -93, 82, -7, -74, 71, -21, -55, 60, -34, -36, 50, -47, + -17, 39, -61, 2, 28, -75, 21, 18, -88, 40, 7, -102, + -91, 80, -3, -72, 70, -17, -53, 59, -30, -34, 48, -43, + -15, 37, -57, 4, 27, -71, 23, 16, -84, 42, 5, -98, + -89, 79, 0, -69, 68, -13, -50, 58, -26, -32, 47, -39, + -12, 36, -53, 7, 25, -67, 25, 15, -80, 45, 4, -94, + -86, 78, 4, -67, 67, -9, -48, 56, -22, -29, 46, -35, + -10, 35, -49, 9, 24, -63, 28, 13, -76, 47, 3, -90, + -83, 76, 9, -64, 65, -4, -45, 55, -17, -27, 44, -31, + -7, 33, -45, 12, 23, -58, 30, 12, -71, 50, 1, -85, + -81, 75, 13, -62, 64, 0, -43, 53, -13, -24, 43, -27, + -5, 32, -41, 14, 21, -54, 33, 11, -67, 52, 0, -81, + -79, 74, 17, -59, 63, 3, -41, 52, -9, -22, 41, -23, + -2, 30, -37, 16, 20, -50, 35, 9, -63, 55, -1, -77, + -76, 72, 21, -57, 61, 7, -38, 51, -5, -19, 40, -19, + 0, 29, -33, 19, 19, -46, 38, 8, -59, 57, -2, -73, + -74, 71, 25, -55, 60, 11, -36, 49, -1, -17, 39, -15, + 2, 28, -29, 21, 17, -42, 40, 7, -55, 59, -3, -69, + -71, 69, 29, -52, 58, 15, -33, 48, 2, -14, 37, -10, + 5, 26, -24, 24, 16, -38, 43, 5, -51, 62, -5, -65, + -69, 68, 33, -49, 57, 19, -31, 46, 6, -12, 36, -6, + 7, 25, -20, 26, 14, -34, 45, 4, -47, 64, -6, -61, + -66, 67, 37, -47, 56, 23, -28, 45, 10, -9, 34, -2, + 10, 24, -16, 29, 13, -30, 47, 2, -43, 67, -8, -57, + -64, 65, 41, -45, 54, 27, -26, 44, 14, -7, 33, 1, + 12, 22, -12, 31, 12, -26, 50, 1, -39, 69, -9, -53, + -61, 64, 46, -42, 53, 32, -23, 42, 19, -4, 32, 5, + 15, 21, -8, 34, 10, -21, 53, 0, -34, 72, -10, -48, + -59, 62, 50, -40, 51, 36, -21, 41, 23, -2, 30, 9, + 17, 19, -4, 36, 9, -17, 55, -1, -30, 74, -12, -44, + -57, 61, 54, -37, 50, 40, -18, 40, 27, 0, 29, 13, + 20, 18, 0, 39, 7, -13, 57, -2, -26, 77, -13, -40, + -54, 60, 58, -35, 49, 44, -16, 38, 31, 3, 28, 17, + 22, 17, 3, 41, 6, -9, 60, -4, -22, 79, -14, -36, + -51, 58, 62, -32, 47, 48, -13, 37, 35, 5, 26, 22, + 25, 15, 8, 44, 5, -5, 62, -5, -18, 82, -16, -32, + -49, 57, 66, -30, 46, 52, -11, 35, 39, 8, 25, 26, + 27, 14, 12, 46, 3, -1, 65, -6, -14, 84, -17, -28, + -47, 55, 70, -27, 45, 56, -9, 34, 43, 10, 23, 30, + 30, 12, 16, 48, 2, 2, 67, -8, -10, 87, -19, -24, + -44, 54, 74, -25, 43, 60, -6, 33, 47, 13, 22, 34, + 32, 11, 20, 51, 0, 6, 70, -9, -6, 89, -20, -20, + -42, 53, 78, -23, 42, 64, -4, 31, 51, 15, 21, 38, + 34, 10, 24, 53, 0, 10, 72, -10, -2, 91, -21, -16, + -39, 51, 83, -20, 40, 69, -1, 30, 56, 18, 19, 42, + 37, 8, 28, 56, -1, 15, 75, -12, 2, 94, -23, -11, + -37, 50, 87, -17, 39, 73, 1, 28, 60, 20, 18, 46, + 39, 7, 32, 58, -3, 19, 77, -13, 6, 96, -24, -7, + -34, 49, 91, -15, 38, 77, 4, 27, 64, 22, 16, 50, + 42, 6, 36, 61, -4, 23, 79, -15, 10, 99, -26, -3, + -32, 47, 95, -13, 36, 81, 6, 26, 68, 25, 15, 54, + 44, 4, 40, 63, -5, 27, 82, -16, 14, 101, -27, 0, + -29, 46, 99, -10, 35, 85, 9, 24, 72, 28, 14, 59, + 47, 3, 45, 66, -7, 31, 85, -18, 18, 104, -29, 4, + -27, 44, 103, -8, 33, 89, 11, 23, 76, 30, 12, 63, + 49, 1, 49, 68, -8, 35, 87, -19, 22, 106, -30, 8, + -25, 43, 107, -5, 32, 93, 14, 21, 80, 32, 11, 67, + 52, 0, 53, 71, -10, 39, 89, -20, 26, 109, -31, 12, + -100, 90, -20, -81, 79, -34, -62, 68, -47, -43, 58, -61, + -24, 47, -74, -5, 36, -88, 14, 26, -101, 33, 15, -115, + -98, 89, -16, -78, 78, -30, -59, 67, -43, -41, 57, -57, + -21, 46, -70, -2, 35, -84, 16, 24, -97, 36, 13, -111, + -95, 87, -12, -76, 76, -26, -57, 66, -39, -38, 55, -53, + -19, 44, -66, 0, 34, -80, 19, 23, -93, 38, 12, -107, + -92, 86, -7, -73, 75, -21, -54, 64, -35, -35, 54, -48, + -16, 43, -62, 3, 32, -75, 21, 22, -89, 41, 11, -102, + -90, 84, -3, -71, 74, -17, -52, 63, -31, -33, 52, -44, + -14, 41, -58, 5, 31, -71, 24, 20, -85, 43, 9, -98, + -88, 83, 0, -68, 72, -13, -49, 62, -27, -31, 51, -40, + -11, 40, -54, 7, 29, -67, 26, 19, -81, 46, 8, -94, + -85, 82, 4, -66, 71, -9, -47, 60, -23, -28, 50, -36, + -9, 39, -50, 10, 28, -63, 29, 17, -77, 48, 7, -90, + -83, 80, 8, -63, 69, -5, -44, 59, -18, -26, 48, -32, + -6, 37, -45, 13, 27, -59, 31, 16, -72, 51, 5, -86, + -80, 79, 12, -61, 68, -1, -42, 57, -14, -23, 47, -28, + -4, 36, -41, 15, 25, -55, 34, 15, -68, 53, 4, -82, + -78, 78, 16, -58, 67, 2, -40, 56, -10, -21, 45, -24, + -1, 34, -37, 17, 24, -51, 36, 13, -64, 55, 2, -78, + -75, 76, 20, -56, 65, 6, -37, 55, -6, -18, 44, -20, + 1, 33, -33, 20, 23, -47, 38, 12, -60, 58, 1, -74, + -73, 75, 24, -54, 64, 10, -35, 53, -2, -16, 43, -16, + 3, 32, -29, 22, 21, -43, 41, 11, -56, 60, 0, -70, + -70, 73, 29, -51, 62, 15, -32, 52, 1, -13, 41, -11, + 6, 30, -25, 25, 20, -38, 44, 9, -52, 63, -1, -65, + -68, 72, 33, -49, 61, 19, -30, 50, 5, -11, 40, -7, + 8, 29, -21, 27, 18, -34, 46, 8, -48, 65, -2, -61, + -66, 71, 37, -46, 60, 23, -27, 49, 9, -9, 38, -3, + 11, 28, -17, 30, 17, -30, 48, 6, -44, 68, -4, -57, + -63, 69, 41, -44, 58, 27, -25, 48, 13, -6, 37, 0, + 13, 26, -13, 32, 16, -26, 51, 5, -40, 70, -5, -53, + -60, 68, 45, -41, 57, 31, -22, 46, 18, -4, 36, 4, + 16, 25, -8, 35, 14, -22, 53, 3, -35, 73, -6, -49, + -58, 66, 49, -39, 55, 35, -20, 45, 22, -1, 34, 8, + 18, 23, -4, 37, 13, -18, 56, 2, -31, 75, -8, -45, + -56, 65, 53, -36, 54, 39, -18, 44, 26, 1, 33, 12, + 21, 22, 0, 39, 11, -14, 58, 1, -27, 78, -9, -41, + -53, 64, 57, -34, 53, 43, -15, 42, 30, 4, 32, 16, + 23, 21, 3, 42, 10, -10, 61, 0, -23, 80, -10, -37, + -51, 62, 62, -31, 51, 48, -12, 41, 34, 6, 30, 21, + 26, 19, 7, 45, 9, -5, 63, -1, -19, 83, -12, -32, + -48, 61, 66, -29, 50, 52, -10, 39, 38, 9, 29, 25, + 28, 18, 11, 47, 7, -1, 66, -2, -15, 85, -13, -28, + -46, 59, 70, -26, 49, 56, -8, 38, 42, 11, 27, 29, + 31, 16, 15, 49, 6, 2, 68, -4, -11, 87, -15, -24, + -43, 58, 74, -24, 47, 60, -5, 37, 46, 14, 26, 33, + 33, 15, 19, 52, 4, 6, 70, -5, -7, 90, -16, -20, + -41, 57, 78, -22, 46, 64, -3, 35, 50, 16, 25, 37, + 35, 14, 23, 54, 3, 10, 73, -6, -3, 92, -17, -16, + -38, 55, 82, -19, 44, 68, 0, 34, 55, 19, 23, 41, + 38, 12, 28, 57, 2, 14, 76, -8, 1, 95, -19, -12, + -36, 54, 86, -17, 43, 72, 2, 32, 59, 21, 22, 45, + 40, 11, 32, 59, 0, 18, 78, -9, 5, 97, -20, -8, + -34, 53, 90, -14, 42, 76, 5, 31, 63, 23, 20, 49, + 43, 10, 36, 62, 0, 22, 80, -11, 9, 100, -22, -4, + -31, 51, 94, -12, 40, 80, 7, 30, 67, 26, 19, 53, + 45, 8, 40, 64, -1, 26, 83, -12, 13, 102, -23, 0, + -28, 50, 99, -9, 39, 85, 10, 28, 71, 28, 18, 58, + 48, 7, 44, 67, -3, 31, 85, -14, 17, 105, -25, 4, + -26, 48, 103, -7, 37, 89, 12, 27, 75, 31, 16, 62, + 50, 5, 48, 69, -4, 35, 88, -15, 21, 107, -26, 8, + -24, 47, 107, -4, 36, 93, 14, 25, 79, 33, 15, 66, + 53, 4, 52, 71, -6, 39, 90, -16, 25, 110, -27, 12, + -99, 94, -21, -80, 83, -34, -61, 72, -48, -42, 62, -61, + -23, 51, -75, -4, 40, -88, 15, 30, -102, 34, 19, -116, + -97, 93, -17, -77, 82, -30, -58, 71, -44, -40, 61, -57, + -20, 50, -71, -2, 39, -84, 17, 28, -98, 37, 17, -112, + -94, 91, -13, -75, 80, -26, -56, 70, -40, -37, 59, -53, + -18, 48, -67, 1, 38, -80, 20, 27, -94, 39, 16, -108, + -92, 90, -8, -72, 79, -22, -53, 68, -35, -35, 58, -49, + -15, 47, -62, 4, 36, -76, 22, 26, -89, 42, 15, -103, + -89, 88, -4, -70, 78, -18, -51, 67, -31, -32, 56, -45, + -13, 45, -58, 6, 35, -72, 25, 24, -85, 44, 13, -99, + -87, 87, 0, -67, 76, -14, -49, 66, -27, -30, 55, -41, + -10, 44, -54, 8, 33, -68, 27, 23, -81, 47, 12, -95, + -84, 86, 3, -65, 75, -10, -46, 64, -23, -27, 54, -37, + -8, 43, -50, 11, 32, -64, 30, 21, -77, 49, 11, -91, + -82, 84, 7, -62, 73, -5, -44, 63, -19, -25, 52, -32, + -5, 41, -46, 13, 31, -59, 32, 20, -73, 52, 9, -87, + -79, 83, 11, -60, 72, -1, -41, 61, -15, -22, 51, -28, + -3, 40, -42, 16, 29, -55, 35, 19, -69, 54, 8, -83, + -77, 82, 15, -58, 71, 2, -39, 60, -11, -20, 49, -24, + -1, 38, -38, 18, 28, -51, 37, 17, -65, 56, 6, -79, + -74, 80, 19, -55, 69, 6, -36, 59, -7, -18, 48, -20, + 2, 37, -34, 21, 27, -47, 39, 16, -61, 59, 5, -75, + -72, 79, 23, -53, 68, 10, -34, 57, -3, -15, 47, -16, + 4, 36, -30, 23, 25, -43, 42, 15, -57, 61, 4, -71, + -69, 77, 28, -50, 66, 14, -31, 56, 1, -12, 45, -12, + 7, 34, -25, 26, 24, -39, 44, 13, -52, 64, 2, -66, + -67, 76, 32, -48, 65, 18, -29, 54, 5, -10, 44, -8, + 9, 33, -21, 28, 22, -35, 47, 12, -48, 66, 1, -62, + -65, 75, 36, -45, 64, 22, -26, 53, 9, -8, 42, -4, + 12, 32, -17, 30, 21, -31, 49, 10, -44, 69, 0, -58, + -62, 73, 40, -43, 62, 26, -24, 52, 13, -5, 41, 0, + 14, 30, -13, 33, 20, -27, 52, 9, -40, 71, -1, -54, + -60, 72, 44, -40, 61, 31, -21, 50, 17, -3, 40, 4, + 17, 29, -9, 36, 18, -22, 54, 7, -36, 74, -2, -50, + -57, 70, 48, -38, 59, 35, -19, 49, 21, 0, 38, 8, + 19, 27, -5, 38, 17, -18, 57, 6, -32, 76, -4, -46, + -55, 69, 52, -35, 58, 39, -17, 48, 25, 2, 37, 12, + 22, 26, -1, 40, 15, -14, 59, 5, -28, 79, -5, -42, + -52, 68, 56, -33, 57, 43, -14, 46, 29, 5, 36, 16, + 24, 25, 2, 43, 14, -10, 62, 3, -24, 81, -6, -38, + -50, 66, 61, -30, 55, 47, -12, 45, 34, 7, 34, 20, + 27, 23, 7, 45, 13, -6, 64, 2, -19, 84, -8, -33, + -47, 65, 65, -28, 54, 51, -9, 43, 38, 10, 33, 24, + 29, 22, 11, 48, 11, -2, 67, 1, -15, 86, -9, -29, + -45, 63, 69, -26, 53, 55, -7, 42, 42, 12, 31, 28, + 31, 20, 15, 50, 10, 1, 69, 0, -11, 88, -11, -25, + -42, 62, 73, -23, 51, 59, -4, 41, 46, 14, 30, 32, + 34, 19, 19, 53, 8, 5, 71, -1, -7, 91, -12, -21, + -40, 61, 77, -21, 50, 63, -2, 39, 50, 17, 29, 36, + 36, 18, 23, 55, 7, 9, 74, -2, -3, 93, -13, -17, + -37, 59, 81, -18, 48, 68, 1, 38, 54, 20, 27, 41, + 39, 16, 27, 58, 6, 14, 76, -4, 0, 96, -15, -13, + -35, 58, 85, -16, 47, 72, 3, 36, 58, 22, 26, 45, + 41, 15, 31, 60, 4, 18, 79, -5, 4, 98, -16, -9, + -33, 57, 89, -13, 46, 76, 6, 35, 62, 24, 24, 49, + 44, 14, 35, 62, 3, 22, 81, -7, 8, 101, -18, -5, + -30, 55, 93, -11, 44, 80, 8, 34, 66, 27, 23, 53, + 46, 12, 39, 65, 2, 26, 84, -8, 12, 103, -19, -1, + -28, 54, 98, -8, 43, 84, 11, 32, 71, 29, 22, 57, + 49, 11, 44, 68, 0, 30, 86, -10, 17, 106, -21, 3, + -25, 52, 102, -6, 41, 88, 13, 31, 75, 32, 20, 61, + 51, 9, 48, 70, 0, 34, 89, -11, 21, 108, -22, 7, + -23, 51, 106, -3, 40, 92, 15, 29, 79, 34, 19, 65, + 54, 8, 52, 72, -2, 38, 91, -12, 25, 110, -23, 11, + -98, 99, -21, -79, 88, -35, -60, 77, -48, -41, 66, -62, + -22, 55, -76, -3, 45, -89, 16, 34, -103, 35, 23, -116, + -96, 97, -17, -76, 86, -31, -57, 76, -44, -39, 65, -58, + -19, 54, -72, 0, 44, -85, 18, 33, -99, 38, 22, -112, + -93, 96, -13, -74, 85, -27, -55, 74, -40, -36, 64, -54, + -17, 53, -68, 2, 42, -81, 21, 32, -95, 40, 21, -108, + -90, 94, -9, -71, 83, -23, -52, 73, -36, -34, 62, -49, + -14, 51, -63, 5, 41, -77, 23, 30, -90, 43, 19, -104, + -88, 93, -5, -69, 82, -19, -50, 71, -32, -31, 61, -45, + -12, 50, -59, 7, 39, -73, 26, 29, -86, 45, 18, -100, + -86, 92, -1, -66, 81, -15, -48, 70, -28, -29, 59, -41, + -9, 49, -55, 9, 38, -69, 28, 27, -82, 48, 16, -96, + -83, 90, 2, -64, 79, -11, -45, 69, -24, -26, 58, -37, + -7, 47, -51, 12, 37, -65, 31, 26, -78, 50, 15, -92, + -81, 89, 7, -61, 78, -6, -42, 67, -19, -24, 57, -33, + -4, 46, -47, 14, 35, -60, 33, 24, -74, 53, 14, -87, + -78, 87, 11, -59, 76, -2, -40, 66, -15, -21, 55, -29, + -2, 44, -43, 17, 34, -56, 36, 23, -70, 55, 12, -83, + -76, 86, 15, -56, 75, 1, -38, 65, -11, -19, 54, -25, + 0, 43, -39, 19, 32, -52, 38, 22, -66, 57, 11, -79, + -73, 85, 19, -54, 74, 5, -35, 63, -7, -17, 53, -21, + 3, 42, -35, 22, 31, -48, 40, 20, -62, 60, 9, -75, + -71, 83, 23, -52, 72, 9, -33, 62, -3, -14, 51, -17, + 5, 40, -31, 24, 30, -44, 43, 19, -58, 62, 8, -71, + -68, 82, 27, -49, 71, 13, -30, 60, 0, -11, 50, -12, + 8, 39, -26, 27, 28, -40, 46, 18, -53, 65, 7, -67, + -66, 80, 31, -47, 70, 17, -28, 59, 4, -9, 48, -8, + 10, 37, -22, 29, 27, -36, 48, 16, -49, 67, 5, -63, + -64, 79, 35, -44, 68, 21, -25, 58, 8, -7, 47, -4, + 13, 36, -18, 32, 25, -32, 50, 15, -45, 70, 4, -59, + -61, 78, 39, -42, 67, 25, -23, 56, 12, -4, 46, 0, + 15, 35, -14, 34, 24, -28, 53, 14, -41, 72, 3, -55, + -59, 76, 44, -39, 65, 30, -20, 55, 17, -2, 44, 3, + 18, 33, -10, 37, 23, -23, 55, 12, -37, 75, 1, -50, + -56, 75, 48, -37, 64, 34, -18, 53, 21, 1, 43, 7, + 20, 32, -6, 39, 21, -19, 58, 11, -33, 77, 0, -46, + -54, 74, 52, -34, 63, 38, -16, 52, 25, 3, 41, 11, + 23, 30, -2, 41, 20, -15, 60, 9, -29, 80, -1, -42, + -51, 72, 56, -32, 61, 42, -13, 51, 29, 6, 40, 15, + 25, 29, 1, 44, 19, -11, 63, 8, -25, 82, -2, -38, + -49, 71, 60, -29, 60, 46, -10, 49, 33, 8, 39, 20, + 28, 28, 6, 46, 17, -7, 65, 6, -20, 85, -4, -34, + -46, 69, 64, -27, 58, 50, -8, 48, 37, 11, 37, 24, + 30, 26, 10, 49, 16, -3, 68, 5, -16, 87, -5, -30, + -44, 68, 68, -24, 57, 54, -6, 46, 41, 13, 36, 28, + 32, 25, 14, 51, 14, 0, 70, 4, -12, 89, -6, -26, + -41, 67, 72, -22, 56, 58, -3, 45, 45, 15, 35, 32, + 35, 24, 18, 54, 13, 4, 72, 2, -8, 92, -8, -22, + -39, 65, 76, -20, 54, 62, -1, 44, 49, 18, 33, 36, + 37, 22, 22, 56, 12, 8, 75, 1, -4, 94, -9, -18, + -36, 64, 81, -17, 53, 67, 2, 42, 54, 21, 32, 40, + 40, 21, 26, 59, 10, 13, 78, 0, 0, 97, -10, -13, + -34, 62, 85, -15, 51, 71, 4, 41, 58, 23, 30, 44, + 42, 19, 30, 61, 9, 17, 80, -1, 3, 99, -12, -9, + -32, 61, 89, -12, 50, 75, 7, 40, 62, 25, 29, 48, + 45, 18, 34, 64, 7, 21, 82, -2, 7, 102, -13, -5, + -29, 60, 93, -10, 49, 79, 9, 38, 66, 28, 28, 52, + 47, 17, 38, 66, 6, 25, 85, -4, 11, 104, -14, -1, + -27, 58, 97, -7, 47, 83, 12, 37, 70, 30, 26, 57, + 50, 15, 43, 69, 5, 29, 87, -5, 16, 107, -16, 2, + -24, 57, 101, -5, 46, 87, 14, 35, 74, 33, 25, 61, + 52, 14, 47, 71, 3, 33, 90, -6, 20, 109, -17, 6, + -22, 55, 105, -2, 45, 91, 16, 34, 78, 35, 23, 65, + 55, 12, 51, 73, 2, 37, 92, -8, 24, 112, -19, 10, + -97, 103, -22, -78, 92, -36, -59, 81, -49, -40, 70, -63, + -21, 59, -76, -2, 49, -90, 17, 38, -103, 36, 27, -117, + -95, 101, -18, -75, 90, -32, -57, 80, -45, -38, 69, -59, + -18, 58, -72, 0, 48, -86, 19, 37, -99, 39, 26, -113, + -92, 100, -14, -73, 89, -28, -54, 78, -41, -35, 68, -55, + -16, 57, -68, 3, 46, -82, 22, 36, -95, 41, 25, -109, + -90, 98, -9, -70, 87, -23, -51, 77, -37, -33, 66, -50, + -13, 55, -64, 6, 45, -77, 24, 34, -91, 44, 23, -104, + -87, 97, -5, -68, 86, -19, -49, 75, -33, -30, 65, -46, + -11, 54, -60, 8, 43, -73, 27, 33, -87, 46, 22, -100, + -85, 96, -1, -65, 85, -15, -47, 74, -29, -28, 63, -42, + -8, 53, -56, 10, 42, -69, 29, 31, -83, 48, 20, -96, + -82, 94, 2, -63, 83, -11, -44, 73, -25, -25, 62, -38, + -6, 51, -52, 13, 41, -65, 31, 30, -79, 51, 19, -92, + -80, 93, 6, -60, 82, -7, -42, 71, -20, -23, 61, -34, + -3, 50, -47, 15, 39, -61, 34, 28, -74, 54, 18, -88, + -77, 91, 10, -58, 80, -3, -39, 70, -16, -20, 59, -30, + -1, 48, -43, 18, 38, -57, 37, 27, -70, 56, 16, -84, + -75, 90, 14, -56, 79, 0, -37, 69, -12, -18, 58, -26, + 1, 47, -39, 20, 36, -53, 39, 26, -66, 58, 15, -80, + -73, 89, 18, -53, 78, 4, -34, 67, -8, -16, 57, -22, + 4, 46, -35, 23, 35, -49, 41, 24, -62, 61, 13, -76, + -70, 87, 22, -51, 76, 8, -32, 66, -4, -13, 55, -18, + 6, 44, -31, 25, 34, -45, 44, 23, -58, 63, 12, -72, + -67, 86, 27, -48, 75, 13, -29, 64, 0, -11, 54, -13, + 9, 43, -27, 28, 32, -40, 46, 22, -54, 66, 11, -67, + -65, 84, 31, -46, 74, 17, -27, 63, 3, -8, 52, -9, + 11, 41, -23, 30, 31, -36, 49, 20, -50, 68, 9, -63, + -63, 83, 35, -43, 72, 21, -25, 62, 7, -6, 51, -5, + 14, 40, -19, 32, 29, -32, 51, 19, -46, 71, 8, -59, + -60, 82, 39, -41, 71, 25, -22, 60, 11, -3, 50, -1, + 16, 39, -15, 35, 28, -28, 54, 18, -42, 73, 7, -55, + -58, 80, 43, -38, 69, 29, -19, 59, 16, -1, 48, 2, + 19, 37, -10, 38, 27, -24, 56, 16, -37, 76, 5, -51, + -55, 79, 47, -36, 68, 33, -17, 57, 20, 2, 47, 6, + 21, 36, -6, 40, 25, -20, 59, 15, -33, 78, 4, -47, + -53, 78, 51, -33, 67, 37, -15, 56, 24, 4, 45, 10, + 24, 34, -2, 42, 24, -16, 61, 13, -29, 80, 2, -43, + -50, 76, 55, -31, 65, 41, -12, 55, 28, 7, 44, 14, + 26, 33, 1, 45, 23, -12, 63, 12, -25, 83, 1, -39, + -48, 75, 60, -28, 64, 46, -10, 53, 32, 9, 43, 19, + 29, 32, 5, 47, 21, -7, 66, 10, -21, 86, 0, -34, + -45, 73, 64, -26, 62, 50, -7, 52, 36, 12, 41, 23, + 31, 30, 9, 50, 20, -3, 69, 9, -17, 88, -1, -30, + -43, 72, 68, -24, 61, 54, -5, 50, 40, 14, 40, 27, + 33, 29, 13, 52, 18, 0, 71, 8, -13, 90, -2, -26, + -41, 71, 72, -21, 60, 58, -2, 49, 44, 16, 39, 31, + 36, 28, 17, 55, 17, 4, 73, 6, -9, 93, -4, -22, + -38, 69, 76, -19, 58, 62, 0, 48, 48, 19, 37, 35, + 38, 26, 21, 57, 16, 8, 76, 5, -5, 95, -5, -18, + -35, 68, 80, -16, 57, 66, 3, 46, 53, 21, 36, 39, + 41, 25, 26, 60, 14, 12, 78, 4, 0, 98, -6, -14, + -33, 66, 84, -14, 55, 70, 5, 45, 57, 24, 34, 43, + 43, 23, 30, 62, 13, 16, 81, 2, 3, 100, -8, -10, + -31, 65, 88, -11, 54, 74, 7, 44, 61, 26, 33, 47, + 46, 22, 34, 64, 11, 20, 83, 1, 7, 103, -9, -6, + -28, 64, 92, -9, 53, 78, 10, 42, 65, 29, 32, 51, + 48, 21, 38, 67, 10, 24, 86, 0, 11, 105, -10, -2, + -26, 62, 97, -6, 51, 83, 13, 41, 69, 31, 30, 56, + 51, 19, 42, 69, 9, 29, 88, -1, 15, 108, -12, 2, + -23, 61, 101, -4, 50, 87, 15, 39, 73, 34, 29, 60, + 53, 18, 46, 72, 7, 33, 91, -2, 19, 110, -13, 6, + -21, 59, 105, -1, 49, 91, 17, 38, 77, 36, 27, 64, + 55, 16, 50, 74, 6, 37, 93, -4, 23, 112, -15, 10, + -96, 107, -23, -77, 96, -36, -58, 85, -50, -39, 74, -63, + -20, 63, -77, -1, 53, -90, 18, 42, -104, 37, 31, -118, + -94, 105, -19, -74, 94, -32, -56, 84, -46, -37, 73, -59, + -17, 62, -73, 1, 52, -86, 20, 41, -100, 39, 30, -114, + -91, 104, -15, -72, 93, -28, -53, 82, -42, -34, 72, -55, + -15, 61, -69, 4, 50, -82, 23, 40, -96, 42, 29, -110, + -89, 102, -10, -69, 91, -24, -51, 81, -37, -32, 70, -51, + -12, 59, -65, 6, 49, -78, 25, 38, -91, 45, 27, -105, + -86, 101, -6, -67, 90, -20, -48, 79, -33, -29, 69, -47, + -10, 58, -61, 9, 47, -74, 28, 37, -87, 47, 26, -101, + -84, 100, -2, -65, 89, -16, -46, 78, -29, -27, 67, -43, + -8, 57, -57, 11, 46, -70, 30, 35, -83, 49, 24, -97, + -81, 98, 1, -62, 87, -12, -43, 77, -25, -25, 66, -39, + -5, 55, -53, 14, 45, -66, 32, 34, -79, 52, 23, -93, + -79, 97, 5, -59, 86, -7, -41, 75, -21, -22, 65, -34, + -2, 54, -48, 16, 43, -61, 35, 32, -75, 54, 22, -89, + -76, 95, 9, -57, 84, -3, -38, 74, -17, -19, 63, -30, + 0, 52, -44, 19, 42, -57, 37, 31, -71, 57, 20, -85, + -74, 94, 13, -55, 83, 0, -36, 73, -13, -17, 62, -26, + 2, 51, -40, 21, 40, -53, 40, 30, -67, 59, 19, -81, + -72, 93, 17, -52, 82, 4, -33, 71, -9, -15, 61, -22, + 5, 50, -36, 23, 39, -49, 42, 28, -63, 62, 17, -77, + -69, 91, 21, -50, 80, 8, -31, 70, -5, -12, 59, -18, + 7, 48, -32, 26, 38, -45, 45, 27, -59, 64, 16, -73, + -67, 90, 26, -47, 79, 12, -28, 68, 0, -10, 58, -14, + 10, 47, -28, 29, 36, -41, 47, 26, -54, 67, 15, -68, + -64, 88, 30, -45, 78, 16, -26, 67, 3, -7, 56, -10, + 12, 45, -24, 31, 35, -37, 50, 24, -50, 69, 13, -64, + -62, 87, 34, -42, 76, 20, -24, 66, 7, -5, 55, -6, + 15, 44, -20, 33, 33, -33, 52, 23, -46, 71, 12, -60, + -59, 86, 38, -40, 75, 24, -21, 64, 11, -2, 54, -2, + 17, 43, -16, 36, 32, -29, 55, 22, -42, 74, 11, -56, + -57, 84, 42, -37, 73, 29, -19, 63, 15, 0, 52, 2, + 20, 41, -11, 38, 31, -24, 57, 20, -38, 77, 9, -52, + -54, 83, 46, -35, 72, 33, -16, 61, 19, 3, 51, 6, + 22, 40, -7, 41, 29, -20, 60, 19, -34, 79, 8, -48, + -52, 82, 50, -33, 71, 37, -14, 60, 23, 5, 49, 10, + 24, 38, -3, 43, 28, -16, 62, 17, -30, 81, 6, -44, + -50, 80, 54, -30, 69, 41, -11, 59, 27, 7, 48, 14, + 27, 37, 0, 46, 27, -12, 64, 16, -26, 84, 5, -40, + -47, 79, 59, -27, 68, 45, -9, 57, 32, 10, 47, 18, + 29, 36, 4, 48, 25, -8, 67, 14, -21, 86, 3, -35, + -44, 77, 63, -25, 66, 49, -6, 56, 36, 13, 45, 22, + 32, 34, 8, 51, 24, -4, 69, 13, -17, 89, 2, -31, + -42, 76, 67, -23, 65, 53, -4, 54, 40, 15, 44, 26, + 34, 33, 12, 53, 22, 0, 72, 12, -13, 91, 1, -27, + -40, 75, 71, -20, 64, 57, -1, 53, 44, 17, 43, 30, + 37, 32, 16, 55, 21, 3, 74, 10, -9, 94, 0, -23, + -37, 73, 75, -18, 62, 61, 1, 52, 48, 20, 41, 34, + 39, 30, 20, 58, 20, 7, 77, 9, -5, 96, -1, -19, + -35, 72, 79, -15, 61, 66, 4, 50, 52, 22, 40, 39, + 42, 29, 25, 61, 18, 12, 79, 8, -1, 99, -2, -15, + -32, 70, 83, -13, 59, 70, 6, 49, 56, 25, 38, 43, + 44, 27, 29, 63, 17, 16, 82, 6, 2, 101, -4, -11, + -30, 69, 87, -10, 58, 74, 8, 48, 60, 27, 37, 47, + 47, 26, 33, 65, 15, 20, 84, 5, 6, 103, -5, -7, + -27, 68, 91, -8, 57, 78, 11, 46, 64, 30, 36, 51, + 49, 25, 37, 68, 14, 24, 87, 3, 10, 106, -6, -3, + -25, 66, 96, -5, 55, 82, 13, 45, 69, 32, 34, 55, + 52, 23, 41, 70, 13, 28, 89, 2, 15, 109, -8, 1, + -22, 65, 100, -3, 54, 86, 16, 43, 73, 35, 33, 59, + 54, 22, 45, 73, 11, 32, 92, 1, 19, 111, -9, 5, + -20, 63, 104, -1, 53, 90, 18, 42, 77, 37, 31, 63, + 56, 20, 49, 75, 10, 36, 94, 0, 23, 113, -11, 9, + -95, 111, -23, -76, 100, -37, -57, 89, -50, -38, 78, -64, + -19, 67, -78, 0, 57, -91, 19, 46, -104, 38, 35, -118, + -93, 109, -19, -73, 98, -33, -55, 88, -46, -36, 77, -60, + -17, 66, -74, 2, 56, -87, 21, 45, -100, 40, 34, -114, + -90, 108, -15, -71, 97, -29, -52, 86, -42, -34, 76, -56, + -14, 65, -70, 5, 54, -83, 23, 44, -96, 43, 33, -110, + -88, 106, -11, -68, 95, -25, -50, 85, -38, -31, 74, -51, + -11, 63, -65, 7, 53, -79, 26, 42, -92, 45, 31, -106, + -85, 105, -7, -66, 94, -21, -47, 83, -34, -28, 73, -47, + -9, 62, -61, 10, 51, -75, 29, 41, -88, 48, 30, -102, + -83, 104, -3, -64, 93, -17, -45, 82, -30, -26, 71, -43, + -7, 61, -57, 12, 50, -71, 31, 39, -84, 50, 28, -98, + -81, 102, 0, -61, 91, -13, -42, 81, -26, -24, 70, -39, + -4, 59, -53, 15, 49, -67, 33, 38, -80, 53, 27, -94, + -78, 101, 5, -59, 90, -8, -40, 79, -21, -21, 69, -35, + -2, 58, -49, 17, 47, -62, 36, 36, -75, 55, 26, -89, + -76, 99, 9, -56, 88, -4, -37, 78, -17, -19, 67, -31, + 1, 56, -45, 20, 46, -58, 38, 35, -71, 58, 24, -85, + -73, 98, 13, -54, 87, 0, -35, 77, -13, -16, 66, -27, + 3, 55, -41, 22, 44, -54, 41, 34, -67, 60, 23, -81, + -71, 97, 17, -51, 86, 3, -33, 75, -9, -14, 65, -23, + 6, 54, -37, 24, 43, -50, 43, 32, -63, 63, 21, -77, + -68, 95, 21, -49, 84, 7, -30, 74, -5, -11, 63, -19, + 8, 52, -33, 27, 42, -46, 46, 31, -59, 65, 20, -73, + -66, 94, 25, -46, 83, 11, -27, 72, -1, -9, 62, -14, + 11, 51, -28, 29, 40, -42, 48, 30, -55, 68, 19, -69, + -63, 92, 29, -44, 82, 15, -25, 71, 2, -6, 60, -10, + 13, 49, -24, 32, 39, -38, 51, 28, -51, 70, 17, -65, + -61, 91, 33, -41, 80, 19, -23, 70, 6, -4, 59, -6, + 15, 48, -20, 34, 37, -34, 53, 27, -47, 72, 16, -61, + -58, 90, 37, -39, 79, 23, -20, 68, 10, -2, 58, -2, + 18, 47, -16, 37, 36, -30, 55, 26, -43, 75, 15, -57, + -56, 88, 42, -36, 77, 28, -18, 67, 15, 1, 56, 1, + 21, 45, -12, 39, 35, -25, 58, 24, -38, 77, 13, -52, + -53, 87, 46, -34, 76, 32, -15, 65, 19, 4, 55, 5, + 23, 44, -8, 42, 33, -21, 61, 23, -34, 80, 12, -48, + -51, 86, 50, -32, 75, 36, -13, 64, 23, 6, 53, 9, + 25, 42, -4, 44, 32, -17, 63, 21, -30, 82, 10, -44, + -49, 84, 54, -29, 73, 40, -10, 63, 27, 8, 52, 13, + 28, 41, 0, 47, 31, -13, 65, 20, -26, 85, 9, -40, + -46, 83, 58, -27, 72, 44, -8, 61, 31, 11, 51, 18, + 30, 40, 4, 49, 29, -9, 68, 18, -22, 87, 7, -36, + -44, 81, 62, -24, 70, 48, -5, 60, 35, 13, 49, 22, + 33, 38, 8, 52, 28, -5, 70, 17, -18, 90, 6, -32, + -41, 80, 66, -22, 69, 52, -3, 58, 39, 16, 48, 26, + 35, 37, 12, 54, 26, -1, 73, 16, -14, 92, 5, -28, + -39, 79, 70, -19, 68, 56, -1, 57, 43, 18, 47, 30, + 38, 36, 16, 56, 25, 2, 75, 14, -10, 95, 3, -24, + -36, 77, 74, -17, 66, 60, 2, 56, 47, 21, 45, 34, + 40, 34, 20, 59, 24, 6, 78, 13, -6, 97, 2, -20, + -34, 76, 79, -14, 65, 65, 5, 54, 52, 23, 44, 38, + 43, 33, 24, 61, 22, 11, 80, 12, -1, 100, 1, -15, + -31, 74, 83, -12, 63, 69, 7, 53, 56, 26, 42, 42, + 45, 31, 28, 64, 21, 15, 83, 10, 2, 102, 0, -11, + -29, 73, 87, -9, 62, 73, 9, 52, 60, 28, 41, 46, + 47, 30, 32, 66, 19, 19, 85, 9, 6, 104, -1, -7, + -26, 72, 91, -7, 61, 77, 12, 50, 64, 30, 40, 50, + 50, 29, 36, 69, 18, 23, 87, 7, 10, 107, -2, -3, + -24, 70, 95, -4, 59, 81, 14, 49, 68, 33, 38, 55, + 53, 27, 41, 71, 17, 27, 90, 6, 14, 109, -4, 0, + -21, 69, 99, -2, 58, 85, 17, 47, 72, 36, 37, 59, + 55, 26, 45, 74, 15, 31, 92, 5, 18, 112, -5, 4, + -19, 67, 103, 0, 57, 89, 19, 46, 76, 38, 35, 63, + 57, 24, 49, 76, 14, 35, 95, 3, 22, 114, -7, 8, + -94, 115, -24, -75, 104, -38, -56, 93, -51, -37, 83, -65, + -18, 72, -78, 1, 61, -92, 20, 51, -105, 39, 40, -119, + -92, 114, -20, -72, 103, -34, -54, 92, -47, -35, 82, -61, + -16, 71, -74, 3, 60, -88, 22, 49, -101, 41, 38, -115, + -89, 112, -16, -70, 101, -30, -51, 91, -43, -32, 80, -57, + -13, 69, -70, 6, 59, -84, 24, 48, -97, 44, 37, -111, + -87, 111, -11, -67, 100, -25, -49, 89, -39, -30, 79, -52, + -10, 68, -66, 8, 57, -79, 27, 47, -93, 47, 36, -107, + -84, 109, -7, -65, 99, -21, -46, 88, -35, -27, 77, -48, + -8, 66, -62, 11, 56, -75, 30, 45, -89, 49, 34, -103, + -82, 108, -3, -63, 97, -17, -44, 87, -31, -25, 76, -44, + -6, 65, -58, 13, 54, -71, 32, 44, -85, 51, 33, -99, + -80, 107, 0, -60, 96, -13, -41, 85, -27, -23, 75, -40, + -3, 64, -54, 16, 53, -67, 34, 42, -81, 54, 32, -95, + -77, 105, 4, -57, 94, -9, -39, 84, -22, -20, 73, -36, + -1, 62, -49, 18, 52, -63, 37, 41, -76, 56, 30, -90, + -74, 104, 8, -55, 93, -5, -36, 82, -18, -18, 72, -32, + 2, 61, -45, 21, 50, -59, 39, 40, -72, 59, 29, -86, + -72, 103, 12, -53, 92, -1, -34, 81, -14, -15, 70, -28, + 4, 59, -41, 23, 49, -55, 42, 38, -68, 61, 27, -82, + -70, 101, 16, -50, 90, 2, -32, 80, -10, -13, 69, -24, + 7, 58, -37, 25, 48, -51, 44, 37, -64, 64, 26, -78, + -67, 100, 20, -48, 89, 6, -29, 78, -6, -10, 68, -20, + 9, 57, -33, 28, 46, -47, 47, 36, -60, 66, 25, -74, + -65, 98, 25, -45, 87, 11, -26, 77, -2, -8, 66, -15, + 12, 55, -29, 30, 45, -42, 49, 34, -56, 69, 23, -70, + -62, 97, 29, -43, 86, 15, -24, 75, 1, -5, 65, -11, + 14, 54, -25, 33, 43, -38, 52, 33, -52, 71, 22, -66, + -60, 96, 33, -40, 85, 19, -22, 74, 5, -3, 63, -7, + 16, 53, -21, 35, 42, -34, 54, 31, -48, 73, 20, -62, + -57, 94, 37, -38, 83, 23, -19, 73, 9, 0, 62, -3, + 19, 51, -17, 38, 41, -30, 56, 30, -44, 76, 19, -58, + -55, 93, 41, -35, 82, 27, -17, 71, 14, 2, 61, 0, + 22, 50, -12, 40, 39, -26, 59, 28, -39, 79, 18, -53, + -52, 91, 45, -33, 80, 31, -14, 70, 18, 5, 59, 4, + 24, 48, -8, 43, 38, -22, 62, 27, -35, 81, 16, -49, + -50, 90, 49, -31, 79, 35, -12, 69, 22, 7, 58, 8, + 26, 47, -4, 45, 36, -18, 64, 26, -31, 83, 15, -45, + -48, 89, 53, -28, 78, 39, -9, 67, 26, 9, 57, 12, + 29, 46, 0, 48, 35, -14, 66, 24, -27, 86, 14, -41, + -45, 87, 58, -26, 76, 44, -7, 66, 30, 12, 55, 17, + 31, 44, 3, 50, 34, -9, 69, 23, -23, 88, 12, -37, + -42, 86, 62, -23, 75, 48, -4, 64, 34, 14, 54, 21, + 34, 43, 7, 53, 32, -5, 71, 22, -19, 91, 11, -33, + -40, 84, 66, -21, 74, 52, -2, 63, 38, 17, 52, 25, + 36, 41, 11, 55, 31, -1, 74, 20, -15, 93, 9, -29, + -38, 83, 70, -18, 72, 56, 0, 62, 42, 19, 51, 29, + 39, 40, 15, 57, 29, 2, 76, 19, -11, 96, 8, -25, + -35, 82, 74, -16, 71, 60, 3, 60, 46, 22, 50, 33, + 41, 39, 19, 60, 28, 6, 79, 18, -7, 98, 7, -21, + -33, 80, 78, -13, 69, 64, 6, 59, 51, 24, 48, 37, + 44, 37, 24, 62, 27, 10, 81, 16, -2, 101, 5, -16, + -30, 79, 82, -11, 68, 68, 8, 57, 55, 27, 47, 41, + 46, 36, 28, 65, 25, 14, 84, 15, 1, 103, 4, -12, + -28, 78, 86, -8, 67, 72, 10, 56, 59, 29, 45, 45, + 48, 35, 32, 67, 24, 18, 86, 13, 5, 105, 2, -8, + -25, 76, 90, -6, 65, 76, 13, 55, 63, 31, 44, 49, + 51, 33, 36, 70, 23, 22, 88, 12, 9, 108, 1, -4, + -23, 75, 95, -3, 64, 81, 15, 53, 67, 34, 43, 54, + 54, 32, 40, 72, 21, 27, 91, 10, 13, 110, 0, 0, + -20, 73, 99, -1, 62, 85, 18, 52, 71, 37, 41, 58, + 56, 30, 44, 75, 20, 31, 94, 9, 17, 113, -1, 3, + -18, 72, 103, 1, 61, 89, 20, 50, 75, 39, 40, 62, + 58, 29, 48, 77, 18, 35, 96, 8, 21, 115, -2, 7, + -93, 119, -25, -74, 108, -38, -55, 97, -52, -36, 87, -65, + -17, 76, -79, 2, 65, -92, 21, 55, -106, 40, 44, -120, + -91, 118, -21, -72, 107, -34, -53, 96, -48, -34, 86, -61, + -15, 75, -75, 4, 64, -88, 23, 53, -102, 42, 42, -116, + -89, 116, -17, -69, 105, -30, -50, 95, -44, -32, 84, -57, + -12, 73, -71, 7, 63, -84, 25, 52, -98, 45, 41, -112, + -86, 115, -12, -66, 104, -26, -48, 93, -39, -29, 83, -53, + -10, 72, -67, 9, 61, -80, 28, 51, -93, 47, 40, -107, + -83, 113, -8, -64, 103, -22, -45, 92, -35, -26, 81, -49, + -7, 70, -63, 12, 60, -76, 30, 49, -89, 50, 38, -103, + -81, 112, -4, -62, 101, -18, -43, 91, -31, -24, 80, -45, + -5, 69, -59, 14, 58, -72, 33, 48, -85, 52, 37, -99, + -79, 111, 0, -59, 100, -14, -40, 89, -27, -22, 79, -41, + -2, 68, -55, 16, 57, -68, 35, 46, -81, 55, 36, -95, + -76, 109, 3, -57, 98, -9, -38, 88, -23, -19, 77, -36, + 0, 66, -50, 19, 56, -63, 38, 45, -77, 57, 34, -91, + -74, 108, 7, -54, 97, -5, -35, 86, -19, -17, 76, -32, + 3, 65, -46, 22, 54, -59, 40, 44, -73, 60, 33, -87, + -71, 107, 11, -52, 96, -1, -33, 85, -15, -14, 74, -28, + 5, 63, -42, 24, 53, -55, 43, 42, -69, 62, 31, -83, + -69, 105, 15, -49, 94, 2, -31, 84, -11, -12, 73, -24, + 8, 62, -38, 26, 52, -51, 45, 41, -65, 64, 30, -79, + -66, 104, 19, -47, 93, 6, -28, 82, -7, -9, 72, -20, + 10, 61, -34, 29, 50, -47, 47, 40, -61, 67, 29, -75, + -64, 102, 24, -44, 91, 10, -26, 81, -2, -7, 70, -16, + 13, 59, -30, 31, 49, -43, 50, 38, -56, 70, 27, -70, + -61, 101, 28, -42, 90, 14, -23, 79, 1, -4, 69, -12, + 15, 58, -26, 34, 47, -39, 53, 37, -52, 72, 26, -66, + -59, 100, 32, -40, 89, 18, -21, 78, 5, -2, 67, -8, + 17, 57, -22, 36, 46, -35, 55, 35, -48, 74, 24, -62, + -57, 98, 36, -37, 87, 22, -18, 77, 9, 0, 66, -4, + 20, 55, -18, 39, 45, -31, 57, 34, -44, 77, 23, -58, + -54, 97, 40, -34, 86, 27, -16, 75, 13, 3, 65, 0, + 22, 54, -13, 41, 43, -26, 60, 32, -40, 79, 22, -54, + -51, 95, 44, -32, 84, 31, -13, 74, 17, 6, 63, 4, + 25, 52, -9, 44, 42, -22, 62, 31, -36, 82, 20, -50, + -49, 94, 48, -30, 83, 35, -11, 73, 21, 8, 62, 8, + 27, 51, -5, 46, 40, -18, 65, 30, -32, 84, 19, -46, + -47, 93, 52, -27, 82, 39, -8, 71, 25, 10, 61, 12, + 30, 50, -1, 48, 39, -14, 67, 28, -28, 87, 18, -42, + -44, 91, 57, -25, 80, 43, -6, 70, 30, 13, 59, 16, + 32, 48, 2, 51, 38, -10, 70, 27, -23, 89, 16, -37, + -42, 90, 61, -22, 79, 47, -3, 68, 34, 15, 58, 20, + 35, 47, 6, 54, 36, -6, 72, 26, -19, 92, 15, -33, + -39, 88, 65, -20, 78, 51, -1, 67, 38, 18, 56, 24, + 37, 45, 10, 56, 35, -2, 75, 24, -15, 94, 13, -29, + -37, 87, 69, -17, 76, 55, 1, 66, 42, 20, 55, 28, + 40, 44, 14, 58, 33, 1, 77, 23, -11, 96, 12, -25, + -34, 86, 73, -15, 75, 59, 4, 64, 46, 23, 54, 32, + 42, 43, 18, 61, 32, 5, 79, 22, -7, 99, 11, -21, + -32, 84, 77, -12, 73, 64, 6, 63, 50, 25, 52, 37, + 45, 41, 23, 63, 31, 10, 82, 20, -3, 102, 9, -17, + -29, 83, 81, -10, 72, 68, 9, 61, 54, 28, 51, 41, + 47, 40, 27, 66, 29, 14, 85, 19, 0, 104, 8, -13, + -27, 82, 85, -8, 71, 72, 11, 60, 58, 30, 49, 45, + 49, 39, 31, 68, 28, 18, 87, 17, 4, 106, 6, -9, + -25, 80, 89, -5, 69, 76, 14, 59, 62, 32, 48, 49, + 52, 37, 35, 71, 27, 22, 89, 16, 8, 109, 5, -5, + -22, 79, 94, -2, 68, 80, 16, 57, 67, 35, 47, 53, + 54, 36, 39, 73, 25, 26, 92, 14, 13, 111, 4, 0, + -19, 77, 98, 0, 66, 84, 19, 56, 71, 37, 45, 57, + 57, 34, 43, 76, 24, 30, 94, 13, 17, 114, 2, 3, + -17, 76, 102, 2, 65, 88, 21, 54, 75, 40, 44, 61, + 59, 33, 47, 78, 22, 34, 97, 12, 21, 116, 1, 7, + -92, 123, -25, -73, 112, -39, -54, 101, -52, -35, 91, -66, + -16, 80, -80, 3, 69, -93, 21, 59, -106, 41, 48, -120, + -90, 122, -21, -71, 111, -35, -52, 100, -48, -33, 90, -62, + -14, 79, -76, 5, 68, -89, 24, 57, -102, 43, 46, -116, + -88, 120, -17, -68, 109, -31, -49, 99, -44, -31, 88, -58, + -11, 77, -72, 7, 67, -85, 26, 56, -98, 46, 45, -112, + -85, 119, -13, -66, 108, -27, -47, 97, -40, -28, 87, -53, + -9, 76, -67, 10, 65, -81, 29, 55, -94, 48, 44, -108, + -83, 117, -9, -63, 107, -23, -44, 96, -36, -26, 85, -49, + -6, 74, -63, 13, 64, -77, 31, 53, -90, 51, 42, -104, + -80, 116, -5, -61, 105, -19, -42, 95, -32, -23, 84, -45, + -4, 73, -59, 15, 62, -73, 34, 52, -86, 53, 41, -100, + -78, 115, -1, -58, 104, -15, -40, 93, -28, -21, 83, -41, + -1, 72, -55, 17, 61, -69, 36, 50, -82, 56, 40, -96, + -75, 113, 3, -56, 102, -10, -37, 92, -23, -18, 81, -37, + 1, 70, -51, 20, 60, -64, 39, 49, -77, 58, 38, -91, + -73, 112, 7, -53, 101, -6, -34, 90, -19, -16, 80, -33, + 4, 69, -47, 22, 58, -60, 41, 48, -73, 61, 37, -87, + -70, 111, 11, -51, 100, -2, -32, 89, -15, -13, 78, -29, + 6, 67, -43, 25, 57, -56, 44, 46, -69, 63, 35, -83, + -68, 109, 15, -48, 98, 1, -30, 88, -11, -11, 77, -25, + 8, 66, -39, 27, 56, -52, 46, 45, -65, 65, 34, -79, + -65, 108, 19, -46, 97, 5, -27, 86, -7, -9, 76, -21, + 11, 65, -35, 30, 54, -48, 48, 44, -61, 68, 33, -75, + -63, 106, 23, -43, 95, 9, -25, 85, -3, -6, 74, -16, + 14, 63, -30, 32, 53, -44, 51, 42, -57, 70, 31, -71, + -60, 105, 27, -41, 94, 13, -22, 83, 0, -3, 73, -12, + 16, 62, -26, 35, 51, -40, 53, 41, -53, 73, 30, -67, + -58, 104, 31, -39, 93, 17, -20, 82, 4, -1, 71, -8, + 18, 61, -22, 37, 50, -36, 56, 39, -49, 75, 28, -63, + -56, 102, 35, -36, 91, 21, -17, 81, 8, 1, 70, -4, + 21, 59, -18, 39, 49, -32, 58, 38, -45, 78, 27, -59, + -53, 101, 40, -34, 90, 26, -15, 79, 13, 4, 69, 0, + 23, 58, -14, 42, 47, -27, 61, 36, -40, 80, 26, -54, + -51, 99, 44, -31, 88, 30, -12, 78, 17, 6, 67, 3, + 26, 56, -10, 45, 46, -23, 63, 35, -36, 83, 24, -50, + -48, 98, 48, -29, 87, 34, -10, 77, 21, 9, 66, 7, + 28, 55, -6, 47, 44, -19, 66, 34, -32, 85, 23, -46, + -46, 97, 52, -26, 86, 38, -8, 75, 25, 11, 65, 11, + 31, 54, -2, 49, 43, -15, 68, 32, -28, 88, 22, -42, + -43, 95, 56, -24, 84, 42, -5, 74, 29, 14, 63, 16, + 33, 52, 2, 52, 42, -11, 71, 31, -24, 90, 20, -38, + -41, 94, 60, -21, 83, 46, -3, 72, 33, 16, 62, 20, + 36, 51, 6, 54, 40, -7, 73, 30, -20, 93, 19, -34, + -38, 92, 64, -19, 82, 50, 0, 71, 37, 19, 60, 24, + 38, 49, 10, 57, 39, -3, 76, 28, -16, 95, 17, -30, + -36, 91, 68, -17, 80, 54, 2, 70, 41, 21, 59, 28, + 40, 48, 14, 59, 37, 0, 78, 27, -12, 97, 16, -26, + -33, 90, 72, -14, 79, 58, 5, 68, 45, 23, 58, 32, + 43, 47, 18, 62, 36, 4, 80, 26, -8, 100, 15, -22, + -31, 88, 77, -11, 77, 63, 7, 67, 50, 26, 56, 36, + 46, 45, 22, 64, 35, 9, 83, 24, -3, 102, 13, -17, + -28, 87, 81, -9, 76, 67, 10, 65, 54, 29, 55, 40, + 48, 44, 26, 67, 33, 13, 85, 23, 0, 105, 12, -13, + -26, 86, 85, -7, 75, 71, 12, 64, 58, 31, 53, 44, + 50, 43, 30, 69, 32, 17, 88, 21, 4, 107, 10, -9, + -24, 84, 89, -4, 73, 75, 15, 63, 62, 33, 52, 48, + 53, 41, 34, 71, 31, 21, 90, 20, 8, 110, 9, -5, + -21, 83, 93, -2, 72, 79, 17, 61, 66, 36, 51, 53, + 55, 40, 39, 74, 29, 25, 93, 18, 12, 112, 8, -1, + -19, 81, 97, 1, 70, 83, 20, 60, 70, 38, 49, 57, + 58, 38, 43, 77, 28, 29, 95, 17, 16, 115, 6, 2, + -16, 80, 101, 3, 69, 87, 22, 58, 74, 41, 48, 61, + 60, 37, 47, 79, 26, 33, 98, 16, 20, 117, 5, 6, + -119, -5, -6, -100, -16, -20, -81, -26, -33, -62, -37, -47, + -43, -48, -61, -24, -58, -74, -5, -69, -87, 14, -80, -101, + -117, -6, -2, -97, -17, -16, -79, -28, -29, -60, -38, -43, + -40, -49, -57, -22, -60, -70, -3, -70, -83, 17, -81, -97, + -114, -8, 1, -95, -18, -12, -76, -29, -25, -57, -40, -39, + -38, -51, -53, -19, -61, -66, 0, -72, -79, 19, -83, -93, + -112, -9, 5, -92, -20, -8, -73, -31, -21, -55, -41, -34, + -35, -52, -48, -17, -63, -62, 2, -73, -75, 22, -84, -89, + -109, -10, 9, -90, -21, -4, -71, -32, -17, -52, -43, -30, + -33, -53, -44, -14, -64, -58, 5, -75, -71, 24, -86, -85, + -107, -12, 13, -87, -23, 0, -69, -33, -13, -50, -44, -26, + -31, -55, -40, -12, -65, -54, 7, -76, -67, 26, -87, -81, + -104, -13, 17, -85, -24, 3, -66, -35, -9, -48, -45, -22, + -28, -56, -36, -9, -67, -50, 9, -77, -63, 29, -88, -77, + -102, -15, 22, -82, -26, 8, -64, -36, -4, -45, -47, -18, + -25, -58, -32, -7, -68, -45, 12, -79, -58, 31, -90, -72, + -99, -16, 26, -80, -27, 12, -61, -37, 0, -42, -48, -14, + -23, -59, -28, -4, -70, -41, 15, -80, -54, 34, -91, -68, + -97, -17, 30, -78, -28, 16, -59, -39, 3, -40, -49, -10, + -21, -60, -24, -2, -71, -37, 17, -82, -50, 36, -92, -64, + -95, -19, 34, -75, -30, 20, -56, -40, 7, -38, -51, -6, + -18, -62, -20, 1, -72, -33, 19, -83, -46, 39, -94, -60, + -92, -20, 38, -73, -31, 24, -54, -42, 11, -35, -52, -2, + -16, -63, -16, 3, -74, -29, 22, -84, -42, 41, -95, -56, + -90, -22, 42, -70, -32, 28, -51, -43, 15, -33, -54, 2, + -13, -65, -11, 6, -75, -25, 24, -86, -38, 44, -97, -52, + -87, -23, 46, -68, -34, 32, -49, -44, 19, -30, -55, 6, + -11, -66, -7, 8, -77, -21, 27, -87, -34, 46, -98, -48, + -85, -24, 50, -65, -35, 36, -47, -46, 23, -28, -56, 10, + -8, -67, -3, 10, -78, -17, 29, -88, -30, 49, -99, -44, + -82, -26, 54, -63, -36, 40, -44, -47, 27, -25, -58, 14, + -6, -69, 0, 13, -79, -13, 32, -90, -26, 51, -101, -40, + -80, -27, 59, -60, -38, 45, -41, -49, 32, -23, -59, 18, + -3, -70, 4, 15, -81, -8, 34, -91, -21, 54, -102, -35, + -77, -28, 63, -58, -39, 49, -39, -50, 36, -20, -61, 22, + -1, -71, 8, 18, -82, -4, 37, -93, -17, 56, -104, -31, + -75, -30, 67, -55, -41, 53, -37, -51, 40, -18, -62, 26, + 1, -73, 12, 20, -83, 0, 39, -94, -13, 58, -105, -27, + -72, -31, 71, -53, -42, 57, -34, -53, 44, -16, -63, 30, + 4, -74, 16, 23, -85, 3, 41, -95, -9, 61, -106, -23, + -70, -33, 75, -50, -44, 61, -32, -54, 48, -13, -65, 35, + 7, -76, 21, 25, -86, 7, 44, -97, -5, 63, -108, -19, + -67, -34, 79, -48, -45, 65, -29, -56, 52, -10, -66, 39, + 9, -77, 25, 28, -88, 11, 46, -98, -1, 66, -109, -15, + -65, -35, 83, -46, -46, 69, -27, -57, 56, -8, -67, 43, + 11, -78, 29, 30, -89, 15, 49, -100, 2, 68, -111, -11, + -63, -37, 87, -43, -48, 73, -24, -58, 60, -6, -69, 47, + 14, -80, 33, 32, -90, 19, 51, -101, 6, 71, -112, -7, + -60, -38, 91, -41, -49, 77, -22, -60, 64, -3, -70, 51, + 16, -81, 37, 35, -92, 23, 54, -102, 10, 73, -113, -3, + -58, -40, 96, -38, -50, 82, -19, -61, 69, -1, -72, 55, + 19, -83, 41, 38, -93, 28, 56, -104, 15, 76, -115, 1, + -55, -41, 100, -36, -52, 86, -17, -62, 73, 2, -73, 59, + 21, -84, 45, 40, -95, 32, 59, -105, 19, 78, -116, 5, + -53, -42, 104, -33, -53, 90, -15, -64, 77, 4, -74, 63, + 24, -85, 49, 42, -96, 36, 61, -107, 23, 81, -117, 9, + -50, -44, 108, -31, -55, 94, -12, -65, 81, 7, -76, 67, + 26, -87, 53, 45, -97, 40, 64, -108, 27, 83, -119, 13, + -48, -45, 112, -28, -56, 98, -9, -67, 85, 9, -77, 72, + 29, -88, 58, 47, -99, 44, 66, -109, 31, 86, -120, 17, + -45, -46, 116, -26, -57, 102, -7, -68, 89, 12, -79, 76, + 31, -90, 62, 50, -100, 48, 69, -111, 35, 88, -122, 21, + -43, -48, 120, -23, -59, 106, -5, -69, 93, 14, -80, 80, + 33, -91, 66, 52, -101, 52, 71, -112, 39, 90, -123, 25, + -118, -1, -7, -99, -12, -21, -80, -22, -34, -61, -33, -47, + -42, -44, -61, -23, -54, -75, -4, -65, -88, 15, -76, -102, + -116, -2, -3, -96, -13, -17, -78, -24, -30, -59, -34, -43, + -39, -45, -57, -21, -56, -71, -2, -66, -84, 17, -77, -98, + -113, -4, 0, -94, -14, -13, -75, -25, -26, -56, -36, -39, + -37, -47, -53, -18, -57, -67, 0, -68, -80, 20, -79, -94, + -111, -5, 5, -91, -16, -8, -73, -27, -22, -54, -37, -35, + -34, -48, -49, -16, -59, -62, 3, -69, -76, 23, -80, -89, + -108, -6, 9, -89, -17, -4, -70, -28, -18, -51, -39, -31, + -32, -49, -45, -13, -60, -58, 6, -71, -72, 25, -82, -85, + -106, -8, 13, -87, -19, 0, -68, -29, -14, -49, -40, -27, + -30, -51, -41, -11, -61, -54, 8, -72, -68, 27, -83, -81, + -104, -9, 17, -84, -20, 3, -65, -31, -10, -47, -41, -23, + -27, -52, -37, -8, -63, -50, 10, -73, -64, 30, -84, -77, + -101, -11, 21, -81, -22, 7, -63, -32, -5, -44, -43, -18, + -25, -54, -32, -6, -64, -46, 13, -75, -59, 32, -86, -73, + -98, -12, 25, -79, -23, 11, -60, -33, -1, -42, -44, -14, + -22, -55, -28, -3, -66, -42, 15, -76, -55, 35, -87, -69, + -96, -13, 29, -77, -24, 15, -58, -35, 2, -39, -45, -10, + -20, -56, -24, -1, -67, -38, 18, -78, -51, 37, -88, -65, + -94, -15, 33, -74, -26, 19, -56, -36, 6, -37, -47, -6, + -17, -58, -20, 1, -68, -34, 20, -79, -47, 40, -90, -61, + -91, -16, 37, -72, -27, 23, -53, -38, 10, -34, -48, -2, + -15, -59, -16, 4, -70, -30, 23, -80, -43, 42, -91, -57, + -89, -18, 42, -69, -28, 28, -50, -39, 14, -32, -50, 1, + -12, -61, -12, 6, -71, -25, 25, -82, -39, 45, -93, -52, + -86, -19, 46, -67, -30, 32, -48, -40, 18, -29, -51, 5, + -10, -62, -8, 9, -73, -21, 28, -83, -35, 47, -94, -48, + -84, -20, 50, -64, -31, 36, -46, -42, 22, -27, -52, 9, + -8, -63, -4, 11, -74, -17, 30, -84, -31, 49, -95, -44, + -81, -22, 54, -62, -32, 40, -43, -43, 26, -24, -54, 13, + -5, -65, 0, 14, -75, -13, 32, -86, -27, 52, -97, -40, + -79, -23, 58, -59, -34, 44, -41, -45, 31, -22, -55, 18, + -2, -66, 4, 16, -77, -9, 35, -87, -22, 55, -98, -36, + -76, -24, 62, -57, -35, 48, -38, -46, 35, -19, -57, 22, + 0, -67, 8, 19, -78, -5, 38, -89, -18, 57, -100, -32, + -74, -26, 66, -55, -37, 52, -36, -47, 39, -17, -58, 26, + 2, -69, 12, 21, -79, -1, 40, -90, -14, 59, -101, -28, + -72, -27, 70, -52, -38, 56, -33, -49, 43, -15, -59, 30, + 5, -70, 16, 24, -81, 2, 42, -91, -10, 62, -102, -24, + -69, -29, 75, -49, -40, 61, -31, -50, 47, -12, -61, 34, + 7, -72, 20, 26, -82, 7, 45, -93, -6, 64, -104, -19, + -66, -30, 79, -47, -41, 65, -28, -52, 51, -10, -62, 38, + 10, -73, 24, 29, -84, 11, 47, -94, -2, 67, -105, -15, + -64, -31, 83, -45, -42, 69, -26, -53, 55, -7, -63, 42, + 12, -74, 28, 31, -85, 15, 50, -96, 1, 69, -107, -11, + -62, -33, 87, -42, -44, 73, -24, -54, 59, -5, -65, 46, + 15, -76, 32, 33, -86, 19, 52, -97, 5, 72, -108, -7, + -59, -34, 91, -40, -45, 77, -21, -56, 63, -2, -66, 50, + 17, -77, 36, 36, -88, 23, 55, -98, 9, 74, -109, -3, + -57, -36, 95, -37, -46, 81, -18, -57, 68, 0, -68, 55, + 20, -79, 41, 38, -89, 27, 57, -100, 14, 77, -111, 0, + -54, -37, 99, -35, -48, 85, -16, -58, 72, 3, -69, 59, + 22, -80, 45, 41, -91, 31, 60, -101, 18, 79, -112, 4, + -52, -38, 103, -32, -49, 89, -14, -60, 76, 5, -70, 63, + 24, -81, 49, 43, -92, 35, 62, -103, 22, 81, -113, 8, + -49, -40, 107, -30, -51, 93, -11, -61, 80, 8, -72, 67, + 27, -83, 53, 46, -93, 39, 64, -104, 26, 84, -115, 12, + -47, -41, 112, -27, -52, 98, -9, -63, 84, 10, -73, 71, + 30, -84, 57, 48, -95, 44, 67, -105, 30, 87, -116, 17, + -44, -42, 116, -25, -53, 102, -6, -64, 88, 13, -75, 75, + 32, -86, 61, 51, -96, 48, 70, -107, 34, 89, -118, 21, + -42, -44, 120, -23, -55, 106, -4, -65, 92, 15, -76, 79, + 34, -87, 65, 53, -97, 52, 72, -108, 38, 91, -119, 25, + -117, 2, -8, -98, -8, -21, -79, -18, -35, -60, -29, -48, + -41, -40, -62, -22, -50, -75, -3, -61, -89, 16, -72, -103, + -115, 1, -4, -96, -9, -17, -77, -20, -31, -58, -30, -44, + -39, -41, -58, -20, -52, -71, -1, -62, -85, 18, -73, -99, + -113, 0, 0, -93, -10, -13, -74, -21, -27, -56, -32, -40, + -36, -43, -54, -17, -53, -67, 1, -64, -81, 21, -75, -95, + -110, -1, 4, -90, -12, -9, -72, -23, -22, -53, -33, -36, + -33, -44, -49, -15, -55, -63, 4, -65, -76, 23, -76, -90, + -107, -2, 8, -88, -13, -5, -69, -24, -18, -50, -35, -32, + -31, -45, -45, -12, -56, -59, 6, -67, -72, 26, -78, -86, + -105, -4, 12, -86, -15, -1, -67, -25, -14, -48, -36, -28, + -29, -47, -41, -10, -57, -55, 9, -68, -68, 28, -79, -82, + -103, -5, 16, -83, -16, 2, -64, -27, -10, -46, -37, -24, + -26, -48, -37, -8, -59, -51, 11, -69, -64, 31, -80, -78, + -100, -7, 21, -81, -18, 7, -62, -28, -6, -43, -39, -19, + -24, -50, -33, -5, -60, -46, 14, -71, -60, 33, -82, -74, + -98, -8, 25, -78, -19, 11, -59, -29, -2, -41, -40, -15, + -21, -51, -29, -2, -62, -42, 16, -72, -56, 36, -83, -70, + -95, -9, 29, -76, -20, 15, -57, -31, 1, -38, -41, -11, + -19, -52, -25, 0, -63, -38, 19, -74, -52, 38, -84, -66, + -93, -11, 33, -73, -22, 19, -55, -32, 5, -36, -43, -7, + -16, -54, -21, 2, -64, -34, 21, -75, -48, 40, -86, -62, + -90, -12, 37, -71, -23, 23, -52, -34, 9, -33, -44, -3, + -14, -55, -17, 5, -66, -30, 24, -76, -44, 43, -87, -58, + -88, -14, 41, -68, -24, 27, -50, -35, 14, -31, -46, 0, + -11, -57, -12, 7, -67, -26, 26, -78, -39, 46, -89, -53, + -85, -15, 45, -66, -26, 31, -47, -36, 18, -28, -47, 4, + -9, -58, -8, 10, -69, -22, 29, -79, -35, 48, -90, -49, + -83, -16, 49, -64, -27, 35, -45, -38, 22, -26, -48, 8, + -7, -59, -4, 12, -70, -18, 31, -80, -31, 50, -91, -45, + -81, -18, 53, -61, -28, 39, -42, -39, 26, -24, -50, 12, + -4, -61, 0, 15, -71, -14, 33, -82, -27, 53, -93, -41, + -78, -19, 58, -58, -30, 44, -40, -41, 30, -21, -51, 17, + -2, -62, 3, 17, -73, -9, 36, -83, -23, 55, -94, -37, + -75, -20, 62, -56, -31, 48, -37, -42, 34, -18, -53, 21, + 1, -63, 7, 20, -74, -5, 38, -85, -19, 58, -96, -33, + -73, -22, 66, -54, -33, 52, -35, -43, 38, -16, -54, 25, + 3, -65, 11, 22, -75, -1, 41, -86, -15, 60, -97, -29, + -71, -23, 70, -51, -34, 56, -32, -45, 42, -14, -55, 29, + 6, -66, 15, 24, -77, 2, 43, -87, -11, 63, -98, -25, + -68, -25, 74, -49, -36, 60, -30, -46, 47, -11, -57, 33, + 8, -68, 20, 27, -78, 6, 46, -89, -6, 65, -100, -20, + -66, -26, 78, -46, -37, 64, -27, -48, 51, -9, -58, 37, + 11, -69, 24, 30, -80, 10, 48, -90, -2, 68, -101, -16, + -63, -27, 82, -44, -38, 68, -25, -49, 55, -6, -59, 41, + 13, -70, 28, 32, -81, 14, 51, -92, 1, 70, -103, -12, + -61, -29, 86, -41, -40, 72, -23, -50, 59, -4, -61, 45, + 16, -72, 32, 34, -82, 18, 53, -93, 5, 72, -104, -8, + -58, -30, 90, -39, -41, 76, -20, -52, 63, -1, -62, 49, + 18, -73, 36, 37, -84, 22, 55, -94, 9, 75, -105, -4, + -56, -32, 95, -36, -42, 81, -18, -53, 67, 1, -64, 54, + 21, -75, 40, 39, -85, 27, 58, -96, 13, 78, -107, 0, + -53, -33, 99, -34, -44, 85, -15, -54, 71, 4, -65, 58, + 23, -76, 44, 42, -87, 31, 61, -97, 17, 80, -108, 3, + -51, -34, 103, -32, -45, 89, -13, -56, 75, 6, -66, 62, + 25, -77, 48, 44, -88, 35, 63, -99, 21, 82, -109, 7, + -49, -36, 107, -29, -47, 93, -10, -57, 79, 8, -68, 66, + 28, -79, 52, 47, -89, 39, 65, -100, 25, 85, -111, 11, + -46, -37, 111, -26, -48, 97, -8, -59, 84, 11, -69, 70, + 30, -80, 57, 49, -91, 43, 68, -101, 30, 87, -112, 16, + -43, -38, 115, -24, -49, 101, -5, -60, 88, 14, -71, 74, + 33, -82, 61, 52, -92, 47, 70, -103, 34, 90, -114, 20, + -41, -40, 119, -22, -51, 105, -3, -61, 92, 16, -72, 78, + 35, -83, 65, 54, -93, 51, 73, -104, 38, 92, -115, 24, + -116, 7, -8, -97, -3, -22, -78, -14, -35, -59, -24, -49, + -40, -35, -63, -21, -46, -76, -2, -57, -89, 17, -67, -103, + -114, 5, -4, -94, -5, -18, -76, -15, -31, -57, -26, -45, + -38, -37, -59, -19, -47, -72, 0, -58, -85, 19, -69, -99, + -111, 4, 0, -92, -6, -14, -73, -17, -27, -55, -27, -41, + -35, -38, -55, -16, -49, -68, 2, -59, -81, 22, -70, -95, + -109, 2, 3, -89, -7, -10, -71, -18, -23, -52, -29, -36, + -32, -40, -50, -14, -50, -64, 5, -61, -77, 24, -72, -91, + -106, 1, 7, -87, -9, -6, -68, -19, -19, -49, -30, -32, + -30, -41, -46, -11, -52, -60, 7, -62, -73, 27, -73, -87, + -104, 0, 11, -85, -10, -2, -66, -21, -15, -47, -31, -28, + -28, -42, -42, -9, -53, -56, 10, -63, -69, 29, -74, -83, + -102, -1, 15, -82, -12, 1, -63, -22, -11, -45, -33, -24, + -25, -44, -38, -7, -54, -52, 12, -65, -65, 32, -76, -79, + -99, -2, 20, -80, -13, 6, -61, -24, -6, -42, -34, -20, + -23, -45, -34, -4, -56, -47, 15, -66, -60, 34, -77, -74, + -97, -3, 24, -77, -14, 10, -58, -25, -2, -40, -36, -16, + -20, -47, -30, -1, -57, -43, 17, -68, -56, 37, -79, -70, + -94, -5, 28, -75, -16, 14, -56, -26, 1, -37, -37, -12, + -18, -48, -26, 1, -58, -39, 20, -69, -52, 39, -80, -66, + -92, -6, 32, -72, -17, 18, -54, -28, 5, -35, -38, -8, + -15, -49, -22, 3, -60, -35, 22, -70, -48, 42, -81, -62, + -89, -7, 36, -70, -18, 22, -51, -29, 9, -32, -40, -4, + -13, -51, -18, 6, -61, -31, 25, -72, -44, 44, -83, -58, + -87, -9, 40, -67, -20, 26, -49, -31, 13, -30, -41, 0, + -10, -52, -13, 8, -63, -27, 27, -73, -40, 47, -84, -54, + -84, -10, 44, -65, -21, 30, -46, -32, 17, -27, -42, 4, + -8, -53, -9, 11, -64, -23, 30, -75, -36, 49, -86, -50, + -82, -12, 48, -63, -23, 34, -44, -33, 21, -25, -44, 8, + -6, -55, -5, 13, -65, -19, 32, -76, -32, 51, -87, -46, + -79, -13, 52, -60, -24, 38, -41, -35, 25, -23, -45, 12, + -3, -56, -1, 16, -67, -15, 34, -77, -28, 54, -88, -42, + -77, -15, 57, -57, -26, 43, -39, -36, 30, -20, -47, 16, + 0, -58, 2, 18, -68, -10, 37, -79, -23, 56, -90, -37, + -74, -16, 61, -55, -27, 47, -36, -37, 34, -17, -48, 20, + 2, -59, 6, 21, -70, -6, 39, -80, -19, 59, -91, -33, + -72, -17, 65, -53, -28, 51, -34, -39, 38, -15, -49, 24, + 4, -60, 10, 23, -71, -2, 42, -82, -15, 61, -92, -29, + -70, -19, 69, -50, -30, 55, -31, -40, 42, -13, -51, 28, + 7, -62, 14, 25, -72, 1, 44, -83, -11, 64, -94, -25, + -67, -20, 73, -48, -31, 59, -29, -42, 46, -10, -52, 33, + 9, -63, 19, 28, -74, 5, 47, -84, -7, 66, -95, -21, + -65, -21, 77, -45, -32, 63, -26, -43, 50, -8, -54, 37, + 12, -65, 23, 31, -75, 9, 49, -86, -3, 69, -97, -17, + -62, -23, 81, -43, -34, 67, -24, -44, 54, -5, -55, 41, + 14, -66, 27, 33, -77, 13, 52, -87, 0, 71, -98, -13, + -60, -24, 85, -40, -35, 71, -22, -46, 58, -3, -56, 45, + 17, -67, 31, 35, -78, 17, 54, -88, 4, 74, -99, -9, + -57, -26, 89, -38, -36, 75, -19, -47, 62, 0, -58, 49, + 19, -69, 35, 38, -79, 21, 57, -90, 8, 76, -101, -5, + -55, -27, 94, -35, -38, 80, -17, -49, 67, 2, -59, 53, + 22, -70, 39, 40, -81, 26, 59, -91, 13, 79, -102, 0, + -52, -28, 98, -33, -39, 84, -14, -50, 71, 5, -61, 57, + 24, -71, 43, 43, -82, 30, 62, -93, 17, 81, -104, 3, + -50, -30, 102, -31, -41, 88, -12, -51, 75, 7, -62, 61, + 26, -73, 47, 45, -83, 34, 64, -94, 21, 83, -105, 7, + -47, -31, 106, -28, -42, 92, -9, -53, 79, 9, -63, 65, + 29, -74, 51, 48, -85, 38, 66, -95, 25, 86, -106, 11, + -45, -33, 110, -25, -44, 96, -7, -54, 83, 12, -65, 70, + 32, -76, 56, 50, -86, 42, 69, -97, 29, 88, -108, 15, + -42, -34, 114, -23, -45, 100, -4, -56, 87, 15, -66, 74, + 34, -77, 60, 53, -88, 46, 71, -98, 33, 91, -109, 19, + -40, -35, 118, -21, -46, 104, -2, -57, 91, 17, -67, 78, + 36, -78, 64, 55, -89, 50, 74, -100, 37, 93, -111, 23, + -115, 11, -9, -96, 0, -23, -77, -10, -36, -58, -20, -49, + -39, -31, -63, -20, -42, -77, -1, -53, -90, 18, -63, -104, + -113, 9, -5, -94, -1, -19, -75, -11, -32, -56, -22, -45, + -37, -33, -59, -18, -43, -73, 1, -54, -86, 20, -65, -100, + -111, 8, -1, -91, -2, -15, -72, -13, -28, -54, -23, -41, + -34, -34, -55, -15, -45, -69, 3, -55, -82, 23, -66, -96, + -108, 6, 3, -88, -3, -10, -70, -14, -24, -51, -25, -37, + -32, -36, -51, -13, -46, -64, 6, -57, -78, 25, -68, -91, + -105, 5, 7, -86, -5, -6, -67, -15, -20, -49, -26, -33, + -29, -37, -47, -10, -48, -60, 8, -58, -74, 28, -69, -87, + -103, 4, 11, -84, -6, -2, -65, -17, -16, -46, -27, -29, + -27, -38, -43, -8, -49, -56, 11, -59, -70, 30, -70, -83, + -101, 2, 15, -81, -8, 1, -63, -18, -12, -44, -29, -25, + -24, -40, -39, -6, -50, -52, 13, -61, -66, 33, -72, -79, + -98, 1, 19, -79, -9, 5, -60, -20, -7, -41, -30, -20, + -22, -41, -34, -3, -52, -48, 16, -62, -61, 35, -73, -75, + -96, 0, 23, -76, -10, 9, -57, -21, -3, -39, -32, -16, + -19, -43, -30, -1, -53, -44, 18, -64, -57, 38, -75, -71, + -93, -1, 27, -74, -12, 13, -55, -22, 0, -36, -33, -12, + -17, -44, -26, 2, -54, -40, 21, -65, -53, 40, -76, -67, + -91, -2, 31, -71, -13, 17, -53, -24, 4, -34, -34, -8, + -15, -45, -22, 4, -56, -36, 23, -66, -49, 42, -77, -63, + -88, -3, 35, -69, -14, 21, -50, -25, 8, -31, -36, -4, + -12, -47, -18, 7, -57, -32, 25, -68, -45, 45, -79, -59, + -86, -5, 40, -66, -16, 26, -48, -27, 12, -29, -37, 0, + -9, -48, -14, 9, -59, -27, 28, -69, -41, 48, -80, -54, + -83, -6, 44, -64, -17, 30, -45, -28, 16, -26, -38, 3, + -7, -49, -10, 12, -60, -23, 31, -71, -37, 50, -82, -50, + -81, -8, 48, -62, -19, 34, -43, -29, 20, -24, -40, 7, + -5, -51, -6, 14, -61, -19, 33, -72, -33, 52, -83, -46, + -79, -9, 52, -59, -20, 38, -40, -31, 24, -22, -41, 11, + -2, -52, -2, 17, -63, -15, 35, -73, -29, 55, -84, -42, + -76, -11, 56, -57, -22, 42, -38, -32, 29, -19, -43, 16, + 0, -54, 2, 19, -64, -11, 38, -75, -24, 57, -86, -38, + -73, -12, 60, -54, -23, 46, -35, -33, 33, -17, -44, 20, + 3, -55, 6, 22, -66, -7, 40, -76, -20, 60, -87, -34, + -71, -13, 64, -52, -24, 50, -33, -35, 37, -14, -45, 24, + 5, -56, 10, 24, -67, -3, 43, -78, -16, 62, -88, -30, + -69, -15, 68, -49, -26, 54, -31, -36, 41, -12, -47, 28, + 8, -58, 14, 26, -68, 0, 45, -79, -12, 65, -90, -26, + -66, -16, 73, -47, -27, 59, -28, -38, 45, -9, -48, 32, + 10, -59, 18, 29, -70, 5, 48, -80, -8, 67, -91, -21, + -64, -17, 77, -44, -28, 63, -25, -39, 49, -7, -50, 36, + 13, -61, 22, 31, -71, 9, 50, -82, -4, 70, -93, -17, + -61, -19, 81, -42, -30, 67, -23, -40, 53, -4, -51, 40, + 15, -62, 26, 34, -73, 13, 53, -83, 0, 72, -94, -13, + -59, -20, 85, -39, -31, 71, -21, -42, 57, -2, -52, 44, + 17, -63, 30, 36, -74, 17, 55, -84, 3, 74, -95, -9, + -56, -22, 89, -37, -32, 75, -18, -43, 61, 0, -54, 48, + 20, -65, 34, 39, -75, 21, 57, -86, 7, 77, -97, -5, + -54, -23, 93, -34, -34, 79, -16, -45, 66, 3, -55, 53, + 23, -66, 39, 41, -77, 25, 60, -87, 12, 79, -98, -1, + -51, -24, 97, -32, -35, 83, -13, -46, 70, 6, -57, 57, + 25, -67, 43, 44, -78, 29, 63, -89, 16, 82, -100, 2, + -49, -26, 101, -30, -37, 87, -11, -47, 74, 8, -58, 61, + 27, -69, 47, 46, -79, 33, 65, -90, 20, 84, -101, 6, + -47, -27, 105, -27, -38, 91, -8, -49, 78, 10, -59, 65, + 30, -70, 51, 49, -81, 37, 67, -91, 24, 87, -102, 10, + -44, -29, 110, -25, -40, 96, -6, -50, 82, 13, -61, 69, + 32, -72, 55, 51, -82, 42, 70, -93, 28, 89, -104, 15, + -41, -30, 114, -22, -41, 100, -3, -52, 86, 15, -62, 73, + 35, -73, 59, 54, -84, 46, 72, -94, 32, 92, -105, 19, + -39, -31, 118, -20, -42, 104, -1, -53, 90, 18, -63, 77, + 37, -74, 63, 56, -85, 50, 75, -96, 36, 94, -107, 23, + -114, 15, -10, -95, 4, -23, -76, -6, -37, -57, -16, -50, + -38, -27, -64, -19, -38, -77, -1, -49, -91, 19, -59, -105, + -112, 13, -6, -93, 2, -19, -74, -7, -33, -55, -18, -46, + -36, -29, -60, -17, -39, -73, 2, -50, -87, 21, -61, -101, + -110, 12, -2, -90, 1, -15, -71, -9, -29, -53, -19, -42, + -33, -30, -56, -15, -41, -69, 4, -51, -83, 24, -62, -97, + -107, 10, 2, -88, 0, -11, -69, -10, -24, -50, -21, -38, + -31, -32, -51, -12, -42, -65, 7, -53, -78, 26, -64, -92, + -105, 9, 6, -85, -1, -7, -66, -11, -20, -48, -22, -34, + -28, -33, -47, -9, -44, -61, 9, -54, -74, 29, -65, -88, + -102, 8, 10, -83, -2, -3, -64, -13, -16, -45, -23, -30, + -26, -34, -43, -7, -45, -57, 12, -55, -70, 31, -66, -84, + -100, 6, 14, -80, -4, 0, -62, -14, -12, -43, -25, -26, + -23, -36, -39, -5, -46, -53, 14, -57, -66, 33, -68, -80, + -97, 5, 18, -78, -5, 5, -59, -16, -8, -40, -26, -21, + -21, -37, -35, -2, -48, -48, 17, -58, -62, 36, -69, -76, + -95, 4, 22, -75, -6, 9, -57, -17, -4, -38, -28, -17, + -18, -39, -31, 0, -49, -44, 19, -60, -58, 39, -71, -72, + -92, 2, 26, -73, -8, 13, -54, -18, 0, -35, -29, -13, + -16, -40, -27, 3, -50, -40, 22, -61, -54, 41, -72, -68, + -90, 1, 30, -71, -9, 17, -52, -20, 3, -33, -30, -9, + -14, -41, -23, 5, -52, -36, 24, -62, -50, 43, -73, -64, + -88, 0, 34, -68, -10, 21, -49, -21, 7, -31, -32, -5, + -11, -43, -19, 8, -53, -32, 26, -64, -46, 46, -75, -60, + -85, -1, 39, -65, -12, 25, -47, -23, 12, -28, -33, -1, + -9, -44, -14, 10, -55, -28, 29, -65, -41, 48, -76, -55, + -82, -2, 43, -63, -13, 29, -44, -24, 16, -26, -34, 2, + -6, -45, -10, 13, -56, -24, 31, -67, -37, 51, -78, -51, + -80, -4, 47, -61, -15, 33, -42, -25, 20, -23, -36, 6, + -4, -47, -6, 15, -57, -20, 34, -68, -33, 53, -79, -47, + -78, -5, 51, -58, -16, 37, -40, -27, 24, -21, -37, 10, + -1, -48, -2, 17, -59, -16, 36, -69, -29, 56, -80, -43, + -75, -7, 55, -56, -18, 42, -37, -28, 28, -18, -39, 15, + 1, -50, 1, 20, -60, -11, 39, -71, -25, 58, -82, -39, + -73, -8, 59, -53, -19, 46, -34, -29, 32, -16, -40, 19, + 4, -51, 5, 23, -62, -7, 41, -72, -21, 61, -83, -35, + -70, -9, 63, -51, -20, 50, -32, -31, 36, -13, -41, 23, + 6, -52, 9, 25, -63, -3, 44, -74, -17, 63, -84, -31, + -68, -11, 67, -48, -22, 54, -30, -32, 40, -11, -43, 27, + 9, -54, 13, 27, -64, 0, 46, -75, -13, 65, -86, -27, + -65, -12, 72, -46, -23, 58, -27, -34, 45, -8, -44, 31, + 11, -55, 18, 30, -66, 4, 49, -76, -8, 68, -87, -22, + -63, -13, 76, -43, -24, 62, -25, -35, 49, -6, -46, 35, + 14, -57, 22, 32, -67, 8, 51, -78, -4, 71, -89, -18, + -60, -15, 80, -41, -26, 66, -22, -36, 53, -3, -47, 39, + 16, -58, 26, 35, -69, 12, 54, -79, 0, 73, -90, -14, + -58, -16, 84, -39, -27, 70, -20, -38, 57, -1, -48, 43, + 18, -59, 30, 37, -70, 16, 56, -80, 3, 75, -91, -10, + -56, -18, 88, -36, -28, 74, -17, -39, 61, 1, -50, 47, + 21, -61, 34, 40, -71, 20, 58, -82, 7, 78, -93, -6, + -53, -19, 92, -33, -30, 79, -15, -41, 65, 4, -51, 52, + 23, -62, 38, 42, -73, 25, 61, -83, 11, 80, -94, -2, + -50, -20, 96, -31, -31, 83, -12, -42, 69, 6, -53, 56, + 26, -63, 42, 45, -74, 29, 63, -85, 15, 83, -96, 1, + -48, -22, 100, -29, -33, 87, -10, -43, 73, 9, -54, 60, + 28, -65, 46, 47, -75, 33, 66, -86, 19, 85, -97, 5, + -46, -23, 104, -26, -34, 91, -8, -45, 77, 11, -55, 64, + 31, -66, 50, 49, -77, 37, 68, -87, 23, 88, -98, 9, + -43, -25, 109, -24, -36, 95, -5, -46, 82, 14, -57, 68, + 33, -68, 55, 52, -78, 41, 71, -89, 28, 90, -100, 14, + -41, -26, 113, -21, -37, 99, -2, -48, 86, 16, -58, 72, + 36, -69, 59, 55, -80, 45, 73, -90, 32, 93, -101, 18, + -38, -27, 117, -19, -38, 103, 0, -49, 90, 19, -59, 76, + 38, -70, 63, 57, -81, 49, 76, -92, 36, 95, -103, 22, + -114, 19, -10, -94, 8, -24, -75, -2, -37, -57, -12, -51, + -37, -23, -65, -18, -34, -78, 0, -45, -91, 20, -55, -105, + -111, 17, -6, -92, 6, -20, -73, -3, -33, -54, -14, -47, + -35, -25, -61, -16, -35, -74, 3, -46, -87, 22, -57, -101, + -109, 16, -2, -89, 5, -16, -71, -5, -29, -52, -15, -43, + -32, -26, -57, -14, -37, -70, 5, -47, -83, 25, -58, -97, + -106, 14, 1, -87, 4, -12, -68, -6, -25, -49, -17, -38, + -30, -28, -52, -11, -38, -66, 8, -49, -79, 27, -60, -93, + -104, 13, 5, -84, 2, -8, -66, -7, -21, -47, -18, -34, + -27, -29, -48, -9, -40, -62, 10, -50, -75, 30, -61, -89, + -101, 12, 9, -82, 1, -4, -63, -9, -17, -44, -19, -30, + -25, -30, -44, -6, -41, -58, 13, -51, -71, 32, -62, -85, + -99, 10, 13, -79, 0, 0, -61, -10, -13, -42, -21, -26, + -23, -32, -40, -4, -42, -54, 15, -53, -67, 34, -64, -81, + -96, 9, 18, -77, -1, 4, -58, -12, -8, -39, -22, -22, + -20, -33, -36, -1, -44, -49, 18, -54, -62, 37, -65, -76, + -94, 8, 22, -74, -2, 8, -56, -13, -4, -37, -24, -18, + -17, -35, -32, 1, -45, -45, 20, -56, -58, 39, -67, -72, + -91, 6, 26, -72, -4, 12, -53, -14, 0, -34, -25, -14, + -15, -36, -28, 4, -46, -41, 22, -57, -54, 42, -68, -68, + -89, 5, 30, -70, -5, 16, -51, -16, 3, -32, -26, -10, + -13, -37, -24, 6, -48, -37, 25, -58, -50, 44, -69, -64, + -87, 4, 34, -67, -6, 20, -48, -17, 7, -30, -28, -6, + -10, -39, -20, 8, -49, -33, 27, -60, -46, 47, -71, -60, + -84, 2, 38, -65, -8, 25, -46, -19, 11, -27, -29, -1, + -8, -40, -15, 11, -51, -29, 30, -61, -42, 49, -72, -56, + -82, 1, 42, -62, -9, 29, -43, -20, 15, -25, -30, 2, + -5, -41, -11, 14, -52, -25, 32, -63, -38, 52, -74, -52, + -79, 0, 46, -60, -11, 33, -41, -21, 19, -22, -32, 6, + -3, -43, -7, 16, -53, -21, 35, -64, -34, 54, -75, -48, + -77, -1, 50, -57, -12, 37, -39, -23, 23, -20, -33, 10, + 0, -44, -3, 18, -55, -17, 37, -65, -30, 57, -76, -44, + -74, -3, 55, -55, -14, 41, -36, -24, 28, -17, -35, 14, + 2, -46, 0, 21, -56, -12, 40, -67, -25, 59, -78, -39, + -72, -4, 59, -52, -15, 45, -34, -25, 32, -15, -36, 18, + 5, -47, 4, 23, -58, -8, 42, -68, -21, 62, -79, -35, + -69, -5, 63, -50, -16, 49, -31, -27, 36, -12, -37, 22, + 7, -48, 8, 26, -59, -4, 45, -70, -17, 64, -80, -31, + -67, -7, 67, -48, -18, 53, -29, -28, 40, -10, -39, 26, + 9, -50, 12, 28, -60, 0, 47, -71, -13, 66, -82, -27, + -64, -8, 71, -45, -19, 58, -26, -30, 44, -7, -40, 31, + 12, -51, 17, 31, -62, 3, 50, -72, -9, 69, -83, -23, + -62, -9, 75, -42, -20, 61, -24, -31, 48, -5, -42, 35, + 15, -53, 21, 33, -63, 7, 52, -74, -5, 71, -85, -19, + -59, -11, 79, -40, -22, 65, -21, -32, 52, -2, -43, 39, + 17, -54, 25, 36, -65, 11, 54, -75, -1, 74, -86, -15, + -57, -12, 83, -38, -23, 69, -19, -34, 56, 0, -44, 43, + 19, -55, 29, 38, -66, 15, 57, -76, 2, 76, -87, -11, + -55, -14, 87, -35, -24, 73, -16, -35, 60, 2, -46, 47, + 22, -57, 33, 40, -67, 19, 59, -78, 6, 79, -89, -7, + -52, -15, 92, -33, -26, 78, -14, -37, 65, 5, -47, 51, + 24, -58, 37, 43, -69, 24, 62, -79, 11, 81, -90, -2, + -50, -16, 96, -30, -27, 82, -11, -38, 69, 7, -49, 55, + 27, -59, 41, 46, -70, 28, 64, -81, 15, 84, -92, 1, + -47, -18, 100, -28, -29, 86, -9, -39, 73, 10, -50, 59, + 29, -61, 45, 48, -71, 32, 67, -82, 19, 86, -93, 5, + -45, -19, 104, -25, -30, 90, -7, -41, 77, 12, -51, 63, + 32, -62, 49, 50, -73, 36, 69, -83, 23, 88, -94, 9, + -42, -21, 108, -23, -32, 94, -4, -42, 81, 15, -53, 68, + 34, -64, 54, 53, -74, 40, 72, -85, 27, 91, -96, 13, + -40, -22, 112, -20, -33, 98, -2, -44, 85, 17, -54, 72, + 37, -65, 58, 55, -76, 44, 74, -86, 31, 94, -97, 17, + -37, -23, 116, -18, -34, 102, 1, -45, 89, 20, -55, 76, + 39, -66, 62, 58, -77, 48, 77, -88, 35, 96, -99, 21, + -112, 23, -11, -93, 12, -25, -74, 2, -38, -56, -8, -52, + -36, -19, -65, -17, -29, -79, 1, -40, -92, 21, -51, -106, + -110, 22, -7, -91, 11, -21, -72, 0, -34, -53, -9, -48, + -34, -20, -61, -15, -31, -75, 4, -41, -88, 23, -52, -102, + -108, 21, -3, -88, 10, -17, -70, 0, -30, -51, -11, -44, + -31, -22, -57, -13, -32, -71, 6, -43, -84, 26, -54, -98, + -105, 19, 1, -86, 8, -12, -67, -2, -26, -48, -12, -39, + -29, -23, -53, -10, -34, -66, 9, -44, -80, 28, -55, -93, + -103, 18, 5, -83, 7, -8, -64, -3, -22, -46, -14, -35, + -26, -24, -49, -8, -35, -62, 11, -46, -76, 31, -57, -89, + -100, 16, 9, -81, 5, -4, -62, -4, -18, -43, -15, -31, + -24, -26, -45, -5, -36, -58, 14, -47, -72, 33, -58, -85, + -98, 15, 13, -78, 4, 0, -60, -6, -14, -41, -16, -27, + -22, -27, -41, -3, -38, -54, 16, -48, -68, 35, -59, -81, + -95, 13, 17, -76, 2, 3, -57, -7, -9, -38, -18, -23, + -19, -29, -36, 0, -39, -50, 19, -50, -63, 38, -61, -77, + -93, 12, 21, -73, 1, 7, -55, -8, -5, -36, -19, -19, + -16, -30, -32, 2, -41, -46, 21, -51, -59, 40, -62, -73, + -90, 11, 25, -71, 0, 11, -52, -10, -1, -33, -20, -15, + -14, -31, -28, 5, -42, -42, 24, -53, -55, 43, -63, -69, + -88, 9, 29, -69, -1, 15, -50, -11, 2, -31, -22, -11, + -12, -33, -24, 7, -43, -38, 26, -54, -51, 45, -65, -65, + -86, 8, 33, -66, -2, 19, -47, -13, 6, -29, -23, -7, + -9, -34, -20, 10, -45, -34, 28, -55, -47, 48, -66, -61, + -83, 6, 38, -64, -3, 24, -45, -14, 10, -26, -25, -2, + -7, -36, -16, 12, -46, -29, 31, -57, -43, 50, -68, -56, + -81, 5, 42, -61, -5, 28, -42, -15, 14, -24, -26, 1, + -4, -37, -12, 15, -48, -25, 33, -58, -39, 53, -69, -52, + -78, 4, 46, -59, -6, 32, -40, -17, 18, -21, -27, 5, + -2, -38, -8, 17, -49, -21, 36, -59, -35, 55, -70, -48, + -76, 2, 50, -56, -7, 36, -38, -18, 22, -19, -29, 9, + 1, -40, -4, 19, -50, -17, 38, -61, -31, 58, -72, -44, + -73, 1, 54, -54, -9, 40, -35, -20, 27, -16, -30, 13, + 3, -41, 0, 22, -52, -13, 41, -62, -26, 60, -73, -40, + -71, 0, 58, -51, -10, 44, -32, -21, 31, -14, -32, 17, + 6, -42, 4, 24, -53, -9, 43, -64, -22, 63, -75, -36, + -68, -1, 62, -49, -12, 48, -30, -22, 35, -11, -33, 21, + 8, -44, 8, 27, -54, -5, 46, -65, -18, 65, -76, -32, + -66, -2, 66, -46, -13, 52, -28, -24, 39, -9, -34, 25, + 10, -45, 12, 29, -56, -1, 48, -66, -14, 67, -77, -28, + -63, -4, 71, -44, -15, 57, -25, -25, 43, -6, -36, 30, + 13, -47, 16, 32, -57, 3, 51, -68, -10, 70, -79, -23, + -61, -5, 75, -41, -16, 61, -23, -27, 47, -4, -37, 34, + 16, -48, 20, 34, -59, 7, 53, -69, -6, 72, -80, -19, + -58, -6, 79, -39, -17, 65, -20, -28, 51, -1, -38, 38, + 18, -49, 24, 37, -60, 11, 56, -71, -2, 75, -82, -15, + -56, -8, 83, -37, -19, 69, -18, -29, 55, 1, -40, 42, + 20, -51, 28, 39, -61, 15, 58, -72, 1, 77, -83, -11, + -54, -9, 87, -34, -20, 73, -15, -31, 59, 3, -41, 46, + 23, -52, 32, 42, -63, 19, 60, -73, 5, 80, -84, -7, + -51, -11, 91, -32, -21, 77, -13, -32, 64, 6, -43, 50, + 25, -54, 37, 44, -64, 23, 63, -75, 10, 82, -86, -3, + -49, -12, 95, -29, -23, 81, -10, -33, 68, 8, -44, 54, + 28, -55, 41, 47, -66, 27, 65, -76, 14, 85, -87, 0, + -46, -13, 99, -27, -24, 85, -8, -35, 72, 11, -45, 58, + 30, -56, 45, 49, -67, 31, 68, -78, 18, 87, -88, 4, + -44, -15, 103, -24, -26, 89, -6, -36, 76, 13, -47, 62, + 33, -58, 49, 51, -68, 35, 70, -79, 22, 90, -90, 8, + -41, -16, 108, -22, -27, 94, -3, -38, 80, 16, -48, 67, + 35, -59, 53, 54, -70, 40, 73, -80, 26, 92, -91, 13, + -39, -17, 112, -19, -28, 98, 0, -39, 84, 18, -50, 71, + 38, -61, 57, 56, -71, 44, 75, -82, 30, 95, -93, 17, + -36, -19, 116, -17, -30, 102, 2, -40, 88, 21, -51, 75, + 40, -62, 61, 59, -72, 48, 78, -83, 34, 97, -94, 21, + -112, 27, -12, -92, 16, -25, -73, 6, -39, -55, -4, -52, + -35, -15, -66, -16, -25, -79, 2, -36, -93, 22, -47, -107, + -109, 26, -8, -90, 15, -21, -71, 4, -35, -52, -5, -48, + -33, -16, -62, -14, -27, -75, 5, -37, -89, 24, -48, -103, + -107, 25, -4, -87, 14, -17, -69, 3, -31, -50, -7, -44, + -30, -18, -58, -12, -28, -71, 7, -39, -85, 26, -50, -99, + -104, 23, 0, -85, 12, -13, -66, 1, -26, -47, -8, -40, + -28, -19, -53, -9, -30, -67, 10, -40, -80, 29, -51, -94, + -102, 22, 4, -82, 11, -9, -64, 0, -22, -45, -10, -36, + -25, -20, -49, -7, -31, -63, 12, -42, -76, 32, -53, -90, + -99, 20, 8, -80, 9, -5, -61, 0, -18, -42, -11, -32, + -23, -22, -45, -4, -32, -59, 15, -43, -72, 34, -54, -86, + -97, 19, 12, -78, 8, -1, -59, -2, -14, -40, -12, -28, + -21, -23, -41, -2, -34, -55, 17, -44, -68, 36, -55, -82, + -94, 17, 16, -75, 6, 3, -56, -3, -10, -37, -14, -23, + -18, -25, -37, 1, -35, -50, 20, -46, -64, 39, -57, -78, + -92, 16, 20, -72, 5, 7, -54, -4, -6, -35, -15, -19, + -16, -26, -33, 3, -37, -46, 22, -47, -60, 41, -58, -74, + -89, 15, 24, -70, 4, 11, -51, -6, -2, -33, -16, -15, + -13, -27, -29, 6, -38, -42, 24, -49, -56, 44, -59, -70, + -87, 13, 28, -68, 2, 15, -49, -7, 1, -30, -18, -11, + -11, -29, -25, 8, -39, -38, 27, -50, -52, 46, -61, -66, + -85, 12, 32, -65, 1, 19, -47, -9, 5, -28, -19, -7, + -8, -30, -21, 10, -41, -34, 29, -51, -48, 49, -62, -62, + -82, 10, 37, -63, 0, 23, -44, -10, 10, -25, -21, -3, + -6, -32, -16, 13, -42, -30, 32, -53, -43, 51, -64, -57, + -80, 9, 41, -60, -1, 27, -41, -11, 14, -23, -22, 0, + -3, -33, -12, 16, -44, -26, 34, -54, -39, 54, -65, -53, + -77, 8, 45, -58, -2, 31, -39, -13, 18, -20, -23, 4, + -1, -34, -8, 18, -45, -22, 37, -55, -35, 56, -66, -49, + -75, 6, 49, -55, -3, 35, -37, -14, 22, -18, -25, 8, + 2, -36, -4, 20, -46, -18, 39, -57, -31, 58, -68, -45, + -72, 5, 53, -53, -5, 40, -34, -16, 26, -15, -26, 13, + 4, -37, 0, 23, -48, -13, 42, -58, -27, 61, -69, -41, + -70, 4, 57, -50, -6, 44, -32, -17, 30, -13, -28, 17, + 7, -38, 3, 25, -49, -9, 44, -60, -23, 64, -71, -37, + -67, 2, 61, -48, -8, 48, -29, -18, 34, -10, -29, 21, + 9, -40, 7, 28, -50, -5, 47, -61, -19, 66, -72, -33, + -65, 1, 65, -46, -9, 52, -27, -20, 38, -8, -30, 25, + 11, -41, 11, 30, -52, -1, 49, -62, -15, 68, -73, -29, + -62, 0, 70, -43, -11, 56, -24, -21, 43, -5, -32, 29, + 14, -43, 16, 33, -53, 2, 52, -64, -10, 71, -75, -24, + -60, -1, 74, -40, -12, 60, -22, -23, 47, -3, -33, 33, + 16, -44, 20, 35, -55, 6, 54, -65, -6, 73, -76, -20, + -57, -2, 78, -38, -13, 64, -19, -24, 51, -1, -34, 37, + 19, -45, 24, 38, -56, 10, 56, -67, -2, 76, -78, -16, + -55, -4, 82, -36, -15, 68, -17, -25, 55, 2, -36, 41, + 21, -47, 28, 40, -57, 14, 59, -68, 1, 78, -79, -12, + -53, -5, 86, -33, -16, 72, -15, -27, 59, 4, -37, 45, + 24, -48, 32, 42, -59, 18, 61, -69, 5, 81, -80, -8, + -50, -7, 90, -31, -17, 77, -12, -28, 63, 7, -39, 50, + 26, -50, 36, 45, -60, 23, 64, -71, 9, 83, -82, -4, + -48, -8, 94, -28, -19, 81, -9, -29, 67, 9, -40, 54, + 29, -51, 40, 47, -62, 27, 66, -72, 13, 86, -83, 0, + -45, -9, 98, -26, -20, 85, -7, -31, 71, 12, -41, 58, + 31, -52, 44, 50, -63, 31, 69, -74, 17, 88, -84, 3, + -43, -11, 102, -23, -22, 89, -5, -32, 75, 14, -43, 62, + 33, -54, 48, 52, -64, 35, 71, -75, 21, 90, -86, 7, + -40, -12, 107, -21, -23, 93, -2, -34, 80, 17, -44, 66, + 36, -55, 53, 55, -66, 39, 74, -76, 26, 93, -87, 12, + -38, -13, 111, -18, -24, 97, 0, -35, 84, 19, -46, 70, + 39, -57, 57, 57, -67, 43, 76, -78, 30, 96, -89, 16, + -35, -15, 115, -16, -26, 101, 3, -36, 88, 22, -47, 74, + 41, -58, 61, 60, -68, 47, 79, -79, 34, 98, -90, 20, + -111, 31, -12, -91, 20, -26, -73, 10, -39, -54, 0, -53, + -34, -11, -67, -16, -21, -80, 3, -32, -93, 23, -43, -107, + -108, 30, -8, -89, 19, -22, -70, 8, -35, -51, -1, -49, + -32, -12, -63, -13, -23, -76, 6, -33, -89, 25, -44, -103, + -106, 29, -4, -87, 18, -18, -68, 7, -31, -49, -3, -45, + -30, -14, -59, -11, -24, -72, 8, -35, -85, 27, -46, -99, + -103, 27, 0, -84, 16, -14, -65, 5, -27, -46, -4, -40, + -27, -15, -54, -8, -26, -68, 11, -36, -81, 30, -47, -95, + -101, 26, 3, -81, 15, -10, -63, 4, -23, -44, -6, -36, + -24, -16, -50, -6, -27, -64, 13, -38, -77, 32, -49, -91, + -98, 24, 7, -79, 13, -6, -60, 3, -19, -41, -7, -32, + -22, -18, -46, -3, -28, -60, 15, -39, -73, 35, -50, -87, + -96, 23, 11, -77, 12, -2, -58, 1, -15, -39, -8, -28, + -20, -19, -42, -1, -30, -56, 18, -40, -69, 37, -51, -83, + -93, 21, 16, -74, 10, 2, -55, 0, -10, -36, -10, -24, + -17, -21, -38, 2, -31, -51, 21, -42, -64, 40, -53, -78, + -91, 20, 20, -72, 9, 6, -53, 0, -6, -34, -11, -20, + -15, -22, -34, 4, -33, -47, 23, -43, -60, 42, -54, -74, + -89, 19, 24, -69, 8, 10, -50, -2, -2, -32, -12, -16, + -12, -23, -30, 7, -34, -43, 25, -45, -56, 45, -55, -70, + -86, 17, 28, -67, 6, 14, -48, -3, 1, -29, -14, -12, + -10, -25, -26, 9, -35, -39, 28, -46, -52, 47, -57, -66, + -84, 16, 32, -64, 5, 18, -46, -5, 5, -27, -15, -8, + -7, -26, -22, 11, -37, -35, 30, -47, -48, 49, -58, -62, + -81, 14, 36, -62, 4, 22, -43, -6, 9, -24, -17, -3, + -5, -28, -17, 14, -38, -31, 33, -49, -44, 52, -60, -58, + -79, 13, 40, -59, 2, 26, -41, -7, 13, -22, -18, 0, + -2, -29, -13, 16, -40, -27, 35, -50, -40, 55, -61, -54, + -76, 12, 44, -57, 1, 30, -38, -9, 17, -19, -19, 4, + 0, -30, -9, 19, -41, -23, 38, -51, -36, 57, -62, -50, + -74, 10, 48, -55, 0, 34, -36, -10, 21, -17, -21, 8, + 2, -32, -5, 21, -42, -19, 40, -53, -32, 59, -64, -46, + -71, 9, 53, -52, -1, 39, -33, -12, 26, -14, -22, 12, + 5, -33, -1, 24, -44, -14, 43, -54, -27, 62, -65, -41, + -69, 8, 57, -49, -2, 43, -31, -13, 30, -12, -24, 16, + 7, -34, 2, 26, -45, -10, 45, -56, -23, 64, -67, -37, + -66, 6, 61, -47, -4, 47, -28, -14, 34, -9, -25, 20, + 10, -36, 6, 29, -46, -6, 47, -57, -19, 67, -68, -33, + -64, 5, 65, -45, -5, 51, -26, -16, 38, -7, -26, 24, + 12, -37, 10, 31, -48, -2, 50, -58, -15, 69, -69, -29, + -61, 3, 69, -42, -7, 55, -23, -17, 42, -4, -28, 29, + 15, -39, 15, 34, -49, 1, 53, -60, -11, 72, -71, -25, + -59, 2, 73, -40, -8, 59, -21, -19, 46, -2, -29, 33, + 17, -40, 19, 36, -51, 5, 55, -61, -7, 74, -72, -21, + -57, 1, 77, -37, -9, 63, -18, -20, 50, 0, -30, 37, + 20, -41, 23, 39, -52, 9, 57, -63, -3, 77, -74, -17, + -54, 0, 81, -35, -11, 67, -16, -21, 54, 3, -32, 41, + 22, -43, 27, 41, -53, 13, 60, -64, 0, 79, -75, -13, + -52, -1, 85, -32, -12, 71, -14, -23, 58, 5, -33, 45, + 25, -44, 31, 43, -55, 17, 62, -65, 4, 81, -76, -9, + -49, -3, 90, -30, -13, 76, -11, -24, 63, 8, -35, 49, + 27, -46, 35, 46, -56, 22, 65, -67, 9, 84, -78, -4, + -47, -4, 94, -27, -15, 80, -9, -25, 67, 10, -36, 53, + 30, -47, 39, 48, -58, 26, 67, -68, 13, 87, -79, 0, + -44, -5, 98, -25, -16, 84, -6, -27, 71, 13, -37, 57, + 32, -48, 43, 51, -59, 30, 70, -70, 17, 89, -80, 3, + -42, -7, 102, -23, -18, 88, -4, -28, 75, 15, -39, 61, + 34, -50, 47, 53, -60, 34, 72, -71, 21, 91, -82, 7, + -39, -8, 106, -20, -19, 92, -1, -30, 79, 18, -40, 66, + 37, -51, 52, 56, -62, 38, 75, -72, 25, 94, -83, 11, + -37, -9, 110, -17, -20, 96, 1, -31, 83, 20, -42, 70, + 39, -53, 56, 58, -63, 42, 77, -74, 29, 96, -85, 15, + -34, -11, 114, -15, -22, 100, 4, -32, 87, 23, -43, 74, + 42, -54, 60, 61, -64, 46, 79, -75, 33, 99, -86, 19, + -110, 35, -13, -90, 24, -27, -72, 14, -40, -53, 3, -53, + -33, -7, -67, -15, -17, -81, 4, -28, -94, 23, -39, -108, + -107, 34, -9, -88, 23, -23, -69, 12, -36, -50, 2, -49, + -31, -8, -63, -12, -19, -77, 7, -29, -90, 26, -40, -104, + -105, 33, -5, -86, 22, -19, -67, 11, -32, -48, 0, -45, + -29, -10, -59, -10, -20, -73, 9, -31, -86, 28, -42, -100, + -102, 31, 0, -83, 20, -14, -64, 9, -28, -45, 0, -41, + -26, -11, -55, -7, -22, -68, 12, -32, -82, 31, -43, -95, + -100, 30, 3, -81, 19, -10, -62, 8, -24, -43, -2, -37, + -24, -12, -51, -5, -23, -64, 14, -34, -78, 33, -45, -91, + -98, 28, 7, -78, 17, -6, -59, 7, -20, -41, -3, -33, + -21, -14, -47, -2, -24, -60, 16, -35, -74, 36, -46, -87, + -95, 27, 11, -76, 16, -2, -57, 5, -16, -38, -4, -29, + -19, -15, -43, 0, -26, -56, 19, -36, -70, 38, -47, -83, + -92, 25, 15, -73, 14, 1, -54, 4, -11, -35, -6, -24, + -16, -17, -38, 3, -27, -52, 21, -38, -65, 41, -49, -79, + -90, 24, 19, -71, 13, 5, -52, 3, -7, -33, -7, -20, + -14, -18, -34, 5, -29, -48, 24, -39, -61, 43, -50, -75, + -88, 23, 23, -68, 12, 9, -49, 1, -3, -31, -8, -16, + -11, -19, -30, 7, -30, -44, 26, -41, -57, 46, -51, -71, + -85, 21, 27, -66, 10, 13, -47, 0, 0, -28, -10, -12, + -9, -21, -26, 10, -31, -40, 29, -42, -53, 48, -53, -67, + -83, 20, 31, -63, 9, 17, -45, -1, 4, -26, -11, -8, + -7, -22, -22, 12, -33, -36, 31, -43, -49, 50, -54, -63, + -80, 18, 36, -61, 8, 22, -42, -2, 8, -23, -13, -4, + -4, -24, -18, 15, -34, -31, 34, -45, -45, 53, -56, -58, + -78, 17, 40, -58, 6, 26, -40, -3, 12, -21, -14, 0, + -1, -25, -14, 17, -36, -27, 36, -46, -41, 55, -57, -54, + -75, 16, 44, -56, 5, 30, -37, -5, 16, -18, -15, 3, + 1, -26, -10, 20, -37, -23, 39, -47, -37, 58, -58, -50, + -73, 14, 48, -54, 4, 34, -35, -6, 20, -16, -17, 7, + 3, -28, -6, 22, -38, -19, 41, -49, -33, 60, -60, -46, + -70, 13, 52, -51, 2, 38, -32, -8, 25, -13, -18, 12, + 6, -29, -1, 25, -40, -15, 44, -50, -28, 63, -61, -42, + -68, 12, 56, -49, 1, 42, -30, -9, 29, -11, -20, 16, + 8, -30, 2, 27, -41, -11, 46, -52, -24, 65, -63, -38, + -66, 10, 60, -46, 0, 46, -27, -10, 33, -9, -21, 20, + 11, -32, 6, 30, -42, -7, 48, -53, -20, 68, -64, -34, + -63, 9, 64, -44, -1, 50, -25, -12, 37, -6, -22, 24, + 13, -33, 10, 32, -44, -3, 51, -54, -16, 70, -65, -30, + -60, 7, 69, -41, -3, 55, -22, -13, 41, -3, -24, 28, + 16, -35, 14, 35, -45, 1, 53, -56, -12, 73, -67, -25, + -58, 6, 73, -39, -4, 59, -20, -15, 45, -1, -25, 32, + 18, -36, 18, 37, -47, 5, 56, -57, -8, 75, -68, -21, + -56, 5, 77, -36, -5, 63, -17, -16, 49, 1, -26, 36, + 21, -37, 22, 39, -48, 9, 58, -59, -4, 78, -70, -17, + -53, 3, 81, -34, -7, 67, -15, -17, 53, 4, -28, 40, + 23, -39, 26, 42, -49, 13, 61, -60, 0, 80, -71, -13, + -51, 2, 85, -31, -8, 71, -13, -19, 57, 6, -29, 44, + 25, -40, 30, 44, -51, 17, 63, -61, 3, 82, -72, -9, + -48, 0, 89, -29, -9, 75, -10, -20, 62, 9, -31, 49, + 28, -42, 35, 47, -52, 21, 66, -63, 8, 85, -74, -5, + -46, 0, 93, -26, -11, 79, -8, -21, 66, 11, -32, 53, + 31, -43, 39, 49, -54, 25, 68, -64, 12, 87, -75, -1, + -43, -1, 97, -24, -12, 83, -5, -23, 70, 14, -33, 57, + 33, -44, 43, 52, -55, 29, 70, -66, 16, 90, -76, 2, + -41, -3, 101, -22, -14, 87, -3, -24, 74, 16, -35, 61, + 35, -46, 47, 54, -56, 33, 73, -67, 20, 92, -78, 6, + -38, -4, 106, -19, -15, 92, 0, -26, 78, 19, -36, 65, + 38, -47, 51, 57, -58, 38, 76, -68, 24, 95, -79, 11, + -36, -5, 110, -17, -16, 96, 2, -27, 82, 21, -38, 69, + 40, -49, 55, 59, -59, 42, 78, -70, 28, 97, -81, 15, + -34, -7, 114, -14, -18, 100, 5, -28, 86, 23, -39, 73, + 43, -50, 59, 62, -60, 46, 80, -71, 32, 100, -82, 19, + -109, 39, -14, -89, 28, -27, -71, 18, -41, -52, 7, -54, + -33, -3, -68, -14, -13, -81, 5, -24, -95, 24, -35, -109, + -106, 38, -10, -87, 27, -23, -68, 16, -37, -50, 6, -50, + -30, -4, -64, -11, -15, -77, 7, -25, -91, 27, -36, -105, + -104, 37, -6, -85, 26, -19, -66, 15, -33, -47, 4, -46, + -28, -6, -60, -9, -16, -73, 10, -27, -87, 29, -38, -101, + -101, 35, -1, -82, 24, -15, -63, 13, -28, -44, 3, -42, + -25, -7, -55, -6, -18, -69, 13, -28, -82, 32, -39, -96, + -99, 34, 2, -80, 23, -11, -61, 12, -24, -42, 1, -38, + -23, -8, -51, -4, -19, -65, 15, -30, -78, 34, -41, -92, + -97, 32, 6, -77, 21, -7, -58, 11, -20, -40, 0, -34, + -20, -10, -47, -1, -20, -61, 17, -31, -74, 37, -42, -88, + -94, 31, 10, -75, 20, -3, -56, 9, -16, -37, 0, -30, + -18, -11, -43, 1, -22, -57, 20, -32, -70, 39, -43, -84, + -92, 29, 14, -72, 18, 1, -53, 8, -12, -35, -2, -25, + -15, -13, -39, 4, -23, -52, 22, -34, -66, 42, -45, -80, + -89, 28, 18, -70, 17, 5, -51, 7, -8, -32, -3, -21, + -13, -14, -35, 6, -25, -48, 25, -35, -62, 44, -46, -76, + -87, 27, 22, -67, 16, 9, -49, 5, -4, -30, -4, -17, + -10, -15, -31, 8, -26, -44, 27, -37, -58, 47, -47, -72, + -84, 25, 26, -65, 14, 13, -46, 4, 0, -27, -6, -13, + -8, -17, -27, 11, -27, -40, 30, -38, -54, 49, -49, -68, + -82, 24, 30, -63, 13, 17, -44, 2, 3, -25, -7, -9, + -6, -18, -23, 13, -29, -36, 32, -39, -50, 51, -50, -64, + -79, 22, 35, -60, 12, 21, -41, 1, 8, -22, -9, -5, + -3, -20, -18, 16, -30, -32, 35, -41, -45, 54, -52, -59, + -77, 21, 39, -57, 10, 25, -39, 0, 12, -20, -10, -1, + -1, -21, -14, 18, -32, -28, 37, -42, -41, 56, -53, -55, + -74, 20, 43, -55, 9, 29, -36, -1, 16, -18, -11, 2, + 2, -22, -10, 21, -33, -24, 39, -43, -37, 59, -54, -51, + -72, 18, 47, -53, 8, 33, -34, -2, 20, -15, -13, 6, + 4, -24, -6, 23, -34, -20, 42, -45, -33, 61, -56, -47, + -69, 17, 51, -50, 6, 38, -31, -4, 24, -12, -14, 11, + 7, -25, -2, 26, -36, -15, 44, -46, -29, 64, -57, -43, + -67, 16, 55, -48, 5, 42, -29, -5, 28, -10, -16, 15, + 9, -26, 1, 28, -37, -11, 47, -48, -25, 66, -59, -39, + -65, 14, 59, -45, 3, 46, -26, -6, 32, -8, -17, 19, + 12, -28, 5, 30, -38, -7, 49, -49, -21, 69, -60, -35, + -62, 13, 63, -43, 2, 50, -24, -8, 36, -5, -18, 23, + 14, -29, 9, 33, -40, -3, 52, -50, -17, 71, -61, -31, + -60, 11, 68, -40, 0, 54, -21, -9, 41, -3, -20, 27, + 17, -31, 14, 36, -41, 0, 54, -52, -12, 74, -63, -26, + -57, 10, 72, -38, 0, 58, -19, -11, 45, 0, -21, 31, + 19, -32, 18, 38, -43, 4, 57, -53, -8, 76, -64, -22, + -55, 9, 76, -35, -1, 62, -17, -12, 49, 2, -22, 35, + 22, -33, 22, 40, -44, 8, 59, -55, -4, 79, -66, -18, + -52, 7, 80, -33, -3, 66, -14, -13, 53, 5, -24, 39, + 24, -35, 26, 43, -45, 12, 62, -56, 0, 81, -67, -14, + -50, 6, 84, -31, -4, 70, -12, -15, 57, 7, -25, 43, + 26, -36, 30, 45, -47, 16, 64, -57, 3, 83, -68, -10, + -47, 4, 88, -28, -5, 75, -9, -16, 61, 10, -27, 48, + 29, -38, 34, 48, -48, 21, 67, -59, 7, 86, -70, -6, + -45, 3, 92, -25, -7, 79, -7, -17, 65, 12, -28, 52, + 31, -39, 38, 50, -50, 25, 69, -60, 11, 88, -71, -2, + -42, 2, 96, -23, -8, 83, -4, -19, 69, 14, -29, 56, + 34, -40, 42, 53, -51, 29, 71, -62, 15, 91, -72, 1, + -40, 0, 100, -21, -10, 87, -2, -20, 73, 17, -31, 60, + 36, -42, 46, 55, -52, 33, 74, -63, 19, 93, -74, 5, + -37, 0, 105, -18, -11, 91, 1, -22, 78, 20, -32, 64, + 39, -43, 51, 58, -54, 37, 76, -64, 24, 96, -75, 10, + -35, -1, 109, -16, -12, 95, 3, -23, 82, 22, -34, 68, + 41, -45, 55, 60, -55, 41, 79, -66, 28, 98, -77, 14, + -33, -3, 113, -13, -14, 99, 6, -24, 86, 24, -35, 72, + 44, -46, 59, 62, -56, 45, 81, -67, 32, 101, -78, 18, + -108, 44, -14, -88, 33, -28, -70, 22, -41, -51, 12, -55, + -32, 1, -69, -13, -9, -82, 6, -20, -95, 25, -30, -109, + -105, 42, -10, -86, 31, -24, -67, 21, -37, -48, 10, -51, + -29, 0, -65, -10, -10, -78, 8, -21, -91, 28, -32, -105, + -103, 41, -6, -84, 30, -20, -65, 19, -33, -46, 9, -47, + -27, -1, -61, -8, -12, -74, 11, -22, -87, 30, -33, -101, + -100, 39, -2, -81, 29, -16, -62, 18, -29, -43, 7, -42, + -24, -3, -56, -5, -13, -70, 14, -24, -83, 33, -35, -97, + -98, 38, 1, -79, 27, -12, -60, 17, -25, -41, 6, -38, + -22, -4, -52, -3, -15, -66, 16, -25, -79, 35, -36, -93, + -96, 37, 5, -76, 26, -8, -57, 15, -21, -39, 5, -34, + -19, -5, -48, 0, -16, -62, 18, -26, -75, 38, -37, -89, + -93, 35, 9, -74, 25, -4, -55, 14, -17, -36, 3, -30, + -17, -7, -44, 2, -17, -58, 21, -28, -71, 40, -39, -85, + -90, 34, 14, -71, 23, 0, -52, 12, -12, -34, 2, -26, + -14, -8, -40, 5, -19, -53, 23, -29, -66, 43, -40, -80, + -88, 33, 18, -69, 22, 4, -50, 11, -8, -31, 0, -22, + -12, -10, -36, 7, -20, -49, 26, -31, -62, 45, -42, -76, + -86, 31, 22, -66, 20, 8, -48, 10, -4, -29, 0, -18, + -9, -11, -32, 9, -21, -45, 28, -32, -58, 48, -43, -72, + -83, 30, 26, -64, 19, 12, -45, 8, 0, -26, -1, -14, + -7, -12, -28, 12, -23, -41, 31, -33, -54, 50, -44, -68, + -81, 29, 30, -62, 18, 16, -43, 7, 3, -24, -3, -10, + -5, -14, -24, 14, -24, -37, 33, -35, -50, 52, -46, -64, + -78, 27, 34, -59, 16, 20, -40, 5, 7, -21, -4, -5, + -2, -15, -19, 17, -26, -33, 36, -36, -46, 55, -47, -60, + -76, 26, 38, -56, 15, 24, -38, 4, 11, -19, -5, -1, + 0, -16, -15, 19, -27, -29, 38, -38, -42, 57, -49, -56, + -73, 24, 42, -54, 13, 28, -35, 3, 15, -16, -7, 2, + 3, -18, -11, 22, -28, -25, 40, -39, -38, 60, -50, -52, + -71, 23, 46, -52, 12, 32, -33, 1, 19, -14, -8, 6, + 5, -19, -7, 24, -30, -21, 43, -40, -34, 62, -51, -48, + -68, 21, 51, -49, 10, 37, -30, 0, 24, -11, -10, 10, + 8, -21, -3, 27, -31, -16, 46, -42, -29, 65, -53, -43, + -66, 20, 55, -47, 9, 41, -28, 0, 28, -9, -11, 14, + 10, -22, 0, 29, -33, -12, 48, -43, -25, 67, -54, -39, + -64, 19, 59, -44, 8, 45, -25, -2, 32, -7, -12, 18, + 13, -23, 4, 32, -34, -8, 50, -45, -21, 70, -55, -35, + -61, 17, 63, -42, 6, 49, -23, -3, 36, -4, -14, 22, + 15, -25, 8, 34, -35, -4, 53, -46, -17, 72, -57, -31, + -58, 16, 67, -39, 5, 53, -20, -5, 40, -2, -15, 27, + 18, -26, 13, 37, -37, 0, 55, -47, -13, 75, -58, -27, + -56, 15, 71, -37, 4, 57, -18, -6, 44, 1, -17, 31, + 20, -28, 17, 39, -38, 3, 58, -49, -9, 77, -60, -23, + -54, 13, 75, -34, 2, 61, -16, -7, 48, 3, -18, 35, + 23, -29, 21, 41, -40, 7, 60, -50, -5, 80, -61, -19, + -51, 12, 79, -32, 1, 65, -13, -9, 52, 6, -19, 39, + 25, -30, 25, 44, -41, 11, 63, -51, -1, 82, -62, -15, + -49, 10, 83, -30, 0, 69, -11, -10, 56, 8, -21, 43, + 27, -32, 29, 46, -42, 15, 65, -53, 2, 84, -64, -11, + -46, 9, 88, -27, -1, 74, -8, -12, 61, 11, -22, 47, + 30, -33, 33, 49, -44, 20, 68, -54, 7, 87, -65, -6, + -44, 8, 92, -24, -2, 78, -6, -13, 65, 13, -24, 51, + 32, -34, 37, 51, -45, 24, 70, -56, 11, 89, -67, -2, + -41, 6, 96, -22, -4, 82, -3, -14, 69, 15, -25, 55, + 35, -36, 41, 54, -46, 28, 72, -57, 15, 92, -68, 1, + -39, 5, 100, -20, -5, 86, -1, -16, 73, 18, -26, 59, + 37, -37, 45, 56, -48, 32, 75, -58, 19, 94, -69, 5, + -36, 3, 104, -17, -7, 90, 2, -17, 77, 21, -28, 64, + 40, -39, 50, 59, -49, 36, 78, -60, 23, 97, -71, 9, + -34, 2, 108, -15, -8, 94, 4, -19, 81, 23, -29, 68, + 42, -40, 54, 61, -51, 40, 80, -61, 27, 99, -72, 13, + -32, 1, 112, -12, -9, 98, 7, -20, 85, 25, -30, 72, + 45, -41, 58, 64, -52, 44, 82, -63, 31, 102, -74, 17, + -107, 48, -15, -88, 37, -29, -69, 26, -42, -50, 16, -56, + -31, 5, -69, -12, -5, -83, 7, -16, -96, 26, -26, -110, + -105, 46, -11, -85, 35, -25, -66, 25, -38, -48, 14, -52, + -28, 3, -65, -9, -6, -79, 9, -17, -92, 29, -28, -106, + -102, 45, -7, -83, 34, -21, -64, 23, -34, -45, 13, -48, + -26, 2, -61, -7, -8, -75, 12, -18, -88, 31, -29, -102, + -99, 43, -2, -80, 33, -16, -61, 22, -30, -42, 11, -43, + -23, 0, -57, -4, -9, -70, 14, -20, -84, 34, -31, -97, + -97, 42, 1, -78, 31, -12, -59, 21, -26, -40, 10, -39, + -21, 0, -53, -2, -11, -66, 17, -21, -80, 36, -32, -93, + -95, 41, 5, -75, 30, -8, -56, 19, -22, -38, 9, -35, + -18, -1, -49, 0, -12, -62, 19, -22, -76, 39, -33, -89, + -92, 39, 9, -73, 29, -4, -54, 18, -18, -35, 7, -31, + -16, -3, -45, 3, -13, -58, 22, -24, -72, 41, -35, -85, + -90, 38, 13, -70, 27, 0, -51, 16, -13, -33, 6, -27, + -13, -4, -40, 6, -15, -54, 24, -25, -67, 44, -36, -81, + -87, 37, 17, -68, 26, 3, -49, 15, -9, -30, 4, -23, + -11, -6, -36, 8, -16, -50, 27, -27, -63, 46, -38, -77, + -85, 35, 21, -65, 24, 7, -47, 14, -5, -28, 3, -19, + -8, -7, -32, 10, -17, -46, 29, -28, -59, 48, -39, -73, + -82, 34, 25, -63, 23, 11, -44, 12, -1, -25, 2, -15, + -6, -8, -28, 13, -19, -42, 31, -29, -55, 51, -40, -69, + -80, 33, 29, -61, 22, 15, -42, 11, 2, -23, 0, -11, + -4, -10, -24, 15, -20, -38, 34, -31, -51, 53, -42, -65, + -77, 31, 34, -58, 20, 20, -39, 9, 6, -20, 0, -6, + -1, -11, -20, 18, -22, -33, 37, -32, -47, 56, -43, -60, + -75, 30, 38, -56, 19, 24, -37, 8, 10, -18, -1, -2, + 1, -12, -16, 20, -23, -29, 39, -34, -43, 58, -45, -56, + -73, 28, 42, -53, 17, 28, -34, 7, 14, -16, -3, 1, + 4, -14, -12, 23, -24, -25, 41, -35, -39, 61, -46, -52, + -70, 27, 46, -51, 16, 32, -32, 5, 18, -13, -4, 5, + 6, -15, -8, 25, -26, -21, 44, -36, -35, 63, -47, -48, + -67, 25, 50, -48, 14, 36, -29, 4, 23, -11, -6, 9, + 9, -17, -3, 28, -27, -17, 46, -38, -30, 66, -49, -44, + -65, 24, 54, -46, 13, 40, -27, 3, 27, -8, -7, 13, + 11, -18, 0, 30, -29, -13, 49, -39, -26, 68, -50, -40, + -63, 23, 58, -43, 12, 44, -25, 1, 31, -6, -8, 17, + 14, -19, 4, 32, -30, -9, 51, -41, -22, 71, -51, -36, + -60, 21, 62, -41, 10, 48, -22, 0, 35, -3, -10, 21, + 16, -21, 8, 35, -31, -5, 54, -42, -18, 73, -53, -32, + -58, 20, 67, -38, 9, 53, -19, -1, 39, -1, -11, 26, + 19, -22, 12, 38, -33, 0, 56, -43, -14, 76, -54, -27, + -55, 19, 71, -36, 8, 57, -17, -2, 43, 2, -13, 30, + 21, -24, 16, 40, -34, 3, 59, -45, -10, 78, -56, -23, + -53, 17, 75, -33, 6, 61, -15, -3, 47, 4, -14, 34, + 24, -25, 20, 42, -36, 7, 61, -46, -6, 80, -57, -19, + -50, 16, 79, -31, 5, 65, -12, -5, 51, 7, -15, 38, + 26, -26, 24, 45, -37, 11, 63, -47, -2, 83, -58, -15, + -48, 14, 83, -29, 4, 69, -10, -6, 55, 9, -17, 42, + 28, -28, 28, 47, -38, 15, 66, -49, 1, 85, -60, -11, + -45, 13, 87, -26, 2, 73, -7, -8, 60, 12, -18, 46, + 31, -29, 33, 50, -40, 19, 69, -50, 6, 88, -61, -7, + -43, 12, 91, -24, 1, 77, -5, -9, 64, 14, -20, 50, + 33, -30, 37, 52, -41, 23, 71, -52, 10, 90, -63, -3, + -41, 10, 95, -21, 0, 81, -2, -10, 68, 16, -21, 54, + 36, -32, 41, 55, -42, 27, 73, -53, 14, 93, -64, 0, + -38, 9, 99, -19, -1, 85, 0, -12, 72, 19, -22, 58, + 38, -33, 45, 57, -44, 31, 76, -54, 18, 95, -65, 4, + -35, 7, 104, -16, -3, 90, 3, -13, 76, 21, -24, 63, + 41, -35, 49, 60, -45, 36, 78, -56, 22, 98, -67, 9, + -33, 6, 108, -14, -4, 94, 5, -15, 80, 24, -25, 67, + 43, -36, 53, 62, -47, 40, 81, -57, 26, 100, -68, 13, + -31, 5, 112, -11, -5, 98, 7, -16, 84, 26, -26, 71, + 46, -37, 57, 64, -48, 44, 83, -59, 30, 103, -70, 17, + -106, 52, -16, -87, 41, -29, -68, 30, -43, -49, 20, -56, + -30, 9, -70, -11, -1, -83, 8, -12, -97, 27, -22, -111, + -104, 50, -12, -84, 39, -25, -65, 29, -39, -47, 18, -52, + -27, 7, -66, -9, -2, -79, 10, -13, -93, 30, -24, -107, + -101, 49, -8, -82, 38, -21, -63, 27, -35, -44, 17, -48, + -25, 6, -62, -6, -4, -75, 13, -14, -89, 32, -25, -103, + -99, 47, -3, -79, 37, -17, -60, 26, -30, -42, 15, -44, + -22, 4, -57, -3, -5, -71, 15, -16, -84, 35, -27, -98, + -96, 46, 0, -77, 35, -13, -58, 25, -26, -39, 14, -40, + -20, 3, -53, -1, -7, -67, 18, -17, -80, 37, -28, -94, + -94, 45, 4, -74, 34, -9, -56, 23, -22, -37, 13, -36, + -17, 2, -49, 1, -8, -63, 20, -18, -76, 40, -29, -90, + -91, 43, 8, -72, 33, -5, -53, 22, -18, -34, 11, -32, + -15, 0, -45, 4, -9, -59, 23, -20, -72, 42, -31, -86, + -89, 42, 12, -69, 31, 0, -51, 20, -14, -32, 10, -27, + -12, 0, -41, 6, -11, -54, 25, -21, -68, 45, -32, -82, + -86, 41, 16, -67, 30, 3, -48, 19, -10, -29, 8, -23, + -10, -2, -37, 9, -12, -50, 28, -23, -64, 47, -34, -78, + -84, 39, 20, -65, 28, 7, -46, 18, -6, -27, 7, -19, + -8, -3, -33, 11, -13, -46, 30, -24, -60, 49, -35, -74, + -81, 38, 24, -62, 27, 11, -43, 16, -2, -25, 6, -15, + -5, -4, -29, 14, -15, -42, 32, -25, -56, 52, -36, -70, + -79, 37, 28, -60, 26, 15, -41, 15, 1, -22, 4, -11, + -3, -6, -25, 16, -16, -38, 35, -27, -52, 54, -38, -66, + -76, 35, 33, -57, 24, 19, -38, 13, 6, -19, 3, -7, + 0, -7, -20, 19, -18, -34, 37, -28, -47, 57, -39, -61, + -74, 34, 37, -55, 23, 23, -36, 12, 10, -17, 2, -3, + 2, -8, -16, 21, -19, -30, 40, -30, -43, 59, -41, -57, + -72, 32, 41, -52, 21, 27, -33, 11, 14, -15, 0, 0, + 5, -10, -12, 23, -20, -26, 42, -31, -39, 62, -42, -53, + -69, 31, 45, -50, 20, 31, -31, 9, 18, -12, 0, 4, + 7, -11, -8, 26, -22, -22, 45, -32, -35, 64, -43, -49, + -67, 29, 49, -47, 18, 36, -28, 8, 22, -10, -2, 9, + 10, -13, -4, 29, -23, -17, 47, -34, -31, 67, -45, -45, + -64, 28, 53, -45, 17, 40, -26, 7, 26, -7, -3, 13, + 12, -14, 0, 31, -25, -13, 50, -35, -27, 69, -46, -41, + -62, 27, 57, -42, 16, 44, -24, 5, 30, -5, -4, 17, + 15, -15, 3, 33, -26, -9, 52, -37, -23, 72, -47, -37, + -59, 25, 61, -40, 14, 48, -21, 4, 34, -2, -6, 21, + 17, -17, 7, 36, -27, -5, 55, -38, -19, 74, -49, -33, + -57, 24, 66, -37, 13, 52, -19, 2, 39, 0, -7, 25, + 20, -18, 12, 38, -29, -1, 57, -39, -14, 77, -50, -28, + -54, 23, 70, -35, 12, 56, -16, 1, 43, 3, -9, 29, + 22, -20, 16, 41, -30, 2, 60, -41, -10, 79, -52, -24, + -52, 21, 74, -33, 10, 60, -14, 0, 47, 5, -10, 33, + 24, -21, 20, 43, -32, 6, 62, -42, -6, 81, -53, -20, + -49, 20, 78, -30, 9, 64, -11, -1, 51, 7, -11, 37, + 27, -22, 24, 46, -33, 10, 64, -43, -2, 84, -54, -16, + -47, 18, 82, -28, 8, 68, -9, -2, 55, 10, -13, 41, + 29, -24, 28, 48, -34, 14, 67, -45, 1, 86, -56, -12, + -44, 17, 86, -25, 6, 73, -6, -4, 59, 13, -14, 46, + 32, -25, 32, 51, -36, 19, 69, -46, 5, 89, -57, -8, + -42, 16, 90, -23, 5, 77, -4, -5, 63, 15, -16, 50, + 34, -26, 36, 53, -37, 23, 72, -48, 9, 91, -59, -4, + -40, 14, 94, -20, 3, 81, -1, -6, 67, 17, -17, 54, + 37, -28, 40, 55, -38, 27, 74, -49, 13, 94, -60, 0, + -37, 13, 98, -18, 2, 85, 1, -8, 71, 20, -18, 58, + 39, -29, 44, 58, -40, 31, 77, -50, 17, 96, -61, 3, + -35, 11, 103, -15, 0, 89, 4, -9, 76, 22, -20, 62, + 42, -31, 49, 61, -41, 35, 79, -52, 22, 99, -63, 8, + -32, 10, 107, -13, 0, 93, 6, -11, 80, 25, -21, 66, + 44, -32, 53, 63, -43, 39, 82, -53, 26, 101, -64, 12, + -30, 9, 111, -10, -1, 97, 8, -12, 84, 27, -22, 70, + 47, -33, 57, 65, -44, 43, 84, -55, 30, 103, -66, 16, + -105, 56, -16, -86, 45, -30, -67, 34, -43, -48, 24, -57, + -29, 13, -71, -10, 2, -84, 9, -8, -97, 28, -18, -111, + -103, 54, -12, -83, 43, -26, -65, 33, -39, -46, 22, -53, + -26, 11, -67, -8, 1, -80, 11, -9, -93, 31, -20, -107, + -100, 53, -8, -81, 42, -22, -62, 31, -35, -43, 21, -49, + -24, 10, -63, -5, 0, -76, 14, -10, -89, 33, -21, -103, + -98, 51, -4, -78, 41, -18, -59, 30, -31, -41, 19, -44, + -21, 8, -58, -3, -1, -72, 16, -12, -85, 36, -23, -99, + -95, 50, 0, -76, 39, -14, -57, 29, -27, -38, 18, -40, + -19, 7, -54, 0, -3, -68, 19, -13, -81, 38, -24, -95, + -93, 49, 3, -73, 38, -10, -55, 27, -23, -36, 17, -36, + -17, 6, -50, 2, -4, -64, 21, -14, -77, 40, -25, -91, + -90, 47, 7, -71, 37, -6, -52, 26, -19, -33, 15, -32, + -14, 4, -46, 5, -5, -60, 23, -16, -73, 43, -27, -87, + -88, 46, 12, -68, 35, -1, -50, 24, -14, -31, 14, -28, + -11, 3, -42, 7, -7, -55, 26, -17, -68, 46, -28, -82, + -85, 45, 16, -66, 34, 2, -47, 23, -10, -28, 12, -24, + -9, 1, -38, 10, -8, -51, 29, -19, -64, 48, -30, -78, + -83, 43, 20, -64, 32, 6, -45, 22, -6, -26, 11, -20, + -7, 0, -34, 12, -9, -47, 31, -20, -60, 50, -31, -74, + -81, 42, 24, -61, 31, 10, -42, 20, -2, -24, 10, -16, + -4, 0, -30, 15, -11, -43, 33, -21, -56, 53, -32, -70, + -78, 41, 28, -59, 30, 14, -40, 19, 1, -21, 8, -12, + -2, -2, -26, 17, -12, -39, 36, -23, -52, 55, -34, -66, + -75, 39, 32, -56, 28, 18, -37, 17, 5, -19, 7, -7, + 1, -3, -21, 20, -14, -35, 38, -24, -48, 58, -35, -62, + -73, 38, 36, -54, 27, 22, -35, 16, 9, -16, 6, -3, + 3, -4, -17, 22, -15, -31, 41, -26, -44, 60, -37, -58, + -71, 36, 40, -51, 25, 26, -33, 15, 13, -14, 4, 0, + 6, -6, -13, 24, -16, -27, 43, -27, -40, 63, -38, -54, + -68, 35, 44, -49, 24, 30, -30, 13, 17, -11, 3, 4, + 8, -7, -9, 27, -18, -23, 46, -28, -36, 65, -39, -50, + -66, 33, 49, -46, 22, 35, -27, 12, 22, -9, 1, 8, + 11, -9, -5, 29, -19, -18, 48, -30, -31, 68, -41, -45, + -63, 32, 53, -44, 21, 39, -25, 11, 26, -6, 0, 12, + 13, -10, -1, 32, -21, -14, 51, -31, -27, 70, -42, -41, + -61, 31, 57, -41, 20, 43, -23, 9, 30, -4, 0, 16, + 15, -11, 2, 34, -22, -10, 53, -33, -23, 72, -43, -37, + -58, 29, 61, -39, 18, 47, -20, 8, 34, -2, -2, 20, + 18, -13, 6, 37, -23, -6, 55, -34, -19, 75, -45, -33, + -56, 28, 65, -36, 17, 51, -18, 6, 38, 1, -3, 25, + 21, -14, 11, 39, -25, -2, 58, -35, -15, 77, -46, -29, + -53, 27, 69, -34, 16, 55, -15, 5, 42, 4, -5, 29, + 23, -16, 15, 42, -26, 1, 61, -37, -11, 80, -48, -25, + -51, 25, 73, -32, 14, 59, -13, 4, 46, 6, -6, 33, + 25, -17, 19, 44, -28, 5, 63, -38, -7, 82, -49, -21, + -49, 24, 77, -29, 13, 63, -10, 2, 50, 8, -7, 37, + 28, -18, 23, 47, -29, 9, 65, -39, -3, 85, -50, -17, + -46, 22, 81, -27, 12, 67, -8, 1, 54, 11, -9, 41, + 30, -20, 27, 49, -30, 13, 68, -41, 0, 87, -52, -13, + -43, 21, 86, -24, 10, 72, -5, 0, 59, 13, -10, 45, + 33, -21, 31, 52, -32, 18, 70, -42, 5, 90, -53, -8, + -41, 20, 90, -22, 9, 76, -3, -1, 63, 16, -12, 49, + 35, -22, 35, 54, -33, 22, 73, -44, 9, 92, -55, -4, + -39, 18, 94, -19, 7, 80, -1, -2, 67, 18, -13, 53, + 38, -24, 39, 56, -34, 26, 75, -45, 13, 95, -56, 0, + -36, 17, 98, -17, 6, 84, 2, -4, 71, 21, -14, 57, + 40, -25, 43, 59, -36, 30, 78, -46, 17, 97, -57, 3, + -34, 15, 102, -14, 4, 88, 5, -5, 75, 23, -16, 62, + 43, -27, 48, 61, -37, 34, 80, -48, 21, 100, -59, 7, + -31, 14, 106, -12, 3, 92, 7, -7, 79, 26, -17, 66, + 45, -28, 52, 64, -39, 38, 83, -49, 25, 102, -60, 11, + -29, 13, 110, -9, 2, 96, 9, -8, 83, 28, -18, 70, + 47, -29, 56, 66, -40, 42, 85, -51, 29, 104, -62, 15, + -104, 60, -17, -85, 49, -31, -66, 39, -44, -47, 28, -58, + -28, 17, -71, -9, 7, -85, 10, -3, -98, 29, -14, -112, + -102, 59, -13, -82, 48, -27, -64, 37, -40, -45, 27, -54, + -25, 16, -67, -7, 5, -81, 12, -4, -94, 32, -15, -108, + -99, 58, -9, -80, 47, -23, -61, 36, -36, -42, 25, -50, + -23, 14, -63, -4, 4, -77, 15, -6, -90, 34, -17, -104, + -97, 56, -4, -77, 45, -18, -58, 34, -32, -40, 24, -45, + -20, 13, -59, -1, 2, -72, 17, -7, -86, 37, -18, -99, + -94, 55, 0, -75, 44, -14, -56, 33, -28, -37, 22, -41, + -18, 12, -55, 1, 1, -68, 20, -9, -82, 39, -20, -95, + -92, 53, 3, -72, 42, -10, -54, 32, -24, -35, 21, -37, + -15, 10, -51, 3, 0, -64, 22, -10, -78, 41, -21, -91, + -89, 52, 7, -70, 41, -6, -51, 30, -20, -32, 20, -33, + -13, 9, -47, 6, -1, -60, 24, -11, -74, 44, -22, -87, + -87, 50, 11, -67, 39, -2, -49, 29, -15, -30, 18, -29, + -10, 7, -42, 8, -2, -56, 27, -13, -69, 47, -24, -83, + -84, 49, 15, -65, 38, 1, -46, 28, -11, -27, 17, -25, + -8, 6, -38, 11, -4, -52, 30, -14, -65, 49, -25, -79, + -82, 48, 19, -63, 37, 5, -44, 26, -7, -25, 16, -21, + -6, 5, -34, 13, -5, -48, 32, -16, -61, 51, -26, -75, + -80, 46, 23, -60, 35, 9, -41, 25, -3, -23, 14, -17, + -3, 3, -30, 16, -6, -44, 34, -17, -57, 54, -28, -71, + -77, 45, 27, -58, 34, 13, -39, 23, 0, -20, 13, -13, + -1, 2, -26, 18, -8, -40, 37, -18, -53, 56, -29, -67, + -74, 43, 32, -55, 33, 18, -36, 22, 4, -18, 11, -8, + 2, 0, -22, 21, -9, -35, 39, -20, -49, 59, -31, -62, + -72, 42, 36, -53, 31, 22, -34, 21, 8, -15, 10, -4, + 4, 0, -18, 23, -11, -31, 42, -21, -45, 61, -32, -58, + -70, 41, 40, -50, 30, 26, -32, 19, 12, -13, 9, 0, + 7, -1, -14, 25, -12, -27, 44, -22, -41, 64, -33, -54, + -67, 39, 44, -48, 29, 30, -29, 18, 16, -10, 7, 3, + 9, -3, -10, 28, -13, -23, 47, -24, -37, 66, -35, -50, + -65, 38, 48, -45, 27, 34, -26, 16, 21, -8, 6, 7, + 12, -4, -5, 31, -15, -19, 49, -25, -32, 69, -36, -46, + -62, 37, 52, -43, 26, 38, -24, 15, 25, -5, 4, 11, + 14, -5, -1, 33, -16, -15, 52, -27, -28, 71, -38, -42, + -60, 35, 56, -40, 24, 42, -22, 14, 29, -3, 3, 15, + 17, -7, 2, 35, -17, -11, 54, -28, -24, 73, -39, -38, + -57, 34, 60, -38, 23, 46, -19, 12, 33, 0, 2, 19, + 19, -8, 6, 38, -19, -7, 56, -29, -20, 76, -40, -34, + -55, 32, 65, -35, 21, 51, -17, 11, 37, 2, 0, 24, + 22, -10, 10, 40, -20, -2, 59, -31, -16, 79, -42, -29, + -52, 31, 69, -33, 20, 55, -14, 9, 41, 5, 0, 28, + 24, -11, 14, 43, -22, 1, 62, -32, -12, 81, -43, -25, + -50, 30, 73, -31, 19, 59, -12, 8, 45, 7, -1, 32, + 26, -12, 18, 45, -23, 5, 64, -34, -8, 83, -45, -21, + -48, 28, 77, -28, 17, 63, -9, 7, 49, 9, -3, 36, + 29, -14, 22, 48, -24, 9, 66, -35, -4, 86, -46, -17, + -45, 27, 81, -26, 16, 67, -7, 5, 53, 12, -4, 40, + 31, -15, 26, 50, -26, 13, 69, -36, 0, 88, -47, -13, + -42, 25, 85, -23, 15, 71, -4, 4, 58, 14, -6, 44, + 34, -17, 31, 53, -27, 17, 71, -38, 4, 91, -49, -9, + -40, 24, 89, -21, 13, 75, -2, 3, 62, 17, -7, 48, + 36, -18, 35, 55, -29, 21, 74, -39, 8, 93, -50, -5, + -38, 23, 93, -18, 12, 79, 0, 1, 66, 19, -8, 52, + 39, -19, 39, 57, -30, 25, 76, -41, 12, 96, -51, -1, + -35, 21, 97, -16, 10, 83, 3, 0, 70, 22, -10, 56, + 41, -21, 43, 60, -31, 29, 79, -42, 16, 98, -53, 2, + -33, 20, 102, -13, 9, 88, 6, -1, 74, 24, -11, 61, + 44, -22, 47, 62, -33, 34, 81, -43, 20, 101, -54, 7, + -30, 19, 106, -11, 8, 92, 8, -2, 78, 27, -13, 65, + 46, -24, 51, 65, -34, 38, 84, -45, 24, 103, -56, 11, + -28, 17, 110, -8, 6, 96, 10, -3, 82, 29, -14, 69, + 48, -25, 55, 67, -35, 42, 86, -46, 28, 105, -57, 15, + -103, 64, -18, -84, 53, -31, -65, 43, -45, -46, 32, -58, + -27, 21, -72, -8, 11, -85, 11, 0, -99, 30, -10, -113, + -101, 63, -14, -81, 52, -27, -63, 41, -41, -44, 31, -54, + -24, 20, -68, -6, 9, -81, 13, 0, -95, 32, -11, -109, + -98, 62, -10, -79, 51, -23, -60, 40, -37, -41, 29, -50, + -22, 18, -64, -3, 8, -77, 16, -2, -91, 35, -13, -105, + -96, 60, -5, -76, 49, -19, -58, 38, -32, -39, 28, -46, + -19, 17, -60, -1, 6, -73, 18, -3, -86, 38, -14, -100, + -93, 59, -1, -74, 48, -15, -55, 37, -28, -36, 26, -42, + -17, 16, -56, 2, 5, -69, 21, -5, -82, 40, -16, -96, + -91, 57, 2, -72, 46, -11, -53, 36, -24, -34, 25, -38, + -15, 14, -52, 4, 4, -65, 23, -6, -78, 42, -17, -92, + -88, 56, 6, -69, 45, -7, -50, 34, -20, -32, 24, -34, + -12, 13, -48, 7, 2, -61, 25, -7, -74, 45, -18, -88, + -86, 54, 10, -66, 43, -2, -48, 33, -16, -29, 22, -29, + -9, 11, -43, 9, 1, -56, 28, -9, -70, 47, -20, -84, + -83, 53, 14, -64, 42, 1, -45, 32, -12, -26, 21, -25, + -7, 10, -39, 12, 0, -52, 30, -10, -66, 50, -21, -80, + -81, 52, 18, -62, 41, 5, -43, 30, -8, -24, 20, -21, + -5, 9, -35, 14, -1, -48, 33, -12, -62, 52, -22, -76, + -79, 50, 22, -59, 39, 9, -40, 29, -4, -22, 18, -17, + -2, 7, -31, 16, -2, -44, 35, -13, -58, 55, -24, -72, + -76, 49, 26, -57, 38, 13, -38, 27, 0, -19, 17, -13, + 0, 6, -27, 19, -4, -40, 38, -14, -54, 57, -25, -68, + -74, 47, 31, -54, 37, 17, -35, 26, 4, -17, 15, -9, + 3, 4, -23, 22, -5, -36, 40, -16, -49, 60, -27, -63, + -71, 46, 35, -52, 35, 21, -33, 25, 8, -14, 14, -5, + 5, 3, -19, 24, -7, -32, 43, -17, -45, 62, -28, -59, + -69, 45, 39, -49, 34, 25, -31, 23, 12, -12, 13, -1, + 8, 2, -15, 26, -8, -28, 45, -18, -41, 64, -29, -55, + -66, 43, 43, -47, 33, 29, -28, 22, 16, -9, 11, 2, + 10, 0, -11, 29, -9, -24, 48, -20, -37, 67, -31, -51, + -64, 42, 47, -44, 31, 34, -26, 20, 20, -7, 10, 7, + 13, 0, -6, 31, -11, -19, 50, -21, -33, 70, -32, -47, + -61, 41, 51, -42, 30, 38, -23, 19, 24, -4, 8, 11, + 15, -1, -2, 34, -12, -15, 53, -23, -29, 72, -34, -43, + -59, 39, 55, -40, 28, 42, -21, 18, 28, -2, 7, 15, + 17, -3, 1, 36, -13, -11, 55, -24, -25, 74, -35, -39, + -57, 38, 59, -37, 27, 46, -18, 16, 32, 0, 6, 19, + 20, -4, 5, 39, -15, -7, 57, -25, -21, 77, -36, -35, + -54, 36, 64, -34, 25, 50, -16, 15, 37, 3, 4, 23, + 22, -6, 9, 41, -16, -3, 60, -27, -16, 79, -38, -30, + -51, 35, 68, -32, 24, 54, -13, 13, 41, 6, 3, 27, + 25, -7, 13, 44, -18, 0, 62, -28, -12, 82, -39, -26, + -49, 34, 72, -30, 23, 58, -11, 12, 45, 8, 2, 31, + 27, -8, 17, 46, -19, 4, 65, -30, -8, 84, -41, -22, + -47, 32, 76, -27, 21, 62, -8, 11, 49, 10, 0, 35, + 30, -10, 21, 48, -20, 8, 67, -31, -4, 87, -42, -18, + -44, 31, 80, -25, 20, 66, -6, 9, 53, 13, 0, 39, + 32, -11, 25, 51, -22, 12, 70, -32, 0, 89, -43, -14, + -42, 29, 84, -22, 19, 71, -3, 8, 57, 15, -2, 44, + 35, -13, 30, 54, -23, 17, 72, -34, 3, 92, -45, -10, + -39, 28, 88, -20, 17, 75, -1, 7, 61, 18, -3, 48, + 37, -14, 34, 56, -25, 21, 75, -35, 7, 94, -46, -6, + -37, 27, 92, -17, 16, 79, 1, 5, 65, 20, -4, 52, + 40, -15, 38, 58, -26, 25, 77, -37, 11, 96, -47, -2, + -34, 25, 96, -15, 14, 83, 4, 4, 69, 23, -6, 56, + 42, -17, 42, 61, -27, 29, 80, -38, 15, 99, -49, 1, + -32, 24, 101, -12, 13, 87, 6, 2, 74, 25, -7, 60, + 45, -18, 46, 63, -29, 33, 82, -39, 20, 102, -50, 6, + -29, 23, 105, -10, 12, 91, 9, 1, 78, 28, -9, 64, + 47, -20, 50, 66, -30, 37, 85, -41, 24, 104, -52, 10, + -27, 21, 109, -8, 10, 95, 11, 0, 82, 30, -10, 68, + 49, -21, 54, 68, -31, 41, 87, -42, 28, 106, -53, 14, + -102, 68, -18, -83, 57, -32, -64, 47, -45, -45, 36, -59, + -26, 25, -73, -7, 15, -86, 12, 4, -99, 31, -6, -113, + -100, 67, -14, -80, 56, -28, -62, 45, -41, -43, 35, -55, + -24, 24, -69, -5, 13, -82, 14, 3, -95, 33, -7, -109, + -97, 66, -10, -78, 55, -24, -59, 44, -37, -41, 33, -51, + -21, 22, -65, -2, 12, -78, 16, 1, -91, 36, -9, -105, + -95, 64, -6, -75, 53, -20, -57, 42, -33, -38, 32, -46, + -18, 21, -60, 0, 10, -74, 19, 0, -87, 38, -10, -101, + -92, 63, -2, -73, 52, -16, -54, 41, -29, -35, 30, -42, + -16, 20, -56, 3, 9, -70, 22, -1, -83, 41, -12, -97, + -90, 61, 1, -71, 50, -12, -52, 40, -25, -33, 29, -38, + -14, 18, -52, 5, 8, -66, 24, -2, -79, 43, -13, -93, + -88, 60, 5, -68, 49, -8, -49, 38, -21, -31, 28, -34, + -11, 17, -48, 8, 6, -62, 26, -3, -75, 46, -14, -89, + -85, 58, 10, -66, 47, -3, -47, 37, -16, -28, 26, -30, + -9, 15, -44, 10, 5, -57, 29, -5, -70, 48, -16, -84, + -83, 57, 14, -63, 46, 0, -44, 36, -12, -26, 25, -26, + -6, 14, -40, 13, 3, -53, 31, -6, -66, 51, -17, -80, + -80, 56, 18, -61, 45, 4, -42, 34, -8, -23, 24, -22, + -4, 13, -36, 15, 2, -49, 34, -8, -62, 53, -18, -76, + -78, 54, 22, -58, 43, 8, -40, 33, -4, -21, 22, -18, + -1, 11, -32, 17, 1, -45, 36, -9, -58, 56, -20, -72, + -75, 53, 26, -56, 42, 12, -37, 31, 0, -18, 21, -14, + 1, 10, -28, 20, 0, -41, 39, -10, -54, 58, -21, -68, + -73, 51, 30, -53, 41, 16, -34, 30, 3, -16, 19, -9, + 4, 8, -23, 22, -1, -37, 41, -12, -50, 61, -23, -64, + -70, 50, 34, -51, 39, 20, -32, 29, 7, -13, 18, -5, + 6, 7, -19, 25, -3, -33, 44, -13, -46, 63, -24, -60, + -68, 49, 38, -48, 38, 24, -30, 27, 11, -11, 17, -1, + 8, 6, -15, 27, -4, -29, 46, -14, -42, 65, -25, -56, + -65, 47, 42, -46, 37, 28, -27, 26, 15, -9, 15, 2, + 11, 4, -11, 30, -5, -25, 48, -16, -38, 68, -27, -52, + -63, 46, 47, -43, 35, 33, -25, 24, 20, -6, 14, 6, + 14, 3, -7, 32, -7, -20, 51, -17, -33, 70, -28, -47, + -60, 45, 51, -41, 34, 37, -22, 23, 24, -3, 12, 10, + 16, 2, -3, 35, -8, -16, 54, -19, -29, 73, -30, -43, + -58, 43, 55, -39, 32, 41, -20, 22, 28, -1, 11, 14, + 18, 0, 0, 37, -9, -12, 56, -20, -25, 75, -31, -39, + -56, 42, 59, -36, 31, 45, -17, 20, 32, 1, 10, 18, + 21, 0, 4, 40, -11, -8, 58, -21, -21, 78, -32, -35, + -53, 40, 63, -34, 29, 49, -15, 19, 36, 4, 8, 23, + 23, -2, 9, 42, -12, -4, 61, -23, -17, 80, -34, -31, + -51, 39, 67, -31, 28, 53, -12, 17, 40, 6, 7, 27, + 26, -3, 13, 45, -14, 0, 63, -24, -13, 83, -35, -27, + -48, 38, 71, -29, 27, 57, -10, 16, 44, 9, 6, 31, + 28, -4, 17, 47, -15, 3, 66, -26, -9, 85, -37, -23, + -46, 36, 75, -26, 25, 61, -8, 15, 48, 11, 4, 35, + 31, -6, 21, 49, -16, 7, 68, -27, -5, 88, -38, -19, + -43, 35, 79, -24, 24, 65, -5, 13, 52, 14, 3, 39, + 33, -7, 25, 52, -18, 11, 71, -28, -1, 90, -39, -15, + -41, 33, 84, -21, 23, 70, -2, 12, 57, 16, 1, 43, + 36, -9, 29, 54, -19, 16, 73, -30, 3, 93, -41, -10, + -38, 32, 88, -19, 21, 74, 0, 11, 61, 19, 0, 47, + 38, -10, 33, 57, -21, 20, 76, -31, 7, 95, -42, -6, + -36, 31, 92, -16, 20, 78, 2, 9, 65, 21, 0, 51, + 40, -11, 37, 59, -22, 24, 78, -33, 11, 97, -43, -2, + -33, 29, 96, -14, 18, 82, 5, 8, 69, 23, -2, 55, + 43, -13, 41, 62, -23, 28, 80, -34, 15, 100, -45, 1, + -31, 28, 100, -11, 17, 86, 7, 6, 73, 26, -3, 60, + 46, -14, 46, 64, -25, 32, 83, -35, 19, 102, -46, 5, + -28, 27, 104, -9, 16, 90, 10, 5, 77, 29, -5, 64, + 48, -16, 50, 67, -26, 36, 85, -37, 23, 105, -48, 9, + -26, 25, 108, -7, 14, 94, 12, 4, 81, 31, -6, 68, + 50, -17, 54, 69, -27, 40, 88, -38, 27, 107, -49, 13, + -101, 72, -19, -82, 61, -33, -63, 51, -46, -44, 40, -59, + -25, 29, -73, -6, 19, -87, 13, 8, -100, 32, -2, -114, + -99, 71, -15, -80, 60, -29, -61, 49, -42, -42, 39, -55, + -23, 28, -69, -4, 17, -83, 15, 7, -96, 34, -3, -110, + -97, 70, -11, -77, 59, -25, -58, 48, -38, -40, 37, -51, + -20, 26, -65, -1, 16, -79, 17, 5, -92, 37, -5, -106, + -94, 68, -6, -74, 57, -20, -56, 46, -34, -37, 36, -47, + -18, 25, -61, 1, 14, -74, 20, 4, -88, 39, -6, -101, + -91, 67, -2, -72, 56, -16, -53, 45, -30, -35, 34, -43, + -15, 24, -57, 4, 13, -70, 22, 2, -84, 42, -8, -97, + -89, 65, 1, -70, 54, -12, -51, 44, -26, -32, 33, -39, + -13, 22, -53, 6, 12, -66, 25, 1, -80, 44, -9, -93, + -87, 64, 5, -67, 53, -8, -49, 42, -22, -30, 32, -35, + -10, 21, -49, 8, 10, -62, 27, 0, -76, 47, -10, -89, + -84, 62, 9, -65, 51, -4, -46, 41, -17, -27, 30, -30, + -8, 19, -44, 11, 9, -58, 30, -1, -71, 49, -12, -85, + -82, 61, 13, -62, 50, 0, -43, 40, -13, -25, 29, -26, + -5, 18, -40, 14, 7, -54, 32, -2, -67, 52, -13, -81, + -79, 60, 17, -60, 49, 3, -41, 38, -9, -22, 28, -22, + -3, 17, -36, 16, 6, -50, 35, -4, -63, 54, -14, -77, + -77, 58, 21, -57, 47, 7, -39, 37, -5, -20, 26, -18, + 0, 15, -32, 18, 5, -46, 37, -5, -59, 56, -16, -73, + -74, 57, 25, -55, 46, 11, -36, 35, -1, -17, 25, -14, + 2, 14, -28, 21, 3, -42, 39, -6, -55, 59, -17, -69, + -72, 55, 30, -52, 45, 16, -34, 34, 2, -15, 23, -10, + 5, 12, -24, 23, 2, -37, 42, -8, -51, 62, -19, -64, + -69, 54, 34, -50, 43, 20, -31, 33, 6, -12, 22, -6, + 7, 11, -20, 26, 0, -33, 45, -9, -47, 64, -20, -60, + -67, 53, 38, -48, 42, 24, -29, 31, 10, -10, 21, -2, + 9, 10, -16, 28, 0, -29, 47, -10, -43, 66, -21, -56, + -65, 51, 42, -45, 41, 28, -26, 30, 14, -8, 19, 1, + 12, 8, -12, 31, -1, -25, 49, -12, -39, 69, -23, -52, + -62, 50, 46, -42, 39, 32, -24, 28, 19, -5, 18, 6, + 14, 7, -7, 33, -3, -21, 52, -13, -34, 71, -24, -48, + -59, 49, 50, -40, 38, 36, -21, 27, 23, -3, 16, 10, + 17, 6, -3, 36, -4, -17, 54, -15, -30, 74, -26, -44, + -57, 47, 54, -38, 36, 40, -19, 26, 27, 0, 15, 14, + 19, 4, 0, 38, -5, -13, 57, -16, -26, 76, -27, -40, + -55, 46, 58, -35, 35, 44, -17, 24, 31, 2, 14, 18, + 22, 3, 4, 40, -7, -9, 59, -17, -22, 79, -28, -36, + -52, 44, 63, -33, 33, 49, -14, 23, 35, 5, 12, 22, + 24, 1, 8, 43, -8, -4, 62, -19, -18, 81, -30, -31, + -50, 43, 67, -30, 32, 53, -11, 21, 39, 7, 11, 26, + 27, 0, 12, 45, -10, 0, 64, -20, -14, 84, -31, -27, + -47, 42, 71, -28, 31, 57, -9, 20, 43, 10, 10, 30, + 29, 0, 16, 48, -11, 3, 67, -22, -10, 86, -33, -23, + -45, 40, 75, -25, 29, 61, -7, 19, 47, 12, 8, 34, + 31, -2, 20, 50, -12, 7, 69, -23, -6, 88, -34, -19, + -42, 39, 79, -23, 28, 65, -4, 17, 51, 15, 7, 38, + 34, -3, 24, 53, -14, 11, 71, -24, -2, 91, -35, -15, + -40, 37, 83, -20, 27, 69, -2, 16, 56, 17, 5, 43, + 37, -5, 29, 55, -15, 15, 74, -26, 2, 94, -37, -11, + -37, 36, 87, -18, 25, 73, 1, 15, 60, 20, 4, 47, + 39, -6, 33, 58, -17, 19, 77, -27, 6, 96, -38, -7, + -35, 35, 91, -16, 24, 77, 3, 13, 64, 22, 3, 51, + 41, -7, 37, 60, -18, 23, 79, -29, 10, 98, -39, -3, + -33, 33, 95, -13, 22, 81, 6, 12, 68, 24, 1, 55, + 44, -9, 41, 63, -19, 27, 81, -30, 14, 101, -41, 0, + -30, 32, 100, -10, 21, 86, 8, 10, 72, 27, 0, 59, + 46, -10, 45, 65, -21, 32, 84, -31, 18, 103, -42, 5, + -27, 31, 104, -8, 20, 90, 11, 9, 76, 29, -1, 63, + 49, -12, 49, 68, -22, 36, 86, -33, 22, 106, -44, 9, + -25, 29, 108, -6, 18, 94, 13, 8, 80, 32, -2, 67, + 51, -13, 53, 70, -23, 40, 89, -34, 26, 108, -45, 13, + -100, 77, -20, -81, 66, -33, -62, 55, -47, -43, 45, -60, + -24, 34, -74, -5, 23, -87, 14, 12, -101, 33, 2, -115, + -98, 75, -16, -79, 64, -29, -60, 54, -43, -41, 43, -56, + -22, 32, -70, -3, 22, -83, 16, 11, -97, 35, 0, -111, + -96, 74, -12, -76, 63, -25, -57, 52, -39, -39, 42, -52, + -19, 31, -66, 0, 20, -79, 18, 10, -93, 38, 0, -107, + -93, 72, -7, -73, 62, -21, -55, 51, -34, -36, 40, -48, + -17, 29, -62, 2, 19, -75, 21, 8, -88, 40, -2, -102, + -90, 71, -3, -71, 60, -17, -52, 50, -30, -33, 39, -44, + -14, 28, -58, 5, 17, -71, 23, 7, -84, 43, -3, -98, + -88, 70, 0, -69, 59, -13, -50, 48, -26, -31, 38, -40, + -12, 27, -54, 7, 16, -67, 26, 6, -80, 45, -4, -94, + -86, 68, 4, -66, 58, -9, -47, 47, -22, -29, 36, -36, + -9, 25, -50, 9, 15, -63, 28, 4, -76, 48, -6, -90, + -83, 67, 8, -64, 56, -4, -45, 45, -18, -26, 35, -31, + -7, 24, -45, 12, 13, -58, 31, 3, -72, 50, -7, -86, + -81, 66, 12, -61, 55, 0, -42, 44, -14, -24, 33, -27, + -4, 22, -41, 15, 12, -54, 33, 1, -68, 53, -9, -82, + -78, 64, 16, -59, 53, 3, -40, 43, -10, -21, 32, -23, + -2, 21, -37, 17, 11, -50, 36, 0, -64, 55, -10, -78, + -76, 63, 20, -56, 52, 7, -38, 41, -6, -19, 31, -19, + 1, 20, -33, 19, 9, -46, 38, 0, -60, 57, -11, -74, + -73, 62, 24, -54, 51, 11, -35, 40, -2, -16, 29, -15, + 3, 18, -29, 22, 8, -42, 40, -2, -56, 60, -13, -70, + -71, 60, 29, -51, 49, 15, -33, 38, 2, -14, 28, -11, + 6, 17, -25, 24, 6, -38, 43, -3, -51, 63, -14, -65, + -68, 59, 33, -49, 48, 19, -30, 37, 6, -11, 27, -7, + 8, 16, -21, 27, 5, -34, 46, -5, -47, 65, -16, -61, + -66, 57, 37, -47, 46, 23, -28, 36, 10, -9, 25, -3, + 10, 14, -17, 29, 4, -30, 48, -6, -43, 67, -17, -57, + -64, 56, 41, -44, 45, 27, -25, 34, 14, -7, 24, 0, + 13, 13, -13, 32, 2, -26, 50, -7, -39, 70, -18, -53, + -61, 54, 45, -41, 43, 32, -23, 33, 18, -4, 22, 5, + 15, 11, -8, 34, 1, -21, 53, -9, -35, 72, -20, -49, + -58, 53, 49, -39, 42, 36, -20, 32, 22, -1, 21, 9, + 18, 10, -4, 37, 0, -17, 55, -10, -31, 75, -21, -45, + -56, 52, 53, -37, 41, 40, -18, 30, 26, 1, 20, 13, + 20, 9, 0, 39, -1, -13, 58, -12, -27, 77, -22, -41, + -54, 50, 57, -34, 39, 44, -15, 29, 30, 3, 18, 17, + 23, 7, 3, 41, -2, -9, 60, -13, -23, 80, -24, -37, + -51, 49, 62, -32, 38, 48, -13, 27, 35, 6, 17, 21, + 25, 6, 7, 44, -4, -5, 63, -14, -18, 82, -25, -32, + -49, 48, 66, -29, 37, 52, -10, 26, 39, 8, 15, 25, + 28, 4, 11, 47, -5, -1, 65, -16, -14, 85, -27, -28, + -46, 46, 70, -27, 35, 56, -8, 25, 43, 11, 14, 29, + 30, 3, 15, 49, -7, 2, 68, -17, -10, 87, -28, -24, + -44, 45, 74, -24, 34, 60, -6, 23, 47, 13, 13, 33, + 33, 2, 19, 51, -8, 6, 70, -18, -6, 89, -29, -20, + -41, 43, 78, -22, 33, 64, -3, 22, 51, 16, 11, 37, + 35, 0, 23, 54, -9, 10, 72, -20, -2, 92, -31, -16, + -39, 42, 82, -19, 31, 69, -1, 20, 55, 18, 10, 42, + 38, 0, 28, 56, -11, 15, 75, -21, 1, 95, -32, -12, + -36, 41, 86, -17, 30, 73, 2, 19, 59, 21, 8, 46, + 40, -1, 32, 59, -12, 19, 78, -23, 5, 97, -34, -8, + -34, 39, 90, -15, 28, 77, 4, 18, 63, 23, 7, 50, + 42, -3, 36, 61, -13, 23, 80, -24, 9, 99, -35, -4, + -32, 38, 94, -12, 27, 81, 7, 16, 67, 25, 6, 54, + 45, -4, 40, 64, -15, 27, 82, -25, 13, 102, -36, 0, + -29, 36, 99, -9, 25, 85, 9, 15, 72, 28, 4, 58, + 47, -6, 44, 66, -16, 31, 85, -27, 18, 104, -38, 4, + -26, 35, 103, -7, 24, 89, 12, 13, 76, 30, 3, 62, + 50, -7, 48, 69, -18, 35, 87, -28, 22, 107, -39, 8, + -24, 34, 107, -5, 23, 93, 14, 12, 80, 33, 2, 66, + 52, -8, 52, 71, -19, 39, 90, -30, 26, 109, -41, 12, + -99, 81, -20, -80, 70, -34, -61, 59, -47, -42, 49, -61, + -23, 38, -75, -4, 27, -88, 14, 16, -101, 34, 6, -115, + -97, 79, -16, -78, 68, -30, -59, 58, -43, -40, 47, -57, + -21, 36, -71, -2, 26, -84, 17, 15, -97, 36, 4, -111, + -95, 78, -12, -75, 67, -26, -56, 56, -39, -38, 46, -53, + -18, 35, -67, 0, 24, -80, 19, 14, -93, 39, 3, -107, + -92, 76, -8, -73, 66, -22, -54, 55, -35, -35, 44, -48, + -16, 33, -62, 3, 23, -76, 22, 12, -89, 41, 1, -103, + -90, 75, -4, -70, 64, -18, -51, 54, -31, -33, 43, -44, + -13, 32, -58, 6, 21, -72, 24, 11, -85, 44, 0, -99, + -87, 74, 0, -68, 63, -14, -49, 52, -27, -30, 42, -40, + -11, 31, -54, 8, 20, -68, 27, 10, -81, 46, 0, -95, + -85, 72, 3, -65, 62, -10, -47, 51, -23, -28, 40, -36, + -8, 29, -50, 10, 19, -64, 29, 8, -77, 49, -2, -91, + -82, 71, 8, -63, 60, -5, -44, 49, -18, -25, 39, -32, + -6, 28, -46, 13, 17, -59, 32, 7, -72, 51, -3, -86, + -80, 70, 12, -60, 59, -1, -41, 48, -14, -23, 37, -28, + -3, 26, -42, 15, 16, -55, 34, 5, -68, 54, -5, -82, + -77, 68, 16, -58, 57, 2, -39, 47, -10, -20, 36, -24, + -1, 25, -38, 18, 15, -51, 37, 4, -64, 56, -6, -78, + -75, 67, 20, -55, 56, 6, -37, 45, -6, -18, 35, -20, + 1, 24, -34, 20, 13, -47, 39, 3, -60, 58, -7, -74, + -72, 66, 24, -53, 55, 10, -34, 44, -2, -16, 33, -16, + 4, 22, -30, 23, 12, -43, 41, 1, -56, 61, -9, -70, + -70, 64, 28, -50, 53, 14, -32, 42, 1, -13, 32, -11, + 7, 21, -25, 25, 10, -39, 44, 0, -52, 63, -10, -66, + -67, 63, 32, -48, 52, 18, -29, 41, 5, -10, 31, -7, + 9, 20, -21, 28, 9, -35, 46, -1, -48, 66, -12, -62, + -65, 61, 36, -46, 50, 22, -27, 40, 9, -8, 29, -3, + 11, 18, -17, 30, 8, -31, 49, -2, -44, 68, -13, -58, + -63, 60, 40, -43, 49, 26, -24, 38, 13, -6, 28, 0, + 14, 17, -13, 32, 6, -27, 51, -3, -40, 71, -14, -54, + -60, 58, 45, -41, 47, 31, -22, 37, 18, -3, 26, 4, + 16, 15, -9, 35, 5, -22, 54, -5, -35, 73, -16, -49, + -58, 57, 49, -38, 46, 35, -19, 36, 22, -1, 25, 8, + 19, 14, -5, 38, 3, -18, 56, -6, -31, 76, -17, -45, + -55, 56, 53, -36, 45, 39, -17, 34, 26, 2, 24, 12, + 21, 13, -1, 40, 2, -14, 59, -8, -27, 78, -18, -41, + -53, 54, 57, -33, 43, 43, -15, 33, 30, 4, 22, 16, + 24, 11, 2, 42, 1, -10, 61, -9, -23, 81, -20, -37, + -50, 53, 61, -31, 42, 47, -12, 31, 34, 7, 21, 21, + 26, 10, 7, 45, 0, -6, 64, -10, -19, 83, -21, -33, + -48, 52, 65, -28, 41, 51, -10, 30, 38, 9, 19, 25, + 29, 8, 11, 47, -1, -2, 66, -12, -15, 86, -23, -29, + -45, 50, 69, -26, 39, 55, -7, 29, 42, 12, 18, 29, + 31, 7, 15, 50, -3, 1, 69, -13, -11, 88, -24, -25, + -43, 49, 73, -24, 38, 59, -5, 27, 46, 14, 17, 33, + 33, 6, 19, 52, -4, 5, 71, -14, -7, 90, -25, -21, + -40, 47, 77, -21, 37, 63, -2, 26, 50, 16, 15, 37, + 36, 4, 23, 55, -5, 9, 73, -16, -3, 93, -27, -17, + -38, 46, 82, -18, 35, 68, 0, 24, 55, 19, 14, 41, + 39, 3, 27, 57, -7, 14, 76, -17, 1, 95, -28, -12, + -35, 45, 86, -16, 34, 72, 3, 23, 59, 22, 12, 45, + 41, 2, 31, 60, -8, 18, 78, -19, 5, 98, -30, -8, + -33, 43, 90, -14, 32, 76, 5, 22, 63, 24, 11, 49, + 43, 0, 35, 62, -9, 22, 81, -20, 9, 100, -31, -4, + -31, 42, 94, -11, 31, 80, 8, 20, 67, 26, 10, 53, + 46, 0, 39, 64, -11, 26, 83, -21, 13, 103, -32, 0, + -28, 40, 98, -9, 29, 84, 10, 19, 71, 29, 8, 58, + 48, -2, 44, 67, -12, 30, 86, -23, 17, 105, -34, 3, + -26, 39, 102, -6, 28, 88, 13, 17, 75, 31, 7, 62, + 51, -3, 48, 70, -14, 34, 88, -24, 21, 108, -35, 7, + -23, 38, 106, -4, 27, 92, 15, 16, 79, 34, 6, 66, + 53, -4, 52, 72, -15, 38, 91, -26, 25, 110, -37, 11, + -98, 85, -21, -79, 74, -35, -60, 63, -48, -42, 53, -62, + -22, 42, -75, -3, 31, -89, 15, 20, -102, 35, 10, -116, + -96, 83, -17, -77, 72, -31, -58, 62, -44, -39, 51, -58, + -20, 40, -71, -1, 30, -85, 18, 19, -98, 37, 8, -112, + -94, 82, -13, -74, 71, -27, -56, 60, -40, -37, 50, -54, + -17, 39, -67, 1, 28, -81, 20, 18, -94, 40, 7, -108, + -91, 80, -8, -72, 70, -22, -53, 59, -36, -34, 48, -49, + -15, 37, -63, 4, 27, -76, 23, 16, -90, 42, 5, -103, + -89, 79, -4, -69, 68, -18, -50, 58, -32, -32, 47, -45, + -12, 36, -59, 6, 25, -72, 25, 15, -86, 45, 4, -99, + -86, 78, 0, -67, 67, -14, -48, 56, -28, -29, 46, -41, + -10, 35, -55, 9, 24, -68, 28, 14, -82, 47, 3, -95, + -84, 76, 3, -64, 66, -10, -46, 55, -24, -27, 44, -37, + -8, 33, -51, 11, 23, -64, 30, 12, -78, 49, 1, -91, + -81, 75, 7, -62, 64, -6, -43, 53, -19, -24, 43, -33, + -5, 32, -46, 14, 21, -60, 33, 11, -73, 52, 0, -87, + -79, 74, 11, -59, 63, -2, -41, 52, -15, -22, 41, -29, + -2, 30, -42, 16, 20, -56, 35, 9, -69, 55, -1, -83, + -76, 72, 15, -57, 61, 1, -38, 51, -11, -19, 40, -25, + 0, 29, -38, 19, 19, -52, 38, 8, -65, 57, -2, -79, + -74, 71, 19, -55, 60, 5, -36, 49, -7, -17, 39, -21, + 2, 28, -34, 21, 17, -48, 40, 7, -61, 59, -3, -75, + -72, 70, 23, -52, 59, 9, -33, 48, -3, -15, 37, -17, + 5, 26, -30, 24, 16, -44, 42, 5, -57, 62, -5, -71, + -69, 68, 28, -50, 57, 14, -31, 46, 0, -12, 36, -12, + 7, 25, -26, 26, 14, -39, 45, 4, -53, 64, -6, -66, + -66, 67, 32, -47, 56, 18, -28, 45, 4, -10, 35, -8, + 10, 24, -22, 29, 13, -35, 47, 2, -49, 67, -8, -62, + -64, 65, 36, -45, 54, 22, -26, 44, 8, -7, 33, -4, + 12, 22, -18, 31, 12, -31, 50, 1, -45, 69, -9, -58, + -62, 64, 40, -42, 53, 26, -24, 42, 12, -5, 32, 0, + 15, 21, -14, 33, 10, -27, 52, 0, -41, 72, -10, -54, + -59, 62, 44, -40, 51, 30, -21, 41, 17, -2, 30, 3, + 17, 19, -9, 36, 9, -23, 55, -1, -36, 74, -12, -50, + -57, 61, 48, -37, 50, 34, -18, 40, 21, 0, 29, 7, + 20, 18, -5, 38, 7, -19, 57, -2, -32, 77, -13, -46, + -54, 60, 52, -35, 49, 38, -16, 38, 25, 3, 28, 11, + 22, 17, -1, 41, 6, -15, 60, -4, -28, 79, -14, -42, + -52, 58, 56, -32, 47, 42, -14, 37, 29, 5, 26, 15, + 24, 15, 2, 43, 5, -11, 62, -5, -24, 81, -16, -38, + -49, 57, 61, -30, 46, 47, -11, 35, 33, 8, 25, 20, + 27, 14, 6, 46, 3, -6, 65, -6, -20, 84, -17, -33, + -47, 56, 65, -27, 45, 51, -9, 34, 37, 10, 23, 24, + 30, 12, 10, 48, 2, -2, 67, -8, -16, 87, -19, -29, + -44, 54, 69, -25, 43, 55, -6, 33, 41, 13, 22, 28, + 32, 11, 14, 51, 0, 1, 70, -9, -12, 89, -20, -25, + -42, 53, 73, -23, 42, 59, -4, 31, 45, 15, 21, 32, + 34, 10, 18, 53, 0, 5, 72, -10, -8, 91, -21, -21, + -40, 51, 77, -20, 41, 63, -1, 30, 49, 17, 19, 36, + 37, 8, 22, 56, -1, 9, 74, -12, -4, 94, -23, -17, + -37, 50, 81, -18, 39, 67, 1, 28, 54, 20, 18, 40, + 39, 7, 27, 58, -3, 13, 77, -13, 0, 96, -24, -13, + -34, 49, 85, -15, 38, 71, 4, 27, 58, 22, 16, 44, + 42, 6, 31, 61, -4, 17, 79, -15, 4, 99, -26, -9, + -32, 47, 89, -13, 36, 75, 6, 26, 62, 25, 15, 48, + 44, 4, 35, 63, -5, 21, 82, -16, 8, 101, -27, -5, + -30, 46, 93, -10, 35, 79, 8, 24, 66, 27, 14, 52, + 47, 3, 39, 65, -7, 25, 84, -17, 12, 104, -28, -1, + -27, 44, 98, -8, 33, 84, 11, 23, 70, 30, 12, 57, + 49, 1, 43, 68, -8, 30, 87, -19, 16, 106, -30, 3, + -25, 43, 102, -5, 32, 88, 14, 21, 74, 32, 11, 61, + 52, 0, 47, 70, -10, 34, 89, -20, 20, 109, -31, 7, + -22, 42, 106, -3, 31, 92, 16, 20, 78, 35, 10, 65, + 54, 0, 51, 73, -11, 38, 92, -22, 24, 111, -33, 11, + -98, 89, -22, -78, 78, -35, -59, 67, -49, -41, 57, -62, + -21, 46, -76, -2, 35, -89, 16, 24, -103, 36, 14, -117, + -95, 87, -18, -76, 76, -31, -57, 66, -45, -38, 55, -58, + -19, 44, -72, 0, 34, -85, 19, 23, -99, 38, 12, -113, + -93, 86, -14, -73, 75, -27, -55, 64, -41, -36, 54, -54, + -16, 43, -68, 2, 32, -81, 21, 22, -95, 40, 11, -109, + -90, 84, -9, -71, 74, -23, -52, 63, -36, -33, 52, -50, + -14, 41, -63, 5, 31, -77, 24, 20, -90, 43, 9, -104, + -88, 83, -5, -68, 72, -19, -50, 62, -32, -31, 51, -46, + -11, 40, -59, 7, 29, -73, 26, 19, -86, 46, 8, -100, + -85, 82, -1, -66, 71, -15, -47, 60, -28, -28, 50, -42, + -9, 39, -55, 10, 28, -69, 29, 18, -82, 48, 7, -96, + -83, 80, 2, -64, 70, -11, -45, 59, -24, -26, 48, -38, + -7, 37, -51, 12, 27, -65, 31, 16, -78, 50, 5, -92, + -80, 79, 6, -61, 68, -6, -42, 57, -20, -23, 47, -33, + -4, 36, -47, 15, 25, -60, 34, 15, -74, 53, 4, -88, + -78, 78, 10, -58, 67, -2, -40, 56, -16, -21, 45, -29, + -2, 34, -43, 17, 24, -56, 36, 13, -70, 55, 2, -84, + -75, 76, 14, -56, 65, 1, -37, 55, -12, -18, 44, -25, + 1, 33, -39, 20, 23, -52, 38, 12, -66, 58, 1, -80, + -73, 75, 18, -54, 64, 5, -35, 53, -8, -16, 43, -21, + 3, 32, -35, 22, 21, -48, 41, 11, -62, 60, 0, -76, + -71, 74, 22, -51, 63, 9, -32, 52, -4, -14, 41, -17, + 6, 30, -31, 24, 20, -44, 43, 9, -58, 63, -1, -72, + -68, 72, 27, -49, 61, 13, -30, 50, 0, -11, 40, -13, + 8, 29, -26, 27, 18, -40, 46, 8, -53, 65, -2, -67, + -66, 71, 31, -46, 60, 17, -27, 49, 4, -9, 39, -9, + 11, 28, -22, 30, 17, -36, 48, 6, -49, 68, -4, -63, + -63, 69, 35, -44, 58, 21, -25, 48, 8, -6, 37, -5, + 13, 26, -18, 32, 16, -32, 51, 5, -45, 70, -5, -59, + -61, 68, 39, -41, 57, 25, -23, 46, 12, -4, 36, -1, + 16, 25, -14, 34, 14, -28, 53, 4, -41, 72, -6, -55, + -58, 66, 43, -39, 55, 30, -20, 45, 16, -1, 34, 3, + 18, 23, -10, 37, 13, -23, 56, 2, -37, 75, -8, -51, + -56, 65, 47, -36, 54, 34, -18, 44, 20, 1, 33, 7, + 21, 22, -6, 39, 11, -19, 58, 1, -33, 78, -9, -47, + -53, 64, 51, -34, 53, 38, -15, 42, 24, 4, 32, 11, + 23, 21, -2, 42, 10, -15, 61, 0, -29, 80, -10, -43, + -51, 62, 55, -32, 51, 42, -13, 41, 28, 6, 30, 15, + 25, 19, 1, 44, 9, -11, 63, -1, -25, 82, -12, -39, + -48, 61, 60, -29, 50, 46, -10, 39, 33, 9, 29, 19, + 28, 18, 6, 47, 7, -7, 66, -2, -20, 85, -13, -34, + -46, 60, 64, -26, 49, 50, -8, 38, 37, 11, 27, 23, + 30, 16, 10, 49, 6, -3, 68, -4, -16, 87, -15, -30, + -43, 58, 68, -24, 47, 54, -5, 37, 41, 13, 26, 27, + 33, 15, 14, 52, 4, 0, 70, -5, -12, 90, -16, -26, + -41, 57, 72, -22, 46, 58, -3, 35, 45, 16, 25, 31, + 35, 14, 18, 54, 3, 4, 73, -6, -8, 92, -17, -22, + -39, 55, 76, -19, 45, 62, -1, 34, 49, 18, 23, 35, + 38, 12, 22, 56, 2, 8, 75, -8, -4, 95, -19, -18, + -36, 54, 80, -17, 43, 67, 2, 32, 53, 21, 22, 40, + 40, 11, 26, 59, 0, 13, 78, -9, 0, 97, -20, -14, + -34, 53, 84, -14, 42, 71, 5, 31, 57, 23, 20, 44, + 43, 10, 30, 62, 0, 17, 80, -11, 3, 100, -22, -10, + -31, 51, 88, -12, 40, 75, 7, 30, 61, 26, 19, 48, + 45, 8, 34, 64, -1, 21, 83, -12, 7, 102, -23, -6, + -29, 50, 92, -9, 39, 79, 9, 28, 65, 28, 18, 52, + 48, 7, 38, 66, -3, 25, 85, -13, 11, 104, -24, -2, + -26, 48, 97, -7, 37, 83, 12, 27, 70, 31, 16, 56, + 50, 5, 43, 69, -4, 29, 88, -15, 16, 107, -26, 2, + -24, 47, 101, -4, 36, 87, 14, 25, 74, 33, 15, 60, + 53, 4, 47, 71, -6, 33, 90, -16, 20, 110, -27, 6, + -21, 46, 105, -2, 35, 91, 17, 24, 78, 36, 14, 64, + 55, 3, 51, 74, -7, 37, 93, -18, 24, 112, -29, 10, + -97, 93, -22, -77, 82, -36, -58, 71, -49, -40, 61, -63, + -20, 50, -77, -2, 39, -90, 17, 28, -103, 37, 18, -117, + -94, 91, -18, -75, 80, -32, -56, 70, -45, -37, 59, -59, + -18, 48, -73, 1, 38, -86, 20, 27, -99, 39, 16, -113, + -92, 90, -14, -72, 79, -28, -54, 68, -41, -35, 58, -55, + -16, 47, -69, 3, 36, -82, 22, 26, -95, 41, 15, -109, + -89, 88, -10, -70, 78, -24, -51, 67, -37, -32, 56, -50, + -13, 45, -64, 6, 35, -78, 25, 24, -91, 44, 13, -105, + -87, 87, -6, -67, 76, -20, -49, 66, -33, -30, 55, -46, + -10, 44, -60, 8, 33, -74, 27, 23, -87, 46, 12, -101, + -84, 86, -2, -65, 75, -16, -46, 64, -29, -27, 54, -42, + -8, 43, -56, 11, 32, -70, 29, 22, -83, 49, 11, -97, + -82, 84, 1, -63, 74, -12, -44, 63, -25, -25, 52, -38, + -6, 41, -52, 13, 31, -66, 32, 20, -79, 51, 9, -93, + -79, 83, 6, -60, 72, -7, -41, 61, -20, -22, 51, -34, + -3, 40, -48, 16, 29, -61, 35, 19, -74, 54, 8, -88, + -77, 82, 10, -58, 71, -3, -39, 60, -16, -20, 49, -30, + -1, 38, -44, 18, 28, -57, 37, 17, -70, 56, 6, -84, + -75, 80, 14, -55, 69, 0, -36, 59, -12, -18, 48, -26, + 2, 37, -40, 21, 27, -53, 39, 16, -66, 59, 5, -80, + -72, 79, 18, -53, 68, 4, -34, 57, -8, -15, 47, -22, + 4, 36, -36, 23, 25, -49, 42, 15, -62, 61, 4, -76, + -70, 78, 22, -50, 67, 8, -32, 56, -4, -13, 45, -18, + 7, 34, -32, 25, 24, -45, 44, 13, -58, 64, 2, -72, + -67, 76, 26, -48, 65, 12, -29, 54, 0, -10, 44, -13, + 9, 33, -27, 28, 22, -41, 47, 12, -54, 66, 1, -68, + -65, 75, 30, -45, 64, 16, -27, 53, 3, -8, 43, -9, + 12, 32, -23, 30, 21, -37, 49, 10, -50, 69, 0, -64, + -62, 73, 34, -43, 62, 20, -24, 52, 7, -5, 41, -5, + 14, 30, -19, 33, 20, -33, 52, 9, -46, 71, -1, -60, + -60, 72, 38, -41, 61, 24, -22, 50, 11, -3, 40, -1, + 16, 29, -15, 35, 18, -29, 54, 8, -42, 73, -2, -56, + -57, 70, 43, -38, 59, 29, -19, 49, 16, 0, 38, 2, + 19, 27, -11, 38, 17, -24, 57, 6, -37, 76, -4, -51, + -55, 69, 47, -35, 58, 33, -17, 48, 20, 2, 37, 6, + 22, 26, -7, 40, 15, -20, 59, 5, -33, 78, -5, -47, + -52, 68, 51, -33, 57, 37, -14, 46, 24, 5, 36, 10, + 24, 25, -3, 43, 14, -16, 61, 3, -29, 81, -6, -43, + -50, 66, 55, -31, 55, 41, -12, 45, 28, 7, 34, 14, + 26, 23, 0, 45, 13, -12, 64, 2, -25, 83, -8, -39, + -47, 65, 59, -28, 54, 45, -9, 43, 32, 10, 33, 19, + 29, 22, 5, 48, 11, -8, 67, 1, -21, 86, -9, -35, + -45, 64, 63, -26, 53, 49, -7, 42, 36, 12, 31, 23, + 31, 20, 9, 50, 10, -4, 69, 0, -17, 88, -11, -31, + -43, 62, 67, -23, 51, 53, -4, 41, 40, 14, 30, 27, + 34, 19, 13, 53, 8, 0, 71, -1, -13, 91, -12, -27, + -40, 61, 71, -21, 50, 57, -2, 39, 44, 17, 29, 31, + 36, 18, 17, 55, 7, 3, 74, -2, -9, 93, -13, -23, + -38, 59, 75, -18, 49, 61, 0, 38, 48, 19, 27, 35, + 39, 16, 21, 57, 6, 7, 76, -4, -5, 96, -15, -19, + -35, 58, 80, -16, 47, 66, 3, 36, 53, 22, 26, 39, + 41, 15, 25, 60, 4, 12, 79, -5, 0, 98, -16, -14, + -33, 57, 84, -13, 46, 70, 5, 35, 57, 24, 24, 43, + 44, 14, 29, 62, 3, 16, 81, -7, 3, 101, -18, -10, + -30, 55, 88, -11, 44, 74, 8, 34, 61, 27, 23, 47, + 46, 12, 33, 65, 2, 20, 84, -8, 7, 103, -19, -6, + -28, 54, 92, -9, 43, 78, 10, 32, 65, 29, 22, 51, + 48, 11, 37, 67, 0, 24, 86, -9, 11, 105, -20, -2, + -25, 52, 96, -6, 41, 82, 13, 31, 69, 32, 20, 56, + 51, 9, 42, 70, 0, 28, 89, -11, 15, 108, -22, 1, + -23, 51, 100, -3, 40, 86, 15, 29, 73, 34, 19, 60, + 54, 8, 46, 72, -2, 32, 91, -12, 19, 110, -23, 5, + -20, 50, 104, -1, 39, 90, 18, 28, 77, 37, 18, 64, + 56, 7, 50, 75, -3, 36, 93, -14, 23, 113, -25, 9, + -96, 97, -23, -76, 86, -37, -57, 76, -50, -39, 65, -64, + -19, 54, -77, -1, 44, -91, 18, 33, -104, 38, 22, -118, + -93, 96, -19, -74, 85, -33, -55, 74, -46, -36, 64, -60, + -17, 53, -73, 2, 42, -87, 21, 32, -100, 40, 21, -114, + -91, 95, -15, -71, 84, -29, -53, 73, -42, -34, 62, -56, + -15, 51, -69, 4, 41, -83, 23, 30, -96, 42, 19, -110, + -88, 93, -10, -69, 82, -24, -50, 71, -38, -31, 61, -51, + -12, 50, -65, 7, 39, -78, 26, 29, -92, 45, 18, -105, + -86, 92, -6, -66, 81, -20, -48, 70, -34, -29, 59, -47, + -9, 49, -61, 9, 38, -74, 28, 27, -88, 47, 16, -101, + -83, 90, -2, -64, 79, -16, -45, 69, -30, -26, 58, -43, + -7, 47, -57, 12, 37, -70, 31, 26, -84, 50, 15, -97, + -81, 89, 1, -62, 78, -12, -43, 67, -26, -24, 57, -39, + -5, 46, -53, 14, 35, -66, 33, 25, -80, 52, 14, -93, + -78, 87, 5, -59, 76, -8, -40, 66, -21, -21, 55, -35, + -2, 44, -48, 17, 34, -62, 36, 23, -75, 55, 12, -89, + -76, 86, 9, -57, 75, -4, -38, 65, -17, -19, 54, -31, + 0, 43, -44, 19, 32, -58, 38, 22, -71, 57, 11, -85, + -73, 85, 13, -54, 74, 0, -35, 63, -13, -17, 53, -27, + 3, 42, -40, 22, 31, -54, 40, 20, -67, 60, 10, -81, + -71, 83, 17, -52, 72, 3, -33, 62, -9, -14, 51, -23, + 5, 40, -36, 24, 30, -50, 43, 19, -63, 62, 8, -77, + -69, 82, 21, -49, 71, 7, -31, 60, -5, -12, 50, -19, + 8, 39, -32, 26, 28, -46, 45, 18, -59, 65, 7, -73, + -66, 80, 26, -47, 70, 12, -28, 59, -1, -9, 48, -14, + 10, 37, -28, 29, 27, -41, 48, 16, -55, 67, 5, -68, + -64, 79, 30, -44, 68, 16, -25, 58, 2, -7, 47, -10, + 13, 36, -24, 31, 25, -37, 50, 15, -51, 70, 4, -64, + -61, 78, 34, -42, 67, 20, -23, 56, 6, -4, 46, -6, + 15, 35, -20, 34, 24, -33, 53, 14, -47, 72, 3, -60, + -59, 76, 38, -39, 66, 24, -21, 55, 10, -2, 44, -2, + 17, 33, -16, 36, 23, -29, 55, 12, -43, 74, 1, -56, + -56, 75, 42, -37, 64, 28, -18, 53, 15, 1, 43, 1, + 20, 32, -11, 39, 21, -25, 58, 11, -38, 77, 0, -52, + -54, 74, 46, -34, 63, 32, -16, 52, 19, 3, 41, 5, + 23, 31, -7, 41, 20, -21, 60, 9, -34, 79, -1, -48, + -51, 72, 50, -32, 61, 36, -13, 51, 23, 6, 40, 9, + 25, 29, -3, 44, 19, -17, 63, 8, -30, 82, -2, -44, + -49, 71, 54, -30, 60, 40, -11, 49, 27, 8, 39, 13, + 27, 28, 0, 46, 17, -13, 65, 7, -26, 84, -3, -40, + -46, 69, 59, -27, 58, 45, -8, 48, 31, 11, 37, 18, + 30, 26, 4, 49, 16, -8, 68, 5, -22, 87, -5, -35, + -44, 68, 63, -25, 57, 49, -6, 46, 35, 13, 36, 22, + 32, 25, 8, 51, 14, -4, 70, 4, -18, 89, -6, -31, + -42, 67, 67, -22, 56, 53, -3, 45, 39, 15, 35, 26, + 35, 24, 12, 54, 13, 0, 72, 2, -14, 92, -8, -27, + -39, 65, 71, -20, 54, 57, -1, 44, 43, 18, 33, 30, + 37, 22, 16, 56, 12, 3, 75, 1, -10, 94, -9, -23, + -37, 64, 75, -17, 53, 61, 1, 42, 47, 20, 32, 34, + 40, 21, 20, 58, 10, 7, 77, 0, -6, 97, -10, -19, + -34, 62, 79, -15, 52, 65, 4, 41, 52, 23, 30, 38, + 42, 19, 25, 61, 9, 11, 80, -1, -1, 99, -12, -15, + -32, 61, 83, -12, 50, 69, 7, 40, 56, 25, 29, 42, + 45, 18, 29, 63, 7, 15, 82, -2, 2, 102, -13, -11, + -29, 60, 87, -10, 49, 73, 9, 38, 60, 28, 28, 46, + 47, 17, 33, 66, 6, 19, 85, -4, 6, 104, -14, -7, + -27, 58, 91, -7, 47, 77, 11, 37, 64, 30, 26, 50, + 49, 15, 37, 68, 5, 23, 87, -5, 10, 106, -16, -3, + -24, 57, 96, -5, 46, 82, 14, 35, 68, 33, 25, 55, + 52, 14, 41, 71, 3, 28, 90, -6, 14, 109, -17, 1, + -22, 56, 100, -2, 45, 86, 16, 34, 72, 35, 23, 59, + 55, 12, 45, 73, 2, 32, 92, -8, 18, 111, -19, 5, + -19, 54, 104, 0, 43, 90, 19, 33, 76, 38, 22, 63, + 57, 11, 49, 76, 1, 36, 94, -9, 22, 114, -20, 9, + -95, 101, -24, -75, 90, -37, -57, 80, -51, -38, 69, -64, + -18, 58, -78, 0, 48, -91, 19, 37, -105, 39, 26, -119, + -92, 100, -20, -73, 89, -33, -54, 78, -47, -35, 68, -60, + -16, 57, -74, 3, 46, -87, 22, 36, -101, 41, 25, -115, + -90, 99, -16, -71, 88, -29, -52, 77, -43, -33, 66, -56, + -14, 55, -70, 5, 45, -83, 24, 34, -97, 43, 23, -111, + -87, 97, -11, -68, 86, -25, -49, 75, -38, -30, 65, -52, + -11, 54, -66, 8, 43, -79, 27, 33, -92, 46, 22, -106, + -85, 96, -7, -65, 85, -21, -47, 74, -34, -28, 63, -48, + -9, 53, -62, 10, 42, -75, 29, 31, -88, 48, 20, -102, + -82, 94, -3, -63, 83, -17, -44, 73, -30, -26, 62, -44, + -6, 51, -58, 13, 41, -71, 31, 30, -84, 51, 19, -98, + -80, 93, 0, -61, 82, -13, -42, 71, -26, -23, 61, -40, + -4, 50, -54, 15, 39, -67, 34, 29, -80, 53, 18, -94, + -77, 91, 4, -58, 80, -8, -39, 70, -22, -20, 59, -35, + -1, 48, -49, 18, 38, -62, 37, 27, -76, 56, 16, -90, + -75, 90, 8, -56, 79, -4, -37, 69, -18, -18, 58, -31, + 1, 47, -45, 20, 36, -58, 39, 26, -72, 58, 15, -86, + -73, 89, 12, -53, 78, 0, -34, 67, -14, -16, 57, -27, + 4, 46, -41, 23, 35, -54, 41, 24, -68, 61, 14, -82, + -70, 87, 16, -51, 76, 3, -32, 66, -10, -13, 55, -23, + 6, 44, -37, 25, 34, -50, 44, 23, -64, 63, 12, -78, + -68, 86, 20, -48, 75, 7, -30, 64, -6, -11, 54, -19, + 9, 43, -33, 27, 32, -46, 46, 22, -60, 65, 11, -74, + -65, 84, 25, -46, 74, 11, -27, 63, -1, -8, 52, -15, + 11, 41, -29, 30, 31, -42, 49, 20, -55, 68, 9, -69, + -63, 83, 29, -43, 72, 15, -25, 62, 2, -6, 51, -11, + 14, 40, -25, 32, 29, -38, 51, 19, -51, 71, 8, -65, + -60, 82, 33, -41, 71, 19, -22, 60, 6, -3, 50, -7, + 16, 39, -21, 35, 28, -34, 54, 18, -47, 73, 7, -61, + -58, 80, 37, -39, 70, 23, -20, 59, 10, -1, 48, -3, + 18, 37, -17, 37, 27, -30, 56, 16, -43, 75, 5, -57, + -55, 79, 41, -36, 68, 28, -17, 57, 14, 2, 47, 1, + 21, 36, -12, 40, 25, -25, 59, 15, -39, 78, 4, -53, + -53, 78, 45, -33, 67, 32, -15, 56, 18, 4, 45, 5, + 23, 35, -8, 42, 24, -21, 61, 13, -35, 80, 2, -49, + -50, 76, 49, -31, 65, 36, -12, 55, 22, 6, 44, 9, + 26, 33, -4, 45, 23, -17, 63, 12, -31, 83, 1, -45, + -48, 75, 53, -29, 64, 40, -10, 53, 26, 9, 43, 13, + 28, 32, 0, 47, 21, -13, 66, 11, -27, 85, 0, -41, + -45, 73, 58, -26, 62, 44, -7, 52, 31, 12, 41, 17, + 31, 30, 3, 50, 20, -9, 69, 9, -22, 88, -1, -36, + -43, 72, 62, -24, 61, 48, -5, 50, 35, 14, 40, 21, + 33, 29, 7, 52, 18, -5, 71, 8, -18, 90, -2, -32, + -41, 71, 66, -21, 60, 52, -2, 49, 39, 16, 39, 25, + 36, 28, 11, 55, 17, -1, 73, 6, -14, 93, -4, -28, + -38, 69, 70, -19, 58, 56, 0, 48, 43, 19, 37, 29, + 38, 26, 15, 57, 16, 2, 76, 5, -10, 95, -5, -24, + -36, 68, 74, -16, 57, 60, 2, 46, 47, 21, 36, 33, + 41, 25, 19, 59, 14, 6, 78, 4, -6, 97, -6, -20, + -33, 66, 78, -14, 56, 65, 5, 45, 51, 24, 34, 38, + 43, 23, 24, 62, 13, 11, 81, 2, -2, 100, -8, -16, + -31, 65, 82, -11, 54, 69, 7, 44, 55, 26, 33, 42, + 46, 22, 28, 64, 11, 15, 83, 1, 1, 103, -9, -12, + -28, 64, 86, -9, 53, 73, 10, 42, 59, 29, 32, 46, + 48, 21, 32, 67, 10, 19, 86, 0, 5, 105, -10, -8, + -26, 62, 90, -7, 51, 77, 12, 41, 63, 31, 30, 50, + 50, 19, 36, 69, 9, 23, 88, -1, 9, 107, -12, -4, + -23, 61, 95, -4, 50, 81, 15, 39, 68, 34, 29, 54, + 53, 18, 40, 72, 7, 27, 91, -2, 14, 110, -13, 0, + -21, 60, 99, -1, 49, 85, 17, 38, 72, 36, 27, 58, + 55, 16, 44, 74, 6, 31, 93, -4, 18, 112, -15, 4, + -18, 58, 103, 1, 47, 89, 20, 37, 76, 38, 26, 62, + 58, 15, 48, 77, 5, 35, 95, -5, 22, 115, -16, 8, + -94, 105, -24, -74, 94, -38, -56, 84, -51, -37, 73, -65, + -17, 62, -79, 1, 52, -92, 20, 41, -105, 39, 30, -119, + -91, 104, -20, -72, 93, -34, -53, 82, -47, -34, 72, -61, + -15, 61, -75, 4, 50, -88, 22, 40, -101, 42, 29, -115, + -89, 103, -16, -70, 92, -30, -51, 81, -43, -32, 70, -57, + -13, 59, -71, 6, 49, -84, 25, 38, -97, 44, 27, -111, + -86, 101, -12, -67, 90, -26, -48, 79, -39, -29, 69, -52, + -10, 58, -66, 9, 47, -80, 28, 37, -93, 47, 26, -107, + -84, 100, -8, -65, 89, -22, -46, 78, -35, -27, 67, -48, + -8, 57, -62, 11, 46, -76, 30, 35, -89, 49, 24, -103, + -82, 98, -4, -62, 87, -18, -43, 77, -31, -25, 66, -44, + -5, 55, -58, 14, 45, -72, 32, 34, -85, 52, 23, -99, + -79, 97, 0, -60, 86, -14, -41, 75, -27, -22, 65, -40, + -3, 54, -54, 16, 43, -68, 35, 33, -81, 54, 22, -95, + -76, 95, 4, -57, 84, -9, -38, 74, -22, -20, 63, -36, + 0, 52, -50, 19, 42, -63, 37, 31, -76, 57, 20, -90, + -74, 94, 8, -55, 83, -5, -36, 73, -18, -17, 62, -32, + 2, 51, -46, 21, 40, -59, 40, 30, -72, 59, 19, -86, + -72, 93, 12, -52, 82, -1, -34, 71, -14, -15, 61, -28, + 5, 50, -42, 23, 39, -55, 42, 28, -68, 62, 18, -82, + -69, 91, 16, -50, 80, 2, -31, 70, -10, -12, 59, -24, + 7, 48, -38, 26, 38, -51, 45, 27, -64, 64, 16, -78, + -67, 90, 20, -48, 79, 6, -29, 68, -6, -10, 58, -20, + 9, 47, -34, 28, 36, -47, 47, 26, -60, 66, 15, -74, + -64, 88, 24, -45, 78, 10, -26, 67, -2, -7, 56, -15, + 12, 45, -29, 31, 35, -43, 50, 24, -56, 69, 13, -70, + -62, 87, 28, -42, 76, 14, -24, 66, 1, -5, 55, -11, + 15, 44, -25, 33, 33, -39, 52, 23, -52, 71, 12, -66, + -59, 86, 32, -40, 75, 18, -21, 64, 5, -2, 54, -7, + 17, 43, -21, 36, 32, -35, 54, 22, -48, 74, 11, -62, + -57, 84, 36, -38, 74, 22, -19, 63, 9, 0, 52, -3, + 19, 41, -17, 38, 31, -31, 57, 20, -44, 76, 9, -58, + -54, 83, 41, -35, 72, 27, -16, 61, 14, 3, 51, 0, + 22, 40, -13, 41, 29, -26, 60, 19, -39, 79, 8, -53, + -52, 82, 45, -33, 71, 31, -14, 60, 18, 5, 49, 4, + 24, 39, -9, 43, 28, -22, 62, 17, -35, 81, 6, -49, + -50, 80, 49, -30, 69, 35, -11, 59, 22, 7, 48, 8, + 27, 37, -5, 46, 27, -18, 64, 16, -31, 84, 5, -45, + -47, 79, 53, -28, 68, 39, -9, 57, 26, 10, 47, 12, + 29, 36, -1, 48, 25, -14, 67, 15, -27, 86, 4, -41, + -44, 77, 57, -25, 66, 43, -6, 56, 30, 12, 45, 17, + 32, 34, 3, 51, 24, -10, 69, 13, -23, 89, 2, -37, + -42, 76, 61, -23, 65, 47, -4, 54, 34, 15, 44, 21, + 34, 33, 7, 53, 22, -6, 72, 12, -19, 91, 1, -33, + -40, 75, 65, -20, 64, 51, -2, 53, 38, 17, 43, 25, + 37, 32, 11, 55, 21, -2, 74, 10, -15, 94, 0, -29, + -37, 73, 69, -18, 62, 55, 1, 52, 42, 20, 41, 29, + 39, 30, 15, 58, 20, 1, 77, 9, -11, 96, -1, -25, + -35, 72, 73, -16, 61, 59, 3, 50, 46, 22, 40, 33, + 41, 29, 19, 60, 18, 5, 79, 8, -7, 98, -2, -21, + -32, 70, 78, -13, 60, 64, 6, 49, 51, 25, 38, 37, + 44, 27, 23, 63, 17, 10, 82, 6, -2, 101, -4, -16, + -30, 69, 82, -10, 58, 68, 8, 48, 55, 27, 37, 41, + 46, 26, 27, 65, 15, 14, 84, 5, 1, 103, -5, -12, + -27, 68, 86, -8, 57, 72, 11, 46, 59, 30, 36, 45, + 49, 25, 31, 68, 14, 18, 86, 3, 5, 106, -6, -8, + -25, 66, 90, -6, 55, 76, 13, 45, 63, 32, 34, 49, + 51, 23, 35, 70, 13, 22, 89, 2, 9, 108, -8, -4, + -22, 65, 94, -3, 54, 80, 16, 43, 67, 35, 33, 54, + 54, 22, 40, 73, 11, 26, 92, 1, 13, 111, -9, 0, + -20, 64, 98, -1, 53, 84, 18, 42, 71, 37, 31, 58, + 56, 20, 44, 75, 10, 30, 94, 0, 17, 113, -11, 3, + -18, 62, 102, 2, 51, 88, 21, 41, 75, 39, 30, 62, + 59, 19, 48, 78, 9, 34, 96, -1, 21, 116, -12, 7, + -93, 109, -25, -74, 98, -39, -55, 88, -52, -36, 77, -66, + -17, 66, -79, 2, 56, -93, 21, 45, -106, 40, 34, -120, + -90, 108, -21, -71, 97, -35, -52, 86, -48, -34, 76, -62, + -14, 65, -75, 5, 54, -89, 23, 44, -102, 43, 33, -116, + -88, 107, -17, -69, 96, -31, -50, 85, -44, -31, 74, -58, + -12, 63, -71, 7, 53, -85, 26, 42, -98, 45, 31, -112, + -85, 105, -12, -66, 94, -26, -47, 83, -40, -28, 73, -53, + -9, 62, -67, 10, 51, -80, 28, 41, -94, 48, 30, -107, + -83, 104, -8, -64, 93, -22, -45, 82, -36, -26, 71, -49, + -7, 61, -63, 12, 50, -76, 31, 39, -90, 50, 28, -103, + -81, 102, -4, -61, 91, -18, -42, 81, -32, -24, 70, -45, + -4, 59, -59, 14, 49, -72, 33, 38, -86, 53, 27, -99, + -78, 101, 0, -59, 90, -14, -40, 79, -28, -21, 69, -41, + -2, 58, -55, 17, 47, -68, 36, 37, -82, 55, 26, -95, + -76, 99, 3, -56, 88, -10, -37, 78, -23, -19, 67, -37, + 1, 56, -50, 20, 46, -64, 38, 35, -77, 58, 24, -91, + -73, 98, 7, -54, 87, -6, -35, 77, -19, -16, 66, -33, + 3, 55, -46, 22, 44, -60, 41, 34, -73, 60, 23, -87, + -71, 97, 11, -51, 86, -2, -33, 75, -15, -14, 65, -29, + 6, 54, -42, 24, 43, -56, 43, 32, -69, 62, 22, -83, + -68, 95, 15, -49, 84, 1, -30, 74, -11, -11, 63, -25, + 8, 52, -38, 27, 42, -52, 46, 31, -65, 65, 20, -79, + -66, 94, 19, -47, 83, 5, -28, 72, -7, -9, 62, -21, + 10, 51, -34, 29, 40, -48, 48, 30, -61, 67, 19, -75, + -63, 92, 24, -44, 82, 10, -25, 71, -3, -6, 60, -16, + 13, 49, -30, 32, 39, -43, 51, 28, -57, 70, 17, -70, + -61, 91, 28, -42, 80, 14, -23, 70, 0, -4, 59, -12, + 15, 48, -26, 34, 37, -39, 53, 27, -53, 72, 16, -66, + -59, 90, 32, -39, 79, 18, -20, 68, 4, -2, 58, -8, + 18, 47, -22, 37, 36, -35, 55, 26, -49, 75, 15, -62, + -56, 88, 36, -37, 78, 22, -18, 67, 8, 1, 56, -4, + 20, 45, -18, 39, 35, -31, 58, 24, -45, 77, 13, -58, + -53, 87, 40, -34, 76, 26, -15, 65, 13, 4, 55, 0, + 23, 44, -13, 42, 33, -27, 60, 23, -40, 80, 12, -54, + -51, 86, 44, -32, 75, 30, -13, 64, 17, 6, 53, 3, + 25, 43, -9, 44, 32, -23, 63, 21, -36, 82, 10, -50, + -49, 84, 48, -29, 73, 34, -10, 63, 21, 8, 52, 7, + 28, 41, -5, 46, 31, -19, 65, 20, -32, 85, 9, -46, + -46, 83, 52, -27, 72, 38, -8, 61, 25, 11, 51, 11, + 30, 40, -1, 49, 29, -15, 68, 19, -28, 87, 8, -42, + -44, 81, 57, -24, 70, 43, -5, 60, 29, 13, 49, 16, + 33, 38, 2, 52, 28, -10, 70, 17, -24, 90, 6, -37, + -41, 80, 61, -22, 69, 47, -3, 58, 33, 16, 48, 20, + 35, 37, 6, 54, 26, -6, 73, 16, -20, 92, 5, -33, + -39, 79, 65, -19, 68, 51, -1, 57, 37, 18, 47, 24, + 38, 36, 10, 56, 25, -2, 75, 14, -16, 94, 3, -29, + -36, 77, 69, -17, 66, 55, 2, 56, 41, 21, 45, 28, + 40, 34, 14, 59, 24, 1, 78, 13, -12, 97, 2, -25, + -34, 76, 73, -15, 65, 59, 4, 54, 45, 23, 44, 32, + 42, 33, 18, 61, 22, 5, 80, 12, -8, 99, 1, -21, + -31, 74, 77, -12, 64, 63, 7, 53, 50, 26, 42, 36, + 45, 31, 23, 64, 21, 9, 83, 10, -3, 102, 0, -17, + -29, 73, 81, -10, 62, 67, 9, 52, 54, 28, 41, 40, + 47, 30, 27, 66, 19, 13, 85, 9, 0, 104, -1, -13, + -27, 72, 85, -7, 61, 71, 12, 50, 58, 30, 40, 44, + 50, 29, 31, 69, 18, 17, 87, 7, 4, 107, -2, -9, + -24, 70, 89, -5, 59, 75, 14, 49, 62, 33, 38, 48, + 52, 27, 35, 71, 17, 21, 90, 6, 8, 109, -4, -5, + -21, 69, 94, -2, 58, 80, 17, 47, 66, 36, 37, 53, + 55, 26, 39, 74, 15, 26, 92, 5, 12, 112, -5, 0, + -19, 68, 98, 0, 57, 84, 19, 46, 70, 38, 35, 57, + 57, 24, 43, 76, 14, 30, 95, 3, 16, 114, -7, 3, + -17, 66, 102, 3, 55, 88, 22, 45, 74, 40, 34, 61, + 60, 23, 47, 78, 13, 34, 97, 2, 20, 117, -8, 7, + -92, 114, -26, -72, 103, -39, -54, 92, -53, -35, 82, -66, + -16, 71, -80, 3, 60, -93, 22, 49, -107, 41, 39, -121, + -89, 112, -22, -70, 101, -35, -51, 91, -49, -33, 80, -62, + -13, 69, -76, 6, 59, -89, 24, 48, -103, 44, 37, -117, + -87, 111, -18, -68, 100, -31, -49, 89, -45, -30, 79, -58, + -11, 68, -72, 8, 57, -85, 27, 47, -99, 46, 36, -113, + -84, 109, -13, -65, 99, -27, -46, 88, -40, -27, 77, -54, + -8, 66, -68, 11, 56, -81, 29, 45, -94, 49, 34, -108, + -82, 108, -9, -63, 97, -23, -44, 87, -36, -25, 76, -50, + -6, 65, -64, 13, 54, -77, 32, 44, -90, 51, 33, -104, + -80, 107, -5, -60, 96, -19, -41, 85, -32, -23, 75, -46, + -3, 64, -60, 15, 53, -73, 34, 43, -86, 54, 32, -100, + -77, 105, -1, -58, 95, -15, -39, 84, -28, -20, 73, -42, + -1, 62, -56, 18, 52, -69, 37, 41, -82, 56, 30, -96, + -75, 104, 2, -55, 93, -10, -36, 82, -24, -18, 72, -37, + 2, 61, -51, 21, 50, -64, 39, 40, -78, 59, 29, -92, + -72, 103, 6, -53, 92, -6, -34, 81, -20, -15, 70, -33, + 4, 59, -47, 23, 49, -60, 42, 38, -74, 61, 27, -88, + -70, 101, 10, -50, 90, -2, -32, 80, -16, -13, 69, -29, + 7, 58, -43, 25, 48, -56, 44, 37, -70, 64, 26, -84, + -67, 100, 14, -48, 89, 1, -29, 78, -12, -10, 68, -25, + 9, 57, -39, 28, 46, -52, 47, 36, -66, 66, 25, -80, + -65, 99, 18, -46, 88, 5, -27, 77, -8, -8, 66, -21, + 11, 55, -35, 30, 45, -48, 49, 34, -62, 68, 23, -76, + -62, 97, 23, -43, 86, 9, -24, 75, -3, -5, 65, -17, + 14, 54, -31, 33, 43, -44, 52, 33, -57, 71, 22, -71, + -60, 96, 27, -40, 85, 13, -22, 74, 0, -3, 64, -13, + 16, 53, -27, 35, 42, -40, 54, 31, -53, 73, 20, -67, + -57, 94, 31, -38, 83, 17, -19, 73, 4, -1, 62, -9, + 19, 51, -23, 38, 41, -36, 56, 30, -49, 76, 19, -63, + -55, 93, 35, -36, 82, 21, -17, 71, 8, 2, 61, -5, + 21, 50, -19, 40, 39, -32, 59, 29, -45, 78, 18, -59, + -52, 91, 39, -33, 80, 26, -14, 70, 12, 5, 59, 0, + 24, 48, -14, 43, 38, -27, 61, 27, -41, 81, 16, -55, + -50, 90, 43, -31, 79, 30, -12, 69, 16, 7, 58, 3, + 26, 47, -10, 45, 36, -23, 64, 26, -37, 83, 15, -51, + -48, 89, 47, -28, 78, 34, -9, 67, 20, 9, 57, 7, + 29, 46, -6, 47, 35, -19, 66, 24, -33, 86, 14, -47, + -45, 87, 51, -26, 76, 38, -7, 66, 24, 12, 55, 11, + 31, 44, -2, 50, 34, -15, 69, 23, -29, 88, 12, -43, + -43, 86, 56, -23, 75, 42, -4, 64, 29, 14, 54, 15, + 34, 43, 1, 53, 32, -11, 71, 22, -24, 91, 11, -38, + -40, 85, 60, -21, 74, 46, -2, 63, 33, 17, 52, 19, + 36, 41, 5, 55, 31, -7, 74, 20, -20, 93, 9, -34, + -38, 83, 64, -18, 72, 50, 0, 62, 37, 19, 51, 23, + 39, 40, 9, 57, 29, -3, 76, 19, -16, 96, 8, -30, + -35, 82, 68, -16, 71, 54, 3, 60, 41, 22, 50, 27, + 41, 39, 13, 60, 28, 0, 79, 18, -12, 98, 7, -26, + -33, 80, 72, -14, 70, 58, 5, 59, 45, 24, 48, 31, + 43, 37, 17, 62, 27, 4, 81, 16, -8, 100, 5, -22, + -30, 79, 76, -11, 68, 63, 8, 57, 49, 27, 47, 36, + 46, 36, 22, 65, 25, 9, 84, 15, -4, 103, 4, -18, + -28, 78, 80, -9, 67, 67, 10, 56, 53, 29, 45, 40, + 48, 35, 26, 67, 24, 13, 86, 13, 0, 105, 2, -14, + -25, 76, 84, -6, 65, 71, 13, 55, 57, 31, 44, 44, + 51, 33, 30, 70, 23, 17, 88, 12, 3, 108, 1, -10, + -23, 75, 88, -4, 64, 75, 15, 53, 61, 34, 43, 48, + 53, 32, 34, 72, 21, 21, 91, 11, 7, 110, 0, -6, + -20, 73, 93, -1, 62, 79, 18, 52, 66, 37, 41, 52, + 56, 30, 38, 75, 20, 25, 93, 9, 12, 113, -1, -1, + -18, 72, 97, 1, 61, 83, 20, 50, 70, 39, 40, 56, + 58, 29, 42, 77, 18, 29, 96, 8, 16, 115, -2, 2, + -16, 71, 101, 4, 60, 87, 23, 49, 74, 41, 39, 60, + 61, 28, 46, 79, 17, 33, 98, 6, 20, 118, -4, 6, + -91, 118, -26, -72, 107, -40, -53, 96, -53, -34, 86, -67, + -15, 75, -81, 4, 64, -94, 23, 53, -108, 42, 43, -121, + -89, 116, -22, -69, 105, -36, -50, 95, -49, -32, 84, -63, + -12, 73, -77, 7, 63, -90, 25, 52, -104, 45, 41, -117, + -86, 115, -18, -67, 104, -32, -48, 93, -45, -29, 83, -59, + -10, 72, -73, 9, 61, -86, 28, 51, -100, 47, 40, -113, + -83, 113, -14, -64, 103, -28, -45, 92, -41, -27, 81, -54, + -7, 70, -68, 12, 60, -82, 30, 49, -95, 50, 38, -109, + -81, 112, -10, -62, 101, -24, -43, 91, -37, -24, 80, -50, + -5, 69, -64, 14, 58, -78, 33, 48, -91, 52, 37, -105, + -79, 111, -6, -59, 100, -20, -41, 89, -33, -22, 79, -46, + -2, 68, -60, 16, 57, -74, 35, 47, -87, 55, 36, -101, + -76, 109, -2, -57, 99, -16, -38, 88, -29, -19, 77, -42, + 0, 66, -56, 19, 56, -70, 38, 45, -83, 57, 34, -97, + -74, 108, 2, -54, 97, -11, -35, 86, -24, -17, 76, -38, + 3, 65, -52, 21, 54, -65, 40, 44, -79, 60, 33, -92, + -71, 107, 6, -52, 96, -7, -33, 85, -20, -14, 74, -34, + 5, 63, -48, 24, 53, -61, 43, 42, -75, 62, 31, -88, + -69, 105, 10, -49, 94, -3, -31, 84, -16, -12, 73, -30, + 7, 62, -44, 26, 52, -57, 45, 41, -71, 64, 30, -84, + -66, 104, 14, -47, 93, 0, -28, 82, -12, -9, 72, -26, + 10, 61, -40, 29, 50, -53, 47, 40, -67, 67, 29, -80, + -64, 103, 18, -45, 92, 4, -26, 81, -8, -7, 70, -22, + 12, 59, -36, 31, 49, -49, 50, 38, -63, 69, 27, -76, + -61, 101, 22, -42, 90, 8, -23, 79, -4, -4, 69, -17, + 15, 58, -31, 34, 47, -45, 53, 37, -58, 72, 26, -72, + -59, 100, 26, -40, 89, 12, -21, 78, 0, -2, 68, -13, + 17, 57, -27, 36, 46, -41, 55, 35, -54, 74, 24, -68, + -57, 98, 30, -37, 87, 16, -18, 77, 3, 0, 66, -9, + 20, 55, -23, 39, 45, -37, 57, 34, -50, 77, 23, -64, + -54, 97, 34, -35, 86, 20, -16, 75, 7, 3, 65, -5, + 22, 54, -19, 41, 43, -33, 60, 33, -46, 79, 22, -60, + -51, 95, 39, -32, 84, 25, -13, 74, 12, 5, 63, -1, + 25, 52, -15, 44, 42, -28, 62, 31, -42, 82, 20, -55, + -49, 94, 43, -30, 83, 29, -11, 73, 16, 8, 62, 2, + 27, 51, -11, 46, 40, -24, 65, 30, -38, 84, 19, -51, + -47, 93, 47, -27, 82, 33, -9, 71, 20, 10, 61, 6, + 30, 50, -7, 48, 39, -20, 67, 28, -34, 87, 18, -47, + -44, 91, 51, -25, 80, 37, -6, 70, 24, 13, 59, 10, + 32, 48, -3, 51, 38, -16, 70, 27, -30, 89, 16, -43, + -42, 90, 55, -22, 79, 41, -3, 68, 28, 15, 58, 15, + 35, 47, 1, 53, 36, -12, 72, 26, -25, 92, 15, -39, + -39, 89, 59, -20, 78, 45, -1, 67, 32, 18, 56, 19, + 37, 45, 5, 56, 35, -8, 75, 24, -21, 94, 13, -35, + -37, 87, 63, -17, 76, 49, 1, 66, 36, 20, 55, 23, + 39, 44, 9, 58, 33, -4, 77, 23, -17, 96, 12, -31, + -34, 86, 67, -15, 75, 53, 4, 64, 40, 23, 54, 27, + 42, 43, 13, 61, 32, 0, 79, 22, -13, 99, 11, -27, + -32, 84, 71, -13, 74, 57, 6, 63, 44, 25, 52, 31, + 44, 41, 17, 63, 31, 3, 82, 20, -9, 101, 9, -23, + -29, 83, 76, -10, 72, 62, 9, 61, 49, 28, 51, 35, + 47, 40, 21, 66, 29, 8, 85, 19, -5, 104, 8, -18, + -27, 82, 80, -8, 71, 66, 11, 60, 53, 30, 49, 39, + 49, 39, 25, 68, 28, 12, 87, 17, -1, 106, 6, -14, + -25, 80, 84, -5, 69, 70, 14, 59, 57, 32, 48, 43, + 52, 37, 29, 71, 27, 16, 89, 16, 2, 109, 5, -10, + -22, 79, 88, -3, 68, 74, 16, 57, 61, 35, 47, 47, + 54, 36, 33, 73, 25, 20, 92, 15, 6, 111, 4, -6, + -19, 77, 92, 0, 66, 78, 19, 56, 65, 37, 45, 52, + 57, 34, 38, 76, 24, 24, 94, 13, 11, 114, 2, -2, + -17, 76, 96, 2, 65, 82, 21, 54, 69, 40, 44, 56, + 59, 33, 42, 78, 22, 28, 97, 12, 15, 116, 1, 1, + -15, 75, 100, 5, 64, 86, 23, 53, 73, 42, 43, 60, + 62, 32, 46, 80, 21, 32, 99, 10, 19, 119, 0, 5, + -90, 122, -27, -71, 111, -41, -52, 100, -54, -33, 90, -68, + -14, 79, -81, 5, 68, -95, 24, 57, -108, 43, 47, -122, + -88, 120, -23, -68, 109, -37, -49, 99, -50, -31, 88, -64, + -11, 77, -77, 7, 67, -91, 26, 56, -104, 46, 45, -118, + -85, 119, -19, -66, 108, -33, -47, 97, -46, -28, 87, -60, + -9, 76, -73, 10, 65, -87, 29, 55, -100, 48, 44, -114, + -83, 117, -14, -63, 107, -28, -44, 96, -42, -26, 85, -55, + -6, 74, -69, 13, 64, -82, 31, 53, -96, 51, 42, -109, + -80, 116, -10, -61, 105, -24, -42, 95, -38, -23, 84, -51, + -4, 73, -65, 15, 62, -78, 34, 52, -92, 53, 41, -105, + -78, 115, -6, -58, 104, -20, -40, 93, -34, -21, 83, -47, + -1, 72, -61, 17, 61, -74, 36, 51, -88, 55, 40, -101, + -75, 113, -2, -56, 103, -16, -37, 92, -30, -18, 81, -43, + 1, 70, -57, 20, 60, -70, 38, 49, -84, 58, 38, -97, + -73, 112, 1, -53, 101, -12, -35, 90, -25, -16, 80, -39, + 4, 69, -52, 22, 58, -66, 41, 48, -79, 61, 37, -93, + -70, 111, 5, -51, 100, -8, -32, 89, -21, -13, 78, -35, + 6, 67, -48, 25, 57, -62, 44, 46, -75, 63, 35, -89, + -68, 109, 9, -49, 98, -4, -30, 88, -17, -11, 77, -31, + 8, 66, -44, 27, 56, -58, 46, 45, -71, 65, 34, -85, + -66, 108, 13, -46, 97, 0, -27, 86, -13, -9, 76, -27, + 11, 65, -40, 30, 54, -54, 48, 44, -67, 68, 33, -81, + -63, 107, 17, -44, 96, 3, -25, 85, -9, -6, 74, -23, + 13, 63, -36, 32, 53, -50, 51, 42, -63, 70, 31, -77, + -60, 105, 22, -41, 94, 8, -22, 83, -5, -3, 73, -18, + 16, 62, -32, 35, 51, -45, 53, 41, -59, 73, 30, -72, + -58, 104, 26, -39, 93, 12, -20, 82, -1, -1, 72, -14, + 18, 61, -28, 37, 50, -41, 56, 39, -55, 75, 28, -68, + -56, 102, 30, -36, 91, 16, -17, 81, 2, 1, 70, -10, + 21, 59, -24, 39, 49, -37, 58, 38, -51, 78, 27, -64, + -53, 101, 34, -34, 90, 20, -15, 79, 6, 4, 69, -6, + 23, 58, -20, 42, 47, -33, 61, 37, -47, 80, 26, -60, + -51, 99, 38, -31, 88, 24, -12, 78, 11, 6, 67, -2, + 26, 56, -15, 45, 46, -29, 63, 35, -42, 83, 24, -56, + -48, 98, 42, -29, 87, 28, -10, 77, 15, 9, 66, 1, + 28, 55, -11, 47, 44, -25, 66, 34, -38, 85, 23, -52, + -46, 97, 46, -26, 86, 32, -8, 75, 19, 11, 65, 5, + 31, 54, -7, 49, 43, -21, 68, 32, -34, 87, 22, -48, + -43, 95, 50, -24, 84, 36, -5, 74, 23, 14, 63, 9, + 33, 52, -3, 52, 42, -17, 70, 31, -30, 90, 20, -44, + -41, 94, 55, -21, 83, 41, -3, 72, 27, 16, 62, 14, + 36, 51, 0, 54, 40, -12, 73, 30, -26, 93, 19, -39, + -38, 93, 59, -19, 82, 45, 0, 71, 31, 19, 60, 18, + 38, 49, 4, 57, 39, -8, 76, 28, -22, 95, 17, -35, + -36, 91, 63, -17, 80, 49, 2, 70, 35, 21, 59, 22, + 40, 48, 8, 59, 37, -4, 78, 27, -18, 97, 16, -31, + -34, 90, 67, -14, 79, 53, 5, 68, 39, 23, 58, 26, + 43, 47, 12, 62, 36, 0, 80, 26, -14, 100, 15, -27, + -31, 88, 71, -12, 78, 57, 7, 67, 43, 26, 56, 30, + 45, 45, 16, 64, 35, 3, 83, 24, -10, 102, 13, -23, + -28, 87, 75, -9, 76, 61, 10, 65, 48, 28, 55, 34, + 48, 44, 21, 67, 33, 7, 85, 23, -5, 105, 12, -19, + -26, 86, 79, -7, 75, 65, 12, 64, 52, 31, 53, 38, + 50, 43, 25, 69, 32, 11, 88, 21, -1, 107, 10, -15, + -24, 84, 83, -4, 73, 69, 14, 63, 56, 33, 52, 42, + 53, 41, 29, 71, 31, 15, 90, 20, 2, 110, 9, -11, + -21, 83, 87, -2, 72, 73, 17, 61, 60, 36, 51, 46, + 55, 40, 33, 74, 29, 19, 93, 19, 6, 112, 8, -7, + -19, 81, 92, 1, 70, 78, 20, 60, 64, 38, 49, 51, + 58, 38, 37, 77, 28, 24, 95, 17, 10, 115, 6, -2, + -16, 80, 96, 3, 69, 82, 22, 58, 68, 41, 48, 55, + 60, 37, 41, 79, 26, 28, 98, 16, 14, 117, 5, 1, + -14, 79, 100, 6, 68, 86, 24, 57, 72, 43, 47, 59, + 63, 36, 45, 81, 25, 32, 100, 14, 18, 119, 3, 5, + -117, -6, -8, -97, -17, -22, -79, -28, -35, -60, -38, -48, + -40, -49, -62, -22, -60, -76, -2, -71, -90, 16, -81, -103, + -114, -7, -4, -95, -18, -18, -76, -29, -31, -57, -40, -44, + -38, -51, -58, -19, -61, -72, 0, -72, -86, 19, -83, -99, + -112, -9, 0, -93, -20, -14, -74, -30, -27, -55, -41, -40, + -36, -52, -54, -17, -62, -68, 2, -73, -82, 21, -84, -95, + -109, -10, 4, -90, -21, -9, -71, -32, -23, -52, -42, -36, + -33, -53, -50, -14, -64, -63, 5, -75, -77, 24, -86, -90, + -107, -12, 8, -88, -23, -5, -69, -33, -19, -50, -44, -32, + -31, -55, -46, -12, -65, -59, 8, -76, -73, 26, -87, -86, + -105, -13, 12, -85, -24, -1, -66, -35, -15, -48, -45, -28, + -28, -56, -42, -9, -67, -55, 10, -78, -69, 29, -88, -82, + -102, -14, 16, -83, -25, 2, -64, -36, -11, -45, -47, -24, + -26, -57, -38, -7, -68, -51, 12, -79, -65, 31, -90, -78, + -99, -16, 20, -80, -27, 6, -61, -37, -6, -42, -48, -19, + -23, -59, -33, -4, -70, -47, 15, -81, -61, 34, -91, -74, + -97, -17, 24, -78, -28, 10, -59, -39, -2, -40, -49, -15, + -21, -60, -29, -2, -71, -43, 17, -82, -57, 36, -92, -70, + -95, -19, 28, -75, -30, 14, -56, -40, 1, -38, -51, -11, + -18, -62, -25, 0, -72, -39, 20, -83, -53, 39, -94, -66, + -92, -20, 32, -73, -31, 18, -54, -41, 5, -35, -52, -7, + -16, -63, -21, 3, -74, -35, 22, -85, -49, 41, -95, -62, + -90, -21, 36, -70, -32, 22, -52, -43, 9, -33, -53, -3, + -14, -64, -17, 5, -75, -31, 25, -86, -45, 43, -97, -58, + -87, -23, 41, -68, -34, 27, -49, -44, 13, -30, -55, 0, + -11, -66, -13, 8, -76, -26, 27, -87, -40, 46, -98, -53, + -85, -24, 45, -65, -35, 31, -47, -46, 17, -28, -56, 4, + -8, -67, -9, 10, -78, -22, 30, -89, -36, 48, -99, -49, + -82, -26, 49, -63, -36, 35, -44, -47, 21, -25, -58, 8, + -6, -69, -5, 13, -79, -18, 32, -90, -32, 51, -101, -45, + -80, -27, 53, -61, -38, 39, -42, -48, 25, -23, -59, 12, + -4, -70, -1, 15, -81, -14, 34, -91, -28, 53, -102, -41, + -77, -28, 57, -58, -39, 43, -39, -50, 30, -20, -61, 17, + -1, -71, 3, 18, -82, -10, 37, -93, -24, 56, -104, -37, + -75, -30, 61, -56, -41, 47, -37, -51, 34, -18, -62, 21, + 1, -73, 7, 20, -83, -6, 40, -94, -20, 58, -105, -33, + -73, -31, 65, -53, -42, 51, -34, -53, 38, -16, -63, 25, + 4, -74, 11, 23, -85, -2, 42, -96, -16, 61, -106, -29, + -70, -32, 69, -51, -43, 55, -32, -54, 42, -13, -65, 29, + 6, -76, 15, 25, -86, 1, 44, -97, -12, 63, -108, -25, + -67, -34, 74, -48, -45, 60, -29, -55, 46, -10, -66, 33, + 9, -77, 19, 28, -88, 6, 47, -99, -7, 66, -109, -20, + -65, -35, 78, -46, -46, 64, -27, -57, 50, -8, -67, 37, + 11, -78, 23, 30, -89, 10, 49, -100, -3, 68, -111, -16, + -63, -37, 82, -43, -48, 68, -24, -58, 54, -6, -69, 41, + 14, -80, 27, 32, -90, 14, 52, -101, 0, 71, -112, -12, + -60, -38, 86, -41, -49, 72, -22, -60, 58, -3, -70, 45, + 16, -81, 31, 35, -92, 18, 54, -103, 4, 73, -113, -8, + -58, -39, 90, -38, -50, 76, -20, -61, 62, -1, -71, 49, + 18, -82, 35, 37, -93, 22, 57, -104, 8, 75, -115, -4, + -55, -41, 94, -36, -52, 80, -17, -62, 67, 2, -73, 54, + 21, -84, 40, 40, -95, 26, 59, -105, 12, 78, -116, 0, + -53, -42, 98, -33, -53, 84, -15, -64, 71, 4, -74, 58, + 24, -85, 44, 42, -96, 30, 62, -107, 16, 80, -117, 3, + -50, -44, 102, -31, -55, 88, -12, -65, 75, 7, -76, 62, + 26, -87, 48, 45, -97, 34, 64, -108, 20, 83, -119, 7, + -48, -45, 106, -29, -56, 92, -10, -66, 79, 9, -77, 66, + 28, -88, 52, 47, -99, 38, 66, -110, 24, 85, -120, 11, + -45, -46, 111, -26, -57, 97, -7, -68, 83, 12, -79, 70, + 31, -90, 56, 50, -100, 43, 69, -111, 29, 88, -122, 16, + -43, -48, 115, -24, -59, 101, -5, -69, 87, 14, -80, 74, + 33, -91, 60, 52, -101, 47, 72, -112, 33, 90, -123, 20, + -41, -49, 119, -21, -60, 105, -2, -71, 91, 16, -81, 78, + 36, -92, 64, 55, -103, 51, 74, -114, 37, 93, -124, 24, + -116, -2, -9, -96, -13, -22, -78, -24, -36, -59, -34, -49, + -40, -45, -63, -21, -56, -76, -1, -67, -90, 17, -77, -104, + -113, -3, -5, -94, -14, -18, -75, -25, -32, -57, -36, -45, + -37, -47, -59, -18, -57, -72, 1, -68, -86, 20, -79, -100, + -111, -5, -1, -92, -16, -14, -73, -26, -28, -54, -37, -41, + -35, -48, -55, -16, -58, -68, 3, -69, -82, 22, -80, -96, + -108, -6, 3, -89, -17, -10, -70, -28, -23, -51, -38, -37, + -32, -49, -50, -13, -60, -64, 6, -71, -78, 25, -82, -91, + -106, -8, 7, -87, -19, -6, -68, -29, -19, -49, -40, -33, + -30, -51, -46, -11, -61, -60, 8, -72, -74, 27, -83, -87, + -104, -9, 11, -84, -20, -2, -65, -31, -15, -47, -41, -29, + -27, -52, -42, -8, -63, -56, 11, -74, -70, 30, -84, -83, + -101, -10, 15, -82, -21, 1, -63, -32, -11, -44, -43, -25, + -25, -53, -38, -6, -64, -52, 13, -75, -66, 32, -86, -79, + -99, -12, 19, -79, -23, 6, -60, -33, -7, -42, -44, -20, + -22, -55, -34, -3, -66, -47, 16, -77, -61, 35, -87, -75, + -96, -13, 23, -77, -24, 10, -58, -35, -3, -39, -45, -16, + -20, -56, -30, -1, -67, -43, 18, -78, -57, 37, -88, -71, + -94, -15, 27, -74, -26, 14, -56, -36, 0, -37, -47, -12, + -17, -58, -26, 1, -68, -39, 21, -79, -53, 40, -90, -67, + -91, -16, 31, -72, -27, 18, -53, -37, 4, -34, -48, -8, + -15, -59, -22, 4, -70, -35, 23, -81, -49, 42, -91, -63, + -89, -17, 35, -70, -28, 22, -51, -39, 8, -32, -49, -4, + -13, -60, -18, 6, -71, -31, 26, -82, -45, 44, -93, -59, + -86, -19, 40, -67, -30, 26, -48, -40, 13, -29, -51, 0, + -10, -62, -13, 9, -72, -27, 28, -83, -41, 47, -94, -54, + -84, -20, 44, -64, -31, 30, -46, -42, 17, -27, -52, 3, + -8, -63, -9, 11, -74, -23, 31, -85, -37, 49, -95, -50, + -81, -22, 48, -62, -32, 34, -43, -43, 21, -25, -54, 7, + -5, -65, -5, 14, -75, -19, 33, -86, -33, 52, -97, -46, + -79, -23, 52, -60, -34, 38, -41, -44, 25, -22, -55, 11, + -3, -66, -1, 16, -77, -15, 35, -87, -29, 54, -98, -42, + -76, -24, 56, -57, -35, 43, -38, -46, 29, -19, -57, 16, + 0, -67, 2, 19, -78, -10, 38, -89, -24, 57, -100, -38, + -74, -26, 60, -55, -37, 47, -36, -47, 33, -17, -58, 20, + 2, -69, 6, 21, -79, -6, 40, -90, -20, 59, -101, -34, + -72, -27, 64, -52, -38, 51, -33, -49, 37, -15, -59, 24, + 5, -70, 10, 23, -81, -2, 43, -92, -16, 62, -102, -30, + -69, -28, 68, -50, -39, 55, -31, -50, 41, -12, -61, 28, + 7, -72, 14, 26, -82, 1, 45, -93, -12, 64, -104, -26, + -67, -30, 73, -47, -41, 59, -28, -51, 46, -10, -62, 32, + 10, -73, 19, 29, -84, 5, 48, -95, -8, 67, -105, -21, + -64, -31, 77, -45, -42, 63, -26, -53, 50, -7, -63, 36, + 12, -74, 23, 31, -85, 9, 50, -96, -4, 69, -107, -17, + -62, -33, 81, -42, -44, 67, -24, -54, 54, -5, -65, 40, + 15, -76, 27, 33, -86, 13, 53, -97, 0, 72, -108, -13, + -59, -34, 85, -40, -45, 71, -21, -56, 58, -2, -66, 44, + 17, -77, 31, 36, -88, 17, 55, -99, 3, 74, -109, -9, + -57, -35, 89, -38, -46, 75, -19, -57, 62, 0, -67, 48, + 19, -78, 35, 38, -89, 21, 58, -100, 7, 76, -111, -5, + -54, -37, 93, -35, -48, 80, -16, -58, 66, 3, -69, 53, + 22, -80, 39, 41, -91, 26, 60, -101, 12, 79, -112, -1, + -52, -38, 97, -32, -49, 84, -14, -60, 70, 5, -70, 57, + 24, -81, 43, 43, -92, 30, 63, -103, 16, 81, -113, 2, + -49, -40, 101, -30, -51, 88, -11, -61, 74, 7, -72, 61, + 27, -83, 47, 46, -93, 34, 65, -104, 20, 84, -115, 6, + -47, -41, 105, -28, -52, 92, -9, -62, 78, 10, -73, 65, + 29, -84, 51, 48, -95, 38, 67, -106, 24, 86, -116, 10, + -44, -42, 110, -25, -53, 96, -6, -64, 83, 13, -75, 69, + 32, -86, 56, 51, -96, 42, 70, -107, 28, 89, -118, 15, + -42, -44, 114, -23, -55, 100, -4, -65, 87, 15, -76, 73, + 34, -87, 60, 53, -97, 46, 72, -108, 32, 91, -119, 19, + -40, -45, 118, -20, -56, 104, -1, -67, 91, 17, -77, 77, + 37, -88, 64, 55, -99, 50, 75, -110, 36, 94, -120, 23, + -115, 1, -9, -96, -9, -23, -77, -20, -36, -58, -30, -50, + -39, -41, -64, -20, -52, -77, 0, -63, -91, 18, -73, -104, + -113, 0, -5, -93, -10, -19, -74, -21, -32, -56, -32, -46, + -36, -43, -60, -17, -53, -73, 2, -64, -87, 21, -75, -100, + -110, -1, -1, -91, -12, -15, -72, -22, -28, -53, -33, -42, + -34, -44, -56, -15, -54, -69, 4, -65, -83, 23, -76, -96, + -107, -2, 2, -88, -13, -10, -69, -24, -24, -51, -34, -37, + -31, -45, -51, -12, -56, -65, 7, -67, -78, 26, -78, -92, + -105, -4, 6, -86, -15, -6, -67, -25, -20, -48, -36, -33, + -29, -47, -47, -10, -57, -61, 9, -68, -74, 28, -79, -88, + -103, -5, 10, -83, -16, -2, -65, -27, -16, -46, -37, -29, + -26, -48, -43, -8, -59, -57, 12, -70, -70, 31, -80, -84, + -100, -6, 14, -81, -17, 1, -62, -28, -12, -43, -39, -25, + -24, -49, -39, -5, -60, -53, 14, -71, -66, 33, -82, -80, + -98, -8, 19, -78, -19, 5, -59, -29, -7, -41, -40, -21, + -21, -51, -35, -3, -62, -48, 17, -73, -62, 36, -83, -75, + -95, -9, 23, -76, -20, 9, -57, -31, -3, -38, -41, -17, + -19, -52, -31, 0, -63, -44, 19, -74, -58, 38, -84, -71, + -93, -11, 27, -73, -22, 13, -55, -32, 0, -36, -43, -13, + -17, -54, -27, 2, -64, -40, 22, -75, -54, 40, -86, -67, + -90, -12, 31, -71, -23, 17, -52, -33, 4, -33, -44, -9, + -14, -55, -23, 5, -66, -36, 24, -77, -50, 43, -87, -63, + -88, -13, 35, -69, -24, 21, -50, -35, 8, -31, -45, -5, + -12, -56, -19, 7, -67, -32, 26, -78, -46, 45, -89, -59, + -85, -15, 39, -66, -26, 26, -47, -36, 12, -28, -47, 0, + -9, -58, -14, 10, -68, -28, 29, -79, -41, 48, -90, -55, + -83, -16, 43, -64, -27, 30, -45, -38, 16, -26, -48, 3, + -7, -59, -10, 12, -70, -24, 32, -81, -37, 50, -91, -51, + -81, -18, 47, -61, -28, 34, -42, -39, 20, -24, -50, 7, + -4, -61, -6, 15, -71, -20, 34, -82, -33, 53, -93, -47, + -78, -19, 51, -59, -30, 38, -40, -40, 24, -21, -51, 11, + -2, -62, -2, 17, -73, -16, 36, -83, -29, 55, -94, -43, + -75, -20, 56, -56, -31, 42, -37, -42, 29, -19, -53, 15, + 1, -63, 1, 20, -74, -11, 39, -85, -25, 58, -96, -38, + -73, -22, 60, -54, -33, 46, -35, -43, 33, -16, -54, 19, + 3, -65, 5, 22, -75, -7, 41, -86, -21, 60, -97, -34, + -71, -23, 64, -51, -34, 50, -33, -45, 37, -14, -55, 23, + 6, -66, 9, 24, -77, -3, 44, -88, -17, 63, -98, -30, + -68, -24, 68, -49, -35, 54, -30, -46, 41, -11, -57, 27, + 8, -68, 13, 27, -78, 0, 46, -89, -13, 65, -100, -26, + -66, -26, 72, -46, -37, 59, -27, -47, 45, -9, -58, 32, + 11, -69, 18, 29, -80, 4, 49, -91, -8, 68, -101, -22, + -63, -27, 76, -44, -38, 63, -25, -49, 49, -6, -59, 36, + 13, -70, 22, 32, -81, 8, 51, -92, -4, 70, -103, -18, + -61, -29, 80, -41, -40, 67, -23, -50, 53, -4, -61, 40, + 15, -72, 26, 34, -82, 12, 54, -93, 0, 72, -104, -14, + -58, -30, 84, -39, -41, 71, -20, -52, 57, -1, -62, 44, + 18, -73, 30, 37, -84, 16, 56, -95, 3, 75, -105, -10, + -56, -31, 88, -37, -42, 75, -18, -53, 61, 1, -63, 48, + 20, -74, 34, 39, -85, 20, 58, -96, 7, 77, -107, -6, + -53, -33, 93, -34, -44, 79, -15, -54, 66, 4, -65, 52, + 23, -76, 38, 42, -87, 25, 61, -97, 11, 80, -108, -1, + -51, -34, 97, -32, -45, 83, -13, -56, 70, 6, -66, 56, + 25, -77, 42, 44, -88, 29, 64, -99, 15, 82, -109, 2, + -49, -36, 101, -29, -47, 87, -10, -57, 74, 8, -68, 60, + 28, -79, 46, 47, -89, 33, 66, -100, 19, 85, -111, 6, + -46, -37, 105, -27, -48, 91, -8, -58, 78, 11, -69, 64, + 30, -80, 50, 49, -91, 37, 68, -102, 23, 87, -112, 10, + -43, -38, 109, -24, -49, 96, -5, -60, 82, 13, -71, 69, + 33, -82, 55, 52, -92, 41, 71, -103, 28, 90, -114, 14, + -41, -40, 113, -22, -51, 100, -3, -61, 86, 16, -72, 73, + 35, -83, 59, 54, -93, 45, 73, -104, 32, 92, -115, 18, + -39, -41, 117, -19, -52, 104, -1, -63, 90, 18, -73, 77, + 38, -84, 63, 56, -95, 49, 76, -106, 36, 95, -116, 22, + -114, 5, -10, -95, -5, -24, -76, -15, -37, -57, -26, -51, + -38, -37, -64, -19, -47, -78, 1, -58, -92, 19, -69, -105, + -112, 4, -6, -92, -6, -20, -73, -17, -33, -55, -27, -47, + -35, -38, -60, -16, -49, -74, 3, -60, -88, 22, -70, -101, + -109, 3, -2, -90, -7, -16, -71, -18, -29, -52, -28, -43, + -33, -39, -56, -14, -50, -70, 5, -61, -84, 24, -72, -97, + -106, 1, 2, -87, -9, -11, -68, -19, -25, -49, -30, -38, + -30, -41, -52, -11, -52, -65, 8, -62, -79, 27, -73, -92, + -104, 0, 6, -85, -10, -7, -66, -21, -21, -47, -31, -34, + -28, -42, -48, -9, -53, -61, 10, -64, -75, 29, -74, -88, + -102, -1, 10, -82, -11, -3, -63, -22, -17, -45, -33, -30, + -25, -44, -44, -7, -54, -57, 13, -65, -71, 32, -76, -84, + -99, -2, 14, -80, -13, 0, -61, -23, -13, -42, -34, -26, + -23, -45, -40, -4, -56, -53, 15, -66, -67, 34, -77, -80, + -97, -3, 18, -77, -14, 4, -58, -25, -8, -40, -36, -22, + -20, -46, -35, -1, -57, -49, 18, -68, -63, 37, -79, -76, + -94, -5, 22, -75, -16, 8, -56, -26, -4, -37, -37, -18, + -18, -48, -31, 1, -58, -45, 20, -69, -59, 39, -80, -72, + -92, -6, 26, -72, -17, 12, -54, -28, 0, -35, -38, -14, + -15, -49, -27, 3, -60, -41, 23, -71, -55, 41, -81, -68, + -89, -7, 30, -70, -18, 16, -51, -29, 3, -32, -40, -10, + -13, -51, -23, 6, -61, -37, 25, -72, -51, 44, -83, -64, + -87, -9, 34, -68, -20, 20, -49, -30, 7, -30, -41, -6, + -11, -52, -19, 8, -62, -33, 27, -73, -47, 46, -84, -60, + -84, -10, 39, -65, -21, 25, -46, -32, 11, -27, -42, -1, + -8, -53, -15, 11, -64, -28, 30, -75, -42, 49, -86, -55, + -82, -12, 43, -63, -23, 29, -44, -33, 15, -25, -44, 2, + -6, -55, -11, 13, -65, -24, 33, -76, -38, 51, -87, -51, + -80, -13, 47, -60, -24, 33, -41, -35, 19, -23, -45, 6, + -3, -56, -7, 16, -67, -20, 35, -78, -34, 54, -88, -47, + -77, -14, 51, -58, -25, 37, -39, -36, 23, -20, -47, 10, + -1, -57, -3, 18, -68, -16, 37, -79, -30, 56, -90, -43, + -74, -16, 55, -55, -27, 41, -36, -37, 28, -18, -48, 14, + 2, -59, 1, 21, -70, -12, 40, -80, -26, 59, -91, -39, + -72, -17, 59, -53, -28, 45, -34, -39, 32, -15, -49, 18, + 4, -60, 5, 23, -71, -8, 42, -82, -22, 61, -92, -35, + -70, -19, 63, -50, -30, 49, -32, -40, 36, -13, -51, 22, + 7, -62, 9, 25, -72, -4, 45, -83, -18, 64, -94, -31, + -67, -20, 67, -48, -31, 53, -29, -41, 40, -10, -52, 26, + 9, -63, 13, 28, -74, 0, 47, -85, -14, 66, -95, -27, + -65, -21, 72, -45, -32, 58, -26, -43, 44, -8, -54, 31, + 12, -65, 17, 31, -75, 4, 50, -86, -9, 69, -97, -22, + -62, -23, 76, -43, -34, 62, -24, -44, 48, -5, -55, 35, + 14, -66, 21, 33, -76, 8, 52, -87, -5, 71, -98, -18, + -60, -24, 80, -40, -35, 66, -22, -46, 52, -3, -56, 39, + 17, -67, 25, 35, -78, 12, 55, -89, -1, 73, -99, -14, + -57, -26, 84, -38, -36, 70, -19, -47, 56, 0, -58, 43, + 19, -69, 29, 38, -79, 16, 57, -90, 2, 76, -101, -10, + -55, -27, 88, -36, -38, 74, -17, -48, 60, 2, -59, 47, + 21, -70, 33, 40, -81, 20, 59, -91, 6, 78, -102, -6, + -52, -28, 92, -33, -39, 78, -14, -50, 65, 5, -61, 51, + 24, -71, 38, 43, -82, 24, 62, -93, 10, 81, -104, -2, + -50, -30, 96, -31, -41, 82, -12, -51, 69, 7, -62, 55, + 26, -73, 42, 45, -83, 28, 65, -94, 14, 83, -105, 1, + -48, -31, 100, -28, -42, 86, -9, -53, 73, 9, -63, 59, + 29, -74, 46, 48, -85, 32, 67, -96, 18, 86, -106, 5, + -45, -32, 104, -26, -43, 90, -7, -54, 77, 12, -65, 63, + 31, -75, 50, 50, -86, 36, 69, -97, 22, 88, -108, 9, + -42, -34, 109, -23, -45, 95, -4, -55, 81, 14, -66, 68, + 34, -77, 54, 53, -88, 41, 72, -99, 27, 91, -109, 14, + -40, -35, 113, -21, -46, 99, -2, -57, 85, 17, -67, 72, + 36, -78, 58, 55, -89, 45, 74, -100, 31, 93, -111, 18, + -38, -37, 117, -18, -48, 103, 0, -58, 89, 19, -69, 76, + 39, -80, 62, 57, -90, 49, 77, -101, 35, 96, -112, 22, + -113, 9, -11, -94, -1, -24, -75, -11, -38, -56, -22, -51, + -37, -33, -65, -18, -43, -78, 1, -54, -92, 20, -65, -106, + -111, 8, -7, -91, -2, -20, -72, -13, -34, -54, -23, -47, + -34, -34, -61, -16, -45, -74, 4, -56, -88, 23, -66, -102, + -108, 7, -3, -89, -3, -16, -70, -14, -30, -51, -24, -43, + -32, -35, -57, -13, -46, -70, 6, -57, -84, 25, -68, -98, + -106, 5, 1, -86, -5, -12, -67, -15, -25, -49, -26, -39, + -29, -37, -52, -10, -48, -66, 9, -58, -80, 28, -69, -93, + -103, 4, 5, -84, -6, -8, -65, -17, -21, -46, -27, -35, + -27, -38, -48, -8, -49, -62, 11, -60, -76, 30, -70, -89, + -101, 2, 9, -81, -7, -4, -63, -18, -17, -44, -29, -31, + -24, -40, -44, -6, -50, -58, 14, -61, -72, 33, -72, -85, + -98, 1, 13, -79, -9, 0, -60, -19, -13, -41, -30, -27, + -22, -41, -40, -3, -52, -54, 16, -62, -68, 35, -73, -81, + -96, 0, 17, -76, -10, 4, -58, -21, -9, -39, -32, -22, + -19, -42, -36, -1, -53, -49, 19, -64, -63, 38, -75, -77, + -93, -1, 21, -74, -12, 8, -55, -22, -5, -36, -33, -18, + -17, -44, -32, 2, -54, -45, 21, -65, -59, 40, -76, -73, + -91, -2, 25, -72, -13, 12, -53, -24, -1, -34, -34, -14, + -15, -45, -28, 4, -56, -41, 24, -67, -55, 42, -77, -69, + -88, -3, 29, -69, -14, 16, -50, -25, 2, -32, -36, -10, + -12, -47, -24, 7, -57, -37, 26, -68, -51, 45, -79, -65, + -86, -5, 33, -67, -16, 20, -48, -26, 6, -29, -37, -6, + -10, -48, -20, 9, -58, -33, 28, -69, -47, 47, -80, -61, + -83, -6, 38, -64, -17, 24, -45, -28, 11, -26, -38, -2, + -7, -49, -15, 12, -60, -29, 31, -71, -43, 50, -82, -56, + -81, -8, 42, -62, -19, 28, -43, -29, 15, -24, -40, 1, + -5, -51, -11, 14, -61, -25, 33, -72, -39, 52, -83, -52, + -79, -9, 46, -59, -20, 32, -40, -31, 19, -22, -41, 5, + -2, -52, -7, 16, -63, -21, 36, -74, -35, 55, -84, -48, + -76, -10, 50, -57, -21, 36, -38, -32, 23, -19, -43, 9, + 0, -53, -3, 19, -64, -17, 38, -75, -31, 57, -86, -44, + -74, -12, 54, -54, -23, 41, -35, -33, 27, -17, -44, 14, + 3, -55, 0, 22, -66, -12, 41, -76, -26, 60, -87, -40, + -71, -13, 58, -52, -24, 45, -33, -35, 31, -14, -45, 18, + 5, -56, 4, 24, -67, -8, 43, -78, -22, 62, -88, -36, + -69, -15, 62, -49, -26, 49, -31, -36, 35, -12, -47, 22, + 8, -58, 8, 26, -68, -4, 46, -79, -18, 65, -90, -32, + -66, -16, 66, -47, -27, 53, -28, -37, 39, -9, -48, 26, + 10, -59, 12, 29, -70, 0, 48, -81, -14, 67, -91, -28, + -64, -17, 71, -44, -28, 57, -26, -39, 44, -7, -50, 30, + 13, -61, 17, 31, -71, 3, 51, -82, -10, 70, -93, -23, + -61, -19, 75, -42, -30, 61, -23, -40, 48, -4, -51, 34, + 15, -62, 21, 34, -72, 7, 53, -83, -6, 72, -94, -19, + -59, -20, 79, -40, -31, 65, -21, -42, 52, -2, -52, 38, + 17, -63, 25, 36, -74, 11, 56, -85, -2, 74, -95, -15, + -56, -22, 83, -37, -32, 69, -18, -43, 56, 0, -54, 42, + 20, -65, 29, 39, -75, 15, 58, -86, 1, 77, -97, -11, + -54, -23, 87, -35, -34, 73, -16, -44, 60, 3, -55, 46, + 22, -66, 33, 41, -77, 19, 60, -87, 5, 79, -98, -7, + -51, -24, 91, -32, -35, 78, -13, -46, 64, 6, -57, 51, + 25, -67, 37, 44, -78, 24, 63, -89, 10, 82, -100, -3, + -49, -26, 95, -30, -37, 82, -11, -47, 68, 8, -58, 55, + 27, -69, 41, 46, -79, 28, 65, -90, 14, 84, -101, 0, + -47, -27, 99, -27, -38, 86, -8, -49, 72, 10, -59, 59, + 30, -70, 45, 48, -81, 32, 68, -92, 18, 87, -102, 4, + -44, -28, 103, -25, -39, 90, -6, -50, 76, 13, -61, 63, + 32, -71, 49, 51, -82, 36, 70, -93, 22, 89, -104, 8, + -42, -30, 108, -22, -41, 94, -3, -51, 81, 15, -62, 67, + 35, -73, 54, 54, -84, 40, 73, -95, 26, 92, -105, 13, + -39, -31, 112, -20, -42, 98, -1, -53, 85, 18, -63, 71, + 37, -74, 58, 56, -85, 44, 75, -96, 30, 94, -107, 17, + -37, -33, 116, -17, -44, 102, 1, -54, 89, 20, -65, 75, + 40, -76, 62, 58, -86, 48, 78, -97, 34, 96, -108, 21, + -112, 13, -11, -93, 2, -25, -74, -7, -38, -55, -18, -52, + -36, -29, -66, -17, -39, -79, 2, -50, -93, 21, -61, -106, + -110, 12, -7, -90, 1, -21, -72, -9, -34, -53, -19, -48, + -33, -30, -62, -15, -41, -75, 5, -52, -89, 24, -62, -102, + -107, 11, -3, -88, 0, -17, -69, -10, -30, -50, -20, -44, + -31, -31, -58, -12, -42, -71, 7, -53, -85, 26, -64, -98, + -105, 9, 0, -85, -1, -13, -66, -11, -26, -48, -22, -39, + -28, -33, -53, -10, -44, -67, 10, -54, -80, 29, -65, -94, + -102, 8, 4, -83, -2, -9, -64, -13, -22, -45, -23, -35, + -26, -34, -49, -7, -45, -63, 12, -56, -76, 31, -66, -90, + -100, 6, 8, -80, -3, -5, -62, -14, -18, -43, -25, -31, + -24, -36, -45, -5, -46, -59, 15, -57, -72, 33, -68, -86, + -97, 5, 12, -78, -5, -1, -59, -15, -14, -40, -26, -27, + -21, -37, -41, -2, -48, -55, 17, -58, -68, 36, -69, -82, + -95, 4, 17, -75, -6, 3, -57, -17, -9, -38, -28, -23, + -18, -38, -37, 0, -49, -50, 20, -60, -64, 39, -71, -77, + -92, 2, 21, -73, -8, 7, -54, -18, -5, -35, -29, -19, + -16, -40, -33, 3, -50, -46, 22, -61, -60, 41, -72, -73, + -90, 1, 25, -71, -9, 11, -52, -20, -1, -33, -30, -15, + -14, -41, -29, 5, -52, -42, 25, -63, -56, 43, -73, -69, + -88, 0, 29, -68, -10, 15, -49, -21, 2, -31, -32, -11, + -11, -43, -25, 8, -53, -38, 27, -64, -52, 46, -75, -65, + -85, -1, 33, -66, -12, 19, -47, -22, 6, -28, -33, -7, + -9, -44, -21, 10, -54, -34, 29, -65, -48, 48, -76, -61, + -82, -2, 37, -63, -13, 23, -44, -24, 10, -26, -34, -2, + -6, -45, -16, 13, -56, -30, 32, -67, -43, 51, -78, -57, + -80, -4, 41, -61, -15, 27, -42, -25, 14, -23, -36, 1, + -4, -47, -12, 15, -57, -26, 34, -68, -39, 53, -79, -53, + -78, -5, 45, -58, -16, 31, -40, -27, 18, -21, -37, 5, + -1, -48, -8, 17, -59, -22, 37, -70, -35, 56, -80, -49, + -75, -6, 49, -56, -17, 35, -37, -28, 22, -18, -39, 9, + 1, -49, -4, 20, -60, -18, 39, -71, -31, 58, -82, -45, + -73, -8, 54, -53, -19, 40, -34, -29, 27, -16, -40, 13, + 4, -51, 0, 22, -62, -13, 42, -72, -27, 61, -83, -40, + -70, -9, 58, -51, -20, 44, -32, -31, 31, -13, -41, 17, + 6, -52, 3, 25, -63, -9, 44, -74, -23, 63, -84, -36, + -68, -11, 62, -48, -22, 48, -30, -32, 35, -11, -43, 21, + 8, -54, 7, 27, -64, -5, 47, -75, -19, 65, -86, -32, + -65, -12, 66, -46, -23, 52, -27, -33, 39, -9, -44, 25, + 11, -55, 11, 30, -66, -1, 49, -77, -15, 68, -87, -28, + -63, -13, 70, -43, -24, 56, -25, -35, 43, -6, -46, 30, + 14, -57, 16, 32, -67, 2, 52, -78, -10, 70, -89, -24, + -60, -15, 74, -41, -26, 60, -22, -36, 47, -3, -47, 34, + 16, -58, 20, 35, -68, 6, 54, -79, -6, 73, -90, -20, + -58, -16, 78, -39, -27, 64, -20, -38, 51, -1, -48, 38, + 18, -59, 24, 37, -70, 10, 56, -81, -2, 75, -91, -16, + -56, -18, 82, -36, -28, 68, -17, -39, 55, 1, -50, 42, + 21, -61, 28, 40, -71, 14, 59, -82, 1, 78, -93, -12, + -53, -19, 86, -34, -30, 72, -15, -40, 59, 4, -51, 46, + 23, -62, 32, 42, -73, 18, 61, -83, 5, 80, -94, -8, + -50, -20, 91, -31, -31, 77, -12, -42, 64, 6, -53, 50, + 26, -63, 36, 45, -74, 23, 64, -85, 9, 83, -96, -3, + -48, -22, 95, -29, -33, 81, -10, -43, 68, 9, -54, 54, + 28, -65, 40, 47, -75, 27, 66, -86, 13, 85, -97, 0, + -46, -23, 99, -26, -34, 85, -8, -45, 72, 11, -55, 58, + 31, -66, 44, 49, -77, 31, 69, -88, 17, 88, -98, 4, + -43, -24, 103, -24, -35, 89, -5, -46, 76, 14, -57, 62, + 33, -67, 48, 52, -78, 35, 71, -89, 21, 90, -100, 8, + -41, -26, 107, -21, -37, 93, -2, -47, 80, 16, -58, 67, + 36, -69, 53, 54, -80, 39, 74, -91, 26, 93, -101, 12, + -38, -27, 111, -19, -38, 97, 0, -49, 84, 19, -59, 71, + 38, -70, 57, 57, -81, 43, 76, -92, 30, 95, -103, 16, + -36, -29, 115, -16, -40, 101, 2, -50, 88, 21, -61, 75, + 40, -72, 61, 59, -82, 47, 79, -93, 34, 97, -104, 20, + -111, 17, -12, -92, 6, -26, -73, -3, -39, -54, -14, -52, + -35, -25, -66, -16, -35, -80, 3, -46, -94, 22, -57, -107, + -109, 16, -8, -89, 5, -22, -71, -5, -35, -52, -15, -48, + -32, -26, -62, -14, -37, -76, 6, -48, -90, 24, -58, -103, + -106, 15, -4, -87, 4, -18, -68, -6, -31, -49, -16, -44, + -30, -27, -58, -11, -38, -72, 8, -49, -86, 27, -60, -99, + -104, 13, 0, -84, 2, -13, -66, -7, -27, -47, -18, -40, + -27, -29, -54, -9, -40, -67, 11, -50, -81, 30, -61, -94, + -101, 12, 4, -82, 1, -9, -63, -9, -23, -44, -19, -36, + -25, -30, -50, -6, -41, -63, 13, -52, -77, 32, -62, -90, + -99, 10, 8, -80, 0, -5, -61, -10, -19, -42, -21, -32, + -23, -32, -46, -4, -42, -59, 16, -53, -73, 34, -64, -86, + -97, 9, 12, -77, -1, -1, -58, -11, -15, -40, -22, -28, + -20, -33, -42, -1, -44, -55, 18, -54, -69, 37, -65, -82, + -94, 8, 16, -74, -2, 2, -56, -13, -10, -37, -24, -23, + -18, -34, -37, 1, -45, -51, 21, -56, -65, 39, -67, -78, + -91, 6, 20, -72, -4, 6, -53, -14, -6, -35, -25, -19, + -15, -36, -33, 4, -46, -47, 23, -57, -61, 42, -68, -74, + -89, 5, 24, -70, -5, 10, -51, -16, -2, -32, -26, -15, + -13, -37, -29, 6, -48, -43, 25, -59, -57, 44, -69, -70, + -87, 4, 28, -67, -6, 14, -49, -17, 1, -30, -28, -11, + -10, -39, -25, 8, -49, -39, 28, -60, -53, 47, -71, -66, + -84, 2, 32, -65, -8, 18, -46, -18, 5, -27, -29, -7, + -8, -40, -21, 11, -50, -35, 30, -61, -49, 49, -72, -62, + -82, 1, 37, -62, -9, 23, -43, -20, 9, -25, -30, -3, + -5, -41, -17, 14, -52, -30, 33, -63, -44, 52, -74, -57, + -79, 0, 41, -60, -11, 27, -41, -21, 13, -22, -32, 0, + -3, -43, -13, 16, -53, -26, 35, -64, -40, 54, -75, -53, + -77, -1, 45, -57, -12, 31, -39, -23, 17, -20, -33, 4, + 0, -44, -9, 18, -55, -22, 38, -66, -36, 56, -76, -49, + -74, -2, 49, -55, -13, 35, -36, -24, 21, -17, -35, 8, + 2, -45, -5, 21, -56, -18, 40, -67, -32, 59, -78, -45, + -72, -4, 53, -52, -15, 39, -34, -25, 26, -15, -36, 13, + 5, -47, 0, 23, -58, -14, 43, -68, -28, 62, -79, -41, + -69, -5, 57, -50, -16, 43, -31, -27, 30, -12, -37, 17, + 7, -48, 3, 26, -59, -10, 45, -70, -24, 64, -80, -37, + -67, -7, 61, -48, -18, 47, -29, -28, 34, -10, -39, 21, + 9, -50, 7, 28, -60, -6, 48, -71, -20, 66, -82, -33, + -65, -8, 65, -45, -19, 51, -26, -29, 38, -8, -40, 25, + 12, -51, 11, 31, -62, -2, 50, -73, -16, 69, -83, -29, + -62, -9, 70, -42, -20, 56, -24, -31, 42, -5, -42, 29, + 14, -53, 15, 33, -63, 2, 53, -74, -11, 71, -85, -24, + -59, -11, 74, -40, -22, 60, -21, -32, 46, -3, -43, 33, + 17, -54, 19, 36, -64, 6, 55, -75, -7, 74, -86, -20, + -57, -12, 78, -38, -23, 64, -19, -34, 50, 0, -44, 37, + 19, -55, 23, 38, -66, 10, 57, -77, -3, 76, -87, -16, + -55, -14, 82, -35, -24, 68, -17, -35, 54, 2, -46, 41, + 22, -57, 27, 40, -67, 14, 60, -78, 0, 79, -89, -12, + -52, -15, 86, -33, -26, 72, -14, -36, 58, 5, -47, 45, + 24, -58, 31, 43, -69, 18, 62, -79, 4, 81, -90, -8, + -50, -16, 90, -30, -27, 76, -11, -38, 63, 7, -49, 50, + 27, -59, 36, 46, -70, 22, 65, -81, 8, 84, -92, -4, + -47, -18, 94, -28, -29, 80, -9, -39, 67, 10, -50, 54, + 29, -61, 40, 48, -71, 26, 67, -82, 12, 86, -93, 0, + -45, -19, 98, -25, -30, 84, -7, -41, 71, 12, -51, 58, + 32, -62, 44, 50, -73, 30, 70, -84, 16, 88, -94, 3, + -42, -20, 102, -23, -31, 88, -4, -42, 75, 15, -53, 62, + 34, -63, 48, 53, -74, 34, 72, -85, 20, 91, -96, 7, + -40, -22, 107, -20, -33, 93, -2, -43, 79, 17, -54, 66, + 37, -65, 52, 55, -76, 39, 75, -87, 25, 94, -97, 12, + -37, -23, 111, -18, -34, 97, 1, -45, 83, 20, -55, 70, + 39, -66, 56, 58, -77, 43, 77, -88, 29, 96, -99, 16, + -35, -25, 115, -16, -36, 101, 3, -46, 87, 22, -57, 74, + 41, -68, 60, 60, -78, 47, 80, -89, 33, 98, -100, 20, + -110, 22, -13, -91, 11, -26, -72, 0, -40, -53, -9, -53, + -34, -20, -67, -15, -31, -80, 4, -42, -94, 23, -52, -108, + -108, 21, -9, -88, 10, -22, -70, 0, -36, -51, -11, -49, + -31, -22, -63, -13, -32, -76, 7, -43, -90, 25, -54, -104, + -105, 19, -5, -86, 8, -18, -67, -1, -32, -48, -12, -45, + -29, -23, -59, -10, -33, -72, 9, -44, -86, 28, -55, -100, + -103, 18, 0, -83, 7, -14, -65, -3, -27, -46, -13, -41, + -26, -24, -55, -8, -35, -68, 12, -46, -82, 31, -57, -95, + -100, 16, 3, -81, 5, -10, -62, -4, -23, -43, -15, -37, + -24, -26, -51, -5, -36, -64, 14, -47, -78, 33, -58, -91, + -98, 15, 7, -79, 4, -6, -60, -6, -19, -41, -16, -33, + -22, -27, -47, -3, -38, -60, 17, -49, -74, 35, -59, -87, + -95, 14, 11, -76, 3, -2, -57, -7, -15, -39, -18, -29, + -19, -28, -43, 0, -39, -56, 19, -50, -70, 38, -61, -83, + -93, 12, 15, -73, 1, 2, -55, -8, -11, -36, -19, -24, + -16, -30, -38, 2, -41, -51, 22, -52, -65, 40, -62, -79, + -90, 11, 19, -71, 0, 6, -52, -10, -7, -33, -20, -20, + -14, -31, -34, 5, -42, -47, 24, -53, -61, 43, -63, -75, + -88, 9, 23, -69, -1, 10, -50, -11, -3, -31, -22, -16, + -12, -33, -30, 7, -43, -43, 26, -54, -57, 45, -65, -71, + -86, 8, 27, -66, -2, 14, -47, -12, 0, -29, -23, -12, + -9, -34, -26, 9, -45, -39, 29, -56, -53, 48, -66, -67, + -83, 7, 31, -64, -3, 18, -45, -14, 4, -26, -24, -8, + -7, -35, -22, 12, -46, -35, 31, -57, -49, 50, -68, -63, + -81, 5, 36, -61, -5, 22, -42, -15, 9, -24, -26, -4, + -4, -37, -18, 15, -47, -31, 34, -58, -45, 53, -69, -58, + -78, 4, 40, -59, -6, 26, -40, -17, 13, -21, -27, 0, + -2, -38, -14, 17, -49, -27, 36, -60, -41, 55, -70, -54, + -76, 2, 44, -56, -7, 30, -38, -18, 17, -19, -29, 3, + 1, -40, -10, 19, -50, -23, 39, -61, -37, 57, -72, -50, + -73, 1, 48, -54, -9, 34, -35, -19, 21, -16, -30, 7, + 3, -41, -6, 22, -52, -19, 41, -62, -33, 60, -73, -46, + -71, 0, 52, -51, -10, 39, -33, -21, 25, -14, -32, 12, + 6, -42, -1, 24, -53, -14, 44, -64, -28, 63, -75, -42, + -68, -1, 56, -49, -12, 43, -30, -22, 29, -11, -33, 16, + 8, -44, 2, 27, -54, -10, 46, -65, -24, 65, -76, -38, + -66, -2, 60, -47, -13, 47, -28, -24, 33, -9, -34, 20, + 10, -45, 6, 29, -56, -6, 49, -67, -20, 67, -77, -34, + -64, -3, 64, -44, -14, 51, -25, -25, 37, -7, -36, 24, + 13, -47, 10, 32, -57, -2, 51, -68, -16, 70, -79, -30, + -61, -5, 69, -41, -16, 55, -23, -26, 42, -4, -37, 28, + 15, -48, 14, 34, -59, 1, 54, -70, -12, 72, -80, -25, + -58, -6, 73, -39, -17, 59, -20, -28, 46, -1, -38, 32, + 18, -49, 18, 37, -60, 5, 56, -71, -8, 75, -82, -21, + -56, -8, 77, -37, -19, 63, -18, -29, 50, 1, -40, 36, + 20, -51, 22, 39, -61, 9, 58, -72, -4, 77, -83, -17, + -54, -9, 81, -34, -20, 67, -15, -31, 54, 3, -41, 40, + 23, -52, 26, 41, -63, 13, 61, -74, 0, 80, -84, -13, + -51, -10, 85, -32, -21, 71, -13, -32, 58, 6, -42, 44, + 25, -53, 30, 44, -64, 17, 63, -75, 3, 82, -86, -9, + -49, -12, 89, -29, -23, 76, -10, -33, 62, 8, -44, 49, + 28, -55, 35, 47, -66, 22, 66, -76, 8, 85, -87, -5, + -46, -13, 93, -27, -24, 80, -8, -35, 66, 11, -45, 53, + 30, -56, 39, 49, -67, 26, 68, -78, 12, 87, -88, -1, + -44, -15, 97, -24, -26, 84, -6, -36, 70, 13, -47, 57, + 33, -58, 43, 51, -68, 30, 71, -79, 16, 89, -90, 2, + -41, -16, 101, -22, -27, 88, -3, -37, 74, 16, -48, 61, + 35, -59, 47, 54, -70, 34, 73, -81, 20, 92, -91, 6, + -39, -17, 106, -19, -28, 92, -1, -39, 79, 18, -50, 65, + 38, -61, 51, 56, -71, 38, 76, -82, 24, 95, -93, 11, + -36, -19, 110, -17, -30, 96, 2, -40, 83, 21, -51, 69, + 40, -62, 55, 59, -72, 42, 78, -83, 28, 97, -94, 15, + -34, -20, 114, -15, -31, 100, 4, -42, 87, 23, -52, 73, + 42, -63, 59, 61, -74, 46, 81, -85, 32, 99, -95, 19, + -109, 26, -13, -90, 15, -27, -71, 4, -40, -52, -5, -54, + -33, -16, -68, -14, -27, -81, 5, -38, -95, 24, -48, -108, + -107, 25, -9, -87, 14, -23, -69, 3, -36, -50, -7, -50, + -31, -18, -64, -12, -28, -77, 8, -39, -91, 26, -50, -104, + -104, 23, -5, -85, 12, -19, -66, 2, -32, -48, -8, -46, + -28, -19, -60, -9, -29, -73, 10, -40, -87, 29, -51, -100, + -102, 22, -1, -82, 11, -15, -64, 0, -28, -45, -9, -41, + -25, -20, -55, -7, -31, -69, 13, -42, -82, 31, -53, -96, + -99, 20, 2, -80, 9, -11, -61, 0, -24, -42, -11, -37, + -23, -22, -51, -4, -32, -65, 15, -43, -78, 34, -54, -92, + -97, 19, 6, -78, 8, -7, -59, -2, -20, -40, -12, -33, + -21, -23, -47, -2, -34, -61, 17, -45, -74, 36, -55, -88, + -95, 18, 10, -75, 7, -3, -56, -3, -16, -38, -14, -29, + -18, -24, -43, 1, -35, -57, 20, -46, -70, 39, -57, -84, + -92, 16, 15, -73, 5, 1, -54, -4, -11, -35, -15, -25, + -16, -26, -39, 3, -37, -52, 23, -48, -66, 41, -58, -79, + -90, 15, 19, -70, 4, 5, -51, -6, -7, -33, -16, -21, + -13, -27, -35, 6, -38, -48, 25, -49, -62, 44, -59, -75, + -87, 13, 23, -68, 2, 9, -49, -7, -3, -30, -18, -17, + -11, -29, -31, 8, -39, -44, 27, -50, -58, 46, -61, -71, + -85, 12, 27, -65, 1, 13, -47, -8, 0, -28, -19, -13, + -8, -30, -27, 10, -41, -40, 30, -52, -54, 49, -62, -67, + -82, 11, 31, -63, 0, 17, -44, -10, 4, -25, -20, -9, + -6, -31, -23, 13, -42, -36, 32, -53, -50, 51, -64, -63, + -80, 9, 35, -60, -1, 21, -41, -11, 8, -23, -22, -4, + -3, -33, -18, 15, -43, -32, 35, -54, -45, 54, -65, -59, + -77, 8, 39, -58, -2, 25, -39, -13, 12, -20, -23, 0, + -1, -34, -14, 18, -45, -28, 37, -56, -41, 56, -66, -55, + -75, 6, 43, -55, -3, 29, -37, -14, 16, -18, -25, 3, + 1, -36, -10, 20, -46, -24, 40, -57, -37, 58, -68, -51, + -72, 5, 47, -53, -5, 33, -34, -15, 20, -16, -26, 7, + 4, -37, -6, 23, -48, -20, 42, -58, -33, 61, -69, -47, + -70, 4, 52, -50, -6, 38, -32, -17, 25, -13, -28, 11, + 7, -38, -2, 25, -49, -15, 45, -60, -29, 63, -71, -42, + -67, 2, 56, -48, -8, 42, -29, -18, 29, -10, -29, 15, + 9, -40, 1, 28, -50, -11, 47, -61, -25, 66, -72, -38, + -65, 1, 60, -46, -9, 46, -27, -20, 33, -8, -30, 19, + 11, -41, 5, 30, -52, -7, 49, -63, -21, 68, -73, -34, + -63, 0, 64, -43, -10, 50, -24, -21, 37, -6, -32, 23, + 14, -43, 9, 33, -53, -3, 52, -64, -17, 71, -75, -30, + -60, -1, 68, -41, -12, 54, -22, -22, 41, -3, -33, 28, + 16, -44, 14, 35, -55, 0, 55, -66, -12, 73, -76, -26, + -58, -2, 72, -38, -13, 58, -19, -24, 45, -1, -34, 32, + 19, -45, 18, 38, -56, 4, 57, -67, -8, 76, -78, -22, + -55, -4, 76, -36, -15, 62, -17, -25, 49, 2, -36, 36, + 21, -47, 22, 40, -57, 8, 59, -68, -4, 78, -79, -18, + -53, -5, 80, -33, -16, 66, -15, -27, 53, 4, -37, 40, + 24, -48, 26, 42, -59, 12, 62, -70, 0, 81, -80, -14, + -50, -6, 84, -31, -17, 70, -12, -28, 57, 7, -38, 44, + 26, -49, 30, 45, -60, 16, 64, -71, 3, 83, -82, -10, + -48, -8, 89, -28, -19, 75, -9, -29, 62, 9, -40, 48, + 29, -51, 34, 47, -62, 21, 67, -72, 7, 86, -83, -5, + -45, -9, 93, -26, -20, 79, -7, -31, 66, 12, -41, 52, + 31, -52, 38, 50, -63, 25, 69, -74, 11, 88, -84, -1, + -43, -11, 97, -23, -22, 83, -5, -32, 70, 14, -43, 56, + 33, -54, 42, 52, -64, 29, 72, -75, 15, 90, -86, 2, + -40, -12, 101, -21, -23, 87, -2, -33, 74, 16, -44, 60, + 36, -55, 46, 55, -66, 33, 74, -77, 19, 93, -87, 6, + -38, -13, 105, -18, -24, 91, 0, -35, 78, 19, -46, 65, + 39, -57, 51, 57, -67, 37, 77, -78, 24, 95, -89, 10, + -35, -15, 109, -16, -26, 95, 3, -36, 82, 22, -47, 69, + 41, -58, 55, 60, -68, 41, 79, -79, 28, 98, -90, 14, + -33, -16, 113, -14, -27, 99, 5, -38, 86, 24, -48, 73, + 43, -59, 59, 62, -70, 45, 81, -81, 32, 100, -91, 18, + -108, 30, -14, -89, 19, -28, -70, 8, -41, -51, -1, -55, + -32, -12, -68, -13, -23, -82, 6, -34, -96, 25, -44, -109, + -106, 29, -10, -87, 18, -24, -68, 7, -37, -49, -3, -51, + -30, -14, -64, -11, -24, -78, 9, -35, -92, 27, -46, -105, + -104, 27, -6, -84, 16, -20, -65, 6, -33, -47, -4, -47, + -27, -15, -60, -8, -25, -74, 11, -36, -88, 30, -47, -101, + -101, 26, -1, -81, 15, -15, -63, 4, -29, -44, -5, -42, + -25, -16, -56, -6, -27, -69, 14, -38, -83, 32, -49, -96, + -98, 24, 2, -79, 13, -11, -60, 3, -25, -42, -7, -38, + -22, -18, -52, -3, -28, -65, 16, -39, -79, 35, -50, -92, + -96, 23, 6, -77, 12, -7, -58, 1, -21, -39, -8, -34, + -20, -19, -48, -1, -30, -61, 18, -41, -75, 37, -51, -88, + -94, 22, 10, -74, 11, -3, -56, 0, -17, -37, -10, -30, + -17, -20, -44, 1, -31, -57, 21, -42, -71, 40, -53, -84, + -91, 20, 14, -72, 9, 0, -53, 0, -12, -34, -11, -26, + -15, -22, -39, 4, -33, -53, 23, -44, -67, 42, -54, -80, + -89, 19, 18, -69, 8, 4, -50, -2, -8, -32, -12, -22, + -12, -23, -35, 7, -34, -49, 26, -45, -63, 45, -55, -76, + -86, 17, 22, -67, 6, 8, -48, -3, -4, -29, -14, -18, + -10, -25, -31, 9, -35, -45, 28, -46, -59, 47, -57, -72, + -84, 16, 26, -64, 5, 12, -46, -4, 0, -27, -15, -14, + -7, -26, -27, 11, -37, -41, 31, -48, -55, 49, -58, -68, + -81, 15, 30, -62, 4, 16, -43, -6, 3, -24, -16, -10, + -5, -27, -23, 14, -38, -37, 33, -49, -51, 52, -60, -64, + -79, 13, 35, -59, 2, 21, -41, -7, 7, -22, -18, -5, + -2, -29, -19, 16, -39, -32, 36, -50, -46, 55, -61, -59, + -76, 12, 39, -57, 1, 25, -38, -9, 11, -19, -19, -1, + 0, -30, -15, 19, -41, -28, 38, -52, -42, 57, -62, -55, + -74, 10, 43, -55, 0, 29, -36, -10, 15, -17, -21, 2, + 2, -32, -11, 21, -42, -24, 41, -53, -38, 59, -64, -51, + -72, 9, 47, -52, -1, 33, -33, -11, 19, -15, -22, 6, + 5, -33, -7, 24, -44, -20, 43, -54, -34, 62, -65, -47, + -69, 8, 51, -49, -2, 37, -31, -13, 24, -12, -24, 10, + 7, -34, -2, 26, -45, -16, 46, -56, -30, 64, -67, -43, + -66, 6, 55, -47, -4, 41, -28, -14, 28, -10, -25, 14, + 10, -36, 1, 29, -46, -12, 48, -57, -26, 67, -68, -39, + -64, 5, 59, -45, -5, 45, -26, -16, 32, -7, -26, 18, + 12, -37, 5, 31, -48, -8, 50, -59, -22, 69, -69, -35, + -62, 4, 63, -42, -6, 49, -24, -17, 36, -5, -28, 22, + 15, -39, 9, 33, -49, -4, 53, -60, -18, 72, -71, -31, + -59, 2, 68, -40, -8, 54, -21, -18, 40, -2, -29, 27, + 17, -40, 13, 36, -51, 0, 55, -62, -13, 74, -72, -26, + -57, 1, 72, -37, -9, 58, -18, -20, 44, 0, -30, 31, + 20, -41, 17, 38, -52, 4, 58, -63, -9, 77, -74, -22, + -54, 0, 76, -35, -11, 62, -16, -21, 48, 3, -32, 35, + 22, -43, 21, 41, -53, 8, 60, -64, -5, 79, -75, -18, + -52, -1, 80, -32, -12, 66, -14, -23, 52, 5, -33, 39, + 24, -44, 25, 43, -55, 12, 63, -66, -1, 81, -76, -14, + -49, -2, 84, -30, -13, 70, -11, -24, 56, 8, -34, 43, + 27, -45, 29, 46, -56, 16, 65, -67, 2, 84, -78, -10, + -47, -4, 88, -27, -15, 74, -9, -25, 61, 10, -36, 47, + 30, -47, 34, 48, -58, 20, 68, -68, 6, 87, -79, -6, + -44, -5, 92, -25, -16, 78, -6, -27, 65, 13, -37, 51, + 32, -48, 38, 51, -59, 24, 70, -70, 10, 89, -80, -2, + -42, -7, 96, -23, -18, 82, -4, -28, 69, 15, -39, 55, + 34, -50, 42, 53, -60, 28, 73, -71, 14, 91, -82, 1, + -40, -8, 100, -20, -19, 86, -1, -29, 73, 17, -40, 59, + 37, -51, 46, 56, -62, 32, 75, -73, 18, 94, -83, 5, + -37, -9, 105, -17, -20, 91, 1, -31, 77, 20, -42, 64, + 39, -53, 50, 58, -63, 37, 78, -74, 23, 96, -85, 10, + -34, -11, 109, -15, -22, 95, 4, -32, 81, 22, -43, 68, + 42, -54, 54, 61, -64, 41, 80, -75, 27, 99, -86, 14, + -32, -12, 113, -13, -23, 99, 6, -34, 85, 25, -44, 72, + 44, -55, 58, 63, -66, 45, 82, -77, 31, 101, -87, 18, + -107, 34, -15, -88, 23, -28, -69, 12, -42, -50, 2, -55, + -31, -8, -69, -12, -19, -82, 7, -30, -96, 26, -40, -110, + -105, 33, -11, -86, 22, -24, -67, 11, -38, -48, 0, -51, + -29, -10, -65, -10, -20, -78, 9, -31, -92, 28, -42, -106, + -103, 31, -7, -83, 20, -20, -64, 10, -34, -46, 0, -47, + -26, -11, -61, -8, -21, -74, 12, -32, -88, 31, -43, -102, + -100, 30, -2, -81, 19, -16, -62, 8, -29, -43, -1, -43, + -24, -12, -56, -5, -23, -70, 15, -34, -84, 33, -45, -97, + -98, 28, 1, -78, 17, -12, -59, 7, -25, -41, -3, -39, + -21, -14, -52, -2, -24, -66, 17, -35, -80, 36, -46, -93, + -95, 27, 5, -76, 16, -8, -57, 5, -21, -38, -4, -35, + -19, -15, -48, 0, -26, -62, 19, -37, -76, 38, -47, -89, + -93, 26, 9, -73, 15, -4, -55, 4, -17, -36, -6, -31, + -16, -16, -44, 2, -27, -58, 22, -38, -72, 40, -49, -85, + -90, 24, 13, -71, 13, 0, -52, 3, -13, -33, -7, -26, + -14, -18, -40, 5, -29, -53, 24, -40, -67, 43, -50, -81, + -88, 23, 17, -68, 12, 4, -50, 1, -9, -31, -8, -22, + -11, -19, -36, 7, -30, -49, 27, -41, -63, 46, -51, -77, + -85, 21, 21, -66, 10, 8, -47, 0, -5, -28, -10, -18, + -9, -21, -32, 10, -31, -45, 29, -42, -59, 48, -53, -73, + -83, 20, 25, -64, 9, 12, -45, 0, -1, -26, -11, -14, + -7, -22, -28, 12, -33, -41, 32, -44, -55, 50, -54, -69, + -81, 19, 29, -61, 8, 16, -42, -2, 2, -24, -12, -10, + -4, -23, -24, 15, -34, -37, 34, -45, -51, 53, -56, -65, + -78, 17, 34, -58, 6, 20, -40, -3, 7, -21, -14, -6, + -2, -25, -19, 17, -35, -33, 37, -46, -47, 55, -57, -60, + -75, 16, 38, -56, 5, 24, -37, -5, 11, -18, -15, -2, + 1, -26, -15, 20, -37, -29, 39, -48, -43, 58, -58, -56, + -73, 14, 42, -54, 4, 28, -35, -6, 15, -16, -17, 1, + 3, -28, -11, 22, -38, -25, 41, -49, -39, 60, -60, -52, + -71, 13, 46, -51, 2, 32, -32, -7, 19, -14, -18, 5, + 6, -29, -7, 24, -40, -21, 44, -50, -35, 63, -61, -48, + -68, 12, 50, -49, 1, 37, -30, -9, 23, -11, -20, 10, + 8, -30, -3, 27, -41, -16, 47, -52, -30, 65, -63, -44, + -66, 10, 54, -46, 0, 41, -27, -10, 27, -9, -21, 14, + 11, -32, 0, 30, -42, -12, 49, -53, -26, 68, -64, -40, + -63, 9, 58, -44, -1, 45, -25, -12, 31, -6, -22, 18, + 13, -33, 4, 32, -44, -8, 51, -55, -22, 70, -65, -36, + -61, 8, 62, -41, -2, 49, -23, -13, 35, -4, -24, 22, + 16, -35, 8, 34, -45, -4, 54, -56, -18, 72, -67, -32, + -58, 6, 67, -39, -4, 53, -20, -14, 40, -1, -25, 26, + 18, -36, 13, 37, -47, 0, 56, -58, -14, 75, -68, -27, + -56, 5, 71, -36, -5, 57, -18, -16, 44, 1, -26, 30, + 21, -37, 17, 39, -48, 3, 59, -59, -10, 78, -70, -23, + -53, 3, 75, -34, -7, 61, -15, -17, 48, 4, -28, 34, + 23, -39, 21, 42, -49, 7, 61, -60, -6, 80, -71, -19, + -51, 2, 79, -32, -8, 65, -13, -19, 52, 6, -29, 38, + 25, -40, 25, 44, -51, 11, 64, -62, -2, 82, -72, -15, + -49, 1, 83, -29, -9, 69, -10, -20, 56, 8, -30, 42, + 28, -41, 29, 47, -52, 15, 66, -63, 1, 85, -74, -11, + -46, 0, 87, -26, -11, 74, -8, -21, 60, 11, -32, 47, + 30, -43, 33, 49, -54, 20, 69, -64, 6, 87, -75, -7, + -43, -1, 91, -24, -12, 78, -5, -23, 64, 14, -33, 51, + 33, -44, 37, 52, -55, 24, 71, -66, 10, 90, -76, -3, + -41, -3, 95, -22, -14, 82, -3, -24, 68, 16, -35, 55, + 35, -46, 41, 54, -56, 28, 73, -67, 14, 92, -78, 0, + -39, -4, 99, -19, -15, 86, 0, -25, 72, 18, -36, 59, + 38, -47, 45, 56, -58, 32, 76, -69, 18, 95, -79, 4, + -36, -5, 104, -17, -16, 90, 2, -27, 77, 21, -38, 63, + 40, -49, 50, 59, -59, 36, 79, -70, 22, 97, -81, 9, + -34, -7, 108, -14, -18, 94, 5, -28, 81, 23, -39, 67, + 43, -50, 54, 62, -60, 40, 81, -71, 26, 100, -82, 13, + -31, -8, 112, -12, -19, 98, 7, -30, 85, 26, -40, 71, + 45, -51, 58, 64, -62, 44, 83, -73, 30, 102, -83, 17, + -106, 38, -15, -87, 27, -29, -68, 16, -42, -50, 6, -56, + -30, -4, -70, -11, -15, -83, 8, -26, -97, 27, -36, -110, + -104, 37, -11, -85, 26, -25, -66, 15, -38, -47, 4, -52, + -28, -6, -66, -9, -16, -79, 10, -27, -93, 29, -38, -106, + -102, 35, -7, -82, 24, -21, -64, 14, -34, -45, 3, -48, + -25, -7, -62, -7, -17, -75, 13, -28, -89, 32, -39, -102, + -99, 34, -3, -80, 23, -17, -61, 12, -30, -42, 2, -43, + -23, -8, -57, -4, -19, -71, 15, -30, -84, 34, -41, -98, + -97, 32, 0, -77, 21, -13, -58, 11, -26, -40, 0, -39, + -20, -10, -53, -2, -20, -67, 18, -31, -80, 37, -42, -94, + -94, 31, 4, -75, 20, -9, -56, 9, -22, -37, 0, -35, + -18, -11, -49, 1, -22, -63, 20, -33, -76, 39, -43, -90, + -92, 30, 8, -72, 19, -5, -54, 8, -18, -35, -2, -31, + -16, -12, -45, 3, -23, -59, 23, -34, -72, 41, -45, -86, + -89, 28, 13, -70, 17, 0, -51, 7, -13, -32, -3, -27, + -13, -14, -41, 6, -25, -54, 25, -36, -68, 44, -46, -81, + -87, 27, 17, -67, 16, 3, -49, 5, -9, -30, -4, -23, + -10, -15, -37, 8, -26, -50, 28, -37, -64, 46, -47, -77, + -84, 25, 21, -65, 14, 7, -46, 4, -5, -27, -6, -19, + -8, -17, -33, 11, -27, -46, 30, -38, -60, 49, -49, -73, + -82, 24, 25, -63, 13, 11, -44, 3, -1, -25, -7, -15, + -6, -18, -29, 13, -29, -42, 32, -40, -56, 51, -50, -69, + -80, 23, 29, -60, 12, 15, -41, 1, 2, -23, -8, -11, + -3, -19, -25, 16, -30, -38, 35, -41, -52, 54, -52, -65, + -77, 21, 33, -58, 10, 19, -39, 0, 6, -20, -10, -6, + -1, -21, -20, 18, -31, -34, 38, -42, -47, 56, -53, -61, + -75, 20, 37, -55, 9, 23, -36, -1, 10, -18, -11, -2, + 2, -22, -16, 21, -33, -30, 40, -44, -43, 59, -54, -57, + -72, 18, 41, -53, 8, 27, -34, -2, 14, -15, -13, 1, + 4, -24, -12, 23, -34, -26, 42, -45, -39, 61, -56, -53, + -70, 17, 45, -50, 6, 31, -32, -3, 18, -13, -14, 5, + 7, -25, -8, 25, -36, -22, 45, -46, -35, 64, -57, -49, + -67, 16, 50, -48, 5, 36, -29, -5, 23, -10, -16, 9, + 9, -26, -4, 28, -37, -17, 47, -48, -31, 66, -59, -44, + -65, 14, 54, -45, 3, 40, -26, -6, 27, -8, -17, 13, + 12, -28, 0, 30, -38, -13, 50, -49, -27, 69, -60, -40, + -62, 13, 58, -43, 2, 44, -24, -8, 31, -5, -18, 17, + 14, -29, 3, 33, -40, -9, 52, -51, -23, 71, -61, -36, + -60, 12, 62, -40, 1, 48, -22, -9, 35, -3, -20, 21, + 16, -31, 7, 35, -41, -5, 55, -52, -19, 73, -63, -32, + -57, 10, 66, -38, 0, 52, -19, -10, 39, 0, -21, 26, + 19, -32, 12, 38, -43, -1, 57, -54, -14, 76, -64, -28, + -55, 9, 70, -35, -1, 56, -17, -12, 43, 2, -22, 30, + 22, -33, 16, 40, -44, 2, 60, -55, -10, 78, -66, -24, + -52, 7, 74, -33, -3, 60, -14, -13, 47, 5, -24, 34, + 24, -35, 20, 43, -45, 6, 62, -56, -6, 81, -67, -20, + -50, 6, 78, -31, -4, 64, -12, -15, 51, 7, -25, 38, + 26, -36, 24, 45, -47, 10, 64, -58, -2, 83, -68, -16, + -48, 5, 82, -28, -5, 68, -9, -16, 55, 9, -26, 42, + 29, -37, 28, 47, -48, 14, 67, -59, 1, 86, -70, -12, + -45, 3, 87, -26, -7, 73, -7, -17, 60, 12, -28, 46, + 31, -39, 32, 50, -50, 19, 70, -60, 5, 88, -71, -7, + -43, 2, 91, -23, -8, 77, -4, -19, 64, 14, -29, 50, + 34, -40, 36, 53, -51, 23, 72, -62, 9, 91, -72, -3, + -40, 0, 95, -21, -10, 81, -2, -20, 68, 17, -31, 54, + 36, -42, 40, 55, -52, 27, 74, -63, 13, 93, -74, 0, + -38, 0, 99, -18, -11, 85, 0, -21, 72, 19, -32, 58, + 39, -43, 44, 57, -54, 31, 77, -65, 17, 96, -75, 4, + -35, -1, 103, -16, -12, 89, 3, -23, 76, 22, -34, 63, + 41, -45, 49, 60, -55, 35, 79, -66, 22, 98, -77, 8, + -33, -3, 107, -13, -14, 93, 6, -24, 80, 24, -35, 67, + 44, -46, 53, 62, -56, 39, 82, -67, 26, 101, -78, 12, + -30, -4, 111, -11, -15, 97, 8, -26, 84, 27, -36, 71, + 46, -47, 57, 65, -58, 43, 84, -69, 30, 103, -79, 16, + -105, 42, -16, -86, 31, -30, -67, 21, -43, -49, 10, -57, + -29, 0, -70, -10, -10, -84, 9, -21, -98, 28, -32, -111, + -103, 41, -12, -84, 30, -26, -65, 19, -39, -46, 9, -53, + -27, -1, -66, -8, -12, -80, 11, -23, -94, 30, -33, -107, + -101, 40, -8, -81, 29, -22, -63, 18, -35, -44, 8, -49, + -24, -2, -62, -6, -13, -76, 14, -24, -90, 33, -35, -103, + -98, 38, -3, -79, 27, -17, -60, 17, -31, -41, 6, -44, + -22, -4, -58, -3, -15, -71, 16, -25, -85, 35, -36, -98, + -96, 37, 0, -76, 26, -13, -57, 15, -27, -39, 5, -40, + -19, -5, -54, -1, -16, -67, 19, -27, -81, 38, -37, -94, + -93, 35, 4, -74, 25, -9, -55, 14, -23, -36, 3, -36, + -17, -7, -50, 2, -17, -63, 21, -28, -77, 40, -39, -90, + -91, 34, 8, -71, 23, -5, -53, 13, -19, -34, 2, -32, + -15, -8, -46, 4, -19, -59, 24, -29, -73, 42, -40, -86, + -88, 33, 12, -69, 22, -1, -50, 11, -14, -31, 0, -28, + -12, -9, -41, 7, -20, -55, 26, -31, -69, 45, -42, -82, + -86, 31, 16, -66, 20, 2, -48, 10, -10, -29, 0, -24, + -9, -11, -37, 9, -21, -51, 29, -32, -65, 48, -43, -78, + -83, 30, 20, -64, 19, 6, -45, 8, -6, -26, -1, -20, + -7, -12, -33, 12, -23, -47, 31, -34, -61, 50, -44, -74, + -81, 29, 24, -62, 18, 10, -43, 7, -2, -24, -3, -16, + -5, -14, -29, 14, -24, -43, 34, -35, -57, 52, -46, -70, + -79, 27, 28, -59, 16, 14, -40, 6, 1, -22, -4, -12, + -2, -15, -25, 17, -25, -39, 36, -36, -53, 55, -47, -66, + -76, 26, 33, -57, 15, 19, -38, 4, 5, -19, -5, -7, + 0, -16, -21, 19, -27, -34, 39, -38, -48, 57, -49, -61, + -73, 24, 37, -54, 13, 23, -35, 3, 9, -17, -7, -3, + 3, -18, -17, 22, -28, -30, 41, -39, -44, 60, -50, -57, + -71, 23, 41, -52, 12, 27, -33, 1, 13, -14, -8, 0, + 5, -19, -13, 24, -30, -26, 43, -41, -40, 62, -51, -53, + -69, 22, 45, -49, 11, 31, -31, 0, 17, -12, -10, 4, + 8, -20, -9, 26, -31, -22, 46, -42, -36, 65, -53, -49, + -66, 20, 49, -47, 9, 35, -28, 0, 22, -9, -11, 8, + 10, -22, -4, 29, -33, -18, 48, -43, -32, 67, -54, -45, + -64, 19, 53, -44, 8, 39, -25, -2, 26, -7, -12, 12, + 13, -23, 0, 31, -34, -14, 51, -45, -28, 70, -55, -41, + -61, 17, 57, -42, 6, 43, -23, -3, 30, -4, -14, 16, + 15, -25, 3, 34, -35, -10, 53, -46, -24, 72, -57, -37, + -59, 16, 61, -39, 5, 47, -21, -4, 34, -2, -15, 20, + 17, -26, 7, 36, -37, -6, 56, -48, -20, 74, -58, -33, + -56, 15, 66, -37, 4, 52, -18, -6, 38, 1, -17, 25, + 20, -28, 11, 39, -38, -1, 58, -49, -15, 77, -60, -28, + -54, 13, 70, -34, 2, 56, -16, -7, 42, 3, -18, 29, + 23, -29, 15, 41, -39, 2, 61, -50, -11, 80, -61, -24, + -51, 12, 74, -32, 1, 60, -13, -9, 46, 6, -19, 33, + 25, -30, 19, 44, -41, 6, 63, -52, -7, 82, -62, -20, + -49, 10, 78, -30, 0, 64, -11, -10, 50, 8, -21, 37, + 27, -32, 23, 46, -42, 10, 66, -53, -3, 84, -64, -16, + -47, 9, 82, -27, -1, 68, -8, -11, 54, 10, -22, 41, + 30, -33, 27, 49, -44, 14, 68, -54, 0, 87, -65, -12, + -44, 8, 86, -25, -2, 72, -6, -13, 59, 13, -24, 45, + 32, -34, 32, 51, -45, 18, 71, -56, 4, 89, -67, -8, + -41, 6, 90, -22, -4, 76, -3, -14, 63, 15, -25, 49, + 35, -36, 36, 54, -46, 22, 73, -57, 8, 92, -68, -4, + -39, 5, 94, -20, -5, 80, -1, -16, 67, 18, -26, 53, + 37, -37, 40, 56, -48, 26, 75, -59, 12, 94, -69, 0, + -37, 4, 98, -17, -6, 84, 1, -17, 71, 20, -28, 57, + 40, -38, 44, 58, -49, 30, 78, -60, 16, 97, -71, 3, + -34, 2, 103, -15, -8, 89, 4, -18, 75, 23, -29, 62, + 42, -40, 48, 61, -51, 35, 80, -62, 21, 99, -72, 8, + -32, 1, 107, -12, -9, 93, 7, -20, 79, 25, -30, 66, + 45, -41, 52, 63, -52, 39, 83, -63, 25, 102, -74, 12, + -29, 0, 111, -10, -11, 97, 9, -21, 83, 28, -32, 70, + 47, -43, 56, 66, -53, 43, 85, -64, 29, 104, -75, 16, + -105, 46, -17, -85, 35, -30, -66, 25, -44, -48, 14, -57, + -28, 3, -71, -9, -6, -84, 10, -17, -98, 29, -28, -112, + -102, 45, -13, -83, 34, -26, -64, 23, -40, -45, 13, -53, + -26, 2, -67, -7, -8, -80, 12, -19, -94, 31, -29, -108, + -100, 44, -9, -80, 33, -22, -62, 22, -36, -43, 12, -49, + -23, 1, -63, -5, -9, -76, 15, -20, -90, 33, -31, -104, + -97, 42, -4, -78, 31, -18, -59, 21, -31, -40, 10, -45, + -21, 0, -59, -2, -11, -72, 17, -21, -86, 36, -32, -99, + -95, 41, 0, -75, 30, -14, -57, 19, -27, -38, 9, -41, + -18, -1, -55, 0, -12, -68, 20, -23, -82, 39, -33, -95, + -92, 39, 3, -73, 29, -10, -54, 18, -23, -35, 7, -37, + -16, -3, -51, 3, -13, -64, 22, -24, -78, 41, -35, -91, + -90, 38, 7, -71, 27, -6, -52, 17, -19, -33, 6, -33, + -14, -4, -47, 5, -15, -60, 25, -25, -74, 43, -36, -87, + -87, 37, 11, -68, 26, -1, -49, 15, -15, -30, 4, -28, + -11, -5, -42, 8, -16, -55, 27, -27, -69, 46, -38, -83, + -85, 35, 15, -65, 24, 2, -47, 14, -11, -28, 3, -24, + -9, -7, -38, 10, -17, -51, 30, -28, -65, 48, -39, -79, + -82, 34, 19, -63, 23, 6, -44, 12, -7, -25, 2, -20, + -6, -8, -34, 13, -19, -47, 32, -30, -61, 51, -40, -75, + -80, 33, 23, -61, 22, 10, -42, 11, -3, -23, 0, -16, + -4, -10, -30, 15, -20, -43, 34, -31, -57, 53, -42, -71, + -78, 31, 27, -58, 20, 14, -39, 10, 0, -21, 0, -12, + -1, -11, -26, 17, -21, -39, 37, -32, -53, 56, -43, -67, + -75, 30, 32, -56, 19, 18, -37, 8, 5, -18, -1, -8, + 1, -12, -22, 20, -23, -35, 40, -34, -49, 58, -45, -62, + -73, 28, 36, -53, 17, 22, -34, 7, 9, -16, -3, -4, + 4, -14, -18, 23, -24, -31, 42, -35, -45, 61, -46, -58, + -70, 27, 40, -51, 16, 26, -32, 5, 13, -13, -4, 0, + 6, -15, -14, 25, -26, -27, 44, -37, -41, 63, -47, -54, + -68, 26, 44, -48, 15, 30, -30, 4, 17, -11, -6, 3, + 9, -16, -10, 27, -27, -23, 47, -38, -37, 65, -49, -50, + -65, 24, 48, -46, 13, 35, -27, 3, 21, -8, -7, 8, + 11, -18, -5, 30, -29, -18, 49, -39, -32, 68, -50, -46, + -63, 23, 52, -43, 12, 39, -25, 1, 25, -6, -8, 12, + 14, -19, -1, 32, -30, -14, 52, -41, -28, 71, -51, -42, + -60, 21, 56, -41, 10, 43, -22, 0, 29, -3, -10, 16, + 16, -21, 2, 35, -31, -10, 54, -42, -24, 73, -53, -38, + -58, 20, 60, -39, 9, 47, -20, 0, 33, -1, -11, 20, + 18, -22, 6, 37, -33, -6, 57, -44, -20, 75, -54, -34, + -55, 19, 65, -36, 8, 51, -17, -2, 38, 2, -13, 24, + 21, -24, 10, 40, -34, -2, 59, -45, -16, 78, -56, -29, + -53, 17, 69, -33, 6, 55, -15, -3, 42, 4, -14, 28, + 23, -25, 14, 42, -35, 1, 62, -46, -12, 80, -57, -25, + -50, 16, 73, -31, 5, 59, -12, -5, 46, 6, -15, 32, + 26, -26, 18, 45, -37, 5, 64, -48, -8, 83, -58, -21, + -48, 14, 77, -29, 4, 63, -10, -6, 50, 9, -17, 36, + 28, -28, 22, 47, -38, 9, 66, -49, -4, 85, -60, -17, + -46, 13, 81, -26, 2, 67, -8, -7, 54, 11, -18, 40, + 31, -29, 26, 49, -40, 13, 69, -50, 0, 88, -61, -13, + -43, 12, 85, -24, 1, 72, -5, -9, 58, 14, -20, 45, + 33, -30, 31, 52, -41, 18, 71, -52, 4, 90, -63, -9, + -41, 10, 89, -21, 0, 76, -2, -10, 62, 16, -21, 49, + 36, -32, 35, 55, -42, 22, 74, -53, 8, 93, -64, -5, + -38, 9, 93, -19, -1, 80, 0, -12, 66, 19, -22, 53, + 38, -33, 39, 57, -44, 26, 76, -55, 12, 95, -65, -1, + -36, 8, 97, -16, -2, 84, 2, -13, 70, 21, -24, 57, + 41, -34, 43, 59, -45, 30, 79, -56, 16, 97, -67, 2, + -33, 6, 102, -14, -4, 88, 5, -14, 75, 24, -25, 61, + 43, -36, 47, 62, -47, 34, 81, -58, 20, 100, -68, 7, + -31, 5, 106, -11, -5, 92, 7, -16, 79, 26, -26, 65, + 46, -37, 51, 64, -48, 38, 84, -59, 24, 103, -70, 11, + -28, 3, 110, -9, -7, 96, 10, -17, 83, 29, -28, 69, + 48, -39, 55, 67, -49, 42, 86, -60, 28, 105, -71, 15, + -104, 50, -17, -84, 39, -31, -65, 29, -44, -47, 18, -58, + -27, 7, -72, -9, -2, -85, 11, -13, -99, 30, -24, -112, + -101, 49, -13, -82, 38, -27, -63, 27, -40, -44, 17, -54, + -25, 6, -68, -6, -4, -81, 13, -15, -95, 32, -25, -108, + -99, 48, -9, -79, 37, -23, -61, 26, -36, -42, 16, -50, + -23, 5, -64, -4, -5, -77, 16, -16, -91, 34, -27, -104, + -96, 46, -5, -77, 35, -19, -58, 25, -32, -39, 14, -45, + -20, 3, -59, -1, -7, -73, 18, -17, -86, 37, -28, -100, + -94, 45, -1, -74, 34, -15, -56, 23, -28, -37, 13, -41, + -17, 2, -55, 1, -8, -69, 21, -19, -82, 39, -29, -96, + -91, 43, 2, -72, 33, -11, -53, 22, -24, -34, 11, -37, + -15, 0, -51, 4, -9, -65, 23, -20, -78, 42, -31, -92, + -89, 42, 6, -70, 31, -7, -51, 21, -20, -32, 10, -33, + -13, 0, -47, 6, -11, -61, 25, -21, -74, 44, -32, -88, + -86, 41, 11, -67, 30, -2, -48, 19, -15, -29, 8, -29, + -10, -1, -43, 9, -12, -56, 28, -23, -70, 47, -34, -83, + -84, 39, 15, -65, 28, 1, -46, 18, -11, -27, 7, -25, + -8, -3, -39, 11, -13, -52, 31, -24, -66, 49, -35, -79, + -82, 38, 19, -62, 27, 5, -43, 16, -7, -25, 6, -21, + -5, -4, -35, 14, -15, -48, 33, -26, -62, 52, -36, -75, + -79, 37, 23, -60, 26, 9, -41, 15, -3, -22, 4, -17, + -3, -6, -31, 16, -16, -44, 35, -27, -58, 54, -38, -71, + -77, 35, 27, -57, 24, 13, -39, 14, 0, -20, 3, -13, + 0, -7, -27, 18, -17, -40, 38, -28, -54, 57, -39, -67, + -74, 34, 31, -55, 23, 17, -36, 12, 4, -17, 2, -8, + 2, -8, -22, 21, -19, -36, 40, -30, -49, 59, -41, -63, + -72, 32, 35, -52, 21, 21, -34, 11, 8, -15, 0, -4, + 5, -10, -18, 23, -20, -32, 43, -31, -45, 62, -42, -59, + -69, 31, 39, -50, 20, 25, -31, 9, 12, -12, 0, 0, + 7, -11, -14, 26, -22, -28, 45, -33, -41, 64, -43, -55, + -67, 30, 43, -48, 19, 29, -29, 8, 16, -10, -2, 3, + 9, -12, -10, 28, -23, -24, 48, -34, -37, 66, -45, -51, + -64, 28, 48, -45, 17, 34, -26, 7, 21, -7, -3, 7, + 12, -14, -6, 31, -25, -19, 50, -35, -33, 69, -46, -46, + -62, 27, 52, -42, 16, 38, -24, 5, 25, -5, -4, 11, + 15, -15, -2, 33, -26, -15, 53, -37, -29, 71, -47, -42, + -59, 25, 56, -40, 14, 42, -21, 4, 29, -2, -6, 15, + 17, -17, 1, 36, -27, -11, 55, -38, -25, 74, -49, -38, + -57, 24, 60, -38, 13, 46, -19, 3, 33, 0, -7, 19, + 19, -18, 5, 38, -29, -7, 57, -40, -21, 76, -50, -34, + -54, 23, 64, -35, 12, 50, -16, 1, 37, 3, -9, 24, + 22, -20, 10, 41, -30, -3, 60, -41, -16, 79, -52, -30, + -52, 21, 68, -33, 10, 54, -14, 0, 41, 5, -10, 28, + 24, -21, 14, 43, -31, 0, 63, -42, -12, 81, -53, -26, + -50, 20, 72, -30, 9, 58, -11, -1, 45, 7, -11, 32, + 27, -22, 18, 46, -33, 4, 65, -44, -8, 84, -54, -22, + -47, 18, 76, -28, 8, 62, -9, -2, 49, 10, -13, 36, + 29, -24, 22, 48, -34, 8, 67, -45, -4, 86, -56, -18, + -45, 17, 80, -25, 6, 66, -7, -3, 53, 12, -14, 40, + 32, -25, 26, 50, -36, 12, 70, -46, 0, 89, -57, -14, + -42, 16, 85, -23, 5, 71, -4, -5, 58, 15, -16, 44, + 34, -26, 30, 53, -37, 17, 72, -48, 3, 91, -59, -9, + -40, 14, 89, -20, 3, 75, -2, -6, 62, 17, -17, 48, + 37, -28, 34, 55, -38, 21, 75, -49, 7, 94, -60, -5, + -37, 13, 93, -18, 2, 79, 1, -8, 66, 20, -18, 52, + 39, -29, 38, 58, -40, 25, 77, -51, 11, 96, -61, -1, + -35, 12, 97, -16, 1, 83, 3, -9, 70, 22, -20, 56, + 41, -30, 42, 60, -41, 29, 80, -52, 15, 98, -63, 2, + -32, 10, 101, -13, 0, 87, 6, -10, 74, 25, -21, 61, + 44, -32, 47, 63, -43, 33, 82, -54, 20, 101, -64, 6, + -30, 9, 105, -10, -1, 91, 8, -12, 78, 27, -22, 65, + 47, -33, 51, 65, -44, 37, 85, -55, 24, 103, -66, 10, + -27, 7, 109, -8, -3, 95, 11, -13, 82, 30, -24, 69, + 49, -35, 55, 68, -45, 41, 87, -56, 28, 106, -67, 14, + -103, 54, -18, -83, 43, -32, -65, 33, -45, -46, 22, -58, + -26, 11, -72, -8, 1, -86, 12, -9, -100, 31, -20, -113, + -100, 53, -14, -81, 42, -28, -62, 31, -41, -43, 21, -54, + -24, 10, -68, -5, 0, -82, 14, -11, -96, 33, -21, -109, + -98, 52, -10, -79, 41, -24, -60, 30, -37, -41, 20, -50, + -22, 9, -64, -3, -1, -78, 17, -12, -92, 35, -23, -105, + -95, 50, -5, -76, 39, -19, -57, 29, -33, -38, 18, -46, + -19, 7, -60, 0, -3, -73, 19, -13, -87, 38, -24, -100, + -93, 49, -1, -74, 38, -15, -55, 27, -29, -36, 17, -42, + -17, 6, -56, 2, -4, -69, 22, -15, -83, 40, -25, -96, + -90, 47, 2, -71, 37, -11, -52, 26, -25, -34, 15, -38, + -14, 4, -52, 5, -5, -65, 24, -16, -79, 43, -27, -92, + -88, 46, 6, -69, 35, -7, -50, 25, -21, -31, 14, -34, + -12, 3, -48, 7, -7, -61, 26, -17, -75, 45, -28, -88, + -85, 45, 10, -66, 34, -3, -47, 23, -16, -28, 12, -29, + -9, 2, -43, 10, -8, -57, 29, -19, -71, 48, -30, -84, + -83, 43, 14, -64, 32, 0, -45, 22, -12, -26, 11, -25, + -7, 0, -39, 12, -9, -53, 31, -20, -67, 50, -31, -80, + -81, 42, 18, -61, 31, 4, -42, 20, -8, -24, 10, -21, + -4, 0, -35, 14, -11, -49, 34, -22, -63, 53, -32, -76, + -78, 41, 22, -59, 30, 8, -40, 19, -4, -21, 8, -17, + -2, -2, -31, 17, -12, -45, 36, -23, -59, 55, -34, -72, + -76, 39, 26, -56, 28, 12, -38, 18, 0, -19, 7, -13, + 0, -3, -27, 19, -13, -41, 39, -24, -55, 57, -35, -68, + -73, 38, 31, -54, 27, 17, -35, 16, 3, -16, 6, -9, + 3, -4, -23, 22, -15, -36, 41, -26, -50, 60, -37, -63, + -71, 36, 35, -51, 25, 21, -33, 15, 7, -14, 4, -5, + 6, -6, -19, 24, -16, -32, 44, -27, -46, 63, -38, -59, + -68, 35, 39, -49, 24, 25, -30, 13, 11, -11, 3, -1, + 8, -7, -15, 27, -18, -28, 46, -29, -42, 65, -39, -55, + -66, 34, 43, -47, 23, 29, -28, 12, 15, -9, 1, 2, + 10, -8, -11, 29, -19, -24, 49, -30, -38, 67, -41, -51, + -63, 32, 47, -44, 21, 33, -25, 11, 20, -6, 0, 7, + 13, -10, -6, 32, -21, -20, 51, -31, -34, 70, -42, -47, + -61, 31, 51, -42, 20, 37, -23, 9, 24, -4, 0, 11, + 15, -11, -2, 34, -22, -16, 54, -33, -30, 72, -43, -43, + -58, 29, 55, -39, 18, 41, -20, 8, 28, -2, -2, 15, + 18, -13, 1, 37, -23, -12, 56, -34, -26, 75, -45, -39, + -56, 28, 59, -37, 17, 45, -18, 7, 32, 1, -3, 19, + 20, -14, 5, 39, -25, -8, 58, -36, -22, 77, -46, -35, + -53, 27, 64, -34, 16, 50, -15, 5, 36, 4, -5, 23, + 23, -16, 9, 42, -26, -3, 61, -37, -17, 80, -48, -30, + -51, 25, 68, -32, 14, 54, -13, 4, 40, 6, -6, 27, + 25, -17, 13, 44, -27, 0, 63, -38, -13, 82, -49, -26, + -49, 24, 72, -29, 13, 58, -10, 2, 44, 8, -7, 31, + 28, -18, 17, 46, -29, 4, 66, -40, -9, 85, -50, -22, + -46, 22, 76, -27, 12, 62, -8, 1, 48, 11, -9, 35, + 30, -20, 21, 49, -30, 8, 68, -41, -5, 87, -52, -18, + -44, 21, 80, -24, 10, 66, -6, 0, 52, 13, -10, 39, + 32, -21, 25, 51, -32, 12, 71, -42, -1, 89, -53, -14, + -41, 20, 84, -22, 9, 70, -3, -1, 57, 16, -12, 44, + 35, -22, 30, 54, -33, 16, 73, -44, 2, 92, -55, -10, + -39, 18, 88, -19, 7, 74, -1, -2, 61, 18, -13, 48, + 38, -24, 34, 56, -34, 20, 76, -45, 6, 94, -56, -6, + -36, 17, 92, -17, 6, 78, 2, -4, 65, 21, -14, 52, + 40, -25, 38, 59, -36, 24, 78, -47, 10, 97, -57, -2, + -34, 16, 96, -15, 5, 82, 4, -5, 69, 23, -16, 56, + 42, -26, 42, 61, -37, 28, 80, -48, 14, 99, -59, 1, + -31, 14, 101, -12, 3, 87, 7, -6, 73, 26, -17, 60, + 45, -28, 46, 64, -39, 33, 83, -50, 19, 102, -60, 6, + -29, 13, 105, -10, 2, 91, 9, -8, 77, 28, -18, 64, + 47, -29, 50, 66, -40, 37, 86, -51, 23, 104, -62, 10, + -26, 11, 109, -7, 0, 95, 12, -9, 81, 30, -20, 68, + 50, -31, 54, 69, -41, 41, 88, -52, 27, 107, -63, 14, + -102, 59, -19, -82, 48, -32, -64, 37, -46, -45, 27, -59, + -25, 16, -73, -7, 5, -86, 13, -5, -100, 32, -15, -114, + -99, 58, -15, -80, 47, -28, -61, 36, -42, -42, 25, -55, + -23, 14, -69, -4, 4, -82, 15, -6, -96, 34, -17, -110, + -97, 56, -11, -78, 45, -24, -59, 35, -38, -40, 24, -51, + -21, 13, -65, -2, 3, -78, 18, -7, -92, 36, -18, -106, + -94, 55, -6, -75, 44, -20, -56, 33, -33, -37, 23, -47, + -18, 12, -61, 1, 1, -74, 20, -9, -88, 39, -20, -101, + -92, 53, -2, -72, 42, -16, -54, 32, -29, -35, 21, -43, + -16, 10, -57, 3, 0, -70, 23, -10, -84, 41, -21, -97, + -89, 52, 1, -70, 41, -12, -51, 30, -25, -33, 20, -39, + -13, 9, -53, 6, -1, -66, 25, -12, -80, 44, -22, -93, + -87, 51, 5, -68, 40, -8, -49, 29, -21, -30, 18, -35, + -11, 8, -49, 8, -2, -62, 27, -13, -76, 46, -24, -89, + -84, 49, 9, -65, 38, -3, -46, 28, -17, -27, 17, -30, + -8, 6, -44, 11, -4, -57, 30, -15, -71, 49, -25, -85, + -82, 48, 13, -63, 37, 0, -44, 26, -13, -25, 16, -26, + -6, 5, -40, 13, -5, -53, 32, -16, -67, 51, -26, -81, + -80, 46, 17, -60, 35, 4, -41, 25, -9, -23, 14, -22, + -3, 3, -36, 16, -6, -49, 35, -17, -63, 54, -28, -77, + -77, 45, 21, -58, 34, 8, -39, 24, -5, -20, 13, -18, + -1, 2, -32, 18, -8, -45, 37, -19, -59, 56, -29, -73, + -75, 44, 25, -55, 33, 12, -37, 22, -1, -18, 12, -14, + 2, 1, -28, 20, -9, -41, 40, -20, -55, 58, -31, -69, + -72, 42, 30, -53, 31, 16, -34, 21, 3, -15, 10, -10, + 4, 0, -24, 23, -10, -37, 42, -21, -51, 61, -32, -64, + -70, 41, 34, -50, 30, 20, -32, 19, 7, -13, 9, -6, + 7, -1, -20, 25, -12, -33, 45, -23, -47, 64, -33, -60, + -67, 39, 38, -48, 29, 24, -29, 18, 11, -10, 7, -2, + 9, -3, -16, 28, -13, -29, 47, -24, -43, 66, -35, -56, + -65, 38, 42, -46, 27, 28, -27, 17, 15, -8, 6, 1, + 11, -4, -12, 30, -15, -25, 50, -25, -39, 68, -36, -52, + -62, 37, 46, -43, 26, 33, -24, 15, 19, -5, 4, 6, + 14, -5, -7, 33, -16, -20, 52, -27, -34, 71, -38, -48, + -60, 35, 50, -40, 24, 37, -22, 14, 23, -3, 3, 10, + 16, -7, -3, 35, -17, -16, 55, -28, -30, 73, -39, -44, + -57, 34, 54, -38, 23, 41, -19, 12, 27, -1, 2, 14, + 19, -8, 0, 38, -19, -12, 57, -30, -26, 76, -40, -40, + -55, 33, 58, -36, 22, 45, -17, 11, 31, 2, 0, 18, + 21, -10, 4, 40, -20, -8, 59, -31, -22, 78, -42, -36, + -52, 31, 63, -33, 20, 49, -14, 10, 36, 5, 0, 22, + 24, -11, 8, 43, -22, -4, 62, -33, -18, 81, -43, -31, + -50, 30, 67, -31, 19, 53, -12, 8, 40, 7, -1, 26, + 26, -12, 12, 45, -23, 0, 64, -34, -14, 83, -45, -27, + -48, 28, 71, -28, 17, 57, -9, 7, 44, 9, -3, 30, + 29, -14, 16, 48, -24, 3, 67, -35, -10, 86, -46, -23, + -45, 27, 75, -26, 16, 61, -7, 5, 48, 12, -4, 34, + 31, -15, 20, 50, -26, 7, 69, -37, -6, 88, -47, -19, + -43, 26, 79, -23, 15, 65, -5, 4, 52, 14, -5, 38, + 34, -16, 24, 52, -27, 11, 72, -38, -2, 90, -49, -15, + -40, 24, 83, -21, 13, 70, -2, 3, 56, 17, -7, 43, + 36, -18, 29, 55, -29, 16, 74, -39, 2, 93, -50, -11, + -38, 23, 87, -18, 12, 74, 0, 1, 60, 19, -8, 47, + 39, -19, 33, 57, -30, 20, 77, -41, 6, 96, -51, -7, + -35, 21, 91, -16, 10, 78, 3, 0, 64, 22, -10, 51, + 41, -21, 37, 60, -31, 24, 79, -42, 10, 98, -53, -3, + -33, 20, 95, -14, 9, 82, 5, 0, 68, 24, -11, 55, + 43, -22, 41, 62, -33, 28, 82, -44, 14, 100, -54, 0, + -30, 19, 100, -11, 8, 86, 8, -2, 73, 27, -13, 59, + 46, -24, 45, 65, -34, 32, 84, -45, 18, 103, -56, 5, + -28, 17, 104, -8, 6, 90, 10, -3, 77, 29, -14, 63, + 48, -25, 49, 67, -35, 36, 87, -46, 22, 105, -57, 9, + -25, 16, 108, -6, 5, 94, 13, -5, 81, 31, -15, 67, + 51, -26, 53, 70, -37, 40, 89, -48, 26, 108, -58, 13, + -101, 63, -19, -81, 52, -33, -63, 41, -46, -44, 31, -60, + -24, 20, -74, -6, 9, -87, 14, -1, -101, 32, -11, -114, + -98, 62, -15, -79, 51, -29, -60, 40, -42, -41, 29, -56, + -22, 18, -70, -3, 8, -83, 16, -2, -97, 35, -13, -110, + -96, 60, -11, -77, 49, -25, -58, 39, -38, -39, 28, -52, + -20, 17, -66, -1, 7, -79, 18, -3, -93, 37, -14, -106, + -93, 59, -7, -74, 48, -21, -55, 37, -34, -36, 27, -47, + -17, 16, -61, 2, 5, -75, 21, -5, -88, 40, -16, -102, + -91, 57, -3, -72, 46, -17, -53, 36, -30, -34, 25, -43, + -15, 14, -57, 4, 4, -71, 24, -6, -84, 42, -17, -98, + -89, 56, 0, -69, 45, -13, -50, 34, -26, -32, 24, -39, + -12, 13, -53, 7, 2, -67, 26, -8, -80, 45, -18, -94, + -86, 55, 4, -67, 44, -9, -48, 33, -22, -29, 22, -35, + -10, 12, -49, 9, 1, -63, 28, -9, -76, 47, -20, -90, + -83, 53, 9, -64, 42, -4, -45, 32, -17, -27, 21, -31, + -7, 10, -45, 12, 0, -58, 31, -11, -72, 50, -21, -85, + -81, 52, 13, -62, 41, 0, -43, 30, -13, -24, 20, -27, + -5, 9, -41, 14, -1, -54, 33, -12, -68, 52, -22, -81, + -79, 50, 17, -59, 39, 3, -41, 29, -9, -22, 18, -23, + -2, 7, -37, 16, -2, -50, 36, -13, -64, 55, -24, -77, + -76, 49, 21, -57, 38, 7, -38, 28, -5, -19, 17, -19, + 0, 6, -33, 19, -4, -46, 38, -15, -60, 57, -25, -73, + -74, 48, 25, -55, 37, 11, -36, 26, -1, -17, 16, -15, + 2, 5, -29, 21, -5, -42, 41, -16, -56, 59, -27, -69, + -71, 46, 29, -52, 35, 15, -33, 25, 2, -14, 14, -10, + 5, 3, -24, 24, -6, -38, 43, -17, -51, 62, -28, -65, + -69, 45, 33, -49, 34, 19, -31, 23, 6, -12, 13, -6, + 8, 2, -20, 26, -8, -34, 46, -19, -47, 64, -29, -61, + -66, 43, 37, -47, 33, 23, -28, 22, 10, -9, 11, -2, + 10, 0, -16, 29, -9, -30, 48, -20, -43, 67, -31, -57, + -64, 42, 41, -45, 31, 27, -26, 21, 14, -7, 10, 1, + 12, 0, -12, 31, -11, -26, 50, -21, -39, 69, -32, -53, + -61, 41, 46, -42, 30, 32, -23, 19, 19, -4, 8, 5, + 15, -1, -8, 34, -12, -21, 53, -23, -35, 72, -34, -48, + -59, 39, 50, -40, 28, 36, -21, 18, 23, -2, 7, 9, + 17, -3, -4, 36, -13, -17, 56, -24, -31, 74, -35, -44, + -57, 38, 54, -37, 27, 40, -18, 16, 27, 0, 6, 13, + 20, -4, 0, 39, -15, -13, 58, -26, -27, 77, -36, -40, + -54, 37, 58, -35, 26, 44, -16, 15, 31, 3, 4, 17, + 22, -6, 3, 41, -16, -9, 60, -27, -23, 79, -38, -36, + -51, 35, 62, -32, 24, 48, -13, 14, 35, 5, 3, 22, + 25, -7, 8, 44, -18, -5, 63, -29, -18, 82, -39, -32, + -49, 34, 66, -30, 23, 52, -11, 12, 39, 8, 2, 26, + 27, -8, 12, 46, -19, -1, 65, -30, -14, 84, -41, -28, + -47, 32, 70, -27, 21, 56, -9, 11, 43, 10, 0, 30, + 30, -10, 16, 48, -20, 2, 68, -31, -10, 87, -42, -24, + -44, 31, 74, -25, 20, 60, -6, 9, 47, 13, 0, 34, + 32, -11, 20, 51, -22, 6, 70, -33, -6, 89, -43, -20, + -42, 30, 78, -23, 19, 64, -4, 8, 51, 15, -1, 38, + 34, -12, 24, 53, -23, 10, 73, -34, -2, 91, -45, -16, + -39, 28, 83, -20, 17, 69, -1, 7, 56, 18, -3, 42, + 37, -14, 28, 56, -25, 15, 75, -35, 1, 94, -46, -11, + -37, 27, 87, -17, 16, 73, 1, 5, 60, 20, -4, 46, + 39, -15, 32, 58, -26, 19, 78, -37, 5, 96, -47, -7, + -34, 25, 91, -15, 14, 77, 4, 4, 64, 23, -6, 50, + 42, -17, 36, 61, -27, 23, 80, -38, 9, 99, -49, -3, + -32, 24, 95, -13, 13, 81, 6, 3, 68, 25, -7, 54, + 44, -18, 40, 63, -29, 27, 82, -40, 13, 101, -50, 0, + -29, 23, 99, -10, 12, 85, 9, 1, 72, 28, -9, 59, + 47, -20, 45, 66, -30, 31, 85, -41, 18, 104, -52, 4, + -27, 21, 103, -8, 10, 89, 11, 0, 76, 30, -10, 63, + 49, -21, 49, 68, -31, 35, 88, -42, 22, 106, -53, 8, + -25, 20, 107, -5, 9, 93, 14, -1, 80, 32, -11, 67, + 52, -22, 53, 71, -33, 39, 90, -44, 26, 109, -54, 12, + -100, 67, -20, -81, 56, -34, -62, 45, -47, -43, 35, -61, + -24, 24, -74, -5, 13, -88, 15, 2, -102, 33, -7, -115, + -97, 66, -16, -78, 55, -30, -59, 44, -43, -41, 33, -57, + -21, 22, -70, -2, 12, -84, 17, 1, -98, 36, -9, -111, + -95, 64, -12, -76, 53, -26, -57, 43, -39, -38, 32, -53, + -19, 21, -66, 0, 11, -80, 19, 0, -94, 38, -10, -107, + -92, 63, -7, -73, 52, -21, -54, 41, -35, -35, 31, -48, + -16, 20, -62, 3, 9, -75, 22, -1, -89, 41, -12, -102, + -90, 61, -3, -71, 50, -17, -52, 40, -31, -33, 29, -44, + -14, 18, -58, 5, 8, -71, 24, -2, -85, 43, -13, -98, + -88, 60, 0, -68, 49, -13, -49, 38, -27, -31, 28, -40, + -11, 17, -54, 7, 6, -67, 27, -4, -81, 46, -14, -94, + -85, 59, 4, -66, 48, -9, -47, 37, -23, -28, 26, -36, + -9, 16, -50, 10, 5, -63, 29, -5, -77, 48, -16, -90, + -83, 57, 8, -63, 46, -5, -44, 36, -18, -26, 25, -32, + -6, 14, -45, 13, 3, -59, 32, -7, -73, 51, -17, -86, + -80, 56, 12, -61, 45, -1, -42, 34, -14, -23, 24, -28, + -4, 13, -41, 15, 2, -55, 34, -8, -69, 53, -18, -82, + -78, 54, 16, -58, 43, 2, -40, 33, -10, -21, 22, -24, + -1, 11, -37, 17, 1, -51, 37, -9, -65, 55, -20, -78, + -75, 53, 20, -56, 42, 6, -37, 32, -6, -18, 21, -20, + 1, 10, -33, 20, 0, -47, 39, -11, -61, 58, -21, -74, + -73, 52, 24, -54, 41, 10, -35, 30, -2, -16, 20, -16, + 3, 9, -29, 22, -1, -43, 41, -12, -57, 60, -23, -70, + -70, 50, 29, -51, 39, 15, -32, 29, 1, -13, 18, -11, + 6, 7, -25, 25, -2, -38, 44, -13, -52, 63, -24, -65, + -68, 49, 33, -49, 38, 19, -30, 27, 5, -11, 17, -7, + 8, 6, -21, 27, -4, -34, 47, -15, -48, 65, -25, -61, + -66, 47, 37, -46, 37, 23, -27, 26, 9, -9, 15, -3, + 11, 4, -17, 30, -5, -30, 49, -16, -44, 68, -27, -57, + -63, 46, 41, -44, 35, 27, -25, 25, 13, -6, 14, 0, + 13, 3, -13, 32, -7, -26, 51, -17, -40, 70, -28, -53, + -60, 45, 45, -41, 34, 31, -22, 23, 18, -3, 12, 4, + 16, 2, -8, 35, -8, -22, 54, -19, -36, 73, -30, -49, + -58, 43, 49, -39, 32, 35, -20, 22, 22, -1, 11, 8, + 18, 0, -4, 37, -9, -18, 56, -20, -32, 75, -31, -45, + -56, 42, 53, -36, 31, 39, -17, 20, 26, 1, 10, 12, + 21, 0, 0, 39, -11, -14, 59, -22, -28, 78, -32, -41, + -53, 41, 57, -34, 30, 43, -15, 19, 30, 4, 8, 16, + 23, -2, 3, 42, -12, -10, 61, -23, -24, 80, -34, -37, + -51, 39, 62, -31, 28, 48, -12, 18, 34, 6, 7, 21, + 26, -3, 7, 45, -14, -5, 64, -25, -19, 83, -35, -32, + -48, 38, 66, -29, 27, 52, -10, 16, 38, 9, 6, 25, + 28, -4, 11, 47, -15, -1, 66, -26, -15, 85, -37, -28, + -46, 36, 70, -26, 25, 56, -8, 15, 42, 11, 4, 29, + 31, -6, 15, 49, -16, 2, 69, -27, -11, 87, -38, -24, + -43, 35, 74, -24, 24, 60, -5, 13, 46, 14, 3, 33, + 33, -7, 19, 52, -18, 6, 71, -29, -7, 90, -39, -20, + -41, 34, 78, -22, 23, 64, -3, 12, 50, 16, 2, 37, + 35, -8, 23, 54, -19, 10, 73, -30, -3, 92, -41, -16, + -38, 32, 82, -19, 21, 68, 0, 11, 55, 19, 0, 41, + 38, -10, 28, 57, -21, 14, 76, -31, 0, 95, -42, -12, + -36, 31, 86, -17, 20, 72, 2, 9, 59, 21, 0, 45, + 40, -11, 32, 59, -22, 18, 79, -33, 4, 97, -43, -8, + -34, 29, 90, -14, 18, 76, 5, 8, 63, 23, -2, 49, + 43, -13, 36, 62, -23, 22, 81, -34, 8, 100, -45, -4, + -31, 28, 94, -12, 17, 80, 7, 7, 67, 26, -3, 53, + 45, -14, 40, 64, -25, 26, 83, -36, 12, 102, -46, 0, + -28, 27, 99, -9, 16, 85, 10, 5, 71, 29, -5, 58, + 48, -16, 44, 67, -26, 31, 86, -37, 17, 105, -48, 4, + -26, 25, 103, -7, 14, 89, 12, 4, 75, 31, -6, 62, + 50, -17, 48, 69, -27, 35, 88, -38, 21, 107, -49, 8, + -24, 24, 107, -4, 13, 93, 15, 2, 79, 33, -7, 66, + 53, -18, 52, 71, -29, 39, 91, -40, 25, 110, -50, 12, + -99, 71, -21, -80, 60, -34, -61, 49, -48, -42, 39, -61, + -23, 28, -75, -4, 17, -88, 15, 6, -102, 34, -3, -116, + -97, 70, -17, -77, 59, -30, -58, 48, -44, -40, 37, -57, + -20, 26, -71, -1, 16, -84, 18, 5, -98, 37, -5, -112, + -94, 68, -13, -75, 57, -26, -56, 47, -40, -37, 36, -53, + -18, 25, -67, 1, 15, -80, 20, 4, -94, 39, -6, -108, + -92, 67, -8, -72, 56, -22, -53, 45, -35, -35, 35, -49, + -15, 24, -62, 4, 13, -76, 23, 2, -90, 42, -8, -103, + -89, 65, -4, -70, 54, -18, -51, 44, -31, -32, 33, -45, + -13, 22, -58, 6, 12, -72, 25, 1, -86, 44, -9, -99, + -87, 64, 0, -67, 53, -14, -49, 42, -27, -30, 32, -41, + -10, 21, -54, 8, 10, -68, 28, 0, -82, 47, -10, -95, + -84, 63, 3, -65, 52, -10, -46, 41, -23, -27, 30, -37, + -8, 20, -50, 11, 9, -64, 30, -1, -78, 49, -12, -91, + -82, 61, 7, -62, 50, -5, -43, 40, -19, -25, 29, -32, + -5, 18, -46, 13, 7, -59, 33, -3, -73, 52, -13, -87, + -79, 60, 11, -60, 49, -1, -41, 38, -15, -22, 28, -28, + -3, 17, -42, 16, 6, -55, 35, -4, -69, 54, -14, -83, + -77, 58, 15, -57, 47, 2, -39, 37, -11, -20, 26, -24, + -1, 15, -38, 18, 5, -51, 38, -5, -65, 56, -16, -79, + -74, 57, 19, -55, 46, 6, -36, 36, -7, -18, 25, -20, + 2, 14, -34, 21, 3, -47, 40, -7, -61, 59, -17, -75, + -72, 56, 23, -53, 45, 10, -34, 34, -3, -15, 24, -16, + 4, 13, -30, 23, 2, -43, 42, -8, -57, 61, -19, -71, + -69, 54, 28, -50, 43, 14, -31, 33, 1, -12, 22, -12, + 7, 11, -25, 26, 1, -39, 45, -9, -53, 64, -20, -66, + -67, 53, 32, -48, 42, 18, -29, 31, 5, -10, 21, -8, + 9, 10, -21, 28, 0, -35, 47, -11, -49, 66, -21, -62, + -65, 51, 36, -45, 41, 22, -26, 30, 9, -8, 19, -4, + 12, 8, -17, 31, -1, -31, 50, -12, -45, 69, -23, -58, + -62, 50, 40, -43, 39, 26, -24, 29, 13, -5, 18, 0, + 14, 7, -13, 33, -3, -27, 52, -13, -41, 71, -24, -54, + -60, 49, 44, -40, 38, 31, -21, 27, 17, -3, 16, 4, + 17, 6, -9, 36, -4, -22, 55, -15, -36, 74, -26, -50, + -57, 47, 48, -38, 36, 35, -19, 26, 21, 0, 15, 8, + 19, 4, -5, 38, -5, -18, 57, -16, -32, 76, -27, -46, + -55, 46, 52, -35, 35, 39, -17, 24, 25, 2, 14, 12, + 22, 3, -1, 40, -7, -14, 60, -18, -28, 79, -28, -42, + -52, 45, 56, -33, 34, 43, -14, 23, 29, 5, 12, 16, + 24, 1, 2, 43, -8, -10, 62, -19, -24, 81, -30, -38, + -50, 43, 61, -30, 32, 47, -11, 22, 34, 7, 11, 20, + 27, 0, 7, 45, -10, -6, 65, -21, -20, 84, -31, -33, + -47, 42, 65, -28, 31, 51, -9, 20, 38, 10, 10, 24, + 29, 0, 11, 48, -11, -2, 67, -22, -16, 86, -33, -29, + -45, 40, 69, -25, 29, 55, -7, 19, 42, 12, 8, 28, + 31, -2, 15, 50, -12, 1, 70, -23, -12, 88, -34, -25, + -42, 39, 73, -23, 28, 59, -4, 17, 46, 14, 7, 32, + 34, -3, 19, 53, -14, 5, 72, -25, -8, 91, -35, -21, + -40, 38, 77, -21, 27, 63, -2, 16, 50, 17, 6, 36, + 36, -4, 23, 55, -15, 9, 74, -26, -4, 93, -37, -17, + -37, 36, 81, -18, 25, 68, 1, 15, 54, 20, 4, 41, + 39, -6, 27, 58, -17, 14, 77, -27, 0, 96, -38, -13, + -35, 35, 85, -16, 24, 72, 3, 13, 58, 22, 3, 45, + 41, -7, 31, 60, -18, 18, 79, -29, 4, 98, -39, -9, + -33, 33, 89, -13, 22, 76, 6, 12, 62, 24, 1, 49, + 44, -9, 35, 62, -19, 22, 82, -30, 8, 101, -41, -5, + -30, 32, 93, -11, 21, 80, 8, 11, 66, 27, 0, 53, + 46, -10, 39, 65, -21, 26, 84, -32, 12, 103, -42, -1, + -28, 31, 98, -8, 20, 84, 11, 9, 71, 29, -1, 57, + 49, -12, 44, 68, -22, 30, 87, -33, 16, 106, -44, 3, + -25, 29, 102, -6, 18, 88, 13, 8, 75, 32, -2, 61, + 51, -13, 48, 70, -23, 34, 89, -34, 20, 108, -45, 7, + -23, 28, 106, -3, 17, 92, 15, 6, 79, 34, -3, 65, + 54, -14, 52, 72, -25, 38, 92, -36, 24, 111, -46, 11, + -98, 75, -21, -79, 64, -35, -60, 54, -49, -41, 43, -62, + -22, 32, -76, -3, 22, -89, 17, 11, -103, 35, 0, -116, + -96, 74, -17, -76, 63, -31, -57, 52, -45, -39, 42, -58, + -19, 31, -72, 0, 20, -85, 19, 9, -99, 38, 0, -112, + -93, 73, -13, -74, 62, -27, -55, 51, -41, -36, 41, -54, + -17, 30, -68, 2, 19, -81, 21, 8, -95, 40, -2, -108, + -90, 71, -9, -71, 60, -23, -52, 50, -36, -34, 39, -49, + -14, 28, -63, 5, 17, -77, 24, 7, -90, 43, -3, -104, + -88, 70, -5, -69, 59, -19, -50, 48, -32, -31, 38, -45, + -12, 27, -59, 7, 16, -73, 26, 5, -86, 45, -4, -100, + -86, 68, -1, -66, 58, -15, -48, 47, -28, -29, 36, -41, + -9, 25, -55, 9, 15, -69, 29, 4, -82, 48, -6, -96, + -83, 67, 2, -64, 56, -11, -45, 46, -24, -26, 35, -37, + -7, 24, -51, 12, 13, -65, 31, 3, -78, 50, -7, -92, + -81, 66, 7, -61, 55, -6, -42, 44, -20, -24, 33, -33, + -4, 23, -47, 14, 12, -60, 34, 1, -74, 53, -9, -87, + -78, 64, 11, -59, 53, -2, -40, 43, -16, -21, 32, -29, + -2, 21, -43, 17, 11, -56, 36, 0, -70, 55, -10, -83, + -76, 63, 15, -56, 52, 1, -38, 41, -12, -19, 31, -25, + 0, 20, -39, 19, 9, -52, 39, -1, -66, 57, -11, -79, + -73, 62, 19, -54, 51, 5, -35, 40, -8, -16, 29, -21, + 3, 18, -35, 22, 8, -48, 41, -2, -62, 60, -13, -75, + -71, 60, 23, -52, 49, 9, -33, 39, -4, -14, 28, -17, + 5, 17, -31, 24, 7, -44, 43, -3, -58, 62, -14, -71, + -68, 59, 27, -49, 48, 13, -30, 37, 0, -11, 27, -12, + 8, 16, -26, 27, 5, -40, 46, -5, -53, 65, -16, -67, + -66, 57, 31, -47, 46, 17, -28, 36, 4, -9, 25, -8, + 10, 14, -22, 29, 4, -36, 49, -6, -49, 67, -17, -63, + -64, 56, 35, -44, 45, 21, -25, 34, 8, -7, 24, -4, + 13, 13, -18, 32, 2, -32, 51, -8, -45, 70, -18, -59, + -61, 55, 39, -42, 44, 25, -23, 33, 12, -4, 22, 0, + 15, 12, -14, 34, 1, -28, 53, -9, -41, 72, -20, -55, + -58, 53, 44, -39, 42, 30, -20, 32, 16, -2, 21, 3, + 18, 10, -10, 37, 0, -23, 56, -10, -37, 75, -21, -50, + -56, 52, 48, -37, 41, 34, -18, 30, 20, 1, 20, 7, + 20, 9, -6, 39, -1, -19, 58, -12, -33, 77, -22, -46, + -54, 50, 52, -34, 39, 38, -16, 29, 24, 3, 18, 11, + 23, 7, -2, 41, -2, -15, 61, -13, -29, 80, -24, -42, + -51, 49, 56, -32, 38, 42, -13, 28, 28, 6, 17, 15, + 25, 6, 1, 44, -4, -11, 63, -15, -25, 82, -25, -38, + -49, 48, 60, -29, 37, 46, -10, 26, 33, 8, 15, 20, + 28, 4, 6, 46, -5, -7, 66, -16, -20, 85, -27, -34, + -46, 46, 64, -27, 35, 50, -8, 25, 37, 11, 14, 24, + 30, 3, 10, 49, -6, -3, 68, -17, -16, 87, -28, -30, + -44, 45, 68, -24, 34, 54, -6, 23, 41, 13, 13, 28, + 32, 2, 14, 51, -8, 0, 71, -19, -12, 89, -29, -26, + -41, 43, 72, -22, 33, 58, -3, 22, 45, 16, 11, 32, + 35, 0, 18, 54, -9, 4, 73, -20, -8, 92, -31, -22, + -39, 42, 76, -20, 31, 62, -1, 21, 49, 18, 10, 36, + 37, 0, 22, 56, -11, 8, 75, -21, -4, 94, -32, -18, + -36, 41, 81, -17, 30, 67, 2, 19, 53, 21, 8, 40, + 40, -1, 26, 59, -12, 13, 78, -23, 0, 97, -34, -13, + -34, 39, 85, -15, 28, 71, 4, 18, 57, 23, 7, 44, + 42, -3, 30, 61, -13, 17, 81, -24, 3, 99, -35, -9, + -32, 38, 89, -12, 27, 75, 7, 16, 61, 25, 6, 48, + 45, -4, 34, 64, -15, 21, 83, -26, 7, 102, -36, -5, + -29, 37, 93, -10, 26, 79, 9, 15, 65, 28, 4, 52, + 47, -5, 38, 66, -16, 25, 85, -27, 11, 104, -38, -1, + -26, 35, 97, -7, 24, 83, 12, 14, 70, 30, 3, 57, + 50, -7, 43, 69, -18, 29, 88, -29, 16, 107, -39, 2, + -24, 34, 101, -5, 23, 87, 14, 12, 74, 33, 2, 61, + 52, -8, 47, 71, -19, 33, 90, -30, 20, 109, -41, 6, + -22, 32, 105, -2, 21, 91, 16, 11, 78, 35, 0, 65, + 55, -10, 51, 73, -20, 37, 93, -31, 24, 112, -42, 10, + -97, 79, -22, -78, 68, -36, -59, 58, -49, -40, 47, -63, + -21, 36, -76, -2, 26, -90, 17, 15, -104, 36, 4, -117, + -95, 78, -18, -75, 67, -32, -56, 56, -45, -38, 46, -59, + -18, 35, -72, 0, 24, -86, 20, 13, -100, 39, 3, -113, + -92, 77, -14, -73, 66, -28, -54, 55, -41, -35, 45, -55, + -16, 34, -68, 3, 23, -82, 22, 12, -96, 41, 1, -109, + -90, 75, -9, -70, 64, -23, -51, 54, -37, -33, 43, -50, + -13, 32, -64, 6, 21, -77, 25, 11, -91, 44, 0, -104, + -87, 74, -5, -68, 63, -19, -49, 52, -33, -30, 42, -46, + -11, 31, -60, 8, 20, -73, 27, 9, -87, 46, 0, -100, + -85, 72, -1, -65, 62, -15, -47, 51, -29, -28, 40, -42, + -8, 29, -56, 10, 19, -69, 30, 8, -83, 48, -2, -96, + -82, 71, 2, -63, 60, -11, -44, 50, -25, -25, 39, -38, + -6, 28, -52, 13, 17, -65, 32, 7, -79, 51, -3, -92, + -80, 70, 6, -60, 59, -7, -42, 48, -20, -23, 37, -34, + -3, 27, -47, 15, 16, -61, 35, 5, -75, 54, -5, -88, + -77, 68, 10, -58, 57, -3, -39, 47, -16, -20, 36, -30, + -1, 25, -43, 18, 15, -57, 37, 4, -71, 56, -6, -84, + -75, 67, 14, -56, 56, 0, -37, 45, -12, -18, 35, -26, + 1, 24, -39, 20, 13, -53, 40, 2, -67, 58, -7, -80, + -73, 66, 18, -53, 55, 4, -34, 44, -8, -16, 33, -22, + 4, 22, -35, 23, 12, -49, 42, 1, -63, 61, -9, -76, + -70, 64, 22, -51, 53, 8, -32, 43, -4, -13, 32, -18, + 6, 21, -31, 25, 11, -45, 44, 0, -59, 63, -10, -72, + -67, 63, 27, -48, 52, 13, -29, 41, 0, -10, 31, -13, + 9, 20, -27, 28, 9, -40, 47, -1, -54, 66, -12, -67, + -65, 61, 31, -46, 50, 17, -27, 40, 3, -8, 29, -9, + 11, 18, -23, 30, 8, -36, 49, -2, -50, 68, -13, -63, + -63, 60, 35, -43, 49, 21, -24, 38, 7, -6, 28, -5, + 14, 17, -19, 32, 6, -32, 52, -4, -46, 71, -14, -59, + -60, 59, 39, -41, 48, 25, -22, 37, 11, -3, 26, -1, + 16, 16, -15, 35, 5, -28, 54, -5, -42, 73, -16, -55, + -58, 57, 43, -38, 46, 29, -19, 36, 16, -1, 25, 2, + 19, 14, -10, 38, 3, -24, 57, -6, -38, 76, -17, -51, + -55, 56, 47, -36, 45, 33, -17, 34, 20, 2, 24, 6, + 21, 13, -6, 40, 2, -20, 59, -8, -34, 78, -18, -47, + -53, 54, 51, -33, 43, 37, -15, 33, 24, 4, 22, 10, + 24, 11, -2, 42, 1, -16, 62, -9, -30, 80, -20, -43, + -50, 53, 55, -31, 42, 41, -12, 32, 28, 7, 21, 14, + 26, 10, 1, 45, 0, -12, 64, -11, -26, 83, -21, -39, + -48, 52, 60, -28, 41, 46, -10, 30, 32, 9, 19, 19, + 29, 8, 5, 47, -1, -7, 67, -12, -21, 86, -23, -34, + -45, 50, 64, -26, 39, 50, -7, 29, 36, 12, 18, 23, + 31, 7, 9, 50, -2, -3, 69, -13, -17, 88, -24, -30, + -43, 49, 68, -24, 38, 54, -5, 27, 40, 14, 17, 27, + 33, 6, 13, 52, -4, 0, 72, -15, -13, 90, -25, -26, + -41, 47, 72, -21, 37, 58, -2, 26, 44, 16, 15, 31, + 36, 4, 17, 55, -5, 4, 74, -16, -9, 93, -27, -22, + -38, 46, 76, -19, 35, 62, 0, 25, 48, 19, 14, 35, + 38, 3, 21, 57, -7, 8, 76, -17, -5, 95, -28, -18, + -35, 45, 80, -16, 34, 66, 3, 23, 53, 21, 12, 39, + 41, 2, 26, 60, -8, 12, 79, -19, -1, 98, -30, -14, + -33, 43, 84, -14, 32, 70, 5, 22, 57, 24, 11, 43, + 43, 0, 30, 62, -9, 16, 81, -20, 2, 100, -31, -10, + -31, 42, 88, -11, 31, 74, 7, 20, 61, 26, 10, 47, + 46, 0, 34, 64, -11, 20, 84, -22, 6, 103, -32, -6, + -28, 41, 92, -9, 30, 78, 10, 19, 65, 29, 8, 51, + 48, -1, 38, 67, -12, 24, 86, -23, 10, 105, -34, -2, + -26, 39, 97, -6, 28, 83, 13, 18, 69, 31, 7, 56, + 51, -3, 42, 70, -14, 29, 89, -25, 15, 108, -35, 2, + -23, 38, 101, -4, 27, 87, 15, 16, 73, 34, 6, 60, + 53, -4, 46, 72, -15, 33, 91, -26, 19, 110, -37, 6, + -21, 36, 105, -1, 25, 91, 17, 15, 77, 36, 4, 64, + 56, -6, 50, 74, -16, 37, 94, -27, 23, 112, -38, 10, + -96, 83, -23, -77, 72, -36, -58, 62, -50, -39, 51, -63, + -20, 40, -77, -1, 30, -90, 18, 19, -104, 37, 8, -118, + -94, 82, -19, -74, 71, -32, -56, 60, -46, -37, 50, -59, + -17, 39, -73, 1, 28, -86, 21, 17, -100, 40, 7, -114, + -91, 81, -15, -72, 70, -28, -53, 59, -42, -34, 49, -55, + -15, 38, -69, 4, 27, -82, 23, 16, -96, 42, 5, -110, + -89, 79, -10, -69, 68, -24, -50, 58, -37, -32, 47, -51, + -12, 36, -65, 6, 25, -78, 26, 15, -92, 45, 4, -105, + -86, 78, -6, -67, 67, -20, -48, 56, -33, -29, 46, -47, + -10, 35, -61, 9, 24, -74, 28, 13, -88, 47, 3, -101, + -84, 76, -2, -64, 66, -16, -46, 55, -29, -27, 44, -43, + -8, 33, -57, 11, 23, -70, 31, 12, -84, 49, 1, -97, + -81, 75, 1, -62, 64, -12, -43, 54, -25, -25, 43, -39, + -5, 32, -53, 14, 21, -66, 33, 11, -80, 52, 0, -93, + -79, 74, 5, -59, 63, -7, -41, 52, -21, -22, 41, -34, + -2, 31, -48, 16, 20, -61, 36, 9, -75, 54, -1, -89, + -76, 72, 9, -57, 61, -3, -38, 51, -17, -19, 40, -30, + 0, 29, -44, 19, 19, -57, 38, 8, -71, 57, -2, -85, + -74, 71, 13, -55, 60, 0, -36, 49, -13, -17, 39, -26, + 2, 28, -40, 21, 17, -53, 40, 6, -67, 59, -3, -81, + -72, 70, 17, -52, 59, 4, -33, 48, -9, -15, 37, -22, + 5, 26, -36, 23, 16, -49, 43, 5, -63, 62, -5, -77, + -69, 68, 21, -50, 57, 8, -31, 47, -5, -12, 36, -18, + 7, 25, -32, 26, 15, -45, 45, 4, -59, 64, -6, -73, + -67, 67, 26, -47, 56, 12, -28, 45, 0, -10, 35, -14, + 10, 24, -28, 29, 13, -41, 48, 2, -55, 67, -8, -68, + -64, 65, 30, -45, 54, 16, -26, 44, 3, -7, 33, -10, + 12, 22, -24, 31, 12, -37, 50, 1, -51, 69, -9, -64, + -62, 64, 34, -42, 53, 20, -24, 42, 7, -5, 32, -6, + 15, 21, -20, 33, 10, -33, 53, 0, -47, 72, -10, -60, + -59, 63, 38, -40, 52, 24, -21, 41, 11, -2, 30, -2, + 17, 20, -16, 36, 9, -29, 55, -1, -43, 74, -12, -56, + -57, 61, 42, -37, 50, 29, -19, 40, 15, 0, 29, 2, + 20, 18, -11, 38, 7, -24, 58, -2, -38, 77, -13, -52, + -54, 60, 46, -35, 49, 33, -16, 38, 19, 3, 28, 6, + 22, 17, -7, 41, 6, -20, 60, -4, -34, 79, -14, -48, + -52, 58, 50, -33, 47, 37, -14, 37, 23, 5, 26, 10, + 24, 15, -3, 43, 5, -16, 63, -5, -30, 81, -16, -44, + -49, 57, 54, -30, 46, 41, -11, 36, 27, 7, 25, 14, + 27, 14, 0, 46, 3, -12, 65, -7, -26, 84, -17, -40, + -47, 56, 59, -27, 45, 45, -9, 34, 32, 10, 23, 18, + 30, 12, 4, 48, 2, -8, 68, -8, -22, 86, -19, -35, + -44, 54, 63, -25, 43, 49, -6, 33, 36, 13, 22, 22, + 32, 11, 8, 51, 1, -4, 70, -9, -18, 89, -20, -31, + -42, 53, 67, -23, 42, 53, -4, 31, 40, 15, 21, 26, + 34, 10, 12, 53, 0, 0, 72, -11, -14, 91, -21, -27, + -40, 51, 71, -20, 41, 57, -1, 30, 44, 17, 19, 30, + 37, 8, 16, 55, -1, 3, 75, -12, -10, 94, -23, -23, + -37, 50, 75, -18, 39, 61, 1, 29, 48, 20, 18, 34, + 39, 7, 20, 58, -3, 7, 77, -13, -6, 96, -24, -19, + -35, 49, 79, -15, 38, 66, 4, 27, 52, 22, 16, 39, + 42, 6, 25, 61, -4, 12, 80, -15, -1, 99, -26, -15, + -32, 47, 83, -13, 36, 70, 6, 26, 56, 25, 15, 43, + 44, 4, 29, 63, -5, 16, 82, -16, 2, 101, -27, -11, + -30, 46, 87, -10, 35, 74, 8, 24, 60, 27, 14, 47, + 47, 3, 33, 65, -7, 20, 85, -18, 6, 104, -28, -7, + -27, 45, 91, -8, 34, 78, 11, 23, 64, 30, 12, 51, + 49, 2, 37, 68, -8, 24, 87, -19, 10, 106, -30, -3, + -25, 43, 96, -5, 32, 82, 13, 22, 69, 32, 11, 55, + 52, 0, 41, 70, -10, 28, 90, -21, 14, 109, -31, 1, + -22, 42, 100, -3, 31, 86, 16, 20, 73, 35, 10, 59, + 54, 0, 45, 73, -11, 32, 92, -22, 18, 111, -33, 5, + -20, 40, 104, -1, 29, 90, 18, 19, 77, 37, 8, 63, + 56, -2, 49, 75, -12, 36, 95, -23, 22, 113, -34, 9, + -95, 87, -23, -76, 76, -37, -57, 66, -50, -38, 55, -64, + -19, 44, -78, 0, 34, -91, 19, 23, -105, 38, 12, -118, + -93, 86, -19, -73, 75, -33, -55, 64, -46, -36, 54, -60, + -17, 43, -74, 2, 32, -87, 22, 21, -101, 40, 11, -114, + -90, 85, -15, -71, 74, -29, -52, 63, -42, -33, 53, -56, + -14, 42, -70, 5, 31, -83, 24, 20, -97, 43, 9, -110, + -88, 83, -11, -68, 72, -25, -50, 62, -38, -31, 51, -51, + -11, 40, -65, 7, 29, -79, 27, 19, -92, 46, 8, -106, + -85, 82, -7, -66, 71, -21, -47, 60, -34, -28, 50, -47, + -9, 39, -61, 10, 28, -75, 29, 17, -88, 48, 7, -102, + -83, 80, -3, -64, 70, -17, -45, 59, -30, -26, 48, -43, + -7, 37, -57, 12, 27, -71, 32, 16, -84, 50, 5, -98, + -81, 79, 0, -61, 68, -13, -42, 58, -26, -24, 47, -39, + -4, 36, -53, 15, 25, -67, 34, 15, -80, 53, 4, -94, + -78, 78, 5, -59, 67, -8, -40, 56, -21, -21, 45, -35, + -2, 35, -49, 17, 24, -62, 37, 13, -76, 55, 2, -89, + -75, 76, 9, -56, 65, -4, -37, 55, -17, -19, 44, -31, + 1, 33, -45, 20, 23, -58, 39, 12, -72, 58, 1, -85, + -73, 75, 13, -54, 64, 0, -35, 53, -13, -16, 43, -27, + 3, 32, -41, 22, 21, -54, 41, 10, -68, 60, 0, -81, + -71, 74, 17, -51, 63, 3, -33, 52, -9, -14, 41, -23, + 6, 30, -37, 24, 20, -50, 44, 9, -64, 63, -1, -77, + -68, 72, 21, -49, 61, 7, -30, 51, -5, -11, 40, -19, + 8, 29, -33, 27, 19, -46, 46, 8, -60, 65, -2, -73, + -66, 71, 25, -46, 60, 11, -27, 49, -1, -9, 39, -14, + 11, 28, -28, 29, 17, -42, 49, 6, -55, 68, -4, -69, + -63, 69, 29, -44, 58, 15, -25, 48, 2, -6, 37, -10, + 13, 26, -24, 32, 16, -38, 51, 5, -51, 70, -5, -65, + -61, 68, 33, -41, 57, 19, -23, 46, 6, -4, 36, -6, + 15, 25, -20, 34, 14, -34, 54, 3, -47, 72, -6, -61, + -58, 67, 37, -39, 56, 23, -20, 45, 10, -1, 34, -2, + 18, 24, -16, 37, 13, -30, 56, 2, -43, 75, -8, -57, + -56, 65, 42, -36, 54, 28, -18, 44, 15, 1, 33, 1, + 21, 22, -12, 39, 11, -25, 59, 1, -39, 78, -9, -52, + -53, 64, 46, -34, 53, 32, -15, 42, 19, 4, 32, 5, + 23, 21, -8, 42, 10, -21, 61, 0, -35, 80, -10, -48, + -51, 62, 50, -32, 51, 36, -13, 41, 23, 6, 30, 9, + 25, 19, -4, 44, 9, -17, 64, -1, -31, 82, -12, -44, + -49, 61, 54, -29, 50, 40, -10, 40, 27, 8, 29, 13, + 28, 18, 0, 47, 7, -13, 66, -3, -27, 85, -13, -40, + -46, 60, 58, -27, 49, 44, -8, 38, 31, 11, 27, 18, + 30, 16, 4, 49, 6, -9, 69, -4, -22, 87, -15, -36, + -43, 58, 62, -24, 47, 48, -5, 37, 35, 13, 26, 22, + 33, 15, 8, 52, 5, -5, 71, -5, -18, 90, -16, -32, + -41, 57, 66, -22, 46, 52, -3, 35, 39, 16, 25, 26, + 35, 14, 12, 54, 3, -1, 73, -7, -14, 92, -17, -28, + -39, 55, 70, -19, 45, 56, -1, 34, 43, 18, 23, 30, + 38, 12, 16, 56, 2, 2, 76, -8, -10, 95, -19, -24, + -36, 54, 74, -17, 43, 60, 2, 33, 47, 21, 22, 34, + 40, 11, 20, 59, 0, 6, 78, -9, -6, 97, -20, -20, + -34, 53, 79, -14, 42, 65, 5, 31, 52, 23, 20, 38, + 43, 10, 24, 61, 0, 11, 81, -11, -2, 100, -22, -15, + -31, 51, 83, -12, 40, 69, 7, 30, 56, 26, 19, 42, + 45, 8, 28, 64, -1, 15, 83, -12, 1, 102, -23, -11, + -29, 50, 87, -9, 39, 73, 9, 28, 60, 28, 18, 46, + 47, 7, 32, 66, -3, 19, 86, -14, 5, 104, -24, -7, + -26, 49, 91, -7, 38, 77, 12, 27, 64, 30, 16, 50, + 50, 6, 36, 69, -4, 23, 88, -15, 9, 107, -26, -3, + -24, 47, 95, -4, 36, 81, 14, 26, 68, 33, 15, 55, + 53, 4, 41, 71, -6, 27, 91, -17, 14, 109, -27, 0, + -21, 46, 99, -2, 35, 85, 17, 24, 72, 36, 14, 59, + 55, 3, 45, 74, -7, 31, 93, -18, 18, 112, -29, 4, + -19, 44, 103, 0, 33, 89, 19, 23, 76, 38, 12, 63, + 57, 1, 49, 76, -8, 35, 95, -19, 22, 114, -30, 8, + -94, 91, -24, -75, 80, -38, -56, 70, -51, -37, 59, -65, + -18, 48, -78, 1, 38, -92, 20, 27, -106, 39, 16, -119, + -92, 90, -20, -73, 79, -34, -54, 68, -47, -35, 58, -61, + -16, 47, -74, 3, 36, -88, 23, 25, -102, 41, 15, -115, + -90, 89, -16, -70, 78, -30, -51, 67, -43, -33, 57, -57, + -13, 46, -70, 6, 35, -84, 25, 24, -98, 44, 13, -111, + -87, 87, -11, -67, 76, -25, -49, 66, -39, -30, 55, -52, + -11, 44, -66, 8, 33, -79, 28, 23, -93, 46, 12, -106, + -84, 86, -7, -65, 75, -21, -46, 64, -35, -27, 54, -48, + -8, 43, -62, 11, 32, -75, 30, 21, -89, 49, 11, -102, + -82, 84, -3, -63, 74, -17, -44, 63, -31, -25, 52, -44, + -6, 41, -58, 13, 31, -71, 32, 20, -85, 51, 9, -98, + -80, 83, 0, -60, 72, -13, -41, 62, -27, -23, 51, -40, + -3, 40, -54, 15, 29, -67, 35, 19, -81, 54, 8, -94, + -77, 82, 4, -58, 71, -9, -39, 60, -22, -20, 49, -36, + -1, 39, -49, 18, 28, -63, 38, 17, -77, 56, 6, -90, + -75, 80, 8, -55, 69, -5, -36, 59, -18, -18, 48, -32, + 2, 37, -45, 21, 27, -59, 40, 16, -73, 59, 5, -86, + -72, 79, 12, -53, 68, -1, -34, 57, -14, -15, 47, -28, + 4, 36, -41, 23, 25, -55, 42, 14, -69, 61, 4, -82, + -70, 78, 16, -50, 67, 2, -32, 56, -10, -13, 45, -24, + 7, 34, -37, 25, 24, -51, 45, 13, -65, 63, 2, -78, + -67, 76, 20, -48, 65, 6, -29, 55, -6, -10, 44, -20, + 9, 33, -33, 28, 23, -47, 47, 12, -61, 66, 1, -74, + -65, 75, 25, -45, 64, 11, -27, 53, -2, -8, 43, -15, + 12, 32, -29, 30, 21, -42, 50, 10, -56, 69, 0, -69, + -62, 73, 29, -43, 62, 15, -24, 52, 1, -5, 41, -11, + 14, 30, -25, 33, 20, -38, 52, 9, -52, 71, -1, -65, + -60, 72, 33, -41, 61, 19, -22, 50, 5, -3, 40, -7, + 16, 29, -21, 35, 18, -34, 55, 7, -48, 73, -2, -61, + -58, 71, 37, -38, 60, 23, -19, 49, 9, -1, 38, -3, + 19, 28, -17, 38, 17, -30, 57, 6, -44, 76, -4, -57, + -55, 69, 41, -35, 58, 27, -17, 48, 14, 2, 37, 0, + 21, 26, -12, 40, 15, -26, 60, 5, -40, 78, -5, -53, + -52, 68, 45, -33, 57, 31, -14, 46, 18, 4, 36, 4, + 24, 25, -8, 43, 14, -22, 62, 3, -36, 81, -6, -49, + -50, 66, 49, -31, 55, 35, -12, 45, 22, 7, 34, 8, + 26, 23, -4, 45, 13, -18, 64, 2, -32, 83, -8, -45, + -48, 65, 53, -28, 54, 39, -10, 44, 26, 9, 33, 12, + 29, 22, 0, 47, 11, -14, 67, 0, -28, 86, -9, -41, + -45, 64, 58, -26, 53, 44, -7, 42, 30, 12, 31, 17, + 31, 20, 3, 50, 10, -9, 69, 0, -23, 88, -11, -36, + -43, 62, 62, -23, 51, 48, -4, 41, 34, 14, 30, 21, + 34, 19, 7, 53, 9, -5, 72, -1, -19, 91, -12, -32, + -40, 61, 66, -21, 50, 52, -2, 39, 38, 17, 29, 25, + 36, 18, 11, 55, 7, -1, 74, -3, -15, 93, -13, -28, + -38, 59, 70, -18, 49, 56, 0, 38, 42, 19, 27, 29, + 39, 16, 15, 57, 6, 2, 77, -4, -11, 95, -15, -24, + -35, 58, 74, -16, 47, 60, 3, 37, 46, 22, 26, 33, + 41, 15, 19, 60, 4, 6, 79, -5, -7, 98, -16, -20, + -33, 57, 78, -13, 46, 64, 5, 35, 51, 24, 24, 37, + 44, 14, 24, 62, 3, 10, 82, -7, -3, 101, -18, -16, + -30, 55, 82, -11, 44, 68, 8, 34, 55, 27, 23, 41, + 46, 12, 28, 65, 2, 14, 84, -8, 0, 103, -19, -12, + -28, 54, 86, -9, 43, 72, 10, 32, 59, 29, 22, 45, + 48, 11, 32, 67, 0, 18, 87, -10, 4, 105, -20, -8, + -26, 53, 90, -6, 42, 76, 13, 31, 63, 31, 20, 49, + 51, 10, 36, 70, 0, 22, 89, -11, 8, 108, -22, -4, + -23, 51, 95, -3, 40, 81, 15, 30, 67, 34, 19, 54, + 53, 8, 40, 72, -2, 27, 92, -13, 13, 110, -23, 0, + -20, 50, 99, -1, 39, 85, 18, 28, 71, 36, 18, 58, + 56, 7, 44, 75, -3, 31, 94, -14, 17, 113, -25, 4, + -18, 48, 103, 1, 37, 89, 20, 27, 75, 39, 16, 62, + 58, 5, 48, 77, -4, 35, 96, -15, 21, 115, -26, 8, + -93, 96, -25, -74, 85, -38, -55, 74, -52, -36, 64, -65, + -17, 53, -79, 2, 42, -92, 21, 31, -106, 40, 21, -120, + -91, 95, -21, -72, 84, -34, -53, 73, -48, -34, 62, -61, + -15, 51, -75, 4, 41, -88, 24, 30, -102, 42, 19, -116, + -88, 93, -17, -69, 82, -30, -50, 72, -44, -32, 61, -57, + -12, 50, -71, 7, 40, -84, 26, 29, -98, 45, 18, -112, + -86, 92, -12, -66, 81, -26, -48, 70, -39, -29, 60, -53, + -9, 49, -67, 9, 38, -80, 29, 27, -94, 47, 16, -107, + -83, 90, -8, -64, 79, -22, -45, 69, -35, -26, 58, -49, + -7, 47, -63, 12, 37, -76, 31, 26, -90, 50, 15, -103, + -81, 89, -4, -62, 78, -18, -43, 67, -31, -24, 57, -45, + -5, 46, -59, 14, 35, -72, 33, 24, -86, 52, 14, -99, + -79, 88, 0, -59, 77, -14, -40, 66, -27, -22, 55, -41, + -2, 45, -55, 16, 34, -68, 36, 23, -82, 55, 12, -95, + -76, 86, 3, -57, 75, -9, -38, 65, -23, -19, 54, -36, + 0, 43, -50, 19, 32, -63, 39, 21, -77, 57, 11, -91, + -74, 85, 7, -54, 74, -5, -35, 63, -19, -17, 53, -32, + 3, 42, -46, 22, 31, -59, 41, 20, -73, 60, 10, -87, + -71, 83, 11, -52, 72, -1, -33, 62, -15, -14, 51, -28, + 5, 40, -42, 24, 30, -55, 43, 19, -69, 62, 8, -83, + -69, 82, 15, -49, 71, 2, -31, 61, -11, -12, 50, -24, + 8, 39, -38, 26, 28, -51, 46, 17, -65, 64, 7, -79, + -66, 81, 19, -47, 70, 6, -28, 59, -7, -9, 49, -20, + 10, 38, -34, 29, 27, -47, 48, 16, -61, 67, 5, -75, + -64, 79, 24, -44, 68, 10, -26, 58, -2, -7, 47, -16, + 13, 36, -30, 31, 26, -43, 51, 15, -57, 70, 4, -70, + -61, 78, 28, -42, 67, 14, -23, 56, 1, -4, 46, -12, + 15, 35, -26, 34, 24, -39, 53, 13, -53, 72, 3, -66, + -59, 76, 32, -40, 66, 18, -21, 55, 5, -2, 44, -8, + 17, 33, -22, 36, 23, -35, 56, 12, -49, 74, 1, -62, + -56, 75, 36, -37, 64, 22, -18, 54, 9, 0, 43, -4, + 20, 32, -18, 39, 21, -31, 58, 11, -45, 77, 0, -58, + -54, 74, 40, -34, 63, 27, -16, 52, 13, 3, 41, 0, + 23, 31, -13, 41, 20, -26, 61, 9, -40, 79, -1, -54, + -51, 72, 44, -32, 61, 31, -13, 51, 17, 6, 40, 4, + 25, 29, -9, 44, 19, -22, 63, 8, -36, 82, -2, -50, + -49, 71, 48, -30, 60, 35, -11, 49, 21, 8, 39, 8, + 27, 28, -5, 46, 17, -18, 65, 6, -32, 84, -3, -46, + -47, 70, 52, -27, 59, 39, -8, 48, 25, 10, 37, 12, + 30, 26, -1, 48, 16, -14, 68, 5, -28, 87, -5, -42, + -44, 68, 57, -25, 57, 43, -6, 47, 30, 13, 36, 16, + 32, 25, 2, 51, 14, -10, 71, 3, -24, 89, -6, -37, + -42, 67, 61, -22, 56, 47, -3, 45, 34, 15, 35, 20, + 35, 24, 6, 54, 13, -6, 73, 2, -20, 92, -8, -33, + -39, 65, 65, -20, 54, 51, -1, 44, 38, 18, 33, 24, + 37, 22, 10, 56, 12, -2, 75, 1, -16, 94, -9, -29, + -37, 64, 69, -17, 53, 55, 1, 42, 42, 20, 32, 28, + 40, 21, 14, 58, 10, 1, 78, 0, -12, 96, -10, -25, + -34, 63, 73, -15, 52, 59, 4, 41, 46, 23, 31, 32, + 42, 20, 18, 61, 9, 5, 80, -1, -8, 99, -12, -21, + -32, 61, 77, -12, 50, 64, 6, 40, 50, 25, 29, 37, + 45, 18, 23, 63, 7, 10, 83, -2, -3, 102, -13, -17, + -29, 60, 81, -10, 49, 68, 9, 38, 54, 28, 28, 41, + 47, 17, 27, 66, 6, 14, 85, -4, 0, 104, -14, -13, + -27, 58, 85, -8, 47, 72, 11, 37, 58, 30, 26, 45, + 49, 15, 31, 68, 5, 18, 88, -5, 4, 106, -16, -9, + -25, 57, 89, -5, 46, 76, 14, 36, 62, 32, 25, 49, + 52, 14, 35, 71, 3, 22, 90, -7, 8, 109, -17, -5, + -22, 56, 94, -2, 45, 80, 16, 34, 67, 35, 23, 53, + 54, 12, 39, 73, 2, 26, 93, -8, 12, 111, -19, 0, + -19, 54, 98, 0, 43, 84, 19, 33, 71, 38, 22, 57, + 57, 11, 43, 76, 1, 30, 95, -9, 16, 114, -20, 3, + -17, 53, 102, 2, 42, 88, 21, 31, 75, 40, 21, 61, + 59, 10, 47, 78, 0, 34, 97, -11, 20, 116, -21, 7, + -92, 100, -25, -73, 89, -39, -54, 78, -52, -35, 68, -66, + -16, 57, -80, 3, 46, -93, 22, 35, -107, 41, 25, -120, + -90, 99, -21, -71, 88, -35, -52, 77, -48, -33, 66, -62, + -14, 55, -76, 5, 45, -89, 24, 34, -103, 43, 23, -116, + -88, 97, -17, -68, 86, -31, -49, 76, -44, -31, 65, -58, + -11, 54, -72, 8, 44, -85, 27, 33, -99, 46, 22, -112, + -85, 96, -13, -66, 85, -27, -47, 74, -40, -28, 64, -53, + -9, 53, -67, 10, 42, -81, 30, 31, -94, 48, 20, -108, + -82, 94, -9, -63, 83, -23, -44, 73, -36, -26, 62, -49, + -6, 51, -63, 13, 41, -77, 32, 30, -90, 51, 19, -104, + -80, 93, -5, -61, 82, -19, -42, 71, -32, -23, 61, -45, + -4, 50, -59, 15, 39, -73, 34, 28, -86, 53, 18, -100, + -78, 92, -1, -58, 81, -15, -40, 70, -28, -21, 59, -41, + -1, 49, -55, 17, 38, -69, 37, 27, -82, 56, 16, -96, + -75, 90, 3, -56, 79, -10, -37, 69, -23, -18, 58, -37, + 1, 47, -51, 20, 36, -64, 39, 25, -78, 58, 15, -91, + -73, 89, 7, -53, 78, -6, -34, 67, -19, -16, 57, -33, + 4, 46, -47, 22, 35, -60, 42, 24, -74, 61, 14, -87, + -70, 87, 11, -51, 76, -2, -32, 66, -15, -13, 55, -29, + 6, 44, -43, 25, 34, -56, 44, 23, -70, 63, 12, -83, + -68, 86, 15, -48, 75, 1, -30, 65, -11, -11, 54, -25, + 8, 43, -39, 27, 32, -52, 47, 21, -66, 65, 11, -79, + -65, 85, 19, -46, 74, 5, -27, 63, -7, -9, 53, -21, + 11, 42, -35, 30, 31, -48, 49, 20, -62, 68, 9, -75, + -63, 83, 23, -43, 72, 9, -25, 62, -3, -6, 51, -16, + 14, 40, -30, 32, 30, -44, 52, 19, -57, 70, 8, -71, + -60, 82, 27, -41, 71, 13, -22, 60, 0, -3, 50, -12, + 16, 39, -26, 35, 28, -40, 54, 17, -53, 73, 7, -67, + -58, 80, 31, -39, 70, 17, -20, 59, 4, -1, 48, -8, + 18, 37, -22, 37, 27, -36, 56, 16, -49, 75, 5, -63, + -56, 79, 35, -36, 68, 21, -17, 58, 8, 1, 47, -4, + 21, 36, -18, 40, 25, -32, 59, 15, -45, 78, 4, -59, + -53, 78, 40, -34, 67, 26, -15, 56, 13, 4, 45, 0, + 23, 35, -14, 42, 24, -27, 62, 13, -41, 80, 2, -54, + -51, 76, 44, -31, 65, 30, -12, 55, 17, 6, 44, 3, + 26, 33, -10, 45, 23, -23, 64, 12, -37, 83, 1, -50, + -48, 75, 48, -29, 64, 34, -10, 53, 21, 9, 43, 7, + 28, 32, -6, 47, 21, -19, 66, 10, -33, 85, 0, -46, + -46, 74, 52, -26, 63, 38, -8, 52, 25, 11, 41, 11, + 31, 30, -2, 49, 20, -15, 69, 9, -29, 88, -1, -42, + -43, 72, 56, -24, 61, 42, -5, 51, 29, 14, 40, 16, + 33, 29, 2, 52, 18, -11, 71, 7, -24, 90, -2, -38, + -41, 71, 60, -21, 60, 46, -2, 49, 33, 16, 39, 20, + 36, 28, 6, 54, 17, -7, 74, 6, -20, 93, -4, -34, + -38, 69, 64, -19, 58, 50, 0, 48, 37, 19, 37, 24, + 38, 26, 10, 57, 16, -3, 76, 5, -16, 95, -5, -30, + -36, 68, 68, -16, 57, 54, 2, 46, 41, 21, 36, 28, + 40, 25, 14, 59, 14, 0, 79, 3, -12, 97, -6, -26, + -33, 67, 72, -14, 56, 58, 5, 45, 45, 23, 35, 32, + 43, 24, 18, 62, 13, 4, 81, 2, -8, 100, -8, -22, + -31, 65, 77, -11, 54, 63, 7, 44, 50, 26, 33, 36, + 46, 22, 22, 64, 11, 9, 84, 1, -4, 102, -9, -17, + -28, 64, 81, -9, 53, 67, 10, 42, 54, 29, 32, 40, + 48, 21, 26, 67, 10, 13, 86, 0, 0, 105, -10, -13, + -26, 62, 85, -7, 51, 71, 12, 41, 58, 31, 30, 44, + 50, 19, 30, 69, 9, 17, 88, -1, 3, 107, -12, -9, + -24, 61, 89, -4, 50, 75, 15, 40, 62, 33, 29, 48, + 53, 18, 34, 72, 7, 21, 91, -3, 7, 110, -13, -5, + -21, 60, 93, -2, 49, 79, 17, 38, 66, 36, 27, 53, + 55, 16, 39, 74, 6, 25, 94, -4, 12, 112, -15, -1, + -19, 58, 97, 1, 47, 83, 20, 37, 70, 38, 26, 57, + 58, 15, 43, 77, 5, 29, 96, -5, 16, 115, -16, 2, + -16, 57, 101, 3, 46, 87, 22, 35, 74, 41, 25, 61, + 60, 14, 47, 79, 3, 33, 98, -7, 20, 117, -17, 6, + -91, 104, -26, -72, 93, -40, -53, 82, -53, -35, 72, -67, + -15, 61, -80, 4, 50, -94, 23, 39, -108, 42, 29, -121, + -89, 103, -22, -70, 92, -36, -51, 81, -49, -32, 70, -63, + -13, 59, -76, 6, 49, -90, 25, 38, -104, 44, 27, -117, + -87, 101, -18, -67, 90, -32, -49, 80, -45, -30, 69, -59, + -10, 58, -72, 8, 48, -86, 28, 37, -100, 47, 26, -113, + -84, 100, -13, -65, 89, -27, -46, 78, -41, -27, 68, -54, + -8, 57, -68, 11, 46, -81, 30, 35, -95, 49, 24, -108, + -82, 98, -9, -62, 87, -23, -43, 77, -37, -25, 66, -50, + -5, 55, -64, 14, 45, -77, 33, 34, -91, 52, 23, -104, + -79, 97, -5, -60, 86, -19, -41, 75, -33, -22, 65, -46, + -3, 54, -60, 16, 43, -73, 35, 32, -87, 54, 22, -100, + -77, 96, -1, -57, 85, -15, -39, 74, -29, -20, 63, -42, + 0, 53, -56, 18, 42, -69, 38, 31, -83, 56, 20, -96, + -74, 94, 2, -55, 83, -11, -36, 73, -24, -17, 62, -38, + 2, 51, -51, 21, 40, -65, 40, 29, -79, 59, 19, -92, + -72, 93, 6, -52, 82, -7, -34, 71, -20, -15, 61, -34, + 5, 50, -47, 23, 39, -61, 43, 28, -75, 62, 18, -88, + -69, 91, 10, -50, 80, -3, -31, 70, -16, -12, 59, -30, + 7, 48, -43, 26, 38, -57, 45, 27, -71, 64, 16, -84, + -67, 90, 14, -48, 79, 0, -29, 69, -12, -10, 58, -26, + 9, 47, -39, 28, 36, -53, 48, 25, -67, 66, 15, -80, + -65, 89, 18, -45, 78, 4, -26, 67, -8, -8, 57, -22, + 12, 46, -35, 31, 35, -49, 50, 24, -63, 69, 13, -76, + -62, 87, 23, -42, 76, 9, -24, 66, -4, -5, 55, -17, + 14, 44, -31, 33, 34, -44, 53, 23, -58, 71, 12, -71, + -59, 86, 27, -40, 75, 13, -21, 64, 0, -3, 54, -13, + 17, 43, -27, 36, 32, -40, 55, 21, -54, 74, 11, -67, + -57, 84, 31, -38, 74, 17, -19, 63, 3, 0, 52, -9, + 19, 41, -23, 38, 31, -36, 57, 20, -50, 76, 9, -63, + -55, 83, 35, -35, 72, 21, -17, 62, 7, 2, 51, -5, + 22, 40, -19, 40, 29, -32, 60, 19, -46, 79, 8, -59, + -52, 82, 39, -33, 71, 25, -14, 60, 12, 5, 49, -1, + 24, 39, -14, 43, 28, -28, 62, 17, -42, 81, 6, -55, + -50, 80, 43, -30, 69, 29, -11, 59, 16, 7, 48, 2, + 27, 37, -10, 46, 27, -24, 65, 16, -38, 84, 5, -51, + -47, 79, 47, -28, 68, 33, -9, 57, 20, 10, 47, 6, + 29, 36, -6, 48, 25, -20, 67, 14, -34, 86, 4, -47, + -45, 78, 51, -25, 67, 37, -7, 56, 24, 12, 45, 10, + 32, 34, -2, 50, 24, -16, 70, 13, -30, 88, 2, -43, + -42, 76, 56, -23, 65, 42, -4, 55, 28, 15, 44, 15, + 34, 33, 1, 53, 22, -11, 72, 11, -25, 91, 1, -38, + -40, 75, 60, -20, 64, 46, -2, 53, 32, 17, 43, 19, + 37, 32, 5, 55, 21, -7, 75, 10, -21, 94, 0, -34, + -37, 73, 64, -18, 62, 50, 1, 52, 36, 20, 41, 23, + 39, 30, 9, 58, 20, -3, 77, 9, -17, 96, -1, -30, + -35, 72, 68, -16, 61, 54, 3, 50, 40, 22, 40, 27, + 41, 29, 13, 60, 18, 0, 80, 7, -13, 98, -2, -26, + -33, 71, 72, -13, 60, 58, 6, 49, 44, 24, 39, 31, + 44, 28, 17, 63, 17, 4, 82, 6, -9, 101, -4, -22, + -30, 69, 76, -10, 58, 62, 8, 48, 49, 27, 37, 35, + 46, 26, 22, 65, 15, 8, 85, 5, -5, 103, -5, -18, + -27, 68, 80, -8, 57, 66, 11, 46, 53, 29, 36, 39, + 49, 25, 26, 68, 14, 12, 87, 3, -1, 106, -6, -14, + -25, 66, 84, -6, 55, 70, 13, 45, 57, 32, 34, 43, + 51, 23, 30, 70, 13, 16, 89, 2, 2, 108, -8, -10, + -23, 65, 88, -3, 54, 74, 15, 44, 61, 34, 33, 47, + 54, 22, 34, 72, 11, 20, 92, 0, 6, 111, -9, -6, + -20, 64, 93, -1, 53, 79, 18, 42, 65, 37, 31, 52, + 56, 20, 38, 75, 10, 25, 94, 0, 11, 113, -11, -1, + -18, 62, 97, 2, 51, 83, 21, 41, 69, 39, 30, 56, + 59, 19, 42, 77, 9, 29, 97, -1, 15, 116, -12, 2, + -15, 61, 101, 4, 50, 87, 23, 39, 73, 42, 29, 60, + 61, 18, 46, 80, 7, 33, 99, -3, 19, 118, -13, 6, + -91, 108, -27, -71, 97, -40, -52, 86, -54, -34, 76, -67, + -14, 65, -81, 5, 54, -94, 24, 43, -108, 43, 33, -122, + -88, 107, -23, -69, 96, -36, -50, 85, -50, -31, 74, -63, + -12, 63, -77, 7, 53, -90, 26, 42, -104, 45, 31, -118, + -86, 105, -19, -66, 94, -32, -48, 84, -46, -29, 73, -59, + -9, 62, -73, 9, 52, -86, 29, 41, -100, 47, 30, -114, + -83, 104, -14, -64, 93, -28, -45, 82, -41, -26, 72, -55, + -7, 61, -69, 12, 50, -82, 31, 39, -96, 50, 28, -109, + -81, 102, -10, -61, 91, -24, -43, 81, -37, -24, 70, -51, + -4, 59, -65, 14, 49, -78, 34, 38, -92, 53, 27, -105, + -78, 101, -6, -59, 90, -20, -40, 79, -33, -21, 69, -47, + -2, 58, -61, 17, 47, -74, 36, 36, -88, 55, 26, -101, + -76, 100, -2, -57, 89, -16, -38, 78, -29, -19, 67, -43, + 0, 57, -57, 19, 46, -70, 39, 35, -84, 57, 24, -97, + -73, 98, 1, -54, 87, -11, -35, 77, -25, -16, 66, -38, + 3, 55, -52, 22, 44, -65, 41, 33, -79, 60, 23, -93, + -71, 97, 5, -51, 86, -7, -33, 75, -21, -14, 65, -34, + 6, 54, -48, 24, 43, -61, 44, 32, -75, 62, 22, -89, + -68, 95, 9, -49, 84, -3, -30, 74, -17, -11, 63, -30, + 8, 52, -44, 27, 42, -57, 46, 31, -71, 65, 20, -85, + -66, 94, 13, -47, 83, 0, -28, 73, -13, -9, 62, -26, + 10, 51, -40, 29, 40, -53, 48, 29, -67, 67, 19, -81, + -64, 93, 17, -44, 82, 4, -25, 71, -9, -7, 61, -22, + 13, 50, -36, 31, 39, -49, 51, 28, -63, 70, 17, -77, + -61, 91, 22, -42, 80, 8, -23, 70, -4, -4, 59, -18, + 15, 48, -32, 34, 38, -45, 54, 27, -59, 72, 16, -72, + -59, 90, 26, -39, 79, 12, -20, 68, 0, -2, 58, -14, + 18, 47, -28, 37, 36, -41, 56, 25, -55, 75, 15, -68, + -56, 88, 30, -37, 78, 16, -18, 67, 3, 1, 56, -10, + 20, 45, -24, 39, 35, -37, 58, 24, -51, 77, 13, -64, + -54, 87, 34, -34, 76, 20, -16, 66, 7, 3, 55, -6, + 23, 44, -20, 41, 33, -33, 61, 23, -47, 79, 12, -60, + -51, 86, 38, -32, 75, 25, -13, 64, 11, 6, 53, -1, + 25, 43, -15, 44, 32, -28, 63, 21, -42, 82, 10, -56, + -49, 84, 42, -29, 73, 29, -11, 63, 15, 8, 52, 2, + 28, 41, -11, 46, 31, -24, 66, 20, -38, 85, 9, -52, + -46, 83, 46, -27, 72, 33, -8, 61, 19, 11, 51, 6, + 30, 40, -7, 49, 29, -20, 68, 18, -34, 87, 8, -48, + -44, 82, 50, -25, 71, 37, -6, 60, 23, 13, 49, 10, + 32, 38, -3, 51, 28, -16, 71, 17, -30, 89, 6, -44, + -41, 80, 55, -22, 69, 41, -3, 59, 28, 16, 48, 14, + 35, 37, 0, 54, 26, -12, 73, 15, -26, 92, 5, -39, + -39, 79, 59, -19, 68, 45, -1, 57, 32, 18, 47, 18, + 37, 36, 4, 56, 25, -8, 76, 14, -22, 94, 3, -35, + -36, 77, 63, -17, 66, 49, 2, 56, 36, 21, 45, 22, + 40, 34, 8, 59, 24, -4, 78, 13, -18, 97, 2, -31, + -34, 76, 67, -15, 65, 53, 4, 54, 40, 23, 44, 26, + 42, 33, 12, 61, 22, 0, 80, 11, -14, 99, 1, -27, + -32, 75, 71, -12, 64, 57, 7, 53, 44, 25, 43, 30, + 45, 32, 16, 63, 21, 3, 83, 10, -10, 102, 0, -23, + -29, 73, 75, -10, 62, 62, 9, 52, 48, 28, 41, 35, + 47, 30, 21, 66, 19, 8, 86, 9, -5, 104, -1, -19, + -27, 72, 79, -7, 61, 66, 12, 50, 52, 30, 40, 39, + 50, 29, 25, 69, 18, 12, 88, 7, -1, 107, -2, -15, + -24, 70, 83, -5, 59, 70, 14, 49, 56, 33, 38, 43, + 52, 27, 29, 71, 17, 16, 90, 6, 2, 109, -4, -11, + -22, 69, 87, -2, 58, 74, 16, 48, 60, 35, 37, 47, + 55, 26, 33, 73, 15, 20, 93, 4, 6, 111, -5, -7, + -19, 68, 92, 0, 57, 78, 19, 46, 65, 38, 35, 51, + 57, 24, 37, 76, 14, 24, 95, 3, 10, 114, -7, -2, + -17, 66, 96, 3, 55, 82, 21, 45, 69, 40, 34, 55, + 60, 23, 41, 78, 13, 28, 98, 2, 14, 117, -8, 1, + -14, 65, 100, 5, 54, 86, 24, 43, 73, 43, 33, 59, + 62, 22, 45, 81, 11, 32, 100, 0, 18, 119, -9, 5, + -90, 112, -27, -70, 101, -41, -51, 91, -55, -33, 80, -68, + -13, 69, -82, 6, 59, -95, 25, 48, -109, 44, 37, -122, + -87, 111, -23, -68, 100, -37, -49, 89, -51, -30, 79, -64, + -11, 68, -78, 8, 57, -91, 27, 46, -105, 46, 36, -118, + -85, 110, -19, -65, 99, -33, -47, 88, -47, -28, 78, -60, + -8, 67, -74, 10, 56, -87, 30, 45, -101, 49, 34, -114, + -82, 108, -15, -63, 97, -29, -44, 87, -42, -25, 76, -55, + -6, 65, -69, 13, 54, -83, 32, 44, -96, 51, 33, -110, + -80, 107, -11, -60, 96, -25, -41, 85, -38, -23, 75, -51, + -3, 64, -65, 15, 53, -79, 35, 42, -92, 54, 32, -106, + -77, 105, -7, -58, 95, -21, -39, 84, -34, -20, 73, -47, + -1, 62, -61, 18, 52, -75, 37, 41, -88, 56, 30, -102, + -75, 104, -3, -55, 93, -17, -37, 83, -30, -18, 72, -43, + 1, 61, -57, 20, 50, -71, 40, 40, -84, 58, 29, -98, + -72, 103, 1, -53, 92, -12, -34, 81, -26, -15, 70, -39, + 4, 60, -53, 23, 49, -66, 42, 38, -80, 61, 27, -93, + -70, 101, 5, -50, 90, -8, -32, 80, -22, -13, 69, -35, + 7, 58, -49, 25, 48, -62, 45, 37, -76, 63, 26, -89, + -67, 100, 9, -48, 89, -4, -29, 78, -18, -10, 68, -31, + 9, 57, -45, 28, 46, -58, 47, 35, -72, 66, 25, -85, + -65, 99, 13, -46, 88, 0, -27, 77, -14, -8, 66, -27, + 11, 55, -41, 30, 45, -54, 49, 34, -68, 68, 23, -81, + -63, 97, 17, -43, 86, 3, -24, 76, -10, -6, 65, -23, + 14, 54, -37, 32, 44, -50, 52, 33, -64, 71, 22, -77, + -60, 96, 21, -41, 85, 7, -22, 74, -5, -3, 64, -18, + 16, 53, -32, 35, 42, -46, 55, 31, -59, 73, 20, -73, + -58, 94, 25, -38, 83, 11, -19, 73, -1, -1, 62, -14, + 19, 51, -28, 38, 41, -42, 57, 30, -55, 76, 19, -69, + -55, 93, 29, -36, 82, 15, -17, 71, 2, 2, 61, -10, + 21, 50, -24, 40, 39, -38, 59, 28, -51, 78, 18, -65, + -53, 92, 33, -33, 81, 19, -15, 70, 6, 4, 59, -6, + 24, 49, -20, 42, 38, -34, 62, 27, -47, 81, 16, -61, + -50, 90, 38, -31, 79, 24, -12, 69, 10, 7, 58, -2, + 26, 47, -16, 45, 36, -29, 64, 26, -43, 83, 15, -56, + -48, 89, 42, -28, 78, 28, -9, 67, 14, 9, 57, 1, + 29, 46, -12, 47, 35, -25, 67, 24, -39, 86, 14, -52, + -45, 87, 46, -26, 76, 32, -7, 66, 18, 12, 55, 5, + 31, 44, -8, 50, 34, -21, 69, 23, -35, 88, 12, -48, + -43, 86, 50, -23, 75, 36, -5, 65, 22, 14, 54, 9, + 33, 43, -4, 52, 32, -17, 72, 21, -31, 90, 11, -44, + -40, 85, 54, -21, 74, 40, -2, 63, 27, 17, 52, 14, + 36, 41, 0, 55, 31, -13, 74, 20, -26, 93, 9, -40, + -38, 83, 58, -18, 72, 44, 0, 62, 31, 19, 51, 18, + 39, 40, 4, 57, 30, -9, 77, 19, -22, 95, 8, -36, + -35, 82, 62, -16, 71, 48, 3, 60, 35, 22, 50, 22, + 41, 39, 8, 60, 28, -5, 79, 17, -18, 98, 7, -32, + -33, 80, 66, -14, 70, 52, 5, 59, 39, 24, 48, 26, + 43, 37, 12, 62, 27, -1, 81, 16, -14, 100, 5, -28, + -31, 79, 70, -11, 68, 56, 8, 58, 43, 26, 47, 30, + 46, 36, 16, 64, 25, 2, 84, 15, -10, 103, 4, -24, + -28, 78, 75, -9, 67, 61, 10, 56, 47, 29, 45, 34, + 48, 35, 20, 67, 24, 7, 87, 13, -6, 105, 2, -19, + -26, 76, 79, -6, 65, 65, 13, 55, 51, 31, 44, 38, + 51, 33, 24, 70, 23, 11, 89, 12, -2, 108, 1, -15, + -23, 75, 83, -4, 64, 69, 15, 53, 55, 34, 43, 42, + 53, 32, 28, 72, 21, 15, 91, 10, 1, 110, 0, -11, + -21, 74, 87, -1, 63, 73, 17, 52, 59, 36, 41, 46, + 56, 31, 32, 74, 20, 19, 94, 9, 5, 113, -1, -7, + -18, 72, 91, 1, 61, 77, 20, 51, 64, 39, 40, 51, + 58, 29, 37, 77, 18, 23, 96, 7, 10, 115, -2, -3, + -16, 71, 95, 4, 60, 81, 22, 49, 68, 41, 39, 55, + 61, 28, 41, 79, 17, 27, 99, 6, 14, 118, -4, 0, + -13, 69, 99, 6, 58, 85, 25, 48, 72, 44, 37, 59, + 63, 26, 45, 82, 16, 31, 101, 5, 18, 120, -5, 4, + -89, 116, -28, -69, 105, -42, -50, 95, -55, -32, 84, -69, + -12, 73, -82, 6, 63, -96, 26, 52, -110, 45, 41, -123, + -86, 115, -24, -67, 104, -38, -48, 93, -51, -29, 83, -65, + -10, 72, -78, 9, 61, -92, 28, 50, -106, 47, 40, -119, + -84, 114, -20, -64, 103, -34, -46, 92, -47, -27, 82, -61, + -8, 71, -74, 11, 60, -88, 31, 49, -102, 49, 38, -115, + -81, 112, -15, -62, 101, -29, -43, 91, -43, -24, 80, -56, + -5, 69, -70, 14, 58, -83, 33, 48, -97, 52, 37, -111, + -79, 111, -11, -59, 100, -25, -41, 89, -39, -22, 79, -52, + -2, 68, -66, 16, 57, -79, 36, 46, -93, 55, 36, -107, + -76, 109, -7, -57, 99, -21, -38, 88, -35, -19, 77, -48, + 0, 66, -62, 19, 56, -75, 38, 45, -89, 57, 34, -103, + -74, 108, -3, -55, 97, -17, -36, 87, -31, -17, 76, -44, + 2, 65, -58, 21, 54, -71, 41, 44, -85, 59, 33, -99, + -71, 107, 0, -52, 96, -13, -33, 85, -26, -14, 74, -40, + 5, 64, -53, 24, 53, -67, 43, 42, -81, 62, 31, -94, + -69, 105, 4, -49, 94, -9, -31, 84, -22, -12, 73, -36, + 7, 62, -49, 26, 52, -63, 46, 41, -77, 64, 30, -90, + -66, 104, 8, -47, 93, -5, -28, 82, -18, -10, 72, -32, + 10, 61, -45, 29, 50, -59, 48, 39, -73, 67, 29, -86, + -64, 103, 12, -45, 92, -1, -26, 81, -14, -7, 70, -28, + 12, 59, -41, 31, 49, -55, 50, 38, -69, 69, 27, -82, + -62, 101, 16, -42, 90, 2, -24, 80, -10, -5, 69, -24, + 15, 58, -37, 33, 48, -51, 53, 37, -65, 72, 26, -78, + -59, 100, 21, -40, 89, 7, -21, 78, -6, -2, 68, -19, + 17, 57, -33, 36, 46, -46, 55, 35, -60, 74, 24, -74, + -57, 98, 25, -37, 87, 11, -18, 77, -2, 0, 66, -15, + 20, 55, -29, 38, 45, -42, 58, 34, -56, 77, 23, -70, + -54, 97, 29, -35, 86, 15, -16, 75, 1, 3, 65, -11, + 22, 54, -25, 41, 43, -38, 60, 32, -52, 79, 22, -66, + -52, 96, 33, -32, 85, 19, -14, 74, 5, 5, 63, -7, + 24, 53, -21, 43, 42, -34, 63, 31, -48, 81, 20, -62, + -49, 94, 37, -30, 83, 23, -11, 73, 10, 8, 62, -3, + 27, 51, -16, 46, 40, -30, 65, 30, -44, 84, 19, -57, + -47, 93, 41, -27, 82, 27, -9, 71, 14, 10, 61, 0, + 30, 50, -12, 48, 39, -26, 68, 28, -40, 87, 18, -53, + -44, 91, 45, -25, 80, 31, -6, 70, 18, 13, 59, 4, + 32, 48, -8, 51, 38, -22, 70, 27, -36, 89, 16, -49, + -42, 90, 49, -23, 79, 35, -4, 69, 22, 15, 58, 8, + 34, 47, -4, 53, 36, -18, 73, 25, -32, 91, 15, -45, + -39, 89, 54, -20, 78, 40, -1, 67, 26, 18, 56, 13, + 37, 45, 0, 56, 35, -13, 75, 24, -27, 94, 13, -41, + -37, 87, 58, -18, 76, 44, 1, 66, 30, 20, 55, 17, + 39, 44, 3, 58, 34, -9, 78, 23, -23, 96, 12, -37, + -34, 86, 62, -15, 75, 48, 4, 64, 34, 22, 54, 21, + 42, 43, 7, 61, 32, -5, 80, 21, -19, 99, 11, -33, + -32, 84, 66, -13, 74, 52, 6, 63, 38, 25, 52, 25, + 44, 41, 11, 63, 31, -1, 82, 20, -15, 101, 9, -29, + -30, 83, 70, -10, 72, 56, 8, 62, 42, 27, 51, 29, + 47, 40, 15, 65, 29, 2, 85, 19, -11, 104, 8, -25, + -27, 82, 74, -8, 71, 60, 11, 60, 47, 30, 49, 33, + 49, 39, 20, 68, 28, 6, 87, 17, -7, 106, 6, -20, + -25, 80, 78, -5, 69, 64, 14, 59, 51, 32, 48, 37, + 52, 37, 24, 70, 27, 10, 90, 16, -3, 109, 5, -16, + -22, 79, 82, -3, 68, 68, 16, 57, 55, 35, 47, 41, + 54, 36, 28, 73, 25, 14, 92, 14, 0, 111, 4, -12, + -20, 78, 86, 0, 67, 72, 18, 56, 59, 37, 45, 45, + 56, 35, 32, 75, 24, 18, 95, 13, 4, 113, 2, -8, + -17, 76, 91, 2, 65, 77, 21, 55, 63, 40, 44, 50, + 59, 33, 36, 78, 22, 23, 97, 11, 9, 116, 1, -4, + -15, 75, 95, 5, 64, 81, 23, 53, 67, 42, 43, 54, + 62, 32, 40, 80, 21, 27, 100, 10, 13, 119, 0, 0, + -12, 73, 99, 7, 62, 85, 26, 52, 71, 45, 41, 58, + 64, 30, 44, 83, 20, 31, 102, 9, 17, 121, -1, 4, + -88, 120, -29, -68, 109, -42, -50, 99, -56, -31, 88, -69, + -11, 77, -83, 7, 67, -96, 27, 56, -110, 46, 45, -124, + -85, 119, -25, -66, 108, -38, -47, 97, -52, -28, 87, -65, + -9, 76, -79, 10, 65, -92, 29, 54, -106, 48, 44, -120, + -83, 118, -21, -64, 107, -34, -45, 96, -48, -26, 86, -61, + -7, 75, -75, 12, 64, -88, 32, 53, -102, 50, 42, -116, + -80, 116, -16, -61, 105, -30, -42, 95, -43, -23, 84, -57, + -4, 73, -71, 15, 62, -84, 34, 52, -98, 53, 41, -111, + -78, 115, -12, -58, 104, -26, -40, 93, -39, -21, 83, -53, + -2, 72, -67, 17, 61, -80, 37, 50, -94, 55, 40, -107, + -75, 113, -8, -56, 103, -22, -37, 92, -35, -18, 81, -49, + 1, 70, -63, 20, 60, -76, 39, 49, -90, 58, 38, -103, + -73, 112, -4, -54, 101, -18, -35, 91, -31, -16, 80, -45, + 3, 69, -59, 22, 58, -72, 41, 48, -86, 60, 37, -99, + -70, 111, 0, -51, 100, -13, -32, 89, -27, -13, 78, -40, + 6, 68, -54, 25, 57, -67, 44, 46, -81, 63, 35, -95, + -68, 109, 3, -49, 98, -9, -30, 88, -23, -11, 77, -36, + 8, 66, -50, 27, 56, -63, 47, 45, -77, 65, 34, -91, + -66, 108, 7, -46, 97, -5, -27, 86, -19, -9, 76, -32, + 11, 65, -46, 30, 54, -59, 49, 43, -73, 68, 33, -87, + -63, 107, 11, -44, 96, -1, -25, 85, -15, -6, 74, -28, + 13, 63, -42, 32, 53, -55, 51, 42, -69, 70, 31, -83, + -61, 105, 15, -41, 94, 2, -23, 84, -11, -4, 73, -24, + 16, 62, -38, 34, 52, -51, 54, 41, -65, 72, 30, -79, + -58, 104, 20, -39, 93, 6, -20, 82, -6, -1, 72, -20, + 18, 61, -34, 37, 50, -47, 56, 39, -61, 75, 28, -74, + -56, 102, 24, -36, 91, 10, -18, 81, -2, 1, 70, -16, + 21, 59, -30, 39, 49, -43, 59, 38, -57, 78, 27, -70, + -53, 101, 28, -34, 90, 14, -15, 79, 1, 4, 69, -12, + 23, 58, -26, 42, 47, -39, 61, 36, -53, 80, 26, -66, + -51, 100, 32, -32, 89, 18, -13, 78, 5, 6, 67, -8, + 25, 57, -22, 44, 46, -35, 64, 35, -49, 82, 24, -62, + -48, 98, 36, -29, 87, 23, -10, 77, 9, 9, 66, -3, + 28, 55, -17, 47, 44, -30, 66, 34, -44, 85, 23, -58, + -46, 97, 40, -26, 86, 27, -8, 75, 13, 11, 65, 0, + 30, 54, -13, 49, 43, -26, 69, 32, -40, 87, 22, -54, + -43, 95, 44, -24, 84, 31, -5, 74, 17, 14, 63, 4, + 33, 52, -9, 52, 42, -22, 71, 31, -36, 90, 20, -50, + -41, 94, 48, -22, 83, 35, -3, 73, 21, 16, 62, 8, + 35, 51, -5, 54, 40, -18, 73, 29, -32, 92, 19, -46, + -38, 93, 53, -19, 82, 39, 0, 71, 26, 19, 60, 12, + 38, 49, -1, 57, 39, -14, 76, 28, -28, 95, 17, -41, + -36, 91, 57, -17, 80, 43, 2, 70, 30, 21, 59, 16, + 40, 48, 2, 59, 38, -10, 79, 27, -24, 97, 16, -37, + -34, 90, 61, -14, 79, 47, 5, 68, 34, 23, 58, 20, + 43, 47, 6, 62, 36, -6, 81, 25, -20, 100, 15, -33, + -31, 88, 65, -12, 78, 51, 7, 67, 38, 26, 56, 24, + 45, 45, 10, 64, 35, -2, 83, 24, -16, 102, 13, -29, + -29, 87, 69, -9, 76, 55, 9, 66, 42, 28, 55, 28, + 48, 44, 14, 66, 33, 1, 86, 23, -12, 104, 12, -25, + -26, 86, 73, -7, 75, 60, 12, 64, 46, 31, 53, 33, + 50, 43, 19, 69, 32, 6, 88, 21, -7, 107, 10, -21, + -24, 84, 77, -4, 73, 64, 14, 63, 50, 33, 52, 37, + 53, 41, 23, 71, 31, 10, 91, 20, -3, 110, 9, -17, + -21, 83, 81, -2, 72, 68, 17, 61, 54, 36, 51, 41, + 55, 40, 27, 74, 29, 14, 93, 18, 0, 112, 8, -13, + -19, 82, 85, 0, 71, 72, 19, 60, 58, 38, 49, 45, + 57, 39, 31, 76, 28, 18, 96, 17, 4, 114, 6, -9, + -16, 80, 90, 3, 69, 76, 22, 59, 63, 41, 48, 49, + 60, 37, 35, 79, 26, 22, 98, 15, 8, 117, 5, -4, + -14, 79, 94, 6, 68, 80, 24, 57, 67, 43, 47, 53, + 62, 36, 39, 81, 25, 26, 101, 14, 12, 119, 4, 0, + -11, 77, 98, 8, 66, 84, 27, 56, 71, 45, 45, 57, + 65, 34, 43, 84, 24, 30, 103, 13, 16, 122, 2, 3, + -114, -7, -10, -95, -18, -23, -76, -29, -37, -57, -40, -50, + -38, -51, -64, -19, -61, -77, 0, -72, -91, 19, -83, -105, + -112, -9, -6, -93, -20, -19, -74, -30, -33, -55, -41, -46, + -36, -52, -60, -17, -62, -73, 2, -73, -87, 21, -84, -101, + -110, -10, -2, -90, -21, -15, -71, -32, -29, -53, -42, -42, + -33, -53, -56, -15, -64, -69, 5, -75, -83, 24, -85, -97, + -107, -12, 2, -88, -23, -11, -69, -33, -24, -50, -44, -38, + -31, -55, -51, -12, -65, -65, 8, -76, -79, 26, -87, -92, + -105, -13, 6, -85, -24, -7, -66, -35, -20, -48, -45, -34, + -28, -56, -47, -9, -67, -61, 10, -78, -75, 29, -88, -88, + -102, -14, 10, -83, -25, -3, -64, -36, -16, -45, -47, -30, + -26, -57, -43, -7, -68, -57, 12, -79, -71, 31, -90, -84, + -100, -16, 14, -80, -27, 0, -62, -37, -12, -43, -48, -26, + -23, -59, -39, -5, -69, -53, 15, -80, -67, 33, -91, -80, + -97, -17, 18, -78, -28, 5, -59, -39, -8, -40, -49, -21, + -21, -60, -35, -2, -71, -48, 17, -82, -62, 36, -92, -76, + -95, -19, 22, -75, -30, 9, -57, -40, -4, -38, -51, -17, + -18, -62, -31, 0, -72, -44, 20, -83, -58, 39, -94, -72, + -92, -20, 26, -73, -31, 13, -54, -41, 0, -35, -52, -13, + -16, -63, -27, 3, -74, -40, 22, -85, -54, 41, -95, -68, + -90, -21, 30, -71, -32, 17, -52, -43, 3, -33, -53, -9, + -14, -64, -23, 5, -75, -36, 25, -86, -50, 43, -96, -64, + -88, -23, 34, -68, -34, 21, -49, -44, 7, -31, -55, -5, + -11, -66, -19, 8, -76, -32, 27, -87, -46, 46, -98, -60, + -85, -24, 39, -65, -35, 25, -47, -46, 12, -28, -56, -1, + -9, -67, -14, 10, -78, -28, 30, -89, -42, 48, -99, -55, + -82, -26, 43, -63, -36, 29, -44, -47, 16, -25, -58, 2, + -6, -69, -10, 13, -79, -24, 32, -90, -38, 51, -101, -51, + -80, -27, 47, -61, -38, 33, -42, -48, 20, -23, -59, 6, + -4, -70, -6, 15, -81, -20, 34, -91, -34, 53, -102, -47, + -78, -28, 51, -58, -39, 37, -39, -50, 24, -21, -60, 10, + -1, -71, -2, 17, -82, -16, 37, -93, -30, 56, -103, -43, + -75, -30, 55, -56, -41, 42, -37, -51, 28, -18, -62, 15, + 1, -73, 1, 20, -83, -11, 40, -94, -25, 58, -105, -39, + -73, -31, 59, -53, -42, 46, -34, -53, 32, -16, -63, 19, + 4, -74, 5, 23, -85, -7, 42, -96, -21, 61, -106, -35, + -70, -32, 63, -51, -43, 50, -32, -54, 36, -13, -65, 23, + 6, -75, 9, 25, -86, -3, 44, -97, -17, 63, -108, -31, + -68, -34, 67, -48, -45, 54, -30, -55, 40, -11, -66, 27, + 9, -77, 13, 27, -87, 0, 47, -98, -13, 65, -109, -27, + -65, -35, 72, -46, -46, 58, -27, -57, 45, -8, -67, 31, + 11, -78, 18, 30, -89, 4, 49, -100, -9, 68, -110, -22, + -63, -37, 76, -43, -48, 62, -25, -58, 49, -6, -69, 35, + 14, -80, 22, 32, -90, 8, 52, -101, -5, 71, -112, -18, + -60, -38, 80, -41, -49, 66, -22, -60, 53, -3, -70, 39, + 16, -81, 26, 35, -92, 12, 54, -103, -1, 73, -113, -14, + -58, -39, 84, -39, -50, 70, -20, -61, 57, -1, -71, 43, + 18, -82, 30, 37, -93, 16, 57, -104, 2, 75, -115, -10, + -56, -41, 88, -36, -52, 74, -17, -62, 61, 1, -73, 47, + 21, -84, 34, 40, -94, 20, 59, -105, 6, 78, -116, -6, + -53, -42, 92, -33, -53, 79, -15, -64, 65, 4, -74, 52, + 23, -85, 38, 42, -96, 25, 62, -107, 11, 80, -117, -2, + -50, -44, 96, -31, -54, 83, -12, -65, 69, 7, -76, 56, + 26, -87, 42, 45, -97, 29, 64, -108, 15, 83, -119, 1, + -48, -45, 100, -29, -56, 87, -10, -66, 73, 9, -77, 60, + 28, -88, 46, 47, -99, 33, 66, -110, 19, 85, -120, 5, + -46, -46, 104, -26, -57, 91, -7, -68, 77, 11, -78, 64, + 31, -89, 50, 49, -100, 37, 69, -111, 23, 88, -121, 9, + -43, -48, 109, -24, -59, 95, -5, -69, 82, 14, -80, 68, + 33, -91, 55, 52, -101, 41, 72, -112, 27, 90, -123, 14, + -41, -49, 113, -21, -60, 99, -2, -71, 86, 16, -81, 72, + 36, -92, 59, 55, -103, 45, 74, -114, 31, 93, -124, 18, + -38, -50, 117, -19, -61, 103, 0, -72, 90, 19, -83, 76, + 38, -94, 63, 57, -104, 49, 76, -115, 35, 95, -126, 22, + -113, -3, -10, -94, -14, -24, -75, -25, -37, -57, -36, -51, + -37, -47, -65, -18, -57, -78, 1, -68, -92, 20, -79, -105, + -111, -5, -6, -92, -16, -20, -73, -26, -33, -54, -37, -47, + -35, -48, -61, -16, -58, -74, 3, -69, -88, 22, -80, -101, + -109, -6, -2, -89, -17, -16, -71, -28, -29, -52, -38, -43, + -32, -49, -57, -14, -60, -70, 6, -71, -84, 25, -81, -97, + -106, -8, 1, -87, -19, -12, -68, -29, -25, -49, -40, -38, + -30, -51, -52, -11, -61, -66, 8, -72, -79, 27, -83, -93, + -104, -9, 5, -84, -20, -8, -65, -31, -21, -47, -41, -34, + -27, -52, -48, -9, -63, -62, 11, -74, -75, 30, -84, -89, + -101, -10, 9, -82, -21, -4, -63, -32, -17, -44, -43, -30, + -25, -53, -44, -6, -64, -58, 13, -75, -71, 32, -86, -85, + -99, -12, 13, -79, -23, 0, -61, -33, -13, -42, -44, -26, + -23, -55, -40, -4, -65, -54, 16, -76, -67, 34, -87, -81, + -96, -13, 18, -77, -24, 4, -58, -35, -8, -39, -45, -22, + -20, -56, -36, -1, -67, -49, 18, -78, -63, 37, -88, -76, + -94, -15, 22, -74, -26, 8, -56, -36, -4, -37, -47, -18, + -17, -58, -32, 1, -68, -45, 21, -79, -59, 39, -90, -72, + -91, -16, 26, -72, -27, 12, -53, -37, 0, -34, -48, -14, + -15, -59, -28, 4, -70, -41, 23, -81, -55, 42, -91, -68, + -89, -17, 30, -70, -28, 16, -51, -39, 3, -32, -49, -10, + -13, -60, -24, 6, -71, -37, 25, -82, -51, 44, -92, -64, + -87, -19, 34, -67, -30, 20, -48, -40, 7, -30, -51, -6, + -10, -62, -20, 9, -72, -33, 28, -83, -47, 47, -94, -60, + -84, -20, 38, -65, -31, 24, -46, -42, 11, -27, -52, -1, + -8, -63, -15, 11, -74, -29, 31, -85, -42, 49, -95, -56, + -82, -22, 42, -62, -32, 28, -43, -43, 15, -25, -54, 2, + -5, -65, -11, 14, -75, -25, 33, -86, -38, 52, -97, -52, + -79, -23, 46, -60, -34, 32, -41, -44, 19, -22, -55, 6, + -3, -66, -7, 16, -77, -21, 35, -87, -34, 54, -98, -48, + -77, -24, 50, -57, -35, 36, -39, -46, 23, -20, -56, 10, + 0, -67, -3, 18, -78, -17, 38, -89, -30, 57, -99, -44, + -74, -26, 55, -55, -37, 41, -36, -47, 28, -17, -58, 14, + 2, -69, 0, 21, -79, -12, 40, -90, -26, 59, -101, -39, + -72, -27, 59, -52, -38, 45, -33, -49, 32, -15, -59, 18, + 5, -70, 4, 23, -81, -8, 43, -92, -22, 62, -102, -35, + -69, -28, 63, -50, -39, 49, -31, -50, 36, -12, -61, 22, + 7, -71, 8, 26, -82, -4, 45, -93, -18, 64, -104, -31, + -67, -30, 67, -47, -41, 53, -29, -51, 40, -10, -62, 26, + 9, -73, 12, 28, -83, 0, 48, -94, -14, 66, -105, -27, + -64, -31, 71, -45, -42, 57, -26, -53, 44, -7, -63, 31, + 12, -74, 17, 31, -85, 3, 50, -96, -9, 69, -106, -23, + -62, -33, 75, -42, -44, 61, -24, -54, 48, -5, -65, 35, + 15, -76, 21, 33, -86, 7, 53, -97, -5, 71, -108, -19, + -59, -34, 79, -40, -45, 65, -21, -56, 52, -2, -66, 39, + 17, -77, 25, 36, -88, 11, 55, -99, -1, 74, -109, -15, + -57, -35, 83, -38, -46, 69, -19, -57, 56, 0, -67, 43, + 19, -78, 29, 38, -89, 15, 57, -100, 2, 76, -111, -11, + -55, -37, 87, -35, -48, 73, -16, -58, 60, 2, -69, 47, + 22, -80, 33, 40, -90, 19, 60, -101, 6, 79, -112, -7, + -52, -38, 92, -33, -49, 78, -14, -60, 65, 5, -70, 51, + 24, -81, 37, 43, -92, 24, 63, -103, 10, 81, -113, -2, + -50, -40, 96, -30, -50, 82, -11, -61, 69, 7, -72, 55, + 27, -83, 41, 46, -93, 28, 65, -104, 14, 84, -115, 1, + -47, -41, 100, -28, -52, 86, -9, -62, 73, 10, -73, 59, + 29, -84, 45, 48, -95, 32, 67, -106, 18, 86, -116, 5, + -45, -42, 104, -25, -53, 90, -7, -64, 77, 12, -74, 63, + 32, -85, 49, 50, -96, 36, 70, -107, 22, 89, -117, 9, + -42, -44, 108, -23, -55, 94, -4, -65, 81, 15, -76, 68, + 34, -87, 54, 53, -97, 40, 72, -108, 27, 91, -119, 13, + -40, -45, 112, -20, -56, 98, -1, -67, 85, 17, -77, 72, + 37, -88, 58, 55, -99, 44, 75, -110, 31, 94, -120, 17, + -37, -46, 116, -18, -57, 102, 1, -68, 89, 20, -79, 76, + 39, -90, 62, 58, -100, 48, 77, -111, 35, 96, -122, 21, + -113, 0, -11, -93, -10, -25, -74, -21, -38, -56, -32, -51, + -36, -43, -65, -17, -53, -79, 2, -64, -92, 21, -75, -106, + -110, -1, -7, -91, -12, -21, -72, -22, -34, -53, -33, -47, + -34, -44, -61, -15, -54, -75, 4, -65, -88, 23, -76, -102, + -108, -2, -3, -88, -13, -17, -70, -24, -30, -51, -34, -43, + -31, -45, -57, -13, -56, -71, 7, -67, -84, 25, -77, -98, + -105, -4, 1, -86, -15, -12, -67, -25, -26, -48, -36, -39, + -29, -47, -53, -10, -57, -66, 9, -68, -80, 28, -79, -93, + -103, -5, 5, -83, -16, -8, -65, -27, -22, -46, -37, -35, + -26, -48, -49, -8, -59, -62, 12, -70, -76, 31, -80, -89, + -100, -6, 9, -81, -17, -4, -62, -28, -18, -43, -39, -31, + -24, -49, -45, -5, -60, -58, 14, -71, -72, 33, -82, -85, + -98, -8, 13, -79, -19, 0, -60, -29, -14, -41, -40, -27, + -22, -51, -41, -3, -61, -54, 17, -72, -68, 35, -83, -81, + -95, -9, 17, -76, -20, 3, -57, -31, -9, -38, -41, -22, + -19, -52, -36, 0, -63, -50, 19, -74, -63, 38, -84, -77, + -93, -11, 21, -73, -22, 7, -55, -32, -5, -36, -43, -18, + -17, -54, -32, 2, -64, -46, 22, -75, -59, 40, -86, -73, + -90, -12, 25, -71, -23, 11, -52, -33, -1, -34, -44, -14, + -14, -55, -28, 5, -66, -42, 24, -77, -55, 43, -87, -69, + -88, -13, 29, -69, -24, 15, -50, -35, 2, -31, -45, -10, + -12, -56, -24, 7, -67, -38, 26, -78, -51, 45, -88, -65, + -86, -15, 33, -66, -26, 19, -48, -36, 6, -29, -47, -6, + -9, -58, -20, 9, -68, -34, 29, -79, -47, 48, -90, -61, + -83, -16, 38, -64, -27, 24, -45, -38, 10, -26, -48, -2, + -7, -59, -16, 12, -70, -29, 31, -81, -43, 50, -91, -56, + -81, -18, 42, -61, -28, 28, -42, -39, 14, -24, -50, 1, + -4, -61, -12, 14, -71, -25, 34, -82, -39, 53, -93, -52, + -78, -19, 46, -59, -30, 32, -40, -40, 18, -21, -51, 5, + -2, -62, -8, 17, -73, -21, 36, -83, -35, 55, -94, -48, + -76, -20, 50, -56, -31, 36, -38, -42, 22, -19, -52, 9, + 0, -63, -4, 19, -74, -17, 39, -85, -31, 57, -95, -44, + -73, -22, 54, -54, -33, 40, -35, -43, 27, -16, -54, 14, + 3, -65, 0, 22, -75, -13, 41, -86, -26, 60, -97, -40, + -71, -23, 58, -51, -34, 44, -33, -45, 31, -14, -55, 18, + 6, -66, 4, 24, -77, -9, 44, -88, -22, 63, -98, -36, + -68, -24, 62, -49, -35, 48, -30, -46, 35, -11, -57, 22, + 8, -67, 8, 27, -78, -5, 46, -89, -18, 65, -100, -32, + -66, -26, 66, -47, -37, 52, -28, -47, 39, -9, -58, 26, + 10, -69, 12, 29, -79, -1, 49, -90, -14, 67, -101, -28, + -63, -27, 71, -44, -38, 57, -25, -49, 43, -6, -59, 30, + 13, -70, 16, 32, -81, 3, 51, -92, -10, 70, -102, -23, + -61, -29, 75, -41, -40, 61, -23, -50, 47, -4, -61, 34, + 15, -72, 20, 34, -82, 7, 54, -93, -6, 72, -104, -19, + -58, -30, 79, -39, -41, 65, -20, -52, 51, -2, -62, 38, + 18, -73, 24, 37, -84, 11, 56, -95, -2, 75, -105, -15, + -56, -31, 83, -37, -42, 69, -18, -53, 55, 1, -63, 42, + 20, -74, 28, 39, -85, 15, 58, -96, 1, 77, -107, -11, + -54, -33, 87, -34, -44, 73, -16, -54, 59, 3, -65, 46, + 23, -76, 32, 41, -86, 19, 61, -97, 5, 80, -108, -7, + -51, -34, 91, -32, -45, 77, -13, -56, 64, 6, -66, 51, + 25, -77, 37, 44, -88, 23, 63, -99, 10, 82, -109, -3, + -49, -36, 95, -29, -46, 81, -10, -57, 68, 8, -68, 55, + 28, -79, 41, 46, -89, 27, 66, -100, 14, 85, -111, 0, + -46, -37, 99, -27, -48, 85, -8, -58, 72, 11, -69, 59, + 30, -80, 45, 49, -91, 31, 68, -102, 18, 87, -112, 4, + -44, -38, 103, -24, -49, 89, -6, -60, 76, 13, -70, 63, + 32, -81, 49, 51, -92, 35, 71, -103, 22, 89, -113, 8, + -41, -40, 108, -22, -51, 94, -3, -61, 80, 16, -72, 67, + 35, -83, 53, 54, -93, 40, 73, -104, 26, 92, -115, 13, + -39, -41, 112, -19, -52, 98, -1, -63, 84, 18, -73, 71, + 38, -84, 57, 56, -95, 44, 76, -106, 30, 95, -116, 17, + -36, -42, 116, -17, -53, 102, 2, -64, 88, 21, -75, 75, + 40, -86, 61, 59, -96, 48, 78, -107, 34, 97, -118, 21, + -112, 4, -12, -92, -6, -25, -73, -16, -39, -55, -27, -52, + -35, -38, -66, -16, -49, -79, 3, -60, -93, 22, -70, -107, + -109, 3, -8, -90, -7, -21, -71, -18, -35, -52, -28, -48, + -33, -39, -62, -14, -50, -75, 5, -61, -89, 24, -71, -103, + -107, 1, -4, -87, -9, -17, -69, -19, -31, -50, -30, -44, + -30, -41, -58, -12, -51, -71, 8, -62, -85, 26, -73, -99, + -104, 0, 0, -85, -10, -13, -66, -21, -26, -47, -31, -40, + -28, -42, -54, -9, -53, -67, 10, -64, -81, 29, -74, -94, + -102, -1, 4, -82, -11, -9, -64, -22, -22, -45, -33, -36, + -25, -44, -50, -7, -54, -63, 13, -65, -77, 32, -76, -90, + -99, -2, 8, -80, -13, -5, -61, -23, -18, -42, -34, -32, + -23, -45, -46, -4, -56, -59, 15, -66, -73, 34, -77, -86, + -97, -3, 12, -78, -14, -1, -59, -25, -14, -40, -35, -28, + -21, -46, -42, -2, -57, -55, 18, -68, -69, 36, -78, -82, + -94, -5, 16, -75, -16, 3, -56, -26, -10, -37, -37, -23, + -18, -48, -37, 1, -58, -50, 20, -69, -64, 39, -80, -78, + -92, -6, 20, -72, -17, 7, -54, -28, -6, -35, -38, -19, + -16, -49, -33, 3, -60, -46, 23, -71, -60, 41, -81, -74, + -89, -7, 24, -70, -18, 11, -51, -29, -2, -32, -40, -15, + -13, -51, -29, 6, -61, -42, 25, -72, -56, 44, -83, -70, + -87, -9, 28, -68, -20, 15, -49, -30, 1, -30, -41, -11, + -11, -52, -25, 8, -62, -38, 27, -73, -52, 46, -84, -66, + -85, -10, 32, -65, -21, 19, -46, -32, 5, -28, -42, -7, + -8, -53, -21, 10, -64, -34, 30, -75, -48, 49, -85, -62, + -82, -12, 37, -63, -23, 23, -44, -33, 10, -25, -44, -3, + -6, -55, -17, 13, -65, -30, 33, -76, -44, 51, -87, -57, + -80, -13, 41, -60, -24, 27, -41, -35, 14, -23, -45, 0, + -3, -56, -13, 16, -67, -26, 35, -78, -40, 54, -88, -53, + -77, -14, 45, -58, -25, 31, -39, -36, 18, -20, -46, 4, + -1, -57, -9, 18, -68, -22, 37, -79, -36, 56, -90, -49, + -75, -16, 49, -55, -27, 35, -37, -37, 22, -18, -48, 8, + 2, -59, -5, 20, -69, -18, 40, -80, -32, 58, -91, -45, + -72, -17, 53, -53, -28, 40, -34, -39, 26, -15, -49, 13, + 4, -60, 0, 23, -71, -13, 42, -82, -27, 61, -92, -41, + -70, -19, 57, -50, -30, 44, -32, -40, 30, -13, -51, 17, + 7, -62, 3, 25, -72, -9, 45, -83, -23, 64, -94, -37, + -67, -20, 61, -48, -31, 48, -29, -41, 34, -10, -52, 21, + 9, -63, 7, 28, -74, -5, 47, -85, -19, 66, -95, -33, + -65, -21, 65, -46, -32, 52, -27, -43, 38, -8, -53, 25, + 11, -64, 11, 30, -75, -1, 50, -86, -15, 68, -96, -29, + -62, -23, 70, -43, -34, 56, -24, -44, 43, -5, -55, 29, + 14, -66, 15, 33, -76, 2, 52, -87, -11, 71, -98, -24, + -60, -24, 74, -40, -35, 60, -22, -46, 47, -3, -56, 33, + 16, -67, 19, 35, -78, 6, 55, -89, -7, 73, -99, -20, + -57, -25, 78, -38, -36, 64, -19, -47, 51, -1, -58, 37, + 19, -69, 23, 38, -79, 10, 57, -90, -3, 76, -101, -16, + -55, -27, 82, -36, -38, 68, -17, -48, 55, 2, -59, 41, + 21, -70, 27, 40, -81, 14, 59, -91, 0, 78, -102, -12, + -53, -28, 86, -33, -39, 72, -15, -50, 59, 4, -60, 45, + 24, -71, 31, 42, -82, 18, 62, -93, 4, 81, -103, -8, + -50, -30, 90, -31, -41, 77, -12, -51, 63, 7, -62, 50, + 26, -73, 36, 45, -83, 23, 64, -94, 9, 83, -105, -4, + -48, -31, 94, -28, -42, 81, -9, -53, 67, 9, -63, 54, + 29, -74, 40, 48, -85, 27, 67, -96, 13, 86, -106, 0, + -45, -32, 98, -26, -43, 85, -7, -54, 71, 12, -65, 58, + 31, -75, 44, 50, -86, 31, 69, -97, 17, 88, -108, 3, + -43, -34, 102, -23, -45, 89, -5, -55, 75, 14, -66, 62, + 34, -77, 48, 52, -87, 35, 72, -98, 21, 90, -109, 7, + -40, -35, 107, -21, -46, 93, -2, -57, 80, 17, -67, 66, + 36, -78, 52, 55, -89, 39, 74, -100, 25, 93, -110, 12, + -38, -37, 111, -18, -48, 97, 0, -58, 84, 19, -69, 70, + 39, -80, 56, 57, -90, 43, 77, -101, 29, 96, -112, 16, + -35, -38, 115, -16, -49, 101, 3, -60, 88, 22, -70, 74, + 41, -81, 60, 60, -92, 47, 79, -103, 33, 98, -113, 20, + -111, 8, -12, -91, -2, -26, -72, -12, -39, -54, -23, -53, + -34, -34, -67, -16, -45, -80, 4, -56, -94, 23, -66, -107, + -108, 7, -8, -89, -3, -22, -70, -14, -35, -51, -24, -49, + -32, -35, -63, -13, -46, -76, 6, -57, -90, 25, -67, -103, + -106, 5, -4, -86, -5, -18, -68, -15, -31, -49, -26, -45, + -30, -37, -59, -11, -47, -72, 9, -58, -86, 27, -69, -99, + -103, 4, 0, -84, -6, -14, -65, -17, -27, -46, -27, -40, + -27, -38, -54, -8, -49, -68, 11, -60, -81, 30, -70, -95, + -101, 2, 3, -81, -7, -10, -63, -18, -23, -44, -29, -36, + -24, -40, -50, -6, -50, -64, 14, -61, -77, 32, -72, -91, + -98, 1, 7, -79, -9, -6, -60, -19, -19, -41, -30, -32, + -22, -41, -46, -3, -52, -60, 16, -62, -73, 35, -73, -87, + -96, 0, 11, -77, -10, -2, -58, -21, -15, -39, -31, -28, + -20, -42, -42, -1, -53, -56, 18, -64, -69, 37, -74, -83, + -93, -1, 16, -74, -12, 2, -55, -22, -10, -36, -33, -24, + -17, -44, -38, 2, -54, -51, 21, -65, -65, 40, -76, -78, + -91, -2, 20, -72, -13, 6, -53, -24, -6, -34, -34, -20, + -15, -45, -34, 4, -56, -47, 24, -67, -61, 42, -77, -74, + -89, -3, 24, -69, -14, 10, -50, -25, -2, -32, -36, -16, + -12, -47, -30, 7, -57, -43, 26, -68, -57, 45, -79, -70, + -86, -5, 28, -67, -16, 14, -48, -26, 1, -29, -37, -12, + -10, -48, -26, 9, -58, -39, 28, -69, -53, 47, -80, -66, + -84, -6, 32, -64, -17, 18, -46, -28, 5, -27, -38, -8, + -7, -49, -22, 11, -60, -35, 31, -71, -49, 50, -81, -62, + -81, -8, 36, -62, -19, 22, -43, -29, 9, -24, -40, -3, + -5, -51, -17, 14, -61, -31, 33, -72, -44, 52, -83, -58, + -79, -9, 40, -59, -20, 26, -41, -31, 13, -22, -41, 0, + -2, -52, -13, 16, -63, -27, 36, -74, -40, 55, -84, -54, + -76, -10, 44, -57, -21, 30, -38, -32, 17, -19, -42, 4, + 0, -53, -9, 19, -64, -23, 38, -75, -36, 57, -86, -50, + -74, -12, 48, -55, -23, 34, -36, -33, 21, -17, -44, 8, + 2, -55, -5, 21, -65, -19, 41, -76, -32, 59, -87, -46, + -71, -13, 53, -52, -24, 39, -33, -35, 26, -14, -45, 12, + 5, -56, -1, 24, -67, -14, 43, -78, -28, 62, -88, -41, + -69, -15, 57, -49, -26, 43, -31, -36, 30, -12, -47, 16, + 8, -58, 2, 26, -68, -10, 46, -79, -24, 64, -90, -37, + -66, -16, 61, -47, -27, 47, -28, -37, 34, -9, -48, 20, + 10, -59, 6, 29, -70, -6, 48, -81, -20, 67, -91, -33, + -64, -17, 65, -45, -28, 51, -26, -39, 38, -7, -49, 24, + 12, -60, 10, 31, -71, -2, 50, -82, -16, 69, -92, -29, + -61, -19, 69, -42, -30, 55, -23, -40, 42, -4, -51, 29, + 15, -62, 15, 34, -72, 1, 53, -83, -11, 72, -94, -25, + -59, -20, 73, -40, -31, 59, -21, -42, 46, -2, -52, 33, + 17, -63, 19, 36, -74, 5, 56, -85, -7, 74, -95, -21, + -57, -21, 77, -37, -32, 63, -18, -43, 50, 0, -54, 37, + 20, -65, 23, 39, -75, 9, 58, -86, -3, 77, -97, -17, + -54, -23, 81, -35, -34, 67, -16, -44, 54, 3, -55, 41, + 22, -66, 27, 41, -77, 13, 60, -87, 0, 79, -98, -13, + -52, -24, 85, -32, -35, 71, -14, -46, 58, 5, -56, 45, + 25, -67, 31, 43, -78, 17, 63, -89, 4, 82, -99, -9, + -49, -26, 90, -30, -37, 76, -11, -47, 63, 8, -58, 49, + 27, -69, 35, 46, -79, 22, 65, -90, 8, 84, -101, -4, + -47, -27, 94, -27, -38, 80, -9, -49, 67, 10, -59, 53, + 30, -70, 39, 48, -81, 26, 68, -92, 12, 87, -102, 0, + -44, -28, 98, -25, -39, 84, -6, -50, 71, 13, -61, 57, + 32, -71, 43, 51, -82, 30, 70, -93, 16, 89, -104, 3, + -42, -30, 102, -23, -41, 88, -4, -51, 75, 15, -62, 61, + 34, -73, 47, 53, -83, 34, 73, -94, 20, 91, -105, 7, + -39, -31, 106, -20, -42, 92, -1, -53, 79, 18, -63, 66, + 37, -74, 52, 56, -85, 38, 75, -96, 25, 94, -106, 11, + -37, -33, 110, -17, -44, 96, 1, -54, 83, 20, -65, 70, + 40, -76, 56, 58, -86, 42, 78, -97, 29, 96, -108, 15, + -34, -34, 114, -15, -45, 100, 4, -56, 87, 23, -66, 74, + 42, -77, 60, 61, -88, 46, 80, -99, 33, 99, -109, 19, + -110, 12, -13, -90, 1, -27, -72, -8, -40, -53, -19, -53, + -33, -30, -67, -15, -41, -81, 5, -52, -95, 24, -62, -108, + -107, 11, -9, -88, 0, -23, -69, -10, -36, -50, -20, -49, + -31, -31, -63, -12, -42, -77, 7, -53, -91, 26, -63, -104, + -105, 9, -5, -86, -1, -19, -67, -11, -32, -48, -22, -45, + -29, -33, -59, -10, -43, -73, 10, -54, -87, 28, -65, -100, + -102, 8, 0, -83, -2, -14, -64, -13, -28, -45, -23, -41, + -26, -34, -55, -7, -45, -68, 12, -56, -82, 31, -66, -95, + -100, 6, 3, -81, -3, -10, -62, -14, -24, -43, -25, -37, + -24, -36, -51, -5, -46, -64, 15, -57, -78, 33, -68, -91, + -97, 5, 7, -78, -5, -6, -59, -15, -20, -41, -26, -33, + -21, -37, -47, -2, -48, -60, 17, -58, -74, 36, -69, -87, + -95, 4, 11, -76, -6, -2, -57, -17, -16, -38, -27, -29, + -19, -38, -43, 0, -49, -56, 19, -60, -70, 38, -70, -83, + -92, 2, 15, -73, -8, 1, -54, -18, -11, -35, -29, -24, + -16, -40, -38, 3, -50, -52, 22, -61, -66, 41, -72, -79, + -90, 1, 19, -71, -9, 5, -52, -20, -7, -33, -30, -20, + -14, -41, -34, 5, -52, -48, 24, -63, -62, 43, -73, -75, + -88, 0, 23, -68, -10, 9, -49, -21, -3, -31, -32, -16, + -11, -43, -30, 7, -53, -44, 27, -64, -58, 46, -75, -71, + -85, -1, 27, -66, -12, 13, -47, -22, 0, -28, -33, -12, + -9, -44, -26, 10, -54, -40, 29, -65, -54, 48, -76, -67, + -83, -2, 31, -63, -13, 17, -45, -24, 4, -26, -34, -8, + -7, -45, -22, 12, -56, -36, 32, -67, -50, 50, -77, -63, + -80, -4, 36, -61, -15, 22, -42, -25, 8, -23, -36, -4, + -4, -47, -18, 15, -57, -31, 34, -68, -45, 53, -79, -58, + -78, -5, 40, -58, -16, 26, -40, -27, 12, -21, -37, 0, + -1, -48, -14, 17, -59, -27, 37, -70, -41, 56, -80, -54, + -75, -6, 44, -56, -17, 30, -37, -28, 16, -18, -38, 3, + 1, -49, -10, 20, -60, -23, 39, -71, -37, 58, -82, -50, + -73, -8, 48, -54, -19, 34, -35, -29, 20, -16, -40, 7, + 3, -51, -6, 22, -61, -19, 42, -72, -33, 60, -83, -46, + -70, -9, 52, -51, -20, 38, -32, -31, 25, -13, -41, 12, + 6, -52, -1, 25, -63, -15, 44, -74, -29, 63, -84, -42, + -68, -11, 56, -49, -22, 42, -30, -32, 29, -11, -43, 16, + 8, -54, 2, 27, -64, -11, 47, -75, -25, 65, -86, -38, + -65, -12, 60, -46, -23, 46, -27, -33, 33, -9, -44, 20, + 11, -55, 6, 30, -66, -7, 49, -77, -21, 68, -87, -34, + -63, -13, 64, -44, -24, 50, -25, -35, 37, -6, -45, 24, + 13, -56, 10, 32, -67, -3, 51, -78, -17, 70, -88, -30, + -60, -15, 69, -41, -26, 55, -22, -36, 41, -3, -47, 28, + 16, -58, 14, 35, -68, 1, 54, -79, -12, 73, -90, -25, + -58, -16, 73, -39, -27, 59, -20, -38, 45, -1, -48, 32, + 18, -59, 18, 37, -70, 5, 56, -81, -8, 75, -91, -21, + -56, -17, 77, -36, -28, 63, -17, -39, 49, 1, -50, 36, + 21, -61, 22, 39, -71, 9, 59, -82, -4, 78, -93, -17, + -53, -19, 81, -34, -30, 67, -15, -40, 53, 4, -51, 40, + 23, -62, 26, 42, -73, 13, 61, -83, 0, 80, -94, -13, + -51, -20, 85, -31, -31, 71, -13, -42, 57, 6, -52, 44, + 25, -63, 30, 44, -74, 17, 64, -85, 3, 82, -95, -9, + -48, -22, 89, -29, -33, 75, -10, -43, 62, 9, -54, 49, + 28, -65, 35, 47, -75, 21, 66, -86, 7, 85, -97, -5, + -46, -23, 93, -26, -34, 79, -8, -45, 66, 11, -55, 53, + 31, -66, 39, 49, -77, 25, 69, -88, 11, 87, -98, -1, + -43, -24, 97, -24, -35, 83, -5, -46, 70, 14, -57, 57, + 33, -67, 43, 52, -78, 29, 71, -89, 15, 90, -100, 2, + -41, -26, 101, -22, -37, 87, -3, -47, 74, 16, -58, 61, + 35, -69, 47, 54, -79, 33, 73, -90, 19, 92, -101, 6, + -38, -27, 106, -19, -38, 92, 0, -49, 78, 19, -59, 65, + 38, -70, 51, 57, -81, 38, 76, -92, 24, 95, -102, 11, + -36, -29, 110, -17, -40, 96, 2, -50, 82, 21, -61, 69, + 40, -72, 55, 59, -82, 42, 79, -93, 28, 97, -104, 15, + -33, -30, 114, -14, -41, 100, 5, -52, 86, 23, -62, 73, + 43, -73, 59, 62, -84, 46, 81, -95, 32, 100, -105, 19, + -109, 16, -14, -89, 5, -27, -71, -4, -41, -52, -15, -54, + -33, -26, -68, -14, -37, -81, 6, -48, -95, 24, -58, -109, + -106, 15, -10, -87, 4, -23, -68, -6, -37, -49, -16, -50, + -30, -27, -64, -11, -38, -77, 8, -49, -91, 27, -59, -105, + -104, 13, -6, -85, 2, -19, -66, -7, -33, -47, -18, -46, + -28, -29, -60, -9, -39, -73, 10, -50, -87, 29, -61, -101, + -101, 12, -1, -82, 1, -15, -63, -9, -28, -44, -19, -42, + -25, -30, -55, -6, -41, -69, 13, -52, -83, 32, -62, -96, + -99, 10, 2, -80, 0, -11, -61, -10, -24, -42, -21, -38, + -23, -32, -51, -4, -42, -65, 16, -53, -79, 34, -64, -92, + -97, 9, 6, -77, -1, -7, -58, -11, -20, -40, -22, -34, + -20, -33, -47, -1, -44, -61, 18, -54, -75, 37, -65, -88, + -94, 8, 10, -75, -2, -3, -56, -13, -16, -37, -23, -30, + -18, -34, -43, 1, -45, -57, 20, -56, -71, 39, -66, -84, + -91, 6, 14, -72, -4, 1, -53, -14, -12, -35, -25, -25, + -15, -36, -39, 4, -46, -52, 23, -57, -66, 42, -68, -80, + -89, 5, 18, -70, -5, 5, -51, -16, -8, -32, -26, -21, + -13, -37, -35, 6, -48, -48, 25, -59, -62, 44, -69, -76, + -87, 4, 22, -67, -6, 9, -49, -17, -4, -30, -28, -17, + -10, -39, -31, 8, -49, -44, 28, -60, -58, 47, -71, -72, + -84, 2, 26, -65, -8, 13, -46, -18, 0, -27, -29, -13, + -8, -40, -27, 11, -50, -40, 30, -61, -54, 49, -72, -68, + -82, 1, 30, -63, -9, 17, -44, -20, 3, -25, -30, -9, + -6, -41, -23, 13, -52, -36, 33, -63, -50, 51, -73, -64, + -79, 0, 35, -60, -11, 21, -41, -21, 8, -22, -32, -5, + -3, -43, -18, 16, -53, -32, 35, -64, -46, 54, -75, -59, + -77, -1, 39, -57, -12, 25, -39, -23, 12, -20, -33, -1, + -1, -44, -14, 18, -55, -28, 38, -66, -42, 56, -76, -55, + -74, -2, 43, -55, -13, 29, -36, -24, 16, -18, -34, 2, + 2, -45, -10, 21, -56, -24, 40, -67, -38, 59, -78, -51, + -72, -4, 47, -53, -15, 33, -34, -25, 20, -15, -36, 6, + 4, -47, -6, 23, -57, -20, 42, -68, -34, 61, -79, -47, + -69, -5, 51, -50, -16, 38, -31, -27, 24, -12, -37, 11, + 7, -48, -2, 26, -59, -15, 45, -70, -29, 64, -80, -43, + -67, -7, 55, -48, -18, 42, -29, -28, 28, -10, -39, 15, + 9, -50, 1, 28, -60, -11, 47, -71, -25, 66, -82, -39, + -65, -8, 59, -45, -19, 46, -26, -29, 32, -8, -40, 19, + 12, -51, 5, 31, -62, -7, 50, -73, -21, 69, -83, -35, + -62, -9, 63, -43, -20, 50, -24, -31, 36, -5, -41, 23, + 14, -52, 9, 33, -63, -3, 52, -74, -17, 71, -84, -31, + -59, -11, 68, -40, -22, 54, -21, -32, 41, -3, -43, 27, + 17, -54, 14, 36, -64, 0, 55, -75, -13, 74, -86, -26, + -57, -12, 72, -38, -23, 58, -19, -34, 45, 0, -44, 31, + 19, -55, 18, 38, -66, 4, 57, -77, -9, 76, -87, -22, + -55, -13, 76, -35, -24, 62, -17, -35, 49, 2, -46, 35, + 22, -57, 22, 40, -67, 8, 60, -78, -5, 79, -89, -18, + -52, -15, 80, -33, -26, 66, -14, -36, 53, 5, -47, 39, + 24, -58, 26, 43, -69, 12, 62, -79, -1, 81, -90, -14, + -50, -16, 84, -31, -27, 70, -12, -38, 57, 7, -48, 43, + 26, -59, 30, 45, -70, 16, 65, -81, 2, 83, -91, -10, + -47, -18, 88, -28, -29, 75, -9, -39, 61, 10, -50, 48, + 29, -61, 34, 48, -71, 21, 67, -82, 7, 86, -93, -6, + -45, -19, 92, -25, -30, 79, -7, -41, 65, 12, -51, 52, + 31, -62, 38, 50, -73, 25, 70, -84, 11, 88, -94, -2, + -42, -20, 96, -23, -31, 83, -4, -42, 69, 14, -53, 56, + 34, -63, 42, 53, -74, 29, 72, -85, 15, 91, -96, 1, + -40, -22, 100, -21, -33, 87, -2, -43, 73, 17, -54, 60, + 36, -65, 46, 55, -75, 33, 74, -86, 19, 93, -97, 5, + -37, -23, 105, -18, -34, 91, 1, -45, 78, 20, -55, 64, + 39, -66, 51, 58, -77, 37, 77, -88, 23, 96, -98, 10, + -35, -25, 109, -16, -36, 95, 3, -46, 82, 22, -57, 68, + 41, -68, 55, 60, -78, 41, 79, -89, 27, 98, -100, 14, + -33, -26, 113, -13, -37, 99, 6, -48, 86, 24, -58, 72, + 44, -69, 59, 63, -80, 45, 82, -91, 31, 101, -101, 18, + -108, 21, -14, -88, 10, -28, -70, 0, -41, -51, -11, -55, + -31, -22, -69, -13, -32, -82, 7, -43, -96, 25, -54, -109, + -105, 19, -10, -86, 8, -24, -67, -1, -37, -48, -12, -51, + -29, -23, -65, -10, -33, -78, 9, -44, -92, 28, -55, -105, + -103, 18, -6, -84, 7, -20, -65, -3, -33, -46, -13, -47, + -27, -24, -61, -8, -35, -74, 11, -46, -88, 30, -56, -101, + -100, 16, -2, -81, 5, -16, -62, -4, -29, -43, -15, -42, + -24, -26, -56, -5, -36, -70, 14, -47, -83, 33, -58, -97, + -98, 15, 1, -79, 4, -12, -60, -6, -25, -41, -16, -38, + -22, -27, -52, -3, -38, -66, 17, -49, -79, 35, -59, -93, + -96, 14, 5, -76, 3, -8, -57, -7, -21, -39, -18, -34, + -19, -28, -48, 0, -39, -62, 19, -50, -75, 38, -61, -89, + -93, 12, 9, -74, 1, -4, -55, -8, -17, -36, -19, -30, + -17, -30, -44, 2, -40, -58, 21, -51, -71, 40, -62, -85, + -90, 11, 14, -71, 0, 0, -52, -10, -12, -34, -20, -26, + -14, -31, -40, 5, -42, -53, 24, -53, -67, 43, -63, -80, + -88, 9, 18, -69, -1, 4, -50, -11, -8, -31, -22, -22, + -12, -33, -36, 7, -43, -49, 26, -54, -63, 45, -65, -76, + -86, 8, 22, -66, -2, 8, -48, -12, -4, -29, -23, -18, + -9, -34, -32, 9, -45, -45, 29, -56, -59, 48, -66, -72, + -83, 7, 26, -64, -3, 12, -45, -14, 0, -26, -24, -14, + -7, -35, -28, 12, -46, -41, 31, -57, -55, 50, -67, -68, + -81, 5, 30, -62, -5, 16, -43, -15, 3, -24, -26, -10, + -5, -37, -24, 14, -47, -37, 34, -58, -51, 52, -69, -64, + -78, 4, 34, -59, -6, 20, -40, -17, 7, -21, -27, -5, + -2, -38, -19, 17, -49, -33, 36, -60, -46, 55, -70, -60, + -76, 2, 38, -56, -7, 24, -38, -18, 11, -19, -29, -1, + 1, -40, -15, 19, -50, -29, 39, -61, -42, 57, -72, -56, + -73, 1, 42, -54, -9, 28, -35, -19, 15, -16, -30, 2, + 3, -41, -11, 22, -52, -25, 41, -62, -38, 60, -73, -52, + -71, 0, 46, -52, -10, 32, -33, -21, 19, -14, -31, 6, + 5, -42, -7, 24, -53, -21, 43, -64, -34, 62, -74, -48, + -68, -1, 51, -49, -12, 37, -30, -22, 24, -11, -33, 10, + 8, -44, -3, 27, -54, -16, 46, -65, -30, 65, -76, -43, + -66, -2, 55, -47, -13, 41, -28, -24, 28, -9, -34, 14, + 10, -45, 0, 29, -56, -12, 49, -67, -26, 67, -77, -39, + -64, -3, 59, -44, -14, 45, -25, -25, 32, -7, -36, 18, + 13, -46, 4, 32, -57, -8, 51, -68, -22, 70, -79, -35, + -61, -5, 63, -42, -16, 49, -23, -26, 36, -4, -37, 22, + 15, -48, 8, 34, -58, -4, 53, -69, -18, 72, -80, -31, + -58, -6, 67, -39, -17, 53, -20, -28, 40, -2, -38, 27, + 18, -49, 13, 37, -60, 0, 56, -71, -13, 75, -81, -27, + -56, -8, 71, -37, -19, 57, -18, -29, 44, 1, -40, 31, + 20, -51, 17, 39, -61, 3, 58, -72, -9, 77, -83, -23, + -54, -9, 75, -34, -20, 61, -16, -31, 48, 3, -41, 35, + 23, -52, 21, 41, -63, 7, 61, -74, -5, 80, -84, -19, + -51, -10, 79, -32, -21, 65, -13, -32, 52, 6, -42, 39, + 25, -53, 25, 44, -64, 11, 63, -75, -1, 82, -86, -15, + -49, -12, 83, -30, -23, 69, -11, -33, 56, 8, -44, 43, + 27, -55, 29, 46, -65, 15, 66, -76, 2, 84, -87, -11, + -46, -13, 88, -27, -24, 74, -8, -35, 61, 11, -45, 47, + 30, -56, 33, 49, -67, 20, 68, -78, 6, 87, -88, -6, + -44, -15, 92, -24, -25, 78, -6, -36, 65, 13, -47, 51, + 32, -58, 37, 51, -68, 24, 71, -79, 10, 89, -90, -2, + -41, -16, 96, -22, -27, 82, -3, -37, 69, 16, -48, 55, + 35, -59, 41, 54, -70, 28, 73, -81, 14, 92, -91, 1, + -39, -17, 100, -20, -28, 86, -1, -39, 73, 18, -49, 59, + 37, -60, 45, 56, -71, 32, 75, -82, 18, 94, -92, 5, + -36, -19, 104, -17, -30, 90, 2, -40, 77, 21, -51, 64, + 40, -62, 50, 59, -72, 36, 78, -83, 23, 97, -94, 9, + -34, -20, 108, -15, -31, 94, 4, -42, 81, 23, -52, 68, + 42, -63, 54, 61, -74, 40, 81, -85, 27, 99, -95, 13, + -32, -21, 112, -12, -32, 98, 7, -43, 85, 25, -54, 72, + 45, -65, 58, 64, -75, 44, 83, -86, 31, 102, -97, 17, + -107, 25, -15, -88, 14, -29, -69, 3, -42, -50, -7, -56, + -31, -18, -69, -12, -28, -83, 8, -39, -97, 26, -50, -110, + -104, 23, -11, -85, 12, -25, -66, 2, -38, -48, -8, -52, + -28, -19, -65, -9, -29, -79, 10, -40, -93, 29, -51, -106, + -102, 22, -7, -83, 11, -21, -64, 0, -34, -45, -9, -48, + -26, -20, -61, -7, -31, -75, 12, -42, -89, 31, -52, -102, + -99, 20, -2, -80, 9, -16, -61, 0, -30, -42, -11, -43, + -23, -22, -57, -4, -32, -70, 15, -43, -84, 34, -54, -97, + -97, 19, 1, -78, 8, -12, -59, -2, -26, -40, -12, -39, + -21, -23, -53, -2, -34, -66, 17, -45, -80, 36, -55, -93, + -95, 18, 5, -75, 7, -8, -56, -3, -22, -38, -14, -35, + -18, -24, -49, 0, -35, -62, 20, -46, -76, 39, -57, -89, + -92, 16, 9, -73, 5, -4, -54, -4, -18, -35, -15, -31, + -16, -26, -45, 3, -36, -58, 22, -47, -72, 41, -58, -85, + -90, 15, 13, -70, 4, 0, -51, -6, -13, -33, -16, -27, + -13, -27, -40, 6, -38, -54, 25, -49, -68, 44, -59, -81, + -87, 13, 17, -68, 2, 3, -49, -7, -9, -30, -18, -23, + -11, -29, -36, 8, -39, -50, 27, -50, -64, 46, -61, -77, + -85, 12, 21, -65, 1, 7, -47, -8, -5, -28, -19, -19, + -8, -30, -32, 10, -41, -46, 30, -52, -60, 48, -62, -73, + -82, 11, 25, -63, 0, 11, -44, -10, -1, -25, -20, -15, + -6, -31, -28, 13, -42, -42, 32, -53, -56, 51, -63, -69, + -80, 9, 29, -61, -1, 15, -42, -11, 2, -23, -22, -11, + -4, -33, -24, 15, -43, -38, 34, -54, -52, 53, -65, -65, + -77, 8, 34, -58, -2, 20, -39, -13, 6, -20, -23, -6, + -1, -34, -20, 18, -45, -33, 37, -56, -47, 56, -66, -60, + -75, 6, 38, -56, -3, 24, -37, -14, 10, -18, -25, -2, + 1, -36, -16, 20, -46, -29, 40, -57, -43, 58, -68, -56, + -73, 5, 42, -53, -5, 28, -34, -15, 14, -16, -26, 1, + 4, -37, -12, 23, -48, -25, 42, -58, -39, 61, -69, -52, + -70, 4, 46, -51, -6, 32, -32, -17, 18, -13, -27, 5, + 6, -38, -8, 25, -49, -21, 44, -60, -35, 63, -70, -48, + -67, 2, 50, -48, -8, 36, -29, -18, 23, -10, -29, 9, + 9, -40, -3, 28, -50, -17, 47, -61, -31, 66, -72, -44, + -65, 1, 54, -46, -9, 40, -27, -20, 27, -8, -30, 13, + 11, -41, 0, 30, -52, -13, 49, -63, -27, 68, -73, -40, + -63, 0, 58, -43, -10, 44, -24, -21, 31, -6, -32, 17, + 14, -42, 4, 32, -53, -9, 52, -64, -23, 71, -75, -36, + -60, -1, 62, -41, -12, 48, -22, -22, 35, -3, -33, 21, + 16, -44, 8, 35, -54, -5, 54, -65, -19, 73, -76, -32, + -58, -2, 67, -38, -13, 53, -19, -24, 39, -1, -34, 26, + 19, -45, 12, 38, -56, 0, 57, -67, -14, 76, -77, -27, + -55, -4, 71, -36, -15, 57, -17, -25, 43, 2, -36, 30, + 21, -47, 16, 40, -57, 3, 59, -68, -10, 78, -79, -23, + -53, -5, 75, -33, -16, 61, -15, -27, 47, 4, -37, 34, + 24, -48, 20, 42, -59, 7, 62, -70, -6, 80, -80, -19, + -50, -6, 79, -31, -17, 65, -12, -28, 51, 7, -38, 38, + 26, -49, 24, 45, -60, 11, 64, -71, -2, 83, -82, -15, + -48, -8, 83, -29, -19, 69, -10, -29, 55, 9, -40, 42, + 28, -51, 28, 47, -61, 15, 66, -72, 1, 85, -83, -11, + -45, -9, 87, -26, -20, 73, -7, -31, 60, 12, -41, 46, + 31, -52, 33, 50, -63, 19, 69, -74, 5, 88, -84, -7, + -43, -11, 91, -24, -21, 77, -5, -32, 64, 14, -43, 50, + 33, -54, 37, 52, -64, 23, 72, -75, 9, 90, -86, -3, + -41, -12, 95, -21, -23, 81, -2, -33, 68, 16, -44, 54, + 36, -55, 41, 55, -66, 27, 74, -77, 13, 93, -87, 0, + -38, -13, 99, -19, -24, 85, 0, -35, 72, 19, -45, 58, + 38, -56, 45, 57, -67, 31, 76, -78, 17, 95, -88, 4, + -35, -15, 104, -16, -26, 90, 3, -36, 76, 22, -47, 63, + 41, -58, 49, 60, -68, 36, 79, -79, 22, 98, -90, 9, + -33, -16, 108, -14, -27, 94, 5, -38, 80, 24, -48, 67, + 43, -59, 53, 62, -70, 40, 81, -81, 26, 100, -91, 13, + -31, -17, 112, -11, -28, 98, 8, -39, 84, 26, -50, 71, + 46, -61, 57, 64, -71, 44, 84, -82, 30, 103, -93, 17, + -106, 29, -16, -87, 18, -29, -68, 7, -43, -49, -3, -56, + -30, -14, -70, -11, -24, -83, 8, -35, -97, 27, -46, -111, + -104, 27, -12, -84, 16, -25, -65, 6, -39, -47, -4, -52, + -27, -15, -66, -8, -25, -79, 11, -36, -93, 30, -47, -107, + -101, 26, -8, -82, 15, -21, -63, 4, -35, -44, -5, -48, + -25, -16, -62, -6, -27, -75, 13, -38, -89, 32, -48, -103, + -99, 24, -3, -79, 13, -17, -60, 3, -30, -42, -7, -44, + -22, -18, -57, -3, -28, -71, 16, -39, -85, 35, -50, -98, + -96, 23, 0, -77, 12, -13, -58, 1, -26, -39, -8, -40, + -20, -19, -53, -1, -30, -67, 18, -41, -81, 37, -51, -94, + -94, 22, 4, -74, 11, -9, -56, 0, -22, -37, -10, -36, + -17, -20, -49, 1, -31, -63, 21, -42, -77, 40, -53, -90, + -91, 20, 8, -72, 9, -5, -53, 0, -18, -34, -11, -32, + -15, -22, -45, 4, -32, -59, 23, -43, -73, 42, -54, -86, + -89, 19, 12, -69, 8, 0, -50, -2, -14, -32, -12, -27, + -12, -23, -41, 6, -34, -54, 26, -45, -68, 45, -55, -82, + -86, 17, 16, -67, 6, 3, -48, -3, -10, -29, -14, -23, + -10, -25, -37, 9, -35, -50, 28, -46, -64, 47, -57, -78, + -84, 16, 20, -64, 5, 7, -46, -4, -6, -27, -15, -19, + -8, -26, -33, 11, -37, -46, 31, -48, -60, 49, -58, -74, + -81, 15, 24, -62, 4, 11, -43, -6, -2, -25, -16, -15, + -5, -27, -29, 14, -38, -42, 33, -49, -56, 52, -59, -70, + -79, 13, 28, -60, 2, 15, -41, -7, 1, -22, -18, -11, + -3, -29, -25, 16, -39, -38, 35, -50, -52, 54, -61, -66, + -76, 12, 33, -57, 1, 19, -38, -9, 6, -19, -19, -7, + 0, -30, -20, 19, -41, -34, 38, -52, -48, 57, -62, -61, + -74, 10, 37, -55, 0, 23, -36, -10, 10, -17, -21, -3, + 2, -32, -16, 21, -42, -30, 40, -53, -44, 59, -64, -57, + -72, 9, 41, -52, -1, 27, -33, -11, 14, -15, -22, 0, + 5, -33, -12, 24, -44, -26, 43, -54, -40, 62, -65, -53, + -69, 8, 45, -50, -2, 31, -31, -13, 18, -12, -23, 4, + 7, -34, -8, 26, -45, -22, 45, -56, -36, 64, -66, -49, + -67, 6, 49, -47, -4, 36, -28, -14, 22, -10, -25, 9, + 10, -36, -4, 29, -46, -17, 48, -57, -31, 67, -68, -45, + -64, 5, 53, -45, -5, 40, -26, -16, 26, -7, -26, 13, + 12, -37, 0, 31, -48, -13, 50, -59, -27, 69, -69, -41, + -62, 4, 57, -42, -6, 44, -24, -17, 30, -5, -28, 17, + 15, -38, 3, 33, -49, -9, 53, -60, -23, 72, -71, -37, + -59, 2, 61, -40, -8, 48, -21, -18, 34, -2, -29, 21, + 17, -40, 7, 36, -50, -5, 55, -61, -19, 74, -72, -33, + -57, 1, 66, -37, -9, 52, -18, -20, 39, 0, -30, 25, + 20, -41, 12, 38, -52, -1, 58, -63, -15, 77, -73, -28, + -54, 0, 70, -35, -11, 56, -16, -21, 43, 3, -32, 29, + 22, -43, 16, 41, -53, 2, 60, -64, -11, 79, -75, -24, + -52, -1, 74, -32, -12, 60, -14, -23, 47, 5, -33, 33, + 24, -44, 20, 43, -55, 6, 63, -66, -7, 81, -76, -20, + -49, -2, 78, -30, -13, 64, -11, -24, 51, 7, -34, 37, + 27, -45, 24, 46, -56, 10, 65, -67, -3, 84, -78, -16, + -47, -4, 82, -28, -15, 68, -9, -25, 55, 10, -36, 41, + 29, -47, 28, 48, -57, 14, 67, -68, 0, 86, -79, -12, + -44, -5, 86, -25, -16, 73, -6, -27, 59, 13, -37, 46, + 32, -48, 32, 51, -59, 19, 70, -70, 5, 89, -80, -8, + -42, -7, 90, -23, -17, 77, -4, -28, 63, 15, -39, 50, + 34, -50, 36, 53, -60, 23, 72, -71, 9, 91, -82, -4, + -40, -8, 94, -20, -19, 81, -1, -29, 67, 17, -40, 54, + 37, -51, 40, 55, -62, 27, 75, -73, 13, 94, -83, 0, + -37, -9, 98, -18, -20, 85, 1, -31, 71, 20, -41, 58, + 39, -52, 44, 58, -63, 31, 77, -74, 17, 96, -84, 3, + -35, -11, 103, -15, -22, 89, 4, -32, 76, 22, -43, 62, + 42, -54, 49, 61, -64, 35, 80, -75, 21, 99, -86, 8, + -32, -12, 107, -13, -23, 93, 6, -34, 80, 25, -44, 66, + 44, -55, 53, 63, -66, 39, 82, -77, 25, 101, -87, 12, + -30, -13, 111, -10, -24, 97, 8, -35, 84, 27, -46, 70, + 47, -57, 57, 65, -67, 43, 85, -78, 29, 104, -89, 16, + -105, 33, -16, -86, 22, -30, -67, 11, -43, -48, 0, -57, + -29, -10, -71, -10, -20, -84, 9, -31, -98, 28, -42, -111, + -103, 31, -12, -83, 20, -26, -65, 10, -39, -46, 0, -53, + -26, -11, -67, -8, -21, -80, 12, -32, -94, 31, -43, -107, + -100, 30, -8, -81, 19, -22, -62, 8, -35, -43, -1, -49, + -24, -12, -63, -5, -23, -76, 14, -34, -90, 33, -44, -103, + -98, 28, -4, -78, 17, -18, -59, 7, -31, -41, -3, -44, + -21, -14, -58, -2, -24, -72, 17, -35, -85, 36, -46, -99, + -95, 27, 0, -76, 16, -14, -57, 5, -27, -38, -4, -40, + -19, -15, -54, 0, -26, -68, 19, -37, -81, 38, -47, -95, + -93, 26, 3, -73, 15, -10, -55, 4, -23, -36, -6, -36, + -16, -16, -50, 2, -27, -64, 22, -38, -77, 40, -49, -91, + -90, 24, 7, -71, 13, -6, -52, 3, -19, -33, -7, -32, + -14, -18, -46, 5, -28, -60, 24, -39, -73, 43, -50, -87, + -88, 23, 12, -68, 12, -1, -50, 1, -14, -31, -8, -28, + -11, -19, -42, 7, -30, -55, 27, -41, -69, 46, -51, -82, + -85, 21, 16, -66, 10, 2, -47, 0, -10, -28, -10, -24, + -9, -21, -38, 10, -31, -51, 29, -42, -65, 48, -53, -78, + -83, 20, 20, -64, 9, 6, -45, 0, -6, -26, -11, -20, + -7, -22, -34, 12, -33, -47, 32, -44, -61, 50, -54, -74, + -81, 19, 24, -61, 8, 10, -42, -2, -2, -24, -12, -16, + -4, -23, -30, 15, -34, -43, 34, -45, -57, 53, -55, -70, + -78, 17, 28, -59, 6, 14, -40, -3, 1, -21, -14, -12, + -2, -25, -26, 17, -35, -39, 36, -46, -53, 55, -57, -66, + -75, 16, 32, -56, 5, 18, -37, -5, 5, -19, -15, -7, + 1, -26, -21, 20, -37, -35, 39, -48, -48, 58, -58, -62, + -73, 14, 36, -54, 4, 22, -35, -6, 9, -16, -17, -3, + 3, -28, -17, 22, -38, -31, 41, -49, -44, 60, -60, -58, + -71, 13, 40, -51, 2, 26, -33, -7, 13, -14, -18, 0, + 6, -29, -13, 24, -40, -27, 44, -50, -40, 63, -61, -54, + -68, 12, 44, -49, 1, 30, -30, -9, 17, -11, -19, 4, + 8, -30, -9, 27, -41, -23, 46, -52, -36, 65, -62, -50, + -66, 10, 49, -46, 0, 35, -27, -10, 22, -9, -21, 8, + 11, -32, -5, 29, -42, -18, 49, -53, -32, 68, -64, -45, + -63, 9, 53, -44, -1, 39, -25, -12, 26, -6, -22, 12, + 13, -33, -1, 32, -44, -14, 51, -55, -28, 70, -65, -41, + -61, 8, 57, -41, -2, 43, -23, -13, 30, -4, -24, 16, + 15, -34, 2, 34, -45, -10, 54, -56, -24, 72, -67, -37, + -58, 6, 61, -39, -4, 47, -20, -14, 34, -1, -25, 20, + 18, -36, 6, 37, -46, -6, 56, -57, -20, 75, -68, -33, + -56, 5, 65, -36, -5, 51, -18, -16, 38, 1, -26, 25, + 21, -37, 11, 39, -48, -2, 59, -59, -15, 78, -69, -29, + -53, 3, 69, -34, -7, 55, -15, -17, 42, 4, -28, 29, + 23, -39, 15, 42, -49, 1, 61, -60, -11, 80, -71, -25, + -51, 2, 73, -32, -8, 59, -13, -19, 46, 6, -29, 33, + 25, -40, 19, 44, -51, 5, 64, -62, -7, 82, -72, -21, + -49, 1, 77, -29, -9, 63, -10, -20, 50, 8, -30, 37, + 28, -41, 23, 47, -52, 9, 66, -63, -3, 85, -74, -17, + -46, 0, 81, -27, -11, 67, -8, -21, 54, 11, -32, 41, + 30, -43, 27, 49, -53, 13, 68, -64, 0, 87, -75, -13, + -43, -1, 86, -24, -12, 72, -5, -23, 59, 13, -33, 45, + 33, -44, 31, 52, -55, 18, 71, -66, 4, 90, -76, -8, + -41, -3, 90, -22, -13, 76, -3, -24, 63, 16, -35, 49, + 35, -46, 35, 54, -56, 22, 73, -67, 8, 92, -78, -4, + -39, -4, 94, -19, -15, 80, -1, -25, 67, 18, -36, 53, + 38, -47, 39, 56, -58, 26, 76, -69, 12, 95, -79, 0, + -36, -5, 98, -17, -16, 84, 2, -27, 71, 21, -37, 57, + 40, -48, 43, 59, -59, 30, 78, -70, 16, 97, -80, 3, + -34, -7, 102, -14, -18, 88, 5, -28, 75, 23, -39, 62, + 43, -50, 48, 61, -60, 34, 81, -71, 21, 100, -82, 7, + -31, -8, 106, -12, -19, 92, 7, -30, 79, 26, -40, 66, + 45, -51, 52, 64, -62, 38, 83, -73, 25, 102, -83, 11, + -29, -9, 110, -9, -20, 96, 9, -31, 83, 28, -42, 70, + 47, -53, 56, 66, -63, 42, 86, -74, 29, 104, -85, 15, + -104, 37, -17, -85, 26, -31, -66, 15, -44, -47, 4, -57, + -28, -6, -71, -9, -16, -85, 10, -27, -99, 29, -38, -112, + -102, 35, -13, -82, 24, -27, -64, 14, -40, -45, 3, -53, + -25, -7, -67, -7, -17, -81, 13, -28, -95, 31, -39, -108, + -99, 34, -9, -80, 23, -23, -61, 12, -36, -42, 2, -49, + -23, -8, -63, -4, -19, -77, 15, -30, -91, 34, -40, -104, + -97, 32, -4, -77, 21, -18, -59, 11, -32, -40, 0, -45, + -20, -10, -59, -2, -20, -72, 18, -31, -86, 37, -42, -99, + -94, 31, 0, -75, 20, -14, -56, 9, -28, -37, 0, -41, + -18, -11, -55, 1, -22, -68, 20, -33, -82, 39, -43, -95, + -92, 30, 3, -73, 19, -10, -54, 8, -24, -35, -2, -37, + -16, -12, -51, 3, -23, -64, 23, -34, -78, 41, -45, -91, + -90, 28, 7, -70, 17, -6, -51, 7, -20, -33, -3, -33, + -13, -14, -47, 6, -24, -60, 25, -35, -74, 44, -46, -87, + -87, 27, 11, -67, 16, -2, -49, 5, -15, -30, -4, -28, + -10, -15, -42, 8, -26, -56, 28, -37, -70, 46, -47, -83, + -84, 25, 15, -65, 14, 1, -46, 4, -11, -27, -6, -24, + -8, -17, -38, 11, -27, -52, 30, -38, -66, 49, -49, -79, + -82, 24, 19, -63, 13, 5, -44, 3, -7, -25, -7, -20, + -6, -18, -34, 13, -29, -48, 32, -40, -62, 51, -50, -75, + -80, 23, 23, -60, 12, 9, -41, 1, -3, -23, -8, -16, + -3, -19, -30, 15, -30, -44, 35, -41, -58, 54, -51, -71, + -77, 21, 27, -58, 10, 13, -39, 0, 0, -20, -10, -12, + -1, -21, -26, 18, -31, -40, 37, -42, -54, 56, -53, -67, + -75, 20, 32, -55, 9, 18, -36, -1, 4, -18, -11, -8, + 2, -22, -22, 21, -33, -35, 40, -44, -49, 59, -54, -62, + -72, 18, 36, -53, 8, 22, -34, -2, 8, -15, -13, -4, + 4, -24, -18, 23, -34, -31, 42, -45, -45, 61, -56, -58, + -70, 17, 40, -50, 6, 26, -32, -3, 12, -13, -14, 0, + 7, -25, -14, 25, -36, -27, 45, -46, -41, 63, -57, -54, + -67, 16, 44, -48, 5, 30, -29, -5, 16, -10, -15, 3, + 9, -26, -10, 28, -37, -23, 47, -48, -37, 66, -58, -50, + -65, 14, 48, -45, 3, 34, -27, -6, 21, -8, -17, 8, + 12, -28, -5, 30, -38, -19, 50, -49, -33, 69, -60, -46, + -62, 13, 52, -43, 2, 38, -24, -8, 25, -5, -18, 12, + 14, -29, -1, 33, -40, -15, 52, -51, -29, 71, -61, -42, + -60, 12, 56, -41, 1, 42, -22, -9, 29, -3, -20, 16, + 16, -30, 2, 35, -41, -11, 55, -52, -25, 73, -63, -38, + -58, 10, 60, -38, 0, 46, -19, -10, 33, -1, -21, 20, + 19, -32, 6, 38, -42, -7, 57, -53, -21, 76, -64, -34, + -55, 9, 65, -35, -1, 51, -17, -12, 37, 2, -22, 24, + 21, -33, 10, 40, -44, -2, 60, -55, -16, 78, -65, -29, + -52, 7, 69, -33, -3, 55, -14, -13, 41, 5, -24, 28, + 24, -35, 14, 43, -45, 1, 62, -56, -12, 81, -67, -25, + -50, 6, 73, -31, -4, 59, -12, -15, 45, 7, -25, 32, + 26, -36, 18, 45, -47, 5, 64, -58, -8, 83, -68, -21, + -48, 5, 77, -28, -5, 63, -9, -16, 49, 9, -26, 36, + 29, -37, 22, 47, -48, 9, 67, -59, -4, 86, -70, -17, + -45, 3, 81, -26, -7, 67, -7, -17, 53, 12, -28, 40, + 31, -39, 26, 50, -49, 13, 69, -60, 0, 88, -71, -13, + -43, 2, 85, -23, -8, 71, -4, -19, 58, 14, -29, 45, + 34, -40, 31, 53, -51, 17, 72, -62, 3, 91, -72, -9, + -40, 0, 89, -21, -9, 75, -2, -20, 62, 17, -31, 49, + 36, -42, 35, 55, -52, 21, 74, -63, 7, 93, -74, -5, + -38, 0, 93, -18, -11, 79, 0, -21, 66, 19, -32, 53, + 39, -43, 39, 57, -54, 25, 77, -65, 11, 95, -75, -1, + -35, -1, 97, -16, -12, 83, 3, -23, 70, 22, -33, 57, + 41, -44, 43, 60, -55, 29, 79, -66, 15, 98, -76, 2, + -33, -3, 102, -13, -14, 88, 5, -24, 74, 24, -35, 61, + 44, -46, 47, 62, -56, 34, 82, -67, 20, 101, -78, 7, + -30, -4, 106, -11, -15, 92, 8, -26, 78, 27, -36, 65, + 46, -47, 51, 65, -58, 38, 84, -69, 24, 103, -79, 11, + -28, -5, 110, -9, -16, 96, 10, -27, 82, 29, -38, 69, + 48, -49, 55, 67, -59, 42, 87, -70, 28, 105, -81, 15, + -103, 41, -18, -84, 30, -31, -65, 20, -45, -46, 9, -58, + -27, -1, -72, -8, -12, -85, 11, -23, -99, 30, -33, -113, + -101, 40, -14, -81, 29, -27, -63, 18, -41, -44, 8, -54, + -24, -2, -68, -6, -13, -81, 14, -24, -95, 33, -34, -109, + -98, 38, -10, -79, 27, -23, -60, 17, -37, -41, 6, -50, + -22, -4, -64, -3, -14, -77, 16, -25, -91, 35, -36, -105, + -96, 37, -5, -76, 26, -19, -57, 15, -32, -39, 5, -46, + -19, -5, -60, -1, -16, -73, 19, -27, -87, 38, -37, -100, + -93, 35, -1, -74, 25, -15, -55, 14, -28, -36, 3, -42, + -17, -7, -56, 2, -17, -69, 21, -28, -83, 40, -39, -96, + -91, 34, 2, -71, 23, -11, -53, 13, -24, -34, 2, -38, + -15, -8, -52, 4, -19, -65, 24, -29, -79, 42, -40, -92, + -88, 33, 6, -69, 22, -7, -50, 11, -20, -32, 1, -34, + -12, -9, -48, 7, -20, -61, 26, -31, -75, 45, -41, -88, + -86, 31, 10, -66, 20, -2, -48, 10, -16, -29, 0, -29, + -9, -11, -43, 9, -21, -56, 29, -32, -70, 47, -43, -84, + -83, 30, 14, -64, 19, 1, -45, 8, -12, -26, -1, -25, + -7, -12, -39, 12, -23, -52, 31, -34, -66, 50, -44, -80, + -81, 29, 18, -62, 18, 5, -43, 7, -8, -24, -3, -21, + -5, -14, -35, 14, -24, -48, 33, -35, -62, 52, -46, -76, + -79, 27, 22, -59, 16, 9, -40, 6, -4, -22, -4, -17, + -2, -15, -31, 16, -25, -44, 36, -36, -58, 55, -47, -72, + -76, 26, 26, -57, 15, 13, -38, 4, 0, -19, -5, -13, + 0, -16, -27, 19, -27, -40, 38, -38, -54, 57, -48, -68, + -74, 24, 31, -54, 13, 17, -35, 3, 4, -17, -7, -9, + 3, -18, -23, 22, -28, -36, 41, -39, -50, 60, -50, -63, + -71, 23, 35, -52, 12, 21, -33, 1, 8, -14, -8, -5, + 5, -19, -19, 24, -30, -32, 43, -41, -46, 62, -51, -59, + -69, 22, 39, -49, 11, 25, -31, 0, 12, -12, -9, -1, + 8, -20, -15, 26, -31, -28, 46, -42, -42, 65, -53, -55, + -66, 20, 43, -47, 9, 29, -28, 0, 16, -9, -11, 2, + 10, -22, -11, 29, -32, -24, 48, -43, -38, 67, -54, -51, + -64, 19, 47, -44, 8, 34, -26, -2, 20, -7, -12, 7, + 13, -23, -6, 31, -34, -19, 51, -45, -33, 70, -55, -47, + -61, 17, 51, -42, 6, 38, -23, -3, 24, -4, -14, 11, + 15, -25, -2, 34, -35, -15, 53, -46, -29, 72, -57, -43, + -59, 16, 55, -40, 5, 42, -21, -4, 28, -2, -15, 15, + 17, -26, 1, 36, -37, -11, 56, -48, -25, 74, -58, -39, + -56, 15, 59, -37, 4, 46, -18, -6, 32, 0, -16, 19, + 20, -27, 5, 39, -38, -7, 58, -49, -21, 77, -59, -35, + -54, 13, 64, -34, 2, 50, -16, -7, 37, 3, -18, 23, + 23, -29, 9, 41, -39, -3, 61, -50, -17, 79, -61, -30, + -51, 12, 68, -32, 1, 54, -13, -9, 41, 6, -19, 27, + 25, -30, 13, 44, -41, 0, 63, -52, -13, 82, -62, -26, + -49, 11, 72, -30, 0, 58, -11, -10, 45, 8, -21, 31, + 27, -32, 17, 46, -42, 4, 65, -53, -9, 84, -64, -22, + -47, 9, 76, -27, -1, 62, -8, -11, 49, 10, -22, 35, + 30, -33, 21, 48, -44, 8, 68, -54, -5, 87, -65, -18, + -44, 8, 80, -25, -2, 66, -6, -13, 53, 13, -23, 39, + 32, -34, 25, 51, -45, 12, 70, -56, -1, 89, -66, -14, + -42, 6, 84, -22, -4, 71, -3, -14, 57, 15, -25, 44, + 35, -36, 30, 54, -46, 17, 73, -57, 3, 92, -68, -10, + -39, 5, 88, -20, -5, 75, -1, -16, 61, 18, -26, 48, + 37, -37, 34, 56, -48, 21, 75, -59, 7, 94, -69, -6, + -37, 4, 92, -17, -6, 79, 1, -17, 65, 20, -28, 52, + 40, -38, 38, 58, -49, 25, 78, -60, 11, 97, -71, -2, + -34, 2, 96, -15, -8, 83, 4, -18, 69, 23, -29, 56, + 42, -40, 42, 61, -50, 29, 80, -61, 15, 99, -72, 1, + -32, 1, 101, -12, -9, 87, 6, -20, 74, 25, -30, 60, + 45, -41, 46, 63, -52, 33, 83, -63, 19, 102, -73, 6, + -29, 0, 105, -10, -11, 91, 9, -21, 78, 28, -32, 64, + 47, -43, 50, 66, -53, 37, 85, -64, 23, 104, -75, 10, + -27, -1, 109, -8, -12, 95, 11, -23, 82, 30, -33, 68, + 49, -44, 54, 68, -55, 41, 88, -66, 27, 106, -76, 14, + -102, 45, -18, -83, 34, -32, -64, 24, -45, -45, 13, -59, + -26, 2, -73, -7, -8, -86, 12, -19, -100, 31, -29, -113, + -100, 44, -14, -80, 33, -28, -62, 22, -41, -43, 12, -55, + -24, 1, -69, -5, -9, -82, 15, -20, -96, 33, -30, -109, + -97, 42, -10, -78, 31, -24, -59, 21, -37, -40, 10, -51, + -21, 0, -65, -2, -10, -78, 17, -21, -92, 36, -32, -105, + -95, 41, -6, -75, 30, -20, -57, 19, -33, -38, 9, -46, + -18, -1, -60, 0, -12, -74, 20, -23, -87, 39, -33, -101, + -92, 39, -2, -73, 29, -16, -54, 18, -29, -35, 7, -42, + -16, -3, -56, 3, -13, -70, 22, -24, -83, 41, -35, -97, + -90, 38, 1, -71, 27, -12, -52, 17, -25, -33, 6, -38, + -14, -4, -52, 5, -15, -66, 25, -25, -79, 43, -36, -93, + -88, 37, 5, -68, 26, -8, -49, 15, -21, -31, 5, -34, + -11, -5, -48, 8, -16, -62, 27, -27, -75, 46, -37, -89, + -85, 35, 10, -66, 24, -3, -47, 14, -16, -28, 3, -30, + -9, -7, -44, 10, -17, -57, 30, -28, -71, 48, -39, -84, + -82, 34, 14, -63, 23, 0, -44, 12, -12, -26, 2, -26, + -6, -8, -40, 13, -19, -53, 32, -30, -67, 51, -40, -80, + -80, 33, 18, -61, 22, 4, -42, 11, -8, -23, 0, -22, + -4, -10, -36, 15, -20, -49, 34, -31, -63, 53, -42, -76, + -78, 31, 22, -58, 20, 8, -40, 10, -4, -21, 0, -18, + -1, -11, -32, 17, -21, -45, 37, -32, -59, 56, -43, -72, + -75, 30, 26, -56, 19, 12, -37, 8, 0, -18, -1, -14, + 1, -12, -28, 20, -23, -41, 39, -34, -55, 58, -44, -68, + -73, 28, 30, -53, 17, 16, -34, 7, 3, -16, -3, -9, + 4, -14, -23, 22, -24, -37, 42, -35, -50, 61, -46, -64, + -70, 27, 34, -51, 16, 20, -32, 5, 7, -13, -4, -5, + 6, -15, -19, 25, -26, -33, 44, -37, -46, 63, -47, -60, + -68, 26, 38, -48, 15, 24, -30, 4, 11, -11, -5, -1, + 8, -16, -15, 27, -27, -29, 47, -38, -42, 65, -49, -56, + -65, 24, 42, -46, 13, 28, -27, 3, 15, -8, -7, 2, + 11, -18, -11, 30, -28, -25, 49, -39, -38, 68, -50, -52, + -63, 23, 47, -43, 12, 33, -25, 1, 20, -6, -8, 6, + 14, -19, -7, 32, -30, -20, 52, -41, -34, 71, -51, -47, + -60, 21, 51, -41, 10, 37, -22, 0, 24, -3, -10, 10, + 16, -21, -3, 35, -31, -16, 54, -42, -30, 73, -53, -43, + -58, 20, 55, -39, 9, 41, -20, 0, 28, -1, -11, 14, + 18, -22, 0, 37, -33, -12, 57, -44, -26, 75, -54, -39, + -56, 19, 59, -36, 8, 45, -17, -2, 32, 1, -12, 18, + 21, -23, 4, 40, -34, -8, 59, -45, -22, 78, -55, -35, + -53, 17, 63, -34, 6, 49, -15, -3, 36, 4, -14, 23, + 23, -25, 9, 42, -35, -4, 62, -46, -17, 80, -57, -31, + -50, 16, 67, -31, 5, 53, -12, -5, 40, 6, -15, 27, + 26, -26, 13, 45, -37, 0, 64, -48, -13, 83, -58, -27, + -48, 15, 71, -29, 4, 57, -10, -6, 44, 9, -17, 31, + 28, -28, 17, 47, -38, 3, 66, -49, -9, 85, -60, -23, + -46, 13, 75, -26, 2, 61, -8, -7, 48, 11, -18, 35, + 31, -29, 21, 49, -40, 7, 69, -50, -5, 88, -61, -19, + -43, 12, 79, -24, 1, 65, -5, -9, 52, 14, -19, 39, + 33, -30, 25, 52, -41, 11, 71, -52, -1, 90, -62, -15, + -41, 10, 84, -21, 0, 70, -2, -10, 57, 16, -21, 43, + 36, -32, 29, 54, -42, 16, 74, -53, 2, 93, -64, -10, + -38, 9, 88, -19, -1, 74, 0, -12, 61, 19, -22, 47, + 38, -33, 33, 57, -44, 20, 76, -55, 6, 95, -65, -6, + -36, 8, 92, -16, -2, 78, 2, -13, 65, 21, -24, 51, + 40, -34, 37, 59, -45, 24, 79, -56, 10, 97, -67, -2, + -33, 6, 96, -14, -4, 82, 5, -14, 69, 23, -25, 55, + 43, -36, 41, 62, -46, 28, 81, -57, 14, 100, -68, 1, + -31, 5, 100, -11, -5, 86, 7, -16, 73, 26, -26, 60, + 46, -37, 46, 64, -48, 32, 84, -59, 19, 102, -69, 5, + -28, 3, 104, -9, -7, 90, 10, -17, 77, 29, -28, 64, + 48, -39, 50, 67, -49, 36, 86, -60, 23, 105, -71, 9, + -26, 2, 108, -7, -8, 94, 12, -19, 81, 31, -29, 68, + 50, -40, 54, 69, -51, 40, 88, -62, 27, 107, -72, 13, + -101, 49, -19, -82, 38, -33, -63, 28, -46, -44, 17, -60, + -25, 6, -73, -6, -4, -87, 13, -15, -101, 32, -25, -114, + -99, 48, -15, -80, 37, -29, -61, 26, -42, -42, 16, -56, + -23, 5, -69, -4, -5, -83, 16, -16, -97, 34, -26, -110, + -97, 46, -11, -77, 35, -25, -58, 25, -38, -40, 14, -52, + -20, 3, -65, -1, -6, -79, 18, -17, -93, 37, -28, -106, + -94, 45, -6, -74, 34, -20, -56, 23, -34, -37, 13, -47, + -18, 2, -61, 1, -8, -74, 21, -19, -88, 39, -29, -101, + -91, 43, -2, -72, 33, -16, -53, 22, -30, -34, 11, -43, + -15, 0, -57, 4, -9, -70, 23, -20, -84, 42, -31, -97, + -89, 42, 1, -70, 31, -12, -51, 21, -26, -32, 10, -39, + -13, 0, -53, 6, -11, -66, 25, -21, -80, 44, -32, -93, + -87, 41, 5, -67, 30, -8, -48, 19, -22, -30, 9, -35, + -10, -1, -49, 8, -12, -62, 28, -23, -76, 47, -33, -89, + -84, 39, 9, -65, 28, -4, -46, 18, -17, -27, 7, -31, + -8, -3, -44, 11, -13, -58, 31, -24, -72, 49, -35, -85, + -82, 38, 13, -62, 27, 0, -43, 16, -13, -25, 6, -27, + -5, -4, -40, 14, -15, -54, 33, -26, -68, 52, -36, -81, + -79, 37, 17, -60, 26, 3, -41, 15, -9, -22, 4, -23, + -3, -6, -36, 16, -16, -50, 35, -27, -64, 54, -38, -77, + -77, 35, 21, -57, 24, 7, -39, 14, -5, -20, 3, -19, + 0, -7, -32, 18, -17, -46, 38, -28, -60, 56, -39, -73, + -74, 34, 25, -55, 23, 11, -36, 12, -1, -17, 2, -15, + 2, -8, -28, 21, -19, -42, 40, -30, -56, 59, -40, -69, + -72, 32, 30, -52, 21, 16, -34, 11, 2, -15, 0, -10, + 5, -10, -24, 23, -20, -37, 43, -31, -51, 62, -42, -64, + -69, 31, 34, -50, 20, 20, -31, 9, 6, -12, 0, -6, + 7, -11, -20, 26, -22, -33, 45, -33, -47, 64, -43, -60, + -67, 30, 38, -48, 19, 24, -29, 8, 10, -10, -1, -2, + 9, -12, -16, 28, -23, -29, 48, -34, -43, 66, -45, -56, + -65, 28, 42, -45, 17, 28, -26, 7, 14, -8, -3, 1, + 12, -14, -12, 31, -24, -25, 50, -35, -39, 69, -46, -52, + -62, 27, 46, -42, 16, 32, -24, 5, 19, -5, -4, 5, + 14, -15, -7, 33, -26, -21, 53, -37, -35, 71, -47, -48, + -59, 25, 50, -40, 14, 36, -21, 4, 23, -3, -6, 9, + 17, -17, -3, 36, -27, -17, 55, -38, -31, 74, -49, -44, + -57, 24, 54, -38, 13, 40, -19, 3, 27, 0, -7, 13, + 19, -18, 0, 38, -29, -13, 57, -40, -27, 76, -50, -40, + -55, 23, 58, -35, 12, 44, -17, 1, 31, 2, -8, 17, + 22, -19, 4, 40, -30, -9, 60, -41, -23, 79, -51, -36, + -52, 21, 63, -33, 10, 49, -14, 0, 35, 5, -10, 22, + 24, -21, 8, 43, -31, -4, 62, -42, -18, 81, -53, -31, + -50, 20, 67, -30, 9, 53, -11, -1, 39, 7, -11, 26, + 27, -22, 12, 46, -33, 0, 65, -44, -14, 84, -54, -27, + -47, 19, 71, -28, 8, 57, -9, -2, 43, 10, -13, 30, + 29, -24, 16, 48, -34, 3, 67, -45, -10, 86, -56, -23, + -45, 17, 75, -25, 6, 61, -7, -3, 47, 12, -14, 34, + 32, -25, 20, 50, -36, 7, 70, -46, -6, 88, -57, -19, + -42, 16, 79, -23, 5, 65, -4, -5, 51, 15, -15, 38, + 34, -26, 24, 53, -37, 11, 72, -48, -2, 91, -58, -15, + -40, 14, 83, -20, 3, 69, -2, -6, 56, 17, -17, 42, + 37, -28, 29, 55, -38, 15, 75, -49, 1, 94, -60, -11, + -37, 13, 87, -18, 2, 73, 1, -8, 60, 20, -18, 46, + 39, -29, 33, 58, -40, 19, 77, -51, 5, 96, -61, -7, + -35, 12, 91, -16, 1, 77, 3, -9, 64, 22, -20, 50, + 41, -30, 37, 60, -41, 23, 80, -52, 9, 98, -63, -3, + -33, 10, 95, -13, 0, 81, 6, -10, 68, 24, -21, 54, + 44, -32, 41, 63, -42, 27, 82, -53, 13, 101, -64, 0, + -30, 9, 100, -10, -1, 86, 8, -12, 72, 27, -22, 59, + 46, -33, 45, 65, -44, 32, 85, -55, 18, 103, -65, 5, + -27, 7, 104, -8, -3, 90, 11, -13, 76, 29, -24, 63, + 49, -35, 49, 68, -45, 36, 87, -56, 22, 106, -67, 9, + -25, 6, 108, -6, -4, 94, 13, -15, 80, 32, -25, 67, + 51, -36, 53, 70, -47, 40, 89, -58, 26, 108, -68, 13, + -100, 53, -20, -81, 42, -33, -62, 32, -47, -43, 21, -60, + -24, 10, -74, -5, 0, -87, 14, -11, -101, 33, -21, -115, + -98, 52, -16, -79, 41, -29, -60, 30, -43, -41, 20, -56, + -22, 9, -70, -3, -1, -83, 16, -12, -97, 35, -22, -111, + -96, 50, -12, -76, 39, -25, -57, 29, -39, -39, 18, -52, + -19, 7, -66, -1, -2, -79, 19, -13, -93, 38, -24, -107, + -93, 49, -7, -74, 38, -21, -55, 27, -34, -36, 17, -48, + -17, 6, -61, 2, -4, -75, 22, -15, -89, 40, -25, -102, + -91, 47, -3, -71, 37, -17, -52, 26, -30, -34, 15, -44, + -14, 4, -57, 5, -5, -71, 24, -16, -85, 43, -27, -98, + -88, 46, 0, -69, 35, -13, -50, 25, -26, -31, 14, -40, + -12, 3, -53, 7, -7, -67, 26, -17, -81, 45, -28, -94, + -86, 45, 4, -66, 34, -9, -48, 23, -22, -29, 13, -36, + -9, 2, -49, 9, -8, -63, 29, -19, -77, 48, -29, -90, + -83, 43, 8, -64, 32, -4, -45, 22, -18, -26, 11, -31, + -7, 0, -45, 12, -9, -58, 31, -20, -72, 50, -31, -86, + -81, 42, 12, -61, 31, 0, -43, 20, -14, -24, 10, -27, + -4, 0, -41, 14, -11, -54, 34, -22, -68, 53, -32, -82, + -78, 41, 16, -59, 30, 3, -40, 19, -10, -21, 8, -23, + -2, -2, -37, 17, -12, -50, 36, -23, -64, 55, -34, -78, + -76, 39, 20, -57, 28, 7, -38, 18, -6, -19, 7, -19, + 0, -3, -33, 19, -13, -46, 39, -24, -60, 57, -35, -74, + -73, 38, 24, -54, 27, 11, -35, 16, -2, -17, 6, -15, + 3, -4, -29, 22, -15, -42, 41, -26, -56, 60, -36, -70, + -71, 36, 29, -51, 25, 15, -33, 15, 2, -14, 4, -11, + 6, -6, -24, 24, -16, -38, 44, -27, -52, 62, -38, -65, + -68, 35, 33, -49, 24, 19, -30, 13, 6, -11, 3, -7, + 8, -7, -20, 27, -18, -34, 46, -29, -48, 65, -39, -61, + -66, 34, 37, -47, 23, 23, -28, 12, 10, -9, 2, -3, + 10, -8, -16, 29, -19, -30, 48, -30, -44, 67, -41, -57, + -64, 32, 41, -44, 21, 27, -25, 11, 14, -7, 0, 0, + 13, -10, -12, 31, -20, -26, 51, -31, -40, 70, -42, -53, + -61, 31, 45, -42, 20, 32, -23, 9, 18, -4, 0, 5, + 15, -11, -8, 34, -22, -21, 54, -33, -35, 72, -43, -49, + -59, 29, 49, -39, 18, 36, -20, 8, 22, -2, -2, 9, + 18, -13, -4, 37, -23, -17, 56, -34, -31, 75, -45, -45, + -56, 28, 53, -37, 17, 40, -18, 7, 26, 1, -3, 13, + 20, -14, 0, 39, -25, -13, 58, -36, -27, 77, -46, -41, + -54, 27, 57, -34, 16, 44, -16, 5, 30, 3, -4, 17, + 23, -15, 3, 41, -26, -9, 61, -37, -23, 80, -47, -37, + -51, 25, 62, -32, 14, 48, -13, 4, 35, 6, -6, 21, + 25, -17, 8, 44, -27, -5, 63, -38, -19, 82, -49, -32, + -49, 24, 66, -29, 13, 52, -11, 2, 39, 8, -7, 25, + 28, -18, 12, 46, -29, -1, 66, -40, -15, 85, -50, -28, + -46, 23, 70, -27, 12, 56, -8, 1, 43, 11, -9, 29, + 30, -20, 16, 49, -30, 2, 68, -41, -11, 87, -52, -24, + -44, 21, 74, -25, 10, 60, -6, 0, 47, 13, -10, 33, + 32, -21, 20, 51, -32, 6, 71, -42, -7, 89, -53, -20, + -41, 20, 78, -22, 9, 64, -3, -1, 51, 15, -11, 37, + 35, -22, 24, 54, -33, 10, 73, -44, -3, 92, -54, -16, + -39, 18, 82, -19, 7, 69, -1, -2, 55, 18, -13, 42, + 38, -24, 28, 56, -34, 15, 76, -45, 1, 94, -56, -12, + -36, 17, 86, -17, 6, 73, 2, -4, 59, 21, -14, 46, + 40, -25, 32, 59, -36, 19, 78, -47, 5, 97, -57, -8, + -34, 16, 90, -15, 5, 77, 4, -5, 63, 23, -16, 50, + 42, -26, 36, 61, -37, 23, 80, -48, 9, 99, -59, -4, + -32, 14, 94, -12, 3, 81, 7, -6, 67, 25, -17, 54, + 45, -28, 40, 63, -38, 27, 83, -49, 13, 102, -60, 0, + -29, 13, 99, -10, 2, 85, 9, -8, 72, 28, -18, 58, + 47, -29, 45, 66, -40, 31, 86, -51, 17, 104, -61, 4, + -27, 11, 103, -7, 0, 89, 12, -9, 76, 30, -20, 62, + 50, -31, 49, 69, -41, 35, 88, -52, 21, 107, -63, 8, + -24, 10, 107, -5, 0, 93, 14, -11, 80, 33, -21, 66, + 52, -32, 53, 71, -43, 39, 90, -54, 25, 109, -64, 12, + -99, 58, -20, -80, 47, -34, -61, 36, -47, -42, 25, -61, + -23, 14, -75, -4, 4, -88, 15, -6, -102, 34, -17, -115, + -97, 56, -16, -78, 45, -30, -59, 35, -43, -40, 24, -57, + -21, 13, -71, -2, 3, -84, 17, -7, -98, 36, -18, -111, + -95, 55, -12, -75, 44, -26, -56, 33, -39, -38, 23, -53, + -18, 12, -67, 1, 1, -80, 20, -9, -94, 39, -19, -107, + -92, 53, -8, -73, 42, -22, -54, 32, -35, -35, 21, -48, + -16, 10, -62, 3, 0, -76, 23, -10, -89, 41, -21, -103, + -89, 52, -4, -70, 41, -18, -51, 30, -31, -33, 20, -44, + -13, 9, -58, 6, -1, -72, 25, -12, -85, 44, -22, -99, + -87, 51, 0, -68, 40, -14, -49, 29, -27, -30, 18, -40, + -11, 8, -54, 8, -2, -68, 27, -13, -81, 46, -24, -95, + -85, 49, 3, -65, 38, -10, -47, 28, -23, -28, 17, -36, + -8, 6, -50, 10, -3, -64, 30, -14, -77, 49, -25, -91, + -82, 48, 8, -63, 37, -5, -44, 26, -18, -25, 16, -32, + -6, 5, -46, 13, -5, -59, 32, -16, -73, 51, -26, -86, + -80, 46, 12, -60, 35, -1, -41, 25, -14, -23, 14, -28, + -3, 3, -42, 15, -6, -55, 35, -17, -69, 54, -28, -82, + -77, 45, 16, -58, 34, 2, -39, 24, -10, -20, 13, -24, + -1, 2, -38, 18, -8, -51, 37, -19, -65, 56, -29, -78, + -75, 44, 20, -55, 33, 6, -37, 22, -6, -18, 12, -20, + 1, 1, -34, 20, -9, -47, 40, -20, -61, 58, -30, -74, + -72, 42, 24, -53, 31, 10, -34, 21, -2, -16, 10, -16, + 4, 0, -30, 23, -10, -43, 42, -21, -57, 61, -32, -70, + -70, 41, 28, -50, 30, 14, -32, 19, 1, -13, 9, -11, + 7, -1, -25, 25, -12, -39, 45, -23, -52, 63, -33, -66, + -67, 39, 32, -48, 29, 18, -29, 18, 5, -10, 7, -7, + 9, -3, -21, 28, -13, -35, 47, -24, -48, 66, -35, -62, + -65, 38, 36, -46, 27, 22, -27, 17, 9, -8, 6, -3, + 11, -4, -17, 30, -15, -31, 49, -25, -44, 68, -36, -58, + -63, 37, 40, -43, 26, 26, -24, 15, 13, -6, 5, 0, + 14, -5, -13, 33, -16, -27, 52, -27, -40, 71, -37, -54, + -60, 35, 45, -41, 24, 31, -22, 14, 18, -3, 3, 4, + 16, -7, -9, 35, -17, -22, 55, -28, -36, 73, -39, -49, + -58, 34, 49, -38, 23, 35, -19, 12, 22, -1, 2, 8, + 19, -8, -5, 38, -19, -18, 57, -30, -32, 76, -40, -45, + -55, 33, 53, -36, 22, 39, -17, 11, 26, 2, 0, 12, + 21, -9, -1, 40, -20, -14, 59, -31, -28, 78, -42, -41, + -53, 31, 57, -33, 20, 43, -15, 10, 30, 4, 0, 16, + 24, -11, 2, 42, -21, -10, 62, -32, -24, 81, -43, -37, + -50, 30, 61, -31, 19, 47, -12, 8, 34, 7, -1, 21, + 26, -12, 7, 45, -23, -6, 64, -34, -19, 83, -44, -33, + -48, 28, 65, -28, 17, 51, -9, 7, 38, 9, -3, 25, + 29, -14, 11, 47, -24, -2, 67, -35, -15, 86, -46, -29, + -45, 27, 69, -26, 16, 55, -7, 5, 42, 12, -4, 29, + 31, -15, 15, 50, -26, 1, 69, -37, -11, 88, -47, -25, + -43, 26, 73, -23, 15, 59, -5, 4, 46, 14, -5, 33, + 33, -16, 19, 52, -27, 5, 72, -38, -7, 90, -49, -21, + -40, 24, 77, -21, 13, 63, -2, 3, 50, 16, -7, 37, + 36, -18, 23, 55, -28, 9, 74, -39, -3, 93, -50, -17, + -38, 23, 82, -18, 12, 68, 0, 1, 55, 19, -8, 41, + 39, -19, 27, 57, -30, 14, 77, -41, 0, 95, -51, -12, + -35, 21, 86, -16, 11, 72, 3, 0, 59, 22, -10, 45, + 41, -21, 31, 60, -31, 18, 79, -42, 4, 98, -53, -8, + -33, 20, 90, -14, 9, 76, 5, 0, 63, 24, -11, 49, + 43, -22, 35, 62, -33, 22, 81, -44, 8, 100, -54, -4, + -31, 19, 94, -11, 8, 80, 8, -2, 67, 26, -12, 53, + 46, -23, 39, 65, -34, 26, 84, -45, 12, 103, -55, 0, + -28, 17, 98, -9, 6, 84, 10, -3, 71, 29, -14, 58, + 48, -25, 44, 67, -35, 30, 87, -46, 17, 105, -57, 3, + -26, 16, 102, -6, 5, 88, 13, -5, 75, 31, -15, 62, + 51, -26, 48, 70, -37, 34, 89, -48, 21, 108, -58, 7, + -23, 15, 106, -4, 4, 92, 15, -6, 79, 34, -17, 66, + 53, -28, 52, 72, -38, 38, 91, -49, 25, 110, -60, 11, + -98, 62, -21, -79, 51, -35, -60, 40, -48, -42, 29, -62, + -22, 18, -75, -3, 8, -89, 16, -2, -103, 35, -13, -116, + -96, 60, -17, -77, 49, -31, -58, 39, -44, -39, 28, -58, + -20, 17, -71, -1, 7, -85, 18, -3, -99, 37, -14, -112, + -94, 59, -13, -74, 48, -27, -56, 37, -40, -37, 27, -54, + -17, 16, -67, 1, 5, -81, 21, -5, -95, 40, -15, -108, + -91, 57, -8, -72, 46, -22, -53, 36, -36, -34, 25, -49, + -15, 14, -63, 4, 4, -76, 23, -6, -90, 42, -17, -103, + -89, 56, -4, -69, 45, -18, -50, 34, -32, -32, 24, -45, + -12, 13, -59, 7, 2, -72, 26, -8, -86, 45, -18, -99, + -86, 55, 0, -67, 44, -14, -48, 33, -28, -29, 22, -41, + -10, 12, -55, 9, 1, -68, 28, -9, -82, 47, -20, -95, + -84, 53, 3, -64, 42, -10, -46, 32, -24, -27, 21, -37, + -7, 10, -51, 11, 0, -64, 31, -10, -78, 49, -21, -91, + -81, 52, 7, -62, 41, -6, -43, 30, -19, -24, 20, -33, + -5, 9, -46, 14, -1, -60, 33, -12, -74, 52, -22, -87, + -79, 50, 11, -59, 39, -2, -41, 29, -15, -22, 18, -29, + -2, 7, -42, 16, -2, -56, 36, -13, -70, 55, -24, -83, + -76, 49, 15, -57, 38, 1, -38, 28, -11, -19, 17, -25, + 0, 6, -38, 19, -4, -52, 38, -15, -66, 57, -25, -79, + -74, 48, 19, -55, 37, 5, -36, 26, -7, -17, 16, -21, + 2, 5, -34, 21, -5, -48, 41, -16, -62, 59, -26, -75, + -72, 46, 23, -52, 35, 9, -33, 25, -3, -15, 14, -17, + 5, 3, -30, 24, -6, -44, 43, -17, -58, 62, -28, -71, + -69, 45, 28, -49, 34, 14, -31, 23, 0, -12, 13, -12, + 7, 2, -26, 26, -8, -39, 46, -19, -53, 64, -29, -66, + -66, 43, 32, -47, 33, 18, -28, 22, 4, -10, 11, -8, + 10, 0, -22, 29, -9, -35, 48, -20, -49, 67, -31, -62, + -64, 42, 36, -45, 31, 22, -26, 21, 8, -7, 10, -4, + 12, 0, -18, 31, -11, -31, 50, -21, -45, 69, -32, -58, + -62, 41, 40, -42, 30, 26, -24, 19, 12, -5, 9, 0, + 15, -1, -14, 33, -12, -27, 53, -23, -41, 72, -33, -54, + -59, 39, 44, -40, 28, 30, -21, 18, 17, -2, 7, 3, + 17, -3, -9, 36, -13, -23, 55, -24, -37, 74, -35, -50, + -57, 38, 48, -37, 27, 34, -18, 16, 21, 0, 6, 7, + 20, -4, -5, 39, -15, -19, 58, -26, -33, 77, -36, -46, + -54, 37, 52, -35, 26, 38, -16, 15, 25, 3, 4, 11, + 22, -5, -1, 41, -16, -15, 60, -27, -29, 79, -38, -42, + -52, 35, 56, -32, 24, 42, -14, 14, 29, 5, 3, 15, + 25, -7, 2, 43, -17, -11, 63, -28, -25, 81, -39, -38, + -49, 34, 61, -30, 23, 47, -11, 12, 33, 8, 2, 20, + 27, -8, 6, 46, -19, -6, 65, -30, -20, 84, -40, -33, + -47, 32, 65, -27, 21, 51, -9, 11, 37, 10, 0, 24, + 30, -10, 10, 48, -20, -2, 68, -31, -16, 87, -42, -29, + -44, 31, 69, -25, 20, 55, -6, 9, 41, 13, 0, 28, + 32, -11, 14, 51, -22, 1, 70, -33, -12, 89, -43, -25, + -42, 30, 73, -23, 19, 59, -4, 8, 45, 15, -1, 32, + 34, -12, 18, 53, -23, 5, 73, -34, -8, 91, -45, -21, + -40, 28, 77, -20, 17, 63, -1, 7, 49, 17, -3, 36, + 37, -14, 22, 56, -24, 9, 75, -35, -4, 94, -46, -17, + -37, 27, 81, -17, 16, 67, 1, 5, 54, 20, -4, 40, + 39, -15, 27, 58, -26, 13, 78, -37, 0, 96, -47, -13, + -34, 25, 85, -15, 15, 71, 4, 4, 58, 22, -6, 44, + 42, -17, 31, 61, -27, 17, 80, -38, 3, 99, -49, -9, + -32, 24, 89, -13, 13, 75, 6, 3, 62, 25, -7, 48, + 44, -18, 35, 63, -29, 21, 82, -40, 7, 101, -50, -5, + -30, 23, 93, -10, 12, 79, 8, 1, 66, 27, -8, 52, + 47, -19, 39, 65, -30, 25, 85, -41, 11, 104, -51, -1, + -27, 21, 98, -8, 10, 84, 11, 0, 70, 30, -10, 57, + 49, -21, 43, 68, -31, 30, 87, -42, 16, 106, -53, 3, + -25, 20, 102, -5, 9, 88, 14, -1, 74, 32, -11, 61, + 52, -22, 47, 70, -33, 34, 90, -44, 20, 109, -54, 7, + -22, 19, 106, -3, 8, 92, 16, -2, 78, 35, -13, 65, + 54, -24, 51, 73, -34, 38, 92, -45, 24, 111, -56, 11, + -98, 66, -22, -78, 55, -35, -59, 44, -49, -41, 33, -62, + -21, 22, -76, -2, 12, -89, 17, 1, -103, 36, -9, -117, + -95, 64, -18, -76, 53, -31, -57, 43, -45, -38, 32, -58, + -19, 21, -72, 0, 11, -85, 19, 0, -99, 38, -10, -113, + -93, 63, -14, -73, 52, -27, -55, 41, -41, -36, 31, -54, + -16, 20, -68, 2, 9, -81, 22, -1, -95, 40, -11, -109, + -90, 61, -9, -71, 50, -23, -52, 40, -36, -33, 29, -50, + -14, 18, -64, 5, 8, -77, 24, -2, -91, 43, -13, -104, + -88, 60, -5, -68, 49, -19, -50, 38, -32, -31, 28, -46, + -11, 17, -60, 7, 6, -73, 27, -4, -87, 46, -14, -100, + -85, 59, -1, -66, 48, -15, -47, 37, -28, -28, 26, -42, + -9, 16, -56, 10, 5, -69, 29, -5, -83, 48, -16, -96, + -83, 57, 2, -64, 46, -11, -45, 36, -24, -26, 25, -38, + -7, 14, -52, 12, 4, -65, 32, -6, -79, 50, -17, -92, + -80, 56, 6, -61, 45, -6, -42, 34, -20, -23, 24, -33, + -4, 13, -47, 15, 2, -60, 34, -8, -74, 53, -18, -88, + -78, 54, 10, -58, 43, -2, -40, 33, -16, -21, 22, -29, + -1, 11, -43, 17, 1, -56, 37, -9, -70, 55, -20, -84, + -75, 53, 14, -56, 42, 1, -37, 32, -12, -18, 21, -25, + 1, 10, -39, 20, 0, -52, 39, -11, -66, 58, -21, -80, + -73, 52, 18, -54, 41, 5, -35, 30, -8, -16, 20, -21, + 3, 9, -35, 22, -1, -48, 41, -12, -62, 60, -22, -76, + -71, 50, 22, -51, 39, 9, -32, 29, -4, -14, 18, -17, + 6, 7, -31, 24, -2, -44, 44, -13, -58, 63, -24, -72, + -68, 49, 27, -49, 38, 13, -30, 27, 0, -11, 17, -13, + 8, 6, -27, 27, -4, -40, 47, -15, -54, 65, -25, -67, + -66, 47, 31, -46, 37, 17, -27, 26, 4, -9, 15, -9, + 11, 4, -23, 30, -5, -36, 49, -16, -50, 68, -27, -63, + -63, 46, 35, -44, 35, 21, -25, 25, 8, -6, 14, -5, + 13, 3, -19, 32, -7, -32, 51, -17, -46, 70, -28, -59, + -61, 45, 39, -41, 34, 25, -23, 23, 12, -4, 13, -1, + 16, 2, -15, 34, -8, -28, 54, -19, -42, 72, -29, -55, + -58, 43, 43, -39, 32, 30, -20, 22, 16, -1, 11, 3, + 18, 0, -10, 37, -9, -23, 56, -20, -37, 75, -31, -51, + -56, 42, 47, -36, 31, 34, -18, 20, 20, 1, 10, 7, + 21, 0, -6, 39, -11, -19, 59, -22, -33, 78, -32, -47, + -53, 41, 51, -34, 30, 38, -15, 19, 24, 4, 8, 11, + 23, -1, -2, 42, -12, -15, 61, -23, -29, 80, -34, -43, + -51, 39, 55, -32, 28, 42, -13, 18, 28, 6, 7, 15, + 25, -3, 1, 44, -13, -11, 64, -24, -25, 82, -35, -39, + -48, 38, 60, -29, 27, 46, -10, 16, 33, 9, 6, 19, + 28, -4, 5, 47, -15, -7, 66, -26, -21, 85, -36, -34, + -46, 36, 64, -26, 25, 50, -8, 15, 37, 11, 4, 23, + 30, -6, 9, 49, -16, -3, 69, -27, -17, 87, -38, -30, + -43, 35, 68, -24, 24, 54, -5, 13, 41, 14, 3, 27, + 33, -7, 13, 52, -18, 0, 71, -29, -13, 90, -39, -26, + -41, 34, 72, -22, 23, 58, -3, 12, 45, 16, 2, 31, + 35, -8, 17, 54, -19, 4, 73, -30, -9, 92, -41, -22, + -39, 32, 76, -19, 21, 62, 0, 11, 49, 18, 0, 35, + 38, -10, 21, 56, -20, 8, 76, -31, -5, 95, -42, -18, + -36, 31, 80, -17, 20, 67, 2, 9, 53, 21, 0, 40, + 40, -11, 26, 59, -22, 13, 79, -33, 0, 97, -43, -14, + -34, 29, 84, -14, 19, 71, 5, 8, 57, 23, -2, 44, + 43, -13, 30, 62, -23, 17, 81, -34, 3, 100, -45, -10, + -31, 28, 88, -12, 17, 75, 7, 7, 61, 26, -3, 48, + 45, -14, 34, 64, -25, 21, 83, -36, 7, 102, -46, -6, + -29, 27, 92, -9, 16, 79, 9, 5, 65, 28, -4, 52, + 48, -15, 38, 66, -26, 25, 86, -37, 11, 104, -47, -2, + -26, 25, 97, -7, 14, 83, 12, 4, 70, 31, -6, 56, + 50, -17, 42, 69, -27, 29, 88, -38, 15, 107, -49, 2, + -24, 24, 101, -4, 13, 87, 14, 2, 74, 33, -7, 60, + 53, -18, 46, 71, -29, 33, 91, -40, 19, 110, -50, 6, + -21, 23, 105, -2, 12, 91, 17, 1, 78, 36, -9, 64, + 55, -20, 50, 74, -30, 37, 93, -41, 23, 112, -52, 10, + -97, 70, -22, -77, 59, -36, -58, 48, -49, -40, 37, -63, + -20, 26, -77, -2, 16, -90, 18, 5, -104, 37, -5, -117, + -94, 68, -18, -75, 57, -32, -56, 47, -45, -37, 36, -59, + -18, 25, -73, 1, 15, -86, 20, 4, -100, 39, -6, -113, + -92, 67, -14, -72, 56, -28, -54, 45, -41, -35, 35, -55, + -16, 24, -69, 3, 13, -82, 23, 2, -96, 41, -7, -109, + -89, 65, -10, -70, 54, -24, -51, 44, -37, -32, 33, -50, + -13, 22, -64, 6, 12, -78, 25, 1, -91, 44, -9, -105, + -87, 64, -6, -67, 53, -20, -49, 42, -33, -30, 32, -46, + -10, 21, -60, 8, 10, -74, 28, 0, -87, 46, -10, -101, + -84, 63, -2, -65, 52, -16, -46, 41, -29, -27, 30, -42, + -8, 20, -56, 11, 9, -70, 30, -1, -83, 49, -12, -97, + -82, 61, 1, -63, 50, -12, -44, 40, -25, -25, 29, -38, + -6, 18, -52, 13, 8, -66, 32, -2, -79, 51, -13, -93, + -79, 60, 6, -60, 49, -7, -41, 38, -20, -22, 28, -34, + -3, 17, -48, 16, 6, -61, 35, -4, -75, 54, -14, -88, + -77, 58, 10, -58, 47, -3, -39, 37, -16, -20, 26, -30, + -1, 15, -44, 18, 5, -57, 38, -5, -71, 56, -16, -84, + -75, 57, 14, -55, 46, 0, -36, 36, -12, -18, 25, -26, + 2, 14, -40, 21, 3, -53, 40, -7, -67, 59, -17, -80, + -72, 56, 18, -53, 45, 4, -34, 34, -8, -15, 24, -22, + 4, 13, -36, 23, 2, -49, 42, -8, -63, 61, -18, -76, + -70, 54, 22, -50, 43, 8, -32, 33, -4, -13, 22, -18, + 7, 11, -32, 25, 1, -45, 45, -9, -59, 64, -20, -72, + -67, 53, 26, -48, 42, 12, -29, 31, 0, -10, 21, -13, + 9, 10, -27, 28, 0, -41, 47, -11, -54, 66, -21, -68, + -65, 51, 30, -45, 41, 16, -26, 30, 3, -8, 19, -9, + 12, 8, -23, 30, -1, -37, 50, -12, -50, 69, -23, -64, + -62, 50, 34, -43, 39, 20, -24, 29, 7, -5, 18, -5, + 14, 7, -19, 33, -3, -33, 52, -13, -46, 71, -24, -60, + -60, 49, 38, -40, 38, 24, -22, 27, 11, -3, 17, -1, + 16, 6, -15, 35, -4, -29, 55, -15, -42, 73, -25, -56, + -57, 47, 43, -38, 36, 29, -19, 26, 16, 0, 15, 2, + 19, 4, -11, 38, -5, -24, 57, -16, -38, 76, -27, -51, + -55, 46, 47, -35, 35, 33, -17, 24, 20, 2, 14, 6, + 22, 3, -7, 40, -7, -20, 60, -18, -34, 78, -28, -47, + -52, 45, 51, -33, 34, 37, -14, 23, 24, 5, 12, 10, + 24, 2, -3, 43, -8, -16, 62, -19, -30, 81, -30, -43, + -50, 43, 55, -31, 32, 41, -12, 22, 28, 7, 11, 14, + 26, 0, 0, 45, -9, -12, 64, -20, -26, 83, -31, -39, + -47, 42, 59, -28, 31, 45, -9, 20, 32, 10, 10, 19, + 29, 0, 5, 48, -11, -8, 67, -22, -21, 86, -32, -35, + -45, 40, 63, -26, 29, 49, -7, 19, 36, 12, 8, 23, + 31, -2, 9, 50, -12, -4, 70, -23, -17, 88, -34, -31, + -43, 39, 67, -23, 28, 53, -4, 17, 40, 14, 7, 27, + 34, -3, 13, 53, -14, 0, 72, -25, -13, 91, -35, -27, + -40, 38, 71, -21, 27, 57, -2, 16, 44, 17, 6, 31, + 36, -4, 17, 55, -15, 3, 74, -26, -9, 93, -37, -23, + -38, 36, 75, -18, 25, 61, 0, 15, 48, 19, 4, 35, + 39, -6, 21, 57, -16, 7, 77, -27, -5, 96, -38, -19, + -35, 35, 80, -16, 24, 66, 3, 13, 53, 22, 3, 39, + 41, -7, 25, 60, -18, 12, 79, -29, -1, 98, -39, -14, + -33, 33, 84, -13, 23, 70, 6, 12, 57, 24, 1, 43, + 44, -9, 29, 62, -19, 16, 82, -30, 2, 101, -41, -10, + -30, 32, 88, -11, 21, 74, 8, 11, 61, 27, 0, 47, + 46, -10, 33, 65, -21, 20, 84, -32, 6, 103, -42, -6, + -28, 31, 92, -8, 20, 78, 10, 9, 65, 29, 0, 51, + 48, -11, 37, 67, -22, 24, 87, -33, 10, 105, -43, -2, + -25, 29, 96, -6, 18, 82, 13, 8, 69, 32, -2, 56, + 51, -13, 42, 70, -23, 28, 89, -34, 15, 108, -45, 1, + -23, 28, 100, -3, 17, 86, 15, 6, 73, 34, -3, 60, + 54, -14, 46, 72, -25, 32, 92, -36, 19, 110, -46, 5, + -20, 27, 104, -1, 16, 90, 18, 5, 77, 37, -5, 64, + 56, -16, 50, 75, -26, 36, 94, -37, 23, 113, -48, 9, + -96, 74, -23, -76, 63, -37, -57, 53, -50, -39, 42, -64, + -19, 31, -77, -1, 20, -91, 19, 9, -105, 38, 0, -118, + -93, 73, -19, -74, 62, -33, -55, 51, -46, -36, 41, -60, + -17, 30, -73, 2, 19, -87, 21, 8, -101, 40, -1, -114, + -91, 71, -15, -71, 60, -29, -53, 50, -42, -34, 39, -56, + -15, 28, -69, 4, 18, -83, 24, 7, -97, 42, -3, -110, + -88, 70, -10, -69, 59, -24, -50, 48, -38, -31, 38, -51, + -12, 27, -65, 7, 16, -78, 26, 5, -92, 45, -4, -106, + -86, 68, -6, -66, 58, -20, -48, 47, -34, -29, 36, -47, + -9, 25, -61, 9, 15, -74, 29, 4, -88, 48, -6, -102, + -83, 67, -2, -64, 56, -16, -45, 46, -30, -26, 35, -43, + -7, 24, -57, 12, 13, -70, 31, 3, -84, 50, -7, -98, + -81, 66, 1, -62, 55, -12, -43, 44, -26, -24, 34, -39, + -5, 23, -53, 14, 12, -66, 34, 1, -80, 52, -8, -94, + -78, 64, 5, -59, 53, -8, -40, 43, -21, -21, 32, -35, + -2, 21, -48, 17, 11, -62, 36, 0, -76, 55, -10, -89, + -76, 63, 9, -56, 52, -4, -38, 41, -17, -19, 31, -31, + 0, 20, -44, 19, 9, -58, 39, -1, -72, 57, -11, -85, + -73, 62, 13, -54, 51, 0, -35, 40, -13, -17, 29, -27, + 3, 18, -40, 22, 8, -54, 41, -2, -68, 60, -13, -81, + -71, 60, 17, -52, 49, 3, -33, 39, -9, -14, 28, -23, + 5, 17, -36, 24, 7, -50, 43, -3, -64, 62, -14, -77, + -69, 59, 21, -49, 48, 7, -31, 37, -5, -12, 27, -19, + 8, 16, -32, 26, 5, -46, 46, -5, -60, 65, -15, -73, + -66, 57, 26, -47, 46, 12, -28, 36, -1, -9, 25, -14, + 10, 14, -28, 29, 4, -41, 48, -6, -55, 67, -17, -69, + -64, 56, 30, -44, 45, 16, -25, 34, 2, -7, 24, -10, + 13, 13, -24, 31, 2, -37, 51, -8, -51, 70, -18, -65, + -61, 55, 34, -42, 44, 20, -23, 33, 6, -4, 23, -6, + 15, 12, -20, 34, 1, -33, 53, -9, -47, 72, -20, -61, + -59, 53, 38, -39, 42, 24, -21, 32, 10, -2, 21, -2, + 17, 10, -16, 36, 0, -29, 56, -10, -43, 74, -21, -57, + -56, 52, 42, -37, 41, 28, -18, 30, 15, 1, 20, 1, + 20, 9, -11, 39, -1, -25, 58, -12, -39, 77, -22, -52, + -54, 50, 46, -34, 39, 32, -16, 29, 19, 3, 18, 5, + 23, 7, -7, 41, -2, -21, 61, -13, -35, 80, -24, -48, + -51, 49, 50, -32, 38, 36, -13, 28, 23, 6, 17, 9, + 25, 6, -3, 44, -4, -17, 63, -15, -31, 82, -25, -44, + -49, 48, 54, -30, 37, 40, -11, 26, 27, 8, 16, 13, + 27, 5, 0, 46, -5, -13, 66, -16, -27, 84, -26, -40, + -46, 46, 59, -27, 35, 45, -8, 25, 31, 11, 14, 18, + 30, 3, 4, 49, -6, -8, 68, -17, -22, 87, -28, -36, + -44, 45, 63, -25, 34, 49, -6, 23, 35, 13, 13, 22, + 32, 2, 8, 51, -8, -4, 71, -19, -18, 89, -29, -32, + -41, 44, 67, -22, 33, 53, -3, 22, 39, 15, 11, 26, + 35, 0, 12, 54, -9, 0, 73, -20, -14, 92, -31, -28, + -39, 42, 71, -20, 31, 57, -1, 21, 43, 18, 10, 30, + 37, 0, 16, 56, -11, 3, 75, -21, -10, 94, -32, -24, + -37, 41, 75, -17, 30, 61, 1, 19, 47, 20, 9, 34, + 40, -1, 20, 58, -12, 7, 78, -23, -6, 97, -33, -20, + -34, 39, 79, -15, 28, 65, 4, 18, 52, 23, 7, 38, + 42, -3, 25, 61, -13, 11, 80, -24, -2, 99, -35, -15, + -32, 38, 83, -12, 27, 69, 7, 16, 56, 25, 6, 42, + 45, -4, 29, 63, -15, 15, 83, -26, 1, 102, -36, -11, + -29, 37, 87, -10, 26, 73, 9, 15, 60, 28, 4, 46, + 47, -5, 33, 66, -16, 19, 85, -27, 5, 104, -38, -7, + -27, 35, 91, -7, 24, 77, 11, 14, 64, 30, 3, 50, + 49, -7, 37, 68, -17, 23, 88, -28, 9, 106, -39, -3, + -24, 34, 96, -5, 23, 82, 14, 12, 68, 33, 2, 55, + 52, -8, 41, 71, -19, 28, 90, -30, 14, 109, -40, 0, + -22, 32, 100, -2, 21, 86, 16, 11, 72, 35, 0, 59, + 55, -10, 45, 73, -20, 32, 93, -31, 18, 112, -42, 4, + -19, 31, 104, 0, 20, 90, 19, 9, 76, 38, 0, 63, + 57, -11, 49, 76, -22, 36, 95, -33, 22, 114, -43, 8, + -95, 78, -24, -75, 67, -37, -57, 57, -51, -38, 46, -64, + -18, 35, -78, 0, 24, -91, 20, 13, -105, 39, 3, -119, + -92, 77, -20, -73, 66, -33, -54, 55, -47, -35, 45, -60, + -16, 34, -74, 3, 23, -87, 22, 12, -101, 41, 2, -115, + -90, 75, -16, -71, 64, -29, -52, 54, -43, -33, 43, -56, + -14, 32, -70, 5, 22, -83, 25, 11, -97, 43, 0, -111, + -87, 74, -11, -68, 63, -25, -49, 52, -38, -30, 42, -52, + -11, 31, -66, 8, 20, -79, 27, 9, -93, 46, 0, -106, + -85, 72, -7, -65, 62, -21, -47, 51, -34, -28, 40, -48, + -9, 29, -62, 10, 19, -75, 30, 8, -89, 48, -2, -102, + -82, 71, -3, -63, 60, -17, -44, 50, -30, -25, 39, -44, + -6, 28, -58, 13, 17, -71, 32, 7, -85, 51, -3, -98, + -80, 70, 0, -61, 59, -13, -42, 48, -26, -23, 38, -40, + -4, 27, -54, 15, 16, -67, 34, 5, -81, 53, -4, -94, + -77, 68, 4, -58, 57, -8, -39, 47, -22, -20, 36, -35, + -1, 25, -49, 18, 15, -62, 37, 4, -76, 56, -6, -90, + -75, 67, 8, -56, 56, -4, -37, 45, -18, -18, 35, -31, + 1, 24, -45, 20, 13, -58, 40, 2, -72, 58, -7, -86, + -73, 66, 12, -53, 55, 0, -34, 44, -14, -16, 33, -27, + 4, 22, -41, 23, 12, -54, 42, 1, -68, 61, -9, -82, + -70, 64, 16, -51, 53, 3, -32, 43, -10, -13, 32, -23, + 6, 21, -37, 25, 11, -50, 44, 0, -64, 63, -10, -78, + -68, 63, 20, -48, 52, 7, -30, 41, -6, -11, 31, -19, + 9, 20, -33, 27, 9, -46, 47, -1, -60, 65, -11, -74, + -65, 61, 25, -46, 50, 11, -27, 40, -1, -8, 29, -15, + 11, 18, -29, 30, 8, -42, 49, -2, -56, 68, -13, -69, + -63, 60, 29, -43, 49, 15, -25, 38, 2, -6, 28, -11, + 14, 17, -25, 32, 6, -38, 52, -4, -52, 71, -14, -65, + -60, 59, 33, -41, 48, 19, -22, 37, 6, -3, 27, -7, + 16, 16, -21, 35, 5, -34, 54, -5, -48, 73, -16, -61, + -58, 57, 37, -39, 46, 23, -20, 36, 10, -1, 25, -3, + 18, 14, -17, 37, 4, -30, 57, -6, -44, 75, -17, -57, + -55, 56, 41, -36, 45, 28, -17, 34, 14, 2, 24, 1, + 21, 13, -12, 40, 2, -25, 59, -8, -39, 78, -18, -53, + -53, 54, 45, -33, 43, 32, -15, 33, 18, 4, 22, 5, + 23, 11, -8, 42, 1, -21, 62, -9, -35, 80, -20, -49, + -50, 53, 49, -31, 42, 36, -12, 32, 22, 7, 21, 9, + 26, 10, -4, 45, 0, -17, 64, -11, -31, 83, -21, -45, + -48, 52, 53, -29, 41, 40, -10, 30, 26, 9, 20, 13, + 28, 9, 0, 47, -1, -13, 66, -12, -27, 85, -22, -41, + -45, 50, 58, -26, 39, 44, -7, 29, 31, 12, 18, 17, + 31, 7, 3, 50, -2, -9, 69, -13, -23, 88, -24, -36, + -43, 49, 62, -24, 38, 48, -5, 27, 35, 14, 17, 21, + 33, 6, 7, 52, -4, -5, 72, -15, -19, 90, -25, -32, + -41, 48, 66, -21, 37, 52, -2, 26, 39, 16, 15, 25, + 36, 4, 11, 55, -5, -1, 74, -16, -15, 93, -27, -28, + -38, 46, 70, -19, 35, 56, 0, 25, 43, 19, 14, 29, + 38, 3, 15, 57, -7, 2, 76, -17, -11, 95, -28, -24, + -36, 45, 74, -16, 34, 60, 2, 23, 47, 21, 13, 33, + 41, 2, 19, 59, -8, 6, 79, -19, -7, 97, -29, -20, + -33, 43, 78, -14, 32, 65, 5, 22, 51, 24, 11, 38, + 43, 0, 24, 62, -9, 11, 81, -20, -2, 100, -31, -16, + -31, 42, 82, -11, 31, 69, 7, 20, 55, 26, 10, 42, + 46, 0, 28, 64, -11, 15, 84, -22, 1, 103, -32, -12, + -28, 41, 86, -9, 30, 73, 10, 19, 59, 29, 8, 46, + 48, -1, 32, 67, -12, 19, 86, -23, 5, 105, -34, -8, + -26, 39, 90, -7, 28, 77, 12, 18, 63, 31, 7, 50, + 50, -3, 36, 69, -13, 23, 89, -24, 9, 107, -35, -4, + -23, 38, 95, -4, 27, 81, 15, 16, 68, 34, 6, 54, + 53, -4, 40, 72, -15, 27, 91, -26, 13, 110, -36, 0, + -21, 36, 99, -1, 25, 85, 17, 15, 72, 36, 4, 58, + 55, -6, 44, 74, -16, 31, 94, -27, 17, 112, -38, 4, + -18, 35, 103, 1, 24, 89, 20, 13, 76, 38, 3, 62, + 58, -7, 48, 77, -18, 35, 96, -29, 21, 115, -39, 8, + -94, 82, -24, -74, 71, -38, -56, 61, -51, -37, 50, -65, + -17, 39, -79, 1, 28, -92, 21, 17, -106, 39, 7, -119, + -91, 81, -20, -72, 70, -34, -53, 59, -47, -34, 49, -61, + -15, 38, -75, 4, 27, -88, 23, 16, -102, 42, 6, -115, + -89, 79, -16, -70, 68, -30, -51, 58, -43, -32, 47, -57, + -13, 36, -71, 6, 26, -84, 25, 15, -98, 44, 4, -111, + -86, 78, -12, -67, 67, -26, -48, 56, -39, -29, 46, -52, + -10, 35, -66, 9, 24, -80, 28, 13, -93, 47, 3, -107, + -84, 76, -8, -65, 66, -22, -46, 55, -35, -27, 44, -48, + -8, 33, -62, 11, 23, -76, 31, 12, -89, 49, 1, -103, + -82, 75, -4, -62, 64, -18, -43, 54, -31, -25, 43, -44, + -5, 32, -58, 14, 21, -72, 33, 11, -85, 52, 0, -99, + -79, 74, 0, -60, 63, -14, -41, 52, -27, -22, 42, -40, + -3, 31, -54, 16, 20, -68, 35, 9, -81, 54, 0, -95, + -76, 72, 4, -57, 61, -9, -38, 51, -22, -19, 40, -36, + 0, 29, -50, 19, 19, -63, 38, 8, -77, 57, -2, -90, + -74, 71, 8, -55, 60, -5, -36, 49, -18, -17, 39, -32, + 2, 28, -46, 21, 17, -59, 40, 6, -73, 59, -3, -86, + -72, 70, 12, -52, 59, -1, -33, 48, -14, -15, 37, -28, + 5, 26, -42, 23, 16, -55, 43, 5, -69, 62, -5, -82, + -69, 68, 16, -50, 57, 2, -31, 47, -10, -12, 36, -24, + 7, 25, -38, 26, 15, -51, 45, 4, -65, 64, -6, -78, + -67, 67, 20, -47, 56, 6, -29, 45, -6, -10, 35, -20, + 9, 24, -34, 28, 13, -47, 48, 2, -61, 66, -7, -74, + -64, 65, 24, -45, 54, 10, -26, 44, -2, -7, 33, -15, + 12, 22, -29, 31, 12, -43, 50, 1, -56, 69, -9, -70, + -62, 64, 28, -42, 53, 14, -24, 42, 1, -5, 32, -11, + 15, 21, -25, 33, 10, -39, 53, 0, -52, 71, -10, -66, + -59, 63, 32, -40, 52, 18, -21, 41, 5, -2, 31, -7, + 17, 20, -21, 36, 9, -35, 55, -1, -48, 74, -12, -62, + -57, 61, 36, -38, 50, 22, -19, 40, 9, 0, 29, -3, + 19, 18, -17, 38, 8, -31, 57, -2, -44, 76, -13, -58, + -54, 60, 41, -35, 49, 27, -16, 38, 14, 3, 28, 0, + 22, 17, -13, 41, 6, -26, 60, -4, -40, 79, -14, -53, + -52, 58, 45, -33, 47, 31, -14, 37, 18, 5, 26, 4, + 24, 15, -9, 43, 5, -22, 63, -5, -36, 81, -16, -49, + -50, 57, 49, -30, 46, 35, -11, 36, 22, 7, 25, 8, + 27, 14, -5, 46, 3, -18, 65, -7, -32, 84, -17, -45, + -47, 56, 53, -28, 45, 39, -9, 34, 26, 10, 24, 12, + 29, 13, -1, 48, 2, -14, 67, -8, -28, 86, -18, -41, + -44, 54, 57, -25, 43, 43, -6, 33, 30, 12, 22, 17, + 32, 11, 3, 51, 1, -10, 70, -9, -23, 89, -20, -37, + -42, 53, 61, -23, 42, 47, -4, 31, 34, 15, 21, 21, + 34, 10, 7, 53, 0, -6, 72, -11, -19, 91, -21, -33, + -40, 52, 65, -20, 41, 51, -2, 30, 38, 17, 19, 25, + 37, 8, 11, 55, -1, -2, 75, -12, -15, 94, -23, -29, + -37, 50, 69, -18, 39, 55, 1, 29, 42, 20, 18, 29, + 39, 7, 15, 58, -3, 1, 77, -13, -11, 96, -24, -25, + -35, 49, 73, -16, 38, 59, 3, 27, 46, 22, 17, 33, + 41, 6, 19, 60, -4, 5, 80, -15, -7, 98, -25, -21, + -32, 47, 78, -13, 36, 64, 6, 26, 51, 25, 15, 37, + 44, 4, 23, 63, -5, 10, 82, -16, -3, 101, -27, -16, + -30, 46, 82, -10, 35, 68, 8, 24, 55, 27, 14, 41, + 47, 3, 27, 65, -7, 14, 85, -18, 0, 103, -28, -12, + -27, 45, 86, -8, 34, 72, 11, 23, 59, 30, 12, 45, + 49, 2, 31, 68, -8, 18, 87, -19, 4, 106, -30, -8, + -25, 43, 90, -6, 32, 76, 13, 22, 63, 32, 11, 49, + 51, 0, 35, 70, -9, 22, 89, -20, 8, 108, -31, -4, + -22, 42, 94, -3, 31, 80, 16, 20, 67, 35, 10, 54, + 54, 0, 40, 73, -11, 26, 92, -22, 13, 111, -32, 0, + -20, 40, 98, -1, 29, 84, 18, 19, 71, 37, 8, 58, + 56, -2, 44, 75, -12, 30, 95, -23, 17, 113, -34, 3, + -18, 39, 102, 2, 28, 88, 21, 17, 75, 39, 7, 62, + 59, -3, 48, 78, -14, 34, 97, -25, 21, 116, -35, 7, + -93, 86, -25, -73, 75, -39, -55, 65, -52, -36, 54, -66, + -17, 43, -79, 2, 32, -93, 22, 21, -107, 40, 11, -120, + -90, 85, -21, -71, 74, -35, -52, 63, -48, -34, 53, -62, + -14, 42, -75, 5, 31, -89, 24, 20, -103, 43, 10, -116, + -88, 83, -17, -69, 72, -31, -50, 62, -44, -31, 51, -58, + -12, 40, -71, 7, 30, -85, 26, 19, -99, 45, 8, -112, + -85, 82, -12, -66, 71, -26, -47, 60, -40, -28, 50, -53, + -9, 39, -67, 10, 28, -80, 29, 17, -94, 48, 7, -107, + -83, 80, -8, -64, 70, -22, -45, 59, -36, -26, 48, -49, + -7, 37, -63, 12, 27, -76, 31, 16, -90, 50, 5, -103, + -81, 79, -4, -61, 68, -18, -42, 58, -32, -24, 47, -45, + -4, 36, -59, 14, 25, -72, 34, 15, -86, 53, 4, -99, + -78, 78, 0, -59, 67, -14, -40, 56, -28, -21, 46, -41, + -2, 35, -55, 17, 24, -68, 36, 13, -82, 55, 3, -95, + -76, 76, 3, -56, 65, -10, -37, 55, -23, -19, 44, -37, + 1, 33, -50, 20, 23, -64, 39, 12, -78, 58, 1, -91, + -73, 75, 7, -54, 64, -6, -35, 53, -19, -16, 43, -33, + 3, 32, -46, 22, 21, -60, 41, 10, -74, 60, 0, -87, + -71, 74, 11, -51, 63, -2, -33, 52, -15, -14, 41, -29, + 6, 30, -42, 24, 20, -56, 44, 9, -70, 63, -1, -83, + -68, 72, 15, -49, 61, 1, -30, 51, -11, -11, 40, -25, + 8, 29, -38, 27, 19, -52, 46, 8, -66, 65, -2, -79, + -66, 71, 19, -47, 60, 5, -28, 49, -7, -9, 39, -21, + 10, 28, -34, 29, 17, -48, 49, 6, -62, 67, -3, -75, + -63, 69, 24, -44, 58, 10, -25, 48, -3, -6, 37, -16, + 13, 26, -30, 32, 16, -43, 51, 5, -57, 70, -5, -70, + -61, 68, 28, -42, 57, 14, -23, 46, 0, -4, 36, -12, + 15, 25, -26, 34, 14, -39, 54, 3, -53, 72, -6, -66, + -58, 67, 32, -39, 56, 18, -20, 45, 4, -2, 35, -8, + 18, 24, -22, 37, 13, -35, 56, 2, -49, 75, -8, -62, + -56, 65, 36, -37, 54, 22, -18, 44, 8, 1, 33, -4, + 20, 22, -18, 39, 12, -31, 58, 1, -45, 77, -9, -58, + -53, 64, 40, -34, 53, 26, -15, 42, 13, 4, 32, 0, + 23, 21, -13, 42, 10, -27, 61, 0, -41, 80, -10, -54, + -51, 62, 44, -32, 51, 30, -13, 41, 17, 6, 30, 3, + 25, 19, -9, 44, 9, -23, 63, -1, -37, 82, -12, -50, + -49, 61, 48, -29, 50, 34, -10, 40, 21, 8, 29, 7, + 28, 18, -5, 46, 7, -19, 66, -3, -33, 85, -13, -46, + -46, 60, 52, -27, 49, 38, -8, 38, 25, 11, 28, 11, + 30, 17, -1, 49, 6, -15, 68, -4, -29, 87, -14, -42, + -44, 58, 57, -24, 47, 43, -5, 37, 29, 13, 26, 16, + 33, 15, 2, 52, 5, -10, 71, -5, -24, 90, -16, -37, + -41, 57, 61, -22, 46, 47, -3, 35, 33, 16, 25, 20, + 35, 14, 6, 54, 3, -6, 73, -7, -20, 92, -17, -33, + -39, 56, 65, -19, 45, 51, -1, 34, 37, 18, 23, 24, + 38, 12, 10, 56, 2, -2, 76, -8, -16, 95, -19, -29, + -36, 54, 69, -17, 43, 55, 2, 33, 41, 21, 22, 28, + 40, 11, 14, 59, 0, 1, 78, -9, -12, 97, -20, -25, + -34, 53, 73, -15, 42, 59, 4, 31, 45, 23, 21, 32, + 42, 10, 18, 61, 0, 5, 81, -11, -8, 99, -21, -21, + -31, 51, 77, -12, 40, 63, 7, 30, 50, 26, 19, 36, + 45, 8, 23, 64, -1, 9, 83, -12, -4, 102, -23, -17, + -29, 50, 81, -10, 39, 67, 9, 28, 54, 28, 18, 40, + 47, 7, 27, 66, -3, 13, 86, -14, 0, 104, -24, -13, + -26, 49, 85, -7, 38, 71, 12, 27, 58, 30, 16, 44, + 50, 6, 31, 69, -4, 17, 88, -15, 3, 107, -26, -9, + -24, 47, 89, -5, 36, 75, 14, 26, 62, 33, 15, 48, + 52, 4, 35, 71, -5, 21, 90, -16, 7, 109, -27, -5, + -21, 46, 94, -2, 35, 80, 17, 24, 66, 36, 14, 53, + 55, 3, 39, 74, -7, 26, 93, -18, 12, 112, -28, 0, + -19, 44, 98, 0, 33, 84, 19, 23, 70, 38, 12, 57, + 57, 1, 43, 76, -8, 30, 95, -19, 16, 114, -30, 3, + -17, 43, 102, 3, 32, 88, 22, 21, 74, 40, 11, 61, + 60, 0, 47, 78, -10, 34, 98, -21, 20, 117, -31, 7, + -92, 90, -26, -73, 79, -39, -54, 69, -53, -35, 58, -66, + -16, 47, -80, 3, 36, -93, 23, 25, -107, 41, 15, -121, + -90, 89, -22, -70, 78, -35, -51, 67, -49, -33, 57, -62, + -13, 46, -76, 6, 35, -89, 25, 24, -103, 44, 14, -117, + -87, 87, -18, -68, 76, -31, -49, 66, -45, -30, 55, -58, + -11, 44, -72, 8, 34, -85, 27, 23, -99, 46, 12, -113, + -84, 86, -13, -65, 75, -27, -46, 64, -40, -28, 54, -54, + -8, 43, -67, 11, 32, -81, 30, 21, -95, 49, 11, -108, + -82, 84, -9, -63, 74, -23, -44, 63, -36, -25, 52, -50, + -6, 41, -63, 13, 31, -77, 32, 20, -91, 51, 9, -104, + -80, 83, -5, -60, 72, -19, -42, 62, -32, -23, 51, -46, + -3, 40, -59, 15, 29, -73, 35, 19, -87, 54, 8, -100, + -77, 82, -1, -58, 71, -15, -39, 60, -28, -20, 50, -42, + -1, 39, -55, 18, 28, -69, 37, 17, -83, 56, 7, -96, + -75, 80, 2, -55, 69, -10, -36, 59, -24, -18, 48, -37, + 2, 37, -51, 20, 27, -64, 40, 16, -78, 59, 5, -92, + -72, 79, 6, -53, 68, -6, -34, 57, -20, -15, 47, -33, + 4, 36, -47, 23, 25, -60, 42, 14, -74, 61, 4, -88, + -70, 78, 10, -50, 67, -2, -32, 56, -16, -13, 45, -29, + 6, 34, -43, 25, 24, -56, 45, 13, -70, 63, 2, -84, + -67, 76, 14, -48, 65, 1, -29, 55, -12, -10, 44, -25, + 9, 33, -39, 28, 23, -52, 47, 12, -66, 66, 1, -80, + -65, 75, 18, -46, 64, 5, -27, 53, -8, -8, 43, -21, + 11, 32, -35, 30, 21, -48, 49, 10, -62, 68, 0, -76, + -62, 73, 23, -43, 62, 9, -24, 52, -3, -5, 41, -17, + 14, 30, -30, 33, 20, -44, 52, 9, -58, 71, -1, -71, + -60, 72, 27, -41, 61, 13, -22, 50, 0, -3, 40, -13, + 16, 29, -26, 35, 18, -40, 55, 7, -54, 73, -2, -67, + -58, 71, 31, -38, 60, 17, -19, 49, 4, -1, 39, -9, + 19, 28, -22, 38, 17, -36, 57, 6, -50, 76, -4, -63, + -55, 69, 35, -36, 58, 21, -17, 48, 8, 2, 37, -5, + 21, 26, -18, 40, 16, -32, 59, 5, -46, 78, -5, -59, + -52, 68, 39, -33, 57, 26, -14, 46, 12, 4, 36, 0, + 24, 25, -14, 43, 14, -27, 62, 3, -41, 81, -6, -55, + -50, 66, 43, -31, 55, 30, -12, 45, 16, 7, 34, 3, + 26, 23, -10, 45, 13, -23, 64, 2, -37, 83, -8, -51, + -48, 65, 47, -28, 54, 34, -10, 44, 20, 9, 33, 7, + 29, 22, -6, 47, 11, -19, 67, 0, -33, 86, -9, -47, + -45, 64, 51, -26, 53, 38, -7, 42, 24, 12, 32, 11, + 31, 21, -2, 50, 10, -15, 69, 0, -29, 88, -10, -43, + -43, 62, 56, -23, 51, 42, -4, 41, 29, 14, 30, 15, + 34, 19, 2, 52, 9, -11, 72, -1, -25, 91, -12, -38, + -40, 61, 60, -21, 50, 46, -2, 39, 33, 17, 29, 19, + 36, 18, 6, 55, 7, -7, 74, -3, -21, 93, -13, -34, + -38, 60, 64, -18, 49, 50, 0, 38, 37, 19, 27, 23, + 38, 16, 10, 57, 6, -3, 77, -4, -17, 95, -15, -30, + -35, 58, 68, -16, 47, 54, 3, 37, 41, 21, 26, 27, + 41, 15, 14, 60, 4, 0, 79, -5, -13, 98, -16, -26, + -33, 57, 72, -14, 46, 58, 5, 35, 45, 24, 25, 31, + 43, 14, 18, 62, 3, 4, 81, -7, -9, 100, -17, -22, + -30, 55, 76, -11, 44, 63, 8, 34, 49, 27, 23, 36, + 46, 12, 22, 65, 2, 9, 84, -8, -4, 103, -19, -18, + -28, 54, 80, -9, 43, 67, 10, 32, 53, 29, 22, 40, + 48, 11, 26, 67, 0, 13, 86, -10, 0, 105, -20, -14, + -26, 53, 84, -6, 42, 71, 13, 31, 57, 31, 20, 44, + 51, 10, 30, 70, 0, 17, 89, -11, 3, 108, -22, -10, + -23, 51, 88, -4, 40, 75, 15, 30, 61, 34, 19, 48, + 53, 8, 34, 72, -1, 21, 91, -12, 7, 110, -23, -6, + -20, 50, 93, -1, 39, 79, 18, 28, 66, 36, 18, 52, + 56, 7, 39, 75, -3, 25, 94, -14, 11, 113, -24, -1, + -18, 48, 97, 1, 37, 83, 20, 27, 70, 39, 16, 56, + 58, 5, 43, 77, -4, 29, 96, -15, 15, 115, -26, 2, + -16, 47, 101, 4, 36, 87, 22, 25, 74, 41, 15, 60, + 61, 4, 47, 79, -6, 33, 99, -17, 19, 118, -27, 6, + -91, 95, -26, -72, 84, -40, -53, 73, -54, -34, 62, -67, + -15, 51, -81, 4, 41, -94, 24, 30, -108, 42, 19, -121, + -89, 93, -22, -69, 82, -36, -50, 72, -50, -32, 61, -63, + -12, 50, -77, 7, 40, -90, 26, 29, -104, 45, 18, -117, + -86, 92, -18, -67, 81, -32, -48, 70, -46, -29, 60, -59, + -10, 49, -73, 9, 38, -86, 28, 27, -100, 47, 17, -113, + -83, 90, -14, -64, 79, -28, -45, 69, -41, -27, 58, -54, + -7, 47, -68, 12, 37, -82, 31, 26, -95, 50, 15, -109, + -81, 89, -10, -62, 78, -24, -43, 67, -37, -24, 57, -50, + -5, 46, -64, 14, 35, -78, 33, 24, -91, 52, 14, -105, + -79, 88, -6, -59, 77, -20, -41, 66, -33, -22, 55, -46, + -2, 45, -60, 16, 34, -74, 36, 23, -87, 55, 12, -101, + -76, 86, -2, -57, 75, -16, -38, 65, -29, -19, 54, -42, + 0, 43, -56, 19, 33, -70, 38, 22, -83, 57, 11, -97, + -74, 85, 2, -54, 74, -11, -35, 63, -25, -17, 53, -38, + 3, 42, -52, 22, 31, -65, 41, 20, -79, 60, 10, -92, + -71, 83, 6, -52, 72, -7, -33, 62, -21, -14, 51, -34, + 5, 40, -48, 24, 30, -61, 43, 19, -75, 62, 8, -88, + -69, 82, 10, -49, 71, -3, -31, 61, -17, -12, 50, -30, + 8, 39, -44, 26, 28, -57, 46, 17, -71, 64, 7, -84, + -66, 81, 14, -47, 70, 0, -28, 59, -13, -9, 49, -26, + 10, 38, -40, 29, 27, -53, 48, 16, -67, 67, 6, -80, + -64, 79, 18, -45, 68, 4, -26, 58, -9, -7, 47, -22, + 12, 36, -36, 31, 26, -49, 50, 15, -63, 69, 4, -76, + -61, 78, 22, -42, 67, 8, -23, 56, -4, -4, 46, -17, + 15, 35, -31, 34, 24, -45, 53, 13, -58, 72, 3, -72, + -59, 76, 26, -40, 66, 12, -21, 55, 0, -2, 44, -13, + 17, 33, -27, 36, 23, -41, 56, 12, -54, 74, 1, -68, + -57, 75, 30, -37, 64, 16, -18, 54, 3, 0, 43, -9, + 20, 32, -23, 39, 21, -37, 58, 11, -50, 77, 0, -64, + -54, 74, 34, -35, 63, 20, -16, 52, 7, 3, 42, -5, + 22, 31, -19, 41, 20, -33, 60, 9, -46, 79, 0, -60, + -51, 72, 39, -32, 61, 25, -13, 51, 11, 5, 40, -1, + 25, 29, -15, 44, 19, -28, 63, 8, -42, 82, -2, -55, + -49, 71, 43, -30, 60, 29, -11, 49, 15, 8, 39, 2, + 27, 28, -11, 46, 17, -24, 65, 6, -38, 84, -3, -51, + -47, 70, 47, -27, 59, 33, -9, 48, 19, 10, 37, 6, + 30, 27, -7, 48, 16, -20, 68, 5, -34, 87, -5, -47, + -44, 68, 51, -25, 57, 37, -6, 47, 23, 13, 36, 10, + 32, 25, -3, 51, 15, -16, 70, 4, -30, 89, -6, -43, + -42, 67, 55, -22, 56, 41, -3, 45, 28, 15, 35, 15, + 35, 24, 1, 54, 13, -12, 73, 2, -25, 92, -7, -39, + -39, 65, 59, -20, 54, 45, -1, 44, 32, 18, 33, 19, + 37, 22, 5, 56, 12, -8, 75, 1, -21, 94, -9, -35, + -37, 64, 63, -17, 53, 49, 1, 42, 36, 20, 32, 23, + 40, 21, 9, 58, 10, -4, 78, 0, -17, 96, -10, -31, + -34, 63, 67, -15, 52, 53, 4, 41, 40, 23, 31, 27, + 42, 20, 13, 61, 9, 0, 80, -1, -13, 99, -12, -27, + -32, 61, 71, -13, 50, 57, 6, 40, 44, 25, 29, 31, + 44, 18, 17, 63, 8, 3, 82, -2, -9, 101, -13, -23, + -29, 60, 76, -10, 49, 62, 9, 38, 48, 28, 28, 35, + 47, 17, 21, 66, 6, 8, 85, -4, -5, 104, -14, -18, + -27, 58, 80, -8, 48, 66, 11, 37, 52, 30, 26, 39, + 49, 15, 25, 68, 5, 12, 88, -5, -1, 106, -16, -14, + -25, 57, 84, -5, 46, 70, 14, 36, 56, 32, 25, 43, + 52, 14, 29, 71, 3, 16, 90, -7, 2, 109, -17, -10, + -22, 56, 88, -3, 45, 74, 16, 34, 60, 35, 24, 47, + 54, 13, 33, 73, 2, 20, 92, -8, 6, 111, -18, -6, + -19, 54, 92, 0, 43, 78, 19, 33, 65, 37, 22, 52, + 57, 11, 38, 76, 1, 24, 95, -9, 11, 114, -20, -2, + -17, 53, 96, 2, 42, 82, 21, 31, 69, 40, 21, 56, + 59, 10, 42, 78, 0, 28, 97, -11, 15, 116, -21, 1, + -15, 52, 100, 5, 41, 86, 23, 30, 73, 42, 19, 60, + 62, 8, 46, 80, -1, 32, 100, -12, 19, 119, -23, 5, + -90, 99, -27, -71, 88, -41, -52, 77, -54, -33, 66, -68, + -14, 55, -81, 5, 45, -95, 24, 34, -109, 43, 23, -122, + -88, 97, -23, -68, 86, -37, -49, 76, -50, -31, 65, -64, + -11, 54, -77, 7, 44, -91, 27, 33, -105, 46, 22, -118, + -85, 96, -19, -66, 85, -33, -47, 74, -46, -28, 64, -60, + -9, 53, -73, 10, 42, -87, 29, 31, -101, 48, 21, -114, + -83, 94, -14, -63, 83, -28, -44, 73, -42, -26, 62, -55, + -6, 51, -69, 13, 41, -82, 32, 30, -96, 51, 19, -109, + -80, 93, -10, -61, 82, -24, -42, 71, -38, -23, 61, -51, + -4, 50, -65, 15, 39, -78, 34, 28, -92, 53, 18, -105, + -78, 92, -6, -58, 81, -20, -40, 70, -34, -21, 59, -47, + -1, 49, -61, 17, 38, -74, 37, 27, -88, 55, 16, -101, + -75, 90, -2, -56, 79, -16, -37, 69, -30, -18, 58, -43, + 1, 47, -57, 20, 37, -70, 39, 26, -84, 58, 15, -97, + -73, 89, 1, -53, 78, -12, -35, 67, -25, -16, 57, -39, + 4, 46, -52, 22, 35, -66, 42, 24, -80, 61, 14, -93, + -70, 87, 5, -51, 76, -8, -32, 66, -21, -13, 55, -35, + 6, 44, -48, 25, 34, -62, 44, 23, -76, 63, 12, -89, + -68, 86, 9, -49, 75, -4, -30, 65, -17, -11, 54, -31, + 8, 43, -44, 27, 32, -58, 47, 21, -72, 65, 11, -85, + -65, 85, 13, -46, 74, 0, -27, 63, -13, -9, 53, -27, + 11, 42, -40, 30, 31, -54, 49, 20, -68, 68, 10, -81, + -63, 83, 17, -44, 72, 3, -25, 62, -9, -6, 51, -23, + 13, 40, -36, 32, 30, -50, 51, 19, -64, 70, 8, -77, + -60, 82, 22, -41, 71, 8, -22, 60, -5, -3, 50, -18, + 16, 39, -32, 35, 28, -45, 54, 17, -59, 73, 7, -72, + -58, 80, 26, -39, 70, 12, -20, 59, -1, -1, 48, -14, + 18, 37, -28, 37, 27, -41, 56, 16, -55, 75, 5, -68, + -56, 79, 30, -36, 68, 16, -17, 58, 2, 1, 47, -10, + 21, 36, -24, 39, 25, -37, 59, 15, -51, 78, 4, -64, + -53, 78, 34, -34, 67, 20, -15, 56, 6, 4, 46, -6, + 23, 35, -20, 42, 24, -33, 61, 13, -47, 80, 3, -60, + -51, 76, 38, -31, 65, 24, -12, 55, 11, 6, 44, -2, + 26, 33, -15, 45, 23, -29, 64, 12, -43, 83, 1, -56, + -48, 75, 42, -29, 64, 28, -10, 53, 15, 9, 43, 1, + 28, 32, -11, 47, 21, -25, 66, 10, -39, 85, 0, -52, + -46, 74, 46, -26, 63, 32, -8, 52, 19, 11, 41, 5, + 31, 31, -7, 49, 20, -21, 69, 9, -35, 87, -1, -48, + -43, 72, 50, -24, 61, 36, -5, 51, 23, 14, 40, 9, + 33, 29, -3, 52, 19, -17, 71, 8, -31, 90, -2, -44, + -41, 71, 55, -21, 60, 41, -3, 49, 27, 16, 39, 14, + 36, 28, 0, 54, 17, -12, 74, 6, -26, 93, -3, -39, + -38, 69, 59, -19, 58, 45, 0, 48, 31, 19, 37, 18, + 38, 26, 4, 57, 16, -8, 76, 5, -22, 95, -5, -35, + -36, 68, 63, -17, 57, 49, 2, 46, 35, 21, 36, 22, + 40, 25, 8, 59, 14, -4, 79, 3, -18, 97, -6, -31, + -34, 67, 67, -14, 56, 53, 5, 45, 39, 23, 35, 26, + 43, 24, 12, 62, 13, 0, 81, 2, -14, 100, -8, -27, + -31, 65, 71, -12, 54, 57, 7, 44, 43, 26, 33, 30, + 45, 22, 16, 64, 12, 3, 83, 1, -10, 102, -9, -23, + -28, 64, 75, -9, 53, 61, 10, 42, 48, 29, 32, 34, + 48, 21, 21, 67, 10, 7, 86, 0, -6, 105, -10, -19, + -26, 62, 79, -7, 52, 65, 12, 41, 52, 31, 30, 38, + 50, 19, 25, 69, 9, 11, 88, -1, -2, 107, -12, -15, + -24, 61, 83, -4, 50, 69, 15, 40, 56, 33, 29, 42, + 53, 18, 29, 71, 7, 15, 91, -3, 1, 110, -13, -11, + -21, 60, 87, -2, 49, 73, 17, 38, 60, 36, 28, 46, + 55, 17, 33, 74, 6, 19, 93, -4, 5, 112, -14, -7, + -19, 58, 92, 1, 47, 78, 20, 37, 64, 38, 26, 51, + 58, 15, 37, 77, 5, 24, 96, -5, 10, 115, -16, -2, + -16, 57, 96, 3, 46, 82, 22, 35, 68, 41, 25, 55, + 60, 14, 41, 79, 3, 28, 98, -7, 14, 117, -17, 1, + -14, 56, 100, 6, 45, 86, 24, 34, 72, 43, 23, 59, + 63, 12, 45, 81, 2, 32, 101, -8, 18, 119, -19, 5, + -89, 103, -28, -70, 92, -41, -51, 81, -55, -32, 70, -68, + -13, 59, -82, 6, 49, -95, 25, 38, -109, 44, 27, -123, + -87, 101, -24, -67, 90, -37, -49, 80, -51, -30, 69, -64, + -10, 58, -78, 8, 48, -91, 28, 37, -105, 47, 26, -119, + -84, 100, -20, -65, 89, -33, -46, 78, -47, -27, 68, -60, + -8, 57, -74, 11, 46, -87, 30, 35, -101, 49, 25, -115, + -82, 98, -15, -62, 87, -29, -43, 77, -42, -25, 66, -56, + -5, 55, -70, 13, 45, -83, 33, 34, -97, 52, 23, -110, + -79, 97, -11, -60, 86, -25, -41, 75, -38, -22, 65, -52, + -3, 54, -66, 16, 43, -79, 35, 32, -93, 54, 22, -106, + -77, 96, -7, -57, 85, -21, -39, 74, -34, -20, 63, -48, + -1, 53, -62, 18, 42, -75, 38, 31, -89, 56, 20, -102, + -74, 94, -3, -55, 83, -17, -36, 73, -30, -18, 62, -44, + 2, 51, -58, 21, 41, -71, 40, 30, -85, 59, 19, -98, + -72, 93, 0, -52, 82, -12, -34, 71, -26, -15, 61, -39, + 5, 50, -53, 23, 39, -66, 43, 28, -80, 61, 18, -94, + -69, 91, 4, -50, 80, -8, -31, 70, -22, -12, 59, -35, + 7, 48, -49, 26, 38, -62, 45, 27, -76, 64, 16, -90, + -67, 90, 8, -48, 79, -4, -29, 69, -18, -10, 58, -31, + 9, 47, -45, 28, 36, -58, 47, 25, -72, 66, 15, -86, + -65, 89, 12, -45, 78, 0, -26, 67, -14, -8, 57, -27, + 12, 46, -41, 31, 35, -54, 50, 24, -68, 69, 14, -82, + -62, 87, 16, -43, 76, 3, -24, 66, -10, -5, 55, -23, + 14, 44, -37, 33, 34, -50, 52, 23, -64, 71, 12, -78, + -60, 86, 21, -40, 75, 7, -21, 64, -5, -3, 54, -19, + 17, 43, -33, 36, 32, -46, 55, 21, -60, 74, 11, -73, + -57, 84, 25, -38, 74, 11, -19, 63, -1, 0, 52, -15, + 19, 41, -29, 38, 31, -42, 57, 20, -56, 76, 9, -69, + -55, 83, 29, -35, 72, 15, -17, 62, 2, 2, 51, -11, + 22, 40, -25, 40, 29, -38, 60, 19, -52, 79, 8, -65, + -52, 82, 33, -33, 71, 19, -14, 60, 6, 5, 50, -7, + 24, 39, -21, 43, 28, -34, 62, 17, -48, 81, 7, -61, + -50, 80, 37, -30, 69, 24, -11, 59, 10, 7, 48, -2, + 27, 37, -16, 45, 27, -29, 65, 16, -43, 84, 5, -57, + -47, 79, 41, -28, 68, 28, -9, 57, 14, 10, 47, 1, + 29, 36, -12, 48, 25, -25, 67, 14, -39, 86, 4, -53, + -45, 78, 45, -25, 67, 32, -7, 56, 18, 12, 45, 5, + 31, 35, -8, 50, 24, -21, 70, 13, -35, 88, 2, -49, + -42, 76, 49, -23, 65, 36, -4, 55, 22, 14, 44, 9, + 34, 33, -4, 53, 23, -17, 72, 12, -31, 91, 1, -45, + -40, 75, 54, -20, 64, 40, -2, 53, 27, 17, 43, 13, + 37, 32, 0, 55, 21, -13, 75, 10, -27, 93, 0, -40, + -37, 73, 58, -18, 62, 44, 1, 52, 31, 20, 41, 17, + 39, 30, 3, 58, 20, -9, 77, 9, -23, 96, -1, -36, + -35, 72, 62, -16, 61, 48, 3, 50, 35, 22, 40, 21, + 41, 29, 7, 60, 18, -5, 79, 7, -19, 98, -2, -32, + -33, 71, 66, -13, 60, 52, 6, 49, 39, 24, 39, 25, + 44, 28, 11, 63, 17, -1, 82, 6, -15, 101, -4, -28, + -30, 69, 70, -11, 58, 56, 8, 48, 43, 27, 37, 29, + 46, 26, 15, 65, 16, 2, 84, 5, -11, 103, -5, -24, + -28, 68, 74, -8, 57, 61, 11, 46, 47, 29, 36, 34, + 49, 25, 20, 68, 14, 7, 87, 3, -6, 106, -6, -20, + -25, 66, 78, -6, 56, 65, 13, 45, 51, 32, 34, 38, + 51, 23, 24, 70, 13, 11, 89, 2, -2, 108, -8, -16, + -23, 65, 82, -3, 54, 69, 15, 44, 55, 34, 33, 42, + 54, 22, 28, 72, 11, 15, 92, 0, 1, 111, -9, -12, + -20, 64, 86, -1, 53, 73, 18, 42, 59, 37, 32, 46, + 56, 21, 32, 75, 10, 19, 94, 0, 5, 113, -10, -8, + -18, 62, 91, 2, 51, 77, 21, 41, 64, 39, 30, 50, + 59, 19, 36, 77, 9, 23, 97, -1, 9, 116, -12, -3, + -15, 61, 95, 4, 50, 81, 23, 39, 68, 42, 29, 54, + 61, 18, 40, 80, 7, 27, 99, -3, 13, 118, -13, 0, + -13, 60, 99, 7, 49, 85, 25, 38, 72, 44, 27, 58, + 63, 16, 44, 82, 6, 31, 102, -4, 17, 120, -15, 4, + -88, 107, -28, -69, 96, -42, -50, 85, -55, -31, 74, -69, + -12, 63, -83, 7, 53, -96, 26, 42, -110, 45, 31, -123, + -86, 105, -24, -66, 94, -38, -48, 84, -51, -29, 73, -65, + -9, 62, -79, 9, 52, -92, 29, 41, -106, 47, 30, -119, + -83, 104, -20, -64, 93, -34, -45, 82, -47, -26, 72, -61, + -7, 61, -75, 12, 50, -88, 31, 39, -102, 50, 29, -115, + -81, 102, -16, -61, 91, -30, -43, 81, -43, -24, 70, -56, + -4, 59, -70, 14, 49, -84, 34, 38, -97, 53, 27, -111, + -78, 101, -12, -59, 90, -26, -40, 79, -39, -21, 69, -52, + -2, 58, -66, 17, 47, -80, 36, 36, -93, 55, 26, -107, + -76, 100, -8, -57, 89, -22, -38, 78, -35, -19, 67, -48, + 0, 57, -62, 19, 46, -76, 39, 35, -89, 57, 24, -103, + -74, 98, -4, -54, 87, -18, -35, 77, -31, -17, 66, -44, + 3, 55, -58, 22, 45, -72, 41, 34, -85, 60, 23, -99, + -71, 97, 0, -51, 86, -13, -33, 75, -26, -14, 65, -40, + 5, 54, -54, 24, 43, -67, 44, 32, -81, 62, 22, -94, + -68, 95, 4, -49, 84, -9, -30, 74, -22, -12, 63, -36, + 8, 52, -50, 27, 42, -63, 46, 31, -77, 65, 20, -90, + -66, 94, 8, -47, 83, -5, -28, 73, -18, -9, 62, -32, + 10, 51, -46, 29, 40, -59, 48, 29, -73, 67, 19, -86, + -64, 93, 12, -44, 82, -1, -26, 71, -14, -7, 61, -28, + 13, 50, -42, 31, 39, -55, 51, 28, -69, 70, 18, -82, + -61, 91, 16, -42, 80, 2, -23, 70, -10, -4, 59, -24, + 15, 48, -38, 34, 38, -51, 53, 27, -65, 72, 16, -78, + -59, 90, 20, -39, 79, 6, -20, 68, -6, -2, 58, -19, + 18, 47, -33, 37, 36, -47, 56, 25, -60, 75, 15, -74, + -56, 88, 24, -37, 78, 10, -18, 67, -2, 1, 56, -15, + 20, 45, -29, 39, 35, -43, 58, 24, -56, 77, 13, -70, + -54, 87, 28, -34, 76, 14, -16, 66, 1, 3, 55, -11, + 23, 44, -25, 41, 33, -39, 61, 23, -52, 79, 12, -66, + -51, 86, 32, -32, 75, 18, -13, 64, 5, 6, 54, -7, + 25, 43, -21, 44, 32, -35, 63, 21, -48, 82, 11, -62, + -49, 84, 37, -29, 73, 23, -11, 63, 10, 8, 52, -3, + 28, 41, -17, 46, 31, -30, 66, 20, -44, 85, 9, -57, + -46, 83, 41, -27, 72, 27, -8, 61, 14, 11, 51, 0, + 30, 40, -13, 49, 29, -26, 68, 18, -40, 87, 8, -53, + -44, 82, 45, -25, 71, 31, -6, 60, 18, 13, 49, 4, + 32, 39, -9, 51, 28, -22, 71, 17, -36, 89, 6, -49, + -42, 80, 49, -22, 69, 35, -3, 59, 22, 15, 48, 8, + 35, 37, -5, 54, 27, -18, 73, 16, -32, 92, 5, -45, + -39, 79, 53, -19, 68, 39, -1, 57, 26, 18, 47, 13, + 37, 36, 0, 56, 25, -14, 76, 14, -27, 94, 4, -41, + -36, 77, 57, -17, 66, 43, 2, 56, 30, 20, 45, 17, + 40, 34, 3, 59, 24, -10, 78, 13, -23, 97, 2, -37, + -34, 76, 61, -15, 65, 47, 4, 54, 34, 23, 44, 21, + 42, 33, 7, 61, 22, -6, 80, 11, -19, 99, 1, -33, + -32, 75, 65, -12, 64, 51, 6, 53, 38, 25, 43, 25, + 45, 32, 11, 63, 21, -2, 83, 10, -15, 102, 0, -29, + -29, 73, 69, -10, 62, 55, 9, 52, 42, 28, 41, 29, + 47, 30, 15, 66, 20, 1, 85, 9, -11, 104, -1, -25, + -27, 72, 74, -7, 61, 60, 12, 50, 47, 30, 40, 33, + 50, 29, 19, 68, 18, 6, 88, 7, -7, 107, -2, -20, + -24, 70, 78, -5, 60, 64, 14, 49, 51, 33, 38, 37, + 52, 27, 23, 71, 17, 10, 90, 6, -3, 109, -4, -16, + -22, 69, 82, -2, 58, 68, 16, 48, 55, 35, 37, 41, + 54, 26, 27, 73, 15, 14, 93, 4, 0, 111, -5, -12, + -19, 68, 86, 0, 57, 72, 19, 46, 59, 38, 36, 45, + 57, 25, 31, 76, 14, 18, 95, 3, 4, 114, -6, -8, + -17, 66, 90, 3, 55, 76, 21, 45, 63, 40, 34, 50, + 60, 23, 36, 78, 13, 22, 98, 2, 9, 117, -8, -4, + -14, 65, 94, 5, 54, 80, 24, 43, 67, 43, 33, 54, + 62, 22, 40, 81, 11, 26, 100, 0, 13, 119, -9, 0, + -12, 64, 98, 7, 53, 84, 26, 42, 71, 45, 31, 58, + 64, 20, 44, 83, 10, 30, 103, 0, 17, 121, -11, 3, + -87, 111, -29, -68, 100, -43, -49, 90, -56, -30, 79, -70, + -11, 68, -83, 8, 57, -97, 27, 46, -111, 46, 36, -124, + -85, 110, -25, -65, 99, -39, -47, 88, -52, -28, 78, -66, + -8, 67, -79, 10, 56, -93, 30, 45, -107, 48, 35, -120, + -82, 108, -21, -63, 97, -35, -44, 87, -48, -25, 76, -62, + -6, 65, -75, 13, 55, -89, 32, 44, -103, 51, 33, -116, + -80, 107, -16, -60, 96, -30, -42, 85, -44, -23, 75, -57, + -3, 64, -71, 15, 53, -84, 35, 42, -98, 54, 32, -112, + -77, 105, -12, -58, 95, -26, -39, 84, -40, -20, 73, -53, + -1, 62, -67, 18, 52, -80, 37, 41, -94, 56, 30, -108, + -75, 104, -8, -56, 93, -22, -37, 83, -36, -18, 72, -49, + 1, 61, -63, 20, 50, -76, 40, 40, -90, 58, 29, -104, + -73, 103, -4, -53, 92, -18, -34, 81, -32, -16, 71, -45, + 4, 60, -59, 23, 49, -72, 42, 38, -86, 61, 28, -100, + -70, 101, 0, -50, 90, -14, -32, 80, -27, -13, 69, -41, + 6, 58, -54, 25, 48, -68, 45, 37, -82, 63, 26, -95, + -67, 100, 3, -48, 89, -10, -29, 78, -23, -10, 68, -37, + 9, 57, -50, 28, 46, -64, 47, 35, -78, 66, 25, -91, + -65, 99, 7, -46, 88, -6, -27, 77, -19, -8, 66, -33, + 11, 55, -46, 30, 45, -60, 49, 34, -74, 68, 23, -87, + -63, 97, 11, -43, 86, -2, -24, 76, -15, -6, 65, -29, + 14, 54, -42, 32, 44, -56, 52, 33, -70, 71, 22, -83, + -60, 96, 15, -41, 85, 1, -22, 74, -11, -3, 64, -25, + 16, 53, -38, 35, 42, -52, 54, 31, -66, 73, 21, -79, + -58, 94, 20, -38, 83, 6, -19, 73, -7, -1, 62, -20, + 19, 51, -34, 38, 41, -47, 57, 30, -61, 76, 19, -75, + -55, 93, 24, -36, 82, 10, -17, 71, -3, 2, 61, -16, + 21, 50, -30, 40, 39, -43, 59, 28, -57, 78, 18, -71, + -53, 92, 28, -33, 81, 14, -15, 70, 0, 4, 60, -12, + 24, 49, -26, 42, 38, -39, 62, 27, -53, 80, 16, -67, + -50, 90, 32, -31, 79, 18, -12, 69, 4, 7, 58, -8, + 26, 47, -22, 45, 37, -35, 64, 26, -49, 83, 15, -63, + -48, 89, 36, -28, 78, 22, -10, 67, 9, 9, 57, -4, + 29, 46, -17, 47, 35, -31, 67, 24, -45, 86, 14, -58, + -45, 87, 40, -26, 76, 26, -7, 66, 13, 12, 55, 0, + 31, 44, -13, 50, 34, -27, 69, 23, -41, 88, 12, -54, + -43, 86, 44, -24, 75, 30, -5, 65, 17, 14, 54, 3, + 33, 43, -9, 52, 32, -23, 72, 21, -37, 90, 11, -50, + -41, 85, 48, -21, 74, 34, -2, 63, 21, 16, 53, 7, + 36, 42, -5, 55, 31, -19, 74, 20, -33, 93, 10, -46, + -38, 83, 53, -18, 72, 39, 0, 62, 25, 19, 51, 12, + 38, 40, -1, 57, 30, -14, 77, 19, -28, 95, 8, -42, + -35, 82, 57, -16, 71, 43, 3, 60, 29, 22, 50, 16, + 41, 39, 2, 60, 28, -10, 79, 17, -24, 98, 7, -38, + -33, 81, 61, -14, 70, 47, 5, 59, 33, 24, 48, 20, + 43, 37, 6, 62, 27, -6, 81, 16, -20, 100, 5, -34, + -31, 79, 65, -11, 68, 51, 8, 58, 37, 26, 47, 24, + 46, 36, 10, 64, 25, -2, 84, 15, -16, 103, 4, -30, + -28, 78, 69, -9, 67, 55, 10, 56, 41, 29, 46, 28, + 48, 35, 14, 67, 24, 1, 86, 13, -12, 105, 3, -26, + -26, 76, 73, -6, 65, 59, 13, 55, 46, 31, 44, 32, + 51, 33, 19, 70, 23, 5, 89, 12, -8, 108, 1, -21, + -23, 75, 77, -4, 64, 63, 15, 53, 50, 34, 43, 36, + 53, 32, 23, 72, 21, 9, 91, 10, -4, 110, 0, -17, + -21, 74, 81, -1, 63, 67, 17, 52, 54, 36, 41, 40, + 56, 31, 27, 74, 20, 13, 94, 9, 0, 112, -1, -13, + -18, 72, 85, 1, 61, 71, 20, 51, 58, 39, 40, 44, + 58, 29, 31, 77, 19, 17, 96, 8, 3, 115, -2, -9, + -16, 71, 90, 4, 60, 76, 22, 49, 62, 41, 39, 49, + 61, 28, 35, 79, 17, 22, 99, 6, 8, 118, -3, -5, + -13, 69, 94, 6, 58, 80, 25, 48, 66, 44, 37, 53, + 63, 26, 39, 82, 16, 26, 101, 5, 12, 120, -5, -1, + -11, 68, 98, 8, 57, 84, 27, 46, 70, 46, 36, 57, + 65, 25, 43, 84, 14, 30, 104, 3, 16, 122, -6, 2, + -86, 115, -30, -67, 104, -43, -48, 94, -57, -29, 83, -70, + -10, 72, -84, 9, 61, -97, 28, 50, -111, 47, 40, -125, + -84, 114, -26, -64, 103, -39, -46, 92, -53, -27, 82, -66, + -8, 71, -80, 11, 60, -93, 31, 49, -107, 49, 39, -121, + -81, 112, -22, -62, 101, -35, -43, 91, -49, -25, 80, -62, + -5, 69, -76, 14, 59, -89, 33, 48, -103, 52, 37, -117, + -79, 111, -17, -59, 100, -31, -41, 89, -44, -22, 79, -58, + -2, 68, -72, 16, 57, -85, 36, 46, -99, 54, 36, -112, + -76, 109, -13, -57, 99, -27, -38, 88, -40, -19, 77, -54, + 0, 66, -68, 19, 56, -81, 38, 45, -95, 57, 34, -108, + -74, 108, -9, -55, 97, -23, -36, 87, -36, -17, 76, -50, + 2, 65, -64, 21, 54, -77, 40, 44, -91, 59, 33, -104, + -72, 107, -5, -52, 96, -19, -33, 85, -32, -15, 75, -46, + 5, 64, -60, 23, 53, -73, 43, 42, -87, 62, 32, -100, + -69, 105, -1, -50, 94, -14, -31, 84, -28, -12, 73, -41, + 7, 62, -55, 26, 52, -68, 46, 41, -82, 64, 30, -96, + -67, 104, 2, -47, 93, -10, -28, 82, -24, -10, 72, -37, + 10, 61, -51, 29, 50, -64, 48, 39, -78, 67, 29, -92, + -64, 103, 6, -45, 92, -6, -26, 81, -20, -7, 70, -33, + 12, 59, -47, 31, 49, -60, 50, 38, -74, 69, 27, -88, + -62, 101, 10, -42, 90, -2, -24, 80, -16, -5, 69, -29, + 15, 58, -43, 33, 48, -56, 53, 37, -70, 72, 26, -84, + -59, 100, 14, -40, 89, 1, -21, 78, -12, -2, 68, -25, + 17, 57, -39, 36, 46, -52, 55, 35, -66, 74, 25, -80, + -57, 98, 19, -37, 87, 5, -18, 77, -7, 0, 66, -21, + 20, 55, -35, 38, 45, -48, 58, 34, -62, 77, 23, -75, + -54, 97, 23, -35, 86, 9, -16, 75, -3, 3, 65, -17, + 22, 54, -31, 41, 43, -44, 60, 32, -58, 79, 22, -71, + -52, 96, 27, -32, 85, 13, -14, 74, 0, 5, 64, -13, + 24, 53, -27, 43, 42, -40, 63, 31, -54, 81, 20, -67, + -49, 94, 31, -30, 83, 17, -11, 73, 4, 7, 62, -9, + 27, 51, -23, 46, 41, -36, 65, 30, -50, 84, 19, -63, + -47, 93, 35, -27, 82, 22, -9, 71, 8, 10, 61, -4, + 30, 50, -18, 48, 39, -31, 68, 28, -45, 86, 18, -59, + -44, 91, 39, -25, 80, 26, -6, 70, 12, 13, 59, 0, + 32, 48, -14, 51, 38, -27, 70, 27, -41, 89, 16, -55, + -42, 90, 43, -23, 79, 30, -4, 69, 16, 15, 58, 3, + 34, 47, -10, 53, 36, -23, 72, 25, -37, 91, 15, -51, + -40, 89, 47, -20, 78, 34, -1, 67, 20, 17, 57, 7, + 37, 46, -6, 55, 35, -19, 75, 24, -33, 94, 14, -47, + -37, 87, 52, -18, 76, 38, 1, 66, 25, 20, 55, 11, + 39, 44, -2, 58, 34, -15, 78, 23, -29, 96, 12, -42, + -35, 86, 56, -15, 75, 42, 4, 64, 29, 22, 54, 15, + 42, 43, 1, 61, 32, -11, 80, 21, -25, 99, 11, -38, + -32, 85, 60, -13, 74, 46, 6, 63, 33, 25, 52, 19, + 44, 41, 5, 63, 31, -7, 82, 20, -21, 101, 9, -34, + -30, 83, 64, -10, 72, 50, 8, 62, 37, 27, 51, 23, + 47, 40, 9, 65, 29, -3, 85, 19, -17, 104, 8, -30, + -27, 82, 68, -8, 71, 54, 11, 60, 41, 30, 50, 27, + 49, 39, 13, 68, 28, 0, 87, 17, -13, 106, 7, -26, + -25, 80, 72, -5, 69, 59, 13, 59, 45, 32, 48, 32, + 52, 37, 18, 70, 27, 5, 90, 16, -8, 109, 5, -22, + -22, 79, 76, -3, 68, 63, 16, 57, 49, 35, 47, 36, + 54, 36, 22, 73, 25, 9, 92, 14, -4, 111, 4, -18, + -20, 78, 80, -1, 67, 67, 18, 56, 53, 37, 45, 40, + 56, 35, 26, 75, 24, 13, 95, 13, 0, 113, 2, -14, + -17, 76, 84, 2, 65, 71, 21, 55, 57, 39, 44, 44, + 59, 33, 30, 78, 23, 17, 97, 12, 3, 116, 1, -10, + -15, 75, 89, 5, 64, 75, 23, 53, 62, 42, 43, 48, + 62, 32, 34, 80, 21, 21, 100, 10, 7, 118, 0, -5, + -12, 73, 93, 7, 62, 79, 26, 52, 66, 45, 41, 52, + 64, 30, 38, 83, 20, 25, 102, 9, 11, 121, -1, -1, + -10, 72, 97, 9, 61, 83, 28, 50, 70, 47, 40, 56, + 66, 29, 42, 85, 18, 29, 104, 7, 15, 123, -2, 2, + -85, 119, -30, -66, 108, -44, -47, 98, -57, -28, 87, -71, + -9, 76, -85, 10, 65, -98, 29, 54, -112, 48, 44, -125, + -83, 118, -26, -64, 107, -40, -45, 96, -53, -26, 86, -67, + -7, 75, -81, 12, 64, -94, 32, 53, -108, 50, 43, -121, + -81, 116, -22, -61, 105, -36, -42, 95, -49, -24, 84, -63, + -4, 73, -77, 15, 63, -90, 34, 52, -104, 53, 41, -117, + -78, 115, -18, -58, 104, -32, -40, 93, -45, -21, 83, -58, + -2, 72, -72, 17, 61, -86, 37, 50, -99, 55, 40, -113, + -75, 113, -14, -56, 103, -28, -37, 92, -41, -19, 81, -54, + 1, 70, -68, 20, 60, -82, 39, 49, -95, 58, 38, -109, + -73, 112, -10, -54, 101, -24, -35, 91, -37, -16, 80, -50, + 3, 69, -64, 22, 58, -78, 41, 48, -91, 60, 37, -105, + -71, 111, -6, -51, 100, -20, -33, 89, -33, -14, 79, -46, + 6, 68, -60, 24, 57, -74, 44, 46, -87, 63, 36, -101, + -68, 109, -1, -49, 98, -15, -30, 88, -28, -11, 77, -42, + 8, 66, -56, 27, 56, -69, 46, 45, -83, 65, 34, -96, + -66, 108, 2, -46, 97, -11, -27, 86, -24, -9, 76, -38, + 11, 65, -52, 29, 54, -65, 49, 43, -79, 68, 33, -92, + -63, 107, 6, -44, 96, -7, -25, 85, -20, -6, 74, -34, + 13, 63, -48, 32, 53, -61, 51, 42, -75, 70, 31, -88, + -61, 105, 10, -41, 94, -3, -23, 84, -16, -4, 73, -30, + 15, 62, -44, 34, 52, -57, 54, 41, -71, 72, 30, -84, + -58, 104, 14, -39, 93, 0, -20, 82, -12, -1, 72, -26, + 18, 61, -40, 37, 50, -53, 56, 39, -67, 75, 29, -80, + -56, 102, 18, -36, 91, 4, -18, 81, -8, 1, 70, -21, + 21, 59, -35, 39, 49, -49, 59, 38, -62, 78, 27, -76, + -53, 101, 22, -34, 90, 8, -15, 79, -4, 4, 69, -17, + 23, 58, -31, 42, 47, -45, 61, 36, -58, 80, 26, -72, + -51, 100, 26, -32, 89, 12, -13, 78, 0, 6, 68, -13, + 25, 57, -27, 44, 46, -41, 64, 35, -54, 82, 24, -68, + -49, 98, 30, -29, 87, 16, -10, 77, 3, 8, 66, -9, + 28, 55, -23, 47, 45, -37, 66, 34, -50, 85, 23, -64, + -46, 97, 35, -27, 86, 21, -8, 75, 8, 11, 65, -5, + 30, 54, -19, 49, 43, -32, 69, 32, -46, 87, 22, -59, + -43, 95, 39, -24, 84, 25, -5, 74, 12, 13, 63, -1, + 33, 52, -15, 52, 42, -28, 71, 31, -42, 90, 20, -55, + -41, 94, 43, -22, 83, 29, -3, 73, 16, 16, 62, 2, + 35, 51, -11, 54, 40, -24, 73, 29, -38, 92, 19, -51, + -39, 93, 47, -19, 82, 33, -1, 71, 20, 18, 61, 6, + 38, 50, -7, 56, 39, -20, 76, 28, -34, 95, 18, -47, + -36, 91, 51, -17, 80, 37, 2, 70, 24, 21, 59, 11, + 40, 48, -2, 59, 38, -16, 78, 27, -29, 97, 16, -43, + -34, 90, 55, -14, 79, 41, 5, 68, 28, 23, 58, 15, + 43, 47, 1, 61, 36, -12, 81, 25, -25, 100, 15, -39, + -31, 89, 59, -12, 78, 45, 7, 67, 32, 26, 56, 19, + 45, 45, 5, 64, 35, -8, 83, 24, -21, 102, 13, -35, + -29, 87, 63, -9, 76, 49, 9, 66, 36, 28, 55, 23, + 47, 44, 9, 66, 33, -4, 86, 23, -17, 104, 12, -31, + -26, 86, 67, -7, 75, 53, 12, 64, 40, 31, 54, 27, + 50, 43, 13, 69, 32, 0, 88, 21, -13, 107, 11, -27, + -24, 84, 72, -4, 73, 58, 14, 63, 45, 33, 52, 31, + 53, 41, 17, 71, 31, 4, 91, 20, -9, 110, 9, -22, + -21, 83, 76, -2, 72, 62, 17, 61, 49, 36, 51, 35, + 55, 40, 21, 74, 29, 8, 93, 18, -5, 112, 8, -18, + -19, 82, 80, 0, 71, 66, 19, 60, 53, 38, 49, 39, + 57, 39, 25, 76, 28, 12, 96, 17, -1, 114, 6, -14, + -17, 80, 84, 3, 69, 70, 22, 59, 57, 40, 48, 43, + 60, 37, 29, 79, 27, 16, 98, 16, 2, 117, 5, -10, + -14, 79, 88, 5, 68, 74, 24, 57, 61, 43, 47, 48, + 62, 36, 34, 81, 25, 20, 101, 14, 7, 119, 4, -6, + -11, 77, 92, 8, 66, 78, 27, 56, 65, 45, 45, 52, + 65, 34, 38, 84, 24, 24, 103, 13, 11, 122, 2, -2, + -9, 76, 96, 10, 65, 82, 29, 54, 69, 48, 44, 56, + 67, 33, 42, 86, 22, 28, 105, 11, 15, 124, 1, 1, + -112, -9, -11, -93, -20, -25, -74, -30, -38, -55, -41, -52, + -36, -52, -66, -17, -62, -79, 2, -73, -93, 21, -84, -106, + -110, -10, -7, -90, -21, -21, -72, -32, -34, -53, -42, -48, + -33, -53, -62, -15, -64, -75, 5, -75, -89, 24, -85, -102, + -107, -11, -3, -88, -22, -17, -69, -33, -30, -50, -44, -44, + -31, -55, -58, -12, -65, -71, 7, -76, -85, 26, -87, -98, + -105, -13, 0, -85, -24, -13, -66, -35, -26, -48, -45, -39, + -28, -56, -53, -9, -67, -67, 10, -78, -80, 29, -88, -94, + -102, -14, 4, -83, -25, -9, -64, -36, -22, -45, -46, -35, + -26, -57, -49, -7, -68, -63, 12, -79, -76, 31, -90, -90, + -100, -16, 8, -80, -27, -5, -62, -37, -18, -43, -48, -31, + -23, -59, -45, -5, -69, -59, 15, -80, -72, 33, -91, -86, + -97, -17, 12, -78, -28, -1, -59, -39, -14, -40, -49, -27, + -21, -60, -41, -2, -71, -55, 17, -82, -68, 36, -92, -82, + -95, -19, 17, -75, -29, 3, -57, -40, -9, -38, -51, -23, + -18, -62, -37, 0, -72, -50, 20, -83, -64, 39, -94, -77, + -92, -20, 21, -73, -31, 7, -54, -41, -5, -35, -52, -19, + -16, -63, -33, 3, -74, -46, 22, -85, -60, 41, -95, -73, + -90, -21, 25, -71, -32, 11, -52, -43, -1, -33, -53, -15, + -14, -64, -29, 5, -75, -42, 25, -86, -56, 43, -96, -69, + -88, -23, 29, -68, -34, 15, -49, -44, 2, -31, -55, -11, + -11, -66, -25, 8, -76, -38, 27, -87, -52, 46, -98, -65, + -85, -24, 33, -66, -35, 19, -47, -45, 6, -28, -56, -7, + -9, -67, -21, 10, -78, -34, 29, -89, -48, 48, -99, -61, + -82, -25, 37, -63, -36, 23, -44, -47, 10, -26, -58, -2, + -6, -69, -16, 13, -79, -30, 32, -90, -43, 51, -101, -57, + -80, -27, 41, -61, -38, 27, -42, -48, 14, -23, -59, 1, + -4, -70, -12, 15, -80, -26, 34, -91, -39, 53, -102, -53, + -78, -28, 45, -58, -39, 31, -40, -50, 18, -21, -60, 5, + -1, -71, -8, 17, -82, -22, 37, -93, -35, 56, -103, -49, + -75, -30, 49, -56, -40, 35, -37, -51, 22, -18, -62, 9, + 1, -73, -4, 20, -83, -18, 39, -94, -31, 58, -105, -45, + -73, -31, 54, -53, -42, 40, -34, -53, 27, -16, -63, 13, + 4, -74, 0, 22, -85, -13, 42, -96, -27, 61, -106, -40, + -70, -32, 58, -51, -43, 44, -32, -54, 31, -13, -65, 17, + 6, -75, 3, 25, -86, -9, 44, -97, -23, 63, -108, -36, + -68, -34, 62, -48, -45, 48, -30, -55, 35, -11, -66, 21, + 8, -77, 7, 27, -87, -5, 47, -98, -19, 65, -109, -32, + -65, -35, 66, -46, -46, 52, -27, -57, 39, -8, -67, 25, + 11, -78, 11, 30, -89, -1, 49, -100, -15, 68, -110, -28, + -63, -37, 70, -43, -48, 56, -25, -58, 43, -6, -69, 30, + 14, -80, 16, 32, -90, 2, 52, -101, -10, 71, -112, -24, + -60, -38, 74, -41, -49, 60, -22, -59, 47, -3, -70, 34, + 16, -81, 20, 35, -92, 6, 54, -103, -6, 73, -113, -20, + -58, -39, 78, -39, -50, 64, -20, -61, 51, -1, -71, 38, + 18, -82, 24, 37, -93, 10, 57, -104, -2, 75, -115, -16, + -56, -41, 82, -36, -52, 68, -17, -62, 55, 1, -73, 42, + 21, -84, 28, 40, -94, 14, 59, -105, 1, 78, -116, -12, + -53, -42, 86, -34, -53, 72, -15, -64, 59, 4, -74, 46, + 23, -85, 32, 42, -96, 18, 61, -107, 5, 80, -117, -8, + -50, -44, 91, -31, -54, 77, -12, -65, 64, 6, -76, 50, + 26, -87, 36, 45, -97, 23, 64, -108, 9, 83, -119, -3, + -48, -45, 95, -29, -56, 81, -10, -66, 68, 9, -77, 54, + 28, -88, 40, 47, -99, 27, 66, -109, 13, 85, -120, 0, + -46, -46, 99, -26, -57, 85, -8, -68, 72, 11, -78, 58, + 31, -89, 44, 49, -100, 31, 69, -111, 17, 88, -121, 4, + -43, -48, 103, -24, -59, 89, -5, -69, 76, 14, -80, 62, + 33, -91, 48, 52, -101, 35, 71, -112, 21, 90, -123, 8, + -41, -49, 107, -21, -60, 93, -2, -71, 80, 16, -81, 67, + 36, -92, 53, 54, -103, 39, 74, -114, 26, 93, -124, 12, + -38, -50, 111, -19, -61, 97, 0, -72, 84, 19, -83, 71, + 38, -94, 57, 57, -104, 43, 76, -115, 30, 95, -126, 16, + -36, -52, 115, -16, -63, 101, 2, -73, 88, 21, -84, 75, + 40, -95, 61, 59, -105, 47, 79, -116, 34, 97, -127, 20, + -111, -5, -12, -92, -16, -26, -73, -26, -39, -54, -37, -52, + -35, -48, -66, -16, -58, -80, 3, -69, -94, 22, -80, -107, + -109, -6, -8, -89, -17, -22, -71, -28, -35, -52, -38, -48, + -32, -49, -62, -14, -60, -76, 6, -71, -90, 24, -81, -103, + -106, -7, -4, -87, -18, -18, -68, -29, -31, -49, -40, -44, + -30, -51, -58, -11, -61, -72, 8, -72, -86, 27, -83, -99, + -104, -9, 0, -84, -20, -13, -66, -31, -27, -47, -41, -40, + -27, -52, -54, -9, -63, -67, 11, -74, -81, 30, -84, -94, + -101, -10, 4, -82, -21, -9, -63, -32, -23, -44, -42, -36, + -25, -53, -50, -6, -64, -63, 13, -75, -77, 32, -86, -90, + -99, -12, 8, -80, -23, -5, -61, -33, -19, -42, -44, -32, + -23, -55, -46, -4, -65, -59, 16, -76, -73, 34, -87, -86, + -97, -13, 12, -77, -24, -1, -58, -35, -15, -40, -45, -28, + -20, -56, -42, -1, -67, -55, 18, -78, -69, 37, -88, -82, + -94, -15, 16, -74, -25, 2, -56, -36, -10, -37, -47, -23, + -17, -58, -37, 1, -68, -51, 21, -79, -65, 39, -90, -78, + -91, -16, 20, -72, -27, 6, -53, -37, -6, -34, -48, -19, + -15, -59, -33, 4, -70, -47, 23, -81, -61, 42, -91, -74, + -89, -17, 24, -70, -28, 10, -51, -39, -2, -32, -49, -15, + -13, -60, -29, 6, -71, -43, 25, -82, -57, 44, -92, -70, + -87, -19, 28, -67, -30, 14, -48, -40, 1, -30, -51, -11, + -10, -62, -25, 8, -72, -39, 28, -83, -53, 47, -94, -66, + -84, -20, 32, -65, -31, 18, -46, -41, 5, -27, -52, -7, + -8, -63, -21, 11, -74, -35, 30, -85, -49, 49, -95, -62, + -82, -21, 37, -62, -32, 23, -43, -43, 9, -25, -54, -3, + -5, -65, -17, 14, -75, -30, 33, -86, -44, 52, -97, -57, + -79, -23, 41, -60, -34, 27, -41, -44, 13, -22, -55, 0, + -3, -66, -13, 16, -76, -26, 35, -87, -40, 54, -98, -53, + -77, -24, 45, -57, -35, 31, -39, -46, 17, -20, -56, 4, + 0, -67, -9, 18, -78, -22, 38, -89, -36, 56, -99, -49, + -74, -26, 49, -55, -36, 35, -36, -47, 21, -17, -58, 8, + 2, -69, -5, 21, -79, -18, 40, -90, -32, 59, -101, -45, + -72, -27, 53, -52, -38, 39, -34, -49, 26, -15, -59, 13, + 5, -70, 0, 23, -81, -14, 43, -92, -28, 62, -102, -41, + -69, -28, 57, -50, -39, 43, -31, -50, 30, -12, -61, 17, + 7, -71, 3, 26, -82, -10, 45, -93, -24, 64, -104, -37, + -67, -30, 61, -48, -41, 47, -29, -51, 34, -10, -62, 21, + 9, -73, 7, 28, -83, -6, 48, -94, -20, 66, -105, -33, + -65, -31, 65, -45, -42, 51, -26, -53, 38, -8, -63, 25, + 12, -74, 11, 31, -85, -2, 50, -96, -16, 69, -106, -29, + -62, -33, 70, -42, -44, 56, -24, -54, 42, -5, -65, 29, + 14, -76, 15, 33, -86, 2, 53, -97, -11, 71, -108, -24, + -59, -34, 74, -40, -45, 60, -21, -55, 46, -2, -66, 33, + 17, -77, 19, 36, -88, 6, 55, -99, -7, 74, -109, -20, + -57, -35, 78, -38, -46, 64, -19, -57, 50, 0, -67, 37, + 19, -78, 23, 38, -89, 10, 57, -100, -3, 76, -111, -16, + -55, -37, 82, -35, -48, 68, -16, -58, 54, 2, -69, 41, + 22, -80, 27, 40, -90, 14, 60, -101, 0, 79, -112, -12, + -52, -38, 86, -33, -49, 72, -14, -60, 58, 5, -70, 45, + 24, -81, 31, 43, -92, 18, 62, -103, 4, 81, -113, -8, + -50, -40, 90, -30, -50, 76, -11, -61, 63, 7, -72, 50, + 27, -83, 36, 46, -93, 22, 65, -104, 8, 84, -115, -4, + -47, -41, 94, -28, -52, 80, -9, -62, 67, 10, -73, 54, + 29, -84, 40, 48, -95, 26, 67, -105, 12, 86, -116, 0, + -45, -42, 98, -25, -53, 84, -7, -64, 71, 12, -74, 58, + 32, -85, 44, 50, -96, 30, 70, -107, 16, 88, -117, 3, + -42, -44, 102, -23, -55, 88, -4, -65, 75, 15, -76, 62, + 34, -87, 48, 53, -97, 34, 72, -108, 20, 91, -119, 7, + -40, -45, 107, -20, -56, 93, -2, -67, 79, 17, -77, 66, + 37, -88, 52, 55, -99, 39, 75, -110, 25, 94, -120, 12, + -37, -46, 111, -18, -57, 97, 1, -68, 83, 20, -79, 70, + 39, -90, 56, 58, -100, 43, 77, -111, 29, 96, -122, 16, + -35, -48, 115, -16, -59, 101, 3, -69, 87, 22, -80, 74, + 41, -91, 60, 60, -101, 47, 80, -112, 33, 98, -123, 20, + -110, -1, -13, -91, -12, -26, -72, -22, -40, -53, -33, -53, + -34, -44, -67, -15, -54, -80, 4, -65, -94, 23, -76, -108, + -108, -2, -9, -88, -13, -22, -70, -24, -36, -51, -34, -49, + -32, -45, -63, -13, -56, -76, 7, -67, -90, 25, -77, -104, + -105, -3, -5, -86, -14, -18, -67, -25, -32, -49, -36, -45, + -29, -47, -59, -10, -57, -72, 9, -68, -86, 28, -79, -100, + -103, -5, 0, -83, -16, -14, -65, -27, -27, -46, -37, -41, + -26, -48, -54, -8, -59, -68, 12, -70, -82, 30, -80, -95, + -100, -6, 3, -81, -17, -10, -62, -28, -23, -43, -38, -37, + -24, -49, -50, -5, -60, -64, 14, -71, -78, 33, -82, -91, + -98, -8, 7, -79, -19, -6, -60, -29, -19, -41, -40, -33, + -22, -51, -46, -3, -61, -60, 16, -72, -74, 35, -83, -87, + -96, -9, 11, -76, -20, -2, -57, -31, -15, -39, -41, -29, + -19, -52, -42, 0, -63, -56, 19, -74, -70, 38, -84, -83, + -93, -11, 15, -74, -21, 2, -55, -32, -11, -36, -43, -24, + -17, -54, -38, 2, -64, -51, 22, -75, -65, 40, -86, -79, + -91, -12, 19, -71, -23, 6, -52, -33, -7, -34, -44, -20, + -14, -55, -34, 5, -66, -47, 24, -77, -61, 43, -87, -75, + -88, -13, 23, -69, -24, 10, -50, -35, -3, -31, -45, -16, + -12, -56, -30, 7, -67, -43, 26, -78, -57, 45, -88, -71, + -86, -15, 27, -66, -26, 14, -48, -36, 0, -29, -47, -12, + -9, -58, -26, 9, -68, -39, 29, -79, -53, 48, -90, -67, + -83, -16, 31, -64, -27, 18, -45, -37, 4, -26, -48, -8, + -7, -59, -22, 12, -70, -35, 31, -81, -49, 50, -91, -63, + -81, -17, 36, -61, -28, 22, -42, -39, 9, -24, -50, -4, + -4, -61, -17, 14, -71, -31, 34, -82, -45, 53, -93, -58, + -78, -19, 40, -59, -30, 26, -40, -40, 13, -21, -51, 0, + -2, -62, -13, 17, -72, -27, 36, -83, -41, 55, -94, -54, + -76, -20, 44, -56, -31, 30, -38, -42, 17, -19, -52, 3, + 0, -63, -9, 19, -74, -23, 39, -85, -37, 57, -95, -50, + -73, -22, 48, -54, -32, 34, -35, -43, 21, -17, -54, 7, + 3, -65, -5, 22, -75, -19, 41, -86, -33, 60, -97, -46, + -71, -23, 52, -51, -34, 39, -33, -45, 25, -14, -55, 12, + 6, -66, -1, 24, -77, -14, 44, -88, -28, 62, -98, -42, + -68, -24, 56, -49, -35, 43, -30, -46, 29, -11, -57, 16, + 8, -67, 2, 27, -78, -10, 46, -89, -24, 65, -100, -38, + -66, -26, 60, -47, -37, 47, -28, -47, 33, -9, -58, 20, + 10, -69, 6, 29, -79, -6, 48, -90, -20, 67, -101, -34, + -64, -27, 64, -44, -38, 51, -25, -49, 37, -7, -59, 24, + 13, -70, 10, 31, -81, -2, 51, -92, -16, 70, -102, -30, + -61, -29, 69, -42, -40, 55, -23, -50, 42, -4, -61, 28, + 15, -72, 15, 34, -82, 1, 54, -93, -12, 72, -104, -25, + -59, -30, 73, -39, -41, 59, -20, -51, 46, -2, -62, 32, + 18, -73, 19, 37, -84, 5, 56, -95, -8, 75, -105, -21, + -56, -31, 77, -37, -42, 63, -18, -53, 50, 1, -63, 36, + 20, -74, 23, 39, -85, 9, 58, -96, -4, 77, -107, -17, + -54, -33, 81, -34, -44, 67, -16, -54, 54, 3, -65, 40, + 23, -76, 27, 41, -86, 13, 61, -97, 0, 80, -108, -13, + -51, -34, 85, -32, -45, 71, -13, -56, 58, 6, -66, 44, + 25, -77, 31, 44, -88, 17, 63, -99, 3, 82, -109, -9, + -49, -36, 89, -29, -46, 76, -10, -57, 62, 8, -68, 49, + 28, -79, 35, 46, -89, 22, 66, -100, 8, 85, -111, -5, + -46, -37, 93, -27, -48, 80, -8, -58, 66, 11, -69, 53, + 30, -80, 39, 49, -91, 26, 68, -101, 12, 87, -112, -1, + -44, -38, 97, -24, -49, 84, -6, -60, 70, 13, -70, 57, + 32, -81, 43, 51, -92, 30, 71, -103, 16, 89, -113, 2, + -41, -40, 101, -22, -51, 88, -3, -61, 74, 15, -72, 61, + 35, -83, 47, 54, -93, 34, 73, -104, 20, 92, -115, 6, + -39, -41, 106, -19, -52, 92, -1, -63, 79, 18, -73, 65, + 38, -84, 52, 56, -95, 38, 76, -106, 24, 94, -116, 11, + -36, -42, 110, -17, -53, 96, 2, -64, 83, 21, -75, 69, + 40, -86, 56, 59, -96, 42, 78, -107, 28, 97, -118, 15, + -34, -44, 114, -15, -55, 100, 4, -65, 87, 23, -76, 73, + 42, -87, 60, 61, -97, 46, 80, -108, 32, 99, -119, 19, + -109, 3, -13, -90, -7, -27, -71, -18, -40, -52, -28, -54, + -33, -39, -68, -14, -50, -81, 5, -61, -95, 24, -71, -108, + -107, 1, -9, -87, -9, -23, -69, -19, -36, -50, -30, -50, + -31, -41, -64, -12, -51, -77, 8, -62, -91, 26, -73, -104, + -104, 0, -5, -85, -10, -19, -66, -21, -32, -47, -31, -46, + -28, -42, -60, -9, -53, -73, 10, -64, -87, 29, -74, -100, + -102, 0, -1, -82, -11, -15, -64, -22, -28, -45, -33, -41, + -25, -44, -55, -7, -54, -69, 13, -65, -82, 32, -76, -96, + -99, -2, 2, -80, -13, -11, -61, -23, -24, -42, -34, -37, + -23, -45, -51, -4, -56, -65, 15, -66, -78, 34, -77, -92, + -97, -3, 6, -78, -14, -7, -59, -25, -20, -40, -35, -33, + -21, -46, -47, -2, -57, -61, 18, -68, -74, 36, -78, -88, + -95, -5, 10, -75, -15, -3, -56, -26, -16, -38, -37, -29, + -18, -48, -43, 1, -58, -57, 20, -69, -70, 39, -80, -84, + -92, -6, 15, -73, -17, 1, -54, -28, -11, -35, -38, -25, + -16, -49, -39, 3, -60, -52, 23, -71, -66, 41, -81, -79, + -89, -7, 19, -70, -18, 5, -51, -29, -7, -33, -40, -21, + -13, -50, -35, 6, -61, -48, 25, -72, -62, 44, -83, -75, + -87, -9, 23, -68, -20, 9, -49, -30, -3, -30, -41, -17, + -11, -52, -31, 8, -62, -44, 27, -73, -58, 46, -84, -71, + -85, -10, 27, -65, -21, 13, -47, -32, 0, -28, -42, -13, + -8, -53, -27, 10, -64, -40, 30, -75, -54, 49, -85, -67, + -82, -11, 31, -63, -22, 17, -44, -33, 4, -25, -44, -9, + -6, -55, -23, 13, -65, -36, 32, -76, -50, 51, -87, -63, + -80, -13, 35, -60, -24, 21, -41, -35, 8, -23, -45, -4, + -3, -56, -18, 15, -67, -32, 35, -78, -45, 54, -88, -59, + -77, -14, 39, -58, -25, 25, -39, -36, 12, -20, -46, 0, + -1, -57, -14, 18, -68, -28, 37, -79, -41, 56, -90, -55, + -75, -16, 43, -55, -27, 29, -37, -37, 16, -18, -48, 3, + 1, -59, -10, 20, -69, -24, 40, -80, -37, 58, -91, -51, + -72, -17, 47, -53, -28, 33, -34, -39, 20, -15, -49, 7, + 4, -60, -6, 23, -71, -20, 42, -82, -33, 61, -92, -47, + -70, -19, 52, -50, -29, 38, -32, -40, 25, -13, -51, 11, + 7, -62, -2, 25, -72, -15, 45, -83, -29, 64, -94, -42, + -67, -20, 56, -48, -31, 42, -29, -41, 29, -10, -52, 15, + 9, -63, 1, 28, -74, -11, 47, -84, -25, 66, -95, -38, + -65, -21, 60, -46, -32, 46, -27, -43, 33, -8, -53, 19, + 11, -64, 5, 30, -75, -7, 50, -86, -21, 68, -96, -34, + -63, -23, 64, -43, -34, 50, -24, -44, 37, -6, -55, 23, + 14, -66, 9, 33, -76, -3, 52, -87, -17, 71, -98, -30, + -60, -24, 68, -41, -35, 54, -22, -46, 41, -3, -56, 28, + 16, -67, 14, 35, -78, 0, 55, -89, -12, 73, -99, -26, + -57, -25, 72, -38, -36, 58, -19, -47, 45, -1, -58, 32, + 19, -69, 18, 38, -79, 4, 57, -90, -8, 76, -101, -22, + -55, -27, 76, -36, -38, 62, -17, -48, 49, 2, -59, 36, + 21, -70, 22, 40, -80, 8, 59, -91, -4, 78, -102, -18, + -53, -28, 80, -33, -39, 66, -15, -50, 53, 4, -60, 40, + 24, -71, 26, 42, -82, 12, 62, -93, 0, 81, -103, -14, + -50, -30, 84, -31, -40, 70, -12, -51, 57, 7, -62, 44, + 26, -73, 30, 45, -83, 16, 64, -94, 3, 83, -105, -10, + -48, -31, 89, -28, -42, 75, -9, -53, 62, 9, -63, 48, + 29, -74, 34, 47, -85, 21, 67, -96, 7, 86, -106, -5, + -45, -32, 93, -26, -43, 79, -7, -54, 66, 12, -65, 52, + 31, -75, 38, 50, -86, 25, 69, -97, 11, 88, -108, -1, + -43, -34, 97, -23, -45, 83, -5, -55, 70, 14, -66, 56, + 33, -77, 42, 52, -87, 29, 72, -98, 15, 90, -109, 2, + -40, -35, 101, -21, -46, 87, -2, -57, 74, 16, -67, 60, + 36, -78, 46, 55, -89, 33, 74, -100, 19, 93, -110, 6, + -38, -37, 105, -18, -48, 91, 0, -58, 78, 19, -69, 65, + 39, -80, 51, 57, -90, 37, 77, -101, 24, 95, -112, 10, + -35, -38, 109, -16, -49, 95, 3, -59, 82, 22, -70, 69, + 41, -81, 55, 60, -92, 41, 79, -103, 28, 98, -113, 14, + -33, -39, 113, -14, -50, 99, 5, -61, 86, 24, -71, 73, + 43, -82, 59, 62, -93, 45, 81, -104, 32, 100, -115, 18, + -108, 7, -14, -89, -3, -28, -70, -14, -41, -51, -24, -55, + -32, -35, -68, -13, -46, -82, 6, -57, -96, 25, -67, -109, + -106, 5, -10, -87, -5, -24, -68, -15, -37, -49, -26, -51, + -30, -37, -64, -11, -47, -78, 9, -58, -92, 27, -69, -105, + -104, 4, -6, -84, -6, -20, -65, -17, -33, -47, -27, -47, + -27, -38, -60, -8, -49, -74, 11, -60, -88, 30, -70, -101, + -101, 3, -1, -81, -7, -15, -63, -18, -29, -44, -29, -42, + -25, -40, -56, -6, -50, -69, 14, -61, -83, 32, -72, -96, + -98, 1, 2, -79, -9, -11, -60, -19, -25, -41, -30, -38, + -22, -41, -52, -3, -52, -65, 16, -62, -79, 35, -73, -92, + -96, 0, 6, -77, -10, -7, -58, -21, -21, -39, -31, -34, + -20, -42, -48, -1, -53, -61, 18, -64, -75, 37, -74, -88, + -94, -1, 10, -74, -11, -3, -55, -22, -17, -37, -33, -30, + -17, -44, -44, 1, -54, -57, 21, -65, -71, 40, -76, -84, + -91, -2, 14, -72, -13, 0, -53, -24, -12, -34, -34, -26, + -15, -45, -39, 4, -56, -53, 24, -67, -67, 42, -77, -80, + -89, -3, 18, -69, -14, 4, -50, -25, -8, -32, -36, -22, + -12, -46, -35, 7, -57, -49, 26, -68, -63, 45, -79, -76, + -86, -5, 22, -67, -16, 8, -48, -26, -4, -29, -37, -18, + -10, -48, -31, 9, -58, -45, 28, -69, -59, 47, -80, -72, + -84, -6, 26, -64, -17, 12, -46, -28, 0, -27, -38, -14, + -7, -49, -27, 11, -60, -41, 31, -71, -55, 49, -81, -68, + -81, -7, 30, -62, -18, 16, -43, -29, 3, -24, -40, -10, + -5, -51, -23, 14, -61, -37, 33, -72, -51, 52, -83, -64, + -79, -9, 35, -59, -20, 21, -41, -31, 7, -22, -41, -5, + -2, -52, -19, 16, -63, -32, 36, -74, -46, 55, -84, -59, + -76, -10, 39, -57, -21, 25, -38, -32, 11, -19, -42, -1, + 0, -53, -15, 19, -64, -28, 38, -75, -42, 57, -86, -55, + -74, -12, 43, -55, -23, 29, -36, -33, 15, -17, -44, 2, + 2, -55, -11, 21, -65, -24, 41, -76, -38, 59, -87, -51, + -72, -13, 47, -52, -24, 33, -33, -35, 19, -15, -45, 6, + 5, -56, -7, 24, -67, -20, 43, -78, -34, 62, -88, -47, + -69, -15, 51, -49, -25, 37, -31, -36, 24, -12, -47, 10, + 7, -58, -2, 26, -68, -16, 46, -79, -30, 64, -90, -43, + -66, -16, 55, -47, -27, 41, -28, -37, 28, -10, -48, 14, + 10, -59, 1, 29, -70, -12, 48, -80, -26, 67, -91, -39, + -64, -17, 59, -45, -28, 45, -26, -39, 32, -7, -49, 18, + 12, -60, 5, 31, -71, -8, 50, -82, -22, 69, -92, -35, + -62, -19, 63, -42, -30, 49, -24, -40, 36, -5, -51, 22, + 15, -62, 9, 33, -72, -4, 53, -83, -18, 72, -94, -31, + -59, -20, 68, -40, -31, 54, -21, -42, 40, -2, -52, 27, + 17, -63, 13, 36, -74, 0, 55, -85, -13, 74, -95, -26, + -57, -21, 72, -37, -32, 58, -18, -43, 44, 0, -54, 31, + 20, -65, 17, 39, -75, 4, 58, -86, -9, 77, -97, -22, + -54, -23, 76, -35, -34, 62, -16, -44, 48, 3, -55, 35, + 22, -66, 21, 41, -76, 8, 60, -87, -5, 79, -98, -18, + -52, -24, 80, -32, -35, 66, -14, -46, 52, 5, -56, 39, + 25, -67, 25, 43, -78, 12, 63, -89, -1, 81, -99, -14, + -49, -26, 84, -30, -36, 70, -11, -47, 56, 8, -58, 43, + 27, -69, 29, 46, -79, 16, 65, -90, 2, 84, -101, -10, + -47, -27, 88, -27, -38, 74, -9, -49, 61, 10, -59, 47, + 30, -70, 34, 48, -81, 20, 68, -92, 6, 87, -102, -6, + -44, -28, 92, -25, -39, 78, -6, -50, 65, 13, -61, 51, + 32, -71, 38, 51, -82, 24, 70, -93, 10, 89, -104, -2, + -42, -30, 96, -23, -41, 82, -4, -51, 69, 15, -62, 55, + 34, -73, 42, 53, -83, 28, 73, -94, 14, 91, -105, 1, + -40, -31, 100, -20, -42, 86, -1, -53, 73, 17, -63, 59, + 37, -74, 46, 56, -85, 32, 75, -96, 18, 94, -106, 5, + -37, -33, 105, -17, -44, 91, 1, -54, 77, 20, -65, 64, + 39, -76, 50, 58, -86, 37, 78, -97, 23, 96, -108, 10, + -34, -34, 109, -15, -45, 95, 4, -55, 81, 22, -66, 68, + 42, -77, 54, 61, -88, 41, 80, -99, 27, 99, -109, 14, + -32, -35, 113, -13, -46, 99, 6, -57, 85, 25, -67, 72, + 44, -78, 58, 63, -89, 45, 82, -100, 31, 101, -111, 18, + -107, 11, -15, -88, 0, -28, -69, -10, -42, -50, -20, -55, + -31, -31, -69, -12, -42, -82, 7, -53, -96, 26, -63, -110, + -105, 9, -11, -86, -1, -24, -67, -11, -38, -48, -22, -51, + -29, -33, -65, -10, -43, -78, 9, -54, -92, 28, -65, -106, + -103, 8, -7, -83, -2, -20, -64, -13, -34, -46, -23, -47, + -26, -34, -61, -8, -45, -74, 12, -56, -88, 31, -66, -102, + -100, 7, -2, -81, -3, -16, -62, -14, -29, -43, -25, -43, + -24, -36, -56, -5, -46, -70, 15, -57, -84, 33, -68, -97, + -98, 5, 1, -78, -5, -12, -59, -15, -25, -41, -26, -39, + -21, -37, -52, -2, -48, -66, 17, -58, -80, 36, -69, -93, + -95, 4, 5, -76, -6, -8, -57, -17, -21, -38, -27, -35, + -19, -38, -48, 0, -49, -62, 19, -60, -76, 38, -70, -89, + -93, 2, 9, -73, -7, -4, -55, -18, -17, -36, -29, -31, + -16, -40, -44, 2, -50, -58, 22, -61, -72, 41, -72, -85, + -90, 1, 13, -71, -9, 0, -52, -20, -13, -33, -30, -26, + -14, -41, -40, 5, -52, -53, 24, -63, -67, 43, -73, -81, + -88, 0, 17, -68, -10, 4, -50, -21, -9, -31, -32, -22, + -11, -42, -36, 7, -53, -49, 27, -64, -63, 46, -75, -77, + -85, -1, 21, -66, -12, 8, -47, -22, -5, -28, -33, -18, + -9, -44, -32, 10, -54, -45, 29, -65, -59, 48, -76, -73, + -83, -2, 25, -64, -13, 12, -45, -24, -1, -26, -34, -14, + -7, -45, -28, 12, -56, -41, 32, -67, -55, 50, -77, -69, + -80, -3, 29, -61, -14, 16, -42, -25, 2, -24, -36, -10, + -4, -47, -24, 15, -57, -37, 34, -68, -51, 53, -79, -65, + -78, -5, 34, -58, -16, 20, -40, -27, 7, -21, -37, -6, + -1, -48, -19, 17, -59, -33, 37, -70, -47, 55, -80, -60, + -75, -6, 38, -56, -17, 24, -37, -28, 11, -18, -38, -2, + 1, -49, -15, 20, -60, -29, 39, -71, -43, 58, -82, -56, + -73, -8, 42, -54, -19, 28, -35, -29, 15, -16, -40, 1, + 3, -51, -11, 22, -61, -25, 41, -72, -39, 60, -83, -52, + -71, -9, 46, -51, -20, 32, -32, -31, 19, -14, -41, 5, + 6, -52, -7, 24, -63, -21, 44, -74, -35, 63, -84, -48, + -68, -11, 50, -49, -21, 37, -30, -32, 23, -11, -43, 10, + 8, -54, -3, 27, -64, -16, 47, -75, -30, 65, -86, -44, + -66, -12, 54, -46, -23, 41, -27, -33, 27, -9, -44, 14, + 11, -55, 0, 30, -66, -12, 49, -76, -26, 68, -87, -40, + -63, -13, 58, -44, -24, 45, -25, -35, 31, -6, -45, 18, + 13, -56, 4, 32, -67, -8, 51, -78, -22, 70, -88, -36, + -61, -15, 62, -41, -26, 49, -23, -36, 35, -4, -47, 22, + 16, -58, 8, 34, -68, -4, 54, -79, -18, 73, -90, -32, + -58, -16, 67, -39, -27, 53, -20, -38, 40, -1, -48, 26, + 18, -59, 13, 37, -70, 0, 56, -81, -14, 75, -91, -27, + -56, -17, 71, -36, -28, 57, -18, -39, 44, 1, -50, 30, + 21, -61, 17, 39, -71, 3, 59, -82, -10, 78, -93, -23, + -53, -19, 75, -34, -30, 61, -15, -40, 48, 4, -51, 34, + 23, -62, 21, 42, -72, 7, 61, -83, -6, 80, -94, -19, + -51, -20, 79, -32, -31, 65, -13, -42, 52, 6, -52, 38, + 25, -63, 25, 44, -74, 11, 64, -85, -2, 82, -95, -15, + -48, -22, 83, -29, -32, 69, -10, -43, 56, 8, -54, 42, + 28, -65, 29, 47, -75, 15, 66, -86, 1, 85, -97, -11, + -46, -23, 87, -26, -34, 74, -8, -45, 60, 11, -55, 47, + 31, -66, 33, 49, -77, 20, 69, -88, 6, 87, -98, -7, + -43, -24, 91, -24, -35, 78, -5, -46, 64, 14, -57, 51, + 33, -67, 37, 52, -78, 24, 71, -89, 10, 90, -100, -3, + -41, -26, 95, -22, -37, 82, -3, -47, 68, 16, -58, 55, + 35, -69, 41, 54, -79, 28, 73, -90, 14, 92, -101, 0, + -39, -27, 99, -19, -38, 86, 0, -49, 72, 18, -59, 59, + 38, -70, 45, 56, -81, 32, 76, -92, 18, 95, -102, 4, + -36, -29, 104, -17, -40, 90, 2, -50, 77, 21, -61, 63, + 40, -72, 50, 59, -82, 36, 79, -93, 22, 97, -104, 9, + -34, -30, 108, -14, -41, 94, 5, -51, 81, 23, -62, 67, + 43, -73, 54, 62, -84, 40, 81, -95, 26, 100, -105, 13, + -31, -31, 112, -12, -42, 98, 7, -53, 85, 26, -63, 71, + 45, -74, 58, 64, -85, 44, 83, -96, 30, 102, -107, 17, + -106, 15, -15, -87, 4, -29, -68, -6, -42, -50, -16, -56, + -30, -27, -70, -11, -38, -83, 8, -49, -97, 27, -59, -110, + -104, 13, -11, -85, 2, -25, -66, -7, -38, -47, -18, -52, + -28, -29, -66, -9, -39, -79, 10, -50, -93, 29, -61, -106, + -102, 12, -7, -82, 1, -21, -64, -9, -34, -45, -19, -48, + -25, -30, -62, -7, -41, -75, 13, -52, -89, 32, -62, -102, + -99, 11, -3, -80, 0, -17, -61, -10, -30, -42, -21, -43, + -23, -32, -57, -4, -42, -71, 15, -53, -84, 34, -64, -98, + -97, 9, 0, -77, -1, -13, -58, -11, -26, -40, -22, -39, + -20, -33, -53, -2, -44, -67, 18, -54, -80, 37, -65, -94, + -94, 8, 4, -75, -2, -9, -56, -13, -22, -37, -23, -35, + -18, -34, -49, 1, -45, -63, 20, -56, -76, 39, -66, -90, + -92, 6, 8, -72, -3, -5, -54, -14, -18, -35, -25, -31, + -16, -36, -45, 3, -46, -59, 23, -57, -72, 41, -68, -86, + -89, 5, 13, -70, -5, 0, -51, -16, -13, -32, -26, -27, + -13, -37, -41, 6, -48, -54, 25, -59, -68, 44, -69, -81, + -87, 4, 17, -67, -6, 3, -49, -17, -9, -30, -28, -23, + -10, -38, -37, 8, -49, -50, 28, -60, -64, 47, -71, -77, + -84, 2, 21, -65, -8, 7, -46, -18, -5, -27, -29, -19, + -8, -40, -33, 11, -50, -46, 30, -61, -60, 49, -72, -73, + -82, 1, 25, -63, -9, 11, -44, -20, -1, -25, -30, -15, + -6, -41, -29, 13, -52, -42, 33, -63, -56, 51, -73, -69, + -80, 0, 29, -60, -10, 15, -41, -21, 2, -23, -32, -11, + -3, -43, -25, 16, -53, -38, 35, -64, -52, 54, -75, -65, + -77, -1, 33, -58, -12, 19, -39, -23, 6, -20, -33, -6, + -1, -44, -20, 18, -55, -34, 38, -66, -47, 56, -76, -61, + -74, -2, 37, -55, -13, 23, -36, -24, 10, -18, -34, -2, + 2, -45, -16, 21, -56, -30, 40, -67, -43, 59, -78, -57, + -72, -4, 41, -53, -15, 27, -34, -25, 14, -15, -36, 1, + 4, -47, -12, 23, -57, -26, 42, -68, -39, 61, -79, -53, + -70, -5, 45, -50, -16, 31, -32, -27, 18, -13, -37, 5, + 7, -48, -8, 25, -59, -22, 45, -70, -35, 64, -80, -49, + -67, -7, 50, -48, -17, 36, -29, -28, 23, -10, -39, 9, + 9, -50, -4, 28, -60, -17, 47, -71, -31, 66, -82, -44, + -65, -8, 54, -45, -19, 40, -26, -29, 27, -8, -40, 13, + 12, -51, 0, 30, -62, -13, 50, -72, -27, 69, -83, -40, + -62, -9, 58, -43, -20, 44, -24, -31, 31, -5, -41, 17, + 14, -52, 3, 33, -63, -9, 52, -74, -23, 71, -84, -36, + -60, -11, 62, -40, -22, 48, -22, -32, 35, -3, -43, 21, + 16, -54, 7, 35, -64, -5, 55, -75, -19, 73, -86, -32, + -57, -12, 66, -38, -23, 52, -19, -34, 39, 0, -44, 26, + 19, -55, 12, 38, -66, -1, 57, -77, -14, 76, -87, -28, + -55, -13, 70, -35, -24, 56, -17, -35, 43, 2, -46, 30, + 22, -57, 16, 40, -67, 2, 60, -78, -10, 78, -89, -24, + -52, -15, 74, -33, -26, 60, -14, -36, 47, 5, -47, 34, + 24, -58, 20, 43, -68, 6, 62, -79, -6, 81, -90, -20, + -50, -16, 78, -31, -27, 64, -12, -38, 51, 7, -48, 38, + 26, -59, 24, 45, -70, 10, 64, -81, -2, 83, -91, -16, + -48, -18, 82, -28, -28, 68, -9, -39, 55, 9, -50, 42, + 29, -61, 28, 48, -71, 14, 67, -82, 1, 86, -93, -12, + -45, -19, 87, -26, -30, 73, -7, -41, 60, 12, -51, 46, + 31, -62, 32, 50, -73, 19, 70, -84, 5, 88, -94, -7, + -42, -20, 91, -23, -31, 77, -4, -42, 64, 14, -53, 50, + 34, -63, 36, 53, -74, 23, 72, -85, 9, 91, -96, -3, + -40, -22, 95, -21, -33, 81, -2, -43, 68, 17, -54, 54, + 36, -65, 40, 55, -75, 27, 74, -86, 13, 93, -97, 0, + -38, -23, 99, -18, -34, 85, 0, -45, 72, 19, -55, 58, + 39, -66, 44, 57, -77, 31, 77, -88, 17, 96, -98, 4, + -35, -25, 103, -16, -36, 89, 3, -46, 76, 22, -57, 63, + 41, -68, 49, 60, -78, 35, 79, -89, 22, 98, -100, 8, + -33, -26, 107, -13, -37, 93, 6, -47, 80, 24, -58, 67, + 44, -69, 53, 62, -80, 39, 82, -91, 26, 101, -101, 12, + -30, -27, 111, -11, -38, 97, 8, -49, 84, 27, -59, 71, + 46, -70, 57, 65, -81, 43, 84, -92, 30, 103, -103, 16, + -105, 19, -16, -86, 8, -30, -67, -1, -43, -49, -12, -57, + -29, -23, -70, -10, -33, -84, 9, -44, -98, 28, -55, -111, + -103, 18, -12, -84, 7, -26, -65, -3, -39, -46, -13, -53, + -27, -24, -66, -8, -35, -80, 11, -46, -94, 30, -56, -107, + -101, 17, -8, -81, 6, -22, -63, -4, -35, -44, -15, -49, + -24, -26, -62, -6, -36, -76, 14, -47, -90, 33, -58, -103, + -98, 15, -3, -79, 4, -17, -60, -6, -31, -41, -16, -44, + -22, -27, -58, -3, -38, -71, 16, -49, -85, 35, -59, -98, + -96, 14, 0, -76, 3, -13, -57, -7, -27, -39, -17, -40, + -19, -28, -54, 0, -39, -67, 19, -50, -81, 38, -61, -94, + -93, 12, 4, -74, 1, -9, -55, -8, -23, -36, -19, -36, + -17, -30, -50, 2, -40, -63, 21, -51, -77, 40, -62, -90, + -91, 11, 8, -71, 0, -5, -53, -10, -19, -34, -20, -32, + -14, -31, -46, 4, -42, -59, 24, -53, -73, 42, -63, -86, + -88, 9, 12, -69, 0, -1, -50, -11, -14, -31, -22, -28, + -12, -33, -41, 7, -43, -55, 26, -54, -69, 45, -65, -82, + -86, 8, 16, -66, -2, 2, -48, -12, -10, -29, -23, -24, + -9, -34, -37, 9, -45, -51, 29, -56, -65, 48, -66, -78, + -83, 7, 20, -64, -3, 6, -45, -14, -6, -26, -24, -20, + -7, -35, -33, 12, -46, -47, 31, -57, -61, 50, -67, -74, + -81, 5, 24, -62, -5, 10, -43, -15, -2, -24, -26, -16, + -5, -37, -29, 14, -47, -43, 34, -58, -57, 52, -69, -70, + -79, 4, 28, -59, -6, 14, -40, -16, 1, -22, -27, -12, + -2, -38, -25, 17, -49, -39, 36, -60, -53, 55, -70, -66, + -76, 3, 33, -56, -7, 19, -38, -18, 5, -19, -29, -7, + 0, -40, -21, 19, -50, -34, 39, -61, -48, 57, -72, -61, + -73, 1, 37, -54, -9, 23, -35, -19, 9, -17, -30, -3, + 3, -41, -17, 22, -51, -30, 41, -62, -44, 60, -73, -57, + -71, 0, 41, -52, -10, 27, -33, -21, 13, -14, -31, 0, + 5, -42, -13, 24, -53, -26, 43, -64, -40, 62, -74, -53, + -69, -1, 45, -49, -11, 31, -31, -22, 17, -12, -33, 4, + 8, -44, -9, 26, -54, -22, 46, -65, -36, 65, -76, -49, + -66, -2, 49, -47, -13, 35, -28, -24, 22, -9, -34, 8, + 10, -45, -4, 29, -56, -18, 48, -67, -32, 67, -77, -45, + -64, -3, 53, -44, -14, 39, -25, -25, 26, -7, -36, 12, + 13, -46, 0, 32, -57, -14, 51, -68, -28, 70, -79, -41, + -61, -5, 57, -42, -16, 43, -23, -26, 30, -4, -37, 16, + 15, -48, 3, 34, -58, -10, 53, -69, -24, 72, -80, -37, + -59, -6, 61, -39, -17, 47, -21, -28, 34, -2, -38, 20, + 18, -49, 7, 36, -60, -6, 56, -71, -20, 74, -81, -33, + -56, -8, 66, -37, -19, 52, -18, -29, 38, 1, -40, 25, + 20, -51, 11, 39, -61, -1, 58, -72, -15, 77, -83, -28, + -54, -9, 70, -34, -20, 56, -16, -30, 42, 3, -41, 29, + 23, -52, 15, 41, -63, 2, 61, -74, -11, 80, -84, -24, + -51, -10, 74, -32, -21, 60, -13, -32, 46, 6, -42, 33, + 25, -53, 19, 44, -64, 6, 63, -75, -7, 82, -86, -20, + -49, -12, 78, -30, -23, 64, -11, -33, 50, 8, -44, 37, + 27, -55, 23, 46, -65, 10, 66, -76, -3, 84, -87, -16, + -47, -13, 82, -27, -24, 68, -8, -35, 54, 10, -45, 41, + 30, -56, 27, 49, -67, 14, 68, -78, 0, 87, -88, -12, + -44, -15, 86, -24, -25, 72, -6, -36, 59, 13, -47, 45, + 32, -58, 32, 51, -68, 18, 71, -79, 4, 89, -90, -8, + -41, -16, 90, -22, -27, 76, -3, -37, 63, 15, -48, 49, + 35, -59, 36, 54, -70, 22, 73, -80, 8, 92, -91, -4, + -39, -17, 94, -20, -28, 80, -1, -39, 67, 18, -49, 53, + 37, -60, 40, 56, -71, 26, 75, -82, 12, 94, -92, 0, + -37, -19, 98, -17, -30, 84, 1, -40, 71, 20, -51, 57, + 40, -62, 44, 58, -72, 30, 78, -83, 16, 97, -94, 3, + -34, -20, 103, -15, -31, 89, 4, -42, 75, 23, -52, 62, + 42, -63, 48, 61, -74, 35, 80, -85, 21, 99, -95, 8, + -32, -21, 107, -12, -32, 93, 7, -43, 79, 25, -54, 66, + 45, -65, 52, 63, -75, 39, 83, -86, 25, 102, -97, 12, + -29, -23, 111, -10, -34, 97, 9, -44, 83, 28, -55, 70, + 47, -66, 56, 66, -76, 43, 85, -87, 29, 104, -98, 16, + -105, 23, -17, -85, 12, -30, -66, 2, -44, -48, -8, -57, + -28, -19, -71, -9, -29, -84, 10, -40, -98, 29, -51, -112, + -102, 22, -13, -83, 11, -26, -64, 0, -40, -45, -9, -53, + -26, -20, -67, -7, -31, -80, 12, -42, -94, 31, -52, -108, + -100, 21, -9, -80, 10, -22, -62, 0, -36, -43, -11, -49, + -23, -22, -63, -5, -32, -76, 15, -43, -90, 33, -54, -104, + -97, 19, -4, -78, 8, -18, -59, -2, -31, -40, -12, -45, + -21, -23, -59, -2, -34, -72, 17, -45, -86, 36, -55, -99, + -95, 18, 0, -75, 7, -14, -57, -3, -27, -38, -13, -41, + -18, -24, -55, 0, -35, -68, 20, -46, -82, 39, -57, -95, + -92, 16, 3, -73, 5, -10, -54, -4, -23, -35, -15, -37, + -16, -26, -51, 3, -36, -64, 22, -47, -78, 41, -58, -91, + -90, 15, 7, -71, 4, -6, -52, -6, -19, -33, -16, -33, + -14, -27, -47, 5, -38, -60, 25, -49, -74, 43, -59, -87, + -87, 13, 11, -68, 3, -1, -49, -7, -15, -30, -18, -28, + -11, -29, -42, 8, -39, -55, 27, -50, -69, 46, -61, -83, + -85, 12, 15, -65, 1, 2, -47, -8, -11, -28, -19, -24, + -8, -30, -38, 10, -41, -51, 30, -52, -65, 48, -62, -79, + -82, 11, 19, -63, 0, 6, -44, -10, -7, -25, -20, -20, + -6, -31, -34, 13, -42, -47, 32, -53, -61, 51, -63, -75, + -80, 9, 23, -61, -1, 10, -42, -11, -3, -23, -22, -16, + -4, -33, -30, 15, -43, -43, 34, -54, -57, 53, -65, -71, + -78, 8, 27, -58, -2, 14, -39, -12, 0, -21, -23, -12, + -1, -34, -26, 17, -45, -39, 37, -56, -53, 56, -66, -67, + -75, 7, 32, -56, -3, 18, -37, -14, 5, -18, -25, -8, + 1, -36, -22, 20, -46, -35, 40, -57, -49, 58, -68, -62, + -73, 5, 36, -53, -5, 22, -34, -15, 9, -16, -26, -4, + 4, -37, -18, 23, -47, -31, 42, -58, -45, 61, -69, -58, + -70, 4, 40, -51, -6, 26, -32, -17, 13, -13, -27, 0, + 6, -38, -14, 25, -49, -27, 44, -60, -41, 63, -70, -54, + -68, 2, 44, -48, -7, 30, -30, -18, 17, -11, -29, 3, + 9, -40, -10, 27, -50, -23, 47, -61, -37, 65, -72, -50, + -65, 1, 48, -46, -9, 35, -27, -20, 21, -8, -30, 8, + 11, -41, -5, 30, -52, -18, 49, -63, -32, 68, -73, -46, + -63, 0, 52, -43, -10, 39, -25, -21, 25, -6, -32, 12, + 14, -42, -1, 32, -53, -14, 52, -64, -28, 71, -75, -42, + -60, -1, 56, -41, -12, 43, -22, -22, 29, -3, -33, 16, + 16, -44, 2, 35, -54, -10, 54, -65, -24, 73, -76, -38, + -58, -2, 60, -39, -13, 47, -20, -24, 33, -1, -34, 20, + 18, -45, 6, 37, -56, -6, 57, -67, -20, 75, -77, -34, + -55, -4, 65, -36, -15, 51, -17, -25, 38, 2, -36, 24, + 21, -47, 10, 40, -57, -2, 59, -68, -16, 78, -79, -29, + -53, -5, 69, -33, -16, 55, -15, -26, 42, 4, -37, 28, + 23, -48, 14, 42, -59, 1, 62, -70, -12, 80, -80, -25, + -50, -6, 73, -31, -17, 59, -12, -28, 46, 7, -38, 32, + 26, -49, 18, 45, -60, 5, 64, -71, -8, 83, -82, -21, + -48, -8, 77, -29, -19, 63, -10, -29, 50, 9, -40, 36, + 28, -51, 22, 47, -61, 9, 66, -72, -4, 85, -83, -17, + -46, -9, 81, -26, -20, 67, -7, -31, 54, 11, -41, 40, + 31, -52, 26, 49, -63, 13, 69, -74, 0, 88, -84, -13, + -43, -11, 85, -24, -21, 72, -5, -32, 58, 14, -43, 45, + 33, -54, 31, 52, -64, 18, 72, -75, 4, 90, -86, -9, + -41, -12, 89, -21, -23, 76, -2, -33, 62, 16, -44, 49, + 36, -55, 35, 55, -66, 22, 74, -76, 8, 93, -87, -5, + -38, -13, 93, -19, -24, 80, 0, -35, 66, 19, -45, 53, + 38, -56, 39, 57, -67, 26, 76, -78, 12, 95, -88, -1, + -36, -15, 97, -16, -26, 84, 2, -36, 70, 21, -47, 57, + 41, -58, 43, 59, -68, 30, 79, -79, 16, 97, -90, 2, + -33, -16, 102, -14, -27, 88, 5, -38, 75, 24, -48, 61, + 43, -59, 47, 62, -70, 34, 81, -81, 20, 100, -91, 7, + -31, -17, 106, -11, -28, 92, 7, -39, 79, 26, -50, 65, + 46, -61, 51, 64, -71, 38, 84, -82, 24, 103, -93, 11, + -28, -19, 110, -9, -30, 96, 10, -40, 83, 29, -51, 69, + 48, -62, 55, 67, -72, 42, 86, -83, 28, 105, -94, 15, + -104, 27, -17, -84, 16, -31, -65, 6, -44, -47, -4, -58, + -27, -15, -72, -9, -25, -85, 11, -36, -99, 30, -47, -112, + -101, 26, -13, -82, 15, -27, -63, 4, -40, -44, -5, -54, + -25, -16, -68, -6, -27, -81, 13, -38, -95, 32, -48, -108, + -99, 25, -9, -79, 14, -23, -61, 3, -36, -42, -7, -50, + -23, -18, -64, -4, -28, -77, 16, -39, -91, 34, -50, -104, + -96, 23, -5, -77, 12, -19, -58, 1, -32, -39, -8, -45, + -20, -19, -59, -1, -30, -73, 18, -41, -86, 37, -51, -100, + -94, 22, -1, -74, 11, -15, -56, 0, -28, -37, -9, -41, + -17, -20, -55, 1, -31, -69, 21, -42, -82, 39, -53, -96, + -91, 20, 2, -72, 9, -11, -53, 0, -24, -34, -11, -37, + -15, -22, -51, 4, -32, -65, 23, -43, -78, 42, -54, -92, + -89, 19, 6, -70, 8, -7, -51, -2, -20, -32, -12, -33, + -13, -23, -47, 6, -34, -61, 25, -45, -74, 44, -55, -88, + -86, 17, 11, -67, 7, -2, -48, -3, -15, -29, -14, -29, + -10, -25, -43, 9, -35, -56, 28, -46, -70, 47, -57, -83, + -84, 16, 15, -65, 5, 1, -46, -4, -11, -27, -15, -25, + -8, -26, -39, 11, -37, -52, 31, -48, -66, 49, -58, -79, + -82, 15, 19, -62, 4, 5, -43, -6, -7, -25, -16, -21, + -5, -27, -35, 14, -38, -48, 33, -49, -62, 52, -59, -75, + -79, 13, 23, -60, 2, 9, -41, -7, -3, -22, -18, -17, + -3, -29, -31, 16, -39, -44, 35, -50, -58, 54, -61, -71, + -77, 12, 27, -57, 1, 13, -39, -8, 0, -20, -19, -13, + 0, -30, -27, 18, -41, -40, 38, -52, -54, 57, -62, -67, + -74, 11, 31, -55, 0, 17, -36, -10, 4, -17, -21, -8, + 2, -32, -22, 21, -42, -36, 40, -53, -49, 59, -64, -63, + -72, 9, 35, -52, -1, 21, -33, -11, 8, -15, -22, -4, + 5, -33, -18, 23, -43, -32, 43, -54, -45, 62, -65, -59, + -69, 8, 39, -50, -2, 25, -31, -13, 12, -12, -23, 0, + 7, -34, -14, 26, -45, -28, 45, -56, -41, 64, -66, -55, + -67, 6, 43, -47, -3, 29, -29, -14, 16, -10, -25, 3, + 9, -36, -10, 28, -46, -24, 48, -57, -37, 66, -68, -51, + -64, 5, 48, -45, -5, 34, -26, -16, 21, -7, -26, 7, + 12, -37, -6, 31, -48, -19, 50, -59, -33, 69, -69, -46, + -62, 4, 52, -42, -6, 38, -24, -17, 25, -5, -28, 11, + 15, -38, -2, 33, -49, -15, 53, -60, -29, 71, -71, -42, + -59, 2, 56, -40, -8, 42, -21, -18, 29, -2, -29, 15, + 17, -40, 1, 36, -50, -11, 55, -61, -25, 74, -72, -38, + -57, 1, 60, -38, -9, 46, -19, -20, 33, 0, -30, 19, + 19, -41, 5, 38, -52, -7, 57, -63, -21, 76, -73, -34, + -54, 0, 64, -35, -11, 50, -16, -21, 37, 3, -32, 24, + 22, -43, 10, 41, -53, -3, 60, -64, -16, 79, -75, -30, + -52, -1, 68, -33, -12, 54, -14, -22, 41, 5, -33, 28, + 24, -44, 14, 43, -55, 0, 63, -66, -12, 81, -76, -26, + -50, -2, 72, -30, -13, 58, -11, -24, 45, 7, -34, 32, + 27, -45, 18, 46, -56, 4, 65, -67, -8, 84, -78, -22, + -47, -4, 76, -28, -15, 62, -9, -25, 49, 10, -36, 36, + 29, -47, 22, 48, -57, 8, 67, -68, -4, 86, -79, -18, + -45, -5, 80, -25, -16, 66, -7, -27, 53, 12, -37, 40, + 32, -48, 26, 50, -59, 12, 70, -70, 0, 89, -80, -14, + -42, -7, 85, -23, -17, 71, -4, -28, 58, 15, -39, 44, + 34, -50, 30, 53, -60, 17, 72, -71, 3, 91, -82, -9, + -40, -8, 89, -20, -19, 75, -1, -29, 62, 17, -40, 48, + 37, -51, 34, 55, -62, 21, 75, -72, 7, 94, -83, -5, + -37, -9, 93, -18, -20, 79, 1, -31, 66, 20, -41, 52, + 39, -52, 38, 58, -63, 25, 77, -74, 11, 96, -84, -1, + -35, -11, 97, -15, -22, 83, 3, -32, 70, 22, -43, 56, + 41, -54, 42, 60, -64, 29, 80, -75, 15, 98, -86, 2, + -32, -12, 101, -13, -23, 87, 6, -34, 74, 25, -44, 61, + 44, -55, 47, 63, -66, 33, 82, -77, 20, 101, -87, 6, + -30, -13, 105, -10, -24, 91, 8, -35, 78, 27, -46, 65, + 47, -57, 51, 65, -67, 37, 85, -78, 24, 103, -89, 10, + -27, -15, 109, -8, -26, 95, 11, -36, 82, 30, -47, 69, + 49, -58, 55, 68, -68, 41, 87, -79, 28, 106, -90, 14, + -103, 31, -18, -83, 20, -32, -65, 10, -45, -46, 0, -59, + -26, -11, -72, -8, -21, -86, 12, -32, -100, 31, -43, -113, + -100, 30, -14, -81, 19, -28, -62, 8, -41, -43, -1, -55, + -24, -12, -68, -5, -23, -82, 14, -34, -96, 33, -44, -109, + -98, 29, -10, -79, 18, -24, -60, 7, -37, -41, -3, -51, + -22, -14, -64, -3, -24, -78, 17, -35, -92, 35, -46, -105, + -95, 27, -5, -76, 16, -19, -57, 5, -33, -38, -4, -46, + -19, -15, -60, 0, -26, -73, 19, -37, -87, 38, -47, -100, + -93, 26, -1, -73, 15, -15, -55, 4, -29, -36, -5, -42, + -17, -16, -56, 2, -27, -69, 22, -38, -83, 40, -49, -96, + -90, 24, 2, -71, 13, -11, -52, 3, -25, -34, -7, -38, + -14, -18, -52, 5, -28, -65, 24, -39, -79, 43, -50, -92, + -88, 23, 6, -69, 12, -7, -50, 1, -21, -31, -8, -34, + -12, -19, -48, 7, -30, -61, 26, -41, -75, 45, -51, -88, + -85, 21, 10, -66, 11, -3, -47, 0, -16, -28, -10, -30, + -9, -21, -43, 10, -31, -57, 29, -42, -71, 48, -53, -84, + -83, 20, 14, -64, 9, 0, -45, 0, -12, -26, -11, -26, + -7, -22, -39, 12, -33, -53, 31, -44, -67, 50, -54, -80, + -81, 19, 18, -61, 8, 4, -42, -2, -8, -24, -12, -22, + -4, -23, -35, 15, -34, -49, 34, -45, -63, 53, -55, -76, + -78, 17, 22, -59, 6, 8, -40, -3, -4, -21, -14, -18, + -2, -25, -31, 17, -35, -45, 36, -46, -59, 55, -57, -72, + -76, 16, 26, -56, 5, 12, -38, -4, 0, -19, -15, -14, + 1, -26, -27, 19, -37, -41, 39, -48, -55, 57, -58, -68, + -73, 15, 31, -54, 4, 17, -35, -6, 3, -16, -17, -9, + 3, -28, -23, 22, -38, -36, 41, -49, -50, 60, -60, -63, + -71, 13, 35, -51, 2, 21, -33, -7, 7, -14, -18, -5, + 6, -29, -19, 24, -39, -32, 44, -50, -46, 63, -61, -59, + -68, 12, 39, -49, 1, 25, -30, -9, 11, -11, -19, -1, + 8, -30, -15, 27, -41, -28, 46, -52, -42, 65, -62, -55, + -66, 10, 43, -47, 0, 29, -28, -10, 15, -9, -21, 2, + 10, -32, -11, 29, -42, -24, 49, -53, -38, 67, -64, -51, + -63, 9, 47, -44, -1, 33, -25, -12, 20, -6, -22, 6, + 13, -33, -6, 32, -44, -20, 51, -55, -34, 70, -65, -47, + -61, 8, 51, -41, -2, 37, -23, -13, 24, -4, -24, 10, + 15, -34, -2, 34, -45, -16, 54, -56, -30, 72, -67, -43, + -58, 6, 55, -39, -4, 41, -20, -14, 28, -2, -25, 14, + 18, -36, 1, 37, -46, -12, 56, -57, -26, 75, -68, -39, + -56, 5, 59, -37, -5, 45, -18, -16, 32, 1, -26, 18, + 20, -37, 5, 39, -48, -8, 58, -59, -22, 77, -69, -35, + -53, 3, 64, -34, -7, 50, -15, -17, 36, 4, -28, 23, + 23, -39, 9, 42, -49, -3, 61, -60, -17, 80, -71, -30, + -51, 2, 68, -32, -8, 54, -13, -18, 40, 6, -29, 27, + 25, -40, 13, 44, -51, 0, 63, -62, -13, 82, -72, -26, + -49, 1, 72, -29, -9, 58, -10, -20, 44, 8, -30, 31, + 28, -41, 17, 46, -52, 4, 66, -63, -9, 85, -74, -22, + -46, 0, 76, -27, -11, 62, -8, -21, 48, 11, -32, 35, + 30, -43, 21, 49, -53, 8, 68, -64, -5, 87, -75, -18, + -44, -1, 80, -24, -12, 66, -6, -23, 52, 13, -33, 39, + 32, -44, 25, 51, -55, 12, 71, -66, -1, 89, -76, -14, + -41, -3, 84, -22, -13, 70, -3, -24, 57, 16, -35, 43, + 35, -46, 30, 54, -56, 16, 73, -67, 2, 92, -78, -10, + -39, -4, 88, -19, -15, 74, -1, -25, 61, 18, -36, 47, + 38, -47, 34, 56, -58, 20, 76, -68, 6, 95, -79, -6, + -36, -5, 92, -17, -16, 78, 2, -27, 65, 21, -37, 51, + 40, -48, 38, 59, -59, 24, 78, -70, 10, 97, -80, -2, + -34, -7, 96, -15, -18, 82, 4, -28, 69, 23, -39, 55, + 42, -50, 42, 61, -60, 28, 81, -71, 14, 99, -82, 1, + -31, -8, 101, -12, -19, 87, 7, -30, 73, 26, -40, 60, + 45, -51, 46, 64, -62, 33, 83, -73, 19, 102, -83, 6, + -29, -9, 105, -9, -20, 91, 9, -31, 77, 28, -42, 64, + 47, -53, 50, 66, -63, 37, 86, -74, 23, 104, -85, 10, + -26, -11, 109, -7, -22, 95, 12, -32, 81, 30, -43, 68, + 50, -54, 54, 69, -64, 41, 88, -75, 27, 107, -86, 14, + -102, 35, -19, -82, 24, -32, -64, 14, -46, -45, 3, -59, + -25, -7, -73, -7, -17, -86, 13, -28, -100, 31, -39, -114, + -99, 34, -15, -80, 23, -28, -61, 12, -42, -42, 2, -55, + -23, -8, -69, -4, -19, -82, 15, -30, -96, 34, -40, -110, + -97, 33, -11, -78, 22, -24, -59, 11, -38, -40, 0, -51, + -21, -10, -65, -2, -20, -78, 17, -31, -92, 36, -42, -106, + -94, 31, -6, -75, 20, -20, -56, 9, -33, -37, 0, -47, + -18, -11, -60, 1, -22, -74, 20, -33, -88, 39, -43, -101, + -92, 30, -2, -73, 19, -16, -54, 8, -29, -35, -1, -43, + -16, -12, -56, 3, -23, -70, 23, -34, -84, 41, -45, -97, + -90, 28, 1, -70, 17, -12, -51, 7, -25, -33, -3, -39, + -13, -14, -52, 6, -24, -66, 25, -35, -80, 44, -46, -93, + -87, 27, 5, -68, 16, -8, -49, 5, -21, -30, -4, -35, + -11, -15, -48, 8, -26, -62, 27, -37, -76, 46, -47, -89, + -84, 25, 9, -65, 15, -3, -46, 4, -17, -28, -6, -30, + -8, -17, -44, 11, -27, -57, 30, -38, -71, 49, -49, -85, + -82, 24, 13, -63, 13, 0, -44, 3, -13, -25, -7, -26, + -6, -18, -40, 13, -29, -53, 32, -40, -67, 51, -50, -81, + -80, 23, 17, -60, 12, 4, -42, 1, -9, -23, -8, -22, + -3, -19, -36, 15, -30, -49, 35, -41, -63, 54, -51, -77, + -77, 21, 21, -58, 10, 8, -39, 0, -5, -20, -10, -18, + -1, -21, -32, 18, -31, -45, 37, -42, -59, 56, -53, -73, + -75, 20, 25, -56, 9, 12, -37, 0, -1, -18, -11, -14, + 1, -22, -28, 20, -33, -41, 40, -44, -55, 58, -54, -69, + -72, 19, 30, -53, 8, 16, -34, -2, 3, -15, -13, -10, + 4, -24, -23, 23, -34, -37, 42, -45, -51, 61, -56, -64, + -70, 17, 34, -50, 6, 20, -32, -3, 7, -13, -14, -6, + 6, -25, -19, 25, -35, -33, 45, -46, -47, 63, -57, -60, + -67, 16, 38, -48, 5, 24, -29, -5, 11, -10, -15, -2, + 9, -26, -15, 28, -37, -29, 47, -48, -43, 66, -58, -56, + -65, 14, 42, -46, 4, 28, -27, -6, 15, -8, -17, 1, + 11, -28, -11, 30, -38, -25, 49, -49, -39, 68, -60, -52, + -62, 13, 46, -43, 2, 33, -24, -8, 19, -5, -18, 6, + 14, -29, -7, 33, -40, -20, 52, -51, -34, 71, -61, -48, + -60, 12, 50, -41, 1, 37, -22, -9, 23, -3, -20, 10, + 16, -30, -3, 35, -41, -16, 55, -52, -30, 73, -63, -44, + -58, 10, 54, -38, 0, 41, -19, -10, 27, -1, -21, 14, + 19, -32, 0, 38, -42, -12, 57, -53, -26, 76, -64, -40, + -55, 9, 58, -36, -1, 45, -17, -12, 31, 2, -22, 18, + 21, -33, 4, 40, -44, -8, 59, -55, -22, 78, -65, -36, + -52, 7, 63, -33, -3, 49, -14, -13, 36, 4, -24, 22, + 24, -35, 9, 43, -45, -4, 62, -56, -18, 81, -67, -31, + -50, 6, 67, -31, -4, 53, -12, -14, 40, 7, -25, 26, + 26, -36, 13, 45, -47, 0, 64, -58, -14, 83, -68, -27, + -48, 5, 71, -28, -5, 57, -10, -16, 44, 9, -26, 30, + 29, -37, 17, 47, -48, 3, 67, -59, -10, 86, -70, -23, + -45, 3, 75, -26, -7, 61, -7, -17, 48, 12, -28, 34, + 31, -39, 21, 50, -49, 7, 69, -60, -6, 88, -71, -19, + -43, 2, 79, -24, -8, 65, -5, -19, 52, 14, -29, 38, + 33, -40, 25, 52, -51, 11, 72, -62, -2, 90, -72, -15, + -40, 0, 83, -21, -9, 70, -2, -20, 56, 17, -31, 43, + 36, -42, 29, 55, -52, 16, 74, -63, 2, 93, -74, -11, + -38, 0, 87, -18, -11, 74, 0, -21, 60, 19, -32, 47, + 38, -43, 33, 57, -54, 20, 77, -64, 6, 95, -75, -7, + -35, -1, 91, -16, -12, 78, 3, -23, 64, 22, -33, 51, + 41, -44, 37, 60, -55, 24, 79, -66, 10, 98, -76, -3, + -33, -3, 95, -14, -14, 82, 5, -24, 68, 24, -35, 55, + 43, -46, 41, 62, -56, 28, 81, -67, 14, 100, -78, 0, + -30, -4, 100, -11, -15, 86, 8, -26, 73, 27, -36, 59, + 46, -47, 46, 65, -58, 32, 84, -69, 18, 103, -79, 5, + -28, -5, 104, -9, -16, 90, 10, -27, 77, 29, -38, 63, + 48, -49, 50, 67, -59, 36, 87, -70, 22, 105, -81, 9, + -26, -7, 108, -6, -18, 94, 13, -28, 81, 31, -39, 67, + 51, -50, 54, 70, -60, 40, 89, -71, 26, 108, -82, 13, + -101, 40, -19, -81, 29, -33, -63, 18, -46, -44, 8, -60, + -24, -2, -74, -6, -13, -87, 14, -24, -101, 32, -34, -114, + -98, 38, -15, -79, 27, -29, -60, 17, -42, -41, 6, -56, + -22, -4, -70, -3, -14, -83, 16, -25, -97, 35, -36, -110, + -96, 37, -11, -77, 26, -25, -58, 15, -38, -39, 5, -52, + -20, -5, -66, -1, -16, -79, 18, -27, -93, 37, -37, -106, + -93, 36, -7, -74, 25, -21, -55, 14, -34, -36, 3, -47, + -17, -7, -61, 2, -17, -75, 21, -28, -88, 40, -39, -102, + -91, 34, -3, -72, 23, -17, -53, 13, -30, -34, 2, -43, + -15, -8, -57, 4, -19, -71, 24, -29, -84, 42, -40, -98, + -89, 33, 0, -69, 22, -13, -50, 11, -26, -32, 1, -39, + -12, -9, -53, 7, -20, -67, 26, -31, -80, 45, -41, -94, + -86, 31, 4, -67, 21, -9, -48, 10, -22, -29, 0, -35, + -10, -11, -49, 9, -21, -63, 28, -32, -76, 47, -43, -90, + -83, 30, 9, -64, 19, -4, -45, 8, -17, -26, -1, -31, + -7, -12, -45, 12, -23, -58, 31, -34, -72, 50, -44, -85, + -81, 29, 13, -62, 18, 0, -43, 7, -13, -24, -3, -27, + -5, -13, -41, 14, -24, -54, 33, -35, -68, 52, -46, -81, + -79, 27, 17, -59, 16, 3, -40, 6, -9, -22, -4, -23, + -2, -15, -37, 16, -25, -50, 36, -36, -64, 55, -47, -77, + -76, 26, 21, -57, 15, 7, -38, 4, -5, -19, -5, -19, + 0, -16, -33, 19, -27, -46, 38, -38, -60, 57, -48, -73, + -74, 25, 25, -54, 14, 11, -36, 3, -1, -17, -7, -15, + 2, -18, -29, 21, -28, -42, 41, -39, -56, 59, -50, -69, + -71, 23, 29, -52, 12, 15, -33, 1, 2, -14, -8, -10, + 5, -19, -24, 24, -30, -38, 43, -41, -51, 62, -51, -65, + -69, 22, 33, -49, 11, 19, -31, 0, 6, -12, -9, -6, + 8, -20, -20, 26, -31, -34, 46, -42, -47, 64, -53, -61, + -66, 20, 37, -47, 9, 23, -28, 0, 10, -9, -11, -2, + 10, -22, -16, 29, -32, -30, 48, -43, -43, 67, -54, -57, + -64, 19, 41, -45, 8, 27, -26, -2, 14, -7, -12, 1, + 12, -23, -12, 31, -34, -26, 50, -45, -39, 69, -55, -53, + -61, 17, 46, -42, 7, 32, -23, -3, 19, -4, -14, 5, + 15, -25, -8, 34, -35, -21, 53, -46, -35, 72, -57, -48, + -59, 16, 50, -40, 5, 36, -21, -4, 23, -2, -15, 9, + 17, -26, -4, 36, -37, -17, 56, -47, -31, 74, -58, -44, + -57, 15, 54, -37, 4, 40, -18, -6, 27, 0, -16, 13, + 20, -27, 0, 39, -38, -13, 58, -49, -27, 77, -59, -40, + -54, 13, 58, -35, 2, 44, -16, -7, 31, 3, -18, 17, + 22, -29, 3, 41, -39, -9, 60, -50, -23, 79, -61, -36, + -51, 12, 62, -32, 1, 48, -13, -9, 35, 5, -19, 22, + 25, -30, 8, 44, -41, -5, 63, -52, -18, 82, -62, -32, + -49, 11, 66, -30, 0, 52, -11, -10, 39, 8, -21, 26, + 27, -32, 12, 46, -42, -1, 65, -53, -14, 84, -64, -28, + -47, 9, 70, -27, -1, 56, -9, -11, 43, 10, -22, 30, + 30, -33, 16, 48, -43, 2, 68, -54, -10, 87, -65, -24, + -44, 8, 74, -25, -2, 60, -6, -13, 47, 13, -23, 34, + 32, -34, 20, 51, -45, 6, 70, -56, -6, 89, -66, -20, + -42, 6, 78, -23, -3, 64, -4, -14, 51, 15, -25, 38, + 34, -36, 24, 53, -46, 10, 73, -57, -2, 91, -68, -16, + -39, 5, 83, -20, -5, 69, -1, -16, 56, 18, -26, 42, + 37, -37, 28, 56, -48, 15, 75, -59, 1, 94, -69, -11, + -37, 4, 87, -17, -6, 73, 1, -17, 60, 20, -28, 46, + 40, -38, 32, 58, -49, 19, 78, -60, 5, 96, -71, -7, + -34, 2, 91, -15, -8, 77, 4, -18, 64, 23, -29, 50, + 42, -40, 36, 61, -50, 23, 80, -61, 9, 99, -72, -3, + -32, 1, 95, -13, -9, 81, 6, -20, 68, 25, -30, 54, + 44, -41, 40, 63, -52, 27, 82, -63, 13, 101, -73, 0, + -29, 0, 99, -10, -11, 85, 9, -21, 72, 28, -32, 59, + 47, -43, 45, 66, -53, 31, 85, -64, 18, 104, -75, 4, + -27, -1, 103, -8, -12, 89, 11, -22, 76, 30, -33, 63, + 49, -44, 49, 68, -55, 35, 88, -66, 22, 106, -76, 8, + -25, -2, 107, -5, -13, 93, 14, -24, 80, 32, -34, 67, + 52, -45, 53, 71, -56, 39, 90, -67, 26, 109, -78, 12, + -100, 44, -20, -80, 33, -34, -62, 22, -47, -43, 12, -61, + -24, 1, -74, -5, -9, -88, 15, -20, -102, 33, -30, -115, + -97, 42, -16, -78, 31, -30, -59, 21, -43, -41, 10, -57, + -21, 0, -70, -2, -10, -84, 17, -21, -98, 36, -32, -111, + -95, 41, -12, -76, 30, -26, -57, 19, -39, -38, 9, -53, + -19, -1, -66, 0, -12, -80, 19, -23, -94, 38, -33, -107, + -92, 40, -7, -73, 29, -21, -54, 18, -35, -35, 7, -48, + -16, -3, -62, 3, -13, -75, 22, -24, -89, 41, -35, -102, + -90, 38, -3, -71, 27, -17, -52, 17, -31, -33, 6, -44, + -14, -4, -58, 5, -15, -71, 24, -25, -85, 43, -36, -98, + -88, 37, 0, -68, 26, -13, -49, 15, -27, -31, 5, -40, + -11, -5, -54, 7, -16, -67, 27, -27, -81, 46, -37, -94, + -85, 35, 4, -66, 25, -9, -47, 14, -23, -28, 3, -36, + -9, -7, -50, 10, -17, -63, 29, -28, -77, 48, -39, -90, + -83, 34, 8, -63, 23, -5, -44, 12, -18, -26, 2, -32, + -6, -8, -45, 13, -19, -59, 32, -30, -73, 51, -40, -86, + -80, 33, 12, -61, 22, -1, -42, 11, -14, -23, 0, -28, + -4, -9, -41, 15, -20, -55, 34, -31, -69, 53, -42, -82, + -78, 31, 16, -58, 20, 2, -40, 10, -10, -21, 0, -24, + -1, -11, -37, 17, -21, -51, 37, -32, -65, 56, -43, -78, + -75, 30, 20, -56, 19, 6, -37, 8, -6, -18, -1, -20, + 1, -12, -33, 20, -23, -47, 39, -34, -61, 58, -44, -74, + -73, 29, 24, -54, 18, 10, -35, 7, -2, -16, -3, -16, + 3, -14, -29, 22, -24, -43, 42, -35, -57, 60, -46, -70, + -70, 27, 29, -51, 16, 15, -32, 5, 1, -13, -4, -11, + 6, -15, -25, 25, -26, -38, 44, -37, -52, 63, -47, -65, + -68, 26, 33, -49, 15, 19, -30, 4, 5, -11, -5, -7, + 8, -16, -21, 27, -27, -34, 47, -38, -48, 65, -49, -61, + -65, 24, 37, -46, 13, 23, -27, 3, 9, -9, -7, -3, + 11, -18, -17, 30, -28, -30, 49, -39, -44, 68, -50, -57, + -63, 23, 41, -44, 12, 27, -25, 1, 13, -6, -8, 0, + 13, -19, -13, 32, -30, -26, 51, -41, -40, 70, -51, -53, + -60, 21, 45, -41, 11, 31, -22, 0, 18, -3, -10, 4, + 16, -21, -8, 35, -31, -22, 54, -42, -36, 73, -53, -49, + -58, 20, 49, -39, 9, 35, -20, 0, 22, -1, -11, 8, + 18, -22, -4, 37, -33, -18, 56, -43, -32, 75, -54, -45, + -56, 19, 53, -36, 8, 39, -17, -2, 26, 1, -12, 12, + 21, -23, 0, 39, -34, -14, 59, -45, -28, 78, -55, -41, + -53, 17, 57, -34, 6, 43, -15, -3, 30, 4, -14, 16, + 23, -25, 3, 42, -35, -10, 61, -46, -24, 80, -57, -37, + -51, 16, 62, -31, 5, 48, -12, -5, 34, 6, -15, 21, + 26, -26, 7, 45, -37, -5, 64, -48, -19, 83, -58, -32, + -48, 15, 66, -29, 4, 52, -10, -6, 38, 9, -17, 25, + 28, -28, 11, 47, -38, -1, 66, -49, -15, 85, -60, -28, + -46, 13, 70, -26, 2, 56, -8, -7, 42, 11, -18, 29, + 31, -29, 15, 49, -39, 2, 69, -50, -11, 88, -61, -24, + -43, 12, 74, -24, 1, 60, -5, -9, 46, 14, -19, 33, + 33, -30, 19, 52, -41, 6, 71, -52, -7, 90, -62, -20, + -41, 10, 78, -22, 0, 64, -3, -10, 50, 16, -21, 37, + 35, -32, 23, 54, -42, 10, 74, -53, -3, 92, -64, -16, + -38, 9, 82, -19, -1, 68, 0, -12, 55, 19, -22, 41, + 38, -33, 28, 57, -44, 14, 76, -55, 0, 95, -65, -12, + -36, 8, 86, -17, -2, 72, 2, -13, 59, 21, -24, 45, + 40, -34, 32, 59, -45, 18, 79, -56, 4, 97, -67, -8, + -33, 6, 90, -14, -4, 76, 5, -14, 63, 23, -25, 49, + 43, -36, 36, 62, -46, 22, 81, -57, 8, 100, -68, -4, + -31, 5, 94, -12, -5, 80, 7, -16, 67, 26, -26, 53, + 45, -37, 40, 64, -48, 26, 83, -59, 12, 102, -69, 0, + -28, 3, 99, -9, -7, 85, 10, -17, 71, 29, -28, 58, + 48, -39, 44, 67, -49, 31, 86, -60, 17, 105, -71, 4, + -26, 2, 103, -7, -8, 89, 12, -18, 75, 31, -29, 62, + 50, -40, 48, 69, -51, 35, 88, -62, 21, 107, -72, 8, + -24, 1, 107, -4, -9, 93, 15, -20, 79, 33, -30, 66, + 53, -41, 52, 71, -52, 39, 91, -63, 25, 110, -74, 12, + -99, 48, -21, -80, 37, -34, -61, 26, -48, -42, 16, -61, + -23, 5, -75, -4, -5, -88, 16, -16, -102, 34, -26, -116, + -97, 46, -17, -77, 35, -30, -58, 25, -44, -40, 14, -57, + -20, 3, -71, -1, -6, -84, 18, -17, -98, 37, -28, -112, + -94, 45, -13, -75, 34, -26, -56, 23, -40, -37, 13, -53, + -18, 2, -67, 1, -8, -80, 20, -19, -94, 39, -29, -108, + -91, 44, -8, -72, 33, -22, -53, 22, -35, -35, 11, -49, + -15, 0, -63, 4, -9, -76, 23, -20, -90, 42, -31, -103, + -89, 42, -4, -70, 31, -18, -51, 21, -31, -32, 10, -45, + -13, 0, -59, 6, -11, -72, 25, -21, -86, 44, -32, -99, + -87, 41, 0, -67, 30, -14, -49, 19, -27, -30, 9, -41, + -10, -1, -55, 8, -12, -68, 28, -23, -82, 47, -33, -95, + -84, 39, 3, -65, 29, -10, -46, 18, -23, -27, 7, -37, + -8, -3, -51, 11, -13, -64, 30, -24, -78, 49, -35, -91, + -82, 38, 7, -62, 27, -5, -43, 16, -19, -25, 6, -32, + -5, -4, -46, 13, -15, -59, 33, -26, -73, 52, -36, -87, + -79, 37, 11, -60, 26, -1, -41, 15, -15, -22, 4, -28, + -3, -5, -42, 16, -16, -55, 35, -27, -69, 54, -38, -83, + -77, 35, 15, -57, 24, 2, -39, 14, -11, -20, 3, -24, + -1, -7, -38, 18, -17, -51, 38, -28, -65, 56, -39, -79, + -74, 34, 19, -55, 23, 6, -36, 12, -7, -17, 2, -20, + 2, -8, -34, 21, -19, -47, 40, -30, -61, 59, -40, -75, + -72, 33, 23, -53, 22, 10, -34, 11, -3, -15, 0, -16, + 4, -10, -30, 23, -20, -43, 42, -31, -57, 61, -42, -71, + -69, 31, 28, -50, 20, 14, -31, 9, 1, -12, 0, -12, + 7, -11, -26, 26, -22, -39, 45, -33, -53, 64, -43, -66, + -67, 30, 32, -48, 19, 18, -29, 8, 5, -10, -1, -8, + 9, -12, -22, 28, -23, -35, 48, -34, -49, 66, -45, -62, + -65, 28, 36, -45, 17, 22, -26, 7, 9, -8, -3, -4, + 12, -14, -18, 31, -24, -31, 50, -35, -45, 69, -46, -58, + -62, 27, 40, -43, 16, 26, -24, 5, 13, -5, -4, 0, + 14, -15, -14, 33, -26, -27, 52, -37, -41, 71, -47, -54, + -59, 25, 44, -40, 15, 31, -21, 4, 17, -3, -6, 4, + 17, -17, -9, 36, -27, -22, 55, -38, -36, 74, -49, -50, + -57, 24, 48, -38, 13, 35, -19, 3, 21, 0, -7, 8, + 19, -18, -5, 38, -29, -18, 57, -39, -32, 76, -50, -46, + -55, 23, 52, -35, 12, 39, -17, 1, 25, 2, -8, 12, + 22, -19, -1, 40, -30, -14, 60, -41, -28, 79, -51, -42, + -52, 21, 56, -33, 10, 43, -14, 0, 29, 5, -10, 16, + 24, -21, 2, 43, -31, -10, 62, -42, -24, 81, -53, -38, + -50, 20, 61, -30, 9, 47, -11, -1, 34, 7, -11, 20, + 27, -22, 6, 45, -33, -6, 65, -44, -20, 84, -54, -33, + -47, 19, 65, -28, 8, 51, -9, -2, 38, 10, -13, 24, + 29, -24, 10, 48, -34, -2, 67, -45, -16, 86, -56, -29, + -45, 17, 69, -25, 6, 55, -7, -3, 42, 12, -14, 28, + 31, -25, 14, 50, -35, 1, 70, -46, -12, 88, -57, -25, + -42, 16, 73, -23, 5, 59, -4, -5, 46, 14, -15, 32, + 34, -26, 18, 53, -37, 5, 72, -48, -8, 91, -58, -21, + -40, 14, 77, -21, 4, 63, -2, -6, 50, 17, -17, 36, + 36, -28, 22, 55, -38, 9, 74, -49, -4, 93, -60, -17, + -37, 13, 81, -18, 2, 68, 1, -8, 54, 20, -18, 41, + 39, -29, 27, 58, -40, 14, 77, -51, 0, 96, -61, -13, + -35, 12, 85, -16, 1, 72, 3, -9, 58, 22, -20, 45, + 41, -30, 31, 60, -41, 18, 79, -52, 4, 98, -63, -9, + -33, 10, 89, -13, 0, 76, 6, -10, 62, 24, -21, 49, + 44, -32, 35, 63, -42, 22, 82, -53, 8, 101, -64, -5, + -30, 9, 93, -11, -1, 80, 8, -12, 66, 27, -22, 53, + 46, -33, 39, 65, -44, 26, 84, -55, 12, 103, -65, -1, + -27, 7, 98, -8, -3, 84, 11, -13, 71, 29, -24, 57, + 49, -35, 43, 68, -45, 30, 87, -56, 16, 106, -67, 3, + -25, 6, 102, -6, -4, 88, 13, -14, 75, 32, -25, 61, + 51, -36, 47, 70, -47, 34, 89, -58, 20, 108, -68, 7, + -23, 5, 106, -3, -5, 92, 15, -16, 79, 34, -26, 65, + 54, -37, 51, 72, -48, 38, 92, -59, 24, 111, -70, 11, + -98, 52, -21, -79, 41, -35, -60, 30, -48, -41, 20, -62, + -22, 9, -76, -3, -1, -89, 16, -12, -103, 35, -22, -116, + -96, 50, -17, -76, 39, -31, -57, 29, -44, -39, 18, -58, + -19, 7, -72, -1, -2, -85, 19, -13, -99, 38, -24, -112, + -93, 49, -13, -74, 38, -27, -55, 27, -40, -36, 17, -54, + -17, 6, -68, 2, -4, -81, 21, -15, -95, 40, -25, -108, + -91, 48, -9, -71, 37, -23, -52, 26, -36, -34, 15, -49, + -14, 4, -63, 5, -5, -77, 24, -16, -90, 43, -27, -104, + -88, 46, -5, -69, 35, -19, -50, 25, -32, -31, 14, -45, + -12, 3, -59, 7, -7, -73, 26, -17, -86, 45, -28, -100, + -86, 45, -1, -66, 34, -15, -48, 23, -28, -29, 13, -41, + -9, 2, -55, 9, -8, -69, 29, -19, -82, 47, -29, -96, + -83, 43, 2, -64, 33, -11, -45, 22, -24, -26, 11, -37, + -7, 0, -51, 12, -9, -65, 31, -20, -78, 50, -31, -92, + -81, 42, 7, -61, 31, -6, -43, 20, -19, -24, 10, -33, + -4, 0, -47, 14, -11, -60, 34, -22, -74, 53, -32, -87, + -78, 41, 11, -59, 30, -2, -40, 19, -15, -21, 8, -29, + -2, -1, -43, 17, -12, -56, 36, -23, -70, 55, -34, -83, + -76, 39, 15, -57, 28, 1, -38, 18, -11, -19, 7, -25, + 0, -3, -39, 19, -13, -52, 39, -24, -66, 57, -35, -79, + -74, 38, 19, -54, 27, 5, -35, 16, -7, -17, 6, -21, + 3, -4, -35, 22, -15, -48, 41, -26, -62, 60, -36, -75, + -71, 37, 23, -52, 26, 9, -33, 15, -3, -14, 4, -17, + 5, -6, -31, 24, -16, -44, 43, -27, -58, 62, -38, -71, + -68, 35, 27, -49, 24, 13, -30, 13, 0, -12, 3, -12, + 8, -7, -26, 27, -18, -40, 46, -29, -53, 65, -39, -67, + -66, 34, 31, -47, 23, 17, -28, 12, 4, -9, 2, -8, + 10, -8, -22, 29, -19, -36, 48, -30, -49, 67, -41, -63, + -64, 32, 35, -44, 21, 21, -26, 11, 8, -7, 0, -4, + 13, -10, -18, 31, -20, -32, 51, -31, -45, 70, -42, -59, + -61, 31, 39, -42, 20, 25, -23, 9, 12, -4, 0, 0, + 15, -11, -14, 34, -22, -28, 53, -33, -41, 72, -43, -55, + -59, 29, 44, -39, 19, 30, -20, 8, 17, -2, -2, 3, + 18, -13, -10, 37, -23, -23, 56, -34, -37, 75, -45, -50, + -56, 28, 48, -37, 17, 34, -18, 7, 21, 1, -3, 7, + 20, -14, -6, 39, -25, -19, 58, -35, -33, 77, -46, -46, + -54, 27, 52, -34, 16, 38, -16, 5, 25, 3, -4, 11, + 23, -15, -2, 41, -26, -15, 61, -37, -29, 79, -47, -42, + -51, 25, 56, -32, 14, 42, -13, 4, 29, 6, -6, 15, + 25, -17, 1, 44, -27, -11, 63, -38, -25, 82, -49, -38, + -49, 24, 60, -29, 13, 46, -11, 2, 33, 8, -7, 20, + 28, -18, 6, 46, -29, -7, 66, -40, -20, 85, -50, -34, + -46, 23, 64, -27, 12, 50, -8, 1, 37, 11, -9, 24, + 30, -20, 10, 49, -30, -3, 68, -41, -16, 87, -52, -30, + -44, 21, 68, -25, 10, 54, -6, 0, 41, 13, -10, 28, + 32, -21, 14, 51, -31, 0, 71, -42, -12, 89, -53, -26, + -42, 20, 72, -22, 9, 58, -3, -1, 45, 15, -11, 32, + 35, -22, 18, 54, -33, 4, 73, -44, -8, 92, -54, -22, + -39, 18, 76, -20, 8, 62, -1, -2, 49, 18, -13, 36, + 37, -24, 22, 56, -34, 8, 75, -45, -4, 94, -56, -18, + -36, 17, 81, -17, 6, 67, 2, -4, 54, 20, -14, 40, + 40, -25, 26, 59, -36, 13, 78, -47, 0, 97, -57, -13, + -34, 16, 85, -15, 5, 71, 4, -5, 58, 23, -16, 44, + 42, -26, 30, 61, -37, 17, 80, -48, 3, 99, -59, -9, + -32, 14, 89, -12, 3, 75, 6, -6, 62, 25, -17, 48, + 45, -28, 34, 63, -38, 21, 83, -49, 7, 102, -60, -5, + -29, 13, 93, -10, 2, 79, 9, -8, 66, 28, -18, 52, + 47, -29, 38, 66, -40, 25, 85, -51, 11, 104, -61, -1, + -27, 11, 97, -7, 0, 83, 12, -9, 70, 30, -20, 57, + 50, -31, 43, 69, -41, 29, 88, -52, 16, 107, -63, 2, + -24, 10, 101, -5, 0, 87, 14, -10, 74, 33, -21, 61, + 52, -32, 47, 71, -43, 33, 90, -54, 20, 109, -64, 6, + -22, 9, 105, -2, -1, 91, 16, -12, 78, 35, -22, 65, + 55, -33, 51, 73, -44, 37, 93, -55, 24, 111, -66, 10, + -97, 56, -22, -78, 45, -36, -59, 35, -49, -40, 24, -63, + -21, 13, -76, -2, 3, -90, 17, -7, -104, 36, -18, -117, + -95, 55, -18, -75, 44, -32, -56, 33, -45, -38, 23, -59, + -18, 12, -72, 0, 1, -86, 20, -9, -100, 39, -19, -113, + -92, 54, -14, -73, 43, -28, -54, 32, -41, -35, 21, -55, + -16, 10, -68, 3, 0, -82, 22, -10, -96, 41, -21, -109, + -90, 52, -9, -70, 41, -23, -51, 30, -37, -33, 20, -50, + -13, 9, -64, 6, -1, -77, 25, -12, -91, 44, -22, -104, + -87, 51, -5, -68, 40, -19, -49, 29, -33, -30, 19, -46, + -11, 8, -60, 8, -2, -73, 27, -13, -87, 46, -24, -100, + -85, 49, -1, -65, 38, -15, -47, 28, -29, -28, 17, -42, + -8, 6, -56, 10, -3, -69, 30, -14, -83, 48, -25, -96, + -82, 48, 2, -63, 37, -11, -44, 26, -25, -25, 16, -38, + -6, 5, -52, 13, -5, -65, 32, -16, -79, 51, -26, -92, + -80, 46, 6, -60, 36, -7, -42, 25, -20, -23, 14, -34, + -3, 3, -47, 15, -6, -61, 35, -17, -75, 54, -28, -88, + -77, 45, 10, -58, 34, -3, -39, 24, -16, -20, 13, -30, + -1, 2, -43, 18, -8, -57, 37, -19, -71, 56, -29, -84, + -75, 44, 14, -56, 33, 0, -37, 22, -12, -18, 12, -26, + 1, 1, -39, 20, -9, -53, 40, -20, -67, 58, -30, -80, + -72, 42, 18, -53, 31, 4, -34, 21, -8, -16, 10, -22, + 4, 0, -35, 23, -10, -49, 42, -21, -63, 61, -32, -76, + -70, 41, 22, -51, 30, 8, -32, 20, -4, -13, 9, -18, + 6, -1, -31, 25, -12, -45, 44, -23, -59, 63, -33, -72, + -67, 40, 27, -48, 29, 13, -29, 18, 0, -10, 7, -13, + 9, -3, -27, 28, -13, -40, 47, -24, -54, 66, -35, -67, + -65, 38, 31, -46, 27, 17, -27, 17, 3, -8, 6, -9, + 11, -4, -23, 30, -14, -36, 49, -25, -50, 68, -36, -63, + -63, 37, 35, -43, 26, 21, -24, 15, 7, -6, 5, -5, + 14, -5, -19, 32, -16, -32, 52, -27, -46, 71, -37, -59, + -60, 35, 39, -41, 25, 25, -22, 14, 11, -3, 3, -1, + 16, -7, -15, 35, -17, -28, 54, -28, -42, 73, -39, -55, + -58, 34, 43, -38, 23, 29, -19, 12, 16, -1, 2, 2, + 19, -8, -10, 38, -19, -24, 57, -30, -38, 76, -40, -51, + -55, 33, 47, -36, 22, 33, -17, 11, 20, 2, 0, 6, + 21, -9, -6, 40, -20, -20, 59, -31, -34, 78, -42, -47, + -53, 31, 51, -33, 20, 37, -15, 10, 24, 4, 0, 10, + 24, -11, -2, 42, -21, -16, 62, -32, -30, 80, -43, -43, + -50, 30, 55, -31, 19, 41, -12, 8, 28, 7, -1, 14, + 26, -12, 1, 45, -23, -12, 64, -34, -26, 83, -44, -39, + -48, 28, 60, -28, 17, 46, -10, 7, 32, 9, -3, 19, + 29, -14, 5, 47, -24, -7, 67, -35, -21, 86, -46, -34, + -45, 27, 64, -26, 16, 50, -7, 6, 36, 12, -4, 23, + 31, -15, 9, 50, -26, -3, 69, -37, -17, 88, -47, -30, + -43, 26, 68, -24, 15, 54, -5, 4, 40, 14, -5, 27, + 33, -16, 13, 52, -27, 0, 72, -38, -13, 90, -49, -26, + -41, 24, 72, -21, 13, 58, -2, 3, 44, 16, -7, 31, + 36, -18, 17, 55, -28, 4, 74, -39, -9, 93, -50, -22, + -38, 23, 76, -19, 12, 62, 0, 1, 48, 19, -8, 35, + 38, -19, 21, 57, -30, 8, 76, -41, -5, 95, -51, -18, + -35, 21, 80, -16, 11, 66, 3, 0, 53, 22, -10, 39, + 41, -21, 26, 60, -31, 12, 79, -42, -1, 98, -53, -14, + -33, 20, 84, -14, 9, 70, 5, 0, 57, 24, -11, 43, + 43, -22, 30, 62, -33, 16, 81, -43, 2, 100, -54, -10, + -31, 19, 88, -11, 8, 74, 8, -2, 61, 26, -12, 47, + 46, -23, 34, 64, -34, 20, 84, -45, 6, 103, -55, -6, + -28, 17, 92, -9, 6, 78, 10, -3, 65, 29, -14, 51, + 48, -25, 38, 67, -35, 24, 86, -46, 10, 105, -57, -2, + -26, 16, 97, -6, 5, 83, 13, -5, 69, 31, -15, 56, + 51, -26, 42, 70, -37, 29, 89, -48, 15, 108, -58, 2, + -23, 15, 101, -4, 4, 87, 15, -6, 73, 34, -17, 60, + 53, -28, 46, 72, -38, 33, 91, -49, 19, 110, -60, 6, + -21, 13, 105, -1, 2, 91, 17, -7, 77, 36, -18, 64, + 56, -29, 50, 74, -39, 37, 94, -50, 23, 112, -61, 10, + -96, 60, -23, -77, 49, -36, -58, 39, -50, -39, 28, -63, + -20, 17, -77, -1, 7, -90, 18, -3, -104, 37, -14, -118, + -94, 59, -19, -74, 48, -32, -56, 37, -46, -37, 27, -59, + -17, 16, -73, 1, 5, -86, 21, -5, -100, 40, -15, -114, + -91, 58, -15, -72, 47, -28, -53, 36, -42, -34, 25, -55, + -15, 14, -69, 4, 4, -82, 23, -6, -96, 42, -17, -110, + -89, 56, -10, -69, 45, -24, -50, 34, -37, -32, 24, -51, + -12, 13, -65, 6, 2, -78, 26, -8, -92, 45, -18, -105, + -86, 55, -6, -67, 44, -20, -48, 33, -33, -29, 23, -47, + -10, 12, -61, 9, 1, -74, 28, -9, -88, 47, -20, -101, + -84, 53, -2, -64, 42, -16, -46, 32, -29, -27, 21, -43, + -8, 10, -57, 11, 0, -70, 31, -10, -84, 49, -21, -97, + -81, 52, 1, -62, 41, -12, -43, 30, -25, -25, 20, -39, + -5, 9, -53, 14, -1, -66, 33, -12, -80, 52, -22, -93, + -79, 50, 5, -59, 40, -7, -41, 29, -21, -22, 18, -34, + -2, 7, -48, 16, -2, -61, 36, -13, -75, 54, -24, -89, + -76, 49, 9, -57, 38, -3, -38, 28, -17, -19, 17, -30, + 0, 6, -44, 19, -4, -57, 38, -15, -71, 57, -25, -85, + -74, 48, 13, -55, 37, 0, -36, 26, -13, -17, 16, -26, + 2, 5, -40, 21, -5, -53, 40, -16, -67, 59, -26, -81, + -72, 46, 17, -52, 35, 4, -33, 25, -9, -15, 14, -22, + 5, 3, -36, 24, -6, -49, 43, -17, -63, 62, -28, -77, + -69, 45, 21, -50, 34, 8, -31, 24, -5, -12, 13, -18, + 7, 2, -32, 26, -8, -45, 45, -19, -59, 64, -29, -73, + -67, 44, 26, -47, 33, 12, -28, 22, 0, -10, 11, -14, + 10, 0, -28, 29, -9, -41, 48, -20, -55, 67, -31, -68, + -64, 42, 30, -45, 31, 16, -26, 21, 3, -7, 10, -10, + 12, 0, -24, 31, -10, -37, 50, -21, -51, 69, -32, -64, + -62, 41, 34, -42, 30, 20, -24, 19, 7, -5, 9, -6, + 15, -1, -20, 33, -12, -33, 53, -23, -47, 72, -33, -60, + -59, 39, 38, -40, 29, 24, -21, 18, 11, -2, 7, -2, + 17, -3, -16, 36, -13, -29, 55, -24, -43, 74, -35, -56, + -57, 38, 42, -37, 27, 29, -18, 16, 15, 0, 6, 2, + 20, -4, -11, 38, -15, -24, 58, -26, -38, 77, -36, -52, + -54, 37, 46, -35, 26, 33, -16, 15, 19, 3, 4, 6, + 22, -5, -7, 41, -16, -20, 60, -27, -34, 79, -38, -48, + -52, 35, 50, -32, 24, 37, -14, 14, 23, 5, 3, 10, + 24, -7, -3, 43, -17, -16, 63, -28, -30, 81, -39, -44, + -49, 34, 54, -30, 23, 41, -11, 12, 27, 7, 2, 14, + 27, -8, 0, 46, -19, -12, 65, -30, -26, 84, -40, -40, + -47, 32, 59, -27, 21, 45, -9, 11, 32, 10, 0, 18, + 30, -10, 4, 48, -20, -8, 68, -31, -22, 86, -42, -35, + -44, 31, 63, -25, 20, 49, -6, 10, 36, 13, 0, 22, + 32, -11, 8, 51, -22, -4, 70, -33, -18, 89, -43, -31, + -42, 30, 67, -23, 19, 53, -4, 8, 40, 15, -1, 26, + 34, -12, 12, 53, -23, 0, 72, -34, -14, 91, -45, -27, + -40, 28, 71, -20, 17, 57, -1, 7, 44, 17, -3, 30, + 37, -14, 16, 56, -24, 3, 75, -35, -10, 94, -46, -23, + -37, 27, 75, -18, 16, 61, 1, 5, 48, 20, -4, 34, + 39, -15, 20, 58, -26, 7, 77, -37, -6, 96, -47, -19, + -35, 25, 79, -15, 15, 66, 4, 4, 52, 22, -6, 39, + 42, -17, 25, 61, -27, 12, 80, -38, -1, 99, -49, -15, + -32, 24, 83, -13, 13, 70, 6, 3, 56, 25, -7, 43, + 44, -18, 29, 63, -29, 16, 82, -39, 2, 101, -50, -11, + -30, 23, 87, -10, 12, 74, 8, 1, 60, 27, -8, 47, + 47, -19, 33, 65, -30, 20, 85, -41, 6, 104, -51, -7, + -27, 21, 91, -8, 10, 78, 11, 0, 64, 30, -10, 51, + 49, -21, 37, 68, -31, 24, 87, -42, 10, 106, -53, -3, + -25, 20, 96, -5, 9, 82, 14, -1, 69, 32, -11, 55, + 52, -22, 41, 70, -33, 28, 90, -44, 14, 109, -54, 1, + -22, 19, 100, -3, 8, 86, 16, -2, 73, 35, -13, 59, + 54, -24, 45, 73, -34, 32, 92, -45, 18, 111, -56, 5, + -20, 17, 104, 0, 6, 90, 18, -3, 77, 37, -14, 63, + 56, -25, 49, 75, -35, 36, 95, -46, 22, 113, -57, 9, + -95, 64, -23, -76, 53, -37, -57, 43, -50, -38, 32, -64, + -19, 21, -78, 0, 11, -91, 19, 0, -105, 38, -10, -118, + -93, 63, -19, -73, 52, -33, -55, 41, -46, -36, 31, -60, + -16, 20, -74, 2, 9, -87, 22, -1, -101, 40, -11, -114, + -90, 62, -15, -71, 51, -29, -52, 40, -42, -33, 29, -56, + -14, 18, -70, 5, 8, -83, 24, -2, -97, 43, -13, -110, + -88, 60, -11, -68, 49, -25, -50, 38, -38, -31, 28, -51, + -11, 17, -65, 7, 6, -79, 27, -4, -92, 46, -14, -106, + -85, 59, -7, -66, 48, -21, -47, 37, -34, -28, 27, -47, + -9, 16, -61, 10, 5, -75, 29, -5, -88, 48, -16, -102, + -83, 57, -3, -64, 46, -17, -45, 36, -30, -26, 25, -43, + -7, 14, -57, 12, 4, -71, 32, -6, -84, 50, -17, -98, + -81, 56, 0, -61, 45, -13, -42, 34, -26, -24, 24, -39, + -4, 13, -53, 15, 2, -67, 34, -8, -80, 53, -18, -94, + -78, 54, 5, -58, 44, -8, -40, 33, -21, -21, 22, -35, + -2, 11, -49, 17, 1, -62, 37, -9, -76, 55, -20, -89, + -75, 53, 9, -56, 42, -4, -37, 32, -17, -19, 21, -31, + 1, 10, -45, 20, 0, -58, 39, -11, -72, 58, -21, -85, + -73, 52, 13, -54, 41, 0, -35, 30, -13, -16, 20, -27, + 3, 9, -41, 22, -1, -54, 41, -12, -68, 60, -22, -81, + -71, 50, 17, -51, 39, 3, -33, 29, -9, -14, 18, -23, + 6, 7, -37, 24, -2, -50, 44, -13, -64, 63, -24, -77, + -68, 49, 21, -49, 38, 7, -30, 28, -5, -11, 17, -19, + 8, 6, -33, 27, -4, -46, 46, -15, -60, 65, -25, -73, + -66, 48, 25, -46, 37, 11, -27, 26, -1, -9, 15, -14, + 11, 4, -28, 30, -5, -42, 49, -16, -55, 68, -27, -69, + -63, 46, 29, -44, 35, 15, -25, 25, 2, -6, 14, -10, + 13, 3, -24, 32, -6, -38, 51, -17, -51, 70, -28, -65, + -61, 45, 33, -41, 34, 19, -23, 23, 6, -4, 13, -6, + 16, 2, -20, 34, -8, -34, 54, -19, -47, 72, -29, -61, + -58, 43, 37, -39, 33, 23, -20, 22, 10, -1, 11, -2, + 18, 0, -16, 37, -9, -30, 56, -20, -43, 75, -31, -57, + -56, 42, 42, -36, 31, 28, -18, 20, 15, 1, 10, 1, + 21, 0, -12, 39, -11, -25, 59, -22, -39, 78, -32, -52, + -53, 41, 46, -34, 30, 32, -15, 19, 19, 4, 8, 5, + 23, -1, -8, 42, -12, -21, 61, -23, -35, 80, -34, -48, + -51, 39, 50, -32, 28, 36, -13, 18, 23, 6, 7, 9, + 25, -3, -4, 44, -13, -17, 64, -24, -31, 82, -35, -44, + -49, 38, 54, -29, 27, 40, -10, 16, 27, 8, 6, 13, + 28, -4, 0, 47, -15, -13, 66, -26, -27, 85, -36, -40, + -46, 36, 58, -26, 25, 44, -8, 15, 31, 11, 4, 18, + 30, -6, 4, 49, -16, -9, 69, -27, -22, 87, -38, -36, + -43, 35, 62, -24, 24, 48, -5, 14, 35, 13, 3, 22, + 33, -7, 8, 52, -18, -5, 71, -29, -18, 90, -39, -32, + -41, 34, 66, -22, 23, 52, -3, 12, 39, 16, 2, 26, + 35, -8, 12, 54, -19, -1, 73, -30, -14, 92, -41, -28, + -39, 32, 70, -19, 21, 56, -1, 11, 43, 18, 0, 30, + 38, -10, 16, 56, -20, 2, 76, -31, -10, 95, -42, -24, + -36, 31, 74, -17, 20, 60, 2, 9, 47, 21, 0, 34, + 40, -11, 20, 59, -22, 6, 78, -33, -6, 97, -43, -20, + -34, 29, 79, -14, 19, 65, 5, 8, 52, 23, -2, 38, + 43, -13, 24, 61, -23, 11, 81, -34, -2, 100, -45, -15, + -31, 28, 83, -12, 17, 69, 7, 7, 56, 26, -3, 42, + 45, -14, 28, 64, -25, 15, 83, -35, 1, 102, -46, -11, + -29, 27, 87, -9, 16, 73, 9, 5, 60, 28, -4, 46, + 47, -15, 32, 66, -26, 19, 86, -37, 5, 104, -47, -7, + -26, 25, 91, -7, 14, 77, 12, 4, 64, 31, -6, 50, + 50, -17, 36, 69, -27, 23, 88, -38, 9, 107, -49, -3, + -24, 24, 95, -4, 13, 81, 14, 2, 68, 33, -7, 55, + 53, -18, 41, 71, -29, 27, 91, -40, 14, 110, -50, 0, + -21, 23, 99, -2, 12, 85, 17, 1, 72, 36, -9, 59, + 55, -20, 45, 74, -30, 31, 93, -41, 18, 112, -52, 4, + -19, 21, 103, 0, 10, 89, 19, 0, 76, 38, -10, 63, + 57, -21, 49, 76, -31, 35, 96, -42, 22, 114, -53, 8, + -94, 68, -24, -75, 57, -38, -56, 47, -51, -37, 36, -65, + -18, 25, -78, 1, 15, -92, 20, 4, -106, 39, -6, -119, + -92, 67, -20, -73, 56, -34, -54, 45, -47, -35, 35, -61, + -16, 24, -74, 3, 13, -88, 23, 2, -102, 41, -7, -115, + -89, 66, -16, -70, 55, -30, -51, 44, -43, -33, 33, -57, + -13, 22, -70, 6, 12, -84, 25, 1, -98, 44, -9, -111, + -87, 64, -11, -67, 53, -25, -49, 42, -39, -30, 32, -52, + -10, 21, -66, 8, 10, -79, 28, 0, -93, 46, -10, -106, + -84, 63, -7, -65, 52, -21, -46, 41, -35, -27, 31, -48, + -8, 20, -62, 11, 9, -75, 30, -1, -89, 49, -12, -102, + -82, 61, -3, -63, 50, -17, -44, 40, -31, -25, 29, -44, + -6, 18, -58, 13, 8, -71, 32, -2, -85, 51, -13, -98, + -80, 60, 0, -60, 49, -13, -41, 38, -27, -23, 28, -40, + -3, 17, -54, 15, 6, -67, 35, -4, -81, 54, -14, -94, + -77, 58, 4, -58, 48, -9, -39, 37, -22, -20, 26, -36, + -1, 15, -49, 18, 5, -63, 38, -5, -77, 56, -16, -90, + -75, 57, 8, -55, 46, -5, -36, 36, -18, -18, 25, -32, + 2, 14, -45, 21, 3, -59, 40, -7, -73, 59, -17, -86, + -72, 56, 12, -53, 45, -1, -34, 34, -14, -15, 24, -28, + 4, 13, -41, 23, 2, -55, 42, -8, -69, 61, -18, -82, + -70, 54, 16, -50, 43, 2, -32, 33, -10, -13, 22, -24, + 7, 11, -37, 25, 1, -51, 45, -9, -65, 63, -20, -78, + -67, 53, 20, -48, 42, 6, -29, 32, -6, -10, 21, -20, + 9, 10, -33, 28, 0, -47, 47, -11, -61, 66, -21, -74, + -65, 52, 25, -45, 41, 11, -27, 30, -2, -8, 19, -15, + 12, 8, -29, 30, -1, -42, 50, -12, -56, 69, -23, -69, + -62, 50, 29, -43, 39, 15, -24, 29, 1, -5, 18, -11, + 14, 7, -25, 33, -2, -38, 52, -13, -52, 71, -24, -65, + -60, 49, 33, -41, 38, 19, -22, 27, 5, -3, 17, -7, + 16, 6, -21, 35, -4, -34, 55, -15, -48, 73, -25, -61, + -58, 47, 37, -38, 37, 23, -19, 26, 9, -1, 15, -3, + 19, 4, -17, 38, -5, -30, 57, -16, -44, 76, -27, -57, + -55, 46, 41, -35, 35, 27, -17, 24, 14, 2, 14, 0, + 21, 3, -12, 40, -7, -26, 60, -18, -40, 78, -28, -53, + -52, 45, 45, -33, 34, 31, -14, 23, 18, 5, 12, 4, + 24, 2, -8, 43, -8, -22, 62, -19, -36, 81, -30, -49, + -50, 43, 49, -31, 32, 35, -12, 22, 22, 7, 11, 8, + 26, 0, -4, 45, -9, -18, 64, -20, -32, 83, -31, -45, + -48, 42, 53, -28, 31, 39, -9, 20, 26, 9, 10, 12, + 29, 0, 0, 47, -11, -14, 67, -22, -28, 86, -32, -41, + -45, 40, 58, -26, 29, 44, -7, 19, 30, 12, 8, 17, + 31, -2, 3, 50, -12, -9, 70, -23, -23, 88, -34, -36, + -43, 39, 62, -23, 28, 48, -4, 18, 34, 14, 7, 21, + 34, -3, 7, 53, -14, -5, 72, -25, -19, 91, -35, -32, + -40, 38, 66, -21, 27, 52, -2, 16, 38, 17, 6, 25, + 36, -4, 11, 55, -15, -1, 74, -26, -15, 93, -37, -28, + -38, 36, 70, -18, 25, 56, 0, 15, 42, 19, 4, 29, + 39, -6, 15, 57, -16, 2, 77, -27, -11, 95, -38, -24, + -35, 35, 74, -16, 24, 60, 3, 13, 46, 22, 3, 33, + 41, -7, 19, 60, -18, 6, 79, -29, -7, 98, -39, -20, + -33, 33, 78, -13, 23, 64, 5, 12, 51, 24, 1, 37, + 44, -9, 24, 62, -19, 10, 82, -30, -3, 101, -41, -16, + -30, 32, 82, -11, 21, 68, 8, 11, 55, 27, 0, 41, + 46, -10, 28, 65, -21, 14, 84, -31, 0, 103, -42, -12, + -28, 31, 86, -9, 20, 72, 10, 9, 59, 29, 0, 45, + 48, -11, 32, 67, -22, 18, 87, -33, 4, 105, -43, -8, + -26, 29, 90, -6, 18, 76, 13, 8, 63, 31, -2, 49, + 51, -13, 36, 70, -23, 22, 89, -34, 8, 108, -45, -4, + -23, 28, 95, -3, 17, 81, 15, 6, 67, 34, -3, 54, + 53, -14, 40, 72, -25, 27, 92, -36, 13, 110, -46, 0, + -20, 27, 99, -1, 16, 85, 18, 5, 71, 37, -5, 58, + 56, -16, 44, 75, -26, 31, 94, -37, 17, 113, -48, 4, + -18, 25, 103, 1, 14, 89, 20, 4, 75, 39, -6, 62, + 58, -17, 48, 77, -27, 35, 96, -38, 21, 115, -49, 8, + -93, 73, -25, -74, 62, -38, -55, 51, -52, -36, 41, -65, + -17, 30, -79, 2, 19, -92, 21, 8, -106, 40, -1, -120, + -91, 71, -21, -71, 60, -34, -53, 50, -48, -34, 39, -61, + -15, 28, -75, 4, 18, -88, 24, 7, -102, 42, -3, -116, + -88, 70, -17, -69, 59, -30, -50, 48, -44, -32, 38, -57, + -12, 27, -71, 7, 16, -84, 26, 5, -98, 45, -4, -112, + -86, 69, -12, -66, 58, -26, -48, 47, -39, -29, 36, -53, + -9, 25, -67, 9, 15, -80, 29, 4, -94, 47, -6, -107, + -83, 67, -8, -64, 56, -22, -45, 46, -35, -26, 35, -49, + -7, 24, -63, 12, 13, -76, 31, 3, -90, 50, -7, -103, + -81, 66, -4, -62, 55, -18, -43, 44, -31, -24, 34, -45, + -5, 23, -59, 14, 12, -72, 33, 1, -86, 52, -8, -99, + -79, 64, 0, -59, 54, -14, -40, 43, -27, -22, 32, -41, + -2, 21, -55, 16, 11, -68, 36, 0, -82, 55, -10, -95, + -76, 63, 3, -57, 52, -9, -38, 41, -23, -19, 31, -36, + 0, 20, -50, 19, 9, -63, 39, -1, -77, 57, -11, -91, + -74, 62, 7, -54, 51, -5, -35, 40, -19, -17, 29, -32, + 3, 19, -46, 22, 8, -59, 41, -2, -73, 60, -13, -87, + -71, 60, 11, -52, 49, -1, -33, 39, -15, -14, 28, -28, + 5, 17, -42, 24, 7, -55, 43, -3, -69, 62, -14, -83, + -69, 59, 15, -49, 48, 2, -31, 37, -11, -12, 27, -24, + 8, 16, -38, 26, 5, -51, 46, -5, -65, 65, -15, -79, + -66, 58, 19, -47, 47, 6, -28, 36, -7, -9, 25, -20, + 10, 14, -34, 29, 4, -47, 48, -6, -61, 67, -17, -75, + -64, 56, 24, -44, 45, 10, -25, 34, -2, -7, 24, -16, + 13, 13, -30, 31, 2, -43, 51, -8, -57, 70, -18, -70, + -61, 55, 28, -42, 44, 14, -23, 33, 1, -4, 23, -12, + 15, 12, -26, 34, 1, -39, 53, -9, -53, 72, -20, -66, + -59, 53, 32, -39, 42, 18, -21, 32, 5, -2, 21, -8, + 17, 10, -22, 36, 0, -35, 56, -10, -49, 74, -21, -62, + -56, 52, 36, -37, 41, 22, -18, 30, 9, 0, 20, -4, + 20, 9, -18, 39, -1, -31, 58, -12, -45, 77, -22, -58, + -54, 50, 40, -34, 40, 27, -16, 29, 13, 3, 18, 0, + 23, 7, -13, 41, -2, -26, 61, -13, -40, 79, -24, -54, + -51, 49, 44, -32, 38, 31, -13, 28, 17, 6, 17, 4, + 25, 6, -9, 44, -4, -22, 63, -14, -36, 82, -25, -50, + -49, 48, 48, -30, 37, 35, -11, 26, 21, 8, 16, 8, + 27, 5, -5, 46, -5, -18, 65, -16, -32, 84, -26, -46, + -47, 46, 52, -27, 35, 39, -8, 25, 25, 10, 14, 12, + 30, 3, -1, 48, -6, -14, 68, -17, -28, 87, -28, -42, + -44, 45, 57, -25, 34, 43, -6, 23, 30, 13, 13, 16, + 32, 2, 2, 51, -8, -10, 71, -19, -24, 89, -29, -37, + -42, 44, 61, -22, 33, 47, -3, 22, 34, 15, 11, 20, + 35, 0, 6, 54, -9, -6, 73, -20, -20, 92, -31, -33, + -39, 42, 65, -20, 31, 51, -1, 21, 38, 18, 10, 24, + 37, 0, 10, 56, -10, -2, 75, -21, -16, 94, -32, -29, + -37, 41, 69, -17, 30, 55, 1, 19, 42, 20, 9, 28, + 40, -1, 14, 58, -12, 1, 78, -23, -12, 97, -33, -25, + -34, 39, 73, -15, 29, 59, 4, 18, 46, 23, 7, 32, + 42, -3, 18, 61, -13, 5, 80, -24, -8, 99, -35, -21, + -32, 38, 77, -12, 27, 64, 6, 16, 50, 25, 6, 37, + 45, -4, 23, 63, -15, 10, 83, -26, -3, 102, -36, -17, + -29, 37, 81, -10, 26, 68, 9, 15, 54, 28, 4, 41, + 47, -5, 27, 66, -16, 14, 85, -27, 0, 104, -38, -13, + -27, 35, 85, -8, 24, 72, 11, 14, 58, 30, 3, 45, + 49, -7, 31, 68, -17, 18, 88, -28, 4, 106, -39, -9, + -24, 34, 89, -5, 23, 76, 14, 12, 62, 32, 2, 49, + 52, -8, 35, 71, -19, 22, 90, -30, 8, 109, -40, -5, + -22, 32, 94, -2, 21, 80, 16, 11, 67, 35, 0, 53, + 55, -10, 39, 73, -20, 26, 93, -31, 12, 111, -42, 0, + -19, 31, 98, 0, 20, 84, 19, 10, 71, 38, 0, 57, + 57, -11, 43, 76, -22, 30, 95, -33, 16, 114, -43, 3, + -17, 30, 102, 2, 19, 88, 21, 8, 75, 40, -1, 61, + 59, -12, 47, 78, -23, 34, 97, -34, 20, 116, -45, 7, + -92, 77, -25, -73, 66, -39, -54, 55, -53, -35, 45, -66, + -16, 34, -80, 3, 23, -93, 22, 12, -107, 41, 2, -120, + -90, 75, -21, -71, 64, -35, -52, 54, -49, -33, 43, -62, + -14, 32, -76, 5, 22, -89, 25, 11, -103, 43, 0, -116, + -88, 74, -17, -68, 63, -31, -49, 52, -45, -31, 42, -58, + -11, 31, -72, 8, 20, -85, 27, 9, -99, 46, 0, -112, + -85, 73, -13, -65, 62, -27, -47, 51, -40, -28, 40, -53, + -9, 29, -67, 10, 19, -81, 30, 8, -94, 48, -2, -108, + -82, 71, -9, -63, 60, -23, -44, 50, -36, -26, 39, -49, + -6, 28, -63, 13, 17, -77, 32, 7, -90, 51, -3, -104, + -80, 70, -5, -61, 59, -19, -42, 48, -32, -23, 38, -45, + -4, 27, -59, 15, 16, -73, 34, 5, -86, 53, -4, -100, + -78, 68, -1, -58, 58, -15, -40, 47, -28, -21, 36, -41, + -1, 25, -55, 17, 15, -69, 37, 4, -82, 56, -6, -96, + -75, 67, 3, -56, 56, -10, -37, 45, -24, -18, 35, -37, + 1, 24, -51, 20, 13, -64, 39, 2, -78, 58, -7, -91, + -73, 66, 7, -53, 55, -6, -34, 44, -20, -16, 33, -33, + 4, 23, -47, 22, 12, -60, 42, 1, -74, 61, -9, -87, + -70, 64, 11, -51, 53, -2, -32, 43, -16, -13, 32, -29, + 6, 21, -43, 25, 11, -56, 44, 0, -70, 63, -10, -83, + -68, 63, 15, -48, 52, 1, -30, 41, -12, -11, 31, -25, + 8, 20, -39, 27, 9, -52, 47, -1, -66, 65, -11, -79, + -65, 62, 19, -46, 51, 5, -27, 40, -8, -8, 29, -21, + 11, 18, -35, 30, 8, -48, 49, -2, -62, 68, -13, -75, + -63, 60, 23, -43, 49, 9, -25, 38, -3, -6, 28, -16, + 14, 17, -30, 32, 6, -44, 52, -4, -57, 71, -14, -71, + -60, 59, 27, -41, 48, 13, -22, 37, 0, -3, 27, -12, + 16, 16, -26, 35, 5, -40, 54, -5, -53, 73, -16, -67, + -58, 57, 31, -39, 46, 17, -20, 36, 4, -1, 25, -8, + 18, 14, -22, 37, 4, -36, 57, -6, -49, 75, -17, -63, + -56, 56, 35, -36, 45, 21, -17, 34, 8, 1, 24, -4, + 21, 13, -18, 40, 2, -32, 59, -8, -45, 78, -18, -59, + -53, 54, 40, -34, 44, 26, -15, 33, 12, 4, 22, 0, + 23, 11, -14, 42, 1, -27, 62, -9, -41, 80, -20, -54, + -50, 53, 44, -31, 42, 30, -12, 32, 16, 6, 21, 3, + 26, 10, -10, 45, 0, -23, 64, -10, -37, 83, -21, -50, + -48, 52, 48, -29, 41, 34, -10, 30, 20, 9, 20, 7, + 28, 9, -6, 47, -1, -19, 66, -12, -33, 85, -22, -46, + -46, 50, 52, -26, 39, 38, -8, 29, 24, 11, 18, 11, + 31, 7, -2, 49, -2, -15, 69, -13, -29, 88, -24, -42, + -43, 49, 56, -24, 38, 42, -5, 27, 29, 14, 17, 16, + 33, 6, 2, 52, -4, -11, 71, -15, -24, 90, -25, -38, + -41, 48, 60, -21, 37, 46, -2, 26, 33, 16, 15, 20, + 36, 4, 6, 54, -5, -7, 74, -16, -20, 93, -27, -34, + -38, 46, 64, -19, 35, 50, 0, 25, 37, 19, 14, 24, + 38, 3, 10, 57, -6, -3, 76, -17, -16, 95, -28, -30, + -36, 45, 68, -16, 34, 54, 2, 23, 41, 21, 13, 28, + 40, 2, 14, 59, -8, 0, 79, -19, -12, 97, -29, -26, + -33, 43, 72, -14, 33, 58, 5, 22, 45, 24, 11, 32, + 43, 0, 18, 62, -9, 4, 81, -20, -8, 100, -31, -22, + -31, 42, 77, -11, 31, 63, 7, 20, 49, 26, 10, 36, + 46, 0, 22, 64, -11, 9, 84, -22, -4, 103, -32, -17, + -28, 41, 81, -9, 30, 67, 10, 19, 53, 29, 8, 40, + 48, -1, 26, 67, -12, 13, 86, -23, 0, 105, -34, -13, + -26, 39, 85, -7, 28, 71, 12, 18, 57, 31, 7, 44, + 50, -3, 30, 69, -13, 17, 89, -24, 3, 107, -35, -9, + -24, 38, 89, -4, 27, 75, 15, 16, 61, 33, 6, 48, + 53, -4, 34, 72, -15, 21, 91, -26, 7, 110, -36, -5, + -21, 36, 93, -2, 25, 79, 17, 15, 66, 36, 4, 53, + 55, -6, 39, 74, -16, 25, 94, -27, 12, 112, -38, -1, + -18, 35, 97, 1, 24, 83, 20, 14, 70, 38, 3, 57, + 58, -7, 43, 77, -18, 29, 96, -29, 16, 115, -39, 2, + -16, 34, 101, 3, 23, 87, 22, 12, 74, 41, 2, 61, + 60, -8, 47, 79, -19, 33, 98, -30, 20, 117, -41, 6, + -91, 81, -26, -72, 70, -40, -53, 59, -53, -34, 49, -67, + -15, 38, -80, 4, 27, -94, 23, 16, -108, 42, 6, -121, + -89, 79, -22, -70, 68, -36, -51, 58, -49, -32, 47, -63, + -13, 36, -76, 6, 26, -90, 25, 15, -104, 44, 4, -117, + -87, 78, -18, -67, 67, -32, -48, 56, -45, -30, 46, -59, + -10, 35, -72, 8, 24, -86, 28, 13, -100, 47, 3, -113, + -84, 77, -13, -65, 66, -27, -46, 55, -41, -27, 44, -54, + -8, 33, -68, 11, 23, -81, 31, 12, -95, 49, 1, -108, + -82, 75, -9, -62, 64, -23, -43, 54, -37, -25, 43, -50, + -5, 32, -64, 14, 21, -77, 33, 11, -91, 52, 0, -104, + -79, 74, -5, -60, 63, -19, -41, 52, -33, -22, 42, -46, + -3, 31, -60, 16, 20, -73, 35, 9, -87, 54, 0, -100, + -77, 72, -1, -57, 62, -15, -39, 51, -29, -20, 40, -42, + 0, 29, -56, 18, 19, -69, 38, 8, -83, 56, -2, -96, + -74, 71, 2, -55, 60, -11, -36, 49, -24, -17, 39, -38, + 2, 28, -51, 21, 17, -65, 40, 6, -79, 59, -3, -92, + -72, 70, 6, -52, 59, -7, -34, 48, -20, -15, 37, -34, + 5, 27, -47, 23, 16, -61, 43, 5, -75, 62, -5, -88, + -69, 68, 10, -50, 57, -3, -31, 47, -16, -12, 36, -30, + 7, 25, -43, 26, 15, -57, 45, 4, -71, 64, -6, -84, + -67, 67, 14, -48, 56, 0, -29, 45, -12, -10, 35, -26, + 9, 24, -39, 28, 13, -53, 48, 2, -67, 66, -7, -80, + -65, 66, 18, -45, 55, 4, -26, 44, -8, -8, 33, -22, + 12, 22, -35, 31, 12, -49, 50, 1, -63, 69, -9, -76, + -62, 64, 23, -42, 53, 9, -24, 42, -4, -5, 32, -17, + 14, 21, -31, 33, 10, -44, 53, 0, -58, 71, -10, -71, + -59, 63, 27, -40, 52, 13, -21, 41, 0, -2, 31, -13, + 17, 20, -27, 36, 9, -40, 55, -1, -54, 74, -12, -67, + -57, 61, 31, -38, 50, 17, -19, 40, 3, 0, 29, -9, + 19, 18, -23, 38, 8, -36, 57, -2, -50, 76, -13, -63, + -55, 60, 35, -35, 49, 21, -16, 38, 7, 2, 28, -5, + 22, 17, -19, 40, 6, -32, 60, -4, -46, 79, -14, -59, + -52, 58, 39, -33, 48, 25, -14, 37, 12, 5, 26, -1, + 24, 15, -14, 43, 5, -28, 63, -5, -42, 81, -16, -55, + -50, 57, 43, -30, 46, 29, -11, 36, 16, 7, 25, 2, + 27, 14, -10, 46, 3, -24, 65, -6, -38, 84, -17, -51, + -47, 56, 47, -28, 45, 33, -9, 34, 20, 10, 24, 6, + 29, 13, -6, 48, 2, -20, 67, -8, -34, 86, -18, -47, + -45, 54, 51, -25, 43, 37, -7, 33, 24, 12, 22, 10, + 32, 11, -2, 50, 1, -16, 70, -9, -30, 88, -20, -43, + -42, 53, 56, -23, 42, 42, -4, 31, 28, 15, 21, 15, + 34, 10, 1, 53, 0, -11, 72, -11, -25, 91, -21, -38, + -40, 52, 60, -20, 41, 46, -2, 30, 32, 17, 19, 19, + 37, 8, 5, 55, -1, -7, 75, -12, -21, 94, -23, -34, + -37, 50, 64, -18, 39, 50, 1, 29, 36, 20, 18, 23, + 39, 7, 9, 58, -2, -3, 77, -13, -17, 96, -24, -30, + -35, 49, 68, -16, 38, 54, 3, 27, 40, 22, 17, 27, + 41, 6, 13, 60, -4, 0, 80, -15, -13, 98, -25, -26, + -33, 47, 72, -13, 37, 58, 6, 26, 44, 24, 15, 31, + 44, 4, 17, 63, -5, 4, 82, -16, -9, 101, -27, -22, + -30, 46, 76, -10, 35, 62, 8, 24, 49, 27, 14, 35, + 46, 3, 22, 65, -7, 8, 85, -18, -5, 103, -28, -18, + -27, 45, 80, -8, 34, 66, 11, 23, 53, 29, 12, 39, + 49, 2, 26, 68, -8, 12, 87, -19, -1, 106, -30, -14, + -25, 43, 84, -6, 32, 70, 13, 22, 57, 32, 11, 43, + 51, 0, 30, 70, -9, 16, 89, -20, 2, 108, -31, -10, + -23, 42, 88, -3, 31, 74, 15, 20, 61, 34, 10, 47, + 54, 0, 34, 72, -11, 20, 92, -22, 6, 111, -32, -6, + -20, 40, 93, -1, 29, 79, 18, 19, 65, 37, 8, 52, + 56, -2, 38, 75, -12, 25, 94, -23, 11, 113, -34, -1, + -18, 39, 97, 2, 28, 83, 21, 18, 69, 39, 7, 56, + 59, -3, 42, 78, -14, 29, 97, -25, 15, 116, -35, 2, + -15, 38, 101, 4, 27, 87, 23, 16, 73, 42, 6, 60, + 61, -4, 46, 80, -15, 33, 99, -26, 19, 118, -37, 6, + -91, 85, -27, -71, 74, -40, -52, 63, -54, -34, 53, -67, + -14, 42, -81, 5, 31, -94, 24, 20, -108, 43, 10, -122, + -88, 83, -23, -69, 72, -36, -50, 62, -50, -31, 51, -63, + -12, 40, -77, 7, 30, -90, 26, 19, -104, 45, 8, -118, + -86, 82, -19, -66, 71, -32, -48, 60, -46, -29, 50, -59, + -9, 39, -73, 9, 28, -86, 29, 17, -100, 48, 7, -114, + -83, 81, -14, -64, 70, -28, -45, 59, -41, -26, 48, -55, + -7, 37, -69, 12, 27, -82, 31, 16, -96, 50, 5, -109, + -81, 79, -10, -61, 68, -24, -42, 58, -37, -24, 47, -51, + -4, 36, -65, 14, 25, -78, 34, 15, -92, 53, 4, -105, + -78, 78, -6, -59, 67, -20, -40, 56, -33, -21, 46, -47, + -2, 35, -61, 17, 24, -74, 36, 13, -88, 55, 3, -101, + -76, 76, -2, -56, 66, -16, -38, 55, -29, -19, 44, -43, + 0, 33, -57, 19, 23, -70, 39, 12, -84, 57, 1, -97, + -73, 75, 1, -54, 64, -11, -35, 53, -25, -16, 43, -38, + 3, 32, -52, 22, 21, -65, 41, 10, -79, 60, 0, -93, + -71, 74, 5, -51, 63, -7, -33, 52, -21, -14, 41, -34, + 6, 31, -48, 24, 20, -61, 44, 9, -75, 62, -1, -89, + -68, 72, 9, -49, 61, -3, -30, 51, -17, -11, 40, -30, + 8, 29, -44, 27, 19, -57, 46, 8, -71, 65, -2, -85, + -66, 71, 13, -47, 60, 0, -28, 49, -13, -9, 39, -26, + 10, 28, -40, 29, 17, -53, 48, 6, -67, 67, -3, -81, + -64, 70, 17, -44, 59, 4, -25, 48, -9, -7, 37, -22, + 13, 26, -36, 31, 16, -49, 51, 5, -63, 70, -5, -77, + -61, 68, 22, -42, 57, 8, -23, 46, -4, -4, 36, -18, + 15, 25, -32, 34, 14, -45, 54, 3, -59, 72, -6, -72, + -59, 67, 26, -39, 56, 12, -20, 45, 0, -2, 35, -14, + 18, 24, -28, 37, 13, -41, 56, 2, -55, 75, -8, -68, + -56, 65, 30, -37, 54, 16, -18, 44, 3, 1, 33, -10, + 20, 22, -24, 39, 12, -37, 58, 1, -51, 77, -9, -64, + -54, 64, 34, -34, 53, 20, -16, 42, 7, 3, 32, -6, + 23, 21, -20, 41, 10, -33, 61, 0, -47, 80, -10, -60, + -51, 62, 38, -32, 52, 25, -13, 41, 11, 6, 30, -1, + 25, 19, -15, 44, 9, -28, 63, -1, -42, 82, -12, -56, + -49, 61, 42, -29, 50, 29, -11, 40, 15, 8, 29, 2, + 28, 18, -11, 46, 7, -24, 66, -2, -38, 85, -13, -52, + -46, 60, 46, -27, 49, 33, -8, 38, 19, 11, 28, 6, + 30, 17, -7, 49, 6, -20, 68, -4, -34, 87, -14, -48, + -44, 58, 50, -25, 47, 37, -6, 37, 23, 13, 26, 10, + 32, 15, -3, 51, 5, -16, 71, -5, -30, 89, -16, -44, + -41, 57, 55, -22, 46, 41, -3, 35, 28, 16, 25, 14, + 35, 14, 0, 54, 3, -12, 73, -7, -26, 92, -17, -39, + -39, 56, 59, -19, 45, 45, -1, 34, 32, 18, 23, 18, + 38, 12, 4, 56, 2, -8, 76, -8, -22, 94, -19, -35, + -36, 54, 63, -17, 43, 49, 2, 33, 36, 21, 22, 22, + 40, 11, 8, 59, 1, -4, 78, -9, -18, 97, -20, -31, + -34, 53, 67, -15, 42, 53, 4, 31, 40, 23, 21, 26, + 42, 10, 12, 61, 0, 0, 80, -11, -14, 99, -21, -27, + -32, 51, 71, -12, 41, 57, 7, 30, 44, 25, 19, 30, + 45, 8, 16, 63, -1, 3, 83, -12, -10, 102, -23, -23, + -29, 50, 75, -10, 39, 62, 9, 28, 48, 28, 18, 35, + 47, 7, 21, 66, -3, 8, 86, -14, -5, 104, -24, -19, + -27, 49, 79, -7, 38, 66, 12, 27, 52, 30, 16, 39, + 50, 6, 25, 69, -4, 12, 88, -15, -1, 107, -26, -15, + -24, 47, 83, -5, 36, 70, 14, 26, 56, 33, 15, 43, + 52, 4, 29, 71, -5, 16, 90, -16, 2, 109, -27, -11, + -22, 46, 87, -2, 35, 74, 16, 24, 60, 35, 14, 47, + 55, 3, 33, 73, -7, 20, 93, -18, 6, 112, -28, -7, + -19, 44, 92, 0, 33, 78, 19, 23, 65, 38, 12, 51, + 57, 1, 37, 76, -8, 24, 95, -19, 10, 114, -30, -2, + -17, 43, 96, 3, 32, 82, 21, 22, 69, 40, 11, 55, + 60, 0, 41, 78, -10, 28, 98, -21, 14, 117, -31, 1, + -14, 42, 100, 5, 31, 86, 24, 20, 73, 43, 10, 59, + 62, 0, 45, 81, -11, 32, 100, -22, 18, 119, -33, 5, + -90, 89, -27, -70, 78, -41, -51, 67, -54, -33, 57, -68, + -13, 46, -82, 5, 35, -95, 25, 24, -109, 44, 14, -122, + -87, 87, -23, -68, 76, -37, -49, 66, -50, -30, 55, -64, + -11, 44, -78, 8, 34, -91, 27, 23, -105, 46, 12, -118, + -85, 86, -19, -65, 75, -33, -47, 64, -46, -28, 54, -60, + -9, 43, -74, 10, 32, -87, 30, 21, -101, 48, 11, -114, + -82, 85, -15, -63, 74, -29, -44, 63, -42, -25, 52, -55, + -6, 41, -69, 13, 31, -83, 32, 20, -96, 51, 9, -110, + -80, 83, -11, -60, 72, -25, -42, 62, -38, -23, 51, -51, + -3, 40, -65, 15, 29, -79, 35, 19, -92, 54, 8, -106, + -77, 82, -7, -58, 71, -21, -39, 60, -34, -20, 50, -47, + -1, 39, -61, 18, 28, -75, 37, 17, -88, 56, 7, -102, + -75, 80, -3, -56, 70, -17, -37, 59, -30, -18, 48, -43, + 1, 37, -57, 20, 27, -71, 40, 16, -84, 58, 5, -98, + -72, 79, 1, -53, 68, -12, -34, 57, -25, -15, 47, -39, + 4, 36, -53, 23, 25, -66, 42, 14, -80, 61, 4, -93, + -70, 78, 5, -51, 67, -8, -32, 56, -21, -13, 45, -35, + 6, 35, -49, 25, 24, -62, 45, 13, -76, 63, 2, -89, + -67, 76, 9, -48, 65, -4, -29, 55, -17, -11, 44, -31, + 9, 33, -45, 28, 23, -58, 47, 12, -72, 66, 1, -85, + -65, 75, 13, -46, 64, 0, -27, 53, -13, -8, 43, -27, + 11, 32, -41, 30, 21, -54, 49, 10, -68, 68, 0, -81, + -63, 74, 17, -43, 63, 3, -25, 52, -9, -6, 41, -23, + 14, 30, -37, 32, 20, -50, 52, 9, -64, 71, -1, -77, + -60, 72, 21, -41, 61, 7, -22, 50, -5, -3, 40, -18, + 16, 29, -32, 35, 18, -46, 54, 7, -59, 73, -2, -73, + -58, 71, 25, -38, 60, 11, -19, 49, -1, -1, 39, -14, + 19, 28, -28, 37, 17, -42, 57, 6, -55, 76, -4, -69, + -55, 69, 29, -36, 58, 15, -17, 48, 2, 2, 37, -10, + 21, 26, -24, 40, 16, -38, 59, 5, -51, 78, -5, -65, + -53, 68, 33, -33, 57, 19, -15, 46, 6, 4, 36, -6, + 23, 25, -20, 42, 14, -34, 62, 3, -47, 80, -6, -61, + -50, 66, 38, -31, 56, 24, -12, 45, 11, 7, 34, -2, + 26, 23, -16, 45, 13, -29, 64, 2, -43, 83, -8, -56, + -48, 65, 42, -28, 54, 28, -10, 44, 15, 9, 33, 1, + 29, 22, -12, 47, 11, -25, 67, 1, -39, 86, -9, -52, + -45, 64, 46, -26, 53, 32, -7, 42, 19, 12, 32, 5, + 31, 21, -8, 50, 10, -21, 69, 0, -35, 88, -10, -48, + -43, 62, 50, -24, 51, 36, -5, 41, 23, 14, 30, 9, + 33, 19, -4, 52, 9, -17, 72, -1, -31, 90, -12, -44, + -40, 61, 54, -21, 50, 40, -2, 39, 27, 17, 29, 14, + 36, 18, 0, 55, 7, -13, 74, -3, -26, 93, -13, -40, + -38, 60, 58, -19, 49, 44, 0, 38, 31, 19, 27, 18, + 38, 16, 4, 57, 6, -9, 77, -4, -22, 95, -15, -36, + -35, 58, 62, -16, 47, 48, 3, 37, 35, 21, 26, 22, + 41, 15, 8, 60, 5, -5, 79, -5, -18, 98, -16, -32, + -33, 57, 66, -14, 46, 52, 5, 35, 39, 24, 25, 26, + 43, 14, 12, 62, 3, -1, 81, -7, -14, 100, -17, -28, + -31, 55, 70, -11, 45, 56, 7, 34, 43, 26, 23, 30, + 46, 12, 16, 64, 2, 2, 84, -8, -10, 103, -19, -24, + -28, 54, 75, -9, 43, 61, 10, 32, 48, 29, 22, 34, + 48, 11, 20, 67, 0, 7, 86, -10, -6, 105, -20, -19, + -26, 53, 79, -6, 42, 65, 13, 31, 52, 31, 20, 38, + 51, 10, 24, 69, 0, 11, 89, -11, -2, 108, -22, -15, + -23, 51, 83, -4, 40, 69, 15, 30, 56, 34, 19, 42, + 53, 8, 28, 72, -1, 15, 91, -12, 1, 110, -23, -11, + -21, 50, 87, -1, 39, 73, 17, 28, 60, 36, 18, 46, + 55, 7, 32, 74, -3, 19, 94, -14, 5, 112, -24, -7, + -18, 48, 91, 1, 37, 77, 20, 27, 64, 39, 16, 51, + 58, 5, 37, 77, -4, 23, 96, -15, 10, 115, -26, -3, + -16, 47, 95, 4, 36, 81, 22, 26, 68, 41, 15, 55, + 61, 4, 41, 79, -6, 27, 99, -17, 14, 117, -27, 0, + -13, 46, 99, 6, 35, 85, 25, 24, 72, 44, 14, 59, + 63, 3, 45, 82, -7, 31, 101, -18, 18, 120, -29, 4, + -89, 93, -28, -69, 82, -42, -50, 72, -55, -32, 61, -69, + -12, 50, -82, 7, 40, -96, 26, 29, -110, 45, 18, -123, + -86, 92, -24, -67, 81, -38, -48, 70, -51, -29, 60, -65, + -10, 49, -78, 9, 38, -92, 28, 27, -106, 47, 17, -119, + -84, 91, -20, -64, 80, -34, -46, 69, -47, -27, 58, -61, + -7, 47, -74, 11, 37, -88, 31, 26, -102, 49, 15, -115, + -81, 89, -15, -62, 78, -29, -43, 67, -43, -24, 57, -56, + -5, 46, -70, 14, 35, -83, 33, 24, -97, 52, 14, -111, + -79, 88, -11, -59, 77, -25, -41, 66, -39, -22, 56, -52, + -2, 45, -66, 16, 34, -79, 36, 23, -93, 55, 12, -107, + -76, 86, -7, -57, 75, -21, -38, 65, -35, -19, 54, -48, + 0, 43, -62, 19, 33, -75, 38, 22, -89, 57, 11, -103, + -74, 85, -3, -55, 74, -17, -36, 63, -31, -17, 53, -44, + 2, 42, -58, 21, 31, -71, 41, 20, -85, 59, 10, -99, + -71, 83, 0, -52, 73, -13, -33, 62, -26, -14, 51, -40, + 5, 40, -53, 24, 30, -67, 43, 19, -81, 62, 8, -94, + -69, 82, 4, -49, 71, -9, -31, 61, -22, -12, 50, -36, + 7, 39, -49, 26, 28, -63, 46, 17, -77, 64, 7, -90, + -66, 81, 8, -47, 70, -5, -28, 59, -18, -10, 49, -32, + 10, 38, -45, 29, 27, -59, 48, 16, -73, 67, 6, -86, + -64, 79, 12, -45, 68, -1, -26, 58, -14, -7, 47, -28, + 12, 36, -41, 31, 26, -55, 50, 15, -69, 69, 4, -82, + -62, 78, 16, -42, 67, 2, -24, 57, -10, -5, 46, -24, + 15, 35, -37, 33, 24, -51, 53, 13, -65, 72, 3, -78, + -59, 77, 21, -40, 66, 7, -21, 55, -6, -2, 44, -19, + 17, 33, -33, 36, 23, -46, 55, 12, -60, 74, 1, -74, + -57, 75, 25, -37, 64, 11, -18, 54, -2, 0, 43, -15, + 20, 32, -29, 39, 22, -42, 58, 11, -56, 77, 0, -70, + -54, 74, 29, -35, 63, 15, -16, 52, 1, 3, 42, -11, + 22, 31, -25, 41, 20, -38, 60, 9, -52, 79, 0, -66, + -52, 72, 33, -32, 62, 19, -14, 51, 5, 5, 40, -7, + 25, 29, -21, 43, 19, -34, 63, 8, -48, 81, -2, -62, + -49, 71, 37, -30, 60, 23, -11, 49, 10, 8, 39, -3, + 27, 28, -16, 46, 17, -30, 65, 6, -44, 84, -3, -57, + -47, 70, 41, -27, 59, 27, -9, 48, 14, 10, 37, 0, + 30, 27, -12, 48, 16, -26, 68, 5, -40, 87, -5, -53, + -44, 68, 45, -25, 57, 31, -6, 47, 18, 13, 36, 4, + 32, 25, -8, 51, 15, -22, 70, 4, -36, 89, -6, -49, + -42, 67, 49, -23, 56, 35, -4, 45, 22, 15, 35, 8, + 34, 24, -4, 53, 13, -18, 73, 2, -32, 91, -7, -45, + -39, 65, 54, -20, 54, 40, -1, 44, 26, 18, 33, 13, + 37, 22, 0, 56, 12, -13, 75, 1, -27, 94, -9, -41, + -37, 64, 58, -17, 53, 44, 1, 43, 30, 20, 32, 17, + 39, 21, 3, 58, 10, -9, 78, 0, -23, 96, -10, -37, + -34, 63, 62, -15, 52, 48, 4, 41, 34, 22, 31, 21, + 42, 20, 7, 61, 9, -5, 80, -1, -19, 99, -12, -33, + -32, 61, 66, -13, 50, 52, 6, 40, 38, 25, 29, 25, + 44, 18, 11, 63, 8, -1, 82, -2, -15, 101, -13, -29, + -30, 60, 70, -10, 49, 56, 8, 38, 42, 27, 28, 29, + 47, 17, 15, 65, 6, 2, 85, -4, -11, 104, -14, -25, + -27, 58, 74, -8, 48, 60, 11, 37, 47, 30, 26, 33, + 49, 15, 20, 68, 5, 6, 87, -5, -7, 106, -16, -20, + -25, 57, 78, -5, 46, 64, 14, 36, 51, 32, 25, 37, + 52, 14, 24, 71, 3, 10, 90, -6, -3, 109, -17, -16, + -22, 56, 82, -3, 45, 68, 16, 34, 55, 35, 24, 41, + 54, 13, 28, 73, 2, 14, 92, -8, 0, 111, -18, -12, + -20, 54, 86, 0, 43, 72, 18, 33, 59, 37, 22, 45, + 57, 11, 32, 75, 1, 18, 95, -9, 4, 113, -20, -8, + -17, 53, 91, 2, 42, 77, 21, 31, 63, 40, 21, 50, + 59, 10, 36, 78, 0, 23, 97, -11, 9, 116, -21, -4, + -15, 52, 95, 5, 41, 81, 23, 30, 67, 42, 19, 54, + 62, 8, 40, 80, -1, 27, 100, -12, 13, 119, -23, 0, + -12, 50, 99, 7, 39, 85, 26, 29, 71, 45, 18, 58, + 64, 7, 44, 83, -2, 31, 102, -13, 17, 121, -24, 3, + -88, 97, -29, -68, 86, -42, -50, 76, -56, -31, 65, -69, + -11, 54, -83, 7, 44, -96, 27, 33, -110, 46, 22, -124, + -85, 96, -25, -66, 85, -38, -47, 74, -52, -28, 64, -65, + -9, 53, -79, 10, 42, -92, 29, 31, -106, 48, 21, -120, + -83, 95, -21, -64, 84, -34, -45, 73, -48, -26, 62, -61, + -7, 51, -75, 12, 41, -88, 32, 30, -102, 50, 19, -116, + -80, 93, -16, -61, 82, -30, -42, 71, -43, -23, 61, -57, + -4, 50, -71, 15, 39, -84, 34, 28, -98, 53, 18, -111, + -78, 92, -12, -58, 81, -26, -40, 70, -39, -21, 60, -53, + -1, 49, -67, 17, 38, -80, 37, 27, -94, 55, 16, -107, + -75, 90, -8, -56, 79, -22, -37, 69, -35, -18, 58, -49, + 1, 47, -63, 20, 37, -76, 39, 26, -90, 58, 15, -103, + -73, 89, -4, -54, 78, -18, -35, 67, -31, -16, 57, -45, + 3, 46, -59, 22, 35, -72, 41, 24, -86, 60, 14, -99, + -70, 87, 0, -51, 77, -13, -32, 66, -27, -13, 55, -40, + 6, 44, -54, 25, 34, -67, 44, 23, -81, 63, 12, -95, + -68, 86, 3, -49, 75, -9, -30, 65, -23, -11, 54, -36, + 8, 43, -50, 27, 32, -63, 47, 21, -77, 65, 11, -91, + -66, 85, 7, -46, 74, -5, -27, 63, -19, -9, 53, -32, + 11, 42, -46, 30, 31, -59, 49, 20, -73, 68, 10, -87, + -63, 83, 11, -44, 72, -1, -25, 62, -15, -6, 51, -28, + 13, 40, -42, 32, 30, -55, 51, 19, -69, 70, 8, -83, + -61, 82, 15, -41, 71, 2, -23, 61, -11, -4, 50, -24, + 16, 39, -38, 34, 28, -51, 54, 17, -65, 72, 7, -79, + -58, 81, 20, -39, 70, 6, -20, 59, -6, -1, 48, -20, + 18, 37, -34, 37, 27, -47, 56, 16, -61, 75, 5, -74, + -56, 79, 24, -36, 68, 10, -18, 58, -2, 1, 47, -16, + 21, 36, -30, 39, 26, -43, 59, 15, -57, 78, 4, -70, + -53, 78, 28, -34, 67, 14, -15, 56, 1, 4, 46, -12, + 23, 35, -26, 42, 24, -39, 61, 13, -53, 80, 3, -66, + -51, 76, 32, -32, 66, 18, -13, 55, 5, 6, 44, -8, + 25, 33, -22, 44, 23, -35, 64, 12, -49, 82, 1, -62, + -48, 75, 36, -29, 64, 23, -10, 53, 9, 9, 43, -3, + 28, 32, -17, 47, 21, -30, 66, 10, -44, 85, 0, -58, + -46, 74, 40, -26, 63, 27, -8, 52, 13, 11, 41, 0, + 31, 31, -13, 49, 20, -26, 69, 9, -40, 87, -1, -54, + -43, 72, 44, -24, 61, 31, -5, 51, 17, 14, 40, 4, + 33, 29, -9, 52, 19, -22, 71, 8, -36, 90, -2, -50, + -41, 71, 48, -22, 60, 35, -3, 49, 21, 16, 39, 8, + 35, 28, -5, 54, 17, -18, 73, 6, -32, 92, -3, -46, + -38, 69, 53, -19, 58, 39, 0, 48, 26, 19, 37, 12, + 38, 26, -1, 57, 16, -14, 76, 5, -28, 95, -5, -41, + -36, 68, 57, -17, 57, 43, 2, 47, 30, 21, 36, 16, + 40, 25, 2, 59, 14, -10, 79, 3, -24, 97, -6, -37, + -34, 67, 61, -14, 56, 47, 5, 45, 34, 23, 35, 20, + 43, 24, 6, 62, 13, -6, 81, 2, -20, 100, -8, -33, + -31, 65, 65, -12, 54, 51, 7, 44, 38, 26, 33, 24, + 45, 22, 10, 64, 12, -2, 83, 1, -16, 102, -9, -29, + -29, 64, 69, -9, 53, 55, 9, 42, 42, 28, 32, 28, + 48, 21, 14, 66, 10, 1, 86, 0, -12, 104, -10, -25, + -26, 62, 73, -7, 52, 60, 12, 41, 46, 31, 30, 33, + 50, 19, 19, 69, 9, 6, 88, -1, -7, 107, -12, -21, + -24, 61, 77, -4, 50, 64, 14, 40, 50, 33, 29, 37, + 53, 18, 23, 71, 7, 10, 91, -2, -3, 110, -13, -17, + -21, 60, 81, -2, 49, 68, 17, 38, 54, 36, 28, 41, + 55, 17, 27, 74, 6, 14, 93, -4, 0, 112, -14, -13, + -19, 58, 85, 0, 47, 72, 19, 37, 58, 38, 26, 45, + 57, 15, 31, 76, 5, 18, 96, -5, 4, 114, -16, -9, + -16, 57, 90, 3, 46, 76, 22, 35, 63, 41, 25, 49, + 60, 14, 35, 79, 3, 22, 98, -7, 8, 117, -17, -4, + -14, 56, 94, 6, 45, 80, 24, 34, 67, 43, 23, 53, + 62, 12, 39, 81, 2, 26, 101, -8, 12, 119, -19, 0, + -11, 54, 98, 8, 43, 84, 27, 33, 71, 46, 22, 57, + 65, 11, 43, 84, 1, 30, 103, -9, 16, 122, -20, 3, + -87, 101, -29, -67, 90, -43, -49, 80, -56, -30, 69, -70, + -10, 58, -84, 8, 48, -97, 28, 37, -111, 46, 26, -124, + -84, 100, -25, -65, 89, -39, -46, 78, -52, -27, 68, -66, + -8, 57, -80, 11, 46, -93, 30, 35, -107, 49, 25, -120, + -82, 99, -21, -63, 88, -35, -44, 77, -48, -25, 66, -62, + -6, 55, -76, 13, 45, -89, 32, 34, -103, 51, 23, -116, + -79, 97, -17, -60, 86, -31, -41, 75, -44, -22, 65, -57, + -3, 54, -71, 16, 43, -85, 35, 32, -98, 54, 22, -112, + -77, 96, -13, -58, 85, -27, -39, 74, -40, -20, 64, -53, + -1, 53, -67, 18, 42, -81, 38, 31, -94, 56, 20, -108, + -74, 94, -9, -55, 83, -23, -36, 73, -36, -18, 62, -49, + 2, 51, -63, 21, 41, -77, 40, 30, -90, 59, 19, -104, + -72, 93, -5, -53, 82, -19, -34, 71, -32, -15, 61, -45, + 4, 50, -59, 23, 39, -73, 42, 28, -86, 61, 18, -100, + -69, 91, 0, -50, 81, -14, -31, 70, -27, -12, 59, -41, + 7, 48, -55, 26, 38, -68, 45, 27, -82, 64, 16, -95, + -67, 90, 3, -48, 79, -10, -29, 69, -23, -10, 58, -37, + 9, 47, -51, 28, 36, -64, 47, 25, -78, 66, 15, -91, + -65, 89, 7, -45, 78, -6, -26, 67, -19, -8, 57, -33, + 12, 46, -47, 30, 35, -60, 50, 24, -74, 69, 14, -87, + -62, 87, 11, -43, 76, -2, -24, 66, -15, -5, 55, -29, + 14, 44, -43, 33, 34, -56, 52, 23, -70, 71, 12, -83, + -60, 86, 15, -40, 75, 1, -22, 65, -11, -3, 54, -25, + 16, 43, -39, 35, 32, -52, 55, 21, -66, 73, 11, -79, + -57, 85, 19, -38, 74, 5, -19, 63, -7, 0, 52, -20, + 19, 41, -34, 38, 31, -48, 57, 20, -61, 76, 9, -75, + -55, 83, 23, -35, 72, 9, -17, 62, -3, 2, 51, -16, + 22, 40, -30, 40, 30, -44, 60, 19, -57, 78, 8, -71, + -52, 82, 27, -33, 71, 13, -14, 60, 0, 5, 50, -12, + 24, 39, -26, 43, 28, -40, 62, 17, -53, 81, 7, -67, + -50, 80, 31, -31, 70, 17, -12, 59, 4, 7, 48, -8, + 26, 37, -22, 45, 27, -36, 64, 16, -49, 83, 5, -63, + -47, 79, 36, -28, 68, 22, -9, 57, 9, 10, 47, -4, + 29, 36, -18, 48, 25, -31, 67, 14, -45, 86, 4, -58, + -45, 78, 40, -26, 67, 26, -7, 56, 13, 12, 45, 0, + 31, 35, -14, 50, 24, -27, 70, 13, -41, 88, 2, -54, + -43, 76, 44, -23, 65, 30, -4, 55, 17, 14, 44, 3, + 34, 33, -10, 53, 23, -23, 72, 12, -37, 91, 1, -50, + -40, 75, 48, -21, 64, 34, -2, 53, 21, 17, 43, 7, + 36, 32, -6, 55, 21, -19, 74, 10, -33, 93, 0, -46, + -37, 73, 52, -18, 62, 38, 1, 52, 25, 20, 41, 12, + 39, 30, -1, 58, 20, -15, 77, 9, -28, 96, -1, -42, + -35, 72, 56, -16, 61, 42, 3, 51, 29, 22, 40, 16, + 41, 29, 2, 60, 18, -11, 79, 7, -24, 98, -2, -38, + -33, 71, 60, -13, 60, 46, 6, 49, 33, 24, 39, 20, + 44, 28, 6, 62, 17, -7, 82, 6, -20, 101, -4, -34, + -30, 69, 64, -11, 58, 50, 8, 48, 37, 27, 37, 24, + 46, 26, 10, 65, 16, -3, 84, 5, -16, 103, -5, -30, + -28, 68, 68, -8, 57, 54, 10, 46, 41, 29, 36, 28, + 48, 25, 14, 67, 14, 0, 87, 3, -12, 105, -6, -26, + -25, 66, 73, -6, 56, 59, 13, 45, 46, 32, 34, 32, + 51, 23, 18, 70, 13, 5, 89, 2, -8, 108, -8, -21, + -23, 65, 77, -3, 54, 63, 15, 44, 50, 34, 33, 36, + 54, 22, 22, 72, 11, 9, 92, 1, -4, 110, -9, -17, + -20, 64, 81, -1, 53, 67, 18, 42, 54, 37, 32, 40, + 56, 21, 26, 75, 10, 13, 94, 0, 0, 113, -10, -13, + -18, 62, 85, 1, 51, 71, 20, 41, 58, 39, 30, 44, + 58, 19, 30, 77, 9, 17, 96, -1, 3, 115, -12, -9, + -15, 61, 89, 4, 50, 75, 23, 39, 62, 42, 29, 49, + 61, 18, 35, 80, 7, 21, 99, -3, 8, 118, -13, -5, + -13, 60, 93, 6, 49, 79, 25, 38, 66, 44, 27, 53, + 63, 16, 39, 82, 6, 25, 102, -4, 12, 120, -15, -1, + -11, 58, 97, 9, 47, 83, 28, 37, 70, 46, 26, 57, + 66, 15, 43, 85, 5, 29, 104, -5, 16, 123, -16, 2, + -86, 105, -30, -66, 94, -44, -48, 84, -57, -29, 73, -71, + -10, 62, -84, 9, 52, -98, 29, 41, -112, 47, 30, -125, + -83, 104, -26, -64, 93, -40, -45, 82, -53, -27, 72, -67, + -7, 61, -80, 12, 50, -94, 31, 39, -108, 50, 29, -121, + -81, 103, -22, -62, 92, -36, -43, 81, -49, -24, 70, -63, + -5, 59, -76, 14, 49, -90, 33, 38, -104, 52, 27, -117, + -78, 101, -17, -59, 90, -31, -40, 79, -45, -21, 69, -58, + -2, 58, -72, 17, 47, -85, 36, 36, -99, 55, 26, -112, + -76, 100, -13, -57, 89, -27, -38, 78, -41, -19, 68, -54, + 0, 57, -68, 19, 46, -81, 38, 35, -95, 57, 24, -108, + -74, 98, -9, -54, 87, -23, -35, 77, -37, -17, 66, -50, + 3, 55, -64, 22, 45, -77, 41, 34, -91, 60, 23, -104, + -71, 97, -5, -52, 86, -19, -33, 75, -33, -14, 65, -46, + 5, 54, -60, 24, 43, -73, 43, 32, -87, 62, 22, -100, + -69, 95, -1, -49, 85, -15, -30, 74, -28, -12, 63, -42, + 8, 52, -55, 27, 42, -69, 46, 31, -83, 65, 20, -96, + -66, 94, 2, -47, 83, -11, -28, 73, -24, -9, 62, -38, + 10, 51, -51, 29, 40, -65, 48, 29, -79, 67, 19, -92, + -64, 93, 6, -44, 82, -7, -26, 71, -20, -7, 61, -34, + 13, 50, -47, 31, 39, -61, 51, 28, -75, 70, 18, -88, + -61, 91, 10, -42, 80, -3, -23, 70, -16, -4, 59, -30, + 15, 48, -43, 34, 38, -57, 53, 27, -71, 72, 16, -84, + -59, 90, 14, -40, 79, 0, -21, 69, -12, -2, 58, -26, + 17, 47, -39, 36, 36, -53, 56, 25, -67, 74, 15, -80, + -56, 89, 19, -37, 78, 5, -18, 67, -8, 1, 56, -21, + 20, 45, -35, 39, 35, -48, 58, 24, -62, 77, 13, -75, + -54, 87, 23, -34, 76, 9, -16, 66, -4, 3, 55, -17, + 22, 44, -31, 41, 34, -44, 61, 23, -58, 79, 12, -71, + -51, 86, 27, -32, 75, 13, -13, 64, 0, 5, 54, -13, + 25, 43, -27, 44, 32, -40, 63, 21, -54, 82, 11, -67, + -49, 84, 31, -30, 74, 17, -11, 63, 3, 8, 52, -9, + 27, 41, -23, 46, 31, -36, 65, 20, -50, 84, 9, -63, + -46, 83, 35, -27, 72, 21, -8, 61, 8, 11, 51, -5, + 30, 40, -18, 49, 29, -32, 68, 18, -46, 87, 8, -59, + -44, 82, 39, -25, 71, 25, -6, 60, 12, 13, 49, -1, + 32, 39, -14, 51, 28, -28, 70, 17, -42, 89, 6, -55, + -42, 80, 43, -22, 69, 29, -3, 59, 16, 15, 48, 2, + 35, 37, -10, 54, 27, -24, 73, 16, -38, 92, 5, -51, + -39, 79, 47, -20, 68, 33, -1, 57, 20, 18, 47, 6, + 37, 36, -6, 56, 25, -20, 75, 14, -34, 94, 4, -47, + -37, 77, 52, -17, 66, 38, 2, 56, 24, 20, 45, 11, + 40, 34, -2, 59, 24, -15, 78, 13, -29, 97, 2, -42, + -34, 76, 56, -15, 65, 42, 4, 55, 28, 23, 44, 15, + 42, 33, 1, 61, 22, -11, 80, 11, -25, 99, 1, -38, + -32, 75, 60, -12, 64, 46, 6, 53, 32, 25, 43, 19, + 45, 32, 5, 63, 21, -7, 83, 10, -21, 102, 0, -34, + -29, 73, 64, -10, 62, 50, 9, 52, 36, 28, 41, 23, + 47, 30, 9, 66, 20, -3, 85, 9, -17, 104, -1, -30, + -27, 72, 68, -8, 61, 54, 11, 50, 40, 30, 40, 27, + 49, 29, 13, 68, 18, 0, 88, 7, -13, 106, -2, -26, + -24, 70, 72, -5, 60, 58, 14, 49, 45, 33, 38, 31, + 52, 27, 18, 71, 17, 4, 90, 6, -9, 109, -4, -22, + -22, 69, 76, -2, 58, 62, 16, 48, 49, 35, 37, 35, + 54, 26, 22, 73, 15, 8, 93, 5, -5, 111, -5, -18, + -19, 68, 80, 0, 57, 66, 19, 46, 53, 37, 36, 39, + 57, 25, 26, 76, 14, 12, 95, 3, -1, 114, -6, -14, + -17, 66, 84, 2, 55, 70, 21, 45, 57, 40, 34, 43, + 59, 23, 30, 78, 13, 16, 97, 2, 2, 116, -8, -10, + -14, 65, 89, 5, 54, 75, 24, 43, 61, 43, 33, 48, + 62, 22, 34, 81, 11, 21, 100, 0, 7, 119, -9, -5, + -12, 64, 93, 7, 53, 79, 26, 42, 65, 45, 31, 52, + 64, 20, 38, 83, 10, 25, 102, 0, 11, 121, -11, -1, + -10, 62, 97, 10, 51, 83, 29, 41, 69, 47, 30, 56, + 67, 19, 42, 85, 9, 29, 105, -1, 15, 124, -12, 2, + -85, 110, -31, -65, 99, -44, -47, 88, -58, -28, 78, -71, + -9, 67, -85, 10, 56, -98, 30, 45, -112, 48, 35, -126, + -82, 108, -27, -63, 97, -40, -44, 87, -54, -25, 76, -67, + -6, 65, -81, 13, 55, -94, 32, 44, -108, 51, 33, -122, + -80, 107, -23, -61, 96, -36, -42, 85, -50, -23, 75, -63, + -4, 64, -77, 15, 53, -90, 34, 42, -104, 53, 32, -118, + -77, 106, -18, -58, 95, -32, -39, 84, -45, -20, 73, -59, + -1, 62, -73, 18, 52, -86, 37, 41, -100, 56, 30, -113, + -75, 104, -14, -56, 93, -28, -37, 83, -41, -18, 72, -55, + 1, 61, -69, 20, 50, -82, 40, 40, -96, 58, 29, -109, + -73, 103, -10, -53, 92, -24, -34, 81, -37, -16, 71, -51, + 4, 60, -65, 23, 49, -78, 42, 38, -92, 61, 28, -105, + -70, 101, -6, -51, 91, -20, -32, 80, -33, -13, 69, -47, + 6, 58, -61, 25, 48, -74, 44, 37, -88, 63, 26, -101, + -67, 100, -2, -48, 89, -15, -29, 78, -29, -11, 68, -42, + 9, 57, -56, 28, 46, -69, 47, 35, -83, 66, 25, -97, + -65, 99, 1, -46, 88, -11, -27, 77, -25, -8, 66, -38, + 11, 56, -52, 30, 45, -65, 49, 34, -79, 68, 23, -93, + -63, 97, 5, -43, 86, -7, -25, 76, -21, -6, 65, -34, + 14, 54, -48, 32, 44, -61, 52, 33, -75, 71, 22, -89, + -60, 96, 9, -41, 85, -3, -22, 74, -17, -3, 64, -30, + 16, 53, -44, 35, 42, -57, 54, 31, -71, 73, 21, -85, + -58, 95, 13, -39, 84, 0, -20, 73, -13, -1, 62, -26, + 18, 51, -40, 37, 41, -53, 57, 30, -67, 75, 19, -81, + -55, 93, 18, -36, 82, 4, -17, 71, -8, 2, 61, -22, + 21, 50, -36, 40, 39, -49, 59, 28, -63, 78, 18, -76, + -53, 92, 22, -33, 81, 8, -15, 70, -4, 4, 60, -18, + 23, 49, -32, 42, 38, -45, 62, 27, -59, 80, 16, -72, + -50, 90, 26, -31, 79, 12, -12, 69, 0, 7, 58, -14, + 26, 47, -28, 45, 37, -41, 64, 26, -55, 83, 15, -68, + -48, 89, 30, -29, 78, 16, -10, 67, 3, 9, 57, -10, + 28, 46, -24, 47, 35, -37, 66, 24, -51, 85, 14, -64, + -45, 87, 34, -26, 77, 21, -7, 66, 7, 12, 55, -5, + 31, 44, -19, 50, 34, -32, 69, 23, -46, 88, 12, -60, + -43, 86, 38, -24, 75, 25, -5, 65, 11, 14, 54, -1, + 33, 43, -15, 52, 32, -28, 72, 22, -42, 90, 11, -56, + -41, 85, 42, -21, 74, 29, -2, 63, 15, 16, 53, 2, + 36, 42, -11, 55, 31, -24, 74, 20, -38, 93, 10, -52, + -38, 83, 46, -19, 72, 33, 0, 62, 19, 19, 51, 6, + 38, 40, -7, 57, 30, -20, 76, 19, -34, 95, 8, -48, + -35, 82, 51, -16, 71, 37, 3, 60, 24, 21, 50, 10, + 41, 39, -3, 60, 28, -16, 79, 17, -30, 98, 7, -43, + -33, 81, 55, -14, 70, 41, 5, 59, 28, 24, 48, 14, + 43, 37, 0, 62, 27, -12, 81, 16, -26, 100, 5, -39, + -31, 79, 59, -11, 68, 45, 7, 58, 32, 26, 47, 18, + 46, 36, 4, 64, 26, -8, 84, 15, -22, 103, 4, -35, + -28, 78, 63, -9, 67, 49, 10, 56, 36, 29, 46, 22, + 48, 35, 8, 67, 24, -4, 86, 13, -18, 105, 3, -31, + -26, 76, 67, -7, 66, 53, 12, 55, 40, 31, 44, 26, + 50, 33, 12, 69, 23, 0, 89, 12, -14, 107, 1, -27, + -23, 75, 71, -4, 64, 58, 15, 53, 44, 34, 43, 31, + 53, 32, 17, 72, 21, 4, 91, 10, -9, 110, 0, -23, + -21, 74, 75, -1, 63, 62, 17, 52, 48, 36, 41, 35, + 55, 31, 21, 74, 20, 8, 94, 9, -5, 112, -1, -19, + -18, 72, 79, 1, 61, 66, 20, 51, 52, 38, 40, 39, + 58, 29, 25, 77, 19, 12, 96, 8, -1, 115, -2, -15, + -16, 71, 83, 3, 60, 70, 22, 49, 56, 41, 39, 43, + 60, 28, 29, 79, 17, 16, 98, 6, 2, 117, -3, -11, + -13, 69, 88, 6, 58, 74, 25, 48, 61, 44, 37, 47, + 63, 26, 33, 82, 16, 20, 101, 5, 6, 120, -5, -6, + -11, 68, 92, 8, 57, 78, 27, 47, 65, 46, 36, 51, + 65, 25, 37, 84, 14, 24, 103, 3, 10, 122, -6, -2, + -9, 67, 96, 11, 56, 82, 30, 45, 69, 48, 35, 55, + 68, 24, 41, 87, 13, 28, 106, 2, 14, 125, -8, 1, + -84, 114, -31, -65, 103, -45, -46, 92, -59, -27, 82, -72, + -8, 71, -86, 11, 60, -99, 31, 49, -113, 49, 39, -126, + -82, 112, -27, -62, 101, -41, -43, 91, -55, -25, 80, -68, + -5, 69, -82, 14, 59, -95, 33, 48, -109, 52, 37, -122, + -79, 111, -23, -60, 100, -37, -41, 89, -51, -22, 79, -64, + -3, 68, -78, 16, 57, -91, 35, 46, -105, 54, 36, -118, + -76, 110, -19, -57, 99, -33, -38, 88, -46, -19, 77, -59, + 0, 66, -73, 19, 56, -87, 38, 45, -100, 57, 34, -114, + -74, 108, -15, -55, 97, -29, -36, 87, -42, -17, 76, -55, + 2, 65, -69, 21, 54, -83, 40, 44, -96, 59, 33, -110, + -72, 107, -11, -52, 96, -25, -33, 85, -38, -15, 75, -51, + 5, 64, -65, 23, 53, -79, 43, 42, -92, 62, 32, -106, + -69, 105, -7, -50, 95, -21, -31, 84, -34, -12, 73, -47, + 7, 62, -61, 26, 52, -75, 45, 41, -88, 64, 30, -102, + -67, 104, -2, -47, 93, -16, -28, 82, -30, -10, 72, -43, + 10, 61, -57, 29, 50, -70, 48, 39, -84, 67, 29, -97, + -64, 103, 1, -45, 92, -12, -26, 81, -26, -7, 70, -39, + 12, 60, -53, 31, 49, -66, 50, 38, -80, 69, 27, -93, + -62, 101, 5, -42, 90, -8, -24, 80, -22, -5, 69, -35, + 15, 58, -49, 33, 48, -62, 53, 37, -76, 71, 26, -89, + -59, 100, 9, -40, 89, -4, -21, 78, -18, -2, 68, -31, + 17, 57, -45, 36, 46, -58, 55, 35, -72, 74, 25, -85, + -57, 99, 13, -38, 88, 0, -19, 77, -14, 0, 66, -27, + 19, 55, -41, 38, 45, -54, 57, 34, -68, 76, 23, -81, + -54, 97, 17, -35, 86, 3, -16, 75, -9, 3, 65, -22, + 22, 54, -36, 41, 43, -50, 60, 32, -63, 79, 22, -77, + -52, 96, 21, -33, 85, 7, -14, 74, -5, 5, 64, -18, + 24, 53, -32, 43, 42, -46, 63, 31, -59, 81, 20, -73, + -50, 94, 25, -30, 83, 11, -11, 73, -1, 7, 62, -14, + 27, 51, -28, 46, 41, -42, 65, 30, -55, 84, 19, -69, + -47, 93, 29, -28, 82, 15, -9, 71, 2, 10, 61, -10, + 29, 50, -24, 48, 39, -38, 67, 28, -51, 86, 18, -65, + -44, 91, 34, -25, 81, 20, -6, 70, 6, 13, 59, -6, + 32, 48, -20, 51, 38, -33, 70, 27, -47, 89, 16, -60, + -42, 90, 38, -23, 79, 24, -4, 69, 10, 15, 58, -2, + 34, 47, -16, 53, 36, -29, 72, 26, -43, 91, 15, -56, + -40, 89, 42, -20, 78, 28, -1, 67, 14, 17, 57, 1, + 37, 46, -12, 55, 35, -25, 75, 24, -39, 94, 14, -52, + -37, 87, 46, -18, 76, 32, 1, 66, 18, 20, 55, 5, + 39, 44, -8, 58, 34, -21, 77, 23, -35, 96, 12, -48, + -35, 86, 50, -15, 75, 36, 4, 64, 23, 22, 54, 10, + 42, 43, -3, 61, 32, -17, 80, 21, -30, 99, 11, -44, + -32, 85, 54, -13, 74, 40, 6, 63, 27, 25, 52, 14, + 44, 41, 0, 63, 31, -13, 82, 20, -26, 101, 9, -40, + -30, 83, 58, -10, 72, 44, 8, 62, 31, 27, 51, 18, + 47, 40, 4, 65, 30, -9, 85, 19, -22, 103, 8, -36, + -27, 82, 62, -8, 71, 48, 11, 60, 35, 30, 50, 22, + 49, 39, 8, 68, 28, -5, 87, 17, -18, 106, 7, -32, + -25, 80, 66, -6, 70, 52, 13, 59, 39, 32, 48, 26, + 51, 37, 12, 70, 27, -1, 89, 16, -14, 108, 5, -28, + -22, 79, 71, -3, 68, 57, 16, 57, 43, 35, 47, 30, + 54, 36, 16, 73, 25, 3, 92, 14, -10, 111, 4, -23, + -20, 78, 75, -1, 67, 61, 18, 56, 47, 37, 45, 34, + 56, 35, 20, 75, 24, 7, 95, 13, -6, 113, 2, -19, + -18, 76, 79, 2, 65, 65, 21, 55, 51, 39, 44, 38, + 59, 33, 24, 78, 23, 11, 97, 12, -2, 116, 1, -15, + -15, 75, 83, 4, 64, 69, 23, 53, 55, 42, 43, 42, + 61, 32, 28, 80, 21, 15, 99, 10, 1, 118, 0, -11, + -12, 73, 87, 7, 62, 73, 26, 52, 60, 44, 41, 47, + 64, 30, 33, 83, 20, 19, 102, 9, 6, 121, -1, -7, + -10, 72, 91, 9, 61, 77, 28, 51, 64, 47, 40, 51, + 66, 29, 37, 85, 18, 23, 104, 7, 10, 123, -2, -3, + -8, 71, 95, 12, 60, 81, 30, 49, 68, 49, 39, 55, + 69, 28, 41, 87, 17, 27, 107, 6, 14, 126, -4, 0, + -83, 118, -32, -64, 107, -46, -45, 96, -59, -26, 86, -73, + -7, 75, -86, 12, 64, -100, 31, 53, -114, 50, 43, -127, + -81, 116, -28, -61, 105, -42, -42, 95, -55, -24, 84, -69, + -4, 73, -82, 14, 63, -96, 34, 52, -110, 53, 41, -123, + -78, 115, -24, -59, 104, -38, -40, 93, -51, -21, 83, -65, + -2, 72, -78, 17, 61, -92, 36, 50, -106, 55, 40, -119, + -76, 114, -19, -56, 103, -33, -37, 92, -47, -19, 81, -60, + 1, 70, -74, 20, 60, -87, 39, 49, -101, 58, 38, -115, + -73, 112, -15, -54, 101, -29, -35, 91, -43, -16, 80, -56, + 3, 69, -70, 22, 58, -83, 41, 48, -97, 60, 37, -111, + -71, 111, -11, -51, 100, -25, -33, 89, -39, -14, 79, -52, + 6, 68, -66, 24, 57, -79, 44, 46, -93, 63, 36, -107, + -68, 109, -7, -49, 99, -21, -30, 88, -35, -11, 77, -48, + 8, 66, -62, 27, 56, -75, 46, 45, -89, 65, 34, -103, + -66, 108, -3, -46, 97, -17, -27, 86, -30, -9, 76, -44, + 11, 65, -57, 29, 54, -71, 49, 43, -85, 68, 33, -98, + -63, 107, 0, -44, 96, -13, -25, 85, -26, -6, 74, -40, + 13, 64, -53, 32, 53, -67, 51, 42, -81, 70, 31, -94, + -61, 105, 4, -41, 94, -9, -23, 84, -22, -4, 73, -36, + 15, 62, -49, 34, 52, -63, 54, 41, -77, 72, 30, -90, + -58, 104, 8, -39, 93, -5, -20, 82, -18, -2, 72, -32, + 18, 61, -45, 37, 50, -59, 56, 39, -73, 75, 29, -86, + -56, 103, 12, -37, 92, -1, -18, 81, -14, 1, 70, -28, + 20, 59, -41, 39, 49, -55, 58, 38, -69, 77, 27, -82, + -53, 101, 17, -34, 90, 3, -15, 79, -10, 4, 69, -23, + 23, 58, -37, 42, 47, -50, 61, 36, -64, 80, 26, -78, + -51, 100, 21, -32, 89, 7, -13, 78, -6, 6, 68, -19, + 25, 57, -33, 44, 46, -46, 63, 35, -60, 82, 24, -74, + -49, 98, 25, -29, 87, 11, -10, 77, -2, 8, 66, -15, + 28, 55, -29, 46, 45, -42, 66, 34, -56, 85, 23, -70, + -46, 97, 29, -27, 86, 15, -8, 75, 1, 11, 65, -11, + 30, 54, -25, 49, 43, -38, 68, 32, -52, 87, 22, -66, + -44, 95, 33, -24, 85, 19, -5, 74, 6, 13, 63, -7, + 33, 52, -20, 52, 42, -34, 71, 31, -48, 90, 20, -61, + -41, 94, 37, -22, 83, 23, -3, 73, 10, 16, 62, -3, + 35, 51, -16, 54, 40, -30, 73, 30, -44, 92, 19, -57, + -39, 93, 41, -19, 82, 27, -1, 71, 14, 18, 61, 0, + 38, 50, -12, 56, 39, -26, 76, 28, -40, 95, 18, -53, + -36, 91, 45, -17, 80, 31, 2, 70, 18, 21, 59, 4, + 40, 48, -8, 59, 38, -22, 78, 27, -36, 97, 16, -49, + -34, 90, 50, -14, 79, 36, 4, 68, 22, 23, 58, 9, + 43, 47, -4, 61, 36, -17, 81, 25, -31, 100, 15, -45, + -31, 89, 54, -12, 78, 40, 7, 67, 26, 26, 56, 13, + 45, 45, 0, 64, 35, -13, 83, 24, -27, 102, 13, -41, + -29, 87, 58, -10, 76, 44, 9, 66, 30, 28, 55, 17, + 47, 44, 3, 66, 34, -9, 86, 23, -23, 104, 12, -37, + -26, 86, 62, -7, 75, 48, 12, 64, 34, 30, 54, 21, + 50, 43, 7, 69, 32, -5, 88, 21, -19, 107, 11, -33, + -24, 84, 66, -5, 74, 52, 14, 63, 38, 33, 52, 25, + 52, 41, 11, 71, 31, -1, 90, 20, -15, 109, 9, -28, + -21, 83, 70, -2, 72, 56, 17, 61, 43, 36, 51, 29, + 55, 40, 16, 74, 29, 2, 93, 18, -11, 112, 8, -24, + -19, 82, 74, 0, 71, 60, 19, 60, 47, 38, 49, 33, + 57, 39, 20, 76, 28, 6, 95, 17, -7, 114, 6, -20, + -17, 80, 78, 3, 69, 64, 22, 59, 51, 40, 48, 37, + 60, 37, 24, 78, 27, 10, 98, 16, -3, 117, 5, -16, + -14, 79, 82, 5, 68, 68, 24, 57, 55, 43, 47, 41, + 62, 36, 28, 81, 25, 14, 100, 14, 0, 119, 4, -12, + -12, 77, 87, 8, 66, 73, 27, 56, 59, 45, 45, 46, + 65, 34, 32, 84, 24, 19, 103, 13, 5, 122, 2, -7, + -9, 76, 91, 10, 65, 77, 29, 55, 63, 48, 44, 50, + 67, 33, 36, 86, 22, 23, 105, 11, 9, 124, 1, -3, + -7, 75, 95, 13, 64, 81, 31, 53, 67, 50, 43, 54, + 70, 32, 40, 88, 21, 27, 108, 10, 13, 127, 0, 0 +}; diff --git a/src/openmv/src/omv/img/zbar.c b/src/openmv/src/omv/img/zbar.c new file mode 100755 index 0000000..fe92d2f --- /dev/null +++ b/src/openmv/src/omv/img/zbar.c @@ -0,0 +1,8880 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include "imlib.h" +#ifdef IMLIB_ENABLE_BARCODES +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define free(ptr) ({ umm_free(ptr); }) +#define malloc(size) ({ void *_r = umm_malloc(size); if(!_r) fb_alloc_fail(); _r; }) +#define realloc(ptr, size) ({ void *_r = umm_realloc((ptr), (size)); if(!_r) fb_alloc_fail(); _r; }) +#define calloc(num, item_size) ({ void *_r = umm_calloc((num), (item_size)); if(!_r) fb_alloc_fail(); _r; }) +#define assert(expression) +#define zprintf(...) +#define dbprintf(...) while(0) +#define zassert(condition, retval, format, ...) do { if(!(condition)) return(retval); } while(0) + +#define zbar_image_write_png(...) +#define svg_open(...) +#define svg_image(...) +#define svg_group_start(...) +#define svg_path_start(...) +#define svg_path_end(...) +#define svg_group_end(...) +#define svg_close(...) + +#define NO_STATS +#define ENABLE_EAN +#define FIXME_ADDON_SYNC +#define ENABLE_I25 +#define ENABLE_DATABAR +#define ENABLE_CODABAR +#define ENABLE_CODE39 +#define ENABLE_CODE93 +#define ENABLE_CODE128 +#define ENABLE_PDF417 + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "zbar.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/** @file + * ZBar Barcode Reader C API definition + */ + +/** @mainpage + * + * interface to the barcode reader is available at several levels. + * most applications will want to use the high-level interfaces: + * + * @section high-level High-Level Interfaces + * + * these interfaces wrap all library functionality into an easy-to-use + * package for a specific toolkit: + * - the "GTK+ 2.x widget" may be used with GTK GUI applications. a + * Python wrapper is included for PyGtk + * - the @ref zbar::QZBar "Qt4 widget" may be used with Qt GUI + * applications + * - the Processor interface (in @ref c-processor "C" or @ref + * zbar::Processor "C++") adds a scanning window to an application + * with no GUI. + * + * @section mid-level Intermediate Interfaces + * + * building blocks used to construct high-level interfaces: + * - the ImageScanner (in @ref c-imagescanner "C" or @ref + * zbar::ImageScanner "C++") looks for barcodes in a library defined + * image object + * - the Window abstraction (in @ref c-window "C" or @ref + * zbar::Window "C++") sinks library images, displaying them on the + * platform display + * - the Video abstraction (in @ref c-video "C" or @ref zbar::Video + * "C++") sources library images from a video device + * + * @section low-level Low-Level Interfaces + * + * direct interaction with barcode scanning and decoding: + * - the Scanner (in @ref c-scanner "C" or @ref zbar::Scanner "C++") + * looks for barcodes in a linear intensity sample stream + * - the Decoder (in @ref c-decoder "C" or @ref zbar::Decoder "C++") + * extracts barcodes from a stream of bar and space widths + */ + +/** @name Global library interfaces */ +/*@{*/ + +/** "color" of element: bar or space. */ +typedef enum zbar_color_e { + ZBAR_SPACE = 0, /**< light area or space between bars */ + ZBAR_BAR = 1, /**< dark area or colored bar segment */ +} zbar_color_t; + +/** decoded symbol type. */ +typedef enum zbar_symbol_type_e { + ZBAR_NONE = 0, /**< no symbol decoded */ + ZBAR_PARTIAL = 1, /**< intermediate status */ + ZBAR_EAN2 = 2, /**< GS1 2-digit add-on */ + ZBAR_EAN5 = 5, /**< GS1 5-digit add-on */ + ZBAR_EAN8 = 8, /**< EAN-8 */ + ZBAR_UPCE = 9, /**< UPC-E */ + ZBAR_ISBN10 = 10, /**< ISBN-10 (from EAN-13). @since 0.4 */ + ZBAR_UPCA = 12, /**< UPC-A */ + ZBAR_EAN13 = 13, /**< EAN-13 */ + ZBAR_ISBN13 = 14, /**< ISBN-13 (from EAN-13). @since 0.4 */ + ZBAR_COMPOSITE = 15, /**< EAN/UPC composite */ + ZBAR_I25 = 25, /**< Interleaved 2 of 5. @since 0.4 */ + ZBAR_DATABAR = 34, /**< GS1 DataBar (RSS). @since 0.11 */ + ZBAR_DATABAR_EXP = 35, /**< GS1 DataBar Expanded. @since 0.11 */ + ZBAR_CODABAR = 38, /**< Codabar. @since 0.11 */ + ZBAR_CODE39 = 39, /**< Code 39. @since 0.4 */ + ZBAR_PDF417 = 57, /**< PDF417. @since 0.6 */ + ZBAR_QRCODE = 64, /**< QR Code. @since 0.10 */ + ZBAR_CODE93 = 93, /**< Code 93. @since 0.11 */ + ZBAR_CODE128 = 128, /**< Code 128 */ + + /** mask for base symbol type. + * @deprecated in 0.11, remove this from existing code + */ + ZBAR_SYMBOL = 0x00ff, + /** 2-digit add-on flag. + * @deprecated in 0.11, a ::ZBAR_EAN2 component is used for + * 2-digit GS1 add-ons + */ + ZBAR_ADDON2 = 0x0200, + /** 5-digit add-on flag. + * @deprecated in 0.11, a ::ZBAR_EAN5 component is used for + * 5-digit GS1 add-ons + */ + ZBAR_ADDON5 = 0x0500, + /** add-on flag mask. + * @deprecated in 0.11, GS1 add-ons are represented using composite + * symbols of type ::ZBAR_COMPOSITE; add-on components use ::ZBAR_EAN2 + * or ::ZBAR_EAN5 + */ + ZBAR_ADDON = 0x0700, +} zbar_symbol_type_t; + +/** decoded symbol coarse orientation. + * @since 0.11 + */ +typedef enum zbar_orientation_e { + ZBAR_ORIENT_UNKNOWN = -1, /**< unable to determine orientation */ + ZBAR_ORIENT_UP, /**< upright, read left to right */ + ZBAR_ORIENT_RIGHT, /**< sideways, read top to bottom */ + ZBAR_ORIENT_DOWN, /**< upside-down, read right to left */ + ZBAR_ORIENT_LEFT, /**< sideways, read bottom to top */ +} zbar_orientation_t; + +/** decoder configuration options. + * @since 0.4 + */ +typedef enum zbar_config_e { + ZBAR_CFG_ENABLE = 0, /**< enable symbology/feature */ + ZBAR_CFG_ADD_CHECK, /**< enable check digit when optional */ + ZBAR_CFG_EMIT_CHECK, /**< return check digit when present */ + ZBAR_CFG_ASCII, /**< enable full ASCII character set */ + ZBAR_CFG_NUM, /**< number of boolean decoder configs */ + + ZBAR_CFG_MIN_LEN = 0x20, /**< minimum data length for valid decode */ + ZBAR_CFG_MAX_LEN, /**< maximum data length for valid decode */ + + ZBAR_CFG_UNCERTAINTY = 0x40,/**< required video consistency frames */ + + ZBAR_CFG_POSITION = 0x80, /**< enable scanner to collect position data */ + + ZBAR_CFG_X_DENSITY = 0x100, /**< image scanner vertical scan density */ + ZBAR_CFG_Y_DENSITY, /**< image scanner horizontal scan density */ +} zbar_config_t; + +/** decoder symbology modifier flags. + * @since 0.11 + */ +typedef enum zbar_modifier_e { + /** barcode tagged as GS1 (EAN.UCC) reserved + * (eg, FNC1 before first data character). + * data may be parsed as a sequence of GS1 AIs + */ + ZBAR_MOD_GS1 = 0, + + /** barcode tagged as AIM reserved + * (eg, FNC1 after first character or digit pair) + */ + ZBAR_MOD_AIM, + + /** number of modifiers */ + ZBAR_MOD_NUM, +} zbar_modifier_t; + +/** retrieve string name for symbol encoding. + * @param sym symbol type encoding + * @returns the static string name for the specified symbol type, + * or "UNKNOWN" if the encoding is not recognized + */ +extern const char *zbar_get_symbol_name(zbar_symbol_type_t sym); + +/** retrieve string name for addon encoding. + * @param sym symbol type encoding + * @returns static string name for any addon, or the empty string + * if no addons were decoded + * @deprecated in 0.11 + */ +extern const char *zbar_get_addon_name(zbar_symbol_type_t sym); + +/** retrieve string name for configuration setting. + * @param config setting to name + * @returns static string name for config, + * or the empty string if value is not a known config + */ +extern const char *zbar_get_config_name(zbar_config_t config); + +/** retrieve string name for modifier. + * @param modifier flag to name + * @returns static string name for modifier, + * or the empty string if the value is not a known flag + */ +extern const char *zbar_get_modifier_name(zbar_modifier_t modifier); + +/** retrieve string name for orientation. + * @param orientation orientation encoding + * @returns the static string name for the specified orientation, + * or "UNKNOWN" if the orientation is not recognized + * @since 0.11 + */ +extern const char *zbar_get_orientation_name(zbar_orientation_t orientation); + +/** parse a configuration string of the form "[symbology.]config[=value]". + * the config must match one of the recognized names. + * the symbology, if present, must match one of the recognized names. + * if symbology is unspecified, it will be set to 0. + * if value is unspecified it will be set to 1. + * @returns 0 if the config is parsed successfully, 1 otherwise + * @since 0.4 + */ +extern int zbar_parse_config(const char *config_string, + zbar_symbol_type_t *symbology, + zbar_config_t *config, + int *value); + +/** consistently compute fourcc values across architectures + * (adapted from v4l2 specification) + * @since 0.11 + */ +#define zbar_fourcc(a, b, c, d) \ + ((unsigned long)(a) | \ + ((unsigned long)(b) << 8) | \ + ((unsigned long)(c) << 16) | \ + ((unsigned long)(d) << 24)) + +/** parse a fourcc string into its encoded integer value. + * @since 0.11 + */ +static inline unsigned long zbar_fourcc_parse (const char *format) +{ + unsigned long fourcc = 0; + if(format) { + int i; + for(i = 0; i < 4 && format[i]; i++) + fourcc |= ((unsigned long)format[i]) << (i * 8); + } + return(fourcc); +} + +/*@}*/ + +struct zbar_symbol_s; +typedef struct zbar_symbol_s zbar_symbol_t; + +struct zbar_symbol_set_s; +typedef struct zbar_symbol_set_s zbar_symbol_set_t; + + +/*------------------------------------------------------------*/ +/** @name Symbol interface + * decoded barcode symbol result object. stores type, data, and image + * location of decoded symbol. all memory is owned by the library + */ +/*@{*/ + +/** @typedef zbar_symbol_t + * opaque decoded symbol object. + */ + +/** symbol reference count manipulation. + * increment the reference count when you store a new reference to the + * symbol. decrement when the reference is no longer used. do not + * refer to the symbol once the count is decremented and the + * containing image has been recycled or destroyed. + * @note the containing image holds a reference to the symbol, so you + * only need to use this if you keep a symbol after the image has been + * destroyed or reused. + * @since 0.9 + */ +extern void zbar_symbol_ref(const zbar_symbol_t *symbol, + int refs); + +/** retrieve type of decoded symbol. + * @returns the symbol type + */ +extern zbar_symbol_type_t zbar_symbol_get_type(const zbar_symbol_t *symbol); + +/** retrieve symbology boolean config settings. + * @returns a bitmask indicating which configs were set for the detected + * symbology during decoding. + * @since 0.11 + */ +extern unsigned int zbar_symbol_get_configs(const zbar_symbol_t *symbol); + +/** retrieve symbology modifier flag settings. + * @returns a bitmask indicating which characteristics were detected + * during decoding. + * @since 0.11 + */ +extern unsigned int zbar_symbol_get_modifiers(const zbar_symbol_t *symbol); + +/** retrieve data decoded from symbol. + * @returns the data string + */ +extern const char *zbar_symbol_get_data(const zbar_symbol_t *symbol); + +/** retrieve length of binary data. + * @returns the length of the decoded data + */ +extern unsigned int zbar_symbol_get_data_length(const zbar_symbol_t *symbol); + +/** retrieve a symbol confidence metric. + * @returns an unscaled, relative quantity: larger values are better + * than smaller values, where "large" and "small" are application + * dependent. + * @note expect the exact definition of this quantity to change as the + * metric is refined. currently, only the ordered relationship + * between two values is defined and will remain stable in the future + * @since 0.9 + */ +extern int zbar_symbol_get_quality(const zbar_symbol_t *symbol); + +/** retrieve current cache count. when the cache is enabled for the + * image_scanner this provides inter-frame reliability and redundancy + * information for video streams. + * @returns < 0 if symbol is still uncertain. + * @returns 0 if symbol is newly verified. + * @returns > 0 for duplicate symbols + */ +extern int zbar_symbol_get_count(const zbar_symbol_t *symbol); + +/** retrieve the number of points in the location polygon. the + * location polygon defines the image area that the symbol was + * extracted from. + * @returns the number of points in the location polygon + * @note this is currently not a polygon, but the scan locations + * where the symbol was decoded + */ +extern unsigned zbar_symbol_get_loc_size(const zbar_symbol_t *symbol); + +/** retrieve location polygon x-coordinates. + * points are specified by 0-based index. + * @returns the x-coordinate for a point in the location polygon. + * @returns -1 if index is out of range + */ +extern int zbar_symbol_get_loc_x(const zbar_symbol_t *symbol, + unsigned index); + +/** retrieve location polygon y-coordinates. + * points are specified by 0-based index. + * @returns the y-coordinate for a point in the location polygon. + * @returns -1 if index is out of range + */ +extern int zbar_symbol_get_loc_y(const zbar_symbol_t *symbol, + unsigned index); + +/** retrieve general orientation of decoded symbol. + * @returns a coarse, axis-aligned indication of symbol orientation or + * ::ZBAR_ORIENT_UNKNOWN if unknown + * @since 0.11 + */ +extern zbar_orientation_t +zbar_symbol_get_orientation(const zbar_symbol_t *symbol); + +/** iterate the set to which this symbol belongs (there can be only one). + * @returns the next symbol in the set, or + * @returns NULL when no more results are available + */ +extern const zbar_symbol_t *zbar_symbol_next(const zbar_symbol_t *symbol); + +/** retrieve components of a composite result. + * @returns the symbol set containing the components + * @returns NULL if the symbol is already a physical symbol + * @since 0.10 + */ +extern const zbar_symbol_set_t* +zbar_symbol_get_components(const zbar_symbol_t *symbol); + +/** iterate components of a composite result. + * @returns the first physical component symbol of a composite result + * @returns NULL if the symbol is already a physical symbol + * @since 0.10 + */ +extern const zbar_symbol_t* +zbar_symbol_first_component(const zbar_symbol_t *symbol); + +/** print XML symbol element representation to user result buffer. + * @see http://zbar.sourceforge.net/2008/barcode.xsd for the schema. + * @param symbol is the symbol to print + * @param buffer is the inout result pointer, it will be reallocated + * with a larger size if necessary. + * @param buflen is inout length of the result buffer. + * @returns the buffer pointer + * @since 0.6 + */ +extern char *zbar_symbol_xml(const zbar_symbol_t *symbol, + char **buffer, + unsigned *buflen); + +/*@}*/ + +/*------------------------------------------------------------*/ +/** @name Symbol Set interface + * container for decoded result symbols associated with an image + * or a composite symbol. + * @since 0.10 + */ +/*@{*/ + +/** @typedef zbar_symbol_set_t + * opaque symbol iterator object. + * @since 0.10 + */ + +/** reference count manipulation. + * increment the reference count when you store a new reference. + * decrement when the reference is no longer used. do not refer to + * the object any longer once references have been released. + * @since 0.10 + */ +extern void zbar_symbol_set_ref(const zbar_symbol_set_t *symbols, + int refs); + +/** retrieve set size. + * @returns the number of symbols in the set. + * @since 0.10 + */ +extern int zbar_symbol_set_get_size(const zbar_symbol_set_t *symbols); + +/** set iterator. + * @returns the first decoded symbol result in a set + * @returns NULL if the set is empty + * @since 0.10 + */ +extern const zbar_symbol_t* +zbar_symbol_set_first_symbol(const zbar_symbol_set_t *symbols); + +/** raw result iterator. + * @returns the first decoded symbol result in a set, *before* filtering + * @returns NULL if the set is empty + * @since 0.11 + */ +extern const zbar_symbol_t* +zbar_symbol_set_first_unfiltered(const zbar_symbol_set_t *symbols); + +/*@}*/ + +/*------------------------------------------------------------*/ +/** @name Image interface + * stores image data samples along with associated format and size + * metadata + */ +/*@{*/ + +struct zbar_image_s; +/** opaque image object. */ +typedef struct zbar_image_s zbar_image_t; + +/** cleanup handler callback function. + * called to free sample data when an image is destroyed. + */ +typedef void (zbar_image_cleanup_handler_t)(zbar_image_t *image); + +/** data handler callback function. + * called when decoded symbol results are available for an image + */ +typedef void (zbar_image_data_handler_t)(zbar_image_t *image, + const void *userdata); + +/*@}*/ + +/*------------------------------------------------------------*/ +/** @name Image Scanner interface + * @anchor c-imagescanner + * mid-level image scanner interface. + * reads barcodes from 2-D images + */ +/*@{*/ + +struct zbar_image_scanner_s; +/** opaque image scanner object. */ +typedef struct zbar_image_scanner_s zbar_image_scanner_t; + +/** constructor. */ +extern zbar_image_scanner_t *zbar_image_scanner_create(void); + +/** destructor. */ +extern void zbar_image_scanner_destroy(zbar_image_scanner_t *scanner); + +/** setup result handler callback. + * the specified function will be called by the scanner whenever + * new results are available from a decoded image. + * pass a NULL value to disable callbacks. + * @returns the previously registered handler + */ +extern zbar_image_data_handler_t* +zbar_image_scanner_set_data_handler(zbar_image_scanner_t *scanner, + zbar_image_data_handler_t *handler, + const void *userdata); + + +/** set config for indicated symbology (0 for all) to specified value. + * @returns 0 for success, non-0 for failure (config does not apply to + * specified symbology, or value out of range) + * @see zbar_decoder_set_config() + * @since 0.4 + */ +extern int zbar_image_scanner_set_config(zbar_image_scanner_t *scanner, + zbar_symbol_type_t symbology, + zbar_config_t config, + int value); + +/** parse configuration string using zbar_parse_config() + * and apply to image scanner using zbar_image_scanner_set_config(). + * @returns 0 for success, non-0 for failure + * @see zbar_parse_config() + * @see zbar_image_scanner_set_config() + * @since 0.4 + */ +static inline int +zbar_image_scanner_parse_config (zbar_image_scanner_t *scanner, + const char *config_string) +{ + zbar_symbol_type_t sym; + zbar_config_t cfg; + int val; + return(zbar_parse_config(config_string, &sym, &cfg, &val) || + zbar_image_scanner_set_config(scanner, sym, cfg, val)); +} + +/** enable or disable the inter-image result cache (default disabled). + * mostly useful for scanning video frames, the cache filters + * duplicate results from consecutive images, while adding some + * consistency checking and hysteresis to the results. + * this interface also clears the cache + */ +extern void zbar_image_scanner_enable_cache(zbar_image_scanner_t *scanner, + int enable); + +/** remove any previously decoded results from the image scanner and the + * specified image. somewhat more efficient version of + * zbar_image_set_symbols(image, NULL) which may retain memory for + * subsequent decodes + * @since 0.10 + */ +extern void zbar_image_scanner_recycle_image(zbar_image_scanner_t *scanner, + zbar_image_t *image); + +/** retrieve decode results for last scanned image. + * @returns the symbol set result container or NULL if no results are + * available + * @note the symbol set does not have its reference count adjusted; + * ensure that the count is incremented if the results may be kept + * after the next image is scanned + * @since 0.10 + */ +extern const zbar_symbol_set_t* +zbar_image_scanner_get_results(const zbar_image_scanner_t *scanner); + +/** scan for symbols in provided image. The image format must be + * "Y800" or "GRAY". + * @returns >0 if symbols were successfully decoded from the image, + * 0 if no symbols were found or -1 if an error occurs + * @see zbar_image_convert() + * @since 0.9 - changed to only accept grayscale images + */ +extern int zbar_scan_image(zbar_image_scanner_t *scanner, + zbar_image_t *image); + +/*@}*/ + +/*------------------------------------------------------------*/ +/** @name Decoder interface + * @anchor c-decoder + * low-level bar width stream decoder interface. + * identifies symbols and extracts encoded data + */ +/*@{*/ + +struct zbar_decoder_s; +/** opaque decoder object. */ +typedef struct zbar_decoder_s zbar_decoder_t; + +/** decoder data handler callback function. + * called by decoder when new data has just been decoded + */ +typedef void (zbar_decoder_handler_t)(zbar_decoder_t *decoder); + +/** constructor. */ +extern zbar_decoder_t *zbar_decoder_create(void); + +/** destructor. */ +extern void zbar_decoder_destroy(zbar_decoder_t *decoder); + +/** set config for indicated symbology (0 for all) to specified value. + * @returns 0 for success, non-0 for failure (config does not apply to + * specified symbology, or value out of range) + * @since 0.4 + */ +extern int zbar_decoder_set_config(zbar_decoder_t *decoder, + zbar_symbol_type_t symbology, + zbar_config_t config, + int value); + +/** parse configuration string using zbar_parse_config() + * and apply to decoder using zbar_decoder_set_config(). + * @returns 0 for success, non-0 for failure + * @see zbar_parse_config() + * @see zbar_decoder_set_config() + * @since 0.4 + */ +static inline int zbar_decoder_parse_config (zbar_decoder_t *decoder, + const char *config_string) +{ + zbar_symbol_type_t sym; + zbar_config_t cfg; + int val; + return(zbar_parse_config(config_string, &sym, &cfg, &val) || + zbar_decoder_set_config(decoder, sym, cfg, val)); +} + +/** retrieve symbology boolean config settings. + * @returns a bitmask indicating which configs are currently set for the + * specified symbology. + * @since 0.11 + */ +extern unsigned int zbar_decoder_get_configs(const zbar_decoder_t *decoder, + zbar_symbol_type_t symbology); + +/** clear all decoder state. + * any partial symbols are flushed + */ +extern void zbar_decoder_reset(zbar_decoder_t *decoder); + +/** mark start of a new scan pass. + * clears any intra-symbol state and resets color to ::ZBAR_SPACE. + * any partially decoded symbol state is retained + */ +extern void zbar_decoder_new_scan(zbar_decoder_t *decoder); + +/** process next bar/space width from input stream. + * the width is in arbitrary relative units. first value of a scan + * is ::ZBAR_SPACE width, alternating from there. + * @returns appropriate symbol type if width completes + * decode of a symbol (data is available for retrieval) + * @returns ::ZBAR_PARTIAL as a hint if part of a symbol was decoded + * @returns ::ZBAR_NONE (0) if no new symbol data is available + */ +extern zbar_symbol_type_t zbar_decode_width(zbar_decoder_t *decoder, + unsigned width); + +/** retrieve color of @em next element passed to + * zbar_decode_width(). */ +extern zbar_color_t zbar_decoder_get_color(const zbar_decoder_t *decoder); + +/** retrieve last decoded data. + * @returns the data string or NULL if no new data available. + * the returned data buffer is owned by library, contents are only + * valid between non-0 return from zbar_decode_width and next library + * call + */ +extern const char *zbar_decoder_get_data(const zbar_decoder_t *decoder); + +/** retrieve length of binary data. + * @returns the length of the decoded data or 0 if no new data + * available. + */ +extern unsigned int +zbar_decoder_get_data_length(const zbar_decoder_t *decoder); + +/** retrieve last decoded symbol type. + * @returns the type or ::ZBAR_NONE if no new data available + */ +extern zbar_symbol_type_t +zbar_decoder_get_type(const zbar_decoder_t *decoder); + +/** retrieve modifier flags for the last decoded symbol. + * @returns a bitmask indicating which characteristics were detected + * during decoding. + * @since 0.11 + */ +extern unsigned int zbar_decoder_get_modifiers(const zbar_decoder_t *decoder); + +/** retrieve last decode direction. + * @returns 1 for forward and -1 for reverse + * @returns 0 if the decode direction is unknown or does not apply + * @since 0.11 + */ +extern int zbar_decoder_get_direction(const zbar_decoder_t *decoder); + +/** setup data handler callback. + * the registered function will be called by the decoder + * just before zbar_decode_width() returns a non-zero value. + * pass a NULL value to disable callbacks. + * @returns the previously registered handler + */ +extern zbar_decoder_handler_t* +zbar_decoder_set_handler(zbar_decoder_t *decoder, + zbar_decoder_handler_t *handler); + +/** associate user specified data value with the decoder. */ +extern void zbar_decoder_set_userdata(zbar_decoder_t *decoder, + void *userdata); + +/** return user specified data value associated with the decoder. */ +extern void *zbar_decoder_get_userdata(const zbar_decoder_t *decoder); + +/*@}*/ + +/*------------------------------------------------------------*/ +/** @name Scanner interface + * @anchor c-scanner + * low-level linear intensity sample stream scanner interface. + * identifies "bar" edges and measures width between them. + * optionally passes to bar width decoder + */ +/*@{*/ + +struct zbar_scanner_s; +/** opaque scanner object. */ +typedef struct zbar_scanner_s zbar_scanner_t; + +/** constructor. + * if decoder is non-NULL it will be attached to scanner + * and called automatically at each new edge + * current color is initialized to ::ZBAR_SPACE + * (so an initial BAR->SPACE transition may be discarded) + */ +extern zbar_scanner_t *zbar_scanner_create(zbar_decoder_t *decoder); + +/** destructor. */ +extern void zbar_scanner_destroy(zbar_scanner_t *scanner); + +/** clear all scanner state. + * also resets an associated decoder + */ +extern zbar_symbol_type_t zbar_scanner_reset(zbar_scanner_t *scanner); + +/** mark start of a new scan pass. resets color to ::ZBAR_SPACE. + * also updates an associated decoder. + * @returns any decode results flushed from the pipeline + * @note when not using callback handlers, the return value should + * be checked the same as zbar_scan_y() + * @note call zbar_scanner_flush() at least twice before calling this + * method to ensure no decode results are lost + */ +extern zbar_symbol_type_t zbar_scanner_new_scan(zbar_scanner_t *scanner); + +/** flush scanner processing pipeline. + * forces current scanner position to be a scan boundary. + * call multiple times (max 3) to completely flush decoder. + * @returns any decode/scan results flushed from the pipeline + * @note when not using callback handlers, the return value should + * be checked the same as zbar_scan_y() + * @since 0.9 + */ +extern zbar_symbol_type_t zbar_scanner_flush(zbar_scanner_t *scanner); + +/** process next sample intensity value. + * intensity (y) is in arbitrary relative units. + * @returns result of zbar_decode_width() if a decoder is attached, + * otherwise @returns (::ZBAR_PARTIAL) when new edge is detected + * or 0 (::ZBAR_NONE) if no new edge is detected + */ +extern zbar_symbol_type_t zbar_scan_y(zbar_scanner_t *scanner, + int y); + +/** process next sample from RGB (or BGR) triple. */ +static inline zbar_symbol_type_t zbar_scan_rgb24 (zbar_scanner_t *scanner, + unsigned char *rgb) +{ + return(zbar_scan_y(scanner, rgb[0] + rgb[1] + rgb[2])); +} + +/** retrieve last scanned width. */ +extern unsigned zbar_scanner_get_width(const zbar_scanner_t *scanner); + +/** retrieve sample position of last edge. + * @since 0.10 + */ +extern unsigned zbar_scanner_get_edge(const zbar_scanner_t *scn, + unsigned offset, + int prec); + +/** retrieve last scanned color. */ +extern zbar_color_t zbar_scanner_get_color(const zbar_scanner_t *scanner); + +/*@}*/ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "config.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +int zbar_parse_config (const char *cfgstr, + zbar_symbol_type_t *sym, + zbar_config_t *cfg, + int *val) +{ + const char *dot, *eq; + int len; + char negate; + if(!cfgstr) + return(1); + + dot = strchr(cfgstr, '.'); + if(dot) { + int len = dot - cfgstr; + if(!len || (len == 1 && !strncmp(cfgstr, "*", len))) + *sym = 0; + else if(len < 2) + return(1); + else if(!strncmp(cfgstr, "qrcode", len)) + *sym = ZBAR_QRCODE; + else if(!strncmp(cfgstr, "db", len)) + *sym = ZBAR_DATABAR; + else if(len < 3) + return(1); + else if(!strncmp(cfgstr, "upca", len)) + *sym = ZBAR_UPCA; + else if(!strncmp(cfgstr, "upce", len)) + *sym = ZBAR_UPCE; + else if(!strncmp(cfgstr, "ean13", len)) + *sym = ZBAR_EAN13; + else if(!strncmp(cfgstr, "ean8", len)) + *sym = ZBAR_EAN8; + else if(!strncmp(cfgstr, "ean5", len)) + *sym = ZBAR_EAN5; + else if(!strncmp(cfgstr, "ean2", len)) + *sym = ZBAR_EAN2; + else if(!strncmp(cfgstr, "composite", len)) + *sym = ZBAR_COMPOSITE; + else if(!strncmp(cfgstr, "i25", len)) + *sym = ZBAR_I25; + else if(len < 4) + return(1); + else if(!strncmp(cfgstr, "scanner", len)) + *sym = ZBAR_PARTIAL; /* FIXME lame */ + else if(!strncmp(cfgstr, "isbn13", len)) + *sym = ZBAR_ISBN13; + else if(!strncmp(cfgstr, "isbn10", len)) + *sym = ZBAR_ISBN10; + else if(!strncmp(cfgstr, "db-exp", len)) + *sym = ZBAR_DATABAR_EXP; + else if(!strncmp(cfgstr, "codabar", len)) + *sym = ZBAR_CODABAR; + else if(len < 6) + return(1); + else if(!strncmp(cfgstr, "code93", len)) + *sym = ZBAR_CODE93; + else if(!strncmp(cfgstr, "code39", len)) + *sym = ZBAR_CODE39; + else if(!strncmp(cfgstr, "pdf417", len)) + *sym = ZBAR_PDF417; + else if(len < 7) + return(1); + else if(!strncmp(cfgstr, "code128", len)) + *sym = ZBAR_CODE128; + else if(!strncmp(cfgstr, "databar", len)) + *sym = ZBAR_DATABAR; + else if(!strncmp(cfgstr, "databar-exp", len)) + *sym = ZBAR_DATABAR_EXP; + else + return(1); + cfgstr = dot + 1; + } + else + *sym = 0; + + len = strlen(cfgstr); + eq = strchr(cfgstr, '='); + if(eq) + len = eq - cfgstr; + else + *val = 1; /* handle this here so we can override later */ + negate = 0; + + if(len > 3 && !strncmp(cfgstr, "no-", 3)) { + negate = 1; + cfgstr += 3; + len -= 3; + } + + if(len < 1) + return(1); + else if(!strncmp(cfgstr, "y-density", len)) + *cfg = ZBAR_CFG_Y_DENSITY; + else if(!strncmp(cfgstr, "x-density", len)) + *cfg = ZBAR_CFG_X_DENSITY; + else if(len < 2) + return(1); + else if(!strncmp(cfgstr, "enable", len)) + *cfg = ZBAR_CFG_ENABLE; + else if(len < 3) + return(1); + else if(!strncmp(cfgstr, "disable", len)) { + *cfg = ZBAR_CFG_ENABLE; + negate = !negate; /* no-disable ?!? */ + } + else if(!strncmp(cfgstr, "min-length", len)) + *cfg = ZBAR_CFG_MIN_LEN; + else if(!strncmp(cfgstr, "max-length", len)) + *cfg = ZBAR_CFG_MAX_LEN; + else if(!strncmp(cfgstr, "ascii", len)) + *cfg = ZBAR_CFG_ASCII; + else if(!strncmp(cfgstr, "add-check", len)) + *cfg = ZBAR_CFG_ADD_CHECK; + else if(!strncmp(cfgstr, "emit-check", len)) + *cfg = ZBAR_CFG_EMIT_CHECK; + else if(!strncmp(cfgstr, "uncertainty", len)) + *cfg = ZBAR_CFG_UNCERTAINTY; + else if(!strncmp(cfgstr, "position", len)) + *cfg = ZBAR_CFG_POSITION; + else + return(1); + + if(eq) { +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + *val = strtol(eq + 1, NULL, 0); +#ifdef HAVE_ERRNO_H + if(errno) + return(1); +#endif + } + if(negate) + *val = !*val; + + return(0); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "image.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define fourcc zbar_fourcc + +struct zbar_image_s { + uint32_t format; /* fourcc image format code */ + unsigned width, height; /* image size */ + const void *data; /* image sample data */ + unsigned long datalen; /* allocated/mapped size of data */ + unsigned crop_x, crop_y; /* crop rectangle */ + unsigned crop_w, crop_h; + void *userdata; /* user specified data associated w/image */ + + unsigned seq; /* page/frame sequence number */ + zbar_symbol_set_t *syms; /* decoded result set */ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "refcnt.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +typedef int refcnt_t; + +static inline int _zbar_refcnt (refcnt_t *cnt, + int delta) +{ + int rc = (*cnt += delta); + assert(rc >= 0); + return(rc); +} + +void _zbar_refcnt_init(void); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "refcnt.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +void _zbar_refcnt_init () +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "symbol.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define NUM_SYMS 20 + +typedef struct zbar_point_s { + int x, y; +} zbar_point_t; + +struct zbar_symbol_set_s { + refcnt_t refcnt; + int nsyms; /* number of filtered symbols */ + zbar_symbol_t *head; /* first of decoded symbol results */ + zbar_symbol_t *tail; /* last of unfiltered symbol results */ +}; + +struct zbar_symbol_s { + zbar_symbol_type_t type; /* symbol type */ + unsigned int configs; /* symbology boolean config bitmask */ + unsigned int modifiers; /* symbology modifier bitmask */ + unsigned int data_alloc; /* allocation size of data */ + unsigned int datalen; /* length of binary symbol data */ + char *data; /* symbol data */ + + unsigned pts_alloc; /* allocation size of pts */ + unsigned npts; /* number of points in location polygon */ + zbar_point_t *pts; /* list of points in location polygon */ + zbar_orientation_t orient; /* coarse orientation */ + + refcnt_t refcnt; /* reference count */ + zbar_symbol_t *next; /* linked list of results (or siblings) */ + zbar_symbol_set_t *syms; /* components of composite result */ + unsigned long time; /* relative symbol capture time */ + int cache_count; /* cache state */ + int quality; /* relative symbol reliability metric */ +}; + +extern int _zbar_get_symbol_hash(zbar_symbol_type_t); + +extern void _zbar_symbol_free(zbar_symbol_t*); + +extern zbar_symbol_set_t *_zbar_symbol_set_create(void); +extern void _zbar_symbol_set_free(zbar_symbol_set_t*); + +static inline void sym_add_point (zbar_symbol_t *sym, + int x, + int y) +{ + int i = sym->npts; + if(++sym->npts >= sym->pts_alloc) + sym->pts = realloc(sym->pts, ++sym->pts_alloc * sizeof(zbar_point_t)); + sym->pts[i].x = x; + sym->pts[i].y = y; +} + +static inline void _zbar_symbol_refcnt (zbar_symbol_t *sym, + int delta) +{ + if(!_zbar_refcnt(&sym->refcnt, delta) && delta <= 0) + _zbar_symbol_free(sym); +} + +static inline void _zbar_symbol_set_add (zbar_symbol_set_t *syms, + zbar_symbol_t *sym) +{ + sym->next = syms->head; + syms->head = sym; + syms->nsyms++; + + _zbar_symbol_refcnt(sym, 1); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "symbol.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +const char *zbar_get_symbol_name (zbar_symbol_type_t sym) +{ + switch(sym & ZBAR_SYMBOL) { + case ZBAR_EAN2: return("EAN-2"); + case ZBAR_EAN5: return("EAN-5"); + case ZBAR_EAN8: return("EAN-8"); + case ZBAR_UPCE: return("UPC-E"); + case ZBAR_ISBN10: return("ISBN-10"); + case ZBAR_UPCA: return("UPC-A"); + case ZBAR_EAN13: return("EAN-13"); + case ZBAR_ISBN13: return("ISBN-13"); + case ZBAR_COMPOSITE: return("COMPOSITE"); + case ZBAR_I25: return("I2/5"); + case ZBAR_DATABAR: return("DataBar"); + case ZBAR_DATABAR_EXP: return("DataBar-Exp"); + case ZBAR_CODABAR: return("Codabar"); + case ZBAR_CODE39: return("CODE-39"); + case ZBAR_CODE93: return("CODE-93"); + case ZBAR_CODE128: return("CODE-128"); + case ZBAR_PDF417: return("PDF417"); + case ZBAR_QRCODE: return("QR-Code"); + default: return("UNKNOWN"); + } +} + +const char *zbar_get_addon_name (zbar_symbol_type_t sym) +{ + return(""); +} + +const char *zbar_get_config_name (zbar_config_t cfg) +{ + switch(cfg) { + case ZBAR_CFG_ENABLE: return("ENABLE"); + case ZBAR_CFG_ADD_CHECK: return("ADD_CHECK"); + case ZBAR_CFG_EMIT_CHECK: return("EMIT_CHECK"); + case ZBAR_CFG_ASCII: return("ASCII"); + case ZBAR_CFG_MIN_LEN: return("MIN_LEN"); + case ZBAR_CFG_MAX_LEN: return("MAX_LEN"); + case ZBAR_CFG_UNCERTAINTY: return("UNCERTAINTY"); + case ZBAR_CFG_POSITION: return("POSITION"); + case ZBAR_CFG_X_DENSITY: return("X_DENSITY"); + case ZBAR_CFG_Y_DENSITY: return("Y_DENSITY"); + default: return(""); + } +} + +const char *zbar_get_modifier_name (zbar_modifier_t mod) +{ + switch(mod) { + case ZBAR_MOD_GS1: return("GS1"); + case ZBAR_MOD_AIM: return("AIM"); + default: return(""); + } +} + +const char *zbar_get_orientation_name (zbar_orientation_t orient) +{ + switch(orient) { + case ZBAR_ORIENT_UP: return("UP"); + case ZBAR_ORIENT_RIGHT: return("RIGHT"); + case ZBAR_ORIENT_DOWN: return("DOWN"); + case ZBAR_ORIENT_LEFT: return("LEFT"); + default: return("UNKNOWN"); + } +} + +int _zbar_get_symbol_hash (zbar_symbol_type_t sym) +{ + static const signed char hash[0x20] = { + 0x00, 0x01, 0x10, 0x11, -1, 0x11, 0x16, 0x0c, + 0x05, 0x06, 0x08, -1, 0x04, 0x03, 0x07, 0x12, + -1, -1, -1, -1, -1, -1, -1, 0x02, + -1, 0x00, 0x12, 0x0c, 0x0b, 0x1d, 0x0a, 0x00, + }; + int g0 = hash[sym & 0x1f]; + int g1 = hash[~(sym >> 4) & 0x1f]; + assert(g0 >= 0 && g1 >= 0); + if(g0 < 0 || g1 < 0) + return(0); + return((g0 + g1) & 0x1f); +} + +void _zbar_symbol_free (zbar_symbol_t *sym) +{ + if(sym->syms) { + zbar_symbol_set_ref(sym->syms, -1); + sym->syms = NULL; + } + if(sym->pts) + free(sym->pts); + if(sym->data_alloc && sym->data) + free(sym->data); + free(sym); +} + +void zbar_symbol_ref (const zbar_symbol_t *sym, + int refs) +{ + zbar_symbol_t *ncsym = (zbar_symbol_t*)sym; + _zbar_symbol_refcnt(ncsym, refs); +} + +zbar_symbol_type_t zbar_symbol_get_type (const zbar_symbol_t *sym) +{ + return(sym->type); +} + +unsigned int zbar_symbol_get_configs (const zbar_symbol_t *sym) +{ + return(sym->configs); +} + +unsigned int zbar_symbol_get_modifiers (const zbar_symbol_t *sym) +{ + return(sym->modifiers); +} + +const char *zbar_symbol_get_data (const zbar_symbol_t *sym) +{ + return(sym->data); +} + +unsigned int zbar_symbol_get_data_length (const zbar_symbol_t *sym) +{ + return(sym->datalen); +} + +int zbar_symbol_get_count (const zbar_symbol_t *sym) +{ + return(sym->cache_count); +} + +int zbar_symbol_get_quality (const zbar_symbol_t *sym) +{ + return(sym->quality); +} + +unsigned zbar_symbol_get_loc_size (const zbar_symbol_t *sym) +{ + return(sym->npts); +} + +int zbar_symbol_get_loc_x (const zbar_symbol_t *sym, + unsigned idx) +{ + if(idx < sym->npts) + return(sym->pts[idx].x); + else + return(-1); +} + +int zbar_symbol_get_loc_y (const zbar_symbol_t *sym, + unsigned idx) +{ + if(idx < sym->npts) + return(sym->pts[idx].y); + else + return(-1); +} + +zbar_orientation_t zbar_symbol_get_orientation (const zbar_symbol_t *sym) +{ + return(sym->orient); +} + +const zbar_symbol_t *zbar_symbol_next (const zbar_symbol_t *sym) +{ + return((sym) ? sym->next : NULL); +} + +const zbar_symbol_set_t* +zbar_symbol_get_components (const zbar_symbol_t *sym) +{ + return(sym->syms); +} + +const zbar_symbol_t *zbar_symbol_first_component (const zbar_symbol_t *sym) +{ + return((sym && sym->syms) ? sym->syms->head : NULL); +} + +zbar_symbol_set_t *_zbar_symbol_set_create () +{ + zbar_symbol_set_t *syms = calloc(1, sizeof(*syms)); + _zbar_refcnt(&syms->refcnt, 1); + return(syms); +} + +inline void _zbar_symbol_set_free (zbar_symbol_set_t *syms) +{ + zbar_symbol_t *sym, *next; + for(sym = syms->head; sym; sym = next) { + next = sym->next; + sym->next = NULL; + _zbar_symbol_refcnt(sym, -1); + } + syms->head = NULL; + free(syms); +} + +void zbar_symbol_set_ref (const zbar_symbol_set_t *syms, + int delta) +{ + zbar_symbol_set_t *ncsyms = (zbar_symbol_set_t*)syms; + if(!_zbar_refcnt(&ncsyms->refcnt, delta) && delta <= 0) + _zbar_symbol_set_free(ncsyms); +} + +int zbar_symbol_set_get_size (const zbar_symbol_set_t *syms) +{ + return(syms->nsyms); +} + +const zbar_symbol_t* +zbar_symbol_set_first_symbol (const zbar_symbol_set_t *syms) +{ + zbar_symbol_t *sym = syms->tail; + if(sym) + return(sym->next); + return(syms->head); +} + +const zbar_symbol_t* +zbar_symbol_set_first_unfiltered (const zbar_symbol_set_t *syms) +{ + return(syms->head); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "img_scanner.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* internal image scanner APIs for 2D readers */ + +extern zbar_symbol_t *_zbar_image_scanner_alloc_sym(zbar_image_scanner_t*, + zbar_symbol_type_t, + int); +extern void _zbar_image_scanner_add_sym(zbar_image_scanner_t*, + zbar_symbol_t*); +extern void _zbar_image_scanner_recycle_syms(zbar_image_scanner_t*, + zbar_symbol_t*); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "img_scanner.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#if 0 +# define ASSERT_POS \ + assert(p == data + x + y * (intptr_t)w) +#else +# define ASSERT_POS +#endif + +/* FIXME cache setting configurability */ + +/* time interval for which two images are considered "nearby" + */ +#define CACHE_PROXIMITY 1000 /* ms */ + +/* time that a result must *not* be detected before + * it will be reported again + */ +#define CACHE_HYSTERESIS 2000 /* ms */ + +/* time after which cache entries are invalidated + */ +#define CACHE_TIMEOUT (CACHE_HYSTERESIS * 2) /* ms */ + +#define NUM_SCN_CFGS (ZBAR_CFG_Y_DENSITY - ZBAR_CFG_X_DENSITY + 1) + +#define CFG(iscn, cfg) ((iscn)->configs[(cfg) - ZBAR_CFG_X_DENSITY]) +#define TEST_CFG(iscn, cfg) (((iscn)->config >> ((cfg) - ZBAR_CFG_POSITION)) & 1) + +#ifndef NO_STATS +# define STAT(x) iscn->stat_##x++ +#else +# define STAT(...) +# define dump_stats(...) +#endif + +#define RECYCLE_BUCKETS 5 + +typedef struct recycle_bucket_s { + int nsyms; + zbar_symbol_t *head; +} recycle_bucket_t; + +/* image scanner state */ +struct zbar_image_scanner_s { + zbar_scanner_t *scn; /* associated linear intensity scanner */ + zbar_decoder_t *dcode; /* associated symbol decoder */ +#ifdef ENABLE_QRCODE + qr_reader *qr; /* QR Code 2D reader */ +#endif + + const void *userdata; /* application data */ + /* user result callback */ + zbar_image_data_handler_t *handler; + + unsigned long time; /* scan start time */ + zbar_image_t *img; /* currently scanning image *root* */ + int dx, dy, du, umin, v; /* current scan direction */ + zbar_symbol_set_t *syms; /* previous decode results */ + /* recycled symbols in 4^n size buckets */ + recycle_bucket_t recycle[RECYCLE_BUCKETS]; + + int enable_cache; /* current result cache state */ + zbar_symbol_t *cache; /* inter-image result cache entries */ + + /* configuration settings */ + unsigned config; /* config flags */ + unsigned ean_config; + int configs[NUM_SCN_CFGS]; /* int valued configurations */ + int sym_configs[1][NUM_SYMS]; /* per-symbology configurations */ + +#ifndef NO_STATS + int stat_syms_new; + int stat_iscn_syms_inuse, stat_iscn_syms_recycle; + int stat_img_syms_inuse, stat_img_syms_recycle; + int stat_sym_new; + int stat_sym_recycle[RECYCLE_BUCKETS]; +#endif +}; + +void _zbar_image_scanner_recycle_syms (zbar_image_scanner_t *iscn, + zbar_symbol_t *sym) +{ + zbar_symbol_t *next = NULL; + for(; sym; sym = next) { + next = sym->next; + if(sym->refcnt && _zbar_refcnt(&sym->refcnt, -1)) { + /* unlink referenced symbol */ + /* FIXME handle outstanding component refs (currently unsupported) + */ + assert(sym->data_alloc); + sym->next = NULL; + } + else { + int i; + recycle_bucket_t *bucket; + /* recycle unreferenced symbol */ + if(!sym->data_alloc) { + sym->data = NULL; + sym->datalen = 0; + } + if(sym->syms) { + if(_zbar_refcnt(&sym->syms->refcnt, -1)) + assert(0); + _zbar_image_scanner_recycle_syms(iscn, sym->syms->head); + sym->syms->head = NULL; + _zbar_symbol_set_free(sym->syms); + sym->syms = NULL; + } + for(i = 0; i < RECYCLE_BUCKETS; i++) + if(sym->data_alloc < 1 << (i * 2)) + break; + if(i == RECYCLE_BUCKETS) { + assert(sym->data); + free(sym->data); + sym->data = NULL; + sym->data_alloc = 0; + i = 0; + } + bucket = &iscn->recycle[i]; + /* FIXME cap bucket fill */ + bucket->nsyms++; + sym->next = bucket->head; + bucket->head = sym; + } + } +} + +static inline int recycle_syms (zbar_image_scanner_t *iscn, + zbar_symbol_set_t *syms) +{ + if(_zbar_refcnt(&syms->refcnt, -1)) + return(1); + + _zbar_image_scanner_recycle_syms(iscn, syms->head); + syms->head = syms->tail = NULL; + syms->nsyms = 0; + return(0); +} + +inline void zbar_image_scanner_recycle_image (zbar_image_scanner_t *iscn, + zbar_image_t *img) +{ + zbar_symbol_set_t *syms = iscn->syms; + if(syms && syms->refcnt) { + if(recycle_syms(iscn, syms)) { + STAT(iscn_syms_inuse); + iscn->syms = NULL; + } + else + STAT(iscn_syms_recycle); + } + + syms = img->syms; + img->syms = NULL; + if(syms && recycle_syms(iscn, syms)) + STAT(img_syms_inuse); + else if(syms) { + STAT(img_syms_recycle); + + /* select one set to resurrect, destroy the other */ + if(iscn->syms) + _zbar_symbol_set_free(syms); + else + iscn->syms = syms; + } +} + +inline zbar_symbol_t* +_zbar_image_scanner_alloc_sym (zbar_image_scanner_t *iscn, + zbar_symbol_type_t type, + int datalen) +{ + /* recycle old or alloc new symbol */ + zbar_symbol_t *sym = NULL; + int i; + for(i = 0; i < RECYCLE_BUCKETS - 1; i++) + if(datalen <= 1 << (i * 2)) + break; + + for(; i > 0; i--) + if((sym = iscn->recycle[i].head)) { + STAT(sym_recycle[i]); + break; + } + + if(sym) { + iscn->recycle[i].head = sym->next; + sym->next = NULL; + assert(iscn->recycle[i].nsyms); + iscn->recycle[i].nsyms--; + } + else { + sym = calloc(1, sizeof(zbar_symbol_t)); + STAT(sym_new); + } + + /* init new symbol */ + sym->type = type; + sym->quality = 1; + sym->npts = 0; + sym->orient = ZBAR_ORIENT_UNKNOWN; + sym->cache_count = 0; + sym->time = iscn->time; + assert(!sym->syms); + + if(datalen > 0) { + sym->datalen = datalen - 1; + if(sym->data_alloc < datalen) { + if(sym->data) + free(sym->data); + sym->data_alloc = datalen; + sym->data = malloc(datalen); + } + } + else { + if(sym->data) + free(sym->data); + sym->data = NULL; + sym->datalen = sym->data_alloc = 0; + } + return(sym); +} + +static inline zbar_symbol_t *cache_lookup (zbar_image_scanner_t *iscn, + zbar_symbol_t *sym) +{ + /* search for matching entry in cache */ + zbar_symbol_t **entry = &iscn->cache; + while(*entry) { + if((*entry)->type == sym->type && + (*entry)->datalen == sym->datalen && + !memcmp((*entry)->data, sym->data, sym->datalen)) + break; + if((sym->time - (*entry)->time) > CACHE_TIMEOUT) { + /* recycle stale cache entry */ + zbar_symbol_t *next = (*entry)->next; + (*entry)->next = NULL; + _zbar_image_scanner_recycle_syms(iscn, *entry); + *entry = next; + } + else + entry = &(*entry)->next; + } + return(*entry); +} + +static inline void cache_sym (zbar_image_scanner_t *iscn, + zbar_symbol_t *sym) +{ + if(iscn->enable_cache) { + uint32_t age, near_thresh, far_thresh, dup; + zbar_symbol_t *entry = cache_lookup(iscn, sym); + if(!entry) { + /* FIXME reuse sym */ + entry = _zbar_image_scanner_alloc_sym(iscn, sym->type, + sym->datalen + 1); + entry->configs = sym->configs; + entry->modifiers = sym->modifiers; + memcpy(entry->data, sym->data, sym->datalen); + entry->time = sym->time - CACHE_HYSTERESIS; + entry->cache_count = 0; + /* add to cache */ + entry->next = iscn->cache; + iscn->cache = entry; + } + + /* consistency check and hysteresis */ + age = sym->time - entry->time; + entry->time = sym->time; + near_thresh = (age < CACHE_PROXIMITY); + far_thresh = (age >= CACHE_HYSTERESIS); + dup = (entry->cache_count >= 0); + if((!dup && !near_thresh) || far_thresh) { + int type = sym->type; + int h = _zbar_get_symbol_hash(type); + entry->cache_count = -iscn->sym_configs[0][h]; + } + else if(dup || near_thresh) + entry->cache_count++; + + sym->cache_count = entry->cache_count; + } + else + sym->cache_count = 0; +} + +void _zbar_image_scanner_add_sym(zbar_image_scanner_t *iscn, + zbar_symbol_t *sym) +{ + zbar_symbol_set_t *syms; + cache_sym(iscn, sym); + + syms = iscn->syms; + if(sym->cache_count || !syms->tail) { + sym->next = syms->head; + syms->head = sym; + } + else { + sym->next = syms->tail->next; + syms->tail->next = sym; + } + + if(!sym->cache_count) + syms->nsyms++; + else if(!syms->tail) + syms->tail = sym; + + _zbar_symbol_refcnt(sym, 1); +} + +#ifdef ENABLE_QRCODE +extern qr_finder_line *_zbar_decoder_get_qr_finder_line(zbar_decoder_t*); + +# define QR_FIXED(v, rnd) ((((v) << 1) + (rnd)) << (QR_FINDER_SUBPREC - 1)) +# define PRINT_FIXED(val, prec) \ + ((val) >> (prec)), \ + (1000 * ((val) & ((1 << (prec)) - 1)) / (1 << (prec))) + +static inline void qr_handler (zbar_image_scanner_t *iscn) +{ + unsigned u; + int vert; + qr_finder_line *line = _zbar_decoder_get_qr_finder_line(iscn->dcode); + assert(line); + u = zbar_scanner_get_edge(iscn->scn, line->pos[0], + QR_FINDER_SUBPREC); + line->boffs = u - zbar_scanner_get_edge(iscn->scn, line->boffs, + QR_FINDER_SUBPREC); + line->len = zbar_scanner_get_edge(iscn->scn, line->len, + QR_FINDER_SUBPREC); + line->eoffs = zbar_scanner_get_edge(iscn->scn, line->eoffs, + QR_FINDER_SUBPREC) - line->len; + line->len -= u; + + u = QR_FIXED(iscn->umin, 0) + iscn->du * u; + if(iscn->du < 0) { + int tmp = line->boffs; + line->boffs = line->eoffs; + line->eoffs = tmp; + u -= line->len; + } + vert = !iscn->dx; + line->pos[vert] = u; + line->pos[!vert] = QR_FIXED(iscn->v, 1); + + _zbar_qr_found_line(iscn->qr, vert, line); +} +#endif + +static void symbol_handler (zbar_decoder_t *dcode) +{ + zbar_image_scanner_t *iscn = zbar_decoder_get_userdata(dcode); + zbar_symbol_type_t type = zbar_decoder_get_type(dcode); + int x = 0, y = 0, dir; + const char *data; + unsigned datalen; + zbar_symbol_t *sym; + +#ifdef ENABLE_QRCODE + if(type == ZBAR_QRCODE) { + qr_handler(iscn); + return; + } +#else + assert(type != ZBAR_QRCODE); +#endif + + if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) { + /* tmp position fixup */ + int w = zbar_scanner_get_width(iscn->scn); + int u = iscn->umin + iscn->du * zbar_scanner_get_edge(iscn->scn, w, 0); + if(iscn->dx) { + x = u; + y = iscn->v; + } + else { + x = iscn->v; + y = u; + } + } + + /* FIXME debug flag to save/display all PARTIALs */ + if(type <= ZBAR_PARTIAL) { + zprintf(256, "partial symbol @(%d,%d)\n", x, y); + return; + } + + data = zbar_decoder_get_data(dcode); + datalen = zbar_decoder_get_data_length(dcode); + + /* FIXME need better symbol matching */ + for(sym = iscn->syms->head; sym; sym = sym->next) + if(sym->type == type && + sym->datalen == datalen && + !memcmp(sym->data, data, datalen)) { + sym->quality++; + zprintf(224, "dup symbol @(%d,%d): dup %s: %.20s\n", + x, y, zbar_get_symbol_name(type), data); + if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) + /* add new point to existing set */ + /* FIXME should be polygon */ + sym_add_point(sym, x, y); + return; + } + + sym = _zbar_image_scanner_alloc_sym(iscn, type, datalen + 1); + sym->configs = zbar_decoder_get_configs(dcode, type); + sym->modifiers = zbar_decoder_get_modifiers(dcode); + /* FIXME grab decoder buffer */ + memcpy(sym->data, data, datalen + 1); + + /* initialize first point */ + if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) { + zprintf(192, "new symbol @(%d,%d): %s: %.20s\n", + x, y, zbar_get_symbol_name(type), data); + sym_add_point(sym, x, y); + } + + dir = zbar_decoder_get_direction(dcode); + if(dir) + sym->orient = (iscn->dy != 0) + ((iscn->du ^ dir) & 2); + + _zbar_image_scanner_add_sym(iscn, sym); +} + +zbar_image_scanner_t *zbar_image_scanner_create () +{ + zbar_image_scanner_t *iscn = calloc(1, sizeof(zbar_image_scanner_t)); + if(!iscn) + return(NULL); + iscn->dcode = zbar_decoder_create(); + iscn->scn = zbar_scanner_create(iscn->dcode); + if(!iscn->dcode || !iscn->scn) { + zbar_image_scanner_destroy(iscn); + return(NULL); + } + zbar_decoder_set_userdata(iscn->dcode, iscn); + zbar_decoder_set_handler(iscn->dcode, symbol_handler); + +#ifdef ENABLE_QRCODE + iscn->qr = _zbar_qr_create(); +#endif + + /* apply default configuration */ + CFG(iscn, ZBAR_CFG_X_DENSITY) = 1; + CFG(iscn, ZBAR_CFG_Y_DENSITY) = 1; + zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_POSITION, 1); + zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_UNCERTAINTY, 2); + zbar_image_scanner_set_config(iscn, ZBAR_QRCODE, ZBAR_CFG_UNCERTAINTY, 0); + zbar_image_scanner_set_config(iscn, ZBAR_CODE128, ZBAR_CFG_UNCERTAINTY, 0); + zbar_image_scanner_set_config(iscn, ZBAR_CODE93, ZBAR_CFG_UNCERTAINTY, 0); + zbar_image_scanner_set_config(iscn, ZBAR_CODE39, ZBAR_CFG_UNCERTAINTY, 0); + zbar_image_scanner_set_config(iscn, ZBAR_CODABAR, ZBAR_CFG_UNCERTAINTY, 1); + zbar_image_scanner_set_config(iscn, ZBAR_COMPOSITE, ZBAR_CFG_UNCERTAINTY, 0); + return(iscn); +} + +#ifndef NO_STATS +static inline void dump_stats (const zbar_image_scanner_t *iscn) +{ + int i; + zprintf(1, "symbol sets allocated = %-4d\n", iscn->stat_syms_new); + zprintf(1, " scanner syms in use = %-4d\trecycled = %-4d\n", + iscn->stat_iscn_syms_inuse, iscn->stat_iscn_syms_recycle); + zprintf(1, " image syms in use = %-4d\trecycled = %-4d\n", + iscn->stat_img_syms_inuse, iscn->stat_img_syms_recycle); + zprintf(1, "symbols allocated = %-4d\n", iscn->stat_sym_new); + for(i = 0; i < RECYCLE_BUCKETS; i++) + zprintf(1, " recycled[%d] = %-4d\n", + i, iscn->stat_sym_recycle[i]); +} +#endif + +void zbar_image_scanner_destroy (zbar_image_scanner_t *iscn) +{ + int i; + dump_stats(iscn); + if(iscn->syms) { + if(iscn->syms->refcnt) + zbar_symbol_set_ref(iscn->syms, -1); + else + _zbar_symbol_set_free(iscn->syms); + iscn->syms = NULL; + } + if(iscn->scn) + zbar_scanner_destroy(iscn->scn); + iscn->scn = NULL; + if(iscn->dcode) + zbar_decoder_destroy(iscn->dcode); + iscn->dcode = NULL; + for(i = 0; i < RECYCLE_BUCKETS; i++) { + zbar_symbol_t *sym, *next; + for(sym = iscn->recycle[i].head; sym; sym = next) { + next = sym->next; + _zbar_symbol_free(sym); + } + } +#ifdef ENABLE_QRCODE + if(iscn->qr) { + _zbar_qr_destroy(iscn->qr); + iscn->qr = NULL; + } +#endif + free(iscn); +} + +zbar_image_data_handler_t* +zbar_image_scanner_set_data_handler (zbar_image_scanner_t *iscn, + zbar_image_data_handler_t *handler, + const void *userdata) +{ + zbar_image_data_handler_t *result = iscn->handler; + iscn->handler = handler; + iscn->userdata = userdata; + return(result); +} + +int zbar_image_scanner_set_config (zbar_image_scanner_t *iscn, + zbar_symbol_type_t sym, + zbar_config_t cfg, + int val) +{ + if((sym == 0 || sym == ZBAR_COMPOSITE) && cfg == ZBAR_CFG_ENABLE) { + iscn->ean_config = !!val; + if(sym) + return(0); + } + + if(cfg < ZBAR_CFG_UNCERTAINTY) + return(zbar_decoder_set_config(iscn->dcode, sym, cfg, val)); + + if(cfg < ZBAR_CFG_POSITION) { + int c, i; + if(cfg > ZBAR_CFG_UNCERTAINTY) + return(1); + c = cfg - ZBAR_CFG_UNCERTAINTY; + if(sym > ZBAR_PARTIAL) { + i = _zbar_get_symbol_hash(sym); + iscn->sym_configs[c][i] = val; + } + else + for(i = 0; i < NUM_SYMS; i++) + iscn->sym_configs[c][i] = val; + return(0); + } + + if(sym > ZBAR_PARTIAL) + return(1); + + if(cfg >= ZBAR_CFG_X_DENSITY && cfg <= ZBAR_CFG_Y_DENSITY) { + CFG(iscn, cfg) = val; + return(0); + } + + if(cfg > ZBAR_CFG_POSITION) + return(1); + cfg -= ZBAR_CFG_POSITION; + + if(!val) + iscn->config &= ~(1 << cfg); + else if(val == 1) + iscn->config |= (1 << cfg); + else + return(1); + + return(0); +} + +void zbar_image_scanner_enable_cache (zbar_image_scanner_t *iscn, + int enable) +{ + if(iscn->cache) { + /* recycle all cached syms */ + _zbar_image_scanner_recycle_syms(iscn, iscn->cache); + iscn->cache = NULL; + } + iscn->enable_cache = (enable) ? 1 : 0; +} + +const zbar_symbol_set_t * +zbar_image_scanner_get_results (const zbar_image_scanner_t *iscn) +{ + return(iscn->syms); +} + +static inline void quiet_border (zbar_image_scanner_t *iscn) +{ + /* flush scanner pipeline */ + zbar_scanner_t *scn = iscn->scn; + zbar_scanner_flush(scn); + zbar_scanner_flush(scn); + zbar_scanner_new_scan(scn); +} + +#define movedelta(dx, dy) do { \ + x += (dx); \ + y += (dy); \ + p += (dx) + ((uintptr_t)(dy) * w); \ + } while(0); + +int zbar_scan_image (zbar_image_scanner_t *iscn, + zbar_image_t *img) +{ + zbar_symbol_set_t *syms; + const uint8_t *data; + zbar_scanner_t *scn = iscn->scn; + unsigned w, h, cx1, cy1; + int density; + + /* timestamp image + * FIXME prefer video timestamp + */ + iscn->time = 0;//_zbar_timer_now(); + +#ifdef ENABLE_QRCODE + _zbar_qr_reset(iscn->qr); +#endif + + /* image must be in grayscale format */ + if(img->format != fourcc('Y','8','0','0') && + img->format != fourcc('G','R','E','Y')) + return(-1); + iscn->img = img; + + /* recycle previous scanner and image results */ + zbar_image_scanner_recycle_image(iscn, img); + syms = iscn->syms; + if(!syms) { + syms = iscn->syms = _zbar_symbol_set_create(); + STAT(syms_new); + zbar_symbol_set_ref(syms, 1); + } + else + zbar_symbol_set_ref(syms, 2); + img->syms = syms; + + w = img->width; + h = img->height; + cx1 = img->crop_x + img->crop_w; + assert(cx1 <= w); + cy1 = img->crop_y + img->crop_h; + assert(cy1 <= h); + data = img->data; + + zbar_image_write_png(img, "debug.png"); + svg_open("debug.svg", 0, 0, w, h); + svg_image("debug.png", w, h); + + zbar_scanner_new_scan(scn); + + density = CFG(iscn, ZBAR_CFG_Y_DENSITY); + if(density > 0) { + const uint8_t *p = data; + int x = 0, y = 0; + + int border = (((img->crop_h - 1) % density) + 1) / 2; + if(border > img->crop_h / 2) + border = img->crop_h / 2; + border += img->crop_y; + assert(border <= h); + svg_group_start("scanner", 0, 1, 1, 0, 0); + iscn->dy = 0; + + movedelta(img->crop_x, border); + iscn->v = y; + + while(y < cy1) { + int cx0 = img->crop_x;; + zprintf(128, "img_x+: %04d,%04d @%p\n", x, y, p); + svg_path_start("vedge", 1. / 32, 0, y + 0.5); + iscn->dx = iscn->du = 1; + iscn->umin = cx0; + while(x < cx1) { + uint8_t d = *p; + movedelta(1, 0); + zbar_scan_y(scn, d); + } + ASSERT_POS; + quiet_border(iscn); + svg_path_end(); + + movedelta(-1, density); + iscn->v = y; + if(y >= cy1) + break; + + zprintf(128, "img_x-: %04d,%04d @%p\n", x, y, p); + svg_path_start("vedge", -1. / 32, w, y + 0.5); + iscn->dx = iscn->du = -1; + iscn->umin = cx1; + while(x >= cx0) { + uint8_t d = *p; + movedelta(-1, 0); + zbar_scan_y(scn, d); + } + ASSERT_POS; + quiet_border(iscn); + svg_path_end(); + + movedelta(1, density); + iscn->v = y; + } + svg_group_end(); + } + iscn->dx = 0; + + density = CFG(iscn, ZBAR_CFG_X_DENSITY); + if(density > 0) { + const uint8_t *p = data; + int x = 0, y = 0; + + int border = (((img->crop_w - 1) % density) + 1) / 2; + if(border > img->crop_w / 2) + border = img->crop_w / 2; + border += img->crop_x; + assert(border <= w); + svg_group_start("scanner", 90, 1, -1, 0, 0); + movedelta(border, img->crop_y); + iscn->v = x; + + while(x < cx1) { + int cy0 = img->crop_y; + zprintf(128, "img_y+: %04d,%04d @%p\n", x, y, p); + svg_path_start("vedge", 1. / 32, 0, x + 0.5); + iscn->dy = iscn->du = 1; + iscn->umin = cy0; + while(y < cy1) { + uint8_t d = *p; + movedelta(0, 1); + zbar_scan_y(scn, d); + } + ASSERT_POS; + quiet_border(iscn); + svg_path_end(); + + movedelta(density, -1); + iscn->v = x; + if(x >= cx1) + break; + + zprintf(128, "img_y-: %04d,%04d @%p\n", x, y, p); + svg_path_start("vedge", -1. / 32, h, x + 0.5); + iscn->dy = iscn->du = -1; + iscn->umin = cy1; + while(y >= cy0) { + uint8_t d = *p; + movedelta(0, -1); + zbar_scan_y(scn, d); + } + ASSERT_POS; + quiet_border(iscn); + svg_path_end(); + + movedelta(density, 1); + iscn->v = x; + } + svg_group_end(); + } + iscn->dy = 0; + iscn->img = NULL; + +#ifdef ENABLE_QRCODE + _zbar_qr_decode(iscn->qr, iscn, img); +#endif + + /* FIXME tmp hack to filter bad EAN results */ + /* FIXME tmp hack to merge simple case EAN add-ons */ + char filter = (!iscn->enable_cache && + (density == 1 || CFG(iscn, ZBAR_CFG_Y_DENSITY) == 1)); + int nean = 0, naddon = 0; + if(syms->nsyms) { + zbar_symbol_t **symp; + for(symp = &syms->head; *symp; ) { + zbar_symbol_t *sym = *symp; + if(sym->cache_count <= 0 && + ((sym->type < ZBAR_COMPOSITE && sym->type > ZBAR_PARTIAL) || + sym->type == ZBAR_DATABAR || + sym->type == ZBAR_DATABAR_EXP || + sym->type == ZBAR_CODABAR)) + { + if((sym->type == ZBAR_CODABAR || filter) && sym->quality < 4) { + if(iscn->enable_cache) { + /* revert cache update */ + zbar_symbol_t *entry = cache_lookup(iscn, sym); + if(entry) + entry->cache_count--; + else + assert(0); + } + + /* recycle */ + *symp = sym->next; + syms->nsyms--; + sym->next = NULL; + _zbar_image_scanner_recycle_syms(iscn, sym); + continue; + } + else if(sym->type < ZBAR_COMPOSITE && + sym->type != ZBAR_ISBN10) + { + if(sym->type > ZBAR_EAN5) + nean++; + else + naddon++; + } + } + symp = &sym->next; + } + + if(nean == 1 && naddon == 1 && iscn->ean_config) { + /* create container symbol for composite result */ + zbar_symbol_t *ean = NULL, *addon = NULL; + for(symp = &syms->head; *symp; ) { + zbar_symbol_t *sym = *symp; + if(sym->type < ZBAR_COMPOSITE && sym->type > ZBAR_PARTIAL) { + /* move to composite */ + *symp = sym->next; + syms->nsyms--; + sym->next = NULL; + if(sym->type <= ZBAR_EAN5) + addon = sym; + else + ean = sym; + } + else + symp = &sym->next; + } + assert(ean); + assert(addon); + + int datalen = ean->datalen + addon->datalen + 1; + zbar_symbol_t *ean_sym = + _zbar_image_scanner_alloc_sym(iscn, ZBAR_COMPOSITE, datalen); + ean_sym->orient = ean->orient; + ean_sym->syms = _zbar_symbol_set_create(); + memcpy(ean_sym->data, ean->data, ean->datalen); + memcpy(ean_sym->data + ean->datalen, + addon->data, addon->datalen + 1); + ean_sym->syms->head = ean; + ean->next = addon; + ean_sym->syms->nsyms = 2; + _zbar_image_scanner_add_sym(iscn, ean_sym); + } + } + + if(syms->nsyms && iscn->handler) + iscn->handler(img, iscn->userdata); + + svg_close(); + return(syms->nsyms); +} + +#undef TEST_CFG +#undef CFG + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define NUM_CFGS (ZBAR_CFG_MAX_LEN - ZBAR_CFG_MIN_LEN + 1) + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "ean.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* state of each parallel decode attempt */ +typedef struct ean_pass_s { + signed char state; /* module position of w[idx] in symbol */ +#define STATE_REV 0x80 /* scan direction reversed */ +#define STATE_ADDON 0x40 /* scanning add-on */ +#define STATE_IDX 0x3f /* element offset into symbol */ + unsigned width; /* width of last character */ + unsigned char raw[7]; /* decode in process */ +} ean_pass_t; + +/* EAN/UPC specific decode state */ +typedef struct ean_decoder_s { + ean_pass_t pass[4]; /* state of each parallel decode attempt */ + zbar_symbol_type_t left; /* current holding buffer contents */ + zbar_symbol_type_t right; + int direction; /* scan direction */ + unsigned s4, width; /* character width */ + signed char buf[18]; /* holding buffer */ + + signed char enable; + unsigned ean13_config; + unsigned ean8_config; + unsigned upca_config; + unsigned upce_config; + unsigned isbn10_config; + unsigned isbn13_config; + unsigned ean5_config; + unsigned ean2_config; +} ean_decoder_t; + +/* reset EAN/UPC pass specific state */ +static inline void ean_new_scan (ean_decoder_t *ean) +{ + ean->pass[0].state = ean->pass[1].state = -1; + ean->pass[2].state = ean->pass[3].state = -1; + ean->s4 = 0; +} + +/* reset all EAN/UPC state */ +static inline void ean_reset (ean_decoder_t *ean) +{ + ean_new_scan(ean); + ean->left = ean->right = ZBAR_NONE; +} + +static inline unsigned ean_get_config (ean_decoder_t *ean, + zbar_symbol_type_t sym) +{ + switch(sym) { + case ZBAR_EAN2: return(ean->ean2_config); + case ZBAR_EAN5: return(ean->ean5_config); + case ZBAR_EAN8: return(ean->ean8_config); + case ZBAR_UPCE: return(ean->upce_config); + case ZBAR_ISBN10: return(ean->isbn10_config); + case ZBAR_UPCA: return(ean->upca_config); + case ZBAR_EAN13: return(ean->ean13_config); + case ZBAR_ISBN13: return(ean->isbn13_config); + default: return(0); + } +} + +/* decode EAN/UPC symbols */ +zbar_symbol_type_t _zbar_decode_ean(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "i25.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* interleaved 2 of 5 specific decode state */ +typedef struct i25_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */ + unsigned element : 4; /* element offset 0-8 */ + int character : 12; /* character position in symbol */ + unsigned s10; /* current character width */ + unsigned width; /* last character width */ + unsigned char buf[4]; /* initial scan buffer */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} i25_decoder_t; + +/* reset interleaved 2 of 5 specific state */ +static inline void i25_reset (i25_decoder_t *i25) +{ + i25->direction = 0; + i25->element = 0; + i25->character = -1; + i25->s10 = 0; +} + +/* decode interleaved 2 of 5 symbols */ +zbar_symbol_type_t _zbar_decode_i25(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "databar.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define DATABAR_MAX_SEGMENTS 32 + +/* active DataBar (partial) segment entry */ +typedef struct databar_segment_s { + signed finder : 5; /* finder pattern */ + unsigned exp : 1; /* DataBar expanded finder */ + unsigned color : 1; /* finder coloring */ + unsigned side : 1; /* data character side of finder */ + + unsigned partial : 1; /* unpaired partial segment */ + unsigned count : 7; /* times encountered */ + unsigned epoch : 8; /* age, in characters scanned */ + unsigned check : 8; /* bar checksum */ + signed short data; /* decoded character data */ + unsigned short width; /* measured width of finder (14 modules) */ +} databar_segment_t; + +/* DataBar specific decode state */ +typedef struct databar_decoder_s { + unsigned config; /* decoder configuration flags */ + unsigned config_exp; + + unsigned csegs : 8; /* allocated segments */ + unsigned epoch : 8; /* current scan */ + + databar_segment_t *segs; /* active segment list */ + signed char chars[16]; /* outstanding character indices */ +} databar_decoder_t; + +/* reset DataBar segment decode state */ +static inline void databar_new_scan (databar_decoder_t *db) +{ + int i; + for(i = 0; i < 16; i++) + if(db->chars[i] >= 0) { + databar_segment_t *seg = db->segs + db->chars[i]; + if(seg->partial) + seg->finder = -1; + db->chars[i] = -1; + } +} + +/* reset DataBar accumulated segments */ +static inline void databar_reset (databar_decoder_t *db) +{ + int i, n = db->csegs; + databar_new_scan(db); + for(i = 0; i < n; i++) + db->segs[i].finder = -1; +} + +/* decode DataBar symbols */ +zbar_symbol_type_t _zbar_decode_databar(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "codabar.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2011 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* Codabar specific decode state */ +typedef struct codabar_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd, 1=rev */ + unsigned element : 4; /* element offset 0-7 */ + int character : 12; /* character position in symbol */ + unsigned s7; /* current character width */ + unsigned width; /* last character width */ + unsigned char buf[6]; /* initial scan buffer */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} codabar_decoder_t; + +/* reset Codabar specific state */ +static inline void codabar_reset (codabar_decoder_t *codabar) +{ + codabar->direction = 0; + codabar->element = 0; + codabar->character = -1; + codabar->s7 = 0; +} + +/* decode Codabar symbols */ +zbar_symbol_type_t _zbar_decode_codabar(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code39.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* Code 39 specific decode state */ +typedef struct code39_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd, 1=rev */ + unsigned element : 4; /* element offset 0-8 */ + int character : 12; /* character position in symbol */ + unsigned s9; /* current character width */ + unsigned width; /* last character width */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} code39_decoder_t; + +/* reset Code 39 specific state */ +static inline void code39_reset (code39_decoder_t *dcode39) +{ + dcode39->direction = 0; + dcode39->element = 0; + dcode39->character = -1; + dcode39->s9 = 0; +} + +/* decode Code 39 symbols */ +zbar_symbol_type_t _zbar_decode_code39(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code93.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* Code 93 specific decode state */ +typedef struct code93_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */ + unsigned element : 3; /* element offset 0-5 */ + int character : 12; /* character position in symbol */ + unsigned width; /* last character width */ + unsigned char buf; /* first character */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} code93_decoder_t; + +/* reset Code 93 specific state */ +static inline void code93_reset (code93_decoder_t *dcode93) +{ + dcode93->direction = 0; + dcode93->element = 0; + dcode93->character = -1; +} + +/* decode Code 93 symbols */ +zbar_symbol_type_t _zbar_decode_code93(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code128.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* Code 128 specific decode state */ +typedef struct code128_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */ + unsigned element : 3; /* element offset 0-5 */ + int character : 12; /* character position in symbol */ + unsigned char start; /* start character */ + unsigned s6; /* character width */ + unsigned width; /* last character width */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} code128_decoder_t; + +/* reset Code 128 specific state */ +static inline void code128_reset (code128_decoder_t *dcode128) +{ + dcode128->direction = 0; + dcode128->element = 0; + dcode128->character = -1; + dcode128->s6 = 0; +} + +/* decode Code 128 symbols */ +zbar_symbol_type_t _zbar_decode_code128(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "pdf417.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* PDF417 specific decode state */ +typedef struct pdf417_decoder_s { + unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */ + unsigned element : 3; /* element offset 0-7 */ + int character : 12; /* character position in symbol */ + unsigned s8; /* character width */ + + unsigned config; + int configs[NUM_CFGS]; /* int valued configurations */ +} pdf417_decoder_t; + +/* reset PDF417 specific state */ +static inline void pdf417_reset (pdf417_decoder_t *pdf417) +{ + pdf417->direction = 0; + pdf417->element = 0; + pdf417->character = -1; + pdf417->s8 = 0; +} + +/* decode PDF417 symbols */ +zbar_symbol_type_t _zbar_decode_pdf417(zbar_decoder_t *dcode); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "decoder.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* size of bar width history (implementation assumes power of two) */ +#ifndef DECODE_WINDOW +# define DECODE_WINDOW 16 +#endif + +/* initial data buffer allocation */ +#ifndef BUFFER_MIN +# define BUFFER_MIN 0x20 +#endif + +/* maximum data buffer allocation + * (longer symbols are rejected) + */ +#ifndef BUFFER_MAX +# define BUFFER_MAX 0x100 +#endif + +/* buffer allocation increment */ +#ifndef BUFFER_INCR +# define BUFFER_INCR 0x10 +#endif + +#define CFG(dcode, cfg) ((dcode).configs[(cfg) - ZBAR_CFG_MIN_LEN]) +#define TEST_CFG(config, cfg) (((config) >> (cfg)) & 1) +#define MOD(mod) (1 << (mod)) + +/* symbology independent decoder state */ +struct zbar_decoder_s { + unsigned char idx; /* current width index */ + unsigned w[DECODE_WINDOW]; /* window of last N bar widths */ + zbar_symbol_type_t type; /* type of last decoded data */ + zbar_symbol_type_t lock; /* buffer lock */ + unsigned modifiers; /* symbology modifier */ + int direction; /* direction of last decoded data */ + unsigned s6; /* 6-element character width */ + + /* everything above here is automatically reset */ + unsigned buf_alloc; /* dynamic buffer allocation */ + unsigned buflen; /* binary data length */ + unsigned char *buf; /* decoded characters */ + void *userdata; /* application data */ + zbar_decoder_handler_t *handler; /* application callback */ + + /* symbology specific state */ +#ifdef ENABLE_EAN + ean_decoder_t ean; /* EAN/UPC parallel decode attempts */ +#endif +#ifdef ENABLE_I25 + i25_decoder_t i25; /* Interleaved 2 of 5 decode state */ +#endif +#ifdef ENABLE_DATABAR + databar_decoder_t databar; /* DataBar decode state */ +#endif +#ifdef ENABLE_CODABAR + codabar_decoder_t codabar; /* Codabar decode state */ +#endif +#ifdef ENABLE_CODE39 + code39_decoder_t code39; /* Code 39 decode state */ +#endif +#ifdef ENABLE_CODE93 + code93_decoder_t code93; /* Code 93 decode state */ +#endif +#ifdef ENABLE_CODE128 + code128_decoder_t code128; /* Code 128 decode state */ +#endif +#ifdef ENABLE_PDF417 + pdf417_decoder_t pdf417; /* PDF417 decode state */ +#endif +#ifdef ENABLE_QRCODE + qr_finder_t qrf; /* QR Code finder state */ +#endif +}; + +/* return current element color */ +static inline char get_color (const zbar_decoder_t *dcode) +{ + return(dcode->idx & 1); +} + +/* retrieve i-th previous element width */ +static inline unsigned get_width (const zbar_decoder_t *dcode, + unsigned char offset) +{ + return(dcode->w[(dcode->idx - offset) & (DECODE_WINDOW - 1)]); +} + +/* retrieve bar+space pair width starting at offset i */ +static inline unsigned pair_width (const zbar_decoder_t *dcode, + unsigned char offset) +{ + return(get_width(dcode, offset) + get_width(dcode, offset + 1)); +} + +/* calculate total character width "s" + * - start of character identified by context sensitive offset + * (<= DECODE_WINDOW - n) + * - size of character is n elements + */ +static inline unsigned calc_s (const zbar_decoder_t *dcode, + unsigned char offset, + unsigned char n) +{ + /* FIXME check that this gets unrolled for constant n */ + unsigned s = 0; + while(n--) + s += get_width(dcode, offset++); + return(s); +} + +/* fixed character width decode assist + * bar+space width are compared as a fraction of the reference dimension "x" + * - +/- 1/2 x tolerance + * - measured total character width (s) compared to symbology baseline (n) + * (n = 7 for EAN/UPC, 11 for Code 128) + * - bar+space *pair width* "e" is used to factor out bad "exposures" + * ("blooming" or "swelling" of dark or light areas) + * => using like-edge measurements avoids these issues + * - n should be > 3 + */ +static inline int decode_e (unsigned e, + unsigned s, + unsigned n) +{ + /* result is encoded number of units - 2 + * (for use as zero based index) + * or -1 if invalid + */ + unsigned char E = ((e * n * 2 + 1) / s - 3) / 2; + return((E >= n - 3) ? -1 : E); +} + +/* sort three like-colored elements and return ordering + */ +static inline unsigned decode_sort3 (zbar_decoder_t *dcode, + int i0) +{ + unsigned w0 = get_width(dcode, i0); + unsigned w2 = get_width(dcode, i0 + 2); + unsigned w4 = get_width(dcode, i0 + 4); + if(w0 < w2) { + if(w2 < w4) + return((i0 << 8) | ((i0 + 2) << 4) | (i0 + 4)); + if(w0 < w4) + return((i0 << 8) | ((i0 + 4) << 4) | (i0 + 2)); + return(((i0 + 4) << 8) | (i0 << 4) | (i0 + 2)); + } + if(w4 < w2) + return(((i0 + 4) << 8) | ((i0 + 2) << 4) | i0); + if(w0 < w4) + return(((i0 + 2) << 8) | (i0 << 4) | (i0 + 4)); + return(((i0 + 2) << 8) | ((i0 + 4) << 4) | i0); +} + +/* sort N like-colored elements and return ordering + */ +static inline unsigned decode_sortn (zbar_decoder_t *dcode, + int n, + int i0) +{ + unsigned mask = 0, sort = 0; + int i; + for(i = n - 1; i >= 0; i--) { + unsigned wmin = UINT_MAX; + int jmin = -1, j; + for(j = n - 1; j >= 0; j--) { + if((mask >> j) & 1) + continue; + unsigned w = get_width(dcode, i0 + j * 2); + if(wmin >= w) { + wmin = w; + jmin = j; + } + } + zassert(jmin >= 0, 0, "sortn(%d,%d) jmin=%d", + n, i0, jmin); + sort <<= 4; + mask |= 1 << jmin; + sort |= i0 + jmin * 2; + } + return(sort); +} + +/* acquire shared state lock */ +static inline char acquire_lock (zbar_decoder_t *dcode, + zbar_symbol_type_t req) +{ + if(dcode->lock) { + dbprintf(2, " [locked %d]\n", dcode->lock); + return(1); + } + dcode->lock = req; + return(0); +} + +/* check and release shared state lock */ +static inline char release_lock (zbar_decoder_t *dcode, + zbar_symbol_type_t req) +{ + zassert(dcode->lock == req, 1, "lock=%d req=%d\n", + dcode->lock, req); + dcode->lock = 0; + return(0); +} + +/* ensure output buffer has sufficient allocation for request */ +static inline char size_buf (zbar_decoder_t *dcode, + unsigned len) +{ + unsigned char *buf; + if(len <= BUFFER_MIN) + return(0); + if(len < dcode->buf_alloc) + /* FIXME size reduction heuristic? */ + return(0); + if(len > BUFFER_MAX) + return(1); + if(len < dcode->buf_alloc + BUFFER_INCR) { + len = dcode->buf_alloc + BUFFER_INCR; + if(len > BUFFER_MAX) + len = BUFFER_MAX; + } + buf = realloc(dcode->buf, len); + if(!buf) + return(1); + dcode->buf = buf; + dcode->buf_alloc = len; + return(0); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "ean.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* partial decode symbol location */ +typedef enum symbol_partial_e { + EAN_LEFT = 0x0000, + EAN_RIGHT = 0x1000, +} symbol_partial_t; + +/* convert compact encoded D2E1E2 to character (bit4 is parity) */ +static const unsigned char digits[] = { /* E1 E2 */ + 0x06, 0x10, 0x04, 0x13, /* 2 2-5 */ + 0x19, 0x08, 0x11, 0x05, /* 3 2-5 (d2 <= thr) */ + 0x09, 0x12, 0x07, 0x15, /* 4 2-5 (d2 <= thr) */ + 0x16, 0x00, 0x14, 0x03, /* 5 2-5 */ + 0x18, 0x01, 0x02, 0x17, /* E1E2=43,44,33,34 (d2 > thr) */ +}; + +static const unsigned char parity_decode[] = { + 0xf0, /* [xx] BBBBBB = RIGHT half EAN-13 */ + + /* UPC-E check digit encoding */ + 0xff, + 0xff, + 0x0f, /* [07] BBBAAA = 0 */ + 0xff, + 0x1f, /* [0b] BBABAA = 1 */ + 0x2f, /* [0d] BBAABA = 2 */ + 0xf3, /* [0e] BBAAAB = 3 */ + 0xff, + 0x4f, /* [13] BABBAA = 4 */ + 0x7f, /* [15] BABABA = 7 */ + 0xf8, /* [16] BABAAB = 8 */ + 0x5f, /* [19] BAABBA = 5 */ + 0xf9, /* [1a] BAABAB = 9 */ + 0xf6, /* [1c] BAAABB = 6 */ + 0xff, + + /* LEFT half EAN-13 leading digit */ + 0xff, + 0x6f, /* [23] ABBBAA = 6 */ + 0x9f, /* [25] ABBABA = 9 */ + 0xf5, /* [26] ABBAAB = 5 */ + 0x8f, /* [29] ABABBA = 8 */ + 0xf7, /* [2a] ABABAB = 7 */ + 0xf4, /* [2c] ABAABB = 4 */ + 0xff, + 0x3f, /* [31] AABBBA = 3 */ + 0xf2, /* [32] AABBAB = 2 */ + 0xf1, /* [34] AABABB = 1 */ + 0xff, + 0xff, + 0xff, + 0xff, + 0x0f, /* [3f] AAAAAA = 0 */ +}; + +static inline int check_width (unsigned w0, + unsigned w1) +{ + unsigned dw0 = w0; + w0 *= 8; + w1 *= 8; + return(w0 - dw0 <= w1 && w1 <= w0 + dw0); +} + +/* evaluate previous N (>= 2) widths as auxiliary pattern, + * using preceding 4 as character width + */ +static inline signed char aux_end (zbar_decoder_t *dcode, + unsigned char fwd) +{ + signed char code, i; + + /* reference width from previous character */ + unsigned s = calc_s(dcode, 4 + fwd, 4); + + /* check quiet zone */ + unsigned qz = get_width(dcode, 0); + if(!fwd && qz && qz <= s * 3 / 4) { + dbprintf(2, " [invalid quiet]"); + return(-1); + } + + dbprintf(2, " ("); + code = 0; + for(i = 1 - fwd; i < 3 + fwd; i++) { + unsigned e = get_width(dcode, i) + get_width(dcode, i + 1); + dbprintf(2, " %d", e); + code = (code << 2) | decode_e(e, s, 7); + if(code < 0) { + dbprintf(2, " [invalid end guard]"); + return(-1); + } + } + dbprintf(2, ") s=%d aux=%x", s, code); + return(code); +} + +/* determine possible auxiliary pattern + * using current 4 as possible character + */ +static inline signed char aux_start (zbar_decoder_t *dcode) +{ + /* FIXME NB add-on has no guard in reverse */ + unsigned e1, e2 = get_width(dcode, 5) + get_width(dcode, 6); + unsigned char E1; + if(dcode->ean.s4 < 6) + return(-1); + + if(decode_e(e2, dcode->ean.s4, 7)) { + dbprintf(2, " [invalid any]"); + return(-1); + } + + e1 = get_width(dcode, 4) + get_width(dcode, 5); + E1 = decode_e(e1, dcode->ean.s4, 7); + + if(get_color(dcode) == ZBAR_BAR) { + /* check for quiet-zone */ + unsigned qz = get_width(dcode, 7); + if(!qz || qz > dcode->ean.s4 * 3 / 4) { + if(!E1) { + dbprintf(2, " [valid normal]"); + return(0); /* normal symbol start */ + } + else if(E1 == 1) { + dbprintf(2, " [valid add-on]"); + return(STATE_ADDON); /* add-on symbol start */ + } + } + dbprintf(2, " [invalid start]"); + return(-1); + } + + if(!E1) { + /* attempting decode from SPACE => validate center guard */ + unsigned e3 = get_width(dcode, 6) + get_width(dcode, 7); + unsigned e4 = get_width(dcode, 7) + get_width(dcode, 8); + if(!decode_e(e3, dcode->ean.s4, 7) && + !decode_e(e4, dcode->ean.s4, 7)) { + dbprintf(2, " [valid center]"); + return(0); /* start after center guard */ + } + } + dbprintf(2, " [invalid center]"); + return(-1); +} + +/* check addon delimiter using current 4 as character + */ +static inline signed char aux_mid (zbar_decoder_t *dcode) +{ + unsigned e = get_width(dcode, 4) + get_width(dcode, 5); + return(decode_e(e, dcode->ean.s4, 7)); +} + +/* attempt to decode previous 4 widths (2 bars and 2 spaces) as a character */ +static inline signed char decode4 (zbar_decoder_t *dcode) +{ + signed char code; + + /* calculate similar edge measurements */ + unsigned e1 = ((get_color(dcode) == ZBAR_BAR) + ? get_width(dcode, 0) + get_width(dcode, 1) + : get_width(dcode, 2) + get_width(dcode, 3)); + unsigned e2 = get_width(dcode, 1) + get_width(dcode, 2); + dbprintf(2, "\n e1=%d e2=%d", e1, e2); + + if(dcode->ean.s4 < 6) + return(-1); + + /* create compacted encoding for direct lookup */ + code = ((decode_e(e1, dcode->ean.s4, 7) << 2) | + decode_e(e2, dcode->ean.s4, 7)); + if(code < 0) + return(-1); + dbprintf(2, " code=%x", code); + + /* 4 combinations require additional determinant (D2) + E1E2 == 34 (0110) + E1E2 == 43 (1001) + E1E2 == 33 (0101) + E1E2 == 44 (1010) + */ + if((1 << code) & 0x0660) { + unsigned char mid, alt; + /* use sum of bar widths */ + unsigned d2 = ((get_color(dcode) == ZBAR_BAR) + ? get_width(dcode, 0) + get_width(dcode, 2) + : get_width(dcode, 1) + get_width(dcode, 3)); + d2 *= 7; + mid = (((1 << code) & 0x0420) + ? 3 /* E1E2 in 33,44 */ + : 4); /* E1E2 in 34,43 */ + alt = d2 > (mid * dcode->ean.s4); + if(alt) + code = ((code >> 1) & 3) | 0x10; /* compress code space */ + dbprintf(2, " (d2=%d(%d) alt=%d)", d2, mid * dcode->ean.s4, alt); + } + dbprintf(2, " char=%02x", digits[(unsigned char)code]); + zassert(code < 0x14, -1, "code=%02x e1=%x e2=%x s4=%x color=%x\n", + code, e1, e2, dcode->ean.s4, get_color(dcode)); + return(code); +} + +static inline char ean_part_end2 (ean_decoder_t *ean, + ean_pass_t *pass) +{ + if(!TEST_CFG(ean->ean2_config, ZBAR_CFG_ENABLE)) + return(ZBAR_NONE); + + /* extract parity bits */ + unsigned char par = ((pass->raw[1] & 0x10) >> 3 | + (pass->raw[2] & 0x10) >> 4); + /* calculate "checksum" */ + unsigned char chk = ~((pass->raw[1] & 0xf) * 10 + + (pass->raw[2] & 0xf)) & 0x3; + dbprintf(2, " par=%x chk=%x", par, chk); + if(par != chk) + return(ZBAR_NONE); + + dbprintf(2, "\n"); + dbprintf(1, "decode2=%x%x\n", + pass->raw[1] & 0xf, pass->raw[2] & 0xf); + return(ZBAR_EAN2); +} + +static inline zbar_symbol_type_t ean_part_end4 (ean_pass_t *pass, + unsigned char fwd) +{ + /* extract parity bits */ + unsigned char par = ((pass->raw[1] & 0x10) >> 1 | + (pass->raw[2] & 0x10) >> 2 | + (pass->raw[3] & 0x10) >> 3 | + (pass->raw[4] & 0x10) >> 4); + + dbprintf(2, " par=%x", par); + if(par && par != 0xf) + /* invalid parity combination */ + return(ZBAR_NONE); + + if((!par) == fwd) { + /* reverse sampled digits */ + unsigned char tmp = pass->raw[1]; + pass->state |= STATE_REV; + pass->raw[1] = pass->raw[4]; + pass->raw[4] = tmp; + tmp = pass->raw[2]; + pass->raw[2] = pass->raw[3]; + pass->raw[3] = tmp; + } + + dbprintf(2, "\n"); + dbprintf(1, "decode4=%x%x%x%x\n", + pass->raw[1] & 0xf, pass->raw[2] & 0xf, + pass->raw[3] & 0xf, pass->raw[4] & 0xf); + if(!par) + return(ZBAR_EAN8 | EAN_RIGHT); + return(ZBAR_EAN8 | EAN_LEFT); +} + +static inline char ean_part_end5 (ean_decoder_t *ean, + ean_pass_t *pass) +{ + if(!TEST_CFG(ean->ean5_config, ZBAR_CFG_ENABLE)) + return(ZBAR_NONE); + + /* extract parity bits */ + unsigned char par = ((pass->raw[1] & 0x10) | + (pass->raw[2] & 0x10) >> 1 | + (pass->raw[3] & 0x10) >> 2 | + (pass->raw[4] & 0x10) >> 3 | + (pass->raw[5] & 0x10) >> 4); + /* calculate checksum */ + unsigned char chk = (((pass->raw[1] & 0x0f) + + (pass->raw[2] & 0x0f) * 3 + + (pass->raw[3] & 0x0f) + + (pass->raw[4] & 0x0f) * 3 + + (pass->raw[5] & 0x0f)) * 3) % 10; + + unsigned char parchk = parity_decode[par >> 1]; + if(par & 1) + parchk >>= 4; + parchk &= 0xf; + dbprintf(2, " par=%x(%d) chk=%d", par, parchk, chk); + if(parchk != chk) + return(ZBAR_NONE); + + dbprintf(2, "\n"); + dbprintf(1, "decode5=%x%x%x%x%x\n", + pass->raw[1] & 0xf, pass->raw[2] & 0xf, + pass->raw[3] & 0xf, pass->raw[4] & 0xf, + pass->raw[5] & 0xf); + + return(ZBAR_EAN5); +} + +static inline zbar_symbol_type_t ean_part_end7 (ean_decoder_t *ean, + ean_pass_t *pass, + unsigned char fwd) +{ + /* calculate parity index */ + unsigned char par = ((fwd) + ? ((pass->raw[1] & 0x10) << 1 | + (pass->raw[2] & 0x10) | + (pass->raw[3] & 0x10) >> 1 | + (pass->raw[4] & 0x10) >> 2 | + (pass->raw[5] & 0x10) >> 3 | + (pass->raw[6] & 0x10) >> 4) + : ((pass->raw[1] & 0x10) >> 4 | + (pass->raw[2] & 0x10) >> 3 | + (pass->raw[3] & 0x10) >> 2 | + (pass->raw[4] & 0x10) >> 1 | + (pass->raw[5] & 0x10) | + (pass->raw[6] & 0x10) << 1)); + + /* lookup parity combination */ + pass->raw[0] = parity_decode[par >> 1]; + if(par & 1) + pass->raw[0] >>= 4; + pass->raw[0] &= 0xf; + dbprintf(2, " par=%02x(%x)", par, pass->raw[0]); + + if(pass->raw[0] == 0xf) + /* invalid parity combination */ + return(ZBAR_NONE); + + if((!par) == fwd) { + unsigned char i; + pass->state |= STATE_REV; + /* reverse sampled digits */ + for(i = 1; i < 4; i++) { + unsigned char tmp = pass->raw[i]; + pass->raw[i] = pass->raw[7 - i]; + pass->raw[7 - i] = tmp; + } + } + + dbprintf(2, "\n"); + dbprintf(1, "decode=%x%x%x%x%x%x%x(%02x)\n", + pass->raw[0] & 0xf, pass->raw[1] & 0xf, + pass->raw[2] & 0xf, pass->raw[3] & 0xf, + pass->raw[4] & 0xf, pass->raw[5] & 0xf, + pass->raw[6] & 0xf, par); + + if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE)) { + if(!par) + return(ZBAR_EAN13 | EAN_RIGHT); + if(par & 0x20) + return(ZBAR_EAN13 | EAN_LEFT); + } + if(par && !(par & 0x20)) + return(ZBAR_UPCE); + + return(ZBAR_NONE); +} + +/* update state for one of 4 parallel passes */ +static inline zbar_symbol_type_t decode_pass (zbar_decoder_t *dcode, + ean_pass_t *pass) +{ + unsigned char idx, fwd; + pass->state++; + idx = pass->state & STATE_IDX; + fwd = pass->state & 1; + + if(get_color(dcode) == ZBAR_SPACE) { + if(pass->state & STATE_ADDON) { + dbprintf(2, " i=%d", idx); + if(idx == 0x09 || idx == 0x21) { + unsigned qz = get_width(dcode, 0); + unsigned s = calc_s(dcode, 1, 4); + zbar_symbol_type_t part = !qz || (qz >= s * 3 / 4); + if(part && idx == 0x09) + part = ean_part_end2(&dcode->ean, pass); + else if(part) + part = ean_part_end5(&dcode->ean, pass); + + if(part || idx == 0x21) { + dcode->ean.direction = 0; + pass->state = -1; + return(part); + } + } + if((idx & 7) == 1) { + dbprintf(2, " +"); + pass->state += 2; + idx += 2; + } + } + else if((idx == 0x10 || idx == 0x11) && + TEST_CFG(dcode->ean.ean8_config, ZBAR_CFG_ENABLE) && + !aux_end(dcode, fwd)) { + dbprintf(2, " fwd=%x", fwd); + zbar_symbol_type_t part = ean_part_end4(pass, fwd); + if(part) + dcode->ean.direction = (pass->state & STATE_REV) != 0; + pass->state = -1; + return(part); + } + else if((idx == 0x18 || idx == 0x19)) { + zbar_symbol_type_t part = ZBAR_NONE; + dbprintf(2, " fwd=%x", fwd); + if(!aux_end(dcode, fwd) && pass->raw[5] != 0xff) + part = ean_part_end7(&dcode->ean, pass, fwd); + if(part) + dcode->ean.direction = (pass->state & STATE_REV) != 0; + pass->state = -1; + return(part); + } + } + + if(pass->state & STATE_ADDON) + idx >>= 1; + + if(!(idx & 0x03) && idx <= 0x14) { + signed char code = -1; + unsigned w = pass->width; + if(!dcode->ean.s4) + return(0); + /* validate guard bars before decoding first char of symbol */ + if(!pass->state) { + pass->state = aux_start(dcode); + pass->width = dcode->ean.s4; + if(pass->state < 0) + return(0); + idx = pass->state & STATE_IDX; + } + else { + w = check_width(w, dcode->ean.s4); + if(w) + pass->width = (pass->width + dcode->ean.s4 * 3) / 4; + } + + if(w) + code = decode4(dcode); + else + dbprintf(2, " [bad width]"); + + if((code < 0 && idx != 0x10) || + (idx > 0 && (pass->state & STATE_ADDON) && aux_mid(dcode))) + pass->state = -1; + else if(code < 0) + pass->raw[5] = 0xff; + else { + dbprintf(2, "\n raw[%x]=%02x =>", idx >> 2, + digits[(unsigned char)code]); + pass->raw[(idx >> 2) + 1] = digits[(unsigned char)code]; + dbprintf(2, " raw=%d%d%d%d%d%d%d", + pass->raw[0] & 0xf, pass->raw[1] & 0xf, + pass->raw[2] & 0xf, pass->raw[3] & 0xf, + pass->raw[4] & 0xf, pass->raw[5] & 0xf, + pass->raw[6] & 0xf); + } + } + return(0); +} + +static inline signed char ean_verify_checksum (ean_decoder_t *ean, + int n) +{ + unsigned char chk = 0; + unsigned char i, d; + for(i = 0; i < n; i++) { + unsigned char d = ean->buf[i]; + zassert(d < 10, -1, "i=%x d=%x chk=%x %s\n", i, d, chk, + _zbar_decoder_buf_dump((void*)ean->buf, 18)); + chk += d; + if((i ^ n) & 1) { + chk += d << 1; + if(chk >= 20) + chk -= 20; + } + if(chk >= 10) + chk -= 10; + } + zassert(chk < 10, -1, "chk=%x n=%x %s", chk, n, + _zbar_decoder_buf_dump((void*)ean->buf, 18)); + if(chk) + chk = 10 - chk; + d = ean->buf[n]; + zassert(d < 10, -1, "n=%x d=%x chk=%x %s\n", n, d, chk, + _zbar_decoder_buf_dump((void*)ean->buf, 18)); + if(chk != d) { + dbprintf(1, "\nchecksum mismatch %d != %d (%s)\n", + chk, d, dsprintbuf(ean)); + return(-1); + } + return(0); +} + +static inline unsigned char isbn10_calc_checksum (ean_decoder_t *ean) +{ + unsigned int chk = 0; + unsigned char w; + for(w = 10; w > 1; w--) { + unsigned char d = ean->buf[13 - w]; + zassert(d < 10, '?', "w=%x d=%x chk=%x %s\n", w, d, chk, + _zbar_decoder_buf_dump((void*)ean->buf, 18)); + chk += d * w; + } + chk = chk % 11; + if(!chk) + return('0'); + chk = 11 - chk; + if(chk < 10) + return(chk + '0'); + return('X'); +} + +static inline void ean_expand_upce (ean_decoder_t *ean, + ean_pass_t *pass) +{ + int i = 0; + unsigned char decode; + /* parity encoded digit is checksum */ + ean->buf[12] = pass->raw[i++]; + + decode = pass->raw[6] & 0xf; + ean->buf[0] = 0; + ean->buf[1] = 0; + ean->buf[2] = pass->raw[i++] & 0xf; + ean->buf[3] = pass->raw[i++] & 0xf; + ean->buf[4] = (decode < 3) ? decode : pass->raw[i++] & 0xf; + ean->buf[5] = (decode < 4) ? 0 : pass->raw[i++] & 0xf; + ean->buf[6] = (decode < 5) ? 0 : pass->raw[i++] & 0xf; + ean->buf[7] = 0; + ean->buf[8] = 0; + ean->buf[9] = (decode < 3) ? pass->raw[i++] & 0xf : 0; + ean->buf[10] = (decode < 4) ? pass->raw[i++] & 0xf : 0; + ean->buf[11] = (decode < 5) ? pass->raw[i] & 0xf : decode; +} + +static inline zbar_symbol_type_t integrate_partial (ean_decoder_t *ean, + ean_pass_t *pass, + zbar_symbol_type_t part) +{ + /* copy raw data into holding buffer */ + /* if same partial is not consistent, reset others */ + dbprintf(2, " integrate part=%x (%s)", part, dsprintbuf(ean)); + signed char i, j; + + if((ean->left && ((part & ZBAR_SYMBOL) != ean->left)) || + (ean->right && ((part & ZBAR_SYMBOL) != ean->right))) { + /* partial mismatch - reset collected parts */ + dbprintf(2, " rst(type %x %x)", ean->left, ean->right); + ean->left = ean->right = ZBAR_NONE; + } + + if((ean->left || ean->right) && + !check_width(ean->width, pass->width)) { + dbprintf(2, " rst(width %d)", pass->width); + ean->left = ean->right = ZBAR_NONE; + } + + + if(part & EAN_RIGHT) { + part &= ZBAR_SYMBOL; + j = part - 1; + for(i = part >> 1; i; i--, j--) { + unsigned char digit = pass->raw[i] & 0xf; + if(ean->right && ean->buf[j] != digit) { + /* partial mismatch - reset collected parts */ + dbprintf(2, " rst(right)"); + ean->left = ean->right = ZBAR_NONE; + } + ean->buf[j] = digit; + } + ean->right = part; + part &= ean->left; /* FIXME!? */ + } + else if(part == ZBAR_EAN13 || part == ZBAR_EAN8) /* EAN_LEFT */ { + j = (part - 1) >> 1; + for(i = part >> 1; j >= 0; i--, j--) { + unsigned char digit = pass->raw[i] & 0xf; + if(ean->left && ean->buf[j] != digit) { + /* partial mismatch - reset collected parts */ + dbprintf(2, " rst(left)"); + ean->left = ean->right = ZBAR_NONE; + } + ean->buf[j] = digit; + } + ean->left = part; + part &= ean->right; /* FIXME!? */ + } + else if(part != ZBAR_UPCE) /* add-ons */ { + for(i = part; i > 0; i--) + ean->buf[i - 1] = pass->raw[i] & 0xf; + ean->left = part; + } + else + ean_expand_upce(ean, pass); + + ean->width = pass->width; + + if(!part) + part = ZBAR_PARTIAL; + + if(((part == ZBAR_EAN13 || + part == ZBAR_UPCE) && ean_verify_checksum(ean, 12)) || + (part == ZBAR_EAN8 && ean_verify_checksum(ean, 7))) { + /* invalid checksum */ + if(ean->right) + ean->left = ZBAR_NONE; + else + ean->right = ZBAR_NONE; + part = ZBAR_NONE; + } + + if(part == ZBAR_EAN13) { + /* special case EAN-13 subsets */ + if(!ean->buf[0] && TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE)) + part = ZBAR_UPCA; + else if(ean->buf[0] == 9 && ean->buf[1] == 7) { + /* ISBN-10 has priority over ISBN-13(?) */ + if(ean->buf[2] == 8 && + TEST_CFG(ean->isbn10_config, ZBAR_CFG_ENABLE)) + part = ZBAR_ISBN10; + else if((ean->buf[2] == 8 || ean->buf[2] == 9) && + TEST_CFG(ean->isbn13_config, ZBAR_CFG_ENABLE)) + part = ZBAR_ISBN13; + } + } + else if(part == ZBAR_UPCE) { + if(TEST_CFG(ean->upce_config, ZBAR_CFG_ENABLE)) { + /* UPC-E was decompressed for checksum verification, + * but user requested compressed result + */ + ean->buf[0] = ean->buf[1] = 0; + for(i = 2; i < 8; i++) + ean->buf[i] = pass->raw[i - 1] & 0xf; + ean->buf[i] = pass->raw[0] & 0xf; + } + else if(TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE)) + /* UPC-E reported as UPC-A has priority over EAN-13 */ + part = ZBAR_UPCA; + else if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE)) + part = ZBAR_EAN13; + else + part = ZBAR_NONE; + } + + dbprintf(2, " dir=%d %x/%x=%x", + ean->direction, ean->left, ean->right, part); + return(part); +} + +/* copy result to output buffer */ +static inline void ean_postprocess (zbar_decoder_t *dcode, + zbar_symbol_type_t sym) +{ + ean_decoder_t *ean = &dcode->ean; + zbar_symbol_type_t base = sym; + int i = 0, j = 0; + if(base > ZBAR_PARTIAL) { + if(base == ZBAR_UPCA) + i = 1; + else if(base == ZBAR_UPCE) { + i = 1; + base--; + } + else if(base == ZBAR_ISBN13) + base = ZBAR_EAN13; + else if(base == ZBAR_ISBN10) + i = 3; + + if(base == ZBAR_ISBN10 || + (base > ZBAR_EAN5 && + !TEST_CFG(ean_get_config(ean, sym), ZBAR_CFG_EMIT_CHECK))) + base--; + + for(; j < base && ean->buf[i] >= 0; i++, j++) + dcode->buf[j] = ean->buf[i] + '0'; + + if(sym == ZBAR_ISBN10 && j == 9 && + TEST_CFG(ean->isbn10_config, ZBAR_CFG_EMIT_CHECK)) + /* recalculate ISBN-10 check digit */ + dcode->buf[j++] = isbn10_calc_checksum(ean); + } + dcode->buflen = j; + dcode->buf[j] = '\0'; + dcode->direction = 1 - 2 * ean->direction; + dcode->modifiers = 0; + dbprintf(2, " base=%d j=%d (%s)", base, j, dcode->buf); +} + +zbar_symbol_type_t _zbar_decode_ean (zbar_decoder_t *dcode) +{ + /* process upto 4 separate passes */ + zbar_symbol_type_t sym = ZBAR_NONE; + unsigned char pass_idx = dcode->idx & 3; + unsigned char i; + + /* update latest character width */ + dcode->ean.s4 -= get_width(dcode, 4); + dcode->ean.s4 += get_width(dcode, 0); + + for(i = 0; i < 4; i++) { + ean_pass_t *pass = &dcode->ean.pass[i]; + if(pass->state >= 0 || + i == pass_idx) + { + zbar_symbol_type_t part; + dbprintf(2, " ean[%x/%x]: idx=%x st=%d s=%d", + i, pass_idx, dcode->idx, pass->state, dcode->ean.s4); + part = decode_pass(dcode, pass); + if(part) { + /* update accumulated data from new partial decode */ + sym = integrate_partial(&dcode->ean, pass, part); + if(sym) { + /* this pass valid => _reset_ all passes */ + dbprintf(2, " sym=%x", sym); + dcode->ean.pass[0].state = dcode->ean.pass[1].state = -1; + dcode->ean.pass[2].state = dcode->ean.pass[3].state = -1; + if(sym > ZBAR_PARTIAL) { + if(!acquire_lock(dcode, sym)) + ean_postprocess(dcode, sym); + else { + dbprintf(1, " [locked %d]", dcode->lock); + sym = ZBAR_PARTIAL; + } + } + } + } + dbprintf(2, "\n"); + } + } + return(sym); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "i25.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +static inline unsigned char i25_decode1 (unsigned char enc, + unsigned e, + unsigned s) +{ + unsigned char E = decode_e(e, s, 45); + if(E > 7) + return(0xff); + enc <<= 1; + if(E > 2) + enc |= 1; + return(enc); +} + +static inline unsigned char i25_decode10 (zbar_decoder_t *dcode, + unsigned char offset) +{ + i25_decoder_t *dcode25 = &dcode->i25; + dbprintf(2, " s=%d", dcode25->s10); + if(dcode25->s10 < 10) + return(0xff); + + /* threshold bar width ratios */ + unsigned char enc = 0, par = 0; + signed char i; + for(i = 8; i >= 0; i -= 2) { + unsigned char j = offset + ((dcode25->direction) ? i : 8 - i); + enc = i25_decode1(enc, get_width(dcode, j), dcode25->s10); + if(enc == 0xff) + return(0xff); + if(enc & 1) + par++; + } + + dbprintf(2, " enc=%02x par=%x", enc, par); + + /* parity check */ + if(par != 2) { + dbprintf(2, " [bad parity]"); + return(0xff); + } + + /* decode binary weights */ + enc &= 0xf; + if(enc & 8) { + if(enc == 12) + enc = 0; + else if(--enc > 9) { + dbprintf(2, " [invalid encoding]"); + return(0xff); + } + } + + dbprintf(2, " => %x", enc); + return(enc); +} + +static inline signed char i25_decode_start (zbar_decoder_t *dcode) +{ + i25_decoder_t *dcode25 = &dcode->i25; + if(dcode25->s10 < 10) + return(ZBAR_NONE); + + unsigned char enc = 0; + unsigned char i = 10; + enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10); + enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10); + enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10); + + if((get_color(dcode) == ZBAR_BAR) + ? enc != 4 + : (enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10))) { + dbprintf(4, " i25: s=%d enc=%x [invalid]\n", dcode25->s10, enc); + return(ZBAR_NONE); + } + + /* check leading quiet zone - spec is 10n(?) + * we require 5.25n for w=2n to 6.75n for w=3n + * (FIXME should really factor in w:n ratio) + */ + unsigned quiet = get_width(dcode, i); + if(quiet && quiet < dcode25->s10 * 3 / 8) { + dbprintf(3, " i25: s=%d enc=%x q=%d [invalid qz]\n", + dcode25->s10, enc, quiet); + return(ZBAR_NONE); + } + + dcode25->direction = get_color(dcode); + dcode25->element = 1; + dcode25->character = 0; + return(ZBAR_PARTIAL); +} + +static inline int i25_acquire_lock (zbar_decoder_t *dcode) +{ + int i; + /* lock shared resources */ + if(acquire_lock(dcode, ZBAR_I25)) { + dcode->i25.character = -1; + return(1); + } + + /* copy holding buffer */ + for(i = 4; --i >= 0; ) + dcode->buf[i] = dcode->i25.buf[i]; + return(0); +} + +static inline signed char i25_decode_end (zbar_decoder_t *dcode) +{ + i25_decoder_t *dcode25 = &dcode->i25; + + /* check trailing quiet zone */ + unsigned quiet = get_width(dcode, 0); + if((quiet && quiet < dcode25->width * 3 / 8) || + decode_e(get_width(dcode, 1), dcode25->width, 45) > 2 || + decode_e(get_width(dcode, 2), dcode25->width, 45) > 2) { + dbprintf(3, " i25: s=%d q=%d [invalid qz]\n", + dcode25->width, quiet); + return(ZBAR_NONE); + } + + /* check exit condition */ + unsigned char E = decode_e(get_width(dcode, 3), dcode25->width, 45); + if((!dcode25->direction) + ? E - 3 > 4 + : (E > 2 || + decode_e(get_width(dcode, 4), dcode25->width, 45) > 2)) + return(ZBAR_NONE); + + if(dcode25->character <= 4 && + i25_acquire_lock(dcode)) + return(ZBAR_PARTIAL); + + dcode->direction = 1 - 2 * dcode25->direction; + if(dcode25->direction) { + /* reverse buffer */ + dbprintf(2, " (rev)"); + int i; + for(i = 0; i < dcode25->character / 2; i++) { + unsigned j = dcode25->character - 1 - i; + char c = dcode->buf[i]; + dcode->buf[i] = dcode->buf[j]; + dcode->buf[j] = c; + } + } + + if(dcode25->character < CFG(*dcode25, ZBAR_CFG_MIN_LEN) || + (CFG(*dcode25, ZBAR_CFG_MAX_LEN) > 0 && + dcode25->character > CFG(*dcode25, ZBAR_CFG_MAX_LEN))) { + dbprintf(2, " [invalid len]\n"); + release_lock(dcode, ZBAR_I25); + dcode25->character = -1; + return(ZBAR_NONE); + } + + zassert(dcode25->character < dcode->buf_alloc, ZBAR_NONE, "i=%02x %s\n", + dcode25->character, + _zbar_decoder_buf_dump(dcode->buf, dcode25->character)); + dcode->buflen = dcode25->character; + dcode->buf[dcode25->character] = '\0'; + dcode->modifiers = 0; + dbprintf(2, " [valid end]\n"); + dcode25->character = -1; + return(ZBAR_I25); +} + +zbar_symbol_type_t _zbar_decode_i25 (zbar_decoder_t *dcode) +{ + i25_decoder_t *dcode25 = &dcode->i25; + + /* update latest character width */ + dcode25->s10 -= get_width(dcode, 10); + dcode25->s10 += get_width(dcode, 0); + + if(dcode25->character < 0 && + !i25_decode_start(dcode)) + return(ZBAR_NONE); + + if(--dcode25->element == 6 - dcode25->direction) + return(i25_decode_end(dcode)); + else if(dcode25->element) + return(ZBAR_NONE); + + /* FIXME check current character width against previous */ + dcode25->width = dcode25->s10; + + dbprintf(2, " i25[%c%02d+%x]", + (dcode25->direction) ? '<' : '>', + dcode25->character, dcode25->element); + + if(dcode25->character == 4 && i25_acquire_lock(dcode)) + return(ZBAR_PARTIAL); + + unsigned char c = i25_decode10(dcode, 1); + dbprintf(2, " c=%x", c); + if(c > 9) { + dbprintf(2, " [aborted]\n"); + goto reset; + } + + if(size_buf(dcode, dcode25->character + 3)) { + dbprintf(2, " [overflow]\n"); + goto reset; + } + + unsigned char *buf; + if(dcode25->character >= 4) + buf = dcode->buf; + else + buf = dcode25->buf; + buf[dcode25->character++] = c + '0'; + + c = i25_decode10(dcode, 0); + dbprintf(2, " c=%x", c); + if(c > 9) { + dbprintf(2, " [aborted]\n"); + goto reset; + } + else + dbprintf(2, "\n"); + + buf[dcode25->character++] = c + '0'; + dcode25->element = 10; + return((dcode25->character == 2) ? ZBAR_PARTIAL : ZBAR_NONE); + +reset: + if(dcode25->character >= 4) + release_lock(dcode, ZBAR_I25); + dcode25->character = -1; + return(ZBAR_NONE); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "codabar.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2011 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define NIBUF 6 /* initial scan buffer size */ + +static const signed char codabar_lo[12] = { + 0x0, 0x1, 0x4, 0x5, 0x2, 0xa, 0xb, 0x9, + 0x6, 0x7, 0x8, 0x3 +}; + +static const unsigned char codabar_hi[8] = { + 0x1, 0x4, 0x7, 0x6, 0x2, 0x3, 0x0, 0x5 +}; + +static const unsigned char codabar_characters[20] = + "0123456789-$:/.+ABCD"; + +static inline int +codabar_check_width (unsigned ref, + unsigned w) +{ + unsigned dref = ref; + ref *= 4; + w *= 4; + return(ref - dref <= w && w <= ref + dref); +} + +static inline signed char +codabar_decode7 (zbar_decoder_t *dcode) +{ + codabar_decoder_t *codabar = &dcode->codabar; + unsigned s = codabar->s7; + dbprintf(2, " s=%d", s); + if(s < 7) + return(-1); + + /* check width */ + if(!codabar_check_width(codabar->width, s)) { + dbprintf(2, " [width]"); + return(-1); + } + + /* extract min/max bar */ + unsigned ibar = decode_sortn(dcode, 4, 1); + dbprintf(2, " bar=%04x", ibar); + + unsigned wbmax = get_width(dcode, ibar & 0xf); + unsigned wbmin = get_width(dcode, ibar >> 12); + if(8 * wbmin < wbmax || + 3 * wbmin > 2 * wbmax) + { + dbprintf(2, " [bar outer ratio]"); + return(-1); + } + + unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf); + unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf); + unsigned long b0b3 = wbmin * wbmax; + unsigned long b1b2 = wb1 * wb2; + if(b1b2 + b1b2 / 8 < b0b3) { + /* single wide bar combinations */ + if(8 * wbmin < 5 * wb1 || + 8 * wb1 < 5 * wb2 || + 4 * wb2 > 3 * wbmax || + wb2 * wb2 >= wb1 * wbmax) + { + dbprintf(2, " [1bar inner ratios]"); + return(-1); + } + ibar = (ibar >> 1) & 0x3; + } + else if(b1b2 > b0b3 + b0b3 / 8) { + /* three wide bars, no wide spaces */ + if(4 * wbmin > 3 * wb1 || + 8 * wb1 < 5 * wb2 || + 8 * wb2 < 5 * wbmax || + wbmin * wb2 >= wb1 * wb1) + { + dbprintf(2, " [3bar inner ratios]"); + return(-1); + } + ibar = (ibar >> 13) + 4; + } + else { + dbprintf(2, " [bar inner ratios]"); + return(-1); + } + + unsigned ispc = decode_sort3(dcode, 2); + dbprintf(2, "(%x) spc=%03x", ibar, ispc); + + unsigned wsmax = get_width(dcode, ispc & 0xf); + unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf); + unsigned wsmin = get_width(dcode, (ispc >> 8) & 0xf); + if(ibar >> 2) { + /* verify no wide spaces */ + if(8 * wsmin < wsmax || + 8 * wsmin < 5 * wsmid || + 8 * wsmid < 5 * wsmax) + { + dbprintf(2, " [0space inner ratios]"); + return(-1); + } + ibar &= 0x3; + if(codabar->direction) + ibar = 3 - ibar; + int c = (0xfcde >> (ibar << 2)) & 0xf; + dbprintf(2, " ex[%d]=%x", ibar, c); + return(c); + } + else if(8 * wsmin < wsmax || + 3 * wsmin > 2 * wsmax) + { + dbprintf(2, " [space outer ratio]"); + return(-1); + } + + unsigned long s0s2 = wsmin * wsmax; + unsigned long s1s1 = wsmid * wsmid; + if(s1s1 + s1s1 / 8 < s0s2) { + /* single wide space */ + if(8 * wsmin < 5 * wsmid || + 4 * wsmid > 3 * wsmax) + { + dbprintf(2, " [1space inner ratios]"); + return(-1); + } + ispc = ((ispc & 0xf) >> 1) - 1; + unsigned ic = (ispc << 2) | ibar; + if(codabar->direction) + ic = 11 - ic; + int c = codabar_lo[ic]; + dbprintf(2, "(%d) lo[%d]=%x", ispc, ic, c); + return(c); + } + else if(s1s1 > s0s2 + s0s2 / 8) { + /* two wide spaces, check start/stop */ + if(4 * wsmin > 3 * wsmid || + 8 * wsmid < 5 * wsmax) + { + dbprintf(2, " [2space inner ratios]"); + return(-1); + } + if((ispc >> 8) == 4) { + dbprintf(2, " [space comb]"); + return(-1); + } + ispc >>= 10; + dbprintf(2, "(%d)", ispc); + unsigned ic = ispc * 4 + ibar; + zassert(ic < 8, -1, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar); + unsigned char c = codabar_hi[ic]; + if(c >> 2 != codabar->direction) { + dbprintf(2, " [invalid stop]"); + return(-1); + } + c = (c & 0x3) | 0x10; + dbprintf(2, " hi[%d]=%x", ic, c); + return(c); + } + else { + dbprintf(2, " [space inner ratios]"); + return(-1); + } +} + +static inline signed char +codabar_decode_start (zbar_decoder_t *dcode) +{ + codabar_decoder_t *codabar = &dcode->codabar; + unsigned s = codabar->s7; + if(s < 8) + return(ZBAR_NONE); + dbprintf(2, " codabar: s=%d", s); + + /* check leading quiet zone - spec is 10x */ + unsigned qz = get_width(dcode, 8); + if((qz && qz * 2 < s) || + 4 * get_width(dcode, 0) > 3 * s) + { + dbprintf(2, " [invalid qz/ics]\n"); + return(ZBAR_NONE); + } + + /* check space ratios first */ + unsigned ispc = decode_sort3(dcode, 2); + dbprintf(2, " spc=%03x", ispc); + if((ispc >> 8) == 4) { + dbprintf(2, " [space comb]\n"); + return(ZBAR_NONE); + } + + /* require 2 wide and 1 narrow spaces */ + unsigned wsmax = get_width(dcode, ispc & 0xf); + unsigned wsmin = get_width(dcode, ispc >> 8); + unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf); + if(8 * wsmin < wsmax || + 3 * wsmin > 2 * wsmax || + 4 * wsmin > 3 * wsmid || + 8 * wsmid < 5 * wsmax || + wsmid * wsmid <= wsmax * wsmin) + { + dbprintf(2, " [space ratio]\n"); + return(ZBAR_NONE); + } + ispc >>= 10; + dbprintf(2, "(%d)", ispc); + + /* check bar ratios */ + unsigned ibar = decode_sortn(dcode, 4, 1); + dbprintf(2, " bar=%04x", ibar); + + unsigned wbmax = get_width(dcode, ibar & 0xf); + unsigned wbmin = get_width(dcode, ibar >> 12); + if(8 * wbmin < wbmax || + 3 * wbmin > 2 * wbmax) + { + dbprintf(2, " [bar outer ratio]\n"); + return(ZBAR_NONE); + } + + /* require 1 wide & 3 narrow bars */ + unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf); + unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf); + if(8 * wbmin < 5 * wb1 || + 8 * wb1 < 5 * wb2 || + 4 * wb2 > 3 * wbmax || + wb1 * wb2 >= wbmin * wbmax || + wb2 * wb2 >= wb1 * wbmax) + { + dbprintf(2, " [bar inner ratios]\n"); + return(ZBAR_NONE); + } + ibar = ((ibar & 0xf) - 1) >> 1; + dbprintf(2, "(%d)", ibar); + + /* decode combination */ + int ic = ispc * 4 + ibar; + zassert(ic < 8, ZBAR_NONE, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar); + int c = codabar_hi[ic]; + codabar->buf[0] = (c & 0x3) | 0x10; + + /* set character direction */ + codabar->direction = c >> 2; + + codabar->element = 4; + codabar->character = 1; + codabar->width = codabar->s7; + dbprintf(1, " start=%c dir=%x [valid start]\n", + codabar->buf[0] + 0x31, codabar->direction); + return(ZBAR_PARTIAL); +} + +static inline int +codabar_checksum (zbar_decoder_t *dcode, + unsigned n) +{ + unsigned chk = 0; + unsigned char *buf = dcode->buf; + while(n--) + chk += *(buf++); + return(!!(chk & 0xf)); +} + +static inline zbar_symbol_type_t +codabar_postprocess (zbar_decoder_t *dcode) +{ + codabar_decoder_t *codabar = &dcode->codabar; + int dir = codabar->direction; + dcode->direction = 1 - 2 * dir; + int i, n = codabar->character; + for(i = 0; i < NIBUF; i++) + dcode->buf[i] = codabar->buf[i]; + if(dir) + /* reverse buffer */ + for(i = 0; i < n / 2; i++) { + unsigned j = n - 1 - i; + char code = dcode->buf[i]; + dcode->buf[i] = dcode->buf[j]; + dcode->buf[j] = code; + } + + if(TEST_CFG(codabar->config, ZBAR_CFG_ADD_CHECK)) { + /* validate checksum */ + if(codabar_checksum(dcode, n)) + return(ZBAR_NONE); + if(!TEST_CFG(codabar->config, ZBAR_CFG_EMIT_CHECK)) { + dcode->buf[n - 2] = dcode->buf[n - 1]; + n--; + } + } + + for(i = 0; i < n; i++) { + unsigned c = dcode->buf[i]; + dcode->buf[i] = ((c < 0x14) + ? codabar_characters[c] + : '?'); + } + dcode->buflen = i; + dcode->buf[i] = '\0'; + dcode->modifiers = 0; + + codabar->character = -1; + return(ZBAR_CODABAR); +} + +zbar_symbol_type_t +_zbar_decode_codabar (zbar_decoder_t *dcode) +{ + codabar_decoder_t *codabar = &dcode->codabar; + + /* update latest character width */ + codabar->s7 -= get_width(dcode, 8); + codabar->s7 += get_width(dcode, 1); + + if(get_color(dcode) != ZBAR_SPACE) + return(ZBAR_NONE); + if(codabar->character < 0) + return(codabar_decode_start(dcode)); + if(codabar->character < 2 && + codabar_decode_start(dcode)) + return(ZBAR_PARTIAL); + if(--codabar->element) + return(ZBAR_NONE); + codabar->element = 4; + + dbprintf(1, " codabar[%c%02d+%x]", + (codabar->direction) ? '<' : '>', + codabar->character, codabar->element); + + signed char c = codabar_decode7(dcode); + dbprintf(1, " %d", c); + if(c < 0) { + dbprintf(1, " [aborted]\n"); + goto reset; + } + + unsigned char *buf; + if(codabar->character < NIBUF) + buf = codabar->buf; + else { + if(codabar->character >= BUFFER_MIN && + size_buf(dcode, codabar->character + 1)) + { + dbprintf(1, " [overflow]\n"); + goto reset; + } + buf = dcode->buf; + } + buf[codabar->character++] = c; + + /* lock shared resources */ + if(codabar->character == NIBUF && + acquire_lock(dcode, ZBAR_CODABAR)) + { + codabar->character = -1; + return(ZBAR_PARTIAL); + } + + unsigned s = codabar->s7; + if(c & 0x10) { + unsigned qz = get_width(dcode, 0); + if(qz && qz * 2 < s) { + dbprintf(2, " [invalid qz]\n"); + goto reset; + } + unsigned n = codabar->character; + if(n < CFG(*codabar, ZBAR_CFG_MIN_LEN) || + (CFG(*codabar, ZBAR_CFG_MAX_LEN) > 0 && + n > CFG(*codabar, ZBAR_CFG_MAX_LEN))) + { + dbprintf(2, " [invalid len]\n"); + goto reset; + } + if(codabar->character < NIBUF && + acquire_lock(dcode, ZBAR_CODABAR)) + { + codabar->character = -1; + return(ZBAR_PARTIAL); + } + dbprintf(2, " stop=%c", c + 0x31); + + zbar_symbol_type_t sym = codabar_postprocess(dcode); + if(sym > ZBAR_PARTIAL) + dbprintf(2, " [valid stop]"); + else { + release_lock(dcode, ZBAR_CODABAR); + codabar->character = -1; + } + dbprintf(2, "\n"); + return(sym); + } + else if(4 * get_width(dcode, 0) > 3 * s) { + dbprintf(2, " [ics]\n"); + goto reset; + } + + dbprintf(2, "\n"); + return(ZBAR_NONE); + +reset: + if(codabar->character >= NIBUF) + release_lock(dcode, ZBAR_CODABAR); + codabar->character = -1; + return(ZBAR_NONE); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "databar.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define GS ('\035') + +enum { SCH_NUM, SCH_ALNUM, SCH_ISO646 }; + +static const signed char finder_hash[0x20] = { + 0x16, 0x1f, 0x02, 0x00, 0x03, 0x00, 0x06, 0x0b, + 0x1f, 0x0e, 0x17, 0x0c, 0x0b, 0x14, 0x11, 0x0c, + 0x1f, 0x03, 0x13, 0x08, 0x00, 0x0a, -1, 0x16, + 0x0c, 0x09, -1, 0x1a, 0x1f, 0x1c, 0x00, -1, +}; + +/* DataBar character encoding groups */ +struct group_s { + unsigned short sum; + unsigned char wmax; + unsigned char todd; + unsigned char teven; +} groups[] = { + /* (17,4) DataBar Expanded character groups */ + { 0, 7, 87, 4 }, + { 348, 5, 52, 20 }, + { 1388, 4, 30, 52 }, + { 2948, 3, 10, 104 }, + { 3988, 1, 1, 204 }, + + /* (16,4) DataBar outer character groups */ + { 0, 8, 161, 1 }, + { 161, 6, 80, 10 }, + { 961, 4, 31, 34 }, + { 2015, 3, 10, 70 }, + { 2715, 1, 1, 126 }, + + /* (15,4) DataBar inner character groups */ + { 1516, 8, 81, 1 }, + { 1036, 6, 48, 10 }, + { 336, 4, 20, 35 }, + { 0, 2, 4, 84 }, +}; + +static const unsigned char exp_sequences[] = { + /* sequence Group 1 */ + 0x01, + 0x23, + 0x25, 0x07, + 0x29, 0x47, + 0x29, 0x67, 0x0b, + 0x29, 0x87, 0xab, + /* sequence Group 2 */ + 0x21, 0x43, 0x65, 0x07, + 0x21, 0x43, 0x65, 0x89, + 0x21, 0x43, 0x65, 0xa9, 0x0b, + 0x21, 0x43, 0x67, 0x89, 0xab +}; + +/* DataBar expanded checksum multipliers */ +static const unsigned char exp_checksums[] = { + 1, 189, 62, 113, 46, 43, 109, 134, 6, 79, 161, 45 +}; + +static inline void +append_check14 (unsigned char *buf) +{ + unsigned char chk = 0, d; + int i; + for(i = 13; --i >= 0; ) { + d = *(buf++) - '0'; + chk += d; + if(!(i & 1)) + chk += d << 1; + } + chk %= 10; + if(chk) + chk = 10 - chk; + *buf = chk + '0'; +} + +static inline void +decode10 (unsigned char *buf, + unsigned long n, + int i) +{ + buf += i; + while(--i >= 0) { + unsigned char d = n % 10; + n /= 10; + *--buf = '0' + d; + } +} + +#define VAR_MAX(l, i) ((((l) * 12 + (i)) * 2 + 6) / 7) + +#define FEED_BITS(b) \ + while(i < (b) && len) { \ + d = (d << 12) | (*(data++) & 0xfff); \ + i += 12; \ + len--; \ + dbprintf(2, " %03lx", d & 0xfff); \ + } + +#define PUSH_CHAR(c) \ + *(buf++) = (c) + +#define PUSH_CHAR4(c0, c1, c2, c3) do { \ + PUSH_CHAR(c0); \ + PUSH_CHAR(c1); \ + PUSH_CHAR(c2); \ + PUSH_CHAR(c3); \ + } while(0); + +static inline int +databar_postprocess_exp (zbar_decoder_t *dcode, + int *data) +{ + int i = 0, enc; + unsigned n; + unsigned char *buf; + unsigned long d = *(data++); + int len = d / 211 + 4, buflen; + + /* grok encodation method */ + d = *(data++); + dbprintf(2, "\n len=%d %03lx", len, d & 0xfff); + n = (d >> 4) & 0x7f; + if(n >= 0x40) { + i = 10; + enc = 1; + buflen = 2 + 14 + VAR_MAX(len, 10 - 2 - 44 + 6) + 2; + } + else if(n >= 0x38) { + i = 4; + enc = 6 + (n & 7); + buflen = 2 + 14 + 4 + 6 + 2 + 6 + 2; + } + else if(n >= 0x30) { + i = 6; + enc = 2 + ((n >> 2) & 1); + buflen = 2 + 14 + 4 + 3 + VAR_MAX(len, 6 - 2 - 44 - 2 - 10) + 2; + } + else if(n >= 0x20) { + i = 7; + enc = 4 + ((n >> 3) & 1); + buflen = 2 + 14 + 4 + 6; + } + else { + i = 9; + enc = 0; + buflen = VAR_MAX(len, 9 - 2) + 2; + } + dbprintf(2, " buflen=%d enc=%d", buflen, enc); + zassert(buflen > 2, -1, "buflen=%d\n", buflen); + + if(enc < 4) { + /* grok variable length symbol bit field */ + if((len ^ (d >> (--i))) & 1) + /* even/odd length mismatch */ + return(-1); + if(((d >> (--i)) & 1) != (len > 14)) + /* size group mismatch */ + return(-1); + } + len -= 2; + dbprintf(2, " [%d+%d]", i, len); + + if(size_buf(dcode, buflen)) + return(-1); + buf = dcode->buf; + + /* handle compressed fields */ + if(enc) { + PUSH_CHAR('0'); + PUSH_CHAR('1'); + } + + if(enc == 1) { + i -= 4; + n = (d >> i) & 0xf; + if(i >= 10) + return(-1); + PUSH_CHAR('0' + n); + } + else if(enc) + PUSH_CHAR('9'); + + if(enc) { + int j; + for(j = 0; j < 4; j++) { + FEED_BITS(10); + i -= 10; + n = (d >> i) & 0x3ff; + if(n >= 1000) + return(-1); + decode10(buf, n, 3); + buf += 3; + } + append_check14(buf - 13); + buf++; + } + + switch(enc) + { + case 2: /* 01100: AI 392x */ + FEED_BITS(2); + i -= 2; + n = (d >> i) & 0x3; + PUSH_CHAR4('3', '9', '2', '0' + n); + break; + + case 3: /* 01101: AI 393x */ + FEED_BITS(12); + i -= 2; + n = (d >> i) & 0x3; + PUSH_CHAR4('3', '9', '3', '0' + n); + i -= 10; + n = (d >> i) & 0x3ff; + if(n >= 1000) + return(-1); + decode10(buf, n, 3); + buf += 3; + break; + + case 4: /* 0100: AI 3103 */ + FEED_BITS(15); + i -= 15; + n = (d >> i) & 0x7fff; + PUSH_CHAR4('3', '1', '0', '3'); + decode10(buf, n, 6); + buf += 6; + break; + + case 5: /* 0101: AI 3202/3203 */ + FEED_BITS(15); + i -= 15; + n = (d >> i) & 0x7fff; + dbprintf(2, " v=%d", n); + PUSH_CHAR4('3', '2', '0', (n >= 10000) ? '3' : '2' ); + if(n >= 10000) + n -= 10000; + decode10(buf, n, 6); + buf += 6; + break; + } + if(enc >= 6) { + /* 0111000 - 0111111: AI 310x/320x + AI 11/13/15/17 */ + PUSH_CHAR4('3', '1' + (enc & 1), '0', 'x'); + FEED_BITS(20); + i -= 20; + n = (d >> i) & 0xfffff; + dbprintf(2, " [%d+%d] %d", i, len, n); + if(n >= 1000000) + return(-1); + decode10(buf, n, 6); + *(buf - 1) = *buf; + *buf = '0'; + buf += 6; + + FEED_BITS(16); + i -= 16; + n = (d >> i) & 0xffff; + if(n < 38400) { + int dd, mm, yy; + dd = n % 32; + n /= 32; + mm = n % 12 + 1; + n /= 12; + yy = n; + PUSH_CHAR('1'); + PUSH_CHAR('0' + ((enc - 6) | 1)); + decode10(buf, yy, 2); + buf += 2; + decode10(buf, mm, 2); + buf += 2; + decode10(buf, dd, 2); + buf += 2; + } + else if(n > 38400) + return(-1); + } + + if(enc < 4) { + /* remainder is general-purpose data compaction */ + int scheme = SCH_NUM; + while(i > 0 || len > 0) { + FEED_BITS(8); + dbprintf(2, " [%d+%d]", i, len); + + if(scheme == SCH_NUM) { + int n1; + i -= 4; + if(i < 0) + break; + if(!((d >> i) & 0xf)) { + scheme = SCH_ALNUM; + dbprintf(2, ">A"); + continue; + } + if(!len && i < 3) { + /* special case last digit */ + n = ((d >> i) & 0xf) - 1; + if(n > 9) + return(-1); + *(buf++) = '0' + n; + break; + } + i -= 3; + zassert(i >= 0, -1, "\n"); + n = ((d >> i) & 0x7f) - 8; + n1 = n % 11; + n = n / 11; + dbprintf(2, "N%d%d", n, n1); + *(buf++) = (n < 10) ? '0' + n : GS; + *(buf++) = (n1 < 10) ? '0' + n1 : GS; + } + else { + unsigned c = 0; + i -= 3; + if(i < 0) + break; + if(!((d >> i) & 0x7)) { + scheme = SCH_NUM; + continue; + } + i -= 2; + if(i < 0) + break; + n = (d >> i) & 0x1f; + if(n == 0x04) { + scheme ^= 0x3; + dbprintf(2, ">%d", scheme); + } + else if(n == 0x0f) + c = GS; + else if(n < 0x0f) + c = 43 + n; + else if(scheme == SCH_ALNUM) { + i--; + if(i < 0) + return(-1); + n = (d >> i) & 0x1f; + if(n < 0x1a) + c = 'A' + n; + else if(n == 0x1a) + c = '*'; + else if(n < 0x1f) + c = ',' + n - 0x1b; + else + return(-1); + } + else if(scheme == SCH_ISO646 && n < 0x1d) { + i -= 2; + if(i < 0) + return(-1); + n = (d >> i) & 0x3f; + if(n < 0x1a) + c = 'A' + n; + else if(n < 0x34) + c = 'a' + n - 0x1a; + else + return(-1); + } + else if(scheme == SCH_ISO646) { + i -= 3; + if(i < 0) + return(-1); + n = ((d >> i) & 0x1f); + dbprintf(2, "(%02x)", n); + if(n < 0xa) + c = '!' + n - 8; + else if(n < 0x15) + c = '%' + n - 0xa; + else if(n < 0x1b) + c = ':' + n - 0x15; + else if(n == 0x1b) + c = '_'; + else if(n == 0x1c) + c = ' '; + else + return(-1); + } + else + return(-1); + + if(c) { + dbprintf(2, "%d%c", scheme, c); + *(buf++) = c; + } + } + } + /* FIXME check pad? */ + } + + i = buf - dcode->buf; + zassert(i < dcode->buf_alloc, -1, "i=%02x %s\n", i, + _zbar_decoder_buf_dump(dcode->buf, i)); + + *buf = 0; + dcode->buflen = i; + if(i && *--buf == GS) { + *buf = 0; + dcode->buflen--; + } + + dbprintf(2, "\n %s", _zbar_decoder_buf_dump(dcode->buf, dcode->buflen)); + return(0); +} +#undef FEED_BITS + +/* convert from heterogeneous base {1597,2841} + * to base 10 character representation + */ +static inline void +databar_postprocess (zbar_decoder_t *dcode, + unsigned d[4]) +{ + databar_decoder_t *db = &dcode->databar; + int i; + unsigned c, chk = 0; + unsigned char *buf = dcode->buf; + *(buf++) = '0'; + *(buf++) = '1'; + buf += 15; + *--buf = '\0'; + *--buf = '\0'; + + dbprintf(2, "\n d={%d,%d,%d,%d}", d[0], d[1], d[2], d[3]); + unsigned long r = d[0] * 1597 + d[1]; + d[1] = r / 10000; + r %= 10000; + r = r * 2841 + d[2]; + d[2] = r / 10000; + r %= 10000; + r = r * 1597 + d[3]; + d[3] = r / 10000; + dbprintf(2, " r=%ld", r); + + for(i = 4; --i >= 0; ) { + c = r % 10; + chk += c; + if(i & 1) + chk += c << 1; + *--buf = c + '0'; + if(i) + r /= 10; + } + + dbprintf(2, " d={%d,%d,%d}", d[1], d[2], d[3]); + r = d[1] * 2841 + d[2]; + d[2] = r / 10000; + r %= 10000; + r = r * 1597 + d[3]; + d[3] = r / 10000; + dbprintf(2, " r=%ld", r); + + for(i = 4; --i >= 0; ) { + c = r % 10; + chk += c; + if(i & 1) + chk += c << 1; + *--buf = c + '0'; + if(i) + r /= 10; + } + + r = d[2] * 1597 + d[3]; + dbprintf(2, " d={%d,%d} r=%ld", d[2], d[3], r); + + for(i = 5; --i >= 0; ) { + c = r % 10; + chk += c; + if(!(i & 1)) + chk += c << 1; + *--buf = c + '0'; + if(i) + r /= 10; + } + + /* NB linkage flag not supported */ + if(TEST_CFG(db->config, ZBAR_CFG_EMIT_CHECK)) { + chk %= 10; + if(chk) + chk = 10 - chk; + buf[13] = chk + '0'; + dcode->buflen = buf - dcode->buf + 14; + } + else + dcode->buflen = buf - dcode->buf + 13; + + dbprintf(2, "\n %s", _zbar_decoder_buf_dump(dcode->buf, 16)); +} + +static inline int +databar_check_width (unsigned wf, + unsigned wd, + unsigned n) +{ + unsigned dwf = wf * 3; + wd *= 14; + wf *= n; + return(wf - dwf <= wd && wd <= wf + dwf); +} + +static inline void +merge_segment (databar_decoder_t *db, + databar_segment_t *seg) +{ + unsigned csegs = db->csegs; + int i; + for(i = 0; i < csegs; i++) { + databar_segment_t *s = db->segs + i; + if(s != seg && s->finder == seg->finder && s->exp == seg->exp && + s->color == seg->color && s->side == seg->side && + s->data == seg->data && s->check == seg->check && + databar_check_width(seg->width, s->width, 14)) { + /* merge with existing segment */ + unsigned cnt = s->count; + if(cnt < 0x7f) + cnt++; + seg->count = cnt; + seg->partial &= s->partial; + seg->width = (3 * seg->width + s->width + 2) / 4; + s->finder = -1; + dbprintf(2, " dup@%d(%d,%d)", + i, cnt, (db->epoch - seg->epoch) & 0xff); + } + else if(s->finder >= 0) { + unsigned age = (db->epoch - s->epoch) & 0xff; + if(age >= 248 || (age >= 128 && s->count < 2)) + s->finder = -1; + } + } +} + +static inline zbar_symbol_type_t +match_segment (zbar_decoder_t *dcode, + databar_segment_t *seg) +{ + databar_decoder_t *db = &dcode->databar; + unsigned csegs = db->csegs, maxage = 0xfff; + int i0, i1, i2, maxcnt = 0; + databar_segment_t *smax[3] = { NULL, }; + + if(seg->partial && seg->count < 4) + return(ZBAR_PARTIAL); + + for(i0 = 0; i0 < csegs; i0++) { + databar_segment_t *s0 = db->segs + i0; + if(s0 == seg || s0->finder != seg->finder || s0->exp || + s0->color != seg->color || s0->side == seg->side || + (s0->partial && s0->count < 4) || + !databar_check_width(seg->width, s0->width, 14)) + continue; + + for(i1 = 0; i1 < csegs; i1++) { + databar_segment_t *s1 = db->segs + i1; + int chkf, chks, chk; + unsigned age1; + if(i1 == i0 || s1->finder < 0 || s1->exp || + s1->color == seg->color || + (s1->partial && s1->count < 4) || + !databar_check_width(seg->width, s1->width, 14)) + continue; + dbprintf(2, "\n\t[%d,%d] f=%d(0%xx)/%d(%x%x%x)", + i0, i1, seg->finder, seg->color, + s1->finder, s1->exp, s1->color, s1->side); + + if(seg->color) + chkf = seg->finder + s1->finder * 9; + else + chkf = s1->finder + seg->finder * 9; + if(chkf > 72) + chkf--; + if(chkf > 8) + chkf--; + + chks = (seg->check + s0->check + s1->check) % 79; + + if(chkf >= chks) + chk = chkf - chks; + else + chk = 79 + chkf - chks; + + dbprintf(2, " chk=(%d,%d) => %d", chkf, chks, chk); + age1 = (((db->epoch - s0->epoch) & 0xff) + + ((db->epoch - s1->epoch) & 0xff)); + + for(i2 = i1 + 1; i2 < csegs; i2++) { + databar_segment_t *s2 = db->segs + i2; + unsigned cnt, age2, age; + if(i2 == i0 || s2->finder != s1->finder || s2->exp || + s2->color != s1->color || s2->side == s1->side || + s2->check != chk || + (s2->partial && s2->count < 4) || + !databar_check_width(seg->width, s2->width, 14)) + continue; + age2 = (db->epoch - s2->epoch) & 0xff; + age = age1 + age2; + cnt = s0->count + s1->count + s2->count; + dbprintf(2, " [%d] MATCH cnt=%d age=%d", i2, cnt, age); + if(maxcnt < cnt || + (maxcnt == cnt && maxage > age)) { + maxcnt = cnt; + maxage = age; + smax[0] = s0; + smax[1] = s1; + smax[2] = s2; + } + } + } + } + + if(!smax[0]) + return(ZBAR_PARTIAL); + + unsigned d[4]; + d[(seg->color << 1) | seg->side] = seg->data; + for(i0 = 0; i0 < 3; i0++) { + d[(smax[i0]->color << 1) | smax[i0]->side] = smax[i0]->data; + if(!--(smax[i0]->count)) + smax[i0]->finder = -1; + } + seg->finder = -1; + + if(size_buf(dcode, 18)) + return(ZBAR_PARTIAL); + + if(acquire_lock(dcode, ZBAR_DATABAR)) + return(ZBAR_PARTIAL); + + databar_postprocess(dcode, d); + dcode->modifiers = MOD(ZBAR_MOD_GS1); + dcode->direction = 1 - 2 * (seg->side ^ seg->color ^ 1); + return(ZBAR_DATABAR); +} + +static inline unsigned +lookup_sequence (databar_segment_t *seg, + int fixed, + int seq[22]) +{ + unsigned n = seg->data / 211, i; + const unsigned char *p; + i = (n + 1) / 2 + 1; + n += 4; + i = (i * i) / 4; + dbprintf(2, " {%d,%d:", i, n); + p = exp_sequences + i; + + fixed >>= 1; + seq[0] = 0; + seq[1] = 1; + for(i = 2; i < n; ) { + int s = *p; + if(!(i & 2)) { + p++; + s >>= 4; + } + else + s &= 0xf; + if(s == fixed) + fixed = -1; + s <<= 1; + dbprintf(2, "%x", s); + seq[i++] = s++; + seq[i++] = s; + } + dbprintf(2, "}"); + seq[n] = -1; + return(fixed < 1); +} + +#define IDX(s) \ + (((s)->finder << 2) | ((s)->color << 1) | ((s)->color ^ (s)->side)) + +static inline zbar_symbol_type_t +match_segment_exp (zbar_decoder_t *dcode, + databar_segment_t *seg, + int dir) +{ + databar_decoder_t *db = &dcode->databar; + int bestsegs[22], i = 0, segs[22], seq[22]; + int ifixed = seg - db->segs, fixed = IDX(seg), maxcnt = 0; + int iseg[DATABAR_MAX_SEGMENTS]; + unsigned csegs = db->csegs, width = seg->width, maxage = 0x7fff; + + bestsegs[0] = segs[0] = seq[1] = -1; + seq[0] = 0; + + dbprintf(2, "\n fixed=%d@%d: ", fixed, ifixed); + for(i = csegs, seg = db->segs + csegs - 1; --i >= 0; seg--) { + if(seg->exp && seg->finder >= 0 && + (!seg->partial || seg->count >= 4)) + iseg[i] = IDX(seg); + else + iseg[i] = -1; + dbprintf(2, " %d", iseg[i]); + } + + for(i = 0; ; i--) { + if(!i) + dbprintf(2, "\n "); + for(; i >= 0 && seq[i] >= 0; i--) { + int j; + dbprintf(2, " [%d]%d", i, seq[i]); + + if(seq[i] == fixed) { + seg = db->segs + ifixed; + if(segs[i] < 0 && databar_check_width(width, seg->width, 14)) { + dbprintf(2, "*"); + j = ifixed; + } + else + continue; + } + else { + for(j = segs[i] + 1; j < csegs; j++) { + if(iseg[j] == seq[i] && + (!i || databar_check_width(width, db->segs[j].width, 14))) { + seg = db->segs + j; + break; + } + } + if(j == csegs) + continue; + } + + if(!i) { + if(!lookup_sequence(seg, fixed, seq)) { + dbprintf(2, "[nf]"); + continue; + } + width = seg->width; + dbprintf(2, " A00@%d", j); + } + else { + width = (width + seg->width) / 2; + dbprintf(2, " %c%x%x@%d", + 'A' + seg->finder, seg->color, seg->side, j); + } + segs[i++] = j; + segs[i++] = -1; + } + if(i < 0) + break; + + seg = db->segs + segs[0]; + unsigned cnt = 0, chk = 0, age = (db->epoch - seg->epoch) & 0xff; + for(i = 1; segs[i] >= 0; i++) { + seg = db->segs + segs[i]; + chk += seg->check; + cnt += seg->count; + age += (db->epoch - seg->epoch) & 0xff; + } + + unsigned data0 = db->segs[segs[0]].data; + unsigned chk0 = data0 % 211; + chk %= 211; + + dbprintf(2, " chk=%d ?= %d", chk, chk0); + if(chk != chk0) + continue; + + dbprintf(2, " cnt=%d age=%d", cnt, age); + if(maxcnt > cnt || (maxcnt == cnt && maxage <= age)) + continue; + + dbprintf(2, " !"); + maxcnt = cnt; + maxage = age; + for(i = 0; segs[i] >= 0; i++) + bestsegs[i] = segs[i]; + bestsegs[i] = -1; + } + + if(bestsegs[0] < 0) + return(ZBAR_PARTIAL); + + if(acquire_lock(dcode, ZBAR_DATABAR_EXP)) + return(ZBAR_PARTIAL); + + for(i = 0; bestsegs[i] >= 0; i++) + segs[i] = db->segs[bestsegs[i]].data; + + if(databar_postprocess_exp(dcode, segs)) { + release_lock(dcode, ZBAR_DATABAR_EXP); + return(ZBAR_PARTIAL); + } + + for(i = 0; bestsegs[i] >= 0; i++) + if(bestsegs[i] != ifixed) { + seg = db->segs + bestsegs[i]; + if(!--seg->count) + seg->finder = -1; + } + + /* FIXME stacked rows are frequently reversed, + * so direction is impossible to determine at this level + */ + dcode->direction = (1 - 2 * (seg->side ^ seg->color)) * dir; + dcode->modifiers = MOD(ZBAR_MOD_GS1); + return(ZBAR_DATABAR_EXP); +} +#undef IDX + +static inline unsigned +databar_calc_check (unsigned sig0, + unsigned sig1, + unsigned side, + unsigned mod) +{ + unsigned chk = 0; + int i; + for(i = 4; --i >= 0; ) { + chk = (chk * 3 + (sig1 & 0xf) + 1) * 3 + (sig0 & 0xf) + 1; + sig1 >>= 4; + sig0 >>= 4; + if(!(i & 1)) + chk %= mod; + } + dbprintf(2, " chk=%d", chk); + + if(side) + chk = (chk * (6561 % mod)) % mod; + return(chk); +} + +static inline int +calc_value4 (unsigned sig, + unsigned n, + unsigned wmax, + unsigned nonarrow) +{ + unsigned v = 0; + n--; + + unsigned w0 = (sig >> 12) & 0xf; + if(w0 > 1) { + if(w0 > wmax) + return(-1); + unsigned n0 = n - w0; + unsigned sk20 = (n - 1) * n * (2 * n - 1); + unsigned sk21 = n0 * (n0 + 1) * (2 * n0 + 1); + v = sk20 - sk21 - 3 * (w0 - 1) * (2 * n - w0); + + if(!nonarrow && w0 > 2 && n > 4) { + unsigned k = (n - 2) * (n - 1) * (2 * n - 3) - sk21; + k -= 3 * (w0 - 2) * (14 * n - 7 * w0 - 31); + v -= k; + } + + if(n - 2 > wmax) { + unsigned wm20 = 2 * wmax * (wmax + 1); + unsigned wm21 = (2 * wmax + 1); + unsigned k = sk20; + if(n0 > wmax) { + k -= sk21; + k += 3 * (w0 - 1) * (wm20 - wm21 * (2 * n - w0)); + } + else { + k -= (wmax + 1) * (wmax + 2) * (2 * wmax + 3); + k += 3 * (n - wmax - 2) * (wm20 - wm21 * (n + wmax + 1)); + } + k *= 3; + v -= k; + } + v /= 12; + } + else + nonarrow = 1; + n -= w0; + + unsigned w1 = (sig >> 8) & 0xf; + if(w1 > 1) { + if(w1 > wmax) + return(-1); + v += (2 * n - w1) * (w1 - 1) / 2; + if(!nonarrow && w1 > 2 && n > 3) + v -= (2 * n - w1 - 5) * (w1 - 2) / 2; + if(n - 1 > wmax) { + if(n - w1 > wmax) + v -= (w1 - 1) * (2 * n - w1 - 2 * wmax); + else + v -= (n - wmax) * (n - wmax - 1); + } + } + else + nonarrow = 1; + n -= w1; + + unsigned w2 = (sig >> 4) & 0xf; + if(w2 > 1) { + if(w2 > wmax) + return(-1); + v += w2 - 1; + if(!nonarrow && w2 > 2 && n > 2) + v -= n - 2; + if(n > wmax) + v -= n - wmax; + } + else + nonarrow = 1; + + unsigned w3 = sig & 0xf; + if(w3 == 1) + nonarrow = 1; + else if(w3 > wmax) + return(-1); + + if(!nonarrow) + return(-1); + + return(v); +} + +static inline zbar_symbol_type_t +decode_char (zbar_decoder_t *dcode, + databar_segment_t *seg, + int off, + int dir) +{ + databar_decoder_t *db = &dcode->databar; + unsigned s = calc_s(dcode, (dir > 0) ? off : off - 6, 8); + int n, i, emin[2] = { 0, }, sum = 0; + unsigned sig0 = 0, sig1 = 0; + + if(seg->exp) + n = 17; + else if(seg->side) + n = 15; + else + n = 16; + emin[1] = -n; + + dbprintf(2, "\n char[%c%d]: n=%d s=%d w=%d sig=", + (dir < 0) ? '>' : '<', off, n, s, seg->width); + if(s < 13 || !databar_check_width(seg->width, s, n)) + return(ZBAR_NONE); + + for(i = 4; --i >= 0; ) { + int e = decode_e(pair_width(dcode, off), s, n); + if(e < 0) + return(ZBAR_NONE); + dbprintf(2, "%d", e); + sum = e - sum; + off += dir; + sig1 <<= 4; + if(emin[1] < -sum) + emin[1] = -sum; + sig1 += sum; + if(!i) + break; + + e = decode_e(pair_width(dcode, off), s, n); + if(e < 0) + return(ZBAR_NONE); + dbprintf(2, "%d", e); + sum = e - sum; + off += dir; + sig0 <<= 4; + if(emin[0] > sum) + emin[0] = sum; + sig0 += sum; + } + + int diff = emin[~n & 1]; + diff = diff + (diff << 4); + diff = diff + (diff << 8); + + sig0 -= diff; + sig1 += diff; + + dbprintf(2, " emin=%d,%d el=%04x/%04x", emin[0], emin[1], sig0, sig1); + + unsigned sum0 = sig0 + (sig0 >> 8); + unsigned sum1 = sig1 + (sig1 >> 8); + sum0 += sum0 >> 4; + sum1 += sum1 >> 4; + sum0 &= 0xf; + sum1 &= 0xf; + + dbprintf(2, " sum=%d/%d", sum0, sum1); + + if(sum0 + sum1 + 8 != n) { + dbprintf(2, " [SUM]"); + return(ZBAR_NONE); + } + + if(((sum0 ^ (n >> 1)) | (sum1 ^ (n >> 1) ^ n)) & 1) { + dbprintf(2, " [ODD]"); + return(ZBAR_NONE); + } + + i = ((n & 0x3) ^ 1) * 5 + (sum1 >> 1); + zassert(i < sizeof(groups) / sizeof(*groups), -1, + "n=%d sum=%d/%d sig=%04x/%04x g=%d", + n, sum0, sum1, sig0, sig1, i); + struct group_s *g = groups + i; + dbprintf(2, "\n g=%d(%d,%d,%d/%d)", + i, g->sum, g->wmax, g->todd, g->teven); + + int vodd = calc_value4(sig0 + 0x1111, sum0 + 4, g->wmax, ~n & 1); + dbprintf(2, " v=%d", vodd); + if(vodd < 0 || vodd > g->todd) + return(ZBAR_NONE); + + int veven = calc_value4(sig1 + 0x1111, sum1 + 4, 9 - g->wmax, n & 1); + dbprintf(2, "/%d", veven); + if(veven < 0 || veven > g->teven) + return(ZBAR_NONE); + + int v = g->sum; + if(n & 2) + v += vodd + veven * g->todd; + else + v += veven + vodd * g->teven; + + dbprintf(2, " f=%d(%x%x%x)", seg->finder, seg->exp, seg->color, seg->side); + + unsigned chk = 0; + if(seg->exp) { + unsigned side = seg->color ^ seg->side ^ 1; + if(v >= 4096) + return(ZBAR_NONE); + /* skip A1 left */ + chk = databar_calc_check(sig0, sig1, side, 211); + if(seg->finder || seg->color || seg->side) { + i = (seg->finder << 1) - side + seg->color; + zassert(i >= 0 && i < 12, ZBAR_NONE, + "f=%d(%x%x%x) side=%d i=%d\n", + seg->finder, seg->exp, seg->color, seg->side, side, i); + chk = (chk * exp_checksums[i]) % 211; + } + else if(v >= 4009) + return(ZBAR_NONE); + else + chk = 0; + } + else { + chk = databar_calc_check(sig0, sig1, seg->side, 79); + if(seg->color) + chk = (chk * 16) % 79; + } + dbprintf(2, " => %d val=%d", chk, v); + + seg->check = chk; + seg->data = v; + + merge_segment(db, seg); + + if(seg->exp) + return(match_segment_exp(dcode, seg, dir)); + else if(dir > 0) + return(match_segment(dcode, seg)); + return(ZBAR_PARTIAL); +} + +static inline int +alloc_segment (databar_decoder_t *db) +{ + unsigned maxage = 0, csegs = db->csegs; + int i, old = -1; + for(i = 0; i < csegs; i++) { + databar_segment_t *seg = db->segs + i; + unsigned age; + if(seg->finder < 0) { + dbprintf(2, " free@%d", i); + return(i); + } + age = (db->epoch - seg->epoch) & 0xff; + if(age >= 128 && seg->count < 2) { + seg->finder = -1; + dbprintf(2, " stale@%d (%d - %d = %d)", + i, db->epoch, seg->epoch, age); + return(i); + } + + /* score based on both age and count */ + if(age > seg->count) + age = age - seg->count + 1; + else + age = 1; + + if(maxage < age) { + maxage = age; + old = i; + dbprintf(2, " old@%d(%u)", i, age); + } + } + + if(csegs < DATABAR_MAX_SEGMENTS) { + dbprintf(2, " new@%d", i); + i = csegs; + csegs *= 2; + if(csegs > DATABAR_MAX_SEGMENTS) + csegs = DATABAR_MAX_SEGMENTS; + if(csegs != db->csegs) { + databar_segment_t *seg; + db->segs = realloc(db->segs, csegs * sizeof(*db->segs)); + db->csegs = csegs; + seg = db->segs + csegs; + while(--seg, --csegs >= i) { + seg->finder = -1; + seg->exp = 0; + seg->color = 0; + seg->side = 0; + seg->partial = 0; + seg->count = 0; + seg->epoch = 0; + seg->check = 0; + } + return(i); + } + } + zassert(old >= 0, -1, "\n"); + + db->segs[old].finder = -1; + return(old); +} + +static inline zbar_symbol_type_t +decode_finder (zbar_decoder_t *dcode) +{ + databar_decoder_t *db = &dcode->databar; + databar_segment_t *seg; + unsigned e0 = pair_width(dcode, 1); + unsigned e2 = pair_width(dcode, 3); + unsigned e1, e3, s, finder, dir; + int sig, iseg; + dbprintf(2, " databar: e0=%d e2=%d", e0, e2); + if(e0 < e2) { + unsigned e = e2 * 4; + if(e < 15 * e0 || e > 34 * e0) + return(ZBAR_NONE); + dir = 0; + e3 = pair_width(dcode, 4); + } + else { + unsigned e = e0 * 4; + if(e < 15 * e2 || e > 34 * e2) + return(ZBAR_NONE); + dir = 1; + e2 = e0; + e3 = pair_width(dcode, 0); + } + e1 = pair_width(dcode, 2); + + s = e1 + e3; + dbprintf(2, " e1=%d e3=%d dir=%d s=%d", e1, e3, dir, s); + if(s < 12) + return(ZBAR_NONE); + + sig = ((decode_e(e3, s, 14) << 8) | (decode_e(e2, s, 14) << 4) | + decode_e(e1, s, 14)); + dbprintf(2, " sig=%04x", sig & 0xfff); + if(sig < 0 || + ((sig >> 4) & 0xf) < 8 || + ((sig >> 4) & 0xf) > 10 || + (sig & 0xf) >= 10 || + ((sig >> 8) & 0xf) >= 10 || + (((sig >> 8) + sig) & 0xf) != 10) + return(ZBAR_NONE); + + finder = (finder_hash[(sig - (sig >> 5)) & 0x1f] + + finder_hash[(sig >> 1) & 0x1f]) & 0x1f; + dbprintf(2, " finder=%d", finder); + if(finder == 0x1f || + !TEST_CFG((finder < 9) ? db->config : db->config_exp, ZBAR_CFG_ENABLE)) + return(ZBAR_NONE); + + zassert(finder >= 0, ZBAR_NONE, "dir=%d sig=%04x f=%d\n", + dir, sig & 0xfff, finder); + + iseg = alloc_segment(db); + if(iseg < 0) + return(ZBAR_NONE); + + seg = db->segs + iseg; + seg->finder = (finder >= 9) ? finder - 9 : finder; + seg->exp = (finder >= 9); + seg->color = get_color(dcode) ^ dir ^ 1; + seg->side = dir; + seg->partial = 0; + seg->count = 1; + seg->width = s; + seg->epoch = db->epoch; + + int rc = decode_char(dcode, seg, 12 - dir, -1); + if(!rc) + seg->partial = 1; + else + db->epoch++; + + int i = (dcode->idx + 8 + dir) & 0xf; + zassert(db->chars[i] == -1, ZBAR_NONE, "\n"); + db->chars[i] = iseg; + return(rc); +} + +zbar_symbol_type_t +_zbar_decode_databar (zbar_decoder_t *dcode) +{ + databar_decoder_t *db = &dcode->databar; + databar_segment_t *seg, *pair; + zbar_symbol_type_t sym; + int iseg, i = dcode->idx & 0xf; + + sym = decode_finder(dcode); + dbprintf(2, "\n"); + + iseg = db->chars[i]; + if(iseg < 0) + return(sym); + + db->chars[i] = -1; + seg = db->segs + iseg; + dbprintf(2, " databar: i=%d part=%d f=%d(%x%x%x)", + iseg, seg->partial, seg->finder, seg->exp, seg->color, seg->side); + zassert(seg->finder >= 0, ZBAR_NONE, "i=%d f=%d(%x%x%x) part=%x\n", + iseg, seg->finder, seg->exp, seg->color, seg->side, seg->partial); + + if(seg->partial) { + pair = NULL; + seg->side = !seg->side; + } + else { + int jseg = alloc_segment(db); + pair = db->segs + iseg; + seg = db->segs + jseg; + seg->finder = pair->finder; + seg->exp = pair->exp; + seg->color = pair->color; + seg->side = !pair->side; + seg->partial = 0; + seg->count = 1; + seg->width = pair->width; + seg->epoch = db->epoch; + } + + sym = decode_char(dcode, seg, 1, 1); + if(!sym) { + seg->finder = -1; + if(pair) + pair->partial = 1; + } + else + db->epoch++; + dbprintf(2, "\n"); + + return(sym); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code39.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define NUM_CHARS (0x2c) + +static const unsigned char code39_hi[32] = { + 0x80 | 0x00, /* 2 next */ + 0x40 | 0x02, /* 4 */ + 0x80 | 0x06, /* 2 next */ + 0xc0 | 0x08, /* 2 skip */ + 0x40 | 0x0a, /* 4 */ + 0x80 | 0x0e, /* 2 next */ + 0xc0 | 0x10, /* 2 skip */ + 0x00 | 0x12, /* direct */ + + 0x80 | 0x13, /* 2 next */ + 0xc0 | 0x15, /* 2 skip */ + 0x80 | 0x17, /* 2 next */ + 0xff, + 0xc0 | 0x19, /* 2 skip */ + 0x00 | 0x1b, /* direct */ + 0xff, + 0xff, + + 0x40 | 0x1c, /* 4 */ + 0x80 | 0x20, /* 2 next */ + 0xc0 | 0x22, /* 2 skip */ + 0x00 | 0x24, /* direct */ + 0x80 | 0x25, /* 2 next */ + 0xff, + 0x00 | 0x27, /* direct */ + 0xff, + + 0xc0 | 0x28, /* 2 skip */ + 0x00 | 0x2a, /* direct */ + 0xff, + 0xff, + 0x00 | 0x2b, /* direct */ + 0xff, + 0xff, + 0xff, +}; + +typedef struct char39_s { + unsigned char chk, rev, fwd; +} char39_t; + +static const char39_t code39_encodings[NUM_CHARS] = { + { 0x07, 0x1a, 0x20 }, /* 00 */ + { 0x0d, 0x10, 0x03 }, /* 01 */ + { 0x13, 0x17, 0x22 }, /* 02 */ + { 0x16, 0x1d, 0x23 }, /* 03 */ + { 0x19, 0x0d, 0x05 }, /* 04 */ + { 0x1c, 0x13, 0x06 }, /* 05 */ + { 0x25, 0x07, 0x0c }, /* 06 */ + { 0x2a, 0x2a, 0x27 }, /* 07 */ + { 0x31, 0x04, 0x0e }, /* 08 */ + { 0x34, 0x00, 0x0f }, /* 09 */ + { 0x43, 0x15, 0x25 }, /* 0a */ + { 0x46, 0x1c, 0x26 }, /* 0b */ + { 0x49, 0x0b, 0x08 }, /* 0c */ + { 0x4c, 0x12, 0x09 }, /* 0d */ + { 0x52, 0x19, 0x2b }, /* 0e */ + { 0x58, 0x0f, 0x00 }, /* 0f */ + { 0x61, 0x02, 0x11 }, /* 10 */ + { 0x64, 0x09, 0x12 }, /* 11 */ + { 0x70, 0x06, 0x13 }, /* 12 */ + { 0x85, 0x24, 0x16 }, /* 13 */ + { 0x8a, 0x29, 0x28 }, /* 14 */ + { 0x91, 0x21, 0x18 }, /* 15 */ + { 0x94, 0x2b, 0x19 }, /* 16 */ + { 0xa2, 0x28, 0x29 }, /* 17 */ + { 0xa8, 0x27, 0x2a }, /* 18 */ + { 0xc1, 0x1f, 0x1b }, /* 19 */ + { 0xc4, 0x26, 0x1c }, /* 1a */ + { 0xd0, 0x23, 0x1d }, /* 1b */ + { 0x03, 0x14, 0x1e }, /* 1c */ + { 0x06, 0x1b, 0x1f }, /* 1d */ + { 0x09, 0x0a, 0x01 }, /* 1e */ + { 0x0c, 0x11, 0x02 }, /* 1f */ + { 0x12, 0x18, 0x21 }, /* 20 */ + { 0x18, 0x0e, 0x04 }, /* 21 */ + { 0x21, 0x01, 0x0a }, /* 22 */ + { 0x24, 0x08, 0x0b }, /* 23 */ + { 0x30, 0x05, 0x0d }, /* 24 */ + { 0x42, 0x16, 0x24 }, /* 25 */ + { 0x48, 0x0c, 0x07 }, /* 26 */ + { 0x60, 0x03, 0x10 }, /* 27 */ + { 0x81, 0x1e, 0x14 }, /* 28 */ + { 0x84, 0x25, 0x15 }, /* 29 */ + { 0x90, 0x22, 0x17 }, /* 2a */ + { 0xc0, 0x20, 0x1a }, /* 2b */ +}; + +static const unsigned char code39_characters[NUM_CHARS] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*"; + +static inline unsigned char code39_decode1 (unsigned char enc, + unsigned e, + unsigned s) +{ + unsigned char E = decode_e(e, s, 72); + if(E > 18) + return(0xff); + enc <<= 1; + if(E > 6) { + enc |= 1; + dbprintf(2, "1"); + } + else + dbprintf(2, "0"); + return(enc); +} + +static inline signed char code39_decode9 (zbar_decoder_t *dcode) +{ + code39_decoder_t *dcode39 = &dcode->code39; + + if(dcode39->s9 < 9) + return(-1); + + /* threshold bar width ratios */ + unsigned char i, enc = 0; + for(i = 0; i < 5; i++) { + enc = code39_decode1(enc, get_width(dcode, i), dcode39->s9); + if(enc == 0xff) + return(-1); + } + zassert(enc < 0x20, -1, " enc=%x s9=%x\n", enc, dcode39->s9); + + /* lookup first 5 encoded widths for coarse decode */ + unsigned char idx = code39_hi[enc]; + if(idx == 0xff) + return(-1); + + /* encode remaining widths (NB first encoded width is lost) */ + for(; i < 9; i++) { + enc = code39_decode1(enc, get_width(dcode, i), dcode39->s9); + if(enc == 0xff) + return(-1); + } + + if((idx & 0xc0) == 0x80) + idx = (idx & 0x3f) + ((enc >> 3) & 1); + else if((idx & 0xc0) == 0xc0) + idx = (idx & 0x3f) + ((enc >> 2) & 1); + else if(idx & 0xc0) + idx = (idx & 0x3f) + ((enc >> 2) & 3); + zassert(idx < 0x2c, -1, " idx=%x enc=%x s9=%x\n", idx, enc, dcode39->s9); + + const char39_t *c = &code39_encodings[idx]; + dbprintf(2, " i=%02x chk=%02x c=%02x/%02x", idx, c->chk, c->fwd, c->rev); + if(enc != c->chk) + return(-1); + + dcode39->width = dcode39->s9; + return((dcode39->direction) ? c->rev : c->fwd); +} + +static inline signed char code39_decode_start (zbar_decoder_t *dcode) +{ + code39_decoder_t *dcode39 = &dcode->code39; + dbprintf(2, " s=%d ", dcode39->s9); + + signed char c = code39_decode9(dcode); + if(c != 0x19 && c != 0x2b) { + dbprintf(2, "\n"); + return(ZBAR_NONE); + } + dcode39->direction ^= (c == 0x19); + + /* check leading quiet zone - spec is 10x */ + unsigned quiet = get_width(dcode, 9); + if(quiet && quiet < dcode39->s9 / 2) { + dbprintf(2, " [invalid quiet]\n"); + return(ZBAR_NONE); + } + + dcode39->element = 9; + dcode39->character = 0; + dbprintf(1, " dir=%x [valid start]\n", dcode39->direction); + return(ZBAR_PARTIAL); +} + +static inline int code39_postprocess (zbar_decoder_t *dcode) +{ + code39_decoder_t *dcode39 = &dcode->code39; + dcode->direction = 1 - 2 * dcode39->direction; + int i; + if(dcode39->direction) { + /* reverse buffer */ + dbprintf(2, " (rev)"); + for(i = 0; i < dcode39->character / 2; i++) { + unsigned j = dcode39->character - 1 - i; + char code = dcode->buf[i]; + dcode->buf[i] = dcode->buf[j]; + dcode->buf[j] = code; + } + } + for(i = 0; i < dcode39->character; i++) + dcode->buf[i] = ((dcode->buf[i] < 0x2b) + ? code39_characters[(unsigned)dcode->buf[i]] + : '?'); + zassert(i < dcode->buf_alloc, -1, "i=%02x %s\n", i, + _zbar_decoder_buf_dump(dcode->buf, dcode39->character)); + dcode->buflen = i; + dcode->buf[i] = '\0'; + dcode->modifiers = 0; + return(0); +} + +static inline int +c39_check_width (unsigned ref, + unsigned w) +{ + unsigned dref = ref; + ref *= 4; + w *= 4; + return(ref - dref <= w && w <= ref + dref); +} + +zbar_symbol_type_t _zbar_decode_code39 (zbar_decoder_t *dcode) +{ + code39_decoder_t *dcode39 = &dcode->code39; + + /* update latest character width */ + dcode39->s9 -= get_width(dcode, 9); + dcode39->s9 += get_width(dcode, 0); + + if(dcode39->character < 0) { + if(get_color(dcode) != ZBAR_BAR) + return(ZBAR_NONE); + dbprintf(2, " code39:"); + return(code39_decode_start(dcode)); + } + + if(++dcode39->element < 9) + return(ZBAR_NONE); + + dbprintf(2, " code39[%c%02d+%x]", + (dcode39->direction) ? '<' : '>', + dcode39->character, dcode39->element); + + if(dcode39->element == 10) { + unsigned space = get_width(dcode, 0); + if(dcode39->character && + dcode->buf[dcode39->character - 1] == 0x2b) { /* STOP */ + /* trim STOP character */ + dcode39->character--; + zbar_symbol_type_t sym = ZBAR_NONE; + + /* trailing quiet zone check */ + if(space && space < dcode39->width / 2) + dbprintf(2, " [invalid qz]\n"); + else if(dcode39->character < CFG(*dcode39, ZBAR_CFG_MIN_LEN) || + (CFG(*dcode39, ZBAR_CFG_MAX_LEN) > 0 && + dcode39->character > CFG(*dcode39, ZBAR_CFG_MAX_LEN))) + dbprintf(2, " [invalid len]\n"); + else if(!code39_postprocess(dcode)) { + /* FIXME checksum */ + dbprintf(2, " [valid end]\n"); + sym = ZBAR_CODE39; + } + dcode39->character = -1; + if(!sym) + release_lock(dcode, ZBAR_CODE39); + return(sym); + } + if(space > dcode39->width / 2) { + /* inter-character space check failure */ + dbprintf(2, " ics>%d [invalid ics]", dcode39->width); + if(dcode39->character) + release_lock(dcode, ZBAR_CODE39); + dcode39->character = -1; + } + dcode39->element = 0; + dbprintf(2, "\n"); + return(ZBAR_NONE); + } + + dbprintf(2, " s=%d ", dcode39->s9); + if(!c39_check_width(dcode39->width, dcode39->s9)) { + dbprintf(2, " [width]\n"); + if(dcode39->character) + release_lock(dcode, ZBAR_CODE39); + dcode39->character = -1; + return(ZBAR_NONE); + } + + signed char c = code39_decode9(dcode); + dbprintf(2, " c=%d", c); + + /* lock shared resources */ + if(!dcode39->character && acquire_lock(dcode, ZBAR_CODE39)) { + dcode39->character = -1; + return(ZBAR_PARTIAL); + } + + if(c < 0 || size_buf(dcode, dcode39->character + 1)) { + dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n"); + release_lock(dcode, ZBAR_CODE39); + dcode39->character = -1; + return(ZBAR_NONE); + } + else { + zassert(c < 0x2c, ZBAR_NONE, "c=%02x s9=%x\n", c, dcode39->s9); + dbprintf(2, "\n"); + } + + dcode->buf[dcode39->character++] = c; + + return(ZBAR_NONE); +} + +#undef NUM_CHARS + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code93.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +static const signed char code93_hash[0x40] = { + 0x0f, 0x2b, 0x30, 0x38, 0x13, 0x1b, 0x11, 0x2a, + 0x0a, -1, 0x2f, 0x0f, 0x38, 0x38, 0x2f, 0x37, + 0x24, 0x3a, 0x1b, 0x36, 0x18, 0x26, 0x02, 0x2c, + 0x2b, 0x05, 0x21, 0x3b, 0x04, 0x15, 0x12, 0x0c, + 0x00, 0x26, 0x23, 0x00, -1, 0x2e, 0x3f, 0x13, + 0x2e, 0x36, -1, 0x08, 0x09, -1, 0x15, 0x14, + -1, 0x00, 0x21, 0x3b, -1, 0x33, 0x00, -1, + 0x2d, 0x0c, 0x1b, 0x0a, 0x3f, 0x3f, 0x29, 0x1c, +}; + +static inline int +c93_check_width (unsigned cur, + unsigned prev) +{ + unsigned dw; + if(prev > cur) + dw = prev - cur; + else + dw = cur - prev; + dw *= 4; + return(dw > prev); +} + +static inline int +encode6 (zbar_decoder_t *dcode) +{ + /* build edge signature of character */ + unsigned s = dcode->s6; + int sig = 0, i; + + dbprintf(2, " s=%d ", s); + if(s < 9) + return(-1); + + for(i = 6; --i > 0; ) { + unsigned c = decode_e(pair_width(dcode, i), s, 9); + if(c > 3) + return(-1); + sig = (sig << 2) | c; + dbprintf(2, "%d", c); + } + dbprintf(2, " sig=%03x", sig); + + return(sig); +} + +static inline int +validate_sig (int sig) +{ + int i, sum = 0, emin = 0, sig0 = 0, sig1 = 0; + dbprintf(3, " sum=0"); + for(i = 3; --i >= 0; ) { + int e = sig & 3; + sig >>= 2; + sum = e - sum; + sig1 <<= 4; + sig1 += sum; + dbprintf(3, "%d", sum); + if(!i) + break; + + e = sig & 3; + sig >>= 2; + sum = e - sum; + sig0 <<= 4; + if(emin > sum) + emin = sum; + sig0 += sum; + dbprintf(3, "%d", sum); + } + + dbprintf(3, " emin=%d sig=%03x/%03x", emin, sig1 & 0xfff, sig0 & 0xfff); + + emin = emin + (emin << 4) + (emin << 8); + sig0 -= emin; + sig1 += emin; + + dbprintf(3, "=%03x/%03x", sig1 & 0xfff, sig0 & 0xfff); + return((sig0 | sig1) & 0x888); +} + +static inline int +c93_decode6 (zbar_decoder_t *dcode) +{ + int sig = encode6(dcode); + int g0, g1, c; + if(sig < 0 || + (sig & 0x3) + ((sig >> 4) & 0x3) + ((sig >> 8) & 0x3) != 3 || + validate_sig(sig)) + return(-1); + + if(dcode->code93.direction) { + /* reverse signature */ + unsigned tmp = sig & 0x030; + sig = ((sig & 0x3c0) >> 6) | ((sig & 0x00f) << 6); + sig = ((sig & 0x30c) >> 2) | ((sig & 0x0c3) << 2) | tmp; + } + + g0 = code93_hash[(sig - (sig >> 4)) & 0x3f]; + g1 = code93_hash[((sig >> 2) - (sig >> 7)) & 0x3f]; + zassert(g0 >= 0 && g1 >= 0, -1, + "dir=%x sig=%03x g0=%03x g1=%03x %s\n", + dcode->code93.direction, sig, g0, g1, + _zbar_decoder_buf_dump(dcode->buf, dcode->code93.character)); + + c = (g0 + g1) & 0x3f; + dbprintf(2, " g0=%x g1=%x c=%02x", g0, g1, c); + return(c); +} + +static inline zbar_symbol_type_t +decode_start (zbar_decoder_t *dcode) +{ + code93_decoder_t *dcode93 = &dcode->code93; + unsigned dir, qz, s = dcode->s6; + int c; + + dbprintf(2, " code93:"); + c = encode6(dcode); + if(c < 0 || (c != 0x00f && c != 0x0f0)) + return(ZBAR_NONE); + + dir = (c >> 7); + + if(dir) { + if(decode_e(pair_width(dcode, 0), s, 9)) + return(ZBAR_NONE); + qz = get_width(dcode, 8); + } + + qz = get_width(dcode, 7); + if(qz && qz < (s * 3) / 4) { + dbprintf(2, " [invalid qz %d]", qz); + return(ZBAR_NONE); + } + + /* decoded valid start/stop - initialize state */ + dcode93->direction = dir; + dcode93->element = (!dir) ? 0 : 7; + dcode93->character = 0; + dcode93->width = s; + + dbprintf(2, " dir=%x [valid start]", dir); + return(ZBAR_PARTIAL); +} + +static inline zbar_symbol_type_t +decode_abort (zbar_decoder_t *dcode, + const char *reason) +{ + code93_decoder_t *dcode93 = &dcode->code93; + if(dcode93->character > 1) + release_lock(dcode, ZBAR_CODE93); + dcode93->character = -1; + if(reason) + dbprintf(1, " [%s]\n", reason); + return(ZBAR_NONE); +} + +static inline zbar_symbol_type_t +check_stop (zbar_decoder_t *dcode) +{ + code93_decoder_t *dcode93 = &dcode->code93; + unsigned n = dcode93->character, s = dcode->s6; + int max_len = CFG(*dcode93, ZBAR_CFG_MAX_LEN); + if(n < 2 || + n < CFG(*dcode93, ZBAR_CFG_MIN_LEN) || + (max_len && n > max_len)) + return(decode_abort(dcode, "invalid len")); + + if(dcode93->direction) { + unsigned qz = get_width(dcode, 0); + if(qz && qz < (s * 3) / 4) + return(decode_abort(dcode, "invalid qz")); + } + else if(decode_e(pair_width(dcode, 0), s, 9)) + /* FIXME forward-trailing QZ check */ + return(decode_abort(dcode, "invalid stop")); + + return(ZBAR_CODE93); +} + +#define CHKMOD (47) + +static inline int +plusmod47 (int acc, + int add) +{ + acc += add; + if(acc >= CHKMOD) + acc -= CHKMOD; + return(acc); +} + +static inline int +validate_checksums (zbar_decoder_t *dcode) +{ + code93_decoder_t *dcode93 = &dcode->code93; + unsigned d, i, n = dcode93->character; + unsigned sum_c = 0, acc_c = 0, i_c = (n - 2) % 20; + unsigned sum_k = 0, acc_k = 0, i_k = (n - 1) % 15; + + for(i = 0; i < n - 2; i++) { + d = dcode->buf[(dcode93->direction) ? n - 1 - i : i]; + + if(!i_c--) { + acc_c = 0; + i_c = 19; + } + acc_c = plusmod47(acc_c, d); + sum_c = plusmod47(sum_c, acc_c); + + if(!i_k--) { + acc_k = 0; + i_k = 14; + } + acc_k = plusmod47(acc_k, d); + sum_k = plusmod47(sum_k, acc_k); + } + + d = dcode->buf[(dcode93->direction) ? 1 : n - 2]; + dbprintf(2, " C=%02x?=%02x", d, sum_c); + if(d != sum_c) + return(1); + + acc_k = plusmod47(acc_k, sum_c); + sum_k = plusmod47(sum_k, acc_k); + d = dcode->buf[(dcode93->direction) ? 0 : n - 1]; + dbprintf(2, " K=%02x?=%02x", d, sum_k); + if(d != sum_k) + return(1); + + return(0); +} + +/* resolve scan direction and convert to ASCII */ +static inline int +c93_postprocess (zbar_decoder_t *dcode) +{ + code93_decoder_t *dcode93 = &dcode->code93; + unsigned i, j, n = dcode93->character; + static const unsigned char code93_graph[] = "-. $/+%"; + static const unsigned char code93_s2[] = + "\x1b\x1c\x1d\x1e\x1f;<=>?[\\]^_{|}~\x7f\x00\x40`\x7f\x7f\x7f"; + + dbprintf(2, "\n postproc len=%d", n); + dcode->direction = 1 - 2 * dcode93->direction; + if(dcode93->direction) { + /* reverse buffer */ + dbprintf(2, " (rev)"); + for(i = 0; i < n / 2; i++) { + unsigned j = n - 1 - i; + unsigned char d = dcode->buf[i]; + dcode->buf[i] = dcode->buf[j]; + dcode->buf[j] = d; + } + } + + n -= 2; + for(i = 0, j = 0; i < n; ) { + unsigned char d = dcode->buf[i++]; + if(d < 0xa) + d = '0' + d; + else if(d < 0x24) + d = 'A' + d - 0xa; + else if(d < 0x2b) + d = code93_graph[d - 0x24]; + else { + unsigned shift = d; + zassert(shift < 0x2f, -1, "%s\n", + _zbar_decoder_buf_dump(dcode->buf, dcode93->character)); + d = dcode->buf[i++]; + if(d < 0xa || d >= 0x24) + return(1); + d -= 0xa; + switch(shift) + { + case 0x2b: d++; break; + case 0x2c: d = code93_s2[d]; break; + case 0x2d: d += 0x21; break; + case 0x2e: d += 0x61; break; + default: return(1); + } + } + dcode->buf[j++] = d; + } + + zassert(j < dcode->buf_alloc, 1, + "j=%02x %s\n", j, + _zbar_decoder_buf_dump(dcode->buf, dcode->code93.character)); + dcode->buflen = j; + dcode->buf[j] = '\0'; + dcode->modifiers = 0; + return(0); +} + +zbar_symbol_type_t +_zbar_decode_code93 (zbar_decoder_t *dcode) +{ + code93_decoder_t *dcode93 = &dcode->code93; + int c; + + if(dcode93->character < 0) { + zbar_symbol_type_t sym; + if(get_color(dcode) != ZBAR_BAR) + return(ZBAR_NONE); + sym = decode_start(dcode); + dbprintf(2, "\n"); + return(sym); + } + + if(/* process every 6th element of active symbol */ + ++dcode93->element != 6 || + /* decode color based on direction */ + get_color(dcode) == dcode93->direction) + return(ZBAR_NONE); + + dcode93->element = 0; + + dbprintf(2, " code93[%c%02d+%x]:", + (dcode93->direction) ? '<' : '>', + dcode93->character, dcode93->element); + + if(c93_check_width(dcode->s6, dcode93->width)) + return(decode_abort(dcode, "width var")); + + c = c93_decode6(dcode); + if(c < 0) + return(decode_abort(dcode, "aborted")); + + if(c == 0x2f) { + if(!check_stop(dcode)) + return(ZBAR_NONE); + if(validate_checksums(dcode)) + return(decode_abort(dcode, "checksum error")); + if(c93_postprocess(dcode)) + return(decode_abort(dcode, "invalid encoding")); + + dbprintf(2, " [valid end]\n"); + dbprintf(3, " %s\n", + _zbar_decoder_buf_dump(dcode->buf, dcode93->character)); + + dcode93->character = -1; + return(ZBAR_CODE93); + } + + if(size_buf(dcode, dcode93->character + 1)) + return(decode_abort(dcode, "overflow")); + + dcode93->width = dcode->s6; + + if(dcode93->character == 1) { + /* lock shared resources */ + if(acquire_lock(dcode, ZBAR_CODE93)) + return(decode_abort(dcode, NULL)); + dcode->buf[0] = dcode93->buf; + } + + if(!dcode93->character) + dcode93->buf = c; + else + dcode->buf[dcode93->character] = c; + dcode93->character++; + + dbprintf(2, "\n"); + return(ZBAR_NONE); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "code128.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define NUM_CHARS 108 /* total number of character codes */ + +typedef enum code128_char_e { + FNC3 = 0x60, + FNC2 = 0x61, + SHIFT = 0x62, + CODE_C = 0x63, + CODE_B = 0x64, + CODE_A = 0x65, + FNC1 = 0x66, + START_A = 0x67, + START_B = 0x68, + START_C = 0x69, + STOP_FWD = 0x6a, + STOP_REV = 0x6b, + FNC4 = 0x6c, +} code128_char_t; + +static const unsigned char characters[NUM_CHARS] = { + 0x5c, 0xbf, 0xa1, /* [00] 00 */ + 0x2a, 0xc5, 0x0c, 0xa4, /* [03] 01 */ + 0x2d, 0xe3, 0x0f, /* [07] 02 */ + 0x5f, 0xe4, /* [0a] 03 */ + + 0x6b, 0xe8, 0x69, 0xa7, 0xe7, /* [0c] 10 */ + 0xc1, 0x51, 0x1e, 0x83, 0xd9, 0x00, 0x84, 0x1f, /* [11] 11 */ + 0xc7, 0x0d, 0x33, 0x86, 0xb5, 0x0e, 0x15, 0x87, /* [19] 12 */ + 0x10, 0xda, 0x11, /* [21] 13 */ + + 0x36, 0xe5, 0x18, 0x37, /* [24] 20 */ + 0xcc, 0x13, 0x39, 0x89, 0x97, 0x14, 0x1b, 0x8a, 0x3a, 0xbd, /* [28] 21 */ + 0xa2, 0x5e, 0x01, 0x85, 0xb0, 0x02, 0xa3, /* [32] 22 */ + 0xa5, 0x2c, 0x16, 0x88, 0xbc, 0x12, 0xa6, /* [39] 23 */ + + 0x61, 0xe6, 0x56, 0x62, /* [40] 30 */ + 0x19, 0xdb, 0x1a, /* [44] 31 */ + 0xa8, 0x32, 0x1c, 0x8b, 0xcd, 0x1d, 0xa9, /* [47] 32 */ + 0xc3, 0x20, 0xc4, /* [4e] 33 */ + + 0x50, 0x5d, 0xc0, /* [51] 0014 0025 0034 */ + 0x2b, 0xc6, /* [54] 0134 0143 */ + 0x2e, /* [56] 0243 */ + 0x53, 0x60, /* [57] 0341 0352 */ + 0x31, /* [59] 1024 */ + 0x52, 0xc2, /* [5a] 1114 1134 */ + 0x34, 0xc8, /* [5c] 1242 1243 */ + 0x55, /* [5e] 1441 */ + + 0x57, 0x3e, 0xce, /* [5f] 4100 5200 4300 */ + 0x3b, 0xc9, /* [62] 4310 3410 */ + 0x6a, /* [64] 3420 */ + 0x54, 0x4f, /* [65] 1430 2530 */ + 0x38, /* [67] 4201 */ + 0x58, 0xcb, /* [68] 4111 4311 */ + 0x2f, 0xca, /* [6a] 2421 3421 */ +}; + +static const unsigned char lo_base[8] = { + 0x00, 0x07, 0x0c, 0x19, 0x24, 0x32, 0x40, 0x47 +}; + +static const unsigned char lo_offset[0x80] = { + 0xff, 0xf0, 0xff, 0x1f, 0xff, 0xf2, 0xff, 0xff, /* 00 [00] */ + 0xff, 0xff, 0xff, 0x3f, 0xf4, 0xf5, 0xff, 0x6f, /* 01 */ + 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf1, 0xff, 0x2f, /* 02 [07] */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x4f, /* 03 */ + 0xff, 0x0f, 0xf1, 0xf2, 0xff, 0x3f, 0xff, 0xf4, /* 10 [0c] */ + 0xf5, 0xf6, 0xf7, 0x89, 0xff, 0xab, 0xff, 0xfc, /* 11 */ + 0xff, 0xff, 0x0f, 0x1f, 0x23, 0x45, 0xf6, 0x7f, /* 12 [19] */ + 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xf9, 0xaf, /* 13 */ + + 0xf0, 0xf1, 0xff, 0x2f, 0xff, 0xf3, 0xff, 0xff, /* 20 [24] */ + 0x4f, 0x5f, 0x67, 0x89, 0xfa, 0xbf, 0xff, 0xcd, /* 21 */ + 0xf0, 0xf1, 0xf2, 0x3f, 0xf4, 0x56, 0xff, 0xff, /* 22 [32] */ + 0xff, 0xff, 0x7f, 0x8f, 0x9a, 0xff, 0xbc, 0xdf, /* 23 */ + 0x0f, 0x1f, 0xf2, 0xff, 0xff, 0x3f, 0xff, 0xff, /* 30 [40] */ + 0xf4, 0xff, 0xf5, 0x6f, 0xff, 0xff, 0xff, 0xff, /* 31 */ + 0x0f, 0x1f, 0x23, 0xff, 0x45, 0x6f, 0xff, 0xff, /* 32 [47] */ + 0xf7, 0xff, 0xf8, 0x9f, 0xff, 0xff, 0xff, 0xff, /* 33 */ +}; + +static inline signed char decode_lo (int sig) +{ + unsigned char offset = (((sig >> 1) & 0x01) | + ((sig >> 3) & 0x06) | + ((sig >> 5) & 0x18) | + ((sig >> 7) & 0x60)); + unsigned char idx = lo_offset[offset]; + unsigned char base, c; + + if(sig & 1) + idx &= 0xf; + else + idx >>= 4; + if(idx == 0xf) + return(-1); + + base = (sig >> 11) | ((sig >> 9) & 1); + zassert(base < 8, -1, "sig=%x offset=%x idx=%x base=%x\n", + sig, offset, idx, base); + idx += lo_base[base]; + + zassert(idx <= 0x50, -1, "sig=%x offset=%x base=%x idx=%x\n", + sig, offset, base, idx); + c = characters[idx]; + dbprintf(2, " %02x(%x(%02x)/%x(%02x)) => %02x", + idx, base, lo_base[base], offset, lo_offset[offset], + (unsigned char)c); + return(c); +} + +static inline signed char decode_hi (int sig) +{ + unsigned char rev = (sig & 0x4400) != 0; + unsigned char idx, c; + if(rev) + sig = (((sig >> 12) & 0x000f) | + ((sig >> 4) & 0x00f0) | + ((sig << 4) & 0x0f00) | + ((sig << 12) & 0xf000)); + dbprintf(2, " rev=%x", rev != 0); + + switch(sig) { + case 0x0014: idx = 0x0; break; + case 0x0025: idx = 0x1; break; + case 0x0034: idx = 0x2; break; + case 0x0134: idx = 0x3; break; + case 0x0143: idx = 0x4; break; + case 0x0243: idx = 0x5; break; + case 0x0341: idx = 0x6; break; + case 0x0352: idx = 0x7; break; + case 0x1024: idx = 0x8; break; + case 0x1114: idx = 0x9; break; + case 0x1134: idx = 0xa; break; + case 0x1242: idx = 0xb; break; + case 0x1243: idx = 0xc; break; + case 0x1441: idx = 0xd; rev = 0; break; + default: return(-1); + } + if(rev) + idx += 0xe; + c = characters[0x51 + idx]; + dbprintf(2, " %02x => %02x", idx, c); + return(c); +} + +static inline unsigned char calc_check (unsigned char c) +{ + if(!(c & 0x80)) + return(0x18); + c &= 0x7f; + if(c < 0x3d) + return((c < 0x30 && c != 0x17) ? 0x10 : 0x20); + if(c < 0x50) + return((c == 0x4d) ? 0x20 : 0x10); + return((c < 0x67) ? 0x20 : 0x10); +} + +static inline signed char decode6 (zbar_decoder_t *dcode) +{ + int sig; + signed char c, chk; + unsigned bars; + + /* build edge signature of character */ + unsigned s = dcode->code128.s6; + + dbprintf(2, " s=%d", s); + if(s < 5) + return(-1); + /* calculate similar edge measurements */ + sig = (get_color(dcode) == ZBAR_BAR) + ? ((decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 11) << 12) | + (decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 11) << 8) | + (decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 11) << 4) | + (decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 11))) + : ((decode_e(get_width(dcode, 5) + get_width(dcode, 4), s, 11) << 12) | + (decode_e(get_width(dcode, 4) + get_width(dcode, 3), s, 11) << 8) | + (decode_e(get_width(dcode, 3) + get_width(dcode, 2), s, 11) << 4) | + (decode_e(get_width(dcode, 2) + get_width(dcode, 1), s, 11))); + if(sig < 0) + return(-1); + dbprintf(2, " sig=%04x", sig); + /* lookup edge signature */ + c = (sig & 0x4444) ? decode_hi(sig) : decode_lo(sig); + if(c == -1) + return(-1); + + /* character validation */ + bars = (get_color(dcode) == ZBAR_BAR) + ? (get_width(dcode, 0) + get_width(dcode, 2) + get_width(dcode, 4)) + : (get_width(dcode, 1) + get_width(dcode, 3) + get_width(dcode, 5)); + bars = bars * 11 * 4 / s; + chk = calc_check(c); + dbprintf(2, " bars=%d chk=%d", bars, chk); + if(chk - 7 > bars || bars > chk + 7) + return(-1); + + return(c & 0x7f); +} + +static inline unsigned char validate_checksum (zbar_decoder_t *dcode) +{ + unsigned idx, sum, i, acc = 0; + unsigned char check, err; + + code128_decoder_t *dcode128 = &dcode->code128; + if(dcode128->character < 3) + return(1); + + /* add in irregularly weighted start character */ + idx = (dcode128->direction) ? dcode128->character - 1 : 0; + sum = dcode->buf[idx]; + if(sum >= 103) + sum -= 103; + + /* calculate sum in reverse to avoid multiply operations */ + for(i = dcode128->character - 3; i; i--) { + zassert(sum < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n", + dcode128->direction, i, sum, acc, + _zbar_decoder_buf_dump(dcode->buf, dcode128->character)); + idx = (dcode128->direction) ? dcode128->character - 1 - i : i; + acc += dcode->buf[idx]; + if(acc >= 103) + acc -= 103; + zassert(acc < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n", + dcode128->direction, i, sum, acc, + _zbar_decoder_buf_dump(dcode->buf, dcode128->character)); + sum += acc; + if(sum >= 103) + sum -= 103; + } + + /* and compare to check character */ + idx = (dcode128->direction) ? 1 : dcode128->character - 2; + check = dcode->buf[idx]; + dbprintf(2, " chk=%02x(%02x)", sum, check); + err = (sum != check); + if(err) + dbprintf(1, " [checksum error]\n"); + return(err); +} + +/* expand and decode character set C */ +static inline unsigned postprocess_c (zbar_decoder_t *dcode, + unsigned start, + unsigned end, + unsigned dst) +{ + unsigned i, j; + + /* expand buffer to accomodate 2x set C characters (2 digits per-char) */ + unsigned delta = end - start; + unsigned newlen = dcode->code128.character + delta; + size_buf(dcode, newlen); + + /* relocate unprocessed data to end of buffer */ + memmove(dcode->buf + start + delta, dcode->buf + start, + dcode->code128.character - start); + dcode->code128.character = newlen; + + for(i = 0, j = dst; i < delta; i++, j += 2) { + /* convert each set C character into two ASCII digits */ + unsigned char code = dcode->buf[start + delta + i]; + dcode->buf[j] = '0'; + if(code >= 50) { + code -= 50; + dcode->buf[j] += 5; + } + if(code >= 30) { + code -= 30; + dcode->buf[j] += 3; + } + if(code >= 20) { + code -= 20; + dcode->buf[j] += 2; + } + if(code >= 10) { + code -= 10; + dcode->buf[j] += 1; + } + zassert(dcode->buf[j] <= '9', delta, + "start=%x end=%x i=%x j=%x %s\n", start, end, i, j, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + zassert(code <= 9, delta, + "start=%x end=%x i=%x j=%x %s\n", start, end, i, j, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + dcode->buf[j + 1] = '0' + code; + } + return(delta); +} + +/* resolve scan direction and convert to ASCII */ +static inline unsigned char postprocess (zbar_decoder_t *dcode) +{ + unsigned i, j, cexp; + unsigned char code = 0, charset; + code128_decoder_t *dcode128 = &dcode->code128; + dbprintf(2, "\n postproc len=%d", dcode128->character); + dcode->modifiers = 0; + dcode->direction = 1 - 2 * dcode128->direction; + if(dcode128->direction) { + /* reverse buffer */ + dbprintf(2, " (rev)"); + for(i = 0; i < dcode128->character / 2; i++) { + unsigned j = dcode128->character - 1 - i; + code = dcode->buf[i]; + dcode->buf[i] = dcode->buf[j]; + dcode->buf[j] = code; + } + zassert(dcode->buf[dcode128->character - 1] == STOP_REV, 1, + "dir=%x %s\n", dcode128->direction, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + } + else + zassert(dcode->buf[dcode128->character - 1] == STOP_FWD, 1, + "dir=%x %s\n", dcode128->direction, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + + code = dcode->buf[0]; + zassert(code >= START_A && code <= START_C, 1, "%s\n", + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + + charset = code - START_A; + cexp = (code == START_C) ? 1 : 0; + dbprintf(2, " start=%c", 'A' + charset); + + for(i = 1, j = 0; i < dcode128->character - 2; i++) { + unsigned char code = dcode->buf[i]; + zassert(!(code & 0x80), 1, + "i=%x j=%x code=%02x charset=%x cexp=%x %s\n", + i, j, code, charset, cexp, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + + if((charset & 0x2) && (code < 100)) + /* defer character set C for expansion */ + continue; + else if(code < 0x60) { + /* convert character set B to ASCII */ + code = code + 0x20; + if((!charset || (charset == 0x81)) && (code >= 0x60)) + /* convert character set A to ASCII */ + code -= 0x60; + dcode->buf[j++] = code; + if(charset & 0x80) + charset &= 0x7f; + } + else { + dbprintf(2, " %02x", code); + if(charset & 0x2) { + unsigned delta; + /* expand character set C to ASCII */ + zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n", + i, j, code, charset, cexp, + _zbar_decoder_buf_dump(dcode->buf, + dcode->code128.character)); + delta = postprocess_c(dcode, cexp, i, j); + i += delta; + j += delta * 2; + cexp = 0; + } + if(code < CODE_C) { + if(code == SHIFT) + charset |= 0x80; + else if(code == FNC2) { + /* FIXME FNC2 - message append */ + } + else if(code == FNC3) { + /* FIXME FNC3 - initialize */ + } + } + else if(code == FNC1) { + /* FNC1 - Code 128 subsets or ASCII 0x1d */ + if(i == 1) + dcode->modifiers |= MOD(ZBAR_MOD_GS1); + else if(i == 2) + dcode->modifiers |= MOD(ZBAR_MOD_AIM); + else if(i < dcode->code128.character - 3) + dcode->buf[j++] = 0x1d; + /*else drop trailing FNC1 */ + } + else if(code >= START_A) { + dbprintf(1, " [truncated]\n"); + return(1); + } + else { + unsigned char newset = CODE_A - code; + zassert(code >= CODE_C && code <= CODE_A, 1, + "i=%x j=%x code=%02x charset=%x cexp=%x %s\n", + i, j, code, charset, cexp, + _zbar_decoder_buf_dump(dcode->buf, + dcode->code128.character)); + if(newset != charset) + charset = newset; + else { + /* FIXME FNC4 - extended ASCII */ + } + } + if(charset & 0x2) + cexp = i + 1; + } + } + if(charset & 0x2) { + zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n", + i, j, code, charset, cexp, + _zbar_decoder_buf_dump(dcode->buf, + dcode->code128.character)); + j += postprocess_c(dcode, cexp, i, j) * 2; + } + zassert(j < dcode->buf_alloc, 1, "j=%02x %s\n", j, + _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character)); + dcode->buflen = j; + dcode->buf[j] = '\0'; + dcode->code128.character = j; + return(0); +} + +zbar_symbol_type_t _zbar_decode_code128 (zbar_decoder_t *dcode) +{ + code128_decoder_t *dcode128 = &dcode->code128; + signed char c; + + /* update latest character width */ + dcode128->s6 -= get_width(dcode, 6); + dcode128->s6 += get_width(dcode, 0); + + if((dcode128->character < 0) + ? get_color(dcode) != ZBAR_SPACE + : (/* process every 6th element of active symbol */ + ++dcode128->element != 6 || + /* decode color based on direction */ + get_color(dcode) != dcode128->direction)) + return(0); + dcode128->element = 0; + + dbprintf(2, " code128[%c%02d+%x]:", + (dcode128->direction) ? '<' : '>', + dcode128->character, dcode128->element); + + c = decode6(dcode); + if(dcode128->character < 0) { + unsigned qz; + dbprintf(2, " c=%02x", c); + if(c < START_A || c > STOP_REV || c == STOP_FWD) { + dbprintf(2, " [invalid]\n"); + return(0); + } + qz = get_width(dcode, 6); + if(qz && qz < (dcode128->s6 * 3) / 4) { + dbprintf(2, " [invalid qz %d]\n", qz); + return(0); + } + /* decoded valid start/stop */ + /* initialize state */ + dcode128->character = 1; + if(c == STOP_REV) { + dcode128->direction = ZBAR_BAR; + dcode128->element = 7; + } + else + dcode128->direction = ZBAR_SPACE; + dcode128->start = c; + dcode128->width = dcode128->s6; + dbprintf(2, " dir=%x [valid start]\n", dcode128->direction); + return(0); + } + else if(c < 0 || size_buf(dcode, dcode128->character + 1)) { + dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n"); + if(dcode128->character > 1) + release_lock(dcode, ZBAR_CODE128); + dcode128->character = -1; + return(0); + } + else { + unsigned dw; + if(dcode128->width > dcode128->s6) + dw = dcode128->width - dcode128->s6; + else + dw = dcode128->s6 - dcode128->width; + dw *= 4; + if(dw > dcode128->width) { + dbprintf(1, " [width var]\n"); + if(dcode128->character > 1) + release_lock(dcode, ZBAR_CODE128); + dcode128->character = -1; + return(0); + } + } + dcode128->width = dcode128->s6; + + zassert(dcode->buf_alloc > dcode128->character, 0, + "alloc=%x idx=%x c=%02x %s\n", + dcode->buf_alloc, dcode128->character, c, + _zbar_decoder_buf_dump(dcode->buf, dcode->buf_alloc)); + + if(dcode128->character == 1) { + /* lock shared resources */ + if(acquire_lock(dcode, ZBAR_CODE128)) { + dcode128->character = -1; + return(0); + } + dcode->buf[0] = dcode128->start; + } + + dcode->buf[dcode128->character++] = c; + + if(dcode128->character > 2 && + ((dcode128->direction) + ? c >= START_A && c <= START_C + : c == STOP_FWD)) { + /* FIXME STOP_FWD should check extra bar (and QZ!) */ + zbar_symbol_type_t sym = ZBAR_CODE128; + if(validate_checksum(dcode) || postprocess(dcode)) + sym = ZBAR_NONE; + else if(dcode128->character < CFG(*dcode128, ZBAR_CFG_MIN_LEN) || + (CFG(*dcode128, ZBAR_CFG_MAX_LEN) > 0 && + dcode128->character > CFG(*dcode128, ZBAR_CFG_MAX_LEN))) { + dbprintf(2, " [invalid len]\n"); + sym = ZBAR_NONE; + } + else + dbprintf(2, " [valid end]\n"); + dcode128->character = -1; + if(!sym) + release_lock(dcode, ZBAR_CODE128); + return(sym); + } + + dbprintf(2, "\n"); + return(0); +} + +#undef NUM_CHARS + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "pdf417_hash.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +/* PDF417 bar to codeword decode table */ + +#define PDF417_HASH_MASK 0xfff + +static const signed short pdf417_hash[PDF417_HASH_MASK + 1] = { + 0x170, 0xd8e, 0x02e, 0x000, 0xa21, 0xc99, 0x000, 0xf06, + 0xdaa, 0x7a1, 0xc5f, 0x7ff, 0xbcf, 0xac8, 0x000, 0xc51, + 0x49a, 0x5c7, 0x000, 0xef2, 0x000, 0x7dd, 0x9ee, 0xe32, + 0x1b7, 0x489, 0x3b7, 0xe70, 0x9c8, 0xe5e, 0xdf4, 0x599, + 0x4e0, 0x608, 0x639, 0xead, 0x0ac, 0x57c, 0x000, 0x20d, + 0x61b, 0x000, 0x7d1, 0x80f, 0x803, 0x000, 0x946, 0x093, + 0x79c, 0xf9c, 0xb34, 0x6d8, 0x4f1, 0x975, 0x886, 0x313, + 0xe8a, 0xf20, 0x3c9, 0xa92, 0xb90, 0xa1d, 0x091, 0x0ac, + 0xb50, 0x3af, 0x90a, 0x45a, 0x815, 0xf29, 0xb20, 0xb6d, + 0xc5c, 0x1cd, 0x1e2, 0x1bf, 0x963, 0x80b, 0xa7c, 0x9b7, + 0xb65, 0x6b7, 0x117, 0xc04, 0x000, 0x18e, 0x000, 0x77f, + 0xe0e, 0xf48, 0x370, 0x818, 0x379, 0x000, 0x090, 0xe77, + 0xd99, 0x8b8, 0xb95, 0x8a9, 0x94c, 0xc48, 0x679, 0x000, + 0x41a, 0x9ea, 0xb0e, 0x9c1, 0x1b4, 0x000, 0x630, 0x811, + 0x4b1, 0xc05, 0x98f, 0xa68, 0x485, 0x706, 0xfff, 0x0d9, + 0xddc, 0x000, 0x83f, 0x54e, 0x290, 0xfe7, 0x64f, 0xf36, + 0x000, 0x151, 0xb9b, 0x5cd, 0x961, 0x690, -1, 0xa7a, + 0x328, 0x707, 0xe6d, 0xe1f, -1, 0x6a0, 0xf3e, 0xb27, + 0x315, 0xc8c, 0x6de, 0x996, 0x2f9, 0xc4c, 0x90f, -1, + 0xaa7, 0x9e9, 0xfff, 0x0bb, 0x33b, 0xbc6, 0xe17, 0x000, + 0x85d, 0x912, 0x5f7, 0x000, 0xff1, 0xba1, 0x086, 0xa1e, + 0x85a, 0x4cf, 0xd47, 0x5a9, 0x5dc, 0x0bc, -1, 0x544, + 0x522, 0x1ff, 0xfa6, 0xa83, 0xc7d, 0x545, 0xd75, 0xb6f, + 0x284, 0xf11, 0xe46, -1, 0x900, 0x0f3, 0xe31, 0x705, + 0x06d, 0xd59, 0x67b, 0xe56, -1, 0xde2, 0x000, 0xd42, + -1, 0x24b, 0x000, 0xf87, 0x842, -1, 0xbb9, 0x065, + 0x626, 0x86a, 0x9f8, -1, 0x7ac, 0xe20, 0xbe9, 0x357, + 0xfff, 0xf82, 0x219, 0x9d4, 0x269, 0x8a6, 0x251, 0x0af, + 0xd02, 0x09a, 0x803, 0x0a5, 0xfed, 0x278, -1, 0x338, + 0x1e5, 0xcad, 0xf9e, 0x73e, 0xb39, 0xe48, 0x754, -1, + 0x680, 0xd99, 0x4d4, 0x80b, 0x4be, 0xb0d, 0x5f2, -1, + 0x4b1, 0x38a, 0xff5, 0x000, 0xa1b, 0xece, 0xa06, 0x8e6, + 0xdcb, 0xcb8, 0xc63, 0x98c, 0x346, 0x69c, 0x299, 0xa52, + 0xfff, 0x000, -1, 0x7b2, 0xbf8, 0x2d1, 0xaff, 0x2f2, + 0xd69, 0xf20, -1, 0xdcf, 0x9fb, 0x68f, 0x24e, 0xfd7, + 0xfdb, 0x894, 0xc8f, 0x615, 0xa25, 0x36d, 0x1bb, 0x064, + 0xb80, 0x280, 0xd7a, -1, 0xd75, 0xc90, 0xdce, 0xdce, + 0x011, 0x869, 0xb2f, 0xd24, 0xe26, 0x492, 0xe0a, 0xcae, + -1, 0x2ac, 0x38c, 0x0b9, 0xc4f, -1, 0x32b, 0x415, + 0x49c, 0x11c, 0x816, 0xd08, 0xf5c, 0x356, 0x2b3, 0xfbf, + 0x7ff, 0x35d, 0x276, 0x292, 0x4f5, 0x0e2, 0xc68, 0x4c4, + 0x000, 0xb5e, 0xd0b, 0xca7, 0x624, 0x247, 0xf0d, 0x017, + 0x7ec, 0x2a6, 0x62c, 0x192, 0x610, 0xd98, 0x7a4, 0xfa3, + 0x80b, 0x043, 0xd7b, 0x301, 0x69d, 0x7e4, 0x10c, 0xacb, + 0x6eb, 0xea7, 0xe65, 0x75d, 0x4f5, 0x5b0, 0xa50, 0x7b6, + 0x0ec, -1, 0xcf9, 0x4b4, 0x639, 0x111, 0xbdf, 0xe89, + 0x9fa, 0x76b, 0xdf6, 0x2d0, 0x857, 0x3a3, 0x000, 0xa3e, + 0x8cb, 0x35f, 0x4f0, 0x022, 0xb38, 0xc12, 0x93c, 0x2fc, + 0x546, 0xe6e, 0x91f, 0x145, 0xfff, 0x1af, 0x957, 0xbde, + 0x09d, 0xfd2, 0x9df, 0x2dc, 0x07f, 0x115, 0x7bf, 0xa35, + 0x061, 0x9bf, 0xc85, 0x918, 0x0c8, 0x317, 0xce5, 0xf28, + 0x108, 0x51b, 0x621, 0x188, 0x000, 0x28c, 0xf67, 0x6ef, + 0x000, 0xd72, 0xce2, 0x1be, 0x000, 0x000, 0x282, 0x357, + -1, 0x4e5, 0x246, 0x859, 0x66c, 0x5d3, 0x9fd, 0x000, + 0x000, 0x82f, 0xc29, 0x331, 0xa93, 0x000, 0xae4, 0x48a, + 0x254, 0x000, 0x0ba, 0xe83, 0x7c7, 0xb6e, 0x88e, 0x774, + 0xf6f, 0x85d, 0x47f, 0xcd6, 0xe41, 0xdb6, 0x000, 0x0f4, + 0xb4d, 0x77f, 0x000, 0x901, 0x1a2, 0x44a, 0x482, 0x000, + 0xe99, 0xa75, 0x000, 0x7ab, 0x000, 0x0b6, 0x35c, 0x306, + 0x11c, 0x08e, 0x6eb, 0x11c, 0x771, 0xff9, 0x1c8, 0x63b, + 0x58b, 0x9d2, 0x250, 0x198, 0xfe7, 0xebc, 0x000, 0xa97, + 0xacc, 0xd4b, 0x28b, 0x892, 0x150, 0xcf4, 0xbc1, 0x000, + 0x662, 0xdd8, 0x61f, 0x903, 0x083, 0x000, 0xc55, 0x02f, + 0xc29, 0x4f5, 0xbcf, 0xe27, 0x9e3, 0xb13, 0xadc, 0x845, + 0x415, 0x0ae, 0x000, 0xe30, 0x931, 0x84a, 0xb09, 0x250, + 0x631, 0x7aa, 0x026, 0xdc9, 0x486, 0x3a7, 0xab0, 0xe04, + 0xe1a, 0xe17, 0x611, 0x556, 0xfac, 0x3c6, 0x5ab, 0x002, + 0xc16, 0xe60, -1, 0xc51, 0x772, 0x67f, 0xfa9, 0x83c, + 0x974, 0x96a, 0xe94, 0x250, 0xa20, 0xc95, 0x65b, 0x479, + 0xe48, 0xa35, 0x23f, 0x5cf, 0x40a, 0xcf0, 0xe82, 0x1da, + 0x390, 0xc86, 0xa92, 0x433, 0xbed, 0x4a7, 0x09a, 0x15a, + 0xb8d, 0x9c7, 0x5fb, 0x8a0, 0x000, 0xf9a, 0xf3c, 0x11c, + 0x20c, 0xf23, 0x79d, 0xc79, 0xb71, 0x7af, 0xc5b, 0x771, + 0x629, 0x834, 0xb34, 0x20c, 0x940, 0x2ca, 0x60b, 0x000, + 0x4cb, 0x70b, 0x000, 0x000, 0x9e8, 0x000, 0xdca, 0x000, + 0x1ae, 0xb21, 0xfe3, 0x191, 0x9e1, 0x7f6, 0x04f, 0x64a, + 0xba2, 0x59e, 0x1ae, 0x000, 0x728, 0x000, 0x081, 0xecd, + 0x946, 0x000, 0xdee, 0x3ff, 0xdf9, 0x1bf, 0x01a, 0x1a9, + 0xc58, 0xe05, 0x3bf, 0x5e8, 0x39d, 0xbfa, 0x23f, 0xb8d, + -1, 0x000, 0x779, 0x540, 0xf2c, 0x7cc, 0x340, 0x77a, + 0xa8e, 0xe8d, 0x2fd, 0xfed, 0x5d1, 0x308, 0x00f, 0xf4a, + 0x39b, 0xbe2, 0x0e5, -1, 0xf4d, 0x1fe, 0xf00, 0x867, + 0x195, 0x2de, 0x712, 0x000, 0x00c, 0x0a3, 0x1f3, 0x4ee, + 0x317, 0x665, 0x000, 0x5d8, 0x291, 0x6c4, 0xa46, 0x492, + 0x8d4, 0x647, 0x57f, 0x000, 0x259, 0xd87, 0x5c2, 0x1d8, + 0xfad, -1, -1, 0x79f, 0x43a, 0xfd1, 0x164, 0x6e1, + 0x350, 0xf00, 0x0e9, 0xac4, 0xe35, 0x307, 0xfff, 0xabb, + 0xc1a, 0x768, 0x000, 0x372, 0x839, 0xf4b, 0x1c3, 0xab0, + 0xcb6, 0x943, 0xbe9, 0x20f, 0xddc, 0xe18, 0x4eb, 0x21d, + 0x530, 0x24c, 0x000, 0xf79, -1, 0x1bd, -1, 0x155, + 0x435, -1, 0x132, 0x5c2, 0xb3d, 0x802, 0x733, -1, + 0x336, 0xf19, 0xfea, 0xd2a, 0x07f, 0x8e9, 0x000, 0xdab, + -1, 0x088, 0x4b1, 0x7ac, 0x000, 0xe66, 0xde0, 0x73c, + 0xfff, 0x02f, -1, 0x000, -1, 0x000, 0x562, 0x389, + 0xb20, 0x9ea, -1, 0x3f8, 0x567, 0x035, 0xa55, 0x255, + 0xc98, 0x65f, -1, 0x1ac, 0x571, 0x13d, 0xf57, 0x32a, + 0xbdb, 0x0ec, 0x47d, 0x43a, -1, 0x1aa, 0x9d6, 0x843, + -1, 0x244, 0xb03, 0xd0d, 0x579, 0x1b1, 0xea7, 0x000, + 0x062, -1, 0x533, 0x1db, 0xf1f, 0x2f7, 0x2df, 0x3e5, + 0xdec, 0xc5c, 0x55a, 0xf6c, 0x4c1, 0x5a8, 0xcd4, 0x6fd, + 0x1a6, 0x4b8, 0x98a, 0xe17, 0xeb9, 0xfd1, -1, 0x175, + 0x4d6, 0xba2, 0x000, 0x614, 0x147, 0x429, 0xfee, -1, + 0x0d8, -1, 0x98a, 0xdd2, 0xedd, 0x255, 0xef3, 0x345, + 0x000, 0xf3e, -1, -1, 0x210, 0x88a, 0x699, -1, + 0x02c, 0xfee, 0x1c1, 0xb38, 0x000, 0x7cc, 0x165, 0x536, + -1, 0x1ae, 0xefb, 0x734, -1, 0x1a4, 0x984, 0x804, + 0x487, -1, -1, 0x31e, 0x9f2, 0x966, 0x000, 0xcb0, + 0x552, 0x0c9, -1, 0x750, 0x650, 0x064, 0xffe, 0xe84, + 0x537, 0xee7, 0x834, -1, 0x998, 0xa03, -1, 0xcdf, + 0x4be, 0x310, 0x051, 0xf3f, 0x040, 0x973, 0x925, 0x000, + 0x000, 0xe51, 0x8b1, 0x468, 0xe11, 0xd4f, 0x374, 0x33a, + 0x126, 0x88b, 0x43a, 0xc9b, 0xdb9, 0x3c2, 0x3bd, 0x1ae, + 0x000, 0xc4a, 0x000, 0x4c4, 0x859, 0xe5a, 0x000, 0xeb4, + 0xd40, 0x87d, 0xc79, 0xe13, 0x50b, -1, 0x724, 0x000, + 0x7be, 0x062, 0xe7f, 0xad0, 0x5f3, 0x69e, 0x381, 0x272, + 0x50f, 0xac8, 0x053, 0x55e, 0xf19, 0xd71, 0x75b, 0xbf2, + 0x000, 0x3ac, 0xdf0, 0xd75, 0x7e3, 0xe75, 0xa13, 0xfd8, + 0xbdc, 0x1d9, 0x15f, 0x8cc, 0xba4, 0xb79, 0xb7f, 0x812, + 0xfe6, 0x000, 0x2d3, 0xd7b, 0x5d4, 0xad2, 0x316, 0x908, + 0x323, 0x758, 0xb0b, 0x965, 0x1a9, 0xdce, 0x660, 0x625, + 0xeff, 0x0ed, 0x000, 0x323, 0x986, 0x831, 0x5c5, 0x22f, + 0xd49, 0xec6, 0x90e, 0x234, 0x000, 0x80f, 0x16c, 0x528, + 0x1f8, 0x2bd, 0x97d, 0xe20, 0xf29, 0x97d, 0x3a0, 0x7fc, + 0x086, 0x720, 0x1f9, 0x3eb, 0xf67, 0x423, 0xa55, 0x69e, + 0xede, 0x206, 0x7fa, 0x809, 0xfa8, 0xe22, 0x15e, 0x2a0, + 0x04a, 0xf7b, 0x4ea, 0xd9a, -1, 0x1d8, 0x0b4, 0xb87, + 0x406, -1, 0xcdf, 0x187, 0xf6d, 0x914, 0x4b1, 0x000, + 0x104, 0x67e, 0xc74, 0x6da, 0xe67, 0x7d2, 0xd1f, 0x64c, + 0x19d, 0x000, 0xa17, 0xfd5, 0x000, 0x8ad, 0xf38, 0xd65, + 0xabd, 0x75e, 0x667, 0x632, 0x346, 0xc48, 0xa77, 0x45e, + 0x2b5, 0xded, 0x7da, 0x160, 0x560, -1, 0xf4e, 0xb0c, + 0xdb0, 0x287, 0x34a, 0x065, 0x439, 0x2ec, 0x679, 0xefa, + 0x208, 0xeb1, 0x1b0, 0x8c8, 0xca6, 0x62c, 0xa10, 0x673, + 0x000, 0x000, 0xc6a, 0x7b2, 0xbd7, 0xb2b, 0x17a, 0x6f3, + 0x1ab, 0xffa, 0x5e0, 0x1fa, 0xb8f, 0xe5c, 0xcab, 0xdbc, + 0x10f, 0x000, 0x000, 0xefe, 0x34b, 0x1d9, 0x834, 0x52f, + 0xb58, 0x82b, 0x6e8, 0x1f3, 0x719, 0x64e, 0xf55, 0xccd, + 0x531, 0x0de, 0x3aa, 0x150, 0x89a, 0x3b9, 0x26e, 0xebc, + 0x7ae, 0x670, 0x315, 0x8a9, 0x03b, 0x896, 0x247, 0x2f4, + 0x450, 0xd10, 0xb79, 0x0ed, 0x041, -1, 0x707, 0x9e1, + 0xed6, 0x6d2, 0x000, 0xfff, 0xb1a, 0x084, 0xaf3, 0x47f, + 0x02f, 0xac3, 0x751, 0x8c4, 0x291, 0xadd, 0x000, 0xea1, + 0x8ec, 0xf9f, 0x5c2, 0x000, 0xd6b, 0x71e, 0x000, 0xcea, + 0x971, 0x5f8, 0x4b9, 0x7c6, 0xb7e, 0x353, 0xd25, 0x423, + 0x6ec, 0xb71, 0xf93, 0x000, 0x795, 0xc43, 0xaa2, 0x96a, + 0xcbd, 0xb55, 0x184, 0xdf0, 0x3d9, 0xbfe, 0xf79, 0x8f0, + 0x22c, 0xeeb, 0x000, 0xa4b, 0xe07, 0xf34, 0xc9d, 0x4be, + 0x95b, 0x371, 0x78c, 0x9e9, 0xde6, 0x072, 0xf0d, 0x60b, + 0x5a5, 0xab1, 0x000, 0x260, 0x000, 0xd2a, 0xd90, 0x154, + 0x4c6, 0x438, 0x5d9, 0x736, 0x062, 0x000, 0x000, 0xb84, + 0x72e, 0x0b7, 0x000, 0x050, 0x063, 0xa95, 0x89b, 0x917, + 0x049, 0xb14, 0x9a0, 0x734, 0x0c3, 0xd50, 0x917, 0xb02, + 0x8cf, 0x453, 0x0af, 0x8e5, 0x000, 0x7aa, 0x5d5, 0x81b, + 0x788, 0xb9c, 0x01a, 0x974, 0x000, 0x000, 0x37f, 0xd9f, + 0x000, 0xec4, 0x4f4, 0xbff, 0x4fe, 0x860, 0x11c, 0x74e, + 0x34a, 0x281, 0x52f, 0xb05, 0xa89, 0xbee, 0x6ad, 0x9fc, + 0x9ba, 0xb0b, 0x515, 0x1c7, 0x330, 0xfde, 0x97e, 0x6e7, + 0xc45, -1, 0x658, 0x710, 0x28a, 0x921, 0x1de, 0x4a1, + 0x9d7, 0xe32, 0xa2d, 0xb0f, 0x545, 0xd6f, 0x329, 0x9b8, + 0xb4d, 0x9a0, 0x938, 0x783, 0xfa7, 0xd0a, 0xdc9, 0x0fe, + 0x000, 0x249, 0x000, 0x8cd, 0x922, 0x7cd, 0x021, 0xa89, + 0x3d5, 0xcee, 0x0a1, 0x6d6, 0x000, -1, 0x48b, 0x000, + 0x87a, 0x8bb, 0x9ed, 0x01f, 0xe20, 0xb7f, -1, 0xe95, + 0x593, 0x1da, 0x57a, -1, 0xf3a, 0x000, 0x000, -1, + -1, 0x160, 0x501, 0x7a3, 0xb59, -1, -1, 0xc7f, + -1, 0xf79, -1, -1, 0x48d, 0x781, -1, -1, + 0xb74, -1, 0x3c4, 0xbe9, -1, -1, 0x9a4, 0x9ae, + 0xa75, -1, -1, 0x9cd, 0x000, -1, -1, -1, + 0xc3c, 0x2d4, -1, 0x173, 0xf38, 0x000, -1, 0xee9, + -1, 0xb91, 0xcc1, 0x86d, 0x8ab, 0xeb0, 0xec7, 0x687, + 0xd98, 0xa95, 0x744, 0xe7c, 0x826, 0x80e, 0x599, 0x3d9, + 0xf2f, -1, 0x96a, 0xfd1, 0x174, -1, 0x000, 0x1aa, + 0x50e, -1, 0x5a2, 0xbcd, 0x000, -1, 0x019, 0x588, + 0x18d, 0x470, 0x812, 0xeec, 0xf63, 0x05c, -1, 0x000, + 0xb7f, 0x357, 0x436, 0xbb4, 0x1fb, 0x425, 0x1ed, 0xe13, + 0x66c, 0x555, 0xb11, 0x7b5, 0x48d, 0x38d, 0xf72, 0x000, + 0x000, 0xa66, 0x4fa, 0xf36, 0x1eb, 0x000, 0x95f, 0x000, + 0xd9a, 0x82f, 0x07f, 0x253, 0x70f, 0x915, -1, 0x12d, + 0x040, 0x2ca, 0x446, 0x90a, 0x7a8, 0x687, 0x000, 0x04e, + 0x74f, 0x1ca, 0x793, 0x3c7, 0x3f0, 0x4c7, 0x000, 0xc30, + 0x533, 0x889, 0x9ef, 0xebd, 0x984, 0x18f, 0xfe1, 0x8ea, + 0x185, 0x410, 0x107, 0x000, 0x73e, 0xd4b, 0x8fc, 0xd34, + 0x1e6, 0x4bf, 0xbac, 0x7c3, 0x000, 0x7c8, 0xb2f, 0x02c, + 0xa46, 0x000, 0x0f9, 0x680, 0x94d, 0x6ad, 0x767, 0xfeb, + 0x6c7, 0x2d5, 0x43f, 0x9af, 0x261, 0xe83, 0xfa7, 0xb7b, + 0xf2d, 0x2f5, 0x4d7, 0x494, 0xbc2, 0x45b, 0x000, 0x17d, + 0x5c6, 0xe2b, 0xb20, 0x19e, 0x6ba, 0x973, 0xedd, 0xea8, + 0x000, 0x9f3, 0xd9a, 0x7fa, 0xb78, 0x556, 0xbb6, 0xc58, + 0x210, 0x000, 0xf9a, 0x56d, 0x48b, 0xf12, 0x000, 0x54d, + 0x5f4, 0x1ad, 0x86e, 0xe16, 0x6ff, 0xa35, 0x47e, 0x4c7, + 0x93c, -1, -1, 0xc98, 0xd3f, 0x000, 0x788, 0x6ef, + 0x959, 0xec2, 0x45e, 0xa4d, 0xa90, 0x000, 0x768, 0x8bb, + 0x6ee, 0x7f5, 0x770, 0xfa8, 0xba4, 0xf49, 0x7b8, 0x616, + 0x2bd, 0x23f, 0xe8c, 0x9fa, 0xa49, 0x213, 0x98a, 0x2c1, + 0x595, 0x885, 0x6de, 0x057, 0x1bc, 0x000, 0xc58, 0x7a8, + 0x5c1, 0x3d0, 0xa78, 0xb80, 0x000, 0xc06, -1, 0x428, + 0xe92, 0xfa3, 0x341, -1, 0x000, 0x000, 0x1ca, 0x27c, + 0xdeb, 0x835, 0x4c8, 0xdb3, 0x000, 0xf9d, 0x000, 0xe81, + 0xc22, 0xfce, -1, 0xe6e, 0x96e, 0x161, -1, 0x3b9, + 0x945, 0xa95, 0x13d, 0x748, 0x184, 0x588, 0x636, 0xf7e, + 0xb44, 0x2b7, 0x217, 0xee5, 0x65a, 0xc47, -1, 0xca3, + 0x83e, 0x431, 0xc64, 0x636, 0x06e, 0x404, 0x993, -1, + 0xeb3, 0x134, 0x8a3, 0xca9, -1, -1, 0x2ab, 0x000, + 0x8ed, 0x877, 0x1a8, 0xc89, 0x000, 0x000, 0xf94, 0x000, + 0x709, 0x249, 0x9ac, 0x22a, 0x605, 0x000, 0x000, 0x6b4, + 0x00c, 0xc53, 0xf23, 0x005, 0x29f, 0x865, 0xf79, 0x000, + 0x5fa, 0x764, 0xe51, 0xbdc, 0xb64, 0x0f3, 0xf29, 0x2f7, + 0x5da, 0x000, 0x16f, 0xb8b, 0x255, 0x9cc, 0xe43, 0x279, + 0x2c2, 0x483, -1, 0xf7d, 0x7bb, 0x000, 0x9e3, 0xd84, + 0xe36, 0x6e6, 0x000, -1, 0x33f, 0x41d, 0x5b5, 0x83e, + 0x2f4, 0xf5b, 0x9fc, 0xb1e, -1, 0x8f4, 0xb26, 0x856, + 0x3b6, 0x126, 0x4c2, 0x274, 0x0c1, 0xfa9, 0x57d, 0x000, + 0x100, 0x7af, 0xc62, 0x000, 0xa55, 0x416, 0x93f, 0x78c, + 0xfba, 0x5a2, 0x0c2, 0x4d4, 0xa3e, 0xcc3, 0xe73, 0xd02, + 0x8df, 0x3e9, 0xe9a, 0x0f6, 0x32c, 0x23d, 0xdab, 0xf50, + 0xfc2, 0x000, 0x065, 0xc23, 0xd3d, 0xc84, 0x35e, 0x000, + 0xa24, 0x634, 0x4b4, 0xa52, 0x098, 0xb39, 0x9a4, 0xe71, + 0x8aa, 0x741, 0x000, 0xb16, 0x5c2, 0xea1, 0xc01, 0x5c1, + 0x30d, 0xca4, 0x201, 0xc9c, 0x717, 0x000, 0xba0, 0x537, + 0x619, 0x000, 0xfd9, 0x6dc, 0xdaa, 0x1da, 0xe51, 0xd39, + 0xb4c, 0x8a1, 0x098, 0x2f8, 0x191, 0x9dc, 0xdb0, 0x5e1, + 0x000, 0xe97, 0xef1, 0x8d3, 0xb0d, 0xfce, 0x336, 0xee1, + 0x7a2, 0xbc8, 0x494, 0x580, 0xba7, 0x000, 0x62a, 0x96a, + 0x527, 0x859, 0x811, 0xef0, 0x429, 0xef4, 0xf3d, 0x000, + 0x9d6, 0xb71, 0x000, 0x14b, 0xf3d, 0xb16, 0x204, 0x0c1, + 0xcd4, 0x339, 0x39d, 0xfe3, 0x837, 0x8c7, 0x955, 0x69a, + 0x5f6, 0x4c6, -1, 0x3d5, 0x000, 0x0e7, 0x4b1, -1, + 0xa3e, 0xb03, 0x1ea, 0xac8, -1, 0x000, 0xed8, -1, + 0x4e0, 0x9f7, 0xc91, 0x6b3, -1, -1, 0xa53, 0x290, + 0xa64, 0x0e3, 0x3dc, 0xed3, 0xf2f, 0x000, 0xd7c, 0xf44, + -1, 0x205, 0x900, 0x864, -1, -1, 0xed3, 0x7d2, + 0x000, -1, 0xdd2, 0x79b, 0x000, -1, 0xae6, 0x5cf, + 0xde8, 0x000, 0x1f2, -1, 0x2f3, 0x000, -1, 0x2ce, + 0xcf2, 0x8f4, 0xee8, 0x165, 0x309, 0x15f, -1, 0x714, + 0xbfc, 0x532, 0xad0, 0x151, 0x2d5, 0x0a4, 0x391, -1, + 0x0dc, 0x0c1, 0x451, -1, -1, 0x6a0, 0x250, -1, + 0xab8, 0x977, 0xa86, 0x407, 0x72f, -1, 0x05f, 0x000, + 0xefe, 0x950, 0x4f4, 0x957, -1, 0xd68, 0x26c, 0xa30, + 0x4f1, 0x279, 0x584, 0xb34, -1, 0x4d7, 0x258, 0x000, + 0x518, 0x685, 0x91c, 0x3ac, 0x0fa, -1, 0x979, 0x40c, + 0x506, 0x000, -1, 0x7bd, 0xb97, 0x87f, 0xc06, 0x050, + 0x7bf, 0xe3e, 0xc81, 0x000, 0x65e, 0x000, -1, 0xb76, + 0xc37, 0x4c4, 0xfc9, 0x336, 0x9fa, 0xaa2, 0x32c, 0xb8b, + 0xaa9, 0xc95, 0x85a, 0xa9a, 0x260, 0x4cd, 0x8fe, 0xd3c, + 0x982, 0x0d7, 0xbc1, 0xdcf, 0xe62, 0xe0d, 0xf8f, 0xd7b, + 0x91a, 0x3e0, 0x33a, 0x1c5, 0xf00, 0xde5, 0xad1, 0xebc, + 0xebc, 0x942, 0xd86, 0x3bf, 0x8ce, 0xb8c, 0x000, 0x8d6, + 0x784, 0xb74, -1, 0x818, 0x000, 0xfff, 0x07e, 0x029, + 0xf48, 0xb65, 0xd81, 0x220, 0x095, 0x21f, 0xac4, 0xb31, + -1, 0x864, 0x000, 0x3bd, 0xf85, 0x237, 0x369, 0x2d9, + 0xfdf, 0x25a, 0x782, 0x7b8, 0xabd, 0x5e3, 0x438, 0x230, + 0xbc4, 0x7ad, 0x00a, 0x441, 0x6dc, 0x2c4, 0xf16, 0x0b3, + 0x04c, 0xfd2, 0x8aa, 0xad8, 0x3e4, 0x142, 0x585, 0xc8f, + 0x9bf, 0x29b, 0xac9, 0x743, 0xfb5, 0x7fc, 0x05e, 0xd38, + 0x002, -1, 0xb4e, 0xd0c, 0x84c, 0xf93, 0x91f, 0xcd2, + 0x04f, 0x569, 0xd1b, 0xfc6, 0x630, 0x6f6, 0x1d8, 0x91a, + 0x4da, 0x9f5, 0x07a, 0xcf5, 0x634, 0x42f, 0xfff, 0x951, + 0x0f9, 0xc01, 0x491, 0xbd6, 0x730, 0xfea, 0x9f4, 0xbfc, + 0xf1a, 0x413, 0xa2a, 0xdc6, 0xc87, 0x9db, 0xc2c, 0x30f, + 0xdb5, 0x785, 0xbaa, 0x000, 0x000, 0xa49, 0x000, 0x61d, + 0xf6f, -1, 0x031, -1, 0x441, 0x7bf, 0x53e, -1, + 0x6fd, 0x0f6, -1, 0xadb, -1, 0x000, 0x432, 0x187, + 0xd37, 0x154, 0x539, 0xc08, 0xe51, 0x219, 0x1e9, 0x897, + 0xa0e, 0x201, 0x447, 0x89f, 0x000, 0x463, 0x726, 0xa05, + 0xab9, 0xd01, 0x1e4, 0xfea, 0x895, 0x816, 0x313, 0xae3, + 0x3a4, -1, 0x70f, -1, 0xa42, 0x5e9, 0x78e, -1, + 0x317, 0x6c8, 0x000, 0xbf7, 0xefd, -1, 0xb17, 0x382, + 0xd26, 0x5ff, 0xf81, 0x20b, 0x373, 0x774, 0x081, 0xaae, + 0xfdb, 0xe5d, -1, -1, 0xcb7, 0x738, 0x919, 0x933, + 0x398, 0x000, 0x14e, -1, 0xe14, 0xbf8, 0x11c, 0x94b, + 0x031, -1, 0x000, 0x2d4, 0xd41, 0xdc6, 0x9f6, 0xea7, + 0x9e8, 0x2ec, 0x10a, 0x50d, 0xeae, 0xdb0, 0xef0, 0x9c8, + 0x000, -1, 0x82e, 0x9d3, 0xdb7, 0x46d, -1, 0x230, + 0x73b, 0x45b, -1, -1, 0x000, 0x4a7, -1, -1, + 0x47c, 0x10e, 0x4b4, -1, -1, -1, 0x1d7, 0xa5d, + 0x233, 0x6b2, 0x6bd, 0x387, 0x7ca, 0xb1a, 0xf75, 0xea4, + 0xdc9, 0x98b, 0x80c, 0x702, 0xe22, 0xa6e, 0x6f8, 0x05b, + 0x17c, -1, 0x000, 0xebe, 0xc8e, 0xaec, -1, 0x42b, + 0xdce, -1, -1, -1, 0xef3, 0xc52, 0x31b, -1, + 0xdff, 0xbd0, 0x000, 0xa72, 0x525, 0x9cf, 0x2ff, 0xfc8, + 0x37c, 0xbce, 0xd8c, 0xd88, 0x3a6, 0xed8, 0x4ab, 0x000, + 0x449, 0x9d7, -1, -1, 0x9be, 0x59f, 0x000, 0x882, + -1, 0x742, 0x000, -1, -1, -1, 0xe8b, 0x0f3, + 0x771, -1, 0x3ea, 0x8f9, 0xcbb, 0x548, 0x46d, 0x000, + -1, 0xf74, 0xa23, 0x15b, -1, 0xaeb, 0x7f8, 0xbe2, + 0x000, -1, 0x023, 0x61e, 0x95d, 0x7ac, 0x024, 0x141, + 0x561, 0x9fe, 0xb10, -1, 0x623, 0xc47, 0x413, 0x0e7, + 0x663, 0xcdf, 0xebe, 0x5c9, 0x573, 0x21d, 0xb28, 0x280, + 0xb9f, 0xd1a, 0xecf, 0xff0, 0x000, 0xfc0, 0x085, 0x9c4, + 0x48c, 0x000, 0xb0b, 0x43d, -1, 0x73b, 0x802, 0x633, + 0x6ef, -1, -1, 0x5c1, 0xea6, 0x0a9, 0xab4, 0xacd, + 0xb81, 0xa32, -1, -1, 0xa26, 0x9d5, 0xf7c, -1, + 0xf69, 0xdbb, 0x6d5, 0x405, -1, 0xd0a, 0xfe0, 0xf5e, + 0xbd7, -1, 0x89a, 0x868, 0xeb2, 0x792, 0x7fe, 0x115, + 0x000, 0x8bb, 0xdd1, 0xc40, 0x453, 0xbb3, 0x7cc, 0x3e6, + 0x071, 0x0f1, 0xbae, 0xf67, 0x896, 0x38e, 0x86e, 0xfaa, + 0xccc, -1, 0x411, 0x8e5, 0x699, 0x2ef, 0x785, 0x9d4, + 0xe30, 0xb2e, 0x976, 0x203, 0x035, 0x75d, 0x8f1, 0x144, + 0x092, 0x1a5, -1, 0x55f, 0x000, 0xa43, 0x5be, 0x68d, + 0x852, 0xb87, 0x9af, 0x0c0, -1, 0xa50, 0x9ca, 0x15f, + 0xf06, 0x869, 0x0f3, -1, 0x000, -1, 0x9a9, -1, + -1, -1, -1, 0xf05, 0x000, -1, 0x000, 0x4a9, + 0xf9d, -1, 0x000, 0xab1, 0x04c, -1, 0xd17, 0x893, + 0x763, 0x332, -1, 0xc41, 0x5bd, 0xa72, 0x67c, 0xb78, + 0x973, 0x6c7, 0x569, -1, 0x96a, 0xc68, 0x48c, -1, + 0x6fa, -1, 0xa2a, 0x44f, -1, 0x73f, 0x28f, 0x536, + 0xd91, 0xc86, 0xef8, 0x1f5, 0xfb4, 0x060, 0x230, 0xe10, + -1, 0x000, 0x305, 0x0e6, 0xb19, 0x1e2, 0x7fc, 0xf35, + -1, 0x7d9, 0x000, 0x000, 0xd2f, 0xb3a, 0x0a2, 0x7c9, + 0xda6, 0x37c, 0xe43, -1, 0x7da, 0x0d6, 0x000, -1, + 0xd40, -1, 0x156, 0xee9, -1, 0x239, 0x10f, 0x60c, + 0x9d4, 0x663, 0x565, 0x603, 0x38b, -1, 0x606, 0x13c, + 0x681, 0x436, 0xc29, 0x9c7, 0x1d9, 0x000, 0x0a6, 0x996, + 0x231, 0x055, 0x01f, 0x0a3, 0xd96, 0x7c8, 0x0f3, 0xaa7, + 0xd99, -1, 0x3be, 0x476, 0x25f, 0x38c, 0xdf3, 0x6d5, + 0xcb5, 0xadd, 0x000, 0x136, 0x64d, 0xc0d, 0xe61, 0xd0b, + -1, 0x000, 0x535, 0x9c3, 0x279, 0x00c, 0xa87, 0xa31, + 0xc4a, 0x167, 0x423, 0xec8, -1, 0x926, 0xa4d, 0x5ba, + -1, -1, 0x9bf, 0x000, 0x47f, 0x8f3, 0xd5b, 0xc3b, + 0xa18, -1, 0x548, 0x8f7, 0x8cf, 0x000, 0x9bd, 0xaa2, + 0x7ec, 0x000, 0xfb8, 0xafd, 0xe68, -1, 0xfa7, 0x31c, + 0xef3, 0x288, 0xdf0, 0x1bc, 0xfe9, 0x1ea, 0xa9f, 0x000, + 0x53f, 0x000, 0xda6, 0x09c, 0x1bf, 0x09c, 0x31c, 0x0c8, + 0x31c, -1, 0x689, 0x211, -1, 0x77f, 0x723, 0xb8f, + 0x683, 0x351, -1, 0xb33, 0xce0, -1, 0x61c, 0x073, + 0x783, 0x6b2, 0x6a8, 0x729, 0x81b, 0xabf, 0xd15, 0x563, + 0x433, -1, 0x823, 0xf99, 0x2c5, -1, 0x367, 0xcc4, + 0x934, 0x6f2, 0xdf0, 0xa1f, 0x579, 0x012, -1, 0x508, + 0x070, -1, 0x018, 0x270, 0xa6f, -1, 0x7a7, -1, + 0x826, 0x4b5, -1, 0x7d8, 0xb20, -1, 0xc28, 0x463, + -1, 0xdf9, 0x22c, 0xe17, 0x4f2, 0xe13, 0x4ff, 0x40a, + 0xdcb, 0x9ed, 0x34a, 0xeb8, 0xa0e, 0x5f2, 0x594, 0x60d, + 0x4b6, 0xd3c, 0x675, 0x1c4, 0xbb5, 0xc73, 0xfad, 0xead, + -1, 0xfb6, -1, 0x146, 0xd40, 0x02f, 0x000, 0x302, + -1, -1, 0x6e5, 0x000, 0xed7, 0xd8c, 0x7a3, 0x0fc, + 0x259, 0x34b, 0xa1b, 0x882, -1, 0x211, 0x000, 0xd30, + 0xe02, 0x5cd, 0x53e, 0x11b, 0xa16, -1, 0x24e, -1, + 0xace, 0xe9a, -1, 0x5c6, 0x9be, 0x000, 0x169, 0x982, + -1, 0x3fd, 0x457, 0x06f, 0x7e7, 0xed1, 0x5ee, 0xcef, + 0x62b, 0x26c, 0xc9f, 0xe68, 0x59f, 0x0b5, 0x000, 0x0bc, + 0x086, 0x890, 0x005, 0xc42, 0x939, 0xaca, 0xdd9, -1, + -1, 0x6e5, 0x0dd, 0x434, 0x297, 0xe21, 0x0f5, -1, + 0xa6c, 0x4ad, 0x978, 0x433, 0xa41, 0xd6f, 0x8bf, 0xfb8, + -1, 0x928, 0x85e, 0xfb6, 0x5c7, 0x99a, 0x8ec, 0xebc, + 0x226, 0x7d4, 0xdcd, 0xc0b, 0x000, 0x7f4, 0xc6f, 0x000, + 0x3ad, 0x5b2, -1, 0x67b, -1, 0x568, 0x6e2, -1, + -1, -1, 0x3f3, 0xaf5, 0x33f, -1, 0x022, 0x1bd, + 0xae5, -1, 0x9c3, 0x000, 0x92b, 0xee5, 0x29c, 0x000, + 0x15e, 0xe71, 0xacb, 0x9d2, 0x1a3, 0xb7f, 0xa5b, 0x095, + -1, 0xb6e, 0x79f, 0x3d1, 0x7d0, 0x131, 0xcd7, -1, + 0x2c3, -1, 0x396, 0x4d2, 0x297, 0x405, 0x634, -1, + -1, -1, 0x928, 0xbca, 0xb6c, 0x011, 0xfc0, 0xbaf, + 0xbd2, -1, 0x585, 0x000, 0xb8a, 0x7f9, 0xd6b, 0x4eb, + 0x9a3, 0x000, -1, 0xaeb, 0xa47, 0xcef, 0x9c6, -1, + 0x000, -1, 0x2a9, 0x371, 0xca6, -1, 0xb7d, 0x15f, + 0x2a9, -1, 0xe80, 0x7a7, 0x23a, 0x000, 0x000, 0xcc9, + 0x60e, -1, 0x130, 0x9cd, 0x498, 0xe25, 0x366, 0x34b, + 0x899, 0xe49, 0x1a8, 0xc93, 0x94d, 0x05e, -1, 0x0c2, + 0x757, 0xb9d, 0xaa3, 0x086, 0x395, 0x3c3, 0xa2e, 0xf77, + 0xcb1, 0x45e, 0x169, 0xbba, 0x367, 0x8cb, 0x260, 0x5a0, + 0x8cb, 0x737, 0xa1f, 0xaaf, 0xf92, 0x430, 0x97d, 0x542, + 0xb09, -1, 0x774, 0x084, 0x4c0, 0x2b3, 0xaf6, 0x93c, + 0x32d, 0xee2, -1, 0x605, 0xece, 0x8eb, 0xc62, 0x01d, + 0x000, 0xaba, 0xfc5, 0xb8e, 0xc07, 0xfb6, 0xbca, 0x8f0, + 0xd33, -1, 0x283, 0x6d6, 0x6ad, 0x678, 0x51a, 0xc95, + 0xda4, 0x962, 0x9ed, 0x307, 0x94a, 0x052, 0xf4e, 0x3bd, + 0x210, 0x71a, 0x3c7, 0x5a4, 0x6e7, 0x23a, 0x523, 0x1dc, + 0x6b2, 0x5e0, 0xbb0, 0xae4, 0xdb1, 0xd40, 0xc0d, 0x59e, + 0x21b, 0x4e6, 0x8be, 0x3b1, 0xc71, 0x5e4, 0x4aa, 0xaf3, + 0xa27, 0x43c, 0x9ea, 0x2ee, 0x6b2, 0xd51, 0x59d, 0xd3a, + 0xd43, 0x59d, 0x405, 0x2d4, 0x05b, 0x1b9, 0x68b, 0xbfa, + 0xbb9, 0x77a, 0xf91, 0xfcb, -1, 0x949, 0x177, 0x68d, + 0xcc3, 0xcf2, 0x000, 0xa87, 0x2e6, 0xd2f, 0x111, 0x168, + 0x94c, 0x54c, 0x000, 0x0c5, 0x829, 0xcbc, 0xc0b, 0x1ed, + 0x836, 0x9d8, 0xbdc, 0xc5e, 0x4e5, 0xb94, 0x6f2, 0x74f, + 0x878, 0x3b2, 0x48d, 0xc72, 0xcff, 0xccb, 0x8f9, 0x7ee, + 0x869, 0x228, 0x035, 0x81e, 0xcf9, 0x309, 0xdf2, -1, + 0x047, 0xdd3, 0xcab, 0x11d, 0xe76, 0xb52, 0xbbd, 0x12d, + 0xf37, 0x552, 0x61d, 0xdd8, 0x2cd, 0x298, 0x9e2, 0xf2c, + 0x9f7, 0xf41, 0xcb4, 0x277, 0xfde, 0xe7e, 0x82a, 0x86b, + 0x9cc, 0x580, 0xfcc, 0x33a, 0x438, 0xd6e, 0x000, 0xc04, + 0xd50, 0x681, 0x1b3, 0x322, 0x86c, 0x4a6, 0x000, 0xa17, + 0xd53, 0xdc0, 0xb61, 0x323, 0x3d1, 0x3fb, 0x929, 0xa6e, + 0x919, 0xae0, 0x283, 0xe6a, 0xed3, 0x371, 0xd51, 0x309, + 0x510, 0xd50, 0x6f4, 0xc84, 0x566, 0xba7, 0x75b, 0xbeb, + 0x793, 0x58f, 0x974, 0xe77, 0x52c, 0xcef, 0x942, 0xa7c, + 0x56a, 0xaa0, 0x784, 0x0ec, 0xad3, 0xccf, 0xecf, 0xc3f, + 0x846, 0x1b2, 0x112, 0x4ee, 0x18b, 0xa76, 0xe14, -1, + 0xfb1, 0xb4c, -1, 0xd54, 0x0e0, 0x72d, 0xdf0, 0xf0c, + 0x881, 0xc60, 0xe1b, 0x000, 0x453, 0xe21, 0xb2a, 0x6df, + 0x84f, 0x000, 0x12a, 0x991, 0x587, 0xa4e, 0x522, 0x000, + 0xe17, 0xc64, 0x994, 0x4cc, 0x0e5, 0xc2b, 0x8cf, 0x458, + 0x992, 0xec0, 0xc80, 0xefb, 0x7b7, 0x863, 0xc0a, 0x250, + 0x338, 0xa44, 0x8ab, 0x873, 0x134, 0x23c, 0x4f6, 0x066, + 0xd0f, 0xdd6, 0x93d, 0xf20, 0x000, 0x9bb, 0x255, 0xe7b, + 0x916, 0x4f3, 0x68e, 0xb82, 0x2b4, 0x9d7, 0xfd1, 0x0fb, + 0x11e, 0x204, 0x241, 0x67f, 0x1c4, 0xe91, 0xf41, 0xb4a, + -1, 0x6d2, 0xce6, 0xdfb, -1, 0xdd0, 0xb8d, 0x8db, + 0x86c, 0x224, 0xdeb, 0x7bb, 0x50e, 0x000, 0xb79, 0x11e, + 0x486, 0xd4c, 0x000, 0xa54, 0x946, 0x83a, 0x537, 0x875, + 0x000, 0x8e4, 0x95a, 0xdd5, 0x9d5, 0x910, 0x95b, 0x8c8, + 0xd22, 0x07c, 0xac0, 0x000, 0x048, 0x170, 0x9b2, 0xcea, + 0xb0f, 0x958, 0x0f9, 0xa9e, 0x87a, 0x166, 0x69c, 0x112, + 0xde0, 0x487, 0xeca, 0x639, 0x4ee, 0x7fa, 0x2cc, 0x709, + 0x87a, 0x5bb, 0xf64, 0x173, 0xdc6, 0xaaf, 0xbff, 0xf2a, + 0x8fb, 0xd44, 0x0ca, 0xf34, 0xb3a, 0xeb3, 0xfc5, 0x61d, + 0x92f, 0x6fb, 0x1a1, 0xd85, 0x8fe, 0xb6a, 0x0a1, 0x44f, + 0x89a, 0xc5d, 0x13b, 0x5cc, 0x000, 0x9ac, 0x9e6, 0xf95, + 0x511, 0xf2e, 0xf3c, 0x707, 0xec5, 0xaec, 0xc72, 0xeb1, + 0x105, 0xda3, 0xbcb, 0x1d6, 0xf16, 0xd50, 0x306, 0x03f, + 0xe6a, 0x25c, 0x9fe, 0xd3f, 0x8a4, 0x7bc, 0x0bc, 0x532, + 0x62e, 0x111, 0x797, 0xc2c, 0x9d0, 0x338, 0xbc7, 0xd64, + 0xb09, 0x4d6, 0xcba, 0x62c, 0xef2, 0x32b, 0x9c5, 0xc06, + 0x38b, 0xbb2, 0x8b7, 0x6f2, 0x7ec, 0xa77, -1, 0x7a3, + 0xc95, 0xa91, 0x5d3, 0xffc, -1, 0xe27, 0xa0a, 0x071, + 0x9da, 0x000, 0xba3, 0x3fd, 0x120, 0x845, 0x151, 0xb5f, + 0x193, 0xe99, 0x0f6, 0x640, 0xef4, 0xe17, 0x46b, 0x432, + 0x8a4, 0x415, 0x252, 0x79c, 0xbe5, 0x3f0, 0xb64, 0x984, + 0x5a7, 0x1be, 0xedc, -1, 0xd7e, 0x5b4, -1, 0xd27, + 0x03e, 0x136, 0xb30, 0xfff, 0x1dc, 0xc32, 0x84a, 0x392, + 0xf4f, 0x911, 0x501, 0x836, 0x700, 0x9ac, 0x000, 0xdb5, + 0xfa3, 0x5d3, 0x1f8, 0x888, -1, 0xfa4, 0xfe7, 0xd87, + 0x9fe, 0x6af, 0x9a5, 0xfd5, 0xf49, 0xded, 0x416, 0x2fc, + 0x078, 0xd2e, 0xbf1, 0xcd9, 0x733, -1, 0xb50, 0xd57, + 0xaa1, -1, 0x9b0, 0x874, 0x18f, -1, -1, 0x2f9, + 0xfbb, 0xf73, 0x646, 0x868, 0x000, 0x000, 0xba2, 0xd74, + 0xc8f, 0xe36, 0xcfd, 0x5b8, 0x850, 0x48a, 0x689, 0x7ad, + 0xefd, 0x7e1, 0xf45, 0xd9e, 0x0f0, 0x7c0, 0x675, -1, + 0xf26, 0x3c0, 0xe2d, 0xb62, 0x276, -1, 0xf90, 0x837, + 0xc7c, 0x8ed, 0x08d, 0x1d6, 0x506, 0xac9, 0xd81, 0x1be, + 0xf7e, 0x1a3, 0xb2a, 0x5e2, 0x217, 0x1df, 0x5a3, 0x498, + 0xfb1, 0x432, 0x2ca, 0x5a1, 0x5d5, 0x135, 0x6f0, -1, + 0xf70, 0x000, 0xd4c, 0x634, -1, 0x8ca, 0x198, -1, + 0x7b9, 0x629, 0xc16, 0x68c, 0xea2, -1, 0xba0, 0x6d9, + 0xce9, 0x7b2, 0x000, 0xf59, 0x252, 0x575, 0x0a8, 0x894, + 0x000, 0x824, 0xf63, 0xd70, 0xdd8, 0x856, 0xc77, 0x334, + 0xeb2, 0x2b8, 0x307, 0xc34, 0x2e7, 0xa74, 0x6b9, 0x0e1, + 0x20f, 0x3ee, 0xf80, 0xa1f, 0x6e6, 0xa03, 0x3c7, 0x72f, + 0xfff, 0x156, 0x273, 0x1b7, 0xd90, 0x998, 0x474, 0xf1b, + 0x80f, 0xe4c, 0x0ba, 0xfff, 0x85e, 0x3af, 0x58f, 0x000, + 0xf6b, 0x71c, 0x4ed, 0xec3, 0x4cb, 0x000, 0xa68, 0x6ca, + 0x086, 0x000, 0x6e4, 0xab3, 0xff5, 0x281, 0xf0a, 0xc92, + 0x8d5, 0x486, 0xdd1, 0x903, 0x8e3, 0x9df, 0x2ab, 0xd08, + 0x144, 0xdcd, 0x281, 0x046, 0x161, 0xe83, 0xf24, 0xce7, + 0x30a, 0xf89, 0xf01, 0x308, 0x142, 0x9df, 0x44d, 0x9dd, + 0x3ed, 0x81b, 0xd9d, 0x000, 0x8c2, 0xe01, 0xfe6, 0xa20, + 0x167, 0xedd, 0xdb1, 0x470, 0xe70, 0x3aa, 0x0ff, 0x4d1, + 0xd30, 0x67a, 0xc56, 0x3d8, 0xf2e, 0x86a, 0x18b, 0x3f5, + 0x1a7, 0xd97, 0x652, 0x000, 0x00d, 0xbc7, 0xed3, 0x39e, + 0xb0d, 0xd8d, 0xc49, 0x2db, 0x44e, 0x820, 0x189, 0xd51, + 0x523, 0x161, 0x2eb, 0x41c, 0x951, -1, 0xbb7, -1, + -1, 0x0a7, 0x3ed, 0xfaa, 0x18e, 0xa34, 0x820, 0x2b4, + -1, 0x8c2, 0x3ee, 0x59d, 0x97b, 0x209, 0x3a2, 0x102, + 0x351, 0x6bf, 0xd3f, 0x4fc, 0x55f, 0x4b5, 0xe22, 0xf13, + 0x53a, 0x08a, 0x38d, 0xf4b, 0x424, 0xea6, 0x48e, 0x11c, + 0x339, 0x5bd, 0xf7c, 0x3bd, 0x15a, 0x35c, 0x854, 0x71b, + 0x30f, 0x065, 0x97e, 0x354, 0x28e, 0x344, 0x926, 0xc0b, + 0xae0, 0x5db, 0xb3e, 0x661, 0x432, 0x3c8, 0xf5e, 0x368, + 0xc85, 0xfff, 0x7f5, 0x0b6, 0x98b, -1, 0x28c, 0x784, + 0xb78, 0x50a, 0x696, 0x47c, 0x40d, -1, 0xe4d, 0x5fc, + -1, -1, 0xadb, 0x1db, 0x830, 0xd48, -1, 0xf3a, + 0xee4, 0xed4, 0xb1a, 0xa14, 0x36d, 0xf1c, 0x774, 0x000, + 0x942, 0x278, 0x7ee, 0x000, 0x550, 0x57c, 0x343, 0x22b, + 0x324, 0xa34, 0x0ea, 0x230, 0x51b, 0x2d1, 0x500, 0x59f, + 0xd56, 0x540, 0x2f4, 0x87d, 0x9e5, 0x9c5, 0x5ea, 0x771, + 0x491, 0x206, 0xa4b, 0x4bf, 0xdaf, 0x308, 0xb25, 0x261, + 0x991, 0x000, 0x88e, 0x7e8, 0x3d6, 0x15d, 0xebc, 0x6c2, + 0xd45, 0x000, 0x3c6, 0x48d, 0x622, 0x758, 0xfa9, 0x3cf, + 0x401, 0xcdb, 0xe3f, 0x544, 0xf1f, 0x000, -1, 0x4d4, + 0x000, 0x7f1, 0xba4, 0x81c, 0x92f, 0x7d1, 0xa83, 0xa31, + 0xe74, 0xa20, 0x475, 0x489, 0xf20, 0x3d1, 0xac1, 0xb2d, + 0x6b2, 0x1b6, 0x063, 0xd00, 0xfeb, 0x5ca, 0xb2c, 0xcb2, + 0x1cb, 0x251, 0x82b, 0x8ba, 0x40b, 0xf1e, 0xa8a, 0xd24, + 0x880, 0x84e, 0x8cb, 0x0a3, 0x000, 0xaf7, 0xf99, 0x6a1, + 0x156, 0x382, 0x0a0, 0x000, 0xed1, 0xd07, 0xbf5, 0x000, + 0x295, 0xe48, 0x760, 0x019, 0x97f, 0xb46, 0xff5, 0x7c9, + 0x1cf, 0xba4, 0x630, 0xe58, 0xda6, 0xd4b, 0xc02, 0xf9f, + 0x11c, 0x000, 0xb99, 0x51f, 0x43e, 0x199, 0xdfb, 0x72f, + 0x913, 0x509, 0xac5, 0xa2e, 0xcdb, 0x348, 0xb15, 0x472, + 0x95d, 0x67f, 0x000, 0x4b9, 0xd78, 0xc87, 0x0f6, 0x281, + 0x0bd, 0x924, 0x35e, 0x129, 0xffd, 0xe24, 0x000, 0x640, + 0x09b, 0xd10, 0xa0d, 0x000, 0x474, 0x189, 0x49f, 0x62d, + 0xcba, 0x561, 0x000, 0x58a, 0xaa1, 0x603, 0x5ab, 0x0c7, + 0x00a, 0x784, 0x5e4, 0x7e4, 0xe4d, -1, 0x276, 0x465, + 0xee9, 0xe51, 0xdae, 0xbb1, 0x51f, 0xcba, 0x1c3, 0xd70, + 0x000, 0x5be, 0x4ea, 0x3cc, 0xf13, 0x811, 0x813, 0x234, + 0x7e4, 0xbae, 0xd97, 0xb74, 0x000, 0x76a, 0xda1, 0x000, + 0xd8c, 0x53a, 0xc5a, 0x000, 0x000, 0x61b, 0xd87, 0x141, + 0x383, 0xe06, 0x6a3, 0x6c3, 0xbcc, 0xc44, 0xf63, 0xd8b, + 0x58d, 0x000, 0x839, 0x77a, 0x000, 0x8e4, 0x000, 0xdbe, + 0x483, 0xd5b, 0xa9d, 0xca5, 0x431, 0x491, 0x29a, 0x27d, + 0x2d2, 0x691, 0x000, 0x19a, 0xa0d, 0xb0b, 0xf32, 0xe49, + 0xfbf, 0x399, 0xd20, 0x000, 0x66a, 0x000, 0x447, 0xb20, + 0x894, 0x038, 0xc9c, 0xff0, 0x000, 0x0d4, 0xad4, 0x768, + 0x65c, 0x000, 0x27b, 0x6c6, 0x9be, 0xd35, 0xc6a, 0xdd3, + 0x000, 0x2a7, 0x158, 0x38d, 0x8ef, 0x7b6, 0xd49, 0x30c, + 0xec3, 0x211, 0x17c, 0xcd0, 0x61f, 0x000, 0xe6e, 0x1d4, + 0x6e9, 0x000, 0xc2d, 0x5c3, 0xcd4, 0x760, 0x532, 0xc94, + 0x590, 0x000, 0x4a3, 0xc33, 0x000, 0x426, 0x604, 0xa06, + 0xa99, 0x917, 0x0c4, 0xc8d, 0x9e5, 0xcc7, 0x415, 0xf79, + 0x000, 0xaf4, 0x622, 0x756, 0x9c2, 0xa51, 0xb0f, 0x4ef, + 0xbc4, 0xe15, 0x29e, 0x055, 0x6c9, 0x695, 0x94f, 0x9d6, + 0x000, 0xb9f, 0xd46, 0x1d4, 0x000, 0xcb2, 0x9e8, 0x000, + 0xa5e, 0xce0, 0x000, 0x098, 0xa98, 0x6d9, 0x5e2, 0x95f, + 0x791, 0xeb8, 0x5fa, 0x60a, 0xacc, 0x3d3, 0x4df, 0x0df, + 0x9ca, 0x972, 0x3cc, 0x583, 0xca5, 0xe1a, 0x000, 0x2d3, + 0x266, 0x000, 0x06c, 0xfff, 0x62d, 0x64e, 0x40c, 0x599, + 0x475, 0xaa9, 0xba6, 0x96f, 0xe32, 0x059, 0x342, 0x36d, + 0xfd1, 0x09b, 0x878, 0x9f8, 0x000, 0x3ad, 0xdba, 0x000, + 0x544, 0xc1a, 0x000, 0xee8, 0x492, 0xa6b, 0x447, 0xd2a, + 0xb4e, 0x02c, 0xadb, 0xde2, 0x904, 0x62d, 0xf01, 0xbb8, + 0x255, 0x382, 0xfff, 0x29e, 0x000, 0x000, 0x011, 0xfff, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "pdf417.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2008-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#define PDF417_STOP 0xbff + +static inline signed short pdf417_decode8 (zbar_decoder_t *dcode) +{ + /* build edge signature of character + * from similar edge measurements + */ + unsigned s = dcode->pdf417.s8; + dbprintf(2, " s=%d ", s); + if(s < 8) + return(-1); + + long sig = 0; + signed char e; + unsigned char i; + for(i = 0; i < 7; i++) { + if(get_color(dcode) == ZBAR_SPACE) + e = decode_e(get_width(dcode, i) + + get_width(dcode, i + 1), s, 17); + else + e = decode_e(get_width(dcode, 7 - i) + + get_width(dcode, 6 - i), s, 17); + dbprintf(4, "%x", e); + if(e < 0 || e > 8) + return(-1); + sig = (sig << 3) ^ e; + } + dbprintf(2, " sig=%06lx", sig); + + /* determine cluster number */ + int clst = ((sig & 7) - ((sig >> 3) & 7) + + ((sig >> 12) & 7) - ((sig >> 15) & 7)); + if(clst < 0) + clst += 9; + dbprintf(2, " k=%d", clst); + zassert(clst >= 0 && clst < 9, -1, "dir=%x sig=%lx k=%x %s\n", + dcode->pdf417.direction, sig, clst, + _zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character)); + + if(clst != 0 && clst != 3 && clst != 6) { + if(get_color(dcode) && clst == 7 && sig == 0x080007) + return(PDF417_STOP); + return(-1); + } + + signed short g[3]; + sig &= 0x3ffff; + g[0] = pdf417_hash[(sig - (sig >> 10)) & PDF417_HASH_MASK]; + g[1] = pdf417_hash[((sig >> 8) - sig) & PDF417_HASH_MASK]; + g[2] = pdf417_hash[((sig >> 14) - (sig >> 1)) & PDF417_HASH_MASK]; + zassert(g[0] >= 0 && g[1] >= 0 && g[2] >= 0, -1, + "dir=%x sig=%lx k=%x g0=%03x g1=%03x g2=%03x %s\n", + dcode->pdf417.direction, sig, clst, g[0], g[1], g[2], + _zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character)); + + unsigned short c = (g[0] + g[1] + g[2]) & PDF417_HASH_MASK; + dbprintf(2, " g0=%x g1=%x g2=%x c=%03d(%d)", + g[0], g[1], g[2], c & 0x3ff, c >> 10); + return(c); +} + +static inline signed char pdf417_decode_start(zbar_decoder_t *dcode) +{ + unsigned s = dcode->pdf417.s8; + if(s < 8) + return(0); + + int ei = decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 17); + int ex = (get_color(dcode) == ZBAR_SPACE) ? 2 : 6; + if(ei != ex) + return(0); + + ei = decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 17); + if(ei) + return(0); + + ei = decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 17); + ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2; + if(ei != ex) + return(0); + + ei = decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 17); + ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2; + if(ei != ex) + return(0); + + ei = decode_e(get_width(dcode, 4) + get_width(dcode, 5), s, 17); + if(ei) + return(0); + + ei = decode_e(get_width(dcode, 5) + get_width(dcode, 6), s, 17); + if(ei) + return(0); + + ei = decode_e(get_width(dcode, 6) + get_width(dcode, 7), s, 17); + ex = (get_color(dcode) == ZBAR_SPACE) ? 7 : 1; + if(ei != ex) + return(0); + + ei = decode_e(get_width(dcode, 7) + get_width(dcode, 8), s, 17); + ex = (get_color(dcode) == ZBAR_SPACE) ? 8 : 1; + + if(get_color(dcode) == ZBAR_BAR) { + /* stop character has extra bar */ + if(ei != 1) + return(0); + ei = decode_e(get_width(dcode, 8) + get_width(dcode, 9), s, 17); + } + + dbprintf(2, " pdf417[%c]: s=%d", + (get_color(dcode)) ? '<' : '>', s); + + /* check quiet zone */ + if(ei >= 0 && ei < ex) { + dbprintf(2, " [invalid quiet]\n"); + return(0); + } + + /* lock shared resources */ + if(acquire_lock(dcode, ZBAR_PDF417)) { + dbprintf(2, " [locked %d]\n", dcode->lock); + return(0); + } + + pdf417_decoder_t *dcode417 = &dcode->pdf417; + dcode417->direction = get_color(dcode); + dcode417->element = 0; + dcode417->character = 0; + + dbprintf(2, " [valid start]\n"); + return(ZBAR_PARTIAL); +} + +zbar_symbol_type_t _zbar_decode_pdf417 (zbar_decoder_t *dcode) +{ + pdf417_decoder_t *dcode417 = &dcode->pdf417; + + /* update latest character width */ + dcode417->s8 -= get_width(dcode, 8); + dcode417->s8 += get_width(dcode, 0); + + if(dcode417->character < 0) { + pdf417_decode_start(dcode); + dbprintf(4, "\n"); + return(0); + } + + /* process every 8th element of active symbol */ + if(++dcode417->element) + return(0); + dcode417->element = 0; + + dbprintf(2, " pdf417[%c%02d]:", + (dcode417->direction) ? '<' : '>', dcode417->character); + + if(get_color(dcode) != dcode417->direction) { + int c = dcode417->character; + release_lock(dcode, ZBAR_PDF417); + dcode417->character = -1; + zassert(get_color(dcode) == dcode417->direction, ZBAR_NONE, + "color=%x dir=%x char=%d elem=0 %s\n", + get_color(dcode), dcode417->direction, c, + _zbar_decoder_buf_dump(dcode->buf, c)); + } + + signed short c = pdf417_decode8(dcode); + if(c < 0 || size_buf(dcode, dcode417->character + 1)) { + dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n"); + release_lock(dcode, ZBAR_PDF417); + dcode417->character = -1; + return(0); + } + + /* FIXME TBD infer dimensions, save codewords */ + + if(c == PDF417_STOP) { + dbprintf(1, " [valid stop]"); + /* FIXME check trailing bar and qz */ + dcode->direction = 1 - 2 * dcode417->direction; + dcode->modifiers = 0; + release_lock(dcode, ZBAR_PDF417); + dcode417->character = -1; + } + + dbprintf(2, "\n"); + return(0); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "decoder.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +zbar_decoder_t *zbar_decoder_create () +{ + zbar_decoder_t *dcode = calloc(1, sizeof(zbar_decoder_t)); + dcode->buf_alloc = BUFFER_MIN; + dcode->buf = malloc(dcode->buf_alloc); + + /* initialize default configs */ +#ifdef ENABLE_EAN + dcode->ean.enable = 1; + dcode->ean.ean13_config = ((1 << ZBAR_CFG_ENABLE) | + (1 << ZBAR_CFG_EMIT_CHECK)); + dcode->ean.ean8_config = ((1 << ZBAR_CFG_ENABLE) | + (1 << ZBAR_CFG_EMIT_CHECK)); + dcode->ean.upca_config = 1 << ZBAR_CFG_EMIT_CHECK; + dcode->ean.upce_config = 1 << ZBAR_CFG_EMIT_CHECK; + dcode->ean.isbn10_config = 1 << ZBAR_CFG_EMIT_CHECK; + dcode->ean.isbn13_config = 1 << ZBAR_CFG_EMIT_CHECK; +# ifdef FIXME_ADDON_SYNC + dcode->ean.ean2_config = 1 << ZBAR_CFG_ENABLE; + dcode->ean.ean5_config = 1 << ZBAR_CFG_ENABLE; +# endif +#endif +#ifdef ENABLE_I25 + dcode->i25.config = 1 << ZBAR_CFG_ENABLE; + CFG(dcode->i25, ZBAR_CFG_MIN_LEN) = 6; +#endif +#ifdef ENABLE_DATABAR + dcode->databar.config = ((1 << ZBAR_CFG_ENABLE) | + (1 << ZBAR_CFG_EMIT_CHECK)); + dcode->databar.config_exp = ((1 << ZBAR_CFG_ENABLE) | + (1 << ZBAR_CFG_EMIT_CHECK)); + dcode->databar.csegs = 4; + dcode->databar.segs = calloc(4, sizeof(*dcode->databar.segs)); +#endif +#ifdef ENABLE_CODABAR + dcode->codabar.config = 1 << ZBAR_CFG_ENABLE; + CFG(dcode->codabar, ZBAR_CFG_MIN_LEN) = 4; +#endif +#ifdef ENABLE_CODE39 + dcode->code39.config = 1 << ZBAR_CFG_ENABLE; + CFG(dcode->code39, ZBAR_CFG_MIN_LEN) = 1; +#endif +#ifdef ENABLE_CODE93 + dcode->code93.config = 1 << ZBAR_CFG_ENABLE; +#endif +#ifdef ENABLE_CODE128 + dcode->code128.config = 1 << ZBAR_CFG_ENABLE; +#endif +#ifdef ENABLE_PDF417 + dcode->pdf417.config = 1 << ZBAR_CFG_ENABLE; +#endif +#ifdef ENABLE_QRCODE + dcode->qrf.config = 1 << ZBAR_CFG_ENABLE; +#endif + + zbar_decoder_reset(dcode); + return(dcode); +} + +void zbar_decoder_destroy (zbar_decoder_t *dcode) +{ +#ifdef ENABLE_DATABAR + if(dcode->databar.segs) + free(dcode->databar.segs); +#endif + if(dcode->buf) + free(dcode->buf); + free(dcode); +} + +void zbar_decoder_reset (zbar_decoder_t *dcode) +{ + memset(dcode, 0, (long)&dcode->buf_alloc - (long)dcode); +#ifdef ENABLE_EAN + ean_reset(&dcode->ean); +#endif +#ifdef ENABLE_I25 + i25_reset(&dcode->i25); +#endif +#ifdef ENABLE_DATABAR + databar_reset(&dcode->databar); +#endif +#ifdef ENABLE_CODABAR + codabar_reset(&dcode->codabar); +#endif +#ifdef ENABLE_CODE39 + code39_reset(&dcode->code39); +#endif +#ifdef ENABLE_CODE93 + code93_reset(&dcode->code93); +#endif +#ifdef ENABLE_CODE128 + code128_reset(&dcode->code128); +#endif +#ifdef ENABLE_PDF417 + pdf417_reset(&dcode->pdf417); +#endif +#ifdef ENABLE_QRCODE + qr_finder_reset(&dcode->qrf); +#endif +} + +void zbar_decoder_new_scan (zbar_decoder_t *dcode) +{ + /* soft reset decoder */ + memset(dcode->w, 0, sizeof(dcode->w)); + dcode->lock = 0; + dcode->idx = 0; + dcode->s6 = 0; +#ifdef ENABLE_EAN + ean_new_scan(&dcode->ean); +#endif +#ifdef ENABLE_I25 + i25_reset(&dcode->i25); +#endif +#ifdef ENABLE_DATABAR + databar_new_scan(&dcode->databar); +#endif +#ifdef ENABLE_CODABAR + codabar_reset(&dcode->codabar); +#endif +#ifdef ENABLE_CODE39 + code39_reset(&dcode->code39); +#endif +#ifdef ENABLE_CODE93 + code93_reset(&dcode->code93); +#endif +#ifdef ENABLE_CODE128 + code128_reset(&dcode->code128); +#endif +#ifdef ENABLE_PDF417 + pdf417_reset(&dcode->pdf417); +#endif +#ifdef ENABLE_QRCODE + qr_finder_reset(&dcode->qrf); +#endif +} + + +zbar_color_t zbar_decoder_get_color (const zbar_decoder_t *dcode) +{ + return(get_color(dcode)); +} + +const char *zbar_decoder_get_data (const zbar_decoder_t *dcode) +{ + return((char*)dcode->buf); +} + +unsigned int zbar_decoder_get_data_length (const zbar_decoder_t *dcode) +{ + return(dcode->buflen); +} + +int zbar_decoder_get_direction (const zbar_decoder_t *dcode) +{ + return(dcode->direction); +} + +zbar_decoder_handler_t * +zbar_decoder_set_handler (zbar_decoder_t *dcode, + zbar_decoder_handler_t *handler) +{ + zbar_decoder_handler_t *result = dcode->handler; + dcode->handler = handler; + return(result); +} + +void zbar_decoder_set_userdata (zbar_decoder_t *dcode, + void *userdata) +{ + dcode->userdata = userdata; +} + +void *zbar_decoder_get_userdata (const zbar_decoder_t *dcode) +{ + return(dcode->userdata); +} + +zbar_symbol_type_t zbar_decoder_get_type (const zbar_decoder_t *dcode) +{ + return(dcode->type); +} + +unsigned int zbar_decoder_get_modifiers (const zbar_decoder_t *dcode) +{ + return(dcode->modifiers); +} + +zbar_symbol_type_t zbar_decode_width (zbar_decoder_t *dcode, + unsigned w) +{ + zbar_symbol_type_t tmp, sym = ZBAR_NONE; + + dcode->w[dcode->idx & (DECODE_WINDOW - 1)] = w; + dbprintf(1, " decode[%x]: w=%d (%g)\n", dcode->idx, w, (w / 32.)); + + /* update shared character width */ + dcode->s6 -= get_width(dcode, 7); + dcode->s6 += get_width(dcode, 1); + + /* each decoder processes width stream in parallel */ +#ifdef ENABLE_QRCODE + if(TEST_CFG(dcode->qrf.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_find_qr(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_EAN + if((dcode->ean.enable) && + (tmp = _zbar_decode_ean(dcode))) + sym = tmp; +#endif +#ifdef ENABLE_CODE39 + if(TEST_CFG(dcode->code39.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_code39(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_CODE93 + if(TEST_CFG(dcode->code93.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_code93(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_CODE128 + if(TEST_CFG(dcode->code128.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_code128(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_DATABAR + if(TEST_CFG(dcode->databar.config | dcode->databar.config_exp, + ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_databar(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_CODABAR + if(TEST_CFG(dcode->codabar.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_codabar(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_I25 + if(TEST_CFG(dcode->i25.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_i25(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif +#ifdef ENABLE_PDF417 + if(TEST_CFG(dcode->pdf417.config, ZBAR_CFG_ENABLE) && + (tmp = _zbar_decode_pdf417(dcode)) > ZBAR_PARTIAL) + sym = tmp; +#endif + + dcode->idx++; + dcode->type = sym; + if(sym) { + if(dcode->lock && sym > ZBAR_PARTIAL && sym != ZBAR_QRCODE) + release_lock(dcode, sym); + if(dcode->handler) + dcode->handler(dcode); + } + return(sym); +} + +static inline const unsigned int* +decoder_get_configp (const zbar_decoder_t *dcode, + zbar_symbol_type_t sym) +{ + const unsigned int *config; + switch(sym) { +#ifdef ENABLE_EAN + case ZBAR_EAN13: + config = &dcode->ean.ean13_config; + break; + + case ZBAR_EAN2: + config = &dcode->ean.ean2_config; + break; + + case ZBAR_EAN5: + config = &dcode->ean.ean5_config; + break; + + case ZBAR_EAN8: + config = &dcode->ean.ean8_config; + break; + + case ZBAR_UPCA: + config = &dcode->ean.upca_config; + break; + + case ZBAR_UPCE: + config = &dcode->ean.upce_config; + break; + + case ZBAR_ISBN10: + config = &dcode->ean.isbn10_config; + break; + + case ZBAR_ISBN13: + config = &dcode->ean.isbn13_config; + break; +#endif + +#ifdef ENABLE_I25 + case ZBAR_I25: + config = &dcode->i25.config; + break; +#endif + +#ifdef ENABLE_DATABAR + case ZBAR_DATABAR: + config = &dcode->databar.config; + break; + case ZBAR_DATABAR_EXP: + config = &dcode->databar.config_exp; + break; +#endif + +#ifdef ENABLE_CODABAR + case ZBAR_CODABAR: + config = &dcode->codabar.config; + break; +#endif + +#ifdef ENABLE_CODE39 + case ZBAR_CODE39: + config = &dcode->code39.config; + break; +#endif + +#ifdef ENABLE_CODE93 + case ZBAR_CODE93: + config = &dcode->code93.config; + break; +#endif + +#ifdef ENABLE_CODE128 + case ZBAR_CODE128: + config = &dcode->code128.config; + break; +#endif + +#ifdef ENABLE_PDF417 + case ZBAR_PDF417: + config = &dcode->pdf417.config; + break; +#endif + +#ifdef ENABLE_QRCODE + case ZBAR_QRCODE: + config = &dcode->qrf.config; + break; +#endif + + default: + config = NULL; + } + return(config); +} + +unsigned int zbar_decoder_get_configs (const zbar_decoder_t *dcode, + zbar_symbol_type_t sym) +{ + const unsigned *config = decoder_get_configp(dcode, sym); + if(!config) + return(0); + return(*config); +} + +static inline int decoder_set_config_bool (zbar_decoder_t *dcode, + zbar_symbol_type_t sym, + zbar_config_t cfg, + int val) +{ + unsigned *config = (void*)decoder_get_configp(dcode, sym); + if(!config || cfg >= ZBAR_CFG_NUM) + return(1); + + if(!val) + *config &= ~(1 << cfg); + else if(val == 1) + *config |= (1 << cfg); + else + return(1); + +#ifdef ENABLE_EAN + dcode->ean.enable = TEST_CFG(dcode->ean.ean13_config | + dcode->ean.ean2_config | + dcode->ean.ean5_config | + dcode->ean.ean8_config | + dcode->ean.upca_config | + dcode->ean.upce_config | + dcode->ean.isbn10_config | + dcode->ean.isbn13_config, + ZBAR_CFG_ENABLE); +#endif + + return(0); +} + +static inline int decoder_set_config_int (zbar_decoder_t *dcode, + zbar_symbol_type_t sym, + zbar_config_t cfg, + int val) +{ + switch(sym) { + +#ifdef ENABLE_I25 + case ZBAR_I25: + CFG(dcode->i25, cfg) = val; + break; +#endif +#ifdef ENABLE_CODABAR + case ZBAR_CODABAR: + CFG(dcode->codabar, cfg) = val; + break; +#endif +#ifdef ENABLE_CODE39 + case ZBAR_CODE39: + CFG(dcode->code39, cfg) = val; + break; +#endif +#ifdef ENABLE_CODE93 + case ZBAR_CODE93: + CFG(dcode->code93, cfg) = val; + break; +#endif +#ifdef ENABLE_CODE128 + case ZBAR_CODE128: + CFG(dcode->code128, cfg) = val; + break; +#endif +#ifdef ENABLE_PDF417 + case ZBAR_PDF417: + CFG(dcode->pdf417, cfg) = val; + break; +#endif + + default: + return(1); + } + return(0); +} + +int zbar_decoder_set_config (zbar_decoder_t *dcode, + zbar_symbol_type_t sym, + zbar_config_t cfg, + int val) +{ + if(sym == ZBAR_NONE) { + static const zbar_symbol_type_t all[] = { + ZBAR_EAN13, ZBAR_EAN2, ZBAR_EAN5, ZBAR_EAN8, + ZBAR_UPCA, ZBAR_UPCE, ZBAR_ISBN10, ZBAR_ISBN13, + ZBAR_I25, ZBAR_DATABAR, ZBAR_DATABAR_EXP, ZBAR_CODABAR, + ZBAR_CODE39, ZBAR_CODE93, ZBAR_CODE128, ZBAR_QRCODE, + ZBAR_PDF417, 0 + }; + const zbar_symbol_type_t *symp; + for(symp = all; *symp; symp++) + zbar_decoder_set_config(dcode, *symp, cfg, val); + return(0); + } + + if(cfg >= 0 && cfg < ZBAR_CFG_NUM) + return(decoder_set_config_bool(dcode, sym, cfg, val)); + else if(cfg >= ZBAR_CFG_MIN_LEN && cfg <= ZBAR_CFG_MAX_LEN) + return(decoder_set_config_int(dcode, sym, cfg, val)); + else + return(1); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "scanner.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#ifndef ZBAR_FIXED +# define ZBAR_FIXED 5 +#endif +#define ROUND (1 << (ZBAR_FIXED - 1)) + +/* FIXME add runtime config API for these */ +#ifndef ZBAR_SCANNER_THRESH_MIN +# define ZBAR_SCANNER_THRESH_MIN 4 +#endif + +#ifndef ZBAR_SCANNER_THRESH_INIT_WEIGHT +# define ZBAR_SCANNER_THRESH_INIT_WEIGHT .44 +#endif +#define THRESH_INIT ((unsigned)((ZBAR_SCANNER_THRESH_INIT_WEIGHT \ + * (1 << (ZBAR_FIXED + 1)) + 1) / 2)) + +#ifndef ZBAR_SCANNER_THRESH_FADE +# define ZBAR_SCANNER_THRESH_FADE 8 +#endif + +#ifndef ZBAR_SCANNER_EWMA_WEIGHT +# define ZBAR_SCANNER_EWMA_WEIGHT .78 +#endif +#define EWMA_WEIGHT ((unsigned)((ZBAR_SCANNER_EWMA_WEIGHT \ + * (1 << (ZBAR_FIXED + 1)) + 1) / 2)) + +/* scanner state */ +struct zbar_scanner_s { + zbar_decoder_t *decoder; /* associated bar width decoder */ + unsigned y1_min_thresh; /* minimum threshold */ + + unsigned x; /* relative scan position of next sample */ + int y0[4]; /* short circular buffer of average intensities */ + + int y1_sign; /* slope at last crossing */ + unsigned y1_thresh; /* current slope threshold */ + + unsigned cur_edge; /* interpolated position of tracking edge */ + unsigned last_edge; /* interpolated position of last located edge */ + unsigned width; /* last element width */ +}; + +zbar_scanner_t *zbar_scanner_create (zbar_decoder_t *dcode) +{ + zbar_scanner_t *scn = malloc(sizeof(zbar_scanner_t)); + scn->decoder = dcode; + scn->y1_min_thresh = ZBAR_SCANNER_THRESH_MIN; + zbar_scanner_reset(scn); + return(scn); +} + +void zbar_scanner_destroy (zbar_scanner_t *scn) +{ + free(scn); +} + +zbar_symbol_type_t zbar_scanner_reset (zbar_scanner_t *scn) +{ + memset(&scn->x, 0, sizeof(zbar_scanner_t) - offsetof(zbar_scanner_t, x)); + scn->y1_thresh = scn->y1_min_thresh; + if(scn->decoder) + zbar_decoder_reset(scn->decoder); + return(ZBAR_NONE); +} + +unsigned zbar_scanner_get_width (const zbar_scanner_t *scn) +{ + return(scn->width); +} + +unsigned zbar_scanner_get_edge (const zbar_scanner_t *scn, + unsigned offset, + int prec) +{ + unsigned edge = scn->last_edge - offset - (1 << ZBAR_FIXED) - ROUND; + prec = ZBAR_FIXED - prec; + if(prec > 0) + return(edge >> prec); + else if(!prec) + return(edge); + else + return(edge << -prec); +} + +zbar_color_t zbar_scanner_get_color (const zbar_scanner_t *scn) +{ + return((scn->y1_sign <= 0) ? ZBAR_SPACE : ZBAR_BAR); +} + +static inline unsigned calc_thresh (zbar_scanner_t *scn) +{ + /* threshold 1st to improve noise rejection */ + unsigned dx, thresh = scn->y1_thresh; + unsigned long t; + if((thresh <= scn->y1_min_thresh) || !scn->width) { + dbprintf(1, " tmin=%d", scn->y1_min_thresh); + return(scn->y1_min_thresh); + } + /* slowly return threshold to min */ + dx = (scn->x << ZBAR_FIXED) - scn->last_edge; + t = thresh * dx; + t /= scn->width; + t /= ZBAR_SCANNER_THRESH_FADE; + dbprintf(1, " thr=%d t=%ld x=%d last=%d.%d (%d)", + thresh, t, scn->x, scn->last_edge >> ZBAR_FIXED, + scn->last_edge & ((1 << ZBAR_FIXED) - 1), dx); + if(thresh > t) { + thresh -= t; + if(thresh > scn->y1_min_thresh) + return(thresh); + } + scn->y1_thresh = scn->y1_min_thresh; + return(scn->y1_min_thresh); +} + +static inline zbar_symbol_type_t process_edge (zbar_scanner_t *scn, + int y1) +{ + if(!scn->y1_sign) + scn->last_edge = scn->cur_edge = (1 << ZBAR_FIXED) + ROUND; + else if(!scn->last_edge) + scn->last_edge = scn->cur_edge; + + scn->width = scn->cur_edge - scn->last_edge; + dbprintf(1, " sgn=%d cur=%d.%d w=%d (%s)\n", + scn->y1_sign, scn->cur_edge >> ZBAR_FIXED, + scn->cur_edge & ((1 << ZBAR_FIXED) - 1), scn->width, + ((y1 > 0) ? "SPACE" : "BAR")); + scn->last_edge = scn->cur_edge; + +#if DEBUG_SVG > 1 + svg_path_moveto(SVG_ABS, scn->last_edge - (1 << ZBAR_FIXED) - ROUND, 0); +#endif + + /* pass to decoder */ + if(scn->decoder) + return(zbar_decode_width(scn->decoder, scn->width)); + return(ZBAR_PARTIAL); +} + +inline zbar_symbol_type_t zbar_scanner_flush (zbar_scanner_t *scn) +{ + unsigned x; + if(!scn->y1_sign) + return(ZBAR_NONE); + + x = (scn->x << ZBAR_FIXED) + ROUND; + + if(scn->cur_edge != x || scn->y1_sign > 0) { + zbar_symbol_type_t edge = process_edge(scn, -scn->y1_sign); + dbprintf(1, "flush0:"); + scn->cur_edge = x; + scn->y1_sign = -scn->y1_sign; + return(edge); + } + + scn->y1_sign = scn->width = 0; + if(scn->decoder) + return(zbar_decode_width(scn->decoder, 0)); + return(ZBAR_PARTIAL); +} + +zbar_symbol_type_t zbar_scanner_new_scan (zbar_scanner_t *scn) +{ + zbar_symbol_type_t edge = ZBAR_NONE; + while(scn->y1_sign) { + zbar_symbol_type_t tmp = zbar_scanner_flush(scn); + if(tmp < 0 || tmp > edge) + edge = tmp; + } + + /* reset scanner and associated decoder */ + memset(&scn->x, 0, sizeof(zbar_scanner_t) - offsetof(zbar_scanner_t, x)); + scn->y1_thresh = scn->y1_min_thresh; + if(scn->decoder) + zbar_decoder_new_scan(scn->decoder); + return(edge); +} + +zbar_symbol_type_t zbar_scan_y (zbar_scanner_t *scn, + int y) +{ + /* FIXME calc and clip to max y range... */ + /* retrieve short value history */ + register int x = scn->x; + register int y0_1 = scn->y0[(x - 1) & 3]; + register int y0_0 = y0_1; + register int y0_2, y0_3, y1_1, y2_1, y2_2; + zbar_symbol_type_t edge; + if(x) { + /* update weighted moving average */ + y0_0 += ((int)((y - y0_1) * EWMA_WEIGHT)) >> ZBAR_FIXED; + scn->y0[x & 3] = y0_0; + } + else + y0_0 = y0_1 = scn->y0[0] = scn->y0[1] = scn->y0[2] = scn->y0[3] = y; + y0_2 = scn->y0[(x - 2) & 3]; + y0_3 = scn->y0[(x - 3) & 3]; + /* 1st differential @ x-1 */ + y1_1 = y0_1 - y0_2; + { + register int y1_2 = y0_2 - y0_3; + if((abs(y1_1) < abs(y1_2)) && + ((y1_1 >= 0) == (y1_2 >= 0))) + y1_1 = y1_2; + } + + /* 2nd differentials @ x-1 & x-2 */ + y2_1 = y0_0 - (y0_1 * 2) + y0_2; + y2_2 = y0_1 - (y0_2 * 2) + y0_3; + + dbprintf(1, "scan: x=%d y=%d y0=%d y1=%d y2=%d", + x, y, y0_1, y1_1, y2_1); + + edge = ZBAR_NONE; + /* 2nd zero-crossing is 1st local min/max - could be edge */ + if((!y2_1 || + ((y2_1 > 0) ? y2_2 < 0 : y2_2 > 0)) && + (calc_thresh(scn) <= abs(y1_1))) + { + /* check for 1st sign change */ + char y1_rev = (scn->y1_sign > 0) ? y1_1 < 0 : y1_1 > 0; + if(y1_rev) + /* intensity change reversal - finalize previous edge */ + edge = process_edge(scn, y1_1); + + if(y1_rev || (abs(scn->y1_sign) < abs(y1_1))) { + int d; + scn->y1_sign = y1_1; + + /* adaptive thresholding */ + /* start at multiple of new min/max */ + scn->y1_thresh = (abs(y1_1) * THRESH_INIT + ROUND) >> ZBAR_FIXED; + dbprintf(1, "\tthr=%d", scn->y1_thresh); + if(scn->y1_thresh < scn->y1_min_thresh) + scn->y1_thresh = scn->y1_min_thresh; + + /* update current edge */ + d = y2_1 - y2_2; + scn->cur_edge = 1 << ZBAR_FIXED; + if(!d) + scn->cur_edge >>= 1; + else if(y2_1) + /* interpolate zero crossing */ + scn->cur_edge -= ((y2_1 << ZBAR_FIXED) + 1) / d; + scn->cur_edge += x << ZBAR_FIXED; + dbprintf(1, "\n"); + } + } + else + dbprintf(1, "\n"); + /* FIXME add fall-thru pass to decoder after heuristic "idle" period + (eg, 6-8 * last width) */ + scn->x = x + 1; + return(edge); +} + +/* undocumented API for drawing cutesy debug graphics */ +void zbar_scanner_get_state (const zbar_scanner_t *scn, + unsigned *x, + unsigned *cur_edge, + unsigned *last_edge, + int *y0, + int *y1, + int *y2, + int *y1_thresh) +{ + register int y0_0 = scn->y0[(scn->x - 1) & 3]; + register int y0_1 = scn->y0[(scn->x - 2) & 3]; + register int y0_2 = scn->y0[(scn->x - 3) & 3]; + zbar_scanner_t *mut_scn; + if(x) *x = scn->x - 1; + if(last_edge) *last_edge = scn->last_edge; + if(y0) *y0 = y0_1; + if(y1) *y1 = y0_1 - y0_2; + if(y2) *y2 = y0_0 - (y0_1 * 2) + y0_2; + /* NB not quite accurate (uses updated x) */ + mut_scn = (zbar_scanner_t*)scn; + if(y1_thresh) *y1_thresh = calc_thresh(mut_scn); + dbprintf(1, "\n"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void imlib_find_barcodes(list_t *out, image_t *ptr, rectangle_t *roi) +{ + uint8_t *grayscale_image = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->data : fb_alloc(roi->w * roi->h); + umm_init_x(fb_avail()); + zbar_image_scanner_t *scanner = zbar_image_scanner_create(); + zbar_image_scanner_set_config(scanner, 0, ZBAR_CFG_ENABLE, 1); + + zbar_image_t image; + image.format = *((int *) "Y800"); + image.width = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->w : roi->w; + image.height = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->h : roi->h; + image.data = grayscale_image; + image.datalen = ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->w : roi->w) * ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? ptr->h : roi->h); + image.crop_x = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->x : 0; + image.crop_y = (ptr->bpp == IMAGE_BPP_GRAYSCALE) ? roi->y : 0; + image.crop_w = roi->w; + image.crop_h = roi->h; + image.userdata = 0; + image.seq = 0; + image.syms = 0; + + switch (ptr->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi->y, yy = roi->y + roi->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(ptr, y); + for (int x = roi->x, xx = roi->x + roi->w; x < xx; x++) { + *(grayscale_image++) = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { + memset(grayscale_image, 0, roi->w * roi->h); + break; + } + } + + list_init(out, sizeof(find_barcodes_list_lnk_data_t)); + + if (zbar_scan_image(scanner, &image) > 0) { + for (const zbar_symbol_t *symbol = (image.syms) ? image.syms->head : NULL; symbol; symbol = zbar_symbol_next(symbol)) { + if (zbar_symbol_get_loc_size(symbol) > 0) { + find_barcodes_list_lnk_data_t lnk_data; + + rectangle_init(&(lnk_data.rect), + zbar_symbol_get_loc_x(symbol, 0) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x), + zbar_symbol_get_loc_y(symbol, 0) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y), + (zbar_symbol_get_loc_size(symbol) == 1) ? 1 : 0, + (zbar_symbol_get_loc_size(symbol) == 1) ? 1 : 0); + + for (size_t k = 1, l = zbar_symbol_get_loc_size(symbol); k < l; k++) { + rectangle_t temp; + rectangle_init(&temp, + zbar_symbol_get_loc_x(symbol, k) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->x), + zbar_symbol_get_loc_y(symbol, k) + ((ptr->bpp == IMAGE_BPP_GRAYSCALE) ? 0 : roi->y), + 0, + 0); + rectangle_united(&(lnk_data.rect), &temp); + } + + // Add corners... + lnk_data.corners[0].x = lnk_data.rect.x; // top-left + lnk_data.corners[0].y = lnk_data.rect.y; // top-left + lnk_data.corners[1].x = lnk_data.rect.x + lnk_data.rect.w; // top-right + lnk_data.corners[1].y = lnk_data.rect.y; // top-right + lnk_data.corners[2].x = lnk_data.rect.x + lnk_data.rect.w; // bottom-right + lnk_data.corners[2].y = lnk_data.rect.y + lnk_data.rect.h; // bottom-right + lnk_data.corners[3].x = lnk_data.rect.x; // bottom-left + lnk_data.corners[3].y = lnk_data.rect.y + lnk_data.rect.h; // bottom-left + + // Payload is already null terminated. + lnk_data.payload_len = zbar_symbol_get_data_length(symbol); + lnk_data.payload = xalloc(zbar_symbol_get_data_length(symbol)); + memcpy(lnk_data.payload, zbar_symbol_get_data(symbol), zbar_symbol_get_data_length(symbol)); + + switch (zbar_symbol_get_type(symbol)) { + case ZBAR_EAN2: lnk_data.type = BARCODE_EAN2; break; + case ZBAR_EAN5: lnk_data.type = BARCODE_EAN5; break; + case ZBAR_EAN8: lnk_data.type = BARCODE_EAN8; break; + case ZBAR_UPCE: lnk_data.type = BARCODE_UPCE; break; + case ZBAR_ISBN10: lnk_data.type = BARCODE_ISBN10; break; + case ZBAR_UPCA: lnk_data.type = BARCODE_UPCA; break; + case ZBAR_EAN13: lnk_data.type = BARCODE_EAN13; break; + case ZBAR_ISBN13: lnk_data.type = BARCODE_ISBN13; break; + case ZBAR_I25: lnk_data.type = BARCODE_I25; break; + case ZBAR_DATABAR: lnk_data.type = BARCODE_DATABAR; break; + case ZBAR_DATABAR_EXP: lnk_data.type = BARCODE_DATABAR_EXP; break; + case ZBAR_CODABAR: lnk_data.type = BARCODE_CODABAR; break; + case ZBAR_CODE39: lnk_data.type = BARCODE_CODE39; break; + case ZBAR_PDF417: lnk_data.type = BARCODE_PDF417; break; + case ZBAR_CODE93: lnk_data.type = BARCODE_CODE93; break; + case ZBAR_CODE128: lnk_data.type = BARCODE_CODE128; break; + default: continue; + } + + switch (zbar_symbol_get_orientation(symbol)) { + case ZBAR_ORIENT_UP: lnk_data.rotation = 0; break; + case ZBAR_ORIENT_RIGHT: lnk_data.rotation = 270; break; + case ZBAR_ORIENT_DOWN: lnk_data.rotation = 180; break; + case ZBAR_ORIENT_LEFT: lnk_data.rotation = 90; break; + default: continue; + } + + lnk_data.quality = zbar_symbol_get_quality(symbol); + + list_push_back(out, &lnk_data); + } + } + } + + for (;;) { // Merge overlapping. + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(find_barcodes_list_lnk_data_t)); + + while (list_size(out)) { + find_barcodes_list_lnk_data_t lnk_code; + list_pop_front(out, &lnk_code); + + for (size_t k = 0, l = list_size(out); k < l; k++) { + find_barcodes_list_lnk_data_t tmp_code; + list_pop_front(out, &tmp_code); + + if (rectangle_overlap(&(lnk_code.rect), &(tmp_code.rect)) + && (lnk_code.payload_len == tmp_code.payload_len) + && (!strcmp(lnk_code.payload, tmp_code.payload)) + && (lnk_code.type == tmp_code.type)) { + lnk_code.rotation = ((lnk_code.rect.w * lnk_code.rect.h) > (tmp_code.rect.w * tmp_code.rect.h)) ? lnk_code.rotation : tmp_code.rotation; + lnk_code.quality += tmp_code.quality; // won't overflow + rectangle_united(&(lnk_code.rect), &(tmp_code.rect)); + merge_occured = true; + } else { + list_push_back(out, &tmp_code); + } + } + + list_push_back(&out_temp, &lnk_code); + } + + list_copy(out, &out_temp); + + if (!merge_occured) { + break; + } + } + + if (image.syms) { + image.data = NULL; + zbar_symbol_set_ref(image.syms, -1); + image.syms = NULL; + } + + zbar_image_scanner_destroy(scanner); + fb_free(); // umm_init_x(); + if (ptr->bpp != IMAGE_BPP_GRAYSCALE) fb_free(); // grayscale_image; +} + +#pragma GCC diagnostic pop +#endif //IMLIB_ENABLE_BARCODES diff --git a/src/openmv/src/omv/ini.c b/src/openmv/src/omv/ini.c new file mode 100755 index 0000000..3069d8b --- /dev/null +++ b/src/openmv/src/omv/ini.c @@ -0,0 +1,560 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include +#include +#include "ini.h" + +/*------------------------------------------------------------------------- + _isppace.c - part of ctype.h + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +char ini_isspace (unsigned char c) +{ + if ( c == ' ' + || c == '\f' + || c == '\n' + || c == '\r' + || c == '\t' + || c == '\v' ) + return 1; + + return 0; +} + +/* + * atoi.c -- + * + * Source code for the "atoi" library procedure. + * + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +/* + *---------------------------------------------------------------------- + * + * atoi -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If there + * are no decimal digits in string, then 0 is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +ini_atoi(string) + const char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ +{ + register int result = 0; + register unsigned int digit; + int sign; + + /* + * Skip any leading blanks. + */ + + while (ini_isspace(*string)) { + string += 1; + } + + /* + * Check for a sign. + */ + + if (*string == '-') { + sign = 1; + string += 1; + } else { + sign = 0; + if (*string == '+') { + string += 1; + } + } + + for (;*string; string++) { + digit = *string - '0'; + if ((digit < 0) || (digit > 9)) { + break; + } + result = (10*result) + digit; + } + + if (sign) { + return -result; + } + return result; +} + +bool ini_is_true(const char *value) +{ + int i = ini_atoi(value); + if (i) return true; + if (strlen(value) != 4) return false; + if ((value[0] != 'T') && (value[0] != 't')) return false; + if ((value[1] != 'R') && (value[1] != 'r')) return false; + if ((value[2] != 'U') && (value[2] != 'u')) return false; + if ((value[3] != 'E') && (value[3] != 'e')) return false; + return true; +} + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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 University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Copy src to dst, truncating or null-padding to always copy n bytes. + * Return dst. + */ +char * +strncpy(char *dst, const char *src, size_t n) +{ + if (n != 0) { + char *d = dst; + const char *s = src; + do { + if ((*d++ = *s++) == 0) { + /* NUL pad the remaining n-1 bytes */ + while (--n != 0) + *d++ = 0; + break; + } + } while (--n != 0); + } + return (dst); +} + +/* + * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se) + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Opsycon AB. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +/** ini_fgetc(fp) -- get char from stream */ + +int +ini_fgetc(FIL *fp) +{ + char c; + UINT b; + + if (f_read (fp, &c, 1, &b) != FR_OK || b != 1) + return (EOF); + return (c); +} + +/* + * Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se) + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Opsycon AB. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + +/** char *ini_fgets(dst,max,fp) -- get string from stream */ + +char * +ini_fgets(char *dst, int max, FIL *fp) +{ + int c = EOF; + char *p; + + /* get max bytes or upto a newline */ + + for (p = dst, max--; max > 0; max--) { + if ((c = ini_fgetc (fp)) == EOF) + break; + *p++ = c; + if (c == '\n') + break; + } + *p = 0; + if (p == dst || c == EOF) + return NULL; + return (p); +} + +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Used by ini_parse_string() to keep track of string parsing state. */ +typedef struct { + const char* ptr; + size_t num_left; +} ini_parse_string_ctx; + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && ini_isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && ini_isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char (of chars) or inline comment in given string, + or pointer to null at end of string if neither found. Inline comment must + be prefixed by a whitespace character to register as a comment. */ +static char* find_chars_or_comment(const char* s, const char* chars) +{ +#if INI_ALLOW_INLINE_COMMENTS + int was_space = 0; + while (*s && (!chars || !strchr(chars, *s)) && + !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { + was_space = ini_isspace((unsigned char)(*s)); + s++; + } +#else + while (*s && (!chars || !strchr(chars, *s))) { + s++; + } +#endif + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; + int max_line = INI_MAX_LINE; +#else + char* line; + int max_line = INI_INITIAL_ALLOC; +#endif +#if INI_ALLOW_REALLOC + char* new_line; + int offset; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_INITIAL_ALLOC); + if (!line) { + return -2; + } +#endif + +#if INI_HANDLER_LINENO +#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) +#else +#define HANDLER(u, s, n, v) handler(u, s, n, v) +#endif + + /* Scan through stream line by line */ + while (reader(line, max_line, stream) != NULL) { +#if INI_ALLOW_REALLOC + offset = strlen(line); + while (offset == max_line - 1 && line[offset - 1] != '\n') { + max_line *= 2; + if (max_line > INI_MAX_LINE) + max_line = INI_MAX_LINE; + new_line = realloc(line, max_line); + if (!new_line) { + free(line); + return -2; + } + line = new_line; + if (reader(line + offset, max_line - offset, stream) == NULL) + break; + if (max_line >= INI_MAX_LINE) + break; + offset += strlen(line + offset); + } +#endif + + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') { + /* Per Python configparser, allow both ; and # comments at the + start of a line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-blank line with leading whitespace, treat as continuation + of previous name's value (as per Python configparser). */ + if (!HANDLER(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_chars_or_comment(start + 1, "]"); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start) { + /* Not a comment, must be a name[=:]value pair */ + end = find_chars_or_comment(start, "=:"); + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = end + 1; +#if INI_ALLOW_INLINE_COMMENTS + end = find_chars_or_comment(value, NULL); + if (*end) + *end = '\0'; +#endif + value = lskip(value); + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!HANDLER(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse_file(FIL* file, ini_handler handler, void* user) +{ + return ini_parse_stream((ini_reader)ini_fgets, file, handler, user); +} + +/* See documentation in header file. */ +int ini_parse(FATFS *fs, const char* filename, ini_handler handler, void* user) +{ + FIL file; + int error; + + FRESULT res = f_open(fs, &file, filename, FA_READ | FA_OPEN_EXISTING); + if (res != FR_OK) + return -1; + error = ini_parse_file(&file, handler, user); + res = f_close(&file); + if (res != FR_OK) + return -1; + return error; +} + +/* An ini_reader function to read the next line from a string buffer. This + is the ini_fgets() equivalent used by ini_parse_string(). */ +static char* ini_reader_string(char* str, int num, void* stream) { + ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; + const char* ctx_ptr = ctx->ptr; + size_t ctx_num_left = ctx->num_left; + char* strp = str; + char c; + + if (ctx_num_left == 0 || num < 2) + return NULL; + + while (num > 1 && ctx_num_left != 0) { + c = *ctx_ptr++; + ctx_num_left--; + *strp++ = c; + if (c == '\n') + break; + num--; + } + + *strp = '\0'; + ctx->ptr = ctx_ptr; + ctx->num_left = ctx_num_left; + return str; +} + +/* See documentation in header file. */ +int ini_parse_string(const char* string, ini_handler handler, void* user) { + ini_parse_string_ctx ctx; + + ctx.ptr = string; + ctx.num_left = strlen(string); + return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, + user); +} diff --git a/src/openmv/src/omv/ini.h b/src/openmv/src/omv/ini.h new file mode 100755 index 0000000..1fff809 --- /dev/null +++ b/src/openmv/src/omv/ini.h @@ -0,0 +1,132 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +int ini_atoi(const char *string); +bool ini_is_true(const char *value); + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ff_wrapper.h" + +/* Nonzero if ini_handler callback should accept lineno parameter. */ +#ifndef INI_HANDLER_LINENO +#define INI_HANDLER_LINENO 0 +#endif + +/* Typedef for prototype of handler function. */ +#if INI_HANDLER_LINENO +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value, + int lineno); +#else +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value); +#endif + +/* Typedef for prototype of fgets-style reader function. */ +typedef char* (*ini_reader)(char* str, int num, void* stream); + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's configparser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(FATFS *fs, const char* filename, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes a FIL* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FIL* file, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes an ini_reader function pointer instead of + filename. Used for implementing custom or string-based I/O (see also + ini_parse_string). */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user); + +/* Same as ini_parse(), but takes a zero-terminated string with the INI data +instead of a file. Useful for parsing INI data from a network socket or +already in memory. */ +int ini_parse_string(const char* string, ini_handler handler, void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + configparser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Nonzero to allow inline comments (with valid inline comment characters + specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match + Python 3.2+ configparser behaviour. */ +#ifndef INI_ALLOW_INLINE_COMMENTS +#define INI_ALLOW_INLINE_COMMENTS 1 +#endif +#ifndef INI_INLINE_COMMENT_PREFIXES +#define INI_INLINE_COMMENT_PREFIXES ";" +#endif + +/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Maximum line length for any line in INI file (stack or heap). Note that + this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +/* Nonzero to allow heap line buffer to grow via realloc(), zero for a + fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is + zero. */ +#ifndef INI_ALLOW_REALLOC +#define INI_ALLOW_REALLOC 0 +#endif + +/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK + is zero. */ +#ifndef INI_INITIAL_ALLOC +#define INI_INITIAL_ALLOC 200 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */ diff --git a/src/openmv/src/omv/lepton.c b/src/openmv/src/omv/lepton.c new file mode 100755 index 0000000..62b0e5f --- /dev/null +++ b/src/openmv/src/omv/lepton.c @@ -0,0 +1,514 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Lepton driver. + * + */ + +#include STM32_HAL_H +#include "mp.h" +#include "irq.h" +#include "cambus.h" +#include "sensor.h" +#include "systick.h" +#include "framebuffer.h" +#include "omv_boardconfig.h" +#include "common.h" + +#if defined(OMV_ENABLE_LEPTON) +#include "crc16.h" +#include "LEPTON_SDK.h" +#include "LEPTON_AGC.h" +#include "LEPTON_SYS.h" +#include "LEPTON_VID.h" +#include "LEPTON_OEM.h" +#include "LEPTON_RAD.h" +#include "LEPTON_I2C_Reg.h" + +#define VOSPI_LINE_PIXELS (80) +#define VOSPI_NUMBER_PACKETS (60) +#define VOSPI_SPECIAL_PACKET (20) +#define VOSPI_LINE_SIZE (80 * 2) +#define VOSPI_HEADER_SIZE (4) +#define VOSPI_PACKET_SIZE (VOSPI_HEADER_SIZE + VOSPI_LINE_SIZE) +#define VOSPI_HEADER_SEG(buf) (((buf[0] >> 4) & 0x7)) +#define VOSPI_HEADER_PID(buf) (((buf[0] << 8) | (buf[1] << 0)) & 0x0FFF) +#define VOSPI_HEADER_CRC(buf) (((buf[2] << 8) | (buf[3] << 0))) +#define VOSPI_FIRST_PACKET (0) +#define VOSPI_FIRST_SEGMENT (1) +#define LEPTON_TIMEOUT (1000) + +static int h_res = 0; +static int v_res = 0; +static bool h_mirror = false; +static bool v_flip = false; + +static SPI_HandleTypeDef SPIHandle; +static DMA_HandleTypeDef DMAHandle; + +extern uint8_t _line_buf; +extern uint8_t _vospi_buf; +extern const uint16_t rainbow_table[256]; + +static bool vospi_resync = true; +static uint8_t *vospi_packet = &_line_buf; +static uint8_t *vospi_buffer = &_vospi_buf; +static volatile uint32_t vospi_pid = 0; +static volatile uint32_t vospi_seg = 1; +static uint32_t vospi_packets = 60; + +void LEPTON_SPI_IRQHandler(void) +{ + HAL_SPI_IRQHandler(&SPIHandle); +} + +void LEPTON_SPI_DMA_IRQHandler(void) +{ + HAL_DMA_IRQHandler(SPIHandle.hdmarx); +} + +static void lepton_sync() +{ + HAL_SPI_Abort(&SPIHandle); + + // Disable DMA IRQ + HAL_NVIC_DisableIRQ(LEPTON_SPI_DMA_IRQn); + + debug_printf("resync...\n"); + systick_sleep(200); + + vospi_resync = false; + vospi_pid = VOSPI_FIRST_PACKET; + vospi_seg = VOSPI_FIRST_SEGMENT; + + HAL_NVIC_EnableIRQ(LEPTON_SPI_DMA_IRQn); + HAL_SPI_Receive_DMA(&SPIHandle, vospi_packet, VOSPI_PACKET_SIZE); +} + +static uint16_t lepton_calc_crc(uint8_t *buf) +{ + buf[0] &= 0x0F; + buf[1] &= 0xFF; + buf[2] = 0; + buf[3] = 0; + return CalcCRC16Bytes(VOSPI_LINE_SIZE, (char *) buf); +} + +static int sleep(sensor_t *sensor, int enable) +{ + if (enable) { + DCMI_PWDN_LOW(); + systick_sleep(100); + } else { + DCMI_PWDN_HIGH(); + systick_sleep(100); + } + + return 0; +} + +static int read_reg(sensor_t *sensor, uint8_t reg_addr) +{ + uint16_t reg_data; + if (cambus_readw2(sensor->slv_addr, reg_addr, ®_data)) { + return -1; + } + return reg_data; +} + +static int write_reg(sensor_t *sensor, uint8_t reg_addr, uint16_t reg_data) +{ + return cambus_writew2(sensor->slv_addr, reg_addr, reg_data); +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + return 0; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + return 0; +} + +static int set_framerate(sensor_t *sensor, framerate_t framerate) +{ + return 0; +} + +static int set_contrast(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_brightness(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_saturation(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + return 0; +} + +static int set_quality(sensor_t *sensor, int quality) +{ + return 0; +} + +static int set_colorbar(sensor_t *sensor, int enable) +{ + return 0; +} + +static int set_special_effect(sensor_t *sensor, sde_t sde) +{ + return 0; +} + +static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling) +{ + return 0; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + return 0; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + return 0; +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) +{ + return 0; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + return 0; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + return 0; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + h_mirror = enable; + return 0; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + v_flip = enable; + return 0; +} + +static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef) +{ + return 0; +} + +static int reset(sensor_t *sensor) +{ + DCMI_PWDN_LOW(); + systick_sleep(10); + + DCMI_PWDN_HIGH(); + systick_sleep(10); + + DCMI_RESET_LOW(); + systick_sleep(10); + + DCMI_RESET_HIGH(); + systick_sleep(1000); + + LEP_AGC_ROI_T roi; + LEP_CAMERA_PORT_DESC_T handle = {0}; + h_res = v_res = h_mirror = v_flip = 0; + + for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) { + if (LEP_OpenPort(0, LEP_CCI_TWI, 0, &handle) == LEP_OK) { + break; + } + if (HAL_GetTick() - start >= LEPTON_TIMEOUT) { + return -1; + } + } + + for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) { + LEP_SDK_BOOT_STATUS_E status; + if (LEP_GetCameraBootStatus(&handle, &status) != LEP_OK) { + return -1; + } + if (status == LEP_BOOT_STATUS_BOOTED) { + break; + } + if (HAL_GetTick() - start >= LEPTON_TIMEOUT) { + return -1; + } + } + + for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) { + LEP_UINT16 status; + if (LEP_DirectReadRegister(&handle, LEP_I2C_STATUS_REG, &status) != LEP_OK) { + return -1; + } + if (!(status & LEP_I2C_STATUS_BUSY_BIT_MASK)) { + break; + } + if (HAL_GetTick() - start >= LEPTON_TIMEOUT) { + return -1; + } + } + + for (uint32_t start = HAL_GetTick(); ;systick_sleep(1)) { + LEP_SYS_STATUS_E status; + if (LEP_GetSysFFCStatus(&handle, &status) != LEP_OK) { + return -1; + } + if (status == LEP_SYS_STATUS_READY) { + break; + } + if (HAL_GetTick() - start >= (LEPTON_TIMEOUT * 5)) { + return -1; + } + } + + if (LEP_SetRadEnableState(&handle, LEP_RAD_DISABLE) != LEP_OK + || LEP_GetAgcROI(&handle, &roi) != LEP_OK + || LEP_SetAgcEnableState(&handle, LEP_AGC_ENABLE) != LEP_OK + || LEP_SetAgcCalcEnableState(&handle, LEP_AGC_ENABLE) != LEP_OK) { + return -1; + } + + h_res = roi.endCol + 1; + v_res = roi.endRow + 1; + + if (v_res > 60) { + vospi_packets = 240; + } else { + vospi_packets = 60; + } + + // resync and enable DMA before the first snapshot. + vospi_resync = true; + return 0; +} + +void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) +{ + (void) lepton_calc_crc; // to shut the compiler up. + + if (vospi_resync == true) { + return; // nothing to do here + } + + if (vospi_pid < vospi_packets && (vospi_packet[0] & 0xF) != 0xF) { + uint32_t pid = VOSPI_HEADER_PID(vospi_packet); + uint32_t seg = VOSPI_HEADER_SEG(vospi_packet); + if (pid != (vospi_pid % VOSPI_NUMBER_PACKETS)) { + if (vospi_pid == VOSPI_FIRST_PACKET) { + // Wait for the first packet of the first segement. + vospi_pid = VOSPI_FIRST_PACKET; + vospi_seg = VOSPI_FIRST_SEGMENT; + } else { // lost sync + vospi_resync = true; + debug_printf("lost sync, packet id:%lu expected id:%lu \n", pid, vospi_pid); + } + } else if (vospi_packets > 60 && pid == VOSPI_SPECIAL_PACKET && seg != vospi_seg ) { + if (vospi_seg == VOSPI_FIRST_SEGMENT) { + // Wait for the first packet of the first segement. + vospi_pid = VOSPI_FIRST_PACKET; + vospi_seg = VOSPI_FIRST_SEGMENT; + } else { // lost sync + vospi_resync = true; + debug_printf("lost sync, segment id:%lu expected id:%lu\n", seg, vospi_seg); + } + } else { + memcpy(vospi_buffer + vospi_pid * VOSPI_LINE_SIZE, + vospi_packet + VOSPI_HEADER_SIZE, VOSPI_LINE_SIZE); + if ((++vospi_pid % VOSPI_NUMBER_PACKETS) == 0) { + vospi_seg++; + } + } + } + +} + +static int snapshot(sensor_t *sensor, image_t *image, streaming_cb_t cb) +{ + if ((!h_res) || (!v_res) || (!sensor->framesize) || (!sensor->pixformat)) { + return -1; + } + + fb_update_jpeg_buffer(); + + vospi_pid = VOSPI_FIRST_PACKET; + vospi_seg = VOSPI_FIRST_SEGMENT; + do { + if (vospi_resync == true) { + lepton_sync(); + } + __WFI(); + } while (vospi_pid < vospi_packets); + + image->w = MAIN_FB()->w; + image->h = MAIN_FB()->h; + image->bpp = MAIN_FB()->bpp; // invalid + image->data = MAIN_FB()->pixels; // valid + + uint16_t *src = (uint16_t*) vospi_buffer; + + for (int y=0; y>8; + switch (sensor->pixformat) { + case PIXFORMAT_RGB565: { + IMAGE_PUT_RGB565_PIXEL(image, x, y, rainbow_table[val]); + break; + } + case PIXFORMAT_GRAYSCALE: { + IMAGE_PUT_GRAYSCALE_PIXEL(image, x, y, val); + break; + } + default: { + break; + } + } + } + } + + switch (sensor->pixformat) { + case PIXFORMAT_GRAYSCALE: { + MAIN_FB()->bpp = 1; + break; + } + case PIXFORMAT_RGB565: { + MAIN_FB()->bpp = 2; + break; + } + default: { + break; + } + } + + image->bpp = MAIN_FB()->bpp; + return 0; +} + +int lepton_init(sensor_t *sensor) +{ + sensor->gs_bpp = sizeof(uint8_t); + sensor->reset = reset; + sensor->sleep = sleep; + sensor->snapshot = snapshot; + sensor->read_reg = read_reg; + sensor->write_reg = write_reg; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_contrast = set_contrast; + sensor->set_brightness = set_brightness; + sensor->set_saturation = set_saturation; + sensor->set_gainceiling = set_gainceiling; + sensor->set_quality = set_quality; + sensor->set_colorbar = set_colorbar; + sensor->set_special_effect = set_special_effect; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + sensor->set_lens_correction = set_lens_correction; + + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + // Configure the DMA handler for Transmission process + DMAHandle.Instance = LEPTON_SPI_DMA_STREAM; + DMAHandle.Init.Request = LEPTON_SPI_DMA_REQUEST; + DMAHandle.Init.Mode = DMA_CIRCULAR; + DMAHandle.Init.Priority = DMA_PRIORITY_HIGH; + DMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; + // When the DMA is configured in direct mode (the FIFO is disabled), the source and + // destination transfer widths are equal, and both defined by PSIZE (MSIZE is ignored). + // Additionally, burst transfers are not possible (MBURST and PBURST are both ignored). + DMAHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + DMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + // Note MBURST and PBURST are ignored. + DMAHandle.Init.MemBurst = DMA_MBURST_INC4; + DMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + DMAHandle.Init.MemInc = DMA_MINC_ENABLE; + DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + + // NVIC configuration for DMA transfer complete interrupt + NVIC_SetPriority(LEPTON_SPI_DMA_IRQn, IRQ_PRI_DMA21); + HAL_NVIC_DisableIRQ(LEPTON_SPI_DMA_IRQn); + + HAL_DMA_DeInit(&DMAHandle); + if (HAL_DMA_Init(&DMAHandle) != HAL_OK) { + // Initialization Error + return -1; + } + + memset(&SPIHandle, 0, sizeof(SPIHandle)); + SPIHandle.Instance = LEPTON_SPI; + SPIHandle.Init.NSS = SPI_NSS_HARD_OUTPUT; + SPIHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; + SPIHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; + SPIHandle.Init.Mode = SPI_MODE_MASTER; + SPIHandle.Init.TIMode = SPI_TIMODE_DISABLE; + SPIHandle.Init.Direction = SPI_DIRECTION_2LINES_RXONLY; + SPIHandle.Init.DataSize = SPI_DATASIZE_8BIT; + SPIHandle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA; + SPIHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; + SPIHandle.Init.CLKPhase = SPI_PHASE_2EDGE; + SPIHandle.Init.CLKPolarity = SPI_POLARITY_HIGH; + SPIHandle.Init.BaudRatePrescaler = LEPTON_SPI_PRESCALER; + // Recommanded setting to avoid glitches + SPIHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + + if (HAL_SPI_Init(&SPIHandle) != HAL_OK) { + LEPTON_SPI_RESET(); + LEPTON_SPI_RELEASE(); + LEPTON_SPI_CLK_DISABLE(); + return -1; + } + + // Associate the initialized DMA handle to the the SPI handle + __HAL_LINKDMA(&SPIHandle, hdmarx, DMAHandle); + + // NVIC configuration for SPI transfer complete interrupt + NVIC_SetPriority(LEPTON_SPI_IRQn, IRQ_PRI_DCMI); + HAL_NVIC_EnableIRQ(LEPTON_SPI_IRQn); + + return 0; +} +#else +int lepton_init(sensor_t *sensor) +{ + return -1; +} +#endif //defined(OMV_ENABLE_LEPTON) diff --git a/src/openmv/src/omv/lepton.h b/src/openmv/src/omv/lepton.h new file mode 100755 index 0000000..c2a38fe --- /dev/null +++ b/src/openmv/src/omv/lepton.h @@ -0,0 +1,14 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Lepton driver. + * + */ +#ifndef __LEPTON_H__ +#define __LEPTON_H__ +#include "sensor.h" +#define LEPTON_XCLK_FREQ 25000000 +int lepton_init(sensor_t *sensor); +#endif // __LEPTON_H__ diff --git a/src/openmv/src/omv/main.c b/src/openmv/src/omv/main.c new file mode 100755 index 0000000..b68d194 --- /dev/null +++ b/src/openmv/src/omv/main.c @@ -0,0 +1,633 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * main function. + * + */ +#include +#include +#include +#include STM32_HAL_H +#include "mpconfig.h" +#include "systick.h" +#include "pendsv.h" +#include "qstr.h" +#include "nlr.h" +#include "lexer.h" +#include "parse.h" +#include "compile.h" +#include "runtime.h" +#include "obj.h" +#include "objmodule.h" +#include "objstr.h" +#include "gc.h" +#include "stackctrl.h" +#include "gccollect.h" +#include "readline.h" +#include "timer.h" +#include "pin.h" +#include "usb.h" +#include "rtc.h" +#include "storage.h" +#include "sdcard.h" +#include "ff.h" +#include "modnetwork.h" +#include "modmachine.h" + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "lib/utils/pyexec.h" + +#include "irq.h" +#include "rng.h" +#include "led.h" +#include "spi.h" +#include "i2c.h" +#include "uart.h" +#include "dac.h" +#include "can.h" +#include "extint.h" +#include "servo.h" + +#include "sensor.h" +#include "usbdbg.h" +#include "wifidbg.h" +#include "sdram.h" +#include "fb_alloc.h" +#include "ff_wrapper.h" + +#include "usbd_core.h" +#include "usbd_desc.h" +#include "usbd_cdc_msc_hid.h" +#include "usbd_cdc_interface.h" +#include "usbd_msc_storage.h" + +#include "py_sensor.h" +#include "py_image.h" +#include "py_lcd.h" +#include "py_fir.h" + +#include "framebuffer.h" + +#include "ini.h" + +int errno; +char _vfs_buf; +static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) &_vfs_buf; +pyb_thread_t pyb_thread_main; + +static const char fresh_main_py[] = +"# main.py -- put your code here!\n" +"import pyb, time\n" +"led = pyb.LED(3)\n" +"usb = pyb.USB_VCP()\n" +"while (usb.isconnected()==False):\n" +" led.on()\n" +" time.sleep(150)\n" +" led.off()\n" +" time.sleep(100)\n" +" led.on()\n" +" time.sleep(150)\n" +" led.off()\n" +" time.sleep(600)\n" +; + +static const char fresh_readme_txt[] = +"Thank you for supporting the OpenMV project!\r\n" +"\r\n" +"To download the IDE, please visit:\r\n" +"https://openmv.io/pages/download\r\n" +"\r\n" +"For tutorials and documentation, please visit:\r\n" +"http://docs.openmv.io/\r\n" +"\r\n" +"For technical support and projects, please visit the forums:\r\n" +"http://forums.openmv.io/\r\n" +"\r\n" +"Please use github to report bugs and issues:\r\n" +"https://github.com/openmv/openmv\r\n" +; + +#ifdef OPENMV1 +static const char fresh_selftest_py[] =""; +#else +static const char fresh_selftest_py[] = +"import sensor, time, pyb\n" +"\n" +"def test_int_adc():\n" +" adc = pyb.ADCAll(12)\n" +" # Test VBAT\n" +" vbat = adc.read_core_vbat()\n" +" vbat_diff = abs(vbat-3.3)\n" +" if (vbat_diff > 0.1):\n" +" raise Exception('INTERNAL ADC TEST FAILED VBAT=%fv'%vbat)\n" +"\n" +" # Test VREF\n" +" vref = adc.read_core_vref()\n" +" vref_diff = abs(vref-1.2)\n" +" if (vref_diff > 0.1):\n" +" raise Exception('INTERNAL ADC TEST FAILED VREF=%fv'%vref)\n" +" adc = None\n" +" print('INTERNAL ADC TEST PASSED...')\n" +"\n" +"def test_color_bars():\n" +" sensor.reset()\n" +" # Set sensor settings\n" +" sensor.set_brightness(0)\n" +" sensor.set_saturation(3)\n" +" sensor.set_gainceiling(8)\n" +" sensor.set_contrast(2)\n" +"\n" +" # Set sensor pixel format\n" +" sensor.set_framesize(sensor.QVGA)\n" +" sensor.set_pixformat(sensor.RGB565)\n" +"\n" +" # Enable colorbar test mode\n" +" sensor.set_colorbar(True)\n" +"\n" +" # Skip a few frames to allow the sensor settle down\n" +" for i in range(0, 100):\n" +" image = sensor.snapshot()\n" +"\n" +" #color bars thresholds\n" +" t = [lambda r, g, b: r < 70 and g < 70 and b < 70, # Black\n" +" lambda r, g, b: r < 70 and g < 70 and b > 200, # Blue\n" +" lambda r, g, b: r > 200 and g < 70 and b < 70, # Red\n" +" lambda r, g, b: r > 200 and g < 70 and b > 200, # Purple\n" +" lambda r, g, b: r < 70 and g > 200 and b < 70, # Green\n" +" lambda r, g, b: r < 70 and g > 200 and b > 200, # Aqua\n" +" lambda r, g, b: r > 200 and g > 200 and b < 70, # Yellow\n" +" lambda r, g, b: r > 200 and g > 200 and b > 200] # White\n" +"\n" +" # color bars are inverted for OV7725\n" +" if (sensor.get_id() == sensor.OV7725):\n" +" t = t[::-1]\n" +"\n" +" #320x240 image with 8 color bars each one is approx 40 pixels.\n" +" #we start from the center of the frame buffer, and average the\n" +" #values of 10 sample pixels from the center of each color bar.\n" +" for i in range(0, 8):\n" +" avg = (0, 0, 0)\n" +" idx = 40*i+20 #center of colorbars\n" +" for off in range(0, 10): #avg 10 pixels\n" +" rgb = image.get_pixel(idx+off, 120)\n" +" avg = tuple(map(sum, zip(avg, rgb)))\n" +"\n" +" if not t[i](avg[0]/10, avg[1]/10, avg[2]/10):\n" +" raise Exception('COLOR BARS TEST FAILED.'\n" +" 'BAR#(%d): RGB(%d,%d,%d)'%(i+1, avg[0]/10, avg[1]/10, avg[2]/10))\n" +"\n" +" print('COLOR BARS TEST PASSED...')\n" +"\n" +"if __name__ == '__main__':\n" +" print('')\n" +" test_int_adc()\n" +" if sensor.get_id() == sensor.OV7725: test_color_bars()\n" +"\n" +; +#endif + +void flash_error(int n) { + led_state(LED_RED, 0); + led_state(LED_GREEN, 0); + led_state(LED_BLUE, 0); + for (int i = 0; i < n; i++) { + led_state(LED_RED, 0); + HAL_Delay(100); + led_state(LED_RED, 1); + HAL_Delay(100); + } + led_state(LED_RED, 0); +} + +void NORETURN __fatal_error(const char *msg) { + FIL fp; + if (f_open(&vfs_fat->fatfs, &fp, "ERROR.LOG", + FA_WRITE|FA_CREATE_ALWAYS) == FR_OK) { + UINT bytes; + const char *hdr = "FATAL ERROR:\n"; + f_write(&fp, hdr, strlen(hdr), &bytes); + f_write(&fp, msg, strlen(msg), &bytes); + } + f_close(&fp); + storage_flush(); + + for (uint i = 0;;) { + led_toggle(((i++) & 3)); + for (volatile uint delay = 0; delay < 500000; delay++) { + } + } +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + __fatal_error(""); +} + +#ifndef NDEBUG +void __attribute__((weak)) + __assert_func(const char *file, int line, const char *func, const char *expr) { + (void)func; + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + __fatal_error(""); +} +#endif + +void make_flash_fs() +{ + FIL fp; + UINT n; + + led_state(LED_RED, 1); + + uint8_t working_buf[_MAX_SS]; + if (f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf)) != FR_OK) { + __fatal_error("Could not create LFS"); + } + + // Create default main.py + f_open(&vfs_fat->fatfs, &fp, "/main.py", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n); + f_close(&fp); + + // Create readme file + f_open(&vfs_fat->fatfs, &fp, "/README.txt", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n); + f_close(&fp); + + // Create default selftest.py + f_open(&vfs_fat->fatfs, &fp, "/selftest.py", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_selftest_py, sizeof(fresh_selftest_py) - 1 /* don't count null terminator */, &n); + f_close(&fp); + + led_state(LED_RED, 0); +} + +#ifdef STACK_PROTECTOR +uint32_t __stack_chk_guard=0xDEADBEEF; + +void NORETURN __stack_chk_fail(void) +{ + while (1) { + flash_error(100); + } +} +#endif + +typedef struct openmv_config { + bool wifidbg; + wifidbg_config_t wifidbg_config; +} openmv_config_t; + +#if 0 +int ini_handler_callback(void *user, const char *section, const char *name, const char *value) +{ + openmv_config_t *openmv_config = (openmv_config_t *) user; + + #define MATCH(s, n) ((strcmp(section, (s)) == 0) && (strcmp(name, (n)) == 0)) + + if (MATCH("BoardConfig", "REPLUart")) { + if (ini_is_true(value)) { + mp_obj_t args[2] = { + MP_OBJ_NEW_SMALL_INT(3), // UART Port + MP_OBJ_NEW_SMALL_INT(115200) // Baud Rate + }; + + MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t) &pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); + } + } else if (MATCH("BoardConfig", "WiFiDebug")) { + openmv_config->wifidbg = ini_is_true(value); + } else if (MATCH("WiFiConfig", "Mode")) { + openmv_config->wifidbg_config.mode = ini_atoi(value); + } else if (MATCH("WiFiConfig", "ClientSSID")) { + strncpy(openmv_config->wifidbg_config.client_ssid, value, WINC_MAX_SSID_LEN); + } else if (MATCH("WiFiConfig", "ClientKey")) { + strncpy(openmv_config->wifidbg_config.client_key, value, WINC_MAX_PSK_LEN); + } else if (MATCH("WiFiConfig", "ClientSecurity")) { + openmv_config->wifidbg_config.client_security = ini_atoi(value); + } else if (MATCH("WiFiConfig", "ClientChannel")) { + openmv_config->wifidbg_config.client_channel = ini_atoi(value); + } else if (MATCH("WiFiConfig", "AccessPointSSID")) { + strncpy(openmv_config->wifidbg_config.access_point_ssid, value, WINC_MAX_SSID_LEN); + } else if (MATCH("WiFiConfig", "AccessPointKey")) { + strncpy(openmv_config->wifidbg_config.access_point_key, value, WINC_MAX_PSK_LEN); + } else if (MATCH("WiFiConfig", "AccessPointSecurity")) { + openmv_config->wifidbg_config.access_point_security = ini_atoi(value); + } else if (MATCH("WiFiConfig", "AccessPointChannel")) { + openmv_config->wifidbg_config.access_point_channel = ini_atoi(value); + } else if (MATCH("WiFiConfig", "BoardName")) { + strncpy(openmv_config->wifidbg_config.board_name, value, WINC_MAX_BOARD_NAME_LEN); + } else { + return 0; + } + + return 1; + + #undef MATCH +} +#endif +FRESULT exec_boot_script(const char *path, bool selftest, bool interruptible) +{ + nlr_buf_t nlr; + bool interrupted = false; + FRESULT f_res = f_stat(&vfs_fat->fatfs, path, NULL); + + if (f_res == FR_OK) { + if (nlr_push(&nlr) == 0) { + // Enable IDE interrupts if allowed. + if (interruptible) { + usbdbg_set_irq_enabled(true); + usbdbg_set_script_running(true); + } + + // Parse, compile and execute the script. + pyexec_file(path); + nlr_pop(); + } else { + interrupted = true; + } + } + + // Disable IDE interrupts + usbdbg_set_irq_enabled(false); + usbdbg_set_script_running(false); + + if (interrupted) { + if (selftest) { + // Get the exception message. TODO: might be a hack. + mp_obj_str_t *str = mp_obj_exception_get_value((mp_obj_t)nlr.ret_val); + // If any of the self-tests fail log the exception message + // and loop forever. Note: IDE exceptions will not be caught. + __fatal_error((const char*) str->data); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + if (nlr_push(&nlr) == 0) { + flash_error(3); + nlr_pop(); + }// If this gets interrupted again ignore it. + } + } + + if (selftest && f_res == FR_OK) { + // Remove self tests script and flush cache + f_unlink(&vfs_fat->fatfs, path); + storage_flush(); + + // Set flag for SWD debugger. + // Note: main.py does not use the frame buffer. + MAIN_FB()->bpp = 0xDEADBEEF; + } + + return f_res; +} +int omv_main(void) +{ + int sensor_init_ret = 0; + bool sdcard_mounted = false; + bool first_soft_reset = true; + + // Uncomment to disable write buffer to get precise faults. + // NOTE: Cache should be disabled on M7. + //SCnSCB->ACTLR |= SCnSCB_ACTLR_DISDEFWBUF_Msk; + + // STM32F4xx HAL library initialization: + // - Set NVIC Group Priority to 4 + // - Configure the Flash prefetch, instruction and Data caches + // - Configure the Systick to generate an interrupt each 1 msec + // NOTE: The bootloader enables the CCM/DTCM memory. + HAL_Init(); + + // Basic sub-system init + led_init(); + pendsv_init(); + pyb_thread_init(&pyb_thread_main); + + // Re-enable IRQs (disabled by bootloader) + __enable_irq(); + +soft_reset: + led_state(LED_IR, 0); + led_state(LED_RED, 1); + led_state(LED_GREEN, 1); + led_state(LED_BLUE, 1); + + machine_init(); + + // Python threading init + mp_thread_init(); + + // Stack limit should be less than real stack size, so we have a + // chance to recover from limit hit. (Limit is measured in bytes) + mp_stack_set_top(&_ram_end); + mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 1024); + + // GC init + gc_init(&_heap_start, &_heap_end); + + // Micro Python init + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + // Initialise low-level sub-systems. Here we need to do the very basic + // things like zeroing out memory and resetting any of the sub-systems. + readline_init0(); + pin_init0(); + extint_init0(); + timer_init0(); + #if MICROPY_HW_ENABLE_CAN + can_init0(); + #endif + i2c_init0(); + spi_init0(); + uart_init0(); + MP_STATE_PORT(pyb_stdio_uart) = NULL; // need to zero + dac_init(); + pyb_usb_init0(); + sensor_init0(); + fb_alloc_init0(); + file_buffer_init0(); + py_lcd_init0(); + //py_fir_init0(); + servo_init(); + usbdbg_init(); + sdcard_init(); + + if (first_soft_reset) { + rtc_init_start(false); + } + + // Initialize the sensor and check the result after + // mounting the file-system to log errors (if any). + if (first_soft_reset) { + sensor_init_ret = sensor_init(); + } + + //mod_network_init(); + + // Remove the BASEPRI masking (if any) + irq_set_base_priority(0); + + // Initialize storage + if (sdcard_is_present()) { + // Init the vfs object + vfs_fat->flags = 0; + sdcard_init_vfs(vfs_fat, 1); + + // Try to mount the SD card + FRESULT res = f_mount(&vfs_fat->fatfs); + if (res != FR_OK) { + sdcard_mounted = false; + } else { + sdcard_mounted = true; + // Set USB medium to SD + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; + } + } + + if (sdcard_mounted == false) { + storage_init(); + + // init the vfs object + vfs_fat->flags = 0; + pyb_flash_init_vfs(vfs_fat); + + // Try to mount the flash + FRESULT res = f_mount(&vfs_fat->fatfs); + + if (res == FR_NO_FILESYSTEM) { + // Create a fresh fs + make_flash_fs(); + // Flush storage + storage_flush(); + } else if (res != FR_OK) { + __fatal_error("Could not access LFS\n"); + } + + // Set USB medium to flash + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; + } + + // Mount the storage device (there should be no other devices mounted at this point) + // we allocate this structure on the heap because vfs->next is a root pointer. + mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); + if (vfs == NULL) { + __fatal_error("Failed to alloc memory for vfs mount\n"); + } + + vfs->str = "/"; + vfs->len = 1; + vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); + vfs->next = NULL; + MP_STATE_VM(vfs_mount_table) = vfs; + MP_STATE_PORT(vfs_cur) = vfs; + + // set label + f_setlabel(&vfs_fat->fatfs, "OPENMV_DISK"); + + // Parse OpenMV configuration file. +#if 0 + openmv_config_t openmv_config; + if (first_soft_reset) { + memset(&openmv_config, 0, sizeof(openmv_config)); + // Parse config, and init wifi if enabled. + ini_parse(&vfs_fat->fatfs, "/openmv.config", ini_handler_callback, &openmv_config); + if (openmv_config.wifidbg == true && + wifidbg_init(&openmv_config.wifidbg_config) != 0) { + openmv_config.wifidbg = false; + } + } +#endif + // Run boot script(s) + if (first_soft_reset) { + // Execute the boot.py script before initializing the USB dev + // to override the USB mode if required, otherwise VCP+MSC is used. + exec_boot_script("/boot.py", false, false); + } + + // Init USB device to default setting if it was not already configured + if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { + pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); + } + + // check sensor init result + if (first_soft_reset && sensor_init_ret != 0) { + char buf[512]; + snprintf(buf, sizeof(buf), "Failed to init sensor, error:%d", sensor_init_ret); + __fatal_error(buf); + } + + // Turn boot-up LEDs off + led_state(LED_RED, 0); + led_state(LED_GREEN, 0); + led_state(LED_BLUE, 0); +#if 0 + if (openmv_config.wifidbg == true) { + timer_tim5_init(100); + } +#endif + // Run boot script(s) + if (first_soft_reset) { + exec_boot_script("/selftest.py", true, false); + exec_boot_script("/main.py", false, true); + } +#if 0 + do { + usbdbg_init(); + + // If there's no script ready, just re-exec REPL + while (!usbdbg_script_ready()) { + nlr_buf_t nlr; + + if (nlr_push(&nlr) == 0) { + // enable IDE interrupt + usbdbg_set_irq_enabled(true); + + // run REPL + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + + nlr_pop(); + } + } + + if (usbdbg_script_ready()) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // Enable IDE interrupt + usbdbg_set_irq_enabled(true); + + // Execute the script. + pyexec_str(usbdbg_get_script()); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + } + } while (openmv_config.wifidbg == true); +#endif + // Disable all other IRQs except Systick and Flash IRQs + // Note: FS IRQ is disable, since we're going for a soft-reset. + irq_set_base_priority(IRQ_PRI_FLASH+1); + + // soft reset + storage_flush(); + timer_deinit(); + uart_deinit(); + #if MICROPY_HW_ENABLE_CAN + can_deinit(); + #endif + pyb_thread_deinit(); + + first_soft_reset = false; + goto soft_reset; +} diff --git a/src/openmv/src/omv/mk b/src/openmv/src/omv/mk new file mode 100755 index 0000000..d886bc6 --- /dev/null +++ b/src/openmv/src/omv/mk @@ -0,0 +1,121 @@ +# Sources +#SRCS += $(addprefix , \ + xalloc.c \ + fb_alloc.c \ + umm_malloc.c \ + ff_wrapper.c \ + ini.c \ + framebuffer.c \ + array.c \ + cambus.c \ + ov9650.c \ + ov2640.c \ + ov7725.c \ + mt9v034.c \ + lepton.c \ + sensor.c \ + soft_i2c.c \ + mutex.c \ + trace.c \ + ) + +SRCS += $(addprefix , \ + xalloc.c \ + fb_alloc.c \ + umm_malloc.c \ + ff_wrapper.c \ + ini.c \ + framebuffer.c \ + array.c \ + mutex.c \ + trace.c \ + ) + +SRCS += $(addprefix img/, \ + binary.c \ + blob.c \ + clahe.c \ + draw.c \ + qrcode.c \ + apriltag.c \ + dmtx.c \ + zbar.c \ + fmath.c \ + fsort.c \ + qsort.c \ + fft.c \ + filter.c \ + haar.c \ + imlib.c \ + collections.c \ + stats.c \ + integral.c \ + integral_mw.c \ + kmeans.c \ + lab_tab.c \ + xyz_tab.c \ + yuv_tab.c \ + rainbow_tab.c \ + rgb2rgb_tab.c \ + invariant_tab.c \ + mathop.c \ + pool.c \ + point.c \ + rectangle.c \ + bmp.c \ + ppm.c \ + gif.c \ + mjpeg.c \ + fast.c \ + agast.c \ + orb.c \ + template.c \ + phasecorrelation.c \ + shadow_removal.c \ + font.c \ + jpeg.c \ + lbp.c \ + eye.c \ + hough.c \ + line.c \ + lsd.c \ + sincos_tab.c \ + edge.c \ + hog.c \ + selective_search.c \ + ) + +#SRCS += $(addprefix nn/, \ + nn.c \ + ) + + +SRCS += $(addprefix py/, \ + py_helper.c \ + py_omv.c \ + py_sensor.c \ + py_image.c \ + py_time.c \ + py_lcd.c \ + py_gif.c \ + py_mjpeg.c \ + py_cpufreq.c \ + py_nn.c \ + ) + +OBJS = $(addprefix $(BUILD)/, $(SRCS:.c=.o)) +OBJ_DIRS = $(sort $(dir $(OBJS))) + +all: | $(OBJ_DIRS) $(OBJS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/%.o : %.c + $(ECHO) "CC $<" + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD)/%.o : %.s + $(ECHO) "AS $<" + $(AS) $(AFLAGS) $< -o $@ + +-include $(OBJS:%.o=%.d) diff --git a/src/openmv/src/omv/mt9v034.c b/src/openmv/src/omv/mt9v034.c new file mode 100755 index 0000000..195f818 --- /dev/null +++ b/src/openmv/src/omv/mt9v034.c @@ -0,0 +1,548 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MT9V034 driver. + * + */ + +#include STM32_HAL_H +#include "cambus.h" +#include "mt9v034.h" +#include "systick.h" +#include "framebuffer.h" +#include "sensor.h" +#include "omv_boardconfig.h" +#if defined(OMV_ENABLE_MT9V034) +#define MT9V034_MAX_HEIGHT (480) +#define MT9V034_MAX_WIDTH (752) +#define MT9V034_CHIP_VERSION (0x00) +#define MT9V034_COL_START (0x01) +#define MT9V034_COL_START_MIN (1) +#define MT9V034_COL_START_MAX (752) +#define MT9V034_ROW_START (0x02) +#define MT9V034_ROW_START_MIN (4) +#define MT9V034_ROW_START_MAX (482) +#define MT9V034_WINDOW_HEIGHT (0x03) +#define MT9V034_WINDOW_HEIGHT_MIN (1) +#define MT9V034_WINDOW_HEIGHT_MAX (480) +#define MT9V034_WINDOW_WIDTH (0x04) +#define MT9V034_WINDOW_WIDTH_MIN (1) +#define MT9V034_WINDOW_WIDTH_MAX (752) +#define MT9V034_HORIZONTAL_BLANKING (0x05) +#define MT9V034_HORIZONTAL_BLANKING_MIN (43) +#define MT9V034_HORIZONTAL_BLANKING_MAX (1023) +#define MT9V034_HORIZONTAL_BLANKING_DEF (94) +#define MT9V034_VERTICAL_BLANKING (0x06) +#define MT9V034_VERTICAL_BLANKING_MIN (4) +#define MT9V034_VERTICAL_BLANKING_MAX (3000) +#define MT9V034_VERTICAL_BLANKING_DEF (45) +#define MT9V034_CHIP_CONTROL (0x07) +#define MT9V034_CHIP_CONTROL_MASTER_MODE (1 << 3) +#define MT9V034_CHIP_CONTROL_DOUT_ENABLE (1 << 7) +#define MT9V034_CHIP_CONTROL_SEQUENTIAL (1 << 8) +#define MT9V034_SHUTTER_WIDTH1 (0x08) +#define MT9V034_SHUTTER_WIDTH2 (0x09) +#define MT9V034_SHUTTER_WIDTH_CONTROL (0x0A) +#define MT9V034_TOTAL_SHUTTER_WIDTH (0x0B) +#define MT9V034_TOTAL_SHUTTER_WIDTH_MIN (1) +#define MT9V034_TOTAL_SHUTTER_WIDTH_MAX (32767) +#define MT9V034_RESET (0x0C) +#define MT9V034_READ_MODE (0x0D) +#define MT9V034_READ_MODE_ROW_BIN_2 (1 << 0) +#define MT9V034_READ_MODE_ROW_BIN_4 (1 << 1) +#define MT9V034_READ_MODE_COL_BIN_2 (1 << 2) +#define MT9V034_READ_MODE_COL_BIN_4 (1 << 3) +#define MT9V034_READ_MODE_ROW_FLIP (1 << 4) +#define MT9V034_READ_MODE_COL_FLIP (1 << 5) +#define MT9V034_READ_MODE_DARK_COLS (1 << 6) +#define MT9V034_READ_MODE_DARK_ROWS (1 << 7) +#define MT9V034_PIXEL_OPERATION_MODE (0x0F) +#define MT9V034_PIXEL_OPERATION_MODE_HDR (1 << 0) +#define MT9V034_PIXEL_OPERATION_MODE_COLOR (1 << 1) +#define MT9V034_ANALOG_GAIN (0x35) +#define MT9V034_ANALOG_GAIN_MIN (16) +#define MT9V034_ANALOG_GAIN_MAX (64) +#define MT9V034_MAX_ANALOG_GAIN (0x36) +#define MT9V034_MAX_ANALOG_GAIN_MAX (127) +#define MT9V034_FRAME_DARK_AVERAGE (0x42) +#define MT9V034_DARK_AVG_THRESH (0x46) +#define MT9V034_DARK_AVG_LOW_THRESH_MASK (255 << 0) +#define MT9V034_DARK_AVG_LOW_THRESH_SHIFT (0) +#define MT9V034_DARK_AVG_HIGH_THRESH_MASK (255 << 8) +#define MT9V034_DARK_AVG_HIGH_THRESH_SHIFT (8) +#define MT9V034_ROW_NOISE_CORR_CONTROL (0x70) +#define MT9V034_ROW_NOISE_CORR_ENABLE (1 << 5) +#define MT9V034_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) +#define MT9V034_PIXEL_CLOCK (0x72) +#define MT9V034_PIXEL_CLOCK_INV_LINE (1 << 0) +#define MT9V034_PIXEL_CLOCK_INV_FRAME (1 << 1) +#define MT9V034_PIXEL_CLOCK_XOR_LINE (1 << 2) +#define MT9V034_PIXEL_CLOCK_CONT_LINE (1 << 3) +#define MT9V034_PIXEL_CLOCK_INV_PXL_CLK (1 << 4) +#define MT9V034_TEST_PATTERN (0x7F) +#define MT9V034_TEST_PATTERN_DATA_MASK (1023 << 0) +#define MT9V034_TEST_PATTERN_DATA_SHIFT (0) +#define MT9V034_TEST_PATTERN_USE_DATA (1 << 10) +#define MT9V034_TEST_PATTERN_GRAY_MASK (3 << 11) +#define MT9V034_TEST_PATTERN_GRAY_NONE (0 << 11) +#define MT9V034_TEST_PATTERN_GRAY_VERTICAL (1 << 11) +#define MT9V034_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11) +#define MT9V034_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) +#define MT9V034_TEST_PATTERN_ENABLE (1 << 13) +#define MT9V034_TEST_PATTERN_FLIP (1 << 14) +#define MT9V034_AEC_AGC_ENABLE (0xAF) +#define MT9V034_AEC_ENABLE (1 << 0) +#define MT9V034_AGC_ENABLE (1 << 1) +#define MT9V034_THERMAL_INFO (0xC1) +#define MT9V034_ID_REG (0x6B) +#define MT9V034_MAX_GAIN (0xAB) +#define MT9V034_MAX_EXPOSE (0xAD) +#define MT9V034_PIXEL_COUNT (0xB0) +#define MT9V034_FINE_SHUTTER_WIDTH_TOTAL (0xD5) + +#define MICROSECOND_CLKS (1000000) + +typedef enum { MT9V034_NOT_SET, MT9V034_CFA, MT9V034_GS, MT9V034_GS_CFA } MT9V034_mode_t; +static MT9V034_mode_t MT9V034_mode = MT9V034_NOT_SET; + +static int reset(sensor_t *sensor) +{ + MT9V034_mode = MT9V034_NOT_SET; + + DCMI_PWDN_HIGH(); + systick_sleep(1); + + DCMI_PWDN_LOW(); + systick_sleep(1); + + DCMI_RESET_LOW(); + systick_sleep(1); + + DCMI_RESET_HIGH(); + systick_sleep(1); + + int ret = 0; + + // Setup reconmended reserved register settings. + ret |= cambus_writew(sensor->slv_addr, 0x13, 0x2D2E); + ret |= cambus_writew(sensor->slv_addr, 0x20, 0x01C7); + ret |= cambus_writew(sensor->slv_addr, 0x24, 0x001B); + ret |= cambus_writew(sensor->slv_addr, 0x2B, 0x0003); + ret |= cambus_writew(sensor->slv_addr, 0x2F, 0x0003); + + ret |= cambus_writew(sensor->slv_addr, MT9V034_READ_MODE, + MT9V034_READ_MODE_ROW_FLIP | MT9V034_READ_MODE_COL_FLIP); + + ret |= cambus_writew(sensor->slv_addr, MT9V034_PIXEL_OPERATION_MODE, + MT9V034_PIXEL_OPERATION_MODE_HDR | MT9V034_PIXEL_OPERATION_MODE_COLOR); + + return ret; +} + +static int sleep(sensor_t *sensor, int enable) +{ + if (enable) { + DCMI_PWDN_HIGH(); + systick_sleep(1); + } else { + DCMI_PWDN_LOW(); + systick_sleep(1); + } + + return 0; +} + +static int read_reg(sensor_t *sensor, uint8_t reg_addr) +{ + uint16_t reg_data; + + if (cambus_readw(sensor->slv_addr, reg_addr, ®_data) != 0) { + return -1; + } + + return reg_data; +} + +static int write_reg(sensor_t *sensor, uint8_t reg_addr, uint16_t reg_data) +{ + return cambus_writew(sensor->slv_addr, reg_addr, reg_data); +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + return 0; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + uint16_t width = resolution[framesize][0]; + uint16_t height = resolution[framesize][1]; + + if (sensor->pixformat == PIXFORMAT_INVLAID) { + return -1; + } + + if ((width > MT9V034_MAX_WIDTH) || (height > MT9V034_MAX_HEIGHT)) { + return -1; + } + + uint16_t reg, read_mode; + + if (cambus_readw(sensor->slv_addr, MT9V034_ID_REG, ®) != 0) { + return -1; + } + + if (cambus_readw(sensor->slv_addr, MT9V034_READ_MODE, &read_mode) != 0) { + return -1; + } + + read_mode &= 0xFFF0; + bool is_cfa = ((reg >> 9) & 0x7) == 0x6; + MT9V034_mode_t mode_tmp = is_cfa ? MT9V034_CFA : MT9V034_GS; + int read_mode_mul = 1; + + if ((!is_cfa) || (sensor->pixformat == PIXFORMAT_GRAYSCALE)) { + if ((width <= (MT9V034_MAX_WIDTH / 4)) && (height <= (MT9V034_MAX_HEIGHT / 4))) { + read_mode_mul = 4; + read_mode |= MT9V034_READ_MODE_COL_BIN_4 | MT9V034_READ_MODE_ROW_BIN_4; + } else if ((width <= (MT9V034_MAX_WIDTH / 2)) && (height <= (MT9V034_MAX_HEIGHT / 2))) { + read_mode_mul = 2; + read_mode |= MT9V034_READ_MODE_COL_BIN_2 | MT9V034_READ_MODE_ROW_BIN_2; + } else if (is_cfa && (sensor->pixformat == PIXFORMAT_GRAYSCALE)) { + mode_tmp = MT9V034_GS_CFA; + } + } + + int ret = 0; + + ret |= cambus_writew(sensor->slv_addr, MT9V034_COL_START, + ((MT9V034_MAX_WIDTH - (width * read_mode_mul)) / 2) + MT9V034_COL_START_MIN); + ret |= cambus_writew(sensor->slv_addr, MT9V034_ROW_START, + ((MT9V034_MAX_HEIGHT - (height * read_mode_mul)) / 2) + MT9V034_ROW_START_MIN); + ret |= cambus_writew(sensor->slv_addr, MT9V034_WINDOW_WIDTH, width * read_mode_mul); + ret |= cambus_writew(sensor->slv_addr, MT9V034_WINDOW_HEIGHT, height * read_mode_mul); + + // Notes: 1. The MT9V034 uses column parallel analog-digital converters, thus short row timing is not possible. + // The minimum total row time is 690 columns (horizontal width + horizontal blanking). The minimum + // horizontal blanking is 61. When the window width is set below 627, horizontal blanking + // must be increased. + ret |= cambus_writew(sensor->slv_addr, MT9V034_HORIZONTAL_BLANKING, + MT9V034_HORIZONTAL_BLANKING_DEF + (MT9V034_MAX_WIDTH - (width * read_mode_mul))); + + ret |= cambus_writew(sensor->slv_addr, MT9V034_READ_MODE, read_mode); + ret |= cambus_writew(sensor->slv_addr, MT9V034_PIXEL_COUNT, (width * height) / 8); + + if (ret == 0) { + MT9V034_mode = mode_tmp; + } + + return ret; +} + +static int set_framerate(sensor_t *sensor, framerate_t framerate) +{ + return 0; +} + +static int set_contrast(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_brightness(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_saturation(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + return 0; +} + +static int set_quality(sensor_t *sensor, int quality) +{ + return 0; +} + +static int set_colorbar(sensor_t *sensor, int enable) +{ + uint16_t test; + int ret = cambus_readw(sensor->slv_addr, MT9V034_TEST_PATTERN, &test); + ret |= cambus_writew(sensor->slv_addr, MT9V034_TEST_PATTERN, + (test & (~(MT9V034_TEST_PATTERN_ENABLE | MT9V034_TEST_PATTERN_GRAY_MASK))) + | ((enable != 0) ? (MT9V034_TEST_PATTERN_ENABLE | MT9V034_TEST_PATTERN_GRAY_VERTICAL) : 0)); + return ret; +} + +static int set_special_effect(sensor_t *sensor, sde_t sde) +{ + return 0; +} + +static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling) +{ + uint16_t reg; + int ret = cambus_readw(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, ®); + ret |= cambus_writew(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, + (reg & (~MT9V034_AGC_ENABLE)) | ((enable != 0) ? MT9V034_AGC_ENABLE : 0)); + + if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) { + int gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db / 20.0) * fast_log(10.0)) * 16.0), 127), 0); + + ret |= cambus_readw(sensor->slv_addr, MT9V034_ANALOG_GAIN, ®); + ret |= cambus_writew(sensor->slv_addr, MT9V034_ANALOG_GAIN, (reg & 0xFF80) | gain); + } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) { + int gain_ceiling = IM_MAX(IM_MIN(fast_roundf(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)) * 16.0), 127), 16); + + ret |= cambus_readw(sensor->slv_addr, MT9V034_MAX_GAIN, ®); + ret |= cambus_writew(sensor->slv_addr, MT9V034_MAX_GAIN, (reg & 0xFF80) | gain_ceiling); + } + + return ret; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + uint16_t gain; + int ret = cambus_readw(sensor->slv_addr, MT9V034_ANALOG_GAIN, &gain); + + *gain_db = 20.0 * (fast_log((gain & 0x7F) / 16.0) / fast_log(10.0)); + + return ret; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + uint16_t reg, row_time_0, row_time_1; + int ret = cambus_readw(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, ®); + ret |= cambus_writew(sensor->slv_addr, MT9V034_AEC_AGC_ENABLE, + (reg & (~MT9V034_AEC_ENABLE)) | ((enable != 0) ? MT9V034_AEC_ENABLE : 0)); + + if ((enable == 0) && (exposure_us >= 0)) { + ret |= cambus_readw(sensor->slv_addr, MT9V034_WINDOW_WIDTH, &row_time_0); + ret |= cambus_readw(sensor->slv_addr, MT9V034_HORIZONTAL_BLANKING, &row_time_1); + + int exposure = IM_MIN(exposure_us, MICROSECOND_CLKS / 2) * (MT9V034_XCLK_FREQ / MICROSECOND_CLKS); + int row_time = row_time_0 + row_time_1; + int coarse_time = exposure / row_time; + int fine_time = exposure % row_time; + + ret |= cambus_writew(sensor->slv_addr, MT9V034_TOTAL_SHUTTER_WIDTH, coarse_time); + ret |= cambus_writew(sensor->slv_addr, MT9V034_FINE_SHUTTER_WIDTH_TOTAL, fine_time); + } + + return ret; +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) +{ + uint16_t int_rows, int_pixels, row_time_0, row_time_1; + int ret = cambus_readw(sensor->slv_addr, MT9V034_TOTAL_SHUTTER_WIDTH, &int_rows); + ret |= cambus_readw(sensor->slv_addr, MT9V034_FINE_SHUTTER_WIDTH_TOTAL, &int_pixels); + ret |= cambus_readw(sensor->slv_addr, MT9V034_WINDOW_WIDTH, &row_time_0); + ret |= cambus_readw(sensor->slv_addr, MT9V034_HORIZONTAL_BLANKING, &row_time_1); + + *exposure_us = ((int_rows * (row_time_0 + row_time_1)) + int_pixels) / (MT9V034_XCLK_FREQ / MICROSECOND_CLKS); + + return ret; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + return 0; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + return 0; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + uint16_t read_mode; + int ret = cambus_readw(sensor->slv_addr, MT9V034_READ_MODE, &read_mode); + ret |= cambus_writew(sensor->slv_addr, MT9V034_READ_MODE, // inverted behavior + (read_mode & (~MT9V034_READ_MODE_COL_FLIP)) | ((enable == 0) ? MT9V034_READ_MODE_COL_FLIP : 0)); + return ret; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + uint16_t read_mode; + int ret = cambus_readw(sensor->slv_addr, MT9V034_READ_MODE, &read_mode); + ret |= cambus_writew(sensor->slv_addr, MT9V034_READ_MODE, // inverted behavior + (read_mode & (~MT9V034_READ_MODE_ROW_FLIP)) | ((enable == 0) ? MT9V034_READ_MODE_ROW_FLIP : 0)); + return ret; +} + +static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef) +{ + return 0; +} + +static int snapshot(sensor_t *sensor, image_t *image, streaming_cb_t cb) +{ + if ((!sensor->pixformat) || (!sensor->framesize) || (MT9V034_mode == MT9V034_NOT_SET)) { + return -1; + } + + pixformat_t pixformat_bak = sensor->pixformat; + sensor->pixformat = PIXFORMAT_GRAYSCALE; + + image_t new_image; + DCMI_FSIN_HIGH(); + int ret = sensor_snapshot(sensor, &new_image, NULL); + DCMI_FSIN_LOW(); + + sensor->pixformat = pixformat_bak; + + if (ret != 0) { + return -1; + } + + if (MT9V034_mode == MT9V034_GS) { + switch (sensor->pixformat) { + case PIXFORMAT_BAYER: { + new_image.bpp = IMAGE_BPP_BAYER; + break; + } + case PIXFORMAT_GRAYSCALE: { + new_image.bpp = IMAGE_BPP_GRAYSCALE; + break; + } + case PIXFORMAT_RGB565: { + new_image.bpp = IMAGE_BPP_RGB565; + uint16_t *rgbbuf = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(&new_image)); + + for (int y = new_image.h - 1; y >= 0; y--) { + imlib_bayer_to_rgb565(&new_image, new_image.w, 1, 0, y, rgbbuf); + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&new_image, y), + rgbbuf, IMAGE_RGB565_LINE_LEN_BYTES(&new_image)); + } + + fb_free(); + break; + } + default : { + return -1; + } + } + } else { + switch (sensor->pixformat) { + case PIXFORMAT_BAYER: { + new_image.bpp = IMAGE_BPP_BAYER; + break; + } + case PIXFORMAT_GRAYSCALE: { + new_image.bpp = IMAGE_BPP_GRAYSCALE; + if (MT9V034_mode == MT9V034_GS_CFA) { + int ksize = 1, brows = ksize + 1; + image_t buf; + buf.w = new_image.w; + buf.h = brows; + buf.bpp = new_image.bpp; + buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(&new_image) * brows); + uint16_t *rgbbuf = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(&new_image)); + + for (int y = 0, yy = new_image.h; y < yy; y++) { + uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)); + imlib_bayer_to_rgb565(&new_image, new_image.w, 1, 0, y, rgbbuf); + + for (int x = 0, xx = new_image.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(rgbbuf, x))); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&new_image, (y - ksize)), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(&new_image)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = new_image.h - ksize, yy = new_image.h; y < yy; y++) { + memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&new_image, y), + IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_GRAYSCALE_LINE_LEN_BYTES(&new_image)); + } + + fb_free(); + fb_free(); + } + break; + } + case PIXFORMAT_RGB565: { + new_image.bpp = IMAGE_BPP_RGB565; + uint16_t *rgbbuf = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(&new_image)); + + for (int y = new_image.h - 1; y >= 0; y--) { + imlib_bayer_to_rgb565(&new_image, new_image.w, 1, 0, y, rgbbuf); + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&new_image, y), + rgbbuf, IMAGE_RGB565_LINE_LEN_BYTES(&new_image)); + } + + fb_free(); + break; + } + default : { + return -1; + } + } + } + + if (image) { + memcpy(image, &new_image, sizeof(image_t)); + } + + return 0; +} + +int mt9v034_init(sensor_t *sensor) +{ + sensor->gs_bpp = sizeof(uint8_t); + sensor->reset = reset; + sensor->sleep = sleep; + sensor->read_reg = read_reg; + sensor->write_reg = write_reg; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_contrast = set_contrast; + sensor->set_brightness = set_brightness; + sensor->set_saturation = set_saturation; + sensor->set_gainceiling = set_gainceiling; + sensor->set_quality = set_quality; + sensor->set_colorbar = set_colorbar; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + sensor->set_special_effect = set_special_effect; + sensor->set_lens_correction = set_lens_correction; + sensor->snapshot = snapshot; + + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + return 0; +} +#else +int mt9v034_init(sensor_t *sensor) +{ + return -1; +} +#endif //defined(OMV_ENABLE_MT9V034) diff --git a/src/openmv/src/omv/mt9v034.h b/src/openmv/src/omv/mt9v034.h new file mode 100755 index 0000000..782c135 --- /dev/null +++ b/src/openmv/src/omv/mt9v034.h @@ -0,0 +1,14 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MT9V034 driver. + * + */ +#ifndef __MT9V034_H__ +#define __MT9V034_H__ +#include "sensor.h" +#define MT9V034_XCLK_FREQ 27000000 +int mt9v034_init(sensor_t *sensor); +#endif // __MT9V034_H__ diff --git a/src/openmv/src/omv/mutex.c b/src/openmv/src/omv/mutex.c new file mode 100755 index 0000000..579ec91 --- /dev/null +++ b/src/openmv/src/omv/mutex.c @@ -0,0 +1,35 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Mutex. + * + */ +#include "mutex.h" + +// This is a standard implementation of mutexs on ARM processors following the ARM guide. +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEJCHB.html + +void mutex_init(mutex_t *mutex) +{ + return; +} + +void mutex_lock(mutex_t *mutex, uint32_t tid) +{ + return; +} + + +int mutex_try_lock(mutex_t *mutex, uint32_t tid) +{ + return 1; +} + + +void mutex_unlock(mutex_t *mutex, uint32_t tid) +{ + return; +} + diff --git a/src/openmv/src/omv/mutex.h b/src/openmv/src/omv/mutex.h new file mode 100755 index 0000000..c249be0 --- /dev/null +++ b/src/openmv/src/omv/mutex.h @@ -0,0 +1,23 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Mutex. + * + */ +#ifndef __MUTEX_H__ +#define __MUTEX_H__ +#include +#define MUTEX_TID_IDE (1<<0) +#define MUTEX_TID_OMV (1<<1) + +typedef volatile struct { + uint32_t tid; + uint32_t lock; +} mutex_t; +void mutex_init(mutex_t *mutex); +void mutex_lock(mutex_t *mutex, uint32_t tid); +int mutex_try_lock(mutex_t *mutex, uint32_t tid); +void mutex_unlock(mutex_t *mutex, uint32_t tid); +#endif /* __MUTEX_H__ */ diff --git a/src/openmv/src/omv/nn/nn.c b/src/openmv/src/omv/nn/nn.c new file mode 100755 index 0000000..56ea6cf --- /dev/null +++ b/src/openmv/src/omv/nn/nn.c @@ -0,0 +1,580 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CNN code. + * + */ +#include "nn.h" +#include "imlib.h" +#include "common.h" +#include "ff_wrapper.h" +#include "arm_math.h" +#include "arm_nnfunctions.h" +#include "omv_boardconfig.h" +#ifdef IMLIB_ENABLE_CNN + +static const char *layer_to_str(layer_type_t type) +{ + static const char *layers[] = { + "DATA", "CONV", "RELU", "POOL", "IP" + }; + if (type > sizeof(layers)/sizeof(layers[0])) { + return "Unknown layer"; + } else { + return layers[type]; + } +} + +int nn_dump_network(nn_t *net) +{ + layer_t *layer = net->layers; + + printf("Net type: %4s Num layers: %lu Max layer: %lu Max col buf: %lu Max scratch buf: %lu\n", + net->type, net->n_layers, net->max_layer_size, net->max_colbuf_size, net->max_scrbuf_size); + + while (layer != NULL) { + printf("Layer: %s Shape: [%lu, %lu, %lu, %lu] ", + layer_to_str(layer->type), layer->n, layer->c, layer->h, layer->w); + switch (layer->type) { + case LAYER_TYPE_DATA: { + data_layer_t *data_layer = (data_layer_t *) layer; + printf("r_mean: %lu g_mean: %lu b_mean: %lu scale: %lu\n", + data_layer->r_mean, data_layer->g_mean, data_layer->b_mean, data_layer->scale); + break; + } + + case LAYER_TYPE_CONV: { + conv_layer_t *conv_layer = (conv_layer_t *) layer; + printf("l_shift: %lu r_shift:%lu k_size: %lu k_stride: %lu k_padding: %lu\n", + conv_layer->l_shift, conv_layer->r_shift, + conv_layer->krn_dim, conv_layer->krn_str, conv_layer->krn_pad); + break; + } + + case LAYER_TYPE_RELU: { + // Nothing to read for RELU layer + printf("\n"); + //relu_layer_t *relu_layer = layer; + break; + } + + case LAYER_TYPE_POOL: { + pool_layer_t *pool_layer = (pool_layer_t *) layer; + printf("k_size: %lu k_stride: %lu k_padding: %lu\n", + pool_layer->krn_dim, pool_layer->krn_str, pool_layer->krn_pad); + break; + } + + case LAYER_TYPE_IP: { + ip_layer_t *ip_layer = (ip_layer_t*) layer; + printf("l_shift: %lu r_shift:%lu\n", ip_layer->l_shift, ip_layer->r_shift); + break; + } + } + layer = layer->next; + } + return 0; +} + +int nn_load_network(nn_t *net, const char *path) +{ + FIL fp; + int res = 0; + + file_read_open(&fp, path); + file_buffer_on(&fp); + + // Read network type + read_data(&fp, net->type, 4); + + // Read number of layers + read_data(&fp, &net->n_layers, 4); + + layer_t *prev_layer = NULL; + for (int i=0; in_layers; i++) { + layer_t *layer; + layer_type_t layer_type; + + // Read layer type + read_data(&fp, &layer_type, 4); + switch (layer_type) { + case LAYER_TYPE_DATA: + layer = xalloc0(sizeof(data_layer_t)); + break; + case LAYER_TYPE_CONV: + layer = xalloc0(sizeof(conv_layer_t)); + break; + case LAYER_TYPE_RELU: + layer = xalloc0(sizeof(relu_layer_t)); + break; + case LAYER_TYPE_POOL: + layer = xalloc0(sizeof(pool_layer_t)); + break; + case LAYER_TYPE_IP: + layer = xalloc0(sizeof(ip_layer_t)); + break; + default: + res = -1; + goto error; + } + + if (prev_layer == NULL) { // First layer + net->layers = layer; + } else { + layer->prev = prev_layer; + prev_layer->next = layer; + } + prev_layer = layer; + + // Set type + layer->type = layer_type; + + // Read layer shape (NCHW) + read_data(&fp, &layer->n, 4); + read_data(&fp, &layer->c, 4); + read_data(&fp, &layer->h, 4); + read_data(&fp, &layer->w, 4); + + switch (layer_type) { + case LAYER_TYPE_DATA: { + data_layer_t *data_layer = (data_layer_t *) layer; + // Read data layer R, G, B mean and input scale + read_data(&fp, &data_layer->r_mean, 4); + read_data(&fp, &data_layer->g_mean, 4); + read_data(&fp, &data_layer->b_mean, 4); + read_data(&fp, &data_layer->scale, 4); + break; + } + + case LAYER_TYPE_CONV: { + conv_layer_t *conv_layer = (conv_layer_t *) layer; + // Read layer l_shift, r_shift + read_data(&fp, &conv_layer->l_shift, 4); + read_data(&fp, &conv_layer->r_shift, 4); + // Read krnel dim, stride and padding + read_data(&fp, &conv_layer->krn_dim, 4); + read_data(&fp, &conv_layer->krn_pad, 4); + read_data(&fp, &conv_layer->krn_str, 4); + + // Alloc and read weights array + read_data(&fp, &conv_layer->w_size, 4); + conv_layer->wt = xalloc(conv_layer->w_size); + read_data(&fp, conv_layer->wt, conv_layer->w_size); + + // Alloc and read bias array + read_data(&fp, &conv_layer->b_size, 4); + conv_layer->bias = xalloc(conv_layer->b_size); + read_data(&fp, conv_layer->bias, conv_layer->b_size); + break; + } + + case LAYER_TYPE_RELU: { + // Nothing to read for RELU layer + break; + } + + case LAYER_TYPE_POOL: { + pool_layer_t *pool_layer = (pool_layer_t *) layer; + // Read pooling layer type + read_data(&fp, &pool_layer->ptype, 4); + // Read krnel dim, stride and padding + read_data(&fp, &pool_layer->krn_dim, 4); + read_data(&fp, &pool_layer->krn_pad, 4); + read_data(&fp, &pool_layer->krn_str, 4); + break; + } + + case LAYER_TYPE_IP: { + ip_layer_t *ip_layer = (ip_layer_t *) layer; + // Read layer l_shift, r_shift + read_data(&fp, &ip_layer->l_shift, 4); + read_data(&fp, &ip_layer->r_shift, 4); + + // Alloc and read weights array + read_data(&fp, &ip_layer->w_size, 4); + ip_layer->wt = xalloc(ip_layer->w_size); + read_data(&fp, ip_layer->wt, ip_layer->w_size); + + // Alloc and read bias array + read_data(&fp, &ip_layer->b_size, 4); + ip_layer->bias = xalloc(ip_layer->b_size); + read_data(&fp, ip_layer->bias, ip_layer->b_size); + break; + } + } + } + + layer_t *layer = net->layers; + while (layer != NULL) { + // First layer is DATA will be skipped, so prev_layer *should* not be NULL. + prev_layer = layer->prev; + + if (layer->type == LAYER_TYPE_IP) { + uint32_t fc_buffer_size = 2 * prev_layer->c * prev_layer->w * prev_layer->h; + net->max_colbuf_size = IM_MAX(net->max_colbuf_size, fc_buffer_size); + } + + if (layer->type == LAYER_TYPE_CONV) { + conv_layer_t *conv_layer = (conv_layer_t *) layer; + uint32_t im2col_buffer_size = 2 * 2 * conv_layer->c * conv_layer->krn_dim * conv_layer->krn_dim; + net->max_colbuf_size = IM_MAX(net->max_colbuf_size, im2col_buffer_size); + } + + if (layer->type == LAYER_TYPE_IP) { + uint32_t buffer_size = layer->c; + if (prev_layer->type == LAYER_TYPE_IP) { + buffer_size = buffer_size + prev_layer->c; + } else if (prev_layer->type == LAYER_TYPE_CONV || prev_layer->type == LAYER_TYPE_POOL) { + buffer_size = buffer_size + prev_layer->c * prev_layer->h * prev_layer->w; + } + net->max_scrbuf_size = IM_MAX(net->max_scrbuf_size, buffer_size); + } + + if (layer->type == LAYER_TYPE_CONV || layer->type == LAYER_TYPE_POOL) { + uint32_t buffer_size = layer->c * layer->h * layer->w + prev_layer->c * prev_layer->h * prev_layer->w; + net->max_scrbuf_size = IM_MAX(net->max_scrbuf_size, buffer_size); + } + + uint32_t layer_size = layer->c * layer->h * layer->w; + net->max_layer_size = IM_MAX(net->max_layer_size, layer_size); + if (layer->next == NULL) { + net->output_size = layer->c; + } + layer = layer->next; + } + + // Alloc output buffer. + net->output_data = xalloc(net->output_size); +error: + file_buffer_off(&fp); + file_close(&fp); + return res; +} + +#ifndef __SSAT +#define __SSAT(a, b) ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _b = 1 << (_b - 1); \ + _a = _a < (_b - 1) ? _a : (_b - 1); \ + _a > (-_b) ? _a : (-_b); }) +#endif + +void nn_transform_input(data_layer_t *data_layer, image_t *img, q7_t *input_data, rectangle_t *roi) +{ + int input_scale = data_layer->scale; + // Scale, convert and normalize input image. + int x_ratio = (int)((roi->w<<16)/data_layer->w)+1; + int y_ratio = (int)((roi->h<<16)/data_layer->h)+1; + + if ((img->bpp == 2) && (data_layer->c == 3)) { // RGB565 to RGB888 + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i+=3) { + int sx = (x*x_ratio)>>16; + uint16_t p = IM_GET_RGB565_PIXEL(img, sx+roi->x, sy+roi->y); + input_data[i+0] = (q7_t)__SSAT((((((int) COLOR_RGB565_TO_R8(p)) + - (int) data_layer->r_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+1] = (q7_t)__SSAT((((((int) COLOR_RGB565_TO_G8(p)) + - (int) data_layer->g_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+2] = (q7_t)__SSAT((((((int) COLOR_RGB565_TO_B8(p)) + - (int) data_layer->b_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } else if ((img->bpp == 2) && (data_layer->c == 1)) { // RGB565 to GS + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i++) { + int sx = (x*x_ratio)>>16; + uint16_t p = IM_GET_RGB565_PIXEL(img, sx+roi->x, sy+roi->y); + input_data[i] = (q7_t)__SSAT((((((int) COLOR_RGB565_TO_GRAYSCALE(p)) + - (int) data_layer->r_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } else if ((img->bpp == 1) && (data_layer->c == 3)) { // GS to RGB88 + int mean = (int) ((0.30f * data_layer->r_mean) + + (0.59f * data_layer->g_mean) + + (0.11f * data_layer->b_mean)); + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i+=3) { + int sx = (x*x_ratio)>>16; + int p = (int) IMAGE_GET_GRAYSCALE_PIXEL(img, sx+roi->x, sy+roi->y); + input_data[i+0] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+1] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+2] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } else if ((img->bpp == 1) && (data_layer->c == 1)) { // GS to GS + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i++) { + int sx = (x*x_ratio)>>16; + int p = (int) IMAGE_GET_GRAYSCALE_PIXEL(img, sx+roi->x, sy+roi->y); + input_data[i] = (q7_t)__SSAT((((p - (int) data_layer->r_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } else if ((img->bpp == 0) && (data_layer->c == 3)) { // BINARY to RGB88 + int mean = (int) ((0.30f * data_layer->r_mean) + + (0.59f * data_layer->g_mean) + + (0.11f * data_layer->b_mean)); + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i+=3) { + int sx = (x*x_ratio)>>16; + int p = (int) COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(img, sx+roi->x, sy+roi->y)); + input_data[i+0] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+1] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + input_data[i+2] = (q7_t)__SSAT((((p - (int) mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } else if ((img->bpp == 0) && (data_layer->c == 1)) { // BINARY to GS + for (int y=0, i=0; yh; y++) { + int sy = (y*y_ratio)>>16; + for (int x=0; xw; x++, i++) { + int sx = (x*x_ratio)>>16; + int p = (int) COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(img, sx+roi->x, sy+roi->y)); + input_data[i] = (q7_t)__SSAT((((p - (int) data_layer->r_mean)<<7) + (1<<(input_scale-1))) >> input_scale, 8); + } + } + } +} + +int nn_run_network(nn_t *net, image_t *img, rectangle_t *roi, bool softmax) +{ + uint32_t layer_idx = 0; + layer_t *layer = net->layers; + + if (layer == NULL) { + printf("First layer is NULL!\n"); + return -1; + } + + if (layer->type != LAYER_TYPE_DATA) { + printf("First layer is not a DATA layer!\n"); + return -1; + } + + q7_t *input_data = NULL; + q7_t *input_buffer = NULL; + q7_t *output_buffer = NULL; + + q7_t *buffer1 = fb_alloc(net->max_scrbuf_size); + q7_t *buffer2 = buffer1 + net->max_layer_size; + q7_t *col_buffer = fb_alloc(net->max_colbuf_size); + + while (layer != NULL) { + layer_t *prev_layer = layer->prev; + + switch (layer->type) { + case LAYER_TYPE_DATA: { + data_layer_t *data_layer = (data_layer_t *) layer; + input_data = fb_alloc(data_layer->c * data_layer->h * data_layer->w); + nn_transform_input(data_layer, img, input_data, roi); + // Set image data as input buffer for the next layer. + input_buffer = input_data; + output_buffer = buffer1; + break; + } + + case LAYER_TYPE_CONV: { + conv_func_t conv_func = NULL; + conv_layer_t *conv_layer = (conv_layer_t *) layer; + if (prev_layer->c % 4 != 0 || + conv_layer->n % 2 != 0 || prev_layer->h % 2 != 0) { + conv_func = arm_convolve_HWC_q7_basic; + if (prev_layer->c == 3) { + conv_func = arm_convolve_HWC_q7_RGB; + } + } else { + conv_func = arm_convolve_HWC_q7_fast; + } + conv_func(input_buffer, prev_layer->h, prev_layer->c, conv_layer->wt, conv_layer->c, + conv_layer->krn_dim, conv_layer->krn_pad, conv_layer->krn_str, conv_layer->bias, + conv_layer->l_shift, conv_layer->r_shift, output_buffer, conv_layer->h, (q15_t*)col_buffer, NULL); + break; + } + + case LAYER_TYPE_RELU: { + relu_layer_t *relu_layer = (relu_layer_t *) layer; + arm_relu_q7(input_buffer, relu_layer->h * relu_layer->w * relu_layer->c); + break; + } + + case LAYER_TYPE_POOL: { + pool_func_t pool_func = NULL; + pool_layer_t *pool_layer = (pool_layer_t *) layer; + if (pool_layer->ptype == POOL_TYPE_MAX) { + pool_func = arm_maxpool_q7_HWC; + } else { + pool_func = arm_avepool_q7_HWC; + } + pool_func(input_buffer, prev_layer->h, prev_layer->c, pool_layer->krn_dim, + pool_layer->krn_pad, pool_layer->krn_str, layer->w, col_buffer, output_buffer); + break; + } + + case LAYER_TYPE_IP: { + ip_layer_t *ip_layer = (ip_layer_t*) layer; + arm_fully_connected_q7_opt(input_buffer, ip_layer->wt, prev_layer->c * prev_layer->h * prev_layer->w, + ip_layer->c, ip_layer->l_shift, ip_layer->r_shift, ip_layer->bias, output_buffer, (q15_t*)col_buffer); + break; + } + } + + if (layer_idx++ > 0) { + if (input_buffer == input_data) { + // Image data has been processed + input_buffer = buffer2; + } + + if (layer->type != LAYER_TYPE_RELU) { + // Switch buffers + q7_t *tmp_buffer = input_buffer; + input_buffer = output_buffer; + output_buffer = tmp_buffer; + } + + // Last layer + if (layer->next && layer->next->next == NULL) { + output_buffer = net->output_data; + } + } + + layer = layer->next; + } + + // Softmax output + if (softmax) { + arm_softmax_q7(net->output_data, net->output_size, net->output_data); + } + + fb_free_all(); + return 0; +} + +#define BUFFER_2STR(buffer)\ + (buffer == buffer1) ? "buffer1":\ + (buffer == buffer2) ? "buffer2":\ + (buffer == input_data) ? "input_data":\ + (buffer == net->output_data) ? "output_data": "???" + +#define CONV_FUNC_2STR(conv_func)\ + (conv_func == arm_convolve_HWC_q7_basic) ? "arm_convolve_HWC_q7_basic" :\ + (conv_func == arm_convolve_HWC_q7_fast ) ? "arm_convolve_HWC_q7_fast":"arm_convolve_HWC_q7_RGB" + +#define POOL_FUNC_2STR(pool_func)\ + (pool_func == arm_maxpool_q7_HWC) ? "arm_maxpool_q7_HWC" : "arm_avepool_q7_HWC" + +int nn_dry_run_network(nn_t *net, image_t *img, bool softmax) +{ + uint32_t layer_idx = 0; + layer_t *layer = net->layers; + + if (layer == NULL) { + printf("First layer is NULL!\n"); + return -1; + } + + if (layer->type != LAYER_TYPE_DATA) { + printf("First layer is not a DATA layer!\n"); + return -1; + } + + q7_t *input_data = NULL; + q7_t *input_buffer = NULL; + q7_t *output_buffer = NULL; + + q7_t *buffer1 = fb_alloc(net->max_scrbuf_size); + q7_t *buffer2 = buffer1 + net->max_layer_size; + + while (layer != NULL) { + layer_t *prev_layer = layer->prev; + switch (layer->type) { + case LAYER_TYPE_DATA: { + data_layer_t *data_layer = (data_layer_t *) layer; + // Set image data as input buffer for the next layer. + input_buffer = input_data = fb_alloc(data_layer->c * data_layer->h * data_layer->w); + output_buffer = buffer1; + break; + } + + case LAYER_TYPE_CONV: { + conv_func_t conv_func = NULL; + conv_layer_t *conv_layer = (conv_layer_t *) layer; + if (prev_layer->c % 4 != 0 || + conv_layer->n % 2 != 0 || prev_layer->h % 2 != 0) { + conv_func = arm_convolve_HWC_q7_basic; + if (prev_layer->c == 3) { + conv_func = arm_convolve_HWC_q7_RGB; + } + } else { + conv_func = arm_convolve_HWC_q7_fast; + } + printf("forward: %s(%s, %lu, %lu, %s, %lu, %lu, %lu, %lu, %s, %lu, %lu, %s, %lu, %s, %p);\n", + CONV_FUNC_2STR(conv_func), BUFFER_2STR(input_buffer), + prev_layer->h, prev_layer->c, "conv_wt", conv_layer->c, + conv_layer->krn_dim, conv_layer->krn_pad, conv_layer->krn_str, + "conv_bias", conv_layer->l_shift, conv_layer->r_shift, + BUFFER_2STR(output_buffer), conv_layer->h, "col_buffer", NULL); + break; + } + + case LAYER_TYPE_RELU: { + relu_layer_t *relu_layer = (relu_layer_t *) layer; + printf("forward: arm_relu_q7(%s, %lu*%lu*%lu);\n", + BUFFER_2STR(input_buffer), relu_layer->h, relu_layer->w, relu_layer->c); + break; + } + + case LAYER_TYPE_POOL: { + pool_func_t pool_func = NULL; + pool_layer_t *pool_layer = (pool_layer_t *) layer; + if (pool_layer->ptype == POOL_TYPE_MAX) { + pool_func = arm_maxpool_q7_HWC; + } else { + pool_func = arm_avepool_q7_HWC; + } + printf("forward: %s(%s, %lu, %lu, %lu, %lu, %lu, %lu, %s, %s);\n", + POOL_FUNC_2STR(pool_func), BUFFER_2STR(input_buffer), + prev_layer->h, prev_layer->c, pool_layer->krn_dim, + pool_layer->krn_pad, pool_layer->krn_str, layer->w, "col_buffer", BUFFER_2STR(output_buffer)); + break; + } + + case LAYER_TYPE_IP: { + ip_layer_t *ip_layer = (ip_layer_t*) layer; + printf("forward: arm_fully_connected_q7_opt(%s, %s, %lu, %lu, %lu, %lu, %s, %s, %s);\n", + BUFFER_2STR(input_buffer), "ip_wt", prev_layer->c * prev_layer->h * prev_layer->w, + ip_layer->c, ip_layer->l_shift, ip_layer->r_shift, "ip_bias", BUFFER_2STR(output_buffer), "col_buffer"); + break; + } + } + + if (layer_idx++ > 0) { + if (input_buffer == input_data) { + // Image data has been processed + input_buffer = buffer2; + } + + if (layer->type != LAYER_TYPE_RELU) { + // Switch buffers + q7_t *tmp_buffer = input_buffer; + input_buffer = output_buffer; + output_buffer = tmp_buffer; + } + + // Last layer + if (layer->next && layer->next->next == NULL) { + output_buffer = net->output_data; + } + } + + layer = layer->next; + } + + fb_free_all(); + printf("\n"); + return 0; +} +#endif //IMLIB_ENABLE_CNN diff --git a/src/openmv/src/omv/nn/nn.h b/src/openmv/src/omv/nn/nn.h new file mode 100755 index 0000000..0ee1152 --- /dev/null +++ b/src/openmv/src/omv/nn/nn.h @@ -0,0 +1,105 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CNN code. + * + */ +#ifndef __NN_H__ +#define __NN_H__ +#include +#include +typedef enum { + LAYER_TYPE_DATA = 0, + LAYER_TYPE_CONV, + LAYER_TYPE_RELU, + LAYER_TYPE_POOL, + LAYER_TYPE_IP, +} layer_type_t; + +typedef enum { + POOL_TYPE_MAX, + POOL_TYPE_AVE, +} pool_type_t; + +typedef enum { + NETWORK_TYPE_CAFFE = 0, +} network_type_t; + +#define NN_LAYER_BASE \ + layer_type_t type; \ + uint32_t n, c, h, w;\ + struct _layer *prev;\ + struct _layer *next \ + +typedef struct _layer { + NN_LAYER_BASE; +} layer_t; + +typedef struct { + NN_LAYER_BASE; + uint32_t r_mean; + uint32_t g_mean; + uint32_t b_mean; + uint32_t scale; +} data_layer_t; + +typedef struct { + NN_LAYER_BASE; + uint32_t l_shift; + uint32_t r_shift; + uint32_t krn_dim; + uint32_t krn_str; + uint32_t krn_pad; + uint32_t w_size; + uint32_t b_size; + int8_t *wt, *bias; +} conv_layer_t; + +typedef struct { + NN_LAYER_BASE; +} relu_layer_t; + +typedef struct { + NN_LAYER_BASE; + pool_type_t ptype; + uint32_t krn_dim; + uint32_t krn_str; + uint32_t krn_pad; +} pool_layer_t; + +typedef struct { + NN_LAYER_BASE; + uint32_t l_shift; + uint32_t r_shift; + uint32_t w_size; + uint32_t b_size; + int8_t *wt, *bias; +} ip_layer_t; + +typedef struct { + uint8_t type[4]; + uint32_t n_layers; + int8_t *output_data; + uint32_t output_size; + uint32_t max_layer_size; + uint32_t max_colbuf_size; + uint32_t max_scrbuf_size; + layer_t *layers; +} nn_t; + +typedef arm_status (*conv_func_t) (const q7_t * Im_in, const uint16_t dim_im_in, const uint16_t ch_im_in, + const q7_t * wt, const uint16_t ch_im_out, const uint16_t dim_kernel, const uint16_t padding, + const uint16_t stride, const q7_t * bias, const uint16_t bias_shift, const uint16_t out_shift, + q7_t * Im_out, const uint16_t dim_im_out, q15_t * bufferA, q7_t * bufferB); + +typedef void (*pool_func_t)(q7_t * Im_in, const uint16_t dim_im_in, const uint16_t ch_im_in, + const uint16_t dim_kernel, const uint16_t padding, const uint16_t stride, + const uint16_t dim_im_out, q7_t * bufferA, q7_t * Im_out); + + +int nn_dump_network(nn_t *net); +int nn_load_network(nn_t *net, const char *path); +int nn_run_network(nn_t *net, image_t *img, rectangle_t *roi, bool softmax); +int nn_dry_run_network(nn_t *net, image_t *img, bool softmax); +#endif //#define __CNN_H__ diff --git a/src/openmv/src/omv/ov2640.c b/src/openmv/src/omv/ov2640.c new file mode 100755 index 0000000..4b68552 --- /dev/null +++ b/src/openmv/src/omv/ov2640.c @@ -0,0 +1,859 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV2640 driver. + * + */ +#include +#include +#include +#include STM32_HAL_H +#include "cambus.h" +#include "ov2640.h" +#include "systick.h" +#include "ov2640_regs.h" +#include "omv_boardconfig.h" + +#define SVGA_HSIZE (800) +#define SVGA_VSIZE (600) + +#define UXGA_HSIZE (1600) +#define UXGA_VSIZE (1200) + +static const uint8_t default_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { 0x2c, 0xff }, + { 0x2e, 0xdf }, + { BANK_SEL, BANK_SEL_SENSOR }, + { 0x3c, 0x32 }, + { CLKRC, 0x80 }, /* Set PCLK divider */ + { COM2, COM2_OUT_DRIVE_3x }, /* Output drive x2 */ +#ifdef OPENMV2 + { REG04, 0xF8}, /* Mirror/VFLIP/AEC[1:0] */ +#else + { REG04_SET(REG04_HREF_EN)}, +#endif + { COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) }, + { COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, + { 0x2c, 0x0c }, + { 0x33, 0x78 }, + { 0x3a, 0x33 }, + { 0x3b, 0xfb }, + { 0x3e, 0x00 }, + { 0x43, 0x11 }, + { 0x16, 0x10 }, + { 0x39, 0x02 }, + { 0x35, 0x88 }, + { 0x22, 0x0a }, + { 0x37, 0x40 }, + { 0x23, 0x00 }, + { ARCOM2, 0xa0 }, + { 0x06, 0x02 }, + { 0x06, 0x88 }, + { 0x07, 0xc0 }, + { 0x0d, 0xb7 }, + { 0x0e, 0x01 }, + { 0x4c, 0x00 }, + { 0x4a, 0x81 }, + { 0x21, 0x99 }, + { AEW, 0x40 }, + { AEB, 0x38 }, + /* AGC/AEC fast mode operating region */ + { VV, VV_AGC_TH_SET(0x08, 0x02) }, + { COM19, 0x00 }, /* Zoom control 2 MSBs */ + { ZOOMS, 0x00 }, /* Zoom control 8 MSBs */ + { 0x5c, 0x00 }, + { 0x63, 0x00 }, + { FLL, 0x00 }, + { FLH, 0x00 }, + + /* Set banding filter */ + { COM3, COM3_BAND_SET(COM3_BAND_AUTO) }, + { REG5D, 0x55 }, + { REG5E, 0x7d }, + { REG5F, 0x7d }, + { REG60, 0x55 }, + { HISTO_LOW, 0x70 }, + { HISTO_HIGH, 0x80 }, + { 0x7c, 0x05 }, + { 0x20, 0x80 }, + { 0x28, 0x30 }, + { 0x6c, 0x00 }, + { 0x6d, 0x80 }, + { 0x6e, 0x00 }, + { 0x70, 0x02 }, + { 0x71, 0x94 }, + { 0x73, 0xc1 }, + { 0x3d, 0x34 }, + //{ COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, + { 0x5a, 0x57 }, + { BD50, 0xbb }, + { BD60, 0x9c }, + + { BANK_SEL, BANK_SEL_DSP }, + { 0xe5, 0x7f }, + { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, + { 0x41, 0x24 }, + { RESET, RESET_JPEG | RESET_DVP }, + { 0x76, 0xff }, + { 0x33, 0xa0 }, + { 0x42, 0x20 }, + { 0x43, 0x18 }, + { 0x4c, 0x00 }, + { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, + { 0x88, 0x3f }, + { 0xd7, 0x03 }, + { 0xd9, 0x10 }, + { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, + { 0xc8, 0x08 }, + { 0xc9, 0x80 }, + { BPADDR, 0x00 }, + { BPDATA, 0x00 }, + { BPADDR, 0x03 }, + { BPDATA, 0x48 }, + { BPDATA, 0x48 }, + { BPADDR, 0x08 }, + { BPDATA, 0x20 }, + { BPDATA, 0x10 }, + { BPDATA, 0x0e }, + { 0x90, 0x00 }, + { 0x91, 0x0e }, + { 0x91, 0x1a }, + { 0x91, 0x31 }, + { 0x91, 0x5a }, + { 0x91, 0x69 }, + { 0x91, 0x75 }, + { 0x91, 0x7e }, + { 0x91, 0x88 }, + { 0x91, 0x8f }, + { 0x91, 0x96 }, + { 0x91, 0xa3 }, + { 0x91, 0xaf }, + { 0x91, 0xc4 }, + { 0x91, 0xd7 }, + { 0x91, 0xe8 }, + { 0x91, 0x20 }, + { 0x92, 0x00 }, + { 0x93, 0x06 }, + { 0x93, 0xe3 }, + { 0x93, 0x03 }, + { 0x93, 0x03 }, + { 0x93, 0x00 }, + { 0x93, 0x02 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x93, 0x00 }, + { 0x96, 0x00 }, + { 0x97, 0x08 }, + { 0x97, 0x19 }, + { 0x97, 0x02 }, + { 0x97, 0x0c }, + { 0x97, 0x24 }, + { 0x97, 0x30 }, + { 0x97, 0x28 }, + { 0x97, 0x26 }, + { 0x97, 0x02 }, + { 0x97, 0x98 }, + { 0x97, 0x80 }, + { 0x97, 0x00 }, + { 0x97, 0x00 }, + { 0xa4, 0x00 }, + { 0xa8, 0x00 }, + { 0xc5, 0x11 }, + { 0xc6, 0x51 }, + { 0xbf, 0x80 }, + { 0xc7, 0x10 }, + { 0xb6, 0x66 }, + { 0xb8, 0xA5 }, + { 0xb7, 0x64 }, + { 0xb9, 0x7C }, + { 0xb3, 0xaf }, + { 0xb4, 0x97 }, + { 0xb5, 0xFF }, + { 0xb0, 0xC5 }, + { 0xb1, 0x94 }, + { 0xb2, 0x0f }, + { 0xc4, 0x5c }, + { 0xa6, 0x00 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x1b }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x19 }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0xa7, 0x20 }, + { 0xa7, 0xd8 }, + { 0xa7, 0x19 }, + { 0xa7, 0x31 }, + { 0xa7, 0x00 }, + { 0xa7, 0x18 }, + { 0x7f, 0x00 }, + { 0xe5, 0x1f }, + { 0xe1, 0x77 }, + { 0xdd, 0x7f }, + { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, + { 0x00, 0x00 } +}; + +static const uint8_t svga_regs[][2] = { + { BANK_SEL, BANK_SEL_SENSOR }, + /* DSP input image resoultion and window size control */ + { COM7, COM7_RES_SVGA}, + { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ + { REG32, 0x09 }, /* UXGA=0x36, SVGA/CIF=0x09 */ + + { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ + { HSTOP, 0x43 }, /* UXGA=0x75, SVGA/CIF=0x43 */ + + { VSTART, 0x00 }, /* UXGA=0x01, SVGA/CIF=0x00 */ + { VSTOP, 0x4b }, /* UXGA=0x97, SVGA/CIF=0x4b */ + { 0x3d, 0x38 }, /* UXGA=0x34, SVGA/CIF=0x38 */ + + { 0x35, 0xda }, + { 0x22, 0x1a }, + { 0x37, 0xc3 }, + { 0x34, 0xc0 }, + { 0x06, 0x88 }, + { 0x0d, 0x87 }, + { 0x0e, 0x41 }, + { 0x42, 0x03 }, + + /* Set DSP input image size and offset. + The sensor output image can be scaled with OUTW/OUTH */ + { BANK_SEL, BANK_SEL_DSP }, + { R_BYPASS, R_BYPASS_DSP_BYPAS }, + + { RESET, RESET_DVP }, + { HSIZE8, (SVGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ + { VSIZE8, (SVGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ + + /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ + { SIZEL, ((SVGA_HSIZE>>6)&0x40) | ((SVGA_HSIZE&0x7)<<3) | (SVGA_VSIZE&0x7)}, + + { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ + { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ + { HSIZE, ((SVGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0]= HSIZE/4 */ + { VSIZE, ((SVGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0]= VSIZE/4 */ + + /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ + { VHYX, ((SVGA_VSIZE>>3)&0x80) | ((SVGA_HSIZE>>7)&0x08) }, + { TEST, (SVGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ + + { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | + CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, + + /* H_DIVIDER/V_DIVIDER */ + { CTRLI, CTRLI_LP_DP | 0x00}, + /* DVP prescalar */ + { R_DVP_SP, R_DVP_SP_AUTO_MODE}, + + { R_BYPASS, R_BYPASS_DSP_EN }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t uxga_regs[][2] = { + { BANK_SEL, BANK_SEL_SENSOR }, + /* DSP input image resoultion and window size control */ + { COM7, COM7_RES_UXGA}, + { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ + { REG32, 0x36 }, /* UXGA=0x36, SVGA/CIF=0x09 */ + + { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ + { HSTOP, 0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */ + + { VSTART, 0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */ + { VSTOP, 0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */ + { 0x3d, 0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */ + + { 0x35, 0x88 }, + { 0x22, 0x0a }, + { 0x37, 0x40 }, + { 0x34, 0xa0 }, + { 0x06, 0x02 }, + { 0x0d, 0xb7 }, + { 0x0e, 0x01 }, + { 0x42, 0x83 }, + + /* Set DSP input image size and offset. + The sensor output image can be scaled with OUTW/OUTH */ + { BANK_SEL, BANK_SEL_DSP }, + { R_BYPASS, R_BYPASS_DSP_BYPAS }, + + { RESET, RESET_DVP }, + { HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ + { VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ + + /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ + { SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)}, + + { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ + { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ + { HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */ + { VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */ + + /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ + { VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) }, + { TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ + + { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | + CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, + + /* H_DIVIDER/V_DIVIDER */ + { CTRLI, CTRLI_LP_DP | 0x00}, + /* DVP prescalar */ + { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04}, + + { R_BYPASS, R_BYPASS_DSP_EN }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t yuv422_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { RESET, RESET_DVP}, + { IMAGE_MODE, IMAGE_MODE_YUV422 }, + { 0xD7, 0x01 }, + { 0xE1, 0x67 }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t rgb565_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { RESET, RESET_DVP}, + { IMAGE_MODE, IMAGE_MODE_RGB565 }, + { 0xD7, 0x03 }, + { 0xE1, 0x77 }, + { RESET, 0x00 }, + {0, 0}, +}; + +static const uint8_t jpeg_regs[][2] = { + { BANK_SEL, BANK_SEL_DSP }, + { RESET, RESET_DVP}, + { IMAGE_MODE, IMAGE_MODE_JPEG_EN|IMAGE_MODE_RGB565 }, + { 0xD7, 0x03 }, + { 0xE1, 0x77 }, + { QS, 0x0C }, + { RESET, 0x00 }, + {0, 0}, +}; + +#define NUM_BRIGHTNESS_LEVELS (5) +static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { + { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, + { 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ + { 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ + { 0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ + { 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ + { 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ +}; + +#define NUM_CONTRAST_LEVELS (5) +static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { + { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA }, + { 0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ + { 0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ + { 0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ + { 0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ + { 0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ +}; + +#define NUM_SATURATION_LEVELS (5) +static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { + { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, + { 0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */ + { 0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */ + { 0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */ + { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */ + { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +2 */ +}; + +static int reset(sensor_t *sensor) +{ + int i=0; + const uint8_t (*regs)[2]; + + /* Reset all registers */ + cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); + cambus_writeb(sensor->slv_addr, COM7, COM7_SRST); + + /* delay n ms */ + systick_sleep(10); + + i = 0; + regs = default_regs; + /* Write initial regsiters */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + i = 0; + regs = svga_regs; + /* Write DSP input regsiters */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + return 0; +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + int i=0; + const uint8_t (*regs)[2]=NULL; + + /* read pixel format reg */ + switch (pixformat) { + case PIXFORMAT_RGB565: + regs = rgb565_regs; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_GRAYSCALE: + regs = yuv422_regs; + break; + case PIXFORMAT_JPEG: + regs = jpeg_regs; + break; + default: + return -1; + } + + /* Write initial regsiters */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + /* delay n ms */ + systick_sleep(30); + + return 0; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + int ret=0; + uint8_t clkrc; + uint16_t w = resolution[framesize][0]; + uint16_t h = resolution[framesize][1]; + + int i=0; + const uint8_t (*regs)[2]; + + if ((w <= 800) && (h <= 600)) { + clkrc =0x80; + regs = svga_regs; + } else { + clkrc =0x81; + regs = uxga_regs; + } + + /* Disable DSP */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + ret |= cambus_writeb(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_BYPAS); + + /* Write output width */ + ret |= cambus_writeb(sensor->slv_addr, ZMOW, (w>>2)&0xFF); /* OUTW[7:0] (real/4) */ + ret |= cambus_writeb(sensor->slv_addr, ZMOH, (h>>2)&0xFF); /* OUTH[7:0] (real/4) */ + ret |= cambus_writeb(sensor->slv_addr, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); /* OUTH[8]/OUTW[9:8] */ + + /* Set CLKRC */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); + ret |= cambus_writeb(sensor->slv_addr, CLKRC, clkrc); + + /* Write DSP input regsiters */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + /* Enable DSP */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + ret |= cambus_writeb(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_EN); + + /* delay n ms */ + systick_sleep(30); + + return ret; +} + +static int set_framerate(sensor_t *sensor, framerate_t framerate) +{ + return 0; +} + +static int set_contrast(sensor_t *sensor, int level) +{ + int ret=0; + + level += (NUM_CONTRAST_LEVELS / 2 + 1); + if (level < 0 || level > NUM_CONTRAST_LEVELS) { + return -1; + } + + /* Switch to DSP register bank */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + + /* Write contrast registers */ + for (int i=0; islv_addr, contrast_regs[0][i], contrast_regs[level][i]); + } + + return ret; +} + +static int set_brightness(sensor_t *sensor, int level) +{ + int ret=0; + + level += (NUM_BRIGHTNESS_LEVELS / 2 + 1); + if (level < 0 || level > NUM_BRIGHTNESS_LEVELS) { + return -1; + } + + /* Switch to DSP register bank */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + + /* Write brightness registers */ + for (int i=0; islv_addr, brightness_regs[0][i], brightness_regs[level][i]); + } + + return ret; +} + +static int set_saturation(sensor_t *sensor, int level) +{ + int ret=0; + + level += (NUM_SATURATION_LEVELS / 2 + 1); + if (level < 0 || level > NUM_SATURATION_LEVELS) { + return -1; + } + + /* Switch to DSP register bank */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + + /* Write contrast registers */ + for (int i=0; islv_addr, saturation_regs[0][i], saturation_regs[level][i]); + } + + return ret; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + int ret =0; + + /* Switch to SENSOR register bank */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); + + /* Write gain ceiling register */ + ret |= cambus_writeb(sensor->slv_addr, COM9, COM9_AGC_SET(gainceiling)); + + return ret; +} + +static int set_quality(sensor_t *sensor, int qs) +{ + int ret=0; + + /* Switch to DSP register bank */ + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); + + /* Write QS register */ + ret |= cambus_writeb(sensor->slv_addr, QS, qs); + + return ret; +} + +static int set_colorbar(sensor_t *sensor, int enable) +{ + uint8_t reg; + /* Switch to SENSOR register bank */ + int ret = cambus_writeb(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); + + /* Update COM7 */ + ret |= cambus_readb(sensor->slv_addr, COM7, ®); + + if (enable) { + reg |= COM7_COLOR_BAR; + } else { + reg &= ~COM7_COLOR_BAR; + } + + return cambus_writeb(sensor->slv_addr, COM7, reg) | ret; +} + +static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, COM8, (reg & (~COM8_AGC_EN)) | ((enable != 0) ? COM8_AGC_EN : 0)); + + if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) { + float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 32.0), 1.0); + + int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0))); + int gain_hi = 0xF >> (4 - gain_temp); + int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15); + + ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0)); + } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) { + float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 2.0); + + ret |= cambus_readb(sensor->slv_addr, COM9, ®); + ret |= cambus_writeb(sensor->slv_addr, COM9, (reg & 0x1F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 5)); + } + + return ret; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + uint8_t reg, gain; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, COM8, ®); + + // DISABLED + // if (reg & COM8_AGC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, reg & (~COM8_AGC_EN)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, GAIN, &gain); + + // DISABLED + // if (reg & COM8_AGC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, reg | COM8_AGC_EN); + // } + // DISABLED + + int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1)); + float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0); + *gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0)); + + return ret; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, (enable != 0))); + + if ((enable == 0) && (exposure_us >= 0)) { + ret |= cambus_readb(sensor->slv_addr, COM7, ®); + int t_line = 0; + + if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322; + if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390; + if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195; + + ret |= cambus_readb(sensor->slv_addr, CLKRC, ®); + int pll_mult = (reg & CLKRC_DOUBLE) ? 2 : 1; + int clk_rc = ((reg & CLKRC_DIVIDER_MASK) + 1) * 2; + + ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR)); + ret |= cambus_readb(sensor->slv_addr, IMAGE_MODE, ®); + int t_pclk = 0; + + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2; + + int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000); + + ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + + ret |= cambus_readb(sensor->slv_addr, REG04, ®); + ret |= cambus_writeb(sensor->slv_addr, REG04, (reg & 0xFC) | ((exposure >> 0) & 0x3)); + + ret |= cambus_readb(sensor->slv_addr, AEC, ®); + ret |= cambus_writeb(sensor->slv_addr, AEC, (reg & 0x00) | ((exposure >> 2) & 0xFF)); + + ret |= cambus_readb(sensor->slv_addr, REG04, ®); + ret |= cambus_writeb(sensor->slv_addr, REG04, (reg & 0xC0) | ((exposure >> 10) & 0x3F)); + } + + return ret; +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) +{ + uint8_t reg, aec_10, aec_92, aec_1510; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, COM8, ®); + + // DISABLED + // if (reg & COM8_AEC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, reg & (~COM8_AEC_EN)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, REG04, &aec_10); + ret |= cambus_readb(sensor->slv_addr, AEC, &aec_92); + ret |= cambus_readb(sensor->slv_addr, REG45, &aec_1510); + + // DISABLED + // if (reg & COM8_AEC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, reg | COM8_AEC_EN); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, COM7, ®); + int t_line = 0; + + if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322; + if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390; + if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195; + + ret |= cambus_readb(sensor->slv_addr, CLKRC, ®); + int pll_mult = (reg & CLKRC_DOUBLE) ? 2 : 1; + int clk_rc = ((reg & CLKRC_DIVIDER_MASK) + 1) * 2; + + ret |= cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR)); + ret |= cambus_readb(sensor->slv_addr, IMAGE_MODE, ®); + int t_pclk = 0; + + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2; + + uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0); + *exposure_us = (exposure*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000); + + return ret; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR)); + ret |= cambus_readb(sensor->slv_addr, CTRL1, ®); + ret |= cambus_writeb(sensor->slv_addr, CTRL1, (reg & (~CTRL1_AWB)) | ((enable != 0) ? CTRL1_AWB : 0)); + + if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db)) + && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) { + } + + return ret; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg & (~BANK_SEL_SENSOR)); + ret |= cambus_readb(sensor->slv_addr, CTRL1, ®); + + // DISABLED + // if (reg & CTRL1_AWB) { + // ret |= cambus_writeb(sensor->slv_addr, CTRL1, reg & (~CTRL1_AWB)); + // } + // DISABLED + + // DISABLED + // if (reg & CTRL1_AWB) { + // ret |= cambus_writeb(sensor->slv_addr, CTRL1, reg | CTRL1_AWB); + // } + // DISABLED + + return ret; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, REG04, ®); + + if (enable) { + reg |= REG04_HFLIP_IMG; + } else { + reg &= ~REG04_HFLIP_IMG; + } + + ret |= cambus_writeb(sensor->slv_addr, REG04, reg); + + return ret; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, BANK_SEL, ®); + ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); + ret |= cambus_readb(sensor->slv_addr, REG04, ®); + + if (enable) { + reg |= REG04_VFLIP_IMG; + } else { + reg &= ~REG04_VFLIP_IMG; + } + + ret |= cambus_writeb(sensor->slv_addr, REG04, reg); + + return ret; +} + +int ov2640_init(sensor_t *sensor) +{ + // Initialize sensor structure. + sensor->gs_bpp = 2; + sensor->reset = reset; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_contrast = set_contrast; + sensor->set_brightness = set_brightness; + sensor->set_saturation = set_saturation; + sensor->set_gainceiling = set_gainceiling; + sensor->set_quality = set_quality; + sensor->set_colorbar = set_colorbar; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + + // Set sensor flags + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 1); + + return 0; +} diff --git a/src/openmv/src/omv/ov2640.h b/src/openmv/src/omv/ov2640.h new file mode 100755 index 0000000..a890499 --- /dev/null +++ b/src/openmv/src/omv/ov2640.h @@ -0,0 +1,13 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV2640 driver. + * + */ +#ifndef __OV2640_H__ +#define __OV2640_H__ +#include "sensor.h" +int ov2640_init(sensor_t *sensor); +#endif // __OV2640_H__ diff --git a/src/openmv/src/omv/ov2640_regs.h b/src/openmv/src/omv/ov2640_regs.h new file mode 100755 index 0000000..7112e59 --- /dev/null +++ b/src/openmv/src/omv/ov2640_regs.h @@ -0,0 +1,211 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV2640 register definitions. + */ + +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ + +/* DSP register bank FF=0x00*/ + +#define QS 0x44 +#define HSIZE 0x51 +#define VSIZE 0x52 +#define XOFFL 0x53 +#define YOFFL 0x54 +#define VHYX 0x55 +#define DPRP 0x56 +#define TEST 0x57 +#define ZMOW 0x5A +#define ZMOH 0x5B +#define ZMHH 0x5C +#define BPADDR 0x7C +#define BPDATA 0x7D +#define SIZEL 0x8C +#define HSIZE8 0xC0 +#define VSIZE8 0xC1 +#define CTRL1 0xC3 +#define MS_SP 0xF0 +#define SS_ID 0xF7 +#define SS_CTRL 0xF7 +#define MC_AL 0xFA +#define MC_AH 0xFB +#define MC_D 0xFC +#define P_CMD 0xFD +#define P_STATUS 0xFE + +#define CTRLI 0x50 +#define CTRLI_LP_DP 0x80 +#define CTRLI_ROUND 0x40 + +#define CTRL0 0xC2 +#define CTRL0_AEC_EN 0x80 +#define CTRL0_AEC_SEL 0x40 +#define CTRL0_STAT_SEL 0x20 +#define CTRL0_VFIRST 0x10 +#define CTRL0_YUV422 0x08 +#define CTRL0_YUV_EN 0x04 +#define CTRL0_RGB_EN 0x02 +#define CTRL0_RAW_EN 0x01 + +#define CTRL2 0x86 +#define CTRL2_DCW_EN 0x20 +#define CTRL2_SDE_EN 0x10 +#define CTRL2_UV_ADJ_EN 0x08 +#define CTRL2_UV_AVG_EN 0x04 +#define CTRL2_CMX_EN 0x01 + +#define CTRL3 0x87 +#define CTRL3_BPC_EN 0x80 +#define CTRL3_WPC_EN 0x40 +#define R_DVP_SP 0xD3 +#define R_DVP_SP_AUTO_MODE 0x80 + +#define R_BYPASS 0x05 +#define R_BYPASS_DSP_EN 0x00 +#define R_BYPASS_DSP_BYPAS 0x01 + +#define IMAGE_MODE 0xDA +#define IMAGE_MODE_Y8_DVP_EN 0x40 +#define IMAGE_MODE_JPEG_EN 0x10 +#define IMAGE_MODE_YUV422 0x00 +#define IMAGE_MODE_RAW10 0x04 +#define IMAGE_MODE_RGB565 0x08 +#define IMAGE_MODE_HREF_VSYNC 0x02 +#define IMAGE_MODE_LBYTE_FIRST 0x01 +#define IMAGE_MODE_GET_FMT(x) ((x)&0xC) + +#define RESET 0xE0 +#define RESET_MICROC 0x40 +#define RESET_SCCB 0x20 +#define RESET_JPEG 0x10 +#define RESET_DVP 0x04 +#define RESET_IPU 0x02 +#define RESET_CIF 0x01 + +#define MC_BIST 0xF9 +#define MC_BIST_RESET 0x80 +#define MC_BIST_BOOT_ROM_SEL 0x40 +#define MC_BIST_12KB_SEL 0x20 +#define MC_BIST_12KB_MASK 0x30 +#define MC_BIST_512KB_SEL 0x08 +#define MC_BIST_512KB_MASK 0x0C +#define MC_BIST_BUSY_BIT_R 0x02 +#define MC_BIST_MC_RES_ONE_SH_W 0x02 +#define MC_BIST_LAUNCH 0x01 + +#define BANK_SEL 0xFF +#define BANK_SEL_DSP 0x00 +#define BANK_SEL_SENSOR 0x01 + +/* Sensor register bank FF=0x01*/ + +#define GAIN 0x00 +#define COM1 0x03 +#define REG_PID 0x0A +#define REG_VER 0x0B +#define COM4 0x0D +#define AEC 0x10 + +#define CLKRC 0x11 +#define CLKRC_DOUBLE 0x80 +#define CLKRC_DIVIDER_MASK 0x3F + +#define COM10 0x15 +#define HSTART 0x17 +#define HSTOP 0x18 +#define VSTART 0x19 +#define VSTOP 0x1A +#define MIDH 0x1C +#define MIDL 0x1D +#define AEW 0x24 +#define AEB 0x25 +#define REG2A 0x2A +#define FRARL 0x2B +#define ADDVSL 0x2D +#define ADDVSH 0x2E +#define YAVG 0x2F +#define HSDY 0x30 +#define HEDY 0x31 +#define ARCOM2 0x34 +#define REG45 0x45 +#define FLL 0x46 +#define FLH 0x47 +#define COM19 0x48 +#define ZOOMS 0x49 +#define COM22 0x4B +#define COM25 0x4E +#define BD50 0x4F +#define BD60 0x50 +#define REG5D 0x5D +#define REG5E 0x5E +#define REG5F 0x5F +#define REG60 0x60 +#define HISTO_LOW 0x61 +#define HISTO_HIGH 0x62 + +#define REG04 0x04 +#define REG04_DEFAULT 0x28 +#define REG04_HFLIP_IMG 0x80 +#define REG04_VFLIP_IMG 0x40 +#define REG04_VREF_EN 0x10 +#define REG04_HREF_EN 0x08 +#define REG04_SET(x) (REG04_DEFAULT|x) + +#define REG08 0x08 +#define COM2 0x09 +#define COM2_STDBY 0x10 +#define COM2_OUT_DRIVE_1x 0x00 +#define COM2_OUT_DRIVE_2x 0x01 +#define COM2_OUT_DRIVE_3x 0x02 +#define COM2_OUT_DRIVE_4x 0x03 + +#define COM3 0x0C +#define COM3_DEFAULT 0x38 +#define COM3_BAND_50Hz 0x04 +#define COM3_BAND_60Hz 0x00 +#define COM3_BAND_AUTO 0x02 +#define COM3_BAND_SET(x) (COM3_DEFAULT|x) + +#define COM7 0x12 +#define COM7_SRST 0x80 +#define COM7_RES_UXGA 0x00 /* UXGA */ +#define COM7_RES_SVGA 0x40 /* SVGA */ +#define COM7_RES_CIF 0x20 /* CIF */ +#define COM7_ZOOM_EN 0x04 /* Enable Zoom */ +#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ +#define COM7_GET_RES(x) ((x)&0x70) + +#define COM8 0x13 +#define COM8_DEFAULT 0xC0 +#define COM8_BNDF_EN 0x20 /* Enable Banding filter */ +#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ +#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ +#define COM8_SET(x) (COM8_DEFAULT|x) +#define COM8_SET_AEC(r,x) (((r)&0xFE)|((x)&1)) + +#define COM9 0x14 /* AGC gain ceiling */ +#define COM9_DEFAULT 0x08 +#define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ +#define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ +#define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ +#define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ +#define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ +#define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ +#define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ +#define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) + +#define CTRL1_AWB 0x08 /* Enable AWB */ + +#define VV 0x26 +#define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) + +#define REG32 0x32 +#define REG32_UXGA 0x36 +#define REG32_SVGA 0x09 +#define REG32_CIF 0x00 + +#endif //__REG_REGS_H__ diff --git a/src/openmv/src/omv/ov7725.c b/src/openmv/src/omv/ov7725.c new file mode 100755 index 0000000..5da43a8 --- /dev/null +++ b/src/openmv/src/omv/ov7725.c @@ -0,0 +1,627 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV7725 driver. + * + */ +#include +#include +#include +#include STM32_HAL_H +#include "cambus.h" +#include "ov7725.h" +#include "ov7725_regs.h" +#include "systick.h" +#include "omv_boardconfig.h" + +static const uint8_t default_regs[][2] = { + {COM3, COM3_SWAP_YUV}, + {COM7, COM7_RES_VGA | COM7_FMT_RGB565 | COM7_FMT_RGB}, + + {COM4, OMV_OV7725_PLL_CONFIG}, + {CLKRC, 0xC0}, /* Res/Bypass pre-scalar */ + + // VGA Window Size + {HSTART, 0x23}, + {HSIZE, 0xA0}, + {VSTART, 0x07}, + {VSIZE, 0xF0}, + {HREF, 0x00}, + + // Scale down to QVGA Resoultion + {HOUTSIZE, 0x50}, + {VOUTSIZE, 0x78}, + + {COM12, 0x03}, + {EXHCH, 0x00}, + {TGT_B, 0x7F}, + {FIXGAIN, 0x09}, + {AWB_CTRL0, 0xE0}, + {DSP_CTRL1, 0xFF}, + + {DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN}, + + {DSP_CTRL3, 0x00}, + {DSP_CTRL4, 0x00}, + {DSPAUTO, 0xFF}, + + {COM8, 0xF0}, + {COM6, 0xC5}, + {COM9, 0x21}, + {BDBASE, 0x7F}, + {BDSTEP, 0x03}, + {AEW, 0x96}, + {AEB, 0x64}, + {VPT, 0xA1}, + {EXHCL, 0x00}, + {AWB_CTRL3, 0xAA}, + {COM8, 0xFF}, + + //Gamma + {GAM1, 0x0C}, + {GAM2, 0x16}, + {GAM3, 0x2A}, + {GAM4, 0x4E}, + {GAM5, 0x61}, + {GAM6, 0x6F}, + {GAM7, 0x7B}, + {GAM8, 0x86}, + {GAM9, 0x8E}, + {GAM10, 0x97}, + {GAM11, 0xA4}, + {GAM12, 0xAF}, + {GAM13, 0xC5}, + {GAM14, 0xD7}, + {GAM15, 0xE8}, + + {SLOP, 0x20}, + {EDGE1, 0x05}, + {EDGE2, 0x03}, + {EDGE3, 0x00}, + {DNSOFF, 0x01}, + + {MTX1, 0xB0}, + {MTX2, 0x9D}, + {MTX3, 0x13}, + {MTX4, 0x16}, + {MTX5, 0x7B}, + {MTX6, 0x91}, + {MTX_CTRL, 0x1E}, + + {BRIGHTNESS, 0x08}, + {CONTRAST, 0x20}, + {UVADJ0, 0x81}, + {SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)}, + + // For 30 fps/60Hz + {DM_LNL, 0x00}, + {DM_LNH, 0x00}, + {BDBASE, 0x7F}, + {BDSTEP, 0x03}, + + // Lens Correction, should be tuned with real camera module + {LC_CTR, 0x01}, // Enable LC and use 1 coefficient for all 3 channels + {LC_RADI, 0x30}, // The radius of the circle where no compensation applies + {LC_COEF, 0x30}, // RGB Lens correction coefficient + + // Frame reduction in night mode. + {COM5, 0xD5}, + + {0x00, 0x00}, +}; + +#define NUM_BRIGHTNESS_LEVELS (9) +static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS][2] = { + {0x38, 0x0e}, /* -4 */ + {0x28, 0x0e}, /* -3 */ + {0x18, 0x0e}, /* -2 */ + {0x08, 0x0e}, /* -1 */ + {0x08, 0x06}, /* 0 */ + {0x18, 0x06}, /* +1 */ + {0x28, 0x06}, /* +2 */ + {0x38, 0x06}, /* +3 */ + {0x48, 0x06}, /* +4 */ +}; + +#define NUM_CONTRAST_LEVELS (9) +static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS][1] = { + {0x10}, /* -4 */ + {0x14}, /* -3 */ + {0x18}, /* -2 */ + {0x1C}, /* -1 */ + {0x20}, /* 0 */ + {0x24}, /* +1 */ + {0x28}, /* +2 */ + {0x2C}, /* +3 */ + {0x30}, /* +4 */ +}; + +#define NUM_SATURATION_LEVELS (9) +static const uint8_t saturation_regs[NUM_SATURATION_LEVELS][2] = { + {0x00, 0x00}, /* -4 */ + {0x10, 0x10}, /* -3 */ + {0x20, 0x20}, /* -2 */ + {0x30, 0x30}, /* -1 */ + {0x40, 0x40}, /* 0 */ + {0x50, 0x50}, /* +1 */ + {0x60, 0x60}, /* +2 */ + {0x70, 0x70}, /* +3 */ + {0x80, 0x80}, /* +4 */ +}; + +static int reset(sensor_t *sensor) +{ + int i=0; + const uint8_t (*regs)[2]; + + // Reset all registers + cambus_writeb(sensor->slv_addr, COM7, COM7_RESET); + + // Delay 10 ms + systick_sleep(10); + + // Write default regsiters + for (i=0, regs = default_regs; regs[i][0]; i++) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + } + + // Delay + systick_sleep(30); + + return 0; +} + +static int sleep(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM2, ®); + + if (enable) { + reg |= COM2_SOFT_SLEEP; + } else { + reg &= ~COM2_SOFT_SLEEP; + } + + // Write back register + return cambus_writeb(sensor->slv_addr, COM2, reg) | ret; +} + +static int read_reg(sensor_t *sensor, uint8_t reg_addr) +{ + uint8_t reg_data; + if (cambus_readb(sensor->slv_addr, reg_addr, ®_data) != 0) { + return -1; + } + return reg_data; +} + +static int write_reg(sensor_t *sensor, uint8_t reg_addr, uint16_t reg_data) +{ + return cambus_writeb(sensor->slv_addr, reg_addr, reg_data); +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM7, ®); + + switch (pixformat) { + case PIXFORMAT_RGB565: + reg = COM7_SET_FMT(reg, COM7_FMT_RGB); + ret = cambus_writeb(sensor->slv_addr, DSP_CTRL4, 0); + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_GRAYSCALE: + reg = COM7_SET_FMT(reg, COM7_FMT_YUV); + ret = cambus_writeb(sensor->slv_addr, DSP_CTRL4, 0); + break; + case PIXFORMAT_BAYER: + reg = COM7_SET_FMT(reg, COM7_FMT_P_BAYER); + ret = cambus_writeb(sensor->slv_addr, DSP_CTRL4, DSP_CTRL4_RAW8); + break; + + default: + return -1; + } + + // Write back register + return cambus_writeb(sensor->slv_addr, COM7, reg) | ret; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + int ret=0; + uint16_t w = resolution[framesize][0]; + uint16_t h = resolution[framesize][1]; + + // Write MSBs + ret |= cambus_writeb(sensor->slv_addr, HOUTSIZE, w>>2); + ret |= cambus_writeb(sensor->slv_addr, VOUTSIZE, h>>1); + + // Write LSBs + ret |= cambus_writeb(sensor->slv_addr, EXHCH, ((w&0x3) | ((h&0x1) << 2))); + + if ((w <= 320) && (h <= 240)) { + // Set QVGA Resolution + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM7, ®); + reg = COM7_SET_RES(reg, COM7_RES_QVGA); + ret |= cambus_writeb(sensor->slv_addr, COM7, reg); + + // Set QVGA Window Size + ret |= cambus_writeb(sensor->slv_addr, HSTART, 0x3F); + ret |= cambus_writeb(sensor->slv_addr, HSIZE, 0x50); + ret |= cambus_writeb(sensor->slv_addr, VSTART, 0x03); + ret |= cambus_writeb(sensor->slv_addr, VSIZE, 0x78); + ret |= cambus_writeb(sensor->slv_addr, HREF, 0x00); + + // Enable auto-scaling/zooming factors + ret |= cambus_writeb(sensor->slv_addr, DSPAUTO, 0xFF); + } else { + // Set VGA Resolution + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM7, ®); + reg = COM7_SET_RES(reg, COM7_RES_VGA); + ret |= cambus_writeb(sensor->slv_addr, COM7, reg); + + // Set VGA Window Size + ret |= cambus_writeb(sensor->slv_addr, HSTART, 0x23); + ret |= cambus_writeb(sensor->slv_addr, HSIZE, 0xA0); + ret |= cambus_writeb(sensor->slv_addr, VSTART, 0x07); + ret |= cambus_writeb(sensor->slv_addr, VSIZE, 0xF0); + ret |= cambus_writeb(sensor->slv_addr, HREF, 0x00); + + // Disable auto-scaling/zooming factors + ret |= cambus_writeb(sensor->slv_addr, DSPAUTO, 0xF3); + + // Clear auto-scaling/zooming factors + ret |= cambus_writeb(sensor->slv_addr, SCAL0, 0x00); + ret |= cambus_writeb(sensor->slv_addr, SCAL1, 0x00); + ret |= cambus_writeb(sensor->slv_addr, SCAL2, 0x00); + } + + return ret; +} + +static int set_framerate(sensor_t *sensor, framerate_t framerate) +{ + return 0; +} + +static int set_contrast(sensor_t *sensor, int level) +{ + level += (NUM_CONTRAST_LEVELS / 2); + if (level < 0 || level >= NUM_CONTRAST_LEVELS) { + return -1; + } + + return cambus_writeb(sensor->slv_addr, CONTRAST, contrast_regs[level][0]); +} + +static int set_brightness(sensor_t *sensor, int level) +{ + int ret=0; + level += (NUM_BRIGHTNESS_LEVELS / 2); + if (level < 0 || level >= NUM_BRIGHTNESS_LEVELS) { + return -1; + } + + ret |= cambus_writeb(sensor->slv_addr, BRIGHTNESS, brightness_regs[level][0]); + ret |= cambus_writeb(sensor->slv_addr, SIGN_BIT, brightness_regs[level][1]); + return ret; +} + +static int set_saturation(sensor_t *sensor, int level) +{ + int ret=0; + + level += (NUM_SATURATION_LEVELS / 2 ); + if (level < 0 || level >= NUM_SATURATION_LEVELS) { + return -1; + } + + ret |= cambus_writeb(sensor->slv_addr, USAT, saturation_regs[level][0]); + ret |= cambus_writeb(sensor->slv_addr, VSAT, saturation_regs[level][1]); + return ret; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM9, ®); + + // Set gain ceiling + reg = COM9_SET_AGC(reg, gainceiling); + return cambus_writeb(sensor->slv_addr, COM9, reg) | ret; +} + +static int set_colorbar(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM3, ®); + + // Enable colorbar test pattern output + reg = COM3_SET_CBAR(reg, enable); + ret |= cambus_writeb(sensor->slv_addr, COM3, reg); + + // Enable DSP colorbar output + ret |= cambus_readb(sensor->slv_addr, DSP_CTRL3, ®); + reg = DSP_CTRL3_SET_CBAR(reg, enable); + return cambus_writeb(sensor->slv_addr, DSP_CTRL3, reg) | ret; +} + +static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AGC(reg, (enable != 0))); + + if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) { + float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 32.0), 1.0); + + int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0))); + int gain_hi = 0xF >> (4 - gain_temp); + int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15); + + ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0)); + } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) { + float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 32.0), 2.0); + + ret |= cambus_readb(sensor->slv_addr, COM9, ®); + ret |= cambus_writeb(sensor->slv_addr, COM9, (reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4)); + } + + return ret; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + uint8_t reg, gain; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + + // DISABLED + // if (reg & COM8_AGC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AGC(reg, 0)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, GAIN, &gain); + + // DISABLED + // if (reg & COM8_AGC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AGC(reg, 1)); + // } + // DISABLED + + int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1)); + float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0); + *gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0)); + + return ret; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, (enable != 0))); + + if ((enable == 0) && (exposure_us >= 0)) { + ret |= cambus_readb(sensor->slv_addr, COM7, ®); + + int t_line = (reg & COM7_RES_QVGA) ? (320 + 256) : (640 + 144); + int t_pclk = (COM7_GET_FMT(reg) == COM7_FMT_P_BAYER) ? 1 : 2; + + ret |= cambus_readb(sensor->slv_addr, COM4, ®); + int pll_mult = 0; + + if (COM4_GET_PLL(reg) == COM4_PLL_BYPASS) pll_mult = 1; + if (COM4_GET_PLL(reg) == COM4_PLL_4x) pll_mult = 4; + if (COM4_GET_PLL(reg) == COM4_PLL_6x) pll_mult = 6; + if (COM4_GET_PLL(reg) == COM4_PLL_8x) pll_mult = 8; + + ret |= cambus_readb(sensor->slv_addr, CLKRC, ®); + int clk_rc = 0; + + if (reg & CLKRC_NO_PRESCALE) { + clk_rc = 1; + } else { + clk_rc = ((reg & CLKRC_PRESCALER) + 1) * 2; + } + + int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000); + + ret |= cambus_writeb(sensor->slv_addr, AEC, ((exposure >> 0) & 0xFF)); + ret |= cambus_writeb(sensor->slv_addr, AECH, ((exposure >> 8) & 0xFF)); + } + + return ret; +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) +{ + uint8_t reg, aec_l, aec_h; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + + // DISABLED + // if (reg & COM8_AEC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, 0)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, AEC, &aec_l); + ret |= cambus_readb(sensor->slv_addr, AECH, &aec_h); + + // DISABLED + // if (reg & COM8_AEC_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AEC(reg, 1)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, COM7, ®); + + int t_line = (reg & COM7_RES_QVGA) ? (320 + 256) : (640 + 144); + int t_pclk = (COM7_GET_FMT(reg) == COM7_FMT_P_BAYER) ? 1 : 2; + + ret |= cambus_readb(sensor->slv_addr, COM4, ®); + int pll_mult = 0; + + if (COM4_GET_PLL(reg) == COM4_PLL_BYPASS) pll_mult = 1; + if (COM4_GET_PLL(reg) == COM4_PLL_4x) pll_mult = 4; + if (COM4_GET_PLL(reg) == COM4_PLL_6x) pll_mult = 6; + if (COM4_GET_PLL(reg) == COM4_PLL_8x) pll_mult = 8; + + ret |= cambus_readb(sensor->slv_addr, CLKRC, ®); + int clk_rc = 0; + + if (reg & CLKRC_NO_PRESCALE) { + clk_rc = 1; + } else { + clk_rc = ((reg & CLKRC_PRESCALER) + 1) * 2; + } + + *exposure_us = (((aec_h<<8)+(aec_l<<0))*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000); + + return ret; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AWB(reg, (enable != 0))); + + if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db)) + && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) { + ret |= cambus_readb(sensor->slv_addr, AWB_CTRL1, ®); + float gain_div = (reg & 0x2) ? 64.0 : 128.0; + + int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0); + int g_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((g_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0); + int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0)) * gain_div), 255), 0); + + ret |= cambus_writeb(sensor->slv_addr, BLUE, b_gain); + ret |= cambus_writeb(sensor->slv_addr, RED, r_gain); + ret |= cambus_writeb(sensor->slv_addr, GREEN, g_gain); + } + + return ret; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + uint8_t reg, blue, red, green; + int ret = cambus_readb(sensor->slv_addr, COM8, ®); + + // DISABLED + // if (reg & COM8_AWB_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AWB(reg, 0)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, BLUE, &blue); + ret |= cambus_readb(sensor->slv_addr, RED, &red); + ret |= cambus_readb(sensor->slv_addr, GREEN, &green); + + // DISABLED + // if (reg & COM8_AWB_EN) { + // ret |= cambus_writeb(sensor->slv_addr, COM8, COM8_SET_AWB(reg, 1)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, AWB_CTRL1, ®); + float gain_div = (reg & 0x2) ? 64.0 : 128.0; + + *r_gain_db = 20.0 * (fast_log(red / gain_div) / fast_log(10.0)); + *g_gain_db = 20.0 * (fast_log(green / gain_div) / fast_log(10.0)); + *b_gain_db = 20.0 * (fast_log(blue / gain_div) / fast_log(10.0)); + + return ret; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM3, ®); + ret |= cambus_writeb(sensor->slv_addr, COM3, COM3_SET_MIRROR(reg, enable)) ; + + return ret; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, COM3, ®); + ret |= cambus_writeb(sensor->slv_addr, COM3, COM3_SET_FLIP(reg, enable)); + + return ret; +} + +static int set_special_effect(sensor_t *sensor, sde_t sde) +{ + int ret=0; + + switch (sde) { + case SDE_NEGATIVE: + ret |= cambus_writeb(sensor->slv_addr, SDE, 0x46); + break; + case SDE_NORMAL: + ret |= cambus_writeb(sensor->slv_addr, SDE, 0x06); + ret |= cambus_writeb(sensor->slv_addr, UFIX, 0x80); + ret |= cambus_writeb(sensor->slv_addr, UFIX, 0x80); + break; + default: + return -1; + } + + return ret; +} + +static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef) +{ + int ret=0; + + ret |= cambus_writeb(sensor->slv_addr, LC_CTR, (enable&0x01)); + ret |= cambus_writeb(sensor->slv_addr, LC_RADI, radi); + ret |= cambus_writeb(sensor->slv_addr, LC_COEF, coef); + return ret; +} + +int ov7725_init(sensor_t *sensor) +{ + // Initialize sensor structure. + sensor->gs_bpp = 2; + sensor->reset = reset; + sensor->sleep = sleep; + sensor->read_reg = read_reg; + sensor->write_reg = write_reg; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_contrast = set_contrast; + sensor->set_brightness = set_brightness; + sensor->set_saturation = set_saturation; + sensor->set_gainceiling = set_gainceiling; + sensor->set_colorbar = set_colorbar; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + sensor->set_special_effect = set_special_effect; + sensor->set_lens_correction = set_lens_correction; + + // Set sensor flags + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + return 0; +} diff --git a/src/openmv/src/omv/ov7725.h b/src/openmv/src/omv/ov7725.h new file mode 100755 index 0000000..1881f73 --- /dev/null +++ b/src/openmv/src/omv/ov7725.h @@ -0,0 +1,13 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV7725 driver. + * + */ +#ifndef __OV7725_H__ +#define __OV7725_H__ +#include "sensor.h" +int ov7725_init(sensor_t *sensor); +#endif // __OV7725_H__ diff --git a/src/openmv/src/omv/ov7725_regs.h b/src/openmv/src/omv/ov7725_regs.h new file mode 100755 index 0000000..c85e472 --- /dev/null +++ b/src/openmv/src/omv/ov7725_regs.h @@ -0,0 +1,345 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV7725 register definitions. + */ + +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ + +#define GAIN 0x00 /* AGC - Gain control gain setting */ +#define BLUE 0x01 /* AWB - Blue channel gain setting */ +#define RED 0x02 /* AWB - Red channel gain setting */ +#define GREEN 0x03 /* AWB - Green channel gain setting */ +#define BAVG 0x05 /* U/B Average Level */ +#define GAVG 0x06 /* Y/Gb Average Level */ +#define RAVG 0x07 /* V/R Average Level */ +#define AECH 0x08 /* Exposure Value - AEC MSBs */ + +#define COM2 0x09 /* Common Control 2 */ +#define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */ +#define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */ +#define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */ +#define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */ +#define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */ + +#define PID 0x0A /* Product ID Number MSB */ +#define VER 0x0B /* Product ID Number LSB */ + +#define COM3 0x0C /* Common Control 3 */ +#define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */ +#define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */ +#define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */ +#define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */ +#define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */ +#define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */ +#define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */ +#define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */ +#define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0)) +#define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6)) +#define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7)) +#define COM3_GET_CBAR(r) ((r>>0)&1) +#define COM3_GET_MIRROR(r) ((r>>6)&1) +#define COM3_GET_FLIP(r) ((r>>7)&1) + +#define COM4 0x0D /* Common Control 4 */ +#define COM4_PLL_BYPASS 0x00 /* Bypass PLL */ +#define COM4_PLL_4x 0x40 /* PLL frequency 4x */ +#define COM4_PLL_6x 0x80 /* PLL frequency 6x */ +#define COM4_PLL_8x 0xC0 /* PLL frequency 8x */ +#define COM4_AEC_FULL 0x00 /* AEC evaluate full window */ +#define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */ +#define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */ +#define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */ +#define COM4_GET_PLL(r) (r&0xC0) + +#define COM5 0x0E /* Common Control 5 */ +#define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */ +#define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */ +#define COM5_AFR_0 0x00 /* No reduction of frame rate */ +#define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */ +#define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */ +#define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */ +#define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */ +#define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */ +#define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */ +#define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */ + +#define COM6 0x0F /* Common Control 6 */ +#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */ + +#define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */ + +#define CLKRC 0x11 /* Internal Clock */ +#define CLKRC_NO_PRESCALE 0x40 /* Use external clock directly */ +#define CLKRC_PRESCALER 0x3F /* Internal clock pre-scaler */ + +#define COM7 0x12 /* Common Control 7 */ +#define COM7_RESET 0x80 /* SCCB Register Reset */ +#define COM7_RES_VGA 0x00 /* Resolution VGA */ +#define COM7_RES_QVGA 0x40 /* Resolution QVGA */ +#define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */ +#define COM7_SENSOR_RAW 0x10 /* Sensor RAW */ +#define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */ +#define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */ +#define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */ +#define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */ +#define COM7_FMT_YUV 0x00 /* Output format YUV */ +#define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */ +#define COM7_FMT_RGB 0x02 /* Output format RGB */ +#define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */ +#define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0)) +#define COM7_SET_RES(r, x) ((r&0xBF)|(x)) +#define COM7_GET_FMT(r) (r&0x03) + +#define COM8 0x13 /* Common Control 8 */ +#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */ +#define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */ +#define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */ +#define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */ +#define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */ +#define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */ +#define COM8_AGC_EN 0x04 /* AGC Enable */ +#define COM8_AWB_EN 0x02 /* AWB Enable */ +#define COM8_AEC_EN 0x01 /* AEC Enable */ +#define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2)) +#define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1)) +#define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0)) + +#define COM9 0x14 /* Common Control 9 */ +#define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */ +#define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */ +#define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */ +#define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */ +#define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */ +#define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */ +#define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ +#define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ +#define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4)) + +#define COM10 0x15 /* Common Control 10 */ +#define COM10_NEGATIVE 0x80 /* Output negative data */ +#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ +#define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */ +#define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */ +#define COM10_PCLK_REV 0x10 /* PCLK reverse */ +#define COM10_HREF_REV 0x08 /* HREF reverse */ +#define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */ +#define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */ +#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ +#define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */ +#define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */ + +#define REG16 0x16 /* Register 16 */ +#define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */ + +#define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */ +#define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */ +#define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */ +#define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */ +#define PSHFT 0x1B /* Data Format - Pixel Delay Select */ +#define MIDH 0x1C /* Manufacturer ID Byte - High */ +#define MIDL 0x1D /* Manufacturer ID Byte - Low */ +#define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */ + +#define COM11 0x20 /* Common Control 11 */ +#define COM11_SNGL_FRAME_EN 0x02 /* Single frame ON/OFF selection */ +#define COM11_SNGL_XFR_TRIG 0x01 /* Single frame transfer trigger */ + +#define BDBASE 0x22 /* Banding Filter Minimum AEC Value */ +#define BDSTEP 0x23 /* Banding Filter Maximum Step */ +#define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */ +#define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */ +#define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */ +#define REG28 0x28 /* Selection on the number of dummy rows, N */ +#define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */ +#define EXHCH 0x2A /* Dummy Pixel Insert MSB */ +#define EXHCL 0x2B /* Dummy Pixel Insert LSB */ +#define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */ +#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */ +#define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */ +#define YAVE 0x2F /* Y/G Channel Average Value */ +#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */ +#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance Low Level Threshold */ +#define HREF 0x32 /* Image Start and Size Control */ +#define DM_LNL 0x33 /* Dummy Row Low 8 Bits */ +#define DM_LNH 0x34 /* Dummy Row High 8 Bits */ +#define ADOFF_B 0x35 /* AD Offset Compensation Value for B Channel */ +#define ADOFF_R 0x36 /* AD Offset Compensation Value for R Channel */ +#define ADOFF_GB 0x37 /* AD Offset Compensation Value for GB Channel */ +#define ADOFF_GR 0x38 /* AD Offset Compensation Value for GR Channel */ +#define OFF_B 0x39 /* AD Offset Compensation Value for B Channel */ +#define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */ +#define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */ +#define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */ + +#define COM12 0x3D /* DC offset compensation for analog process */ + +#define COM13 0x3E /* Common Control 13 */ +#define COM13_BLC_EN 0x80 /* BLC enable */ +#define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */ +#define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */ +#define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */ + +#define COM14 0x3F /* Common Control 14 */ +#define COM15 0x40 /* Common Control 15 */ +#define COM16 0x41 /* Common Control 16 */ +#define TGT_B 0x42 /* BLC Blue Channel Target Value */ +#define TGT_R 0x43 /* BLC Red Channel Target Value */ +#define TGT_GB 0x44 /* BLC Gb Channel Target Value */ +#define TGT_GR 0x45 /* BLC Gr Channel Target Value */ + +#define LC_CTR 0x46 /* Lens Correction Control */ +#define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */ +#define LC_CTR_RGB_COMP_3 0x04 /* R, G, and B channel compensation coefficient is set by registers + LC_COEFB (0x4B), LC_COEF (0x49), and LC_COEFR (0x4C), respectively */ +#define LC_CTR_EN 0x01 /* Lens correction enable */ +#define LC_XC 0x47 /* X Coordinate of Lens Correction Center Relative to Array Center */ +#define LC_YC 0x48 /* Y Coordinate of Lens Correction Center Relative to Array Center */ +#define LC_COEF 0x49 /* Lens Correction Coefficient */ +#define LC_RADI 0x4A /* Lens Correction Radius */ +#define LC_COEFB 0x4B /* Lens Correction B Channel Compensation Coefficient */ +#define LC_COEFR 0x4C /* Lens Correction R Channel Compensation Coefficient */ + +#define FIXGAIN 0x4D /* Analog Fix Gain Amplifier */ +#define AREF0 0x4E /* Sensor Reference Control */ +#define AREF1 0x4F /* Sensor Reference Current Control */ +#define AREF2 0x50 /* Analog Reference Control */ +#define AREF3 0x51 /* ADC Reference Control */ +#define AREF4 0x52 /* ADC Reference Control */ +#define AREF5 0x53 /* ADC Reference Control */ +#define AREF6 0x54 /* Analog Reference Control */ +#define AREF7 0x55 /* Analog Reference Control */ +#define UFIX 0x60 /* U Channel Fixed Value Output */ +#define VFIX 0x61 /* V Channel Fixed Value Output */ +#define AWBB_BLK 0x62 /* AWB Option for Advanced AWB */ + +#define AWB_CTRL0 0x63 /* AWB Control Byte 0 */ +#define AWB_CTRL0_GAIN_EN 0x80 /* AWB gain enable */ +#define AWB_CTRL0_CALC_EN 0x40 /* AWB calculate enable */ +#define AWB_CTRL0_WBC_MASK 0x0F /* WBC threshold 2 */ + +#define DSP_CTRL1 0x64 /* DSP Control Byte 1 */ +#define DSP_CTRL1_FIFO_EN 0x80 /* FIFO enable/disable selection */ +#define DSP_CTRL1_UV_EN 0x40 /* UV adjust function ON/OFF selection */ +#define DSP_CTRL1_SDE_EN 0x20 /* SDE enable */ +#define DSP_CTRL1_MTRX_EN 0x10 /* Color matrix ON/OFF selection */ +#define DSP_CTRL1_INTRP_EN 0x08 /* Interpolation ON/OFF selection */ +#define DSP_CTRL1_GAMMA_EN 0x04 /* Gamma function ON/OFF selection */ +#define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */ +#define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */ + +#define DSP_CTRL2 0x65 /* DSP Control Byte 2 */ +#define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */ +#define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */ +#define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */ +#define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */ + +#define DSP_CTRL3 0x66 /* DSP Control Byte 3 */ +#define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */ +#define DSP_CTRL3_CBAR_EN 0x20 /* DSP color bar ON/OFF selection */ +#define DSP_CTRL3_FIFO_EN 0x08 /* FIFO power down ON/OFF selection */ +#define DSP_CTRL3_SCAL1_PWDN 0x04 /* Scaling module power down control 1 */ +#define DSP_CTRL3_SCAL2_PWDN 0x02 /* Scaling module power down control 2 */ +#define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */ +#define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5)) + +#define DSP_CTRL4 0x67 /* DSP Control Byte 4 */ +#define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */ +#define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */ +#define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */ + +#define AWB_BIAS 0x68 /* AWB BLC Level Clip */ +#define AWB_CTRL1 0x69 /* AWB Control 1 */ +#define AWB_CTRL2 0x6A /* AWB Control 2 */ + +#define AWB_CTRL3 0x6B /* AWB Control 3 */ +#define AWB_CTRL3_ADVANCED 0x80 /* AWB mode select - Advanced AWB */ +#define AWB_CTRL3_SIMPLE 0x00 /* AWB mode select - Simple AWB */ + +#define AWB_CTRL4 0x6C /* AWB Control 4 */ +#define AWB_CTRL5 0x6D /* AWB Control 5 */ +#define AWB_CTRL6 0x6E /* AWB Control 6 */ +#define AWB_CTRL7 0x6F /* AWB Control 7 */ +#define AWB_CTRL8 0x70 /* AWB Control 8 */ +#define AWB_CTRL9 0x71 /* AWB Control 9 */ +#define AWB_CTRL10 0x72 /* AWB Control 10 */ +#define AWB_CTRL11 0x73 /* AWB Control 11 */ +#define AWB_CTRL12 0x74 /* AWB Control 12 */ +#define AWB_CTRL13 0x75 /* AWB Control 13 */ +#define AWB_CTRL14 0x76 /* AWB Control 14 */ +#define AWB_CTRL15 0x77 /* AWB Control 15 */ +#define AWB_CTRL16 0x78 /* AWB Control 16 */ +#define AWB_CTRL17 0x79 /* AWB Control 17 */ +#define AWB_CTRL18 0x7A /* AWB Control 18 */ +#define AWB_CTRL19 0x7B /* AWB Control 19 */ +#define AWB_CTRL20 0x7C /* AWB Control 20 */ +#define AWB_CTRL21 0x7D /* AWB Control 21 */ +#define GAM1 0x7E /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */ +#define GAM2 0x7F /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */ +#define GAM3 0x80 /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */ +#define GAM4 0x81 /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */ +#define GAM5 0x82 /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */ +#define GAM6 0x83 /* Gamma Curve 6th Segment Input End Point 0x30 Output Value */ +#define GAM7 0x84 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */ +#define GAM8 0x85 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */ +#define GAM9 0x86 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */ +#define GAM10 0x87 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */ +#define GAM11 0x88 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */ +#define GAM12 0x89 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */ +#define GAM13 0x8A /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */ +#define GAM14 0x8B /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */ +#define GAM15 0x8C /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */ +#define SLOP 0x8D /* Gamma Curve Highest Segment Slope */ +#define DNSTH 0x8E /* De-noise Threshold */ +#define EDGE0 0x8F /* Edge Enhancement Strength Control */ +#define EDGE1 0x90 /* Edge Enhancement Threshold Control */ +#define DNSOFF 0x91 /* Auto De-noise Threshold Control */ +#define EDGE2 0x92 /* Edge Enhancement Strength Upper Limit */ +#define EDGE3 0x93 /* Edge Enhancement Strength Upper Limit */ +#define MTX1 0x94 /* Matrix Coefficient 1 */ +#define MTX2 0x95 /* Matrix Coefficient 2 */ +#define MTX3 0x96 /* Matrix Coefficient 3 */ +#define MTX4 0x97 /* Matrix Coefficient 4 */ +#define MTX5 0x98 /* Matrix Coefficient 5 */ +#define MTX6 0x99 /* Matrix Coefficient 6 */ + +#define MTX_CTRL 0x9A /* Matrix Control */ +#define MTX_CTRL_DBL_EN 0x80 /* Matrix double ON/OFF selection */ + +#define BRIGHTNESS 0x9B /* Brightness Control */ +#define CONTRAST 0x9C /* Contrast Gain */ +#define UVADJ0 0x9E /* Auto UV Adjust Control 0 */ +#define UVADJ1 0x9F /* Auto UV Adjust Control 1 */ +#define SCAL0 0xA0 /* DCW Ratio Control */ +#define SCAL1 0xA1 /* Horizontal Zoom Out Control */ +#define SCAL2 0xA2 /* Vertical Zoom Out Control */ +#define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */ +#define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */ + +#define SDE 0xA6 /* Special Digital Effect Control */ +#define SDE_NEGATIVE_EN 0x40 /* Negative image enable */ +#define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */ +#define SDE_V_FIXED_EN 0x10 /* V fixed value enable */ +#define SDE_U_FIXED_EN 0x08 /* U fixed value enable */ +#define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */ +#define SDE_SATURATION_EN 0x02 /* Saturation enable */ +#define SDE_HUE_EN 0x01 /* Hue enable */ + +#define USAT 0xA7 /* U Component Saturation Gain */ +#define VSAT 0xA8 /* V Component Saturation Gain */ +#define HUECOS 0xA9 /* Cosine value × 0x80 */ +#define HUESIN 0xAA /* Sine value × 0x80 */ +#define SIGN_BIT 0xAB /* Sign Bit for Hue and Brightness */ + +#define DSPAUTO 0xAC /* DSP Auto Function ON/OFF Control */ +#define DSPAUTO_AWB_EN 0x80 /* AWB auto threshold control */ +#define DSPAUTO_DENOISE_EN 0x40 /* De-noise auto threshold control */ +#define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */ +#define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */ +#define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */ +#define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2)) */ + +#endif //__REG_REGS_H__ diff --git a/src/openmv/src/omv/ov9650.c b/src/openmv/src/omv/ov9650.c new file mode 100755 index 0000000..902052f --- /dev/null +++ b/src/openmv/src/omv/ov9650.c @@ -0,0 +1,547 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV9650 driver. + * + */ +#include +#include +#include +#include STM32_HAL_H +#include "cambus.h" +#include "ov9650.h" +#include "systick.h" +#include "ov9650_regs.h" +#include "omv_boardconfig.h" + +#define NUM_BR_LEVELS 7 + +static const uint8_t default_regs[][2] = { + /* See Implementation Guide */ + {REG_COM2, 0x01}, /* Output drive x2 */ + {REG_COM5, 0x00}, /* System clock */ + {REG_CLKRC, 0x81}, /* Clock control 30 FPS*/ + {REG_MVFP, 0x10}, /* Mirror/VFlip */ + + {REG_OFON, 0x43}, /* Power down register */ + {REG_ACOM38, 0x12}, /* reserved */ + {REG_ADC, 0x91}, /* reserved */ + {REG_RSVD35, 0x81}, /* reserved */ + + /* Default QQVGA-RGB565 */ + {REG_COM7, 0x14}, /* QVGA/RGB565 */ + {REG_COM1, 0x24}, /* QQVGA/Skip Option */ + {REG_COM3, 0x04}, /* Vario Pixels */ + {REG_COM4, 0x80}, /* Vario Pixels */ + {REG_COM15, 0xD0}, /* Output range 0x00-0xFF/RGB565*/ + + /* YUV fmt /Special Effects Controls */ + {REG_TSLB, 0x01}, /* YUYV/DBLC Enable/Bitwise reverse*/ + {REG_MANU, 0x80}, /* Manual U */ + {REG_MANV, 0x80}, /* Manual V */ + + /* Dummy pixels settings */ + {REG_EXHCH, 0x00}, /* Dummy Pixel Insert MSB */ + {REG_EXHCL, 0x00}, /* Dummy Pixel Insert LSB */ + + {REG_ADVFH, 0x00}, /* Dummy Pixel Insert MSB */ + {REG_ADVFL, 0x00}, /* Dummy Pixel Insert LSB */ + + /* See Implementation Guide Section 3.4.1.2 */ + {REG_COM8, 0xA7}, /* Enable Fast Mode AEC/Enable Banding Filter/AGC/AWB/AEC */ + {0x60, 0x8C}, /* Normal AWB, 0x0C for Advanced AWB */ + {REG_AEW, 0x70}, /* AGC/AEC Threshold Upper Limit */ + {REG_AEB, 0x64}, /* AGC/AEC Threshold Lower Limit */ + {REG_VPT, 0xC3}, /* Fast AEC operating region */ + + + /* See OV9650 Implementation Guide */ + {REG_COM11, 0x01}, /* Night Mode-Automatic/Manual Banding Filter */ + {REG_MBD, 0x1a}, /* MBD[7:0] Manual banding filter LSB */ + {REG_HV, 0x0A}, /* HV[0] Manual banding filter MSB */ + {REG_COM12, 0x04}, /* HREF options/ UV average */ + {REG_COM9, 0x20}, /* Gain ceiling [6:4]/Over-Exposure */ + {REG_COM16, 0x02}, /* Color matrix coeff double option */ + {REG_COM13, 0x10}, /* Gamma/Colour Matrix/UV delay */ + {REG_COM23, 0x00}, /* Disable Color bar/Analog Color Gain */ + {REG_PSHFT, 0x00}, /* Pixel delay after HREF */ + {REG_COM10, 0x00}, /* Slave mode, HREF vs HSYNC, signals negate */ + {REG_EDGE, 0xa6}, /* Edge enhancement treshhold and factor */ + {REG_COM6, 0x43}, /* HREF & ADBLC options */ + {REG_COM22, 0x20}, /* Edge enhancement/Denoising */ + + /* Some registers discovered with probing */ + {REG_COM21, 0x00}, /* COM21[3] Digital Zoom */ + {REG_GRCOM, 0x24}, /* Enable Internal Regulator */ + {0xaa, 0x00}, /* some edge effect 0x80 */ + {0xab, 0x00}, /* makes image blurry 0x40 */ + +#if 0 + /* When AEC is not used */ + {REG_AECH, 0x00}, /* Exposure Value MSB */ + {REG_AECHM, 0x00}, /* Exposure Value LSB */ +#endif + +#if 0 + /* Windowing Settings */ + {REG_HSTART, 0x1d}, /* Horiz start high bits */ + {REG_HSTOP, 0xbd}, /* Horiz stop high bits */ + {REG_HREF, 0xbf}, /* HREF pieces */ + + {REG_VSTART, 0x00}, /* Vert start high bits */ + {REG_VSTOP, 0x80}, /* Vert stop high bits */ + {REG_VREF, 0x12}, /* Pieces of GAIN, VSTART, VSTOP */ +#endif + +#if 1 + /* gamma curve p */ + {0x6c, 0x40}, + {0x6d, 0x30}, + {0x6e, 0x4b}, + {0x6f, 0x60}, + {0x70, 0x70}, + {0x71, 0x70}, + {0x72, 0x70}, + {0x73, 0x70}, + {0x74, 0x60}, + {0x75, 0x60}, + {0x76, 0x50}, + {0x77, 0x48}, + {0x78, 0x3a}, + {0x79, 0x2e}, + {0x7a, 0x28}, + {0x7b, 0x22}, + + /* Gamma curve T */ + {0x7c, 0x04}, + {0x7d, 0x07}, + {0x7e, 0x10}, + {0x7f, 0x28}, + {0x80, 0x36}, + {0x81, 0x44}, + {0x82, 0x52}, + {0x83, 0x60}, + {0x84, 0x6c}, + {0x85, 0x78}, + {0x86, 0x8c}, + {0x87, 0x9e}, + {0x88, 0xbb}, + {0x89, 0xd2}, + {0x8a, 0xe6}, + + /* Reserved Registers, see OV965x App Note */ + {0x16, 0x07}, + {0x96, 0x04}, + {0x8e, 0x00}, + {0x94, 0x88}, + {0x95, 0x88}, + {0x5c, 0x96}, + {0x5d, 0x96}, + {0x5e, 0x10}, + {0x59, 0xeb}, + {0x5a, 0x9c}, + {0x5b, 0x55}, +#endif + + /* NULL reg */ + {0x00, 0x00} +}; + +static const uint8_t rgb565_regs[][2] = { + /* See Implementation Guide */ + {REG_COM3, 0x04}, /* Vario Pixels */ + {REG_COM4, 0x80}, /* Vario Pixels */ + {REG_COM15, 0xD0}, /* Output range 0x00-0xFF/RGB565*/ + + /* RGB color matrix */ + {REG_MTX1, 0x71}, + {REG_MTX2, 0x3e}, + {REG_MTX3, 0x0c}, + + {REG_MTX4, 0x33}, + {REG_MTX5, 0x72}, + {REG_MTX6, 0x00}, + + {REG_MTX7, 0x2b}, + {REG_MTX8, 0x66}, + {REG_MTX9, 0xd2}, + {REG_MTXS, 0x65}, + + /* NULL reg */ + {0x00, 0x00} +}; + +static const uint8_t yuv422_regs[][2] = { + /* See Implementation Guide */ + {REG_COM3, 0x04}, /* Vario Pixels */ + {REG_COM4, 0x80}, /* Vario Pixels */ + {REG_COM15, 0xC0}, /* Output range 0x00-0xFF */ + + /* YUV color matrix */ + {REG_MTX1, 0x3a}, + {REG_MTX2, 0x3d}, + {REG_MTX3, 0x03}, + + {REG_MTX4, 0x12}, + {REG_MTX5, 0x26}, + {REG_MTX6, 0x38}, + + {REG_MTX7, 0x40}, + {REG_MTX8, 0x40}, + {REG_MTX9, 0x40}, + {REG_MTXS, 0x0d}, + + /* NULL reg */ + {0x00, 0x00} +}; + +static int reset(sensor_t *sensor) +{ + int i=0; + const uint8_t (*regs)[2]=default_regs; + + /* Reset all registers */ + cambus_writeb(sensor->slv_addr, REG_COM7, 0x80); + + /* delay n ms */ + systick_sleep(10); + + /* Write initial regsiters */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + return 0; +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + int i=0; + const uint8_t (*regs)[2]; + uint8_t com7=0; /* framesize/RGB */ + + /* read pixel format reg */ + cambus_readb(sensor->slv_addr, REG_COM7, &com7); + + switch (pixformat) { + case PIXFORMAT_RGB565: + com7 |= REG_COM7_RGB; + regs = rgb565_regs; + break; + case PIXFORMAT_YUV422: + com7 &= (~REG_COM7_RGB); + regs = yuv422_regs; + break; + case PIXFORMAT_GRAYSCALE: + com7 &= (~REG_COM7_RGB); + regs = yuv422_regs; + break; + default: + return -1; + } + + /* Set pixel format */ + cambus_writeb(sensor->slv_addr, REG_COM7, com7); + + /* Write pixel format registers */ + while (regs[i][0]) { + cambus_writeb(sensor->slv_addr, regs[i][0], regs[i][1]); + i++; + } + + return 0; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + uint8_t com7=0; /* framesize/RGB */ + uint8_t com1=0; /* Skip option */ + + /* read COM7 RGB bit */ + cambus_readb(sensor->slv_addr, REG_COM7, &com7); + com7 &= REG_COM7_RGB; + + switch (framesize) { + case FRAMESIZE_QQCIF: + com7 |= REG_COM7_QCIF; + com1 |= REG_COM1_QQCIF|REG_COM1_SKIP2; + break; + case FRAMESIZE_QQVGA: + com7 |= REG_COM7_QVGA; + com1 |= REG_COM1_QQVGA|REG_COM1_SKIP2; + break; + case FRAMESIZE_QCIF: + com7 |= REG_COM7_QCIF; + break; + default: + return -1; + } + + /* write the frame size registers */ + cambus_writeb(sensor->slv_addr, REG_COM1, com1); + cambus_writeb(sensor->slv_addr, REG_COM7, com7); + + return 0; +} + +static int set_framerate(sensor_t *sensor, framerate_t framerate) +{ + /* Write framerate register */ + cambus_writeb(sensor->slv_addr, REG_CLKRC, framerate); + return 0; +} + +static int set_brightness(sensor_t *sensor, int level) +{ + int i; + + static uint8_t regs[NUM_BR_LEVELS + 1][3] = { + { REG_AEW, REG_AEB, REG_VPT }, + { 0x1c, 0x12, 0x50 }, /* -3 */ + { 0x3d, 0x30, 0x71 }, /* -2 */ + { 0x50, 0x44, 0x92 }, /* -1 */ + { 0x70, 0x64, 0xc3 }, /* 0 */ + { 0x90, 0x84, 0xd4 }, /* +1 */ + { 0xc4, 0xbf, 0xf9 }, /* +2 */ + { 0xd8, 0xd0, 0xfa }, /* +3 */ + }; + + level += (NUM_BR_LEVELS / 2 + 1); + if (level < 0 || level > NUM_BR_LEVELS) { + return -1; + } + + for (i=0; i<3; i++) { + cambus_writeb(sensor->slv_addr, regs[0][i], regs[level][i]); + } + + return 0; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + /* Write gain ceiling register */ + cambus_writeb(sensor->slv_addr, REG_COM9, (gainceiling<<4)); + return 0; +} + +static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_COM8, (reg & (~REG_COM8_AGC)) | ((enable != 0) ? REG_COM8_AGC : 0)); +#if 0 + if ((enable == 0) && (!isnanf(gain_db)) && (!isinf(gain_db))) { + float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 128.0), 1.0); + + int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0))); + int gain_hi = 0x3F >> (6 - gain_temp); + int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15); + + ret |= cambus_writeb(sensor->slv_addr, REG_GAIN, ((gain_hi & 0x0F) << 4) | (gain_lo << 0)); + ret |= cambus_readb(sensor->slv_addr, REG_VREF, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_VREF, ((gain_hi & 0x30) << 2) | (reg & 0x3F)); + } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinf(gain_db_ceiling))) { + float gain_ceiling = IM_MAX(IM_MIN(fast_expf((gain_db_ceiling / 20.0) * fast_log(10.0)), 128.0), 2.0); + + ret |= cambus_readb(sensor->slv_addr, REG_COM9, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_COM9, (reg & 0x8F) | ((fast_ceilf(fast_log2(gain_ceiling)) - 1) << 4)); + } +#endif + return ret; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + uint8_t reg, gain_lo, gain_hi; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + + // DISABLED + // if (reg & REG_COM8_AGC) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg & (~REG_COM8_AGC)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, REG_GAIN, &gain_lo); + ret |= cambus_readb(sensor->slv_addr, REG_VREF, &gain_hi); + + // DISABLED + // if (reg & REG_COM8_AGC) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg | REG_COM8_AGC); + // } + // DISABLED + + int gain = ((gain_hi & 0xC0) << 2) | gain_lo; + int hi_gain = 1 << (((gain >> 9) & 1) + ((gain >> 8) & 1) + ((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1)); + float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0); + *gain_db = 20.0 * (fast_log(hi_gain * lo_gain) / fast_log(10.0)); + + return ret; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_COM8, (reg & (~REG_COM8_AEC)) | ((enable != 0) ? REG_COM8_AEC : 0)); + + if ((enable == 0) && (exposure_us >= 0)) { + ret |= cambus_readb(sensor->slv_addr, REG_COM7, ®); + int t_line = 0, t_pclk = (reg & REG_COM7_RGB) ? 2 : 1; + + if (reg & REG_COM7_VGA) t_line = 640 + 160; + if (reg & REG_COM7_CIF) t_line = 352 + 168; + if (reg & REG_COM7_QVGA) t_line = 320 + 80; + if (reg & REG_COM7_QCIF) t_line = 176 + 84; + + ret |= cambus_readb(sensor->slv_addr, REG_CLKRC, ®); + int pll_mult = (reg & REG_CLKRC_DOUBLE) ? 2 : 1; + int clk_rc = ((reg & REG_CLKRC_DIVIDER_MASK) + 1) * 2; + + int exposure = IM_MAX(IM_MIN(((exposure_us*(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000); + + ret |= cambus_readb(sensor->slv_addr, REG_COM1, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_COM1, (reg & 0xFC) | ((exposure >> 0) & 0x3)); + + ret |= cambus_readb(sensor->slv_addr, REG_AECH, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_AECH, (reg & 0x00) | ((exposure >> 2) & 0xFF)); + + ret |= cambus_readb(sensor->slv_addr, REG_AECHM, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_AECHM, (reg & 0xC0) | ((exposure >> 10) & 0x3F)); + } + + return ret; +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) +{ + uint8_t reg, aec_10, aec_92, aec_1510; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + + // DISABLED + // if (reg & REG_COM8_AEC) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg & (~REG_COM8_AEC)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, REG_COM1, &aec_10); + ret |= cambus_readb(sensor->slv_addr, REG_AECH, &aec_92); + ret |= cambus_readb(sensor->slv_addr, REG_AECHM, &aec_1510); + + // DISABLED + // if (reg & REG_COM8_AEC) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg | REG_COM8_AEC); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, REG_COM7, ®); + int t_line = 0, t_pclk = (reg & REG_COM7_RGB) ? 2 : 1; + + if (reg & REG_COM7_VGA) t_line = 640 + 160; + if (reg & REG_COM7_CIF) t_line = 352 + 168; + if (reg & REG_COM7_QVGA) t_line = 320 + 80; + if (reg & REG_COM7_QCIF) t_line = 176 + 84; + + ret |= cambus_readb(sensor->slv_addr, REG_CLKRC, ®); + int pll_mult = (reg & REG_CLKRC_DOUBLE) ? 2 : 1; + int clk_rc = ((reg & REG_CLKRC_DIVIDER_MASK) + 1) * 2; + + uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0); + *exposure_us = (exposure*t_line*t_pclk)/(((OMV_XCLK_FREQUENCY/clk_rc)*pll_mult)/1000000); + + return ret; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + uint8_t reg; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + ret |= cambus_writeb(sensor->slv_addr, REG_COM8, (reg & (~REG_COM8_AWB)) | ((enable != 0) ? REG_COM8_AWB : 0)); + + if ((enable == 0) && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db)) + && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) { + int r_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((r_gain_db / 20.0) * fast_log(10.0)) * 128.0), 255), 0); + int b_gain = IM_MAX(IM_MIN(fast_roundf(fast_expf((b_gain_db / 20.0) * fast_log(10.0)) * 128.0), 255), 0); + + ret |= cambus_writeb(sensor->slv_addr, REG_BLUE, b_gain); + ret |= cambus_writeb(sensor->slv_addr, REG_RED, r_gain); + } + + return ret; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + uint8_t reg, blue, red; + int ret = cambus_readb(sensor->slv_addr, REG_COM8, ®); + + // DISABLED + // if (reg & REG_COM8_AWB) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg & (~REG_COM8_AWB)); + // } + // DISABLED + + ret |= cambus_readb(sensor->slv_addr, REG_BLUE, &blue); + ret |= cambus_readb(sensor->slv_addr, REG_RED, &red); + + // DISABLED + // if (reg & REG_COM8_AWB) { + // ret |= cambus_writeb(sensor->slv_addr, REG_COM8, reg | REG_COM8_AWB); + // } + // DISABLED + + *r_gain_db = 20.0 * (fast_log(red / 128.0) / fast_log(10.0)); + *b_gain_db = 20.0 * (fast_log(blue / 128.0) / fast_log(10.0)); + + return ret; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + uint8_t val; + int ret = cambus_readb(sensor->slv_addr, REG_MVFP, &val); + ret |= cambus_writeb(sensor->slv_addr, REG_MVFP, enable ? (val | REG_MVFP_HMIRROR) : (val & (~REG_MVFP_HMIRROR))); + + return ret; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + uint8_t val; + int ret = cambus_readb(sensor->slv_addr, REG_MVFP, &val); + ret |= cambus_writeb(sensor->slv_addr, REG_MVFP, enable ? (val | REG_MVFP_VFLIP) : (val & (~REG_MVFP_VFLIP))); + + return ret; +} + +int ov9650_init(sensor_t *sensor) +{ + // Initialize sensor structure. + sensor->gs_bpp = 2; + sensor->reset = reset; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; + sensor->set_brightness = set_brightness; + sensor->set_gainceiling = set_gainceiling; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + + // Set sensor flags + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + return 0; +} diff --git a/src/openmv/src/omv/ov9650.h b/src/openmv/src/omv/ov9650.h new file mode 100755 index 0000000..2623351 --- /dev/null +++ b/src/openmv/src/omv/ov9650.h @@ -0,0 +1,13 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV9650 driver. + * + */ +#ifndef __OV9650_H__ +#define __OV9650_H__ +#include "sensor.h" +int ov9650_init(sensor_t *sensor); +#endif // __OV9650_H__ diff --git a/src/openmv/src/omv/ov9650_regs.h b/src/openmv/src/omv/ov9650_regs.h new file mode 100755 index 0000000..38eae74 --- /dev/null +++ b/src/openmv/src/omv/ov9650_regs.h @@ -0,0 +1,135 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV9650 register definitions. + */ + +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ + +#define REG_GAIN 0x00 +#define REG_BLUE 0x01 +#define REG_RED 0x02 +#define REG_VREF 0x03 +#define REG_COM1 0x04 +#define REG_BAVE 0x05 +#define REG_GEAVE 0x06 +#define REG_RAVE 0x08 +#define REG_COM2 0x09 +#define REG_PID 0x0A +#define REG_VER 0x0B +#define REG_COM3 0x0C +#define REG_COM4 0x0D +#define REG_COM5 0x0E +#define REG_COM6 0x0F +#define REG_AECH 0x10 +#define REG_CLKRC 0x11 +#define REG_COM7 0x12 +#define REG_COM8 0x13 +#define REG_COM9 0x14 +#define REG_COM10 0x15 +#define REG_RSVD16 0x16 +#define REG_HSTART 0x17 +#define REG_HSTOP 0x18 +#define REG_VSTART 0x19 +#define REG_VSTOP 0x1A +#define REG_PSHFT 0x1B +#define REG_MIDH 0x1C +#define REG_MIDL 0x1D +#define REG_MVFP 0x1E +#define REG_BOS 0x20 +#define REG_GBOS 0x21 +#define REG_GROS 0x22 +#define REG_ROS 0x23 +#define REG_AEW 0x24 +#define REG_AEB 0x25 +#define REG_VPT 0x26 +#define REG_BBIAS 0x27 +#define REG_GbBIAS 0x28 +#define REG_GRCOM 0x29 +#define REG_EXHCH 0x2A +#define REG_EXHCL 0x2B +#define REG_RBIAS 0x2C +#define REG_ADVFL 0x2D +#define REG_ADVFH 0x2E +#define REG_YAVE 0x2F +#define REG_HSYST 0x30 +#define REG_HSYEN 0x31 +#define REG_HREF 0x32 +#define REG_CHLF 0x33 +#define REG_ARBLM 0x34 +#define REG_RSVD35 0x35 +#define REG_RSVD36 0x36 +#define REG_ADC 0x37 +#define REG_ACOM38 0x38 +#define REG_OFON 0x39 +#define REG_TSLB 0x3A +#define REG_COM11 0x3B +#define REG_COM12 0x3C +#define REG_COM13 0x3D +#define REG_COM14 0x3E +#define REG_EDGE 0x3F +#define REG_COM15 0x40 +#define REG_COM16 0x41 +#define REG_COM17 0x42 +#define REG_MTX1 0x4F +#define REG_MTX2 0x50 +#define REG_MTX3 0x51 +#define REG_MTX4 0x52 +#define REG_MTX5 0x53 +#define REG_MTX6 0x54 +#define REG_MTX7 0x55 +#define REG_MTX8 0x56 +#define REG_MTX9 0x57 +#define REG_MTXS 0x58 +#define REG_LCC1 0x62 +#define REG_LCC2 0x63 +#define REG_LCC3 0x64 +#define REG_LCC4 0x65 +#define REG_LCC5 0x66 +#define REG_MANU 0x67 +#define REG_MANV 0x68 +#define REG_HV 0x69 +#define REG_MBD 0x6A +#define REG_DBLV 0x6B +#define REG_COM21 0x8B +#define REG_COM22 0x8C +#define REG_COM23 0x8D +#define REG_COM24 0x8E +#define REG_DBLC1 0x8F +#define REG_DBLC_B 0x90 +#define REG_DBLC_R 0x91 +#define REG_DMLNL 0x92 +#define REG_DMLNH 0x93 +#define REG_LCCFB 0x9D +#define REG_LCCFR 0x9E +#define REG_DBLC_GB 0x9F +#define REG_DBLC_GR 0xA0 +#define REG_AECHM 0xA1 +#define REG_COM25 0xA4 +#define REG_COM26 0xA5 +#define REG_GGAIN 0xA6 +#define REG_VGAST 0xA7 + +/* register bits */ + +#define REG_COM1_QQCIF (1<<5) +#define REG_COM1_QQVGA (1<<5) +#define REG_COM1_SKIP2 (1<<2) +#define REG_COM1_SKIP3 (1<<3) +#define REG_COM7_RGB (1<<2) +#define REG_COM7_QCIF (1<<3) +#define REG_COM7_QVGA (1<<4) +#define REG_COM7_CIF (1<<5) +#define REG_COM7_VGA (1<<6) +#define REG_COM8_AGC (1<<2) +#define REG_COM8_AWB (1<<1) +#define REG_COM8_AEC (1<<0) +#define REG_MVFP_HMIRROR (1<<5) +#define REG_MVFP_VFLIP (1<<4) +#define REG_CLKRC_DOUBLE (1<<8) +#define REG_CLKRC_DIVIDER_MASK (0x3F) + +#endif //__REG_REGS_H__ diff --git a/src/openmv/src/omv/py/mp.h b/src/openmv/src/omv/py/mp.h new file mode 100755 index 0000000..e6b6dd1 --- /dev/null +++ b/src/openmv/src/omv/py/mp.h @@ -0,0 +1,28 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MicroPython header. + * + */ +#ifndef __MP_H__ +#define __MP_H__ +#include +#include +#include "mpconfig.h" +#include "misc.h" +#include "qstr.h" +#include "misc.h" +#include "nlr.h" +#include "lexer.h" +#include "parse.h" +#include "obj.h" +#include "objtuple.h" +#include "runtime.h" +#include "stream.h" +#include "gc.h" +#include "readline.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#endif // __MP_H__ diff --git a/src/openmv/src/omv/py/py_assert.h b/src/openmv/src/omv/py/py_assert.h new file mode 100755 index 0000000..eae85e0 --- /dev/null +++ b/src/openmv/src/omv/py/py_assert.h @@ -0,0 +1,62 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MP assertions. + * + */ +#ifndef __PY_ASSERT_H__ +#define __PY_ASSERT_H__ +#include "mp.h" +#define PY_ASSERT_TRUE(cond) \ + do { \ + if ((cond) == 0) { \ + nlr_jump(mp_obj_new_exception_msg( \ + &mp_type_OSError, \ + "Operation not supported")); \ + } \ + } while(0) + +#define PY_ASSERT_TRUE_MSG(cond, msg) \ + do { \ + if ((cond) == 0) { \ + nlr_jump(mp_obj_new_exception_msg( \ + &mp_type_OSError, msg)); \ + } \ + } while(0) + +#define PY_ASSERT_FALSE_MSG(cond, msg) \ + do { \ + if ((cond) == 1) { \ + nlr_jump(mp_obj_new_exception_msg( \ + &mp_type_OSError, msg)); \ + } \ + } while(0) + +#define PY_ASSERT_TYPE(obj, type) \ + do { \ + __typeof__ (obj) _a = (obj); \ + __typeof__ (type) _b = (type); \ + if (!MP_OBJ_IS_TYPE(_a, _b)) { \ + nlr_jump(mp_obj_new_exception_msg_varg( \ + &mp_type_TypeError, \ + "Can't convert %s to %s", \ + mp_obj_get_type_str(_a), \ + mp_obj_get_type_str(_b))); \ + } \ + } while(0) +/* IS_TYPE doesn't work for str objs */ +#define PY_ASSERT_STR(obj) \ + do { \ + __typeof__ (obj) _a = (obj); \ + if (!MP_OBJ_IS_STR(_a)) { \ + nlr_jump(mp_obj_new_exception_msg_varg( \ + &mp_type_TypeError, \ + "Can't convert %s to %s", \ + mp_obj_get_type_str(_a), \ + str_type.name)); \ + } \ + } while(0) + +#endif // __PY_ASSERT_H__ diff --git a/src/openmv/src/omv/py/py_cpufreq.c b/src/openmv/src/omv/py/py_cpufreq.c new file mode 100755 index 0000000..bb431f3 --- /dev/null +++ b/src/openmv/src/omv/py/py_cpufreq.c @@ -0,0 +1,124 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CPU frequency module. + * + */ + +#include +#include +#include +#include +#include STM32_HAL_H +#include "py_cpufreq.h" + +enum cpufreq_freqs { + CPUFREQ_120MHZ=0, + CPUFREQ_144MHZ=1, + CPUFREQ_168MHZ=2, + CPUFREQ_192MHZ=3, + CPUFREQ_216MHZ=4, + CPUFREQ_MAX +}; + +static const uint32_t cpufreq_pllq[] = {5, 6, 7, 8, 9}; +static const uint32_t cpufreq_freq[] = {120, 144, 168, 192, 216}; +static const uint32_t cpufreq_latency[] = { // Flash latency (see table 11) + FLASH_LATENCY_3, FLASH_LATENCY_4, FLASH_LATENCY_5, FLASH_LATENCY_7, FLASH_LATENCY_7 +}; + +void py_cpufreq_init0() +{ + +} + +mp_obj_t py_cpufreq_get_frequency() +{ + mp_obj_t tuple[4] = { + mp_obj_new_int(HAL_RCC_GetSysClockFreq()), + mp_obj_new_int(HAL_RCC_GetHCLKFreq()), + mp_obj_new_int(HAL_RCC_GetPCLK1Freq()), + mp_obj_new_int(HAL_RCC_GetPCLK2Freq()), + }; + return mp_obj_new_tuple(4, tuple); +} + +mp_obj_t py_cpufreq_set_frequency(mp_obj_t cpufreq_idx_obj) +{ + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_OscInitTypeDef RCC_OscInitStruct; + + // Check CPU frequency index range + uint32_t cpufreq_idx = mp_obj_get_int(cpufreq_idx_obj); + if (cpufreq_idx < 0 || cpufreq_idx >= CPUFREQ_MAX) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported frequency!")); + } + + // Return if frequency hasn't changed + if (cpufreq_freq[cpufreq_idx] == (HAL_RCC_GetSysClockFreq()/1000000)) { + return mp_const_true; + } + + // Select HSE as system clock source + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | + RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; + // Configure the HCLK, PCLK1 and PCLK2 clocks dividers + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK) { + // Initialization Error + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "RCC CLK Initialization Error!!")); + } + + // Enable HSE Oscillator and activate PLL with HSE as source + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 12; // depends on HSE + RCC_OscInitStruct.PLL.PLLN = cpufreq_freq[cpufreq_idx] * 2; + RCC_OscInitStruct.PLL.PLLP = 2; + RCC_OscInitStruct.PLL.PLLQ = cpufreq_pllq[cpufreq_idx]; + + if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + // Initialization Error + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "RCC OSC Initialization Error!!")); + } + + // Select PLL as system clock source + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, cpufreq_latency[cpufreq_idx]) != HAL_OK) { + // Initialization Error + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "RCC CLK Initialization Error!!")); + } + + // Do a soft-reset ? + //nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Frequency is set!")); + return mp_const_true; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_cpufreq_get_frequency_obj, py_cpufreq_get_frequency); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_cpufreq_set_frequency_obj, py_cpufreq_set_frequency); + +static const mp_map_elem_t globals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_cpufreq) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CPUFREQ_120MHZ), MP_OBJ_NEW_SMALL_INT(CPUFREQ_120MHZ) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CPUFREQ_144MHZ), MP_OBJ_NEW_SMALL_INT(CPUFREQ_144MHZ) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CPUFREQ_168MHZ), MP_OBJ_NEW_SMALL_INT(CPUFREQ_168MHZ) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CPUFREQ_192MHZ), MP_OBJ_NEW_SMALL_INT(CPUFREQ_192MHZ) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CPUFREQ_216MHZ), MP_OBJ_NEW_SMALL_INT(CPUFREQ_216MHZ) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_frequency), (mp_obj_t)&py_cpufreq_get_frequency_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_frequency), (mp_obj_t)&py_cpufreq_set_frequency_obj }, + { NULL, NULL }, +}; +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t cpufreq_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_cpufreq.h b/src/openmv/src/omv/py/py_cpufreq.h new file mode 100755 index 0000000..3711b36 --- /dev/null +++ b/src/openmv/src/omv/py/py_cpufreq.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CPU Frequency module. + * + */ +#ifndef __PY_CPUFREQ_H__ +#define __PY_CPUFREQ_H__ +void py_cpufreq_init0(); +#endif // __PY_CPUFREQ_H__ diff --git a/src/openmv/src/omv/py/py_fir.h b/src/openmv/src/omv/py/py_fir.h new file mode 100755 index 0000000..00dec0f --- /dev/null +++ b/src/openmv/src/omv/py/py_fir.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MLX Python module. + * + */ +#ifndef __PY_FIR_H__ +#define __PY_FIR_H__ +void py_fir_init0(); +#endif // __PY_FIR_H__ diff --git a/src/openmv/src/omv/py/py_gif.c b/src/openmv/src/omv/py/py_gif.c new file mode 100755 index 0000000..9215fca --- /dev/null +++ b/src/openmv/src/omv/py/py_gif.c @@ -0,0 +1,145 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * GIF Python module. + * + */ +#include "mp.h" +#include "ff_wrapper.h" +#include "framebuffer.h" +#include "sensor.h" +#include "py_assert.h" +#include "py_helper.h" +#include "py_image.h" + +static const mp_obj_type_t py_gif_type; // forward declare +// Gif class +typedef struct py_gif_obj { + mp_obj_base_t base; + int width; + int height; + bool color; + bool loop; + FIL fp; +} py_gif_obj_t; + +static mp_obj_t py_gif_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + py_gif_obj_t *gif = m_new_obj(py_gif_obj_t); + gif->width = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); + gif->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); + gif->color = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MAIN_FB()->bpp>=2); + gif->loop = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true); + gif->base.type = &py_gif_type; + + file_write_open(&gif->fp, mp_obj_str_get_str(args[0])); + gif_open(&gif->fp, gif->width, gif->height, gif->color, gif->loop); + return gif; +} + +static mp_obj_t py_gif_width(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + return mp_obj_new_int(arg_gif->width); +} + +static mp_obj_t py_gif_height(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + return mp_obj_new_int(arg_gif->height); +} +typedef enum { + PIXFORMAT_INVLAID = 0, + PIXFORMAT_BAYER, // 1BPP/RAW + PIXFORMAT_RGB565, // 2BPP/RGB565 + PIXFORMAT_YUV422, // 2BPP/YUV422 + PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE + PIXFORMAT_JPEG, // JPEG/COMPRESSED +} pixformat_t; + +static mp_obj_t py_gif_format(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + return mp_obj_new_int(arg_gif->color ? PIXFORMAT_RGB565 : PIXFORMAT_GRAYSCALE); +} + +static mp_obj_t py_gif_size(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + return mp_obj_new_int(file_size_w_buf(&arg_gif->fp)); +} + +static mp_obj_t py_gif_loop(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + return mp_obj_new_int(arg_gif->loop); +} + +static mp_obj_t py_gif_add_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + py_gif_obj_t *arg_gif = args[0]; + image_t *arg_img = py_image_cobj(args[1]); + PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img), "Operation not supported on JPEG images."); + PY_ASSERT_FALSE_MSG(IM_IS_BINARY(arg_img), "Operation not supported on binary images."); + PY_ASSERT_FALSE_MSG((arg_gif->width != arg_img->w) || + (arg_gif->height != arg_img->h), "Unexpected image geometry!"); + + int delay = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_delay), 10); + + gif_add_frame(&arg_gif->fp, arg_img, delay); + return mp_const_none; +} + +static mp_obj_t py_gif_close(mp_obj_t gif_obj) +{ + py_gif_obj_t *arg_gif = gif_obj; + gif_close(&arg_gif->fp); + return mp_const_none; +} + +static void py_gif_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_gif_obj_t *self = self_in; + mp_printf(print, "", self->width, self->height, self->color, self->loop); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_width_obj, py_gif_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_height_obj, py_gif_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_format_obj, py_gif_format); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_size_obj, py_gif_size); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_loop_obj, py_gif_loop); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_add_frame_obj, 2, py_gif_add_frame); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_close_obj, py_gif_close); +static const mp_map_elem_t locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_gif_width_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_gif_height_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&py_gif_format_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&py_gif_size_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_loop), (mp_obj_t)&py_gif_loop_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_add_frame), (mp_obj_t)&py_gif_add_frame_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&py_gif_close_obj }, + { NULL, NULL }, +}; +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +static const mp_obj_type_t py_gif_type = { + { &mp_type_type }, + .name = MP_QSTR_Gif, + .print = py_gif_print, + .locals_dict = (mp_obj_t)&locals_dict, +}; + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_open_obj, 1, py_gif_open); +static const mp_map_elem_t globals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gif) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Gif), (mp_obj_t)&py_gif_open_obj }, + { NULL, NULL }, +}; +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t gif_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_helper.c b/src/openmv/src/omv/py/py_helper.c new file mode 100755 index 0000000..ea21d99 --- /dev/null +++ b/src/openmv/src/omv/py/py_helper.c @@ -0,0 +1,306 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include "py_helper.h" + +extern void *py_image_cobj(mp_obj_t img_obj); + +mp_obj_t py_func_unavailable(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + PY_ASSERT_TRUE_MSG(false, "This function is unavailable on your OpenMV Cam."); + return args[0]; +} +MP_DEFINE_CONST_FUN_OBJ_KW(py_func_unavailable_obj, 1, py_func_unavailable); + +image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE(arg_img), "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE_BAYER(arg_img), "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(arg_img->bpp == IMAGE_BPP_GRAYSCALE, "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_color(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(arg_img->bpp == IMAGE_BPP_RGB565, "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, image_t *default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + default_val = py_helper_arg_to_image_mutable(kw_arg->value); + } else if (n_args > arg_index) { + default_val = py_helper_arg_to_image_mutable(args[arg_index]); + } + + return default_val; +} + +image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args) +{ + return py_helper_keyword_to_image_mutable(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); +} + +void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + mp_obj_t *arg_rectangle; + mp_obj_get_array_fixed_n(kw_arg->value, 4, &arg_rectangle); + r->x = mp_obj_get_int(arg_rectangle[0]); + r->y = mp_obj_get_int(arg_rectangle[1]); + r->w = mp_obj_get_int(arg_rectangle[2]); + r->h = mp_obj_get_int(arg_rectangle[3]); + } else if (n_args > arg_index) { + mp_obj_t *arg_rectangle; + mp_obj_get_array_fixed_n(args[arg_index], 4, &arg_rectangle); + r->x = mp_obj_get_int(arg_rectangle[0]); + r->y = mp_obj_get_int(arg_rectangle[1]); + r->w = mp_obj_get_int(arg_rectangle[2]); + r->h = mp_obj_get_int(arg_rectangle[3]); + } else { + r->x = 0; + r->y = 0; + r->w = img->w; + r->h = img->h; + } + + PY_ASSERT_TRUE_MSG((r->w >= 1) && (r->h >= 1), "Invalid ROI dimensions!"); + rectangle_t temp; + temp.x = 0; + temp.y = 0; + temp.w = img->w; + temp.h = img->h; + + PY_ASSERT_TRUE_MSG(rectangle_overlap(r, &temp), "ROI does not overlap on the image!"); + rectangle_intersected(r, &temp); +} + +void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, rectangle_t *r) +{ + py_helper_keyword_rectangle(img, n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_roi), r); +} + +int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + default_val = mp_obj_get_int(kw_arg->value); + } else if (n_args > arg_index) { + default_val = mp_obj_get_int(args[arg_index]); + } + + return default_val; +} + +float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + default_val = mp_obj_get_float(kw_arg->value); + } else if (n_args > arg_index) { + default_val = mp_obj_get_float(args[arg_index]); + } + + return default_val; +} + +void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int *x, int size) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]); + } else if (n_args > arg_index) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]); + } +} + +void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float *x, int size) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]); + } else if (n_args > arg_index) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]); + } +} + +uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items) +{ + if (MP_OBJ_IS_TYPE(args[arg_index], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[arg_index], &mp_type_list)) { + mp_obj_get_array_fixed_n(args[arg_index], len, (mp_obj_t **) items); + return arg_index + 1; + } else { + PY_ASSERT_TRUE_MSG((n_args - arg_index) >= len, "Not enough positional arguments!"); + *items = args + arg_index; + return arg_index + len; + } +} + +int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, int default_val) +{ + mp_map_elem_t *kw_arg = kw_args ? mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP) : NULL; + + if (kw_arg) { + if (mp_obj_is_integer(kw_arg->value)) { + default_val = mp_obj_get_int(kw_arg->value); + } else { + mp_obj_t *arg_color; + mp_obj_get_array_fixed_n(kw_arg->value, 3, &arg_color); + default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN), + IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN), + IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN)); + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + default_val = COLOR_RGB565_TO_BINARY(default_val); + break; + } + case IMAGE_BPP_GRAYSCALE: { + default_val = COLOR_RGB565_TO_GRAYSCALE(default_val); + break; + } + default: { + break; + } + } + } + } else if (n_args > arg_index) { + if (mp_obj_is_integer(args[arg_index])) { + default_val = mp_obj_get_int(args[arg_index]); + } else { + mp_obj_t *arg_color; + mp_obj_get_array_fixed_n(args[arg_index], 3, &arg_color); + default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN), + IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN), + IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN)); + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + default_val = COLOR_RGB565_TO_BINARY(default_val); + break; + } + case IMAGE_BPP_GRAYSCALE: { + default_val = COLOR_RGB565_TO_GRAYSCALE(default_val); + break; + } + default: { + break; + } + } + } + } + + return default_val; +} + +void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds) +{ + mp_uint_t arg_thresholds_len; + mp_obj_t *arg_thresholds; + mp_obj_get_array(arg, &arg_thresholds_len, &arg_thresholds); + if (!arg_thresholds_len) return; + for(mp_uint_t i = 0; i < arg_thresholds_len; i++) { + mp_uint_t arg_threshold_len; + mp_obj_t *arg_threshold; + mp_obj_get_array(arg_thresholds[i], &arg_threshold_len, &arg_threshold); + if (arg_threshold_len) { + color_thresholds_list_lnk_data_t lnk_data; + lnk_data.LMin = (arg_threshold_len > 0) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[0]), + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : + IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN); + lnk_data.LMax = (arg_threshold_len > 1) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[1]), + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX); + lnk_data.AMin = (arg_threshold_len > 2) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[2]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MIN; + lnk_data.AMax = (arg_threshold_len > 3) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[3]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MAX; + lnk_data.BMin = (arg_threshold_len > 4) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[4]), COLOR_B_MAX), COLOR_B_MIN) : COLOR_B_MIN; + lnk_data.BMax = (arg_threshold_len > 5) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[5]), COLOR_B_MAX), COLOR_B_MIN) : COLOR_B_MAX; + color_thresholds_list_lnk_data_t lnk_data_tmp; + memcpy(&lnk_data_tmp, &lnk_data, sizeof(color_thresholds_list_lnk_data_t)); + lnk_data.LMin = IM_MIN(lnk_data_tmp.LMin, lnk_data_tmp.LMax); + lnk_data.LMax = IM_MAX(lnk_data_tmp.LMin, lnk_data_tmp.LMax); + lnk_data.AMin = IM_MIN(lnk_data_tmp.AMin, lnk_data_tmp.AMax); + lnk_data.AMax = IM_MAX(lnk_data_tmp.AMin, lnk_data_tmp.AMax); + lnk_data.BMin = IM_MIN(lnk_data_tmp.BMin, lnk_data_tmp.BMax); + lnk_data.BMax = IM_MAX(lnk_data_tmp.BMin, lnk_data_tmp.BMax); + list_push_back(thresholds, &lnk_data); + } + } +} + +void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, list_t *thresholds) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thresholds), MP_MAP_LOOKUP); + + if (kw_arg) { + py_helper_arg_to_thresholds(kw_arg->value, thresholds); + } else if (n_args > arg_index) { + py_helper_arg_to_thresholds(args[arg_index], thresholds); + } +} + +int py_helper_arg_to_ksize(const mp_obj_t arg) +{ + int ksize = mp_obj_get_int(arg); + PY_ASSERT_TRUE_MSG(ksize >= 0, "KernelSize must be >= 0!"); + return ksize; +} + +int py_helper_ksize_to_n(int ksize) +{ + return ((ksize * 2) + 1) * ((ksize * 2) + 1); +} + +mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args, uint arg_index, mp_map_t *kw_args, mp_obj_t kw) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + return kw_arg->value; + } else if (n_args > arg_index) { + return args[arg_index]; + } else { + return NULL; + } +} diff --git a/src/openmv/src/omv/py/py_helper.h b/src/openmv/src/omv/py/py_helper.h new file mode 100755 index 0000000..c113176 --- /dev/null +++ b/src/openmv/src/omv/py/py_helper.h @@ -0,0 +1,40 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#ifndef __PY_HELPER_H__ +#define __PY_HELPER_H__ +#include "imlib.h" +#include "py_assert.h" +extern const mp_obj_fun_builtin_var_t py_func_unavailable_obj; +image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg); +image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg); +image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg); +image_t *py_helper_arg_to_image_color(const mp_obj_t arg); +image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, image_t *default_val); +image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args); +void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r); +void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, rectangle_t *r); +int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int default_val); +float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float default_val); +void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int *x, int size); +void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float *x, int size); +uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items); +int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, int default_val); +void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds); +void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, list_t *thresholds); +int py_helper_arg_to_ksize(const mp_obj_t arg); +int py_helper_ksize_to_n(int ksize); +mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args, uint arg_index, mp_map_t *kw_args, mp_obj_t kw); +#endif // __PY_HELPER__ diff --git a/src/openmv/src/omv/py/py_image.c b/src/openmv/src/omv/py/py_image.c new file mode 100755 index 0000000..9bc5ec3 --- /dev/null +++ b/src/openmv/src/omv/py/py_image.c @@ -0,0 +1,6184 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Image Python module. + * + */ + +#include +#include "imlib.h" +#include "array.h" +#include "sensor.h" +#include "ff_wrapper.h" +#include "xalloc.h" +#include "fb_alloc.h" +#include "framebuffer.h" +#include "py_assert.h" +#include "py_helper.h" +#include "py_image.h" +#include "omv_boardconfig.h" +#include "py/runtime0.h" +#include "py/runtime.h" + +static const mp_obj_type_t py_cascade_type; +static const mp_obj_type_t py_image_type; + +//extern const char *ffs_strerror(FRESULT res); + +/*hutu*/ +static char *ffs_strerr(FRESULT res) +{ + static const char *ffs_errors[]={ + "Succeeded", + "A hard error occurred in the low level disk I/O layer", + "Assertion failed", + "The physical drive cannot work", + "Could not find the file", + "Could not find the path", + "The path name format is invalid", + "Access denied due to prohibited access or directory full", + "Access denied due to prohibited access", + "The file/directory object is invalid", + "The physical drive is write protected", + "The logical drive number is invalid", + "The volume has no work area", + "There is no valid FAT volume", + "The f_mkfs() aborted due to any parameter error", + "Could not get a grant to access the volume within defined period", + "The operation is rejected according to the file sharing policy", + "LFN working buffer could not be allocated", + "Number of open files > _FS_SHARE", + "Given parameter is invalid", + }; + + if (res>sizeof(ffs_errors)/sizeof(ffs_errors[0])) { + return "unknown error"; + } else { + return ffs_errors[res]; + } +} + + +// Haar Cascade /////////////////////////////////////////////////////////////// + +typedef struct _py_cascade_obj_t { + mp_obj_base_t base; + struct cascade _cobj; +} py_cascade_obj_t; + +void *py_cascade_cobj(mp_obj_t cascade) +{ + PY_ASSERT_TYPE(cascade, &py_cascade_type); + return &((py_cascade_obj_t *)cascade)->_cobj; +} + +static void py_cascade_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_cascade_obj_t *self = self_in; + mp_printf(print, "{\"width\":%d, \"height\":%d, \"n_stages\":%d, \"n_features\":%d, \"n_rectangles\":%d}", + self->_cobj.window.w, self->_cobj.window.h, self->_cobj.n_stages, + self->_cobj.n_features, self->_cobj.n_rectangles); +} + +static const mp_obj_type_t py_cascade_type = { + { &mp_type_type }, + .name = MP_QSTR_Cascade, + .print = py_cascade_print, +}; + +// Keypoints object /////////////////////////////////////////////////////////// + +typedef struct _py_kp_obj_t { + mp_obj_base_t base; + array_t *kpts; + int threshold; + bool normalized; +} py_kp_obj_t; + +static void py_kp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kp_obj_t *self = self_in; + mp_printf(print, "{\"size\":%d, \"threshold\":%d, \"normalized\":%d}", array_length(self->kpts), self->threshold, self->normalized); +} + +mp_obj_t py_kp_unary_op(mp_uint_t op, mp_obj_t self_in) { + py_kp_obj_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(array_length(self->kpts)); + + default: + return MP_OBJ_NULL; // op not supported + } +} + +static mp_obj_t py_kp_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_kp_obj_t *self = self_in; + int size = array_length(self->kpts); + int i = mp_get_index(self->base.type, size, index, false); + kp_t *kp = array_at(self->kpts, i); + return mp_obj_new_tuple(5, (mp_obj_t []) {mp_obj_new_int(kp->x), + mp_obj_new_int(kp->y), + mp_obj_new_int(kp->score), + mp_obj_new_int(kp->octave), + mp_obj_new_int(kp->angle)}); + } + + return MP_OBJ_NULL; // op not supported +} + +static const mp_obj_type_t py_kp_type = { + { &mp_type_type }, + .name = MP_QSTR_kp_desc, + .print = py_kp_print, + .subscr = py_kp_subscr, + .unary_op = py_kp_unary_op, +}; + +py_kp_obj_t *py_kpts_obj(mp_obj_t kpts_obj) +{ + PY_ASSERT_TYPE(kpts_obj, &py_kp_type); + return kpts_obj; +} + +// LBP descriptor ///////////////////////////////////////////////////////////// + +typedef struct _py_lbp_obj_t { + mp_obj_base_t base; + uint8_t *hist; +} py_lbp_obj_t; + +static void py_lbp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + mp_printf(print, "{}"); +} + +static const mp_obj_type_t py_lbp_type = { + { &mp_type_type }, + .name = MP_QSTR_lbp_desc, + .print = py_lbp_print, +}; + +// Keypoints match object ///////////////////////////////////////////////////// +#define kptmatch_obj_size 9 +typedef struct _py_kptmatch_obj_t { + mp_obj_base_t base; + mp_obj_t cx, cy; + mp_obj_t x, y, w, h; + mp_obj_t count; + mp_obj_t theta; + mp_obj_t match; +} py_kptmatch_obj_t; + +static void py_kptmatch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kptmatch_obj_t *self = self_in; + mp_printf(print, "{\"cx\":%d, \"cy\":%d, \"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"count\":%d, \"theta\":%d}", + mp_obj_get_int(self->cx), mp_obj_get_int(self->cy), mp_obj_get_int(self->x), mp_obj_get_int(self->y), + mp_obj_get_int(self->w), mp_obj_get_int(self->h), mp_obj_get_int(self->count), mp_obj_get_int(self->theta)); +} + +static mp_obj_t py_kptmatch_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_kptmatch_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(kptmatch_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, kptmatch_obj_size, index, false)) { + case 0: return self->cx; + case 1: return self->cy; + case 2: return self->x; + case 3: return self->y; + case 4: return self->w; + case 5: return self->h; + case 6: return self->count; + case 7: return self->theta; + case 8: return self->match; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_kptmatch_cx(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->cx; } +mp_obj_t py_kptmatch_cy(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->cy; } +mp_obj_t py_kptmatch_x (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->x; } +mp_obj_t py_kptmatch_y (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->y; } +mp_obj_t py_kptmatch_w (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->w; } +mp_obj_t py_kptmatch_h (mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->h; } +mp_obj_t py_kptmatch_count(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->count; } +mp_obj_t py_kptmatch_theta(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->theta; } +mp_obj_t py_kptmatch_match(mp_obj_t self_in) { return ((py_kptmatch_obj_t *) self_in)->match; } +mp_obj_t py_kptmatch_rect(mp_obj_t self_in) { + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_kptmatch_obj_t *) self_in)->x, + ((py_kptmatch_obj_t *) self_in)->y, + ((py_kptmatch_obj_t *) self_in)->w, + ((py_kptmatch_obj_t *) self_in)->h}); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_cx_obj, py_kptmatch_cx); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_cy_obj, py_kptmatch_cy); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_x_obj, py_kptmatch_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_y_obj, py_kptmatch_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_w_obj, py_kptmatch_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_h_obj, py_kptmatch_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_count_obj, py_kptmatch_count); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_theta_obj, py_kptmatch_theta); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_match_obj, py_kptmatch_match); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kptmatch_rect_obj, py_kptmatch_rect); + +STATIC const mp_rom_map_elem_t py_kptmatch_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_cx), MP_ROM_PTR(&py_kptmatch_cx_obj) }, + { MP_ROM_QSTR(MP_QSTR_cy), MP_ROM_PTR(&py_kptmatch_cy_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_kptmatch_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_kptmatch_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_kptmatch_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_kptmatch_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&py_kptmatch_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_theta), MP_ROM_PTR(&py_kptmatch_theta_obj) }, + { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&py_kptmatch_match_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_kptmatch_rect_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_kptmatch_locals_dict, py_kptmatch_locals_dict_table); + +static const mp_obj_type_t py_kptmatch_type = { + { &mp_type_type }, + .name = MP_QSTR_kptmatch, + .print = py_kptmatch_print, + .subscr = py_kptmatch_subscr, + .locals_dict = (mp_obj_t) &py_kptmatch_locals_dict +}; + +// Image ////////////////////////////////////////////////////////////////////// + +typedef struct _py_image_obj_t { + mp_obj_base_t base; + image_t _cobj; +} py_image_obj_t; + +void *py_image_cobj(mp_obj_t img_obj) +{ + PY_ASSERT_TYPE(img_obj, &py_image_type); + return &((py_image_obj_t *)img_obj)->_cobj; +} + +static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_image_obj_t *self = self_in; + switch(self->_cobj.bpp) { + case IMAGE_BPP_BINARY: { + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"binary\", \"size\":%d}", + self->_cobj.w, self->_cobj.h, + ((self->_cobj.w + UINT32_T_MASK) >> UINT32_T_SHIFT) * self->_cobj.h); + break; + } + case IMAGE_BPP_GRAYSCALE: { + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"grayscale\", \"size\":%d}", + self->_cobj.w, self->_cobj.h, + (self->_cobj.w * self->_cobj.h) * sizeof(uint8_t)); + break; + } + case IMAGE_BPP_RGB565: { + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"rgb565\", \"size\":%d}", + self->_cobj.w, self->_cobj.h, + (self->_cobj.w * self->_cobj.h) * sizeof(uint16_t)); + break; + } + default: { + if((self->_cobj.data[0] == 0xFE) && (self->_cobj.data[self->_cobj.bpp-1] == 0xFE)) { // for ide + print->print_strn(print->data, (const char *) self->_cobj.data, self->_cobj.bpp); + } else { // not for ide + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"jpeg\", \"size\":%d}", + self->_cobj.w, self->_cobj.h, + self->_cobj.bpp); + } + break; + } + } +} + +static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + py_image_obj_t *self = self_in; + if (value == MP_OBJ_NULL) { // delete + } else if (value == MP_OBJ_SENTINEL) { // load + switch (self->_cobj.bpp) { + case IMAGE_BPP_BINARY: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + result->items[i] = mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w)); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w)); + } + case IMAGE_BPP_BAYER: + case IMAGE_BPP_GRAYSCALE: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w); + result->items[i] = mp_obj_new_int(p); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + uint8_t p = IMAGE_GET_GRAYSCALE_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w); + return mp_obj_new_int(p); + } + case IMAGE_BPP_RGB565: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + uint16_t p = IMAGE_GET_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w); + result->items[i] = mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)), + mp_obj_new_int(COLOR_RGB565_TO_G8(p)), + mp_obj_new_int(COLOR_RGB565_TO_B8(p))}); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + uint16_t p = IMAGE_GET_RGB565_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w); + return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_int(COLOR_RGB565_TO_R8(p)), + mp_obj_new_int(COLOR_RGB565_TO_G8(p)), + mp_obj_new_int(COLOR_RGB565_TO_B8(p))}); + } + default: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.bpp, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + result->items[i] = mp_obj_new_int(self->_cobj.data[slice.start + i]); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.bpp, index, false); + return mp_obj_new_int(self->_cobj.data[i]); + } + } + } else { // store + switch (self->_cobj.bpp) { + case IMAGE_BPP_BINARY: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, mp_obj_get_int(value_l[i])); + } + } else { + mp_int_t v = mp_obj_get_int(value); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, v); + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + IMAGE_PUT_BINARY_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, mp_obj_get_int(value)); + return mp_const_none; + } + case IMAGE_BPP_BAYER: + case IMAGE_BPP_GRAYSCALE: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + uint8_t p = mp_obj_get_int(value_l[i]); + IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p); + } + } else { + uint8_t p = mp_obj_get_int(value); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p); + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + uint8_t p = mp_obj_get_int(value); + IMAGE_PUT_GRAYSCALE_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, p); + return mp_const_none; + } + case IMAGE_BPP_RGB565: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.w * self->_cobj.h, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + mp_obj_t *value_2; + mp_obj_get_array_fixed_n(value_l[i], 3, &value_2); + uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2])); + IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p); + } + } else { + mp_obj_t *value_2; + mp_obj_get_array_fixed_n(value, 3, &value_2); + uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2])); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), (slice.start + i) % self->_cobj.w, (slice.start + i) / self->_cobj.w, p); + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.w * self->_cobj.h, index, false); + mp_obj_t *value_2; + mp_obj_get_array_fixed_n(value, 3, &value_2); + uint16_t p = COLOR_R8_G8_B8_TO_RGB565(mp_obj_get_int(value_2[0]), mp_obj_get_int(value_2[1]), mp_obj_get_int(value_2[2])); + IMAGE_PUT_RGB565_PIXEL(&(self->_cobj), i % self->_cobj.w, i / self->_cobj.w, p); + return mp_const_none; + } + default: { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->_cobj.bpp, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + self->_cobj.data[slice.start + i] = mp_obj_get_int(value_l[i]); + } + } else { + mp_int_t v = mp_obj_get_int(value); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + self->_cobj.data[slice.start + i] = v; + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->_cobj.bpp, index, false); + self->_cobj.data[i] = mp_obj_get_int(value); + return mp_const_none; + } + } + } + return MP_OBJ_NULL; // op not supported +} + +static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) +{ + py_image_obj_t *self = self_in; + if (flags == MP_BUFFER_READ) { + bufinfo->buf = self->_cobj.data; + bufinfo->len = image_size(&self->_cobj); + bufinfo->typecode = 'b'; + return 0; + } else { // Can't write to an image! + bufinfo->buf = NULL; + bufinfo->len = 0; + bufinfo->typecode = -1; + return 1; + } +} + +//////////////// +// Basic Methods +//////////////// + +static mp_obj_t py_image_width(mp_obj_t img_obj) +{ + return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->w); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width); + +static mp_obj_t py_image_height(mp_obj_t img_obj) +{ + return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->h); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height); + + +typedef enum { + PIXFORMAT_INVLAID = 0, + PIXFORMAT_BAYER, // 1BPP/RAW + PIXFORMAT_RGB565, // 2BPP/RGB565 + PIXFORMAT_YUV422, // 2BPP/YUV422 + PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE + PIXFORMAT_JPEG, // JPEG/COMPRESSED +} pixformat_t; + +static mp_obj_t py_image_format(mp_obj_t img_obj) +{ + switch (((image_t *) py_image_cobj(img_obj))->bpp) { + case IMAGE_BPP_BINARY: return mp_const_none; // TODO: FIXME! + case IMAGE_BPP_GRAYSCALE: return mp_obj_new_int(PIXFORMAT_GRAYSCALE); + case IMAGE_BPP_RGB565: return mp_obj_new_int(PIXFORMAT_RGB565); + case IMAGE_BPP_BAYER: return mp_obj_new_int(PIXFORMAT_BAYER); + default: return mp_obj_new_int(PIXFORMAT_JPEG); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format); + +static mp_obj_t py_image_size(mp_obj_t img_obj) +{ + return mp_obj_new_int(image_size((image_t *) py_image_cobj(img_obj))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size); + +STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + bool arg_rgbtuple = + py_helper_keyword_int(n_args, args, offset, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgbtuple), arg_img->bpp == IMAGE_BPP_RGB565); + + if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { + return mp_const_none; + } + + switch (arg_img->bpp) { + case IMAGE_BPP_BINARY: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_BINARY_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_BINARY_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_BINARY_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_GRAYSCALE: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_RGB565: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_R5_TO_R8(COLOR_RGB565_TO_R5(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_G6_TO_G8(COLOR_RGB565_TO_G6(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_B5_TO_B8(COLOR_RGB565_TO_B5(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_BAYER: + if (arg_rgbtuple) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y); // Correct! + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); // Correct! + } + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_pixel_obj, 2, py_image_get_pixel); + +STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. + + if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { + return args[0]; + } + + switch (arg_img->bpp) { + case IMAGE_BPP_BINARY: { + IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_GRAYSCALE: { + IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_RGB565: { + IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_BAYER: { + IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); // Correct! + return args[0]; + } + default: return args[0]; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_set_pixel_obj, 2, py_image_set_pixel); + +static mp_obj_t py_image_mean_pool(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); + + int x_div = mp_obj_get_int(x_div_obj); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(y_div_obj); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = arg_img->pixels; + + imlib_mean_pool(arg_img, &out_img, x_div, y_div); + arg_img->w = out_img.w; + arg_img->h = out_img.h; + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->w = out_img.w; + MAIN_FB()->h = out_img.h; + } + + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pool_obj, py_image_mean_pool); + +static mp_obj_t py_image_mean_pooled(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); + + int x_div = mp_obj_get_int(x_div_obj); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(y_div_obj); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = xalloc(image_size(&out_img)); + + imlib_mean_pool(arg_img, &out_img, x_div, y_div); + return py_image_from_struct(&out_img); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pooled_obj, py_image_mean_pooled); + +static mp_obj_t py_image_midpoint_pool(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + int x_div = mp_obj_get_int(args[1]); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(args[2]); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + int bias = IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256, 256), 0); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = arg_img->pixels; + + imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, bias); + arg_img->w = out_img.w; + arg_img->h = out_img.h; + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->w = out_img.w; + MAIN_FB()->h = out_img.h; + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pool_obj, 3, py_image_midpoint_pool); + +static mp_obj_t py_image_midpoint_pooled(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + int x_div = mp_obj_get_int(args[1]); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(args[2]); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + int bias = IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256, 256), 0); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = xalloc(image_size(&out_img)); + + imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, bias); + return py_image_from_struct(&out_img); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midpoint_pooled); + +static mp_obj_t py_image_to_bitmap(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false); + + image_t out; + out.w = arg_img->w; + out.h = arg_img->h; + out.bpp = IMAGE_BPP_BINARY; + out.data = copy ? xalloc(image_size(&out)) : arg_img->data; + + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + if (copy) memcpy(out.data, arg_img->data, image_size(&out)); + break; + } + case IMAGE_BPP_GRAYSCALE: { + PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint8_t))) || copy, + "Can't convert to bitmap in place!"); + fb_alloc_mark(); + uint32_t *out_lin_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out)); + for (int y = 0, yy = out.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_BINARY_PIXEL_FAST(out_lin_ptr, x, + COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x))); + } + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y), + out_lin_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out)); + } + fb_free(); + fb_alloc_free_till_mark(); + break; + } + case IMAGE_BPP_RGB565: { + PY_ASSERT_TRUE_MSG((out.w >= (sizeof(uint32_t)/sizeof(uint16_t))) || copy, + "Can't convert to bitmap in place!"); + fb_alloc_mark(); + uint32_t *out_lin_ptr = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(&out)); + for (int y = 0, yy = out.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_BINARY_PIXEL_FAST(out_lin_ptr, x, + COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))); + } + memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&out, y), + out_lin_ptr, IMAGE_BINARY_LINE_LEN_BYTES(&out)); + } + fb_free(); + fb_alloc_free_till_mark(); + break; + } + default: { + break; + } + } + + if ((!copy) && (MAIN_FB()->pixels == out.data)) { + MAIN_FB()->bpp = out.bpp; + } + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_bitmap_obj, 1, py_image_to_bitmap); + +static mp_obj_t py_image_to_grayscale(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false); + + image_t out; + out.w = arg_img->w; + out.h = arg_img->h; + out.bpp = IMAGE_BPP_GRAYSCALE; + out.data = copy ? xalloc(image_size(&out)) : arg_img->data; + + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + PY_ASSERT_TRUE_MSG((out.w == 1) || copy, + "Can't convert to grayscale in place!"); + for (int y = 0, yy = out.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y); + uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, + COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x))); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + if (copy) memcpy(out.data, arg_img->data, image_size(&out)); + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = out.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y); + uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, + COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))); + } + } + break; + } + default: { + break; + } + } + + if ((!copy) && (MAIN_FB()->pixels == out.data)) { + MAIN_FB()->bpp = out.bpp; + } + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_grayscale_obj, 1, py_image_to_grayscale); + +static mp_obj_t py_image_to_rgb565(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false); + + image_t out; + out.w = arg_img->w; + out.h = arg_img->h; + out.bpp = IMAGE_BPP_RGB565; + out.data = copy ? xalloc(image_size(&out)) : arg_img->data; + + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + PY_ASSERT_TRUE_MSG((out.w == 1) || copy, + "Can't convert to grayscale in place!"); + for (int y = 0, yy = out.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + imlib_yuv_to_rgb(IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX, 0, 0)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + PY_ASSERT_TRUE_MSG(copy, + "Can't convert to rgb565 in place!"); + for (int y = 0, yy = out.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + imlib_yuv_to_rgb(IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x), 0, 0)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + if (copy) memcpy(out.data, arg_img->data, image_size(&out)); + break; + } + default: { + break; + } + } + + if ((!copy) && (MAIN_FB()->pixels == out.data)) { + MAIN_FB()->bpp = out.bpp; + } + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rgb565_obj, 1, py_image_to_rgb565); + +extern const uint16_t rainbow_table[256]; + +static mp_obj_t py_image_to_rainbow(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + bool copy = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false); + + image_t out; + out.w = arg_img->w; + out.h = arg_img->h; + out.bpp = IMAGE_BPP_RGB565; + out.data = copy ? xalloc(image_size(&out)) : arg_img->data; + + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + PY_ASSERT_TRUE_MSG((out.w == 1) || copy, + "Can't convert to rainbow in place!"); + for (int y = 0, yy = out.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + rainbow_table[IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) * COLOR_GRAYSCALE_MAX]); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + PY_ASSERT_TRUE_MSG(copy, + "Can't convert to rainbow in place!"); + for (int y = 0, yy = out.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + rainbow_table[IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)]); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = out.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y); + uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&out, y); + for (int x = 0, xx = out.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, + rainbow_table[COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))]); + } + } + break; + } + default: { + break; + } + } + + if ((!copy) && (MAIN_FB()->pixels == out.data)) { + MAIN_FB()->bpp = out.bpp; + } + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_rainbow_obj, 1, py_image_to_rainbow); + +static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + uint32_t size; + fb_alloc_mark(); + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; + PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); + PY_ASSERT_TRUE_MSG(out.bpp <= image_size(arg_img), "Can't compress in place!"); + memcpy(arg_img->data, out.data, out.bpp); + arg_img->bpp = out.bpp; + fb_free(); + fb_alloc_free_till_mark(); + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->bpp = arg_img->bpp; + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_obj, 1, py_image_compress); + +static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + uint32_t size; + fb_alloc_mark(); + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; + PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); + PY_ASSERT_TRUE_MSG(out.bpp <= image_size(arg_img), "Can't compress in place!"); + uint8_t *ptr = arg_img->data; + + *ptr++ = 0xFE; + + for(int i = 0, j = (out.bpp / 3) * 3; i < j; i += 3) { + int x = 0; + x |= out.data[i + 0] << 0; + x |= out.data[i + 1] << 8; + x |= out.data[i + 2] << 16; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x3F); + *ptr++ = 0x80 | ((x >> 12) & 0x3F); + *ptr++ = 0x80 | ((x >> 18) & 0x3F); + } + + if((out.bpp % 3) == 2) { // 2 bytes -> 16-bits -> 24-bits sent + int x = 0; + x |= out.data[out.bpp - 2] << 0; + x |= out.data[out.bpp - 1] << 8; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x3F); + *ptr++ = 0x80 | ((x >> 12) & 0x3F); + } + + if((out.bpp % 3) == 1) { // 1 byte -> 8-bits -> 16-bits sent + int x = 0; + x |= out.data[out.bpp - 1] << 0; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x3F); + } + + *ptr++ = 0xFE; + + out.bpp = (((out.bpp * 8) + 5) / 6) + 2; + arg_img->bpp = out.bpp; + fb_free(); + fb_alloc_free_till_mark(); + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->bpp = arg_img->bpp; + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_for_ide_obj, 1, py_image_compress_for_ide); + +static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + uint32_t size; + fb_alloc_mark(); + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; + PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); + uint8_t *temp = xalloc(out.bpp); + memcpy(temp, out.data, out.bpp); + out.data = temp; + fb_free(); + fb_alloc_free_till_mark(); + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_obj, 1, py_image_compressed); + +static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + uint32_t size; + fb_alloc_mark(); + uint8_t *buffer = fb_alloc_all(&size); + image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; + PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); + uint8_t *temp = xalloc((((out.bpp * 8) + 5) / 6) + 2); + uint8_t *ptr = temp; + + *ptr++ = 0xFE; + + for(int i = 0, j = (out.bpp / 3) * 3; i < j; i += 3) { + int x = 0; + x |= out.data[i + 0] << 0; + x |= out.data[i + 1] << 8; + x |= out.data[i + 2] << 16; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x3F); + *ptr++ = 0x80 | ((x >> 12) & 0x3F); + *ptr++ = 0x80 | ((x >> 18) & 0x3F); + } + + if((out.bpp % 3) == 2) { // 2 bytes -> 16-bits -> 24-bits sent + int x = 0; + x |= out.data[out.bpp - 2] << 0; + x |= out.data[out.bpp - 1] << 8; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x3F); + *ptr++ = 0x80 | ((x >> 12) & 0x0F); + } + + if((out.bpp % 3) == 1) { // 1 byte -> 8-bits -> 16-bits sent + int x = 0; + x |= out.data[out.bpp - 1] << 0; + *ptr++ = 0x80 | ((x >> 0) & 0x3F); + *ptr++ = 0x80 | ((x >> 6) & 0x03); + } + + *ptr++ = 0xFE; + + out.bpp = (((out.bpp * 8) + 5) / 6) + 2; + out.data = temp; + fb_free(); + fb_alloc_free_till_mark(); + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide); + +static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_image_cobj(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + bool copy_to_fb = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false); + if (copy_to_fb) fb_update_jpeg_buffer(); + + image_t image; + image.w = roi.w; + image.h = roi.h; + image.bpp = arg_img->bpp; + image.data = NULL; + + if (copy_to_fb) { + PY_ASSERT_TRUE_MSG(arg_img->data != MAIN_FB()->pixels, "Cannot copy to fb!"); + PY_ASSERT_TRUE_MSG((image_size(&image) <= OMV_RAW_BUF_SIZE), "FB Overflow!"); + MAIN_FB()->w = image.w; + MAIN_FB()->h = image.h; + MAIN_FB()->bpp = image.bpp; + image.data = MAIN_FB()->pixels; + } else { + image.data = xalloc(image_size(&image)); + } + + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y); + uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y); + uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_BAYER: { // Correct! + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { // JPEG + memcpy(image.data, arg_img->data, image_size(&image)); + break; + } + } + + return py_image_from_struct(&image); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy); + +static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_image_cobj(args[0]); + const char *path = mp_obj_str_get_str(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); + + int arg_q = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + fb_alloc_mark(); + imlib_save_image(arg_img, path, &roi, arg_q); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save); + +////////////////// +// Drawing Methods +////////////////// + +STATIC mp_obj_t py_image_clear(mp_obj_t img_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(img_obj); + memset(arg_img->data, 0, image_size(arg_img)); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_clear_obj, py_image_clear); + +STATIC mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec); + int arg_x0 = mp_obj_get_int(arg_vec[0]); + int arg_y0 = mp_obj_get_int(arg_vec[1]); + int arg_x1 = mp_obj_get_int(arg_vec[2]); + int arg_y1 = mp_obj_get_int(arg_vec[3]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_thickness = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + + imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line); + +STATIC mp_obj_t py_image_draw_rectangle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec); + int arg_rx = mp_obj_get_int(arg_vec[0]); + int arg_ry = mp_obj_get_int(arg_vec[1]); + int arg_rw = mp_obj_get_int(arg_vec[2]); + int arg_rh = mp_obj_get_int(arg_vec[3]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_thickness = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + bool arg_fill = + py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false); + + imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c, arg_thickness, arg_fill); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle); + +STATIC mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec); + int arg_cx = mp_obj_get_int(arg_vec[0]); + int arg_cy = mp_obj_get_int(arg_vec[1]); + int arg_cr = mp_obj_get_int(arg_vec[2]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_thickness = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + bool arg_fill = + py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false); + + imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c, arg_thickness, arg_fill); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 2, py_image_draw_circle); + +STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec); + int arg_x_off = mp_obj_get_int(arg_vec[0]); + int arg_y_off = mp_obj_get_int(arg_vec[1]); + const char *arg_str = mp_obj_str_get_str(arg_vec[2]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_scale = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale), 1); + int arg_x_spacing = + py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_spacing), 0); + int arg_y_spacing = + py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_spacing), 0); + bool arg_mono_space = + py_helper_keyword_int(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mono_space), true); + + imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, + arg_c, arg_scale, arg_x_spacing, arg_y_spacing, + arg_mono_space); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 2, py_image_draw_string); + +STATIC mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_s = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 5); + int arg_thickness = + py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + + imlib_draw_line(arg_img, arg_x - arg_s, arg_y , arg_x + arg_s, arg_y , arg_c, arg_thickness); + imlib_draw_line(arg_img, arg_x , arg_y - arg_s, arg_x , arg_y + arg_s, arg_c, arg_thickness); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 2, py_image_draw_cross); + +STATIC mp_obj_t py_image_draw_arrow(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec); + int arg_x0 = mp_obj_get_int(arg_vec[0]); + int arg_y0 = mp_obj_get_int(arg_vec[1]); + int arg_x1 = mp_obj_get_int(arg_vec[2]); + int arg_y1 = mp_obj_get_int(arg_vec[3]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White. + int arg_s = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10); + int arg_thickness = + py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + + int dx = (arg_x1 - arg_x0); + int dy = (arg_y1 - arg_y0); + float length = fast_sqrtf((dx * dx) + (dy * dy)); + + float ux = IM_DIV(dx, length); + float uy = IM_DIV(dy, length); + float vx = -uy; + float vy = ux; + + int a0x = fast_roundf(arg_x1 - (arg_s * ux) + (arg_s * vx * 0.5)); + int a0y = fast_roundf(arg_y1 - (arg_s * uy) + (arg_s * vy * 0.5)); + int a1x = fast_roundf(arg_x1 - (arg_s * ux) - (arg_s * vx * 0.5)); + int a1y = fast_roundf(arg_y1 - (arg_s * uy) - (arg_s * vy * 0.5)); + + imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness); + imlib_draw_line(arg_img, arg_x1, arg_y1, a0x, a0y, arg_c, arg_thickness); + imlib_draw_line(arg_img, arg_x1, arg_y1, a1x, a1y, arg_c, arg_thickness); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_arrow_obj, 2, py_image_draw_arrow); + +STATIC mp_obj_t py_image_draw_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + image_t *arg_other = + py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 2, 2, &arg_vec); + int arg_cx = mp_obj_get_int(arg_vec[0]); + int arg_cy = mp_obj_get_int(arg_vec[1]); + + float arg_x_scale = + py_helper_keyword_float(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), 1.0f); + PY_ASSERT_TRUE_MSG((0.0f <= arg_x_scale), "Error: 0.0 <= x_scale!"); + float arg_y_scale = + py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), 1.0f); + PY_ASSERT_TRUE_MSG((0.0f <= arg_y_scale), "Error: 0.0 <= y_scale!"); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, offset + 2, kw_args); + + imlib_draw_image(arg_img, arg_other, arg_cx, arg_cy, arg_x_scale, arg_y_scale, arg_msk); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_image_obj, 3, py_image_draw_image); + +STATIC mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + py_kp_obj_t *kpts_obj = py_kpts_obj(args[1]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, 2, kw_args, -1); // White. + int arg_s = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10); + int arg_thickness = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1); + bool arg_fill = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false); + + for (int i = 0, ii = array_length(kpts_obj->kpts); i < ii; i++) { + kp_t *kp = array_at(kpts_obj->kpts, i); + int cx = kp->x; + int cy = kp->y; + int si = sin_table[kp->angle] * arg_s; + int co = cos_table[kp->angle] * arg_s; + imlib_draw_line(arg_img, cx, cy, cx + co, cy + si, arg_c, arg_thickness); + imlib_draw_circle(arg_img, cx, cy, (arg_s - 2) / 2, arg_c, arg_thickness, arg_fill); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints); + +#ifdef IMLIB_ENABLE_FLOOD_FILL +STATIC mp_obj_t py_image_flood_fill(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x_off = mp_obj_get_int(arg_vec[0]); + int arg_y_off = mp_obj_get_int(arg_vec[1]); + + float arg_seed_threshold = + py_helper_keyword_float(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_seed_threshold), 0.05); + PY_ASSERT_TRUE_MSG((0.0f <= arg_seed_threshold) && (arg_seed_threshold <= 1.0f), + "Error: 0.0 <= seed_threshold <= 1.0!"); + float arg_floating_threshold = + py_helper_keyword_float(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_floating_threshold), 0.05); + PY_ASSERT_TRUE_MSG((0.0f <= arg_floating_threshold) && (arg_floating_threshold <= 1.0f), + "Error: 0.0 <= floating_threshold <= 1.0!"); + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset + 2, kw_args, -1); // White. + bool arg_invert = + py_helper_keyword_float(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + bool clear_background = + py_helper_keyword_float(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_clear_background), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, offset + 5, kw_args); + + fb_alloc_mark(); + imlib_flood_fill(arg_img, arg_x_off, arg_y_off, + arg_seed_threshold, arg_floating_threshold, + arg_c, arg_invert, clear_background, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_flood_fill_obj, 2, py_image_flood_fill); +#endif // IMLIB_ENABLE_FLOOD_FILL + +#ifdef IMLIB_ENABLE_BINARY_OPS +///////////////// +// Binary Methods +///////////////// + +STATIC mp_obj_t py_image_binary(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + list_t arg_thresholds; + list_init(&arg_thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_arg_to_thresholds(args[1], &arg_thresholds); + + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + bool arg_zero = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zero), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 4, kw_args); + bool arg_to_bitmap = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_to_bitmap), false); + bool arg_copy = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy), false); + + PY_ASSERT_TRUE_MSG((!arg_to_bitmap) || arg_copy, + "Can't convert to bitmap in place!"); + + image_t out; + out.w = arg_img->w; + out.h = arg_img->h; + out.bpp = arg_to_bitmap ? IMAGE_BPP_BINARY : arg_img->bpp; + out.data = arg_copy ? xalloc(image_size(&out)) : arg_img->data; + + fb_alloc_mark(); + imlib_binary(&out, arg_img, &arg_thresholds, arg_invert, arg_zero, arg_msk); + fb_alloc_free_till_mark(); + list_free(&arg_thresholds); + + if ((!arg_copy) && (MAIN_FB()->pixels == out.data)) { + MAIN_FB()->bpp = out.bpp; + } + + return py_image_from_struct(&out); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_binary_obj, 2, py_image_binary); + +STATIC mp_obj_t py_image_invert(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_invert(py_helper_arg_to_image_mutable(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert); + +STATIC mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_and(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_and(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and); + +STATIC mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_nand(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_nand(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand); + +STATIC mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_or(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_or(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or); + +STATIC mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_nor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_nor(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor); + +STATIC mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_xor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_xor(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor); + +STATIC mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_b_xnor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_b_xnor(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor); + +STATIC mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), + py_helper_ksize_to_n(arg_ksize) - 1); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_erode(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_erode_obj, 2, py_image_erode); + +STATIC mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), + 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_dilate(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate); + +STATIC mp_obj_t py_image_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_open(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_open_obj, 2, py_image_open); + +STATIC mp_obj_t py_image_close(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_close(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_close_obj, 2, py_image_close); +#endif // IMLIB_ENABLE_BINARY_OPS + +#ifdef IMLIB_ENABLE_MATH_OPS +/////////////// +// Math Methods +/////////////// + +STATIC mp_obj_t py_image_top_hat(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_top_hat(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_top_hat_obj, 2, py_image_top_hat); + +STATIC mp_obj_t py_image_black_hat(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_black_hat(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_black_hat_obj, 2, py_image_black_hat); + +STATIC mp_obj_t py_image_negate(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_negate(py_helper_arg_to_image_mutable(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate); + +STATIC mp_obj_t py_image_replace(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_hmirror = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false); + bool arg_vflip = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 4, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_replace(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_hmirror, arg_vflip, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_replace(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_hmirror, arg_vflip, arg_msk); + } else { + imlib_replace(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_hmirror, arg_vflip, arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_replace_obj, 2, py_image_replace); + +STATIC mp_obj_t py_image_add(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_add(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_add(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_add(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 2, py_image_add); + +STATIC mp_obj_t py_image_sub(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_sub(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_reverse, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_sub(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_reverse, arg_msk); + } else { + imlib_sub(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_reverse, arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 2, py_image_sub); + +STATIC mp_obj_t py_image_mul(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_mul(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_invert, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_mul(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_invert, arg_msk); + } else { + imlib_mul(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_invert, arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mul_obj, 2, py_image_mul); + +STATIC mp_obj_t py_image_div(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_div(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_invert, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_div(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_invert, arg_msk); + } else { + imlib_div(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_invert, arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_div_obj, 2, py_image_div); + +STATIC mp_obj_t py_image_min(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_min(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_min(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_min(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 2, py_image_min); + +STATIC mp_obj_t py_image_max(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_max(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_max(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_max(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 2, py_image_max); + +STATIC mp_obj_t py_image_difference(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_difference(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_difference(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_msk); + } else { + imlib_difference(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 2, py_image_difference); + +STATIC mp_obj_t py_image_blend(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_alpha = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128) / 256.0f; + PY_ASSERT_TRUE_MSG((0 <= arg_alpha) && (arg_alpha <= 1), "Error: 0 <= alpha <= 256!"); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(args[1])) { + imlib_blend(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, arg_alpha, arg_msk); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_blend(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), 0, arg_alpha, arg_msk); + } else { + imlib_blend(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + arg_alpha, arg_msk); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend); +#endif//IMLIB_ENABLE_MATH_OPS + +//////////////////// +// Filtering Methods +//////////////////// + +static mp_obj_t py_image_histeq(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_adaptive = + py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_adaptive), false); + float arg_clip_limit = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_clip_limit), -1); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + if (arg_adaptive) imlib_clahe_histeq(arg_img, arg_clip_limit, arg_msk); else imlib_histeq(arg_img, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_histeq_obj, 1, py_image_histeq); + +#ifdef IMLIB_ENABLE_MEAN +STATIC mp_obj_t py_image_mean(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args); + + fb_alloc_mark(); + imlib_mean_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mean_obj, 2, py_image_mean); +#endif // IMLIB_ENABLE_MEAN + +#ifdef IMLIB_ENABLE_MEDIAN +STATIC mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + float arg_percentile = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_percentile), 0.5f); + PY_ASSERT_TRUE_MSG((0 <= arg_percentile) && (arg_percentile <= 1), "Error: 0 <= percentile <= 1!"); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args); + + fb_alloc_mark(); + imlib_median_filter(arg_img, arg_ksize, arg_percentile, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 2, py_image_median); +#endif // IMLIB_ENABLE_MEDIAN + +#ifdef IMLIB_ENABLE_MODE +STATIC mp_obj_t py_image_mode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args); + + fb_alloc_mark(); + imlib_mode_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mode_obj, 2, py_image_mode); +#endif // IMLIB_ENABLE_MODE + +#ifdef IMLIB_ENABLE_MIDPOINT +STATIC mp_obj_t py_image_midpoint(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + float arg_bias = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5f); + PY_ASSERT_TRUE_MSG((0 <= arg_bias) && (arg_bias <= 1), "Error: 0 <= bias <= 1!"); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args); + + fb_alloc_mark(); + imlib_midpoint_filter(arg_img, arg_ksize, arg_bias, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint); +#endif // IMLIB_ENABLE_MIDPOINT + +#ifdef IMLIB_ENABLE_MORPH +STATIC mp_obj_t py_image_morph(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + + int n = py_helper_ksize_to_n(arg_ksize); + + mp_obj_t *krn; + mp_obj_get_array_fixed_n(args[2], n, &krn); + + fb_alloc_mark(); + + int *arg_krn = fb_alloc(n * sizeof(int)); + int arg_m = 0; + + for (int i = 0; i < n; i++) { + arg_krn[i] = mp_obj_get_int(krn[i]); + arg_m += arg_krn[i]; + } + + if (arg_m == 0) { + arg_m = 1; + } + + float arg_mul = + py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); + float arg_add = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args); + + imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph); +#endif //IMLIB_ENABLE_MORPH + +#ifdef IMLIB_ENABLE_GAUSSIAN +STATIC mp_obj_t py_image_gaussian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + + int k_2 = arg_ksize * 2; + int n = k_2 + 1; + + fb_alloc_mark(); + + int *pascal = fb_alloc(n * sizeof(int)); + pascal[0] = 1; + + for (int i = 0; i < k_2; i++) { // Compute a row of pascal's triangle. + pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1); + } + + int *arg_krn = fb_alloc(n * n * sizeof(int)); + int arg_m = 0; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + int temp = pascal[i] * pascal[j]; + arg_krn[(i * n) + j] = temp; + arg_m += temp; + } + } + + if (py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_unsharp), false)) { + arg_krn[((n/2)*n)+(n/2)] -= arg_m * 2; + arg_m = -arg_m; + } + + float arg_mul = + py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); + float arg_add = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args); + + imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_free(); + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 2, py_image_gaussian); +#endif // IMLIB_ENABLE_GAUSSIAN + +#ifdef IMLIB_ENABLE_LAPLACIAN +STATIC mp_obj_t py_image_laplacian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + + int k_2 = arg_ksize * 2; + int n = k_2 + 1; + + fb_alloc_mark(); + + int *pascal = fb_alloc(n * sizeof(int)); + pascal[0] = 1; + + for (int i = 0; i < k_2; i++) { // Compute a row of pascal's triangle. + pascal[i + 1] = (pascal[i] * (k_2 - i)) / (i + 1); + } + + int *arg_krn = fb_alloc(n * n * sizeof(int)); + int arg_m = 0; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + int temp = pascal[i] * pascal[j]; + arg_krn[(i * n) + j] = -temp; + arg_m += temp; + } + } + + arg_krn[((n/2)*n)+(n/2)] += arg_m; + arg_m = arg_krn[((n/2)*n)+(n/2)]; + + if (py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_sharpen), false)) { + arg_krn[((n/2)*n)+(n/2)] += arg_m; + } + + float arg_mul = + py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); + float arg_add = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 8, kw_args); + + imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_free(); + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_laplacian_obj, 2, py_image_laplacian); +#endif // IMLIB_ENABLE_LAPLACIAN + +#ifdef IMLIB_ENABLE_BILATERAL +STATIC mp_obj_t py_image_bilateral(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + float arg_color_sigma = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_sigma), 0.1); + float arg_space_sigma = + py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_space_sigma), 1); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 7, kw_args); + + fb_alloc_mark(); + imlib_bilateral_filter(arg_img, arg_ksize, arg_color_sigma, arg_space_sigma, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_bilateral_obj, 2, py_image_bilateral); +#endif // IMLIB_ENABLE_BILATERAL + +#ifdef IMLIB_ENABLE_CARTOON +STATIC mp_obj_t py_image_cartoon(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_seed_threshold = + py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_seed_threshold), 0.05); + PY_ASSERT_TRUE_MSG((0.0f <= arg_seed_threshold) && (arg_seed_threshold <= 1.0f), + "Error: 0.0 <= seed_threshold <= 1.0!"); + float arg_floating_threshold = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_floating_threshold), 0.05); + PY_ASSERT_TRUE_MSG((0.0f <= arg_floating_threshold) && (arg_floating_threshold <= 1.0f), + "Error: 0.0 <= floating_threshold <= 1.0!"); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_cartoon_filter(arg_img, arg_seed_threshold, arg_floating_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_cartoon_obj, 1, py_image_cartoon); +#endif // IMLIB_ENABLE_CARTOON + +///////////////////////// +// Shadow Removal Methods +///////////////////////// + +#ifdef IMLIB_ENABLE_REMOVE_SHADOWS +STATIC mp_obj_t py_image_remove_shadows(uint n_args, const mp_obj_t *args) +{ + image_t *arg_img = + py_helper_arg_to_image_color(args[0]); + + fb_alloc_mark(); + + if (n_args < 2) { + imlib_remove_shadows(arg_img, NULL, NULL, 0, true); + } else if (MP_OBJ_IS_STR(args[1])) { + imlib_remove_shadows(arg_img, mp_obj_str_get_str(args[1]), NULL, 0, false); + } else if (MP_OBJ_IS_TYPE(args[1], &py_image_type)) { + imlib_remove_shadows(arg_img, NULL, py_helper_arg_to_image_color(args[1]), 0, false); + } else { + imlib_remove_shadows(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, n_args, args, 1, NULL, 0), + false); + } + + fb_alloc_free_till_mark(); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_remove_shadows_obj, 1, 2, py_image_remove_shadows); +#endif // IMLIB_ENABLE_REMOVE_SHADOWS + +#ifdef IMLIB_ENABLE_CHROMINVAR +STATIC mp_obj_t py_image_chrominvar(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_chrominvar(py_helper_arg_to_image_color(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_chrominvar_obj, py_image_chrominvar); +#endif // IMLIB_ENABLE_CHROMINVAR + +#ifdef IMLIB_ENABLE_ILLUMINVAR +STATIC mp_obj_t py_image_illuminvar(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_illuminvar(py_helper_arg_to_image_color(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_illuminvar_obj, py_image_illuminvar); +#endif // IMLIB_ENABLE_ILLUMINVAR + +//////////////////// +// Geometric Methods +//////////////////// + +#ifdef IMLIB_ENABLE_LINPOLAR +static mp_obj_t py_image_linpolar(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); + + fb_alloc_mark(); + imlib_logpolar(arg_img, true, arg_reverse); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_linpolar_obj, 1, py_image_linpolar); +#endif // IMLIB_ENABLE_LINPOLAR + +#ifdef IMLIB_ENABLE_LOGPOLAR +static mp_obj_t py_image_logpolar(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); + + fb_alloc_mark(); + imlib_logpolar(arg_img, false, arg_reverse); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_logpolar_obj, 1, py_image_logpolar); +#endif // IMLIB_ENABLE_LOGPOLAR + +STATIC mp_obj_t py_image_lens_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_strength = + py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_strength), 1.8); + PY_ASSERT_TRUE_MSG(arg_strength > 0.0, "Strength must be > 0!"); + float arg_zoom = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0); + PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!"); + + fb_alloc_mark(); + imlib_lens_corr(arg_img, arg_strength, arg_zoom); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_lens_corr_obj, 1, py_image_lens_corr); + +#ifdef IMLIB_ENABLE_ROTATION_CORR +STATIC mp_obj_t py_image_rotation_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_x_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_rotation), 0.0)); + float arg_y_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_rotation), 0.0)); + float arg_z_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_z_rotation), 0.0)); + float arg_x_translation = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_translation), 0.0); + float arg_y_translation = + py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_translation), 0.0); + float arg_zoom = + py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0); + PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!"); + + fb_alloc_mark(); + imlib_rotation_corr(arg_img, + arg_x_rotation, arg_y_rotation, arg_z_rotation, + arg_x_translation, arg_y_translation, + arg_zoom); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_rotation_corr_obj, 1, py_image_rotation_corr); +#endif // IMLIB_ENABLE_ROTATION_CORR + +////////////// +// Get Methods +////////////// + +#ifdef IMLIB_ENABLE_GET_SIMILARITY +// Similarity Object // +#define py_similarity_obj_size 4 +typedef struct py_similarity_obj { + mp_obj_base_t base; + mp_obj_t avg, std, min, max; +} py_similarity_obj_t; + +static void py_similarity_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_similarity_obj_t *self = self_in; + mp_printf(print, + "{\"mean\":%f, \"stdev\":%f, \"min\":%f, \"max\":%f}", + (double) mp_obj_get_float(self->avg), + (double) mp_obj_get_float(self->std), + (double) mp_obj_get_float(self->min), + (double) mp_obj_get_float(self->max)); +} + +static mp_obj_t py_similarity_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_similarity_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_similarity_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->avg) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_similarity_obj_size, index, false)) { + case 0: return self->avg; + case 1: return self->std; + case 2: return self->min; + case 3: return self->max; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_similarity_mean(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->avg; } +mp_obj_t py_similarity_stdev(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->std; } +mp_obj_t py_similarity_min(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->min; } +mp_obj_t py_similarity_max(mp_obj_t self_in) { return ((py_similarity_obj_t *) self_in)->max; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_mean_obj, py_similarity_mean); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_stdev_obj, py_similarity_stdev); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_min_obj, py_similarity_min); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_similarity_max_obj, py_similarity_max); + +STATIC const mp_rom_map_elem_t py_similarity_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_similarity_mean_obj) }, + { MP_ROM_QSTR(MP_QSTR_stdev), MP_ROM_PTR(&py_similarity_stdev_obj) }, + { MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_similarity_min_obj) }, + { MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_similarity_max_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_similarity_locals_dict, py_similarity_locals_dict_table); + +static const mp_obj_type_t py_similarity_type = { + { &mp_type_type }, + .name = MP_QSTR_similarity, + .print = py_similarity_print, + .subscr = py_similarity_subscr, + .locals_dict = (mp_obj_t) &py_similarity_locals_dict +}; + +static mp_obj_t py_image_get_similarity(mp_obj_t img_obj, mp_obj_t other_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); + float avg, std, min, max; + + fb_alloc_mark(); + + if (MP_OBJ_IS_STR(other_obj)) { + imlib_get_similarity(arg_img, mp_obj_str_get_str(other_obj), NULL, 0, &avg, &std, &min, &max); + } else if (MP_OBJ_IS_TYPE(other_obj, &py_image_type)) { + imlib_get_similarity(arg_img, NULL, py_helper_arg_to_image_mutable(other_obj), 0, &avg, &std, &min, &max); + } else { + imlib_get_similarity(arg_img, NULL, NULL, + py_helper_keyword_color(arg_img, 1, &other_obj, 0, NULL, 0), + &avg, &std, &min, &max); + } + + fb_alloc_free_till_mark(); + + py_similarity_obj_t *o = m_new_obj(py_similarity_obj_t); + o->base.type = &py_similarity_type; + o->avg = mp_obj_new_float(avg); + o->std = mp_obj_new_float(std); + o->min = mp_obj_new_float(min); + o->max = mp_obj_new_float(max); + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_get_similarity_obj, py_image_get_similarity); +#endif // IMLIB_ENABLE_GET_SIMILARITY + +// Statistics Object // +#define py_statistics_obj_size 24 +typedef struct py_statistics_obj { + mp_obj_base_t base; + image_bpp_t bpp; + mp_obj_t LMean, LMedian, LMode, LSTDev, LMin, LMax, LLQ, LUQ, + AMean, AMedian, AMode, ASTDev, AMin, AMax, ALQ, AUQ, + BMean, BMedian, BMode, BSTDev, BMin, BMax, BLQ, BUQ; +} py_statistics_obj_t; + +static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_statistics_obj_t *self = self_in; + switch(self->bpp) { + case IMAGE_BPP_BINARY: { + mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}", + mp_obj_get_int(self->LMean), + mp_obj_get_int(self->LMedian), + mp_obj_get_int(self->LMode), + mp_obj_get_int(self->LSTDev), + mp_obj_get_int(self->LMin), + mp_obj_get_int(self->LMax), + mp_obj_get_int(self->LLQ), + mp_obj_get_int(self->LUQ)); + break; + } + case IMAGE_BPP_GRAYSCALE: { + mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}", + mp_obj_get_int(self->LMean), + mp_obj_get_int(self->LMedian), + mp_obj_get_int(self->LMode), + mp_obj_get_int(self->LSTDev), + mp_obj_get_int(self->LMin), + mp_obj_get_int(self->LMax), + mp_obj_get_int(self->LLQ), + mp_obj_get_int(self->LUQ)); + break; + } + case IMAGE_BPP_RGB565: { + mp_printf(print, "{\"l_mean\":%d, \"l_median\":%d, \"l_mode\":%d, \"l_stdev\":%d, \"l_min\":%d, \"l_max\":%d, \"l_lq\":%d, \"l_uq\":%d," + " \"a_mean\":%d, \"a_median\":%d, \"a_mode\":%d, \"a_stdev\":%d, \"a_min\":%d, \"a_max\":%d, \"a_lq\":%d, \"a_uq\":%d," + " \"b_mean\":%d, \"b_median\":%d, \"b_mode\":%d, \"b_stdev\":%d, \"b_min\":%d, \"b_max\":%d, \"b_lq\":%d, \"b_uq\":%d}", + mp_obj_get_int(self->LMean), + mp_obj_get_int(self->LMedian), + mp_obj_get_int(self->LMode), + mp_obj_get_int(self->LSTDev), + mp_obj_get_int(self->LMin), + mp_obj_get_int(self->LMax), + mp_obj_get_int(self->LLQ), + mp_obj_get_int(self->LUQ), + mp_obj_get_int(self->AMean), + mp_obj_get_int(self->AMedian), + mp_obj_get_int(self->AMode), + mp_obj_get_int(self->ASTDev), + mp_obj_get_int(self->AMin), + mp_obj_get_int(self->AMax), + mp_obj_get_int(self->ALQ), + mp_obj_get_int(self->AUQ), + mp_obj_get_int(self->BMean), + mp_obj_get_int(self->BMedian), + mp_obj_get_int(self->BMode), + mp_obj_get_int(self->BSTDev), + mp_obj_get_int(self->BMin), + mp_obj_get_int(self->BMax), + mp_obj_get_int(self->BLQ), + mp_obj_get_int(self->BUQ)); + break; + } + default: { + mp_printf(print, "{}"); + break; + } + } +} + +static mp_obj_t py_statistics_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_statistics_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_statistics_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->LMean) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_statistics_obj_size, index, false)) { + case 0: return self->LMean; + case 1: return self->LMedian; + case 2: return self->LMode; + case 3: return self->LSTDev; + case 4: return self->LMin; + case 5: return self->LMax; + case 6: return self->LLQ; + case 7: return self->LUQ; + case 8: return self->AMean; + case 9: return self->AMedian; + case 10: return self->AMode; + case 11: return self->ASTDev; + case 12: return self->AMin; + case 13: return self->AMax; + case 14: return self->ALQ; + case 15: return self->AUQ; + case 16: return self->BMean; + case 17: return self->BMedian; + case 18: return self->BMode; + case 19: return self->BSTDev; + case 20: return self->BMin; + case 21: return self->BMax; + case 22: return self->BLQ; + case 23: return self->BUQ; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_statistics_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMean; } +mp_obj_t py_statistics_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMedian; } +mp_obj_t py_statistics_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMode; } +mp_obj_t py_statistics_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LSTDev; } +mp_obj_t py_statistics_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMin; } +mp_obj_t py_statistics_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMax; } +mp_obj_t py_statistics_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LLQ; } +mp_obj_t py_statistics_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LUQ; } +mp_obj_t py_statistics_l_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMean; } +mp_obj_t py_statistics_l_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMedian; } +mp_obj_t py_statistics_l_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMode; } +mp_obj_t py_statistics_l_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LSTDev; } +mp_obj_t py_statistics_l_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMin; } +mp_obj_t py_statistics_l_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LMax; } +mp_obj_t py_statistics_l_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LLQ; } +mp_obj_t py_statistics_l_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->LUQ; } +mp_obj_t py_statistics_a_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMean; } +mp_obj_t py_statistics_a_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMedian; } +mp_obj_t py_statistics_a_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMode; } +mp_obj_t py_statistics_a_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->ASTDev; } +mp_obj_t py_statistics_a_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMin; } +mp_obj_t py_statistics_a_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AMax; } +mp_obj_t py_statistics_a_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->ALQ; } +mp_obj_t py_statistics_a_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->AUQ; } +mp_obj_t py_statistics_b_mean(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMean; } +mp_obj_t py_statistics_b_median(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMedian; } +mp_obj_t py_statistics_b_mode(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMode; } +mp_obj_t py_statistics_b_stdev(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BSTDev; } +mp_obj_t py_statistics_b_min(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMin; } +mp_obj_t py_statistics_b_max(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BMax; } +mp_obj_t py_statistics_b_lq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BLQ; } +mp_obj_t py_statistics_b_uq(mp_obj_t self_in) { return ((py_statistics_obj_t *) self_in)->BUQ; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_mean_obj, py_statistics_mean); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_median_obj, py_statistics_median); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_mode_obj, py_statistics_mode); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_stdev_obj, py_statistics_stdev); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_min_obj, py_statistics_min); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_max_obj, py_statistics_max); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_lq_obj, py_statistics_lq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_uq_obj, py_statistics_uq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_mean_obj, py_statistics_l_mean); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_median_obj, py_statistics_l_median); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_mode_obj, py_statistics_l_mode); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_stdev_obj, py_statistics_l_stdev); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_min_obj, py_statistics_l_min); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_max_obj, py_statistics_l_max); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_lq_obj, py_statistics_l_lq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_l_uq_obj, py_statistics_l_uq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_mean_obj, py_statistics_a_mean); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_median_obj, py_statistics_a_median); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_mode_obj, py_statistics_a_mode); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_stdev_obj, py_statistics_a_stdev); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_min_obj, py_statistics_a_min); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_max_obj, py_statistics_a_max); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_lq_obj, py_statistics_a_lq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_a_uq_obj, py_statistics_a_uq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_mean_obj, py_statistics_b_mean); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_median_obj, py_statistics_b_median); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_mode_obj, py_statistics_b_mode); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_stdev_obj, py_statistics_b_stdev); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_min_obj, py_statistics_b_min); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_max_obj, py_statistics_b_max); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_lq_obj, py_statistics_b_lq); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_statistics_b_uq_obj, py_statistics_b_uq); + +STATIC const mp_rom_map_elem_t py_statistics_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_statistics_mean_obj) }, + { MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&py_statistics_median_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&py_statistics_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_stdev), MP_ROM_PTR(&py_statistics_stdev_obj) }, + { MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_statistics_min_obj) }, + { MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_statistics_max_obj) }, + { MP_ROM_QSTR(MP_QSTR_lq), MP_ROM_PTR(&py_statistics_lq_obj) }, + { MP_ROM_QSTR(MP_QSTR_uq), MP_ROM_PTR(&py_statistics_uq_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_mean), MP_ROM_PTR(&py_statistics_l_mean_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_median), MP_ROM_PTR(&py_statistics_l_median_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_mode), MP_ROM_PTR(&py_statistics_l_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_stdev), MP_ROM_PTR(&py_statistics_l_stdev_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_min), MP_ROM_PTR(&py_statistics_l_min_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_max), MP_ROM_PTR(&py_statistics_l_max_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_lq), MP_ROM_PTR(&py_statistics_l_lq_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_uq), MP_ROM_PTR(&py_statistics_l_uq_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_mean), MP_ROM_PTR(&py_statistics_a_mean_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_median), MP_ROM_PTR(&py_statistics_a_median_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_mode), MP_ROM_PTR(&py_statistics_a_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_stdev), MP_ROM_PTR(&py_statistics_a_stdev_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_min), MP_ROM_PTR(&py_statistics_a_min_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_max), MP_ROM_PTR(&py_statistics_a_max_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_lq), MP_ROM_PTR(&py_statistics_a_lq_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_uq), MP_ROM_PTR(&py_statistics_a_uq_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_mean), MP_ROM_PTR(&py_statistics_b_mean_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_median), MP_ROM_PTR(&py_statistics_b_median_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_mode), MP_ROM_PTR(&py_statistics_b_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_stdev), MP_ROM_PTR(&py_statistics_b_stdev_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_min), MP_ROM_PTR(&py_statistics_b_min_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_max), MP_ROM_PTR(&py_statistics_b_max_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_lq), MP_ROM_PTR(&py_statistics_b_lq_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_uq), MP_ROM_PTR(&py_statistics_b_uq_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_statistics_locals_dict, py_statistics_locals_dict_table); + +static const mp_obj_type_t py_statistics_type = { + { &mp_type_type }, + .name = MP_QSTR_statistics, + .print = py_statistics_print, + .subscr = py_statistics_subscr, + .locals_dict = (mp_obj_t) &py_statistics_locals_dict +}; + +// Percentile Object // +#define py_percentile_obj_size 3 +typedef struct py_percentile_obj { + mp_obj_base_t base; + image_bpp_t bpp; + mp_obj_t LValue, AValue, BValue; +} py_percentile_obj_t; + +static void py_percentile_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_percentile_obj_t *self = self_in; + switch(self->bpp) { + case IMAGE_BPP_BINARY: { + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); + break; + } + case IMAGE_BPP_GRAYSCALE: { + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); + break; + } + case IMAGE_BPP_RGB565: { + mp_printf(print, "{\"l_value:%d\", \"a_value\":%d, \"b_value\":%d}", + mp_obj_get_int(self->LValue), + mp_obj_get_int(self->AValue), + mp_obj_get_int(self->BValue)); + break; + } + default: { + mp_printf(print, "{}"); + break; + } + } +} + +static mp_obj_t py_percentile_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_percentile_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_percentile_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->LValue) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_percentile_obj_size, index, false)) { + case 0: return self->LValue; + case 1: return self->AValue; + case 2: return self->BValue; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_percentile_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->LValue; } +mp_obj_t py_percentile_l_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->LValue; } +mp_obj_t py_percentile_a_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->AValue; } +mp_obj_t py_percentile_b_value(mp_obj_t self_in) { return ((py_percentile_obj_t *) self_in)->BValue; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_value_obj, py_percentile_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_l_value_obj, py_percentile_l_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_a_value_obj, py_percentile_a_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_percentile_b_value_obj, py_percentile_b_value); + +STATIC const mp_rom_map_elem_t py_percentile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&py_percentile_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_value), MP_ROM_PTR(&py_percentile_l_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_value), MP_ROM_PTR(&py_percentile_a_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_value), MP_ROM_PTR(&py_percentile_b_value_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_percentile_locals_dict, py_percentile_locals_dict_table); + +static const mp_obj_type_t py_percentile_type = { + { &mp_type_type }, + .name = MP_QSTR_percentile, + .print = py_percentile_print, + .subscr = py_percentile_subscr, + .locals_dict = (mp_obj_t) &py_percentile_locals_dict +}; + +// Threshold Object // +#define py_threshold_obj_size 3 +typedef struct py_threshold_obj { + mp_obj_base_t base; + image_bpp_t bpp; + mp_obj_t LValue, AValue, BValue; +} py_threshold_obj_t; + +static void py_threshold_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_threshold_obj_t *self = self_in; + switch(self->bpp) { + case IMAGE_BPP_BINARY: { + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); + break; + } + case IMAGE_BPP_GRAYSCALE: { + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); + break; + } + case IMAGE_BPP_RGB565: { + mp_printf(print, "{\"l_value\":%d, \"a_value\":%d, \"b_value\":%d}", + mp_obj_get_int(self->LValue), + mp_obj_get_int(self->AValue), + mp_obj_get_int(self->BValue)); + break; + } + default: { + mp_printf(print, "{}"); + break; + } + } +} + +static mp_obj_t py_threshold_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_threshold_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_threshold_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->LValue) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_threshold_obj_size, index, false)) { + case 0: return self->LValue; + case 1: return self->AValue; + case 2: return self->BValue; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_threshold_value(mp_obj_t self_in) { return ((py_threshold_obj_t *) self_in)->LValue; } +mp_obj_t py_threshold_l_value(mp_obj_t self_in) { return ((py_threshold_obj_t *) self_in)->LValue; } +mp_obj_t py_threshold_a_value(mp_obj_t self_in) { return ((py_threshold_obj_t *) self_in)->AValue; } +mp_obj_t py_threshold_b_value(mp_obj_t self_in) { return ((py_threshold_obj_t *) self_in)->BValue; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_threshold_value_obj, py_threshold_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_threshold_l_value_obj, py_threshold_l_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_threshold_a_value_obj, py_threshold_a_value); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_threshold_b_value_obj, py_threshold_b_value); + +STATIC const mp_rom_map_elem_t py_threshold_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&py_threshold_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_value), MP_ROM_PTR(&py_threshold_l_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_value), MP_ROM_PTR(&py_threshold_a_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_value), MP_ROM_PTR(&py_threshold_b_value_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_threshold_locals_dict, py_threshold_locals_dict_table); + +static const mp_obj_type_t py_threshold_type = { + { &mp_type_type }, + .name = MP_QSTR_threshold, + .print = py_threshold_print, + .subscr = py_threshold_subscr, + .locals_dict = (mp_obj_t) &py_threshold_locals_dict +}; + +// Histogram Object // +#define py_histogram_obj_size 3 +typedef struct py_histogram_obj { + mp_obj_base_t base; + image_bpp_t bpp; + mp_obj_t LBins, ABins, BBins; +} py_histogram_obj_t; + +static void py_histogram_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_histogram_obj_t *self = self_in; + switch(self->bpp) { + case IMAGE_BPP_BINARY: { + mp_printf(print, "{\"bins\":"); + mp_obj_print_helper(print, self->LBins, kind); + mp_printf(print, "}"); + break; + } + case IMAGE_BPP_GRAYSCALE: { + mp_printf(print, "{\"bins\":"); + mp_obj_print_helper(print, self->LBins, kind); + mp_printf(print, "}"); + break; + } + case IMAGE_BPP_RGB565: { + mp_printf(print, "{\"l_bins\":"); + mp_obj_print_helper(print, self->LBins, kind); + mp_printf(print, ", \"a_bins\":"); + mp_obj_print_helper(print, self->ABins, kind); + mp_printf(print, ", \"b_bins\":"); + mp_obj_print_helper(print, self->BBins, kind); + mp_printf(print, "}"); + break; + } + default: { + mp_printf(print, "{}"); + break; + } + } +} + +static mp_obj_t py_histogram_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_histogram_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_histogram_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->LBins) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_histogram_obj_size, index, false)) { + case 0: return self->LBins; + case 1: return self->ABins; + case 2: return self->BBins; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_histogram_bins(mp_obj_t self_in) { return ((py_histogram_obj_t *) self_in)->LBins; } +mp_obj_t py_histogram_l_bins(mp_obj_t self_in) { return ((py_histogram_obj_t *) self_in)->LBins; } +mp_obj_t py_histogram_a_bins(mp_obj_t self_in) { return ((py_histogram_obj_t *) self_in)->ABins; } +mp_obj_t py_histogram_b_bins(mp_obj_t self_in) { return ((py_histogram_obj_t *) self_in)->BBins; } + +mp_obj_t py_histogram_get_percentile(mp_obj_t self_in, mp_obj_t percentile) +{ + histogram_t hist; + hist.LBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->len; + hist.ABinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->len; + hist.BBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->len; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = fb_alloc(hist.ABinCount * sizeof(float)); + hist.BBins = fb_alloc(hist.BBinCount * sizeof(float)); + + for (int i = 0; i < hist.LBinCount; i++) { + hist.LBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->items[i]); + } + + for (int i = 0; i < hist.ABinCount; i++) { + hist.ABins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->items[i]); + } + + for (int i = 0; i < hist.BBinCount; i++) { + hist.BBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->items[i]); + } + + percentile_t p; + imlib_get_percentile(&p, ((py_histogram_obj_t *) self_in)->bpp, &hist, mp_obj_get_float(percentile)); + if (hist.BBinCount) fb_free(); + if (hist.ABinCount) fb_free(); + if (hist.LBinCount) fb_free(); + fb_alloc_free_till_mark(); + + py_percentile_obj_t *o = m_new_obj(py_percentile_obj_t); + o->base.type = &py_percentile_type; + o->bpp = ((py_histogram_obj_t *) self_in)->bpp; + + o->LValue = mp_obj_new_int(p.LValue); + o->AValue = mp_obj_new_int(p.AValue); + o->BValue = mp_obj_new_int(p.BValue); + + return o; +} + +mp_obj_t py_histogram_get_threshold(mp_obj_t self_in) +{ + histogram_t hist; + hist.LBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->len; + hist.ABinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->len; + hist.BBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->len; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = fb_alloc(hist.ABinCount * sizeof(float)); + hist.BBins = fb_alloc(hist.BBinCount * sizeof(float)); + + for (int i = 0; i < hist.LBinCount; i++) { + hist.LBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->items[i]); + } + + for (int i = 0; i < hist.ABinCount; i++) { + hist.ABins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->items[i]); + } + + for (int i = 0; i < hist.BBinCount; i++) { + hist.BBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->items[i]); + } + + threshold_t t; + imlib_get_threshold(&t, ((py_histogram_obj_t *) self_in)->bpp, &hist); + if (hist.BBinCount) fb_free(); + if (hist.ABinCount) fb_free(); + if (hist.LBinCount) fb_free(); + fb_alloc_free_till_mark(); + + py_threshold_obj_t *o = m_new_obj(py_threshold_obj_t); + o->base.type = &py_threshold_type; + o->bpp = ((py_threshold_obj_t *) self_in)->bpp; + + o->LValue = mp_obj_new_int(t.LValue); + o->AValue = mp_obj_new_int(t.AValue); + o->BValue = mp_obj_new_int(t.BValue); + + return o; +} + +mp_obj_t py_histogram_get_statistics(mp_obj_t self_in) +{ + histogram_t hist; + hist.LBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->len; + hist.ABinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->len; + hist.BBinCount = ((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->len; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = fb_alloc(hist.ABinCount * sizeof(float)); + hist.BBins = fb_alloc(hist.BBinCount * sizeof(float)); + + for (int i = 0; i < hist.LBinCount; i++) { + hist.LBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->LBins)->items[i]); + } + + for (int i = 0; i < hist.ABinCount; i++) { + hist.ABins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->ABins)->items[i]); + } + + for (int i = 0; i < hist.BBinCount; i++) { + hist.BBins[i] = mp_obj_get_float(((mp_obj_list_t *) ((py_histogram_obj_t *) self_in)->BBins)->items[i]); + } + + statistics_t stats; + imlib_get_statistics(&stats, ((py_histogram_obj_t *) self_in)->bpp, &hist); + if (hist.BBinCount) fb_free(); + if (hist.ABinCount) fb_free(); + if (hist.LBinCount) fb_free(); + fb_alloc_free_till_mark(); + + py_statistics_obj_t *o = m_new_obj(py_statistics_obj_t); + o->base.type = &py_statistics_type; + o->bpp = ((py_histogram_obj_t *) self_in)->bpp; + + o->LMean = mp_obj_new_int(stats.LMean); + o->LMedian = mp_obj_new_int(stats.LMedian); + o->LMode= mp_obj_new_int(stats.LMode); + o->LSTDev = mp_obj_new_int(stats.LSTDev); + o->LMin = mp_obj_new_int(stats.LMin); + o->LMax = mp_obj_new_int(stats.LMax); + o->LLQ = mp_obj_new_int(stats.LLQ); + o->LUQ = mp_obj_new_int(stats.LUQ); + o->AMean = mp_obj_new_int(stats.AMean); + o->AMedian = mp_obj_new_int(stats.AMedian); + o->AMode= mp_obj_new_int(stats.AMode); + o->ASTDev = mp_obj_new_int(stats.ASTDev); + o->AMin = mp_obj_new_int(stats.AMin); + o->AMax = mp_obj_new_int(stats.AMax); + o->ALQ = mp_obj_new_int(stats.ALQ); + o->AUQ = mp_obj_new_int(stats.AUQ); + o->BMean = mp_obj_new_int(stats.BMean); + o->BMedian = mp_obj_new_int(stats.BMedian); + o->BMode= mp_obj_new_int(stats.BMode); + o->BSTDev = mp_obj_new_int(stats.BSTDev); + o->BMin = mp_obj_new_int(stats.BMin); + o->BMax = mp_obj_new_int(stats.BMax); + o->BLQ = mp_obj_new_int(stats.BLQ); + o->BUQ = mp_obj_new_int(stats.BUQ); + + return o; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_bins_obj, py_histogram_bins); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_l_bins_obj, py_histogram_l_bins); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_a_bins_obj, py_histogram_a_bins); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_b_bins_obj, py_histogram_b_bins); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_histogram_get_percentile_obj, py_histogram_get_percentile); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_get_threshold_obj, py_histogram_get_threshold); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_histogram_get_statistics_obj, py_histogram_get_statistics); + +STATIC const mp_rom_map_elem_t py_histogram_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_bins), MP_ROM_PTR(&py_histogram_bins_obj) }, + { MP_ROM_QSTR(MP_QSTR_l_bins), MP_ROM_PTR(&py_histogram_l_bins_obj) }, + { MP_ROM_QSTR(MP_QSTR_a_bins), MP_ROM_PTR(&py_histogram_a_bins_obj) }, + { MP_ROM_QSTR(MP_QSTR_b_bins), MP_ROM_PTR(&py_histogram_b_bins_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_percentile), MP_ROM_PTR(&py_histogram_get_percentile_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_threshold), MP_ROM_PTR(&py_histogram_get_threshold_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_stats), MP_ROM_PTR(&py_histogram_get_statistics_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_statistics), MP_ROM_PTR(&py_histogram_get_statistics_obj) }, + { MP_ROM_QSTR(MP_QSTR_statistics), MP_ROM_PTR(&py_histogram_get_statistics_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_histogram_locals_dict, py_histogram_locals_dict_table); + +static const mp_obj_type_t py_histogram_type = { + { &mp_type_type }, + .name = MP_QSTR_histogram, + .print = py_histogram_print, + .subscr = py_histogram_subscr, + .locals_dict = (mp_obj_t) &py_histogram_locals_dict +}; + +static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_keyword_thresholds(n_args, args, 1, kw_args, &thresholds); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + histogram_t hist; + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); + PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + hist.ABinCount = 0; + hist.BBinCount = 0; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = NULL; + hist.BBins = NULL; + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + case IMAGE_BPP_GRAYSCALE: { + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); + PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + hist.ABinCount = 0; + hist.BBinCount = 0; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = NULL; + hist.BBins = NULL; + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + case IMAGE_BPP_RGB565: { + int l_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_L_MAX-COLOR_L_MIN+1)); + PY_ASSERT_TRUE_MSG(l_bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + int a_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_A_MAX-COLOR_A_MIN+1)); + PY_ASSERT_TRUE_MSG(a_bins >= 2, "bins must be >= 2"); + hist.ABinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); + PY_ASSERT_TRUE_MSG(hist.ABinCount >= 2, "a_bins must be >= 2"); + int b_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_B_MAX-COLOR_B_MIN+1)); + PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2"); + hist.BBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); + PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2"); + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = fb_alloc(hist.ABinCount * sizeof(float)); + hist.BBins = fb_alloc(hist.BBinCount * sizeof(float)); + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + default: { + return MP_OBJ_NULL; + } + } + + py_histogram_obj_t *o = m_new_obj(py_histogram_obj_t); + o->base.type = &py_histogram_type; + o->bpp = arg_img->bpp; + + o->LBins = mp_obj_new_list(hist.LBinCount, NULL); + o->ABins = mp_obj_new_list(hist.ABinCount, NULL); + o->BBins = mp_obj_new_list(hist.BBinCount, NULL); + + for (int i = 0; i < hist.LBinCount; i++) { + ((mp_obj_list_t *) o->LBins)->items[i] = mp_obj_new_float(hist.LBins[i]); + } + + for (int i = 0; i < hist.ABinCount; i++) { + ((mp_obj_list_t *) o->ABins)->items[i] = mp_obj_new_float(hist.ABins[i]); + } + + for (int i = 0; i < hist.BBinCount; i++) { + ((mp_obj_list_t *) o->BBins)->items[i] = mp_obj_new_float(hist.BBins[i]); + } + + if (hist.BBinCount) fb_free(); + if (hist.ABinCount) fb_free(); + if (hist.LBinCount) fb_free(); + fb_alloc_free_till_mark(); + + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_histogram_obj, 1, py_image_get_histogram); + +static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_keyword_thresholds(n_args, args, 1, kw_args, &thresholds); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + histogram_t hist; + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); + PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + hist.ABinCount = 0; + hist.BBinCount = 0; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = NULL; + hist.BBins = NULL; + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + case IMAGE_BPP_GRAYSCALE: { + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); + PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + hist.ABinCount = 0; + hist.BBinCount = 0; + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = NULL; + hist.BBins = NULL; + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + case IMAGE_BPP_RGB565: { + int l_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_L_MAX-COLOR_L_MIN+1)); + PY_ASSERT_TRUE_MSG(l_bins >= 2, "bins must be >= 2"); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); + PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); + int a_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_A_MAX-COLOR_A_MIN+1)); + PY_ASSERT_TRUE_MSG(a_bins >= 2, "bins must be >= 2"); + hist.ABinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); + PY_ASSERT_TRUE_MSG(hist.ABinCount >= 2, "a_bins must be >= 2"); + int b_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_B_MAX-COLOR_B_MIN+1)); + PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2"); + hist.BBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); + PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2"); + fb_alloc_mark(); + hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); + hist.ABins = fb_alloc(hist.ABinCount * sizeof(float)); + hist.BBins = fb_alloc(hist.BBinCount * sizeof(float)); + imlib_get_histogram(&hist, arg_img, &roi, &thresholds, invert); + list_free(&thresholds); + break; + } + default: { + return MP_OBJ_NULL; + } + } + + statistics_t stats; + imlib_get_statistics(&stats, arg_img->bpp, &hist); + if (hist.BBinCount) fb_free(); + if (hist.ABinCount) fb_free(); + if (hist.LBinCount) fb_free(); + fb_alloc_free_till_mark(); + + py_statistics_obj_t *o = m_new_obj(py_statistics_obj_t); + o->base.type = &py_statistics_type; + o->bpp = arg_img->bpp; + + o->LMean = mp_obj_new_int(stats.LMean); + o->LMedian = mp_obj_new_int(stats.LMedian); + o->LMode= mp_obj_new_int(stats.LMode); + o->LSTDev = mp_obj_new_int(stats.LSTDev); + o->LMin = mp_obj_new_int(stats.LMin); + o->LMax = mp_obj_new_int(stats.LMax); + o->LLQ = mp_obj_new_int(stats.LLQ); + o->LUQ = mp_obj_new_int(stats.LUQ); + o->AMean = mp_obj_new_int(stats.AMean); + o->AMedian = mp_obj_new_int(stats.AMedian); + o->AMode= mp_obj_new_int(stats.AMode); + o->ASTDev = mp_obj_new_int(stats.ASTDev); + o->AMin = mp_obj_new_int(stats.AMin); + o->AMax = mp_obj_new_int(stats.AMax); + o->ALQ = mp_obj_new_int(stats.ALQ); + o->AUQ = mp_obj_new_int(stats.AUQ); + o->BMean = mp_obj_new_int(stats.BMean); + o->BMedian = mp_obj_new_int(stats.BMedian); + o->BMode= mp_obj_new_int(stats.BMode); + o->BSTDev = mp_obj_new_int(stats.BSTDev); + o->BMin = mp_obj_new_int(stats.BMin); + o->BMax = mp_obj_new_int(stats.BMax); + o->BLQ = mp_obj_new_int(stats.BLQ); + o->BUQ = mp_obj_new_int(stats.BUQ); + + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_statistics_obj, 1, py_image_get_statistics); + +// Line Object // +#define py_line_obj_size 8 +typedef struct py_line_obj { + mp_obj_base_t base; + mp_obj_t x1, y1, x2, y2, length, magnitude, theta, rho; +} py_line_obj_t; + +static void py_line_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_line_obj_t *self = self_in; + mp_printf(print, + "{\"x1\":%d, \"y1\":%d, \"x2\":%d, \"y2\":%d, \"length\":%d, \"magnitude\":%d, \"theta\":%d, \"rho\":%d}", + mp_obj_get_int(self->x1), + mp_obj_get_int(self->y1), + mp_obj_get_int(self->x2), + mp_obj_get_int(self->y2), + mp_obj_get_int(self->length), + mp_obj_get_int(self->magnitude), + mp_obj_get_int(self->theta), + mp_obj_get_int(self->rho)); +} + +static mp_obj_t py_line_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_line_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_line_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x1) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_line_obj_size, index, false)) { + case 0: return self->x1; + case 1: return self->y1; + case 2: return self->x2; + case 3: return self->y2; + case 4: return self->length; + case 5: return self->magnitude; + case 6: return self->theta; + case 7: return self->rho; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_line_line(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_line_obj_t *) self_in)->x1, + ((py_line_obj_t *) self_in)->y1, + ((py_line_obj_t *) self_in)->x2, + ((py_line_obj_t *) self_in)->y2}); +} + +mp_obj_t py_line_x1(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->x1; } +mp_obj_t py_line_y1(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->y1; } +mp_obj_t py_line_x2(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->x2; } +mp_obj_t py_line_y2(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->y2; } +mp_obj_t py_line_length(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->length; } +mp_obj_t py_line_magnitude(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->magnitude; } +mp_obj_t py_line_theta(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->theta; } +mp_obj_t py_line_rho(mp_obj_t self_in) { return ((py_line_obj_t *) self_in)->rho; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_line_obj, py_line_line); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_x1_obj, py_line_x1); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_y1_obj, py_line_y1); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_x2_obj, py_line_x2); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_y2_obj, py_line_y2); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_length_obj, py_line_length); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_magnitude_obj, py_line_magnitude); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_theta_obj, py_line_theta); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_line_rho_obj, py_line_rho); + +STATIC const mp_rom_map_elem_t py_line_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&py_line_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_x1), MP_ROM_PTR(&py_line_x1_obj) }, + { MP_ROM_QSTR(MP_QSTR_y1), MP_ROM_PTR(&py_line_y1_obj) }, + { MP_ROM_QSTR(MP_QSTR_x2), MP_ROM_PTR(&py_line_x2_obj) }, + { MP_ROM_QSTR(MP_QSTR_y2), MP_ROM_PTR(&py_line_y2_obj) }, + { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&py_line_length_obj) }, + { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_line_magnitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_theta), MP_ROM_PTR(&py_line_theta_obj) }, + { MP_ROM_QSTR(MP_QSTR_rho), MP_ROM_PTR(&py_line_rho_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_line_locals_dict, py_line_locals_dict_table); + +static const mp_obj_type_t py_line_type = { + { &mp_type_type }, + .name = MP_QSTR_line, + .print = py_line_print, + .subscr = py_line_subscr, + .locals_dict = (mp_obj_t) &py_line_locals_dict +}; + +static mp_obj_t py_image_get_regression(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_arg_to_thresholds(args[1], &thresholds); + if (!list_size(&thresholds)) return mp_const_none; + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + unsigned int area_threshold = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); + unsigned int pixels_threshold = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); + bool robust = py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_robust), false); + + find_lines_list_lnk_data_t out; + fb_alloc_mark(); + bool result = imlib_get_regression(&out, arg_img, &roi, x_stride, y_stride, &thresholds, invert, area_threshold, pixels_threshold, robust); + fb_alloc_free_till_mark(); + list_free(&thresholds); + if (!result) { + return mp_const_none; + } + + py_line_obj_t *o = m_new_obj(py_line_obj_t); + o->base.type = &py_line_type; + o->x1 = mp_obj_new_int(out.line.x1); + o->y1 = mp_obj_new_int(out.line.y1); + o->x2 = mp_obj_new_int(out.line.x2); + o->y2 = mp_obj_new_int(out.line.y2); + int x_diff = out.line.x2 - out.line.x1; + int y_diff = out.line.y2 - out.line.y1; + o->length = mp_obj_new_int(fast_roundf(fast_sqrtf((x_diff * x_diff) + (y_diff * y_diff)))); + o->magnitude = mp_obj_new_int(out.magnitude); + o->theta = mp_obj_new_int(out.theta); + o->rho = mp_obj_new_int(out.rho); + + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_regression_obj, 2, py_image_get_regression); + +/////////////// +// Find Methods +/////////////// + +// Blob Object // +#define py_blob_obj_size 10 +typedef struct py_blob_obj { + mp_obj_base_t base; + mp_obj_t x, y, w, h, pixels, cx, cy, rotation, code, count; +} py_blob_obj_t; + +static void py_blob_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_blob_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"pixels\":%d, \"cx\":%d, \"cy\":%d, \"rotation\":%f, \"code\":%d, \"count\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_get_int(self->pixels), + mp_obj_get_int(self->cx), + mp_obj_get_int(self->cy), + (double) mp_obj_get_float(self->rotation), + mp_obj_get_int(self->code), + mp_obj_get_int(self->count)); +} + +static mp_obj_t py_blob_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_blob_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_blob_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_blob_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->pixels; + case 5: return self->cx; + case 6: return self->cy; + case 7: return self->rotation; + case 8: return self->code; + case 9: return self->count; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_blob_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_blob_obj_t *) self_in)->x, + ((py_blob_obj_t *) self_in)->y, + ((py_blob_obj_t *) self_in)->w, + ((py_blob_obj_t *) self_in)->h}); +} + +mp_obj_t py_blob_x(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->x; } +mp_obj_t py_blob_y(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->y; } +mp_obj_t py_blob_w(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->w; } +mp_obj_t py_blob_h(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->h; } +mp_obj_t py_blob_pixels(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->pixels; } +mp_obj_t py_blob_cx(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->cx; } +mp_obj_t py_blob_cy(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->cy; } +mp_obj_t py_blob_rotation(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->rotation; } +mp_obj_t py_blob_code(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->code; } +mp_obj_t py_blob_count(mp_obj_t self_in) { return ((py_blob_obj_t *) self_in)->count; } +mp_obj_t py_blob_area(mp_obj_t self_in) { + return mp_obj_new_int(mp_obj_get_int(((py_blob_obj_t *) self_in)->w) * mp_obj_get_int(((py_blob_obj_t *) self_in)->h)); +} +mp_obj_t py_blob_density(mp_obj_t self_in) { + int area = mp_obj_get_int(((py_blob_obj_t *) self_in)->w) * mp_obj_get_int(((py_blob_obj_t *) self_in)->h); + if (area) return mp_obj_new_float(mp_obj_get_int(((py_blob_obj_t *) self_in)->pixels) / ((float) area)); + return mp_obj_new_float(0.0f); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_rect_obj, py_blob_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_x_obj, py_blob_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_y_obj, py_blob_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_w_obj, py_blob_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_h_obj, py_blob_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_pixels_obj, py_blob_pixels); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_cx_obj, py_blob_cx); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_cy_obj, py_blob_cy); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_rotation_obj, py_blob_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_code_obj, py_blob_code); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_count_obj, py_blob_count); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_area_obj, py_blob_area); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_blob_density_obj, py_blob_density); + +STATIC const mp_rom_map_elem_t py_blob_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_blob_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_blob_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_blob_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_blob_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_blob_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixels), MP_ROM_PTR(&py_blob_pixels_obj) }, + { MP_ROM_QSTR(MP_QSTR_cx), MP_ROM_PTR(&py_blob_cx_obj) }, + { MP_ROM_QSTR(MP_QSTR_cy), MP_ROM_PTR(&py_blob_cy_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_blob_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_code), MP_ROM_PTR(&py_blob_code_obj) }, + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&py_blob_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_area), MP_ROM_PTR(&py_blob_area_obj) } , + { MP_ROM_QSTR(MP_QSTR_density), MP_ROM_PTR(&py_blob_density_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_blob_locals_dict, py_blob_locals_dict_table); + +static const mp_obj_type_t py_blob_type = { + { &mp_type_type }, + .name = MP_QSTR_blob, + .print = py_blob_print, + .subscr = py_blob_subscr, + .locals_dict = (mp_obj_t) &py_blob_locals_dict +}; + +static bool py_image_find_blobs_threshold_cb(void *fun_obj, find_blobs_list_lnk_data_t *blob) +{ + py_blob_obj_t *o = m_new_obj(py_blob_obj_t); + o->base.type = &py_blob_type; + o->x = mp_obj_new_int(blob->rect.x); + o->y = mp_obj_new_int(blob->rect.y); + o->w = mp_obj_new_int(blob->rect.w); + o->h = mp_obj_new_int(blob->rect.h); + o->pixels = mp_obj_new_int(blob->pixels); + o->cx = mp_obj_new_int(blob->centroid.x); + o->cy = mp_obj_new_int(blob->centroid.y); + o->rotation = mp_obj_new_float(blob->rotation); + o->code = mp_obj_new_int(blob->code); + o->count = mp_obj_new_int(blob->count); + + return mp_obj_is_true(mp_call_function_1(fun_obj, o)); +} + +static bool py_image_find_blobs_merge_cb(void *fun_obj, find_blobs_list_lnk_data_t *blob0, find_blobs_list_lnk_data_t *blob1) +{ + py_blob_obj_t *o0 = m_new_obj(py_blob_obj_t); + o0->base.type = &py_blob_type; + o0->x = mp_obj_new_int(blob0->rect.x); + o0->y = mp_obj_new_int(blob0->rect.y); + o0->w = mp_obj_new_int(blob0->rect.w); + o0->h = mp_obj_new_int(blob0->rect.h); + o0->pixels = mp_obj_new_int(blob0->pixels); + o0->cx = mp_obj_new_int(blob0->centroid.x); + o0->cy = mp_obj_new_int(blob0->centroid.y); + o0->rotation = mp_obj_new_float(blob0->rotation); + o0->code = mp_obj_new_int(blob0->code); + o0->count = mp_obj_new_int(blob0->count); + + py_blob_obj_t *o1 = m_new_obj(py_blob_obj_t); + o1->base.type = &py_blob_type; + o1->x = mp_obj_new_int(blob1->rect.x); + o1->y = mp_obj_new_int(blob1->rect.y); + o1->w = mp_obj_new_int(blob1->rect.w); + o1->h = mp_obj_new_int(blob1->rect.h); + o1->pixels = mp_obj_new_int(blob1->pixels); + o1->cx = mp_obj_new_int(blob1->centroid.x); + o1->cy = mp_obj_new_int(blob1->centroid.y); + o1->rotation = mp_obj_new_float(blob1->rotation); + o1->code = mp_obj_new_int(blob1->code); + o1->count = mp_obj_new_int(blob1->count); + + return mp_obj_is_true(mp_call_function_2(fun_obj, o0, o1)); +} + +static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + list_t thresholds; + list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_arg_to_thresholds(args[1], &thresholds); + if (!list_size(&thresholds)) return mp_obj_new_list(0, NULL); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + unsigned int area_threshold = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); + unsigned int pixels_threshold = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); + bool merge = py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge), false); + int margin = py_helper_keyword_int(n_args, args, 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_margin), 0); + mp_obj_t threshold_cb = py_helper_keyword_object(n_args, args, 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold_cb)); + mp_obj_t merge_cb = py_helper_keyword_object(n_args, args, 11, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_cb)); + + list_t out; + fb_alloc_mark(); + imlib_find_blobs(&out, arg_img, &roi, x_stride, y_stride, &thresholds, invert, + area_threshold, pixels_threshold, merge, margin, + py_image_find_blobs_threshold_cb, threshold_cb, py_image_find_blobs_merge_cb, merge_cb); + fb_alloc_free_till_mark(); + list_free(&thresholds); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_blobs_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_blob_obj_t *o = m_new_obj(py_blob_obj_t); + o->base.type = &py_blob_type; + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->pixels = mp_obj_new_int(lnk_data.pixels); + o->cx = mp_obj_new_int(lnk_data.centroid.x); + o->cy = mp_obj_new_int(lnk_data.centroid.y); + o->rotation = mp_obj_new_float(lnk_data.rotation); + o->code = mp_obj_new_int(lnk_data.code); + o->count = mp_obj_new_int(lnk_data.count); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_blobs_obj, 2, py_image_find_blobs); + +#ifdef IMLIB_ENABLE_FIND_LINES +static mp_obj_t py_image_find_lines(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + uint32_t threshold = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000); + unsigned int theta_margin = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_theta_margin), 25); + unsigned int rho_margin = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rho_margin), 25); + + list_t out; + fb_alloc_mark(); + imlib_find_lines(&out, arg_img, &roi, x_stride, y_stride, threshold, theta_margin, rho_margin); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_lines_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_line_obj_t *o = m_new_obj(py_line_obj_t); + o->base.type = &py_line_type; + o->x1 = mp_obj_new_int(lnk_data.line.x1); + o->y1 = mp_obj_new_int(lnk_data.line.y1); + o->x2 = mp_obj_new_int(lnk_data.line.x2); + o->y2 = mp_obj_new_int(lnk_data.line.y2); + int x_diff = lnk_data.line.x2 - lnk_data.line.x1; + int y_diff = lnk_data.line.y2 - lnk_data.line.y1; + o->length = mp_obj_new_int(fast_roundf(fast_sqrtf((x_diff * x_diff) + (y_diff * y_diff)))); + o->magnitude = mp_obj_new_int(lnk_data.magnitude); + o->theta = mp_obj_new_int(lnk_data.theta); + o->rho = mp_obj_new_int(lnk_data.rho); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lines_obj, 1, py_image_find_lines); +#endif // IMLIB_ENABLE_FIND_LINES + +#ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS +static mp_obj_t py_image_find_line_segments(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + unsigned int merge_distance = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_distance), 0); + unsigned int max_theta_diff = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_theta_diff), 15); + + list_t out; + fb_alloc_mark(); + imlib_lsd_find_line_segments(&out, arg_img, &roi, merge_distance, max_theta_diff); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_lines_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_line_obj_t *o = m_new_obj(py_line_obj_t); + o->base.type = &py_line_type; + o->x1 = mp_obj_new_int(lnk_data.line.x1); + o->y1 = mp_obj_new_int(lnk_data.line.y1); + o->x2 = mp_obj_new_int(lnk_data.line.x2); + o->y2 = mp_obj_new_int(lnk_data.line.y2); + int x_diff = lnk_data.line.x2 - lnk_data.line.x1; + int y_diff = lnk_data.line.y2 - lnk_data.line.y1; + o->length = mp_obj_new_int(fast_roundf(fast_sqrtf((x_diff * x_diff) + (y_diff * y_diff)))); + o->magnitude = mp_obj_new_int(lnk_data.magnitude); + o->theta = mp_obj_new_int(lnk_data.theta); + o->rho = mp_obj_new_int(lnk_data.rho); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_line_segments_obj, 1, py_image_find_line_segments); +#endif // IMLIB_ENABLE_FIND_LINE_SEGMENTS + +#ifdef IMLIB_ENABLE_FIND_CIRCLES +// Circle Object // +#define py_circle_obj_size 4 +typedef struct py_circle_obj { + mp_obj_base_t base; + mp_obj_t x, y, r, magnitude; +} py_circle_obj_t; + +static void py_circle_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_circle_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"r\":%d, \"magnitude\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->r), + mp_obj_get_int(self->magnitude)); +} + +static mp_obj_t py_circle_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_circle_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_circle_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_circle_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->r; + case 3: return self->magnitude; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_circle_circle(mp_obj_t self_in) +{ + return mp_obj_new_tuple(3, (mp_obj_t []) {((py_circle_obj_t *) self_in)->x, + ((py_circle_obj_t *) self_in)->y, + ((py_circle_obj_t *) self_in)->r}); +} + +mp_obj_t py_circle_x(mp_obj_t self_in) { return ((py_circle_obj_t *) self_in)->x; } +mp_obj_t py_circle_y(mp_obj_t self_in) { return ((py_circle_obj_t *) self_in)->y; } +mp_obj_t py_circle_r(mp_obj_t self_in) { return ((py_circle_obj_t *) self_in)->r; } +mp_obj_t py_circle_magnitude(mp_obj_t self_in) { return ((py_circle_obj_t *) self_in)->magnitude; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_circle_circle_obj, py_circle_circle); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_circle_x_obj, py_circle_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_circle_y_obj, py_circle_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_circle_r_obj, py_circle_r); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_circle_magnitude_obj, py_circle_magnitude); + +STATIC const mp_rom_map_elem_t py_circle_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&py_circle_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_circle_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_circle_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_r), MP_ROM_PTR(&py_circle_r_obj) }, + { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_circle_magnitude_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_circle_locals_dict, py_circle_locals_dict_table); + +static const mp_obj_type_t py_circle_type = { + { &mp_type_type }, + .name = MP_QSTR_circle, + .print = py_circle_print, + .subscr = py_circle_subscr, + .locals_dict = (mp_obj_t) &py_circle_locals_dict +}; + +static mp_obj_t py_image_find_circles(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + uint32_t threshold = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 2000); + unsigned int x_margin = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_margin), 10); + unsigned int y_margin = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_margin), 10); + unsigned int r_margin = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_margin), 10); + unsigned int r_min = IM_MAX(py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_min), + 2), 2); + unsigned int r_max = IM_MIN(py_helper_keyword_int(n_args, args, 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_max), + IM_MIN((roi.w / 2), (roi.h / 2))), IM_MIN((roi.w / 2), (roi.h / 2))); + unsigned int r_step = py_helper_keyword_int(n_args, args, 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_step), 2); + + list_t out; + fb_alloc_mark(); + imlib_find_circles(&out, arg_img, &roi, x_stride, y_stride, threshold, x_margin, y_margin, r_margin, + r_min, r_max, r_step); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_circles_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_circle_obj_t *o = m_new_obj(py_circle_obj_t); + o->base.type = &py_circle_type; + o->x = mp_obj_new_int(lnk_data.p.x); + o->y = mp_obj_new_int(lnk_data.p.y); + o->r = mp_obj_new_int(lnk_data.r); + o->magnitude = mp_obj_new_int(lnk_data.magnitude); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_circles_obj, 1, py_image_find_circles); +#endif // IMLIB_ENABLE_FIND_CIRCLES + +#ifdef IMLIB_ENABLE_FIND_RECTS +// Rect Object // +#define py_rect_obj_size 5 +typedef struct py_rect_obj { + mp_obj_base_t base; + mp_obj_t corners; + mp_obj_t x, y, w, h, magnitude; +} py_rect_obj_t; + +static void py_rect_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_rect_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"magnitude\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_get_int(self->magnitude)); +} + +static mp_obj_t py_rect_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_rect_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_rect_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_rect_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->magnitude; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_rect_corners(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->corners; } +mp_obj_t py_rect_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_rect_obj_t *) self_in)->x, + ((py_rect_obj_t *) self_in)->y, + ((py_rect_obj_t *) self_in)->w, + ((py_rect_obj_t *) self_in)->h}); +} + +mp_obj_t py_rect_x(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->x; } +mp_obj_t py_rect_y(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->y; } +mp_obj_t py_rect_w(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->w; } +mp_obj_t py_rect_h(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->h; } +mp_obj_t py_rect_magnitude(mp_obj_t self_in) { return ((py_rect_obj_t *) self_in)->magnitude; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_corners_obj, py_rect_corners); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_rect_obj, py_rect_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_x_obj, py_rect_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_y_obj, py_rect_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_w_obj, py_rect_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_h_obj, py_rect_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_rect_magnitude_obj, py_rect_magnitude); + +STATIC const mp_rom_map_elem_t py_rect_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_corners), MP_ROM_PTR(&py_rect_corners_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_rect_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_rect_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_rect_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_rect_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_rect_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_rect_magnitude_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_rect_locals_dict, py_rect_locals_dict_table); + +static const mp_obj_type_t py_rect_type = { + { &mp_type_type }, + .name = MP_QSTR_rect, + .print = py_rect_print, + .subscr = py_rect_subscr, + .locals_dict = (mp_obj_t) &py_rect_locals_dict +}; + +static mp_obj_t py_image_find_rects(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + uint32_t threshold = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000); + + list_t out; + fb_alloc_mark(); + imlib_find_rects(&out, arg_img, &roi, threshold); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_rects_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_rect_obj_t *o = m_new_obj(py_rect_obj_t); + o->base.type = &py_rect_type; + o->corners = mp_obj_new_tuple(4, (mp_obj_t []) + {mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[0].x), mp_obj_new_int(lnk_data.corners[0].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[1].x), mp_obj_new_int(lnk_data.corners[1].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[2].x), mp_obj_new_int(lnk_data.corners[2].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[3].x), mp_obj_new_int(lnk_data.corners[3].y)})}); + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->magnitude = mp_obj_new_int(lnk_data.magnitude); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_rects_obj, 1, py_image_find_rects); +#endif // IMLIB_ENABLE_FIND_RECTS + +#ifdef IMLIB_ENABLE_QRCODES +// QRCode Object // +#define py_qrcode_obj_size 10 +typedef struct py_qrcode_obj { + mp_obj_base_t base; + mp_obj_t corners; + mp_obj_t x, y, w, h, payload, version, ecc_level, mask, data_type, eci; +} py_qrcode_obj_t; + +static void py_qrcode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_qrcode_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"version\":%d, \"ecc_level\":%d, \"mask\":%d, \"data_type\":%d, \"eci\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_str_get_str(self->payload), + mp_obj_get_int(self->version), + mp_obj_get_int(self->ecc_level), + mp_obj_get_int(self->mask), + mp_obj_get_int(self->data_type), + mp_obj_get_int(self->eci)); +} + +static mp_obj_t py_qrcode_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_qrcode_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_qrcode_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_qrcode_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->payload; + case 5: return self->version; + case 6: return self->ecc_level; + case 7: return self->mask; + case 8: return self->data_type; + case 9: return self->eci; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_qrcode_corners(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->corners; } +mp_obj_t py_qrcode_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_qrcode_obj_t *) self_in)->x, + ((py_qrcode_obj_t *) self_in)->y, + ((py_qrcode_obj_t *) self_in)->w, + ((py_qrcode_obj_t *) self_in)->h}); +} + +mp_obj_t py_qrcode_x(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->x; } +mp_obj_t py_qrcode_y(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->y; } +mp_obj_t py_qrcode_w(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->w; } +mp_obj_t py_qrcode_h(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->h; } +mp_obj_t py_qrcode_payload(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->payload; } +mp_obj_t py_qrcode_version(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->version; } +mp_obj_t py_qrcode_ecc_level(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->ecc_level; } +mp_obj_t py_qrcode_mask(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->mask; } +mp_obj_t py_qrcode_data_type(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->data_type; } +mp_obj_t py_qrcode_eci(mp_obj_t self_in) { return ((py_qrcode_obj_t *) self_in)->eci; } +mp_obj_t py_qrcode_is_numeric(mp_obj_t self_in) { return mp_obj_new_bool(mp_obj_get_int(((py_qrcode_obj_t *) self_in)->data_type) == 1); } +mp_obj_t py_qrcode_is_alphanumeric(mp_obj_t self_in) { return mp_obj_new_bool(mp_obj_get_int(((py_qrcode_obj_t *) self_in)->data_type) == 2); } +mp_obj_t py_qrcode_is_binary(mp_obj_t self_in) { return mp_obj_new_bool(mp_obj_get_int(((py_qrcode_obj_t *) self_in)->data_type) == 4); } +mp_obj_t py_qrcode_is_kanji(mp_obj_t self_in) { return mp_obj_new_bool(mp_obj_get_int(((py_qrcode_obj_t *) self_in)->data_type) == 8); } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_corners_obj, py_qrcode_corners); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_rect_obj, py_qrcode_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_x_obj, py_qrcode_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_y_obj, py_qrcode_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_w_obj, py_qrcode_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_h_obj, py_qrcode_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_payload_obj, py_qrcode_payload); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_version_obj, py_qrcode_version); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_ecc_level_obj, py_qrcode_ecc_level); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_mask_obj, py_qrcode_mask); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_data_type_obj, py_qrcode_data_type); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_eci_obj, py_qrcode_eci); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_is_numeric_obj, py_qrcode_is_numeric); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_is_alphanumeric_obj, py_qrcode_is_alphanumeric); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_is_binary_obj, py_qrcode_is_binary); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_qrcode_is_kanji_obj, py_qrcode_is_kanji); + +STATIC const mp_rom_map_elem_t py_qrcode_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_corners), MP_ROM_PTR(&py_qrcode_corners_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_qrcode_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_qrcode_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_qrcode_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_qrcode_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_qrcode_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_payload), MP_ROM_PTR(&py_qrcode_payload_obj) }, + { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&py_qrcode_version_obj) }, + { MP_ROM_QSTR(MP_QSTR_ecc_level), MP_ROM_PTR(&py_qrcode_ecc_level_obj) }, + { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&py_qrcode_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_data_type), MP_ROM_PTR(&py_qrcode_data_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_eci), MP_ROM_PTR(&py_qrcode_eci_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_numeric), MP_ROM_PTR(&py_qrcode_is_numeric_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_alphanumeric), MP_ROM_PTR(&py_qrcode_is_alphanumeric_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_binary), MP_ROM_PTR(&py_qrcode_is_binary_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_kanji), MP_ROM_PTR(&py_qrcode_is_kanji_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_qrcode_locals_dict, py_qrcode_locals_dict_table); + +static const mp_obj_type_t py_qrcode_type = { + { &mp_type_type }, + .name = MP_QSTR_qrcode, + .print = py_qrcode_print, + .subscr = py_qrcode_subscr, + .locals_dict = (mp_obj_t) &py_qrcode_locals_dict +}; + +static mp_obj_t py_image_find_qrcodes(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + list_t out; + fb_alloc_mark(); + imlib_find_qrcodes(&out, arg_img, &roi); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_qrcodes_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_qrcode_obj_t *o = m_new_obj(py_qrcode_obj_t); + o->base.type = &py_qrcode_type; + o->corners = mp_obj_new_tuple(4, (mp_obj_t []) + {mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[0].x), mp_obj_new_int(lnk_data.corners[0].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[1].x), mp_obj_new_int(lnk_data.corners[1].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[2].x), mp_obj_new_int(lnk_data.corners[2].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[3].x), mp_obj_new_int(lnk_data.corners[3].y)})}); + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->payload = mp_obj_new_str(lnk_data.payload, lnk_data.payload_len); + o->version = mp_obj_new_int(lnk_data.version); + o->ecc_level = mp_obj_new_int(lnk_data.ecc_level); + o->mask = mp_obj_new_int(lnk_data.mask); + o->data_type = mp_obj_new_int(lnk_data.data_type); + o->eci = mp_obj_new_int(lnk_data.eci); + + objects_list->items[i] = o; + xfree(lnk_data.payload); + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_qrcodes_obj, 1, py_image_find_qrcodes); +#endif // IMLIB_ENABLE_QRCODES + +#ifdef IMLIB_ENABLE_APRILTAGS +// AprilTag Object // +#define py_apriltag_obj_size 18 +typedef struct py_apriltag_obj { + mp_obj_base_t base; + mp_obj_t corners; + mp_obj_t x, y, w, h, id, family, cx, cy, rotation, decision_margin, hamming, goodness; + mp_obj_t x_translation, y_translation, z_translation; + mp_obj_t x_rotation, y_rotation, z_rotation; +} py_apriltag_obj_t; + +static void py_apriltag_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_apriltag_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"id\":%d," + " \"family\":%d, \"cx\":%d, \"cy\":%d, \"rotation\":%f, \"decision_margin\":%f, \"hamming\":%d, \"goodness\":%f," + " \"x_translation\":%f, \"y_translation\":%f, \"z_translation\":%f," + " \"x_rotation\":%f, \"y_rotation\":%f, \"z_rotation\":%f}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_get_int(self->id), + mp_obj_get_int(self->family), + mp_obj_get_int(self->cx), + mp_obj_get_int(self->cy), + (double) mp_obj_get_float(self->rotation), + (double) mp_obj_get_float(self->decision_margin), + mp_obj_get_int(self->hamming), + (double) mp_obj_get_float(self->goodness), + (double) mp_obj_get_float(self->x_translation), + (double) mp_obj_get_float(self->y_translation), + (double) mp_obj_get_float(self->z_translation), + (double) mp_obj_get_float(self->x_rotation), + (double) mp_obj_get_float(self->y_rotation), + (double) mp_obj_get_float(self->z_rotation)); +} + +static mp_obj_t py_apriltag_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_apriltag_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_apriltag_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_apriltag_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->id; + case 5: return self->family; + case 6: return self->cx; + case 7: return self->cy; + case 8: return self->rotation; + case 9: return self->decision_margin; + case 10: return self->hamming; + case 11: return self->goodness; + case 12: return self->x_translation; + case 13: return self->y_translation; + case 14: return self->z_translation; + case 15: return self->x_rotation; + case 16: return self->y_rotation; + case 17: return self->z_rotation; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_apriltag_corners(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->corners; } +mp_obj_t py_apriltag_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_apriltag_obj_t *) self_in)->x, + ((py_apriltag_obj_t *) self_in)->y, + ((py_apriltag_obj_t *) self_in)->w, + ((py_apriltag_obj_t *) self_in)->h}); +} + +mp_obj_t py_apriltag_x(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->x; } +mp_obj_t py_apriltag_y(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->y; } +mp_obj_t py_apriltag_w(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->w; } +mp_obj_t py_apriltag_h(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->h; } +mp_obj_t py_apriltag_id(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->id; } +mp_obj_t py_apriltag_family(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->family; } +mp_obj_t py_apriltag_cx(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->cx; } +mp_obj_t py_apriltag_cy(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->cy; } +mp_obj_t py_apriltag_rotation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->rotation; } +mp_obj_t py_apriltag_decision_margin(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->decision_margin; } +mp_obj_t py_apriltag_hamming(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->hamming; } +mp_obj_t py_apriltag_goodness(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->goodness; } +mp_obj_t py_apriltag_x_translation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->x_translation; } +mp_obj_t py_apriltag_y_translation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->y_translation; } +mp_obj_t py_apriltag_z_translation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->z_translation; } +mp_obj_t py_apriltag_x_rotation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->x_rotation; } +mp_obj_t py_apriltag_y_rotation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->y_rotation; } +mp_obj_t py_apriltag_z_rotation(mp_obj_t self_in) { return ((py_apriltag_obj_t *) self_in)->z_rotation; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_corners_obj, py_apriltag_corners); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_rect_obj, py_apriltag_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_x_obj, py_apriltag_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_y_obj, py_apriltag_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_w_obj, py_apriltag_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_h_obj, py_apriltag_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_id_obj, py_apriltag_id); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_family_obj, py_apriltag_family); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_cx_obj, py_apriltag_cx); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_cy_obj, py_apriltag_cy); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_rotation_obj, py_apriltag_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_decision_margin_obj, py_apriltag_decision_margin); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_hamming_obj, py_apriltag_hamming); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_goodness_obj, py_apriltag_goodness); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_x_translation_obj, py_apriltag_x_translation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_y_translation_obj, py_apriltag_y_translation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_z_translation_obj, py_apriltag_z_translation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_x_rotation_obj, py_apriltag_x_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_y_rotation_obj, py_apriltag_y_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_apriltag_z_rotation_obj, py_apriltag_z_rotation); + +STATIC const mp_rom_map_elem_t py_apriltag_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_corners), MP_ROM_PTR(&py_apriltag_corners_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_apriltag_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_apriltag_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_apriltag_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_apriltag_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_apriltag_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&py_apriltag_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_family), MP_ROM_PTR(&py_apriltag_family_obj) }, + { MP_ROM_QSTR(MP_QSTR_cx), MP_ROM_PTR(&py_apriltag_cx_obj) }, + { MP_ROM_QSTR(MP_QSTR_cy), MP_ROM_PTR(&py_apriltag_cy_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_apriltag_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_decision_margin), MP_ROM_PTR(&py_apriltag_decision_margin_obj) }, + { MP_ROM_QSTR(MP_QSTR_hamming), MP_ROM_PTR(&py_apriltag_hamming_obj) }, + { MP_ROM_QSTR(MP_QSTR_goodness), MP_ROM_PTR(&py_apriltag_goodness_obj) }, + { MP_ROM_QSTR(MP_QSTR_x_translation), MP_ROM_PTR(&py_apriltag_x_translation_obj) }, + { MP_ROM_QSTR(MP_QSTR_y_translation), MP_ROM_PTR(&py_apriltag_y_translation_obj) }, + { MP_ROM_QSTR(MP_QSTR_z_translation), MP_ROM_PTR(&py_apriltag_z_translation_obj) }, + { MP_ROM_QSTR(MP_QSTR_x_rotation), MP_ROM_PTR(&py_apriltag_x_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_y_rotation), MP_ROM_PTR(&py_apriltag_y_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_z_rotation), MP_ROM_PTR(&py_apriltag_z_rotation_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_apriltag_locals_dict, py_apriltag_locals_dict_table); + +static const mp_obj_type_t py_apriltag_type = { + { &mp_type_type }, + .name = MP_QSTR_apriltag, + .print = py_apriltag_print, + .subscr = py_apriltag_subscr, + .locals_dict = (mp_obj_t) &py_apriltag_locals_dict +}; + +static mp_obj_t py_image_find_apriltags(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + PY_ASSERT_TRUE_MSG((roi.w * roi.h) < 65536, "The maximum supported resolution for find_apriltags() is < 64K pixels."); + if ((roi.w < 4) || (roi.h < 4)) { + return mp_obj_new_list(0, NULL); + } + + apriltag_families_t families = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_families), TAG36H11); + // 2.8mm Focal Length w/ OV7725 sensor for reference. + float fx = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fx), (2.8 / 3.984) * arg_img->w); + // 2.8mm Focal Length w/ OV7725 sensor for reference. + float fy = py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fy), (2.8 / 2.952) * arg_img->h); + // Use the image versus the roi here since the image should be projected from the camera center. + float cx = py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cx), arg_img->w * 0.5); + // Use the image versus the roi here since the image should be projected from the camera center. + float cy = py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cy), arg_img->h * 0.5); + + list_t out; + fb_alloc_mark(); + imlib_find_apriltags(&out, arg_img, &roi, families, fx, fy, cx, cy); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_apriltags_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_apriltag_obj_t *o = m_new_obj(py_apriltag_obj_t); + o->base.type = &py_apriltag_type; + o->corners = mp_obj_new_tuple(4, (mp_obj_t []) + {mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[0].x), mp_obj_new_int(lnk_data.corners[0].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[1].x), mp_obj_new_int(lnk_data.corners[1].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[2].x), mp_obj_new_int(lnk_data.corners[2].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[3].x), mp_obj_new_int(lnk_data.corners[3].y)})}); + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->id = mp_obj_new_int(lnk_data.id); + o->family = mp_obj_new_int(lnk_data.family); + o->cx = mp_obj_new_int(lnk_data.centroid.x); + o->cy = mp_obj_new_int(lnk_data.centroid.y); + o->rotation = mp_obj_new_float(lnk_data.z_rotation); + o->decision_margin = mp_obj_new_float(lnk_data.decision_margin); + o->hamming = mp_obj_new_int(lnk_data.hamming); + o->goodness = mp_obj_new_float(lnk_data.goodness); + o->x_translation = mp_obj_new_float(lnk_data.x_translation); + o->y_translation = mp_obj_new_float(lnk_data.y_translation); + o->z_translation = mp_obj_new_float(lnk_data.z_translation); + o->x_rotation = mp_obj_new_float(lnk_data.x_rotation); + o->y_rotation = mp_obj_new_float(lnk_data.y_rotation); + o->z_rotation = mp_obj_new_float(lnk_data.z_rotation); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_apriltags_obj, 1, py_image_find_apriltags); +#endif // IMLIB_ENABLE_APRILTAGS + +#ifdef IMLIB_ENABLE_DATAMATRICES +// DataMatrix Object // +#define py_datamatrix_obj_size 10 +typedef struct py_datamatrix_obj { + mp_obj_base_t base; + mp_obj_t corners; + mp_obj_t x, y, w, h, payload, rotation, rows, columns, capacity, padding; +} py_datamatrix_obj_t; + +static void py_datamatrix_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_datamatrix_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"rotation\":%f, \"rows\":%d, \"columns\":%d, \"capacity\":%d, \"padding\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_str_get_str(self->payload), + (double) mp_obj_get_float(self->rotation), + mp_obj_get_int(self->rows), + mp_obj_get_int(self->columns), + mp_obj_get_int(self->capacity), + mp_obj_get_int(self->padding)); +} + +static mp_obj_t py_datamatrix_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_datamatrix_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_datamatrix_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_datamatrix_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->payload; + case 5: return self->rotation; + case 6: return self->rows; + case 7: return self->columns; + case 8: return self->capacity; + case 9: return self->padding; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_datamatrix_corners(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->corners; } +mp_obj_t py_datamatrix_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_datamatrix_obj_t *) self_in)->x, + ((py_datamatrix_obj_t *) self_in)->y, + ((py_datamatrix_obj_t *) self_in)->w, + ((py_datamatrix_obj_t *) self_in)->h}); +} + +mp_obj_t py_datamatrix_x(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->x; } +mp_obj_t py_datamatrix_y(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->y; } +mp_obj_t py_datamatrix_w(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->w; } +mp_obj_t py_datamatrix_h(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->h; } +mp_obj_t py_datamatrix_payload(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->payload; } +mp_obj_t py_datamatrix_rotation(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->rotation; } +mp_obj_t py_datamatrix_rows(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->rows; } +mp_obj_t py_datamatrix_columns(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->columns; } +mp_obj_t py_datamatrix_capacity(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->capacity; } +mp_obj_t py_datamatrix_padding(mp_obj_t self_in) { return ((py_datamatrix_obj_t *) self_in)->padding; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_corners_obj, py_datamatrix_corners); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_rect_obj, py_datamatrix_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_x_obj, py_datamatrix_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_y_obj, py_datamatrix_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_w_obj, py_datamatrix_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_h_obj, py_datamatrix_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_payload_obj, py_datamatrix_payload); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_rotation_obj, py_datamatrix_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_rows_obj, py_datamatrix_rows); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_columns_obj, py_datamatrix_columns); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_capacity_obj, py_datamatrix_capacity); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_datamatrix_padding_obj, py_datamatrix_padding); + +STATIC const mp_rom_map_elem_t py_datamatrix_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_corners), MP_ROM_PTR(&py_datamatrix_corners_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_datamatrix_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_datamatrix_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_datamatrix_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_datamatrix_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_datamatrix_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_payload), MP_ROM_PTR(&py_datamatrix_payload_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_datamatrix_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_rows), MP_ROM_PTR(&py_datamatrix_rows_obj) }, + { MP_ROM_QSTR(MP_QSTR_columns), MP_ROM_PTR(&py_datamatrix_columns_obj) }, + { MP_ROM_QSTR(MP_QSTR_capacity), MP_ROM_PTR(&py_datamatrix_capacity_obj) }, + { MP_ROM_QSTR(MP_QSTR_padding), MP_ROM_PTR(&py_datamatrix_padding_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_datamatrix_locals_dict, py_datamatrix_locals_dict_table); + +static const mp_obj_type_t py_datamatrix_type = { + { &mp_type_type }, + .name = MP_QSTR_datamatrix, + .print = py_datamatrix_print, + .subscr = py_datamatrix_subscr, + .locals_dict = (mp_obj_t) &py_datamatrix_locals_dict +}; + +static mp_obj_t py_image_find_datamatrices(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + int effort = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_effort), 200); + + list_t out; + fb_alloc_mark(); + imlib_find_datamatrices(&out, arg_img, &roi, effort); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_datamatrices_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_datamatrix_obj_t *o = m_new_obj(py_datamatrix_obj_t); + o->base.type = &py_datamatrix_type; + o->corners = mp_obj_new_tuple(4, (mp_obj_t []) + {mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[0].x), mp_obj_new_int(lnk_data.corners[0].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[1].x), mp_obj_new_int(lnk_data.corners[1].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[2].x), mp_obj_new_int(lnk_data.corners[2].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[3].x), mp_obj_new_int(lnk_data.corners[3].y)})}); + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->payload = mp_obj_new_str(lnk_data.payload, lnk_data.payload_len); + o->rotation = mp_obj_new_float(IM_DEG2RAD(lnk_data.rotation)); + o->rows = mp_obj_new_int(lnk_data.rows); + o->columns = mp_obj_new_int(lnk_data.columns); + o->capacity = mp_obj_new_int(lnk_data.capacity); + o->padding = mp_obj_new_int(lnk_data.padding); + + objects_list->items[i] = o; + xfree(lnk_data.payload); + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_datamatrices_obj, 1, py_image_find_datamatrices); +#endif // IMLIB_ENABLE_DATAMATRICES + +#ifdef IMLIB_ENABLE_BARCODES +// BarCode Object // +#define py_barcode_obj_size 8 +typedef struct py_barcode_obj { + mp_obj_base_t base; + mp_obj_t corners; + mp_obj_t x, y, w, h, payload, type, rotation, quality; +} py_barcode_obj_t; + +static void py_barcode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_barcode_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"type\":%d, \"rotation\":%f, \"quality\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_str_get_str(self->payload), + mp_obj_get_int(self->type), + (double) mp_obj_get_float(self->rotation), + mp_obj_get_int(self->quality)); +} + +static mp_obj_t py_barcode_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_barcode_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_barcode_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_barcode_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->payload; + case 5: return self->type; + case 6: return self->rotation; + case 7: return self->quality; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_barcode_corners(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->corners; } +mp_obj_t py_barcode_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_barcode_obj_t *) self_in)->x, + ((py_barcode_obj_t *) self_in)->y, + ((py_barcode_obj_t *) self_in)->w, + ((py_barcode_obj_t *) self_in)->h}); +} + +mp_obj_t py_barcode_x(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->x; } +mp_obj_t py_barcode_y(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->y; } +mp_obj_t py_barcode_w(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->w; } +mp_obj_t py_barcode_h(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->h; } +mp_obj_t py_barcode_payload_fun(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->payload; } +mp_obj_t py_barcode_type_fun(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->type; } +mp_obj_t py_barcode_rotation_fun(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->rotation; } +mp_obj_t py_barcode_quality_fun(mp_obj_t self_in) { return ((py_barcode_obj_t *) self_in)->quality; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_corners_obj, py_barcode_corners); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_rect_obj, py_barcode_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_x_obj, py_barcode_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_y_obj, py_barcode_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_w_obj, py_barcode_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_h_obj, py_barcode_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_payload_fun_obj, py_barcode_payload_fun); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_type_fun_obj, py_barcode_type_fun); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_rotation_fun_obj, py_barcode_rotation_fun); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_barcode_quality_fun_obj, py_barcode_quality_fun); + +STATIC const mp_rom_map_elem_t py_barcode_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_corners), MP_ROM_PTR(&py_barcode_corners_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_barcode_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_barcode_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_barcode_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_barcode_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_barcode_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_payload), MP_ROM_PTR(&py_barcode_payload_fun_obj) }, + { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_barcode_type_fun_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_barcode_rotation_fun_obj) }, + { MP_ROM_QSTR(MP_QSTR_quality), MP_ROM_PTR(&py_barcode_quality_fun_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_barcode_locals_dict, py_barcode_locals_dict_table); + +static const mp_obj_type_t py_barcode_type = { + { &mp_type_type }, + .name = MP_QSTR_barcode, + .print = py_barcode_print, + .subscr = py_barcode_subscr, + .locals_dict = (mp_obj_t) &py_barcode_locals_dict +}; + +static mp_obj_t py_image_find_barcodes(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + list_t out; + fb_alloc_mark(); + imlib_find_barcodes(&out, arg_img, &roi); + fb_alloc_free_till_mark(); + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + for (size_t i = 0; list_size(&out); i++) { + find_barcodes_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_barcode_obj_t *o = m_new_obj(py_barcode_obj_t); + o->base.type = &py_barcode_type; + o->corners = mp_obj_new_tuple(4, (mp_obj_t []) + {mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[0].x), mp_obj_new_int(lnk_data.corners[0].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[1].x), mp_obj_new_int(lnk_data.corners[1].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[2].x), mp_obj_new_int(lnk_data.corners[2].y)}), + mp_obj_new_tuple(2, (mp_obj_t []) {mp_obj_new_int(lnk_data.corners[3].x), mp_obj_new_int(lnk_data.corners[3].y)})}); + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->payload = mp_obj_new_str(lnk_data.payload, lnk_data.payload_len); + o->type = mp_obj_new_int(lnk_data.type); + o->rotation = mp_obj_new_float(IM_DEG2RAD(lnk_data.rotation)); + o->quality = mp_obj_new_int(lnk_data.quality); + + objects_list->items[i] = o; + xfree(lnk_data.payload); + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_barcodes_obj, 1, py_image_find_barcodes); +#endif // IMLIB_ENABLE_BARCODES + +#ifdef IMLIB_ENABLE_FIND_DISPLACEMENT +// Displacement Object // +#define py_displacement_obj_size 5 +typedef struct py_displacement_obj { + mp_obj_base_t base; + mp_obj_t x_translation, y_translation, rotation, scale, response; +} py_displacement_obj_t; + +static void py_displacement_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_displacement_obj_t *self = self_in; + mp_printf(print, + "{\"x_translation\":%f, \"y_translation\":%f, \"rotation\":%f, \"scale\":%f, \"response\":%f}", + (double) mp_obj_get_float(self->x_translation), + (double) mp_obj_get_float(self->y_translation), + (double) mp_obj_get_float(self->rotation), + (double) mp_obj_get_float(self->scale), + (double) mp_obj_get_float(self->response)); +} + +static mp_obj_t py_displacement_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_displacement_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_displacement_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x_translation) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_displacement_obj_size, index, false)) { + case 0: return self->x_translation; + case 1: return self->y_translation; + case 2: return self->rotation; + case 3: return self->scale; + case 4: return self->response; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_displacement_x_translation(mp_obj_t self_in) { return ((py_displacement_obj_t *) self_in)->x_translation; } +mp_obj_t py_displacement_y_translation(mp_obj_t self_in) { return ((py_displacement_obj_t *) self_in)->y_translation; } +mp_obj_t py_displacement_rotation(mp_obj_t self_in) { return ((py_displacement_obj_t *) self_in)->rotation; } +mp_obj_t py_displacement_scale(mp_obj_t self_in) { return ((py_displacement_obj_t *) self_in)->scale; } +mp_obj_t py_displacement_response(mp_obj_t self_in) { return ((py_displacement_obj_t *) self_in)->response; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_displacement_x_translation_obj, py_displacement_x_translation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_displacement_y_translation_obj, py_displacement_y_translation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_displacement_rotation_obj, py_displacement_rotation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_displacement_scale_obj, py_displacement_scale); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_displacement_response_obj, py_displacement_response); + +STATIC const mp_rom_map_elem_t py_displacement_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x_translation), MP_ROM_PTR(&py_displacement_x_translation_obj) }, + { MP_ROM_QSTR(MP_QSTR_y_translation), MP_ROM_PTR(&py_displacement_y_translation_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_displacement_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&py_displacement_scale_obj) }, + { MP_ROM_QSTR(MP_QSTR_response), MP_ROM_PTR(&py_displacement_response_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_displacement_locals_dict, py_displacement_locals_dict_table); + +static const mp_obj_type_t py_displacement_type = { + { &mp_type_type }, + .name = MP_QSTR_displacement, + .print = py_displacement_print, + .subscr = py_displacement_subscr, + .locals_dict = (mp_obj_t) &py_displacement_locals_dict +}; + +static mp_obj_t py_image_find_displacement(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + image_t *arg_template_img = py_helper_arg_to_image_mutable(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); + + rectangle_t template_roi; + py_helper_keyword_rectangle(arg_template_img, n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_template_roi), &template_roi); + + PY_ASSERT_FALSE_MSG((roi.w != template_roi.w) || (roi.h != template_roi.h), "ROI(w,h) != TEMPLATE_ROI(w,h)"); + + bool logpolar = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_logpolar), false); + bool fix_rotation_scale = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fix_rotation_scale), false); + + float x, y, r, s, response; + fb_alloc_mark(); + imlib_phasecorrelate(arg_img, arg_template_img, &roi, &template_roi, logpolar, fix_rotation_scale, &x, &y, &r, &s, &response); + fb_alloc_free_till_mark(); + + py_displacement_obj_t *o = m_new_obj(py_displacement_obj_t); + o->base.type = &py_displacement_type; + o->x_translation = mp_obj_new_float(x); + o->y_translation = mp_obj_new_float(y); + o->rotation = mp_obj_new_float(r); + o->scale = mp_obj_new_float(s); + o->response = mp_obj_new_float(response); + + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_displacement_obj, 2, py_image_find_displacement); +#endif // IMLIB_ENABLE_FIND_DISPLACEMENT + +static mp_obj_t py_image_find_template(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + image_t *arg_template = py_helper_arg_to_image_grayscale(args[1]); + float arg_thresh = mp_obj_get_float(args[2]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + // Make sure ROI is bigger than or equal to template size + PY_ASSERT_TRUE_MSG((roi.w >= arg_template->w && roi.h >= arg_template->h), + "Region of interest is smaller than template!"); + + // Make sure ROI is smaller than or equal to image size + PY_ASSERT_TRUE_MSG(((roi.x + roi.w) <= arg_img->w && (roi.y + roi.h) <= arg_img->h), + "Region of interest is bigger than image!"); + + int step = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_step), 2); + int search = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_search), SEARCH_EX); + + // Find template + rectangle_t r; + float corr; + if (search == SEARCH_DS) { + corr = imlib_template_match_ds(arg_img, arg_template, &r); + } else { + corr = imlib_template_match_ex(arg_img, arg_template, &roi, step, &r); + } + + if (corr > arg_thresh) { + mp_obj_t rec_obj[4] = { + mp_obj_new_int(r.x), + mp_obj_new_int(r.y), + mp_obj_new_int(r.w), + mp_obj_new_int(r.h) + }; + return mp_obj_new_tuple(4, rec_obj); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_template_obj, 3, py_image_find_template); + +static mp_obj_t py_image_find_features(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + cascade_t *cascade = py_cascade_cobj(args[1]); + cascade->threshold = py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0.5f); + cascade->scale_factor = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 4, kw_args, &roi); + + // Make sure ROI is bigger than feature size + PY_ASSERT_TRUE_MSG((roi.w > cascade->window.w && roi.h > cascade->window.h), + "Region of interest is smaller than detector window!"); + + // Detect objects + array_t *objects_array = imlib_detect_objects(arg_img, cascade, &roi); + + // Add detected objects to a new Python list... + mp_obj_t objects_list = mp_obj_new_list(0, NULL); + for (int i=0; ix), + mp_obj_new_int(r->y), + mp_obj_new_int(r->w), + mp_obj_new_int(r->h), + }; + mp_obj_list_append(objects_list, mp_obj_new_tuple(4, rec_obj)); + } + array_free(objects_array); + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_features_obj, 2, py_image_find_features); + +static mp_obj_t py_image_find_eye(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + point_t iris; + imlib_find_iris(arg_img, &iris, &roi); + + mp_obj_t eye_obj[2] = { + mp_obj_new_int(iris.x), + mp_obj_new_int(iris.y), + }; + + return mp_obj_new_tuple(2, eye_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_eye_obj, 2, py_image_find_eye); + +static mp_obj_t py_image_find_lbp(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + py_lbp_obj_t *lbp_obj = m_new_obj(py_lbp_obj_t); + lbp_obj->base.type = &py_lbp_type; + lbp_obj->hist = imlib_lbp_desc(arg_img, &roi); + return lbp_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lbp_obj, 2, py_image_find_lbp); + +static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + int threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 20); + bool normalized = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_normalized), false); + float scale_factor = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); + int max_keypoints = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_keypoints), 100); + corner_detector_t corner_detector = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_corner_detector), CORNER_AGAST); + + #ifndef IMLIB_ENABLE_FAST + // Force AGAST when FAST is disabled. + corner_detector = CORNER_AGAST; + #endif + + // Find keypoints + array_t *kpts = orb_find_keypoints(arg_img, normalized, threshold, scale_factor, max_keypoints, corner_detector, &roi); + + if (array_length(kpts)) { + py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t); + kp_obj->base.type = &py_kp_type; + kp_obj->kpts = kpts; + kp_obj->threshold = threshold; + kp_obj->normalized = normalized; + return kp_obj; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); + +#ifdef IMLIB_ENABLE_BINARY_OPS +static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + edge_detector_t edge_type = mp_obj_get_int(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); + + int thresh[2] = {100, 200}; + mp_obj_t thresh_obj = py_helper_keyword_object(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold)); + + if (thresh_obj) { + mp_obj_t *thresh_array; + mp_obj_get_array_fixed_n(thresh_obj, 2, &thresh_array); + thresh[0] = mp_obj_get_int(thresh_array[0]); + thresh[1] = mp_obj_get_int(thresh_array[1]); + } + + switch (edge_type) { + case EDGE_SIMPLE: { + imlib_edge_simple(arg_img, &roi, thresh[0], thresh[1]); + break; + } + case EDGE_CANNY: { + imlib_edge_canny(arg_img, &roi, thresh[0], thresh[1]); + break; + } + + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges); +#endif + +#ifdef IMLIB_ENABLE_HOG +static mp_obj_t py_image_find_hog(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + int size = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 8); + + imlib_find_hog(arg_img, &roi, size); + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_hog_obj, 1, py_image_find_hog); +#endif // IMLIB_ENABLE_HOG + +#ifdef IMLIB_ENABLE_SELECTIVE_SEARCH +static mp_obj_t py_image_selective_search(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *img = py_helper_arg_to_image_mutable(args[0]); + int t = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 500); + int s = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 20); + float a1 = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a1), 1.0f); + float a2 = py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a1), 1.0f); + float a3 = py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a1), 1.0f); + array_t *proposals_array = imlib_selective_search(img, t, s, a1, a2, a3); + + // Add proposals to a new Python list... + mp_obj_t proposals_list = mp_obj_new_list(0, NULL); + for (int i=0; ix), + mp_obj_new_int(r->y), + mp_obj_new_int(r->w), + mp_obj_new_int(r->h), + }; + mp_obj_list_append(proposals_list, mp_obj_new_tuple(4, rec_obj)); + } + + array_free(proposals_array); + return proposals_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_selective_search_obj, 1, py_image_selective_search); +#endif // IMLIB_ENABLE_SELECTIVE_SEARCH + +static const mp_rom_map_elem_t locals_dict_table[] = { + /* Basic Methods */ + {MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&py_image_width_obj)}, + {MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&py_image_height_obj)}, + {MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&py_image_format_obj)}, + {MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_image_size_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(&py_image_get_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&py_image_set_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_mean_pool), MP_ROM_PTR(&py_image_mean_pool_obj)}, + {MP_ROM_QSTR(MP_QSTR_mean_pooled), MP_ROM_PTR(&py_image_mean_pooled_obj)}, + {MP_ROM_QSTR(MP_QSTR_midpoint_pool), MP_ROM_PTR(&py_image_midpoint_pool_obj)}, + {MP_ROM_QSTR(MP_QSTR_midpoint_pooled), MP_ROM_PTR(&py_image_midpoint_pooled_obj)}, + {MP_ROM_QSTR(MP_QSTR_to_bitmap), MP_ROM_PTR(&py_image_to_bitmap_obj)}, + {MP_ROM_QSTR(MP_QSTR_to_grayscale), MP_ROM_PTR(&py_image_to_grayscale_obj)}, + {MP_ROM_QSTR(MP_QSTR_to_rgb565), MP_ROM_PTR(&py_image_to_rgb565_obj)}, + {MP_ROM_QSTR(MP_QSTR_to_rainbow), MP_ROM_PTR(&py_image_to_rainbow_obj)}, + {MP_ROM_QSTR(MP_QSTR_compress), MP_ROM_PTR(&py_image_compress_obj)}, + {MP_ROM_QSTR(MP_QSTR_compress_for_ide), MP_ROM_PTR(&py_image_compress_for_ide_obj)}, + {MP_ROM_QSTR(MP_QSTR_compressed), MP_ROM_PTR(&py_image_compressed_obj)}, + {MP_ROM_QSTR(MP_QSTR_compressed_for_ide), MP_ROM_PTR(&py_image_compressed_for_ide_obj)}, + {MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&py_image_copy_obj)}, + {MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&py_image_save_obj)}, + /* Drawing Methods */ + {MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&py_image_clear_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&py_image_draw_line_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_rectangle), MP_ROM_PTR(&py_image_draw_rectangle_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&py_image_draw_circle_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&py_image_draw_string_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_cross), MP_ROM_PTR(&py_image_draw_cross_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_arrow), MP_ROM_PTR(&py_image_draw_arrow_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_image), MP_ROM_PTR(&py_image_draw_image_obj)}, +#ifdef IMLIB_ENABLE_FLOOD_FILL + {MP_ROM_QSTR(MP_QSTR_flood_fill), MP_ROM_PTR(&py_image_flood_fill_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_flood_fill), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + {MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)}, + /* Binary Methods */ +#ifdef IMLIB_ENABLE_BINARY_OPS + {MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)}, + {MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&py_image_invert_obj)}, + {MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_image_b_and_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_and), MP_ROM_PTR(&py_image_b_and_obj)}, + {MP_ROM_QSTR(MP_QSTR_nand), MP_ROM_PTR(&py_image_b_nand_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nand), MP_ROM_PTR(&py_image_b_nand_obj)}, + {MP_ROM_QSTR(MP_QSTR_or), MP_ROM_PTR(&py_image_b_or_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_or), MP_ROM_PTR(&py_image_b_or_obj)}, + {MP_ROM_QSTR(MP_QSTR_nor), MP_ROM_PTR(&py_image_b_nor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nor), MP_ROM_PTR(&py_image_b_nor_obj)}, + {MP_ROM_QSTR(MP_QSTR_xor), MP_ROM_PTR(&py_image_b_xor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xor), MP_ROM_PTR(&py_image_b_xor_obj)}, + {MP_ROM_QSTR(MP_QSTR_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)}, + {MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_image_erode_obj)}, + {MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_image_dilate_obj)}, + {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_image_open_obj)}, + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_image_close_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_and), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_nand), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nand), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_or), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_or), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_nor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_xor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_xnor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_MATH_OPS + {MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_image_top_hat_obj)}, + {MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_image_black_hat_obj)}, + /* Math Methods */ + {MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)}, + {MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)}, + {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_image_add_obj)}, + {MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&py_image_sub_obj)}, + {MP_ROM_QSTR(MP_QSTR_mul), MP_ROM_PTR(&py_image_mul_obj)}, + {MP_ROM_QSTR(MP_QSTR_div), MP_ROM_PTR(&py_image_div_obj)}, + {MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_image_min_obj)}, + {MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_image_max_obj)}, + {MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&py_image_difference_obj)}, + {MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&py_image_blend_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_mul), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_div), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + /* Filtering Methods */ + {MP_ROM_QSTR(MP_QSTR_histeq), MP_ROM_PTR(&py_image_histeq_obj)}, +#ifdef IMLIB_ENABLE_MEAN + {MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_image_mean_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_MEDIAN + {MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&py_image_median_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_MODE + {MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&py_image_mode_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_MIDPOINT + {MP_ROM_QSTR(MP_QSTR_midpoint), MP_ROM_PTR(&py_image_midpoint_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_midpoint), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_MORPH + {MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&py_image_morph_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_GAUSSIAN + {MP_ROM_QSTR(MP_QSTR_blur), MP_ROM_PTR(&py_image_gaussian_obj)}, + {MP_ROM_QSTR(MP_QSTR_gaussian), MP_ROM_PTR(&py_image_gaussian_obj)}, + {MP_ROM_QSTR(MP_QSTR_gaussian_blur), MP_ROM_PTR(&py_image_gaussian_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_blur), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_gaussian), MP_ROM_PTR(&py_func_unavailable_obj)}, + {MP_ROM_QSTR(MP_QSTR_gaussian_blur), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_LAPLACIAN + {MP_ROM_QSTR(MP_QSTR_laplacian), MP_ROM_PTR(&py_image_laplacian_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_laplacian), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_BILATERAL + {MP_ROM_QSTR(MP_QSTR_bilateral), MP_ROM_PTR(&py_image_bilateral_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_bilateral), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_CARTOON + {MP_ROM_QSTR(MP_QSTR_cartoon), MP_ROM_PTR(&py_image_cartoon_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_cartoon), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + /* Shadow Removal Methods */ +#ifdef IMLIB_ENABLE_REMOVE_SHADOWS + {MP_ROM_QSTR(MP_QSTR_remove_shadows), MP_ROM_PTR(&py_image_remove_shadows_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_remove_shadows), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_CHROMINVAR + {MP_ROM_QSTR(MP_QSTR_chrominvar), MP_ROM_PTR(&py_image_chrominvar_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_chrominvar), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_ILLUMINVAR + {MP_ROM_QSTR(MP_QSTR_illuminvar), MP_ROM_PTR(&py_image_illuminvar_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_illuminvar), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + /* Geometric Methods */ +#ifdef IMLIB_ENABLE_LINPOLAR + {MP_ROM_QSTR(MP_QSTR_linpolar), MP_ROM_PTR(&py_image_linpolar_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_linpolar), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_LOGPOLAR + {MP_ROM_QSTR(MP_QSTR_logpolar), MP_ROM_PTR(&py_image_logpolar_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_logpolar), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + {MP_ROM_QSTR(MP_QSTR_lens_corr), MP_ROM_PTR(&py_image_lens_corr_obj)}, +#ifdef IMLIB_ENABLE_ROTATION_CORR + {MP_ROM_QSTR(MP_QSTR_rotation_corr), MP_ROM_PTR(&py_image_rotation_corr_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_rotation_corr), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + /* Get Methods */ +#ifdef IMLIB_ENABLE_GET_SIMILARITY + {MP_ROM_QSTR(MP_QSTR_get_similarity), MP_ROM_PTR(&py_image_get_similarity_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_get_similarity), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + {MP_ROM_QSTR(MP_QSTR_get_hist), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_histogram), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_histogram), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_stats), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_statistics), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_statistics), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_regression), MP_ROM_PTR(&py_image_get_regression_obj)}, + /* Find Methods */ + {MP_ROM_QSTR(MP_QSTR_find_blobs), MP_ROM_PTR(&py_image_find_blobs_obj)}, +#ifdef IMLIB_ENABLE_FIND_LINES + {MP_ROM_QSTR(MP_QSTR_find_lines), MP_ROM_PTR(&py_image_find_lines_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_lines), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS + {MP_ROM_QSTR(MP_QSTR_find_line_segments), MP_ROM_PTR(&py_image_find_line_segments_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_line_segments), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_FIND_CIRCLES + {MP_ROM_QSTR(MP_QSTR_find_circles), MP_ROM_PTR(&py_image_find_circles_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_circles), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_FIND_RECTS + {MP_ROM_QSTR(MP_QSTR_find_rects), MP_ROM_PTR(&py_image_find_rects_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_rects), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_QRCODES + {MP_ROM_QSTR(MP_QSTR_find_qrcodes), MP_ROM_PTR(&py_image_find_qrcodes_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_qrcodes), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_APRILTAGS + {MP_ROM_QSTR(MP_QSTR_find_apriltags), MP_ROM_PTR(&py_image_find_apriltags_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_apriltags), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_DATAMATRICES + {MP_ROM_QSTR(MP_QSTR_find_datamatrices), MP_ROM_PTR(&py_image_find_datamatrices_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_datamatrices), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_BARCODES + {MP_ROM_QSTR(MP_QSTR_find_barcodes), MP_ROM_PTR(&py_image_find_barcodes_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_barcodes), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_FIND_DISPLACEMENT + {MP_ROM_QSTR(MP_QSTR_find_displacement), MP_ROM_PTR(&py_image_find_displacement_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_displacement), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif + {MP_ROM_QSTR(MP_QSTR_find_template), MP_ROM_PTR(&py_image_find_template_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_features), MP_ROM_PTR(&py_image_find_features_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_eye), MP_ROM_PTR(&py_image_find_eye_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_lbp), MP_ROM_PTR(&py_image_find_lbp_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_keypoints), MP_ROM_PTR(&py_image_find_keypoints_obj)}, +#ifdef IMLIB_ENABLE_BINARY_OPS + {MP_ROM_QSTR(MP_QSTR_find_edges), MP_ROM_PTR(&py_image_find_edges_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_edges), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_HOG + {MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_image_find_hog_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +#ifdef IMLIB_ENABLE_SELECTIVE_SEARCH + {MP_ROM_QSTR(MP_QSTR_selective_search), MP_ROM_PTR(&py_image_selective_search_obj)}, +#else + {MP_ROM_QSTR(MP_QSTR_selective_search), MP_ROM_PTR(&py_func_unavailable_obj)}, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +static const mp_obj_type_t py_image_type = { + { &mp_type_type }, + .name = MP_QSTR_Image, + .print = py_image_print, + .buffer_p = { .get_buffer = py_image_get_buffer }, + .subscr = py_image_subscr, + .locals_dict = (mp_obj_t) &locals_dict +}; + +// ImageWriter Object // +typedef struct py_imagewriter_obj { + mp_obj_base_t base; + FIL fp; + uint32_t ms; +} py_imagewriter_obj_t; + +static void py_imagewriter_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_imagewriter_obj_t *self = self_in; + mp_printf(print, "{\"size\":%d}", f_size(&self->fp)); +} + +mp_obj_t py_imagewriter_size(mp_obj_t self_in) +{ + return mp_obj_new_int(f_size(&((py_imagewriter_obj_t *) self_in)->fp)); +} + +mp_obj_t py_imagewriter_add_frame(mp_obj_t self_in, mp_obj_t img_obj) +{ + // Don't use the file buffer here... + + FIL *fp = &((py_imagewriter_obj_t *) self_in)->fp; + PY_ASSERT_TYPE(img_obj, &py_image_type); + image_t *arg_img = &((py_image_obj_t *) img_obj)->_cobj; + + //uint32_t ms = systick_current_millis(); // Write out elapsed ms. hutu + uint32_t ms = 0; + write_long(fp, ms - ((py_imagewriter_obj_t *) self_in)->ms); + ((py_imagewriter_obj_t *) self_in)->ms = ms; + + write_long(fp, arg_img->w); + write_long(fp, arg_img->h); + write_long(fp, arg_img->bpp); + + uint32_t size = image_size(arg_img); + + write_data(fp, arg_img->data, size); + if (size % 16) write_data(fp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16 - (size % 16)); // Pad to multiple of 16 bytes. + return self_in; +} + +mp_obj_t py_imagewriter_close(mp_obj_t self_in) +{ + file_close(&((py_imagewriter_obj_t *) self_in)->fp); + return self_in; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagewriter_size_obj, py_imagewriter_size); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_imagewriter_add_frame_obj, py_imagewriter_add_frame); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagewriter_close_obj, py_imagewriter_close); + +STATIC const mp_rom_map_elem_t py_imagewriter_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_imagewriter_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_frame), MP_ROM_PTR(&py_imagewriter_add_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagewriter_close_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_imagewriter_locals_dict, py_imagewriter_locals_dict_table); + +static const mp_obj_type_t py_imagewriter_type = { + { &mp_type_type }, + .name = MP_QSTR_imagewriter, + .print = py_imagewriter_print, + .locals_dict = (mp_obj_t) &py_imagewriter_locals_dict +}; + +mp_obj_t py_image_imagewriter(mp_obj_t path) +{ + py_imagewriter_obj_t *obj = m_new_obj(py_imagewriter_obj_t); + obj->base.type = &py_imagewriter_type; + file_write_open(&obj->fp, mp_obj_str_get_str(path)); + + write_long(&obj->fp, *((uint32_t *) "OMV ")); // OpenMV + write_long(&obj->fp, *((uint32_t *) "IMG ")); // Image + write_long(&obj->fp, *((uint32_t *) "STR ")); // Stream + write_long(&obj->fp, *((uint32_t *) "V1.0")); // v1.0 + + //obj->ms = systick_current_millis(); hutu + obj->ms = 0; + return obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagewriter_obj, py_image_imagewriter); + +// ImageReader Object // +typedef struct py_imagereader_obj { + mp_obj_base_t base; + FIL fp; + uint32_t ms; +} py_imagereader_obj_t; + +static void py_imagereader_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_imagereader_obj_t *self = self_in; + mp_printf(print, "{\"size\":%d}", f_size(&self->fp)); +} + +mp_obj_t py_imagereader_size(mp_obj_t self_in) +{ + return mp_obj_new_int(f_size(&((py_imagereader_obj_t *) self_in)->fp)); +} + +mp_obj_t py_imagereader_next_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + // Don't use the file buffer here... + + bool copy_to_fb = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), true); + if (copy_to_fb) fb_update_jpeg_buffer(); + + FIL *fp = &((py_imagereader_obj_t *) args[0])->fp; + image_t image = {0}; + + if (f_eof(fp)) { + if (!py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true)) { + return mp_const_none; + } + + file_seek(fp, 16); // skip past the header + + if (f_eof(fp)) { // empty file + return mp_const_none; + } + } + + + uint32_t ms_tmp; + read_long(fp, &ms_tmp); +#if 0 //hutu + + uint32_t ms; // Wait for elapsed ms. + for (ms = systick_current_millis(); + ((ms - ((py_imagewriter_obj_t *) args[0])->ms) < ms_tmp); + ms = systick_current_millis()) { + __WFI(); + } + + ((py_imagewriter_obj_t *) args[0])->ms = ms; +#endif + read_long(fp, (uint32_t *) &image.w); + read_long(fp, (uint32_t *) &image.h); + read_long(fp, (uint32_t *) &image.bpp); + + uint32_t size = image_size(&image); + + if (copy_to_fb) { + PY_ASSERT_TRUE_MSG((size <= OMV_RAW_BUF_SIZE), "FB Overflow!"); + image.data = MAIN_FB()->pixels; + MAIN_FB()->w = image.w; + MAIN_FB()->h = image.h; + MAIN_FB()->bpp = image.bpp; + } else { + image.data = xalloc(size); + } + + char ignore[15]; + read_data(fp, image.data, size); + if (size % 16) read_data(fp, ignore, 16 - (size % 16)); // Read in to multiple of 16 bytes. + + return py_image_from_struct(&image); +} + +mp_obj_t py_imagereader_close(mp_obj_t self_in) +{ + file_close(&((py_imagereader_obj_t *) self_in)->fp); + return self_in; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagereader_size_obj, py_imagereader_size); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_imagereader_next_frame_obj, 1, py_imagereader_next_frame); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagereader_close_obj, py_imagereader_close); + +STATIC const mp_rom_map_elem_t py_imagereader_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_imagereader_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_next_frame), MP_ROM_PTR(&py_imagereader_next_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagereader_close_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_imagereader_locals_dict, py_imagereader_locals_dict_table); + +static const mp_obj_type_t py_imagereader_type = { + { &mp_type_type }, + .name = MP_QSTR_imagereader, + .print = py_imagereader_print, + .locals_dict = (mp_obj_t) &py_imagereader_locals_dict +}; + +mp_obj_t py_image_imagereader(mp_obj_t path) +{ + py_imagereader_obj_t *obj = m_new_obj(py_imagereader_obj_t); + obj->base.type = &py_imagereader_type; + file_read_open(&obj->fp, mp_obj_str_get_str(path)); + + read_long_expect(&obj->fp, *((uint32_t *) "OMV ")); // OpenMV + read_long_expect(&obj->fp, *((uint32_t *) "IMG ")); // Image + read_long_expect(&obj->fp, *((uint32_t *) "STR ")); // Stream + read_long_expect(&obj->fp, *((uint32_t *) "V1.0")); // v1.0 + + //obj->ms = systick_current_millis(); hutu + obj->ms = 0; + return obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagereader_obj, py_image_imagereader); + +mp_obj_t py_image(int w, int h, int bpp, void *pixels) +{ + py_image_obj_t *o = m_new_obj(py_image_obj_t); + o->base.type = &py_image_type; + o->_cobj.w = w; + o->_cobj.h = h; + o->_cobj.bpp = bpp; + o->_cobj.pixels = pixels; + return o; +} + +mp_obj_t py_image_from_struct(image_t *img) +{ + py_image_obj_t *o = m_new_obj(py_image_obj_t); + o->base.type = &py_image_type; + o->_cobj = *img; + return o; +} + +mp_obj_t py_image_rgb_to_lab(mp_obj_t tuple) +{ + mp_obj_t *rgb; + mp_obj_get_array_fixed_n(tuple, 3, &rgb); + + simple_color_t rgb_color, lab_color; + rgb_color.red = mp_obj_get_int(rgb[0]); + rgb_color.green = mp_obj_get_int(rgb[1]); + rgb_color.blue = mp_obj_get_int(rgb[2]); + imlib_rgb_to_lab(&rgb_color, &lab_color); + + return mp_obj_new_tuple(3, (mp_obj_t[3]) + {mp_obj_new_int(lab_color.L), + mp_obj_new_int(lab_color.A), + mp_obj_new_int(lab_color.B)}); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_lab_obj, py_image_rgb_to_lab); + +mp_obj_t py_image_lab_to_rgb(mp_obj_t tuple) +{ + mp_obj_t *lab; + mp_obj_get_array_fixed_n(tuple, 3, &lab); + + simple_color_t lab_color, rgb_color; + lab_color.L = mp_obj_get_int(lab[0]); + lab_color.A = mp_obj_get_int(lab[1]); + lab_color.B = mp_obj_get_int(lab[2]); + imlib_lab_to_rgb(&lab_color, &rgb_color); + + return mp_obj_new_tuple(3, (mp_obj_t[3]) + {mp_obj_new_int(rgb_color.red), + mp_obj_new_int(rgb_color.green), + mp_obj_new_int(rgb_color.blue)}); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_lab_to_rgb_obj, py_image_lab_to_rgb); + +mp_obj_t py_image_rgb_to_grayscale(mp_obj_t tuple) +{ + mp_obj_t *rgb; + mp_obj_get_array_fixed_n(tuple, 3, &rgb); + + simple_color_t rgb_color, grayscale_color; + rgb_color.red = mp_obj_get_int(rgb[0]); + rgb_color.green = mp_obj_get_int(rgb[1]); + rgb_color.blue = mp_obj_get_int(rgb[2]); + imlib_rgb_to_grayscale(&rgb_color, &grayscale_color); + + return mp_obj_new_int(grayscale_color.G); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_grayscale_obj, py_image_rgb_to_grayscale); + +mp_obj_t py_image_grayscale_to_rgb(mp_obj_t not_tuple) +{ + simple_color_t grayscale_color, rgb_color; + grayscale_color.G = mp_obj_get_int(not_tuple); + imlib_grayscale_to_rgb(&grayscale_color, &rgb_color); + + return mp_obj_new_tuple(3, (mp_obj_t[3]) + {mp_obj_new_int(rgb_color.red), + mp_obj_new_int(rgb_color.green), + mp_obj_new_int(rgb_color.blue)}); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_grayscale_to_rgb_obj, py_image_grayscale_to_rgb); + +mp_obj_t py_image_load_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + const char *path = mp_obj_str_get_str(args[0]); + + bool copy_to_fb = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false); + if (copy_to_fb) fb_update_jpeg_buffer(); + + image_t image = {0}; + + if (copy_to_fb) { + MAIN_FB()->w = 0; + MAIN_FB()->h = 0; + MAIN_FB()->bpp = 0; + + FIL fp; + img_read_settings_t rs; + imlib_read_geometry(&fp, &image, path, &rs); + file_buffer_off(&fp); + file_close(&fp); + + uint32_t size = image_size(&image); + + PY_ASSERT_TRUE_MSG((size <= OMV_RAW_BUF_SIZE), "FB Overflow!"); + MAIN_FB()->w = image.w; + MAIN_FB()->h = image.h; + MAIN_FB()->bpp = image.bpp; + image.data = MAIN_FB()->pixels; + } + + imlib_load_image(&image, path); + return py_image_from_struct(&image); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_image_obj, 1, py_image_load_image); + +mp_obj_t py_image_load_cascade(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + cascade_t cascade; + const char *path = mp_obj_str_get_str(args[0]); + + // Load cascade from file or flash + int res = imlib_load_cascade(&cascade, path); + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerr(res))); + } + + // Read the number of stages + int stages = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("stages")), cascade.n_stages); + // Check the number of stages + if (stages > 0 && stages < cascade.n_stages) { + cascade.n_stages = stages; + } + + // Return micropython cascade object + py_cascade_obj_t *o = m_new_obj(py_cascade_obj_t); + o->base.type = &py_cascade_type; + o->_cobj = cascade; + return o; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_cascade); + +mp_obj_t py_image_load_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + FIL fp; + UINT bytes; + FRESULT res; + + uint32_t desc_type; + mp_obj_t desc = mp_const_none; + const char *path = mp_obj_str_get_str(args[0]); + + if ((res = f_open_helper(&fp, path, FA_READ|FA_OPEN_EXISTING)) == FR_OK) { + // Read descriptor type + res = f_read(&fp, &desc_type, sizeof(desc_type), &bytes); + if (res != FR_OK || bytes != sizeof(desc_type)) { + goto error; + } + + // Load descriptor + switch (desc_type) { + case DESC_LBP: { + py_lbp_obj_t *lbp = m_new_obj(py_lbp_obj_t); + lbp->base.type = &py_lbp_type; + + res = imlib_lbp_desc_load(&fp, &lbp->hist); + if (res == FR_OK) { + desc = lbp; + } + break; + } + + case DESC_ORB: { + array_t *kpts = NULL; + array_alloc(&kpts, xfree); + + res = orb_load_descriptor(&fp, kpts); + if (res == FR_OK) { + // Return keypoints MP object + py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t); + kp_obj->base.type = &py_kp_type; + kp_obj->kpts = kpts; + kp_obj->threshold = 10; + kp_obj->normalized = false; + desc = kp_obj; + } + break; + } + } + + f_close(&fp); + } + +error: + // File open or write error + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerr(res))); + } + + // If no file error and descriptor is still none, then it's not supported. + if (desc == mp_const_none) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Descriptor type is not supported")); + } + return desc; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 1, py_image_load_descriptor); + +mp_obj_t py_image_save_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + FIL fp; + UINT bytes; + FRESULT res; + + uint32_t desc_type; + const char *path = mp_obj_str_get_str(args[1]); + + if ((res = f_open_helper(&fp, path, FA_WRITE|FA_CREATE_ALWAYS)) == FR_OK) { + // Find descriptor type + mp_obj_type_t *desc_obj_type = mp_obj_get_type(args[0]); + if (desc_obj_type == &py_lbp_type) { + desc_type = DESC_LBP; + } else if (desc_obj_type == &py_kp_type) { + desc_type = DESC_ORB; + } + + // Write descriptor type + res = f_write(&fp, &desc_type, sizeof(desc_type), &bytes); + if (res != FR_OK || bytes != sizeof(desc_type)) { + goto error; + } + + // Write descriptor + switch (desc_type) { + case DESC_LBP: { + py_lbp_obj_t *lbp = ((py_lbp_obj_t*)args[0]); + res = imlib_lbp_desc_save(&fp, lbp->hist); + break; + } + + case DESC_ORB: { + py_kp_obj_t *kpts = ((py_kp_obj_t*)args[0]); + res = orb_save_descriptor(&fp, kpts->kpts); + break; + } + } + // ignore unsupported descriptors when saving + f_close(&fp); + } + +error: + // File open or read error + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerr(res))); + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 2, py_image_save_descriptor); + +static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + mp_obj_t match_obj = mp_const_none; + mp_obj_type_t *desc1_type = mp_obj_get_type(args[0]); + mp_obj_type_t *desc2_type = mp_obj_get_type(args[1]); + PY_ASSERT_TRUE_MSG((desc1_type == desc2_type), "Descriptors have different types!"); + + if (desc1_type == &py_lbp_type) { + py_lbp_obj_t *lbp1 = ((py_lbp_obj_t*)args[0]); + py_lbp_obj_t *lbp2 = ((py_lbp_obj_t*)args[1]); + + // Sanity checks + PY_ASSERT_TYPE(lbp1, &py_lbp_type); + PY_ASSERT_TYPE(lbp2, &py_lbp_type); + + // Match descriptors + match_obj = mp_obj_new_int(imlib_lbp_desc_distance(lbp1->hist, lbp2->hist)); + } else if (desc1_type == &py_kp_type) { + py_kp_obj_t *kpts1 = ((py_kp_obj_t*)args[0]); + py_kp_obj_t *kpts2 = ((py_kp_obj_t*)args[1]); + int threshold = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 85); + int filter_outliers = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_filter_outliers), false); + + // Sanity checks + PY_ASSERT_TYPE(kpts1, &py_kp_type); + PY_ASSERT_TYPE(kpts2, &py_kp_type); + PY_ASSERT_TRUE_MSG((threshold >=0 && threshold <= 100), "Expected threshold between 0 and 100"); + + int theta = 0; // Estimated angle of rotation + int count = 0; // Number of matches + point_t c = {0}; // Centroid + rectangle_t r = {0}; // Bounding rectangle + // List of matching keypoints indices + mp_obj_t match_list = mp_obj_new_list(0, NULL); + + if (array_length(kpts1->kpts) && array_length(kpts1->kpts)) { + int *match = fb_alloc(array_length(kpts1->kpts) * sizeof(int) * 2); + + // Match the two keypoint sets + count = orb_match_keypoints(kpts1->kpts, kpts2->kpts, match, threshold, &r, &c, &theta); + + // Add matching keypoints to Python list. + for (int i=0; ikpts, &r, &c); + } + } + + py_kptmatch_obj_t *o = m_new_obj(py_kptmatch_obj_t); + o->base.type = &py_kptmatch_type; + o->cx = mp_obj_new_int(c.x); + o->cy = mp_obj_new_int(c.y); + o->x = mp_obj_new_int(r.x); + o->y = mp_obj_new_int(r.y); + o->w = mp_obj_new_int(r.w); + o->h = mp_obj_new_int(r.h); + o->count = mp_obj_new_int(count); + o->theta = mp_obj_new_int(theta); + o->match = match_list; + match_obj = o; + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Descriptor type is not supported")); + } + + return match_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 2, py_image_match_descriptor); + +int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) +{ + FIL fp; + FRESULT res = FR_OK; + + printf("Save Descriptor: ROI(%d %d %d %d)\n", roi->x, roi->y, roi->w, roi->h); + array_t *kpts = orb_find_keypoints(img, false, 20, 1.5f, 100, CORNER_AGAST, roi); + printf("Save Descriptor: KPTS(%d)\n", array_length(kpts)); + + if (array_length(kpts)) { + if ((res = f_open_helper(&fp, path, FA_WRITE|FA_CREATE_ALWAYS)) == FR_OK) { + res = orb_save_descriptor(&fp, kpts); + f_close(&fp); + } + // File open/write error + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerr(res))); + } + } + return 0; +} + +static const mp_rom_map_elem_t globals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image)}, + {MP_ROM_QSTR(MP_QSTR_SEARCH_EX), MP_ROM_INT(SEARCH_EX)}, + {MP_ROM_QSTR(MP_QSTR_SEARCH_DS), MP_ROM_INT(SEARCH_DS)}, + {MP_ROM_QSTR(MP_QSTR_EDGE_CANNY), MP_ROM_INT(EDGE_CANNY)}, + {MP_ROM_QSTR(MP_QSTR_EDGE_SIMPLE), MP_ROM_INT(EDGE_SIMPLE)}, + {MP_ROM_QSTR(MP_QSTR_CORNER_FAST), MP_ROM_INT(CORNER_FAST)}, + {MP_ROM_QSTR(MP_QSTR_CORNER_AGAST), MP_ROM_INT(CORNER_AGAST)}, +#ifdef IMLIB_ENABLE_APRILTAGS + {MP_ROM_QSTR(MP_QSTR_TAG16H5), MP_ROM_INT(TAG16H5)}, + {MP_ROM_QSTR(MP_QSTR_TAG25H7), MP_ROM_INT(TAG25H7)}, + {MP_ROM_QSTR(MP_QSTR_TAG25H9), MP_ROM_INT(TAG25H9)}, + {MP_ROM_QSTR(MP_QSTR_TAG36H10), MP_ROM_INT(TAG36H10)}, + {MP_ROM_QSTR(MP_QSTR_TAG36H11), MP_ROM_INT(TAG36H11)}, + {MP_ROM_QSTR(MP_QSTR_ARTOOLKIT), MP_ROM_INT(ARTOOLKIT)}, +#endif +#ifdef IMLIB_ENABLE_BARCODES + {MP_ROM_QSTR(MP_QSTR_EAN2), MP_ROM_INT(BARCODE_EAN2)}, + {MP_ROM_QSTR(MP_QSTR_EAN5), MP_ROM_INT(BARCODE_EAN5)}, + {MP_ROM_QSTR(MP_QSTR_EAN8), MP_ROM_INT(BARCODE_EAN8)}, + {MP_ROM_QSTR(MP_QSTR_UPCE), MP_ROM_INT(BARCODE_UPCE)}, + {MP_ROM_QSTR(MP_QSTR_ISBN10), MP_ROM_INT(BARCODE_ISBN10)}, + {MP_ROM_QSTR(MP_QSTR_UPCA), MP_ROM_INT(BARCODE_UPCA)}, + {MP_ROM_QSTR(MP_QSTR_EAN13), MP_ROM_INT(BARCODE_EAN13)}, + {MP_ROM_QSTR(MP_QSTR_ISBN13), MP_ROM_INT(BARCODE_ISBN13)}, + {MP_ROM_QSTR(MP_QSTR_I25), MP_ROM_INT(BARCODE_I25)}, + {MP_ROM_QSTR(MP_QSTR_DATABAR), MP_ROM_INT(BARCODE_DATABAR)}, + {MP_ROM_QSTR(MP_QSTR_DATABAR_EXP), MP_ROM_INT(BARCODE_DATABAR_EXP)}, + {MP_ROM_QSTR(MP_QSTR_CODABAR), MP_ROM_INT(BARCODE_CODABAR)}, + {MP_ROM_QSTR(MP_QSTR_CODE39), MP_ROM_INT(BARCODE_CODE39)}, + {MP_ROM_QSTR(MP_QSTR_PDF417), MP_ROM_INT(BARCODE_PDF417)}, + {MP_ROM_QSTR(MP_QSTR_CODE93), MP_ROM_INT(BARCODE_CODE93)}, + {MP_ROM_QSTR(MP_QSTR_CODE128), MP_ROM_INT(BARCODE_CODE128)}, +#endif + {MP_ROM_QSTR(MP_QSTR_ImageWriter), MP_ROM_PTR(&py_image_imagewriter_obj)}, + {MP_ROM_QSTR(MP_QSTR_ImageReader), MP_ROM_PTR(&py_image_imagereader_obj)}, + {MP_ROM_QSTR(MP_QSTR_rgb_to_lab), MP_ROM_PTR(&py_image_rgb_to_lab_obj)}, + {MP_ROM_QSTR(MP_QSTR_lab_to_rgb), MP_ROM_PTR(&py_image_lab_to_rgb_obj)}, + {MP_ROM_QSTR(MP_QSTR_rgb_to_grayscale), MP_ROM_PTR(&py_image_rgb_to_grayscale_obj)}, + {MP_ROM_QSTR(MP_QSTR_grayscale_to_rgb), MP_ROM_PTR(&py_image_grayscale_to_rgb_obj)}, + {MP_ROM_QSTR(MP_QSTR_Image), MP_ROM_PTR(&py_image_load_image_obj)}, + {MP_ROM_QSTR(MP_QSTR_HaarCascade), MP_ROM_PTR(&py_image_load_cascade_obj)}, + {MP_ROM_QSTR(MP_QSTR_load_descriptor), MP_ROM_PTR(&py_image_load_descriptor_obj)}, + {MP_ROM_QSTR(MP_QSTR_save_descriptor), MP_ROM_PTR(&py_image_save_descriptor_obj)}, + {MP_ROM_QSTR(MP_QSTR_match_descriptor), MP_ROM_PTR(&py_image_match_descriptor_obj)} +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t image_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t) &globals_dict +}; diff --git a/src/openmv/src/omv/py/py_image.h b/src/openmv/src/omv/py/py_image.h new file mode 100755 index 0000000..ca9e4e2 --- /dev/null +++ b/src/openmv/src/omv/py/py_image.h @@ -0,0 +1,17 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Image Python module. + * + */ +#ifndef __PY_IMAGE_H__ +#define __PY_IMAGE_H__ +// DISABLED #include +#include "imlib.h" +mp_obj_t py_image(int width, int height, int bpp, void *pixels); +mp_obj_t py_image_from_struct(image_t *img); +void *py_image_cobj(mp_obj_t img_obj); +int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi); +#endif // __PY_IMAGE_H__ diff --git a/src/openmv/src/omv/py/py_lcd.c b/src/openmv/src/omv/py/py_lcd.c new file mode 100755 index 0000000..e2a34f8 --- /dev/null +++ b/src/openmv/src/omv/py/py_lcd.c @@ -0,0 +1,396 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * LCD Python module. + * + */ +#include +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "py_assert.h" +#include "py_helper.h" +#include "py_image.h" + +#define RST_PORT GPIOD +#define RST_PIN GPIO_PIN_12 +#define RST_PIN_WRITE(bit) HAL_GPIO_WritePin(RST_PORT, RST_PIN, bit); + +#define RS_PORT GPIOD +#define RS_PIN GPIO_PIN_13 +#define RS_PIN_WRITE(bit) HAL_GPIO_WritePin(RS_PORT, RS_PIN, bit); + +#define CS_PORT GPIOB +#define CS_PIN GPIO_PIN_12 +#define CS_PIN_WRITE(bit) HAL_GPIO_WritePin(CS_PORT, CS_PIN, bit); + +#define LED_PORT GPIOA +#define LED_PIN GPIO_PIN_5 +#define LED_PIN_WRITE(bit) HAL_GPIO_WritePin(LED_PORT, LED_PIN, bit); + +extern mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t pyb_spi_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); +extern mp_obj_t pyb_spi_deinit(mp_obj_t self_in); + +static mp_obj_t spi_port = NULL; +static int width = 0; +static int height = 0; +static enum { LCD_NONE, LCD_SHIELD } type = LCD_NONE; +static bool backlight_init = false; + +// Send out 8-bit data using the SPI object. +static void lcd_write_command_byte(uint8_t data_byte) +{ + mp_map_t arg_map; + arg_map.all_keys_are_qstrs = true; + arg_map.is_fixed = true; + arg_map.is_ordered = true; + arg_map.used = 0; + arg_map.alloc = 0; + arg_map.table = NULL; + + CS_PIN_WRITE(false); + RS_PIN_WRITE(false); // command + pyb_spi_send( + 2, (mp_obj_t []) { + spi_port, + mp_obj_new_int(data_byte) + }, + &arg_map + ); + CS_PIN_WRITE(true); +} + +// Send out 8-bit data using the SPI object. +static void lcd_write_data_byte(uint8_t data_byte) +{ + mp_map_t arg_map; + arg_map.all_keys_are_qstrs = true; + arg_map.is_fixed = true; + arg_map.is_ordered = true; + arg_map.used = 0; + arg_map.alloc = 0; + arg_map.table = NULL; + + CS_PIN_WRITE(false); + RS_PIN_WRITE(true); // data + pyb_spi_send( + 2, (mp_obj_t []) { + spi_port, + mp_obj_new_int(data_byte) + }, + &arg_map + ); + CS_PIN_WRITE(true); +} + +// Send out 8-bit data using the SPI object. +static void lcd_write_command(uint8_t data_byte, uint32_t len, uint8_t *dat) +{ + lcd_write_command_byte(data_byte); + for (uint32_t i=0; i width) { + int adjust = rect.w - width; + rect.w -= adjust; + rect.x += adjust / 2; + } else if (rect.w < width) { + int adjust = width - rect.w; + l_pad = adjust / 2; + r_pad = (adjust + 1) / 2; + } + + // Fit Y. + int t_pad = 0, b_pad = 0; + if (rect.h > height) { + int adjust = rect.h - height; + rect.h -= adjust; + rect.y += adjust / 2; + } else if (rect.h < height) { + int adjust = height - rect.h; + t_pad = adjust / 2; + b_pad = (adjust + 1) / 2; + } + + switch (type) { + case LCD_NONE: + return mp_const_none; + case LCD_SHIELD: + lcd_write_command_byte(0x2C); + uint8_t *zero = fb_alloc0(width*2); + uint16_t *line = fb_alloc(width*2); + for (int i=0; ipixels) + + ((rect.y + i) * arg_img->w) + rect.x)); + } + if (r_pad) { + lcd_write_data(r_pad*2, zero); // r_pad < width + } + } + for (int i=0; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * LCD Python module. + * + */ +#ifndef __PY_LCD_H__ +#define __PY_LCD_H__ +void py_lcd_init0(); +#endif // __PY_LCD_H__ diff --git a/src/openmv/src/omv/py/py_mjpeg.c b/src/openmv/src/omv/py/py_mjpeg.c new file mode 100755 index 0000000..4d856d9 --- /dev/null +++ b/src/openmv/src/omv/py/py_mjpeg.c @@ -0,0 +1,120 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MJPEG Python module. + * + */ +#include "mp.h" +#include "ff_wrapper.h" +#include "framebuffer.h" +#include "sensor.h" +#include "py_assert.h" +#include "py_helper.h" +#include "py_image.h" + +static const mp_obj_type_t py_mjpeg_type; // forward declare +// Mjpeg class +typedef struct py_mjpeg_obj { + mp_obj_base_t base; + int width; + int height; + uint32_t frames; + uint32_t bytes; + FIL fp; +} py_mjpeg_obj_t; + +static mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + py_mjpeg_obj_t *mjpeg = m_new_obj(py_mjpeg_obj_t); + mjpeg->width = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); + mjpeg->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); + mjpeg->frames = 0; // private + mjpeg->bytes = 0; // private + mjpeg->base.type = &py_mjpeg_type; + + file_write_open(&mjpeg->fp, mp_obj_str_get_str(args[0])); + mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height); + return mjpeg; +} + +static mp_obj_t py_mjpeg_width(mp_obj_t mjpeg_obj) +{ + py_mjpeg_obj_t *arg_mjpeg = mjpeg_obj; + return mp_obj_new_int(arg_mjpeg->width); +} + +static mp_obj_t py_mjpeg_height(mp_obj_t mjpeg_obj) +{ + py_mjpeg_obj_t *arg_mjpeg = mjpeg_obj; + return mp_obj_new_int(arg_mjpeg->height); +} + +static mp_obj_t py_mjpeg_size(mp_obj_t mjpeg_obj) +{ + py_mjpeg_obj_t *arg_mjpeg = mjpeg_obj; + return mp_obj_new_int(f_size(&arg_mjpeg->fp)); +} + +static mp_obj_t py_mjpeg_add_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + py_mjpeg_obj_t *arg_mjpeg = args[0]; + image_t *arg_img = py_image_cobj(args[1]); + PY_ASSERT_FALSE_MSG((arg_mjpeg->width != arg_img->w) + || (arg_mjpeg->height != arg_img->h), + "Unexpected image geometry"); + + int arg_q = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + arg_q = IM_MIN(IM_MAX(arg_q, 1), 100); + mjpeg_add_frame(&arg_mjpeg->fp, &arg_mjpeg->frames, &arg_mjpeg->bytes, arg_img, arg_q); + return mp_const_none; +} + +static mp_obj_t py_mjpeg_close(mp_obj_t mjpeg_obj, mp_obj_t fps_obj) +{ + py_mjpeg_obj_t *arg_mjpeg = mjpeg_obj; + mjpeg_close(&arg_mjpeg->fp, &arg_mjpeg->frames, &arg_mjpeg->bytes, mp_obj_get_float(fps_obj)); + return mp_const_none; +} + +static void py_mjpeg_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_mjpeg_obj_t *self = self_in; + mp_printf(print, "", self->width, self->height); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_width_obj, py_mjpeg_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_height_obj, py_mjpeg_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_mjpeg_size_obj, py_mjpeg_size); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_mjpeg_add_frame_obj, 2, py_mjpeg_add_frame); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_mjpeg_close_obj, py_mjpeg_close); +static const mp_map_elem_t locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_mjpeg_width_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_mjpeg_height_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&py_mjpeg_size_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_add_frame), (mp_obj_t)&py_mjpeg_add_frame_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&py_mjpeg_close_obj }, + { NULL, NULL }, +}; +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +static const mp_obj_type_t py_mjpeg_type = { + { &mp_type_type }, + .name = MP_QSTR_Mjpeg, + .print = py_mjpeg_print, + .locals_dict = (mp_obj_t)&locals_dict, +}; + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_mjpeg_open_obj, 1, py_mjpeg_open); +static const mp_map_elem_t globals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mjpeg) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Mjpeg), (mp_obj_t)&py_mjpeg_open_obj }, + { NULL, NULL }, +}; +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t mjpeg_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_nn.c b/src/openmv/src/omv/py/py_nn.c new file mode 100755 index 0000000..88982a9 --- /dev/null +++ b/src/openmv/src/omv/py/py_nn.c @@ -0,0 +1,407 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ +#include +#include "nn.h" +#include "py_helper.h" +#include "py_image.h" +#include "omv_boardconfig.h" + +#ifdef IMLIB_ENABLE_CNN + +static const mp_obj_type_t py_net_type; + +typedef struct _py_net_obj_t { + mp_obj_base_t base; + nn_t _cobj; +} py_net_obj_t; + +void *py_net_cobj(mp_obj_t net_obj) +{ + PY_ASSERT_TYPE(net_obj, &py_net_type); + return &((py_net_obj_t *)net_obj)->_cobj; +} + +STATIC void py_net_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_net_obj_t *self = self_in; + nn_dump_network(py_net_cobj(self)); +} + +STATIC mp_obj_t py_net_forward(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + nn_t *net = py_net_cobj(args[0]); + image_t *img = py_helper_arg_to_image_mutable(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(img, n_args, args, 2, kw_args, &roi); + + bool softmax = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_softmax), false); + bool dry_run = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_dry_run), false); + + mp_obj_t output_list = mp_obj_new_list(0, NULL); + fb_alloc_mark(); + + if (dry_run == false) { + nn_run_network(net, img, &roi, softmax); + } else { + nn_dry_run_network(net, img, softmax); + } + + for (int i=0; ioutput_size; i++) { + mp_obj_list_append(output_list, mp_obj_new_float(((float) (net->output_data[i] + 128)) / 255)); + } + + fb_alloc_free_till_mark(); + return output_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_net_forward_obj, 2, py_net_forward); + +// NN Class Object +#define py_nn_class_obj_size 6 +typedef struct py_nn_class_obj { + mp_obj_base_t base; + mp_obj_t x, y, w, h, index, value; +} py_nn_class_obj_t; + +static void py_nn_class_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_nn_class_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"index\":%d, \"value\":%f}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + mp_obj_get_int(self->index), + (double) mp_obj_get_float(self->value)); +} + +static mp_obj_t py_nn_class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + if (value == MP_OBJ_SENTINEL) { // load + py_nn_class_obj_t *self = self_in; + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(py_nn_class_obj_size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + mp_seq_copy(result->items, &(self->x) + slice.start, result->len, mp_obj_t); + return result; + } + switch (mp_get_index(self->base.type, py_nn_class_obj_size, index, false)) { + case 0: return self->x; + case 1: return self->y; + case 2: return self->w; + case 3: return self->h; + case 4: return self->index; + case 5: return self->value; + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_nn_class_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t []) {((py_nn_class_obj_t *) self_in)->x, + ((py_nn_class_obj_t *) self_in)->y, + ((py_nn_class_obj_t *) self_in)->w, + ((py_nn_class_obj_t *) self_in)->h}); +} + +mp_obj_t py_nn_class_x(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->x; } +mp_obj_t py_nn_class_y(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->y; } +mp_obj_t py_nn_class_w(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->w; } +mp_obj_t py_nn_class_h(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->h; } +mp_obj_t py_nn_class_index(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->index; } +mp_obj_t py_nn_class_value(mp_obj_t self_in) { return ((py_nn_class_obj_t *) self_in)->value; } + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_rect_obj, py_nn_class_rect); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_x_obj, py_nn_class_x); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_y_obj, py_nn_class_y); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_w_obj, py_nn_class_w); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_h_obj, py_nn_class_h); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_index_obj, py_nn_class_index); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_class_value_obj, py_nn_class_value); + +STATIC const mp_rom_map_elem_t py_nn_class_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_nn_class_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_nn_class_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_nn_class_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_nn_class_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_nn_class_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&py_nn_class_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&py_nn_class_value_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(py_nn_class_locals_dict, py_nn_class_locals_dict_table); + +static const mp_obj_type_t py_nn_class_type = { + { &mp_type_type }, + .name = MP_QSTR_nn_class, + .print = py_nn_class_print, + .subscr = py_nn_class_subscr, + .locals_dict = (mp_obj_t) &py_nn_class_locals_dict +}; + +typedef struct py_nn_class_obj_list_lnk_data { + rectangle_t rect; + int index; + float value; + int merge_number; +} py_nn_class_obj_list_lnk_data_t; + +STATIC mp_obj_t py_net_search(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + nn_t *arg_net = py_net_cobj(args[0]); + image_t *arg_img = py_helper_arg_to_image_mutable(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); + + float arg_threshold = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0.6); + PY_ASSERT_TRUE_MSG((0 <= arg_threshold) && (arg_threshold <= 1), "0 <= threshold <= 1"); + + float arg_min_scale = py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_min_scale), 1.0); + PY_ASSERT_TRUE_MSG((0 < arg_min_scale) && (arg_min_scale <= 1), "0 < min_scale <= 1"); + + float arg_scale_mul = py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_mul), 0.5); + PY_ASSERT_TRUE_MSG((0 <= arg_scale_mul) && (arg_scale_mul < 1), "0 <= scale_mul < 1"); + + float arg_x_overlap = py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_overlap), 0); + PY_ASSERT_TRUE_MSG(((0 <= arg_x_overlap) && (arg_x_overlap < 1)) || (arg_x_overlap == -1), "0 <= x_overlap < 1"); + + float arg_y_overlap = py_helper_keyword_float(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_overlap), 0); + PY_ASSERT_TRUE_MSG(((0 <= arg_y_overlap) && (arg_y_overlap < 1)) || (arg_y_overlap == -1), "0 <= y_overlap < 1"); + + float arg_contrast_threshold = py_helper_keyword_float(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_contrast_threshold), 1); + PY_ASSERT_TRUE_MSG(0 <= arg_contrast_threshold, "0 <= contrast_threshold"); + + bool softmax = py_helper_keyword_int(n_args, args, 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_softmax), false); + + list_t out; + list_init(&out, sizeof(py_nn_class_obj_list_lnk_data_t)); + + fb_alloc_mark(); + + for (float scale = 1; scale >= arg_min_scale; scale *= arg_scale_mul) { + // Either provide a subtle offset to center multiple detection windows or center the only detection window. + for (int y = roi.y + ((arg_y_overlap != -1) ? (fmodf(roi.h, (roi.h * scale)) / 2) : ((roi.h - (roi.h * scale)) / 2)); + // Finish when the detection window is outside of the ROI. + (y + (roi.h * scale)) <= (roi.y + roi.h); + // Step by an overlap amount accounting for scale or just terminate after one iteration. + y += ((arg_y_overlap != -1) ? (roi.h * scale * (1 - arg_y_overlap)) : roi.h)) { + // Either provide a subtle offset to center multiple detection windows or center the only detection window. + for (int x = roi.x + ((arg_x_overlap != -1) ? (fmodf(roi.w, (roi.w * scale)) / 2) : ((roi.w - (roi.w * scale)) / 2)); + // Finish when the detection window is outside of the ROI. + (x + (roi.w * scale)) <= (roi.x + roi.w); + // Step by an overlap amount accounting for scale or just terminate after one iteration. + x += ((arg_x_overlap != -1) ? (roi.w * scale * (1 - arg_x_overlap)) : roi.w)) { + rectangle_t new_roi; + rectangle_init(&new_roi, x, y, roi.w * scale, roi.h * scale); + if (rectangle_overlap(&roi, &new_roi)) { + + int sum = 0; + int sum_2 = 0; + for (int b = new_roi.y, bb = new_roi.y + new_roi.h, bbb = fast_sqrtf(new_roi.h); b < bb; b += bbb) { + for (int a = new_roi.x, aa = new_roi.x + new_roi.w, aaa = fast_sqrtf(new_roi.w); a < aa; a += aaa) { + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + int pixel = COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL(arg_img, a, b)); + sum += pixel; + sum_2 += pixel * pixel; + } + case IMAGE_BPP_GRAYSCALE: { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, a, b); + sum += pixel; + sum_2 += pixel * pixel; + } + case IMAGE_BPP_RGB565: { + int pixel = COLOR_RGB565_TO_GRAYSCALE(IMAGE_GET_RGB565_PIXEL(arg_img, a, b)); + sum += pixel; + sum_2 += pixel * pixel; + } + } + } + } + + int area = new_roi.w * new_roi.h; + int mean = sum / area; + int variance = (sum_2 / area) - (mean * mean); + + if (fast_sqrtf(variance) >= arg_contrast_threshold) { // Skip flat regions... + nn_run_network(arg_net, arg_img, &new_roi, softmax); + + int max_index = -1; + float max_value = -1; + for (int i=0; ioutput_size; i++) { + float value = ((float) (arg_net->output_data[i] + 128)) / 255; + if ((value >= arg_threshold) && (value > max_value)) { + max_index = i; + max_value = value; + } + } + + if (max_index != -1) { + py_nn_class_obj_list_lnk_data_t lnk_data; + lnk_data.rect.x = new_roi.x; + lnk_data.rect.y = new_roi.y; + lnk_data.rect.w = new_roi.w; + lnk_data.rect.h = new_roi.h; + lnk_data.index = max_index; + lnk_data.value = max_value; + lnk_data.merge_number = 1; + list_push_back(&out, &lnk_data); + } + } + } + } + } + } + + fb_alloc_free_till_mark(); + + // Merge all overlapping and same detections and average them. + + for (;;) { + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(py_nn_class_obj_list_lnk_data_t)); + + while (list_size(&out)) { + py_nn_class_obj_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + for (size_t k = 0, l = list_size(&out); k < l; k++) { + py_nn_class_obj_list_lnk_data_t tmp_data; + list_pop_front(&out, &tmp_data); + + if ((lnk_data.index == tmp_data.index) + && rectangle_overlap(&(lnk_data.rect), &(tmp_data.rect))) { + lnk_data.rect.x = ((lnk_data.rect.x * lnk_data.merge_number) + tmp_data.rect.x) / (lnk_data.merge_number + 1); + lnk_data.rect.y = ((lnk_data.rect.y * lnk_data.merge_number) + tmp_data.rect.y) / (lnk_data.merge_number + 1); + lnk_data.rect.w = ((lnk_data.rect.w * lnk_data.merge_number) + tmp_data.rect.w) / (lnk_data.merge_number + 1); + lnk_data.rect.h = ((lnk_data.rect.h * lnk_data.merge_number) + tmp_data.rect.h) / (lnk_data.merge_number + 1); + lnk_data.value = ((lnk_data.value * lnk_data.merge_number) + tmp_data.value) / (lnk_data.merge_number + 1); + lnk_data.merge_number += 1; + merge_occured = true; + } else { + list_push_back(&out, &tmp_data); + } + } + + list_push_back(&out_temp, &lnk_data); + } + + list_copy(&out, &out_temp); + + if (!merge_occured) { + break; + } + } + + // Determine the winner between overlapping different class detections. + + for (;;) { + bool merge_occured = false; + + list_t out_temp; + list_init(&out_temp, sizeof(py_nn_class_obj_list_lnk_data_t)); + + while (list_size(&out)) { + py_nn_class_obj_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + for (size_t k = 0, l = list_size(&out); k < l; k++) { + py_nn_class_obj_list_lnk_data_t tmp_data; + list_pop_front(&out, &tmp_data); + + if ((lnk_data.index != tmp_data.index) + && rectangle_overlap(&(lnk_data.rect), &(tmp_data.rect))) { + if (tmp_data.value > lnk_data.value) { + memcpy(&lnk_data, &tmp_data, sizeof(py_nn_class_obj_list_lnk_data_t)); + } + + merge_occured = true; + } else { + list_push_back(&out, &tmp_data); + } + } + + list_push_back(&out_temp, &lnk_data); + } + + list_copy(&out, &out_temp); + + if (!merge_occured) { + break; + } + } + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + + for (size_t i = 0; list_size(&out); i++) { + py_nn_class_obj_list_lnk_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_nn_class_obj_t *o = m_new_obj(py_nn_class_obj_t); + o->base.type = &py_nn_class_type; + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->index = mp_obj_new_int(lnk_data.index); + o->value = mp_obj_new_float(lnk_data.value); + + objects_list->items[i] = o; + } + + return objects_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_net_search_obj, 2, py_net_search); + +STATIC const mp_rom_map_elem_t locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_forward), MP_ROM_PTR(&py_net_forward_obj) }, + { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&py_net_search_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +static const mp_obj_type_t py_net_type = { + { &mp_type_type }, + .name = MP_QSTR_Net, + .print = py_net_print, + .locals_dict = (mp_obj_t) &locals_dict +}; + +static mp_obj_t py_nn_load(mp_obj_t path_obj) +{ + const char *path = mp_obj_str_get_str(path_obj); + py_net_obj_t *net = m_new_obj(py_net_obj_t); + net->base.type = &py_net_type; + nn_load_network(py_net_cobj(net), path); + return net; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_nn_load_obj, py_nn_load); + +#endif // IMLIB_ENABLE_CNN + +STATIC const mp_rom_map_elem_t globals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_nn) }, +#ifdef IMLIB_ENABLE_CNN + { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&py_nn_load_obj) }, +#else + { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&py_func_unavailable_obj) } +#endif // IMLIB_ENABLE_CNN +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t nn_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t) &globals_dict +}; diff --git a/src/openmv/src/omv/py/py_omv.c b/src/openmv/src/omv/py/py_omv.c new file mode 100755 index 0000000..ddbbe59 --- /dev/null +++ b/src/openmv/src/omv/py/py_omv.c @@ -0,0 +1,69 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ +#include +#include "omv_boardconfig.h" + +#define OMV_FIRMWARE_VERSION_MAJOR (3) +#define OMV_FIRMWARE_VERSION_MINOR (2) +#define OMV_FIRMWARE_VERSION_PATCH (0) + +/*Should be replaced by CPUID*/ +#define OMV_BOARD_ID_MAJOR (0x20181102) +#define OMV_BOARD_ID_MINOR (0x210bd) +#define OMV_BOARD_ID_PATCH (0x00000001) + +static mp_obj_t py_omv_version_string() +{ + char str[12]; + snprintf(str, 12, "%d.%d.%d", + OMV_FIRMWARE_VERSION_MAJOR, + OMV_FIRMWARE_VERSION_MINOR, + OMV_FIRMWARE_VERSION_PATCH); + return mp_obj_new_str(str, strlen(str)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_omv_version_string_obj, py_omv_version_string); + +static mp_obj_t py_omv_arch() +{ + char *str = OMV_ARCH_STR; + return mp_obj_new_str(str, strlen(str)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_omv_arch_obj, py_omv_arch); + +static mp_obj_t py_omv_board_type() +{ + char *str = OMV_BOARD_TYPE; + return mp_obj_new_str(str, strlen(str)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_omv_board_type_obj, py_omv_board_type); + +static mp_obj_t py_omv_board_id() +{ + char str[25]; + snprintf(str, 25, "%08X%08X%08X", + OMV_BOARD_ID_MAJOR, + OMV_BOARD_ID_MINOR, + OMV_BOARD_ID_PATCH); + return mp_obj_new_str(str, strlen(str)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_omv_board_id_obj, py_omv_board_id); + +static const mp_rom_map_elem_t globals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_omv) }, + { MP_ROM_QSTR(MP_QSTR_version_major), MP_ROM_INT(OMV_FIRMWARE_VERSION_MAJOR) }, + { MP_ROM_QSTR(MP_QSTR_version_minor), MP_ROM_INT(OMV_FIRMWARE_VERSION_MINOR) }, + { MP_ROM_QSTR(MP_QSTR_version_patch), MP_ROM_INT(OMV_FIRMWARE_VERSION_PATCH) }, + { MP_ROM_QSTR(MP_QSTR_version_string), MP_ROM_PTR(&py_omv_version_string_obj) }, + { MP_ROM_QSTR(MP_QSTR_arch), MP_ROM_PTR(&py_omv_arch_obj) }, + { MP_ROM_QSTR(MP_QSTR_board_type), MP_ROM_PTR(&py_omv_board_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_board_id), MP_ROM_PTR(&py_omv_board_id_obj) } +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t omv_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t) &globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_sensor.c b/src/openmv/src/omv/py/py_sensor.c new file mode 100755 index 0000000..1a613b9 --- /dev/null +++ b/src/openmv/src/omv/py/py_sensor.c @@ -0,0 +1,558 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Sensor Python module. + * + */ +#include "mp.h" +#include "pin.h" +#include "sensor.h" +#include "imlib.h" +#include "xalloc.h" +#include "py_assert.h" +#include "py_image.h" +#include "py_sensor.h" +#include "omv_boardconfig.h" +#include "py_helper.h" +#include "framebuffer.h" +#include "systick.h" + +extern sensor_t sensor; + +static mp_obj_t py_sensor_reset() { + PY_ASSERT_FALSE_MSG(sensor_reset() != 0, "Reset Failed"); + return mp_const_none; +} + +static mp_obj_t py_sensor_sleep(mp_obj_t enable) { + PY_ASSERT_FALSE_MSG(sensor_sleep(mp_obj_is_true(enable)) != 0, "Sleep Failed"); + return mp_const_none; +} + +static mp_obj_t py_sensor_shutdown(mp_obj_t enable) { + PY_ASSERT_FALSE_MSG(sensor_shutdown(mp_obj_is_true(enable)) != 0, "Shutdown Failed"); + return mp_const_none; +} + +static mp_obj_t py_sensor_flush() { + fb_update_jpeg_buffer(); + return mp_const_none; +} + +static mp_obj_t py_sensor_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // Snapshot image + mp_obj_t image = py_image(0, 0, 0, 0); + + // Sanity checks + PY_ASSERT_TRUE_MSG((sensor.pixformat != PIXFORMAT_JPEG), "Operation not supported on JPEG"); + + if (sensor.snapshot(&sensor, (image_t*) py_image_cobj(image), NULL)==-1) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); + return mp_const_false; + } + + return image; +} + +static mp_obj_t py_sensor_skip_frames(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_time), MP_MAP_LOOKUP); + mp_int_t time = 300; // OV Recommended. + + if (kw_arg != NULL) { + time = mp_obj_get_int(kw_arg->value); + } + + uint32_t millis = systick_current_millis(); + + if (!n_args) { + while ((systick_current_millis() - millis) < time) { // 32-bit math handles wrap arrounds... + if (sensor.snapshot(&sensor, NULL, NULL) == -1) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); + } + } + } else { + for (int i = 0, j = mp_obj_get_int(args[0]); i < j; i++) { + if ((kw_arg != NULL) && ((systick_current_millis() - millis) >= time)) { + break; + } + + if (sensor.snapshot(&sensor, NULL, NULL) == -1) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Sensor Timeout!!")); + } + } + } + + return mp_const_none; +} + +static mp_obj_t py_sensor_width() +{ + return mp_obj_new_int(resolution[sensor.framesize][0]); +} + +static mp_obj_t py_sensor_height() +{ + return mp_obj_new_int(resolution[sensor.framesize][1]); +} + +static mp_obj_t py_sensor_get_fb() +{ + if (MAIN_FB()->bpp == 0) { + return mp_const_none; + } + + image_t image = { + .w = MAIN_FB()->w, + .h = MAIN_FB()->h, + .bpp = MAIN_FB()->bpp, + .pixels = MAIN_FB()->pixels + }; + + return py_image_from_struct(&image); +} + +static mp_obj_t py_sensor_get_id() { + return mp_obj_new_int(sensor_get_id()); +} + +static mp_obj_t py_sensor_alloc_extra_fb(mp_obj_t w_obj, mp_obj_t h_obj, mp_obj_t type_obj) +{ + int w = mp_obj_get_int(w_obj); + PY_ASSERT_TRUE_MSG(w > 0, "Width must be > 0"); + + int h = mp_obj_get_int(h_obj); + PY_ASSERT_TRUE_MSG(h > 0, "Height must be > 0"); + + image_t img = { + .w = w, + .h = h, + .bpp = 0, + .pixels = 0 + }; + + switch(mp_obj_get_int(type_obj)) { + // TODO: PIXFORMAT_BINARY + // case PIXFOTMAT_BINARY: + // img.bpp = IMAGE_BPP_BINARY; + // break; + // TODO: PIXFORMAT_BINARY + case PIXFORMAT_GRAYSCALE: + img.bpp = IMAGE_BPP_GRAYSCALE; + break; + case PIXFORMAT_RGB565: + img.bpp = IMAGE_BPP_RGB565; + break; + case PIXFORMAT_BAYER: + img.bpp = IMAGE_BPP_BAYER; + break; + case PIXFORMAT_JPEG: + img.bpp = IMAGE_BPP_JPEG; + break; + default: + PY_ASSERT_TRUE_MSG(false, "Unknown type"); + break; + } + + fb_alloc_mark(); + img.pixels = fb_alloc0(image_size(&img)); + return py_image_from_struct(&img); +} + +static mp_obj_t py_sensor_dealloc_extra_fb() +{ + fb_free(); + fb_alloc_free_till_mark(); + return mp_const_none; +} + +static mp_obj_t py_sensor_set_pixformat(mp_obj_t pixformat) { + if (sensor_set_pixformat(mp_obj_get_int(pixformat)) != 0) { + PY_ASSERT_TRUE_MSG(0, "Pixel format is not supported!"); + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_framerate(mp_obj_t framerate) { + framerate_t fr; + switch (mp_obj_get_int(framerate)) { + case 2: + fr = FRAMERATE_2FPS; + break; + case 8: + fr = FRAMERATE_8FPS; + break; + case 15: + fr = FRAMERATE_15FPS; + break; + case 30: + fr = FRAMERATE_30FPS; + break; + case 60: + fr = FRAMERATE_60FPS; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid framerate")); + break; + } + + if (sensor_set_framerate(fr) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_framesize(mp_obj_t framesize) { + if (sensor_set_framesize(mp_obj_get_int(framesize)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_windowing(mp_obj_t roi_obj) { + int x, y, w, h; + int res_w = resolution[sensor.framesize][0]; + int res_h = resolution[sensor.framesize][1]; + + mp_obj_t *array; + mp_uint_t array_len; + mp_obj_get_array(roi_obj, &array_len, &array); + + if (array_len == 4) { + x = mp_obj_get_int(array[0]); + y = mp_obj_get_int(array[1]); + w = mp_obj_get_int(array[2]); + h = mp_obj_get_int(array[3]); + } else if (array_len == 2) { + w = mp_obj_get_int(array[0]); + h = mp_obj_get_int(array[1]); + x = (res_w / 2) - (w / 2); + y = (res_h / 2) - (h / 2); + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "The tuple/list must either be (x, y, w, h) or (w, h)")); + } + + if (w < 8 || h < 8) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "The selected window is too small")); + } + + if (x < 0 || (x + w) > res_w || y < 0 || (y + h) > res_h) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "The selected window is outside the bounds of the frame")); + } + + if (sensor_set_windowing(x, y, w, h) != 0) { + return mp_const_false; + } + + return mp_const_true; +} + +static mp_obj_t py_sensor_set_gainceiling(mp_obj_t gainceiling) { + gainceiling_t gain; + switch (mp_obj_get_int(gainceiling)) { + case 2: + gain = GAINCEILING_2X; + break; + case 4: + gain = GAINCEILING_4X; + break; + case 8: + gain = GAINCEILING_8X; + break; + case 16: + gain = GAINCEILING_16X; + break; + case 32: + gain = GAINCEILING_32X; + break; + case 64: + gain = GAINCEILING_64X; + break; + case 128: + gain = GAINCEILING_128X; + break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid gainceiling")); + break; + } + + if (sensor_set_gainceiling(gain) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_brightness(mp_obj_t brightness) { + if (sensor_set_brightness(mp_obj_get_int(brightness)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_contrast(mp_obj_t contrast) { + if (sensor_set_contrast(mp_obj_get_int(contrast)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_saturation(mp_obj_t saturation) { + if (sensor_set_saturation(mp_obj_get_int(saturation)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_quality(mp_obj_t qs) { + int q = mp_obj_get_int(qs); + PY_ASSERT_TRUE((q >= 0 && q <= 100)); + + q = 100-q; //invert quality + q = 255*q/100; //map to 0->255 + if (sensor_set_quality(q) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_colorbar(mp_obj_t enable) { + if (sensor_set_colorbar(mp_obj_is_true(enable)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + int enable = mp_obj_get_int(args[0]); + float gain_db = py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), NAN); + float gain_db_ceiling = py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db_ceiling), NAN); + if (sensor_set_auto_gain(enable, gain_db, gain_db_ceiling) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_get_gain_db() { + float gain_db; + if (sensor_get_gain_db(&gain_db) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_obj_new_float(gain_db); +} + +static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + int exposure_us = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_exposure_us), -1); + if (sensor_set_auto_exposure(mp_obj_get_int(args[0]), exposure_us) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_get_exposure_us() { + int exposure_us; + if (sensor_get_exposure_us(&exposure_us) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_obj_new_int(exposure_us); +} + +static mp_obj_t py_sensor_set_auto_whitebal(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + int enable = mp_obj_get_int(args[0]); + float rgb_gain_db[3] = {NAN, NAN, NAN}; + py_helper_keyword_float_array(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_gain_db), rgb_gain_db, 3); + if (sensor_set_auto_whitebal(enable, rgb_gain_db[0], rgb_gain_db[1], rgb_gain_db[2]) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_get_rgb_gain_db() { + float r_gain_db = 0.0, g_gain_db = 0.0, b_gain_db = 0.0; + if (sensor_get_rgb_gain_db(&r_gain_db, &g_gain_db, &b_gain_db) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_obj_new_tuple(3, (mp_obj_t []) {mp_obj_new_float(r_gain_db), mp_obj_new_float(g_gain_db), mp_obj_new_float(b_gain_db)}); +} + +static mp_obj_t py_sensor_set_hmirror(mp_obj_t enable) { + if (sensor_set_hmirror(mp_obj_is_true(enable)) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_set_vflip(mp_obj_t enable) { + if (sensor_set_vflip(mp_obj_is_true(enable)) != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); + } + return mp_const_none; +} + +static mp_obj_t py_sensor_set_special_effect(mp_obj_t sde) { + if (sensor_set_special_effect(mp_obj_get_int(sde)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_lens_correction(mp_obj_t enable, mp_obj_t radi, mp_obj_t coef) { + if (sensor_set_lens_correction(mp_obj_is_true(enable), + mp_obj_get_int(radi), mp_obj_get_int(coef)) != 0) { + return mp_const_false; + } + return mp_const_true; +} + +static mp_obj_t py_sensor_set_vsync_output(mp_obj_t pin_obj) { + pin_obj_t *pin = pin_obj; + sensor_set_vsync_output(pin->gpio, pin->pin_mask); + return mp_const_true; +} + +static mp_obj_t py_sensor_write_reg(mp_obj_t addr, mp_obj_t val) { + sensor_write_reg(mp_obj_get_int(addr), mp_obj_get_int(val)); + return mp_const_none; +} + +static mp_obj_t py_sensor_read_reg(mp_obj_t addr) { + return mp_obj_new_int(sensor_read_reg(mp_obj_get_int(addr))); +} + +//static void py_sensor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +// mp_printf(print, "", +// sensor.id.MIDH, sensor.id.MIDL, sensor.id.PID, sensor.id.VER); +//} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_reset_obj, py_sensor_reset); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_sleep_obj, py_sensor_sleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_shutdown_obj, py_sensor_shutdown); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_flush_obj, py_sensor_flush); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_snapshot_obj, 0, py_sensor_snapshot); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_skip_frames_obj, 0, py_sensor_skip_frames); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_width_obj, py_sensor_width); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_height_obj, py_sensor_height); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_fb_obj, py_sensor_get_fb); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_id_obj, py_sensor_get_id); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_sensor_alloc_extra_fb_obj, py_sensor_alloc_extra_fb); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_dealloc_extra_fb_obj, py_sensor_dealloc_extra_fb); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_pixformat_obj, py_sensor_set_pixformat); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_framerate_obj, py_sensor_set_framerate); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_framesize_obj, py_sensor_set_framesize); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_windowing_obj, py_sensor_set_windowing); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_gainceiling_obj, py_sensor_set_gainceiling); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_contrast_obj, py_sensor_set_contrast); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_brightness_obj, py_sensor_set_brightness); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_saturation_obj, py_sensor_set_saturation); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_quality_obj, py_sensor_set_quality); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_colorbar_obj, py_sensor_set_colorbar); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_gain_obj, 1,py_sensor_set_auto_gain); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_gain_db_obj, py_sensor_get_gain_db); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_exposure_obj,1,py_sensor_set_auto_exposure); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_exposure_us_obj, py_sensor_get_exposure_us); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_sensor_set_auto_whitebal_obj,1,py_sensor_set_auto_whitebal); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_sensor_get_rgb_gain_db_obj, py_sensor_get_rgb_gain_db); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_hmirror_obj, py_sensor_set_hmirror); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vflip_obj, py_sensor_set_vflip); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_special_effect_obj, py_sensor_set_special_effect); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_sensor_set_lens_correction_obj, py_sensor_set_lens_correction); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_set_vsync_output_obj, py_sensor_set_vsync_output); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_sensor_write_reg_obj, py_sensor_write_reg); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_sensor_read_reg_obj, py_sensor_read_reg); + +STATIC const mp_map_elem_t globals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sensor) }, + // Pixel format + { MP_OBJ_NEW_QSTR(MP_QSTR_BAYER), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_BAYER)}, /* 1BPP/RAW*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_RGB565)}, /* 2BPP/RGB565*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_YUV422), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_YUV422)}, /* 2BPP/YUV422*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_GRAYSCALE), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_GRAYSCALE)},/* 1BPP/GRAYSCALE*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_JPEG), MP_OBJ_NEW_SMALL_INT(PIXFORMAT_JPEG)}, /* JPEG/COMPRESSED*/ + { MP_OBJ_NEW_QSTR(MP_QSTR_OV9650), MP_OBJ_NEW_SMALL_INT(OV9650_ID)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_OV2640), MP_OBJ_NEW_SMALL_INT(OV2640_ID)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_OV7725), MP_OBJ_NEW_SMALL_INT(OV7725_ID)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_MT9V034), MP_OBJ_NEW_SMALL_INT(MT9V034_ID)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_LEPTON), MP_OBJ_NEW_SMALL_INT(LEPTON_ID)}, + + // Special effects + { MP_OBJ_NEW_QSTR(MP_QSTR_NORMAL), MP_OBJ_NEW_SMALL_INT(SDE_NORMAL)}, /* Normal/No SDE */ + { MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(SDE_NEGATIVE)}, /* Negative image */ + + // C/SIF Resolutions + { MP_OBJ_NEW_QSTR(MP_QSTR_QQCIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQCIF)}, /* 88x72 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QCIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QCIF)}, /* 176x144 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_CIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_CIF)}, /* 352x288 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QQSIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQSIF)}, /* 88x60 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QSIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QSIF)}, /* 176x120 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_SIF), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_SIF)}, /* 352x240 */ + // VGA Resolutions + { MP_OBJ_NEW_QSTR(MP_QSTR_QQQQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQQQVGA)}, /* 40x30 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QQQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQQVGA)}, /* 80x60 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQVGA)}, /* 160x120 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QVGA)}, /* 320x240 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_VGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_VGA)}, /* 640x480 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_HQQQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_HQQQVGA)}, /* 80x40 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_HQQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_HQQVGA)}, /* 160x80 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_HQVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_HQVGA)}, /* 240x160 */ + // FFT Resolutions + { MP_OBJ_NEW_QSTR(MP_QSTR_B64X32), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_64X32)}, /* 64x32 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_B64X64), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_64X64)}, /* 64x64 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_B128X64), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_128X64)}, /* 128x64 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_B128X128), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_128X128)}, /* 128x128 */ + // Other + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_LCD)}, /* 128x160 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_QQVGA2), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_QQVGA2)}, /* 128x160 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_WVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_WVGA)}, /* 720x480 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_WVGA2), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_WVGA2)}, /* 752x480 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_SVGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_SVGA)}, /* 800x600 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_SXGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_SXGA)}, /* 1280x1024 */ + { MP_OBJ_NEW_QSTR(MP_QSTR_UXGA), MP_OBJ_NEW_SMALL_INT(FRAMESIZE_UXGA)}, /* 1600x1200 */ + + // Sensor functions + { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&py_sensor_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&py_sensor_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_shutdown), (mp_obj_t)&py_sensor_shutdown_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_flush), (mp_obj_t)&py_sensor_flush_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_snapshot), (mp_obj_t)&py_sensor_snapshot_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_skip_frames), (mp_obj_t)&py_sensor_skip_frames_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_sensor_width_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_sensor_height_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_fb), (mp_obj_t)&py_sensor_get_fb_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_id), (mp_obj_t)&py_sensor_get_id_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_alloc_extra_fb), (mp_obj_t)&py_sensor_alloc_extra_fb_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_dealloc_extra_fb), (mp_obj_t)&py_sensor_dealloc_extra_fb_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_pixformat), (mp_obj_t)&py_sensor_set_pixformat_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_framerate), (mp_obj_t)&py_sensor_set_framerate_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_framesize), (mp_obj_t)&py_sensor_set_framesize_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_windowing), (mp_obj_t)&py_sensor_set_windowing_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_gainceiling), (mp_obj_t)&py_sensor_set_gainceiling_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_contrast), (mp_obj_t)&py_sensor_set_contrast_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_brightness), (mp_obj_t)&py_sensor_set_brightness_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_saturation), (mp_obj_t)&py_sensor_set_saturation_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_quality), (mp_obj_t)&py_sensor_set_quality_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_colorbar), (mp_obj_t)&py_sensor_set_colorbar_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_gain), (mp_obj_t)&py_sensor_set_auto_gain_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_gain_db), (mp_obj_t)&py_sensor_get_gain_db_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_exposure), (mp_obj_t)&py_sensor_set_auto_exposure_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_exposure_us), (mp_obj_t)&py_sensor_get_exposure_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_auto_whitebal), (mp_obj_t)&py_sensor_set_auto_whitebal_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_rgb_gain_db), (mp_obj_t)&py_sensor_get_rgb_gain_db_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_hmirror), (mp_obj_t)&py_sensor_set_hmirror_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_vflip), (mp_obj_t)&py_sensor_set_vflip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_special_effect), (mp_obj_t)&py_sensor_set_special_effect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_lens_correction), (mp_obj_t)&py_sensor_set_lens_correction_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set_vsync_output), (mp_obj_t)&py_sensor_set_vsync_output_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___write_reg), (mp_obj_t)&py_sensor_write_reg_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___read_reg), (mp_obj_t)&py_sensor_read_reg_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t sensor_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_sensor.h b/src/openmv/src/omv/py/py_sensor.h new file mode 100755 index 0000000..9add13d --- /dev/null +++ b/src/openmv/src/omv/py/py_sensor.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Sensor Python module. + * + */ +#ifndef __PY_SENSOR_H__ +#define __PY_SENSOR_H__ +const mp_obj_module_t *py_sensor_init(); +#endif // __PY_SENSOR_H__ diff --git a/src/openmv/src/omv/py/py_time.c b/src/openmv/src/omv/py/py_time.c new file mode 100755 index 0000000..4c6e394 --- /dev/null +++ b/src/openmv/src/omv/py/py_time.c @@ -0,0 +1,129 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Time Python module. + * + */ +#include +#include "systick.h" +#include "py_time.h" + +/* Clock Type */ +typedef struct _py_clock_obj_t { + mp_obj_base_t base; + uint32_t t_start; + uint32_t t_ticks; + uint32_t t_frame; +} py_clock_obj_t; + +mp_obj_t py_clock_tick(mp_obj_t clock_obj) +{ + py_clock_obj_t *clock = (py_clock_obj_t*) clock_obj; + clock->t_start = systick_current_millis(); + return mp_const_none; +} + +mp_obj_t py_clock_fps(mp_obj_t clock_obj) +{ + py_clock_obj_t *clock = (py_clock_obj_t*) clock_obj; + clock->t_frame++; + clock->t_ticks += (systick_current_millis()-clock->t_start); + float fps = 1000.0f / (clock->t_ticks/(float)clock->t_frame); + if (clock->t_ticks >= 2000) { + // Reset the FPS clock every 2s + clock->t_frame = 0; + clock->t_ticks = 0; + } + return mp_obj_new_float(fps); +} + +mp_obj_t py_clock_avg(mp_obj_t clock_obj) +{ + py_clock_obj_t *clock = (py_clock_obj_t*) clock_obj; + clock->t_frame++; + clock->t_ticks += (systick_current_millis()-clock->t_start); + return mp_obj_new_float(clock->t_ticks/(float)clock->t_frame); +} + +mp_obj_t py_clock_reset(mp_obj_t clock_obj) +{ + py_clock_obj_t *clock = (py_clock_obj_t*) clock_obj; + clock->t_start = 0; + clock->t_ticks = 0; + clock->t_frame = 0; + return mp_const_none; +} + +static void py_clock_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_clock_obj_t *self = self_in; + + /* print some info */ + mp_printf(print, "t_start:%d t_ticks:%d t_frame:%d\n", + self->t_start, self->t_ticks, self->t_frame); +} + +static MP_DEFINE_CONST_FUN_OBJ_1(py_clock_tick_obj, py_clock_tick); +static MP_DEFINE_CONST_FUN_OBJ_1(py_clock_fps_obj, py_clock_fps); +static MP_DEFINE_CONST_FUN_OBJ_1(py_clock_avg_obj, py_clock_avg); +static MP_DEFINE_CONST_FUN_OBJ_1(py_clock_reset_obj, py_clock_reset); + +static const mp_map_elem_t locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_tick), (mp_obj_t)&py_clock_tick_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_fps), (mp_obj_t)&py_clock_fps_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_avg), (mp_obj_t)&py_clock_avg_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&py_clock_reset_obj}, + { NULL, NULL }, +}; + +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +static const mp_obj_type_t py_clock_type = { + { &mp_type_type }, + .name = MP_QSTR_Clock, + .print = py_clock_print, + .locals_dict = (mp_obj_t)&locals_dict, +}; + +static mp_obj_t py_time_ticks() +{ + return mp_obj_new_int(systick_current_millis()); +} + +static mp_obj_t py_time_sleep(mp_obj_t ms) +{ + systick_sleep(mp_obj_get_int(ms)); + return mp_const_none; +} + +static mp_obj_t py_time_clock() +{ + py_clock_obj_t *clock =NULL; + clock = m_new_obj(py_clock_obj_t); + clock->base.type = &py_clock_type; + clock->t_start = 0; + clock->t_ticks = 0; + clock->t_frame = 0; + + return clock; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_time_ticks_obj, py_time_ticks); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_time_sleep_obj, py_time_sleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_time_clock_obj, py_time_clock); + +static const mp_map_elem_t globals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_time) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks), (mp_obj_t)&py_time_ticks_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&py_time_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_clock), (mp_obj_t)&py_time_clock_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t time_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; diff --git a/src/openmv/src/omv/py/py_time.h b/src/openmv/src/omv/py/py_time.h new file mode 100755 index 0000000..89b50fa --- /dev/null +++ b/src/openmv/src/omv/py/py_time.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Time Python module. + * + */ +#ifndef __PY_TIME_H__ +#define __PY_TIME_H__ +const mp_obj_module_t *py_time_init(); +#endif // __PY_TIME_H__ diff --git a/src/openmv/src/omv/py/py_tof.h b/src/openmv/src/omv/py/py_tof.h new file mode 100755 index 0000000..3211dfd --- /dev/null +++ b/src/openmv/src/omv/py/py_tof.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * ToF Python module. + * + */ +#ifndef __PY_TOF_H__ +#define __PY_TOF_H__ +void py_tof_init0(); +#endif // __PY_TOF_H__ diff --git a/src/openmv/src/omv/py/qstrdefsomv.h b/src/openmv/src/omv/py/qstrdefsomv.h new file mode 100755 index 0000000..4211fd1 --- /dev/null +++ b/src/openmv/src/omv/py/qstrdefsomv.h @@ -0,0 +1,1026 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * qstrs specific to openmv + * + */ + +// OMV Module +Q(omv) +Q(version_major) +Q(version_minor) +Q(version_patch) +Q(version_string) +Q(arch) +Q(board_type) +Q(board_id) + +// Image module +Q(image) +Q(Image) +Q(rgb_to_lab) +Q(lab_to_rgb) +Q(rgb_to_grayscale) +Q(grayscale_to_rgb) +Q(HaarCascade) +Q(search) +Q(SEARCH_EX) +Q(SEARCH_DS) +Q(EDGE_CANNY) +Q(EDGE_SIMPLE) +Q(CORNER_FAST) +Q(CORNER_AGAST) +Q(load_descriptor) +Q(save_descriptor) +Q(match_descriptor) + +// Image class +Q(copy) +Q(copy_to_fb) +Q(save) +Q(width) +Q(height) +Q(format) +Q(size) +Q(midpoint_pool) +Q(midpoint_pooled) +Q(mean_pool) +Q(mean_pooled) +Q(find_template) +Q(kp_desc) +Q(lbp_desc) +Q(Cascade) +Q(find_features) +Q(find_keypoints) +Q(find_lbp) +Q(find_eye) +Q(find_edges) +Q(find_hog) +Q(cmp_lbp) +Q(roi) +Q(normalized) +Q(filter_outliers) +Q(scale_factor) +Q(max_keypoints) +Q(corner_detector) +Q(kptmatch) +Q(selective_search) +Q(a1) +Q(a2) +Q(a3) + +// Lcd Module +Q(lcd) +Q(type) +Q(set_backlight) +Q(get_backlight) +Q(display) +Q(clear) + +// Gif module +Q(gif) +Q(Gif) +Q(open) +Q(add_frame) +Q(loop) + +// Mjpeg module +Q(mjpeg) +Q(Mjpeg) + +// Led Module +Q(led) +Q(RED) +Q(GREEN) +Q(BLUE) +Q(IR) +Q(on) +Q(off) +Q(toggle) + +// Time Module +Q(time) +Q(ticks) +Q(sleep) +Q(clock) +Q(Clock) + +// Clock +Q(tick) +Q(fps) +Q(avg) + +//Sensor Module +Q(sensor) +Q(BAYER) +Q(RGB565) +Q(YUV422) +Q(GRAYSCALE) +Q(JPEG) +Q(OV9650) +Q(OV2640) +Q(OV7725) +Q(MT9V034) +Q(LEPTON) +Q(value) +Q(shutdown) + +// NN Module +Q(load) + +// Net +Q(Net) + +// Forward +Q(forward) +Q(dry_run) +Q(softmax) + +// Search +// duplicate Q(search) +// duplicate Q(roi) +// duplicate Q(threshold) +Q(min_scale) +Q(scale_mul) +Q(x_overlap) +Q(y_overlap) +Q(contrast_threshold) +// duplicate Q(softmax) +// NN Class +Q(nn_class) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +// duplicate Q(index) +// duplicate Q(value) + +// C/SIF Resolutions +Q(QQCIF) +Q(QCIF) +Q(CIF) +Q(QQSIF) +Q(QSIF) +Q(SIF) +// VGA Resolutions +Q(QQQQVGA) +Q(QQQVGA) +Q(QQVGA) +Q(QVGA) +Q(VGA) +Q(HQQQVGA) +Q(HQQVGA) +Q(HQVGA) +// FFT Resolutions +Q(B64X32) +Q(B64X64) +Q(B128X64) +Q(B128X128) +// Other +Q(LCD) +Q(QQVGA2) +Q(WVGA) +Q(WVGA2) +Q(SVGA) +Q(SXGA) +Q(UXGA) + +//SDE +Q(NORMAL) +Q(NEGATIVE) + +Q(reset) +Q(flush) +Q(snapshot) +Q(skip_frames) +Q(get_fb) +Q(get_id) +Q(alloc_extra_fb) +Q(dealloc_extra_fb) +Q(set_pixformat) +Q(set_framerate) +Q(set_framesize) +Q(set_vsync_output) +Q(set_binning) +Q(set_windowing) +Q(set_gainceiling) +Q(set_contrast) +Q(set_brightness) +Q(set_saturation) +Q(set_quality) +Q(set_colorbar) +Q(set_auto_gain) +Q(gain_db) +Q(gain_db_ceiling) +Q(get_gain_db) +Q(set_auto_exposure) +Q(exposure_us) +Q(get_exposure_us) +Q(set_auto_whitebal) +Q(rgb_gain_db) +Q(get_rgb_gain_db) +Q(set_hmirror) +Q(set_vflip) +Q(set_special_effect) +Q(set_lens_correction) +Q(__write_reg) +Q(__read_reg) + +// GPIOS +Q(P1) +Q(P2) +Q(P3) +Q(P4) +Q(P5) +Q(P6) +Q(PA1) +Q(PA2) +Q(PA3) +Q(PA4) +Q(PA5) +Q(PA6) +Q(PA7) +Q(PA8) +Q(PB1) +Q(PB2) +Q(PB3) +Q(PB4) +Q(IN) +Q(OUT) +Q(gpio) +Q(GPIO) +Q(low) +Q(high) + +// SPI +Q(spi) +Q(read) +Q(write) +Q(write_image) + +// UART +Q(uart) + +// File +Q(file) +Q(close) + +//Wlan +Q(wlan) +Q(WEP) +Q(WPA) +Q(WPA2) +Q(init) +Q(connect) +Q(connected) +Q(ifconfig) +Q(patch_version) +Q(patch_program) +Q(socket) +Q(send) +Q(recv) +Q(bind) +Q(listen) +Q(accept) +Q(settimeout) +Q(setblocking) +Q(select) +Q(AF_INET) +Q(AF_INET6) +Q(SOCK_STREAM) +Q(SOCK_DGRAM) +Q(SOCK_RAW) +Q(IPPROTO_IP) +Q(IPPROTO_ICMP) +Q(IPPROTO_IPV4) +Q(IPPROTO_TCP) +Q(IPPROTO_UDP) +Q(IPPROTO_IPV6) +Q(IPPROTO_RAW) + +// for WINC1500 module +Q(WINC) +Q(connect) +Q(start_ap) +Q(disconnect) +Q(isconnected) +Q(connected_sta) +Q(wait_for_sta) +Q(ifconfig) +Q(fw_version) +Q(fw_dump) +Q(fw_update) +Q(scan) +Q(rssi) +Q(OPEN) +Q(WEP) +Q(WPA_PSK) +Q(802_1X) +Q(MODE_STA) +Q(MODE_AP) +Q(MODE_P2P) +Q(MODE_BSP) +Q(MODE_FIRMWARE) +Q(ssid) +Q(key) +Q(security) +Q(bssid) + +// cpufreq Module +Q(cpufreq) +Q(CPUFREQ_120MHZ) +Q(CPUFREQ_144MHZ) +Q(CPUFREQ_168MHZ) +Q(CPUFREQ_192MHZ) +Q(CPUFREQ_216MHZ) +Q(get_frequency) +Q(set_frequency) + +// Get Pixel +Q(get_pixel) +Q(rgbtuple) + +// Set Pixel +Q(set_pixel) +Q(color) + +// To Bitmap +Q(to_bitmap) +// duplicate Q(copy) + +// To Grayscale +Q(to_grayscale) +// duplicate Q(copy) + +// To RGB565 +Q(to_rgb565) +// duplicate Q(copy) + +// To Rainbow +Q(to_rainbow) +// duplicate Q(copy) + +// Compress (in place) +Q(compress) +Q(quality) + +// Compress for IDE (in place) +Q(compress_for_ide) +// duplicate Q(quality) + +// Compressed (out of place) +Q(compressed) +// duplicate Q(quality) + +// Compressed for IDE (out of place) +Q(compressed_for_ide) +// duplicate Q(quality) + +// Clear +Q(clear) + +// Draw Line +Q(draw_line) +// duplicate Q(color) +Q(thickness) + +// Draw Rectangle +Q(draw_rectangle) +// duplicate Q(color) +// duplicate Q(thickness) +Q(fill) + +// Draw Circle +Q(draw_circle) +// duplicate Q(color) +// duplicate Q(thickness) +// duplicate Q(fill) + +// Draw String +Q(draw_string) +// duplicate Q(color) +Q(scale) +Q(x_spacing) +Q(y_spacing) +Q(mono_space) + +// Draw Cross +Q(draw_cross) +// duplicate Q(color) +// duplicate Q(size) +// duplicate Q(thickness) + +// Draw Arrow +Q(draw_arrow) +// duplicate Q(color) +// duplicate Q(size) +// duplicate Q(thickness) + +// Draw Image +Q(draw_image) +Q(x_scale) +Q(y_scale) +Q(mask) + +// Draw Keypoints +Q(draw_keypoints) +// duplicate Q(color) +// duplicate Q(size) +// duplicate Q(thickness) +// duplicate Q(fill) + +// Flood Fill +Q(flood_fill) +Q(seed_threshold) +Q(floating_threshold) +// duplicate Q(color) +Q(invert) +Q(clear_background) +// duplicate Q(mask) + +// Binary +Q(binary) +// duplicate Q(invert) +Q(zero) +// duplicate Q(mask) +// duplciate Q(to_bitmap) +// duplicate Q(copy) + +// Invert +// duplicate Q(invert) + +// And +Q(and) +Q(b_and) +// duplicate Q(mask) + +// Nand +Q(nand) +Q(b_nand) +// duplicate Q(mask) + +// Or +Q(or) +Q(b_or) +// duplicate Q(mask) + +// Nor +Q(nor) +Q(b_nor) +// duplicate Q(mask) + +// Xor +Q(xor) +Q(b_xor) +// duplicate Q(mask) + +// Xnor +Q(xnor) +Q(b_xnor) +// duplicate Q(mask) + +// Erode +Q(erode) +// duplicate Q(threshold) +// duplicate Q(mask) + +// Dilate +Q(dilate) +Q(threshold) +// duplicate Q(mask) + +// Open +// duplicate Q(open) +// duplicate Q(threshold) +// duplicate Q(mask) + +// Close +// duplicate Q(close) +// duplicate Q(threshold) +// duplicate Q(mask) + +// Top Hat +Q(top_hat) +// duplicate Q(threshold) +// duplicate Q(mask) + +// Black Hat +Q(black_hat) +// duplicate Q(threshold) +// duplicate Q(mask) + +// Negate +Q(negate) + +// Replace +Q(replace) +Q(hmirror) +Q(vflip) +// duplicate Q(mask) + +// Add Op +Q(add) +// duplicate Q(mask) + +// Sub Op +Q(sub) +Q(reverse) +// duplicate Q(mask) + +// Mul Op +Q(mul) +// duplicate Q(invert) +// duplicate Q(mask) + +// Div Op +Q(div) +// duplicate Q(invert) +// duplicate Q(mask) + +// Min +// duplicate Q(min) +// duplicate Q(mask) + +// Max +// duplicate Q(max) +// duplicate Q(mask) + +// Difference +Q(difference) +// duplicate Q(mask) + +// Blend +Q(blend) +Q(alpha) +// duplicate Q(mask) + +// Histogram Equalization +Q(histeq) +Q(adaptive) +Q(clip_limit) +// duplicate Q(mask) + +// Mean +Q(mean) +// duplicate Q(threshold) +Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Median +Q(median) +Q(percentile) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Mode +Q(mode) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Midpoint +Q(midpoint) +Q(bias) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Moprh +Q(morph) +// duplicate Q(mul) +// duplicate Q(add) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Gaussian Blur +Q(blur) +Q(gaussian) +Q(gaussian_blur) +Q(unsharp) +// duplicate Q(mul) +// duplicate Q(add) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Laplacian +Q(laplacian) +Q(sharpen) +// duplicate Q(mul) +// duplicate Q(add) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Bilateral +Q(bilateral) +Q(color_sigma) +Q(space_sigma) +// duplicate Q(threshold) +// duplicate Q(offset) +// duplicate Q(invert) +// duplicate Q(mask) + +// Cartoon +Q(cartoon) +// duplicate Q(seed_threshold) +// duplicate Q(floating_threshold) +Q(mask) + +// Shadow Removal +Q(remove_shadows) + +// Chromination Invariant +Q(chrominvar) + +// Illumination Invariant +Q(illuminvar) + +// Linear Polar +Q(linpolar) +// duplicate Q(reverse) + +// Log Polar +Q(logpolar) +// duplicate Q(reverse) + +// Lens Correction +Q(lens_corr) +Q(strength) +Q(zoom) + +// Rotation Correction +Q(rotation_corr) +Q(x_rotation) +Q(y_rotation) +Q(z_rotation) +Q(x_translation) +Q(y_translation) +// duplicate Q(zoom) + +// Structural Similarity +Q(get_similarity) +// Similarity Object +Q(similarity) +// duplicate Q(mean) +Q(stdev) +// duplicate Q(min) +// duplicate Q(max) + +// Get Histogram +Q(get_hist) +Q(get_histogram) +// duplicate Q(roi) +Q(bins) +Q(l_bins) +Q(a_bins) +Q(b_bins) +Q(thresholds) +// duplicate Q(invert) +// Histogram Object +Q(histogram) +// duplicate Q(bins) +// duplicate Q(l_bins) +// duplicate Q(a_bins) +// duplicate Q(b_bins) +Q(get_percentile) +Q(get_threshold) +Q(get_stats) +Q(get_statistics) +Q(statistics) +// Percentile Object +// duplicate Q(percentile) +Q(value) +Q(l_value) +Q(a_value) +Q(b_value) +// Threshold Object +// duplicate Q(threshold) +// duplicate Q(value) +// duplicate Q(l_value) +// duplicate Q(a_value) +// duplicate Q(b_value) + +// Get Statistics +// duplicate Q(get_stats) +// duplicate Q(get_statistics) +// duplicate Q(roi) +// duplicate Q(bins) +// duplicate Q(l_bins) +// duplicate Q(a_bins) +// duplicate Q(b_bins) +// duplicate Q(thresholds) +// duplicate Q(invert) +// Statistics Object +// duplicate Q(statistics) +// duplicate Q(mean) +// duplicate Q(median) +// duplicate Q(mode) +// duplicate Q(stdev) +// duplicate Q(min) +// duplicate Q(max) +Q(lq) +Q(uq) +Q(l_mean) +Q(l_median) +Q(l_mode) +Q(l_stdev) +Q(l_min) +Q(l_max) +Q(l_lq) +Q(l_uq) +Q(a_mean) +Q(a_median) +Q(a_mode) +Q(a_stdev) +Q(a_min) +Q(a_max) +Q(a_lq) +Q(a_uq) +Q(b_mean) +Q(b_median) +Q(b_mode) +Q(b_stdev) +Q(b_min) +Q(b_max) +Q(b_lq) +Q(b_uq) + +// Get Regression +Q(get_regression) +// duplicate Q(roi) +Q(x_stride) +Q(y_stride) +// duplicate Q(invert) +Q(area_threshold) +Q(pixels_threshold) +Q(robust) +// Line Object +Q(line) +// duplicate Q(line) +Q(x1) +Q(y1) +Q(x2) +Q(y2) +Q(length) +Q(magnitude) +Q(theta) +Q(rho) + +// Find Blobs +Q(find_blobs) +// duplicate Q(roi) +// duplicate Q(x_stride) +// duplicate Q(y_stride) +// duplicate Q(invert) +// duplicate Q(area_threshold) +// duplicate Q(pixels_threshold) +Q(merge) +Q(margin) +Q(threshold_cb) +Q(merge_cb) +// Blob Object +Q(blob) +Q(rect) +Q(x) +Q(y) +Q(w) +Q(h) +Q(pixels) +Q(cx) +Q(cy) +Q(rotation) +Q(code) +Q(count) +Q(area) +Q(density) + +// Find Lines +Q(find_lines) +// duplicate Q(roi) +// duplicate Q(x_stride) +// duplicate Q(y_stride) +// duplicate Q(threshold) +Q(theta_margin) +Q(rho_margin) + +// Find Line Segments +Q(find_line_segments) +// duplicate Q(roi) +Q(merge_distance) +Q(max_theta_diff) + +// Find Circles +Q(find_circles) +// duplicate Q(roi) +// duplicate Q(x_stride) +// duplicate Q(y_stride) +// duplicate Q(threshold) +Q(x_margin) +Q(y_margin) +Q(r_margin) +Q(r_min) +Q(r_max) +Q(r_step) +// Circle Object +Q(circle) +// duplicate Q(circle) +// duplicate Q(x) +// duplicate Q(y) +Q(r) +// duplicate Q(magnitude) + +// Find Rects +Q(find_rects) +// duplicate Q(roi) +// duplicate Q(threshold) +// Rect Object +// duplicate Q(rect) +Q(corners) +// duplicate Q(rect) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +// duplicate Q(magnitude) + +// Find QRCodes +Q(find_qrcodes) +// duplicate Q(roi) +// QRCode Object +Q(qrcode) +// duplicate Q(corners) +// duplicate Q(rect) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +Q(payload) +Q(version) +Q(ecc_level) +Q(mask) +Q(data_type) +Q(eci) +Q(is_numeric) +Q(is_alphanumeric) +Q(is_binary) +Q(is_kanji) + +// Find AprilTags +Q(find_apriltags) +// duplicate Q(roi) +Q(families) +Q(fx) +Q(fy) +// duplicate Q(cx) +// duplicate Q(cy) +// AprilTag Object +Q(apriltag) +// duplicate Q(corners) +// duplicate Q(rect) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +Q(id) +Q(family) +Q(hamming) +// duplicate Q(cx) +// duplicate Q(cy) +// duplicate Q(rotation) +Q(goodness) +Q(decision_margin) +// duplicate Q(x_translation) +// duplicate Q(y_translation) +Q(z_translation) +// duplicate Q(x_rotation) +// duplicate Q(y_rotation) +// duplicate Q(z_rotation) +Q(TAG16H5) +Q(TAG25H7) +Q(TAG25H9) +Q(TAG36H10) +Q(TAG36H11) +Q(ARTOOLKIT) + +// Find DataMatrices +Q(find_datamatrices) +// duplicate Q(roi) +Q(effort) +// DataMatrix Object +Q(datamatrix) +// duplicate Q(corners) +// duplicate Q(rect) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +// duplicate Q(payload) +// duplicate Q(rotation) +Q(rows) +Q(columns) +Q(capacity) +Q(padding) + +// Find BarCodes +Q(find_barcodes) +// duplicate Q(roi) +// BarCode Object +Q(barcode) +// duplicate Q(corners) +// duplicate Q(rect) +// duplicate Q(x) +// duplicate Q(y) +// duplicate Q(w) +// duplicate Q(h) +// duplicate Q(payload) +// duplicate Q(type) +// duplicate Q(rotation) +// duplicate Q(quality) +Q(EAN2) +Q(EAN5) +Q(EAN8) +Q(UPCE) +Q(ISBN10) +Q(UPCA) +Q(EAN13) +Q(ISBN13) +Q(I25) +Q(DATABAR) +Q(DATABAR_EXP) +Q(CODABAR) +Q(CODE39) +Q(PDF417) +Q(CODE93) +Q(CODE128) + +// Find Displacement +Q(find_displacement) +// duplicate Q(roi) +Q(template_roi) +// duplicate Q(logpolar) +Q(fix_rotation_scale) +Q(displacement) +// duplicate Q(x_translation) +// duplicate Q(y_translation) +// duplicate Q(rotation) +// duplicate Q(scale) +Q(response) + +// Image Writer +Q(ImageWriter) +// Image Writer Object +Q(imagewriter) +// duplicate Q(size) +// duplicate Q(add_frame) +// duplicate Q(close) + +// Image Reader +Q(ImageReader) +// Image Reader Object +Q(imagereader) +// duplicate Q(size) +Q(next_frame) +// duplicate Q(copy_to_fb) +// duplicate Q(loop) +// duplicate Q(close) + +// FIR Module +Q(fir) +// duplicate Q(init) +Q(FIR_NONE) +Q(FIR_SHIELD) +Q(FIR_MLX90620) +Q(FIR_MLX90621) +Q(FIR_MLX90640) +Q(FIR_AMG8833) +Q(refresh) +Q(resolution) +// duplicate Q(deinit) +// duplicate Q(width) +// duplicate Q(height) +// duplicate Q(type) +Q(read_ta) +Q(read_ir) +Q(draw_ta) +// duplicate Q(alpha) +// duplicate Q(scale) +Q(draw_ir) +// duplicate Q(alpha) +// duplicate Q(scale) +// duplicate Q(snapshot) +// duplicate Q(alpha) +// duplicate Q(scale) +Q(pixformat) +// duplciate Q(copy_to_fb) diff --git a/src/openmv/src/omv/ringbuf.c b/src/openmv/src/omv/ringbuf.c new file mode 100755 index 0000000..e66330e --- /dev/null +++ b/src/openmv/src/omv/ringbuf.c @@ -0,0 +1,44 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Simple Ring Buffer implementation. + * + */ +#include +#include "ringbuf.h" + +void ring_buf_init(ring_buf_t *buf) +{ + memset(buf, 0, sizeof(*buf)); +} + +int ring_buf_empty(ring_buf_t *buf) +{ + return (buf->head == buf->tail); +} + +void ring_buf_put(ring_buf_t *buf, uint8_t c) +{ + if ((buf->tail + 1) % BUFFER_SIZE == buf->head) { + /*buffer is full*/ + return; + } + + buf->data[buf->tail] = c; + buf->tail = (buf->tail + 1) % BUFFER_SIZE; +} + +uint8_t ring_buf_get(ring_buf_t *buf) +{ + uint8_t c; + if (buf->head == buf->tail) { + /*buffer is empty*/ + return 0; + } + + c = buf->data[buf->head]; + buf->head = (buf->head + 1) % BUFFER_SIZE; + return c; +} diff --git a/src/openmv/src/omv/ringbuf.h b/src/openmv/src/omv/ringbuf.h new file mode 100755 index 0000000..f7a3766 --- /dev/null +++ b/src/openmv/src/omv/ringbuf.h @@ -0,0 +1,24 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Simple Ring Buffer implementation. + * + */ +#ifndef __RING_BUFFER_H__ +#define __RING_BUFFER_H__ +#include +#define BUFFER_SIZE (1024) + +typedef struct ring_buffer { + volatile uint32_t head; + volatile uint32_t tail; + uint8_t data[BUFFER_SIZE]; +} ring_buf_t; + +void ring_buf_init(ring_buf_t *buf); +int ring_buf_empty(ring_buf_t *buf); +void ring_buf_put(ring_buf_t *buf, uint8_t c); +uint8_t ring_buf_get(ring_buf_t *buf); +#endif /* __RING_BUFFER_H__ */ diff --git a/src/openmv/src/omv/sdcard_sdio.c b/src/openmv/src/omv/sdcard_sdio.c new file mode 100755 index 0000000..4afff96 --- /dev/null +++ b/src/openmv/src/omv/sdcard_sdio.c @@ -0,0 +1,205 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SD card SDIO driver. + * + */ +#include +#include STM32_HAL_H +#include + +#include "mp.h" +#include "irq.h" +#include "ffconf.h" +#include "diskio.h" +#include "systick.h" +#include "sdcard.h" +#include "omv_boardconfig.h" + +#define SDIO_TIMEOUT (0xFFFFFFFF) // Delay counter +#define SDIO_TXRX_STREAM DMA2_Stream3 +#define SDIO_TXRX_CHANNEL DMA_CHANNEL_4 + +#define UNALIGNED_BUFFER(p) ((uint32_t)p & 3) +#define CCM_BUFFER(p) (!(((uint32_t) p) & (1u<<29))) + +SD_HandleTypeDef SDHandle; +static DMA_HandleTypeDef DMAHandle; + +static void dma_init(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel, uint32_t direction) +{ + DMAHandle.Instance = dma_stream; + DMAHandle.Init.Channel = dma_channel; + DMAHandle.Init.Direction = direction; + DMAHandle.Init.MemInc = DMA_MINC_ENABLE; + DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + DMAHandle.Init.Mode = DMA_PFCTRL; + DMAHandle.Init.Priority = DMA_PRIORITY_LOW; + DMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + DMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + DMAHandle.Init.MemBurst = DMA_MBURST_INC4; + DMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + + // Associate the DMA handle with the SDIO handle + // Note: The DMA handle is linked to both SDIO TX/RX handles + // since we're using a single DMA channel/IRQHandler for TX/RX. + __HAL_LINKDMA(&SDHandle, hdmatx, DMAHandle); + __HAL_LINKDMA(&SDHandle, hdmarx, DMAHandle); + + HAL_DMA_DeInit(&DMAHandle); + if (HAL_DMA_Init(&DMAHandle) != HAL_OK) { + // Initialization Error + __BKPT(0); + } + + // Configure and enable SD IRQ Channel + HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); +} + +static void dma_deinit() +{ + // Just disable the DMA IRQ + HAL_NVIC_DisableIRQ(DMA2_Stream3_IRQn); +} + +bool sdcard_is_present(void) +{ + return (HAL_GPIO_ReadPin(SD_CD_PORT, SD_CD_PIN)==GPIO_PIN_RESET); +} + +extern void __fatal_error(const char *msg); + +void sdcard_init(void) +{ + volatile int retry=10; + HAL_SD_CardInfoTypedef cardinfo; + + // SDIO configuration + SDHandle.Instance = SDIO; + SDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + SDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + SDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + SDHandle.Init.BusWide = SDIO_BUS_WIDE_1B; + SDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + SDHandle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; //INIT_CLK_DIV will be used first + + // Deinit SD + HAL_SD_DeInit(&SDHandle); + // Init SD interface + while(HAL_SD_Init(&SDHandle, &cardinfo) != SD_OK && retry--) { + if (retry == 0) { + __fatal_error("Failed to init sdcard: init timeout"); + } + systick_sleep(100); + } + + /* Configure the SD Card in wide bus mode. */ + if (HAL_SD_WideBusOperation_Config(&SDHandle, SDIO_BUS_WIDE_4B) != SD_OK) { + __fatal_error("Failed to init sensor, sdcard: config wide bus"); + } + + // Configure and enable DMA IRQ Channel + // SDIO IRQ should have a higher priority than DMA IRQ because it needs to + // preempt the DMA irq handler to set a flag indicating the end of transfer. + HAL_NVIC_SetPriority(SDIO_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO); + HAL_NVIC_EnableIRQ(SDIO_IRQn); +} + +bool sdcard_power_on(void) +{ + if (!sdcard_is_present()) { + return false; + } + + return true; +} + +void sdcard_power_off(void) +{ + +} + +mp_uint_t sdcard_read_blocks(uint8_t *buff, uint32_t sector, uint32_t count) +{ + HAL_SD_ErrorTypedef err; + + // If buffer is unaligned or located in CCM don't use DMA. + if (CCM_BUFFER(buff) || UNALIGNED_BUFFER(buff)) { + if (UNALIGNED_BUFFER(buff)) { + printf("unaligned read buf:%p count%lu \n", buff, count); + } + // This transfer has to be done in an atomic section. + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + err = HAL_SD_ReadBlocks(&SDHandle, (uint32_t*)buff, + sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count); + MICROPY_END_ATOMIC_SECTION(atomic_state); + } else { + // Disable USB IRQ to prevent FatFS/MSC contention + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); __DSB(); __ISB(); + + dma_init(SDIO_TXRX_STREAM, SDIO_TXRX_CHANNEL, DMA_PERIPH_TO_MEMORY); + + err = HAL_SD_ReadBlocks_DMA(&SDHandle, (uint32_t*)buff, + sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count); + + if (err == SD_OK) { + err = HAL_SD_CheckReadOperation(&SDHandle, SDIO_TIMEOUT); + } + + if (err != SD_OK) { + printf("read buf:%p addr:%lu count%lu error:%d\n", buff, sector, count, err); + } + dma_deinit(); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + return (err != SD_OK); +} + +mp_uint_t sdcard_write_blocks(const uint8_t *buff, uint32_t sector, uint32_t count) +{ + HAL_SD_ErrorTypedef err; + + // If buffer is unaligned or located in CCM don't use DMA. + if (CCM_BUFFER(buff) || UNALIGNED_BUFFER(buff)) { + if (UNALIGNED_BUFFER(buff)) { + printf("unaligned write buf:%p count%lu \n", buff, count); + } + + // This transfer has to be done in an atomic section. + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + err = HAL_SD_WriteBlocks(&SDHandle, (uint32_t*)buff, + sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count); + MICROPY_END_ATOMIC_SECTION(atomic_state); + } else { + // Disable USB IRQ to prevent FatFS/MSC contention + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); __DSB(); __ISB(); + + dma_init(SDIO_TXRX_STREAM, SDIO_TXRX_CHANNEL, DMA_MEMORY_TO_PERIPH); + + err = HAL_SD_WriteBlocks_DMA(&SDHandle, (uint32_t*)buff, + sector * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, count); + + if (err == SD_OK) { + err = HAL_SD_CheckWriteOperation(&SDHandle, SDIO_TIMEOUT); + } + + if (err != SD_OK) { + printf("write buf:%p addr:%lu count%lu error:%d\n", buff, sector, count, err); + } + dma_deinit(); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } + return (err != SD_OK); +} + +uint64_t sdcard_get_capacity_in_bytes(void) +{ + HAL_SD_CardInfoTypedef cardinfo; + HAL_SD_Get_CardInfo(&SDHandle, &cardinfo); + return cardinfo.CardCapacity; +} diff --git a/src/openmv/src/omv/sdcard_spi.c b/src/openmv/src/omv/sdcard_spi.c new file mode 100755 index 0000000..6b79191 --- /dev/null +++ b/src/openmv/src/omv/sdcard_spi.c @@ -0,0 +1,499 @@ +/* Copyright (c) 2010, Martin Thomas, ChaN All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the copyright holders nor the names of + 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 OWNER 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 "mp.h" +#include +#include STM32_HAL_H +#include "ffconf.h" +#include "diskio.h" +#include "pincfg.h" +#include "systick.h" +#include "sdcard.h" + +/* Definitions for MMC/SDC command */ +#define CMD0 (0x40+0) /* GO_IDLE_STATE */ +#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ +#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (0x40+8) /* SEND_IF_COND */ +#define CMD9 (0x40+9) /* SEND_CSD */ +#define CMD10 (0x40+10) /* SEND_CID */ +#define CMD12 (0x40+12) /* STOP_TRANSMISSION */ +#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */ +#define CMD16 (0x40+16) /* SET_BLOCKLEN */ +#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ +#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */ +#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (0x40+24) /* WRITE_BLOCK */ +#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD55 (0x40+55) /* APP_CMD */ +#define CMD58 (0x40+58) /* READ_OCR */ + +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + +#define SD_TIMEOUT (100000) +#define SPI_TIMEOUT (100) /* in ms */ + +/*-------------------------------------------------------------------------- + Module Private Functions and Variables + ---------------------------------------------------------------------------*/ +static BYTE CardType; /* Card type flags */ +static const DWORD socket_state_mask_cp = (1 << 0); +static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */ + +static SPI_HandleTypeDef SPIHandle; +DRESULT sdcard_ioctl(BYTE drv, BYTE ctrl, void *buff); + +bool sdcard_is_present(void) +{ + return (HAL_GPIO_ReadPin(SD_CD_PORT, SD_CD_PIN)==GPIO_PIN_RESET); +} + +/*-----------------------------------------------------------------------*/ +/* Transmit/Receive a byte to MMC via SPI (Platform dependent) */ +/*-----------------------------------------------------------------------*/ +static BYTE spi_send(BYTE out) +{ + if (HAL_SPI_TransmitReceive(&SPIHandle, &out, &out, 1, SPI_TIMEOUT) != HAL_OK) { + BREAK(); + } + return out; +} + +static bool spi_send_buff(const BYTE *buff, uint32_t size) +{ + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + bool res = (HAL_SPI_Transmit(&SPIHandle, (void*)buff, size, SPI_TIMEOUT) == HAL_OK); + MICROPY_END_ATOMIC_SECTION(atomic_state); + return res; +} + +#define spi_recv() spi_send(0xFF) + +static bool spi_recv_buff(BYTE *buff, uint32_t size) +{ + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + do { + *buff++ = spi_recv(); + } while (--size); + MICROPY_END_ATOMIC_SECTION(atomic_state); + return true; +} + +/*-----------------------------------------------------------------------*/ +/* Wait for card ready */ +/*-----------------------------------------------------------------------*/ +static BYTE wait_ready(void) +{ + BYTE res; + volatile int timeout = SD_TIMEOUT; + + spi_recv(); + do + res = spi_recv(); + while ((res != 0xFF) && timeout--); + + return res; +} + +/*-----------------------------------------------------------------------*/ +/* SD_DESELECT the card and release SPI bus */ +/*-----------------------------------------------------------------------*/ +static void release_spi(void) +{ + SD_DESELECT(); + spi_recv(); +} + +/*-----------------------------------------------------------------------*/ +/* Receive a data packet from MMC */ +/*-----------------------------------------------------------------------*/ +static bool rcvr_datablock(BYTE *buff, UINT btr) +{ + BYTE token; + volatile int timeout = SD_TIMEOUT; + do { /* Wait for data packet in timeout of 100ms */ + token = spi_recv(); + } while ((token == 0xFF) && timeout--); + + if(token != 0xFE) { + return false; /* If not valid data token, return with error */ + } + + spi_recv_buff(buff, btr); + + /* Discard CRC */ + spi_recv(); + spi_recv(); + return true; +} + +/*-----------------------------------------------------------------------*/ +/* Send a data packet to MMC */ +/*-----------------------------------------------------------------------*/ +static bool xmit_datablock(const BYTE *buff, BYTE token) +{ + BYTE resp; + + if (wait_ready() != 0xFF) { + return false; + } + + /* transmit data token */ + spi_send(token); + + if (token != 0xFD) { /* Is data token */ + spi_send_buff(buff, SDCARD_BLOCK_SIZE); + + /* CRC (Dummy) */ + spi_send(0xFF); + spi_send(0xFF); + + /* Receive data response */ + resp = spi_recv(); + + /* If not accepted, return with error */ + if ((resp & 0x1F) != 0x05) + return false; + } + + return true; +} + +static BYTE send_cmd(BYTE cmd, DWORD arg) +{ + BYTE n, res; + + if (cmd & 0x80) { /* ACMD is the command sequence of CMD55-CMD */ + cmd &= 0x7F; + res = send_cmd(CMD55, 0); + if (res > 1) return res; + } + + /* SD_SELECT the card and wait for ready */ + SD_DESELECT(); + SD_SELECT(); + if (wait_ready() != 0xFF) { + return 0xFF; + } + + /* Send command packet */ + spi_send(cmd); /* Start + Command index */ + spi_send((BYTE)(arg >> 24)); /* Argument[31..24] */ + spi_send((BYTE)(arg >> 16)); /* Argument[23..16] */ + spi_send((BYTE)(arg >> 8)); /* Argument[15..8] */ + spi_send((BYTE)arg); /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ + if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ + spi_send(n); + + /* Receive command response */ + if (cmd == CMD12) spi_recv(); /* Skip a stuff byte when stop reading */ + + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do + res = spi_recv(); + while ((res & 0x80) && --n); + + return res; /* Return with the response value */ +} + + +void sdcard_hw_init(uint32_t baudrate) +{ + /* SPI configuration */ + SPIHandle.Instance = SD_SPI; + SPIHandle.Init.Mode = SPI_MODE_MASTER; + SPIHandle.Init.Direction = SPI_DIRECTION_2LINES; + SPIHandle.Init.DataSize = SPI_DATASIZE_8BIT; + SPIHandle.Init.CLKPolarity = SPI_POLARITY_LOW; + SPIHandle.Init.CLKPhase = SPI_PHASE_1EDGE; + SPIHandle.Init.NSS = SPI_NSS_SOFT; + SPIHandle.Init.BaudRatePrescaler = baudrate; + SPIHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; + SPIHandle.Init.TIMode = SPI_TIMODE_DISABLED; + SPIHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; + SPIHandle.Init.CRCPolynomial = 7; + + /* Initialize the SPI */ + if (HAL_SPI_Init(&SPIHandle) != HAL_OK) { + /* Initialization Error */ + BREAK(); + } else { + // TODO is this needed ? + uint8_t buf[1]; + // TODO use while ? + HAL_SPI_Receive(&SPIHandle, buf, sizeof(buf), SD_TIMEOUT); + } +} + +void sdcard_init(void) +{ + BYTE n, cmd, ty, ocr[4]; + volatile int timeout = SD_TIMEOUT; + + sdcard_hw_init(SPI_BAUDRATEPRESCALER_256); + systick_sleep(250); + + for (n = 10; n; n--) { + /* 80 dummy clocks */ + spi_recv(); + } + + ty = 0; + if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + if (send_cmd(CMD8, 0x1AA) == 1) { /* SDHC */ + for (n = 0; n < 4; n++) { + ocr[n] = spi_recv(); /* Get trailing return value of R7 response */ + } + if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at VDD range of 2.7-3.6V */ + while (--timeout && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (timeout && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + for (n = 0; n < 4; n++) { + ocr[n] = spi_recv(); + } + ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; + } + } + } else { /* SDSC or MMC */ + if (send_cmd(ACMD41, 0) <= 1) { + ty = CT_SD1; cmd = ACMD41; /* SDSC */ + } else { + ty = CT_MMC; cmd = CMD1; /* MMC */ + } + while (--timeout && send_cmd(cmd, 0)); /* Wait for leaving idle state */ + if (!timeout || send_cmd(CMD16, SDCARD_BLOCK_SIZE) != 0) /* Set R/W block length */ + ty = 0; + } + } + + CardType = ty; + release_spi(); + + if (ty) { + /* Initialization succeeded */ + Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ + sdcard_hw_init(SPI_BAUDRATEPRESCALER_2); + } else { + /* Initialization failed */ + BREAK(); + } +} + +bool sdcard_power_on(void) +{ + return true; +} + +void sdcard_power_off(void) +{ + +} + +mp_uint_t sdcard_read_blocks(uint8_t *buff, uint32_t sector, uint32_t count) +{ + if (Stat & STA_NOINIT) { + return false; + } + + if (!(CardType & CT_BLOCK)) { + sector *= SDCARD_BLOCK_SIZE; /* Convert to byte address if needed */ + } + + if (count == 1) { /* Single block read */ + if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ + if (rcvr_datablock(buff, SDCARD_BLOCK_SIZE)) { + count = 0; + } + } + } else { /* Multiple block read */ + if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ + do { + if (!rcvr_datablock(buff, SDCARD_BLOCK_SIZE)) { + break; + } + buff += SDCARD_BLOCK_SIZE; + } while (--count); + send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + } + } + release_spi(); + return count ? true: false; +} + +mp_uint_t sdcard_write_blocks(const uint8_t *buff, uint32_t sector, uint32_t count) +{ + if (Stat & STA_NOINIT) { + return false; + } + + if (!(CardType & CT_BLOCK)) { + sector *= SDCARD_BLOCK_SIZE; /* Convert to byte address if needed */ + } + + if (count == 1) { /* Single block write */ + if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ + && xmit_datablock(buff, 0xFE)) + count = 0; + } else { /* Multiple block write */ + if (CardType & CT_SDC) { + send_cmd(ACMD23, count); + } + + if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!xmit_datablock(buff, 0xFC)) break; + buff += SDCARD_BLOCK_SIZE; + } while (--count); + if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ + count = 1; + } + } + release_spi(); + return count ? true: false; +} + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +uint64_t sdcard_get_capacity_in_bytes(void) +{ + uint32_t sec; + sdcard_ioctl(0, GET_SECTOR_COUNT, &sec); + return sec * SDCARD_BLOCK_SIZE; +} + +DRESULT sdcard_ioctl ( + BYTE drv, /* Physical drive number (0) */ + BYTE ctrl, /* Control code */ + void *buff /* Buffer to send/receive control data */ + ) +{ + DRESULT res; + BYTE n, csd[16], *ptr = buff; + WORD csize; + + if (drv) return RES_PARERR; + + res = RES_ERROR; + + if (Stat & STA_NOINIT) return RES_NOTRDY; + + switch (ctrl) { + case CTRL_SYNC : /* Make sure that no pending write process */ + SD_SELECT(); + if (wait_ready() == 0xFF) + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC version 2.00 */ + csize = csd[9] + ((WORD)csd[8] << 8) + 1; + *(DWORD*)buff = (DWORD)csize << 10; + } else { /* SDC version 1.XX or MMC*/ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(DWORD*)buff = (DWORD)csize << (n - 9); + } + res = RES_OK; + } + break; + + case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */ + *(WORD*)buff = SDCARD_BLOCK_SIZE; + res = RES_OK; + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + if (CardType & CT_SD2) { /* SDC version 2.00 */ + if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ + spi_recv(); + if (rcvr_datablock(csd, 16)) { /* Read partial block */ + for (n = 64 - 16; n; n--) spi_recv(); /* Purge trailing data */ + *(DWORD*)buff = 16UL << (csd[10] >> 4); + res = RES_OK; + } + } + } else { /* SDC version 1.XX or MMC */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ + if (CardType & CT_SD1) { /* SDC version 1.XX */ + *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); + } else { /* MMC */ + *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); + } + res = RES_OK; + } + } + break; + + case MMC_GET_TYPE : /* Get card type flags (1 byte) */ + *ptr = CardType; + res = RES_OK; + break; + + case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ + if (send_cmd(CMD9, 0) == 0 /* READ_CSD */ + && rcvr_datablock(ptr, 16)) + res = RES_OK; + break; + + case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ + if (send_cmd(CMD10, 0) == 0 /* READ_CID */ + && rcvr_datablock(ptr, 16)) + res = RES_OK; + break; + + case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ + if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ + for (n = 4; n; n--) *ptr++ = spi_recv(); + res = RES_OK; + } + break; + + case MMC_GET_SDSTAT : /* Receive SD status as a data block (64 bytes) */ + if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ + spi_recv(); + if (rcvr_datablock(ptr, 64)) + res = RES_OK; + } + break; + + default: + res = RES_PARERR; + } + + release_spi(); + + return res; +} diff --git a/src/openmv/src/omv/sdram.c b/src/openmv/src/omv/sdram.c new file mode 100755 index 0000000..181a34c --- /dev/null +++ b/src/openmv/src/omv/sdram.c @@ -0,0 +1,183 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SDRAM Driver. + * + */ +#include +#include +#include +#include "mdefs.h" +#include "pincfg.h" +#include "systick.h" +#include "sdram.h" + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) +#define REFRESH_COUNT ((uint32_t)0x0569) /* SDRAM refresh counter (90Mhz SD clock) */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +static SDRAM_HandleTypeDef hsdram; +static FMC_SDRAM_TimingTypeDef SDRAM_Timing; +static FMC_SDRAM_CommandTypeDef command; +static void sdram_init_seq(SDRAM_HandleTypeDef + *hsdram, FMC_SDRAM_CommandTypeDef *command); +extern void __fatal_error(const char *msg); + +bool sdram_init() +{ + /* SDRAM device configuration */ + hsdram.Instance = FMC_SDRAM_DEVICE; + /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ + /* TMRD: 2 Clock cycles */ + SDRAM_Timing.LoadToActiveDelay = 2; + /* TXSR: min=70ns (6x11.90ns) */ + SDRAM_Timing.ExitSelfRefreshDelay = 7; + /* TRAS: min=45ns (4x11.90ns) max=120k (ns) */ + SDRAM_Timing.SelfRefreshTime = 7; + /* TRC: min=67ns (6x11.90ns) */ + SDRAM_Timing.RowCycleDelay = 10; + /* TWR: 2 Clock cycles */ + SDRAM_Timing.WriteRecoveryTime = 2; + /* TRP: 20ns => 2x11.90ns */ + SDRAM_Timing.RPDelay = 3; + /* TRCD: 20ns => 2x11.90ns */ + SDRAM_Timing.RCDDelay = 3; + + hsdram.Init.SDBank = FMC_SDRAM_BANK1; + hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_10; + hsdram.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_8; + hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + hsdram.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_3; + hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; + hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1; + + /* Initialize the SDRAM controller */ + if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { + return false; + } + + sdram_init_seq(&hsdram, &command); + return true; +} + +static void sdram_init_seq(SDRAM_HandleTypeDef + *hsdram, FMC_SDRAM_CommandTypeDef *command) +{ + /* Program the SDRAM external device */ + __IO uint32_t tmpmrd =0; + + /* Step 3: Configure a clock configuration enable command */ + command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 4: Insert 100 ms delay */ + HAL_Delay(100); + + /* Step 5: Configure a PALL (precharge all) command */ + command->CommandMode = FMC_SDRAM_CMD_PALL; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 6 : Configure a Auto-Refresh command */ + command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + command->AutoRefreshNumber = 4; + command->ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 7: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + SDRAM_MODEREG_CAS_LATENCY_3 | + SDRAM_MODEREG_OPERATING_MODE_STANDARD | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + command->AutoRefreshNumber = 1; + command->ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(hsdram, command, 0x1000); + + /* Step 8: Set the refresh rate counter */ + /* (15.62 us x Freq) - 20 */ + /* Set the device refresh counter */ + HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); +} + + +bool DISABLE_OPT sdram_test() +{ + uint8_t pattern = 0xAA; + uint8_t antipattern = 0x55; + uint32_t mem_size = (16*1024*1024); + uint8_t * const mem_base = (uint8_t*)0xC0000000; + + printf("sdram test...\n"); + /* test data bus */ + for (uint8_t i=1; i; i<<=1) { + *mem_base = i; + if (*mem_base != i) { + printf("data bus lines test failed! data (%d)\n", i); + BREAK(); + } + } + + /* test address bus */ + /* Check individual address lines */ + for (uint32_t i=1; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * SDRAM Driver. + * + */ +#ifndef __SDRAM_H__ +#define __SDRAM_H__ +bool sdram_init(); +bool sdram_test(); +#endif // __SDRAM_H__ diff --git a/src/openmv/src/omv/sensor.c b/src/openmv/src/omv/sensor.c new file mode 100755 index 0000000..da4ce62 --- /dev/null +++ b/src/openmv/src/omv/sensor.c @@ -0,0 +1,977 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Sensor abstraction layer. + * + */ +#if 0 +#include +#include +#include "mp.h" +#include "irq.h" +#include "cambus.h" +#include "ov9650.h" +#include "ov2640.h" +#include "ov7725.h" +#include "sensor.h" +#include "framebuffer.h" +#include "omv_boardconfig.h" + +#define OV_CHIP_ID (0x0A) +#define ON_CHIP_ID (0x00) +#define MAX_XFER_SIZE (0xFFFC*4) + +sensor_t sensor = {0}; +TIM_HandleTypeDef TIMHandle = {0}; +DMA_HandleTypeDef DMAHandle = {0}; +DCMI_HandleTypeDef DCMIHandle = {0}; + +static volatile int line = 0; +uint8_t _line_buf; +static uint8_t *dest_fb = NULL; + +const int resolution[][2] = { + {0, 0 }, + // C/SIF Resolutions + {88, 72 }, /* QQCIF */ + {176, 144 }, /* QCIF */ + {352, 288 }, /* CIF */ + {88, 60 }, /* QQSIF */ + {176, 120 }, /* QSIF */ + {352, 240 }, /* SIF */ + // VGA Resolutions + {40, 30 }, /* QQQQVGA */ + {80, 60 }, /* QQQVGA */ + {160, 120 }, /* QQVGA */ + {320, 240 }, /* QVGA */ + {640, 480 }, /* VGA */ + {60, 40 }, /* HQQQVGA */ + {120, 80 }, /* HQQVGA */ + {240, 160 }, /* HQVGA */ + // FFT Resolutions + {64, 32 }, /* 64x32 */ + {64, 64 }, /* 64x64 */ + {128, 64 }, /* 128x64 */ + {128, 128 }, /* 128x64 */ + // Other + {128, 160 }, /* LCD */ + {128, 160 }, /* QQVGA2 */ + {720, 480 }, /* WVGA */ + {752, 480 }, /* WVGA2 */ + {800, 600 }, /* SVGA */ + {1280, 1024}, /* SXGA */ + {1600, 1200}, /* UXGA */ +}; + +#if (OMV_XCLK_SOURCE == OMV_XCLK_TIM) +static int extclk_config(int frequency) +{ + /* TCLK (PCLK * 2) */ + int tclk = DCMI_TIM_PCLK_FREQ() * 2; + + /* Period should be even */ + int period = (tclk / frequency) - 1; + + if (TIMHandle.Init.Period && (TIMHandle.Init.Period != period)) { + // __HAL_TIM_SET_AUTORELOAD sets TIMHandle.Init.Period... + __HAL_TIM_SET_AUTORELOAD(&TIMHandle, period); + __HAL_TIM_SET_COMPARE(&TIMHandle, DCMI_TIM_CHANNEL, period / 2); + return 0; + } + + /* Timer base configuration */ + TIMHandle.Instance = DCMI_TIM; + TIMHandle.Init.Period = period; + TIMHandle.Init.Prescaler = TIM_ETRPRESCALER_DIV1; + TIMHandle.Init.CounterMode = TIM_COUNTERMODE_UP; + TIMHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + + /* Timer channel configuration */ + TIM_OC_InitTypeDef TIMOCHandle; + TIMOCHandle.Pulse = period / 2; + TIMOCHandle.OCMode = TIM_OCMODE_PWM1; + TIMOCHandle.OCPolarity = TIM_OCPOLARITY_HIGH; + TIMOCHandle.OCFastMode = TIM_OCFAST_DISABLE; + TIMOCHandle.OCIdleState = TIM_OCIDLESTATE_RESET; + + if ((HAL_TIM_PWM_Init(&TIMHandle) != HAL_OK) + || (HAL_TIM_PWM_ConfigChannel(&TIMHandle, &TIMOCHandle, DCMI_TIM_CHANNEL) != HAL_OK) + || (HAL_TIM_PWM_Start(&TIMHandle, DCMI_TIM_CHANNEL) != HAL_OK)) { + return -1; + } + + return 0; +} +#endif // (OMV_XCLK_SOURCE == OMV_XCLK_TIM) + +static int dcmi_config(uint32_t jpeg_mode) +{ + // DCMI configuration + DCMIHandle.Instance = DCMI; + // VSYNC clock polarity + DCMIHandle.Init.VSPolarity = SENSOR_HW_FLAGS_GET(&sensor, SENSOR_HW_FLAGS_VSYNC) ? + DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW; + // HSYNC clock polarity + DCMIHandle.Init.HSPolarity = SENSOR_HW_FLAGS_GET(&sensor, SENSOR_HW_FLAGS_HSYNC) ? + DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW; + // PXCLK clock polarity + DCMIHandle.Init.PCKPolarity = SENSOR_HW_FLAGS_GET(&sensor, SENSOR_HW_FLAGS_PIXCK) ? + DCMI_PCKPOLARITY_RISING : DCMI_PCKPOLARITY_FALLING; + + DCMIHandle.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; // Enable Hardware synchronization + DCMIHandle.Init.CaptureRate = DCMI_CR_ALL_FRAME; // Capture rate all frames + DCMIHandle.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; // Capture 8 bits on every pixel clock + DCMIHandle.Init.JPEGMode = jpeg_mode; // Set JPEG Mode + #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_H7) + DCMIHandle.Init.ByteSelectMode = DCMI_BSM_ALL; // Capture all received bytes + DCMIHandle.Init.ByteSelectStart = DCMI_OEBS_ODD; // Ignored + DCMIHandle.Init.LineSelectMode = DCMI_LSM_ALL; // Capture all received lines + DCMIHandle.Init.LineSelectStart = DCMI_OELS_ODD; // Ignored + #endif + + // Associate the DMA handle to the DCMI handle + __HAL_LINKDMA(&DCMIHandle, DMA_Handle, DMAHandle); + + // Initialize the DCMI + HAL_DCMI_DeInit(&DCMIHandle); + if (HAL_DCMI_Init(&DCMIHandle) != HAL_OK) { + // Initialization Error + return -1; + } + + // Configure and enable DCMI IRQ Channel + NVIC_SetPriority(DCMI_IRQn, IRQ_PRI_DCMI); + HAL_NVIC_EnableIRQ(DCMI_IRQn); + return 0; +} + +static int dma_config() +{ + // DMA Stream configuration + DMAHandle.Instance = DMA2_Stream1; /* Select the DMA instance */ + #if defined(MCU_SERIES_H7) + DMAHandle.Init.Request = DMA_REQUEST_DCMI; /* DMA Channel */ + #else + DMAHandle.Init.Channel = DMA_CHANNEL_1; /* DMA Channel */ + #endif + DMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; /* Peripheral to memory transfer */ + DMAHandle.Init.MemInc = DMA_MINC_ENABLE; /* Memory increment mode Enable */ + DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; /* Peripheral increment mode Enable */ + DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */ + DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; /* Memory data alignment : Word */ + DMAHandle.Init.Mode = DMA_NORMAL; /* Normal DMA mode */ + DMAHandle.Init.Priority = DMA_PRIORITY_HIGH; /* Priority level : high */ + DMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* FIFO mode enabled */ + DMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; /* FIFO threshold full */ + DMAHandle.Init.MemBurst = DMA_MBURST_INC4; /* Memory burst */ + DMAHandle.Init.PeriphBurst = DMA_PBURST_SINGLE; /* Peripheral burst */ + + // Configure and disable DMA IRQ Channel + NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21); + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + // Initialize the DMA stream + HAL_DMA_DeInit(&DMAHandle); + if (HAL_DMA_Init(&DMAHandle) != HAL_OK) { + // Initialization Error + return -1; + } + + return 0; +} + +void sensor_init0() +{ + // Init FB mutex + mutex_init(&JPEG_FB()->lock); + + // Save fb_enabled flag state + int fb_enabled = JPEG_FB()->enabled; + + // Clear framebuffers + memset(MAIN_FB(), 0, sizeof(*MAIN_FB())); + memset(JPEG_FB(), 0, sizeof(*JPEG_FB())); + + // Set default quality + JPEG_FB()->quality = 35; + + // Set fb_enabled + JPEG_FB()->enabled = fb_enabled; +} + +int sensor_init() +{ + int init_ret = 0; + + /* Do a power cycle */ + DCMI_PWDN_HIGH(); + systick_sleep(10); + + DCMI_PWDN_LOW(); + systick_sleep(10); + + // Initialize the camera bus. + cambus_init(); + systick_sleep(10); + + // Configure the sensor external clock (XCLK) to XCLK_FREQ. + // + // Max pixclk is 2.5 * HCLK: + // STM32F427@180MHz PCLK = 71.9999MHz + // STM32F769@216MHz PCLK = 86.4000MHz + // + // OV2640: + // The sensor's internal PLL (when CLKRC=0x80) doubles the XCLK_FREQ + // (XCLK=XCLK_FREQ*2), and the unscaled PIXCLK output is XCLK_FREQ*4 + // + // OV7725 PCLK when prescalar is enabled (CLKRC[6]=0): + // Internal clock = Input clock × PLL multiplier / [(CLKRC[5:0] + 1) × 2] + // + // OV7725 PCLK when prescalar is disabled (CLKRC[6]=1): + // Internal clock = Input clock × PLL multiplier + // + #if (OMV_XCLK_SOURCE == OMV_XCLK_TIM) + // Configure external clock timer. + if (extclk_config(OMV_XCLK_FREQUENCY) != 0) { + // Timer problem + return -1; + } + #elif (OMV_XCLK_SOURCE == OMV_XCLK_MCO) + // Pass through the MCO1 clock with source input set to HSE (12MHz). + // Note MCO1 is multiplexed on OPENMV2/TIM1 only. + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1); + #else + #error "OMV_XCLK_SOURCE is not set!" + #endif + + /* Reset the sesnor state */ + memset(&sensor, 0, sizeof(sensor_t)); + + /* Some sensors have different reset polarities, and we can't know which sensor + is connected before initializing cambus and probing the sensor, which in turn + requires pulling the sensor out of the reset state. So we try to probe the + sensor with both polarities to determine line state. */ + sensor.pwdn_pol = ACTIVE_HIGH; + sensor.reset_pol = ACTIVE_HIGH; + + /* Reset the sensor */ + DCMI_RESET_HIGH(); + systick_sleep(10); + + DCMI_RESET_LOW(); + systick_sleep(10); + + /* Probe the sensor */ + sensor.slv_addr = cambus_scan(); + if (sensor.slv_addr == 0) { + /* Sensor has been held in reset, + so the reset line is active low */ + sensor.reset_pol = ACTIVE_LOW; + + /* Pull the sensor out of the reset state */ + DCMI_RESET_HIGH(); + systick_sleep(10); + + /* Probe again to set the slave addr */ + sensor.slv_addr = cambus_scan(); + if (sensor.slv_addr == 0) { + sensor.pwdn_pol = ACTIVE_LOW; + + DCMI_PWDN_HIGH(); + systick_sleep(10); + + sensor.slv_addr = cambus_scan(); + if (sensor.slv_addr == 0) { + sensor.reset_pol = ACTIVE_HIGH; + + DCMI_RESET_LOW(); + systick_sleep(10); + + sensor.slv_addr = cambus_scan(); + if (sensor.slv_addr == 0) { + return -2; + } + } + } + } + + // Clear sensor chip ID. + sensor.chip_id = 0; + + // Set default snapshot function. + sensor.snapshot = sensor_snapshot; + + if (sensor.slv_addr == LEPTON_ID) { + sensor.chip_id = LEPTON_ID; + if (extclk_config(LEPTON_XCLK_FREQ) != 0) { + return -3; + } + init_ret = lepton_init(&sensor); + } else { + // Read ON semi sensor ID. + cambus_readb(sensor.slv_addr, ON_CHIP_ID, &sensor.chip_id); + if (sensor.chip_id == MT9V034_ID) { + if (extclk_config(MT9V034_XCLK_FREQ) != 0) { + return -3; + } + init_ret = mt9v034_init(&sensor); + } else { // Read OV sensor ID. + cambus_readb(sensor.slv_addr, OV_CHIP_ID, &sensor.chip_id); + // Initialize sensor struct. + switch (sensor.chip_id) { + case OV9650_ID: + init_ret = ov9650_init(&sensor); + break; + case OV2640_ID: + init_ret = ov2640_init(&sensor); + break; + case OV7725_ID: + init_ret = ov7725_init(&sensor); + break; + default: + // Sensor is not supported. + return -3; + } + } + } + + if (init_ret != 0 ) { + // Sensor init failed. + return -4; + } + + /* Configure the DCMI DMA Stream */ + if (dma_config() != 0) { + // DMA problem + return -5; + } + + /* Configure the DCMI interface. This should be called + after ovxxx_init to set VSYNC/HSYNC/PCLK polarities */ + if (dcmi_config(DCMI_JPEG_DISABLE) != 0){ + // DCMI config failed + return -6; + } + + // Disable VSYNC EXTI IRQ + HAL_NVIC_DisableIRQ(DCMI_VSYNC_IRQN); + + // Clear fb_enabled flag + // This is executed only once to initialize the FB enabled flag. + JPEG_FB()->enabled = 0; + + /* All good! */ + return 0; +} + +int sensor_reset() +{ + // Reset the sesnor state + sensor.sde = 0; + sensor.pixformat = 0; + sensor.framesize = 0; + sensor.framerate = 0; + sensor.gainceiling = 0; + sensor.vsync_gpio = NULL; + + // Call sensor-specific reset function + if (sensor.reset(&sensor) != 0) { + return -1; + } + + // Just in case there's a running DMA request. + HAL_DMA_Abort(&DMAHandle); + + // Disable VSYNC EXTI IRQ + HAL_NVIC_DisableIRQ(DCMI_VSYNC_IRQN); + return 0; +} + +int sensor_get_id() +{ + return sensor.chip_id; +} + +int sensor_sleep(int enable) +{ + if (sensor.sleep == NULL + || sensor.sleep(&sensor, enable) != 0) { + // Operation not supported + return -1; + } + return 0; +} + +int sensor_shutdown(int enable) +{ + if (enable) { + DCMI_PWDN_HIGH(); + } else { + DCMI_PWDN_LOW(); + } + + systick_sleep(10); + return 0; +} + +int sensor_read_reg(uint8_t reg_addr) +{ + if (sensor.read_reg == NULL) { + // Operation not supported + return -1; + } + return sensor.read_reg(&sensor, reg_addr); +} + +int sensor_write_reg(uint8_t reg_addr, uint16_t reg_data) +{ + if (sensor.write_reg == NULL) { + // Operation not supported + return -1; + } + return sensor.write_reg(&sensor, reg_addr, reg_data); +} + +int sensor_set_pixformat(pixformat_t pixformat) +{ + uint32_t jpeg_mode = DCMI_JPEG_DISABLE; + + if (sensor.pixformat == pixformat) { + // No change + return 0; + } + + if (sensor.set_pixformat == NULL + || sensor.set_pixformat(&sensor, pixformat) != 0) { + // Operation not supported + return -1; + } + + // Set pixel format + sensor.pixformat = pixformat; + + // Set JPEG mode + if (pixformat == PIXFORMAT_JPEG) { + jpeg_mode = DCMI_JPEG_ENABLE; + } + + // Skip the first frame. + MAIN_FB()->bpp = -1; + + return dcmi_config(jpeg_mode); +} + +int sensor_set_framesize(framesize_t framesize) +{ + if (sensor.framesize == framesize) { + // No change + return 0; + } + + // Call the sensor specific function + if (sensor.set_framesize == NULL + || sensor.set_framesize(&sensor, framesize) != 0) { + // Operation not supported + return -1; + } + + // Set framebuffer size + sensor.framesize = framesize; + + // Skip the first frame. + MAIN_FB()->bpp = -1; + + // Set MAIN FB x, y offset. + MAIN_FB()->x = 0; + MAIN_FB()->y = 0; + + // Set MAIN FB width and height. + MAIN_FB()->w = resolution[framesize][0]; + MAIN_FB()->h = resolution[framesize][1]; + + // Set MAIN FB backup width and height. + MAIN_FB()->u = resolution[framesize][0]; + MAIN_FB()->v = resolution[framesize][1]; + return 0; +} + +int sensor_set_framerate(framerate_t framerate) +{ + if (sensor.framerate == framerate) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_framerate == NULL + || sensor.set_framerate(&sensor, framerate) != 0) { + /* operation not supported */ + return -1; + } + + /* set the frame rate */ + sensor.framerate = framerate; + + return 0; +} + +int sensor_set_windowing(int x, int y, int w, int h) +{ + MAIN_FB()->x = x; + MAIN_FB()->y = y; + MAIN_FB()->w = MAIN_FB()->u = w; + MAIN_FB()->h = MAIN_FB()->v = h; + return 0; +} + +int sensor_set_contrast(int level) +{ + if (sensor.set_contrast != NULL) { + return sensor.set_contrast(&sensor, level); + } + return -1; +} + +int sensor_set_brightness(int level) +{ + if (sensor.set_brightness != NULL) { + return sensor.set_brightness(&sensor, level); + } + return -1; +} + +int sensor_set_saturation(int level) +{ + if (sensor.set_saturation != NULL) { + return sensor.set_saturation(&sensor, level); + } + return -1; +} + +int sensor_set_gainceiling(gainceiling_t gainceiling) +{ + if (sensor.gainceiling == gainceiling) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_gainceiling == NULL + || sensor.set_gainceiling(&sensor, gainceiling) != 0) { + /* operation not supported */ + return -1; + } + + sensor.gainceiling = gainceiling; + return 0; +} + +int sensor_set_quality(int qs) +{ + /* call the sensor specific function */ + if (sensor.set_quality == NULL + || sensor.set_quality(&sensor, qs) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_colorbar(int enable) +{ + /* call the sensor specific function */ + if (sensor.set_colorbar == NULL + || sensor.set_colorbar(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_gain(int enable, float gain_db, float gain_db_ceiling) +{ + /* call the sensor specific function */ + if (sensor.set_auto_gain == NULL + || sensor.set_auto_gain(&sensor, enable, gain_db, gain_db_ceiling) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_gain_db(float *gain_db) +{ + /* call the sensor specific function */ + if (sensor.get_gain_db == NULL + || sensor.get_gain_db(&sensor, gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_exposure(int enable, int exposure_us) +{ + /* call the sensor specific function */ + if (sensor.set_auto_exposure == NULL + || sensor.set_auto_exposure(&sensor, enable, exposure_us) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_exposure_us(int *exposure_us) +{ + /* call the sensor specific function */ + if (sensor.get_exposure_us == NULL + || sensor.get_exposure_us(&sensor, exposure_us) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + /* call the sensor specific function */ + if (sensor.set_auto_whitebal == NULL + || sensor.set_auto_whitebal(&sensor, enable, r_gain_db, g_gain_db, b_gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + /* call the sensor specific function */ + if (sensor.get_rgb_gain_db == NULL + || sensor.get_rgb_gain_db(&sensor, r_gain_db, g_gain_db, b_gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_hmirror(int enable) +{ + /* call the sensor specific function */ + if (sensor.set_hmirror == NULL + || sensor.set_hmirror(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_vflip(int enable) +{ + /* call the sensor specific function */ + if (sensor.set_vflip == NULL + || sensor.set_vflip(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_special_effect(sde_t sde) +{ + if (sensor.sde == sde) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_special_effect == NULL + || sensor.set_special_effect(&sensor, sde) != 0) { + /* operation not supported */ + return -1; + } + + sensor.sde = sde; + return 0; +} + +int sensor_set_lens_correction(int enable, int radi, int coef) +{ + /* call the sensor specific function */ + if (sensor.set_lens_correction == NULL + || sensor.set_lens_correction(&sensor, enable, radi, coef) != 0) { + /* operation not supported */ + return -1; + } + + return 0; +} + +int sensor_set_vsync_output(GPIO_TypeDef *gpio, uint32_t pin) +{ + sensor.vsync_pin = pin; + sensor.vsync_gpio = gpio; + // Enable VSYNC EXTI IRQ + NVIC_SetPriority(DCMI_VSYNC_IRQN, IRQ_PRI_EXTINT); + HAL_NVIC_EnableIRQ(DCMI_VSYNC_IRQN); + return 0; +} + +void DCMI_VsyncExtiCallback() +{ + __HAL_GPIO_EXTI_CLEAR_FLAG(1 << DCMI_VSYNC_IRQ_LINE); + if (sensor.vsync_gpio != NULL) { + HAL_GPIO_WritePin(sensor.vsync_gpio, sensor.vsync_pin, + !HAL_GPIO_ReadPin(DCMI_VSYNC_PORT, DCMI_VSYNC_PIN)); + } +} + +static void sensor_check_buffsize() +{ + int bpp=0; + switch (sensor.pixformat) { + case PIXFORMAT_BAYER: + case PIXFORMAT_GRAYSCALE: + bpp = 1; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + bpp = 2; + break; + default: + break; + } + + if ((MAIN_FB()->w * MAIN_FB()->h * bpp) > OMV_RAW_BUF_SIZE) { + if (sensor.pixformat == PIXFORMAT_GRAYSCALE) { + // Crop higher GS resolutions to QVGA + sensor_set_windowing(190, 120, 320, 240); + } else if (sensor.pixformat == PIXFORMAT_RGB565) { + // Switch to BAYER if the frame is too big to fit in RAM. + sensor_set_pixformat(PIXFORMAT_BAYER); + } + } + +} + +// This function is called back after each line transfer is complete, +// with a pointer to the line buffer that was used. At this point the +// DMA transfers the next line to the other half of the line buffer. +// Note: For JPEG this function is called once (and ignored) at the end of the transfer. +void DCMI_DMAConvCpltUser(uint32_t addr) +{ + uint8_t *src = (uint8_t*) addr; + uint8_t *dst = dest_fb; + + uint16_t *src16 = (uint16_t*) addr; + uint16_t *dst16 = (uint16_t*) dest_fb; + + // Skip lines outside the window. + if (line >= MAIN_FB()->y && line <= (MAIN_FB()->y + MAIN_FB()->h)) { + switch (sensor.pixformat) { + case PIXFORMAT_BAYER: + dst += (line - MAIN_FB()->y) * MAIN_FB()->w; + for (int i=0; iw; i++) { + dst[i] = src[MAIN_FB()->x + i]; + } + break; + case PIXFORMAT_GRAYSCALE: + dst += (line - MAIN_FB()->y) * MAIN_FB()->w; + if (sensor.gs_bpp == 1) { + // 1BPP GRAYSCALE. + for (int i=0; iw; i++) { + dst[i] = src[MAIN_FB()->x + i]; + } + } else { + // Extract Y channel from YUV. + for (int i=0; iw; i++) { + dst[i] = src[MAIN_FB()->x * 2 + i * 2]; + } + } + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + dst16 += (line - MAIN_FB()->y) * MAIN_FB()->w; + for (int i=0; iw; i++) { + dst16[i] = src16[MAIN_FB()->x + i]; + } + break; + case PIXFORMAT_JPEG: + break; + default: + break; + } + } + + line++; +} + +// This is the default snapshot function, which can be replaced in sensor_init functions. This function +// uses the DCMI and DMA to capture frames and each line is processed in the DCMI_DMAConvCpltUser function. +int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_cb) +{ + uint32_t frame = 0; + bool streaming = (streaming_cb != NULL); // Streaming mode. + bool doublebuf = false; // Use double buffers in streaming mode. + uint32_t addr, length, tick_start; + + // Compress the framebuffer for the IDE preview, only if it's not the first frame, + // the framebuffer is enabled and the image sensor does not support JPEG encoding. + // Note: This doesn't run unless the IDE is connected and the framebuffer is enabled. + fb_update_jpeg_buffer(); + + // Make sure the raw frame fits into the FB. If it doesn't it will be cropped if + // the format is set to GS, otherwise the pixel format will be swicthed to BAYER. + sensor_check_buffsize(); + + // Set the current frame buffer target used in the DMA line callback + // (DCMI_DMAConvCpltUser function), in both snapshot and streaming modes. + dest_fb = MAIN_FB()->pixels; + + // The user may have changed the MAIN_FB width or height on the last image so we need + // to restore that here. We don't have to restore bpp because that's taken care of + // already in the code below. Note that we do the JPEG compression above first to save + // the FB of whatever the user set it to and now we restore. + MAIN_FB()->w = MAIN_FB()->u; + MAIN_FB()->h = MAIN_FB()->v; + + // We use the stored frame size to read the whole frame. Note that cropping is + // done in the line function using the diemensions stored in MAIN_FB()->x,y,w,h. + uint32_t w = resolution[sensor->framesize][0]; + uint32_t h = resolution[sensor->framesize][1]; + + // Setup the size and address of the transfer + switch (sensor->pixformat) { + case PIXFORMAT_RGB565: + case PIXFORMAT_YUV422: + // RGB/YUV read 2 bytes per pixel. + length = (w * h * 2); + addr = (uint32_t) &_line_buf; + break; + case PIXFORMAT_BAYER: + // BAYER/RAW: 1 byte per pixel + length = (w * h * 1); + addr = (uint32_t) &_line_buf; + break; + case PIXFORMAT_GRAYSCALE: + // 1/2BPP Grayscale. + length = (w * h * sensor->gs_bpp); + addr = (uint32_t) &_line_buf; + break; + case PIXFORMAT_JPEG: + // Sensor has hardware JPEG set max frame size. + length = MAX_XFER_SIZE; + addr = (uint32_t) (MAIN_FB()->pixels); + break; + default: + return -1; + } + + if (streaming_cb) { + image->pixels = NULL; + } + + // If two frames fit in ram, use double buffering in streaming mode. + doublebuf = ((length*2) <= OMV_RAW_BUF_SIZE); + + do { + // Clear line counter + line = 0; + + // Snapshot start tick + tick_start = HAL_GetTick(); + + // Enable DMA IRQ + HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); + + if (sensor->pixformat == PIXFORMAT_JPEG) { + // Start a regular transfer + HAL_DCMI_Start_DMA(&DCMIHandle, + DCMI_MODE_SNAPSHOT, addr, length/4); + } else { + // Start a multibuffer transfer (line by line) + HAL_DCMI_Start_DMA_MB(&DCMIHandle, + DCMI_MODE_SNAPSHOT, addr, length/4, h); + } + + if (streaming_cb && doublebuf && image->pixels != NULL) { + // Call streaming callback function with previous frame. + // Note: Image pointer should Not be NULL in streaming mode. + streaming = streaming_cb(image); + } + + // Wait for frame + while ((DCMI->CR & DCMI_CR_CAPTURE) != 0) { + // Wait for interrupt + __WFI(); + + if ((HAL_GetTick() - tick_start) >= 3000) { + // Sensor timeout, most likely a HW issue. + // Abort the DMA request. + HAL_DMA_Abort(&DMAHandle); + return -1; + } + } + + // Abort DMA transfer. + // Note: In JPEG mode the DMA will still be waiting for data since + // the max frame size is set, so we need to abort the DMA transfer. + HAL_DMA_Abort(&DMAHandle); + + // Disable DMA IRQ + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + // Fix the BPP + switch (sensor->pixformat) { + case PIXFORMAT_GRAYSCALE: + MAIN_FB()->bpp = 1; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + MAIN_FB()->bpp = 2; + break; + case PIXFORMAT_BAYER: + MAIN_FB()->bpp = 3; + break; + case PIXFORMAT_JPEG: + // Read the number of data items transferred + MAIN_FB()->bpp = (MAX_XFER_SIZE - __HAL_DMA_GET_COUNTER(&DMAHandle))*4; + break; + default: + break; + } + + // Set the user image. + if (image != NULL) { + image->w = MAIN_FB()->w; + image->h = MAIN_FB()->h; + image->bpp = MAIN_FB()->bpp; + image->pixels = MAIN_FB()->pixels; + + if (streaming_cb) { + // In streaming mode, either switch frame buffers in double buffer mode, + // or call the streaming callback with the main FB in single buffer mode. + if (doublebuf == false) { + // In single buffer mode, call streaming callback. + streaming = streaming_cb(image); + } else { + // In double buffer mode, switch frame buffers. + if (frame == 0) { + image->pixels = MAIN_FB()->pixels; + // Next frame will be transfered to the second half. + dest_fb = MAIN_FB()->pixels + length; + } else { + image->pixels = MAIN_FB()->pixels + length; + // Next frame will be transfered to the first half. + dest_fb = MAIN_FB()->pixels; + } + frame ^= 1; // Switch frame buffers. + } + } + } + } while (streaming == true); + + return 0; +} +#endif diff --git a/src/openmv/src/omv/sensor.h b/src/openmv/src/omv/sensor.h new file mode 100755 index 0000000..1ef8ea5 --- /dev/null +++ b/src/openmv/src/omv/sensor.h @@ -0,0 +1,250 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Sensor abstraction layer. + * + */ +#if 0 +#ifndef __SENSOR_H__ +#define __SENSOR_H__ +#include +#include "imlib.h" + +#define OV9650_ID (0x96) +#define OV2640_ID (0x26) +#define OV7725_ID (0x77) +#define MT9V034_ID (0x13) +#define LEPTON_ID (0x54) + +typedef enum { + PIXFORMAT_INVLAID = 0, + PIXFORMAT_BAYER, // 1BPP/RAW + PIXFORMAT_RGB565, // 2BPP/RGB565 + PIXFORMAT_YUV422, // 2BPP/YUV422 + PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE + PIXFORMAT_JPEG, // JPEG/COMPRESSED +} pixformat_t; + +typedef enum { + FRAMESIZE_INVALID = 0, + // C/SIF Resolutions + FRAMESIZE_QQCIF, // 88x72 + FRAMESIZE_QCIF, // 176x144 + FRAMESIZE_CIF, // 352x288 + FRAMESIZE_QQSIF, // 88x60 + FRAMESIZE_QSIF, // 176x120 + FRAMESIZE_SIF, // 352x240 + // VGA Resolutions + FRAMESIZE_QQQQVGA, // 40x30 + FRAMESIZE_QQQVGA, // 80x60 + FRAMESIZE_QQVGA, // 160x120 + FRAMESIZE_QVGA, // 320x240 + FRAMESIZE_VGA, // 640x480 + FRAMESIZE_HQQQVGA, // 60x40 + FRAMESIZE_HQQVGA, // 120x80 + FRAMESIZE_HQVGA, // 240x160 + // FFT Resolutions + FRAMESIZE_64X32, // 64x32 + FRAMESIZE_64X64, // 64x64 + FRAMESIZE_128X64, // 128x64 + FRAMESIZE_128X128, // 128x128 + // Other + FRAMESIZE_LCD, // 128x160 + FRAMESIZE_QQVGA2, // 128x160 + FRAMESIZE_WVGA, // 720x480 + FRAMESIZE_WVGA2, // 752x480 + FRAMESIZE_SVGA, // 800x600 + FRAMESIZE_SXGA, // 1280x1024 + FRAMESIZE_UXGA, // 1600x1200 +} framesize_t; + +typedef enum { + FRAMERATE_2FPS =0x9F, + FRAMERATE_8FPS =0x87, + FRAMERATE_15FPS=0x83, + FRAMERATE_30FPS=0x81, + FRAMERATE_60FPS=0x80, +} framerate_t; + +typedef enum { + GAINCEILING_2X, + GAINCEILING_4X, + GAINCEILING_8X, + GAINCEILING_16X, + GAINCEILING_32X, + GAINCEILING_64X, + GAINCEILING_128X, +} gainceiling_t; + +typedef enum { + SDE_NORMAL, + SDE_NEGATIVE, +} sde_t; + +typedef enum { + ATTR_CONTRAST=0, + ATTR_BRIGHTNESS, + ATTR_SATURATION, + ATTR_GAINCEILING, +} sensor_attr_t; + +typedef enum { + ACTIVE_LOW, + ACTIVE_HIGH +} polarity_t; + +#define SENSOR_HW_FLAGS_VSYNC (0) // vertical sync polarity. +#define SENSOR_HW_FLAGS_HSYNC (1) // horizontal sync polarity. +#define SENSOR_HW_FLAGS_PIXCK (2) // pixel clock edge. +#define SENSOR_HW_FLAGS_FSYNC (3) // hardware frame sync. +#define SENSOR_HW_FLAGS_JPEGE (4) // hardware JPEG encoder. +#define SENSOR_HW_FLAGS_GET(s, x) ((s)->hw_flags & (1<hw_flags |= (v<hw_flags &= ~(1< + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Software I2C implementation. + * + */ +#include +#include "soft_i2c.h" +#include "omv_boardconfig.h" + +#define ACK 0 +#define NACK 1 + +static void delay(void) +{ + for(volatile int i=0; i> (7 - i)) & 1); + delay(); + I2C_SIOC_H(); + delay(); + I2C_SIOC_L(); + delay(); + } + + I2C_SIOD_H(); + delay(); + + I2C_SIOC_H(); + delay(); + + /* Read ACK */ + i = I2C_SIOD_READ(); + delay(); + + I2C_SIOC_L(); + delay(); + + I2C_SIOD_L(); + delay(); + return i; +} + +int soft_i2c_read_bytes(uint8_t slv_addr, uint8_t *buf, int len, bool stop) +{ + int ret = 0; + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + i2c_start(); + ret |= i2c_write_byte(slv_addr | 1); + for(int i=0; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Software I2C implementation. + * + */ +#ifndef __SOFT_I2C_H__ +#define __SOFT_I2C_H__ +#include +int soft_i2c_read_bytes(uint8_t slv_addr, uint8_t *buf, int len, bool stop); +int soft_i2c_write_bytes(uint8_t slv_addr, uint8_t *buf, int len, bool stop); +void soft_i2c_init(); +void soft_i2c_deinit(); +#endif // __SOFT_I2C_H__ diff --git a/src/openmv/src/omv/trace.c b/src/openmv/src/omv/trace.c new file mode 100755 index 0000000..d0017dc --- /dev/null +++ b/src/openmv/src/omv/trace.c @@ -0,0 +1,27 @@ +#include "trace.h" +#include + +#define TRACEBUF_SIZE (256) +typedef struct _tracebuf_t { + uint8_t idx; + uint8_t buf[TRACEBUF_SIZE]; +} tracebuf_t; + +static tracebuf_t tracebuf; + +void trace_init() +{ + tracebuf.idx = 0; + for (int i=0; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Trace buffer. + * + */ +#ifndef __TRACE_H__ +#define __TRACE_H__ +#include +void trace_init(); +void trace_insert(uint32_t x); +#endif /* __TRACE_H__ */ diff --git a/src/openmv/src/omv/umm_malloc.c b/src/openmv/src/omv/umm_malloc.c new file mode 100755 index 0000000..0d6539c --- /dev/null +++ b/src/openmv/src/omv/umm_malloc.c @@ -0,0 +1,675 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#include +#include +#include "fb_alloc.h" +#include "umm_malloc.h" + +NORETURN void umm_alloc_fail() +{ + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, + "Out of temporary Frame Buffer Heap Memory!" + " Please reduce the resolution of the image you are running this algorithm on to bypass this issue!")); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "umm_malloc.c" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//The MIT License (MIT) + +//Copyright (c) 2015 Ralph Hempel + +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: + +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. + +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +/* ---------------------------------------------------------------------------- + * umm_malloc.c - a memory allocator for embedded systems (microcontrollers) + * + * See LICENSE for copyright notice + * See README.md for acknowledgements and description of internals + * ---------------------------------------------------------------------------- + * + * R.Hempel 2007-09-22 - Original + * R.Hempel 2008-12-11 - Added MIT License biolerplate + * - realloc() now looks to see if previous block is free + * - made common operations functions + * R.Hempel 2009-03-02 - Added macros to disable tasking + * - Added function to dump heap and check for valid free + * pointer + * R.Hempel 2009-03-09 - Changed name to umm_malloc to avoid conflicts with + * the mm_malloc() library functions + * - Added some test code to assimilate a free block + * with the very block if possible. Complicated and + * not worth the grief. + * D.Frank 2014-04-02 - Fixed heap configuration when UMM_TEST_MAIN is NOT set, + * added user-dependent configuration file umm_malloc_cfg.h + * R.Hempel 2016-12-04 - Add support for Unity test framework + * - Reorganize source files to avoid redundant content + * - Move integrity and poison checking to separate file + * R.Hempel 2017-12-29 - Fix bug in realloc when requesting a new block that + * results in OOM error - see Issue 11 + * ---------------------------------------------------------------------------- + */ + +/* A couple of macros to make packing structures less compiler dependent */ + +#define UMM_H_ATTPACKPRE +#define UMM_H_ATTPACKSUF __attribute__((__packed__)) + +#define UMM_BEST_FIT +#undef UMM_FIRST_FIT + +/* + * A couple of macros to make it easier to protect the memory allocator + * in a multitasking system. You should set these macros up to use whatever + * your system uses for this purpose. You can disable interrupts entirely, or + * just disable task switching - it's up to you + * + * NOTE WELL that these macros MUST be allowed to nest, because umm_free() is + * called from within umm_malloc() + */ + +#define UMM_CRITICAL_ENTRY() +#define UMM_CRITICAL_EXIT() + +#define DBGLOG_TRACE(format, ...) + +#define DBGLOG_DEBUG(format, ...) + +/* ------------------------------------------------------------------------- */ + +UMM_H_ATTPACKPRE typedef struct umm_ptr_t { + unsigned short int next; + unsigned short int prev; +} UMM_H_ATTPACKSUF umm_ptr; + + +UMM_H_ATTPACKPRE typedef struct umm_block_t { + union { + umm_ptr used; + } header; + union { + umm_ptr free; + unsigned char data[16]; + } body; +} UMM_H_ATTPACKSUF umm_block; + +#define UMM_FREELIST_MASK (0x8000) +#define UMM_BLOCKNO_MASK (0x7FFF) + +/* ------------------------------------------------------------------------- */ + +umm_block *umm_heap = NULL; +unsigned short int umm_numblocks = 0; + +#define UMM_NUMBLOCKS (umm_numblocks) + +/* ------------------------------------------------------------------------ */ + +#define UMM_BLOCK(b) (umm_heap[b]) + +#define UMM_NBLOCK(b) (UMM_BLOCK(b).header.used.next) +#define UMM_PBLOCK(b) (UMM_BLOCK(b).header.used.prev) +#define UMM_NFREE(b) (UMM_BLOCK(b).body.free.next) +#define UMM_PFREE(b) (UMM_BLOCK(b).body.free.prev) +#define UMM_DATA(b) (UMM_BLOCK(b).body.data) + +/* ------------------------------------------------------------------------ */ + +static unsigned short int umm_blocks( size_t size ) { + + /* + * The calculation of the block size is not too difficult, but there are + * a few little things that we need to be mindful of. + * + * When a block removed from the free list, the space used by the free + * pointers is available for data. That's what the first calculation + * of size is doing. + */ + + if( size <= (sizeof(((umm_block *)0)->body)) ) + return( 1 ); + + /* + * If it's for more than that, then we need to figure out the number of + * additional whole blocks the size of an umm_block are required. + */ + + size -= ( 1 + (sizeof(((umm_block *)0)->body)) ); + + return( 2 + size/(sizeof(umm_block)) ); +} + +/* ------------------------------------------------------------------------ */ +/* + * Split the block `c` into two blocks: `c` and `c + blocks`. + * + * - `new_freemask` should be `0` if `c + blocks` used, or `UMM_FREELIST_MASK` + * otherwise. + * + * Note that free pointers are NOT modified by this function. + */ +static void umm_split_block( unsigned short int c, + unsigned short int blocks, + unsigned short int new_freemask ) { + + UMM_NBLOCK(c+blocks) = (UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) | new_freemask; + UMM_PBLOCK(c+blocks) = c; + + UMM_PBLOCK(UMM_NBLOCK(c) & UMM_BLOCKNO_MASK) = (c+blocks); + UMM_NBLOCK(c) = (c+blocks); +} + +/* ------------------------------------------------------------------------ */ + +static void umm_disconnect_from_free_list( unsigned short int c ) { + /* Disconnect this block from the FREE list */ + + UMM_NFREE(UMM_PFREE(c)) = UMM_NFREE(c); + UMM_PFREE(UMM_NFREE(c)) = UMM_PFREE(c); + + /* And clear the free block indicator */ + + UMM_NBLOCK(c) &= (~UMM_FREELIST_MASK); +} + +/* ------------------------------------------------------------------------ + * The umm_assimilate_up() function assumes that UMM_NBLOCK(c) does NOT + * have the UMM_FREELIST_MASK bit set! + */ + +static void umm_assimilate_up( unsigned short int c ) { + + if( UMM_NBLOCK(UMM_NBLOCK(c)) & UMM_FREELIST_MASK ) { + /* + * The next block is a free block, so assimilate up and remove it from + * the free list + */ + + DBGLOG_DEBUG( "Assimilate up to next block, which is FREE\n" ); + + /* Disconnect the next block from the FREE list */ + + umm_disconnect_from_free_list( UMM_NBLOCK(c) ); + + /* Assimilate the next block with this one */ + + UMM_PBLOCK(UMM_NBLOCK(UMM_NBLOCK(c)) & UMM_BLOCKNO_MASK) = c; + UMM_NBLOCK(c) = UMM_NBLOCK(UMM_NBLOCK(c)) & UMM_BLOCKNO_MASK; + } +} + +/* ------------------------------------------------------------------------ + * The umm_assimilate_down() function assumes that UMM_NBLOCK(c) does NOT + * have the UMM_FREELIST_MASK bit set! + */ + +static unsigned short int umm_assimilate_down( unsigned short int c, unsigned short int freemask ) { + + UMM_NBLOCK(UMM_PBLOCK(c)) = UMM_NBLOCK(c) | freemask; + UMM_PBLOCK(UMM_NBLOCK(c)) = UMM_PBLOCK(c); + + return( UMM_PBLOCK(c) ); +} + +/* ------------------------------------------------------------------------- */ + +void umm_init_x( size_t size ) { + uint32_t UMM_MALLOC_CFG_HEAP_SIZE = (size / sizeof(size_t)) * sizeof(size_t); + if (UMM_MALLOC_CFG_HEAP_SIZE < (sizeof(umm_block) * 128)) fb_alloc_fail(); + if (UMM_MALLOC_CFG_HEAP_SIZE > (sizeof(umm_block) * 32768)) UMM_MALLOC_CFG_HEAP_SIZE = sizeof(umm_block) * 32768; + void *UMM_MALLOC_CFG_HEAP_ADDR = fb_alloc(UMM_MALLOC_CFG_HEAP_SIZE); + /* init heap pointer and size, and memset it to 0 */ + umm_heap = (umm_block *)UMM_MALLOC_CFG_HEAP_ADDR; + umm_numblocks = (UMM_MALLOC_CFG_HEAP_SIZE / sizeof(umm_block)); + memset(umm_heap, 0x00, UMM_MALLOC_CFG_HEAP_SIZE); + + /* setup initial blank heap structure */ + { + /* index of the 0th `umm_block` */ + const unsigned short int block_0th = 0; + /* index of the 1st `umm_block` */ + const unsigned short int block_1th = 1; + /* index of the latest `umm_block` */ + const unsigned short int block_last = UMM_NUMBLOCKS - 1; + + /* setup the 0th `umm_block`, which just points to the 1st */ + UMM_NBLOCK(block_0th) = block_1th; + UMM_NFREE(block_0th) = block_1th; + UMM_PFREE(block_0th) = block_1th; + + /* + * Now, we need to set the whole heap space as a huge free block. We should + * not touch the 0th `umm_block`, since it's special: the 0th `umm_block` + * is the head of the free block list. It's a part of the heap invariant. + * + * See the detailed explanation at the beginning of the file. + */ + + /* + * 1th `umm_block` has pointers: + * + * - next `umm_block`: the latest one + * - prev `umm_block`: the 0th + * + * Plus, it's a free `umm_block`, so we need to apply `UMM_FREELIST_MASK` + * + * And it's the last free block, so the next free block is 0. + */ + UMM_NBLOCK(block_1th) = block_last | UMM_FREELIST_MASK; + UMM_NFREE(block_1th) = 0; + UMM_PBLOCK(block_1th) = block_0th; + UMM_PFREE(block_1th) = block_0th; + + /* + * latest `umm_block` has pointers: + * + * - next `umm_block`: 0 (meaning, there are no more `umm_blocks`) + * - prev `umm_block`: the 1st + * + * It's not a free block, so we don't touch NFREE / PFREE at all. + */ + UMM_NBLOCK(block_last) = 0; + UMM_PBLOCK(block_last) = block_1th; + } +} + +void umm_init( void ) { + umm_init_x(0); +} + +/* ------------------------------------------------------------------------ */ + +void umm_free( void *ptr ) { + + unsigned short int c; + + /* If we're being asked to free a NULL pointer, well that's just silly! */ + + if( (void *)0 == ptr ) { + DBGLOG_DEBUG( "free a null pointer -> do nothing\n" ); + + return; + } + + /* + * FIXME: At some point it might be a good idea to add a check to make sure + * that the pointer we're being asked to free up is actually within + * the umm_heap! + * + * NOTE: See the new umm_info() function that you can use to see if a ptr is + * on the free list! + */ + + /* Protect the critical section... */ + UMM_CRITICAL_ENTRY(); + + /* Figure out which block we're in. Note the use of truncated division... */ + + c = (((char *)ptr)-(char *)(&(umm_heap[0])))/sizeof(umm_block); + + DBGLOG_DEBUG( "Freeing block %6i\n", c ); + + /* Now let's assimilate this block with the next one if possible. */ + + umm_assimilate_up( c ); + + /* Then assimilate with the previous block if possible */ + + if( UMM_NBLOCK(UMM_PBLOCK(c)) & UMM_FREELIST_MASK ) { + + DBGLOG_DEBUG( "Assimilate down to next block, which is FREE\n" ); + + c = umm_assimilate_down(c, UMM_FREELIST_MASK); + } else { + /* + * The previous block is not a free block, so add this one to the head + * of the free list + */ + + DBGLOG_DEBUG( "Just add to head of free list\n" ); + + UMM_PFREE(UMM_NFREE(0)) = c; + UMM_NFREE(c) = UMM_NFREE(0); + UMM_PFREE(c) = 0; + UMM_NFREE(0) = c; + + UMM_NBLOCK(c) |= UMM_FREELIST_MASK; + } + + /* Release the critical section... */ + UMM_CRITICAL_EXIT(); +} + +/* ------------------------------------------------------------------------ */ + +void *umm_malloc( size_t size ) { + unsigned short int blocks; + unsigned short int blockSize = 0; + + unsigned short int bestSize; + unsigned short int bestBlock; + + unsigned short int cf; + + if (umm_heap == NULL) { + umm_init(); + } + + /* + * the very first thing we do is figure out if we're being asked to allocate + * a size of 0 - and if we are we'll simply return a null pointer. if not + * then reduce the size by 1 byte so that the subsequent calculations on + * the number of blocks to allocate are easier... + */ + + if( 0 == size ) { + DBGLOG_DEBUG( "malloc a block of 0 bytes -> do nothing\n" ); + + return( (void *)NULL ); + } + + /* Protect the critical section... */ + UMM_CRITICAL_ENTRY(); + + blocks = umm_blocks( size ); + + /* + * Now we can scan through the free list until we find a space that's big + * enough to hold the number of blocks we need. + * + * This part may be customized to be a best-fit, worst-fit, or first-fit + * algorithm + */ + + cf = UMM_NFREE(0); + + bestBlock = UMM_NFREE(0); + bestSize = 0x7FFF; + + while( cf ) { + blockSize = (UMM_NBLOCK(cf) & UMM_BLOCKNO_MASK) - cf; + + DBGLOG_TRACE( "Looking at block %6i size %6i\n", cf, blockSize ); + +#if defined UMM_BEST_FIT + if( (blockSize >= blocks) && (blockSize < bestSize) ) { + bestBlock = cf; + bestSize = blockSize; + } +#elif defined UMM_FIRST_FIT + /* This is the first block that fits! */ + if( (blockSize >= blocks) ) + break; +#else +# error "No UMM_*_FIT is defined - check umm_malloc_cfg.h" +#endif + + cf = UMM_NFREE(cf); + } + + if( 0x7FFF != bestSize ) { + cf = bestBlock; + blockSize = bestSize; + } + + if( UMM_NBLOCK(cf) & UMM_BLOCKNO_MASK && blockSize >= blocks ) { + /* + * This is an existing block in the memory heap, we just need to split off + * what we need, unlink it from the free list and mark it as in use, and + * link the rest of the block back into the freelist as if it was a new + * block on the free list... + */ + + if( blockSize == blocks ) { + /* It's an exact fit and we don't neet to split off a block. */ + DBGLOG_DEBUG( "Allocating %6i blocks starting at %6i - exact\n", blocks, cf ); + + /* Disconnect this block from the FREE list */ + + umm_disconnect_from_free_list( cf ); + + } else { + /* It's not an exact fit and we need to split off a block. */ + DBGLOG_DEBUG( "Allocating %6i blocks starting at %6i - existing\n", blocks, cf ); + + /* + * split current free block `cf` into two blocks. The first one will be + * returned to user, so it's not free, and the second one will be free. + */ + umm_split_block( cf, blocks, UMM_FREELIST_MASK /*new block is free*/ ); + + /* + * `umm_split_block()` does not update the free pointers (it affects + * only free flags), but effectively we've just moved beginning of the + * free block from `cf` to `cf + blocks`. So we have to adjust pointers + * to and from adjacent free blocks. + */ + + /* previous free block */ + UMM_NFREE( UMM_PFREE(cf) ) = cf + blocks; + UMM_PFREE( cf + blocks ) = UMM_PFREE(cf); + + /* next free block */ + UMM_PFREE( UMM_NFREE(cf) ) = cf + blocks; + UMM_NFREE( cf + blocks ) = UMM_NFREE(cf); + } + } else { + /* Out of memory */ + + DBGLOG_DEBUG( "Can't allocate %5i blocks\n", blocks ); + + /* Release the critical section... */ + UMM_CRITICAL_EXIT(); + + return( (void *)NULL ); + } + + /* Release the critical section... */ + UMM_CRITICAL_EXIT(); + + return( (void *)&UMM_DATA(cf) ); +} + +/* ------------------------------------------------------------------------ */ + +void *umm_realloc( void *ptr, size_t size ) { + + unsigned short int blocks; + unsigned short int blockSize; + unsigned short int prevBlockSize = 0; + unsigned short int nextBlockSize = 0; + + unsigned short int c; + + size_t curSize; + + if (umm_heap == NULL) { + umm_init(); + } + + /* + * This code looks after the case of a NULL value for ptr. The ANSI C + * standard says that if ptr is NULL and size is non-zero, then we've + * got to work the same a malloc(). If size is also 0, then our version + * of malloc() returns a NULL pointer, which is OK as far as the ANSI C + * standard is concerned. + */ + + if( ((void *)NULL == ptr) ) { + DBGLOG_DEBUG( "realloc the NULL pointer - call malloc()\n" ); + + return( umm_malloc(size) ); + } + + /* + * Now we're sure that we have a non_NULL ptr, but we're not sure what + * we should do with it. If the size is 0, then the ANSI C standard says that + * we should operate the same as free. + */ + + if( 0 == size ) { + DBGLOG_DEBUG( "realloc to 0 size, just free the block\n" ); + + umm_free( ptr ); + + return( (void *)NULL ); + } + + /* + * Otherwise we need to actually do a reallocation. A naiive approach + * would be to malloc() a new block of the correct size, copy the old data + * to the new block, and then free the old block. + * + * While this will work, we end up doing a lot of possibly unnecessary + * copying. So first, let's figure out how many blocks we'll need. + */ + + blocks = umm_blocks( size ); + + /* Figure out which block we're in. Note the use of truncated division... */ + + c = (((char *)ptr)-(char *)(&(umm_heap[0])))/sizeof(umm_block); + + /* Figure out how big this block is ... the free bit is not set :-) */ + + blockSize = (UMM_NBLOCK(c) - c); + + /* Figure out how many bytes are in this block */ + + curSize = (blockSize*sizeof(umm_block))-(sizeof(((umm_block *)0)->header)); + + /* Protect the critical section... */ + UMM_CRITICAL_ENTRY(); + + /* Now figure out if the previous and/or next blocks are free as well as + * their sizes - this will help us to minimize special code later when we + * decide if it's possible to use the adjacent blocks. + * + * We set prevBlockSize and nextBlockSize to non-zero values ONLY if they + * are free! + */ + + if ((UMM_NBLOCK(UMM_NBLOCK(c)) & UMM_FREELIST_MASK)) { + nextBlockSize = (UMM_NBLOCK(UMM_NBLOCK(c)) & UMM_BLOCKNO_MASK) - UMM_NBLOCK(c); + } + + if ((UMM_NBLOCK(UMM_PBLOCK(c)) & UMM_FREELIST_MASK)) { + prevBlockSize = (c - UMM_PBLOCK(c)); + } + + DBGLOG_DEBUG( "realloc blocks %i blockSize %i nextBlockSize %i prevBlockSize %i\n", blocks, blockSize, nextBlockSize, prevBlockSize ); + + /* + * Ok, now that we're here we know how many blocks we want and the current + * blockSize. The prevBlockSize and nextBlockSize are set and we can figure + * out the best strategy for the new allocation as follows: + * + * 1. If the new block is the same size or smaller than the current block do + * nothing. + * 2. If the next block is free and adding it to the current block gives us + * enough memory, assimilate the next block. + * 3. If the prev block is free and adding it to the current block gives us + * enough memory, remove the previous block from the free list, assimilate + * it, copy to the new block. + * 4. If the prev and next blocks are free and adding them to the current + * block gives us enough memory, assimilate the next block, remove the + * previous block from the free list, assimilate it, copy to the new block. + * 5. Otherwise try to allocate an entirely new block of memory. If the + * allocation works free the old block and return the new pointer. If + * the allocation fails, return NULL and leave the old block intact. + * + * All that's left to do is decide if the fit was exact or not. If the fit + * was not exact, then split the memory block so that we use only the requested + * number of blocks and add what's left to the free list. + */ + + if (blockSize >= blocks) { + DBGLOG_DEBUG( "realloc the same or smaller size block - %i, do nothing\n", blocks ); + /* This space intentionally left blank */ + } else if ((blockSize + nextBlockSize) >= blocks) { + DBGLOG_DEBUG( "realloc using next block - %i\n", blocks ); + umm_assimilate_up( c ); + blockSize += nextBlockSize; + } else if ((prevBlockSize + blockSize) >= blocks) { + DBGLOG_DEBUG( "realloc using prev block - %i\n", blocks ); + umm_disconnect_from_free_list( UMM_PBLOCK(c) ); + c = umm_assimilate_down(c, 0); + memmove( (void *)&UMM_DATA(c), ptr, curSize ); + ptr = (void *)&UMM_DATA(c); + blockSize += prevBlockSize; + } else if ((prevBlockSize + blockSize + nextBlockSize) >= blocks) { + DBGLOG_DEBUG( "realloc using prev and next block - %i\n", blocks ); + umm_assimilate_up( c ); + umm_disconnect_from_free_list( UMM_PBLOCK(c) ); + c = umm_assimilate_down(c, 0); + memmove( (void *)&UMM_DATA(c), ptr, curSize ); + ptr = (void *)&UMM_DATA(c); + blockSize += (prevBlockSize + nextBlockSize); + } else { + DBGLOG_DEBUG( "realloc a completely new block %i\n", blocks ); + void *oldptr = ptr; + if( (ptr = umm_malloc( size )) ) { + DBGLOG_DEBUG( "realloc %i to a bigger block %i, copy, and free the old\n", blockSize, blocks ); + memcpy( ptr, oldptr, curSize ); + umm_free( oldptr ); + } else { + DBGLOG_DEBUG( "realloc %i to a bigger block %i failed - return NULL and leave the old block!\n", blockSize, blocks ); + /* This space intentionally left blnk */ + } + blockSize = blocks; + } + + /* Now all we need to do is figure out if the block fit exactly or if we + * need to split and free ... + */ + + if (blockSize > blocks ) { + DBGLOG_DEBUG( "split and free %i blocks from %i\n", blocks, blockSize ); + umm_split_block( c, blocks, 0 ); + umm_free( (void *)&UMM_DATA(c+blocks) ); + } + + /* Release the critical section... */ + UMM_CRITICAL_EXIT(); + + return( ptr ); +} + +/* ------------------------------------------------------------------------ */ + +void *umm_calloc( size_t num, size_t item_size ) { + void *ret; + + ret = umm_malloc((size_t)(item_size * num)); + + if (ret) + memset(ret, 0x00, (size_t)(item_size * num)); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/openmv/src/omv/umm_malloc.h b/src/openmv/src/omv/umm_malloc.h new file mode 100755 index 0000000..fe3c5d6 --- /dev/null +++ b/src/openmv/src/omv/umm_malloc.h @@ -0,0 +1,61 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2017 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ + +#ifndef __UMM_MALLOC_H__ +#define __UMM_MALLOC_H__ +#include + +void umm_alloc_fail(); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////// "umm_malloc.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//The MIT License (MIT) + +//Copyright (c) 2015 Ralph Hempel + +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: + +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. + +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +/* ---------------------------------------------------------------------------- + * umm_malloc.h - a memory allocator for embedded systems (microcontrollers) + * + * See copyright notice in LICENSE.TXT + * ---------------------------------------------------------------------------- + */ + + +/* ------------------------------------------------------------------------ */ + +void umm_init_x( size_t size ); // Min of 2.5KB - Max of 640 KB. +void *umm_malloc( size_t size ); +void *umm_calloc( size_t num, size_t size ); +void *umm_realloc( void *ptr, size_t size ); +void umm_free( void *ptr ); + + +/* ------------------------------------------------------------------------ */ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif /* __UMM_MALLOC_H__ */ diff --git a/src/openmv/src/omv/usbdbg.c b/src/openmv/src/omv/usbdbg.c new file mode 100755 index 0000000..45d486e --- /dev/null +++ b/src/openmv/src/omv/usbdbg.c @@ -0,0 +1,336 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * USB debug support. + * + */ +#include "mp.h" +#include "imlib.h" +#include "sensor.h" +#include "framebuffer.h" +#include "ff.h" +#include "usb.h" +#include "usbdbg.h" +#include "nlr.h" +#include "lexer.h" +#include "parse.h" +#include "compile.h" +#include "runtime.h" +#include "omv_boardconfig.h" + +static int xfer_bytes; +static int xfer_length; +static enum usbdbg_cmd cmd; + +static volatile bool script_ready; +static volatile bool script_running; +static vstr_t script_buf; +static mp_obj_t mp_const_ide_interrupt = MP_OBJ_NULL; +extern const char *ffs_strerror(FRESULT res); + +void usbdbg_init() +{ + script_ready=false; + script_running=false; + vstr_init(&script_buf, 32); + mp_const_ide_interrupt = mp_obj_new_exception_msg(&mp_type_Exception, "IDE interrupt"); +} + +bool usbdbg_script_ready() +{ + return script_ready; +} + +vstr_t *usbdbg_get_script() +{ + return &script_buf; +} + +void usbdbg_set_script_running(bool running) +{ + script_running = running; +} + +inline void usbdbg_set_irq_enabled(bool enabled) +{ + if (enabled) { + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + } else { + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); + } + __DSB(); __ISB(); +} + +void usbdbg_data_in(void *buffer, int length) +{ + switch (cmd) { + case USBDBG_FW_VERSION: { + uint32_t *ver_buf = buffer; + ver_buf[0] = FIRMWARE_VERSION_MAJOR; + ver_buf[1] = FIRMWARE_VERSION_MINOR; + ver_buf[2] = FIRMWARE_VERSION_PATCH; + cmd = USBDBG_NONE; + break; + } + + case USBDBG_TX_BUF_LEN: { + uint32_t tx_buf_len = usb_cdc_tx_buf_len(); + memcpy(buffer, &tx_buf_len, sizeof(tx_buf_len)); + cmd = USBDBG_NONE; + break; + } + + case USBDBG_TX_BUF: { + uint8_t *tx_buf = usb_cdc_tx_buf(length); + memcpy(buffer, tx_buf, length); + if (xfer_bytes == xfer_length) { + cmd = USBDBG_NONE; + } + break; + } + + case USBDBG_FRAME_SIZE: + // Return 0 if FB is locked or not ready. + ((uint32_t*)buffer)[0] = 0; + // Try to lock FB. If header size == 0 frame is not ready + if (mutex_try_lock(&JPEG_FB()->lock, MUTEX_TID_IDE)) { + // If header size == 0 frame is not ready + if (JPEG_FB()->size == 0) { + // unlock FB + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_IDE); + } else { + // Return header w, h and size/bpp + ((uint32_t*)buffer)[0] = JPEG_FB()->w; + ((uint32_t*)buffer)[1] = JPEG_FB()->h; + ((uint32_t*)buffer)[2] = JPEG_FB()->size; + } + } + cmd = USBDBG_NONE; + break; + + case USBDBG_FRAME_DUMP: + if (xfer_bytes < xfer_length) { + memcpy(buffer, JPEG_FB()->pixels+xfer_bytes, length); + xfer_bytes += length; + if (xfer_bytes == xfer_length) { + cmd = USBDBG_NONE; + JPEG_FB()->w = 0; JPEG_FB()->h = 0; JPEG_FB()->size = 0; + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_IDE); + } + } + break; + + case USBDBG_ARCH_STR: { + snprintf((char *) buffer, 64, "%s [%s:%08X%08X%08X]", + OMV_ARCH_STR, OMV_BOARD_TYPE, + *((unsigned int *) (OMV_UNIQUE_ID_ADDR + 8)), + *((unsigned int *) (OMV_UNIQUE_ID_ADDR + 4)), + *((unsigned int *) (OMV_UNIQUE_ID_ADDR + 0))); + cmd = USBDBG_NONE; + break; + } + + case USBDBG_SCRIPT_RUNNING: { + uint32_t *buf = buffer; + buf[0] = (uint32_t) script_running; + cmd = USBDBG_NONE; + break; + } + default: /* error */ + break; + } +} + +extern int py_image_descriptor_from_roi(image_t *image, const char *path, rectangle_t *roi); + +void usbdbg_data_out(void *buffer, int length) +{ + switch (cmd) { + case USBDBG_SCRIPT_EXEC: + // check if GC is locked before allocating memory for vstr. If GC was locked + // at least once before the script is fully uploaded xfer_bytes will be less + // than the total length (xfer_length) and the script will Not be executed. + if (!script_running && !gc_is_locked()) { + vstr_add_strn(&script_buf, buffer, length); + xfer_bytes += length; + if (xfer_bytes == xfer_length) { + // Set script ready flag + script_ready = true; + + // Set script running flag + script_running = true; + + // Disable IDE IRQ (re-enabled by pyexec or main). + usbdbg_set_irq_enabled(false); + + // Clear interrupt traceback + mp_obj_exception_clear_traceback(mp_const_ide_interrupt); + // Interrupt running REPL + // Note: setting pendsv explicitly here because the VM is probably + // waiting in REPL and the soft interrupt flag will not be checked. + pendsv_nlr_jump_hard(mp_const_ide_interrupt); + } + } + break; + + case USBDBG_TEMPLATE_SAVE: { + image_t image ={ + .w = MAIN_FB()->w, + .h = MAIN_FB()->h, + .bpp = MAIN_FB()->bpp, + .pixels = MAIN_FB()->pixels + }; + + // null terminate the path + length = (length == 64) ? 63:length; + ((char*)buffer)[length] = 0; + + rectangle_t *roi = (rectangle_t*)buffer; + char *path = (char*)buffer+sizeof(rectangle_t); + + imlib_save_image(&image, path, roi, 50); + // raise a flash IRQ to flush image + //NVIC->STIR = FLASH_IRQn; + break; + } + + case USBDBG_DESCRIPTOR_SAVE: { + image_t image ={ + .w = MAIN_FB()->w, + .h = MAIN_FB()->h, + .bpp = MAIN_FB()->bpp, + .pixels = MAIN_FB()->pixels + }; + + // null terminate the path + length = (length == 64) ? 63:length; + ((char*)buffer)[length] = 0; + + rectangle_t *roi = (rectangle_t*)buffer; + char *path = (char*)buffer+sizeof(rectangle_t); + + py_image_descriptor_from_roi(&image, path, roi); + break; + } + default: /* error */ + break; + } +} + +void usbdbg_control(void *buffer, uint8_t request, uint32_t length) +{ + cmd = (enum usbdbg_cmd) request; + switch (cmd) { + case USBDBG_FW_VERSION: + xfer_bytes = 0; + xfer_length = length; + break; + + case USBDBG_FRAME_SIZE: + xfer_bytes = 0; + xfer_length = length; + break; + + case USBDBG_FRAME_DUMP: + xfer_bytes = 0; + xfer_length = length; + break; + + case USBDBG_ARCH_STR: + xfer_bytes = 0; + xfer_length = length; + break; + + case USBDBG_SCRIPT_EXEC: + xfer_bytes = 0; + xfer_length = length; + vstr_reset(&script_buf); + break; + + case USBDBG_SCRIPT_STOP: + if (script_running) { + // Set script running flag + script_running = false; + + // Disable IDE IRQ (re-enabled by pyexec or main). + usbdbg_set_irq_enabled(false); + + // interrupt running code by raising an exception + mp_obj_exception_clear_traceback(mp_const_ide_interrupt); + pendsv_nlr_jump_hard(mp_const_ide_interrupt); + } + cmd = USBDBG_NONE; + break; + + case USBDBG_SCRIPT_SAVE: + /* save running script */ + // TODO + break; + + case USBDBG_SCRIPT_RUNNING: + xfer_bytes = 0; + xfer_length =length; + break; + + case USBDBG_TEMPLATE_SAVE: + case USBDBG_DESCRIPTOR_SAVE: + /* save template */ + xfer_bytes = 0; + xfer_length =length; + break; + + case USBDBG_ATTR_WRITE: { + /* write sensor attribute */ + int16_t attr= *((int16_t*)buffer); + int16_t val = *((int16_t*)buffer+1); + switch (attr) { + case ATTR_CONTRAST: + sensor_set_contrast(val); + break; + case ATTR_BRIGHTNESS: + sensor_set_brightness(val); + break; + case ATTR_SATURATION: + sensor_set_saturation(val); + break; + case ATTR_GAINCEILING: + sensor_set_gainceiling(val); + break; + default: + break; + } + cmd = USBDBG_NONE; + break; + } + + case USBDBG_SYS_RESET: + NVIC_SystemReset(); + break; + + case USBDBG_FB_ENABLE: { + int16_t enable = *((int16_t*)buffer); + JPEG_FB()->enabled = enable; + if (enable == 0) { + // When disabling framebuffer, the IDE might still be holding FB lock. + // If the IDE is not the current lock owner, this operation is ignored. + mutex_unlock(&JPEG_FB()->lock, MUTEX_TID_IDE); + } + cmd = USBDBG_NONE; + break; + } + + case USBDBG_TX_BUF: + case USBDBG_TX_BUF_LEN: + xfer_bytes = 0; + xfer_length = length; + break; + + default: /* error */ + cmd = USBDBG_NONE; + break; + } +} + + diff --git a/src/openmv/src/omv/usbdbg.h b/src/openmv/src/omv/usbdbg.h new file mode 100755 index 0000000..1907ad1 --- /dev/null +++ b/src/openmv/src/omv/usbdbg.h @@ -0,0 +1,60 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * USB debug support. + * + */ +#ifndef __USBDBG_H__ +#define __USBDBG_H__ +/** + * Firmware major, minor and patch versions. + * Increment the major version if the ABI has changed. + * Increment the minor version when a new command is added. + * Increment the patch version for fixes that don't affect the ABI. + * + * Note: incrementing the major version will require a fw upgrade, + * the IDE will Not connect if the major version number is different. + */ +#define FIRMWARE_VERSION_MAJOR (3) +#define FIRMWARE_VERSION_MINOR (2) +#define FIRMWARE_VERSION_PATCH (0) + +/** + * To add a new debugging command, increment the last command value used. + * Set the MSB of the value if the request has a device-to-host data phase. + * Add the command to usr/openmv.py using the same value. + * Handle the command control and data in/out (if any) phases in usbdbg.c. + * + * See usbdbg.c for examples. + */ +enum usbdbg_cmd { + USBDBG_NONE =0x00, + USBDBG_FW_VERSION =0x80, + USBDBG_FRAME_SIZE =0x81, + USBDBG_FRAME_DUMP =0x82, + USBDBG_ARCH_STR =0x83, + USBDBG_SCRIPT_EXEC =0x05, + USBDBG_SCRIPT_STOP =0x06, + USBDBG_SCRIPT_SAVE =0x07, + USBDBG_SCRIPT_RUNNING =0x87, + USBDBG_TEMPLATE_SAVE =0x08, + USBDBG_DESCRIPTOR_SAVE =0x09, + USBDBG_ATTR_READ =0x8A, + USBDBG_ATTR_WRITE =0x0B, + USBDBG_SYS_RESET =0x0C, + USBDBG_FB_ENABLE =0x0D, + USBDBG_TX_BUF_LEN =0x8E, + USBDBG_TX_BUF =0x8F +}; +void usbdbg_init(); +bool usbdbg_script_ready(); +vstr_t *usbdbg_get_script(); +bool usbdbg_get_irq_enabled(); +void usbdbg_set_irq_enabled(bool enabled); +void usbdbg_set_script_running(bool running); +void usbdbg_data_in(void *buffer, int length); +void usbdbg_data_out(void *buffer, int length); +void usbdbg_control(void *buffer, uint8_t brequest, uint32_t wlength); +#endif /* __USBDBG_H__ */ diff --git a/src/openmv/src/omv/wifidbg.h b/src/openmv/src/omv/wifidbg.h new file mode 100755 index 0000000..3f5621c --- /dev/null +++ b/src/openmv/src/omv/wifidbg.h @@ -0,0 +1,13 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ +#ifndef __WIFI_DBG_H__ +#define __WIFI_DBG_H__ +typedef struct wifidbg_config { + uint8_t unused; +} wifidbg_config_t; +int wifidbg_init(wifidbg_config_t *config); +void wifidbg_dispatch(); + +#endif /* __WIFIDBG_H__ */ diff --git a/src/openmv/src/omv/xalloc.c b/src/openmv/src/omv/xalloc.c new file mode 100755 index 0000000..63cc289 --- /dev/null +++ b/src/openmv/src/omv/xalloc.c @@ -0,0 +1,61 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Memory allocation functions. + * + */ +#include +#include "xalloc.h" + +NORETURN static void xalloc_fail() +{ + nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, "Out of normal MicroPython Heap Memory!" + " Please reduce the resolution of the image you are running this algorithm on to bypass this issue!")); +} + +// returns null pointer without error if size==0 +void *xalloc(uint32_t size) +{ + void *mem = gc_alloc(size, false); + if (size && (mem == NULL)) { + xalloc_fail(); + } + return mem; +} + +// returns null pointer without error if size==0 +void *xalloc_try_alloc(uint32_t size) +{ + return gc_alloc(size, false); +} + +// returns null pointer without error if size==0 +void *xalloc0(uint32_t size) +{ + void *mem = gc_alloc(size, false); + if (size && (mem == NULL)) { + xalloc_fail(); + } + memset(mem, 0, size); + return mem; +} + +// returns without error if mem==null +void xfree(void *mem) +{ + gc_free(mem); +} + +// returns null pointer without error if size==0 +// allocs if mem==null and size!=0 +// frees if mem!=null and size==0 +void *xrealloc(void *mem, uint32_t size) +{ + mem = gc_realloc(mem, size, true); + if (size && (mem == NULL)) { + xalloc_fail(); + } + return mem; +} diff --git a/src/openmv/src/omv/xalloc.h b/src/openmv/src/omv/xalloc.h new file mode 100755 index 0000000..f79838f --- /dev/null +++ b/src/openmv/src/omv/xalloc.h @@ -0,0 +1,17 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Memory allocation functions. + * + */ +#ifndef __XALLOC_H__ +#define __XALLOC_H__ +#include +void *xalloc(uint32_t size); +void *xalloc_try_alloc(uint32_t size); +void *xalloc0(uint32_t size); +void xfree(void *mem); +void *xrealloc(void *mem, uint32_t size); +#endif // __XALLOC_H__